summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Makefile11
-rw-r--r--drivers/accel/Kconfig8
-rw-r--r--drivers/accel/Makefile (renamed from drivers/staging/media/deprecated/fsl-viu/Makefile)4
-rw-r--r--drivers/accel/habanalabs/Kconfig (renamed from drivers/misc/habanalabs/Kconfig)8
-rw-r--r--drivers/accel/habanalabs/Makefile (renamed from drivers/misc/habanalabs/Makefile)2
-rw-r--r--drivers/accel/habanalabs/common/Makefile (renamed from drivers/misc/habanalabs/common/Makefile)0
-rw-r--r--drivers/accel/habanalabs/common/asid.c (renamed from drivers/misc/habanalabs/common/asid.c)0
-rw-r--r--drivers/accel/habanalabs/common/command_buffer.c (renamed from drivers/misc/habanalabs/common/command_buffer.c)22
-rw-r--r--drivers/accel/habanalabs/common/command_submission.c (renamed from drivers/misc/habanalabs/common/command_submission.c)133
-rw-r--r--drivers/accel/habanalabs/common/context.c (renamed from drivers/misc/habanalabs/common/context.c)0
-rw-r--r--drivers/accel/habanalabs/common/debugfs.c (renamed from drivers/misc/habanalabs/common/debugfs.c)0
-rw-r--r--drivers/accel/habanalabs/common/decoder.c (renamed from drivers/misc/habanalabs/common/decoder.c)0
-rw-r--r--drivers/accel/habanalabs/common/device.c (renamed from drivers/misc/habanalabs/common/device.c)109
-rw-r--r--drivers/accel/habanalabs/common/firmware_if.c (renamed from drivers/misc/habanalabs/common/firmware_if.c)189
-rw-r--r--drivers/accel/habanalabs/common/habanalabs.h (renamed from drivers/misc/habanalabs/common/habanalabs.h)122
-rw-r--r--drivers/accel/habanalabs/common/habanalabs_drv.c (renamed from drivers/misc/habanalabs/common/habanalabs_drv.c)6
-rw-r--r--drivers/accel/habanalabs/common/habanalabs_ioctl.c (renamed from drivers/misc/habanalabs/common/habanalabs_ioctl.c)101
-rw-r--r--drivers/accel/habanalabs/common/hw_queue.c (renamed from drivers/misc/habanalabs/common/hw_queue.c)0
-rw-r--r--drivers/accel/habanalabs/common/hwmon.c (renamed from drivers/misc/habanalabs/common/hwmon.c)0
-rw-r--r--drivers/accel/habanalabs/common/irq.c (renamed from drivers/misc/habanalabs/common/irq.c)38
-rw-r--r--drivers/accel/habanalabs/common/memory.c (renamed from drivers/misc/habanalabs/common/memory.c)371
-rw-r--r--drivers/accel/habanalabs/common/memory_mgr.c (renamed from drivers/misc/habanalabs/common/memory_mgr.c)3
-rw-r--r--drivers/accel/habanalabs/common/mmu/Makefile (renamed from drivers/misc/habanalabs/common/mmu/Makefile)0
-rw-r--r--drivers/accel/habanalabs/common/mmu/mmu.c (renamed from drivers/misc/habanalabs/common/mmu/mmu.c)2
-rw-r--r--drivers/accel/habanalabs/common/mmu/mmu_v1.c (renamed from drivers/misc/habanalabs/common/mmu/mmu_v1.c)1
-rw-r--r--drivers/accel/habanalabs/common/mmu/mmu_v2_hr.c (renamed from drivers/misc/habanalabs/common/mmu/mmu_v2_hr.c)0
-rw-r--r--drivers/accel/habanalabs/common/pci/Makefile (renamed from drivers/misc/habanalabs/common/pci/Makefile)0
-rw-r--r--drivers/accel/habanalabs/common/pci/pci.c (renamed from drivers/misc/habanalabs/common/pci/pci.c)10
-rw-r--r--drivers/accel/habanalabs/common/security.c (renamed from drivers/misc/habanalabs/common/security.c)174
-rw-r--r--drivers/accel/habanalabs/common/security.h163
-rw-r--r--drivers/accel/habanalabs/common/state_dump.c (renamed from drivers/misc/habanalabs/common/state_dump.c)2
-rw-r--r--drivers/accel/habanalabs/common/sysfs.c (renamed from drivers/misc/habanalabs/common/sysfs.c)0
-rw-r--r--drivers/accel/habanalabs/gaudi/Makefile (renamed from drivers/misc/habanalabs/gaudi/Makefile)0
-rw-r--r--drivers/accel/habanalabs/gaudi/gaudi.c (renamed from drivers/misc/habanalabs/gaudi/gaudi.c)31
-rw-r--r--drivers/accel/habanalabs/gaudi/gaudiP.h (renamed from drivers/misc/habanalabs/gaudi/gaudiP.h)2
-rw-r--r--drivers/accel/habanalabs/gaudi/gaudi_coresight.c (renamed from drivers/misc/habanalabs/gaudi/gaudi_coresight.c)3
-rw-r--r--drivers/accel/habanalabs/gaudi/gaudi_security.c (renamed from drivers/misc/habanalabs/gaudi/gaudi_security.c)0
-rw-r--r--drivers/accel/habanalabs/gaudi2/Makefile (renamed from drivers/misc/habanalabs/gaudi2/Makefile)0
-rw-r--r--drivers/accel/habanalabs/gaudi2/gaudi2.c (renamed from drivers/misc/habanalabs/gaudi2/gaudi2.c)1183
-rw-r--r--drivers/accel/habanalabs/gaudi2/gaudi2P.h (renamed from drivers/misc/habanalabs/gaudi2/gaudi2P.h)39
-rw-r--r--drivers/accel/habanalabs/gaudi2/gaudi2_coresight.c (renamed from drivers/misc/habanalabs/gaudi2/gaudi2_coresight.c)10
-rw-r--r--drivers/accel/habanalabs/gaudi2/gaudi2_coresight_regs.h (renamed from drivers/misc/habanalabs/gaudi2/gaudi2_coresight_regs.h)0
-rw-r--r--drivers/accel/habanalabs/gaudi2/gaudi2_masks.h (renamed from drivers/misc/habanalabs/gaudi2/gaudi2_masks.h)0
-rw-r--r--drivers/accel/habanalabs/gaudi2/gaudi2_security.c (renamed from drivers/misc/habanalabs/gaudi2/gaudi2_security.c)37
-rw-r--r--drivers/accel/habanalabs/goya/Makefile (renamed from drivers/misc/habanalabs/goya/Makefile)0
-rw-r--r--drivers/accel/habanalabs/goya/goya.c (renamed from drivers/misc/habanalabs/goya/goya.c)16
-rw-r--r--drivers/accel/habanalabs/goya/goyaP.h (renamed from drivers/misc/habanalabs/goya/goyaP.h)2
-rw-r--r--drivers/accel/habanalabs/goya/goya_coresight.c (renamed from drivers/misc/habanalabs/goya/goya_coresight.c)2
-rw-r--r--drivers/accel/habanalabs/goya/goya_hwmgr.c (renamed from drivers/misc/habanalabs/goya/goya_hwmgr.c)0
-rw-r--r--drivers/accel/habanalabs/goya/goya_security.c (renamed from drivers/misc/habanalabs/goya/goya_security.c)0
-rw-r--r--drivers/accel/habanalabs/include/common/cpucp_if.h (renamed from drivers/misc/habanalabs/include/common/cpucp_if.h)96
-rw-r--r--drivers/accel/habanalabs/include/common/hl_boot_if.h (renamed from drivers/misc/habanalabs/include/common/hl_boot_if.h)151
-rw-r--r--drivers/accel/habanalabs/include/common/qman_if.h (renamed from drivers/misc/habanalabs/include/common/qman_if.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/cpu_if_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/cpu_if_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/dma0_core_masks.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/dma0_core_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/dma0_core_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/dma0_core_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/dma0_qm_masks.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/dma0_qm_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/dma0_qm_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/dma0_qm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/dma1_core_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/dma1_core_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/dma1_qm_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/dma1_qm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/dma2_core_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/dma2_core_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/dma2_qm_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/dma2_qm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/dma3_core_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/dma3_core_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/dma3_qm_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/dma3_qm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/dma4_core_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/dma4_core_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/dma4_qm_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/dma4_qm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/dma5_core_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/dma5_core_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/dma5_qm_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/dma5_qm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/dma6_core_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/dma6_core_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/dma6_qm_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/dma6_qm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/dma7_core_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/dma7_core_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/dma7_qm_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/dma7_qm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/dma_if_e_n_down_ch0_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/dma_if_e_n_down_ch0_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/dma_if_e_n_down_ch1_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/dma_if_e_n_down_ch1_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/dma_if_e_n_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/dma_if_e_n_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/dma_if_e_s_down_ch0_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/dma_if_e_s_down_ch0_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/dma_if_e_s_down_ch1_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/dma_if_e_s_down_ch1_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/dma_if_e_s_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/dma_if_e_s_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/dma_if_w_n_down_ch0_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/dma_if_w_n_down_ch0_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/dma_if_w_n_down_ch1_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/dma_if_w_n_down_ch1_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/dma_if_w_n_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/dma_if_w_n_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/dma_if_w_s_down_ch0_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/dma_if_w_s_down_ch0_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/dma_if_w_s_down_ch1_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/dma_if_w_s_down_ch1_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/dma_if_w_s_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/dma_if_w_s_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/gaudi_blocks.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/gaudi_blocks.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/gaudi_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/gaudi_regs.h)2
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/mme0_ctrl_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/mme0_ctrl_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/mme0_qm_masks.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/mme0_qm_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/mme0_qm_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/mme0_qm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/mme1_ctrl_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/mme1_ctrl_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/mme2_ctrl_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/mme2_ctrl_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/mme2_qm_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/mme2_qm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/mme3_ctrl_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/mme3_ctrl_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/mmu_up_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/mmu_up_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/nic0_qm0_masks.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/nic0_qm0_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/nic0_qm0_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/nic0_qm0_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/nic0_qm1_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/nic0_qm1_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/nic1_qm0_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/nic1_qm0_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/nic1_qm1_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/nic1_qm1_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/nic2_qm0_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/nic2_qm0_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/nic2_qm1_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/nic2_qm1_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/nic3_qm0_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/nic3_qm0_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/nic3_qm1_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/nic3_qm1_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/nic4_qm0_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/nic4_qm0_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/nic4_qm1_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/nic4_qm1_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_0_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_0_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_1_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_1_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_2_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_2_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_3_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_3_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_4_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_4_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_5_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_5_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_6_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_6_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_7_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_7_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/psoc_cpu_pll_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/psoc_cpu_pll_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/psoc_etr_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/psoc_etr_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/psoc_global_conf_masks.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/psoc_global_conf_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/psoc_global_conf_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/psoc_global_conf_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/psoc_timestamp_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/psoc_timestamp_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_0_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_0_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_1_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_1_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_2_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_2_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_3_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_3_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_4_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_4_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_5_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_5_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_6_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_6_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_7_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_7_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/stlb_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/stlb_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/tpc0_cfg_masks.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/tpc0_cfg_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/tpc0_cfg_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/tpc0_cfg_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/tpc0_qm_masks.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/tpc0_qm_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/tpc0_qm_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/tpc0_qm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/tpc1_cfg_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/tpc1_cfg_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/tpc1_qm_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/tpc1_qm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/tpc2_cfg_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/tpc2_cfg_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/tpc2_qm_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/tpc2_qm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/tpc3_cfg_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/tpc3_cfg_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/tpc3_qm_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/tpc3_qm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/tpc4_cfg_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/tpc4_cfg_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/tpc4_qm_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/tpc4_qm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/tpc5_cfg_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/tpc5_cfg_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/tpc5_qm_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/tpc5_qm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/tpc6_cfg_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/tpc6_cfg_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/tpc6_qm_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/tpc6_qm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/tpc7_cfg_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/tpc7_cfg_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/asic_reg/tpc7_qm_regs.h (renamed from drivers/misc/habanalabs/include/gaudi/asic_reg/tpc7_qm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/gaudi.h (renamed from drivers/misc/habanalabs/include/gaudi/gaudi.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/gaudi_async_events.h (renamed from drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h (renamed from drivers/misc/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/gaudi_coresight.h (renamed from drivers/misc/habanalabs/include/gaudi/gaudi_coresight.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/gaudi_fw_if.h (renamed from drivers/misc/habanalabs/include/gaudi/gaudi_fw_if.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/gaudi_masks.h (renamed from drivers/misc/habanalabs/include/gaudi/gaudi_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/gaudi_packets.h (renamed from drivers/misc/habanalabs/include/gaudi/gaudi_packets.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi/gaudi_reg_map.h (renamed from drivers/misc/habanalabs/include/gaudi/gaudi_reg_map.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/arc/gaudi2_arc_common_packets.h211
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/arc_farm_arc0_acp_eng_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/arc_farm_arc0_acp_eng_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/arc_farm_arc0_aux_masks.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/arc_farm_arc0_aux_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/arc_farm_arc0_aux_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/arc_farm_arc0_aux_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/arc_farm_arc0_dup_eng_axuser_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/arc_farm_arc0_dup_eng_axuser_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/arc_farm_arc0_dup_eng_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/arc_farm_arc0_dup_eng_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_ctx_axuser_masks.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_ctx_axuser_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_ctx_axuser_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_ctx_axuser_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_ctx_masks.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_ctx_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_ctx_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_ctx_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_kdma_cgm_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_kdma_cgm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_masks.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/cpu_if_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/cpu_if_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_dec0_cmd_masks.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_dec0_cmd_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_dec0_cmd_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_dec0_cmd_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_core_ctx_axuser_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_core_ctx_axuser_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_core_ctx_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_core_ctx_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_core_masks.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_core_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_core_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_core_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_qm_arc_aux_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_qm_arc_aux_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_qm_axuser_nonsecured_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_qm_axuser_nonsecured_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_qm_cgm_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_qm_cgm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_qm_masks.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_qm_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_qm_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_qm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_edma1_core_ctx_axuser_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_edma1_core_ctx_axuser_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_edma1_qm_axuser_nonsecured_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_edma1_qm_axuser_nonsecured_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_hmmu0_mmu_masks.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_hmmu0_mmu_masks.h)15
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_hmmu0_mmu_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_hmmu0_mmu_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_hmmu0_stlb_masks.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_hmmu0_stlb_masks.h)41
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_hmmu0_stlb_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_hmmu0_stlb_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_acc_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_acc_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_cout0_master_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_cout0_master_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_cout0_slave_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_cout0_slave_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_cout1_master_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_cout1_master_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_cout1_slave_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_cout1_slave_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in0_master_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in0_master_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in0_slave_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in0_slave_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in1_master_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in1_master_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in1_slave_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in1_slave_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in2_master_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in2_master_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in2_slave_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in2_slave_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in3_master_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in3_master_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in3_slave_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in3_slave_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in4_master_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in4_master_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in4_slave_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in4_slave_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_base_addr_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_base_addr_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_non_tensor_end_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_non_tensor_end_regs.h)6
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_non_tensor_start_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_non_tensor_start_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_tensor_a_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_tensor_a_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_tensor_b_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_tensor_b_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_tensor_cout_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_tensor_cout_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_masks.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_masks.h)9
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_mme_axuser_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_mme_axuser_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_arc_acp_eng_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_arc_acp_eng_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_arc_aux_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_arc_aux_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_arc_dup_eng_axuser_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_arc_dup_eng_axuser_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_arc_dup_eng_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_arc_dup_eng_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_axuser_nonsecured_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_axuser_nonsecured_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_axuser_secured_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_axuser_secured_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_cgm_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_cgm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_sbte0_masks.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_sbte0_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_sbte0_mstr_if_axuser_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_sbte0_mstr_if_axuser_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_wb0_mstr_if_axuser_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_wb0_mstr_if_axuser_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_rtr0_ctrl_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_rtr0_ctrl_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_rtr0_mstr_if_rr_prvt_hbw_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_rtr0_mstr_if_rr_prvt_hbw_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_rtr0_mstr_if_rr_prvt_lbw_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_rtr0_mstr_if_rr_prvt_lbw_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_rtr0_mstr_if_rr_shrd_hbw_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_rtr0_mstr_if_rr_shrd_hbw_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_rtr0_mstr_if_rr_shrd_lbw_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_rtr0_mstr_if_rr_shrd_lbw_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_sync_mngr_glbl_masks.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_sync_mngr_glbl_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_sync_mngr_glbl_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_sync_mngr_glbl_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_sync_mngr_mstr_if_axuser_masks.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_sync_mngr_mstr_if_axuser_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_sync_mngr_mstr_if_axuser_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_sync_mngr_mstr_if_axuser_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_sync_mngr_objs_masks.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_sync_mngr_objs_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_sync_mngr_objs_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_sync_mngr_objs_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_axuser_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_axuser_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_kernel_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_kernel_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_kernel_tensor_0_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_kernel_tensor_0_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_masks.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_qm_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_qm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_qm_sync_object_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_qm_sync_object_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_qm_tensor_0_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_qm_tensor_0_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_special_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_special_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_eml_busmon_0_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_eml_busmon_0_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_eml_etf_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_eml_etf_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_eml_funnel_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_eml_funnel_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_eml_spmu_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_eml_spmu_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_eml_stm_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_eml_stm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_qm_arc_aux_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_qm_arc_aux_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_qm_axuser_nonsecured_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_qm_axuser_nonsecured_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_qm_cgm_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_qm_cgm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_qm_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_qm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_axuser_dec_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_axuser_dec_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_axuser_msix_abnrm_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_axuser_msix_abnrm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_axuser_msix_l2c_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_axuser_msix_l2c_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_axuser_msix_nrm_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_axuser_msix_nrm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_axuser_msix_vcd_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_axuser_msix_vcd_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_masks.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_masks.h)6
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_ctrl_special_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_ctrl_special_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore1_mme_ctrl_lo_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore1_mme_ctrl_lo_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore1_sync_mngr_glbl_regs.h1203
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore3_mme_ctrl_lo_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore3_mme_ctrl_lo_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/gaudi2_blocks_linux_driver.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/gaudi2_blocks_linux_driver.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/gaudi2_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/gaudi2_regs.h)1
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/nic0_qm0_cgm_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/nic0_qm0_cgm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/nic0_qm0_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/nic0_qm0_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/nic0_qm_arc_aux0_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/nic0_qm_arc_aux0_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/nic0_qpc0_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/nic0_qpc0_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/nic0_umr0_0_completion_queue_ci_1_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/nic0_umr0_0_completion_queue_ci_1_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/nic0_umr0_0_unsecure_doorbell0_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/nic0_umr0_0_unsecure_doorbell0_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_aux_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_aux_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_dbi_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_dbi_regs.h)3
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_dec0_cmd_masks.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_dec0_cmd_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_dec0_cmd_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_dec0_cmd_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_axuser_dec_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_axuser_dec_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_axuser_msix_abnrm_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_axuser_msix_abnrm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_axuser_msix_l2c_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_axuser_msix_l2c_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_axuser_msix_nrm_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_axuser_msix_nrm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_axuser_msix_vcd_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_axuser_msix_vcd_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_masks.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_masks.h)3
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_ctrl_special_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_ctrl_special_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_wrap_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_wrap_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_wrap_special_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_wrap_special_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma0_core_ctx_axuser_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma0_core_ctx_axuser_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma0_core_ctx_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma0_core_ctx_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma0_core_masks.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma0_core_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma0_core_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma0_core_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma0_core_special_masks.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma0_core_special_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma0_qm_arc_aux_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma0_qm_arc_aux_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma0_qm_axuser_nonsecured_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma0_qm_axuser_nonsecured_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma0_qm_axuser_secured_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma0_qm_axuser_secured_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma0_qm_cgm_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma0_qm_cgm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma0_qm_masks.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma0_qm_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma0_qm_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma0_qm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma1_core_ctx_axuser_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma1_core_ctx_axuser_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma1_qm_axuser_nonsecured_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma1_qm_axuser_nonsecured_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/pmmu_hbw_stlb_masks.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/pmmu_hbw_stlb_masks.h)3
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/pmmu_hbw_stlb_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/pmmu_hbw_stlb_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/pmmu_pif_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/pmmu_pif_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/psoc_etr_masks.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/psoc_etr_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/psoc_etr_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/psoc_etr_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/psoc_global_conf_masks.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/psoc_global_conf_masks.h)27
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/psoc_global_conf_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/psoc_global_conf_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/psoc_reset_conf_masks.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/psoc_reset_conf_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/psoc_reset_conf_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/psoc_reset_conf_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/psoc_timestamp_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/psoc_timestamp_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/rot0_desc_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/rot0_desc_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/rot0_masks.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/rot0_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/rot0_qm_arc_aux_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/rot0_qm_arc_aux_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/rot0_qm_axuser_nonsecured_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/rot0_qm_axuser_nonsecured_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/rot0_qm_cgm_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/rot0_qm_cgm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/rot0_qm_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/rot0_qm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/rot0_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/rot0_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/xbar_edge_0_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/xbar_edge_0_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/asic_reg/xbar_mid_0_regs.h (renamed from drivers/misc/habanalabs/include/gaudi2/asic_reg/xbar_mid_0_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/gaudi2.h (renamed from drivers/misc/habanalabs/include/gaudi2/gaudi2.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/gaudi2_async_events.h (renamed from drivers/misc/habanalabs/include/gaudi2/gaudi2_async_events.h)1
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/gaudi2_async_ids_map_extended.h (renamed from drivers/misc/habanalabs/include/gaudi2/gaudi2_async_ids_map_extended.h)2
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/gaudi2_coresight.h (renamed from drivers/misc/habanalabs/include/gaudi2/gaudi2_coresight.h)0
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/gaudi2_fw_if.h (renamed from drivers/misc/habanalabs/include/gaudi2/gaudi2_fw_if.h)23
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/gaudi2_packets.h (renamed from drivers/misc/habanalabs/include/gaudi2/gaudi2_packets.h)4
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/gaudi2_reg_map.h (renamed from drivers/misc/habanalabs/include/gaudi2/gaudi2_reg_map.h)16
-rw-r--r--drivers/accel/habanalabs/include/gaudi2/gaudi2_special_blocks.h157
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/cpu_ca53_cfg_masks.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/cpu_ca53_cfg_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/cpu_ca53_cfg_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/cpu_ca53_cfg_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/cpu_if_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/cpu_if_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/cpu_pll_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/cpu_pll_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/dma_ch_0_masks.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/dma_ch_0_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/dma_ch_0_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/dma_ch_0_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/dma_ch_1_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/dma_ch_1_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/dma_ch_2_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/dma_ch_2_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/dma_ch_3_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/dma_ch_3_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/dma_ch_4_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/dma_ch_4_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/dma_macro_masks.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/dma_macro_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/dma_macro_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/dma_macro_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/dma_nrtr_masks.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/dma_nrtr_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/dma_nrtr_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/dma_nrtr_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/dma_qm_0_masks.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/dma_qm_0_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/dma_qm_0_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/dma_qm_0_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/dma_qm_1_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/dma_qm_1_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/dma_qm_2_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/dma_qm_2_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/dma_qm_3_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/dma_qm_3_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/dma_qm_4_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/dma_qm_4_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/goya_blocks.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/goya_blocks.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/goya_masks.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/goya_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/goya_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/goya_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/ic_pll_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/ic_pll_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/mc_pll_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/mc_pll_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/mme1_rtr_masks.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/mme1_rtr_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/mme1_rtr_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/mme1_rtr_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/mme2_rtr_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/mme2_rtr_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/mme3_rtr_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/mme3_rtr_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/mme4_rtr_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/mme4_rtr_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/mme5_rtr_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/mme5_rtr_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/mme6_rtr_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/mme6_rtr_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/mme_cmdq_masks.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/mme_cmdq_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/mme_cmdq_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/mme_cmdq_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/mme_masks.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/mme_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/mme_qm_masks.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/mme_qm_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/mme_qm_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/mme_qm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/mme_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/mme_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/mmu_masks.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/mmu_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/mmu_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/mmu_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/pci_nrtr_masks.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/pci_nrtr_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/pci_nrtr_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/pci_nrtr_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/pcie_aux_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/pcie_aux_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/pcie_wrap_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/pcie_wrap_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/psoc_emmc_pll_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/psoc_emmc_pll_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/psoc_etr_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/psoc_etr_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/psoc_global_conf_masks.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/psoc_global_conf_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/psoc_global_conf_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/psoc_global_conf_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/psoc_mme_pll_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/psoc_mme_pll_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/psoc_pci_pll_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/psoc_pci_pll_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/psoc_spi_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/psoc_spi_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/psoc_timestamp_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/psoc_timestamp_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/sram_y0_x0_rtr_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/sram_y0_x0_rtr_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/sram_y0_x1_rtr_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/sram_y0_x1_rtr_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/sram_y0_x2_rtr_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/sram_y0_x2_rtr_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/sram_y0_x3_rtr_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/sram_y0_x3_rtr_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/sram_y0_x4_rtr_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/sram_y0_x4_rtr_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/stlb_masks.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/stlb_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/stlb_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/stlb_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc0_cfg_masks.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc0_cfg_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc0_cfg_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc0_cfg_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc0_cmdq_masks.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc0_cmdq_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc0_cmdq_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc0_cmdq_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc0_eml_cfg_masks.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc0_eml_cfg_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc0_eml_cfg_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc0_eml_cfg_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc0_nrtr_masks.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc0_nrtr_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc0_nrtr_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc0_nrtr_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc0_qm_masks.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc0_qm_masks.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc0_qm_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc0_qm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc1_cfg_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc1_cfg_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc1_cmdq_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc1_cmdq_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc1_qm_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc1_qm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc1_rtr_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc1_rtr_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc2_cfg_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc2_cfg_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc2_cmdq_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc2_cmdq_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc2_qm_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc2_qm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc2_rtr_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc2_rtr_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc3_cfg_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc3_cfg_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc3_cmdq_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc3_cmdq_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc3_qm_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc3_qm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc3_rtr_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc3_rtr_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc4_cfg_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc4_cfg_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc4_cmdq_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc4_cmdq_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc4_qm_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc4_qm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc4_rtr_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc4_rtr_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc5_cfg_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc5_cfg_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc5_cmdq_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc5_cmdq_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc5_qm_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc5_qm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc5_rtr_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc5_rtr_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc6_cfg_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc6_cfg_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc6_cmdq_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc6_cmdq_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc6_qm_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc6_qm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc6_rtr_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc6_rtr_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc7_cfg_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc7_cfg_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc7_cmdq_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc7_cmdq_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc7_nrtr_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc7_nrtr_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc7_qm_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc7_qm_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/asic_reg/tpc_pll_regs.h (renamed from drivers/misc/habanalabs/include/goya/asic_reg/tpc_pll_regs.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/goya.h (renamed from drivers/misc/habanalabs/include/goya/goya.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/goya_async_events.h (renamed from drivers/misc/habanalabs/include/goya/goya_async_events.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/goya_coresight.h (renamed from drivers/misc/habanalabs/include/goya/goya_coresight.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/goya_fw_if.h (renamed from drivers/misc/habanalabs/include/goya/goya_fw_if.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/goya_packets.h (renamed from drivers/misc/habanalabs/include/goya/goya_packets.h)0
-rw-r--r--drivers/accel/habanalabs/include/goya/goya_reg_map.h (renamed from drivers/misc/habanalabs/include/goya/goya_reg_map.h)0
-rw-r--r--drivers/accel/habanalabs/include/hw_ip/mmu/mmu_general.h (renamed from drivers/misc/habanalabs/include/hw_ip/mmu/mmu_general.h)0
-rw-r--r--drivers/accel/habanalabs/include/hw_ip/mmu/mmu_v1_0.h (renamed from drivers/misc/habanalabs/include/hw_ip/mmu/mmu_v1_0.h)0
-rw-r--r--drivers/accel/habanalabs/include/hw_ip/mmu/mmu_v1_1.h (renamed from drivers/misc/habanalabs/include/hw_ip/mmu/mmu_v1_1.h)0
-rw-r--r--drivers/accel/habanalabs/include/hw_ip/mmu/mmu_v2_0.h (renamed from drivers/misc/habanalabs/include/hw_ip/mmu/mmu_v2_0.h)0
-rw-r--r--drivers/accel/habanalabs/include/hw_ip/pci/pci_general.h (renamed from drivers/misc/habanalabs/include/hw_ip/pci/pci_general.h)0
-rw-r--r--drivers/accel/ivpu/Kconfig15
-rw-r--r--drivers/accel/ivpu/Makefile16
-rw-r--r--drivers/accel/ivpu/TODO11
-rw-r--r--drivers/accel/ivpu/ivpu_drv.c655
-rw-r--r--drivers/accel/ivpu/ivpu_drv.h190
-rw-r--r--drivers/accel/ivpu/ivpu_fw.c434
-rw-r--r--drivers/accel/ivpu/ivpu_fw.h38
-rw-r--r--drivers/accel/ivpu/ivpu_gem.c749
-rw-r--r--drivers/accel/ivpu/ivpu_gem.h127
-rw-r--r--drivers/accel/ivpu/ivpu_hw.h170
-rw-r--r--drivers/accel/ivpu/ivpu_hw_mtl.c1084
-rw-r--r--drivers/accel/ivpu/ivpu_hw_mtl_reg.h280
-rw-r--r--drivers/accel/ivpu/ivpu_hw_reg_io.h115
-rw-r--r--drivers/accel/ivpu/ivpu_ipc.c510
-rw-r--r--drivers/accel/ivpu/ivpu_ipc.h93
-rw-r--r--drivers/accel/ivpu/ivpu_job.c615
-rw-r--r--drivers/accel/ivpu/ivpu_job.h67
-rw-r--r--drivers/accel/ivpu/ivpu_jsm_msg.c180
-rw-r--r--drivers/accel/ivpu/ivpu_jsm_msg.h23
-rw-r--r--drivers/accel/ivpu/ivpu_mmu.c883
-rw-r--r--drivers/accel/ivpu/ivpu_mmu.h50
-rw-r--r--drivers/accel/ivpu/ivpu_mmu_context.c398
-rw-r--r--drivers/accel/ivpu/ivpu_mmu_context.h50
-rw-r--r--drivers/accel/ivpu/ivpu_pm.c329
-rw-r--r--drivers/accel/ivpu/ivpu_pm.h38
-rw-r--r--drivers/accel/ivpu/vpu_boot_api.h349
-rw-r--r--drivers/accel/ivpu/vpu_jsm_api.h1008
-rw-r--r--drivers/accessibility/speakup/main.c2
-rw-r--r--drivers/acpi/bus.c2
-rw-r--r--drivers/acpi/device_pm.c19
-rw-r--r--drivers/acpi/device_sysfs.c8
-rw-r--r--drivers/acpi/internal.h2
-rw-r--r--drivers/acpi/numa/hmat.c4
-rw-r--r--drivers/acpi/pci_root.c3
-rw-r--r--drivers/acpi/pfr_telemetry.c2
-rw-r--r--drivers/acpi/pptt.c93
-rw-r--r--drivers/amba/bus.c4
-rw-r--r--drivers/android/binder.c68
-rw-r--r--drivers/android/binder_alloc.c2
-rw-r--r--drivers/android/binder_internal.h3
-rw-r--r--drivers/android/binderfs.c4
-rw-r--r--drivers/ata/Kconfig14
-rw-r--r--drivers/ata/Makefile2
-rw-r--r--drivers/ata/acard-ahci.c8
-rw-r--r--drivers/ata/ahci_octeon.c6
-rw-r--r--drivers/ata/libahci.c171
-rw-r--r--drivers/ata/libata-core.c81
-rw-r--r--drivers/ata/libata-eh.c117
-rw-r--r--drivers/ata/libata-sata.c7
-rw-r--r--drivers/ata/libata-scsi.c64
-rw-r--r--drivers/ata/libata-sff.c10
-rw-r--r--drivers/ata/libata-trace.c2
-rw-r--r--drivers/ata/pata_parport/Kconfig141
-rw-r--r--drivers/ata/pata_parport/Makefile19
-rw-r--r--drivers/ata/pata_parport/aten.c (renamed from drivers/block/paride/aten.c)2
-rw-r--r--drivers/ata/pata_parport/bpck.c (renamed from drivers/block/paride/bpck.c)2
-rw-r--r--drivers/ata/pata_parport/bpck6.c (renamed from drivers/block/paride/bpck6.c)2
-rw-r--r--drivers/ata/pata_parport/comm.c (renamed from drivers/block/paride/comm.c)2
-rw-r--r--drivers/ata/pata_parport/dstr.c (renamed from drivers/block/paride/dstr.c)2
-rw-r--r--drivers/ata/pata_parport/epat.c (renamed from drivers/block/paride/epat.c)2
-rw-r--r--drivers/ata/pata_parport/epia.c (renamed from drivers/block/paride/epia.c)2
-rw-r--r--drivers/ata/pata_parport/fit2.c (renamed from drivers/block/paride/fit2.c)2
-rw-r--r--drivers/ata/pata_parport/fit3.c (renamed from drivers/block/paride/fit3.c)2
-rw-r--r--drivers/ata/pata_parport/friq.c (renamed from drivers/block/paride/friq.c)2
-rw-r--r--drivers/ata/pata_parport/frpw.c (renamed from drivers/block/paride/frpw.c)2
-rw-r--r--drivers/ata/pata_parport/kbic.c (renamed from drivers/block/paride/kbic.c)2
-rw-r--r--drivers/ata/pata_parport/ktti.c (renamed from drivers/block/paride/ktti.c)2
-rw-r--r--drivers/ata/pata_parport/on20.c (renamed from drivers/block/paride/on20.c)2
-rw-r--r--drivers/ata/pata_parport/on26.c (renamed from drivers/block/paride/on26.c)2
-rw-r--r--drivers/ata/pata_parport/pata_parport.c761
-rw-r--r--drivers/ata/pata_parport/ppc6lnx.c (renamed from drivers/block/paride/ppc6lnx.c)0
-rw-r--r--drivers/ata/sata_fsl.c5
-rw-r--r--drivers/ata/sata_inic162x.c14
-rw-r--r--drivers/ata/sata_promise.c2
-rw-r--r--drivers/ata/sata_sil24.c7
-rw-r--r--drivers/ata/sata_sx4.c2
-rw-r--r--drivers/auxdisplay/hd44780.c2
-rw-r--r--drivers/base/arch_topology.c12
-rw-r--r--drivers/base/auxiliary.c2
-rw-r--r--drivers/base/base.h21
-rw-r--r--drivers/base/bus.c575
-rw-r--r--drivers/base/cacheinfo.c161
-rw-r--r--drivers/base/class.c34
-rw-r--r--drivers/base/component.c2
-rw-r--r--drivers/base/core.c495
-rw-r--r--drivers/base/cpu.c40
-rw-r--r--drivers/base/dd.c36
-rw-r--r--drivers/base/devtmpfs.c16
-rw-r--r--drivers/base/driver.c29
-rw-r--r--drivers/base/memory.c9
-rw-r--r--drivers/base/node.c3
-rw-r--r--drivers/base/physical_location.c5
-rw-r--r--drivers/base/platform.c48
-rw-r--r--drivers/base/power/domain.c26
-rw-r--r--drivers/base/regmap/regmap-irq.c25
-rw-r--r--drivers/base/regmap/regmap.c6
-rw-r--r--drivers/base/soc.c4
-rw-r--r--drivers/base/swnode.c63
-rw-r--r--drivers/base/test/property-entry-test.c30
-rw-r--r--drivers/base/transport_class.c17
-rw-r--r--drivers/bcma/main.c6
-rw-r--r--drivers/block/Kconfig29
-rw-r--r--drivers/block/brd.c15
-rw-r--r--drivers/block/paride/Kconfig302
-rw-r--r--drivers/block/paride/Makefile29
-rw-r--r--drivers/block/paride/Transition-notes128
-rw-r--r--drivers/block/paride/mkd31
-rw-r--r--drivers/block/paride/paride.c479
-rw-r--r--drivers/block/paride/paride.h172
-rw-r--r--drivers/block/paride/pcd.c1042
-rw-r--r--drivers/block/paride/pd.c1032
-rw-r--r--drivers/block/paride/pf.c1057
-rw-r--r--drivers/block/paride/pg.c734
-rw-r--r--drivers/block/paride/pseudo.h102
-rw-r--r--drivers/block/paride/pt.c1024
-rw-r--r--drivers/block/rbd.c20
-rw-r--r--drivers/block/virtio_blk.c468
-rw-r--r--drivers/block/zram/zram_drv.c69
-rw-r--r--drivers/bus/fsl-mc/fsl-mc-bus.c4
-rw-r--r--drivers/bus/imx-weim.c4
-rw-r--r--drivers/bus/mhi/Makefile4
-rw-r--r--drivers/bus/mhi/ep/main.c89
-rw-r--r--drivers/bus/mhi/ep/sm.c42
-rw-r--r--drivers/bus/mhi/host/init.c6
-rw-r--r--drivers/bus/mips_cdmm.c4
-rw-r--r--drivers/bus/simple-pm-bus.c46
-rw-r--r--drivers/bus/sunxi-rsb.c7
-rw-r--r--drivers/char/applicom.c5
-rw-r--r--drivers/char/ipmi/ipmi_ipmb.c2
-rw-r--r--drivers/char/ipmi/ipmi_ssif.c113
-rw-r--r--drivers/char/mem.c2
-rw-r--r--drivers/char/mspec.c2
-rw-r--r--drivers/char/pcmcia/cm4000_cs.c6
-rw-r--r--drivers/char/pcmcia/synclink_cs.c40
-rw-r--r--drivers/char/virtio_console.c5
-rw-r--r--drivers/clk/Kconfig1
-rw-r--r--drivers/clk/at91/Makefile16
-rw-r--r--drivers/clk/at91/at91rm9200.c2
-rw-r--r--drivers/clk/at91/at91sam9260.c2
-rw-r--r--drivers/clk/at91/at91sam9g45.c10
-rw-r--r--drivers/clk/at91/at91sam9n12.c12
-rw-r--r--drivers/clk/at91/at91sam9rl.c2
-rw-r--r--drivers/clk/at91/at91sam9x5.c17
-rw-r--r--drivers/clk/at91/clk-peripheral.c8
-rw-r--r--drivers/clk/at91/clk-system.c4
-rw-r--r--drivers/clk/at91/dt-compat.c25
-rw-r--r--drivers/clk/at91/pmc.h4
-rw-r--r--drivers/clk/at91/sam9x60.c20
-rw-r--r--drivers/clk/at91/sama5d2.c22
-rw-r--r--drivers/clk/at91/sama5d3.c20
-rw-r--r--drivers/clk/at91/sama5d4.c22
-rw-r--r--drivers/clk/at91/sama7g5.c4
-rw-r--r--drivers/clk/clk-renesas-pcie.c1
-rw-r--r--drivers/clk/clk-versaclock5.c28
-rw-r--r--drivers/clk/clk.c11
-rw-r--r--drivers/clk/imx/Kconfig2
-rw-r--r--drivers/clk/imx/Makefile1
-rw-r--r--drivers/clk/imx/clk-gpr-mux.c119
-rw-r--r--drivers/clk/imx/clk-imx25.c2
-rw-r--r--drivers/clk/imx/clk-imx27.c2
-rw-r--r--drivers/clk/imx/clk-imx35.c2
-rw-r--r--drivers/clk/imx/clk-imx5.c6
-rw-r--r--drivers/clk/imx/clk-imx6q.c15
-rw-r--r--drivers/clk/imx/clk-imx6sl.c2
-rw-r--r--drivers/clk/imx/clk-imx6sll.c2
-rw-r--r--drivers/clk/imx/clk-imx6sx.c2
-rw-r--r--drivers/clk/imx/clk-imx6ul.c33
-rw-r--r--drivers/clk/imx/clk-imx7d.c2
-rw-r--r--drivers/clk/imx/clk-imx7ulp.c4
-rw-r--r--drivers/clk/imx/clk-imx8mm.c2
-rw-r--r--drivers/clk/imx/clk-imx8mn.c2
-rw-r--r--drivers/clk/imx/clk-imx8mp.c2
-rw-r--r--drivers/clk/imx/clk-imx8mq.c2
-rw-r--r--drivers/clk/imx/clk-imx8ulp.c2
-rw-r--r--drivers/clk/imx/clk-imx93.c2
-rw-r--r--drivers/clk/imx/clk-imxrt1050.c4
-rw-r--r--drivers/clk/imx/clk-pfd.c2
-rw-r--r--drivers/clk/imx/clk-pll14xx.c2
-rw-r--r--drivers/clk/imx/clk-pllv3.c2
-rw-r--r--drivers/clk/imx/clk.c31
-rw-r--r--drivers/clk/imx/clk.h12
-rw-r--r--drivers/clk/mediatek/Kconfig49
-rw-r--r--drivers/clk/mediatek/Makefile10
-rw-r--r--drivers/clk/mediatek/clk-cpumux.c8
-rw-r--r--drivers/clk/mediatek/clk-cpumux.h2
-rw-r--r--drivers/clk/mediatek/clk-gate.c23
-rw-r--r--drivers/clk/mediatek/clk-gate.h7
-rw-r--r--drivers/clk/mediatek/clk-mt2701-aud.c31
-rw-r--r--drivers/clk/mediatek/clk-mt2701-eth.c36
-rw-r--r--drivers/clk/mediatek/clk-mt2701-g3d.c56
-rw-r--r--drivers/clk/mediatek/clk-mt2701-hif.c38
-rw-r--r--drivers/clk/mediatek/clk-mt2701-mm.c4
-rw-r--r--drivers/clk/mediatek/clk-mt2701.c24
-rw-r--r--drivers/clk/mediatek/clk-mt2712-mm.c4
-rw-r--r--drivers/clk/mediatek/clk-mt2712.c99
-rw-r--r--drivers/clk/mediatek/clk-mt6765.c13
-rw-r--r--drivers/clk/mediatek/clk-mt6779-mm.c4
-rw-r--r--drivers/clk/mediatek/clk-mt6779.c59
-rw-r--r--drivers/clk/mediatek/clk-mt6795-infracfg.c6
-rw-r--r--drivers/clk/mediatek/clk-mt6795-mm.c3
-rw-r--r--drivers/clk/mediatek/clk-mt6795-pericfg.c6
-rw-r--r--drivers/clk/mediatek/clk-mt6795-topckgen.c84
-rw-r--r--drivers/clk/mediatek/clk-mt6797-mm.c4
-rw-r--r--drivers/clk/mediatek/clk-mt6797.c7
-rw-r--r--drivers/clk/mediatek/clk-mt7622-aud.c54
-rw-r--r--drivers/clk/mediatek/clk-mt7622-eth.c82
-rw-r--r--drivers/clk/mediatek/clk-mt7622-hif.c85
-rw-r--r--drivers/clk/mediatek/clk-mt7622.c26
-rw-r--r--drivers/clk/mediatek/clk-mt7629-eth.c7
-rw-r--r--drivers/clk/mediatek/clk-mt7629-hif.c85
-rw-r--r--drivers/clk/mediatek/clk-mt7629.c22
-rw-r--r--drivers/clk/mediatek/clk-mt7981-apmixed.c102
-rw-r--r--drivers/clk/mediatek/clk-mt7981-eth.c118
-rw-r--r--drivers/clk/mediatek/clk-mt7981-infracfg.c207
-rw-r--r--drivers/clk/mediatek/clk-mt7981-topckgen.c422
-rw-r--r--drivers/clk/mediatek/clk-mt7986-eth.c10
-rw-r--r--drivers/clk/mediatek/clk-mt7986-infracfg.c7
-rw-r--r--drivers/clk/mediatek/clk-mt7986-topckgen.c100
-rw-r--r--drivers/clk/mediatek/clk-mt8135.c18
-rw-r--r--drivers/clk/mediatek/clk-mt8167-aud.c2
-rw-r--r--drivers/clk/mediatek/clk-mt8167-img.c2
-rw-r--r--drivers/clk/mediatek/clk-mt8167-mfgcfg.c2
-rw-r--r--drivers/clk/mediatek/clk-mt8167-mm.c4
-rw-r--r--drivers/clk/mediatek/clk-mt8167-vdec.c3
-rw-r--r--drivers/clk/mediatek/clk-mt8167.c12
-rw-r--r--drivers/clk/mediatek/clk-mt8173-apmixedsys.c157
-rw-r--r--drivers/clk/mediatek/clk-mt8173-img.c55
-rw-r--r--drivers/clk/mediatek/clk-mt8173-infracfg.c155
-rw-r--r--drivers/clk/mediatek/clk-mt8173-mm.c22
-rw-r--r--drivers/clk/mediatek/clk-mt8173-pericfg.c122
-rw-r--r--drivers/clk/mediatek/clk-mt8173-topckgen.c653
-rw-r--r--drivers/clk/mediatek/clk-mt8173-vdecsys.c57
-rw-r--r--drivers/clk/mediatek/clk-mt8173-vencsys.c64
-rw-r--r--drivers/clk/mediatek/clk-mt8173.c1125
-rw-r--r--drivers/clk/mediatek/clk-mt8183-audio.c27
-rw-r--r--drivers/clk/mediatek/clk-mt8183-mm.c4
-rw-r--r--drivers/clk/mediatek/clk-mt8183.c130
-rw-r--r--drivers/clk/mediatek/clk-mt8186-mcu.c3
-rw-r--r--drivers/clk/mediatek/clk-mt8186-mm.c3
-rw-r--r--drivers/clk/mediatek/clk-mt8186-topckgen.c112
-rw-r--r--drivers/clk/mediatek/clk-mt8192-aud.c30
-rw-r--r--drivers/clk/mediatek/clk-mt8192-mm.c3
-rw-r--r--drivers/clk/mediatek/clk-mt8192.c182
-rw-r--r--drivers/clk/mediatek/clk-mt8195-apmixedsys.c3
-rw-r--r--drivers/clk/mediatek/clk-mt8195-topckgen.c9
-rw-r--r--drivers/clk/mediatek/clk-mt8195-vdo0.c3
-rw-r--r--drivers/clk/mediatek/clk-mt8195-vdo1.c3
-rw-r--r--drivers/clk/mediatek/clk-mt8195-vpp0.c58
-rw-r--r--drivers/clk/mediatek/clk-mt8195-vpp1.c58
-rw-r--r--drivers/clk/mediatek/clk-mt8365-mm.c5
-rw-r--r--drivers/clk/mediatek/clk-mt8365.c14
-rw-r--r--drivers/clk/mediatek/clk-mt8516-aud.c2
-rw-r--r--drivers/clk/mediatek/clk-mt8516.c12
-rw-r--r--drivers/clk/mediatek/clk-mtk.c136
-rw-r--r--drivers/clk/mediatek/clk-mtk.h35
-rw-r--r--drivers/clk/mediatek/clk-mux.c14
-rw-r--r--drivers/clk/mediatek/clk-mux.h3
-rw-r--r--drivers/clk/meson/clk-cpu-dyndiv.c9
-rw-r--r--drivers/clk/meson/clk-dualdiv.c21
-rw-r--r--drivers/clk/meson/clk-mpll.c20
-rw-r--r--drivers/clk/meson/sclk-div.c11
-rw-r--r--drivers/clk/qcom/Kconfig40
-rw-r--r--drivers/clk/qcom/Makefile7
-rw-r--r--drivers/clk/qcom/apcs-msm8996.c89
-rw-r--r--drivers/clk/qcom/camcc-sc7280.c268
-rw-r--r--drivers/clk/qcom/camcc-sm6350.c1906
-rw-r--r--drivers/clk/qcom/camcc-sm8450.c324
-rw-r--r--drivers/clk/qcom/clk-alpha-pll.c5
-rw-r--r--drivers/clk/qcom/clk-alpha-pll.h1
-rw-r--r--drivers/clk/qcom/clk-cbf-8996.c315
-rw-r--r--drivers/clk/qcom/clk-cpu-8996.c146
-rw-r--r--drivers/clk/qcom/clk-rpmh.c56
-rw-r--r--drivers/clk/qcom/clk-smd-rpm.c1445
-rw-r--r--drivers/clk/qcom/clk-spmi-pmic-div.c10
-rw-r--r--drivers/clk/qcom/dispcc-qcm2290.c6
-rw-r--r--drivers/clk/qcom/dispcc-sc7180.c8
-rw-r--r--drivers/clk/qcom/dispcc-sm6115.c4
-rw-r--r--drivers/clk/qcom/dispcc-sm6125.c2
-rw-r--r--drivers/clk/qcom/dispcc-sm6375.c4
-rw-r--r--drivers/clk/qcom/dispcc-sm8250.c9
-rw-r--r--drivers/clk/qcom/dispcc-sm8450.c221
-rw-r--r--drivers/clk/qcom/dispcc-sm8550.c1807
-rw-r--r--drivers/clk/qcom/gcc-apq8084.c1024
-rw-r--r--drivers/clk/qcom/gcc-ipq8074.c4
-rw-r--r--drivers/clk/qcom/gcc-msm8939.c32
-rw-r--r--drivers/clk/qcom/gcc-msm8974.c10
-rw-r--r--drivers/clk/qcom/gcc-msm8976.c30
-rw-r--r--drivers/clk/qcom/gcc-msm8998.c13
-rw-r--r--drivers/clk/qcom/gcc-qcs404.c842
-rw-r--r--drivers/clk/qcom/gcc-qdu1000.c2653
-rw-r--r--drivers/clk/qcom/gcc-sa8775p.c4785
-rw-r--r--drivers/clk/qcom/gcc-sc7180.c19
-rw-r--r--drivers/clk/qcom/gcc-sc7280.c10
-rw-r--r--drivers/clk/qcom/gcc-sdx55.c64
-rw-r--r--drivers/clk/qcom/gcc-sdx65.c109
-rw-r--r--drivers/clk/qcom/gcc-sm6115.c4
-rw-r--r--drivers/clk/qcom/gcc-sm6375.c257
-rw-r--r--drivers/clk/qcom/gcc-sm8150.c17
-rw-r--r--drivers/clk/qcom/gcc-sm8250.c10
-rw-r--r--drivers/clk/qcom/gcc-sm8350.c15
-rw-r--r--drivers/clk/qcom/gcc-sm8450.c236
-rw-r--r--drivers/clk/qcom/gcc-sm8550.c252
-rw-r--r--drivers/clk/qcom/gdsc.c11
-rw-r--r--drivers/clk/qcom/gpucc-msm8998.c8
-rw-r--r--drivers/clk/qcom/gpucc-sc7180.c11
-rw-r--r--drivers/clk/qcom/gpucc-sdm845.c7
-rw-r--r--drivers/clk/qcom/krait-cc.c4
-rw-r--r--drivers/clk/qcom/lpasscc-sc7280.c10
-rw-r--r--drivers/clk/qcom/lpasscorecc-sc7180.c20
-rw-r--r--drivers/clk/qcom/mmcc-apq8084.c1189
-rw-r--r--drivers/clk/qcom/mmcc-msm8998.c25
-rw-r--r--drivers/clk/qcom/tcsrcc-sm8550.c192
-rw-r--r--drivers/clk/qcom/videocc-sm8250.c9
-rw-r--r--drivers/clk/ralink/clk-mt7621.c10
-rw-r--r--drivers/clk/renesas/Kconfig2
-rw-r--r--drivers/clk/renesas/r8a7795-cpg-mssr.c126
-rw-r--r--drivers/clk/renesas/r8a779a0-cpg-mssr.c4
-rw-r--r--drivers/clk/renesas/r8a779g0-cpg-mssr.c37
-rw-r--r--drivers/clk/renesas/r9a06g032-clocks.c28
-rw-r--r--drivers/clk/renesas/r9a07g044-cpg.c26
-rw-r--r--drivers/clk/renesas/r9a09g011-cpg.c73
-rw-r--r--drivers/clk/renesas/rcar-gen3-cpg.c17
-rw-r--r--drivers/clk/renesas/rcar-gen4-cpg.c156
-rw-r--r--drivers/clk/renesas/rcar-gen4-cpg.h3
-rw-r--r--drivers/clk/renesas/renesas-cpg-mssr.c35
-rw-r--r--drivers/clk/renesas/renesas-cpg-mssr.h14
-rw-r--r--drivers/clk/sprd/Kconfig2
-rw-r--r--drivers/clk/sunxi-ng/Kconfig71
-rw-r--r--drivers/clk/sunxi-ng/ccu-sun20i-d1.c13
-rw-r--r--drivers/clk/sunxi-ng/ccu-sun20i-d1.h2
-rw-r--r--drivers/clk/sunxi-ng/ccu-sun8i-h3.c15
-rw-r--r--drivers/clk/sunxi-ng/ccu_mmc_timing.c8
-rw-r--r--drivers/clk/sunxi-ng/ccu_mp.c11
-rw-r--r--drivers/clk/sunxi-ng/ccu_nk.c9
-rw-r--r--drivers/clk/sunxi-ng/ccu_nkm.c10
-rw-r--r--drivers/clk/sunxi-ng/ccu_nkmp.c10
-rw-r--r--drivers/clk/sunxi-ng/ccu_nm.c9
-rw-r--r--drivers/comedi/Kconfig2
-rw-r--r--drivers/comedi/comedi_fops.c1
-rw-r--r--drivers/counter/Kconfig91
-rw-r--r--drivers/cpuidle/cpuidle-qcom-spm.c2
-rw-r--r--drivers/crypto/hisilicon/qm.c171
-rw-r--r--drivers/cxl/Kconfig14
-rw-r--r--drivers/cxl/acpi.c5
-rw-r--r--drivers/cxl/core/Makefile3
-rw-r--r--drivers/cxl/core/core.h7
-rw-r--r--drivers/cxl/core/hdm.c144
-rw-r--r--drivers/cxl/core/mbox.c263
-rw-r--r--drivers/cxl/core/memdev.c7
-rw-r--r--drivers/cxl/core/pci.c316
-rw-r--r--drivers/cxl/core/port.c131
-rw-r--r--drivers/cxl/core/region.c878
-rw-r--r--drivers/cxl/core/trace.c5
-rw-r--r--drivers/cxl/core/trace.h606
-rw-r--r--drivers/cxl/cxl.h100
-rw-r--r--drivers/cxl/cxlmem.h188
-rw-r--r--drivers/cxl/cxlpci.h12
-rw-r--r--drivers/cxl/pci.c425
-rw-r--r--drivers/cxl/pmem.c1
-rw-r--r--drivers/cxl/port.c119
-rw-r--r--drivers/dax/Kconfig17
-rw-r--r--drivers/dax/Makefile2
-rw-r--r--drivers/dax/bus.c57
-rw-r--r--drivers/dax/bus.h12
-rw-r--r--drivers/dax/cxl.c53
-rw-r--r--drivers/dax/device.c5
-rw-r--r--drivers/dax/hmem/Makefile3
-rw-r--r--drivers/dax/hmem/device.c102
-rw-r--r--drivers/dax/hmem/hmem.c148
-rw-r--r--drivers/dax/kmem.c5
-rw-r--r--drivers/dma-buf/dma-buf-sysfs-stats.c2
-rw-r--r--drivers/dma-buf/dma-buf.c14
-rw-r--r--drivers/dma-buf/udmabuf.c28
-rw-r--r--drivers/dma/Kconfig16
-rw-r--r--drivers/dma/at_xdmac.c220
-rw-r--r--drivers/dma/bcm2835-dma.c4
-rw-r--r--drivers/dma/dma-axi-dmac.c4
-rw-r--r--drivers/dma/dmaengine.c26
-rw-r--r--drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c6
-rw-r--r--drivers/dma/dw-edma/Kconfig5
-rw-r--r--drivers/dma/dw-edma/dw-edma-core.c196
-rw-r--r--drivers/dma/dw-edma/dw-edma-core.h10
-rw-r--r--drivers/dma/dw-edma/dw-edma-pcie.c56
-rw-r--r--drivers/dma/dw-edma/dw-edma-v0-core.c100
-rw-r--r--drivers/dma/dw-edma/dw-edma-v0-core.h1
-rw-r--r--drivers/dma/dw-edma/dw-edma-v0-debugfs.c374
-rw-r--r--drivers/dma/dw-edma/dw-edma-v0-debugfs.h5
-rw-r--r--drivers/dma/dw/core.c11
-rw-r--r--drivers/dma/fsl-edma.c8
-rw-r--r--drivers/dma/fsl-qdma.c10
-rw-r--r--drivers/dma/idma64.c8
-rw-r--r--drivers/dma/idxd/cdev.c2
-rw-r--r--drivers/dma/idxd/device.c14
-rw-r--r--drivers/dma/idxd/dma.c6
-rw-r--r--drivers/dma/idxd/init.c7
-rw-r--r--drivers/dma/idxd/sysfs.c4
-rw-r--r--drivers/dma/img-mdc-dma.c4
-rw-r--r--drivers/dma/imx-dma.c4
-rw-r--r--drivers/dma/imx-sdma.c43
-rw-r--r--drivers/dma/mcf-edma.c5
-rw-r--r--drivers/dma/mediatek/mtk-hsdma.c4
-rw-r--r--drivers/dma/mmp_pdma.c4
-rw-r--r--drivers/dma/mmp_tdma.c4
-rw-r--r--drivers/dma/moxart-dma.c4
-rw-r--r--drivers/dma/mv_xor_v2.c7
-rw-r--r--drivers/dma/mxs-dma.c4
-rw-r--r--drivers/dma/nbpfaxi.c4
-rw-r--r--drivers/dma/ppc4xx/adma.c12
-rw-r--r--drivers/dma/ptdma/ptdma-dmaengine.c2
-rw-r--r--drivers/dma/pxa_dma.c4
-rw-r--r--drivers/dma/qcom/bam_dma.c4
-rw-r--r--drivers/dma/sf-pdma/sf-pdma.c7
-rw-r--r--drivers/dma/sf-pdma/sf-pdma.h1
-rw-r--r--drivers/dma/sh/usb-dmac.c4
-rw-r--r--drivers/dma/stm32-dmamux.c4
-rw-r--r--drivers/dma/stm32-mdma.c4
-rw-r--r--drivers/dma/sun4i-dma.c4
-rw-r--r--drivers/dma/sun6i-dma.c7
-rw-r--r--drivers/dma/tegra210-adma.c4
-rw-r--r--drivers/dma/ti/Makefile3
-rw-r--r--drivers/dma/ti/cppi41.c10
-rw-r--r--drivers/dma/ti/k3-psil-am62a.c196
-rw-r--r--drivers/dma/ti/k3-psil-priv.h1
-rw-r--r--drivers/dma/ti/k3-psil.c1
-rw-r--r--drivers/dma/ti/k3-udma.c42
-rw-r--r--drivers/dma/ti/omap-dma.c4
-rw-r--r--drivers/dma/xilinx/Makefile1
-rw-r--r--drivers/dma/xilinx/xdma-regs.h166
-rw-r--r--drivers/dma/xilinx/xdma.c974
-rw-r--r--drivers/dma/xilinx/zynqmp_dma.c4
-rw-r--r--drivers/eisa/eisa-bus.c4
-rw-r--r--drivers/extcon/extcon-intel-cht-wc.c1
-rw-r--r--drivers/firewire/core-cdev.c43
-rw-r--r--drivers/firewire/core-device.c8
-rw-r--r--drivers/firewire/core-transaction.c53
-rw-r--r--drivers/firewire/core.h9
-rw-r--r--drivers/firmware/arm_ffa/bus.c4
-rw-r--r--drivers/firmware/arm_scmi/Kconfig32
-rw-r--r--drivers/firmware/arm_scmi/Makefile9
-rw-r--r--drivers/firmware/arm_scmi/bus.c398
-rw-r--r--drivers/firmware/arm_scmi/common.h100
-rw-r--r--drivers/firmware/arm_scmi/driver.c1223
-rw-r--r--drivers/firmware/arm_scmi/mailbox.c6
-rw-r--r--drivers/firmware/arm_scmi/optee.c6
-rw-r--r--drivers/firmware/arm_scmi/protocols.h7
-rw-r--r--drivers/firmware/arm_scmi/raw_mode.c1443
-rw-r--r--drivers/firmware/arm_scmi/raw_mode.h31
-rw-r--r--drivers/firmware/arm_scmi/smc.c6
-rw-r--r--drivers/firmware/arm_scmi/virtio.c4
-rw-r--r--drivers/firmware/dmi-sysfs.c14
-rw-r--r--drivers/firmware/efi/cper_cxl.c12
-rw-r--r--drivers/firmware/efi/earlycon.c41
-rw-r--r--drivers/firmware/efi/efi-init.c2
-rw-r--r--drivers/firmware/efi/efi.c74
-rw-r--r--drivers/firmware/efi/esrt.c15
-rw-r--r--drivers/firmware/efi/libstub/efi-stub-helper.c67
-rw-r--r--drivers/firmware/efi/libstub/efistub.h23
-rw-r--r--drivers/firmware/efi/libstub/zboot.c2
-rw-r--r--drivers/firmware/efi/memattr.c7
-rw-r--r--drivers/firmware/efi/sysfb_efi.c8
-rw-r--r--drivers/firmware/efi/vars.c38
-rw-r--r--drivers/firmware/google/Kconfig8
-rw-r--r--drivers/firmware/google/framebuffer-coreboot.c4
-rw-r--r--drivers/firmware/google/gsmi.c2
-rw-r--r--drivers/firmware/meson/meson_sm.c2
-rw-r--r--drivers/firmware/qcom_scm-legacy.c2
-rw-r--r--drivers/firmware/qcom_scm-smc.c88
-rw-r--r--drivers/firmware/qcom_scm.c92
-rw-r--r--drivers/firmware/qcom_scm.h8
-rw-r--r--drivers/firmware/stratix10-svc.c25
-rw-r--r--drivers/firmware/sysfb_simplefb.c43
-rw-r--r--drivers/firmware/xilinx/zynqmp.c27
-rw-r--r--drivers/fpga/Kconfig2
-rw-r--r--drivers/fpga/dfl-afu-region.c1
-rw-r--r--drivers/fpga/dfl-afu.h2
-rw-r--r--drivers/fpga/dfl-fme-perf.c2
-rw-r--r--drivers/fpga/dfl-fme-pr.c4
-rw-r--r--drivers/fpga/dfl-fme-pr.h2
-rw-r--r--drivers/fpga/dfl.c253
-rw-r--r--drivers/fpga/dfl.h43
-rw-r--r--drivers/fpga/fpga-bridge.c11
-rw-r--r--drivers/fpga/intel-m10-bmc-sec-update.c415
-rw-r--r--drivers/fpga/microchip-spi.c145
-rw-r--r--drivers/fsi/fsi-core.c6
-rw-r--r--drivers/gpio/Kconfig10
-rw-r--r--drivers/gpio/TODO4
-rw-r--r--drivers/gpio/gpio-104-dio-48e.c398
-rw-r--r--drivers/gpio/gpio-104-idi-48.c336
-rw-r--r--drivers/gpio/gpio-davinci.c3
-rw-r--r--drivers/gpio/gpio-ge.c1
-rw-r--r--drivers/gpio/gpio-gpio-mm.c154
-rw-r--r--drivers/gpio/gpio-i8255.c320
-rw-r--r--drivers/gpio/gpio-i8255.h54
-rw-r--r--drivers/gpio/gpio-msc313.c6
-rw-r--r--drivers/gpio/gpio-mvebu.c6
-rw-r--r--drivers/gpio/gpio-omap.c2
-rw-r--r--drivers/gpio/gpio-pca953x.c34
-rw-r--r--drivers/gpio/gpio-pca9570.c24
-rw-r--r--drivers/gpio/gpio-pcf857x.c118
-rw-r--r--drivers/gpio/gpio-regmap.c17
-rw-r--r--drivers/gpio/gpio-rockchip.c2
-rw-r--r--drivers/gpio/gpio-sim.c9
-rw-r--r--drivers/gpio/gpio-tegra186.c41
-rw-r--r--drivers/gpio/gpio-vf610.c2
-rw-r--r--drivers/gpio/gpio-wcd934x.c1
-rw-r--r--drivers/gpio/gpio-xilinx.c11
-rw-r--r--drivers/gpio/gpio-zevio.c9
-rw-r--r--drivers/gpio/gpiolib-acpi.c10
-rw-r--r--drivers/gpio/gpiolib-acpi.h4
-rw-r--r--drivers/gpio/gpiolib-cdev.c21
-rw-r--r--drivers/gpio/gpiolib-devres.c55
-rw-r--r--drivers/gpio/gpiolib-of.c140
-rw-r--r--drivers/gpio/gpiolib-of.h5
-rw-r--r--drivers/gpio/gpiolib.c85
-rw-r--r--drivers/gpio/gpiolib.h10
-rw-r--r--drivers/gpu/drm/Kconfig67
-rw-r--r--drivers/gpu/drm/Makefile9
-rw-r--r--drivers/gpu/drm/amd/amdgpu/Kconfig3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/Makefile7
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu.h16
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c13
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c31
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c11
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c24
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_cs.h2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_device.c122
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_display.c3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c26
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_encoders.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.h1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c9
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c51
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h11
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c11
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c53
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c59
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_object.c6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c350
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c238
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c23
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c7
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c9
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c62
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h5
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_securedisplay.c8
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_securedisplay.h2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c27
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c255
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h5
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c44
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c21
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c18
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c210
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c9
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c166
-rw-r--r--drivers/gpu/drm/amd/amdgpu/atombios_crtc.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/atombios_encoders.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cik_sdma.c16
-rw-r--r--drivers/gpu/drm/amd/amdgpu/dce_v10_0.c9
-rw-r--r--drivers/gpu/drm/amd/amdgpu/dce_v11_0.c9
-rw-r--r--drivers/gpu/drm/amd/amdgpu/dce_v6_0.c9
-rw-r--r--drivers/gpu/drm/amd/amdgpu/dce_v8_0.c9
-rw-r--r--drivers/gpu/drm/amd/amdgpu/df_v1_7.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/df_v4_3.c61
-rw-r--r--drivers/gpu/drm/amd/amdgpu/df_v4_3.h (renamed from drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_frl.h)15
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c155
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c324
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v11_0_3.c88
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v11_0_3.h29
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c33
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c71
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c97
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c174
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfxhub_v2_0.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfxhub_v2_1.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0.c13
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0_3.c10
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c40
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c18
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c16
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c18
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c18
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c42
-rw-r--r--drivers/gpu/drm/amd/amdgpu/imu_v11_0.c7
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mes_v10_1.c108
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mes_v11_0.c107
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mmhub_v1_7.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mmhub_v2_3.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mmhub_v3_0.c37
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_1.c6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_2.c12
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mxgpu_ai.h1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mxgpu_nv.h1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/nbio_v7_2.c5
-rw-r--r--drivers/gpu/drm/amd/amdgpu/nv.c101
-rw-r--r--drivers/gpu/drm/amd/amdgpu/psp_v10_0.c80
-rw-r--r--drivers/gpu/drm/amd/amdgpu/psp_v11_0.c131
-rw-r--r--drivers/gpu/drm/amd/amdgpu/psp_v12_0.c78
-rw-r--r--drivers/gpu/drm/amd/amdgpu/psp_v13_0.c27
-rw-r--r--drivers/gpu/drm/amd/amdgpu/psp_v13_0_4.c14
-rw-r--r--drivers/gpu/drm/amd/amdgpu/psp_v3_1.c16
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c18
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c18
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c68
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c30
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c63
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c74
-rw-r--r--drivers/gpu/drm/amd/amdgpu/smu_v13_0_10.c303
-rw-r--r--drivers/gpu/drm/amd/amdgpu/smu_v13_0_10.h32
-rw-r--r--drivers/gpu/drm/amd/amdgpu/soc21.c62
-rw-r--r--drivers/gpu/drm/amd/amdgpu/ta_secureDisplay_if.h24
-rw-r--r--drivers/gpu/drm/amd/amdgpu/umc_v6_7.c7
-rw-r--r--drivers/gpu/drm/amd/amdgpu/umc_v8_10.c216
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c5
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c5
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c5
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c9
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c96
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_chardev.c27
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_device.c11
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c5
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v9.c27
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c4
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_events.c13
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_migrate.c3
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c15
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_priv.h2
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_process.c18
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_svm.c1
-rw-r--r--drivers/gpu/drm/amd/display/Kconfig1
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c744
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h83
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c165
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h26
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c10
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c205
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c153
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h17
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c198
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c91
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c22
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h1
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c3
-rw-r--r--drivers/gpu/drm/amd/display/dc/Makefile5
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/bios_parser.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c17
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/command_table2.c14
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/command_table2.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c3
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_smu.c3
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c28
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c101
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc.c156
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_link.c4948
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c7553
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c61
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c103
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_resource.c121
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_stat.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_stream.c11
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc.h220
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_bios_types.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_ddc_types.h31
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_dp_types.h170
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_hdmi_types.h134
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_hw_types.h24
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_link.h199
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_stream.h5
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_types.h112
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_aux.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c108
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h12
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c28
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c15
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c37
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c119
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c17
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c22
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn201/dcn201_link_encoder.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hwseq.c6
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn21/dcn21_link_encoder.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c6
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_link_encoder.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_stream_encoder.c26
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_stream_encoder.h4
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c50
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c9
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c24
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn301/dcn301_dio_link_encoder.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c3
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c16
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c6
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_link_encoder.c5
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.c25
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c18
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.h12
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c63
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.h4
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c4
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.c29
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.h5
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dio_stream_encoder.c13
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dio_stream_encoder.h4
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c30
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c6
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn314/dcn314_optc.c3
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c61
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.h4
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dio_link_encoder.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dio_stream_encoder.c34
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.c29
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.h19
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubp.c6
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubp.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c242
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c70
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h22
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c209
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn321/dcn321_dio_link_encoder.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c18
-rw-r--r--drivers/gpu/drm/amd/display/dc/dm_helpers.h7
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/Makefile3
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c58
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20.c8
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20v2.c10
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn21/display_mode_vba_21.c12
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c5
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c4
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c7
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c4
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn314/display_rq_dlg_calc_314.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c212
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c74
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c64
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.h10
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c7
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dsc/dscc_types.h5
-rw-r--r--drivers/gpu/drm/amd/display/dc/dsc/rc_calc_dpi.c10
-rw-r--r--drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_factory_dcn20.c6
-rw-r--r--drivers/gpu/drm/amd/display/dc/gpio/dcn30/hw_factory_dcn30.c6
-rw-r--r--drivers/gpu/drm/amd/display/dc/gpio/dcn32/hw_factory_dcn32.c6
-rw-r--r--drivers/gpu/drm/amd/display/dc/gpio/ddc_regs.h7
-rw-r--r--drivers/gpu/drm/amd/display/dc/hdcp/hdcp_msg.c5
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/core_types.h51
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h133
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h267
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/dc_link_dpia.h105
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/aux_engine.h8
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h1
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h17
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h1
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h1
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/link.h157
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/resource.h13
-rw-r--r--drivers/gpu/drm/amd/display/dc/irq/dcn201/irq_service_dcn201.c7
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/Makefile37
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c1046
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.h33
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_trace.c (renamed from drivers/gpu/drm/amd/display/dc/link/link_dp_trace.c)18
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_trace.h (renamed from drivers/gpu/drm/amd/display/dc/link/link_dp_trace.h)6
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/accessories/link_fpga.c95
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/accessories/link_fpga.h30
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dio.c (renamed from drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.c)17
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dio.h (renamed from drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.h)1
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dpia.c (renamed from drivers/gpu/drm/amd/display/dc/link/link_hwss_dpia.c)0
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dpia.h (renamed from drivers/gpu/drm/amd/display/dc/link/link_hwss_dpia.h)0
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.c (renamed from drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.c)42
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.h (renamed from drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.h)1
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/link_detection.c1323
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/link_detection.h30
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/link_dpms.c2528
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/link_dpms.h40
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/link_factory.c577
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/link_factory.h29
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/link_resource.c114
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/link_resource.h31
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/link_validation.c398
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/link_validation.h28
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_ddc.c (renamed from drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c)410
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_ddc.h (renamed from drivers/gpu/drm/amd/display/include/i2caux_interface.h)71
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c2244
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.h79
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia.c106
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia.h (renamed from drivers/gpu/drm/tdfx/tdfx_drv.h)42
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.c441
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.h (renamed from drivers/gpu/drm/amd/display/dc/link/link_dp_dpia_bw.h)36
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c389
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.h (renamed from drivers/gpu/drm/amd/display/dc/link/link_dp_dpia_bw.c)11
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.c208
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.h56
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c1701
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.h182
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_128b_132b.c259
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_128b_132b.h42
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_8b_10b.c414
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_8b_10b.h61
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_auxless.c79
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_auxless.h35
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.c (renamed from drivers/gpu/drm/amd/display/dc/core/dc_link_dpia.c)312
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.h41
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c579
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.h45
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_dpcd.c (renamed from drivers/gpu/drm/amd/display/dc/core/dc_link_dpcd.c)13
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_dpcd.h (renamed from drivers/gpu/drm/amd/display/dc/inc/link_dpcd.h)5
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c833
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h33
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_hpd.c240
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_hpd.h47
-rw-r--r--drivers/gpu/drm/amd/display/dmub/dmub_srv.h17
-rw-r--r--drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h124
-rw-r--r--drivers/gpu/drm/amd/display/dmub/src/dmub_srv_stat.c21
-rw-r--r--drivers/gpu/drm/amd/display/include/ddc_service_types.h6
-rw-r--r--drivers/gpu/drm/amd/display/include/dpcd_defs.h5
-rw-r--r--drivers/gpu/drm/amd/display/include/link_service_types.h7
-rw-r--r--drivers/gpu/drm/amd/display/modules/color/color_gamma.c140
-rw-r--r--drivers/gpu/drm/amd/display/modules/color/color_gamma.h3
-rw-r--r--drivers/gpu/drm/amd/display/modules/freesync/freesync.c74
-rw-r--r--drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h36
-rw-r--r--drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c55
-rw-r--r--drivers/gpu/drm/amd/display/modules/power/power_helpers.c31
-rw-r--r--drivers/gpu/drm/amd/display/modules/power/power_helpers.h3
-rw-r--r--drivers/gpu/drm/amd/include/amd_shared.h1
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/df/df_4_3_offset.h30
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/df/df_4_3_sh_mask.h157
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/gc/gc_11_0_3_offset.h8
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/gc/gc_11_0_3_sh_mask.h50
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/xgmi/xgmi_6_1_0_sh_mask.h87
-rw-r--r--drivers/gpu/drm/amd/include/ivsrcid/gfx/irqsrcs_gfx_11_0_0.h2
-rw-r--r--drivers/gpu/drm/amd/include/kgd_pp_interface.h3
-rw-r--r--drivers/gpu/drm/amd/pm/amdgpu_dpm.c18
-rw-r--r--drivers/gpu/drm/amd/pm/amdgpu_pm.c2
-rw-r--r--drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h1
-rw-r--r--drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c11
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c13
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c16
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c87
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.c16
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c32
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_processpptables.c1
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c23
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.c1
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c21
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.c1
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h2
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/inc/smu11_driver_if.h2
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/inc/smu9_driver_if.h2
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/inc/vega12/smu9_driver_if.h2
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c3
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/smumgr/iceland_smumgr.c2
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/smumgr/smu10_smumgr.c10
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/smumgr/tonga_smumgr.c2
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c58
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h2
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu11_driver_if_arcturus.h2
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu11_driver_if_navi10.h2
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu11_driver_if_sienna_cichlid.h2
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_aldebaran.h2
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_0.h2
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_7.h2
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_0_ppsmc.h1
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h3
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h5
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c6
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c55
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c4
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c92
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c75
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c6
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h3
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_crtc.c1
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_drv.c1
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_kms.h1
-rw-r--r--drivers/gpu/drm/arm/hdlcd_drv.c24
-rw-r--r--drivers/gpu/drm/armada/armada_fbdev.c7
-rw-r--r--drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c1
-rw-r--r--drivers/gpu/drm/aspeed/aspeed_gfx_drv.c1
-rw-r--r--drivers/gpu/drm/aspeed/aspeed_gfx_out.c1
-rw-r--r--drivers/gpu/drm/ast/Kconfig2
-rw-r--r--drivers/gpu/drm/ast/ast_drv.c1
-rw-r--r--drivers/gpu/drm/ast/ast_main.c1
-rw-r--r--drivers/gpu/drm/ast/ast_mode.c3
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c9
-rw-r--r--drivers/gpu/drm/bridge/Kconfig11
-rw-r--r--drivers/gpu/drm/bridge/Makefile1
-rw-r--r--drivers/gpu/drm/bridge/adv7511/adv7511_drv.c5
-rw-r--r--drivers/gpu/drm/bridge/analogix/analogix-anx6345.c6
-rw-r--r--drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c5
-rw-r--r--drivers/gpu/drm/bridge/analogix/anx7625.c7
-rw-r--r--drivers/gpu/drm/bridge/cadence/Kconfig21
-rw-r--r--drivers/gpu/drm/bridge/cadence/Makefile3
-rw-r--r--drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c (renamed from drivers/gpu/drm/bridge/cdns-dsi.c)83
-rw-r--r--drivers/gpu/drm/bridge/cadence/cdns-dsi-core.h84
-rw-r--r--drivers/gpu/drm/bridge/cadence/cdns-dsi-j721e.c51
-rw-r--r--drivers/gpu/drm/bridge/cadence/cdns-dsi-j721e.h16
-rw-r--r--drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c1
-rw-r--r--drivers/gpu/drm/bridge/chipone-icn6211.c5
-rw-r--r--drivers/gpu/drm/bridge/chrontel-ch7033.c5
-rw-r--r--drivers/gpu/drm/bridge/fsl-ldb.c80
-rw-r--r--drivers/gpu/drm/bridge/ite-it6505.c133
-rw-r--r--drivers/gpu/drm/bridge/ite-it66121.c321
-rw-r--r--drivers/gpu/drm/bridge/lontium-lt8912b.c26
-rw-r--r--drivers/gpu/drm/bridge/lontium-lt9211.c5
-rw-r--r--drivers/gpu/drm/bridge/lontium-lt9611.c346
-rw-r--r--drivers/gpu/drm/bridge/lontium-lt9611uxc.c5
-rw-r--r--drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c16
-rw-r--r--drivers/gpu/drm/bridge/nxp-ptn3460.c5
-rw-r--r--drivers/gpu/drm/bridge/panel.c13
-rw-r--r--drivers/gpu/drm/bridge/parade-ps8622.c6
-rw-r--r--drivers/gpu/drm/bridge/parade-ps8640.c22
-rw-r--r--drivers/gpu/drm/bridge/sii902x.c38
-rw-r--r--drivers/gpu/drm/bridge/sii9234.c5
-rw-r--r--drivers/gpu/drm/bridge/sil-sii8620.c5
-rw-r--r--drivers/gpu/drm/bridge/tc358764.c1
-rw-r--r--drivers/gpu/drm/bridge/tc358767.c12
-rw-r--r--drivers/gpu/drm/bridge/tc358768.c6
-rw-r--r--drivers/gpu/drm/bridge/tc358775.c5
-rw-r--r--drivers/gpu/drm/bridge/ti-sn65dsi83.c8
-rw-r--r--drivers/gpu/drm/bridge/ti-sn65dsi86.c5
-rw-r--r--drivers/gpu/drm/bridge/ti-tfp410.c5
-rw-r--r--drivers/gpu/drm/display/drm_dp_aux_bus.c7
-rw-r--r--drivers/gpu/drm/display/drm_dp_mst_topology.c71
-rw-r--r--drivers/gpu/drm/drm_atomic.c23
-rw-r--r--drivers/gpu/drm/drm_atomic_state_helper.c124
-rw-r--r--drivers/gpu/drm/drm_atomic_uapi.c4
-rw-r--r--drivers/gpu/drm/drm_blend.c13
-rw-r--r--drivers/gpu/drm/drm_bridge.c294
-rw-r--r--drivers/gpu/drm/drm_bridge_connector.c27
-rw-r--r--drivers/gpu/drm/drm_bufs.c12
-rw-r--r--drivers/gpu/drm/drm_client.c21
-rw-r--r--drivers/gpu/drm/drm_client_modeset.c4
-rw-r--r--drivers/gpu/drm/drm_connector.c174
-rw-r--r--drivers/gpu/drm/drm_context.c36
-rw-r--r--drivers/gpu/drm/drm_debugfs.c110
-rw-r--r--drivers/gpu/drm/drm_drv.c7
-rw-r--r--drivers/gpu/drm/drm_edid.c528
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c321
-rw-r--r--drivers/gpu/drm/drm_fbdev_generic.c130
-rw-r--r--drivers/gpu/drm/drm_file.c18
-rw-r--r--drivers/gpu/drm/drm_format_helper.c496
-rw-r--r--drivers/gpu/drm/drm_fourcc.c4
-rw-r--r--drivers/gpu/drm/drm_framebuffer.c11
-rw-r--r--drivers/gpu/drm/drm_gem.c21
-rw-r--r--drivers/gpu/drm/drm_gem_atomic_helper.c31
-rw-r--r--drivers/gpu/drm/drm_gem_dma_helper.c7
-rw-r--r--drivers/gpu/drm/drm_gem_shmem_helper.c73
-rw-r--r--drivers/gpu/drm/drm_gem_ttm_helper.c2
-rw-r--r--drivers/gpu/drm/drm_gem_vram_helper.c12
-rw-r--r--drivers/gpu/drm/drm_internal.h5
-rw-r--r--drivers/gpu/drm/drm_ioc32.c13
-rw-r--r--drivers/gpu/drm/drm_ioctl.c25
-rw-r--r--drivers/gpu/drm/drm_lease.c66
-rw-r--r--drivers/gpu/drm/drm_mipi_dbi.c158
-rw-r--r--drivers/gpu/drm/drm_mipi_dsi.c56
-rw-r--r--drivers/gpu/drm/drm_mode_config.c10
-rw-r--r--drivers/gpu/drm/drm_modes.c551
-rw-r--r--drivers/gpu/drm/drm_panel_orientation_quirks.c39
-rw-r--r--drivers/gpu/drm/drm_plane.c5
-rw-r--r--drivers/gpu/drm/drm_plane_helper.c1
-rw-r--r--drivers/gpu/drm/drm_probe_helper.c160
-rw-r--r--drivers/gpu/drm/drm_simple_kms_helper.c2
-rw-r--r--drivers/gpu/drm/drm_vm.c8
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_drv.c54
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_drv.h5
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_gem.c2
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c9
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_gpu.c66
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_gpu.h8
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_hwdb.c36
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_sched.c18
-rw-r--r--drivers/gpu/drm/etnaviv/state_hi.xml.h86
-rw-r--r--drivers/gpu/drm/exynos/exynos5433_drm_decon.c13
-rw-r--r--drivers/gpu/drm/exynos/exynos7_drm_decon.c12
-rw-r--r--drivers/gpu/drm/exynos/exynos_dp.c11
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dsi.c50
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fbdev.c7
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimc.c11
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimd.c11
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_g2d.c10
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gem.c4
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_mic.c11
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_rotator.c12
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_scaler.c12
-rw-r--r--drivers/gpu/drm/gma500/Kconfig2
-rw-r--r--drivers/gpu/drm/gma500/backlight.c2
-rw-r--r--drivers/gpu/drm/gma500/cdv_device.c1
-rw-r--r--drivers/gpu/drm/gma500/cdv_intel_crt.c2
-rw-r--r--drivers/gpu/drm/gma500/cdv_intel_display.c1
-rw-r--r--drivers/gpu/drm/gma500/cdv_intel_dp.c1
-rw-r--r--drivers/gpu/drm/gma500/cdv_intel_hdmi.c2
-rw-r--r--drivers/gpu/drm/gma500/cdv_intel_lvds.c2
-rw-r--r--drivers/gpu/drm/gma500/framebuffer.c15
-rw-r--r--drivers/gpu/drm/gma500/gma_display.c2
-rw-r--r--drivers/gpu/drm/gma500/oaktrail_crtc.c1
-rw-r--r--drivers/gpu/drm/gma500/oaktrail_hdmi.c2
-rw-r--r--drivers/gpu/drm/gma500/oaktrail_lvds.c1
-rw-r--r--drivers/gpu/drm/gma500/psb_device.c1
-rw-r--r--drivers/gpu/drm/gma500/psb_intel_display.c3
-rw-r--r--drivers/gpu/drm/gma500/psb_intel_drv.h1
-rw-r--r--drivers/gpu/drm/gma500/psb_intel_lvds.c2
-rw-r--r--drivers/gpu/drm/gma500/psb_intel_sdvo.c2
-rw-r--r--drivers/gpu/drm/gud/gud_connector.c10
-rw-r--r--drivers/gpu/drm/gud/gud_drv.c18
-rw-r--r--drivers/gpu/drm/gud/gud_internal.h1
-rw-r--r--drivers/gpu/drm/gud/gud_pipe.c223
-rw-r--r--drivers/gpu/drm/hisilicon/hibmc/Kconfig2
-rw-r--r--drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c4
-rw-r--r--drivers/gpu/drm/i2c/ch7006_drv.c14
-rw-r--r--drivers/gpu/drm/i2c/ch7006_priv.h1
-rw-r--r--drivers/gpu/drm/i2c/sil164_drv.c4
-rw-r--r--drivers/gpu/drm/i2c/tda9950.c5
-rw-r--r--drivers/gpu/drm/i2c/tda998x_drv.c4
-rw-r--r--drivers/gpu/drm/i810/Makefile8
-rw-r--r--drivers/gpu/drm/i810/i810_dma.c1266
-rw-r--r--drivers/gpu/drm/i810/i810_drv.c101
-rw-r--r--drivers/gpu/drm/i810/i810_drv.h246
-rw-r--r--drivers/gpu/drm/i915/Kconfig26
-rw-r--r--drivers/gpu/drm/i915/Makefile20
-rw-r--r--drivers/gpu/drm/i915/display/dvo_ch7xxx.c22
-rw-r--r--drivers/gpu/drm/i915/display/dvo_sil164.c13
-rw-r--r--drivers/gpu/drm/i915/display/g4x_dp.c2
-rw-r--r--drivers/gpu/drm/i915/display/g4x_hdmi.c2
-rw-r--r--drivers/gpu/drm/i915/display/icl_dsi.c5
-rw-r--r--drivers/gpu/drm/i915/display/intel_atomic.c85
-rw-r--r--drivers/gpu/drm/i915/display/intel_atomic_plane.c1
-rw-r--r--drivers/gpu/drm/i915/display/intel_audio.c328
-rw-r--r--drivers/gpu/drm/i915/display/intel_audio.h9
-rw-r--r--drivers/gpu/drm/i915/display/intel_backlight.c573
-rw-r--r--drivers/gpu/drm/i915/display/intel_backlight_regs.h27
-rw-r--r--drivers/gpu/drm/i915/display/intel_bios.c82
-rw-r--r--drivers/gpu/drm/i915/display/intel_bios.h13
-rw-r--r--drivers/gpu/drm/i915/display/intel_bw.h2
-rw-r--r--drivers/gpu/drm/i915/display/intel_cdclk.c216
-rw-r--r--drivers/gpu/drm/i915/display/intel_cdclk.h2
-rw-r--r--drivers/gpu/drm/i915/display/intel_color.c1265
-rw-r--r--drivers/gpu/drm/i915/display/intel_color.h10
-rw-r--r--drivers/gpu/drm/i915/display/intel_connector.c7
-rw-r--r--drivers/gpu/drm/i915/display/intel_crt.c53
-rw-r--r--drivers/gpu/drm/i915/display/intel_crtc.c1
-rw-r--r--drivers/gpu/drm/i915/display/intel_crtc_state_dump.c17
-rw-r--r--drivers/gpu/drm/i915/display/intel_ddi.c30
-rw-r--r--drivers/gpu/drm/i915/display/intel_de.h46
-rw-r--r--drivers/gpu/drm/i915/display/intel_display.c219
-rw-r--r--drivers/gpu/drm/i915/display/intel_display.h123
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_core.h34
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_limits.h124
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_power.c2
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_power_map.c1
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_trace.h1
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_types.h39
-rw-r--r--drivers/gpu/drm/i915/display/intel_dmc.c135
-rw-r--r--drivers/gpu/drm/i915/display/intel_dmc.h5
-rw-r--r--drivers/gpu/drm/i915/display/intel_dmc_regs.h10
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp.c306
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp.h19
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_aux.c41
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_mst.c310
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_mst.h4
-rw-r--r--drivers/gpu/drm/i915/display/intel_dpio_phy.c9
-rw-r--r--drivers/gpu/drm/i915/display/intel_dpll.c2
-rw-r--r--drivers/gpu/drm/i915/display/intel_dpll_mgr.c4
-rw-r--r--drivers/gpu/drm/i915/display/intel_drrs.c8
-rw-r--r--drivers/gpu/drm/i915/display/intel_dsb.c328
-rw-r--r--drivers/gpu/drm/i915/display/intel_dsb.h14
-rw-r--r--drivers/gpu/drm/i915/display/intel_dvo.c410
-rw-r--r--drivers/gpu/drm/i915/display/intel_dvo_dev.h7
-rw-r--r--drivers/gpu/drm/i915/display/intel_dvo_regs.h54
-rw-r--r--drivers/gpu/drm/i915/display/intel_fb.c2
-rw-r--r--drivers/gpu/drm/i915/display/intel_fb_pin.c2
-rw-r--r--drivers/gpu/drm/i915/display/intel_fbc.c32
-rw-r--r--drivers/gpu/drm/i915/display/intel_fbdev.c31
-rw-r--r--drivers/gpu/drm/i915/display/intel_gmbus.c46
-rw-r--r--drivers/gpu/drm/i915/display/intel_hdmi.c53
-rw-r--r--drivers/gpu/drm/i915/display/intel_hti.c3
-rw-r--r--drivers/gpu/drm/i915/display/intel_lvds.c53
-rw-r--r--drivers/gpu/drm/i915/display/intel_modeset_setup.c4
-rw-r--r--drivers/gpu/drm/i915/display/intel_opregion.c29
-rw-r--r--drivers/gpu/drm/i915/display/intel_opregion.h4
-rw-r--r--drivers/gpu/drm/i915/display/intel_panel.c19
-rw-r--r--drivers/gpu/drm/i915/display/intel_panel.h5
-rw-r--r--drivers/gpu/drm/i915/display/intel_pch_refclk.c10
-rw-r--r--drivers/gpu/drm/i915/display/intel_pipe_crc.c23
-rw-r--r--drivers/gpu/drm/i915/display/intel_plane_initial.c2
-rw-r--r--drivers/gpu/drm/i915/display/intel_pps.c360
-rw-r--r--drivers/gpu/drm/i915/display/intel_pps.h2
-rw-r--r--drivers/gpu/drm/i915/display/intel_psr.c101
-rw-r--r--drivers/gpu/drm/i915/display/intel_quirks.c2
-rw-r--r--drivers/gpu/drm/i915/display/intel_sdvo.c47
-rw-r--r--drivers/gpu/drm/i915/display/intel_snps_phy.c17
-rw-r--r--drivers/gpu/drm/i915/display/intel_tc.c55
-rw-r--r--drivers/gpu/drm/i915/display/intel_tv.c4
-rw-r--r--drivers/gpu/drm/i915/display/intel_vblank.c441
-rw-r--r--drivers/gpu/drm/i915/display/intel_vblank.h23
-rw-r--r--drivers/gpu/drm/i915/display/intel_vdsc.c11
-rw-r--r--drivers/gpu/drm/i915/display/intel_vga.c32
-rw-r--r--drivers/gpu/drm/i915/display/intel_vrr.c55
-rw-r--r--drivers/gpu/drm/i915/display/skl_scaler.c49
-rw-r--r--drivers/gpu/drm/i915/display/skl_universal_plane.c2
-rw-r--r--drivers/gpu/drm/i915/display/skl_watermark.c42
-rw-r--r--drivers/gpu/drm/i915/display/skl_watermark.h2
-rw-r--r--drivers/gpu/drm/i915/display/vlv_dsi.c4
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_clflush.c1
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_context.c15
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_create.c3
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_domain.c16
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c35
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_internal.c7
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_mman.c6
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_object.c7
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_object.h303
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_object_types.h2
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_pages.c27
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_phys.c4
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_shmem.c25
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_shrinker.c2
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_stolen.c42
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_tiling.c4
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_ttm.c58
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c58
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_userptr.c6
-rw-r--r--drivers/gpu/drm/i915/gem/selftests/huge_gem_object.c6
-rw-r--r--drivers/gpu/drm/i915/gem/selftests/huge_pages.c10
-rw-r--r--drivers/gpu/drm/i915/gem/selftests/i915_gem_client_blt.c23
-rw-r--r--drivers/gpu/drm/i915/gem/selftests/i915_gem_coherency.c2
-rw-r--r--drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c35
-rw-r--r--drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c10
-rw-r--r--drivers/gpu/drm/i915/gem/selftests/i915_gem_object.c8
-rw-r--r--drivers/gpu/drm/i915/gem/selftests/igt_gem_utils.c15
-rw-r--r--drivers/gpu/drm/i915/gem/selftests/igt_gem_utils.h2
-rw-r--r--drivers/gpu/drm/i915/gt/gen7_renderclear.c2
-rw-r--r--drivers/gpu/drm/i915/gt/intel_engine.h2
-rw-r--r--drivers/gpu/drm/i915/gt/intel_engine_cs.c29
-rw-r--r--drivers/gpu/drm/i915/gt/intel_engine_pm.c18
-rw-r--r--drivers/gpu/drm/i915/gt/intel_engine_regs.h1
-rw-r--r--drivers/gpu/drm/i915/gt/intel_execlists_submission.c21
-rw-r--r--drivers/gpu/drm/i915/gt/intel_ggtt.c191
-rw-r--r--drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c4
-rw-r--r--drivers/gpu/drm/i915/gt/intel_ggtt_gmch.c6
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gpu_commands.h7
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gsc.c8
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gt.c167
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gt.h5
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gt_clock_utils.c8
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gt_debugfs.c2
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gt_irq.c11
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gt_mcr.c146
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gt_mcr.h2
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gt_pm.c17
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gt_print.h51
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gt_regs.h45
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gt_sysfs.c4
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c42
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gt_types.h20
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gtt.c34
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gtt.h30
-rw-r--r--drivers/gpu/drm/i915/gt/intel_lrc.c6
-rw-r--r--drivers/gpu/drm/i915/gt/intel_migrate.c6
-rw-r--r--drivers/gpu/drm/i915/gt/intel_mocs.c3
-rw-r--r--drivers/gpu/drm/i915/gt/intel_rc6.c12
-rw-r--r--drivers/gpu/drm/i915/gt/intel_renderstate.c2
-rw-r--r--drivers/gpu/drm/i915/gt/intel_reset.c18
-rw-r--r--drivers/gpu/drm/i915/gt/intel_ring.c6
-rw-r--r--drivers/gpu/drm/i915/gt/intel_ring_submission.c2
-rw-r--r--drivers/gpu/drm/i915/gt/intel_rps.c1
-rw-r--r--drivers/gpu/drm/i915/gt/intel_rps.h3
-rw-r--r--drivers/gpu/drm/i915/gt/intel_workarounds.c316
-rw-r--r--drivers/gpu/drm/i915/gt/selftest_engine_cs.c8
-rw-r--r--drivers/gpu/drm/i915/gt/selftest_execlists.c30
-rw-r--r--drivers/gpu/drm/i915/gt/selftest_hangcheck.c15
-rw-r--r--drivers/gpu/drm/i915/gt/selftest_lrc.c20
-rw-r--r--drivers/gpu/drm/i915/gt/selftest_migrate.c173
-rw-r--r--drivers/gpu/drm/i915/gt/selftest_mocs.c4
-rw-r--r--drivers/gpu/drm/i915/gt/selftest_reset.c2
-rw-r--r--drivers/gpu/drm/i915/gt/selftest_ring_submission.c2
-rw-r--r--drivers/gpu/drm/i915/gt/selftest_rps.c12
-rw-r--r--drivers/gpu/drm/i915/gt/selftest_workarounds.c20
-rw-r--r--drivers/gpu/drm/i915/gt/shmem_utils.c7
-rw-r--r--drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h6
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_gsc_fw.c210
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_gsc_fw.h15
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_gsc_uc.c137
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_gsc_uc.h47
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc.c47
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc.h11
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c8
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c8
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c23
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c22
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc_log.c38
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc_print.h48
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c106
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_huc_fw.c2
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_uc.c99
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_uc.h3
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c291
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h23
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_uc_fw_abi.h3
-rw-r--r--drivers/gpu/drm/i915/gvt/cmd_parser.c1
-rw-r--r--drivers/gpu/drm/i915/gvt/debugfs.c16
-rw-r--r--drivers/gpu/drm/i915/gvt/display.c1
-rw-r--r--drivers/gpu/drm/i915/gvt/dmabuf.c10
-rw-r--r--drivers/gpu/drm/i915/gvt/fb_decoder.h2
-rw-r--r--drivers/gpu/drm/i915/gvt/firmware.c2
-rw-r--r--drivers/gpu/drm/i915/gvt/kvmgt.c2
-rw-r--r--drivers/gpu/drm/i915/gvt/vgpu.c2
-rw-r--r--drivers/gpu/drm/i915/i915_cmd_parser.c4
-rw-r--r--drivers/gpu/drm/i915/i915_config.c5
-rw-r--r--drivers/gpu/drm/i915/i915_config.h23
-rw-r--r--drivers/gpu/drm/i915/i915_debugfs.c8
-rw-r--r--drivers/gpu/drm/i915/i915_debugfs_params.c33
-rw-r--r--drivers/gpu/drm/i915/i915_deps.c2
-rw-r--r--drivers/gpu/drm/i915/i915_driver.c194
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h134
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c22
-rw-r--r--drivers/gpu/drm/i915/i915_gem.h7
-rw-r--r--drivers/gpu/drm/i915/i915_gem_evict.c51
-rw-r--r--drivers/gpu/drm/i915/i915_gem_gtt.h5
-rw-r--r--drivers/gpu/drm/i915/i915_gpu_error.c71
-rw-r--r--drivers/gpu/drm/i915/i915_gpu_error.h2
-rw-r--r--drivers/gpu/drm/i915/i915_hwmon.c43
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c436
-rw-r--r--drivers/gpu/drm/i915/i915_irq.h6
-rw-r--r--drivers/gpu/drm/i915/i915_params.c91
-rw-r--r--drivers/gpu/drm/i915/i915_params.h1
-rw-r--r--drivers/gpu/drm/i915/i915_pci.c53
-rw-r--r--drivers/gpu/drm/i915/i915_perf.c51
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h110
-rw-r--r--drivers/gpu/drm/i915/i915_request.c1
-rw-r--r--drivers/gpu/drm/i915/i915_scatterlist.c13
-rw-r--r--drivers/gpu/drm/i915/i915_ttm_buddy_manager.c2
-rw-r--r--drivers/gpu/drm/i915/i915_utils.h4
-rw-r--r--drivers/gpu/drm/i915/i915_vma.c80
-rw-r--r--drivers/gpu/drm/i915/i915_vma.h52
-rw-r--r--drivers/gpu/drm/i915/i915_vma_resource.c4
-rw-r--r--drivers/gpu/drm/i915/i915_vma_resource.h17
-rw-r--r--drivers/gpu/drm/i915/i915_vma_types.h3
-rw-r--r--drivers/gpu/drm/i915/intel_device_info.c7
-rw-r--r--drivers/gpu/drm/i915/intel_device_info.h2
-rw-r--r--drivers/gpu/drm/i915/intel_gvt_mmio_table.c1
-rw-r--r--drivers/gpu/drm/i915/intel_mchbar_regs.h2
-rw-r--r--drivers/gpu/drm/i915/intel_memory_region.c2
-rw-r--r--drivers/gpu/drm/i915/intel_pm.c11
-rw-r--r--drivers/gpu/drm/i915/intel_pm_types.h2
-rw-r--r--drivers/gpu/drm/i915/intel_region_ttm.c17
-rw-r--r--drivers/gpu/drm/i915/intel_runtime_pm.h2
-rw-r--r--drivers/gpu/drm/i915/intel_uncore.c59
-rw-r--r--drivers/gpu/drm/i915/intel_uncore.h13
-rw-r--r--drivers/gpu/drm/i915/intel_wakeref.h21
-rw-r--r--drivers/gpu/drm/i915/pxp/intel_pxp.c128
-rw-r--r--drivers/gpu/drm/i915/pxp/intel_pxp.h9
-rw-r--r--drivers/gpu/drm/i915/pxp/intel_pxp_cmd.c8
-rw-r--r--drivers/gpu/drm/i915/pxp/intel_pxp_cmd_interface_cmn.h1
-rw-r--r--drivers/gpu/drm/i915/pxp/intel_pxp_debugfs.c36
-rw-r--r--drivers/gpu/drm/i915/pxp/intel_pxp_debugfs.h4
-rw-r--r--drivers/gpu/drm/i915/pxp/intel_pxp_huc.c11
-rw-r--r--drivers/gpu/drm/i915/pxp/intel_pxp_irq.c18
-rw-r--r--drivers/gpu/drm/i915/pxp/intel_pxp_pm.c6
-rw-r--r--drivers/gpu/drm/i915/pxp/intel_pxp_session.c10
-rw-r--r--drivers/gpu/drm/i915/pxp/intel_pxp_tee.c35
-rw-r--r--drivers/gpu/drm/i915/pxp/intel_pxp_types.h8
-rw-r--r--drivers/gpu/drm/i915/selftests/i915_gem.c6
-rw-r--r--drivers/gpu/drm/i915/selftests/i915_gem_gtt.c4
-rw-r--r--drivers/gpu/drm/i915/selftests/i915_request.c20
-rw-r--r--drivers/gpu/drm/i915/selftests/igt_flush_test.c28
-rw-r--r--drivers/gpu/drm/i915/selftests/igt_spinner.c8
-rw-r--r--drivers/gpu/drm/i915/selftests/mock_gtt.c2
-rw-r--r--drivers/gpu/drm/i915/selftests/scatterlist.c4
-rw-r--r--drivers/gpu/drm/i915/soc/intel_dram.c (renamed from drivers/gpu/drm/i915/intel_dram.c)0
-rw-r--r--drivers/gpu/drm/i915/soc/intel_dram.h (renamed from drivers/gpu/drm/i915/intel_dram.h)0
-rw-r--r--drivers/gpu/drm/i915/soc/intel_gmch.c171
-rw-r--r--drivers/gpu/drm/i915/soc/intel_gmch.h18
-rw-r--r--drivers/gpu/drm/i915/soc/intel_pch.c (renamed from drivers/gpu/drm/i915/intel_pch.c)0
-rw-r--r--drivers/gpu/drm/i915/soc/intel_pch.h (renamed from drivers/gpu/drm/i915/intel_pch.h)0
-rw-r--r--drivers/gpu/drm/i915/vlv_sideband.c1
-rw-r--r--drivers/gpu/drm/imx/Kconfig41
-rw-r--r--drivers/gpu/drm/imx/Makefile10
-rw-r--r--drivers/gpu/drm/imx/dcss/dcss-dev.c23
-rw-r--r--drivers/gpu/drm/imx/dcss/dcss-dev.h7
-rw-r--r--drivers/gpu/drm/imx/dcss/dcss-drv.c15
-rw-r--r--drivers/gpu/drm/imx/dcss/dcss-kms.c2
-rw-r--r--drivers/gpu/drm/imx/ipuv3/Kconfig41
-rw-r--r--drivers/gpu/drm/imx/ipuv3/Makefile11
-rw-r--r--drivers/gpu/drm/imx/ipuv3/dw_hdmi-imx.c (renamed from drivers/gpu/drm/imx/dw_hdmi-imx.c)0
-rw-r--r--drivers/gpu/drm/imx/ipuv3/imx-drm-core.c (renamed from drivers/gpu/drm/imx/imx-drm-core.c)0
-rw-r--r--drivers/gpu/drm/imx/ipuv3/imx-drm.h (renamed from drivers/gpu/drm/imx/imx-drm.h)0
-rw-r--r--drivers/gpu/drm/imx/ipuv3/imx-ldb.c (renamed from drivers/gpu/drm/imx/imx-ldb.c)0
-rw-r--r--drivers/gpu/drm/imx/ipuv3/imx-tve.c (renamed from drivers/gpu/drm/imx/imx-tve.c)0
-rw-r--r--drivers/gpu/drm/imx/ipuv3/ipuv3-crtc.c (renamed from drivers/gpu/drm/imx/ipuv3-crtc.c)0
-rw-r--r--drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c (renamed from drivers/gpu/drm/imx/ipuv3-plane.c)0
-rw-r--r--drivers/gpu/drm/imx/ipuv3/ipuv3-plane.h (renamed from drivers/gpu/drm/imx/ipuv3-plane.h)0
-rw-r--r--drivers/gpu/drm/imx/ipuv3/parallel-display.c (renamed from drivers/gpu/drm/imx/parallel-display.c)0
-rw-r--r--drivers/gpu/drm/ingenic/ingenic-drm-drv.c1
-rw-r--r--drivers/gpu/drm/kmb/kmb_crtc.c1
-rw-r--r--drivers/gpu/drm/kmb/kmb_plane.c1
-rw-r--r--drivers/gpu/drm/logicvc/logicvc_drm.c13
-rw-r--r--drivers/gpu/drm/logicvc/logicvc_interface.c1
-rw-r--r--drivers/gpu/drm/logicvc/logicvc_mode.c1
-rw-r--r--drivers/gpu/drm/mediatek/Kconfig1
-rw-r--r--drivers/gpu/drm/mediatek/mtk_cec.c2
-rw-r--r--drivers/gpu/drm/mediatek/mtk_disp_aal.c1
-rw-r--r--drivers/gpu/drm/mediatek/mtk_disp_ccorr.c1
-rw-r--r--drivers/gpu/drm/mediatek/mtk_disp_color.c1
-rw-r--r--drivers/gpu/drm/mediatek/mtk_disp_gamma.c1
-rw-r--r--drivers/gpu/drm/mediatek/mtk_disp_ovl.c1
-rw-r--r--drivers/gpu/drm/mediatek/mtk_disp_rdma.c1
-rw-r--r--drivers/gpu/drm/mediatek/mtk_dp.c6
-rw-r--r--drivers/gpu/drm/mediatek/mtk_dpi.c32
-rw-r--r--drivers/gpu/drm/mediatek/mtk_drm_crtc.c2
-rw-r--r--drivers/gpu/drm/mediatek/mtk_drm_drv.c5
-rw-r--r--drivers/gpu/drm/mediatek/mtk_drm_gem.c13
-rw-r--r--drivers/gpu/drm/mediatek/mtk_dsi.c3
-rw-r--r--drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c3
-rw-r--r--drivers/gpu/drm/meson/meson_dw_hdmi.c23
-rw-r--r--drivers/gpu/drm/mga/Makefile11
-rw-r--r--drivers/gpu/drm/mga/mga_dma.c1168
-rw-r--r--drivers/gpu/drm/mga/mga_drv.c104
-rw-r--r--drivers/gpu/drm/mga/mga_drv.h685
-rw-r--r--drivers/gpu/drm/mga/mga_ioc32.c197
-rw-r--r--drivers/gpu/drm/mga/mga_irq.c169
-rw-r--r--drivers/gpu/drm/mga/mga_state.c1099
-rw-r--r--drivers/gpu/drm/mga/mga_warp.c167
-rw-r--r--drivers/gpu/drm/mgag200/Kconfig2
-rw-r--r--drivers/gpu/drm/msm/Kconfig7
-rw-r--r--drivers/gpu/drm/msm/adreno/a2xx_gpu.c27
-rw-r--r--drivers/gpu/drm/msm/adreno/a2xx_gpu.h1
-rw-r--r--drivers/gpu/drm/msm/adreno/a5xx_gpu.c2
-rw-r--r--drivers/gpu/drm/msm/adreno/a6xx.xml.h18
-rw-r--r--drivers/gpu/drm/msm/adreno/a6xx_gpu.c2
-rw-r--r--drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c61
-rw-r--r--drivers/gpu/drm/msm/adreno/a6xx_gpu_state.h66
-rw-r--r--drivers/gpu/drm/msm/adreno/adreno_gpu.c6
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c17
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c30
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h47
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c18
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c12
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c14
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c872
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h19
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c147
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c27
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h4
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c30
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h3
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h7
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c6
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c25
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_hwio.h21
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c20
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c15
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c14
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c2
-rw-r--r--drivers/gpu/drm/msm/disp/mdp4/mdp4_irq.c9
-rw-r--r--drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c5
-rw-r--r--drivers/gpu/drm/msm/disp/mdp5/mdp5_irq.c9
-rw-r--r--drivers/gpu/drm/msm/disp/msm_disp_snapshot.c3
-rw-r--r--drivers/gpu/drm/msm/dp/dp_display.c157
-rw-r--r--drivers/gpu/drm/msm/dp/dp_display.h1
-rw-r--r--drivers/gpu/drm/msm/dp/dp_drm.c3
-rw-r--r--drivers/gpu/drm/msm/dp/dp_drm.h4
-rw-r--r--drivers/gpu/drm/msm/dp/dp_panel.c7
-rw-r--r--drivers/gpu/drm/msm/dp/dp_panel.h1
-rw-r--r--drivers/gpu/drm/msm/dp/dp_parser.c50
-rw-r--r--drivers/gpu/drm/msm/dp/dp_parser.h2
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi.h3
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi_cfg.c22
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi_cfg.h2
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi_host.c69
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi_manager.c20
-rw-r--r--drivers/gpu/drm/msm/dsi/phy/dsi_phy.c12
-rw-r--r--drivers/gpu/drm/msm/dsi/phy/dsi_phy.h4
-rw-r--r--drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c243
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi.c6
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi_hdcp.c2
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi_pll_8960.c21
-rw-r--r--drivers/gpu/drm/msm/msm_debugfs.c12
-rw-r--r--drivers/gpu/drm/msm/msm_drv.c18
-rw-r--r--drivers/gpu/drm/msm/msm_drv.h12
-rw-r--r--drivers/gpu/drm/msm/msm_fbdev.c10
-rw-r--r--drivers/gpu/drm/msm/msm_fence.c2
-rw-r--r--drivers/gpu/drm/msm/msm_gem.c2
-rw-r--r--drivers/gpu/drm/msm/msm_gem_submit.c15
-rw-r--r--drivers/gpu/drm/msm/msm_gpu.h15
-rw-r--r--drivers/gpu/drm/msm/msm_gpu_devfreq.c148
-rw-r--r--drivers/gpu/drm/msm/msm_mdss.c16
-rw-r--r--drivers/gpu/drm/mxsfb/Kconfig2
-rw-r--r--drivers/gpu/drm/mxsfb/mxsfb_drv.c10
-rw-r--r--drivers/gpu/drm/nouveau/Kconfig14
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/crtc.c2
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/dac.c2
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/dfp.c2
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/tvmodesnv17.c1
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/tvnv04.c2
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/tvnv17.c7
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/disp.c2
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/head.c1
-rw-r--r--drivers/gpu/drm/nouveau/include/nvfw/hs.h2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo.c7
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo.h3
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drm.c12
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h3
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_gem.c11
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_mem.c3
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_mem.h2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_prime.c1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_sgdma.c1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_vga.c1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g84.c5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g98.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm107.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gt215.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/devinit/mcp89.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.h2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/devinit/priv.h2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c3
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dispc.c5
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dsi.c26
-rw-r--r--drivers/gpu/drm/omapdrm/omap_drv.c41
-rw-r--r--drivers/gpu/drm/omapdrm/omap_fbdev.c8
-rw-r--r--drivers/gpu/drm/omapdrm/omap_gem.c5
-rw-r--r--drivers/gpu/drm/omapdrm/omap_irq.c4
-rw-r--r--drivers/gpu/drm/panel/Kconfig38
-rw-r--r--drivers/gpu/drm/panel/Makefile4
-rw-r--r--drivers/gpu/drm/panel/panel-asus-z00t-tm5p5-n35596.c96
-rw-r--r--drivers/gpu/drm/panel/panel-auo-a030jtn01.c308
-rw-r--r--drivers/gpu/drm/panel/panel-boe-bf060y8m-aj0.c42
-rw-r--r--drivers/gpu/drm/panel/panel-edp.c11
-rw-r--r--drivers/gpu/drm/panel/panel-elida-kd35t133.c46
-rw-r--r--drivers/gpu/drm/panel/panel-himax-hx8394.c451
-rw-r--r--drivers/gpu/drm/panel/panel-ilitek-ili9341.c6
-rw-r--r--drivers/gpu/drm/panel/panel-ilitek-ili9881c.c1
-rw-r--r--drivers/gpu/drm/panel/panel-jdi-fhd-r63452.c58
-rw-r--r--drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c106
-rw-r--r--drivers/gpu/drm/panel/panel-mantix-mlaf057we51.c24
-rw-r--r--drivers/gpu/drm/panel/panel-novatek-nt35950.c14
-rw-r--r--drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c5
-rw-r--r--drivers/gpu/drm/panel/panel-orisetech-ota5601a.c364
-rw-r--r--drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c6
-rw-r--r--drivers/gpu/drm/panel/panel-ronbo-rb070d30.c2
-rw-r--r--drivers/gpu/drm/panel/panel-samsung-atna33xc20.c10
-rw-r--r--drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c5
-rw-r--r--drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c4
-rw-r--r--drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams452ef01.c44
-rw-r--r--drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c3
-rw-r--r--drivers/gpu/drm/panel/panel-samsung-sofef00.c33
-rw-r--r--drivers/gpu/drm/panel/panel-sharp-ls060t1sx01.c19
-rw-r--r--drivers/gpu/drm/panel/panel-simple.c6
-rw-r--r--drivers/gpu/drm/panel/panel-sitronix-st7703.c341
-rw-r--r--drivers/gpu/drm/panel/panel-sony-tulip-truly-nt35521.c398
-rw-r--r--drivers/gpu/drm/panel/panel-visionox-vtdr6130.c350
-rw-r--r--drivers/gpu/drm/panel/panel-xinpeng-xpp055c272.c112
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_device.c10
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_device.h4
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_drv.c7
-rw-r--r--drivers/gpu/drm/qxl/qxl_cmd.c16
-rw-r--r--drivers/gpu/drm/qxl/qxl_drv.h3
-rw-r--r--drivers/gpu/drm/qxl/qxl_ttm.c4
-rw-r--r--drivers/gpu/drm/r128/Makefile10
-rw-r--r--drivers/gpu/drm/r128/ati_pcigart.c228
-rw-r--r--drivers/gpu/drm/r128/ati_pcigart.h31
-rw-r--r--drivers/gpu/drm/r128/r128_cce.c944
-rw-r--r--drivers/gpu/drm/r128/r128_drv.c116
-rw-r--r--drivers/gpu/drm/r128/r128_drv.h544
-rw-r--r--drivers/gpu/drm/r128/r128_ioc32.c199
-rw-r--r--drivers/gpu/drm/r128/r128_irq.c118
-rw-r--r--drivers/gpu/drm/r128/r128_state.c1641
-rw-r--r--drivers/gpu/drm/radeon/Kconfig2
-rw-r--r--drivers/gpu/drm/radeon/atombios.h10
-rw-r--r--drivers/gpu/drm/radeon/atombios_crtc.c3
-rw-r--r--drivers/gpu/drm/radeon/atombios_encoders.c6
-rw-r--r--drivers/gpu/drm/radeon/r300.c1
-rw-r--r--drivers/gpu/drm/radeon/radeon.h3
-rw-r--r--drivers/gpu/drm/radeon/radeon_acpi.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_asic.c1
-rw-r--r--drivers/gpu/drm/radeon/radeon_connectors.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_device.c6
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c1
-rw-r--r--drivers/gpu/drm/radeon/radeon_dp_auxch.c5
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_encoders.c1
-rw-r--r--drivers/gpu/drm/radeon/radeon_fb.c10
-rw-r--r--drivers/gpu/drm/radeon/radeon_irq_kms.c1
-rw-r--r--drivers/gpu/drm/radeon/radeon_legacy_crtc.c5
-rw-r--r--drivers/gpu/drm/radeon/radeon_legacy_encoders.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_legacy_tv.c1
-rw-r--r--drivers/gpu/drm/radeon/radeon_mode.h2
-rw-r--r--drivers/gpu/drm/radeon/radeon_pm.c4
-rw-r--r--drivers/gpu/drm/radeon/radeon_prime.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_ttm.c4
-rw-r--r--drivers/gpu/drm/rcar-du/Kconfig6
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_crtc.c39
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_drv.c82
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_drv.h2
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_group.c26
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_kms.c30
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_regs.h8
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_vsp.c50
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_lvds.c92
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c497
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h6
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_gem.c3
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_vop2.c1
-rw-r--r--drivers/gpu/drm/savage/Makefile9
-rw-r--r--drivers/gpu/drm/savage/savage_bci.c1082
-rw-r--r--drivers/gpu/drm/savage/savage_drv.c91
-rw-r--r--drivers/gpu/drm/savage/savage_drv.h580
-rw-r--r--drivers/gpu/drm/savage/savage_state.c1169
-rw-r--r--drivers/gpu/drm/scheduler/sched_main.c19
-rw-r--r--drivers/gpu/drm/shmobile/shmob_drm_crtc.c2
-rw-r--r--drivers/gpu/drm/shmobile/shmob_drm_drv.c10
-rw-r--r--drivers/gpu/drm/shmobile/shmob_drm_plane.c1
-rw-r--r--drivers/gpu/drm/sis/Makefile10
-rw-r--r--drivers/gpu/drm/sis/sis_drv.c143
-rw-r--r--drivers/gpu/drm/sis/sis_drv.h80
-rw-r--r--drivers/gpu/drm/sis/sis_mm.c363
-rw-r--r--drivers/gpu/drm/solomon/ssd130x.c15
-rw-r--r--drivers/gpu/drm/sprd/sprd_dpu.c5
-rw-r--r--drivers/gpu/drm/sprd/sprd_drm.c1
-rw-r--r--drivers/gpu/drm/sprd/sprd_dsi.c1
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_tv.c141
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c2
-rw-r--r--drivers/gpu/drm/tdfx/Makefile8
-rw-r--r--drivers/gpu/drm/tdfx/tdfx_drv.c90
-rw-r--r--drivers/gpu/drm/tegra/dpaux.c6
-rw-r--r--drivers/gpu/drm/tegra/drm.c2
-rw-r--r--drivers/gpu/drm/tegra/fb.c8
-rw-r--r--drivers/gpu/drm/tegra/firewall.c3
-rw-r--r--drivers/gpu/drm/tegra/gem.c5
-rw-r--r--drivers/gpu/drm/tegra/nvdec.c16
-rw-r--r--drivers/gpu/drm/tegra/submit.c19
-rw-r--r--drivers/gpu/drm/tegra/vic.c39
-rw-r--r--drivers/gpu/drm/tests/Makefile8
-rw-r--r--drivers/gpu/drm/tests/drm_client_modeset_test.c110
-rw-r--r--drivers/gpu/drm/tests/drm_cmdline_parser_test.c68
-rw-r--r--drivers/gpu/drm/tests/drm_connector_test.c76
-rw-r--r--drivers/gpu/drm/tests/drm_format_helper_test.c384
-rw-r--r--drivers/gpu/drm/tests/drm_kunit_helpers.c105
-rw-r--r--drivers/gpu/drm/tests/drm_kunit_helpers.h11
-rw-r--r--drivers/gpu/drm/tests/drm_managed_test.c71
-rw-r--r--drivers/gpu/drm/tests/drm_modes_test.c158
-rw-r--r--drivers/gpu/drm/tests/drm_probe_helper_test.c218
-rw-r--r--drivers/gpu/drm/tidss/tidss_crtc.c1
-rw-r--r--drivers/gpu/drm/tidss/tidss_dispc.c6
-rw-r--r--drivers/gpu/drm/tidss/tidss_drv.c1
-rw-r--r--drivers/gpu/drm/tidss/tidss_encoder.c2
-rw-r--r--drivers/gpu/drm/tidss/tidss_kms.c1
-rw-r--r--drivers/gpu/drm/tidss/tidss_plane.c1
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_drv.c9
-rw-r--r--drivers/gpu/drm/tiny/cirrus.c2
-rw-r--r--drivers/gpu/drm/tiny/gm12u320.c15
-rw-r--r--drivers/gpu/drm/tiny/hx8357d.c5
-rw-r--r--drivers/gpu/drm/tiny/ili9163.c6
-rw-r--r--drivers/gpu/drm/tiny/ili9225.c36
-rw-r--r--drivers/gpu/drm/tiny/ili9341.c5
-rw-r--r--drivers/gpu/drm/tiny/ili9486.c20
-rw-r--r--drivers/gpu/drm/tiny/mi0283qt.c5
-rw-r--r--drivers/gpu/drm/tiny/ofdrm.c40
-rw-r--r--drivers/gpu/drm/tiny/panel-mipi-dbi.c10
-rw-r--r--drivers/gpu/drm/tiny/simpledrm.c140
-rw-r--r--drivers/gpu/drm/tiny/st7586.c39
-rw-r--r--drivers/gpu/drm/tiny/st7735r.c5
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo.c227
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_util.c131
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_vm.c22
-rw-r--r--drivers/gpu/drm/ttm/ttm_device.c26
-rw-r--r--drivers/gpu/drm/ttm/ttm_execbuf_util.c6
-rw-r--r--drivers/gpu/drm/ttm/ttm_pool.c3
-rw-r--r--drivers/gpu/drm/ttm/ttm_range_manager.c2
-rw-r--r--drivers/gpu/drm/ttm/ttm_resource.c3
-rw-r--r--drivers/gpu/drm/ttm/ttm_tt.c3
-rw-r--r--drivers/gpu/drm/udl/udl_drv.c2
-rw-r--r--drivers/gpu/drm/udl/udl_modeset.c1
-rw-r--r--drivers/gpu/drm/v3d/v3d_debugfs.c22
-rw-r--r--drivers/gpu/drm/v3d/v3d_gem.c62
-rw-r--r--drivers/gpu/drm/vboxvideo/vbox_drv.c8
-rw-r--r--drivers/gpu/drm/vboxvideo/vbox_main.c1
-rw-r--r--drivers/gpu/drm/vc4/Kconfig16
-rw-r--r--drivers/gpu/drm/vc4/Makefile7
-rw-r--r--drivers/gpu/drm/vc4/tests/.kunitconfig13
-rw-r--r--drivers/gpu/drm/vc4/tests/vc4_mock.c200
-rw-r--r--drivers/gpu/drm/vc4/tests/vc4_mock.h63
-rw-r--r--drivers/gpu/drm/vc4/tests/vc4_mock_crtc.c41
-rw-r--r--drivers/gpu/drm/vc4/tests/vc4_mock_output.c138
-rw-r--r--drivers/gpu/drm/vc4/tests/vc4_mock_plane.c47
-rw-r--r--drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c1039
-rw-r--r--drivers/gpu/drm/vc4/vc4_bo.c10
-rw-r--r--drivers/gpu/drm/vc4/vc4_crtc.c215
-rw-r--r--drivers/gpu/drm/vc4/vc4_debugfs.c36
-rw-r--r--drivers/gpu/drm/vc4/vc4_dpi.c34
-rw-r--r--drivers/gpu/drm/vc4/vc4_drv.c5
-rw-r--r--drivers/gpu/drm/vc4/vc4_drv.h148
-rw-r--r--drivers/gpu/drm/vc4/vc4_dsi.c189
-rw-r--r--drivers/gpu/drm/vc4/vc4_hdmi.c28
-rw-r--r--drivers/gpu/drm/vc4/vc4_hdmi_regs.h4
-rw-r--r--drivers/gpu/drm/vc4/vc4_hvs.c272
-rw-r--r--drivers/gpu/drm/vc4/vc4_kms.c139
-rw-r--r--drivers/gpu/drm/vc4/vc4_plane.c139
-rw-r--r--drivers/gpu/drm/vc4/vc4_regs.h20
-rw-r--r--drivers/gpu/drm/vc4/vc4_txp.c62
-rw-r--r--drivers/gpu/drm/vc4/vc4_v3d.c14
-rw-r--r--drivers/gpu/drm/vc4/vc4_vec.c365
-rw-r--r--drivers/gpu/drm/via/Makefile8
-rw-r--r--drivers/gpu/drm/via/via_3d_reg.h1771
-rw-r--r--drivers/gpu/drm/via/via_dri1.c3630
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_drv.h3
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_trace.h26
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_vq.c13
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_vram.c2
-rw-r--r--drivers/gpu/drm/vkms/vkms_drv.c27
-rw-r--r--drivers/gpu/drm/vkms/vkms_drv.h4
-rw-r--r--drivers/gpu/drm/vkms/vkms_plane.c36
-rw-r--r--drivers/gpu/drm/vmwgfx/ttm_object.h10
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c2
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.c1
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.h4
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c2
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c1
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c1
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_system_manager.c1
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c1
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c2
-rw-r--r--drivers/gpu/drm/xen/xen_drm_front_gem.c3
-rw-r--r--drivers/gpu/host1x/bus.c2
-rw-r--r--drivers/gpu/host1x/cdma.c16
-rw-r--r--drivers/gpu/host1x/cdma.h2
-rw-r--r--drivers/gpu/host1x/context.c8
-rw-r--r--drivers/gpu/host1x/debug.c7
-rw-r--r--drivers/gpu/host1x/dev.c4
-rw-r--r--drivers/gpu/host1x/dev.h10
-rw-r--r--drivers/gpu/host1x/fence.c118
-rw-r--r--drivers/gpu/host1x/fence.h19
-rw-r--r--drivers/gpu/host1x/hw/channel_hw.c60
-rw-r--r--drivers/gpu/host1x/hw/hw_host1x06_uclass.h2
-rw-r--r--drivers/gpu/host1x/hw/hw_host1x07_uclass.h2
-rw-r--r--drivers/gpu/host1x/hw/hw_host1x08_uclass.h2
-rw-r--r--drivers/gpu/host1x/hw/intr_hw.c74
-rw-r--r--drivers/gpu/host1x/hw/syncpt_hw.c3
-rw-r--r--drivers/gpu/host1x/intr.c334
-rw-r--r--drivers/gpu/host1x/intr.h83
-rw-r--r--drivers/gpu/host1x/job.c12
-rw-r--r--drivers/gpu/host1x/syncpt.c98
-rw-r--r--drivers/gpu/host1x/syncpt.h3
-rw-r--r--drivers/gpu/ipu-v3/ipu-common.c1
-rw-r--r--drivers/greybus/core.c14
-rw-r--r--drivers/hid/.kunitconfig1
-rw-r--r--drivers/hid/Kconfig39
-rw-r--r--drivers/hid/Makefile3
-rw-r--r--drivers/hid/amd-sfh-hid/Kconfig2
-rw-r--r--drivers/hid/amd-sfh-hid/amd_sfh_hid.c2
-rw-r--r--drivers/hid/bpf/Kconfig16
-rw-r--r--drivers/hid/bpf/Makefile11
-rw-r--r--drivers/hid/bpf/entrypoints/Makefile93
-rw-r--r--drivers/hid/bpf/entrypoints/README4
-rw-r--r--drivers/hid/bpf/entrypoints/entrypoints.bpf.c25
-rw-r--r--drivers/hid/bpf/entrypoints/entrypoints.lskel.h248
-rw-r--r--drivers/hid/bpf/hid_bpf_dispatch.c551
-rw-r--r--drivers/hid/bpf/hid_bpf_dispatch.h25
-rw-r--r--drivers/hid/bpf/hid_bpf_jmp_table.c565
-rw-r--r--drivers/hid/hid-asus.c37
-rw-r--r--drivers/hid/hid-bigbenff.c75
-rw-r--r--drivers/hid/hid-core.c50
-rw-r--r--drivers/hid/hid-debug.c1
-rw-r--r--drivers/hid/hid-evision.c53
-rw-r--r--drivers/hid/hid-hyperv.c2
-rw-r--r--drivers/hid/hid-ids.h7
-rw-r--r--drivers/hid/hid-input-test.c80
-rw-r--r--drivers/hid/hid-input.c48
-rw-r--r--drivers/hid/hid-letsketch.c2
-rw-r--r--drivers/hid/hid-logitech-dj.c4
-rw-r--r--drivers/hid/hid-logitech-hidpp.c152
-rw-r--r--drivers/hid/hid-mcp2221.c3
-rw-r--r--drivers/hid/hid-multitouch.c39
-rw-r--r--drivers/hid/hid-playstation.c41
-rw-r--r--drivers/hid/hid-quirks.c2
-rw-r--r--drivers/hid/hid-sensor-custom.c242
-rw-r--r--drivers/hid/hid-sensor-hub.c6
-rw-r--r--drivers/hid/hid-sony.c1021
-rw-r--r--drivers/hid/hid-steam.c385
-rw-r--r--drivers/hid/hid-uclogic-core-test.c105
-rw-r--r--drivers/hid/hid-uclogic-core.c61
-rw-r--r--drivers/hid/hid-uclogic-params-test.c16
-rw-r--r--drivers/hid/hid-uclogic-params.c124
-rw-r--r--drivers/hid/hid-uclogic-params.h40
-rw-r--r--drivers/hid/hid-uclogic-rdesc-test.c3
-rw-r--r--drivers/hid/hid-uclogic-rdesc.c6
-rw-r--r--drivers/hid/hid-uclogic-rdesc.h5
-rw-r--r--drivers/hid/i2c-hid/Kconfig31
-rw-r--r--drivers/hid/i2c-hid/i2c-hid-acpi.c26
-rw-r--r--drivers/hid/i2c-hid/i2c-hid-core.c24
-rw-r--r--drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c42
-rw-r--r--drivers/hid/i2c-hid/i2c-hid-of-goodix.c98
-rw-r--r--drivers/hid/i2c-hid/i2c-hid.h3
-rw-r--r--drivers/hid/intel-ish-hid/Kconfig2
-rw-r--r--drivers/hid/intel-ish-hid/ishtp-hid.c2
-rw-r--r--drivers/hid/intel-ish-hid/ishtp/bus.c2
-rw-r--r--drivers/hid/surface-hid/surface_hid_core.c2
-rw-r--r--drivers/hid/uhid.c3
-rw-r--r--drivers/hid/usbhid/hid-core.c9
-rw-r--r--drivers/hsi/clients/cmt_speech.c2
-rw-r--r--drivers/hsi/hsi_core.c2
-rw-r--r--drivers/hv/vmbus_drv.c4
-rw-r--r--drivers/hwmon/Kconfig20
-rw-r--r--drivers/hwmon/Makefile2
-rw-r--r--drivers/hwmon/aht10.c3
-rw-r--r--drivers/hwmon/aquacomputer_d5next.c444
-rw-r--r--drivers/hwmon/asus-ec-sensors.c3
-rw-r--r--drivers/hwmon/coretemp.c132
-rw-r--r--drivers/hwmon/drivetemp.c11
-rw-r--r--drivers/hwmon/emc2305.c24
-rw-r--r--drivers/hwmon/ftsteutates.c555
-rw-r--r--drivers/hwmon/gxp-fan-ctrl.c253
-rw-r--r--drivers/hwmon/hih6130.c4
-rw-r--r--drivers/hwmon/ibmpex.c2
-rw-r--r--drivers/hwmon/iio_hwmon.c8
-rw-r--r--drivers/hwmon/intel-m10-bmc-hwmon.c229
-rw-r--r--drivers/hwmon/it87.c195
-rw-r--r--drivers/hwmon/ltc2945.c132
-rw-r--r--drivers/hwmon/mc34vr500.c263
-rw-r--r--drivers/hwmon/mlxreg-fan.c6
-rw-r--r--drivers/hwmon/nct6775-core.c2
-rw-r--r--drivers/hwmon/nct6775-platform.c150
-rw-r--r--drivers/hwmon/nzxt-smart2.c1
-rw-r--r--drivers/hwmon/oxp-sensors.c52
-rw-r--r--drivers/hwmon/peci/cputemp.c2
-rw-r--r--drivers/hwmon/pmbus/Kconfig36
-rw-r--r--drivers/hwmon/pmbus/Makefile2
-rw-r--r--drivers/hwmon/pmbus/ltc2978.c16
-rw-r--r--drivers/hwmon/pmbus/max16601.c14
-rw-r--r--drivers/hwmon/pmbus/mpq7932.c156
-rw-r--r--drivers/hwmon/pmbus/pmbus.h5
-rw-r--r--drivers/hwmon/pmbus/tda38640.c74
-rw-r--r--drivers/hwmon/sht15.c8
-rw-r--r--drivers/hwmon/sht21.c4
-rw-r--r--drivers/hwspinlock/hwspinlock_core.c2
-rw-r--r--drivers/hwtracing/coresight/Kconfig35
-rw-r--r--drivers/hwtracing/coresight/Makefile5
-rw-r--r--drivers/hwtracing/coresight/coresight-core.c87
-rw-r--r--drivers/hwtracing/coresight/coresight-cti-core.c23
-rw-r--r--drivers/hwtracing/coresight/coresight-cti-sysfs.c15
-rw-r--r--drivers/hwtracing/coresight/coresight-cti.h2
-rw-r--r--drivers/hwtracing/coresight/coresight-etm-perf.c31
-rw-r--r--drivers/hwtracing/coresight/coresight-etm-perf.h2
-rw-r--r--drivers/hwtracing/coresight/coresight-etm.h3
-rw-r--r--drivers/hwtracing/coresight/coresight-etm3x-core.c93
-rw-r--r--drivers/hwtracing/coresight/coresight-etm3x-sysfs.c27
-rw-r--r--drivers/hwtracing/coresight/coresight-etm4x-core.c91
-rw-r--r--drivers/hwtracing/coresight/coresight-etm4x-sysfs.c27
-rw-r--r--drivers/hwtracing/coresight/coresight-etm4x.h3
-rw-r--r--drivers/hwtracing/coresight/coresight-stm.c49
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc-core.c4
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc-etf.c45
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc-etr.c19
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc.h2
-rw-r--r--drivers/hwtracing/coresight/coresight-tpda.c211
-rw-r--r--drivers/hwtracing/coresight/coresight-tpda.h35
-rw-r--r--drivers/hwtracing/coresight/coresight-tpdm.c259
-rw-r--r--drivers/hwtracing/coresight/coresight-tpdm.h62
-rw-r--r--drivers/hwtracing/coresight/coresight-trace-id.c297
-rw-r--r--drivers/hwtracing/coresight/coresight-trace-id.h156
-rw-r--r--drivers/hwtracing/coresight/ultrasoc-smb.c648
-rw-r--r--drivers/hwtracing/coresight/ultrasoc-smb.h125
-rw-r--r--drivers/hwtracing/intel_th/core.c6
-rw-r--r--drivers/hwtracing/intel_th/intel_th.h4
-rw-r--r--drivers/hwtracing/intel_th/msu.c2
-rw-r--r--drivers/hwtracing/ptt/hisi_ptt.c10
-rw-r--r--drivers/hwtracing/stm/core.c2
-rw-r--r--drivers/i2c/algos/i2c-algo-bit.c77
-rw-r--r--drivers/i2c/busses/Kconfig18
-rw-r--r--drivers/i2c/busses/Makefile2
-rw-r--r--drivers/i2c/busses/i2c-aspeed.c4
-rw-r--r--drivers/i2c/busses/i2c-au1550.c4
-rw-r--r--drivers/i2c/busses/i2c-bcm2835.c4
-rw-r--r--drivers/i2c/busses/i2c-cadence.c23
-rw-r--r--drivers/i2c/busses/i2c-cht-wc.c46
-rw-r--r--drivers/i2c/busses/i2c-designware-common.c13
-rw-r--r--drivers/i2c/busses/i2c-designware-core.h5
-rw-r--r--drivers/i2c/busses/i2c-designware-master.c33
-rw-r--r--drivers/i2c/busses/i2c-designware-slave.c4
-rw-r--r--drivers/i2c/busses/i2c-gpio.c47
-rw-r--r--drivers/i2c/busses/i2c-gxp.c620
-rw-r--r--drivers/i2c/busses/i2c-i801.c310
-rw-r--r--drivers/i2c/busses/i2c-ls2x.c370
-rw-r--r--drivers/i2c/busses/i2c-mt65xx.c7
-rw-r--r--drivers/i2c/busses/i2c-nvidia-gpu.c4
-rw-r--r--drivers/i2c/busses/i2c-qcom-cci.c8
-rw-r--r--drivers/i2c/busses/i2c-qcom-geni.c4
-rw-r--r--drivers/i2c/busses/i2c-st.c9
-rw-r--r--drivers/i2c/busses/i2c-xiic.c586
-rw-r--r--drivers/i2c/i2c-core-base.c9
-rw-r--r--drivers/i2c/i2c-dev.c16
-rw-r--r--drivers/i3c/device.c14
-rw-r--r--drivers/i3c/master.c5
-rw-r--r--drivers/i3c/master/dw-i3c-master.c5
-rw-r--r--drivers/iio/accel/Kconfig2
-rw-r--r--drivers/iio/accel/bma400.h4
-rw-r--r--drivers/iio/accel/bma400_core.c29
-rw-r--r--drivers/iio/accel/mma9551_core.c10
-rw-r--r--drivers/iio/accel/st_accel.h1
-rw-r--r--drivers/iio/accel/st_accel_core.c1
-rw-r--r--drivers/iio/accel/st_accel_i2c.c5
-rw-r--r--drivers/iio/accel/st_accel_spi.c5
-rw-r--r--drivers/iio/adc/Kconfig34
-rw-r--r--drivers/iio/adc/Makefile3
-rw-r--r--drivers/iio/adc/ad7291.c2
-rw-r--r--drivers/iio/adc/at91-sama5d2_adc.c4
-rw-r--r--drivers/iio/adc/ep93xx_adc.c8
-rw-r--r--drivers/iio/adc/imx93_adc.c484
-rw-r--r--drivers/iio/adc/max11410.c3
-rw-r--r--drivers/iio/adc/qcom-spmi-adc5.c8
-rw-r--r--drivers/iio/adc/stm32-dfsdm-core.c99
-rw-r--r--drivers/iio/adc/stm32-dfsdm.h60
-rw-r--r--drivers/iio/adc/ti-adc128s052.c54
-rw-r--r--drivers/iio/adc/ti-ads7924.c474
-rw-r--r--drivers/iio/adc/ti-lmp92064.c332
-rw-r--r--drivers/iio/adc/xilinx-ams.c9
-rw-r--r--drivers/iio/cdc/ad7746.c3
-rw-r--r--drivers/iio/chemical/scd30_core.c46
-rw-r--r--drivers/iio/common/scmi_sensors/scmi_iio.c4
-rw-r--r--drivers/iio/dac/Kconfig21
-rw-r--r--drivers/iio/dac/Makefile1
-rw-r--r--drivers/iio/dac/ad5686.c7
-rw-r--r--drivers/iio/dac/ad5686.h1
-rw-r--r--drivers/iio/dac/ad5696-i2c.c2
-rw-r--r--drivers/iio/dac/max5522.c207
-rw-r--r--drivers/iio/imu/bno055/bno055_ser_trace.c2
-rw-r--r--drivers/iio/imu/kmx61.c2
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h5
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c12
-rw-r--r--drivers/iio/industrialio-core.c64
-rw-r--r--drivers/iio/light/Makefile2
-rw-r--r--drivers/iio/light/hid-sensor-als.c27
-rw-r--r--drivers/iio/light/hid-sensor-prox.c37
-rw-r--r--drivers/iio/light/max44009.c5
-rw-r--r--drivers/iio/light/tsl2563.c189
-rw-r--r--drivers/iio/light/vcnl4000.c449
-rw-r--r--drivers/iio/magnetometer/Kconfig14
-rw-r--r--drivers/iio/magnetometer/Makefile2
-rw-r--r--drivers/iio/magnetometer/st_magn.h1
-rw-r--r--drivers/iio/magnetometer/st_magn_core.c1
-rw-r--r--drivers/iio/magnetometer/st_magn_i2c.c5
-rw-r--r--drivers/iio/magnetometer/st_magn_spi.c5
-rw-r--r--drivers/iio/magnetometer/tmag5273.c743
-rw-r--r--drivers/iio/pressure/ms5611.h4
-rw-r--r--drivers/iio/pressure/ms5611_core.c49
-rw-r--r--drivers/iio/pressure/ms5611_i2c.c6
-rw-r--r--drivers/iio/pressure/ms5611_spi.c6
-rw-r--r--drivers/infiniband/core/cma.c300
-rw-r--r--drivers/infiniband/core/sa_query.c171
-rw-r--r--drivers/infiniband/hw/cxgb4/cm.c7
-rw-r--r--drivers/infiniband/hw/cxgb4/cq.c2
-rw-r--r--drivers/infiniband/hw/cxgb4/restrack.c2
-rw-r--r--drivers/infiniband/hw/cxgb4/t4fw_ri_api.h26
-rw-r--r--drivers/infiniband/hw/erdma/erdma_hw.h4
-rw-r--r--drivers/infiniband/hw/erdma/erdma_verbs.c4
-rw-r--r--drivers/infiniband/hw/hfi1/chip.c59
-rw-r--r--drivers/infiniband/hw/hfi1/exp_rcv.h5
-rw-r--r--drivers/infiniband/hw/hfi1/file_ops.c85
-rw-r--r--drivers/infiniband/hw/hfi1/init.c2
-rw-r--r--drivers/infiniband/hw/hfi1/sdma.c4
-rw-r--r--drivers/infiniband/hw/hfi1/sdma.h15
-rw-r--r--drivers/infiniband/hw/hfi1/user_exp_rcv.c46
-rw-r--r--drivers/infiniband/hw/hfi1/user_pages.c61
-rw-r--r--drivers/infiniband/hw/hfi1/verbs.c81
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_device.h19
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_hw_v2.c109
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_hw_v2.h3
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_main.c17
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_qp.c66
-rw-r--r--drivers/infiniband/hw/irdma/hw.c2
-rw-r--r--drivers/infiniband/hw/irdma/verbs.c313
-rw-r--r--drivers/infiniband/hw/mana/main.c22
-rw-r--r--drivers/infiniband/hw/mlx4/main.c8
-rw-r--r--drivers/infiniband/hw/mlx4/mlx4_ib.h3
-rw-r--r--drivers/infiniband/hw/mlx4/qp.c121
-rw-r--r--drivers/infiniband/hw/mlx5/cmd.c45
-rw-r--r--drivers/infiniband/hw/mlx5/cmd.h3
-rw-r--r--drivers/infiniband/hw/mlx5/cong.c28
-rw-r--r--drivers/infiniband/hw/mlx5/main.c28
-rw-r--r--drivers/infiniband/hw/mlx5/mlx5_ib.h51
-rw-r--r--drivers/infiniband/hw/mlx5/mr.c490
-rw-r--r--drivers/infiniband/hw/mlx5/odp.c67
-rw-r--r--drivers/infiniband/hw/mlx5/qp.c164
-rw-r--r--drivers/infiniband/hw/mlx5/qp.h4
-rw-r--r--drivers/infiniband/hw/mlx5/qpc.c7
-rw-r--r--drivers/infiniband/hw/mlx5/srq.c2
-rw-r--r--drivers/infiniband/hw/mlx5/umr.c4
-rw-r--r--drivers/infiniband/hw/mlx5/wr.c2
-rw-r--r--drivers/infiniband/hw/qib/qib_file_ops.c13
-rw-r--r--drivers/infiniband/hw/usnic/usnic_ib_verbs.c2
-rw-r--r--drivers/infiniband/hw/usnic/usnic_uiom.c8
-rw-r--r--drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c2
-rw-r--r--drivers/infiniband/sw/rxe/rxe.h38
-rw-r--r--drivers/infiniband/sw/rxe/rxe_loc.h12
-rw-r--r--drivers/infiniband/sw/rxe/rxe_mr.c606
-rw-r--r--drivers/infiniband/sw/rxe/rxe_pool.c46
-rw-r--r--drivers/infiniband/sw/rxe/rxe_pool.h3
-rw-r--r--drivers/infiniband/sw/rxe/rxe_queue.h108
-rw-r--r--drivers/infiniband/sw/rxe/rxe_resp.c202
-rw-r--r--drivers/infiniband/sw/rxe/rxe_verbs.c115
-rw-r--r--drivers/infiniband/sw/rxe/rxe_verbs.h32
-rw-r--r--drivers/infiniband/sw/siw/siw_mem.c23
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c2
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.c2
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c2
-rw-r--r--drivers/input/input.c23
-rw-r--r--drivers/input/joystick/xpad.c2
-rw-r--r--drivers/input/keyboard/Kconfig2
-rw-r--r--drivers/input/keyboard/applespi.c10
-rw-r--r--drivers/input/keyboard/cap11xx.c19
-rw-r--r--drivers/input/keyboard/cros_ec_keyb.c15
-rw-r--r--drivers/input/keyboard/mtk-pmic-keys.c17
-rw-r--r--drivers/input/keyboard/omap4-keypad.c6
-rw-r--r--drivers/input/keyboard/samsung-keypad.c12
-rw-r--r--drivers/input/keyboard/spear-keyboard.c4
-rw-r--r--drivers/input/keyboard/st-keyscan.c4
-rw-r--r--drivers/input/keyboard/tegra-kbc.c4
-rw-r--r--drivers/input/misc/88pm860x_onkey.c9
-rw-r--r--drivers/input/misc/ad714x-i2c.c14
-rw-r--r--drivers/input/misc/ad714x-spi.c14
-rw-r--r--drivers/input/misc/ad714x.c12
-rw-r--r--drivers/input/misc/ad714x.h4
-rw-r--r--drivers/input/misc/adxl34x-i2c.c25
-rw-r--r--drivers/input/misc/adxl34x-spi.c25
-rw-r--r--drivers/input/misc/adxl34x.c16
-rw-r--r--drivers/input/misc/adxl34x.h4
-rw-r--r--drivers/input/misc/axp20x-pek.c12
-rw-r--r--drivers/input/misc/cma3000_d0x_i2c.c6
-rw-r--r--drivers/input/misc/da7280.c8
-rw-r--r--drivers/input/misc/drv260x.c8
-rw-r--r--drivers/input/misc/drv2665.c8
-rw-r--r--drivers/input/misc/drv2667.c8
-rw-r--r--drivers/input/misc/e3x0-button.c10
-rw-r--r--drivers/input/misc/gpio-vibra.c10
-rw-r--r--drivers/input/misc/iqs269a.c335
-rw-r--r--drivers/input/misc/iqs626a.c164
-rw-r--r--drivers/input/misc/kxtj9.c8
-rw-r--r--drivers/input/misc/max77693-haptic.c11
-rw-r--r--drivers/input/misc/max8925_onkey.c9
-rw-r--r--drivers/input/misc/max8997_haptic.c7
-rw-r--r--drivers/input/misc/palmas-pwrbutton.c10
-rw-r--r--drivers/input/misc/pcf8574_keypad.c16
-rw-r--r--drivers/input/misc/pm8941-pwrkey.c10
-rw-r--r--drivers/input/misc/pm8xxx-vibrator.c6
-rw-r--r--drivers/input/misc/pmic8xxx-pwrkey.c8
-rw-r--r--drivers/input/misc/pwm-beeper.c10
-rw-r--r--drivers/input/misc/pwm-vibra.c10
-rw-r--r--drivers/input/misc/regulator-haptic.c8
-rw-r--r--drivers/input/misc/rotary_encoder.c10
-rw-r--r--drivers/input/misc/stpmic1_onkey.c12
-rw-r--r--drivers/input/misc/twl4030-vibra.c10
-rw-r--r--drivers/input/misc/twl6040-vibra.c7
-rw-r--r--drivers/input/misc/wistron_btns.c6
-rw-r--r--drivers/input/mouse/cyapa.c14
-rw-r--r--drivers/input/mouse/elan_i2c_core.c8
-rw-r--r--drivers/input/mouse/navpoint.c9
-rw-r--r--drivers/input/mouse/synaptics_i2c.c10
-rw-r--r--drivers/input/rmi4/rmi_i2c.c11
-rw-r--r--drivers/input/rmi4/rmi_smbus.c15
-rw-r--r--drivers/input/rmi4/rmi_spi.c13
-rw-r--r--drivers/input/serio/altera_ps2.c4
-rw-r--r--drivers/input/serio/ambakmi.c6
-rw-r--r--drivers/input/serio/apbps2.c4
-rw-r--r--drivers/input/serio/arc_ps2.c4
-rw-r--r--drivers/input/serio/olpc_apsp.c4
-rw-r--r--drivers/input/serio/serio.c4
-rw-r--r--drivers/input/touchscreen/ad7877.c8
-rw-r--r--drivers/input/touchscreen/ads7846.c31
-rw-r--r--drivers/input/touchscreen/ar1021_i2c.c9
-rw-r--r--drivers/input/touchscreen/atmel_mxt_ts.c8
-rw-r--r--drivers/input/touchscreen/auo-pixcir-ts.c10
-rw-r--r--drivers/input/touchscreen/bu21013_ts.c8
-rw-r--r--drivers/input/touchscreen/bu21029_ts.c8
-rw-r--r--drivers/input/touchscreen/chipone_icn8318.c6
-rw-r--r--drivers/input/touchscreen/chipone_icn8505.c8
-rw-r--r--drivers/input/touchscreen/cy8ctma140.c9
-rw-r--r--drivers/input/touchscreen/cy8ctmg110_ts.c9
-rw-r--r--drivers/input/touchscreen/cyttsp4_core.c9
-rw-r--r--drivers/input/touchscreen/cyttsp4_i2c.c2
-rw-r--r--drivers/input/touchscreen/cyttsp4_spi.c2
-rw-r--r--drivers/input/touchscreen/cyttsp5.c2
-rw-r--r--drivers/input/touchscreen/cyttsp_core.c7
-rw-r--r--drivers/input/touchscreen/cyttsp_i2c.c2
-rw-r--r--drivers/input/touchscreen/cyttsp_spi.c2
-rw-r--r--drivers/input/touchscreen/edt-ft5x06.c12
-rw-r--r--drivers/input/touchscreen/eeti_ts.c8
-rw-r--r--drivers/input/touchscreen/egalax_ts.c9
-rw-r--r--drivers/input/touchscreen/ektf2127.c10
-rw-r--r--drivers/input/touchscreen/elants_i2c.c10
-rw-r--r--drivers/input/touchscreen/exc3000.c10
-rw-r--r--drivers/input/touchscreen/goodix.c8
-rw-r--r--drivers/input/touchscreen/hideep.c8
-rw-r--r--drivers/input/touchscreen/ilitek_ts_i2c.c8
-rw-r--r--drivers/input/touchscreen/imagis.c8
-rw-r--r--drivers/input/touchscreen/imx6ul_tsc.c10
-rw-r--r--drivers/input/touchscreen/ipaq-micro-ts.c11
-rw-r--r--drivers/input/touchscreen/iqs5xx.c8
-rw-r--r--drivers/input/touchscreen/mcs5000_ts.c9
-rw-r--r--drivers/input/touchscreen/melfas_mip4.c8
-rw-r--r--drivers/input/touchscreen/migor_ts.c8
-rw-r--r--drivers/input/touchscreen/mms114.c8
-rw-r--r--drivers/input/touchscreen/msg2638.c8
-rw-r--r--drivers/input/touchscreen/pixcir_i2c_ts.c10
-rw-r--r--drivers/input/touchscreen/raydium_i2c_ts.c12
-rw-r--r--drivers/input/touchscreen/s6sy761.c15
-rw-r--r--drivers/input/touchscreen/silead.c8
-rw-r--r--drivers/input/touchscreen/st1232.c10
-rw-r--r--drivers/input/touchscreen/stmfts.c14
-rw-r--r--drivers/input/touchscreen/surface3_spi.c12
-rw-r--r--drivers/input/touchscreen/ti_am335x_tsc.c8
-rw-r--r--drivers/input/touchscreen/tsc2004.c2
-rw-r--r--drivers/input/touchscreen/tsc2005.c2
-rw-r--r--drivers/input/touchscreen/tsc200x-core.c7
-rw-r--r--drivers/input/touchscreen/wacom_i2c.c8
-rw-r--r--drivers/input/touchscreen/wdt87xx_i2c.c8
-rw-r--r--drivers/input/touchscreen/wm97xx-core.c10
-rw-r--r--drivers/input/touchscreen/zforce_ts.c8
-rw-r--r--drivers/input/touchscreen/zinitix.c8
-rw-r--r--drivers/interconnect/core.c14
-rw-r--r--drivers/interconnect/qcom/Kconfig18
-rw-r--r--drivers/interconnect/qcom/Makefile4
-rw-r--r--drivers/interconnect/qcom/sa8775p.c2541
-rw-r--r--drivers/interconnect/qcom/sc7180.h4
-rw-r--r--drivers/interconnect/qcom/sc8180x.c38
-rw-r--r--drivers/interconnect/qcom/sc8180x.h4
-rw-r--r--drivers/interconnect/qcom/sc8280xp.c25
-rw-r--r--drivers/interconnect/qcom/sc8280xp.h4
-rw-r--r--drivers/interconnect/qcom/sdm670.c440
-rw-r--r--drivers/interconnect/qcom/sdm670.h128
-rw-r--r--drivers/interconnect/qcom/sdx55.h4
-rw-r--r--drivers/interconnect/qcom/sm8150.c21
-rw-r--r--drivers/interconnect/qcom/sm8150.h4
-rw-r--r--drivers/interconnect/qcom/sm8250.c21
-rw-r--r--drivers/interconnect/qcom/sm8250.h4
-rw-r--r--drivers/iommu/Kconfig18
-rw-r--r--drivers/iommu/amd/init.c16
-rw-r--r--drivers/iommu/amd/iommu.c94
-rw-r--r--drivers/iommu/apple-dart.c632
-rw-r--r--drivers/iommu/arm/arm-smmu/arm-smmu-qcom-debug.c2
-rw-r--r--drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c4
-rw-r--r--drivers/iommu/arm/arm-smmu/qcom_iommu.c25
-rw-r--r--drivers/iommu/dma-iommu.c21
-rw-r--r--drivers/iommu/exynos-iommu.c216
-rw-r--r--drivers/iommu/fsl_pamu_domain.c6
-rw-r--r--drivers/iommu/intel/Kconfig11
-rw-r--r--drivers/iommu/intel/Makefile1
-rw-r--r--drivers/iommu/intel/dmar.c33
-rw-r--r--drivers/iommu/intel/iommu.c124
-rw-r--r--drivers/iommu/intel/iommu.h115
-rw-r--r--drivers/iommu/intel/irq_remapping.c3
-rw-r--r--drivers/iommu/intel/pasid.c20
-rw-r--r--drivers/iommu/intel/perfmon.c877
-rw-r--r--drivers/iommu/intel/perfmon.h64
-rw-r--r--drivers/iommu/intel/svm.c90
-rw-r--r--drivers/iommu/iommu-traces.c1
-rw-r--r--drivers/iommu/iommu.c195
-rw-r--r--drivers/iommu/iommufd/Kconfig2
-rw-r--r--drivers/iommu/iommufd/device.c8
-rw-r--r--drivers/iommu/iommufd/iommufd_private.h2
-rw-r--r--drivers/iommu/iommufd/main.c3
-rw-r--r--drivers/iommu/iommufd/pages.c6
-rw-r--r--drivers/iommu/iommufd/vfio_compat.c107
-rw-r--r--drivers/iommu/ipmmu-vmsa.c28
-rw-r--r--drivers/iommu/msm_iommu.c6
-rw-r--r--drivers/iommu/mtk_iommu.c9
-rw-r--r--drivers/iommu/mtk_iommu_v1.c4
-rw-r--r--drivers/iommu/of_iommu.c96
-rw-r--r--drivers/iommu/omap-iommu.c6
-rw-r--r--drivers/iommu/rockchip-iommu.c1
-rw-r--r--drivers/iommu/s390-iommu.c24
-rw-r--r--drivers/iommu/sprd-iommu.c16
-rw-r--r--drivers/iommu/sun50i-iommu.c1
-rw-r--r--drivers/iommu/tegra-gart.c6
-rw-r--r--drivers/iommu/tegra-smmu.c9
-rw-r--r--drivers/ipack/devices/ipoctal.c6
-rw-r--r--drivers/ipack/ipack.c4
-rw-r--r--drivers/irqchip/irq-apple-aic.c53
-rw-r--r--drivers/irqchip/irq-gic-v3-its.c4
-rw-r--r--drivers/irqchip/irq-imx-gpcv2.c1
-rw-r--r--drivers/leds/Kconfig11
-rw-r--r--drivers/leds/Makefile1
-rw-r--r--drivers/leds/flash/leds-mt6360.c38
-rw-r--r--drivers/leds/led-class.c1
-rw-r--r--drivers/leds/leds-an30259a.c21
-rw-r--r--drivers/leds/leds-asic3.c177
-rw-r--r--drivers/leds/leds-bcm6328.c49
-rw-r--r--drivers/leds/leds-bcm6358.c32
-rw-r--r--drivers/leds/leds-bd2802.c5
-rw-r--r--drivers/leds/leds-blinkm.c5
-rw-r--r--drivers/leds/leds-is31fl319x.c7
-rw-r--r--drivers/leds/leds-is31fl32xx.c5
-rw-r--r--drivers/leds/leds-lm3530.c5
-rw-r--r--drivers/leds/leds-lm3532.c5
-rw-r--r--drivers/leds/leds-lm355x.c6
-rw-r--r--drivers/leds/leds-lm3642.c5
-rw-r--r--drivers/leds/leds-lm3692x.c6
-rw-r--r--drivers/leds/leds-lm3697.c5
-rw-r--r--drivers/leds/leds-lp3944.c5
-rw-r--r--drivers/leds/leds-lp3952.c5
-rw-r--r--drivers/leds/leds-lp5521.c6
-rw-r--r--drivers/leds/leds-lp5523.c6
-rw-r--r--drivers/leds/leds-lp5562.c5
-rw-r--r--drivers/leds/leds-lp8501.c6
-rw-r--r--drivers/leds/leds-lp8860.c5
-rw-r--r--drivers/leds/leds-mt6323.c30
-rw-r--r--drivers/leds/leds-pca9532.c9
-rw-r--r--drivers/leds/leds-pca955x.c26
-rw-r--r--drivers/leds/leds-pca963x.c6
-rw-r--r--drivers/leds/leds-pm8058.c29
-rw-r--r--drivers/leds/leds-pwm.c4
-rw-r--r--drivers/leds/leds-syscon.c49
-rw-r--r--drivers/leds/leds-tca6507.c8
-rw-r--r--drivers/leds/leds-tlc591xx.c5
-rw-r--r--drivers/leds/leds-turris-omnia.c5
-rw-r--r--drivers/leds/leds.h1
-rw-r--r--drivers/leds/simple/simatic-ipc-leds-gpio.c2
-rw-r--r--drivers/leds/trigger/ledtrig-disk.c4
-rw-r--r--drivers/macintosh/macio_asic.c7
-rw-r--r--drivers/macintosh/windfarm_lm75_sensor.c4
-rw-r--r--drivers/macintosh/windfarm_smu_sensors.c4
-rw-r--r--drivers/mailbox/qcom-apcs-ipc-mailbox.c3
-rw-r--r--drivers/mailbox/zynqmp-ipi-mailbox.c6
-rw-r--r--drivers/mcb/mcb-core.c4
-rw-r--r--drivers/md/bcache/bcache_ondisk.h8
-rw-r--r--drivers/md/dm-audit.c2
-rw-r--r--drivers/md/dm-bio-prison-v1.c19
-rw-r--r--drivers/md/dm-bio-prison-v1.h1
-rw-r--r--drivers/md/dm-bio-prison-v2.c15
-rw-r--r--drivers/md/dm-bio-prison-v2.h11
-rw-r--r--drivers/md/dm-bio-record.h1
-rw-r--r--drivers/md/dm-bufio.c130
-rw-r--r--drivers/md/dm-builtin.c3
-rw-r--r--drivers/md/dm-cache-background-tracker.c17
-rw-r--r--drivers/md/dm-cache-background-tracker.h47
-rw-r--r--drivers/md/dm-cache-block-types.h1
-rw-r--r--drivers/md/dm-cache-metadata.c74
-rw-r--r--drivers/md/dm-cache-metadata.h5
-rw-r--r--drivers/md/dm-cache-policy-internal.h14
-rw-r--r--drivers/md/dm-cache-policy-smq.c166
-rw-r--r--drivers/md/dm-cache-policy.c3
-rw-r--r--drivers/md/dm-cache-policy.h7
-rw-r--r--drivers/md/dm-cache-target.c141
-rw-r--r--drivers/md/dm-clone-target.c2
-rw-r--r--drivers/md/dm-core.h9
-rw-r--r--drivers/md/dm-crypt.c117
-rw-r--r--drivers/md/dm-delay.c7
-rw-r--r--drivers/md/dm-dust.c2
-rw-r--r--drivers/md/dm-ebs-target.c5
-rw-r--r--drivers/md/dm-era-target.c122
-rw-r--r--drivers/md/dm-exception-store.c7
-rw-r--r--drivers/md/dm-exception-store.h57
-rw-r--r--drivers/md/dm-flakey.c58
-rw-r--r--drivers/md/dm-ima.c5
-rw-r--r--drivers/md/dm-ima.h7
-rw-r--r--drivers/md/dm-init.c5
-rw-r--r--drivers/md/dm-integrity.c541
-rw-r--r--drivers/md/dm-io-rewind.c8
-rw-r--r--drivers/md/dm-io-tracker.h1
-rw-r--r--drivers/md/dm-io.c88
-rw-r--r--drivers/md/dm-ioctl.c168
-rw-r--r--drivers/md/dm-kcopyd.c61
-rw-r--r--drivers/md/dm-linear.c5
-rw-r--r--drivers/md/dm-log-userspace-base.c15
-rw-r--r--drivers/md/dm-log-userspace-transfer.c8
-rw-r--r--drivers/md/dm-log-userspace-transfer.h1
-rw-r--r--drivers/md/dm-log-writes.c23
-rw-r--r--drivers/md/dm-log.c65
-rw-r--r--drivers/md/dm-mpath.c125
-rw-r--r--drivers/md/dm-mpath.h3
-rw-r--r--drivers/md/dm-path-selector.c4
-rw-r--r--drivers/md/dm-path-selector.h28
-rw-r--r--drivers/md/dm-ps-historical-service-time.c2
-rw-r--r--drivers/md/dm-ps-io-affinity.c6
-rw-r--r--drivers/md/dm-ps-queue-length.c15
-rw-r--r--drivers/md/dm-ps-round-robin.c22
-rw-r--r--drivers/md/dm-ps-service-time.c26
-rw-r--r--drivers/md/dm-raid.c35
-rw-r--r--drivers/md/dm-raid1.c92
-rw-r--r--drivers/md/dm-region-hash.c29
-rw-r--r--drivers/md/dm-rq.c27
-rw-r--r--drivers/md/dm-rq.h3
-rw-r--r--drivers/md/dm-snap-persistent.c48
-rw-r--r--drivers/md/dm-snap-transient.c18
-rw-r--r--drivers/md/dm-snap.c91
-rw-r--r--drivers/md/dm-stats.c103
-rw-r--r--drivers/md/dm-stats.h6
-rw-r--r--drivers/md/dm-stripe.c53
-rw-r--r--drivers/md/dm-switch.c47
-rw-r--r--drivers/md/dm-sysfs.c12
-rw-r--r--drivers/md/dm-table.c58
-rw-r--r--drivers/md/dm-target.c6
-rw-r--r--drivers/md/dm-thin-metadata.c66
-rw-r--r--drivers/md/dm-thin-metadata.h1
-rw-r--r--drivers/md/dm-thin.c88
-rw-r--r--drivers/md/dm-uevent.c6
-rw-r--r--drivers/md/dm-uevent.h6
-rw-r--r--drivers/md/dm-unstripe.c1
-rw-r--r--drivers/md/dm-verity-fec.c30
-rw-r--r--drivers/md/dm-verity-fec.h18
-rw-r--r--drivers/md/dm-verity-target.c83
-rw-r--r--drivers/md/dm-verity-verify-sig.c2
-rw-r--r--drivers/md/dm-verity-verify-sig.h2
-rw-r--r--drivers/md/dm-verity.h8
-rw-r--r--drivers/md/dm-writecache.c171
-rw-r--r--drivers/md/dm-zero.c1
-rw-r--r--drivers/md/dm-zone.c2
-rw-r--r--drivers/md/dm-zoned-metadata.c22
-rw-r--r--drivers/md/dm-zoned-target.c1
-rw-r--r--drivers/md/dm.c116
-rw-r--r--drivers/md/dm.h16
-rw-r--r--drivers/md/persistent-data/dm-array.c82
-rw-r--r--drivers/md/persistent-data/dm-array.h3
-rw-r--r--drivers/md/persistent-data/dm-bitset.c14
-rw-r--r--drivers/md/persistent-data/dm-bitset.h1
-rw-r--r--drivers/md/persistent-data/dm-block-manager.c32
-rw-r--r--drivers/md/persistent-data/dm-block-manager.h7
-rw-r--r--drivers/md/persistent-data/dm-btree-internal.h6
-rw-r--r--drivers/md/persistent-data/dm-btree-remove.c52
-rw-r--r--drivers/md/persistent-data/dm-btree-spine.c21
-rw-r--r--drivers/md/persistent-data/dm-btree.c130
-rw-r--r--drivers/md/persistent-data/dm-btree.h15
-rw-r--r--drivers/md/persistent-data/dm-persistent-data-internal.h7
-rw-r--r--drivers/md/persistent-data/dm-space-map-common.c52
-rw-r--r--drivers/md/persistent-data/dm-space-map-common.h11
-rw-r--r--drivers/md/persistent-data/dm-space-map-disk.c13
-rw-r--r--drivers/md/persistent-data/dm-space-map-disk.h1
-rw-r--r--drivers/md/persistent-data/dm-space-map-metadata.c24
-rw-r--r--drivers/md/persistent-data/dm-space-map-metadata.h1
-rw-r--r--drivers/md/persistent-data/dm-space-map.h1
-rw-r--r--drivers/md/persistent-data/dm-transaction-manager.c18
-rw-r--r--drivers/md/persistent-data/dm-transaction-manager.h3
-rw-r--r--drivers/media/common/Kconfig4
-rw-r--r--drivers/media/common/Makefile3
-rw-r--r--drivers/media/common/saa7146/Kconfig (renamed from drivers/staging/media/deprecated/saa7146/common/Kconfig)0
-rw-r--r--drivers/media/common/saa7146/Makefile (renamed from drivers/staging/media/deprecated/saa7146/common/Makefile)0
-rw-r--r--drivers/media/common/saa7146/saa7146_core.c (renamed from drivers/staging/media/deprecated/saa7146/common/saa7146_core.c)2
-rw-r--r--drivers/media/common/saa7146/saa7146_fops.c (renamed from drivers/staging/media/deprecated/saa7146/common/saa7146_fops.c)2
-rw-r--r--drivers/media/common/saa7146/saa7146_hlp.c (renamed from drivers/staging/media/deprecated/saa7146/common/saa7146_hlp.c)2
-rw-r--r--drivers/media/common/saa7146/saa7146_i2c.c (renamed from drivers/staging/media/deprecated/saa7146/common/saa7146_i2c.c)2
-rw-r--r--drivers/media/common/saa7146/saa7146_vbi.c (renamed from drivers/staging/media/deprecated/saa7146/common/saa7146_vbi.c)2
-rw-r--r--drivers/media/common/saa7146/saa7146_video.c (renamed from drivers/staging/media/deprecated/saa7146/common/saa7146_video.c)2
-rw-r--r--drivers/media/common/uvc.c183
-rw-r--r--drivers/media/common/videobuf2/videobuf2-core.c25
-rw-r--r--drivers/media/common/videobuf2/videobuf2-dma-contig.c2
-rw-r--r--drivers/media/common/videobuf2/videobuf2-vmalloc.c2
-rw-r--r--drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c4
-rw-r--r--drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c14
-rw-r--r--drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c14
-rw-r--r--drivers/media/dvb-frontends/drx39xyj/drxj.c9
-rw-r--r--drivers/media/dvb-frontends/dvb-pll.c5
-rw-r--r--drivers/media/dvb-frontends/m88ds3103.c6
-rw-r--r--drivers/media/dvb-frontends/mb86a16.c9
-rw-r--r--drivers/media/dvb-frontends/mn88443x.c6
-rw-r--r--drivers/media/dvb-frontends/tc90522.c6
-rw-r--r--drivers/media/i2c/Kconfig40
-rw-r--r--drivers/media/i2c/Makefile3
-rw-r--r--drivers/media/i2c/adv7180.c6
-rw-r--r--drivers/media/i2c/adv7604.c6
-rw-r--r--drivers/media/i2c/ak7375.c38
-rw-r--r--drivers/media/i2c/cs53l32a.c6
-rw-r--r--drivers/media/i2c/imx219.c311
-rw-r--r--drivers/media/i2c/imx290.c1019
-rw-r--r--drivers/media/i2c/imx296.c1172
-rw-r--r--drivers/media/i2c/imx415.c1300
-rw-r--r--drivers/media/i2c/ir-kbd-i2c.c5
-rw-r--r--drivers/media/i2c/max9286.c463
-rw-r--r--drivers/media/i2c/msp3400-driver.c5
-rw-r--r--drivers/media/i2c/mt9p031.c6
-rw-r--r--drivers/media/i2c/mt9v032.c6
-rw-r--r--drivers/media/i2c/ov2740.c4
-rw-r--r--drivers/media/i2c/ov5640.c86
-rw-r--r--drivers/media/i2c/ov5670.c312
-rw-r--r--drivers/media/i2c/ov5675.c198
-rw-r--r--drivers/media/i2c/ov7670.c8
-rw-r--r--drivers/media/i2c/ov772x.c3
-rw-r--r--drivers/media/i2c/ov8858.c2008
-rw-r--r--drivers/media/i2c/ov9282.c9
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3-core.c22
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c1
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3.h1
-rw-r--r--drivers/media/i2c/saa7115.c6
-rw-r--r--drivers/media/i2c/saa7127.c6
-rw-r--r--drivers/media/i2c/st-vgxy61.c4
-rw-r--r--drivers/media/i2c/tc358746.c9
-rw-r--r--drivers/media/i2c/tda1997x.c6
-rw-r--r--drivers/media/i2c/tvaudio.c5
-rw-r--r--drivers/media/i2c/tvp514x.c6
-rw-r--r--drivers/media/i2c/video-i2c.c6
-rw-r--r--drivers/media/mc/mc-entity.c86
-rw-r--r--drivers/media/pci/Kconfig2
-rw-r--r--drivers/media/pci/Makefile4
-rw-r--r--drivers/media/pci/intel/ipu3/cio2-bridge.c27
-rw-r--r--drivers/media/pci/intel/ipu3/cio2-bridge.h5
-rw-r--r--drivers/media/pci/intel/ipu3/ipu3-cio2-main.c3
-rw-r--r--drivers/media/pci/saa7134/saa7134-core.c2
-rw-r--r--drivers/media/pci/saa7146/Kconfig (renamed from drivers/staging/media/deprecated/saa7146/saa7146/Kconfig)15
-rw-r--r--drivers/media/pci/saa7146/Makefile (renamed from drivers/staging/media/deprecated/saa7146/saa7146/Makefile)0
-rw-r--r--drivers/media/pci/saa7146/hexium_gemini.c (renamed from drivers/staging/media/deprecated/saa7146/saa7146/hexium_gemini.c)2
-rw-r--r--drivers/media/pci/saa7146/hexium_orion.c (renamed from drivers/staging/media/deprecated/saa7146/saa7146/hexium_orion.c)2
-rw-r--r--drivers/media/pci/saa7146/mxb.c (renamed from drivers/staging/media/deprecated/saa7146/saa7146/mxb.c)2
-rw-r--r--drivers/media/pci/ttpci/Kconfig (renamed from drivers/staging/media/deprecated/saa7146/ttpci/Kconfig)17
-rw-r--r--drivers/media/pci/ttpci/Makefile (renamed from drivers/staging/media/deprecated/saa7146/ttpci/Makefile)0
-rw-r--r--drivers/media/pci/ttpci/budget-av.c (renamed from drivers/staging/media/deprecated/saa7146/ttpci/budget-av.c)2
-rw-r--r--drivers/media/pci/ttpci/budget-ci.c (renamed from drivers/staging/media/deprecated/saa7146/ttpci/budget-ci.c)0
-rw-r--r--drivers/media/pci/ttpci/budget-core.c (renamed from drivers/staging/media/deprecated/saa7146/ttpci/budget-core.c)0
-rw-r--r--drivers/media/pci/ttpci/budget.c (renamed from drivers/staging/media/deprecated/saa7146/ttpci/budget.c)0
-rw-r--r--drivers/media/pci/ttpci/budget.h (renamed from drivers/staging/media/deprecated/saa7146/ttpci/budget.h)2
-rw-r--r--drivers/media/platform/amphion/venc.c18
-rw-r--r--drivers/media/platform/amphion/vpu_color.c6
-rw-r--r--drivers/media/platform/chips-media/imx-vdoa.c6
-rw-r--r--drivers/media/platform/marvell/mmp-driver.c2
-rw-r--r--drivers/media/platform/mediatek/mdp3/Kconfig7
-rw-r--r--drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c3
-rw-r--r--drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c7
-rw-r--r--drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c6
-rw-r--r--drivers/media/platform/mediatek/vcodec/venc/venc_h264_if.c4
-rw-r--r--drivers/media/platform/microchip/microchip-isc-base.c109
-rw-r--r--drivers/media/platform/nxp/dw100/dw100.c2
-rw-r--r--drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c35
-rw-r--r--drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h4
-rw-r--r--drivers/media/platform/nxp/imx-mipi-csis.c252
-rw-r--r--drivers/media/platform/nxp/imx-pxp.c359
-rw-r--r--drivers/media/platform/nxp/imx7-media-csi.c239
-rw-r--r--drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c3
-rw-r--r--drivers/media/platform/qcom/venus/firmware.c4
-rw-r--r--drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c2
-rw-r--r--drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c2
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_drv.c4
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_hgo.c4
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_lif.c1
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_pipe.c18
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_regs.h26
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_rpf.c64
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_video.c4
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_wpf.c4
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c15
-rw-r--r--drivers/media/platform/samsung/exynos4-is/fimc-is.h3
-rw-r--r--drivers/media/platform/samsung/exynos4-is/media-dev.h1
-rw-r--r--drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c4
-rw-r--r--drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c1
-rw-r--r--drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c4
-rw-r--r--drivers/media/platform/ti/cal/cal.c4
-rw-r--r--drivers/media/platform/ti/davinci/vpif.c2
-rw-r--r--drivers/media/platform/ti/omap3isp/isp.c9
-rw-r--r--drivers/media/platform/ti/omap3isp/ispvideo.c20
-rw-r--r--drivers/media/platform/verisilicon/hantro_drv.c2
-rw-r--r--drivers/media/platform/verisilicon/hantro_v4l2.c9
-rw-r--r--drivers/media/platform/xilinx/xilinx-dma.c28
-rw-r--r--drivers/media/radio/wl128x/fmdrv_common.c2
-rw-r--r--drivers/media/rc/Kconfig4
-rw-r--r--drivers/media/rc/ene_ir.c3
-rw-r--r--drivers/media/rc/gpio-ir-recv.c18
-rw-r--r--drivers/media/rc/ir-rx51.c6
-rw-r--r--drivers/media/rc/pwm-ir-tx.c2
-rw-r--r--drivers/media/rc/rc-main.c2
-rw-r--r--drivers/media/test-drivers/vidtv/vidtv_psi.c2
-rw-r--r--drivers/media/test-drivers/visl/visl-video.c2
-rw-r--r--drivers/media/tuners/si2157.c6
-rw-r--r--drivers/media/usb/dvb-usb-v2/af9015.c4
-rw-r--r--drivers/media/usb/go7007/go7007-v4l2.c6
-rw-r--r--drivers/media/usb/siano/smsusb.c1
-rw-r--r--drivers/media/usb/uvc/Kconfig1
-rw-r--r--drivers/media/usb/uvc/uvc_ctrl.c342
-rw-r--r--drivers/media/usb/uvc/uvc_driver.c185
-rw-r--r--drivers/media/usb/uvc/uvc_entity.c2
-rw-r--r--drivers/media/usb/uvc/uvc_status.c125
-rw-r--r--drivers/media/usb/uvc/uvc_v4l2.c111
-rw-r--r--drivers/media/usb/uvc/uvc_video.c58
-rw-r--r--drivers/media/usb/uvc/uvcvideo.h39
-rw-r--r--drivers/media/v4l2-core/v4l2-h264.c4
-rw-r--r--drivers/media/v4l2-core/v4l2-ioctl.c31
-rw-r--r--drivers/media/v4l2-core/v4l2-jpeg.c4
-rw-r--r--drivers/media/v4l2-core/v4l2-mem2mem.c4
-rw-r--r--drivers/media/v4l2-core/v4l2-subdev.c1017
-rw-r--r--drivers/media/v4l2-core/videobuf-dma-contig.c2
-rw-r--r--drivers/media/v4l2-core/videobuf-dma-sg.c4
-rw-r--r--drivers/media/v4l2-core/videobuf-vmalloc.c2
-rw-r--r--drivers/memory/renesas-rpc-if.c155
-rw-r--r--drivers/memory/ti-emif-pm.c7
-rw-r--r--drivers/memstick/core/Kconfig2
-rw-r--r--drivers/memstick/core/memstick.c6
-rw-r--r--drivers/mfd/Kconfig33
-rw-r--r--drivers/mfd/Makefile5
-rw-r--r--drivers/mfd/arizona-core.c2
-rw-r--r--drivers/mfd/axp20x.c27
-rw-r--r--drivers/mfd/intel-m10-bmc-core.c122
-rw-r--r--drivers/mfd/intel-m10-bmc-pmci.c455
-rw-r--r--drivers/mfd/intel-m10-bmc-spi.c168
-rw-r--r--drivers/mfd/intel-m10-bmc.c238
-rw-r--r--drivers/mfd/intel_soc_pmic_chtwc.c8
-rw-r--r--drivers/mfd/kempld-core.c7
-rw-r--r--drivers/mfd/lm3533-core.c2
-rw-r--r--drivers/mfd/max8925-core.c6
-rw-r--r--drivers/mfd/ntxec.c1
-rw-r--r--drivers/mfd/ocelot-core.c2
-rw-r--r--drivers/mfd/pcf50633-adc.c7
-rw-r--r--drivers/mfd/qcom-pm8xxx.c3
-rw-r--r--drivers/mfd/rk808.c1
-rw-r--r--drivers/mfd/simple-mfd-i2c.c2
-rw-r--r--drivers/mfd/syscon.c27
-rw-r--r--drivers/mfd/twl-core.c9
-rw-r--r--drivers/mfd/twl4030-power.c6
-rw-r--r--drivers/mfd/wm97xx-core.c4
-rw-r--r--drivers/misc/Kconfig21
-rw-r--r--drivers/misc/Makefile3
-rw-r--r--drivers/misc/cxl/context.c2
-rw-r--r--drivers/misc/eeprom/at25.c8
-rw-r--r--drivers/misc/eeprom/idt_89hpesx.c10
-rw-r--r--drivers/misc/enclosure.c2
-rw-r--r--drivers/misc/fastrpc.c15
-rw-r--r--drivers/misc/genwqe/card_utils.c6
-rw-r--r--drivers/misc/habanalabs/include/gaudi2/arc/gaudi2_arc_common_packets.h213
-rw-r--r--drivers/misc/isl29003.c10
-rw-r--r--drivers/misc/mei/bus-fixup.c26
-rw-r--r--drivers/misc/mei/bus.c7
-rw-r--r--drivers/misc/mei/hdcp/mei_hdcp.c4
-rw-r--r--drivers/misc/mei/mei_dev.h5
-rw-r--r--drivers/misc/mei/pxp/mei_pxp.c4
-rw-r--r--drivers/misc/ocxl/context.c4
-rw-r--r--drivers/misc/ocxl/sysfs.c2
-rw-r--r--drivers/misc/open-dice.c18
-rw-r--r--drivers/misc/pci_endpoint_test.c4
-rw-r--r--drivers/misc/sgi-gru/grufile.c4
-rw-r--r--drivers/misc/sgi-gru/grukservices.c8
-rw-r--r--drivers/misc/ti-st/st_core.c2
-rw-r--r--drivers/misc/tifm_core.c4
-rw-r--r--drivers/misc/uacce/uacce.c52
-rw-r--r--drivers/misc/vmw_balloon.c2
-rw-r--r--drivers/misc/vmw_vmci/vmci_host.c2
-rw-r--r--drivers/misc/xilinx_tmr_inject.c171
-rw-r--r--drivers/misc/xilinx_tmr_manager.c220
-rw-r--r--drivers/mmc/core/Kconfig3
-rw-r--r--drivers/mmc/core/block.c25
-rw-r--r--drivers/mmc/core/bus.c4
-rw-r--r--drivers/mmc/core/host.c26
-rw-r--r--drivers/mmc/core/mmc_ops.c1
-rw-r--r--drivers/mmc/core/pwrseq_simple.c4
-rw-r--r--drivers/mmc/core/sdio_bus.c4
-rw-r--r--drivers/mmc/core/sdio_io.c2
-rw-r--r--drivers/mmc/core/sdio_uart.c13
-rw-r--r--drivers/mmc/core/slot-gpio.c17
-rw-r--r--drivers/mmc/host/Kconfig11
-rw-r--r--drivers/mmc/host/Makefile1
-rw-r--r--drivers/mmc/host/atmel-mci.c3
-rw-r--r--drivers/mmc/host/dw_mmc-starfive.c186
-rw-r--r--drivers/mmc/host/jz4740_mmc.c38
-rw-r--r--drivers/mmc/host/meson-gx-mmc.c92
-rw-r--r--drivers/mmc/host/moxart-mmc.c9
-rw-r--r--drivers/mmc/host/renesas_sdhi_internal_dmac.c11
-rw-r--r--drivers/mmc/host/sdhci-brcmstb.c8
-rw-r--r--drivers/mmc/host/sdhci-esdhc-imx.c66
-rw-r--r--drivers/mmc/host/sdhci-iproc.c14
-rw-r--r--drivers/mmc/host/sdhci-msm.c2
-rw-r--r--drivers/mmc/host/sdhci-of-dwcmshc.c19
-rw-r--r--drivers/mmc/host/sdhci-pci-core.c8
-rw-r--r--drivers/mmc/host/sdhci-pxav2.c154
-rw-r--r--drivers/mmc/host/sdhci-pxav3.c4
-rw-r--r--drivers/mmc/host/sdhci-sprd.c6
-rw-r--r--drivers/mmc/host/sdhci.c3
-rw-r--r--drivers/mmc/host/sdhci.h2
-rw-r--r--drivers/mmc/host/uniphier-sd.c83
-rw-r--r--drivers/most/Kconfig2
-rw-r--r--drivers/most/most_cdev.c5
-rw-r--r--drivers/most/most_snd.c10
-rw-r--r--drivers/most/most_usb.c6
-rw-r--r--drivers/mtd/devices/mtd_dataflash.c9
-rw-r--r--drivers/mtd/hyperbus/rpc-if.c18
-rw-r--r--drivers/mtd/mtdpart.c10
-rw-r--r--drivers/mtd/nand/ecc-mtk.c28
-rw-r--r--drivers/mtd/nand/raw/Kconfig7
-rw-r--r--drivers/mtd/nand/raw/Makefile1
-rw-r--r--drivers/mtd/nand/raw/fsl_elbc_nand.c8
-rw-r--r--drivers/mtd/nand/raw/marvell_nand.c7
-rw-r--r--drivers/mtd/nand/raw/nand_base.c149
-rw-r--r--drivers/mtd/nand/raw/nand_jedec.c3
-rw-r--r--drivers/mtd/nand/raw/nand_onfi.c3
-rw-r--r--drivers/mtd/nand/raw/pasemi_nand.c63
-rw-r--r--drivers/mtd/nand/raw/sunxi_nand.c120
-rw-r--r--drivers/mtd/nand/raw/tmio_nand.c533
-rw-r--r--drivers/mtd/nand/raw/vf610_nfc.c4
-rw-r--r--drivers/mtd/nand/spi/Makefile2
-rw-r--r--drivers/mtd/nand/spi/alliancememory.c153
-rw-r--r--drivers/mtd/nand/spi/core.c1
-rw-r--r--drivers/mtd/nand/spi/macronix.c3
-rw-r--r--drivers/mtd/parsers/ofpart_core.c19
-rw-r--r--drivers/mtd/spi-nor/core.c20
-rw-r--r--drivers/mtd/spi-nor/core.h44
-rw-r--r--drivers/mtd/spi-nor/debugfs.c2
-rw-r--r--drivers/mtd/spi-nor/issi.c2
-rw-r--r--drivers/mtd/spi-nor/macronix.c2
-rw-r--r--drivers/mtd/spi-nor/sfdp.c78
-rw-r--r--drivers/mtd/spi-nor/sfdp.h9
-rw-r--r--drivers/mtd/spi-nor/spansion.c27
-rw-r--r--drivers/mtd/ubi/block.c109
-rw-r--r--drivers/mtd/ubi/build.c32
-rw-r--r--drivers/mtd/ubi/debug.c19
-rw-r--r--drivers/mtd/ubi/eba.c2
-rw-r--r--drivers/mtd/ubi/fastmap-wl.c12
-rw-r--r--drivers/mtd/ubi/fastmap.c2
-rw-r--r--drivers/mtd/ubi/kapi.c1
-rw-r--r--drivers/mtd/ubi/misc.c2
-rw-r--r--drivers/mtd/ubi/vmt.c18
-rw-r--r--drivers/mtd/ubi/wl.c27
-rw-r--r--drivers/net/dsa/ocelot/felix_vsc9959.c2
-rw-r--r--drivers/net/dsa/ocelot/ocelot_ext.c3
-rw-r--r--drivers/net/dsa/ocelot/seville_vsc9953.c4
-rw-r--r--drivers/net/ethernet/freescale/fman/fman_memac.c9
-rw-r--r--drivers/net/ethernet/ibm/ibmvnic.c4
-rw-r--r--drivers/net/ethernet/intel/Kconfig4
-rw-r--r--drivers/net/ethernet/intel/ice/Makefile2
-rw-r--r--drivers/net/ethernet/intel/ice/ice_gnss.h4
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c2
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c76
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/qp.c14
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/ecpf.c4
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c25
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c3
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/tc/act_stats.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h4
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_main.c22
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_stats.c1
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_stats.h1
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_tc.c59
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c3
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/geneve.c1
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/ipsec_fs_roce.c13
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/sriov.c4
-rw-r--r--drivers/net/ethernet/microchip/lan966x/lan966x_main.c5
-rw-r--r--drivers/net/ethernet/qlogic/qede/qede_main.c21
-rw-r--r--drivers/net/ethernet/sun/sunhme.c6
-rw-r--r--drivers/net/ipa/ipa_main.c2
-rw-r--r--drivers/net/ipa/ipa_mem.c6
-rw-r--r--drivers/net/mdio/mdio-mscc-miim.c9
-rw-r--r--drivers/net/phy/mdio_bus.c2
-rw-r--r--drivers/net/phy/phy-c45.c56
-rw-r--r--drivers/net/phy/phy_device.c21
-rw-r--r--drivers/net/wireless/ath/ath10k/qmi.c2
-rw-r--r--drivers/net/wireless/ath/ath10k/snoc.c2
-rw-r--r--drivers/net/wireless/ath/ath11k/ahb.c4
-rw-r--r--drivers/net/wireless/ath/ath11k/pci.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/usb.c1
-rw-r--r--drivers/net/xen-netback/netback.c5
-rw-r--r--drivers/net/xen-netback/xenbus.c2
-rw-r--r--drivers/nfc/st-nci/se.c6
-rw-r--r--drivers/nfc/st21nfca/se.c6
-rw-r--r--drivers/nvdimm/btt.c16
-rw-r--r--drivers/nvdimm/bus.c23
-rw-r--r--drivers/nvdimm/dax_devs.c2
-rw-r--r--drivers/nvdimm/dimm_devs.c7
-rw-r--r--drivers/nvdimm/nd-core.h11
-rw-r--r--drivers/nvdimm/nd.h4
-rw-r--r--drivers/nvdimm/pmem.c24
-rw-r--r--drivers/nvdimm/region_devs.c4
-rw-r--r--drivers/nvdimm/virtio_pmem.c11
-rw-r--r--drivers/nvmem/Kconfig10
-rw-r--r--drivers/nvmem/Makefile1
-rw-r--r--drivers/nvmem/core.c145
-rw-r--r--drivers/nvmem/imx-ocotp.c4
-rw-r--r--drivers/nvmem/qcom-spmi-sdam.c13
-rw-r--r--drivers/nvmem/rave-sp-eeprom.c2
-rw-r--r--drivers/nvmem/stm32-bsec-optee-ta.c298
-rw-r--r--drivers/nvmem/stm32-bsec-optee-ta.h80
-rw-r--r--drivers/nvmem/stm32-romem.c84
-rw-r--r--drivers/nvmem/sunxi_sid.c8
-rw-r--r--drivers/of/Kconfig14
-rw-r--r--drivers/of/address.c41
-rw-r--r--drivers/of/base.c3
-rw-r--r--drivers/of/device.c10
-rw-r--r--drivers/of/dynamic.c31
-rw-r--r--drivers/of/irq.c12
-rw-r--r--drivers/of/kobj.c2
-rw-r--r--drivers/of/of_reserved_mem.c10
-rw-r--r--drivers/of/overlay.c2
-rw-r--r--drivers/of/platform.c7
-rw-r--r--drivers/of/property.c94
-rw-r--r--drivers/of/unittest-data/testcases_common.dtsi1
-rw-r--r--drivers/of/unittest-data/tests-lifecycle.dtsi8
-rw-r--r--drivers/of/unittest.c150
-rw-r--r--drivers/parport/parport_pc.c125
-rw-r--r--drivers/pci/controller/Kconfig3
-rw-r--r--drivers/pci/controller/dwc/Kconfig23
-rw-r--r--drivers/pci/controller/dwc/pci-dra7xx.c2
-rw-r--r--drivers/pci/controller/dwc/pci-imx6.c200
-rw-r--r--drivers/pci/controller/dwc/pcie-bt1.c4
-rw-r--r--drivers/pci/controller/dwc/pcie-designware-ep.c12
-rw-r--r--drivers/pci/controller/dwc/pcie-designware-host.c25
-rw-r--r--drivers/pci/controller/dwc/pcie-designware.c195
-rw-r--r--drivers/pci/controller/dwc/pcie-designware.h21
-rw-r--r--drivers/pci/controller/dwc/pcie-histb.c1
-rw-r--r--drivers/pci/controller/dwc/pcie-qcom.c15
-rw-r--r--drivers/pci/controller/dwc/pcie-tegra194.c9
-rw-r--r--drivers/pci/controller/mobiveil/pcie-mobiveil-plat.c1
-rw-r--r--drivers/pci/controller/pci-loongson.c71
-rw-r--r--drivers/pci/controller/pci-tegra.c6
-rw-r--r--drivers/pci/controller/pci-versatile.c1
-rw-r--r--drivers/pci/controller/pcie-hisi-error.c1
-rw-r--r--drivers/pci/controller/pcie-microchip-host.c1
-rw-r--r--drivers/pci/controller/pcie-mt7621.c2
-rw-r--r--drivers/pci/controller/vmd.c97
-rw-r--r--drivers/pci/endpoint/functions/pci-epf-test.c38
-rw-r--r--drivers/pci/endpoint/functions/pci-epf-vntb.c1
-rw-r--r--drivers/pci/endpoint/pci-ep-cfs.c1
-rw-r--r--drivers/pci/endpoint/pci-epc-core.c33
-rw-r--r--drivers/pci/endpoint/pci-epc-mem.c1
-rw-r--r--drivers/pci/endpoint/pci-epf-core.c1
-rw-r--r--drivers/pci/hotplug/acpiphp_core.c1
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c2
-rw-r--r--drivers/pci/hotplug/shpchp_core.c1
-rw-r--r--drivers/pci/iov.c2
-rw-r--r--drivers/pci/p2pdma.c8
-rw-r--r--drivers/pci/pci-acpi.c45
-rw-r--r--drivers/pci/pci-driver.c6
-rw-r--r--drivers/pci/pci.c69
-rw-r--r--drivers/pci/pci.h59
-rw-r--r--drivers/pci/pcie/aer.c51
-rw-r--r--drivers/pci/pcie/aspm.c54
-rw-r--r--drivers/pci/pcie/dpc.c4
-rw-r--r--drivers/pci/pcie/portdrv.c16
-rw-r--r--drivers/pci/probe.c5
-rw-r--r--drivers/pci/quirks.c31
-rw-r--r--drivers/pci/setup-bus.c236
-rw-r--r--drivers/pci/slot.c2
-rw-r--r--drivers/pci/switch/switchtec.c13
-rw-r--r--drivers/pcmcia/ds.c4
-rw-r--r--drivers/perf/riscv_pmu_sbi.c71
-rw-r--r--drivers/phy/allwinner/phy-sun4i-usb.c59
-rw-r--r--drivers/phy/mediatek/phy-mtk-io.h4
-rw-r--r--drivers/phy/phy-can-transceiver.c4
-rw-r--r--drivers/phy/phy-core.c51
-rw-r--r--drivers/phy/qualcomm/Kconfig68
-rw-r--r--drivers/phy/qualcomm/Makefile14
-rw-r--r--drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c259
-rw-r--r--drivers/phy/qualcomm/phy-qcom-pcie2.c6
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-combo.c750
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c6
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-pcie.c588
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6.h15
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6_20.h23
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v2.h25
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v3.h3
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v5.h5
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h31
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-pcs-usb-v6.h31
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-pcs-v2.h19
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-pcs-v5.h4
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-pcs-v6.h16
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-pcs-v6_20.h18
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h82
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com.h2
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-qserdes-ln-shrd-v6.h32
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h30
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v5_5nm.h5
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v6.h77
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v6_20.h45
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-ufs.c688
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-usb.c83
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp.h23
-rw-r--r--drivers/phy/qualcomm/phy-qcom-snps-eusb2.c441
-rw-r--r--drivers/phy/renesas/r8a779f0-ether-serdes.c65
-rw-r--r--drivers/phy/rockchip/phy-rockchip-typec.c7
-rw-r--r--drivers/phy/samsung/phy-exynos-dp-video.c7
-rw-r--r--drivers/phy/samsung/phy-exynos-mipi-video.c7
-rw-r--r--drivers/phy/tegra/Makefile1
-rw-r--r--drivers/phy/tegra/xusb-tegra186.c64
-rw-r--r--drivers/phy/tegra/xusb.c23
-rw-r--r--drivers/phy/tegra/xusb.h23
-rw-r--r--drivers/phy/ti/phy-j721e-wiz.c66
-rw-r--r--drivers/pinctrl/Kconfig2
-rw-r--r--drivers/pinctrl/bcm/pinctrl-bcm2835.c10
-rw-r--r--drivers/pinctrl/core.c14
-rw-r--r--drivers/pinctrl/freescale/pinctrl-mxs.c6
-rw-r--r--drivers/pinctrl/freescale/pinctrl-mxs.h6
-rw-r--r--drivers/pinctrl/intel/pinctrl-alderlake.c18
-rw-r--r--drivers/pinctrl/intel/pinctrl-baytrail.c10
-rw-r--r--drivers/pinctrl/intel/pinctrl-broxton.c31
-rw-r--r--drivers/pinctrl/intel/pinctrl-cannonlake.c31
-rw-r--r--drivers/pinctrl/intel/pinctrl-cedarfork.c13
-rw-r--r--drivers/pinctrl/intel/pinctrl-cherryview.c6
-rw-r--r--drivers/pinctrl/intel/pinctrl-denverton.c13
-rw-r--r--drivers/pinctrl/intel/pinctrl-elkhartlake.c24
-rw-r--r--drivers/pinctrl/intel/pinctrl-emmitsburg.c13
-rw-r--r--drivers/pinctrl/intel/pinctrl-geminilake.c21
-rw-r--r--drivers/pinctrl/intel/pinctrl-icelake.c35
-rw-r--r--drivers/pinctrl/intel/pinctrl-intel.c74
-rw-r--r--drivers/pinctrl/intel/pinctrl-intel.h55
-rw-r--r--drivers/pinctrl/intel/pinctrl-jasperlake.c13
-rw-r--r--drivers/pinctrl/intel/pinctrl-lakefield.c13
-rw-r--r--drivers/pinctrl/intel/pinctrl-lewisburg.c12
-rw-r--r--drivers/pinctrl/intel/pinctrl-lynxpoint.c8
-rw-r--r--drivers/pinctrl/intel/pinctrl-merrifield.c6
-rw-r--r--drivers/pinctrl/intel/pinctrl-meteorlake.c23
-rw-r--r--drivers/pinctrl/intel/pinctrl-moorefield.c6
-rw-r--r--drivers/pinctrl/intel/pinctrl-sunrisepoint.c37
-rw-r--r--drivers/pinctrl/intel/pinctrl-tigerlake.c30
-rw-r--r--drivers/pinctrl/mediatek/Kconfig5
-rw-r--r--drivers/pinctrl/mediatek/Makefile1
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-moore.c1
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt7981.c1048
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mtk-common.c1
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-paris.c5
-rw-r--r--drivers/pinctrl/nomadik/pinctrl-abx500.c2
-rw-r--r--drivers/pinctrl/pinctrl-amd.c7
-rw-r--r--drivers/pinctrl/pinctrl-amd.h1
-rw-r--r--drivers/pinctrl/pinctrl-at91-pio4.c4
-rw-r--r--drivers/pinctrl/pinctrl-at91.c44
-rw-r--r--drivers/pinctrl/pinctrl-da850-pupd.c6
-rw-r--r--drivers/pinctrl/pinctrl-digicolor.c10
-rw-r--r--drivers/pinctrl/pinctrl-mcp23s08_i2c.c5
-rw-r--r--drivers/pinctrl/pinctrl-rockchip.c1
-rw-r--r--drivers/pinctrl/pinctrl-sx150x.c6
-rw-r--r--drivers/pinctrl/pinctrl-thunderbay.c7
-rw-r--r--drivers/pinctrl/pinmux.c4
-rw-r--r--drivers/pinctrl/qcom/Kconfig50
-rw-r--r--drivers/pinctrl/qcom/Makefile5
-rw-r--r--drivers/pinctrl/qcom/pinctrl-ipq5332.c861
-rw-r--r--drivers/pinctrl/qcom/pinctrl-lpass-lpi.c1
-rw-r--r--drivers/pinctrl/qcom/pinctrl-msm.c11
-rw-r--r--drivers/pinctrl/qcom/pinctrl-msm.h1
-rw-r--r--drivers/pinctrl/qcom/pinctrl-msm8226.c11
-rw-r--r--drivers/pinctrl/qcom/pinctrl-msm8976.c8
-rw-r--r--drivers/pinctrl/qcom/pinctrl-qdu1000.c1274
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sa8775p.c1537
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sm8550-lpass-lpi.c240
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sm8550.c1790
-rw-r--r--drivers/pinctrl/qcom/pinctrl-spmi-gpio.c8
-rw-r--r--drivers/pinctrl/qcom/pinctrl-spmi-mpp.c2
-rw-r--r--drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c2
-rw-r--r--drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c2
-rw-r--r--drivers/pinctrl/ralink/pinctrl-mt7620.c164
-rw-r--r--drivers/pinctrl/ralink/pinctrl-mt7621.c48
-rw-r--r--drivers/pinctrl/ralink/pinctrl-rt2880.c28
-rw-r--r--drivers/pinctrl/ralink/pinctrl-rt305x.c82
-rw-r--r--drivers/pinctrl/ralink/pinctrl-rt3883.c44
-rw-r--r--drivers/pinctrl/renesas/pfc-r8a77950.c244
-rw-r--r--drivers/pinctrl/renesas/pfc-r8a779g0.c112
-rw-r--r--drivers/pinctrl/renesas/pinctrl-rzg2l.c25
-rw-r--r--drivers/pinctrl/samsung/pinctrl-samsung.c2
-rw-r--r--drivers/pinctrl/starfive/Kconfig33
-rw-r--r--drivers/pinctrl/starfive/Makefile4
-rw-r--r--drivers/pinctrl/starfive/pinctrl-starfive-jh7110-aon.c177
-rw-r--r--drivers/pinctrl/starfive/pinctrl-starfive-jh7110-sys.c449
-rw-r--r--drivers/pinctrl/starfive/pinctrl-starfive-jh7110.c982
-rw-r--r--drivers/pinctrl/starfive/pinctrl-starfive-jh7110.h70
-rw-r--r--drivers/pinctrl/stm32/pinctrl-stm32.c1
-rw-r--r--drivers/pinctrl/sunplus/sppctl.c1
-rw-r--r--drivers/platform/surface/aggregator/bus.c4
-rw-r--r--drivers/platform/x86/asus-tf103c-dock.c4
-rw-r--r--drivers/platform/x86/wmi.c15
-rw-r--r--drivers/platform/x86/x86-android-tablets.c2
-rw-r--r--drivers/power/reset/Kconfig7
-rw-r--r--drivers/power/reset/Makefile1
-rw-r--r--drivers/power/reset/odroid-go-ultra-poweroff.c177
-rw-r--r--drivers/power/reset/syscon-reboot.c6
-rw-r--r--drivers/power/supply/Kconfig44
-rw-r--r--drivers/power/supply/Makefile3
-rw-r--r--drivers/power/supply/ab8500_fg.c22
-rw-r--r--drivers/power/supply/bq2415x_charger.c42
-rw-r--r--drivers/power/supply/bq24190_charger.c2
-rw-r--r--drivers/power/supply/bq24257_charger.c8
-rw-r--r--drivers/power/supply/bq256xx_charger.c4
-rw-r--r--drivers/power/supply/bq25890_charger.c181
-rw-r--r--drivers/power/supply/bq27xxx_battery.c8
-rw-r--r--drivers/power/supply/charger-manager.c6
-rw-r--r--drivers/power/supply/collie_battery.c4
-rw-r--r--drivers/power/supply/da9150-charger.c9
-rw-r--r--drivers/power/supply/ds2780_battery.c8
-rw-r--r--drivers/power/supply/ds2781_battery.c8
-rw-r--r--drivers/power/supply/lp8788-charger.c7
-rw-r--r--drivers/power/supply/ltc4162-l-charger.c12
-rw-r--r--drivers/power/supply/max14577_charger.c2
-rw-r--r--drivers/power/supply/max1721x_battery.c8
-rw-r--r--drivers/power/supply/max77650-charger.c8
-rw-r--r--drivers/power/supply/max77693_charger.c6
-rw-r--r--drivers/power/supply/mp2629_charger.c2
-rw-r--r--drivers/power/supply/olpc_battery.c2
-rw-r--r--drivers/power/supply/pcf50633-charger.c6
-rw-r--r--drivers/power/supply/power_supply_core.c93
-rw-r--r--drivers/power/supply/power_supply_leds.c1
-rw-r--r--drivers/power/supply/power_supply_sysfs.c10
-rw-r--r--drivers/power/supply/qcom_battmgr.c1410
-rw-r--r--drivers/power/supply/rt9467-charger.c1282
-rw-r--r--drivers/power/supply/rt9471.c930
-rw-r--r--drivers/power/supply/test_power.c3
-rw-r--r--drivers/power/supply/twl4030_charger.c6
-rw-r--r--drivers/power/supply/wm8350_power.c2
-rw-r--r--drivers/pps/clients/pps-ldisc.c6
-rw-r--r--drivers/ptp/ptp_private.h2
-rw-r--r--drivers/ptp/ptp_vclock.c44
-rw-r--r--drivers/pwm/pwm-ab8500.c112
-rw-r--r--drivers/pwm/pwm-dwc.c38
-rw-r--r--drivers/pwm/pwm-iqs620a.c4
-rw-r--r--drivers/pwm/pwm-lp3943.c1
-rw-r--r--drivers/pwm/pwm-sifive.c8
-rw-r--r--drivers/pwm/pwm-stm32-lp.c2
-rw-r--r--drivers/rapidio/rio-driver.c4
-rw-r--r--drivers/regulator/Kconfig8
-rw-r--r--drivers/regulator/Makefile1
-rw-r--r--drivers/regulator/act8945a-regulator.c6
-rw-r--r--drivers/regulator/core.c6
-rw-r--r--drivers/regulator/fixed-helper.c2
-rw-r--r--drivers/regulator/max20411-regulator.c163
-rw-r--r--drivers/regulator/max597x-regulator.c54
-rw-r--r--drivers/regulator/max77802-regulator.c34
-rw-r--r--drivers/regulator/mcp16502.c1
-rw-r--r--drivers/regulator/s5m8767.c6
-rw-r--r--drivers/regulator/scmi-regulator.c16
-rw-r--r--drivers/regulator/tps65219-regulator.c24
-rw-r--r--drivers/remoteproc/mtk_scp.c1
-rw-r--r--drivers/remoteproc/mtk_scp_ipi.c32
-rw-r--r--drivers/remoteproc/pru_rproc.c230
-rw-r--r--drivers/remoteproc/qcom_common.c19
-rw-r--r--drivers/remoteproc/qcom_common.h8
-rw-r--r--drivers/remoteproc/qcom_q6v5.c4
-rw-r--r--drivers/remoteproc/qcom_q6v5_adsp.c125
-rw-r--r--drivers/remoteproc/qcom_q6v5_mss.c263
-rw-r--r--drivers/remoteproc/qcom_q6v5_pas.c338
-rw-r--r--drivers/remoteproc/qcom_sysmon.c2
-rw-r--r--drivers/remoteproc/qcom_wcnss.c14
-rw-r--r--drivers/remoteproc/qcom_wcnss.h2
-rw-r--r--drivers/remoteproc/remoteproc_core.c5
-rw-r--r--drivers/remoteproc/ti_k3_dsp_remoteproc.c12
-rw-r--r--drivers/rpmsg/qcom_glink_native.c208
-rw-r--r--drivers/rpmsg/qcom_glink_native.h8
-rw-r--r--drivers/rpmsg/qcom_glink_rpm.c96
-rw-r--r--drivers/rpmsg/qcom_glink_smem.c102
-rw-r--r--drivers/rpmsg/qcom_glink_ssr.c2
-rw-r--r--drivers/rpmsg/rpmsg_char.c8
-rw-r--r--drivers/rpmsg/rpmsg_core.c4
-rw-r--r--drivers/rpmsg/rpmsg_ctrl.c2
-rw-r--r--drivers/rtc/Kconfig14
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/interface.c2
-rw-r--r--drivers/rtc/rtc-ab-eoz9.c7
-rw-r--r--drivers/rtc/rtc-abx80x.c77
-rw-r--r--drivers/rtc/rtc-brcmstb-waketimer.c152
-rw-r--r--drivers/rtc/rtc-ds1307.c6
-rw-r--r--drivers/rtc/rtc-efi.c2
-rw-r--r--drivers/rtc/rtc-hym8563.c7
-rw-r--r--drivers/rtc/rtc-isl12022.c93
-rw-r--r--drivers/rtc/rtc-jz4740.c94
-rw-r--r--drivers/rtc/rtc-m41t80.c7
-rw-r--r--drivers/rtc/rtc-max8907.c1
-rw-r--r--drivers/rtc/rtc-moxart.c89
-rw-r--r--drivers/rtc/rtc-nxp-bbnsm.c226
-rw-r--r--drivers/rtc/rtc-pcf2123.c7
-rw-r--r--drivers/rtc/rtc-pcf85063.c7
-rw-r--r--drivers/rtc/rtc-pcf8523.c7
-rw-r--r--drivers/rtc/rtc-pcf85363.c44
-rw-r--r--drivers/rtc/rtc-pcf8563.c7
-rw-r--r--drivers/rtc/rtc-pm8xxx.c533
-rw-r--r--drivers/rtc/rtc-rv3028.c7
-rw-r--r--drivers/rtc/rtc-rv3029c2.c7
-rw-r--r--drivers/rtc/rtc-rv3032.c14
-rw-r--r--drivers/rtc/rtc-rv8803.c52
-rw-r--r--drivers/rtc/rtc-rx6110.c1
-rw-r--r--drivers/rtc/rtc-rx8010.c8
-rw-r--r--drivers/rtc/rtc-sun6i.c16
-rw-r--r--drivers/s390/char/con3215.c4
-rw-r--r--drivers/s390/cio/css.c4
-rw-r--r--drivers/s390/cio/device.c8
-rw-r--r--drivers/s390/cio/scm.c2
-rw-r--r--drivers/s390/crypto/ap_bus.c4
-rw-r--r--drivers/s390/virtio/virtio_ccw.c46
-rw-r--r--drivers/sbus/char/oradax.c2
-rw-r--r--drivers/scsi/3w-sas.c12
-rw-r--r--drivers/scsi/3w-sas.h4
-rw-r--r--drivers/scsi/aacraid/aachba.c5
-rw-r--r--drivers/scsi/aic94xx/aic94xx_task.c3
-rw-r--r--drivers/scsi/ch.c30
-rw-r--r--drivers/scsi/cxlflash/ocxl_hw.c2
-rw-r--r--drivers/scsi/cxlflash/superpipe.c34
-rw-r--r--drivers/scsi/cxlflash/vlun.c32
-rw-r--r--drivers/scsi/device_handler/scsi_dh_alua.c26
-rw-r--r--drivers/scsi/device_handler/scsi_dh_emc.c13
-rw-r--r--drivers/scsi/device_handler/scsi_dh_hp_sw.c22
-rw-r--r--drivers/scsi/device_handler/scsi_dh_rdac.c12
-rw-r--r--drivers/scsi/elx/libefc_sli/sli4.c2
-rw-r--r--drivers/scsi/ipr.c20
-rw-r--r--drivers/scsi/ips.c11
-rw-r--r--drivers/scsi/libsas/sas_ata.c99
-rw-r--r--drivers/scsi/libsas/sas_discover.c6
-rw-r--r--drivers/scsi/libsas/sas_expander.c125
-rw-r--r--drivers/scsi/lpfc/lpfc.h4
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c63
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h4
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c33
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c17
-rw-r--r--drivers/scsi/lpfc/lpfc_hw4.h7
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c94
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c8
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c83
-rw-r--r--drivers/scsi/lpfc/lpfc_sli4.h5
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h6
-rw-r--r--drivers/scsi/lpfc/lpfc_vmid.c41
-rw-r--r--drivers/scsi/lpfc/lpfc_vport.c16
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fusion.c2
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fusion.h5
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_base.c3
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_ctl.c2
-rw-r--r--drivers/scsi/mvumi.c4
-rw-r--r--drivers/scsi/mvumi.h6
-rw-r--r--drivers/scsi/pm8001/pm8001_ctl.c46
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c5
-rw-r--r--drivers/scsi/qla2xxx/qla_bsg.c9
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h51
-rw-r--r--drivers/scsi/qla2xxx/qla_dfs.c10
-rw-r--r--drivers/scsi/qla2xxx/qla_edif.c96
-rw-r--r--drivers/scsi/qla2xxx/qla_edif.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_edif_bsg.h15
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h18
-rw-r--r--drivers/scsi/qla2xxx/qla_gs.c407
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c97
-rw-r--r--drivers/scsi/qla2xxx/qla_inline.h110
-rw-r--r--drivers/scsi/qla2xxx/qla_iocb.c107
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c9
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c8
-rw-r--r--drivers/scsi/qla2xxx/qla_mid.c302
-rw-r--r--drivers/scsi/qla2xxx/qla_nvme.c38
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c61
-rw-r--r--drivers/scsi/qla2xxx/qla_target.c106
-rw-r--r--drivers/scsi/qla2xxx/qla_target.h1
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h6
-rw-r--r--drivers/scsi/qla2xxx/tcm_qla2xxx.c13
-rw-r--r--drivers/scsi/scsi.c12
-rw-r--r--drivers/scsi/scsi_ioctl.c7
-rw-r--r--drivers/scsi/scsi_lib.c78
-rw-r--r--drivers/scsi/scsi_scan.c26
-rw-r--r--drivers/scsi/scsi_sysfs.c4
-rw-r--r--drivers/scsi/scsi_transport_spi.c31
-rw-r--r--drivers/scsi/sd.c83
-rw-r--r--drivers/scsi/sd_zbc.c8
-rw-r--r--drivers/scsi/ses.c14
-rw-r--r--drivers/scsi/sg.c2
-rw-r--r--drivers/scsi/smartpqi/smartpqi.h2
-rw-r--r--drivers/scsi/smartpqi/smartpqi_init.c3
-rw-r--r--drivers/scsi/snic/snic_debugfs.c4
-rw-r--r--drivers/scsi/sr.c11
-rw-r--r--drivers/scsi/sr_ioctl.c17
-rw-r--r--drivers/scsi/virtio_scsi.c18
-rw-r--r--drivers/sh/clk/core.c2
-rw-r--r--drivers/sh/maple/maple.c7
-rw-r--r--drivers/slimbus/core.c4
-rw-r--r--drivers/soc/Kconfig2
-rw-r--r--drivers/soc/Makefile4
-rw-r--r--drivers/soc/amlogic/meson-ee-pwrc.c17
-rw-r--r--drivers/soc/apple/apple-pmgr-pwrstate.c11
-rw-r--r--drivers/soc/apple/rtkit-crashlog.c93
-rw-r--r--drivers/soc/apple/rtkit.c36
-rw-r--r--drivers/soc/bcm/bcm2835-power.c6
-rw-r--r--drivers/soc/imx/Kconfig11
-rw-r--r--drivers/soc/imx/Makefile6
-rw-r--r--drivers/soc/imx/gpcv2.c2
-rw-r--r--drivers/soc/imx/imx8m-blk-ctrl.c27
-rw-r--r--drivers/soc/imx/imx8mp-blk-ctrl.c108
-rw-r--r--drivers/soc/imx/imx93-pd.c1
-rw-r--r--drivers/soc/imx/imx93-src.c1
-rw-r--r--drivers/soc/mediatek/Kconfig7
-rw-r--r--drivers/soc/mediatek/Makefile1
-rw-r--r--drivers/soc/mediatek/mt8186-pm-domains.h4
-rw-r--r--drivers/soc/mediatek/mt8188-mmsys.h149
-rw-r--r--drivers/soc/mediatek/mt8188-pm-domains.h623
-rw-r--r--drivers/soc/mediatek/mt8195-mmsys.h146
-rw-r--r--drivers/soc/mediatek/mtk-devapc.c11
-rw-r--r--drivers/soc/mediatek/mtk-mmsys.c200
-rw-r--r--drivers/soc/mediatek/mtk-mmsys.h2
-rw-r--r--drivers/soc/mediatek/mtk-mutex.c113
-rw-r--r--drivers/soc/mediatek/mtk-pm-domains.c13
-rw-r--r--drivers/soc/mediatek/mtk-pm-domains.h5
-rw-r--r--drivers/soc/mediatek/mtk-regulator-coupler.c159
-rw-r--r--drivers/soc/mediatek/mtk-svs.c155
-rw-r--r--drivers/soc/nuvoton/Kconfig11
-rw-r--r--drivers/soc/nuvoton/Makefile2
-rw-r--r--drivers/soc/nuvoton/wpcm450-soc.c109
-rw-r--r--drivers/soc/qcom/Kconfig27
-rw-r--r--drivers/soc/qcom/Makefile3
-rw-r--r--drivers/soc/qcom/apr.c4
-rw-r--r--drivers/soc/qcom/mdt_loader.c2
-rw-r--r--drivers/soc/qcom/ocmem.c2
-rw-r--r--drivers/soc/qcom/pmic_glink.c336
-rw-r--r--drivers/soc/qcom/pmic_glink_altmode.c478
-rw-r--r--drivers/soc/qcom/qcom-geni-se.c2
-rw-r--r--drivers/soc/qcom/qcom_stats.c10
-rw-r--r--drivers/soc/qcom/ramp_controller.c343
-rw-r--r--drivers/soc/qcom/rmtfs_mem.c31
-rw-r--r--drivers/soc/qcom/rpmhpd.c34
-rw-r--r--drivers/soc/qcom/rpmpd.c18
-rw-r--r--drivers/soc/qcom/smd-rpm.c1
-rw-r--r--drivers/soc/qcom/socinfo.c112
-rw-r--r--drivers/soc/renesas/Kconfig4
-rw-r--r--drivers/soc/renesas/Makefile1
-rw-r--r--drivers/soc/renesas/pwc-rzv2m.c141
-rw-r--r--drivers/soc/renesas/r8a779g0-sysc.c1
-rw-r--r--drivers/soc/renesas/rcar-sysc.c2
-rw-r--r--drivers/soc/sifive/Kconfig2
-rw-r--r--drivers/soc/starfive/Kconfig12
-rw-r--r--drivers/soc/starfive/Makefile3
-rw-r--r--drivers/soc/starfive/jh71xx_pmu.c383
-rw-r--r--drivers/soc/sunxi/Kconfig9
-rw-r--r--drivers/soc/sunxi/Makefile1
-rw-r--r--drivers/soc/sunxi/sun20i-ppu.c207
-rw-r--r--drivers/soc/sunxi/sunxi_sram.c3
-rw-r--r--drivers/soc/xilinx/xlnx_event_manager.c4
-rw-r--r--drivers/soc/xilinx/zynqmp_pm_domains.c2
-rw-r--r--drivers/soundwire/bus.c56
-rw-r--r--drivers/soundwire/bus.h3
-rw-r--r--drivers/soundwire/bus_type.c13
-rw-r--r--drivers/soundwire/cadence_master.c80
-rw-r--r--drivers/soundwire/cadence_master.h22
-rw-r--r--drivers/soundwire/debugfs.c13
-rw-r--r--drivers/soundwire/intel.c27
-rw-r--r--drivers/soundwire/intel_auxdevice.c1
-rw-r--r--drivers/soundwire/stream.c42
-rw-r--r--drivers/spi/Kconfig38
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/atmel-quadspi.c8
-rw-r--r--drivers/spi/spi-altera-core.c30
-rw-r--r--drivers/spi/spi-altera-dfl.c36
-rw-r--r--drivers/spi/spi-altera-platform.c36
-rw-r--r--drivers/spi/spi-ar934x.c10
-rw-r--r--drivers/spi/spi-armada-3700.c98
-rw-r--r--drivers/spi/spi-at91-usart.c40
-rw-r--r--drivers/spi/spi-ath79.c40
-rw-r--r--drivers/spi/spi-atmel.c254
-rw-r--r--drivers/spi/spi-bcm63xx-hsspi.c493
-rw-r--r--drivers/spi/spi-bcmbca-hsspi.c654
-rw-r--r--drivers/spi/spi-cadence-quadspi.c44
-rw-r--r--drivers/spi/spi-geni-qcom.c213
-rw-r--r--drivers/spi/spi-intel-pci.c13
-rw-r--r--drivers/spi/spi-intel.c10
-rw-r--r--drivers/spi/spi-loopback-test.c8
-rw-r--r--drivers/spi/spi-mem.c2
-rw-r--r--drivers/spi/spi-mtk-snfi.c41
-rw-r--r--drivers/spi/spi-pl022.c1
-rw-r--r--drivers/spi/spi-rpc-if.c14
-rw-r--r--drivers/spi/spi-sn-f-ospi.c2
-rw-r--r--drivers/spi/spi-synquacer.c7
-rw-r--r--drivers/spi/spi-tegra210-quad.c15
-rw-r--r--drivers/spi/spi-xilinx.c9
-rw-r--r--drivers/spi/spi.c71
-rw-r--r--drivers/spi/spidev.c13
-rw-r--r--drivers/spmi/spmi.c2
-rw-r--r--drivers/ssb/main.c4
-rw-r--r--drivers/staging/emxx_udc/emxx_udc.c7
-rw-r--r--drivers/staging/greybus/audio_codec.c6
-rw-r--r--drivers/staging/greybus/gbphy.c14
-rw-r--r--drivers/staging/greybus/gpio.c6
-rw-r--r--drivers/staging/greybus/hid.c2
-rw-r--r--drivers/staging/greybus/uart.c4
-rw-r--r--drivers/staging/greybus/usb.c2
-rw-r--r--drivers/staging/ks7010/ks_wlan_net.c3
-rw-r--r--drivers/staging/media/Kconfig9
-rw-r--r--drivers/staging/media/Makefile8
-rw-r--r--drivers/staging/media/atomisp/Kconfig2
-rw-r--r--drivers/staging/media/atomisp/i2c/atomisp-gc0310.c249
-rw-r--r--drivers/staging/media/atomisp/i2c/atomisp-gc2235.c176
-rw-r--r--drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c206
-rw-r--r--drivers/staging/media/atomisp/i2c/atomisp-ov2680.c1280
-rw-r--r--drivers/staging/media/atomisp/i2c/atomisp-ov2722.c195
-rw-r--r--drivers/staging/media/atomisp/i2c/gc0310.h10
-rw-r--r--drivers/staging/media/atomisp/i2c/gc2235.h31
-rw-r--r--drivers/staging/media/atomisp/i2c/mt9m114.h15
-rw-r--r--drivers/staging/media/atomisp/i2c/ov2680.h836
-rw-r--r--drivers/staging/media/atomisp/i2c/ov2722.h36
-rw-r--r--drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c195
-rw-r--r--drivers/staging/media/atomisp/i2c/ov5693/ov5693.h61
-rw-r--r--drivers/staging/media/atomisp/include/linux/atomisp.h50
-rw-r--r--drivers/staging/media/atomisp/include/linux/atomisp_gmin_platform.h2
-rw-r--r--drivers/staging/media/atomisp/include/linux/atomisp_platform.h11
-rw-r--r--drivers/staging/media/atomisp/notes.txt6
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_cmd.c90
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_cmd.h9
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_csi2.c41
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_csi2.h5
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_fops.c89
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_fops.h3
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c120
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_internal.h7
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_ioctl.c60
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_subdev.c171
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_subdev.h13
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_tpg.c2
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_v4l2.c165
-rw-r--r--drivers/staging/media/atomisp/pci/css_2401_system/host/isys_dma_private.h2
-rw-r--r--drivers/staging/media/atomisp/pci/hive_isp_css_common/host/vmem.c20
-rw-r--r--drivers/staging/media/atomisp/pci/hmm/hmm_bo.c2
-rw-r--r--drivers/staging/media/atomisp/pci/sh_css.c7
-rw-r--r--drivers/staging/media/atomisp/pci/sh_css_params.c38
-rw-r--r--drivers/staging/media/av7110/Kconfig (renamed from drivers/staging/media/deprecated/saa7146/av7110/Kconfig)20
-rw-r--r--drivers/staging/media/av7110/Makefile (renamed from drivers/staging/media/deprecated/saa7146/av7110/Makefile)3
-rw-r--r--drivers/staging/media/av7110/TODO3
-rw-r--r--drivers/staging/media/av7110/audio-bilingual-channel-select.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio-bilingual-channel-select.rst)0
-rw-r--r--drivers/staging/media/av7110/audio-channel-select.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio-channel-select.rst)0
-rw-r--r--drivers/staging/media/av7110/audio-clear-buffer.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio-clear-buffer.rst)0
-rw-r--r--drivers/staging/media/av7110/audio-continue.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio-continue.rst)0
-rw-r--r--drivers/staging/media/av7110/audio-fclose.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio-fclose.rst)0
-rw-r--r--drivers/staging/media/av7110/audio-fopen.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio-fopen.rst)0
-rw-r--r--drivers/staging/media/av7110/audio-fwrite.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio-fwrite.rst)0
-rw-r--r--drivers/staging/media/av7110/audio-get-capabilities.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio-get-capabilities.rst)0
-rw-r--r--drivers/staging/media/av7110/audio-get-status.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio-get-status.rst)0
-rw-r--r--drivers/staging/media/av7110/audio-pause.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio-pause.rst)0
-rw-r--r--drivers/staging/media/av7110/audio-play.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio-play.rst)0
-rw-r--r--drivers/staging/media/av7110/audio-select-source.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio-select-source.rst)0
-rw-r--r--drivers/staging/media/av7110/audio-set-av-sync.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio-set-av-sync.rst)0
-rw-r--r--drivers/staging/media/av7110/audio-set-bypass-mode.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio-set-bypass-mode.rst)0
-rw-r--r--drivers/staging/media/av7110/audio-set-id.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio-set-id.rst)0
-rw-r--r--drivers/staging/media/av7110/audio-set-mixer.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio-set-mixer.rst)0
-rw-r--r--drivers/staging/media/av7110/audio-set-mute.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio-set-mute.rst)0
-rw-r--r--drivers/staging/media/av7110/audio-set-streamtype.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio-set-streamtype.rst)0
-rw-r--r--drivers/staging/media/av7110/audio-stop.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio-stop.rst)0
-rw-r--r--drivers/staging/media/av7110/audio.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio.rst)0
-rw-r--r--drivers/staging/media/av7110/audio_data_types.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio_data_types.rst)0
-rw-r--r--drivers/staging/media/av7110/audio_function_calls.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/audio_function_calls.rst)0
-rw-r--r--drivers/staging/media/av7110/av7110.c (renamed from drivers/staging/media/deprecated/saa7146/av7110/av7110.c)0
-rw-r--r--drivers/staging/media/av7110/av7110.h (renamed from drivers/staging/media/deprecated/saa7146/av7110/av7110.h)2
-rw-r--r--drivers/staging/media/av7110/av7110_av.c (renamed from drivers/staging/media/deprecated/saa7146/av7110/av7110_av.c)0
-rw-r--r--drivers/staging/media/av7110/av7110_av.h (renamed from drivers/staging/media/deprecated/saa7146/av7110/av7110_av.h)0
-rw-r--r--drivers/staging/media/av7110/av7110_ca.c (renamed from drivers/staging/media/deprecated/saa7146/av7110/av7110_ca.c)0
-rw-r--r--drivers/staging/media/av7110/av7110_ca.h (renamed from drivers/staging/media/deprecated/saa7146/av7110/av7110_ca.h)0
-rw-r--r--drivers/staging/media/av7110/av7110_hw.c (renamed from drivers/staging/media/deprecated/saa7146/av7110/av7110_hw.c)0
-rw-r--r--drivers/staging/media/av7110/av7110_hw.h (renamed from drivers/staging/media/deprecated/saa7146/av7110/av7110_hw.h)0
-rw-r--r--drivers/staging/media/av7110/av7110_ipack.c (renamed from drivers/staging/media/deprecated/saa7146/av7110/av7110_ipack.c)0
-rw-r--r--drivers/staging/media/av7110/av7110_ipack.h (renamed from drivers/staging/media/deprecated/saa7146/av7110/av7110_ipack.h)0
-rw-r--r--drivers/staging/media/av7110/av7110_ir.c (renamed from drivers/staging/media/deprecated/saa7146/av7110/av7110_ir.c)0
-rw-r--r--drivers/staging/media/av7110/av7110_v4l.c (renamed from drivers/staging/media/deprecated/saa7146/av7110/av7110_v4l.c)0
-rw-r--r--drivers/staging/media/av7110/budget-patch.c (renamed from drivers/staging/media/deprecated/saa7146/av7110/budget-patch.c)0
-rw-r--r--drivers/staging/media/av7110/dvb_filter.c (renamed from drivers/staging/media/deprecated/saa7146/av7110/dvb_filter.c)0
-rw-r--r--drivers/staging/media/av7110/dvb_filter.h (renamed from drivers/staging/media/deprecated/saa7146/av7110/dvb_filter.h)0
-rw-r--r--drivers/staging/media/av7110/sp8870.c (renamed from drivers/staging/media/deprecated/saa7146/av7110/sp8870.c)0
-rw-r--r--drivers/staging/media/av7110/sp8870.h (renamed from drivers/staging/media/deprecated/saa7146/av7110/sp8870.h)0
-rw-r--r--drivers/staging/media/av7110/video-clear-buffer.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-clear-buffer.rst)0
-rw-r--r--drivers/staging/media/av7110/video-command.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-command.rst)0
-rw-r--r--drivers/staging/media/av7110/video-continue.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-continue.rst)0
-rw-r--r--drivers/staging/media/av7110/video-fast-forward.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-fast-forward.rst)0
-rw-r--r--drivers/staging/media/av7110/video-fclose.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-fclose.rst)0
-rw-r--r--drivers/staging/media/av7110/video-fopen.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-fopen.rst)0
-rw-r--r--drivers/staging/media/av7110/video-freeze.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-freeze.rst)0
-rw-r--r--drivers/staging/media/av7110/video-fwrite.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-fwrite.rst)0
-rw-r--r--drivers/staging/media/av7110/video-get-capabilities.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-get-capabilities.rst)0
-rw-r--r--drivers/staging/media/av7110/video-get-event.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-get-event.rst)0
-rw-r--r--drivers/staging/media/av7110/video-get-frame-count.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-get-frame-count.rst)0
-rw-r--r--drivers/staging/media/av7110/video-get-pts.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-get-pts.rst)0
-rw-r--r--drivers/staging/media/av7110/video-get-size.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-get-size.rst)0
-rw-r--r--drivers/staging/media/av7110/video-get-status.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-get-status.rst)0
-rw-r--r--drivers/staging/media/av7110/video-play.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-play.rst)0
-rw-r--r--drivers/staging/media/av7110/video-select-source.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-select-source.rst)0
-rw-r--r--drivers/staging/media/av7110/video-set-blank.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-set-blank.rst)0
-rw-r--r--drivers/staging/media/av7110/video-set-display-format.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-set-display-format.rst)0
-rw-r--r--drivers/staging/media/av7110/video-set-format.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-set-format.rst)0
-rw-r--r--drivers/staging/media/av7110/video-set-streamtype.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-set-streamtype.rst)0
-rw-r--r--drivers/staging/media/av7110/video-slowmotion.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-slowmotion.rst)0
-rw-r--r--drivers/staging/media/av7110/video-stillpicture.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-stillpicture.rst)0
-rw-r--r--drivers/staging/media/av7110/video-stop.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-stop.rst)0
-rw-r--r--drivers/staging/media/av7110/video-try-command.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video-try-command.rst)0
-rw-r--r--drivers/staging/media/av7110/video.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video.rst)0
-rw-r--r--drivers/staging/media/av7110/video_function_calls.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video_function_calls.rst)0
-rw-r--r--drivers/staging/media/av7110/video_types.rst (renamed from drivers/staging/media/deprecated/saa7146/av7110/video_types.rst)0
-rw-r--r--drivers/staging/media/deprecated/cpia2/Kconfig13
-rw-r--r--drivers/staging/media/deprecated/cpia2/Makefile4
-rw-r--r--drivers/staging/media/deprecated/cpia2/TODO6
-rw-r--r--drivers/staging/media/deprecated/cpia2/cpia2.h475
-rw-r--r--drivers/staging/media/deprecated/cpia2/cpia2_core.c2434
-rw-r--r--drivers/staging/media/deprecated/cpia2/cpia2_registers.h463
-rw-r--r--drivers/staging/media/deprecated/cpia2/cpia2_usb.c966
-rw-r--r--drivers/staging/media/deprecated/cpia2/cpia2_v4l.c1226
-rw-r--r--drivers/staging/media/deprecated/fsl-viu/Kconfig15
-rw-r--r--drivers/staging/media/deprecated/fsl-viu/TODO7
-rw-r--r--drivers/staging/media/deprecated/fsl-viu/fsl-viu.c1599
-rw-r--r--drivers/staging/media/deprecated/meye/Kconfig19
-rw-r--r--drivers/staging/media/deprecated/meye/Makefile2
-rw-r--r--drivers/staging/media/deprecated/meye/TODO6
-rw-r--r--drivers/staging/media/deprecated/meye/meye.c1814
-rw-r--r--drivers/staging/media/deprecated/meye/meye.h311
-rw-r--r--drivers/staging/media/deprecated/saa7146/Kconfig5
-rw-r--r--drivers/staging/media/deprecated/saa7146/Makefile2
-rw-r--r--drivers/staging/media/deprecated/saa7146/av7110/TODO9
-rw-r--r--drivers/staging/media/deprecated/saa7146/common/saa7146.h472
-rw-r--r--drivers/staging/media/deprecated/saa7146/common/saa7146_vv.h266
-rw-r--r--drivers/staging/media/deprecated/saa7146/saa7146/TODO7
-rw-r--r--drivers/staging/media/deprecated/saa7146/ttpci/TODO7
-rw-r--r--drivers/staging/media/deprecated/stkwebcam/Kconfig18
-rw-r--r--drivers/staging/media/deprecated/stkwebcam/Makefile5
-rw-r--r--drivers/staging/media/deprecated/stkwebcam/TODO12
-rw-r--r--drivers/staging/media/deprecated/stkwebcam/stk-sensor.c587
-rw-r--r--drivers/staging/media/deprecated/stkwebcam/stk-webcam.c1434
-rw-r--r--drivers/staging/media/deprecated/stkwebcam/stk-webcam.h123
-rw-r--r--drivers/staging/media/deprecated/tm6000/Kconfig37
-rw-r--r--drivers/staging/media/deprecated/tm6000/Makefile14
-rw-r--r--drivers/staging/media/deprecated/tm6000/TODO7
-rw-r--r--drivers/staging/media/deprecated/tm6000/tm6000-alsa.c440
-rw-r--r--drivers/staging/media/deprecated/tm6000/tm6000-cards.c1397
-rw-r--r--drivers/staging/media/deprecated/tm6000/tm6000-core.c916
-rw-r--r--drivers/staging/media/deprecated/tm6000/tm6000-dvb.c454
-rw-r--r--drivers/staging/media/deprecated/tm6000/tm6000-i2c.c317
-rw-r--r--drivers/staging/media/deprecated/tm6000/tm6000-input.c503
-rw-r--r--drivers/staging/media/deprecated/tm6000/tm6000-regs.h588
-rw-r--r--drivers/staging/media/deprecated/tm6000/tm6000-stds.c623
-rw-r--r--drivers/staging/media/deprecated/tm6000/tm6000-usb-isoc.h38
-rw-r--r--drivers/staging/media/deprecated/tm6000/tm6000-video.c1703
-rw-r--r--drivers/staging/media/deprecated/tm6000/tm6000.h396
-rw-r--r--drivers/staging/media/deprecated/zr364xx/Kconfig18
-rw-r--r--drivers/staging/media/deprecated/zr364xx/Makefile3
-rw-r--r--drivers/staging/media/deprecated/zr364xx/TODO7
-rw-r--r--drivers/staging/media/deprecated/zr364xx/zr364xx.c1635
-rw-r--r--drivers/staging/media/imx/imx-media-csi.c7
-rw-r--r--drivers/staging/media/imx/imx-media-fim.c13
-rw-r--r--drivers/staging/media/imx/imx-media.h6
-rw-r--r--drivers/staging/media/meson/vdec/esparser.c3
-rw-r--r--drivers/staging/media/omap4iss/iss_video.c66
-rw-r--r--drivers/staging/pi433/TODO3
-rw-r--r--drivers/staging/pi433/pi433_if.c11
-rw-r--r--drivers/staging/r8188eu/core/rtw_cmd.c67
-rw-r--r--drivers/staging/r8188eu/core/rtw_fw.c10
-rw-r--r--drivers/staging/r8188eu/core/rtw_mlme.c5
-rw-r--r--drivers/staging/r8188eu/core/rtw_mlme_ext.c31
-rw-r--r--drivers/staging/r8188eu/core/rtw_pwrctrl.c23
-rw-r--r--drivers/staging/r8188eu/core/rtw_recv.c30
-rw-r--r--drivers/staging/r8188eu/core/rtw_sta_mgt.c26
-rw-r--r--drivers/staging/r8188eu/core/rtw_xmit.c478
-rw-r--r--drivers/staging/r8188eu/hal/rtl8188e_cmd.c4
-rw-r--r--drivers/staging/r8188eu/hal/rtl8188e_phycfg.c35
-rw-r--r--drivers/staging/r8188eu/hal/rtl8188e_rf6052.c7
-rw-r--r--drivers/staging/r8188eu/hal/rtl8188eu_xmit.c42
-rw-r--r--drivers/staging/r8188eu/hal/usb_halinit.c31
-rw-r--r--drivers/staging/r8188eu/hal/usb_ops_linux.c80
-rw-r--r--drivers/staging/r8188eu/include/drv_types.h4
-rw-r--r--drivers/staging/r8188eu/include/hal_intf.h2
-rw-r--r--drivers/staging/r8188eu/include/osdep_intf.h32
-rw-r--r--drivers/staging/r8188eu/include/rtl8188e_cmd.h2
-rw-r--r--drivers/staging/r8188eu/include/rtl8188e_spec.h21
-rw-r--r--drivers/staging/r8188eu/include/rtl8188e_xmit.h16
-rw-r--r--drivers/staging/r8188eu/include/rtw_cmd.h3
-rw-r--r--drivers/staging/r8188eu/include/rtw_io.h257
-rw-r--r--drivers/staging/r8188eu/include/rtw_pwrctrl.h3
-rw-r--r--drivers/staging/r8188eu/include/rtw_xmit.h57
-rw-r--r--drivers/staging/r8188eu/include/usb_ops.h2
-rw-r--r--drivers/staging/r8188eu/include/usb_ops_linux.h29
-rw-r--r--drivers/staging/r8188eu/os_dep/ioctl_linux.c6
-rw-r--r--drivers/staging/r8188eu/os_dep/os_intfs.c17
-rw-r--r--drivers/staging/r8188eu/os_dep/usb_intf.c33
-rw-r--r--drivers/staging/r8188eu/os_dep/usb_ops_linux.c106
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c22
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c2
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c355
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c4
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_hw.h219
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c374
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_phyreg.h2
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_core.c86
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_core.h208
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_dm.c342
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_dm.h45
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_pm.c2
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211.h2
-rw-r--r--drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c14
-rw-r--r--drivers/staging/rts5208/ms.c2
-rw-r--r--drivers/staging/vc04_services/Makefile2
-rw-r--r--drivers/staging/vc04_services/bcm2835-audio/Makefile2
-rw-r--r--drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c12
-rw-r--r--drivers/staging/vc04_services/bcm2835-audio/bcm2835.h3
-rw-r--r--drivers/staging/vc04_services/bcm2835-camera/Makefile5
-rw-r--r--drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c10
-rw-r--r--drivers/staging/vc04_services/bcm2835-camera/controls.c6
-rw-r--r--drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h63
-rw-r--r--drivers/staging/vc04_services/interface/TODO5
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c136
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h8
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c226
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h38
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c36
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_ioctl.h11
-rw-r--r--drivers/staging/vc04_services/vchiq-mmal/Makefile5
-rw-r--r--drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c15
-rw-r--r--drivers/staging/vme_user/vme.h26
-rw-r--r--drivers/staging/vme_user/vme_bridge.h36
-rw-r--r--drivers/staging/wlan-ng/hfa384x.h171
-rw-r--r--drivers/target/target_core_pscsi.c12
-rw-r--r--drivers/target/target_core_user.c2
-rw-r--r--drivers/tee/tee_core.c2
-rw-r--r--drivers/thermal/qcom/lmh.c2
-rw-r--r--drivers/thunderbolt/acpi.c13
-rw-r--r--drivers/thunderbolt/ctl.c52
-rw-r--r--drivers/thunderbolt/ctl.h2
-rw-r--r--drivers/thunderbolt/debugfs.c5
-rw-r--r--drivers/thunderbolt/switch.c46
-rw-r--r--drivers/thunderbolt/tb.c508
-rw-r--r--drivers/thunderbolt/tb.h41
-rw-r--r--drivers/thunderbolt/tb_msgs.h11
-rw-r--r--drivers/thunderbolt/tb_regs.h36
-rw-r--r--drivers/thunderbolt/tunnel.c506
-rw-r--r--drivers/thunderbolt/tunnel.h18
-rw-r--r--drivers/thunderbolt/usb4.c572
-rw-r--r--drivers/thunderbolt/xdomain.c6
-rw-r--r--drivers/tty/amiserial.c12
-rw-r--r--drivers/tty/hvc/hvc_console.c4
-rw-r--r--drivers/tty/hvc/hvc_console.h2
-rw-r--r--drivers/tty/hvc/hvc_iucv.c6
-rw-r--r--drivers/tty/hvc/hvcs.c91
-rw-r--r--drivers/tty/moxa.c82
-rw-r--r--drivers/tty/mxser.c11
-rw-r--r--drivers/tty/n_gsm.c160
-rw-r--r--drivers/tty/serdev/core.c2
-rw-r--r--drivers/tty/serial/8250/8250_dfl.c167
-rw-r--r--drivers/tty/serial/8250/8250_early.c4
-rw-r--r--drivers/tty/serial/8250/8250_pci.c25
-rw-r--r--drivers/tty/serial/8250/8250_pci1xxxx.c494
-rw-r--r--drivers/tty/serial/8250/8250_pcilib.c40
-rw-r--r--drivers/tty/serial/8250/8250_pcilib.h15
-rw-r--r--drivers/tty/serial/8250/8250_port.c57
-rw-r--r--drivers/tty/serial/8250/Kconfig27
-rw-r--r--drivers/tty/serial/8250/Makefile3
-rw-r--r--drivers/tty/serial/Kconfig16
-rw-r--r--drivers/tty/serial/Makefile2
-rw-r--r--drivers/tty/serial/arc_uart.c7
-rw-r--r--drivers/tty/serial/earlycon-semihost.c (renamed from drivers/tty/serial/earlycon-arm-semihost.c)25
-rw-r--r--drivers/tty/serial/earlycon.c9
-rw-r--r--drivers/tty/serial/fsl_lpuart.c119
-rw-r--r--drivers/tty/serial/imx.c308
-rw-r--r--drivers/tty/serial/liteuart.c241
-rw-r--r--drivers/tty/serial/max3100.c2
-rw-r--r--drivers/tty/serial/max310x.c3
-rw-r--r--drivers/tty/serial/msm_serial.c1
-rw-r--r--drivers/tty/serial/pch_uart.c2
-rw-r--r--drivers/tty/serial/pic32_uart.c2
-rw-r--r--drivers/tty/serial/qcom_geni_serial.c638
-rw-r--r--drivers/tty/serial/sc16is7xx.c51
-rw-r--r--drivers/tty/serial/sccnxp.c12
-rw-r--r--drivers/tty/serial/serial-tegra.c7
-rw-r--r--drivers/tty/serial/serial_core.c77
-rw-r--r--drivers/tty/serial/stm32-usart.c6
-rw-r--r--drivers/tty/serial/sunhv.c8
-rw-r--r--drivers/tty/serial/ucc_uart.c2
-rw-r--r--drivers/tty/synclink_gt.c21
-rw-r--r--drivers/tty/tty_io.c8
-rw-r--r--drivers/tty/tty_ioctl.c8
-rw-r--r--drivers/tty/tty_port.c22
-rw-r--r--drivers/tty/vt/vc_screen.c11
-rw-r--r--drivers/tty/vt/vt.c310
-rw-r--r--drivers/ufs/core/Makefile2
-rw-r--r--drivers/ufs/core/ufs-mcq.c431
-rw-r--r--drivers/ufs/core/ufs_bsg.c144
-rw-r--r--drivers/ufs/core/ufshcd-priv.h109
-rw-r--r--drivers/ufs/core/ufshcd.c863
-rw-r--r--drivers/ufs/core/ufshpb.c4
-rw-r--r--drivers/ufs/host/Kconfig19
-rw-r--r--drivers/ufs/host/Makefile1
-rw-r--r--drivers/ufs/host/ufs-exynos.c10
-rw-r--r--drivers/ufs/host/ufs-qcom-ice.c2
-rw-r--r--drivers/ufs/host/ufs-qcom.c548
-rw-r--r--drivers/ufs/host/ufs-qcom.h97
-rw-r--r--drivers/ufs/host/ufs-sprd.c458
-rw-r--r--drivers/ufs/host/ufs-sprd.h85
-rw-r--r--drivers/uio/uio.c2
-rw-r--r--drivers/usb/cdns3/cdnsp-gadget.c2
-rw-r--r--drivers/usb/cdns3/cdnsp-gadget.h4
-rw-r--r--drivers/usb/cdns3/cdnsp-ring.c110
-rw-r--r--drivers/usb/chipidea/ci_hdrc_imx.c10
-rw-r--r--drivers/usb/chipidea/debug.c2
-rw-r--r--drivers/usb/chipidea/usbmisc_imx.c6
-rw-r--r--drivers/usb/class/cdc-acm.c4
-rw-r--r--drivers/usb/common/ulpi.c18
-rw-r--r--drivers/usb/core/devio.c3
-rw-r--r--drivers/usb/core/driver.c6
-rw-r--r--drivers/usb/core/hub.c5
-rw-r--r--drivers/usb/core/message.c8
-rw-r--r--drivers/usb/core/sysfs.c5
-rw-r--r--drivers/usb/core/usb.c10
-rw-r--r--drivers/usb/dwc3/core.h2
-rw-r--r--drivers/usb/dwc3/debug.h3
-rw-r--r--drivers/usb/dwc3/debugfs.c19
-rw-r--r--drivers/usb/dwc3/dwc3-pci.c4
-rw-r--r--drivers/usb/dwc3/dwc3-xilinx.c1
-rw-r--r--drivers/usb/dwc3/gadget.c4
-rw-r--r--drivers/usb/early/xhci-dbc.c8
-rw-r--r--drivers/usb/fotg210/Kconfig2
-rw-r--r--drivers/usb/fotg210/fotg210-core.c83
-rw-r--r--drivers/usb/fotg210/fotg210-hcd.c69
-rw-r--r--drivers/usb/fotg210/fotg210-hcd.h1
-rw-r--r--drivers/usb/fotg210/fotg210-udc.c161
-rw-r--r--drivers/usb/fotg210/fotg210-udc.h4
-rw-r--r--drivers/usb/fotg210/fotg210.h27
-rw-r--r--drivers/usb/gadget/Kconfig1
-rw-r--r--drivers/usb/gadget/composite.c102
-rw-r--r--drivers/usb/gadget/configfs.c500
-rw-r--r--drivers/usb/gadget/function/f_fs.c8
-rw-r--r--drivers/usb/gadget/function/f_uvc.c150
-rw-r--r--drivers/usb/gadget/function/u_ether.c38
-rw-r--r--drivers/usb/gadget/function/u_serial.c23
-rw-r--r--drivers/usb/gadget/function/u_uvc.h18
-rw-r--r--drivers/usb/gadget/function/uvc.h4
-rw-r--r--drivers/usb/gadget/function/uvc_configfs.c1106
-rw-r--r--drivers/usb/gadget/function/uvc_configfs.h52
-rw-r--r--drivers/usb/gadget/function/uvc_v4l2.c16
-rw-r--r--drivers/usb/gadget/legacy/hid.c7
-rw-r--r--drivers/usb/gadget/udc/Kconfig22
-rw-r--r--drivers/usb/gadget/udc/Makefile2
-rw-r--r--drivers/usb/gadget/udc/bcm63xx_udc.c13
-rw-r--r--drivers/usb/gadget/udc/fusb300_udc.c10
-rw-r--r--drivers/usb/gadget/udc/gr_udc.c2
-rw-r--r--drivers/usb/gadget/udc/lpc32xx_udc.c2
-rw-r--r--drivers/usb/gadget/udc/pxa25x_udc.c2
-rw-r--r--drivers/usb/gadget/udc/pxa27x_udc.c2
-rw-r--r--drivers/usb/gadget/udc/renesas_usb3.c136
-rw-r--r--drivers/usb/gadget/udc/renesas_usbf.c3406
-rw-r--r--drivers/usb/gadget/udc/rzv2m_usb3drd.c139
-rw-r--r--drivers/usb/gadget/udc/tegra-xudc.c50
-rw-r--r--drivers/usb/host/Kconfig22
-rw-r--r--drivers/usb/host/Makefile8
-rw-r--r--drivers/usb/host/ehci-exynos.c23
-rw-r--r--drivers/usb/host/ehci-fsl.c2
-rw-r--r--drivers/usb/host/fsl-mph-dr-of.c3
-rw-r--r--drivers/usb/host/isp116x-hcd.c2
-rw-r--r--drivers/usb/host/isp1362-hcd.c2
-rw-r--r--drivers/usb/host/max3421-hcd.c15
-rw-r--r--drivers/usb/host/ohci-exynos.c23
-rw-r--r--drivers/usb/host/sl811-hcd.c2
-rw-r--r--drivers/usb/host/uhci-hcd.c6
-rw-r--r--drivers/usb/host/xhci-debugfs.c2
-rw-r--r--drivers/usb/host/xhci-hub.c257
-rw-r--r--drivers/usb/host/xhci-mem.c338
-rw-r--r--drivers/usb/host/xhci-mvebu.c2
-rw-r--r--drivers/usb/host/xhci-plat.c144
-rw-r--r--drivers/usb/host/xhci-plat.h7
-rw-r--r--drivers/usb/host/xhci-rcar.c102
-rw-r--r--drivers/usb/host/xhci-rcar.h55
-rw-r--r--drivers/usb/host/xhci-ring.c88
-rw-r--r--drivers/usb/host/xhci-rzv2m.c38
-rw-r--r--drivers/usb/host/xhci-rzv2m.h16
-rw-r--r--drivers/usb/host/xhci-tegra.c392
-rw-r--r--drivers/usb/host/xhci.c81
-rw-r--r--drivers/usb/host/xhci.h40
-rw-r--r--drivers/usb/misc/onboard_usb_hub.c4
-rw-r--r--drivers/usb/misc/onboard_usb_hub.h11
-rw-r--r--drivers/usb/mon/mon_bin.c3
-rw-r--r--drivers/usb/mtu3/mtu3_gadget.c3
-rw-r--r--drivers/usb/mtu3/mtu3_hw_regs.h1
-rw-r--r--drivers/usb/mtu3/mtu3_qmu.c7
-rw-r--r--drivers/usb/musb/da8xx.c4
-rw-r--r--drivers/usb/musb/mediatek.c3
-rw-r--r--drivers/usb/musb/sunxi.c99
-rw-r--r--drivers/usb/phy/phy.c6
-rw-r--r--drivers/usb/roles/class.c3
-rw-r--r--drivers/usb/serial/console.c2
-rw-r--r--drivers/usb/serial/option.c4
-rw-r--r--drivers/usb/serial/usb-serial.c6
-rw-r--r--drivers/usb/storage/ene_ub6250.c2
-rw-r--r--drivers/usb/typec/altmodes/displayport.c12
-rw-r--r--drivers/usb/typec/bus.c37
-rw-r--r--drivers/usb/typec/bus.h2
-rw-r--r--drivers/usb/typec/class.c17
-rw-r--r--drivers/usb/typec/hd3ss3220.c29
-rw-r--r--drivers/usb/typec/mux/Kconfig6
-rw-r--r--drivers/usb/typec/mux/Makefile1
-rw-r--r--drivers/usb/typec/mux/gpio-sbu-mux.c172
-rw-r--r--drivers/usb/typec/mux/intel_pmc_mux.c13
-rw-r--r--drivers/usb/typec/pd.c9
-rw-r--r--drivers/usb/typec/retimer.h2
-rw-r--r--drivers/usb/typec/tcpm/Makefile1
-rw-r--r--drivers/usb/typec/tcpm/maxim_contaminant.c387
-rw-r--r--drivers/usb/typec/tcpm/tcpci.c19
-rw-r--r--drivers/usb/typec/tcpm/tcpci_maxim.h89
-rw-r--r--drivers/usb/typec/tcpm/tcpci_maxim_core.c (renamed from drivers/usb/typec/tcpm/tcpci_maxim.c)53
-rw-r--r--drivers/usb/typec/tcpm/tcpm.c60
-rw-r--r--drivers/usb/typec/tipd/core.c38
-rw-r--r--drivers/usb/typec/ucsi/ucsi.c164
-rw-r--r--drivers/usb/typec/ucsi/ucsi.h8
-rw-r--r--drivers/usb/typec/ucsi/ucsi_ccg.c22
-rw-r--r--drivers/vdpa/Kconfig30
-rw-r--r--drivers/vdpa/Makefile1
-rw-r--r--drivers/vdpa/ifcvf/ifcvf_base.c32
-rw-r--r--drivers/vdpa/ifcvf/ifcvf_base.h10
-rw-r--r--drivers/vdpa/ifcvf/ifcvf_main.c162
-rw-r--r--drivers/vdpa/mlx5/Makefile2
-rw-r--r--drivers/vdpa/mlx5/core/mr.c1
-rw-r--r--drivers/vdpa/mlx5/core/resources.c3
-rw-r--r--drivers/vdpa/mlx5/net/debug.c152
-rw-r--r--drivers/vdpa/mlx5/net/mlx5_vnet.c259
-rw-r--r--drivers/vdpa/mlx5/net/mlx5_vnet.h94
-rw-r--r--drivers/vdpa/solidrun/Makefile6
-rw-r--r--drivers/vdpa/solidrun/snet_hwmon.c188
-rw-r--r--drivers/vdpa/solidrun/snet_main.c1111
-rw-r--r--drivers/vdpa/solidrun/snet_vdpa.h194
-rw-r--r--drivers/vdpa/vdpa.c110
-rw-r--r--drivers/vdpa/vdpa_sim/vdpa_sim.c233
-rw-r--r--drivers/vdpa/vdpa_sim/vdpa_sim.h7
-rw-r--r--drivers/vdpa/vdpa_sim/vdpa_sim_blk.c1
-rw-r--r--drivers/vdpa/vdpa_sim/vdpa_sim_net.c219
-rw-r--r--drivers/vdpa/vdpa_user/iova_domain.c2
-rw-r--r--drivers/vfio/Kconfig2
-rw-r--r--drivers/vfio/container.c14
-rw-r--r--drivers/vfio/fsl-mc/vfio_fsl_mc.c2
-rw-r--r--drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c4
-rw-r--r--drivers/vfio/group.c53
-rw-r--r--drivers/vfio/iommufd.c19
-rw-r--r--drivers/vfio/mdev/Kconfig8
-rw-r--r--drivers/vfio/mdev/mdev_sysfs.c2
-rw-r--r--drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c4
-rw-r--r--drivers/vfio/pci/mlx5/cmd.c79
-rw-r--r--drivers/vfio/pci/mlx5/cmd.h28
-rw-r--r--drivers/vfio/pci/mlx5/main.c261
-rw-r--r--drivers/vfio/pci/vfio_pci_config.c6
-rw-r--r--drivers/vfio/pci/vfio_pci_core.c9
-rw-r--r--drivers/vfio/pci/vfio_pci_igd.c2
-rw-r--r--drivers/vfio/pci/vfio_pci_intrs.c10
-rw-r--r--drivers/vfio/pci/vfio_pci_rdwr.c2
-rw-r--r--drivers/vfio/platform/vfio_platform_common.c12
-rw-r--r--drivers/vfio/platform/vfio_platform_irq.c8
-rw-r--r--drivers/vfio/vfio.h33
-rw-r--r--drivers/vfio/vfio_iommu_type1.c273
-rw-r--r--drivers/vfio/vfio_main.c77
-rw-r--r--drivers/vfio/virqfd.c2
-rw-r--r--drivers/vhost/net.c5
-rw-r--r--drivers/vhost/scsi.c6
-rw-r--r--drivers/vhost/test.c3
-rw-r--r--drivers/vhost/vdpa.c43
-rw-r--r--drivers/vhost/vhost.c2
-rw-r--r--drivers/vhost/vhost.h2
-rw-r--r--drivers/vhost/vsock.c2
-rw-r--r--drivers/video/backlight/Kconfig22
-rw-r--r--drivers/video/backlight/Makefile3
-rw-r--r--drivers/video/backlight/aat2870_bl.c7
-rw-r--r--drivers/video/backlight/arcxcnn_bl.c5
-rw-r--r--drivers/video/backlight/backlight.c2
-rw-r--r--drivers/video/backlight/ipaq_micro_bl.c7
-rw-r--r--drivers/video/backlight/ktd253-backlight.c9
-rw-r--r--drivers/video/backlight/ktz8866.c208
-rw-r--r--drivers/video/backlight/pwm_bl.c68
-rw-r--r--drivers/video/backlight/sky81452-backlight.c2
-rw-r--r--drivers/video/backlight/tosa_bl.c172
-rw-r--r--drivers/video/backlight/tosa_bl.h8
-rw-r--r--drivers/video/backlight/tosa_lcd.c284
-rw-r--r--drivers/video/console/newport_con.c9
-rw-r--r--drivers/video/console/sticon.c9
-rw-r--r--drivers/video/console/vgacon.c8
-rw-r--r--drivers/video/fbdev/68328fb.c2
-rw-r--r--drivers/video/fbdev/clps711x-fb.c10
-rw-r--r--drivers/video/fbdev/core/fb_defio.c8
-rw-r--r--drivers/video/fbdev/core/fbcon.c76
-rw-r--r--drivers/video/fbdev/core/fbmem.c33
-rw-r--r--drivers/video/fbdev/core/fbsysfs.c1
-rw-r--r--drivers/video/fbdev/efifb.c35
-rw-r--r--drivers/video/fbdev/hyperv_fb.c17
-rw-r--r--drivers/video/fbdev/offb.c33
-rw-r--r--drivers/video/fbdev/simplefb.c19
-rw-r--r--drivers/video/fbdev/vesafb.c37
-rw-r--r--drivers/video/fbdev/vga16fb.c15
-rw-r--r--drivers/virtio/virtio.c4
-rw-r--r--drivers/virtio/virtio_ring.c133
-rw-r--r--drivers/virtio/virtio_vdpa.c13
-rw-r--r--drivers/w1/w1.c10
-rw-r--r--drivers/watchdog/Kconfig4
-rw-r--r--drivers/watchdog/apple_wdt.c18
-rw-r--r--drivers/watchdog/armada_37xx_wdt.c15
-rw-r--r--drivers/watchdog/aspeed_wdt.c1
-rw-r--r--drivers/watchdog/at91rm9200_wdt.c2
-rw-r--r--drivers/watchdog/at91sam9_wdt.c7
-rw-r--r--drivers/watchdog/bcm7038_wdt.c15
-rw-r--r--drivers/watchdog/cadence_wdt.c17
-rw-r--r--drivers/watchdog/da9062_wdt.c15
-rw-r--r--drivers/watchdog/da9063_wdt.c15
-rw-r--r--drivers/watchdog/davinci_wdt.c18
-rw-r--r--drivers/watchdog/dw_wdt.c1
-rw-r--r--drivers/watchdog/iTCO_wdt.c4
-rw-r--r--drivers/watchdog/imgpdc_wdt.c31
-rw-r--r--drivers/watchdog/imx2_wdt.c55
-rw-r--r--drivers/watchdog/imx7ulp_wdt.c15
-rw-r--r--drivers/watchdog/lpc18xx_wdt.c30
-rw-r--r--drivers/watchdog/meson_gxbb_wdt.c16
-rw-r--r--drivers/watchdog/mt7621_wdt.c122
-rw-r--r--drivers/watchdog/mtk_wdt.c7
-rw-r--r--drivers/watchdog/of_xilinx_wdt.c16
-rw-r--r--drivers/watchdog/pcwd_usb.c6
-rw-r--r--drivers/watchdog/pic32-dmt.c15
-rw-r--r--drivers/watchdog/pic32-wdt.c17
-rw-r--r--drivers/watchdog/pnx4008_wdt.c15
-rw-r--r--drivers/watchdog/qcom-wdt.c16
-rw-r--r--drivers/watchdog/realtek_otto_wdt.c17
-rw-r--r--drivers/watchdog/rtd119x_wdt.c16
-rw-r--r--drivers/watchdog/rzg2l_wdt.c45
-rw-r--r--drivers/watchdog/rzn1_wdt.c18
-rw-r--r--drivers/watchdog/sbsa_gwdt.c1
-rw-r--r--drivers/watchdog/visconti_wdt.c17
-rw-r--r--drivers/watchdog/watchdog_dev.c23
-rw-r--r--drivers/watchdog/wdat_wdt.c6
-rw-r--r--drivers/watchdog/ziirave_wdt.c5
-rw-r--r--drivers/xen/efi.c61
-rw-r--r--drivers/xen/gntalloc.c2
-rw-r--r--drivers/xen/gntdev.c4
-rw-r--r--drivers/xen/privcmd-buf.c2
-rw-r--r--drivers/xen/privcmd.c4
-rw-r--r--drivers/xen/pvcalls-back.c2
-rw-r--r--drivers/xen/xenbus/xenbus_probe_backend.c8
-rw-r--r--drivers/xen/xenbus/xenbus_probe_frontend.c4
-rw-r--r--drivers/zorro/zorro-driver.c4
4073 files changed, 172702 insertions, 113449 deletions
diff --git a/drivers/Makefile b/drivers/Makefile
index bdf1c66141c9..20b118dca999 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -6,6 +6,11 @@
# Rewritten to use lists instead of if-statements.
#
+# Some driver Makefiles miss $(srctree)/ for include directive.
+ifdef building_out_of_srctree
+MAKEFLAGS += --include-dir=$(srctree)
+endif
+
obj-y += irqchip/
obj-y += bus/
@@ -71,7 +76,7 @@ obj-$(CONFIG_FB_INTEL) += video/fbdev/intelfb/
obj-$(CONFIG_PARPORT) += parport/
obj-y += base/ block/ misc/ mfd/ nfc/
obj-$(CONFIG_LIBNVDIMM) += nvdimm/
-obj-$(CONFIG_DAX) += dax/
+obj-y += dax/
obj-$(CONFIG_DMA_SHARED_BUFFER) += dma-buf/
obj-$(CONFIG_NUBUS) += nubus/
obj-y += cxl/
@@ -98,7 +103,6 @@ obj-$(CONFIG_DIO) += dio/
obj-$(CONFIG_SBUS) += sbus/
obj-$(CONFIG_ZORRO) += zorro/
obj-$(CONFIG_ATA_OVER_ETH) += block/aoe/
-obj-$(CONFIG_PARIDE) += block/paride/
obj-$(CONFIG_TC) += tc/
obj-$(CONFIG_USB_PHY) += usb/
obj-$(CONFIG_USB) += usb/
@@ -137,7 +141,7 @@ obj-$(CONFIG_CRYPTO) += crypto/
obj-$(CONFIG_SUPERH) += sh/
obj-y += clocksource/
obj-$(CONFIG_DCA) += dca/
-obj-$(CONFIG_HID) += hid/
+obj-$(CONFIG_HID_SUPPORT) += hid/
obj-$(CONFIG_PPC_PS3) += ps3/
obj-$(CONFIG_OF) += of/
obj-$(CONFIG_SSB) += ssb/
@@ -189,3 +193,4 @@ obj-$(CONFIG_COUNTER) += counter/
obj-$(CONFIG_MOST) += most/
obj-$(CONFIG_PECI) += peci/
obj-$(CONFIG_HTE) += hte/
+obj-$(CONFIG_DRM_ACCEL) += accel/
diff --git a/drivers/accel/Kconfig b/drivers/accel/Kconfig
index c9ce849b2984..c437206aa3f1 100644
--- a/drivers/accel/Kconfig
+++ b/drivers/accel/Kconfig
@@ -6,9 +6,10 @@
# as, but not limited to, Machine-Learning and Deep-Learning acceleration
# devices
#
+if DRM
+
menuconfig DRM_ACCEL
bool "Compute Acceleration Framework"
- depends on DRM
help
Framework for device drivers of compute acceleration devices, such
as, but not limited to, Machine-Learning and Deep-Learning
@@ -22,3 +23,8 @@ menuconfig DRM_ACCEL
major number than GPUs, and will be exposed to user-space using
different device files, called accel/accel* (in /dev, sysfs
and debugfs).
+
+source "drivers/accel/habanalabs/Kconfig"
+source "drivers/accel/ivpu/Kconfig"
+
+endif
diff --git a/drivers/staging/media/deprecated/fsl-viu/Makefile b/drivers/accel/Makefile
index 931ec56ad08c..07aa77aed1c8 100644
--- a/drivers/staging/media/deprecated/fsl-viu/Makefile
+++ b/drivers/accel/Makefile
@@ -1,2 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_VIDEO_VIU) += fsl-viu.o
+
+obj-y += habanalabs/
+obj-y += ivpu/
diff --git a/drivers/misc/habanalabs/Kconfig b/drivers/accel/habanalabs/Kconfig
index bd01d0d940c0..be85336107f9 100644
--- a/drivers/misc/habanalabs/Kconfig
+++ b/drivers/accel/habanalabs/Kconfig
@@ -3,8 +3,10 @@
# HabanaLabs AI accelerators driver
#
-config HABANA_AI
- tristate "HabanaAI accelerators (habanalabs)"
+config DRM_ACCEL_HABANALABS
+ tristate "HabanaLabs AI accelerators"
+ depends on DRM_ACCEL
+ depends on X86_64
depends on PCI && HAS_IOMEM
select GENERIC_ALLOCATOR
select HWMON
@@ -19,7 +21,7 @@ config HABANA_AI
the user to submit workloads to the devices.
The user-space interface is described in
- include/uapi/misc/habanalabs.h
+ include/uapi/drm/habanalabs_accel.h
If unsure, say N.
diff --git a/drivers/misc/habanalabs/Makefile b/drivers/accel/habanalabs/Makefile
index a48a9e0969ed..98510cdd5066 100644
--- a/drivers/misc/habanalabs/Makefile
+++ b/drivers/accel/habanalabs/Makefile
@@ -3,7 +3,7 @@
# Makefile for HabanaLabs AI accelerators driver
#
-obj-$(CONFIG_HABANA_AI) := habanalabs.o
+obj-$(CONFIG_DRM_ACCEL_HABANALABS) := habanalabs.o
include $(src)/common/Makefile
habanalabs-y += $(HL_COMMON_FILES)
diff --git a/drivers/misc/habanalabs/common/Makefile b/drivers/accel/habanalabs/common/Makefile
index e6abffea9f87..e6abffea9f87 100644
--- a/drivers/misc/habanalabs/common/Makefile
+++ b/drivers/accel/habanalabs/common/Makefile
diff --git a/drivers/misc/habanalabs/common/asid.c b/drivers/accel/habanalabs/common/asid.c
index c9c2619cc43d..c9c2619cc43d 100644
--- a/drivers/misc/habanalabs/common/asid.c
+++ b/drivers/accel/habanalabs/common/asid.c
diff --git a/drivers/misc/habanalabs/common/command_buffer.c b/drivers/accel/habanalabs/common/command_buffer.c
index 2b332991ac6a..3a0535ac28b1 100644
--- a/drivers/misc/habanalabs/common/command_buffer.c
+++ b/drivers/accel/habanalabs/common/command_buffer.c
@@ -5,7 +5,7 @@
* All Rights Reserved.
*/
-#include <uapi/misc/habanalabs.h>
+#include <uapi/drm/habanalabs_accel.h>
#include "habanalabs.h"
#include <linux/mm.h>
@@ -88,6 +88,7 @@ static void cb_fini(struct hl_device *hdev, struct hl_cb *cb)
static void cb_do_release(struct hl_device *hdev, struct hl_cb *cb)
{
if (cb->is_pool) {
+ atomic_set(&cb->is_handle_destroyed, 0);
spin_lock(&hdev->cb_pool_lock);
list_add(&cb->pool_list, &hdev->cb_pool);
spin_unlock(&hdev->cb_pool_lock);
@@ -298,8 +299,25 @@ int hl_cb_create(struct hl_device *hdev, struct hl_mem_mgr *mmg,
int hl_cb_destroy(struct hl_mem_mgr *mmg, u64 cb_handle)
{
+ struct hl_cb *cb;
int rc;
+ cb = hl_cb_get(mmg, cb_handle);
+ if (!cb) {
+ dev_dbg(mmg->dev, "CB destroy failed, no CB was found for handle %#llx\n",
+ cb_handle);
+ return -EINVAL;
+ }
+
+ /* Make sure that CB handle isn't destroyed more than once */
+ rc = atomic_cmpxchg(&cb->is_handle_destroyed, 0, 1);
+ hl_cb_put(cb);
+ if (rc) {
+ dev_dbg(mmg->dev, "CB destroy failed, handle %#llx was already destroyed\n",
+ cb_handle);
+ return -EINVAL;
+ }
+
rc = hl_mmap_mem_buf_put_handle(mmg, cb_handle);
if (rc < 0)
return rc; /* Invalid handle */
@@ -350,7 +368,7 @@ int hl_cb_ioctl(struct hl_fpriv *hpriv, void *data)
int rc;
if (!hl_device_operational(hdev, &status)) {
- dev_warn_ratelimited(hdev->dev,
+ dev_dbg_ratelimited(hdev->dev,
"Device is %s. Can't execute CB IOCTL\n",
hdev->status[status]);
return -EBUSY;
diff --git a/drivers/misc/habanalabs/common/command_submission.c b/drivers/accel/habanalabs/common/command_submission.c
index ea0e5101c10e..8270db0a72a2 100644
--- a/drivers/misc/habanalabs/common/command_submission.c
+++ b/drivers/accel/habanalabs/common/command_submission.c
@@ -5,7 +5,7 @@
* All Rights Reserved.
*/
-#include <uapi/misc/habanalabs.h>
+#include <uapi/drm/habanalabs_accel.h>
#include "habanalabs.h"
#include <linux/uaccess.h>
@@ -13,7 +13,8 @@
#define HL_CS_FLAGS_TYPE_MASK (HL_CS_FLAGS_SIGNAL | HL_CS_FLAGS_WAIT | \
HL_CS_FLAGS_COLLECTIVE_WAIT | HL_CS_FLAGS_RESERVE_SIGNALS_ONLY | \
- HL_CS_FLAGS_UNRESERVE_SIGNALS_ONLY | HL_CS_FLAGS_ENGINE_CORE_COMMAND)
+ HL_CS_FLAGS_UNRESERVE_SIGNALS_ONLY | HL_CS_FLAGS_ENGINE_CORE_COMMAND | \
+ HL_CS_FLAGS_FLUSH_PCI_HBW_WRITES)
#define MAX_TS_ITER_NUM 10
@@ -397,8 +398,16 @@ static void hl_complete_job(struct hl_device *hdev, struct hl_cs_job *job)
* flow by calling 'hl_hw_queue_update_ci'.
*/
if (cs_needs_completion(cs) &&
- (job->queue_type == QUEUE_TYPE_EXT || job->queue_type == QUEUE_TYPE_HW))
+ (job->queue_type == QUEUE_TYPE_EXT || job->queue_type == QUEUE_TYPE_HW)) {
+
+ /* In CS based completions, the timestamp is already available,
+ * so no need to extract it from job
+ */
+ if (hdev->asic_prop.completion_mode == HL_COMPLETION_MODE_JOB)
+ cs->completion_timestamp = job->timestamp;
+
cs_put(cs);
+ }
hl_cs_job_put(job);
}
@@ -775,7 +784,7 @@ out:
}
if (cs->timestamp) {
- cs->fence->timestamp = ktime_get();
+ cs->fence->timestamp = cs->completion_timestamp;
hl_push_cs_outcome(hdev, &cs->ctx->outcome_store, cs->sequence,
cs->fence->timestamp, cs->fence->error);
}
@@ -1117,6 +1126,27 @@ void hl_release_pending_user_interrupts(struct hl_device *hdev)
wake_pending_user_interrupt_threads(interrupt);
}
+static void force_complete_cs(struct hl_device *hdev)
+{
+ struct hl_cs *cs;
+
+ spin_lock(&hdev->cs_mirror_lock);
+
+ list_for_each_entry(cs, &hdev->cs_mirror_list, mirror_node) {
+ cs->fence->error = -EIO;
+ complete_all(&cs->fence->completion);
+ }
+
+ spin_unlock(&hdev->cs_mirror_lock);
+}
+
+void hl_abort_waitings_for_completion(struct hl_device *hdev)
+{
+ force_complete_cs(hdev);
+ force_complete_multi_cs(hdev);
+ hl_release_pending_user_interrupts(hdev);
+}
+
static void job_wq_completion(struct work_struct *work)
{
struct hl_cs_job *job = container_of(work, struct hl_cs_job,
@@ -1274,6 +1304,8 @@ static enum hl_cs_type hl_cs_get_cs_type(u32 cs_type_flags)
return CS_UNRESERVE_SIGNALS;
else if (cs_type_flags & HL_CS_FLAGS_ENGINE_CORE_COMMAND)
return CS_TYPE_ENGINE_CORE;
+ else if (cs_type_flags & HL_CS_FLAGS_FLUSH_PCI_HBW_WRITES)
+ return CS_TYPE_FLUSH_PCI_HBW_WRITES;
else
return CS_TYPE_DEFAULT;
}
@@ -1286,6 +1318,13 @@ static int hl_cs_sanity_checks(struct hl_fpriv *hpriv, union hl_cs_args *args)
enum hl_device_status status;
enum hl_cs_type cs_type;
bool is_sync_stream;
+ int i;
+
+ for (i = 0 ; i < sizeof(args->in.pad) ; i++)
+ if (args->in.pad[i]) {
+ dev_dbg(hdev->dev, "Padding bytes must be 0\n");
+ return -EINVAL;
+ }
if (!hl_device_operational(hdev, &status)) {
return -EBUSY;
@@ -2422,6 +2461,21 @@ static int cs_ioctl_engine_cores(struct hl_fpriv *hpriv, u64 engine_cores,
return rc;
}
+static int cs_ioctl_flush_pci_hbw_writes(struct hl_fpriv *hpriv)
+{
+ struct hl_device *hdev = hpriv->hdev;
+ struct asic_fixed_properties *prop = &hdev->asic_prop;
+
+ if (!prop->hbw_flush_reg) {
+ dev_dbg(hdev->dev, "HBW flush is not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ RREG32(prop->hbw_flush_reg);
+
+ return 0;
+}
+
int hl_cs_ioctl(struct hl_fpriv *hpriv, void *data)
{
union hl_cs_args *args = data;
@@ -2478,6 +2532,9 @@ int hl_cs_ioctl(struct hl_fpriv *hpriv, void *data)
rc = cs_ioctl_engine_cores(hpriv, args->in.engine_cores,
args->in.num_engine_cores, args->in.core_command);
break;
+ case CS_TYPE_FLUSH_PCI_HBW_WRITES:
+ rc = cs_ioctl_flush_pci_hbw_writes(hpriv);
+ break;
default:
rc = cs_ioctl_default(hpriv, chunks, num_chunks, &cs_seq,
args->in.cs_flags,
@@ -2569,7 +2626,9 @@ report_results:
*status = CS_WAIT_STATUS_BUSY;
}
- if (error == -ETIMEDOUT || error == -EIO)
+ if (completion_rc == -ERESTARTSYS)
+ rc = completion_rc;
+ else if (error == -ETIMEDOUT || error == -EIO)
rc = error;
return rc;
@@ -2699,7 +2758,8 @@ static int hl_cs_poll_fences(struct multi_cs_data *mcs_data, struct multi_cs_com
break;
default:
dev_err(hdev->dev, "Invalid fence status\n");
- return -EINVAL;
+ rc = -EINVAL;
+ break;
}
}
@@ -2828,6 +2888,9 @@ static int hl_wait_multi_cs_completion(struct multi_cs_data *mcs_data,
if (completion_rc > 0)
mcs_data->timestamp = mcs_compl->timestamp;
+ if (completion_rc == -ERESTARTSYS)
+ return completion_rc;
+
mcs_data->wait_status = completion_rc;
return 0;
@@ -2870,7 +2933,13 @@ static int hl_multi_cs_wait_ioctl(struct hl_fpriv *hpriv, void *data)
u32 size_to_copy;
u64 *cs_seq_arr;
u8 seq_arr_len;
- int rc;
+ int rc, i;
+
+ for (i = 0 ; i < sizeof(args->in.pad) ; i++)
+ if (args->in.pad[i]) {
+ dev_dbg(hdev->dev, "Padding bytes must be 0\n");
+ return -EINVAL;
+ }
if (!hdev->supports_wait_for_multi_cs) {
dev_err(hdev->dev, "Wait for multi CS is not supported\n");
@@ -2973,15 +3042,15 @@ put_ctx:
free_seq_arr:
kfree(cs_seq_arr);
- if (rc)
- return rc;
-
- if (mcs_data.wait_status == -ERESTARTSYS) {
+ if (rc == -ERESTARTSYS) {
dev_err_ratelimited(hdev->dev,
"user process got signal while waiting for Multi-CS\n");
- return -EINTR;
+ rc = -EINTR;
}
+ if (rc)
+ return rc;
+
/* update output args */
memset(args, 0, sizeof(*args));
@@ -3119,19 +3188,18 @@ start_over:
goto start_over;
}
} else {
+ /* Fill up the new registration node info */
+ requested_offset_record->ts_reg_info.buf = buf;
+ requested_offset_record->ts_reg_info.cq_cb = cq_cb;
+ requested_offset_record->ts_reg_info.timestamp_kernel_addr =
+ (u64 *) ts_buff->user_buff_address + ts_offset;
+ requested_offset_record->cq_kernel_addr =
+ (u64 *) cq_cb->kernel_address + cq_offset;
+ requested_offset_record->cq_target_value = target_value;
+
spin_unlock_irqrestore(wait_list_lock, flags);
}
- /* Fill up the new registration node info */
- requested_offset_record->ts_reg_info.in_use = 1;
- requested_offset_record->ts_reg_info.buf = buf;
- requested_offset_record->ts_reg_info.cq_cb = cq_cb;
- requested_offset_record->ts_reg_info.timestamp_kernel_addr =
- (u64 *) ts_buff->user_buff_address + ts_offset;
- requested_offset_record->cq_kernel_addr =
- (u64 *) cq_cb->kernel_address + cq_offset;
- requested_offset_record->cq_target_value = target_value;
-
*pend = requested_offset_record;
dev_dbg(buf->mmg->dev, "Found available node in TS kernel CB %p\n",
@@ -3179,7 +3247,7 @@ static int _hl_interrupt_wait_ioctl(struct hl_device *hdev, struct hl_ctx *ctx,
goto put_cq_cb;
}
- /* Find first available record */
+ /* get ts buffer record */
rc = ts_buff_get_kernel_ts_record(buf, cq_cb, ts_offset,
cq_counters_offset, target_value,
&interrupt->wait_list_lock, &pend);
@@ -3227,7 +3295,19 @@ static int _hl_interrupt_wait_ioctl(struct hl_device *hdev, struct hl_ctx *ctx,
* Note that we cannot have sorted list by target value,
* in order to shorten the list pass loop, since
* same list could have nodes for different cq counter handle.
+ * Note:
+ * Mark ts buff offset as in use here in the spinlock protection area
+ * to avoid getting in the re-use section in ts_buff_get_kernel_ts_record
+ * before adding the node to the list. this scenario might happen when
+ * multiple threads are racing on same offset and one thread could
+ * set the ts buff in ts_buff_get_kernel_ts_record then the other thread
+ * takes over and get to ts_buff_get_kernel_ts_record and then we will try
+ * to re-use the same ts buff offset, and will try to delete a non existing
+ * node from the list.
*/
+ if (register_ts_record)
+ pend->ts_reg_info.in_use = 1;
+
list_add_tail(&pend->wait_list_node, &interrupt->wait_list_head);
spin_unlock_irqrestore(&interrupt->wait_list_lock, flags);
@@ -3489,14 +3569,15 @@ static int hl_interrupt_wait_ioctl(struct hl_fpriv *hpriv, void *data)
int hl_wait_ioctl(struct hl_fpriv *hpriv, void *data)
{
+ struct hl_device *hdev = hpriv->hdev;
union hl_wait_cs_args *args = data;
u32 flags = args->in.flags;
int rc;
- /* If the device is not operational, no point in waiting for any command submission or
- * user interrupt
+ /* If the device is not operational, or if an error has happened and user should release the
+ * device, there is no point in waiting for any command submission or user interrupt.
*/
- if (!hl_device_operational(hpriv->hdev, NULL))
+ if (!hl_device_operational(hpriv->hdev, NULL) || hdev->reset_info.watchdog_active)
return -EBUSY;
if (flags & HL_WAIT_CS_FLAGS_INTERRUPT)
diff --git a/drivers/misc/habanalabs/common/context.c b/drivers/accel/habanalabs/common/context.c
index 9c8b1b37b510..9c8b1b37b510 100644
--- a/drivers/misc/habanalabs/common/context.c
+++ b/drivers/accel/habanalabs/common/context.c
diff --git a/drivers/misc/habanalabs/common/debugfs.c b/drivers/accel/habanalabs/common/debugfs.c
index 945c0e6758ca..945c0e6758ca 100644
--- a/drivers/misc/habanalabs/common/debugfs.c
+++ b/drivers/accel/habanalabs/common/debugfs.c
diff --git a/drivers/misc/habanalabs/common/decoder.c b/drivers/accel/habanalabs/common/decoder.c
index 2aab14d74b53..2aab14d74b53 100644
--- a/drivers/misc/habanalabs/common/decoder.c
+++ b/drivers/accel/habanalabs/common/decoder.c
diff --git a/drivers/misc/habanalabs/common/device.c b/drivers/accel/habanalabs/common/device.c
index 87ab329e65d4..9933e5858a36 100644
--- a/drivers/misc/habanalabs/common/device.c
+++ b/drivers/accel/habanalabs/common/device.c
@@ -7,7 +7,7 @@
#define pr_fmt(fmt) "habanalabs: " fmt
-#include <uapi/misc/habanalabs.h>
+#include <uapi/drm/habanalabs_accel.h>
#include "habanalabs.h"
#include <linux/pci.h>
@@ -428,8 +428,10 @@ static void hpriv_release(struct kref *ref)
*/
reset_device = hdev->reset_upon_device_release || hdev->reset_info.watchdog_active;
- /* Unless device is reset in any case, check idle status and reset if device is not idle */
- if (!reset_device && hdev->pdev && !hdev->pldm)
+ /* Check the device idle status and reset if not idle.
+ * Skip it if already in reset, or if device is going to be reset in any case.
+ */
+ if (!hdev->reset_info.in_reset && !reset_device && hdev->pdev && !hdev->pldm)
device_is_idle = hdev->asic_funcs->is_device_idle(hdev, idle_mask,
HL_BUSY_ENGINES_MASK_EXT_SIZE, NULL);
if (!device_is_idle) {
@@ -511,11 +513,6 @@ static int hl_device_release(struct inode *inode, struct file *filp)
return 0;
}
- /* Each pending user interrupt holds the user's context, hence we
- * must release them all before calling hl_ctx_mgr_fini().
- */
- hl_release_pending_user_interrupts(hpriv->hdev);
-
hl_ctx_mgr_fini(hdev, &hpriv->ctx_mgr);
hl_mem_mgr_fini(&hpriv->mem_mgr);
@@ -1428,8 +1425,8 @@ static void handle_reset_trigger(struct hl_device *hdev, u32 flags)
int hl_device_reset(struct hl_device *hdev, u32 flags)
{
bool hard_reset, from_hard_reset_thread, fw_reset, hard_instead_soft = false,
- reset_upon_device_release = false, schedule_hard_reset = false, delay_reset,
- from_dev_release, from_watchdog_thread;
+ reset_upon_device_release = false, schedule_hard_reset = false,
+ delay_reset, from_dev_release, from_watchdog_thread;
u64 idle_mask[HL_BUSY_ENGINES_MASK_EXT_SIZE] = {0};
struct hl_ctx *ctx;
int i, rc;
@@ -1446,12 +1443,17 @@ int hl_device_reset(struct hl_device *hdev, u32 flags)
delay_reset = !!(flags & HL_DRV_RESET_DELAY);
from_watchdog_thread = !!(flags & HL_DRV_RESET_FROM_WD_THR);
+ if (!hard_reset && (hl_device_status(hdev) == HL_DEVICE_STATUS_MALFUNCTION)) {
+ dev_dbg(hdev->dev, "soft-reset isn't supported on a malfunctioning device\n");
+ return 0;
+ }
+
if (!hard_reset && !hdev->asic_prop.supports_compute_reset) {
hard_instead_soft = true;
hard_reset = true;
}
- if (hdev->reset_upon_device_release && (flags & HL_DRV_RESET_DEV_RELEASE)) {
+ if (hdev->reset_upon_device_release && from_dev_release) {
if (hard_reset) {
dev_crit(hdev->dev,
"Aborting reset because hard-reset is mutually exclusive with reset-on-device-release\n");
@@ -1512,6 +1514,7 @@ do_reset:
&hdev->device_release_watchdog_work.reset_work);
if (from_dev_release) {
+ hdev->reset_info.in_compute_reset = 0;
flags |= HL_DRV_RESET_HARD;
flags &= ~HL_DRV_RESET_DEV_RELEASE;
hard_reset = true;
@@ -1566,7 +1569,8 @@ kill_processes:
if (rc == -EBUSY) {
if (hdev->device_fini_pending) {
dev_crit(hdev->dev,
- "Failed to kill all open processes, stopping hard reset\n");
+ "%s Failed to kill all open processes, stopping hard reset\n",
+ dev_name(&(hdev)->pdev->dev));
goto out_err;
}
@@ -1576,7 +1580,8 @@ kill_processes:
if (rc) {
dev_crit(hdev->dev,
- "Failed to kill all open processes, stopping hard reset\n");
+ "%s Failed to kill all open processes, stopping hard reset\n",
+ dev_name(&(hdev)->pdev->dev));
goto out_err;
}
@@ -1627,14 +1632,16 @@ kill_processes:
* ensure driver puts the driver in a unusable state
*/
dev_crit(hdev->dev,
- "Consecutive FW fatal errors received, stopping hard reset\n");
+ "%s Consecutive FW fatal errors received, stopping hard reset\n",
+ dev_name(&(hdev)->pdev->dev));
rc = -EIO;
goto out_err;
}
if (hdev->kernel_ctx) {
dev_crit(hdev->dev,
- "kernel ctx was alive during hard reset, something is terribly wrong\n");
+ "%s kernel ctx was alive during hard reset, something is terribly wrong\n",
+ dev_name(&(hdev)->pdev->dev));
rc = -EBUSY;
goto out_err;
}
@@ -1732,7 +1739,7 @@ kill_processes:
rc = hdev->asic_funcs->scrub_device_mem(hdev);
if (rc) {
dev_err(hdev->dev, "scrub mem failed from device reset (%d)\n", rc);
- return rc;
+ goto out_err;
}
spin_lock(&hdev->reset_info.lock);
@@ -1752,9 +1759,13 @@ kill_processes:
hdev->reset_info.needs_reset = false;
if (hard_reset)
- dev_info(hdev->dev, "Successfully finished resetting the device\n");
+ dev_info(hdev->dev,
+ "Successfully finished resetting the %s device\n",
+ dev_name(&(hdev)->pdev->dev));
else
- dev_dbg(hdev->dev, "Successfully finished resetting the device\n");
+ dev_dbg(hdev->dev,
+ "Successfully finished resetting the %s device\n",
+ dev_name(&(hdev)->pdev->dev));
if (hard_reset) {
hdev->reset_info.hard_reset_cnt++;
@@ -1789,7 +1800,9 @@ out_err:
hdev->reset_info.in_compute_reset = 0;
if (hard_reset) {
- dev_err(hdev->dev, "Failed to reset! Device is NOT usable\n");
+ dev_err(hdev->dev,
+ "%s Failed to reset! Device is NOT usable\n",
+ dev_name(&(hdev)->pdev->dev));
hdev->reset_info.hard_reset_cnt++;
} else if (reset_upon_device_release) {
spin_unlock(&hdev->reset_info.lock);
@@ -1870,6 +1883,8 @@ out:
hl_ctx_put(ctx);
+ hl_abort_waitings_for_completion(hdev);
+
return 0;
device_reset:
@@ -2186,7 +2201,8 @@ int hl_device_init(struct hl_device *hdev, struct class *hclass)
}
dev_notice(hdev->dev,
- "Successfully added device to habanalabs driver\n");
+ "Successfully added device %s to habanalabs driver\n",
+ dev_name(&(hdev)->pdev->dev));
hdev->init_done = true;
@@ -2235,11 +2251,11 @@ out_disabled:
device_cdev_sysfs_add(hdev);
if (hdev->pdev)
dev_err(&hdev->pdev->dev,
- "Failed to initialize hl%d. Device is NOT usable !\n",
- hdev->cdev_idx);
+ "Failed to initialize hl%d. Device %s is NOT usable !\n",
+ hdev->cdev_idx, dev_name(&(hdev)->pdev->dev));
else
- pr_err("Failed to initialize hl%d. Device is NOT usable !\n",
- hdev->cdev_idx);
+ pr_err("Failed to initialize hl%d. Device %s is NOT usable !\n",
+ hdev->cdev_idx, dev_name(&(hdev)->pdev->dev));
return rc;
}
@@ -2295,7 +2311,8 @@ void hl_device_fini(struct hl_device *hdev)
if (ktime_compare(ktime_get(), timeout) > 0) {
dev_crit(hdev->dev,
- "Failed to remove device because reset function did not finish\n");
+ "%s Failed to remove device because reset function did not finish\n",
+ dev_name(&(hdev)->pdev->dev));
return;
}
}
@@ -2363,7 +2380,7 @@ void hl_device_fini(struct hl_device *hdev)
hl_mmu_fini(hdev);
- vfree(hdev->captured_err_info.pgf_info.user_mappings);
+ vfree(hdev->captured_err_info.page_fault_info.user_mappings);
hl_eq_fini(hdev, &hdev->event_queue);
@@ -2402,7 +2419,12 @@ void hl_device_fini(struct hl_device *hdev)
*/
inline u32 hl_rreg(struct hl_device *hdev, u32 reg)
{
- return readl(hdev->rmmio + reg);
+ u32 val = readl(hdev->rmmio + reg);
+
+ if (unlikely(trace_habanalabs_rreg32_enabled()))
+ trace_habanalabs_rreg32(hdev->dev, reg, val);
+
+ return val;
}
/*
@@ -2417,12 +2439,17 @@ inline u32 hl_rreg(struct hl_device *hdev, u32 reg)
*/
inline void hl_wreg(struct hl_device *hdev, u32 reg, u32 val)
{
+ if (unlikely(trace_habanalabs_wreg32_enabled()))
+ trace_habanalabs_wreg32(hdev->dev, reg, val);
+
writel(val, hdev->rmmio + reg);
}
void hl_capture_razwi(struct hl_device *hdev, u64 addr, u16 *engine_id, u16 num_of_engines,
u8 flags)
{
+ struct razwi_info *razwi_info = &hdev->captured_err_info.razwi_info;
+
if (num_of_engines > HL_RAZWI_MAX_NUM_OF_ENGINES_PER_RTR) {
dev_err(hdev->dev,
"Number of possible razwi initiators (%u) exceeded limit (%u)\n",
@@ -2431,15 +2458,17 @@ void hl_capture_razwi(struct hl_device *hdev, u64 addr, u16 *engine_id, u16 num_
}
/* In case it's the first razwi since the device was opened, capture its parameters */
- if (atomic_cmpxchg(&hdev->captured_err_info.razwi_info_recorded, 0, 1))
+ if (atomic_cmpxchg(&hdev->captured_err_info.razwi_info.razwi_detected, 0, 1))
return;
- hdev->captured_err_info.razwi.timestamp = ktime_to_ns(ktime_get());
- hdev->captured_err_info.razwi.addr = addr;
- hdev->captured_err_info.razwi.num_of_possible_engines = num_of_engines;
- memcpy(&hdev->captured_err_info.razwi.engine_id[0], &engine_id[0],
+ razwi_info->razwi.timestamp = ktime_to_ns(ktime_get());
+ razwi_info->razwi.addr = addr;
+ razwi_info->razwi.num_of_possible_engines = num_of_engines;
+ memcpy(&razwi_info->razwi.engine_id[0], &engine_id[0],
num_of_engines * sizeof(u16));
- hdev->captured_err_info.razwi.flags = flags;
+ razwi_info->razwi.flags = flags;
+
+ razwi_info->razwi_info_available = true;
}
void hl_handle_razwi(struct hl_device *hdev, u64 addr, u16 *engine_id, u16 num_of_engines,
@@ -2453,7 +2482,7 @@ void hl_handle_razwi(struct hl_device *hdev, u64 addr, u16 *engine_id, u16 num_o
static void hl_capture_user_mappings(struct hl_device *hdev, bool is_pmmu)
{
- struct page_fault_info *pgf_info = &hdev->captured_err_info.pgf_info;
+ struct page_fault_info *pgf_info = &hdev->captured_err_info.page_fault_info;
struct hl_vm_phys_pg_pack *phys_pg_pack = NULL;
struct hl_vm_hash_node *hnode;
struct hl_userptr *userptr;
@@ -2515,14 +2544,18 @@ finish:
void hl_capture_page_fault(struct hl_device *hdev, u64 addr, u16 eng_id, bool is_pmmu)
{
+ struct page_fault_info *pgf_info = &hdev->captured_err_info.page_fault_info;
+
/* Capture only the first page fault */
- if (atomic_cmpxchg(&hdev->captured_err_info.pgf_info_recorded, 0, 1))
+ if (atomic_cmpxchg(&pgf_info->page_fault_detected, 0, 1))
return;
- hdev->captured_err_info.pgf_info.pgf.timestamp = ktime_to_ns(ktime_get());
- hdev->captured_err_info.pgf_info.pgf.addr = addr;
- hdev->captured_err_info.pgf_info.pgf.engine_id = eng_id;
+ pgf_info->page_fault.timestamp = ktime_to_ns(ktime_get());
+ pgf_info->page_fault.addr = addr;
+ pgf_info->page_fault.engine_id = eng_id;
hl_capture_user_mappings(hdev, is_pmmu);
+
+ pgf_info->page_fault_info_available = true;
}
void hl_handle_page_fault(struct hl_device *hdev, u64 addr, u16 eng_id, bool is_pmmu,
diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/accel/habanalabs/common/firmware_if.c
index 228b92278e48..da892d8fb3d6 100644
--- a/drivers/misc/habanalabs/common/firmware_if.c
+++ b/drivers/accel/habanalabs/common/firmware_if.c
@@ -14,8 +14,32 @@
#include <linux/ctype.h>
#include <linux/vmalloc.h>
+#include <trace/events/habanalabs.h>
+
#define FW_FILE_MAX_SIZE 0x1400000 /* maximum size of 20MB */
+static char *comms_cmd_str_arr[COMMS_INVLD_LAST] = {
+ [COMMS_NOOP] = __stringify(COMMS_NOOP),
+ [COMMS_CLR_STS] = __stringify(COMMS_CLR_STS),
+ [COMMS_RST_STATE] = __stringify(COMMS_RST_STATE),
+ [COMMS_PREP_DESC] = __stringify(COMMS_PREP_DESC),
+ [COMMS_DATA_RDY] = __stringify(COMMS_DATA_RDY),
+ [COMMS_EXEC] = __stringify(COMMS_EXEC),
+ [COMMS_RST_DEV] = __stringify(COMMS_RST_DEV),
+ [COMMS_GOTO_WFE] = __stringify(COMMS_GOTO_WFE),
+ [COMMS_SKIP_BMC] = __stringify(COMMS_SKIP_BMC),
+ [COMMS_PREP_DESC_ELBI] = __stringify(COMMS_PREP_DESC_ELBI),
+};
+
+static char *comms_sts_str_arr[COMMS_STS_INVLD_LAST] = {
+ [COMMS_STS_NOOP] = __stringify(COMMS_STS_NOOP),
+ [COMMS_STS_ACK] = __stringify(COMMS_STS_ACK),
+ [COMMS_STS_OK] = __stringify(COMMS_STS_OK),
+ [COMMS_STS_ERR] = __stringify(COMMS_STS_ERR),
+ [COMMS_STS_VALID_ERR] = __stringify(COMMS_STS_VALID_ERR),
+ [COMMS_STS_TIMEOUT_ERR] = __stringify(COMMS_STS_TIMEOUT_ERR),
+};
+
static char *extract_fw_ver_from_str(const char *fw_str)
{
char *str, *fw_ver, *whitespace;
@@ -311,7 +335,7 @@ int hl_fw_send_cpu_message(struct hl_device *hdev, u32 hw_queue_id, u32 *msg,
dev_dbg(hdev->dev, "Device CPU packet timeout (0x%x) due to FW reset\n",
tmp);
else
- dev_err(hdev->dev, "Device CPU packet timeout (0x%x)\n", tmp);
+ dev_err(hdev->dev, "Device CPU packet timeout (status = 0x%x)\n", tmp);
hdev->device_cpu_disabled = true;
goto out;
}
@@ -1322,13 +1346,12 @@ static void detect_cpu_boot_status(struct hl_device *hdev, u32 status)
break;
default:
dev_err(hdev->dev,
- "Device boot progress - Invalid status code %d\n",
- status);
+ "Device boot progress - Invalid or unexpected status code %d\n", status);
break;
}
}
-static int hl_fw_wait_preboot_ready(struct hl_device *hdev)
+int hl_fw_wait_preboot_ready(struct hl_device *hdev)
{
struct pre_fw_load_props *pre_fw_load = &hdev->fw_loader.pre_fw_load;
u32 status;
@@ -1353,8 +1376,8 @@ static int hl_fw_wait_preboot_ready(struct hl_device *hdev)
pre_fw_load->wait_for_preboot_timeout);
if (rc) {
- dev_err(hdev->dev, "CPU boot ready status timeout\n");
detect_cpu_boot_status(hdev, status);
+ dev_err(hdev->dev, "CPU boot ready timeout (status = %d)\n", status);
/* If we read all FF, then something is totally wrong, no point
* of reading specific errors
@@ -1634,6 +1657,7 @@ static void hl_fw_dynamic_send_cmd(struct hl_device *hdev,
val = FIELD_PREP(COMMS_COMMAND_CMD_MASK, cmd);
val |= FIELD_PREP(COMMS_COMMAND_SIZE_MASK, size);
+ trace_habanalabs_comms_send_cmd(hdev->dev, comms_cmd_str_arr[cmd]);
WREG32(le32_to_cpu(dyn_regs->kmd_msg_to_cpu), val);
}
@@ -1691,6 +1715,8 @@ static int hl_fw_dynamic_wait_for_status(struct hl_device *hdev,
dyn_regs = &fw_loader->dynamic_loader.comm_desc.cpu_dyn_regs;
+ trace_habanalabs_comms_wait_status(hdev->dev, comms_sts_str_arr[expected_status]);
+
/* Wait for expected status */
rc = hl_poll_timeout(
hdev,
@@ -1706,6 +1732,8 @@ static int hl_fw_dynamic_wait_for_status(struct hl_device *hdev,
return -EIO;
}
+ trace_habanalabs_comms_wait_status_done(hdev->dev, comms_sts_str_arr[expected_status]);
+
/*
* skip storing FW response for NOOP to preserve the actual desired
* FW status
@@ -1778,6 +1806,8 @@ int hl_fw_dynamic_send_protocol_cmd(struct hl_device *hdev,
{
int rc;
+ trace_habanalabs_comms_protocol_cmd(hdev->dev, comms_cmd_str_arr[cmd]);
+
/* first send clear command to clean former commands */
rc = hl_fw_dynamic_send_clear_cmd(hdev, fw_loader);
if (rc)
@@ -1884,7 +1914,7 @@ static int hl_fw_dynamic_validate_memory_bound(struct hl_device *hdev,
*
* @hdev: pointer to the habanalabs device structure
* @fw_loader: managing structure for loading device's FW
- * @fw_desc: the descriptor form FW
+ * @fw_desc: the descriptor from FW
*
* @return 0 on success, otherwise non-zero error code
*/
@@ -1901,11 +1931,11 @@ static int hl_fw_dynamic_validate_descriptor(struct hl_device *hdev,
int rc;
if (le32_to_cpu(fw_desc->header.magic) != HL_COMMS_DESC_MAGIC)
- dev_warn(hdev->dev, "Invalid magic for dynamic FW descriptor (%x)\n",
+ dev_dbg(hdev->dev, "Invalid magic for dynamic FW descriptor (%x)\n",
fw_desc->header.magic);
if (fw_desc->header.version != HL_COMMS_DESC_VER)
- dev_warn(hdev->dev, "Invalid version for dynamic FW descriptor (%x)\n",
+ dev_dbg(hdev->dev, "Invalid version for dynamic FW descriptor (%x)\n",
fw_desc->header.version);
/*
@@ -1976,6 +2006,43 @@ static int hl_fw_dynamic_validate_response(struct hl_device *hdev,
return rc;
}
+/*
+ * hl_fw_dynamic_read_descriptor_msg - read and show the ascii msg that sent by fw
+ *
+ * @hdev: pointer to the habanalabs device structure
+ * @fw_desc: the descriptor from FW
+ */
+static void hl_fw_dynamic_read_descriptor_msg(struct hl_device *hdev,
+ struct lkd_fw_comms_desc *fw_desc)
+{
+ int i;
+ char *msg;
+
+ for (i = 0 ; i < LKD_FW_ASCII_MSG_MAX ; i++) {
+ if (!fw_desc->ascii_msg[i].valid)
+ return;
+
+ /* force NULL termination */
+ msg = fw_desc->ascii_msg[i].msg;
+ msg[LKD_FW_ASCII_MSG_MAX_LEN - 1] = '\0';
+
+ switch (fw_desc->ascii_msg[i].msg_lvl) {
+ case LKD_FW_ASCII_MSG_ERR:
+ dev_err(hdev->dev, "fw: %s", fw_desc->ascii_msg[i].msg);
+ break;
+ case LKD_FW_ASCII_MSG_WRN:
+ dev_warn(hdev->dev, "fw: %s", fw_desc->ascii_msg[i].msg);
+ break;
+ case LKD_FW_ASCII_MSG_INF:
+ dev_info(hdev->dev, "fw: %s", fw_desc->ascii_msg[i].msg);
+ break;
+ default:
+ dev_dbg(hdev->dev, "fw: %s", fw_desc->ascii_msg[i].msg);
+ break;
+ }
+ }
+}
+
/**
* hl_fw_dynamic_read_and_validate_descriptor - read and validate FW descriptor
*
@@ -1988,9 +2055,10 @@ static int hl_fw_dynamic_read_and_validate_descriptor(struct hl_device *hdev,
struct fw_load_mgr *fw_loader)
{
struct lkd_fw_comms_desc *fw_desc;
- void __iomem *src, *temp_fw_desc;
struct pci_mem_region *region;
struct fw_response *response;
+ void *temp_fw_desc;
+ void __iomem *src;
u16 fw_data_size;
enum pci_region region_id;
int rc;
@@ -2039,6 +2107,10 @@ static int hl_fw_dynamic_read_and_validate_descriptor(struct hl_device *hdev,
rc = hl_fw_dynamic_validate_descriptor(hdev, fw_loader,
(struct lkd_fw_comms_desc *) temp_fw_desc);
+
+ if (!rc)
+ hl_fw_dynamic_read_descriptor_msg(hdev, temp_fw_desc);
+
vfree(temp_fw_desc);
return rc;
@@ -2354,7 +2426,7 @@ static int hl_fw_dynamic_wait_for_boot_fit_active(struct hl_device *hdev,
hdev->fw_poll_interval_usec,
dyn_loader->wait_for_bl_timeout);
if (rc) {
- dev_err(hdev->dev, "failed to wait for boot\n");
+ dev_err(hdev->dev, "failed to wait for boot (status = %d)\n", status);
return rc;
}
@@ -2381,7 +2453,7 @@ static int hl_fw_dynamic_wait_for_linux_active(struct hl_device *hdev,
hdev->fw_poll_interval_usec,
fw_loader->cpu_timeout);
if (rc) {
- dev_err(hdev->dev, "failed to wait for Linux\n");
+ dev_err(hdev->dev, "failed to wait for Linux (status = %d)\n", status);
return rc;
}
@@ -2459,51 +2531,54 @@ static void hl_fw_linux_update_state(struct hl_device *hdev,
static int hl_fw_dynamic_send_msg(struct hl_device *hdev,
struct fw_load_mgr *fw_loader, u8 msg_type, void *data)
{
- struct lkd_msg_comms msg;
+ struct lkd_msg_comms *msg;
int rc;
- memset(&msg, 0, sizeof(msg));
+ msg = kzalloc(sizeof(*msg), GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
/* create message to be sent */
- msg.header.type = msg_type;
- msg.header.size = cpu_to_le16(sizeof(struct comms_msg_header));
- msg.header.magic = cpu_to_le32(HL_COMMS_MSG_MAGIC);
+ msg->header.type = msg_type;
+ msg->header.size = cpu_to_le16(sizeof(struct comms_msg_header));
+ msg->header.magic = cpu_to_le32(HL_COMMS_MSG_MAGIC);
switch (msg_type) {
case HL_COMMS_RESET_CAUSE_TYPE:
- msg.reset_cause = *(__u8 *) data;
+ msg->reset_cause = *(__u8 *) data;
break;
default:
dev_err(hdev->dev,
"Send COMMS message - invalid message type %u\n",
msg_type);
- return -EINVAL;
+ rc = -EINVAL;
+ goto out;
}
rc = hl_fw_dynamic_request_descriptor(hdev, fw_loader,
sizeof(struct lkd_msg_comms));
if (rc)
- return rc;
+ goto out;
/* copy message to space allocated by FW */
- rc = hl_fw_dynamic_copy_msg(hdev, &msg, fw_loader);
+ rc = hl_fw_dynamic_copy_msg(hdev, msg, fw_loader);
if (rc)
- return rc;
+ goto out;
rc = hl_fw_dynamic_send_protocol_cmd(hdev, fw_loader, COMMS_DATA_RDY,
0, true,
fw_loader->cpu_timeout);
if (rc)
- return rc;
+ goto out;
rc = hl_fw_dynamic_send_protocol_cmd(hdev, fw_loader, COMMS_EXEC,
0, true,
fw_loader->cpu_timeout);
- if (rc)
- return rc;
- return 0;
+out:
+ kfree(msg);
+ return rc;
}
/**
@@ -2560,13 +2635,43 @@ static int hl_fw_dynamic_init_cpu(struct hl_device *hdev,
}
if (!(hdev->fw_components & FW_TYPE_BOOT_CPU)) {
+ struct lkd_fw_binning_info *binning_info;
+
rc = hl_fw_dynamic_request_descriptor(hdev, fw_loader, 0);
if (rc)
goto protocol_err;
/* read preboot version */
- return hl_fw_dynamic_read_device_fw_version(hdev, FW_COMP_PREBOOT,
+ rc = hl_fw_dynamic_read_device_fw_version(hdev, FW_COMP_PREBOOT,
fw_loader->dynamic_loader.comm_desc.cur_fw_ver);
+
+ if (rc)
+ return rc;
+
+ /* read binning info from preboot */
+ if (hdev->support_preboot_binning) {
+ binning_info = &fw_loader->dynamic_loader.comm_desc.binning_info;
+ hdev->tpc_binning = le64_to_cpu(binning_info->tpc_mask_l);
+ hdev->dram_binning = le32_to_cpu(binning_info->dram_mask);
+ hdev->edma_binning = le32_to_cpu(binning_info->edma_mask);
+ hdev->decoder_binning = le32_to_cpu(binning_info->dec_mask);
+ hdev->rotator_binning = le32_to_cpu(binning_info->rot_mask);
+
+ rc = hdev->asic_funcs->set_dram_properties(hdev);
+ if (rc)
+ return rc;
+
+ rc = hdev->asic_funcs->set_binning_masks(hdev);
+ if (rc)
+ return rc;
+
+ dev_dbg(hdev->dev,
+ "Read binning masks: tpc: 0x%llx, dram: 0x%llx, edma: 0x%x, dec: 0x%x, rot:0x%x\n",
+ hdev->tpc_binning, hdev->dram_binning, hdev->edma_binning,
+ hdev->decoder_binning, hdev->rotator_binning);
+ }
+
+ return 0;
}
/* load boot fit to FW */
@@ -2687,7 +2792,7 @@ static int hl_fw_static_init_cpu(struct hl_device *hdev,
if (rc) {
dev_dbg(hdev->dev,
- "No boot fit request received, resuming boot\n");
+ "No boot fit request received (status = %d), resuming boot\n", status);
} else {
rc = hdev->asic_funcs->load_boot_fit_to_device(hdev);
if (rc)
@@ -2710,7 +2815,7 @@ static int hl_fw_static_init_cpu(struct hl_device *hdev,
if (rc) {
dev_err(hdev->dev,
- "Timeout waiting for boot fit load ack\n");
+ "Timeout waiting for boot fit load ack (status = %d)\n", status);
goto out;
}
@@ -2788,7 +2893,7 @@ static int hl_fw_static_init_cpu(struct hl_device *hdev,
if (rc) {
dev_err(hdev->dev,
- "Failed to get ACK on skipping BMC, %d\n",
+ "Failed to get ACK on skipping BMC (status = %d)\n",
status);
WREG32(msg_to_cpu_reg, KMD_MSG_NA);
rc = -EIO;
@@ -2815,7 +2920,7 @@ static int hl_fw_static_init_cpu(struct hl_device *hdev,
"Device reports FIT image is corrupted\n");
else
dev_err(hdev->dev,
- "Failed to load firmware to device, %d\n",
+ "Failed to load firmware to device (status = %d)\n",
status);
rc = -EIO;
@@ -3043,3 +3148,27 @@ int hl_fw_get_sec_attest_info(struct hl_device *hdev, struct cpucp_sec_attest_in
sizeof(struct cpucp_sec_attest_info), nonce,
HL_CPUCP_SEC_ATTEST_INFO_TINEOUT_USEC);
}
+
+int hl_fw_send_generic_request(struct hl_device *hdev, enum hl_passthrough_type sub_opcode,
+ dma_addr_t buff, u32 *size)
+{
+ struct cpucp_packet pkt = {0};
+ u64 result;
+ int rc = 0;
+
+ pkt.ctl = cpu_to_le32(CPUCP_PACKET_GENERIC_PASSTHROUGH << CPUCP_PKT_CTL_OPCODE_SHIFT);
+ pkt.addr = cpu_to_le64(buff);
+ pkt.data_max_size = cpu_to_le32(*size);
+ pkt.pkt_subidx = cpu_to_le32(sub_opcode);
+
+ rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *)&pkt, sizeof(pkt),
+ HL_CPUCP_INFO_TIMEOUT_USEC, &result);
+ if (rc)
+ dev_err(hdev->dev, "failed to send CPUCP data of generic fw pkt\n");
+ else
+ dev_dbg(hdev->dev, "generic pkt was successful, result: 0x%llx\n", result);
+
+ *size = (u32)result;
+
+ return rc;
+}
diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/accel/habanalabs/common/habanalabs.h
index e2527d976ee0..fa05e76d3d21 100644
--- a/drivers/misc/habanalabs/common/habanalabs.h
+++ b/drivers/accel/habanalabs/common/habanalabs.h
@@ -11,7 +11,7 @@
#include "../include/common/cpucp_if.h"
#include "../include/common/qman_if.h"
#include "../include/hw_ip/mmu/mmu_general.h"
-#include <uapi/misc/habanalabs.h>
+#include <uapi/drm/habanalabs_accel.h>
#include <linux/cdev.h>
#include <linux/iopoll.h>
@@ -29,6 +29,8 @@
#include <linux/coresight.h>
#include <linux/dma-buf.h>
+#include "security.h"
+
#define HL_NAME "habanalabs"
struct hl_device;
@@ -375,7 +377,8 @@ enum hl_cs_type {
CS_TYPE_COLLECTIVE_WAIT,
CS_RESERVE_SIGNALS,
CS_UNRESERVE_SIGNALS,
- CS_TYPE_ENGINE_CORE
+ CS_TYPE_ENGINE_CORE,
+ CS_TYPE_FLUSH_PCI_HBW_WRITES,
};
/*
@@ -545,6 +548,8 @@ struct hl_hints_range {
/**
* struct asic_fixed_properties - ASIC specific immutable properties.
* @hw_queues_props: H/W queues properties.
+ * @special_blocks: points to an array containing special blocks info.
+ * @skip_special_blocks_cfg: special blocks skip configs.
* @cpucp_info: received various information from CPU-CP regarding the H/W, e.g.
* available sensors.
* @uboot_ver: F/W U-boot version.
@@ -644,6 +649,10 @@ struct hl_hints_range {
* (i.e. the DRAM supports multiple page sizes), otherwise
* it will shall be equal to dram_page_size.
* @num_engine_cores: number of engine cpu cores
+ * @num_of_special_blocks: special_blocks array size.
+ * @glbl_err_cause_num: global err cause number.
+ * @hbw_flush_reg: register to read to generate HBW flush. value of 0 means HBW flush is
+ * not supported.
* @collective_first_sob: first sync object available for collective use
* @collective_first_mon: first monitor available for collective use
* @sync_stream_first_sob: first sync object available for sync stream use
@@ -692,6 +701,8 @@ struct hl_hints_range {
*/
struct asic_fixed_properties {
struct hw_queue_properties *hw_queues_props;
+ struct hl_special_block_info *special_blocks;
+ struct hl_skip_blocks_cfg skip_special_blocks_cfg;
struct cpucp_info cpucp_info;
char uboot_ver[VERSION_MAX_LEN];
char preboot_ver[VERSION_MAX_LEN];
@@ -764,6 +775,9 @@ struct asic_fixed_properties {
u32 xbar_edge_enabled_mask;
u32 device_mem_alloc_default_page_size;
u32 num_engine_cores;
+ u32 num_of_special_blocks;
+ u32 glbl_err_cause_num;
+ u32 hbw_flush_reg;
u16 collective_first_sob;
u16 collective_first_mon;
u16 sync_stream_first_sob;
@@ -935,6 +949,7 @@ struct hl_mmap_mem_buf {
* @size: holds the CB's size.
* @roundup_size: holds the cb size after roundup to page size.
* @cs_cnt: holds number of CS that this CB participates in.
+ * @is_handle_destroyed: atomic boolean indicating whether or not the CB handle was destroyed.
* @is_pool: true if CB was acquired from the pool, false otherwise.
* @is_internal: internally allocated
* @is_mmu_mapped: true if the CB is mapped to the device's MMU.
@@ -951,6 +966,7 @@ struct hl_cb {
u32 size;
u32 roundup_size;
atomic_t cs_cnt;
+ atomic_t is_handle_destroyed;
u8 is_pool;
u8 is_internal;
u8 is_mmu_mapped;
@@ -1077,20 +1093,25 @@ struct hl_cq {
atomic_t free_slots_cnt;
};
+enum hl_user_interrupt_type {
+ HL_USR_INTERRUPT_CQ = 0,
+ HL_USR_INTERRUPT_DECODER,
+};
+
/**
* struct hl_user_interrupt - holds user interrupt information
* @hdev: pointer to the device structure
+ * @type: user interrupt type
* @wait_list_head: head to the list of user threads pending on this interrupt
* @wait_list_lock: protects wait_list_head
* @interrupt_id: msix interrupt id
- * @is_decoder: whether this entry represents a decoder interrupt
*/
struct hl_user_interrupt {
- struct hl_device *hdev;
- struct list_head wait_list_head;
- spinlock_t wait_list_lock;
- u32 interrupt_id;
- bool is_decoder;
+ struct hl_device *hdev;
+ enum hl_user_interrupt_type type;
+ struct list_head wait_list_head;
+ spinlock_t wait_list_lock;
+ u32 interrupt_id;
};
/**
@@ -1540,8 +1561,10 @@ struct engines_data {
* @check_if_razwi_happened: check if there was a razwi due to RR violation.
* @access_dev_mem: access device memory
* @set_dram_bar_base: set the base of the DRAM BAR
- * @set_engine_cores: set a config command to enigne cores
+ * @set_engine_cores: set a config command to engine cores
* @send_device_activity: indication to FW about device availability
+ * @set_dram_properties: set DRAM related properties.
+ * @set_binning_masks: set binning/enable masks for all relevant components.
*/
struct hl_asic_funcs {
int (*early_init)(struct hl_device *hdev);
@@ -1679,6 +1702,8 @@ struct hl_asic_funcs {
int (*set_engine_cores)(struct hl_device *hdev, u32 *core_ids,
u32 num_cores, u32 core_command);
int (*send_device_activity)(struct hl_device *hdev, bool open);
+ int (*set_dram_properties)(struct hl_device *hdev);
+ int (*set_binning_masks)(struct hl_device *hdev);
};
@@ -1739,8 +1764,9 @@ struct hl_cs_counters_atomic {
* struct hl_dmabuf_priv - a dma-buf private object.
* @dmabuf: pointer to dma-buf object.
* @ctx: pointer to the dma-buf owner's context.
- * @phys_pg_pack: pointer to physical page pack if the dma-buf was exported for
- * memory allocation handle.
+ * @phys_pg_pack: pointer to physical page pack if the dma-buf was exported
+ * where virtual memory is supported.
+ * @memhash_hnode: pointer to the memhash node. this object holds the export count.
* @device_address: physical address of the device's memory. Relevant only
* if phys_pg_pack is NULL (dma-buf was exported from address).
* The total size can be taken from the dmabuf object.
@@ -1749,6 +1775,7 @@ struct hl_dmabuf_priv {
struct dma_buf *dmabuf;
struct hl_ctx *ctx;
struct hl_vm_phys_pg_pack *phys_pg_pack;
+ struct hl_vm_hash_node *memhash_hnode;
uint64_t device_address;
};
@@ -1923,6 +1950,7 @@ struct hl_userptr {
* @type: CS_TYPE_*.
* @jobs_cnt: counter of submitted jobs on all queues.
* @encaps_sig_hdl_id: encaps signals handle id, set for the first staged cs.
+ * @completion_timestamp: timestamp of the last completed cs job.
* @sob_addr_offset: sob offset from the configuration base address.
* @initial_sob_count: count of completed signals in SOB before current submission of signal or
* cs with encaps signals.
@@ -1955,6 +1983,7 @@ struct hl_cs {
struct list_head staged_cs_node;
struct list_head debugfs_list;
struct hl_cs_encaps_sig_handle *encaps_sig_hdl;
+ ktime_t completion_timestamp;
u64 sequence;
u64 staged_sequence;
u64 timeout_jiffies;
@@ -1990,6 +2019,7 @@ struct hl_cs {
* @debugfs_list: node in debugfs list of command submission jobs.
* @refcount: reference counter for usage of the CS job.
* @queue_type: the type of the H/W queue this job is submitted to.
+ * @timestamp: timestamp upon job completion
* @id: the id of this job inside a CS.
* @hw_queue_id: the id of the H/W queue this job is submitted to.
* @user_cb_size: the actual size of the CB we got from the user.
@@ -2016,6 +2046,7 @@ struct hl_cs_job {
struct list_head debugfs_list;
struct kref refcount;
enum hl_queue_type queue_type;
+ ktime_t timestamp;
u32 id;
u32 hw_queue_id;
u32 user_cb_size;
@@ -2076,12 +2107,16 @@ struct hl_cs_parser {
* hl_userptr).
* @node: node to hang on the hash table in context object.
* @vaddr: key virtual address.
+ * @handle: memory handle for device memory allocation.
* @ptr: value pointer (hl_vm_phys_pg_list or hl_userptr).
+ * @export_cnt: number of exports from within the VA block.
*/
struct hl_vm_hash_node {
struct hlist_node node;
u64 vaddr;
+ u64 handle;
void *ptr;
+ int export_cnt;
};
/**
@@ -2109,10 +2144,10 @@ struct hl_vm_hw_block_list_node {
* @pages: the physical page array.
* @npages: num physical pages in the pack.
* @total_size: total size of all the pages in this list.
+ * @exported_size: buffer exported size.
* @node: used to attach to deletion list that is used when all the allocations are cleared
* at the teardown of the context.
* @mapping_cnt: number of shared mappings.
- * @exporting_cnt: number of dma-buf exporting.
* @asid: the context related to this list.
* @page_size: size of each page in the pack.
* @flags: HL_MEM_* flags related to this list.
@@ -2126,9 +2161,9 @@ struct hl_vm_phys_pg_pack {
u64 *pages;
u64 npages;
u64 total_size;
+ u64 exported_size;
struct list_head node;
atomic_t mapping_cnt;
- u32 exporting_cnt;
u32 asid;
u32 page_size;
u32 flags;
@@ -2675,11 +2710,11 @@ void hl_wreg(struct hl_device *hdev, u32 reg, u32 val);
p->size = sz; \
})
-#define HL_USR_INTR_STRUCT_INIT(usr_intr, hdev, intr_id, decoder) \
+#define HL_USR_INTR_STRUCT_INIT(usr_intr, hdev, intr_id, intr_type) \
({ \
usr_intr.hdev = hdev; \
usr_intr.interrupt_id = intr_id; \
- usr_intr.is_decoder = decoder; \
+ usr_intr.type = intr_type; \
INIT_LIST_HEAD(&usr_intr.wait_list_head); \
spin_lock_init(&usr_intr.wait_list_lock); \
})
@@ -2961,37 +2996,53 @@ struct undefined_opcode_info {
};
/**
- * struct page_fault_info - info about page fault
- * @pgf_info: page fault information.
+ * struct page_fault_info - page fault information.
+ * @page_fault: holds information collected during a page fault.
* @user_mappings: buffer containing user mappings.
* @num_of_user_mappings: number of user mappings.
+ * @page_fault_detected: if set as 1, then a page-fault was discovered for the
+ * first time after the driver has finished booting-up.
+ * Since we're looking for the page-fault's root cause,
+ * we don't care of the others that might follow it-
+ * so once changed to 1, it will remain that way.
+ * @page_fault_info_available: indicates that a page fault info is now available.
*/
struct page_fault_info {
- struct hl_page_fault_info pgf;
+ struct hl_page_fault_info page_fault;
struct hl_user_mapping *user_mappings;
u64 num_of_user_mappings;
+ atomic_t page_fault_detected;
+ bool page_fault_info_available;
+};
+
+/**
+ * struct razwi_info - RAZWI information.
+ * @razwi: holds information collected during a RAZWI
+ * @razwi_detected: if set as 1, then a RAZWI was discovered for the
+ * first time after the driver has finished booting-up.
+ * Since we're looking for the RAZWI's root cause,
+ * we don't care of the others that might follow it-
+ * so once changed to 1, it will remain that way.
+ * @razwi_info_available: indicates that a RAZWI info is now available.
+ */
+struct razwi_info {
+ struct hl_info_razwi_event razwi;
+ atomic_t razwi_detected;
+ bool razwi_info_available;
};
/**
* struct hl_error_info - holds information collected during an error.
* @cs_timeout: CS timeout error information.
- * @razwi: razwi information.
- * @razwi_info_recorded: if set writing to razwi information is enabled.
- * otherwise - disabled, so the first (root cause) razwi will not be
- * overwritten.
- * @undef_opcode: undefined opcode information
- * @pgf_info: page fault information.
- * @pgf_info_recorded: if set writing to page fault information is enabled.
- * otherwise - disabled, so the first (root cause) page fault will not be
- * overwritten.
+ * @razwi_info: RAZWI information.
+ * @undef_opcode: undefined opcode information.
+ * @page_fault_info: page fault information.
*/
struct hl_error_info {
struct cs_timeout_info cs_timeout;
- struct hl_info_razwi_event razwi;
- atomic_t razwi_info_recorded;
+ struct razwi_info razwi_info;
struct undefined_opcode_info undef_opcode;
- struct page_fault_info pgf_info;
- atomic_t pgf_info_recorded;
+ struct page_fault_info page_fault_info;
};
/**
@@ -3157,6 +3208,8 @@ struct hl_reset_info {
* @edma_binning: contains mask of edma engines that is received from the f/w which
* indicates which edma engines are binned-out
* @device_release_watchdog_timeout_sec: device release watchdog timeout value in seconds.
+ * @rotator_binning: contains mask of rotators engines that is received from the f/w
+ * which indicates which rotator engines are binned-out(Gaudi3 and above).
* @id: device minor.
* @id_control: minor of the control device.
* @cdev_idx: char device index. Used for setting its name.
@@ -3214,6 +3267,7 @@ struct hl_reset_info {
* @heartbeat: Controls if we want to enable the heartbeat mechanism vs. the f/w, which verifies
* that the f/w is always alive. Used only for testing.
* @supports_ctx_switch: true if a ctx switch is required upon first submission.
+ * @support_preboot_binning: true if we support read binning info from preboot.
*/
struct hl_device {
struct pci_dev *pdev;
@@ -3322,6 +3376,7 @@ struct hl_device {
u32 decoder_binning;
u32 edma_binning;
u32 device_release_watchdog_timeout_sec;
+ u32 rotator_binning;
u16 id;
u16 id_control;
u16 cdev_idx;
@@ -3355,6 +3410,7 @@ struct hl_device {
u8 supports_mmu_prefetch;
u8 reset_upon_device_release;
u8 supports_ctx_switch;
+ u8 support_preboot_binning;
/* Parameters for bring-up */
u64 nic_ports_mask;
@@ -3729,6 +3785,7 @@ int hl_fw_cpucp_power_get(struct hl_device *hdev, u64 *power);
void hl_fw_ask_hard_reset_without_linux(struct hl_device *hdev);
void hl_fw_ask_halt_machine_without_linux(struct hl_device *hdev);
int hl_fw_init_cpu(struct hl_device *hdev);
+int hl_fw_wait_preboot_ready(struct hl_device *hdev);
int hl_fw_read_preboot_status(struct hl_device *hdev);
int hl_fw_dynamic_send_protocol_cmd(struct hl_device *hdev,
struct fw_load_mgr *fw_loader,
@@ -3772,6 +3829,8 @@ int hl_fw_get_clk_rate(struct hl_device *hdev, u32 *cur_clk, u32 *max_clk);
void hl_fw_set_pll_profile(struct hl_device *hdev);
void hl_sysfs_add_dev_clk_attr(struct hl_device *hdev, struct attribute_group *dev_clk_attr_grp);
void hl_sysfs_add_dev_vrm_attr(struct hl_device *hdev, struct attribute_group *dev_vrm_attr_grp);
+int hl_fw_send_generic_request(struct hl_device *hdev, enum hl_passthrough_type sub_opcode,
+ dma_addr_t buff, u32 *size);
void hw_sob_get(struct hl_hw_sob *hw_sob);
void hw_sob_put(struct hl_hw_sob *hw_sob);
@@ -3786,6 +3845,7 @@ void hl_dec_fini(struct hl_device *hdev);
void hl_dec_ctx_fini(struct hl_ctx *ctx);
void hl_release_pending_user_interrupts(struct hl_device *hdev);
+void hl_abort_waitings_for_completion(struct hl_device *hdev);
int hl_cs_signal_sob_wraparound_handler(struct hl_device *hdev, u32 q_idx,
struct hl_hw_sob **hw_sob, u32 count, bool encaps_sig);
diff --git a/drivers/misc/habanalabs/common/habanalabs_drv.c b/drivers/accel/habanalabs/common/habanalabs_drv.c
index 7815c60df54e..03dae57dc838 100644
--- a/drivers/misc/habanalabs/common/habanalabs_drv.c
+++ b/drivers/accel/habanalabs/common/habanalabs_drv.c
@@ -222,9 +222,11 @@ int hl_device_open(struct inode *inode, struct file *filp)
hl_debugfs_add_file(hpriv);
atomic_set(&hdev->captured_err_info.cs_timeout.write_enable, 1);
- atomic_set(&hdev->captured_err_info.razwi_info_recorded, 0);
- atomic_set(&hdev->captured_err_info.pgf_info_recorded, 0);
+ atomic_set(&hdev->captured_err_info.razwi_info.razwi_detected, 0);
+ atomic_set(&hdev->captured_err_info.page_fault_info.page_fault_detected, 0);
hdev->captured_err_info.undef_opcode.write_enable = true;
+ hdev->captured_err_info.razwi_info.razwi_info_available = false;
+ hdev->captured_err_info.page_fault_info.page_fault_info_available = false;
hdev->open_counter++;
hdev->last_successful_open_jif = jiffies;
diff --git a/drivers/misc/habanalabs/common/habanalabs_ioctl.c b/drivers/accel/habanalabs/common/habanalabs_ioctl.c
index b6abfa7761a7..5005e6fca691 100644
--- a/drivers/misc/habanalabs/common/habanalabs_ioctl.c
+++ b/drivers/accel/habanalabs/common/habanalabs_ioctl.c
@@ -7,7 +7,7 @@
#define pr_fmt(fmt) "habanalabs: " fmt
-#include <uapi/misc/habanalabs.h>
+#include <uapi/drm/habanalabs_accel.h>
#include "habanalabs.h"
#include <linux/fs.h>
@@ -607,16 +607,20 @@ static int cs_timeout_info(struct hl_fpriv *hpriv, struct hl_info_args *args)
static int razwi_info(struct hl_fpriv *hpriv, struct hl_info_args *args)
{
+ void __user *out = (void __user *) (uintptr_t) args->return_pointer;
struct hl_device *hdev = hpriv->hdev;
u32 max_size = args->return_size;
- struct hl_info_razwi_event *info = &hdev->captured_err_info.razwi;
- void __user *out = (void __user *) (uintptr_t) args->return_pointer;
+ struct razwi_info *razwi_info;
if ((!max_size) || (!out))
return -EINVAL;
- return copy_to_user(out, info, min_t(size_t, max_size, sizeof(struct hl_info_razwi_event)))
- ? -EFAULT : 0;
+ razwi_info = &hdev->captured_err_info.razwi_info;
+ if (!razwi_info->razwi_info_available)
+ return 0;
+
+ return copy_to_user(out, &razwi_info->razwi,
+ min_t(size_t, max_size, sizeof(struct hl_info_razwi_event))) ? -EFAULT : 0;
}
static int undefined_opcode_info(struct hl_fpriv *hpriv, struct hl_info_args *args)
@@ -786,16 +790,20 @@ static int engine_status_info(struct hl_fpriv *hpriv, struct hl_info_args *args)
static int page_fault_info(struct hl_fpriv *hpriv, struct hl_info_args *args)
{
+ void __user *out = (void __user *) (uintptr_t) args->return_pointer;
struct hl_device *hdev = hpriv->hdev;
u32 max_size = args->return_size;
- struct hl_page_fault_info *info = &hdev->captured_err_info.pgf_info.pgf;
- void __user *out = (void __user *) (uintptr_t) args->return_pointer;
+ struct page_fault_info *pgf_info;
if ((!max_size) || (!out))
return -EINVAL;
- return copy_to_user(out, info, min_t(size_t, max_size, sizeof(struct hl_page_fault_info)))
- ? -EFAULT : 0;
+ pgf_info = &hdev->captured_err_info.page_fault_info;
+ if (!pgf_info->page_fault_info_available)
+ return 0;
+
+ return copy_to_user(out, &pgf_info->page_fault,
+ min_t(size_t, max_size, sizeof(struct hl_page_fault_info))) ? -EFAULT : 0;
}
static int user_mappings_info(struct hl_fpriv *hpriv, struct hl_info_args *args)
@@ -806,18 +814,68 @@ static int user_mappings_info(struct hl_fpriv *hpriv, struct hl_info_args *args)
struct page_fault_info *pgf_info;
u64 actual_size;
- pgf_info = &hdev->captured_err_info.pgf_info;
- args->array_size = pgf_info->num_of_user_mappings;
-
if (!out)
return -EINVAL;
+ pgf_info = &hdev->captured_err_info.page_fault_info;
+ if (!pgf_info->page_fault_info_available)
+ return 0;
+
+ args->array_size = pgf_info->num_of_user_mappings;
+
actual_size = pgf_info->num_of_user_mappings * sizeof(struct hl_user_mapping);
if (user_buf_size < actual_size)
return -ENOMEM;
- return copy_to_user(out, pgf_info->user_mappings, min_t(size_t, user_buf_size, actual_size))
- ? -EFAULT : 0;
+ return copy_to_user(out, pgf_info->user_mappings, actual_size) ? -EFAULT : 0;
+}
+
+static int send_fw_generic_request(struct hl_device *hdev, struct hl_info_args *info_args)
+{
+ void __user *buff = (void __user *) (uintptr_t) info_args->return_pointer;
+ u32 size = info_args->return_size;
+ dma_addr_t dma_handle;
+ bool need_input_buff;
+ void *fw_buff;
+ int rc = 0;
+
+ switch (info_args->fw_sub_opcode) {
+ case HL_PASSTHROUGH_VERSIONS:
+ need_input_buff = false;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (size > SZ_1M) {
+ dev_err(hdev->dev, "buffer size cannot exceed 1MB\n");
+ return -EINVAL;
+ }
+
+ fw_buff = hl_cpu_accessible_dma_pool_alloc(hdev, size, &dma_handle);
+ if (!fw_buff)
+ return -ENOMEM;
+
+
+ if (need_input_buff && copy_from_user(fw_buff, buff, size)) {
+ dev_dbg(hdev->dev, "Failed to copy from user FW buff\n");
+ rc = -EFAULT;
+ goto free_buff;
+ }
+
+ rc = hl_fw_send_generic_request(hdev, info_args->fw_sub_opcode, dma_handle, &size);
+ if (rc)
+ goto free_buff;
+
+ if (copy_to_user(buff, fw_buff, min(size, info_args->return_size))) {
+ dev_dbg(hdev->dev, "Failed to copy to user FW generic req output\n");
+ rc = -EFAULT;
+ }
+
+free_buff:
+ hl_cpu_accessible_dma_pool_free(hdev, info_args->return_size, fw_buff);
+
+ return rc;
}
static int _hl_info_ioctl(struct hl_fpriv *hpriv, void *data,
@@ -826,9 +884,13 @@ static int _hl_info_ioctl(struct hl_fpriv *hpriv, void *data,
enum hl_device_status status;
struct hl_info_args *args = data;
struct hl_device *hdev = hpriv->hdev;
-
int rc;
+ if (args->pad) {
+ dev_dbg(hdev->dev, "Padding bytes must be 0\n");
+ return -EINVAL;
+ }
+
/*
* Information is returned for the following opcodes even if the device
* is disabled or in reset.
@@ -893,7 +955,7 @@ static int _hl_info_ioctl(struct hl_fpriv *hpriv, void *data,
}
if (!hl_device_operational(hdev, &status)) {
- dev_warn_ratelimited(dev,
+ dev_dbg_ratelimited(dev,
"Device is %s. Can't execute INFO IOCTL\n",
hdev->status[status]);
return -EBUSY;
@@ -947,6 +1009,9 @@ static int _hl_info_ioctl(struct hl_fpriv *hpriv, void *data,
case HL_INFO_ENGINE_STATUS:
return engine_status_info(hpriv, args);
+ case HL_INFO_FW_GENERIC_REQ:
+ return send_fw_generic_request(hdev, args);
+
default:
dev_err(dev, "Invalid request %d\n", args->op);
rc = -EINVAL;
@@ -975,7 +1040,7 @@ static int hl_debug_ioctl(struct hl_fpriv *hpriv, void *data)
int rc = 0;
if (!hl_device_operational(hdev, &status)) {
- dev_warn_ratelimited(hdev->dev,
+ dev_dbg_ratelimited(hdev->dev,
"Device is %s. Can't execute DEBUG IOCTL\n",
hdev->status[status]);
return -EBUSY;
@@ -1072,8 +1137,6 @@ static long _hl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg,
retcode = -EFAULT;
goto out_err;
}
- } else if (cmd & IOC_OUT) {
- memset(kdata, 0, usize);
}
retcode = func(hpriv, kdata);
diff --git a/drivers/misc/habanalabs/common/hw_queue.c b/drivers/accel/habanalabs/common/hw_queue.c
index d0087c0ec48c..d0087c0ec48c 100644
--- a/drivers/misc/habanalabs/common/hw_queue.c
+++ b/drivers/accel/habanalabs/common/hw_queue.c
diff --git a/drivers/misc/habanalabs/common/hwmon.c b/drivers/accel/habanalabs/common/hwmon.c
index 55eb0203817f..55eb0203817f 100644
--- a/drivers/misc/habanalabs/common/hwmon.c
+++ b/drivers/accel/habanalabs/common/hwmon.c
diff --git a/drivers/misc/habanalabs/common/irq.c b/drivers/accel/habanalabs/common/irq.c
index 94d537fd4fde..04844e843a7b 100644
--- a/drivers/misc/habanalabs/common/irq.c
+++ b/drivers/accel/habanalabs/common/irq.c
@@ -72,15 +72,17 @@ static void irq_handle_eqe(struct work_struct *work)
* @hdev: pointer to device structure
* @cs_seq: command submission sequence
* @cq: completion queue
+ * @timestamp: interrupt timestamp
*
*/
-static void job_finish(struct hl_device *hdev, u32 cs_seq, struct hl_cq *cq)
+static void job_finish(struct hl_device *hdev, u32 cs_seq, struct hl_cq *cq, ktime_t timestamp)
{
struct hl_hw_queue *queue;
struct hl_cs_job *job;
queue = &hdev->kernel_queues[cq->hw_queue_id];
job = queue->shadow_queue[hl_pi_2_offset(cs_seq)];
+ job->timestamp = timestamp;
queue_work(hdev->cq_wq[cq->cq_idx], &job->finish_work);
atomic_inc(&queue->ci);
@@ -91,9 +93,10 @@ static void job_finish(struct hl_device *hdev, u32 cs_seq, struct hl_cq *cq)
*
* @hdev: pointer to device structure
* @cs_seq: command submission sequence
+ * @timestamp: interrupt timestamp
*
*/
-static void cs_finish(struct hl_device *hdev, u16 cs_seq)
+static void cs_finish(struct hl_device *hdev, u16 cs_seq, ktime_t timestamp)
{
struct asic_fixed_properties *prop = &hdev->asic_prop;
struct hl_hw_queue *queue;
@@ -113,6 +116,7 @@ static void cs_finish(struct hl_device *hdev, u16 cs_seq)
atomic_inc(&queue->ci);
}
+ cs->completion_timestamp = timestamp;
queue_work(hdev->cs_cmplt_wq, &cs->finish_work);
}
@@ -130,6 +134,7 @@ irqreturn_t hl_irq_handler_cq(int irq, void *arg)
bool shadow_index_valid, entry_ready;
u16 shadow_index;
struct hl_cq_entry *cq_entry, *cq_base;
+ ktime_t timestamp = ktime_get();
if (hdev->disabled) {
dev_dbg(hdev->dev,
@@ -171,9 +176,9 @@ irqreturn_t hl_irq_handler_cq(int irq, void *arg)
if (shadow_index_valid && !hdev->disabled) {
if (hdev->asic_prop.completion_mode ==
HL_COMPLETION_MODE_CS)
- cs_finish(hdev, shadow_index);
+ cs_finish(hdev, shadow_index, timestamp);
else
- job_finish(hdev, shadow_index, cq);
+ job_finish(hdev, shadow_index, cq, timestamp);
}
/* Clear CQ entry ready bit */
@@ -228,7 +233,7 @@ static void hl_ts_free_objects(struct work_struct *work)
* list to a dedicated workqueue to do the actual put.
*/
static int handle_registration_node(struct hl_device *hdev, struct hl_user_pending_interrupt *pend,
- struct list_head **free_list)
+ struct list_head **free_list, ktime_t now)
{
struct timestamp_reg_free_node *free_node;
u64 timestamp;
@@ -246,7 +251,7 @@ static int handle_registration_node(struct hl_device *hdev, struct hl_user_pendi
if (!free_node)
return -ENOMEM;
- timestamp = ktime_get_ns();
+ timestamp = ktime_to_ns(now);
*pend->ts_reg_info.timestamp_kernel_addr = timestamp;
@@ -298,7 +303,7 @@ static void handle_user_interrupt(struct hl_device *hdev, struct hl_user_interru
if (pend->ts_reg_info.buf) {
if (!reg_node_handle_fail) {
rc = handle_registration_node(hdev, pend,
- &ts_reg_free_list_head);
+ &ts_reg_free_list_head, now);
if (rc)
reg_node_handle_fail = true;
}
@@ -333,13 +338,22 @@ irqreturn_t hl_irq_handler_user_interrupt(int irq, void *arg)
struct hl_user_interrupt *user_int = arg;
struct hl_device *hdev = user_int->hdev;
- if (user_int->is_decoder)
- handle_user_interrupt(hdev, &hdev->common_decoder_interrupt);
- else
+ switch (user_int->type) {
+ case HL_USR_INTERRUPT_CQ:
handle_user_interrupt(hdev, &hdev->common_user_cq_interrupt);
- /* Handle user cq or decoder interrupts registered on this specific irq */
- handle_user_interrupt(hdev, user_int);
+ /* Handle user cq interrupt registered on this specific irq */
+ handle_user_interrupt(hdev, user_int);
+ break;
+ case HL_USR_INTERRUPT_DECODER:
+ handle_user_interrupt(hdev, &hdev->common_decoder_interrupt);
+
+ /* Handle decoder interrupt registered on this specific irq */
+ handle_user_interrupt(hdev, user_int);
+ break;
+ default:
+ break;
+ }
return IRQ_HANDLED;
}
diff --git a/drivers/misc/habanalabs/common/memory.c b/drivers/accel/habanalabs/common/memory.c
index 5e9ae7600d75..761a47e89b00 100644
--- a/drivers/misc/habanalabs/common/memory.c
+++ b/drivers/accel/habanalabs/common/memory.c
@@ -5,7 +5,7 @@
* All Rights Reserved.
*/
-#include <uapi/misc/habanalabs.h>
+#include <uapi/drm/habanalabs_accel.h>
#include "habanalabs.h"
#include "../include/hw_ip/mmu/mmu_general.h"
@@ -19,7 +19,9 @@ MODULE_IMPORT_NS(DMA_BUF);
#define HL_MMU_DEBUG 0
/* use small pages for supporting non-pow2 (32M/40M/48M) DRAM phys page sizes */
-#define DRAM_POOL_PAGE_SIZE SZ_8M
+#define DRAM_POOL_PAGE_SIZE SZ_8M
+
+#define MEM_HANDLE_INVALID ULONG_MAX
static int allocate_timestamps_buffers(struct hl_fpriv *hpriv,
struct hl_mem_in *args, u64 *handle);
@@ -371,12 +373,6 @@ static int free_device_memory(struct hl_ctx *ctx, struct hl_mem_in *args)
return -EINVAL;
}
- if (phys_pg_pack->exporting_cnt) {
- spin_unlock(&vm->idr_lock);
- dev_dbg(hdev->dev, "handle %u is exported, cannot free\n", handle);
- return -EINVAL;
- }
-
/* must remove from idr before the freeing of the physical pages as the refcount of the pool
* is also the trigger of the idr destroy
*/
@@ -1240,6 +1236,7 @@ static int map_device_va(struct hl_ctx *ctx, struct hl_mem_in *args, u64 *device
hnode->ptr = vm_type;
hnode->vaddr = ret_vaddr;
+ hnode->handle = is_userptr ? MEM_HANDLE_INVALID : handle;
mutex_lock(&ctx->mem_hash_lock);
hash_add(ctx->mem_hash, &hnode->node, ret_vaddr);
@@ -1313,6 +1310,12 @@ static int unmap_device_va(struct hl_ctx *ctx, struct hl_mem_in *args,
return -EINVAL;
}
+ if (hnode->export_cnt) {
+ mutex_unlock(&ctx->mem_hash_lock);
+ dev_err(hdev->dev, "failed to unmap %#llx, memory is exported\n", vaddr);
+ return -EINVAL;
+ }
+
hash_del(&hnode->node);
mutex_unlock(&ctx->mem_hash_lock);
@@ -1545,10 +1548,10 @@ static int set_dma_sg(struct scatterlist *sg, u64 bar_address, u64 chunk_size,
}
static struct sg_table *alloc_sgt_from_device_pages(struct hl_device *hdev, u64 *pages, u64 npages,
- u64 page_size, struct device *dev,
- enum dma_data_direction dir)
+ u64 page_size, u64 exported_size,
+ struct device *dev, enum dma_data_direction dir)
{
- u64 chunk_size, bar_address, dma_max_seg_size;
+ u64 chunk_size, bar_address, dma_max_seg_size, cur_size_to_export, cur_npages;
struct asic_fixed_properties *prop;
int rc, i, j, nents, cur_page;
struct scatterlist *sg;
@@ -1574,16 +1577,23 @@ static struct sg_table *alloc_sgt_from_device_pages(struct hl_device *hdev, u64
if (!sgt)
return ERR_PTR(-ENOMEM);
+ /* remove export size restrictions in case not explicitly defined */
+ cur_size_to_export = exported_size ? exported_size : (npages * page_size);
+
/* If the size of each page is larger than the dma max segment size,
* then we can't combine pages and the number of entries in the SGL
* will just be the
* <number of pages> * <chunks of max segment size in each page>
*/
- if (page_size > dma_max_seg_size)
- nents = npages * DIV_ROUND_UP_ULL(page_size, dma_max_seg_size);
- else
+ if (page_size > dma_max_seg_size) {
+ /* we should limit number of pages according to the exported size */
+ cur_npages = DIV_ROUND_UP_SECTOR_T(cur_size_to_export, page_size);
+ nents = cur_npages * DIV_ROUND_UP_SECTOR_T(page_size, dma_max_seg_size);
+ } else {
+ cur_npages = npages;
+
/* Get number of non-contiguous chunks */
- for (i = 1, nents = 1, chunk_size = page_size ; i < npages ; i++) {
+ for (i = 1, nents = 1, chunk_size = page_size ; i < cur_npages ; i++) {
if (pages[i - 1] + page_size != pages[i] ||
chunk_size + page_size > dma_max_seg_size) {
nents++;
@@ -1593,6 +1603,7 @@ static struct sg_table *alloc_sgt_from_device_pages(struct hl_device *hdev, u64
chunk_size += page_size;
}
+ }
rc = sg_alloc_table(sgt, nents, GFP_KERNEL | __GFP_ZERO);
if (rc)
@@ -1615,7 +1626,8 @@ static struct sg_table *alloc_sgt_from_device_pages(struct hl_device *hdev, u64
else
cur_device_address += dma_max_seg_size;
- chunk_size = min(size_left, dma_max_seg_size);
+ /* make sure not to export over exported size */
+ chunk_size = min3(size_left, dma_max_seg_size, cur_size_to_export);
bar_address = hdev->dram_pci_bar_start + cur_device_address;
@@ -1623,6 +1635,8 @@ static struct sg_table *alloc_sgt_from_device_pages(struct hl_device *hdev, u64
if (rc)
goto error_unmap;
+ cur_size_to_export -= chunk_size;
+
if (size_left > dma_max_seg_size) {
size_left -= dma_max_seg_size;
} else {
@@ -1634,7 +1648,7 @@ static struct sg_table *alloc_sgt_from_device_pages(struct hl_device *hdev, u64
/* Merge pages and put them into the scatterlist */
for_each_sgtable_dma_sg(sgt, sg, i) {
chunk_size = page_size;
- for (j = cur_page + 1 ; j < npages ; j++) {
+ for (j = cur_page + 1 ; j < cur_npages ; j++) {
if (pages[j - 1] + page_size != pages[j] ||
chunk_size + page_size > dma_max_seg_size)
break;
@@ -1645,10 +1659,13 @@ static struct sg_table *alloc_sgt_from_device_pages(struct hl_device *hdev, u64
bar_address = hdev->dram_pci_bar_start +
(pages[cur_page] - prop->dram_base_address);
+ /* make sure not to export over exported size */
+ chunk_size = min(chunk_size, cur_size_to_export);
rc = set_dma_sg(sg, bar_address, chunk_size, dev, dir);
if (rc)
goto error_unmap;
+ cur_size_to_export -= chunk_size;
cur_page = j;
}
}
@@ -1719,6 +1736,7 @@ static struct sg_table *hl_map_dmabuf(struct dma_buf_attachment *attachment,
phys_pg_pack->pages,
phys_pg_pack->npages,
phys_pg_pack->page_size,
+ phys_pg_pack->exported_size,
attachment->dev,
dir);
else
@@ -1726,6 +1744,7 @@ static struct sg_table *hl_map_dmabuf(struct dma_buf_attachment *attachment,
&hl_dmabuf->device_address,
1,
hl_dmabuf->dmabuf->size,
+ 0,
attachment->dev,
dir);
@@ -1763,18 +1782,20 @@ static void hl_unmap_dmabuf(struct dma_buf_attachment *attachment,
static void hl_release_dmabuf(struct dma_buf *dmabuf)
{
struct hl_dmabuf_priv *hl_dmabuf = dmabuf->priv;
- struct hl_ctx *ctx = hl_dmabuf->ctx;
- struct hl_device *hdev = ctx->hdev;
- struct hl_vm *vm = &hdev->vm;
+ struct hl_ctx *ctx;
- if (hl_dmabuf->phys_pg_pack) {
- spin_lock(&vm->idr_lock);
- hl_dmabuf->phys_pg_pack->exporting_cnt--;
- spin_unlock(&vm->idr_lock);
- }
+ if (!hl_dmabuf)
+ return;
- hl_ctx_put(hl_dmabuf->ctx);
+ ctx = hl_dmabuf->ctx;
+ if (hl_dmabuf->memhash_hnode) {
+ mutex_lock(&ctx->mem_hash_lock);
+ hl_dmabuf->memhash_hnode->export_cnt--;
+ mutex_unlock(&ctx->mem_hash_lock);
+ }
+
+ hl_ctx_put(ctx);
kfree(hl_dmabuf);
}
@@ -1785,7 +1806,7 @@ static const struct dma_buf_ops habanalabs_dmabuf_ops = {
.release = hl_release_dmabuf,
};
-static int export_dmabuf_common(struct hl_ctx *ctx,
+static int export_dmabuf(struct hl_ctx *ctx,
struct hl_dmabuf_priv *hl_dmabuf,
u64 total_size, int flags, int *dmabuf_fd)
{
@@ -1806,7 +1827,7 @@ static int export_dmabuf_common(struct hl_ctx *ctx,
fd = dma_buf_fd(hl_dmabuf->dmabuf, flags);
if (fd < 0) {
- dev_err(hdev->dev, "failed to get a file descriptor for a dma-buf\n");
+ dev_err(hdev->dev, "failed to get a file descriptor for a dma-buf, %d\n", fd);
rc = fd;
goto err_dma_buf_put;
}
@@ -1819,36 +1840,13 @@ static int export_dmabuf_common(struct hl_ctx *ctx,
return 0;
err_dma_buf_put:
+ hl_dmabuf->dmabuf->priv = NULL;
dma_buf_put(hl_dmabuf->dmabuf);
return rc;
}
-/**
- * export_dmabuf_from_addr() - export a dma-buf object for the given memory
- * address and size.
- * @ctx: pointer to the context structure.
- * @device_addr: device memory physical address.
- * @size: size of device memory.
- * @flags: DMA-BUF file/FD flags.
- * @dmabuf_fd: pointer to result FD that represents the dma-buf object.
- *
- * Create and export a dma-buf object for an existing memory allocation inside
- * the device memory, and return a FD which is associated with the dma-buf
- * object.
- *
- * Return: 0 on success, non-zero for failure.
- */
-static int export_dmabuf_from_addr(struct hl_ctx *ctx, u64 device_addr,
- u64 size, int flags, int *dmabuf_fd)
+static int validate_export_params_common(struct hl_device *hdev, u64 device_addr, u64 size)
{
- struct hl_dmabuf_priv *hl_dmabuf;
- struct hl_device *hdev = ctx->hdev;
- struct asic_fixed_properties *prop;
- u64 bar_address;
- int rc;
-
- prop = &hdev->asic_prop;
-
if (!IS_ALIGNED(device_addr, PAGE_SIZE)) {
dev_dbg(hdev->dev,
"exported device memory address 0x%llx should be aligned to 0x%lx\n",
@@ -1863,49 +1861,150 @@ static int export_dmabuf_from_addr(struct hl_ctx *ctx, u64 device_addr,
return -EINVAL;
}
+ return 0;
+}
+
+static int validate_export_params_no_mmu(struct hl_device *hdev, u64 device_addr, u64 size)
+{
+ struct asic_fixed_properties *prop = &hdev->asic_prop;
+ u64 bar_address;
+ int rc;
+
+ rc = validate_export_params_common(hdev, device_addr, size);
+ if (rc)
+ return rc;
+
if (device_addr < prop->dram_user_base_address ||
- device_addr + size > prop->dram_end_address ||
- device_addr + size < device_addr) {
+ (device_addr + size) > prop->dram_end_address ||
+ (device_addr + size) < device_addr) {
dev_dbg(hdev->dev,
"DRAM memory range 0x%llx (+0x%llx) is outside of DRAM boundaries\n",
device_addr, size);
return -EINVAL;
}
- bar_address = hdev->dram_pci_bar_start +
- (device_addr - prop->dram_base_address);
+ bar_address = hdev->dram_pci_bar_start + (device_addr - prop->dram_base_address);
- if (bar_address + size >
- hdev->dram_pci_bar_start + prop->dram_pci_bar_size ||
- bar_address + size < bar_address) {
+ if ((bar_address + size) > (hdev->dram_pci_bar_start + prop->dram_pci_bar_size) ||
+ (bar_address + size) < bar_address) {
dev_dbg(hdev->dev,
"DRAM memory range 0x%llx (+0x%llx) is outside of PCI BAR boundaries\n",
device_addr, size);
return -EINVAL;
}
- hl_dmabuf = kzalloc(sizeof(*hl_dmabuf), GFP_KERNEL);
- if (!hl_dmabuf)
- return -ENOMEM;
+ return 0;
+}
- hl_dmabuf->device_address = device_addr;
+static int validate_export_params(struct hl_device *hdev, u64 device_addr, u64 size, u64 offset,
+ struct hl_vm_phys_pg_pack *phys_pg_pack)
+{
+ struct asic_fixed_properties *prop = &hdev->asic_prop;
+ u64 bar_address;
+ int i, rc;
- rc = export_dmabuf_common(ctx, hl_dmabuf, size, flags, dmabuf_fd);
+ rc = validate_export_params_common(hdev, device_addr, size);
if (rc)
- goto err_free_dmabuf_wrapper;
+ return rc;
+
+ if ((offset + size) > phys_pg_pack->total_size) {
+ dev_dbg(hdev->dev, "offset %#llx and size %#llx exceed total map size %#llx\n",
+ offset, size, phys_pg_pack->total_size);
+ return -EINVAL;
+ }
+
+ for (i = 0 ; i < phys_pg_pack->npages ; i++) {
+
+ bar_address = hdev->dram_pci_bar_start +
+ (phys_pg_pack->pages[i] - prop->dram_base_address);
+
+ if ((bar_address + phys_pg_pack->page_size) >
+ (hdev->dram_pci_bar_start + prop->dram_pci_bar_size) ||
+ (bar_address + phys_pg_pack->page_size) < bar_address) {
+ dev_dbg(hdev->dev,
+ "DRAM memory range 0x%llx (+0x%x) is outside of PCI BAR boundaries\n",
+ phys_pg_pack->pages[i],
+ phys_pg_pack->page_size);
+
+ return -EINVAL;
+ }
+ }
return 0;
+}
-err_free_dmabuf_wrapper:
- kfree(hl_dmabuf);
- return rc;
+static struct hl_vm_hash_node *memhash_node_export_get(struct hl_ctx *ctx, u64 addr)
+{
+ struct hl_device *hdev = ctx->hdev;
+ struct hl_vm_hash_node *hnode;
+
+ /* get the memory handle */
+ mutex_lock(&ctx->mem_hash_lock);
+ hash_for_each_possible(ctx->mem_hash, hnode, node, (unsigned long)addr)
+ if (addr == hnode->vaddr)
+ break;
+
+ if (!hnode) {
+ mutex_unlock(&ctx->mem_hash_lock);
+ dev_dbg(hdev->dev, "map address %#llx not found\n", addr);
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (upper_32_bits(hnode->handle)) {
+ mutex_unlock(&ctx->mem_hash_lock);
+ dev_dbg(hdev->dev, "invalid handle %#llx for map address %#llx\n",
+ hnode->handle, addr);
+ return ERR_PTR(-EINVAL);
+ }
+
+ /*
+ * node found, increase export count so this memory cannot be unmapped
+ * and the hash node cannot be deleted.
+ */
+ hnode->export_cnt++;
+ mutex_unlock(&ctx->mem_hash_lock);
+
+ return hnode;
+}
+
+static void memhash_node_export_put(struct hl_ctx *ctx, struct hl_vm_hash_node *hnode)
+{
+ mutex_lock(&ctx->mem_hash_lock);
+ hnode->export_cnt--;
+ mutex_unlock(&ctx->mem_hash_lock);
+}
+
+static struct hl_vm_phys_pg_pack *get_phys_pg_pack_from_hash_node(struct hl_device *hdev,
+ struct hl_vm_hash_node *hnode)
+{
+ struct hl_vm_phys_pg_pack *phys_pg_pack;
+ struct hl_vm *vm = &hdev->vm;
+
+ spin_lock(&vm->idr_lock);
+ phys_pg_pack = idr_find(&vm->phys_pg_pack_handles, (u32) hnode->handle);
+ if (!phys_pg_pack) {
+ spin_unlock(&vm->idr_lock);
+ dev_dbg(hdev->dev, "no match for handle 0x%x\n", (u32) hnode->handle);
+ return ERR_PTR(-EINVAL);
+ }
+
+ spin_unlock(&vm->idr_lock);
+
+ if (phys_pg_pack->vm_type != VM_TYPE_PHYS_PACK) {
+ dev_dbg(hdev->dev, "handle 0x%llx does not represent DRAM memory\n", hnode->handle);
+ return ERR_PTR(-EINVAL);
+ }
+
+ return phys_pg_pack;
}
/**
- * export_dmabuf_from_handle() - export a dma-buf object for the given memory
- * handle.
+ * export_dmabuf_from_addr() - export a dma-buf object for the given memory
+ * address and size.
* @ctx: pointer to the context structure.
- * @handle: device memory allocation handle.
+ * @addr: device address.
+ * @size: size of device memory to export.
+ * @offset: the offset into the buffer from which to start exporting
* @flags: DMA-BUF file/FD flags.
* @dmabuf_fd: pointer to result FD that represents the dma-buf object.
*
@@ -1915,87 +2014,69 @@ err_free_dmabuf_wrapper:
*
* Return: 0 on success, non-zero for failure.
*/
-static int export_dmabuf_from_handle(struct hl_ctx *ctx, u64 handle, int flags,
- int *dmabuf_fd)
+static int export_dmabuf_from_addr(struct hl_ctx *ctx, u64 addr, u64 size, u64 offset,
+ int flags, int *dmabuf_fd)
{
- struct hl_vm_phys_pg_pack *phys_pg_pack;
- struct hl_dmabuf_priv *hl_dmabuf;
- struct hl_device *hdev = ctx->hdev;
+ struct hl_vm_phys_pg_pack *phys_pg_pack = NULL;
+ struct hl_vm_hash_node *hnode = NULL;
struct asic_fixed_properties *prop;
- struct hl_vm *vm = &hdev->vm;
- u64 bar_address;
- int rc, i;
+ struct hl_dmabuf_priv *hl_dmabuf;
+ struct hl_device *hdev;
+ u64 export_addr;
+ int rc;
+ hdev = ctx->hdev;
prop = &hdev->asic_prop;
- if (upper_32_bits(handle)) {
- dev_dbg(hdev->dev, "no match for handle 0x%llx\n", handle);
+ /* offset must be 0 in devices without virtual memory support */
+ if (!prop->dram_supports_virtual_memory && offset) {
+ dev_dbg(hdev->dev, "offset is not allowed in device without virtual memory\n");
return -EINVAL;
}
- spin_lock(&vm->idr_lock);
+ export_addr = addr + offset;
- phys_pg_pack = idr_find(&vm->phys_pg_pack_handles, (u32) handle);
- if (!phys_pg_pack) {
- spin_unlock(&vm->idr_lock);
- dev_dbg(hdev->dev, "no match for handle 0x%x\n", (u32) handle);
- return -EINVAL;
- }
-
- /* increment now to avoid freeing device memory while exporting */
- phys_pg_pack->exporting_cnt++;
-
- spin_unlock(&vm->idr_lock);
-
- if (phys_pg_pack->vm_type != VM_TYPE_PHYS_PACK) {
- dev_dbg(hdev->dev, "handle 0x%llx does not represent DRAM memory\n", handle);
- rc = -EINVAL;
- goto err_dec_exporting_cnt;
- }
-
- for (i = 0 ; i < phys_pg_pack->npages ; i++) {
-
- bar_address = hdev->dram_pci_bar_start +
- (phys_pg_pack->pages[i] -
- prop->dram_base_address);
-
- if (bar_address + phys_pg_pack->page_size >
- hdev->dram_pci_bar_start + prop->dram_pci_bar_size ||
- bar_address + phys_pg_pack->page_size < bar_address) {
-
- dev_dbg(hdev->dev,
- "DRAM memory range 0x%llx (+0x%x) is outside of PCI BAR boundaries\n",
- phys_pg_pack->pages[i],
- phys_pg_pack->page_size);
+ hl_dmabuf = kzalloc(sizeof(*hl_dmabuf), GFP_KERNEL);
+ if (!hl_dmabuf)
+ return -ENOMEM;
- rc = -EINVAL;
- goto err_dec_exporting_cnt;
+ if (prop->dram_supports_virtual_memory) {
+ hnode = memhash_node_export_get(ctx, addr);
+ if (IS_ERR(hnode)) {
+ rc = PTR_ERR(hnode);
+ goto err_free_dmabuf_wrapper;
}
- }
+ phys_pg_pack = get_phys_pg_pack_from_hash_node(hdev, hnode);
+ if (IS_ERR(phys_pg_pack)) {
+ rc = PTR_ERR(phys_pg_pack);
+ goto dec_memhash_export_cnt;
+ }
+ rc = validate_export_params(hdev, export_addr, size, offset, phys_pg_pack);
+ if (rc)
+ goto dec_memhash_export_cnt;
- hl_dmabuf = kzalloc(sizeof(*hl_dmabuf), GFP_KERNEL);
- if (!hl_dmabuf) {
- rc = -ENOMEM;
- goto err_dec_exporting_cnt;
+ phys_pg_pack->exported_size = size;
+ hl_dmabuf->phys_pg_pack = phys_pg_pack;
+ hl_dmabuf->memhash_hnode = hnode;
+ } else {
+ rc = validate_export_params_no_mmu(hdev, export_addr, size);
+ if (rc)
+ goto err_free_dmabuf_wrapper;
}
- hl_dmabuf->phys_pg_pack = phys_pg_pack;
+ hl_dmabuf->device_address = export_addr;
- rc = export_dmabuf_common(ctx, hl_dmabuf, phys_pg_pack->total_size,
- flags, dmabuf_fd);
+ rc = export_dmabuf(ctx, hl_dmabuf, size, flags, dmabuf_fd);
if (rc)
- goto err_free_dmabuf_wrapper;
+ goto dec_memhash_export_cnt;
return 0;
+dec_memhash_export_cnt:
+ if (prop->dram_supports_virtual_memory)
+ memhash_node_export_put(ctx, hnode);
err_free_dmabuf_wrapper:
kfree(hl_dmabuf);
-
-err_dec_exporting_cnt:
- spin_lock(&vm->idr_lock);
- phys_pg_pack->exporting_cnt--;
- spin_unlock(&vm->idr_lock);
-
return rc;
}
@@ -2082,19 +2163,20 @@ static int hl_ts_mmap(struct hl_mmap_mem_buf *buf, struct vm_area_struct *vma, v
{
struct hl_ts_buff *ts_buff = buf->private;
- vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP | VM_DONTCOPY | VM_NORESERVE;
+ vm_flags_set(vma, VM_DONTEXPAND | VM_DONTDUMP | VM_DONTCOPY | VM_NORESERVE);
return remap_vmalloc_range(vma, ts_buff->user_buff_address, 0);
}
static int hl_ts_alloc_buf(struct hl_mmap_mem_buf *buf, gfp_t gfp, void *args)
{
struct hl_ts_buff *ts_buff = NULL;
- u32 size, num_elements;
+ u32 num_elements;
+ size_t size;
void *p;
num_elements = *(u32 *)args;
- ts_buff = kzalloc(sizeof(*ts_buff), GFP_KERNEL);
+ ts_buff = kzalloc(sizeof(*ts_buff), gfp);
if (!ts_buff)
return -ENOMEM;
@@ -2180,7 +2262,7 @@ int hl_mem_ioctl(struct hl_fpriv *hpriv, void *data)
int rc, dmabuf_fd = -EBADF;
if (!hl_device_operational(hdev, &status)) {
- dev_warn_ratelimited(hdev->dev,
+ dev_dbg_ratelimited(hdev->dev,
"Device is %s. Can't execute MEMORY IOCTL\n",
hdev->status[status]);
return -EBUSY;
@@ -2269,17 +2351,12 @@ int hl_mem_ioctl(struct hl_fpriv *hpriv, void *data)
break;
case HL_MEM_OP_EXPORT_DMABUF_FD:
- if (hdev->asic_prop.dram_supports_virtual_memory)
- rc = export_dmabuf_from_handle(ctx,
- args->in.export_dmabuf_fd.handle,
- args->in.flags,
- &dmabuf_fd);
- else
- rc = export_dmabuf_from_addr(ctx,
- args->in.export_dmabuf_fd.handle,
- args->in.export_dmabuf_fd.mem_size,
- args->in.flags,
- &dmabuf_fd);
+ rc = export_dmabuf_from_addr(ctx,
+ args->in.export_dmabuf_fd.addr,
+ args->in.export_dmabuf_fd.mem_size,
+ args->in.export_dmabuf_fd.offset,
+ args->in.flags,
+ &dmabuf_fd);
memset(args, 0, sizeof(*args));
args->out.fd = dmabuf_fd;
break;
diff --git a/drivers/misc/habanalabs/common/memory_mgr.c b/drivers/accel/habanalabs/common/memory_mgr.c
index 1936d653699e..0f2759e26547 100644
--- a/drivers/misc/habanalabs/common/memory_mgr.c
+++ b/drivers/accel/habanalabs/common/memory_mgr.c
@@ -25,8 +25,7 @@ struct hl_mmap_mem_buf *hl_mmap_mem_buf_get(struct hl_mem_mgr *mmg, u64 handle)
buf = idr_find(&mmg->handles, lower_32_bits(handle >> PAGE_SHIFT));
if (!buf) {
spin_unlock(&mmg->lock);
- dev_warn(mmg->dev,
- "Buff get failed, no match to handle %#llx\n", handle);
+ dev_dbg(mmg->dev, "Buff get failed, no match to handle %#llx\n", handle);
return NULL;
}
kref_get(&buf->refcount);
diff --git a/drivers/misc/habanalabs/common/mmu/Makefile b/drivers/accel/habanalabs/common/mmu/Makefile
index 1806c524e04a..1806c524e04a 100644
--- a/drivers/misc/habanalabs/common/mmu/Makefile
+++ b/drivers/accel/habanalabs/common/mmu/Makefile
diff --git a/drivers/misc/habanalabs/common/mmu/mmu.c b/drivers/accel/habanalabs/common/mmu/mmu.c
index 2c1005f74cf4..a42ae8bc61e8 100644
--- a/drivers/misc/habanalabs/common/mmu/mmu.c
+++ b/drivers/accel/habanalabs/common/mmu/mmu.c
@@ -781,7 +781,7 @@ static void mmu_dma_mem_free_from_chunk(struct gen_pool *pool,
struct gen_pool_chunk *chunk,
void *data)
{
- struct hl_device *hdev = (struct hl_device *)data;
+ struct hl_device *hdev = data;
hl_asic_dma_free_coherent(hdev, (chunk->end_addr - chunk->start_addr) + 1,
(void *)chunk->start_addr, chunk->phys_addr);
diff --git a/drivers/misc/habanalabs/common/mmu/mmu_v1.c b/drivers/accel/habanalabs/common/mmu/mmu_v1.c
index 8a40de4a4761..d925dc4dd097 100644
--- a/drivers/misc/habanalabs/common/mmu/mmu_v1.c
+++ b/drivers/accel/habanalabs/common/mmu/mmu_v1.c
@@ -345,7 +345,6 @@ static void dram_default_mapping_fini(struct hl_ctx *ctx)
}
hop2_pte_addr = hop2_addr;
- hop2_pte_addr = hop2_addr;
for (i = 0 ; i < num_of_hop3 ; i++) {
clear_pte(ctx, hop2_pte_addr);
put_pte(ctx, hop2_addr);
diff --git a/drivers/misc/habanalabs/common/mmu/mmu_v2_hr.c b/drivers/accel/habanalabs/common/mmu/mmu_v2_hr.c
index afe7ef964f82..afe7ef964f82 100644
--- a/drivers/misc/habanalabs/common/mmu/mmu_v2_hr.c
+++ b/drivers/accel/habanalabs/common/mmu/mmu_v2_hr.c
diff --git a/drivers/misc/habanalabs/common/pci/Makefile b/drivers/accel/habanalabs/common/pci/Makefile
index dc922a686683..dc922a686683 100644
--- a/drivers/misc/habanalabs/common/pci/Makefile
+++ b/drivers/accel/habanalabs/common/pci/Makefile
diff --git a/drivers/misc/habanalabs/common/pci/pci.c b/drivers/accel/habanalabs/common/pci/pci.c
index 5fe3da5fba30..d1f4c695baf2 100644
--- a/drivers/misc/habanalabs/common/pci/pci.c
+++ b/drivers/accel/habanalabs/common/pci/pci.c
@@ -10,6 +10,8 @@
#include <linux/pci.h>
+#include <trace/events/habanalabs.h>
+
#define HL_PLDM_PCI_ELBI_TIMEOUT_MSEC (HL_PCI_ELBI_TIMEOUT_MSEC * 100)
#define IATU_REGION_CTRL_REGION_EN_MASK BIT(31)
@@ -120,6 +122,9 @@ int hl_pci_elbi_read(struct hl_device *hdev, u64 addr, u32 *data)
if ((val & PCI_CONFIG_ELBI_STS_MASK) == PCI_CONFIG_ELBI_STS_DONE) {
pci_read_config_dword(pdev, mmPCI_CONFIG_ELBI_DATA, data);
+ if (unlikely(trace_habanalabs_elbi_read_enabled()))
+ trace_habanalabs_elbi_read(hdev->dev, (u32) addr, val);
+
return 0;
}
@@ -179,8 +184,11 @@ static int hl_pci_elbi_write(struct hl_device *hdev, u64 addr, u32 data)
usleep_range(300, 500);
}
- if ((val & PCI_CONFIG_ELBI_STS_MASK) == PCI_CONFIG_ELBI_STS_DONE)
+ if ((val & PCI_CONFIG_ELBI_STS_MASK) == PCI_CONFIG_ELBI_STS_DONE) {
+ if (unlikely(trace_habanalabs_elbi_write_enabled()))
+ trace_habanalabs_elbi_write(hdev->dev, (u32) addr, val);
return 0;
+ }
if (val & PCI_CONFIG_ELBI_STS_ERR)
return -EIO;
diff --git a/drivers/misc/habanalabs/common/security.c b/drivers/accel/habanalabs/common/security.c
index 6196c0487c8b..5f03ade07ead 100644
--- a/drivers/misc/habanalabs/common/security.c
+++ b/drivers/accel/habanalabs/common/security.c
@@ -7,6 +7,19 @@
#include "habanalabs.h"
+static const char * const hl_glbl_error_cause[HL_MAX_NUM_OF_GLBL_ERR_CAUSE] = {
+ "Error due to un-priv read",
+ "Error due to un-secure read",
+ "Error due to read from unmapped reg",
+ "Error due to un-priv write",
+ "Error due to un-secure write",
+ "Error due to write to unmapped reg",
+ "External I/F write sec violation",
+ "External I/F write to un-mapped reg",
+ "Read to write only",
+ "Write to read only"
+};
+
/**
* hl_get_pb_block - return the relevant block within the block array
*
@@ -598,3 +611,164 @@ void hl_ack_pb_single_dcore(struct hl_device *hdev, u32 dcore_offset,
blocks_array_size);
}
+
+static u32 hl_automated_get_block_base_addr(struct hl_device *hdev,
+ struct hl_special_block_info *block_info,
+ u32 major, u32 minor, u32 sub_minor)
+{
+ u32 fw_block_base_address = block_info->base_addr +
+ major * block_info->major_offset +
+ minor * block_info->minor_offset +
+ sub_minor * block_info->sub_minor_offset;
+ struct asic_fixed_properties *prop = &hdev->asic_prop;
+
+ /* Calculation above returns an address for FW use, and therefore should
+ * be casted for driver use.
+ */
+ return (fw_block_base_address - lower_32_bits(prop->cfg_base_address));
+}
+
+static bool hl_check_block_type_exclusion(struct hl_skip_blocks_cfg *skip_blocks_cfg,
+ int block_type)
+{
+ int i;
+
+ /* Check if block type is listed in the exclusion list of block types */
+ for (i = 0 ; i < skip_blocks_cfg->block_types_len ; i++)
+ if (block_type == skip_blocks_cfg->block_types[i])
+ return true;
+
+ return false;
+}
+
+static bool hl_check_block_range_exclusion(struct hl_device *hdev,
+ struct hl_skip_blocks_cfg *skip_blocks_cfg,
+ struct hl_special_block_info *block_info,
+ u32 major, u32 minor, u32 sub_minor)
+{
+ u32 blocks_in_range, block_base_addr_in_range, block_base_addr;
+ int i, j;
+
+ block_base_addr = hl_automated_get_block_base_addr(hdev, block_info,
+ major, minor, sub_minor);
+
+ for (i = 0 ; i < skip_blocks_cfg->block_ranges_len ; i++) {
+ blocks_in_range = (skip_blocks_cfg->block_ranges[i].end -
+ skip_blocks_cfg->block_ranges[i].start) /
+ HL_BLOCK_SIZE + 1;
+ for (j = 0 ; j < blocks_in_range ; j++) {
+ block_base_addr_in_range = skip_blocks_cfg->block_ranges[i].start +
+ j * HL_BLOCK_SIZE;
+ if (block_base_addr == block_base_addr_in_range)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static int hl_read_glbl_errors(struct hl_device *hdev,
+ u32 blk_idx, u32 major, u32 minor, u32 sub_minor, void *data)
+{
+ struct hl_special_block_info *special_blocks = hdev->asic_prop.special_blocks;
+ struct hl_special_block_info *current_block = &special_blocks[blk_idx];
+ u32 glbl_err_addr, glbl_err_cause, addr_val, cause_val, block_base,
+ base = current_block->base_addr - lower_32_bits(hdev->asic_prop.cfg_base_address);
+ int i;
+
+ block_base = base + major * current_block->major_offset +
+ minor * current_block->minor_offset +
+ sub_minor * current_block->sub_minor_offset;
+
+ glbl_err_cause = block_base + HL_GLBL_ERR_CAUSE_OFFSET;
+ cause_val = RREG32(glbl_err_cause);
+ if (!cause_val)
+ return 0;
+
+ glbl_err_addr = block_base + HL_GLBL_ERR_ADDR_OFFSET;
+ addr_val = RREG32(glbl_err_addr);
+
+ for (i = 0 ; i < hdev->asic_prop.glbl_err_cause_num ; i++) {
+ if (cause_val & BIT(i))
+ dev_err_ratelimited(hdev->dev,
+ "%s, addr %#llx\n",
+ hl_glbl_error_cause[i],
+ hdev->asic_prop.cfg_base_address + block_base +
+ FIELD_GET(HL_GLBL_ERR_ADDRESS_MASK, addr_val));
+ }
+
+ WREG32(glbl_err_cause, cause_val);
+
+ return 0;
+}
+
+void hl_check_for_glbl_errors(struct hl_device *hdev)
+{
+ struct asic_fixed_properties *prop = &hdev->asic_prop;
+ struct hl_special_blocks_cfg special_blocks_cfg;
+ struct iterate_special_ctx glbl_err_iter;
+ int rc;
+
+ memset(&special_blocks_cfg, 0, sizeof(special_blocks_cfg));
+ special_blocks_cfg.skip_blocks_cfg = &prop->skip_special_blocks_cfg;
+
+ glbl_err_iter.fn = &hl_read_glbl_errors;
+ glbl_err_iter.data = &special_blocks_cfg;
+
+ rc = hl_iterate_special_blocks(hdev, &glbl_err_iter);
+ if (rc)
+ dev_err_ratelimited(hdev->dev,
+ "Could not iterate special blocks, glbl error check failed\n");
+}
+
+int hl_iterate_special_blocks(struct hl_device *hdev, struct iterate_special_ctx *ctx)
+{
+ struct hl_special_blocks_cfg *special_blocks_cfg =
+ (struct hl_special_blocks_cfg *)ctx->data;
+ struct hl_skip_blocks_cfg *skip_blocks_cfg =
+ special_blocks_cfg->skip_blocks_cfg;
+ u32 major, minor, sub_minor, blk_idx, num_blocks;
+ struct hl_special_block_info *block_info_arr;
+ int rc;
+
+ block_info_arr = hdev->asic_prop.special_blocks;
+ if (!block_info_arr)
+ return -EINVAL;
+
+ num_blocks = hdev->asic_prop.num_of_special_blocks;
+
+ for (blk_idx = 0 ; blk_idx < num_blocks ; blk_idx++, block_info_arr++) {
+ if (hl_check_block_type_exclusion(skip_blocks_cfg, block_info_arr->block_type))
+ continue;
+
+ for (major = 0 ; major < block_info_arr->major ; major++) {
+ minor = 0;
+ do {
+ sub_minor = 0;
+ do {
+ if ((hl_check_block_range_exclusion(hdev,
+ skip_blocks_cfg, block_info_arr,
+ major, minor, sub_minor)) ||
+ (skip_blocks_cfg->skip_block_hook &&
+ skip_blocks_cfg->skip_block_hook(hdev,
+ special_blocks_cfg,
+ blk_idx, major, minor, sub_minor))) {
+ sub_minor++;
+ continue;
+ }
+
+ rc = ctx->fn(hdev, blk_idx, major, minor,
+ sub_minor, ctx->data);
+ if (rc)
+ return rc;
+
+ sub_minor++;
+ } while (sub_minor < block_info_arr->sub_minor);
+
+ minor++;
+ } while (minor < block_info_arr->minor);
+ }
+ }
+
+ return 0;
+}
diff --git a/drivers/accel/habanalabs/common/security.h b/drivers/accel/habanalabs/common/security.h
new file mode 100644
index 000000000000..234b4a6ed8bc
--- /dev/null
+++ b/drivers/accel/habanalabs/common/security.h
@@ -0,0 +1,163 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright 2016-2022 HabanaLabs, Ltd.
+ * All Rights Reserved.
+ *
+ */
+
+#ifndef SECURITY_H_
+#define SECURITY_H_
+
+#include <linux/io-64-nonatomic-lo-hi.h>
+
+extern struct hl_device *hdev;
+
+/* special blocks */
+#define HL_MAX_NUM_OF_GLBL_ERR_CAUSE 10
+#define HL_GLBL_ERR_ADDRESS_MASK GENMASK(11, 0)
+/* GLBL_ERR_ADDR register offset from the start of the block */
+#define HL_GLBL_ERR_ADDR_OFFSET 0xF44
+/* GLBL_ERR_CAUSE register offset from the start of the block */
+#define HL_GLBL_ERR_CAUSE_OFFSET 0xF48
+
+/*
+ * struct hl_special_block_info - stores address details of a particular type of
+ * IP block which has a SPECIAL part.
+ *
+ * @block_type: block type as described in every ASIC's block_types enum.
+ * @base_addr: base address of the first block of particular type,
+ * e.g., address of NIC0_UMR0_0 of 'NIC_UMR' block.
+ * @major: number of major blocks of particular type.
+ * @minor: number of minor blocks of particular type.
+ * @sub_minor: number of sub minor blocks of particular type.
+ * @major_offset: address gap between 2 consecutive major blocks of particular type,
+ * e.g., offset between NIC0_UMR0_0 and NIC1_UMR0_0 is 0x80000.
+ * @minor_offset: address gap between 2 consecutive minor blocks of particular type,
+ * e.g., offset between NIC0_UMR0_0 and NIC0_UMR1_0 is 0x20000.
+ * @sub_minor_offset: address gap between 2 consecutive sub_minor blocks of particular
+ * type, e.g., offset between NIC0_UMR0_0 and NIC0_UMR0_1 is 0x1000.
+ *
+ * e.g., in Gaudi2, NIC_UMR blocks can be interpreted as:
+ * NIC<major>_UMR<minor>_<sub_minor> where major=12, minor=2, sub_minor=15.
+ * In other words, for each of 12 major numbers (i.e 0 to 11) there are
+ * 2 blocks with different minor numbers (i.e. 0 to 1). Again, for each minor
+ * number there are 15 blocks with different sub_minor numbers (i.e. 0 to 14).
+ * So different blocks are NIC0_UMR0_0, NIC0_UMR0_1, ..., NIC0_UMR1_0, ....,
+ * NIC11_UMR1_14.
+ *
+ * Struct's formatted data is located in the SOL-based auto-generated protbits headers.
+ */
+struct hl_special_block_info {
+ int block_type;
+ u32 base_addr;
+ u32 major;
+ u32 minor;
+ u32 sub_minor;
+ u32 major_offset;
+ u32 minor_offset;
+ u32 sub_minor_offset;
+};
+
+/*
+ * struct hl_automated_pb_cfg - represents configurations of a particular type
+ * of IP block which has protection bits.
+ *
+ * @addr: address details as described in hl_automation_pb_addr struct.
+ * @prot_map: each bit corresponds to one among 32 protection configuration regs
+ * (e.g., SPECIAL_GLBL_PRIV). '1' means 0xffffffff and '0' means 0x0
+ * to be written into the corresponding protection configuration reg.
+ * This bit is meaningful if same bit in data_map is 0, otherwise ignored.
+ * @data_map: each bit corresponds to one among 32 protection configuration regs
+ * (e.g., SPECIAL_GLBL_PRIV). '1' means corresponding protection
+ * configuration reg is to be written with a value in array pointed
+ * by 'data', otherwise the value is decided by 'prot_map'.
+ * @data: pointer to data array which stores the config value(s) to be written
+ * to corresponding protection configuration reg(s).
+ * @data_size: size of the data array.
+ *
+ * Each bit of 'data_map' and 'prot_map' fields corresponds to one among 32
+ * protection configuration registers e.g., SPECIAL GLBL PRIV regs (starting at
+ * offset 0xE80). '1' in 'data_map' means protection configuration to be done
+ * using configuration in data array. '0' in 'data_map" means protection
+ * configuration to be done as per the value of corresponding bit in 'prot_map'.
+ * '1' in 'prot_map' means the register to be programmed with 0xFFFFFFFF
+ * (all non-protected). '0' in 'prot_map' means the register to be programmed
+ * with 0x0 (all protected).
+ *
+ * e.g., prot_map = 0x00000001, data_map = 0xC0000000 , data = {0xff, 0x12}
+ * SPECIAL_GLBL_PRIV[0] = 0xFFFFFFFF
+ * SPECIAL_GLBL_PRIV[1..29] = 0x0
+ * SPECIAL_GLBL_PRIV[30] = 0xFF
+ * SPECIAL_GLBL_PRIV[31] = 0x12
+ */
+struct hl_automated_pb_cfg {
+ struct hl_special_block_info addr;
+ u32 prot_map;
+ u32 data_map;
+ const u32 *data;
+ u8 data_size;
+};
+
+/* struct hl_special_blocks_cfg - holds special blocks cfg data.
+ *
+ * @priv_automated_pb_cfg: points to the main privileged PB array.
+ * @sec_automated_pb_cfg: points to the main secured PB array.
+ * @skip_blocks_cfg: holds arrays of block types & block ranges to be excluded.
+ * @priv_cfg_size: size of the main privileged PB array.
+ * @sec_cfg_size: size of the main secured PB array.
+ * @prot_lvl_priv: indication if it's a privileged/secured PB configurations.
+ */
+struct hl_special_blocks_cfg {
+ struct hl_automated_pb_cfg *priv_automated_pb_cfg;
+ struct hl_automated_pb_cfg *sec_automated_pb_cfg;
+ struct hl_skip_blocks_cfg *skip_blocks_cfg;
+ u32 priv_cfg_size;
+ u32 sec_cfg_size;
+ u8 prot_lvl_priv;
+};
+
+/* Automated security */
+
+/* struct hl_skip_blocks_cfg - holds arrays of block types & block ranges to be
+ * excluded from special blocks configurations.
+ *
+ * @block_types: an array of block types NOT to be configured.
+ * @block_types_len: len of an array of block types not to be configured.
+ * @block_ranges: an array of block ranges not to be configured.
+ * @block_ranges_len: len of an array of block ranges not to be configured.
+ * @skip_block_hook: hook that will be called before initializing special blocks.
+ */
+struct hl_skip_blocks_cfg {
+ int *block_types;
+ size_t block_types_len;
+ struct range *block_ranges;
+ size_t block_ranges_len;
+ bool (*skip_block_hook)(struct hl_device *hdev,
+ struct hl_special_blocks_cfg *special_blocks_cfg,
+ u32 blk_idx, u32 major, u32 minor, u32 sub_minor);
+};
+
+/**
+ * struct iterate_special_ctx - HW module special block iterator
+ * @fn: function to apply to each HW module special block instance
+ * @data: optional internal data to the function iterator
+ */
+struct iterate_special_ctx {
+ /*
+ * callback for the HW module special block iterator
+ * @hdev: pointer to the habanalabs device structure
+ * @block_id: block (ASIC specific definition can be dcore/hdcore)
+ * @major: major block index within block_id
+ * @minor: minor block index within the major block
+ * @sub_minor: sub_minor block index within the minor block
+ * @data: function specific data
+ */
+ int (*fn)(struct hl_device *hdev, u32 block_id, u32 major, u32 minor,
+ u32 sub_minor, void *data);
+ void *data;
+};
+
+int hl_iterate_special_blocks(struct hl_device *hdev, struct iterate_special_ctx *ctx);
+void hl_check_for_glbl_errors(struct hl_device *hdev);
+
+#endif /* SECURITY_H_ */
diff --git a/drivers/misc/habanalabs/common/state_dump.c b/drivers/accel/habanalabs/common/state_dump.c
index 74726907c95e..3a9931f24259 100644
--- a/drivers/misc/habanalabs/common/state_dump.c
+++ b/drivers/accel/habanalabs/common/state_dump.c
@@ -6,7 +6,7 @@
*/
#include <linux/vmalloc.h>
-#include <uapi/misc/habanalabs.h>
+#include <uapi/drm/habanalabs_accel.h>
#include "habanalabs.h"
/**
diff --git a/drivers/misc/habanalabs/common/sysfs.c b/drivers/accel/habanalabs/common/sysfs.c
index 735d8bed0066..735d8bed0066 100644
--- a/drivers/misc/habanalabs/common/sysfs.c
+++ b/drivers/accel/habanalabs/common/sysfs.c
diff --git a/drivers/misc/habanalabs/gaudi/Makefile b/drivers/accel/habanalabs/gaudi/Makefile
index 10577c33a816..10577c33a816 100644
--- a/drivers/misc/habanalabs/gaudi/Makefile
+++ b/drivers/accel/habanalabs/gaudi/Makefile
diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/accel/habanalabs/gaudi/gaudi.c
index 9f5e208701ba..bb858b94e1e8 100644
--- a/drivers/misc/habanalabs/gaudi/gaudi.c
+++ b/drivers/accel/habanalabs/gaudi/gaudi.c
@@ -701,6 +701,8 @@ static int gaudi_set_fixed_properties(struct hl_device *hdev)
prop->dma_mask = 48;
+ prop->hbw_flush_reg = mmPCIE_WRAP_RR_ELBI_RD_SEC_REG_CTRL;
+
return 0;
}
@@ -4236,8 +4238,8 @@ static int gaudi_mmap(struct hl_device *hdev, struct vm_area_struct *vma,
{
int rc;
- vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP |
- VM_DONTCOPY | VM_NORESERVE;
+ vm_flags_set(vma, VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP |
+ VM_DONTCOPY | VM_NORESERVE);
rc = dma_mmap_coherent(hdev->dev, vma, cpu_addr,
(dma_addr - HOST_PHYS_BASE), size);
@@ -6432,12 +6434,6 @@ static int gaudi_send_job_on_qman0(struct hl_device *hdev,
else
timeout = HL_DEVICE_TIMEOUT_USEC;
- if (!hdev->asic_funcs->is_device_idle(hdev, NULL, 0, NULL)) {
- dev_err_ratelimited(hdev->dev,
- "Can't send driver job on QMAN0 because the device is not idle\n");
- return -EBUSY;
- }
-
fence_ptr = hl_asic_dma_pool_zalloc(hdev, 4, GFP_KERNEL, &fence_dma_addr);
if (!fence_ptr) {
dev_err(hdev->dev,
@@ -7584,7 +7580,7 @@ static int tpc_krn_event_to_tpc_id(u16 tpc_dec_event_type)
return (tpc_dec_event_type - GAUDI_EVENT_TPC0_KRN_ERR) / 6;
}
-static void gaudi_print_clk_change_info(struct hl_device *hdev, u16 event_type)
+static void gaudi_print_clk_change_info(struct hl_device *hdev, u16 event_type, u64 *event_mask)
{
ktime_t zero_time = ktime_set(0, 0);
@@ -7612,6 +7608,7 @@ static void gaudi_print_clk_change_info(struct hl_device *hdev, u16 event_type)
hdev->clk_throttling.aggregated_reason |= HL_CLK_THROTTLE_THERMAL;
hdev->clk_throttling.timestamp[HL_CLK_THROTTLE_TYPE_THERMAL].start = ktime_get();
hdev->clk_throttling.timestamp[HL_CLK_THROTTLE_TYPE_THERMAL].end = zero_time;
+ *event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
dev_info_ratelimited(hdev->dev,
"Clock throttling due to overheating\n");
break;
@@ -7619,6 +7616,7 @@ static void gaudi_print_clk_change_info(struct hl_device *hdev, u16 event_type)
case GAUDI_EVENT_FIX_THERMAL_ENV_E:
hdev->clk_throttling.current_reason &= ~HL_CLK_THROTTLE_THERMAL;
hdev->clk_throttling.timestamp[HL_CLK_THROTTLE_TYPE_THERMAL].end = ktime_get();
+ *event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
dev_info_ratelimited(hdev->dev,
"Thermal envelop is safe, back to optimal clock\n");
break;
@@ -7887,8 +7885,7 @@ static void gaudi_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entr
break;
case GAUDI_EVENT_FIX_POWER_ENV_S ... GAUDI_EVENT_FIX_THERMAL_ENV_E:
- event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
- gaudi_print_clk_change_info(hdev, event_type);
+ gaudi_print_clk_change_info(hdev, event_type, &event_mask);
hl_fw_unmask_irq(hdev, event_type);
break;
@@ -9133,6 +9130,16 @@ static u32 *gaudi_get_stream_master_qid_arr(void)
return gaudi_stream_master;
}
+static int gaudi_set_dram_properties(struct hl_device *hdev)
+{
+ return 0;
+}
+
+static int gaudi_set_binning_masks(struct hl_device *hdev)
+{
+ return 0;
+}
+
static void gaudi_check_if_razwi_happened(struct hl_device *hdev)
{
}
@@ -9259,6 +9266,8 @@ static const struct hl_asic_funcs gaudi_funcs = {
.access_dev_mem = hl_access_dev_mem,
.set_dram_bar_base = gaudi_set_hbm_bar_base,
.send_device_activity = gaudi_send_device_activity,
+ .set_dram_properties = gaudi_set_dram_properties,
+ .set_binning_masks = gaudi_set_binning_masks,
};
/**
diff --git a/drivers/misc/habanalabs/gaudi/gaudiP.h b/drivers/accel/habanalabs/gaudi/gaudiP.h
index 4fbcf3f0afe5..3d88d56c8eb3 100644
--- a/drivers/misc/habanalabs/gaudi/gaudiP.h
+++ b/drivers/accel/habanalabs/gaudi/gaudiP.h
@@ -8,7 +8,7 @@
#ifndef GAUDIP_H_
#define GAUDIP_H_
-#include <uapi/misc/habanalabs.h>
+#include <uapi/drm/habanalabs_accel.h>
#include "../common/habanalabs.h"
#include "../include/common/hl_boot_if.h"
#include "../include/gaudi/gaudi_packets.h"
diff --git a/drivers/misc/habanalabs/gaudi/gaudi_coresight.c b/drivers/accel/habanalabs/gaudi/gaudi_coresight.c
index 08108f5fed67..3455b14554c6 100644
--- a/drivers/misc/habanalabs/gaudi/gaudi_coresight.c
+++ b/drivers/accel/habanalabs/gaudi/gaudi_coresight.c
@@ -11,7 +11,8 @@
#include "../include/gaudi/gaudi_masks.h"
#include "../include/gaudi/gaudi_reg_map.h"
-#include <uapi/misc/habanalabs.h>
+#include <uapi/drm/habanalabs_accel.h>
+
#define SPMU_SECTION_SIZE MME0_ACC_SPMU_MAX_OFFSET
#define SPMU_EVENT_TYPES_OFFSET 0x400
#define SPMU_MAX_COUNTERS 6
diff --git a/drivers/misc/habanalabs/gaudi/gaudi_security.c b/drivers/accel/habanalabs/gaudi/gaudi_security.c
index 81a3c79a8bc6..81a3c79a8bc6 100644
--- a/drivers/misc/habanalabs/gaudi/gaudi_security.c
+++ b/drivers/accel/habanalabs/gaudi/gaudi_security.c
diff --git a/drivers/misc/habanalabs/gaudi2/Makefile b/drivers/accel/habanalabs/gaudi2/Makefile
index 1e047883ba74..1e047883ba74 100644
--- a/drivers/misc/habanalabs/gaudi2/Makefile
+++ b/drivers/accel/habanalabs/gaudi2/Makefile
diff --git a/drivers/misc/habanalabs/gaudi2/gaudi2.c b/drivers/accel/habanalabs/gaudi2/gaudi2.c
index e793fb2bdcbe..6f415fa94eee 100644
--- a/drivers/misc/habanalabs/gaudi2/gaudi2.c
+++ b/drivers/accel/habanalabs/gaudi2/gaudi2.c
@@ -7,6 +7,7 @@
#include "gaudi2P.h"
#include "gaudi2_masks.h"
+#include "../include/gaudi2/gaudi2_special_blocks.h"
#include "../include/hw_ip/mmu/mmu_general.h"
#include "../include/hw_ip/mmu/mmu_v2_0.h"
#include "../include/gaudi2/gaudi2_packets.h"
@@ -53,6 +54,7 @@
#define GAUDI2_HIF_HMMU_FULL_MASK 0xFFFF
#define GAUDI2_DECODER_FULL_MASK 0x3FF
+#define GAUDI2_NA_EVENT_CAUSE 0xFF
#define GAUDI2_NUM_OF_QM_ERR_CAUSE 18
#define GAUDI2_NUM_OF_QM_LCP_ERR_CAUSE 25
#define GAUDI2_NUM_OF_QM_ARB_ERR_CAUSE 3
@@ -675,14 +677,13 @@ static const char * const gaudi2_kdma_core_interrupts_cause[GAUDI2_NUM_OF_DMA_CO
struct gaudi2_sm_sei_cause_data {
const char *cause_name;
const char *log_name;
- u32 log_mask;
};
static const struct gaudi2_sm_sei_cause_data
gaudi2_sm_sei_cause[GAUDI2_NUM_OF_SM_SEI_ERR_CAUSE] = {
- {"calculated SO value overflow/underflow", "SOB group ID", 0x7FF},
- {"payload address of monitor is not aligned to 4B", "monitor addr", 0xFFFF},
- {"armed monitor write got BRESP (SLVERR or DECERR)", "AXI id", 0xFFFF},
+ {"calculated SO value overflow/underflow", "SOB ID"},
+ {"payload address of monitor is not aligned to 4B", "monitor addr"},
+ {"armed monitor write got BRESP (SLVERR or DECERR)", "AXI id"},
};
static const char * const
@@ -1568,7 +1569,7 @@ enum rtr_id {
DCORE3_RTR7,
};
-static const u32 gaudi2_tpc_initiator_rtr_id[NUM_OF_TPC_PER_DCORE * NUM_OF_DCORES + 1] = {
+static const u32 gaudi2_tpc_initiator_hbw_rtr_id[NUM_OF_TPC_PER_DCORE * NUM_OF_DCORES + 1] = {
DCORE0_RTR1, DCORE0_RTR1, DCORE0_RTR2, DCORE0_RTR2, DCORE0_RTR3, DCORE0_RTR3,
DCORE1_RTR6, DCORE1_RTR6, DCORE1_RTR5, DCORE1_RTR5, DCORE1_RTR4, DCORE1_RTR4,
DCORE2_RTR3, DCORE2_RTR3, DCORE2_RTR2, DCORE2_RTR2, DCORE2_RTR1, DCORE2_RTR1,
@@ -1576,33 +1577,61 @@ static const u32 gaudi2_tpc_initiator_rtr_id[NUM_OF_TPC_PER_DCORE * NUM_OF_DCORE
DCORE0_RTR0
};
-static const u32 gaudi2_dec_initiator_rtr_id[NUMBER_OF_DEC] = {
+static const u32 gaudi2_tpc_initiator_lbw_rtr_id[NUM_OF_TPC_PER_DCORE * NUM_OF_DCORES + 1] = {
+ DCORE0_RTR1, DCORE0_RTR1, DCORE0_RTR1, DCORE0_RTR1, DCORE0_RTR2, DCORE0_RTR2,
+ DCORE1_RTR7, DCORE1_RTR7, DCORE1_RTR6, DCORE1_RTR6, DCORE1_RTR5, DCORE1_RTR5,
+ DCORE2_RTR2, DCORE2_RTR2, DCORE2_RTR1, DCORE2_RTR1, DCORE2_RTR0, DCORE2_RTR0,
+ DCORE3_RTR5, DCORE3_RTR5, DCORE3_RTR6, DCORE3_RTR6, DCORE3_RTR7, DCORE3_RTR7,
+ DCORE0_RTR0
+};
+
+static const u32 gaudi2_dec_initiator_hbw_rtr_id[NUMBER_OF_DEC] = {
DCORE0_RTR0, DCORE0_RTR0, DCORE1_RTR7, DCORE1_RTR7, DCORE2_RTR0, DCORE2_RTR0,
DCORE3_RTR7, DCORE3_RTR7, DCORE0_RTR0, DCORE0_RTR0
};
-static const u32 gaudi2_nic_initiator_rtr_id[NIC_NUMBER_OF_MACROS] = {
+static const u32 gaudi2_dec_initiator_lbw_rtr_id[NUMBER_OF_DEC] = {
+ DCORE0_RTR1, DCORE0_RTR1, DCORE1_RTR6, DCORE1_RTR6, DCORE2_RTR1, DCORE2_RTR1,
+ DCORE3_RTR6, DCORE3_RTR6, DCORE0_RTR0, DCORE0_RTR0
+};
+
+static const u32 gaudi2_nic_initiator_hbw_rtr_id[NIC_NUMBER_OF_MACROS] = {
DCORE1_RTR7, DCORE1_RTR7, DCORE1_RTR7, DCORE1_RTR7, DCORE1_RTR7, DCORE2_RTR0,
DCORE2_RTR0, DCORE2_RTR0, DCORE2_RTR0, DCORE3_RTR7, DCORE3_RTR7, DCORE3_RTR7
};
-struct sft_info {
- u8 interface_id;
- u8 dcore_id;
+static const u32 gaudi2_nic_initiator_lbw_rtr_id[NIC_NUMBER_OF_MACROS] = {
+ DCORE1_RTR7, DCORE1_RTR7, DCORE1_RTR7, DCORE1_RTR7, DCORE1_RTR7, DCORE2_RTR0,
+ DCORE2_RTR0, DCORE2_RTR0, DCORE2_RTR0, DCORE3_RTR7, DCORE3_RTR7, DCORE3_RTR7
};
-static const struct sft_info gaudi2_edma_initiator_sft_id[NUM_OF_EDMA_PER_DCORE * NUM_OF_DCORES] = {
- {0, 0}, {1, 0}, {0, 1}, {1, 1}, {1, 2}, {1, 3}, {0, 2}, {0, 3},
+static const u32 gaudi2_edma_initiator_hbw_sft[NUM_OF_EDMA_PER_DCORE * NUM_OF_DCORES] = {
+ mmSFT0_HBW_RTR_IF1_MSTR_IF_RR_SHRD_HBW_BASE,
+ mmSFT0_HBW_RTR_IF0_MSTR_IF_RR_SHRD_HBW_BASE,
+ mmSFT1_HBW_RTR_IF1_MSTR_IF_RR_SHRD_HBW_BASE,
+ mmSFT1_HBW_RTR_IF0_MSTR_IF_RR_SHRD_HBW_BASE,
+ mmSFT2_HBW_RTR_IF0_MSTR_IF_RR_SHRD_HBW_BASE,
+ mmSFT2_HBW_RTR_IF1_MSTR_IF_RR_SHRD_HBW_BASE,
+ mmSFT3_HBW_RTR_IF0_MSTR_IF_RR_SHRD_HBW_BASE,
+ mmSFT3_HBW_RTR_IF1_MSTR_IF_RR_SHRD_HBW_BASE
};
-static const u32 gaudi2_pdma_initiator_rtr_id[NUM_OF_PDMA] = {
+static const u32 gaudi2_pdma_initiator_hbw_rtr_id[NUM_OF_PDMA] = {
DCORE0_RTR0, DCORE0_RTR0
};
-static const u32 gaudi2_rot_initiator_rtr_id[NUM_OF_ROT] = {
+static const u32 gaudi2_pdma_initiator_lbw_rtr_id[NUM_OF_PDMA] = {
+ DCORE0_RTR2, DCORE0_RTR2
+};
+
+static const u32 gaudi2_rot_initiator_hbw_rtr_id[NUM_OF_ROT] = {
DCORE2_RTR0, DCORE3_RTR7
};
+static const u32 gaudi2_rot_initiator_lbw_rtr_id[NUM_OF_ROT] = {
+ DCORE2_RTR2, DCORE3_RTR5
+};
+
struct mme_initiators_rtr_id {
u32 wap0;
u32 wap1;
@@ -1655,6 +1684,30 @@ struct hbm_mc_error_causes {
char cause[50];
};
+static struct hl_special_block_info gaudi2_special_blocks[] = GAUDI2_SPECIAL_BLOCKS;
+
+/* Special blocks iterator is currently used to configure security protection bits,
+ * and read global errors. Most HW blocks are addressable and those who aren't (N/A)-
+ * must be skipped. Following configurations are commonly used for both PB config
+ * and global error reading, since currently they both share the same settings.
+ * Once it changes, we must remember to use separate configurations for either one.
+ */
+static int gaudi2_iterator_skip_block_types[] = {
+ GAUDI2_BLOCK_TYPE_PLL,
+ GAUDI2_BLOCK_TYPE_EU_BIST,
+ GAUDI2_BLOCK_TYPE_HBM,
+ GAUDI2_BLOCK_TYPE_XFT
+};
+
+static struct range gaudi2_iterator_skip_block_ranges[] = {
+ /* Skip all PSOC blocks except for PSOC_GLOBAL_CONF */
+ {mmPSOC_I2C_M0_BASE, mmPSOC_EFUSE_BASE},
+ {mmPSOC_BTL_BASE, mmPSOC_MSTR_IF_RR_SHRD_HBW_BASE},
+ /* Skip all CPU blocks except for CPU_IF */
+ {mmCPU_CA53_CFG_BASE, mmCPU_CA53_CFG_BASE},
+ {mmCPU_TIMESTAMP_BASE, mmCPU_MSTR_IF_RR_SHRD_HBW_BASE}
+};
+
static struct hbm_mc_error_causes hbm_mc_spi[GAUDI2_NUM_OF_HBM_MC_SPI_CAUSE] = {
{HBM_MC_SPI_TEMP_PIN_CHG_MASK, "temperature pins changed"},
{HBM_MC_SPI_THR_ENG_MASK, "temperature-based throttling engaged"},
@@ -2070,6 +2123,8 @@ static int gaudi2_set_fixed_properties(struct hl_device *hdev)
prop->dma_mask = 64;
+ prop->hbw_flush_reg = mmPCIE_WRAP_SPECIAL_GLBL_SPARE_0;
+
return 0;
}
@@ -2434,6 +2489,25 @@ static int gaudi2_set_cluster_binning_masks(struct hl_device *hdev)
return 0;
}
+static int gaudi2_set_binning_masks(struct hl_device *hdev)
+{
+ int rc;
+
+ rc = gaudi2_set_cluster_binning_masks(hdev);
+ if (rc)
+ return rc;
+
+ rc = gaudi2_set_tpc_binning_masks(hdev);
+ if (rc)
+ return rc;
+
+ rc = gaudi2_set_dec_binning_masks(hdev);
+ if (rc)
+ return rc;
+
+ return 0;
+}
+
static int gaudi2_cpucp_info_get(struct hl_device *hdev)
{
struct gaudi2_device *gaudi2 = hdev->asic_specific;
@@ -2485,19 +2559,11 @@ static int gaudi2_cpucp_info_get(struct hl_device *hdev)
* at this point the DRAM parameters need to be updated according to data obtained
* from the FW
*/
- rc = gaudi2_set_dram_properties(hdev);
+ rc = hdev->asic_funcs->set_dram_properties(hdev);
if (rc)
return rc;
- rc = gaudi2_set_cluster_binning_masks(hdev);
- if (rc)
- return rc;
-
- rc = gaudi2_set_tpc_binning_masks(hdev);
- if (rc)
- return rc;
-
- rc = gaudi2_set_dec_binning_masks(hdev);
+ rc = hdev->asic_funcs->set_binning_masks(hdev);
if (rc)
return rc;
@@ -2925,11 +2991,11 @@ static void gaudi2_user_interrupt_setup(struct hl_device *hdev)
/* Initialize common user CQ interrupt */
HL_USR_INTR_STRUCT_INIT(hdev->common_user_cq_interrupt, hdev,
- HL_COMMON_USER_CQ_INTERRUPT_ID, false);
+ HL_COMMON_USER_CQ_INTERRUPT_ID, HL_USR_INTERRUPT_CQ);
/* Initialize common decoder interrupt */
HL_USR_INTR_STRUCT_INIT(hdev->common_decoder_interrupt, hdev,
- HL_COMMON_DEC_INTERRUPT_ID, true);
+ HL_COMMON_DEC_INTERRUPT_ID, HL_USR_INTERRUPT_DECODER);
/* User interrupts structure holds both decoder and user interrupts from various engines.
* We first initialize the decoder interrupts and then we add the user interrupts.
@@ -2942,10 +3008,11 @@ static void gaudi2_user_interrupt_setup(struct hl_device *hdev)
*/
for (i = GAUDI2_IRQ_NUM_DCORE0_DEC0_NRM, j = 0 ; i <= GAUDI2_IRQ_NUM_SHARED_DEC1_NRM;
i += 2, j++)
- HL_USR_INTR_STRUCT_INIT(hdev->user_interrupt[j], hdev, i, true);
+ HL_USR_INTR_STRUCT_INIT(hdev->user_interrupt[j], hdev, i,
+ HL_USR_INTERRUPT_DECODER);
for (i = GAUDI2_IRQ_NUM_USER_FIRST, k = 0 ; k < prop->user_interrupt_count; i++, j++, k++)
- HL_USR_INTR_STRUCT_INIT(hdev->user_interrupt[j], hdev, i, false);
+ HL_USR_INTR_STRUCT_INIT(hdev->user_interrupt[j], hdev, i, HL_USR_INTERRUPT_CQ);
}
static inline int gaudi2_get_non_zero_random_int(void)
@@ -2955,6 +3022,99 @@ static inline int gaudi2_get_non_zero_random_int(void)
return rand ? rand : 1;
}
+static void gaudi2_special_blocks_free(struct hl_device *hdev)
+{
+ struct asic_fixed_properties *prop = &hdev->asic_prop;
+ struct hl_skip_blocks_cfg *skip_special_blocks_cfg =
+ &prop->skip_special_blocks_cfg;
+
+ kfree(prop->special_blocks);
+ kfree(skip_special_blocks_cfg->block_types);
+ kfree(skip_special_blocks_cfg->block_ranges);
+}
+
+static void gaudi2_special_blocks_iterator_free(struct hl_device *hdev)
+{
+ gaudi2_special_blocks_free(hdev);
+}
+
+static bool gaudi2_special_block_skip(struct hl_device *hdev,
+ struct hl_special_blocks_cfg *special_blocks_cfg,
+ u32 blk_idx, u32 major, u32 minor, u32 sub_minor)
+{
+ return false;
+}
+
+static int gaudi2_special_blocks_config(struct hl_device *hdev)
+{
+ struct asic_fixed_properties *prop = &hdev->asic_prop;
+ int i, rc;
+
+ /* Configure Special blocks */
+ prop->glbl_err_cause_num = GAUDI2_NUM_OF_GLBL_ERR_CAUSE;
+ prop->num_of_special_blocks = ARRAY_SIZE(gaudi2_special_blocks);
+ prop->special_blocks = kmalloc_array(prop->num_of_special_blocks,
+ sizeof(*prop->special_blocks), GFP_KERNEL);
+ if (!prop->special_blocks)
+ return -ENOMEM;
+
+ for (i = 0 ; i < prop->num_of_special_blocks ; i++)
+ memcpy(&prop->special_blocks[i], &gaudi2_special_blocks[i],
+ sizeof(*prop->special_blocks));
+
+ /* Configure when to skip Special blocks */
+ memset(&prop->skip_special_blocks_cfg, 0, sizeof(prop->skip_special_blocks_cfg));
+ prop->skip_special_blocks_cfg.skip_block_hook = gaudi2_special_block_skip;
+
+ if (ARRAY_SIZE(gaudi2_iterator_skip_block_types)) {
+ prop->skip_special_blocks_cfg.block_types =
+ kmalloc_array(ARRAY_SIZE(gaudi2_iterator_skip_block_types),
+ sizeof(gaudi2_iterator_skip_block_types[0]), GFP_KERNEL);
+ if (!prop->skip_special_blocks_cfg.block_types) {
+ rc = -ENOMEM;
+ goto free_special_blocks;
+ }
+
+ memcpy(prop->skip_special_blocks_cfg.block_types, gaudi2_iterator_skip_block_types,
+ sizeof(gaudi2_iterator_skip_block_types));
+
+ prop->skip_special_blocks_cfg.block_types_len =
+ ARRAY_SIZE(gaudi2_iterator_skip_block_types);
+ }
+
+ if (ARRAY_SIZE(gaudi2_iterator_skip_block_ranges)) {
+ prop->skip_special_blocks_cfg.block_ranges =
+ kmalloc_array(ARRAY_SIZE(gaudi2_iterator_skip_block_ranges),
+ sizeof(gaudi2_iterator_skip_block_ranges[0]), GFP_KERNEL);
+ if (!prop->skip_special_blocks_cfg.block_ranges) {
+ rc = -ENOMEM;
+ goto free_skip_special_blocks_types;
+ }
+
+ for (i = 0 ; i < ARRAY_SIZE(gaudi2_iterator_skip_block_ranges) ; i++)
+ memcpy(&prop->skip_special_blocks_cfg.block_ranges[i],
+ &gaudi2_iterator_skip_block_ranges[i],
+ sizeof(struct range));
+
+ prop->skip_special_blocks_cfg.block_ranges_len =
+ ARRAY_SIZE(gaudi2_iterator_skip_block_ranges);
+ }
+
+ return 0;
+
+free_skip_special_blocks_types:
+ kfree(prop->skip_special_blocks_cfg.block_types);
+free_special_blocks:
+ kfree(prop->special_blocks);
+
+ return rc;
+}
+
+static int gaudi2_special_blocks_iterator_config(struct hl_device *hdev)
+{
+ return gaudi2_special_blocks_config(hdev);
+}
+
static int gaudi2_sw_init(struct hl_device *hdev)
{
struct asic_fixed_properties *prop = &hdev->asic_prop;
@@ -3050,8 +3210,15 @@ static int gaudi2_sw_init(struct hl_device *hdev)
hdev->asic_funcs->set_pci_memory_regions(hdev);
+ rc = gaudi2_special_blocks_iterator_config(hdev);
+ if (rc)
+ goto free_scratchpad_mem;
+
return 0;
+free_scratchpad_mem:
+ hl_asic_dma_pool_free(hdev, gaudi2->scratchpad_kernel_address,
+ gaudi2->scratchpad_bus_address);
free_virt_msix_db_mem:
hl_cpu_accessible_dma_pool_free(hdev, prop->pmmu.page_size, gaudi2->virt_msix_db_cpu_addr);
free_cpu_accessible_dma_pool:
@@ -3071,6 +3238,8 @@ static int gaudi2_sw_fini(struct hl_device *hdev)
struct asic_fixed_properties *prop = &hdev->asic_prop;
struct gaudi2_device *gaudi2 = hdev->asic_specific;
+ gaudi2_special_blocks_iterator_free(hdev);
+
hl_cpu_accessible_dma_pool_free(hdev, prop->pmmu.page_size, gaudi2->virt_msix_db_cpu_addr);
gen_pool_destroy(hdev->cpu_accessible_dma_pool);
@@ -5483,7 +5652,31 @@ static void gaudi2_hw_fini(struct hl_device *hdev, bool hard_reset, bool fw_rese
skip_reset:
if (driver_performs_reset || hard_reset)
- gaudi2_poll_btm_indication(hdev, reset_sleep_ms, poll_timeout_us);
+ /*
+ * Instead of waiting for BTM indication we should wait for preboot ready:
+ * Consider the below scenario:
+ * 1. FW update is being triggered
+ * - setting the dirty bit
+ * 2. hard reset will be triggered due to the dirty bit
+ * 3. FW initiates the reset:
+ * - dirty bit cleared
+ * - BTM indication cleared
+ * - preboot ready indication cleared
+ * 4. during hard reset:
+ * - BTM indication will be set
+ * - BIST test performed and another reset triggered
+ * 5. only after this reset the preboot will set the preboot ready
+ *
+ * when polling on BTM indication alone we can lose sync with FW while trying to
+ * communicate with FW that is during reset.
+ * to overcome this we will always wait to preboot ready indication
+ */
+ if ((hdev->fw_components & FW_TYPE_PREBOOT_CPU)) {
+ msleep(reset_sleep_ms);
+ hl_fw_wait_preboot_ready(hdev);
+ } else {
+ gaudi2_poll_btm_indication(hdev, reset_sleep_ms, poll_timeout_us);
+ }
else
gaudi2_get_soft_rst_done_indication(hdev, poll_timeout_us);
@@ -5538,8 +5731,8 @@ static int gaudi2_mmap(struct hl_device *hdev, struct vm_area_struct *vma,
{
int rc;
- vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP |
- VM_DONTCOPY | VM_NORESERVE;
+ vm_flags_set(vma, VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP |
+ VM_DONTCOPY | VM_NORESERVE);
#ifdef _HAS_DMA_MMAP_COHERENT
@@ -6803,38 +6996,37 @@ static inline bool is_info_event(u32 event)
switch (event) {
case GAUDI2_EVENT_CPU_CPLD_SHUTDOWN_CAUSE:
case GAUDI2_EVENT_CPU_FIX_POWER_ENV_S ... GAUDI2_EVENT_CPU_FIX_THERMAL_ENV_E:
+
+ /* return in case of NIC status event - these events are received periodically and not as
+ * an indication to an error.
+ */
+ case GAUDI2_EVENT_CPU0_STATUS_NIC0_ENG0 ... GAUDI2_EVENT_CPU11_STATUS_NIC11_ENG1:
return true;
default:
return false;
}
}
-static void gaudi2_print_irq_info(struct hl_device *hdev, u16 event_type)
+static void gaudi2_print_event(struct hl_device *hdev, u16 event_type,
+ bool ratelimited, const char *fmt, ...)
{
- char desc[64] = "";
- bool event_valid = false;
+ struct va_format vaf;
+ va_list args;
- /* return in case of NIC status event - these events are received periodically and not as
- * an indication to an error, thus not printed.
- */
- if (event_type >= GAUDI2_EVENT_CPU0_STATUS_NIC0_ENG0 &&
- event_type <= GAUDI2_EVENT_CPU11_STATUS_NIC11_ENG1)
- return;
+ va_start(args, fmt);
+ vaf.fmt = fmt;
+ vaf.va = &args;
- if (gaudi2_irq_map_table[event_type].valid) {
- snprintf(desc, sizeof(desc), gaudi2_irq_map_table[event_type].name);
- event_valid = true;
- }
-
- if (!event_valid)
- snprintf(desc, sizeof(desc), "N/A");
-
- if (is_info_event(event_type))
- dev_info_ratelimited(hdev->dev, "Received H/W interrupt %d [\"%s\"]\n",
- event_type, desc);
+ if (ratelimited)
+ dev_err_ratelimited(hdev->dev, "%s: %pV\n",
+ gaudi2_irq_map_table[event_type].valid ?
+ gaudi2_irq_map_table[event_type].name : "N/A Event", &vaf);
else
- dev_err_ratelimited(hdev->dev, "Received H/W interrupt %d [\"%s\"]\n",
- event_type, desc);
+ dev_err(hdev->dev, "%s: %pV\n",
+ gaudi2_irq_map_table[event_type].valid ?
+ gaudi2_irq_map_table[event_type].name : "N/A Event", &vaf);
+
+ va_end(args);
}
static bool gaudi2_handle_ecc_event(struct hl_device *hdev, u16 event_type,
@@ -6847,7 +7039,7 @@ static bool gaudi2_handle_ecc_event(struct hl_device *hdev, u16 event_type,
ecc_syndrom = le64_to_cpu(ecc_data->ecc_syndrom);
memory_wrapper_idx = ecc_data->memory_wrapper_idx;
- dev_err(hdev->dev,
+ gaudi2_print_event(hdev, event_type, !ecc_data->is_critical,
"ECC error detected. address: %#llx. Syndrom: %#llx. block id %u. critical %u.\n",
ecc_address, ecc_syndrom, memory_wrapper_idx, ecc_data->is_critical);
@@ -6987,10 +7179,10 @@ static void print_qman_data_on_err(struct hl_device *hdev, u32 qid_base, u32 str
gaudi2_print_last_pqes_on_err(hdev, qid_base, i, qman_base, false);
}
-static void gaudi2_handle_qman_err_generic(struct hl_device *hdev, const char *qm_name,
- u64 qman_base, u32 qid_base)
+static int gaudi2_handle_qman_err_generic(struct hl_device *hdev, u16 event_type,
+ u64 qman_base, u32 qid_base)
{
- u32 i, j, glbl_sts_val, arb_err_val, num_error_causes;
+ u32 i, j, glbl_sts_val, arb_err_val, num_error_causes, error_count = 0;
u64 glbl_sts_addr, arb_err_addr;
char reg_desc[32];
@@ -7013,12 +7205,14 @@ static void gaudi2_handle_qman_err_generic(struct hl_device *hdev, const char *q
}
for (j = 0 ; j < num_error_causes ; j++)
- if (glbl_sts_val & BIT(j))
- dev_err_ratelimited(hdev->dev, "%s %s. err cause: %s\n",
- qm_name, reg_desc,
- i == QMAN_STREAMS ?
- gaudi2_qman_lower_cp_error_cause[j] :
- gaudi2_qman_error_cause[j]);
+ if (glbl_sts_val & BIT(j)) {
+ gaudi2_print_event(hdev, event_type, true,
+ "%s. err cause: %s", reg_desc,
+ i == QMAN_STREAMS ?
+ gaudi2_qman_lower_cp_error_cause[j] :
+ gaudi2_qman_error_cause[j]);
+ error_count++;
+ }
print_qman_data_on_err(hdev, qid_base, i, qman_base);
}
@@ -7026,18 +7220,23 @@ static void gaudi2_handle_qman_err_generic(struct hl_device *hdev, const char *q
arb_err_val = RREG32(arb_err_addr);
if (!arb_err_val)
- return;
+ goto out;
for (j = 0 ; j < GAUDI2_NUM_OF_QM_ARB_ERR_CAUSE ; j++) {
- if (arb_err_val & BIT(j))
- dev_err_ratelimited(hdev->dev, "%s ARB_ERR. err cause: %s\n",
- qm_name, gaudi2_qman_arb_error_cause[j]);
+ if (arb_err_val & BIT(j)) {
+ gaudi2_print_event(hdev, event_type, true,
+ "ARB_ERR. err cause: %s",
+ gaudi2_qman_arb_error_cause[j]);
+ error_count++;
+ }
}
+
+out:
+ return error_count;
}
static void gaudi2_razwi_rr_hbw_shared_printf_info(struct hl_device *hdev,
u64 rtr_mstr_if_base_addr, bool is_write, char *name,
- bool read_razwi_regs, struct hl_eq_razwi_info *razwi_info,
enum gaudi2_engine_id id, u64 *event_mask)
{
u32 razwi_hi, razwi_lo, razwi_xy;
@@ -7045,26 +7244,14 @@ static void gaudi2_razwi_rr_hbw_shared_printf_info(struct hl_device *hdev,
u8 rd_wr_flag;
if (is_write) {
- if (read_razwi_regs) {
- razwi_hi = RREG32(rtr_mstr_if_base_addr + RR_SHRD_HBW_AW_RAZWI_HI);
- razwi_lo = RREG32(rtr_mstr_if_base_addr + RR_SHRD_HBW_AW_RAZWI_LO);
- razwi_xy = RREG32(rtr_mstr_if_base_addr + RR_SHRD_HBW_AW_RAZWI_XY);
- } else {
- razwi_hi = le32_to_cpu(razwi_info->hbw.rr_aw_razwi_hi_reg);
- razwi_lo = le32_to_cpu(razwi_info->hbw.rr_aw_razwi_lo_reg);
- razwi_xy = le32_to_cpu(razwi_info->hbw.rr_aw_razwi_id_reg);
- }
+ razwi_hi = RREG32(rtr_mstr_if_base_addr + RR_SHRD_HBW_AW_RAZWI_HI);
+ razwi_lo = RREG32(rtr_mstr_if_base_addr + RR_SHRD_HBW_AW_RAZWI_LO);
+ razwi_xy = RREG32(rtr_mstr_if_base_addr + RR_SHRD_HBW_AW_RAZWI_XY);
rd_wr_flag = HL_RAZWI_WRITE;
} else {
- if (read_razwi_regs) {
- razwi_hi = RREG32(rtr_mstr_if_base_addr + RR_SHRD_HBW_AR_RAZWI_HI);
- razwi_lo = RREG32(rtr_mstr_if_base_addr + RR_SHRD_HBW_AR_RAZWI_LO);
- razwi_xy = RREG32(rtr_mstr_if_base_addr + RR_SHRD_HBW_AR_RAZWI_XY);
- } else {
- razwi_hi = le32_to_cpu(razwi_info->hbw.rr_ar_razwi_hi_reg);
- razwi_lo = le32_to_cpu(razwi_info->hbw.rr_ar_razwi_lo_reg);
- razwi_xy = le32_to_cpu(razwi_info->hbw.rr_ar_razwi_id_reg);
- }
+ razwi_hi = RREG32(rtr_mstr_if_base_addr + RR_SHRD_HBW_AR_RAZWI_HI);
+ razwi_lo = RREG32(rtr_mstr_if_base_addr + RR_SHRD_HBW_AR_RAZWI_LO);
+ razwi_xy = RREG32(rtr_mstr_if_base_addr + RR_SHRD_HBW_AR_RAZWI_XY);
rd_wr_flag = HL_RAZWI_READ;
}
@@ -7078,38 +7265,26 @@ static void gaudi2_razwi_rr_hbw_shared_printf_info(struct hl_device *hdev,
static void gaudi2_razwi_rr_lbw_shared_printf_info(struct hl_device *hdev,
u64 rtr_mstr_if_base_addr, bool is_write, char *name,
- bool read_razwi_regs, struct hl_eq_razwi_info *razwi_info,
enum gaudi2_engine_id id, u64 *event_mask)
{
- u32 razwi_addr, razwi_xy;
+ u64 razwi_addr = CFG_BASE;
+ u32 razwi_xy;
u16 eng_id = id;
u8 rd_wr_flag;
if (is_write) {
- if (read_razwi_regs) {
- razwi_addr = RREG32(rtr_mstr_if_base_addr + RR_SHRD_LBW_AW_RAZWI);
- razwi_xy = RREG32(rtr_mstr_if_base_addr + RR_SHRD_LBW_AW_RAZWI_XY);
- } else {
- razwi_addr = le32_to_cpu(razwi_info->lbw.rr_aw_razwi_reg);
- razwi_xy = le32_to_cpu(razwi_info->lbw.rr_aw_razwi_id_reg);
- }
-
+ razwi_addr += RREG32(rtr_mstr_if_base_addr + RR_SHRD_LBW_AW_RAZWI);
+ razwi_xy = RREG32(rtr_mstr_if_base_addr + RR_SHRD_LBW_AW_RAZWI_XY);
rd_wr_flag = HL_RAZWI_WRITE;
} else {
- if (read_razwi_regs) {
- razwi_addr = RREG32(rtr_mstr_if_base_addr + RR_SHRD_LBW_AR_RAZWI);
- razwi_xy = RREG32(rtr_mstr_if_base_addr + RR_SHRD_LBW_AR_RAZWI_XY);
- } else {
- razwi_addr = le32_to_cpu(razwi_info->lbw.rr_ar_razwi_reg);
- razwi_xy = le32_to_cpu(razwi_info->lbw.rr_ar_razwi_id_reg);
- }
-
+ razwi_addr += RREG32(rtr_mstr_if_base_addr + RR_SHRD_LBW_AR_RAZWI);
+ razwi_xy = RREG32(rtr_mstr_if_base_addr + RR_SHRD_LBW_AR_RAZWI_XY);
rd_wr_flag = HL_RAZWI_READ;
}
hl_handle_razwi(hdev, razwi_addr, &eng_id, 1, rd_wr_flag | HL_RAZWI_LBW, event_mask);
dev_err_ratelimited(hdev->dev,
- "%s-RAZWI SHARED RR LBW %s error, mstr_if 0x%llx, captured address 0x%x Initiator coordinates 0x%x\n",
+ "%s-RAZWI SHARED RR LBW %s error, mstr_if 0x%llx, captured address 0x%llX Initiator coordinates 0x%x\n",
name, is_write ? "WR" : "RD", rtr_mstr_if_base_addr, razwi_addr,
razwi_xy);
}
@@ -7164,183 +7339,148 @@ static enum gaudi2_engine_id gaudi2_razwi_calc_engine_id(struct hl_device *hdev,
*/
static void gaudi2_ack_module_razwi_event_handler(struct hl_device *hdev,
enum razwi_event_sources module, u8 module_idx,
- u8 module_sub_idx, struct hl_eq_razwi_info *razwi_info,
- u64 *event_mask)
+ u8 module_sub_idx, u64 *event_mask)
{
- bool via_sft = false, read_razwi_regs = false;
- u32 rtr_id, dcore_id, dcore_rtr_id, sft_id, eng_id;
- u64 rtr_mstr_if_base_addr;
+ bool via_sft = false;
+ u32 hbw_rtr_id, lbw_rtr_id, dcore_id, dcore_rtr_id, eng_id;
+ u64 hbw_rtr_mstr_if_base_addr, lbw_rtr_mstr_if_base_addr;
u32 hbw_shrd_aw = 0, hbw_shrd_ar = 0;
u32 lbw_shrd_aw = 0, lbw_shrd_ar = 0;
char initiator_name[64];
- if (hdev->pldm || !(hdev->fw_components & FW_TYPE_LINUX) || !razwi_info)
- read_razwi_regs = true;
-
switch (module) {
case RAZWI_TPC:
- rtr_id = gaudi2_tpc_initiator_rtr_id[module_idx];
+ hbw_rtr_id = gaudi2_tpc_initiator_hbw_rtr_id[module_idx];
+
+ /* TODO : remove this check and depend only on tpc routers table
+ * when SW-118828 is resolved
+ */
+ if (!hdev->asic_prop.fw_security_enabled &&
+ ((module_idx == 0) || (module_idx == 1)))
+ lbw_rtr_id = DCORE0_RTR0;
+ else
+ lbw_rtr_id = gaudi2_tpc_initiator_lbw_rtr_id[module_idx];
sprintf(initiator_name, "TPC_%u", module_idx);
break;
case RAZWI_MME:
sprintf(initiator_name, "MME_%u", module_idx);
switch (module_sub_idx) {
case MME_WAP0:
- rtr_id = gaudi2_mme_initiator_rtr_id[module_idx].wap0;
+ hbw_rtr_id = gaudi2_mme_initiator_rtr_id[module_idx].wap0;
break;
case MME_WAP1:
- rtr_id = gaudi2_mme_initiator_rtr_id[module_idx].wap1;
+ hbw_rtr_id = gaudi2_mme_initiator_rtr_id[module_idx].wap1;
break;
case MME_WRITE:
- rtr_id = gaudi2_mme_initiator_rtr_id[module_idx].write;
+ hbw_rtr_id = gaudi2_mme_initiator_rtr_id[module_idx].write;
break;
case MME_READ:
- rtr_id = gaudi2_mme_initiator_rtr_id[module_idx].read;
+ hbw_rtr_id = gaudi2_mme_initiator_rtr_id[module_idx].read;
break;
case MME_SBTE0:
- rtr_id = gaudi2_mme_initiator_rtr_id[module_idx].sbte0;
+ hbw_rtr_id = gaudi2_mme_initiator_rtr_id[module_idx].sbte0;
break;
case MME_SBTE1:
- rtr_id = gaudi2_mme_initiator_rtr_id[module_idx].sbte1;
+ hbw_rtr_id = gaudi2_mme_initiator_rtr_id[module_idx].sbte1;
break;
case MME_SBTE2:
- rtr_id = gaudi2_mme_initiator_rtr_id[module_idx].sbte2;
+ hbw_rtr_id = gaudi2_mme_initiator_rtr_id[module_idx].sbte2;
break;
case MME_SBTE3:
- rtr_id = gaudi2_mme_initiator_rtr_id[module_idx].sbte3;
+ hbw_rtr_id = gaudi2_mme_initiator_rtr_id[module_idx].sbte3;
break;
case MME_SBTE4:
- rtr_id = gaudi2_mme_initiator_rtr_id[module_idx].sbte4;
+ hbw_rtr_id = gaudi2_mme_initiator_rtr_id[module_idx].sbte4;
break;
default:
return;
}
+ lbw_rtr_id = hbw_rtr_id;
break;
case RAZWI_EDMA:
- sft_id = gaudi2_edma_initiator_sft_id[module_idx].interface_id;
- dcore_id = gaudi2_edma_initiator_sft_id[module_idx].dcore_id;
+ hbw_rtr_mstr_if_base_addr = gaudi2_edma_initiator_hbw_sft[module_idx];
+ dcore_id = module_idx / NUM_OF_EDMA_PER_DCORE;
+ /* SFT has separate MSTR_IF for LBW, only there we can
+ * read the LBW razwi related registers
+ */
+ lbw_rtr_mstr_if_base_addr = mmSFT0_LBW_RTR_IF_MSTR_IF_RR_SHRD_HBW_BASE +
+ dcore_id * SFT_DCORE_OFFSET;
via_sft = true;
sprintf(initiator_name, "EDMA_%u", module_idx);
break;
case RAZWI_PDMA:
- rtr_id = gaudi2_pdma_initiator_rtr_id[module_idx];
+ hbw_rtr_id = gaudi2_pdma_initiator_hbw_rtr_id[module_idx];
+ lbw_rtr_id = gaudi2_pdma_initiator_lbw_rtr_id[module_idx];
sprintf(initiator_name, "PDMA_%u", module_idx);
break;
case RAZWI_NIC:
- rtr_id = gaudi2_nic_initiator_rtr_id[module_idx];
+ hbw_rtr_id = gaudi2_nic_initiator_hbw_rtr_id[module_idx];
+ lbw_rtr_id = gaudi2_nic_initiator_lbw_rtr_id[module_idx];
sprintf(initiator_name, "NIC_%u", module_idx);
break;
case RAZWI_DEC:
- rtr_id = gaudi2_dec_initiator_rtr_id[module_idx];
+ hbw_rtr_id = gaudi2_dec_initiator_hbw_rtr_id[module_idx];
+ lbw_rtr_id = gaudi2_dec_initiator_lbw_rtr_id[module_idx];
sprintf(initiator_name, "DEC_%u", module_idx);
break;
case RAZWI_ROT:
- rtr_id = gaudi2_rot_initiator_rtr_id[module_idx];
+ hbw_rtr_id = gaudi2_rot_initiator_hbw_rtr_id[module_idx];
+ lbw_rtr_id = gaudi2_rot_initiator_lbw_rtr_id[module_idx];
sprintf(initiator_name, "ROT_%u", module_idx);
break;
default:
return;
}
- if (!read_razwi_regs) {
- if (le32_to_cpu(razwi_info->razwi_happened_mask) & RAZWI_HAPPENED_HBW) {
- hbw_shrd_aw = le32_to_cpu(razwi_info->razwi_happened_mask) &
- RAZWI_HAPPENED_AW;
- hbw_shrd_ar = le32_to_cpu(razwi_info->razwi_happened_mask) &
- RAZWI_HAPPENED_AR;
- } else if (le32_to_cpu(razwi_info->razwi_happened_mask) & RAZWI_HAPPENED_LBW) {
- lbw_shrd_aw = le32_to_cpu(razwi_info->razwi_happened_mask) &
- RAZWI_HAPPENED_AW;
- lbw_shrd_ar = le32_to_cpu(razwi_info->razwi_happened_mask) &
- RAZWI_HAPPENED_AR;
- }
- rtr_mstr_if_base_addr = 0;
-
- goto dump_info;
- }
-
/* Find router mstr_if register base */
- if (via_sft) {
- rtr_mstr_if_base_addr = mmSFT0_HBW_RTR_IF0_RTR_CTRL_BASE +
- dcore_id * SFT_DCORE_OFFSET +
- sft_id * SFT_IF_OFFSET +
- RTR_MSTR_IF_OFFSET;
- } else {
- dcore_id = rtr_id / NUM_OF_RTR_PER_DCORE;
- dcore_rtr_id = rtr_id % NUM_OF_RTR_PER_DCORE;
- rtr_mstr_if_base_addr = mmDCORE0_RTR0_CTRL_BASE +
+ if (!via_sft) {
+ dcore_id = hbw_rtr_id / NUM_OF_RTR_PER_DCORE;
+ dcore_rtr_id = hbw_rtr_id % NUM_OF_RTR_PER_DCORE;
+ hbw_rtr_mstr_if_base_addr = mmDCORE0_RTR0_CTRL_BASE +
dcore_id * DCORE_OFFSET +
dcore_rtr_id * DCORE_RTR_OFFSET +
RTR_MSTR_IF_OFFSET;
+ lbw_rtr_mstr_if_base_addr = hbw_rtr_mstr_if_base_addr +
+ (((s32)lbw_rtr_id - hbw_rtr_id) * DCORE_RTR_OFFSET);
}
/* Find out event cause by reading "RAZWI_HAPPENED" registers */
- hbw_shrd_aw = RREG32(rtr_mstr_if_base_addr + RR_SHRD_HBW_AW_RAZWI_HAPPENED);
-
- hbw_shrd_ar = RREG32(rtr_mstr_if_base_addr + RR_SHRD_HBW_AR_RAZWI_HAPPENED);
-
- if (via_sft) {
- /* SFT has separate MSTR_IF for LBW, only there we can
- * read the LBW razwi related registers
- */
- u64 base;
-
- base = mmSFT0_HBW_RTR_IF0_RTR_CTRL_BASE + dcore_id * SFT_DCORE_OFFSET +
- RTR_LBW_MSTR_IF_OFFSET;
-
- lbw_shrd_aw = RREG32(base + RR_SHRD_LBW_AW_RAZWI_HAPPENED);
-
- lbw_shrd_ar = RREG32(base + RR_SHRD_LBW_AR_RAZWI_HAPPENED);
- } else {
- lbw_shrd_aw = RREG32(rtr_mstr_if_base_addr + RR_SHRD_LBW_AW_RAZWI_HAPPENED);
-
- lbw_shrd_ar = RREG32(rtr_mstr_if_base_addr + RR_SHRD_LBW_AR_RAZWI_HAPPENED);
- }
-
-dump_info:
- /* check if there is no RR razwi indication at all */
- if (!hbw_shrd_aw && !hbw_shrd_ar && !lbw_shrd_aw && !lbw_shrd_ar)
- return;
+ hbw_shrd_aw = RREG32(hbw_rtr_mstr_if_base_addr + RR_SHRD_HBW_AW_RAZWI_HAPPENED);
+ hbw_shrd_ar = RREG32(hbw_rtr_mstr_if_base_addr + RR_SHRD_HBW_AR_RAZWI_HAPPENED);
+ lbw_shrd_aw = RREG32(lbw_rtr_mstr_if_base_addr + RR_SHRD_LBW_AW_RAZWI_HAPPENED);
+ lbw_shrd_ar = RREG32(lbw_rtr_mstr_if_base_addr + RR_SHRD_LBW_AR_RAZWI_HAPPENED);
eng_id = gaudi2_razwi_calc_engine_id(hdev, module, module_idx);
if (hbw_shrd_aw) {
- gaudi2_razwi_rr_hbw_shared_printf_info(hdev, rtr_mstr_if_base_addr, true,
- initiator_name, read_razwi_regs, razwi_info,
- eng_id, event_mask);
+ gaudi2_razwi_rr_hbw_shared_printf_info(hdev, hbw_rtr_mstr_if_base_addr, true,
+ initiator_name, eng_id, event_mask);
/* Clear event indication */
- if (read_razwi_regs)
- WREG32(rtr_mstr_if_base_addr + RR_SHRD_HBW_AW_RAZWI_HAPPENED, hbw_shrd_aw);
+ WREG32(hbw_rtr_mstr_if_base_addr + RR_SHRD_HBW_AW_RAZWI_HAPPENED, hbw_shrd_aw);
}
if (hbw_shrd_ar) {
- gaudi2_razwi_rr_hbw_shared_printf_info(hdev, rtr_mstr_if_base_addr, false,
- initiator_name, read_razwi_regs, razwi_info,
- eng_id, event_mask);
+ gaudi2_razwi_rr_hbw_shared_printf_info(hdev, hbw_rtr_mstr_if_base_addr, false,
+ initiator_name, eng_id, event_mask);
/* Clear event indication */
- if (read_razwi_regs)
- WREG32(rtr_mstr_if_base_addr + RR_SHRD_HBW_AR_RAZWI_HAPPENED, hbw_shrd_ar);
+ WREG32(hbw_rtr_mstr_if_base_addr + RR_SHRD_HBW_AR_RAZWI_HAPPENED, hbw_shrd_ar);
}
if (lbw_shrd_aw) {
- gaudi2_razwi_rr_lbw_shared_printf_info(hdev, rtr_mstr_if_base_addr, true,
- initiator_name, read_razwi_regs, razwi_info,
- eng_id, event_mask);
+ gaudi2_razwi_rr_lbw_shared_printf_info(hdev, lbw_rtr_mstr_if_base_addr, true,
+ initiator_name, eng_id, event_mask);
/* Clear event indication */
- if (read_razwi_regs)
- WREG32(rtr_mstr_if_base_addr + RR_SHRD_LBW_AW_RAZWI_HAPPENED, lbw_shrd_aw);
+ WREG32(lbw_rtr_mstr_if_base_addr + RR_SHRD_LBW_AW_RAZWI_HAPPENED, lbw_shrd_aw);
}
if (lbw_shrd_ar) {
- gaudi2_razwi_rr_lbw_shared_printf_info(hdev, rtr_mstr_if_base_addr, false,
- initiator_name, read_razwi_regs, razwi_info,
- eng_id, event_mask);
+ gaudi2_razwi_rr_lbw_shared_printf_info(hdev, lbw_rtr_mstr_if_base_addr, false,
+ initiator_name, eng_id, event_mask);
/* Clear event indication */
- if (read_razwi_regs)
- WREG32(rtr_mstr_if_base_addr + RR_SHRD_LBW_AR_RAZWI_HAPPENED, lbw_shrd_ar);
+ WREG32(lbw_rtr_mstr_if_base_addr + RR_SHRD_LBW_AR_RAZWI_HAPPENED, lbw_shrd_ar);
}
}
@@ -7352,42 +7492,38 @@ static void gaudi2_check_if_razwi_happened(struct hl_device *hdev)
/* check all TPCs */
for (mod_idx = 0 ; mod_idx < (NUM_OF_TPC_PER_DCORE * NUM_OF_DCORES + 1) ; mod_idx++) {
if (prop->tpc_enabled_mask & BIT(mod_idx))
- gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_TPC, mod_idx, 0, NULL,
- NULL);
+ gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_TPC, mod_idx, 0, NULL);
}
/* check all MMEs */
for (mod_idx = 0 ; mod_idx < (NUM_OF_MME_PER_DCORE * NUM_OF_DCORES) ; mod_idx++)
for (sub_mod = MME_WAP0 ; sub_mod < MME_INITIATORS_MAX ; sub_mod++)
gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_MME, mod_idx,
- sub_mod, NULL, NULL);
+ sub_mod, NULL);
/* check all EDMAs */
for (mod_idx = 0 ; mod_idx < (NUM_OF_EDMA_PER_DCORE * NUM_OF_DCORES) ; mod_idx++)
if (prop->edma_enabled_mask & BIT(mod_idx))
- gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_EDMA, mod_idx, 0, NULL,
- NULL);
+ gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_EDMA, mod_idx, 0, NULL);
/* check all PDMAs */
for (mod_idx = 0 ; mod_idx < NUM_OF_PDMA ; mod_idx++)
- gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_PDMA, mod_idx, 0, NULL,
- NULL);
+ gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_PDMA, mod_idx, 0, NULL);
/* check all NICs */
for (mod_idx = 0 ; mod_idx < NIC_NUMBER_OF_PORTS ; mod_idx++)
if (hdev->nic_ports_mask & BIT(mod_idx))
gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_NIC, mod_idx >> 1, 0,
- NULL, NULL);
+ NULL);
/* check all DECs */
for (mod_idx = 0 ; mod_idx < NUMBER_OF_DEC ; mod_idx++)
if (prop->decoder_enabled_mask & BIT(mod_idx))
- gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_DEC, mod_idx, 0, NULL,
- NULL);
+ gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_DEC, mod_idx, 0, NULL);
/* check all ROTs */
for (mod_idx = 0 ; mod_idx < NUM_OF_ROT ; mod_idx++)
- gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_ROT, mod_idx, 0, NULL, NULL);
+ gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_ROT, mod_idx, 0, NULL);
}
static const char *gaudi2_get_initiators_name(u32 rtr_id)
@@ -7645,19 +7781,19 @@ static void gaudi2_razwi_unmapped_addr_lbw_printf_info(struct hl_device *hdev, u
u64 *event_mask)
{
u16 engines[HL_RAZWI_MAX_NUM_OF_ENGINES_PER_RTR], num_of_eng;
- u32 razwi_addr;
+ u64 razwi_addr = CFG_BASE;
u8 rd_wr_flag;
num_of_eng = gaudi2_get_razwi_initiators(rtr_id, &engines[0]);
if (is_write) {
- razwi_addr = RREG32(rtr_ctrl_base_addr + DEC_RAZWI_LBW_AW_ADDR);
+ razwi_addr += RREG32(rtr_ctrl_base_addr + DEC_RAZWI_LBW_AW_ADDR);
rd_wr_flag = HL_RAZWI_WRITE;
/* Clear set indication */
WREG32(rtr_ctrl_base_addr + DEC_RAZWI_LBW_AW_SET, 0x1);
} else {
- razwi_addr = RREG32(rtr_ctrl_base_addr + DEC_RAZWI_LBW_AR_ADDR);
+ razwi_addr += RREG32(rtr_ctrl_base_addr + DEC_RAZWI_LBW_AR_ADDR);
rd_wr_flag = HL_RAZWI_READ;
/* Clear set indication */
@@ -7667,7 +7803,7 @@ static void gaudi2_razwi_unmapped_addr_lbw_printf_info(struct hl_device *hdev, u
hl_handle_razwi(hdev, razwi_addr, &engines[0], num_of_eng, rd_wr_flag | HL_RAZWI_LBW,
event_mask);
dev_err_ratelimited(hdev->dev,
- "RAZWI PSOC unmapped LBW %s error, rtr id %u, address %#x\n",
+ "RAZWI PSOC unmapped LBW %s error, rtr id %u, address 0x%llX\n",
is_write ? "WR" : "RD", rtr_id, razwi_addr);
dev_err_ratelimited(hdev->dev,
@@ -7675,17 +7811,17 @@ static void gaudi2_razwi_unmapped_addr_lbw_printf_info(struct hl_device *hdev, u
}
/* PSOC RAZWI interrupt occurs only when trying to access a bad address */
-static void gaudi2_ack_psoc_razwi_event_handler(struct hl_device *hdev, u64 *event_mask)
+static int gaudi2_ack_psoc_razwi_event_handler(struct hl_device *hdev, u64 *event_mask)
{
u32 hbw_aw_set, hbw_ar_set, lbw_aw_set, lbw_ar_set, rtr_id, dcore_id, dcore_rtr_id, xy,
- razwi_mask_info, razwi_intr = 0;
+ razwi_mask_info, razwi_intr = 0, error_count = 0;
int rtr_map_arr_len = NUM_OF_RTR_PER_DCORE * NUM_OF_DCORES;
u64 rtr_ctrl_base_addr;
if (hdev->pldm || !(hdev->fw_components & FW_TYPE_LINUX)) {
razwi_intr = RREG32(mmPSOC_GLOBAL_CONF_RAZWI_INTERRUPT);
if (!razwi_intr)
- return;
+ return 0;
}
razwi_mask_info = RREG32(mmPSOC_GLOBAL_CONF_RAZWI_MASK_INFO);
@@ -7743,33 +7879,41 @@ static void gaudi2_ack_psoc_razwi_event_handler(struct hl_device *hdev, u64 *eve
gaudi2_razwi_unmapped_addr_lbw_printf_info(hdev, rtr_id,
rtr_ctrl_base_addr, false, event_mask);
+ error_count++;
+
clear:
/* Clear Interrupts only on pldm or if f/w doesn't handle interrupts */
if (hdev->pldm || !(hdev->fw_components & FW_TYPE_LINUX))
WREG32(mmPSOC_GLOBAL_CONF_RAZWI_INTERRUPT, razwi_intr);
+
+ return error_count;
}
-static void _gaudi2_handle_qm_sei_err(struct hl_device *hdev, u64 qman_base)
+static int _gaudi2_handle_qm_sei_err(struct hl_device *hdev, u64 qman_base, u16 event_type)
{
- u32 i, sts_val, sts_clr_val = 0;
+ u32 i, sts_val, sts_clr_val = 0, error_count = 0;
sts_val = RREG32(qman_base + QM_SEI_STATUS_OFFSET);
for (i = 0 ; i < GAUDI2_NUM_OF_QM_SEI_ERR_CAUSE ; i++) {
if (sts_val & BIT(i)) {
- dev_err_ratelimited(hdev->dev, "QM SEI. err cause: %s\n",
- gaudi2_qm_sei_error_cause[i]);
+ gaudi2_print_event(hdev, event_type, true,
+ "err cause: %s", gaudi2_qm_sei_error_cause[i]);
sts_clr_val |= BIT(i);
+ error_count++;
}
}
WREG32(qman_base + QM_SEI_STATUS_OFFSET, sts_clr_val);
+
+ return error_count;
}
-static void gaudi2_handle_qm_sei_err(struct hl_device *hdev, u16 event_type,
- struct hl_eq_razwi_info *razwi_info, u64 *event_mask)
+static int gaudi2_handle_qm_sei_err(struct hl_device *hdev, u16 event_type,
+ bool extended_err_check, u64 *event_mask)
{
enum razwi_event_sources module;
+ u32 error_count = 0;
u64 qman_base;
u8 index;
@@ -7808,26 +7952,30 @@ static void gaudi2_handle_qm_sei_err(struct hl_device *hdev, u16 event_type,
module = RAZWI_ROT;
break;
default:
- return;
+ return 0;
}
- _gaudi2_handle_qm_sei_err(hdev, qman_base);
+ error_count = _gaudi2_handle_qm_sei_err(hdev, qman_base, event_type);
/* There is a single event per NIC macro, so should check its both QMAN blocks */
if (event_type >= GAUDI2_EVENT_NIC0_AXI_ERROR_RESPONSE &&
event_type <= GAUDI2_EVENT_NIC11_AXI_ERROR_RESPONSE)
- _gaudi2_handle_qm_sei_err(hdev, qman_base + NIC_QM_OFFSET);
+ error_count += _gaudi2_handle_qm_sei_err(hdev,
+ qman_base + NIC_QM_OFFSET, event_type);
- /* check if RAZWI happened */
- if (razwi_info)
- gaudi2_ack_module_razwi_event_handler(hdev, module, 0, 0, razwi_info, event_mask);
+ if (extended_err_check) {
+ /* check if RAZWI happened */
+ gaudi2_ack_module_razwi_event_handler(hdev, module, 0, 0, event_mask);
+ hl_check_for_glbl_errors(hdev);
+ }
+
+ return error_count;
}
-static void gaudi2_handle_qman_err(struct hl_device *hdev, u16 event_type)
+static int gaudi2_handle_qman_err(struct hl_device *hdev, u16 event_type, u64 *event_mask)
{
- u32 qid_base;
+ u32 qid_base, error_count = 0;
u64 qman_base;
- char desc[32];
u8 index;
switch (event_type) {
@@ -7835,194 +7983,207 @@ static void gaudi2_handle_qman_err(struct hl_device *hdev, u16 event_type)
index = event_type - GAUDI2_EVENT_TPC0_QM;
qid_base = GAUDI2_QUEUE_ID_DCORE0_TPC_0_0 + index * QMAN_STREAMS;
qman_base = mmDCORE0_TPC0_QM_BASE + index * DCORE_TPC_OFFSET;
- snprintf(desc, ARRAY_SIZE(desc), "DCORE0_TPC%d_QM", index);
break;
case GAUDI2_EVENT_TPC6_QM ... GAUDI2_EVENT_TPC11_QM:
index = event_type - GAUDI2_EVENT_TPC6_QM;
qid_base = GAUDI2_QUEUE_ID_DCORE1_TPC_0_0 + index * QMAN_STREAMS;
qman_base = mmDCORE1_TPC0_QM_BASE + index * DCORE_TPC_OFFSET;
- snprintf(desc, ARRAY_SIZE(desc), "DCORE1_TPC%d_QM", index);
break;
case GAUDI2_EVENT_TPC12_QM ... GAUDI2_EVENT_TPC17_QM:
index = event_type - GAUDI2_EVENT_TPC12_QM;
qid_base = GAUDI2_QUEUE_ID_DCORE2_TPC_0_0 + index * QMAN_STREAMS;
qman_base = mmDCORE2_TPC0_QM_BASE + index * DCORE_TPC_OFFSET;
- snprintf(desc, ARRAY_SIZE(desc), "DCORE2_TPC%d_QM", index);
break;
case GAUDI2_EVENT_TPC18_QM ... GAUDI2_EVENT_TPC23_QM:
index = event_type - GAUDI2_EVENT_TPC18_QM;
qid_base = GAUDI2_QUEUE_ID_DCORE3_TPC_0_0 + index * QMAN_STREAMS;
qman_base = mmDCORE3_TPC0_QM_BASE + index * DCORE_TPC_OFFSET;
- snprintf(desc, ARRAY_SIZE(desc), "DCORE3_TPC%d_QM", index);
break;
case GAUDI2_EVENT_TPC24_QM:
qid_base = GAUDI2_QUEUE_ID_DCORE0_TPC_6_0;
qman_base = mmDCORE0_TPC6_QM_BASE;
- snprintf(desc, ARRAY_SIZE(desc), "DCORE0_TPC6_QM");
break;
case GAUDI2_EVENT_MME0_QM:
qid_base = GAUDI2_QUEUE_ID_DCORE0_MME_0_0;
qman_base = mmDCORE0_MME_QM_BASE;
- snprintf(desc, ARRAY_SIZE(desc), "DCORE0_MME_QM");
break;
case GAUDI2_EVENT_MME1_QM:
qid_base = GAUDI2_QUEUE_ID_DCORE1_MME_0_0;
qman_base = mmDCORE1_MME_QM_BASE;
- snprintf(desc, ARRAY_SIZE(desc), "DCORE1_MME_QM");
break;
case GAUDI2_EVENT_MME2_QM:
qid_base = GAUDI2_QUEUE_ID_DCORE2_MME_0_0;
qman_base = mmDCORE2_MME_QM_BASE;
- snprintf(desc, ARRAY_SIZE(desc), "DCORE2_MME_QM");
break;
case GAUDI2_EVENT_MME3_QM:
qid_base = GAUDI2_QUEUE_ID_DCORE3_MME_0_0;
qman_base = mmDCORE3_MME_QM_BASE;
- snprintf(desc, ARRAY_SIZE(desc), "DCORE3_MME_QM");
break;
case GAUDI2_EVENT_HDMA0_QM:
+ index = 0;
qid_base = GAUDI2_QUEUE_ID_DCORE0_EDMA_0_0;
qman_base = mmDCORE0_EDMA0_QM_BASE;
- snprintf(desc, ARRAY_SIZE(desc), "DCORE0_EDMA0_QM");
break;
case GAUDI2_EVENT_HDMA1_QM:
+ index = 1;
qid_base = GAUDI2_QUEUE_ID_DCORE0_EDMA_1_0;
qman_base = mmDCORE0_EDMA1_QM_BASE;
- snprintf(desc, ARRAY_SIZE(desc), "DCORE0_EDMA1_QM");
break;
case GAUDI2_EVENT_HDMA2_QM:
+ index = 2;
qid_base = GAUDI2_QUEUE_ID_DCORE1_EDMA_0_0;
qman_base = mmDCORE1_EDMA0_QM_BASE;
- snprintf(desc, ARRAY_SIZE(desc), "DCORE1_EDMA0_QM");
break;
case GAUDI2_EVENT_HDMA3_QM:
+ index = 3;
qid_base = GAUDI2_QUEUE_ID_DCORE1_EDMA_1_0;
qman_base = mmDCORE1_EDMA1_QM_BASE;
- snprintf(desc, ARRAY_SIZE(desc), "DCORE1_EDMA1_QM");
break;
case GAUDI2_EVENT_HDMA4_QM:
+ index = 4;
qid_base = GAUDI2_QUEUE_ID_DCORE2_EDMA_0_0;
qman_base = mmDCORE2_EDMA0_QM_BASE;
- snprintf(desc, ARRAY_SIZE(desc), "DCORE2_EDMA0_QM");
break;
case GAUDI2_EVENT_HDMA5_QM:
+ index = 5;
qid_base = GAUDI2_QUEUE_ID_DCORE2_EDMA_1_0;
qman_base = mmDCORE2_EDMA1_QM_BASE;
- snprintf(desc, ARRAY_SIZE(desc), "DCORE2_EDMA1_QM");
break;
case GAUDI2_EVENT_HDMA6_QM:
+ index = 6;
qid_base = GAUDI2_QUEUE_ID_DCORE3_EDMA_0_0;
qman_base = mmDCORE3_EDMA0_QM_BASE;
- snprintf(desc, ARRAY_SIZE(desc), "DCORE3_EDMA0_QM");
break;
case GAUDI2_EVENT_HDMA7_QM:
+ index = 7;
qid_base = GAUDI2_QUEUE_ID_DCORE3_EDMA_1_0;
qman_base = mmDCORE3_EDMA1_QM_BASE;
- snprintf(desc, ARRAY_SIZE(desc), "DCORE3_EDMA1_QM");
break;
case GAUDI2_EVENT_PDMA0_QM:
qid_base = GAUDI2_QUEUE_ID_PDMA_0_0;
qman_base = mmPDMA0_QM_BASE;
- snprintf(desc, ARRAY_SIZE(desc), "PDMA0_QM");
break;
case GAUDI2_EVENT_PDMA1_QM:
qid_base = GAUDI2_QUEUE_ID_PDMA_1_0;
qman_base = mmPDMA1_QM_BASE;
- snprintf(desc, ARRAY_SIZE(desc), "PDMA1_QM");
break;
case GAUDI2_EVENT_ROTATOR0_ROT0_QM:
qid_base = GAUDI2_QUEUE_ID_ROT_0_0;
qman_base = mmROT0_QM_BASE;
- snprintf(desc, ARRAY_SIZE(desc), "ROTATOR0_QM");
break;
case GAUDI2_EVENT_ROTATOR1_ROT1_QM:
qid_base = GAUDI2_QUEUE_ID_ROT_1_0;
qman_base = mmROT1_QM_BASE;
- snprintf(desc, ARRAY_SIZE(desc), "ROTATOR1_QM");
break;
default:
- return;
+ return 0;
}
- gaudi2_handle_qman_err_generic(hdev, desc, qman_base, qid_base);
+ error_count = gaudi2_handle_qman_err_generic(hdev, event_type, qman_base, qid_base);
/* Handle EDMA QM SEI here because there is no AXI error response event for EDMA */
- if (event_type >= GAUDI2_EVENT_HDMA2_QM && event_type <= GAUDI2_EVENT_HDMA5_QM)
- _gaudi2_handle_qm_sei_err(hdev, qman_base);
+ if (event_type >= GAUDI2_EVENT_HDMA2_QM && event_type <= GAUDI2_EVENT_HDMA5_QM) {
+ error_count += _gaudi2_handle_qm_sei_err(hdev, qman_base, event_type);
+ gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_EDMA, index, 0, event_mask);
+ }
+
+ hl_check_for_glbl_errors(hdev);
+
+ return error_count;
}
-static void gaudi2_handle_arc_farm_sei_err(struct hl_device *hdev)
+static int gaudi2_handle_arc_farm_sei_err(struct hl_device *hdev, u16 event_type)
{
- u32 i, sts_val, sts_clr_val = 0;
+ u32 i, sts_val, sts_clr_val = 0, error_count = 0;
sts_val = RREG32(mmARC_FARM_ARC0_AUX_ARC_SEI_INTR_STS);
for (i = 0 ; i < GAUDI2_NUM_OF_ARC_SEI_ERR_CAUSE ; i++) {
if (sts_val & BIT(i)) {
- dev_err_ratelimited(hdev->dev, "ARC SEI. err cause: %s\n",
- gaudi2_arc_sei_error_cause[i]);
+ gaudi2_print_event(hdev, event_type, true,
+ "err cause: %s", gaudi2_arc_sei_error_cause[i]);
sts_clr_val |= BIT(i);
+ error_count++;
}
}
+ hl_check_for_glbl_errors(hdev);
+
WREG32(mmARC_FARM_ARC0_AUX_ARC_SEI_INTR_CLR, sts_clr_val);
+
+ return error_count;
}
-static void gaudi2_handle_cpu_sei_err(struct hl_device *hdev)
+static int gaudi2_handle_cpu_sei_err(struct hl_device *hdev, u16 event_type)
{
- u32 i, sts_val, sts_clr_val = 0;
+ u32 i, sts_val, sts_clr_val = 0, error_count = 0;
sts_val = RREG32(mmCPU_IF_CPU_SEI_INTR_STS);
for (i = 0 ; i < GAUDI2_NUM_OF_CPU_SEI_ERR_CAUSE ; i++) {
if (sts_val & BIT(i)) {
- dev_err_ratelimited(hdev->dev, "CPU SEI. err cause: %s\n",
- gaudi2_cpu_sei_error_cause[i]);
+ gaudi2_print_event(hdev, event_type, true,
+ "err cause: %s", gaudi2_cpu_sei_error_cause[i]);
sts_clr_val |= BIT(i);
+ error_count++;
}
}
+ hl_check_for_glbl_errors(hdev);
+
WREG32(mmCPU_IF_CPU_SEI_INTR_CLR, sts_clr_val);
+
+ return error_count;
}
-static void gaudi2_handle_rot_err(struct hl_device *hdev, u8 rot_index,
+static int gaudi2_handle_rot_err(struct hl_device *hdev, u8 rot_index, u16 event_type,
struct hl_eq_razwi_with_intr_cause *razwi_with_intr_cause,
u64 *event_mask)
{
u64 intr_cause_data = le64_to_cpu(razwi_with_intr_cause->intr_cause.intr_cause_data);
+ u32 error_count = 0;
int i;
for (i = 0 ; i < GAUDI2_NUM_OF_ROT_ERR_CAUSE ; i++)
- if (intr_cause_data & BIT(i))
- dev_err_ratelimited(hdev->dev, "ROT%u. err cause: %s\n",
- rot_index, guadi2_rot_error_cause[i]);
+ if (intr_cause_data & BIT(i)) {
+ gaudi2_print_event(hdev, event_type, true,
+ "err cause: %s", guadi2_rot_error_cause[i]);
+ error_count++;
+ }
/* check if RAZWI happened */
- gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_ROT, rot_index, 0,
- &razwi_with_intr_cause->razwi_info, event_mask);
+ gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_ROT, rot_index, 0, event_mask);
+ hl_check_for_glbl_errors(hdev);
+
+ return error_count;
}
-static void gaudi2_tpc_ack_interrupts(struct hl_device *hdev, u8 tpc_index, char *interrupt_name,
+static int gaudi2_tpc_ack_interrupts(struct hl_device *hdev, u8 tpc_index, u16 event_type,
struct hl_eq_razwi_with_intr_cause *razwi_with_intr_cause,
u64 *event_mask)
{
u64 intr_cause_data = le64_to_cpu(razwi_with_intr_cause->intr_cause.intr_cause_data);
+ u32 error_count = 0;
int i;
for (i = 0 ; i < GAUDI2_NUM_OF_TPC_INTR_CAUSE ; i++)
- if (intr_cause_data & BIT(i))
- dev_err_ratelimited(hdev->dev, "TPC%d_%s interrupt cause: %s\n",
- tpc_index, interrupt_name, gaudi2_tpc_interrupts_cause[i]);
+ if (intr_cause_data & BIT(i)) {
+ gaudi2_print_event(hdev, event_type, true,
+ "interrupt cause: %s", gaudi2_tpc_interrupts_cause[i]);
+ error_count++;
+ }
/* check if RAZWI happened */
- gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_TPC, tpc_index, 0,
- &razwi_with_intr_cause->razwi_info, event_mask);
+ gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_TPC, tpc_index, 0, event_mask);
+ hl_check_for_glbl_errors(hdev);
+
+ return error_count;
}
-static void gaudi2_handle_dec_err(struct hl_device *hdev, u8 dec_index, const char *interrupt_name,
- struct hl_eq_razwi_info *razwi_info, u64 *event_mask)
+static int gaudi2_handle_dec_err(struct hl_device *hdev, u8 dec_index, u16 event_type,
+ u64 *event_mask)
{
- u32 sts_addr, sts_val, sts_clr_val = 0;
+ u32 sts_addr, sts_val, sts_clr_val = 0, error_count = 0;
int i;
if (dec_index < NUM_OF_VDEC_PER_DCORE * NUM_OF_DCORES)
@@ -8039,24 +8200,27 @@ static void gaudi2_handle_dec_err(struct hl_device *hdev, u8 dec_index, const ch
for (i = 0 ; i < GAUDI2_NUM_OF_DEC_ERR_CAUSE ; i++) {
if (sts_val & BIT(i)) {
- dev_err_ratelimited(hdev->dev, "DEC%u_%s err cause: %s\n",
- dec_index, interrupt_name, gaudi2_dec_error_cause[i]);
+ gaudi2_print_event(hdev, event_type, true,
+ "err cause: %s", gaudi2_dec_error_cause[i]);
sts_clr_val |= BIT(i);
+ error_count++;
}
}
/* check if RAZWI happened */
- gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_DEC, dec_index, 0, razwi_info,
- event_mask);
+ gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_DEC, dec_index, 0, event_mask);
+ hl_check_for_glbl_errors(hdev);
/* Write 1 clear errors */
WREG32(sts_addr, sts_clr_val);
+
+ return error_count;
}
-static void gaudi2_handle_mme_err(struct hl_device *hdev, u8 mme_index, const char *interrupt_name,
- struct hl_eq_razwi_info *razwi_info, u64 *event_mask)
+static int gaudi2_handle_mme_err(struct hl_device *hdev, u8 mme_index, u16 event_type,
+ u64 *event_mask)
{
- u32 sts_addr, sts_val, sts_clr_addr, sts_clr_val = 0;
+ u32 sts_addr, sts_val, sts_clr_addr, sts_clr_val = 0, error_count = 0;
int i;
sts_addr = mmDCORE0_MME_CTRL_LO_INTR_CAUSE + DCORE_OFFSET * mme_index;
@@ -8066,35 +8230,45 @@ static void gaudi2_handle_mme_err(struct hl_device *hdev, u8 mme_index, const ch
for (i = 0 ; i < GAUDI2_NUM_OF_MME_ERR_CAUSE ; i++) {
if (sts_val & BIT(i)) {
- dev_err_ratelimited(hdev->dev, "MME%u_%s err cause: %s\n",
- mme_index, interrupt_name, guadi2_mme_error_cause[i]);
+ gaudi2_print_event(hdev, event_type, true,
+ "err cause: %s", guadi2_mme_error_cause[i]);
sts_clr_val |= BIT(i);
+ error_count++;
}
}
/* check if RAZWI happened */
for (i = MME_WRITE ; i < MME_INITIATORS_MAX ; i++)
- gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_MME, mme_index, i, razwi_info,
- event_mask);
+ gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_MME, mme_index, i, event_mask);
+
+ hl_check_for_glbl_errors(hdev);
WREG32(sts_clr_addr, sts_clr_val);
+
+ return error_count;
}
-static void gaudi2_handle_mme_sbte_err(struct hl_device *hdev, u8 mme_index, u8 sbte_index,
+static int gaudi2_handle_mme_sbte_err(struct hl_device *hdev, u16 event_type,
u64 intr_cause_data)
{
- int i;
+ int i, error_count = 0;
for (i = 0 ; i < GAUDI2_NUM_OF_MME_SBTE_ERR_CAUSE ; i++)
- if (intr_cause_data & BIT(i))
- dev_err_ratelimited(hdev->dev, "MME%uSBTE%u_AXI_ERR_RSP err cause: %s\n",
- mme_index, sbte_index, guadi2_mme_sbte_error_cause[i]);
+ if (intr_cause_data & BIT(i)) {
+ gaudi2_print_event(hdev, event_type, true,
+ "err cause: %s", guadi2_mme_sbte_error_cause[i]);
+ error_count++;
+ }
+
+ hl_check_for_glbl_errors(hdev);
+
+ return error_count;
}
-static void gaudi2_handle_mme_wap_err(struct hl_device *hdev, u8 mme_index,
- struct hl_eq_razwi_info *razwi_info, u64 *event_mask)
+static int gaudi2_handle_mme_wap_err(struct hl_device *hdev, u8 mme_index, u16 event_type,
+ u64 *event_mask)
{
- u32 sts_addr, sts_val, sts_clr_addr, sts_clr_val = 0;
+ u32 sts_addr, sts_val, sts_clr_addr, sts_clr_val = 0, error_count = 0;
int i;
sts_addr = mmDCORE0_MME_ACC_INTR_CAUSE + DCORE_OFFSET * mme_index;
@@ -8104,24 +8278,27 @@ static void gaudi2_handle_mme_wap_err(struct hl_device *hdev, u8 mme_index,
for (i = 0 ; i < GAUDI2_NUM_OF_MME_WAP_ERR_CAUSE ; i++) {
if (sts_val & BIT(i)) {
- dev_err_ratelimited(hdev->dev,
- "MME%u_WAP_SOURCE_RESULT_INVALID err cause: %s\n",
- mme_index, guadi2_mme_wap_error_cause[i]);
+ gaudi2_print_event(hdev, event_type, true,
+ "err cause: %s", guadi2_mme_wap_error_cause[i]);
sts_clr_val |= BIT(i);
+ error_count++;
}
}
/* check if RAZWI happened on WAP0/1 */
- gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_MME, mme_index, MME_WAP0, razwi_info,
- event_mask);
- gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_MME, mme_index, MME_WAP1, razwi_info,
- event_mask);
+ gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_MME, mme_index, MME_WAP0, event_mask);
+ gaudi2_ack_module_razwi_event_handler(hdev, RAZWI_MME, mme_index, MME_WAP1, event_mask);
+ hl_check_for_glbl_errors(hdev);
WREG32(sts_clr_addr, sts_clr_val);
+
+ return error_count;
}
-static void gaudi2_handle_kdma_core_event(struct hl_device *hdev, u64 intr_cause_data)
+static int gaudi2_handle_kdma_core_event(struct hl_device *hdev, u16 event_type,
+ u64 intr_cause_data)
{
+ u32 error_count = 0;
int i;
/* If an AXI read or write error is received, an error is reported and
@@ -8130,19 +8307,33 @@ static void gaudi2_handle_kdma_core_event(struct hl_device *hdev, u64 intr_cause
* the actual error caused by a LBW KDMA transaction.
*/
for (i = 0 ; i < GAUDI2_NUM_OF_DMA_CORE_INTR_CAUSE ; i++)
- if (intr_cause_data & BIT(i))
- dev_err_ratelimited(hdev->dev, "kdma core err cause: %s\n",
- gaudi2_kdma_core_interrupts_cause[i]);
+ if (intr_cause_data & BIT(i)) {
+ gaudi2_print_event(hdev, event_type, true,
+ "err cause: %s", gaudi2_kdma_core_interrupts_cause[i]);
+ error_count++;
+ }
+
+ hl_check_for_glbl_errors(hdev);
+
+ return error_count;
}
-static void gaudi2_handle_dma_core_event(struct hl_device *hdev, u64 intr_cause_data)
+static int gaudi2_handle_dma_core_event(struct hl_device *hdev, u16 event_type,
+ u64 intr_cause_data)
{
+ u32 error_count = 0;
int i;
for (i = 0 ; i < GAUDI2_NUM_OF_DMA_CORE_INTR_CAUSE ; i++)
- if (intr_cause_data & BIT(i))
- dev_err_ratelimited(hdev->dev, "dma core err cause: %s\n",
- gaudi2_dma_core_interrupts_cause[i]);
+ if (intr_cause_data & BIT(i)) {
+ gaudi2_print_event(hdev, event_type, true,
+ "err cause: %s", gaudi2_dma_core_interrupts_cause[i]);
+ error_count++;
+ }
+
+ hl_check_for_glbl_errors(hdev);
+
+ return error_count;
}
static void gaudi2_print_pcie_mstr_rr_mstr_if_razwi_info(struct hl_device *hdev, u64 *event_mask)
@@ -8151,86 +8342,98 @@ static void gaudi2_print_pcie_mstr_rr_mstr_if_razwi_info(struct hl_device *hdev,
razwi_happened_addr = mstr_if_base_addr + RR_SHRD_HBW_AW_RAZWI_HAPPENED;
if (RREG32(razwi_happened_addr)) {
- gaudi2_razwi_rr_hbw_shared_printf_info(hdev, mstr_if_base_addr, true, "PCIE", true,
- NULL, GAUDI2_ENGINE_ID_PCIE, event_mask);
+ gaudi2_razwi_rr_hbw_shared_printf_info(hdev, mstr_if_base_addr, true, "PCIE",
+ GAUDI2_ENGINE_ID_PCIE, event_mask);
WREG32(razwi_happened_addr, 0x1);
}
razwi_happened_addr = mstr_if_base_addr + RR_SHRD_HBW_AR_RAZWI_HAPPENED;
if (RREG32(razwi_happened_addr)) {
- gaudi2_razwi_rr_hbw_shared_printf_info(hdev, mstr_if_base_addr, false, "PCIE", true,
- NULL, GAUDI2_ENGINE_ID_PCIE, event_mask);
+ gaudi2_razwi_rr_hbw_shared_printf_info(hdev, mstr_if_base_addr, false, "PCIE",
+ GAUDI2_ENGINE_ID_PCIE, event_mask);
WREG32(razwi_happened_addr, 0x1);
}
razwi_happened_addr = mstr_if_base_addr + RR_SHRD_LBW_AW_RAZWI_HAPPENED;
if (RREG32(razwi_happened_addr)) {
- gaudi2_razwi_rr_lbw_shared_printf_info(hdev, mstr_if_base_addr, true, "PCIE", true,
- NULL, GAUDI2_ENGINE_ID_PCIE, event_mask);
+ gaudi2_razwi_rr_lbw_shared_printf_info(hdev, mstr_if_base_addr, true, "PCIE",
+ GAUDI2_ENGINE_ID_PCIE, event_mask);
WREG32(razwi_happened_addr, 0x1);
}
razwi_happened_addr = mstr_if_base_addr + RR_SHRD_LBW_AR_RAZWI_HAPPENED;
if (RREG32(razwi_happened_addr)) {
- gaudi2_razwi_rr_lbw_shared_printf_info(hdev, mstr_if_base_addr, false, "PCIE", true,
- NULL, GAUDI2_ENGINE_ID_PCIE, event_mask);
+ gaudi2_razwi_rr_lbw_shared_printf_info(hdev, mstr_if_base_addr, false, "PCIE",
+ GAUDI2_ENGINE_ID_PCIE, event_mask);
WREG32(razwi_happened_addr, 0x1);
}
}
-static void gaudi2_print_pcie_addr_dec_info(struct hl_device *hdev, u64 intr_cause_data,
- u64 *event_mask)
+static int gaudi2_print_pcie_addr_dec_info(struct hl_device *hdev, u16 event_type,
+ u64 intr_cause_data, u64 *event_mask)
{
+ u32 error_count = 0;
int i;
for (i = 0 ; i < GAUDI2_NUM_OF_PCIE_ADDR_DEC_ERR_CAUSE ; i++) {
if (!(intr_cause_data & BIT_ULL(i)))
continue;
- dev_err_ratelimited(hdev->dev, "PCIE ADDR DEC Error: %s\n",
- gaudi2_pcie_addr_dec_error_cause[i]);
+ gaudi2_print_event(hdev, event_type, true,
+ "err cause: %s", gaudi2_pcie_addr_dec_error_cause[i]);
+ error_count++;
switch (intr_cause_data & BIT_ULL(i)) {
case PCIE_WRAP_PCIE_IC_SEI_INTR_IND_AXI_LBW_ERR_INTR_MASK:
+ hl_check_for_glbl_errors(hdev);
break;
case PCIE_WRAP_PCIE_IC_SEI_INTR_IND_BAD_ACCESS_INTR_MASK:
gaudi2_print_pcie_mstr_rr_mstr_if_razwi_info(hdev, event_mask);
break;
}
}
+
+ return error_count;
}
-static void gaudi2_handle_pif_fatal(struct hl_device *hdev, u64 intr_cause_data)
+static int gaudi2_handle_pif_fatal(struct hl_device *hdev, u16 event_type,
+ u64 intr_cause_data)
{
+ u32 error_count = 0;
int i;
for (i = 0 ; i < GAUDI2_NUM_OF_PMMU_FATAL_ERR_CAUSE ; i++) {
- if (intr_cause_data & BIT_ULL(i))
- dev_err_ratelimited(hdev->dev, "PMMU PIF err cause: %s\n",
- gaudi2_pmmu_fatal_interrupts_cause[i]);
+ if (intr_cause_data & BIT_ULL(i)) {
+ gaudi2_print_event(hdev, event_type, true,
+ "err cause: %s", gaudi2_pmmu_fatal_interrupts_cause[i]);
+ error_count++;
+ }
}
+
+ return error_count;
}
-static void gaudi2_handle_hif_fatal(struct hl_device *hdev, u16 event_type, u64 intr_cause_data)
+static int gaudi2_handle_hif_fatal(struct hl_device *hdev, u16 event_type, u64 intr_cause_data)
{
- u32 dcore_id, hif_id;
+ u32 error_count = 0;
int i;
- dcore_id = (event_type - GAUDI2_EVENT_HIF0_FATAL) / 4;
- hif_id = (event_type - GAUDI2_EVENT_HIF0_FATAL) % 4;
-
for (i = 0 ; i < GAUDI2_NUM_OF_HIF_FATAL_ERR_CAUSE ; i++) {
- if (intr_cause_data & BIT_ULL(i))
- dev_err_ratelimited(hdev->dev, "DCORE%u_HIF%u: %s\n", dcore_id, hif_id,
- gaudi2_hif_fatal_interrupts_cause[i]);
+ if (intr_cause_data & BIT_ULL(i)) {
+ gaudi2_print_event(hdev, event_type, true,
+ "err cause: %s", gaudi2_hif_fatal_interrupts_cause[i]);
+ error_count++;
+ }
}
+
+ return error_count;
}
static void gaudi2_handle_page_error(struct hl_device *hdev, u64 mmu_base, bool is_pmmu,
u64 *event_mask)
{
- u32 valid, val;
+ u32 valid, val, axid_l, axid_h;
u64 addr;
valid = RREG32(mmu_base + MMU_OFFSET(mmDCORE0_HMMU0_MMU_ACCESS_PAGE_ERROR_VALID));
@@ -8243,8 +8446,11 @@ static void gaudi2_handle_page_error(struct hl_device *hdev, u64 mmu_base, bool
addr <<= 32;
addr |= RREG32(mmu_base + MMU_OFFSET(mmDCORE0_HMMU0_MMU_PAGE_ERROR_CAPTURE_VA));
- dev_err_ratelimited(hdev->dev, "%s page fault on va 0x%llx\n",
- is_pmmu ? "PMMU" : "HMMU", addr);
+ axid_l = RREG32(mmu_base + MMU_OFFSET(mmDCORE0_HMMU0_MMU_PAGE_FAULT_ID_LSB));
+ axid_h = RREG32(mmu_base + MMU_OFFSET(mmDCORE0_HMMU0_MMU_PAGE_FAULT_ID_MSB));
+
+ dev_err_ratelimited(hdev->dev, "%s page fault on va 0x%llx, transaction id 0x%llX\n",
+ is_pmmu ? "PMMU" : "HMMU", addr, ((u64)axid_h << 32) + axid_l);
hl_handle_page_fault(hdev, addr, 0, is_pmmu, event_mask);
WREG32(mmu_base + MMU_OFFSET(mmDCORE0_HMMU0_MMU_PAGE_ERROR_CAPTURE), 0);
@@ -8270,18 +8476,18 @@ static void gaudi2_handle_access_error(struct hl_device *hdev, u64 mmu_base, boo
WREG32(mmu_base + MMU_OFFSET(mmDCORE0_HMMU0_MMU_ACCESS_ERROR_CAPTURE), 0);
}
-static void gaudi2_handle_mmu_spi_sei_generic(struct hl_device *hdev, const char *mmu_name,
+static int gaudi2_handle_mmu_spi_sei_generic(struct hl_device *hdev, u16 event_type,
u64 mmu_base, bool is_pmmu, u64 *event_mask)
{
- u32 spi_sei_cause, interrupt_clr = 0x0;
+ u32 spi_sei_cause, interrupt_clr = 0x0, error_count = 0;
int i;
spi_sei_cause = RREG32(mmu_base + MMU_SPI_SEI_CAUSE_OFFSET);
for (i = 0 ; i < GAUDI2_NUM_OF_MMU_SPI_SEI_CAUSE ; i++) {
if (spi_sei_cause & BIT(i)) {
- dev_err_ratelimited(hdev->dev, "%s SPI_SEI ERR. err cause: %s\n",
- mmu_name, gaudi2_mmu_spi_sei[i].cause);
+ gaudi2_print_event(hdev, event_type, true,
+ "err cause: %s", gaudi2_mmu_spi_sei[i].cause);
if (i == 0)
gaudi2_handle_page_error(hdev, mmu_base, is_pmmu, event_mask);
@@ -8290,6 +8496,8 @@ static void gaudi2_handle_mmu_spi_sei_generic(struct hl_device *hdev, const char
if (gaudi2_mmu_spi_sei[i].clear_bit >= 0)
interrupt_clr |= BIT(gaudi2_mmu_spi_sei[i].clear_bit);
+
+ error_count++;
}
}
@@ -8298,12 +8506,14 @@ static void gaudi2_handle_mmu_spi_sei_generic(struct hl_device *hdev, const char
/* Clear interrupt */
WREG32(mmu_base + MMU_INTERRUPT_CLR_OFFSET, interrupt_clr);
+
+ return error_count;
}
-static void gaudi2_handle_sm_err(struct hl_device *hdev, u8 sm_index)
+static int gaudi2_handle_sm_err(struct hl_device *hdev, u16 event_type, u8 sm_index)
{
- u32 sei_cause_addr, sei_cause_val, sei_cause_cause, sei_cause_log;
- u32 cq_intr_addr, cq_intr_val, cq_intr_queue_index;
+ u32 sei_cause_addr, sei_cause_val, sei_cause_cause, sei_cause_log,
+ cq_intr_addr, cq_intr_val, cq_intr_queue_index, error_count = 0;
int i;
sei_cause_addr = mmDCORE0_SYNC_MNGR_GLBL_SM_SEI_CAUSE + DCORE_OFFSET * sm_index;
@@ -8323,11 +8533,12 @@ static void gaudi2_handle_sm_err(struct hl_device *hdev, u8 sm_index)
if (!(sei_cause_cause & BIT(i)))
continue;
- dev_err_ratelimited(hdev->dev, "SM%u SEI ERR. err cause: %s. %s: 0x%X\n",
- sm_index,
- gaudi2_sm_sei_cause[i].cause_name,
- gaudi2_sm_sei_cause[i].log_name,
- sei_cause_log & gaudi2_sm_sei_cause[i].log_mask);
+ gaudi2_print_event(hdev, event_type, true,
+ "err cause: %s. %s: 0x%X\n",
+ gaudi2_sm_sei_cause[i].cause_name,
+ gaudi2_sm_sei_cause[i].log_name,
+ sei_cause_log);
+ error_count++;
break;
}
@@ -8343,16 +8554,21 @@ static void gaudi2_handle_sm_err(struct hl_device *hdev, u8 sm_index)
dev_err_ratelimited(hdev->dev, "SM%u err. err cause: CQ_INTR. queue index: %u\n",
sm_index, cq_intr_queue_index);
+ error_count++;
/* Clear CQ_INTR */
WREG32(cq_intr_addr, 0);
}
+
+ hl_check_for_glbl_errors(hdev);
+
+ return error_count;
}
-static void gaudi2_handle_mmu_spi_sei_err(struct hl_device *hdev, u16 event_type, u64 *event_mask)
+static int gaudi2_handle_mmu_spi_sei_err(struct hl_device *hdev, u16 event_type, u64 *event_mask)
{
bool is_pmmu = false;
- char desc[32];
+ u32 error_count = 0;
u64 mmu_base;
u8 index;
@@ -8360,54 +8576,49 @@ static void gaudi2_handle_mmu_spi_sei_err(struct hl_device *hdev, u16 event_type
case GAUDI2_EVENT_HMMU0_PAGE_FAULT_OR_WR_PERM ... GAUDI2_EVENT_HMMU3_SECURITY_ERROR:
index = (event_type - GAUDI2_EVENT_HMMU0_PAGE_FAULT_OR_WR_PERM) / 3;
mmu_base = mmDCORE0_HMMU0_MMU_BASE + index * DCORE_HMMU_OFFSET;
- snprintf(desc, ARRAY_SIZE(desc), "DCORE0_HMMU%d", index);
break;
case GAUDI2_EVENT_HMMU_0_AXI_ERR_RSP ... GAUDI2_EVENT_HMMU_3_AXI_ERR_RSP:
index = (event_type - GAUDI2_EVENT_HMMU_0_AXI_ERR_RSP);
mmu_base = mmDCORE0_HMMU0_MMU_BASE + index * DCORE_HMMU_OFFSET;
- snprintf(desc, ARRAY_SIZE(desc), "DCORE0_HMMU%d", index);
break;
case GAUDI2_EVENT_HMMU8_PAGE_FAULT_WR_PERM ... GAUDI2_EVENT_HMMU11_SECURITY_ERROR:
index = (event_type - GAUDI2_EVENT_HMMU8_PAGE_FAULT_WR_PERM) / 3;
mmu_base = mmDCORE1_HMMU0_MMU_BASE + index * DCORE_HMMU_OFFSET;
- snprintf(desc, ARRAY_SIZE(desc), "DCORE1_HMMU%d", index);
break;
case GAUDI2_EVENT_HMMU_8_AXI_ERR_RSP ... GAUDI2_EVENT_HMMU_11_AXI_ERR_RSP:
index = (event_type - GAUDI2_EVENT_HMMU_8_AXI_ERR_RSP);
mmu_base = mmDCORE1_HMMU0_MMU_BASE + index * DCORE_HMMU_OFFSET;
- snprintf(desc, ARRAY_SIZE(desc), "DCORE1_HMMU%d", index);
break;
case GAUDI2_EVENT_HMMU7_PAGE_FAULT_WR_PERM ... GAUDI2_EVENT_HMMU4_SECURITY_ERROR:
index = (event_type - GAUDI2_EVENT_HMMU7_PAGE_FAULT_WR_PERM) / 3;
mmu_base = mmDCORE2_HMMU0_MMU_BASE + index * DCORE_HMMU_OFFSET;
- snprintf(desc, ARRAY_SIZE(desc), "DCORE2_HMMU%d", index);
break;
case GAUDI2_EVENT_HMMU_7_AXI_ERR_RSP ... GAUDI2_EVENT_HMMU_4_AXI_ERR_RSP:
index = (event_type - GAUDI2_EVENT_HMMU_7_AXI_ERR_RSP);
mmu_base = mmDCORE2_HMMU0_MMU_BASE + index * DCORE_HMMU_OFFSET;
- snprintf(desc, ARRAY_SIZE(desc), "DCORE2_HMMU%d", index);
break;
case GAUDI2_EVENT_HMMU15_PAGE_FAULT_WR_PERM ... GAUDI2_EVENT_HMMU12_SECURITY_ERROR:
index = (event_type - GAUDI2_EVENT_HMMU15_PAGE_FAULT_WR_PERM) / 3;
mmu_base = mmDCORE3_HMMU0_MMU_BASE + index * DCORE_HMMU_OFFSET;
- snprintf(desc, ARRAY_SIZE(desc), "DCORE3_HMMU%d", index);
break;
case GAUDI2_EVENT_HMMU_15_AXI_ERR_RSP ... GAUDI2_EVENT_HMMU_12_AXI_ERR_RSP:
index = (event_type - GAUDI2_EVENT_HMMU_15_AXI_ERR_RSP);
mmu_base = mmDCORE3_HMMU0_MMU_BASE + index * DCORE_HMMU_OFFSET;
- snprintf(desc, ARRAY_SIZE(desc), "DCORE3_HMMU%d", index);
break;
case GAUDI2_EVENT_PMMU0_PAGE_FAULT_WR_PERM ... GAUDI2_EVENT_PMMU0_SECURITY_ERROR:
case GAUDI2_EVENT_PMMU_AXI_ERR_RSP_0:
is_pmmu = true;
mmu_base = mmPMMU_HBW_MMU_BASE;
- snprintf(desc, ARRAY_SIZE(desc), "PMMU");
break;
default:
- return;
+ return 0;
}
- gaudi2_handle_mmu_spi_sei_generic(hdev, desc, mmu_base, is_pmmu, event_mask);
+ error_count = gaudi2_handle_mmu_spi_sei_generic(hdev, event_type, mmu_base,
+ is_pmmu, event_mask);
+ hl_check_for_glbl_errors(hdev);
+
+ return error_count;
}
@@ -8527,22 +8738,17 @@ static bool gaudi2_handle_hbm_mc_sei_err(struct hl_device *hdev, u16 event_type,
cause_idx = sei_data->hdr.sei_cause;
if (cause_idx > GAUDI2_NUM_OF_HBM_SEI_CAUSE - 1) {
- dev_err_ratelimited(hdev->dev, "Invalid HBM SEI event cause (%d) provided by FW\n",
- cause_idx);
+ gaudi2_print_event(hdev, event_type, true,
+ "err cause: %s",
+ "Invalid HBM SEI event cause (%d) provided by FW\n", cause_idx);
return true;
}
- if (sei_data->hdr.is_critical)
- dev_err(hdev->dev,
- "System Critical Error Interrupt - HBM(%u) MC(%u) MC_CH(%u) MC_PC(%u). Error cause: %s\n",
- hbm_id, mc_id, sei_data->hdr.mc_channel, sei_data->hdr.mc_pseudo_channel,
- hbm_mc_sei_cause[cause_idx]);
-
- else
- dev_err_ratelimited(hdev->dev,
- "System Non-Critical Error Interrupt - HBM(%u) MC(%u) MC_CH(%u) MC_PC(%u). Error cause: %s\n",
- hbm_id, mc_id, sei_data->hdr.mc_channel, sei_data->hdr.mc_pseudo_channel,
- hbm_mc_sei_cause[cause_idx]);
+ gaudi2_print_event(hdev, event_type, !sei_data->hdr.is_critical,
+ "System %s Error Interrupt - HBM(%u) MC(%u) MC_CH(%u) MC_PC(%u). Error cause: %s\n",
+ sei_data->hdr.is_critical ? "Critical" : "Non-critical",
+ hbm_id, mc_id, sei_data->hdr.mc_channel, sei_data->hdr.mc_pseudo_channel,
+ hbm_mc_sei_cause[cause_idx]);
/* Print error-specific info */
switch (cause_idx) {
@@ -8586,24 +8792,33 @@ static bool gaudi2_handle_hbm_mc_sei_err(struct hl_device *hdev, u16 event_type,
return require_hard_reset;
}
-static void gaudi2_handle_hbm_cattrip(struct hl_device *hdev, u64 intr_cause_data)
+static int gaudi2_handle_hbm_cattrip(struct hl_device *hdev, u16 event_type,
+ u64 intr_cause_data)
{
- dev_err(hdev->dev,
- "HBM catastrophic temperature error (CATTRIP) cause %#llx\n",
- intr_cause_data);
+ if (intr_cause_data) {
+ gaudi2_print_event(hdev, event_type, true,
+ "temperature error cause: %#llx", intr_cause_data);
+ return 1;
+ }
+
+ return 0;
}
-static void gaudi2_handle_hbm_mc_spi(struct hl_device *hdev, u64 intr_cause_data)
+static int gaudi2_handle_hbm_mc_spi(struct hl_device *hdev, u64 intr_cause_data)
{
- u32 i;
+ u32 i, error_count = 0;
for (i = 0 ; i < GAUDI2_NUM_OF_HBM_MC_SPI_CAUSE ; i++)
- if (intr_cause_data & hbm_mc_spi[i].mask)
+ if (intr_cause_data & hbm_mc_spi[i].mask) {
dev_dbg(hdev->dev, "HBM spi event: notification cause(%s)\n",
hbm_mc_spi[i].cause);
+ error_count++;
+ }
+
+ return error_count;
}
-static void gaudi2_print_clk_change_info(struct hl_device *hdev, u16 event_type)
+static void gaudi2_print_clk_change_info(struct hl_device *hdev, u16 event_type, u64 *event_mask)
{
ktime_t zero_time = ktime_set(0, 0);
@@ -8615,13 +8830,13 @@ static void gaudi2_print_clk_change_info(struct hl_device *hdev, u16 event_type)
hdev->clk_throttling.aggregated_reason |= HL_CLK_THROTTLE_POWER;
hdev->clk_throttling.timestamp[HL_CLK_THROTTLE_TYPE_POWER].start = ktime_get();
hdev->clk_throttling.timestamp[HL_CLK_THROTTLE_TYPE_POWER].end = zero_time;
- dev_info_ratelimited(hdev->dev, "Clock throttling due to power consumption\n");
+ dev_dbg_ratelimited(hdev->dev, "Clock throttling due to power consumption\n");
break;
case GAUDI2_EVENT_CPU_FIX_POWER_ENV_E:
hdev->clk_throttling.current_reason &= ~HL_CLK_THROTTLE_POWER;
hdev->clk_throttling.timestamp[HL_CLK_THROTTLE_TYPE_POWER].end = ktime_get();
- dev_info_ratelimited(hdev->dev, "Power envelop is safe, back to optimal clock\n");
+ dev_dbg_ratelimited(hdev->dev, "Power envelop is safe, back to optimal clock\n");
break;
case GAUDI2_EVENT_CPU_FIX_THERMAL_ENV_S:
@@ -8629,12 +8844,14 @@ static void gaudi2_print_clk_change_info(struct hl_device *hdev, u16 event_type)
hdev->clk_throttling.aggregated_reason |= HL_CLK_THROTTLE_THERMAL;
hdev->clk_throttling.timestamp[HL_CLK_THROTTLE_TYPE_THERMAL].start = ktime_get();
hdev->clk_throttling.timestamp[HL_CLK_THROTTLE_TYPE_THERMAL].end = zero_time;
+ *event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
dev_info_ratelimited(hdev->dev, "Clock throttling due to overheating\n");
break;
case GAUDI2_EVENT_CPU_FIX_THERMAL_ENV_E:
hdev->clk_throttling.current_reason &= ~HL_CLK_THROTTLE_THERMAL;
hdev->clk_throttling.timestamp[HL_CLK_THROTTLE_TYPE_THERMAL].end = ktime_get();
+ *event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
dev_info_ratelimited(hdev->dev, "Thermal envelop is safe, back to optimal clock\n");
break;
@@ -8646,43 +8863,49 @@ static void gaudi2_print_clk_change_info(struct hl_device *hdev, u16 event_type)
mutex_unlock(&hdev->clk_throttling.lock);
}
-static void gaudi2_print_out_of_sync_info(struct hl_device *hdev,
+static void gaudi2_print_out_of_sync_info(struct hl_device *hdev, u16 event_type,
struct cpucp_pkt_sync_err *sync_err)
{
struct hl_hw_queue *q = &hdev->kernel_queues[GAUDI2_QUEUE_ID_CPU_PQ];
- dev_err(hdev->dev, "Out of sync with FW, FW: pi=%u, ci=%u, LKD: pi=%u, ci=%d\n",
- le32_to_cpu(sync_err->pi), le32_to_cpu(sync_err->ci), q->pi, atomic_read(&q->ci));
+ gaudi2_print_event(hdev, event_type, false,
+ "FW: pi=%u, ci=%u, LKD: pi=%u, ci=%d\n",
+ le32_to_cpu(sync_err->pi), le32_to_cpu(sync_err->ci),
+ q->pi, atomic_read(&q->ci));
}
-static void gaudi2_handle_pcie_p2p_msix(struct hl_device *hdev)
+static int gaudi2_handle_pcie_p2p_msix(struct hl_device *hdev, u16 event_type)
{
- u32 p2p_intr, msix_gw_intr;
+ u32 p2p_intr, msix_gw_intr, error_count = 0;
p2p_intr = RREG32(mmPCIE_WRAP_P2P_INTR);
msix_gw_intr = RREG32(mmPCIE_WRAP_MSIX_GW_INTR);
if (p2p_intr) {
- dev_err_ratelimited(hdev->dev,
+ gaudi2_print_event(hdev, event_type, true,
"pcie p2p transaction terminated due to security, req_id(0x%x)\n",
RREG32(mmPCIE_WRAP_P2P_REQ_ID));
WREG32(mmPCIE_WRAP_P2P_INTR, 0x1);
+ error_count++;
}
if (msix_gw_intr) {
- dev_err_ratelimited(hdev->dev,
+ gaudi2_print_event(hdev, event_type, true,
"pcie msi-x gen denied due to vector num check failure, vec(0x%X)\n",
RREG32(mmPCIE_WRAP_MSIX_GW_VEC));
WREG32(mmPCIE_WRAP_MSIX_GW_INTR, 0x1);
+ error_count++;
}
+
+ return error_count;
}
-static void gaudi2_handle_pcie_drain(struct hl_device *hdev,
+static int gaudi2_handle_pcie_drain(struct hl_device *hdev,
struct hl_eq_pcie_drain_ind_data *drain_data)
{
- u64 lbw_rd, lbw_wr, hbw_rd, hbw_wr, cause;
+ u64 lbw_rd, lbw_wr, hbw_rd, hbw_wr, cause, error_count = 0;
cause = le64_to_cpu(drain_data->intr_cause.intr_cause_data);
lbw_rd = le64_to_cpu(drain_data->drain_rd_addr_lbw);
@@ -8690,39 +8913,52 @@ static void gaudi2_handle_pcie_drain(struct hl_device *hdev,
hbw_rd = le64_to_cpu(drain_data->drain_rd_addr_hbw);
hbw_wr = le64_to_cpu(drain_data->drain_wr_addr_hbw);
- if (cause & BIT_ULL(0))
+ if (cause & BIT_ULL(0)) {
dev_err_ratelimited(hdev->dev,
"PCIE AXI drain LBW completed, read_err %u, write_err %u\n",
!!lbw_rd, !!lbw_wr);
+ error_count++;
+ }
- if (cause & BIT_ULL(1))
+ if (cause & BIT_ULL(1)) {
dev_err_ratelimited(hdev->dev,
"PCIE AXI drain HBW completed, raddr %#llx, waddr %#llx\n",
hbw_rd, hbw_wr);
+ error_count++;
+ }
+
+ return error_count;
}
-static void gaudi2_handle_psoc_drain(struct hl_device *hdev, u64 intr_cause_data)
+static int gaudi2_handle_psoc_drain(struct hl_device *hdev, u64 intr_cause_data)
{
+ u32 error_count = 0;
int i;
for (i = 0 ; i < GAUDI2_NUM_OF_AXI_DRAIN_ERR_CAUSE ; i++) {
- if (intr_cause_data & BIT_ULL(i))
+ if (intr_cause_data & BIT_ULL(i)) {
dev_err_ratelimited(hdev->dev, "PSOC %s completed\n",
gaudi2_psoc_axi_drain_interrupts_cause[i]);
+ error_count++;
+ }
}
+
+ hl_check_for_glbl_errors(hdev);
+
+ return error_count;
}
-static void gaudi2_print_cpu_pkt_failure_info(struct hl_device *hdev,
+static void gaudi2_print_cpu_pkt_failure_info(struct hl_device *hdev, u16 event_type,
struct cpucp_pkt_sync_err *sync_err)
{
struct hl_hw_queue *q = &hdev->kernel_queues[GAUDI2_QUEUE_ID_CPU_PQ];
- dev_warn(hdev->dev,
+ gaudi2_print_event(hdev, event_type, false,
"FW reported sanity check failure, FW: pi=%u, ci=%u, LKD: pi=%u, ci=%d\n",
le32_to_cpu(sync_err->pi), le32_to_cpu(sync_err->ci), q->pi, atomic_read(&q->ci));
}
-static void hl_arc_event_handle(struct hl_device *hdev,
+static int hl_arc_event_handle(struct hl_device *hdev, u16 event_type,
struct hl_eq_engine_arc_intr_data *data)
{
struct hl_engine_arc_dccm_queue_full_irq *q;
@@ -8737,12 +8973,13 @@ static void hl_arc_event_handle(struct hl_device *hdev,
case ENGINE_ARC_DCCM_QUEUE_FULL_IRQ:
q = (struct hl_engine_arc_dccm_queue_full_irq *) &payload;
- dev_err_ratelimited(hdev->dev,
+ gaudi2_print_event(hdev, event_type, true,
"ARC DCCM Full event: EngId: %u, Intr_type: %u, Qidx: %u\n",
engine_id, intr_type, q->queue_index);
- break;
+ return 1;
default:
- dev_err_ratelimited(hdev->dev, "Unknown ARC event type\n");
+ gaudi2_print_event(hdev, event_type, true, "Unknown ARC event type\n");
+ return 0;
}
}
@@ -8750,8 +8987,7 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent
{
struct gaudi2_device *gaudi2 = hdev->asic_specific;
bool reset_required = false, is_critical = false;
- u32 ctl, reset_flags = HL_DRV_RESET_HARD;
- int index, sbte_index;
+ u32 index, ctl, reset_flags = HL_DRV_RESET_HARD, error_count = 0;
u64 event_mask = 0;
u16 event_type;
@@ -8767,8 +9003,6 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent
gaudi2->events_stat[event_type]++;
gaudi2->events_stat_aggregate[event_type]++;
- gaudi2_print_irq_info(hdev, event_type);
-
switch (event_type) {
case GAUDI2_EVENT_PCIE_CORE_SERR ... GAUDI2_EVENT_ARC0_ECC_DERR:
fallthrough;
@@ -8777,6 +9011,7 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent
event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
reset_required = gaudi2_handle_ecc_event(hdev, event_type, &eq_entry->ecc_data);
is_critical = eq_entry->ecc_data.is_critical;
+ error_count++;
break;
case GAUDI2_EVENT_TPC0_QM ... GAUDI2_EVENT_PDMA1_QM:
@@ -8784,48 +9019,48 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent
case GAUDI2_EVENT_ROTATOR0_ROT0_QM ... GAUDI2_EVENT_ROTATOR1_ROT1_QM:
fallthrough;
case GAUDI2_EVENT_NIC0_QM0 ... GAUDI2_EVENT_NIC11_QM1:
- gaudi2_handle_qman_err(hdev, event_type);
+ error_count = gaudi2_handle_qman_err(hdev, event_type, &event_mask);
event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
break;
case GAUDI2_EVENT_ARC_AXI_ERROR_RESPONSE_0:
reset_flags |= HL_DRV_RESET_FW_FATAL_ERR;
- gaudi2_handle_arc_farm_sei_err(hdev);
+ error_count = gaudi2_handle_arc_farm_sei_err(hdev, event_type);
event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
break;
case GAUDI2_EVENT_CPU_AXI_ERR_RSP:
- gaudi2_handle_cpu_sei_err(hdev);
+ error_count = gaudi2_handle_cpu_sei_err(hdev, event_type);
event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
break;
case GAUDI2_EVENT_PDMA_CH0_AXI_ERR_RSP:
case GAUDI2_EVENT_PDMA_CH1_AXI_ERR_RSP:
reset_flags |= HL_DRV_RESET_FW_FATAL_ERR;
- gaudi2_handle_qm_sei_err(hdev, event_type, &eq_entry->razwi_info, &event_mask);
+ error_count = gaudi2_handle_qm_sei_err(hdev, event_type, true, &event_mask);
event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
break;
case GAUDI2_EVENT_ROTATOR0_AXI_ERROR_RESPONSE:
case GAUDI2_EVENT_ROTATOR1_AXI_ERROR_RESPONSE:
index = event_type - GAUDI2_EVENT_ROTATOR0_AXI_ERROR_RESPONSE;
- gaudi2_handle_rot_err(hdev, index, &eq_entry->razwi_with_intr_cause, &event_mask);
- gaudi2_handle_qm_sei_err(hdev, event_type, NULL, &event_mask);
+ error_count = gaudi2_handle_rot_err(hdev, index, event_type,
+ &eq_entry->razwi_with_intr_cause, &event_mask);
+ error_count += gaudi2_handle_qm_sei_err(hdev, event_type, false, &event_mask);
event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
break;
case GAUDI2_EVENT_TPC0_AXI_ERR_RSP ... GAUDI2_EVENT_TPC24_AXI_ERR_RSP:
index = event_type - GAUDI2_EVENT_TPC0_AXI_ERR_RSP;
- gaudi2_tpc_ack_interrupts(hdev, index, "AXI_ERR_RSP",
+ error_count = gaudi2_tpc_ack_interrupts(hdev, index, event_type,
&eq_entry->razwi_with_intr_cause, &event_mask);
- gaudi2_handle_qm_sei_err(hdev, event_type, NULL, &event_mask);
+ error_count += gaudi2_handle_qm_sei_err(hdev, event_type, false, &event_mask);
event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
break;
case GAUDI2_EVENT_DEC0_AXI_ERR_RSPONSE ... GAUDI2_EVENT_DEC9_AXI_ERR_RSPONSE:
index = event_type - GAUDI2_EVENT_DEC0_AXI_ERR_RSPONSE;
- gaudi2_handle_dec_err(hdev, index, "AXI_ERR_RESPONSE", &eq_entry->razwi_info,
- &event_mask);
+ error_count = gaudi2_handle_dec_err(hdev, index, event_type, &event_mask);
event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
break;
@@ -8856,8 +9091,8 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent
case GAUDI2_EVENT_TPC24_KERNEL_ERR:
index = (event_type - GAUDI2_EVENT_TPC0_KERNEL_ERR) /
(GAUDI2_EVENT_TPC1_KERNEL_ERR - GAUDI2_EVENT_TPC0_KERNEL_ERR);
- gaudi2_tpc_ack_interrupts(hdev, index, "KRN_ERR", &eq_entry->razwi_with_intr_cause,
- &event_mask);
+ error_count = gaudi2_tpc_ack_interrupts(hdev, index, event_type,
+ &eq_entry->razwi_with_intr_cause, &event_mask);
event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
break;
@@ -8873,7 +9108,7 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent
case GAUDI2_EVENT_DEC9_SPI:
index = (event_type - GAUDI2_EVENT_DEC0_SPI) /
(GAUDI2_EVENT_DEC1_SPI - GAUDI2_EVENT_DEC0_SPI);
- gaudi2_handle_dec_err(hdev, index, "SPI", &eq_entry->razwi_info, &event_mask);
+ error_count = gaudi2_handle_dec_err(hdev, index, event_type, &event_mask);
event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
break;
@@ -8884,9 +9119,8 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent
index = (event_type - GAUDI2_EVENT_MME0_CTRL_AXI_ERROR_RESPONSE) /
(GAUDI2_EVENT_MME1_CTRL_AXI_ERROR_RESPONSE -
GAUDI2_EVENT_MME0_CTRL_AXI_ERROR_RESPONSE);
- gaudi2_handle_mme_err(hdev, index,
- "CTRL_AXI_ERROR_RESPONSE", &eq_entry->razwi_info, &event_mask);
- gaudi2_handle_qm_sei_err(hdev, event_type, NULL, &event_mask);
+ error_count = gaudi2_handle_mme_err(hdev, index, event_type, &event_mask);
+ error_count += gaudi2_handle_qm_sei_err(hdev, event_type, false, &event_mask);
event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
break;
@@ -8897,8 +9131,7 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent
index = (event_type - GAUDI2_EVENT_MME0_QMAN_SW_ERROR) /
(GAUDI2_EVENT_MME1_QMAN_SW_ERROR -
GAUDI2_EVENT_MME0_QMAN_SW_ERROR);
- gaudi2_handle_mme_err(hdev, index, "QMAN_SW_ERROR", &eq_entry->razwi_info,
- &event_mask);
+ error_count = gaudi2_handle_mme_err(hdev, index, event_type, &event_mask);
event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
break;
@@ -8909,25 +9142,25 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent
index = (event_type - GAUDI2_EVENT_MME0_WAP_SOURCE_RESULT_INVALID) /
(GAUDI2_EVENT_MME1_WAP_SOURCE_RESULT_INVALID -
GAUDI2_EVENT_MME0_WAP_SOURCE_RESULT_INVALID);
- gaudi2_handle_mme_wap_err(hdev, index, &eq_entry->razwi_info, &event_mask);
+ error_count = gaudi2_handle_mme_wap_err(hdev, index, event_type, &event_mask);
event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
break;
case GAUDI2_EVENT_KDMA_CH0_AXI_ERR_RSP:
case GAUDI2_EVENT_KDMA0_CORE:
- gaudi2_handle_kdma_core_event(hdev,
+ error_count = gaudi2_handle_kdma_core_event(hdev, event_type,
le64_to_cpu(eq_entry->intr_cause.intr_cause_data));
event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
break;
case GAUDI2_EVENT_HDMA2_CORE ... GAUDI2_EVENT_PDMA1_CORE:
- gaudi2_handle_dma_core_event(hdev,
+ error_count = gaudi2_handle_dma_core_event(hdev, event_type,
le64_to_cpu(eq_entry->intr_cause.intr_cause_data));
event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
break;
case GAUDI2_EVENT_PCIE_ADDR_DEC_ERR:
- gaudi2_print_pcie_addr_dec_info(hdev,
+ error_count = gaudi2_print_pcie_addr_dec_info(hdev, event_type,
le64_to_cpu(eq_entry->intr_cause.intr_cause_data), &event_mask);
reset_flags |= HL_DRV_RESET_FW_FATAL_ERR;
event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
@@ -8937,27 +9170,27 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent
case GAUDI2_EVENT_HMMU_0_AXI_ERR_RSP ... GAUDI2_EVENT_HMMU_12_AXI_ERR_RSP:
case GAUDI2_EVENT_PMMU0_PAGE_FAULT_WR_PERM ... GAUDI2_EVENT_PMMU0_SECURITY_ERROR:
case GAUDI2_EVENT_PMMU_AXI_ERR_RSP_0:
- gaudi2_handle_mmu_spi_sei_err(hdev, event_type, &event_mask);
+ error_count = gaudi2_handle_mmu_spi_sei_err(hdev, event_type, &event_mask);
reset_flags |= HL_DRV_RESET_FW_FATAL_ERR;
event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
break;
case GAUDI2_EVENT_HIF0_FATAL ... GAUDI2_EVENT_HIF12_FATAL:
- gaudi2_handle_hif_fatal(hdev, event_type,
+ error_count = gaudi2_handle_hif_fatal(hdev, event_type,
le64_to_cpu(eq_entry->intr_cause.intr_cause_data));
reset_flags |= HL_DRV_RESET_FW_FATAL_ERR;
event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
break;
case GAUDI2_EVENT_PMMU_FATAL_0:
- gaudi2_handle_pif_fatal(hdev,
+ error_count = gaudi2_handle_pif_fatal(hdev, event_type,
le64_to_cpu(eq_entry->intr_cause.intr_cause_data));
reset_flags |= HL_DRV_RESET_FW_FATAL_ERR;
event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
break;
case GAUDI2_EVENT_PSOC63_RAZWI_OR_PID_MIN_MAX_INTERRUPT:
- gaudi2_ack_psoc_razwi_event_handler(hdev, &event_mask);
+ error_count = gaudi2_ack_psoc_razwi_event_handler(hdev, &event_mask);
event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
break;
@@ -8967,33 +9200,39 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent
reset_flags |= HL_DRV_RESET_FW_FATAL_ERR;
reset_required = true;
}
+ error_count++;
break;
case GAUDI2_EVENT_HBM_CATTRIP_0 ... GAUDI2_EVENT_HBM_CATTRIP_5:
- gaudi2_handle_hbm_cattrip(hdev, le64_to_cpu(eq_entry->intr_cause.intr_cause_data));
+ error_count = gaudi2_handle_hbm_cattrip(hdev, event_type,
+ le64_to_cpu(eq_entry->intr_cause.intr_cause_data));
event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
break;
case GAUDI2_EVENT_HBM0_MC0_SPI ... GAUDI2_EVENT_HBM5_MC1_SPI:
- gaudi2_handle_hbm_mc_spi(hdev, le64_to_cpu(eq_entry->intr_cause.intr_cause_data));
+ error_count = gaudi2_handle_hbm_mc_spi(hdev,
+ le64_to_cpu(eq_entry->intr_cause.intr_cause_data));
event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
break;
case GAUDI2_EVENT_PCIE_DRAIN_COMPLETE:
- gaudi2_handle_pcie_drain(hdev, &eq_entry->pcie_drain_ind_data);
+ error_count = gaudi2_handle_pcie_drain(hdev, &eq_entry->pcie_drain_ind_data);
event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
break;
case GAUDI2_EVENT_PSOC59_RPM_ERROR_OR_DRAIN:
- gaudi2_handle_psoc_drain(hdev, le64_to_cpu(eq_entry->intr_cause.intr_cause_data));
+ error_count = gaudi2_handle_psoc_drain(hdev,
+ le64_to_cpu(eq_entry->intr_cause.intr_cause_data));
event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
break;
case GAUDI2_EVENT_CPU_AXI_ECC:
+ error_count = GAUDI2_NA_EVENT_CAUSE;
reset_flags |= HL_DRV_RESET_FW_FATAL_ERR;
event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
break;
case GAUDI2_EVENT_CPU_L2_RAM_ECC:
+ error_count = GAUDI2_NA_EVENT_CAUSE;
reset_flags |= HL_DRV_RESET_FW_FATAL_ERR;
event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
break;
@@ -9001,31 +9240,30 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent
case GAUDI2_EVENT_MME1_SBTE0_AXI_ERR_RSP ... GAUDI2_EVENT_MME1_SBTE4_AXI_ERR_RSP:
case GAUDI2_EVENT_MME2_SBTE0_AXI_ERR_RSP ... GAUDI2_EVENT_MME2_SBTE4_AXI_ERR_RSP:
case GAUDI2_EVENT_MME3_SBTE0_AXI_ERR_RSP ... GAUDI2_EVENT_MME3_SBTE4_AXI_ERR_RSP:
- index = (event_type - GAUDI2_EVENT_MME0_SBTE0_AXI_ERR_RSP) /
- (GAUDI2_EVENT_MME1_SBTE0_AXI_ERR_RSP -
- GAUDI2_EVENT_MME0_SBTE0_AXI_ERR_RSP);
- sbte_index = (event_type - GAUDI2_EVENT_MME0_SBTE0_AXI_ERR_RSP) %
- (GAUDI2_EVENT_MME1_SBTE0_AXI_ERR_RSP -
- GAUDI2_EVENT_MME0_SBTE0_AXI_ERR_RSP);
- gaudi2_handle_mme_sbte_err(hdev, index, sbte_index,
+ error_count = gaudi2_handle_mme_sbte_err(hdev, event_type,
le64_to_cpu(eq_entry->intr_cause.intr_cause_data));
event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
break;
case GAUDI2_EVENT_VM0_ALARM_A ... GAUDI2_EVENT_VM3_ALARM_B:
+ error_count = GAUDI2_NA_EVENT_CAUSE;
reset_flags |= HL_DRV_RESET_FW_FATAL_ERR;
event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
break;
case GAUDI2_EVENT_PSOC_AXI_ERR_RSP:
+ error_count = GAUDI2_NA_EVENT_CAUSE;
event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
break;
case GAUDI2_EVENT_PSOC_PRSTN_FALL:
+ error_count = GAUDI2_NA_EVENT_CAUSE;
event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
break;
case GAUDI2_EVENT_PCIE_APB_TIMEOUT:
+ error_count = GAUDI2_NA_EVENT_CAUSE;
reset_flags |= HL_DRV_RESET_FW_FATAL_ERR;
event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
break;
case GAUDI2_EVENT_PCIE_FATAL_ERR:
+ error_count = GAUDI2_NA_EVENT_CAUSE;
event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
break;
case GAUDI2_EVENT_TPC0_BMON_SPMU:
@@ -9078,6 +9316,7 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent
case GAUDI2_EVENT_DEC8_BMON_SPMU:
case GAUDI2_EVENT_DEC9_BMON_SPMU:
case GAUDI2_EVENT_ROTATOR0_BMON_SPMU ... GAUDI2_EVENT_SM3_BMON_SPMU:
+ error_count = GAUDI2_NA_EVENT_CAUSE;
event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
break;
@@ -9085,67 +9324,87 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent
case GAUDI2_EVENT_CPU_FIX_POWER_ENV_E:
case GAUDI2_EVENT_CPU_FIX_THERMAL_ENV_S:
case GAUDI2_EVENT_CPU_FIX_THERMAL_ENV_E:
- gaudi2_print_clk_change_info(hdev, event_type);
- event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
+ gaudi2_print_clk_change_info(hdev, event_type, &event_mask);
+ error_count = GAUDI2_NA_EVENT_CAUSE;
break;
case GAUDI2_EVENT_CPU_PKT_QUEUE_OUT_SYNC:
- gaudi2_print_out_of_sync_info(hdev, &eq_entry->pkt_sync_err);
+ gaudi2_print_out_of_sync_info(hdev, event_type, &eq_entry->pkt_sync_err);
+ error_count = GAUDI2_NA_EVENT_CAUSE;
event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
break;
case GAUDI2_EVENT_PCIE_FLR_REQUESTED:
event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
+ error_count = GAUDI2_NA_EVENT_CAUSE;
/* Do nothing- FW will handle it */
break;
case GAUDI2_EVENT_PCIE_P2P_MSIX:
- gaudi2_handle_pcie_p2p_msix(hdev);
+ error_count = gaudi2_handle_pcie_p2p_msix(hdev, event_type);
event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
break;
case GAUDI2_EVENT_SM0_AXI_ERROR_RESPONSE ... GAUDI2_EVENT_SM3_AXI_ERROR_RESPONSE:
index = event_type - GAUDI2_EVENT_SM0_AXI_ERROR_RESPONSE;
- gaudi2_handle_sm_err(hdev, index);
+ error_count = gaudi2_handle_sm_err(hdev, event_type, index);
event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
break;
case GAUDI2_EVENT_PSOC_MME_PLL_LOCK_ERR ... GAUDI2_EVENT_DCORE2_HBM_PLL_LOCK_ERR:
+ error_count = GAUDI2_NA_EVENT_CAUSE;
event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
break;
case GAUDI2_EVENT_CPU_CPLD_SHUTDOWN_CAUSE:
dev_info(hdev->dev, "CPLD shutdown cause, reset reason: 0x%llx\n",
le64_to_cpu(eq_entry->data[0]));
+ error_count = GAUDI2_NA_EVENT_CAUSE;
event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
break;
case GAUDI2_EVENT_CPU_CPLD_SHUTDOWN_EVENT:
dev_err(hdev->dev, "CPLD shutdown event, reset reason: 0x%llx\n",
le64_to_cpu(eq_entry->data[0]));
+ error_count = GAUDI2_NA_EVENT_CAUSE;
event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
break;
case GAUDI2_EVENT_CPU_PKT_SANITY_FAILED:
- gaudi2_print_cpu_pkt_failure_info(hdev, &eq_entry->pkt_sync_err);
+ gaudi2_print_cpu_pkt_failure_info(hdev, event_type, &eq_entry->pkt_sync_err);
+ error_count = GAUDI2_NA_EVENT_CAUSE;
event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
break;
case GAUDI2_EVENT_ARC_DCCM_FULL:
- hl_arc_event_handle(hdev, &eq_entry->arc_data);
+ error_count = hl_arc_event_handle(hdev, event_type, &eq_entry->arc_data);
event_mask |= HL_NOTIFIER_EVENT_USER_ENGINE_ERR;
break;
case GAUDI2_EVENT_CPU_FP32_NOT_SUPPORTED:
+ case GAUDI2_EVENT_DEV_RESET_REQ:
event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR;
+ error_count = GAUDI2_NA_EVENT_CAUSE;
is_critical = true;
break;
default:
- if (gaudi2_irq_map_table[event_type].valid)
+ if (gaudi2_irq_map_table[event_type].valid) {
dev_err_ratelimited(hdev->dev, "Cannot find handler for event %d\n",
event_type);
+ error_count = GAUDI2_NA_EVENT_CAUSE;
+ }
}
+ /* Make sure to dump an error in case no error cause was printed so far.
+ * Note that although we have counted the errors, we use this number as
+ * a boolean.
+ */
+ if (error_count == GAUDI2_NA_EVENT_CAUSE && !is_info_event(event_type))
+ gaudi2_print_event(hdev, event_type, true, "%d", event_type);
+ else if (error_count == 0)
+ gaudi2_print_event(hdev, event_type, true,
+ "No error cause for H/W event %u\n", event_type);
+
if ((gaudi2_irq_map_table[event_type].reset || reset_required) &&
(hdev->hard_reset_on_fw_events ||
(hdev->asic_prop.fw_security_enabled && is_critical)))
@@ -10116,8 +10375,8 @@ static int gaudi2_block_mmap(struct hl_device *hdev, struct vm_area_struct *vma,
address = pci_resource_start(hdev->pdev, SRAM_CFG_BAR_ID) + offset_in_bar;
- vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP |
- VM_DONTCOPY | VM_NORESERVE;
+ vm_flags_set(vma, VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP |
+ VM_DONTCOPY | VM_NORESERVE);
rc = remap_pfn_range(vma, vma->vm_start, address >> PAGE_SHIFT,
block_size, vma->vm_page_prot);
@@ -10466,6 +10725,8 @@ static const struct hl_asic_funcs gaudi2_funcs = {
.set_dram_bar_base = gaudi2_set_hbm_bar_base,
.set_engine_cores = gaudi2_set_engine_cores,
.send_device_activity = gaudi2_send_device_activity,
+ .set_dram_properties = gaudi2_set_dram_properties,
+ .set_binning_masks = gaudi2_set_binning_masks,
};
void gaudi2_set_asic_funcs(struct hl_device *hdev)
diff --git a/drivers/misc/habanalabs/gaudi2/gaudi2P.h b/drivers/accel/habanalabs/gaudi2/gaudi2P.h
index b4383c199bbb..2687404d9d21 100644
--- a/drivers/misc/habanalabs/gaudi2/gaudi2P.h
+++ b/drivers/accel/habanalabs/gaudi2/gaudi2P.h
@@ -8,7 +8,7 @@
#ifndef GAUDI2P_H_
#define GAUDI2P_H_
-#include <uapi/misc/habanalabs.h>
+#include <uapi/drm/habanalabs_accel.h>
#include "../common/habanalabs.h"
#include "../include/common/hl_boot_if.h"
#include "../include/gaudi2/gaudi2.h"
@@ -240,6 +240,8 @@
#define GAUDI2_SOB_INCREMENT_BY_ONE (FIELD_PREP(DCORE0_SYNC_MNGR_OBJS_SOB_OBJ_VAL_MASK, 1) | \
FIELD_PREP(DCORE0_SYNC_MNGR_OBJS_SOB_OBJ_INC_MASK, 1))
+#define GAUDI2_NUM_OF_GLBL_ERR_CAUSE 8
+
enum gaudi2_reserved_sob_id {
GAUDI2_RESERVED_SOB_CS_COMPLETION_FIRST,
GAUDI2_RESERVED_SOB_CS_COMPLETION_LAST =
@@ -532,6 +534,41 @@ struct gaudi2_device {
u32 num_of_valid_hw_events;
};
+/*
+ * Types of the Gaudi2 IP blocks, used by special blocks iterator.
+ * Required for scenarios where only particular block types can be
+ * addressed (e.g., special PLDM images).
+ */
+enum gaudi2_block_types {
+ GAUDI2_BLOCK_TYPE_PLL,
+ GAUDI2_BLOCK_TYPE_RTR,
+ GAUDI2_BLOCK_TYPE_CPU,
+ GAUDI2_BLOCK_TYPE_HIF,
+ GAUDI2_BLOCK_TYPE_HBM,
+ GAUDI2_BLOCK_TYPE_NIC,
+ GAUDI2_BLOCK_TYPE_PCIE,
+ GAUDI2_BLOCK_TYPE_PCIE_PMA,
+ GAUDI2_BLOCK_TYPE_PDMA,
+ GAUDI2_BLOCK_TYPE_EDMA,
+ GAUDI2_BLOCK_TYPE_PMMU,
+ GAUDI2_BLOCK_TYPE_PSOC,
+ GAUDI2_BLOCK_TYPE_ROT,
+ GAUDI2_BLOCK_TYPE_ARC_FARM,
+ GAUDI2_BLOCK_TYPE_DEC,
+ GAUDI2_BLOCK_TYPE_MME,
+ GAUDI2_BLOCK_TYPE_EU_BIST,
+ GAUDI2_BLOCK_TYPE_SYNC_MNGR,
+ GAUDI2_BLOCK_TYPE_STLB,
+ GAUDI2_BLOCK_TYPE_TPC,
+ GAUDI2_BLOCK_TYPE_HMMU,
+ GAUDI2_BLOCK_TYPE_SRAM,
+ GAUDI2_BLOCK_TYPE_XBAR,
+ GAUDI2_BLOCK_TYPE_KDMA,
+ GAUDI2_BLOCK_TYPE_XDMA,
+ GAUDI2_BLOCK_TYPE_XFT,
+ GAUDI2_BLOCK_TYPE_MAX
+};
+
extern const u32 gaudi2_dma_core_blocks_bases[DMA_CORE_ID_SIZE];
extern const u32 gaudi2_qm_blocks_bases[GAUDI2_QUEUE_ID_SIZE];
extern const u32 gaudi2_mme_acc_blocks_bases[MME_ID_SIZE];
diff --git a/drivers/misc/habanalabs/gaudi2/gaudi2_coresight.c b/drivers/accel/habanalabs/gaudi2/gaudi2_coresight.c
index 56c6ab692482..1dfbe293ecec 100644
--- a/drivers/misc/habanalabs/gaudi2/gaudi2_coresight.c
+++ b/drivers/accel/habanalabs/gaudi2/gaudi2_coresight.c
@@ -5,7 +5,7 @@
* All Rights Reserved.
*/
#include "gaudi2_coresight_regs.h"
-#include <uapi/misc/habanalabs.h>
+#include <uapi/drm/habanalabs_accel.h>
#define GAUDI2_PLDM_CORESIGHT_TIMEOUT_USEC (CORESIGHT_TIMEOUT_USEC * 2000)
#define SPMU_MAX_COUNTERS 6
@@ -2376,10 +2376,10 @@ static int gaudi2_config_bmon(struct hl_device *hdev, struct hl_debug_params *pa
WREG32(base_reg + mmBMON_ADDRH_S2_OFFSET, upper_32_bits(input->start_addr2));
WREG32(base_reg + mmBMON_ADDRL_E2_OFFSET, lower_32_bits(input->end_addr2));
WREG32(base_reg + mmBMON_ADDRH_E2_OFFSET, upper_32_bits(input->end_addr2));
- WREG32(base_reg + mmBMON_ADDRL_S3_OFFSET, lower_32_bits(input->start_addr2));
- WREG32(base_reg + mmBMON_ADDRH_S3_OFFSET, upper_32_bits(input->start_addr2));
- WREG32(base_reg + mmBMON_ADDRL_E3_OFFSET, lower_32_bits(input->end_addr2));
- WREG32(base_reg + mmBMON_ADDRH_E3_OFFSET, upper_32_bits(input->end_addr2));
+ WREG32(base_reg + mmBMON_ADDRL_S3_OFFSET, lower_32_bits(input->start_addr3));
+ WREG32(base_reg + mmBMON_ADDRH_S3_OFFSET, upper_32_bits(input->start_addr3));
+ WREG32(base_reg + mmBMON_ADDRL_E3_OFFSET, lower_32_bits(input->end_addr3));
+ WREG32(base_reg + mmBMON_ADDRH_E3_OFFSET, upper_32_bits(input->end_addr3));
WREG32(base_reg + mmBMON_IDL_OFFSET, 0x0);
WREG32(base_reg + mmBMON_IDH_OFFSET, 0x0);
diff --git a/drivers/misc/habanalabs/gaudi2/gaudi2_coresight_regs.h b/drivers/accel/habanalabs/gaudi2/gaudi2_coresight_regs.h
index df8729286e06..df8729286e06 100644
--- a/drivers/misc/habanalabs/gaudi2/gaudi2_coresight_regs.h
+++ b/drivers/accel/habanalabs/gaudi2/gaudi2_coresight_regs.h
diff --git a/drivers/misc/habanalabs/gaudi2/gaudi2_masks.h b/drivers/accel/habanalabs/gaudi2/gaudi2_masks.h
index e9ac87828221..e9ac87828221 100644
--- a/drivers/misc/habanalabs/gaudi2/gaudi2_masks.h
+++ b/drivers/accel/habanalabs/gaudi2/gaudi2_masks.h
diff --git a/drivers/misc/habanalabs/gaudi2/gaudi2_security.c b/drivers/accel/habanalabs/gaudi2/gaudi2_security.c
index 768c2f3dc900..a212f82e6604 100644
--- a/drivers/misc/habanalabs/gaudi2/gaudi2_security.c
+++ b/drivers/accel/habanalabs/gaudi2/gaudi2_security.c
@@ -1561,6 +1561,7 @@ static const u32 gaudi2_pb_dcr0_tpc0_unsecured_regs[] = {
mmDCORE0_TPC0_CFG_LUT_FUNC128_BASE_ADDR_HI,
mmDCORE0_TPC0_CFG_LUT_FUNC256_BASE_ADDR_LO,
mmDCORE0_TPC0_CFG_LUT_FUNC256_BASE_ADDR_HI,
+ mmDCORE0_TPC0_CFG_KERNEL_KERNEL_CONFIG,
mmDCORE0_TPC0_CFG_KERNEL_SRF_0,
mmDCORE0_TPC0_CFG_KERNEL_SRF_1,
mmDCORE0_TPC0_CFG_KERNEL_SRF_2,
@@ -1666,6 +1667,10 @@ static const u32 gaudi2_pb_dcr0_sm_glbl[] = {
mmDCORE0_SYNC_MNGR_GLBL_BASE,
};
+static const u32 gaudi2_pb_dcr1_sm_glbl[] = {
+ mmDCORE1_SYNC_MNGR_GLBL_BASE,
+};
+
static const struct range gaudi2_pb_dcr0_sm_glbl_unsecured_regs[] = {
{mmDCORE0_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_1, mmDCORE0_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_63},
{mmDCORE0_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_1, mmDCORE0_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_63},
@@ -1678,14 +1683,14 @@ static const struct range gaudi2_pb_dcr0_sm_glbl_unsecured_regs[] = {
};
static const struct range gaudi2_pb_dcr_x_sm_glbl_unsecured_regs[] = {
- {mmDCORE0_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_0, mmDCORE0_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_63},
- {mmDCORE0_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_0, mmDCORE0_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_63},
- {mmDCORE0_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_0, mmDCORE0_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_63},
- {mmDCORE0_SYNC_MNGR_GLBL_CQ_PI_0, mmDCORE0_SYNC_MNGR_GLBL_CQ_PI_63},
- {mmDCORE0_SYNC_MNGR_GLBL_LBW_ADDR_L_0, mmDCORE0_SYNC_MNGR_GLBL_LBW_ADDR_L_63},
- {mmDCORE0_SYNC_MNGR_GLBL_LBW_ADDR_H_0, mmDCORE0_SYNC_MNGR_GLBL_LBW_ADDR_H_63},
- {mmDCORE0_SYNC_MNGR_GLBL_LBW_DATA_0, mmDCORE0_SYNC_MNGR_GLBL_LBW_DATA_63},
- {mmDCORE0_SYNC_MNGR_GLBL_CQ_INC_MODE_0, mmDCORE0_SYNC_MNGR_GLBL_CQ_INC_MODE_63},
+ {mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_0, mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_63},
+ {mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_0, mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_63},
+ {mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_0, mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_63},
+ {mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_0, mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_63},
+ {mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_0, mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_63},
+ {mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_0, mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_63},
+ {mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_0, mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_63},
+ {mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_0, mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_63},
};
static const u32 gaudi2_pb_arc_sched[] = {
@@ -3358,14 +3363,6 @@ static int gaudi2_init_protection_bits(struct hl_device *hdev)
/* Sync Manager GLBL */
- /* Unsecure all CQ registers */
- rc |= hl_init_pb_ranges(hdev, NUM_OF_DCORES, DCORE_OFFSET,
- HL_PB_SINGLE_INSTANCE, HL_PB_NA,
- gaudi2_pb_dcr0_sm_glbl,
- ARRAY_SIZE(gaudi2_pb_dcr0_sm_glbl),
- gaudi2_pb_dcr_x_sm_glbl_unsecured_regs,
- ARRAY_SIZE(gaudi2_pb_dcr_x_sm_glbl_unsecured_regs));
-
/* Secure Dcore0 CQ0 registers */
rc |= hl_init_pb_ranges(hdev, HL_PB_SHARED, HL_PB_NA,
HL_PB_SINGLE_INSTANCE, HL_PB_NA,
@@ -3374,6 +3371,14 @@ static int gaudi2_init_protection_bits(struct hl_device *hdev)
gaudi2_pb_dcr0_sm_glbl_unsecured_regs,
ARRAY_SIZE(gaudi2_pb_dcr0_sm_glbl_unsecured_regs));
+ /* Unsecure all other CQ registers */
+ rc |= hl_init_pb_ranges(hdev, NUM_OF_DCORES - 1, DCORE_OFFSET,
+ HL_PB_SINGLE_INSTANCE, HL_PB_NA,
+ gaudi2_pb_dcr1_sm_glbl,
+ ARRAY_SIZE(gaudi2_pb_dcr1_sm_glbl),
+ gaudi2_pb_dcr_x_sm_glbl_unsecured_regs,
+ ARRAY_SIZE(gaudi2_pb_dcr_x_sm_glbl_unsecured_regs));
+
/* PSOC.
* Except for PSOC_GLOBAL_CONF, skip when security is enabled in F/W, because the blocks are
* protected by privileged RR.
diff --git a/drivers/misc/habanalabs/goya/Makefile b/drivers/accel/habanalabs/goya/Makefile
index b3f3b7b96683..b3f3b7b96683 100644
--- a/drivers/misc/habanalabs/goya/Makefile
+++ b/drivers/accel/habanalabs/goya/Makefile
diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/accel/habanalabs/goya/goya.c
index 0f083fcf81a6..df65e9bdc18a 100644
--- a/drivers/misc/habanalabs/goya/goya.c
+++ b/drivers/accel/habanalabs/goya/goya.c
@@ -2880,8 +2880,8 @@ static int goya_mmap(struct hl_device *hdev, struct vm_area_struct *vma,
{
int rc;
- vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP |
- VM_DONTCOPY | VM_NORESERVE;
+ vm_flags_set(vma, VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP |
+ VM_DONTCOPY | VM_NORESERVE);
rc = dma_mmap_coherent(hdev->dev, vma, cpu_addr,
(dma_addr - HOST_PHYS_BASE), size);
@@ -5420,6 +5420,16 @@ static int goya_scrub_device_dram(struct hl_device *hdev, u64 val)
return -EOPNOTSUPP;
}
+static int goya_set_dram_properties(struct hl_device *hdev)
+{
+ return 0;
+}
+
+static int goya_set_binning_masks(struct hl_device *hdev)
+{
+ return 0;
+}
+
static int goya_send_device_activity(struct hl_device *hdev, bool open)
{
return 0;
@@ -5518,6 +5528,8 @@ static const struct hl_asic_funcs goya_funcs = {
.access_dev_mem = hl_access_dev_mem,
.set_dram_bar_base = goya_set_ddr_bar_base,
.send_device_activity = goya_send_device_activity,
+ .set_dram_properties = goya_set_dram_properties,
+ .set_binning_masks = goya_set_binning_masks,
};
/*
diff --git a/drivers/misc/habanalabs/goya/goyaP.h b/drivers/accel/habanalabs/goya/goyaP.h
index d6ec43d6f6b0..5df3d30b91fd 100644
--- a/drivers/misc/habanalabs/goya/goyaP.h
+++ b/drivers/accel/habanalabs/goya/goyaP.h
@@ -8,7 +8,7 @@
#ifndef GOYAP_H_
#define GOYAP_H_
-#include <uapi/misc/habanalabs.h>
+#include <uapi/drm/habanalabs_accel.h>
#include "../common/habanalabs.h"
#include "../include/common/hl_boot_if.h"
#include "../include/goya/goya_packets.h"
diff --git a/drivers/misc/habanalabs/goya/goya_coresight.c b/drivers/accel/habanalabs/goya/goya_coresight.c
index 2c5133cfae65..e7ac3046cfaa 100644
--- a/drivers/misc/habanalabs/goya/goya_coresight.c
+++ b/drivers/accel/habanalabs/goya/goya_coresight.c
@@ -10,7 +10,7 @@
#include "../include/goya/asic_reg/goya_regs.h"
#include "../include/goya/asic_reg/goya_masks.h"
-#include <uapi/misc/habanalabs.h>
+#include <uapi/drm/habanalabs_accel.h>
#define GOYA_PLDM_CORESIGHT_TIMEOUT_USEC (CORESIGHT_TIMEOUT_USEC * 100)
diff --git a/drivers/misc/habanalabs/goya/goya_hwmgr.c b/drivers/accel/habanalabs/goya/goya_hwmgr.c
index b595721751c1..b595721751c1 100644
--- a/drivers/misc/habanalabs/goya/goya_hwmgr.c
+++ b/drivers/accel/habanalabs/goya/goya_hwmgr.c
diff --git a/drivers/misc/habanalabs/goya/goya_security.c b/drivers/accel/habanalabs/goya/goya_security.c
index 14c3bae3ccdc..14c3bae3ccdc 100644
--- a/drivers/misc/habanalabs/goya/goya_security.c
+++ b/drivers/accel/habanalabs/goya/goya_security.c
diff --git a/drivers/misc/habanalabs/include/common/cpucp_if.h b/drivers/accel/habanalabs/include/common/cpucp_if.h
index baa5aa43b6f4..d713252a4f13 100644
--- a/drivers/misc/habanalabs/include/common/cpucp_if.h
+++ b/drivers/accel/habanalabs/include/common/cpucp_if.h
@@ -344,6 +344,16 @@ struct hl_eq_engine_arc_intr_data {
__le64 pad[5];
};
+#define ADDR_DEC_ADDRESS_COUNT_MAX 4
+
+/* Data structure specifies details of ADDR_DEC interrupt */
+struct hl_eq_addr_dec_intr_data {
+ struct hl_eq_intr_cause intr_cause;
+ __le64 addr[ADDR_DEC_ADDRESS_COUNT_MAX];
+ __u8 addr_cnt;
+ __u8 pad[7];
+};
+
struct hl_eq_entry {
struct hl_eq_header hdr;
union {
@@ -358,6 +368,7 @@ struct hl_eq_entry {
struct hl_eq_razwi_with_intr_cause razwi_with_intr_cause;
struct hl_eq_hbm_sei_data sei_data; /* Gaudi2 HBM */
struct hl_eq_engine_arc_intr_data arc_data;
+ struct hl_eq_addr_dec_intr_data addr_dec;
__le64 data[7];
};
};
@@ -643,6 +654,10 @@ enum pq_init_status {
* data corruption in case of mismatched driver/FW versions.
* Relevant only to Gaudi.
*
+ * CPUCP_PACKET_GENERIC_PASSTHROUGH -
+ * Generic opcode for all firmware info that is only passed to host
+ * through the LKD, without getting parsed there.
+ *
* CPUCP_PACKET_ACTIVE_STATUS_SET -
* LKD sends FW indication whether device is free or in use, this indication is reported
* also to the BMC.
@@ -704,9 +719,12 @@ enum cpucp_packet_id {
CPUCP_PACKET_RESERVED5, /* not used */
CPUCP_PACKET_RESERVED6, /* not used */
CPUCP_PACKET_RESERVED7, /* not used */
+ CPUCP_PACKET_GENERIC_PASSTHROUGH, /* IOCTL */
CPUCP_PACKET_RESERVED8, /* not used */
- CPUCP_PACKET_RESERVED9, /* not used */
CPUCP_PACKET_ACTIVE_STATUS_SET, /* internal */
+ CPUCP_PACKET_RESERVED9, /* not used */
+ CPUCP_PACKET_RESERVED10, /* not used */
+ CPUCP_PACKET_RESERVED11, /* not used */
CPUCP_PACKET_ID_MAX /* must be last */
};
@@ -727,6 +745,11 @@ enum cpucp_packet_id {
#define CPUCP_PKT_RES_PLL_OUT3_SHIFT 48
#define CPUCP_PKT_RES_PLL_OUT3_MASK 0xFFFF000000000000ull
+#define CPUCP_PKT_RES_EEPROM_OUT0_SHIFT 0
+#define CPUCP_PKT_RES_EEPROM_OUT0_MASK 0x000000000000FFFFull
+#define CPUCP_PKT_RES_EEPROM_OUT1_SHIFT 16
+#define CPUCP_PKT_RES_EEPROM_OUT1_MASK 0x0000000000FF0000ull
+
#define CPUCP_PKT_VAL_PFC_IN1_SHIFT 0
#define CPUCP_PKT_VAL_PFC_IN1_MASK 0x0000000000000001ull
#define CPUCP_PKT_VAL_PFC_IN2_SHIFT 1
@@ -805,8 +828,13 @@ struct cpucp_packet {
__le32 nonce;
};
- /* For NIC requests */
- __le32 port_index;
+ union {
+ /* For NIC requests */
+ __le32 port_index;
+
+ /* For Generic packet sub index */
+ __le32 pkt_subidx;
+ };
};
struct cpucp_unmask_irq_arr_packet {
@@ -881,7 +909,9 @@ enum cpucp_in_attributes {
cpucp_in_max,
cpucp_in_lowest = 6,
cpucp_in_highest = 7,
- cpucp_in_reset_history
+ cpucp_in_reset_history,
+ cpucp_in_intr_alarm_a,
+ cpucp_in_intr_alarm_b,
};
enum cpucp_curr_attributes {
@@ -976,6 +1006,11 @@ enum pll_index {
IC_PLL = 16,
MC_PLL = 17,
EMMC_PLL = 18,
+ D2D_PLL = 19,
+ CS_PLL = 20,
+ C2C_PLL = 21,
+ NCH_PLL = 22,
+ C2M_PLL = 23,
PLL_MAX
};
@@ -1135,8 +1170,9 @@ enum cpucp_serdes_type {
HLS1_SERDES_TYPE,
HLS1H_SERDES_TYPE,
HLS2_SERDES_TYPE,
- UNKNOWN_SERDES_TYPE,
- MAX_NUM_SERDES_TYPE = UNKNOWN_SERDES_TYPE
+ HLS2_TYPE_1_SERDES_TYPE,
+ MAX_NUM_SERDES_TYPE, /* number of types */
+ UNKNOWN_SERDES_TYPE = 0xFFFF /* serdes_type is u16 */
};
struct cpucp_nic_info {
@@ -1161,6 +1197,21 @@ struct page_discard_info {
};
/*
+ * struct frac_val - fracture value represented by "integer.frac".
+ * @integer: the integer part of the fracture value;
+ * @frac: the fracture part of the fracture value.
+ */
+struct frac_val {
+ union {
+ struct {
+ __le16 integer;
+ __le16 frac;
+ };
+ __le32 val;
+ };
+};
+
+/*
* struct ser_val - the SER (symbol error rate) value is represented by "integer * 10 ^ -exp".
* @integer: the integer part of the SER value;
* @exp: the exponent part of the SER value.
@@ -1183,8 +1234,12 @@ struct ser_val {
* @pcs_link: has PCS link.
* @phy_ready: is PHY ready.
* @auto_neg: is Autoneg enabled.
- * @timeout_retransmission_cnt: timeout retransmission events
- * @high_ber_cnt: high ber events
+ * @timeout_retransmission_cnt: timeout retransmission events.
+ * @high_ber_cnt: high ber events.
+ * @pre_fec_ser: pre FEC SER value.
+ * @post_fec_ser: post FEC SER value.
+ * @throughput: measured throughput.
+ * @latency: measured latency.
*/
struct cpucp_nic_status {
__le32 port;
@@ -1200,6 +1255,10 @@ struct cpucp_nic_status {
__u8 auto_neg;
__le32 timeout_retransmission_cnt;
__le32 high_ber_cnt;
+ struct ser_val pre_fec_ser;
+ struct ser_val post_fec_ser;
+ struct frac_val bandwidth;
+ struct frac_val lat;
};
enum cpucp_hbm_row_replace_cause {
@@ -1292,6 +1351,7 @@ struct cpucp_dev_info_signed {
__u8 certificate[SEC_CERTIFICATE_BUF_SZ];
};
+#define DCORE_MON_REGS_SZ 512
/*
* struct dcore_monitor_regs_data - DCORE monitor regs data.
* the structure follows sync manager block layout. relevant only to Gaudi.
@@ -1302,11 +1362,11 @@ struct cpucp_dev_info_signed {
* @mon_status: array of monitor status.
*/
struct dcore_monitor_regs_data {
- __le32 mon_pay_addrl[512];
- __le32 mon_pay_addrh[512];
- __le32 mon_pay_data[512];
- __le32 mon_arm[512];
- __le32 mon_status[512];
+ __le32 mon_pay_addrl[DCORE_MON_REGS_SZ];
+ __le32 mon_pay_addrh[DCORE_MON_REGS_SZ];
+ __le32 mon_pay_data[DCORE_MON_REGS_SZ];
+ __le32 mon_arm[DCORE_MON_REGS_SZ];
+ __le32 mon_status[DCORE_MON_REGS_SZ];
};
/* contains SM data for each SYNC_MNGR (relevant only to Gaudi) */
@@ -1317,4 +1377,14 @@ struct cpucp_monitor_dump {
struct dcore_monitor_regs_data sync_mngr_e_n;
};
+/*
+ * The Type of the generic request (and other input arguments) will be fetched from user by reading
+ * from "pkt_subidx" field in struct cpucp_packet.
+ *
+ * HL_PASSTHROUGHT_VERSIONS - Fetch all firmware versions.
+ */
+enum hl_passthrough_type {
+ HL_PASSTHROUGH_VERSIONS,
+};
+
#endif /* CPUCP_IF_H */
diff --git a/drivers/misc/habanalabs/include/common/hl_boot_if.h b/drivers/accel/habanalabs/include/common/hl_boot_if.h
index e0ea51cc7475..2256add057c5 100644
--- a/drivers/misc/habanalabs/include/common/hl_boot_if.h
+++ b/drivers/accel/habanalabs/include/common/hl_boot_if.h
@@ -41,6 +41,19 @@ enum cpu_boot_err {
};
/*
+ * Mask for fatal failures
+ * This mask contains all possible fatal failures, and a dynamic code
+ * will clear the non-relevant ones.
+ */
+#define CPU_BOOT_ERR_FATAL_MASK \
+ ((1 << CPU_BOOT_ERR_DRAM_INIT_FAIL) | \
+ (1 << CPU_BOOT_ERR_PLL_FAIL) | \
+ (1 << CPU_BOOT_ERR_DEVICE_UNUSABLE_FAIL) | \
+ (1 << CPU_BOOT_ERR_BINNING_FAIL) | \
+ (1 << CPU_BOOT_ERR_DRAM_SKIPPED) | \
+ (1 << CPU_BOOT_ERR_EEPROM_FAIL))
+
+/*
* CPU error bits in BOOT_ERROR registers
*
* CPU_BOOT_ERR0_DRAM_INIT_FAIL DRAM initialization failed.
@@ -439,7 +452,7 @@ struct cpu_dyn_regs {
/* TODO: remove the desc magic after the code is updated to use message */
/* HCDM - Habana Communications Descriptor Magic */
#define HL_COMMS_DESC_MAGIC 0x4843444D
-#define HL_COMMS_DESC_VER 1
+#define HL_COMMS_DESC_VER 3
/* HCMv - Habana Communications Message + header version */
#define HL_COMMS_MSG_MAGIC_VALUE 0x48434D00
@@ -450,8 +463,10 @@ struct cpu_dyn_regs {
((ver) & HL_COMMS_MSG_MAGIC_VER_MASK))
#define HL_COMMS_MSG_MAGIC_V0 HL_COMMS_DESC_MAGIC
#define HL_COMMS_MSG_MAGIC_V1 HL_COMMS_MSG_MAGIC_VER(1)
+#define HL_COMMS_MSG_MAGIC_V2 HL_COMMS_MSG_MAGIC_VER(2)
+#define HL_COMMS_MSG_MAGIC_V3 HL_COMMS_MSG_MAGIC_VER(3)
-#define HL_COMMS_MSG_MAGIC HL_COMMS_MSG_MAGIC_V1
+#define HL_COMMS_MSG_MAGIC HL_COMMS_MSG_MAGIC_V3
#define HL_COMMS_MSG_MAGIC_VALIDATE_MAGIC(magic) \
(((magic) & HL_COMMS_MSG_MAGIC_MASK) == \
@@ -474,22 +489,31 @@ enum comms_msg_type {
/*
* Binning information shared between LKD and FW
- * @tpc_mask - TPC binning information
+ * @tpc_mask_l - TPC binning information lower 64 bit
* @dec_mask - Decoder binning information
- * @hbm_mask - HBM binning information
+ * @dram_mask - DRAM binning information
* @edma_mask - EDMA binning information
* @mme_mask_l - MME binning information lower 32
* @mme_mask_h - MME binning information upper 32
- * @reserved - reserved field for 64 bit alignment
+ * @rot_mask - Rotator binning information
+ * @xbar_mask - xBAR binning information
+ * @reserved - reserved field for future binning info w/o ABI change
+ * @tpc_mask_h - TPC binning information upper 64 bit
+ * @nic_mask - NIC binning information
*/
struct lkd_fw_binning_info {
- __le64 tpc_mask;
+ __le64 tpc_mask_l;
__le32 dec_mask;
- __le32 hbm_mask;
+ __le32 dram_mask;
__le32 edma_mask;
__le32 mme_mask_l;
__le32 mme_mask_h;
- __le32 reserved;
+ __le32 rot_mask;
+ __le32 xbar_mask;
+ __le32 reserved0;
+ __le64 tpc_mask_h;
+ __le64 nic_mask;
+ __le32 reserved1[8];
};
/* TODO: remove this struct after the code is updated to use message */
@@ -512,6 +536,23 @@ struct comms_msg_header {
__u8 reserved[4]; /* pad to 64 bit */
};
+enum lkd_fw_ascii_msg_lvls {
+ LKD_FW_ASCII_MSG_ERR = 0,
+ LKD_FW_ASCII_MSG_WRN = 1,
+ LKD_FW_ASCII_MSG_INF = 2,
+ LKD_FW_ASCII_MSG_DBG = 3,
+};
+
+#define LKD_FW_ASCII_MSG_MAX_LEN 128
+#define LKD_FW_ASCII_MSG_MAX 4 /* consider ABI when changing */
+
+struct lkd_fw_ascii_msg {
+ __u8 valid;
+ __u8 msg_lvl;
+ __u8 reserved[6];
+ char msg[LKD_FW_ASCII_MSG_MAX_LEN];
+};
+
/* this is the main FW descriptor - consider ABI when changing */
struct lkd_fw_comms_desc {
struct comms_desc_header header;
@@ -521,6 +562,8 @@ struct lkd_fw_comms_desc {
/* can be used for 1 more version w/o ABI change */
char reserved0[VERSION_MAX_LEN];
__le64 img_addr; /* address for next FW component load */
+ struct lkd_fw_binning_info binning_info;
+ struct lkd_fw_ascii_msg ascii_msg[LKD_FW_ASCII_MSG_MAX];
};
enum comms_reset_cause {
@@ -545,6 +588,8 @@ struct lkd_fw_comms_msg {
char reserved0[VERSION_MAX_LEN];
/* address for next FW component load */
__le64 img_addr;
+ struct lkd_fw_binning_info binning_info;
+ struct lkd_fw_ascii_msg ascii_msg[LKD_FW_ASCII_MSG_MAX];
};
struct {
__u8 reset_cause;
@@ -552,7 +597,7 @@ struct lkd_fw_comms_msg {
struct {
__u8 fw_cfg_skip; /* 1 - skip, 0 - don't skip */
};
- struct lkd_fw_binning_info binning_info;
+ struct lkd_fw_binning_info binning_conf;
};
};
@@ -699,4 +744,92 @@ struct comms_status {
};
};
+/**
+ * HL_MODULES_MAX_NUM is determined by the size of modules_mask in struct
+ * hl_component_versions
+ */
+enum hl_modules {
+ HL_MODULES_BOOT_INFO = 0,
+ HL_MODULES_EEPROM,
+ HL_MODULES_FDT,
+ HL_MODULES_I2C,
+ HL_MODULES_LZ4,
+ HL_MODULES_MBEDTLS,
+ HL_MODULES_MAX_NUM = 16
+};
+
+/**
+ * HL_COMPONENTS_MAX_NUM is determined by the size of components_mask in
+ * struct cpucp_versions
+ */
+enum hl_components {
+ HL_COMPONENTS_PID = 0,
+ HL_COMPONENTS_MGMT,
+ HL_COMPONENTS_PREBOOT,
+ HL_COMPONENTS_PPBOOT,
+ HL_COMPONENTS_ARMCP,
+ HL_COMPONENTS_CPLD,
+ HL_COMPONENTS_UBOOT,
+ HL_COMPONENTS_MAX_NUM = 16
+};
+
+/**
+ * struct hl_component_versions - versions associated with hl component.
+ * @struct_size: size of all the struct (including dynamic size of modules).
+ * @modules_offset: offset of the modules field in this struct.
+ * @component: version of the component itself.
+ * @fw_os: Firmware OS Version.
+ * @modules_mask: i'th bit (from LSB) is a flag - on if module i in enum
+ * hl_modules is used.
+ * @modules_counter: number of set bits in modules_mask.
+ * @reserved: reserved for future use.
+ * @modules: versions of the component's modules. Elborated explanation in
+ * struct cpucp_versions.
+ */
+struct hl_component_versions {
+ __le16 struct_size;
+ __le16 modules_offset;
+ __u8 component[VERSION_MAX_LEN];
+ __u8 fw_os[VERSION_MAX_LEN];
+ __le16 modules_mask;
+ __u8 modules_counter;
+ __u8 reserved[1];
+ __u8 modules[][VERSION_MAX_LEN];
+};
+
+/**
+ * struct hl_fw_versions - all versions (fuse, cpucp's components with their
+ * modules)
+ * @struct_size: size of all the struct (including dynamic size of components).
+ * @components_offset: offset of the components field in this struct.
+ * @fuse: silicon production FUSE information.
+ * @components_mask: i'th bit (from LSB) is a flag - on if component i in enum
+ * hl_components is used.
+ * @components_counter: number of set bits in components_mask.
+ * @reserved: reserved for future use.
+ * @components: versions of hl components. Index i corresponds to the i'th bit
+ * that is *on* in components_mask. For example, if
+ * components_mask=0b101, then *components represents arcpid and
+ * *(hl_component_versions*)((char*)components + 1') represents
+ * preboot, where 1' = components[0].struct_size.
+ */
+struct hl_fw_versions {
+ __le16 struct_size;
+ __le16 components_offset;
+ __u8 fuse[VERSION_MAX_LEN];
+ __le16 components_mask;
+ __u8 components_counter;
+ __u8 reserved[1];
+ struct hl_component_versions components[];
+};
+
+/* Max size of struct hl_component_versions */
+#define HL_COMPONENT_VERSIONS_MAX_SIZE \
+ (sizeof(struct hl_component_versions) + HL_MODULES_MAX_NUM * \
+ VERSION_MAX_LEN)
+
+/* Max size of struct hl_fw_versions */
+#define HL_FW_VERSIONS_MAX_SIZE (sizeof(struct hl_fw_versions) + \
+ HL_COMPONENTS_MAX_NUM * HL_COMPONENT_VERSIONS_MAX_SIZE)
+
#endif /* HL_BOOT_IF_H */
diff --git a/drivers/misc/habanalabs/include/common/qman_if.h b/drivers/accel/habanalabs/include/common/qman_if.h
index 7ed7739575ee..7ed7739575ee 100644
--- a/drivers/misc/habanalabs/include/common/qman_if.h
+++ b/drivers/accel/habanalabs/include/common/qman_if.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/cpu_if_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/cpu_if_regs.h
index cf80e31317ad..cf80e31317ad 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/cpu_if_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/cpu_if_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma0_core_masks.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma0_core_masks.h
index d079a37acab8..d079a37acab8 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma0_core_masks.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma0_core_masks.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma0_core_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma0_core_regs.h
index 1fdd5d5fc6d2..1fdd5d5fc6d2 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma0_core_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma0_core_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma0_qm_masks.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma0_qm_masks.h
index 48376aabc3ba..48376aabc3ba 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma0_qm_masks.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma0_qm_masks.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma0_qm_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma0_qm_regs.h
index 8e56a93d88a1..8e56a93d88a1 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma0_qm_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma0_qm_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma1_core_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma1_core_regs.h
index 4d8d8f26c5d4..4d8d8f26c5d4 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma1_core_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma1_core_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma1_qm_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma1_qm_regs.h
index c3ef300849be..c3ef300849be 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma1_qm_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma1_qm_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma2_core_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma2_core_regs.h
index a42862cd5ae0..a42862cd5ae0 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma2_core_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma2_core_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma2_qm_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma2_qm_regs.h
index 8c4d4e016852..8c4d4e016852 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma2_qm_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma2_qm_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma3_core_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma3_core_regs.h
index fb145f416fe6..fb145f416fe6 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma3_core_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma3_core_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma3_qm_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma3_qm_regs.h
index a4b461ca3d94..a4b461ca3d94 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma3_qm_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma3_qm_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma4_core_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma4_core_regs.h
index 192d11404b1c..192d11404b1c 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma4_core_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma4_core_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma4_qm_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma4_qm_regs.h
index f0cbda0d1e4d..f0cbda0d1e4d 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma4_qm_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma4_qm_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma5_core_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma5_core_regs.h
index 6e07c6fb6fc9..6e07c6fb6fc9 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma5_core_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma5_core_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma5_qm_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma5_qm_regs.h
index 0faea21756c5..0faea21756c5 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma5_qm_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma5_qm_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma6_core_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma6_core_regs.h
index 4962c13e2e2e..4962c13e2e2e 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma6_core_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma6_core_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma6_qm_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma6_qm_regs.h
index af87adb94c94..af87adb94c94 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma6_qm_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma6_qm_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma7_core_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma7_core_regs.h
index 8dd705d20195..8dd705d20195 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma7_core_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma7_core_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma7_qm_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma7_qm_regs.h
index d6c631f63e3e..d6c631f63e3e 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma7_qm_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma7_qm_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma_if_e_n_down_ch0_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma_if_e_n_down_ch0_regs.h
index 8c1c72df4469..8c1c72df4469 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma_if_e_n_down_ch0_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma_if_e_n_down_ch0_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma_if_e_n_down_ch1_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma_if_e_n_down_ch1_regs.h
index b2b593fcec30..b2b593fcec30 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma_if_e_n_down_ch1_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma_if_e_n_down_ch1_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma_if_e_n_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma_if_e_n_regs.h
index 8a10c6a76156..8a10c6a76156 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma_if_e_n_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma_if_e_n_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma_if_e_s_down_ch0_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma_if_e_s_down_ch0_regs.h
index cd61289a1e8a..cd61289a1e8a 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma_if_e_s_down_ch0_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma_if_e_s_down_ch0_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma_if_e_s_down_ch1_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma_if_e_s_down_ch1_regs.h
index 3f32370a14c7..3f32370a14c7 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma_if_e_s_down_ch1_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma_if_e_s_down_ch1_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma_if_e_s_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma_if_e_s_regs.h
index 78c18da7154b..78c18da7154b 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma_if_e_s_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma_if_e_s_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma_if_w_n_down_ch0_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma_if_w_n_down_ch0_regs.h
index 4ccaf8712948..4ccaf8712948 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma_if_w_n_down_ch0_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma_if_w_n_down_ch0_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma_if_w_n_down_ch1_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma_if_w_n_down_ch1_regs.h
index 9236f4183084..9236f4183084 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma_if_w_n_down_ch1_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma_if_w_n_down_ch1_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma_if_w_n_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma_if_w_n_regs.h
index da60893a5fab..da60893a5fab 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma_if_w_n_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma_if_w_n_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma_if_w_s_down_ch0_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma_if_w_s_down_ch0_regs.h
index 56ffc920d58a..56ffc920d58a 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma_if_w_s_down_ch0_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma_if_w_s_down_ch0_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma_if_w_s_down_ch1_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma_if_w_s_down_ch1_regs.h
index cbc642918deb..cbc642918deb 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma_if_w_s_down_ch1_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma_if_w_s_down_ch1_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma_if_w_s_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma_if_w_s_regs.h
index 2382bc41bea6..2382bc41bea6 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/dma_if_w_s_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/dma_if_w_s_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/gaudi_blocks.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/gaudi_blocks.h
index c7596aac7a5c..c7596aac7a5c 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/gaudi_blocks.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/gaudi_blocks.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/gaudi_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/gaudi_regs.h
index 1a6576666794..23ee8691db46 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/gaudi_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/gaudi_regs.h
@@ -320,4 +320,6 @@
#define mmPSOC_TPC_PLL_NR 0xC73100
#define mmIF_W_PLL_NR 0x488100
+#define mmPCIE_WRAP_RR_ELBI_RD_SEC_REG_CTRL 0xC01208
+
#endif /* ASIC_REG_GAUDI_REGS_H_ */
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/mme0_ctrl_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/mme0_ctrl_regs.h
index 083d073a0128..083d073a0128 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/mme0_ctrl_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/mme0_ctrl_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/mme0_qm_masks.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/mme0_qm_masks.h
index e6dd30ce0ca7..e6dd30ce0ca7 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/mme0_qm_masks.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/mme0_qm_masks.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/mme0_qm_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/mme0_qm_regs.h
index 4f078b328b00..4f078b328b00 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/mme0_qm_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/mme0_qm_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/mme1_ctrl_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/mme1_ctrl_regs.h
index 6c07f7d45490..6c07f7d45490 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/mme1_ctrl_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/mme1_ctrl_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/mme2_ctrl_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/mme2_ctrl_regs.h
index a1f2eb8b91bd..a1f2eb8b91bd 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/mme2_ctrl_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/mme2_ctrl_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/mme2_qm_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/mme2_qm_regs.h
index c1ea6a422010..c1ea6a422010 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/mme2_qm_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/mme2_qm_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/mme3_ctrl_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/mme3_ctrl_regs.h
index 36f6edc72e3d..36f6edc72e3d 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/mme3_ctrl_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/mme3_ctrl_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/mmu_up_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/mmu_up_regs.h
index 61465b599850..61465b599850 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/mmu_up_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/mmu_up_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/nic0_qm0_masks.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/nic0_qm0_masks.h
index bd37b6452133..bd37b6452133 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/nic0_qm0_masks.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/nic0_qm0_masks.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/nic0_qm0_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/nic0_qm0_regs.h
index 7c97f4041b8e..7c97f4041b8e 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/nic0_qm0_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/nic0_qm0_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/nic0_qm1_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/nic0_qm1_regs.h
index fe96c575b5c6..fe96c575b5c6 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/nic0_qm1_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/nic0_qm1_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/nic1_qm0_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/nic1_qm0_regs.h
index 0d1caf057ad0..0d1caf057ad0 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/nic1_qm0_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/nic1_qm0_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/nic1_qm1_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/nic1_qm1_regs.h
index 1b115ee6d6f0..1b115ee6d6f0 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/nic1_qm1_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/nic1_qm1_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/nic2_qm0_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/nic2_qm0_regs.h
index a89116a4586f..a89116a4586f 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/nic2_qm0_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/nic2_qm0_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/nic2_qm1_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/nic2_qm1_regs.h
index b7f091ddc89c..b7f091ddc89c 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/nic2_qm1_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/nic2_qm1_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/nic3_qm0_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/nic3_qm0_regs.h
index 4712cc62b009..4712cc62b009 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/nic3_qm0_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/nic3_qm0_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/nic3_qm1_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/nic3_qm1_regs.h
index 7fa040f65004..7fa040f65004 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/nic3_qm1_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/nic3_qm1_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/nic4_qm0_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/nic4_qm0_regs.h
index 99d5319672dd..99d5319672dd 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/nic4_qm0_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/nic4_qm0_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/nic4_qm1_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/nic4_qm1_regs.h
index 34b21b21da52..34b21b21da52 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/nic4_qm1_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/nic4_qm1_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_0_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_0_regs.h
index 2efa2a54deb4..2efa2a54deb4 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_0_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_0_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_1_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_1_regs.h
index a6047d4e2560..a6047d4e2560 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_1_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_1_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_2_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_2_regs.h
index 9de8442f9bc2..9de8442f9bc2 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_2_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_2_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_3_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_3_regs.h
index 34fd47685edd..34fd47685edd 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_3_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_3_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_4_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_4_regs.h
index 543a98f81767..543a98f81767 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_4_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_4_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_5_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_5_regs.h
index 95486b7ddf1d..95486b7ddf1d 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_5_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_5_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_6_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_6_regs.h
index b79c59887b21..b79c59887b21 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_6_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_6_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_7_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_7_regs.h
index 3a6a34ba2958..3a6a34ba2958 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_7_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/nif_rtr_ctrl_7_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/psoc_cpu_pll_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/psoc_cpu_pll_regs.h
index 2585c70f59ef..2585c70f59ef 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/psoc_cpu_pll_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/psoc_cpu_pll_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/psoc_etr_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/psoc_etr_regs.h
index b7c33e025db5..b7c33e025db5 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/psoc_etr_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/psoc_etr_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/psoc_global_conf_masks.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/psoc_global_conf_masks.h
index 6703e678ee9f..6703e678ee9f 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/psoc_global_conf_masks.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/psoc_global_conf_masks.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/psoc_global_conf_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/psoc_global_conf_regs.h
index 1b5cfcc1d85f..1b5cfcc1d85f 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/psoc_global_conf_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/psoc_global_conf_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/psoc_timestamp_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/psoc_timestamp_regs.h
index 9ce24597d4b0..9ce24597d4b0 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/psoc_timestamp_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/psoc_timestamp_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_0_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_0_regs.h
index ddf824392cf7..ddf824392cf7 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_0_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_0_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_1_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_1_regs.h
index c6d517dbbd54..c6d517dbbd54 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_1_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_1_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_2_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_2_regs.h
index 330e5b42d679..330e5b42d679 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_2_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_2_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_3_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_3_regs.h
index d749f1968e5e..d749f1968e5e 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_3_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_3_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_4_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_4_regs.h
index ad48773c4bbd..ad48773c4bbd 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_4_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_4_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_5_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_5_regs.h
index 6c27850ca3f5..6c27850ca3f5 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_5_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_5_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_6_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_6_regs.h
index a9ea89aa6405..a9ea89aa6405 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_6_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_6_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_7_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_7_regs.h
index a37772c531d9..a37772c531d9 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_7_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/sif_rtr_ctrl_7_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/stlb_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/stlb_regs.h
index 07d2a9000102..07d2a9000102 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/stlb_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/stlb_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/tpc0_cfg_masks.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/tpc0_cfg_masks.h
index 8f67c11c8de9..8f67c11c8de9 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/tpc0_cfg_masks.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/tpc0_cfg_masks.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/tpc0_cfg_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/tpc0_cfg_regs.h
index b82a906265a8..b82a906265a8 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/tpc0_cfg_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/tpc0_cfg_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/tpc0_qm_masks.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/tpc0_qm_masks.h
index 8e71532c6f36..8e71532c6f36 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/tpc0_qm_masks.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/tpc0_qm_masks.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/tpc0_qm_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/tpc0_qm_regs.h
index f9e310ab6df2..f9e310ab6df2 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/tpc0_qm_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/tpc0_qm_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/tpc1_cfg_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/tpc1_cfg_regs.h
index 6736c476d979..6736c476d979 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/tpc1_cfg_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/tpc1_cfg_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/tpc1_qm_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/tpc1_qm_regs.h
index af10ef7a87d9..af10ef7a87d9 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/tpc1_qm_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/tpc1_qm_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/tpc2_cfg_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/tpc2_cfg_regs.h
index 3e77c37952bc..3e77c37952bc 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/tpc2_cfg_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/tpc2_cfg_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/tpc2_qm_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/tpc2_qm_regs.h
index 2919e2fa58f8..2919e2fa58f8 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/tpc2_qm_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/tpc2_qm_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/tpc3_cfg_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/tpc3_cfg_regs.h
index 6d42469659f1..6d42469659f1 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/tpc3_cfg_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/tpc3_cfg_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/tpc3_qm_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/tpc3_qm_regs.h
index 5f2a0fd86c9e..5f2a0fd86c9e 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/tpc3_qm_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/tpc3_qm_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/tpc4_cfg_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/tpc4_cfg_regs.h
index 7a9447f39a74..7a9447f39a74 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/tpc4_cfg_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/tpc4_cfg_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/tpc4_qm_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/tpc4_qm_regs.h
index 80e63402f6e0..80e63402f6e0 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/tpc4_qm_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/tpc4_qm_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/tpc5_cfg_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/tpc5_cfg_regs.h
index f428f891935a..f428f891935a 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/tpc5_cfg_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/tpc5_cfg_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/tpc5_qm_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/tpc5_qm_regs.h
index cd3a810ff4c4..cd3a810ff4c4 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/tpc5_qm_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/tpc5_qm_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/tpc6_cfg_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/tpc6_cfg_regs.h
index eb251e72813f..eb251e72813f 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/tpc6_cfg_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/tpc6_cfg_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/tpc6_qm_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/tpc6_qm_regs.h
index e35ef7fd8b1c..e35ef7fd8b1c 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/tpc6_qm_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/tpc6_qm_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/tpc7_cfg_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/tpc7_cfg_regs.h
index 1887b10e58e2..1887b10e58e2 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/tpc7_cfg_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/tpc7_cfg_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/asic_reg/tpc7_qm_regs.h b/drivers/accel/habanalabs/include/gaudi/asic_reg/tpc7_qm_regs.h
index 5c36c972c027..5c36c972c027 100644
--- a/drivers/misc/habanalabs/include/gaudi/asic_reg/tpc7_qm_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi/asic_reg/tpc7_qm_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi/gaudi.h b/drivers/accel/habanalabs/include/gaudi/gaudi.h
index ffae107b1693..ffae107b1693 100644
--- a/drivers/misc/habanalabs/include/gaudi/gaudi.h
+++ b/drivers/accel/habanalabs/include/gaudi/gaudi.h
diff --git a/drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h b/drivers/accel/habanalabs/include/gaudi/gaudi_async_events.h
index c07ed4ed304c..c07ed4ed304c 100644
--- a/drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h
+++ b/drivers/accel/habanalabs/include/gaudi/gaudi_async_events.h
diff --git a/drivers/misc/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h b/drivers/accel/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h
index 479b6b038254..479b6b038254 100644
--- a/drivers/misc/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h
+++ b/drivers/accel/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h
diff --git a/drivers/misc/habanalabs/include/gaudi/gaudi_coresight.h b/drivers/accel/habanalabs/include/gaudi/gaudi_coresight.h
index c45cc7f4d4d7..c45cc7f4d4d7 100644
--- a/drivers/misc/habanalabs/include/gaudi/gaudi_coresight.h
+++ b/drivers/accel/habanalabs/include/gaudi/gaudi_coresight.h
diff --git a/drivers/misc/habanalabs/include/gaudi/gaudi_fw_if.h b/drivers/accel/habanalabs/include/gaudi/gaudi_fw_if.h
index 2dba02757d37..2dba02757d37 100644
--- a/drivers/misc/habanalabs/include/gaudi/gaudi_fw_if.h
+++ b/drivers/accel/habanalabs/include/gaudi/gaudi_fw_if.h
diff --git a/drivers/misc/habanalabs/include/gaudi/gaudi_masks.h b/drivers/accel/habanalabs/include/gaudi/gaudi_masks.h
index 880c57b26c63..880c57b26c63 100644
--- a/drivers/misc/habanalabs/include/gaudi/gaudi_masks.h
+++ b/drivers/accel/habanalabs/include/gaudi/gaudi_masks.h
diff --git a/drivers/misc/habanalabs/include/gaudi/gaudi_packets.h b/drivers/accel/habanalabs/include/gaudi/gaudi_packets.h
index 66fc083a7c6a..66fc083a7c6a 100644
--- a/drivers/misc/habanalabs/include/gaudi/gaudi_packets.h
+++ b/drivers/accel/habanalabs/include/gaudi/gaudi_packets.h
diff --git a/drivers/misc/habanalabs/include/gaudi/gaudi_reg_map.h b/drivers/accel/habanalabs/include/gaudi/gaudi_reg_map.h
index 92f25c2ae083..92f25c2ae083 100644
--- a/drivers/misc/habanalabs/include/gaudi/gaudi_reg_map.h
+++ b/drivers/accel/habanalabs/include/gaudi/gaudi_reg_map.h
diff --git a/drivers/accel/habanalabs/include/gaudi2/arc/gaudi2_arc_common_packets.h b/drivers/accel/habanalabs/include/gaudi2/arc/gaudi2_arc_common_packets.h
new file mode 100644
index 000000000000..22a6ab9a7f47
--- /dev/null
+++ b/drivers/accel/habanalabs/include/gaudi2/arc/gaudi2_arc_common_packets.h
@@ -0,0 +1,211 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2020 HabanaLabs Ltd.
+ * All Rights Reserved.
+ */
+
+#ifndef __GAUDI2_ARC_COMMON_PACKETS_H__
+#define __GAUDI2_ARC_COMMON_PACKETS_H__
+
+enum {
+ CPU_ID_SCHED_ARC0 = 0, /* FARM_ARC0 */
+ CPU_ID_SCHED_ARC1 = 1, /* FARM_ARC1 */
+ CPU_ID_SCHED_ARC2 = 2, /* FARM_ARC2 */
+ CPU_ID_SCHED_ARC3 = 3, /* FARM_ARC3 */
+ /* Dcore1 MME Engine ARC instance used as scheduler */
+ CPU_ID_SCHED_ARC4 = 4, /* DCORE1_MME0 */
+ /* Dcore3 MME Engine ARC instance used as scheduler */
+ CPU_ID_SCHED_ARC5 = 5, /* DCORE3_MME0 */
+
+ CPU_ID_TPC_QMAN_ARC0 = 6, /* DCORE0_TPC0 */
+ CPU_ID_TPC_QMAN_ARC1 = 7, /* DCORE0_TPC1 */
+ CPU_ID_TPC_QMAN_ARC2 = 8, /* DCORE0_TPC2 */
+ CPU_ID_TPC_QMAN_ARC3 = 9, /* DCORE0_TPC3 */
+ CPU_ID_TPC_QMAN_ARC4 = 10, /* DCORE0_TPC4 */
+ CPU_ID_TPC_QMAN_ARC5 = 11, /* DCORE0_TPC5 */
+ CPU_ID_TPC_QMAN_ARC6 = 12, /* DCORE1_TPC0 */
+ CPU_ID_TPC_QMAN_ARC7 = 13, /* DCORE1_TPC1 */
+ CPU_ID_TPC_QMAN_ARC8 = 14, /* DCORE1_TPC2 */
+ CPU_ID_TPC_QMAN_ARC9 = 15, /* DCORE1_TPC3 */
+ CPU_ID_TPC_QMAN_ARC10 = 16, /* DCORE1_TPC4 */
+ CPU_ID_TPC_QMAN_ARC11 = 17, /* DCORE1_TPC5 */
+ CPU_ID_TPC_QMAN_ARC12 = 18, /* DCORE2_TPC0 */
+ CPU_ID_TPC_QMAN_ARC13 = 19, /* DCORE2_TPC1 */
+ CPU_ID_TPC_QMAN_ARC14 = 20, /* DCORE2_TPC2 */
+ CPU_ID_TPC_QMAN_ARC15 = 21, /* DCORE2_TPC3 */
+ CPU_ID_TPC_QMAN_ARC16 = 22, /* DCORE2_TPC4 */
+ CPU_ID_TPC_QMAN_ARC17 = 23, /* DCORE2_TPC5 */
+ CPU_ID_TPC_QMAN_ARC18 = 24, /* DCORE3_TPC0 */
+ CPU_ID_TPC_QMAN_ARC19 = 25, /* DCORE3_TPC1 */
+ CPU_ID_TPC_QMAN_ARC20 = 26, /* DCORE3_TPC2 */
+ CPU_ID_TPC_QMAN_ARC21 = 27, /* DCORE3_TPC3 */
+ CPU_ID_TPC_QMAN_ARC22 = 28, /* DCORE3_TPC4 */
+ CPU_ID_TPC_QMAN_ARC23 = 29, /* DCORE3_TPC5 */
+ CPU_ID_TPC_QMAN_ARC24 = 30, /* DCORE0_TPC6 - Never present */
+
+ CPU_ID_MME_QMAN_ARC0 = 31, /* DCORE0_MME0 */
+ CPU_ID_MME_QMAN_ARC1 = 32, /* DCORE2_MME0 */
+
+ CPU_ID_EDMA_QMAN_ARC0 = 33, /* DCORE0_EDMA0 */
+ CPU_ID_EDMA_QMAN_ARC1 = 34, /* DCORE0_EDMA1 */
+ CPU_ID_EDMA_QMAN_ARC2 = 35, /* DCORE1_EDMA0 */
+ CPU_ID_EDMA_QMAN_ARC3 = 36, /* DCORE1_EDMA1 */
+ CPU_ID_EDMA_QMAN_ARC4 = 37, /* DCORE2_EDMA0 */
+ CPU_ID_EDMA_QMAN_ARC5 = 38, /* DCORE2_EDMA1 */
+ CPU_ID_EDMA_QMAN_ARC6 = 39, /* DCORE3_EDMA0 */
+ CPU_ID_EDMA_QMAN_ARC7 = 40, /* DCORE3_EDMA1 */
+
+ CPU_ID_PDMA_QMAN_ARC0 = 41, /* DCORE0_PDMA0 */
+ CPU_ID_PDMA_QMAN_ARC1 = 42, /* DCORE0_PDMA1 */
+
+ CPU_ID_ROT_QMAN_ARC0 = 43, /* ROT0 */
+ CPU_ID_ROT_QMAN_ARC1 = 44, /* ROT1 */
+
+ CPU_ID_NIC_QMAN_ARC0 = 45, /* NIC0_0 */
+ CPU_ID_NIC_QMAN_ARC1 = 46, /* NIC0_1 */
+ CPU_ID_NIC_QMAN_ARC2 = 47, /* NIC1_0 */
+ CPU_ID_NIC_QMAN_ARC3 = 48, /* NIC1_1 */
+ CPU_ID_NIC_QMAN_ARC4 = 49, /* NIC2_0 */
+ CPU_ID_NIC_QMAN_ARC5 = 50, /* NIC2_1 */
+ CPU_ID_NIC_QMAN_ARC6 = 51, /* NIC3_0 */
+ CPU_ID_NIC_QMAN_ARC7 = 52, /* NIC3_1 */
+ CPU_ID_NIC_QMAN_ARC8 = 53, /* NIC4_0 */
+ CPU_ID_NIC_QMAN_ARC9 = 54, /* NIC4_1 */
+ CPU_ID_NIC_QMAN_ARC10 = 55, /* NIC5_0 */
+ CPU_ID_NIC_QMAN_ARC11 = 56, /* NIC5_1 */
+ CPU_ID_NIC_QMAN_ARC12 = 57, /* NIC6_0 */
+ CPU_ID_NIC_QMAN_ARC13 = 58, /* NIC6_1 */
+ CPU_ID_NIC_QMAN_ARC14 = 59, /* NIC7_0 */
+ CPU_ID_NIC_QMAN_ARC15 = 60, /* NIC7_1 */
+ CPU_ID_NIC_QMAN_ARC16 = 61, /* NIC8_0 */
+ CPU_ID_NIC_QMAN_ARC17 = 62, /* NIC8_1 */
+ CPU_ID_NIC_QMAN_ARC18 = 63, /* NIC9_0 */
+ CPU_ID_NIC_QMAN_ARC19 = 64, /* NIC9_1 */
+ CPU_ID_NIC_QMAN_ARC20 = 65, /* NIC10_0 */
+ CPU_ID_NIC_QMAN_ARC21 = 66, /* NIC10_1 */
+ CPU_ID_NIC_QMAN_ARC22 = 67, /* NIC11_0 */
+ CPU_ID_NIC_QMAN_ARC23 = 68, /* NIC11_1 */
+
+ CPU_ID_MAX = 69,
+ CPU_ID_SCHED_MAX = 6,
+
+ CPU_ID_ALL = 0xFE,
+ CPU_ID_INVALID = 0xFF,
+};
+
+enum arc_regions_t {
+ ARC_REGION0_UNSED = 0,
+ /*
+ * Extension registers
+ * None
+ */
+ ARC_REGION1_SRAM = 1,
+ /*
+ * Extension registers
+ * AUX_SRAM_LSB_ADDR
+ * AUX_SRAM_MSB_ADDR
+ * ARC Address: 0x1000_0000
+ */
+ ARC_REGION2_CFG = 2,
+ /*
+ * Extension registers
+ * AUX_CFG_LSB_ADDR
+ * AUX_CFG_MSB_ADDR
+ * ARC Address: 0x2000_0000
+ */
+ ARC_REGION3_GENERAL = 3,
+ /*
+ * Extension registers
+ * AUX_GENERAL_PURPOSE_LSB_ADDR_0
+ * AUX_GENERAL_PURPOSE_MSB_ADDR_0
+ * ARC Address: 0x3000_0000
+ */
+ ARC_REGION4_HBM0_FW = 4,
+ /*
+ * Extension registers
+ * AUX_HBM0_LSB_ADDR
+ * AUX_HBM0_MSB_ADDR
+ * AUX_HBM0_OFFSET
+ * ARC Address: 0x4000_0000
+ */
+ ARC_REGION5_HBM1_GC_DATA = 5,
+ /*
+ * Extension registers
+ * AUX_HBM1_LSB_ADDR
+ * AUX_HBM1_MSB_ADDR
+ * AUX_HBM1_OFFSET
+ * ARC Address: 0x5000_0000
+ */
+ ARC_REGION6_HBM2_GC_DATA = 6,
+ /*
+ * Extension registers
+ * AUX_HBM2_LSB_ADDR
+ * AUX_HBM2_MSB_ADDR
+ * AUX_HBM2_OFFSET
+ * ARC Address: 0x6000_0000
+ */
+ ARC_REGION7_HBM3_GC_DATA = 7,
+ /*
+ * Extension registers
+ * AUX_HBM3_LSB_ADDR
+ * AUX_HBM3_MSB_ADDR
+ * AUX_HBM3_OFFSET
+ * ARC Address: 0x7000_0000
+ */
+ ARC_REGION8_DCCM = 8,
+ /*
+ * Extension registers
+ * None
+ * ARC Address: 0x8000_0000
+ */
+ ARC_REGION9_PCIE = 9,
+ /*
+ * Extension registers
+ * AUX_PCIE_LSB_ADDR
+ * AUX_PCIE_MSB_ADDR
+ * ARC Address: 0x9000_0000
+ */
+ ARC_REGION10_GENERAL = 10,
+ /*
+ * Extension registers
+ * AUX_GENERAL_PURPOSE_LSB_ADDR_1
+ * AUX_GENERAL_PURPOSE_MSB_ADDR_1
+ * ARC Address: 0xA000_0000
+ */
+ ARC_REGION11_GENERAL = 11,
+ /*
+ * Extension registers
+ * AUX_GENERAL_PURPOSE_LSB_ADDR_2
+ * AUX_GENERAL_PURPOSE_MSB_ADDR_2
+ * ARC Address: 0xB000_0000
+ */
+ ARC_REGION12_GENERAL = 12,
+ /*
+ * Extension registers
+ * AUX_GENERAL_PURPOSE_LSB_ADDR_3
+ * AUX_GENERAL_PURPOSE_MSB_ADDR_3
+ * ARC Address: 0xC000_0000
+ */
+ ARC_REGION13_GENERAL = 13,
+ /*
+ * Extension registers
+ * AUX_GENERAL_PURPOSE_LSB_ADDR_4
+ * AUX_GENERAL_PURPOSE_MSB_ADDR_4
+ * ARC Address: 0xD000_0000
+ */
+ ARC_REGION14_GENERAL = 14,
+ /*
+ * Extension registers
+ * AUX_GENERAL_PURPOSE_LSB_ADDR_5
+ * AUX_GENERAL_PURPOSE_MSB_ADDR_5
+ * ARC Address: 0xE000_0000
+ */
+ ARC_REGION15_LBU = 15
+ /*
+ * Extension registers
+ * None
+ * ARC Address: 0xF000_0000
+ */
+};
+
+#endif /* __GAUDI2_ARC_COMMON_PACKETS_H__ */
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/arc_farm_arc0_acp_eng_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/arc_farm_arc0_acp_eng_regs.h
index 1974df13b5f9..1974df13b5f9 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/arc_farm_arc0_acp_eng_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/arc_farm_arc0_acp_eng_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/arc_farm_arc0_aux_masks.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/arc_farm_arc0_aux_masks.h
index fc2c52af6509..fc2c52af6509 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/arc_farm_arc0_aux_masks.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/arc_farm_arc0_aux_masks.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/arc_farm_arc0_aux_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/arc_farm_arc0_aux_regs.h
index 5345b5faa3a2..5345b5faa3a2 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/arc_farm_arc0_aux_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/arc_farm_arc0_aux_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/arc_farm_arc0_dup_eng_axuser_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/arc_farm_arc0_dup_eng_axuser_regs.h
index bde077eed285..bde077eed285 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/arc_farm_arc0_dup_eng_axuser_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/arc_farm_arc0_dup_eng_axuser_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/arc_farm_arc0_dup_eng_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/arc_farm_arc0_dup_eng_regs.h
index 491af75c12c3..491af75c12c3 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/arc_farm_arc0_dup_eng_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/arc_farm_arc0_dup_eng_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_ctx_axuser_masks.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_ctx_axuser_masks.h
index 12d6a124a2e9..12d6a124a2e9 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_ctx_axuser_masks.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_ctx_axuser_masks.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_ctx_axuser_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_ctx_axuser_regs.h
index 23f9d2df52a7..23f9d2df52a7 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_ctx_axuser_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_ctx_axuser_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_ctx_masks.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_ctx_masks.h
index bee4de0b28d6..bee4de0b28d6 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_ctx_masks.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_ctx_masks.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_ctx_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_ctx_regs.h
index b9f09e8199e6..b9f09e8199e6 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_ctx_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_ctx_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_kdma_cgm_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_kdma_cgm_regs.h
index d6dd2c066fa9..d6dd2c066fa9 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_kdma_cgm_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_kdma_cgm_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_masks.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_masks.h
index 5903dbacec80..5903dbacec80 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_masks.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_masks.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_regs.h
index e312cf810c0e..e312cf810c0e 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/arc_farm_kdma_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/cpu_if_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/cpu_if_regs.h
index 9b3eceec9d5d..9b3eceec9d5d 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/cpu_if_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/cpu_if_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_dec0_cmd_masks.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_dec0_cmd_masks.h
index 296ab832013f..296ab832013f 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_dec0_cmd_masks.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_dec0_cmd_masks.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_dec0_cmd_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_dec0_cmd_regs.h
index e26f0d77c9dc..e26f0d77c9dc 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_dec0_cmd_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_dec0_cmd_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_core_ctx_axuser_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_core_ctx_axuser_regs.h
index 8de48939243b..8de48939243b 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_core_ctx_axuser_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_core_ctx_axuser_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_core_ctx_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_core_ctx_regs.h
index f73e76c8f5bd..f73e76c8f5bd 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_core_ctx_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_core_ctx_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_core_masks.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_core_masks.h
index d600f6bf70d8..d600f6bf70d8 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_core_masks.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_core_masks.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_core_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_core_regs.h
index 84f068e4c602..84f068e4c602 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_core_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_core_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_qm_arc_aux_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_qm_arc_aux_regs.h
index 0fc45300df81..0fc45300df81 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_qm_arc_aux_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_qm_arc_aux_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_qm_axuser_nonsecured_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_qm_axuser_nonsecured_regs.h
index 88d2a133f129..88d2a133f129 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_qm_axuser_nonsecured_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_qm_axuser_nonsecured_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_qm_cgm_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_qm_cgm_regs.h
index 0b0a76a5b2a0..0b0a76a5b2a0 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_qm_cgm_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_qm_cgm_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_qm_masks.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_qm_masks.h
index 102e2a65811c..102e2a65811c 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_qm_masks.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_qm_masks.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_qm_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_qm_regs.h
index 32d475b9ed11..32d475b9ed11 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_qm_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_edma0_qm_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_edma1_core_ctx_axuser_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_edma1_core_ctx_axuser_regs.h
index b608a634562f..b608a634562f 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_edma1_core_ctx_axuser_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_edma1_core_ctx_axuser_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_edma1_qm_axuser_nonsecured_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_edma1_qm_axuser_nonsecured_regs.h
index c3a462f2a9ac..c3a462f2a9ac 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_edma1_qm_axuser_nonsecured_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_edma1_qm_axuser_nonsecured_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_hmmu0_mmu_masks.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_hmmu0_mmu_masks.h
index df51eac10dd7..2965b6a3b423 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_hmmu0_mmu_masks.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_hmmu0_mmu_masks.h
@@ -150,8 +150,7 @@
#define DCORE0_HMMU0_MMU_STATIC_MULTI_PAGE_SIZE_HOP1_PAGE_SIZE_SHIFT 16
#define DCORE0_HMMU0_MMU_STATIC_MULTI_PAGE_SIZE_HOP1_PAGE_SIZE_MASK 0xF0000
#define DCORE0_HMMU0_MMU_STATIC_MULTI_PAGE_SIZE_CFG_8_BITS_HOP_MODE_EN_SHIFT 20
-#define DCORE0_HMMU0_MMU_STATIC_MULTI_PAGE_SIZE_CFG_8_BITS_HOP_MODE_EN_MASK \
-0x100000
+#define DCORE0_HMMU0_MMU_STATIC_MULTI_PAGE_SIZE_CFG_8_BITS_HOP_MODE_EN_MASK 0x100000
/* DCORE0_HMMU0_MMU_CORE_SEP_CACHE_RNG */
#define DCORE0_HMMU0_MMU_CORE_SEP_CACHE_RNG_CORE_SET_MASK_SHIFT 0
@@ -235,23 +234,19 @@
/* DCORE0_HMMU0_MMU_ILLEGAL_ADDR_WRITE_63_32 */
#define DCORE0_HMMU0_MMU_ILLEGAL_ADDR_WRITE_63_32_ILLEGAL_ADDR_63_32_SHIFT 0
-#define DCORE0_HMMU0_MMU_ILLEGAL_ADDR_WRITE_63_32_ILLEGAL_ADDR_63_32_MASK \
-0xFFFFFFFF
+#define DCORE0_HMMU0_MMU_ILLEGAL_ADDR_WRITE_63_32_ILLEGAL_ADDR_63_32_MASK 0xFFFFFFFF
/* DCORE0_HMMU0_MMU_ILLEGAL_ADDR_WRITE_31_0 */
#define DCORE0_HMMU0_MMU_ILLEGAL_ADDR_WRITE_31_0_ILLEGAL_ADDR_31_0_SHIFT 0
-#define DCORE0_HMMU0_MMU_ILLEGAL_ADDR_WRITE_31_0_ILLEGAL_ADDR_31_0_MASK \
-0xFFFFFFFF
+#define DCORE0_HMMU0_MMU_ILLEGAL_ADDR_WRITE_31_0_ILLEGAL_ADDR_31_0_MASK 0xFFFFFFFF
/* DCORE0_HMMU0_MMU_ILLEGAL_ADDR_READ_63_32 */
#define DCORE0_HMMU0_MMU_ILLEGAL_ADDR_READ_63_32_ILLEGAL_ADDR_63_32_SHIFT 0
-#define DCORE0_HMMU0_MMU_ILLEGAL_ADDR_READ_63_32_ILLEGAL_ADDR_63_32_MASK \
-0xFFFFFFFF
+#define DCORE0_HMMU0_MMU_ILLEGAL_ADDR_READ_63_32_ILLEGAL_ADDR_63_32_MASK 0xFFFFFFFF
/* DCORE0_HMMU0_MMU_ILLEGAL_ADDR_READ_31_0 */
#define DCORE0_HMMU0_MMU_ILLEGAL_ADDR_READ_31_0_ILLEGAL_ADDR_31_0_SHIFT 0
-#define DCORE0_HMMU0_MMU_ILLEGAL_ADDR_READ_31_0_ILLEGAL_ADDR_31_0_MASK \
-0xFFFFFFFF
+#define DCORE0_HMMU0_MMU_ILLEGAL_ADDR_READ_31_0_ILLEGAL_ADDR_31_0_MASK 0xFFFFFFFF
/* DCORE0_HMMU0_MMU_RAZWI_WRITE_VLD */
#define DCORE0_HMMU0_MMU_RAZWI_WRITE_VLD_R_SHIFT 0
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_hmmu0_mmu_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_hmmu0_mmu_regs.h
index 08ccd695ec89..08ccd695ec89 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_hmmu0_mmu_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_hmmu0_mmu_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_hmmu0_stlb_masks.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_hmmu0_stlb_masks.h
index 192eba5f07bb..a311778b21e7 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_hmmu0_stlb_masks.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_hmmu0_stlb_masks.h
@@ -92,8 +92,7 @@
#define DCORE0_HMMU0_STLB_HOP_CONFIGURATION_ONLY_LARGE_PAGE_SHIFT 20
#define DCORE0_HMMU0_STLB_HOP_CONFIGURATION_ONLY_LARGE_PAGE_MASK 0x100000
#define DCORE0_HMMU0_STLB_HOP_CONFIGURATION_LARGE_PAGE_INDICATION_BIT_SHIFT 21
-#define DCORE0_HMMU0_STLB_HOP_CONFIGURATION_LARGE_PAGE_INDICATION_BIT_MASK \
-0x7E00000
+#define DCORE0_HMMU0_STLB_HOP_CONFIGURATION_LARGE_PAGE_INDICATION_BIT_MASK 0x7E00000
/* DCORE0_HMMU0_STLB_LINK_LIST_LOOKUP_MASK_63_32 */
#define DCORE0_HMMU0_STLB_LINK_LIST_LOOKUP_MASK_63_32_R_SHIFT 0
@@ -228,12 +227,8 @@
#define DCORE0_HMMU0_STLB_MEM_READ_ARPROT_R_MASK 0x7
/* DCORE0_HMMU0_STLB_RANGE_CACHE_INVALIDATION */
-#define \
-DCORE0_HMMU0_STLB_RANGE_CACHE_INVALIDATION_RANGE_INVALIDATION_ENABLE_SHIFT \
-0
-#define \
-DCORE0_HMMU0_STLB_RANGE_CACHE_INVALIDATION_RANGE_INVALIDATION_ENABLE_MASK \
-0x1
+#define DCORE0_HMMU0_STLB_RANGE_CACHE_INVALIDATION_RANGE_INVALIDATION_ENABLE_SHIFT 0
+#define DCORE0_HMMU0_STLB_RANGE_CACHE_INVALIDATION_RANGE_INVALIDATION_ENABLE_MASK 0x1
#define DCORE0_HMMU0_STLB_RANGE_CACHE_INVALIDATION_INVALIDATION_ASID_EN_SHIFT 1
#define DCORE0_HMMU0_STLB_RANGE_CACHE_INVALIDATION_INVALIDATION_ASID_EN_MASK 0x2
#define DCORE0_HMMU0_STLB_RANGE_CACHE_INVALIDATION_INVALIDATION_ASID_SHIFT 2
@@ -261,53 +256,43 @@ DCORE0_HMMU0_STLB_RANGE_CACHE_INVALIDATION_RANGE_INVALIDATION_ENABLE_MASK \
/* DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_0 */
#define DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_0_ASID_POLY_MATRIX_H3_SHIFT 0
-#define DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_0_ASID_POLY_MATRIX_H3_MASK \
-0x1FF
+#define DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_0_ASID_POLY_MATRIX_H3_MASK 0x1FF
/* DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_1 */
#define DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_1_ASID_POLY_MATRIX_H3_SHIFT 0
-#define DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_1_ASID_POLY_MATRIX_H3_MASK \
-0x1FF
+#define DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_1_ASID_POLY_MATRIX_H3_MASK 0x1FF
/* DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_2 */
#define DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_2_ASID_POLY_MATRIX_H3_SHIFT 0
-#define DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_2_ASID_POLY_MATRIX_H3_MASK \
-0x1FF
+#define DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_2_ASID_POLY_MATRIX_H3_MASK 0x1FF
/* DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_3 */
#define DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_3_ASID_POLY_MATRIX_H3_SHIFT 0
-#define DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_3_ASID_POLY_MATRIX_H3_MASK \
-0x1FF
+#define DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_3_ASID_POLY_MATRIX_H3_MASK 0x1FF
/* DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_4 */
#define DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_4_ASID_POLY_MATRIX_H3_SHIFT 0
-#define DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_4_ASID_POLY_MATRIX_H3_MASK \
-0x1FF
+#define DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_4_ASID_POLY_MATRIX_H3_MASK 0x1FF
/* DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_5 */
#define DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_5_ASID_POLY_MATRIX_H3_SHIFT 0
-#define DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_5_ASID_POLY_MATRIX_H3_MASK \
-0x1FF
+#define DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_5_ASID_POLY_MATRIX_H3_MASK 0x1FF
/* DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_6 */
#define DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_6_ASID_POLY_MATRIX_H3_SHIFT 0
-#define DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_6_ASID_POLY_MATRIX_H3_MASK \
-0x1FF
+#define DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_6_ASID_POLY_MATRIX_H3_MASK 0x1FF
/* DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_7 */
#define DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_7_ASID_POLY_MATRIX_H3_SHIFT 0
-#define DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_7_ASID_POLY_MATRIX_H3_MASK \
-0x1FF
+#define DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_7_ASID_POLY_MATRIX_H3_MASK 0x1FF
/* DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_8 */
#define DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_8_ASID_POLY_MATRIX_H3_SHIFT 0
-#define DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_8_ASID_POLY_MATRIX_H3_MASK \
-0x1FF
+#define DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_8_ASID_POLY_MATRIX_H3_MASK 0x1FF
/* DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_9 */
#define DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_9_ASID_POLY_MATRIX_H3_SHIFT 0
-#define DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_9_ASID_POLY_MATRIX_H3_MASK \
-0x1FF
+#define DCORE0_HMMU0_STLB_ASID_SCR_POLY_MATRIX_H3_9_ASID_POLY_MATRIX_H3_MASK 0x1FF
/* DCORE0_HMMU0_STLB_ASID_SCR_POLY_MAT_H3_10 */
#define DCORE0_HMMU0_STLB_ASID_SCR_POLY_MAT_H3_10_ASID_POLY_MATRIX_H3_SHIFT 0
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_hmmu0_stlb_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_hmmu0_stlb_regs.h
index 864a259f68e2..864a259f68e2 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_hmmu0_stlb_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_hmmu0_stlb_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_acc_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_acc_regs.h
index 07bed3ec740e..07bed3ec740e 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_acc_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_acc_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_cout0_master_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_cout0_master_regs.h
index c9043979fd69..c9043979fd69 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_cout0_master_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_cout0_master_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_cout0_slave_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_cout0_slave_regs.h
index 7d74aea4576f..7d74aea4576f 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_cout0_slave_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_cout0_slave_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_cout1_master_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_cout1_master_regs.h
index f6f519eb5f6f..f6f519eb5f6f 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_cout1_master_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_cout1_master_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_cout1_slave_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_cout1_slave_regs.h
index 0e0c056ade9b..0e0c056ade9b 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_cout1_slave_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_cout1_slave_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in0_master_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in0_master_regs.h
index 34c6134a2f93..34c6134a2f93 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in0_master_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in0_master_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in0_slave_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in0_slave_regs.h
index 55065032f87c..55065032f87c 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in0_slave_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in0_slave_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in1_master_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in1_master_regs.h
index 6022b387eacf..6022b387eacf 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in1_master_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in1_master_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in1_slave_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in1_slave_regs.h
index f9c9b01f0d1a..f9c9b01f0d1a 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in1_slave_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in1_slave_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in2_master_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in2_master_regs.h
index d96119b8c435..d96119b8c435 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in2_master_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in2_master_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in2_slave_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in2_slave_regs.h
index c80d6817efe1..c80d6817efe1 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in2_slave_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in2_slave_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in3_master_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in3_master_regs.h
index 753b31dc1760..753b31dc1760 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in3_master_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in3_master_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in3_slave_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in3_slave_regs.h
index f68d043edcd9..f68d043edcd9 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in3_slave_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in3_slave_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in4_master_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in4_master_regs.h
index a6dce326bd74..a6dce326bd74 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in4_master_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in4_master_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in4_slave_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in4_slave_regs.h
index 5ace0f43cc78..5ace0f43cc78 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in4_slave_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_agu_in4_slave_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_base_addr_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_base_addr_regs.h
index b375393dfdc0..b375393dfdc0 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_base_addr_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_base_addr_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_non_tensor_end_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_non_tensor_end_regs.h
index 7c22b9383f3c..fb53feb0a1a6 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_non_tensor_end_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_non_tensor_end_regs.h
@@ -20,8 +20,7 @@
*****************************************
*/
-#define mmDCORE0_MME_CTRL_LO_ARCH_NON_TENSOR_END_CONV_KERNEL_SIZE_MINUS_1 \
-0x40CB280
+#define mmDCORE0_MME_CTRL_LO_ARCH_NON_TENSOR_END_CONV_KERNEL_SIZE_MINUS_1 0x40CB280
#define mmDCORE0_MME_CTRL_LO_ARCH_NON_TENSOR_END_CONV_LOW 0x40CB284
@@ -29,8 +28,7 @@
#define mmDCORE0_MME_CTRL_LO_ARCH_NON_TENSOR_END_OUTER_LOOP 0x40CB28C
-#define mmDCORE0_MME_CTRL_LO_ARCH_NON_TENSOR_END_NUM_ITERATIONS_MINUS_1 \
-0x40CB290
+#define mmDCORE0_MME_CTRL_LO_ARCH_NON_TENSOR_END_NUM_ITERATIONS_MINUS_1 0x40CB290
#define mmDCORE0_MME_CTRL_LO_ARCH_NON_TENSOR_END_SB_REPEAT 0x40CB294
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_non_tensor_start_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_non_tensor_start_regs.h
index d17c165faf8b..d17c165faf8b 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_non_tensor_start_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_non_tensor_start_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_tensor_a_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_tensor_a_regs.h
index 7b77884e0024..7b77884e0024 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_tensor_a_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_tensor_a_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_tensor_b_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_tensor_b_regs.h
index a2a2ba454d6d..a2a2ba454d6d 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_tensor_b_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_tensor_b_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_tensor_cout_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_tensor_cout_regs.h
index 7ad7b197cf87..7ad7b197cf87 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_tensor_cout_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_arch_tensor_cout_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_masks.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_masks.h
index f699661d76aa..da0c94075e64 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_masks.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_masks.h
@@ -78,8 +78,7 @@
#define DCORE0_MME_CTRL_LO_ARCH_SYNC_OBJ_DW0_MASTER_WAIT_SLAVE_FENCE_SHIFT 15
#define DCORE0_MME_CTRL_LO_ARCH_SYNC_OBJ_DW0_MASTER_WAIT_SLAVE_FENCE_MASK 0x8000
#define DCORE0_MME_CTRL_LO_ARCH_SYNC_OBJ_DW0_SLAVE_SEND_FENCE2MASTER_SHIFT 16
-#define DCORE0_MME_CTRL_LO_ARCH_SYNC_OBJ_DW0_SLAVE_SEND_FENCE2MASTER_MASK \
-0x10000
+#define DCORE0_MME_CTRL_LO_ARCH_SYNC_OBJ_DW0_SLAVE_SEND_FENCE2MASTER_MASK 0x10000
#define DCORE0_MME_CTRL_LO_ARCH_SYNC_OBJ_DW0_SLAVE_SIGNAL_EN_SHIFT 17
#define DCORE0_MME_CTRL_LO_ARCH_SYNC_OBJ_DW0_SLAVE_SIGNAL_EN_MASK 0x20000
#define DCORE0_MME_CTRL_LO_ARCH_SYNC_OBJ_DW0_SLAVE0_USE_SLV_ADR_SHIFT 18
@@ -87,11 +86,9 @@
#define DCORE0_MME_CTRL_LO_ARCH_SYNC_OBJ_DW0_SLAVE1_USE_SLV_ADR_SHIFT 19
#define DCORE0_MME_CTRL_LO_ARCH_SYNC_OBJ_DW0_SLAVE1_USE_SLV_ADR_MASK 0x80000
#define DCORE0_MME_CTRL_LO_ARCH_SYNC_OBJ_DW0_SLAVE0_USE_MSTR_ADR_PLUS4_SHIFT 20
-#define DCORE0_MME_CTRL_LO_ARCH_SYNC_OBJ_DW0_SLAVE0_USE_MSTR_ADR_PLUS4_MASK \
-0x100000
+#define DCORE0_MME_CTRL_LO_ARCH_SYNC_OBJ_DW0_SLAVE0_USE_MSTR_ADR_PLUS4_MASK 0x100000
#define DCORE0_MME_CTRL_LO_ARCH_SYNC_OBJ_DW0_SLAVE1_USE_MSTR_ADR_PLUS4_SHIFT 21
-#define DCORE0_MME_CTRL_LO_ARCH_SYNC_OBJ_DW0_SLAVE1_USE_MSTR_ADR_PLUS4_MASK \
-0x200000
+#define DCORE0_MME_CTRL_LO_ARCH_SYNC_OBJ_DW0_SLAVE1_USE_MSTR_ADR_PLUS4_MASK 0x200000
/* DCORE0_MME_CTRL_LO_ARCH_SYNC_OBJ_ADDR0 */
#define DCORE0_MME_CTRL_LO_ARCH_SYNC_OBJ_ADDR0_V_SHIFT 0
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_mme_axuser_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_mme_axuser_regs.h
index a51617a6f1fb..a51617a6f1fb 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_mme_axuser_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_mme_axuser_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_regs.h
index 1b91c9c13132..1b91c9c13132 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_ctrl_lo_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_arc_acp_eng_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_arc_acp_eng_regs.h
index f702fe6e9365..f702fe6e9365 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_arc_acp_eng_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_arc_acp_eng_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_arc_aux_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_arc_aux_regs.h
index 917f8ab88373..917f8ab88373 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_arc_aux_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_arc_aux_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_arc_dup_eng_axuser_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_arc_dup_eng_axuser_regs.h
index c7ebaf73c51e..c7ebaf73c51e 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_arc_dup_eng_axuser_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_arc_dup_eng_axuser_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_arc_dup_eng_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_arc_dup_eng_regs.h
index 61654e37335b..61654e37335b 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_arc_dup_eng_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_arc_dup_eng_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_axuser_nonsecured_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_axuser_nonsecured_regs.h
index 32089b8250ed..32089b8250ed 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_axuser_nonsecured_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_axuser_nonsecured_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_axuser_secured_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_axuser_secured_regs.h
index e168c1cc2a7d..e168c1cc2a7d 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_axuser_secured_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_axuser_secured_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_cgm_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_cgm_regs.h
index 543aba18ef68..543aba18ef68 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_cgm_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_cgm_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_regs.h
index c45583fcc2cf..c45583fcc2cf 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_qm_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_sbte0_masks.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_sbte0_masks.h
index 077ae5232790..077ae5232790 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_sbte0_masks.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_sbte0_masks.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_sbte0_mstr_if_axuser_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_sbte0_mstr_if_axuser_regs.h
index 211fa2c2c35b..211fa2c2c35b 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_sbte0_mstr_if_axuser_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_sbte0_mstr_if_axuser_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_wb0_mstr_if_axuser_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_wb0_mstr_if_axuser_regs.h
index 374a01d2b8d5..374a01d2b8d5 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_mme_wb0_mstr_if_axuser_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_mme_wb0_mstr_if_axuser_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_rtr0_ctrl_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_rtr0_ctrl_regs.h
index 22f4d6c805c5..22f4d6c805c5 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_rtr0_ctrl_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_rtr0_ctrl_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_rtr0_mstr_if_rr_prvt_hbw_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_rtr0_mstr_if_rr_prvt_hbw_regs.h
index 3a7290b3a5c9..3a7290b3a5c9 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_rtr0_mstr_if_rr_prvt_hbw_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_rtr0_mstr_if_rr_prvt_hbw_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_rtr0_mstr_if_rr_prvt_lbw_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_rtr0_mstr_if_rr_prvt_lbw_regs.h
index 5b52b88fee0f..5b52b88fee0f 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_rtr0_mstr_if_rr_prvt_lbw_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_rtr0_mstr_if_rr_prvt_lbw_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_rtr0_mstr_if_rr_shrd_hbw_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_rtr0_mstr_if_rr_shrd_hbw_regs.h
index d9b3f5cd392b..d9b3f5cd392b 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_rtr0_mstr_if_rr_shrd_hbw_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_rtr0_mstr_if_rr_shrd_hbw_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_rtr0_mstr_if_rr_shrd_lbw_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_rtr0_mstr_if_rr_shrd_lbw_regs.h
index 1bba940d3031..1bba940d3031 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_rtr0_mstr_if_rr_shrd_lbw_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_rtr0_mstr_if_rr_shrd_lbw_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_sync_mngr_glbl_masks.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_sync_mngr_glbl_masks.h
index f21540501cdd..f21540501cdd 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_sync_mngr_glbl_masks.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_sync_mngr_glbl_masks.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_sync_mngr_glbl_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_sync_mngr_glbl_regs.h
index c3c4991e6660..c3c4991e6660 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_sync_mngr_glbl_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_sync_mngr_glbl_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_sync_mngr_mstr_if_axuser_masks.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_sync_mngr_mstr_if_axuser_masks.h
index 76b273a41255..76b273a41255 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_sync_mngr_mstr_if_axuser_masks.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_sync_mngr_mstr_if_axuser_masks.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_sync_mngr_mstr_if_axuser_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_sync_mngr_mstr_if_axuser_regs.h
index 0bddc734329f..0bddc734329f 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_sync_mngr_mstr_if_axuser_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_sync_mngr_mstr_if_axuser_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_sync_mngr_objs_masks.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_sync_mngr_objs_masks.h
index 3a5b27df0ab4..3a5b27df0ab4 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_sync_mngr_objs_masks.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_sync_mngr_objs_masks.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_sync_mngr_objs_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_sync_mngr_objs_regs.h
index 8f082a1c9b1b..8f082a1c9b1b 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_sync_mngr_objs_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_sync_mngr_objs_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_axuser_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_axuser_regs.h
index 2d4a22680a23..2d4a22680a23 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_axuser_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_axuser_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_kernel_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_kernel_regs.h
index cdab39debd2c..cdab39debd2c 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_kernel_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_kernel_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_kernel_tensor_0_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_kernel_tensor_0_regs.h
index 4ef1c1edc5f7..4ef1c1edc5f7 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_kernel_tensor_0_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_kernel_tensor_0_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_masks.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_masks.h
index cdecbd0f9d84..cdecbd0f9d84 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_masks.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_masks.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_qm_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_qm_regs.h
index 4cd9e26a150f..4cd9e26a150f 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_qm_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_qm_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_qm_sync_object_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_qm_sync_object_regs.h
index 8da278a3f3fe..8da278a3f3fe 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_qm_sync_object_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_qm_sync_object_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_qm_tensor_0_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_qm_tensor_0_regs.h
index 2e4ff06e4858..2e4ff06e4858 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_qm_tensor_0_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_qm_tensor_0_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_regs.h
index 4d48f0c6880b..4d48f0c6880b 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_special_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_special_regs.h
index 76ab8a1a7f31..76ab8a1a7f31 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_special_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_cfg_special_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_eml_busmon_0_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_eml_busmon_0_regs.h
index f07da4a24f06..f07da4a24f06 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_eml_busmon_0_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_eml_busmon_0_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_eml_etf_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_eml_etf_regs.h
index aee9cbc78c3d..aee9cbc78c3d 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_eml_etf_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_eml_etf_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_eml_funnel_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_eml_funnel_regs.h
index dee670b666ee..dee670b666ee 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_eml_funnel_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_eml_funnel_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_eml_spmu_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_eml_spmu_regs.h
index 580ae57476bd..580ae57476bd 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_eml_spmu_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_eml_spmu_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_eml_stm_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_eml_stm_regs.h
index 91686c563fe5..91686c563fe5 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_eml_stm_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_eml_stm_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_qm_arc_aux_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_qm_arc_aux_regs.h
index e007dabc5382..e007dabc5382 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_qm_arc_aux_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_qm_arc_aux_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_qm_axuser_nonsecured_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_qm_axuser_nonsecured_regs.h
index 149b85f5f045..149b85f5f045 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_qm_axuser_nonsecured_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_qm_axuser_nonsecured_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_qm_cgm_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_qm_cgm_regs.h
index d4aad1875ad6..d4aad1875ad6 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_qm_cgm_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_qm_cgm_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_qm_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_qm_regs.h
index cca8683cbca1..cca8683cbca1 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_qm_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_tpc0_qm_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_axuser_dec_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_axuser_dec_regs.h
index e68667cc795a..e68667cc795a 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_axuser_dec_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_axuser_dec_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_axuser_msix_abnrm_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_axuser_msix_abnrm_regs.h
index f7ffdcbd1a76..f7ffdcbd1a76 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_axuser_msix_abnrm_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_axuser_msix_abnrm_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_axuser_msix_l2c_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_axuser_msix_l2c_regs.h
index 4c1bb5306cba..4c1bb5306cba 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_axuser_msix_l2c_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_axuser_msix_l2c_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_axuser_msix_nrm_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_axuser_msix_nrm_regs.h
index e413905ffe25..e413905ffe25 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_axuser_msix_nrm_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_axuser_msix_nrm_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_axuser_msix_vcd_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_axuser_msix_vcd_regs.h
index bce75ac6e279..bce75ac6e279 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_axuser_msix_vcd_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_axuser_msix_vcd_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_masks.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_masks.h
index 68dd98459c86..1c02f3dfdb6e 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_masks.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_masks.h
@@ -106,8 +106,7 @@
#define DCORE0_VDEC0_BRDG_CTRL_HBW_AXI_VIOL_CAUSE_AWBURST_VIOL_SHIFT 2
#define DCORE0_VDEC0_BRDG_CTRL_HBW_AXI_VIOL_CAUSE_AWBURST_VIOL_MASK 0x4
#define DCORE0_VDEC0_BRDG_CTRL_HBW_AXI_VIOL_CAUSE_AWADDR_SIZE_ALIGN_VIOL_SHIFT 3
-#define DCORE0_VDEC0_BRDG_CTRL_HBW_AXI_VIOL_CAUSE_AWADDR_SIZE_ALIGN_VIOL_MASK \
-0x8
+#define DCORE0_VDEC0_BRDG_CTRL_HBW_AXI_VIOL_CAUSE_AWADDR_SIZE_ALIGN_VIOL_MASK 0x8
#define DCORE0_VDEC0_BRDG_CTRL_HBW_AXI_VIOL_CAUSE_AWSIZE_VIOL_SHIFT 4
#define DCORE0_VDEC0_BRDG_CTRL_HBW_AXI_VIOL_CAUSE_AWSIZE_VIOL_MASK 0x10
#define DCORE0_VDEC0_BRDG_CTRL_HBW_AXI_VIOL_CAUSE_ARLEN_GT_31_SHIFT 5
@@ -117,8 +116,7 @@
#define DCORE0_VDEC0_BRDG_CTRL_HBW_AXI_VIOL_CAUSE_ARBURST_VIOL_SHIFT 7
#define DCORE0_VDEC0_BRDG_CTRL_HBW_AXI_VIOL_CAUSE_ARBURST_VIOL_MASK 0x80
#define DCORE0_VDEC0_BRDG_CTRL_HBW_AXI_VIOL_CAUSE_ARADDR_SIZE_ALIGN_VIOL_SHIFT 8
-#define DCORE0_VDEC0_BRDG_CTRL_HBW_AXI_VIOL_CAUSE_ARADDR_SIZE_ALIGN_VIOL_MASK \
-0x100
+#define DCORE0_VDEC0_BRDG_CTRL_HBW_AXI_VIOL_CAUSE_ARADDR_SIZE_ALIGN_VIOL_MASK 0x100
#define DCORE0_VDEC0_BRDG_CTRL_HBW_AXI_VIOL_CAUSE_ARSIZE_VIOL_SHIFT 9
#define DCORE0_VDEC0_BRDG_CTRL_HBW_AXI_VIOL_CAUSE_ARSIZE_VIOL_MASK 0x200
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_regs.h
index d2844307a6bf..d2844307a6bf 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_brdg_ctrl_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_ctrl_special_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_ctrl_special_regs.h
index 89b522b12998..89b522b12998 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_ctrl_special_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore0_vdec0_ctrl_special_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore1_mme_ctrl_lo_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore1_mme_ctrl_lo_regs.h
index 622613dc76fb..622613dc76fb 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore1_mme_ctrl_lo_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore1_mme_ctrl_lo_regs.h
diff --git a/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore1_sync_mngr_glbl_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore1_sync_mngr_glbl_regs.h
new file mode 100644
index 000000000000..3d3802755814
--- /dev/null
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore1_sync_mngr_glbl_regs.h
@@ -0,0 +1,1203 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright 2016-2020 HabanaLabs, Ltd.
+ * All Rights Reserved.
+ *
+ */
+
+/************************************
+ ** This is an auto-generated file **
+ ** DO NOT EDIT BELOW **
+ ************************************/
+
+#ifndef ASIC_REG_DCORE1_SYNC_MNGR_GLBL_REGS_H_
+#define ASIC_REG_DCORE1_SYNC_MNGR_GLBL_REGS_H_
+
+/*
+ *****************************************
+ * DCORE1_SYNC_MNGR_GLBL
+ * (Prototype: SOB_GLBL)
+ *****************************************
+ */
+
+#define mmDCORE1_SYNC_MNGR_GLBL_SM_SEI_MASK 0x431E000
+
+#define mmDCORE1_SYNC_MNGR_GLBL_SM_SEI_CAUSE 0x431E004
+
+#define mmDCORE1_SYNC_MNGR_GLBL_L2H_CPMR_L 0x431E008
+
+#define mmDCORE1_SYNC_MNGR_GLBL_L2H_CPMR_H 0x431E00C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_L2H_MASK_L 0x431E020
+
+#define mmDCORE1_SYNC_MNGR_GLBL_L2H_MASK_H 0x431E024
+
+#define mmDCORE1_SYNC_MNGR_GLBL_ASID_SEC 0x431E030
+
+#define mmDCORE1_SYNC_MNGR_GLBL_ASID_PRIV_ONLY 0x431E034
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DELAY 0x431E038
+
+#define mmDCORE1_SYNC_MNGR_GLBL_PI_SIZE 0x431E03C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_SOB_ONLY 0x431E040
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INTR 0x431E044
+
+#define mmDCORE1_SYNC_MNGR_GLBL_ASID_NONE_SEC_PRIV 0x431E048
+
+#define mmDCORE1_SYNC_MNGR_GLBL_PI_INC_MODE_SIZE 0x431E04C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_0 0x431E050
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_1 0x431E054
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_2 0x431E058
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_3 0x431E05C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_4 0x431E060
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_5 0x431E064
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_6 0x431E068
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_7 0x431E06C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_8 0x431E070
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_9 0x431E074
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_10 0x431E078
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_11 0x431E07C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_12 0x431E080
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_13 0x431E084
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_14 0x431E088
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_15 0x431E08C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_16 0x431E090
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_17 0x431E094
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_18 0x431E098
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_19 0x431E09C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_20 0x431E0A0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_21 0x431E0A4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_22 0x431E0A8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_23 0x431E0AC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_24 0x431E0B0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_25 0x431E0B4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_26 0x431E0B8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_27 0x431E0BC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_28 0x431E0C0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_29 0x431E0C4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_30 0x431E0C8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_31 0x431E0CC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_32 0x431E0D0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_33 0x431E0D4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_34 0x431E0D8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_35 0x431E0DC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_36 0x431E0E0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_37 0x431E0E4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_38 0x431E0E8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_39 0x431E0EC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_40 0x431E0F0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_41 0x431E0F4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_42 0x431E0F8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_43 0x431E0FC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_44 0x431E100
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_45 0x431E104
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_46 0x431E108
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_47 0x431E10C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_48 0x431E110
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_49 0x431E114
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_50 0x431E118
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_51 0x431E11C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_52 0x431E120
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_53 0x431E124
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_54 0x431E128
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_55 0x431E12C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_56 0x431E130
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_57 0x431E134
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_58 0x431E138
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_59 0x431E13C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_60 0x431E140
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_61 0x431E144
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_62 0x431E148
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_L_63 0x431E14C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_0 0x431E150
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_1 0x431E154
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_2 0x431E158
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_3 0x431E15C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_4 0x431E160
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_5 0x431E164
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_6 0x431E168
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_7 0x431E16C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_8 0x431E170
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_9 0x431E174
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_10 0x431E178
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_11 0x431E17C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_12 0x431E180
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_13 0x431E184
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_14 0x431E188
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_15 0x431E18C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_16 0x431E190
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_17 0x431E194
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_18 0x431E198
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_19 0x431E19C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_20 0x431E1A0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_21 0x431E1A4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_22 0x431E1A8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_23 0x431E1AC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_24 0x431E1B0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_25 0x431E1B4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_26 0x431E1B8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_27 0x431E1BC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_28 0x431E1C0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_29 0x431E1C4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_30 0x431E1C8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_31 0x431E1CC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_32 0x431E1D0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_33 0x431E1D4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_34 0x431E1D8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_35 0x431E1DC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_36 0x431E1E0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_37 0x431E1E4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_38 0x431E1E8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_39 0x431E1EC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_40 0x431E1F0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_41 0x431E1F4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_42 0x431E1F8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_43 0x431E1FC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_44 0x431E200
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_45 0x431E204
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_46 0x431E208
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_47 0x431E20C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_48 0x431E210
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_49 0x431E214
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_50 0x431E218
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_51 0x431E21C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_52 0x431E220
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_53 0x431E224
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_54 0x431E228
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_55 0x431E22C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_56 0x431E230
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_57 0x431E234
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_58 0x431E238
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_59 0x431E23C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_60 0x431E240
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_61 0x431E244
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_62 0x431E248
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_BASE_ADDR_H_63 0x431E24C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_0 0x431E250
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_1 0x431E254
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_2 0x431E258
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_3 0x431E25C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_4 0x431E260
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_5 0x431E264
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_6 0x431E268
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_7 0x431E26C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_8 0x431E270
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_9 0x431E274
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_10 0x431E278
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_11 0x431E27C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_12 0x431E280
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_13 0x431E284
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_14 0x431E288
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_15 0x431E28C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_16 0x431E290
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_17 0x431E294
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_18 0x431E298
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_19 0x431E29C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_20 0x431E2A0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_21 0x431E2A4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_22 0x431E2A8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_23 0x431E2AC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_24 0x431E2B0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_25 0x431E2B4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_26 0x431E2B8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_27 0x431E2BC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_28 0x431E2C0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_29 0x431E2C4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_30 0x431E2C8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_31 0x431E2CC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_32 0x431E2D0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_33 0x431E2D4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_34 0x431E2D8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_35 0x431E2DC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_36 0x431E2E0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_37 0x431E2E4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_38 0x431E2E8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_39 0x431E2EC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_40 0x431E2F0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_41 0x431E2F4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_42 0x431E2F8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_43 0x431E2FC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_44 0x431E300
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_45 0x431E304
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_46 0x431E308
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_47 0x431E30C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_48 0x431E310
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_49 0x431E314
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_50 0x431E318
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_51 0x431E31C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_52 0x431E320
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_53 0x431E324
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_54 0x431E328
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_55 0x431E32C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_56 0x431E330
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_57 0x431E334
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_58 0x431E338
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_59 0x431E33C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_60 0x431E340
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_61 0x431E344
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_62 0x431E348
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SIZE_LOG2_63 0x431E34C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_0 0x431E350
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_1 0x431E354
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_2 0x431E358
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_3 0x431E35C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_4 0x431E360
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_5 0x431E364
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_6 0x431E368
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_7 0x431E36C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_8 0x431E370
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_9 0x431E374
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_10 0x431E378
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_11 0x431E37C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_12 0x431E380
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_13 0x431E384
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_14 0x431E388
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_15 0x431E38C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_16 0x431E390
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_17 0x431E394
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_18 0x431E398
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_19 0x431E39C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_20 0x431E3A0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_21 0x431E3A4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_22 0x431E3A8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_23 0x431E3AC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_24 0x431E3B0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_25 0x431E3B4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_26 0x431E3B8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_27 0x431E3BC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_28 0x431E3C0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_29 0x431E3C4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_30 0x431E3C8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_31 0x431E3CC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_32 0x431E3D0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_33 0x431E3D4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_34 0x431E3D8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_35 0x431E3DC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_36 0x431E3E0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_37 0x431E3E4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_38 0x431E3E8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_39 0x431E3EC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_40 0x431E3F0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_41 0x431E3F4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_42 0x431E3F8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_43 0x431E3FC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_44 0x431E400
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_45 0x431E404
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_46 0x431E408
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_47 0x431E40C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_48 0x431E410
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_49 0x431E414
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_50 0x431E418
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_51 0x431E41C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_52 0x431E420
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_53 0x431E424
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_54 0x431E428
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_55 0x431E42C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_56 0x431E430
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_57 0x431E434
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_58 0x431E438
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_59 0x431E43C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_60 0x431E440
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_61 0x431E444
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_62 0x431E448
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_PI_63 0x431E44C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_0 0x431E450
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_1 0x431E454
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_2 0x431E458
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_3 0x431E45C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_4 0x431E460
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_5 0x431E464
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_6 0x431E468
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_7 0x431E46C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_8 0x431E470
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_9 0x431E474
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_10 0x431E478
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_11 0x431E47C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_12 0x431E480
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_13 0x431E484
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_14 0x431E488
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_15 0x431E48C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_16 0x431E490
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_17 0x431E494
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_18 0x431E498
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_19 0x431E49C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_20 0x431E4A0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_21 0x431E4A4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_22 0x431E4A8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_23 0x431E4AC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_24 0x431E4B0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_25 0x431E4B4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_26 0x431E4B8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_27 0x431E4BC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_28 0x431E4C0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_29 0x431E4C4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_30 0x431E4C8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_31 0x431E4CC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_32 0x431E4D0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_33 0x431E4D4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_34 0x431E4D8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_35 0x431E4DC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_36 0x431E4E0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_37 0x431E4E4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_38 0x431E4E8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_39 0x431E4EC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_40 0x431E4F0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_41 0x431E4F4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_42 0x431E4F8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_43 0x431E4FC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_44 0x431E500
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_45 0x431E504
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_46 0x431E508
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_47 0x431E50C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_48 0x431E510
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_49 0x431E514
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_50 0x431E518
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_51 0x431E51C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_52 0x431E520
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_53 0x431E524
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_54 0x431E528
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_55 0x431E52C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_56 0x431E530
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_57 0x431E534
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_58 0x431E538
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_59 0x431E53C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_60 0x431E540
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_61 0x431E544
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_62 0x431E548
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_SEC_63 0x431E54C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_0 0x431E550
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_1 0x431E554
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_2 0x431E558
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_3 0x431E55C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_4 0x431E560
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_5 0x431E564
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_6 0x431E568
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_7 0x431E56C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_8 0x431E570
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_9 0x431E574
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_10 0x431E578
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_11 0x431E57C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_12 0x431E580
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_13 0x431E584
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_14 0x431E588
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_15 0x431E58C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_16 0x431E590
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_17 0x431E594
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_18 0x431E598
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_19 0x431E59C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_20 0x431E5A0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_21 0x431E5A4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_22 0x431E5A8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_23 0x431E5AC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_24 0x431E5B0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_25 0x431E5B4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_26 0x431E5B8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_27 0x431E5BC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_28 0x431E5C0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_29 0x431E5C4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_30 0x431E5C8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_31 0x431E5CC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_32 0x431E5D0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_33 0x431E5D4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_34 0x431E5D8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_35 0x431E5DC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_36 0x431E5E0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_37 0x431E5E4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_38 0x431E5E8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_39 0x431E5EC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_40 0x431E5F0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_41 0x431E5F4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_42 0x431E5F8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_43 0x431E5FC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_44 0x431E600
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_45 0x431E604
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_46 0x431E608
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_47 0x431E60C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_48 0x431E610
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_49 0x431E614
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_50 0x431E618
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_51 0x431E61C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_52 0x431E620
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_53 0x431E624
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_54 0x431E628
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_55 0x431E62C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_56 0x431E630
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_57 0x431E634
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_58 0x431E638
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_59 0x431E63C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_60 0x431E640
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_61 0x431E644
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_62 0x431E648
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_L_63 0x431E64C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_0 0x431E650
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_1 0x431E654
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_2 0x431E658
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_3 0x431E65C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_4 0x431E660
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_5 0x431E664
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_6 0x431E668
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_7 0x431E66C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_8 0x431E670
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_9 0x431E674
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_10 0x431E678
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_11 0x431E67C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_12 0x431E680
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_13 0x431E684
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_14 0x431E688
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_15 0x431E68C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_16 0x431E690
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_17 0x431E694
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_18 0x431E698
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_19 0x431E69C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_20 0x431E6A0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_21 0x431E6A4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_22 0x431E6A8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_23 0x431E6AC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_24 0x431E6B0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_25 0x431E6B4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_26 0x431E6B8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_27 0x431E6BC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_28 0x431E6C0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_29 0x431E6C4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_30 0x431E6C8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_31 0x431E6CC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_32 0x431E6D0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_33 0x431E6D4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_34 0x431E6D8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_35 0x431E6DC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_36 0x431E6E0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_37 0x431E6E4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_38 0x431E6E8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_39 0x431E6EC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_40 0x431E6F0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_41 0x431E6F4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_42 0x431E6F8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_43 0x431E6FC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_44 0x431E700
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_45 0x431E704
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_46 0x431E708
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_47 0x431E70C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_48 0x431E710
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_49 0x431E714
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_50 0x431E718
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_51 0x431E71C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_52 0x431E720
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_53 0x431E724
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_54 0x431E728
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_55 0x431E72C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_56 0x431E730
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_57 0x431E734
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_58 0x431E738
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_59 0x431E73C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_60 0x431E740
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_61 0x431E744
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_62 0x431E748
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_ADDR_H_63 0x431E74C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_0 0x431E750
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_1 0x431E754
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_2 0x431E758
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_3 0x431E75C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_4 0x431E760
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_5 0x431E764
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_6 0x431E768
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_7 0x431E76C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_8 0x431E770
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_9 0x431E774
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_10 0x431E778
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_11 0x431E77C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_12 0x431E780
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_13 0x431E784
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_14 0x431E788
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_15 0x431E78C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_16 0x431E790
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_17 0x431E794
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_18 0x431E798
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_19 0x431E79C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_20 0x431E7A0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_21 0x431E7A4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_22 0x431E7A8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_23 0x431E7AC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_24 0x431E7B0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_25 0x431E7B4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_26 0x431E7B8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_27 0x431E7BC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_28 0x431E7C0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_29 0x431E7C4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_30 0x431E7C8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_31 0x431E7CC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_32 0x431E7D0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_33 0x431E7D4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_34 0x431E7D8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_35 0x431E7DC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_36 0x431E7E0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_37 0x431E7E4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_38 0x431E7E8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_39 0x431E7EC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_40 0x431E7F0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_41 0x431E7F4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_42 0x431E7F8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_43 0x431E7FC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_44 0x431E800
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_45 0x431E804
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_46 0x431E808
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_47 0x431E80C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_48 0x431E810
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_49 0x431E814
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_50 0x431E818
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_51 0x431E81C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_52 0x431E820
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_53 0x431E824
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_54 0x431E828
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_55 0x431E82C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_56 0x431E830
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_57 0x431E834
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_58 0x431E838
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_59 0x431E83C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_60 0x431E840
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_61 0x431E844
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_62 0x431E848
+
+#define mmDCORE1_SYNC_MNGR_GLBL_LBW_DATA_63 0x431E84C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_0 0x431E850
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_1 0x431E854
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_2 0x431E858
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_3 0x431E85C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_4 0x431E860
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_5 0x431E864
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_6 0x431E868
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_7 0x431E86C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_8 0x431E870
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_9 0x431E874
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_10 0x431E878
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_11 0x431E87C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_12 0x431E880
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_13 0x431E884
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_14 0x431E888
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_15 0x431E88C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_16 0x431E890
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_17 0x431E894
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_18 0x431E898
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_19 0x431E89C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_20 0x431E8A0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_21 0x431E8A4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_22 0x431E8A8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_23 0x431E8AC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_24 0x431E8B0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_25 0x431E8B4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_26 0x431E8B8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_27 0x431E8BC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_28 0x431E8C0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_29 0x431E8C4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_30 0x431E8C8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_31 0x431E8CC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_32 0x431E8D0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_33 0x431E8D4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_34 0x431E8D8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_35 0x431E8DC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_36 0x431E8E0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_37 0x431E8E4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_38 0x431E8E8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_39 0x431E8EC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_40 0x431E8F0
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_41 0x431E8F4
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_42 0x431E8F8
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_43 0x431E8FC
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_44 0x431E900
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_45 0x431E904
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_46 0x431E908
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_47 0x431E90C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_48 0x431E910
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_49 0x431E914
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_50 0x431E918
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_51 0x431E91C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_52 0x431E920
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_53 0x431E924
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_54 0x431E928
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_55 0x431E92C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_56 0x431E930
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_57 0x431E934
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_58 0x431E938
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_59 0x431E93C
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_60 0x431E940
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_61 0x431E944
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_62 0x431E948
+
+#define mmDCORE1_SYNC_MNGR_GLBL_CQ_INC_MODE_63 0x431E94C
+
+#endif /* ASIC_REG_DCORE1_SYNC_MNGR_GLBL_REGS_H_ */
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore3_mme_ctrl_lo_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore3_mme_ctrl_lo_regs.h
index b06469f5a279..b06469f5a279 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/dcore3_mme_ctrl_lo_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/dcore3_mme_ctrl_lo_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/gaudi2_blocks_linux_driver.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/gaudi2_blocks_linux_driver.h
index 3caee4515ad6..3caee4515ad6 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/gaudi2_blocks_linux_driver.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/gaudi2_blocks_linux_driver.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/gaudi2_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/gaudi2_regs.h
index 6aa1b1412462..0bf3092bfeea 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/gaudi2_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/gaudi2_regs.h
@@ -31,6 +31,7 @@
#include "dcore0_sync_mngr_objs_regs.h"
#include "dcore0_sync_mngr_glbl_regs.h"
#include "dcore0_sync_mngr_mstr_if_axuser_regs.h"
+#include "dcore1_sync_mngr_glbl_regs.h"
#include "pdma0_qm_arc_aux_regs.h"
#include "pdma0_core_ctx_regs.h"
#include "pdma0_core_regs.h"
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/nic0_qm0_cgm_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/nic0_qm0_cgm_regs.h
index d49906a68511..d49906a68511 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/nic0_qm0_cgm_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/nic0_qm0_cgm_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/nic0_qm0_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/nic0_qm0_regs.h
index acb19c1cd4bd..acb19c1cd4bd 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/nic0_qm0_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/nic0_qm0_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/nic0_qm_arc_aux0_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/nic0_qm_arc_aux0_regs.h
index 5f380a44dd21..5f380a44dd21 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/nic0_qm_arc_aux0_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/nic0_qm_arc_aux0_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/nic0_qpc0_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/nic0_qpc0_regs.h
index eaee29da4244..eaee29da4244 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/nic0_qpc0_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/nic0_qpc0_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/nic0_umr0_0_completion_queue_ci_1_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/nic0_umr0_0_completion_queue_ci_1_regs.h
index 2153319a50a0..2153319a50a0 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/nic0_umr0_0_completion_queue_ci_1_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/nic0_umr0_0_completion_queue_ci_1_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/nic0_umr0_0_unsecure_doorbell0_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/nic0_umr0_0_unsecure_doorbell0_regs.h
index de8eac74c2fb..de8eac74c2fb 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/nic0_umr0_0_unsecure_doorbell0_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/nic0_umr0_0_unsecure_doorbell0_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_aux_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_aux_regs.h
index 44182fc18234..44182fc18234 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_aux_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_aux_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_dbi_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_dbi_regs.h
index cc5842ec6ceb..2ee79d8e62d0 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_dbi_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_dbi_regs.h
@@ -48,8 +48,7 @@
#define mmPCIE_DBI_PCI_CAP_PTR_REG 0x4C02034
-#define mmPCIE_DBI_MAX_LATENCY_MIN_GRANT_INTERRUPT_PIN_INTERRUPT_LINE_REG \
-0x4C0203C
+#define mmPCIE_DBI_MAX_LATENCY_MIN_GRANT_INTERRUPT_PIN_INTERRUPT_LINE_REG 0x4C0203C
#define mmPCIE_DBI_CAP_ID_NXT_PTR_REG 0x4C02040
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_dec0_cmd_masks.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_dec0_cmd_masks.h
index 2b5af010c7a5..2b5af010c7a5 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_dec0_cmd_masks.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_dec0_cmd_masks.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_dec0_cmd_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_dec0_cmd_regs.h
index dc7d3f6a4b50..dc7d3f6a4b50 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_dec0_cmd_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_dec0_cmd_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_axuser_dec_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_axuser_dec_regs.h
index 242c6525bd71..242c6525bd71 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_axuser_dec_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_axuser_dec_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_axuser_msix_abnrm_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_axuser_msix_abnrm_regs.h
index 98d035463561..98d035463561 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_axuser_msix_abnrm_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_axuser_msix_abnrm_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_axuser_msix_l2c_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_axuser_msix_l2c_regs.h
index 33ef37619417..33ef37619417 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_axuser_msix_l2c_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_axuser_msix_l2c_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_axuser_msix_nrm_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_axuser_msix_nrm_regs.h
index c4587d5d6406..c4587d5d6406 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_axuser_msix_nrm_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_axuser_msix_nrm_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_axuser_msix_vcd_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_axuser_msix_vcd_regs.h
index 35349ad375d0..35349ad375d0 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_axuser_msix_vcd_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_axuser_msix_vcd_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_masks.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_masks.h
index d29837883216..7a96aebf08b3 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_masks.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_masks.h
@@ -116,8 +116,7 @@
#define PCIE_VDEC0_BRDG_CTRL_HBW_AXI_VIOL_CAUSE_ARBURST_VIOL_SHIFT 7
#define PCIE_VDEC0_BRDG_CTRL_HBW_AXI_VIOL_CAUSE_ARBURST_VIOL_MASK 0x80
#define PCIE_VDEC0_BRDG_CTRL_HBW_AXI_VIOL_CAUSE_ARADDR_SIZE_ALIGN_VIOL_SHIFT 8
-#define PCIE_VDEC0_BRDG_CTRL_HBW_AXI_VIOL_CAUSE_ARADDR_SIZE_ALIGN_VIOL_MASK \
-0x100
+#define PCIE_VDEC0_BRDG_CTRL_HBW_AXI_VIOL_CAUSE_ARADDR_SIZE_ALIGN_VIOL_MASK 0x100
#define PCIE_VDEC0_BRDG_CTRL_HBW_AXI_VIOL_CAUSE_ARSIZE_VIOL_SHIFT 9
#define PCIE_VDEC0_BRDG_CTRL_HBW_AXI_VIOL_CAUSE_ARSIZE_VIOL_MASK 0x200
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_regs.h
index c7badd212f2b..c7badd212f2b 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_brdg_ctrl_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_ctrl_special_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_ctrl_special_regs.h
index 491b0cd935af..491b0cd935af 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_ctrl_special_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_vdec0_ctrl_special_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_wrap_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_wrap_regs.h
index a09422f2f281..a09422f2f281 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_wrap_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_wrap_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_wrap_special_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_wrap_special_regs.h
index 46558e7a7f63..46558e7a7f63 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pcie_wrap_special_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pcie_wrap_special_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma0_core_ctx_axuser_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma0_core_ctx_axuser_regs.h
index bacbe4c6fc3c..bacbe4c6fc3c 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma0_core_ctx_axuser_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma0_core_ctx_axuser_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma0_core_ctx_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma0_core_ctx_regs.h
index 02b57f07cfaf..02b57f07cfaf 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma0_core_ctx_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma0_core_ctx_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma0_core_masks.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma0_core_masks.h
index 909cda03c246..909cda03c246 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma0_core_masks.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma0_core_masks.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma0_core_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma0_core_regs.h
index 84079b5077e2..84079b5077e2 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma0_core_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma0_core_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma0_core_special_masks.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma0_core_special_masks.h
index 15d257e3830e..15d257e3830e 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma0_core_special_masks.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma0_core_special_masks.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma0_qm_arc_aux_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma0_qm_arc_aux_regs.h
index 9b1cb609d134..9b1cb609d134 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma0_qm_arc_aux_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma0_qm_arc_aux_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma0_qm_axuser_nonsecured_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma0_qm_axuser_nonsecured_regs.h
index d2e0756ec5f2..d2e0756ec5f2 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma0_qm_axuser_nonsecured_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma0_qm_axuser_nonsecured_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma0_qm_axuser_secured_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma0_qm_axuser_secured_regs.h
index 8bf0516b83f7..8bf0516b83f7 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma0_qm_axuser_secured_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma0_qm_axuser_secured_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma0_qm_cgm_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma0_qm_cgm_regs.h
index 96c0ce176e73..96c0ce176e73 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma0_qm_cgm_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma0_qm_cgm_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma0_qm_masks.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma0_qm_masks.h
index b79cae8f5571..b79cae8f5571 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma0_qm_masks.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma0_qm_masks.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma0_qm_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma0_qm_regs.h
index 77d803c938d4..77d803c938d4 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma0_qm_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma0_qm_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma1_core_ctx_axuser_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma1_core_ctx_axuser_regs.h
index ccc6dfd22dd7..ccc6dfd22dd7 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma1_core_ctx_axuser_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma1_core_ctx_axuser_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma1_qm_axuser_nonsecured_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma1_qm_axuser_nonsecured_regs.h
index 5fd72d050fff..5fd72d050fff 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pdma1_qm_axuser_nonsecured_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pdma1_qm_axuser_nonsecured_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pmmu_hbw_stlb_masks.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pmmu_hbw_stlb_masks.h
index 0276506ea523..b4f32632cd36 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pmmu_hbw_stlb_masks.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pmmu_hbw_stlb_masks.h
@@ -228,8 +228,7 @@
/* PMMU_HBW_STLB_RANGE_CACHE_INVALIDATION */
#define PMMU_HBW_STLB_RANGE_CACHE_INVALIDATION_RANGE_INVALIDATION_ENABLE_SHIFT 0
-#define PMMU_HBW_STLB_RANGE_CACHE_INVALIDATION_RANGE_INVALIDATION_ENABLE_MASK \
-0x1
+#define PMMU_HBW_STLB_RANGE_CACHE_INVALIDATION_RANGE_INVALIDATION_ENABLE_MASK 0x1
#define PMMU_HBW_STLB_RANGE_CACHE_INVALIDATION_INVALIDATION_ASID_EN_SHIFT 1
#define PMMU_HBW_STLB_RANGE_CACHE_INVALIDATION_INVALIDATION_ASID_EN_MASK 0x2
#define PMMU_HBW_STLB_RANGE_CACHE_INVALIDATION_INVALIDATION_ASID_SHIFT 2
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pmmu_hbw_stlb_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pmmu_hbw_stlb_regs.h
index 87c66c08e24a..87c66c08e24a 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pmmu_hbw_stlb_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pmmu_hbw_stlb_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pmmu_pif_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pmmu_pif_regs.h
index dd12793734b4..dd12793734b4 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/pmmu_pif_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/pmmu_pif_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/psoc_etr_masks.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/psoc_etr_masks.h
index 42e67c1059c4..42e67c1059c4 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/psoc_etr_masks.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/psoc_etr_masks.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/psoc_etr_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/psoc_etr_regs.h
index 980a3e0054c5..980a3e0054c5 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/psoc_etr_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/psoc_etr_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/psoc_global_conf_masks.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/psoc_global_conf_masks.h
index 9be3d656da3a..85a81e2cb546 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/psoc_global_conf_masks.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/psoc_global_conf_masks.h
@@ -1306,11 +1306,9 @@
#define PSOC_GLOBAL_CONF_AXI_DRAIN_NL_SRC_CTRL0_ADDR_EXTMEM_PC_LOC2_SHIFT 12
#define PSOC_GLOBAL_CONF_AXI_DRAIN_NL_SRC_CTRL0_ADDR_EXTMEM_PC_LOC2_MASK 0x3F000
#define PSOC_GLOBAL_CONF_AXI_DRAIN_NL_SRC_CTRL0_ADDR_EXTMEM_PC_LOC3_SHIFT 18
-#define PSOC_GLOBAL_CONF_AXI_DRAIN_NL_SRC_CTRL0_ADDR_EXTMEM_PC_LOC3_MASK \
-0xFC0000
+#define PSOC_GLOBAL_CONF_AXI_DRAIN_NL_SRC_CTRL0_ADDR_EXTMEM_PC_LOC3_MASK 0xFC0000
#define PSOC_GLOBAL_CONF_AXI_DRAIN_NL_SRC_CTRL0_ADDR_EXTMEM_HBM_LOC0_SHIFT 24
-#define PSOC_GLOBAL_CONF_AXI_DRAIN_NL_SRC_CTRL0_ADDR_EXTMEM_HBM_LOC0_MASK \
-0x3F000000
+#define PSOC_GLOBAL_CONF_AXI_DRAIN_NL_SRC_CTRL0_ADDR_EXTMEM_HBM_LOC0_MASK 0x3F000000
/* PSOC_GLOBAL_CONF_AXI_DRAIN_NL_SRC_CTRL1 */
#define PSOC_GLOBAL_CONF_AXI_DRAIN_NL_SRC_CTRL1_ADDR_EXTMEM_HBM_LOC1_SHIFT 0
@@ -1322,24 +1320,17 @@
#define PSOC_GLOBAL_CONF_AXI_DRAIN_NL_SRC_CTRL1_NON_LIN_HBM_CNT_EN_SHIFT 13
#define PSOC_GLOBAL_CONF_AXI_DRAIN_NL_SRC_CTRL1_NON_LIN_HBM_CNT_EN_MASK 0x2000
#define PSOC_GLOBAL_CONF_AXI_DRAIN_NL_SRC_CTRL1_NON_LIN_HBM_ALL_ADDR_EN_SHIFT 14
-#define PSOC_GLOBAL_CONF_AXI_DRAIN_NL_SRC_CTRL1_NON_LIN_HBM_ALL_ADDR_EN_MASK \
-0x4000
-#define PSOC_GLOBAL_CONF_AXI_DRAIN_NL_SRC_CTRL1_NON_LIN_HBM_ALL_ADDR_MASK_SHIFT \
-16
-#define PSOC_GLOBAL_CONF_AXI_DRAIN_NL_SRC_CTRL1_NON_LIN_HBM_ALL_ADDR_MASK_MASK \
-0xFF0000
+#define PSOC_GLOBAL_CONF_AXI_DRAIN_NL_SRC_CTRL1_NON_LIN_HBM_ALL_ADDR_EN_MASK 0x4000
+#define PSOC_GLOBAL_CONF_AXI_DRAIN_NL_SRC_CTRL1_NON_LIN_HBM_ALL_ADDR_MASK_SHIFT 16
+#define PSOC_GLOBAL_CONF_AXI_DRAIN_NL_SRC_CTRL1_NON_LIN_HBM_ALL_ADDR_MASK_MASK 0xFF0000
#define PSOC_GLOBAL_CONF_AXI_DRAIN_NL_SRC_CTRL1_HBM_NUM_SHIFT 24
#define PSOC_GLOBAL_CONF_AXI_DRAIN_NL_SRC_CTRL1_HBM_NUM_MASK 0x7000000
/* PSOC_GLOBAL_CONF_AXI_DRAIN_NL_SRC_CTRL2 */
-#define PSOC_GLOBAL_CONF_AXI_DRAIN_NL_SRC_CTRL2_SCRAM_NONLIN_HBM_CNT_MASK_SHIFT \
-0
-#define PSOC_GLOBAL_CONF_AXI_DRAIN_NL_SRC_CTRL2_SCRAM_NONLIN_HBM_CNT_MASK_MASK \
-0xFFFF
-#define PSOC_GLOBAL_CONF_AXI_DRAIN_NL_SRC_CTRL2_SCRAM_NONLIN_EXTM_PC_MASK_SHIFT \
-16
-#define PSOC_GLOBAL_CONF_AXI_DRAIN_NL_SRC_CTRL2_SCRAM_NONLIN_EXTM_PC_MASK_MASK \
-0xFFFF0000
+#define PSOC_GLOBAL_CONF_AXI_DRAIN_NL_SRC_CTRL2_SCRAM_NONLIN_HBM_CNT_MASK_SHIFT 0
+#define PSOC_GLOBAL_CONF_AXI_DRAIN_NL_SRC_CTRL2_SCRAM_NONLIN_HBM_CNT_MASK_MASK 0xFFFF
+#define PSOC_GLOBAL_CONF_AXI_DRAIN_NL_SRC_CTRL2_SCRAM_NONLIN_EXTM_PC_MASK_SHIFT 16
+#define PSOC_GLOBAL_CONF_AXI_DRAIN_NL_SRC_CTRL2_SCRAM_NONLIN_EXTM_PC_MASK_MASK 0xFFFF0000
/* PSOC_GLOBAL_CONF_AXI_DRAIN_NL_SRC_CTRL3 */
#define PSOC_GLOBAL_CONF_AXI_DRAIN_NL_SRC_CTRL3_HBM_MAP0_SHIFT 0
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/psoc_global_conf_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/psoc_global_conf_regs.h
index 48980fa8e37b..48980fa8e37b 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/psoc_global_conf_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/psoc_global_conf_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/psoc_reset_conf_masks.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/psoc_reset_conf_masks.h
index e0cf35226e7f..e0cf35226e7f 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/psoc_reset_conf_masks.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/psoc_reset_conf_masks.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/psoc_reset_conf_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/psoc_reset_conf_regs.h
index 6a89624f01d1..6a89624f01d1 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/psoc_reset_conf_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/psoc_reset_conf_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/psoc_timestamp_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/psoc_timestamp_regs.h
index 699becc28887..699becc28887 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/psoc_timestamp_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/psoc_timestamp_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/rot0_desc_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/rot0_desc_regs.h
index 79320320ebcb..79320320ebcb 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/rot0_desc_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/rot0_desc_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/rot0_masks.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/rot0_masks.h
index f2e739ede3d9..f2e739ede3d9 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/rot0_masks.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/rot0_masks.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/rot0_qm_arc_aux_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/rot0_qm_arc_aux_regs.h
index e83daa33d737..e83daa33d737 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/rot0_qm_arc_aux_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/rot0_qm_arc_aux_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/rot0_qm_axuser_nonsecured_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/rot0_qm_axuser_nonsecured_regs.h
index 8e040a2ef1c1..8e040a2ef1c1 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/rot0_qm_axuser_nonsecured_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/rot0_qm_axuser_nonsecured_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/rot0_qm_cgm_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/rot0_qm_cgm_regs.h
index 077ae2347a3d..077ae2347a3d 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/rot0_qm_cgm_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/rot0_qm_cgm_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/rot0_qm_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/rot0_qm_regs.h
index de3c85510af2..de3c85510af2 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/rot0_qm_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/rot0_qm_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/rot0_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/rot0_regs.h
index 7d85dc5559da..7d85dc5559da 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/rot0_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/rot0_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/xbar_edge_0_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/xbar_edge_0_regs.h
index e8aebd7f5f85..e8aebd7f5f85 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/xbar_edge_0_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/xbar_edge_0_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/asic_reg/xbar_mid_0_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/xbar_mid_0_regs.h
index 3d39d1a94851..3d39d1a94851 100644
--- a/drivers/misc/habanalabs/include/gaudi2/asic_reg/xbar_mid_0_regs.h
+++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/xbar_mid_0_regs.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/gaudi2.h b/drivers/accel/habanalabs/include/gaudi2/gaudi2.h
index 5b4f9e108798..5b4f9e108798 100644
--- a/drivers/misc/habanalabs/include/gaudi2/gaudi2.h
+++ b/drivers/accel/habanalabs/include/gaudi2/gaudi2.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/gaudi2_async_events.h b/drivers/accel/habanalabs/include/gaudi2/gaudi2_async_events.h
index 305b576222e6..50852cc80373 100644
--- a/drivers/misc/habanalabs/include/gaudi2/gaudi2_async_events.h
+++ b/drivers/accel/habanalabs/include/gaudi2/gaudi2_async_events.h
@@ -958,6 +958,7 @@ enum gaudi2_async_event_id {
GAUDI2_EVENT_CPU11_STATUS_NIC11_ENG1 = 1318,
GAUDI2_EVENT_ARC_DCCM_FULL = 1319,
GAUDI2_EVENT_CPU_FP32_NOT_SUPPORTED = 1320,
+ GAUDI2_EVENT_DEV_RESET_REQ = 1321,
GAUDI2_EVENT_SIZE,
};
diff --git a/drivers/misc/habanalabs/include/gaudi2/gaudi2_async_ids_map_extended.h b/drivers/accel/habanalabs/include/gaudi2/gaudi2_async_ids_map_extended.h
index d510cb10c883..82be01bea98e 100644
--- a/drivers/misc/habanalabs/include/gaudi2/gaudi2_async_ids_map_extended.h
+++ b/drivers/accel/habanalabs/include/gaudi2/gaudi2_async_ids_map_extended.h
@@ -2665,6 +2665,8 @@ static struct gaudi2_async_events_ids_map gaudi2_irq_map_table[] = {
.msg = 1, .reset = 0, .name = "ARC_DCCM_FULL" },
{ .fc_id = 1320, .cpu_id = 626, .valid = 1,
.msg = 1, .reset = 1, .name = "FP32_NOT_SUPPORTED" },
+ { .fc_id = 1321, .cpu_id = 627, .valid = 1,
+ .msg = 1, .reset = 1, .name = "DEV_RESET_REQ" },
};
#endif /* __GAUDI2_ASYNC_IDS_MAP_EVENTS_EXT_H_ */
diff --git a/drivers/misc/habanalabs/include/gaudi2/gaudi2_coresight.h b/drivers/accel/habanalabs/include/gaudi2/gaudi2_coresight.h
index 14f09d7758c7..14f09d7758c7 100644
--- a/drivers/misc/habanalabs/include/gaudi2/gaudi2_coresight.h
+++ b/drivers/accel/habanalabs/include/gaudi2/gaudi2_coresight.h
diff --git a/drivers/misc/habanalabs/include/gaudi2/gaudi2_fw_if.h b/drivers/accel/habanalabs/include/gaudi2/gaudi2_fw_if.h
index e4a7d5725096..82f3ca2a3966 100644
--- a/drivers/misc/habanalabs/include/gaudi2/gaudi2_fw_if.h
+++ b/drivers/accel/habanalabs/include/gaudi2/gaudi2_fw_if.h
@@ -20,22 +20,25 @@
#define GAUDI2_NUM_MME 4
+#define NUM_OF_GPIOS_PER_PORT 16
+#define GAUDI2_WD_GPIO (62 % NUM_OF_GPIOS_PER_PORT)
+
#define GAUDI2_ARCPID_TX_MB_SIZE 0x1000
#define GAUDI2_ARCPID_RX_MB_SIZE 0x400
#define GAUDI2_ARM_TX_MB_SIZE 0x400
#define GAUDI2_ARM_RX_MB_SIZE 0x1800
#define GAUDI2_DCCM_BASE_ADDR 0x27020000
-#define GAUDI2_ARCPID_TX_MB_ADDR GAUDI2_DCCM_BASE_ADDR
-
-#define GAUDI2_ARCPID_RX_MB_ADDR (GAUDI2_ARCPID_TX_MB_ADDR + \
- GAUDI2_ARCPID_TX_MB_SIZE)
#define GAUDI2_ARM_TX_MB_ADDR GAUDI2_MAILBOX_BASE_ADDR
#define GAUDI2_ARM_RX_MB_ADDR (GAUDI2_ARM_TX_MB_ADDR + \
GAUDI2_ARM_TX_MB_SIZE)
+#define GAUDI2_ARCPID_TX_MB_ADDR (GAUDI2_ARM_RX_MB_ADDR + GAUDI2_ARM_RX_MB_SIZE)
+
+#define GAUDI2_ARCPID_RX_MB_ADDR (GAUDI2_ARCPID_TX_MB_ADDR + GAUDI2_ARCPID_TX_MB_SIZE)
+
#define GAUDI2_ARM_TX_MB_OFFSET (GAUDI2_ARM_TX_MB_ADDR - \
GAUDI2_SP_SRAM_BASE_ADDR)
@@ -58,7 +61,9 @@ struct gaudi2_cold_rst_data {
u32 spsram_init_done : 1;
u32 fake_security_enable : 1;
u32 fake_sig_validation_en : 1;
- u32 reserved : 26;
+ u32 bist_skip_enable : 1;
+ u32 bist_need_iatu_config : 1;
+ u32 reserved : 24;
};
__le32 data;
};
@@ -77,10 +82,10 @@ enum gaudi2_rst_src {
};
struct gaudi2_redundancy_ctx {
- int redundant_hbm;
- int redundant_edma;
- int redundant_tpc;
- int redundant_vdec;
+ __le32 redundant_hbm;
+ __le32 redundant_edma;
+ __le32 redundant_tpc;
+ __le32 redundant_vdec;
__le64 hbm_mask;
__le64 edma_mask;
__le64 tpc_mask;
diff --git a/drivers/misc/habanalabs/include/gaudi2/gaudi2_packets.h b/drivers/accel/habanalabs/include/gaudi2/gaudi2_packets.h
index 8bf90fc18bf5..a812f8503f90 100644
--- a/drivers/misc/habanalabs/include/gaudi2/gaudi2_packets.h
+++ b/drivers/accel/habanalabs/include/gaudi2/gaudi2_packets.h
@@ -59,7 +59,7 @@ struct gaudi2_packet {
/* The rest of the packet data follows. Use the corresponding
* packet_XXX struct to deference the data, based on packet type
*/
- u8 contents[0];
+ u8 contents[];
};
struct packet_nop {
@@ -80,7 +80,7 @@ struct packet_wreg32 {
struct packet_wreg_bulk {
__le32 size64;
__le32 ctl;
- __le64 values[0]; /* data starts here */
+ __le64 values[]; /* data starts here */
};
struct packet_msg_long {
diff --git a/drivers/misc/habanalabs/include/gaudi2/gaudi2_reg_map.h b/drivers/accel/habanalabs/include/gaudi2/gaudi2_reg_map.h
index ae7feb388f63..f3eaeb6d9b7e 100644
--- a/drivers/misc/habanalabs/include/gaudi2/gaudi2_reg_map.h
+++ b/drivers/accel/habanalabs/include/gaudi2/gaudi2_reg_map.h
@@ -24,14 +24,14 @@
#define mmGIC_HOST_HALT_IRQ_POLL_REG mmPSOC_GLOBAL_CONF_SCRATCHPAD_10
#define mmGIC_HOST_INTS_IRQ_POLL_REG mmPSOC_GLOBAL_CONF_SCRATCHPAD_11
#define mmGIC_HOST_SOFT_RST_IRQ_POLL_REG mmPSOC_GLOBAL_CONF_SCRATCHPAD_12
-#define mmEEPROM_COPY_LOCATION_REG mmPSOC_GLOBAL_CONF_SCRATCHPAD_13
#define mmCPU_RST_STATUS_TO_HOST mmPSOC_GLOBAL_CONF_SCRATCHPAD_14
-#define mmENGINE_ARC_IRQ_CTRL_POLL_REG mmPSOC_GLOBAL_CONF_SCRATCHPAD_15
-#define mmPID_CFG_REG mmPSOC_GLOBAL_CONF_SCRATCHPAD_18
/*
- * TODO: mmGIC_RAZWI_STATUS_REG is temporary
- * macro and to be removed after GAUDI2 PO
+ * Single scratchpad register used for all ARCs to notify dccm queue full event to FW.
+ * So a new event would overwrite any unhandled previous event. In other words, incase
+ * of multiple events before previous ones are handled, last one would be considered.
*/
+#define mmENGINE_ARC_IRQ_CTRL_POLL_REG mmPSOC_GLOBAL_CONF_SCRATCHPAD_15
+#define mmPID_CFG_REG mmPSOC_GLOBAL_CONF_SCRATCHPAD_18
#define mmGIC_RAZWI_STATUS_REG mmPSOC_GLOBAL_CONF_SCRATCHPAD_19
#define mmCPU_BOOT_DEV_STS0 mmPSOC_GLOBAL_CONF_SCRATCHPAD_20
#define mmCPU_BOOT_DEV_STS1 mmPSOC_GLOBAL_CONF_SCRATCHPAD_21
@@ -40,11 +40,10 @@
#define mmCPU_BOOT_ERR1 mmPSOC_GLOBAL_CONF_SCRATCHPAD_25
#define mmUPD_STS mmPSOC_GLOBAL_CONF_SCRATCHPAD_26
#define mmUPD_CMD mmPSOC_GLOBAL_CONF_SCRATCHPAD_27
-#define mmUBOOT_VER_OFFSET mmPSOC_GLOBAL_CONF_SCRATCHPAD_29
+#define mmPPBOOT_VER_OFFSET mmPSOC_GLOBAL_CONF_SCRATCHPAD_28
#define mmRDWR_TEST mmPSOC_GLOBAL_CONF_SCRATCHPAD_30
#define mmBTL_ID mmPSOC_GLOBAL_CONF_SCRATCHPAD_31
#define mmRST_SRC mmPSOC_GLOBAL_CONF_COLD_RST_FLOPS_0
-#define mmPREBOOT_PCIE_EN mmPSOC_GLOBAL_CONF_COLD_RST_FLOPS_1
#define mmCOLD_RST_DATA mmPSOC_GLOBAL_CONF_COLD_RST_FLOPS_2
#define mmUPD_PENDING_STS mmPSOC_GLOBAL_CONF_COLD_RST_FLOPS_3
#define mmPID_CMD_REQ_REG mmPSOC_PID_PID_CMD_0
@@ -55,5 +54,8 @@
#define mmPID_CMD_TELEMETRY_REG_0_HI mmPSOC_PID_PID_CMD_5
#define mmPID_CMD_TELEMETRY_REG_1 mmPSOC_PID_PID_CMD_6
#define mmPID_CMD_TELEMETRY_REG_1_HI mmPSOC_PID_PID_CMD_7
+#define mmWD_GPIO_OUTSET_REG mmPSOC_GPIO3_OUTENSET
+#define mmWD_GPIO_DATAOUT_REG mmPSOC_GPIO3_DATAOUT
+#define mmSTM_PROFILER_SPE_REG mmPSOC_STM_STMSPER
#endif /* GAUDI2_REG_MAP_H_ */
diff --git a/drivers/accel/habanalabs/include/gaudi2/gaudi2_special_blocks.h b/drivers/accel/habanalabs/include/gaudi2/gaudi2_special_blocks.h
new file mode 100644
index 000000000000..a55668f92dd1
--- /dev/null
+++ b/drivers/accel/habanalabs/include/gaudi2/gaudi2_special_blocks.h
@@ -0,0 +1,157 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright 2022 HabanaLabs, Ltd.
+ * All Rights Reserved.
+ */
+
+/*
+ * This file was generated automatically.
+ * DON'T EDIT THIS FILE.
+ */
+
+#ifndef GAUDI2_SPECIAL_BLOCKS_H
+#define GAUDI2_SPECIAL_BLOCKS_H
+
+#define GAUDI2_SPECIAL_BLOCKS { \
+ { GAUDI2_BLOCK_TYPE_TPC, 0xfc008000, 4, 6, 0, 0x200000, 0x10000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_TPC, 0xfc00a000, 4, 6, 0, 0x200000, 0x10000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_TPC, 0xfc00b000, 4, 6, 0, 0x200000, 0x10000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_TPC, 0xfc00c000, 4, 6, 0, 0x200000, 0x10000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_HMMU, 0xfc080000, 4, 4, 0, 0x200000, 0x10000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_HMMU, 0xfc081000, 4, 4, 0, 0x200000, 0x10000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_HMMU, 0xfc083000, 4, 4, 0, 0x200000, 0x10000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_HMMU, 0xfc084000, 4, 4, 0, 0x200000, 0x10000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_MME, 0xfc0c8000, 4, 0, 0, 0x200000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_MME, 0xfc0c9000, 4, 0, 0, 0x200000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_MME, 0xfc0ca000, 4, 0, 0, 0x200000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_MME, 0xfc0cb000, 4, 0, 0, 0x200000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_MME, 0xfc0cc000, 4, 0, 0, 0x200000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_EU_BIST, 0xfc0cd000, 4, 0, 0, 0x200000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_MME, 0xfc0ce000, 4, 0, 0, 0x200000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_MME, 0xfc0cf000, 4, 0, 0, 0x200000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_MME, 0xfc0d0000, 4, 5, 0, 0x200000, 0x8000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_MME, 0xfc0d1000, 4, 5, 0, 0x200000, 0x8000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_MME, 0xfc0f8000, 4, 0, 0, 0x200000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_MME, 0xfc0f9000, 4, 2, 0, 0x200000, 0x1000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_SYNC_MNGR, 0xfc11e000, 4, 0, 0, 0x200000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_SYNC_MNGR, 0xfc11f000, 4, 0, 0, 0x200000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_HIF, 0xfc120000, 4, 4, 0, 0x200000, 0x4000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_RTR, 0xfc140000, 4, 8, 0, 0x200000, 0x8000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_RTR, 0xfc141000, 4, 8, 0, 0x200000, 0x8000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_RTR, 0xfc142000, 4, 8, 0, 0x200000, 0x8000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_RTR, 0xfc143000, 4, 8, 0, 0x200000, 0x8000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_RTR, 0xfc144000, 4, 8, 0, 0x200000, 0x8000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_RTR, 0xfc145000, 4, 8, 0, 0x200000, 0x8000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_SRAM, 0xfc180000, 4, 8, 0, 0x200000, 0x8000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_RTR, 0xfc181000, 4, 8, 0, 0x200000, 0x8000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_SRAM, 0xfc182000, 4, 8, 0, 0x200000, 0x8000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_EDMA, 0xfc1c8000, 4, 2, 0, 0x200000, 0x10000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_EDMA, 0xfc1ca000, 4, 2, 0, 0x200000, 0x10000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_EDMA, 0xfc1cb000, 4, 2, 0, 0x200000, 0x10000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_EDMA, 0xfc1cc000, 4, 2, 0, 0x200000, 0x10000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_DEC, 0xfc1e3000, 4, 2, 0, 0x200000, 0x10000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_DEC, 0xfc1e4000, 4, 2, 0, 0x200000, 0x10000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_DEC, 0xfc1e5000, 4, 2, 0, 0x200000, 0x10000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PCIE, 0xfcc01000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PCIE, 0xfcc04000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PCIE, 0xfcc07000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PCIE, 0xfcc10000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PCIE, 0xfcc14000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PCIE, 0xfcc15000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PCIE, 0xfcc16000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PSOC, 0xfcc4a000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PSOC, 0xfcc4b000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PSOC, 0xfcc4e000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PSOC, 0xfcc4f000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PSOC, 0xfcc53000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PSOC, 0xfcc54000, 2, 0, 0, 0x1000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PSOC, 0xfcc58000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PSOC, 0xfcc59000, 2, 0, 0, 0x3000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PSOC, 0xfcc5a000, 2, 0, 0, 0x3000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PSOC, 0xfcc5b000, 2, 0, 0, 0x3000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PSOC, 0xfcc60000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PSOC, 0xfcc61000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PSOC, 0xfcc62000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PSOC, 0xfcc63000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PSOC, 0xfcc64000, 3, 0, 0, 0x1000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PLL, 0xfcc6c000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PLL, 0xfcc6d000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PLL, 0xfcc6e000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PSOC, 0xfcc74000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PSOC, 0xfcc76000, 3, 0, 0, 0x1000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PSOC, 0xfcc79000, 2, 0, 0, 0x1000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PSOC, 0xfcc7b000, 3, 0, 0, 0x1000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PSOC, 0xfcc7f000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PDMA, 0xfcc88000, 2, 0, 0, 0x10000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PDMA, 0xfcc8a000, 2, 0, 0, 0x10000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PDMA, 0xfcc8b000, 2, 0, 0, 0x10000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PDMA, 0xfcc8c000, 2, 0, 0, 0x10000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_CPU, 0xfccc0000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_CPU, 0xfccc1000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_CPU, 0xfccc3000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PMMU, 0xfcd00000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PMMU, 0xfcd01000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PMMU, 0xfcd02000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PMMU, 0xfcd03000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PLL, 0xfcd04000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PLL, 0xfcd05000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_XBAR, 0xfcd40000, 4, 0, 0, 0x10000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PLL, 0xfcd41000, 4, 0, 0, 0x10000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PLL, 0xfcd42000, 4, 0, 0, 0x10000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PLL, 0xfcd43000, 4, 0, 0, 0x10000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PLL, 0xfcd44000, 2, 0, 0, 0x10000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_XBAR, 0xfcd48000, 4, 0, 0, 0x10000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PLL, 0xfcd55000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PLL, 0xfcd64000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PLL, 0xfcd65000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PLL, 0xfcd74000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_ROT, 0xfce08000, 2, 0, 0, 0x10000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_ROT, 0xfce0a000, 2, 0, 0, 0x10000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_ROT, 0xfce0b000, 2, 0, 0, 0x10000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_ROT, 0xfce0c000, 2, 0, 0, 0x10000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_RTR, 0xfce40000, 4, 2, 0, 0x10000, 0x4000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_RTR, 0xfce41000, 4, 2, 0, 0x10000, 0x4000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_RTR, 0xfce42000, 4, 2, 0, 0x10000, 0x4000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_RTR, 0xfce43000, 4, 2, 0, 0x10000, 0x4000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_RTR, 0xfce48000, 4, 0, 0, 0x10000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_RTR, 0xfce49000, 4, 0, 0, 0x10000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_RTR, 0xfce4a000, 4, 0, 0, 0x10000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_RTR, 0xfce4b000, 4, 0, 0, 0x10000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_RTR, 0xfce4c000, 4, 0, 0, 0x10000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_ARC_FARM, 0xfce81000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_ARC_FARM, 0xfce82000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_ARC_FARM, 0xfce88000, 4, 0, 0, 0x20000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_ARC_FARM, 0xfce89000, 4, 0, 0, 0x20000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_ARC_FARM, 0xfce8b000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_ARC_FARM, 0xfce8c000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_ARC_FARM, 0xfce8f000, 4, 0, 0, 0x20000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_DEC, 0xfcf03000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_DEC, 0xfcf04000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_DEC, 0xfcf05000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_XFT, 0xfcf40000, 4, 0, 0, 0x10000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PLL, 0xfcf41000, 4, 0, 0, 0x10000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PLL, 0xfcf42000, 4, 0, 0, 0x10000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PLL, 0xfcf43000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PLL, 0xfcf53000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_PLL, 0xfcf73000, 1, 0, 0, 0x0, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_HBM, 0xfd000000, 6, 2, 0, 0x80000, 0x20000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_HBM, 0xfd001000, 6, 2, 8, 0x80000, 0x20000, 0x1000 }, \
+ { GAUDI2_BLOCK_TYPE_HBM, 0xfd009000, 6, 2, 0, 0x80000, 0x20000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_NIC, 0xfd400000, 12, 2, 15, 0x80000, 0x20000, 0x1000 }, \
+ { GAUDI2_BLOCK_TYPE_NIC, 0xfd418000, 12, 2, 0, 0x80000, 0x20000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_NIC, 0xfd41a000, 12, 2, 0, 0x80000, 0x20000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_NIC, 0xfd41f000, 12, 2, 0, 0x80000, 0x20000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_NIC, 0xfd448000, 12, 0, 0, 0x80000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_NIC, 0xfd449000, 12, 0, 0, 0x80000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_NIC, 0xfd44a000, 12, 2, 0, 0x80000, 0x1000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_NIC, 0xfd44c000, 12, 2, 0, 0x80000, 0x1000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_NIC, 0xfd450000, 12, 2, 0, 0x80000, 0x1000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_NIC, 0xfd452000, 12, 2, 0, 0x80000, 0x1000, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_NIC, 0xfd454000, 12, 0, 0, 0x80000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_NIC, 0xfd455000, 12, 0, 0, 0x80000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_NIC, 0xfd460000, 12, 0, 0, 0x80000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_NIC, 0xfd468000, 12, 0, 0, 0x80000, 0x0, 0x0 }, \
+ { GAUDI2_BLOCK_TYPE_NIC, 0xfd469000, 12, 0, 0, 0x80000, 0x0, 0x0 }, \
+}
+
+#endif
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/cpu_ca53_cfg_masks.h b/drivers/accel/habanalabs/include/goya/asic_reg/cpu_ca53_cfg_masks.h
index 4e0dbbbbde20..4e0dbbbbde20 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/cpu_ca53_cfg_masks.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/cpu_ca53_cfg_masks.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/cpu_ca53_cfg_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/cpu_ca53_cfg_regs.h
index f3faf1aad91a..f3faf1aad91a 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/cpu_ca53_cfg_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/cpu_ca53_cfg_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/cpu_if_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/cpu_if_regs.h
index cf657918962a..cf657918962a 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/cpu_if_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/cpu_if_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/cpu_pll_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/cpu_pll_regs.h
index 8c8f9726d4b9..8c8f9726d4b9 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/cpu_pll_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/cpu_pll_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/dma_ch_0_masks.h b/drivers/accel/habanalabs/include/goya/asic_reg/dma_ch_0_masks.h
index 028143408401..028143408401 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/dma_ch_0_masks.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/dma_ch_0_masks.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/dma_ch_0_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/dma_ch_0_regs.h
index 0b246fe6ad04..0b246fe6ad04 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/dma_ch_0_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/dma_ch_0_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/dma_ch_1_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/dma_ch_1_regs.h
index 5449031722f2..5449031722f2 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/dma_ch_1_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/dma_ch_1_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/dma_ch_2_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/dma_ch_2_regs.h
index a4768521d18a..a4768521d18a 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/dma_ch_2_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/dma_ch_2_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/dma_ch_3_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/dma_ch_3_regs.h
index 619d01897ff8..619d01897ff8 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/dma_ch_3_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/dma_ch_3_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/dma_ch_4_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/dma_ch_4_regs.h
index 038617e163f1..038617e163f1 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/dma_ch_4_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/dma_ch_4_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/dma_macro_masks.h b/drivers/accel/habanalabs/include/goya/asic_reg/dma_macro_masks.h
index f43b564af1be..f43b564af1be 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/dma_macro_masks.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/dma_macro_masks.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/dma_macro_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/dma_macro_regs.h
index c3bfc1b8e3fd..c3bfc1b8e3fd 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/dma_macro_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/dma_macro_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/dma_nrtr_masks.h b/drivers/accel/habanalabs/include/goya/asic_reg/dma_nrtr_masks.h
index bc977488c072..bc977488c072 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/dma_nrtr_masks.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/dma_nrtr_masks.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/dma_nrtr_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/dma_nrtr_regs.h
index c4abc7ff1fc6..c4abc7ff1fc6 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/dma_nrtr_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/dma_nrtr_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/dma_qm_0_masks.h b/drivers/accel/habanalabs/include/goya/asic_reg/dma_qm_0_masks.h
index b17f72c31ab6..b17f72c31ab6 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/dma_qm_0_masks.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/dma_qm_0_masks.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/dma_qm_0_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/dma_qm_0_regs.h
index bf360b301154..bf360b301154 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/dma_qm_0_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/dma_qm_0_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/dma_qm_1_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/dma_qm_1_regs.h
index 51d432d05ac4..51d432d05ac4 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/dma_qm_1_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/dma_qm_1_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/dma_qm_2_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/dma_qm_2_regs.h
index 18fc0c2b6cc2..18fc0c2b6cc2 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/dma_qm_2_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/dma_qm_2_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/dma_qm_3_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/dma_qm_3_regs.h
index 6cf7204bf5cc..6cf7204bf5cc 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/dma_qm_3_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/dma_qm_3_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/dma_qm_4_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/dma_qm_4_regs.h
index 36fef2682875..36fef2682875 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/dma_qm_4_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/dma_qm_4_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/goya_blocks.h b/drivers/accel/habanalabs/include/goya/asic_reg/goya_blocks.h
index 85b15010cd7a..85b15010cd7a 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/goya_blocks.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/goya_blocks.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/goya_masks.h b/drivers/accel/habanalabs/include/goya/asic_reg/goya_masks.h
index 9ff3cb245580..9ff3cb245580 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/goya_masks.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/goya_masks.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/goya_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/goya_regs.h
index ce65c9da5c60..ce65c9da5c60 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/goya_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/goya_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/ic_pll_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/ic_pll_regs.h
index 4ae7fed8b18c..4ae7fed8b18c 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/ic_pll_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/ic_pll_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/mc_pll_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/mc_pll_regs.h
index 6d35d852798b..6d35d852798b 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/mc_pll_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/mc_pll_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/mme1_rtr_masks.h b/drivers/accel/habanalabs/include/goya/asic_reg/mme1_rtr_masks.h
index 6c23f8b96e7e..6c23f8b96e7e 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/mme1_rtr_masks.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/mme1_rtr_masks.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/mme1_rtr_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/mme1_rtr_regs.h
index 122e9d529939..122e9d529939 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/mme1_rtr_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/mme1_rtr_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/mme2_rtr_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/mme2_rtr_regs.h
index 00ce2252bbfb..00ce2252bbfb 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/mme2_rtr_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/mme2_rtr_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/mme3_rtr_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/mme3_rtr_regs.h
index 8e3eb7fd2070..8e3eb7fd2070 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/mme3_rtr_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/mme3_rtr_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/mme4_rtr_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/mme4_rtr_regs.h
index 79b67bbc8567..79b67bbc8567 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/mme4_rtr_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/mme4_rtr_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/mme5_rtr_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/mme5_rtr_regs.h
index 0ac3c37ce47f..0ac3c37ce47f 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/mme5_rtr_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/mme5_rtr_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/mme6_rtr_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/mme6_rtr_regs.h
index 50c49cce72a6..50c49cce72a6 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/mme6_rtr_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/mme6_rtr_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/mme_cmdq_masks.h b/drivers/accel/habanalabs/include/goya/asic_reg/mme_cmdq_masks.h
index fe7d95bdcef9..fe7d95bdcef9 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/mme_cmdq_masks.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/mme_cmdq_masks.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/mme_cmdq_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/mme_cmdq_regs.h
index 5f8b85d2b4b1..5f8b85d2b4b1 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/mme_cmdq_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/mme_cmdq_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/mme_masks.h b/drivers/accel/habanalabs/include/goya/asic_reg/mme_masks.h
index 1882c413cbe0..1882c413cbe0 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/mme_masks.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/mme_masks.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/mme_qm_masks.h b/drivers/accel/habanalabs/include/goya/asic_reg/mme_qm_masks.h
index e464e381555c..e464e381555c 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/mme_qm_masks.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/mme_qm_masks.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/mme_qm_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/mme_qm_regs.h
index 538708beffc9..538708beffc9 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/mme_qm_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/mme_qm_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/mme_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/mme_regs.h
index 0396cbfd5c89..0396cbfd5c89 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/mme_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/mme_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/mmu_masks.h b/drivers/accel/habanalabs/include/goya/asic_reg/mmu_masks.h
index c3e69062b135..c3e69062b135 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/mmu_masks.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/mmu_masks.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/mmu_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/mmu_regs.h
index 7ec81f12031e..7ec81f12031e 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/mmu_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/mmu_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/pci_nrtr_masks.h b/drivers/accel/habanalabs/include/goya/asic_reg/pci_nrtr_masks.h
index ceb59f2e28b3..ceb59f2e28b3 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/pci_nrtr_masks.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/pci_nrtr_masks.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/pci_nrtr_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/pci_nrtr_regs.h
index dd067f301ac2..dd067f301ac2 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/pci_nrtr_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/pci_nrtr_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/pcie_aux_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/pcie_aux_regs.h
index 35b1d8ac6f63..35b1d8ac6f63 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/pcie_aux_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/pcie_aux_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/pcie_wrap_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/pcie_wrap_regs.h
index d1e55aace4a0..d1e55aace4a0 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/pcie_wrap_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/pcie_wrap_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/psoc_emmc_pll_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/psoc_emmc_pll_regs.h
index 9271ea95ebe9..9271ea95ebe9 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/psoc_emmc_pll_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/psoc_emmc_pll_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/psoc_etr_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/psoc_etr_regs.h
index b7c33e025db5..b7c33e025db5 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/psoc_etr_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/psoc_etr_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/psoc_global_conf_masks.h b/drivers/accel/habanalabs/include/goya/asic_reg/psoc_global_conf_masks.h
index 324266653c9a..324266653c9a 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/psoc_global_conf_masks.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/psoc_global_conf_masks.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/psoc_global_conf_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/psoc_global_conf_regs.h
index 8141f422e712..8141f422e712 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/psoc_global_conf_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/psoc_global_conf_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/psoc_mme_pll_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/psoc_mme_pll_regs.h
index 4789ebb9c337..4789ebb9c337 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/psoc_mme_pll_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/psoc_mme_pll_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/psoc_pci_pll_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/psoc_pci_pll_regs.h
index 27a296ea6c3d..27a296ea6c3d 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/psoc_pci_pll_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/psoc_pci_pll_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/psoc_spi_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/psoc_spi_regs.h
index 66aee7fa6b1e..66aee7fa6b1e 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/psoc_spi_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/psoc_spi_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/psoc_timestamp_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/psoc_timestamp_regs.h
index 9ce24597d4b0..9ce24597d4b0 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/psoc_timestamp_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/psoc_timestamp_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/sram_y0_x0_rtr_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/sram_y0_x0_rtr_regs.h
index 2ea1770b078f..2ea1770b078f 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/sram_y0_x0_rtr_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/sram_y0_x0_rtr_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/sram_y0_x1_rtr_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/sram_y0_x1_rtr_regs.h
index 37e0713efa73..37e0713efa73 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/sram_y0_x1_rtr_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/sram_y0_x1_rtr_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/sram_y0_x2_rtr_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/sram_y0_x2_rtr_regs.h
index d2572279a2b9..d2572279a2b9 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/sram_y0_x2_rtr_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/sram_y0_x2_rtr_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/sram_y0_x3_rtr_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/sram_y0_x3_rtr_regs.h
index 68c5b402c506..68c5b402c506 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/sram_y0_x3_rtr_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/sram_y0_x3_rtr_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/sram_y0_x4_rtr_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/sram_y0_x4_rtr_regs.h
index a42f1ba06d28..a42f1ba06d28 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/sram_y0_x4_rtr_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/sram_y0_x4_rtr_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/stlb_masks.h b/drivers/accel/habanalabs/include/goya/asic_reg/stlb_masks.h
index 94f2ed4a36bd..94f2ed4a36bd 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/stlb_masks.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/stlb_masks.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/stlb_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/stlb_regs.h
index 35013f65acd2..35013f65acd2 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/stlb_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/stlb_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc0_cfg_masks.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc0_cfg_masks.h
index 89c9507a512f..89c9507a512f 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc0_cfg_masks.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc0_cfg_masks.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc0_cfg_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc0_cfg_regs.h
index 7d71c4b73a5e..7d71c4b73a5e 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc0_cfg_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc0_cfg_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc0_cmdq_masks.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc0_cmdq_masks.h
index 9395f2458771..9395f2458771 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc0_cmdq_masks.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc0_cmdq_masks.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc0_cmdq_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc0_cmdq_regs.h
index bc51df573bf0..bc51df573bf0 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc0_cmdq_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc0_cmdq_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc0_eml_cfg_masks.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc0_eml_cfg_masks.h
index 553c6b6bd5ec..553c6b6bd5ec 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc0_eml_cfg_masks.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc0_eml_cfg_masks.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc0_eml_cfg_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc0_eml_cfg_regs.h
index 8495479c3659..8495479c3659 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc0_eml_cfg_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc0_eml_cfg_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc0_nrtr_masks.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc0_nrtr_masks.h
index 43fafcf01041..43fafcf01041 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc0_nrtr_masks.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc0_nrtr_masks.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc0_nrtr_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc0_nrtr_regs.h
index ce3346dd2042..ce3346dd2042 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc0_nrtr_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc0_nrtr_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc0_qm_masks.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc0_qm_masks.h
index 2e4b45947944..2e4b45947944 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc0_qm_masks.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc0_qm_masks.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc0_qm_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc0_qm_regs.h
index 4fa09eb88878..4fa09eb88878 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc0_qm_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc0_qm_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc1_cfg_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc1_cfg_regs.h
index 928eef1808ae..928eef1808ae 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc1_cfg_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc1_cfg_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc1_cmdq_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc1_cmdq_regs.h
index 30ae0f307328..30ae0f307328 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc1_cmdq_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc1_cmdq_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc1_qm_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc1_qm_regs.h
index b95de4f95ba9..b95de4f95ba9 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc1_qm_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc1_qm_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc1_rtr_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc1_rtr_regs.h
index 0f91e307879e..0f91e307879e 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc1_rtr_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc1_rtr_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc2_cfg_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc2_cfg_regs.h
index 73421227f35b..73421227f35b 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc2_cfg_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc2_cfg_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc2_cmdq_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc2_cmdq_regs.h
index 27b66bf2da9f..27b66bf2da9f 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc2_cmdq_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc2_cmdq_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc2_qm_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc2_qm_regs.h
index 31e5b2f53905..31e5b2f53905 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc2_qm_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc2_qm_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc2_rtr_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc2_rtr_regs.h
index 4eddeaa15d94..4eddeaa15d94 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc2_rtr_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc2_rtr_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc3_cfg_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc3_cfg_regs.h
index ce573a1a8361..ce573a1a8361 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc3_cfg_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc3_cfg_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc3_cmdq_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc3_cmdq_regs.h
index 11d81fca0a0f..11d81fca0a0f 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc3_cmdq_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc3_cmdq_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc3_qm_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc3_qm_regs.h
index e41595a19e69..e41595a19e69 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc3_qm_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc3_qm_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc3_rtr_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc3_rtr_regs.h
index 34a438b1efe5..34a438b1efe5 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc3_rtr_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc3_rtr_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc4_cfg_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc4_cfg_regs.h
index d44caf0fc1bb..d44caf0fc1bb 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc4_cfg_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc4_cfg_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc4_cmdq_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc4_cmdq_regs.h
index f13a6532961f..f13a6532961f 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc4_cmdq_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc4_cmdq_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc4_qm_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc4_qm_regs.h
index db081fc17cfc..db081fc17cfc 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc4_qm_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc4_qm_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc4_rtr_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc4_rtr_regs.h
index 8c5372303b28..8c5372303b28 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc4_rtr_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc4_rtr_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc5_cfg_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc5_cfg_regs.h
index 5139fde71011..5139fde71011 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc5_cfg_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc5_cfg_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc5_cmdq_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc5_cmdq_regs.h
index 1e7cd6e1e888..1e7cd6e1e888 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc5_cmdq_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc5_cmdq_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc5_qm_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc5_qm_regs.h
index ac0d3820cd6b..ac0d3820cd6b 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc5_qm_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc5_qm_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc5_rtr_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc5_rtr_regs.h
index 57f83bc3b17d..57f83bc3b17d 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc5_rtr_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc5_rtr_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc6_cfg_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc6_cfg_regs.h
index 94e0191c06c1..94e0191c06c1 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc6_cfg_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc6_cfg_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc6_cmdq_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc6_cmdq_regs.h
index 7a1a0e87b225..7a1a0e87b225 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc6_cmdq_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc6_cmdq_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc6_qm_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc6_qm_regs.h
index 80fa0fe0f60f..80fa0fe0f60f 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc6_qm_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc6_qm_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc6_rtr_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc6_rtr_regs.h
index d6cae8b8af66..d6cae8b8af66 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc6_rtr_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc6_rtr_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc7_cfg_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc7_cfg_regs.h
index 234147adb779..234147adb779 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc7_cfg_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc7_cfg_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc7_cmdq_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc7_cmdq_regs.h
index 4c160632fe7d..4c160632fe7d 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc7_cmdq_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc7_cmdq_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc7_nrtr_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc7_nrtr_regs.h
index 0c13d4d167aa..0c13d4d167aa 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc7_nrtr_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc7_nrtr_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc7_qm_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc7_qm_regs.h
index cbe11425bfb0..cbe11425bfb0 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc7_qm_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc7_qm_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/asic_reg/tpc_pll_regs.h b/drivers/accel/habanalabs/include/goya/asic_reg/tpc_pll_regs.h
index e25e19660a9d..e25e19660a9d 100644
--- a/drivers/misc/habanalabs/include/goya/asic_reg/tpc_pll_regs.h
+++ b/drivers/accel/habanalabs/include/goya/asic_reg/tpc_pll_regs.h
diff --git a/drivers/misc/habanalabs/include/goya/goya.h b/drivers/accel/habanalabs/include/goya/goya.h
index 1b4ca435021d..1b4ca435021d 100644
--- a/drivers/misc/habanalabs/include/goya/goya.h
+++ b/drivers/accel/habanalabs/include/goya/goya.h
diff --git a/drivers/misc/habanalabs/include/goya/goya_async_events.h b/drivers/accel/habanalabs/include/goya/goya_async_events.h
index 09081401cb1d..09081401cb1d 100644
--- a/drivers/misc/habanalabs/include/goya/goya_async_events.h
+++ b/drivers/accel/habanalabs/include/goya/goya_async_events.h
diff --git a/drivers/misc/habanalabs/include/goya/goya_coresight.h b/drivers/accel/habanalabs/include/goya/goya_coresight.h
index 6e933c0ca5cd..6e933c0ca5cd 100644
--- a/drivers/misc/habanalabs/include/goya/goya_coresight.h
+++ b/drivers/accel/habanalabs/include/goya/goya_coresight.h
diff --git a/drivers/misc/habanalabs/include/goya/goya_fw_if.h b/drivers/accel/habanalabs/include/goya/goya_fw_if.h
index bc05f86c73ac..bc05f86c73ac 100644
--- a/drivers/misc/habanalabs/include/goya/goya_fw_if.h
+++ b/drivers/accel/habanalabs/include/goya/goya_fw_if.h
diff --git a/drivers/misc/habanalabs/include/goya/goya_packets.h b/drivers/accel/habanalabs/include/goya/goya_packets.h
index 896799204fb0..896799204fb0 100644
--- a/drivers/misc/habanalabs/include/goya/goya_packets.h
+++ b/drivers/accel/habanalabs/include/goya/goya_packets.h
diff --git a/drivers/misc/habanalabs/include/goya/goya_reg_map.h b/drivers/accel/habanalabs/include/goya/goya_reg_map.h
index f3ab282cafa4..f3ab282cafa4 100644
--- a/drivers/misc/habanalabs/include/goya/goya_reg_map.h
+++ b/drivers/accel/habanalabs/include/goya/goya_reg_map.h
diff --git a/drivers/misc/habanalabs/include/hw_ip/mmu/mmu_general.h b/drivers/accel/habanalabs/include/hw_ip/mmu/mmu_general.h
index d408feecd483..d408feecd483 100644
--- a/drivers/misc/habanalabs/include/hw_ip/mmu/mmu_general.h
+++ b/drivers/accel/habanalabs/include/hw_ip/mmu/mmu_general.h
diff --git a/drivers/misc/habanalabs/include/hw_ip/mmu/mmu_v1_0.h b/drivers/accel/habanalabs/include/hw_ip/mmu/mmu_v1_0.h
index 86511002e367..86511002e367 100644
--- a/drivers/misc/habanalabs/include/hw_ip/mmu/mmu_v1_0.h
+++ b/drivers/accel/habanalabs/include/hw_ip/mmu/mmu_v1_0.h
diff --git a/drivers/misc/habanalabs/include/hw_ip/mmu/mmu_v1_1.h b/drivers/accel/habanalabs/include/hw_ip/mmu/mmu_v1_1.h
index 9c727a5d47b4..9c727a5d47b4 100644
--- a/drivers/misc/habanalabs/include/hw_ip/mmu/mmu_v1_1.h
+++ b/drivers/accel/habanalabs/include/hw_ip/mmu/mmu_v1_1.h
diff --git a/drivers/misc/habanalabs/include/hw_ip/mmu/mmu_v2_0.h b/drivers/accel/habanalabs/include/hw_ip/mmu/mmu_v2_0.h
index cd7bf25d2da9..cd7bf25d2da9 100644
--- a/drivers/misc/habanalabs/include/hw_ip/mmu/mmu_v2_0.h
+++ b/drivers/accel/habanalabs/include/hw_ip/mmu/mmu_v2_0.h
diff --git a/drivers/misc/habanalabs/include/hw_ip/pci/pci_general.h b/drivers/accel/habanalabs/include/hw_ip/pci/pci_general.h
index f5d497dc9bdc..f5d497dc9bdc 100644
--- a/drivers/misc/habanalabs/include/hw_ip/pci/pci_general.h
+++ b/drivers/accel/habanalabs/include/hw_ip/pci/pci_general.h
diff --git a/drivers/accel/ivpu/Kconfig b/drivers/accel/ivpu/Kconfig
new file mode 100644
index 000000000000..9bdf168bf1d0
--- /dev/null
+++ b/drivers/accel/ivpu/Kconfig
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config DRM_ACCEL_IVPU
+ tristate "Intel VPU for Meteor Lake and newer"
+ depends on DRM_ACCEL
+ depends on X86_64 && !UML
+ depends on PCI && PCI_MSI
+ select FW_LOADER
+ select SHMEM
+ help
+ Choose this option if you have a system that has an 14th generation Intel CPU
+ or newer. VPU stands for Versatile Processing Unit and it's a CPU-integrated
+ inference accelerator for Computer Vision and Deep Learning applications.
+
+ If "M" is selected, the module will be called intel_vpu.
diff --git a/drivers/accel/ivpu/Makefile b/drivers/accel/ivpu/Makefile
new file mode 100644
index 000000000000..80f1fb3548ae
--- /dev/null
+++ b/drivers/accel/ivpu/Makefile
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# Copyright (C) 2023 Intel Corporation
+
+intel_vpu-y := \
+ ivpu_drv.o \
+ ivpu_fw.o \
+ ivpu_gem.o \
+ ivpu_hw_mtl.o \
+ ivpu_ipc.o \
+ ivpu_job.o \
+ ivpu_jsm_msg.o \
+ ivpu_mmu.o \
+ ivpu_mmu_context.o \
+ ivpu_pm.o
+
+obj-$(CONFIG_DRM_ACCEL_IVPU) += intel_vpu.o \ No newline at end of file
diff --git a/drivers/accel/ivpu/TODO b/drivers/accel/ivpu/TODO
new file mode 100644
index 000000000000..9077217ae10f
--- /dev/null
+++ b/drivers/accel/ivpu/TODO
@@ -0,0 +1,11 @@
+- Move to threaded_irqs to mitigate potential infinite loop in ivpu_ipc_irq_handler()
+- Implement support for BLOB IDs
+- Add debugfs support to improve debugging and testing
+- Add tracing events for performance debugging
+- Implement HW based scheduling support
+- Use syncobjs for submit/sync
+- Refactor IPC protocol to improve message latency
+- Implement BO cache and MADVISE IOCTL
+- Add support for user allocated buffers using prime import and dma-buf heaps
+- Refactor struct ivpu_bo to use struct drm_gem_shmem_object
+- Add driver/device documentation
diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c
new file mode 100644
index 000000000000..231f29bb5025
--- /dev/null
+++ b/drivers/accel/ivpu/ivpu_drv.c
@@ -0,0 +1,655 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2020-2023 Intel Corporation
+ */
+
+#include <linux/firmware.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include <drm/drm_accel.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_file.h>
+#include <drm/drm_gem.h>
+#include <drm/drm_ioctl.h>
+#include <drm/drm_prime.h>
+
+#include "vpu_boot_api.h"
+#include "ivpu_drv.h"
+#include "ivpu_fw.h"
+#include "ivpu_gem.h"
+#include "ivpu_hw.h"
+#include "ivpu_ipc.h"
+#include "ivpu_job.h"
+#include "ivpu_jsm_msg.h"
+#include "ivpu_mmu.h"
+#include "ivpu_mmu_context.h"
+#include "ivpu_pm.h"
+
+#ifndef DRIVER_VERSION_STR
+#define DRIVER_VERSION_STR __stringify(DRM_IVPU_DRIVER_MAJOR) "." \
+ __stringify(DRM_IVPU_DRIVER_MINOR) "."
+#endif
+
+static const struct drm_driver driver;
+
+static struct lock_class_key submitted_jobs_xa_lock_class_key;
+
+int ivpu_dbg_mask;
+module_param_named(dbg_mask, ivpu_dbg_mask, int, 0644);
+MODULE_PARM_DESC(dbg_mask, "Driver debug mask. See IVPU_DBG_* macros.");
+
+int ivpu_test_mode;
+module_param_named_unsafe(test_mode, ivpu_test_mode, int, 0644);
+MODULE_PARM_DESC(test_mode, "Test mode: 0 - normal operation, 1 - fw unit test, 2 - null hw");
+
+u8 ivpu_pll_min_ratio;
+module_param_named(pll_min_ratio, ivpu_pll_min_ratio, byte, 0644);
+MODULE_PARM_DESC(pll_min_ratio, "Minimum PLL ratio used to set VPU frequency");
+
+u8 ivpu_pll_max_ratio = U8_MAX;
+module_param_named(pll_max_ratio, ivpu_pll_max_ratio, byte, 0644);
+MODULE_PARM_DESC(pll_max_ratio, "Maximum PLL ratio used to set VPU frequency");
+
+struct ivpu_file_priv *ivpu_file_priv_get(struct ivpu_file_priv *file_priv)
+{
+ struct ivpu_device *vdev = file_priv->vdev;
+
+ kref_get(&file_priv->ref);
+
+ ivpu_dbg(vdev, KREF, "file_priv get: ctx %u refcount %u\n",
+ file_priv->ctx.id, kref_read(&file_priv->ref));
+
+ return file_priv;
+}
+
+struct ivpu_file_priv *ivpu_file_priv_get_by_ctx_id(struct ivpu_device *vdev, unsigned long id)
+{
+ struct ivpu_file_priv *file_priv;
+
+ xa_lock_irq(&vdev->context_xa);
+ file_priv = xa_load(&vdev->context_xa, id);
+ /* file_priv may still be in context_xa during file_priv_release() */
+ if (file_priv && !kref_get_unless_zero(&file_priv->ref))
+ file_priv = NULL;
+ xa_unlock_irq(&vdev->context_xa);
+
+ if (file_priv)
+ ivpu_dbg(vdev, KREF, "file_priv get by id: ctx %u refcount %u\n",
+ file_priv->ctx.id, kref_read(&file_priv->ref));
+
+ return file_priv;
+}
+
+static void file_priv_release(struct kref *ref)
+{
+ struct ivpu_file_priv *file_priv = container_of(ref, struct ivpu_file_priv, ref);
+ struct ivpu_device *vdev = file_priv->vdev;
+
+ ivpu_dbg(vdev, FILE, "file_priv release: ctx %u\n", file_priv->ctx.id);
+
+ ivpu_cmdq_release_all(file_priv);
+ ivpu_bo_remove_all_bos_from_context(&file_priv->ctx);
+ ivpu_jsm_context_release(vdev, file_priv->ctx.id);
+ ivpu_mmu_user_context_fini(vdev, &file_priv->ctx);
+ drm_WARN_ON(&vdev->drm, xa_erase_irq(&vdev->context_xa, file_priv->ctx.id) != file_priv);
+ mutex_destroy(&file_priv->lock);
+ kfree(file_priv);
+}
+
+void ivpu_file_priv_put(struct ivpu_file_priv **link)
+{
+ struct ivpu_file_priv *file_priv = *link;
+ struct ivpu_device *vdev = file_priv->vdev;
+
+ drm_WARN_ON(&vdev->drm, !file_priv);
+
+ ivpu_dbg(vdev, KREF, "file_priv put: ctx %u refcount %u\n",
+ file_priv->ctx.id, kref_read(&file_priv->ref));
+
+ *link = NULL;
+ kref_put(&file_priv->ref, file_priv_release);
+}
+
+static int ivpu_get_param_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
+{
+ struct ivpu_file_priv *file_priv = file->driver_priv;
+ struct ivpu_device *vdev = file_priv->vdev;
+ struct pci_dev *pdev = to_pci_dev(vdev->drm.dev);
+ struct drm_ivpu_param *args = data;
+ int ret = 0;
+
+ switch (args->param) {
+ case DRM_IVPU_PARAM_DEVICE_ID:
+ args->value = pdev->device;
+ break;
+ case DRM_IVPU_PARAM_DEVICE_REVISION:
+ args->value = pdev->revision;
+ break;
+ case DRM_IVPU_PARAM_PLATFORM_TYPE:
+ args->value = vdev->platform;
+ break;
+ case DRM_IVPU_PARAM_CORE_CLOCK_RATE:
+ args->value = ivpu_hw_reg_pll_freq_get(vdev);
+ break;
+ case DRM_IVPU_PARAM_NUM_CONTEXTS:
+ args->value = ivpu_get_context_count(vdev);
+ break;
+ case DRM_IVPU_PARAM_CONTEXT_BASE_ADDRESS:
+ args->value = vdev->hw->ranges.user_low.start;
+ break;
+ case DRM_IVPU_PARAM_CONTEXT_PRIORITY:
+ args->value = file_priv->priority;
+ break;
+ case DRM_IVPU_PARAM_CONTEXT_ID:
+ args->value = file_priv->ctx.id;
+ break;
+ case DRM_IVPU_PARAM_FW_API_VERSION:
+ if (args->index < VPU_FW_API_VER_NUM) {
+ struct vpu_firmware_header *fw_hdr;
+
+ fw_hdr = (struct vpu_firmware_header *)vdev->fw->file->data;
+ args->value = fw_hdr->api_version[args->index];
+ } else {
+ ret = -EINVAL;
+ }
+ break;
+ case DRM_IVPU_PARAM_ENGINE_HEARTBEAT:
+ ret = ivpu_jsm_get_heartbeat(vdev, args->index, &args->value);
+ break;
+ case DRM_IVPU_PARAM_UNIQUE_INFERENCE_ID:
+ args->value = (u64)atomic64_inc_return(&vdev->unique_id_counter);
+ break;
+ case DRM_IVPU_PARAM_TILE_CONFIG:
+ args->value = vdev->hw->tile_fuse;
+ break;
+ case DRM_IVPU_PARAM_SKU:
+ args->value = vdev->hw->sku;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int ivpu_set_param_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
+{
+ struct ivpu_file_priv *file_priv = file->driver_priv;
+ struct drm_ivpu_param *args = data;
+ int ret = 0;
+
+ switch (args->param) {
+ case DRM_IVPU_PARAM_CONTEXT_PRIORITY:
+ if (args->value <= DRM_IVPU_CONTEXT_PRIORITY_REALTIME)
+ file_priv->priority = args->value;
+ else
+ ret = -EINVAL;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int ivpu_open(struct drm_device *dev, struct drm_file *file)
+{
+ struct ivpu_device *vdev = to_ivpu_device(dev);
+ struct ivpu_file_priv *file_priv;
+ u32 ctx_id;
+ void *old;
+ int ret;
+
+ ret = xa_alloc_irq(&vdev->context_xa, &ctx_id, NULL, vdev->context_xa_limit, GFP_KERNEL);
+ if (ret) {
+ ivpu_err(vdev, "Failed to allocate context id: %d\n", ret);
+ return ret;
+ }
+
+ file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL);
+ if (!file_priv) {
+ ret = -ENOMEM;
+ goto err_xa_erase;
+ }
+
+ file_priv->vdev = vdev;
+ file_priv->priority = DRM_IVPU_CONTEXT_PRIORITY_NORMAL;
+ kref_init(&file_priv->ref);
+ mutex_init(&file_priv->lock);
+
+ ret = ivpu_mmu_user_context_init(vdev, &file_priv->ctx, ctx_id);
+ if (ret)
+ goto err_mutex_destroy;
+
+ old = xa_store_irq(&vdev->context_xa, ctx_id, file_priv, GFP_KERNEL);
+ if (xa_is_err(old)) {
+ ret = xa_err(old);
+ ivpu_err(vdev, "Failed to store context %u: %d\n", ctx_id, ret);
+ goto err_ctx_fini;
+ }
+
+ ivpu_dbg(vdev, FILE, "file_priv create: ctx %u process %s pid %d\n",
+ ctx_id, current->comm, task_pid_nr(current));
+
+ file->driver_priv = file_priv;
+ return 0;
+
+err_ctx_fini:
+ ivpu_mmu_user_context_fini(vdev, &file_priv->ctx);
+err_mutex_destroy:
+ mutex_destroy(&file_priv->lock);
+ kfree(file_priv);
+err_xa_erase:
+ xa_erase_irq(&vdev->context_xa, ctx_id);
+ return ret;
+}
+
+static void ivpu_postclose(struct drm_device *dev, struct drm_file *file)
+{
+ struct ivpu_file_priv *file_priv = file->driver_priv;
+ struct ivpu_device *vdev = to_ivpu_device(dev);
+
+ ivpu_dbg(vdev, FILE, "file_priv close: ctx %u process %s pid %d\n",
+ file_priv->ctx.id, current->comm, task_pid_nr(current));
+
+ ivpu_file_priv_put(&file_priv);
+}
+
+static const struct drm_ioctl_desc ivpu_drm_ioctls[] = {
+ DRM_IOCTL_DEF_DRV(IVPU_GET_PARAM, ivpu_get_param_ioctl, 0),
+ DRM_IOCTL_DEF_DRV(IVPU_SET_PARAM, ivpu_set_param_ioctl, 0),
+ DRM_IOCTL_DEF_DRV(IVPU_BO_CREATE, ivpu_bo_create_ioctl, 0),
+ DRM_IOCTL_DEF_DRV(IVPU_BO_INFO, ivpu_bo_info_ioctl, 0),
+ DRM_IOCTL_DEF_DRV(IVPU_SUBMIT, ivpu_submit_ioctl, 0),
+ DRM_IOCTL_DEF_DRV(IVPU_BO_WAIT, ivpu_bo_wait_ioctl, 0),
+};
+
+static int ivpu_wait_for_ready(struct ivpu_device *vdev)
+{
+ struct ivpu_ipc_consumer cons;
+ struct ivpu_ipc_hdr ipc_hdr;
+ unsigned long timeout;
+ int ret;
+
+ if (ivpu_test_mode == IVPU_TEST_MODE_FW_TEST)
+ return 0;
+
+ ivpu_ipc_consumer_add(vdev, &cons, IVPU_IPC_CHAN_BOOT_MSG);
+
+ timeout = jiffies + msecs_to_jiffies(vdev->timeout.boot);
+ while (1) {
+ ret = ivpu_ipc_irq_handler(vdev);
+ if (ret)
+ break;
+ ret = ivpu_ipc_receive(vdev, &cons, &ipc_hdr, NULL, 0);
+ if (ret != -ETIMEDOUT || time_after_eq(jiffies, timeout))
+ break;
+
+ cond_resched();
+ }
+
+ ivpu_ipc_consumer_del(vdev, &cons);
+
+ if (!ret && ipc_hdr.data_addr != IVPU_IPC_BOOT_MSG_DATA_ADDR) {
+ ivpu_err(vdev, "Invalid VPU ready message: 0x%x\n",
+ ipc_hdr.data_addr);
+ return -EIO;
+ }
+
+ if (!ret)
+ ivpu_info(vdev, "VPU ready message received successfully\n");
+ else
+ ivpu_hw_diagnose_failure(vdev);
+
+ return ret;
+}
+
+/**
+ * ivpu_boot() - Start VPU firmware
+ * @vdev: VPU device
+ *
+ * This function is paired with ivpu_shutdown() but it doesn't power up the
+ * VPU because power up has to be called very early in ivpu_probe().
+ */
+int ivpu_boot(struct ivpu_device *vdev)
+{
+ int ret;
+
+ /* Update boot params located at first 4KB of FW memory */
+ ivpu_fw_boot_params_setup(vdev, vdev->fw->mem->kvaddr);
+
+ ret = ivpu_hw_boot_fw(vdev);
+ if (ret) {
+ ivpu_err(vdev, "Failed to start the firmware: %d\n", ret);
+ return ret;
+ }
+
+ ret = ivpu_wait_for_ready(vdev);
+ if (ret) {
+ ivpu_err(vdev, "Failed to boot the firmware: %d\n", ret);
+ return ret;
+ }
+
+ ivpu_hw_irq_clear(vdev);
+ enable_irq(vdev->irq);
+ ivpu_hw_irq_enable(vdev);
+ ivpu_ipc_enable(vdev);
+ return 0;
+}
+
+int ivpu_shutdown(struct ivpu_device *vdev)
+{
+ int ret;
+
+ ivpu_hw_irq_disable(vdev);
+ disable_irq(vdev->irq);
+ ivpu_ipc_disable(vdev);
+ ivpu_mmu_disable(vdev);
+
+ ret = ivpu_hw_power_down(vdev);
+ if (ret)
+ ivpu_warn(vdev, "Failed to power down HW: %d\n", ret);
+
+ return ret;
+}
+
+static const struct file_operations ivpu_fops = {
+ .owner = THIS_MODULE,
+ DRM_ACCEL_FOPS,
+};
+
+static const struct drm_driver driver = {
+ .driver_features = DRIVER_GEM | DRIVER_COMPUTE_ACCEL,
+
+ .open = ivpu_open,
+ .postclose = ivpu_postclose,
+ .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+ .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+ .gem_prime_import = ivpu_gem_prime_import,
+ .gem_prime_mmap = drm_gem_prime_mmap,
+
+ .ioctls = ivpu_drm_ioctls,
+ .num_ioctls = ARRAY_SIZE(ivpu_drm_ioctls),
+ .fops = &ivpu_fops,
+
+ .name = DRIVER_NAME,
+ .desc = DRIVER_DESC,
+ .date = DRIVER_DATE,
+ .major = DRM_IVPU_DRIVER_MAJOR,
+ .minor = DRM_IVPU_DRIVER_MINOR,
+};
+
+static int ivpu_irq_init(struct ivpu_device *vdev)
+{
+ struct pci_dev *pdev = to_pci_dev(vdev->drm.dev);
+ int ret;
+
+ ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI | PCI_IRQ_MSIX);
+ if (ret < 0) {
+ ivpu_err(vdev, "Failed to allocate a MSI IRQ: %d\n", ret);
+ return ret;
+ }
+
+ vdev->irq = pci_irq_vector(pdev, 0);
+
+ ret = devm_request_irq(vdev->drm.dev, vdev->irq, vdev->hw->ops->irq_handler,
+ IRQF_NO_AUTOEN, DRIVER_NAME, vdev);
+ if (ret)
+ ivpu_err(vdev, "Failed to request an IRQ %d\n", ret);
+
+ return ret;
+}
+
+static int ivpu_pci_init(struct ivpu_device *vdev)
+{
+ struct pci_dev *pdev = to_pci_dev(vdev->drm.dev);
+ struct resource *bar0 = &pdev->resource[0];
+ struct resource *bar4 = &pdev->resource[4];
+ int ret;
+
+ ivpu_dbg(vdev, MISC, "Mapping BAR0 (RegV) %pR\n", bar0);
+ vdev->regv = devm_ioremap_resource(vdev->drm.dev, bar0);
+ if (IS_ERR(vdev->regv)) {
+ ivpu_err(vdev, "Failed to map bar 0: %pe\n", vdev->regv);
+ return PTR_ERR(vdev->regv);
+ }
+
+ ivpu_dbg(vdev, MISC, "Mapping BAR4 (RegB) %pR\n", bar4);
+ vdev->regb = devm_ioremap_resource(vdev->drm.dev, bar4);
+ if (IS_ERR(vdev->regb)) {
+ ivpu_err(vdev, "Failed to map bar 4: %pe\n", vdev->regb);
+ return PTR_ERR(vdev->regb);
+ }
+
+ ret = dma_set_mask_and_coherent(vdev->drm.dev, DMA_BIT_MASK(38));
+ if (ret) {
+ ivpu_err(vdev, "Failed to set DMA mask: %d\n", ret);
+ return ret;
+ }
+ dma_set_max_seg_size(vdev->drm.dev, UINT_MAX);
+
+ /* Clear any pending errors */
+ pcie_capability_clear_word(pdev, PCI_EXP_DEVSTA, 0x3f);
+
+ ret = pcim_enable_device(pdev);
+ if (ret) {
+ ivpu_err(vdev, "Failed to enable PCI device: %d\n", ret);
+ return ret;
+ }
+
+ pci_set_master(pdev);
+
+ return 0;
+}
+
+static int ivpu_dev_init(struct ivpu_device *vdev)
+{
+ int ret;
+
+ vdev->hw = drmm_kzalloc(&vdev->drm, sizeof(*vdev->hw), GFP_KERNEL);
+ if (!vdev->hw)
+ return -ENOMEM;
+
+ vdev->mmu = drmm_kzalloc(&vdev->drm, sizeof(*vdev->mmu), GFP_KERNEL);
+ if (!vdev->mmu)
+ return -ENOMEM;
+
+ vdev->fw = drmm_kzalloc(&vdev->drm, sizeof(*vdev->fw), GFP_KERNEL);
+ if (!vdev->fw)
+ return -ENOMEM;
+
+ vdev->ipc = drmm_kzalloc(&vdev->drm, sizeof(*vdev->ipc), GFP_KERNEL);
+ if (!vdev->ipc)
+ return -ENOMEM;
+
+ vdev->pm = drmm_kzalloc(&vdev->drm, sizeof(*vdev->pm), GFP_KERNEL);
+ if (!vdev->pm)
+ return -ENOMEM;
+
+ vdev->hw->ops = &ivpu_hw_mtl_ops;
+ vdev->platform = IVPU_PLATFORM_INVALID;
+ vdev->context_xa_limit.min = IVPU_GLOBAL_CONTEXT_MMU_SSID + 1;
+ vdev->context_xa_limit.max = IVPU_CONTEXT_LIMIT;
+ atomic64_set(&vdev->unique_id_counter, 0);
+ xa_init_flags(&vdev->context_xa, XA_FLAGS_ALLOC);
+ xa_init_flags(&vdev->submitted_jobs_xa, XA_FLAGS_ALLOC1);
+ lockdep_set_class(&vdev->submitted_jobs_xa.xa_lock, &submitted_jobs_xa_lock_class_key);
+
+ ret = ivpu_pci_init(vdev);
+ if (ret) {
+ ivpu_err(vdev, "Failed to initialize PCI device: %d\n", ret);
+ goto err_xa_destroy;
+ }
+
+ ret = ivpu_irq_init(vdev);
+ if (ret) {
+ ivpu_err(vdev, "Failed to initialize IRQs: %d\n", ret);
+ goto err_xa_destroy;
+ }
+
+ /* Init basic HW info based on buttress registers which are accessible before power up */
+ ret = ivpu_hw_info_init(vdev);
+ if (ret) {
+ ivpu_err(vdev, "Failed to initialize HW info: %d\n", ret);
+ goto err_xa_destroy;
+ }
+
+ /* Power up early so the rest of init code can access VPU registers */
+ ret = ivpu_hw_power_up(vdev);
+ if (ret) {
+ ivpu_err(vdev, "Failed to power up HW: %d\n", ret);
+ goto err_xa_destroy;
+ }
+
+ ret = ivpu_mmu_global_context_init(vdev);
+ if (ret) {
+ ivpu_err(vdev, "Failed to initialize global MMU context: %d\n", ret);
+ goto err_power_down;
+ }
+
+ ret = ivpu_mmu_init(vdev);
+ if (ret) {
+ ivpu_err(vdev, "Failed to initialize MMU device: %d\n", ret);
+ goto err_mmu_gctx_fini;
+ }
+
+ ret = ivpu_fw_init(vdev);
+ if (ret) {
+ ivpu_err(vdev, "Failed to initialize firmware: %d\n", ret);
+ goto err_mmu_gctx_fini;
+ }
+
+ ret = ivpu_ipc_init(vdev);
+ if (ret) {
+ ivpu_err(vdev, "Failed to initialize IPC: %d\n", ret);
+ goto err_fw_fini;
+ }
+
+ ret = ivpu_pm_init(vdev);
+ if (ret) {
+ ivpu_err(vdev, "Failed to initialize PM: %d\n", ret);
+ goto err_ipc_fini;
+ }
+
+ ret = ivpu_job_done_thread_init(vdev);
+ if (ret) {
+ ivpu_err(vdev, "Failed to initialize job done thread: %d\n", ret);
+ goto err_ipc_fini;
+ }
+
+ ret = ivpu_fw_load(vdev);
+ if (ret) {
+ ivpu_err(vdev, "Failed to load firmware: %d\n", ret);
+ goto err_job_done_thread_fini;
+ }
+
+ ret = ivpu_boot(vdev);
+ if (ret) {
+ ivpu_err(vdev, "Failed to boot: %d\n", ret);
+ goto err_job_done_thread_fini;
+ }
+
+ ivpu_pm_enable(vdev);
+
+ return 0;
+
+err_job_done_thread_fini:
+ ivpu_job_done_thread_fini(vdev);
+err_ipc_fini:
+ ivpu_ipc_fini(vdev);
+err_fw_fini:
+ ivpu_fw_fini(vdev);
+err_mmu_gctx_fini:
+ ivpu_mmu_global_context_fini(vdev);
+err_power_down:
+ ivpu_hw_power_down(vdev);
+err_xa_destroy:
+ xa_destroy(&vdev->submitted_jobs_xa);
+ xa_destroy(&vdev->context_xa);
+ return ret;
+}
+
+static void ivpu_dev_fini(struct ivpu_device *vdev)
+{
+ ivpu_pm_disable(vdev);
+ ivpu_shutdown(vdev);
+ ivpu_job_done_thread_fini(vdev);
+ ivpu_ipc_fini(vdev);
+ ivpu_fw_fini(vdev);
+ ivpu_mmu_global_context_fini(vdev);
+
+ drm_WARN_ON(&vdev->drm, !xa_empty(&vdev->submitted_jobs_xa));
+ xa_destroy(&vdev->submitted_jobs_xa);
+ drm_WARN_ON(&vdev->drm, !xa_empty(&vdev->context_xa));
+ xa_destroy(&vdev->context_xa);
+}
+
+static struct pci_device_id ivpu_pci_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_MTL) },
+ { }
+};
+MODULE_DEVICE_TABLE(pci, ivpu_pci_ids);
+
+static int ivpu_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct ivpu_device *vdev;
+ int ret;
+
+ vdev = devm_drm_dev_alloc(&pdev->dev, &driver, struct ivpu_device, drm);
+ if (IS_ERR(vdev))
+ return PTR_ERR(vdev);
+
+ pci_set_drvdata(pdev, vdev);
+
+ ret = ivpu_dev_init(vdev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to initialize VPU device: %d\n", ret);
+ return ret;
+ }
+
+ ret = drm_dev_register(&vdev->drm, 0);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register DRM device: %d\n", ret);
+ ivpu_dev_fini(vdev);
+ }
+
+ return ret;
+}
+
+static void ivpu_remove(struct pci_dev *pdev)
+{
+ struct ivpu_device *vdev = pci_get_drvdata(pdev);
+
+ drm_dev_unregister(&vdev->drm);
+ ivpu_dev_fini(vdev);
+}
+
+static const struct dev_pm_ops ivpu_drv_pci_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(ivpu_pm_suspend_cb, ivpu_pm_resume_cb)
+ SET_RUNTIME_PM_OPS(ivpu_pm_runtime_suspend_cb, ivpu_pm_runtime_resume_cb, NULL)
+};
+
+static const struct pci_error_handlers ivpu_drv_pci_err = {
+ .reset_prepare = ivpu_pm_reset_prepare_cb,
+ .reset_done = ivpu_pm_reset_done_cb,
+};
+
+static struct pci_driver ivpu_pci_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = ivpu_pci_ids,
+ .probe = ivpu_probe,
+ .remove = ivpu_remove,
+ .driver = {
+ .pm = &ivpu_drv_pci_pm,
+ },
+ .err_handler = &ivpu_drv_pci_err,
+};
+
+module_pci_driver(ivpu_pci_driver);
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL and additional rights");
+MODULE_VERSION(DRIVER_VERSION_STR);
diff --git a/drivers/accel/ivpu/ivpu_drv.h b/drivers/accel/ivpu/ivpu_drv.h
new file mode 100644
index 000000000000..f47b4965db2e
--- /dev/null
+++ b/drivers/accel/ivpu/ivpu_drv.h
@@ -0,0 +1,190 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2020-2023 Intel Corporation
+ */
+
+#ifndef __IVPU_DRV_H__
+#define __IVPU_DRV_H__
+
+#include <drm/drm_device.h>
+#include <drm/drm_managed.h>
+#include <drm/drm_mm.h>
+#include <drm/drm_print.h>
+
+#include <linux/pci.h>
+#include <linux/xarray.h>
+#include <uapi/drm/ivpu_accel.h>
+
+#include "ivpu_mmu_context.h"
+
+#define DRIVER_NAME "intel_vpu"
+#define DRIVER_DESC "Driver for Intel Versatile Processing Unit (VPU)"
+#define DRIVER_DATE "20230117"
+
+#define PCI_DEVICE_ID_MTL 0x7d1d
+
+#define IVPU_GLOBAL_CONTEXT_MMU_SSID 0
+#define IVPU_CONTEXT_LIMIT 64
+#define IVPU_NUM_ENGINES 2
+
+#define IVPU_PLATFORM_SILICON 0
+#define IVPU_PLATFORM_SIMICS 2
+#define IVPU_PLATFORM_FPGA 3
+#define IVPU_PLATFORM_INVALID 8
+
+#define IVPU_DBG_REG BIT(0)
+#define IVPU_DBG_IRQ BIT(1)
+#define IVPU_DBG_MMU BIT(2)
+#define IVPU_DBG_FILE BIT(3)
+#define IVPU_DBG_MISC BIT(4)
+#define IVPU_DBG_FW_BOOT BIT(5)
+#define IVPU_DBG_PM BIT(6)
+#define IVPU_DBG_IPC BIT(7)
+#define IVPU_DBG_BO BIT(8)
+#define IVPU_DBG_JOB BIT(9)
+#define IVPU_DBG_JSM BIT(10)
+#define IVPU_DBG_KREF BIT(11)
+#define IVPU_DBG_RPM BIT(12)
+
+#define ivpu_err(vdev, fmt, ...) \
+ drm_err(&(vdev)->drm, "%s(): " fmt, __func__, ##__VA_ARGS__)
+
+#define ivpu_err_ratelimited(vdev, fmt, ...) \
+ drm_err_ratelimited(&(vdev)->drm, "%s(): " fmt, __func__, ##__VA_ARGS__)
+
+#define ivpu_warn(vdev, fmt, ...) \
+ drm_warn(&(vdev)->drm, "%s(): " fmt, __func__, ##__VA_ARGS__)
+
+#define ivpu_warn_ratelimited(vdev, fmt, ...) \
+ drm_err_ratelimited(&(vdev)->drm, "%s(): " fmt, __func__, ##__VA_ARGS__)
+
+#define ivpu_info(vdev, fmt, ...) drm_info(&(vdev)->drm, fmt, ##__VA_ARGS__)
+
+#define ivpu_dbg(vdev, type, fmt, args...) do { \
+ if (unlikely(IVPU_DBG_##type & ivpu_dbg_mask)) \
+ dev_dbg((vdev)->drm.dev, "[%s] " fmt, #type, ##args); \
+} while (0)
+
+#define IVPU_WA(wa_name) (vdev->wa.wa_name)
+
+struct ivpu_wa_table {
+ bool punit_disabled;
+ bool clear_runtime_mem;
+};
+
+struct ivpu_hw_info;
+struct ivpu_mmu_info;
+struct ivpu_fw_info;
+struct ivpu_ipc_info;
+struct ivpu_pm_info;
+
+struct ivpu_device {
+ struct drm_device drm;
+ void __iomem *regb;
+ void __iomem *regv;
+ u32 platform;
+ u32 irq;
+
+ struct ivpu_wa_table wa;
+ struct ivpu_hw_info *hw;
+ struct ivpu_mmu_info *mmu;
+ struct ivpu_fw_info *fw;
+ struct ivpu_ipc_info *ipc;
+ struct ivpu_pm_info *pm;
+
+ struct ivpu_mmu_context gctx;
+ struct xarray context_xa;
+ struct xa_limit context_xa_limit;
+
+ struct xarray submitted_jobs_xa;
+ struct task_struct *job_done_thread;
+
+ atomic64_t unique_id_counter;
+
+ struct {
+ int boot;
+ int jsm;
+ int tdr;
+ int reschedule_suspend;
+ } timeout;
+};
+
+/*
+ * file_priv has its own refcount (ref) that allows user space to close the fd
+ * without blocking even if VPU is still processing some jobs.
+ */
+struct ivpu_file_priv {
+ struct kref ref;
+ struct ivpu_device *vdev;
+ struct mutex lock; /* Protects cmdq */
+ struct ivpu_cmdq *cmdq[IVPU_NUM_ENGINES];
+ struct ivpu_mmu_context ctx;
+ u32 priority;
+ bool has_mmu_faults;
+};
+
+extern int ivpu_dbg_mask;
+extern u8 ivpu_pll_min_ratio;
+extern u8 ivpu_pll_max_ratio;
+
+#define IVPU_TEST_MODE_DISABLED 0
+#define IVPU_TEST_MODE_FW_TEST 1
+#define IVPU_TEST_MODE_NULL_HW 2
+extern int ivpu_test_mode;
+
+struct ivpu_file_priv *ivpu_file_priv_get(struct ivpu_file_priv *file_priv);
+struct ivpu_file_priv *ivpu_file_priv_get_by_ctx_id(struct ivpu_device *vdev, unsigned long id);
+void ivpu_file_priv_put(struct ivpu_file_priv **link);
+
+int ivpu_boot(struct ivpu_device *vdev);
+int ivpu_shutdown(struct ivpu_device *vdev);
+
+static inline bool ivpu_is_mtl(struct ivpu_device *vdev)
+{
+ return to_pci_dev(vdev->drm.dev)->device == PCI_DEVICE_ID_MTL;
+}
+
+static inline u8 ivpu_revision(struct ivpu_device *vdev)
+{
+ return to_pci_dev(vdev->drm.dev)->revision;
+}
+
+static inline u16 ivpu_device_id(struct ivpu_device *vdev)
+{
+ return to_pci_dev(vdev->drm.dev)->device;
+}
+
+static inline struct ivpu_device *to_ivpu_device(struct drm_device *dev)
+{
+ return container_of(dev, struct ivpu_device, drm);
+}
+
+static inline u32 ivpu_get_context_count(struct ivpu_device *vdev)
+{
+ struct xa_limit ctx_limit = vdev->context_xa_limit;
+
+ return (ctx_limit.max - ctx_limit.min + 1);
+}
+
+static inline u32 ivpu_get_platform(struct ivpu_device *vdev)
+{
+ WARN_ON_ONCE(vdev->platform == IVPU_PLATFORM_INVALID);
+ return vdev->platform;
+}
+
+static inline bool ivpu_is_silicon(struct ivpu_device *vdev)
+{
+ return ivpu_get_platform(vdev) == IVPU_PLATFORM_SILICON;
+}
+
+static inline bool ivpu_is_simics(struct ivpu_device *vdev)
+{
+ return ivpu_get_platform(vdev) == IVPU_PLATFORM_SIMICS;
+}
+
+static inline bool ivpu_is_fpga(struct ivpu_device *vdev)
+{
+ return ivpu_get_platform(vdev) == IVPU_PLATFORM_FPGA;
+}
+
+#endif /* __IVPU_DRV_H__ */
diff --git a/drivers/accel/ivpu/ivpu_fw.c b/drivers/accel/ivpu/ivpu_fw.c
new file mode 100644
index 000000000000..f58951a0d81b
--- /dev/null
+++ b/drivers/accel/ivpu/ivpu_fw.c
@@ -0,0 +1,434 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2020-2023 Intel Corporation
+ */
+
+#include <linux/firmware.h>
+#include <linux/highmem.h>
+#include <linux/moduleparam.h>
+#include <linux/pci.h>
+
+#include "vpu_boot_api.h"
+#include "ivpu_drv.h"
+#include "ivpu_fw.h"
+#include "ivpu_gem.h"
+#include "ivpu_hw.h"
+#include "ivpu_ipc.h"
+#include "ivpu_pm.h"
+
+#define FW_GLOBAL_MEM_START (2ull * SZ_1G)
+#define FW_GLOBAL_MEM_END (3ull * SZ_1G)
+#define FW_SHARED_MEM_SIZE SZ_256M /* Must be aligned to FW_SHARED_MEM_ALIGNMENT */
+#define FW_SHARED_MEM_ALIGNMENT SZ_128K /* VPU MTRR limitation */
+#define FW_RUNTIME_MAX_SIZE SZ_512M
+#define FW_SHAVE_NN_MAX_SIZE SZ_2M
+#define FW_RUNTIME_MIN_ADDR (FW_GLOBAL_MEM_START)
+#define FW_RUNTIME_MAX_ADDR (FW_GLOBAL_MEM_END - FW_SHARED_MEM_SIZE)
+#define FW_VERSION_HEADER_SIZE SZ_4K
+#define FW_FILE_IMAGE_OFFSET (VPU_FW_HEADER_SIZE + FW_VERSION_HEADER_SIZE)
+
+#define WATCHDOG_MSS_REDIRECT 32
+#define WATCHDOG_NCE_REDIRECT 33
+
+#define ADDR_TO_L2_CACHE_CFG(addr) ((addr) >> 31)
+
+#define IVPU_FW_CHECK_API(vdev, fw_hdr, name, min_major) \
+ ivpu_fw_check_api(vdev, fw_hdr, #name, \
+ VPU_##name##_API_VER_INDEX, \
+ VPU_##name##_API_VER_MAJOR, \
+ VPU_##name##_API_VER_MINOR, min_major)
+
+static char *ivpu_firmware;
+module_param_named_unsafe(firmware, ivpu_firmware, charp, 0644);
+MODULE_PARM_DESC(firmware, "VPU firmware binary in /lib/firmware/..");
+
+static int ivpu_fw_request(struct ivpu_device *vdev)
+{
+ static const char * const fw_names[] = {
+ "mtl_vpu.bin",
+ "intel/vpu/mtl_vpu_v0.0.bin"
+ };
+ int ret = -ENOENT;
+ int i;
+
+ if (ivpu_firmware)
+ return request_firmware(&vdev->fw->file, ivpu_firmware, vdev->drm.dev);
+
+ for (i = 0; i < ARRAY_SIZE(fw_names); i++) {
+ ret = firmware_request_nowarn(&vdev->fw->file, fw_names[i], vdev->drm.dev);
+ if (!ret)
+ return 0;
+ }
+
+ ivpu_err(vdev, "Failed to request firmware: %d\n", ret);
+ return ret;
+}
+
+static int
+ivpu_fw_check_api(struct ivpu_device *vdev, const struct vpu_firmware_header *fw_hdr,
+ const char *str, int index, u16 expected_major, u16 expected_minor,
+ u16 min_major)
+{
+ u16 major = (u16)(fw_hdr->api_version[index] >> 16);
+ u16 minor = (u16)(fw_hdr->api_version[index]);
+
+ if (major < min_major) {
+ ivpu_err(vdev, "Incompatible FW %s API version: %d.%d, required %d.0 or later\n",
+ str, major, minor, min_major);
+ return -EINVAL;
+ }
+ if (major != expected_major) {
+ ivpu_warn(vdev, "Major FW %s API version different: %d.%d (expected %d.%d)\n",
+ str, major, minor, expected_major, expected_minor);
+ }
+ ivpu_dbg(vdev, FW_BOOT, "FW %s API version: %d.%d (expected %d.%d)\n",
+ str, major, minor, expected_major, expected_minor);
+
+ return 0;
+}
+
+static int ivpu_fw_parse(struct ivpu_device *vdev)
+{
+ struct ivpu_fw_info *fw = vdev->fw;
+ const struct vpu_firmware_header *fw_hdr = (const void *)fw->file->data;
+ u64 runtime_addr, image_load_addr, runtime_size, image_size;
+
+ if (fw->file->size <= FW_FILE_IMAGE_OFFSET) {
+ ivpu_err(vdev, "Firmware file is too small: %zu\n", fw->file->size);
+ return -EINVAL;
+ }
+
+ if (fw_hdr->header_version != VPU_FW_HEADER_VERSION) {
+ ivpu_err(vdev, "Invalid firmware header version: %u\n", fw_hdr->header_version);
+ return -EINVAL;
+ }
+
+ runtime_addr = fw_hdr->boot_params_load_address;
+ runtime_size = fw_hdr->runtime_size;
+ image_load_addr = fw_hdr->image_load_address;
+ image_size = fw_hdr->image_size;
+
+ if (runtime_addr < FW_RUNTIME_MIN_ADDR || runtime_addr > FW_RUNTIME_MAX_ADDR) {
+ ivpu_err(vdev, "Invalid firmware runtime address: 0x%llx\n", runtime_addr);
+ return -EINVAL;
+ }
+
+ if (runtime_size < fw->file->size || runtime_size > FW_RUNTIME_MAX_SIZE) {
+ ivpu_err(vdev, "Invalid firmware runtime size: %llu\n", runtime_size);
+ return -EINVAL;
+ }
+
+ if (FW_FILE_IMAGE_OFFSET + image_size > fw->file->size) {
+ ivpu_err(vdev, "Invalid image size: %llu\n", image_size);
+ return -EINVAL;
+ }
+
+ if (image_load_addr < runtime_addr ||
+ image_load_addr + image_size > runtime_addr + runtime_size) {
+ ivpu_err(vdev, "Invalid firmware load address size: 0x%llx and size %llu\n",
+ image_load_addr, image_size);
+ return -EINVAL;
+ }
+
+ if (fw_hdr->shave_nn_fw_size > FW_SHAVE_NN_MAX_SIZE) {
+ ivpu_err(vdev, "SHAVE NN firmware is too big: %u\n", fw_hdr->shave_nn_fw_size);
+ return -EINVAL;
+ }
+
+ if (fw_hdr->entry_point < image_load_addr ||
+ fw_hdr->entry_point >= image_load_addr + image_size) {
+ ivpu_err(vdev, "Invalid entry point: 0x%llx\n", fw_hdr->entry_point);
+ return -EINVAL;
+ }
+ ivpu_dbg(vdev, FW_BOOT, "Header version: 0x%x, format 0x%x\n",
+ fw_hdr->header_version, fw_hdr->image_format);
+ ivpu_dbg(vdev, FW_BOOT, "FW version: %s\n", (char *)fw_hdr + VPU_FW_HEADER_SIZE);
+
+ if (IVPU_FW_CHECK_API(vdev, fw_hdr, BOOT, 3))
+ return -EINVAL;
+ if (IVPU_FW_CHECK_API(vdev, fw_hdr, JSM, 3))
+ return -EINVAL;
+
+ fw->runtime_addr = runtime_addr;
+ fw->runtime_size = runtime_size;
+ fw->image_load_offset = image_load_addr - runtime_addr;
+ fw->image_size = image_size;
+ fw->shave_nn_size = PAGE_ALIGN(fw_hdr->shave_nn_fw_size);
+
+ fw->cold_boot_entry_point = fw_hdr->entry_point;
+ fw->entry_point = fw->cold_boot_entry_point;
+
+ ivpu_dbg(vdev, FW_BOOT, "Size: file %lu image %u runtime %u shavenn %u\n",
+ fw->file->size, fw->image_size, fw->runtime_size, fw->shave_nn_size);
+ ivpu_dbg(vdev, FW_BOOT, "Address: runtime 0x%llx, load 0x%llx, entry point 0x%llx\n",
+ fw->runtime_addr, image_load_addr, fw->entry_point);
+
+ return 0;
+}
+
+static void ivpu_fw_release(struct ivpu_device *vdev)
+{
+ release_firmware(vdev->fw->file);
+}
+
+static int ivpu_fw_update_global_range(struct ivpu_device *vdev)
+{
+ struct ivpu_fw_info *fw = vdev->fw;
+ u64 start = ALIGN(fw->runtime_addr + fw->runtime_size, FW_SHARED_MEM_ALIGNMENT);
+ u64 size = FW_SHARED_MEM_SIZE;
+
+ if (start + size > FW_GLOBAL_MEM_END) {
+ ivpu_err(vdev, "No space for shared region, start %lld, size %lld\n", start, size);
+ return -EINVAL;
+ }
+
+ ivpu_hw_init_range(&vdev->hw->ranges.global_low, start, size);
+ return 0;
+}
+
+static int ivpu_fw_mem_init(struct ivpu_device *vdev)
+{
+ struct ivpu_fw_info *fw = vdev->fw;
+ int ret;
+
+ ret = ivpu_fw_update_global_range(vdev);
+ if (ret)
+ return ret;
+
+ fw->mem = ivpu_bo_alloc_internal(vdev, fw->runtime_addr, fw->runtime_size, DRM_IVPU_BO_WC);
+ if (!fw->mem) {
+ ivpu_err(vdev, "Failed to allocate firmware runtime memory\n");
+ return -ENOMEM;
+ }
+
+ if (fw->shave_nn_size) {
+ fw->mem_shave_nn = ivpu_bo_alloc_internal(vdev, vdev->hw->ranges.global_high.start,
+ fw->shave_nn_size, DRM_IVPU_BO_UNCACHED);
+ if (!fw->mem_shave_nn) {
+ ivpu_err(vdev, "Failed to allocate shavenn buffer\n");
+ ivpu_bo_free_internal(fw->mem);
+ return -ENOMEM;
+ }
+ }
+
+ return 0;
+}
+
+static void ivpu_fw_mem_fini(struct ivpu_device *vdev)
+{
+ struct ivpu_fw_info *fw = vdev->fw;
+
+ if (fw->mem_shave_nn) {
+ ivpu_bo_free_internal(fw->mem_shave_nn);
+ fw->mem_shave_nn = NULL;
+ }
+
+ ivpu_bo_free_internal(fw->mem);
+ fw->mem = NULL;
+}
+
+int ivpu_fw_init(struct ivpu_device *vdev)
+{
+ int ret;
+
+ ret = ivpu_fw_request(vdev);
+ if (ret)
+ return ret;
+
+ ret = ivpu_fw_parse(vdev);
+ if (ret)
+ goto err_fw_release;
+
+ ret = ivpu_fw_mem_init(vdev);
+ if (ret)
+ goto err_fw_release;
+
+ return 0;
+
+err_fw_release:
+ ivpu_fw_release(vdev);
+ return ret;
+}
+
+void ivpu_fw_fini(struct ivpu_device *vdev)
+{
+ ivpu_fw_mem_fini(vdev);
+ ivpu_fw_release(vdev);
+}
+
+int ivpu_fw_load(struct ivpu_device *vdev)
+{
+ struct ivpu_fw_info *fw = vdev->fw;
+ u64 image_end_offset = fw->image_load_offset + fw->image_size;
+
+ memset(fw->mem->kvaddr, 0, fw->image_load_offset);
+ memcpy(fw->mem->kvaddr + fw->image_load_offset,
+ fw->file->data + FW_FILE_IMAGE_OFFSET, fw->image_size);
+
+ if (IVPU_WA(clear_runtime_mem)) {
+ u8 *start = fw->mem->kvaddr + image_end_offset;
+ u64 size = fw->mem->base.size - image_end_offset;
+
+ memset(start, 0, size);
+ }
+
+ wmb(); /* Flush WC buffers after writing fw->mem */
+
+ return 0;
+}
+
+static void ivpu_fw_boot_params_print(struct ivpu_device *vdev, struct vpu_boot_params *boot_params)
+{
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.magic = 0x%x\n",
+ boot_params->magic);
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.vpu_id = 0x%x\n",
+ boot_params->vpu_id);
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.vpu_count = 0x%x\n",
+ boot_params->vpu_count);
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.frequency = %u\n",
+ boot_params->frequency);
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.perf_clk_frequency = %u\n",
+ boot_params->perf_clk_frequency);
+
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.ipc_header_area_start = 0x%llx\n",
+ boot_params->ipc_header_area_start);
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.ipc_header_area_size = 0x%x\n",
+ boot_params->ipc_header_area_size);
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.shared_region_base = 0x%llx\n",
+ boot_params->shared_region_base);
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.shared_region_size = 0x%x\n",
+ boot_params->shared_region_size);
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.ipc_payload_area_start = 0x%llx\n",
+ boot_params->ipc_payload_area_start);
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.ipc_payload_area_size = 0x%x\n",
+ boot_params->ipc_payload_area_size);
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.global_aliased_pio_base = 0x%llx\n",
+ boot_params->global_aliased_pio_base);
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.global_aliased_pio_size = 0x%x\n",
+ boot_params->global_aliased_pio_size);
+
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.autoconfig = 0x%x\n",
+ boot_params->autoconfig);
+
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.cache_defaults[VPU_BOOT_L2_CACHE_CFG_NN].use = 0x%x\n",
+ boot_params->cache_defaults[VPU_BOOT_L2_CACHE_CFG_NN].use);
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.cache_defaults[VPU_BOOT_L2_CACHE_CFG_NN].cfg = 0x%x\n",
+ boot_params->cache_defaults[VPU_BOOT_L2_CACHE_CFG_NN].cfg);
+
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.global_memory_allocator_base = 0x%llx\n",
+ boot_params->global_memory_allocator_base);
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.global_memory_allocator_size = 0x%x\n",
+ boot_params->global_memory_allocator_size);
+
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.shave_nn_fw_base = 0x%llx\n",
+ boot_params->shave_nn_fw_base);
+
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.watchdog_irq_mss = 0x%x\n",
+ boot_params->watchdog_irq_mss);
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.watchdog_irq_nce = 0x%x\n",
+ boot_params->watchdog_irq_nce);
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.host_to_vpu_irq = 0x%x\n",
+ boot_params->host_to_vpu_irq);
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.job_done_irq = 0x%x\n",
+ boot_params->job_done_irq);
+
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.host_version_id = 0x%x\n",
+ boot_params->host_version_id);
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.si_stepping = 0x%x\n",
+ boot_params->si_stepping);
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.device_id = 0x%llx\n",
+ boot_params->device_id);
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.feature_exclusion = 0x%llx\n",
+ boot_params->feature_exclusion);
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.sku = 0x%llx\n",
+ boot_params->sku);
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.min_freq_pll_ratio = 0x%x\n",
+ boot_params->min_freq_pll_ratio);
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.pn_freq_pll_ratio = 0x%x\n",
+ boot_params->pn_freq_pll_ratio);
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.max_freq_pll_ratio = 0x%x\n",
+ boot_params->max_freq_pll_ratio);
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.default_trace_level = 0x%x\n",
+ boot_params->default_trace_level);
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.tracing_buff_message_format_mask = 0x%llx\n",
+ boot_params->tracing_buff_message_format_mask);
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.trace_destination_mask = 0x%x\n",
+ boot_params->trace_destination_mask);
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.trace_hw_component_mask = 0x%llx\n",
+ boot_params->trace_hw_component_mask);
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.boot_type = 0x%x\n",
+ boot_params->boot_type);
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.punit_telemetry_sram_base = 0x%llx\n",
+ boot_params->punit_telemetry_sram_base);
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.punit_telemetry_sram_size = 0x%llx\n",
+ boot_params->punit_telemetry_sram_size);
+ ivpu_dbg(vdev, FW_BOOT, "boot_params.vpu_telemetry_enable = 0x%x\n",
+ boot_params->vpu_telemetry_enable);
+}
+
+void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params *boot_params)
+{
+ struct ivpu_bo *ipc_mem_rx = vdev->ipc->mem_rx;
+
+ /* In case of warm boot we only have to reset the entrypoint addr */
+ if (!ivpu_fw_is_cold_boot(vdev)) {
+ boot_params->save_restore_ret_address = 0;
+ vdev->pm->is_warmboot = true;
+ return;
+ }
+
+ vdev->pm->is_warmboot = false;
+
+ boot_params->magic = VPU_BOOT_PARAMS_MAGIC;
+ boot_params->vpu_id = to_pci_dev(vdev->drm.dev)->bus->number;
+ boot_params->frequency = ivpu_hw_reg_pll_freq_get(vdev);
+
+ /*
+ * Uncached region of VPU address space, covers IPC buffers, job queues
+ * and log buffers, programmable to L2$ Uncached by VPU MTRR
+ */
+ boot_params->shared_region_base = vdev->hw->ranges.global_low.start;
+ boot_params->shared_region_size = vdev->hw->ranges.global_low.end -
+ vdev->hw->ranges.global_low.start;
+
+ boot_params->ipc_header_area_start = ipc_mem_rx->vpu_addr;
+ boot_params->ipc_header_area_size = ipc_mem_rx->base.size / 2;
+
+ boot_params->ipc_payload_area_start = ipc_mem_rx->vpu_addr + ipc_mem_rx->base.size / 2;
+ boot_params->ipc_payload_area_size = ipc_mem_rx->base.size / 2;
+
+ boot_params->global_aliased_pio_base =
+ vdev->hw->ranges.global_aliased_pio.start;
+ boot_params->global_aliased_pio_size =
+ ivpu_hw_range_size(&vdev->hw->ranges.global_aliased_pio);
+
+ /* Allow configuration for L2C_PAGE_TABLE with boot param value */
+ boot_params->autoconfig = 1;
+
+ /* Enable L2 cache for first 2GB of high memory */
+ boot_params->cache_defaults[VPU_BOOT_L2_CACHE_CFG_NN].use = 1;
+ boot_params->cache_defaults[VPU_BOOT_L2_CACHE_CFG_NN].cfg =
+ ADDR_TO_L2_CACHE_CFG(vdev->hw->ranges.global_high.start);
+
+ if (vdev->fw->mem_shave_nn)
+ boot_params->shave_nn_fw_base = vdev->fw->mem_shave_nn->vpu_addr;
+
+ boot_params->watchdog_irq_mss = WATCHDOG_MSS_REDIRECT;
+ boot_params->watchdog_irq_nce = WATCHDOG_NCE_REDIRECT;
+ boot_params->si_stepping = ivpu_revision(vdev);
+ boot_params->device_id = ivpu_device_id(vdev);
+ boot_params->feature_exclusion = vdev->hw->tile_fuse;
+ boot_params->sku = vdev->hw->sku;
+
+ boot_params->min_freq_pll_ratio = vdev->hw->pll.min_ratio;
+ boot_params->pn_freq_pll_ratio = vdev->hw->pll.pn_ratio;
+ boot_params->max_freq_pll_ratio = vdev->hw->pll.max_ratio;
+
+ boot_params->punit_telemetry_sram_base = ivpu_hw_reg_telemetry_offset_get(vdev);
+ boot_params->punit_telemetry_sram_size = ivpu_hw_reg_telemetry_size_get(vdev);
+ boot_params->vpu_telemetry_enable = ivpu_hw_reg_telemetry_enable_get(vdev);
+
+ wmb(); /* Flush WC buffers after writing bootparams */
+
+ ivpu_fw_boot_params_print(vdev, boot_params);
+}
diff --git a/drivers/accel/ivpu/ivpu_fw.h b/drivers/accel/ivpu/ivpu_fw.h
new file mode 100644
index 000000000000..8d275c802d1c
--- /dev/null
+++ b/drivers/accel/ivpu/ivpu_fw.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2020-2023 Intel Corporation
+ */
+
+#ifndef __IVPU_FW_H__
+#define __IVPU_FW_H__
+
+struct ivpu_device;
+struct ivpu_bo;
+struct vpu_boot_params;
+
+struct ivpu_fw_info {
+ const struct firmware *file;
+ struct ivpu_bo *mem;
+ struct ivpu_bo *mem_shave_nn;
+ struct ivpu_bo *mem_log_crit;
+ struct ivpu_bo *mem_log_verb;
+ u64 runtime_addr;
+ u32 runtime_size;
+ u64 image_load_offset;
+ u32 image_size;
+ u32 shave_nn_size;
+ u64 entry_point; /* Cold or warm boot entry point for next boot */
+ u64 cold_boot_entry_point;
+};
+
+int ivpu_fw_init(struct ivpu_device *vdev);
+void ivpu_fw_fini(struct ivpu_device *vdev);
+int ivpu_fw_load(struct ivpu_device *vdev);
+void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params *bp);
+
+static inline bool ivpu_fw_is_cold_boot(struct ivpu_device *vdev)
+{
+ return vdev->fw->entry_point == vdev->fw->cold_boot_entry_point;
+}
+
+#endif /* __IVPU_FW_H__ */
diff --git a/drivers/accel/ivpu/ivpu_gem.c b/drivers/accel/ivpu/ivpu_gem.c
new file mode 100644
index 000000000000..52b339aefadc
--- /dev/null
+++ b/drivers/accel/ivpu/ivpu_gem.c
@@ -0,0 +1,749 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2020-2023 Intel Corporation
+ */
+
+#include <linux/dma-buf.h>
+#include <linux/highmem.h>
+#include <linux/module.h>
+#include <linux/set_memory.h>
+#include <linux/xarray.h>
+
+#include <drm/drm_cache.h>
+#include <drm/drm_debugfs.h>
+#include <drm/drm_file.h>
+#include <drm/drm_utils.h>
+
+#include "ivpu_drv.h"
+#include "ivpu_gem.h"
+#include "ivpu_hw.h"
+#include "ivpu_mmu.h"
+#include "ivpu_mmu_context.h"
+
+MODULE_IMPORT_NS(DMA_BUF);
+
+static const struct drm_gem_object_funcs ivpu_gem_funcs;
+
+static struct lock_class_key prime_bo_lock_class_key;
+
+static int __must_check prime_alloc_pages_locked(struct ivpu_bo *bo)
+{
+ /* Pages are managed by the underlying dma-buf */
+ return 0;
+}
+
+static void prime_free_pages_locked(struct ivpu_bo *bo)
+{
+ /* Pages are managed by the underlying dma-buf */
+}
+
+static int prime_map_pages_locked(struct ivpu_bo *bo)
+{
+ struct ivpu_device *vdev = ivpu_bo_to_vdev(bo);
+ struct sg_table *sgt;
+
+ sgt = dma_buf_map_attachment_unlocked(bo->base.import_attach, DMA_BIDIRECTIONAL);
+ if (IS_ERR(sgt)) {
+ ivpu_err(vdev, "Failed to map attachment: %ld\n", PTR_ERR(sgt));
+ return PTR_ERR(sgt);
+ }
+
+ bo->sgt = sgt;
+ return 0;
+}
+
+static void prime_unmap_pages_locked(struct ivpu_bo *bo)
+{
+ dma_buf_unmap_attachment_unlocked(bo->base.import_attach, bo->sgt, DMA_BIDIRECTIONAL);
+ bo->sgt = NULL;
+}
+
+static const struct ivpu_bo_ops prime_ops = {
+ .type = IVPU_BO_TYPE_PRIME,
+ .name = "prime",
+ .alloc_pages = prime_alloc_pages_locked,
+ .free_pages = prime_free_pages_locked,
+ .map_pages = prime_map_pages_locked,
+ .unmap_pages = prime_unmap_pages_locked,
+};
+
+static int __must_check shmem_alloc_pages_locked(struct ivpu_bo *bo)
+{
+ int npages = bo->base.size >> PAGE_SHIFT;
+ struct page **pages;
+
+ pages = drm_gem_get_pages(&bo->base);
+ if (IS_ERR(pages))
+ return PTR_ERR(pages);
+
+ if (bo->flags & DRM_IVPU_BO_WC)
+ set_pages_array_wc(pages, npages);
+ else if (bo->flags & DRM_IVPU_BO_UNCACHED)
+ set_pages_array_uc(pages, npages);
+
+ bo->pages = pages;
+ return 0;
+}
+
+static void shmem_free_pages_locked(struct ivpu_bo *bo)
+{
+ if (ivpu_bo_cache_mode(bo) != DRM_IVPU_BO_CACHED)
+ set_pages_array_wb(bo->pages, bo->base.size >> PAGE_SHIFT);
+
+ drm_gem_put_pages(&bo->base, bo->pages, true, false);
+ bo->pages = NULL;
+}
+
+static int ivpu_bo_map_pages_locked(struct ivpu_bo *bo)
+{
+ int npages = bo->base.size >> PAGE_SHIFT;
+ struct ivpu_device *vdev = ivpu_bo_to_vdev(bo);
+ struct sg_table *sgt;
+ int ret;
+
+ sgt = drm_prime_pages_to_sg(&vdev->drm, bo->pages, npages);
+ if (IS_ERR(sgt)) {
+ ivpu_err(vdev, "Failed to allocate sgtable\n");
+ return PTR_ERR(sgt);
+ }
+
+ ret = dma_map_sgtable(vdev->drm.dev, sgt, DMA_BIDIRECTIONAL, 0);
+ if (ret) {
+ ivpu_err(vdev, "Failed to map BO in IOMMU: %d\n", ret);
+ goto err_free_sgt;
+ }
+
+ bo->sgt = sgt;
+ return 0;
+
+err_free_sgt:
+ kfree(sgt);
+ return ret;
+}
+
+static void ivpu_bo_unmap_pages_locked(struct ivpu_bo *bo)
+{
+ struct ivpu_device *vdev = ivpu_bo_to_vdev(bo);
+
+ dma_unmap_sgtable(vdev->drm.dev, bo->sgt, DMA_BIDIRECTIONAL, 0);
+ sg_free_table(bo->sgt);
+ kfree(bo->sgt);
+ bo->sgt = NULL;
+}
+
+static const struct ivpu_bo_ops shmem_ops = {
+ .type = IVPU_BO_TYPE_SHMEM,
+ .name = "shmem",
+ .alloc_pages = shmem_alloc_pages_locked,
+ .free_pages = shmem_free_pages_locked,
+ .map_pages = ivpu_bo_map_pages_locked,
+ .unmap_pages = ivpu_bo_unmap_pages_locked,
+};
+
+static int __must_check internal_alloc_pages_locked(struct ivpu_bo *bo)
+{
+ unsigned int i, npages = bo->base.size >> PAGE_SHIFT;
+ struct page **pages;
+ int ret;
+
+ pages = kvmalloc_array(npages, sizeof(*bo->pages), GFP_KERNEL);
+ if (!pages)
+ return -ENOMEM;
+
+ for (i = 0; i < npages; i++) {
+ pages[i] = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO);
+ if (!pages[i]) {
+ ret = -ENOMEM;
+ goto err_free_pages;
+ }
+ cond_resched();
+ }
+
+ bo->pages = pages;
+ return 0;
+
+err_free_pages:
+ while (i--)
+ put_page(pages[i]);
+ kvfree(pages);
+ return ret;
+}
+
+static void internal_free_pages_locked(struct ivpu_bo *bo)
+{
+ unsigned int i, npages = bo->base.size >> PAGE_SHIFT;
+
+ for (i = 0; i < npages; i++)
+ put_page(bo->pages[i]);
+
+ kvfree(bo->pages);
+ bo->pages = NULL;
+}
+
+static const struct ivpu_bo_ops internal_ops = {
+ .type = IVPU_BO_TYPE_INTERNAL,
+ .name = "internal",
+ .alloc_pages = internal_alloc_pages_locked,
+ .free_pages = internal_free_pages_locked,
+ .map_pages = ivpu_bo_map_pages_locked,
+ .unmap_pages = ivpu_bo_unmap_pages_locked,
+};
+
+static int __must_check ivpu_bo_alloc_and_map_pages_locked(struct ivpu_bo *bo)
+{
+ struct ivpu_device *vdev = ivpu_bo_to_vdev(bo);
+ int ret;
+
+ lockdep_assert_held(&bo->lock);
+ drm_WARN_ON(&vdev->drm, bo->sgt);
+
+ ret = bo->ops->alloc_pages(bo);
+ if (ret) {
+ ivpu_err(vdev, "Failed to allocate pages for BO: %d", ret);
+ return ret;
+ }
+
+ ret = bo->ops->map_pages(bo);
+ if (ret) {
+ ivpu_err(vdev, "Failed to map pages for BO: %d", ret);
+ goto err_free_pages;
+ }
+ return ret;
+
+err_free_pages:
+ bo->ops->free_pages(bo);
+ return ret;
+}
+
+static void ivpu_bo_unmap_and_free_pages(struct ivpu_bo *bo)
+{
+ mutex_lock(&bo->lock);
+
+ WARN_ON(!bo->sgt);
+ bo->ops->unmap_pages(bo);
+ WARN_ON(bo->sgt);
+ bo->ops->free_pages(bo);
+ WARN_ON(bo->pages);
+
+ mutex_unlock(&bo->lock);
+}
+
+/*
+ * ivpu_bo_pin() - pin the backing physical pages and map them to VPU.
+ *
+ * This function pins physical memory pages, then maps the physical pages
+ * to IOMMU address space and finally updates the VPU MMU page tables
+ * to allow the VPU to translate VPU address to IOMMU address.
+ */
+int __must_check ivpu_bo_pin(struct ivpu_bo *bo)
+{
+ struct ivpu_device *vdev = ivpu_bo_to_vdev(bo);
+ int ret = 0;
+
+ mutex_lock(&bo->lock);
+
+ if (!bo->vpu_addr) {
+ ivpu_err(vdev, "vpu_addr not set for BO ctx_id: %d handle: %d\n",
+ bo->ctx->id, bo->handle);
+ ret = -EINVAL;
+ goto unlock;
+ }
+
+ if (!bo->sgt) {
+ ret = ivpu_bo_alloc_and_map_pages_locked(bo);
+ if (ret)
+ goto unlock;
+ }
+
+ if (!bo->mmu_mapped) {
+ ret = ivpu_mmu_context_map_sgt(vdev, bo->ctx, bo->vpu_addr, bo->sgt,
+ ivpu_bo_is_snooped(bo));
+ if (ret) {
+ ivpu_err(vdev, "Failed to map BO in MMU: %d\n", ret);
+ goto unlock;
+ }
+ bo->mmu_mapped = true;
+ }
+
+unlock:
+ mutex_unlock(&bo->lock);
+
+ return ret;
+}
+
+static int
+ivpu_bo_alloc_vpu_addr(struct ivpu_bo *bo, struct ivpu_mmu_context *ctx,
+ const struct ivpu_addr_range *range)
+{
+ struct ivpu_device *vdev = ivpu_bo_to_vdev(bo);
+ int ret;
+
+ if (!range) {
+ if (bo->flags & DRM_IVPU_BO_HIGH_MEM)
+ range = &vdev->hw->ranges.user_high;
+ else
+ range = &vdev->hw->ranges.user_low;
+ }
+
+ mutex_lock(&ctx->lock);
+ ret = ivpu_mmu_context_insert_node_locked(ctx, range, bo->base.size, &bo->mm_node);
+ if (!ret) {
+ bo->ctx = ctx;
+ bo->vpu_addr = bo->mm_node.start;
+ list_add_tail(&bo->ctx_node, &ctx->bo_list);
+ }
+ mutex_unlock(&ctx->lock);
+
+ return ret;
+}
+
+static void ivpu_bo_free_vpu_addr(struct ivpu_bo *bo)
+{
+ struct ivpu_device *vdev = ivpu_bo_to_vdev(bo);
+ struct ivpu_mmu_context *ctx = bo->ctx;
+
+ ivpu_dbg(vdev, BO, "remove from ctx: ctx %d vpu_addr 0x%llx allocated %d mmu_mapped %d\n",
+ ctx->id, bo->vpu_addr, (bool)bo->sgt, bo->mmu_mapped);
+
+ mutex_lock(&bo->lock);
+
+ if (bo->mmu_mapped) {
+ drm_WARN_ON(&vdev->drm, !bo->sgt);
+ ivpu_mmu_context_unmap_sgt(vdev, ctx, bo->vpu_addr, bo->sgt);
+ bo->mmu_mapped = false;
+ }
+
+ mutex_lock(&ctx->lock);
+ list_del(&bo->ctx_node);
+ bo->vpu_addr = 0;
+ bo->ctx = NULL;
+ ivpu_mmu_context_remove_node_locked(ctx, &bo->mm_node);
+ mutex_unlock(&ctx->lock);
+
+ mutex_unlock(&bo->lock);
+}
+
+void ivpu_bo_remove_all_bos_from_context(struct ivpu_mmu_context *ctx)
+{
+ struct ivpu_bo *bo, *tmp;
+
+ list_for_each_entry_safe(bo, tmp, &ctx->bo_list, ctx_node)
+ ivpu_bo_free_vpu_addr(bo);
+}
+
+static struct ivpu_bo *
+ivpu_bo_alloc(struct ivpu_device *vdev, struct ivpu_mmu_context *mmu_context,
+ u64 size, u32 flags, const struct ivpu_bo_ops *ops,
+ const struct ivpu_addr_range *range, u64 user_ptr)
+{
+ struct ivpu_bo *bo;
+ int ret = 0;
+
+ if (drm_WARN_ON(&vdev->drm, size == 0 || !PAGE_ALIGNED(size)))
+ return ERR_PTR(-EINVAL);
+
+ switch (flags & DRM_IVPU_BO_CACHE_MASK) {
+ case DRM_IVPU_BO_CACHED:
+ case DRM_IVPU_BO_UNCACHED:
+ case DRM_IVPU_BO_WC:
+ break;
+ default:
+ return ERR_PTR(-EINVAL);
+ }
+
+ bo = kzalloc(sizeof(*bo), GFP_KERNEL);
+ if (!bo)
+ return ERR_PTR(-ENOMEM);
+
+ mutex_init(&bo->lock);
+ bo->base.funcs = &ivpu_gem_funcs;
+ bo->flags = flags;
+ bo->ops = ops;
+ bo->user_ptr = user_ptr;
+
+ if (ops->type == IVPU_BO_TYPE_SHMEM)
+ ret = drm_gem_object_init(&vdev->drm, &bo->base, size);
+ else
+ drm_gem_private_object_init(&vdev->drm, &bo->base, size);
+
+ if (ret) {
+ ivpu_err(vdev, "Failed to initialize drm object\n");
+ goto err_free;
+ }
+
+ if (flags & DRM_IVPU_BO_MAPPABLE) {
+ ret = drm_gem_create_mmap_offset(&bo->base);
+ if (ret) {
+ ivpu_err(vdev, "Failed to allocate mmap offset\n");
+ goto err_release;
+ }
+ }
+
+ if (mmu_context) {
+ ret = ivpu_bo_alloc_vpu_addr(bo, mmu_context, range);
+ if (ret) {
+ ivpu_err(vdev, "Failed to add BO to context: %d\n", ret);
+ goto err_release;
+ }
+ }
+
+ return bo;
+
+err_release:
+ drm_gem_object_release(&bo->base);
+err_free:
+ kfree(bo);
+ return ERR_PTR(ret);
+}
+
+static void ivpu_bo_free(struct drm_gem_object *obj)
+{
+ struct ivpu_bo *bo = to_ivpu_bo(obj);
+ struct ivpu_device *vdev = ivpu_bo_to_vdev(bo);
+
+ if (bo->ctx)
+ ivpu_dbg(vdev, BO, "free: ctx %d vpu_addr 0x%llx allocated %d mmu_mapped %d\n",
+ bo->ctx->id, bo->vpu_addr, (bool)bo->sgt, bo->mmu_mapped);
+ else
+ ivpu_dbg(vdev, BO, "free: ctx (released) allocated %d mmu_mapped %d\n",
+ (bool)bo->sgt, bo->mmu_mapped);
+
+ drm_WARN_ON(&vdev->drm, !dma_resv_test_signaled(obj->resv, DMA_RESV_USAGE_READ));
+
+ vunmap(bo->kvaddr);
+
+ if (bo->ctx)
+ ivpu_bo_free_vpu_addr(bo);
+
+ if (bo->sgt)
+ ivpu_bo_unmap_and_free_pages(bo);
+
+ if (bo->base.import_attach)
+ drm_prime_gem_destroy(&bo->base, bo->sgt);
+
+ drm_gem_object_release(&bo->base);
+
+ mutex_destroy(&bo->lock);
+ kfree(bo);
+}
+
+static int ivpu_bo_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
+{
+ struct ivpu_bo *bo = to_ivpu_bo(obj);
+ struct ivpu_device *vdev = ivpu_bo_to_vdev(bo);
+
+ ivpu_dbg(vdev, BO, "mmap: ctx %u handle %u vpu_addr 0x%llx size %zu type %s",
+ bo->ctx->id, bo->handle, bo->vpu_addr, bo->base.size, bo->ops->name);
+
+ if (obj->import_attach) {
+ /* Drop the reference drm_gem_mmap_obj() acquired.*/
+ drm_gem_object_put(obj);
+ vma->vm_private_data = NULL;
+ return dma_buf_mmap(obj->dma_buf, vma, 0);
+ }
+
+ vm_flags_set(vma, VM_PFNMAP | VM_DONTEXPAND);
+ vma->vm_page_prot = ivpu_bo_pgprot(bo, vm_get_page_prot(vma->vm_flags));
+
+ return 0;
+}
+
+static struct sg_table *ivpu_bo_get_sg_table(struct drm_gem_object *obj)
+{
+ struct ivpu_bo *bo = to_ivpu_bo(obj);
+ loff_t npages = obj->size >> PAGE_SHIFT;
+ int ret = 0;
+
+ mutex_lock(&bo->lock);
+
+ if (!bo->sgt)
+ ret = ivpu_bo_alloc_and_map_pages_locked(bo);
+
+ mutex_unlock(&bo->lock);
+
+ if (ret)
+ return ERR_PTR(ret);
+
+ return drm_prime_pages_to_sg(obj->dev, bo->pages, npages);
+}
+
+static vm_fault_t ivpu_vm_fault(struct vm_fault *vmf)
+{
+ struct vm_area_struct *vma = vmf->vma;
+ struct drm_gem_object *obj = vma->vm_private_data;
+ struct ivpu_bo *bo = to_ivpu_bo(obj);
+ loff_t npages = obj->size >> PAGE_SHIFT;
+ pgoff_t page_offset;
+ struct page *page;
+ vm_fault_t ret;
+ int err;
+
+ mutex_lock(&bo->lock);
+
+ if (!bo->sgt) {
+ err = ivpu_bo_alloc_and_map_pages_locked(bo);
+ if (err) {
+ ret = vmf_error(err);
+ goto unlock;
+ }
+ }
+
+ /* We don't use vmf->pgoff since that has the fake offset */
+ page_offset = (vmf->address - vma->vm_start) >> PAGE_SHIFT;
+ if (page_offset >= npages) {
+ ret = VM_FAULT_SIGBUS;
+ } else {
+ page = bo->pages[page_offset];
+ ret = vmf_insert_pfn(vma, vmf->address, page_to_pfn(page));
+ }
+
+unlock:
+ mutex_unlock(&bo->lock);
+
+ return ret;
+}
+
+static const struct vm_operations_struct ivpu_vm_ops = {
+ .fault = ivpu_vm_fault,
+ .open = drm_gem_vm_open,
+ .close = drm_gem_vm_close,
+};
+
+static const struct drm_gem_object_funcs ivpu_gem_funcs = {
+ .free = ivpu_bo_free,
+ .mmap = ivpu_bo_mmap,
+ .vm_ops = &ivpu_vm_ops,
+ .get_sg_table = ivpu_bo_get_sg_table,
+};
+
+int
+ivpu_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
+{
+ struct ivpu_file_priv *file_priv = file->driver_priv;
+ struct ivpu_device *vdev = file_priv->vdev;
+ struct drm_ivpu_bo_create *args = data;
+ u64 size = PAGE_ALIGN(args->size);
+ struct ivpu_bo *bo;
+ int ret;
+
+ if (args->flags & ~DRM_IVPU_BO_FLAGS)
+ return -EINVAL;
+
+ if (size == 0)
+ return -EINVAL;
+
+ bo = ivpu_bo_alloc(vdev, &file_priv->ctx, size, args->flags, &shmem_ops, NULL, 0);
+ if (IS_ERR(bo)) {
+ ivpu_err(vdev, "Failed to create BO: %pe (ctx %u size %llu flags 0x%x)",
+ bo, file_priv->ctx.id, args->size, args->flags);
+ return PTR_ERR(bo);
+ }
+
+ ret = drm_gem_handle_create(file, &bo->base, &bo->handle);
+ if (!ret) {
+ args->vpu_addr = bo->vpu_addr;
+ args->handle = bo->handle;
+ }
+
+ drm_gem_object_put(&bo->base);
+
+ ivpu_dbg(vdev, BO, "alloc shmem: ctx %u vpu_addr 0x%llx size %zu flags 0x%x\n",
+ file_priv->ctx.id, bo->vpu_addr, bo->base.size, bo->flags);
+
+ return ret;
+}
+
+struct ivpu_bo *
+ivpu_bo_alloc_internal(struct ivpu_device *vdev, u64 vpu_addr, u64 size, u32 flags)
+{
+ const struct ivpu_addr_range *range;
+ struct ivpu_addr_range fixed_range;
+ struct ivpu_bo *bo;
+ pgprot_t prot;
+ int ret;
+
+ drm_WARN_ON(&vdev->drm, !PAGE_ALIGNED(vpu_addr));
+ drm_WARN_ON(&vdev->drm, !PAGE_ALIGNED(size));
+
+ if (vpu_addr) {
+ fixed_range.start = vpu_addr;
+ fixed_range.end = vpu_addr + size;
+ range = &fixed_range;
+ } else {
+ range = &vdev->hw->ranges.global_low;
+ }
+
+ bo = ivpu_bo_alloc(vdev, &vdev->gctx, size, flags, &internal_ops, range, 0);
+ if (IS_ERR(bo)) {
+ ivpu_err(vdev, "Failed to create BO: %pe (vpu_addr 0x%llx size %llu flags 0x%x)",
+ bo, vpu_addr, size, flags);
+ return NULL;
+ }
+
+ ret = ivpu_bo_pin(bo);
+ if (ret)
+ goto err_put;
+
+ if (ivpu_bo_cache_mode(bo) != DRM_IVPU_BO_CACHED)
+ drm_clflush_pages(bo->pages, bo->base.size >> PAGE_SHIFT);
+
+ prot = ivpu_bo_pgprot(bo, PAGE_KERNEL);
+ bo->kvaddr = vmap(bo->pages, bo->base.size >> PAGE_SHIFT, VM_MAP, prot);
+ if (!bo->kvaddr) {
+ ivpu_err(vdev, "Failed to map BO into kernel virtual memory\n");
+ goto err_put;
+ }
+
+ ivpu_dbg(vdev, BO, "alloc internal: ctx 0 vpu_addr 0x%llx size %zu flags 0x%x\n",
+ bo->vpu_addr, bo->base.size, flags);
+
+ return bo;
+
+err_put:
+ drm_gem_object_put(&bo->base);
+ return NULL;
+}
+
+void ivpu_bo_free_internal(struct ivpu_bo *bo)
+{
+ drm_gem_object_put(&bo->base);
+}
+
+struct drm_gem_object *ivpu_gem_prime_import(struct drm_device *dev, struct dma_buf *buf)
+{
+ struct ivpu_device *vdev = to_ivpu_device(dev);
+ struct dma_buf_attachment *attach;
+ struct ivpu_bo *bo;
+
+ attach = dma_buf_attach(buf, dev->dev);
+ if (IS_ERR(attach))
+ return ERR_CAST(attach);
+
+ get_dma_buf(buf);
+
+ bo = ivpu_bo_alloc(vdev, NULL, buf->size, DRM_IVPU_BO_MAPPABLE, &prime_ops, NULL, 0);
+ if (IS_ERR(bo)) {
+ ivpu_err(vdev, "Failed to import BO: %pe (size %lu)", bo, buf->size);
+ goto err_detach;
+ }
+
+ lockdep_set_class(&bo->lock, &prime_bo_lock_class_key);
+
+ bo->base.import_attach = attach;
+
+ return &bo->base;
+
+err_detach:
+ dma_buf_detach(buf, attach);
+ dma_buf_put(buf);
+ return ERR_CAST(bo);
+}
+
+int ivpu_bo_info_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
+{
+ struct ivpu_file_priv *file_priv = file->driver_priv;
+ struct ivpu_device *vdev = to_ivpu_device(dev);
+ struct drm_ivpu_bo_info *args = data;
+ struct drm_gem_object *obj;
+ struct ivpu_bo *bo;
+ int ret = 0;
+
+ obj = drm_gem_object_lookup(file, args->handle);
+ if (!obj)
+ return -ENOENT;
+
+ bo = to_ivpu_bo(obj);
+
+ mutex_lock(&bo->lock);
+
+ if (!bo->ctx) {
+ ret = ivpu_bo_alloc_vpu_addr(bo, &file_priv->ctx, NULL);
+ if (ret) {
+ ivpu_err(vdev, "Failed to allocate vpu_addr: %d\n", ret);
+ goto unlock;
+ }
+ }
+
+ args->flags = bo->flags;
+ args->mmap_offset = drm_vma_node_offset_addr(&obj->vma_node);
+ args->vpu_addr = bo->vpu_addr;
+ args->size = obj->size;
+unlock:
+ mutex_unlock(&bo->lock);
+ drm_gem_object_put(obj);
+ return ret;
+}
+
+int ivpu_bo_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
+{
+ struct drm_ivpu_bo_wait *args = data;
+ struct drm_gem_object *obj;
+ unsigned long timeout;
+ long ret;
+
+ timeout = drm_timeout_abs_to_jiffies(args->timeout_ns);
+
+ obj = drm_gem_object_lookup(file, args->handle);
+ if (!obj)
+ return -EINVAL;
+
+ ret = dma_resv_wait_timeout(obj->resv, DMA_RESV_USAGE_READ, true, timeout);
+ if (ret == 0) {
+ ret = -ETIMEDOUT;
+ } else if (ret > 0) {
+ ret = 0;
+ args->job_status = to_ivpu_bo(obj)->job_status;
+ }
+
+ drm_gem_object_put(obj);
+
+ return ret;
+}
+
+static void ivpu_bo_print_info(struct ivpu_bo *bo, struct drm_printer *p)
+{
+ unsigned long dma_refcount = 0;
+
+ if (bo->base.dma_buf && bo->base.dma_buf->file)
+ dma_refcount = atomic_long_read(&bo->base.dma_buf->file->f_count);
+
+ drm_printf(p, "%5u %6d %16llx %10lu %10u %12lu %14s\n",
+ bo->ctx->id, bo->handle, bo->vpu_addr, bo->base.size,
+ kref_read(&bo->base.refcount), dma_refcount, bo->ops->name);
+}
+
+void ivpu_bo_list(struct drm_device *dev, struct drm_printer *p)
+{
+ struct ivpu_device *vdev = to_ivpu_device(dev);
+ struct ivpu_file_priv *file_priv;
+ unsigned long ctx_id;
+ struct ivpu_bo *bo;
+
+ drm_printf(p, "%5s %6s %16s %10s %10s %12s %14s\n",
+ "ctx", "handle", "vpu_addr", "size", "refcount", "dma_refcount", "type");
+
+ mutex_lock(&vdev->gctx.lock);
+ list_for_each_entry(bo, &vdev->gctx.bo_list, ctx_node)
+ ivpu_bo_print_info(bo, p);
+ mutex_unlock(&vdev->gctx.lock);
+
+ xa_for_each(&vdev->context_xa, ctx_id, file_priv) {
+ file_priv = ivpu_file_priv_get_by_ctx_id(vdev, ctx_id);
+ if (!file_priv)
+ continue;
+
+ mutex_lock(&file_priv->ctx.lock);
+ list_for_each_entry(bo, &file_priv->ctx.bo_list, ctx_node)
+ ivpu_bo_print_info(bo, p);
+ mutex_unlock(&file_priv->ctx.lock);
+
+ ivpu_file_priv_put(&file_priv);
+ }
+}
+
+void ivpu_bo_list_print(struct drm_device *dev)
+{
+ struct drm_printer p = drm_info_printer(dev->dev);
+
+ ivpu_bo_list(dev, &p);
+}
diff --git a/drivers/accel/ivpu/ivpu_gem.h b/drivers/accel/ivpu/ivpu_gem.h
new file mode 100644
index 000000000000..6b0ceda5f253
--- /dev/null
+++ b/drivers/accel/ivpu/ivpu_gem.h
@@ -0,0 +1,127 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2020-2023 Intel Corporation
+ */
+#ifndef __IVPU_GEM_H__
+#define __IVPU_GEM_H__
+
+#include <drm/drm_gem.h>
+#include <drm/drm_mm.h>
+
+struct dma_buf;
+struct ivpu_bo_ops;
+struct ivpu_file_priv;
+
+struct ivpu_bo {
+ struct drm_gem_object base;
+ const struct ivpu_bo_ops *ops;
+
+ struct ivpu_mmu_context *ctx;
+ struct list_head ctx_node;
+ struct drm_mm_node mm_node;
+
+ struct mutex lock; /* Protects: pages, sgt, mmu_mapped */
+ struct sg_table *sgt;
+ struct page **pages;
+ bool mmu_mapped;
+
+ void *kvaddr;
+ u64 vpu_addr;
+ u32 handle;
+ u32 flags;
+ uintptr_t user_ptr;
+ u32 job_status;
+};
+
+enum ivpu_bo_type {
+ IVPU_BO_TYPE_SHMEM = 1,
+ IVPU_BO_TYPE_INTERNAL,
+ IVPU_BO_TYPE_PRIME,
+};
+
+struct ivpu_bo_ops {
+ enum ivpu_bo_type type;
+ const char *name;
+ int (*alloc_pages)(struct ivpu_bo *bo);
+ void (*free_pages)(struct ivpu_bo *bo);
+ int (*map_pages)(struct ivpu_bo *bo);
+ void (*unmap_pages)(struct ivpu_bo *bo);
+};
+
+int ivpu_bo_pin(struct ivpu_bo *bo);
+void ivpu_bo_remove_all_bos_from_context(struct ivpu_mmu_context *ctx);
+void ivpu_bo_list(struct drm_device *dev, struct drm_printer *p);
+void ivpu_bo_list_print(struct drm_device *dev);
+
+struct ivpu_bo *
+ivpu_bo_alloc_internal(struct ivpu_device *vdev, u64 vpu_addr, u64 size, u32 flags);
+void ivpu_bo_free_internal(struct ivpu_bo *bo);
+struct drm_gem_object *ivpu_gem_prime_import(struct drm_device *dev, struct dma_buf *dma_buf);
+void ivpu_bo_unmap_sgt_and_remove_from_context(struct ivpu_bo *bo);
+
+int ivpu_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *file);
+int ivpu_bo_info_ioctl(struct drm_device *dev, void *data, struct drm_file *file);
+int ivpu_bo_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file);
+
+static inline struct ivpu_bo *to_ivpu_bo(struct drm_gem_object *obj)
+{
+ return container_of(obj, struct ivpu_bo, base);
+}
+
+static inline struct page *ivpu_bo_get_page(struct ivpu_bo *bo, u64 offset)
+{
+ if (offset > bo->base.size || !bo->pages)
+ return NULL;
+
+ return bo->pages[offset / PAGE_SIZE];
+}
+
+static inline u32 ivpu_bo_cache_mode(struct ivpu_bo *bo)
+{
+ return bo->flags & DRM_IVPU_BO_CACHE_MASK;
+}
+
+static inline bool ivpu_bo_is_snooped(struct ivpu_bo *bo)
+{
+ return ivpu_bo_cache_mode(bo) == DRM_IVPU_BO_CACHED;
+}
+
+static inline pgprot_t ivpu_bo_pgprot(struct ivpu_bo *bo, pgprot_t prot)
+{
+ if (bo->flags & DRM_IVPU_BO_WC)
+ return pgprot_writecombine(prot);
+
+ if (bo->flags & DRM_IVPU_BO_UNCACHED)
+ return pgprot_noncached(prot);
+
+ return prot;
+}
+
+static inline struct ivpu_device *ivpu_bo_to_vdev(struct ivpu_bo *bo)
+{
+ return to_ivpu_device(bo->base.dev);
+}
+
+static inline void *ivpu_to_cpu_addr(struct ivpu_bo *bo, u32 vpu_addr)
+{
+ if (vpu_addr < bo->vpu_addr)
+ return NULL;
+
+ if (vpu_addr >= (bo->vpu_addr + bo->base.size))
+ return NULL;
+
+ return bo->kvaddr + (vpu_addr - bo->vpu_addr);
+}
+
+static inline u32 cpu_to_vpu_addr(struct ivpu_bo *bo, void *cpu_addr)
+{
+ if (cpu_addr < bo->kvaddr)
+ return 0;
+
+ if (cpu_addr >= (bo->kvaddr + bo->base.size))
+ return 0;
+
+ return bo->vpu_addr + (cpu_addr - bo->kvaddr);
+}
+
+#endif /* __IVPU_GEM_H__ */
diff --git a/drivers/accel/ivpu/ivpu_hw.h b/drivers/accel/ivpu/ivpu_hw.h
new file mode 100644
index 000000000000..50a9304ab09c
--- /dev/null
+++ b/drivers/accel/ivpu/ivpu_hw.h
@@ -0,0 +1,170 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2020-2023 Intel Corporation
+ */
+
+#ifndef __IVPU_HW_H__
+#define __IVPU_HW_H__
+
+#include "ivpu_drv.h"
+
+struct ivpu_hw_ops {
+ int (*info_init)(struct ivpu_device *vdev);
+ int (*power_up)(struct ivpu_device *vdev);
+ int (*boot_fw)(struct ivpu_device *vdev);
+ int (*power_down)(struct ivpu_device *vdev);
+ bool (*is_idle)(struct ivpu_device *vdev);
+ void (*wdt_disable)(struct ivpu_device *vdev);
+ void (*diagnose_failure)(struct ivpu_device *vdev);
+ u32 (*reg_pll_freq_get)(struct ivpu_device *vdev);
+ u32 (*reg_telemetry_offset_get)(struct ivpu_device *vdev);
+ u32 (*reg_telemetry_size_get)(struct ivpu_device *vdev);
+ u32 (*reg_telemetry_enable_get)(struct ivpu_device *vdev);
+ void (*reg_db_set)(struct ivpu_device *vdev, u32 db_id);
+ u32 (*reg_ipc_rx_addr_get)(struct ivpu_device *vdev);
+ u32 (*reg_ipc_rx_count_get)(struct ivpu_device *vdev);
+ void (*reg_ipc_tx_set)(struct ivpu_device *vdev, u32 vpu_addr);
+ void (*irq_clear)(struct ivpu_device *vdev);
+ void (*irq_enable)(struct ivpu_device *vdev);
+ void (*irq_disable)(struct ivpu_device *vdev);
+ irqreturn_t (*irq_handler)(int irq, void *ptr);
+};
+
+struct ivpu_addr_range {
+ resource_size_t start;
+ resource_size_t end;
+};
+
+struct ivpu_hw_info {
+ const struct ivpu_hw_ops *ops;
+ struct {
+ struct ivpu_addr_range global_low;
+ struct ivpu_addr_range global_high;
+ struct ivpu_addr_range user_low;
+ struct ivpu_addr_range user_high;
+ struct ivpu_addr_range global_aliased_pio;
+ } ranges;
+ struct {
+ u8 min_ratio;
+ u8 max_ratio;
+ /*
+ * Pll ratio for the efficiency frequency. The VPU has optimum
+ * performance to power ratio at this frequency.
+ */
+ u8 pn_ratio;
+ u32 profiling_freq;
+ } pll;
+ u32 tile_fuse;
+ u32 sku;
+ u16 config;
+};
+
+extern const struct ivpu_hw_ops ivpu_hw_mtl_ops;
+
+static inline int ivpu_hw_info_init(struct ivpu_device *vdev)
+{
+ return vdev->hw->ops->info_init(vdev);
+};
+
+static inline int ivpu_hw_power_up(struct ivpu_device *vdev)
+{
+ ivpu_dbg(vdev, PM, "HW power up\n");
+
+ return vdev->hw->ops->power_up(vdev);
+};
+
+static inline int ivpu_hw_boot_fw(struct ivpu_device *vdev)
+{
+ return vdev->hw->ops->boot_fw(vdev);
+};
+
+static inline bool ivpu_hw_is_idle(struct ivpu_device *vdev)
+{
+ return vdev->hw->ops->is_idle(vdev);
+};
+
+static inline int ivpu_hw_power_down(struct ivpu_device *vdev)
+{
+ ivpu_dbg(vdev, PM, "HW power down\n");
+
+ return vdev->hw->ops->power_down(vdev);
+};
+
+static inline void ivpu_hw_wdt_disable(struct ivpu_device *vdev)
+{
+ vdev->hw->ops->wdt_disable(vdev);
+};
+
+/* Register indirect accesses */
+static inline u32 ivpu_hw_reg_pll_freq_get(struct ivpu_device *vdev)
+{
+ return vdev->hw->ops->reg_pll_freq_get(vdev);
+};
+
+static inline u32 ivpu_hw_reg_telemetry_offset_get(struct ivpu_device *vdev)
+{
+ return vdev->hw->ops->reg_telemetry_offset_get(vdev);
+};
+
+static inline u32 ivpu_hw_reg_telemetry_size_get(struct ivpu_device *vdev)
+{
+ return vdev->hw->ops->reg_telemetry_size_get(vdev);
+};
+
+static inline u32 ivpu_hw_reg_telemetry_enable_get(struct ivpu_device *vdev)
+{
+ return vdev->hw->ops->reg_telemetry_enable_get(vdev);
+};
+
+static inline void ivpu_hw_reg_db_set(struct ivpu_device *vdev, u32 db_id)
+{
+ vdev->hw->ops->reg_db_set(vdev, db_id);
+};
+
+static inline u32 ivpu_hw_reg_ipc_rx_addr_get(struct ivpu_device *vdev)
+{
+ return vdev->hw->ops->reg_ipc_rx_addr_get(vdev);
+};
+
+static inline u32 ivpu_hw_reg_ipc_rx_count_get(struct ivpu_device *vdev)
+{
+ return vdev->hw->ops->reg_ipc_rx_count_get(vdev);
+};
+
+static inline void ivpu_hw_reg_ipc_tx_set(struct ivpu_device *vdev, u32 vpu_addr)
+{
+ vdev->hw->ops->reg_ipc_tx_set(vdev, vpu_addr);
+};
+
+static inline void ivpu_hw_irq_clear(struct ivpu_device *vdev)
+{
+ vdev->hw->ops->irq_clear(vdev);
+};
+
+static inline void ivpu_hw_irq_enable(struct ivpu_device *vdev)
+{
+ vdev->hw->ops->irq_enable(vdev);
+};
+
+static inline void ivpu_hw_irq_disable(struct ivpu_device *vdev)
+{
+ vdev->hw->ops->irq_disable(vdev);
+};
+
+static inline void ivpu_hw_init_range(struct ivpu_addr_range *range, u64 start, u64 size)
+{
+ range->start = start;
+ range->end = start + size;
+}
+
+static inline u64 ivpu_hw_range_size(const struct ivpu_addr_range *range)
+{
+ return range->end - range->start;
+}
+
+static inline void ivpu_hw_diagnose_failure(struct ivpu_device *vdev)
+{
+ vdev->hw->ops->diagnose_failure(vdev);
+}
+
+#endif /* __IVPU_HW_H__ */
diff --git a/drivers/accel/ivpu/ivpu_hw_mtl.c b/drivers/accel/ivpu/ivpu_hw_mtl.c
new file mode 100644
index 000000000000..62bfaa9081c4
--- /dev/null
+++ b/drivers/accel/ivpu/ivpu_hw_mtl.c
@@ -0,0 +1,1084 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2020-2023 Intel Corporation
+ */
+
+#include "ivpu_drv.h"
+#include "ivpu_fw.h"
+#include "ivpu_hw_mtl_reg.h"
+#include "ivpu_hw_reg_io.h"
+#include "ivpu_hw.h"
+#include "ivpu_ipc.h"
+#include "ivpu_mmu.h"
+#include "ivpu_pm.h"
+
+#define TILE_FUSE_ENABLE_BOTH 0x0
+#define TILE_FUSE_ENABLE_UPPER 0x1
+#define TILE_FUSE_ENABLE_LOWER 0x2
+
+#define TILE_SKU_BOTH_MTL 0x3630
+#define TILE_SKU_LOWER_MTL 0x3631
+#define TILE_SKU_UPPER_MTL 0x3632
+
+/* Work point configuration values */
+#define WP_CONFIG_1_TILE_5_3_RATIO 0x0101
+#define WP_CONFIG_1_TILE_4_3_RATIO 0x0102
+#define WP_CONFIG_2_TILE_5_3_RATIO 0x0201
+#define WP_CONFIG_2_TILE_4_3_RATIO 0x0202
+#define WP_CONFIG_0_TILE_PLL_OFF 0x0000
+
+#define PLL_REF_CLK_FREQ (50 * 1000000)
+#define PLL_SIMULATION_FREQ (10 * 1000000)
+#define PLL_RATIO_TO_FREQ(x) ((x) * PLL_REF_CLK_FREQ)
+#define PLL_DEFAULT_EPP_VALUE 0x80
+
+#define TIM_SAFE_ENABLE 0xf1d0dead
+#define TIM_WATCHDOG_RESET_VALUE 0xffffffff
+
+#define TIMEOUT_US (150 * USEC_PER_MSEC)
+#define PWR_ISLAND_STATUS_TIMEOUT_US (5 * USEC_PER_MSEC)
+#define PLL_TIMEOUT_US (1500 * USEC_PER_MSEC)
+#define IDLE_TIMEOUT_US (500 * USEC_PER_MSEC)
+
+#define ICB_0_IRQ_MASK ((REG_FLD(MTL_VPU_HOST_SS_ICB_STATUS_0, HOST_IPC_FIFO_INT)) | \
+ (REG_FLD(MTL_VPU_HOST_SS_ICB_STATUS_0, MMU_IRQ_0_INT)) | \
+ (REG_FLD(MTL_VPU_HOST_SS_ICB_STATUS_0, MMU_IRQ_1_INT)) | \
+ (REG_FLD(MTL_VPU_HOST_SS_ICB_STATUS_0, MMU_IRQ_2_INT)) | \
+ (REG_FLD(MTL_VPU_HOST_SS_ICB_STATUS_0, NOC_FIREWALL_INT)) | \
+ (REG_FLD(MTL_VPU_HOST_SS_ICB_STATUS_0, CPU_INT_REDIRECT_0_INT)) | \
+ (REG_FLD(MTL_VPU_HOST_SS_ICB_STATUS_0, CPU_INT_REDIRECT_1_INT)))
+
+#define ICB_1_IRQ_MASK ((REG_FLD(MTL_VPU_HOST_SS_ICB_STATUS_1, CPU_INT_REDIRECT_2_INT)) | \
+ (REG_FLD(MTL_VPU_HOST_SS_ICB_STATUS_1, CPU_INT_REDIRECT_3_INT)) | \
+ (REG_FLD(MTL_VPU_HOST_SS_ICB_STATUS_1, CPU_INT_REDIRECT_4_INT)))
+
+#define ICB_0_1_IRQ_MASK ((((u64)ICB_1_IRQ_MASK) << 32) | ICB_0_IRQ_MASK)
+
+#define BUTTRESS_IRQ_MASK ((REG_FLD(MTL_BUTTRESS_INTERRUPT_STAT, FREQ_CHANGE)) | \
+ (REG_FLD(MTL_BUTTRESS_INTERRUPT_STAT, ATS_ERR)) | \
+ (REG_FLD(MTL_BUTTRESS_INTERRUPT_STAT, UFI_ERR)))
+
+#define BUTTRESS_IRQ_ENABLE_MASK ((u32)~BUTTRESS_IRQ_MASK)
+#define BUTTRESS_IRQ_DISABLE_MASK ((u32)-1)
+
+#define ITF_FIREWALL_VIOLATION_MASK ((REG_FLD(MTL_VPU_HOST_SS_FW_SOC_IRQ_EN, CSS_ROM_CMX)) | \
+ (REG_FLD(MTL_VPU_HOST_SS_FW_SOC_IRQ_EN, CSS_DBG)) | \
+ (REG_FLD(MTL_VPU_HOST_SS_FW_SOC_IRQ_EN, CSS_CTRL)) | \
+ (REG_FLD(MTL_VPU_HOST_SS_FW_SOC_IRQ_EN, DEC400)) | \
+ (REG_FLD(MTL_VPU_HOST_SS_FW_SOC_IRQ_EN, MSS_NCE)) | \
+ (REG_FLD(MTL_VPU_HOST_SS_FW_SOC_IRQ_EN, MSS_MBI)) | \
+ (REG_FLD(MTL_VPU_HOST_SS_FW_SOC_IRQ_EN, MSS_MBI_CMX)))
+
+static char *ivpu_platform_to_str(u32 platform)
+{
+ switch (platform) {
+ case IVPU_PLATFORM_SILICON:
+ return "IVPU_PLATFORM_SILICON";
+ case IVPU_PLATFORM_SIMICS:
+ return "IVPU_PLATFORM_SIMICS";
+ case IVPU_PLATFORM_FPGA:
+ return "IVPU_PLATFORM_FPGA";
+ default:
+ return "Invalid platform";
+ }
+}
+
+static void ivpu_hw_read_platform(struct ivpu_device *vdev)
+{
+ u32 gen_ctrl = REGV_RD32(MTL_VPU_HOST_SS_GEN_CTRL);
+ u32 platform = REG_GET_FLD(MTL_VPU_HOST_SS_GEN_CTRL, PS, gen_ctrl);
+
+ if (platform == IVPU_PLATFORM_SIMICS || platform == IVPU_PLATFORM_FPGA)
+ vdev->platform = platform;
+ else
+ vdev->platform = IVPU_PLATFORM_SILICON;
+
+ ivpu_dbg(vdev, MISC, "Platform type: %s (%d)\n",
+ ivpu_platform_to_str(vdev->platform), vdev->platform);
+}
+
+static void ivpu_hw_wa_init(struct ivpu_device *vdev)
+{
+ vdev->wa.punit_disabled = ivpu_is_fpga(vdev);
+ vdev->wa.clear_runtime_mem = false;
+}
+
+static void ivpu_hw_timeouts_init(struct ivpu_device *vdev)
+{
+ if (ivpu_is_simics(vdev) || ivpu_is_fpga(vdev)) {
+ vdev->timeout.boot = 100000;
+ vdev->timeout.jsm = 50000;
+ vdev->timeout.tdr = 2000000;
+ vdev->timeout.reschedule_suspend = 1000;
+ } else {
+ vdev->timeout.boot = 1000;
+ vdev->timeout.jsm = 500;
+ vdev->timeout.tdr = 2000;
+ vdev->timeout.reschedule_suspend = 10;
+ }
+}
+
+static int ivpu_pll_wait_for_cmd_send(struct ivpu_device *vdev)
+{
+ return REGB_POLL_FLD(MTL_BUTTRESS_WP_REQ_CMD, SEND, 0, PLL_TIMEOUT_US);
+}
+
+/* Send KMD initiated workpoint change */
+static int ivpu_pll_cmd_send(struct ivpu_device *vdev, u16 min_ratio, u16 max_ratio,
+ u16 target_ratio, u16 config)
+{
+ int ret;
+ u32 val;
+
+ ret = ivpu_pll_wait_for_cmd_send(vdev);
+ if (ret) {
+ ivpu_err(vdev, "Failed to sync before WP request: %d\n", ret);
+ return ret;
+ }
+
+ val = REGB_RD32(MTL_BUTTRESS_WP_REQ_PAYLOAD0);
+ val = REG_SET_FLD_NUM(MTL_BUTTRESS_WP_REQ_PAYLOAD0, MIN_RATIO, min_ratio, val);
+ val = REG_SET_FLD_NUM(MTL_BUTTRESS_WP_REQ_PAYLOAD0, MAX_RATIO, max_ratio, val);
+ REGB_WR32(MTL_BUTTRESS_WP_REQ_PAYLOAD0, val);
+
+ val = REGB_RD32(MTL_BUTTRESS_WP_REQ_PAYLOAD1);
+ val = REG_SET_FLD_NUM(MTL_BUTTRESS_WP_REQ_PAYLOAD1, TARGET_RATIO, target_ratio, val);
+ val = REG_SET_FLD_NUM(MTL_BUTTRESS_WP_REQ_PAYLOAD1, EPP, PLL_DEFAULT_EPP_VALUE, val);
+ REGB_WR32(MTL_BUTTRESS_WP_REQ_PAYLOAD1, val);
+
+ val = REGB_RD32(MTL_BUTTRESS_WP_REQ_PAYLOAD2);
+ val = REG_SET_FLD_NUM(MTL_BUTTRESS_WP_REQ_PAYLOAD2, CONFIG, config, val);
+ REGB_WR32(MTL_BUTTRESS_WP_REQ_PAYLOAD2, val);
+
+ val = REGB_RD32(MTL_BUTTRESS_WP_REQ_CMD);
+ val = REG_SET_FLD(MTL_BUTTRESS_WP_REQ_CMD, SEND, val);
+ REGB_WR32(MTL_BUTTRESS_WP_REQ_CMD, val);
+
+ ret = ivpu_pll_wait_for_cmd_send(vdev);
+ if (ret)
+ ivpu_err(vdev, "Failed to sync after WP request: %d\n", ret);
+
+ return ret;
+}
+
+static int ivpu_pll_wait_for_lock(struct ivpu_device *vdev, bool enable)
+{
+ u32 exp_val = enable ? 0x1 : 0x0;
+
+ if (IVPU_WA(punit_disabled))
+ return 0;
+
+ return REGB_POLL_FLD(MTL_BUTTRESS_PLL_STATUS, LOCK, exp_val, PLL_TIMEOUT_US);
+}
+
+static int ivpu_pll_wait_for_status_ready(struct ivpu_device *vdev)
+{
+ if (IVPU_WA(punit_disabled))
+ return 0;
+
+ return REGB_POLL_FLD(MTL_BUTTRESS_VPU_STATUS, READY, 1, PLL_TIMEOUT_US);
+}
+
+static void ivpu_pll_init_frequency_ratios(struct ivpu_device *vdev)
+{
+ struct ivpu_hw_info *hw = vdev->hw;
+ u8 fuse_min_ratio, fuse_max_ratio, fuse_pn_ratio;
+ u32 fmin_fuse, fmax_fuse;
+
+ fmin_fuse = REGB_RD32(MTL_BUTTRESS_FMIN_FUSE);
+ fuse_min_ratio = REG_GET_FLD(MTL_BUTTRESS_FMIN_FUSE, MIN_RATIO, fmin_fuse);
+ fuse_pn_ratio = REG_GET_FLD(MTL_BUTTRESS_FMIN_FUSE, PN_RATIO, fmin_fuse);
+
+ fmax_fuse = REGB_RD32(MTL_BUTTRESS_FMAX_FUSE);
+ fuse_max_ratio = REG_GET_FLD(MTL_BUTTRESS_FMAX_FUSE, MAX_RATIO, fmax_fuse);
+
+ hw->pll.min_ratio = clamp_t(u8, ivpu_pll_min_ratio, fuse_min_ratio, fuse_max_ratio);
+ hw->pll.max_ratio = clamp_t(u8, ivpu_pll_max_ratio, hw->pll.min_ratio, fuse_max_ratio);
+ hw->pll.pn_ratio = clamp_t(u8, fuse_pn_ratio, hw->pll.min_ratio, hw->pll.max_ratio);
+}
+
+static int ivpu_pll_drive(struct ivpu_device *vdev, bool enable)
+{
+ struct ivpu_hw_info *hw = vdev->hw;
+ u16 target_ratio;
+ u16 config;
+ int ret;
+
+ if (IVPU_WA(punit_disabled)) {
+ ivpu_dbg(vdev, PM, "Skipping PLL request on %s\n",
+ ivpu_platform_to_str(vdev->platform));
+ return 0;
+ }
+
+ if (enable) {
+ target_ratio = hw->pll.pn_ratio;
+ config = hw->config;
+ } else {
+ target_ratio = 0;
+ config = 0;
+ }
+
+ ivpu_dbg(vdev, PM, "PLL workpoint request: %d Hz\n", PLL_RATIO_TO_FREQ(target_ratio));
+
+ ret = ivpu_pll_cmd_send(vdev, hw->pll.min_ratio, hw->pll.max_ratio, target_ratio, config);
+ if (ret) {
+ ivpu_err(vdev, "Failed to send PLL workpoint request: %d\n", ret);
+ return ret;
+ }
+
+ ret = ivpu_pll_wait_for_lock(vdev, enable);
+ if (ret) {
+ ivpu_err(vdev, "Timed out waiting for PLL lock\n");
+ return ret;
+ }
+
+ if (enable) {
+ ret = ivpu_pll_wait_for_status_ready(vdev);
+ if (ret) {
+ ivpu_err(vdev, "Timed out waiting for PLL ready status\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int ivpu_pll_enable(struct ivpu_device *vdev)
+{
+ return ivpu_pll_drive(vdev, true);
+}
+
+static int ivpu_pll_disable(struct ivpu_device *vdev)
+{
+ return ivpu_pll_drive(vdev, false);
+}
+
+static void ivpu_boot_host_ss_rst_clr_assert(struct ivpu_device *vdev)
+{
+ u32 val = REGV_RD32(MTL_VPU_HOST_SS_CPR_RST_CLR);
+
+ val = REG_SET_FLD(MTL_VPU_HOST_SS_CPR_RST_CLR, TOP_NOC, val);
+ val = REG_SET_FLD(MTL_VPU_HOST_SS_CPR_RST_CLR, DSS_MAS, val);
+ val = REG_SET_FLD(MTL_VPU_HOST_SS_CPR_RST_CLR, MSS_MAS, val);
+
+ REGV_WR32(MTL_VPU_HOST_SS_CPR_RST_CLR, val);
+}
+
+static void ivpu_boot_host_ss_rst_drive(struct ivpu_device *vdev, bool enable)
+{
+ u32 val = REGV_RD32(MTL_VPU_HOST_SS_CPR_RST_SET);
+
+ if (enable) {
+ val = REG_SET_FLD(MTL_VPU_HOST_SS_CPR_RST_SET, TOP_NOC, val);
+ val = REG_SET_FLD(MTL_VPU_HOST_SS_CPR_RST_SET, DSS_MAS, val);
+ val = REG_SET_FLD(MTL_VPU_HOST_SS_CPR_RST_SET, MSS_MAS, val);
+ } else {
+ val = REG_CLR_FLD(MTL_VPU_HOST_SS_CPR_RST_SET, TOP_NOC, val);
+ val = REG_CLR_FLD(MTL_VPU_HOST_SS_CPR_RST_SET, DSS_MAS, val);
+ val = REG_CLR_FLD(MTL_VPU_HOST_SS_CPR_RST_SET, MSS_MAS, val);
+ }
+
+ REGV_WR32(MTL_VPU_HOST_SS_CPR_RST_SET, val);
+}
+
+static void ivpu_boot_host_ss_clk_drive(struct ivpu_device *vdev, bool enable)
+{
+ u32 val = REGV_RD32(MTL_VPU_HOST_SS_CPR_CLK_SET);
+
+ if (enable) {
+ val = REG_SET_FLD(MTL_VPU_HOST_SS_CPR_CLK_SET, TOP_NOC, val);
+ val = REG_SET_FLD(MTL_VPU_HOST_SS_CPR_CLK_SET, DSS_MAS, val);
+ val = REG_SET_FLD(MTL_VPU_HOST_SS_CPR_CLK_SET, MSS_MAS, val);
+ } else {
+ val = REG_CLR_FLD(MTL_VPU_HOST_SS_CPR_CLK_SET, TOP_NOC, val);
+ val = REG_CLR_FLD(MTL_VPU_HOST_SS_CPR_CLK_SET, DSS_MAS, val);
+ val = REG_CLR_FLD(MTL_VPU_HOST_SS_CPR_CLK_SET, MSS_MAS, val);
+ }
+
+ REGV_WR32(MTL_VPU_HOST_SS_CPR_CLK_SET, val);
+}
+
+static int ivpu_boot_noc_qreqn_check(struct ivpu_device *vdev, u32 exp_val)
+{
+ u32 val = REGV_RD32(MTL_VPU_HOST_SS_NOC_QREQN);
+
+ if (!REG_TEST_FLD_NUM(MTL_VPU_HOST_SS_NOC_QREQN, TOP_SOCMMIO, exp_val, val))
+ return -EIO;
+
+ return 0;
+}
+
+static int ivpu_boot_noc_qacceptn_check(struct ivpu_device *vdev, u32 exp_val)
+{
+ u32 val = REGV_RD32(MTL_VPU_HOST_SS_NOC_QACCEPTN);
+
+ if (!REG_TEST_FLD_NUM(MTL_VPU_HOST_SS_NOC_QACCEPTN, TOP_SOCMMIO, exp_val, val))
+ return -EIO;
+
+ return 0;
+}
+
+static int ivpu_boot_noc_qdeny_check(struct ivpu_device *vdev, u32 exp_val)
+{
+ u32 val = REGV_RD32(MTL_VPU_HOST_SS_NOC_QDENY);
+
+ if (!REG_TEST_FLD_NUM(MTL_VPU_HOST_SS_NOC_QDENY, TOP_SOCMMIO, exp_val, val))
+ return -EIO;
+
+ return 0;
+}
+
+static int ivpu_boot_top_noc_qrenqn_check(struct ivpu_device *vdev, u32 exp_val)
+{
+ u32 val = REGV_RD32(MTL_VPU_TOP_NOC_QREQN);
+
+ if (!REG_TEST_FLD_NUM(MTL_VPU_TOP_NOC_QREQN, CPU_CTRL, exp_val, val) ||
+ !REG_TEST_FLD_NUM(MTL_VPU_TOP_NOC_QREQN, HOSTIF_L2CACHE, exp_val, val))
+ return -EIO;
+
+ return 0;
+}
+
+static int ivpu_boot_top_noc_qacceptn_check(struct ivpu_device *vdev, u32 exp_val)
+{
+ u32 val = REGV_RD32(MTL_VPU_TOP_NOC_QACCEPTN);
+
+ if (!REG_TEST_FLD_NUM(MTL_VPU_TOP_NOC_QACCEPTN, CPU_CTRL, exp_val, val) ||
+ !REG_TEST_FLD_NUM(MTL_VPU_TOP_NOC_QACCEPTN, HOSTIF_L2CACHE, exp_val, val))
+ return -EIO;
+
+ return 0;
+}
+
+static int ivpu_boot_top_noc_qdeny_check(struct ivpu_device *vdev, u32 exp_val)
+{
+ u32 val = REGV_RD32(MTL_VPU_TOP_NOC_QDENY);
+
+ if (!REG_TEST_FLD_NUM(MTL_VPU_TOP_NOC_QDENY, CPU_CTRL, exp_val, val) ||
+ !REG_TEST_FLD_NUM(MTL_VPU_TOP_NOC_QDENY, HOSTIF_L2CACHE, exp_val, val))
+ return -EIO;
+
+ return 0;
+}
+
+static int ivpu_boot_host_ss_configure(struct ivpu_device *vdev)
+{
+ ivpu_boot_host_ss_rst_clr_assert(vdev);
+
+ return ivpu_boot_noc_qreqn_check(vdev, 0x0);
+}
+
+static void ivpu_boot_vpu_idle_gen_disable(struct ivpu_device *vdev)
+{
+ REGV_WR32(MTL_VPU_HOST_SS_AON_VPU_IDLE_GEN, 0x0);
+}
+
+static int ivpu_boot_host_ss_axi_drive(struct ivpu_device *vdev, bool enable)
+{
+ int ret;
+ u32 val;
+
+ val = REGV_RD32(MTL_VPU_HOST_SS_NOC_QREQN);
+ if (enable)
+ val = REG_SET_FLD(MTL_VPU_HOST_SS_NOC_QREQN, TOP_SOCMMIO, val);
+ else
+ val = REG_CLR_FLD(MTL_VPU_HOST_SS_NOC_QREQN, TOP_SOCMMIO, val);
+ REGV_WR32(MTL_VPU_HOST_SS_NOC_QREQN, val);
+
+ ret = ivpu_boot_noc_qacceptn_check(vdev, enable ? 0x1 : 0x0);
+ if (ret) {
+ ivpu_err(vdev, "Failed qacceptn check: %d\n", ret);
+ return ret;
+ }
+
+ ret = ivpu_boot_noc_qdeny_check(vdev, 0x0);
+ if (ret)
+ ivpu_err(vdev, "Failed qdeny check: %d\n", ret);
+
+ return ret;
+}
+
+static int ivpu_boot_host_ss_axi_enable(struct ivpu_device *vdev)
+{
+ return ivpu_boot_host_ss_axi_drive(vdev, true);
+}
+
+static int ivpu_boot_host_ss_axi_disable(struct ivpu_device *vdev)
+{
+ return ivpu_boot_host_ss_axi_drive(vdev, false);
+}
+
+static int ivpu_boot_host_ss_top_noc_drive(struct ivpu_device *vdev, bool enable)
+{
+ int ret;
+ u32 val;
+
+ val = REGV_RD32(MTL_VPU_TOP_NOC_QREQN);
+ if (enable) {
+ val = REG_SET_FLD(MTL_VPU_TOP_NOC_QREQN, CPU_CTRL, val);
+ val = REG_SET_FLD(MTL_VPU_TOP_NOC_QREQN, HOSTIF_L2CACHE, val);
+ } else {
+ val = REG_CLR_FLD(MTL_VPU_TOP_NOC_QREQN, CPU_CTRL, val);
+ val = REG_CLR_FLD(MTL_VPU_TOP_NOC_QREQN, HOSTIF_L2CACHE, val);
+ }
+ REGV_WR32(MTL_VPU_TOP_NOC_QREQN, val);
+
+ ret = ivpu_boot_top_noc_qacceptn_check(vdev, enable ? 0x1 : 0x0);
+ if (ret) {
+ ivpu_err(vdev, "Failed qacceptn check: %d\n", ret);
+ return ret;
+ }
+
+ ret = ivpu_boot_top_noc_qdeny_check(vdev, 0x0);
+ if (ret)
+ ivpu_err(vdev, "Failed qdeny check: %d\n", ret);
+
+ return ret;
+}
+
+static int ivpu_boot_host_ss_top_noc_enable(struct ivpu_device *vdev)
+{
+ return ivpu_boot_host_ss_top_noc_drive(vdev, true);
+}
+
+static int ivpu_boot_host_ss_top_noc_disable(struct ivpu_device *vdev)
+{
+ return ivpu_boot_host_ss_top_noc_drive(vdev, false);
+}
+
+static void ivpu_boot_pwr_island_trickle_drive(struct ivpu_device *vdev, bool enable)
+{
+ u32 val = REGV_RD32(MTL_VPU_HOST_SS_AON_PWR_ISLAND_TRICKLE_EN0);
+
+ if (enable)
+ val = REG_SET_FLD(MTL_VPU_HOST_SS_AON_PWR_ISLAND_TRICKLE_EN0, MSS_CPU, val);
+ else
+ val = REG_CLR_FLD(MTL_VPU_HOST_SS_AON_PWR_ISLAND_TRICKLE_EN0, MSS_CPU, val);
+
+ REGV_WR32(MTL_VPU_HOST_SS_AON_PWR_ISLAND_TRICKLE_EN0, val);
+}
+
+static void ivpu_boot_pwr_island_drive(struct ivpu_device *vdev, bool enable)
+{
+ u32 val = REGV_RD32(MTL_VPU_HOST_SS_AON_PWR_ISLAND_EN0);
+
+ if (enable)
+ val = REG_SET_FLD(MTL_VPU_HOST_SS_AON_PWR_ISLAND_EN0, MSS_CPU, val);
+ else
+ val = REG_CLR_FLD(MTL_VPU_HOST_SS_AON_PWR_ISLAND_EN0, MSS_CPU, val);
+
+ REGV_WR32(MTL_VPU_HOST_SS_AON_PWR_ISLAND_EN0, val);
+}
+
+static int ivpu_boot_wait_for_pwr_island_status(struct ivpu_device *vdev, u32 exp_val)
+{
+ /* FPGA model (UPF) is not power aware, skipped Power Island polling */
+ if (ivpu_is_fpga(vdev))
+ return 0;
+
+ return REGV_POLL_FLD(MTL_VPU_HOST_SS_AON_PWR_ISLAND_STATUS0, MSS_CPU,
+ exp_val, PWR_ISLAND_STATUS_TIMEOUT_US);
+}
+
+static void ivpu_boot_pwr_island_isolation_drive(struct ivpu_device *vdev, bool enable)
+{
+ u32 val = REGV_RD32(MTL_VPU_HOST_SS_AON_PWR_ISO_EN0);
+
+ if (enable)
+ val = REG_SET_FLD(MTL_VPU_HOST_SS_AON_PWR_ISO_EN0, MSS_CPU, val);
+ else
+ val = REG_CLR_FLD(MTL_VPU_HOST_SS_AON_PWR_ISO_EN0, MSS_CPU, val);
+
+ REGV_WR32(MTL_VPU_HOST_SS_AON_PWR_ISO_EN0, val);
+}
+
+static void ivpu_boot_dpu_active_drive(struct ivpu_device *vdev, bool enable)
+{
+ u32 val = REGV_RD32(MTL_VPU_HOST_SS_AON_DPU_ACTIVE);
+
+ if (enable)
+ val = REG_SET_FLD(MTL_VPU_HOST_SS_AON_DPU_ACTIVE, DPU_ACTIVE, val);
+ else
+ val = REG_CLR_FLD(MTL_VPU_HOST_SS_AON_DPU_ACTIVE, DPU_ACTIVE, val);
+
+ REGV_WR32(MTL_VPU_HOST_SS_AON_DPU_ACTIVE, val);
+}
+
+static int ivpu_boot_pwr_domain_disable(struct ivpu_device *vdev)
+{
+ ivpu_boot_dpu_active_drive(vdev, false);
+ ivpu_boot_pwr_island_isolation_drive(vdev, true);
+ ivpu_boot_pwr_island_trickle_drive(vdev, false);
+ ivpu_boot_pwr_island_drive(vdev, false);
+
+ return ivpu_boot_wait_for_pwr_island_status(vdev, 0x0);
+}
+
+static int ivpu_boot_pwr_domain_enable(struct ivpu_device *vdev)
+{
+ int ret;
+
+ ivpu_boot_pwr_island_trickle_drive(vdev, true);
+ ivpu_boot_pwr_island_drive(vdev, true);
+
+ ret = ivpu_boot_wait_for_pwr_island_status(vdev, 0x1);
+ if (ret) {
+ ivpu_err(vdev, "Timed out waiting for power island status\n");
+ return ret;
+ }
+
+ ret = ivpu_boot_top_noc_qrenqn_check(vdev, 0x0);
+ if (ret) {
+ ivpu_err(vdev, "Failed qrenqn check %d\n", ret);
+ return ret;
+ }
+
+ ivpu_boot_host_ss_clk_drive(vdev, true);
+ ivpu_boot_pwr_island_isolation_drive(vdev, false);
+ ivpu_boot_host_ss_rst_drive(vdev, true);
+ ivpu_boot_dpu_active_drive(vdev, true);
+
+ return ret;
+}
+
+static void ivpu_boot_no_snoop_enable(struct ivpu_device *vdev)
+{
+ u32 val = REGV_RD32(MTL_VPU_HOST_IF_TCU_PTW_OVERRIDES);
+
+ val = REG_SET_FLD(MTL_VPU_HOST_IF_TCU_PTW_OVERRIDES, NOSNOOP_OVERRIDE_EN, val);
+ val = REG_SET_FLD(MTL_VPU_HOST_IF_TCU_PTW_OVERRIDES, AW_NOSNOOP_OVERRIDE, val);
+ val = REG_SET_FLD(MTL_VPU_HOST_IF_TCU_PTW_OVERRIDES, AR_NOSNOOP_OVERRIDE, val);
+
+ REGV_WR32(MTL_VPU_HOST_IF_TCU_PTW_OVERRIDES, val);
+}
+
+static void ivpu_boot_tbu_mmu_enable(struct ivpu_device *vdev)
+{
+ u32 val = REGV_RD32(MTL_VPU_HOST_IF_TBU_MMUSSIDV);
+
+ if (ivpu_is_fpga(vdev)) {
+ val = REG_SET_FLD(MTL_VPU_HOST_IF_TBU_MMUSSIDV, TBU0_AWMMUSSIDV, val);
+ val = REG_SET_FLD(MTL_VPU_HOST_IF_TBU_MMUSSIDV, TBU0_ARMMUSSIDV, val);
+ val = REG_SET_FLD(MTL_VPU_HOST_IF_TBU_MMUSSIDV, TBU2_AWMMUSSIDV, val);
+ val = REG_SET_FLD(MTL_VPU_HOST_IF_TBU_MMUSSIDV, TBU2_ARMMUSSIDV, val);
+ } else {
+ val = REG_SET_FLD(MTL_VPU_HOST_IF_TBU_MMUSSIDV, TBU0_AWMMUSSIDV, val);
+ val = REG_SET_FLD(MTL_VPU_HOST_IF_TBU_MMUSSIDV, TBU0_ARMMUSSIDV, val);
+ val = REG_SET_FLD(MTL_VPU_HOST_IF_TBU_MMUSSIDV, TBU1_AWMMUSSIDV, val);
+ val = REG_SET_FLD(MTL_VPU_HOST_IF_TBU_MMUSSIDV, TBU1_ARMMUSSIDV, val);
+ val = REG_SET_FLD(MTL_VPU_HOST_IF_TBU_MMUSSIDV, TBU2_AWMMUSSIDV, val);
+ val = REG_SET_FLD(MTL_VPU_HOST_IF_TBU_MMUSSIDV, TBU2_ARMMUSSIDV, val);
+ val = REG_SET_FLD(MTL_VPU_HOST_IF_TBU_MMUSSIDV, TBU3_AWMMUSSIDV, val);
+ val = REG_SET_FLD(MTL_VPU_HOST_IF_TBU_MMUSSIDV, TBU3_ARMMUSSIDV, val);
+ }
+
+ REGV_WR32(MTL_VPU_HOST_IF_TBU_MMUSSIDV, val);
+}
+
+static void ivpu_boot_soc_cpu_boot(struct ivpu_device *vdev)
+{
+ u32 val;
+
+ val = REGV_RD32(MTL_VPU_CPU_SS_MSSCPU_CPR_LEON_RT_VEC);
+ val = REG_SET_FLD(MTL_VPU_CPU_SS_MSSCPU_CPR_LEON_RT_VEC, IRQI_RSTRUN0, val);
+
+ val = REG_CLR_FLD(MTL_VPU_CPU_SS_MSSCPU_CPR_LEON_RT_VEC, IRQI_RSTVEC, val);
+ REGV_WR32(MTL_VPU_CPU_SS_MSSCPU_CPR_LEON_RT_VEC, val);
+
+ val = REG_SET_FLD(MTL_VPU_CPU_SS_MSSCPU_CPR_LEON_RT_VEC, IRQI_RESUME0, val);
+ REGV_WR32(MTL_VPU_CPU_SS_MSSCPU_CPR_LEON_RT_VEC, val);
+
+ val = REG_CLR_FLD(MTL_VPU_CPU_SS_MSSCPU_CPR_LEON_RT_VEC, IRQI_RESUME0, val);
+ REGV_WR32(MTL_VPU_CPU_SS_MSSCPU_CPR_LEON_RT_VEC, val);
+
+ val = vdev->fw->entry_point >> 9;
+ REGV_WR32(MTL_VPU_HOST_SS_LOADING_ADDRESS_LO, val);
+
+ val = REG_SET_FLD(MTL_VPU_HOST_SS_LOADING_ADDRESS_LO, DONE, val);
+ REGV_WR32(MTL_VPU_HOST_SS_LOADING_ADDRESS_LO, val);
+
+ ivpu_dbg(vdev, PM, "Booting firmware, mode: %s\n",
+ vdev->fw->entry_point == vdev->fw->cold_boot_entry_point ? "cold boot" : "resume");
+}
+
+static int ivpu_boot_d0i3_drive(struct ivpu_device *vdev, bool enable)
+{
+ int ret;
+ u32 val;
+
+ ret = REGB_POLL_FLD(MTL_BUTTRESS_VPU_D0I3_CONTROL, INPROGRESS, 0, TIMEOUT_US);
+ if (ret) {
+ ivpu_err(vdev, "Failed to sync before D0i3 transition: %d\n", ret);
+ return ret;
+ }
+
+ val = REGB_RD32(MTL_BUTTRESS_VPU_D0I3_CONTROL);
+ if (enable)
+ val = REG_SET_FLD(MTL_BUTTRESS_VPU_D0I3_CONTROL, I3, val);
+ else
+ val = REG_CLR_FLD(MTL_BUTTRESS_VPU_D0I3_CONTROL, I3, val);
+ REGB_WR32(MTL_BUTTRESS_VPU_D0I3_CONTROL, val);
+
+ ret = REGB_POLL_FLD(MTL_BUTTRESS_VPU_D0I3_CONTROL, INPROGRESS, 0, TIMEOUT_US);
+ if (ret)
+ ivpu_err(vdev, "Failed to sync after D0i3 transition: %d\n", ret);
+
+ return ret;
+}
+
+static int ivpu_hw_mtl_info_init(struct ivpu_device *vdev)
+{
+ struct ivpu_hw_info *hw = vdev->hw;
+ u32 tile_fuse;
+
+ tile_fuse = REGB_RD32(MTL_BUTTRESS_TILE_FUSE);
+ if (!REG_TEST_FLD(MTL_BUTTRESS_TILE_FUSE, VALID, tile_fuse))
+ ivpu_warn(vdev, "Tile Fuse: Invalid (0x%x)\n", tile_fuse);
+
+ hw->tile_fuse = REG_GET_FLD(MTL_BUTTRESS_TILE_FUSE, SKU, tile_fuse);
+ switch (hw->tile_fuse) {
+ case TILE_FUSE_ENABLE_LOWER:
+ hw->sku = TILE_SKU_LOWER_MTL;
+ hw->config = WP_CONFIG_1_TILE_5_3_RATIO;
+ ivpu_dbg(vdev, MISC, "Tile Fuse: Enable Lower\n");
+ break;
+ case TILE_FUSE_ENABLE_UPPER:
+ hw->sku = TILE_SKU_UPPER_MTL;
+ hw->config = WP_CONFIG_1_TILE_4_3_RATIO;
+ ivpu_dbg(vdev, MISC, "Tile Fuse: Enable Upper\n");
+ break;
+ case TILE_FUSE_ENABLE_BOTH:
+ hw->sku = TILE_SKU_BOTH_MTL;
+ hw->config = WP_CONFIG_2_TILE_5_3_RATIO;
+ ivpu_dbg(vdev, MISC, "Tile Fuse: Enable Both\n");
+ break;
+ default:
+ hw->config = WP_CONFIG_0_TILE_PLL_OFF;
+ ivpu_dbg(vdev, MISC, "Tile Fuse: Disable\n");
+ break;
+ }
+
+ ivpu_pll_init_frequency_ratios(vdev);
+
+ ivpu_hw_init_range(&hw->ranges.global_low, 0x80000000, SZ_512M);
+ ivpu_hw_init_range(&hw->ranges.global_high, 0x180000000, SZ_2M);
+ ivpu_hw_init_range(&hw->ranges.user_low, 0xc0000000, 255 * SZ_1M);
+ ivpu_hw_init_range(&hw->ranges.user_high, 0x180000000, SZ_2G);
+ hw->ranges.global_aliased_pio = hw->ranges.user_low;
+
+ return 0;
+}
+
+static int ivpu_hw_mtl_reset(struct ivpu_device *vdev)
+{
+ int ret;
+ u32 val;
+
+ if (IVPU_WA(punit_disabled))
+ return 0;
+
+ ret = REGB_POLL_FLD(MTL_BUTTRESS_VPU_IP_RESET, TRIGGER, 0, TIMEOUT_US);
+ if (ret) {
+ ivpu_err(vdev, "Timed out waiting for TRIGGER bit\n");
+ return ret;
+ }
+
+ val = REGB_RD32(MTL_BUTTRESS_VPU_IP_RESET);
+ val = REG_SET_FLD(MTL_BUTTRESS_VPU_IP_RESET, TRIGGER, val);
+ REGB_WR32(MTL_BUTTRESS_VPU_IP_RESET, val);
+
+ ret = REGB_POLL_FLD(MTL_BUTTRESS_VPU_IP_RESET, TRIGGER, 0, TIMEOUT_US);
+ if (ret)
+ ivpu_err(vdev, "Timed out waiting for RESET completion\n");
+
+ return ret;
+}
+
+static int ivpu_hw_mtl_d0i3_enable(struct ivpu_device *vdev)
+{
+ int ret;
+
+ ret = ivpu_boot_d0i3_drive(vdev, true);
+ if (ret)
+ ivpu_err(vdev, "Failed to enable D0i3: %d\n", ret);
+
+ udelay(5); /* VPU requires 5 us to complete the transition */
+
+ return ret;
+}
+
+static int ivpu_hw_mtl_d0i3_disable(struct ivpu_device *vdev)
+{
+ int ret;
+
+ ret = ivpu_boot_d0i3_drive(vdev, false);
+ if (ret)
+ ivpu_err(vdev, "Failed to disable D0i3: %d\n", ret);
+
+ return ret;
+}
+
+static int ivpu_hw_mtl_power_up(struct ivpu_device *vdev)
+{
+ int ret;
+
+ ivpu_hw_read_platform(vdev);
+ ivpu_hw_wa_init(vdev);
+ ivpu_hw_timeouts_init(vdev);
+
+ ret = ivpu_hw_mtl_reset(vdev);
+ if (ret)
+ ivpu_warn(vdev, "Failed to reset HW: %d\n", ret);
+
+ ret = ivpu_hw_mtl_d0i3_disable(vdev);
+ if (ret)
+ ivpu_warn(vdev, "Failed to disable D0I3: %d\n", ret);
+
+ ret = ivpu_pll_enable(vdev);
+ if (ret) {
+ ivpu_err(vdev, "Failed to enable PLL: %d\n", ret);
+ return ret;
+ }
+
+ ret = ivpu_boot_host_ss_configure(vdev);
+ if (ret) {
+ ivpu_err(vdev, "Failed to configure host SS: %d\n", ret);
+ return ret;
+ }
+
+ /*
+ * The control circuitry for vpu_idle indication logic powers up active.
+ * To ensure unnecessary low power mode signal from LRT during bring up,
+ * KMD disables the circuitry prior to bringing up the Main Power island.
+ */
+ ivpu_boot_vpu_idle_gen_disable(vdev);
+
+ ret = ivpu_boot_pwr_domain_enable(vdev);
+ if (ret) {
+ ivpu_err(vdev, "Failed to enable power domain: %d\n", ret);
+ return ret;
+ }
+
+ ret = ivpu_boot_host_ss_axi_enable(vdev);
+ if (ret) {
+ ivpu_err(vdev, "Failed to enable AXI: %d\n", ret);
+ return ret;
+ }
+
+ ret = ivpu_boot_host_ss_top_noc_enable(vdev);
+ if (ret)
+ ivpu_err(vdev, "Failed to enable TOP NOC: %d\n", ret);
+
+ return ret;
+}
+
+static int ivpu_hw_mtl_boot_fw(struct ivpu_device *vdev)
+{
+ ivpu_boot_no_snoop_enable(vdev);
+ ivpu_boot_tbu_mmu_enable(vdev);
+ ivpu_boot_soc_cpu_boot(vdev);
+
+ return 0;
+}
+
+static bool ivpu_hw_mtl_is_idle(struct ivpu_device *vdev)
+{
+ u32 val;
+
+ if (IVPU_WA(punit_disabled))
+ return true;
+
+ val = REGB_RD32(MTL_BUTTRESS_VPU_STATUS);
+ return REG_TEST_FLD(MTL_BUTTRESS_VPU_STATUS, READY, val) &&
+ REG_TEST_FLD(MTL_BUTTRESS_VPU_STATUS, IDLE, val);
+}
+
+static int ivpu_hw_mtl_power_down(struct ivpu_device *vdev)
+{
+ int ret = 0;
+
+ /* FPGA requires manual clearing of IP_Reset bit by enabling quiescent state */
+ if (ivpu_is_fpga(vdev)) {
+ if (ivpu_boot_host_ss_top_noc_disable(vdev)) {
+ ivpu_err(vdev, "Failed to disable TOP NOC\n");
+ ret = -EIO;
+ }
+
+ if (ivpu_boot_host_ss_axi_disable(vdev)) {
+ ivpu_err(vdev, "Failed to disable AXI\n");
+ ret = -EIO;
+ }
+ }
+
+ if (ivpu_boot_pwr_domain_disable(vdev)) {
+ ivpu_err(vdev, "Failed to disable power domain\n");
+ ret = -EIO;
+ }
+
+ if (ivpu_pll_disable(vdev)) {
+ ivpu_err(vdev, "Failed to disable PLL\n");
+ ret = -EIO;
+ }
+
+ if (ivpu_hw_mtl_d0i3_enable(vdev))
+ ivpu_warn(vdev, "Failed to enable D0I3\n");
+
+ return ret;
+}
+
+static void ivpu_hw_mtl_wdt_disable(struct ivpu_device *vdev)
+{
+ u32 val;
+
+ /* Enable writing and set non-zero WDT value */
+ REGV_WR32(MTL_VPU_CPU_SS_TIM_SAFE, TIM_SAFE_ENABLE);
+ REGV_WR32(MTL_VPU_CPU_SS_TIM_WATCHDOG, TIM_WATCHDOG_RESET_VALUE);
+
+ /* Enable writing and disable watchdog timer */
+ REGV_WR32(MTL_VPU_CPU_SS_TIM_SAFE, TIM_SAFE_ENABLE);
+ REGV_WR32(MTL_VPU_CPU_SS_TIM_WDOG_EN, 0);
+
+ /* Now clear the timeout interrupt */
+ val = REGV_RD32(MTL_VPU_CPU_SS_TIM_GEN_CONFIG);
+ val = REG_CLR_FLD(MTL_VPU_CPU_SS_TIM_GEN_CONFIG, WDOG_TO_INT_CLR, val);
+ REGV_WR32(MTL_VPU_CPU_SS_TIM_GEN_CONFIG, val);
+}
+
+/* Register indirect accesses */
+static u32 ivpu_hw_mtl_reg_pll_freq_get(struct ivpu_device *vdev)
+{
+ u32 pll_curr_ratio;
+
+ pll_curr_ratio = REGB_RD32(MTL_BUTTRESS_CURRENT_PLL);
+ pll_curr_ratio &= MTL_BUTTRESS_CURRENT_PLL_RATIO_MASK;
+
+ if (!ivpu_is_silicon(vdev))
+ return PLL_SIMULATION_FREQ;
+
+ return PLL_RATIO_TO_FREQ(pll_curr_ratio);
+}
+
+static u32 ivpu_hw_mtl_reg_telemetry_offset_get(struct ivpu_device *vdev)
+{
+ return REGB_RD32(MTL_BUTTRESS_VPU_TELEMETRY_OFFSET);
+}
+
+static u32 ivpu_hw_mtl_reg_telemetry_size_get(struct ivpu_device *vdev)
+{
+ return REGB_RD32(MTL_BUTTRESS_VPU_TELEMETRY_SIZE);
+}
+
+static u32 ivpu_hw_mtl_reg_telemetry_enable_get(struct ivpu_device *vdev)
+{
+ return REGB_RD32(MTL_BUTTRESS_VPU_TELEMETRY_ENABLE);
+}
+
+static void ivpu_hw_mtl_reg_db_set(struct ivpu_device *vdev, u32 db_id)
+{
+ u32 reg_stride = MTL_VPU_CPU_SS_DOORBELL_1 - MTL_VPU_CPU_SS_DOORBELL_0;
+ u32 val = REG_FLD(MTL_VPU_CPU_SS_DOORBELL_0, SET);
+
+ REGV_WR32I(MTL_VPU_CPU_SS_DOORBELL_0, reg_stride, db_id, val);
+}
+
+static u32 ivpu_hw_mtl_reg_ipc_rx_addr_get(struct ivpu_device *vdev)
+{
+ return REGV_RD32(MTL_VPU_HOST_SS_TIM_IPC_FIFO_ATM);
+}
+
+static u32 ivpu_hw_mtl_reg_ipc_rx_count_get(struct ivpu_device *vdev)
+{
+ u32 count = REGV_RD32_SILENT(MTL_VPU_HOST_SS_TIM_IPC_FIFO_STAT);
+
+ return REG_GET_FLD(MTL_VPU_HOST_SS_TIM_IPC_FIFO_STAT, FILL_LEVEL, count);
+}
+
+static void ivpu_hw_mtl_reg_ipc_tx_set(struct ivpu_device *vdev, u32 vpu_addr)
+{
+ REGV_WR32(MTL_VPU_CPU_SS_TIM_IPC_FIFO, vpu_addr);
+}
+
+static void ivpu_hw_mtl_irq_clear(struct ivpu_device *vdev)
+{
+ REGV_WR64(MTL_VPU_HOST_SS_ICB_CLEAR_0, ICB_0_1_IRQ_MASK);
+}
+
+static void ivpu_hw_mtl_irq_enable(struct ivpu_device *vdev)
+{
+ REGV_WR32(MTL_VPU_HOST_SS_FW_SOC_IRQ_EN, ITF_FIREWALL_VIOLATION_MASK);
+ REGV_WR64(MTL_VPU_HOST_SS_ICB_ENABLE_0, ICB_0_1_IRQ_MASK);
+ REGB_WR32(MTL_BUTTRESS_LOCAL_INT_MASK, BUTTRESS_IRQ_ENABLE_MASK);
+ REGB_WR32(MTL_BUTTRESS_GLOBAL_INT_MASK, 0x0);
+}
+
+static void ivpu_hw_mtl_irq_disable(struct ivpu_device *vdev)
+{
+ REGB_WR32(MTL_BUTTRESS_GLOBAL_INT_MASK, 0x1);
+ REGB_WR32(MTL_BUTTRESS_LOCAL_INT_MASK, BUTTRESS_IRQ_DISABLE_MASK);
+ REGV_WR64(MTL_VPU_HOST_SS_ICB_ENABLE_0, 0x0ull);
+ REGB_WR32(MTL_VPU_HOST_SS_FW_SOC_IRQ_EN, 0x0);
+}
+
+static void ivpu_hw_mtl_irq_wdt_nce_handler(struct ivpu_device *vdev)
+{
+ ivpu_err_ratelimited(vdev, "WDT NCE irq\n");
+
+ ivpu_pm_schedule_recovery(vdev);
+}
+
+static void ivpu_hw_mtl_irq_wdt_mss_handler(struct ivpu_device *vdev)
+{
+ ivpu_err_ratelimited(vdev, "WDT MSS irq\n");
+
+ ivpu_hw_wdt_disable(vdev);
+ ivpu_pm_schedule_recovery(vdev);
+}
+
+static void ivpu_hw_mtl_irq_noc_firewall_handler(struct ivpu_device *vdev)
+{
+ ivpu_err_ratelimited(vdev, "NOC Firewall irq\n");
+
+ ivpu_pm_schedule_recovery(vdev);
+}
+
+/* Handler for IRQs from VPU core (irqV) */
+static u32 ivpu_hw_mtl_irqv_handler(struct ivpu_device *vdev, int irq)
+{
+ u32 status = REGV_RD32(MTL_VPU_HOST_SS_ICB_STATUS_0) & ICB_0_IRQ_MASK;
+
+ REGV_WR32(MTL_VPU_HOST_SS_ICB_CLEAR_0, status);
+
+ if (REG_TEST_FLD(MTL_VPU_HOST_SS_ICB_STATUS_0, MMU_IRQ_0_INT, status))
+ ivpu_mmu_irq_evtq_handler(vdev);
+
+ if (REG_TEST_FLD(MTL_VPU_HOST_SS_ICB_STATUS_0, HOST_IPC_FIFO_INT, status))
+ ivpu_ipc_irq_handler(vdev);
+
+ if (REG_TEST_FLD(MTL_VPU_HOST_SS_ICB_STATUS_0, MMU_IRQ_1_INT, status))
+ ivpu_dbg(vdev, IRQ, "MMU sync complete\n");
+
+ if (REG_TEST_FLD(MTL_VPU_HOST_SS_ICB_STATUS_0, MMU_IRQ_2_INT, status))
+ ivpu_mmu_irq_gerr_handler(vdev);
+
+ if (REG_TEST_FLD(MTL_VPU_HOST_SS_ICB_STATUS_0, CPU_INT_REDIRECT_0_INT, status))
+ ivpu_hw_mtl_irq_wdt_mss_handler(vdev);
+
+ if (REG_TEST_FLD(MTL_VPU_HOST_SS_ICB_STATUS_0, CPU_INT_REDIRECT_1_INT, status))
+ ivpu_hw_mtl_irq_wdt_nce_handler(vdev);
+
+ if (REG_TEST_FLD(MTL_VPU_HOST_SS_ICB_STATUS_0, NOC_FIREWALL_INT, status))
+ ivpu_hw_mtl_irq_noc_firewall_handler(vdev);
+
+ return status;
+}
+
+/* Handler for IRQs from Buttress core (irqB) */
+static u32 ivpu_hw_mtl_irqb_handler(struct ivpu_device *vdev, int irq)
+{
+ u32 status = REGB_RD32(MTL_BUTTRESS_INTERRUPT_STAT) & BUTTRESS_IRQ_MASK;
+ bool schedule_recovery = false;
+
+ if (status == 0)
+ return 0;
+
+ /* Disable global interrupt before handling local buttress interrupts */
+ REGB_WR32(MTL_BUTTRESS_GLOBAL_INT_MASK, 0x1);
+
+ if (REG_TEST_FLD(MTL_BUTTRESS_INTERRUPT_STAT, FREQ_CHANGE, status))
+ ivpu_dbg(vdev, IRQ, "FREQ_CHANGE irq: %08x", REGB_RD32(MTL_BUTTRESS_CURRENT_PLL));
+
+ if (REG_TEST_FLD(MTL_BUTTRESS_INTERRUPT_STAT, ATS_ERR, status)) {
+ ivpu_err(vdev, "ATS_ERR irq 0x%016llx", REGB_RD64(MTL_BUTTRESS_ATS_ERR_LOG_0));
+ REGB_WR32(MTL_BUTTRESS_ATS_ERR_CLEAR, 0x1);
+ schedule_recovery = true;
+ }
+
+ if (REG_TEST_FLD(MTL_BUTTRESS_INTERRUPT_STAT, UFI_ERR, status)) {
+ u32 ufi_log = REGB_RD32(MTL_BUTTRESS_UFI_ERR_LOG);
+
+ ivpu_err(vdev, "UFI_ERR irq (0x%08x) opcode: 0x%02lx axi_id: 0x%02lx cq_id: 0x%03lx",
+ ufi_log, REG_GET_FLD(MTL_BUTTRESS_UFI_ERR_LOG, OPCODE, ufi_log),
+ REG_GET_FLD(MTL_BUTTRESS_UFI_ERR_LOG, AXI_ID, ufi_log),
+ REG_GET_FLD(MTL_BUTTRESS_UFI_ERR_LOG, CQ_ID, ufi_log));
+ REGB_WR32(MTL_BUTTRESS_UFI_ERR_CLEAR, 0x1);
+ schedule_recovery = true;
+ }
+
+ /*
+ * Clear local interrupt status by writing 0 to all bits.
+ * This must be done after interrupts are cleared at the source.
+ * Writing 1 triggers an interrupt, so we can't perform read update write.
+ */
+ REGB_WR32(MTL_BUTTRESS_INTERRUPT_STAT, 0x0);
+
+ /* Re-enable global interrupt */
+ REGB_WR32(MTL_BUTTRESS_GLOBAL_INT_MASK, 0x0);
+
+ if (schedule_recovery)
+ ivpu_pm_schedule_recovery(vdev);
+
+ return status;
+}
+
+static irqreturn_t ivpu_hw_mtl_irq_handler(int irq, void *ptr)
+{
+ struct ivpu_device *vdev = ptr;
+ u32 ret_irqv, ret_irqb;
+
+ ret_irqv = ivpu_hw_mtl_irqv_handler(vdev, irq);
+ ret_irqb = ivpu_hw_mtl_irqb_handler(vdev, irq);
+
+ return IRQ_RETVAL(ret_irqb | ret_irqv);
+}
+
+static void ivpu_hw_mtl_diagnose_failure(struct ivpu_device *vdev)
+{
+ u32 irqv = REGV_RD32(MTL_VPU_HOST_SS_ICB_STATUS_0) & ICB_0_IRQ_MASK;
+ u32 irqb = REGB_RD32(MTL_BUTTRESS_INTERRUPT_STAT) & BUTTRESS_IRQ_MASK;
+
+ if (ivpu_hw_mtl_reg_ipc_rx_count_get(vdev))
+ ivpu_err(vdev, "IPC FIFO queue not empty, missed IPC IRQ");
+
+ if (REG_TEST_FLD(MTL_VPU_HOST_SS_ICB_STATUS_0, CPU_INT_REDIRECT_0_INT, irqv))
+ ivpu_err(vdev, "WDT MSS timeout detected\n");
+
+ if (REG_TEST_FLD(MTL_VPU_HOST_SS_ICB_STATUS_0, CPU_INT_REDIRECT_1_INT, irqv))
+ ivpu_err(vdev, "WDT NCE timeout detected\n");
+
+ if (REG_TEST_FLD(MTL_VPU_HOST_SS_ICB_STATUS_0, NOC_FIREWALL_INT, irqv))
+ ivpu_err(vdev, "NOC Firewall irq detected\n");
+
+ if (REG_TEST_FLD(MTL_BUTTRESS_INTERRUPT_STAT, ATS_ERR, irqb))
+ ivpu_err(vdev, "ATS_ERR irq 0x%016llx", REGB_RD64(MTL_BUTTRESS_ATS_ERR_LOG_0));
+
+ if (REG_TEST_FLD(MTL_BUTTRESS_INTERRUPT_STAT, UFI_ERR, irqb)) {
+ u32 ufi_log = REGB_RD32(MTL_BUTTRESS_UFI_ERR_LOG);
+
+ ivpu_err(vdev, "UFI_ERR irq (0x%08x) opcode: 0x%02lx axi_id: 0x%02lx cq_id: 0x%03lx",
+ ufi_log, REG_GET_FLD(MTL_BUTTRESS_UFI_ERR_LOG, OPCODE, ufi_log),
+ REG_GET_FLD(MTL_BUTTRESS_UFI_ERR_LOG, AXI_ID, ufi_log),
+ REG_GET_FLD(MTL_BUTTRESS_UFI_ERR_LOG, CQ_ID, ufi_log));
+ }
+}
+
+const struct ivpu_hw_ops ivpu_hw_mtl_ops = {
+ .info_init = ivpu_hw_mtl_info_init,
+ .power_up = ivpu_hw_mtl_power_up,
+ .is_idle = ivpu_hw_mtl_is_idle,
+ .power_down = ivpu_hw_mtl_power_down,
+ .boot_fw = ivpu_hw_mtl_boot_fw,
+ .wdt_disable = ivpu_hw_mtl_wdt_disable,
+ .diagnose_failure = ivpu_hw_mtl_diagnose_failure,
+ .reg_pll_freq_get = ivpu_hw_mtl_reg_pll_freq_get,
+ .reg_telemetry_offset_get = ivpu_hw_mtl_reg_telemetry_offset_get,
+ .reg_telemetry_size_get = ivpu_hw_mtl_reg_telemetry_size_get,
+ .reg_telemetry_enable_get = ivpu_hw_mtl_reg_telemetry_enable_get,
+ .reg_db_set = ivpu_hw_mtl_reg_db_set,
+ .reg_ipc_rx_addr_get = ivpu_hw_mtl_reg_ipc_rx_addr_get,
+ .reg_ipc_rx_count_get = ivpu_hw_mtl_reg_ipc_rx_count_get,
+ .reg_ipc_tx_set = ivpu_hw_mtl_reg_ipc_tx_set,
+ .irq_clear = ivpu_hw_mtl_irq_clear,
+ .irq_enable = ivpu_hw_mtl_irq_enable,
+ .irq_disable = ivpu_hw_mtl_irq_disable,
+ .irq_handler = ivpu_hw_mtl_irq_handler,
+};
diff --git a/drivers/accel/ivpu/ivpu_hw_mtl_reg.h b/drivers/accel/ivpu/ivpu_hw_mtl_reg.h
new file mode 100644
index 000000000000..d83ccfd9a871
--- /dev/null
+++ b/drivers/accel/ivpu/ivpu_hw_mtl_reg.h
@@ -0,0 +1,280 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2020-2023 Intel Corporation
+ */
+
+#ifndef __IVPU_HW_MTL_REG_H__
+#define __IVPU_HW_MTL_REG_H__
+
+#include <linux/bits.h>
+
+#define MTL_BUTTRESS_INTERRUPT_TYPE 0x00000000u
+
+#define MTL_BUTTRESS_INTERRUPT_STAT 0x00000004u
+#define MTL_BUTTRESS_INTERRUPT_STAT_FREQ_CHANGE_MASK BIT_MASK(0)
+#define MTL_BUTTRESS_INTERRUPT_STAT_ATS_ERR_MASK BIT_MASK(1)
+#define MTL_BUTTRESS_INTERRUPT_STAT_UFI_ERR_MASK BIT_MASK(2)
+
+#define MTL_BUTTRESS_WP_REQ_PAYLOAD0 0x00000008u
+#define MTL_BUTTRESS_WP_REQ_PAYLOAD0_MIN_RATIO_MASK GENMASK(15, 0)
+#define MTL_BUTTRESS_WP_REQ_PAYLOAD0_MAX_RATIO_MASK GENMASK(31, 16)
+
+#define MTL_BUTTRESS_WP_REQ_PAYLOAD1 0x0000000cu
+#define MTL_BUTTRESS_WP_REQ_PAYLOAD1_TARGET_RATIO_MASK GENMASK(15, 0)
+#define MTL_BUTTRESS_WP_REQ_PAYLOAD1_EPP_MASK GENMASK(31, 16)
+
+#define MTL_BUTTRESS_WP_REQ_PAYLOAD2 0x00000010u
+#define MTL_BUTTRESS_WP_REQ_PAYLOAD2_CONFIG_MASK GENMASK(15, 0)
+
+#define MTL_BUTTRESS_WP_REQ_CMD 0x00000014u
+#define MTL_BUTTRESS_WP_REQ_CMD_SEND_MASK BIT_MASK(0)
+
+#define MTL_BUTTRESS_WP_DOWNLOAD 0x00000018u
+#define MTL_BUTTRESS_WP_DOWNLOAD_TARGET_RATIO_MASK GENMASK(15, 0)
+
+#define MTL_BUTTRESS_CURRENT_PLL 0x0000001cu
+#define MTL_BUTTRESS_CURRENT_PLL_RATIO_MASK GENMASK(15, 0)
+
+#define MTL_BUTTRESS_PLL_ENABLE 0x00000020u
+
+#define MTL_BUTTRESS_FMIN_FUSE 0x00000024u
+#define MTL_BUTTRESS_FMIN_FUSE_MIN_RATIO_MASK GENMASK(7, 0)
+#define MTL_BUTTRESS_FMIN_FUSE_PN_RATIO_MASK GENMASK(15, 8)
+
+#define MTL_BUTTRESS_FMAX_FUSE 0x00000028u
+#define MTL_BUTTRESS_FMAX_FUSE_MAX_RATIO_MASK GENMASK(7, 0)
+
+#define MTL_BUTTRESS_TILE_FUSE 0x0000002cu
+#define MTL_BUTTRESS_TILE_FUSE_VALID_MASK BIT_MASK(0)
+#define MTL_BUTTRESS_TILE_FUSE_SKU_MASK GENMASK(3, 2)
+
+#define MTL_BUTTRESS_LOCAL_INT_MASK 0x00000030u
+#define MTL_BUTTRESS_GLOBAL_INT_MASK 0x00000034u
+
+#define MTL_BUTTRESS_PLL_STATUS 0x00000040u
+#define MTL_BUTTRESS_PLL_STATUS_LOCK_MASK BIT_MASK(1)
+
+#define MTL_BUTTRESS_VPU_STATUS 0x00000044u
+#define MTL_BUTTRESS_VPU_STATUS_READY_MASK BIT_MASK(0)
+#define MTL_BUTTRESS_VPU_STATUS_IDLE_MASK BIT_MASK(1)
+
+#define MTL_BUTTRESS_VPU_D0I3_CONTROL 0x00000060u
+#define MTL_BUTTRESS_VPU_D0I3_CONTROL_INPROGRESS_MASK BIT_MASK(0)
+#define MTL_BUTTRESS_VPU_D0I3_CONTROL_I3_MASK BIT_MASK(2)
+
+#define MTL_BUTTRESS_VPU_IP_RESET 0x00000050u
+#define MTL_BUTTRESS_VPU_IP_RESET_TRIGGER_MASK BIT_MASK(0)
+
+#define MTL_BUTTRESS_VPU_TELEMETRY_OFFSET 0x00000080u
+#define MTL_BUTTRESS_VPU_TELEMETRY_SIZE 0x00000084u
+#define MTL_BUTTRESS_VPU_TELEMETRY_ENABLE 0x00000088u
+
+#define MTL_BUTTRESS_ATS_ERR_LOG_0 0x000000a0u
+#define MTL_BUTTRESS_ATS_ERR_LOG_1 0x000000a4u
+#define MTL_BUTTRESS_ATS_ERR_CLEAR 0x000000a8u
+
+#define MTL_BUTTRESS_UFI_ERR_LOG 0x000000b0u
+#define MTL_BUTTRESS_UFI_ERR_LOG_CQ_ID_MASK GENMASK(11, 0)
+#define MTL_BUTTRESS_UFI_ERR_LOG_AXI_ID_MASK GENMASK(19, 12)
+#define MTL_BUTTRESS_UFI_ERR_LOG_OPCODE_MASK GENMASK(24, 20)
+
+#define MTL_BUTTRESS_UFI_ERR_CLEAR 0x000000b4u
+
+#define MTL_VPU_HOST_SS_CPR_CLK_SET 0x00000084u
+#define MTL_VPU_HOST_SS_CPR_CLK_SET_TOP_NOC_MASK BIT_MASK(1)
+#define MTL_VPU_HOST_SS_CPR_CLK_SET_DSS_MAS_MASK BIT_MASK(10)
+#define MTL_VPU_HOST_SS_CPR_CLK_SET_MSS_MAS_MASK BIT_MASK(11)
+
+#define MTL_VPU_HOST_SS_CPR_RST_SET 0x00000094u
+#define MTL_VPU_HOST_SS_CPR_RST_SET_TOP_NOC_MASK BIT_MASK(1)
+#define MTL_VPU_HOST_SS_CPR_RST_SET_DSS_MAS_MASK BIT_MASK(10)
+#define MTL_VPU_HOST_SS_CPR_RST_SET_MSS_MAS_MASK BIT_MASK(11)
+
+#define MTL_VPU_HOST_SS_CPR_RST_CLR 0x00000098u
+#define MTL_VPU_HOST_SS_CPR_RST_CLR_TOP_NOC_MASK BIT_MASK(1)
+#define MTL_VPU_HOST_SS_CPR_RST_CLR_DSS_MAS_MASK BIT_MASK(10)
+#define MTL_VPU_HOST_SS_CPR_RST_CLR_MSS_MAS_MASK BIT_MASK(11)
+
+#define MTL_VPU_HOST_SS_HW_VERSION 0x00000108u
+#define MTL_VPU_HOST_SS_HW_VERSION_SOC_REVISION_MASK GENMASK(7, 0)
+#define MTL_VPU_HOST_SS_HW_VERSION_SOC_NUMBER_MASK GENMASK(15, 8)
+#define MTL_VPU_HOST_SS_HW_VERSION_VPU_GENERATION_MASK GENMASK(23, 16)
+
+#define MTL_VPU_HOST_SS_GEN_CTRL 0x00000118u
+#define MTL_VPU_HOST_SS_GEN_CTRL_PS_MASK GENMASK(31, 29)
+
+#define MTL_VPU_HOST_SS_NOC_QREQN 0x00000154u
+#define MTL_VPU_HOST_SS_NOC_QREQN_TOP_SOCMMIO_MASK BIT_MASK(0)
+
+#define MTL_VPU_HOST_SS_NOC_QACCEPTN 0x00000158u
+#define MTL_VPU_HOST_SS_NOC_QACCEPTN_TOP_SOCMMIO_MASK BIT_MASK(0)
+
+#define MTL_VPU_HOST_SS_NOC_QDENY 0x0000015cu
+#define MTL_VPU_HOST_SS_NOC_QDENY_TOP_SOCMMIO_MASK BIT_MASK(0)
+
+#define MTL_VPU_TOP_NOC_QREQN 0x00000160u
+#define MTL_VPU_TOP_NOC_QREQN_CPU_CTRL_MASK BIT_MASK(0)
+#define MTL_VPU_TOP_NOC_QREQN_HOSTIF_L2CACHE_MASK BIT_MASK(1)
+
+#define MTL_VPU_TOP_NOC_QACCEPTN 0x00000164u
+#define MTL_VPU_TOP_NOC_QACCEPTN_CPU_CTRL_MASK BIT_MASK(0)
+#define MTL_VPU_TOP_NOC_QACCEPTN_HOSTIF_L2CACHE_MASK BIT_MASK(1)
+
+#define MTL_VPU_TOP_NOC_QDENY 0x00000168u
+#define MTL_VPU_TOP_NOC_QDENY_CPU_CTRL_MASK BIT_MASK(0)
+#define MTL_VPU_TOP_NOC_QDENY_HOSTIF_L2CACHE_MASK BIT_MASK(1)
+
+#define MTL_VPU_HOST_SS_FW_SOC_IRQ_EN 0x00000170u
+#define MTL_VPU_HOST_SS_FW_SOC_IRQ_EN_CSS_ROM_CMX_MASK BIT_MASK(0)
+#define MTL_VPU_HOST_SS_FW_SOC_IRQ_EN_CSS_DBG_MASK BIT_MASK(1)
+#define MTL_VPU_HOST_SS_FW_SOC_IRQ_EN_CSS_CTRL_MASK BIT_MASK(2)
+#define MTL_VPU_HOST_SS_FW_SOC_IRQ_EN_DEC400_MASK BIT_MASK(3)
+#define MTL_VPU_HOST_SS_FW_SOC_IRQ_EN_MSS_NCE_MASK BIT_MASK(4)
+#define MTL_VPU_HOST_SS_FW_SOC_IRQ_EN_MSS_MBI_MASK BIT_MASK(5)
+#define MTL_VPU_HOST_SS_FW_SOC_IRQ_EN_MSS_MBI_CMX_MASK BIT_MASK(6)
+
+#define MTL_VPU_HOST_SS_ICB_STATUS_0 0x00010210u
+#define MTL_VPU_HOST_SS_ICB_STATUS_0_TIMER_0_INT_MASK BIT_MASK(0)
+#define MTL_VPU_HOST_SS_ICB_STATUS_0_TIMER_1_INT_MASK BIT_MASK(1)
+#define MTL_VPU_HOST_SS_ICB_STATUS_0_TIMER_2_INT_MASK BIT_MASK(2)
+#define MTL_VPU_HOST_SS_ICB_STATUS_0_TIMER_3_INT_MASK BIT_MASK(3)
+#define MTL_VPU_HOST_SS_ICB_STATUS_0_HOST_IPC_FIFO_INT_MASK BIT_MASK(4)
+#define MTL_VPU_HOST_SS_ICB_STATUS_0_MMU_IRQ_0_INT_MASK BIT_MASK(5)
+#define MTL_VPU_HOST_SS_ICB_STATUS_0_MMU_IRQ_1_INT_MASK BIT_MASK(6)
+#define MTL_VPU_HOST_SS_ICB_STATUS_0_MMU_IRQ_2_INT_MASK BIT_MASK(7)
+#define MTL_VPU_HOST_SS_ICB_STATUS_0_NOC_FIREWALL_INT_MASK BIT_MASK(8)
+#define MTL_VPU_HOST_SS_ICB_STATUS_0_CPU_INT_REDIRECT_0_INT_MASK BIT_MASK(30)
+#define MTL_VPU_HOST_SS_ICB_STATUS_0_CPU_INT_REDIRECT_1_INT_MASK BIT_MASK(31)
+
+#define MTL_VPU_HOST_SS_ICB_STATUS_1 0x00010214u
+#define MTL_VPU_HOST_SS_ICB_STATUS_1_CPU_INT_REDIRECT_2_INT_MASK BIT_MASK(0)
+#define MTL_VPU_HOST_SS_ICB_STATUS_1_CPU_INT_REDIRECT_3_INT_MASK BIT_MASK(1)
+#define MTL_VPU_HOST_SS_ICB_STATUS_1_CPU_INT_REDIRECT_4_INT_MASK BIT_MASK(2)
+
+#define MTL_VPU_HOST_SS_ICB_CLEAR_0 0x00010220u
+#define MTL_VPU_HOST_SS_ICB_CLEAR_1 0x00010224u
+#define MTL_VPU_HOST_SS_ICB_ENABLE_0 0x00010240u
+
+#define MTL_VPU_HOST_SS_TIM_IPC_FIFO_ATM 0x000200f4u
+
+#define MTL_VPU_HOST_SS_TIM_IPC_FIFO_STAT 0x000200fcu
+#define MTL_VPU_HOST_SS_TIM_IPC_FIFO_STAT_READ_POINTER_MASK GENMASK(7, 0)
+#define MTL_VPU_HOST_SS_TIM_IPC_FIFO_STAT_WRITE_POINTER_MASK GENMASK(15, 8)
+#define MTL_VPU_HOST_SS_TIM_IPC_FIFO_STAT_FILL_LEVEL_MASK GENMASK(23, 16)
+#define MTL_VPU_HOST_SS_TIM_IPC_FIFO_STAT_RSVD0_MASK GENMASK(31, 24)
+
+#define MTL_VPU_HOST_SS_AON_PWR_ISO_EN0 0x00030020u
+#define MTL_VPU_HOST_SS_AON_PWR_ISO_EN0_MSS_CPU_MASK BIT_MASK(3)
+
+#define MTL_VPU_HOST_SS_AON_PWR_ISLAND_EN0 0x00030024u
+#define MTL_VPU_HOST_SS_AON_PWR_ISLAND_EN0_MSS_CPU_MASK BIT_MASK(3)
+
+#define MTL_VPU_HOST_SS_AON_PWR_ISLAND_TRICKLE_EN0 0x00030028u
+#define MTL_VPU_HOST_SS_AON_PWR_ISLAND_TRICKLE_EN0_MSS_CPU_MASK BIT_MASK(3)
+
+#define MTL_VPU_HOST_SS_AON_PWR_ISLAND_STATUS0 0x0003002cu
+#define MTL_VPU_HOST_SS_AON_PWR_ISLAND_STATUS0_MSS_CPU_MASK BIT_MASK(3)
+
+#define MTL_VPU_HOST_SS_AON_VPU_IDLE_GEN 0x00030200u
+#define MTL_VPU_HOST_SS_AON_VPU_IDLE_GEN_EN_MASK BIT_MASK(0)
+
+#define MTL_VPU_HOST_SS_AON_DPU_ACTIVE 0x00030204u
+#define MTL_VPU_HOST_SS_AON_DPU_ACTIVE_DPU_ACTIVE_MASK BIT_MASK(0)
+
+#define MTL_VPU_HOST_SS_LOADING_ADDRESS_LO 0x00041040u
+#define MTL_VPU_HOST_SS_LOADING_ADDRESS_LO_DONE_MASK BIT_MASK(0)
+#define MTL_VPU_HOST_SS_LOADING_ADDRESS_LO_IOSF_RS_ID_MASK GENMASK(2, 1)
+#define MTL_VPU_HOST_SS_LOADING_ADDRESS_LO_IMAGE_LOCATION_MASK GENMASK(31, 3)
+
+#define MTL_VPU_HOST_SS_WORKPOINT_CONFIG_MIRROR 0x00082020u
+#define MTL_VPU_HOST_SS_WORKPOINT_CONFIG_MIRROR_FINAL_PLL_FREQ_MASK GENMASK(15, 0)
+#define MTL_VPU_HOST_SS_WORKPOINT_CONFIG_MIRROR_CONFIG_ID_MASK GENMASK(31, 16)
+
+#define MTL_VPU_HOST_MMU_IDR0 0x00200000u
+#define MTL_VPU_HOST_MMU_IDR1 0x00200004u
+#define MTL_VPU_HOST_MMU_IDR3 0x0020000cu
+#define MTL_VPU_HOST_MMU_IDR5 0x00200014u
+#define MTL_VPU_HOST_MMU_CR0 0x00200020u
+#define MTL_VPU_HOST_MMU_CR0ACK 0x00200024u
+#define MTL_VPU_HOST_MMU_CR1 0x00200028u
+#define MTL_VPU_HOST_MMU_CR2 0x0020002cu
+#define MTL_VPU_HOST_MMU_IRQ_CTRL 0x00200050u
+#define MTL_VPU_HOST_MMU_IRQ_CTRLACK 0x00200054u
+
+#define MTL_VPU_HOST_MMU_GERROR 0x00200060u
+#define MTL_VPU_HOST_MMU_GERROR_CMDQ_MASK BIT_MASK(0)
+#define MTL_VPU_HOST_MMU_GERROR_EVTQ_ABT_MASK BIT_MASK(2)
+#define MTL_VPU_HOST_MMU_GERROR_PRIQ_ABT_MASK BIT_MASK(3)
+#define MTL_VPU_HOST_MMU_GERROR_MSI_CMDQ_ABT_MASK BIT_MASK(4)
+#define MTL_VPU_HOST_MMU_GERROR_MSI_EVTQ_ABT_MASK BIT_MASK(5)
+#define MTL_VPU_HOST_MMU_GERROR_MSI_PRIQ_ABT_MASK BIT_MASK(6)
+#define MTL_VPU_HOST_MMU_GERROR_MSI_ABT_MASK BIT_MASK(7)
+
+#define MTL_VPU_HOST_MMU_GERRORN 0x00200064u
+
+#define MTL_VPU_HOST_MMU_STRTAB_BASE 0x00200080u
+#define MTL_VPU_HOST_MMU_STRTAB_BASE_CFG 0x00200088u
+#define MTL_VPU_HOST_MMU_CMDQ_BASE 0x00200090u
+#define MTL_VPU_HOST_MMU_CMDQ_PROD 0x00200098u
+#define MTL_VPU_HOST_MMU_CMDQ_CONS 0x0020009cu
+#define MTL_VPU_HOST_MMU_EVTQ_BASE 0x002000a0u
+#define MTL_VPU_HOST_MMU_EVTQ_PROD 0x002000a8u
+#define MTL_VPU_HOST_MMU_EVTQ_CONS 0x002000acu
+#define MTL_VPU_HOST_MMU_EVTQ_PROD_SEC (0x002000a8u + SZ_64K)
+#define MTL_VPU_HOST_MMU_EVTQ_CONS_SEC (0x002000acu + SZ_64K)
+
+#define MTL_VPU_HOST_IF_TCU_PTW_OVERRIDES 0x00360000u
+#define MTL_VPU_HOST_IF_TCU_PTW_OVERRIDES_CACHE_OVERRIDE_EN_MASK BIT_MASK(0)
+#define MTL_VPU_HOST_IF_TCU_PTW_OVERRIDES_AWCACHE_OVERRIDE_MASK BIT_MASK(1)
+#define MTL_VPU_HOST_IF_TCU_PTW_OVERRIDES_ARCACHE_OVERRIDE_MASK BIT_MASK(2)
+#define MTL_VPU_HOST_IF_TCU_PTW_OVERRIDES_NOSNOOP_OVERRIDE_EN_MASK BIT_MASK(3)
+#define MTL_VPU_HOST_IF_TCU_PTW_OVERRIDES_AW_NOSNOOP_OVERRIDE_MASK BIT_MASK(4)
+#define MTL_VPU_HOST_IF_TCU_PTW_OVERRIDES_AR_NOSNOOP_OVERRIDE_MASK BIT_MASK(5)
+#define MTL_VPU_HOST_IF_TCU_PTW_OVERRIDES_PTW_AW_CONTEXT_FLAG_MASK GENMASK(10, 6)
+#define MTL_VPU_HOST_IF_TCU_PTW_OVERRIDES_PTW_AR_CONTEXT_FLAG_MASK GENMASK(15, 11)
+
+#define MTL_VPU_HOST_IF_TBU_MMUSSIDV 0x00360004u
+#define MTL_VPU_HOST_IF_TBU_MMUSSIDV_TBU0_AWMMUSSIDV_MASK BIT_MASK(0)
+#define MTL_VPU_HOST_IF_TBU_MMUSSIDV_TBU0_ARMMUSSIDV_MASK BIT_MASK(1)
+#define MTL_VPU_HOST_IF_TBU_MMUSSIDV_TBU1_AWMMUSSIDV_MASK BIT_MASK(2)
+#define MTL_VPU_HOST_IF_TBU_MMUSSIDV_TBU1_ARMMUSSIDV_MASK BIT_MASK(3)
+#define MTL_VPU_HOST_IF_TBU_MMUSSIDV_TBU2_AWMMUSSIDV_MASK BIT_MASK(4)
+#define MTL_VPU_HOST_IF_TBU_MMUSSIDV_TBU2_ARMMUSSIDV_MASK BIT_MASK(5)
+#define MTL_VPU_HOST_IF_TBU_MMUSSIDV_TBU3_AWMMUSSIDV_MASK BIT_MASK(6)
+#define MTL_VPU_HOST_IF_TBU_MMUSSIDV_TBU3_ARMMUSSIDV_MASK BIT_MASK(7)
+#define MTL_VPU_HOST_IF_TBU_MMUSSIDV_TBU4_AWMMUSSIDV_MASK BIT_MASK(8)
+#define MTL_VPU_HOST_IF_TBU_MMUSSIDV_TBU4_ARMMUSSIDV_MASK BIT_MASK(9)
+
+#define MTL_VPU_CPU_SS_DSU_LEON_RT_BASE 0x04000000u
+#define MTL_VPU_CPU_SS_DSU_LEON_RT_DSU_CTRL 0x04000000u
+#define MTL_VPU_CPU_SS_DSU_LEON_RT_PC_REG 0x04400010u
+#define MTL_VPU_CPU_SS_DSU_LEON_RT_NPC_REG 0x04400014u
+#define MTL_VPU_CPU_SS_DSU_LEON_RT_DSU_TRAP_REG 0x04400020u
+
+#define MTL_VPU_CPU_SS_MSSCPU_CPR_CLK_SET 0x06010004u
+#define MTL_VPU_CPU_SS_MSSCPU_CPR_CLK_SET_CPU_DSU_MASK BIT_MASK(1)
+
+#define MTL_VPU_CPU_SS_MSSCPU_CPR_RST_CLR 0x06010018u
+#define MTL_VPU_CPU_SS_MSSCPU_CPR_RST_CLR_CPU_DSU_MASK BIT_MASK(1)
+
+#define MTL_VPU_CPU_SS_MSSCPU_CPR_LEON_RT_VEC 0x06010040u
+#define MTL_VPU_CPU_SS_MSSCPU_CPR_LEON_RT_VEC_IRQI_RSTRUN0_MASK BIT_MASK(0)
+#define MTL_VPU_CPU_SS_MSSCPU_CPR_LEON_RT_VEC_IRQI_RESUME0_MASK BIT_MASK(1)
+#define MTL_VPU_CPU_SS_MSSCPU_CPR_LEON_RT_VEC_IRQI_RSTRUN1_MASK BIT_MASK(2)
+#define MTL_VPU_CPU_SS_MSSCPU_CPR_LEON_RT_VEC_IRQI_RESUME1_MASK BIT_MASK(3)
+#define MTL_VPU_CPU_SS_MSSCPU_CPR_LEON_RT_VEC_IRQI_RSTVEC_MASK GENMASK(31, 4)
+
+#define MTL_VPU_CPU_SS_TIM_WATCHDOG 0x0602009cu
+#define MTL_VPU_CPU_SS_TIM_WDOG_EN 0x060200a4u
+#define MTL_VPU_CPU_SS_TIM_SAFE 0x060200a8u
+#define MTL_VPU_CPU_SS_TIM_IPC_FIFO 0x060200f0u
+
+#define MTL_VPU_CPU_SS_TIM_GEN_CONFIG 0x06021008u
+#define MTL_VPU_CPU_SS_TIM_GEN_CONFIG_WDOG_TO_INT_CLR_MASK BIT_MASK(9)
+
+#define MTL_VPU_CPU_SS_DOORBELL_0 0x06300000u
+#define MTL_VPU_CPU_SS_DOORBELL_0_SET_MASK BIT_MASK(0)
+
+#define MTL_VPU_CPU_SS_DOORBELL_1 0x06301000u
+
+#endif /* __IVPU_HW_MTL_REG_H__ */
diff --git a/drivers/accel/ivpu/ivpu_hw_reg_io.h b/drivers/accel/ivpu/ivpu_hw_reg_io.h
new file mode 100644
index 000000000000..43c2c0c2d050
--- /dev/null
+++ b/drivers/accel/ivpu/ivpu_hw_reg_io.h
@@ -0,0 +1,115 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2020-2023 Intel Corporation
+ */
+
+#ifndef __IVPU_HW_REG_IO_H__
+#define __IVPU_HW_REG_IO_H__
+
+#include <linux/bitfield.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+
+#include "ivpu_drv.h"
+
+#define REG_POLL_SLEEP_US 50
+#define REG_IO_ERROR 0xffffffff
+
+#define REGB_RD32(reg) ivpu_hw_reg_rd32(vdev, vdev->regb, (reg), #reg, __func__)
+#define REGB_RD32_SILENT(reg) readl(vdev->regb + (reg))
+#define REGB_RD64(reg) ivpu_hw_reg_rd64(vdev, vdev->regb, (reg), #reg, __func__)
+#define REGB_WR32(reg, val) ivpu_hw_reg_wr32(vdev, vdev->regb, (reg), (val), #reg, __func__)
+#define REGB_WR64(reg, val) ivpu_hw_reg_wr64(vdev, vdev->regb, (reg), (val), #reg, __func__)
+
+#define REGV_RD32(reg) ivpu_hw_reg_rd32(vdev, vdev->regv, (reg), #reg, __func__)
+#define REGV_RD32_SILENT(reg) readl(vdev->regv + (reg))
+#define REGV_RD64(reg) ivpu_hw_reg_rd64(vdev, vdev->regv, (reg), #reg, __func__)
+#define REGV_WR32(reg, val) ivpu_hw_reg_wr32(vdev, vdev->regv, (reg), (val), #reg, __func__)
+#define REGV_WR64(reg, val) ivpu_hw_reg_wr64(vdev, vdev->regv, (reg), (val), #reg, __func__)
+
+#define REGV_WR32I(reg, stride, index, val) \
+ ivpu_hw_reg_wr32_index(vdev, vdev->regv, (reg), (stride), (index), (val), #reg, __func__)
+
+#define REG_FLD(REG, FLD) \
+ (REG##_##FLD##_MASK)
+#define REG_FLD_NUM(REG, FLD, num) \
+ FIELD_PREP(REG##_##FLD##_MASK, num)
+#define REG_GET_FLD(REG, FLD, val) \
+ FIELD_GET(REG##_##FLD##_MASK, val)
+#define REG_CLR_FLD(REG, FLD, val) \
+ ((val) & ~(REG##_##FLD##_MASK))
+#define REG_SET_FLD(REG, FLD, val) \
+ ((val) | (REG##_##FLD##_MASK))
+#define REG_SET_FLD_NUM(REG, FLD, num, val) \
+ (((val) & ~(REG##_##FLD##_MASK)) | FIELD_PREP(REG##_##FLD##_MASK, num))
+#define REG_TEST_FLD(REG, FLD, val) \
+ ((REG##_##FLD##_MASK) == ((val) & (REG##_##FLD##_MASK)))
+#define REG_TEST_FLD_NUM(REG, FLD, num, val) \
+ ((num) == FIELD_GET(REG##_##FLD##_MASK, val))
+
+#define REGB_POLL(reg, var, cond, timeout_us) \
+ read_poll_timeout(REGB_RD32_SILENT, var, cond, REG_POLL_SLEEP_US, timeout_us, false, reg)
+
+#define REGV_POLL(reg, var, cond, timeout_us) \
+ read_poll_timeout(REGV_RD32_SILENT, var, cond, REG_POLL_SLEEP_US, timeout_us, false, reg)
+
+#define REGB_POLL_FLD(reg, fld, val, timeout_us) \
+({ \
+ u32 var; \
+ REGB_POLL(reg, var, (FIELD_GET(reg##_##fld##_MASK, var) == (val)), timeout_us); \
+})
+
+#define REGV_POLL_FLD(reg, fld, val, timeout_us) \
+({ \
+ u32 var; \
+ REGV_POLL(reg, var, (FIELD_GET(reg##_##fld##_MASK, var) == (val)), timeout_us); \
+})
+
+static inline u32
+ivpu_hw_reg_rd32(struct ivpu_device *vdev, void __iomem *base, u32 reg,
+ const char *name, const char *func)
+{
+ u32 val = readl(base + reg);
+
+ ivpu_dbg(vdev, REG, "%s RD: %s (0x%08x) => 0x%08x\n", func, name, reg, val);
+ return val;
+}
+
+static inline u64
+ivpu_hw_reg_rd64(struct ivpu_device *vdev, void __iomem *base, u32 reg,
+ const char *name, const char *func)
+{
+ u64 val = readq(base + reg);
+
+ ivpu_dbg(vdev, REG, "%s RD: %s (0x%08x) => 0x%016llx\n", func, name, reg, val);
+ return val;
+}
+
+static inline void
+ivpu_hw_reg_wr32(struct ivpu_device *vdev, void __iomem *base, u32 reg, u32 val,
+ const char *name, const char *func)
+{
+ ivpu_dbg(vdev, REG, "%s WR: %s (0x%08x) <= 0x%08x\n", func, name, reg, val);
+ writel(val, base + reg);
+}
+
+static inline void
+ivpu_hw_reg_wr64(struct ivpu_device *vdev, void __iomem *base, u32 reg, u64 val,
+ const char *name, const char *func)
+{
+ ivpu_dbg(vdev, REG, "%s WR: %s (0x%08x) <= 0x%016llx\n", func, name, reg, val);
+ writeq(val, base + reg);
+}
+
+static inline void
+ivpu_hw_reg_wr32_index(struct ivpu_device *vdev, void __iomem *base, u32 reg,
+ u32 stride, u32 index, u32 val, const char *name,
+ const char *func)
+{
+ reg += index * stride;
+
+ ivpu_dbg(vdev, REG, "%s WR: %s_%d (0x%08x) <= 0x%08x\n", func, name, index, reg, val);
+ writel(val, base + reg);
+}
+
+#endif /* __IVPU_HW_REG_IO_H__ */
diff --git a/drivers/accel/ivpu/ivpu_ipc.c b/drivers/accel/ivpu/ivpu_ipc.c
new file mode 100644
index 000000000000..3adcfa80fc0e
--- /dev/null
+++ b/drivers/accel/ivpu/ivpu_ipc.c
@@ -0,0 +1,510 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2020-2023 Intel Corporation
+ */
+
+#include <linux/genalloc.h>
+#include <linux/highmem.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+
+#include "ivpu_drv.h"
+#include "ivpu_gem.h"
+#include "ivpu_hw.h"
+#include "ivpu_hw_reg_io.h"
+#include "ivpu_ipc.h"
+#include "ivpu_jsm_msg.h"
+#include "ivpu_pm.h"
+
+#define IPC_MAX_RX_MSG 128
+#define IS_KTHREAD() (get_current()->flags & PF_KTHREAD)
+
+struct ivpu_ipc_tx_buf {
+ struct ivpu_ipc_hdr ipc;
+ struct vpu_jsm_msg jsm;
+};
+
+struct ivpu_ipc_rx_msg {
+ struct list_head link;
+ struct ivpu_ipc_hdr *ipc_hdr;
+ struct vpu_jsm_msg *jsm_msg;
+};
+
+static void ivpu_ipc_msg_dump(struct ivpu_device *vdev, char *c,
+ struct ivpu_ipc_hdr *ipc_hdr, u32 vpu_addr)
+{
+ ivpu_dbg(vdev, IPC,
+ "%s: vpu:0x%x (data_addr:0x%08x, data_size:0x%x, channel:0x%x, src_node:0x%x, dst_node:0x%x, status:0x%x)",
+ c, vpu_addr, ipc_hdr->data_addr, ipc_hdr->data_size, ipc_hdr->channel,
+ ipc_hdr->src_node, ipc_hdr->dst_node, ipc_hdr->status);
+}
+
+static void ivpu_jsm_msg_dump(struct ivpu_device *vdev, char *c,
+ struct vpu_jsm_msg *jsm_msg, u32 vpu_addr)
+{
+ u32 *payload = (u32 *)&jsm_msg->payload;
+
+ ivpu_dbg(vdev, JSM,
+ "%s: vpu:0x%08x (type:0x%x, status:0x%x, id: 0x%x, result: 0x%x, payload:0x%x 0x%x 0x%x 0x%x 0x%x)\n",
+ c, vpu_addr, jsm_msg->type, jsm_msg->status, jsm_msg->request_id, jsm_msg->result,
+ payload[0], payload[1], payload[2], payload[3], payload[4]);
+}
+
+static void
+ivpu_ipc_rx_mark_free(struct ivpu_device *vdev, struct ivpu_ipc_hdr *ipc_hdr,
+ struct vpu_jsm_msg *jsm_msg)
+{
+ ipc_hdr->status = IVPU_IPC_HDR_FREE;
+ if (jsm_msg)
+ jsm_msg->status = VPU_JSM_MSG_FREE;
+ wmb(); /* Flush WC buffers for message statuses */
+}
+
+static void ivpu_ipc_mem_fini(struct ivpu_device *vdev)
+{
+ struct ivpu_ipc_info *ipc = vdev->ipc;
+
+ ivpu_bo_free_internal(ipc->mem_rx);
+ ivpu_bo_free_internal(ipc->mem_tx);
+}
+
+static int
+ivpu_ipc_tx_prepare(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons,
+ struct vpu_jsm_msg *req)
+{
+ struct ivpu_ipc_info *ipc = vdev->ipc;
+ struct ivpu_ipc_tx_buf *tx_buf;
+ u32 tx_buf_vpu_addr;
+ u32 jsm_vpu_addr;
+
+ tx_buf_vpu_addr = gen_pool_alloc(ipc->mm_tx, sizeof(*tx_buf));
+ if (!tx_buf_vpu_addr) {
+ ivpu_err(vdev, "Failed to reserve IPC buffer, size %ld\n",
+ sizeof(*tx_buf));
+ return -ENOMEM;
+ }
+
+ tx_buf = ivpu_to_cpu_addr(ipc->mem_tx, tx_buf_vpu_addr);
+ if (drm_WARN_ON(&vdev->drm, !tx_buf)) {
+ gen_pool_free(ipc->mm_tx, tx_buf_vpu_addr, sizeof(*tx_buf));
+ return -EIO;
+ }
+
+ jsm_vpu_addr = tx_buf_vpu_addr + offsetof(struct ivpu_ipc_tx_buf, jsm);
+
+ if (tx_buf->ipc.status != IVPU_IPC_HDR_FREE)
+ ivpu_warn(vdev, "IPC message vpu:0x%x not released by firmware\n",
+ tx_buf_vpu_addr);
+
+ if (tx_buf->jsm.status != VPU_JSM_MSG_FREE)
+ ivpu_warn(vdev, "JSM message vpu:0x%x not released by firmware\n",
+ jsm_vpu_addr);
+
+ memset(tx_buf, 0, sizeof(*tx_buf));
+ tx_buf->ipc.data_addr = jsm_vpu_addr;
+ /* TODO: Set data_size to actual JSM message size, not union of all messages */
+ tx_buf->ipc.data_size = sizeof(*req);
+ tx_buf->ipc.channel = cons->channel;
+ tx_buf->ipc.src_node = 0;
+ tx_buf->ipc.dst_node = 1;
+ tx_buf->ipc.status = IVPU_IPC_HDR_ALLOCATED;
+ tx_buf->jsm.type = req->type;
+ tx_buf->jsm.status = VPU_JSM_MSG_ALLOCATED;
+ tx_buf->jsm.payload = req->payload;
+
+ req->request_id = atomic_inc_return(&ipc->request_id);
+ tx_buf->jsm.request_id = req->request_id;
+ cons->request_id = req->request_id;
+ wmb(); /* Flush WC buffers for IPC, JSM msgs */
+
+ cons->tx_vpu_addr = tx_buf_vpu_addr;
+
+ ivpu_jsm_msg_dump(vdev, "TX", &tx_buf->jsm, jsm_vpu_addr);
+ ivpu_ipc_msg_dump(vdev, "TX", &tx_buf->ipc, tx_buf_vpu_addr);
+
+ return 0;
+}
+
+static void ivpu_ipc_tx_release(struct ivpu_device *vdev, u32 vpu_addr)
+{
+ struct ivpu_ipc_info *ipc = vdev->ipc;
+
+ if (vpu_addr)
+ gen_pool_free(ipc->mm_tx, vpu_addr, sizeof(struct ivpu_ipc_tx_buf));
+}
+
+static void ivpu_ipc_tx(struct ivpu_device *vdev, u32 vpu_addr)
+{
+ ivpu_hw_reg_ipc_tx_set(vdev, vpu_addr);
+}
+
+void
+ivpu_ipc_consumer_add(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, u32 channel)
+{
+ struct ivpu_ipc_info *ipc = vdev->ipc;
+
+ INIT_LIST_HEAD(&cons->link);
+ cons->channel = channel;
+ cons->tx_vpu_addr = 0;
+ cons->request_id = 0;
+ spin_lock_init(&cons->rx_msg_lock);
+ INIT_LIST_HEAD(&cons->rx_msg_list);
+ init_waitqueue_head(&cons->rx_msg_wq);
+
+ spin_lock_irq(&ipc->cons_list_lock);
+ list_add_tail(&cons->link, &ipc->cons_list);
+ spin_unlock_irq(&ipc->cons_list_lock);
+}
+
+void ivpu_ipc_consumer_del(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons)
+{
+ struct ivpu_ipc_info *ipc = vdev->ipc;
+ struct ivpu_ipc_rx_msg *rx_msg, *r;
+
+ spin_lock_irq(&ipc->cons_list_lock);
+ list_del(&cons->link);
+ spin_unlock_irq(&ipc->cons_list_lock);
+
+ spin_lock_irq(&cons->rx_msg_lock);
+ list_for_each_entry_safe(rx_msg, r, &cons->rx_msg_list, link) {
+ list_del(&rx_msg->link);
+ ivpu_ipc_rx_mark_free(vdev, rx_msg->ipc_hdr, rx_msg->jsm_msg);
+ atomic_dec(&ipc->rx_msg_count);
+ kfree(rx_msg);
+ }
+ spin_unlock_irq(&cons->rx_msg_lock);
+
+ ivpu_ipc_tx_release(vdev, cons->tx_vpu_addr);
+}
+
+static int
+ivpu_ipc_send(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, struct vpu_jsm_msg *req)
+{
+ struct ivpu_ipc_info *ipc = vdev->ipc;
+ int ret;
+
+ ret = mutex_lock_interruptible(&ipc->lock);
+ if (ret)
+ return ret;
+
+ if (!ipc->on) {
+ ret = -EAGAIN;
+ goto unlock;
+ }
+
+ ret = ivpu_ipc_tx_prepare(vdev, cons, req);
+ if (ret)
+ goto unlock;
+
+ ivpu_ipc_tx(vdev, cons->tx_vpu_addr);
+
+unlock:
+ mutex_unlock(&ipc->lock);
+ return ret;
+}
+
+int ivpu_ipc_receive(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons,
+ struct ivpu_ipc_hdr *ipc_buf,
+ struct vpu_jsm_msg *ipc_payload, unsigned long timeout_ms)
+{
+ struct ivpu_ipc_info *ipc = vdev->ipc;
+ struct ivpu_ipc_rx_msg *rx_msg;
+ int wait_ret, ret = 0;
+
+ wait_ret = wait_event_interruptible_timeout(cons->rx_msg_wq,
+ (IS_KTHREAD() && kthread_should_stop()) ||
+ !list_empty(&cons->rx_msg_list),
+ msecs_to_jiffies(timeout_ms));
+
+ if (IS_KTHREAD() && kthread_should_stop())
+ return -EINTR;
+
+ if (wait_ret == 0)
+ return -ETIMEDOUT;
+
+ if (wait_ret < 0)
+ return -ERESTARTSYS;
+
+ spin_lock_irq(&cons->rx_msg_lock);
+ rx_msg = list_first_entry_or_null(&cons->rx_msg_list, struct ivpu_ipc_rx_msg, link);
+ if (!rx_msg) {
+ spin_unlock_irq(&cons->rx_msg_lock);
+ return -EAGAIN;
+ }
+ list_del(&rx_msg->link);
+ spin_unlock_irq(&cons->rx_msg_lock);
+
+ if (ipc_buf)
+ memcpy(ipc_buf, rx_msg->ipc_hdr, sizeof(*ipc_buf));
+ if (rx_msg->jsm_msg) {
+ u32 size = min_t(int, rx_msg->ipc_hdr->data_size, sizeof(*ipc_payload));
+
+ if (rx_msg->jsm_msg->result != VPU_JSM_STATUS_SUCCESS) {
+ ivpu_dbg(vdev, IPC, "IPC resp result error: %d\n", rx_msg->jsm_msg->result);
+ ret = -EBADMSG;
+ }
+
+ if (ipc_payload)
+ memcpy(ipc_payload, rx_msg->jsm_msg, size);
+ }
+
+ ivpu_ipc_rx_mark_free(vdev, rx_msg->ipc_hdr, rx_msg->jsm_msg);
+ atomic_dec(&ipc->rx_msg_count);
+ kfree(rx_msg);
+
+ return ret;
+}
+
+static int
+ivpu_ipc_send_receive_internal(struct ivpu_device *vdev, struct vpu_jsm_msg *req,
+ enum vpu_ipc_msg_type expected_resp_type,
+ struct vpu_jsm_msg *resp, u32 channel,
+ unsigned long timeout_ms)
+{
+ struct ivpu_ipc_consumer cons;
+ int ret;
+
+ ivpu_ipc_consumer_add(vdev, &cons, channel);
+
+ ret = ivpu_ipc_send(vdev, &cons, req);
+ if (ret) {
+ ivpu_warn(vdev, "IPC send failed: %d\n", ret);
+ goto consumer_del;
+ }
+
+ ret = ivpu_ipc_receive(vdev, &cons, NULL, resp, timeout_ms);
+ if (ret) {
+ ivpu_warn(vdev, "IPC receive failed: type 0x%x, ret %d\n", req->type, ret);
+ goto consumer_del;
+ }
+
+ if (resp->type != expected_resp_type) {
+ ivpu_warn(vdev, "Invalid JSM response type: 0x%x\n", resp->type);
+ ret = -EBADE;
+ }
+
+consumer_del:
+ ivpu_ipc_consumer_del(vdev, &cons);
+ return ret;
+}
+
+int ivpu_ipc_send_receive(struct ivpu_device *vdev, struct vpu_jsm_msg *req,
+ enum vpu_ipc_msg_type expected_resp_type,
+ struct vpu_jsm_msg *resp, u32 channel,
+ unsigned long timeout_ms)
+{
+ struct vpu_jsm_msg hb_req = { .type = VPU_JSM_MSG_QUERY_ENGINE_HB };
+ struct vpu_jsm_msg hb_resp;
+ int ret, hb_ret;
+
+ ret = ivpu_rpm_get(vdev);
+ if (ret < 0)
+ return ret;
+
+ ret = ivpu_ipc_send_receive_internal(vdev, req, expected_resp_type, resp,
+ channel, timeout_ms);
+ if (ret != -ETIMEDOUT)
+ goto rpm_put;
+
+ hb_ret = ivpu_ipc_send_receive_internal(vdev, &hb_req, VPU_JSM_MSG_QUERY_ENGINE_HB_DONE,
+ &hb_resp, VPU_IPC_CHAN_ASYNC_CMD,
+ vdev->timeout.jsm);
+ if (hb_ret == -ETIMEDOUT) {
+ ivpu_hw_diagnose_failure(vdev);
+ ivpu_pm_schedule_recovery(vdev);
+ }
+
+rpm_put:
+ ivpu_rpm_put(vdev);
+ return ret;
+}
+
+static bool
+ivpu_ipc_match_consumer(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons,
+ struct ivpu_ipc_hdr *ipc_hdr, struct vpu_jsm_msg *jsm_msg)
+{
+ if (cons->channel != ipc_hdr->channel)
+ return false;
+
+ if (!jsm_msg || jsm_msg->request_id == cons->request_id)
+ return true;
+
+ return false;
+}
+
+static void
+ivpu_ipc_dispatch(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons,
+ struct ivpu_ipc_hdr *ipc_hdr, struct vpu_jsm_msg *jsm_msg)
+{
+ struct ivpu_ipc_info *ipc = vdev->ipc;
+ struct ivpu_ipc_rx_msg *rx_msg;
+ unsigned long flags;
+
+ lockdep_assert_held(&ipc->cons_list_lock);
+
+ rx_msg = kzalloc(sizeof(*rx_msg), GFP_ATOMIC);
+ if (!rx_msg) {
+ ivpu_ipc_rx_mark_free(vdev, ipc_hdr, jsm_msg);
+ return;
+ }
+
+ atomic_inc(&ipc->rx_msg_count);
+
+ rx_msg->ipc_hdr = ipc_hdr;
+ rx_msg->jsm_msg = jsm_msg;
+
+ spin_lock_irqsave(&cons->rx_msg_lock, flags);
+ list_add_tail(&rx_msg->link, &cons->rx_msg_list);
+ spin_unlock_irqrestore(&cons->rx_msg_lock, flags);
+
+ wake_up(&cons->rx_msg_wq);
+}
+
+int ivpu_ipc_irq_handler(struct ivpu_device *vdev)
+{
+ struct ivpu_ipc_info *ipc = vdev->ipc;
+ struct ivpu_ipc_consumer *cons;
+ struct ivpu_ipc_hdr *ipc_hdr;
+ struct vpu_jsm_msg *jsm_msg;
+ unsigned long flags;
+ bool dispatched;
+ u32 vpu_addr;
+
+ /*
+ * Driver needs to purge all messages from IPC FIFO to clear IPC interrupt.
+ * Without purge IPC FIFO to 0 next IPC interrupts won't be generated.
+ */
+ while (ivpu_hw_reg_ipc_rx_count_get(vdev)) {
+ vpu_addr = ivpu_hw_reg_ipc_rx_addr_get(vdev);
+ if (vpu_addr == REG_IO_ERROR) {
+ ivpu_err(vdev, "Failed to read IPC rx addr register\n");
+ return -EIO;
+ }
+
+ ipc_hdr = ivpu_to_cpu_addr(ipc->mem_rx, vpu_addr);
+ if (!ipc_hdr) {
+ ivpu_warn(vdev, "IPC msg 0x%x out of range\n", vpu_addr);
+ continue;
+ }
+ ivpu_ipc_msg_dump(vdev, "RX", ipc_hdr, vpu_addr);
+
+ jsm_msg = NULL;
+ if (ipc_hdr->channel != IVPU_IPC_CHAN_BOOT_MSG) {
+ jsm_msg = ivpu_to_cpu_addr(ipc->mem_rx, ipc_hdr->data_addr);
+ if (!jsm_msg) {
+ ivpu_warn(vdev, "JSM msg 0x%x out of range\n", ipc_hdr->data_addr);
+ ivpu_ipc_rx_mark_free(vdev, ipc_hdr, NULL);
+ continue;
+ }
+ ivpu_jsm_msg_dump(vdev, "RX", jsm_msg, ipc_hdr->data_addr);
+ }
+
+ if (atomic_read(&ipc->rx_msg_count) > IPC_MAX_RX_MSG) {
+ ivpu_warn(vdev, "IPC RX msg dropped, msg count %d\n", IPC_MAX_RX_MSG);
+ ivpu_ipc_rx_mark_free(vdev, ipc_hdr, jsm_msg);
+ continue;
+ }
+
+ dispatched = false;
+ spin_lock_irqsave(&ipc->cons_list_lock, flags);
+ list_for_each_entry(cons, &ipc->cons_list, link) {
+ if (ivpu_ipc_match_consumer(vdev, cons, ipc_hdr, jsm_msg)) {
+ ivpu_ipc_dispatch(vdev, cons, ipc_hdr, jsm_msg);
+ dispatched = true;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&ipc->cons_list_lock, flags);
+
+ if (!dispatched) {
+ ivpu_dbg(vdev, IPC, "IPC RX msg 0x%x dropped (no consumer)\n", vpu_addr);
+ ivpu_ipc_rx_mark_free(vdev, ipc_hdr, jsm_msg);
+ }
+ }
+
+ return 0;
+}
+
+int ivpu_ipc_init(struct ivpu_device *vdev)
+{
+ struct ivpu_ipc_info *ipc = vdev->ipc;
+ int ret = -ENOMEM;
+
+ ipc->mem_tx = ivpu_bo_alloc_internal(vdev, 0, SZ_16K, DRM_IVPU_BO_WC);
+ if (!ipc->mem_tx)
+ return ret;
+
+ ipc->mem_rx = ivpu_bo_alloc_internal(vdev, 0, SZ_16K, DRM_IVPU_BO_WC);
+ if (!ipc->mem_rx)
+ goto err_free_tx;
+
+ ipc->mm_tx = devm_gen_pool_create(vdev->drm.dev, __ffs(IVPU_IPC_ALIGNMENT),
+ -1, "TX_IPC_JSM");
+ if (IS_ERR(ipc->mm_tx)) {
+ ret = PTR_ERR(ipc->mm_tx);
+ ivpu_err(vdev, "Failed to create gen pool, %pe\n", ipc->mm_tx);
+ goto err_free_rx;
+ }
+
+ ret = gen_pool_add(ipc->mm_tx, ipc->mem_tx->vpu_addr, ipc->mem_tx->base.size, -1);
+ if (ret) {
+ ivpu_err(vdev, "gen_pool_add failed, ret %d\n", ret);
+ goto err_free_rx;
+ }
+
+ INIT_LIST_HEAD(&ipc->cons_list);
+ spin_lock_init(&ipc->cons_list_lock);
+ drmm_mutex_init(&vdev->drm, &ipc->lock);
+
+ ivpu_ipc_reset(vdev);
+ return 0;
+
+err_free_rx:
+ ivpu_bo_free_internal(ipc->mem_rx);
+err_free_tx:
+ ivpu_bo_free_internal(ipc->mem_tx);
+ return ret;
+}
+
+void ivpu_ipc_fini(struct ivpu_device *vdev)
+{
+ ivpu_ipc_mem_fini(vdev);
+}
+
+void ivpu_ipc_enable(struct ivpu_device *vdev)
+{
+ struct ivpu_ipc_info *ipc = vdev->ipc;
+
+ mutex_lock(&ipc->lock);
+ ipc->on = true;
+ mutex_unlock(&ipc->lock);
+}
+
+void ivpu_ipc_disable(struct ivpu_device *vdev)
+{
+ struct ivpu_ipc_info *ipc = vdev->ipc;
+ struct ivpu_ipc_consumer *cons, *c;
+ unsigned long flags;
+
+ mutex_lock(&ipc->lock);
+ ipc->on = false;
+ mutex_unlock(&ipc->lock);
+
+ spin_lock_irqsave(&ipc->cons_list_lock, flags);
+ list_for_each_entry_safe(cons, c, &ipc->cons_list, link)
+ wake_up(&cons->rx_msg_wq);
+ spin_unlock_irqrestore(&ipc->cons_list_lock, flags);
+}
+
+void ivpu_ipc_reset(struct ivpu_device *vdev)
+{
+ struct ivpu_ipc_info *ipc = vdev->ipc;
+
+ mutex_lock(&ipc->lock);
+
+ memset(ipc->mem_tx->kvaddr, 0, ipc->mem_tx->base.size);
+ memset(ipc->mem_rx->kvaddr, 0, ipc->mem_rx->base.size);
+ wmb(); /* Flush WC buffers for TX and RX rings */
+
+ mutex_unlock(&ipc->lock);
+}
diff --git a/drivers/accel/ivpu/ivpu_ipc.h b/drivers/accel/ivpu/ivpu_ipc.h
new file mode 100644
index 000000000000..9838202ecfad
--- /dev/null
+++ b/drivers/accel/ivpu/ivpu_ipc.h
@@ -0,0 +1,93 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2020-2023 Intel Corporation
+ */
+
+#ifndef __IVPU_IPC_H__
+#define __IVPU_IPC_H__
+
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+
+#include "vpu_jsm_api.h"
+
+struct ivpu_bo;
+
+/* VPU FW boot notification */
+#define IVPU_IPC_CHAN_BOOT_MSG 0x3ff
+#define IVPU_IPC_BOOT_MSG_DATA_ADDR 0x424f4f54
+
+/* The alignment to be used for IPC Buffers and IPC Data. */
+#define IVPU_IPC_ALIGNMENT 64
+
+#define IVPU_IPC_HDR_FREE 0
+#define IVPU_IPC_HDR_ALLOCATED 0
+
+/**
+ * struct ivpu_ipc_hdr - The IPC message header structure, exchanged
+ * with the VPU device firmware.
+ * @data_addr: The VPU address of the payload (JSM message)
+ * @data_size: The size of the payload.
+ * @channel: The channel used.
+ * @src_node: The Node ID of the sender.
+ * @dst_node: The Node ID of the intended receiver.
+ * @status: IPC buffer usage status
+ */
+struct ivpu_ipc_hdr {
+ u32 data_addr;
+ u32 data_size;
+ u16 channel;
+ u8 src_node;
+ u8 dst_node;
+ u8 status;
+} __packed __aligned(IVPU_IPC_ALIGNMENT);
+
+struct ivpu_ipc_consumer {
+ struct list_head link;
+ u32 channel;
+ u32 tx_vpu_addr;
+ u32 request_id;
+
+ spinlock_t rx_msg_lock; /* Protects rx_msg_list */
+ struct list_head rx_msg_list;
+ wait_queue_head_t rx_msg_wq;
+};
+
+struct ivpu_ipc_info {
+ struct gen_pool *mm_tx;
+ struct ivpu_bo *mem_tx;
+ struct ivpu_bo *mem_rx;
+
+ atomic_t rx_msg_count;
+
+ spinlock_t cons_list_lock; /* Protects cons_list */
+ struct list_head cons_list;
+
+ atomic_t request_id;
+ struct mutex lock; /* Lock on status */
+ bool on;
+};
+
+int ivpu_ipc_init(struct ivpu_device *vdev);
+void ivpu_ipc_fini(struct ivpu_device *vdev);
+
+void ivpu_ipc_enable(struct ivpu_device *vdev);
+void ivpu_ipc_disable(struct ivpu_device *vdev);
+void ivpu_ipc_reset(struct ivpu_device *vdev);
+
+int ivpu_ipc_irq_handler(struct ivpu_device *vdev);
+
+void ivpu_ipc_consumer_add(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons,
+ u32 channel);
+void ivpu_ipc_consumer_del(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons);
+
+int ivpu_ipc_receive(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons,
+ struct ivpu_ipc_hdr *ipc_buf, struct vpu_jsm_msg *ipc_payload,
+ unsigned long timeout_ms);
+
+int ivpu_ipc_send_receive(struct ivpu_device *vdev, struct vpu_jsm_msg *req,
+ enum vpu_ipc_msg_type expected_resp_type,
+ struct vpu_jsm_msg *resp, u32 channel,
+ unsigned long timeout_ms);
+
+#endif /* __IVPU_IPC_H__ */
diff --git a/drivers/accel/ivpu/ivpu_job.c b/drivers/accel/ivpu/ivpu_job.c
new file mode 100644
index 000000000000..94068aedf97c
--- /dev/null
+++ b/drivers/accel/ivpu/ivpu_job.c
@@ -0,0 +1,615 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2020-2023 Intel Corporation
+ */
+
+#include <drm/drm_file.h>
+
+#include <linux/bitfield.h>
+#include <linux/highmem.h>
+#include <linux/kthread.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <uapi/drm/ivpu_accel.h>
+
+#include "ivpu_drv.h"
+#include "ivpu_hw.h"
+#include "ivpu_ipc.h"
+#include "ivpu_job.h"
+#include "ivpu_jsm_msg.h"
+#include "ivpu_pm.h"
+
+#define CMD_BUF_IDX 0
+#define JOB_ID_JOB_MASK GENMASK(7, 0)
+#define JOB_ID_CONTEXT_MASK GENMASK(31, 8)
+#define JOB_MAX_BUFFER_COUNT 65535
+
+static unsigned int ivpu_tdr_timeout_ms;
+module_param_named(tdr_timeout_ms, ivpu_tdr_timeout_ms, uint, 0644);
+MODULE_PARM_DESC(tdr_timeout_ms, "Timeout for device hang detection, in milliseconds, 0 - default");
+
+static void ivpu_cmdq_ring_db(struct ivpu_device *vdev, struct ivpu_cmdq *cmdq)
+{
+ ivpu_hw_reg_db_set(vdev, cmdq->db_id);
+}
+
+static struct ivpu_cmdq *ivpu_cmdq_alloc(struct ivpu_file_priv *file_priv, u16 engine)
+{
+ struct ivpu_device *vdev = file_priv->vdev;
+ struct vpu_job_queue_header *jobq_header;
+ struct ivpu_cmdq *cmdq;
+
+ cmdq = kzalloc(sizeof(*cmdq), GFP_KERNEL);
+ if (!cmdq)
+ return NULL;
+
+ cmdq->mem = ivpu_bo_alloc_internal(vdev, 0, SZ_4K, DRM_IVPU_BO_WC);
+ if (!cmdq->mem)
+ goto cmdq_free;
+
+ cmdq->db_id = file_priv->ctx.id + engine * ivpu_get_context_count(vdev);
+ cmdq->entry_count = (u32)((cmdq->mem->base.size - sizeof(struct vpu_job_queue_header)) /
+ sizeof(struct vpu_job_queue_entry));
+
+ cmdq->jobq = (struct vpu_job_queue *)cmdq->mem->kvaddr;
+ jobq_header = &cmdq->jobq->header;
+ jobq_header->engine_idx = engine;
+ jobq_header->head = 0;
+ jobq_header->tail = 0;
+ wmb(); /* Flush WC buffer for jobq->header */
+
+ return cmdq;
+
+cmdq_free:
+ kfree(cmdq);
+ return NULL;
+}
+
+static void ivpu_cmdq_free(struct ivpu_file_priv *file_priv, struct ivpu_cmdq *cmdq)
+{
+ if (!cmdq)
+ return;
+
+ ivpu_bo_free_internal(cmdq->mem);
+ kfree(cmdq);
+}
+
+static struct ivpu_cmdq *ivpu_cmdq_acquire(struct ivpu_file_priv *file_priv, u16 engine)
+{
+ struct ivpu_device *vdev = file_priv->vdev;
+ struct ivpu_cmdq *cmdq = file_priv->cmdq[engine];
+ int ret;
+
+ lockdep_assert_held(&file_priv->lock);
+
+ if (!cmdq) {
+ cmdq = ivpu_cmdq_alloc(file_priv, engine);
+ if (!cmdq)
+ return NULL;
+ file_priv->cmdq[engine] = cmdq;
+ }
+
+ if (cmdq->db_registered)
+ return cmdq;
+
+ ret = ivpu_jsm_register_db(vdev, file_priv->ctx.id, cmdq->db_id,
+ cmdq->mem->vpu_addr, cmdq->mem->base.size);
+ if (ret)
+ return NULL;
+
+ cmdq->db_registered = true;
+
+ return cmdq;
+}
+
+static void ivpu_cmdq_release_locked(struct ivpu_file_priv *file_priv, u16 engine)
+{
+ struct ivpu_cmdq *cmdq = file_priv->cmdq[engine];
+
+ lockdep_assert_held(&file_priv->lock);
+
+ if (cmdq) {
+ file_priv->cmdq[engine] = NULL;
+ if (cmdq->db_registered)
+ ivpu_jsm_unregister_db(file_priv->vdev, cmdq->db_id);
+
+ ivpu_cmdq_free(file_priv, cmdq);
+ }
+}
+
+void ivpu_cmdq_release_all(struct ivpu_file_priv *file_priv)
+{
+ int i;
+
+ mutex_lock(&file_priv->lock);
+
+ for (i = 0; i < IVPU_NUM_ENGINES; i++)
+ ivpu_cmdq_release_locked(file_priv, i);
+
+ mutex_unlock(&file_priv->lock);
+}
+
+/*
+ * Mark the doorbell as unregistered and reset job queue pointers.
+ * This function needs to be called when the VPU hardware is restarted
+ * and FW looses job queue state. The next time job queue is used it
+ * will be registered again.
+ */
+static void ivpu_cmdq_reset_locked(struct ivpu_file_priv *file_priv, u16 engine)
+{
+ struct ivpu_cmdq *cmdq = file_priv->cmdq[engine];
+
+ lockdep_assert_held(&file_priv->lock);
+
+ if (cmdq) {
+ cmdq->db_registered = false;
+ cmdq->jobq->header.head = 0;
+ cmdq->jobq->header.tail = 0;
+ wmb(); /* Flush WC buffer for jobq header */
+ }
+}
+
+static void ivpu_cmdq_reset_all(struct ivpu_file_priv *file_priv)
+{
+ int i;
+
+ mutex_lock(&file_priv->lock);
+
+ for (i = 0; i < IVPU_NUM_ENGINES; i++)
+ ivpu_cmdq_reset_locked(file_priv, i);
+
+ mutex_unlock(&file_priv->lock);
+}
+
+void ivpu_cmdq_reset_all_contexts(struct ivpu_device *vdev)
+{
+ struct ivpu_file_priv *file_priv;
+ unsigned long ctx_id;
+
+ xa_for_each(&vdev->context_xa, ctx_id, file_priv) {
+ file_priv = ivpu_file_priv_get_by_ctx_id(vdev, ctx_id);
+ if (!file_priv)
+ continue;
+
+ ivpu_cmdq_reset_all(file_priv);
+
+ ivpu_file_priv_put(&file_priv);
+ }
+}
+
+static int ivpu_cmdq_push_job(struct ivpu_cmdq *cmdq, struct ivpu_job *job)
+{
+ struct ivpu_device *vdev = job->vdev;
+ struct vpu_job_queue_header *header = &cmdq->jobq->header;
+ struct vpu_job_queue_entry *entry;
+ u32 tail = READ_ONCE(header->tail);
+ u32 next_entry = (tail + 1) % cmdq->entry_count;
+
+ /* Check if there is space left in job queue */
+ if (next_entry == header->head) {
+ ivpu_dbg(vdev, JOB, "Job queue full: ctx %d engine %d db %d head %d tail %d\n",
+ job->file_priv->ctx.id, job->engine_idx, cmdq->db_id, header->head, tail);
+ return -EBUSY;
+ }
+
+ entry = &cmdq->jobq->job[tail];
+ entry->batch_buf_addr = job->cmd_buf_vpu_addr;
+ entry->job_id = job->job_id;
+ entry->flags = 0;
+ wmb(); /* Ensure that tail is updated after filling entry */
+ header->tail = next_entry;
+ wmb(); /* Flush WC buffer for jobq header */
+
+ return 0;
+}
+
+struct ivpu_fence {
+ struct dma_fence base;
+ spinlock_t lock; /* protects base */
+ struct ivpu_device *vdev;
+};
+
+static inline struct ivpu_fence *to_vpu_fence(struct dma_fence *fence)
+{
+ return container_of(fence, struct ivpu_fence, base);
+}
+
+static const char *ivpu_fence_get_driver_name(struct dma_fence *fence)
+{
+ return DRIVER_NAME;
+}
+
+static const char *ivpu_fence_get_timeline_name(struct dma_fence *fence)
+{
+ struct ivpu_fence *ivpu_fence = to_vpu_fence(fence);
+
+ return dev_name(ivpu_fence->vdev->drm.dev);
+}
+
+static const struct dma_fence_ops ivpu_fence_ops = {
+ .get_driver_name = ivpu_fence_get_driver_name,
+ .get_timeline_name = ivpu_fence_get_timeline_name,
+};
+
+static struct dma_fence *ivpu_fence_create(struct ivpu_device *vdev)
+{
+ struct ivpu_fence *fence;
+
+ fence = kzalloc(sizeof(*fence), GFP_KERNEL);
+ if (!fence)
+ return NULL;
+
+ fence->vdev = vdev;
+ spin_lock_init(&fence->lock);
+ dma_fence_init(&fence->base, &ivpu_fence_ops, &fence->lock, dma_fence_context_alloc(1), 1);
+
+ return &fence->base;
+}
+
+static void job_get(struct ivpu_job *job, struct ivpu_job **link)
+{
+ struct ivpu_device *vdev = job->vdev;
+
+ kref_get(&job->ref);
+ *link = job;
+
+ ivpu_dbg(vdev, KREF, "Job get: id %u refcount %u\n", job->job_id, kref_read(&job->ref));
+}
+
+static void job_release(struct kref *ref)
+{
+ struct ivpu_job *job = container_of(ref, struct ivpu_job, ref);
+ struct ivpu_device *vdev = job->vdev;
+ u32 i;
+
+ for (i = 0; i < job->bo_count; i++)
+ if (job->bos[i])
+ drm_gem_object_put(&job->bos[i]->base);
+
+ dma_fence_put(job->done_fence);
+ ivpu_file_priv_put(&job->file_priv);
+
+ ivpu_dbg(vdev, KREF, "Job released: id %u\n", job->job_id);
+ kfree(job);
+
+ /* Allow the VPU to get suspended, must be called after ivpu_file_priv_put() */
+ ivpu_rpm_put(vdev);
+}
+
+static void job_put(struct ivpu_job *job)
+{
+ struct ivpu_device *vdev = job->vdev;
+
+ ivpu_dbg(vdev, KREF, "Job put: id %u refcount %u\n", job->job_id, kref_read(&job->ref));
+ kref_put(&job->ref, job_release);
+}
+
+static struct ivpu_job *
+ivpu_create_job(struct ivpu_file_priv *file_priv, u32 engine_idx, u32 bo_count)
+{
+ struct ivpu_device *vdev = file_priv->vdev;
+ struct ivpu_job *job;
+ size_t buf_size;
+ int ret;
+
+ ret = ivpu_rpm_get(vdev);
+ if (ret < 0)
+ return NULL;
+
+ buf_size = sizeof(*job) + bo_count * sizeof(struct ivpu_bo *);
+ job = kzalloc(buf_size, GFP_KERNEL);
+ if (!job)
+ goto err_rpm_put;
+
+ kref_init(&job->ref);
+
+ job->vdev = vdev;
+ job->engine_idx = engine_idx;
+ job->bo_count = bo_count;
+ job->done_fence = ivpu_fence_create(vdev);
+ if (!job->done_fence) {
+ ivpu_warn_ratelimited(vdev, "Failed to create a fence\n");
+ goto err_free_job;
+ }
+
+ job->file_priv = ivpu_file_priv_get(file_priv);
+
+ ivpu_dbg(vdev, JOB, "Job created: ctx %2d engine %d", file_priv->ctx.id, job->engine_idx);
+
+ return job;
+
+err_free_job:
+ kfree(job);
+err_rpm_put:
+ ivpu_rpm_put(vdev);
+ return NULL;
+}
+
+static int ivpu_job_done(struct ivpu_device *vdev, u32 job_id, u32 job_status)
+{
+ struct ivpu_job *job;
+
+ job = xa_erase(&vdev->submitted_jobs_xa, job_id);
+ if (!job)
+ return -ENOENT;
+
+ if (job->file_priv->has_mmu_faults)
+ job_status = VPU_JSM_STATUS_ABORTED;
+
+ job->bos[CMD_BUF_IDX]->job_status = job_status;
+ dma_fence_signal(job->done_fence);
+
+ ivpu_dbg(vdev, JOB, "Job complete: id %3u ctx %2d engine %d status 0x%x\n",
+ job->job_id, job->file_priv->ctx.id, job->engine_idx, job_status);
+
+ job_put(job);
+ return 0;
+}
+
+static void ivpu_job_done_message(struct ivpu_device *vdev, void *msg)
+{
+ struct vpu_ipc_msg_payload_job_done *payload;
+ struct vpu_jsm_msg *job_ret_msg = msg;
+ int ret;
+
+ payload = (struct vpu_ipc_msg_payload_job_done *)&job_ret_msg->payload;
+
+ ret = ivpu_job_done(vdev, payload->job_id, payload->job_status);
+ if (ret)
+ ivpu_err(vdev, "Failed to finish job %d: %d\n", payload->job_id, ret);
+}
+
+void ivpu_jobs_abort_all(struct ivpu_device *vdev)
+{
+ struct ivpu_job *job;
+ unsigned long id;
+
+ xa_for_each(&vdev->submitted_jobs_xa, id, job)
+ ivpu_job_done(vdev, id, VPU_JSM_STATUS_ABORTED);
+}
+
+static int ivpu_direct_job_submission(struct ivpu_job *job)
+{
+ struct ivpu_file_priv *file_priv = job->file_priv;
+ struct ivpu_device *vdev = job->vdev;
+ struct xa_limit job_id_range;
+ struct ivpu_cmdq *cmdq;
+ int ret;
+
+ mutex_lock(&file_priv->lock);
+
+ cmdq = ivpu_cmdq_acquire(job->file_priv, job->engine_idx);
+ if (!cmdq) {
+ ivpu_warn(vdev, "Failed get job queue, ctx %d engine %d\n",
+ file_priv->ctx.id, job->engine_idx);
+ ret = -EINVAL;
+ goto err_unlock;
+ }
+
+ job_id_range.min = FIELD_PREP(JOB_ID_CONTEXT_MASK, (file_priv->ctx.id - 1));
+ job_id_range.max = job_id_range.min | JOB_ID_JOB_MASK;
+
+ job_get(job, &job);
+ ret = xa_alloc(&vdev->submitted_jobs_xa, &job->job_id, job, job_id_range, GFP_KERNEL);
+ if (ret) {
+ ivpu_warn_ratelimited(vdev, "Failed to allocate job id: %d\n", ret);
+ goto err_job_put;
+ }
+
+ ret = ivpu_cmdq_push_job(cmdq, job);
+ if (ret)
+ goto err_xa_erase;
+
+ ivpu_dbg(vdev, JOB, "Job submitted: id %3u addr 0x%llx ctx %2d engine %d next %d\n",
+ job->job_id, job->cmd_buf_vpu_addr, file_priv->ctx.id,
+ job->engine_idx, cmdq->jobq->header.tail);
+
+ if (ivpu_test_mode == IVPU_TEST_MODE_NULL_HW) {
+ ivpu_job_done(vdev, job->job_id, VPU_JSM_STATUS_SUCCESS);
+ cmdq->jobq->header.head = cmdq->jobq->header.tail;
+ wmb(); /* Flush WC buffer for jobq header */
+ } else {
+ ivpu_cmdq_ring_db(vdev, cmdq);
+ }
+
+ mutex_unlock(&file_priv->lock);
+ return 0;
+
+err_xa_erase:
+ xa_erase(&vdev->submitted_jobs_xa, job->job_id);
+err_job_put:
+ job_put(job);
+err_unlock:
+ mutex_unlock(&file_priv->lock);
+ return ret;
+}
+
+static int
+ivpu_job_prepare_bos_for_submit(struct drm_file *file, struct ivpu_job *job, u32 *buf_handles,
+ u32 buf_count, u32 commands_offset)
+{
+ struct ivpu_file_priv *file_priv = file->driver_priv;
+ struct ivpu_device *vdev = file_priv->vdev;
+ struct ww_acquire_ctx acquire_ctx;
+ struct ivpu_bo *bo;
+ int ret;
+ u32 i;
+
+ for (i = 0; i < buf_count; i++) {
+ struct drm_gem_object *obj = drm_gem_object_lookup(file, buf_handles[i]);
+
+ if (!obj)
+ return -ENOENT;
+
+ job->bos[i] = to_ivpu_bo(obj);
+
+ ret = ivpu_bo_pin(job->bos[i]);
+ if (ret)
+ return ret;
+ }
+
+ bo = job->bos[CMD_BUF_IDX];
+ if (!dma_resv_test_signaled(bo->base.resv, DMA_RESV_USAGE_READ)) {
+ ivpu_warn(vdev, "Buffer is already in use\n");
+ return -EBUSY;
+ }
+
+ if (commands_offset >= bo->base.size) {
+ ivpu_warn(vdev, "Invalid command buffer offset %u\n", commands_offset);
+ return -EINVAL;
+ }
+
+ job->cmd_buf_vpu_addr = bo->vpu_addr + commands_offset;
+
+ ret = drm_gem_lock_reservations((struct drm_gem_object **)job->bos, buf_count,
+ &acquire_ctx);
+ if (ret) {
+ ivpu_warn(vdev, "Failed to lock reservations: %d\n", ret);
+ return ret;
+ }
+
+ for (i = 0; i < buf_count; i++) {
+ ret = dma_resv_reserve_fences(job->bos[i]->base.resv, 1);
+ if (ret) {
+ ivpu_warn(vdev, "Failed to reserve fences: %d\n", ret);
+ goto unlock_reservations;
+ }
+ }
+
+ for (i = 0; i < buf_count; i++)
+ dma_resv_add_fence(job->bos[i]->base.resv, job->done_fence, DMA_RESV_USAGE_WRITE);
+
+unlock_reservations:
+ drm_gem_unlock_reservations((struct drm_gem_object **)job->bos, buf_count, &acquire_ctx);
+
+ wmb(); /* Flush write combining buffers */
+
+ return ret;
+}
+
+int ivpu_submit_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
+{
+ int ret = 0;
+ struct ivpu_file_priv *file_priv = file->driver_priv;
+ struct ivpu_device *vdev = file_priv->vdev;
+ struct drm_ivpu_submit *params = data;
+ struct ivpu_job *job;
+ u32 *buf_handles;
+
+ if (params->engine > DRM_IVPU_ENGINE_COPY)
+ return -EINVAL;
+
+ if (params->buffer_count == 0 || params->buffer_count > JOB_MAX_BUFFER_COUNT)
+ return -EINVAL;
+
+ if (!IS_ALIGNED(params->commands_offset, 8))
+ return -EINVAL;
+
+ if (!file_priv->ctx.id)
+ return -EINVAL;
+
+ if (file_priv->has_mmu_faults)
+ return -EBADFD;
+
+ buf_handles = kcalloc(params->buffer_count, sizeof(u32), GFP_KERNEL);
+ if (!buf_handles)
+ return -ENOMEM;
+
+ ret = copy_from_user(buf_handles,
+ (void __user *)params->buffers_ptr,
+ params->buffer_count * sizeof(u32));
+ if (ret) {
+ ret = -EFAULT;
+ goto free_handles;
+ }
+
+ ivpu_dbg(vdev, JOB, "Submit ioctl: ctx %u buf_count %u\n",
+ file_priv->ctx.id, params->buffer_count);
+
+ job = ivpu_create_job(file_priv, params->engine, params->buffer_count);
+ if (!job) {
+ ivpu_err(vdev, "Failed to create job\n");
+ ret = -ENOMEM;
+ goto free_handles;
+ }
+
+ ret = ivpu_job_prepare_bos_for_submit(file, job, buf_handles, params->buffer_count,
+ params->commands_offset);
+ if (ret) {
+ ivpu_err(vdev, "Failed to prepare job, ret %d\n", ret);
+ goto job_put;
+ }
+
+ ret = ivpu_direct_job_submission(job);
+ if (ret) {
+ dma_fence_signal(job->done_fence);
+ ivpu_err(vdev, "Failed to submit job to the HW, ret %d\n", ret);
+ }
+
+job_put:
+ job_put(job);
+free_handles:
+ kfree(buf_handles);
+
+ return ret;
+}
+
+static int ivpu_job_done_thread(void *arg)
+{
+ struct ivpu_device *vdev = (struct ivpu_device *)arg;
+ struct ivpu_ipc_consumer cons;
+ struct vpu_jsm_msg jsm_msg;
+ bool jobs_submitted;
+ unsigned int timeout;
+ int ret;
+
+ ivpu_dbg(vdev, JOB, "Started %s\n", __func__);
+
+ ivpu_ipc_consumer_add(vdev, &cons, VPU_IPC_CHAN_JOB_RET);
+
+ while (!kthread_should_stop()) {
+ timeout = ivpu_tdr_timeout_ms ? ivpu_tdr_timeout_ms : vdev->timeout.tdr;
+ jobs_submitted = !xa_empty(&vdev->submitted_jobs_xa);
+ ret = ivpu_ipc_receive(vdev, &cons, NULL, &jsm_msg, timeout);
+ if (!ret) {
+ ivpu_job_done_message(vdev, &jsm_msg);
+ } else if (ret == -ETIMEDOUT) {
+ if (jobs_submitted && !xa_empty(&vdev->submitted_jobs_xa)) {
+ ivpu_err(vdev, "TDR detected, timeout %d ms", timeout);
+ ivpu_hw_diagnose_failure(vdev);
+ ivpu_pm_schedule_recovery(vdev);
+ }
+ }
+ }
+
+ ivpu_ipc_consumer_del(vdev, &cons);
+
+ ivpu_jobs_abort_all(vdev);
+
+ ivpu_dbg(vdev, JOB, "Stopped %s\n", __func__);
+ return 0;
+}
+
+int ivpu_job_done_thread_init(struct ivpu_device *vdev)
+{
+ struct task_struct *thread;
+
+ thread = kthread_run(&ivpu_job_done_thread, (void *)vdev, "ivpu_job_done_thread");
+ if (IS_ERR(thread)) {
+ ivpu_err(vdev, "Failed to start job completion thread\n");
+ return -EIO;
+ }
+
+ get_task_struct(thread);
+ wake_up_process(thread);
+
+ vdev->job_done_thread = thread;
+
+ return 0;
+}
+
+void ivpu_job_done_thread_fini(struct ivpu_device *vdev)
+{
+ kthread_stop(vdev->job_done_thread);
+ put_task_struct(vdev->job_done_thread);
+}
diff --git a/drivers/accel/ivpu/ivpu_job.h b/drivers/accel/ivpu/ivpu_job.h
new file mode 100644
index 000000000000..aa1f0b9479b0
--- /dev/null
+++ b/drivers/accel/ivpu/ivpu_job.h
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2020-2023 Intel Corporation
+ */
+
+#ifndef __IVPU_JOB_H__
+#define __IVPU_JOB_H__
+
+#include <linux/kref.h>
+#include <linux/idr.h>
+
+#include "ivpu_gem.h"
+
+struct ivpu_device;
+struct ivpu_file_priv;
+
+/**
+ * struct ivpu_cmdq - Object representing device queue used to send jobs.
+ * @jobq: Pointer to job queue memory shared with the device
+ * @mem: Memory allocated for the job queue, shared with device
+ * @entry_count Number of job entries in the queue
+ * @db_id: Doorbell assigned to this job queue
+ * @db_registered: True if doorbell is registered in device
+ */
+struct ivpu_cmdq {
+ struct vpu_job_queue *jobq;
+ struct ivpu_bo *mem;
+ u32 entry_count;
+ u32 db_id;
+ bool db_registered;
+};
+
+/**
+ * struct ivpu_job - KMD object that represents batchbuffer / DMA buffer.
+ * Each batch / DMA buffer is a job to be submitted and executed by the VPU FW.
+ * This is a unit of execution, and be tracked by the job_id for
+ * any status reporting from VPU FW through IPC JOB RET/DONE message.
+ * @file_priv: The client that submitted this job
+ * @job_id: Job ID for KMD tracking and job status reporting from VPU FW
+ * @status: Status of the Job from IPC JOB RET/DONE message
+ * @batch_buffer: CPU vaddr points to the batch buffer memory allocated for the job
+ * @submit_status_offset: Offset within batch buffer where job completion handler
+ will update the job status
+ */
+struct ivpu_job {
+ struct kref ref;
+ struct ivpu_device *vdev;
+ struct ivpu_file_priv *file_priv;
+ struct dma_fence *done_fence;
+ u64 cmd_buf_vpu_addr;
+ u32 job_id;
+ u32 engine_idx;
+ size_t bo_count;
+ struct ivpu_bo *bos[];
+};
+
+int ivpu_submit_ioctl(struct drm_device *dev, void *data, struct drm_file *file);
+
+void ivpu_cmdq_release_all(struct ivpu_file_priv *file_priv);
+void ivpu_cmdq_reset_all_contexts(struct ivpu_device *vdev);
+
+int ivpu_job_done_thread_init(struct ivpu_device *vdev);
+void ivpu_job_done_thread_fini(struct ivpu_device *vdev);
+
+void ivpu_jobs_abort_all(struct ivpu_device *vdev);
+
+#endif /* __IVPU_JOB_H__ */
diff --git a/drivers/accel/ivpu/ivpu_jsm_msg.c b/drivers/accel/ivpu/ivpu_jsm_msg.c
new file mode 100644
index 000000000000..831bfd2b2d39
--- /dev/null
+++ b/drivers/accel/ivpu/ivpu_jsm_msg.c
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2020-2023 Intel Corporation
+ */
+
+#include "ivpu_drv.h"
+#include "ivpu_ipc.h"
+#include "ivpu_jsm_msg.h"
+
+int ivpu_jsm_register_db(struct ivpu_device *vdev, u32 ctx_id, u32 db_id,
+ u64 jobq_base, u32 jobq_size)
+{
+ struct vpu_jsm_msg req = { .type = VPU_JSM_MSG_REGISTER_DB };
+ struct vpu_jsm_msg resp;
+ int ret = 0;
+
+ req.payload.register_db.db_idx = db_id;
+ req.payload.register_db.jobq_base = jobq_base;
+ req.payload.register_db.jobq_size = jobq_size;
+ req.payload.register_db.host_ssid = ctx_id;
+
+ ret = ivpu_ipc_send_receive(vdev, &req, VPU_JSM_MSG_REGISTER_DB_DONE, &resp,
+ VPU_IPC_CHAN_ASYNC_CMD, vdev->timeout.jsm);
+ if (ret) {
+ ivpu_err(vdev, "Failed to register doorbell %d: %d\n", db_id, ret);
+ return ret;
+ }
+
+ ivpu_dbg(vdev, JSM, "Doorbell %d registered to context %d\n", db_id, ctx_id);
+
+ return 0;
+}
+
+int ivpu_jsm_unregister_db(struct ivpu_device *vdev, u32 db_id)
+{
+ struct vpu_jsm_msg req = { .type = VPU_JSM_MSG_UNREGISTER_DB };
+ struct vpu_jsm_msg resp;
+ int ret = 0;
+
+ req.payload.unregister_db.db_idx = db_id;
+
+ ret = ivpu_ipc_send_receive(vdev, &req, VPU_JSM_MSG_UNREGISTER_DB_DONE, &resp,
+ VPU_IPC_CHAN_ASYNC_CMD, vdev->timeout.jsm);
+ if (ret) {
+ ivpu_warn(vdev, "Failed to unregister doorbell %d: %d\n", db_id, ret);
+ return ret;
+ }
+
+ ivpu_dbg(vdev, JSM, "Doorbell %d unregistered\n", db_id);
+
+ return 0;
+}
+
+int ivpu_jsm_get_heartbeat(struct ivpu_device *vdev, u32 engine, u64 *heartbeat)
+{
+ struct vpu_jsm_msg req = { .type = VPU_JSM_MSG_QUERY_ENGINE_HB };
+ struct vpu_jsm_msg resp;
+ int ret;
+
+ if (engine > VPU_ENGINE_COPY)
+ return -EINVAL;
+
+ req.payload.query_engine_hb.engine_idx = engine;
+
+ ret = ivpu_ipc_send_receive(vdev, &req, VPU_JSM_MSG_QUERY_ENGINE_HB_DONE, &resp,
+ VPU_IPC_CHAN_ASYNC_CMD, vdev->timeout.jsm);
+ if (ret) {
+ ivpu_err(vdev, "Failed to get heartbeat from engine %d: %d\n", engine, ret);
+ return ret;
+ }
+
+ *heartbeat = resp.payload.query_engine_hb_done.heartbeat;
+ return ret;
+}
+
+int ivpu_jsm_reset_engine(struct ivpu_device *vdev, u32 engine)
+{
+ struct vpu_jsm_msg req = { .type = VPU_JSM_MSG_ENGINE_RESET };
+ struct vpu_jsm_msg resp;
+ int ret;
+
+ if (engine > VPU_ENGINE_COPY)
+ return -EINVAL;
+
+ req.payload.engine_reset.engine_idx = engine;
+
+ ret = ivpu_ipc_send_receive(vdev, &req, VPU_JSM_MSG_ENGINE_RESET_DONE, &resp,
+ VPU_IPC_CHAN_ASYNC_CMD, vdev->timeout.jsm);
+ if (ret)
+ ivpu_err(vdev, "Failed to reset engine %d: %d\n", engine, ret);
+
+ return ret;
+}
+
+int ivpu_jsm_preempt_engine(struct ivpu_device *vdev, u32 engine, u32 preempt_id)
+{
+ struct vpu_jsm_msg req = { .type = VPU_JSM_MSG_ENGINE_PREEMPT };
+ struct vpu_jsm_msg resp;
+ int ret;
+
+ if (engine > VPU_ENGINE_COPY)
+ return -EINVAL;
+
+ req.payload.engine_preempt.engine_idx = engine;
+ req.payload.engine_preempt.preempt_id = preempt_id;
+
+ ret = ivpu_ipc_send_receive(vdev, &req, VPU_JSM_MSG_ENGINE_PREEMPT_DONE, &resp,
+ VPU_IPC_CHAN_ASYNC_CMD, vdev->timeout.jsm);
+ if (ret)
+ ivpu_err(vdev, "Failed to preempt engine %d: %d\n", engine, ret);
+
+ return ret;
+}
+
+int ivpu_jsm_dyndbg_control(struct ivpu_device *vdev, char *command, size_t size)
+{
+ struct vpu_jsm_msg req = { .type = VPU_JSM_MSG_DYNDBG_CONTROL };
+ struct vpu_jsm_msg resp;
+ int ret;
+
+ if (!strncpy(req.payload.dyndbg_control.dyndbg_cmd, command, VPU_DYNDBG_CMD_MAX_LEN - 1))
+ return -ENOMEM;
+
+ ret = ivpu_ipc_send_receive(vdev, &req, VPU_JSM_MSG_DYNDBG_CONTROL_RSP, &resp,
+ VPU_IPC_CHAN_ASYNC_CMD, vdev->timeout.jsm);
+ if (ret)
+ ivpu_warn(vdev, "Failed to send command \"%s\": ret %d\n", command, ret);
+
+ return ret;
+}
+
+int ivpu_jsm_trace_get_capability(struct ivpu_device *vdev, u32 *trace_destination_mask,
+ u64 *trace_hw_component_mask)
+{
+ struct vpu_jsm_msg req = { .type = VPU_JSM_MSG_TRACE_GET_CAPABILITY };
+ struct vpu_jsm_msg resp;
+ int ret;
+
+ ret = ivpu_ipc_send_receive(vdev, &req, VPU_JSM_MSG_TRACE_GET_CAPABILITY_RSP, &resp,
+ VPU_IPC_CHAN_ASYNC_CMD, vdev->timeout.jsm);
+ if (ret) {
+ ivpu_warn(vdev, "Failed to get trace capability: %d\n", ret);
+ return ret;
+ }
+
+ *trace_destination_mask = resp.payload.trace_capability.trace_destination_mask;
+ *trace_hw_component_mask = resp.payload.trace_capability.trace_hw_component_mask;
+
+ return ret;
+}
+
+int ivpu_jsm_trace_set_config(struct ivpu_device *vdev, u32 trace_level, u32 trace_destination_mask,
+ u64 trace_hw_component_mask)
+{
+ struct vpu_jsm_msg req = { .type = VPU_JSM_MSG_TRACE_SET_CONFIG };
+ struct vpu_jsm_msg resp;
+ int ret;
+
+ req.payload.trace_config.trace_level = trace_level;
+ req.payload.trace_config.trace_destination_mask = trace_destination_mask;
+ req.payload.trace_config.trace_hw_component_mask = trace_hw_component_mask;
+
+ ret = ivpu_ipc_send_receive(vdev, &req, VPU_JSM_MSG_TRACE_SET_CONFIG_RSP, &resp,
+ VPU_IPC_CHAN_ASYNC_CMD, vdev->timeout.jsm);
+ if (ret)
+ ivpu_warn(vdev, "Failed to set config: %d\n", ret);
+
+ return ret;
+}
+
+int ivpu_jsm_context_release(struct ivpu_device *vdev, u32 host_ssid)
+{
+ struct vpu_jsm_msg req = { .type = VPU_JSM_MSG_SSID_RELEASE };
+ struct vpu_jsm_msg resp;
+
+ req.payload.ssid_release.host_ssid = host_ssid;
+
+ return ivpu_ipc_send_receive(vdev, &req, VPU_JSM_MSG_SSID_RELEASE_DONE, &resp,
+ VPU_IPC_CHAN_ASYNC_CMD, vdev->timeout.jsm);
+}
diff --git a/drivers/accel/ivpu/ivpu_jsm_msg.h b/drivers/accel/ivpu/ivpu_jsm_msg.h
new file mode 100644
index 000000000000..ab50d7b017c1
--- /dev/null
+++ b/drivers/accel/ivpu/ivpu_jsm_msg.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2020-2023 Intel Corporation
+ */
+
+#ifndef __IVPU_JSM_MSG_H__
+#define __IVPU_JSM_MSG_H__
+
+#include "vpu_jsm_api.h"
+
+int ivpu_jsm_register_db(struct ivpu_device *vdev, u32 ctx_id, u32 db_id,
+ u64 jobq_base, u32 jobq_size);
+int ivpu_jsm_unregister_db(struct ivpu_device *vdev, u32 db_id);
+int ivpu_jsm_get_heartbeat(struct ivpu_device *vdev, u32 engine, u64 *heartbeat);
+int ivpu_jsm_reset_engine(struct ivpu_device *vdev, u32 engine);
+int ivpu_jsm_preempt_engine(struct ivpu_device *vdev, u32 engine, u32 preempt_id);
+int ivpu_jsm_dyndbg_control(struct ivpu_device *vdev, char *command, size_t size);
+int ivpu_jsm_trace_get_capability(struct ivpu_device *vdev, u32 *trace_destination_mask,
+ u64 *trace_hw_component_mask);
+int ivpu_jsm_trace_set_config(struct ivpu_device *vdev, u32 trace_level, u32 trace_destination_mask,
+ u64 trace_hw_component_mask);
+int ivpu_jsm_context_release(struct ivpu_device *vdev, u32 host_ssid);
+#endif
diff --git a/drivers/accel/ivpu/ivpu_mmu.c b/drivers/accel/ivpu/ivpu_mmu.c
new file mode 100644
index 000000000000..694e978aba66
--- /dev/null
+++ b/drivers/accel/ivpu/ivpu_mmu.c
@@ -0,0 +1,883 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2020-2023 Intel Corporation
+ */
+
+#include <linux/circ_buf.h>
+#include <linux/highmem.h>
+
+#include "ivpu_drv.h"
+#include "ivpu_hw_mtl_reg.h"
+#include "ivpu_hw_reg_io.h"
+#include "ivpu_mmu.h"
+#include "ivpu_mmu_context.h"
+#include "ivpu_pm.h"
+
+#define IVPU_MMU_IDR0_REF 0x080f3e0f
+#define IVPU_MMU_IDR0_REF_SIMICS 0x080f3e1f
+#define IVPU_MMU_IDR1_REF 0x0e739d18
+#define IVPU_MMU_IDR3_REF 0x0000003c
+#define IVPU_MMU_IDR5_REF 0x00040070
+#define IVPU_MMU_IDR5_REF_SIMICS 0x00000075
+#define IVPU_MMU_IDR5_REF_FPGA 0x00800075
+
+#define IVPU_MMU_CDTAB_ENT_SIZE 64
+#define IVPU_MMU_CDTAB_ENT_COUNT_LOG2 8 /* 256 entries */
+#define IVPU_MMU_CDTAB_ENT_COUNT ((u32)1 << IVPU_MMU_CDTAB_ENT_COUNT_LOG2)
+
+#define IVPU_MMU_STREAM_ID0 0
+#define IVPU_MMU_STREAM_ID3 3
+
+#define IVPU_MMU_STRTAB_ENT_SIZE 64
+#define IVPU_MMU_STRTAB_ENT_COUNT 4
+#define IVPU_MMU_STRTAB_CFG_LOG2SIZE 2
+#define IVPU_MMU_STRTAB_CFG IVPU_MMU_STRTAB_CFG_LOG2SIZE
+
+#define IVPU_MMU_Q_COUNT_LOG2 4 /* 16 entries */
+#define IVPU_MMU_Q_COUNT ((u32)1 << IVPU_MMU_Q_COUNT_LOG2)
+#define IVPU_MMU_Q_WRAP_BIT (IVPU_MMU_Q_COUNT << 1)
+#define IVPU_MMU_Q_WRAP_MASK (IVPU_MMU_Q_WRAP_BIT - 1)
+#define IVPU_MMU_Q_IDX_MASK (IVPU_MMU_Q_COUNT - 1)
+#define IVPU_MMU_Q_IDX(val) ((val) & IVPU_MMU_Q_IDX_MASK)
+
+#define IVPU_MMU_CMDQ_CMD_SIZE 16
+#define IVPU_MMU_CMDQ_SIZE (IVPU_MMU_Q_COUNT * IVPU_MMU_CMDQ_CMD_SIZE)
+
+#define IVPU_MMU_EVTQ_CMD_SIZE 32
+#define IVPU_MMU_EVTQ_SIZE (IVPU_MMU_Q_COUNT * IVPU_MMU_EVTQ_CMD_SIZE)
+
+#define IVPU_MMU_CMD_OPCODE GENMASK(7, 0)
+
+#define IVPU_MMU_CMD_SYNC_0_CS GENMASK(13, 12)
+#define IVPU_MMU_CMD_SYNC_0_MSH GENMASK(23, 22)
+#define IVPU_MMU_CMD_SYNC_0_MSI_ATTR GENMASK(27, 24)
+#define IVPU_MMU_CMD_SYNC_0_MSI_ATTR GENMASK(27, 24)
+#define IVPU_MMU_CMD_SYNC_0_MSI_DATA GENMASK(63, 32)
+
+#define IVPU_MMU_CMD_CFGI_0_SSEC BIT(10)
+#define IVPU_MMU_CMD_CFGI_0_SSV BIT(11)
+#define IVPU_MMU_CMD_CFGI_0_SSID GENMASK(31, 12)
+#define IVPU_MMU_CMD_CFGI_0_SID GENMASK(63, 32)
+#define IVPU_MMU_CMD_CFGI_1_RANGE GENMASK(4, 0)
+
+#define IVPU_MMU_CMD_TLBI_0_ASID GENMASK(63, 48)
+#define IVPU_MMU_CMD_TLBI_0_VMID GENMASK(47, 32)
+
+#define CMD_PREFETCH_CFG 0x1
+#define CMD_CFGI_STE 0x3
+#define CMD_CFGI_ALL 0x4
+#define CMD_CFGI_CD 0x5
+#define CMD_CFGI_CD_ALL 0x6
+#define CMD_TLBI_NH_ASID 0x11
+#define CMD_TLBI_EL2_ALL 0x20
+#define CMD_TLBI_NSNH_ALL 0x30
+#define CMD_SYNC 0x46
+
+#define IVPU_MMU_EVT_F_UUT 0x01
+#define IVPU_MMU_EVT_C_BAD_STREAMID 0x02
+#define IVPU_MMU_EVT_F_STE_FETCH 0x03
+#define IVPU_MMU_EVT_C_BAD_STE 0x04
+#define IVPU_MMU_EVT_F_BAD_ATS_TREQ 0x05
+#define IVPU_MMU_EVT_F_STREAM_DISABLED 0x06
+#define IVPU_MMU_EVT_F_TRANSL_FORBIDDEN 0x07
+#define IVPU_MMU_EVT_C_BAD_SUBSTREAMID 0x08
+#define IVPU_MMU_EVT_F_CD_FETCH 0x09
+#define IVPU_MMU_EVT_C_BAD_CD 0x0a
+#define IVPU_MMU_EVT_F_WALK_EABT 0x0b
+#define IVPU_MMU_EVT_F_TRANSLATION 0x10
+#define IVPU_MMU_EVT_F_ADDR_SIZE 0x11
+#define IVPU_MMU_EVT_F_ACCESS 0x12
+#define IVPU_MMU_EVT_F_PERMISSION 0x13
+#define IVPU_MMU_EVT_F_TLB_CONFLICT 0x20
+#define IVPU_MMU_EVT_F_CFG_CONFLICT 0x21
+#define IVPU_MMU_EVT_E_PAGE_REQUEST 0x24
+#define IVPU_MMU_EVT_F_VMS_FETCH 0x25
+
+#define IVPU_MMU_EVT_OP_MASK GENMASK_ULL(7, 0)
+#define IVPU_MMU_EVT_SSID_MASK GENMASK_ULL(31, 12)
+
+#define IVPU_MMU_Q_BASE_RWA BIT(62)
+#define IVPU_MMU_Q_BASE_ADDR_MASK GENMASK_ULL(51, 5)
+#define IVPU_MMU_STRTAB_BASE_RA BIT(62)
+#define IVPU_MMU_STRTAB_BASE_ADDR_MASK GENMASK_ULL(51, 6)
+
+#define IVPU_MMU_IRQ_EVTQ_EN BIT(2)
+#define IVPU_MMU_IRQ_GERROR_EN BIT(0)
+
+#define IVPU_MMU_CR0_ATSCHK BIT(4)
+#define IVPU_MMU_CR0_CMDQEN BIT(3)
+#define IVPU_MMU_CR0_EVTQEN BIT(2)
+#define IVPU_MMU_CR0_PRIQEN BIT(1)
+#define IVPU_MMU_CR0_SMMUEN BIT(0)
+
+#define IVPU_MMU_CR1_TABLE_SH GENMASK(11, 10)
+#define IVPU_MMU_CR1_TABLE_OC GENMASK(9, 8)
+#define IVPU_MMU_CR1_TABLE_IC GENMASK(7, 6)
+#define IVPU_MMU_CR1_QUEUE_SH GENMASK(5, 4)
+#define IVPU_MMU_CR1_QUEUE_OC GENMASK(3, 2)
+#define IVPU_MMU_CR1_QUEUE_IC GENMASK(1, 0)
+#define IVPU_MMU_CACHE_NC 0
+#define IVPU_MMU_CACHE_WB 1
+#define IVPU_MMU_CACHE_WT 2
+#define IVPU_MMU_SH_NSH 0
+#define IVPU_MMU_SH_OSH 2
+#define IVPU_MMU_SH_ISH 3
+
+#define IVPU_MMU_CMDQ_OP GENMASK_ULL(7, 0)
+
+#define IVPU_MMU_CD_0_TCR_T0SZ GENMASK_ULL(5, 0)
+#define IVPU_MMU_CD_0_TCR_TG0 GENMASK_ULL(7, 6)
+#define IVPU_MMU_CD_0_TCR_IRGN0 GENMASK_ULL(9, 8)
+#define IVPU_MMU_CD_0_TCR_ORGN0 GENMASK_ULL(11, 10)
+#define IVPU_MMU_CD_0_TCR_SH0 GENMASK_ULL(13, 12)
+#define IVPU_MMU_CD_0_TCR_EPD0 BIT_ULL(14)
+#define IVPU_MMU_CD_0_TCR_EPD1 BIT_ULL(30)
+#define IVPU_MMU_CD_0_ENDI BIT(15)
+#define IVPU_MMU_CD_0_V BIT(31)
+#define IVPU_MMU_CD_0_TCR_IPS GENMASK_ULL(34, 32)
+#define IVPU_MMU_CD_0_TCR_TBI0 BIT_ULL(38)
+#define IVPU_MMU_CD_0_AA64 BIT(41)
+#define IVPU_MMU_CD_0_S BIT(44)
+#define IVPU_MMU_CD_0_R BIT(45)
+#define IVPU_MMU_CD_0_A BIT(46)
+#define IVPU_MMU_CD_0_ASET BIT(47)
+#define IVPU_MMU_CD_0_ASID GENMASK_ULL(63, 48)
+
+#define IVPU_MMU_CD_1_TTB0_MASK GENMASK_ULL(51, 4)
+
+#define IVPU_MMU_STE_0_S1CDMAX GENMASK_ULL(63, 59)
+#define IVPU_MMU_STE_0_S1FMT GENMASK_ULL(5, 4)
+#define IVPU_MMU_STE_0_S1FMT_LINEAR 0
+#define IVPU_MMU_STE_DWORDS 8
+#define IVPU_MMU_STE_0_CFG_S1_TRANS 5
+#define IVPU_MMU_STE_0_CFG GENMASK_ULL(3, 1)
+#define IVPU_MMU_STE_0_S1CTXPTR_MASK GENMASK_ULL(51, 6)
+#define IVPU_MMU_STE_0_V BIT(0)
+
+#define IVPU_MMU_STE_1_STRW_NSEL1 0ul
+#define IVPU_MMU_STE_1_CONT GENMASK_ULL(16, 13)
+#define IVPU_MMU_STE_1_STRW GENMASK_ULL(31, 30)
+#define IVPU_MMU_STE_1_PRIVCFG GENMASK_ULL(49, 48)
+#define IVPU_MMU_STE_1_PRIVCFG_UNPRIV 2ul
+#define IVPU_MMU_STE_1_INSTCFG GENMASK_ULL(51, 50)
+#define IVPU_MMU_STE_1_INSTCFG_DATA 2ul
+#define IVPU_MMU_STE_1_MEV BIT(19)
+#define IVPU_MMU_STE_1_S1STALLD BIT(27)
+#define IVPU_MMU_STE_1_S1C_CACHE_NC 0ul
+#define IVPU_MMU_STE_1_S1C_CACHE_WBRA 1ul
+#define IVPU_MMU_STE_1_S1C_CACHE_WT 2ul
+#define IVPU_MMU_STE_1_S1C_CACHE_WB 3ul
+#define IVPU_MMU_STE_1_S1CIR GENMASK_ULL(3, 2)
+#define IVPU_MMU_STE_1_S1COR GENMASK_ULL(5, 4)
+#define IVPU_MMU_STE_1_S1CSH GENMASK_ULL(7, 6)
+#define IVPU_MMU_STE_1_S1DSS GENMASK_ULL(1, 0)
+#define IVPU_MMU_STE_1_S1DSS_TERMINATE 0x0
+
+#define IVPU_MMU_REG_TIMEOUT_US (10 * USEC_PER_MSEC)
+#define IVPU_MMU_QUEUE_TIMEOUT_US (100 * USEC_PER_MSEC)
+
+#define IVPU_MMU_GERROR_ERR_MASK ((REG_FLD(MTL_VPU_HOST_MMU_GERROR, CMDQ)) | \
+ (REG_FLD(MTL_VPU_HOST_MMU_GERROR, EVTQ_ABT)) | \
+ (REG_FLD(MTL_VPU_HOST_MMU_GERROR, PRIQ_ABT)) | \
+ (REG_FLD(MTL_VPU_HOST_MMU_GERROR, MSI_CMDQ_ABT)) | \
+ (REG_FLD(MTL_VPU_HOST_MMU_GERROR, MSI_EVTQ_ABT)) | \
+ (REG_FLD(MTL_VPU_HOST_MMU_GERROR, MSI_PRIQ_ABT)) | \
+ (REG_FLD(MTL_VPU_HOST_MMU_GERROR, MSI_ABT)))
+
+static char *ivpu_mmu_event_to_str(u32 cmd)
+{
+ switch (cmd) {
+ case IVPU_MMU_EVT_F_UUT:
+ return "Unsupported Upstream Transaction";
+ case IVPU_MMU_EVT_C_BAD_STREAMID:
+ return "Transaction StreamID out of range";
+ case IVPU_MMU_EVT_F_STE_FETCH:
+ return "Fetch of STE caused external abort";
+ case IVPU_MMU_EVT_C_BAD_STE:
+ return "Used STE invalid";
+ case IVPU_MMU_EVT_F_BAD_ATS_TREQ:
+ return "Address Request disallowed for a StreamID";
+ case IVPU_MMU_EVT_F_STREAM_DISABLED:
+ return "Transaction marks non-substream disabled";
+ case IVPU_MMU_EVT_F_TRANSL_FORBIDDEN:
+ return "MMU bypass is disallowed for this StreamID";
+ case IVPU_MMU_EVT_C_BAD_SUBSTREAMID:
+ return "Invalid StreamID";
+ case IVPU_MMU_EVT_F_CD_FETCH:
+ return "Fetch of CD caused external abort";
+ case IVPU_MMU_EVT_C_BAD_CD:
+ return "Fetched CD invalid";
+ case IVPU_MMU_EVT_F_WALK_EABT:
+ return " An external abort occurred fetching a TLB";
+ case IVPU_MMU_EVT_F_TRANSLATION:
+ return "Translation fault";
+ case IVPU_MMU_EVT_F_ADDR_SIZE:
+ return " Output address caused address size fault";
+ case IVPU_MMU_EVT_F_ACCESS:
+ return "Access flag fault";
+ case IVPU_MMU_EVT_F_PERMISSION:
+ return "Permission fault occurred on page access";
+ case IVPU_MMU_EVT_F_TLB_CONFLICT:
+ return "A TLB conflict";
+ case IVPU_MMU_EVT_F_CFG_CONFLICT:
+ return "A configuration cache conflict";
+ case IVPU_MMU_EVT_E_PAGE_REQUEST:
+ return "Page request hint from a client device";
+ case IVPU_MMU_EVT_F_VMS_FETCH:
+ return "Fetch of VMS caused external abort";
+ default:
+ return "Unknown CMDQ command";
+ }
+}
+
+static void ivpu_mmu_config_check(struct ivpu_device *vdev)
+{
+ u32 val_ref;
+ u32 val;
+
+ if (ivpu_is_simics(vdev))
+ val_ref = IVPU_MMU_IDR0_REF_SIMICS;
+ else
+ val_ref = IVPU_MMU_IDR0_REF;
+
+ val = REGV_RD32(MTL_VPU_HOST_MMU_IDR0);
+ if (val != val_ref)
+ ivpu_dbg(vdev, MMU, "IDR0 0x%x != IDR0_REF 0x%x\n", val, val_ref);
+
+ val = REGV_RD32(MTL_VPU_HOST_MMU_IDR1);
+ if (val != IVPU_MMU_IDR1_REF)
+ ivpu_dbg(vdev, MMU, "IDR1 0x%x != IDR1_REF 0x%x\n", val, IVPU_MMU_IDR1_REF);
+
+ val = REGV_RD32(MTL_VPU_HOST_MMU_IDR3);
+ if (val != IVPU_MMU_IDR3_REF)
+ ivpu_dbg(vdev, MMU, "IDR3 0x%x != IDR3_REF 0x%x\n", val, IVPU_MMU_IDR3_REF);
+
+ if (ivpu_is_simics(vdev))
+ val_ref = IVPU_MMU_IDR5_REF_SIMICS;
+ else if (ivpu_is_fpga(vdev))
+ val_ref = IVPU_MMU_IDR5_REF_FPGA;
+ else
+ val_ref = IVPU_MMU_IDR5_REF;
+
+ val = REGV_RD32(MTL_VPU_HOST_MMU_IDR5);
+ if (val != val_ref)
+ ivpu_dbg(vdev, MMU, "IDR5 0x%x != IDR5_REF 0x%x\n", val, val_ref);
+}
+
+static int ivpu_mmu_cdtab_alloc(struct ivpu_device *vdev)
+{
+ struct ivpu_mmu_info *mmu = vdev->mmu;
+ struct ivpu_mmu_cdtab *cdtab = &mmu->cdtab;
+ size_t size = IVPU_MMU_CDTAB_ENT_COUNT * IVPU_MMU_CDTAB_ENT_SIZE;
+
+ cdtab->base = dmam_alloc_coherent(vdev->drm.dev, size, &cdtab->dma, GFP_KERNEL);
+ if (!cdtab->base)
+ return -ENOMEM;
+
+ ivpu_dbg(vdev, MMU, "CDTAB alloc: dma=%pad size=%zu\n", &cdtab->dma, size);
+
+ return 0;
+}
+
+static int ivpu_mmu_strtab_alloc(struct ivpu_device *vdev)
+{
+ struct ivpu_mmu_info *mmu = vdev->mmu;
+ struct ivpu_mmu_strtab *strtab = &mmu->strtab;
+ size_t size = IVPU_MMU_STRTAB_ENT_COUNT * IVPU_MMU_STRTAB_ENT_SIZE;
+
+ strtab->base = dmam_alloc_coherent(vdev->drm.dev, size, &strtab->dma, GFP_KERNEL);
+ if (!strtab->base)
+ return -ENOMEM;
+
+ strtab->base_cfg = IVPU_MMU_STRTAB_CFG;
+ strtab->dma_q = IVPU_MMU_STRTAB_BASE_RA;
+ strtab->dma_q |= strtab->dma & IVPU_MMU_STRTAB_BASE_ADDR_MASK;
+
+ ivpu_dbg(vdev, MMU, "STRTAB alloc: dma=%pad dma_q=%pad size=%zu\n",
+ &strtab->dma, &strtab->dma_q, size);
+
+ return 0;
+}
+
+static int ivpu_mmu_cmdq_alloc(struct ivpu_device *vdev)
+{
+ struct ivpu_mmu_info *mmu = vdev->mmu;
+ struct ivpu_mmu_queue *q = &mmu->cmdq;
+
+ q->base = dmam_alloc_coherent(vdev->drm.dev, IVPU_MMU_CMDQ_SIZE, &q->dma, GFP_KERNEL);
+ if (!q->base)
+ return -ENOMEM;
+
+ q->dma_q = IVPU_MMU_Q_BASE_RWA;
+ q->dma_q |= q->dma & IVPU_MMU_Q_BASE_ADDR_MASK;
+ q->dma_q |= IVPU_MMU_Q_COUNT_LOG2;
+
+ ivpu_dbg(vdev, MMU, "CMDQ alloc: dma=%pad dma_q=%pad size=%u\n",
+ &q->dma, &q->dma_q, IVPU_MMU_CMDQ_SIZE);
+
+ return 0;
+}
+
+static int ivpu_mmu_evtq_alloc(struct ivpu_device *vdev)
+{
+ struct ivpu_mmu_info *mmu = vdev->mmu;
+ struct ivpu_mmu_queue *q = &mmu->evtq;
+
+ q->base = dmam_alloc_coherent(vdev->drm.dev, IVPU_MMU_EVTQ_SIZE, &q->dma, GFP_KERNEL);
+ if (!q->base)
+ return -ENOMEM;
+
+ q->dma_q = IVPU_MMU_Q_BASE_RWA;
+ q->dma_q |= q->dma & IVPU_MMU_Q_BASE_ADDR_MASK;
+ q->dma_q |= IVPU_MMU_Q_COUNT_LOG2;
+
+ ivpu_dbg(vdev, MMU, "EVTQ alloc: dma=%pad dma_q=%pad size=%u\n",
+ &q->dma, &q->dma_q, IVPU_MMU_EVTQ_SIZE);
+
+ return 0;
+}
+
+static int ivpu_mmu_structs_alloc(struct ivpu_device *vdev)
+{
+ int ret;
+
+ ret = ivpu_mmu_cdtab_alloc(vdev);
+ if (ret) {
+ ivpu_err(vdev, "Failed to allocate cdtab: %d\n", ret);
+ return ret;
+ }
+
+ ret = ivpu_mmu_strtab_alloc(vdev);
+ if (ret) {
+ ivpu_err(vdev, "Failed to allocate strtab: %d\n", ret);
+ return ret;
+ }
+
+ ret = ivpu_mmu_cmdq_alloc(vdev);
+ if (ret) {
+ ivpu_err(vdev, "Failed to allocate cmdq: %d\n", ret);
+ return ret;
+ }
+
+ ret = ivpu_mmu_evtq_alloc(vdev);
+ if (ret)
+ ivpu_err(vdev, "Failed to allocate evtq: %d\n", ret);
+
+ return ret;
+}
+
+static int ivpu_mmu_reg_write(struct ivpu_device *vdev, u32 reg, u32 val)
+{
+ u32 reg_ack = reg + 4; /* ACK register is 4B after base register */
+ u32 val_ack;
+ int ret;
+
+ REGV_WR32(reg, val);
+
+ ret = REGV_POLL(reg_ack, val_ack, (val == val_ack), IVPU_MMU_REG_TIMEOUT_US);
+ if (ret)
+ ivpu_err(vdev, "Failed to write register 0x%x\n", reg);
+
+ return ret;
+}
+
+static int ivpu_mmu_irqs_setup(struct ivpu_device *vdev)
+{
+ u32 irq_ctrl = IVPU_MMU_IRQ_EVTQ_EN | IVPU_MMU_IRQ_GERROR_EN;
+ int ret;
+
+ ret = ivpu_mmu_reg_write(vdev, MTL_VPU_HOST_MMU_IRQ_CTRL, 0);
+ if (ret)
+ return ret;
+
+ return ivpu_mmu_reg_write(vdev, MTL_VPU_HOST_MMU_IRQ_CTRL, irq_ctrl);
+}
+
+static int ivpu_mmu_cmdq_wait_for_cons(struct ivpu_device *vdev)
+{
+ struct ivpu_mmu_queue *cmdq = &vdev->mmu->cmdq;
+
+ return REGV_POLL(MTL_VPU_HOST_MMU_CMDQ_CONS, cmdq->cons, (cmdq->prod == cmdq->cons),
+ IVPU_MMU_QUEUE_TIMEOUT_US);
+}
+
+static int ivpu_mmu_cmdq_cmd_write(struct ivpu_device *vdev, const char *name, u64 data0, u64 data1)
+{
+ struct ivpu_mmu_queue *q = &vdev->mmu->cmdq;
+ u64 *queue_buffer = q->base;
+ int idx = IVPU_MMU_Q_IDX(q->prod) * (IVPU_MMU_CMDQ_CMD_SIZE / sizeof(*queue_buffer));
+
+ if (!CIRC_SPACE(IVPU_MMU_Q_IDX(q->prod), IVPU_MMU_Q_IDX(q->cons), IVPU_MMU_Q_COUNT)) {
+ ivpu_err(vdev, "Failed to write MMU CMD %s\n", name);
+ return -EBUSY;
+ }
+
+ queue_buffer[idx] = data0;
+ queue_buffer[idx + 1] = data1;
+ q->prod = (q->prod + 1) & IVPU_MMU_Q_WRAP_MASK;
+
+ ivpu_dbg(vdev, MMU, "CMD write: %s data: 0x%llx 0x%llx\n", name, data0, data1);
+
+ return 0;
+}
+
+static int ivpu_mmu_cmdq_sync(struct ivpu_device *vdev)
+{
+ struct ivpu_mmu_queue *q = &vdev->mmu->cmdq;
+ u64 val;
+ int ret;
+
+ val = FIELD_PREP(IVPU_MMU_CMD_OPCODE, CMD_SYNC) |
+ FIELD_PREP(IVPU_MMU_CMD_SYNC_0_CS, 0x2) |
+ FIELD_PREP(IVPU_MMU_CMD_SYNC_0_MSH, 0x3) |
+ FIELD_PREP(IVPU_MMU_CMD_SYNC_0_MSI_ATTR, 0xf);
+
+ ret = ivpu_mmu_cmdq_cmd_write(vdev, "SYNC", val, 0);
+ if (ret)
+ return ret;
+
+ clflush_cache_range(q->base, IVPU_MMU_CMDQ_SIZE);
+ REGV_WR32(MTL_VPU_HOST_MMU_CMDQ_PROD, q->prod);
+
+ ret = ivpu_mmu_cmdq_wait_for_cons(vdev);
+ if (ret)
+ ivpu_err(vdev, "Timed out waiting for consumer: %d\n", ret);
+
+ return ret;
+}
+
+static int ivpu_mmu_cmdq_write_cfgi_all(struct ivpu_device *vdev)
+{
+ u64 data0 = FIELD_PREP(IVPU_MMU_CMD_OPCODE, CMD_CFGI_ALL);
+ u64 data1 = FIELD_PREP(IVPU_MMU_CMD_CFGI_1_RANGE, 0x1f);
+
+ return ivpu_mmu_cmdq_cmd_write(vdev, "CFGI_ALL", data0, data1);
+}
+
+static int ivpu_mmu_cmdq_write_tlbi_nh_asid(struct ivpu_device *vdev, u16 ssid)
+{
+ u64 val = FIELD_PREP(IVPU_MMU_CMD_OPCODE, CMD_TLBI_NH_ASID) |
+ FIELD_PREP(IVPU_MMU_CMD_TLBI_0_ASID, ssid);
+
+ return ivpu_mmu_cmdq_cmd_write(vdev, "TLBI_NH_ASID", val, 0);
+}
+
+static int ivpu_mmu_cmdq_write_tlbi_nsnh_all(struct ivpu_device *vdev)
+{
+ u64 val = FIELD_PREP(IVPU_MMU_CMD_OPCODE, CMD_TLBI_NSNH_ALL);
+
+ return ivpu_mmu_cmdq_cmd_write(vdev, "TLBI_NSNH_ALL", val, 0);
+}
+
+static int ivpu_mmu_reset(struct ivpu_device *vdev)
+{
+ struct ivpu_mmu_info *mmu = vdev->mmu;
+ u32 val;
+ int ret;
+
+ memset(mmu->cmdq.base, 0, IVPU_MMU_CMDQ_SIZE);
+ clflush_cache_range(mmu->cmdq.base, IVPU_MMU_CMDQ_SIZE);
+ mmu->cmdq.prod = 0;
+ mmu->cmdq.cons = 0;
+
+ memset(mmu->evtq.base, 0, IVPU_MMU_EVTQ_SIZE);
+ clflush_cache_range(mmu->evtq.base, IVPU_MMU_EVTQ_SIZE);
+ mmu->evtq.prod = 0;
+ mmu->evtq.cons = 0;
+
+ ret = ivpu_mmu_reg_write(vdev, MTL_VPU_HOST_MMU_CR0, 0);
+ if (ret)
+ return ret;
+
+ val = FIELD_PREP(IVPU_MMU_CR1_TABLE_SH, IVPU_MMU_SH_ISH) |
+ FIELD_PREP(IVPU_MMU_CR1_TABLE_OC, IVPU_MMU_CACHE_WB) |
+ FIELD_PREP(IVPU_MMU_CR1_TABLE_IC, IVPU_MMU_CACHE_WB) |
+ FIELD_PREP(IVPU_MMU_CR1_QUEUE_SH, IVPU_MMU_SH_ISH) |
+ FIELD_PREP(IVPU_MMU_CR1_QUEUE_OC, IVPU_MMU_CACHE_WB) |
+ FIELD_PREP(IVPU_MMU_CR1_QUEUE_IC, IVPU_MMU_CACHE_WB);
+ REGV_WR32(MTL_VPU_HOST_MMU_CR1, val);
+
+ REGV_WR64(MTL_VPU_HOST_MMU_STRTAB_BASE, mmu->strtab.dma_q);
+ REGV_WR32(MTL_VPU_HOST_MMU_STRTAB_BASE_CFG, mmu->strtab.base_cfg);
+
+ REGV_WR64(MTL_VPU_HOST_MMU_CMDQ_BASE, mmu->cmdq.dma_q);
+ REGV_WR32(MTL_VPU_HOST_MMU_CMDQ_PROD, 0);
+ REGV_WR32(MTL_VPU_HOST_MMU_CMDQ_CONS, 0);
+
+ val = IVPU_MMU_CR0_CMDQEN;
+ ret = ivpu_mmu_reg_write(vdev, MTL_VPU_HOST_MMU_CR0, val);
+ if (ret)
+ return ret;
+
+ ret = ivpu_mmu_cmdq_write_cfgi_all(vdev);
+ if (ret)
+ return ret;
+
+ ret = ivpu_mmu_cmdq_write_tlbi_nsnh_all(vdev);
+ if (ret)
+ return ret;
+
+ ret = ivpu_mmu_cmdq_sync(vdev);
+ if (ret)
+ return ret;
+
+ REGV_WR64(MTL_VPU_HOST_MMU_EVTQ_BASE, mmu->evtq.dma_q);
+ REGV_WR32(MTL_VPU_HOST_MMU_EVTQ_PROD_SEC, 0);
+ REGV_WR32(MTL_VPU_HOST_MMU_EVTQ_CONS_SEC, 0);
+
+ val |= IVPU_MMU_CR0_EVTQEN;
+ ret = ivpu_mmu_reg_write(vdev, MTL_VPU_HOST_MMU_CR0, val);
+ if (ret)
+ return ret;
+
+ val |= IVPU_MMU_CR0_ATSCHK;
+ ret = ivpu_mmu_reg_write(vdev, MTL_VPU_HOST_MMU_CR0, val);
+ if (ret)
+ return ret;
+
+ ret = ivpu_mmu_irqs_setup(vdev);
+ if (ret)
+ return ret;
+
+ val |= IVPU_MMU_CR0_SMMUEN;
+ return ivpu_mmu_reg_write(vdev, MTL_VPU_HOST_MMU_CR0, val);
+}
+
+static void ivpu_mmu_strtab_link_cd(struct ivpu_device *vdev, u32 sid)
+{
+ struct ivpu_mmu_info *mmu = vdev->mmu;
+ struct ivpu_mmu_strtab *strtab = &mmu->strtab;
+ struct ivpu_mmu_cdtab *cdtab = &mmu->cdtab;
+ u64 *entry = strtab->base + (sid * IVPU_MMU_STRTAB_ENT_SIZE);
+ u64 str[2];
+
+ str[0] = FIELD_PREP(IVPU_MMU_STE_0_CFG, IVPU_MMU_STE_0_CFG_S1_TRANS) |
+ FIELD_PREP(IVPU_MMU_STE_0_S1CDMAX, IVPU_MMU_CDTAB_ENT_COUNT_LOG2) |
+ FIELD_PREP(IVPU_MMU_STE_0_S1FMT, IVPU_MMU_STE_0_S1FMT_LINEAR) |
+ IVPU_MMU_STE_0_V |
+ (cdtab->dma & IVPU_MMU_STE_0_S1CTXPTR_MASK);
+
+ str[1] = FIELD_PREP(IVPU_MMU_STE_1_S1DSS, IVPU_MMU_STE_1_S1DSS_TERMINATE) |
+ FIELD_PREP(IVPU_MMU_STE_1_S1CIR, IVPU_MMU_STE_1_S1C_CACHE_NC) |
+ FIELD_PREP(IVPU_MMU_STE_1_S1COR, IVPU_MMU_STE_1_S1C_CACHE_NC) |
+ FIELD_PREP(IVPU_MMU_STE_1_S1CSH, IVPU_MMU_SH_NSH) |
+ FIELD_PREP(IVPU_MMU_STE_1_PRIVCFG, IVPU_MMU_STE_1_PRIVCFG_UNPRIV) |
+ FIELD_PREP(IVPU_MMU_STE_1_INSTCFG, IVPU_MMU_STE_1_INSTCFG_DATA) |
+ FIELD_PREP(IVPU_MMU_STE_1_STRW, IVPU_MMU_STE_1_STRW_NSEL1) |
+ FIELD_PREP(IVPU_MMU_STE_1_CONT, IVPU_MMU_STRTAB_CFG_LOG2SIZE) |
+ IVPU_MMU_STE_1_MEV |
+ IVPU_MMU_STE_1_S1STALLD;
+
+ WRITE_ONCE(entry[1], str[1]);
+ WRITE_ONCE(entry[0], str[0]);
+
+ clflush_cache_range(entry, IVPU_MMU_STRTAB_ENT_SIZE);
+
+ ivpu_dbg(vdev, MMU, "STRTAB write entry (SSID=%u): 0x%llx, 0x%llx\n", sid, str[0], str[1]);
+}
+
+static int ivpu_mmu_strtab_init(struct ivpu_device *vdev)
+{
+ ivpu_mmu_strtab_link_cd(vdev, IVPU_MMU_STREAM_ID0);
+ ivpu_mmu_strtab_link_cd(vdev, IVPU_MMU_STREAM_ID3);
+
+ return 0;
+}
+
+int ivpu_mmu_invalidate_tlb(struct ivpu_device *vdev, u16 ssid)
+{
+ struct ivpu_mmu_info *mmu = vdev->mmu;
+ int ret;
+
+ ret = mutex_lock_interruptible(&mmu->lock);
+ if (ret)
+ return ret;
+
+ if (!mmu->on) {
+ ret = 0;
+ goto unlock;
+ }
+
+ ret = ivpu_mmu_cmdq_write_tlbi_nh_asid(vdev, ssid);
+ if (ret)
+ goto unlock;
+
+ ret = ivpu_mmu_cmdq_sync(vdev);
+unlock:
+ mutex_unlock(&mmu->lock);
+ return ret;
+}
+
+static int ivpu_mmu_cd_add(struct ivpu_device *vdev, u32 ssid, u64 cd_dma)
+{
+ struct ivpu_mmu_info *mmu = vdev->mmu;
+ struct ivpu_mmu_cdtab *cdtab = &mmu->cdtab;
+ u64 *entry;
+ u64 cd[4];
+ int ret;
+
+ if (ssid > IVPU_MMU_CDTAB_ENT_COUNT)
+ return -EINVAL;
+
+ entry = cdtab->base + (ssid * IVPU_MMU_CDTAB_ENT_SIZE);
+
+ if (cd_dma != 0) {
+ cd[0] = FIELD_PREP(IVPU_MMU_CD_0_TCR_T0SZ, 26) |
+ FIELD_PREP(IVPU_MMU_CD_0_TCR_TG0, 0) |
+ FIELD_PREP(IVPU_MMU_CD_0_TCR_IRGN0, 0) |
+ FIELD_PREP(IVPU_MMU_CD_0_TCR_ORGN0, 0) |
+ FIELD_PREP(IVPU_MMU_CD_0_TCR_SH0, 0) |
+ FIELD_PREP(IVPU_MMU_CD_0_TCR_IPS, 3) |
+ FIELD_PREP(IVPU_MMU_CD_0_ASID, ssid) |
+ IVPU_MMU_CD_0_TCR_EPD1 |
+ IVPU_MMU_CD_0_AA64 |
+ IVPU_MMU_CD_0_R |
+ IVPU_MMU_CD_0_ASET |
+ IVPU_MMU_CD_0_V;
+ cd[1] = cd_dma & IVPU_MMU_CD_1_TTB0_MASK;
+ cd[2] = 0;
+ cd[3] = 0x0000000000007444;
+
+ /* For global context generate memory fault on VPU */
+ if (ssid == IVPU_GLOBAL_CONTEXT_MMU_SSID)
+ cd[0] |= IVPU_MMU_CD_0_A;
+ } else {
+ memset(cd, 0, sizeof(cd));
+ }
+
+ WRITE_ONCE(entry[1], cd[1]);
+ WRITE_ONCE(entry[2], cd[2]);
+ WRITE_ONCE(entry[3], cd[3]);
+ WRITE_ONCE(entry[0], cd[0]);
+
+ clflush_cache_range(entry, IVPU_MMU_CDTAB_ENT_SIZE);
+
+ ivpu_dbg(vdev, MMU, "CDTAB %s entry (SSID=%u, dma=%pad): 0x%llx, 0x%llx, 0x%llx, 0x%llx\n",
+ cd_dma ? "write" : "clear", ssid, &cd_dma, cd[0], cd[1], cd[2], cd[3]);
+
+ ret = mutex_lock_interruptible(&mmu->lock);
+ if (ret)
+ return ret;
+
+ if (!mmu->on) {
+ ret = 0;
+ goto unlock;
+ }
+
+ ret = ivpu_mmu_cmdq_write_cfgi_all(vdev);
+ if (ret)
+ goto unlock;
+
+ ret = ivpu_mmu_cmdq_sync(vdev);
+unlock:
+ mutex_unlock(&mmu->lock);
+ return ret;
+}
+
+static int ivpu_mmu_cd_add_gbl(struct ivpu_device *vdev)
+{
+ int ret;
+
+ ret = ivpu_mmu_cd_add(vdev, 0, vdev->gctx.pgtable.pgd_dma);
+ if (ret)
+ ivpu_err(vdev, "Failed to add global CD entry: %d\n", ret);
+
+ return ret;
+}
+
+static int ivpu_mmu_cd_add_user(struct ivpu_device *vdev, u32 ssid, dma_addr_t cd_dma)
+{
+ int ret;
+
+ if (ssid == 0) {
+ ivpu_err(vdev, "Invalid SSID: %u\n", ssid);
+ return -EINVAL;
+ }
+
+ ret = ivpu_mmu_cd_add(vdev, ssid, cd_dma);
+ if (ret)
+ ivpu_err(vdev, "Failed to add CD entry SSID=%u: %d\n", ssid, ret);
+
+ return ret;
+}
+
+int ivpu_mmu_init(struct ivpu_device *vdev)
+{
+ struct ivpu_mmu_info *mmu = vdev->mmu;
+ int ret;
+
+ ivpu_dbg(vdev, MMU, "Init..\n");
+
+ drmm_mutex_init(&vdev->drm, &mmu->lock);
+ ivpu_mmu_config_check(vdev);
+
+ ret = ivpu_mmu_structs_alloc(vdev);
+ if (ret)
+ return ret;
+
+ ret = ivpu_mmu_strtab_init(vdev);
+ if (ret) {
+ ivpu_err(vdev, "Failed to initialize strtab: %d\n", ret);
+ return ret;
+ }
+
+ ret = ivpu_mmu_cd_add_gbl(vdev);
+ if (ret) {
+ ivpu_err(vdev, "Failed to initialize strtab: %d\n", ret);
+ return ret;
+ }
+
+ ret = ivpu_mmu_enable(vdev);
+ if (ret) {
+ ivpu_err(vdev, "Failed to resume MMU: %d\n", ret);
+ return ret;
+ }
+
+ ivpu_dbg(vdev, MMU, "Init done\n");
+
+ return 0;
+}
+
+int ivpu_mmu_enable(struct ivpu_device *vdev)
+{
+ struct ivpu_mmu_info *mmu = vdev->mmu;
+ int ret;
+
+ mutex_lock(&mmu->lock);
+
+ mmu->on = true;
+
+ ret = ivpu_mmu_reset(vdev);
+ if (ret) {
+ ivpu_err(vdev, "Failed to reset MMU: %d\n", ret);
+ goto err;
+ }
+
+ ret = ivpu_mmu_cmdq_write_cfgi_all(vdev);
+ if (ret)
+ goto err;
+
+ ret = ivpu_mmu_cmdq_write_tlbi_nsnh_all(vdev);
+ if (ret)
+ goto err;
+
+ ret = ivpu_mmu_cmdq_sync(vdev);
+ if (ret)
+ goto err;
+
+ mutex_unlock(&mmu->lock);
+
+ return 0;
+err:
+ mmu->on = false;
+ mutex_unlock(&mmu->lock);
+ return ret;
+}
+
+void ivpu_mmu_disable(struct ivpu_device *vdev)
+{
+ struct ivpu_mmu_info *mmu = vdev->mmu;
+
+ mutex_lock(&mmu->lock);
+ mmu->on = false;
+ mutex_unlock(&mmu->lock);
+}
+
+static void ivpu_mmu_dump_event(struct ivpu_device *vdev, u32 *event)
+{
+ u32 ssid = FIELD_GET(IVPU_MMU_EVT_SSID_MASK, event[0]);
+ u32 op = FIELD_GET(IVPU_MMU_EVT_OP_MASK, event[0]);
+ u64 fetch_addr = ((u64)event[7]) << 32 | event[6];
+ u64 in_addr = ((u64)event[5]) << 32 | event[4];
+ u32 sid = event[1];
+
+ ivpu_err(vdev, "MMU EVTQ: 0x%x (%s) SSID: %d SID: %d, e[2] %08x, e[3] %08x, in addr: 0x%llx, fetch addr: 0x%llx\n",
+ op, ivpu_mmu_event_to_str(op), ssid, sid, event[2], event[3], in_addr, fetch_addr);
+}
+
+static u32 *ivpu_mmu_get_event(struct ivpu_device *vdev)
+{
+ struct ivpu_mmu_queue *evtq = &vdev->mmu->evtq;
+ u32 idx = IVPU_MMU_Q_IDX(evtq->cons);
+ u32 *evt = evtq->base + (idx * IVPU_MMU_EVTQ_CMD_SIZE);
+
+ evtq->prod = REGV_RD32(MTL_VPU_HOST_MMU_EVTQ_PROD_SEC);
+ if (!CIRC_CNT(IVPU_MMU_Q_IDX(evtq->prod), IVPU_MMU_Q_IDX(evtq->cons), IVPU_MMU_Q_COUNT))
+ return NULL;
+
+ clflush_cache_range(evt, IVPU_MMU_EVTQ_CMD_SIZE);
+
+ evtq->cons = (evtq->cons + 1) & IVPU_MMU_Q_WRAP_MASK;
+ REGV_WR32(MTL_VPU_HOST_MMU_EVTQ_CONS_SEC, evtq->cons);
+
+ return evt;
+}
+
+void ivpu_mmu_irq_evtq_handler(struct ivpu_device *vdev)
+{
+ bool schedule_recovery = false;
+ u32 *event;
+ u32 ssid;
+
+ ivpu_dbg(vdev, IRQ, "MMU event queue\n");
+
+ while ((event = ivpu_mmu_get_event(vdev)) != NULL) {
+ ivpu_mmu_dump_event(vdev, event);
+
+ ssid = FIELD_GET(IVPU_MMU_EVT_SSID_MASK, event[0]);
+ if (ssid == IVPU_GLOBAL_CONTEXT_MMU_SSID)
+ schedule_recovery = true;
+ else
+ ivpu_mmu_user_context_mark_invalid(vdev, ssid);
+ }
+
+ if (schedule_recovery)
+ ivpu_pm_schedule_recovery(vdev);
+}
+
+void ivpu_mmu_irq_gerr_handler(struct ivpu_device *vdev)
+{
+ u32 gerror_val, gerrorn_val, active;
+
+ ivpu_dbg(vdev, IRQ, "MMU error\n");
+
+ gerror_val = REGV_RD32(MTL_VPU_HOST_MMU_GERROR);
+ gerrorn_val = REGV_RD32(MTL_VPU_HOST_MMU_GERRORN);
+
+ active = gerror_val ^ gerrorn_val;
+ if (!(active & IVPU_MMU_GERROR_ERR_MASK))
+ return;
+
+ if (REG_TEST_FLD(MTL_VPU_HOST_MMU_GERROR, MSI_ABT, active))
+ ivpu_warn_ratelimited(vdev, "MMU MSI ABT write aborted\n");
+
+ if (REG_TEST_FLD(MTL_VPU_HOST_MMU_GERROR, MSI_PRIQ_ABT, active))
+ ivpu_warn_ratelimited(vdev, "MMU PRIQ MSI ABT write aborted\n");
+
+ if (REG_TEST_FLD(MTL_VPU_HOST_MMU_GERROR, MSI_EVTQ_ABT, active))
+ ivpu_warn_ratelimited(vdev, "MMU EVTQ MSI ABT write aborted\n");
+
+ if (REG_TEST_FLD(MTL_VPU_HOST_MMU_GERROR, MSI_CMDQ_ABT, active))
+ ivpu_warn_ratelimited(vdev, "MMU CMDQ MSI ABT write aborted\n");
+
+ if (REG_TEST_FLD(MTL_VPU_HOST_MMU_GERROR, PRIQ_ABT, active))
+ ivpu_err_ratelimited(vdev, "MMU PRIQ write aborted\n");
+
+ if (REG_TEST_FLD(MTL_VPU_HOST_MMU_GERROR, EVTQ_ABT, active))
+ ivpu_err_ratelimited(vdev, "MMU EVTQ write aborted\n");
+
+ if (REG_TEST_FLD(MTL_VPU_HOST_MMU_GERROR, CMDQ, active))
+ ivpu_err_ratelimited(vdev, "MMU CMDQ write aborted\n");
+
+ REGV_WR32(MTL_VPU_HOST_MMU_GERRORN, gerror_val);
+}
+
+int ivpu_mmu_set_pgtable(struct ivpu_device *vdev, int ssid, struct ivpu_mmu_pgtable *pgtable)
+{
+ return ivpu_mmu_cd_add_user(vdev, ssid, pgtable->pgd_dma);
+}
+
+void ivpu_mmu_clear_pgtable(struct ivpu_device *vdev, int ssid)
+{
+ ivpu_mmu_cd_add_user(vdev, ssid, 0); /* 0 will clear CD entry */
+}
diff --git a/drivers/accel/ivpu/ivpu_mmu.h b/drivers/accel/ivpu/ivpu_mmu.h
new file mode 100644
index 000000000000..cb551126806b
--- /dev/null
+++ b/drivers/accel/ivpu/ivpu_mmu.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2020-2023 Intel Corporation
+ */
+
+#ifndef __IVPU_MMU_H__
+#define __IVPU_MMU_H__
+
+struct ivpu_device;
+
+struct ivpu_mmu_cdtab {
+ void *base;
+ dma_addr_t dma;
+};
+
+struct ivpu_mmu_strtab {
+ void *base;
+ dma_addr_t dma;
+ u64 dma_q;
+ u32 base_cfg;
+};
+
+struct ivpu_mmu_queue {
+ void *base;
+ dma_addr_t dma;
+ u64 dma_q;
+ u32 prod;
+ u32 cons;
+};
+
+struct ivpu_mmu_info {
+ struct mutex lock; /* Protects cdtab, strtab, cmdq, on */
+ struct ivpu_mmu_cdtab cdtab;
+ struct ivpu_mmu_strtab strtab;
+ struct ivpu_mmu_queue cmdq;
+ struct ivpu_mmu_queue evtq;
+ bool on;
+};
+
+int ivpu_mmu_init(struct ivpu_device *vdev);
+void ivpu_mmu_disable(struct ivpu_device *vdev);
+int ivpu_mmu_enable(struct ivpu_device *vdev);
+int ivpu_mmu_set_pgtable(struct ivpu_device *vdev, int ssid, struct ivpu_mmu_pgtable *pgtable);
+void ivpu_mmu_clear_pgtable(struct ivpu_device *vdev, int ssid);
+int ivpu_mmu_invalidate_tlb(struct ivpu_device *vdev, u16 ssid);
+
+void ivpu_mmu_irq_evtq_handler(struct ivpu_device *vdev);
+void ivpu_mmu_irq_gerr_handler(struct ivpu_device *vdev);
+
+#endif /* __IVPU_MMU_H__ */
diff --git a/drivers/accel/ivpu/ivpu_mmu_context.c b/drivers/accel/ivpu/ivpu_mmu_context.c
new file mode 100644
index 000000000000..8ce9b12ac356
--- /dev/null
+++ b/drivers/accel/ivpu/ivpu_mmu_context.c
@@ -0,0 +1,398 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2020-2023 Intel Corporation
+ */
+
+#include <linux/bitfield.h>
+#include <linux/highmem.h>
+
+#include "ivpu_drv.h"
+#include "ivpu_hw.h"
+#include "ivpu_mmu.h"
+#include "ivpu_mmu_context.h"
+
+#define IVPU_MMU_PGD_INDEX_MASK GENMASK(38, 30)
+#define IVPU_MMU_PMD_INDEX_MASK GENMASK(29, 21)
+#define IVPU_MMU_PTE_INDEX_MASK GENMASK(20, 12)
+#define IVPU_MMU_ENTRY_FLAGS_MASK GENMASK(11, 0)
+#define IVPU_MMU_ENTRY_FLAG_NG BIT(11)
+#define IVPU_MMU_ENTRY_FLAG_AF BIT(10)
+#define IVPU_MMU_ENTRY_FLAG_USER BIT(6)
+#define IVPU_MMU_ENTRY_FLAG_LLC_COHERENT BIT(2)
+#define IVPU_MMU_ENTRY_FLAG_TYPE_PAGE BIT(1)
+#define IVPU_MMU_ENTRY_FLAG_VALID BIT(0)
+
+#define IVPU_MMU_PAGE_SIZE SZ_4K
+#define IVPU_MMU_PTE_MAP_SIZE (IVPU_MMU_PGTABLE_ENTRIES * IVPU_MMU_PAGE_SIZE)
+#define IVPU_MMU_PMD_MAP_SIZE (IVPU_MMU_PGTABLE_ENTRIES * IVPU_MMU_PTE_MAP_SIZE)
+#define IVPU_MMU_PGTABLE_SIZE (IVPU_MMU_PGTABLE_ENTRIES * sizeof(u64))
+
+#define IVPU_MMU_DUMMY_ADDRESS 0xdeadb000
+#define IVPU_MMU_ENTRY_VALID (IVPU_MMU_ENTRY_FLAG_TYPE_PAGE | IVPU_MMU_ENTRY_FLAG_VALID)
+#define IVPU_MMU_ENTRY_INVALID (IVPU_MMU_DUMMY_ADDRESS & ~IVPU_MMU_ENTRY_FLAGS_MASK)
+#define IVPU_MMU_ENTRY_MAPPED (IVPU_MMU_ENTRY_FLAG_AF | IVPU_MMU_ENTRY_FLAG_USER | \
+ IVPU_MMU_ENTRY_FLAG_NG | IVPU_MMU_ENTRY_VALID)
+
+static int ivpu_mmu_pgtable_init(struct ivpu_device *vdev, struct ivpu_mmu_pgtable *pgtable)
+{
+ dma_addr_t pgd_dma;
+ u64 *pgd;
+
+ pgd = dma_alloc_wc(vdev->drm.dev, IVPU_MMU_PGTABLE_SIZE, &pgd_dma, GFP_KERNEL);
+ if (!pgd)
+ return -ENOMEM;
+
+ pgtable->pgd = pgd;
+ pgtable->pgd_dma = pgd_dma;
+
+ return 0;
+}
+
+static void ivpu_mmu_pgtable_free(struct ivpu_device *vdev, struct ivpu_mmu_pgtable *pgtable)
+{
+ int pgd_index, pmd_index;
+
+ for (pgd_index = 0; pgd_index < IVPU_MMU_PGTABLE_ENTRIES; ++pgd_index) {
+ u64 **pmd_entries = pgtable->pgd_cpu_entries[pgd_index];
+ u64 *pmd = pgtable->pgd_entries[pgd_index];
+
+ if (!pmd_entries)
+ continue;
+
+ for (pmd_index = 0; pmd_index < IVPU_MMU_PGTABLE_ENTRIES; ++pmd_index) {
+ if (pmd_entries[pmd_index])
+ dma_free_wc(vdev->drm.dev, IVPU_MMU_PGTABLE_SIZE,
+ pmd_entries[pmd_index],
+ pmd[pmd_index] & ~IVPU_MMU_ENTRY_FLAGS_MASK);
+ }
+
+ kfree(pmd_entries);
+ dma_free_wc(vdev->drm.dev, IVPU_MMU_PGTABLE_SIZE, pgtable->pgd_entries[pgd_index],
+ pgtable->pgd[pgd_index] & ~IVPU_MMU_ENTRY_FLAGS_MASK);
+ }
+
+ dma_free_wc(vdev->drm.dev, IVPU_MMU_PGTABLE_SIZE, pgtable->pgd,
+ pgtable->pgd_dma & ~IVPU_MMU_ENTRY_FLAGS_MASK);
+}
+
+static u64*
+ivpu_mmu_ensure_pmd(struct ivpu_device *vdev, struct ivpu_mmu_pgtable *pgtable, u64 pgd_index)
+{
+ u64 **pmd_entries;
+ dma_addr_t pmd_dma;
+ u64 *pmd;
+
+ if (pgtable->pgd_entries[pgd_index])
+ return pgtable->pgd_entries[pgd_index];
+
+ pmd = dma_alloc_wc(vdev->drm.dev, IVPU_MMU_PGTABLE_SIZE, &pmd_dma, GFP_KERNEL);
+ if (!pmd)
+ return NULL;
+
+ pmd_entries = kzalloc(IVPU_MMU_PGTABLE_SIZE, GFP_KERNEL);
+ if (!pmd_entries)
+ goto err_free_pgd;
+
+ pgtable->pgd_entries[pgd_index] = pmd;
+ pgtable->pgd_cpu_entries[pgd_index] = pmd_entries;
+ pgtable->pgd[pgd_index] = pmd_dma | IVPU_MMU_ENTRY_VALID;
+
+ return pmd;
+
+err_free_pgd:
+ dma_free_wc(vdev->drm.dev, IVPU_MMU_PGTABLE_SIZE, pmd, pmd_dma);
+ return NULL;
+}
+
+static u64*
+ivpu_mmu_ensure_pte(struct ivpu_device *vdev, struct ivpu_mmu_pgtable *pgtable,
+ int pgd_index, int pmd_index)
+{
+ dma_addr_t pte_dma;
+ u64 *pte;
+
+ if (pgtable->pgd_cpu_entries[pgd_index][pmd_index])
+ return pgtable->pgd_cpu_entries[pgd_index][pmd_index];
+
+ pte = dma_alloc_wc(vdev->drm.dev, IVPU_MMU_PGTABLE_SIZE, &pte_dma, GFP_KERNEL);
+ if (!pte)
+ return NULL;
+
+ pgtable->pgd_cpu_entries[pgd_index][pmd_index] = pte;
+ pgtable->pgd_entries[pgd_index][pmd_index] = pte_dma | IVPU_MMU_ENTRY_VALID;
+
+ return pte;
+}
+
+static int
+ivpu_mmu_context_map_page(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx,
+ u64 vpu_addr, dma_addr_t dma_addr, int prot)
+{
+ u64 *pte;
+ int pgd_index = FIELD_GET(IVPU_MMU_PGD_INDEX_MASK, vpu_addr);
+ int pmd_index = FIELD_GET(IVPU_MMU_PMD_INDEX_MASK, vpu_addr);
+ int pte_index = FIELD_GET(IVPU_MMU_PTE_INDEX_MASK, vpu_addr);
+
+ /* Allocate PMD - second level page table if needed */
+ if (!ivpu_mmu_ensure_pmd(vdev, &ctx->pgtable, pgd_index))
+ return -ENOMEM;
+
+ /* Allocate PTE - third level page table if needed */
+ pte = ivpu_mmu_ensure_pte(vdev, &ctx->pgtable, pgd_index, pmd_index);
+ if (!pte)
+ return -ENOMEM;
+
+ /* Update PTE - third level page table with DMA address */
+ pte[pte_index] = dma_addr | prot;
+
+ return 0;
+}
+
+static void ivpu_mmu_context_unmap_page(struct ivpu_mmu_context *ctx, u64 vpu_addr)
+{
+ int pgd_index = FIELD_GET(IVPU_MMU_PGD_INDEX_MASK, vpu_addr);
+ int pmd_index = FIELD_GET(IVPU_MMU_PMD_INDEX_MASK, vpu_addr);
+ int pte_index = FIELD_GET(IVPU_MMU_PTE_INDEX_MASK, vpu_addr);
+
+ /* Update PTE with dummy physical address and clear flags */
+ ctx->pgtable.pgd_cpu_entries[pgd_index][pmd_index][pte_index] = IVPU_MMU_ENTRY_INVALID;
+}
+
+static void
+ivpu_mmu_context_flush_page_tables(struct ivpu_mmu_context *ctx, u64 vpu_addr, size_t size)
+{
+ u64 end_addr = vpu_addr + size;
+ u64 *pgd = ctx->pgtable.pgd;
+
+ /* Align to PMD entry (2 MB) */
+ vpu_addr &= ~(IVPU_MMU_PTE_MAP_SIZE - 1);
+
+ while (vpu_addr < end_addr) {
+ int pgd_index = FIELD_GET(IVPU_MMU_PGD_INDEX_MASK, vpu_addr);
+ u64 pmd_end = (pgd_index + 1) * (u64)IVPU_MMU_PMD_MAP_SIZE;
+ u64 *pmd = ctx->pgtable.pgd_entries[pgd_index];
+
+ while (vpu_addr < end_addr && vpu_addr < pmd_end) {
+ int pmd_index = FIELD_GET(IVPU_MMU_PMD_INDEX_MASK, vpu_addr);
+ u64 *pte = ctx->pgtable.pgd_cpu_entries[pgd_index][pmd_index];
+
+ clflush_cache_range(pte, IVPU_MMU_PGTABLE_SIZE);
+ vpu_addr += IVPU_MMU_PTE_MAP_SIZE;
+ }
+ clflush_cache_range(pmd, IVPU_MMU_PGTABLE_SIZE);
+ }
+ clflush_cache_range(pgd, IVPU_MMU_PGTABLE_SIZE);
+}
+
+static int
+ivpu_mmu_context_map_pages(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx,
+ u64 vpu_addr, dma_addr_t dma_addr, size_t size, int prot)
+{
+ while (size) {
+ int ret = ivpu_mmu_context_map_page(vdev, ctx, vpu_addr, dma_addr, prot);
+
+ if (ret)
+ return ret;
+
+ vpu_addr += IVPU_MMU_PAGE_SIZE;
+ dma_addr += IVPU_MMU_PAGE_SIZE;
+ size -= IVPU_MMU_PAGE_SIZE;
+ }
+
+ return 0;
+}
+
+static void ivpu_mmu_context_unmap_pages(struct ivpu_mmu_context *ctx, u64 vpu_addr, size_t size)
+{
+ while (size) {
+ ivpu_mmu_context_unmap_page(ctx, vpu_addr);
+ vpu_addr += IVPU_MMU_PAGE_SIZE;
+ size -= IVPU_MMU_PAGE_SIZE;
+ }
+}
+
+int
+ivpu_mmu_context_map_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx,
+ u64 vpu_addr, struct sg_table *sgt, bool llc_coherent)
+{
+ struct scatterlist *sg;
+ int prot;
+ int ret;
+ u64 i;
+
+ if (!IS_ALIGNED(vpu_addr, IVPU_MMU_PAGE_SIZE))
+ return -EINVAL;
+ /*
+ * VPU is only 32 bit, but DMA engine is 38 bit
+ * Ranges < 2 GB are reserved for VPU internal registers
+ * Limit range to 8 GB
+ */
+ if (vpu_addr < SZ_2G || vpu_addr > SZ_8G)
+ return -EINVAL;
+
+ prot = IVPU_MMU_ENTRY_MAPPED;
+ if (llc_coherent)
+ prot |= IVPU_MMU_ENTRY_FLAG_LLC_COHERENT;
+
+ mutex_lock(&ctx->lock);
+
+ for_each_sgtable_dma_sg(sgt, sg, i) {
+ u64 dma_addr = sg_dma_address(sg) - sg->offset;
+ size_t size = sg_dma_len(sg) + sg->offset;
+
+ ret = ivpu_mmu_context_map_pages(vdev, ctx, vpu_addr, dma_addr, size, prot);
+ if (ret) {
+ ivpu_err(vdev, "Failed to map context pages\n");
+ mutex_unlock(&ctx->lock);
+ return ret;
+ }
+ ivpu_mmu_context_flush_page_tables(ctx, vpu_addr, size);
+ vpu_addr += size;
+ }
+
+ mutex_unlock(&ctx->lock);
+
+ ret = ivpu_mmu_invalidate_tlb(vdev, ctx->id);
+ if (ret)
+ ivpu_err(vdev, "Failed to invalidate TLB for ctx %u: %d\n", ctx->id, ret);
+ return ret;
+}
+
+void
+ivpu_mmu_context_unmap_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx,
+ u64 vpu_addr, struct sg_table *sgt)
+{
+ struct scatterlist *sg;
+ int ret;
+ u64 i;
+
+ if (!IS_ALIGNED(vpu_addr, IVPU_MMU_PAGE_SIZE))
+ ivpu_warn(vdev, "Unaligned vpu_addr: 0x%llx\n", vpu_addr);
+
+ mutex_lock(&ctx->lock);
+
+ for_each_sgtable_dma_sg(sgt, sg, i) {
+ size_t size = sg_dma_len(sg) + sg->offset;
+
+ ivpu_mmu_context_unmap_pages(ctx, vpu_addr, size);
+ ivpu_mmu_context_flush_page_tables(ctx, vpu_addr, size);
+ vpu_addr += size;
+ }
+
+ mutex_unlock(&ctx->lock);
+
+ ret = ivpu_mmu_invalidate_tlb(vdev, ctx->id);
+ if (ret)
+ ivpu_warn(vdev, "Failed to invalidate TLB for ctx %u: %d\n", ctx->id, ret);
+}
+
+int
+ivpu_mmu_context_insert_node_locked(struct ivpu_mmu_context *ctx,
+ const struct ivpu_addr_range *range,
+ u64 size, struct drm_mm_node *node)
+{
+ lockdep_assert_held(&ctx->lock);
+
+ return drm_mm_insert_node_in_range(&ctx->mm, node, size, IVPU_MMU_PAGE_SIZE,
+ 0, range->start, range->end, DRM_MM_INSERT_BEST);
+}
+
+void
+ivpu_mmu_context_remove_node_locked(struct ivpu_mmu_context *ctx, struct drm_mm_node *node)
+{
+ lockdep_assert_held(&ctx->lock);
+
+ drm_mm_remove_node(node);
+}
+
+static int
+ivpu_mmu_context_init(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, u32 context_id)
+{
+ u64 start, end;
+ int ret;
+
+ mutex_init(&ctx->lock);
+ INIT_LIST_HEAD(&ctx->bo_list);
+
+ ret = ivpu_mmu_pgtable_init(vdev, &ctx->pgtable);
+ if (ret)
+ return ret;
+
+ if (!context_id) {
+ start = vdev->hw->ranges.global_low.start;
+ end = vdev->hw->ranges.global_high.end;
+ } else {
+ start = vdev->hw->ranges.user_low.start;
+ end = vdev->hw->ranges.user_high.end;
+ }
+
+ drm_mm_init(&ctx->mm, start, end - start);
+ ctx->id = context_id;
+
+ return 0;
+}
+
+static void ivpu_mmu_context_fini(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx)
+{
+ drm_WARN_ON(&vdev->drm, !ctx->pgtable.pgd);
+
+ mutex_destroy(&ctx->lock);
+ ivpu_mmu_pgtable_free(vdev, &ctx->pgtable);
+ drm_mm_takedown(&ctx->mm);
+}
+
+int ivpu_mmu_global_context_init(struct ivpu_device *vdev)
+{
+ return ivpu_mmu_context_init(vdev, &vdev->gctx, IVPU_GLOBAL_CONTEXT_MMU_SSID);
+}
+
+void ivpu_mmu_global_context_fini(struct ivpu_device *vdev)
+{
+ return ivpu_mmu_context_fini(vdev, &vdev->gctx);
+}
+
+void ivpu_mmu_user_context_mark_invalid(struct ivpu_device *vdev, u32 ssid)
+{
+ struct ivpu_file_priv *file_priv;
+
+ xa_lock(&vdev->context_xa);
+
+ file_priv = xa_load(&vdev->context_xa, ssid);
+ if (file_priv)
+ file_priv->has_mmu_faults = true;
+
+ xa_unlock(&vdev->context_xa);
+}
+
+int ivpu_mmu_user_context_init(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, u32 ctx_id)
+{
+ int ret;
+
+ drm_WARN_ON(&vdev->drm, !ctx_id);
+
+ ret = ivpu_mmu_context_init(vdev, ctx, ctx_id);
+ if (ret) {
+ ivpu_err(vdev, "Failed to initialize context: %d\n", ret);
+ return ret;
+ }
+
+ ret = ivpu_mmu_set_pgtable(vdev, ctx_id, &ctx->pgtable);
+ if (ret) {
+ ivpu_err(vdev, "Failed to set page table: %d\n", ret);
+ goto err_context_fini;
+ }
+
+ return 0;
+
+err_context_fini:
+ ivpu_mmu_context_fini(vdev, ctx);
+ return ret;
+}
+
+void ivpu_mmu_user_context_fini(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx)
+{
+ drm_WARN_ON(&vdev->drm, !ctx->id);
+
+ ivpu_mmu_clear_pgtable(vdev, ctx->id);
+ ivpu_mmu_context_fini(vdev, ctx);
+}
diff --git a/drivers/accel/ivpu/ivpu_mmu_context.h b/drivers/accel/ivpu/ivpu_mmu_context.h
new file mode 100644
index 000000000000..ddf11b95023a
--- /dev/null
+++ b/drivers/accel/ivpu/ivpu_mmu_context.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2020-2023 Intel Corporation
+ */
+
+#ifndef __IVPU_MMU_CONTEXT_H__
+#define __IVPU_MMU_CONTEXT_H__
+
+#include <drm/drm_mm.h>
+
+struct ivpu_device;
+struct ivpu_file_priv;
+struct ivpu_addr_range;
+
+#define IVPU_MMU_PGTABLE_ENTRIES 512
+
+struct ivpu_mmu_pgtable {
+ u64 **pgd_cpu_entries[IVPU_MMU_PGTABLE_ENTRIES];
+ u64 *pgd_entries[IVPU_MMU_PGTABLE_ENTRIES];
+ u64 *pgd;
+ dma_addr_t pgd_dma;
+};
+
+struct ivpu_mmu_context {
+ struct mutex lock; /* protects: mm, pgtable, bo_list */
+ struct drm_mm mm;
+ struct ivpu_mmu_pgtable pgtable;
+ struct list_head bo_list;
+ u32 id;
+};
+
+int ivpu_mmu_global_context_init(struct ivpu_device *vdev);
+void ivpu_mmu_global_context_fini(struct ivpu_device *vdev);
+
+int ivpu_mmu_user_context_init(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, u32 ctx_id);
+void ivpu_mmu_user_context_fini(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx);
+void ivpu_mmu_user_context_mark_invalid(struct ivpu_device *vdev, u32 ssid);
+
+int ivpu_mmu_context_insert_node_locked(struct ivpu_mmu_context *ctx,
+ const struct ivpu_addr_range *range,
+ u64 size, struct drm_mm_node *node);
+void ivpu_mmu_context_remove_node_locked(struct ivpu_mmu_context *ctx,
+ struct drm_mm_node *node);
+
+int ivpu_mmu_context_map_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx,
+ u64 vpu_addr, struct sg_table *sgt, bool llc_coherent);
+void ivpu_mmu_context_unmap_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx,
+ u64 vpu_addr, struct sg_table *sgt);
+
+#endif /* __IVPU_MMU_CONTEXT_H__ */
diff --git a/drivers/accel/ivpu/ivpu_pm.c b/drivers/accel/ivpu/ivpu_pm.c
new file mode 100644
index 000000000000..553bcbd787b3
--- /dev/null
+++ b/drivers/accel/ivpu/ivpu_pm.c
@@ -0,0 +1,329 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2020-2023 Intel Corporation
+ */
+
+#include <linux/highmem.h>
+#include <linux/moduleparam.h>
+#include <linux/pci.h>
+#include <linux/pm_runtime.h>
+#include <linux/reboot.h>
+
+#include "vpu_boot_api.h"
+#include "ivpu_drv.h"
+#include "ivpu_hw.h"
+#include "ivpu_fw.h"
+#include "ivpu_ipc.h"
+#include "ivpu_job.h"
+#include "ivpu_mmu.h"
+#include "ivpu_pm.h"
+
+static bool ivpu_disable_recovery;
+module_param_named_unsafe(disable_recovery, ivpu_disable_recovery, bool, 0644);
+MODULE_PARM_DESC(disable_recovery, "Disables recovery when VPU hang is detected");
+
+#define PM_RESCHEDULE_LIMIT 5
+
+static void ivpu_pm_prepare_cold_boot(struct ivpu_device *vdev)
+{
+ struct ivpu_fw_info *fw = vdev->fw;
+
+ ivpu_cmdq_reset_all_contexts(vdev);
+ ivpu_ipc_reset(vdev);
+ ivpu_fw_load(vdev);
+ fw->entry_point = fw->cold_boot_entry_point;
+}
+
+static void ivpu_pm_prepare_warm_boot(struct ivpu_device *vdev)
+{
+ struct ivpu_fw_info *fw = vdev->fw;
+ struct vpu_boot_params *bp = fw->mem->kvaddr;
+
+ if (!bp->save_restore_ret_address) {
+ ivpu_pm_prepare_cold_boot(vdev);
+ return;
+ }
+
+ ivpu_dbg(vdev, FW_BOOT, "Save/restore entry point %llx", bp->save_restore_ret_address);
+ fw->entry_point = bp->save_restore_ret_address;
+}
+
+static int ivpu_suspend(struct ivpu_device *vdev)
+{
+ int ret;
+
+ ret = ivpu_shutdown(vdev);
+ if (ret) {
+ ivpu_err(vdev, "Failed to shutdown VPU: %d\n", ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int ivpu_resume(struct ivpu_device *vdev)
+{
+ int ret;
+
+retry:
+ ret = ivpu_hw_power_up(vdev);
+ if (ret) {
+ ivpu_err(vdev, "Failed to power up HW: %d\n", ret);
+ return ret;
+ }
+
+ ret = ivpu_mmu_enable(vdev);
+ if (ret) {
+ ivpu_err(vdev, "Failed to resume MMU: %d\n", ret);
+ ivpu_hw_power_down(vdev);
+ return ret;
+ }
+
+ ret = ivpu_boot(vdev);
+ if (ret) {
+ ivpu_mmu_disable(vdev);
+ ivpu_hw_power_down(vdev);
+ if (!ivpu_fw_is_cold_boot(vdev)) {
+ ivpu_warn(vdev, "Failed to resume the FW: %d. Retrying cold boot..\n", ret);
+ ivpu_pm_prepare_cold_boot(vdev);
+ goto retry;
+ } else {
+ ivpu_err(vdev, "Failed to resume the FW: %d\n", ret);
+ }
+ }
+
+ return ret;
+}
+
+static void ivpu_pm_recovery_work(struct work_struct *work)
+{
+ struct ivpu_pm_info *pm = container_of(work, struct ivpu_pm_info, recovery_work);
+ struct ivpu_device *vdev = pm->vdev;
+ char *evt[2] = {"IVPU_PM_EVENT=IVPU_RECOVER", NULL};
+ int ret;
+
+ ret = pci_reset_function(to_pci_dev(vdev->drm.dev));
+ if (ret)
+ ivpu_err(vdev, "Failed to reset VPU: %d\n", ret);
+
+ kobject_uevent_env(&vdev->drm.dev->kobj, KOBJ_CHANGE, evt);
+}
+
+void ivpu_pm_schedule_recovery(struct ivpu_device *vdev)
+{
+ struct ivpu_pm_info *pm = vdev->pm;
+
+ if (ivpu_disable_recovery) {
+ ivpu_err(vdev, "Recovery not available when disable_recovery param is set\n");
+ return;
+ }
+
+ if (ivpu_is_fpga(vdev)) {
+ ivpu_err(vdev, "Recovery not available on FPGA\n");
+ return;
+ }
+
+ /* Schedule recovery if it's not in progress */
+ if (atomic_cmpxchg(&pm->in_reset, 0, 1) == 0) {
+ ivpu_hw_irq_disable(vdev);
+ queue_work(system_long_wq, &pm->recovery_work);
+ }
+}
+
+int ivpu_pm_suspend_cb(struct device *dev)
+{
+ struct drm_device *drm = dev_get_drvdata(dev);
+ struct ivpu_device *vdev = to_ivpu_device(drm);
+ int ret;
+
+ ivpu_dbg(vdev, PM, "Suspend..\n");
+
+ ret = ivpu_suspend(vdev);
+ if (ret && vdev->pm->suspend_reschedule_counter) {
+ ivpu_dbg(vdev, PM, "Failed to enter idle, rescheduling suspend, retries left %d\n",
+ vdev->pm->suspend_reschedule_counter);
+ pm_schedule_suspend(dev, vdev->timeout.reschedule_suspend);
+ vdev->pm->suspend_reschedule_counter--;
+ return -EBUSY;
+ } else if (!vdev->pm->suspend_reschedule_counter) {
+ ivpu_warn(vdev, "Failed to enter idle, force suspend\n");
+ ivpu_pm_prepare_cold_boot(vdev);
+ } else {
+ ivpu_pm_prepare_warm_boot(vdev);
+ }
+
+ vdev->pm->suspend_reschedule_counter = PM_RESCHEDULE_LIMIT;
+
+ pci_save_state(to_pci_dev(dev));
+ pci_set_power_state(to_pci_dev(dev), PCI_D3hot);
+
+ ivpu_dbg(vdev, PM, "Suspend done.\n");
+
+ return ret;
+}
+
+int ivpu_pm_resume_cb(struct device *dev)
+{
+ struct drm_device *drm = dev_get_drvdata(dev);
+ struct ivpu_device *vdev = to_ivpu_device(drm);
+ int ret;
+
+ ivpu_dbg(vdev, PM, "Resume..\n");
+
+ pci_set_power_state(to_pci_dev(dev), PCI_D0);
+ pci_restore_state(to_pci_dev(dev));
+
+ ret = ivpu_resume(vdev);
+ if (ret)
+ ivpu_err(vdev, "Failed to resume: %d\n", ret);
+
+ ivpu_dbg(vdev, PM, "Resume done.\n");
+
+ return ret;
+}
+
+int ivpu_pm_runtime_suspend_cb(struct device *dev)
+{
+ struct drm_device *drm = dev_get_drvdata(dev);
+ struct ivpu_device *vdev = to_ivpu_device(drm);
+ int ret;
+
+ ivpu_dbg(vdev, PM, "Runtime suspend..\n");
+
+ if (!ivpu_hw_is_idle(vdev) && vdev->pm->suspend_reschedule_counter) {
+ ivpu_dbg(vdev, PM, "Failed to enter idle, rescheduling suspend, retries left %d\n",
+ vdev->pm->suspend_reschedule_counter);
+ pm_schedule_suspend(dev, vdev->timeout.reschedule_suspend);
+ vdev->pm->suspend_reschedule_counter--;
+ return -EAGAIN;
+ }
+
+ ret = ivpu_suspend(vdev);
+ if (ret)
+ ivpu_err(vdev, "Failed to set suspend VPU: %d\n", ret);
+
+ if (!vdev->pm->suspend_reschedule_counter) {
+ ivpu_warn(vdev, "VPU failed to enter idle, force suspended.\n");
+ ivpu_pm_prepare_cold_boot(vdev);
+ } else {
+ ivpu_pm_prepare_warm_boot(vdev);
+ }
+
+ vdev->pm->suspend_reschedule_counter = PM_RESCHEDULE_LIMIT;
+
+ ivpu_dbg(vdev, PM, "Runtime suspend done.\n");
+
+ return 0;
+}
+
+int ivpu_pm_runtime_resume_cb(struct device *dev)
+{
+ struct drm_device *drm = dev_get_drvdata(dev);
+ struct ivpu_device *vdev = to_ivpu_device(drm);
+ int ret;
+
+ ivpu_dbg(vdev, PM, "Runtime resume..\n");
+
+ ret = ivpu_resume(vdev);
+ if (ret)
+ ivpu_err(vdev, "Failed to set RESUME state: %d\n", ret);
+
+ ivpu_dbg(vdev, PM, "Runtime resume done.\n");
+
+ return ret;
+}
+
+int ivpu_rpm_get(struct ivpu_device *vdev)
+{
+ int ret;
+
+ ivpu_dbg(vdev, RPM, "rpm_get count %d\n", atomic_read(&vdev->drm.dev->power.usage_count));
+
+ ret = pm_runtime_resume_and_get(vdev->drm.dev);
+ if (!drm_WARN_ON(&vdev->drm, ret < 0))
+ vdev->pm->suspend_reschedule_counter = PM_RESCHEDULE_LIMIT;
+
+ return ret;
+}
+
+void ivpu_rpm_put(struct ivpu_device *vdev)
+{
+ ivpu_dbg(vdev, RPM, "rpm_put count %d\n", atomic_read(&vdev->drm.dev->power.usage_count));
+
+ pm_runtime_mark_last_busy(vdev->drm.dev);
+ pm_runtime_put_autosuspend(vdev->drm.dev);
+}
+
+void ivpu_pm_reset_prepare_cb(struct pci_dev *pdev)
+{
+ struct ivpu_device *vdev = pci_get_drvdata(pdev);
+
+ pm_runtime_get_sync(vdev->drm.dev);
+
+ ivpu_dbg(vdev, PM, "Pre-reset..\n");
+ atomic_set(&vdev->pm->in_reset, 1);
+ ivpu_shutdown(vdev);
+ ivpu_pm_prepare_cold_boot(vdev);
+ ivpu_jobs_abort_all(vdev);
+ ivpu_dbg(vdev, PM, "Pre-reset done.\n");
+}
+
+void ivpu_pm_reset_done_cb(struct pci_dev *pdev)
+{
+ struct ivpu_device *vdev = pci_get_drvdata(pdev);
+ int ret;
+
+ ivpu_dbg(vdev, PM, "Post-reset..\n");
+ ret = ivpu_resume(vdev);
+ if (ret)
+ ivpu_err(vdev, "Failed to set RESUME state: %d\n", ret);
+ atomic_set(&vdev->pm->in_reset, 0);
+ ivpu_dbg(vdev, PM, "Post-reset done.\n");
+
+ pm_runtime_put_autosuspend(vdev->drm.dev);
+}
+
+int ivpu_pm_init(struct ivpu_device *vdev)
+{
+ struct device *dev = vdev->drm.dev;
+ struct ivpu_pm_info *pm = vdev->pm;
+
+ pm->vdev = vdev;
+ pm->suspend_reschedule_counter = PM_RESCHEDULE_LIMIT;
+
+ atomic_set(&pm->in_reset, 0);
+ INIT_WORK(&pm->recovery_work, ivpu_pm_recovery_work);
+
+ pm_runtime_use_autosuspend(dev);
+
+ if (ivpu_disable_recovery)
+ pm_runtime_set_autosuspend_delay(dev, -1);
+ else if (ivpu_is_silicon(vdev))
+ pm_runtime_set_autosuspend_delay(dev, 100);
+ else
+ pm_runtime_set_autosuspend_delay(dev, 60000);
+
+ return 0;
+}
+
+void ivpu_pm_enable(struct ivpu_device *vdev)
+{
+ struct device *dev = vdev->drm.dev;
+
+ pm_runtime_set_active(dev);
+ pm_runtime_allow(dev);
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+
+ ivpu_dbg(vdev, RPM, "Enable RPM count %d\n", atomic_read(&dev->power.usage_count));
+}
+
+void ivpu_pm_disable(struct ivpu_device *vdev)
+{
+ struct device *dev = vdev->drm.dev;
+
+ ivpu_dbg(vdev, RPM, "Disable RPM count %d\n", atomic_read(&dev->power.usage_count));
+
+ pm_runtime_get_noresume(vdev->drm.dev);
+ pm_runtime_forbid(vdev->drm.dev);
+}
diff --git a/drivers/accel/ivpu/ivpu_pm.h b/drivers/accel/ivpu/ivpu_pm.h
new file mode 100644
index 000000000000..dc1b3758e13f
--- /dev/null
+++ b/drivers/accel/ivpu/ivpu_pm.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2020-2023 Intel Corporation
+ */
+
+#ifndef __IVPU_PM_H__
+#define __IVPU_PM_H__
+
+#include <linux/types.h>
+
+struct ivpu_device;
+
+struct ivpu_pm_info {
+ struct ivpu_device *vdev;
+ struct work_struct recovery_work;
+ atomic_t in_reset;
+ bool is_warmboot;
+ u32 suspend_reschedule_counter;
+};
+
+int ivpu_pm_init(struct ivpu_device *vdev);
+void ivpu_pm_enable(struct ivpu_device *vdev);
+void ivpu_pm_disable(struct ivpu_device *vdev);
+
+int ivpu_pm_suspend_cb(struct device *dev);
+int ivpu_pm_resume_cb(struct device *dev);
+int ivpu_pm_runtime_suspend_cb(struct device *dev);
+int ivpu_pm_runtime_resume_cb(struct device *dev);
+
+void ivpu_pm_reset_prepare_cb(struct pci_dev *pdev);
+void ivpu_pm_reset_done_cb(struct pci_dev *pdev);
+
+int __must_check ivpu_rpm_get(struct ivpu_device *vdev);
+void ivpu_rpm_put(struct ivpu_device *vdev);
+
+void ivpu_pm_schedule_recovery(struct ivpu_device *vdev);
+
+#endif /* __IVPU_PM_H__ */
diff --git a/drivers/accel/ivpu/vpu_boot_api.h b/drivers/accel/ivpu/vpu_boot_api.h
new file mode 100644
index 000000000000..6b71be92ba65
--- /dev/null
+++ b/drivers/accel/ivpu/vpu_boot_api.h
@@ -0,0 +1,349 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright (C) 2020-2023 Intel Corporation
+ */
+
+#ifndef VPU_BOOT_API_H
+#define VPU_BOOT_API_H
+
+/*
+ * =========== FW API version information beginning ================
+ * The bellow values will be used to construct the version info this way:
+ * fw_bin_header->api_version[VPU_BOOT_API_VER_ID] = (VPU_BOOT_API_VER_MAJOR << 16) |
+ * VPU_BOOT_API_VER_MINOR;
+ * VPU_BOOT_API_VER_PATCH will be ignored. KMD and compatibility is not affected if this changes.
+ */
+
+/*
+ * Major version changes that break backward compatibility.
+ * Major version must start from 1 and can only be incremented.
+ */
+#define VPU_BOOT_API_VER_MAJOR 3
+
+/*
+ * Minor version changes when API backward compatibility is preserved.
+ * Resets to 0 if Major version is incremented.
+ */
+#define VPU_BOOT_API_VER_MINOR 12
+
+/*
+ * API header changed (field names, documentation, formatting) but API itself has not been changed
+ */
+#define VPU_BOOT_API_VER_PATCH 2
+
+/*
+ * Index in the API version table
+ * Must be unique for each API
+ */
+#define VPU_BOOT_API_VER_INDEX 0
+/* ------------ FW API version information end ---------------------*/
+
+#pragma pack(push, 1)
+
+/*
+ * Firmware image header format
+ */
+#define VPU_FW_HEADER_SIZE 4096
+#define VPU_FW_HEADER_VERSION 0x1
+#define VPU_FW_VERSION_SIZE 32
+#define VPU_FW_API_VER_NUM 16
+
+struct vpu_firmware_header {
+ u32 header_version;
+ u32 image_format;
+ u64 image_load_address;
+ u32 image_size;
+ u64 entry_point;
+ u8 vpu_version[VPU_FW_VERSION_SIZE];
+ u32 compression_type;
+ u64 firmware_version_load_address;
+ u32 firmware_version_size;
+ u64 boot_params_load_address;
+ u32 api_version[VPU_FW_API_VER_NUM];
+ /* Size of memory require for firmware execution */
+ u32 runtime_size;
+ u32 shave_nn_fw_size;
+};
+
+/*
+ * Firmware boot parameters format
+ */
+
+#define VPU_BOOT_PLL_COUNT 3
+#define VPU_BOOT_PLL_OUT_COUNT 4
+
+/** Values for boot_type field */
+#define VPU_BOOT_TYPE_COLDBOOT 0
+#define VPU_BOOT_TYPE_WARMBOOT 1
+
+/** Value for magic filed */
+#define VPU_BOOT_PARAMS_MAGIC 0x10000
+
+/** VPU scheduling mode. By default, OS scheduling is used. */
+#define VPU_SCHEDULING_MODE_OS 0
+#define VPU_SCHEDULING_MODE_HW 1
+
+enum VPU_BOOT_L2_CACHE_CFG_TYPE {
+ VPU_BOOT_L2_CACHE_CFG_UPA = 0,
+ VPU_BOOT_L2_CACHE_CFG_NN = 1,
+ VPU_BOOT_L2_CACHE_CFG_NUM = 2
+};
+
+/**
+ * Logging destinations.
+ *
+ * Logging output can be directed to different logging destinations. This enum
+ * defines the list of logging destinations supported by the VPU firmware (NOTE:
+ * a specific VPU FW binary may support only a subset of such output
+ * destinations, depending on the target platform and compile options).
+ */
+enum vpu_trace_destination {
+ VPU_TRACE_DESTINATION_PIPEPRINT = 0x1,
+ VPU_TRACE_DESTINATION_VERBOSE_TRACING = 0x2,
+ VPU_TRACE_DESTINATION_NORTH_PEAK = 0x4,
+};
+
+/*
+ * Processor bit shifts (for loggable HW components).
+ */
+#define VPU_TRACE_PROC_BIT_ARM 0
+#define VPU_TRACE_PROC_BIT_LRT 1
+#define VPU_TRACE_PROC_BIT_LNN 2
+#define VPU_TRACE_PROC_BIT_SHV_0 3
+#define VPU_TRACE_PROC_BIT_SHV_1 4
+#define VPU_TRACE_PROC_BIT_SHV_2 5
+#define VPU_TRACE_PROC_BIT_SHV_3 6
+#define VPU_TRACE_PROC_BIT_SHV_4 7
+#define VPU_TRACE_PROC_BIT_SHV_5 8
+#define VPU_TRACE_PROC_BIT_SHV_6 9
+#define VPU_TRACE_PROC_BIT_SHV_7 10
+#define VPU_TRACE_PROC_BIT_SHV_8 11
+#define VPU_TRACE_PROC_BIT_SHV_9 12
+#define VPU_TRACE_PROC_BIT_SHV_10 13
+#define VPU_TRACE_PROC_BIT_SHV_11 14
+#define VPU_TRACE_PROC_BIT_SHV_12 15
+#define VPU_TRACE_PROC_BIT_SHV_13 16
+#define VPU_TRACE_PROC_BIT_SHV_14 17
+#define VPU_TRACE_PROC_BIT_SHV_15 18
+#define VPU_TRACE_PROC_BIT_ACT_SHV_0 19
+#define VPU_TRACE_PROC_BIT_ACT_SHV_1 20
+#define VPU_TRACE_PROC_BIT_ACT_SHV_2 21
+#define VPU_TRACE_PROC_BIT_ACT_SHV_3 22
+#define VPU_TRACE_PROC_NO_OF_HW_DEVS 23
+
+/* KMB HW component IDs are sequential, so define first and last IDs. */
+#define VPU_TRACE_PROC_BIT_KMB_FIRST VPU_TRACE_PROC_BIT_LRT
+#define VPU_TRACE_PROC_BIT_KMB_LAST VPU_TRACE_PROC_BIT_SHV_15
+
+struct vpu_boot_l2_cache_config {
+ u8 use;
+ u8 cfg;
+};
+
+struct vpu_warm_boot_section {
+ u32 src;
+ u32 dst;
+ u32 size;
+ u32 core_id;
+ u32 is_clear_op;
+};
+
+struct vpu_boot_params {
+ u32 magic;
+ u32 vpu_id;
+ u32 vpu_count;
+ u32 pad0[5];
+ /* Clock frequencies: 0x20 - 0xFF */
+ u32 frequency;
+ u32 pll[VPU_BOOT_PLL_COUNT][VPU_BOOT_PLL_OUT_COUNT];
+ u32 perf_clk_frequency;
+ u32 pad1[42];
+ /* Memory regions: 0x100 - 0x1FF */
+ u64 ipc_header_area_start;
+ u32 ipc_header_area_size;
+ u64 shared_region_base;
+ u32 shared_region_size;
+ u64 ipc_payload_area_start;
+ u32 ipc_payload_area_size;
+ u64 global_aliased_pio_base;
+ u32 global_aliased_pio_size;
+ u32 autoconfig;
+ struct vpu_boot_l2_cache_config cache_defaults[VPU_BOOT_L2_CACHE_CFG_NUM];
+ u64 global_memory_allocator_base;
+ u32 global_memory_allocator_size;
+ /**
+ * ShaveNN FW section VPU base address
+ * On VPU2.7 HW this address must be within 2GB range starting from L2C_PAGE_TABLE base
+ */
+ u64 shave_nn_fw_base;
+ u64 save_restore_ret_address; /* stores the address of FW's restore entry point */
+ u32 pad2[43];
+ /* IRQ re-direct numbers: 0x200 - 0x2FF */
+ s32 watchdog_irq_mss;
+ s32 watchdog_irq_nce;
+ /* ARM -> VPU doorbell interrupt. ARM is notifying VPU of async command or compute job. */
+ u32 host_to_vpu_irq;
+ /* VPU -> ARM job done interrupt. VPU is notifying ARM of compute job completion. */
+ u32 job_done_irq;
+ /* VPU -> ARM IRQ line to use to request MMU update. */
+ u32 mmu_update_request_irq;
+ /* ARM -> VPU IRQ line to use to notify of MMU update completion. */
+ u32 mmu_update_done_irq;
+ /* ARM -> VPU IRQ line to use to request power level change. */
+ u32 set_power_level_irq;
+ /* VPU -> ARM IRQ line to use to notify of power level change completion. */
+ u32 set_power_level_done_irq;
+ /* VPU -> ARM IRQ line to use to notify of VPU idle state change */
+ u32 set_vpu_idle_update_irq;
+ /* VPU -> ARM IRQ line to use to request counter reset. */
+ u32 metric_query_event_irq;
+ /* ARM -> VPU IRQ line to use to notify of counter reset completion. */
+ u32 metric_query_event_done_irq;
+ /* VPU -> ARM IRQ line to use to notify of preemption completion. */
+ u32 preemption_done_irq;
+ /* Padding. */
+ u32 pad3[52];
+ /* Silicon information: 0x300 - 0x3FF */
+ u32 host_version_id;
+ u32 si_stepping;
+ u64 device_id;
+ u64 feature_exclusion;
+ u64 sku;
+ /** PLL ratio for minimum clock frequency */
+ u32 min_freq_pll_ratio;
+ /** PLL ratio for maximum clock frequency */
+ u32 max_freq_pll_ratio;
+ /**
+ * Initial log level threshold (messages with log level severity less than
+ * the threshold will not be logged); applies to every enabled logging
+ * destination and loggable HW component. See 'mvLog_t' enum for acceptable
+ * values.
+ */
+ u32 default_trace_level;
+ u32 boot_type;
+ u64 punit_telemetry_sram_base;
+ u64 punit_telemetry_sram_size;
+ u32 vpu_telemetry_enable;
+ u64 crit_tracing_buff_addr;
+ u32 crit_tracing_buff_size;
+ u64 verbose_tracing_buff_addr;
+ u32 verbose_tracing_buff_size;
+ u64 verbose_tracing_sw_component_mask; /* TO BE REMOVED */
+ /**
+ * Mask of destinations to which logging messages are delivered; bitwise OR
+ * of values defined in vpu_trace_destination enum.
+ */
+ u32 trace_destination_mask;
+ /**
+ * Mask of hardware components for which logging is enabled; bitwise OR of
+ * bits defined by the VPU_TRACE_PROC_BIT_* macros.
+ */
+ u64 trace_hw_component_mask;
+ /** Mask of trace message formats supported by the driver */
+ u64 tracing_buff_message_format_mask;
+ u64 trace_reserved_1[2];
+ /**
+ * Period at which the VPU reads the temp sensor values into MMIO, on
+ * platforms where that is necessary (in ms). 0 to disable reads.
+ */
+ u32 temp_sensor_period_ms;
+ /** PLL ratio for efficient clock frequency */
+ u32 pn_freq_pll_ratio;
+ u32 pad4[28];
+ /* Warm boot information: 0x400 - 0x43F */
+ u32 warm_boot_sections_count;
+ u32 warm_boot_start_address_reference;
+ u32 warm_boot_section_info_address_offset;
+ u32 pad5[13];
+ /* Power States transitions timestamps: 0x440 - 0x46F*/
+ struct {
+ /* VPU_IDLE -> VPU_ACTIVE transition initiated timestamp */
+ u64 vpu_active_state_requested;
+ /* VPU_IDLE -> VPU_ACTIVE transition completed timestamp */
+ u64 vpu_active_state_achieved;
+ /* VPU_ACTIVE -> VPU_IDLE transition initiated timestamp */
+ u64 vpu_idle_state_requested;
+ /* VPU_ACTIVE -> VPU_IDLE transition completed timestamp */
+ u64 vpu_idle_state_achieved;
+ /* VPU_IDLE -> VPU_STANDBY transition initiated timestamp */
+ u64 vpu_standby_state_requested;
+ /* VPU_IDLE -> VPU_STANDBY transition completed timestamp */
+ u64 vpu_standby_state_achieved;
+ } power_states_timestamps;
+ /* VPU scheduling mode. Values defined by VPU_SCHEDULING_MODE_* macros. */
+ u32 vpu_scheduling_mode;
+ /* Present call period in milliseconds. */
+ u32 vpu_focus_present_timer_ms;
+ /* Unused/reserved: 0x478 - 0xFFF */
+ u32 pad6[738];
+};
+
+/*
+ * Magic numbers set between host and vpu to detect corruptio of tracing init
+ */
+
+#define VPU_TRACING_BUFFER_CANARY (0xCAFECAFE)
+
+/* Tracing buffer message format definitions */
+#define VPU_TRACING_FORMAT_STRING 0
+#define VPU_TRACING_FORMAT_MIPI 2
+/*
+ * Header of the tracing buffer.
+ * The below defined header will be stored at the beginning of
+ * each allocated tracing buffer, followed by a series of 256b
+ * of ASCII trace message entries.
+ */
+struct vpu_tracing_buffer_header {
+ /**
+ * Magic number set by host to detect corruption
+ * @see VPU_TRACING_BUFFER_CANARY
+ */
+ u32 host_canary_start;
+ /* offset from start of buffer for trace entries */
+ u32 read_index;
+ u32 pad_to_cache_line_size_0[14];
+ /* End of first cache line */
+
+ /**
+ * Magic number set by host to detect corruption
+ * @see VPU_TRACING_BUFFER_CANARY
+ */
+ u32 vpu_canary_start;
+ /* offset from start of buffer from write start */
+ u32 write_index;
+ /* counter for buffer wrapping */
+ u32 wrap_count;
+ /* legacy field - do not use */
+ u32 reserved_0;
+ /**
+ * Size of the log buffer include this header (@header_size) and space
+ * reserved for all messages. If @alignment` is greater that 0 the @Size
+ * must be multiple of @Alignment.
+ */
+ u32 size;
+ /* Header version */
+ u16 header_version;
+ /* Header size */
+ u16 header_size;
+ /*
+ * Format of the messages in the trace buffer
+ * 0 - null terminated string
+ * 1 - size + null terminated string
+ * 2 - MIPI-SysT encoding
+ */
+ u32 format;
+ /*
+ * Message alignment
+ * 0 - messages are place 1 after another
+ * n - every message starts and multiple on offset
+ */
+ u32 alignment; /* 64, 128, 256 */
+ /* Name of the logging entity, i.e "LRT", "LNN", "SHV0", etc */
+ char name[16];
+ u32 pad_to_cache_line_size_1[4];
+ /* End of second cache line */
+};
+
+#pragma pack(pop)
+
+#endif
diff --git a/drivers/accel/ivpu/vpu_jsm_api.h b/drivers/accel/ivpu/vpu_jsm_api.h
new file mode 100644
index 000000000000..2949ec8365bd
--- /dev/null
+++ b/drivers/accel/ivpu/vpu_jsm_api.h
@@ -0,0 +1,1008 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright (C) 2020-2023 Intel Corporation
+ */
+
+/**
+ * @file
+ * @brief JSM shared definitions
+ *
+ * @ingroup Jsm
+ * @brief JSM shared definitions
+ * @{
+ */
+#ifndef VPU_JSM_API_H
+#define VPU_JSM_API_H
+
+/*
+ * Major version changes that break backward compatibility
+ */
+#define VPU_JSM_API_VER_MAJOR 3
+
+/*
+ * Minor version changes when API backward compatibility is preserved.
+ */
+#define VPU_JSM_API_VER_MINOR 0
+
+/*
+ * API header changed (field names, documentation, formatting) but API itself has not been changed
+ */
+#define VPU_JSM_API_VER_PATCH 1
+
+/*
+ * Index in the API version table
+ */
+#define VPU_JSM_API_VER_INDEX 4
+
+/*
+ * Number of Priority Bands for Hardware Scheduling
+ * Bands: RealTime, Focus, Normal, Idle
+ */
+#define VPU_HWS_NUM_PRIORITY_BANDS 4
+
+/* Max number of impacted contexts that can be dealt with the engine reset command */
+#define VPU_MAX_ENGINE_RESET_IMPACTED_CONTEXTS 3
+
+/** Pack the API structures for now, once alignment issues are fixed this can be removed */
+#pragma pack(push, 1)
+
+/*
+ * Engine indexes.
+ */
+#define VPU_ENGINE_COMPUTE 0
+#define VPU_ENGINE_COPY 1
+#define VPU_ENGINE_NB 2
+
+/*
+ * VPU status values.
+ */
+#define VPU_JSM_STATUS_SUCCESS 0x0U
+#define VPU_JSM_STATUS_PARSING_ERR 0x1U
+#define VPU_JSM_STATUS_PROCESSING_ERR 0x2U
+#define VPU_JSM_STATUS_PREEMPTED 0x3U
+#define VPU_JSM_STATUS_ABORTED 0x4U
+#define VPU_JSM_STATUS_USER_CTX_VIOL_ERR 0x5U
+#define VPU_JSM_STATUS_GLOBAL_CTX_VIOL_ERR 0x6U
+#define VPU_JSM_STATUS_MVNCI_WRONG_INPUT_FORMAT 0x7U
+#define VPU_JSM_STATUS_MVNCI_UNSUPPORTED_NETWORK_ELEMENT 0x8U
+#define VPU_JSM_STATUS_MVNCI_INVALID_HANDLE 0x9U
+#define VPU_JSM_STATUS_MVNCI_OUT_OF_RESOURCES 0xAU
+#define VPU_JSM_STATUS_MVNCI_NOT_IMPLEMENTED 0xBU
+#define VPU_JSM_STATUS_MVNCI_INTERNAL_ERROR 0xCU
+/* Job status returned when the job was preempted mid-inference */
+#define VPU_JSM_STATUS_PREEMPTED_MID_INFERENCE 0xDU
+
+/*
+ * Host <-> VPU IPC channels.
+ * ASYNC commands use a high priority channel, other messages use low-priority ones.
+ */
+#define VPU_IPC_CHAN_ASYNC_CMD 0
+#define VPU_IPC_CHAN_GEN_CMD 10
+#define VPU_IPC_CHAN_JOB_RET 11
+
+/*
+ * Job flags bit masks.
+ */
+#define VPU_JOB_FLAGS_NULL_SUBMISSION_MASK 0x00000001
+
+/*
+ * Sizes of the reserved areas in jobs, in bytes.
+ */
+#define VPU_JOB_RESERVED_BYTES 16
+/*
+ * Sizes of the reserved areas in job queues, in bytes.
+ */
+#define VPU_JOB_QUEUE_RESERVED_BYTES 52
+
+/*
+ * Max length (including trailing NULL char) of trace entity name (e.g., the
+ * name of a logging destination or a loggable HW component).
+ */
+#define VPU_TRACE_ENTITY_NAME_MAX_LEN 32
+
+/*
+ * Max length (including trailing NULL char) of a dyndbg command.
+ *
+ * NOTE: 96 is used so that the size of 'struct vpu_ipc_msg' in the JSM API is
+ * 128 bytes (multiple of 64 bytes, the cache line size).
+ */
+#define VPU_DYNDBG_CMD_MAX_LEN 96
+
+/*
+ * Job format.
+ */
+struct vpu_job_queue_entry {
+ u64 batch_buf_addr; /**< Address of VPU commands batch buffer */
+ u32 job_id; /**< Job ID */
+ u32 flags; /**< Flags bit field, see VPU_JOB_FLAGS_* above */
+ u64 root_page_table_addr; /**< Address of root page table to use for this job */
+ u64 root_page_table_update_counter; /**< Page tables update events counter */
+ u64 preemption_buffer_address; /**< Address of the preemption buffer to use for this job */
+ u64 preemption_buffer_size; /**< Size of the preemption buffer to use for this job */
+ u8 reserved_0[VPU_JOB_RESERVED_BYTES];
+};
+
+/*
+ * Job queue control registers.
+ */
+struct vpu_job_queue_header {
+ u32 engine_idx;
+ u32 head;
+ u32 tail;
+ u8 reserved_0[VPU_JOB_QUEUE_RESERVED_BYTES];
+};
+
+/*
+ * Job queue format.
+ */
+struct vpu_job_queue {
+ struct vpu_job_queue_header header;
+ struct vpu_job_queue_entry job[];
+};
+
+/**
+ * Logging entity types.
+ *
+ * This enum defines the different types of entities involved in logging.
+ */
+enum vpu_trace_entity_type {
+ /** Logging destination (entity where logs can be stored / printed). */
+ VPU_TRACE_ENTITY_TYPE_DESTINATION = 1,
+ /** Loggable HW component (HW entity that can be logged). */
+ VPU_TRACE_ENTITY_TYPE_HW_COMPONENT = 2,
+};
+
+/*
+ * Host <-> VPU IPC messages types.
+ */
+enum vpu_ipc_msg_type {
+ VPU_JSM_MSG_UNKNOWN = 0xFFFFFFFF,
+ /* IPC Host -> Device, Async commands */
+ VPU_JSM_MSG_ASYNC_CMD = 0x1100,
+ VPU_JSM_MSG_ENGINE_RESET = VPU_JSM_MSG_ASYNC_CMD,
+ VPU_JSM_MSG_ENGINE_PREEMPT = 0x1101,
+ VPU_JSM_MSG_REGISTER_DB = 0x1102,
+ VPU_JSM_MSG_UNREGISTER_DB = 0x1103,
+ VPU_JSM_MSG_QUERY_ENGINE_HB = 0x1104,
+ VPU_JSM_MSG_GET_POWER_LEVEL_COUNT = 0x1105,
+ VPU_JSM_MSG_GET_POWER_LEVEL = 0x1106,
+ VPU_JSM_MSG_SET_POWER_LEVEL = 0x1107,
+ /* @deprecated */
+ VPU_JSM_MSG_METRIC_STREAMER_OPEN = 0x1108,
+ /* @deprecated */
+ VPU_JSM_MSG_METRIC_STREAMER_CLOSE = 0x1109,
+ /** Configure logging (used to modify configuration passed in boot params). */
+ VPU_JSM_MSG_TRACE_SET_CONFIG = 0x110a,
+ /** Return current logging configuration. */
+ VPU_JSM_MSG_TRACE_GET_CONFIG = 0x110b,
+ /**
+ * Get masks of destinations and HW components supported by the firmware
+ * (may vary between HW generations and FW compile
+ * time configurations)
+ */
+ VPU_JSM_MSG_TRACE_GET_CAPABILITY = 0x110c,
+ /** Get the name of a destination or HW component. */
+ VPU_JSM_MSG_TRACE_GET_NAME = 0x110d,
+ /**
+ * Release resource associated with host ssid . All jobs that belong to the host_ssid
+ * aborted and removed from internal scheduling queues. All doorbells assigned
+ * to the host_ssid are unregistered and any internal FW resources belonging to
+ * the host_ssid are released.
+ */
+ VPU_JSM_MSG_SSID_RELEASE = 0x110e,
+ /**
+ * Start collecting metric data.
+ * @see vpu_jsm_metric_streamer_start
+ */
+ VPU_JSM_MSG_METRIC_STREAMER_START = 0x110f,
+ /**
+ * Stop collecting metric data. This command will return success if it is called
+ * for a metric stream that has already been stopped or was never started.
+ * @see vpu_jsm_metric_streamer_stop
+ */
+ VPU_JSM_MSG_METRIC_STREAMER_STOP = 0x1110,
+ /**
+ * Update current and next buffer for metric data collection. This command can
+ * also be used to request information about the number of collected samples
+ * and the amount of data written to the buffer.
+ * @see vpu_jsm_metric_streamer_update
+ */
+ VPU_JSM_MSG_METRIC_STREAMER_UPDATE = 0x1111,
+ /**
+ * Request description of selected metric groups and metric counters within
+ * each group. The VPU will write the description of groups and counters to
+ * the buffer specified in the command structure.
+ * @see vpu_jsm_metric_streamer_start
+ */
+ VPU_JSM_MSG_METRIC_STREAMER_INFO = 0x1112,
+ /** Control command: Priority band setup */
+ VPU_JSM_MSG_SET_PRIORITY_BAND_SETUP = 0x1113,
+ /** Control command: Create command queue */
+ VPU_JSM_MSG_CREATE_CMD_QUEUE = 0x1114,
+ /** Control command: Destroy command queue */
+ VPU_JSM_MSG_DESTROY_CMD_QUEUE = 0x1115,
+ /** Control command: Set context scheduling properties */
+ VPU_JSM_MSG_SET_CONTEXT_SCHED_PROPERTIES = 0x1116,
+ /*
+ * Register a doorbell to notify VPU of new work. The doorbell may later be
+ * deallocated or reassigned to another context.
+ */
+ VPU_JSM_MSG_HWS_REGISTER_DB = 0x1117,
+ /* IPC Host -> Device, General commands */
+ VPU_JSM_MSG_GENERAL_CMD = 0x1200,
+ VPU_JSM_MSG_BLOB_DEINIT = VPU_JSM_MSG_GENERAL_CMD,
+ /**
+ * Control dyndbg behavior by executing a dyndbg command; equivalent to
+ * Linux command: `echo '<dyndbg_cmd>' > <debugfs>/dynamic_debug/control`.
+ */
+ VPU_JSM_MSG_DYNDBG_CONTROL = 0x1201,
+ /* IPC Device -> Host, Job completion */
+ VPU_JSM_MSG_JOB_DONE = 0x2100,
+ /* IPC Device -> Host, Async command completion */
+ VPU_JSM_MSG_ASYNC_CMD_DONE = 0x2200,
+ VPU_JSM_MSG_ENGINE_RESET_DONE = VPU_JSM_MSG_ASYNC_CMD_DONE,
+ VPU_JSM_MSG_ENGINE_PREEMPT_DONE = 0x2201,
+ VPU_JSM_MSG_REGISTER_DB_DONE = 0x2202,
+ VPU_JSM_MSG_UNREGISTER_DB_DONE = 0x2203,
+ VPU_JSM_MSG_QUERY_ENGINE_HB_DONE = 0x2204,
+ VPU_JSM_MSG_GET_POWER_LEVEL_COUNT_DONE = 0x2205,
+ VPU_JSM_MSG_GET_POWER_LEVEL_DONE = 0x2206,
+ VPU_JSM_MSG_SET_POWER_LEVEL_DONE = 0x2207,
+ /* @deprecated */
+ VPU_JSM_MSG_METRIC_STREAMER_OPEN_DONE = 0x2208,
+ /* @deprecated */
+ VPU_JSM_MSG_METRIC_STREAMER_CLOSE_DONE = 0x2209,
+ /** Response to VPU_JSM_MSG_TRACE_SET_CONFIG. */
+ VPU_JSM_MSG_TRACE_SET_CONFIG_RSP = 0x220a,
+ /** Response to VPU_JSM_MSG_TRACE_GET_CONFIG. */
+ VPU_JSM_MSG_TRACE_GET_CONFIG_RSP = 0x220b,
+ /** Response to VPU_JSM_MSG_TRACE_GET_CAPABILITY. */
+ VPU_JSM_MSG_TRACE_GET_CAPABILITY_RSP = 0x220c,
+ /** Response to VPU_JSM_MSG_TRACE_GET_NAME. */
+ VPU_JSM_MSG_TRACE_GET_NAME_RSP = 0x220d,
+ /** Response to VPU_JSM_MSG_SSID_RELEASE. */
+ VPU_JSM_MSG_SSID_RELEASE_DONE = 0x220e,
+ /**
+ * Response to VPU_JSM_MSG_METRIC_STREAMER_START.
+ * VPU will return an error result if metric collection cannot be started,
+ * e.g. when the specified metric mask is invalid.
+ * @see vpu_jsm_metric_streamer_done
+ */
+ VPU_JSM_MSG_METRIC_STREAMER_START_DONE = 0x220f,
+ /**
+ * Response to VPU_JSM_MSG_METRIC_STREAMER_STOP.
+ * Returns information about collected metric data.
+ * @see vpu_jsm_metric_streamer_done
+ */
+ VPU_JSM_MSG_METRIC_STREAMER_STOP_DONE = 0x2210,
+ /**
+ * Response to VPU_JSM_MSG_METRIC_STREAMER_UPDATE.
+ * Returns information about collected metric data.
+ * @see vpu_jsm_metric_streamer_done
+ */
+ VPU_JSM_MSG_METRIC_STREAMER_UPDATE_DONE = 0x2211,
+ /**
+ * Response to VPU_JSM_MSG_METRIC_STREAMER_INFO.
+ * Returns a description of the metric groups and metric counters.
+ * @see vpu_jsm_metric_streamer_done
+ */
+ VPU_JSM_MSG_METRIC_STREAMER_INFO_DONE = 0x2212,
+ /**
+ * Asynchronous event sent from the VPU to the host either when the current
+ * metric buffer is full or when the VPU has collected a multiple of
+ * @notify_sample_count samples as indicated through the start command
+ * (VPU_JSM_MSG_METRIC_STREAMER_START). Returns information about collected
+ * metric data.
+ * @see vpu_jsm_metric_streamer_done
+ */
+ VPU_JSM_MSG_METRIC_STREAMER_NOTIFICATION = 0x2213,
+ /** Response to control command: Priority band setup */
+ VPU_JSM_MSG_SET_PRIORITY_BAND_SETUP_RSP = 0x2214,
+ /** Response to control command: Create command queue */
+ VPU_JSM_MSG_CREATE_CMD_QUEUE_RSP = 0x2215,
+ /** Response to control command: Destroy command queue */
+ VPU_JSM_MSG_DESTROY_CMD_QUEUE_RSP = 0x2216,
+ /** Response to control command: Set context scheduling properties */
+ VPU_JSM_MSG_SET_CONTEXT_SCHED_PROPERTIES_RSP = 0x2217,
+ /* IPC Device -> Host, General command completion */
+ VPU_JSM_MSG_GENERAL_CMD_DONE = 0x2300,
+ VPU_JSM_MSG_BLOB_DEINIT_DONE = VPU_JSM_MSG_GENERAL_CMD_DONE,
+ /** Response to VPU_JSM_MSG_DYNDBG_CONTROL. */
+ VPU_JSM_MSG_DYNDBG_CONTROL_RSP = 0x2301,
+};
+
+enum vpu_ipc_msg_status { VPU_JSM_MSG_FREE, VPU_JSM_MSG_ALLOCATED };
+
+/*
+ * Host <-> LRT IPC message payload definitions
+ */
+struct vpu_ipc_msg_payload_engine_reset {
+ /* Engine to be reset. */
+ u32 engine_idx;
+ /* Reserved */
+ u32 reserved_0;
+};
+
+struct vpu_ipc_msg_payload_engine_preempt {
+ /* Engine to be preempted. */
+ u32 engine_idx;
+ /* ID of the preemption request. */
+ u32 preempt_id;
+};
+
+/*
+ * @brief Register doorbell command structure.
+ * This structure supports doorbell registration for only OS scheduling.
+ * @see VPU_JSM_MSG_REGISTER_DB
+ */
+struct vpu_ipc_msg_payload_register_db {
+ /* Index of the doorbell to register. */
+ u32 db_idx;
+ /* Reserved */
+ u32 reserved_0;
+ /* Virtual address in Global GTT pointing to the start of job queue. */
+ u64 jobq_base;
+ /* Size of the job queue in bytes. */
+ u32 jobq_size;
+ /* Host sub-stream ID for the context assigned to the doorbell. */
+ u32 host_ssid;
+};
+
+/**
+ * @brief Unregister doorbell command structure.
+ * Request structure to unregister a doorbell for both HW and OS scheduling.
+ * @see VPU_JSM_MSG_UNREGISTER_DB
+ */
+struct vpu_ipc_msg_payload_unregister_db {
+ /* Index of the doorbell to unregister. */
+ u32 db_idx;
+ /* Reserved */
+ u32 reserved_0;
+};
+
+struct vpu_ipc_msg_payload_query_engine_hb {
+ /* Engine to return heartbeat value. */
+ u32 engine_idx;
+ /* Reserved */
+ u32 reserved_0;
+};
+
+struct vpu_ipc_msg_payload_power_level {
+ /**
+ * Requested power level. The power level value is in the
+ * range [0, power_level_count-1] where power_level_count
+ * is the number of available power levels as returned by
+ * the get power level count command. A power level of 0
+ * corresponds to the maximum possible power level, while
+ * power_level_count-1 corresponds to the minimum possible
+ * power level. Values outside of this range are not
+ * considered to be valid.
+ */
+ u32 power_level;
+ /* Reserved */
+ u32 reserved_0;
+};
+
+struct vpu_ipc_msg_payload_ssid_release {
+ /* Host sub-stream ID for the context to be released. */
+ u32 host_ssid;
+ /* Reserved */
+ u32 reserved_0;
+};
+
+/**
+ * @brief Metric streamer start command structure.
+ * This structure is also used with VPU_JSM_MSG_METRIC_STREAMER_INFO to request metric
+ * groups and metric counters description from the firmware.
+ * @see VPU_JSM_MSG_METRIC_STREAMER_START
+ * @see VPU_JSM_MSG_METRIC_STREAMER_INFO
+ */
+struct vpu_jsm_metric_streamer_start {
+ /**
+ * Bitmask to select the desired metric groups.
+ * A metric group can belong only to one metric streamer instance at a time.
+ * Since each metric streamer instance has a unique set of metric groups, it
+ * can also identify a metric streamer instance if more than one instance was
+ * started. If the VPU device does not support multiple metric streamer instances,
+ * then VPU_JSM_MSG_METRIC_STREAMER_START will return an error even if the second
+ * instance has different groups to the first.
+ */
+ u64 metric_group_mask;
+ /** Sampling rate in nanoseconds. */
+ u64 sampling_rate;
+ /**
+ * If > 0 the VPU will send a VPU_JSM_MSG_METRIC_STREAMER_NOTIFICATION message
+ * after every @notify_sample_count samples is collected or dropped by the VPU.
+ * If set to UINT_MAX the VPU will only generate a notification when the metric
+ * buffer is full. If set to 0 the VPU will never generate a notification.
+ */
+ u32 notify_sample_count;
+ u32 reserved_0;
+ /**
+ * Address and size of the buffer where the VPU will write metric data. The
+ * VPU writes all counters from enabled metric groups one after another. If
+ * there is no space left to write data at the next sample period the VPU
+ * will switch to the next buffer (@see next_buffer_addr) and will optionally
+ * send a notification to the host driver if @notify_sample_count is non-zero.
+ * If @next_buffer_addr is NULL the VPU will stop collecting metric data.
+ */
+ u64 buffer_addr;
+ u64 buffer_size;
+ /**
+ * Address and size of the next buffer to write metric data to after the initial
+ * buffer is full. If the address is NULL the VPU will stop collecting metric
+ * data.
+ */
+ u64 next_buffer_addr;
+ u64 next_buffer_size;
+};
+
+/**
+ * @brief Metric streamer stop command structure.
+ * @see VPU_JSM_MSG_METRIC_STREAMER_STOP
+ */
+struct vpu_jsm_metric_streamer_stop {
+ /** Bitmask to select the desired metric groups. */
+ u64 metric_group_mask;
+};
+
+/**
+ * Provide VPU FW with buffers to write metric data.
+ * @see VPU_JSM_MSG_METRIC_STREAMER_UPDATE
+ */
+struct vpu_jsm_metric_streamer_update {
+ /** Metric group mask that identifies metric streamer instance. */
+ u64 metric_group_mask;
+ /**
+ * Address and size of the buffer where the VPU will write metric data. If
+ * the buffer address is 0 or same as the currently used buffer the VPU will
+ * continue writing metric data to the current buffer. In this case the
+ * buffer size is ignored and the size of the current buffer is unchanged.
+ * If the address is non-zero and differs from the current buffer address the
+ * VPU will immediately switch data collection to the new buffer.
+ */
+ u64 buffer_addr;
+ u64 buffer_size;
+ /**
+ * Address and size of the next buffer to write metric data after the initial
+ * buffer is full. If the address is NULL the VPU will stop collecting metric
+ * data but will continue to record dropped samples.
+ *
+ * Note that there is a hazard possible if both buffer_addr and the next_buffer_addr
+ * are non-zero in same update request. It is the host's responsibility to ensure
+ * that both addresses make sense even if the VPU just switched to writing samples
+ * from the current to the next buffer.
+ */
+ u64 next_buffer_addr;
+ u64 next_buffer_size;
+};
+
+struct vpu_ipc_msg_payload_blob_deinit {
+ /* 64-bit unique ID for the blob to be de-initialized. */
+ u64 blob_id;
+};
+
+struct vpu_ipc_msg_payload_job_done {
+ /* Engine to which the job was submitted. */
+ u32 engine_idx;
+ /* Index of the doorbell to which the job was submitted */
+ u32 db_idx;
+ /* ID of the completed job */
+ u32 job_id;
+ /* Status of the completed job */
+ u32 job_status;
+ /* Host SSID */
+ u32 host_ssid;
+ /* Zero Padding */
+ u32 reserved_0;
+ /* Command queue id */
+ u64 cmdq_id;
+};
+
+struct vpu_jsm_engine_reset_context {
+ /* Host SSID */
+ u32 host_ssid;
+ /* Zero Padding */
+ u32 reserved_0;
+ /* Command queue id */
+ u64 cmdq_id;
+ /* Flags: 0: cause of hang; 1: collateral damage of reset */
+ u64 flags;
+};
+
+struct vpu_ipc_msg_payload_engine_reset_done {
+ /* Engine ordinal */
+ u32 engine_idx;
+ /* Number of impacted contexts */
+ u32 num_impacted_contexts;
+ /* Array of impacted command queue ids and their flags */
+ struct vpu_jsm_engine_reset_context
+ impacted_contexts[VPU_MAX_ENGINE_RESET_IMPACTED_CONTEXTS];
+};
+
+struct vpu_ipc_msg_payload_engine_preempt_done {
+ /* Engine preempted. */
+ u32 engine_idx;
+ /* ID of the preemption request. */
+ u32 preempt_id;
+};
+
+/**
+ * Response structure for register doorbell command for both OS
+ * and HW scheduling.
+ * @see VPU_JSM_MSG_REGISTER_DB
+ * @see VPU_JSM_MSG_HWS_REGISTER_DB
+ */
+struct vpu_ipc_msg_payload_register_db_done {
+ /* Index of the registered doorbell. */
+ u32 db_idx;
+ /* Reserved */
+ u32 reserved_0;
+};
+
+/**
+ * Response structure for unregister doorbell command for both OS
+ * and HW scheduling.
+ * @see VPU_JSM_MSG_UNREGISTER_DB
+ */
+struct vpu_ipc_msg_payload_unregister_db_done {
+ /* Index of the unregistered doorbell. */
+ u32 db_idx;
+ /* Reserved */
+ u32 reserved_0;
+};
+
+struct vpu_ipc_msg_payload_query_engine_hb_done {
+ /* Engine returning heartbeat value. */
+ u32 engine_idx;
+ /* Reserved */
+ u32 reserved_0;
+ /* Heartbeat value. */
+ u64 heartbeat;
+};
+
+struct vpu_ipc_msg_payload_get_power_level_count_done {
+ /**
+ * Number of supported power levels. The maximum possible
+ * value of power_level_count is 16 but this may vary across
+ * implementations.
+ */
+ u32 power_level_count;
+ /* Reserved */
+ u32 reserved_0;
+ /**
+ * Power consumption limit for each supported power level in
+ * [0-100%] range relative to power level 0.
+ */
+ u8 power_limit[16];
+};
+
+struct vpu_ipc_msg_payload_blob_deinit_done {
+ /* 64-bit unique ID for the blob de-initialized. */
+ u64 blob_id;
+};
+
+/* HWS priority band setup request / response */
+struct vpu_ipc_msg_payload_hws_priority_band_setup {
+ /*
+ * Grace period in 100ns units when preempting another priority band for
+ * this priority band
+ */
+ u32 grace_period[VPU_HWS_NUM_PRIORITY_BANDS];
+ /*
+ * Default quantum in 100ns units for scheduling across processes
+ * within a priority band
+ */
+ u64 process_quantum[VPU_HWS_NUM_PRIORITY_BANDS];
+ /*
+ * Default grace period in 100ns units for processes that preempt each
+ * other within a priority band
+ */
+ u64 process_grace_period[VPU_HWS_NUM_PRIORITY_BANDS];
+ /*
+ * For normal priority band, specifies the target VPU percentage
+ * in situations when it's starved by the focus band.
+ */
+ u32 normal_band_percentage;
+ /* Reserved */
+ u32 reserved_0;
+};
+
+/* HWS create command queue request */
+struct vpu_ipc_msg_payload_hws_create_cmdq {
+ /* Process id */
+ u64 process_id;
+ /* Host SSID */
+ u32 host_ssid;
+ /* Zero Padding */
+ u32 reserved;
+ /* Command queue id */
+ u64 cmdq_id;
+ /* Command queue base */
+ u64 cmdq_base;
+ /* Command queue size */
+ u32 cmdq_size;
+ /* Reserved */
+ u32 reserved_0;
+};
+
+/* HWS create command queue response */
+struct vpu_ipc_msg_payload_hws_create_cmdq_rsp {
+ /* Process id */
+ u64 process_id;
+ /* Host SSID */
+ u32 host_ssid;
+ /* Zero Padding */
+ u32 reserved;
+ /* Command queue id */
+ u64 cmdq_id;
+};
+
+/* HWS destroy command queue request / response */
+struct vpu_ipc_msg_payload_hws_destroy_cmdq {
+ /* Host SSID */
+ u32 host_ssid;
+ /* Zero Padding */
+ u32 reserved;
+ /* Command queue id */
+ u64 cmdq_id;
+};
+
+/* HWS set context scheduling properties request / response */
+struct vpu_ipc_msg_payload_hws_set_context_sched_properties {
+ /* Host SSID */
+ u32 host_ssid;
+ /* Zero Padding */
+ u32 reserved_0;
+ /* Command queue id */
+ u64 cmdq_id;
+ /* Priority band to assign to work of this context */
+ u32 priority_band;
+ /* Inside realtime band assigns a further priority */
+ u32 realtime_priority_level;
+ /* Priority relative to other contexts in the same process */
+ u32 in_process_priority;
+ /* Zero padding / Reserved */
+ u32 reserved_1;
+ /* Context quantum relative to other contexts of same priority in the same process */
+ u64 context_quantum;
+ /* Grace period when preempting context of the same priority within the same process */
+ u64 grace_period_same_priority;
+ /* Grace period when preempting context of a lower priority within the same process */
+ u64 grace_period_lower_priority;
+};
+
+/*
+ * @brief Register doorbell command structure.
+ * This structure supports doorbell registration for both HW and OS scheduling.
+ * Note: Queue base and size are added here so that the same structure can be used for
+ * OS scheduling and HW scheduling. For OS scheduling, cmdq_id will be ignored
+ * and cmdq_base and cmdq_size will be used. For HW scheduling, cmdq_base and cmdq_size will be
+ * ignored and cmdq_id is used.
+ * @see VPU_JSM_MSG_HWS_REGISTER_DB
+ */
+struct vpu_jsm_hws_register_db {
+ /* Index of the doorbell to register. */
+ u32 db_id;
+ /* Host sub-stream ID for the context assigned to the doorbell. */
+ u32 host_ssid;
+ /* ID of the command queue associated with the doorbell. */
+ u64 cmdq_id;
+ /* Virtual address pointing to the start of command queue. */
+ u64 cmdq_base;
+ /* Size of the command queue in bytes. */
+ u64 cmdq_size;
+};
+
+/**
+ * Payload for VPU_JSM_MSG_TRACE_SET_CONFIG[_RSP] and
+ * VPU_JSM_MSG_TRACE_GET_CONFIG_RSP messages.
+ *
+ * The payload is interpreted differently depending on the type of message:
+ *
+ * - For VPU_JSM_MSG_TRACE_SET_CONFIG, the payload specifies the desired
+ * logging configuration to be set.
+ *
+ * - For VPU_JSM_MSG_TRACE_SET_CONFIG_RSP, the payload reports the logging
+ * configuration that was set after a VPU_JSM_MSG_TRACE_SET_CONFIG request.
+ * The host can compare this payload with the one it sent in the
+ * VPU_JSM_MSG_TRACE_SET_CONFIG request to check whether or not the
+ * configuration was set as desired.
+ *
+ * - VPU_JSM_MSG_TRACE_GET_CONFIG_RSP, the payload reports the current logging
+ * configuration.
+ */
+struct vpu_ipc_msg_payload_trace_config {
+ /**
+ * Logging level (currently set or to be set); see 'mvLog_t' enum for
+ * acceptable values. The specified logging level applies to all
+ * destinations and HW components
+ */
+ u32 trace_level;
+ /**
+ * Bitmask of logging destinations (currently enabled or to be enabled);
+ * bitwise OR of values defined in logging_destination enum.
+ */
+ u32 trace_destination_mask;
+ /**
+ * Bitmask of loggable HW components (currently enabled or to be enabled);
+ * bitwise OR of values defined in loggable_hw_component enum.
+ */
+ u64 trace_hw_component_mask;
+ u64 reserved_0; /**< Reserved for future extensions. */
+};
+
+/**
+ * Payload for VPU_JSM_MSG_TRACE_GET_CAPABILITY_RSP messages.
+ */
+struct vpu_ipc_msg_payload_trace_capability_rsp {
+ u32 trace_destination_mask; /**< Bitmask of supported logging destinations. */
+ u32 reserved_0;
+ u64 trace_hw_component_mask; /**< Bitmask of supported loggable HW components. */
+ u64 reserved_1; /**< Reserved for future extensions. */
+};
+
+/**
+ * Payload for VPU_JSM_MSG_TRACE_GET_NAME requests.
+ */
+struct vpu_ipc_msg_payload_trace_get_name {
+ /**
+ * The type of the entity to query name for; see logging_entity_type for
+ * possible values.
+ */
+ u32 entity_type;
+ u32 reserved_0;
+ /**
+ * The ID of the entity to query name for; possible values depends on the
+ * entity type.
+ */
+ u64 entity_id;
+};
+
+/**
+ * Payload for VPU_JSM_MSG_TRACE_GET_NAME_RSP responses.
+ */
+struct vpu_ipc_msg_payload_trace_get_name_rsp {
+ /**
+ * The type of the entity whose name was queried; see logging_entity_type
+ * for possible values.
+ */
+ u32 entity_type;
+ u32 reserved_0;
+ /**
+ * The ID of the entity whose name was queried; possible values depends on
+ * the entity type.
+ */
+ u64 entity_id;
+ /** Reserved for future extensions. */
+ u64 reserved_1;
+ /** The name of the entity. */
+ char entity_name[VPU_TRACE_ENTITY_NAME_MAX_LEN];
+};
+
+/**
+ * Data sent from the VPU to the host in all metric streamer response messages
+ * and in asynchronous notification.
+ * @see VPU_JSM_MSG_METRIC_STREAMER_START_DONE
+ * @see VPU_JSM_MSG_METRIC_STREAMER_STOP_DONE
+ * @see VPU_JSM_MSG_METRIC_STREAMER_UPDATE_DONE
+ * @see VPU_JSM_MSG_METRIC_STREAMER_INFO_DONE
+ * @see VPU_JSM_MSG_METRIC_STREAMER_NOTIFICATION
+ */
+struct vpu_jsm_metric_streamer_done {
+ /** Metric group mask that identifies metric streamer instance. */
+ u64 metric_group_mask;
+ /**
+ * Size in bytes of single sample - total size of all enabled counters.
+ * Some VPU implementations may align sample_size to more than 8 bytes.
+ */
+ u32 sample_size;
+ u32 reserved_0;
+ /**
+ * Number of samples collected since the metric streamer was started.
+ * This will be 0 if the metric streamer was not started.
+ */
+ u32 samples_collected;
+ /**
+ * Number of samples dropped since the metric streamer was started. This
+ * is incremented every time the metric streamer is not able to write
+ * collected samples because the current buffer is full and there is no
+ * next buffer to switch to.
+ */
+ u32 samples_dropped;
+ /** Address of the buffer that contains the latest metric data. */
+ u64 buffer_addr;
+ /**
+ * Number of bytes written into the metric data buffer. In response to the
+ * VPU_JSM_MSG_METRIC_STREAMER_INFO request this field contains the size of
+ * all group and counter descriptors. The size is updated even if the buffer
+ * in the request was NULL or too small to hold descriptors of all counters
+ */
+ u64 bytes_written;
+};
+
+/**
+ * Metric group description placed in the metric buffer after successful completion
+ * of the VPU_JSM_MSG_METRIC_STREAMER_INFO command. This is followed by one or more
+ * @vpu_jsm_metric_counter_descriptor records.
+ * @see VPU_JSM_MSG_METRIC_STREAMER_INFO
+ */
+struct vpu_jsm_metric_group_descriptor {
+ /**
+ * Offset to the next metric group (8-byte aligned). If this offset is 0 this
+ * is the last descriptor. The value of metric_info_size must be greater than
+ * or equal to sizeof(struct vpu_jsm_metric_group_descriptor) + name_string_size
+ * + description_string_size and must be 8-byte aligned.
+ */
+ u32 next_metric_group_info_offset;
+ /**
+ * Offset to the first metric counter description record (8-byte aligned).
+ * @see vpu_jsm_metric_counter_descriptor
+ */
+ u32 next_metric_counter_info_offset;
+ /** Index of the group. This corresponds to bit index in metric_group_mask. */
+ u32 group_id;
+ /** Number of counters in the metric group. */
+ u32 num_counters;
+ /** Data size for all counters, must be a multiple of 8 bytes.*/
+ u32 metric_group_data_size;
+ /**
+ * Metric group domain number. Cannot use multiple, simultaneous metric groups
+ * from the same domain.
+ */
+ u32 domain;
+ /**
+ * Counter name string size. The string must include a null termination character.
+ * The FW may use a fixed size name or send a different name for each counter.
+ * If the VPU uses fixed size strings, all characters from the end of the name
+ * to the of the fixed size character array must be zeroed.
+ */
+ u32 name_string_size;
+ /** Counter description string size, @see name_string_size */
+ u32 description_string_size;
+ u64 reserved_0;
+ /**
+ * Right after this structure, the VPU writes name and description of
+ * the metric group.
+ */
+};
+
+/**
+ * Metric counter description, placed in the buffer after vpu_jsm_metric_group_descriptor.
+ * @see VPU_JSM_MSG_METRIC_STREAMER_INFO
+ */
+struct vpu_jsm_metric_counter_descriptor {
+ /**
+ * Offset to the next counter in a group (8-byte aligned). If this offset is
+ * 0 this is the last counter in the group.
+ */
+ u32 next_metric_counter_info_offset;
+ /**
+ * Offset to the counter data from the start of samples in this metric group.
+ * Note that metric_data_offset % metric_data_size must be 0.
+ */
+ u32 metric_data_offset;
+ /** Size of the metric counter data in bytes. */
+ u32 metric_data_size;
+ /** Metric type, see Level Zero API for definitions. */
+ u32 tier;
+ /** Metric type, see set_metric_type_t for definitions. */
+ u32 metric_type;
+ /** Metric type, see set_value_type_t for definitions. */
+ u32 metric_value_type;
+ /**
+ * Counter name string size. The string must include a null termination character.
+ * The FW may use a fixed size name or send a different name for each counter.
+ * If the VPU uses fixed size strings, all characters from the end of the name
+ * to the of the fixed size character array must be zeroed.
+ */
+ u32 name_string_size;
+ /** Counter description string size, @see name_string_size */
+ u32 description_string_size;
+ /** Counter component name string size, @see name_string_size */
+ u32 component_string_size;
+ /** Counter string size, @see name_string_size */
+ u32 units_string_size;
+ u64 reserved_0;
+ /**
+ * Right after this structure, the VPU writes name, description
+ * component and unit strings.
+ */
+};
+
+/**
+ * Payload for VPU_JSM_MSG_DYNDBG_CONTROL requests.
+ *
+ * VPU_JSM_MSG_DYNDBG_CONTROL are used to control the VPU FW Dynamic Debug
+ * feature, which allows developers to selectively enable / disable MVLOG_DEBUG
+ * messages. This is equivalent to the Dynamic Debug functionality provided by
+ * Linux
+ * (https://www.kernel.org/doc/html/latest/admin-guide/dynamic-debug-howto.html)
+ * The host can control Dynamic Debug behavior by sending dyndbg commands, which
+ * have the same syntax as Linux
+ * dyndbg commands.
+ *
+ * NOTE: in order for MVLOG_DEBUG messages to be actually printed, the host
+ * still has to set the logging level to MVLOG_DEBUG, using the
+ * VPU_JSM_MSG_TRACE_SET_CONFIG command.
+ *
+ * The host can see the current dynamic debug configuration by executing a
+ * special 'show' command. The dyndbg configuration will be printed to the
+ * configured logging destination using MVLOG_INFO logging level.
+ */
+struct vpu_ipc_msg_payload_dyndbg_control {
+ /**
+ * Dyndbg command (same format as Linux dyndbg); must be a NULL-terminated
+ * string.
+ */
+ char dyndbg_cmd[VPU_DYNDBG_CMD_MAX_LEN];
+};
+
+/*
+ * Payloads union, used to define complete message format.
+ */
+union vpu_ipc_msg_payload {
+ struct vpu_ipc_msg_payload_engine_reset engine_reset;
+ struct vpu_ipc_msg_payload_engine_preempt engine_preempt;
+ struct vpu_ipc_msg_payload_register_db register_db;
+ struct vpu_ipc_msg_payload_unregister_db unregister_db;
+ struct vpu_ipc_msg_payload_query_engine_hb query_engine_hb;
+ struct vpu_ipc_msg_payload_power_level power_level;
+ struct vpu_jsm_metric_streamer_start metric_streamer_start;
+ struct vpu_jsm_metric_streamer_stop metric_streamer_stop;
+ struct vpu_jsm_metric_streamer_update metric_streamer_update;
+ struct vpu_ipc_msg_payload_blob_deinit blob_deinit;
+ struct vpu_ipc_msg_payload_ssid_release ssid_release;
+ struct vpu_jsm_hws_register_db hws_register_db;
+ struct vpu_ipc_msg_payload_job_done job_done;
+ struct vpu_ipc_msg_payload_engine_reset_done engine_reset_done;
+ struct vpu_ipc_msg_payload_engine_preempt_done engine_preempt_done;
+ struct vpu_ipc_msg_payload_register_db_done register_db_done;
+ struct vpu_ipc_msg_payload_unregister_db_done unregister_db_done;
+ struct vpu_ipc_msg_payload_query_engine_hb_done query_engine_hb_done;
+ struct vpu_ipc_msg_payload_get_power_level_count_done get_power_level_count_done;
+ struct vpu_jsm_metric_streamer_done metric_streamer_done;
+ struct vpu_ipc_msg_payload_blob_deinit_done blob_deinit_done;
+ struct vpu_ipc_msg_payload_trace_config trace_config;
+ struct vpu_ipc_msg_payload_trace_capability_rsp trace_capability;
+ struct vpu_ipc_msg_payload_trace_get_name trace_get_name;
+ struct vpu_ipc_msg_payload_trace_get_name_rsp trace_get_name_rsp;
+ struct vpu_ipc_msg_payload_dyndbg_control dyndbg_control;
+ struct vpu_ipc_msg_payload_hws_priority_band_setup hws_priority_band_setup;
+ struct vpu_ipc_msg_payload_hws_create_cmdq hws_create_cmdq;
+ struct vpu_ipc_msg_payload_hws_create_cmdq_rsp hws_create_cmdq_rsp;
+ struct vpu_ipc_msg_payload_hws_destroy_cmdq hws_destroy_cmdq;
+ struct vpu_ipc_msg_payload_hws_set_context_sched_properties
+ hws_set_context_sched_properties;
+};
+
+/*
+ * Host <-> LRT IPC message base structure.
+ *
+ * NOTE: All instances of this object must be aligned on a 64B boundary
+ * to allow proper handling of VPU cache operations.
+ */
+struct vpu_jsm_msg {
+ /* Reserved */
+ u64 reserved_0;
+ /* Message type, see vpu_ipc_msg_type enum. */
+ u32 type;
+ /* Buffer status, see vpu_ipc_msg_status enum. */
+ u32 status;
+ /*
+ * Request ID, provided by the host in a request message and passed
+ * back by VPU in the response message.
+ */
+ u32 request_id;
+ /* Request return code set by the VPU, see VPU_JSM_STATUS_* defines. */
+ u32 result;
+ u64 reserved_1;
+ /* Message payload depending on message type, see vpu_ipc_msg_payload union. */
+ union vpu_ipc_msg_payload payload;
+};
+
+#pragma pack(pop)
+
+#endif
+
+///@}
diff --git a/drivers/accessibility/speakup/main.c b/drivers/accessibility/speakup/main.c
index 4733fd6334ab..56c073103cbb 100644
--- a/drivers/accessibility/speakup/main.c
+++ b/drivers/accessibility/speakup/main.c
@@ -2490,7 +2490,7 @@ MODULE_PARM_DESC(punc_level, "Controls the level of punctuation spoken as the sc
MODULE_PARM_DESC(reading_punc, "It controls the level of punctuation when reviewing the screen with speakup's screen review commands.");
MODULE_PARM_DESC(cursor_time, "This controls cursor delay when using arrow keys.");
MODULE_PARM_DESC(say_control, "This controls if speakup speaks shift, alt and control when those keys are pressed or not.");
-MODULE_PARM_DESC(say_word_ctl, "Sets thw say_word_ctl on load.");
+MODULE_PARM_DESC(say_word_ctl, "Sets the say_word_ctl on load.");
MODULE_PARM_DESC(no_interrupt, "Controls if typing interrupts output from speakup.");
MODULE_PARM_DESC(key_echo, "Controls if speakup speaks keys when they are typed. One = on zero = off or don't echo keys.");
MODULE_PARM_DESC(cur_phonetic, "Controls if speakup speaks letters phonetically during navigation. One = on zero = off or don't speak phonetically.");
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 0c05ccde1f7a..9531dd0fef50 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -1014,7 +1014,7 @@ static int acpi_bus_match(struct device *dev, struct device_driver *drv)
&& !acpi_match_device_ids(acpi_dev, acpi_drv->ids);
}
-static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int acpi_device_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
return __acpi_device_uevent_modalias(to_acpi_device(dev), env);
}
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index 97450f4003cc..f007116a8427 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -484,6 +484,25 @@ void acpi_dev_power_up_children_with_adr(struct acpi_device *adev)
acpi_dev_for_each_child(adev, acpi_power_up_if_adr_present, NULL);
}
+/**
+ * acpi_dev_power_state_for_wake - Deepest power state for wakeup signaling
+ * @adev: ACPI companion of the target device.
+ *
+ * Evaluate _S0W for @adev and return the value produced by it or return
+ * ACPI_STATE_UNKNOWN on errors (including _S0W not present).
+ */
+u8 acpi_dev_power_state_for_wake(struct acpi_device *adev)
+{
+ unsigned long long state;
+ acpi_status status;
+
+ status = acpi_evaluate_integer(adev->handle, "_S0W", NULL, &state);
+ if (ACPI_FAILURE(status))
+ return ACPI_STATE_UNKNOWN;
+
+ return state;
+}
+
#ifdef CONFIG_PM
static DEFINE_MUTEX(acpi_pm_notifier_lock);
static DEFINE_MUTEX(acpi_pm_notifier_install_lock);
diff --git a/drivers/acpi/device_sysfs.c b/drivers/acpi/device_sysfs.c
index c3aa15571f16..0fbfbaa8d8e3 100644
--- a/drivers/acpi/device_sysfs.c
+++ b/drivers/acpi/device_sysfs.c
@@ -133,7 +133,7 @@ static void acpi_hide_nondev_subnodes(struct acpi_device_data *data)
* -EINVAL: output error
* -ENOMEM: output is truncated
*/
-static int create_pnp_modalias(struct acpi_device *acpi_dev, char *modalias,
+static int create_pnp_modalias(const struct acpi_device *acpi_dev, char *modalias,
int size)
{
int len;
@@ -191,7 +191,7 @@ static int create_pnp_modalias(struct acpi_device *acpi_dev, char *modalias,
* only be called for devices having ACPI_DT_NAMESPACE_HID in their list of
* ACPI/PNP IDs.
*/
-static int create_of_modalias(struct acpi_device *acpi_dev, char *modalias,
+static int create_of_modalias(const struct acpi_device *acpi_dev, char *modalias,
int size)
{
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
@@ -239,7 +239,7 @@ static int create_of_modalias(struct acpi_device *acpi_dev, char *modalias,
return len;
}
-int __acpi_device_uevent_modalias(struct acpi_device *adev,
+int __acpi_device_uevent_modalias(const struct acpi_device *adev,
struct kobj_uevent_env *env)
{
int len;
@@ -277,7 +277,7 @@ int __acpi_device_uevent_modalias(struct acpi_device *adev,
* Because other buses do not support ACPI HIDs & CIDs, e.g. for a device with
* hid:IBM0001 and cid:ACPI0001 you get: "acpi:IBM0001:ACPI0001".
*/
-int acpi_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env)
+int acpi_device_uevent_modalias(const struct device *dev, struct kobj_uevent_env *env)
{
return __acpi_device_uevent_modalias(acpi_companion_match(dev), env);
}
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index ec584442fb29..06ad497067ac 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -120,7 +120,7 @@ int acpi_bus_register_early_device(int type);
Device Matching and Notification
-------------------------------------------------------------------------- */
struct acpi_device *acpi_companion_match(const struct device *dev);
-int __acpi_device_uevent_modalias(struct acpi_device *adev,
+int __acpi_device_uevent_modalias(const struct acpi_device *adev,
struct kobj_uevent_env *env);
/* --------------------------------------------------------------------------
diff --git a/drivers/acpi/numa/hmat.c b/drivers/acpi/numa/hmat.c
index 605a0c7053be..bba268ecd802 100644
--- a/drivers/acpi/numa/hmat.c
+++ b/drivers/acpi/numa/hmat.c
@@ -718,7 +718,7 @@ static void hmat_register_target_devices(struct memory_target *target)
for (res = target->memregions.child; res; res = res->sibling) {
int target_nid = pxm_to_node(target->memory_pxm);
- hmem_register_device(target_nid, res);
+ hmem_register_resource(target_nid, res);
}
}
@@ -869,4 +869,4 @@ out_put:
acpi_put_table(tbl);
return 0;
}
-device_initcall(hmat_init);
+subsys_initcall(hmat_init);
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index b3c202d2a433..84030804a763 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -1047,6 +1047,9 @@ struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
if (!(root->osc_control_set & OSC_PCI_EXPRESS_DPC_CONTROL))
host_bridge->native_dpc = 0;
+ if (!(root->osc_ext_control_set & OSC_CXL_ERROR_REPORTING_CONTROL))
+ host_bridge->native_cxl_error = 0;
+
/*
* Evaluate the "PCI Boot Configuration" _DSM Function. If it
* exists and returns 0, we must preserve any PCI resource
diff --git a/drivers/acpi/pfr_telemetry.c b/drivers/acpi/pfr_telemetry.c
index 27fb6cdad75f..843f678ade0c 100644
--- a/drivers/acpi/pfr_telemetry.c
+++ b/drivers/acpi/pfr_telemetry.c
@@ -310,7 +310,7 @@ pfrt_log_mmap(struct file *file, struct vm_area_struct *vma)
return -EROFS;
/* changing from read to write with mprotect is not allowed */
- vma->vm_flags &= ~VM_MAYWRITE;
+ vm_flags_clear(vma, VM_MAYWRITE);
pfrt_log_dev = to_pfrt_log_dev(file);
diff --git a/drivers/acpi/pptt.c b/drivers/acpi/pptt.c
index c91342dcbcd6..10975bb603fb 100644
--- a/drivers/acpi/pptt.c
+++ b/drivers/acpi/pptt.c
@@ -81,6 +81,7 @@ static inline bool acpi_pptt_match_type(int table_type, int type)
* acpi_pptt_walk_cache() - Attempt to find the requested acpi_pptt_cache
* @table_hdr: Pointer to the head of the PPTT table
* @local_level: passed res reflects this cache level
+ * @split_levels: Number of split cache levels (data/instruction).
* @res: cache resource in the PPTT we want to walk
* @found: returns a pointer to the requested level if found
* @level: the requested cache level
@@ -100,6 +101,7 @@ static inline bool acpi_pptt_match_type(int table_type, int type)
*/
static unsigned int acpi_pptt_walk_cache(struct acpi_table_header *table_hdr,
unsigned int local_level,
+ unsigned int *split_levels,
struct acpi_subtable_header *res,
struct acpi_pptt_cache **found,
unsigned int level, int type)
@@ -113,8 +115,17 @@ static unsigned int acpi_pptt_walk_cache(struct acpi_table_header *table_hdr,
while (cache) {
local_level++;
+ if (!(cache->flags & ACPI_PPTT_CACHE_TYPE_VALID)) {
+ cache = fetch_pptt_cache(table_hdr, cache->next_level_of_cache);
+ continue;
+ }
+
+ if (split_levels &&
+ (acpi_pptt_match_type(cache->attributes, ACPI_PPTT_CACHE_TYPE_DATA) ||
+ acpi_pptt_match_type(cache->attributes, ACPI_PPTT_CACHE_TYPE_INSTR)))
+ *split_levels = local_level;
+
if (local_level == level &&
- cache->flags & ACPI_PPTT_CACHE_TYPE_VALID &&
acpi_pptt_match_type(cache->attributes, type)) {
if (*found != NULL && cache != *found)
pr_warn("Found duplicate cache level/type unable to determine uniqueness\n");
@@ -135,8 +146,8 @@ static unsigned int acpi_pptt_walk_cache(struct acpi_table_header *table_hdr,
static struct acpi_pptt_cache *
acpi_find_cache_level(struct acpi_table_header *table_hdr,
struct acpi_pptt_processor *cpu_node,
- unsigned int *starting_level, unsigned int level,
- int type)
+ unsigned int *starting_level, unsigned int *split_levels,
+ unsigned int level, int type)
{
struct acpi_subtable_header *res;
unsigned int number_of_levels = *starting_level;
@@ -149,7 +160,8 @@ acpi_find_cache_level(struct acpi_table_header *table_hdr,
resource++;
local_level = acpi_pptt_walk_cache(table_hdr, *starting_level,
- res, &ret, level, type);
+ split_levels, res, &ret,
+ level, type);
/*
* we are looking for the max depth. Since its potentially
* possible for a given node to have resources with differing
@@ -165,29 +177,29 @@ acpi_find_cache_level(struct acpi_table_header *table_hdr,
}
/**
- * acpi_count_levels() - Given a PPTT table, and a CPU node, count the caches
+ * acpi_count_levels() - Given a PPTT table, and a CPU node, count the cache
+ * levels and split cache levels (data/instruction).
* @table_hdr: Pointer to the head of the PPTT table
* @cpu_node: processor node we wish to count caches for
+ * @levels: Number of levels if success.
+ * @split_levels: Number of split cache levels (data/instruction) if
+ * success. Can by NULL.
*
* Given a processor node containing a processing unit, walk into it and count
* how many levels exist solely for it, and then walk up each level until we hit
* the root node (ignore the package level because it may be possible to have
- * caches that exist across packages). Count the number of cache levels that
- * exist at each level on the way up.
- *
- * Return: Total number of levels found.
+ * caches that exist across packages). Count the number of cache levels and
+ * split cache levels (data/instruction) that exist at each level on the way
+ * up.
*/
-static int acpi_count_levels(struct acpi_table_header *table_hdr,
- struct acpi_pptt_processor *cpu_node)
+static void acpi_count_levels(struct acpi_table_header *table_hdr,
+ struct acpi_pptt_processor *cpu_node,
+ unsigned int *levels, unsigned int *split_levels)
{
- int total_levels = 0;
-
do {
- acpi_find_cache_level(table_hdr, cpu_node, &total_levels, 0, 0);
+ acpi_find_cache_level(table_hdr, cpu_node, levels, split_levels, 0, 0);
cpu_node = fetch_pptt_node(table_hdr, cpu_node->parent);
} while (cpu_node);
-
- return total_levels;
}
/**
@@ -281,19 +293,6 @@ static struct acpi_pptt_processor *acpi_find_processor_node(struct acpi_table_he
return NULL;
}
-static int acpi_find_cache_levels(struct acpi_table_header *table_hdr,
- u32 acpi_cpu_id)
-{
- int number_of_levels = 0;
- struct acpi_pptt_processor *cpu;
-
- cpu = acpi_find_processor_node(table_hdr, acpi_cpu_id);
- if (cpu)
- number_of_levels = acpi_count_levels(table_hdr, cpu);
-
- return number_of_levels;
-}
-
static u8 acpi_cache_type(enum cache_type type)
{
switch (type) {
@@ -334,7 +333,7 @@ static struct acpi_pptt_cache *acpi_find_cache_node(struct acpi_table_header *ta
while (cpu_node && !found) {
found = acpi_find_cache_level(table_hdr, cpu_node,
- &total_levels, level, acpi_type);
+ &total_levels, NULL, level, acpi_type);
*node = cpu_node;
cpu_node = fetch_pptt_node(table_hdr, cpu_node->parent);
}
@@ -602,32 +601,48 @@ static int check_acpi_cpu_flag(unsigned int cpu, int rev, u32 flag)
}
/**
- * acpi_find_last_cache_level() - Determines the number of cache levels for a PE
+ * acpi_get_cache_info() - Determine the number of cache levels and
+ * split cache levels (data/instruction) and for a PE.
* @cpu: Kernel logical CPU number
+ * @levels: Number of levels if success.
+ * @split_levels: Number of levels being split (i.e. data/instruction)
+ * if success. Can by NULL.
*
* Given a logical CPU number, returns the number of levels of cache represented
* in the PPTT. Errors caused by lack of a PPTT table, or otherwise, return 0
* indicating we didn't find any cache levels.
*
- * Return: Cache levels visible to this core.
+ * Return: -ENOENT if no PPTT table or no PPTT processor struct found.
+ * 0 on success.
*/
-int acpi_find_last_cache_level(unsigned int cpu)
+int acpi_get_cache_info(unsigned int cpu, unsigned int *levels,
+ unsigned int *split_levels)
{
- u32 acpi_cpu_id;
+ struct acpi_pptt_processor *cpu_node;
struct acpi_table_header *table;
- int number_of_levels = 0;
+ u32 acpi_cpu_id;
+
+ *levels = 0;
+ if (split_levels)
+ *split_levels = 0;
table = acpi_get_pptt();
if (!table)
return -ENOENT;
- pr_debug("Cache Setup find last level CPU=%d\n", cpu);
+ pr_debug("Cache Setup: find cache levels for CPU=%d\n", cpu);
acpi_cpu_id = get_acpi_id_for_cpu(cpu);
- number_of_levels = acpi_find_cache_levels(table, acpi_cpu_id);
- pr_debug("Cache Setup find last level level=%d\n", number_of_levels);
+ cpu_node = acpi_find_processor_node(table, acpi_cpu_id);
+ if (!cpu_node)
+ return -ENOENT;
+
+ acpi_count_levels(table, cpu_node, levels, split_levels);
- return number_of_levels;
+ pr_debug("Cache Setup: last_level=%d split_levels=%d\n",
+ *levels, split_levels ? *split_levels : -1);
+
+ return 0;
}
/**
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c
index ff7454a38058..ce88af9eb562 100644
--- a/drivers/amba/bus.c
+++ b/drivers/amba/bus.c
@@ -235,9 +235,9 @@ static int amba_match(struct device *dev, struct device_driver *drv)
return amba_lookup(pcdrv->id_table, pcdev) != NULL;
}
-static int amba_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int amba_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct amba_device *pcdev = to_amba_device(dev);
+ const struct amba_device *pcdev = to_amba_device(dev);
int retval = 0;
retval = add_uevent_var(env, "AMBA_ID=%08x", pcdev->periphid);
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index 880224ec6abb..fb56bfc45096 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -277,11 +277,11 @@ _binder_proc_lock(struct binder_proc *proc, int line)
/**
* binder_proc_unlock() - Release spinlock for given binder_proc
- * @proc: struct binder_proc to acquire
+ * @proc: struct binder_proc to acquire
*
* Release lock acquired via binder_proc_lock()
*/
-#define binder_proc_unlock(_proc) _binder_proc_unlock(_proc, __LINE__)
+#define binder_proc_unlock(proc) _binder_proc_unlock(proc, __LINE__)
static void
_binder_proc_unlock(struct binder_proc *proc, int line)
__releases(&proc->outer_lock)
@@ -378,7 +378,7 @@ _binder_node_inner_lock(struct binder_node *node, int line)
}
/**
- * binder_node_unlock() - Release node and inner locks
+ * binder_node_inner_unlock() - Release node and inner locks
* @node: struct binder_node to acquire
*
* Release lock acquired via binder_node_lock()
@@ -1194,13 +1194,13 @@ static int binder_inc_ref_olocked(struct binder_ref *ref, int strong,
}
/**
- * binder_dec_ref() - dec the ref for given handle
+ * binder_dec_ref_olocked() - dec the ref for given handle
* @ref: ref to be decremented
* @strong: if true, strong decrement, else weak
*
* Decrement the ref.
*
- * Return: true if ref is cleaned up and ready to be freed
+ * Return: %true if ref is cleaned up and ready to be freed.
*/
static bool binder_dec_ref_olocked(struct binder_ref *ref, int strong)
{
@@ -2728,7 +2728,10 @@ binder_find_outdated_transaction_ilocked(struct binder_transaction *t,
*
* Return: 0 if the transaction was successfully queued
* BR_DEAD_REPLY if the target process or thread is dead
- * BR_FROZEN_REPLY if the target process or thread is frozen
+ * BR_FROZEN_REPLY if the target process or thread is frozen and
+ * the sync transaction was rejected
+ * BR_TRANSACTION_PENDING_FROZEN if the target process is frozen
+ * and the async transaction was successfully queued
*/
static int binder_proc_transaction(struct binder_transaction *t,
struct binder_proc *proc,
@@ -2738,6 +2741,7 @@ static int binder_proc_transaction(struct binder_transaction *t,
bool oneway = !!(t->flags & TF_ONE_WAY);
bool pending_async = false;
struct binder_transaction *t_outdated = NULL;
+ bool frozen = false;
BUG_ON(!node);
binder_node_lock(node);
@@ -2751,15 +2755,16 @@ static int binder_proc_transaction(struct binder_transaction *t,
binder_inner_proc_lock(proc);
if (proc->is_frozen) {
+ frozen = true;
proc->sync_recv |= !oneway;
proc->async_recv |= oneway;
}
- if ((proc->is_frozen && !oneway) || proc->is_dead ||
+ if ((frozen && !oneway) || proc->is_dead ||
(thread && thread->is_dead)) {
binder_inner_proc_unlock(proc);
binder_node_unlock(node);
- return proc->is_frozen ? BR_FROZEN_REPLY : BR_DEAD_REPLY;
+ return frozen ? BR_FROZEN_REPLY : BR_DEAD_REPLY;
}
if (!thread && !pending_async)
@@ -2770,7 +2775,7 @@ static int binder_proc_transaction(struct binder_transaction *t,
} else if (!pending_async) {
binder_enqueue_work_ilocked(&t->work, &proc->todo);
} else {
- if ((t->flags & TF_UPDATE_TXN) && proc->is_frozen) {
+ if ((t->flags & TF_UPDATE_TXN) && frozen) {
t_outdated = binder_find_outdated_transaction_ilocked(t,
&node->async_todo);
if (t_outdated) {
@@ -2807,14 +2812,17 @@ static int binder_proc_transaction(struct binder_transaction *t,
binder_stats_deleted(BINDER_STAT_TRANSACTION);
}
+ if (oneway && frozen)
+ return BR_TRANSACTION_PENDING_FROZEN;
+
return 0;
}
/**
* binder_get_node_refs_for_txn() - Get required refs on node for txn
* @node: struct binder_node for which to get refs
- * @proc: returns @node->proc if valid
- * @error: if no @proc then returns BR_DEAD_REPLY
+ * @procp: returns @node->proc if valid
+ * @error: if no @procp then returns BR_DEAD_REPLY
*
* User-space normally keeps the node alive when creating a transaction
* since it has a reference to the target. The local strong ref keeps it
@@ -2828,8 +2836,8 @@ static int binder_proc_transaction(struct binder_transaction *t,
* constructing the transaction, so we take that here as well.
*
* Return: The target_node with refs taken or NULL if no @node->proc is NULL.
- * Also sets @proc if valid. If the @node->proc is NULL indicating that the
- * target proc has died, @error is set to BR_DEAD_REPLY
+ * Also sets @procp if valid. If the @node->proc is NULL indicating that the
+ * target proc has died, @error is set to BR_DEAD_REPLY.
*/
static struct binder_node *binder_get_node_refs_for_txn(
struct binder_node *node,
@@ -3607,9 +3615,17 @@ static void binder_transaction(struct binder_proc *proc,
} else {
BUG_ON(target_node == NULL);
BUG_ON(t->buffer->async_transaction != 1);
- binder_enqueue_thread_work(thread, tcomplete);
return_error = binder_proc_transaction(t, target_proc, NULL);
- if (return_error)
+ /*
+ * Let the caller know when async transaction reaches a frozen
+ * process and is put in a pending queue, waiting for the target
+ * process to be unfrozen.
+ */
+ if (return_error == BR_TRANSACTION_PENDING_FROZEN)
+ tcomplete->type = BINDER_WORK_TRANSACTION_PENDING;
+ binder_enqueue_thread_work(thread, tcomplete);
+ if (return_error &&
+ return_error != BR_TRANSACTION_PENDING_FROZEN)
goto err_dead_proc_or_thread;
}
if (target_thread)
@@ -4440,10 +4456,13 @@ retry:
binder_stat_br(proc, thread, cmd);
} break;
case BINDER_WORK_TRANSACTION_COMPLETE:
+ case BINDER_WORK_TRANSACTION_PENDING:
case BINDER_WORK_TRANSACTION_ONEWAY_SPAM_SUSPECT: {
if (proc->oneway_spam_detection_enabled &&
w->type == BINDER_WORK_TRANSACTION_ONEWAY_SPAM_SUSPECT)
cmd = BR_ONEWAY_SPAM_SUSPECT;
+ else if (w->type == BINDER_WORK_TRANSACTION_PENDING)
+ cmd = BR_TRANSACTION_PENDING_FROZEN;
else
cmd = BR_TRANSACTION_COMPLETE;
binder_inner_proc_unlock(proc);
@@ -5006,20 +5025,14 @@ static __poll_t binder_poll(struct file *filp,
return 0;
}
-static int binder_ioctl_write_read(struct file *filp,
- unsigned int cmd, unsigned long arg,
+static int binder_ioctl_write_read(struct file *filp, unsigned long arg,
struct binder_thread *thread)
{
int ret = 0;
struct binder_proc *proc = filp->private_data;
- unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;
struct binder_write_read bwr;
- if (size != sizeof(struct binder_write_read)) {
- ret = -EINVAL;
- goto out;
- }
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
ret = -EFAULT;
goto out;
@@ -5296,7 +5309,6 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
int ret;
struct binder_proc *proc = filp->private_data;
struct binder_thread *thread;
- unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;
/*pr_info("binder_ioctl: %d:%d %x %lx\n",
@@ -5318,7 +5330,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
switch (cmd) {
case BINDER_WRITE_READ:
- ret = binder_ioctl_write_read(filp, cmd, arg, thread);
+ ret = binder_ioctl_write_read(filp, arg, thread);
if (ret)
goto err;
break;
@@ -5361,10 +5373,6 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
case BINDER_VERSION: {
struct binder_version __user *ver = ubuf;
- if (size != sizeof(struct binder_version)) {
- ret = -EINVAL;
- goto err;
- }
if (put_user(BINDER_CURRENT_PROTOCOL_VERSION,
&ver->protocol_version)) {
ret = -EINVAL;
@@ -5572,8 +5580,7 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
proc->pid, vma->vm_start, vma->vm_end, "bad vm_flags", -EPERM);
return -EPERM;
}
- vma->vm_flags |= VM_DONTCOPY | VM_MIXEDMAP;
- vma->vm_flags &= ~VM_MAYWRITE;
+ vm_flags_mod(vma, VM_DONTCOPY | VM_MIXEDMAP, VM_MAYWRITE);
vma->vm_ops = &binder_vm_ops;
vma->vm_private_data = proc;
@@ -6170,6 +6177,7 @@ static const char * const binder_return_strings[] = {
"BR_FAILED_REPLY",
"BR_FROZEN_REPLY",
"BR_ONEWAY_SPAM_SUSPECT",
+ "BR_TRANSACTION_PENDING_FROZEN"
};
static const char * const binder_command_strings[] = {
diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c
index 4ad42b0f75cd..55a3c3c2409f 100644
--- a/drivers/android/binder_alloc.c
+++ b/drivers/android/binder_alloc.c
@@ -1019,7 +1019,7 @@ enum lru_status binder_alloc_free_page(struct list_head *item,
if (vma) {
trace_binder_unmap_user_start(alloc, index);
- zap_page_range(vma, page_addr, PAGE_SIZE);
+ zap_page_range_single(vma, page_addr, PAGE_SIZE, NULL);
trace_binder_unmap_user_end(alloc, index);
}
diff --git a/drivers/android/binder_internal.h b/drivers/android/binder_internal.h
index abe19d88c6ec..28ef5b3704b1 100644
--- a/drivers/android/binder_internal.h
+++ b/drivers/android/binder_internal.h
@@ -133,7 +133,7 @@ enum binder_stat_types {
};
struct binder_stats {
- atomic_t br[_IOC_NR(BR_ONEWAY_SPAM_SUSPECT) + 1];
+ atomic_t br[_IOC_NR(BR_TRANSACTION_PENDING_FROZEN) + 1];
atomic_t bc[_IOC_NR(BC_REPLY_SG) + 1];
atomic_t obj_created[BINDER_STAT_COUNT];
atomic_t obj_deleted[BINDER_STAT_COUNT];
@@ -152,6 +152,7 @@ struct binder_work {
enum binder_work_type {
BINDER_WORK_TRANSACTION = 1,
BINDER_WORK_TRANSACTION_COMPLETE,
+ BINDER_WORK_TRANSACTION_PENDING,
BINDER_WORK_TRANSACTION_ONEWAY_SPAM_SUSPECT,
BINDER_WORK_RETURN_ERROR,
BINDER_WORK_NODE,
diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c
index 348d63d1e3d3..76e7d6676657 100644
--- a/drivers/android/binderfs.c
+++ b/drivers/android/binderfs.c
@@ -222,14 +222,14 @@ err:
}
/**
- * binderfs_ctl_ioctl - handle binder device node allocation requests
+ * binder_ctl_ioctl - handle binder device node allocation requests
*
* The request handler for the binder-control device. All requests operate on
* the binderfs mount the binder-control device resides in:
* - BINDER_CTL_ADD
* Allocate a new binder device.
*
- * Return: 0 on success, negative errno on failure
+ * Return: %0 on success, negative errno on failure.
*/
static long binder_ctl_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 0b6358a5b315..b56fba76b43f 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -1144,6 +1144,20 @@ config PATA_WINBOND_VLB
Support for the Winbond W83759A controller on Vesa Local Bus
systems.
+config PATA_PARPORT
+ tristate "Parallel port IDE device support"
+ depends on PARPORT_PC
+ help
+ There are many external CD-ROM and disk devices that connect through
+ your computer's parallel port. Most of them are actually IDE devices
+ using a parallel port IDE adapter. This option enables the
+ PATA_PARPORT subsystem which contains drivers for many of these
+ external drives.
+ Read <file:Documentation/admin-guide/blockdev/paride.rst> for more
+ information.
+
+source "drivers/ata/pata_parport/Kconfig"
+
comment "Generic fallback / legacy drivers"
config PATA_ACPI
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 4ee5c0761d90..20e6645ab737 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -112,6 +112,8 @@ obj-$(CONFIG_PATA_RZ1000) += pata_rz1000.o
obj-$(CONFIG_PATA_PXA) += pata_pxa.o
+obj-$(CONFIG_PATA_PARPORT) += pata_parport/
+
# Should be last but two libata driver
obj-$(CONFIG_PATA_ACPI) += pata_acpi.o
# Should be last but one libata driver
diff --git a/drivers/ata/acard-ahci.c b/drivers/ata/acard-ahci.c
index 7654a40c12b4..993eadd173da 100644
--- a/drivers/ata/acard-ahci.c
+++ b/drivers/ata/acard-ahci.c
@@ -57,7 +57,7 @@ struct acard_sg {
};
static enum ata_completion_errors acard_ahci_qc_prep(struct ata_queued_cmd *qc);
-static bool acard_ahci_qc_fill_rtf(struct ata_queued_cmd *qc);
+static void acard_ahci_qc_fill_rtf(struct ata_queued_cmd *qc);
static int acard_ahci_port_start(struct ata_port *ap);
static int acard_ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
@@ -248,7 +248,7 @@ static enum ata_completion_errors acard_ahci_qc_prep(struct ata_queued_cmd *qc)
return AC_ERR_OK;
}
-static bool acard_ahci_qc_fill_rtf(struct ata_queued_cmd *qc)
+static void acard_ahci_qc_fill_rtf(struct ata_queued_cmd *qc)
{
struct ahci_port_priv *pp = qc->ap->private_data;
u8 *rx_fis = pp->rx_fis;
@@ -263,13 +263,11 @@ static bool acard_ahci_qc_fill_rtf(struct ata_queued_cmd *qc)
* Setup FIS.
*/
if (qc->tf.protocol == ATA_PROT_PIO && qc->dma_dir == DMA_FROM_DEVICE &&
- !(qc->flags & ATA_QCFLAG_FAILED)) {
+ !(qc->flags & ATA_QCFLAG_EH)) {
ata_tf_from_fis(rx_fis + RX_FIS_PIO_SETUP, &qc->result_tf);
qc->result_tf.status = (rx_fis + RX_FIS_PIO_SETUP)[15];
} else
ata_tf_from_fis(rx_fis + RX_FIS_D2H_REG, &qc->result_tf);
-
- return true;
}
static int acard_ahci_port_start(struct ata_port *ap)
diff --git a/drivers/ata/ahci_octeon.c b/drivers/ata/ahci_octeon.c
index b9460b91288f..5021ab3ede49 100644
--- a/drivers/ata/ahci_octeon.c
+++ b/drivers/ata/ahci_octeon.c
@@ -73,11 +73,6 @@ static int ahci_octeon_probe(struct platform_device *pdev)
return 0;
}
-static int ahci_octeon_remove(struct platform_device *pdev)
-{
- return 0;
-}
-
static const struct of_device_id octeon_ahci_match[] = {
{ .compatible = "cavium,octeon-7130-sata-uctl", },
{ /* sentinel */ }
@@ -86,7 +81,6 @@ MODULE_DEVICE_TABLE(of, octeon_ahci_match);
static struct platform_driver ahci_octeon_driver = {
.probe = ahci_octeon_probe,
- .remove = ahci_octeon_remove,
.driver = {
.name = "octeon-ahci",
.of_match_table = octeon_ahci_match,
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index 29acc35bf4a6..8f216de76648 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -55,7 +55,8 @@ static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,
static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
-static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc);
+static void ahci_qc_fill_rtf(struct ata_queued_cmd *qc);
+static void ahci_qc_ncq_fill_rtf(struct ata_port *ap, u64 done_mask);
static int ahci_port_start(struct ata_port *ap);
static void ahci_port_stop(struct ata_port *ap);
static enum ata_completion_errors ahci_qc_prep(struct ata_queued_cmd *qc);
@@ -157,6 +158,7 @@ struct ata_port_operations ahci_ops = {
.qc_prep = ahci_qc_prep,
.qc_issue = ahci_qc_issue,
.qc_fill_rtf = ahci_qc_fill_rtf,
+ .qc_ncq_fill_rtf = ahci_qc_ncq_fill_rtf,
.freeze = ahci_freeze,
.thaw = ahci_thaw,
@@ -1847,18 +1849,47 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
ata_port_abort(ap);
}
-static void ahci_handle_port_interrupt(struct ata_port *ap,
- void __iomem *port_mmio, u32 status)
+static void ahci_qc_complete(struct ata_port *ap, void __iomem *port_mmio)
{
struct ata_eh_info *ehi = &ap->link.eh_info;
struct ahci_port_priv *pp = ap->private_data;
- struct ahci_host_priv *hpriv = ap->host->private_data;
- int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING);
u32 qc_active = 0;
int rc;
+ /*
+ * pp->active_link is not reliable once FBS is enabled, both
+ * PORT_SCR_ACT and PORT_CMD_ISSUE should be checked because
+ * NCQ and non-NCQ commands may be in flight at the same time.
+ */
+ if (pp->fbs_enabled) {
+ if (ap->qc_active) {
+ qc_active = readl(port_mmio + PORT_SCR_ACT);
+ qc_active |= readl(port_mmio + PORT_CMD_ISSUE);
+ }
+ } else {
+ /* pp->active_link is valid iff any command is in flight */
+ if (ap->qc_active && pp->active_link->sactive)
+ qc_active = readl(port_mmio + PORT_SCR_ACT);
+ else
+ qc_active = readl(port_mmio + PORT_CMD_ISSUE);
+ }
+
+ rc = ata_qc_complete_multiple(ap, qc_active);
+ if (unlikely(rc < 0 && !(ap->pflags & ATA_PFLAG_RESETTING))) {
+ ehi->err_mask |= AC_ERR_HSM;
+ ehi->action |= ATA_EH_RESET;
+ ata_port_freeze(ap);
+ }
+}
+
+static void ahci_handle_port_interrupt(struct ata_port *ap,
+ void __iomem *port_mmio, u32 status)
+{
+ struct ahci_port_priv *pp = ap->private_data;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+
/* ignore BAD_PMP while resetting */
- if (unlikely(resetting))
+ if (unlikely(ap->pflags & ATA_PFLAG_RESETTING))
status &= ~PORT_IRQ_BAD_PMP;
if (sata_lpm_ignore_phy_events(&ap->link)) {
@@ -1867,6 +1898,12 @@ static void ahci_handle_port_interrupt(struct ata_port *ap,
}
if (unlikely(status & PORT_IRQ_ERROR)) {
+ /*
+ * Before getting the error notification, we may have
+ * received SDB FISes notifying successful completions.
+ * Handle these first and then handle the error.
+ */
+ ahci_qc_complete(ap, port_mmio);
ahci_error_intr(ap, status);
return;
}
@@ -1903,32 +1940,8 @@ static void ahci_handle_port_interrupt(struct ata_port *ap,
}
}
- /* pp->active_link is not reliable once FBS is enabled, both
- * PORT_SCR_ACT and PORT_CMD_ISSUE should be checked because
- * NCQ and non-NCQ commands may be in flight at the same time.
- */
- if (pp->fbs_enabled) {
- if (ap->qc_active) {
- qc_active = readl(port_mmio + PORT_SCR_ACT);
- qc_active |= readl(port_mmio + PORT_CMD_ISSUE);
- }
- } else {
- /* pp->active_link is valid iff any command is in flight */
- if (ap->qc_active && pp->active_link->sactive)
- qc_active = readl(port_mmio + PORT_SCR_ACT);
- else
- qc_active = readl(port_mmio + PORT_CMD_ISSUE);
- }
-
-
- rc = ata_qc_complete_multiple(ap, qc_active);
-
- /* while resetting, invalid completions are expected */
- if (unlikely(rc < 0 && !resetting)) {
- ehi->err_mask |= AC_ERR_HSM;
- ehi->action |= ATA_EH_RESET;
- ata_port_freeze(ap);
- }
+ /* Handle completed commands */
+ ahci_qc_complete(ap, port_mmio);
}
static void ahci_port_intr(struct ata_port *ap)
@@ -2053,11 +2066,18 @@ unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
}
EXPORT_SYMBOL_GPL(ahci_qc_issue);
-static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc)
+static void ahci_qc_fill_rtf(struct ata_queued_cmd *qc)
{
struct ahci_port_priv *pp = qc->ap->private_data;
u8 *rx_fis = pp->rx_fis;
+ /*
+ * rtf may already be filled (e.g. for successful NCQ commands).
+ * If that is the case, we have nothing to do.
+ */
+ if (qc->flags & ATA_QCFLAG_RTF_FILLED)
+ return;
+
if (pp->fbs_enabled)
rx_fis += qc->dev->link->pmp * AHCI_RX_FIS_SZ;
@@ -2068,9 +2088,12 @@ static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc)
* Setup FIS.
*/
if (qc->tf.protocol == ATA_PROT_PIO && qc->dma_dir == DMA_FROM_DEVICE &&
- !(qc->flags & ATA_QCFLAG_FAILED)) {
+ !(qc->flags & ATA_QCFLAG_EH)) {
ata_tf_from_fis(rx_fis + RX_FIS_PIO_SETUP, &qc->result_tf);
qc->result_tf.status = (rx_fis + RX_FIS_PIO_SETUP)[15];
+ qc->flags |= ATA_QCFLAG_RTF_FILLED;
+ return;
+ }
/*
* For NCQ commands, we never get a D2H FIS, so reading the D2H Register
@@ -2080,15 +2103,85 @@ static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc)
* instead. However, the SDB FIS does not contain the LBA, so we can't
* use the ata_tf_from_fis() helper.
*/
- } else if (ata_is_ncq(qc->tf.protocol)) {
+ if (ata_is_ncq(qc->tf.protocol)) {
const u8 *fis = rx_fis + RX_FIS_SDB;
+ /*
+ * Successful NCQ commands have been filled already.
+ * A failed NCQ command will read the status here.
+ * (Note that a failed NCQ command will get a more specific
+ * error when reading the NCQ Command Error log.)
+ */
qc->result_tf.status = fis[2];
qc->result_tf.error = fis[3];
- } else
- ata_tf_from_fis(rx_fis + RX_FIS_D2H_REG, &qc->result_tf);
+ qc->flags |= ATA_QCFLAG_RTF_FILLED;
+ return;
+ }
+
+ ata_tf_from_fis(rx_fis + RX_FIS_D2H_REG, &qc->result_tf);
+ qc->flags |= ATA_QCFLAG_RTF_FILLED;
+}
+
+static void ahci_qc_ncq_fill_rtf(struct ata_port *ap, u64 done_mask)
+{
+ struct ahci_port_priv *pp = ap->private_data;
+ const u8 *fis;
+
+ /* No outstanding commands. */
+ if (!ap->qc_active)
+ return;
+
+ /*
+ * FBS not enabled, so read status and error once, since they are shared
+ * for all QCs.
+ */
+ if (!pp->fbs_enabled) {
+ u8 status, error;
+
+ /* No outstanding NCQ commands. */
+ if (!pp->active_link->sactive)
+ return;
+
+ fis = pp->rx_fis + RX_FIS_SDB;
+ status = fis[2];
+ error = fis[3];
- return true;
+ while (done_mask) {
+ struct ata_queued_cmd *qc;
+ unsigned int tag = __ffs64(done_mask);
+
+ qc = ata_qc_from_tag(ap, tag);
+ if (qc && ata_is_ncq(qc->tf.protocol)) {
+ qc->result_tf.status = status;
+ qc->result_tf.error = error;
+ qc->flags |= ATA_QCFLAG_RTF_FILLED;
+ }
+ done_mask &= ~(1ULL << tag);
+ }
+
+ return;
+ }
+
+ /*
+ * FBS enabled, so read the status and error for each QC, since the QCs
+ * can belong to different PMP links. (Each PMP link has its own FIS
+ * Receive Area.)
+ */
+ while (done_mask) {
+ struct ata_queued_cmd *qc;
+ unsigned int tag = __ffs64(done_mask);
+
+ qc = ata_qc_from_tag(ap, tag);
+ if (qc && ata_is_ncq(qc->tf.protocol)) {
+ fis = pp->rx_fis;
+ fis += qc->dev->link->pmp * AHCI_RX_FIS_SZ;
+ fis += RX_FIS_SDB;
+ qc->result_tf.status = fis[2];
+ qc->result_tf.error = fis[3];
+ qc->flags |= ATA_QCFLAG_RTF_FILLED;
+ }
+ done_mask &= ~(1ULL << tag);
+ }
}
static void ahci_freeze(struct ata_port *ap)
@@ -2138,7 +2231,7 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
struct ata_port *ap = qc->ap;
/* make DMA engine forget about the failed command */
- if (qc->flags & ATA_QCFLAG_FAILED)
+ if (qc->flags & ATA_QCFLAG_EH)
ahci_kick_engine(ap);
}
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index c4c89d24f84c..14c17c3bda4e 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -552,7 +552,7 @@ static const u8 ata_rw_cmds[] = {
0,
0,
0,
- ATA_CMD_WRITE_MULTI_FUA_EXT,
+ 0,
/* pio */
ATA_CMD_PIO_READ,
ATA_CMD_PIO_WRITE,
@@ -574,17 +574,18 @@ static const u8 ata_rw_cmds[] = {
};
/**
- * ata_rwcmd_protocol - set taskfile r/w commands and protocol
- * @tf: command to examine and configure
- * @dev: device tf belongs to
+ * ata_set_rwcmd_protocol - set taskfile r/w command and protocol
+ * @dev: target device for the taskfile
+ * @tf: taskfile to examine and configure
*
- * Examine the device configuration and tf->flags to calculate
- * the proper read/write commands and protocol to use.
+ * Examine the device configuration and tf->flags to determine
+ * the proper read/write command and protocol to use for @tf.
*
* LOCKING:
* caller.
*/
-static int ata_rwcmd_protocol(struct ata_taskfile *tf, struct ata_device *dev)
+static bool ata_set_rwcmd_protocol(struct ata_device *dev,
+ struct ata_taskfile *tf)
{
u8 cmd;
@@ -607,11 +608,12 @@ static int ata_rwcmd_protocol(struct ata_taskfile *tf, struct ata_device *dev)
}
cmd = ata_rw_cmds[index + fua + lba48 + write];
- if (cmd) {
- tf->command = cmd;
- return 0;
- }
- return -1;
+ if (!cmd)
+ return false;
+
+ tf->command = cmd;
+
+ return true;
}
/**
@@ -725,7 +727,8 @@ int ata_build_rw_tf(struct ata_queued_cmd *qc, u64 block, u32 n_block,
} else if (dev->flags & ATA_DFLAG_LBA) {
tf->flags |= ATA_TFLAG_LBA;
- if (lba_28_ok(block, n_block)) {
+ /* We need LBA48 for FUA writes */
+ if (!(tf->flags & ATA_TFLAG_FUA) && lba_28_ok(block, n_block)) {
/* use LBA28 */
tf->device |= (block >> 24) & 0xf;
} else if (lba_48_ok(block, n_block)) {
@@ -740,11 +743,12 @@ int ata_build_rw_tf(struct ata_queued_cmd *qc, u64 block, u32 n_block,
tf->hob_lbah = (block >> 40) & 0xff;
tf->hob_lbam = (block >> 32) & 0xff;
tf->hob_lbal = (block >> 24) & 0xff;
- } else
+ } else {
/* request too large even for LBA48 */
return -ERANGE;
+ }
- if (unlikely(ata_rwcmd_protocol(tf, dev) < 0))
+ if (unlikely(!ata_set_rwcmd_protocol(dev, tf)))
return -EINVAL;
tf->nsect = n_block & 0xff;
@@ -762,7 +766,7 @@ int ata_build_rw_tf(struct ata_queued_cmd *qc, u64 block, u32 n_block,
if (!lba_28_ok(block, n_block))
return -ERANGE;
- if (unlikely(ata_rwcmd_protocol(tf, dev) < 0))
+ if (unlikely(!ata_set_rwcmd_protocol(dev, tf)))
return -EINVAL;
/* Convert LBA to CHS */
@@ -1590,7 +1594,7 @@ static unsigned ata_exec_internal_sg(struct ata_device *dev,
ap->ops->post_internal_cmd(qc);
/* perform minimal error analysis */
- if (qc->flags & ATA_QCFLAG_FAILED) {
+ if (qc->flags & ATA_QCFLAG_EH) {
if (qc->result_tf.status & (ATA_ERR | ATA_DF))
qc->err_mask |= AC_ERR_DEV;
@@ -2420,6 +2424,28 @@ static void ata_dev_config_chs(struct ata_device *dev)
dev->heads, dev->sectors);
}
+static void ata_dev_config_fua(struct ata_device *dev)
+{
+ /* Ignore FUA support if its use is disabled globally */
+ if (!libata_fua)
+ goto nofua;
+
+ /* Ignore devices without support for WRITE DMA FUA EXT */
+ if (!(dev->flags & ATA_DFLAG_LBA48) || !ata_id_has_fua(dev->id))
+ goto nofua;
+
+ /* Ignore known bad devices and devices that lack NCQ support */
+ if (!ata_ncq_supported(dev) || (dev->horkage & ATA_HORKAGE_NO_FUA))
+ goto nofua;
+
+ dev->flags |= ATA_DFLAG_FUA;
+
+ return;
+
+nofua:
+ dev->flags &= ~ATA_DFLAG_FUA;
+}
+
static void ata_dev_config_devslp(struct ata_device *dev)
{
u8 *sata_setting = dev->link->ap->sector_buf;
@@ -2508,7 +2534,8 @@ static void ata_dev_print_features(struct ata_device *dev)
return;
ata_dev_info(dev,
- "Features:%s%s%s%s%s%s\n",
+ "Features:%s%s%s%s%s%s%s\n",
+ dev->flags & ATA_DFLAG_FUA ? " FUA" : "",
dev->flags & ATA_DFLAG_TRUSTED ? " Trust" : "",
dev->flags & ATA_DFLAG_DA ? " Dev-Attention" : "",
dev->flags & ATA_DFLAG_DEVSLP ? " Dev-Sleep" : "",
@@ -2669,6 +2696,7 @@ int ata_dev_configure(struct ata_device *dev)
ata_dev_config_chs(dev);
}
+ ata_dev_config_fua(dev);
ata_dev_config_devslp(dev);
ata_dev_config_sense_reporting(dev);
ata_dev_config_zac(dev);
@@ -4106,6 +4134,12 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
*/
{ "SATADOM-ML 3ME", NULL, ATA_HORKAGE_NO_LOG_DIR },
+ /* Buggy FUA */
+ { "Maxtor", "BANC1G10", ATA_HORKAGE_NO_FUA },
+ { "WDC*WD2500J*", NULL, ATA_HORKAGE_NO_FUA },
+ { "OCZ-VERTEX*", NULL, ATA_HORKAGE_NO_FUA },
+ { "INTEL*SSDSC2CT*", NULL, ATA_HORKAGE_NO_FUA },
+
/* End Marker */
{ }
};
@@ -4686,10 +4720,10 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
/* XXX: New EH and old EH use different mechanisms to
* synchronize EH with regular execution path.
*
- * In new EH, a failed qc is marked with ATA_QCFLAG_FAILED.
+ * In new EH, a qc owned by EH is marked with ATA_QCFLAG_EH.
* Normal execution path is responsible for not accessing a
- * failed qc. libata core enforces the rule by returning NULL
- * from ata_qc_from_tag() for failed qcs.
+ * qc owned by EH. libata core enforces the rule by returning NULL
+ * from ata_qc_from_tag() for qcs owned by EH.
*
* Old EH depends on ata_qc_complete() nullifying completion
* requests if ATA_QCFLAG_EH_SCHEDULED is set. Old EH does
@@ -4701,7 +4735,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
struct ata_eh_info *ehi = &dev->link->eh_info;
if (unlikely(qc->err_mask))
- qc->flags |= ATA_QCFLAG_FAILED;
+ qc->flags |= ATA_QCFLAG_EH;
/*
* Finish internal commands without any further processing
@@ -4718,7 +4752,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
* Non-internal qc has failed. Fill the result TF and
* summon EH.
*/
- if (unlikely(qc->flags & ATA_QCFLAG_FAILED)) {
+ if (unlikely(qc->flags & ATA_QCFLAG_EH)) {
fill_result_tf(qc);
trace_ata_qc_complete_failed(qc);
ata_qc_schedule_eh(qc);
@@ -6217,6 +6251,7 @@ static const struct ata_force_param force_tbl[] __initconst = {
force_horkage_onoff(lpm, ATA_HORKAGE_NOLPM),
force_horkage_onoff(setxfer, ATA_HORKAGE_NOSETXFER),
force_horkage_on(dump_id, ATA_HORKAGE_DUMP_ID),
+ force_horkage_onoff(fua, ATA_HORKAGE_NO_FUA),
force_horkage_on(disable, ATA_HORKAGE_DISABLE),
};
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 34303ce67c14..a6c901811802 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -565,17 +565,23 @@ void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap,
{
int i;
unsigned long flags;
+ struct scsi_cmnd *scmd, *tmp;
+ int nr_timedout = 0;
/* make sure sff pio task is not running */
ata_sff_flush_pio_task(ap);
+ if (!ap->ops->error_handler)
+ return;
+
/* synchronize with host lock and sort out timeouts */
- /* For new EH, all qcs are finished in one of three ways -
+ /*
+ * For new EH, all qcs are finished in one of three ways -
* normal completion, error completion, and SCSI timeout.
* Both completions can race against SCSI timeout. When normal
* completion wins, the qc never reaches EH. When error
- * completion wins, the qc has ATA_QCFLAG_FAILED set.
+ * completion wins, the qc has ATA_QCFLAG_EH set.
*
* When SCSI timeout wins, things are a bit more complex.
* Normal or error completion can occur after the timeout but
@@ -584,64 +590,61 @@ void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap,
* timed out iff its associated qc is active and not failed.
*/
spin_lock_irqsave(ap->lock, flags);
- if (ap->ops->error_handler) {
- struct scsi_cmnd *scmd, *tmp;
- int nr_timedout = 0;
-
- /* This must occur under the ap->lock as we don't want
- a polled recovery to race the real interrupt handler
-
- The lost_interrupt handler checks for any completed but
- non-notified command and completes much like an IRQ handler.
- We then fall into the error recovery code which will treat
- this as if normal completion won the race */
-
- if (ap->ops->lost_interrupt)
- ap->ops->lost_interrupt(ap);
+ /*
+ * This must occur under the ap->lock as we don't want
+ * a polled recovery to race the real interrupt handler
+ *
+ * The lost_interrupt handler checks for any completed but
+ * non-notified command and completes much like an IRQ handler.
+ *
+ * We then fall into the error recovery code which will treat
+ * this as if normal completion won the race
+ */
+ if (ap->ops->lost_interrupt)
+ ap->ops->lost_interrupt(ap);
- list_for_each_entry_safe(scmd, tmp, eh_work_q, eh_entry) {
- struct ata_queued_cmd *qc;
+ list_for_each_entry_safe(scmd, tmp, eh_work_q, eh_entry) {
+ struct ata_queued_cmd *qc;
- ata_qc_for_each_raw(ap, qc, i) {
- if (qc->flags & ATA_QCFLAG_ACTIVE &&
- qc->scsicmd == scmd)
- break;
- }
+ ata_qc_for_each_raw(ap, qc, i) {
+ if (qc->flags & ATA_QCFLAG_ACTIVE &&
+ qc->scsicmd == scmd)
+ break;
+ }
- if (i < ATA_MAX_QUEUE) {
- /* the scmd has an associated qc */
- if (!(qc->flags & ATA_QCFLAG_FAILED)) {
- /* which hasn't failed yet, timeout */
- qc->err_mask |= AC_ERR_TIMEOUT;
- qc->flags |= ATA_QCFLAG_FAILED;
- nr_timedout++;
- }
- } else {
- /* Normal completion occurred after
- * SCSI timeout but before this point.
- * Successfully complete it.
- */
- scmd->retries = scmd->allowed;
- scsi_eh_finish_cmd(scmd, &ap->eh_done_q);
+ if (i < ATA_MAX_QUEUE) {
+ /* the scmd has an associated qc */
+ if (!(qc->flags & ATA_QCFLAG_EH)) {
+ /* which hasn't failed yet, timeout */
+ qc->err_mask |= AC_ERR_TIMEOUT;
+ qc->flags |= ATA_QCFLAG_EH;
+ nr_timedout++;
}
+ } else {
+ /* Normal completion occurred after
+ * SCSI timeout but before this point.
+ * Successfully complete it.
+ */
+ scmd->retries = scmd->allowed;
+ scsi_eh_finish_cmd(scmd, &ap->eh_done_q);
}
+ }
- /* If we have timed out qcs. They belong to EH from
- * this point but the state of the controller is
- * unknown. Freeze the port to make sure the IRQ
- * handler doesn't diddle with those qcs. This must
- * be done atomically w.r.t. setting QCFLAG_FAILED.
- */
- if (nr_timedout)
- __ata_port_freeze(ap);
+ /*
+ * If we have timed out qcs. They belong to EH from
+ * this point but the state of the controller is
+ * unknown. Freeze the port to make sure the IRQ
+ * handler doesn't diddle with those qcs. This must
+ * be done atomically w.r.t. setting ATA_QCFLAG_EH.
+ */
+ if (nr_timedout)
+ __ata_port_freeze(ap);
+ /* initialize eh_tries */
+ ap->eh_tries = ATA_EH_MAX_TRIES;
- /* initialize eh_tries */
- ap->eh_tries = ATA_EH_MAX_TRIES;
- }
spin_unlock_irqrestore(ap->lock, flags);
-
}
EXPORT_SYMBOL(ata_scsi_cmd_error_handler);
@@ -911,12 +914,12 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
WARN_ON(!ap->ops->error_handler);
- qc->flags |= ATA_QCFLAG_FAILED;
+ qc->flags |= ATA_QCFLAG_EH;
ata_eh_set_pending(ap, 1);
/* The following will fail if timeout has already expired.
* ata_scsi_error() takes care of such scmds on EH entry.
- * Note that ATA_QCFLAG_FAILED is unconditionally set after
+ * Note that ATA_QCFLAG_EH is unconditionally set after
* this function completes.
*/
blk_abort_request(scsi_cmd_to_rq(qc->scsicmd));
@@ -994,7 +997,7 @@ static int ata_do_link_abort(struct ata_port *ap, struct ata_link *link)
/* include internal tag in iteration */
ata_qc_for_each_with_internal(ap, qc, tag) {
if (qc && (!link || qc->dev->link == link)) {
- qc->flags |= ATA_QCFLAG_FAILED;
+ qc->flags |= ATA_QCFLAG_EH;
ata_qc_complete(qc);
nr_aborted++;
}
@@ -1954,7 +1957,7 @@ static void ata_eh_link_autopsy(struct ata_link *link)
all_err_mask |= ehc->i.err_mask;
ata_qc_for_each_raw(ap, qc, tag) {
- if (!(qc->flags & ATA_QCFLAG_FAILED) ||
+ if (!(qc->flags & ATA_QCFLAG_EH) ||
qc->flags & ATA_QCFLAG_RETRY ||
ata_dev_phys_link(qc->dev) != link)
continue;
@@ -2232,7 +2235,7 @@ static void ata_eh_link_report(struct ata_link *link)
desc = ehc->i.desc;
ata_qc_for_each_raw(ap, qc, tag) {
- if (!(qc->flags & ATA_QCFLAG_FAILED) ||
+ if (!(qc->flags & ATA_QCFLAG_EH) ||
ata_dev_phys_link(qc->dev) != link ||
((qc->flags & ATA_QCFLAG_QUIET) &&
qc->err_mask == AC_ERR_DEV))
@@ -2298,7 +2301,7 @@ static void ata_eh_link_report(struct ata_link *link)
char data_buf[20] = "";
char cdb_buf[70] = "";
- if (!(qc->flags & ATA_QCFLAG_FAILED) ||
+ if (!(qc->flags & ATA_QCFLAG_EH) ||
ata_dev_phys_link(qc->dev) != link || !qc->err_mask)
continue;
@@ -3802,7 +3805,7 @@ void ata_eh_finish(struct ata_port *ap)
/* retry or finish qcs */
ata_qc_for_each_raw(ap, qc, tag) {
- if (!(qc->flags & ATA_QCFLAG_FAILED))
+ if (!(qc->flags & ATA_QCFLAG_EH))
continue;
if (qc->err_mask) {
diff --git a/drivers/ata/libata-sata.c b/drivers/ata/libata-sata.c
index 18ef14e749a0..f3e7396e3191 100644
--- a/drivers/ata/libata-sata.c
+++ b/drivers/ata/libata-sata.c
@@ -655,6 +655,9 @@ int ata_qc_complete_multiple(struct ata_port *ap, u64 qc_active)
return -EINVAL;
}
+ if (ap->ops->qc_ncq_fill_rtf)
+ ap->ops->qc_ncq_fill_rtf(ap, done_mask);
+
while (done_mask) {
struct ata_queued_cmd *qc;
unsigned int tag = __ffs64(done_mask);
@@ -1429,7 +1432,7 @@ void ata_eh_analyze_ncq_error(struct ata_link *link)
/* has LLDD analyzed already? */
ata_qc_for_each_raw(ap, qc, tag) {
- if (!(qc->flags & ATA_QCFLAG_FAILED))
+ if (!(qc->flags & ATA_QCFLAG_EH))
continue;
if (qc->err_mask)
@@ -1477,7 +1480,7 @@ void ata_eh_analyze_ncq_error(struct ata_link *link)
}
ata_qc_for_each_raw(ap, qc, tag) {
- if (!(qc->flags & ATA_QCFLAG_FAILED) ||
+ if (!(qc->flags & ATA_QCFLAG_EH) ||
ata_dev_phys_link(qc->dev) != link)
continue;
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index cbb3a7a50816..e093c7a7deeb 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -383,8 +383,12 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
u8 scsi_cmd[MAX_COMMAND_SIZE];
u8 args[4], *argbuf = NULL;
int argsize = 0;
- enum dma_data_direction data_dir;
struct scsi_sense_hdr sshdr;
+ const struct scsi_exec_args exec_args = {
+ .sshdr = &sshdr,
+ .sense = sensebuf,
+ .sense_len = sizeof(sensebuf),
+ };
int cmd_result;
if (arg == NULL)
@@ -407,11 +411,9 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
scsi_cmd[1] = (4 << 1); /* PIO Data-in */
scsi_cmd[2] = 0x0e; /* no off.line or cc, read from dev,
block count in sector count field */
- data_dir = DMA_FROM_DEVICE;
} else {
scsi_cmd[1] = (3 << 1); /* Non-data */
scsi_cmd[2] = 0x20; /* cc but no off.line or data xfer */
- data_dir = DMA_NONE;
}
scsi_cmd[0] = ATA_16;
@@ -429,9 +431,8 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
/* Good values for timeout and retries? Values below
from scsi_ioctl_send_command() for default case... */
- cmd_result = scsi_execute(scsidev, scsi_cmd, data_dir, argbuf, argsize,
- sensebuf, &sshdr, (10*HZ), 5, 0, 0, NULL);
-
+ cmd_result = scsi_execute_cmd(scsidev, scsi_cmd, REQ_OP_DRV_IN, argbuf,
+ argsize, 10 * HZ, 5, &exec_args);
if (cmd_result < 0) {
rc = cmd_result;
goto error;
@@ -491,6 +492,11 @@ int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg)
u8 args[7];
struct scsi_sense_hdr sshdr;
int cmd_result;
+ const struct scsi_exec_args exec_args = {
+ .sshdr = &sshdr,
+ .sense = sensebuf,
+ .sense_len = sizeof(sensebuf),
+ };
if (arg == NULL)
return -EINVAL;
@@ -513,9 +519,8 @@ int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg)
/* Good values for timeout and retries? Values below
from scsi_ioctl_send_command() for default case... */
- cmd_result = scsi_execute(scsidev, scsi_cmd, DMA_NONE, NULL, 0,
- sensebuf, &sshdr, (10*HZ), 5, 0, 0, NULL);
-
+ cmd_result = scsi_execute_cmd(scsidev, scsi_cmd, REQ_OP_DRV_IN, NULL,
+ 0, 10 * HZ, 5, &exec_args);
if (cmd_result < 0) {
rc = cmd_result;
goto error;
@@ -1654,7 +1659,8 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
struct ata_port *ap = qc->ap;
struct scsi_cmnd *cmd = qc->scsicmd;
u8 *cdb = cmd->cmnd;
- int need_sense = (qc->err_mask != 0);
+ int need_sense = (qc->err_mask != 0) &&
+ !(qc->flags & ATA_QCFLAG_SENSE_VALID);
/* For ATA pass thru (SAT) commands, generate a sense block if
* user mandated it or if there's an error. Note that if we
@@ -1668,12 +1674,11 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
if (((cdb[0] == ATA_16) || (cdb[0] == ATA_12)) &&
((cdb[2] & 0x20) || need_sense))
ata_gen_passthru_sense(qc);
- else if (qc->flags & ATA_QCFLAG_SENSE_VALID)
- cmd->result = SAM_STAT_CHECK_CONDITION;
else if (need_sense)
ata_gen_ata_sense(qc);
else
- cmd->result = SAM_STAT_GOOD;
+ /* Keep the SCSI ML and status byte, clear host byte. */
+ cmd->result &= 0x0000ffff;
if (need_sense && !ap->ops->error_handler)
ata_dump_status(ap, &qc->result_tf);
@@ -2240,30 +2245,6 @@ static unsigned int ata_msense_rw_recovery(u8 *buf, bool changeable)
return sizeof(def_rw_recovery_mpage);
}
-/*
- * We can turn this into a real blacklist if it's needed, for now just
- * blacklist any Maxtor BANC1G10 revision firmware
- */
-static int ata_dev_supports_fua(u16 *id)
-{
- unsigned char model[ATA_ID_PROD_LEN + 1], fw[ATA_ID_FW_REV_LEN + 1];
-
- if (!libata_fua)
- return 0;
- if (!ata_id_has_fua(id))
- return 0;
-
- ata_id_c_string(id, model, ATA_ID_PROD, sizeof(model));
- ata_id_c_string(id, fw, ATA_ID_FW_REV, sizeof(fw));
-
- if (strcmp(model, "Maxtor"))
- return 1;
- if (strcmp(fw, "BANC1G10"))
- return 1;
-
- return 0; /* blacklisted */
-}
-
/**
* ata_scsiop_mode_sense - Simulate MODE SENSE 6, 10 commands
* @args: device IDENTIFY data / SCSI command of interest.
@@ -2287,7 +2268,7 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf)
};
u8 pg, spg;
unsigned int ebd, page_control, six_byte;
- u8 dpofua, bp = 0xff;
+ u8 dpofua = 0, bp = 0xff;
u16 fp;
six_byte = (scsicmd[0] == MODE_SENSE);
@@ -2350,9 +2331,7 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf)
goto invalid_fld;
}
- dpofua = 0;
- if (ata_dev_supports_fua(args->id) && (dev->flags & ATA_DFLAG_LBA48) &&
- (!(dev->flags & ATA_DFLAG_PIO) || dev->multi_count))
+ if (dev->flags & ATA_DFLAG_FUA)
dpofua = 1 << 4;
if (six_byte) {
@@ -3266,11 +3245,12 @@ static unsigned int ata_scsiop_maint_in(struct ata_scsi_args *args, u8 *rbuf)
u8 supported = 0;
unsigned int err = 0;
- if (cdb[2] != 1) {
+ if (cdb[2] != 1 && cdb[2] != 3) {
ata_dev_warn(dev, "invalid command format %d\n", cdb[2]);
err = 2;
goto out;
}
+
switch (cdb[3]) {
case INQUIRY:
case MODE_SENSE:
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index 153f49e00713..cd82d3b5ed14 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -1377,14 +1377,10 @@ EXPORT_SYMBOL_GPL(ata_sff_qc_issue);
*
* LOCKING:
* spin_lock_irqsave(host lock)
- *
- * RETURNS:
- * true indicating that result TF is successfully filled.
*/
-bool ata_sff_qc_fill_rtf(struct ata_queued_cmd *qc)
+void ata_sff_qc_fill_rtf(struct ata_queued_cmd *qc)
{
qc->ap->ops->sff_tf_read(qc->ap, &qc->result_tf);
- return true;
}
EXPORT_SYMBOL_GPL(ata_sff_qc_fill_rtf);
@@ -2073,7 +2069,7 @@ void ata_sff_error_handler(struct ata_port *ap)
unsigned long flags;
qc = __ata_qc_from_tag(ap, ap->link.active_tag);
- if (qc && !(qc->flags & ATA_QCFLAG_FAILED))
+ if (qc && !(qc->flags & ATA_QCFLAG_EH))
qc = NULL;
spin_lock_irqsave(ap->lock, flags);
@@ -2796,7 +2792,7 @@ void ata_bmdma_error_handler(struct ata_port *ap)
bool thaw = false;
qc = __ata_qc_from_tag(ap, ap->link.active_tag);
- if (qc && !(qc->flags & ATA_QCFLAG_FAILED))
+ if (qc && !(qc->flags & ATA_QCFLAG_EH))
qc = NULL;
/* reset PIO HSM and stop DMA engine */
diff --git a/drivers/ata/libata-trace.c b/drivers/ata/libata-trace.c
index e0e4d0d5a100..9b5363fd0ab0 100644
--- a/drivers/ata/libata-trace.c
+++ b/drivers/ata/libata-trace.c
@@ -142,7 +142,7 @@ libata_trace_parse_qc_flags(struct trace_seq *p, unsigned int qc_flags)
trace_seq_printf(p, "QUIET ");
if (qc_flags & ATA_QCFLAG_RETRY)
trace_seq_printf(p, "RETRY ");
- if (qc_flags & ATA_QCFLAG_FAILED)
+ if (qc_flags & ATA_QCFLAG_EH)
trace_seq_printf(p, "FAILED ");
if (qc_flags & ATA_QCFLAG_SENSE_VALID)
trace_seq_printf(p, "SENSE_VALID ");
diff --git a/drivers/ata/pata_parport/Kconfig b/drivers/ata/pata_parport/Kconfig
new file mode 100644
index 000000000000..0893a13e7979
--- /dev/null
+++ b/drivers/ata/pata_parport/Kconfig
@@ -0,0 +1,141 @@
+# SPDX-License-Identifier: GPL-2.0
+
+comment "Parallel IDE protocol modules"
+ depends on PATA_PARPORT
+
+config PATA_PARPORT_ATEN
+ tristate "ATEN EH-100 protocol"
+ depends on PATA_PARPORT
+ help
+ This option enables support for the ATEN EH-100 parallel port IDE
+ protocol. This protocol is used in some inexpensive low performance
+ parallel port kits made in Hong Kong.
+
+config PATA_PARPORT_BPCK
+ tristate "MicroSolutions backpack (Series 5) protocol"
+ depends on PATA_PARPORT
+ help
+ This option enables support for the Micro Solutions BACKPACK
+ parallel port Series 5 IDE protocol. (Most BACKPACK drives made
+ before 1999 were Series 5) Series 5 drives will NOT always have the
+ Series noted on the bottom of the drive. Series 6 drivers will.
+
+ In other words, if your BACKPACK drive doesn't say "Series 6" on the
+ bottom, enable this option.
+
+config PATA_PARPORT_BPCK6
+ tristate "MicroSolutions backpack (Series 6) protocol"
+ depends on (PATA_PARPORT) && !64BIT
+ help
+ This option enables support for the Micro Solutions BACKPACK
+ parallel port Series 6 IDE protocol. (Most BACKPACK drives made
+ after 1999 were Series 6) Series 6 drives will have the Series noted
+ on the bottom of the drive. Series 5 drivers don't always have it
+ noted.
+
+ In other words, if your BACKPACK drive says "Series 6" on the
+ bottom, enable this option.
+
+config PATA_PARPORT_COMM
+ tristate "DataStor Commuter protocol"
+ depends on PATA_PARPORT
+ help
+ This option enables support for the Commuter parallel port IDE
+ protocol from DataStor.
+
+config PATA_PARPORT_DSTR
+ tristate "DataStor EP-2000 protocol"
+ depends on PATA_PARPORT
+ help
+ This option enables support for the EP-2000 parallel port IDE
+ protocol from DataStor
+
+config PATA_PARPORT_FIT2
+ tristate "FIT TD-2000 protocol"
+ depends on PATA_PARPORT
+ help
+ This option enables support for the TD-2000 parallel port IDE
+ protocol from Fidelity International Technology. This is a simple
+ (low speed) adapter that is used in some portable hard drives.
+
+config PATA_PARPORT_FIT3
+ tristate "FIT TD-3000 protocol"
+ depends on PATA_PARPORT
+ help
+ This option enables support for the TD-3000 parallel port IDE
+ protocol from Fidelity International Technology. This protocol is
+ used in newer models of their portable disk, CD-ROM and PD/CD
+ devices.
+
+config PATA_PARPORT_EPAT
+ tristate "Shuttle EPAT/EPEZ protocol"
+ depends on PATA_PARPORT
+ help
+ This option enables support for the EPAT parallel port IDE protocol.
+ EPAT is a parallel port IDE adapter manufactured by Shuttle
+ Technology and widely used in devices from major vendors such as
+ Hewlett-Packard, SyQuest, Imation and Avatar.
+
+config PATA_PARPORT_EPATC8
+ bool "Support c7/c8 chips"
+ depends on PATA_PARPORT_EPAT
+ help
+ This option enables support for the newer Shuttle EP1284 (aka c7 and
+ c8) chip. You need this if you are using any recent Imation SuperDisk
+ (LS-120) drive.
+
+config PATA_PARPORT_EPIA
+ tristate "Shuttle EPIA protocol"
+ depends on PATA_PARPORT
+ help
+ This option enables support for the (obsolete) EPIA parallel port
+ IDE protocol from Shuttle Technology. This adapter can still be
+ found in some no-name kits.
+
+config PATA_PARPORT_FRIQ
+ tristate "Freecom IQ ASIC-2 protocol"
+ depends on PATA_PARPORT
+ help
+ This option enables support for version 2 of the Freecom IQ parallel
+ port IDE adapter. This adapter is used by the Maxell Superdisk
+ drive.
+
+config PATA_PARPORT_FRPW
+ tristate "FreeCom power protocol"
+ depends on PATA_PARPORT
+ help
+ This option enables support for the Freecom power parallel port IDE
+ protocol.
+
+config PATA_PARPORT_KBIC
+ tristate "KingByte KBIC-951A/971A protocols"
+ depends on PATA_PARPORT
+ help
+ This option enables support for the KBIC-951A and KBIC-971A parallel
+ port IDE protocols from KingByte Information Corp. KingByte's
+ adapters appear in many no-name portable disk and CD-ROM products,
+ especially in Europe.
+
+config PATA_PARPORT_KTTI
+ tristate "KT PHd protocol"
+ depends on PATA_PARPORT
+ help
+ This option enables support for the "PHd" parallel port IDE protocol
+ from KT Technology. This is a simple (low speed) adapter that is
+ used in some 2.5" portable hard drives.
+
+config PATA_PARPORT_ON20
+ tristate "OnSpec 90c20 protocol"
+ depends on PATA_PARPORT
+ help
+ This option enables support for the (obsolete) 90c20 parallel port
+ IDE protocol from OnSpec (often marketed under the ValuStore brand
+ name).
+
+config PATA_PARPORT_ON26
+ tristate "OnSpec 90c26 protocol"
+ depends on PATA_PARPORT
+ help
+ This option enables support for the 90c26 parallel port IDE protocol
+ from OnSpec Electronics (often marketed under the ValuStore brand
+ name).
diff --git a/drivers/ata/pata_parport/Makefile b/drivers/ata/pata_parport/Makefile
new file mode 100644
index 000000000000..0932c8d55b91
--- /dev/null
+++ b/drivers/ata/pata_parport/Makefile
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_PATA_PARPORT) += pata_parport.o
+
+obj-$(CONFIG_PATA_PARPORT_ATEN) += aten.o
+obj-$(CONFIG_PATA_PARPORT_BPCK) += bpck.o
+obj-$(CONFIG_PATA_PARPORT_COMM) += comm.o
+obj-$(CONFIG_PATA_PARPORT_DSTR) += dstr.o
+obj-$(CONFIG_PATA_PARPORT_KBIC) += kbic.o
+obj-$(CONFIG_PATA_PARPORT_EPAT) += epat.o
+obj-$(CONFIG_PATA_PARPORT_EPIA) += epia.o
+obj-$(CONFIG_PATA_PARPORT_FRPW) += frpw.o
+obj-$(CONFIG_PATA_PARPORT_FRIQ) += friq.o
+obj-$(CONFIG_PATA_PARPORT_FIT2) += fit2.o
+obj-$(CONFIG_PATA_PARPORT_FIT3) += fit3.o
+obj-$(CONFIG_PATA_PARPORT_ON20) += on20.o
+obj-$(CONFIG_PATA_PARPORT_ON26) += on26.o
+obj-$(CONFIG_PATA_PARPORT_KTTI) += ktti.o
+obj-$(CONFIG_PATA_PARPORT_BPCK6) += bpck6.o
diff --git a/drivers/block/paride/aten.c b/drivers/ata/pata_parport/aten.c
index 2695465568ad..b66508bedbd0 100644
--- a/drivers/block/paride/aten.c
+++ b/drivers/ata/pata_parport/aten.c
@@ -25,7 +25,7 @@
#include <linux/types.h>
#include <asm/io.h>
-#include "paride.h"
+#include <linux/pata_parport.h>
#define j44(a,b) ((((a>>4)&0x0f)|(b&0xf0))^0x88)
diff --git a/drivers/block/paride/bpck.c b/drivers/ata/pata_parport/bpck.c
index d880a9465e9b..5fb3cf9ba11d 100644
--- a/drivers/block/paride/bpck.c
+++ b/drivers/ata/pata_parport/bpck.c
@@ -24,7 +24,7 @@
#include <linux/wait.h>
#include <asm/io.h>
-#include "paride.h"
+#include <linux/pata_parport.h>
#undef r2
#undef w2
diff --git a/drivers/block/paride/bpck6.c b/drivers/ata/pata_parport/bpck6.c
index ec64e7f5d1ce..d897e2a28efe 100644
--- a/drivers/block/paride/bpck6.c
+++ b/drivers/ata/pata_parport/bpck6.c
@@ -31,7 +31,7 @@
#include <linux/parport.h>
#include "ppc6lnx.c"
-#include "paride.h"
+#include <linux/pata_parport.h>
/* PARAMETERS */
static bool verbose; /* set this to 1 to see debugging messages and whatnot */
diff --git a/drivers/block/paride/comm.c b/drivers/ata/pata_parport/comm.c
index 9bcd35495323..1775e7ed9336 100644
--- a/drivers/block/paride/comm.c
+++ b/drivers/ata/pata_parport/comm.c
@@ -24,7 +24,7 @@
#include <linux/wait.h>
#include <asm/io.h>
-#include "paride.h"
+#include <linux/pata_parport.h>
/* mode codes: 0 nybble reads, 8-bit writes
1 8-bit reads and writes
diff --git a/drivers/block/paride/dstr.c b/drivers/ata/pata_parport/dstr.c
index accc5c777cbb..edf414d186a6 100644
--- a/drivers/block/paride/dstr.c
+++ b/drivers/ata/pata_parport/dstr.c
@@ -23,7 +23,7 @@
#include <linux/wait.h>
#include <asm/io.h>
-#include "paride.h"
+#include <linux/pata_parport.h>
/* mode codes: 0 nybble reads, 8-bit writes
1 8-bit reads and writes
diff --git a/drivers/block/paride/epat.c b/drivers/ata/pata_parport/epat.c
index 1bcdff77322e..6ce2dee7657f 100644
--- a/drivers/block/paride/epat.c
+++ b/drivers/ata/pata_parport/epat.c
@@ -26,7 +26,7 @@
#include <linux/wait.h>
#include <asm/io.h>
-#include "paride.h"
+#include <linux/pata_parport.h>
#define j44(a,b) (((a>>4)&0x0f)+(b&0xf0))
#define j53(a,b) (((a>>3)&0x1f)+((b<<4)&0xe0))
diff --git a/drivers/block/paride/epia.c b/drivers/ata/pata_parport/epia.c
index fb0e782d055e..417d5a3c7f72 100644
--- a/drivers/block/paride/epia.c
+++ b/drivers/ata/pata_parport/epia.c
@@ -27,7 +27,7 @@
#include <linux/wait.h>
#include <asm/io.h>
-#include "paride.h"
+#include <linux/pata_parport.h>
/* mode codes: 0 nybble reads on port 1, 8-bit writes
1 5/3 reads on ports 1 & 2, 8-bit writes
diff --git a/drivers/block/paride/fit2.c b/drivers/ata/pata_parport/fit2.c
index 381283753ae4..3c7a1069b026 100644
--- a/drivers/block/paride/fit2.c
+++ b/drivers/ata/pata_parport/fit2.c
@@ -23,7 +23,7 @@
#include <linux/wait.h>
#include <asm/io.h>
-#include "paride.h"
+#include <linux/pata_parport.h>
#define j44(a,b) (((a>>4)&0x0f)|(b&0xf0))
diff --git a/drivers/block/paride/fit3.c b/drivers/ata/pata_parport/fit3.c
index 275d269458eb..cd95f4f0edc2 100644
--- a/drivers/block/paride/fit3.c
+++ b/drivers/ata/pata_parport/fit3.c
@@ -27,7 +27,7 @@
#include <linux/wait.h>
#include <asm/io.h>
-#include "paride.h"
+#include <linux/pata_parport.h>
#define j44(a,b) (((a>>3)&0x0f)|((b<<1)&0xf0))
diff --git a/drivers/block/paride/friq.c b/drivers/ata/pata_parport/friq.c
index 4f2ba244689b..da1d0cb016d6 100644
--- a/drivers/block/paride/friq.c
+++ b/drivers/ata/pata_parport/friq.c
@@ -35,7 +35,7 @@
#include <linux/wait.h>
#include <asm/io.h>
-#include "paride.h"
+#include <linux/pata_parport.h>
#define CMD(x) w2(4);w0(0xff);w0(0xff);w0(0x73);w0(0x73);\
w0(0xc9);w0(0xc9);w0(0x26);w0(0x26);w0(x);w0(x);
diff --git a/drivers/block/paride/frpw.c b/drivers/ata/pata_parport/frpw.c
index c3cde364603a..7bc8fa16d5d8 100644
--- a/drivers/block/paride/frpw.c
+++ b/drivers/ata/pata_parport/frpw.c
@@ -33,7 +33,7 @@
#include <linux/wait.h>
#include <asm/io.h>
-#include "paride.h"
+#include <linux/pata_parport.h>
#define cec4 w2(0xc);w2(0xe);w2(0xe);w2(0xc);w2(4);w2(4);w2(4);
#define j44(l,h) (((l>>4)&0x0f)|(h&0xf0))
diff --git a/drivers/block/paride/kbic.c b/drivers/ata/pata_parport/kbic.c
index 35999c415ee3..f0960eb68635 100644
--- a/drivers/block/paride/kbic.c
+++ b/drivers/ata/pata_parport/kbic.c
@@ -28,7 +28,7 @@
#include <linux/wait.h>
#include <asm/io.h>
-#include "paride.h"
+#include <linux/pata_parport.h>
#define r12w() (delay_p,inw(pi->port+1)&0xffff)
diff --git a/drivers/block/paride/ktti.c b/drivers/ata/pata_parport/ktti.c
index 117ab0e8ccf0..fc4f707fed1f 100644
--- a/drivers/block/paride/ktti.c
+++ b/drivers/ata/pata_parport/ktti.c
@@ -19,7 +19,7 @@
#include <linux/wait.h>
#include <asm/io.h>
-#include "paride.h"
+#include <linux/pata_parport.h>
#define j44(a,b) (((a>>4)&0x0f)|(b&0xf0))
diff --git a/drivers/block/paride/on20.c b/drivers/ata/pata_parport/on20.c
index 0173697a1a4d..995fc41e3122 100644
--- a/drivers/block/paride/on20.c
+++ b/drivers/ata/pata_parport/on20.c
@@ -22,7 +22,7 @@
#include <linux/wait.h>
#include <asm/io.h>
-#include "paride.h"
+#include <linux/pata_parport.h>
#define op(f) w2(4);w0(f);w2(5);w2(0xd);w2(5);w2(0xd);w2(5);w2(4);
#define vl(v) w2(4);w0(v);w2(5);w2(7);w2(5);w2(4);
diff --git a/drivers/block/paride/on26.c b/drivers/ata/pata_parport/on26.c
index 95ba256921f2..35f1c481a782 100644
--- a/drivers/block/paride/on26.c
+++ b/drivers/ata/pata_parport/on26.c
@@ -26,7 +26,7 @@
#include <linux/wait.h>
#include <asm/io.h>
-#include "paride.h"
+#include <linux/pata_parport.h>
/* mode codes: 0 nybble reads, 8-bit writes
1 8-bit reads and writes
diff --git a/drivers/ata/pata_parport/pata_parport.c b/drivers/ata/pata_parport/pata_parport.c
new file mode 100644
index 000000000000..294a266a0dda
--- /dev/null
+++ b/drivers/ata/pata_parport/pata_parport.c
@@ -0,0 +1,761 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2023 Ondrej Zary
+ * based on paride.c by Grant R. Guenther <grant@torque.net>
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/parport.h>
+#include <linux/pata_parport.h>
+
+#define DRV_NAME "pata_parport"
+
+static DEFINE_IDR(parport_list);
+static DEFINE_IDR(protocols);
+static DEFINE_IDA(pata_parport_bus_dev_ids);
+static DEFINE_MUTEX(pi_mutex);
+
+static bool probe = true;
+module_param(probe, bool, 0644);
+MODULE_PARM_DESC(probe, "Enable automatic device probing (0=off, 1=on [default])");
+
+/*
+ * libata drivers cannot sleep so this driver claims parport before activating
+ * the ata host and keeps it claimed (and protocol connected) until the ata
+ * host is removed. Unfortunately, this means that you cannot use any chained
+ * devices (neither other pata_parport devices nor a printer).
+ */
+static void pi_connect(struct pi_adapter *pi)
+{
+ parport_claim_or_block(pi->pardev);
+ pi->proto->connect(pi);
+}
+
+static void pi_disconnect(struct pi_adapter *pi)
+{
+ pi->proto->disconnect(pi);
+ parport_release(pi->pardev);
+}
+
+static void pata_parport_dev_select(struct ata_port *ap, unsigned int device)
+{
+ struct pi_adapter *pi = ap->host->private_data;
+ u8 tmp;
+
+ if (device == 0)
+ tmp = ATA_DEVICE_OBS;
+ else
+ tmp = ATA_DEVICE_OBS | ATA_DEV1;
+
+ pi->proto->write_regr(pi, 0, ATA_REG_DEVICE, tmp);
+ ata_sff_pause(ap);
+}
+
+static bool pata_parport_devchk(struct ata_port *ap, unsigned int device)
+{
+ struct pi_adapter *pi = ap->host->private_data;
+ u8 nsect, lbal;
+
+ pata_parport_dev_select(ap, device);
+
+ pi->proto->write_regr(pi, 0, ATA_REG_NSECT, 0x55);
+ pi->proto->write_regr(pi, 0, ATA_REG_LBAL, 0xaa);
+
+ pi->proto->write_regr(pi, 0, ATA_REG_NSECT, 0xaa);
+ pi->proto->write_regr(pi, 0, ATA_REG_LBAL, 0x55);
+
+ pi->proto->write_regr(pi, 0, ATA_REG_NSECT, 055);
+ pi->proto->write_regr(pi, 0, ATA_REG_LBAL, 0xaa);
+
+ nsect = pi->proto->read_regr(pi, 0, ATA_REG_NSECT);
+ lbal = pi->proto->read_regr(pi, 0, ATA_REG_LBAL);
+
+ return (nsect == 0x55) && (lbal == 0xaa);
+}
+
+static int pata_parport_bus_softreset(struct ata_port *ap, unsigned int devmask,
+ unsigned long deadline)
+{
+ struct pi_adapter *pi = ap->host->private_data;
+
+ /* software reset. causes dev0 to be selected */
+ pi->proto->write_regr(pi, 1, 6, ap->ctl);
+ udelay(20);
+ pi->proto->write_regr(pi, 1, 6, ap->ctl | ATA_SRST);
+ udelay(20);
+ pi->proto->write_regr(pi, 1, 6, ap->ctl);
+ ap->last_ctl = ap->ctl;
+
+ /* wait the port to become ready */
+ return ata_sff_wait_after_reset(&ap->link, devmask, deadline);
+}
+
+static int pata_parport_softreset(struct ata_link *link, unsigned int *classes,
+ unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ unsigned int devmask = 0;
+ int rc;
+ u8 err;
+
+ /* determine if device 0/1 are present */
+ if (pata_parport_devchk(ap, 0))
+ devmask |= (1 << 0);
+ if (pata_parport_devchk(ap, 1))
+ devmask |= (1 << 1);
+
+ /* select device 0 again */
+ pata_parport_dev_select(ap, 0);
+
+ /* issue bus reset */
+ rc = pata_parport_bus_softreset(ap, devmask, deadline);
+ if (rc && rc != -ENODEV) {
+ ata_link_err(link, "SRST failed (errno=%d)\n", rc);
+ return rc;
+ }
+
+ /* determine by signature whether we have ATA or ATAPI devices */
+ classes[0] = ata_sff_dev_classify(&link->device[0],
+ devmask & (1 << 0), &err);
+ if (err != 0x81)
+ classes[1] = ata_sff_dev_classify(&link->device[1],
+ devmask & (1 << 1), &err);
+
+ return 0;
+}
+
+static u8 pata_parport_check_status(struct ata_port *ap)
+{
+ struct pi_adapter *pi = ap->host->private_data;
+
+ return pi->proto->read_regr(pi, 0, ATA_REG_STATUS);
+}
+
+static u8 pata_parport_check_altstatus(struct ata_port *ap)
+{
+ struct pi_adapter *pi = ap->host->private_data;
+
+ return pi->proto->read_regr(pi, 1, 6);
+}
+
+static void pata_parport_tf_load(struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ struct pi_adapter *pi = ap->host->private_data;
+
+ if (tf->ctl != ap->last_ctl) {
+ pi->proto->write_regr(pi, 1, 6, tf->ctl);
+ ap->last_ctl = tf->ctl;
+ ata_wait_idle(ap);
+ }
+
+ if (tf->flags & ATA_TFLAG_ISADDR) {
+ if (tf->flags & ATA_TFLAG_LBA48) {
+ pi->proto->write_regr(pi, 0, ATA_REG_FEATURE,
+ tf->hob_feature);
+ pi->proto->write_regr(pi, 0, ATA_REG_NSECT,
+ tf->hob_nsect);
+ pi->proto->write_regr(pi, 0, ATA_REG_LBAL,
+ tf->hob_lbal);
+ pi->proto->write_regr(pi, 0, ATA_REG_LBAM,
+ tf->hob_lbam);
+ pi->proto->write_regr(pi, 0, ATA_REG_LBAH,
+ tf->hob_lbah);
+ }
+ pi->proto->write_regr(pi, 0, ATA_REG_FEATURE, tf->feature);
+ pi->proto->write_regr(pi, 0, ATA_REG_NSECT, tf->nsect);
+ pi->proto->write_regr(pi, 0, ATA_REG_LBAL, tf->lbal);
+ pi->proto->write_regr(pi, 0, ATA_REG_LBAM, tf->lbam);
+ pi->proto->write_regr(pi, 0, ATA_REG_LBAH, tf->lbah);
+ }
+
+ if (tf->flags & ATA_TFLAG_DEVICE)
+ pi->proto->write_regr(pi, 0, ATA_REG_DEVICE, tf->device);
+
+ ata_wait_idle(ap);
+}
+
+static void pata_parport_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ struct pi_adapter *pi = ap->host->private_data;
+
+ tf->status = pi->proto->read_regr(pi, 0, ATA_REG_STATUS);
+ tf->error = pi->proto->read_regr(pi, 0, ATA_REG_ERR);
+ tf->nsect = pi->proto->read_regr(pi, 0, ATA_REG_NSECT);
+ tf->lbal = pi->proto->read_regr(pi, 0, ATA_REG_LBAL);
+ tf->lbam = pi->proto->read_regr(pi, 0, ATA_REG_LBAM);
+ tf->lbah = pi->proto->read_regr(pi, 0, ATA_REG_LBAH);
+ tf->device = pi->proto->read_regr(pi, 0, ATA_REG_DEVICE);
+
+ if (tf->flags & ATA_TFLAG_LBA48) {
+ pi->proto->write_regr(pi, 1, 6, tf->ctl | ATA_HOB);
+ tf->hob_feature = pi->proto->read_regr(pi, 0, ATA_REG_ERR);
+ tf->hob_nsect = pi->proto->read_regr(pi, 0, ATA_REG_NSECT);
+ tf->hob_lbal = pi->proto->read_regr(pi, 0, ATA_REG_LBAL);
+ tf->hob_lbam = pi->proto->read_regr(pi, 0, ATA_REG_LBAM);
+ tf->hob_lbah = pi->proto->read_regr(pi, 0, ATA_REG_LBAH);
+ pi->proto->write_regr(pi, 1, 6, tf->ctl);
+ ap->last_ctl = tf->ctl;
+ }
+}
+
+static void pata_parport_exec_command(struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ struct pi_adapter *pi = ap->host->private_data;
+
+ pi->proto->write_regr(pi, 0, ATA_REG_CMD, tf->command);
+ ata_sff_pause(ap);
+}
+
+static unsigned int pata_parport_data_xfer(struct ata_queued_cmd *qc,
+ unsigned char *buf, unsigned int buflen, int rw)
+{
+ struct ata_port *ap = qc->dev->link->ap;
+ struct pi_adapter *pi = ap->host->private_data;
+
+ if (rw == READ)
+ pi->proto->read_block(pi, buf, buflen);
+ else
+ pi->proto->write_block(pi, buf, buflen);
+
+ return buflen;
+}
+
+static void pata_parport_drain_fifo(struct ata_queued_cmd *qc)
+{
+ int count;
+ struct ata_port *ap;
+ struct pi_adapter *pi;
+ char junk[2];
+
+ /* We only need to flush incoming data when a command was running */
+ if (qc == NULL || qc->dma_dir == DMA_TO_DEVICE)
+ return;
+
+ ap = qc->ap;
+ pi = ap->host->private_data;
+ /* Drain up to 64K of data before we give up this recovery method */
+ for (count = 0; (pata_parport_check_status(ap) & ATA_DRQ)
+ && count < 65536; count += 2) {
+ pi->proto->read_block(pi, junk, 2);
+ }
+
+ if (count)
+ ata_port_dbg(ap, "drained %d bytes to clear DRQ\n", count);
+}
+
+static struct ata_port_operations pata_parport_port_ops = {
+ .inherits = &ata_sff_port_ops,
+
+ .softreset = pata_parport_softreset,
+ .hardreset = NULL,
+
+ .sff_dev_select = pata_parport_dev_select,
+ .sff_check_status = pata_parport_check_status,
+ .sff_check_altstatus = pata_parport_check_altstatus,
+ .sff_tf_load = pata_parport_tf_load,
+ .sff_tf_read = pata_parport_tf_read,
+ .sff_exec_command = pata_parport_exec_command,
+ .sff_data_xfer = pata_parport_data_xfer,
+ .sff_drain_fifo = pata_parport_drain_fifo,
+};
+
+static const struct ata_port_info pata_parport_port_info = {
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_PIO_POLLING,
+ .pio_mask = ATA_PIO0,
+ /* No DMA */
+ .port_ops = &pata_parport_port_ops,
+};
+
+static void pi_release(struct pi_adapter *pi)
+{
+ parport_unregister_device(pi->pardev);
+ if (pi->proto->release_proto)
+ pi->proto->release_proto(pi);
+ module_put(pi->proto->owner);
+}
+
+static int default_test_proto(struct pi_adapter *pi, char *scratch)
+{
+ int j, k;
+ int e[2] = { 0, 0 };
+
+ pi->proto->connect(pi);
+
+ for (j = 0; j < 2; j++) {
+ pi->proto->write_regr(pi, 0, 6, 0xa0 + j * 0x10);
+ for (k = 0; k < 256; k++) {
+ pi->proto->write_regr(pi, 0, 2, k ^ 0xaa);
+ pi->proto->write_regr(pi, 0, 3, k ^ 0x55);
+ if (pi->proto->read_regr(pi, 0, 2) != (k ^ 0xaa))
+ e[j]++;
+ }
+ }
+ pi->proto->disconnect(pi);
+
+ dev_dbg(&pi->dev, "%s: port 0x%x, mode %d, test=(%d,%d)\n",
+ pi->proto->name, pi->port, pi->mode, e[0], e[1]);
+
+ return e[0] && e[1]; /* not here if both > 0 */
+}
+
+static int pi_test_proto(struct pi_adapter *pi, char *scratch)
+{
+ int res;
+
+ parport_claim_or_block(pi->pardev);
+ if (pi->proto->test_proto)
+ res = pi->proto->test_proto(pi, scratch, 1);
+ else
+ res = default_test_proto(pi, scratch);
+ parport_release(pi->pardev);
+
+ return res;
+}
+
+static bool pi_probe_mode(struct pi_adapter *pi, int max, char *scratch)
+{
+ int best, range;
+
+ if (pi->mode != -1) {
+ if (pi->mode >= max)
+ return false;
+ range = 3;
+ if (pi->mode >= pi->proto->epp_first)
+ range = 8;
+ if (range == 8 && pi->port % 8)
+ return false;
+ return !pi_test_proto(pi, scratch);
+ }
+ best = -1;
+ for (pi->mode = 0; pi->mode < max; pi->mode++) {
+ range = 3;
+ if (pi->mode >= pi->proto->epp_first)
+ range = 8;
+ if (range == 8 && pi->port % 8)
+ break;
+ if (!pi_test_proto(pi, scratch))
+ best = pi->mode;
+ }
+ pi->mode = best;
+ return best > -1;
+}
+
+static bool pi_probe_unit(struct pi_adapter *pi, int unit, char *scratch)
+{
+ int max, s, e;
+
+ s = unit;
+ e = s + 1;
+
+ if (s == -1) {
+ s = 0;
+ e = pi->proto->max_units;
+ }
+
+ if (pi->proto->test_port) {
+ parport_claim_or_block(pi->pardev);
+ max = pi->proto->test_port(pi);
+ parport_release(pi->pardev);
+ } else {
+ max = pi->proto->max_mode;
+ }
+
+ if (pi->proto->probe_unit) {
+ parport_claim_or_block(pi->pardev);
+ for (pi->unit = s; pi->unit < e; pi->unit++) {
+ if (pi->proto->probe_unit(pi)) {
+ parport_release(pi->pardev);
+ return pi_probe_mode(pi, max, scratch);
+ }
+ }
+ parport_release(pi->pardev);
+ return false;
+ }
+
+ return pi_probe_mode(pi, max, scratch);
+}
+
+static void pata_parport_dev_release(struct device *dev)
+{
+ struct pi_adapter *pi = container_of(dev, struct pi_adapter, dev);
+
+ kfree(pi);
+}
+
+static void pata_parport_bus_release(struct device *dev)
+{
+ /* nothing to do here but required to avoid warning on device removal */
+}
+
+static struct bus_type pata_parport_bus_type = {
+ .name = DRV_NAME,
+};
+
+static struct device pata_parport_bus = {
+ .init_name = DRV_NAME,
+ .release = pata_parport_bus_release,
+};
+
+static struct scsi_host_template pata_parport_sht = {
+ PATA_PARPORT_SHT("pata_parport")
+};
+
+struct pi_device_match {
+ struct parport *parport;
+ struct pi_protocol *proto;
+};
+
+static int pi_find_dev(struct device *dev, void *data)
+{
+ struct pi_adapter *pi = container_of(dev, struct pi_adapter, dev);
+ struct pi_device_match *match = data;
+
+ return pi->pardev->port == match->parport && pi->proto == match->proto;
+}
+
+static struct pi_adapter *pi_init_one(struct parport *parport,
+ struct pi_protocol *pr, int mode, int unit, int delay)
+{
+ struct pardev_cb par_cb = { };
+ char scratch[512];
+ const struct ata_port_info *ppi[] = { &pata_parport_port_info };
+ struct ata_host *host;
+ struct pi_adapter *pi;
+ struct pi_device_match match = { .parport = parport, .proto = pr };
+ int id;
+
+ /*
+ * Abort if there's a device already registered on the same parport
+ * using the same protocol.
+ */
+ if (bus_for_each_dev(&pata_parport_bus_type, NULL, &match, pi_find_dev))
+ return NULL;
+
+ pi = kzalloc(sizeof(struct pi_adapter), GFP_KERNEL);
+ if (!pi)
+ return NULL;
+
+ /* set up pi->dev before pi_probe_unit() so it can use dev_printk() */
+ pi->dev.parent = &pata_parport_bus;
+ pi->dev.bus = &pata_parport_bus_type;
+ pi->dev.driver = &pr->driver;
+ pi->dev.release = pata_parport_dev_release;
+ id = ida_alloc(&pata_parport_bus_dev_ids, GFP_KERNEL);
+ if (id < 0)
+ return NULL; /* pata_parport_dev_release will do kfree(pi) */
+ pi->dev.id = id;
+ dev_set_name(&pi->dev, "pata_parport.%u", pi->dev.id);
+ if (device_register(&pi->dev)) {
+ put_device(&pi->dev);
+ goto out_ida_free;
+ }
+
+ pi->proto = pr;
+
+ if (!try_module_get(pi->proto->owner))
+ goto out_unreg_dev;
+ if (pi->proto->init_proto && pi->proto->init_proto(pi) < 0)
+ goto out_module_put;
+
+ pi->delay = (delay == -1) ? pi->proto->default_delay : delay;
+ pi->mode = mode;
+ pi->port = parport->base;
+
+ par_cb.private = pi;
+ pi->pardev = parport_register_dev_model(parport, DRV_NAME, &par_cb,
+ pi->dev.id);
+ if (!pi->pardev)
+ goto out_module_put;
+
+ if (!pi_probe_unit(pi, unit, scratch)) {
+ dev_info(&pi->dev, "Adapter not found\n");
+ goto out_unreg_parport;
+ }
+
+ pi->proto->log_adapter(pi, scratch, 1);
+
+ host = ata_host_alloc_pinfo(&pi->pardev->dev, ppi, 1);
+ if (!host)
+ goto out_unreg_parport;
+ dev_set_drvdata(&pi->dev, host);
+ host->private_data = pi;
+
+ ata_port_desc(host->ports[0], "port %s", pi->pardev->port->name);
+ ata_port_desc(host->ports[0], "protocol %s", pi->proto->name);
+
+ pi_connect(pi);
+ if (ata_host_activate(host, 0, NULL, 0, &pata_parport_sht))
+ goto out_unreg_parport;
+
+ return pi;
+
+out_unreg_parport:
+ pi_disconnect(pi);
+ parport_unregister_device(pi->pardev);
+ if (pi->proto->release_proto)
+ pi->proto->release_proto(pi);
+out_module_put:
+ module_put(pi->proto->owner);
+out_unreg_dev:
+ device_unregister(&pi->dev);
+out_ida_free:
+ ida_free(&pata_parport_bus_dev_ids, pi->dev.id);
+ return NULL;
+}
+
+int pata_parport_register_driver(struct pi_protocol *pr)
+{
+ int error;
+ struct parport *parport;
+ int port_num;
+
+ pr->driver.bus = &pata_parport_bus_type;
+ pr->driver.name = pr->name;
+ error = driver_register(&pr->driver);
+ if (error)
+ return error;
+
+ mutex_lock(&pi_mutex);
+ error = idr_alloc(&protocols, pr, 0, 0, GFP_KERNEL);
+ if (error < 0) {
+ driver_unregister(&pr->driver);
+ mutex_unlock(&pi_mutex);
+ return error;
+ }
+
+ pr_info("pata_parport: protocol %s registered\n", pr->name);
+
+ if (probe) {
+ /* probe all parports using this protocol */
+ idr_for_each_entry(&parport_list, parport, port_num)
+ pi_init_one(parport, pr, -1, 0, -1);
+ }
+ mutex_unlock(&pi_mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pata_parport_register_driver);
+
+void pata_parport_unregister_driver(struct pi_protocol *pr)
+{
+ struct pi_protocol *pr_iter;
+ int id = -1;
+
+ mutex_lock(&pi_mutex);
+ idr_for_each_entry(&protocols, pr_iter, id) {
+ if (pr_iter == pr)
+ break;
+ }
+ idr_remove(&protocols, id);
+ mutex_unlock(&pi_mutex);
+ driver_unregister(&pr->driver);
+}
+EXPORT_SYMBOL_GPL(pata_parport_unregister_driver);
+
+static ssize_t new_device_store(struct bus_type *bus, const char *buf,
+ size_t count)
+{
+ char port[12] = "auto";
+ char protocol[8] = "auto";
+ int mode = -1, unit = -1, delay = -1;
+ struct pi_protocol *pr, *pr_wanted;
+ struct device_driver *drv;
+ struct parport *parport;
+ int port_num, port_wanted, pr_num;
+ bool ok = false;
+
+ if (sscanf(buf, "%11s %7s %d %d %d",
+ port, protocol, &mode, &unit, &delay) < 1)
+ return -EINVAL;
+
+ if (sscanf(port, "parport%u", &port_wanted) < 1) {
+ if (strcmp(port, "auto")) {
+ pr_err("invalid port name %s\n", port);
+ return -EINVAL;
+ }
+ port_wanted = -1;
+ }
+
+ drv = driver_find(protocol, &pata_parport_bus_type);
+ if (!drv) {
+ if (strcmp(protocol, "auto")) {
+ pr_err("protocol %s not found\n", protocol);
+ return -EINVAL;
+ }
+ pr_wanted = NULL;
+ } else {
+ pr_wanted = container_of(drv, struct pi_protocol, driver);
+ }
+
+ mutex_lock(&pi_mutex);
+ /* walk all parports */
+ idr_for_each_entry(&parport_list, parport, port_num) {
+ if (port_num == port_wanted || port_wanted == -1) {
+ parport = parport_find_number(port_num);
+ if (!parport) {
+ pr_err("no such port %s\n", port);
+ mutex_unlock(&pi_mutex);
+ return -ENODEV;
+ }
+ /* walk all protocols */
+ idr_for_each_entry(&protocols, pr, pr_num) {
+ if (pr == pr_wanted || !pr_wanted)
+ if (pi_init_one(parport, pr, mode, unit,
+ delay))
+ ok = true;
+ }
+ parport_put_port(parport);
+ }
+ }
+ mutex_unlock(&pi_mutex);
+ if (!ok)
+ return -ENODEV;
+
+ return count;
+}
+static BUS_ATTR_WO(new_device);
+
+static void pi_remove_one(struct device *dev)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct pi_adapter *pi = host->private_data;
+
+ ata_host_detach(host);
+ pi_disconnect(pi);
+ pi_release(pi);
+ device_unregister(dev);
+ ida_free(&pata_parport_bus_dev_ids, dev->id);
+ /* pata_parport_dev_release will do kfree(pi) */
+}
+
+static ssize_t delete_device_store(struct bus_type *bus, const char *buf,
+ size_t count)
+{
+ struct device *dev;
+
+ mutex_lock(&pi_mutex);
+ dev = bus_find_device_by_name(bus, NULL, buf);
+ if (!dev) {
+ mutex_unlock(&pi_mutex);
+ return -ENODEV;
+ }
+
+ pi_remove_one(dev);
+ mutex_unlock(&pi_mutex);
+
+ return count;
+}
+static BUS_ATTR_WO(delete_device);
+
+static void pata_parport_attach(struct parport *port)
+{
+ struct pi_protocol *pr;
+ int pr_num, id;
+
+ mutex_lock(&pi_mutex);
+ id = idr_alloc(&parport_list, port, port->number, port->number,
+ GFP_KERNEL);
+ if (id < 0) {
+ mutex_unlock(&pi_mutex);
+ return;
+ }
+
+ if (probe) {
+ /* probe this port using all protocols */
+ idr_for_each_entry(&protocols, pr, pr_num)
+ pi_init_one(port, pr, -1, 0, -1);
+ }
+ mutex_unlock(&pi_mutex);
+}
+
+static int pi_remove_port(struct device *dev, void *p)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct pi_adapter *pi = host->private_data;
+
+ if (pi->pardev->port == p)
+ pi_remove_one(dev);
+
+ return 0;
+}
+
+static void pata_parport_detach(struct parport *port)
+{
+ mutex_lock(&pi_mutex);
+ bus_for_each_dev(&pata_parport_bus_type, NULL, port, pi_remove_port);
+ idr_remove(&parport_list, port->number);
+ mutex_unlock(&pi_mutex);
+}
+
+static struct parport_driver pata_parport_driver = {
+ .name = DRV_NAME,
+ .match_port = pata_parport_attach,
+ .detach = pata_parport_detach,
+ .devmodel = true,
+};
+
+static __init int pata_parport_init(void)
+{
+ int error;
+
+ error = bus_register(&pata_parport_bus_type);
+ if (error) {
+ pr_err("failed to register pata_parport bus, error: %d\n", error);
+ return error;
+ }
+
+ error = device_register(&pata_parport_bus);
+ if (error) {
+ pr_err("failed to register pata_parport bus, error: %d\n", error);
+ goto out_unregister_bus;
+ }
+
+ error = bus_create_file(&pata_parport_bus_type, &bus_attr_new_device);
+ if (error) {
+ pr_err("unable to create sysfs file, error: %d\n", error);
+ goto out_unregister_dev;
+ }
+
+ error = bus_create_file(&pata_parport_bus_type, &bus_attr_delete_device);
+ if (error) {
+ pr_err("unable to create sysfs file, error: %d\n", error);
+ goto out_remove_new;
+ }
+
+ error = parport_register_driver(&pata_parport_driver);
+ if (error) {
+ pr_err("unable to register parport driver, error: %d\n", error);
+ goto out_remove_del;
+ }
+
+ return 0;
+
+out_remove_del:
+ bus_remove_file(&pata_parport_bus_type, &bus_attr_delete_device);
+out_remove_new:
+ bus_remove_file(&pata_parport_bus_type, &bus_attr_new_device);
+out_unregister_dev:
+ device_unregister(&pata_parport_bus);
+out_unregister_bus:
+ bus_unregister(&pata_parport_bus_type);
+ return error;
+}
+
+static __exit void pata_parport_exit(void)
+{
+ parport_unregister_driver(&pata_parport_driver);
+ bus_remove_file(&pata_parport_bus_type, &bus_attr_new_device);
+ bus_remove_file(&pata_parport_bus_type, &bus_attr_delete_device);
+ device_unregister(&pata_parport_bus);
+ bus_unregister(&pata_parport_bus_type);
+}
+
+MODULE_AUTHOR("Ondrej Zary");
+MODULE_DESCRIPTION("driver for parallel port ATA adapters");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("paride");
+
+module_init(pata_parport_init);
+module_exit(pata_parport_exit);
diff --git a/drivers/block/paride/ppc6lnx.c b/drivers/ata/pata_parport/ppc6lnx.c
index 5e5521d3b1dd..5e5521d3b1dd 100644
--- a/drivers/block/paride/ppc6lnx.c
+++ b/drivers/ata/pata_parport/ppc6lnx.c
diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c
index b9a4f68b371d..b052c5a65c17 100644
--- a/drivers/ata/sata_fsl.c
+++ b/drivers/ata/sata_fsl.c
@@ -566,7 +566,7 @@ static unsigned int sata_fsl_qc_issue(struct ata_queued_cmd *qc)
return 0;
}
-static bool sata_fsl_qc_fill_rtf(struct ata_queued_cmd *qc)
+static void sata_fsl_qc_fill_rtf(struct ata_queued_cmd *qc)
{
struct sata_fsl_port_priv *pp = qc->ap->private_data;
struct sata_fsl_host_priv *host_priv = qc->ap->host->private_data;
@@ -577,7 +577,6 @@ static bool sata_fsl_qc_fill_rtf(struct ata_queued_cmd *qc)
cd = pp->cmdentry + tag;
ata_tf_from_fis(cd->sfis, &qc->result_tf);
- return true;
}
static int sata_fsl_scr_write(struct ata_link *link,
@@ -1042,7 +1041,7 @@ static void sata_fsl_error_handler(struct ata_port *ap)
static void sata_fsl_post_internal_cmd(struct ata_queued_cmd *qc)
{
- if (qc->flags & ATA_QCFLAG_FAILED)
+ if (qc->flags & ATA_QCFLAG_EH)
qc->err_mask |= AC_ERR_OTHER;
if (qc->err_mask) {
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c
index 11e518f0111c..2833c722118d 100644
--- a/drivers/ata/sata_inic162x.c
+++ b/drivers/ata/sata_inic162x.c
@@ -566,7 +566,7 @@ static void inic_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
tf->status = readb(port_base + PORT_TF_COMMAND);
}
-static bool inic_qc_fill_rtf(struct ata_queued_cmd *qc)
+static void inic_qc_fill_rtf(struct ata_queued_cmd *qc)
{
struct ata_taskfile *rtf = &qc->result_tf;
struct ata_taskfile tf;
@@ -580,12 +580,10 @@ static bool inic_qc_fill_rtf(struct ata_queued_cmd *qc)
*/
inic_tf_read(qc->ap, &tf);
- if (!(tf.status & ATA_ERR))
- return false;
-
- rtf->status = tf.status;
- rtf->error = tf.error;
- return true;
+ if (tf.status & ATA_ERR) {
+ rtf->status = tf.status;
+ rtf->error = tf.error;
+ }
}
static void inic_freeze(struct ata_port *ap)
@@ -672,7 +670,7 @@ static void inic_error_handler(struct ata_port *ap)
static void inic_post_internal_cmd(struct ata_queued_cmd *qc)
{
/* make DMA engine forget about the failed command */
- if (qc->flags & ATA_QCFLAG_FAILED)
+ if (qc->flags & ATA_QCFLAG_EH)
inic_reset_port(inic_port_base(qc->ap));
}
diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c
index 9cd7d8b71361..4e60e6c4c35a 100644
--- a/drivers/ata/sata_promise.c
+++ b/drivers/ata/sata_promise.c
@@ -828,7 +828,7 @@ static void pdc_post_internal_cmd(struct ata_queued_cmd *qc)
struct ata_port *ap = qc->ap;
/* make DMA engine forget about the failed command */
- if (qc->flags & ATA_QCFLAG_FAILED)
+ if (qc->flags & ATA_QCFLAG_EH)
pdc_reset_port(ap);
}
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index 2fef6ce93f07..22cc9e9789dd 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -328,7 +328,7 @@ static int sil24_scr_write(struct ata_link *link, unsigned sc_reg, u32 val);
static int sil24_qc_defer(struct ata_queued_cmd *qc);
static enum ata_completion_errors sil24_qc_prep(struct ata_queued_cmd *qc);
static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc);
-static bool sil24_qc_fill_rtf(struct ata_queued_cmd *qc);
+static void sil24_qc_fill_rtf(struct ata_queued_cmd *qc);
static void sil24_pmp_attach(struct ata_port *ap);
static void sil24_pmp_detach(struct ata_port *ap);
static void sil24_freeze(struct ata_port *ap);
@@ -901,10 +901,9 @@ static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc)
return 0;
}
-static bool sil24_qc_fill_rtf(struct ata_queued_cmd *qc)
+static void sil24_qc_fill_rtf(struct ata_queued_cmd *qc)
{
sil24_read_tf(qc->ap, qc->hw_tag, &qc->result_tf);
- return true;
}
static void sil24_pmp_attach(struct ata_port *ap)
@@ -1185,7 +1184,7 @@ static void sil24_post_internal_cmd(struct ata_queued_cmd *qc)
struct ata_port *ap = qc->ap;
/* make DMA engine forget about the failed command */
- if ((qc->flags & ATA_QCFLAG_FAILED) && sil24_init_port(ap))
+ if ((qc->flags & ATA_QCFLAG_EH) && sil24_init_port(ap))
ata_eh_freeze_port(ap);
}
diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c
index ab70cbc78f96..a92c60455b1d 100644
--- a/drivers/ata/sata_sx4.c
+++ b/drivers/ata/sata_sx4.c
@@ -866,7 +866,7 @@ static void pdc_post_internal_cmd(struct ata_queued_cmd *qc)
struct ata_port *ap = qc->ap;
/* make DMA engine forget about the failed command */
- if (qc->flags & ATA_QCFLAG_FAILED)
+ if (qc->flags & ATA_QCFLAG_EH)
pdc_reset_port(ap);
}
diff --git a/drivers/auxdisplay/hd44780.c b/drivers/auxdisplay/hd44780.c
index 8b2a0eb3f32a..d56a5d508ccd 100644
--- a/drivers/auxdisplay/hd44780.c
+++ b/drivers/auxdisplay/hd44780.c
@@ -322,8 +322,10 @@ fail1:
static int hd44780_remove(struct platform_device *pdev)
{
struct charlcd *lcd = platform_get_drvdata(pdev);
+ struct hd44780_common *hdc = lcd->drvdata;
charlcd_unregister(lcd);
+ kfree(hdc->hd44780);
kfree(lcd->drvdata);
kfree(lcd);
diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c
index e7d6e6657ffa..b1c1dd38ab01 100644
--- a/drivers/base/arch_topology.c
+++ b/drivers/base/arch_topology.c
@@ -736,7 +736,7 @@ void update_siblings_masks(unsigned int cpuid)
ret = detect_cache_attributes(cpuid);
if (ret && ret != -ENOENT)
- pr_info("Early cacheinfo failed, ret = %d\n", ret);
+ pr_info("Early cacheinfo allocation failed, ret = %d\n", ret);
/* update core and thread sibling masks */
for_each_online_cpu(cpu) {
@@ -825,7 +825,7 @@ __weak int __init parse_acpi_topology(void)
#if defined(CONFIG_ARM64) || defined(CONFIG_RISCV)
void __init init_cpu_topology(void)
{
- int ret;
+ int cpu, ret;
reset_cpu_topology();
ret = parse_acpi_topology();
@@ -840,6 +840,14 @@ void __init init_cpu_topology(void)
reset_cpu_topology();
return;
}
+
+ for_each_possible_cpu(cpu) {
+ ret = fetch_cache_info(cpu);
+ if (ret) {
+ pr_err("Early cacheinfo failed, ret = %d\n", ret);
+ break;
+ }
+ }
}
void store_cpu_topology(unsigned int cpuid)
diff --git a/drivers/base/auxiliary.c b/drivers/base/auxiliary.c
index 8c5e65930617..4d4c2c8d26c4 100644
--- a/drivers/base/auxiliary.c
+++ b/drivers/base/auxiliary.c
@@ -185,7 +185,7 @@ static int auxiliary_match(struct device *dev, struct device_driver *drv)
return !!auxiliary_match_id(auxdrv->id_table, auxdev);
}
-static int auxiliary_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int auxiliary_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
const char *name, *p;
diff --git a/drivers/base/base.h b/drivers/base/base.h
index 7d4803c03d3e..726a12a244c0 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -52,8 +52,23 @@ struct subsys_private {
struct kset glue_dirs;
struct class *class;
+
+ struct lock_class_key lock_key;
};
-#define to_subsys_private(obj) container_of(obj, struct subsys_private, subsys.kobj)
+#define to_subsys_private(obj) container_of_const(obj, struct subsys_private, subsys.kobj)
+
+static inline struct subsys_private *subsys_get(struct subsys_private *sp)
+{
+ if (sp)
+ kset_get(&sp->subsys);
+ return sp;
+}
+
+static inline void subsys_put(struct subsys_private *sp)
+{
+ if (sp)
+ kset_put(&sp->subsys);
+}
struct driver_private {
struct kobject kobj;
@@ -130,6 +145,8 @@ struct kobject *virtual_device_parent(struct device *dev);
extern int bus_add_device(struct device *dev);
extern void bus_probe_device(struct device *dev);
extern void bus_remove_device(struct device *dev);
+void bus_notify(struct device *dev, enum bus_notifier_event value);
+bool bus_is_registered(const struct bus_type *bus);
extern int bus_add_driver(struct device_driver *drv);
extern void bus_remove_driver(struct device_driver *drv);
@@ -158,6 +175,8 @@ extern void device_block_probing(void);
extern void device_unblock_probing(void);
extern void deferred_probe_extend_timeout(void);
extern void driver_deferred_probe_trigger(void);
+const char *device_get_devnode(const struct device *dev, umode_t *mode,
+ kuid_t *uid, kgid_t *gid, const char **tmp);
/* /sys/devices directory */
extern struct kset *devices_kset;
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 4ec6dbab73be..dd4b82d7510f 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -6,6 +6,7 @@
* Copyright (c) 2002-3 Open Source Development Labs
* Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de>
* Copyright (c) 2007 Novell Inc.
+ * Copyright (c) 2023 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
*/
#include <linux/async.h>
@@ -24,6 +25,9 @@
/* /sys/devices/system */
static struct kset *system_kset;
+/* /sys/bus */
+static struct kset *bus_kset;
+
#define to_bus_attr(_attr) container_of(_attr, struct bus_attribute, attr)
/*
@@ -39,19 +43,63 @@ static struct kset *system_kset;
static int __must_check bus_rescan_devices_helper(struct device *dev,
void *data);
+/**
+ * bus_to_subsys - Turn a struct bus_type into a struct subsys_private
+ *
+ * @bus: pointer to the struct bus_type to look up
+ *
+ * The driver core internals needs to work on the subsys_private structure, not
+ * the external struct bus_type pointer. This function walks the list of
+ * registered busses in the system and finds the matching one and returns the
+ * internal struct subsys_private that relates to that bus.
+ *
+ * Note, the reference count of the return value is INCREMENTED if it is not
+ * NULL. A call to subsys_put() must be done when finished with the pointer in
+ * order for it to be properly freed.
+ */
+static struct subsys_private *bus_to_subsys(const struct bus_type *bus)
+{
+ struct subsys_private *sp = NULL;
+ struct kobject *kobj;
+
+ if (!bus || !bus_kset)
+ return NULL;
+
+ spin_lock(&bus_kset->list_lock);
+
+ if (list_empty(&bus_kset->list))
+ goto done;
+
+ list_for_each_entry(kobj, &bus_kset->list, entry) {
+ struct kset *kset = container_of(kobj, struct kset, kobj);
+
+ sp = container_of_const(kset, struct subsys_private, subsys);
+ if (sp->bus == bus)
+ goto done;
+ }
+ sp = NULL;
+done:
+ sp = subsys_get(sp);
+ spin_unlock(&bus_kset->list_lock);
+ return sp;
+}
+
static struct bus_type *bus_get(struct bus_type *bus)
{
- if (bus) {
- kset_get(&bus->p->subsys);
+ struct subsys_private *sp = bus_to_subsys(bus);
+
+ if (sp)
return bus;
- }
return NULL;
}
-static void bus_put(struct bus_type *bus)
+static void bus_put(const struct bus_type *bus)
{
- if (bus)
- kset_put(&bus->p->subsys);
+ struct subsys_private *sp = bus_to_subsys(bus);
+
+ /* two puts are required as the call to bus_to_subsys incremented it again */
+ subsys_put(sp);
+ subsys_put(sp);
}
static ssize_t drv_attr_show(struct kobject *kobj, struct attribute *attr,
@@ -91,7 +139,7 @@ static void driver_release(struct kobject *kobj)
kfree(drv_priv);
}
-static struct kobj_type driver_ktype = {
+static const struct kobj_type driver_ktype = {
.sysfs_ops = &driver_sysfs_ops,
.release = driver_release,
};
@@ -128,37 +176,42 @@ static const struct sysfs_ops bus_sysfs_ops = {
.store = bus_attr_store,
};
-int bus_create_file(struct bus_type *bus, struct bus_attribute *attr)
+int bus_create_file(const struct bus_type *bus, struct bus_attribute *attr)
{
+ struct subsys_private *sp = bus_to_subsys(bus);
int error;
- if (bus_get(bus)) {
- error = sysfs_create_file(&bus->p->subsys.kobj, &attr->attr);
- bus_put(bus);
- } else
- error = -EINVAL;
+
+ if (!sp)
+ return -EINVAL;
+
+ error = sysfs_create_file(&sp->subsys.kobj, &attr->attr);
+
+ subsys_put(sp);
return error;
}
EXPORT_SYMBOL_GPL(bus_create_file);
-void bus_remove_file(struct bus_type *bus, struct bus_attribute *attr)
+void bus_remove_file(const struct bus_type *bus, struct bus_attribute *attr)
{
- if (bus_get(bus)) {
- sysfs_remove_file(&bus->p->subsys.kobj, &attr->attr);
- bus_put(bus);
- }
+ struct subsys_private *sp = bus_to_subsys(bus);
+
+ if (!sp)
+ return;
+
+ sysfs_remove_file(&sp->subsys.kobj, &attr->attr);
+ subsys_put(sp);
}
EXPORT_SYMBOL_GPL(bus_remove_file);
static void bus_release(struct kobject *kobj)
{
struct subsys_private *priv = to_subsys_private(kobj);
- struct bus_type *bus = priv->bus;
+ lockdep_unregister_key(&priv->lock_key);
kfree(priv);
- bus->p = NULL;
}
-static struct kobj_type bus_ktype = {
+static const struct kobj_type bus_ktype = {
.sysfs_ops = &bus_sysfs_ops,
.release = bus_release,
};
@@ -176,8 +229,6 @@ static const struct kset_uevent_ops bus_uevent_ops = {
.filter = bus_uevent_filter,
};
-static struct kset *bus_kset;
-
/* Manually detach a device from its associated driver. */
static ssize_t unbind_store(struct device_driver *drv, const char *buf,
size_t count)
@@ -225,16 +276,31 @@ static DRIVER_ATTR_IGNORE_LOCKDEP(bind, 0200, NULL, bind_store);
static ssize_t drivers_autoprobe_show(struct bus_type *bus, char *buf)
{
- return sysfs_emit(buf, "%d\n", bus->p->drivers_autoprobe);
+ struct subsys_private *sp = bus_to_subsys(bus);
+ int ret;
+
+ if (!sp)
+ return -EINVAL;
+
+ ret = sysfs_emit(buf, "%d\n", sp->drivers_autoprobe);
+ subsys_put(sp);
+ return ret;
}
static ssize_t drivers_autoprobe_store(struct bus_type *bus,
const char *buf, size_t count)
{
+ struct subsys_private *sp = bus_to_subsys(bus);
+
+ if (!sp)
+ return -EINVAL;
+
if (buf[0] == '0')
- bus->p->drivers_autoprobe = 0;
+ sp->drivers_autoprobe = 0;
else
- bus->p->drivers_autoprobe = 1;
+ sp->drivers_autoprobe = 1;
+
+ subsys_put(sp);
return count;
}
@@ -285,21 +351,23 @@ static struct device *next_device(struct klist_iter *i)
* to retain this data, it should do so, and increment the reference
* count in the supplied callback.
*/
-int bus_for_each_dev(struct bus_type *bus, struct device *start,
+int bus_for_each_dev(const struct bus_type *bus, struct device *start,
void *data, int (*fn)(struct device *, void *))
{
+ struct subsys_private *sp = bus_to_subsys(bus);
struct klist_iter i;
struct device *dev;
int error = 0;
- if (!bus || !bus->p)
+ if (!sp)
return -EINVAL;
- klist_iter_init_node(&bus->p->klist_devices, &i,
+ klist_iter_init_node(&sp->klist_devices, &i,
(start ? &start->p->knode_bus : NULL));
while (!error && (dev = next_device(&i)))
error = fn(dev, data);
klist_iter_exit(&i);
+ subsys_put(sp);
return error;
}
EXPORT_SYMBOL_GPL(bus_for_each_dev);
@@ -319,67 +387,28 @@ EXPORT_SYMBOL_GPL(bus_for_each_dev);
* if it does. If the callback returns non-zero, this function will
* return to the caller and not iterate over any more devices.
*/
-struct device *bus_find_device(struct bus_type *bus,
+struct device *bus_find_device(const struct bus_type *bus,
struct device *start, const void *data,
int (*match)(struct device *dev, const void *data))
{
+ struct subsys_private *sp = bus_to_subsys(bus);
struct klist_iter i;
struct device *dev;
- if (!bus || !bus->p)
+ if (!sp)
return NULL;
- klist_iter_init_node(&bus->p->klist_devices, &i,
+ klist_iter_init_node(&sp->klist_devices, &i,
(start ? &start->p->knode_bus : NULL));
while ((dev = next_device(&i)))
if (match(dev, data) && get_device(dev))
break;
klist_iter_exit(&i);
+ subsys_put(sp);
return dev;
}
EXPORT_SYMBOL_GPL(bus_find_device);
-/**
- * subsys_find_device_by_id - find a device with a specific enumeration number
- * @subsys: subsystem
- * @id: index 'id' in struct device
- * @hint: device to check first
- *
- * Check the hint's next object and if it is a match return it directly,
- * otherwise, fall back to a full list search. Either way a reference for
- * the returned object is taken.
- */
-struct device *subsys_find_device_by_id(struct bus_type *subsys, unsigned int id,
- struct device *hint)
-{
- struct klist_iter i;
- struct device *dev;
-
- if (!subsys)
- return NULL;
-
- if (hint) {
- klist_iter_init_node(&subsys->p->klist_devices, &i, &hint->p->knode_bus);
- dev = next_device(&i);
- if (dev && dev->id == id && get_device(dev)) {
- klist_iter_exit(&i);
- return dev;
- }
- klist_iter_exit(&i);
- }
-
- klist_iter_init_node(&subsys->p->klist_devices, &i, NULL);
- while ((dev = next_device(&i))) {
- if (dev->id == id && get_device(dev)) {
- klist_iter_exit(&i);
- return dev;
- }
- }
- klist_iter_exit(&i);
- return NULL;
-}
-EXPORT_SYMBOL_GPL(subsys_find_device_by_id);
-
static struct device_driver *next_driver(struct klist_iter *i)
{
struct klist_node *n = klist_next(i);
@@ -411,21 +440,23 @@ static struct device_driver *next_driver(struct klist_iter *i)
* in the callback. It must also be sure to increment the refcount
* so it doesn't disappear before returning to the caller.
*/
-int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,
+int bus_for_each_drv(const struct bus_type *bus, struct device_driver *start,
void *data, int (*fn)(struct device_driver *, void *))
{
+ struct subsys_private *sp = bus_to_subsys(bus);
struct klist_iter i;
struct device_driver *drv;
int error = 0;
- if (!bus)
+ if (!sp)
return -EINVAL;
- klist_iter_init_node(&bus->p->klist_drivers, &i,
+ klist_iter_init_node(&sp->klist_drivers, &i,
start ? &start->p->knode_bus : NULL);
while ((drv = next_driver(&i)) && !error)
error = fn(drv, data);
klist_iter_exit(&i);
+ subsys_put(sp);
return error;
}
EXPORT_SYMBOL_GPL(bus_for_each_drv);
@@ -440,32 +471,46 @@ EXPORT_SYMBOL_GPL(bus_for_each_drv);
*/
int bus_add_device(struct device *dev)
{
- struct bus_type *bus = bus_get(dev->bus);
- int error = 0;
+ struct subsys_private *sp = bus_to_subsys(dev->bus);
+ int error;
- if (bus) {
- pr_debug("bus: '%s': add device %s\n", bus->name, dev_name(dev));
- error = device_add_groups(dev, bus->dev_groups);
- if (error)
- goto out_put;
- error = sysfs_create_link(&bus->p->devices_kset->kobj,
- &dev->kobj, dev_name(dev));
- if (error)
- goto out_groups;
- error = sysfs_create_link(&dev->kobj,
- &dev->bus->p->subsys.kobj, "subsystem");
- if (error)
- goto out_subsys;
- klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices);
+ if (!sp) {
+ /*
+ * This is a normal operation for many devices that do not
+ * have a bus assigned to them, just say that all went
+ * well.
+ */
+ return 0;
}
+
+ /*
+ * Reference in sp is now incremented and will be dropped when
+ * the device is removed from the bus
+ */
+
+ pr_debug("bus: '%s': add device %s\n", sp->bus->name, dev_name(dev));
+
+ error = device_add_groups(dev, sp->bus->dev_groups);
+ if (error)
+ goto out_put;
+
+ error = sysfs_create_link(&sp->devices_kset->kobj, &dev->kobj, dev_name(dev));
+ if (error)
+ goto out_groups;
+
+ error = sysfs_create_link(&dev->kobj, &sp->subsys.kobj, "subsystem");
+ if (error)
+ goto out_subsys;
+
+ klist_add_tail(&dev->p->knode_bus, &sp->klist_devices);
return 0;
out_subsys:
- sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev));
+ sysfs_remove_link(&sp->devices_kset->kobj, dev_name(dev));
out_groups:
- device_remove_groups(dev, bus->dev_groups);
+ device_remove_groups(dev, sp->bus->dev_groups);
out_put:
- bus_put(dev->bus);
+ subsys_put(sp);
return error;
}
@@ -477,20 +522,21 @@ out_put:
*/
void bus_probe_device(struct device *dev)
{
- struct bus_type *bus = dev->bus;
+ struct subsys_private *sp = bus_to_subsys(dev->bus);
struct subsys_interface *sif;
- if (!bus)
+ if (!sp)
return;
- if (bus->p->drivers_autoprobe)
+ if (sp->drivers_autoprobe)
device_initial_probe(dev);
- mutex_lock(&bus->p->mutex);
- list_for_each_entry(sif, &bus->p->interfaces, node)
+ mutex_lock(&sp->mutex);
+ list_for_each_entry(sif, &sp->interfaces, node)
if (sif->add_dev)
sif->add_dev(dev, sif);
- mutex_unlock(&bus->p->mutex);
+ mutex_unlock(&sp->mutex);
+ subsys_put(sp);
}
/**
@@ -505,21 +551,20 @@ void bus_probe_device(struct device *dev)
*/
void bus_remove_device(struct device *dev)
{
- struct bus_type *bus = dev->bus;
+ struct subsys_private *sp = bus_to_subsys(dev->bus);
struct subsys_interface *sif;
- if (!bus)
+ if (!sp)
return;
- mutex_lock(&bus->p->mutex);
- list_for_each_entry(sif, &bus->p->interfaces, node)
+ mutex_lock(&sp->mutex);
+ list_for_each_entry(sif, &sp->interfaces, node)
if (sif->remove_dev)
sif->remove_dev(dev, sif);
- mutex_unlock(&bus->p->mutex);
+ mutex_unlock(&sp->mutex);
sysfs_remove_link(&dev->kobj, "subsystem");
- sysfs_remove_link(&dev->bus->p->devices_kset->kobj,
- dev_name(dev));
+ sysfs_remove_link(&sp->devices_kset->kobj, dev_name(dev));
device_remove_groups(dev, dev->bus->dev_groups);
if (klist_node_attached(&dev->p->knode_bus))
klist_del(&dev->p->knode_bus);
@@ -527,7 +572,14 @@ void bus_remove_device(struct device *dev)
pr_debug("bus: '%s': remove device %s\n",
dev->bus->name, dev_name(dev));
device_release_driver(dev);
- bus_put(dev->bus);
+
+ /*
+ * Decrement the reference count twice, once for the bus_to_subsys()
+ * call in the start of this function, and the second one from the
+ * reference increment in bus_add_device()
+ */
+ subsys_put(sp);
+ subsys_put(sp);
}
static int __must_check add_bind_files(struct device_driver *drv)
@@ -552,7 +604,7 @@ static void remove_bind_files(struct device_driver *drv)
static BUS_ATTR_WO(drivers_probe);
static BUS_ATTR_RW(drivers_autoprobe);
-static int add_probe_files(struct bus_type *bus)
+static int add_probe_files(const struct bus_type *bus)
{
int retval;
@@ -567,7 +619,7 @@ out:
return retval;
}
-static void remove_probe_files(struct bus_type *bus)
+static void remove_probe_files(const struct bus_type *bus)
{
bus_remove_file(bus, &bus_attr_drivers_autoprobe);
bus_remove_file(bus, &bus_attr_drivers_probe);
@@ -589,15 +641,18 @@ static DRIVER_ATTR_WO(uevent);
*/
int bus_add_driver(struct device_driver *drv)
{
- struct bus_type *bus;
+ struct subsys_private *sp = bus_to_subsys(drv->bus);
struct driver_private *priv;
int error = 0;
- bus = bus_get(drv->bus);
- if (!bus)
+ if (!sp)
return -EINVAL;
- pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
+ /*
+ * Reference in sp is now incremented and will be dropped when
+ * the driver is removed from the bus
+ */
+ pr_debug("bus: '%s': add driver %s\n", sp->bus->name, drv->name);
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
@@ -607,14 +662,14 @@ int bus_add_driver(struct device_driver *drv)
klist_init(&priv->klist_devices, NULL, NULL);
priv->driver = drv;
drv->p = priv;
- priv->kobj.kset = bus->p->drivers_kset;
+ priv->kobj.kset = sp->drivers_kset;
error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
"%s", drv->name);
if (error)
goto out_unregister;
- klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
- if (drv->bus->p->drivers_autoprobe) {
+ klist_add_tail(&priv->knode_bus, &sp->klist_drivers);
+ if (sp->drivers_autoprobe) {
error = driver_attach(drv);
if (error)
goto out_del_list;
@@ -626,7 +681,7 @@ int bus_add_driver(struct device_driver *drv)
printk(KERN_ERR "%s: uevent attr (%s) failed\n",
__func__, drv->name);
}
- error = driver_add_groups(drv, bus->drv_groups);
+ error = driver_add_groups(drv, sp->bus->drv_groups);
if (error) {
/* How the hell do we get out of this pickle? Give up */
printk(KERN_ERR "%s: driver_add_groups(%s) failed\n",
@@ -651,7 +706,7 @@ out_unregister:
/* drv->p is freed in driver_release() */
drv->p = NULL;
out_put_bus:
- bus_put(bus);
+ subsys_put(sp);
return error;
}
@@ -665,19 +720,29 @@ out_put_bus:
*/
void bus_remove_driver(struct device_driver *drv)
{
- if (!drv->bus)
+ struct subsys_private *sp = bus_to_subsys(drv->bus);
+
+ if (!sp)
return;
+ pr_debug("bus: '%s': remove driver %s\n", sp->bus->name, drv->name);
+
if (!drv->suppress_bind_attrs)
remove_bind_files(drv);
- driver_remove_groups(drv, drv->bus->drv_groups);
+ driver_remove_groups(drv, sp->bus->drv_groups);
driver_remove_file(drv, &driver_attr_uevent);
klist_remove(&drv->p->knode_bus);
- pr_debug("bus: '%s': remove driver %s\n", drv->bus->name, drv->name);
driver_detach(drv);
module_remove_driver(drv);
kobject_put(&drv->p->kobj);
- bus_put(drv->bus);
+
+ /*
+ * Decrement the reference count twice, once for the bus_to_subsys()
+ * call in the start of this function, and the second one from the
+ * reference increment in bus_add_driver()
+ */
+ subsys_put(sp);
+ subsys_put(sp);
}
/* Helper for bus_rescan_devices's iter */
@@ -727,18 +792,6 @@ int device_reprobe(struct device *dev)
}
EXPORT_SYMBOL_GPL(device_reprobe);
-static int bus_add_groups(struct bus_type *bus,
- const struct attribute_group **groups)
-{
- return sysfs_create_groups(&bus->p->subsys.kobj, groups);
-}
-
-static void bus_remove_groups(struct bus_type *bus,
- const struct attribute_group **groups)
-{
- sysfs_remove_groups(&bus->p->subsys.kobj, groups);
-}
-
static void klist_devices_get(struct klist_node *n)
{
struct device_private *dev_prv = to_device_private_bus(n);
@@ -758,10 +811,18 @@ static void klist_devices_put(struct klist_node *n)
static ssize_t bus_uevent_store(struct bus_type *bus,
const char *buf, size_t count)
{
- int rc;
+ struct subsys_private *sp = bus_to_subsys(bus);
+ int ret;
- rc = kobject_synth_uevent(&bus->p->subsys.kobj, buf, count);
- return rc ? rc : count;
+ if (!sp)
+ return -EINVAL;
+
+ ret = kobject_synth_uevent(&sp->subsys.kobj, buf, count);
+ subsys_put(sp);
+
+ if (ret)
+ return ret;
+ return count;
}
/*
* "open code" the old BUS_ATTR() macro here. We want to use BUS_ATTR_WO()
@@ -784,23 +845,24 @@ int bus_register(struct bus_type *bus)
{
int retval;
struct subsys_private *priv;
- struct lock_class_key *key = &bus->lock_key;
+ struct kobject *bus_kobj;
+ struct lock_class_key *key;
priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->bus = bus;
- bus->p = priv;
BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
- retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
+ bus_kobj = &priv->subsys.kobj;
+ retval = kobject_set_name(bus_kobj, "%s", bus->name);
if (retval)
goto out;
- priv->subsys.kobj.kset = bus_kset;
- priv->subsys.kobj.ktype = &bus_ktype;
+ bus_kobj->kset = bus_kset;
+ bus_kobj->ktype = &bus_ktype;
priv->drivers_autoprobe = 1;
retval = kset_register(&priv->subsys);
@@ -811,21 +873,21 @@ int bus_register(struct bus_type *bus)
if (retval)
goto bus_uevent_fail;
- priv->devices_kset = kset_create_and_add("devices", NULL,
- &priv->subsys.kobj);
+ priv->devices_kset = kset_create_and_add("devices", NULL, bus_kobj);
if (!priv->devices_kset) {
retval = -ENOMEM;
goto bus_devices_fail;
}
- priv->drivers_kset = kset_create_and_add("drivers", NULL,
- &priv->subsys.kobj);
+ priv->drivers_kset = kset_create_and_add("drivers", NULL, bus_kobj);
if (!priv->drivers_kset) {
retval = -ENOMEM;
goto bus_drivers_fail;
}
INIT_LIST_HEAD(&priv->interfaces);
+ key = &priv->lock_key;
+ lockdep_register_key(key);
__mutex_init(&priv->mutex, "subsys mutex", key);
klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
klist_init(&priv->klist_drivers, NULL, NULL);
@@ -834,7 +896,7 @@ int bus_register(struct bus_type *bus)
if (retval)
goto bus_probe_files_fail;
- retval = bus_add_groups(bus, bus->bus_groups);
+ retval = sysfs_create_groups(bus_kobj, bus->bus_groups);
if (retval)
goto bus_groups_fail;
@@ -844,16 +906,15 @@ int bus_register(struct bus_type *bus)
bus_groups_fail:
remove_probe_files(bus);
bus_probe_files_fail:
- kset_unregister(bus->p->drivers_kset);
+ kset_unregister(priv->drivers_kset);
bus_drivers_fail:
- kset_unregister(bus->p->devices_kset);
+ kset_unregister(priv->devices_kset);
bus_devices_fail:
bus_remove_file(bus, &bus_attr_uevent);
bus_uevent_fail:
- kset_unregister(&bus->p->subsys);
+ kset_unregister(&priv->subsys);
out:
- kfree(bus->p);
- bus->p = NULL;
+ kfree(priv);
return retval;
}
EXPORT_SYMBOL_GPL(bus_register);
@@ -865,43 +926,82 @@ EXPORT_SYMBOL_GPL(bus_register);
* Unregister the child subsystems and the bus itself.
* Finally, we call bus_put() to release the refcount
*/
-void bus_unregister(struct bus_type *bus)
+void bus_unregister(const struct bus_type *bus)
{
+ struct subsys_private *sp = bus_to_subsys(bus);
+ struct kobject *bus_kobj;
+
+ if (!sp)
+ return;
+
pr_debug("bus: '%s': unregistering\n", bus->name);
if (bus->dev_root)
device_unregister(bus->dev_root);
- bus_remove_groups(bus, bus->bus_groups);
+
+ bus_kobj = &sp->subsys.kobj;
+ sysfs_remove_groups(bus_kobj, bus->bus_groups);
remove_probe_files(bus);
- kset_unregister(bus->p->drivers_kset);
- kset_unregister(bus->p->devices_kset);
bus_remove_file(bus, &bus_attr_uevent);
- kset_unregister(&bus->p->subsys);
+
+ kset_unregister(sp->drivers_kset);
+ kset_unregister(sp->devices_kset);
+ kset_unregister(&sp->subsys);
+ subsys_put(sp);
}
EXPORT_SYMBOL_GPL(bus_unregister);
-int bus_register_notifier(struct bus_type *bus, struct notifier_block *nb)
+int bus_register_notifier(const struct bus_type *bus, struct notifier_block *nb)
{
- return blocking_notifier_chain_register(&bus->p->bus_notifier, nb);
+ struct subsys_private *sp = bus_to_subsys(bus);
+ int retval;
+
+ if (!sp)
+ return -EINVAL;
+
+ retval = blocking_notifier_chain_register(&sp->bus_notifier, nb);
+ subsys_put(sp);
+ return retval;
}
EXPORT_SYMBOL_GPL(bus_register_notifier);
-int bus_unregister_notifier(struct bus_type *bus, struct notifier_block *nb)
+int bus_unregister_notifier(const struct bus_type *bus, struct notifier_block *nb)
{
- return blocking_notifier_chain_unregister(&bus->p->bus_notifier, nb);
+ struct subsys_private *sp = bus_to_subsys(bus);
+ int retval;
+
+ if (!sp)
+ return -EINVAL;
+ retval = blocking_notifier_chain_unregister(&sp->bus_notifier, nb);
+ subsys_put(sp);
+ return retval;
}
EXPORT_SYMBOL_GPL(bus_unregister_notifier);
-struct kset *bus_get_kset(struct bus_type *bus)
+void bus_notify(struct device *dev, enum bus_notifier_event value)
{
- return &bus->p->subsys;
+ struct subsys_private *sp = bus_to_subsys(dev->bus);
+
+ if (!sp)
+ return;
+
+ blocking_notifier_call_chain(&sp->bus_notifier, value, dev);
+ subsys_put(sp);
}
-EXPORT_SYMBOL_GPL(bus_get_kset);
-struct klist *bus_get_device_klist(struct bus_type *bus)
+struct kset *bus_get_kset(const struct bus_type *bus)
{
- return &bus->p->klist_devices;
+ struct subsys_private *sp = bus_to_subsys(bus);
+ struct kset *kset;
+
+ if (!sp)
+ return NULL;
+
+ kset = &sp->subsys;
+ subsys_put(sp);
+
+ return kset;
}
-EXPORT_SYMBOL_GPL(bus_get_device_klist);
+EXPORT_SYMBOL_GPL(bus_get_kset);
/*
* Yes, this forcibly breaks the klist abstraction temporarily. It
@@ -934,13 +1034,16 @@ void bus_sort_breadthfirst(struct bus_type *bus,
int (*compare)(const struct device *a,
const struct device *b))
{
+ struct subsys_private *sp = bus_to_subsys(bus);
LIST_HEAD(sorted_devices);
struct klist_node *n, *tmp;
struct device_private *dev_prv;
struct device *dev;
struct klist *device_klist;
- device_klist = bus_get_device_klist(bus);
+ if (!sp)
+ return;
+ device_klist = &sp->klist_devices;
spin_lock(&device_klist->k_lock);
list_for_each_entry_safe(n, tmp, &device_klist->k_list, n_node) {
@@ -950,13 +1053,19 @@ void bus_sort_breadthfirst(struct bus_type *bus,
}
list_splice(&sorted_devices, &device_klist->k_list);
spin_unlock(&device_klist->k_lock);
+ subsys_put(sp);
}
EXPORT_SYMBOL_GPL(bus_sort_breadthfirst);
+struct subsys_dev_iter {
+ struct klist_iter ki;
+ const struct device_type *type;
+};
+
/**
* subsys_dev_iter_init - initialize subsys device iterator
* @iter: subsys iterator to initialize
- * @subsys: the subsys we wanna iterate over
+ * @sp: the subsys private (i.e. bus) we wanna iterate over
* @start: the device to start iterating from, if any
* @type: device_type of the devices to iterate over, NULL for all
*
@@ -965,17 +1074,16 @@ EXPORT_SYMBOL_GPL(bus_sort_breadthfirst);
* otherwise if it is NULL, the iteration starts at the beginning of
* the list.
*/
-void subsys_dev_iter_init(struct subsys_dev_iter *iter, struct bus_type *subsys,
- struct device *start, const struct device_type *type)
+static void subsys_dev_iter_init(struct subsys_dev_iter *iter, struct subsys_private *sp,
+ struct device *start, const struct device_type *type)
{
struct klist_node *start_knode = NULL;
if (start)
start_knode = &start->p->knode_bus;
- klist_iter_init_node(&subsys->p->klist_devices, &iter->ki, start_knode);
+ klist_iter_init_node(&sp->klist_devices, &iter->ki, start_knode);
iter->type = type;
}
-EXPORT_SYMBOL_GPL(subsys_dev_iter_init);
/**
* subsys_dev_iter_next - iterate to the next device
@@ -989,7 +1097,7 @@ EXPORT_SYMBOL_GPL(subsys_dev_iter_init);
* free to do whatever it wants to do with the device including
* calling back into subsys code.
*/
-struct device *subsys_dev_iter_next(struct subsys_dev_iter *iter)
+static struct device *subsys_dev_iter_next(struct subsys_dev_iter *iter)
{
struct klist_node *knode;
struct device *dev;
@@ -1003,7 +1111,6 @@ struct device *subsys_dev_iter_next(struct subsys_dev_iter *iter)
return dev;
}
}
-EXPORT_SYMBOL_GPL(subsys_dev_iter_next);
/**
* subsys_dev_iter_exit - finish iteration
@@ -1012,34 +1119,38 @@ EXPORT_SYMBOL_GPL(subsys_dev_iter_next);
* Finish an iteration. Always call this function after iteration is
* complete whether the iteration ran till the end or not.
*/
-void subsys_dev_iter_exit(struct subsys_dev_iter *iter)
+static void subsys_dev_iter_exit(struct subsys_dev_iter *iter)
{
klist_iter_exit(&iter->ki);
}
-EXPORT_SYMBOL_GPL(subsys_dev_iter_exit);
int subsys_interface_register(struct subsys_interface *sif)
{
- struct bus_type *subsys;
+ struct subsys_private *sp;
struct subsys_dev_iter iter;
struct device *dev;
if (!sif || !sif->subsys)
return -ENODEV;
- subsys = bus_get(sif->subsys);
- if (!subsys)
+ sp = bus_to_subsys(sif->subsys);
+ if (!sp)
return -EINVAL;
- mutex_lock(&subsys->p->mutex);
- list_add_tail(&sif->node, &subsys->p->interfaces);
+ /*
+ * Reference in sp is now incremented and will be dropped when
+ * the interface is removed from the bus
+ */
+
+ mutex_lock(&sp->mutex);
+ list_add_tail(&sif->node, &sp->interfaces);
if (sif->add_dev) {
- subsys_dev_iter_init(&iter, subsys, NULL, NULL);
+ subsys_dev_iter_init(&iter, sp, NULL, NULL);
while ((dev = subsys_dev_iter_next(&iter)))
sif->add_dev(dev, sif);
subsys_dev_iter_exit(&iter);
}
- mutex_unlock(&subsys->p->mutex);
+ mutex_unlock(&sp->mutex);
return 0;
}
@@ -1047,26 +1158,34 @@ EXPORT_SYMBOL_GPL(subsys_interface_register);
void subsys_interface_unregister(struct subsys_interface *sif)
{
- struct bus_type *subsys;
+ struct subsys_private *sp;
struct subsys_dev_iter iter;
struct device *dev;
if (!sif || !sif->subsys)
return;
- subsys = sif->subsys;
+ sp = bus_to_subsys(sif->subsys);
+ if (!sp)
+ return;
- mutex_lock(&subsys->p->mutex);
+ mutex_lock(&sp->mutex);
list_del_init(&sif->node);
if (sif->remove_dev) {
- subsys_dev_iter_init(&iter, subsys, NULL, NULL);
+ subsys_dev_iter_init(&iter, sp, NULL, NULL);
while ((dev = subsys_dev_iter_next(&iter)))
sif->remove_dev(dev, sif);
subsys_dev_iter_exit(&iter);
}
- mutex_unlock(&subsys->p->mutex);
-
- bus_put(subsys);
+ mutex_unlock(&sp->mutex);
+
+ /*
+ * Decrement the reference count twice, once for the bus_to_subsys()
+ * call in the start of this function, and the second one from the
+ * reference increment in subsys_interface_register()
+ */
+ subsys_put(sp);
+ subsys_put(sp);
}
EXPORT_SYMBOL_GPL(subsys_interface_unregister);
@@ -1166,6 +1285,76 @@ int subsys_virtual_register(struct bus_type *subsys,
}
EXPORT_SYMBOL_GPL(subsys_virtual_register);
+/**
+ * driver_find - locate driver on a bus by its name.
+ * @name: name of the driver.
+ * @bus: bus to scan for the driver.
+ *
+ * Call kset_find_obj() to iterate over list of drivers on
+ * a bus to find driver by name. Return driver if found.
+ *
+ * This routine provides no locking to prevent the driver it returns
+ * from being unregistered or unloaded while the caller is using it.
+ * The caller is responsible for preventing this.
+ */
+struct device_driver *driver_find(const char *name, struct bus_type *bus)
+{
+ struct subsys_private *sp = bus_to_subsys(bus);
+ struct kobject *k;
+ struct driver_private *priv;
+
+ if (!sp)
+ return NULL;
+
+ k = kset_find_obj(sp->drivers_kset, name);
+ subsys_put(sp);
+ if (!k)
+ return NULL;
+
+ priv = to_driver(k);
+
+ /* Drop reference added by kset_find_obj() */
+ kobject_put(k);
+ return priv->driver;
+}
+EXPORT_SYMBOL_GPL(driver_find);
+
+/*
+ * Warning, the value could go to "removed" instantly after calling this function, so be very
+ * careful when calling it...
+ */
+bool bus_is_registered(const struct bus_type *bus)
+{
+ struct subsys_private *sp = bus_to_subsys(bus);
+ bool is_initialized = false;
+
+ if (sp) {
+ is_initialized = true;
+ subsys_put(sp);
+ }
+ return is_initialized;
+}
+
+/**
+ * bus_get_dev_root - return a pointer to the "device root" of a bus
+ * @bus: bus to return the device root of.
+ *
+ * If a bus has a "device root" structure, return it, WITH THE REFERENCE
+ * COUNT INCREMENTED.
+ *
+ * Note, when finished with the device, a call to put_device() is required.
+ *
+ * If the device root is not present (or bus is not a valid pointer), NULL
+ * will be returned.
+ */
+struct device *bus_get_dev_root(const struct bus_type *bus)
+{
+ if (bus)
+ return get_device(bus->dev_root);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(bus_get_dev_root);
+
int __init buses_init(void)
{
bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c
index 950b22cdb5f7..f6573c335f4c 100644
--- a/drivers/base/cacheinfo.c
+++ b/drivers/base/cacheinfo.c
@@ -229,8 +229,71 @@ static int cache_setup_of_node(unsigned int cpu)
return 0;
}
+
+static int of_count_cache_leaves(struct device_node *np)
+{
+ unsigned int leaves = 0;
+
+ if (of_property_read_bool(np, "cache-size"))
+ ++leaves;
+ if (of_property_read_bool(np, "i-cache-size"))
+ ++leaves;
+ if (of_property_read_bool(np, "d-cache-size"))
+ ++leaves;
+
+ if (!leaves) {
+ /* The '[i-|d-|]cache-size' property is required, but
+ * if absent, fallback on the 'cache-unified' property.
+ */
+ if (of_property_read_bool(np, "cache-unified"))
+ return 1;
+ else
+ return 2;
+ }
+
+ return leaves;
+}
+
+int init_of_cache_level(unsigned int cpu)
+{
+ struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+ struct device_node *np = of_cpu_device_node_get(cpu);
+ struct device_node *prev = NULL;
+ unsigned int levels = 0, leaves, level;
+
+ leaves = of_count_cache_leaves(np);
+ if (leaves > 0)
+ levels = 1;
+
+ prev = np;
+ while ((np = of_find_next_cache_node(np))) {
+ of_node_put(prev);
+ prev = np;
+ if (!of_device_is_compatible(np, "cache"))
+ goto err_out;
+ if (of_property_read_u32(np, "cache-level", &level))
+ goto err_out;
+ if (level <= levels)
+ goto err_out;
+
+ leaves += of_count_cache_leaves(np);
+ levels = level;
+ }
+
+ of_node_put(np);
+ this_cpu_ci->num_levels = levels;
+ this_cpu_ci->num_leaves = leaves;
+
+ return 0;
+
+err_out:
+ of_node_put(np);
+ return -EINVAL;
+}
+
#else
static inline int cache_setup_of_node(unsigned int cpu) { return 0; }
+int init_of_cache_level(unsigned int cpu) { return 0; }
#endif
int __weak cache_setup_acpi(unsigned int cpu)
@@ -256,7 +319,7 @@ static int cache_shared_cpu_map_setup(unsigned int cpu)
{
struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
struct cacheinfo *this_leaf, *sib_leaf;
- unsigned int index;
+ unsigned int index, sib_index;
int ret = 0;
if (this_cpu_ci->cpu_map_populated)
@@ -284,11 +347,13 @@ static int cache_shared_cpu_map_setup(unsigned int cpu)
if (i == cpu || !sib_cpu_ci->info_list)
continue;/* skip if itself or no cacheinfo */
-
- sib_leaf = per_cpu_cacheinfo_idx(i, index);
- if (cache_leaves_are_shared(this_leaf, sib_leaf)) {
- cpumask_set_cpu(cpu, &sib_leaf->shared_cpu_map);
- cpumask_set_cpu(i, &this_leaf->shared_cpu_map);
+ for (sib_index = 0; sib_index < cache_leaves(i); sib_index++) {
+ sib_leaf = per_cpu_cacheinfo_idx(i, sib_index);
+ if (cache_leaves_are_shared(this_leaf, sib_leaf)) {
+ cpumask_set_cpu(cpu, &sib_leaf->shared_cpu_map);
+ cpumask_set_cpu(i, &this_leaf->shared_cpu_map);
+ break;
+ }
}
}
/* record the maximum cache line size */
@@ -302,7 +367,7 @@ static int cache_shared_cpu_map_setup(unsigned int cpu)
static void cache_shared_cpu_map_remove(unsigned int cpu)
{
struct cacheinfo *this_leaf, *sib_leaf;
- unsigned int sibling, index;
+ unsigned int sibling, index, sib_index;
for (index = 0; index < cache_leaves(cpu); index++) {
this_leaf = per_cpu_cacheinfo_idx(cpu, index);
@@ -313,9 +378,14 @@ static void cache_shared_cpu_map_remove(unsigned int cpu)
if (sibling == cpu || !sib_cpu_ci->info_list)
continue;/* skip if itself or no cacheinfo */
- sib_leaf = per_cpu_cacheinfo_idx(sibling, index);
- cpumask_clear_cpu(cpu, &sib_leaf->shared_cpu_map);
- cpumask_clear_cpu(sibling, &this_leaf->shared_cpu_map);
+ for (sib_index = 0; sib_index < cache_leaves(sibling); sib_index++) {
+ sib_leaf = per_cpu_cacheinfo_idx(sibling, sib_index);
+ if (cache_leaves_are_shared(this_leaf, sib_leaf)) {
+ cpumask_clear_cpu(cpu, &sib_leaf->shared_cpu_map);
+ cpumask_clear_cpu(sibling, &this_leaf->shared_cpu_map);
+ break;
+ }
+ }
}
}
}
@@ -326,10 +396,6 @@ static void free_cache_attributes(unsigned int cpu)
return;
cache_shared_cpu_map_remove(cpu);
-
- kfree(per_cpu_cacheinfo(cpu));
- per_cpu_cacheinfo(cpu) = NULL;
- cache_leaves(cpu) = 0;
}
int __weak init_cache_level(unsigned int cpu)
@@ -342,29 +408,71 @@ int __weak populate_cache_leaves(unsigned int cpu)
return -ENOENT;
}
+static inline
+int allocate_cache_info(int cpu)
+{
+ per_cpu_cacheinfo(cpu) = kcalloc(cache_leaves(cpu),
+ sizeof(struct cacheinfo), GFP_ATOMIC);
+ if (!per_cpu_cacheinfo(cpu)) {
+ cache_leaves(cpu) = 0;
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+int fetch_cache_info(unsigned int cpu)
+{
+ struct cpu_cacheinfo *this_cpu_ci;
+ unsigned int levels = 0, split_levels = 0;
+ int ret;
+
+ if (acpi_disabled) {
+ ret = init_of_cache_level(cpu);
+ if (ret < 0)
+ return ret;
+ } else {
+ ret = acpi_get_cache_info(cpu, &levels, &split_levels);
+ if (ret < 0)
+ return ret;
+
+ this_cpu_ci = get_cpu_cacheinfo(cpu);
+ this_cpu_ci->num_levels = levels;
+ /*
+ * This assumes that:
+ * - there cannot be any split caches (data/instruction)
+ * above a unified cache
+ * - data/instruction caches come by pair
+ */
+ this_cpu_ci->num_leaves = levels + split_levels;
+ }
+ if (!cache_leaves(cpu))
+ return -ENOENT;
+
+ return allocate_cache_info(cpu);
+}
+
int detect_cache_attributes(unsigned int cpu)
{
int ret;
- /* Since early detection of the cacheinfo is allowed via this
- * function and this also gets called as CPU hotplug callbacks via
- * cacheinfo_cpu_online, the initialisation can be skipped and only
- * CPU maps can be updated as the CPU online status would be update
- * if called via cacheinfo_cpu_online path.
+ /* Since early initialization/allocation of the cacheinfo is allowed
+ * via fetch_cache_info() and this also gets called as CPU hotplug
+ * callbacks via cacheinfo_cpu_online, the init/alloc can be skipped
+ * as it will happen only once (the cacheinfo memory is never freed).
+ * Just populate the cacheinfo.
*/
if (per_cpu_cacheinfo(cpu))
- goto update_cpu_map;
+ goto populate_leaves;
if (init_cache_level(cpu) || !cache_leaves(cpu))
return -ENOENT;
- per_cpu_cacheinfo(cpu) = kcalloc(cache_leaves(cpu),
- sizeof(struct cacheinfo), GFP_ATOMIC);
- if (per_cpu_cacheinfo(cpu) == NULL) {
- cache_leaves(cpu) = 0;
- return -ENOMEM;
- }
+ ret = allocate_cache_info(cpu);
+ if (ret)
+ return ret;
+populate_leaves:
/*
* populate_cache_leaves() may completely setup the cache leaves and
* shared_cpu_map or it may leave it partially setup.
@@ -373,7 +481,6 @@ int detect_cache_attributes(unsigned int cpu)
if (ret)
goto free_ci;
-update_cpu_map:
/*
* For systems using DT for cache hierarchy, fw_token
* and shared_cpu_map will be set up here only if they are
diff --git a/drivers/base/class.c b/drivers/base/class.c
index 86ec554cfe60..2373b3e210d8 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -53,6 +53,8 @@ static void class_release(struct kobject *kobj)
pr_debug("class '%s': release.\n", class->name);
+ class->p = NULL;
+
if (class->class_release)
class->class_release(class);
else
@@ -64,7 +66,7 @@ static void class_release(struct kobject *kobj)
static const struct kobj_ns_type_operations *class_child_ns_type(const struct kobject *kobj)
{
- struct subsys_private *cp = to_subsys_private(kobj);
+ const struct subsys_private *cp = to_subsys_private(kobj);
struct class *class = cp->class;
return class->ns_type;
@@ -75,7 +77,7 @@ static const struct sysfs_ops class_sysfs_ops = {
.store = class_attr_store,
};
-static struct kobj_type class_ktype = {
+static const struct kobj_type class_ktype = {
.sysfs_ops = &class_sysfs_ops,
.release = class_release,
.child_ns_type = class_child_ns_type,
@@ -97,6 +99,7 @@ int class_create_file_ns(struct class *cls, const struct class_attribute *attr,
error = -EINVAL;
return error;
}
+EXPORT_SYMBOL_GPL(class_create_file_ns);
void class_remove_file_ns(struct class *cls, const struct class_attribute *attr,
const void *ns)
@@ -104,6 +107,7 @@ void class_remove_file_ns(struct class *cls, const struct class_attribute *attr,
if (cls)
sysfs_remove_file_ns(&cls->p->subsys.kobj, &attr->attr, ns);
}
+EXPORT_SYMBOL_GPL(class_remove_file_ns);
static struct class *class_get(struct class *cls)
{
@@ -186,17 +190,21 @@ int __class_register(struct class *cls, struct lock_class_key *key)
cls->p = cp;
error = kset_register(&cp->subsys);
- if (error) {
- kfree(cp);
- return error;
- }
+ if (error)
+ goto err_out;
+
error = class_add_groups(class_get(cls), cls->class_groups);
class_put(cls);
if (error) {
kobject_del(&cp->subsys.kobj);
kfree_const(cp->subsys.kobj.name);
- kfree(cp);
+ goto err_out;
}
+ return 0;
+
+err_out:
+ kfree(cp);
+ cls->p = NULL;
return error;
}
EXPORT_SYMBOL_GPL(__class_register);
@@ -207,6 +215,7 @@ void class_unregister(struct class *cls)
class_remove_groups(cls, cls->class_groups);
kset_unregister(&cls->p->subsys);
}
+EXPORT_SYMBOL_GPL(class_unregister);
static void class_create_release(struct class *cls)
{
@@ -270,6 +279,7 @@ void class_destroy(struct class *cls)
class_unregister(cls);
}
+EXPORT_SYMBOL_GPL(class_destroy);
/**
* class_dev_iter_init - initialize class device iterator
@@ -454,6 +464,7 @@ int class_interface_register(struct class_interface *class_intf)
return 0;
}
+EXPORT_SYMBOL_GPL(class_interface_register);
void class_interface_unregister(struct class_interface *class_intf)
{
@@ -476,6 +487,7 @@ void class_interface_unregister(struct class_interface *class_intf)
class_put(parent);
}
+EXPORT_SYMBOL_GPL(class_interface_unregister);
ssize_t show_class_attr_string(struct class *class,
struct class_attribute *attr, char *buf)
@@ -582,11 +594,3 @@ int __init classes_init(void)
return -ENOMEM;
return 0;
}
-
-EXPORT_SYMBOL_GPL(class_create_file_ns);
-EXPORT_SYMBOL_GPL(class_remove_file_ns);
-EXPORT_SYMBOL_GPL(class_unregister);
-EXPORT_SYMBOL_GPL(class_destroy);
-
-EXPORT_SYMBOL_GPL(class_interface_register);
-EXPORT_SYMBOL_GPL(class_interface_unregister);
diff --git a/drivers/base/component.c b/drivers/base/component.c
index 5eadeac6c532..7dbf14a1d915 100644
--- a/drivers/base/component.c
+++ b/drivers/base/component.c
@@ -125,7 +125,7 @@ static void component_debugfs_add(struct aggregate_device *m)
static void component_debugfs_del(struct aggregate_device *m)
{
- debugfs_remove(debugfs_lookup(dev_name(m->parent), component_debugfs_dir));
+ debugfs_lookup_and_remove(dev_name(m->parent), component_debugfs_dir);
}
#else
diff --git a/drivers/base/core.c b/drivers/base/core.c
index bb36aca8d1b7..6878dfcbf0d6 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -54,11 +54,12 @@ static LIST_HEAD(deferred_sync);
static unsigned int defer_sync_state_count = 1;
static DEFINE_MUTEX(fwnode_link_lock);
static bool fw_devlink_is_permissive(void);
+static void __fw_devlink_link_to_consumers(struct device *dev);
static bool fw_devlink_drv_reg_done;
static bool fw_devlink_best_effort;
/**
- * fwnode_link_add - Create a link between two fwnode_handles.
+ * __fwnode_link_add - Create a link between two fwnode_handles.
* @con: Consumer end of the link.
* @sup: Supplier end of the link.
*
@@ -74,35 +75,42 @@ static bool fw_devlink_best_effort;
* Attempts to create duplicate links between the same pair of fwnode handles
* are ignored and there is no reference counting.
*/
-int fwnode_link_add(struct fwnode_handle *con, struct fwnode_handle *sup)
+static int __fwnode_link_add(struct fwnode_handle *con,
+ struct fwnode_handle *sup, u8 flags)
{
struct fwnode_link *link;
- int ret = 0;
-
- mutex_lock(&fwnode_link_lock);
list_for_each_entry(link, &sup->consumers, s_hook)
- if (link->consumer == con)
- goto out;
+ if (link->consumer == con) {
+ link->flags |= flags;
+ return 0;
+ }
link = kzalloc(sizeof(*link), GFP_KERNEL);
- if (!link) {
- ret = -ENOMEM;
- goto out;
- }
+ if (!link)
+ return -ENOMEM;
link->supplier = sup;
INIT_LIST_HEAD(&link->s_hook);
link->consumer = con;
INIT_LIST_HEAD(&link->c_hook);
+ link->flags = flags;
list_add(&link->s_hook, &sup->consumers);
list_add(&link->c_hook, &con->suppliers);
- pr_debug("%pfwP Linked as a fwnode consumer to %pfwP\n",
+ pr_debug("%pfwf Linked as a fwnode consumer to %pfwf\n",
con, sup);
-out:
- mutex_unlock(&fwnode_link_lock);
+ return 0;
+}
+
+int fwnode_link_add(struct fwnode_handle *con, struct fwnode_handle *sup)
+{
+ int ret;
+
+ mutex_lock(&fwnode_link_lock);
+ ret = __fwnode_link_add(con, sup, 0);
+ mutex_unlock(&fwnode_link_lock);
return ret;
}
@@ -114,7 +122,7 @@ out:
*/
static void __fwnode_link_del(struct fwnode_link *link)
{
- pr_debug("%pfwP Dropping the fwnode link to %pfwP\n",
+ pr_debug("%pfwf Dropping the fwnode link to %pfwf\n",
link->consumer, link->supplier);
list_del(&link->s_hook);
list_del(&link->c_hook);
@@ -122,6 +130,19 @@ static void __fwnode_link_del(struct fwnode_link *link)
}
/**
+ * __fwnode_link_cycle - Mark a fwnode link as being part of a cycle.
+ * @link: the fwnode_link to be marked
+ *
+ * The fwnode_link_lock needs to be held when this function is called.
+ */
+static void __fwnode_link_cycle(struct fwnode_link *link)
+{
+ pr_debug("%pfwf: Relaxing link with %pfwf\n",
+ link->consumer, link->supplier);
+ link->flags |= FWLINK_FLAG_CYCLE;
+}
+
+/**
* fwnode_links_purge_suppliers - Delete all supplier links of fwnode_handle.
* @fwnode: fwnode whose supplier links need to be deleted
*
@@ -181,6 +202,51 @@ void fw_devlink_purge_absent_suppliers(struct fwnode_handle *fwnode)
}
EXPORT_SYMBOL_GPL(fw_devlink_purge_absent_suppliers);
+/**
+ * __fwnode_links_move_consumers - Move consumer from @from to @to fwnode_handle
+ * @from: move consumers away from this fwnode
+ * @to: move consumers to this fwnode
+ *
+ * Move all consumer links from @from fwnode to @to fwnode.
+ */
+static void __fwnode_links_move_consumers(struct fwnode_handle *from,
+ struct fwnode_handle *to)
+{
+ struct fwnode_link *link, *tmp;
+
+ list_for_each_entry_safe(link, tmp, &from->consumers, s_hook) {
+ __fwnode_link_add(link->consumer, to, link->flags);
+ __fwnode_link_del(link);
+ }
+}
+
+/**
+ * __fw_devlink_pickup_dangling_consumers - Pick up dangling consumers
+ * @fwnode: fwnode from which to pick up dangling consumers
+ * @new_sup: fwnode of new supplier
+ *
+ * If the @fwnode has a corresponding struct device and the device supports
+ * probing (that is, added to a bus), then we want to let fw_devlink create
+ * MANAGED device links to this device, so leave @fwnode and its descendant's
+ * fwnode links alone.
+ *
+ * Otherwise, move its consumers to the new supplier @new_sup.
+ */
+static void __fw_devlink_pickup_dangling_consumers(struct fwnode_handle *fwnode,
+ struct fwnode_handle *new_sup)
+{
+ struct fwnode_handle *child;
+
+ if (fwnode->dev && fwnode->dev->bus)
+ return;
+
+ fwnode->flags |= FWNODE_FLAG_NOT_DEVICE;
+ __fwnode_links_move_consumers(fwnode, new_sup);
+
+ fwnode_for_each_available_child_node(fwnode, child)
+ __fw_devlink_pickup_dangling_consumers(child, new_sup);
+}
+
static DEFINE_MUTEX(device_links_lock);
DEFINE_STATIC_SRCU(device_links_srcu);
@@ -230,6 +296,12 @@ static bool device_is_ancestor(struct device *dev, struct device *target)
return false;
}
+static inline bool device_link_flag_is_sync_state_only(u32 flags)
+{
+ return (flags & ~(DL_FLAG_INFERRED | DL_FLAG_CYCLE)) ==
+ (DL_FLAG_SYNC_STATE_ONLY | DL_FLAG_MANAGED);
+}
+
/**
* device_is_dependent - Check if one device depends on another one
* @dev: Device to check dependencies for.
@@ -256,8 +328,7 @@ int device_is_dependent(struct device *dev, void *target)
return ret;
list_for_each_entry(link, &dev->links.consumers, s_node) {
- if ((link->flags & ~DL_FLAG_INFERRED) ==
- (DL_FLAG_SYNC_STATE_ONLY | DL_FLAG_MANAGED))
+ if (device_link_flag_is_sync_state_only(link->flags))
continue;
if (link->consumer == target)
@@ -330,8 +401,7 @@ static int device_reorder_to_tail(struct device *dev, void *not_used)
device_for_each_child(dev, NULL, device_reorder_to_tail);
list_for_each_entry(link, &dev->links.consumers, s_node) {
- if ((link->flags & ~DL_FLAG_INFERRED) ==
- (DL_FLAG_SYNC_STATE_ONLY | DL_FLAG_MANAGED))
+ if (device_link_flag_is_sync_state_only(link->flags))
continue;
device_reorder_to_tail(link->consumer, NULL);
}
@@ -592,7 +662,8 @@ postcore_initcall(devlink_class_init);
DL_FLAG_AUTOREMOVE_SUPPLIER | \
DL_FLAG_AUTOPROBE_CONSUMER | \
DL_FLAG_SYNC_STATE_ONLY | \
- DL_FLAG_INFERRED)
+ DL_FLAG_INFERRED | \
+ DL_FLAG_CYCLE)
#define DL_ADD_VALID_FLAGS (DL_MANAGED_LINK_FLAGS | DL_FLAG_STATELESS | \
DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE)
@@ -661,8 +732,6 @@ struct device_link *device_link_add(struct device *consumer,
if (!consumer || !supplier || consumer == supplier ||
flags & ~DL_ADD_VALID_FLAGS ||
(flags & DL_FLAG_STATELESS && flags & DL_MANAGED_LINK_FLAGS) ||
- (flags & DL_FLAG_SYNC_STATE_ONLY &&
- (flags & ~DL_FLAG_INFERRED) != DL_FLAG_SYNC_STATE_ONLY) ||
(flags & DL_FLAG_AUTOPROBE_CONSUMER &&
flags & (DL_FLAG_AUTOREMOVE_CONSUMER |
DL_FLAG_AUTOREMOVE_SUPPLIER)))
@@ -678,6 +747,10 @@ struct device_link *device_link_add(struct device *consumer,
if (!(flags & DL_FLAG_STATELESS))
flags |= DL_FLAG_MANAGED;
+ if (flags & DL_FLAG_SYNC_STATE_ONLY &&
+ !device_link_flag_is_sync_state_only(flags))
+ return NULL;
+
device_links_write_lock();
device_pm_lock();
@@ -942,6 +1015,21 @@ static bool dev_is_best_effort(struct device *dev)
(dev->fwnode && (dev->fwnode->flags & FWNODE_FLAG_BEST_EFFORT));
}
+static struct fwnode_handle *fwnode_links_check_suppliers(
+ struct fwnode_handle *fwnode)
+{
+ struct fwnode_link *link;
+
+ if (!fwnode || fw_devlink_is_permissive())
+ return NULL;
+
+ list_for_each_entry(link, &fwnode->suppliers, c_hook)
+ if (!(link->flags & FWLINK_FLAG_CYCLE))
+ return link->supplier;
+
+ return NULL;
+}
+
/**
* device_links_check_suppliers - Check presence of supplier drivers.
* @dev: Consumer device.
@@ -969,15 +1057,12 @@ int device_links_check_suppliers(struct device *dev)
* probe.
*/
mutex_lock(&fwnode_link_lock);
- if (dev->fwnode && !list_empty(&dev->fwnode->suppliers) &&
- !fw_devlink_is_permissive()) {
- sup_fw = list_first_entry(&dev->fwnode->suppliers,
- struct fwnode_link,
- c_hook)->supplier;
+ sup_fw = fwnode_links_check_suppliers(dev->fwnode);
+ if (sup_fw) {
if (!dev_is_best_effort(dev)) {
fwnode_ret = -EPROBE_DEFER;
dev_err_probe(dev, -EPROBE_DEFER,
- "wait for supplier %pfwP\n", sup_fw);
+ "wait for supplier %pfwf\n", sup_fw);
} else {
fwnode_ret = -EAGAIN;
}
@@ -1162,7 +1247,9 @@ static ssize_t waiting_for_supplier_show(struct device *dev,
bool val;
device_lock(dev);
- val = !list_empty(&dev->fwnode->suppliers);
+ mutex_lock(&fwnode_link_lock);
+ val = !!fwnode_links_check_suppliers(dev->fwnode);
+ mutex_unlock(&fwnode_link_lock);
device_unlock(dev);
return sysfs_emit(buf, "%u\n", val);
}
@@ -1225,16 +1312,23 @@ void device_links_driver_bound(struct device *dev)
* them. So, fw_devlink no longer needs to create device links to any
* of the device's suppliers.
*
- * Also, if a child firmware node of this bound device is not added as
- * a device by now, assume it is never going to be added and make sure
- * other devices don't defer probe indefinitely by waiting for such a
- * child device.
+ * Also, if a child firmware node of this bound device is not added as a
+ * device by now, assume it is never going to be added. Make this bound
+ * device the fallback supplier to the dangling consumers of the child
+ * firmware node because this bound device is probably implementing the
+ * child firmware node functionality and we don't want the dangling
+ * consumers to defer probe indefinitely waiting for a device for the
+ * child firmware node.
*/
if (dev->fwnode && dev->fwnode->dev == dev) {
struct fwnode_handle *child;
fwnode_links_purge_suppliers(dev->fwnode);
+ mutex_lock(&fwnode_link_lock);
fwnode_for_each_available_child_node(dev->fwnode, child)
- fw_devlink_purge_absent_suppliers(child);
+ __fw_devlink_pickup_dangling_consumers(child,
+ dev->fwnode);
+ __fw_devlink_link_to_consumers(dev);
+ mutex_unlock(&fwnode_link_lock);
}
device_remove_file(dev, &dev_attr_waiting_for_supplier);
@@ -1591,8 +1685,11 @@ static int __init fw_devlink_strict_setup(char *arg)
}
early_param("fw_devlink.strict", fw_devlink_strict_setup);
-u32 fw_devlink_get_flags(void)
+static inline u32 fw_devlink_get_flags(u8 fwlink_flags)
{
+ if (fwlink_flags & FWLINK_FLAG_CYCLE)
+ return FW_DEVLINK_FLAGS_PERMISSIVE | DL_FLAG_CYCLE;
+
return fw_devlink_flags;
}
@@ -1630,7 +1727,7 @@ static void fw_devlink_relax_link(struct device_link *link)
if (!(link->flags & DL_FLAG_INFERRED))
return;
- if (link->flags == (DL_FLAG_MANAGED | FW_DEVLINK_FLAGS_PERMISSIVE))
+ if (device_link_flag_is_sync_state_only(link->flags))
return;
pm_runtime_drop_link(link);
@@ -1727,44 +1824,138 @@ static void fw_devlink_unblock_consumers(struct device *dev)
device_links_write_unlock();
}
+
+static bool fwnode_init_without_drv(struct fwnode_handle *fwnode)
+{
+ struct device *dev;
+ bool ret;
+
+ if (!(fwnode->flags & FWNODE_FLAG_INITIALIZED))
+ return false;
+
+ dev = get_dev_from_fwnode(fwnode);
+ ret = !dev || dev->links.status == DL_DEV_NO_DRIVER;
+ put_device(dev);
+
+ return ret;
+}
+
+static bool fwnode_ancestor_init_without_drv(struct fwnode_handle *fwnode)
+{
+ struct fwnode_handle *parent;
+
+ fwnode_for_each_parent_node(fwnode, parent) {
+ if (fwnode_init_without_drv(parent)) {
+ fwnode_handle_put(parent);
+ return true;
+ }
+ }
+
+ return false;
+}
+
/**
- * fw_devlink_relax_cycle - Convert cyclic links to SYNC_STATE_ONLY links
- * @con: Device to check dependencies for.
- * @sup: Device to check against.
- *
- * Check if @sup depends on @con or any device dependent on it (its child or
- * its consumer etc). When such a cyclic dependency is found, convert all
- * device links created solely by fw_devlink into SYNC_STATE_ONLY device links.
- * This is the equivalent of doing fw_devlink=permissive just between the
- * devices in the cycle. We need to do this because, at this point, fw_devlink
- * can't tell which of these dependencies is not a real dependency.
- *
- * Return 1 if a cycle is found. Otherwise, return 0.
+ * __fw_devlink_relax_cycles - Relax and mark dependency cycles.
+ * @con: Potential consumer device.
+ * @sup_handle: Potential supplier's fwnode.
+ *
+ * Needs to be called with fwnode_lock and device link lock held.
+ *
+ * Check if @sup_handle or any of its ancestors or suppliers direct/indirectly
+ * depend on @con. This function can detect multiple cyles between @sup_handle
+ * and @con. When such dependency cycles are found, convert all device links
+ * created solely by fw_devlink into SYNC_STATE_ONLY device links. Also, mark
+ * all fwnode links in the cycle with FWLINK_FLAG_CYCLE so that when they are
+ * converted into a device link in the future, they are created as
+ * SYNC_STATE_ONLY device links. This is the equivalent of doing
+ * fw_devlink=permissive just between the devices in the cycle. We need to do
+ * this because, at this point, fw_devlink can't tell which of these
+ * dependencies is not a real dependency.
+ *
+ * Return true if one or more cycles were found. Otherwise, return false.
*/
-static int fw_devlink_relax_cycle(struct device *con, void *sup)
+static bool __fw_devlink_relax_cycles(struct device *con,
+ struct fwnode_handle *sup_handle)
{
- struct device_link *link;
- int ret;
+ struct device *sup_dev = NULL, *par_dev = NULL;
+ struct fwnode_link *link;
+ struct device_link *dev_link;
+ bool ret = false;
- if (con == sup)
- return 1;
+ if (!sup_handle)
+ return false;
- ret = device_for_each_child(con, sup, fw_devlink_relax_cycle);
- if (ret)
- return ret;
+ /*
+ * We aren't trying to find all cycles. Just a cycle between con and
+ * sup_handle.
+ */
+ if (sup_handle->flags & FWNODE_FLAG_VISITED)
+ return false;
- list_for_each_entry(link, &con->links.consumers, s_node) {
- if ((link->flags & ~DL_FLAG_INFERRED) ==
- (DL_FLAG_SYNC_STATE_ONLY | DL_FLAG_MANAGED))
- continue;
+ sup_handle->flags |= FWNODE_FLAG_VISITED;
- if (!fw_devlink_relax_cycle(link->consumer, sup))
- continue;
+ sup_dev = get_dev_from_fwnode(sup_handle);
- ret = 1;
+ /* Termination condition. */
+ if (sup_dev == con) {
+ ret = true;
+ goto out;
+ }
- fw_devlink_relax_link(link);
+ /*
+ * If sup_dev is bound to a driver and @con hasn't started binding to a
+ * driver, sup_dev can't be a consumer of @con. So, no need to check
+ * further.
+ */
+ if (sup_dev && sup_dev->links.status == DL_DEV_DRIVER_BOUND &&
+ con->links.status == DL_DEV_NO_DRIVER) {
+ ret = false;
+ goto out;
+ }
+
+ list_for_each_entry(link, &sup_handle->suppliers, c_hook) {
+ if (__fw_devlink_relax_cycles(con, link->supplier)) {
+ __fwnode_link_cycle(link);
+ ret = true;
+ }
}
+
+ /*
+ * Give priority to device parent over fwnode parent to account for any
+ * quirks in how fwnodes are converted to devices.
+ */
+ if (sup_dev)
+ par_dev = get_device(sup_dev->parent);
+ else
+ par_dev = fwnode_get_next_parent_dev(sup_handle);
+
+ if (par_dev && __fw_devlink_relax_cycles(con, par_dev->fwnode))
+ ret = true;
+
+ if (!sup_dev)
+ goto out;
+
+ list_for_each_entry(dev_link, &sup_dev->links.suppliers, c_node) {
+ /*
+ * Ignore a SYNC_STATE_ONLY flag only if it wasn't marked as
+ * such due to a cycle.
+ */
+ if (device_link_flag_is_sync_state_only(dev_link->flags) &&
+ !(dev_link->flags & DL_FLAG_CYCLE))
+ continue;
+
+ if (__fw_devlink_relax_cycles(con,
+ dev_link->supplier->fwnode)) {
+ fw_devlink_relax_link(dev_link);
+ dev_link->flags |= DL_FLAG_CYCLE;
+ ret = true;
+ }
+ }
+
+out:
+ sup_handle->flags &= ~FWNODE_FLAG_VISITED;
+ put_device(sup_dev);
+ put_device(par_dev);
return ret;
}
@@ -1772,7 +1963,7 @@ static int fw_devlink_relax_cycle(struct device *con, void *sup)
* fw_devlink_create_devlink - Create a device link from a consumer to fwnode
* @con: consumer device for the device link
* @sup_handle: fwnode handle of supplier
- * @flags: devlink flags
+ * @link: fwnode link that's being converted to a device link
*
* This function will try to create a device link between the consumer device
* @con and the supplier device represented by @sup_handle.
@@ -1789,10 +1980,17 @@ static int fw_devlink_relax_cycle(struct device *con, void *sup)
* possible to do that in the future
*/
static int fw_devlink_create_devlink(struct device *con,
- struct fwnode_handle *sup_handle, u32 flags)
+ struct fwnode_handle *sup_handle,
+ struct fwnode_link *link)
{
struct device *sup_dev;
int ret = 0;
+ u32 flags;
+
+ if (con->fwnode == link->consumer)
+ flags = fw_devlink_get_flags(link->flags);
+ else
+ flags = FW_DEVLINK_FLAGS_PERMISSIVE;
/*
* In some cases, a device P might also be a supplier to its child node
@@ -1813,7 +2011,26 @@ static int fw_devlink_create_devlink(struct device *con,
fwnode_is_ancestor_of(sup_handle, con->fwnode))
return -EINVAL;
- sup_dev = get_dev_from_fwnode(sup_handle);
+ /*
+ * SYNC_STATE_ONLY device links don't block probing and supports cycles.
+ * So cycle detection isn't necessary and shouldn't be done.
+ */
+ if (!(flags & DL_FLAG_SYNC_STATE_ONLY)) {
+ device_links_write_lock();
+ if (__fw_devlink_relax_cycles(con, sup_handle)) {
+ __fwnode_link_cycle(link);
+ flags = fw_devlink_get_flags(link->flags);
+ dev_info(con, "Fixed dependency cycle(s) with %pfwf\n",
+ sup_handle);
+ }
+ device_links_write_unlock();
+ }
+
+ if (sup_handle->flags & FWNODE_FLAG_NOT_DEVICE)
+ sup_dev = fwnode_get_next_parent_dev(sup_handle);
+ else
+ sup_dev = get_dev_from_fwnode(sup_handle);
+
if (sup_dev) {
/*
* If it's one of those drivers that don't actually bind to
@@ -1822,71 +2039,34 @@ static int fw_devlink_create_devlink(struct device *con,
*/
if (sup_dev->links.status == DL_DEV_NO_DRIVER &&
sup_handle->flags & FWNODE_FLAG_INITIALIZED) {
+ dev_dbg(con,
+ "Not linking %pfwf - dev might never probe\n",
+ sup_handle);
ret = -EINVAL;
goto out;
}
- /*
- * If this fails, it is due to cycles in device links. Just
- * give up on this link and treat it as invalid.
- */
- if (!device_link_add(con, sup_dev, flags) &&
- !(flags & DL_FLAG_SYNC_STATE_ONLY)) {
- dev_info(con, "Fixing up cyclic dependency with %s\n",
- dev_name(sup_dev));
- device_links_write_lock();
- fw_devlink_relax_cycle(con, sup_dev);
- device_links_write_unlock();
- device_link_add(con, sup_dev,
- FW_DEVLINK_FLAGS_PERMISSIVE);
+ if (con != sup_dev && !device_link_add(con, sup_dev, flags)) {
+ dev_err(con, "Failed to create device link (0x%x) with %s\n",
+ flags, dev_name(sup_dev));
ret = -EINVAL;
}
goto out;
}
- /* Supplier that's already initialized without a struct device. */
- if (sup_handle->flags & FWNODE_FLAG_INITIALIZED)
- return -EINVAL;
-
- /*
- * DL_FLAG_SYNC_STATE_ONLY doesn't block probing and supports
- * cycles. So cycle detection isn't necessary and shouldn't be
- * done.
- */
- if (flags & DL_FLAG_SYNC_STATE_ONLY)
- return -EAGAIN;
-
/*
- * If we can't find the supplier device from its fwnode, it might be
- * due to a cyclic dependency between fwnodes. Some of these cycles can
- * be broken by applying logic. Check for these types of cycles and
- * break them so that devices in the cycle probe properly.
- *
- * If the supplier's parent is dependent on the consumer, then the
- * consumer and supplier have a cyclic dependency. Since fw_devlink
- * can't tell which of the inferred dependencies are incorrect, don't
- * enforce probe ordering between any of the devices in this cyclic
- * dependency. Do this by relaxing all the fw_devlink device links in
- * this cycle and by treating the fwnode link between the consumer and
- * the supplier as an invalid dependency.
+ * Supplier or supplier's ancestor already initialized without a struct
+ * device or being probed by a driver.
*/
- sup_dev = fwnode_get_next_parent_dev(sup_handle);
- if (sup_dev && device_is_dependent(con, sup_dev)) {
- dev_info(con, "Fixing up cyclic dependency with %pfwP (%s)\n",
- sup_handle, dev_name(sup_dev));
- device_links_write_lock();
- fw_devlink_relax_cycle(con, sup_dev);
- device_links_write_unlock();
- ret = -EINVAL;
- } else {
- /*
- * Can't check for cycles or no cycles. So let's try
- * again later.
- */
- ret = -EAGAIN;
+ if (fwnode_init_without_drv(sup_handle) ||
+ fwnode_ancestor_init_without_drv(sup_handle)) {
+ dev_dbg(con, "Not linking %pfwf - might never become dev\n",
+ sup_handle);
+ return -EINVAL;
}
+ ret = -EAGAIN;
out:
put_device(sup_dev);
return ret;
@@ -1914,7 +2094,6 @@ static void __fw_devlink_link_to_consumers(struct device *dev)
struct fwnode_link *link, *tmp;
list_for_each_entry_safe(link, tmp, &fwnode->consumers, s_hook) {
- u32 dl_flags = fw_devlink_get_flags();
struct device *con_dev;
bool own_link = true;
int ret;
@@ -1944,14 +2123,13 @@ static void __fw_devlink_link_to_consumers(struct device *dev)
con_dev = NULL;
} else {
own_link = false;
- dl_flags = FW_DEVLINK_FLAGS_PERMISSIVE;
}
}
if (!con_dev)
continue;
- ret = fw_devlink_create_devlink(con_dev, fwnode, dl_flags);
+ ret = fw_devlink_create_devlink(con_dev, fwnode, link);
put_device(con_dev);
if (!own_link || ret == -EAGAIN)
continue;
@@ -1971,10 +2149,7 @@ static void __fw_devlink_link_to_consumers(struct device *dev)
*
* The function creates normal (non-SYNC_STATE_ONLY) device links between @dev
* and the real suppliers of @dev. Once these device links are created, the
- * fwnode links are deleted. When such device links are successfully created,
- * this function is called recursively on those supplier devices. This is
- * needed to detect and break some invalid cycles in fwnode links. See
- * fw_devlink_create_devlink() for more details.
+ * fwnode links are deleted.
*
* In addition, it also looks at all the suppliers of the entire fwnode tree
* because some of the child devices of @dev that have not been added yet
@@ -1992,44 +2167,16 @@ static void __fw_devlink_link_to_suppliers(struct device *dev,
bool own_link = (dev->fwnode == fwnode);
struct fwnode_link *link, *tmp;
struct fwnode_handle *child = NULL;
- u32 dl_flags;
-
- if (own_link)
- dl_flags = fw_devlink_get_flags();
- else
- dl_flags = FW_DEVLINK_FLAGS_PERMISSIVE;
list_for_each_entry_safe(link, tmp, &fwnode->suppliers, c_hook) {
int ret;
- struct device *sup_dev;
struct fwnode_handle *sup = link->supplier;
- ret = fw_devlink_create_devlink(dev, sup, dl_flags);
+ ret = fw_devlink_create_devlink(dev, sup, link);
if (!own_link || ret == -EAGAIN)
continue;
__fwnode_link_del(link);
-
- /* If no device link was created, nothing more to do. */
- if (ret)
- continue;
-
- /*
- * If a device link was successfully created to a supplier, we
- * now need to try and link the supplier to all its suppliers.
- *
- * This is needed to detect and delete false dependencies in
- * fwnode links that haven't been converted to a device link
- * yet. See comments in fw_devlink_create_devlink() for more
- * details on the false dependency.
- *
- * Without deleting these false dependencies, some devices will
- * never probe because they'll keep waiting for their false
- * dependency fwnode links to be converted to device links.
- */
- sup_dev = get_dev_from_fwnode(sup);
- __fw_devlink_link_to_suppliers(sup_dev, sup_dev->fwnode);
- put_device(sup_dev);
}
/*
@@ -2312,7 +2459,7 @@ static void device_get_ownership(const struct kobject *kobj, kuid_t *uid, kgid_t
dev->class->get_ownership(dev, uid, gid);
}
-static struct kobj_type device_ktype = {
+static const struct kobj_type device_ktype = {
.release = device_release,
.sysfs_ops = &dev_sysfs_ops,
.namespace = device_namespace,
@@ -2345,9 +2492,9 @@ static const char *dev_uevent_name(const struct kobject *kobj)
return NULL;
}
-static int dev_uevent(struct kobject *kobj, struct kobj_uevent_env *env)
+static int dev_uevent(const struct kobject *kobj, struct kobj_uevent_env *env)
{
- struct device *dev = kobj_to_dev(kobj);
+ const struct device *dev = kobj_to_dev(kobj);
int retval = 0;
/* add device node properties if present */
@@ -2950,7 +3097,7 @@ struct kobj_ns_type_operations *class_dir_child_ns_type(const struct kobject *ko
return dir->class->ns_type;
}
-static struct kobj_type class_dir_ktype = {
+static const struct kobj_type class_dir_ktype = {
.release = class_dir_release,
.sysfs_ops = &kobj_sysfs_ops,
.child_ns_type = class_dir_child_ns_type
@@ -2984,8 +3131,9 @@ static DEFINE_MUTEX(gdp_mutex);
static struct kobject *get_device_parent(struct device *dev,
struct device *parent)
{
+ struct kobject *kobj = NULL;
+
if (dev->class) {
- struct kobject *kobj = NULL;
struct kobject *parent_kobj;
struct kobject *k;
@@ -3033,8 +3181,15 @@ static struct kobject *get_device_parent(struct device *dev,
}
/* subsystems can specify a default root directory for their devices */
- if (!parent && dev->bus && dev->bus->dev_root)
- return &dev->bus->dev_root->kobj;
+ if (!parent && dev->bus) {
+ struct device *dev_root = bus_get_dev_root(dev->bus);
+
+ if (dev_root) {
+ kobj = &dev_root->kobj;
+ put_device(dev_root);
+ return kobj;
+ }
+ }
if (parent)
return &parent->kobj;
@@ -3371,7 +3526,7 @@ int device_add(struct device *dev)
/* we require the name to be set before, and pass NULL */
error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);
if (error) {
- glue_dir = get_glue_dir(dev);
+ glue_dir = kobj;
goto Error;
}
@@ -3411,10 +3566,7 @@ int device_add(struct device *dev)
/* Notify clients of device addition. This call must come
* after dpm_sysfs_add() and before kobject_uevent().
*/
- if (dev->bus)
- blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
- BUS_NOTIFY_ADD_DEVICE, dev);
-
+ bus_notify(dev, BUS_NOTIFY_ADD_DEVICE);
kobject_uevent(&dev->kobj, KOBJ_ADD);
/*
@@ -3471,6 +3623,7 @@ done:
device_pm_remove(dev);
dpm_sysfs_remove(dev);
DPMError:
+ dev->driver = NULL;
bus_remove_device(dev);
BusError:
device_remove_attrs(dev);
@@ -3594,9 +3747,7 @@ void device_del(struct device *dev)
* before dpm_sysfs_remove().
*/
noio_flag = memalloc_noio_save();
- if (dev->bus)
- blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
- BUS_NOTIFY_DEL_DEVICE, dev);
+ bus_notify(dev, BUS_NOTIFY_DEL_DEVICE);
dpm_sysfs_remove(dev);
if (parent)
@@ -3627,9 +3778,7 @@ void device_del(struct device *dev)
device_platform_notify_remove(dev);
device_links_purge(dev);
- if (dev->bus)
- blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
- BUS_NOTIFY_REMOVED_DEVICE, dev);
+ bus_notify(dev, BUS_NOTIFY_REMOVED_DEVICE);
kobject_uevent(&dev->kobj, KOBJ_REMOVE);
glue_dir = get_glue_dir(dev);
kobject_del(&dev->kobj);
@@ -3697,7 +3846,7 @@ static struct device *next_device(struct klist_iter *i)
* a name. This memory is returned in tmp and needs to be
* freed by the caller.
*/
-const char *device_get_devnode(struct device *dev,
+const char *device_get_devnode(const struct device *dev,
umode_t *mode, kuid_t *uid, kgid_t *gid,
const char **tmp)
{
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index 4c98849577d4..182c6122f815 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -125,17 +125,6 @@ static DEVICE_ATTR(release, S_IWUSR, NULL, cpu_release_store);
#endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */
#endif /* CONFIG_HOTPLUG_CPU */
-struct bus_type cpu_subsys = {
- .name = "cpu",
- .dev_name = "cpu",
- .match = cpu_subsys_match,
-#ifdef CONFIG_HOTPLUG_CPU
- .online = cpu_subsys_online,
- .offline = cpu_subsys_offline,
-#endif
-};
-EXPORT_SYMBOL_GPL(cpu_subsys);
-
#ifdef CONFIG_KEXEC
#include <linux/kexec.h>
@@ -336,7 +325,7 @@ static ssize_t print_cpu_modalias(struct device *dev,
return len;
}
-static int cpu_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int cpu_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (buf) {
@@ -348,6 +337,20 @@ static int cpu_uevent(struct device *dev, struct kobj_uevent_env *env)
}
#endif
+struct bus_type cpu_subsys = {
+ .name = "cpu",
+ .dev_name = "cpu",
+ .match = cpu_subsys_match,
+#ifdef CONFIG_HOTPLUG_CPU
+ .online = cpu_subsys_online,
+ .offline = cpu_subsys_offline,
+#endif
+#ifdef CONFIG_GENERIC_CPU_AUTOPROBE
+ .uevent = cpu_uevent,
+#endif
+};
+EXPORT_SYMBOL_GPL(cpu_subsys);
+
/*
* register_cpu - Setup a sysfs device for a CPU.
* @cpu - cpu->hotpluggable field set to 1 will generate a control file in
@@ -368,9 +371,6 @@ int register_cpu(struct cpu *cpu, int num)
cpu->dev.offline_disabled = !cpu->hotpluggable;
cpu->dev.offline = !cpu_online(num);
cpu->dev.of_node = of_get_cpu_node(num, NULL);
-#ifdef CONFIG_GENERIC_CPU_AUTOPROBE
- cpu->dev.bus->uevent = cpu_uevent;
-#endif
cpu->dev.groups = common_cpu_attr_groups;
if (cpu->hotpluggable)
cpu->dev.groups = hotplugable_cpu_attr_groups;
@@ -610,9 +610,13 @@ static const struct attribute_group cpu_root_vulnerabilities_group = {
static void __init cpu_register_vulnerabilities(void)
{
- if (sysfs_create_group(&cpu_subsys.dev_root->kobj,
- &cpu_root_vulnerabilities_group))
- pr_err("Unable to register CPU vulnerabilities\n");
+ struct device *dev = bus_get_dev_root(&cpu_subsys);
+
+ if (dev) {
+ if (sysfs_create_group(&dev->kobj, &cpu_root_vulnerabilities_group))
+ pr_err("Unable to register CPU vulnerabilities\n");
+ put_device(dev);
+ }
}
#else
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index e9b2f9c25efe..8def2ba08a82 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -257,13 +257,11 @@ static int deferred_devs_show(struct seq_file *s, void *data)
DEFINE_SHOW_ATTRIBUTE(deferred_devs);
#ifdef CONFIG_MODULES
-int driver_deferred_probe_timeout = 10;
+static int driver_deferred_probe_timeout = 10;
#else
-int driver_deferred_probe_timeout;
+static int driver_deferred_probe_timeout;
#endif
-EXPORT_SYMBOL_GPL(driver_deferred_probe_timeout);
-
static int __init deferred_probe_timeout_setup(char *str)
{
int timeout;
@@ -372,7 +370,7 @@ late_initcall(deferred_probe_initcall);
static void __exit deferred_probe_exit(void)
{
- debugfs_remove_recursive(debugfs_lookup("devices_deferred", NULL));
+ debugfs_lookup_and_remove("devices_deferred", NULL);
}
__exitcall(deferred_probe_exit);
@@ -413,10 +411,7 @@ static void driver_bound(struct device *dev)
driver_deferred_probe_del(dev);
driver_deferred_probe_trigger();
- if (dev->bus)
- blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
- BUS_NOTIFY_BOUND_DRIVER, dev);
-
+ bus_notify(dev, BUS_NOTIFY_BOUND_DRIVER);
kobject_uevent(&dev->kobj, KOBJ_BIND);
}
@@ -435,9 +430,7 @@ static int driver_sysfs_add(struct device *dev)
{
int ret;
- if (dev->bus)
- blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
- BUS_NOTIFY_BIND_DRIVER, dev);
+ bus_notify(dev, BUS_NOTIFY_BIND_DRIVER);
ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj,
kobject_name(&dev->kobj));
@@ -502,9 +495,8 @@ int device_bind_driver(struct device *dev)
device_links_force_bind(dev);
driver_bound(dev);
}
- else if (dev->bus)
- blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
- BUS_NOTIFY_DRIVER_NOT_BOUND, dev);
+ else
+ bus_notify(dev, BUS_NOTIFY_DRIVER_NOT_BOUND);
return ret;
}
EXPORT_SYMBOL_GPL(device_bind_driver);
@@ -695,9 +687,7 @@ dev_groups_failed:
probe_failed:
driver_sysfs_remove(dev);
sysfs_failed:
- if (dev->bus)
- blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
- BUS_NOTIFY_DRIVER_NOT_BOUND, dev);
+ bus_notify(dev, BUS_NOTIFY_DRIVER_NOT_BOUND);
if (dev->bus && dev->bus->dma_cleanup)
dev->bus->dma_cleanup(dev);
pinctrl_bind_failed:
@@ -1243,10 +1233,7 @@ static void __device_release_driver(struct device *dev, struct device *parent)
driver_sysfs_remove(dev);
- if (dev->bus)
- blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
- BUS_NOTIFY_UNBIND_DRIVER,
- dev);
+ bus_notify(dev, BUS_NOTIFY_UNBIND_DRIVER);
pm_runtime_put_sync(dev);
@@ -1260,11 +1247,8 @@ static void __device_release_driver(struct device *dev, struct device *parent)
klist_remove(&dev->p->knode_driver);
device_pm_check_callbacks(dev);
- if (dev->bus)
- blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
- BUS_NOTIFY_UNBOUND_DRIVER,
- dev);
+ bus_notify(dev, BUS_NOTIFY_UNBOUND_DRIVER);
kobject_uevent(&dev->kobj, KOBJ_UNBIND);
}
}
diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c
index 03e8a95f1f35..ae72d4ba8547 100644
--- a/drivers/base/devtmpfs.c
+++ b/drivers/base/devtmpfs.c
@@ -13,6 +13,8 @@
* overwrite the default setting if needed.
*/
+#define pr_fmt(fmt) "devtmpfs: " fmt
+
#include <linux/kernel.h>
#include <linux/syscalls.h>
#include <linux/mount.h>
@@ -376,9 +378,9 @@ int __init devtmpfs_mount(void)
err = init_mount("devtmpfs", "dev", "devtmpfs", DEVTMPFS_MFLAGS, NULL);
if (err)
- printk(KERN_INFO "devtmpfs: error mounting %i\n", err);
+ pr_info("error mounting %d\n", err);
else
- printk(KERN_INFO "devtmpfs: mounted\n");
+ pr_info("mounted\n");
return err;
}
@@ -460,14 +462,12 @@ int __init devtmpfs_init(void)
mnt = vfs_kern_mount(&internal_fs_type, 0, "devtmpfs", opts);
if (IS_ERR(mnt)) {
- printk(KERN_ERR "devtmpfs: unable to create devtmpfs %ld\n",
- PTR_ERR(mnt));
+ pr_err("unable to create devtmpfs %ld\n", PTR_ERR(mnt));
return PTR_ERR(mnt);
}
err = register_filesystem(&dev_fs_type);
if (err) {
- printk(KERN_ERR "devtmpfs: unable to register devtmpfs "
- "type %i\n", err);
+ pr_err("unable to register devtmpfs type %d\n", err);
return err;
}
@@ -480,12 +480,12 @@ int __init devtmpfs_init(void)
}
if (err) {
- printk(KERN_ERR "devtmpfs: unable to create devtmpfs %i\n", err);
+ pr_err("unable to create devtmpfs %d\n", err);
unregister_filesystem(&dev_fs_type);
thread = NULL;
return err;
}
- printk(KERN_INFO "devtmpfs: initialized\n");
+ pr_info("initialized\n");
return 0;
}
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index 676b6275d5b5..c8436c26ed6a 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -224,7 +224,7 @@ int driver_register(struct device_driver *drv)
int ret;
struct device_driver *other;
- if (!drv->bus->p) {
+ if (!bus_is_registered(drv->bus)) {
pr_err("Driver '%s' was unable to register with bus_type '%s' because the bus was not initialized.\n",
drv->name, drv->bus->name);
return -EINVAL;
@@ -274,30 +274,3 @@ void driver_unregister(struct device_driver *drv)
bus_remove_driver(drv);
}
EXPORT_SYMBOL_GPL(driver_unregister);
-
-/**
- * driver_find - locate driver on a bus by its name.
- * @name: name of the driver.
- * @bus: bus to scan for the driver.
- *
- * Call kset_find_obj() to iterate over list of drivers on
- * a bus to find driver by name. Return driver if found.
- *
- * This routine provides no locking to prevent the driver it returns
- * from being unregistered or unloaded while the caller is using it.
- * The caller is responsible for preventing this.
- */
-struct device_driver *driver_find(const char *name, struct bus_type *bus)
-{
- struct kobject *k = kset_find_obj(bus->p->drivers_kset, name);
- struct driver_private *priv;
-
- if (k) {
- /* Drop reference added by kset_find_obj() */
- kobject_put(k);
- priv = to_driver(k);
- return priv->driver;
- }
- return NULL;
-}
-EXPORT_SYMBOL_GPL(driver_find);
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index fe98fb8d94e5..b456ac213610 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -115,18 +115,13 @@ unsigned long __weak memory_block_size_bytes(void)
}
EXPORT_SYMBOL_GPL(memory_block_size_bytes);
-/*
- * Show the first physical section index (number) of this memory block.
- */
+/* Show the memory block ID, relative to the memory block size */
static ssize_t phys_index_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct memory_block *mem = to_memory_block(dev);
- unsigned long phys_index;
-
- phys_index = mem->start_section_nr / sections_per_block;
- return sysfs_emit(buf, "%08lx\n", phys_index);
+ return sysfs_emit(buf, "%08lx\n", memory_block_id(mem->start_section_nr));
}
/*
diff --git a/drivers/base/node.c b/drivers/base/node.c
index faf3597a96da..b46db17124f3 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -587,6 +587,9 @@ static const struct attribute_group *node_dev_groups[] = {
#ifdef CONFIG_HAVE_ARCH_NODE_DEV_GROUP
&arch_node_dev_group,
#endif
+#ifdef CONFIG_MEMORY_FAILURE
+ &memory_failure_attr_group,
+#endif
NULL
};
diff --git a/drivers/base/physical_location.c b/drivers/base/physical_location.c
index 87af641cfe1a..951819e71b4a 100644
--- a/drivers/base/physical_location.c
+++ b/drivers/base/physical_location.c
@@ -24,8 +24,11 @@ bool dev_add_physical_location(struct device *dev)
dev->physical_location =
kzalloc(sizeof(*dev->physical_location), GFP_KERNEL);
- if (!dev->physical_location)
+ if (!dev->physical_location) {
+ ACPI_FREE(pld);
return false;
+ }
+
dev->physical_location->panel = pld->panel;
dev->physical_location->vertical_position = pld->vertical_position;
dev->physical_location->horizontal_position = pld->horizontal_position;
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 968f3d71eeab..77510e4f47de 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -441,11 +441,9 @@ static int __platform_get_irq_byname(struct platform_device *dev,
struct resource *r;
int ret;
- if (!dev->dev.of_node || IS_ENABLED(CONFIG_OF_IRQ)) {
- ret = fwnode_irq_get_byname(dev_fwnode(&dev->dev), name);
- if (ret > 0 || ret == -EPROBE_DEFER)
- return ret;
- }
+ ret = fwnode_irq_get_byname(dev_fwnode(&dev->dev), name);
+ if (ret > 0 || ret == -EPROBE_DEFER)
+ return ret;
r = platform_get_resource_byname(dev, IORESOURCE_IRQ, name);
if (r) {
@@ -499,6 +497,8 @@ EXPORT_SYMBOL_GPL(platform_get_irq_byname_optional);
* platform_add_devices - add a numbers of platform devices
* @devs: array of platform devices to add
* @num: number of platform devices in array
+ *
+ * Return: 0 on success, negative error number on failure.
*/
int platform_add_devices(struct platform_device **devs, int num)
{
@@ -883,6 +883,13 @@ static int platform_probe_fail(struct platform_device *pdev)
return -ENXIO;
}
+static int is_bound_to_driver(struct device *dev, void *driver)
+{
+ if (dev->driver == driver)
+ return 1;
+ return 0;
+}
+
/**
* __platform_driver_probe - register driver for non-hotpluggable device
* @drv: platform driver structure
@@ -906,7 +913,7 @@ static int platform_probe_fail(struct platform_device *pdev)
int __init_or_module __platform_driver_probe(struct platform_driver *drv,
int (*probe)(struct platform_device *), struct module *module)
{
- int retval, code;
+ int retval;
if (drv->driver.probe_type == PROBE_PREFER_ASYNCHRONOUS) {
pr_err("%s: drivers registered with %s can not be probed asynchronously\n",
@@ -932,24 +939,21 @@ int __init_or_module __platform_driver_probe(struct platform_driver *drv,
/* temporary section violation during probe() */
drv->probe = probe;
- retval = code = __platform_driver_register(drv, module);
+ retval = __platform_driver_register(drv, module);
if (retval)
return retval;
- /*
- * Fixup that section violation, being paranoid about code scanning
- * the list of drivers in order to probe new devices. Check to see
- * if the probe was successful, and make sure any forced probes of
- * new devices fail.
- */
- spin_lock(&drv->driver.bus->p->klist_drivers.k_lock);
+ /* Force all new probes of this driver to fail */
drv->probe = platform_probe_fail;
- if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list))
- retval = -ENODEV;
- spin_unlock(&drv->driver.bus->p->klist_drivers.k_lock);
- if (code != retval)
+ /* Walk all platform devices and see if any actually bound to this driver.
+ * If not, return an error as the device should have done so by now.
+ */
+ if (!bus_for_each_dev(&platform_bus_type, NULL, &drv->driver, is_bound_to_driver)) {
+ retval = -ENODEV;
platform_driver_unregister(drv);
+ }
+
return retval;
}
EXPORT_SYMBOL_GPL(__platform_driver_probe);
@@ -1353,9 +1357,9 @@ static int platform_match(struct device *dev, struct device_driver *drv)
return (strcmp(pdev->name, drv->name) == 0);
}
-static int platform_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int platform_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct platform_device *pdev = to_platform_device(dev);
+ const struct platform_device *pdev = to_platform_device(dev);
int rc;
/* Some devices have extra OF data and an OF-style MODALIAS */
@@ -1416,7 +1420,9 @@ static void platform_remove(struct device *_dev)
struct platform_driver *drv = to_platform_driver(_dev->driver);
struct platform_device *dev = to_platform_device(_dev);
- if (drv->remove) {
+ if (drv->remove_new) {
+ drv->remove_new(dev);
+ } else if (drv->remove) {
int ret = drv->remove(dev);
if (ret)
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 6097644ebdc5..32084e38b73d 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -516,6 +516,31 @@ ktime_t dev_pm_genpd_get_next_hrtimer(struct device *dev)
}
EXPORT_SYMBOL_GPL(dev_pm_genpd_get_next_hrtimer);
+/*
+ * dev_pm_genpd_synced_poweroff - Next power off should be synchronous
+ *
+ * @dev: A device that is attached to the genpd.
+ *
+ * Allows a consumer of the genpd to notify the provider that the next power off
+ * should be synchronous.
+ *
+ * It is assumed that the users guarantee that the genpd wouldn't be detached
+ * while this routine is getting called.
+ */
+void dev_pm_genpd_synced_poweroff(struct device *dev)
+{
+ struct generic_pm_domain *genpd;
+
+ genpd = dev_to_genpd_safe(dev);
+ if (!genpd)
+ return;
+
+ genpd_lock(genpd);
+ genpd->synced_poweroff = true;
+ genpd_unlock(genpd);
+}
+EXPORT_SYMBOL_GPL(dev_pm_genpd_synced_poweroff);
+
static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed)
{
unsigned int state_idx = genpd->state_idx;
@@ -559,6 +584,7 @@ static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed)
out:
raw_notifier_call_chain(&genpd->power_notifiers, GENPD_NOTIFY_ON, NULL);
+ genpd->synced_poweroff = false;
return 0;
err:
raw_notifier_call_chain(&genpd->power_notifiers, GENPD_NOTIFY_OFF,
diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c
index a8f185430a07..8c903b8c9714 100644
--- a/drivers/base/regmap/regmap-irq.c
+++ b/drivers/base/regmap/regmap-irq.c
@@ -189,12 +189,8 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
if (!d->type_buf_def[i])
continue;
reg = d->get_irq_reg(d, d->chip->type_base, i);
- if (d->chip->type_invert)
- ret = regmap_update_bits(d->map, reg,
- d->type_buf_def[i], ~d->type_buf[i]);
- else
- ret = regmap_update_bits(d->map, reg,
- d->type_buf_def[i], d->type_buf[i]);
+ ret = regmap_update_bits(d->map, reg,
+ d->type_buf_def[i], d->type_buf[i]);
if (ret != 0)
dev_err(d->map->dev, "Failed to sync type in %x\n",
reg);
@@ -882,20 +878,6 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
*/
dev_warn(map->dev, "mask_base and unmask_base are inverted, please fix it");
- /* Might as well warn about mask_invert while we're at it... */
- if (chip->mask_invert)
- dev_warn(map->dev, "mask_invert=true ignored");
-
- d->mask_base = chip->unmask_base;
- d->unmask_base = chip->mask_base;
- } else if (chip->mask_invert) {
- /*
- * Swap the roles of mask_base and unmask_base if the bits are
- * inverted. This is deprecated, drivers should use unmask_base
- * directly.
- */
- dev_warn(map->dev, "mask_invert=true is deprecated; please switch to unmask_base");
-
d->mask_base = chip->unmask_base;
d->unmask_base = chip->mask_base;
} else {
@@ -1028,9 +1010,6 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
ret = regmap_read(map, reg, &d->type_buf_def[i]);
- if (d->chip->type_invert)
- d->type_buf_def[i] = ~d->type_buf_def[i];
-
if (ret) {
dev_err(map->dev, "Failed to get type defaults at 0x%x: %d\n",
reg, ret);
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index d12d669157f2..d2a54eb0efd9 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -1942,6 +1942,8 @@ static int _regmap_bus_reg_write(void *context, unsigned int reg,
{
struct regmap *map = context;
+ reg += map->reg_base;
+ reg >>= map->format.reg_downshift;
return map->bus->reg_write(map->bus_context, reg, val);
}
@@ -2840,6 +2842,8 @@ static int _regmap_bus_reg_read(void *context, unsigned int reg,
{
struct regmap *map = context;
+ reg += map->reg_base;
+ reg >>= map->format.reg_downshift;
return map->bus->reg_read(map->bus_context, reg, val);
}
@@ -3231,6 +3235,8 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
*change = false;
if (regmap_volatile(map, reg) && map->reg_update_bits) {
+ reg += map->reg_base;
+ reg >>= map->format.reg_downshift;
ret = map->reg_update_bits(map->bus_context, reg, mask, val);
if (ret == 0 && change)
*change = true;
diff --git a/drivers/base/soc.c b/drivers/base/soc.c
index 22130b5f789d..0fb1d4ab9d8a 100644
--- a/drivers/base/soc.c
+++ b/drivers/base/soc.c
@@ -30,6 +30,7 @@ struct soc_device {
static struct bus_type soc_bus_type = {
.name = "soc",
};
+static bool soc_bus_registered;
static DEVICE_ATTR(machine, 0444, soc_info_show, NULL);
static DEVICE_ATTR(family, 0444, soc_info_show, NULL);
@@ -117,7 +118,7 @@ struct soc_device *soc_device_register(struct soc_device_attribute *soc_dev_attr
const struct attribute_group **soc_attr_groups;
int ret;
- if (!soc_bus_type.p) {
+ if (!soc_bus_registered) {
if (early_soc_dev_attr)
return ERR_PTR(-EBUSY);
early_soc_dev_attr = soc_dev_attr;
@@ -183,6 +184,7 @@ static int __init soc_bus_register(void)
ret = bus_register(&soc_bus_type);
if (ret)
return ret;
+ soc_bus_registered = true;
if (early_soc_dev_attr)
return PTR_ERR(soc_device_register(early_soc_dev_attr));
diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c
index 0a482212c7e8..1886995a0b3a 100644
--- a/drivers/base/swnode.c
+++ b/drivers/base/swnode.c
@@ -760,7 +760,7 @@ static void software_node_release(struct kobject *kobj)
kfree(swnode);
}
-static struct kobj_type software_node_type = {
+static const struct kobj_type software_node_type = {
.release = software_node_release,
.sysfs_ops = &kobj_sysfs_ops,
};
@@ -820,67 +820,6 @@ swnode_register(const struct software_node *node, struct swnode *parent,
}
/**
- * software_node_register_nodes - Register an array of software nodes
- * @nodes: Zero terminated array of software nodes to be registered
- *
- * Register multiple software nodes at once. If any node in the array
- * has its .parent pointer set (which can only be to another software_node),
- * then its parent **must** have been registered before it is; either outside
- * of this function or by ordering the array such that parent comes before
- * child.
- */
-int software_node_register_nodes(const struct software_node *nodes)
-{
- int ret;
- int i;
-
- for (i = 0; nodes[i].name; i++) {
- const struct software_node *parent = nodes[i].parent;
-
- if (parent && !software_node_to_swnode(parent)) {
- ret = -EINVAL;
- goto err_unregister_nodes;
- }
-
- ret = software_node_register(&nodes[i]);
- if (ret)
- goto err_unregister_nodes;
- }
-
- return 0;
-
-err_unregister_nodes:
- software_node_unregister_nodes(nodes);
- return ret;
-}
-EXPORT_SYMBOL_GPL(software_node_register_nodes);
-
-/**
- * software_node_unregister_nodes - Unregister an array of software nodes
- * @nodes: Zero terminated array of software nodes to be unregistered
- *
- * Unregister multiple software nodes at once. If parent pointers are set up
- * in any of the software nodes then the array **must** be ordered such that
- * parents come before their children.
- *
- * NOTE: If you are uncertain whether the array is ordered such that
- * parents will be unregistered before their children, it is wiser to
- * remove the nodes individually, in the correct order (child before
- * parent).
- */
-void software_node_unregister_nodes(const struct software_node *nodes)
-{
- unsigned int i = 0;
-
- while (nodes[i].name)
- i++;
-
- while (i--)
- software_node_unregister(&nodes[i]);
-}
-EXPORT_SYMBOL_GPL(software_node_unregister_nodes);
-
-/**
* software_node_register_node_group - Register a group of software nodes
* @node_group: NULL terminated array of software node pointers to be registered
*
diff --git a/drivers/base/test/property-entry-test.c b/drivers/base/test/property-entry-test.c
index 6071d5bc128c..dd2b606d76a3 100644
--- a/drivers/base/test/property-entry-test.c
+++ b/drivers/base/test/property-entry-test.c
@@ -405,20 +405,18 @@ static void pe_test_move_inline_str(struct kunit *test)
/* Handling of reference properties */
static void pe_test_reference(struct kunit *test)
{
- static const struct software_node nodes[] = {
- { .name = "1", },
- { .name = "2", },
- { }
- };
+ static const struct software_node node1 = { .name = "1" };
+ static const struct software_node node2 = { .name = "2" };
+ static const struct software_node *group[] = { &node1, &node2, NULL };
static const struct software_node_ref_args refs[] = {
- SOFTWARE_NODE_REFERENCE(&nodes[0]),
- SOFTWARE_NODE_REFERENCE(&nodes[1], 3, 4),
+ SOFTWARE_NODE_REFERENCE(&node1),
+ SOFTWARE_NODE_REFERENCE(&node2, 3, 4),
};
const struct property_entry entries[] = {
- PROPERTY_ENTRY_REF("ref-1", &nodes[0]),
- PROPERTY_ENTRY_REF("ref-2", &nodes[1], 1, 2),
+ PROPERTY_ENTRY_REF("ref-1", &node1),
+ PROPERTY_ENTRY_REF("ref-2", &node2, 1, 2),
PROPERTY_ENTRY_REF_ARRAY("ref-3", refs),
{ }
};
@@ -427,7 +425,7 @@ static void pe_test_reference(struct kunit *test)
struct fwnode_reference_args ref;
int error;
- error = software_node_register_nodes(nodes);
+ error = software_node_register_node_group(group);
KUNIT_ASSERT_EQ(test, error, 0);
node = fwnode_create_software_node(entries, NULL);
@@ -436,7 +434,7 @@ static void pe_test_reference(struct kunit *test)
error = fwnode_property_get_reference_args(node, "ref-1", NULL,
0, 0, &ref);
KUNIT_ASSERT_EQ(test, error, 0);
- KUNIT_EXPECT_PTR_EQ(test, to_software_node(ref.fwnode), &nodes[0]);
+ KUNIT_EXPECT_PTR_EQ(test, to_software_node(ref.fwnode), &node1);
KUNIT_EXPECT_EQ(test, ref.nargs, 0U);
/* wrong index */
@@ -447,7 +445,7 @@ static void pe_test_reference(struct kunit *test)
error = fwnode_property_get_reference_args(node, "ref-2", NULL,
1, 0, &ref);
KUNIT_ASSERT_EQ(test, error, 0);
- KUNIT_EXPECT_PTR_EQ(test, to_software_node(ref.fwnode), &nodes[1]);
+ KUNIT_EXPECT_PTR_EQ(test, to_software_node(ref.fwnode), &node2);
KUNIT_EXPECT_EQ(test, ref.nargs, 1U);
KUNIT_EXPECT_EQ(test, ref.args[0], 1LLU);
@@ -455,7 +453,7 @@ static void pe_test_reference(struct kunit *test)
error = fwnode_property_get_reference_args(node, "ref-2", NULL,
3, 0, &ref);
KUNIT_ASSERT_EQ(test, error, 0);
- KUNIT_EXPECT_PTR_EQ(test, to_software_node(ref.fwnode), &nodes[1]);
+ KUNIT_EXPECT_PTR_EQ(test, to_software_node(ref.fwnode), &node2);
KUNIT_EXPECT_EQ(test, ref.nargs, 3U);
KUNIT_EXPECT_EQ(test, ref.args[0], 1LLU);
KUNIT_EXPECT_EQ(test, ref.args[1], 2LLU);
@@ -470,14 +468,14 @@ static void pe_test_reference(struct kunit *test)
error = fwnode_property_get_reference_args(node, "ref-3", NULL,
0, 0, &ref);
KUNIT_ASSERT_EQ(test, error, 0);
- KUNIT_EXPECT_PTR_EQ(test, to_software_node(ref.fwnode), &nodes[0]);
+ KUNIT_EXPECT_PTR_EQ(test, to_software_node(ref.fwnode), &node1);
KUNIT_EXPECT_EQ(test, ref.nargs, 0U);
/* second reference in the array */
error = fwnode_property_get_reference_args(node, "ref-3", NULL,
2, 1, &ref);
KUNIT_ASSERT_EQ(test, error, 0);
- KUNIT_EXPECT_PTR_EQ(test, to_software_node(ref.fwnode), &nodes[1]);
+ KUNIT_EXPECT_PTR_EQ(test, to_software_node(ref.fwnode), &node2);
KUNIT_EXPECT_EQ(test, ref.nargs, 2U);
KUNIT_EXPECT_EQ(test, ref.args[0], 3LLU);
KUNIT_EXPECT_EQ(test, ref.args[1], 4LLU);
@@ -488,7 +486,7 @@ static void pe_test_reference(struct kunit *test)
KUNIT_EXPECT_NE(test, error, 0);
fwnode_remove_software_node(node);
- software_node_unregister_nodes(nodes);
+ software_node_unregister_node_group(group);
}
static struct kunit_case property_entry_test_cases[] = {
diff --git a/drivers/base/transport_class.c b/drivers/base/transport_class.c
index ccc86206e508..09ee2a1e35bb 100644
--- a/drivers/base/transport_class.c
+++ b/drivers/base/transport_class.c
@@ -155,12 +155,27 @@ static int transport_add_class_device(struct attribute_container *cont,
struct device *dev,
struct device *classdev)
{
+ struct transport_class *tclass = class_to_transport_class(cont->class);
int error = attribute_container_add_class_device(classdev);
struct transport_container *tcont =
attribute_container_to_transport_container(cont);
- if (!error && tcont->statistics)
+ if (error)
+ goto err_remove;
+
+ if (tcont->statistics) {
error = sysfs_create_group(&classdev->kobj, tcont->statistics);
+ if (error)
+ goto err_del;
+ }
+
+ return 0;
+
+err_del:
+ attribute_container_class_device_del(classdev);
+err_remove:
+ if (tclass->remove)
+ tclass->remove(tcont, dev, classdev);
return error;
}
diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
index 0a8469e0b13a..7b39f010bbb3 100644
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -28,7 +28,7 @@ static DEFINE_MUTEX(bcma_buses_mutex);
static int bcma_bus_match(struct device *dev, struct device_driver *drv);
static int bcma_device_probe(struct device *dev);
static void bcma_device_remove(struct device *dev);
-static int bcma_device_uevent(struct device *dev, struct kobj_uevent_env *env);
+static int bcma_device_uevent(const struct device *dev, struct kobj_uevent_env *env);
static ssize_t manuf_show(struct device *dev, struct device_attribute *attr, char *buf)
{
@@ -627,9 +627,9 @@ static void bcma_device_remove(struct device *dev)
put_device(dev);
}
-static int bcma_device_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int bcma_device_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct bcma_device *core = container_of(dev, struct bcma_device, dev);
+ const struct bcma_device *core = container_of_const(dev, struct bcma_device, dev);
return add_uevent_var(env,
"MODALIAS=bcma:m%04Xid%04Xrev%02Xcl%02X",
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index a41145d52de9..f79f20430ef7 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -103,35 +103,6 @@ config GDROM
Most users will want to say "Y" here.
You can also build this as a module which will be called gdrom.
-config PARIDE
- tristate "Parallel port IDE device support"
- depends on PARPORT_PC
- help
- There are many external CD-ROM and disk devices that connect through
- your computer's parallel port. Most of them are actually IDE devices
- using a parallel port IDE adapter. This option enables the PARIDE
- subsystem which contains drivers for many of these external drives.
- Read <file:Documentation/admin-guide/blockdev/paride.rst> for more information.
-
- If you have said Y to the "Parallel-port support" configuration
- option, you may share a single port between your printer and other
- parallel port devices. Answer Y to build PARIDE support into your
- kernel, or M if you would like to build it as a loadable module. If
- your parallel port support is in a loadable module, you must build
- PARIDE as a module. If you built PARIDE support into your kernel,
- you may still build the individual protocol modules and high-level
- drivers as loadable modules. If you build this support as a module,
- it will be called paride.
-
- To use the PARIDE support, you must say Y or M here and also to at
- least one high-level driver (e.g. "Parallel port IDE disks",
- "Parallel port ATAPI CD-ROMs", "Parallel port ATAPI disks" etc.) and
- to at least one protocol driver (e.g. "ATEN EH-100 protocol",
- "MicroSolutions backpack protocol", "DataStor Commuter protocol"
- etc.).
-
-source "drivers/block/paride/Kconfig"
-
source "drivers/block/mtip32xx/Kconfig"
source "drivers/block/zram/Kconfig"
diff --git a/drivers/block/brd.c b/drivers/block/brd.c
index a8a77a1efe1e..34177f1bd97d 100644
--- a/drivers/block/brd.c
+++ b/drivers/block/brd.c
@@ -315,23 +315,9 @@ static void brd_submit_bio(struct bio *bio)
bio_endio(bio);
}
-static int brd_rw_page(struct block_device *bdev, sector_t sector,
- struct page *page, enum req_op op)
-{
- struct brd_device *brd = bdev->bd_disk->private_data;
- int err;
-
- if (PageTransHuge(page))
- return -ENOTSUPP;
- err = brd_do_bvec(brd, page, PAGE_SIZE, 0, op, sector);
- page_endio(page, op_is_write(op), err);
- return err;
-}
-
static const struct block_device_operations brd_fops = {
.owner = THIS_MODULE,
.submit_bio = brd_submit_bio,
- .rw_page = brd_rw_page,
};
/*
@@ -417,6 +403,7 @@ static int brd_alloc(int i)
/* Tell the block layer that this is not a rotational device */
blk_queue_flag_set(QUEUE_FLAG_NONROT, disk->queue);
+ blk_queue_flag_set(QUEUE_FLAG_SYNCHRONOUS, disk->queue);
blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, disk->queue);
blk_queue_flag_set(QUEUE_FLAG_NOWAIT, disk->queue);
err = add_disk(disk);
diff --git a/drivers/block/paride/Kconfig b/drivers/block/paride/Kconfig
deleted file mode 100644
index a295634597ba..000000000000
--- a/drivers/block/paride/Kconfig
+++ /dev/null
@@ -1,302 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-#
-# PARIDE configuration
-#
-# PARIDE doesn't need PARPORT, but if PARPORT is configured as a module,
-# PARIDE must also be a module.
-# PARIDE only supports PC style parports. Tough for USB or other parports...
-
-comment "Parallel IDE high-level drivers"
- depends on PARIDE
-
-config PARIDE_PD
- tristate "Parallel port IDE disks"
- depends on PARIDE
- help
- This option enables the high-level driver for IDE-type disk devices
- connected through a parallel port. If you chose to build PARIDE
- support into your kernel, you may answer Y here to build in the
- parallel port IDE driver, otherwise you should answer M to build
- it as a loadable module. The module will be called pd. You
- must also have at least one parallel port protocol driver in your
- system. Among the devices supported by this driver are the SyQuest
- EZ-135, EZ-230 and SparQ drives, the Avatar Shark and the backpack
- hard drives from MicroSolutions.
-
-config PARIDE_PCD
- tristate "Parallel port ATAPI CD-ROMs"
- depends on PARIDE
- select CDROM
- help
- This option enables the high-level driver for ATAPI CD-ROM devices
- connected through a parallel port. If you chose to build PARIDE
- support into your kernel, you may answer Y here to build in the
- parallel port ATAPI CD-ROM driver, otherwise you should answer M to
- build it as a loadable module. The module will be called pcd. You
- must also have at least one parallel port protocol driver in your
- system. Among the devices supported by this driver are the
- MicroSolutions backpack CD-ROM drives and the Freecom Power CD. If
- you have such a CD-ROM drive, you should also say Y or M to "ISO
- 9660 CD-ROM file system support" below, because that's the file
- system used on CD-ROMs.
-
-config PARIDE_PF
- tristate "Parallel port ATAPI disks"
- depends on PARIDE
- help
- This option enables the high-level driver for ATAPI disk devices
- connected through a parallel port. If you chose to build PARIDE
- support into your kernel, you may answer Y here to build in the
- parallel port ATAPI disk driver, otherwise you should answer M
- to build it as a loadable module. The module will be called pf.
- You must also have at least one parallel port protocol driver in
- your system. Among the devices supported by this driver are the
- MicroSolutions backpack PD/CD drive and the Imation Superdisk
- LS-120 drive.
-
-config PARIDE_PT
- tristate "Parallel port ATAPI tapes"
- depends on PARIDE
- help
- This option enables the high-level driver for ATAPI tape devices
- connected through a parallel port. If you chose to build PARIDE
- support into your kernel, you may answer Y here to build in the
- parallel port ATAPI disk driver, otherwise you should answer M
- to build it as a loadable module. The module will be called pt.
- You must also have at least one parallel port protocol driver in
- your system. Among the devices supported by this driver is the
- parallel port version of the HP 5GB drive.
-
-config PARIDE_PG
- tristate "Parallel port generic ATAPI devices"
- depends on PARIDE
- help
- This option enables a special high-level driver for generic ATAPI
- devices connected through a parallel port. The driver allows user
- programs, such as cdrtools, to send ATAPI commands directly to a
- device.
-
- If you chose to build PARIDE support into your kernel, you may
- answer Y here to build in the parallel port generic ATAPI driver,
- otherwise you should answer M to build it as a loadable module. The
- module will be called pg.
-
- You must also have at least one parallel port protocol driver in
- your system.
-
- This driver implements an API loosely related to the generic SCSI
- driver. See <file:include/linux/pg.h>. for details.
-
- You can obtain the most recent version of cdrtools from
- <ftp://ftp.berlios.de/pub/cdrecord/>. Versions 1.6.1a3 and
- later fully support this driver.
-
-comment "Parallel IDE protocol modules"
- depends on PARIDE
-
-config PARIDE_ATEN
- tristate "ATEN EH-100 protocol"
- depends on PARIDE
- help
- This option enables support for the ATEN EH-100 parallel port IDE
- protocol. This protocol is used in some inexpensive low performance
- parallel port kits made in Hong Kong. If you chose to build PARIDE
- support into your kernel, you may answer Y here to build in the
- protocol driver, otherwise you should answer M to build it as a
- loadable module. The module will be called aten. You must also
- have a high-level driver for the type of device that you want to
- support.
-
-config PARIDE_BPCK
- tristate "MicroSolutions backpack (Series 5) protocol"
- depends on PARIDE
- help
- This option enables support for the Micro Solutions BACKPACK
- parallel port Series 5 IDE protocol. (Most BACKPACK drives made
- before 1999 were Series 5) Series 5 drives will NOT always have the
- Series noted on the bottom of the drive. Series 6 drivers will.
-
- In other words, if your BACKPACK drive doesn't say "Series 6" on the
- bottom, enable this option.
-
- If you chose to build PARIDE support into your kernel, you may
- answer Y here to build in the protocol driver, otherwise you should
- answer M to build it as a loadable module. The module will be
- called bpck. You must also have a high-level driver for the type
- of device that you want to support.
-
-config PARIDE_BPCK6
- tristate "MicroSolutions backpack (Series 6) protocol"
- depends on PARIDE && !64BIT
- help
- This option enables support for the Micro Solutions BACKPACK
- parallel port Series 6 IDE protocol. (Most BACKPACK drives made
- after 1999 were Series 6) Series 6 drives will have the Series noted
- on the bottom of the drive. Series 5 drivers don't always have it
- noted.
-
- In other words, if your BACKPACK drive says "Series 6" on the
- bottom, enable this option.
-
- If you chose to build PARIDE support into your kernel, you may
- answer Y here to build in the protocol driver, otherwise you should
- answer M to build it as a loadable module. The module will be
- called bpck6. You must also have a high-level driver for the type
- of device that you want to support.
-
-config PARIDE_COMM
- tristate "DataStor Commuter protocol"
- depends on PARIDE
- help
- This option enables support for the Commuter parallel port IDE
- protocol from DataStor. If you chose to build PARIDE support
- into your kernel, you may answer Y here to build in the protocol
- driver, otherwise you should answer M to build it as a loadable
- module. The module will be called comm. You must also have
- a high-level driver for the type of device that you want to support.
-
-config PARIDE_DSTR
- tristate "DataStor EP-2000 protocol"
- depends on PARIDE
- help
- This option enables support for the EP-2000 parallel port IDE
- protocol from DataStor. If you chose to build PARIDE support
- into your kernel, you may answer Y here to build in the protocol
- driver, otherwise you should answer M to build it as a loadable
- module. The module will be called dstr. You must also have
- a high-level driver for the type of device that you want to support.
-
-config PARIDE_FIT2
- tristate "FIT TD-2000 protocol"
- depends on PARIDE
- help
- This option enables support for the TD-2000 parallel port IDE
- protocol from Fidelity International Technology. This is a simple
- (low speed) adapter that is used in some portable hard drives. If
- you chose to build PARIDE support into your kernel, you may answer Y
- here to build in the protocol driver, otherwise you should answer M
- to build it as a loadable module. The module will be called ktti.
- You must also have a high-level driver for the type of device that
- you want to support.
-
-config PARIDE_FIT3
- tristate "FIT TD-3000 protocol"
- depends on PARIDE
- help
- This option enables support for the TD-3000 parallel port IDE
- protocol from Fidelity International Technology. This protocol is
- used in newer models of their portable disk, CD-ROM and PD/CD
- devices. If you chose to build PARIDE support into your kernel, you
- may answer Y here to build in the protocol driver, otherwise you
- should answer M to build it as a loadable module. The module will be
- called fit3. You must also have a high-level driver for the type
- of device that you want to support.
-
-config PARIDE_EPAT
- tristate "Shuttle EPAT/EPEZ protocol"
- depends on PARIDE
- help
- This option enables support for the EPAT parallel port IDE protocol.
- EPAT is a parallel port IDE adapter manufactured by Shuttle
- Technology and widely used in devices from major vendors such as
- Hewlett-Packard, SyQuest, Imation and Avatar. If you chose to build
- PARIDE support into your kernel, you may answer Y here to build in
- the protocol driver, otherwise you should answer M to build it as a
- loadable module. The module will be called epat. You must also
- have a high-level driver for the type of device that you want to
- support.
-
-config PARIDE_EPATC8
- bool "Support c7/c8 chips"
- depends on PARIDE_EPAT
- help
- This option enables support for the newer Shuttle EP1284 (aka c7 and
- c8) chip. You need this if you are using any recent Imation SuperDisk
- (LS-120) drive.
-
-config PARIDE_EPIA
- tristate "Shuttle EPIA protocol"
- depends on PARIDE
- help
- This option enables support for the (obsolete) EPIA parallel port
- IDE protocol from Shuttle Technology. This adapter can still be
- found in some no-name kits. If you chose to build PARIDE support
- into your kernel, you may answer Y here to build in the protocol
- driver, otherwise you should answer M to build it as a loadable
- module. The module will be called epia. You must also have a
- high-level driver for the type of device that you want to support.
-
-config PARIDE_FRIQ
- tristate "Freecom IQ ASIC-2 protocol"
- depends on PARIDE
- help
- This option enables support for version 2 of the Freecom IQ parallel
- port IDE adapter. This adapter is used by the Maxell Superdisk
- drive. If you chose to build PARIDE support into your kernel, you
- may answer Y here to build in the protocol driver, otherwise you
- should answer M to build it as a loadable module. The module will be
- called friq. You must also have a high-level driver for the type
- of device that you want to support.
-
-config PARIDE_FRPW
- tristate "FreeCom power protocol"
- depends on PARIDE
- help
- This option enables support for the Freecom power parallel port IDE
- protocol. If you chose to build PARIDE support into your kernel, you
- may answer Y here to build in the protocol driver, otherwise you
- should answer M to build it as a loadable module. The module will be
- called frpw. You must also have a high-level driver for the type
- of device that you want to support.
-
-config PARIDE_KBIC
- tristate "KingByte KBIC-951A/971A protocols"
- depends on PARIDE
- help
- This option enables support for the KBIC-951A and KBIC-971A parallel
- port IDE protocols from KingByte Information Corp. KingByte's
- adapters appear in many no-name portable disk and CD-ROM products,
- especially in Europe. If you chose to build PARIDE support into your
- kernel, you may answer Y here to build in the protocol driver,
- otherwise you should answer M to build it as a loadable module. The
- module will be called kbic. You must also have a high-level driver
- for the type of device that you want to support.
-
-config PARIDE_KTTI
- tristate "KT PHd protocol"
- depends on PARIDE
- help
- This option enables support for the "PHd" parallel port IDE protocol
- from KT Technology. This is a simple (low speed) adapter that is
- used in some 2.5" portable hard drives. If you chose to build PARIDE
- support into your kernel, you may answer Y here to build in the
- protocol driver, otherwise you should answer M to build it as a
- loadable module. The module will be called ktti. You must also
- have a high-level driver for the type of device that you want to
- support.
-
-config PARIDE_ON20
- tristate "OnSpec 90c20 protocol"
- depends on PARIDE
- help
- This option enables support for the (obsolete) 90c20 parallel port
- IDE protocol from OnSpec (often marketed under the ValuStore brand
- name). If you chose to build PARIDE support into your kernel, you
- may answer Y here to build in the protocol driver, otherwise you
- should answer M to build it as a loadable module. The module will
- be called on20. You must also have a high-level driver for the
- type of device that you want to support.
-
-config PARIDE_ON26
- tristate "OnSpec 90c26 protocol"
- depends on PARIDE
- help
- This option enables support for the 90c26 parallel port IDE protocol
- from OnSpec Electronics (often marketed under the ValuStore brand
- name). If you chose to build PARIDE support into your kernel, you
- may answer Y here to build in the protocol driver, otherwise you
- should answer M to build it as a loadable module. The module will be
- called on26. You must also have a high-level driver for the type
- of device that you want to support.
-
-#
diff --git a/drivers/block/paride/Makefile b/drivers/block/paride/Makefile
deleted file mode 100644
index cf1742a8475e..000000000000
--- a/drivers/block/paride/Makefile
+++ /dev/null
@@ -1,29 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-#
-# Makefile for Parallel port IDE device drivers.
-#
-# 7 October 2000, Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
-# Rewritten to use lists instead of if-statements.
-#
-
-obj-$(CONFIG_PARIDE) += paride.o
-obj-$(CONFIG_PARIDE_ATEN) += aten.o
-obj-$(CONFIG_PARIDE_BPCK) += bpck.o
-obj-$(CONFIG_PARIDE_COMM) += comm.o
-obj-$(CONFIG_PARIDE_DSTR) += dstr.o
-obj-$(CONFIG_PARIDE_KBIC) += kbic.o
-obj-$(CONFIG_PARIDE_EPAT) += epat.o
-obj-$(CONFIG_PARIDE_EPIA) += epia.o
-obj-$(CONFIG_PARIDE_FRPW) += frpw.o
-obj-$(CONFIG_PARIDE_FRIQ) += friq.o
-obj-$(CONFIG_PARIDE_FIT2) += fit2.o
-obj-$(CONFIG_PARIDE_FIT3) += fit3.o
-obj-$(CONFIG_PARIDE_ON20) += on20.o
-obj-$(CONFIG_PARIDE_ON26) += on26.o
-obj-$(CONFIG_PARIDE_KTTI) += ktti.o
-obj-$(CONFIG_PARIDE_BPCK6) += bpck6.o
-obj-$(CONFIG_PARIDE_PD) += pd.o
-obj-$(CONFIG_PARIDE_PCD) += pcd.o
-obj-$(CONFIG_PARIDE_PF) += pf.o
-obj-$(CONFIG_PARIDE_PT) += pt.o
-obj-$(CONFIG_PARIDE_PG) += pg.o
diff --git a/drivers/block/paride/Transition-notes b/drivers/block/paride/Transition-notes
deleted file mode 100644
index 70374907c020..000000000000
--- a/drivers/block/paride/Transition-notes
+++ /dev/null
@@ -1,128 +0,0 @@
-Lemma 1:
- If ps_tq is scheduled, ps_tq_active is 1. ps_tq_int() can be called
- only when ps_tq_active is 1.
-Proof: All assignments to ps_tq_active and all scheduling of ps_tq happen
- under ps_spinlock. There are three places where that can happen:
- one in ps_set_intr() (A) and two in ps_tq_int() (B and C).
- Consider the sequnce of these events. A can not be preceded by
- anything except B, since it is under if (!ps_tq_active) under
- ps_spinlock. C is always preceded by B, since we can't reach it
- other than through B and we don't drop ps_spinlock between them.
- IOW, the sequence is A?(BA|BC|B)*. OTOH, number of B can not exceed
- the sum of numbers of A and C, since each call of ps_tq_int() is
- the result of ps_tq execution. Therefore, the sequence starts with
- A and each B is preceded by either A or C. Moments when we enter
- ps_tq_int() are sandwiched between {A,C} and B in that sequence,
- since at any time number of B can not exceed the number of these
- moments which, in turn, can not exceed the number of A and C.
- In other words, the sequence of events is (A or C set ps_tq_active to
- 1 and schedule ps_tq, ps_tq is executed, ps_tq_int() is entered,
- B resets ps_tq_active)*.
-
-
-consider the following area:
- * in do_pd_request1(): to calls of pi_do_claimed() and return in
- case when pd_req is NULL.
- * in next_request(): to call of do_pd_request1()
- * in do_pd_read(): to call of ps_set_intr()
- * in do_pd_read_start(): to calls of pi_do_claimed(), next_request()
-and ps_set_intr()
- * in do_pd_read_drq(): to calls of pi_do_claimed() and next_request()
- * in do_pd_write(): to call of ps_set_intr()
- * in do_pd_write_start(): to calls of pi_do_claimed(), next_request()
-and ps_set_intr()
- * in do_pd_write_done(): to calls of pi_do_claimed() and next_request()
- * in ps_set_intr(): to check for ps_tq_active and to scheduling
- ps_tq if ps_tq_active was 0.
- * in ps_tq_int(): from the moment when we get ps_spinlock() to the
- return, call of con() or scheduling ps_tq.
- * in pi_schedule_claimed() when called from pi_do_claimed() called from
- pd.c, everything until returning 1 or setting or setting ->claim_cont
- on the path that returns 0
- * in pi_do_claimed() when called from pd.c, everything until the call
- of pi_do_claimed() plus the everything until the call of cont() if
- pi_do_claimed() has returned 1.
- * in pi_wake_up() called for PIA that belongs to pd.c, everything from
- the moment when pi_spinlock has been acquired.
-
-Lemma 2:
- 1) at any time at most one thread of execution can be in that area or
- be preempted there.
- 2) When there is such a thread, pd_busy is set or pd_lock is held by
- that thread.
- 3) When there is such a thread, ps_tq_active is 0 or ps_spinlock is
- held by that thread.
- 4) When there is such a thread, all PIA belonging to pd.c have NULL
- ->claim_cont or pi_spinlock is held by thread in question.
-
-Proof: consider the first moment when the above is not true.
-
-(1) can become not true if some thread enters that area while another is there.
- a) do_pd_request1() can be called from next_request() or do_pd_request()
- In the first case the thread was already in the area. In the second,
- the thread was holding pd_lock and found pd_busy not set, which would
- mean that (2) was already not true.
- b) ps_set_intr() and pi_schedule_claimed() can be called only from the
- area.
- c) pi_do_claimed() is called by pd.c only from the area.
- d) ps_tq_int() can enter the area only when the thread is holding
- ps_spinlock and ps_tq_active is 1 (due to Lemma 1). It means that
- (3) was already not true.
- e) do_pd_{read,write}* could be called only from the area. The only
- case that needs consideration is call from pi_wake_up() and there
- we would have to be called for the PIA that got ->claimed_cont
- from pd.c. That could happen only if pi_do_claimed() had been
- called from pd.c for that PIA, which happens only for PIA belonging
- to pd.c.
- f) pi_wake_up() can enter the area only when the thread is holding
- pi_spinlock and ->claimed_cont is non-NULL for PIA belonging to
- pd.c. It means that (4) was already not true.
-
-(2) can become not true only when pd_lock is released by the thread in question.
- Indeed, pd_busy is reset only in the area and thread that resets
- it is holding pd_lock. The only place within the area where we
- release pd_lock is in pd_next_buf() (called from within the area).
- But that code does not reset pd_busy, so pd_busy would have to be
- 0 when pd_next_buf() had acquired pd_lock. If it become 0 while
- we were acquiring the lock, (1) would be already false, since
- the thread that had reset it would be in the area simulateously.
- If it was 0 before we tried to acquire pd_lock, (2) would be
- already false.
-
-For similar reasons, (3) can become not true only when ps_spinlock is released
-by the thread in question. However, all such places within the area are right
-after resetting ps_tq_active to 0.
-
-(4) is done the same way - all places where we release pi_spinlock within
-the area are either after resetting ->claimed_cont to NULL while holding
-pi_spinlock, or after not tocuhing ->claimed_cont since acquiring pi_spinlock
-also in the area. The only place where ->claimed_cont is made non-NULL is
-in the area, under pi_spinlock and we do not release it until after leaving
-the area.
-
-QED.
-
-
-Corollary 1: ps_tq_active can be killed. Indeed, the only place where we
-check its value is in ps_set_intr() and if it had been non-zero at that
-point, we would have violated either (2.1) (if it was set while ps_set_intr()
-was acquiring ps_spinlock) or (2.3) (if it was set when we started to
-acquire ps_spinlock).
-
-Corollary 2: ps_spinlock can be killed. Indeed, Lemma 1 and Lemma 2 show
-that the only possible contention is between scheduling ps_tq followed by
-immediate release of spinlock and beginning of execution of ps_tq on
-another CPU.
-
-Corollary 3: assignment to pd_busy in do_pd_read_start() and do_pd_write_start()
-can be killed. Indeed, we are not holding pd_lock and thus pd_busy is already
-1 here.
-
-Corollary 4: in ps_tq_int() uses of con can be replaced with uses of
-ps_continuation, since the latter is changed only from the area.
-We don't need to reset it to NULL, since we are guaranteed that there
-will be a call of ps_set_intr() before we look at ps_continuation again.
-We can remove the check for ps_continuation being NULL for the same
-reason - the value is guaranteed to be set by the last ps_set_intr() and
-we never pass it NULL. Assignements in the beginning of ps_set_intr()
-can be taken to callers as long as they remain within the area.
diff --git a/drivers/block/paride/mkd b/drivers/block/paride/mkd
deleted file mode 100644
index 6d0d802479ea..000000000000
--- a/drivers/block/paride/mkd
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/bash
-# SPDX-License-Identifier: GPL-2.0
-#
-# mkd -- a script to create the device special files for the PARIDE subsystem
-#
-# block devices: pd (45), pcd (46), pf (47)
-# character devices: pt (96), pg (97)
-#
-function mkdev {
- mknod $1 $2 $3 $4 ; chmod 0660 $1 ; chown root:disk $1
-}
-#
-function pd {
- D=$( printf \\$( printf "x%03x" $[ $1 + 97 ] ) )
- mkdev pd$D b 45 $[ $1 * 16 ]
- for P in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
- do mkdev pd$D$P b 45 $[ $1 * 16 + $P ]
- done
-}
-#
-cd /dev
-#
-for u in 0 1 2 3 ; do pd $u ; done
-for u in 0 1 2 3 ; do mkdev pcd$u b 46 $u ; done
-for u in 0 1 2 3 ; do mkdev pf$u b 47 $u ; done
-for u in 0 1 2 3 ; do mkdev pt$u c 96 $u ; done
-for u in 0 1 2 3 ; do mkdev npt$u c 96 $[ $u + 128 ] ; done
-for u in 0 1 2 3 ; do mkdev pg$u c 97 $u ; done
-#
-# end of mkd
-
diff --git a/drivers/block/paride/paride.c b/drivers/block/paride/paride.c
deleted file mode 100644
index 0e287993b778..000000000000
--- a/drivers/block/paride/paride.c
+++ /dev/null
@@ -1,479 +0,0 @@
-/*
- paride.c (c) 1997-8 Grant R. Guenther <grant@torque.net>
- Under the terms of the GNU General Public License.
-
- This is the base module for the family of device drivers
- that support parallel port IDE devices.
-
-*/
-
-/* Changes:
-
- 1.01 GRG 1998.05.03 Use spinlocks
- 1.02 GRG 1998.05.05 init_proto, release_proto, ktti
- 1.03 GRG 1998.08.15 eliminate compiler warning
- 1.04 GRG 1998.11.28 added support for FRIQ
- 1.05 TMW 2000.06.06 use parport_find_number instead of
- parport_enumerate
- 1.06 TMW 2001.03.26 more sane parport-or-not resource management
-*/
-
-#define PI_VERSION "1.06"
-
-#include <linux/module.h>
-#include <linux/kmod.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/string.h>
-#include <linux/spinlock.h>
-#include <linux/wait.h>
-#include <linux/sched.h> /* TASK_* */
-#include <linux/parport.h>
-#include <linux/slab.h>
-
-#include "paride.h"
-
-MODULE_LICENSE("GPL");
-
-#define MAX_PROTOS 32
-
-static struct pi_protocol *protocols[MAX_PROTOS];
-
-static DEFINE_SPINLOCK(pi_spinlock);
-
-void pi_write_regr(PIA * pi, int cont, int regr, int val)
-{
- pi->proto->write_regr(pi, cont, regr, val);
-}
-
-EXPORT_SYMBOL(pi_write_regr);
-
-int pi_read_regr(PIA * pi, int cont, int regr)
-{
- return pi->proto->read_regr(pi, cont, regr);
-}
-
-EXPORT_SYMBOL(pi_read_regr);
-
-void pi_write_block(PIA * pi, char *buf, int count)
-{
- pi->proto->write_block(pi, buf, count);
-}
-
-EXPORT_SYMBOL(pi_write_block);
-
-void pi_read_block(PIA * pi, char *buf, int count)
-{
- pi->proto->read_block(pi, buf, count);
-}
-
-EXPORT_SYMBOL(pi_read_block);
-
-static void pi_wake_up(void *p)
-{
- PIA *pi = (PIA *) p;
- unsigned long flags;
- void (*cont) (void) = NULL;
-
- spin_lock_irqsave(&pi_spinlock, flags);
-
- if (pi->claim_cont && !parport_claim(pi->pardev)) {
- cont = pi->claim_cont;
- pi->claim_cont = NULL;
- pi->claimed = 1;
- }
-
- spin_unlock_irqrestore(&pi_spinlock, flags);
-
- wake_up(&(pi->parq));
-
- if (cont)
- cont();
-}
-
-int pi_schedule_claimed(PIA * pi, void (*cont) (void))
-{
- unsigned long flags;
-
- spin_lock_irqsave(&pi_spinlock, flags);
- if (pi->pardev && parport_claim(pi->pardev)) {
- pi->claim_cont = cont;
- spin_unlock_irqrestore(&pi_spinlock, flags);
- return 0;
- }
- pi->claimed = 1;
- spin_unlock_irqrestore(&pi_spinlock, flags);
- return 1;
-}
-EXPORT_SYMBOL(pi_schedule_claimed);
-
-void pi_do_claimed(PIA * pi, void (*cont) (void))
-{
- if (pi_schedule_claimed(pi, cont))
- cont();
-}
-
-EXPORT_SYMBOL(pi_do_claimed);
-
-static void pi_claim(PIA * pi)
-{
- if (pi->claimed)
- return;
- pi->claimed = 1;
- if (pi->pardev)
- wait_event(pi->parq,
- !parport_claim((struct pardevice *) pi->pardev));
-}
-
-static void pi_unclaim(PIA * pi)
-{
- pi->claimed = 0;
- if (pi->pardev)
- parport_release((struct pardevice *) (pi->pardev));
-}
-
-void pi_connect(PIA * pi)
-{
- pi_claim(pi);
- pi->proto->connect(pi);
-}
-
-EXPORT_SYMBOL(pi_connect);
-
-void pi_disconnect(PIA * pi)
-{
- pi->proto->disconnect(pi);
- pi_unclaim(pi);
-}
-
-EXPORT_SYMBOL(pi_disconnect);
-
-static void pi_unregister_parport(PIA * pi)
-{
- if (pi->pardev) {
- parport_unregister_device((struct pardevice *) (pi->pardev));
- pi->pardev = NULL;
- }
-}
-
-void pi_release(PIA * pi)
-{
- pi_unregister_parport(pi);
- if (pi->proto->release_proto)
- pi->proto->release_proto(pi);
- module_put(pi->proto->owner);
-}
-
-EXPORT_SYMBOL(pi_release);
-
-static int default_test_proto(PIA * pi, char *scratch, int verbose)
-{
- int j, k;
- int e[2] = { 0, 0 };
-
- pi->proto->connect(pi);
-
- for (j = 0; j < 2; j++) {
- pi_write_regr(pi, 0, 6, 0xa0 + j * 0x10);
- for (k = 0; k < 256; k++) {
- pi_write_regr(pi, 0, 2, k ^ 0xaa);
- pi_write_regr(pi, 0, 3, k ^ 0x55);
- if (pi_read_regr(pi, 0, 2) != (k ^ 0xaa))
- e[j]++;
- }
- }
- pi->proto->disconnect(pi);
-
- if (verbose)
- printk("%s: %s: port 0x%x, mode %d, test=(%d,%d)\n",
- pi->device, pi->proto->name, pi->port,
- pi->mode, e[0], e[1]);
-
- return (e[0] && e[1]); /* not here if both > 0 */
-}
-
-static int pi_test_proto(PIA * pi, char *scratch, int verbose)
-{
- int res;
-
- pi_claim(pi);
- if (pi->proto->test_proto)
- res = pi->proto->test_proto(pi, scratch, verbose);
- else
- res = default_test_proto(pi, scratch, verbose);
- pi_unclaim(pi);
-
- return res;
-}
-
-int paride_register(PIP * pr)
-{
- int k;
-
- for (k = 0; k < MAX_PROTOS; k++)
- if (protocols[k] && !strcmp(pr->name, protocols[k]->name)) {
- printk("paride: %s protocol already registered\n",
- pr->name);
- return -1;
- }
- k = 0;
- while ((k < MAX_PROTOS) && (protocols[k]))
- k++;
- if (k == MAX_PROTOS) {
- printk("paride: protocol table full\n");
- return -1;
- }
- protocols[k] = pr;
- pr->index = k;
- printk("paride: %s registered as protocol %d\n", pr->name, k);
- return 0;
-}
-
-EXPORT_SYMBOL(paride_register);
-
-void paride_unregister(PIP * pr)
-{
- if (!pr)
- return;
- if (protocols[pr->index] != pr) {
- printk("paride: %s not registered\n", pr->name);
- return;
- }
- protocols[pr->index] = NULL;
-}
-
-EXPORT_SYMBOL(paride_unregister);
-
-static int pi_register_parport(PIA *pi, int verbose, int unit)
-{
- struct parport *port;
- struct pardev_cb par_cb;
-
- port = parport_find_base(pi->port);
- if (!port)
- return 0;
- memset(&par_cb, 0, sizeof(par_cb));
- par_cb.wakeup = pi_wake_up;
- par_cb.private = (void *)pi;
- pi->pardev = parport_register_dev_model(port, pi->device, &par_cb,
- unit);
- parport_put_port(port);
- if (!pi->pardev)
- return 0;
-
- init_waitqueue_head(&pi->parq);
-
- if (verbose)
- printk("%s: 0x%x is %s\n", pi->device, pi->port, port->name);
-
- pi->parname = (char *) port->name;
-
- return 1;
-}
-
-static int pi_probe_mode(PIA * pi, int max, char *scratch, int verbose)
-{
- int best, range;
-
- if (pi->mode != -1) {
- if (pi->mode >= max)
- return 0;
- range = 3;
- if (pi->mode >= pi->proto->epp_first)
- range = 8;
- if ((range == 8) && (pi->port % 8))
- return 0;
- pi->reserved = range;
- return (!pi_test_proto(pi, scratch, verbose));
- }
- best = -1;
- for (pi->mode = 0; pi->mode < max; pi->mode++) {
- range = 3;
- if (pi->mode >= pi->proto->epp_first)
- range = 8;
- if ((range == 8) && (pi->port % 8))
- break;
- pi->reserved = range;
- if (!pi_test_proto(pi, scratch, verbose))
- best = pi->mode;
- }
- pi->mode = best;
- return (best > -1);
-}
-
-static int pi_probe_unit(PIA * pi, int unit, char *scratch, int verbose)
-{
- int max, s, e;
-
- s = unit;
- e = s + 1;
-
- if (s == -1) {
- s = 0;
- e = pi->proto->max_units;
- }
-
- if (!pi_register_parport(pi, verbose, s))
- return 0;
-
- if (pi->proto->test_port) {
- pi_claim(pi);
- max = pi->proto->test_port(pi);
- pi_unclaim(pi);
- } else
- max = pi->proto->max_mode;
-
- if (pi->proto->probe_unit) {
- pi_claim(pi);
- for (pi->unit = s; pi->unit < e; pi->unit++)
- if (pi->proto->probe_unit(pi)) {
- pi_unclaim(pi);
- if (pi_probe_mode(pi, max, scratch, verbose))
- return 1;
- pi_unregister_parport(pi);
- return 0;
- }
- pi_unclaim(pi);
- pi_unregister_parport(pi);
- return 0;
- }
-
- if (!pi_probe_mode(pi, max, scratch, verbose)) {
- pi_unregister_parport(pi);
- return 0;
- }
- return 1;
-
-}
-
-int pi_init(PIA * pi, int autoprobe, int port, int mode,
- int unit, int protocol, int delay, char *scratch,
- int devtype, int verbose, char *device)
-{
- int p, k, s, e;
- int lpts[7] = { 0x3bc, 0x378, 0x278, 0x268, 0x27c, 0x26c, 0 };
-
- s = protocol;
- e = s + 1;
-
- if (!protocols[0])
- request_module("paride_protocol");
-
- if (autoprobe) {
- s = 0;
- e = MAX_PROTOS;
- } else if ((s < 0) || (s >= MAX_PROTOS) || (port <= 0) ||
- (!protocols[s]) || (unit < 0) ||
- (unit >= protocols[s]->max_units)) {
- printk("%s: Invalid parameters\n", device);
- return 0;
- }
-
- for (p = s; p < e; p++) {
- struct pi_protocol *proto = protocols[p];
- if (!proto)
- continue;
- /* still racy */
- if (!try_module_get(proto->owner))
- continue;
- pi->proto = proto;
- pi->private = 0;
- if (proto->init_proto && proto->init_proto(pi) < 0) {
- pi->proto = NULL;
- module_put(proto->owner);
- continue;
- }
- if (delay == -1)
- pi->delay = pi->proto->default_delay;
- else
- pi->delay = delay;
- pi->devtype = devtype;
- pi->device = device;
-
- pi->parname = NULL;
- pi->pardev = NULL;
- init_waitqueue_head(&pi->parq);
- pi->claimed = 0;
- pi->claim_cont = NULL;
-
- pi->mode = mode;
- if (port != -1) {
- pi->port = port;
- if (pi_probe_unit(pi, unit, scratch, verbose))
- break;
- pi->port = 0;
- } else {
- k = 0;
- while ((pi->port = lpts[k++]))
- if (pi_probe_unit
- (pi, unit, scratch, verbose))
- break;
- if (pi->port)
- break;
- }
- if (pi->proto->release_proto)
- pi->proto->release_proto(pi);
- module_put(proto->owner);
- }
-
- if (!pi->port) {
- if (autoprobe)
- printk("%s: Autoprobe failed\n", device);
- else
- printk("%s: Adapter not found\n", device);
- return 0;
- }
-
- if (pi->parname)
- printk("%s: Sharing %s at 0x%x\n", pi->device,
- pi->parname, pi->port);
-
- pi->proto->log_adapter(pi, scratch, verbose);
-
- return 1;
-}
-
-EXPORT_SYMBOL(pi_init);
-
-static int pi_probe(struct pardevice *par_dev)
-{
- struct device_driver *drv = par_dev->dev.driver;
- int len = strlen(drv->name);
-
- if (strncmp(par_dev->name, drv->name, len))
- return -ENODEV;
-
- return 0;
-}
-
-void *pi_register_driver(char *name)
-{
- struct parport_driver *parp_drv;
- int ret;
-
- parp_drv = kzalloc(sizeof(*parp_drv), GFP_KERNEL);
- if (!parp_drv)
- return NULL;
-
- parp_drv->name = name;
- parp_drv->probe = pi_probe;
- parp_drv->devmodel = true;
-
- ret = parport_register_driver(parp_drv);
- if (ret) {
- kfree(parp_drv);
- return NULL;
- }
- return (void *)parp_drv;
-}
-EXPORT_SYMBOL(pi_register_driver);
-
-void pi_unregister_driver(void *_drv)
-{
- struct parport_driver *drv = _drv;
-
- parport_unregister_driver(drv);
- kfree(drv);
-}
-EXPORT_SYMBOL(pi_unregister_driver);
diff --git a/drivers/block/paride/paride.h b/drivers/block/paride/paride.h
deleted file mode 100644
index ddb9e589da7f..000000000000
--- a/drivers/block/paride/paride.h
+++ /dev/null
@@ -1,172 +0,0 @@
-#ifndef __DRIVERS_PARIDE_H__
-#define __DRIVERS_PARIDE_H__
-
-/*
- paride.h (c) 1997-8 Grant R. Guenther <grant@torque.net>
- Under the terms of the GPL.
-
- This file defines the interface between the high-level parallel
- IDE device drivers (pd, pf, pcd, pt) and the adapter chips.
-
-*/
-
-/* Changes:
-
- 1.01 GRG 1998.05.05 init_proto, release_proto
-*/
-
-#define PARIDE_H_VERSION "1.01"
-
-/* Some adapters need to know what kind of device they are in
-
- Values for devtype:
-*/
-
-#define PI_PD 0 /* IDE disk */
-#define PI_PCD 1 /* ATAPI CDrom */
-#define PI_PF 2 /* ATAPI disk */
-#define PI_PT 3 /* ATAPI tape */
-#define PI_PG 4 /* ATAPI generic */
-
-/* The paride module contains no state, instead the drivers allocate
- a pi_adapter data structure and pass it to paride in every operation.
-
-*/
-
-struct pi_adapter {
-
- struct pi_protocol *proto; /* adapter protocol */
- int port; /* base address of parallel port */
- int mode; /* transfer mode in use */
- int delay; /* adapter delay setting */
- int devtype; /* device type: PI_PD etc. */
- char *device; /* name of driver */
- int unit; /* unit number for chained adapters */
- int saved_r0; /* saved port state */
- int saved_r2; /* saved port state */
- int reserved; /* number of ports reserved */
- unsigned long private; /* for protocol module */
-
- wait_queue_head_t parq; /* semaphore for parport sharing */
- void *pardev; /* pointer to pardevice */
- char *parname; /* parport name */
- int claimed; /* parport has already been claimed */
- void (*claim_cont)(void); /* continuation for parport wait */
-};
-
-typedef struct pi_adapter PIA;
-
-/* functions exported by paride to the high level drivers */
-
-extern int pi_init(PIA *pi,
- int autoprobe, /* 1 to autoprobe */
- int port, /* base port address */
- int mode, /* -1 for autoprobe */
- int unit, /* unit number, if supported */
- int protocol, /* protocol to use */
- int delay, /* -1 to use adapter specific default */
- char * scratch, /* address of 512 byte buffer */
- int devtype, /* device type: PI_PD, PI_PCD, etc ... */
- int verbose, /* log verbose data while probing */
- char *device /* name of the driver */
- ); /* returns 0 on failure, 1 on success */
-
-extern void pi_release(PIA *pi);
-
-/* registers are addressed as (cont,regr)
-
- cont: 0 for command register file, 1 for control register(s)
- regr: 0-7 for register number.
-
-*/
-
-extern void pi_write_regr(PIA *pi, int cont, int regr, int val);
-
-extern int pi_read_regr(PIA *pi, int cont, int regr);
-
-extern void pi_write_block(PIA *pi, char * buf, int count);
-
-extern void pi_read_block(PIA *pi, char * buf, int count);
-
-extern void pi_connect(PIA *pi);
-
-extern void pi_disconnect(PIA *pi);
-
-extern void pi_do_claimed(PIA *pi, void (*cont)(void));
-extern int pi_schedule_claimed(PIA *pi, void (*cont)(void));
-
-/* macros and functions exported to the protocol modules */
-
-#define delay_p (pi->delay?udelay(pi->delay):(void)0)
-#define out_p(offs,byte) outb(byte,pi->port+offs); delay_p;
-#define in_p(offs) (delay_p,inb(pi->port+offs))
-
-#define w0(byte) {out_p(0,byte);}
-#define r0() (in_p(0) & 0xff)
-#define w1(byte) {out_p(1,byte);}
-#define r1() (in_p(1) & 0xff)
-#define w2(byte) {out_p(2,byte);}
-#define r2() (in_p(2) & 0xff)
-#define w3(byte) {out_p(3,byte);}
-#define w4(byte) {out_p(4,byte);}
-#define r4() (in_p(4) & 0xff)
-#define w4w(data) {outw(data,pi->port+4); delay_p;}
-#define w4l(data) {outl(data,pi->port+4); delay_p;}
-#define r4w() (delay_p,inw(pi->port+4)&0xffff)
-#define r4l() (delay_p,inl(pi->port+4)&0xffffffff)
-
-static inline u16 pi_swab16( char *b, int k)
-
-{ union { u16 u; char t[2]; } r;
-
- r.t[0]=b[2*k+1]; r.t[1]=b[2*k];
- return r.u;
-}
-
-static inline u32 pi_swab32( char *b, int k)
-
-{ union { u32 u; char f[4]; } r;
-
- r.f[0]=b[4*k+1]; r.f[1]=b[4*k];
- r.f[2]=b[4*k+3]; r.f[3]=b[4*k+2];
- return r.u;
-}
-
-struct pi_protocol {
-
- char name[8]; /* name for this protocol */
- int index; /* index into protocol table */
-
- int max_mode; /* max mode number */
- int epp_first; /* modes >= this use 8 ports */
-
- int default_delay; /* delay parameter if not specified */
- int max_units; /* max chained units probed for */
-
- void (*write_regr)(PIA *,int,int,int);
- int (*read_regr)(PIA *,int,int);
- void (*write_block)(PIA *,char *,int);
- void (*read_block)(PIA *,char *,int);
-
- void (*connect)(PIA *);
- void (*disconnect)(PIA *);
-
- int (*test_port)(PIA *);
- int (*probe_unit)(PIA *);
- int (*test_proto)(PIA *,char *,int);
- void (*log_adapter)(PIA *,char *,int);
-
- int (*init_proto)(PIA *);
- void (*release_proto)(PIA *);
- struct module *owner;
-};
-
-typedef struct pi_protocol PIP;
-
-extern int paride_register( PIP * );
-extern void paride_unregister ( PIP * );
-void *pi_register_driver(char *);
-void pi_unregister_driver(void *);
-
-#endif /* __DRIVERS_PARIDE_H__ */
-/* end of paride.h */
diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c
deleted file mode 100644
index a5ab40784119..000000000000
--- a/drivers/block/paride/pcd.c
+++ /dev/null
@@ -1,1042 +0,0 @@
-/*
- pcd.c (c) 1997-8 Grant R. Guenther <grant@torque.net>
- Under the terms of the GNU General Public License.
-
- This is a high-level driver for parallel port ATAPI CD-ROM
- drives based on chips supported by the paride module.
-
- By default, the driver will autoprobe for a single parallel
- port ATAPI CD-ROM drive, but if their individual parameters are
- specified, the driver can handle up to 4 drives.
-
- The behaviour of the pcd driver can be altered by setting
- some parameters from the insmod command line. The following
- parameters are adjustable:
-
- drive0 These four arguments can be arrays of
- drive1 1-6 integers as follows:
- drive2
- drive3 <prt>,<pro>,<uni>,<mod>,<slv>,<dly>
-
- Where,
-
- <prt> is the base of the parallel port address for
- the corresponding drive. (required)
-
- <pro> is the protocol number for the adapter that
- supports this drive. These numbers are
- logged by 'paride' when the protocol modules
- are initialised. (0 if not given)
-
- <uni> for those adapters that support chained
- devices, this is the unit selector for the
- chain of devices on the given port. It should
- be zero for devices that don't support chaining.
- (0 if not given)
-
- <mod> this can be -1 to choose the best mode, or one
- of the mode numbers supported by the adapter.
- (-1 if not given)
-
- <slv> ATAPI CD-ROMs can be jumpered to master or slave.
- Set this to 0 to choose the master drive, 1 to
- choose the slave, -1 (the default) to choose the
- first drive found.
-
- <dly> some parallel ports require the driver to
- go more slowly. -1 sets a default value that
- should work with the chosen protocol. Otherwise,
- set this to a small integer, the larger it is
- the slower the port i/o. In some cases, setting
- this to zero will speed up the device. (default -1)
-
- major You may use this parameter to override the
- default major number (46) that this driver
- will use. Be sure to change the device
- name as well.
-
- name This parameter is a character string that
- contains the name the kernel will use for this
- device (in /proc output, for instance).
- (default "pcd")
-
- verbose This parameter controls the amount of logging
- that the driver will do. Set it to 0 for
- normal operation, 1 to see autoprobe progress
- messages, or 2 to see additional debugging
- output. (default 0)
-
- nice This parameter controls the driver's use of
- idle CPU time, at the expense of some speed.
-
- If this driver is built into the kernel, you can use the
- following kernel command line parameters, with the same values
- as the corresponding module parameters listed above:
-
- pcd.drive0
- pcd.drive1
- pcd.drive2
- pcd.drive3
- pcd.nice
-
- In addition, you can use the parameter pcd.disable to disable
- the driver entirely.
-
-*/
-
-/* Changes:
-
- 1.01 GRG 1998.01.24 Added test unit ready support
- 1.02 GRG 1998.05.06 Changes to pcd_completion, ready_wait,
- and loosen interpretation of ATAPI
- standard for clearing error status.
- Use spinlocks. Eliminate sti().
- 1.03 GRG 1998.06.16 Eliminated an Ugh
- 1.04 GRG 1998.08.15 Added extra debugging, improvements to
- pcd_completion, use HZ in loop timing
- 1.05 GRG 1998.08.16 Conformed to "Uniform CD-ROM" standard
- 1.06 GRG 1998.08.19 Added audio ioctl support
- 1.07 GRG 1998.09.24 Increased reset timeout, added jumbo support
-
-*/
-
-#define PCD_VERSION "1.07"
-#define PCD_MAJOR 46
-#define PCD_NAME "pcd"
-#define PCD_UNITS 4
-
-/* Here are things one can override from the insmod command.
- Most are autoprobed by paride unless set here. Verbose is off
- by default.
-
-*/
-
-static int verbose = 0;
-static int major = PCD_MAJOR;
-static char *name = PCD_NAME;
-static int nice = 0;
-static int disable = 0;
-
-static int drive0[6] = { 0, 0, 0, -1, -1, -1 };
-static int drive1[6] = { 0, 0, 0, -1, -1, -1 };
-static int drive2[6] = { 0, 0, 0, -1, -1, -1 };
-static int drive3[6] = { 0, 0, 0, -1, -1, -1 };
-
-static int (*drives[4])[6] = {&drive0, &drive1, &drive2, &drive3};
-static int pcd_drive_count;
-
-enum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV, D_DLY};
-
-/* end of parameters */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/cdrom.h>
-#include <linux/spinlock.h>
-#include <linux/blk-mq.h>
-#include <linux/mutex.h>
-#include <linux/uaccess.h>
-
-static DEFINE_MUTEX(pcd_mutex);
-static DEFINE_SPINLOCK(pcd_lock);
-
-module_param(verbose, int, 0644);
-module_param(major, int, 0);
-module_param(name, charp, 0);
-module_param(nice, int, 0);
-module_param_array(drive0, int, NULL, 0);
-module_param_array(drive1, int, NULL, 0);
-module_param_array(drive2, int, NULL, 0);
-module_param_array(drive3, int, NULL, 0);
-
-#include "paride.h"
-#include "pseudo.h"
-
-#define PCD_RETRIES 5
-#define PCD_TMO 800 /* timeout in jiffies */
-#define PCD_DELAY 50 /* spin delay in uS */
-#define PCD_READY_TMO 20 /* in seconds */
-#define PCD_RESET_TMO 100 /* in tenths of a second */
-
-#define PCD_SPIN (1000000*PCD_TMO)/(HZ*PCD_DELAY)
-
-#define IDE_ERR 0x01
-#define IDE_DRQ 0x08
-#define IDE_READY 0x40
-#define IDE_BUSY 0x80
-
-static int pcd_open(struct cdrom_device_info *cdi, int purpose);
-static void pcd_release(struct cdrom_device_info *cdi);
-static int pcd_drive_status(struct cdrom_device_info *cdi, int slot_nr);
-static unsigned int pcd_check_events(struct cdrom_device_info *cdi,
- unsigned int clearing, int slot_nr);
-static int pcd_tray_move(struct cdrom_device_info *cdi, int position);
-static int pcd_lock_door(struct cdrom_device_info *cdi, int lock);
-static int pcd_drive_reset(struct cdrom_device_info *cdi);
-static int pcd_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn);
-static int pcd_audio_ioctl(struct cdrom_device_info *cdi,
- unsigned int cmd, void *arg);
-static int pcd_packet(struct cdrom_device_info *cdi,
- struct packet_command *cgc);
-
-static void do_pcd_read_drq(void);
-static blk_status_t pcd_queue_rq(struct blk_mq_hw_ctx *hctx,
- const struct blk_mq_queue_data *bd);
-static void do_pcd_read(void);
-
-struct pcd_unit {
- struct pi_adapter pia; /* interface to paride layer */
- struct pi_adapter *pi;
- int drive; /* master/slave */
- int last_sense; /* result of last request sense */
- int changed; /* media change seen */
- int present; /* does this unit exist ? */
- char *name; /* pcd0, pcd1, etc */
- struct cdrom_device_info info; /* uniform cdrom interface */
- struct gendisk *disk;
- struct blk_mq_tag_set tag_set;
- struct list_head rq_list;
-};
-
-static struct pcd_unit pcd[PCD_UNITS];
-
-static char pcd_scratch[64];
-static char pcd_buffer[2048]; /* raw block buffer */
-static int pcd_bufblk = -1; /* block in buffer, in CD units,
- -1 for nothing there. See also
- pd_unit.
- */
-
-/* the variables below are used mainly in the I/O request engine, which
- processes only one request at a time.
-*/
-
-static struct pcd_unit *pcd_current; /* current request's drive */
-static struct request *pcd_req;
-static int pcd_retries; /* retries on current request */
-static int pcd_busy; /* request being processed ? */
-static int pcd_sector; /* address of next requested sector */
-static int pcd_count; /* number of blocks still to do */
-static char *pcd_buf; /* buffer for request in progress */
-static void *par_drv; /* reference of parport driver */
-
-/* kernel glue structures */
-
-static int pcd_block_open(struct block_device *bdev, fmode_t mode)
-{
- struct pcd_unit *cd = bdev->bd_disk->private_data;
- int ret;
-
- bdev_check_media_change(bdev);
-
- mutex_lock(&pcd_mutex);
- ret = cdrom_open(&cd->info, bdev, mode);
- mutex_unlock(&pcd_mutex);
-
- return ret;
-}
-
-static void pcd_block_release(struct gendisk *disk, fmode_t mode)
-{
- struct pcd_unit *cd = disk->private_data;
- mutex_lock(&pcd_mutex);
- cdrom_release(&cd->info, mode);
- mutex_unlock(&pcd_mutex);
-}
-
-static int pcd_block_ioctl(struct block_device *bdev, fmode_t mode,
- unsigned cmd, unsigned long arg)
-{
- struct pcd_unit *cd = bdev->bd_disk->private_data;
- int ret;
-
- mutex_lock(&pcd_mutex);
- ret = cdrom_ioctl(&cd->info, bdev, mode, cmd, arg);
- mutex_unlock(&pcd_mutex);
-
- return ret;
-}
-
-static unsigned int pcd_block_check_events(struct gendisk *disk,
- unsigned int clearing)
-{
- struct pcd_unit *cd = disk->private_data;
- return cdrom_check_events(&cd->info, clearing);
-}
-
-static const struct block_device_operations pcd_bdops = {
- .owner = THIS_MODULE,
- .open = pcd_block_open,
- .release = pcd_block_release,
- .ioctl = pcd_block_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = blkdev_compat_ptr_ioctl,
-#endif
- .check_events = pcd_block_check_events,
-};
-
-static const struct cdrom_device_ops pcd_dops = {
- .open = pcd_open,
- .release = pcd_release,
- .drive_status = pcd_drive_status,
- .check_events = pcd_check_events,
- .tray_move = pcd_tray_move,
- .lock_door = pcd_lock_door,
- .get_mcn = pcd_get_mcn,
- .reset = pcd_drive_reset,
- .audio_ioctl = pcd_audio_ioctl,
- .generic_packet = pcd_packet,
- .capability = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK |
- CDC_MCN | CDC_MEDIA_CHANGED | CDC_RESET |
- CDC_PLAY_AUDIO | CDC_GENERIC_PACKET | CDC_CD_R |
- CDC_CD_RW,
-};
-
-static const struct blk_mq_ops pcd_mq_ops = {
- .queue_rq = pcd_queue_rq,
-};
-
-static int pcd_open(struct cdrom_device_info *cdi, int purpose)
-{
- struct pcd_unit *cd = cdi->handle;
- if (!cd->present)
- return -ENODEV;
- return 0;
-}
-
-static void pcd_release(struct cdrom_device_info *cdi)
-{
-}
-
-static inline int status_reg(struct pcd_unit *cd)
-{
- return pi_read_regr(cd->pi, 1, 6);
-}
-
-static inline int read_reg(struct pcd_unit *cd, int reg)
-{
- return pi_read_regr(cd->pi, 0, reg);
-}
-
-static inline void write_reg(struct pcd_unit *cd, int reg, int val)
-{
- pi_write_regr(cd->pi, 0, reg, val);
-}
-
-static int pcd_wait(struct pcd_unit *cd, int go, int stop, char *fun, char *msg)
-{
- int j, r, e, s, p;
-
- j = 0;
- while ((((r = status_reg(cd)) & go) || (stop && (!(r & stop))))
- && (j++ < PCD_SPIN))
- udelay(PCD_DELAY);
-
- if ((r & (IDE_ERR & stop)) || (j > PCD_SPIN)) {
- s = read_reg(cd, 7);
- e = read_reg(cd, 1);
- p = read_reg(cd, 2);
- if (j > PCD_SPIN)
- e |= 0x100;
- if (fun)
- printk("%s: %s %s: alt=0x%x stat=0x%x err=0x%x"
- " loop=%d phase=%d\n",
- cd->name, fun, msg, r, s, e, j, p);
- return (s << 8) + r;
- }
- return 0;
-}
-
-static int pcd_command(struct pcd_unit *cd, char *cmd, int dlen, char *fun)
-{
- pi_connect(cd->pi);
-
- write_reg(cd, 6, 0xa0 + 0x10 * cd->drive);
-
- if (pcd_wait(cd, IDE_BUSY | IDE_DRQ, 0, fun, "before command")) {
- pi_disconnect(cd->pi);
- return -1;
- }
-
- write_reg(cd, 4, dlen % 256);
- write_reg(cd, 5, dlen / 256);
- write_reg(cd, 7, 0xa0); /* ATAPI packet command */
-
- if (pcd_wait(cd, IDE_BUSY, IDE_DRQ, fun, "command DRQ")) {
- pi_disconnect(cd->pi);
- return -1;
- }
-
- if (read_reg(cd, 2) != 1) {
- printk("%s: %s: command phase error\n", cd->name, fun);
- pi_disconnect(cd->pi);
- return -1;
- }
-
- pi_write_block(cd->pi, cmd, 12);
-
- return 0;
-}
-
-static int pcd_completion(struct pcd_unit *cd, char *buf, char *fun)
-{
- int r, d, p, n, k, j;
-
- r = -1;
- k = 0;
- j = 0;
-
- if (!pcd_wait(cd, IDE_BUSY, IDE_DRQ | IDE_READY | IDE_ERR,
- fun, "completion")) {
- r = 0;
- while (read_reg(cd, 7) & IDE_DRQ) {
- d = read_reg(cd, 4) + 256 * read_reg(cd, 5);
- n = (d + 3) & 0xfffc;
- p = read_reg(cd, 2) & 3;
-
- if ((p == 2) && (n > 0) && (j == 0)) {
- pi_read_block(cd->pi, buf, n);
- if (verbose > 1)
- printk("%s: %s: Read %d bytes\n",
- cd->name, fun, n);
- r = 0;
- j++;
- } else {
- if (verbose > 1)
- printk
- ("%s: %s: Unexpected phase %d, d=%d, k=%d\n",
- cd->name, fun, p, d, k);
- if (verbose < 2)
- printk_once(
- "%s: WARNING: ATAPI phase errors\n",
- cd->name);
- mdelay(1);
- }
- if (k++ > PCD_TMO) {
- printk("%s: Stuck DRQ\n", cd->name);
- break;
- }
- if (pcd_wait
- (cd, IDE_BUSY, IDE_DRQ | IDE_READY | IDE_ERR, fun,
- "completion")) {
- r = -1;
- break;
- }
- }
- }
-
- pi_disconnect(cd->pi);
-
- return r;
-}
-
-static void pcd_req_sense(struct pcd_unit *cd, char *fun)
-{
- char rs_cmd[12] = { 0x03, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0 };
- char buf[16];
- int r, c;
-
- r = pcd_command(cd, rs_cmd, 16, "Request sense");
- mdelay(1);
- if (!r)
- pcd_completion(cd, buf, "Request sense");
-
- cd->last_sense = -1;
- c = 2;
- if (!r) {
- if (fun)
- printk("%s: %s: Sense key: %x, ASC: %x, ASQ: %x\n",
- cd->name, fun, buf[2] & 0xf, buf[12], buf[13]);
- c = buf[2] & 0xf;
- cd->last_sense =
- c | ((buf[12] & 0xff) << 8) | ((buf[13] & 0xff) << 16);
- }
- if ((c == 2) || (c == 6))
- cd->changed = 1;
-}
-
-static int pcd_atapi(struct pcd_unit *cd, char *cmd, int dlen, char *buf, char *fun)
-{
- int r;
-
- r = pcd_command(cd, cmd, dlen, fun);
- mdelay(1);
- if (!r)
- r = pcd_completion(cd, buf, fun);
- if (r)
- pcd_req_sense(cd, fun);
-
- return r;
-}
-
-static int pcd_packet(struct cdrom_device_info *cdi, struct packet_command *cgc)
-{
- return pcd_atapi(cdi->handle, cgc->cmd, cgc->buflen, cgc->buffer,
- "generic packet");
-}
-
-#define DBMSG(msg) ((verbose>1)?(msg):NULL)
-
-static unsigned int pcd_check_events(struct cdrom_device_info *cdi,
- unsigned int clearing, int slot_nr)
-{
- struct pcd_unit *cd = cdi->handle;
- int res = cd->changed;
- if (res)
- cd->changed = 0;
- return res ? DISK_EVENT_MEDIA_CHANGE : 0;
-}
-
-static int pcd_lock_door(struct cdrom_device_info *cdi, int lock)
-{
- char un_cmd[12] = { 0x1e, 0, 0, 0, lock, 0, 0, 0, 0, 0, 0, 0 };
-
- return pcd_atapi(cdi->handle, un_cmd, 0, pcd_scratch,
- lock ? "lock door" : "unlock door");
-}
-
-static int pcd_tray_move(struct cdrom_device_info *cdi, int position)
-{
- char ej_cmd[12] = { 0x1b, 0, 0, 0, 3 - position, 0, 0, 0, 0, 0, 0, 0 };
-
- return pcd_atapi(cdi->handle, ej_cmd, 0, pcd_scratch,
- position ? "eject" : "close tray");
-}
-
-static void pcd_sleep(int cs)
-{
- schedule_timeout_interruptible(cs);
-}
-
-static int pcd_reset(struct pcd_unit *cd)
-{
- int i, k, flg;
- int expect[5] = { 1, 1, 1, 0x14, 0xeb };
-
- pi_connect(cd->pi);
- write_reg(cd, 6, 0xa0 + 0x10 * cd->drive);
- write_reg(cd, 7, 8);
-
- pcd_sleep(20 * HZ / 1000); /* delay a bit */
-
- k = 0;
- while ((k++ < PCD_RESET_TMO) && (status_reg(cd) & IDE_BUSY))
- pcd_sleep(HZ / 10);
-
- flg = 1;
- for (i = 0; i < 5; i++)
- flg &= (read_reg(cd, i + 1) == expect[i]);
-
- if (verbose) {
- printk("%s: Reset (%d) signature = ", cd->name, k);
- for (i = 0; i < 5; i++)
- printk("%3x", read_reg(cd, i + 1));
- if (!flg)
- printk(" (incorrect)");
- printk("\n");
- }
-
- pi_disconnect(cd->pi);
- return flg - 1;
-}
-
-static int pcd_drive_reset(struct cdrom_device_info *cdi)
-{
- return pcd_reset(cdi->handle);
-}
-
-static int pcd_ready_wait(struct pcd_unit *cd, int tmo)
-{
- char tr_cmd[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- int k, p;
-
- k = 0;
- while (k < tmo) {
- cd->last_sense = 0;
- pcd_atapi(cd, tr_cmd, 0, NULL, DBMSG("test unit ready"));
- p = cd->last_sense;
- if (!p)
- return 0;
- if (!(((p & 0xffff) == 0x0402) || ((p & 0xff) == 6)))
- return p;
- k++;
- pcd_sleep(HZ);
- }
- return 0x000020; /* timeout */
-}
-
-static int pcd_drive_status(struct cdrom_device_info *cdi, int slot_nr)
-{
- char rc_cmd[12] = { 0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- struct pcd_unit *cd = cdi->handle;
-
- if (pcd_ready_wait(cd, PCD_READY_TMO))
- return CDS_DRIVE_NOT_READY;
- if (pcd_atapi(cd, rc_cmd, 8, pcd_scratch, DBMSG("check media")))
- return CDS_NO_DISC;
- return CDS_DISC_OK;
-}
-
-static int pcd_identify(struct pcd_unit *cd)
-{
- char id_cmd[12] = { 0x12, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0 };
- char id[18];
- int k, s;
-
- pcd_bufblk = -1;
-
- s = pcd_atapi(cd, id_cmd, 36, pcd_buffer, "identify");
-
- if (s)
- return -1;
- if ((pcd_buffer[0] & 0x1f) != 5) {
- if (verbose)
- printk("%s: %s is not a CD-ROM\n",
- cd->name, cd->drive ? "Slave" : "Master");
- return -1;
- }
- memcpy(id, pcd_buffer + 16, 16);
- id[16] = 0;
- k = 16;
- while ((k >= 0) && (id[k] <= 0x20)) {
- id[k] = 0;
- k--;
- }
-
- printk("%s: %s: %s\n", cd->name, cd->drive ? "Slave" : "Master", id);
-
- return 0;
-}
-
-/*
- * returns 0, with id set if drive is detected, otherwise an error code.
- */
-static int pcd_probe(struct pcd_unit *cd, int ms)
-{
- if (ms == -1) {
- for (cd->drive = 0; cd->drive <= 1; cd->drive++)
- if (!pcd_reset(cd) && !pcd_identify(cd))
- return 0;
- } else {
- cd->drive = ms;
- if (!pcd_reset(cd) && !pcd_identify(cd))
- return 0;
- }
- return -ENODEV;
-}
-
-static int pcd_probe_capabilities(struct pcd_unit *cd)
-{
- char cmd[12] = { 0x5a, 1 << 3, 0x2a, 0, 0, 0, 0, 18, 0, 0, 0, 0 };
- char buffer[32];
- int ret;
-
- ret = pcd_atapi(cd, cmd, 18, buffer, "mode sense capabilities");
- if (ret)
- return ret;
-
- /* we should now have the cap page */
- if ((buffer[11] & 1) == 0)
- cd->info.mask |= CDC_CD_R;
- if ((buffer[11] & 2) == 0)
- cd->info.mask |= CDC_CD_RW;
- if ((buffer[12] & 1) == 0)
- cd->info.mask |= CDC_PLAY_AUDIO;
- if ((buffer[14] & 1) == 0)
- cd->info.mask |= CDC_LOCK;
- if ((buffer[14] & 8) == 0)
- cd->info.mask |= CDC_OPEN_TRAY;
- if ((buffer[14] >> 6) == 0)
- cd->info.mask |= CDC_CLOSE_TRAY;
-
- return 0;
-}
-
-/* I/O request processing */
-static int pcd_queue;
-
-static int set_next_request(void)
-{
- struct pcd_unit *cd;
- int old_pos = pcd_queue;
-
- do {
- cd = &pcd[pcd_queue];
- if (++pcd_queue == PCD_UNITS)
- pcd_queue = 0;
- if (cd->present && !list_empty(&cd->rq_list)) {
- pcd_req = list_first_entry(&cd->rq_list, struct request,
- queuelist);
- list_del_init(&pcd_req->queuelist);
- blk_mq_start_request(pcd_req);
- break;
- }
- } while (pcd_queue != old_pos);
-
- return pcd_req != NULL;
-}
-
-static void pcd_request(void)
-{
- struct pcd_unit *cd;
-
- if (pcd_busy)
- return;
-
- if (!pcd_req && !set_next_request())
- return;
-
- cd = pcd_req->q->disk->private_data;
- if (cd != pcd_current)
- pcd_bufblk = -1;
- pcd_current = cd;
- pcd_sector = blk_rq_pos(pcd_req);
- pcd_count = blk_rq_cur_sectors(pcd_req);
- pcd_buf = bio_data(pcd_req->bio);
- pcd_busy = 1;
- ps_set_intr(do_pcd_read, NULL, 0, nice);
-}
-
-static blk_status_t pcd_queue_rq(struct blk_mq_hw_ctx *hctx,
- const struct blk_mq_queue_data *bd)
-{
- struct pcd_unit *cd = hctx->queue->queuedata;
-
- if (rq_data_dir(bd->rq) != READ) {
- blk_mq_start_request(bd->rq);
- return BLK_STS_IOERR;
- }
-
- spin_lock_irq(&pcd_lock);
- list_add_tail(&bd->rq->queuelist, &cd->rq_list);
- pcd_request();
- spin_unlock_irq(&pcd_lock);
-
- return BLK_STS_OK;
-}
-
-static inline void next_request(blk_status_t err)
-{
- unsigned long saved_flags;
-
- spin_lock_irqsave(&pcd_lock, saved_flags);
- if (!blk_update_request(pcd_req, err, blk_rq_cur_bytes(pcd_req))) {
- __blk_mq_end_request(pcd_req, err);
- pcd_req = NULL;
- }
- pcd_busy = 0;
- pcd_request();
- spin_unlock_irqrestore(&pcd_lock, saved_flags);
-}
-
-static int pcd_ready(void)
-{
- return (((status_reg(pcd_current) & (IDE_BUSY | IDE_DRQ)) == IDE_DRQ));
-}
-
-static void pcd_transfer(void)
-{
-
- while (pcd_count && (pcd_sector / 4 == pcd_bufblk)) {
- int o = (pcd_sector % 4) * 512;
- memcpy(pcd_buf, pcd_buffer + o, 512);
- pcd_count--;
- pcd_buf += 512;
- pcd_sector++;
- }
-}
-
-static void pcd_start(void)
-{
- int b, i;
- char rd_cmd[12] = { 0xa8, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 };
-
- pcd_bufblk = pcd_sector / 4;
- b = pcd_bufblk;
- for (i = 0; i < 4; i++) {
- rd_cmd[5 - i] = b & 0xff;
- b = b >> 8;
- }
-
- if (pcd_command(pcd_current, rd_cmd, 2048, "read block")) {
- pcd_bufblk = -1;
- next_request(BLK_STS_IOERR);
- return;
- }
-
- mdelay(1);
-
- ps_set_intr(do_pcd_read_drq, pcd_ready, PCD_TMO, nice);
-}
-
-static void do_pcd_read(void)
-{
- pcd_busy = 1;
- pcd_retries = 0;
- pcd_transfer();
- if (!pcd_count) {
- next_request(0);
- return;
- }
-
- pi_do_claimed(pcd_current->pi, pcd_start);
-}
-
-static void do_pcd_read_drq(void)
-{
- unsigned long saved_flags;
-
- if (pcd_completion(pcd_current, pcd_buffer, "read block")) {
- if (pcd_retries < PCD_RETRIES) {
- mdelay(1);
- pcd_retries++;
- pi_do_claimed(pcd_current->pi, pcd_start);
- return;
- }
- pcd_bufblk = -1;
- next_request(BLK_STS_IOERR);
- return;
- }
-
- do_pcd_read();
- spin_lock_irqsave(&pcd_lock, saved_flags);
- pcd_request();
- spin_unlock_irqrestore(&pcd_lock, saved_flags);
-}
-
-/* the audio_ioctl stuff is adapted from sr_ioctl.c */
-
-static int pcd_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg)
-{
- struct pcd_unit *cd = cdi->handle;
-
- switch (cmd) {
-
- case CDROMREADTOCHDR:
-
- {
- char cmd[12] =
- { GPCMD_READ_TOC_PMA_ATIP, 0, 0, 0, 0, 0, 0, 0, 12,
- 0, 0, 0 };
- struct cdrom_tochdr *tochdr =
- (struct cdrom_tochdr *) arg;
- char buffer[32];
- int r;
-
- r = pcd_atapi(cd, cmd, 12, buffer, "read toc header");
-
- tochdr->cdth_trk0 = buffer[2];
- tochdr->cdth_trk1 = buffer[3];
-
- return r ? -EIO : 0;
- }
-
- case CDROMREADTOCENTRY:
-
- {
- char cmd[12] =
- { GPCMD_READ_TOC_PMA_ATIP, 0, 0, 0, 0, 0, 0, 0, 12,
- 0, 0, 0 };
-
- struct cdrom_tocentry *tocentry =
- (struct cdrom_tocentry *) arg;
- unsigned char buffer[32];
- int r;
-
- cmd[1] =
- (tocentry->cdte_format == CDROM_MSF ? 0x02 : 0);
- cmd[6] = tocentry->cdte_track;
-
- r = pcd_atapi(cd, cmd, 12, buffer, "read toc entry");
-
- tocentry->cdte_ctrl = buffer[5] & 0xf;
- tocentry->cdte_adr = buffer[5] >> 4;
- tocentry->cdte_datamode =
- (tocentry->cdte_ctrl & 0x04) ? 1 : 0;
- if (tocentry->cdte_format == CDROM_MSF) {
- tocentry->cdte_addr.msf.minute = buffer[9];
- tocentry->cdte_addr.msf.second = buffer[10];
- tocentry->cdte_addr.msf.frame = buffer[11];
- } else
- tocentry->cdte_addr.lba =
- (((((buffer[8] << 8) + buffer[9]) << 8)
- + buffer[10]) << 8) + buffer[11];
-
- return r ? -EIO : 0;
- }
-
- default:
-
- return -ENOSYS;
- }
-}
-
-static int pcd_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn)
-{
- char cmd[12] =
- { GPCMD_READ_SUBCHANNEL, 0, 0x40, 2, 0, 0, 0, 0, 24, 0, 0, 0 };
- char buffer[32];
-
- if (pcd_atapi(cdi->handle, cmd, 24, buffer, "get mcn"))
- return -EIO;
-
- memcpy(mcn->medium_catalog_number, buffer + 9, 13);
- mcn->medium_catalog_number[13] = 0;
-
- return 0;
-}
-
-static int pcd_init_unit(struct pcd_unit *cd, bool autoprobe, int port,
- int mode, int unit, int protocol, int delay, int ms)
-{
- struct gendisk *disk;
- int ret;
-
- ret = blk_mq_alloc_sq_tag_set(&cd->tag_set, &pcd_mq_ops, 1,
- BLK_MQ_F_SHOULD_MERGE);
- if (ret)
- return ret;
-
- disk = blk_mq_alloc_disk(&cd->tag_set, cd);
- if (IS_ERR(disk)) {
- ret = PTR_ERR(disk);
- goto out_free_tag_set;
- }
-
- INIT_LIST_HEAD(&cd->rq_list);
- blk_queue_bounce_limit(disk->queue, BLK_BOUNCE_HIGH);
- cd->disk = disk;
- cd->pi = &cd->pia;
- cd->present = 0;
- cd->last_sense = 0;
- cd->changed = 1;
- cd->drive = (*drives[cd - pcd])[D_SLV];
-
- cd->name = &cd->info.name[0];
- snprintf(cd->name, sizeof(cd->info.name), "%s%d", name, unit);
- cd->info.ops = &pcd_dops;
- cd->info.handle = cd;
- cd->info.speed = 0;
- cd->info.capacity = 1;
- cd->info.mask = 0;
- disk->major = major;
- disk->first_minor = unit;
- disk->minors = 1;
- strcpy(disk->disk_name, cd->name); /* umm... */
- disk->fops = &pcd_bdops;
- disk->flags |= GENHD_FL_NO_PART;
- disk->events = DISK_EVENT_MEDIA_CHANGE;
- disk->event_flags = DISK_EVENT_FLAG_BLOCK_ON_EXCL_WRITE;
-
- if (!pi_init(cd->pi, autoprobe, port, mode, unit, protocol, delay,
- pcd_buffer, PI_PCD, verbose, cd->name)) {
- ret = -ENODEV;
- goto out_free_disk;
- }
- ret = pcd_probe(cd, ms);
- if (ret)
- goto out_pi_release;
-
- cd->present = 1;
- pcd_probe_capabilities(cd);
- ret = register_cdrom(cd->disk, &cd->info);
- if (ret)
- goto out_pi_release;
- ret = add_disk(cd->disk);
- if (ret)
- goto out_unreg_cdrom;
- return 0;
-
-out_unreg_cdrom:
- unregister_cdrom(&cd->info);
-out_pi_release:
- pi_release(cd->pi);
-out_free_disk:
- put_disk(cd->disk);
-out_free_tag_set:
- blk_mq_free_tag_set(&cd->tag_set);
- return ret;
-}
-
-static int __init pcd_init(void)
-{
- int found = 0, unit;
-
- if (disable)
- return -EINVAL;
-
- if (register_blkdev(major, name))
- return -EBUSY;
-
- pr_info("%s: %s version %s, major %d, nice %d\n",
- name, name, PCD_VERSION, major, nice);
-
- par_drv = pi_register_driver(name);
- if (!par_drv) {
- pr_err("failed to register %s driver\n", name);
- goto out_unregister_blkdev;
- }
-
- for (unit = 0; unit < PCD_UNITS; unit++) {
- if ((*drives[unit])[D_PRT])
- pcd_drive_count++;
- }
-
- if (pcd_drive_count == 0) { /* nothing spec'd - so autoprobe for 1 */
- if (!pcd_init_unit(pcd, 1, -1, -1, -1, -1, -1, -1))
- found++;
- } else {
- for (unit = 0; unit < PCD_UNITS; unit++) {
- struct pcd_unit *cd = &pcd[unit];
- int *conf = *drives[unit];
-
- if (!conf[D_PRT])
- continue;
- if (!pcd_init_unit(cd, 0, conf[D_PRT], conf[D_MOD],
- conf[D_UNI], conf[D_PRO], conf[D_DLY],
- conf[D_SLV]))
- found++;
- }
- }
-
- if (!found) {
- pr_info("%s: No CD-ROM drive found\n", name);
- goto out_unregister_pi_driver;
- }
-
- return 0;
-
-out_unregister_pi_driver:
- pi_unregister_driver(par_drv);
-out_unregister_blkdev:
- unregister_blkdev(major, name);
- return -ENODEV;
-}
-
-static void __exit pcd_exit(void)
-{
- struct pcd_unit *cd;
- int unit;
-
- for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) {
- if (!cd->present)
- continue;
-
- unregister_cdrom(&cd->info);
- del_gendisk(cd->disk);
- pi_release(cd->pi);
- put_disk(cd->disk);
-
- blk_mq_free_tag_set(&cd->tag_set);
- }
- pi_unregister_driver(par_drv);
- unregister_blkdev(major, name);
-}
-
-MODULE_LICENSE("GPL");
-module_init(pcd_init)
-module_exit(pcd_exit)
diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
deleted file mode 100644
index f8a75bc90f70..000000000000
--- a/drivers/block/paride/pd.c
+++ /dev/null
@@ -1,1032 +0,0 @@
-/*
- pd.c (c) 1997-8 Grant R. Guenther <grant@torque.net>
- Under the terms of the GNU General Public License.
-
- This is the high-level driver for parallel port IDE hard
- drives based on chips supported by the paride module.
-
- By default, the driver will autoprobe for a single parallel
- port IDE drive, but if their individual parameters are
- specified, the driver can handle up to 4 drives.
-
- The behaviour of the pd driver can be altered by setting
- some parameters from the insmod command line. The following
- parameters are adjustable:
-
- drive0 These four arguments can be arrays of
- drive1 1-8 integers as follows:
- drive2
- drive3 <prt>,<pro>,<uni>,<mod>,<geo>,<sby>,<dly>,<slv>
-
- Where,
-
- <prt> is the base of the parallel port address for
- the corresponding drive. (required)
-
- <pro> is the protocol number for the adapter that
- supports this drive. These numbers are
- logged by 'paride' when the protocol modules
- are initialised. (0 if not given)
-
- <uni> for those adapters that support chained
- devices, this is the unit selector for the
- chain of devices on the given port. It should
- be zero for devices that don't support chaining.
- (0 if not given)
-
- <mod> this can be -1 to choose the best mode, or one
- of the mode numbers supported by the adapter.
- (-1 if not given)
-
- <geo> this defaults to 0 to indicate that the driver
- should use the CHS geometry provided by the drive
- itself. If set to 1, the driver will provide
- a logical geometry with 64 heads and 32 sectors
- per track, to be consistent with most SCSI
- drivers. (0 if not given)
-
- <sby> set this to zero to disable the power saving
- standby mode, if needed. (1 if not given)
-
- <dly> some parallel ports require the driver to
- go more slowly. -1 sets a default value that
- should work with the chosen protocol. Otherwise,
- set this to a small integer, the larger it is
- the slower the port i/o. In some cases, setting
- this to zero will speed up the device. (default -1)
-
- <slv> IDE disks can be jumpered to master or slave.
- Set this to 0 to choose the master drive, 1 to
- choose the slave, -1 (the default) to choose the
- first drive found.
-
-
- major You may use this parameter to override the
- default major number (45) that this driver
- will use. Be sure to change the device
- name as well.
-
- name This parameter is a character string that
- contains the name the kernel will use for this
- device (in /proc output, for instance).
- (default "pd")
-
- cluster The driver will attempt to aggregate requests
- for adjacent blocks into larger multi-block
- clusters. The maximum cluster size (in 512
- byte sectors) is set with this parameter.
- (default 64)
-
- verbose This parameter controls the amount of logging
- that the driver will do. Set it to 0 for
- normal operation, 1 to see autoprobe progress
- messages, or 2 to see additional debugging
- output. (default 0)
-
- nice This parameter controls the driver's use of
- idle CPU time, at the expense of some speed.
-
- If this driver is built into the kernel, you can use kernel
- the following command line parameters, with the same values
- as the corresponding module parameters listed above:
-
- pd.drive0
- pd.drive1
- pd.drive2
- pd.drive3
- pd.cluster
- pd.nice
-
- In addition, you can use the parameter pd.disable to disable
- the driver entirely.
-
-*/
-
-/* Changes:
-
- 1.01 GRG 1997.01.24 Restored pd_reset()
- Added eject ioctl
- 1.02 GRG 1998.05.06 SMP spinlock changes,
- Added slave support
- 1.03 GRG 1998.06.16 Eliminate an Ugh.
- 1.04 GRG 1998.08.15 Extra debugging, use HZ in loop timing
- 1.05 GRG 1998.09.24 Added jumbo support
-
-*/
-
-#define PD_VERSION "1.05"
-#define PD_MAJOR 45
-#define PD_NAME "pd"
-#define PD_UNITS 4
-
-/* Here are things one can override from the insmod command.
- Most are autoprobed by paride unless set here. Verbose is off
- by default.
-
-*/
-#include <linux/types.h>
-
-static int verbose = 0;
-static int major = PD_MAJOR;
-static char *name = PD_NAME;
-static int cluster = 64;
-static int nice = 0;
-static int disable = 0;
-
-static int drive0[8] = { 0, 0, 0, -1, 0, 1, -1, -1 };
-static int drive1[8] = { 0, 0, 0, -1, 0, 1, -1, -1 };
-static int drive2[8] = { 0, 0, 0, -1, 0, 1, -1, -1 };
-static int drive3[8] = { 0, 0, 0, -1, 0, 1, -1, -1 };
-
-static int (*drives[4])[8] = {&drive0, &drive1, &drive2, &drive3};
-
-enum {D_PRT, D_PRO, D_UNI, D_MOD, D_GEO, D_SBY, D_DLY, D_SLV};
-
-/* end of parameters */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/gfp.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/hdreg.h>
-#include <linux/cdrom.h> /* for the eject ioctl */
-#include <linux/blk-mq.h>
-#include <linux/blkpg.h>
-#include <linux/kernel.h>
-#include <linux/mutex.h>
-#include <linux/uaccess.h>
-#include <linux/workqueue.h>
-
-static DEFINE_MUTEX(pd_mutex);
-static DEFINE_SPINLOCK(pd_lock);
-
-module_param(verbose, int, 0);
-module_param(major, int, 0);
-module_param(name, charp, 0);
-module_param(cluster, int, 0);
-module_param(nice, int, 0);
-module_param_array(drive0, int, NULL, 0);
-module_param_array(drive1, int, NULL, 0);
-module_param_array(drive2, int, NULL, 0);
-module_param_array(drive3, int, NULL, 0);
-
-#include "paride.h"
-
-#define PD_BITS 4
-
-/* numbers for "SCSI" geometry */
-
-#define PD_LOG_HEADS 64
-#define PD_LOG_SECTS 32
-
-#define PD_ID_OFF 54
-#define PD_ID_LEN 14
-
-#define PD_MAX_RETRIES 5
-#define PD_TMO 800 /* interrupt timeout in jiffies */
-#define PD_SPIN_DEL 50 /* spin delay in micro-seconds */
-
-#define PD_SPIN (1000000*PD_TMO)/(HZ*PD_SPIN_DEL)
-
-#define STAT_ERR 0x00001
-#define STAT_INDEX 0x00002
-#define STAT_ECC 0x00004
-#define STAT_DRQ 0x00008
-#define STAT_SEEK 0x00010
-#define STAT_WRERR 0x00020
-#define STAT_READY 0x00040
-#define STAT_BUSY 0x00080
-
-#define ERR_AMNF 0x00100
-#define ERR_TK0NF 0x00200
-#define ERR_ABRT 0x00400
-#define ERR_MCR 0x00800
-#define ERR_IDNF 0x01000
-#define ERR_MC 0x02000
-#define ERR_UNC 0x04000
-#define ERR_TMO 0x10000
-
-#define IDE_READ 0x20
-#define IDE_WRITE 0x30
-#define IDE_READ_VRFY 0x40
-#define IDE_INIT_DEV_PARMS 0x91
-#define IDE_STANDBY 0x96
-#define IDE_ACKCHANGE 0xdb
-#define IDE_DOORLOCK 0xde
-#define IDE_DOORUNLOCK 0xdf
-#define IDE_IDENTIFY 0xec
-#define IDE_EJECT 0xed
-
-#define PD_NAMELEN 8
-
-struct pd_unit {
- struct pi_adapter pia; /* interface to paride layer */
- struct pi_adapter *pi;
- int access; /* count of active opens ... */
- int capacity; /* Size of this volume in sectors */
- int heads; /* physical geometry */
- int sectors;
- int cylinders;
- int can_lba;
- int drive; /* master=0 slave=1 */
- int changed; /* Have we seen a disk change ? */
- int removable; /* removable media device ? */
- int standby;
- int alt_geom;
- char name[PD_NAMELEN]; /* pda, pdb, etc ... */
- struct gendisk *gd;
- struct blk_mq_tag_set tag_set;
- struct list_head rq_list;
-};
-
-static struct pd_unit pd[PD_UNITS];
-
-struct pd_req {
- /* for REQ_OP_DRV_IN: */
- enum action (*func)(struct pd_unit *disk);
-};
-
-static char pd_scratch[512]; /* scratch block buffer */
-
-static char *pd_errs[17] = { "ERR", "INDEX", "ECC", "DRQ", "SEEK", "WRERR",
- "READY", "BUSY", "AMNF", "TK0NF", "ABRT", "MCR",
- "IDNF", "MC", "UNC", "???", "TMO"
-};
-
-static void *par_drv; /* reference of parport driver */
-
-static inline int status_reg(struct pd_unit *disk)
-{
- return pi_read_regr(disk->pi, 1, 6);
-}
-
-static inline int read_reg(struct pd_unit *disk, int reg)
-{
- return pi_read_regr(disk->pi, 0, reg);
-}
-
-static inline void write_status(struct pd_unit *disk, int val)
-{
- pi_write_regr(disk->pi, 1, 6, val);
-}
-
-static inline void write_reg(struct pd_unit *disk, int reg, int val)
-{
- pi_write_regr(disk->pi, 0, reg, val);
-}
-
-static inline u8 DRIVE(struct pd_unit *disk)
-{
- return 0xa0+0x10*disk->drive;
-}
-
-/* ide command interface */
-
-static void pd_print_error(struct pd_unit *disk, char *msg, int status)
-{
- int i;
-
- printk("%s: %s: status = 0x%x =", disk->name, msg, status);
- for (i = 0; i < ARRAY_SIZE(pd_errs); i++)
- if (status & (1 << i))
- printk(" %s", pd_errs[i]);
- printk("\n");
-}
-
-static void pd_reset(struct pd_unit *disk)
-{ /* called only for MASTER drive */
- write_status(disk, 4);
- udelay(50);
- write_status(disk, 0);
- udelay(250);
-}
-
-#define DBMSG(msg) ((verbose>1)?(msg):NULL)
-
-static int pd_wait_for(struct pd_unit *disk, int w, char *msg)
-{ /* polled wait */
- int k, r, e;
-
- k = 0;
- while (k < PD_SPIN) {
- r = status_reg(disk);
- k++;
- if (((r & w) == w) && !(r & STAT_BUSY))
- break;
- udelay(PD_SPIN_DEL);
- }
- e = (read_reg(disk, 1) << 8) + read_reg(disk, 7);
- if (k >= PD_SPIN)
- e |= ERR_TMO;
- if ((e & (STAT_ERR | ERR_TMO)) && (msg != NULL))
- pd_print_error(disk, msg, e);
- return e;
-}
-
-static void pd_send_command(struct pd_unit *disk, int n, int s, int h, int c0, int c1, int func)
-{
- write_reg(disk, 6, DRIVE(disk) + h);
- write_reg(disk, 1, 0); /* the IDE task file */
- write_reg(disk, 2, n);
- write_reg(disk, 3, s);
- write_reg(disk, 4, c0);
- write_reg(disk, 5, c1);
- write_reg(disk, 7, func);
-
- udelay(1);
-}
-
-static void pd_ide_command(struct pd_unit *disk, int func, int block, int count)
-{
- int c1, c0, h, s;
-
- if (disk->can_lba) {
- s = block & 255;
- c0 = (block >>= 8) & 255;
- c1 = (block >>= 8) & 255;
- h = ((block >>= 8) & 15) + 0x40;
- } else {
- s = (block % disk->sectors) + 1;
- h = (block /= disk->sectors) % disk->heads;
- c0 = (block /= disk->heads) % 256;
- c1 = (block >>= 8);
- }
- pd_send_command(disk, count, s, h, c0, c1, func);
-}
-
-/* The i/o request engine */
-
-enum action {Fail = 0, Ok = 1, Hold, Wait};
-
-static struct request *pd_req; /* current request */
-static enum action (*phase)(void);
-
-static void run_fsm(void);
-
-static void ps_tq_int(struct work_struct *work);
-
-static DECLARE_DELAYED_WORK(fsm_tq, ps_tq_int);
-
-static void schedule_fsm(void)
-{
- if (!nice)
- schedule_delayed_work(&fsm_tq, 0);
- else
- schedule_delayed_work(&fsm_tq, nice-1);
-}
-
-static void ps_tq_int(struct work_struct *work)
-{
- run_fsm();
-}
-
-static enum action do_pd_io_start(void);
-static enum action pd_special(void);
-static enum action do_pd_read_start(void);
-static enum action do_pd_write_start(void);
-static enum action do_pd_read_drq(void);
-static enum action do_pd_write_done(void);
-
-static int pd_queue;
-static int pd_claimed;
-
-static struct pd_unit *pd_current; /* current request's drive */
-static PIA *pi_current; /* current request's PIA */
-
-static int set_next_request(void)
-{
- struct gendisk *disk;
- struct request_queue *q;
- int old_pos = pd_queue;
-
- do {
- disk = pd[pd_queue].gd;
- q = disk ? disk->queue : NULL;
- if (++pd_queue == PD_UNITS)
- pd_queue = 0;
- if (q) {
- struct pd_unit *disk = q->queuedata;
-
- if (list_empty(&disk->rq_list))
- continue;
-
- pd_req = list_first_entry(&disk->rq_list,
- struct request,
- queuelist);
- list_del_init(&pd_req->queuelist);
- blk_mq_start_request(pd_req);
- break;
- }
- } while (pd_queue != old_pos);
-
- return pd_req != NULL;
-}
-
-static void run_fsm(void)
-{
- while (1) {
- enum action res;
- int stop = 0;
-
- if (!phase) {
- pd_current = pd_req->q->disk->private_data;
- pi_current = pd_current->pi;
- phase = do_pd_io_start;
- }
-
- switch (pd_claimed) {
- case 0:
- pd_claimed = 1;
- if (!pi_schedule_claimed(pi_current, run_fsm))
- return;
- fallthrough;
- case 1:
- pd_claimed = 2;
- pi_current->proto->connect(pi_current);
- }
-
- switch(res = phase()) {
- case Ok: case Fail: {
- blk_status_t err;
-
- err = res == Ok ? 0 : BLK_STS_IOERR;
- pi_disconnect(pi_current);
- pd_claimed = 0;
- phase = NULL;
- spin_lock_irq(&pd_lock);
- if (!blk_update_request(pd_req, err,
- blk_rq_cur_bytes(pd_req))) {
- __blk_mq_end_request(pd_req, err);
- pd_req = NULL;
- stop = !set_next_request();
- }
- spin_unlock_irq(&pd_lock);
- if (stop)
- return;
- }
- fallthrough;
- case Hold:
- schedule_fsm();
- return;
- case Wait:
- pi_disconnect(pi_current);
- pd_claimed = 0;
- }
- }
-}
-
-static int pd_retries = 0; /* i/o error retry count */
-static int pd_block; /* address of next requested block */
-static int pd_count; /* number of blocks still to do */
-static int pd_run; /* sectors in current cluster */
-static char *pd_buf; /* buffer for request in progress */
-
-static enum action do_pd_io_start(void)
-{
- switch (req_op(pd_req)) {
- case REQ_OP_DRV_IN:
- phase = pd_special;
- return pd_special();
- case REQ_OP_READ:
- case REQ_OP_WRITE:
- pd_block = blk_rq_pos(pd_req);
- pd_count = blk_rq_cur_sectors(pd_req);
- if (pd_block + pd_count > get_capacity(pd_req->q->disk))
- return Fail;
- pd_run = blk_rq_sectors(pd_req);
- pd_buf = bio_data(pd_req->bio);
- pd_retries = 0;
- if (req_op(pd_req) == REQ_OP_READ)
- return do_pd_read_start();
- else
- return do_pd_write_start();
- default:
- break;
- }
- return Fail;
-}
-
-static enum action pd_special(void)
-{
- struct pd_req *req = blk_mq_rq_to_pdu(pd_req);
-
- return req->func(pd_current);
-}
-
-static int pd_next_buf(void)
-{
- unsigned long saved_flags;
-
- pd_count--;
- pd_run--;
- pd_buf += 512;
- pd_block++;
- if (!pd_run)
- return 1;
- if (pd_count)
- return 0;
- spin_lock_irqsave(&pd_lock, saved_flags);
- if (!blk_update_request(pd_req, 0, blk_rq_cur_bytes(pd_req))) {
- __blk_mq_end_request(pd_req, 0);
- pd_req = NULL;
- pd_count = 0;
- pd_buf = NULL;
- } else {
- pd_count = blk_rq_cur_sectors(pd_req);
- pd_buf = bio_data(pd_req->bio);
- }
- spin_unlock_irqrestore(&pd_lock, saved_flags);
- return !pd_count;
-}
-
-static unsigned long pd_timeout;
-
-static enum action do_pd_read_start(void)
-{
- if (pd_wait_for(pd_current, STAT_READY, "do_pd_read") & STAT_ERR) {
- if (pd_retries < PD_MAX_RETRIES) {
- pd_retries++;
- return Wait;
- }
- return Fail;
- }
- pd_ide_command(pd_current, IDE_READ, pd_block, pd_run);
- phase = do_pd_read_drq;
- pd_timeout = jiffies + PD_TMO;
- return Hold;
-}
-
-static enum action do_pd_write_start(void)
-{
- if (pd_wait_for(pd_current, STAT_READY, "do_pd_write") & STAT_ERR) {
- if (pd_retries < PD_MAX_RETRIES) {
- pd_retries++;
- return Wait;
- }
- return Fail;
- }
- pd_ide_command(pd_current, IDE_WRITE, pd_block, pd_run);
- while (1) {
- if (pd_wait_for(pd_current, STAT_DRQ, "do_pd_write_drq") & STAT_ERR) {
- if (pd_retries < PD_MAX_RETRIES) {
- pd_retries++;
- return Wait;
- }
- return Fail;
- }
- pi_write_block(pd_current->pi, pd_buf, 512);
- if (pd_next_buf())
- break;
- }
- phase = do_pd_write_done;
- pd_timeout = jiffies + PD_TMO;
- return Hold;
-}
-
-static inline int pd_ready(void)
-{
- return !(status_reg(pd_current) & STAT_BUSY);
-}
-
-static enum action do_pd_read_drq(void)
-{
- if (!pd_ready() && !time_after_eq(jiffies, pd_timeout))
- return Hold;
-
- while (1) {
- if (pd_wait_for(pd_current, STAT_DRQ, "do_pd_read_drq") & STAT_ERR) {
- if (pd_retries < PD_MAX_RETRIES) {
- pd_retries++;
- phase = do_pd_read_start;
- return Wait;
- }
- return Fail;
- }
- pi_read_block(pd_current->pi, pd_buf, 512);
- if (pd_next_buf())
- break;
- }
- return Ok;
-}
-
-static enum action do_pd_write_done(void)
-{
- if (!pd_ready() && !time_after_eq(jiffies, pd_timeout))
- return Hold;
-
- if (pd_wait_for(pd_current, STAT_READY, "do_pd_write_done") & STAT_ERR) {
- if (pd_retries < PD_MAX_RETRIES) {
- pd_retries++;
- phase = do_pd_write_start;
- return Wait;
- }
- return Fail;
- }
- return Ok;
-}
-
-/* special io requests */
-
-/* According to the ATA standard, the default CHS geometry should be
- available following a reset. Some Western Digital drives come up
- in a mode where only LBA addresses are accepted until the device
- parameters are initialised.
-*/
-
-static void pd_init_dev_parms(struct pd_unit *disk)
-{
- pd_wait_for(disk, 0, DBMSG("before init_dev_parms"));
- pd_send_command(disk, disk->sectors, 0, disk->heads - 1, 0, 0,
- IDE_INIT_DEV_PARMS);
- udelay(300);
- pd_wait_for(disk, 0, "Initialise device parameters");
-}
-
-static enum action pd_door_lock(struct pd_unit *disk)
-{
- if (!(pd_wait_for(disk, STAT_READY, "Lock") & STAT_ERR)) {
- pd_send_command(disk, 1, 0, 0, 0, 0, IDE_DOORLOCK);
- pd_wait_for(disk, STAT_READY, "Lock done");
- }
- return Ok;
-}
-
-static enum action pd_door_unlock(struct pd_unit *disk)
-{
- if (!(pd_wait_for(disk, STAT_READY, "Lock") & STAT_ERR)) {
- pd_send_command(disk, 1, 0, 0, 0, 0, IDE_DOORUNLOCK);
- pd_wait_for(disk, STAT_READY, "Lock done");
- }
- return Ok;
-}
-
-static enum action pd_eject(struct pd_unit *disk)
-{
- pd_wait_for(disk, 0, DBMSG("before unlock on eject"));
- pd_send_command(disk, 1, 0, 0, 0, 0, IDE_DOORUNLOCK);
- pd_wait_for(disk, 0, DBMSG("after unlock on eject"));
- pd_wait_for(disk, 0, DBMSG("before eject"));
- pd_send_command(disk, 0, 0, 0, 0, 0, IDE_EJECT);
- pd_wait_for(disk, 0, DBMSG("after eject"));
- return Ok;
-}
-
-static enum action pd_media_check(struct pd_unit *disk)
-{
- int r = pd_wait_for(disk, STAT_READY, DBMSG("before media_check"));
- if (!(r & STAT_ERR)) {
- pd_send_command(disk, 1, 1, 0, 0, 0, IDE_READ_VRFY);
- r = pd_wait_for(disk, STAT_READY, DBMSG("RDY after READ_VRFY"));
- } else
- disk->changed = 1; /* say changed if other error */
- if (r & ERR_MC) {
- disk->changed = 1;
- pd_send_command(disk, 1, 0, 0, 0, 0, IDE_ACKCHANGE);
- pd_wait_for(disk, STAT_READY, DBMSG("RDY after ACKCHANGE"));
- pd_send_command(disk, 1, 1, 0, 0, 0, IDE_READ_VRFY);
- r = pd_wait_for(disk, STAT_READY, DBMSG("RDY after VRFY"));
- }
- return Ok;
-}
-
-static void pd_standby_off(struct pd_unit *disk)
-{
- pd_wait_for(disk, 0, DBMSG("before STANDBY"));
- pd_send_command(disk, 0, 0, 0, 0, 0, IDE_STANDBY);
- pd_wait_for(disk, 0, DBMSG("after STANDBY"));
-}
-
-static enum action pd_identify(struct pd_unit *disk)
-{
- int j;
- char id[PD_ID_LEN + 1];
-
-/* WARNING: here there may be dragons. reset() applies to both drives,
- but we call it only on probing the MASTER. This should allow most
- common configurations to work, but be warned that a reset can clear
- settings on the SLAVE drive.
-*/
-
- if (disk->drive == 0)
- pd_reset(disk);
-
- write_reg(disk, 6, DRIVE(disk));
- pd_wait_for(disk, 0, DBMSG("before IDENT"));
- pd_send_command(disk, 1, 0, 0, 0, 0, IDE_IDENTIFY);
-
- if (pd_wait_for(disk, STAT_DRQ, DBMSG("IDENT DRQ")) & STAT_ERR)
- return Fail;
- pi_read_block(disk->pi, pd_scratch, 512);
- disk->can_lba = pd_scratch[99] & 2;
- disk->sectors = le16_to_cpu(*(__le16 *) (pd_scratch + 12));
- disk->heads = le16_to_cpu(*(__le16 *) (pd_scratch + 6));
- disk->cylinders = le16_to_cpu(*(__le16 *) (pd_scratch + 2));
- if (disk->can_lba)
- disk->capacity = le32_to_cpu(*(__le32 *) (pd_scratch + 120));
- else
- disk->capacity = disk->sectors * disk->heads * disk->cylinders;
-
- for (j = 0; j < PD_ID_LEN; j++)
- id[j ^ 1] = pd_scratch[j + PD_ID_OFF];
- j = PD_ID_LEN - 1;
- while ((j >= 0) && (id[j] <= 0x20))
- j--;
- j++;
- id[j] = 0;
-
- disk->removable = pd_scratch[0] & 0x80;
-
- printk("%s: %s, %s, %d blocks [%dM], (%d/%d/%d), %s media\n",
- disk->name, id,
- disk->drive ? "slave" : "master",
- disk->capacity, disk->capacity / 2048,
- disk->cylinders, disk->heads, disk->sectors,
- disk->removable ? "removable" : "fixed");
-
- if (disk->capacity)
- pd_init_dev_parms(disk);
- if (!disk->standby)
- pd_standby_off(disk);
-
- return Ok;
-}
-
-/* end of io request engine */
-
-static blk_status_t pd_queue_rq(struct blk_mq_hw_ctx *hctx,
- const struct blk_mq_queue_data *bd)
-{
- struct pd_unit *disk = hctx->queue->queuedata;
-
- spin_lock_irq(&pd_lock);
- if (!pd_req) {
- pd_req = bd->rq;
- blk_mq_start_request(pd_req);
- } else
- list_add_tail(&bd->rq->queuelist, &disk->rq_list);
- spin_unlock_irq(&pd_lock);
-
- run_fsm();
- return BLK_STS_OK;
-}
-
-static int pd_special_command(struct pd_unit *disk,
- enum action (*func)(struct pd_unit *disk))
-{
- struct request *rq;
- struct pd_req *req;
-
- rq = blk_mq_alloc_request(disk->gd->queue, REQ_OP_DRV_IN, 0);
- if (IS_ERR(rq))
- return PTR_ERR(rq);
- req = blk_mq_rq_to_pdu(rq);
-
- req->func = func;
- blk_execute_rq(rq, false);
- blk_mq_free_request(rq);
- return 0;
-}
-
-/* kernel glue structures */
-
-static int pd_open(struct block_device *bdev, fmode_t mode)
-{
- struct pd_unit *disk = bdev->bd_disk->private_data;
-
- mutex_lock(&pd_mutex);
- disk->access++;
-
- if (disk->removable) {
- pd_special_command(disk, pd_media_check);
- pd_special_command(disk, pd_door_lock);
- }
- mutex_unlock(&pd_mutex);
- return 0;
-}
-
-static int pd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
-{
- struct pd_unit *disk = bdev->bd_disk->private_data;
-
- if (disk->alt_geom) {
- geo->heads = PD_LOG_HEADS;
- geo->sectors = PD_LOG_SECTS;
- geo->cylinders = disk->capacity / (geo->heads * geo->sectors);
- } else {
- geo->heads = disk->heads;
- geo->sectors = disk->sectors;
- geo->cylinders = disk->cylinders;
- }
-
- return 0;
-}
-
-static int pd_ioctl(struct block_device *bdev, fmode_t mode,
- unsigned int cmd, unsigned long arg)
-{
- struct pd_unit *disk = bdev->bd_disk->private_data;
-
- switch (cmd) {
- case CDROMEJECT:
- mutex_lock(&pd_mutex);
- if (disk->access == 1)
- pd_special_command(disk, pd_eject);
- mutex_unlock(&pd_mutex);
- return 0;
- default:
- return -EINVAL;
- }
-}
-
-static void pd_release(struct gendisk *p, fmode_t mode)
-{
- struct pd_unit *disk = p->private_data;
-
- mutex_lock(&pd_mutex);
- if (!--disk->access && disk->removable)
- pd_special_command(disk, pd_door_unlock);
- mutex_unlock(&pd_mutex);
-}
-
-static unsigned int pd_check_events(struct gendisk *p, unsigned int clearing)
-{
- struct pd_unit *disk = p->private_data;
- int r;
- if (!disk->removable)
- return 0;
- pd_special_command(disk, pd_media_check);
- r = disk->changed;
- disk->changed = 0;
- return r ? DISK_EVENT_MEDIA_CHANGE : 0;
-}
-
-static const struct block_device_operations pd_fops = {
- .owner = THIS_MODULE,
- .open = pd_open,
- .release = pd_release,
- .ioctl = pd_ioctl,
- .compat_ioctl = pd_ioctl,
- .getgeo = pd_getgeo,
- .check_events = pd_check_events,
-};
-
-/* probing */
-
-static const struct blk_mq_ops pd_mq_ops = {
- .queue_rq = pd_queue_rq,
-};
-
-static int pd_probe_drive(struct pd_unit *disk, int autoprobe, int port,
- int mode, int unit, int protocol, int delay)
-{
- int index = disk - pd;
- int *parm = *drives[index];
- struct gendisk *p;
- int ret;
-
- disk->pi = &disk->pia;
- disk->access = 0;
- disk->changed = 1;
- disk->capacity = 0;
- disk->drive = parm[D_SLV];
- snprintf(disk->name, PD_NAMELEN, "%s%c", name, 'a' + index);
- disk->alt_geom = parm[D_GEO];
- disk->standby = parm[D_SBY];
- INIT_LIST_HEAD(&disk->rq_list);
-
- if (!pi_init(disk->pi, autoprobe, port, mode, unit, protocol, delay,
- pd_scratch, PI_PD, verbose, disk->name))
- return -ENXIO;
-
- memset(&disk->tag_set, 0, sizeof(disk->tag_set));
- disk->tag_set.ops = &pd_mq_ops;
- disk->tag_set.cmd_size = sizeof(struct pd_req);
- disk->tag_set.nr_hw_queues = 1;
- disk->tag_set.nr_maps = 1;
- disk->tag_set.queue_depth = 2;
- disk->tag_set.numa_node = NUMA_NO_NODE;
- disk->tag_set.flags = BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_BLOCKING;
- ret = blk_mq_alloc_tag_set(&disk->tag_set);
- if (ret)
- goto pi_release;
-
- p = blk_mq_alloc_disk(&disk->tag_set, disk);
- if (IS_ERR(p)) {
- ret = PTR_ERR(p);
- goto free_tag_set;
- }
- disk->gd = p;
-
- strcpy(p->disk_name, disk->name);
- p->fops = &pd_fops;
- p->major = major;
- p->first_minor = (disk - pd) << PD_BITS;
- p->minors = 1 << PD_BITS;
- p->events = DISK_EVENT_MEDIA_CHANGE;
- p->private_data = disk;
- blk_queue_max_hw_sectors(p->queue, cluster);
- blk_queue_bounce_limit(p->queue, BLK_BOUNCE_HIGH);
-
- if (disk->drive == -1) {
- for (disk->drive = 0; disk->drive <= 1; disk->drive++) {
- ret = pd_special_command(disk, pd_identify);
- if (ret == 0)
- break;
- }
- } else {
- ret = pd_special_command(disk, pd_identify);
- }
- if (ret)
- goto put_disk;
- set_capacity(disk->gd, disk->capacity);
- ret = add_disk(disk->gd);
- if (ret)
- goto cleanup_disk;
- return 0;
-cleanup_disk:
- put_disk(disk->gd);
-put_disk:
- put_disk(p);
- disk->gd = NULL;
-free_tag_set:
- blk_mq_free_tag_set(&disk->tag_set);
-pi_release:
- pi_release(disk->pi);
- return ret;
-}
-
-static int __init pd_init(void)
-{
- int found = 0, unit, pd_drive_count = 0;
- struct pd_unit *disk;
-
- if (disable)
- return -ENODEV;
-
- if (register_blkdev(major, name))
- return -ENODEV;
-
- printk("%s: %s version %s, major %d, cluster %d, nice %d\n",
- name, name, PD_VERSION, major, cluster, nice);
-
- par_drv = pi_register_driver(name);
- if (!par_drv) {
- pr_err("failed to register %s driver\n", name);
- goto out_unregister_blkdev;
- }
-
- for (unit = 0; unit < PD_UNITS; unit++) {
- int *parm = *drives[unit];
-
- if (parm[D_PRT])
- pd_drive_count++;
- }
-
- if (pd_drive_count == 0) { /* nothing spec'd - so autoprobe for 1 */
- if (!pd_probe_drive(pd, 1, -1, -1, -1, -1, -1))
- found++;
- } else {
- for (unit = 0, disk = pd; unit < PD_UNITS; unit++, disk++) {
- int *parm = *drives[unit];
- if (!parm[D_PRT])
- continue;
- if (!pd_probe_drive(disk, 0, parm[D_PRT], parm[D_MOD],
- parm[D_UNI], parm[D_PRO], parm[D_DLY]))
- found++;
- }
- }
- if (!found) {
- printk("%s: no valid drive found\n", name);
- goto out_pi_unregister_driver;
- }
-
- return 0;
-
-out_pi_unregister_driver:
- pi_unregister_driver(par_drv);
-out_unregister_blkdev:
- unregister_blkdev(major, name);
- return -ENODEV;
-}
-
-static void __exit pd_exit(void)
-{
- struct pd_unit *disk;
- int unit;
- unregister_blkdev(major, name);
- for (unit = 0, disk = pd; unit < PD_UNITS; unit++, disk++) {
- struct gendisk *p = disk->gd;
- if (p) {
- disk->gd = NULL;
- del_gendisk(p);
- put_disk(p);
- blk_mq_free_tag_set(&disk->tag_set);
- pi_release(disk->pi);
- }
- }
-}
-
-MODULE_LICENSE("GPL");
-module_init(pd_init)
-module_exit(pd_exit)
diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c
deleted file mode 100644
index eec1b9fde245..000000000000
--- a/drivers/block/paride/pf.c
+++ /dev/null
@@ -1,1057 +0,0 @@
-/*
- pf.c (c) 1997-8 Grant R. Guenther <grant@torque.net>
- Under the terms of the GNU General Public License.
-
- This is the high-level driver for parallel port ATAPI disk
- drives based on chips supported by the paride module.
-
- By default, the driver will autoprobe for a single parallel
- port ATAPI disk drive, but if their individual parameters are
- specified, the driver can handle up to 4 drives.
-
- The behaviour of the pf driver can be altered by setting
- some parameters from the insmod command line. The following
- parameters are adjustable:
-
- drive0 These four arguments can be arrays of
- drive1 1-7 integers as follows:
- drive2
- drive3 <prt>,<pro>,<uni>,<mod>,<slv>,<lun>,<dly>
-
- Where,
-
- <prt> is the base of the parallel port address for
- the corresponding drive. (required)
-
- <pro> is the protocol number for the adapter that
- supports this drive. These numbers are
- logged by 'paride' when the protocol modules
- are initialised. (0 if not given)
-
- <uni> for those adapters that support chained
- devices, this is the unit selector for the
- chain of devices on the given port. It should
- be zero for devices that don't support chaining.
- (0 if not given)
-
- <mod> this can be -1 to choose the best mode, or one
- of the mode numbers supported by the adapter.
- (-1 if not given)
-
- <slv> ATAPI CDroms can be jumpered to master or slave.
- Set this to 0 to choose the master drive, 1 to
- choose the slave, -1 (the default) to choose the
- first drive found.
-
- <lun> Some ATAPI devices support multiple LUNs.
- One example is the ATAPI PD/CD drive from
- Matshita/Panasonic. This device has a
- CD drive on LUN 0 and a PD drive on LUN 1.
- By default, the driver will search for the
- first LUN with a supported device. Set
- this parameter to force it to use a specific
- LUN. (default -1)
-
- <dly> some parallel ports require the driver to
- go more slowly. -1 sets a default value that
- should work with the chosen protocol. Otherwise,
- set this to a small integer, the larger it is
- the slower the port i/o. In some cases, setting
- this to zero will speed up the device. (default -1)
-
- major You may use this parameter to override the
- default major number (47) that this driver
- will use. Be sure to change the device
- name as well.
-
- name This parameter is a character string that
- contains the name the kernel will use for this
- device (in /proc output, for instance).
- (default "pf").
-
- cluster The driver will attempt to aggregate requests
- for adjacent blocks into larger multi-block
- clusters. The maximum cluster size (in 512
- byte sectors) is set with this parameter.
- (default 64)
-
- verbose This parameter controls the amount of logging
- that the driver will do. Set it to 0 for
- normal operation, 1 to see autoprobe progress
- messages, or 2 to see additional debugging
- output. (default 0)
-
- nice This parameter controls the driver's use of
- idle CPU time, at the expense of some speed.
-
- If this driver is built into the kernel, you can use the
- following command line parameters, with the same values
- as the corresponding module parameters listed above:
-
- pf.drive0
- pf.drive1
- pf.drive2
- pf.drive3
- pf.cluster
- pf.nice
-
- In addition, you can use the parameter pf.disable to disable
- the driver entirely.
-
-*/
-
-/* Changes:
-
- 1.01 GRG 1998.05.03 Changes for SMP. Eliminate sti().
- Fix for drives that don't clear STAT_ERR
- until after next CDB delivered.
- Small change in pf_completion to round
- up transfer size.
- 1.02 GRG 1998.06.16 Eliminated an Ugh
- 1.03 GRG 1998.08.16 Use HZ in loop timings, extra debugging
- 1.04 GRG 1998.09.24 Added jumbo support
-
-*/
-
-#define PF_VERSION "1.04"
-#define PF_MAJOR 47
-#define PF_NAME "pf"
-#define PF_UNITS 4
-
-#include <linux/types.h>
-
-/* Here are things one can override from the insmod command.
- Most are autoprobed by paride unless set here. Verbose is off
- by default.
-
-*/
-
-static bool verbose = 0;
-static int major = PF_MAJOR;
-static char *name = PF_NAME;
-static int cluster = 64;
-static int nice = 0;
-static int disable = 0;
-
-static int drive0[7] = { 0, 0, 0, -1, -1, -1, -1 };
-static int drive1[7] = { 0, 0, 0, -1, -1, -1, -1 };
-static int drive2[7] = { 0, 0, 0, -1, -1, -1, -1 };
-static int drive3[7] = { 0, 0, 0, -1, -1, -1, -1 };
-
-static int (*drives[4])[7] = {&drive0, &drive1, &drive2, &drive3};
-static int pf_drive_count;
-
-enum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV, D_LUN, D_DLY};
-
-/* end of parameters */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/hdreg.h>
-#include <linux/cdrom.h>
-#include <linux/spinlock.h>
-#include <linux/blk-mq.h>
-#include <linux/blkpg.h>
-#include <linux/mutex.h>
-#include <linux/uaccess.h>
-
-static DEFINE_MUTEX(pf_mutex);
-static DEFINE_SPINLOCK(pf_spin_lock);
-
-module_param(verbose, bool, 0644);
-module_param(major, int, 0);
-module_param(name, charp, 0);
-module_param(cluster, int, 0);
-module_param(nice, int, 0);
-module_param_array(drive0, int, NULL, 0);
-module_param_array(drive1, int, NULL, 0);
-module_param_array(drive2, int, NULL, 0);
-module_param_array(drive3, int, NULL, 0);
-
-#include "paride.h"
-#include "pseudo.h"
-
-/* constants for faking geometry numbers */
-
-#define PF_FD_MAX 8192 /* use FD geometry under this size */
-#define PF_FD_HDS 2
-#define PF_FD_SPT 18
-#define PF_HD_HDS 64
-#define PF_HD_SPT 32
-
-#define PF_MAX_RETRIES 5
-#define PF_TMO 800 /* interrupt timeout in jiffies */
-#define PF_SPIN_DEL 50 /* spin delay in micro-seconds */
-
-#define PF_SPIN (1000000*PF_TMO)/(HZ*PF_SPIN_DEL)
-
-#define STAT_ERR 0x00001
-#define STAT_INDEX 0x00002
-#define STAT_ECC 0x00004
-#define STAT_DRQ 0x00008
-#define STAT_SEEK 0x00010
-#define STAT_WRERR 0x00020
-#define STAT_READY 0x00040
-#define STAT_BUSY 0x00080
-
-#define ATAPI_REQ_SENSE 0x03
-#define ATAPI_LOCK 0x1e
-#define ATAPI_DOOR 0x1b
-#define ATAPI_MODE_SENSE 0x5a
-#define ATAPI_CAPACITY 0x25
-#define ATAPI_IDENTIFY 0x12
-#define ATAPI_READ_10 0x28
-#define ATAPI_WRITE_10 0x2a
-
-static int pf_open(struct block_device *bdev, fmode_t mode);
-static blk_status_t pf_queue_rq(struct blk_mq_hw_ctx *hctx,
- const struct blk_mq_queue_data *bd);
-static int pf_ioctl(struct block_device *bdev, fmode_t mode,
- unsigned int cmd, unsigned long arg);
-static int pf_getgeo(struct block_device *bdev, struct hd_geometry *geo);
-
-static void pf_release(struct gendisk *disk, fmode_t mode);
-
-static void do_pf_read(void);
-static void do_pf_read_start(void);
-static void do_pf_write(void);
-static void do_pf_write_start(void);
-static void do_pf_read_drq(void);
-static void do_pf_write_done(void);
-
-#define PF_NM 0
-#define PF_RO 1
-#define PF_RW 2
-
-#define PF_NAMELEN 8
-
-struct pf_unit {
- struct pi_adapter pia; /* interface to paride layer */
- struct pi_adapter *pi;
- int removable; /* removable media device ? */
- int media_status; /* media present ? WP ? */
- int drive; /* drive */
- int lun;
- int access; /* count of active opens ... */
- int present; /* device present ? */
- char name[PF_NAMELEN]; /* pf0, pf1, ... */
- struct gendisk *disk;
- struct blk_mq_tag_set tag_set;
- struct list_head rq_list;
-};
-
-static struct pf_unit units[PF_UNITS];
-
-static int pf_identify(struct pf_unit *pf);
-static void pf_lock(struct pf_unit *pf, int func);
-static void pf_eject(struct pf_unit *pf);
-static unsigned int pf_check_events(struct gendisk *disk,
- unsigned int clearing);
-
-static char pf_scratch[512]; /* scratch block buffer */
-
-/* the variables below are used mainly in the I/O request engine, which
- processes only one request at a time.
-*/
-
-static int pf_retries = 0; /* i/o error retry count */
-static int pf_busy = 0; /* request being processed ? */
-static struct request *pf_req; /* current request */
-static int pf_block; /* address of next requested block */
-static int pf_count; /* number of blocks still to do */
-static int pf_run; /* sectors in current cluster */
-static int pf_cmd; /* current command READ/WRITE */
-static struct pf_unit *pf_current;/* unit of current request */
-static int pf_mask; /* stopper for pseudo-int */
-static char *pf_buf; /* buffer for request in progress */
-static void *par_drv; /* reference of parport driver */
-
-/* kernel glue structures */
-
-static const struct block_device_operations pf_fops = {
- .owner = THIS_MODULE,
- .open = pf_open,
- .release = pf_release,
- .ioctl = pf_ioctl,
- .compat_ioctl = pf_ioctl,
- .getgeo = pf_getgeo,
- .check_events = pf_check_events,
-};
-
-static const struct blk_mq_ops pf_mq_ops = {
- .queue_rq = pf_queue_rq,
-};
-
-static int pf_open(struct block_device *bdev, fmode_t mode)
-{
- struct pf_unit *pf = bdev->bd_disk->private_data;
- int ret;
-
- mutex_lock(&pf_mutex);
- pf_identify(pf);
-
- ret = -ENODEV;
- if (pf->media_status == PF_NM)
- goto out;
-
- ret = -EROFS;
- if ((pf->media_status == PF_RO) && (mode & FMODE_WRITE))
- goto out;
-
- ret = 0;
- pf->access++;
- if (pf->removable)
- pf_lock(pf, 1);
-out:
- mutex_unlock(&pf_mutex);
- return ret;
-}
-
-static int pf_getgeo(struct block_device *bdev, struct hd_geometry *geo)
-{
- struct pf_unit *pf = bdev->bd_disk->private_data;
- sector_t capacity = get_capacity(pf->disk);
-
- if (capacity < PF_FD_MAX) {
- geo->cylinders = sector_div(capacity, PF_FD_HDS * PF_FD_SPT);
- geo->heads = PF_FD_HDS;
- geo->sectors = PF_FD_SPT;
- } else {
- geo->cylinders = sector_div(capacity, PF_HD_HDS * PF_HD_SPT);
- geo->heads = PF_HD_HDS;
- geo->sectors = PF_HD_SPT;
- }
-
- return 0;
-}
-
-static int pf_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg)
-{
- struct pf_unit *pf = bdev->bd_disk->private_data;
-
- if (cmd != CDROMEJECT)
- return -EINVAL;
-
- if (pf->access != 1)
- return -EBUSY;
- mutex_lock(&pf_mutex);
- pf_eject(pf);
- mutex_unlock(&pf_mutex);
-
- return 0;
-}
-
-static void pf_release(struct gendisk *disk, fmode_t mode)
-{
- struct pf_unit *pf = disk->private_data;
-
- mutex_lock(&pf_mutex);
- if (pf->access <= 0) {
- mutex_unlock(&pf_mutex);
- WARN_ON(1);
- return;
- }
-
- pf->access--;
-
- if (!pf->access && pf->removable)
- pf_lock(pf, 0);
-
- mutex_unlock(&pf_mutex);
-}
-
-static unsigned int pf_check_events(struct gendisk *disk, unsigned int clearing)
-{
- return DISK_EVENT_MEDIA_CHANGE;
-}
-
-static inline int status_reg(struct pf_unit *pf)
-{
- return pi_read_regr(pf->pi, 1, 6);
-}
-
-static inline int read_reg(struct pf_unit *pf, int reg)
-{
- return pi_read_regr(pf->pi, 0, reg);
-}
-
-static inline void write_reg(struct pf_unit *pf, int reg, int val)
-{
- pi_write_regr(pf->pi, 0, reg, val);
-}
-
-static int pf_wait(struct pf_unit *pf, int go, int stop, char *fun, char *msg)
-{
- int j, r, e, s, p;
-
- j = 0;
- while ((((r = status_reg(pf)) & go) || (stop && (!(r & stop))))
- && (j++ < PF_SPIN))
- udelay(PF_SPIN_DEL);
-
- if ((r & (STAT_ERR & stop)) || (j > PF_SPIN)) {
- s = read_reg(pf, 7);
- e = read_reg(pf, 1);
- p = read_reg(pf, 2);
- if (j > PF_SPIN)
- e |= 0x100;
- if (fun)
- printk("%s: %s %s: alt=0x%x stat=0x%x err=0x%x"
- " loop=%d phase=%d\n",
- pf->name, fun, msg, r, s, e, j, p);
- return (e << 8) + s;
- }
- return 0;
-}
-
-static int pf_command(struct pf_unit *pf, char *cmd, int dlen, char *fun)
-{
- pi_connect(pf->pi);
-
- write_reg(pf, 6, 0xa0+0x10*pf->drive);
-
- if (pf_wait(pf, STAT_BUSY | STAT_DRQ, 0, fun, "before command")) {
- pi_disconnect(pf->pi);
- return -1;
- }
-
- write_reg(pf, 4, dlen % 256);
- write_reg(pf, 5, dlen / 256);
- write_reg(pf, 7, 0xa0); /* ATAPI packet command */
-
- if (pf_wait(pf, STAT_BUSY, STAT_DRQ, fun, "command DRQ")) {
- pi_disconnect(pf->pi);
- return -1;
- }
-
- if (read_reg(pf, 2) != 1) {
- printk("%s: %s: command phase error\n", pf->name, fun);
- pi_disconnect(pf->pi);
- return -1;
- }
-
- pi_write_block(pf->pi, cmd, 12);
-
- return 0;
-}
-
-static int pf_completion(struct pf_unit *pf, char *buf, char *fun)
-{
- int r, s, n;
-
- r = pf_wait(pf, STAT_BUSY, STAT_DRQ | STAT_READY | STAT_ERR,
- fun, "completion");
-
- if ((read_reg(pf, 2) & 2) && (read_reg(pf, 7) & STAT_DRQ)) {
- n = (((read_reg(pf, 4) + 256 * read_reg(pf, 5)) +
- 3) & 0xfffc);
- pi_read_block(pf->pi, buf, n);
- }
-
- s = pf_wait(pf, STAT_BUSY, STAT_READY | STAT_ERR, fun, "data done");
-
- pi_disconnect(pf->pi);
-
- return (r ? r : s);
-}
-
-static void pf_req_sense(struct pf_unit *pf, int quiet)
-{
- char rs_cmd[12] =
- { ATAPI_REQ_SENSE, pf->lun << 5, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0 };
- char buf[16];
- int r;
-
- r = pf_command(pf, rs_cmd, 16, "Request sense");
- mdelay(1);
- if (!r)
- pf_completion(pf, buf, "Request sense");
-
- if ((!r) && (!quiet))
- printk("%s: Sense key: %x, ASC: %x, ASQ: %x\n",
- pf->name, buf[2] & 0xf, buf[12], buf[13]);
-}
-
-static int pf_atapi(struct pf_unit *pf, char *cmd, int dlen, char *buf, char *fun)
-{
- int r;
-
- r = pf_command(pf, cmd, dlen, fun);
- mdelay(1);
- if (!r)
- r = pf_completion(pf, buf, fun);
- if (r)
- pf_req_sense(pf, !fun);
-
- return r;
-}
-
-static void pf_lock(struct pf_unit *pf, int func)
-{
- char lo_cmd[12] = { ATAPI_LOCK, pf->lun << 5, 0, 0, func, 0, 0, 0, 0, 0, 0, 0 };
-
- pf_atapi(pf, lo_cmd, 0, pf_scratch, func ? "lock" : "unlock");
-}
-
-static void pf_eject(struct pf_unit *pf)
-{
- char ej_cmd[12] = { ATAPI_DOOR, pf->lun << 5, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0 };
-
- pf_lock(pf, 0);
- pf_atapi(pf, ej_cmd, 0, pf_scratch, "eject");
-}
-
-#define PF_RESET_TMO 30 /* in tenths of a second */
-
-static void pf_sleep(int cs)
-{
- schedule_timeout_interruptible(cs);
-}
-
-/* the ATAPI standard actually specifies the contents of all 7 registers
- after a reset, but the specification is ambiguous concerning the last
- two bytes, and different drives interpret the standard differently.
- */
-
-static int pf_reset(struct pf_unit *pf)
-{
- int i, k, flg;
- int expect[5] = { 1, 1, 1, 0x14, 0xeb };
-
- pi_connect(pf->pi);
- write_reg(pf, 6, 0xa0+0x10*pf->drive);
- write_reg(pf, 7, 8);
-
- pf_sleep(20 * HZ / 1000);
-
- k = 0;
- while ((k++ < PF_RESET_TMO) && (status_reg(pf) & STAT_BUSY))
- pf_sleep(HZ / 10);
-
- flg = 1;
- for (i = 0; i < 5; i++)
- flg &= (read_reg(pf, i + 1) == expect[i]);
-
- if (verbose) {
- printk("%s: Reset (%d) signature = ", pf->name, k);
- for (i = 0; i < 5; i++)
- printk("%3x", read_reg(pf, i + 1));
- if (!flg)
- printk(" (incorrect)");
- printk("\n");
- }
-
- pi_disconnect(pf->pi);
- return flg - 1;
-}
-
-static void pf_mode_sense(struct pf_unit *pf)
-{
- char ms_cmd[12] =
- { ATAPI_MODE_SENSE, pf->lun << 5, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0 };
- char buf[8];
-
- pf_atapi(pf, ms_cmd, 8, buf, "mode sense");
- pf->media_status = PF_RW;
- if (buf[3] & 0x80)
- pf->media_status = PF_RO;
-}
-
-static void xs(char *buf, char *targ, int offs, int len)
-{
- int j, k, l;
-
- j = 0;
- l = 0;
- for (k = 0; k < len; k++)
- if ((buf[k + offs] != 0x20) || (buf[k + offs] != l))
- l = targ[j++] = buf[k + offs];
- if (l == 0x20)
- j--;
- targ[j] = 0;
-}
-
-static int xl(char *buf, int offs)
-{
- int v, k;
-
- v = 0;
- for (k = 0; k < 4; k++)
- v = v * 256 + (buf[k + offs] & 0xff);
- return v;
-}
-
-static void pf_get_capacity(struct pf_unit *pf)
-{
- char rc_cmd[12] = { ATAPI_CAPACITY, pf->lun << 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- char buf[8];
- int bs;
-
- if (pf_atapi(pf, rc_cmd, 8, buf, "get capacity")) {
- pf->media_status = PF_NM;
- return;
- }
- set_capacity(pf->disk, xl(buf, 0) + 1);
- bs = xl(buf, 4);
- if (bs != 512) {
- set_capacity(pf->disk, 0);
- if (verbose)
- printk("%s: Drive %d, LUN %d,"
- " unsupported block size %d\n",
- pf->name, pf->drive, pf->lun, bs);
- }
-}
-
-static int pf_identify(struct pf_unit *pf)
-{
- int dt, s;
- char *ms[2] = { "master", "slave" };
- char mf[10], id[18];
- char id_cmd[12] =
- { ATAPI_IDENTIFY, pf->lun << 5, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0 };
- char buf[36];
-
- s = pf_atapi(pf, id_cmd, 36, buf, "identify");
- if (s)
- return -1;
-
- dt = buf[0] & 0x1f;
- if ((dt != 0) && (dt != 7)) {
- if (verbose)
- printk("%s: Drive %d, LUN %d, unsupported type %d\n",
- pf->name, pf->drive, pf->lun, dt);
- return -1;
- }
-
- xs(buf, mf, 8, 8);
- xs(buf, id, 16, 16);
-
- pf->removable = (buf[1] & 0x80);
-
- pf_mode_sense(pf);
- pf_mode_sense(pf);
- pf_mode_sense(pf);
-
- pf_get_capacity(pf);
-
- printk("%s: %s %s, %s LUN %d, type %d",
- pf->name, mf, id, ms[pf->drive], pf->lun, dt);
- if (pf->removable)
- printk(", removable");
- if (pf->media_status == PF_NM)
- printk(", no media\n");
- else {
- if (pf->media_status == PF_RO)
- printk(", RO");
- printk(", %llu blocks\n",
- (unsigned long long)get_capacity(pf->disk));
- }
- return 0;
-}
-
-/*
- * returns 0, with id set if drive is detected, otherwise an error code.
- */
-static int pf_probe(struct pf_unit *pf)
-{
- if (pf->drive == -1) {
- for (pf->drive = 0; pf->drive <= 1; pf->drive++)
- if (!pf_reset(pf)) {
- if (pf->lun != -1)
- return pf_identify(pf);
- else
- for (pf->lun = 0; pf->lun < 8; pf->lun++)
- if (!pf_identify(pf))
- return 0;
- }
- } else {
- if (pf_reset(pf))
- return -1;
- if (pf->lun != -1)
- return pf_identify(pf);
- for (pf->lun = 0; pf->lun < 8; pf->lun++)
- if (!pf_identify(pf))
- return 0;
- }
- return -ENODEV;
-}
-
-/* The i/o request engine */
-
-static int pf_start(struct pf_unit *pf, int cmd, int b, int c)
-{
- int i;
- char io_cmd[12] = { cmd, pf->lun << 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-
- for (i = 0; i < 4; i++) {
- io_cmd[5 - i] = b & 0xff;
- b = b >> 8;
- }
-
- io_cmd[8] = c & 0xff;
- io_cmd[7] = (c >> 8) & 0xff;
-
- i = pf_command(pf, io_cmd, c * 512, "start i/o");
-
- mdelay(1);
-
- return i;
-}
-
-static int pf_ready(void)
-{
- return (((status_reg(pf_current) & (STAT_BUSY | pf_mask)) == pf_mask));
-}
-
-static int pf_queue;
-
-static int set_next_request(void)
-{
- struct pf_unit *pf;
- int old_pos = pf_queue;
-
- do {
- pf = &units[pf_queue];
- if (++pf_queue == PF_UNITS)
- pf_queue = 0;
- if (pf->present && !list_empty(&pf->rq_list)) {
- pf_req = list_first_entry(&pf->rq_list, struct request,
- queuelist);
- list_del_init(&pf_req->queuelist);
- blk_mq_start_request(pf_req);
- break;
- }
- } while (pf_queue != old_pos);
-
- return pf_req != NULL;
-}
-
-static void pf_end_request(blk_status_t err)
-{
- if (!pf_req)
- return;
- if (!blk_update_request(pf_req, err, blk_rq_cur_bytes(pf_req))) {
- __blk_mq_end_request(pf_req, err);
- pf_req = NULL;
- }
-}
-
-static void pf_request(void)
-{
- if (pf_busy)
- return;
-repeat:
- if (!pf_req && !set_next_request())
- return;
-
- pf_current = pf_req->q->disk->private_data;
- pf_block = blk_rq_pos(pf_req);
- pf_run = blk_rq_sectors(pf_req);
- pf_count = blk_rq_cur_sectors(pf_req);
-
- if (pf_block + pf_count > get_capacity(pf_req->q->disk)) {
- pf_end_request(BLK_STS_IOERR);
- goto repeat;
- }
-
- pf_cmd = rq_data_dir(pf_req);
- pf_buf = bio_data(pf_req->bio);
- pf_retries = 0;
-
- pf_busy = 1;
- if (pf_cmd == READ)
- pi_do_claimed(pf_current->pi, do_pf_read);
- else if (pf_cmd == WRITE)
- pi_do_claimed(pf_current->pi, do_pf_write);
- else {
- pf_busy = 0;
- pf_end_request(BLK_STS_IOERR);
- goto repeat;
- }
-}
-
-static blk_status_t pf_queue_rq(struct blk_mq_hw_ctx *hctx,
- const struct blk_mq_queue_data *bd)
-{
- struct pf_unit *pf = hctx->queue->queuedata;
-
- spin_lock_irq(&pf_spin_lock);
- list_add_tail(&bd->rq->queuelist, &pf->rq_list);
- pf_request();
- spin_unlock_irq(&pf_spin_lock);
-
- return BLK_STS_OK;
-}
-
-static int pf_next_buf(void)
-{
- unsigned long saved_flags;
-
- pf_count--;
- pf_run--;
- pf_buf += 512;
- pf_block++;
- if (!pf_run)
- return 1;
- if (!pf_count) {
- spin_lock_irqsave(&pf_spin_lock, saved_flags);
- pf_end_request(0);
- spin_unlock_irqrestore(&pf_spin_lock, saved_flags);
- if (!pf_req)
- return 1;
- pf_count = blk_rq_cur_sectors(pf_req);
- pf_buf = bio_data(pf_req->bio);
- }
- return 0;
-}
-
-static inline void next_request(blk_status_t err)
-{
- unsigned long saved_flags;
-
- spin_lock_irqsave(&pf_spin_lock, saved_flags);
- pf_end_request(err);
- pf_busy = 0;
- pf_request();
- spin_unlock_irqrestore(&pf_spin_lock, saved_flags);
-}
-
-/* detach from the calling context - in case the spinlock is held */
-static void do_pf_read(void)
-{
- ps_set_intr(do_pf_read_start, NULL, 0, nice);
-}
-
-static void do_pf_read_start(void)
-{
- pf_busy = 1;
-
- if (pf_start(pf_current, ATAPI_READ_10, pf_block, pf_run)) {
- pi_disconnect(pf_current->pi);
- if (pf_retries < PF_MAX_RETRIES) {
- pf_retries++;
- pi_do_claimed(pf_current->pi, do_pf_read_start);
- return;
- }
- next_request(BLK_STS_IOERR);
- return;
- }
- pf_mask = STAT_DRQ;
- ps_set_intr(do_pf_read_drq, pf_ready, PF_TMO, nice);
-}
-
-static void do_pf_read_drq(void)
-{
- while (1) {
- if (pf_wait(pf_current, STAT_BUSY, STAT_DRQ | STAT_ERR,
- "read block", "completion") & STAT_ERR) {
- pi_disconnect(pf_current->pi);
- if (pf_retries < PF_MAX_RETRIES) {
- pf_req_sense(pf_current, 0);
- pf_retries++;
- pi_do_claimed(pf_current->pi, do_pf_read_start);
- return;
- }
- next_request(BLK_STS_IOERR);
- return;
- }
- pi_read_block(pf_current->pi, pf_buf, 512);
- if (pf_next_buf())
- break;
- }
- pi_disconnect(pf_current->pi);
- next_request(0);
-}
-
-static void do_pf_write(void)
-{
- ps_set_intr(do_pf_write_start, NULL, 0, nice);
-}
-
-static void do_pf_write_start(void)
-{
- pf_busy = 1;
-
- if (pf_start(pf_current, ATAPI_WRITE_10, pf_block, pf_run)) {
- pi_disconnect(pf_current->pi);
- if (pf_retries < PF_MAX_RETRIES) {
- pf_retries++;
- pi_do_claimed(pf_current->pi, do_pf_write_start);
- return;
- }
- next_request(BLK_STS_IOERR);
- return;
- }
-
- while (1) {
- if (pf_wait(pf_current, STAT_BUSY, STAT_DRQ | STAT_ERR,
- "write block", "data wait") & STAT_ERR) {
- pi_disconnect(pf_current->pi);
- if (pf_retries < PF_MAX_RETRIES) {
- pf_retries++;
- pi_do_claimed(pf_current->pi, do_pf_write_start);
- return;
- }
- next_request(BLK_STS_IOERR);
- return;
- }
- pi_write_block(pf_current->pi, pf_buf, 512);
- if (pf_next_buf())
- break;
- }
- pf_mask = 0;
- ps_set_intr(do_pf_write_done, pf_ready, PF_TMO, nice);
-}
-
-static void do_pf_write_done(void)
-{
- if (pf_wait(pf_current, STAT_BUSY, 0, "write block", "done") & STAT_ERR) {
- pi_disconnect(pf_current->pi);
- if (pf_retries < PF_MAX_RETRIES) {
- pf_retries++;
- pi_do_claimed(pf_current->pi, do_pf_write_start);
- return;
- }
- next_request(BLK_STS_IOERR);
- return;
- }
- pi_disconnect(pf_current->pi);
- next_request(0);
-}
-
-static int __init pf_init_unit(struct pf_unit *pf, bool autoprobe, int port,
- int mode, int unit, int protocol, int delay, int ms)
-{
- struct gendisk *disk;
- int ret;
-
- ret = blk_mq_alloc_sq_tag_set(&pf->tag_set, &pf_mq_ops, 1,
- BLK_MQ_F_SHOULD_MERGE);
- if (ret)
- return ret;
-
- disk = blk_mq_alloc_disk(&pf->tag_set, pf);
- if (IS_ERR(disk)) {
- ret = PTR_ERR(disk);
- goto out_free_tag_set;
- }
- disk->major = major;
- disk->first_minor = pf - units;
- disk->minors = 1;
- strcpy(disk->disk_name, pf->name);
- disk->fops = &pf_fops;
- disk->flags |= GENHD_FL_NO_PART;
- disk->events = DISK_EVENT_MEDIA_CHANGE;
- disk->private_data = pf;
-
- blk_queue_max_segments(disk->queue, cluster);
- blk_queue_bounce_limit(disk->queue, BLK_BOUNCE_HIGH);
-
- INIT_LIST_HEAD(&pf->rq_list);
- pf->disk = disk;
- pf->pi = &pf->pia;
- pf->media_status = PF_NM;
- pf->drive = (*drives[disk->first_minor])[D_SLV];
- pf->lun = (*drives[disk->first_minor])[D_LUN];
- snprintf(pf->name, PF_NAMELEN, "%s%d", name, disk->first_minor);
-
- if (!pi_init(pf->pi, autoprobe, port, mode, unit, protocol, delay,
- pf_scratch, PI_PF, verbose, pf->name)) {
- ret = -ENODEV;
- goto out_free_disk;
- }
- ret = pf_probe(pf);
- if (ret)
- goto out_pi_release;
-
- ret = add_disk(disk);
- if (ret)
- goto out_pi_release;
- pf->present = 1;
- return 0;
-
-out_pi_release:
- pi_release(pf->pi);
-out_free_disk:
- put_disk(pf->disk);
-out_free_tag_set:
- blk_mq_free_tag_set(&pf->tag_set);
- return ret;
-}
-
-static int __init pf_init(void)
-{ /* preliminary initialisation */
- struct pf_unit *pf;
- int found = 0, unit;
-
- if (disable)
- return -EINVAL;
-
- if (register_blkdev(major, name))
- return -EBUSY;
-
- printk("%s: %s version %s, major %d, cluster %d, nice %d\n",
- name, name, PF_VERSION, major, cluster, nice);
-
- par_drv = pi_register_driver(name);
- if (!par_drv) {
- pr_err("failed to register %s driver\n", name);
- goto out_unregister_blkdev;
- }
-
- for (unit = 0; unit < PF_UNITS; unit++) {
- if (!(*drives[unit])[D_PRT])
- pf_drive_count++;
- }
-
- pf = units;
- if (pf_drive_count == 0) {
- if (pf_init_unit(pf, 1, -1, -1, -1, -1, -1, verbose))
- found++;
- } else {
- for (unit = 0; unit < PF_UNITS; unit++, pf++) {
- int *conf = *drives[unit];
- if (!conf[D_PRT])
- continue;
- if (pf_init_unit(pf, 0, conf[D_PRT], conf[D_MOD],
- conf[D_UNI], conf[D_PRO], conf[D_DLY],
- verbose))
- found++;
- }
- }
- if (!found) {
- printk("%s: No ATAPI disk detected\n", name);
- goto out_unregister_pi_driver;
- }
- pf_busy = 0;
- return 0;
-
-out_unregister_pi_driver:
- pi_unregister_driver(par_drv);
-out_unregister_blkdev:
- unregister_blkdev(major, name);
- return -ENODEV;
-}
-
-static void __exit pf_exit(void)
-{
- struct pf_unit *pf;
- int unit;
-
- for (pf = units, unit = 0; unit < PF_UNITS; pf++, unit++) {
- if (!pf->present)
- continue;
- del_gendisk(pf->disk);
- put_disk(pf->disk);
- blk_mq_free_tag_set(&pf->tag_set);
- pi_release(pf->pi);
- }
-
- unregister_blkdev(major, name);
-}
-
-MODULE_LICENSE("GPL");
-module_init(pf_init)
-module_exit(pf_exit)
diff --git a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c
deleted file mode 100644
index 3b5882bfb736..000000000000
--- a/drivers/block/paride/pg.c
+++ /dev/null
@@ -1,734 +0,0 @@
-/*
- pg.c (c) 1998 Grant R. Guenther <grant@torque.net>
- Under the terms of the GNU General Public License.
-
- The pg driver provides a simple character device interface for
- sending ATAPI commands to a device. With the exception of the
- ATAPI reset operation, all operations are performed by a pair
- of read and write operations to the appropriate /dev/pgN device.
- A write operation delivers a command and any outbound data in
- a single buffer. Normally, the write will succeed unless the
- device is offline or malfunctioning, or there is already another
- command pending. If the write succeeds, it should be followed
- immediately by a read operation, to obtain any returned data and
- status information. A read will fail if there is no operation
- in progress.
-
- As a special case, the device can be reset with a write operation,
- and in this case, no following read is expected, or permitted.
-
- There are no ioctl() operations. Any single operation
- may transfer at most PG_MAX_DATA bytes. Note that the driver must
- copy the data through an internal buffer. In keeping with all
- current ATAPI devices, command packets are assumed to be exactly
- 12 bytes in length.
-
- To permit future changes to this interface, the headers in the
- read and write buffers contain a single character "magic" flag.
- Currently this flag must be the character "P".
-
- By default, the driver will autoprobe for a single parallel
- port ATAPI device, but if their individual parameters are
- specified, the driver can handle up to 4 devices.
-
- To use this device, you must have the following device
- special files defined:
-
- /dev/pg0 c 97 0
- /dev/pg1 c 97 1
- /dev/pg2 c 97 2
- /dev/pg3 c 97 3
-
- (You'll need to change the 97 to something else if you use
- the 'major' parameter to install the driver on a different
- major number.)
-
- The behaviour of the pg driver can be altered by setting
- some parameters from the insmod command line. The following
- parameters are adjustable:
-
- drive0 These four arguments can be arrays of
- drive1 1-6 integers as follows:
- drive2
- drive3 <prt>,<pro>,<uni>,<mod>,<slv>,<dly>
-
- Where,
-
- <prt> is the base of the parallel port address for
- the corresponding drive. (required)
-
- <pro> is the protocol number for the adapter that
- supports this drive. These numbers are
- logged by 'paride' when the protocol modules
- are initialised. (0 if not given)
-
- <uni> for those adapters that support chained
- devices, this is the unit selector for the
- chain of devices on the given port. It should
- be zero for devices that don't support chaining.
- (0 if not given)
-
- <mod> this can be -1 to choose the best mode, or one
- of the mode numbers supported by the adapter.
- (-1 if not given)
-
- <slv> ATAPI devices can be jumpered to master or slave.
- Set this to 0 to choose the master drive, 1 to
- choose the slave, -1 (the default) to choose the
- first drive found.
-
- <dly> some parallel ports require the driver to
- go more slowly. -1 sets a default value that
- should work with the chosen protocol. Otherwise,
- set this to a small integer, the larger it is
- the slower the port i/o. In some cases, setting
- this to zero will speed up the device. (default -1)
-
- major You may use this parameter to override the
- default major number (97) that this driver
- will use. Be sure to change the device
- name as well.
-
- name This parameter is a character string that
- contains the name the kernel will use for this
- device (in /proc output, for instance).
- (default "pg").
-
- verbose This parameter controls the amount of logging
- that is done by the driver. Set it to 0 for
- quiet operation, to 1 to enable progress
- messages while the driver probes for devices,
- or to 2 for full debug logging. (default 0)
-
- If this driver is built into the kernel, you can use
- the following command line parameters, with the same values
- as the corresponding module parameters listed above:
-
- pg.drive0
- pg.drive1
- pg.drive2
- pg.drive3
-
- In addition, you can use the parameter pg.disable to disable
- the driver entirely.
-
-*/
-
-/* Changes:
-
- 1.01 GRG 1998.06.16 Bug fixes
- 1.02 GRG 1998.09.24 Added jumbo support
-
-*/
-
-#define PG_VERSION "1.02"
-#define PG_MAJOR 97
-#define PG_NAME "pg"
-#define PG_UNITS 4
-
-#ifndef PI_PG
-#define PI_PG 4
-#endif
-
-#include <linux/types.h>
-/* Here are things one can override from the insmod command.
- Most are autoprobed by paride unless set here. Verbose is 0
- by default.
-
-*/
-
-static int verbose;
-static int major = PG_MAJOR;
-static char *name = PG_NAME;
-static int disable = 0;
-
-static int drive0[6] = { 0, 0, 0, -1, -1, -1 };
-static int drive1[6] = { 0, 0, 0, -1, -1, -1 };
-static int drive2[6] = { 0, 0, 0, -1, -1, -1 };
-static int drive3[6] = { 0, 0, 0, -1, -1, -1 };
-
-static int (*drives[4])[6] = {&drive0, &drive1, &drive2, &drive3};
-static int pg_drive_count;
-
-enum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV, D_DLY};
-
-/* end of parameters */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/mtio.h>
-#include <linux/pg.h>
-#include <linux/device.h>
-#include <linux/sched.h> /* current, TASK_* */
-#include <linux/mutex.h>
-#include <linux/jiffies.h>
-
-#include <linux/uaccess.h>
-
-module_param(verbose, int, 0644);
-module_param(major, int, 0);
-module_param(name, charp, 0);
-module_param_array(drive0, int, NULL, 0);
-module_param_array(drive1, int, NULL, 0);
-module_param_array(drive2, int, NULL, 0);
-module_param_array(drive3, int, NULL, 0);
-
-#include "paride.h"
-
-#define PG_SPIN_DEL 50 /* spin delay in micro-seconds */
-#define PG_SPIN 200
-#define PG_TMO HZ
-#define PG_RESET_TMO 10*HZ
-
-#define STAT_ERR 0x01
-#define STAT_INDEX 0x02
-#define STAT_ECC 0x04
-#define STAT_DRQ 0x08
-#define STAT_SEEK 0x10
-#define STAT_WRERR 0x20
-#define STAT_READY 0x40
-#define STAT_BUSY 0x80
-
-#define ATAPI_IDENTIFY 0x12
-
-static DEFINE_MUTEX(pg_mutex);
-static int pg_open(struct inode *inode, struct file *file);
-static int pg_release(struct inode *inode, struct file *file);
-static ssize_t pg_read(struct file *filp, char __user *buf,
- size_t count, loff_t * ppos);
-static ssize_t pg_write(struct file *filp, const char __user *buf,
- size_t count, loff_t * ppos);
-static int pg_detect(void);
-
-#define PG_NAMELEN 8
-
-struct pg {
- struct pi_adapter pia; /* interface to paride layer */
- struct pi_adapter *pi;
- int busy; /* write done, read expected */
- int start; /* jiffies at command start */
- int dlen; /* transfer size requested */
- unsigned long timeout; /* timeout requested */
- int status; /* last sense key */
- int drive; /* drive */
- unsigned long access; /* count of active opens ... */
- int present; /* device present ? */
- char *bufptr;
- char name[PG_NAMELEN]; /* pg0, pg1, ... */
-};
-
-static struct pg devices[PG_UNITS];
-
-static int pg_identify(struct pg *dev, int log);
-
-static char pg_scratch[512]; /* scratch block buffer */
-
-static struct class *pg_class;
-static void *par_drv; /* reference of parport driver */
-
-/* kernel glue structures */
-
-static const struct file_operations pg_fops = {
- .owner = THIS_MODULE,
- .read = pg_read,
- .write = pg_write,
- .open = pg_open,
- .release = pg_release,
- .llseek = noop_llseek,
-};
-
-static void pg_init_units(void)
-{
- int unit;
-
- pg_drive_count = 0;
- for (unit = 0; unit < PG_UNITS; unit++) {
- int *parm = *drives[unit];
- struct pg *dev = &devices[unit];
- dev->pi = &dev->pia;
- clear_bit(0, &dev->access);
- dev->busy = 0;
- dev->present = 0;
- dev->bufptr = NULL;
- dev->drive = parm[D_SLV];
- snprintf(dev->name, PG_NAMELEN, "%s%c", name, 'a'+unit);
- if (parm[D_PRT])
- pg_drive_count++;
- }
-}
-
-static inline int status_reg(struct pg *dev)
-{
- return pi_read_regr(dev->pi, 1, 6);
-}
-
-static inline int read_reg(struct pg *dev, int reg)
-{
- return pi_read_regr(dev->pi, 0, reg);
-}
-
-static inline void write_reg(struct pg *dev, int reg, int val)
-{
- pi_write_regr(dev->pi, 0, reg, val);
-}
-
-static inline u8 DRIVE(struct pg *dev)
-{
- return 0xa0+0x10*dev->drive;
-}
-
-static void pg_sleep(int cs)
-{
- schedule_timeout_interruptible(cs);
-}
-
-static int pg_wait(struct pg *dev, int go, int stop, unsigned long tmo, char *msg)
-{
- int j, r, e, s, p, to;
-
- dev->status = 0;
-
- j = 0;
- while ((((r = status_reg(dev)) & go) || (stop && (!(r & stop))))
- && time_before(jiffies, tmo)) {
- if (j++ < PG_SPIN)
- udelay(PG_SPIN_DEL);
- else
- pg_sleep(1);
- }
-
- to = time_after_eq(jiffies, tmo);
-
- if ((r & (STAT_ERR & stop)) || to) {
- s = read_reg(dev, 7);
- e = read_reg(dev, 1);
- p = read_reg(dev, 2);
- if (verbose > 1)
- printk("%s: %s: stat=0x%x err=0x%x phase=%d%s\n",
- dev->name, msg, s, e, p, to ? " timeout" : "");
- if (to)
- e |= 0x100;
- dev->status = (e >> 4) & 0xff;
- return -1;
- }
- return 0;
-}
-
-static int pg_command(struct pg *dev, char *cmd, int dlen, unsigned long tmo)
-{
- int k;
-
- pi_connect(dev->pi);
-
- write_reg(dev, 6, DRIVE(dev));
-
- if (pg_wait(dev, STAT_BUSY | STAT_DRQ, 0, tmo, "before command"))
- goto fail;
-
- write_reg(dev, 4, dlen % 256);
- write_reg(dev, 5, dlen / 256);
- write_reg(dev, 7, 0xa0); /* ATAPI packet command */
-
- if (pg_wait(dev, STAT_BUSY, STAT_DRQ, tmo, "command DRQ"))
- goto fail;
-
- if (read_reg(dev, 2) != 1) {
- printk("%s: command phase error\n", dev->name);
- goto fail;
- }
-
- pi_write_block(dev->pi, cmd, 12);
-
- if (verbose > 1) {
- printk("%s: Command sent, dlen=%d packet= ", dev->name, dlen);
- for (k = 0; k < 12; k++)
- printk("%02x ", cmd[k] & 0xff);
- printk("\n");
- }
- return 0;
-fail:
- pi_disconnect(dev->pi);
- return -1;
-}
-
-static int pg_completion(struct pg *dev, char *buf, unsigned long tmo)
-{
- int r, d, n, p;
-
- r = pg_wait(dev, STAT_BUSY, STAT_DRQ | STAT_READY | STAT_ERR,
- tmo, "completion");
-
- dev->dlen = 0;
-
- while (read_reg(dev, 7) & STAT_DRQ) {
- d = (read_reg(dev, 4) + 256 * read_reg(dev, 5));
- n = ((d + 3) & 0xfffc);
- p = read_reg(dev, 2) & 3;
- if (p == 0)
- pi_write_block(dev->pi, buf, n);
- if (p == 2)
- pi_read_block(dev->pi, buf, n);
- if (verbose > 1)
- printk("%s: %s %d bytes\n", dev->name,
- p ? "Read" : "Write", n);
- dev->dlen += (1 - p) * d;
- buf += d;
- r = pg_wait(dev, STAT_BUSY, STAT_DRQ | STAT_READY | STAT_ERR,
- tmo, "completion");
- }
-
- pi_disconnect(dev->pi);
-
- return r;
-}
-
-static int pg_reset(struct pg *dev)
-{
- int i, k, err;
- int expect[5] = { 1, 1, 1, 0x14, 0xeb };
- int got[5];
-
- pi_connect(dev->pi);
- write_reg(dev, 6, DRIVE(dev));
- write_reg(dev, 7, 8);
-
- pg_sleep(20 * HZ / 1000);
-
- k = 0;
- while ((k++ < PG_RESET_TMO) && (status_reg(dev) & STAT_BUSY))
- pg_sleep(1);
-
- for (i = 0; i < 5; i++)
- got[i] = read_reg(dev, i + 1);
-
- err = memcmp(expect, got, sizeof(got)) ? -1 : 0;
-
- if (verbose) {
- printk("%s: Reset (%d) signature = ", dev->name, k);
- for (i = 0; i < 5; i++)
- printk("%3x", got[i]);
- if (err)
- printk(" (incorrect)");
- printk("\n");
- }
-
- pi_disconnect(dev->pi);
- return err;
-}
-
-static void xs(char *buf, char *targ, int len)
-{
- char l = '\0';
- int k;
-
- for (k = 0; k < len; k++) {
- char c = *buf++;
- if (c != ' ' && c != l)
- l = *targ++ = c;
- }
- if (l == ' ')
- targ--;
- *targ = '\0';
-}
-
-static int pg_identify(struct pg *dev, int log)
-{
- int s;
- char *ms[2] = { "master", "slave" };
- char mf[10], id[18];
- char id_cmd[12] = { ATAPI_IDENTIFY, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0 };
- char buf[36];
-
- s = pg_command(dev, id_cmd, 36, jiffies + PG_TMO);
- if (s)
- return -1;
- s = pg_completion(dev, buf, jiffies + PG_TMO);
- if (s)
- return -1;
-
- if (log) {
- xs(buf + 8, mf, 8);
- xs(buf + 16, id, 16);
- printk("%s: %s %s, %s\n", dev->name, mf, id, ms[dev->drive]);
- }
-
- return 0;
-}
-
-/*
- * returns 0, with id set if drive is detected
- * -1, if drive detection failed
- */
-static int pg_probe(struct pg *dev)
-{
- if (dev->drive == -1) {
- for (dev->drive = 0; dev->drive <= 1; dev->drive++)
- if (!pg_reset(dev))
- return pg_identify(dev, 1);
- } else {
- if (!pg_reset(dev))
- return pg_identify(dev, 1);
- }
- return -1;
-}
-
-static int pg_detect(void)
-{
- struct pg *dev = &devices[0];
- int k, unit;
-
- printk("%s: %s version %s, major %d\n", name, name, PG_VERSION, major);
-
- par_drv = pi_register_driver(name);
- if (!par_drv) {
- pr_err("failed to register %s driver\n", name);
- return -1;
- }
-
- k = 0;
- if (pg_drive_count == 0) {
- if (pi_init(dev->pi, 1, -1, -1, -1, -1, -1, pg_scratch,
- PI_PG, verbose, dev->name)) {
- if (!pg_probe(dev)) {
- dev->present = 1;
- k++;
- } else
- pi_release(dev->pi);
- }
-
- } else
- for (unit = 0; unit < PG_UNITS; unit++, dev++) {
- int *parm = *drives[unit];
- if (!parm[D_PRT])
- continue;
- if (pi_init(dev->pi, 0, parm[D_PRT], parm[D_MOD],
- parm[D_UNI], parm[D_PRO], parm[D_DLY],
- pg_scratch, PI_PG, verbose, dev->name)) {
- if (!pg_probe(dev)) {
- dev->present = 1;
- k++;
- } else
- pi_release(dev->pi);
- }
- }
-
- if (k)
- return 0;
-
- pi_unregister_driver(par_drv);
- printk("%s: No ATAPI device detected\n", name);
- return -1;
-}
-
-static int pg_open(struct inode *inode, struct file *file)
-{
- int unit = iminor(inode) & 0x7f;
- struct pg *dev = &devices[unit];
- int ret = 0;
-
- mutex_lock(&pg_mutex);
- if ((unit >= PG_UNITS) || (!dev->present)) {
- ret = -ENODEV;
- goto out;
- }
-
- if (test_and_set_bit(0, &dev->access)) {
- ret = -EBUSY;
- goto out;
- }
-
- if (dev->busy) {
- pg_reset(dev);
- dev->busy = 0;
- }
-
- pg_identify(dev, (verbose > 1));
-
- dev->bufptr = kmalloc(PG_MAX_DATA, GFP_KERNEL);
- if (dev->bufptr == NULL) {
- clear_bit(0, &dev->access);
- printk("%s: buffer allocation failed\n", dev->name);
- ret = -ENOMEM;
- goto out;
- }
-
- file->private_data = dev;
-
-out:
- mutex_unlock(&pg_mutex);
- return ret;
-}
-
-static int pg_release(struct inode *inode, struct file *file)
-{
- struct pg *dev = file->private_data;
-
- kfree(dev->bufptr);
- dev->bufptr = NULL;
- clear_bit(0, &dev->access);
-
- return 0;
-}
-
-static ssize_t pg_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
-{
- struct pg *dev = filp->private_data;
- struct pg_write_hdr hdr;
- int hs = sizeof (hdr);
-
- if (dev->busy)
- return -EBUSY;
- if (count < hs)
- return -EINVAL;
-
- if (copy_from_user(&hdr, buf, hs))
- return -EFAULT;
-
- if (hdr.magic != PG_MAGIC)
- return -EINVAL;
- if (hdr.dlen < 0 || hdr.dlen > PG_MAX_DATA)
- return -EINVAL;
- if ((count - hs) > PG_MAX_DATA)
- return -EINVAL;
-
- if (hdr.func == PG_RESET) {
- if (count != hs)
- return -EINVAL;
- if (pg_reset(dev))
- return -EIO;
- return count;
- }
-
- if (hdr.func != PG_COMMAND)
- return -EINVAL;
-
- dev->start = jiffies;
- dev->timeout = hdr.timeout * HZ + HZ / 2 + jiffies;
-
- if (pg_command(dev, hdr.packet, hdr.dlen, jiffies + PG_TMO)) {
- if (dev->status & 0x10)
- return -ETIME;
- return -EIO;
- }
-
- dev->busy = 1;
-
- if (copy_from_user(dev->bufptr, buf + hs, count - hs))
- return -EFAULT;
- return count;
-}
-
-static ssize_t pg_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
-{
- struct pg *dev = filp->private_data;
- struct pg_read_hdr hdr;
- int hs = sizeof (hdr);
- int copy;
-
- if (!dev->busy)
- return -EINVAL;
- if (count < hs)
- return -EINVAL;
-
- dev->busy = 0;
-
- if (pg_completion(dev, dev->bufptr, dev->timeout))
- if (dev->status & 0x10)
- return -ETIME;
-
- memset(&hdr, 0, sizeof(hdr));
- hdr.magic = PG_MAGIC;
- hdr.dlen = dev->dlen;
- copy = 0;
-
- if (hdr.dlen < 0) {
- hdr.dlen = -1 * hdr.dlen;
- copy = hdr.dlen;
- if (copy > (count - hs))
- copy = count - hs;
- }
-
- hdr.duration = (jiffies - dev->start + HZ / 2) / HZ;
- hdr.scsi = dev->status & 0x0f;
-
- if (copy_to_user(buf, &hdr, hs))
- return -EFAULT;
- if (copy > 0)
- if (copy_to_user(buf + hs, dev->bufptr, copy))
- return -EFAULT;
- return copy + hs;
-}
-
-static int __init pg_init(void)
-{
- int unit;
- int err;
-
- if (disable){
- err = -EINVAL;
- goto out;
- }
-
- pg_init_units();
-
- if (pg_detect()) {
- err = -ENODEV;
- goto out;
- }
-
- err = register_chrdev(major, name, &pg_fops);
- if (err < 0) {
- printk("pg_init: unable to get major number %d\n", major);
- for (unit = 0; unit < PG_UNITS; unit++) {
- struct pg *dev = &devices[unit];
- if (dev->present)
- pi_release(dev->pi);
- }
- goto out;
- }
- major = err; /* In case the user specified `major=0' (dynamic) */
- pg_class = class_create(THIS_MODULE, "pg");
- if (IS_ERR(pg_class)) {
- err = PTR_ERR(pg_class);
- goto out_chrdev;
- }
- for (unit = 0; unit < PG_UNITS; unit++) {
- struct pg *dev = &devices[unit];
- if (dev->present)
- device_create(pg_class, NULL, MKDEV(major, unit), NULL,
- "pg%u", unit);
- }
- err = 0;
- goto out;
-
-out_chrdev:
- unregister_chrdev(major, "pg");
-out:
- return err;
-}
-
-static void __exit pg_exit(void)
-{
- int unit;
-
- for (unit = 0; unit < PG_UNITS; unit++) {
- struct pg *dev = &devices[unit];
- if (dev->present)
- device_destroy(pg_class, MKDEV(major, unit));
- }
- class_destroy(pg_class);
- unregister_chrdev(major, name);
-
- for (unit = 0; unit < PG_UNITS; unit++) {
- struct pg *dev = &devices[unit];
- if (dev->present)
- pi_release(dev->pi);
- }
-}
-
-MODULE_LICENSE("GPL");
-module_init(pg_init)
-module_exit(pg_exit)
diff --git a/drivers/block/paride/pseudo.h b/drivers/block/paride/pseudo.h
deleted file mode 100644
index bc3703294143..000000000000
--- a/drivers/block/paride/pseudo.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- pseudo.h (c) 1997-8 Grant R. Guenther <grant@torque.net>
- Under the terms of the GNU General Public License.
-
- This is the "pseudo-interrupt" logic for parallel port drivers.
-
- This module is #included into each driver. It makes one
- function available:
-
- ps_set_intr( void (*continuation)(void),
- int (*ready)(void),
- int timeout,
- int nice )
-
- Which will arrange for ready() to be evaluated frequently and
- when either it returns true, or timeout jiffies have passed,
- continuation() will be invoked.
-
- If nice is 1, the test will done approximately once a
- jiffy. If nice is 0, the test will also be done whenever
- the scheduler runs (by adding it to a task queue). If
- nice is greater than 1, the test will be done once every
- (nice-1) jiffies.
-
-*/
-
-/* Changes:
-
- 1.01 1998.05.03 Switched from cli()/sti() to spinlocks
- 1.02 1998.12.14 Added support for nice > 1
-*/
-
-#define PS_VERSION "1.02"
-
-#include <linux/sched.h>
-#include <linux/workqueue.h>
-
-static void ps_tq_int(struct work_struct *work);
-
-static void (* ps_continuation)(void);
-static int (* ps_ready)(void);
-static unsigned long ps_timeout;
-static int ps_tq_active = 0;
-static int ps_nice = 0;
-
-static DEFINE_SPINLOCK(ps_spinlock __attribute__((unused)));
-
-static DECLARE_DELAYED_WORK(ps_tq, ps_tq_int);
-
-static void ps_set_intr(void (*continuation)(void),
- int (*ready)(void),
- int timeout, int nice)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&ps_spinlock,flags);
-
- ps_continuation = continuation;
- ps_ready = ready;
- ps_timeout = jiffies + timeout;
- ps_nice = nice;
-
- if (!ps_tq_active) {
- ps_tq_active = 1;
- if (!ps_nice)
- schedule_delayed_work(&ps_tq, 0);
- else
- schedule_delayed_work(&ps_tq, ps_nice-1);
- }
- spin_unlock_irqrestore(&ps_spinlock,flags);
-}
-
-static void ps_tq_int(struct work_struct *work)
-{
- void (*con)(void);
- unsigned long flags;
-
- spin_lock_irqsave(&ps_spinlock,flags);
-
- con = ps_continuation;
- ps_tq_active = 0;
-
- if (!con) {
- spin_unlock_irqrestore(&ps_spinlock,flags);
- return;
- }
- if (!ps_ready || ps_ready() || time_after_eq(jiffies, ps_timeout)) {
- ps_continuation = NULL;
- spin_unlock_irqrestore(&ps_spinlock,flags);
- con();
- return;
- }
- ps_tq_active = 1;
- if (!ps_nice)
- schedule_delayed_work(&ps_tq, 0);
- else
- schedule_delayed_work(&ps_tq, ps_nice-1);
- spin_unlock_irqrestore(&ps_spinlock,flags);
-}
-
-/* end of pseudo.h */
-
diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c
deleted file mode 100644
index e815312a00ad..000000000000
--- a/drivers/block/paride/pt.c
+++ /dev/null
@@ -1,1024 +0,0 @@
-/*
- pt.c (c) 1998 Grant R. Guenther <grant@torque.net>
- Under the terms of the GNU General Public License.
-
- This is the high-level driver for parallel port ATAPI tape
- drives based on chips supported by the paride module.
-
- The driver implements both rewinding and non-rewinding
- devices, filemarks, and the rewind ioctl. It allocates
- a small internal "bounce buffer" for each open device, but
- otherwise expects buffering and blocking to be done at the
- user level. As with most block-structured tapes, short
- writes are padded to full tape blocks, so reading back a file
- may return more data than was actually written.
-
- By default, the driver will autoprobe for a single parallel
- port ATAPI tape drive, but if their individual parameters are
- specified, the driver can handle up to 4 drives.
-
- The rewinding devices are named /dev/pt0, /dev/pt1, ...
- while the non-rewinding devices are /dev/npt0, /dev/npt1, etc.
-
- The behaviour of the pt driver can be altered by setting
- some parameters from the insmod command line. The following
- parameters are adjustable:
-
- drive0 These four arguments can be arrays of
- drive1 1-6 integers as follows:
- drive2
- drive3 <prt>,<pro>,<uni>,<mod>,<slv>,<dly>
-
- Where,
-
- <prt> is the base of the parallel port address for
- the corresponding drive. (required)
-
- <pro> is the protocol number for the adapter that
- supports this drive. These numbers are
- logged by 'paride' when the protocol modules
- are initialised. (0 if not given)
-
- <uni> for those adapters that support chained
- devices, this is the unit selector for the
- chain of devices on the given port. It should
- be zero for devices that don't support chaining.
- (0 if not given)
-
- <mod> this can be -1 to choose the best mode, or one
- of the mode numbers supported by the adapter.
- (-1 if not given)
-
- <slv> ATAPI devices can be jumpered to master or slave.
- Set this to 0 to choose the master drive, 1 to
- choose the slave, -1 (the default) to choose the
- first drive found.
-
- <dly> some parallel ports require the driver to
- go more slowly. -1 sets a default value that
- should work with the chosen protocol. Otherwise,
- set this to a small integer, the larger it is
- the slower the port i/o. In some cases, setting
- this to zero will speed up the device. (default -1)
-
- major You may use this parameter to override the
- default major number (96) that this driver
- will use. Be sure to change the device
- name as well.
-
- name This parameter is a character string that
- contains the name the kernel will use for this
- device (in /proc output, for instance).
- (default "pt").
-
- verbose This parameter controls the amount of logging
- that the driver will do. Set it to 0 for
- normal operation, 1 to see autoprobe progress
- messages, or 2 to see additional debugging
- output. (default 0)
-
- If this driver is built into the kernel, you can use
- the following command line parameters, with the same values
- as the corresponding module parameters listed above:
-
- pt.drive0
- pt.drive1
- pt.drive2
- pt.drive3
-
- In addition, you can use the parameter pt.disable to disable
- the driver entirely.
-
-*/
-
-/* Changes:
-
- 1.01 GRG 1998.05.06 Round up transfer size, fix ready_wait,
- loosed interpretation of ATAPI standard
- for clearing error status.
- Eliminate sti();
- 1.02 GRG 1998.06.16 Eliminate an Ugh.
- 1.03 GRG 1998.08.15 Adjusted PT_TMO, use HZ in loop timing,
- extra debugging
- 1.04 GRG 1998.09.24 Repair minor coding error, added jumbo support
-
-*/
-
-#define PT_VERSION "1.04"
-#define PT_MAJOR 96
-#define PT_NAME "pt"
-#define PT_UNITS 4
-
-#include <linux/types.h>
-
-/* Here are things one can override from the insmod command.
- Most are autoprobed by paride unless set here. Verbose is on
- by default.
-
-*/
-
-static int verbose = 0;
-static int major = PT_MAJOR;
-static char *name = PT_NAME;
-static int disable = 0;
-
-static int drive0[6] = { 0, 0, 0, -1, -1, -1 };
-static int drive1[6] = { 0, 0, 0, -1, -1, -1 };
-static int drive2[6] = { 0, 0, 0, -1, -1, -1 };
-static int drive3[6] = { 0, 0, 0, -1, -1, -1 };
-
-static int (*drives[4])[6] = {&drive0, &drive1, &drive2, &drive3};
-
-#define D_PRT 0
-#define D_PRO 1
-#define D_UNI 2
-#define D_MOD 3
-#define D_SLV 4
-#define D_DLY 5
-
-#define DU (*drives[unit])
-
-/* end of parameters */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/mtio.h>
-#include <linux/device.h>
-#include <linux/sched.h> /* current, TASK_*, schedule_timeout() */
-#include <linux/mutex.h>
-
-#include <linux/uaccess.h>
-
-module_param(verbose, int, 0);
-module_param(major, int, 0);
-module_param(name, charp, 0);
-module_param_array(drive0, int, NULL, 0);
-module_param_array(drive1, int, NULL, 0);
-module_param_array(drive2, int, NULL, 0);
-module_param_array(drive3, int, NULL, 0);
-
-#include "paride.h"
-
-#define PT_MAX_RETRIES 5
-#define PT_TMO 3000 /* interrupt timeout in jiffies */
-#define PT_SPIN_DEL 50 /* spin delay in micro-seconds */
-#define PT_RESET_TMO 30 /* 30 seconds */
-#define PT_READY_TMO 60 /* 60 seconds */
-#define PT_REWIND_TMO 1200 /* 20 minutes */
-
-#define PT_SPIN ((1000000/(HZ*PT_SPIN_DEL))*PT_TMO)
-
-#define STAT_ERR 0x00001
-#define STAT_INDEX 0x00002
-#define STAT_ECC 0x00004
-#define STAT_DRQ 0x00008
-#define STAT_SEEK 0x00010
-#define STAT_WRERR 0x00020
-#define STAT_READY 0x00040
-#define STAT_BUSY 0x00080
-#define STAT_SENSE 0x1f000
-
-#define ATAPI_TEST_READY 0x00
-#define ATAPI_REWIND 0x01
-#define ATAPI_REQ_SENSE 0x03
-#define ATAPI_READ_6 0x08
-#define ATAPI_WRITE_6 0x0a
-#define ATAPI_WFM 0x10
-#define ATAPI_IDENTIFY 0x12
-#define ATAPI_MODE_SENSE 0x1a
-#define ATAPI_LOG_SENSE 0x4d
-
-static DEFINE_MUTEX(pt_mutex);
-static int pt_open(struct inode *inode, struct file *file);
-static long pt_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
-static int pt_release(struct inode *inode, struct file *file);
-static ssize_t pt_read(struct file *filp, char __user *buf,
- size_t count, loff_t * ppos);
-static ssize_t pt_write(struct file *filp, const char __user *buf,
- size_t count, loff_t * ppos);
-static int pt_detect(void);
-
-/* bits in tape->flags */
-
-#define PT_MEDIA 1
-#define PT_WRITE_OK 2
-#define PT_REWIND 4
-#define PT_WRITING 8
-#define PT_READING 16
-#define PT_EOF 32
-
-#define PT_NAMELEN 8
-#define PT_BUFSIZE 16384
-
-struct pt_unit {
- struct pi_adapter pia; /* interface to paride layer */
- struct pi_adapter *pi;
- int flags; /* various state flags */
- int last_sense; /* result of last request sense */
- int drive; /* drive */
- atomic_t available; /* 1 if access is available 0 otherwise */
- int bs; /* block size */
- int capacity; /* Size of tape in KB */
- int present; /* device present ? */
- char *bufptr;
- char name[PT_NAMELEN]; /* pf0, pf1, ... */
-};
-
-static int pt_identify(struct pt_unit *tape);
-
-static struct pt_unit pt[PT_UNITS];
-
-static char pt_scratch[512]; /* scratch block buffer */
-static void *par_drv; /* reference of parport driver */
-
-/* kernel glue structures */
-
-static const struct file_operations pt_fops = {
- .owner = THIS_MODULE,
- .read = pt_read,
- .write = pt_write,
- .unlocked_ioctl = pt_ioctl,
- .open = pt_open,
- .release = pt_release,
- .llseek = noop_llseek,
-};
-
-/* sysfs class support */
-static struct class *pt_class;
-
-static inline int status_reg(struct pi_adapter *pi)
-{
- return pi_read_regr(pi, 1, 6);
-}
-
-static inline int read_reg(struct pi_adapter *pi, int reg)
-{
- return pi_read_regr(pi, 0, reg);
-}
-
-static inline void write_reg(struct pi_adapter *pi, int reg, int val)
-{
- pi_write_regr(pi, 0, reg, val);
-}
-
-static inline u8 DRIVE(struct pt_unit *tape)
-{
- return 0xa0+0x10*tape->drive;
-}
-
-static int pt_wait(struct pt_unit *tape, int go, int stop, char *fun, char *msg)
-{
- int j, r, e, s, p;
- struct pi_adapter *pi = tape->pi;
-
- j = 0;
- while ((((r = status_reg(pi)) & go) || (stop && (!(r & stop))))
- && (j++ < PT_SPIN))
- udelay(PT_SPIN_DEL);
-
- if ((r & (STAT_ERR & stop)) || (j > PT_SPIN)) {
- s = read_reg(pi, 7);
- e = read_reg(pi, 1);
- p = read_reg(pi, 2);
- if (j > PT_SPIN)
- e |= 0x100;
- if (fun)
- printk("%s: %s %s: alt=0x%x stat=0x%x err=0x%x"
- " loop=%d phase=%d\n",
- tape->name, fun, msg, r, s, e, j, p);
- return (e << 8) + s;
- }
- return 0;
-}
-
-static int pt_command(struct pt_unit *tape, char *cmd, int dlen, char *fun)
-{
- struct pi_adapter *pi = tape->pi;
- pi_connect(pi);
-
- write_reg(pi, 6, DRIVE(tape));
-
- if (pt_wait(tape, STAT_BUSY | STAT_DRQ, 0, fun, "before command")) {
- pi_disconnect(pi);
- return -1;
- }
-
- write_reg(pi, 4, dlen % 256);
- write_reg(pi, 5, dlen / 256);
- write_reg(pi, 7, 0xa0); /* ATAPI packet command */
-
- if (pt_wait(tape, STAT_BUSY, STAT_DRQ, fun, "command DRQ")) {
- pi_disconnect(pi);
- return -1;
- }
-
- if (read_reg(pi, 2) != 1) {
- printk("%s: %s: command phase error\n", tape->name, fun);
- pi_disconnect(pi);
- return -1;
- }
-
- pi_write_block(pi, cmd, 12);
-
- return 0;
-}
-
-static int pt_completion(struct pt_unit *tape, char *buf, char *fun)
-{
- struct pi_adapter *pi = tape->pi;
- int r, s, n, p;
-
- r = pt_wait(tape, STAT_BUSY, STAT_DRQ | STAT_READY | STAT_ERR,
- fun, "completion");
-
- if (read_reg(pi, 7) & STAT_DRQ) {
- n = (((read_reg(pi, 4) + 256 * read_reg(pi, 5)) +
- 3) & 0xfffc);
- p = read_reg(pi, 2) & 3;
- if (p == 0)
- pi_write_block(pi, buf, n);
- if (p == 2)
- pi_read_block(pi, buf, n);
- }
-
- s = pt_wait(tape, STAT_BUSY, STAT_READY | STAT_ERR, fun, "data done");
-
- pi_disconnect(pi);
-
- return (r ? r : s);
-}
-
-static void pt_req_sense(struct pt_unit *tape, int quiet)
-{
- char rs_cmd[12] = { ATAPI_REQ_SENSE, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0 };
- char buf[16];
- int r;
-
- r = pt_command(tape, rs_cmd, 16, "Request sense");
- mdelay(1);
- if (!r)
- pt_completion(tape, buf, "Request sense");
-
- tape->last_sense = -1;
- if (!r) {
- if (!quiet)
- printk("%s: Sense key: %x, ASC: %x, ASQ: %x\n",
- tape->name, buf[2] & 0xf, buf[12], buf[13]);
- tape->last_sense = (buf[2] & 0xf) | ((buf[12] & 0xff) << 8)
- | ((buf[13] & 0xff) << 16);
- }
-}
-
-static int pt_atapi(struct pt_unit *tape, char *cmd, int dlen, char *buf, char *fun)
-{
- int r;
-
- r = pt_command(tape, cmd, dlen, fun);
- mdelay(1);
- if (!r)
- r = pt_completion(tape, buf, fun);
- if (r)
- pt_req_sense(tape, !fun);
-
- return r;
-}
-
-static void pt_sleep(int cs)
-{
- schedule_timeout_interruptible(cs);
-}
-
-static int pt_poll_dsc(struct pt_unit *tape, int pause, int tmo, char *msg)
-{
- struct pi_adapter *pi = tape->pi;
- int k, e, s;
-
- k = 0;
- e = 0;
- s = 0;
- while (k < tmo) {
- pt_sleep(pause);
- k++;
- pi_connect(pi);
- write_reg(pi, 6, DRIVE(tape));
- s = read_reg(pi, 7);
- e = read_reg(pi, 1);
- pi_disconnect(pi);
- if (s & (STAT_ERR | STAT_SEEK))
- break;
- }
- if ((k >= tmo) || (s & STAT_ERR)) {
- if (k >= tmo)
- printk("%s: %s DSC timeout\n", tape->name, msg);
- else
- printk("%s: %s stat=0x%x err=0x%x\n", tape->name, msg, s,
- e);
- pt_req_sense(tape, 0);
- return 0;
- }
- return 1;
-}
-
-static void pt_media_access_cmd(struct pt_unit *tape, int tmo, char *cmd, char *fun)
-{
- if (pt_command(tape, cmd, 0, fun)) {
- pt_req_sense(tape, 0);
- return;
- }
- pi_disconnect(tape->pi);
- pt_poll_dsc(tape, HZ, tmo, fun);
-}
-
-static void pt_rewind(struct pt_unit *tape)
-{
- char rw_cmd[12] = { ATAPI_REWIND, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-
- pt_media_access_cmd(tape, PT_REWIND_TMO, rw_cmd, "rewind");
-}
-
-static void pt_write_fm(struct pt_unit *tape)
-{
- char wm_cmd[12] = { ATAPI_WFM, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 };
-
- pt_media_access_cmd(tape, PT_TMO, wm_cmd, "write filemark");
-}
-
-#define DBMSG(msg) ((verbose>1)?(msg):NULL)
-
-static int pt_reset(struct pt_unit *tape)
-{
- struct pi_adapter *pi = tape->pi;
- int i, k, flg;
- int expect[5] = { 1, 1, 1, 0x14, 0xeb };
-
- pi_connect(pi);
- write_reg(pi, 6, DRIVE(tape));
- write_reg(pi, 7, 8);
-
- pt_sleep(20 * HZ / 1000);
-
- k = 0;
- while ((k++ < PT_RESET_TMO) && (status_reg(pi) & STAT_BUSY))
- pt_sleep(HZ / 10);
-
- flg = 1;
- for (i = 0; i < 5; i++)
- flg &= (read_reg(pi, i + 1) == expect[i]);
-
- if (verbose) {
- printk("%s: Reset (%d) signature = ", tape->name, k);
- for (i = 0; i < 5; i++)
- printk("%3x", read_reg(pi, i + 1));
- if (!flg)
- printk(" (incorrect)");
- printk("\n");
- }
-
- pi_disconnect(pi);
- return flg - 1;
-}
-
-static int pt_ready_wait(struct pt_unit *tape, int tmo)
-{
- char tr_cmd[12] = { ATAPI_TEST_READY, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- int k, p;
-
- k = 0;
- while (k < tmo) {
- tape->last_sense = 0;
- pt_atapi(tape, tr_cmd, 0, NULL, DBMSG("test unit ready"));
- p = tape->last_sense;
- if (!p)
- return 0;
- if (!(((p & 0xffff) == 0x0402) || ((p & 0xff) == 6)))
- return p;
- k++;
- pt_sleep(HZ);
- }
- return 0x000020; /* timeout */
-}
-
-static void xs(char *buf, char *targ, int offs, int len)
-{
- int j, k, l;
-
- j = 0;
- l = 0;
- for (k = 0; k < len; k++)
- if ((buf[k + offs] != 0x20) || (buf[k + offs] != l))
- l = targ[j++] = buf[k + offs];
- if (l == 0x20)
- j--;
- targ[j] = 0;
-}
-
-static int xn(char *buf, int offs, int size)
-{
- int v, k;
-
- v = 0;
- for (k = 0; k < size; k++)
- v = v * 256 + (buf[k + offs] & 0xff);
- return v;
-}
-
-static int pt_identify(struct pt_unit *tape)
-{
- int dt, s;
- char *ms[2] = { "master", "slave" };
- char mf[10], id[18];
- char id_cmd[12] = { ATAPI_IDENTIFY, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0 };
- char ms_cmd[12] =
- { ATAPI_MODE_SENSE, 0, 0x2a, 0, 36, 0, 0, 0, 0, 0, 0, 0 };
- char ls_cmd[12] =
- { ATAPI_LOG_SENSE, 0, 0x71, 0, 0, 0, 0, 0, 36, 0, 0, 0 };
- char buf[36];
-
- s = pt_atapi(tape, id_cmd, 36, buf, "identify");
- if (s)
- return -1;
-
- dt = buf[0] & 0x1f;
- if (dt != 1) {
- if (verbose)
- printk("%s: Drive %d, unsupported type %d\n",
- tape->name, tape->drive, dt);
- return -1;
- }
-
- xs(buf, mf, 8, 8);
- xs(buf, id, 16, 16);
-
- tape->flags = 0;
- tape->capacity = 0;
- tape->bs = 0;
-
- if (!pt_ready_wait(tape, PT_READY_TMO))
- tape->flags |= PT_MEDIA;
-
- if (!pt_atapi(tape, ms_cmd, 36, buf, "mode sense")) {
- if (!(buf[2] & 0x80))
- tape->flags |= PT_WRITE_OK;
- tape->bs = xn(buf, 10, 2);
- }
-
- if (!pt_atapi(tape, ls_cmd, 36, buf, "log sense"))
- tape->capacity = xn(buf, 24, 4);
-
- printk("%s: %s %s, %s", tape->name, mf, id, ms[tape->drive]);
- if (!(tape->flags & PT_MEDIA))
- printk(", no media\n");
- else {
- if (!(tape->flags & PT_WRITE_OK))
- printk(", RO");
- printk(", blocksize %d, %d MB\n", tape->bs, tape->capacity / 1024);
- }
-
- return 0;
-}
-
-
-/*
- * returns 0, with id set if drive is detected
- * -1, if drive detection failed
- */
-static int pt_probe(struct pt_unit *tape)
-{
- if (tape->drive == -1) {
- for (tape->drive = 0; tape->drive <= 1; tape->drive++)
- if (!pt_reset(tape))
- return pt_identify(tape);
- } else {
- if (!pt_reset(tape))
- return pt_identify(tape);
- }
- return -1;
-}
-
-static int pt_detect(void)
-{
- struct pt_unit *tape;
- int specified = 0, found = 0;
- int unit;
-
- printk("%s: %s version %s, major %d\n", name, name, PT_VERSION, major);
-
- par_drv = pi_register_driver(name);
- if (!par_drv) {
- pr_err("failed to register %s driver\n", name);
- return -1;
- }
-
- specified = 0;
- for (unit = 0; unit < PT_UNITS; unit++) {
- struct pt_unit *tape = &pt[unit];
- tape->pi = &tape->pia;
- atomic_set(&tape->available, 1);
- tape->flags = 0;
- tape->last_sense = 0;
- tape->present = 0;
- tape->bufptr = NULL;
- tape->drive = DU[D_SLV];
- snprintf(tape->name, PT_NAMELEN, "%s%d", name, unit);
- if (!DU[D_PRT])
- continue;
- specified++;
- if (pi_init(tape->pi, 0, DU[D_PRT], DU[D_MOD], DU[D_UNI],
- DU[D_PRO], DU[D_DLY], pt_scratch, PI_PT,
- verbose, tape->name)) {
- if (!pt_probe(tape)) {
- tape->present = 1;
- found++;
- } else
- pi_release(tape->pi);
- }
- }
- if (specified == 0) {
- tape = pt;
- if (pi_init(tape->pi, 1, -1, -1, -1, -1, -1, pt_scratch,
- PI_PT, verbose, tape->name)) {
- if (!pt_probe(tape)) {
- tape->present = 1;
- found++;
- } else
- pi_release(tape->pi);
- }
-
- }
- if (found)
- return 0;
-
- pi_unregister_driver(par_drv);
- printk("%s: No ATAPI tape drive detected\n", name);
- return -1;
-}
-
-static int pt_open(struct inode *inode, struct file *file)
-{
- int unit = iminor(inode) & 0x7F;
- struct pt_unit *tape = pt + unit;
- int err;
-
- mutex_lock(&pt_mutex);
- if (unit >= PT_UNITS || (!tape->present)) {
- mutex_unlock(&pt_mutex);
- return -ENODEV;
- }
-
- err = -EBUSY;
- if (!atomic_dec_and_test(&tape->available))
- goto out;
-
- pt_identify(tape);
-
- err = -ENODEV;
- if (!(tape->flags & PT_MEDIA))
- goto out;
-
- err = -EROFS;
- if ((!(tape->flags & PT_WRITE_OK)) && (file->f_mode & FMODE_WRITE))
- goto out;
-
- if (!(iminor(inode) & 128))
- tape->flags |= PT_REWIND;
-
- err = -ENOMEM;
- tape->bufptr = kmalloc(PT_BUFSIZE, GFP_KERNEL);
- if (tape->bufptr == NULL) {
- printk("%s: buffer allocation failed\n", tape->name);
- goto out;
- }
-
- file->private_data = tape;
- mutex_unlock(&pt_mutex);
- return 0;
-
-out:
- atomic_inc(&tape->available);
- mutex_unlock(&pt_mutex);
- return err;
-}
-
-static long pt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct pt_unit *tape = file->private_data;
- struct mtop __user *p = (void __user *)arg;
- struct mtop mtop;
-
- switch (cmd) {
- case MTIOCTOP:
- if (copy_from_user(&mtop, p, sizeof(struct mtop)))
- return -EFAULT;
-
- switch (mtop.mt_op) {
-
- case MTREW:
- mutex_lock(&pt_mutex);
- pt_rewind(tape);
- mutex_unlock(&pt_mutex);
- return 0;
-
- case MTWEOF:
- mutex_lock(&pt_mutex);
- pt_write_fm(tape);
- mutex_unlock(&pt_mutex);
- return 0;
-
- default:
- /* FIXME: rate limit ?? */
- printk(KERN_DEBUG "%s: Unimplemented mt_op %d\n", tape->name,
- mtop.mt_op);
- return -EINVAL;
- }
-
- default:
- return -ENOTTY;
- }
-}
-
-static int
-pt_release(struct inode *inode, struct file *file)
-{
- struct pt_unit *tape = file->private_data;
-
- if (atomic_read(&tape->available) > 1)
- return -EINVAL;
-
- if (tape->flags & PT_WRITING)
- pt_write_fm(tape);
-
- if (tape->flags & PT_REWIND)
- pt_rewind(tape);
-
- kfree(tape->bufptr);
- tape->bufptr = NULL;
-
- atomic_inc(&tape->available);
-
- return 0;
-
-}
-
-static ssize_t pt_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
-{
- struct pt_unit *tape = filp->private_data;
- struct pi_adapter *pi = tape->pi;
- char rd_cmd[12] = { ATAPI_READ_6, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- int k, n, r, p, s, t, b;
-
- if (!(tape->flags & (PT_READING | PT_WRITING))) {
- tape->flags |= PT_READING;
- if (pt_atapi(tape, rd_cmd, 0, NULL, "start read-ahead"))
- return -EIO;
- } else if (tape->flags & PT_WRITING)
- return -EIO;
-
- if (tape->flags & PT_EOF)
- return 0;
-
- t = 0;
-
- while (count > 0) {
-
- if (!pt_poll_dsc(tape, HZ / 100, PT_TMO, "read"))
- return -EIO;
-
- n = count;
- if (n > 32768)
- n = 32768; /* max per command */
- b = (n - 1 + tape->bs) / tape->bs;
- n = b * tape->bs; /* rounded up to even block */
-
- rd_cmd[4] = b;
-
- r = pt_command(tape, rd_cmd, n, "read");
-
- mdelay(1);
-
- if (r) {
- pt_req_sense(tape, 0);
- return -EIO;
- }
-
- while (1) {
-
- r = pt_wait(tape, STAT_BUSY,
- STAT_DRQ | STAT_ERR | STAT_READY,
- DBMSG("read DRQ"), "");
-
- if (r & STAT_SENSE) {
- pi_disconnect(pi);
- pt_req_sense(tape, 0);
- return -EIO;
- }
-
- if (r)
- tape->flags |= PT_EOF;
-
- s = read_reg(pi, 7);
-
- if (!(s & STAT_DRQ))
- break;
-
- n = (read_reg(pi, 4) + 256 * read_reg(pi, 5));
- p = (read_reg(pi, 2) & 3);
- if (p != 2) {
- pi_disconnect(pi);
- printk("%s: Phase error on read: %d\n", tape->name,
- p);
- return -EIO;
- }
-
- while (n > 0) {
- k = n;
- if (k > PT_BUFSIZE)
- k = PT_BUFSIZE;
- pi_read_block(pi, tape->bufptr, k);
- n -= k;
- b = k;
- if (b > count)
- b = count;
- if (copy_to_user(buf + t, tape->bufptr, b)) {
- pi_disconnect(pi);
- return -EFAULT;
- }
- t += b;
- count -= b;
- }
-
- }
- pi_disconnect(pi);
- if (tape->flags & PT_EOF)
- break;
- }
-
- return t;
-
-}
-
-static ssize_t pt_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
-{
- struct pt_unit *tape = filp->private_data;
- struct pi_adapter *pi = tape->pi;
- char wr_cmd[12] = { ATAPI_WRITE_6, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- int k, n, r, p, s, t, b;
-
- if (!(tape->flags & PT_WRITE_OK))
- return -EROFS;
-
- if (!(tape->flags & (PT_READING | PT_WRITING))) {
- tape->flags |= PT_WRITING;
- if (pt_atapi
- (tape, wr_cmd, 0, NULL, "start buffer-available mode"))
- return -EIO;
- } else if (tape->flags & PT_READING)
- return -EIO;
-
- if (tape->flags & PT_EOF)
- return -ENOSPC;
-
- t = 0;
-
- while (count > 0) {
-
- if (!pt_poll_dsc(tape, HZ / 100, PT_TMO, "write"))
- return -EIO;
-
- n = count;
- if (n > 32768)
- n = 32768; /* max per command */
- b = (n - 1 + tape->bs) / tape->bs;
- n = b * tape->bs; /* rounded up to even block */
-
- wr_cmd[4] = b;
-
- r = pt_command(tape, wr_cmd, n, "write");
-
- mdelay(1);
-
- if (r) { /* error delivering command only */
- pt_req_sense(tape, 0);
- return -EIO;
- }
-
- while (1) {
-
- r = pt_wait(tape, STAT_BUSY,
- STAT_DRQ | STAT_ERR | STAT_READY,
- DBMSG("write DRQ"), NULL);
-
- if (r & STAT_SENSE) {
- pi_disconnect(pi);
- pt_req_sense(tape, 0);
- return -EIO;
- }
-
- if (r)
- tape->flags |= PT_EOF;
-
- s = read_reg(pi, 7);
-
- if (!(s & STAT_DRQ))
- break;
-
- n = (read_reg(pi, 4) + 256 * read_reg(pi, 5));
- p = (read_reg(pi, 2) & 3);
- if (p != 0) {
- pi_disconnect(pi);
- printk("%s: Phase error on write: %d \n",
- tape->name, p);
- return -EIO;
- }
-
- while (n > 0) {
- k = n;
- if (k > PT_BUFSIZE)
- k = PT_BUFSIZE;
- b = k;
- if (b > count)
- b = count;
- if (copy_from_user(tape->bufptr, buf + t, b)) {
- pi_disconnect(pi);
- return -EFAULT;
- }
- pi_write_block(pi, tape->bufptr, k);
- t += b;
- count -= b;
- n -= k;
- }
-
- }
- pi_disconnect(pi);
- if (tape->flags & PT_EOF)
- break;
- }
-
- return t;
-}
-
-static int __init pt_init(void)
-{
- int unit;
- int err;
-
- if (disable) {
- err = -EINVAL;
- goto out;
- }
-
- if (pt_detect()) {
- err = -ENODEV;
- goto out;
- }
-
- err = register_chrdev(major, name, &pt_fops);
- if (err < 0) {
- printk("pt_init: unable to get major number %d\n", major);
- for (unit = 0; unit < PT_UNITS; unit++)
- if (pt[unit].present)
- pi_release(pt[unit].pi);
- goto out;
- }
- major = err;
- pt_class = class_create(THIS_MODULE, "pt");
- if (IS_ERR(pt_class)) {
- err = PTR_ERR(pt_class);
- goto out_chrdev;
- }
-
- for (unit = 0; unit < PT_UNITS; unit++)
- if (pt[unit].present) {
- device_create(pt_class, NULL, MKDEV(major, unit), NULL,
- "pt%d", unit);
- device_create(pt_class, NULL, MKDEV(major, unit + 128),
- NULL, "pt%dn", unit);
- }
- goto out;
-
-out_chrdev:
- unregister_chrdev(major, "pt");
-out:
- return err;
-}
-
-static void __exit pt_exit(void)
-{
- int unit;
- for (unit = 0; unit < PT_UNITS; unit++)
- if (pt[unit].present) {
- device_destroy(pt_class, MKDEV(major, unit));
- device_destroy(pt_class, MKDEV(major, unit + 128));
- }
- class_destroy(pt_class);
- unregister_chrdev(major, name);
- for (unit = 0; unit < PT_UNITS; unit++)
- if (pt[unit].present)
- pi_release(pt[unit].pi);
-}
-
-MODULE_LICENSE("GPL");
-module_init(pt_init)
-module_exit(pt_exit)
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index 1faca7e07a4d..5cb008b9700a 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -5291,8 +5291,7 @@ static void rbd_dev_release(struct device *dev)
module_put(THIS_MODULE);
}
-static struct rbd_device *__rbd_dev_create(struct rbd_client *rbdc,
- struct rbd_spec *spec)
+static struct rbd_device *__rbd_dev_create(struct rbd_spec *spec)
{
struct rbd_device *rbd_dev;
@@ -5337,9 +5336,6 @@ static struct rbd_device *__rbd_dev_create(struct rbd_client *rbdc,
rbd_dev->dev.parent = &rbd_root_dev;
device_initialize(&rbd_dev->dev);
- rbd_dev->rbd_client = rbdc;
- rbd_dev->spec = spec;
-
return rbd_dev;
}
@@ -5352,12 +5348,10 @@ static struct rbd_device *rbd_dev_create(struct rbd_client *rbdc,
{
struct rbd_device *rbd_dev;
- rbd_dev = __rbd_dev_create(rbdc, spec);
+ rbd_dev = __rbd_dev_create(spec);
if (!rbd_dev)
return NULL;
- rbd_dev->opts = opts;
-
/* get an id and fill in device name */
rbd_dev->dev_id = ida_simple_get(&rbd_dev_id_ida, 0,
minor_to_rbd_dev_id(1 << MINORBITS),
@@ -5374,6 +5368,10 @@ static struct rbd_device *rbd_dev_create(struct rbd_client *rbdc,
/* we have a ref from do_rbd_add() */
__module_get(THIS_MODULE);
+ rbd_dev->rbd_client = rbdc;
+ rbd_dev->spec = spec;
+ rbd_dev->opts = opts;
+
dout("%s rbd_dev %p dev_id %d\n", __func__, rbd_dev, rbd_dev->dev_id);
return rbd_dev;
@@ -6735,7 +6733,7 @@ static int rbd_dev_probe_parent(struct rbd_device *rbd_dev, int depth)
goto out_err;
}
- parent = __rbd_dev_create(rbd_dev->rbd_client, rbd_dev->parent_spec);
+ parent = __rbd_dev_create(rbd_dev->parent_spec);
if (!parent) {
ret = -ENOMEM;
goto out_err;
@@ -6745,8 +6743,8 @@ static int rbd_dev_probe_parent(struct rbd_device *rbd_dev, int depth)
* Images related by parent/child relationships always share
* rbd_client and spec/parent_spec, so bump their refcounts.
*/
- __rbd_get_client(rbd_dev->rbd_client);
- rbd_spec_get(rbd_dev->parent_spec);
+ parent->rbd_client = __rbd_get_client(rbd_dev->rbd_client);
+ parent->spec = rbd_spec_get(rbd_dev->parent_spec);
__set_bit(RBD_DEV_FLAG_READONLY, &parent->flags);
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index dc6e9b989910..2723eede6f21 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -15,6 +15,7 @@
#include <linux/blk-mq.h>
#include <linux/blk-mq-virtio.h>
#include <linux/numa.h>
+#include <linux/vmalloc.h>
#include <uapi/linux/virtio_ring.h>
#define PART_BITS 4
@@ -80,22 +81,51 @@ struct virtio_blk {
int num_vqs;
int io_queues[HCTX_MAX_TYPES];
struct virtio_blk_vq *vqs;
+
+ /* For zoned device */
+ unsigned int zone_sectors;
};
struct virtblk_req {
+ /* Out header */
struct virtio_blk_outhdr out_hdr;
- u8 status;
+
+ /* In header */
+ union {
+ u8 status;
+
+ /*
+ * The zone append command has an extended in header.
+ * The status field in zone_append_in_hdr must have
+ * the same offset in virtblk_req as the non-zoned
+ * status field above.
+ */
+ struct {
+ u8 status;
+ u8 reserved[7];
+ __le64 append_sector;
+ } zone_append_in_hdr;
+ };
+
+ size_t in_hdr_len;
+
struct sg_table sg_table;
struct scatterlist sg[];
};
-static inline blk_status_t virtblk_result(struct virtblk_req *vbr)
+static inline blk_status_t virtblk_result(u8 status)
{
- switch (vbr->status) {
+ switch (status) {
case VIRTIO_BLK_S_OK:
return BLK_STS_OK;
case VIRTIO_BLK_S_UNSUPP:
return BLK_STS_NOTSUPP;
+ case VIRTIO_BLK_S_ZONE_OPEN_RESOURCE:
+ return BLK_STS_ZONE_OPEN_RESOURCE;
+ case VIRTIO_BLK_S_ZONE_ACTIVE_RESOURCE:
+ return BLK_STS_ZONE_ACTIVE_RESOURCE;
+ case VIRTIO_BLK_S_IOERR:
+ case VIRTIO_BLK_S_ZONE_UNALIGNED_WP:
default:
return BLK_STS_IOERR;
}
@@ -111,11 +141,11 @@ static inline struct virtio_blk_vq *get_virtio_blk_vq(struct blk_mq_hw_ctx *hctx
static int virtblk_add_req(struct virtqueue *vq, struct virtblk_req *vbr)
{
- struct scatterlist hdr, status, *sgs[3];
+ struct scatterlist out_hdr, in_hdr, *sgs[3];
unsigned int num_out = 0, num_in = 0;
- sg_init_one(&hdr, &vbr->out_hdr, sizeof(vbr->out_hdr));
- sgs[num_out++] = &hdr;
+ sg_init_one(&out_hdr, &vbr->out_hdr, sizeof(vbr->out_hdr));
+ sgs[num_out++] = &out_hdr;
if (vbr->sg_table.nents) {
if (vbr->out_hdr.type & cpu_to_virtio32(vq->vdev, VIRTIO_BLK_T_OUT))
@@ -124,8 +154,8 @@ static int virtblk_add_req(struct virtqueue *vq, struct virtblk_req *vbr)
sgs[num_out + num_in++] = vbr->sg_table.sgl;
}
- sg_init_one(&status, &vbr->status, sizeof(vbr->status));
- sgs[num_out + num_in++] = &status;
+ sg_init_one(&in_hdr, &vbr->status, vbr->in_hdr_len);
+ sgs[num_out + num_in++] = &in_hdr;
return virtqueue_add_sgs(vq, sgs, num_out, num_in, vbr, GFP_ATOMIC);
}
@@ -212,21 +242,22 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev,
struct request *req,
struct virtblk_req *vbr)
{
+ size_t in_hdr_len = sizeof(vbr->status);
bool unmap = false;
u32 type;
+ u64 sector = 0;
- vbr->out_hdr.sector = 0;
+ /* Set fields for all request types */
+ vbr->out_hdr.ioprio = cpu_to_virtio32(vdev, req_get_ioprio(req));
switch (req_op(req)) {
case REQ_OP_READ:
type = VIRTIO_BLK_T_IN;
- vbr->out_hdr.sector = cpu_to_virtio64(vdev,
- blk_rq_pos(req));
+ sector = blk_rq_pos(req);
break;
case REQ_OP_WRITE:
type = VIRTIO_BLK_T_OUT;
- vbr->out_hdr.sector = cpu_to_virtio64(vdev,
- blk_rq_pos(req));
+ sector = blk_rq_pos(req);
break;
case REQ_OP_FLUSH:
type = VIRTIO_BLK_T_FLUSH;
@@ -241,16 +272,42 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev,
case REQ_OP_SECURE_ERASE:
type = VIRTIO_BLK_T_SECURE_ERASE;
break;
- case REQ_OP_DRV_IN:
- type = VIRTIO_BLK_T_GET_ID;
+ case REQ_OP_ZONE_OPEN:
+ type = VIRTIO_BLK_T_ZONE_OPEN;
+ sector = blk_rq_pos(req);
+ break;
+ case REQ_OP_ZONE_CLOSE:
+ type = VIRTIO_BLK_T_ZONE_CLOSE;
+ sector = blk_rq_pos(req);
+ break;
+ case REQ_OP_ZONE_FINISH:
+ type = VIRTIO_BLK_T_ZONE_FINISH;
+ sector = blk_rq_pos(req);
break;
+ case REQ_OP_ZONE_APPEND:
+ type = VIRTIO_BLK_T_ZONE_APPEND;
+ sector = blk_rq_pos(req);
+ in_hdr_len = sizeof(vbr->zone_append_in_hdr);
+ break;
+ case REQ_OP_ZONE_RESET:
+ type = VIRTIO_BLK_T_ZONE_RESET;
+ sector = blk_rq_pos(req);
+ break;
+ case REQ_OP_ZONE_RESET_ALL:
+ type = VIRTIO_BLK_T_ZONE_RESET_ALL;
+ break;
+ case REQ_OP_DRV_IN:
+ /* Out header already filled in, nothing to do */
+ return 0;
default:
WARN_ON_ONCE(1);
return BLK_STS_IOERR;
}
+ /* Set fields for non-REQ_OP_DRV_IN request types */
+ vbr->in_hdr_len = in_hdr_len;
vbr->out_hdr.type = cpu_to_virtio32(vdev, type);
- vbr->out_hdr.ioprio = cpu_to_virtio32(vdev, req_get_ioprio(req));
+ vbr->out_hdr.sector = cpu_to_virtio64(vdev, sector);
if (type == VIRTIO_BLK_T_DISCARD || type == VIRTIO_BLK_T_WRITE_ZEROES ||
type == VIRTIO_BLK_T_SECURE_ERASE) {
@@ -264,39 +321,74 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev,
static inline void virtblk_request_done(struct request *req)
{
struct virtblk_req *vbr = blk_mq_rq_to_pdu(req);
+ blk_status_t status = virtblk_result(vbr->status);
virtblk_unmap_data(req, vbr);
virtblk_cleanup_cmd(req);
- blk_mq_end_request(req, virtblk_result(vbr));
+
+ if (req_op(req) == REQ_OP_ZONE_APPEND)
+ req->__sector = le64_to_cpu(vbr->zone_append_in_hdr.append_sector);
+
+ blk_mq_end_request(req, status);
+}
+
+static void virtblk_complete_batch(struct io_comp_batch *iob)
+{
+ struct request *req;
+
+ rq_list_for_each(&iob->req_list, req) {
+ virtblk_unmap_data(req, blk_mq_rq_to_pdu(req));
+ virtblk_cleanup_cmd(req);
+ }
+ blk_mq_end_request_batch(iob);
+}
+
+static int virtblk_handle_req(struct virtio_blk_vq *vq,
+ struct io_comp_batch *iob)
+{
+ struct virtblk_req *vbr;
+ int req_done = 0;
+ unsigned int len;
+
+ while ((vbr = virtqueue_get_buf(vq->vq, &len)) != NULL) {
+ struct request *req = blk_mq_rq_from_pdu(vbr);
+
+ if (likely(!blk_should_fake_timeout(req->q)) &&
+ !blk_mq_complete_request_remote(req) &&
+ !blk_mq_add_to_batch(req, iob, vbr->status,
+ virtblk_complete_batch))
+ virtblk_request_done(req);
+ req_done++;
+ }
+
+ return req_done;
}
static void virtblk_done(struct virtqueue *vq)
{
struct virtio_blk *vblk = vq->vdev->priv;
- bool req_done = false;
- int qid = vq->index;
- struct virtblk_req *vbr;
+ struct virtio_blk_vq *vblk_vq = &vblk->vqs[vq->index];
+ int req_done = 0;
unsigned long flags;
- unsigned int len;
+ DEFINE_IO_COMP_BATCH(iob);
- spin_lock_irqsave(&vblk->vqs[qid].lock, flags);
+ spin_lock_irqsave(&vblk_vq->lock, flags);
do {
virtqueue_disable_cb(vq);
- while ((vbr = virtqueue_get_buf(vblk->vqs[qid].vq, &len)) != NULL) {
- struct request *req = blk_mq_rq_from_pdu(vbr);
+ req_done += virtblk_handle_req(vblk_vq, &iob);
- if (likely(!blk_should_fake_timeout(req->q)))
- blk_mq_complete_request(req);
- req_done = true;
- }
if (unlikely(virtqueue_is_broken(vq)))
break;
} while (!virtqueue_enable_cb(vq));
- /* In case queue is stopped waiting for more buffers. */
- if (req_done)
+ if (req_done) {
+ if (!rq_list_empty(iob.req_list))
+ iob.complete(&iob);
+
+ /* In case queue is stopped waiting for more buffers. */
blk_mq_start_stopped_hw_queues(vblk->disk->queue, true);
- spin_unlock_irqrestore(&vblk->vqs[qid].lock, flags);
+ }
+ spin_unlock_irqrestore(&vblk_vq->lock, flags);
}
static void virtio_commit_rqs(struct blk_mq_hw_ctx *hctx)
@@ -455,6 +547,275 @@ static void virtio_queue_rqs(struct request **rqlist)
*rqlist = requeue_list;
}
+#ifdef CONFIG_BLK_DEV_ZONED
+static void *virtblk_alloc_report_buffer(struct virtio_blk *vblk,
+ unsigned int nr_zones,
+ unsigned int zone_sectors,
+ size_t *buflen)
+{
+ struct request_queue *q = vblk->disk->queue;
+ size_t bufsize;
+ void *buf;
+
+ nr_zones = min_t(unsigned int, nr_zones,
+ get_capacity(vblk->disk) >> ilog2(zone_sectors));
+
+ bufsize = sizeof(struct virtio_blk_zone_report) +
+ nr_zones * sizeof(struct virtio_blk_zone_descriptor);
+ bufsize = min_t(size_t, bufsize,
+ queue_max_hw_sectors(q) << SECTOR_SHIFT);
+ bufsize = min_t(size_t, bufsize, queue_max_segments(q) << PAGE_SHIFT);
+
+ while (bufsize >= sizeof(struct virtio_blk_zone_report)) {
+ buf = __vmalloc(bufsize, GFP_KERNEL | __GFP_NORETRY);
+ if (buf) {
+ *buflen = bufsize;
+ return buf;
+ }
+ bufsize >>= 1;
+ }
+
+ return NULL;
+}
+
+static int virtblk_submit_zone_report(struct virtio_blk *vblk,
+ char *report_buf, size_t report_len,
+ sector_t sector)
+{
+ struct request_queue *q = vblk->disk->queue;
+ struct request *req;
+ struct virtblk_req *vbr;
+ int err;
+
+ req = blk_mq_alloc_request(q, REQ_OP_DRV_IN, 0);
+ if (IS_ERR(req))
+ return PTR_ERR(req);
+
+ vbr = blk_mq_rq_to_pdu(req);
+ vbr->in_hdr_len = sizeof(vbr->status);
+ vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_ZONE_REPORT);
+ vbr->out_hdr.sector = cpu_to_virtio64(vblk->vdev, sector);
+
+ err = blk_rq_map_kern(q, req, report_buf, report_len, GFP_KERNEL);
+ if (err)
+ goto out;
+
+ blk_execute_rq(req, false);
+ err = blk_status_to_errno(virtblk_result(vbr->status));
+out:
+ blk_mq_free_request(req);
+ return err;
+}
+
+static int virtblk_parse_zone(struct virtio_blk *vblk,
+ struct virtio_blk_zone_descriptor *entry,
+ unsigned int idx, unsigned int zone_sectors,
+ report_zones_cb cb, void *data)
+{
+ struct blk_zone zone = { };
+
+ if (entry->z_type != VIRTIO_BLK_ZT_SWR &&
+ entry->z_type != VIRTIO_BLK_ZT_SWP &&
+ entry->z_type != VIRTIO_BLK_ZT_CONV) {
+ dev_err(&vblk->vdev->dev, "invalid zone type %#x\n",
+ entry->z_type);
+ return -EINVAL;
+ }
+
+ zone.type = entry->z_type;
+ zone.cond = entry->z_state;
+ zone.len = zone_sectors;
+ zone.capacity = le64_to_cpu(entry->z_cap);
+ zone.start = le64_to_cpu(entry->z_start);
+ if (zone.cond == BLK_ZONE_COND_FULL)
+ zone.wp = zone.start + zone.len;
+ else
+ zone.wp = le64_to_cpu(entry->z_wp);
+
+ return cb(&zone, idx, data);
+}
+
+static int virtblk_report_zones(struct gendisk *disk, sector_t sector,
+ unsigned int nr_zones, report_zones_cb cb,
+ void *data)
+{
+ struct virtio_blk *vblk = disk->private_data;
+ struct virtio_blk_zone_report *report;
+ unsigned int zone_sectors = vblk->zone_sectors;
+ unsigned int nz, i;
+ int ret, zone_idx = 0;
+ size_t buflen;
+
+ if (WARN_ON_ONCE(!vblk->zone_sectors))
+ return -EOPNOTSUPP;
+
+ report = virtblk_alloc_report_buffer(vblk, nr_zones,
+ zone_sectors, &buflen);
+ if (!report)
+ return -ENOMEM;
+
+ while (zone_idx < nr_zones && sector < get_capacity(vblk->disk)) {
+ memset(report, 0, buflen);
+
+ ret = virtblk_submit_zone_report(vblk, (char *)report,
+ buflen, sector);
+ if (ret) {
+ if (ret > 0)
+ ret = -EIO;
+ goto out_free;
+ }
+ nz = min((unsigned int)le64_to_cpu(report->nr_zones), nr_zones);
+ if (!nz)
+ break;
+
+ for (i = 0; i < nz && zone_idx < nr_zones; i++) {
+ ret = virtblk_parse_zone(vblk, &report->zones[i],
+ zone_idx, zone_sectors, cb, data);
+ if (ret)
+ goto out_free;
+ sector = le64_to_cpu(report->zones[i].z_start) + zone_sectors;
+ zone_idx++;
+ }
+ }
+
+ if (zone_idx > 0)
+ ret = zone_idx;
+ else
+ ret = -EINVAL;
+out_free:
+ kvfree(report);
+ return ret;
+}
+
+static void virtblk_revalidate_zones(struct virtio_blk *vblk)
+{
+ u8 model;
+
+ if (!vblk->zone_sectors)
+ return;
+
+ virtio_cread(vblk->vdev, struct virtio_blk_config,
+ zoned.model, &model);
+ if (!blk_revalidate_disk_zones(vblk->disk, NULL))
+ set_capacity_and_notify(vblk->disk, 0);
+}
+
+static int virtblk_probe_zoned_device(struct virtio_device *vdev,
+ struct virtio_blk *vblk,
+ struct request_queue *q)
+{
+ u32 v;
+ u8 model;
+ int ret;
+
+ virtio_cread(vdev, struct virtio_blk_config,
+ zoned.model, &model);
+
+ switch (model) {
+ case VIRTIO_BLK_Z_NONE:
+ return 0;
+ case VIRTIO_BLK_Z_HM:
+ break;
+ case VIRTIO_BLK_Z_HA:
+ /*
+ * Present the host-aware device as a regular drive.
+ * TODO It is possible to add an option to make it appear
+ * in the system as a zoned drive.
+ */
+ return 0;
+ default:
+ dev_err(&vdev->dev, "unsupported zone model %d\n", model);
+ return -EINVAL;
+ }
+
+ dev_dbg(&vdev->dev, "probing host-managed zoned device\n");
+
+ disk_set_zoned(vblk->disk, BLK_ZONED_HM);
+ blk_queue_flag_set(QUEUE_FLAG_ZONE_RESETALL, q);
+
+ virtio_cread(vdev, struct virtio_blk_config,
+ zoned.max_open_zones, &v);
+ disk_set_max_open_zones(vblk->disk, le32_to_cpu(v));
+
+ dev_dbg(&vdev->dev, "max open zones = %u\n", le32_to_cpu(v));
+
+ virtio_cread(vdev, struct virtio_blk_config,
+ zoned.max_active_zones, &v);
+ disk_set_max_active_zones(vblk->disk, le32_to_cpu(v));
+ dev_dbg(&vdev->dev, "max active zones = %u\n", le32_to_cpu(v));
+
+ virtio_cread(vdev, struct virtio_blk_config,
+ zoned.write_granularity, &v);
+ if (!v) {
+ dev_warn(&vdev->dev, "zero write granularity reported\n");
+ return -ENODEV;
+ }
+ blk_queue_physical_block_size(q, le32_to_cpu(v));
+ blk_queue_io_min(q, le32_to_cpu(v));
+
+ dev_dbg(&vdev->dev, "write granularity = %u\n", le32_to_cpu(v));
+
+ /*
+ * virtio ZBD specification doesn't require zones to be a power of
+ * two sectors in size, but the code in this driver expects that.
+ */
+ virtio_cread(vdev, struct virtio_blk_config, zoned.zone_sectors, &v);
+ vblk->zone_sectors = le32_to_cpu(v);
+ if (vblk->zone_sectors == 0 || !is_power_of_2(vblk->zone_sectors)) {
+ dev_err(&vdev->dev,
+ "zoned device with non power of two zone size %u\n",
+ vblk->zone_sectors);
+ return -ENODEV;
+ }
+ dev_dbg(&vdev->dev, "zone sectors = %u\n", vblk->zone_sectors);
+
+ if (virtio_has_feature(vdev, VIRTIO_BLK_F_DISCARD)) {
+ dev_warn(&vblk->vdev->dev,
+ "ignoring negotiated F_DISCARD for zoned device\n");
+ blk_queue_max_discard_sectors(q, 0);
+ }
+
+ ret = blk_revalidate_disk_zones(vblk->disk, NULL);
+ if (!ret) {
+ virtio_cread(vdev, struct virtio_blk_config,
+ zoned.max_append_sectors, &v);
+ if (!v) {
+ dev_warn(&vdev->dev, "zero max_append_sectors reported\n");
+ return -ENODEV;
+ }
+ blk_queue_max_zone_append_sectors(q, le32_to_cpu(v));
+ dev_dbg(&vdev->dev, "max append sectors = %u\n", le32_to_cpu(v));
+ }
+
+ return ret;
+}
+
+static inline bool virtblk_has_zoned_feature(struct virtio_device *vdev)
+{
+ return virtio_has_feature(vdev, VIRTIO_BLK_F_ZONED);
+}
+#else
+
+/*
+ * Zoned block device support is not configured in this kernel.
+ * We only need to define a few symbols to avoid compilation errors.
+ */
+#define virtblk_report_zones NULL
+static inline void virtblk_revalidate_zones(struct virtio_blk *vblk)
+{
+}
+static inline int virtblk_probe_zoned_device(struct virtio_device *vdev,
+ struct virtio_blk *vblk, struct request_queue *q)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline bool virtblk_has_zoned_feature(struct virtio_device *vdev)
+{
+ return false;
+}
+#endif /* CONFIG_BLK_DEV_ZONED */
+
/* return id (s/n) string for *disk to *id_str
*/
static int virtblk_get_id(struct gendisk *disk, char *id_str)
@@ -462,18 +823,24 @@ static int virtblk_get_id(struct gendisk *disk, char *id_str)
struct virtio_blk *vblk = disk->private_data;
struct request_queue *q = vblk->disk->queue;
struct request *req;
+ struct virtblk_req *vbr;
int err;
req = blk_mq_alloc_request(q, REQ_OP_DRV_IN, 0);
if (IS_ERR(req))
return PTR_ERR(req);
+ vbr = blk_mq_rq_to_pdu(req);
+ vbr->in_hdr_len = sizeof(vbr->status);
+ vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_GET_ID);
+ vbr->out_hdr.sector = 0;
+
err = blk_rq_map_kern(q, req, id_str, VIRTIO_BLK_ID_BYTES, GFP_KERNEL);
if (err)
goto out;
blk_execute_rq(req, false);
- err = blk_status_to_errno(virtblk_result(blk_mq_rq_to_pdu(req)));
+ err = blk_status_to_errno(virtblk_result(vbr->status));
out:
blk_mq_free_request(req);
return err;
@@ -524,6 +891,7 @@ static const struct block_device_operations virtblk_fops = {
.owner = THIS_MODULE,
.getgeo = virtblk_getgeo,
.free_disk = virtblk_free_disk,
+ .report_zones = virtblk_report_zones,
};
static int index_to_minor(int index)
@@ -594,6 +962,7 @@ static void virtblk_config_changed_work(struct work_struct *work)
struct virtio_blk *vblk =
container_of(work, struct virtio_blk, config_work);
+ virtblk_revalidate_zones(vblk);
virtblk_update_capacity(vblk, true);
}
@@ -835,36 +1204,15 @@ static void virtblk_map_queues(struct blk_mq_tag_set *set)
}
}
-static void virtblk_complete_batch(struct io_comp_batch *iob)
-{
- struct request *req;
-
- rq_list_for_each(&iob->req_list, req) {
- virtblk_unmap_data(req, blk_mq_rq_to_pdu(req));
- virtblk_cleanup_cmd(req);
- }
- blk_mq_end_request_batch(iob);
-}
-
static int virtblk_poll(struct blk_mq_hw_ctx *hctx, struct io_comp_batch *iob)
{
struct virtio_blk *vblk = hctx->queue->queuedata;
struct virtio_blk_vq *vq = get_virtio_blk_vq(hctx);
- struct virtblk_req *vbr;
unsigned long flags;
- unsigned int len;
int found = 0;
spin_lock_irqsave(&vq->lock, flags);
-
- while ((vbr = virtqueue_get_buf(vq->vq, &len)) != NULL) {
- struct request *req = blk_mq_rq_from_pdu(vbr);
-
- found++;
- if (!blk_mq_add_to_batch(req, iob, vbr->status,
- virtblk_complete_batch))
- blk_mq_complete_request(req);
- }
+ found = virtblk_handle_req(vq, iob);
if (found)
blk_mq_start_stopped_hw_queues(vblk->disk->queue, true);
@@ -1150,6 +1498,15 @@ static int virtblk_probe(struct virtio_device *vdev)
virtblk_update_capacity(vblk, false);
virtio_device_ready(vdev);
+ if (virtblk_has_zoned_feature(vdev)) {
+ err = virtblk_probe_zoned_device(vdev, vblk, q);
+ if (err)
+ goto out_cleanup_disk;
+ }
+
+ dev_info(&vdev->dev, "blk config size: %zu\n",
+ sizeof(struct virtio_blk_config));
+
err = device_add_disk(&vdev->dev, vblk->disk, virtblk_attr_groups);
if (err)
goto out_cleanup_disk;
@@ -1251,6 +1608,9 @@ static unsigned int features[] = {
VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_CONFIG_WCE,
VIRTIO_BLK_F_MQ, VIRTIO_BLK_F_DISCARD, VIRTIO_BLK_F_WRITE_ZEROES,
VIRTIO_BLK_F_SECURE_ERASE,
+#ifdef CONFIG_BLK_DEV_ZONED
+ VIRTIO_BLK_F_ZONED,
+#endif /* CONFIG_BLK_DEV_ZONED */
};
static struct virtio_driver virtio_blk = {
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index bd8ae4822dc3..aa490da3cef2 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -190,7 +190,7 @@ static inline bool valid_io_request(struct zram *zram,
end = start + (size >> SECTOR_SHIFT);
bound = zram->disksize >> SECTOR_SHIFT;
- /* out of range range */
+ /* out of range */
if (unlikely(start >= bound || end > bound || start > end))
return false;
@@ -1138,7 +1138,7 @@ static ssize_t recomp_algorithm_store(struct device *dev,
while (*args) {
args = next_arg(args, &param, &val);
- if (!*val)
+ if (!val || !*val)
return -EINVAL;
if (!strcmp(param, "algo")) {
@@ -1448,10 +1448,6 @@ static int __zram_bvec_read(struct zram *zram, struct page *page, u32 index,
/* Slot should be unlocked before the function call */
zram_slot_unlock(zram, index);
- /* A null bio means rw_page was used, we must fallback to bio */
- if (!bio)
- return -EOPNOTSUPP;
-
ret = zram_bvec_read_from_bdev(zram, page, index, bio,
partial_io);
}
@@ -1817,7 +1813,7 @@ static ssize_t recompress_store(struct device *dev,
while (*args) {
args = next_arg(args, &param, &val);
- if (!*val)
+ if (!val || !*val)
return -EINVAL;
if (!strcmp(param, "type")) {
@@ -2074,61 +2070,6 @@ static void zram_slot_free_notify(struct block_device *bdev,
zram_slot_unlock(zram, index);
}
-static int zram_rw_page(struct block_device *bdev, sector_t sector,
- struct page *page, enum req_op op)
-{
- int offset, ret;
- u32 index;
- struct zram *zram;
- struct bio_vec bv;
- unsigned long start_time;
-
- if (PageTransHuge(page))
- return -ENOTSUPP;
- zram = bdev->bd_disk->private_data;
-
- if (!valid_io_request(zram, sector, PAGE_SIZE)) {
- atomic64_inc(&zram->stats.invalid_io);
- ret = -EINVAL;
- goto out;
- }
-
- index = sector >> SECTORS_PER_PAGE_SHIFT;
- offset = (sector & (SECTORS_PER_PAGE - 1)) << SECTOR_SHIFT;
-
- bv.bv_page = page;
- bv.bv_len = PAGE_SIZE;
- bv.bv_offset = 0;
-
- start_time = bdev_start_io_acct(bdev->bd_disk->part0,
- SECTORS_PER_PAGE, op, jiffies);
- ret = zram_bvec_rw(zram, &bv, index, offset, op, NULL);
- bdev_end_io_acct(bdev->bd_disk->part0, op, start_time);
-out:
- /*
- * If I/O fails, just return error(ie, non-zero) without
- * calling page_endio.
- * It causes resubmit the I/O with bio request by upper functions
- * of rw_page(e.g., swap_readpage, __swap_writepage) and
- * bio->bi_end_io does things to handle the error
- * (e.g., SetPageError, set_page_dirty and extra works).
- */
- if (unlikely(ret < 0))
- return ret;
-
- switch (ret) {
- case 0:
- page_endio(page, op_is_write(op), 0);
- break;
- case 1:
- ret = 0;
- break;
- default:
- WARN_ON(1);
- }
- return ret;
-}
-
static void zram_destroy_comps(struct zram *zram)
{
u32 prio;
@@ -2283,7 +2224,6 @@ static const struct block_device_operations zram_devops = {
.open = zram_open,
.submit_bio = zram_submit_bio,
.swap_slot_free_notify = zram_slot_free_notify,
- .rw_page = zram_rw_page,
.owner = THIS_MODULE
};
@@ -2378,10 +2318,11 @@ static int zram_add(void)
zram->disk->private_data = zram;
snprintf(zram->disk->disk_name, 16, "zram%d", device_id);
- /* Actual capacity set using syfs (/sys/block/zram<id>/disksize */
+ /* Actual capacity set using sysfs (/sys/block/zram<id>/disksize */
set_capacity(zram->disk, 0);
/* zram devices sort of resembles non-rotational disks */
blk_queue_flag_set(QUEUE_FLAG_NONROT, zram->disk->queue);
+ blk_queue_flag_set(QUEUE_FLAG_SYNCHRONOUS, zram->disk->queue);
blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, zram->disk->queue);
/*
diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c
index 774f307844b4..36cb091a33b4 100644
--- a/drivers/bus/fsl-mc/fsl-mc-bus.c
+++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
@@ -124,9 +124,9 @@ out:
/*
* fsl_mc_bus_uevent - callback invoked when a device is added
*/
-static int fsl_mc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int fsl_mc_bus_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
+ const struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
if (add_uevent_var(env, "MODALIAS=fsl-mc:v%08Xd%s",
mc_dev->obj_desc.vendor,
diff --git a/drivers/bus/imx-weim.c b/drivers/bus/imx-weim.c
index 828c66bbaa67..2a6b4f676458 100644
--- a/drivers/bus/imx-weim.c
+++ b/drivers/bus/imx-weim.c
@@ -263,7 +263,6 @@ static int weim_parse_dt(struct platform_device *pdev)
static int weim_probe(struct platform_device *pdev)
{
struct weim_priv *priv;
- struct resource *res;
struct clk *clk;
void __iomem *base;
int ret;
@@ -273,8 +272,7 @@ static int weim_probe(struct platform_device *pdev)
return -ENOMEM;
/* get the resource */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- base = devm_ioremap_resource(&pdev->dev, res);
+ base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(base))
return PTR_ERR(base);
diff --git a/drivers/bus/mhi/Makefile b/drivers/bus/mhi/Makefile
index 46981331b38f..354204b0ef3a 100644
--- a/drivers/bus/mhi/Makefile
+++ b/drivers/bus/mhi/Makefile
@@ -1,5 +1,5 @@
# Host MHI stack
-obj-y += host/
+obj-$(CONFIG_MHI_BUS) += host/
# Endpoint MHI stack
-obj-y += ep/
+obj-$(CONFIG_MHI_BUS_EP) += ep/
diff --git a/drivers/bus/mhi/ep/main.c b/drivers/bus/mhi/ep/main.c
index 1dc8a3557a46..a6a48e515478 100644
--- a/drivers/bus/mhi/ep/main.c
+++ b/drivers/bus/mhi/ep/main.c
@@ -123,6 +123,13 @@ static int mhi_ep_process_cmd_ring(struct mhi_ep_ring *ring, struct mhi_ring_ele
int ret;
ch_id = MHI_TRE_GET_CMD_CHID(el);
+
+ /* Check if the channel is supported by the controller */
+ if ((ch_id >= mhi_cntrl->max_chan) || !mhi_cntrl->mhi_chan[ch_id].name) {
+ dev_err(dev, "Channel (%u) not supported!\n", ch_id);
+ return -ENODEV;
+ }
+
mhi_chan = &mhi_cntrl->mhi_chan[ch_id];
ch_ring = &mhi_cntrl->mhi_chan[ch_id].ring;
@@ -196,9 +203,11 @@ static int mhi_ep_process_cmd_ring(struct mhi_ep_ring *ring, struct mhi_ring_ele
mhi_ep_mmio_disable_chdb(mhi_cntrl, ch_id);
/* Send channel disconnect status to client drivers */
- result.transaction_status = -ENOTCONN;
- result.bytes_xferd = 0;
- mhi_chan->xfer_cb(mhi_chan->mhi_dev, &result);
+ if (mhi_chan->xfer_cb) {
+ result.transaction_status = -ENOTCONN;
+ result.bytes_xferd = 0;
+ mhi_chan->xfer_cb(mhi_chan->mhi_dev, &result);
+ }
/* Set channel state to STOP */
mhi_chan->state = MHI_CH_STATE_STOP;
@@ -217,7 +226,7 @@ static int mhi_ep_process_cmd_ring(struct mhi_ep_ring *ring, struct mhi_ring_ele
mutex_unlock(&mhi_chan->lock);
break;
case MHI_PKT_TYPE_RESET_CHAN_CMD:
- dev_dbg(dev, "Received STOP command for channel (%u)\n", ch_id);
+ dev_dbg(dev, "Received RESET command for channel (%u)\n", ch_id);
if (!ch_ring->started) {
dev_err(dev, "Channel (%u) not opened\n", ch_id);
return -ENODEV;
@@ -228,9 +237,11 @@ static int mhi_ep_process_cmd_ring(struct mhi_ep_ring *ring, struct mhi_ring_ele
mhi_ep_ring_reset(mhi_cntrl, ch_ring);
/* Send channel disconnect status to client driver */
- result.transaction_status = -ENOTCONN;
- result.bytes_xferd = 0;
- mhi_chan->xfer_cb(mhi_chan->mhi_dev, &result);
+ if (mhi_chan->xfer_cb) {
+ result.transaction_status = -ENOTCONN;
+ result.bytes_xferd = 0;
+ mhi_chan->xfer_cb(mhi_chan->mhi_dev, &result);
+ }
/* Set channel state to DISABLED */
mhi_chan->state = MHI_CH_STATE_DISABLED;
@@ -719,24 +730,37 @@ static void mhi_ep_ch_ring_worker(struct work_struct *work)
list_del(&itr->node);
ring = itr->ring;
+ chan = &mhi_cntrl->mhi_chan[ring->ch_id];
+ mutex_lock(&chan->lock);
+
+ /*
+ * The ring could've stopped while we waited to grab the (chan->lock), so do
+ * a sanity check before going further.
+ */
+ if (!ring->started) {
+ mutex_unlock(&chan->lock);
+ kfree(itr);
+ continue;
+ }
+
/* Update the write offset for the ring */
ret = mhi_ep_update_wr_offset(ring);
if (ret) {
dev_err(dev, "Error updating write offset for ring\n");
+ mutex_unlock(&chan->lock);
kfree(itr);
continue;
}
/* Sanity check to make sure there are elements in the ring */
if (ring->rd_offset == ring->wr_offset) {
+ mutex_unlock(&chan->lock);
kfree(itr);
continue;
}
el = &ring->ring_cache[ring->rd_offset];
- chan = &mhi_cntrl->mhi_chan[ring->ch_id];
- mutex_lock(&chan->lock);
dev_dbg(dev, "Processing the ring for channel (%u)\n", ring->ch_id);
ret = mhi_ep_process_ch_ring(ring, el);
if (ret) {
@@ -973,44 +997,25 @@ static void mhi_ep_abort_transfer(struct mhi_ep_cntrl *mhi_cntrl)
static void mhi_ep_reset_worker(struct work_struct *work)
{
struct mhi_ep_cntrl *mhi_cntrl = container_of(work, struct mhi_ep_cntrl, reset_work);
- struct device *dev = &mhi_cntrl->mhi_dev->dev;
enum mhi_state cur_state;
- int ret;
- mhi_ep_abort_transfer(mhi_cntrl);
+ mhi_ep_power_down(mhi_cntrl);
+
+ mutex_lock(&mhi_cntrl->state_lock);
- spin_lock_bh(&mhi_cntrl->state_lock);
/* Reset MMIO to signal host that the MHI_RESET is completed in endpoint */
mhi_ep_mmio_reset(mhi_cntrl);
cur_state = mhi_cntrl->mhi_state;
- spin_unlock_bh(&mhi_cntrl->state_lock);
/*
* Only proceed further if the reset is due to SYS_ERR. The host will
* issue reset during shutdown also and we don't need to do re-init in
* that case.
*/
- if (cur_state == MHI_STATE_SYS_ERR) {
- mhi_ep_mmio_init(mhi_cntrl);
-
- /* Set AMSS EE before signaling ready state */
- mhi_ep_mmio_set_env(mhi_cntrl, MHI_EE_AMSS);
-
- /* All set, notify the host that we are ready */
- ret = mhi_ep_set_ready_state(mhi_cntrl);
- if (ret)
- return;
-
- dev_dbg(dev, "READY state notification sent to the host\n");
-
- ret = mhi_ep_enable(mhi_cntrl);
- if (ret) {
- dev_err(dev, "Failed to enable MHI endpoint: %d\n", ret);
- return;
- }
+ if (cur_state == MHI_STATE_SYS_ERR)
+ mhi_ep_power_up(mhi_cntrl);
- enable_irq(mhi_cntrl->irq);
- }
+ mutex_unlock(&mhi_cntrl->state_lock);
}
/*
@@ -1089,11 +1094,11 @@ EXPORT_SYMBOL_GPL(mhi_ep_power_up);
void mhi_ep_power_down(struct mhi_ep_cntrl *mhi_cntrl)
{
- if (mhi_cntrl->enabled)
+ if (mhi_cntrl->enabled) {
mhi_ep_abort_transfer(mhi_cntrl);
-
- kfree(mhi_cntrl->mhi_event);
- disable_irq(mhi_cntrl->irq);
+ kfree(mhi_cntrl->mhi_event);
+ disable_irq(mhi_cntrl->irq);
+ }
}
EXPORT_SYMBOL_GPL(mhi_ep_power_down);
@@ -1119,6 +1124,7 @@ void mhi_ep_suspend_channels(struct mhi_ep_cntrl *mhi_cntrl)
dev_dbg(&mhi_chan->mhi_dev->dev, "Suspending channel\n");
/* Set channel state to SUSPENDED */
+ mhi_chan->state = MHI_CH_STATE_SUSPENDED;
tmp &= ~CHAN_CTX_CHSTATE_MASK;
tmp |= FIELD_PREP(CHAN_CTX_CHSTATE_MASK, MHI_CH_STATE_SUSPENDED);
mhi_cntrl->ch_ctx_cache[i].chcfg = cpu_to_le32(tmp);
@@ -1148,6 +1154,7 @@ void mhi_ep_resume_channels(struct mhi_ep_cntrl *mhi_cntrl)
dev_dbg(&mhi_chan->mhi_dev->dev, "Resuming channel\n");
/* Set channel state to RUNNING */
+ mhi_chan->state = MHI_CH_STATE_RUNNING;
tmp &= ~CHAN_CTX_CHSTATE_MASK;
tmp |= FIELD_PREP(CHAN_CTX_CHSTATE_MASK, MHI_CH_STATE_RUNNING);
mhi_cntrl->ch_ctx_cache[i].chcfg = cpu_to_le32(tmp);
@@ -1381,8 +1388,8 @@ int mhi_ep_register_controller(struct mhi_ep_cntrl *mhi_cntrl,
INIT_LIST_HEAD(&mhi_cntrl->st_transition_list);
INIT_LIST_HEAD(&mhi_cntrl->ch_db_list);
- spin_lock_init(&mhi_cntrl->state_lock);
spin_lock_init(&mhi_cntrl->list_lock);
+ mutex_init(&mhi_cntrl->state_lock);
mutex_init(&mhi_cntrl->event_lock);
/* Set MHI version and AMSS EE before enumeration */
@@ -1543,9 +1550,9 @@ void mhi_ep_driver_unregister(struct mhi_ep_driver *mhi_drv)
}
EXPORT_SYMBOL_GPL(mhi_ep_driver_unregister);
-static int mhi_ep_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int mhi_ep_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct mhi_ep_device *mhi_dev = to_mhi_ep_device(dev);
+ const struct mhi_ep_device *mhi_dev = to_mhi_ep_device(dev);
return add_uevent_var(env, "MODALIAS=" MHI_EP_DEVICE_MODALIAS_FMT,
mhi_dev->name);
diff --git a/drivers/bus/mhi/ep/sm.c b/drivers/bus/mhi/ep/sm.c
index 3655c19e23c7..fd200b2ac0bb 100644
--- a/drivers/bus/mhi/ep/sm.c
+++ b/drivers/bus/mhi/ep/sm.c
@@ -63,24 +63,23 @@ int mhi_ep_set_m0_state(struct mhi_ep_cntrl *mhi_cntrl)
int ret;
/* If MHI is in M3, resume suspended channels */
- spin_lock_bh(&mhi_cntrl->state_lock);
+ mutex_lock(&mhi_cntrl->state_lock);
+
old_state = mhi_cntrl->mhi_state;
if (old_state == MHI_STATE_M3)
mhi_ep_resume_channels(mhi_cntrl);
ret = mhi_ep_set_mhi_state(mhi_cntrl, MHI_STATE_M0);
- spin_unlock_bh(&mhi_cntrl->state_lock);
-
if (ret) {
mhi_ep_handle_syserr(mhi_cntrl);
- return ret;
+ goto err_unlock;
}
/* Signal host that the device moved to M0 */
ret = mhi_ep_send_state_change_event(mhi_cntrl, MHI_STATE_M0);
if (ret) {
dev_err(dev, "Failed sending M0 state change event\n");
- return ret;
+ goto err_unlock;
}
if (old_state == MHI_STATE_READY) {
@@ -88,11 +87,14 @@ int mhi_ep_set_m0_state(struct mhi_ep_cntrl *mhi_cntrl)
ret = mhi_ep_send_ee_event(mhi_cntrl, MHI_EE_AMSS);
if (ret) {
dev_err(dev, "Failed sending AMSS EE event\n");
- return ret;
+ goto err_unlock;
}
}
- return 0;
+err_unlock:
+ mutex_unlock(&mhi_cntrl->state_lock);
+
+ return ret;
}
int mhi_ep_set_m3_state(struct mhi_ep_cntrl *mhi_cntrl)
@@ -100,13 +102,12 @@ int mhi_ep_set_m3_state(struct mhi_ep_cntrl *mhi_cntrl)
struct device *dev = &mhi_cntrl->mhi_dev->dev;
int ret;
- spin_lock_bh(&mhi_cntrl->state_lock);
- ret = mhi_ep_set_mhi_state(mhi_cntrl, MHI_STATE_M3);
- spin_unlock_bh(&mhi_cntrl->state_lock);
+ mutex_lock(&mhi_cntrl->state_lock);
+ ret = mhi_ep_set_mhi_state(mhi_cntrl, MHI_STATE_M3);
if (ret) {
mhi_ep_handle_syserr(mhi_cntrl);
- return ret;
+ goto err_unlock;
}
mhi_ep_suspend_channels(mhi_cntrl);
@@ -115,10 +116,13 @@ int mhi_ep_set_m3_state(struct mhi_ep_cntrl *mhi_cntrl)
ret = mhi_ep_send_state_change_event(mhi_cntrl, MHI_STATE_M3);
if (ret) {
dev_err(dev, "Failed sending M3 state change event\n");
- return ret;
+ goto err_unlock;
}
- return 0;
+err_unlock:
+ mutex_unlock(&mhi_cntrl->state_lock);
+
+ return ret;
}
int mhi_ep_set_ready_state(struct mhi_ep_cntrl *mhi_cntrl)
@@ -127,22 +131,24 @@ int mhi_ep_set_ready_state(struct mhi_ep_cntrl *mhi_cntrl)
enum mhi_state mhi_state;
int ret, is_ready;
- spin_lock_bh(&mhi_cntrl->state_lock);
+ mutex_lock(&mhi_cntrl->state_lock);
+
/* Ensure that the MHISTATUS is set to RESET by host */
mhi_state = mhi_ep_mmio_masked_read(mhi_cntrl, EP_MHISTATUS, MHISTATUS_MHISTATE_MASK);
is_ready = mhi_ep_mmio_masked_read(mhi_cntrl, EP_MHISTATUS, MHISTATUS_READY_MASK);
if (mhi_state != MHI_STATE_RESET || is_ready) {
dev_err(dev, "READY state transition failed. MHI host not in RESET state\n");
- spin_unlock_bh(&mhi_cntrl->state_lock);
- return -EIO;
+ ret = -EIO;
+ goto err_unlock;
}
ret = mhi_ep_set_mhi_state(mhi_cntrl, MHI_STATE_READY);
- spin_unlock_bh(&mhi_cntrl->state_lock);
-
if (ret)
mhi_ep_handle_syserr(mhi_cntrl);
+err_unlock:
+ mutex_unlock(&mhi_cntrl->state_lock);
+
return ret;
}
diff --git a/drivers/bus/mhi/host/init.c b/drivers/bus/mhi/host/init.c
index bf672de35131..3d779ee6396d 100644
--- a/drivers/bus/mhi/host/init.c
+++ b/drivers/bus/mhi/host/init.c
@@ -1395,9 +1395,9 @@ void mhi_driver_unregister(struct mhi_driver *mhi_drv)
}
EXPORT_SYMBOL_GPL(mhi_driver_unregister);
-static int mhi_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int mhi_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct mhi_device *mhi_dev = to_mhi_device(dev);
+ const struct mhi_device *mhi_dev = to_mhi_device(dev);
return add_uevent_var(env, "MODALIAS=" MHI_DEVICE_MODALIAS_FMT,
mhi_dev->name);
@@ -1449,4 +1449,4 @@ postcore_initcall(mhi_init);
module_exit(mhi_exit);
MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("MHI Host Interface");
+MODULE_DESCRIPTION("Modem Host Interface");
diff --git a/drivers/bus/mips_cdmm.c b/drivers/bus/mips_cdmm.c
index fca0d0669aa9..554e1992edd4 100644
--- a/drivers/bus/mips_cdmm.c
+++ b/drivers/bus/mips_cdmm.c
@@ -67,9 +67,9 @@ static int mips_cdmm_match(struct device *dev, struct device_driver *drv)
return mips_cdmm_lookup(cdrv->id_table, cdev) != NULL;
}
-static int mips_cdmm_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int mips_cdmm_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct mips_cdmm_device *cdev = to_mips_cdmm_device(dev);
+ const struct mips_cdmm_device *cdev = to_mips_cdmm_device(dev);
int retval = 0;
retval = add_uevent_var(env, "CDMM_CPU=%u", cdev->cpu);
diff --git a/drivers/bus/simple-pm-bus.c b/drivers/bus/simple-pm-bus.c
index 6b8d6257ed8a..7afe1947e1c0 100644
--- a/drivers/bus/simple-pm-bus.c
+++ b/drivers/bus/simple-pm-bus.c
@@ -8,17 +8,24 @@
* for more details.
*/
+#include <linux/clk.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+struct simple_pm_bus {
+ struct clk_bulk_data *clks;
+ int num_clks;
+};
+
static int simple_pm_bus_probe(struct platform_device *pdev)
{
const struct device *dev = &pdev->dev;
const struct of_dev_auxdata *lookup = dev_get_platdata(dev);
struct device_node *np = dev->of_node;
const struct of_device_id *match;
+ struct simple_pm_bus *bus;
/*
* Allow user to use driver_override to bind this driver to a
@@ -44,6 +51,16 @@ static int simple_pm_bus_probe(struct platform_device *pdev)
return -ENODEV;
}
+ bus = devm_kzalloc(&pdev->dev, sizeof(*bus), GFP_KERNEL);
+ if (!bus)
+ return -ENOMEM;
+
+ bus->num_clks = devm_clk_bulk_get_all(&pdev->dev, &bus->clks);
+ if (bus->num_clks < 0)
+ return dev_err_probe(&pdev->dev, bus->num_clks, "failed to get clocks\n");
+
+ dev_set_drvdata(&pdev->dev, bus);
+
dev_dbg(&pdev->dev, "%s\n", __func__);
pm_runtime_enable(&pdev->dev);
@@ -67,6 +84,34 @@ static int simple_pm_bus_remove(struct platform_device *pdev)
return 0;
}
+static int simple_pm_bus_runtime_suspend(struct device *dev)
+{
+ struct simple_pm_bus *bus = dev_get_drvdata(dev);
+
+ clk_bulk_disable_unprepare(bus->num_clks, bus->clks);
+
+ return 0;
+}
+
+static int simple_pm_bus_runtime_resume(struct device *dev)
+{
+ struct simple_pm_bus *bus = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_bulk_prepare_enable(bus->num_clks, bus->clks);
+ if (ret) {
+ dev_err(dev, "failed to enable clocks: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops simple_pm_bus_pm_ops = {
+ RUNTIME_PM_OPS(simple_pm_bus_runtime_suspend, simple_pm_bus_runtime_resume, NULL)
+ NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
+};
+
#define ONLY_BUS ((void *) 1) /* Match if the device is only a bus. */
static const struct of_device_id simple_pm_bus_of_match[] = {
@@ -85,6 +130,7 @@ static struct platform_driver simple_pm_bus_driver = {
.driver = {
.name = "simple-pm-bus",
.of_match_table = simple_pm_bus_of_match,
+ .pm = pm_ptr(&simple_pm_bus_pm_ops),
},
};
diff --git a/drivers/bus/sunxi-rsb.c b/drivers/bus/sunxi-rsb.c
index 226e87b85116..696c0aefb0ca 100644
--- a/drivers/bus/sunxi-rsb.c
+++ b/drivers/bus/sunxi-rsb.c
@@ -172,12 +172,17 @@ static void sunxi_rsb_device_remove(struct device *dev)
drv->remove(to_sunxi_rsb_device(dev));
}
+static int sunxi_rsb_device_modalias(const struct device *dev, struct kobj_uevent_env *env)
+{
+ return of_device_uevent_modalias(dev, env);
+}
+
static struct bus_type sunxi_rsb_bus = {
.name = RSB_CTRL_NAME,
.match = sunxi_rsb_device_match,
.probe = sunxi_rsb_device_probe,
.remove = sunxi_rsb_device_remove,
- .uevent = of_device_uevent_modalias,
+ .uevent = sunxi_rsb_device_modalias,
};
static void sunxi_rsb_dev_release(struct device *dev)
diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c
index 36203d3fa6ea..69314532f38c 100644
--- a/drivers/char/applicom.c
+++ b/drivers/char/applicom.c
@@ -197,8 +197,10 @@ static int __init applicom_init(void)
if (!pci_match_id(applicom_pci_tbl, dev))
continue;
- if (pci_enable_device(dev))
+ if (pci_enable_device(dev)) {
+ pci_dev_put(dev);
return -EIO;
+ }
RamIO = ioremap(pci_resource_start(dev, 0), LEN_RAM_IO);
@@ -207,6 +209,7 @@ static int __init applicom_init(void)
"space at 0x%llx\n",
(unsigned long long)pci_resource_start(dev, 0));
pci_disable_device(dev);
+ pci_dev_put(dev);
return -EIO;
}
diff --git a/drivers/char/ipmi/ipmi_ipmb.c b/drivers/char/ipmi/ipmi_ipmb.c
index 7c1aee5e11b7..3f1c9f1573e7 100644
--- a/drivers/char/ipmi/ipmi_ipmb.c
+++ b/drivers/char/ipmi/ipmi_ipmb.c
@@ -27,7 +27,7 @@ MODULE_PARM_DESC(bmcaddr, "Address to use for BMC.");
static unsigned int retry_time_ms = 250;
module_param(retry_time_ms, uint, 0644);
-MODULE_PARM_DESC(max_retries, "Timeout time between retries, in milliseconds.");
+MODULE_PARM_DESC(retry_time_ms, "Timeout time between retries, in milliseconds.");
static unsigned int max_retries = 1;
module_param(max_retries, uint, 0644);
diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
index 4bfd1e306616..a5ddebb1edea 100644
--- a/drivers/char/ipmi/ipmi_ssif.c
+++ b/drivers/char/ipmi/ipmi_ssif.c
@@ -74,7 +74,8 @@
/*
* Timer values
*/
-#define SSIF_MSG_USEC 60000 /* 60ms between message tries. */
+#define SSIF_MSG_USEC 60000 /* 60ms between message tries (T3). */
+#define SSIF_REQ_RETRY_USEC 60000 /* 60ms between send retries (T6). */
#define SSIF_MSG_PART_USEC 5000 /* 5ms for a message part */
/* How many times to we retry sending/receiving the message. */
@@ -82,7 +83,9 @@
#define SSIF_RECV_RETRIES 250
#define SSIF_MSG_MSEC (SSIF_MSG_USEC / 1000)
+#define SSIF_REQ_RETRY_MSEC (SSIF_REQ_RETRY_USEC / 1000)
#define SSIF_MSG_JIFFIES ((SSIF_MSG_USEC * 1000) / TICK_NSEC)
+#define SSIF_REQ_RETRY_JIFFIES ((SSIF_REQ_RETRY_USEC * 1000) / TICK_NSEC)
#define SSIF_MSG_PART_JIFFIES ((SSIF_MSG_PART_USEC * 1000) / TICK_NSEC)
/*
@@ -92,7 +95,7 @@
#define SSIF_WATCH_WATCHDOG_TIMEOUT msecs_to_jiffies(250)
enum ssif_intf_state {
- SSIF_NORMAL,
+ SSIF_IDLE,
SSIF_GETTING_FLAGS,
SSIF_GETTING_EVENTS,
SSIF_CLEARING_FLAGS,
@@ -100,8 +103,8 @@ enum ssif_intf_state {
/* FIXME - add watchdog stuff. */
};
-#define SSIF_IDLE(ssif) ((ssif)->ssif_state == SSIF_NORMAL \
- && (ssif)->curr_msg == NULL)
+#define IS_SSIF_IDLE(ssif) ((ssif)->ssif_state == SSIF_IDLE \
+ && (ssif)->curr_msg == NULL)
/*
* Indexes into stats[] in ssif_info below.
@@ -229,6 +232,9 @@ struct ssif_info {
bool got_alert;
bool waiting_alert;
+ /* Used to inform the timeout that it should do a resend. */
+ bool do_resend;
+
/*
* If set to true, this will request events the next time the
* state machine is idle.
@@ -241,12 +247,6 @@ struct ssif_info {
*/
bool req_flags;
- /*
- * Used to perform timer operations when run-to-completion
- * mode is on. This is a countdown timer.
- */
- int rtc_us_timer;
-
/* Used for sending/receiving data. +1 for the length. */
unsigned char data[IPMI_MAX_MSG_LENGTH + 1];
unsigned int data_len;
@@ -348,9 +348,9 @@ static void return_hosed_msg(struct ssif_info *ssif_info,
/*
* Must be called with the message lock held. This will release the
- * message lock. Note that the caller will check SSIF_IDLE and start a
- * new operation, so there is no need to check for new messages to
- * start in here.
+ * message lock. Note that the caller will check IS_SSIF_IDLE and
+ * start a new operation, so there is no need to check for new
+ * messages to start in here.
*/
static void start_clear_flags(struct ssif_info *ssif_info, unsigned long *flags)
{
@@ -367,7 +367,7 @@ static void start_clear_flags(struct ssif_info *ssif_info, unsigned long *flags)
if (start_send(ssif_info, msg, 3) != 0) {
/* Error, just go to normal state. */
- ssif_info->ssif_state = SSIF_NORMAL;
+ ssif_info->ssif_state = SSIF_IDLE;
}
}
@@ -382,7 +382,7 @@ static void start_flag_fetch(struct ssif_info *ssif_info, unsigned long *flags)
mb[0] = (IPMI_NETFN_APP_REQUEST << 2);
mb[1] = IPMI_GET_MSG_FLAGS_CMD;
if (start_send(ssif_info, mb, 2) != 0)
- ssif_info->ssif_state = SSIF_NORMAL;
+ ssif_info->ssif_state = SSIF_IDLE;
}
static void check_start_send(struct ssif_info *ssif_info, unsigned long *flags,
@@ -393,7 +393,7 @@ static void check_start_send(struct ssif_info *ssif_info, unsigned long *flags,
flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
ssif_info->curr_msg = NULL;
- ssif_info->ssif_state = SSIF_NORMAL;
+ ssif_info->ssif_state = SSIF_IDLE;
ipmi_ssif_unlock_cond(ssif_info, flags);
ipmi_free_smi_msg(msg);
}
@@ -407,7 +407,7 @@ static void start_event_fetch(struct ssif_info *ssif_info, unsigned long *flags)
msg = ipmi_alloc_smi_msg();
if (!msg) {
- ssif_info->ssif_state = SSIF_NORMAL;
+ ssif_info->ssif_state = SSIF_IDLE;
ipmi_ssif_unlock_cond(ssif_info, flags);
return;
}
@@ -430,7 +430,7 @@ static void start_recv_msg_fetch(struct ssif_info *ssif_info,
msg = ipmi_alloc_smi_msg();
if (!msg) {
- ssif_info->ssif_state = SSIF_NORMAL;
+ ssif_info->ssif_state = SSIF_IDLE;
ipmi_ssif_unlock_cond(ssif_info, flags);
return;
}
@@ -448,9 +448,9 @@ static void start_recv_msg_fetch(struct ssif_info *ssif_info,
/*
* Must be called with the message lock held. This will release the
- * message lock. Note that the caller will check SSIF_IDLE and start a
- * new operation, so there is no need to check for new messages to
- * start in here.
+ * message lock. Note that the caller will check IS_SSIF_IDLE and
+ * start a new operation, so there is no need to check for new
+ * messages to start in here.
*/
static void handle_flags(struct ssif_info *ssif_info, unsigned long *flags)
{
@@ -466,7 +466,7 @@ static void handle_flags(struct ssif_info *ssif_info, unsigned long *flags)
/* Events available. */
start_event_fetch(ssif_info, flags);
else {
- ssif_info->ssif_state = SSIF_NORMAL;
+ ssif_info->ssif_state = SSIF_IDLE;
ipmi_ssif_unlock_cond(ssif_info, flags);
}
}
@@ -530,7 +530,6 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
static void start_get(struct ssif_info *ssif_info)
{
- ssif_info->rtc_us_timer = 0;
ssif_info->multi_pos = 0;
ssif_i2c_send(ssif_info, msg_done_handler, I2C_SMBUS_READ,
@@ -538,22 +537,28 @@ static void start_get(struct ssif_info *ssif_info)
ssif_info->recv, I2C_SMBUS_BLOCK_DATA);
}
+static void start_resend(struct ssif_info *ssif_info);
+
static void retry_timeout(struct timer_list *t)
{
struct ssif_info *ssif_info = from_timer(ssif_info, t, retry_timer);
unsigned long oflags, *flags;
- bool waiting;
+ bool waiting, resend;
if (ssif_info->stopping)
return;
flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
+ resend = ssif_info->do_resend;
+ ssif_info->do_resend = false;
waiting = ssif_info->waiting_alert;
ssif_info->waiting_alert = false;
ipmi_ssif_unlock_cond(ssif_info, flags);
if (waiting)
start_get(ssif_info);
+ if (resend)
+ start_resend(ssif_info);
}
static void watch_timeout(struct timer_list *t)
@@ -568,7 +573,7 @@ static void watch_timeout(struct timer_list *t)
if (ssif_info->watch_timeout) {
mod_timer(&ssif_info->watch_timer,
jiffies + ssif_info->watch_timeout);
- if (SSIF_IDLE(ssif_info)) {
+ if (IS_SSIF_IDLE(ssif_info)) {
start_flag_fetch(ssif_info, flags); /* Releases lock */
return;
}
@@ -602,8 +607,6 @@ static void ssif_alert(struct i2c_client *client, enum i2c_alert_protocol type,
start_get(ssif_info);
}
-static int start_resend(struct ssif_info *ssif_info);
-
static void msg_done_handler(struct ssif_info *ssif_info, int result,
unsigned char *data, unsigned int len)
{
@@ -622,7 +625,6 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
ssif_info->waiting_alert = true;
- ssif_info->rtc_us_timer = SSIF_MSG_USEC;
if (!ssif_info->stopping)
mod_timer(&ssif_info->retry_timer,
jiffies + SSIF_MSG_JIFFIES);
@@ -756,7 +758,7 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
}
switch (ssif_info->ssif_state) {
- case SSIF_NORMAL:
+ case SSIF_IDLE:
ipmi_ssif_unlock_cond(ssif_info, flags);
if (!msg)
break;
@@ -774,7 +776,7 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
* Error fetching flags, or invalid length,
* just give up for now.
*/
- ssif_info->ssif_state = SSIF_NORMAL;
+ ssif_info->ssif_state = SSIF_IDLE;
ipmi_ssif_unlock_cond(ssif_info, flags);
dev_warn(&ssif_info->client->dev,
"Error getting flags: %d %d, %x\n",
@@ -809,7 +811,7 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
"Invalid response clearing flags: %x %x\n",
data[0], data[1]);
}
- ssif_info->ssif_state = SSIF_NORMAL;
+ ssif_info->ssif_state = SSIF_IDLE;
ipmi_ssif_unlock_cond(ssif_info, flags);
break;
@@ -887,7 +889,7 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
}
flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
- if (SSIF_IDLE(ssif_info) && !ssif_info->stopping) {
+ if (IS_SSIF_IDLE(ssif_info) && !ssif_info->stopping) {
if (ssif_info->req_events)
start_event_fetch(ssif_info, flags);
else if (ssif_info->req_flags)
@@ -909,31 +911,23 @@ static void msg_written_handler(struct ssif_info *ssif_info, int result,
if (result < 0) {
ssif_info->retries_left--;
if (ssif_info->retries_left > 0) {
- if (!start_resend(ssif_info)) {
- ssif_inc_stat(ssif_info, send_retries);
- return;
- }
- /* request failed, just return the error. */
- ssif_inc_stat(ssif_info, send_errors);
-
- if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
- dev_dbg(&ssif_info->client->dev,
- "%s: Out of retries\n", __func__);
- msg_done_handler(ssif_info, -EIO, NULL, 0);
+ /*
+ * Wait the retry timeout time per the spec,
+ * then redo the send.
+ */
+ ssif_info->do_resend = true;
+ mod_timer(&ssif_info->retry_timer,
+ jiffies + SSIF_REQ_RETRY_JIFFIES);
return;
}
ssif_inc_stat(ssif_info, send_errors);
- /*
- * Got an error on transmit, let the done routine
- * handle it.
- */
if (ssif_info->ssif_debug & SSIF_DEBUG_MSG)
dev_dbg(&ssif_info->client->dev,
- "%s: Error %d\n", __func__, result);
+ "%s: Out of retries\n", __func__);
- msg_done_handler(ssif_info, result, NULL, 0);
+ msg_done_handler(ssif_info, -EIO, NULL, 0);
return;
}
@@ -987,7 +981,6 @@ static void msg_written_handler(struct ssif_info *ssif_info, int result,
/* Wait a jiffie then request the next message */
ssif_info->waiting_alert = true;
ssif_info->retries_left = SSIF_RECV_RETRIES;
- ssif_info->rtc_us_timer = SSIF_MSG_PART_USEC;
if (!ssif_info->stopping)
mod_timer(&ssif_info->retry_timer,
jiffies + SSIF_MSG_PART_JIFFIES);
@@ -996,7 +989,7 @@ static void msg_written_handler(struct ssif_info *ssif_info, int result,
}
}
-static int start_resend(struct ssif_info *ssif_info)
+static void start_resend(struct ssif_info *ssif_info)
{
int command;
@@ -1021,7 +1014,6 @@ static int start_resend(struct ssif_info *ssif_info)
ssif_i2c_send(ssif_info, msg_written_handler, I2C_SMBUS_WRITE,
command, ssif_info->data, I2C_SMBUS_BLOCK_DATA);
- return 0;
}
static int start_send(struct ssif_info *ssif_info,
@@ -1036,7 +1028,8 @@ static int start_send(struct ssif_info *ssif_info,
ssif_info->retries_left = SSIF_SEND_RETRIES;
memcpy(ssif_info->data + 1, data, len);
ssif_info->data_len = len;
- return start_resend(ssif_info);
+ start_resend(ssif_info);
+ return 0;
}
/* Must be called with the message lock held. */
@@ -1046,7 +1039,7 @@ static void start_next_msg(struct ssif_info *ssif_info, unsigned long *flags)
unsigned long oflags;
restart:
- if (!SSIF_IDLE(ssif_info)) {
+ if (!IS_SSIF_IDLE(ssif_info)) {
ipmi_ssif_unlock_cond(ssif_info, flags);
return;
}
@@ -1269,7 +1262,7 @@ static void shutdown_ssif(void *send_info)
dev_set_drvdata(&ssif_info->client->dev, NULL);
/* make sure the driver is not looking for flags any more. */
- while (ssif_info->ssif_state != SSIF_NORMAL)
+ while (ssif_info->ssif_state != SSIF_IDLE)
schedule_timeout(1);
ssif_info->stopping = true;
@@ -1334,8 +1327,10 @@ static int do_cmd(struct i2c_client *client, int len, unsigned char *msg,
ret = i2c_smbus_write_block_data(client, SSIF_IPMI_REQUEST, len, msg);
if (ret) {
retry_cnt--;
- if (retry_cnt > 0)
+ if (retry_cnt > 0) {
+ msleep(SSIF_REQ_RETRY_MSEC);
goto retry1;
+ }
return -ENODEV;
}
@@ -1476,8 +1471,10 @@ retry_write:
32, msg);
if (ret) {
retry_cnt--;
- if (retry_cnt > 0)
+ if (retry_cnt > 0) {
+ msleep(SSIF_REQ_RETRY_MSEC);
goto retry_write;
+ }
dev_err(&client->dev, "Could not write multi-part start, though the BMC said it could handle it. Just limit sends to one part.\n");
return ret;
}
@@ -1839,7 +1836,7 @@ static int ssif_probe(struct i2c_client *client)
}
spin_lock_init(&ssif_info->lock);
- ssif_info->ssif_state = SSIF_NORMAL;
+ ssif_info->ssif_state = SSIF_IDLE;
timer_setup(&ssif_info->retry_timer, retry_timeout, 0);
timer_setup(&ssif_info->watch_timer, watch_timeout, 0);
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 83bf2a4dcb57..ffb101d349f0 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -343,7 +343,7 @@ static unsigned zero_mmap_capabilities(struct file *file)
/* can't do an in-place private mapping if there's no MMU */
static inline int private_mapping_ok(struct vm_area_struct *vma)
{
- return vma->vm_flags & VM_MAYSHARE;
+ return is_nommu_shared_mapping(vma->vm_flags);
}
#else
diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c
index f8231e2e84be..b35f651837c8 100644
--- a/drivers/char/mspec.c
+++ b/drivers/char/mspec.c
@@ -206,7 +206,7 @@ mspec_mmap(struct file *file, struct vm_area_struct *vma,
refcount_set(&vdata->refcnt, 1);
vma->vm_private_data = vdata;
- vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP;
+ vm_flags_set(vma, VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP);
if (vdata->type == MSPEC_UNCACHED)
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
vma->vm_ops = &mspec_vm_ops;
diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c
index adaec8fd4b16..e656f42a28ac 100644
--- a/drivers/char/pcmcia/cm4000_cs.c
+++ b/drivers/char/pcmcia/cm4000_cs.c
@@ -529,7 +529,8 @@ static int set_protocol(struct cm4000_dev *dev, struct ptsreq *ptsreq)
DEBUGP(5, dev, "NumRecBytes is valid\n");
break;
}
- usleep_range(10000, 11000);
+ /* can not sleep as this is in atomic context */
+ mdelay(10);
}
if (i == 100) {
DEBUGP(5, dev, "Timeout waiting for NumRecBytes getting "
@@ -549,7 +550,8 @@ static int set_protocol(struct cm4000_dev *dev, struct ptsreq *ptsreq)
}
break;
}
- usleep_range(10000, 11000);
+ /* can not sleep as this is in atomic context */
+ mdelay(10);
}
/* check whether it is a short PTS reply? */
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index b2735be81ab2..6ddfeb2fe98f 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -377,8 +377,8 @@ static void async_mode(MGSLPC_INFO *info);
static void tx_timeout(struct timer_list *t);
-static int carrier_raised(struct tty_port *port);
-static void dtr_rts(struct tty_port *port, int onoff);
+static bool carrier_raised(struct tty_port *port);
+static void dtr_rts(struct tty_port *port, bool active);
#if SYNCLINK_GENERIC_HDLC
#define dev_to_port(D) (dev_to_hdlc(D)->priv)
@@ -483,7 +483,7 @@ static void* mgslpc_get_text_ptr(void)
return mgslpc_get_text_ptr;
}
-/**
+/*
* line discipline callback wrappers
*
* The wrappers maintain line discipline references
@@ -1309,7 +1309,7 @@ static int startup(MGSLPC_INFO * info, struct tty_struct *tty)
if (tty)
clear_bit(TTY_IO_ERROR, &tty->flags);
- tty_port_set_initialized(&info->port, 1);
+ tty_port_set_initialized(&info->port, true);
return 0;
}
@@ -1359,7 +1359,7 @@ static void shutdown(MGSLPC_INFO * info, struct tty_struct *tty)
if (tty)
set_bit(TTY_IO_ERROR, &tty->flags);
- tty_port_set_initialized(&info->port, 0);
+ tty_port_set_initialized(&info->port, false);
}
static void mgslpc_program_hw(MGSLPC_INFO *info, struct tty_struct *tty)
@@ -2430,7 +2430,7 @@ static void mgslpc_hangup(struct tty_struct *tty)
tty_port_hangup(&info->port);
}
-static int carrier_raised(struct tty_port *port)
+static bool carrier_raised(struct tty_port *port)
{
MGSLPC_INFO *info = container_of(port, MGSLPC_INFO, port);
unsigned long flags;
@@ -2439,18 +2439,16 @@ static int carrier_raised(struct tty_port *port)
get_signals(info);
spin_unlock_irqrestore(&info->lock, flags);
- if (info->serial_signals & SerialSignal_DCD)
- return 1;
- return 0;
+ return info->serial_signals & SerialSignal_DCD;
}
-static void dtr_rts(struct tty_port *port, int onoff)
+static void dtr_rts(struct tty_port *port, bool active)
{
MGSLPC_INFO *info = container_of(port, MGSLPC_INFO, port);
unsigned long flags;
spin_lock_irqsave(&info->lock, flags);
- if (onoff)
+ if (active)
info->serial_signals |= SerialSignal_RTS | SerialSignal_DTR;
else
info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR);
@@ -3857,7 +3855,7 @@ static void tx_timeout(struct timer_list *t)
#if SYNCLINK_GENERIC_HDLC
-/**
+/*
* called by generic HDLC layer when protocol selected (PPP, frame relay, etc.)
* set encoding and frame check sequence (FCS) options
*
@@ -3910,7 +3908,7 @@ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding,
return 0;
}
-/**
+/*
* called by generic HDLC layer to send frame
*
* skb socket buffer containing HDLC frame
@@ -3955,7 +3953,7 @@ static netdev_tx_t hdlcdev_xmit(struct sk_buff *skb,
return NETDEV_TX_OK;
}
-/**
+/*
* called by network layer when interface enabled
* claim resources and initialize hardware
*
@@ -4018,7 +4016,7 @@ static int hdlcdev_open(struct net_device *dev)
return 0;
}
-/**
+/*
* called by network layer when interface is disabled
* shutdown hardware and release resources
*
@@ -4049,7 +4047,7 @@ static int hdlcdev_close(struct net_device *dev)
return 0;
}
-/**
+/*
* called by network layer to process IOCTL call to network device
*
* dev pointer to network device structure
@@ -4152,7 +4150,7 @@ static int hdlcdev_wan_ioctl(struct net_device *dev, struct if_settings *ifs)
}
}
-/**
+/*
* called by network layer when transmit timeout is detected
*
* dev pointer to network device structure
@@ -4175,7 +4173,7 @@ static void hdlcdev_tx_timeout(struct net_device *dev, unsigned int txqueue)
netif_wake_queue(dev);
}
-/**
+/*
* called by device driver when transmit completes
* reenable network layer transmit if stopped
*
@@ -4187,7 +4185,7 @@ static void hdlcdev_tx_done(MGSLPC_INFO *info)
netif_wake_queue(info->netdev);
}
-/**
+/*
* called by device driver when frame received
* pass frame to network layer
*
@@ -4227,7 +4225,7 @@ static const struct net_device_ops hdlcdev_ops = {
.ndo_tx_timeout = hdlcdev_tx_timeout,
};
-/**
+/*
* called by device driver when adding device instance
* do generic HDLC initialization
*
@@ -4275,7 +4273,7 @@ static int hdlcdev_init(MGSLPC_INFO *info)
return 0;
}
-/**
+/*
* called by device driver when removing device instance
* do generic HDLC cleanup
*
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 6a821118d553..d5ac4d955bc8 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -1666,9 +1666,8 @@ static void handle_control_message(struct virtio_device *vdev,
"Not enough space to store port name\n");
break;
}
- strncpy(port->name, buf->buf + buf->offset + sizeof(*cpkt),
- name_size - 1);
- port->name[name_size - 1] = 0;
+ strscpy(port->name, buf->buf + buf->offset + sizeof(*cpkt),
+ name_size);
/*
* Since we only have one sysfs attribute, 'name',
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index d79905f3e174..b6c5bf69a2b2 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -23,7 +23,6 @@ menuconfig COMMON_CLK
depends on !HAVE_LEGACY_CLK
select HAVE_CLK_PREPARE
select HAVE_CLK
- select SRCU
select RATIONAL
help
The common clock framework is a single definition of struct
diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile
index 79301e1c1c36..89061b85e7d2 100644
--- a/drivers/clk/at91/Makefile
+++ b/drivers/clk/at91/Makefile
@@ -3,7 +3,7 @@
# Makefile for at91 specific clk
#
-obj-y += pmc.o sckc.o dt-compat.o
+obj-y += pmc.o sckc.o
obj-y += clk-slow.o clk-main.o clk-pll.o clk-plldiv.o clk-master.o
obj-y += clk-system.o clk-peripheral.o clk-programmable.o
@@ -15,12 +15,12 @@ obj-$(CONFIG_HAVE_AT91_H32MX) += clk-h32mx.o
obj-$(CONFIG_HAVE_AT91_GENERATED_CLK) += clk-generated.o
obj-$(CONFIG_HAVE_AT91_I2S_MUX_CLK) += clk-i2s-mux.o
obj-$(CONFIG_HAVE_AT91_SAM9X60_PLL) += clk-sam9x60-pll.o
-obj-$(CONFIG_SOC_AT91RM9200) += at91rm9200.o
-obj-$(CONFIG_SOC_AT91SAM9) += at91sam9260.o at91sam9rl.o at91sam9x5.o
-obj-$(CONFIG_SOC_AT91SAM9) += at91sam9g45.o
-obj-$(CONFIG_SOC_AT91SAM9) += at91sam9n12.o at91sam9x5.o
+obj-$(CONFIG_SOC_AT91RM9200) += at91rm9200.o dt-compat.o
+obj-$(CONFIG_SOC_AT91SAM9) += at91sam9260.o at91sam9rl.o at91sam9x5.o dt-compat.o
+obj-$(CONFIG_SOC_AT91SAM9) += at91sam9g45.o dt-compat.o
+obj-$(CONFIG_SOC_AT91SAM9) += at91sam9n12.o at91sam9x5.o dt-compat.o
obj-$(CONFIG_SOC_SAM9X60) += sam9x60.o
-obj-$(CONFIG_SOC_SAMA5D3) += sama5d3.o
-obj-$(CONFIG_SOC_SAMA5D4) += sama5d4.o
-obj-$(CONFIG_SOC_SAMA5D2) += sama5d2.o
+obj-$(CONFIG_SOC_SAMA5D3) += sama5d3.o dt-compat.o
+obj-$(CONFIG_SOC_SAMA5D4) += sama5d4.o dt-compat.o
+obj-$(CONFIG_SOC_SAMA5D2) += sama5d2.o dt-compat.o
obj-$(CONFIG_SOC_SAMA7G5) += sama7g5.o
diff --git a/drivers/clk/at91/at91rm9200.c b/drivers/clk/at91/at91rm9200.c
index 16870943a13e..0b860126d589 100644
--- a/drivers/clk/at91/at91rm9200.c
+++ b/drivers/clk/at91/at91rm9200.c
@@ -183,7 +183,7 @@ static void __init at91rm9200_pmc_setup(struct device_node *np)
for (i = 0; i < ARRAY_SIZE(at91rm9200_systemck); i++) {
hw = at91_clk_register_system(regmap, at91rm9200_systemck[i].n,
at91rm9200_systemck[i].p,
- at91rm9200_systemck[i].id);
+ at91rm9200_systemck[i].id, 0);
if (IS_ERR(hw))
goto err_free;
diff --git a/drivers/clk/at91/at91sam9260.c b/drivers/clk/at91/at91sam9260.c
index 11550e50cd9f..b521f470428f 100644
--- a/drivers/clk/at91/at91sam9260.c
+++ b/drivers/clk/at91/at91sam9260.c
@@ -460,7 +460,7 @@ static void __init at91sam926x_pmc_setup(struct device_node *np,
for (i = 0; i < data->num_sck; i++) {
hw = at91_clk_register_system(regmap, data->sck[i].n,
data->sck[i].p,
- data->sck[i].id);
+ data->sck[i].id, 0);
if (IS_ERR(hw))
goto err_free;
diff --git a/drivers/clk/at91/at91sam9g45.c b/drivers/clk/at91/at91sam9g45.c
index 8c9344451f46..5099669ddcbd 100644
--- a/drivers/clk/at91/at91sam9g45.c
+++ b/drivers/clk/at91/at91sam9g45.c
@@ -40,9 +40,14 @@ static const struct clk_pll_characteristics plla_characteristics = {
static const struct {
char *n;
char *p;
+ unsigned long flags;
u8 id;
} at91sam9g45_systemck[] = {
- { .n = "ddrck", .p = "masterck_div", .id = 2 },
+ /*
+ * ddrck feeds DDR controller and is enabled by bootloader thus we need
+ * to keep it enabled in case there is no Linux consumer for it.
+ */
+ { .n = "ddrck", .p = "masterck_div", .id = 2, .flags = CLK_IS_CRITICAL },
{ .n = "uhpck", .p = "usbck", .id = 6 },
{ .n = "pck0", .p = "prog0", .id = 8 },
{ .n = "pck1", .p = "prog1", .id = 9 },
@@ -198,7 +203,8 @@ static void __init at91sam9g45_pmc_setup(struct device_node *np)
for (i = 0; i < ARRAY_SIZE(at91sam9g45_systemck); i++) {
hw = at91_clk_register_system(regmap, at91sam9g45_systemck[i].n,
at91sam9g45_systemck[i].p,
- at91sam9g45_systemck[i].id);
+ at91sam9g45_systemck[i].id,
+ at91sam9g45_systemck[i].flags);
if (IS_ERR(hw))
goto err_free;
diff --git a/drivers/clk/at91/at91sam9n12.c b/drivers/clk/at91/at91sam9n12.c
index 0bb19400d199..08a10e12d08d 100644
--- a/drivers/clk/at91/at91sam9n12.c
+++ b/drivers/clk/at91/at91sam9n12.c
@@ -54,9 +54,14 @@ static const struct clk_pll_characteristics pllb_characteristics = {
static const struct {
char *n;
char *p;
+ unsigned long flags;
u8 id;
} at91sam9n12_systemck[] = {
- { .n = "ddrck", .p = "masterck_div", .id = 2 },
+ /*
+ * ddrck feeds DDR controller and is enabled by bootloader thus we need
+ * to keep it enabled in case there is no Linux consumer for it.
+ */
+ { .n = "ddrck", .p = "masterck_div", .id = 2, .flags = CLK_IS_CRITICAL },
{ .n = "lcdck", .p = "masterck_div", .id = 3 },
{ .n = "uhpck", .p = "usbck", .id = 6 },
{ .n = "udpck", .p = "usbck", .id = 7 },
@@ -223,7 +228,8 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np)
for (i = 0; i < ARRAY_SIZE(at91sam9n12_systemck); i++) {
hw = at91_clk_register_system(regmap, at91sam9n12_systemck[i].n,
at91sam9n12_systemck[i].p,
- at91sam9n12_systemck[i].id);
+ at91sam9n12_systemck[i].id,
+ at91sam9n12_systemck[i].flags);
if (IS_ERR(hw))
goto err_free;
@@ -236,7 +242,7 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np)
at91sam9n12_periphck[i].n,
"masterck_div",
at91sam9n12_periphck[i].id,
- &range, INT_MIN);
+ &range, INT_MIN, 0);
if (IS_ERR(hw))
goto err_free;
diff --git a/drivers/clk/at91/at91sam9rl.c b/drivers/clk/at91/at91sam9rl.c
index b992137bab02..1a1b6b2bb0e3 100644
--- a/drivers/clk/at91/at91sam9rl.c
+++ b/drivers/clk/at91/at91sam9rl.c
@@ -160,7 +160,7 @@ static void __init at91sam9rl_pmc_setup(struct device_node *np)
for (i = 0; i < ARRAY_SIZE(at91sam9rl_systemck); i++) {
hw = at91_clk_register_system(regmap, at91sam9rl_systemck[i].n,
at91sam9rl_systemck[i].p,
- at91sam9rl_systemck[i].id);
+ at91sam9rl_systemck[i].id, 0);
if (IS_ERR(hw))
goto err_free;
diff --git a/drivers/clk/at91/at91sam9x5.c b/drivers/clk/at91/at91sam9x5.c
index 3857db2e144b..13e589c95907 100644
--- a/drivers/clk/at91/at91sam9x5.c
+++ b/drivers/clk/at91/at91sam9x5.c
@@ -41,9 +41,14 @@ static const struct clk_pll_characteristics plla_characteristics = {
static const struct {
char *n;
char *p;
+ unsigned long flags;
u8 id;
} at91sam9x5_systemck[] = {
- { .n = "ddrck", .p = "masterck_div", .id = 2 },
+ /*
+ * ddrck feeds DDR controller and is enabled by bootloader thus we need
+ * to keep it enabled in case there is no Linux consumer for it.
+ */
+ { .n = "ddrck", .p = "masterck_div", .id = 2, .flags = CLK_IS_CRITICAL },
{ .n = "smdck", .p = "smdclk", .id = 4 },
{ .n = "uhpck", .p = "usbck", .id = 6 },
{ .n = "udpck", .p = "usbck", .id = 7 },
@@ -248,7 +253,8 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
for (i = 0; i < ARRAY_SIZE(at91sam9x5_systemck); i++) {
hw = at91_clk_register_system(regmap, at91sam9x5_systemck[i].n,
at91sam9x5_systemck[i].p,
- at91sam9x5_systemck[i].id);
+ at91sam9x5_systemck[i].id,
+ at91sam9x5_systemck[i].flags);
if (IS_ERR(hw))
goto err_free;
@@ -256,7 +262,8 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
}
if (has_lcdck) {
- hw = at91_clk_register_system(regmap, "lcdck", "masterck_div", 3);
+ hw = at91_clk_register_system(regmap, "lcdck", "masterck_div",
+ 3, 0);
if (IS_ERR(hw))
goto err_free;
@@ -269,7 +276,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
at91sam9x5_periphck[i].n,
"masterck_div",
at91sam9x5_periphck[i].id,
- &range, INT_MIN);
+ &range, INT_MIN, 0);
if (IS_ERR(hw))
goto err_free;
@@ -282,7 +289,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
extra_pcks[i].n,
"masterck_div",
extra_pcks[i].id,
- &range, INT_MIN);
+ &range, INT_MIN, 0);
if (IS_ERR(hw))
goto err_free;
diff --git a/drivers/clk/at91/clk-peripheral.c b/drivers/clk/at91/clk-peripheral.c
index 5104d4025484..93ea685e27f6 100644
--- a/drivers/clk/at91/clk-peripheral.c
+++ b/drivers/clk/at91/clk-peripheral.c
@@ -445,7 +445,7 @@ at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,
const struct clk_pcr_layout *layout,
const char *name, const char *parent_name,
u32 id, const struct clk_range *range,
- int chg_pid)
+ int chg_pid, unsigned long flags)
{
struct clk_sam9x5_peripheral *periph;
struct clk_init_data init;
@@ -462,12 +462,12 @@ at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,
init.name = name;
init.parent_names = &parent_name;
init.num_parents = 1;
+ init.flags = flags;
if (chg_pid < 0) {
- init.flags = 0;
init.ops = &sam9x5_peripheral_ops;
} else {
- init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
- CLK_SET_RATE_PARENT;
+ init.flags |= CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
+ CLK_SET_RATE_PARENT;
init.ops = &sam9x5_peripheral_chg_ops;
}
diff --git a/drivers/clk/at91/clk-system.c b/drivers/clk/at91/clk-system.c
index 80720fd1a9cf..10193650429e 100644
--- a/drivers/clk/at91/clk-system.c
+++ b/drivers/clk/at91/clk-system.c
@@ -105,7 +105,7 @@ static const struct clk_ops system_ops = {
struct clk_hw * __init
at91_clk_register_system(struct regmap *regmap, const char *name,
- const char *parent_name, u8 id)
+ const char *parent_name, u8 id, unsigned long flags)
{
struct clk_system *sys;
struct clk_hw *hw;
@@ -123,7 +123,7 @@ at91_clk_register_system(struct regmap *regmap, const char *name,
init.ops = &system_ops;
init.parent_names = &parent_name;
init.num_parents = 1;
- init.flags = CLK_SET_RATE_PARENT;
+ init.flags = CLK_SET_RATE_PARENT | flags;
sys->id = id;
sys->hw.init = &init;
diff --git a/drivers/clk/at91/dt-compat.c b/drivers/clk/at91/dt-compat.c
index 85a964cb2d89..97f67e23ef80 100644
--- a/drivers/clk/at91/dt-compat.c
+++ b/drivers/clk/at91/dt-compat.c
@@ -493,18 +493,28 @@ of_at91_clk_periph_setup(struct device_node *np, u8 type)
parent_name, id);
} else {
struct clk_range range = CLK_RANGE(0, 0);
+ unsigned long flags = 0;
of_at91_get_clk_range(periphclknp,
"atmel,clk-output-range",
&range);
+ /*
+ * mpddr_clk feed DDR controller and is enabled by
+ * bootloader thus we need to keep it enabled in case
+ * there is no Linux consumer for it.
+ */
+ if (!strcmp(periphclknp->name, "mpddr_clk"))
+ flags = CLK_IS_CRITICAL;
+
hw = at91_clk_register_sam9x5_peripheral(regmap,
&pmc_pcr_lock,
&dt_pcr_layout,
name,
parent_name,
id, &range,
- INT_MIN);
+ INT_MIN,
+ flags);
}
if (IS_ERR(hw))
@@ -879,6 +889,8 @@ static void __init of_at91rm9200_clk_sys_setup(struct device_node *np)
return;
for_each_child_of_node(np, sysclknp) {
+ unsigned long flags = 0;
+
if (of_property_read_u32(sysclknp, "reg", &id))
continue;
@@ -887,7 +899,16 @@ static void __init of_at91rm9200_clk_sys_setup(struct device_node *np)
parent_name = of_clk_get_parent_name(sysclknp, 0);
- hw = at91_clk_register_system(regmap, name, parent_name, id);
+ /*
+ * ddrck feeds DDR controller and is enabled by bootloader thus
+ * we need to keep it enabled in case there is no Linux consumer
+ * for it.
+ */
+ if (!strcmp(sysclknp->name, "ddrck"))
+ flags = CLK_IS_CRITICAL;
+
+ hw = at91_clk_register_system(regmap, name, parent_name, id,
+ flags);
if (IS_ERR(hw))
continue;
diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
index efe4975bddc3..1b3ca7dd9b57 100644
--- a/drivers/clk/at91/pmc.h
+++ b/drivers/clk/at91/pmc.h
@@ -199,7 +199,7 @@ at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,
const struct clk_pcr_layout *layout,
const char *name, const char *parent_name,
u32 id, const struct clk_range *range,
- int chg_pid);
+ int chg_pid, unsigned long flags);
struct clk_hw * __init
at91_clk_register_pll(struct regmap *regmap, const char *name,
@@ -242,7 +242,7 @@ at91sam9x5_clk_register_smd(struct regmap *regmap, const char *name,
struct clk_hw * __init
at91_clk_register_system(struct regmap *regmap, const char *name,
- const char *parent_name, u8 id);
+ const char *parent_name, u8 id, unsigned long flags);
struct clk_hw * __init
at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name,
diff --git a/drivers/clk/at91/sam9x60.c b/drivers/clk/at91/sam9x60.c
index 9ea4ce501bad..ac070db58195 100644
--- a/drivers/clk/at91/sam9x60.c
+++ b/drivers/clk/at91/sam9x60.c
@@ -75,9 +75,14 @@ static const struct clk_pcr_layout sam9x60_pcr_layout = {
static const struct {
char *n;
char *p;
+ unsigned long flags;
u8 id;
} sam9x60_systemck[] = {
- { .n = "ddrck", .p = "masterck_div", .id = 2 },
+ /*
+ * ddrck feeds DDR controller and is enabled by bootloader thus we need
+ * to keep it enabled in case there is no Linux consumer for it.
+ */
+ { .n = "ddrck", .p = "masterck_div", .id = 2, .flags = CLK_IS_CRITICAL },
{ .n = "uhpck", .p = "usbck", .id = 6 },
{ .n = "pck0", .p = "prog0", .id = 8 },
{ .n = "pck1", .p = "prog1", .id = 9 },
@@ -86,6 +91,7 @@ static const struct {
static const struct {
char *n;
+ unsigned long flags;
u8 id;
} sam9x60_periphck[] = {
{ .n = "pioA_clk", .id = 2, },
@@ -132,7 +138,11 @@ static const struct {
{ .n = "pioD_clk", .id = 44, },
{ .n = "tcb1_clk", .id = 45, },
{ .n = "dbgu_clk", .id = 47, },
- { .n = "mpddr_clk", .id = 49, },
+ /*
+ * mpddr_clk feeds DDR controller and is enabled by bootloader thus we
+ * need to keep it enabled in case there is no Linux consumer for it.
+ */
+ { .n = "mpddr_clk", .id = 49, .flags = CLK_IS_CRITICAL },
};
static const struct {
@@ -315,7 +325,8 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
for (i = 0; i < ARRAY_SIZE(sam9x60_systemck); i++) {
hw = at91_clk_register_system(regmap, sam9x60_systemck[i].n,
sam9x60_systemck[i].p,
- sam9x60_systemck[i].id);
+ sam9x60_systemck[i].id,
+ sam9x60_systemck[i].flags);
if (IS_ERR(hw))
goto err_free;
@@ -328,7 +339,8 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
sam9x60_periphck[i].n,
"masterck_div",
sam9x60_periphck[i].id,
- &range, INT_MIN);
+ &range, INT_MIN,
+ sam9x60_periphck[i].flags);
if (IS_ERR(hw))
goto err_free;
diff --git a/drivers/clk/at91/sama5d2.c b/drivers/clk/at91/sama5d2.c
index 84156dc52bff..c0e3e1a4bbf3 100644
--- a/drivers/clk/at91/sama5d2.c
+++ b/drivers/clk/at91/sama5d2.c
@@ -40,9 +40,14 @@ static const struct clk_pcr_layout sama5d2_pcr_layout = {
static const struct {
char *n;
char *p;
+ unsigned long flags;
u8 id;
} sama5d2_systemck[] = {
- { .n = "ddrck", .p = "masterck_div", .id = 2 },
+ /*
+ * ddrck feeds DDR controller and is enabled by bootloader thus we need
+ * to keep it enabled in case there is no Linux consumer for it.
+ */
+ { .n = "ddrck", .p = "masterck_div", .id = 2, .flags = CLK_IS_CRITICAL },
{ .n = "lcdck", .p = "masterck_div", .id = 3 },
{ .n = "uhpck", .p = "usbck", .id = 6 },
{ .n = "udpck", .p = "usbck", .id = 7 },
@@ -97,6 +102,7 @@ static const struct {
static const struct {
char *n;
+ unsigned long flags;
u8 id;
} sama5d2_periphck[] = {
{ .n = "dma0_clk", .id = 6, },
@@ -104,7 +110,11 @@ static const struct {
{ .n = "aes_clk", .id = 9, },
{ .n = "aesb_clk", .id = 10, },
{ .n = "sha_clk", .id = 12, },
- { .n = "mpddr_clk", .id = 13, },
+ /*
+ * mpddr_clk feeds DDR controller and is enabled by bootloader thus we
+ * need to keep it enabled in case there is no Linux consumer for it.
+ */
+ { .n = "mpddr_clk", .id = 13, .flags = CLK_IS_CRITICAL },
{ .n = "matrix0_clk", .id = 15, },
{ .n = "sdmmc0_hclk", .id = 31, },
{ .n = "sdmmc1_hclk", .id = 32, },
@@ -302,7 +312,8 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
for (i = 0; i < ARRAY_SIZE(sama5d2_systemck); i++) {
hw = at91_clk_register_system(regmap, sama5d2_systemck[i].n,
sama5d2_systemck[i].p,
- sama5d2_systemck[i].id);
+ sama5d2_systemck[i].id,
+ sama5d2_systemck[i].flags);
if (IS_ERR(hw))
goto err_free;
@@ -315,7 +326,8 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
sama5d2_periphck[i].n,
"masterck_div",
sama5d2_periphck[i].id,
- &range, INT_MIN);
+ &range, INT_MIN,
+ sama5d2_periphck[i].flags);
if (IS_ERR(hw))
goto err_free;
@@ -329,7 +341,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
"h32mxck",
sama5d2_periph32ck[i].id,
&sama5d2_periph32ck[i].r,
- INT_MIN);
+ INT_MIN, 0);
if (IS_ERR(hw))
goto err_free;
diff --git a/drivers/clk/at91/sama5d3.c b/drivers/clk/at91/sama5d3.c
index 7e93c6edf305..ad6068b884de 100644
--- a/drivers/clk/at91/sama5d3.c
+++ b/drivers/clk/at91/sama5d3.c
@@ -40,9 +40,14 @@ static const struct clk_pcr_layout sama5d3_pcr_layout = {
static const struct {
char *n;
char *p;
+ unsigned long flags;
u8 id;
} sama5d3_systemck[] = {
- { .n = "ddrck", .p = "masterck_div", .id = 2 },
+ /*
+ * ddrck feeds DDR controller and is enabled by bootloader thus we need
+ * to keep it enabled in case there is no Linux consumer for it.
+ */
+ { .n = "ddrck", .p = "masterck_div", .id = 2, .flags = CLK_IS_CRITICAL },
{ .n = "lcdck", .p = "masterck_div", .id = 3 },
{ .n = "smdck", .p = "smdclk", .id = 4 },
{ .n = "uhpck", .p = "usbck", .id = 6 },
@@ -56,6 +61,7 @@ static const struct {
char *n;
u8 id;
struct clk_range r;
+ unsigned long flags;
} sama5d3_periphck[] = {
{ .n = "dbgu_clk", .id = 2, },
{ .n = "hsmc_clk", .id = 5, },
@@ -99,7 +105,11 @@ static const struct {
{ .n = "tdes_clk", .id = 44, },
{ .n = "trng_clk", .id = 45, },
{ .n = "fuse_clk", .id = 48, },
- { .n = "mpddr_clk", .id = 49, },
+ /*
+ * mpddr_clk feeds DDR controller and is enabled by bootloader thus we
+ * need to keep it enabled in case there is no Linux consumer for it.
+ */
+ { .n = "mpddr_clk", .id = 49, .flags = CLK_IS_CRITICAL },
};
static void __init sama5d3_pmc_setup(struct device_node *np)
@@ -222,7 +232,8 @@ static void __init sama5d3_pmc_setup(struct device_node *np)
for (i = 0; i < ARRAY_SIZE(sama5d3_systemck); i++) {
hw = at91_clk_register_system(regmap, sama5d3_systemck[i].n,
sama5d3_systemck[i].p,
- sama5d3_systemck[i].id);
+ sama5d3_systemck[i].id,
+ sama5d3_systemck[i].flags);
if (IS_ERR(hw))
goto err_free;
@@ -236,7 +247,8 @@ static void __init sama5d3_pmc_setup(struct device_node *np)
"masterck_div",
sama5d3_periphck[i].id,
&sama5d3_periphck[i].r,
- INT_MIN);
+ INT_MIN,
+ sama5d3_periphck[i].flags);
if (IS_ERR(hw))
goto err_free;
diff --git a/drivers/clk/at91/sama5d4.c b/drivers/clk/at91/sama5d4.c
index 1a14a9bce308..e876ec971a39 100644
--- a/drivers/clk/at91/sama5d4.c
+++ b/drivers/clk/at91/sama5d4.c
@@ -39,9 +39,14 @@ static const struct clk_pcr_layout sama5d4_pcr_layout = {
static const struct {
char *n;
char *p;
+ unsigned long flags;
u8 id;
} sama5d4_systemck[] = {
- { .n = "ddrck", .p = "masterck_div", .id = 2 },
+ /*
+ * ddrck feeds DDR controller and is enabled by bootloader thus we need
+ * to keep it enabled in case there is no Linux consumer for it.
+ */
+ { .n = "ddrck", .p = "masterck_div", .id = 2, .flags = CLK_IS_CRITICAL },
{ .n = "lcdck", .p = "masterck_div", .id = 3 },
{ .n = "smdck", .p = "smdclk", .id = 4 },
{ .n = "uhpck", .p = "usbck", .id = 6 },
@@ -103,12 +108,17 @@ static const struct {
static const struct {
char *n;
+ unsigned long flags;
u8 id;
} sama5d4_periphck[] = {
{ .n = "dma0_clk", .id = 8 },
{ .n = "cpkcc_clk", .id = 10 },
{ .n = "aesb_clk", .id = 13 },
- { .n = "mpddr_clk", .id = 16 },
+ /*
+ * mpddr_clk feeds DDR controller and is enabled by bootloader thus we
+ * need to keep it enabled in case there is no Linux consumer for it.
+ */
+ { .n = "mpddr_clk", .id = 16, .flags = CLK_IS_CRITICAL },
{ .n = "matrix0_clk", .id = 18 },
{ .n = "vdec_clk", .id = 19 },
{ .n = "dma1_clk", .id = 50 },
@@ -245,7 +255,8 @@ static void __init sama5d4_pmc_setup(struct device_node *np)
for (i = 0; i < ARRAY_SIZE(sama5d4_systemck); i++) {
hw = at91_clk_register_system(regmap, sama5d4_systemck[i].n,
sama5d4_systemck[i].p,
- sama5d4_systemck[i].id);
+ sama5d4_systemck[i].id,
+ sama5d4_systemck[i].flags);
if (IS_ERR(hw))
goto err_free;
@@ -258,7 +269,8 @@ static void __init sama5d4_pmc_setup(struct device_node *np)
sama5d4_periphck[i].n,
"masterck_div",
sama5d4_periphck[i].id,
- &range, INT_MIN);
+ &range, INT_MIN,
+ sama5d4_periphck[i].flags);
if (IS_ERR(hw))
goto err_free;
@@ -271,7 +283,7 @@ static void __init sama5d4_pmc_setup(struct device_node *np)
sama5d4_periph32ck[i].n,
"h32mxck",
sama5d4_periph32ck[i].id,
- &range, INT_MIN);
+ &range, INT_MIN, 0);
if (IS_ERR(hw))
goto err_free;
diff --git a/drivers/clk/at91/sama7g5.c b/drivers/clk/at91/sama7g5.c
index 9a213ba9e58b..f135b662f1ff 100644
--- a/drivers/clk/at91/sama7g5.c
+++ b/drivers/clk/at91/sama7g5.c
@@ -1068,7 +1068,7 @@ static void __init sama7g5_pmc_setup(struct device_node *np)
for (i = 0; i < ARRAY_SIZE(sama7g5_systemck); i++) {
hw = at91_clk_register_system(regmap, sama7g5_systemck[i].n,
sama7g5_systemck[i].p,
- sama7g5_systemck[i].id);
+ sama7g5_systemck[i].id, 0);
if (IS_ERR(hw))
goto err_free;
@@ -1083,7 +1083,7 @@ static void __init sama7g5_pmc_setup(struct device_node *np)
sama7g5_periphck[i].id,
&sama7g5_periphck[i].r,
sama7g5_periphck[i].chgp ? 0 :
- INT_MIN);
+ INT_MIN, 0);
if (IS_ERR(hw))
goto err_free;
diff --git a/drivers/clk/clk-renesas-pcie.c b/drivers/clk/clk-renesas-pcie.c
index e6247141d0c0..f91f30560820 100644
--- a/drivers/clk/clk-renesas-pcie.c
+++ b/drivers/clk/clk-renesas-pcie.c
@@ -60,7 +60,6 @@ struct rs9_driver_data {
struct i2c_client *client;
struct regmap *regmap;
const struct rs9_chip_info *chip_info;
- struct clk *pin_xin;
struct clk_hw *clk_dif[2];
u8 pll_amplitude;
u8 pll_ssc;
diff --git a/drivers/clk/clk-versaclock5.c b/drivers/clk/clk-versaclock5.c
index e9737969170e..fa71a57875ce 100644
--- a/drivers/clk/clk-versaclock5.c
+++ b/drivers/clk/clk-versaclock5.c
@@ -122,9 +122,8 @@
#define VC5_GLOBAL_REGISTER 0x76
#define VC5_GLOBAL_REGISTER_GLOBAL_RESET BIT(5)
-/* PLL/VCO runs between 2.5 GHz and 3.0 GHz */
+/* The minimum VCO frequency is 2.5 GHz. The maximum is variant specific. */
#define VC5_PLL_VCO_MIN 2500000000UL
-#define VC5_PLL_VCO_MAX 3000000000UL
/* VC5 Input mux settings */
#define VC5_MUX_IN_XIN BIT(0)
@@ -150,6 +149,7 @@ enum vc5_model {
IDT_VC5_5P49V5925,
IDT_VC5_5P49V5933,
IDT_VC5_5P49V5935,
+ IDT_VC6_5P49V60,
IDT_VC6_5P49V6901,
IDT_VC6_5P49V6965,
IDT_VC6_5P49V6975,
@@ -161,6 +161,7 @@ struct vc5_chip_info {
const unsigned int clk_fod_cnt;
const unsigned int clk_out_cnt;
const u32 flags;
+ const unsigned long vco_max;
};
struct vc5_driver_data;
@@ -446,13 +447,11 @@ static long vc5_pll_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
{
struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
+ struct vc5_driver_data *vc5 = hwdata->vc5;
u32 div_int;
u64 div_frc;
- if (rate < VC5_PLL_VCO_MIN)
- rate = VC5_PLL_VCO_MIN;
- if (rate > VC5_PLL_VCO_MAX)
- rate = VC5_PLL_VCO_MAX;
+ rate = clamp(rate, VC5_PLL_VCO_MIN, vc5->chip_info->vco_max);
/* Determine integer part, which is 12 bit wide */
div_int = rate / *parent_rate;
@@ -1212,6 +1211,7 @@ static const struct vc5_chip_info idt_5p49v5923_info = {
.clk_fod_cnt = 2,
.clk_out_cnt = 3,
.flags = 0,
+ .vco_max = 3000000000UL,
};
static const struct vc5_chip_info idt_5p49v5925_info = {
@@ -1219,6 +1219,7 @@ static const struct vc5_chip_info idt_5p49v5925_info = {
.clk_fod_cnt = 4,
.clk_out_cnt = 5,
.flags = 0,
+ .vco_max = 3000000000UL,
};
static const struct vc5_chip_info idt_5p49v5933_info = {
@@ -1226,6 +1227,7 @@ static const struct vc5_chip_info idt_5p49v5933_info = {
.clk_fod_cnt = 2,
.clk_out_cnt = 3,
.flags = VC5_HAS_INTERNAL_XTAL,
+ .vco_max = 3000000000UL,
};
static const struct vc5_chip_info idt_5p49v5935_info = {
@@ -1233,6 +1235,15 @@ static const struct vc5_chip_info idt_5p49v5935_info = {
.clk_fod_cnt = 4,
.clk_out_cnt = 5,
.flags = VC5_HAS_INTERNAL_XTAL,
+ .vco_max = 3000000000UL,
+};
+
+static const struct vc5_chip_info idt_5p49v60_info = {
+ .model = IDT_VC6_5P49V60,
+ .clk_fod_cnt = 4,
+ .clk_out_cnt = 5,
+ .flags = VC5_HAS_PFD_FREQ_DBL | VC5_HAS_BYPASS_SYNC_BIT,
+ .vco_max = 2700000000UL,
};
static const struct vc5_chip_info idt_5p49v6901_info = {
@@ -1240,6 +1251,7 @@ static const struct vc5_chip_info idt_5p49v6901_info = {
.clk_fod_cnt = 4,
.clk_out_cnt = 5,
.flags = VC5_HAS_PFD_FREQ_DBL | VC5_HAS_BYPASS_SYNC_BIT,
+ .vco_max = 3000000000UL,
};
static const struct vc5_chip_info idt_5p49v6965_info = {
@@ -1247,6 +1259,7 @@ static const struct vc5_chip_info idt_5p49v6965_info = {
.clk_fod_cnt = 4,
.clk_out_cnt = 5,
.flags = VC5_HAS_BYPASS_SYNC_BIT,
+ .vco_max = 3000000000UL,
};
static const struct vc5_chip_info idt_5p49v6975_info = {
@@ -1254,6 +1267,7 @@ static const struct vc5_chip_info idt_5p49v6975_info = {
.clk_fod_cnt = 4,
.clk_out_cnt = 5,
.flags = VC5_HAS_BYPASS_SYNC_BIT | VC5_HAS_INTERNAL_XTAL,
+ .vco_max = 3000000000UL,
};
static const struct i2c_device_id vc5_id[] = {
@@ -1261,6 +1275,7 @@ static const struct i2c_device_id vc5_id[] = {
{ "5p49v5925", .driver_data = IDT_VC5_5P49V5925 },
{ "5p49v5933", .driver_data = IDT_VC5_5P49V5933 },
{ "5p49v5935", .driver_data = IDT_VC5_5P49V5935 },
+ { "5p49v60", .driver_data = IDT_VC6_5P49V60 },
{ "5p49v6901", .driver_data = IDT_VC6_5P49V6901 },
{ "5p49v6965", .driver_data = IDT_VC6_5P49V6965 },
{ "5p49v6975", .driver_data = IDT_VC6_5P49V6975 },
@@ -1273,6 +1288,7 @@ static const struct of_device_id clk_vc5_of_match[] = {
{ .compatible = "idt,5p49v5925", .data = &idt_5p49v5925_info },
{ .compatible = "idt,5p49v5933", .data = &idt_5p49v5933_info },
{ .compatible = "idt,5p49v5935", .data = &idt_5p49v5935_info },
+ { .compatible = "idt,5p49v60", .data = &idt_5p49v60_info },
{ .compatible = "idt,5p49v6901", .data = &idt_5p49v6901_info },
{ .compatible = "idt,5p49v6965", .data = &idt_5p49v6965_info },
{ .compatible = "idt,5p49v6975", .data = &idt_5p49v6975_info },
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index f6d7c6a9a654..ae07685c7588 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -244,6 +244,17 @@ static bool clk_core_is_enabled(struct clk_core *core)
}
}
+ /*
+ * This could be called with the enable lock held, or from atomic
+ * context. If the parent isn't enabled already, we can't do
+ * anything here. We can also assume this clock isn't enabled.
+ */
+ if ((core->flags & CLK_OPS_PARENT_ENABLE) && core->parent)
+ if (!clk_core_is_enabled(core->parent)) {
+ ret = false;
+ goto done;
+ }
+
ret = core->ops->is_enabled(core->hw);
done:
if (core->rpm_enabled)
diff --git a/drivers/clk/imx/Kconfig b/drivers/clk/imx/Kconfig
index 25785ec9c276..f6b82e0b9703 100644
--- a/drivers/clk/imx/Kconfig
+++ b/drivers/clk/imx/Kconfig
@@ -115,7 +115,7 @@ config CLK_IMX93
config CLK_IMXRT1050
tristate "IMXRT1050 CCM Clock Driver"
- depends on SOC_IMXRT
+ depends on SOC_IMXRT || COMPILE_TEST
select MXC_CLK
help
Build the driver for i.MXRT1050 CCM Clock Driver
diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile
index e8aacb0ee6ac..a75d59f7cb8a 100644
--- a/drivers/clk/imx/Makefile
+++ b/drivers/clk/imx/Makefile
@@ -22,6 +22,7 @@ mxc-clk-objs += clk-pllv3.o
mxc-clk-objs += clk-pllv4.o
mxc-clk-objs += clk-pll14xx.o
mxc-clk-objs += clk-sscg-pll.o
+mxc-clk-objs += clk-gpr-mux.o
obj-$(CONFIG_MXC_CLK) += mxc-clk.o
obj-$(CONFIG_CLK_IMX8MM) += clk-imx8mm.o
diff --git a/drivers/clk/imx/clk-gpr-mux.c b/drivers/clk/imx/clk-gpr-mux.c
new file mode 100644
index 000000000000..c8d6090f15d6
--- /dev/null
+++ b/drivers/clk/imx/clk-gpr-mux.c
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ */
+
+#define pr_fmt(fmt) "imx:clk-gpr-mux: " fmt
+
+#include <linux/module.h>
+
+#include <linux/clk-provider.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+#include "clk.h"
+
+struct imx_clk_gpr {
+ struct clk_hw hw;
+ struct regmap *regmap;
+ u32 mask;
+ u32 reg;
+ const u32 *mux_table;
+};
+
+static struct imx_clk_gpr *to_imx_clk_gpr(struct clk_hw *hw)
+{
+ return container_of(hw, struct imx_clk_gpr, hw);
+}
+
+static u8 imx_clk_gpr_mux_get_parent(struct clk_hw *hw)
+{
+ struct imx_clk_gpr *priv = to_imx_clk_gpr(hw);
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(priv->regmap, priv->reg, &val);
+ if (ret)
+ goto get_parent_err;
+
+ val &= priv->mask;
+
+ ret = clk_mux_val_to_index(hw, priv->mux_table, 0, val);
+ if (ret < 0)
+ goto get_parent_err;
+
+ return ret;
+
+get_parent_err:
+ pr_err("failed to get parent (%pe)\n", ERR_PTR(ret));
+
+ /* return some realistic non negative value. Potentially we could
+ * give index to some dummy error parent.
+ */
+ return 0;
+}
+
+static int imx_clk_gpr_mux_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct imx_clk_gpr *priv = to_imx_clk_gpr(hw);
+ unsigned int val = clk_mux_index_to_val(priv->mux_table, 0, index);
+
+ return regmap_update_bits(priv->regmap, priv->reg, priv->mask, val);
+}
+
+static int imx_clk_gpr_mux_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ return clk_mux_determine_rate_flags(hw, req, 0);
+}
+
+static const struct clk_ops imx_clk_gpr_mux_ops = {
+ .get_parent = imx_clk_gpr_mux_get_parent,
+ .set_parent = imx_clk_gpr_mux_set_parent,
+ .determine_rate = imx_clk_gpr_mux_determine_rate,
+};
+
+struct clk_hw *imx_clk_gpr_mux(const char *name, const char *compatible,
+ u32 reg, const char **parent_names,
+ u8 num_parents, const u32 *mux_table, u32 mask)
+{
+ struct clk_init_data init = { };
+ struct imx_clk_gpr *priv;
+ struct regmap *regmap;
+ struct clk_hw *hw;
+ int ret;
+
+ regmap = syscon_regmap_lookup_by_compatible(compatible);
+ if (IS_ERR(regmap)) {
+ pr_err("failed to find %s regmap\n", compatible);
+ return ERR_CAST(regmap);
+ }
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &imx_clk_gpr_mux_ops;
+ init.parent_names = parent_names;
+ init.num_parents = num_parents;
+ init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
+
+ priv->hw.init = &init;
+ priv->regmap = regmap;
+ priv->mux_table = mux_table;
+ priv->reg = reg;
+ priv->mask = mask;
+
+ hw = &priv->hw;
+ ret = clk_hw_register(NULL, &priv->hw);
+ if (ret) {
+ kfree(priv);
+ hw = ERR_PTR(ret);
+ }
+
+ return hw;
+}
diff --git a/drivers/clk/imx/clk-imx25.c b/drivers/clk/imx/clk-imx25.c
index 66192fe0a898..cc013b343e62 100644
--- a/drivers/clk/imx/clk-imx25.c
+++ b/drivers/clk/imx/clk-imx25.c
@@ -218,7 +218,7 @@ static int __init __mx25_clocks_init(void __iomem *ccm_base)
*/
clk_set_parent(clk[cko_sel], clk[ipg]);
- imx_register_uart_clocks(6);
+ imx_register_uart_clocks();
return 0;
}
diff --git a/drivers/clk/imx/clk-imx27.c b/drivers/clk/imx/clk-imx27.c
index 56a5fc402b10..5d177125728d 100644
--- a/drivers/clk/imx/clk-imx27.c
+++ b/drivers/clk/imx/clk-imx27.c
@@ -165,7 +165,7 @@ static void __init _mx27_clocks_init(unsigned long fref)
clk_prepare_enable(clk[IMX27_CLK_EMI_AHB_GATE]);
- imx_register_uart_clocks(7);
+ imx_register_uart_clocks();
imx_print_silicon_rev("i.MX27", mx27_revision());
}
diff --git a/drivers/clk/imx/clk-imx35.c b/drivers/clk/imx/clk-imx35.c
index 0fe5ac210156..7dcbaea3fea3 100644
--- a/drivers/clk/imx/clk-imx35.c
+++ b/drivers/clk/imx/clk-imx35.c
@@ -235,7 +235,7 @@ static void __init _mx35_clocks_init(void)
*/
clk_prepare_enable(clk[scc_gate]);
- imx_register_uart_clocks(4);
+ imx_register_uart_clocks();
imx_print_silicon_rev("i.MX35", mx35_revision());
}
diff --git a/drivers/clk/imx/clk-imx5.c b/drivers/clk/imx/clk-imx5.c
index e4493846454d..b82044911603 100644
--- a/drivers/clk/imx/clk-imx5.c
+++ b/drivers/clk/imx/clk-imx5.c
@@ -358,7 +358,7 @@ static void __init mx50_clocks_init(struct device_node *np)
r = clk_round_rate(clk[IMX5_CLK_USBOH3_PER_GATE], 54000000);
clk_set_rate(clk[IMX5_CLK_USBOH3_PER_GATE], r);
- imx_register_uart_clocks(5);
+ imx_register_uart_clocks();
}
CLK_OF_DECLARE(imx50_ccm, "fsl,imx50-ccm", mx50_clocks_init);
@@ -464,7 +464,7 @@ static void __init mx51_clocks_init(struct device_node *np)
val |= 1 << 23;
writel(val, MXC_CCM_CLPCR);
- imx_register_uart_clocks(3);
+ imx_register_uart_clocks();
}
CLK_OF_DECLARE(imx51_ccm, "fsl,imx51-ccm", mx51_clocks_init);
@@ -609,6 +609,6 @@ static void __init mx53_clocks_init(struct device_node *np)
r = clk_round_rate(clk[IMX5_CLK_USBOH3_PER_GATE], 54000000);
clk_set_rate(clk[IMX5_CLK_USBOH3_PER_GATE], r);
- imx_register_uart_clocks(5);
+ imx_register_uart_clocks();
}
CLK_OF_DECLARE(imx53_ccm, "fsl,imx53-ccm", mx53_clocks_init);
diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c
index de36f58d551c..bf4c1d9c9928 100644
--- a/drivers/clk/imx/clk-imx6q.c
+++ b/drivers/clk/imx/clk-imx6q.c
@@ -12,6 +12,7 @@
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/io.h>
+#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
@@ -115,6 +116,10 @@ static struct clk_div_table video_div_table[] = {
{ /* sentinel */ }
};
+static const char * enet_ref_sels[] = { "enet_ref", "enet_ref_pad", };
+static const u32 enet_ref_sels_table[] = { IMX6Q_GPR1_ENET_CLK_SEL_ANATOP, IMX6Q_GPR1_ENET_CLK_SEL_PAD };
+static const u32 enet_ref_sels_table_mask = IMX6Q_GPR1_ENET_CLK_SEL_ANATOP;
+
static unsigned int share_count_esai;
static unsigned int share_count_asrc;
static unsigned int share_count_ssi1;
@@ -908,6 +913,12 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
if (clk_on_imx6q() && imx_get_soc_revision() == IMX_CHIP_REVISION_1_0)
hws[IMX6QDL_CLK_GPT_3M] = hws[IMX6QDL_CLK_GPT_IPG_PER];
+ hws[IMX6QDL_CLK_ENET_REF_PAD] = imx6q_obtain_fixed_clk_hw(ccm_node, "enet_ref_pad", 0);
+
+ hws[IMX6QDL_CLK_ENET_REF_SEL] = imx_clk_gpr_mux("enet_ref_sel", "fsl,imx6q-iomuxc-gpr",
+ IOMUXC_GPR1, enet_ref_sels, ARRAY_SIZE(enet_ref_sels),
+ enet_ref_sels_table, enet_ref_sels_table_mask);
+
imx_check_clk_hws(hws, IMX6QDL_CLK_END);
of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);
@@ -974,6 +985,8 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
hws[IMX6QDL_CLK_PLL3_USB_OTG]->clk);
}
- imx_register_uart_clocks(2);
+ clk_set_parent(hws[IMX6QDL_CLK_ENET_REF_SEL]->clk, hws[IMX6QDL_CLK_ENET_REF]->clk);
+
+ imx_register_uart_clocks();
}
CLK_OF_DECLARE(imx6q, "fsl,imx6q-ccm", imx6q_clocks_init);
diff --git a/drivers/clk/imx/clk-imx6sl.c b/drivers/clk/imx/clk-imx6sl.c
index 277365970320..47b8667cfa3f 100644
--- a/drivers/clk/imx/clk-imx6sl.c
+++ b/drivers/clk/imx/clk-imx6sl.c
@@ -440,6 +440,6 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
clk_set_parent(hws[IMX6SL_CLK_LCDIF_AXI_SEL]->clk,
hws[IMX6SL_CLK_PLL2_PFD2]->clk);
- imx_register_uart_clocks(2);
+ imx_register_uart_clocks();
}
CLK_OF_DECLARE(imx6sl, "fsl,imx6sl-ccm", imx6sl_clocks_init);
diff --git a/drivers/clk/imx/clk-imx6sll.c b/drivers/clk/imx/clk-imx6sll.c
index 1c9351649eab..2fa70bf35e45 100644
--- a/drivers/clk/imx/clk-imx6sll.c
+++ b/drivers/clk/imx/clk-imx6sll.c
@@ -340,7 +340,7 @@ static void __init imx6sll_clocks_init(struct device_node *ccm_node)
of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);
- imx_register_uart_clocks(5);
+ imx_register_uart_clocks();
/* Lower the AHB clock rate before changing the clock source. */
clk_set_rate(hws[IMX6SLL_CLK_AHB]->clk, 99000000);
diff --git a/drivers/clk/imx/clk-imx6sx.c b/drivers/clk/imx/clk-imx6sx.c
index b378531240e6..7cf86707bc39 100644
--- a/drivers/clk/imx/clk-imx6sx.c
+++ b/drivers/clk/imx/clk-imx6sx.c
@@ -548,6 +548,6 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
clk_set_parent(hws[IMX6SX_CLK_QSPI1_SEL]->clk, hws[IMX6SX_CLK_PLL2_BUS]->clk);
clk_set_parent(hws[IMX6SX_CLK_QSPI2_SEL]->clk, hws[IMX6SX_CLK_PLL2_BUS]->clk);
- imx_register_uart_clocks(2);
+ imx_register_uart_clocks();
}
CLK_OF_DECLARE(imx6sx, "fsl,imx6sx-ccm", imx6sx_clocks_init);
diff --git a/drivers/clk/imx/clk-imx6ul.c b/drivers/clk/imx/clk-imx6ul.c
index 67a7a77ca540..2836adb817b7 100644
--- a/drivers/clk/imx/clk-imx6ul.c
+++ b/drivers/clk/imx/clk-imx6ul.c
@@ -10,6 +10,7 @@
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
+#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
@@ -94,6 +95,17 @@ static const struct clk_div_table video_div_table[] = {
{ }
};
+static const char * enet1_ref_sels[] = { "enet1_ref_125m", "enet1_ref_pad", };
+static const u32 enet1_ref_sels_table[] = { IMX6UL_GPR1_ENET1_TX_CLK_DIR,
+ IMX6UL_GPR1_ENET1_CLK_SEL };
+static const u32 enet1_ref_sels_table_mask = IMX6UL_GPR1_ENET1_TX_CLK_DIR |
+ IMX6UL_GPR1_ENET1_CLK_SEL;
+static const char * enet2_ref_sels[] = { "enet2_ref_125m", "enet2_ref_pad", };
+static const u32 enet2_ref_sels_table[] = { IMX6UL_GPR1_ENET2_TX_CLK_DIR,
+ IMX6UL_GPR1_ENET2_CLK_SEL };
+static const u32 enet2_ref_sels_table_mask = IMX6UL_GPR1_ENET2_TX_CLK_DIR |
+ IMX6UL_GPR1_ENET2_CLK_SEL;
+
static u32 share_count_asrc;
static u32 share_count_audio;
static u32 share_count_sai1;
@@ -176,7 +188,7 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
hws[IMX6UL_CLK_PLL3_USB_OTG] = imx_clk_hw_gate("pll3_usb_otg", "pll3_bypass", base + 0x10, 13);
hws[IMX6UL_CLK_PLL4_AUDIO] = imx_clk_hw_gate("pll4_audio", "pll4_bypass", base + 0x70, 13);
hws[IMX6UL_CLK_PLL5_VIDEO] = imx_clk_hw_gate("pll5_video", "pll5_bypass", base + 0xa0, 13);
- hws[IMX6UL_CLK_PLL6_ENET] = imx_clk_hw_gate("pll6_enet", "pll6_bypass", base + 0xe0, 13);
+ hws[IMX6UL_CLK_PLL6_ENET] = imx_clk_hw_fixed_factor("pll6_enet", "pll6_bypass", 1, 1);
hws[IMX6UL_CLK_PLL7_USB_HOST] = imx_clk_hw_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13);
/*
@@ -205,12 +217,13 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
hws[IMX6UL_CLK_PLL3_PFD2] = imx_clk_hw_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0, 2);
hws[IMX6UL_CLK_PLL3_PFD3] = imx_clk_hw_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0, 3);
- hws[IMX6UL_CLK_ENET_REF] = clk_hw_register_divider_table(NULL, "enet_ref", "pll6_enet", 0,
+ hws[IMX6UL_CLK_ENET_REF] = clk_hw_register_divider_table(NULL, "enet1_ref", "pll6_enet", 0,
base + 0xe0, 0, 2, 0, clk_enet_ref_table, &imx_ccm_lock);
hws[IMX6UL_CLK_ENET2_REF] = clk_hw_register_divider_table(NULL, "enet2_ref", "pll6_enet", 0,
base + 0xe0, 2, 2, 0, clk_enet_ref_table, &imx_ccm_lock);
- hws[IMX6UL_CLK_ENET2_REF_125M] = imx_clk_hw_gate("enet_ref_125m", "enet2_ref", base + 0xe0, 20);
+ hws[IMX6UL_CLK_ENET1_REF_125M] = imx_clk_hw_gate("enet1_ref_125m", "enet1_ref", base + 0xe0, 13);
+ hws[IMX6UL_CLK_ENET2_REF_125M] = imx_clk_hw_gate("enet2_ref_125m", "enet2_ref", base + 0xe0, 20);
hws[IMX6UL_CLK_ENET_PTP_REF] = imx_clk_hw_fixed_factor("enet_ptp_ref", "pll6_enet", 1, 20);
hws[IMX6UL_CLK_ENET_PTP] = imx_clk_hw_gate("enet_ptp", "enet_ptp_ref", base + 0xe0, 21);
@@ -471,6 +484,17 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
/* mask handshake of mmdc */
imx_mmdc_mask_handshake(base, 0);
+ hws[IMX6UL_CLK_ENET1_REF_PAD] = imx_obtain_fixed_of_clock(ccm_node, "enet1_ref_pad", 0);
+
+ hws[IMX6UL_CLK_ENET1_REF_SEL] = imx_clk_gpr_mux("enet1_ref_sel", "fsl,imx6ul-iomuxc-gpr",
+ IOMUXC_GPR1, enet1_ref_sels, ARRAY_SIZE(enet1_ref_sels),
+ enet1_ref_sels_table, enet1_ref_sels_table_mask);
+ hws[IMX6UL_CLK_ENET2_REF_PAD] = imx_obtain_fixed_of_clock(ccm_node, "enet2_ref_pad", 0);
+
+ hws[IMX6UL_CLK_ENET2_REF_SEL] = imx_clk_gpr_mux("enet2_ref_sel", "fsl,imx6ul-iomuxc-gpr",
+ IOMUXC_GPR1, enet2_ref_sels, ARRAY_SIZE(enet2_ref_sels),
+ enet2_ref_sels_table, enet2_ref_sels_table_mask);
+
imx_check_clk_hws(hws, IMX6UL_CLK_END);
of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);
@@ -515,6 +539,9 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
clk_set_parent(hws[IMX6ULL_CLK_EPDC_PRE_SEL]->clk, hws[IMX6UL_CLK_PLL3_PFD2]->clk);
clk_set_parent(hws[IMX6UL_CLK_ENFC_SEL]->clk, hws[IMX6UL_CLK_PLL2_PFD2]->clk);
+
+ clk_set_parent(hws[IMX6UL_CLK_ENET1_REF_SEL]->clk, hws[IMX6UL_CLK_ENET_REF]->clk);
+ clk_set_parent(hws[IMX6UL_CLK_ENET2_REF_SEL]->clk, hws[IMX6UL_CLK_ENET2_REF]->clk);
}
CLK_OF_DECLARE(imx6ul, "fsl,imx6ul-ccm", imx6ul_clocks_init);
diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c
index d681b6c4b29a..2b77d1fc7bb9 100644
--- a/drivers/clk/imx/clk-imx7d.c
+++ b/drivers/clk/imx/clk-imx7d.c
@@ -882,7 +882,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
hws[IMX7D_USB1_MAIN_480M_CLK] = imx_clk_hw_fixed_factor("pll_usb1_main_clk", "osc", 20, 1);
hws[IMX7D_USB_MAIN_480M_CLK] = imx_clk_hw_fixed_factor("pll_usb_main_clk", "osc", 20, 1);
- imx_register_uart_clocks(7);
+ imx_register_uart_clocks();
}
CLK_OF_DECLARE(imx7d, "fsl,imx7d-ccm", imx7d_clocks_init);
diff --git a/drivers/clk/imx/clk-imx7ulp.c b/drivers/clk/imx/clk-imx7ulp.c
index 208a0ab80d5e..f4a48a42637f 100644
--- a/drivers/clk/imx/clk-imx7ulp.c
+++ b/drivers/clk/imx/clk-imx7ulp.c
@@ -176,7 +176,7 @@ static void __init imx7ulp_clk_pcc2_init(struct device_node *np)
of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
- imx_register_uart_clocks(2);
+ imx_register_uart_clocks();
}
CLK_OF_DECLARE(imx7ulp_clk_pcc2, "fsl,imx7ulp-pcc2", imx7ulp_clk_pcc2_init);
@@ -223,7 +223,7 @@ static void __init imx7ulp_clk_pcc3_init(struct device_node *np)
of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
- imx_register_uart_clocks(7);
+ imx_register_uart_clocks();
}
CLK_OF_DECLARE(imx7ulp_clk_pcc3, "fsl,imx7ulp-pcc3", imx7ulp_clk_pcc3_init);
diff --git a/drivers/clk/imx/clk-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c
index cb44e8148e53..b618892170f2 100644
--- a/drivers/clk/imx/clk-imx8mm.c
+++ b/drivers/clk/imx/clk-imx8mm.c
@@ -609,7 +609,7 @@ static int imx8mm_clocks_probe(struct platform_device *pdev)
goto unregister_hws;
}
- imx_register_uart_clocks(4);
+ imx_register_uart_clocks();
return 0;
diff --git a/drivers/clk/imx/clk-imx8mn.c b/drivers/clk/imx/clk-imx8mn.c
index af256ade554f..a042ed3a9d6c 100644
--- a/drivers/clk/imx/clk-imx8mn.c
+++ b/drivers/clk/imx/clk-imx8mn.c
@@ -602,7 +602,7 @@ static int imx8mn_clocks_probe(struct platform_device *pdev)
goto unregister_hws;
}
- imx_register_uart_clocks(4);
+ imx_register_uart_clocks();
return 0;
diff --git a/drivers/clk/imx/clk-imx8mp.c b/drivers/clk/imx/clk-imx8mp.c
index a57d877d393d..3253589851ff 100644
--- a/drivers/clk/imx/clk-imx8mp.c
+++ b/drivers/clk/imx/clk-imx8mp.c
@@ -723,7 +723,7 @@ static int imx8mp_clocks_probe(struct platform_device *pdev)
of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_hw_data);
- imx_register_uart_clocks(4);
+ imx_register_uart_clocks();
return 0;
}
diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c
index 2bcaec19a999..4bd65879fcd3 100644
--- a/drivers/clk/imx/clk-imx8mq.c
+++ b/drivers/clk/imx/clk-imx8mq.c
@@ -601,7 +601,7 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
goto unregister_hws;
}
- imx_register_uart_clocks(4);
+ imx_register_uart_clocks();
return 0;
diff --git a/drivers/clk/imx/clk-imx8ulp.c b/drivers/clk/imx/clk-imx8ulp.c
index 8eb1af2d6429..a07df3b44703 100644
--- a/drivers/clk/imx/clk-imx8ulp.c
+++ b/drivers/clk/imx/clk-imx8ulp.c
@@ -385,7 +385,7 @@ static int imx8ulp_clk_pcc3_init(struct platform_device *pdev)
if (ret)
return ret;
- imx_register_uart_clocks(1);
+ imx_register_uart_clocks();
/* register the pcc3 reset controller */
return imx8ulp_pcc_reset_init(pdev, base, pcc3_resets, ARRAY_SIZE(pcc3_resets));
diff --git a/drivers/clk/imx/clk-imx93.c b/drivers/clk/imx/clk-imx93.c
index e464d9e71fbc..8d0974db6bfd 100644
--- a/drivers/clk/imx/clk-imx93.c
+++ b/drivers/clk/imx/clk-imx93.c
@@ -326,6 +326,8 @@ static int imx93_clocks_probe(struct platform_device *pdev)
goto unregister_hws;
}
+ imx_register_uart_clocks();
+
return 0;
unregister_hws:
diff --git a/drivers/clk/imx/clk-imxrt1050.c b/drivers/clk/imx/clk-imxrt1050.c
index e972abd299a8..fd5c51fc92c0 100644
--- a/drivers/clk/imx/clk-imxrt1050.c
+++ b/drivers/clk/imx/clk-imxrt1050.c
@@ -167,3 +167,7 @@ static struct platform_driver imxrt1050_clk_driver = {
},
};
module_platform_driver(imxrt1050_clk_driver);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Jesse Taube <Mr.Bossman075@gmail.com>");
+MODULE_AUTHOR("Giulio Benetti <giulio.benetti@benettiengineering.com>");
diff --git a/drivers/clk/imx/clk-pfd.c b/drivers/clk/imx/clk-pfd.c
index 5d2a9a3be95e..5cf0149dfa15 100644
--- a/drivers/clk/imx/clk-pfd.c
+++ b/drivers/clk/imx/clk-pfd.c
@@ -5,6 +5,7 @@
*/
#include <linux/clk-provider.h>
+#include <linux/export.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/err.h>
@@ -153,3 +154,4 @@ struct clk_hw *imx_clk_hw_pfd(const char *name, const char *parent_name,
return hw;
}
+EXPORT_SYMBOL_GPL(imx_clk_hw_pfd);
diff --git a/drivers/clk/imx/clk-pll14xx.c b/drivers/clk/imx/clk-pll14xx.c
index 828336873a98..7150c59bbfc9 100644
--- a/drivers/clk/imx/clk-pll14xx.c
+++ b/drivers/clk/imx/clk-pll14xx.c
@@ -256,7 +256,7 @@ static unsigned long clk_pll14xx_recalc_rate(struct clk_hw *hw,
if (pll->type == PLL_1443X) {
pll_div_ctl1 = readl_relaxed(pll->base + DIV_CTL1);
- kdiv = FIELD_GET(KDIV_MASK, pll_div_ctl1);
+ kdiv = (s16)FIELD_GET(KDIV_MASK, pll_div_ctl1);
} else {
kdiv = 0;
}
diff --git a/drivers/clk/imx/clk-pllv3.c b/drivers/clk/imx/clk-pllv3.c
index eea32f87c60a..11fb238ee8f0 100644
--- a/drivers/clk/imx/clk-pllv3.c
+++ b/drivers/clk/imx/clk-pllv3.c
@@ -6,6 +6,7 @@
#include <linux/clk-provider.h>
#include <linux/delay.h>
+#include <linux/export.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/slab.h>
@@ -486,3 +487,4 @@ struct clk_hw *imx_clk_hw_pllv3(enum imx_pllv3_type type, const char *name,
return hw;
}
+EXPORT_SYMBOL_GPL(imx_clk_hw_pllv3);
diff --git a/drivers/clk/imx/clk.c b/drivers/clk/imx/clk.c
index b636cc099d96..19cde59a20cb 100644
--- a/drivers/clk/imx/clk.c
+++ b/drivers/clk/imx/clk.c
@@ -110,6 +110,20 @@ struct clk_hw *imx_obtain_fixed_clock_hw(
return __clk_get_hw(clk);
}
+struct clk_hw *imx_obtain_fixed_of_clock(struct device_node *np,
+ const char *name, unsigned long rate)
+{
+ struct clk *clk = of_clk_get_by_name(np, name);
+ struct clk_hw *hw;
+
+ if (IS_ERR(clk))
+ hw = imx_obtain_fixed_clock_hw(name, rate);
+ else
+ hw = __clk_get_hw(clk);
+
+ return hw;
+}
+
struct clk_hw *imx_get_clk_hw_by_name(struct device_node *np, const char *name)
{
struct clk *clk;
@@ -165,8 +179,10 @@ __setup_param("earlycon", imx_keep_uart_earlycon,
__setup_param("earlyprintk", imx_keep_uart_earlyprintk,
imx_keep_uart_clocks_param, 0);
-void imx_register_uart_clocks(unsigned int clk_count)
+void imx_register_uart_clocks(void)
{
+ unsigned int num __maybe_unused;
+
imx_enabled_uart_clocks = 0;
/* i.MX boards use device trees now. For build tests without CONFIG_OF, do nothing */
@@ -174,14 +190,18 @@ void imx_register_uart_clocks(unsigned int clk_count)
if (imx_keep_uart_clocks) {
int i;
- imx_uart_clocks = kcalloc(clk_count, sizeof(struct clk *), GFP_KERNEL);
- if (!imx_uart_clocks)
+ num = of_clk_get_parent_count(of_stdout);
+ if (!num)
return;
if (!of_stdout)
return;
- for (i = 0; i < clk_count; i++) {
+ imx_uart_clocks = kcalloc(num, sizeof(struct clk *), GFP_KERNEL);
+ if (!imx_uart_clocks)
+ return;
+
+ for (i = 0; i < num; i++) {
imx_uart_clocks[imx_enabled_uart_clocks] = of_clk_get(of_stdout, i);
/* Stop if there are no more of_stdout references */
@@ -205,9 +225,10 @@ static int __init imx_clk_disable_uart(void)
clk_disable_unprepare(imx_uart_clocks[i]);
clk_put(imx_uart_clocks[i]);
}
- kfree(imx_uart_clocks);
}
+ kfree(imx_uart_clocks);
+
return 0;
}
late_initcall_sync(imx_clk_disable_uart);
diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h
index 689b3ad927c0..3d94722bbf99 100644
--- a/drivers/clk/imx/clk.h
+++ b/drivers/clk/imx/clk.h
@@ -12,9 +12,9 @@ extern bool mcore_booted;
void imx_check_clocks(struct clk *clks[], unsigned int count);
void imx_check_clk_hws(struct clk_hw *clks[], unsigned int count);
#ifndef MODULE
-void imx_register_uart_clocks(unsigned int clk_count);
+void imx_register_uart_clocks(void);
#else
-static inline void imx_register_uart_clocks(unsigned int clk_count)
+static inline void imx_register_uart_clocks(void)
{
}
#endif
@@ -288,6 +288,9 @@ struct clk * imx_obtain_fixed_clock(
struct clk_hw *imx_obtain_fixed_clock_hw(
const char *name, unsigned long rate);
+struct clk_hw *imx_obtain_fixed_of_clock(struct device_node *np,
+ const char *name, unsigned long rate);
+
struct clk_hw *imx_get_clk_hw_by_name(struct device_node *np, const char *name);
struct clk_hw *imx_clk_hw_gate_exclusive(const char *name, const char *parent,
@@ -458,4 +461,9 @@ struct clk_hw *imx_clk_hw_divider_gate(const char *name, const char *parent_name
unsigned long flags, void __iomem *reg, u8 shift, u8 width,
u8 clk_divider_flags, const struct clk_div_table *table,
spinlock_t *lock);
+
+struct clk_hw *imx_clk_gpr_mux(const char *name, const char *compatible,
+ u32 reg, const char **parent_names,
+ u8 num_parents, const u32 *mux_table, u32 mask);
+
#endif
diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig
index 22e8e79475ee..2d14855dd37e 100644
--- a/drivers/clk/mediatek/Kconfig
+++ b/drivers/clk/mediatek/Kconfig
@@ -388,6 +388,23 @@ config COMMON_CLK_MT7629_HIFSYS
This driver supports MediaTek MT7629 HIFSYS clocks providing
to PCI-E and USB.
+config COMMON_CLK_MT7981
+ bool "Clock driver for MediaTek MT7981"
+ depends on ARCH_MEDIATEK || COMPILE_TEST
+ select COMMON_CLK_MEDIATEK
+ default ARCH_MEDIATEK
+ help
+ This driver supports MediaTek MT7981 basic clocks and clocks
+ required for various peripherals found on this SoC.
+
+config COMMON_CLK_MT7981_ETHSYS
+ tristate "Clock driver for MediaTek MT7981 ETHSYS"
+ depends on COMMON_CLK_MT7981
+ default COMMON_CLK_MT7981
+ help
+ This driver adds support for clocks for Ethernet and SGMII
+ required on MediaTek MT7981 SoC.
+
config COMMON_CLK_MT7986
bool "Clock driver for MediaTek MT7986"
depends on ARCH_MEDIATEK || COMPILE_TEST
@@ -457,19 +474,41 @@ config COMMON_CLK_MT8167_VDECSYS
This driver supports MediaTek MT8167 vdecsys clocks.
config COMMON_CLK_MT8173
- bool "Clock driver for MediaTek MT8173"
- depends on ARCH_MEDIATEK || COMPILE_TEST
+ tristate "Clock driver for MediaTek MT8173"
+ depends on ARM64 || COMPILE_TEST
select COMMON_CLK_MEDIATEK
default ARCH_MEDIATEK
help
- This driver supports MediaTek MT8173 clocks.
+ This driver supports MediaTek MT8173 basic clocks and clocks
+ required for various peripherals found on MediaTek.
+
+config COMMON_CLK_MT8173_IMGSYS
+ tristate "Clock driver for MediaTek MT8173 imgsys"
+ depends on COMMON_CLK_MT8173
+ default COMMON_CLK_MT8173
+ help
+ This driver supports MediaTek MT8173 imgsys clocks.
config COMMON_CLK_MT8173_MMSYS
- bool "Clock driver for MediaTek MT8173 mmsys"
+ tristate "Clock driver for MediaTek MT8173 mmsys"
+ depends on COMMON_CLK_MT8173
+ default COMMON_CLK_MT8173
+ help
+ This driver supports MediaTek MT8173 mmsys clocks.
+
+config COMMON_CLK_MT8173_VDECSYS
+ tristate "Clock driver for MediaTek MT8173 VDECSYS"
+ depends on COMMON_CLK_MT8173
+ default COMMON_CLK_MT8173
+ help
+ This driver supports MediaTek MT8173 vdecsys clocks.
+
+config COMMON_CLK_MT8173_VENCSYS
+ tristate "Clock driver for MediaTek MT8173 VENCSYS"
depends on COMMON_CLK_MT8173
default COMMON_CLK_MT8173
help
- This driver supports MediaTek MT8173 mmsys clocks.
+ This driver supports MediaTek MT8173 vencsys clocks.
config COMMON_CLK_MT8183
bool "Clock driver for MediaTek MT8183"
diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
index e24080fd6e7f..e5d018270ed0 100644
--- a/drivers/clk/mediatek/Makefile
+++ b/drivers/clk/mediatek/Makefile
@@ -53,6 +53,10 @@ obj-$(CONFIG_COMMON_CLK_MT7622_AUDSYS) += clk-mt7622-aud.o
obj-$(CONFIG_COMMON_CLK_MT7629) += clk-mt7629.o
obj-$(CONFIG_COMMON_CLK_MT7629_ETHSYS) += clk-mt7629-eth.o
obj-$(CONFIG_COMMON_CLK_MT7629_HIFSYS) += clk-mt7629-hif.o
+obj-$(CONFIG_COMMON_CLK_MT7981) += clk-mt7981-apmixed.o
+obj-$(CONFIG_COMMON_CLK_MT7981) += clk-mt7981-topckgen.o
+obj-$(CONFIG_COMMON_CLK_MT7981) += clk-mt7981-infracfg.o
+obj-$(CONFIG_COMMON_CLK_MT7981_ETHSYS) += clk-mt7981-eth.o
obj-$(CONFIG_COMMON_CLK_MT7986) += clk-mt7986-apmixed.o
obj-$(CONFIG_COMMON_CLK_MT7986) += clk-mt7986-topckgen.o
obj-$(CONFIG_COMMON_CLK_MT7986) += clk-mt7986-infracfg.o
@@ -64,8 +68,12 @@ obj-$(CONFIG_COMMON_CLK_MT8167_IMGSYS) += clk-mt8167-img.o
obj-$(CONFIG_COMMON_CLK_MT8167_MFGCFG) += clk-mt8167-mfgcfg.o
obj-$(CONFIG_COMMON_CLK_MT8167_MMSYS) += clk-mt8167-mm.o
obj-$(CONFIG_COMMON_CLK_MT8167_VDECSYS) += clk-mt8167-vdec.o
-obj-$(CONFIG_COMMON_CLK_MT8173) += clk-mt8173.o
+obj-$(CONFIG_COMMON_CLK_MT8173) += clk-mt8173-apmixedsys.o clk-mt8173-infracfg.o \
+ clk-mt8173-pericfg.o clk-mt8173-topckgen.o
+obj-$(CONFIG_COMMON_CLK_MT8173_IMGSYS) += clk-mt8173-img.o
obj-$(CONFIG_COMMON_CLK_MT8173_MMSYS) += clk-mt8173-mm.o
+obj-$(CONFIG_COMMON_CLK_MT8173_VDECSYS) += clk-mt8173-vdecsys.o
+obj-$(CONFIG_COMMON_CLK_MT8173_VENCSYS) += clk-mt8173-vencsys.o
obj-$(CONFIG_COMMON_CLK_MT8183) += clk-mt8183.o
obj-$(CONFIG_COMMON_CLK_MT8183_AUDIOSYS) += clk-mt8183-audio.o
obj-$(CONFIG_COMMON_CLK_MT8183_CAMSYS) += clk-mt8183-cam.o
diff --git a/drivers/clk/mediatek/clk-cpumux.c b/drivers/clk/mediatek/clk-cpumux.c
index 25618eff6f2a..da05f06192c0 100644
--- a/drivers/clk/mediatek/clk-cpumux.c
+++ b/drivers/clk/mediatek/clk-cpumux.c
@@ -58,7 +58,7 @@ static const struct clk_ops clk_cpumux_ops = {
};
static struct clk_hw *
-mtk_clk_register_cpumux(const struct mtk_composite *mux,
+mtk_clk_register_cpumux(struct device *dev, const struct mtk_composite *mux,
struct regmap *regmap)
{
struct mtk_clk_cpumux *cpumux;
@@ -81,7 +81,7 @@ mtk_clk_register_cpumux(const struct mtk_composite *mux,
cpumux->regmap = regmap;
cpumux->hw.init = &init;
- ret = clk_hw_register(NULL, &cpumux->hw);
+ ret = clk_hw_register(dev, &cpumux->hw);
if (ret) {
kfree(cpumux);
return ERR_PTR(ret);
@@ -102,7 +102,7 @@ static void mtk_clk_unregister_cpumux(struct clk_hw *hw)
kfree(cpumux);
}
-int mtk_clk_register_cpumuxes(struct device_node *node,
+int mtk_clk_register_cpumuxes(struct device *dev, struct device_node *node,
const struct mtk_composite *clks, int num,
struct clk_hw_onecell_data *clk_data)
{
@@ -125,7 +125,7 @@ int mtk_clk_register_cpumuxes(struct device_node *node,
continue;
}
- hw = mtk_clk_register_cpumux(mux, regmap);
+ hw = mtk_clk_register_cpumux(dev, mux, regmap);
if (IS_ERR(hw)) {
pr_err("Failed to register clk %s: %pe\n", mux->name,
hw);
diff --git a/drivers/clk/mediatek/clk-cpumux.h b/drivers/clk/mediatek/clk-cpumux.h
index 325adbef25d1..64e45c63b4a0 100644
--- a/drivers/clk/mediatek/clk-cpumux.h
+++ b/drivers/clk/mediatek/clk-cpumux.h
@@ -11,7 +11,7 @@ struct clk_hw_onecell_data;
struct device_node;
struct mtk_composite;
-int mtk_clk_register_cpumuxes(struct device_node *node,
+int mtk_clk_register_cpumuxes(struct device *dev, struct device_node *node,
const struct mtk_composite *clks, int num,
struct clk_hw_onecell_data *clk_data);
diff --git a/drivers/clk/mediatek/clk-gate.c b/drivers/clk/mediatek/clk-gate.c
index 0c867136e49d..67d9e741c5e7 100644
--- a/drivers/clk/mediatek/clk-gate.c
+++ b/drivers/clk/mediatek/clk-gate.c
@@ -152,12 +152,12 @@ const struct clk_ops mtk_clk_gate_ops_no_setclr_inv = {
};
EXPORT_SYMBOL_GPL(mtk_clk_gate_ops_no_setclr_inv);
-static struct clk_hw *mtk_clk_register_gate(const char *name,
+static struct clk_hw *mtk_clk_register_gate(struct device *dev, const char *name,
const char *parent_name,
struct regmap *regmap, int set_ofs,
int clr_ofs, int sta_ofs, u8 bit,
const struct clk_ops *ops,
- unsigned long flags, struct device *dev)
+ unsigned long flags)
{
struct mtk_clk_gate *cg;
int ret;
@@ -202,10 +202,9 @@ static void mtk_clk_unregister_gate(struct clk_hw *hw)
kfree(cg);
}
-int mtk_clk_register_gates_with_dev(struct device_node *node,
- const struct mtk_gate *clks, int num,
- struct clk_hw_onecell_data *clk_data,
- struct device *dev)
+int mtk_clk_register_gates(struct device *dev, struct device_node *node,
+ const struct mtk_gate *clks, int num,
+ struct clk_hw_onecell_data *clk_data)
{
int i;
struct clk_hw *hw;
@@ -229,13 +228,13 @@ int mtk_clk_register_gates_with_dev(struct device_node *node,
continue;
}
- hw = mtk_clk_register_gate(gate->name, gate->parent_name,
+ hw = mtk_clk_register_gate(dev, gate->name, gate->parent_name,
regmap,
gate->regs->set_ofs,
gate->regs->clr_ofs,
gate->regs->sta_ofs,
gate->shift, gate->ops,
- gate->flags, dev);
+ gate->flags);
if (IS_ERR(hw)) {
pr_err("Failed to register clk %s: %pe\n", gate->name,
@@ -261,14 +260,6 @@ err:
return PTR_ERR(hw);
}
-EXPORT_SYMBOL_GPL(mtk_clk_register_gates_with_dev);
-
-int mtk_clk_register_gates(struct device_node *node,
- const struct mtk_gate *clks, int num,
- struct clk_hw_onecell_data *clk_data)
-{
- return mtk_clk_register_gates_with_dev(node, clks, num, clk_data, NULL);
-}
EXPORT_SYMBOL_GPL(mtk_clk_register_gates);
void mtk_clk_unregister_gates(const struct mtk_gate *clks, int num,
diff --git a/drivers/clk/mediatek/clk-gate.h b/drivers/clk/mediatek/clk-gate.h
index d9897ef53528..1a46b4c56fc5 100644
--- a/drivers/clk/mediatek/clk-gate.h
+++ b/drivers/clk/mediatek/clk-gate.h
@@ -50,15 +50,10 @@ struct mtk_gate {
#define GATE_MTK(_id, _name, _parent, _regs, _shift, _ops) \
GATE_MTK_FLAGS(_id, _name, _parent, _regs, _shift, _ops, 0)
-int mtk_clk_register_gates(struct device_node *node,
+int mtk_clk_register_gates(struct device *dev, struct device_node *node,
const struct mtk_gate *clks, int num,
struct clk_hw_onecell_data *clk_data);
-int mtk_clk_register_gates_with_dev(struct device_node *node,
- const struct mtk_gate *clks, int num,
- struct clk_hw_onecell_data *clk_data,
- struct device *dev);
-
void mtk_clk_unregister_gates(const struct mtk_gate *clks, int num,
struct clk_hw_onecell_data *clk_data);
diff --git a/drivers/clk/mediatek/clk-mt2701-aud.c b/drivers/clk/mediatek/clk-mt2701-aud.c
index 6ba398eb7df9..1a32d8b7db84 100644
--- a/drivers/clk/mediatek/clk-mt2701-aud.c
+++ b/drivers/clk/mediatek/clk-mt2701-aud.c
@@ -76,6 +76,7 @@ static const struct mtk_gate_regs audio3_cg_regs = {
};
static const struct mtk_gate audio_clks[] = {
+ GATE_DUMMY(CLK_DUMMY, "aud_dummy"),
/* AUDIO0 */
GATE_AUDIO0(CLK_AUD_AFE, "audio_afe", "aud_intbus_sel", 2),
GATE_AUDIO0(CLK_AUD_HDMI, "audio_hdmi", "audpll_sel", 20),
@@ -138,29 +139,27 @@ static const struct mtk_gate audio_clks[] = {
GATE_AUDIO3(CLK_AUD_MEM_ASRC5, "audio_mem_asrc5", "asm_h_sel", 14),
};
+static const struct mtk_clk_desc audio_desc = {
+ .clks = audio_clks,
+ .num_clks = ARRAY_SIZE(audio_clks),
+};
+
static const struct of_device_id of_match_clk_mt2701_aud[] = {
- { .compatible = "mediatek,mt2701-audsys", },
- {}
+ { .compatible = "mediatek,mt2701-audsys", .data = &audio_desc },
+ { /* sentinel */ }
};
static int clk_mt2701_aud_probe(struct platform_device *pdev)
{
- struct clk_hw_onecell_data *clk_data;
- struct device_node *node = pdev->dev.of_node;
int r;
- clk_data = mtk_alloc_clk_data(CLK_AUD_NR);
-
- mtk_clk_register_gates(node, audio_clks, ARRAY_SIZE(audio_clks),
- clk_data);
-
- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+ r = mtk_clk_simple_probe(pdev);
if (r) {
dev_err(&pdev->dev,
"could not register clock provider: %s: %d\n",
pdev->name, r);
- goto err_clk_provider;
+ return r;
}
r = devm_of_platform_populate(&pdev->dev);
@@ -170,13 +169,19 @@ static int clk_mt2701_aud_probe(struct platform_device *pdev)
return 0;
err_plat_populate:
- of_clk_del_provider(node);
-err_clk_provider:
+ mtk_clk_simple_remove(pdev);
return r;
}
+static int clk_mt2701_aud_remove(struct platform_device *pdev)
+{
+ of_platform_depopulate(&pdev->dev);
+ return mtk_clk_simple_remove(pdev);
+}
+
static struct platform_driver clk_mt2701_aud_drv = {
.probe = clk_mt2701_aud_probe,
+ .remove = clk_mt2701_aud_remove,
.driver = {
.name = "clk-mt2701-aud",
.of_match_table = of_match_clk_mt2701_aud,
diff --git a/drivers/clk/mediatek/clk-mt2701-eth.c b/drivers/clk/mediatek/clk-mt2701-eth.c
index edf1e2ed2b59..f3cb78e7f6e9 100644
--- a/drivers/clk/mediatek/clk-mt2701-eth.c
+++ b/drivers/clk/mediatek/clk-mt2701-eth.c
@@ -26,6 +26,7 @@ static const struct mtk_gate_regs eth_cg_regs = {
}
static const struct mtk_gate eth_clks[] = {
+ GATE_DUMMY(CLK_DUMMY, "eth_dummy"),
GATE_ETH(CLK_ETHSYS_HSDMA, "hsdma_clk", "ethif_sel", 5),
GATE_ETH(CLK_ETHSYS_ESW, "esw_clk", "ethpll_500m_ck", 6),
GATE_ETH(CLK_ETHSYS_GP2, "gp2_clk", "trgpll", 7),
@@ -44,35 +45,20 @@ static const struct mtk_clk_rst_desc clk_rst_desc = {
.rst_bank_nr = ARRAY_SIZE(rst_ofs),
};
-static const struct of_device_id of_match_clk_mt2701_eth[] = {
- { .compatible = "mediatek,mt2701-ethsys", },
- {}
+static const struct mtk_clk_desc eth_desc = {
+ .clks = eth_clks,
+ .num_clks = ARRAY_SIZE(eth_clks),
+ .rst_desc = &clk_rst_desc,
};
-static int clk_mt2701_eth_probe(struct platform_device *pdev)
-{
- struct clk_hw_onecell_data *clk_data;
- int r;
- struct device_node *node = pdev->dev.of_node;
-
- clk_data = mtk_alloc_clk_data(CLK_ETHSYS_NR);
-
- mtk_clk_register_gates(node, eth_clks, ARRAY_SIZE(eth_clks),
- clk_data);
-
- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
- if (r)
- dev_err(&pdev->dev,
- "could not register clock provider: %s: %d\n",
- pdev->name, r);
-
- mtk_register_reset_controller_with_dev(&pdev->dev, &clk_rst_desc);
-
- return r;
-}
+static const struct of_device_id of_match_clk_mt2701_eth[] = {
+ { .compatible = "mediatek,mt2701-ethsys", .data = &eth_desc },
+ { /* sentinel */ }
+};
static struct platform_driver clk_mt2701_eth_drv = {
- .probe = clk_mt2701_eth_probe,
+ .probe = mtk_clk_simple_probe,
+ .remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt2701-eth",
.of_match_table = of_match_clk_mt2701_eth,
diff --git a/drivers/clk/mediatek/clk-mt2701-g3d.c b/drivers/clk/mediatek/clk-mt2701-g3d.c
index 1458109d99d9..499a170ba5f9 100644
--- a/drivers/clk/mediatek/clk-mt2701-g3d.c
+++ b/drivers/clk/mediatek/clk-mt2701-g3d.c
@@ -32,6 +32,7 @@ static const struct mtk_gate_regs g3d_cg_regs = {
};
static const struct mtk_gate g3d_clks[] = {
+ GATE_DUMMY(CLK_DUMMY, "g3d_dummy"),
GATE_G3D(CLK_G3DSYS_CORE, "g3d_core", "mfg_sel", 0),
};
@@ -43,57 +44,20 @@ static const struct mtk_clk_rst_desc clk_rst_desc = {
.rst_bank_nr = ARRAY_SIZE(rst_ofs),
};
-static int clk_mt2701_g3dsys_init(struct platform_device *pdev)
-{
- struct clk_hw_onecell_data *clk_data;
- struct device_node *node = pdev->dev.of_node;
- int r;
-
- clk_data = mtk_alloc_clk_data(CLK_G3DSYS_NR);
-
- mtk_clk_register_gates(node, g3d_clks, ARRAY_SIZE(g3d_clks),
- clk_data);
-
- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
- if (r)
- dev_err(&pdev->dev,
- "could not register clock provider: %s: %d\n",
- pdev->name, r);
-
- mtk_register_reset_controller_with_dev(&pdev->dev, &clk_rst_desc);
-
- return r;
-}
+static const struct mtk_clk_desc g3d_desc = {
+ .clks = g3d_clks,
+ .num_clks = ARRAY_SIZE(g3d_clks),
+ .rst_desc = &clk_rst_desc,
+};
static const struct of_device_id of_match_clk_mt2701_g3d[] = {
- {
- .compatible = "mediatek,mt2701-g3dsys",
- .data = clk_mt2701_g3dsys_init,
- }, {
- /* sentinel */
- }
+ { .compatible = "mediatek,mt2701-g3dsys", .data = &g3d_desc },
+ { /* sentinel */ }
};
-static int clk_mt2701_g3d_probe(struct platform_device *pdev)
-{
- int (*clk_init)(struct platform_device *);
- int r;
-
- clk_init = of_device_get_match_data(&pdev->dev);
- if (!clk_init)
- return -EINVAL;
-
- r = clk_init(pdev);
- if (r)
- dev_err(&pdev->dev,
- "could not register clock provider: %s: %d\n",
- pdev->name, r);
-
- return r;
-}
-
static struct platform_driver clk_mt2701_g3d_drv = {
- .probe = clk_mt2701_g3d_probe,
+ .probe = mtk_clk_simple_probe,
+ .remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt2701-g3d",
.of_match_table = of_match_clk_mt2701_g3d,
diff --git a/drivers/clk/mediatek/clk-mt2701-hif.c b/drivers/clk/mediatek/clk-mt2701-hif.c
index 434cbbe8c037..d5465d782993 100644
--- a/drivers/clk/mediatek/clk-mt2701-hif.c
+++ b/drivers/clk/mediatek/clk-mt2701-hif.c
@@ -26,6 +26,7 @@ static const struct mtk_gate_regs hif_cg_regs = {
}
static const struct mtk_gate hif_clks[] = {
+ GATE_DUMMY(CLK_DUMMY, "hif_dummy"),
GATE_HIF(CLK_HIFSYS_USB0PHY, "usb0_phy_clk", "ethpll_500m_ck", 21),
GATE_HIF(CLK_HIFSYS_USB1PHY, "usb1_phy_clk", "ethpll_500m_ck", 22),
GATE_HIF(CLK_HIFSYS_PCIE0, "pcie0_clk", "ethpll_500m_ck", 24),
@@ -41,37 +42,20 @@ static const struct mtk_clk_rst_desc clk_rst_desc = {
.rst_bank_nr = ARRAY_SIZE(rst_ofs),
};
-static const struct of_device_id of_match_clk_mt2701_hif[] = {
- { .compatible = "mediatek,mt2701-hifsys", },
- {}
+static const struct mtk_clk_desc hif_desc = {
+ .clks = hif_clks,
+ .num_clks = ARRAY_SIZE(hif_clks),
+ .rst_desc = &clk_rst_desc,
};
-static int clk_mt2701_hif_probe(struct platform_device *pdev)
-{
- struct clk_hw_onecell_data *clk_data;
- int r;
- struct device_node *node = pdev->dev.of_node;
-
- clk_data = mtk_alloc_clk_data(CLK_HIFSYS_NR);
-
- mtk_clk_register_gates(node, hif_clks, ARRAY_SIZE(hif_clks),
- clk_data);
-
- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
- if (r) {
- dev_err(&pdev->dev,
- "could not register clock provider: %s: %d\n",
- pdev->name, r);
- return r;
- }
-
- mtk_register_reset_controller_with_dev(&pdev->dev, &clk_rst_desc);
-
- return 0;
-}
+static const struct of_device_id of_match_clk_mt2701_hif[] = {
+ { .compatible = "mediatek,mt2701-hifsys", .data = &hif_desc },
+ { /* sentinel */ }
+};
static struct platform_driver clk_mt2701_hif_drv = {
- .probe = clk_mt2701_hif_probe,
+ .probe = mtk_clk_simple_probe,
+ .remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt2701-hif",
.of_match_table = of_match_clk_mt2701_hif,
diff --git a/drivers/clk/mediatek/clk-mt2701-mm.c b/drivers/clk/mediatek/clk-mt2701-mm.c
index 9ea7abad99d2..23d5ddcc1d37 100644
--- a/drivers/clk/mediatek/clk-mt2701-mm.c
+++ b/drivers/clk/mediatek/clk-mt2701-mm.c
@@ -88,8 +88,8 @@ static int clk_mt2701_mm_probe(struct platform_device *pdev)
clk_data = mtk_alloc_clk_data(CLK_MM_NR);
- mtk_clk_register_gates(node, mm_clks, ARRAY_SIZE(mm_clks),
- clk_data);
+ mtk_clk_register_gates(&pdev->dev, node, mm_clks,
+ ARRAY_SIZE(mm_clks), clk_data);
r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
if (r)
diff --git a/drivers/clk/mediatek/clk-mt2701.c b/drivers/clk/mediatek/clk-mt2701.c
index 9b442af37e67..06ca81359d35 100644
--- a/drivers/clk/mediatek/clk-mt2701.c
+++ b/drivers/clk/mediatek/clk-mt2701.c
@@ -683,14 +683,15 @@ static int mtk_topckgen_init(struct platform_device *pdev)
mtk_clk_register_factors(top_fixed_divs, ARRAY_SIZE(top_fixed_divs),
clk_data);
- mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes),
- base, &mt2701_clk_lock, clk_data);
+ mtk_clk_register_composites(&pdev->dev, top_muxes,
+ ARRAY_SIZE(top_muxes), base,
+ &mt2701_clk_lock, clk_data);
mtk_clk_register_dividers(top_adj_divs, ARRAY_SIZE(top_adj_divs),
base, &mt2701_clk_lock, clk_data);
- mtk_clk_register_gates(node, top_clks, ARRAY_SIZE(top_clks),
- clk_data);
+ mtk_clk_register_gates(&pdev->dev, node, top_clks,
+ ARRAY_SIZE(top_clks), clk_data);
return of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
}
@@ -769,7 +770,7 @@ static void __init mtk_infrasys_init_early(struct device_node *node)
mtk_clk_register_factors(infra_fixed_divs, ARRAY_SIZE(infra_fixed_divs),
infra_clk_data);
- mtk_clk_register_cpumuxes(node, cpu_muxes, ARRAY_SIZE(cpu_muxes),
+ mtk_clk_register_cpumuxes(NULL, node, cpu_muxes, ARRAY_SIZE(cpu_muxes),
infra_clk_data);
r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get,
@@ -795,8 +796,8 @@ static int mtk_infrasys_init(struct platform_device *pdev)
}
}
- mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks),
- infra_clk_data);
+ mtk_clk_register_gates(&pdev->dev, node, infra_clks,
+ ARRAY_SIZE(infra_clks), infra_clk_data);
mtk_clk_register_factors(infra_fixed_divs, ARRAY_SIZE(infra_fixed_divs),
infra_clk_data);
@@ -918,11 +919,12 @@ static int mtk_pericfg_init(struct platform_device *pdev)
clk_data = mtk_alloc_clk_data(CLK_PERI_NR);
- mtk_clk_register_gates(node, peri_clks, ARRAY_SIZE(peri_clks),
- clk_data);
+ mtk_clk_register_gates(&pdev->dev, node, peri_clks,
+ ARRAY_SIZE(peri_clks), clk_data);
- mtk_clk_register_composites(peri_muxs, ARRAY_SIZE(peri_muxs), base,
- &mt2701_clk_lock, clk_data);
+ mtk_clk_register_composites(&pdev->dev, peri_muxs,
+ ARRAY_SIZE(peri_muxs), base,
+ &mt2701_clk_lock, clk_data);
r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
if (r)
diff --git a/drivers/clk/mediatek/clk-mt2712-mm.c b/drivers/clk/mediatek/clk-mt2712-mm.c
index 7d44b09b8a0a..25b8af640c12 100644
--- a/drivers/clk/mediatek/clk-mt2712-mm.c
+++ b/drivers/clk/mediatek/clk-mt2712-mm.c
@@ -135,8 +135,8 @@ static int clk_mt2712_mm_probe(struct platform_device *pdev)
clk_data = mtk_alloc_clk_data(CLK_MM_NR_CLK);
- mtk_clk_register_gates(node, mm_clks, ARRAY_SIZE(mm_clks),
- clk_data);
+ mtk_clk_register_gates(&pdev->dev, node, mm_clks,
+ ARRAY_SIZE(mm_clks), clk_data);
r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
diff --git a/drivers/clk/mediatek/clk-mt2712.c b/drivers/clk/mediatek/clk-mt2712.c
index 56980dd6c2ea..94f8fc2a4f7b 100644
--- a/drivers/clk/mediatek/clk-mt2712.c
+++ b/drivers/clk/mediatek/clk-mt2712.c
@@ -1346,12 +1346,13 @@ static int clk_mt2712_top_probe(struct platform_device *pdev)
mtk_clk_register_factors(top_early_divs, ARRAY_SIZE(top_early_divs),
top_clk_data);
mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), top_clk_data);
- mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes), base,
- &mt2712_clk_lock, top_clk_data);
+ mtk_clk_register_composites(&pdev->dev, top_muxes,
+ ARRAY_SIZE(top_muxes), base,
+ &mt2712_clk_lock, top_clk_data);
mtk_clk_register_dividers(top_adj_divs, ARRAY_SIZE(top_adj_divs), base,
&mt2712_clk_lock, top_clk_data);
- mtk_clk_register_gates(node, top_clks, ARRAY_SIZE(top_clks),
- top_clk_data);
+ mtk_clk_register_gates(&pdev->dev, node, top_clks,
+ ARRAY_SIZE(top_clks), top_clk_data);
r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, top_clk_data);
@@ -1362,50 +1363,6 @@ static int clk_mt2712_top_probe(struct platform_device *pdev)
return r;
}
-static int clk_mt2712_infra_probe(struct platform_device *pdev)
-{
- struct clk_hw_onecell_data *clk_data;
- int r;
- struct device_node *node = pdev->dev.of_node;
-
- clk_data = mtk_alloc_clk_data(CLK_INFRA_NR_CLK);
-
- mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks),
- clk_data);
-
- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
-
- if (r != 0)
- pr_err("%s(): could not register clock provider: %d\n",
- __func__, r);
-
- mtk_register_reset_controller_with_dev(&pdev->dev, &clk_rst_desc[0]);
-
- return r;
-}
-
-static int clk_mt2712_peri_probe(struct platform_device *pdev)
-{
- struct clk_hw_onecell_data *clk_data;
- int r;
- struct device_node *node = pdev->dev.of_node;
-
- clk_data = mtk_alloc_clk_data(CLK_PERI_NR_CLK);
-
- mtk_clk_register_gates(node, peri_clks, ARRAY_SIZE(peri_clks),
- clk_data);
-
- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
-
- if (r != 0)
- pr_err("%s(): could not register clock provider: %d\n",
- __func__, r);
-
- mtk_register_reset_controller_with_dev(&pdev->dev, &clk_rst_desc[1]);
-
- return r;
-}
-
static int clk_mt2712_mcu_probe(struct platform_device *pdev)
{
struct clk_hw_onecell_data *clk_data;
@@ -1421,8 +1378,11 @@ static int clk_mt2712_mcu_probe(struct platform_device *pdev)
clk_data = mtk_alloc_clk_data(CLK_MCU_NR_CLK);
- mtk_clk_register_composites(mcu_muxes, ARRAY_SIZE(mcu_muxes), base,
- &mt2712_clk_lock, clk_data);
+ r = mtk_clk_register_composites(&pdev->dev, mcu_muxes,
+ ARRAY_SIZE(mcu_muxes), base,
+ &mt2712_clk_lock, clk_data);
+ if (r)
+ dev_err(&pdev->dev, "Could not register composites: %d\n", r);
r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
@@ -1441,12 +1401,6 @@ static const struct of_device_id of_match_clk_mt2712[] = {
.compatible = "mediatek,mt2712-topckgen",
.data = clk_mt2712_top_probe,
}, {
- .compatible = "mediatek,mt2712-infracfg",
- .data = clk_mt2712_infra_probe,
- }, {
- .compatible = "mediatek,mt2712-pericfg",
- .data = clk_mt2712_peri_probe,
- }, {
.compatible = "mediatek,mt2712-mcucfg",
.data = clk_mt2712_mcu_probe,
}, {
@@ -1472,6 +1426,33 @@ static int clk_mt2712_probe(struct platform_device *pdev)
return r;
}
+static const struct mtk_clk_desc infra_desc = {
+ .clks = infra_clks,
+ .num_clks = ARRAY_SIZE(infra_clks),
+ .rst_desc = &clk_rst_desc[0],
+};
+
+static const struct mtk_clk_desc peri_desc = {
+ .clks = peri_clks,
+ .num_clks = ARRAY_SIZE(peri_clks),
+ .rst_desc = &clk_rst_desc[1],
+};
+
+static const struct of_device_id of_match_clk_mt2712_simple[] = {
+ { .compatible = "mediatek,mt2712-infracfg", .data = &infra_desc },
+ { .compatible = "mediatek,mt2712-pericfg", .data = &peri_desc, },
+ { /* sentinel */ }
+};
+
+static struct platform_driver clk_mt2712_simple_drv = {
+ .probe = mtk_clk_simple_probe,
+ .remove = mtk_clk_simple_remove,
+ .driver = {
+ .name = "clk-mt2712-simple",
+ .of_match_table = of_match_clk_mt2712_simple,
+ },
+};
+
static struct platform_driver clk_mt2712_drv = {
.probe = clk_mt2712_probe,
.driver = {
@@ -1482,7 +1463,11 @@ static struct platform_driver clk_mt2712_drv = {
static int __init clk_mt2712_init(void)
{
- return platform_driver_register(&clk_mt2712_drv);
+ int ret = platform_driver_register(&clk_mt2712_drv);
+
+ if (ret)
+ return ret;
+ return platform_driver_register(&clk_mt2712_simple_drv);
}
arch_initcall(clk_mt2712_init);
diff --git a/drivers/clk/mediatek/clk-mt6765.c b/drivers/clk/mediatek/clk-mt6765.c
index e9b9e6729733..6f5c92a7f620 100644
--- a/drivers/clk/mediatek/clk-mt6765.c
+++ b/drivers/clk/mediatek/clk-mt6765.c
@@ -789,7 +789,7 @@ static int clk_mt6765_apmixed_probe(struct platform_device *pdev)
mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
- mtk_clk_register_gates(node, apmixed_clks,
+ mtk_clk_register_gates(&pdev->dev, node, apmixed_clks,
ARRAY_SIZE(apmixed_clks), clk_data);
r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
@@ -826,10 +826,11 @@ static int clk_mt6765_top_probe(struct platform_device *pdev)
clk_data);
mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs),
clk_data);
- mtk_clk_register_muxes(top_muxes, ARRAY_SIZE(top_muxes), node,
+ mtk_clk_register_muxes(&pdev->dev, top_muxes,
+ ARRAY_SIZE(top_muxes), node,
&mt6765_clk_lock, clk_data);
- mtk_clk_register_gates(node, top_clks, ARRAY_SIZE(top_clks),
- clk_data);
+ mtk_clk_register_gates(&pdev->dev, node, top_clks,
+ ARRAY_SIZE(top_clks), clk_data);
r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
@@ -862,8 +863,8 @@ static int clk_mt6765_ifr_probe(struct platform_device *pdev)
clk_data = mtk_alloc_clk_data(CLK_IFR_NR_CLK);
- mtk_clk_register_gates(node, ifr_clks, ARRAY_SIZE(ifr_clks),
- clk_data);
+ mtk_clk_register_gates(&pdev->dev, node, ifr_clks,
+ ARRAY_SIZE(ifr_clks), clk_data);
r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
if (r)
diff --git a/drivers/clk/mediatek/clk-mt6779-mm.c b/drivers/clk/mediatek/clk-mt6779-mm.c
index eda8cbee3d23..2cccf62d3b36 100644
--- a/drivers/clk/mediatek/clk-mt6779-mm.c
+++ b/drivers/clk/mediatek/clk-mt6779-mm.c
@@ -93,8 +93,8 @@ static int clk_mt6779_mm_probe(struct platform_device *pdev)
clk_data = mtk_alloc_clk_data(CLK_MM_NR_CLK);
- mtk_clk_register_gates(node, mm_clks, ARRAY_SIZE(mm_clks),
- clk_data);
+ mtk_clk_register_gates(&pdev->dev, node, mm_clks,
+ ARRAY_SIZE(mm_clks), clk_data);
return of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
}
diff --git a/drivers/clk/mediatek/clk-mt6779.c b/drivers/clk/mediatek/clk-mt6779.c
index 0d0a90ee5eb2..827025d127d9 100644
--- a/drivers/clk/mediatek/clk-mt6779.c
+++ b/drivers/clk/mediatek/clk-mt6779.c
@@ -880,6 +880,7 @@ static const struct mtk_gate_regs infra3_cg_regs = {
&mtk_clk_gate_ops_setclr)
static const struct mtk_gate infra_clks[] = {
+ GATE_DUMMY(CLK_DUMMY, "ifa_dummy"),
/* INFRA0 */
GATE_INFRA0(CLK_INFRA_PMIC_TMR, "infra_pmic_tmr",
"axi_sel", 0),
@@ -1221,7 +1222,7 @@ static int clk_mt6779_apmixed_probe(struct platform_device *pdev)
mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
- mtk_clk_register_gates(node, apmixed_clks,
+ mtk_clk_register_gates(&pdev->dev, node, apmixed_clks,
ARRAY_SIZE(apmixed_clks), clk_data);
return of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
@@ -1244,27 +1245,17 @@ static int clk_mt6779_top_probe(struct platform_device *pdev)
mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), clk_data);
- mtk_clk_register_muxes(top_muxes, ARRAY_SIZE(top_muxes),
- node, &mt6779_clk_lock, clk_data);
+ mtk_clk_register_muxes(&pdev->dev, top_muxes,
+ ARRAY_SIZE(top_muxes), node,
+ &mt6779_clk_lock, clk_data);
- mtk_clk_register_composites(top_aud_muxes, ARRAY_SIZE(top_aud_muxes),
- base, &mt6779_clk_lock, clk_data);
+ mtk_clk_register_composites(&pdev->dev, top_aud_muxes,
+ ARRAY_SIZE(top_aud_muxes), base,
+ &mt6779_clk_lock, clk_data);
- mtk_clk_register_composites(top_aud_divs, ARRAY_SIZE(top_aud_divs),
- base, &mt6779_clk_lock, clk_data);
-
- return of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
-}
-
-static int clk_mt6779_infra_probe(struct platform_device *pdev)
-{
- struct clk_hw_onecell_data *clk_data;
- struct device_node *node = pdev->dev.of_node;
-
- clk_data = mtk_alloc_clk_data(CLK_INFRA_NR_CLK);
-
- mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks),
- clk_data);
+ mtk_clk_register_composites(&pdev->dev, top_aud_divs,
+ ARRAY_SIZE(top_aud_divs), base,
+ &mt6779_clk_lock, clk_data);
return of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
}
@@ -1277,9 +1268,6 @@ static const struct of_device_id of_match_clk_mt6779[] = {
.compatible = "mediatek,mt6779-topckgen",
.data = clk_mt6779_top_probe,
}, {
- .compatible = "mediatek,mt6779-infracfg_ao",
- .data = clk_mt6779_infra_probe,
- }, {
/* sentinel */
}
};
@@ -1302,6 +1290,25 @@ static int clk_mt6779_probe(struct platform_device *pdev)
return r;
}
+static const struct mtk_clk_desc infra_desc = {
+ .clks = infra_clks,
+ .num_clks = ARRAY_SIZE(infra_clks),
+};
+
+static const struct of_device_id of_match_clk_mt6779_infra[] = {
+ { .compatible = "mediatek,mt6779-infracfg_ao", .data = &infra_desc },
+ { /* sentinel */ }
+};
+
+static struct platform_driver clk_mt6779_infra_drv = {
+ .probe = mtk_clk_simple_probe,
+ .remove = mtk_clk_simple_remove,
+ .driver = {
+ .name = "clk-mt6779-infra",
+ .of_match_table = of_match_clk_mt6779_infra,
+ },
+};
+
static struct platform_driver clk_mt6779_drv = {
.probe = clk_mt6779_probe,
.driver = {
@@ -1312,7 +1319,11 @@ static struct platform_driver clk_mt6779_drv = {
static int __init clk_mt6779_init(void)
{
- return platform_driver_register(&clk_mt6779_drv);
+ int ret = platform_driver_register(&clk_mt6779_drv);
+
+ if (ret)
+ return ret;
+ return platform_driver_register(&clk_mt6779_infra_drv);
}
arch_initcall(clk_mt6779_init);
diff --git a/drivers/clk/mediatek/clk-mt6795-infracfg.c b/drivers/clk/mediatek/clk-mt6795-infracfg.c
index df7eed6e071e..23d9fc057e61 100644
--- a/drivers/clk/mediatek/clk-mt6795-infracfg.c
+++ b/drivers/clk/mediatek/clk-mt6795-infracfg.c
@@ -101,11 +101,13 @@ static int clk_mt6795_infracfg_probe(struct platform_device *pdev)
if (ret)
goto free_clk_data;
- ret = mtk_clk_register_gates(node, infra_gates, ARRAY_SIZE(infra_gates), clk_data);
+ ret = mtk_clk_register_gates(&pdev->dev, node, infra_gates,
+ ARRAY_SIZE(infra_gates), clk_data);
if (ret)
goto free_clk_data;
- ret = mtk_clk_register_cpumuxes(node, cpu_muxes, ARRAY_SIZE(cpu_muxes), clk_data);
+ ret = mtk_clk_register_cpumuxes(&pdev->dev, node, cpu_muxes,
+ ARRAY_SIZE(cpu_muxes), clk_data);
if (ret)
goto unregister_gates;
diff --git a/drivers/clk/mediatek/clk-mt6795-mm.c b/drivers/clk/mediatek/clk-mt6795-mm.c
index fd73f202f292..eebb6143ada2 100644
--- a/drivers/clk/mediatek/clk-mt6795-mm.c
+++ b/drivers/clk/mediatek/clk-mt6795-mm.c
@@ -87,7 +87,8 @@ static int clk_mt6795_mm_probe(struct platform_device *pdev)
if (!clk_data)
return -ENOMEM;
- ret = mtk_clk_register_gates(node, mm_gates, ARRAY_SIZE(mm_gates), clk_data);
+ ret = mtk_clk_register_gates(&pdev->dev, node, mm_gates,
+ ARRAY_SIZE(mm_gates), clk_data);
if (ret)
goto free_clk_data;
diff --git a/drivers/clk/mediatek/clk-mt6795-pericfg.c b/drivers/clk/mediatek/clk-mt6795-pericfg.c
index cb28d35dad59..08aaa9b09c36 100644
--- a/drivers/clk/mediatek/clk-mt6795-pericfg.c
+++ b/drivers/clk/mediatek/clk-mt6795-pericfg.c
@@ -109,11 +109,13 @@ static int clk_mt6795_pericfg_probe(struct platform_device *pdev)
if (ret)
goto free_clk_data;
- ret = mtk_clk_register_gates(node, peri_gates, ARRAY_SIZE(peri_gates), clk_data);
+ ret = mtk_clk_register_gates(&pdev->dev, node, peri_gates,
+ ARRAY_SIZE(peri_gates), clk_data);
if (ret)
goto free_clk_data;
- ret = mtk_clk_register_composites(peri_clks, ARRAY_SIZE(peri_clks), base,
+ ret = mtk_clk_register_composites(&pdev->dev, peri_clks,
+ ARRAY_SIZE(peri_clks), base,
&mt6795_peri_clk_lock, clk_data);
if (ret)
goto unregister_gates;
diff --git a/drivers/clk/mediatek/clk-mt6795-topckgen.c b/drivers/clk/mediatek/clk-mt6795-topckgen.c
index 8b8307635a35..e80fa588e309 100644
--- a/drivers/clk/mediatek/clk-mt6795-topckgen.c
+++ b/drivers/clk/mediatek/clk-mt6795-topckgen.c
@@ -523,86 +523,30 @@ static struct mtk_composite top_aud_divs[] = {
DIV_GATE(CLK_TOP_APLL2_DIV5, "apll2_div5", "apll2_div4", 0x12c, 21, 0x12c, 4, 4),
};
+static const struct mtk_clk_desc topck_desc = {
+ .fixed_clks = fixed_clks,
+ .num_fixed_clks = ARRAY_SIZE(fixed_clks),
+ .factor_clks = top_divs,
+ .num_factor_clks = ARRAY_SIZE(top_divs),
+ .mux_clks = top_muxes,
+ .num_mux_clks = ARRAY_SIZE(top_muxes),
+ .composite_clks = top_aud_divs,
+ .num_composite_clks = ARRAY_SIZE(top_aud_divs),
+ .clk_lock = &mt6795_top_clk_lock,
+};
static const struct of_device_id of_match_clk_mt6795_topckgen[] = {
- { .compatible = "mediatek,mt6795-topckgen" },
+ { .compatible = "mediatek,mt6795-topckgen", .data = &topck_desc },
{ /* sentinel */ }
};
-static int clk_mt6795_topckgen_probe(struct platform_device *pdev)
-{
- struct clk_hw_onecell_data *clk_data;
- struct device_node *node = pdev->dev.of_node;
- void __iomem *base;
- int ret;
-
- base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(base))
- return PTR_ERR(base);
-
- clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK);
- if (!clk_data)
- return -ENOMEM;
-
- ret = mtk_clk_register_fixed_clks(fixed_clks, ARRAY_SIZE(fixed_clks), clk_data);
- if (ret)
- goto free_clk_data;
-
- ret = mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), clk_data);
- if (ret)
- goto unregister_fixed_clks;
-
- ret = mtk_clk_register_muxes(top_muxes, ARRAY_SIZE(top_muxes), node,
- &mt6795_top_clk_lock, clk_data);
- if (ret)
- goto unregister_factors;
-
- ret = mtk_clk_register_composites(top_aud_divs, ARRAY_SIZE(top_aud_divs), base,
- &mt6795_top_clk_lock, clk_data);
- if (ret)
- goto unregister_muxes;
-
- ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
- if (ret)
- goto unregister_composites;
-
- return 0;
-
-unregister_composites:
- mtk_clk_unregister_composites(top_aud_divs, ARRAY_SIZE(top_aud_divs), clk_data);
-unregister_muxes:
- mtk_clk_unregister_muxes(top_muxes, ARRAY_SIZE(top_muxes), clk_data);
-unregister_factors:
- mtk_clk_unregister_factors(top_divs, ARRAY_SIZE(top_divs), clk_data);
-unregister_fixed_clks:
- mtk_clk_unregister_fixed_clks(fixed_clks, ARRAY_SIZE(fixed_clks), clk_data);
-free_clk_data:
- mtk_free_clk_data(clk_data);
- return ret;
-}
-
-static int clk_mt6795_topckgen_remove(struct platform_device *pdev)
-{
- struct device_node *node = pdev->dev.of_node;
- struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev);
-
- of_clk_del_provider(node);
- mtk_clk_unregister_composites(top_aud_divs, ARRAY_SIZE(top_aud_divs), clk_data);
- mtk_clk_unregister_muxes(top_muxes, ARRAY_SIZE(top_muxes), clk_data);
- mtk_clk_unregister_factors(top_divs, ARRAY_SIZE(top_divs), clk_data);
- mtk_clk_unregister_fixed_clks(fixed_clks, ARRAY_SIZE(fixed_clks), clk_data);
- mtk_free_clk_data(clk_data);
-
- return 0;
-}
-
static struct platform_driver clk_mt6795_topckgen_drv = {
.driver = {
.name = "clk-mt6795-topckgen",
.of_match_table = of_match_clk_mt6795_topckgen,
},
- .probe = clk_mt6795_topckgen_probe,
- .remove = clk_mt6795_topckgen_remove,
+ .probe = mtk_clk_simple_probe,
+ .remove = mtk_clk_simple_remove,
};
module_platform_driver(clk_mt6795_topckgen_drv);
diff --git a/drivers/clk/mediatek/clk-mt6797-mm.c b/drivers/clk/mediatek/clk-mt6797-mm.c
index 0846011fc894..deb16a6b16a5 100644
--- a/drivers/clk/mediatek/clk-mt6797-mm.c
+++ b/drivers/clk/mediatek/clk-mt6797-mm.c
@@ -101,8 +101,8 @@ static int clk_mt6797_mm_probe(struct platform_device *pdev)
clk_data = mtk_alloc_clk_data(CLK_MM_NR);
- mtk_clk_register_gates(node, mm_clks, ARRAY_SIZE(mm_clks),
- clk_data);
+ mtk_clk_register_gates(&pdev->dev, node, mm_clks,
+ ARRAY_SIZE(mm_clks), clk_data);
r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
if (r)
diff --git a/drivers/clk/mediatek/clk-mt6797.c b/drivers/clk/mediatek/clk-mt6797.c
index b89f325a4b9b..105a512857b3 100644
--- a/drivers/clk/mediatek/clk-mt6797.c
+++ b/drivers/clk/mediatek/clk-mt6797.c
@@ -396,7 +396,8 @@ static int mtk_topckgen_init(struct platform_device *pdev)
mtk_clk_register_factors(top_fixed_divs, ARRAY_SIZE(top_fixed_divs),
clk_data);
- mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes), base,
+ mtk_clk_register_composites(&pdev->dev, top_muxes,
+ ARRAY_SIZE(top_muxes), base,
&mt6797_clk_lock, clk_data);
return of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
@@ -596,8 +597,8 @@ static int mtk_infrasys_init(struct platform_device *pdev)
}
}
- mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks),
- infra_clk_data);
+ mtk_clk_register_gates(&pdev->dev, node, infra_clks,
+ ARRAY_SIZE(infra_clks), infra_clk_data);
mtk_clk_register_factors(infra_fixed_divs, ARRAY_SIZE(infra_fixed_divs),
infra_clk_data);
diff --git a/drivers/clk/mediatek/clk-mt7622-aud.c b/drivers/clk/mediatek/clk-mt7622-aud.c
index 9f2e5aa7b5d9..b8aabfeb1cba 100644
--- a/drivers/clk/mediatek/clk-mt7622-aud.c
+++ b/drivers/clk/mediatek/clk-mt7622-aud.c
@@ -130,24 +130,22 @@ static const struct mtk_gate audio_clks[] = {
GATE_AUDIO3(CLK_AUDIO_MEM_ASRC5, "audio_mem_asrc5", "asm_h_sel", 14),
};
-static int clk_mt7622_audiosys_init(struct platform_device *pdev)
+static const struct mtk_clk_desc audio_desc = {
+ .clks = audio_clks,
+ .num_clks = ARRAY_SIZE(audio_clks),
+};
+
+static int clk_mt7622_aud_probe(struct platform_device *pdev)
{
- struct clk_hw_onecell_data *clk_data;
- struct device_node *node = pdev->dev.of_node;
int r;
- clk_data = mtk_alloc_clk_data(CLK_AUDIO_NR_CLK);
-
- mtk_clk_register_gates(node, audio_clks, ARRAY_SIZE(audio_clks),
- clk_data);
-
- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+ r = mtk_clk_simple_probe(pdev);
if (r) {
dev_err(&pdev->dev,
"could not register clock provider: %s: %d\n",
pdev->name, r);
- goto err_clk_provider;
+ return r;
}
r = devm_of_platform_populate(&pdev->dev);
@@ -157,40 +155,24 @@ static int clk_mt7622_audiosys_init(struct platform_device *pdev)
return 0;
err_plat_populate:
- of_clk_del_provider(node);
-err_clk_provider:
+ mtk_clk_simple_remove(pdev);
return r;
}
-static const struct of_device_id of_match_clk_mt7622_aud[] = {
- {
- .compatible = "mediatek,mt7622-audsys",
- .data = clk_mt7622_audiosys_init,
- }, {
- /* sentinel */
- }
-};
-
-static int clk_mt7622_aud_probe(struct platform_device *pdev)
+static int clk_mt7622_aud_remove(struct platform_device *pdev)
{
- int (*clk_init)(struct platform_device *);
- int r;
-
- clk_init = of_device_get_match_data(&pdev->dev);
- if (!clk_init)
- return -EINVAL;
-
- r = clk_init(pdev);
- if (r)
- dev_err(&pdev->dev,
- "could not register clock provider: %s: %d\n",
- pdev->name, r);
-
- return r;
+ of_platform_depopulate(&pdev->dev);
+ return mtk_clk_simple_remove(pdev);
}
+static const struct of_device_id of_match_clk_mt7622_aud[] = {
+ { .compatible = "mediatek,mt7622-audsys", .data = &audio_desc },
+ { /* sentinel */ }
+};
+
static struct platform_driver clk_mt7622_aud_drv = {
.probe = clk_mt7622_aud_probe,
+ .remove = clk_mt7622_aud_remove,
.driver = {
.name = "clk-mt7622-aud",
.of_match_table = of_match_clk_mt7622_aud,
diff --git a/drivers/clk/mediatek/clk-mt7622-eth.c b/drivers/clk/mediatek/clk-mt7622-eth.c
index 43de0477d5d9..aee583fa77d0 100644
--- a/drivers/clk/mediatek/clk-mt7622-eth.c
+++ b/drivers/clk/mediatek/clk-mt7622-eth.c
@@ -73,80 +73,26 @@ static const struct mtk_clk_rst_desc clk_rst_desc = {
.rst_bank_nr = ARRAY_SIZE(rst_ofs),
};
-static int clk_mt7622_ethsys_init(struct platform_device *pdev)
-{
- struct clk_hw_onecell_data *clk_data;
- struct device_node *node = pdev->dev.of_node;
- int r;
-
- clk_data = mtk_alloc_clk_data(CLK_ETH_NR_CLK);
-
- mtk_clk_register_gates(node, eth_clks, ARRAY_SIZE(eth_clks),
- clk_data);
-
- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
- if (r)
- dev_err(&pdev->dev,
- "could not register clock provider: %s: %d\n",
- pdev->name, r);
-
- mtk_register_reset_controller_with_dev(&pdev->dev, &clk_rst_desc);
-
- return r;
-}
-
-static int clk_mt7622_sgmiisys_init(struct platform_device *pdev)
-{
- struct clk_hw_onecell_data *clk_data;
- struct device_node *node = pdev->dev.of_node;
- int r;
-
- clk_data = mtk_alloc_clk_data(CLK_SGMII_NR_CLK);
-
- mtk_clk_register_gates(node, sgmii_clks, ARRAY_SIZE(sgmii_clks),
- clk_data);
-
- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
- if (r)
- dev_err(&pdev->dev,
- "could not register clock provider: %s: %d\n",
- pdev->name, r);
+static const struct mtk_clk_desc eth_desc = {
+ .clks = eth_clks,
+ .num_clks = ARRAY_SIZE(eth_clks),
+ .rst_desc = &clk_rst_desc,
+};
- return r;
-}
+static const struct mtk_clk_desc sgmii_desc = {
+ .clks = sgmii_clks,
+ .num_clks = ARRAY_SIZE(sgmii_clks),
+};
static const struct of_device_id of_match_clk_mt7622_eth[] = {
- {
- .compatible = "mediatek,mt7622-ethsys",
- .data = clk_mt7622_ethsys_init,
- }, {
- .compatible = "mediatek,mt7622-sgmiisys",
- .data = clk_mt7622_sgmiisys_init,
- }, {
- /* sentinel */
- }
+ { .compatible = "mediatek,mt7622-ethsys", .data = &eth_desc },
+ { .compatible = "mediatek,mt7622-sgmiisys", .data = &sgmii_desc },
+ { /* sentinel */ }
};
-static int clk_mt7622_eth_probe(struct platform_device *pdev)
-{
- int (*clk_init)(struct platform_device *);
- int r;
-
- clk_init = of_device_get_match_data(&pdev->dev);
- if (!clk_init)
- return -EINVAL;
-
- r = clk_init(pdev);
- if (r)
- dev_err(&pdev->dev,
- "could not register clock provider: %s: %d\n",
- pdev->name, r);
-
- return r;
-}
-
static struct platform_driver clk_mt7622_eth_drv = {
- .probe = clk_mt7622_eth_probe,
+ .probe = mtk_clk_simple_probe,
+ .remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt7622-eth",
.of_match_table = of_match_clk_mt7622_eth,
diff --git a/drivers/clk/mediatek/clk-mt7622-hif.c b/drivers/clk/mediatek/clk-mt7622-hif.c
index 67e96231dd25..ab5cad0c2b1c 100644
--- a/drivers/clk/mediatek/clk-mt7622-hif.c
+++ b/drivers/clk/mediatek/clk-mt7622-hif.c
@@ -84,82 +84,27 @@ static const struct mtk_clk_rst_desc clk_rst_desc = {
.rst_bank_nr = ARRAY_SIZE(rst_ofs),
};
-static int clk_mt7622_ssusbsys_init(struct platform_device *pdev)
-{
- struct clk_hw_onecell_data *clk_data;
- struct device_node *node = pdev->dev.of_node;
- int r;
-
- clk_data = mtk_alloc_clk_data(CLK_SSUSB_NR_CLK);
-
- mtk_clk_register_gates(node, ssusb_clks, ARRAY_SIZE(ssusb_clks),
- clk_data);
-
- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
- if (r)
- dev_err(&pdev->dev,
- "could not register clock provider: %s: %d\n",
- pdev->name, r);
-
- mtk_register_reset_controller_with_dev(&pdev->dev, &clk_rst_desc);
-
- return r;
-}
-
-static int clk_mt7622_pciesys_init(struct platform_device *pdev)
-{
- struct clk_hw_onecell_data *clk_data;
- struct device_node *node = pdev->dev.of_node;
- int r;
-
- clk_data = mtk_alloc_clk_data(CLK_PCIE_NR_CLK);
-
- mtk_clk_register_gates(node, pcie_clks, ARRAY_SIZE(pcie_clks),
- clk_data);
-
- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
- if (r)
- dev_err(&pdev->dev,
- "could not register clock provider: %s: %d\n",
- pdev->name, r);
-
- mtk_register_reset_controller_with_dev(&pdev->dev, &clk_rst_desc);
+static const struct mtk_clk_desc ssusb_desc = {
+ .clks = ssusb_clks,
+ .num_clks = ARRAY_SIZE(ssusb_clks),
+ .rst_desc = &clk_rst_desc,
+};
- return r;
-}
+static const struct mtk_clk_desc pcie_desc = {
+ .clks = pcie_clks,
+ .num_clks = ARRAY_SIZE(pcie_clks),
+ .rst_desc = &clk_rst_desc,
+};
static const struct of_device_id of_match_clk_mt7622_hif[] = {
- {
- .compatible = "mediatek,mt7622-pciesys",
- .data = clk_mt7622_pciesys_init,
- }, {
- .compatible = "mediatek,mt7622-ssusbsys",
- .data = clk_mt7622_ssusbsys_init,
- }, {
- /* sentinel */
- }
+ { .compatible = "mediatek,mt7622-pciesys", .data = &pcie_desc },
+ { .compatible = "mediatek,mt7622-ssusbsys", .data = &ssusb_desc },
+ { /* sentinel */ }
};
-static int clk_mt7622_hif_probe(struct platform_device *pdev)
-{
- int (*clk_init)(struct platform_device *);
- int r;
-
- clk_init = of_device_get_match_data(&pdev->dev);
- if (!clk_init)
- return -EINVAL;
-
- r = clk_init(pdev);
- if (r)
- dev_err(&pdev->dev,
- "could not register clock provider: %s: %d\n",
- pdev->name, r);
-
- return r;
-}
-
static struct platform_driver clk_mt7622_hif_drv = {
- .probe = clk_mt7622_hif_probe,
+ .probe = mtk_clk_simple_probe,
+ .remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt7622-hif",
.of_match_table = of_match_clk_mt7622_hif,
diff --git a/drivers/clk/mediatek/clk-mt7622.c b/drivers/clk/mediatek/clk-mt7622.c
index 3b55f8641fae..5a82c2270bfb 100644
--- a/drivers/clk/mediatek/clk-mt7622.c
+++ b/drivers/clk/mediatek/clk-mt7622.c
@@ -646,14 +646,15 @@ static int mtk_topckgen_init(struct platform_device *pdev)
mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs),
clk_data);
- mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes),
- base, &mt7622_clk_lock, clk_data);
+ mtk_clk_register_composites(&pdev->dev, top_muxes,
+ ARRAY_SIZE(top_muxes), base,
+ &mt7622_clk_lock, clk_data);
mtk_clk_register_dividers(top_adj_divs, ARRAY_SIZE(top_adj_divs),
base, &mt7622_clk_lock, clk_data);
- mtk_clk_register_gates(node, top_clks, ARRAY_SIZE(top_clks),
- clk_data);
+ mtk_clk_register_gates(&pdev->dev, node, top_clks,
+ ARRAY_SIZE(top_clks), clk_data);
clk_prepare_enable(clk_data->hws[CLK_TOP_AXI_SEL]->clk);
clk_prepare_enable(clk_data->hws[CLK_TOP_MEM_SEL]->clk);
@@ -670,11 +671,11 @@ static int mtk_infrasys_init(struct platform_device *pdev)
clk_data = mtk_alloc_clk_data(CLK_INFRA_NR_CLK);
- mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks),
- clk_data);
+ mtk_clk_register_gates(&pdev->dev, node, infra_clks,
+ ARRAY_SIZE(infra_clks), clk_data);
- mtk_clk_register_cpumuxes(node, infra_muxes, ARRAY_SIZE(infra_muxes),
- clk_data);
+ mtk_clk_register_cpumuxes(&pdev->dev, node, infra_muxes,
+ ARRAY_SIZE(infra_muxes), clk_data);
r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get,
clk_data);
@@ -698,7 +699,7 @@ static int mtk_apmixedsys_init(struct platform_device *pdev)
mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls),
clk_data);
- mtk_clk_register_gates(node, apmixed_clks,
+ mtk_clk_register_gates(&pdev->dev, node, apmixed_clks,
ARRAY_SIZE(apmixed_clks), clk_data);
clk_prepare_enable(clk_data->hws[CLK_APMIXED_ARMPLL]->clk);
@@ -720,10 +721,11 @@ static int mtk_pericfg_init(struct platform_device *pdev)
clk_data = mtk_alloc_clk_data(CLK_PERI_NR_CLK);
- mtk_clk_register_gates(node, peri_clks, ARRAY_SIZE(peri_clks),
- clk_data);
+ mtk_clk_register_gates(&pdev->dev, node, peri_clks,
+ ARRAY_SIZE(peri_clks), clk_data);
- mtk_clk_register_composites(peri_muxes, ARRAY_SIZE(peri_muxes), base,
+ mtk_clk_register_composites(&pdev->dev, peri_muxes,
+ ARRAY_SIZE(peri_muxes), base,
&mt7622_clk_lock, clk_data);
r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
diff --git a/drivers/clk/mediatek/clk-mt7629-eth.c b/drivers/clk/mediatek/clk-mt7629-eth.c
index 282dd6559465..a4ae7d6c7a71 100644
--- a/drivers/clk/mediatek/clk-mt7629-eth.c
+++ b/drivers/clk/mediatek/clk-mt7629-eth.c
@@ -92,7 +92,8 @@ static int clk_mt7629_ethsys_init(struct platform_device *pdev)
clk_data = mtk_alloc_clk_data(CLK_ETH_NR_CLK);
- mtk_clk_register_gates(node, eth_clks, CLK_ETH_NR_CLK, clk_data);
+ mtk_clk_register_gates(&pdev->dev, node, eth_clks,
+ CLK_ETH_NR_CLK, clk_data);
r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
if (r)
@@ -114,8 +115,8 @@ static int clk_mt7629_sgmiisys_init(struct platform_device *pdev)
clk_data = mtk_alloc_clk_data(CLK_SGMII_NR_CLK);
- mtk_clk_register_gates(node, sgmii_clks[id++], CLK_SGMII_NR_CLK,
- clk_data);
+ mtk_clk_register_gates(&pdev->dev, node, sgmii_clks[id++],
+ CLK_SGMII_NR_CLK, clk_data);
r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
if (r)
diff --git a/drivers/clk/mediatek/clk-mt7629-hif.c b/drivers/clk/mediatek/clk-mt7629-hif.c
index 0c8b9e139789..c3eb09ea6036 100644
--- a/drivers/clk/mediatek/clk-mt7629-hif.c
+++ b/drivers/clk/mediatek/clk-mt7629-hif.c
@@ -79,82 +79,27 @@ static const struct mtk_clk_rst_desc clk_rst_desc = {
.rst_bank_nr = ARRAY_SIZE(rst_ofs),
};
-static int clk_mt7629_ssusbsys_init(struct platform_device *pdev)
-{
- struct clk_hw_onecell_data *clk_data;
- struct device_node *node = pdev->dev.of_node;
- int r;
-
- clk_data = mtk_alloc_clk_data(CLK_SSUSB_NR_CLK);
-
- mtk_clk_register_gates(node, ssusb_clks, ARRAY_SIZE(ssusb_clks),
- clk_data);
-
- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
- if (r)
- dev_err(&pdev->dev,
- "could not register clock provider: %s: %d\n",
- pdev->name, r);
-
- mtk_register_reset_controller_with_dev(&pdev->dev, &clk_rst_desc);
-
- return r;
-}
-
-static int clk_mt7629_pciesys_init(struct platform_device *pdev)
-{
- struct clk_hw_onecell_data *clk_data;
- struct device_node *node = pdev->dev.of_node;
- int r;
-
- clk_data = mtk_alloc_clk_data(CLK_PCIE_NR_CLK);
-
- mtk_clk_register_gates(node, pcie_clks, ARRAY_SIZE(pcie_clks),
- clk_data);
-
- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
- if (r)
- dev_err(&pdev->dev,
- "could not register clock provider: %s: %d\n",
- pdev->name, r);
-
- mtk_register_reset_controller_with_dev(&pdev->dev, &clk_rst_desc);
+static const struct mtk_clk_desc ssusb_desc = {
+ .clks = ssusb_clks,
+ .num_clks = ARRAY_SIZE(ssusb_clks),
+ .rst_desc = &clk_rst_desc,
+};
- return r;
-}
+static const struct mtk_clk_desc pcie_desc = {
+ .clks = pcie_clks,
+ .num_clks = ARRAY_SIZE(pcie_clks),
+ .rst_desc = &clk_rst_desc,
+};
static const struct of_device_id of_match_clk_mt7629_hif[] = {
- {
- .compatible = "mediatek,mt7629-pciesys",
- .data = clk_mt7629_pciesys_init,
- }, {
- .compatible = "mediatek,mt7629-ssusbsys",
- .data = clk_mt7629_ssusbsys_init,
- }, {
- /* sentinel */
- }
+ { .compatible = "mediatek,mt7629-pciesys", .data = &pcie_desc },
+ { .compatible = "mediatek,mt7629-ssusbsys", .data = &ssusb_desc },
+ { /* sentinel */ }
};
-static int clk_mt7629_hif_probe(struct platform_device *pdev)
-{
- int (*clk_init)(struct platform_device *);
- int r;
-
- clk_init = of_device_get_match_data(&pdev->dev);
- if (!clk_init)
- return -EINVAL;
-
- r = clk_init(pdev);
- if (r)
- dev_err(&pdev->dev,
- "could not register clock provider: %s: %d\n",
- pdev->name, r);
-
- return r;
-}
-
static struct platform_driver clk_mt7629_hif_drv = {
- .probe = clk_mt7629_hif_probe,
+ .probe = mtk_clk_simple_probe,
+ .remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt7629-hif",
.of_match_table = of_match_clk_mt7629_hif,
diff --git a/drivers/clk/mediatek/clk-mt7629.c b/drivers/clk/mediatek/clk-mt7629.c
index e4a08c811adc..cf062d4a7ecc 100644
--- a/drivers/clk/mediatek/clk-mt7629.c
+++ b/drivers/clk/mediatek/clk-mt7629.c
@@ -588,8 +588,9 @@ static int mtk_topckgen_init(struct platform_device *pdev)
mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs),
clk_data);
- mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes),
- base, &mt7629_clk_lock, clk_data);
+ mtk_clk_register_composites(&pdev->dev, top_muxes,
+ ARRAY_SIZE(top_muxes), base,
+ &mt7629_clk_lock, clk_data);
clk_prepare_enable(clk_data->hws[CLK_TOP_AXI_SEL]->clk);
clk_prepare_enable(clk_data->hws[CLK_TOP_MEM_SEL]->clk);
@@ -605,11 +606,11 @@ static int mtk_infrasys_init(struct platform_device *pdev)
clk_data = mtk_alloc_clk_data(CLK_INFRA_NR_CLK);
- mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks),
- clk_data);
+ mtk_clk_register_gates(&pdev->dev, node, infra_clks,
+ ARRAY_SIZE(infra_clks), clk_data);
- mtk_clk_register_cpumuxes(node, infra_muxes, ARRAY_SIZE(infra_muxes),
- clk_data);
+ mtk_clk_register_cpumuxes(&pdev->dev, node, infra_muxes,
+ ARRAY_SIZE(infra_muxes), clk_data);
return of_clk_add_hw_provider(node, of_clk_hw_onecell_get,
clk_data);
@@ -628,10 +629,11 @@ static int mtk_pericfg_init(struct platform_device *pdev)
clk_data = mtk_alloc_clk_data(CLK_PERI_NR_CLK);
- mtk_clk_register_gates(node, peri_clks, ARRAY_SIZE(peri_clks),
- clk_data);
+ mtk_clk_register_gates(&pdev->dev, node, peri_clks,
+ ARRAY_SIZE(peri_clks), clk_data);
- mtk_clk_register_composites(peri_muxes, ARRAY_SIZE(peri_muxes), base,
+ mtk_clk_register_composites(&pdev->dev, peri_muxes,
+ ARRAY_SIZE(peri_muxes), base,
&mt7629_clk_lock, clk_data);
r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
@@ -655,7 +657,7 @@ static int mtk_apmixedsys_init(struct platform_device *pdev)
mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls),
clk_data);
- mtk_clk_register_gates(node, apmixed_clks,
+ mtk_clk_register_gates(&pdev->dev, node, apmixed_clks,
ARRAY_SIZE(apmixed_clks), clk_data);
clk_prepare_enable(clk_data->hws[CLK_APMIXED_ARMPLL]->clk);
diff --git a/drivers/clk/mediatek/clk-mt7981-apmixed.c b/drivers/clk/mediatek/clk-mt7981-apmixed.c
new file mode 100644
index 000000000000..52b7123232bf
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt7981-apmixed.c
@@ -0,0 +1,102 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ * Author: Sam Shih <sam.shih@mediatek.com>
+ * Author: Wenzhen Yu <wenzhen.yu@mediatek.com>
+ * Author: Jianhui Zhao <zhaojh329@gmail.com>
+ * Author: Daniel Golle <daniel@makrotopia.org>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#include "clk-gate.h"
+#include "clk-mtk.h"
+#include "clk-mux.h"
+#include "clk-pll.h"
+
+#include <dt-bindings/clock/mediatek,mt7981-clk.h>
+#include <linux/clk.h>
+
+#define MT7981_PLL_FMAX (2500UL * MHZ)
+#define CON0_MT7981_RST_BAR BIT(27)
+
+#define PLL_xtal(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \
+ _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift, \
+ _div_table, _parent_name) \
+ { \
+ .id = _id, .name = _name, .reg = _reg, .pwr_reg = _pwr_reg, \
+ .en_mask = _en_mask, .flags = _flags, \
+ .rst_bar_mask = CON0_MT7981_RST_BAR, .fmax = MT7981_PLL_FMAX, \
+ .pcwbits = _pcwbits, .pd_reg = _pd_reg, .pd_shift = _pd_shift, \
+ .tuner_reg = _tuner_reg, .pcw_reg = _pcw_reg, \
+ .pcw_shift = _pcw_shift, .div_table = _div_table, \
+ .parent_name = _parent_name, \
+ }
+
+#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, _pd_reg, \
+ _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift) \
+ PLL_xtal(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \
+ _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift, NULL, \
+ "clkxtal")
+
+static const struct mtk_pll_data plls[] = {
+ PLL(CLK_APMIXED_ARMPLL, "armpll", 0x0200, 0x020C, 0x00000001, PLL_AO,
+ 32, 0x0200, 4, 0, 0x0204, 0),
+ PLL(CLK_APMIXED_NET2PLL, "net2pll", 0x0210, 0x021C, 0x00000001, 0, 32,
+ 0x0210, 4, 0, 0x0214, 0),
+ PLL(CLK_APMIXED_MMPLL, "mmpll", 0x0220, 0x022C, 0x00000001, 0, 32,
+ 0x0220, 4, 0, 0x0224, 0),
+ PLL(CLK_APMIXED_SGMPLL, "sgmpll", 0x0230, 0x023C, 0x00000001, 0, 32,
+ 0x0230, 4, 0, 0x0234, 0),
+ PLL(CLK_APMIXED_WEDMCUPLL, "wedmcupll", 0x0240, 0x024C, 0x00000001, 0, 32,
+ 0x0240, 4, 0, 0x0244, 0),
+ PLL(CLK_APMIXED_NET1PLL, "net1pll", 0x0250, 0x025C, 0x00000001, 0, 32,
+ 0x0250, 4, 0, 0x0254, 0),
+ PLL(CLK_APMIXED_MPLL, "mpll", 0x0260, 0x0270, 0x00000001, 0, 32,
+ 0x0260, 4, 0, 0x0264, 0),
+ PLL(CLK_APMIXED_APLL2, "apll2", 0x0278, 0x0288, 0x00000001, 0, 32,
+ 0x0278, 4, 0, 0x027C, 0),
+};
+
+static const struct of_device_id of_match_clk_mt7981_apmixed[] = {
+ { .compatible = "mediatek,mt7981-apmixedsys", },
+ { /* sentinel */ }
+};
+
+static int clk_mt7981_apmixed_probe(struct platform_device *pdev)
+{
+ struct clk_hw_onecell_data *clk_data;
+ struct device_node *node = pdev->dev.of_node;
+ int r;
+
+ clk_data = mtk_alloc_clk_data(ARRAY_SIZE(plls));
+ if (!clk_data)
+ return -ENOMEM;
+
+ mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
+
+ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+ if (r) {
+ pr_err("%s(): could not register clock provider: %d\n",
+ __func__, r);
+ goto free_apmixed_data;
+ }
+ return r;
+
+free_apmixed_data:
+ mtk_free_clk_data(clk_data);
+ return r;
+}
+
+static struct platform_driver clk_mt7981_apmixed_drv = {
+ .probe = clk_mt7981_apmixed_probe,
+ .driver = {
+ .name = "clk-mt7981-apmixed",
+ .of_match_table = of_match_clk_mt7981_apmixed,
+ },
+};
+builtin_platform_driver(clk_mt7981_apmixed_drv);
diff --git a/drivers/clk/mediatek/clk-mt7981-eth.c b/drivers/clk/mediatek/clk-mt7981-eth.c
new file mode 100644
index 000000000000..773350911be2
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt7981-eth.c
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ * Author: Sam Shih <sam.shih@mediatek.com>
+ * Author: Wenzhen Yu <wenzhen.yu@mediatek.com>
+ * Author: Jianhui Zhao <zhaojh329@gmail.com>
+ * Author: Daniel Golle <daniel@makrotopia.org>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#include "clk-mtk.h"
+#include "clk-gate.h"
+
+#include <dt-bindings/clock/mediatek,mt7981-clk.h>
+
+static const struct mtk_gate_regs sgmii0_cg_regs = {
+ .set_ofs = 0xE4,
+ .clr_ofs = 0xE4,
+ .sta_ofs = 0xE4,
+};
+
+#define GATE_SGMII0(_id, _name, _parent, _shift) { \
+ .id = _id, \
+ .name = _name, \
+ .parent_name = _parent, \
+ .regs = &sgmii0_cg_regs, \
+ .shift = _shift, \
+ .ops = &mtk_clk_gate_ops_no_setclr_inv, \
+ }
+
+static const struct mtk_gate sgmii0_clks[] __initconst = {
+ GATE_SGMII0(CLK_SGM0_TX_EN, "sgm0_tx_en", "usb_tx250m", 2),
+ GATE_SGMII0(CLK_SGM0_RX_EN, "sgm0_rx_en", "usb_eq_rx250m", 3),
+ GATE_SGMII0(CLK_SGM0_CK0_EN, "sgm0_ck0_en", "usb_ln0", 4),
+ GATE_SGMII0(CLK_SGM0_CDR_CK0_EN, "sgm0_cdr_ck0_en", "usb_cdr", 5),
+};
+
+static const struct mtk_gate_regs sgmii1_cg_regs = {
+ .set_ofs = 0xE4,
+ .clr_ofs = 0xE4,
+ .sta_ofs = 0xE4,
+};
+
+#define GATE_SGMII1(_id, _name, _parent, _shift) { \
+ .id = _id, \
+ .name = _name, \
+ .parent_name = _parent, \
+ .regs = &sgmii1_cg_regs, \
+ .shift = _shift, \
+ .ops = &mtk_clk_gate_ops_no_setclr_inv, \
+ }
+
+static const struct mtk_gate sgmii1_clks[] __initconst = {
+ GATE_SGMII1(CLK_SGM1_TX_EN, "sgm1_tx_en", "usb_tx250m", 2),
+ GATE_SGMII1(CLK_SGM1_RX_EN, "sgm1_rx_en", "usb_eq_rx250m", 3),
+ GATE_SGMII1(CLK_SGM1_CK1_EN, "sgm1_ck1_en", "usb_ln0", 4),
+ GATE_SGMII1(CLK_SGM1_CDR_CK1_EN, "sgm1_cdr_ck1_en", "usb_cdr", 5),
+};
+
+static const struct mtk_gate_regs eth_cg_regs = {
+ .set_ofs = 0x30,
+ .clr_ofs = 0x30,
+ .sta_ofs = 0x30,
+};
+
+#define GATE_ETH(_id, _name, _parent, _shift) { \
+ .id = _id, \
+ .name = _name, \
+ .parent_name = _parent, \
+ .regs = &eth_cg_regs, \
+ .shift = _shift, \
+ .ops = &mtk_clk_gate_ops_no_setclr_inv, \
+ }
+
+static const struct mtk_gate eth_clks[] __initconst = {
+ GATE_ETH(CLK_ETH_FE_EN, "eth_fe_en", "netsys_2x", 6),
+ GATE_ETH(CLK_ETH_GP2_EN, "eth_gp2_en", "sgm_325m", 7),
+ GATE_ETH(CLK_ETH_GP1_EN, "eth_gp1_en", "sgm_325m", 8),
+ GATE_ETH(CLK_ETH_WOCPU0_EN, "eth_wocpu0_en", "netsys_wed_mcu", 15),
+};
+
+static const struct mtk_clk_desc eth_desc = {
+ .clks = eth_clks,
+ .num_clks = ARRAY_SIZE(eth_clks),
+};
+
+static const struct mtk_clk_desc sgmii0_desc = {
+ .clks = sgmii0_clks,
+ .num_clks = ARRAY_SIZE(sgmii0_clks),
+};
+
+static const struct mtk_clk_desc sgmii1_desc = {
+ .clks = sgmii1_clks,
+ .num_clks = ARRAY_SIZE(sgmii1_clks),
+};
+
+static const struct of_device_id of_match_clk_mt7981_eth[] = {
+ { .compatible = "mediatek,mt7981-ethsys", .data = &eth_desc },
+ { .compatible = "mediatek,mt7981-sgmiisys_0", .data = &sgmii0_desc },
+ { .compatible = "mediatek,mt7981-sgmiisys_1", .data = &sgmii1_desc },
+ { /* sentinel */ }
+};
+
+static struct platform_driver clk_mt7981_eth_drv = {
+ .probe = mtk_clk_simple_probe,
+ .remove = mtk_clk_simple_remove,
+ .driver = {
+ .name = "clk-mt7981-eth",
+ .of_match_table = of_match_clk_mt7981_eth,
+ },
+};
+module_platform_driver(clk_mt7981_eth_drv);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/mediatek/clk-mt7981-infracfg.c b/drivers/clk/mediatek/clk-mt7981-infracfg.c
new file mode 100644
index 000000000000..8cf5057419e8
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt7981-infracfg.c
@@ -0,0 +1,207 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ * Author: Sam Shih <sam.shih@mediatek.com>
+ * Author: Wenzhen Yu <wenzhen.yu@mediatek.com>
+ * Author: Jianhui Zhao <zhaojh329@gmail.com>
+ * Author: Daniel Golle <daniel@makrotopia.org>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include "clk-mtk.h"
+#include "clk-gate.h"
+#include "clk-mux.h"
+
+#include <dt-bindings/clock/mediatek,mt7981-clk.h>
+#include <linux/clk.h>
+
+static DEFINE_SPINLOCK(mt7981_clk_lock);
+
+static const struct mtk_fixed_factor infra_divs[] = {
+ FACTOR(CLK_INFRA_66M_MCK, "infra_66m_mck", "sysaxi_sel", 1, 2),
+};
+
+static const char *const infra_uart_parent[] __initconst = { "csw_f26m_sel",
+ "uart_sel" };
+
+static const char *const infra_spi0_parents[] __initconst = { "i2c_sel",
+ "spi_sel" };
+
+static const char *const infra_spi1_parents[] __initconst = { "i2c_sel",
+ "spim_mst_sel" };
+
+static const char *const infra_pwm1_parents[] __initconst = { "pwm_sel" };
+
+static const char *const infra_pwm_bsel_parents[] __initconst = {
+ "cb_rtc_32p7k", "csw_f26m_sel", "infra_66m_mck", "pwm_sel"
+};
+
+static const char *const infra_pcie_parents[] __initconst = {
+ "cb_rtc_32p7k", "csw_f26m_sel", "cb_cksq_40m", "pextp_tl_ck_sel"
+};
+
+static const struct mtk_mux infra_muxes[] = {
+ /* MODULE_CLK_SEL_0 */
+ MUX_GATE_CLR_SET_UPD(CLK_INFRA_UART0_SEL, "infra_uart0_sel",
+ infra_uart_parent, 0x0018, 0x0010, 0x0014, 0, 1,
+ -1, -1, -1),
+ MUX_GATE_CLR_SET_UPD(CLK_INFRA_UART1_SEL, "infra_uart1_sel",
+ infra_uart_parent, 0x0018, 0x0010, 0x0014, 1, 1,
+ -1, -1, -1),
+ MUX_GATE_CLR_SET_UPD(CLK_INFRA_UART2_SEL, "infra_uart2_sel",
+ infra_uart_parent, 0x0018, 0x0010, 0x0014, 2, 1,
+ -1, -1, -1),
+ MUX_GATE_CLR_SET_UPD(CLK_INFRA_SPI0_SEL, "infra_spi0_sel",
+ infra_spi0_parents, 0x0018, 0x0010, 0x0014, 4, 1,
+ -1, -1, -1),
+ MUX_GATE_CLR_SET_UPD(CLK_INFRA_SPI1_SEL, "infra_spi1_sel",
+ infra_spi1_parents, 0x0018, 0x0010, 0x0014, 5, 1,
+ -1, -1, -1),
+ MUX_GATE_CLR_SET_UPD(CLK_INFRA_SPI2_SEL, "infra_spi2_sel",
+ infra_spi0_parents, 0x0018, 0x0010, 0x0014, 6, 1,
+ -1, -1, -1),
+ MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM1_SEL, "infra_pwm1_sel",
+ infra_pwm1_parents, 0x0018, 0x0010, 0x0014, 9, 1,
+ -1, -1, -1),
+ MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM2_SEL, "infra_pwm2_sel",
+ infra_pwm1_parents, 0x0018, 0x0010, 0x0014, 11, 1,
+ -1, -1, -1),
+ MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM3_SEL, "infra_pwm3_sel",
+ infra_pwm1_parents, 0x0018, 0x0010, 0x0014, 15, 1,
+ -1, -1, -1),
+ MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_BSEL, "infra_pwm_bsel",
+ infra_pwm_bsel_parents, 0x0018, 0x0010, 0x0014, 13,
+ 2, -1, -1, -1),
+ /* MODULE_CLK_SEL_1 */
+ MUX_GATE_CLR_SET_UPD(CLK_INFRA_PCIE_SEL, "infra_pcie_sel",
+ infra_pcie_parents, 0x0028, 0x0020, 0x0024, 0, 2,
+ -1, -1, -1),
+};
+
+static const struct mtk_gate_regs infra0_cg_regs = {
+ .set_ofs = 0x40,
+ .clr_ofs = 0x44,
+ .sta_ofs = 0x48,
+};
+
+static const struct mtk_gate_regs infra1_cg_regs = {
+ .set_ofs = 0x50,
+ .clr_ofs = 0x54,
+ .sta_ofs = 0x58,
+};
+
+static const struct mtk_gate_regs infra2_cg_regs = {
+ .set_ofs = 0x60,
+ .clr_ofs = 0x64,
+ .sta_ofs = 0x68,
+};
+
+#define GATE_INFRA0(_id, _name, _parent, _shift) \
+ { \
+ .id = _id, .name = _name, .parent_name = _parent, \
+ .regs = &infra0_cg_regs, .shift = _shift, \
+ .ops = &mtk_clk_gate_ops_setclr, \
+ }
+
+#define GATE_INFRA1(_id, _name, _parent, _shift) \
+ { \
+ .id = _id, .name = _name, .parent_name = _parent, \
+ .regs = &infra1_cg_regs, .shift = _shift, \
+ .ops = &mtk_clk_gate_ops_setclr, \
+ }
+
+#define GATE_INFRA2(_id, _name, _parent, _shift) \
+ { \
+ .id = _id, .name = _name, .parent_name = _parent, \
+ .regs = &infra2_cg_regs, .shift = _shift, \
+ .ops = &mtk_clk_gate_ops_setclr, \
+ }
+
+static const struct mtk_gate infra_clks[] = {
+ /* INFRA0 */
+ GATE_INFRA0(CLK_INFRA_GPT_STA, "infra_gpt_sta", "infra_66m_mck", 0),
+ GATE_INFRA0(CLK_INFRA_PWM_HCK, "infra_pwm_hck", "infra_66m_mck", 1),
+ GATE_INFRA0(CLK_INFRA_PWM_STA, "infra_pwm_sta", "infra_pwm_bsel", 2),
+ GATE_INFRA0(CLK_INFRA_PWM1_CK, "infra_pwm1", "infra_pwm1_sel", 3),
+ GATE_INFRA0(CLK_INFRA_PWM2_CK, "infra_pwm2", "infra_pwm2_sel", 4),
+ GATE_INFRA0(CLK_INFRA_CQ_DMA_CK, "infra_cq_dma", "sysaxi", 6),
+
+ GATE_INFRA0(CLK_INFRA_AUD_BUS_CK, "infra_aud_bus", "sysaxi", 8),
+ GATE_INFRA0(CLK_INFRA_AUD_26M_CK, "infra_aud_26m", "csw_f26m_sel", 9),
+ GATE_INFRA0(CLK_INFRA_AUD_L_CK, "infra_aud_l", "aud_l", 10),
+ GATE_INFRA0(CLK_INFRA_AUD_AUD_CK, "infra_aud_aud", "a1sys", 11),
+ GATE_INFRA0(CLK_INFRA_AUD_EG2_CK, "infra_aud_eg2", "a_tuner", 13),
+ GATE_INFRA0(CLK_INFRA_DRAMC_26M_CK, "infra_dramc_26m", "csw_f26m_sel",
+ 14),
+ GATE_INFRA0(CLK_INFRA_DBG_CK, "infra_dbg", "infra_66m_mck", 15),
+ GATE_INFRA0(CLK_INFRA_AP_DMA_CK, "infra_ap_dma", "infra_66m_mck", 16),
+ GATE_INFRA0(CLK_INFRA_SEJ_CK, "infra_sej", "infra_66m_mck", 24),
+ GATE_INFRA0(CLK_INFRA_SEJ_13M_CK, "infra_sej_13m", "csw_f26m_sel", 25),
+ GATE_INFRA0(CLK_INFRA_PWM3_CK, "infra_pwm3", "infra_pwm3_sel", 27),
+ /* INFRA1 */
+ GATE_INFRA1(CLK_INFRA_THERM_CK, "infra_therm", "csw_f26m_sel", 0),
+ GATE_INFRA1(CLK_INFRA_I2C0_CK, "infra_i2c0", "i2c_bck", 1),
+ GATE_INFRA1(CLK_INFRA_UART0_CK, "infra_uart0", "infra_uart0_sel", 2),
+ GATE_INFRA1(CLK_INFRA_UART1_CK, "infra_uart1", "infra_uart1_sel", 3),
+ GATE_INFRA1(CLK_INFRA_UART2_CK, "infra_uart2", "infra_uart2_sel", 4),
+ GATE_INFRA1(CLK_INFRA_SPI2_CK, "infra_spi2", "infra_spi2_sel", 6),
+ GATE_INFRA1(CLK_INFRA_SPI2_HCK_CK, "infra_spi2_hck", "infra_66m_mck", 7),
+ GATE_INFRA1(CLK_INFRA_NFI1_CK, "infra_nfi1", "nfi1x", 8),
+ GATE_INFRA1(CLK_INFRA_SPINFI1_CK, "infra_spinfi1", "spinfi_bck", 9),
+ GATE_INFRA1(CLK_INFRA_NFI_HCK_CK, "infra_nfi_hck", "infra_66m_mck", 10),
+ GATE_INFRA1(CLK_INFRA_SPI0_CK, "infra_spi0", "infra_spi0_sel", 11),
+ GATE_INFRA1(CLK_INFRA_SPI1_CK, "infra_spi1", "infra_spi1_sel", 12),
+ GATE_INFRA1(CLK_INFRA_SPI0_HCK_CK, "infra_spi0_hck", "infra_66m_mck",
+ 13),
+ GATE_INFRA1(CLK_INFRA_SPI1_HCK_CK, "infra_spi1_hck", "infra_66m_mck",
+ 14),
+ GATE_INFRA1(CLK_INFRA_FRTC_CK, "infra_frtc", "cb_rtc_32k", 15),
+ GATE_INFRA1(CLK_INFRA_MSDC_CK, "infra_msdc", "emmc_400m", 16),
+ GATE_INFRA1(CLK_INFRA_MSDC_HCK_CK, "infra_msdc_hck", "emmc_208m", 17),
+ GATE_INFRA1(CLK_INFRA_MSDC_133M_CK, "infra_msdc_133m", "sysaxi", 18),
+ GATE_INFRA1(CLK_INFRA_MSDC_66M_CK, "infra_msdc_66m", "sysaxi", 19),
+ GATE_INFRA1(CLK_INFRA_ADC_26M_CK, "infra_adc_26m", "infra_adc_frc", 20),
+ GATE_INFRA1(CLK_INFRA_ADC_FRC_CK, "infra_adc_frc", "csw_f26m", 21),
+ GATE_INFRA1(CLK_INFRA_FBIST2FPC_CK, "infra_fbist2fpc", "nfi1x", 23),
+ GATE_INFRA1(CLK_INFRA_I2C_MCK_CK, "infra_i2c_mck", "sysaxi", 25),
+ GATE_INFRA1(CLK_INFRA_I2C_PCK_CK, "infra_i2c_pck", "infra_66m_mck", 26),
+ /* INFRA2 */
+ GATE_INFRA2(CLK_INFRA_IUSB_133_CK, "infra_iusb_133", "sysaxi", 0),
+ GATE_INFRA2(CLK_INFRA_IUSB_66M_CK, "infra_iusb_66m", "sysaxi", 1),
+ GATE_INFRA2(CLK_INFRA_IUSB_SYS_CK, "infra_iusb_sys", "u2u3_sys", 2),
+ GATE_INFRA2(CLK_INFRA_IUSB_CK, "infra_iusb", "u2u3_ref", 3),
+ GATE_INFRA2(CLK_INFRA_IPCIE_CK, "infra_ipcie", "pextp_tl", 12),
+ GATE_INFRA2(CLK_INFRA_IPCIE_PIPE_CK, "infra_ipcie_pipe", "cb_cksq_40m",
+ 13),
+ GATE_INFRA2(CLK_INFRA_IPCIER_CK, "infra_ipcier", "csw_f26m", 14),
+ GATE_INFRA2(CLK_INFRA_IPCIEB_CK, "infra_ipcieb", "sysaxi", 15),
+};
+
+static const struct mtk_clk_desc infracfg_desc = {
+ .factor_clks = infra_divs,
+ .num_factor_clks = ARRAY_SIZE(infra_divs),
+ .mux_clks = infra_muxes,
+ .num_mux_clks = ARRAY_SIZE(infra_muxes),
+ .clks = infra_clks,
+ .num_clks = ARRAY_SIZE(infra_clks),
+ .clk_lock = &mt7981_clk_lock,
+};
+
+static const struct of_device_id of_match_clk_mt7981_infracfg[] = {
+ { .compatible = "mediatek,mt7981-infracfg", .data = &infracfg_desc },
+ { /* sentinel */ }
+};
+
+static struct platform_driver clk_mt7981_infracfg_drv = {
+ .probe = mtk_clk_simple_probe,
+ .remove = mtk_clk_simple_remove,
+ .driver = {
+ .name = "clk-mt7981-infracfg",
+ .of_match_table = of_match_clk_mt7981_infracfg,
+ },
+};
+builtin_platform_driver(clk_mt7981_infracfg_drv);
diff --git a/drivers/clk/mediatek/clk-mt7981-topckgen.c b/drivers/clk/mediatek/clk-mt7981-topckgen.c
new file mode 100644
index 000000000000..74634d65f5f6
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt7981-topckgen.c
@@ -0,0 +1,422 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ * Author: Sam Shih <sam.shih@mediatek.com>
+ * Author: Wenzhen Yu <wenzhen.yu@mediatek.com>
+ * Author: Jianhui Zhao <zhaojh329@gmail.com>
+ */
+
+
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include "clk-mtk.h"
+#include "clk-gate.h"
+#include "clk-mux.h"
+
+#include <dt-bindings/clock/mediatek,mt7981-clk.h>
+#include <linux/clk.h>
+
+static DEFINE_SPINLOCK(mt7981_clk_lock);
+
+static const struct mtk_fixed_factor top_divs[] = {
+ FACTOR(CLK_TOP_CB_CKSQ_40M, "cb_cksq_40m", "clkxtal", 1, 1),
+ FACTOR(CLK_TOP_CB_M_416M, "cb_m_416m", "mpll", 1, 1),
+ FACTOR(CLK_TOP_CB_M_D2, "cb_m_d2", "mpll", 1, 2),
+ FACTOR(CLK_TOP_CB_M_D3, "cb_m_d3", "mpll", 1, 3),
+ FACTOR(CLK_TOP_M_D3_D2, "m_d3_d2", "mpll", 1, 2),
+ FACTOR(CLK_TOP_CB_M_D4, "cb_m_d4", "mpll", 1, 4),
+ FACTOR(CLK_TOP_CB_M_D8, "cb_m_d8", "mpll", 1, 8),
+ FACTOR(CLK_TOP_M_D8_D2, "m_d8_d2", "mpll", 1, 16),
+ FACTOR(CLK_TOP_CB_MM_720M, "cb_mm_720m", "mmpll", 1, 1),
+ FACTOR(CLK_TOP_CB_MM_D2, "cb_mm_d2", "mmpll", 1, 2),
+ FACTOR(CLK_TOP_CB_MM_D3, "cb_mm_d3", "mmpll", 1, 3),
+ FACTOR(CLK_TOP_CB_MM_D3_D5, "cb_mm_d3_d5", "mmpll", 1, 15),
+ FACTOR(CLK_TOP_CB_MM_D4, "cb_mm_d4", "mmpll", 1, 4),
+ FACTOR(CLK_TOP_CB_MM_D6, "cb_mm_d6", "mmpll", 1, 6),
+ FACTOR(CLK_TOP_MM_D6_D2, "mm_d6_d2", "mmpll", 1, 12),
+ FACTOR(CLK_TOP_CB_MM_D8, "cb_mm_d8", "mmpll", 1, 8),
+ FACTOR(CLK_TOP_CB_APLL2_196M, "cb_apll2_196m", "apll2", 1, 1),
+ FACTOR(CLK_TOP_APLL2_D2, "apll2_d2", "apll2", 1, 2),
+ FACTOR(CLK_TOP_APLL2_D4, "apll2_d4", "apll2", 1, 4),
+ FACTOR(CLK_TOP_NET1_2500M, "net1_2500m", "net1pll", 1, 1),
+ FACTOR(CLK_TOP_CB_NET1_D4, "cb_net1_d4", "net1pll", 1, 4),
+ FACTOR(CLK_TOP_CB_NET1_D5, "cb_net1_d5", "net1pll", 1, 5),
+ FACTOR(CLK_TOP_NET1_D5_D2, "net1_d5_d2", "net1pll", 1, 10),
+ FACTOR(CLK_TOP_NET1_D5_D4, "net1_d5_d4", "net1pll", 1, 20),
+ FACTOR(CLK_TOP_CB_NET1_D8, "cb_net1_d8", "net1pll", 1, 8),
+ FACTOR(CLK_TOP_NET1_D8_D2, "net1_d8_d2", "net1pll", 1, 16),
+ FACTOR(CLK_TOP_NET1_D8_D4, "net1_d8_d4", "net1pll", 1, 32),
+ FACTOR(CLK_TOP_CB_NET2_800M, "cb_net2_800m", "net2pll", 1, 1),
+ FACTOR(CLK_TOP_CB_NET2_D2, "cb_net2_d2", "net2pll", 1, 2),
+ FACTOR(CLK_TOP_CB_NET2_D4, "cb_net2_d4", "net2pll", 1, 4),
+ FACTOR(CLK_TOP_NET2_D4_D2, "net2_d4_d2", "net2pll", 1, 8),
+ FACTOR(CLK_TOP_NET2_D4_D4, "net2_d4_d4", "net2pll", 1, 16),
+ FACTOR(CLK_TOP_CB_NET2_D6, "cb_net2_d6", "net2pll", 1, 6),
+ FACTOR(CLK_TOP_CB_WEDMCU_208M, "cb_wedmcu_208m", "wedmcupll", 1, 1),
+ FACTOR(CLK_TOP_CB_SGM_325M, "cb_sgm_325m", "sgmpll", 1, 1),
+ FACTOR(CLK_TOP_CKSQ_40M_D2, "cksq_40m_d2", "cb_cksq_40m", 1, 2),
+ FACTOR(CLK_TOP_CB_RTC_32K, "cb_rtc_32k", "cb_cksq_40m", 1, 1250),
+ FACTOR(CLK_TOP_CB_RTC_32P7K, "cb_rtc_32p7k", "cb_cksq_40m", 1, 1220),
+ FACTOR(CLK_TOP_USB_TX250M, "usb_tx250m", "cb_cksq_40m", 1, 1),
+ FACTOR(CLK_TOP_FAUD, "faud", "aud_sel", 1, 1),
+ FACTOR(CLK_TOP_NFI1X, "nfi1x", "nfi1x_sel", 1, 1),
+ FACTOR(CLK_TOP_USB_EQ_RX250M, "usb_eq_rx250m", "cb_cksq_40m", 1, 1),
+ FACTOR(CLK_TOP_USB_CDR_CK, "usb_cdr", "cb_cksq_40m", 1, 1),
+ FACTOR(CLK_TOP_USB_LN0_CK, "usb_ln0", "cb_cksq_40m", 1, 1),
+ FACTOR(CLK_TOP_SPINFI_BCK, "spinfi_bck", "spinfi_sel", 1, 1),
+ FACTOR(CLK_TOP_SPI, "spi", "spi_sel", 1, 1),
+ FACTOR(CLK_TOP_SPIM_MST, "spim_mst", "spim_mst_sel", 1, 1),
+ FACTOR(CLK_TOP_UART_BCK, "uart_bck", "uart_sel", 1, 1),
+ FACTOR(CLK_TOP_PWM_BCK, "pwm_bck", "pwm_sel", 1, 1),
+ FACTOR(CLK_TOP_I2C_BCK, "i2c_bck", "i2c_sel", 1, 1),
+ FACTOR(CLK_TOP_PEXTP_TL, "pextp_tl", "pextp_tl_ck_sel", 1, 1),
+ FACTOR(CLK_TOP_EMMC_208M, "emmc_208m", "emmc_208m_sel", 1, 1),
+ FACTOR(CLK_TOP_EMMC_400M, "emmc_400m", "emmc_400m_sel", 1, 1),
+ FACTOR(CLK_TOP_DRAMC_REF, "dramc_ref", "dramc_sel", 1, 1),
+ FACTOR(CLK_TOP_DRAMC_MD32, "dramc_md32", "dramc_md32_sel", 1, 1),
+ FACTOR(CLK_TOP_SYSAXI, "sysaxi", "sysaxi_sel", 1, 1),
+ FACTOR(CLK_TOP_SYSAPB, "sysapb", "sysapb_sel", 1, 1),
+ FACTOR(CLK_TOP_ARM_DB_MAIN, "arm_db_main", "arm_db_main_sel", 1, 1),
+ FACTOR(CLK_TOP_AP2CNN_HOST, "ap2cnn_host", "ap2cnn_host_sel", 1, 1),
+ FACTOR(CLK_TOP_NETSYS, "netsys", "netsys_sel", 1, 1),
+ FACTOR(CLK_TOP_NETSYS_500M, "netsys_500m", "netsys_500m_sel", 1, 1),
+ FACTOR(CLK_TOP_NETSYS_WED_MCU, "netsys_wed_mcu", "netsys_mcu_sel", 1, 1),
+ FACTOR(CLK_TOP_NETSYS_2X, "netsys_2x", "netsys_2x_sel", 1, 1),
+ FACTOR(CLK_TOP_SGM_325M, "sgm_325m", "sgm_325m_sel", 1, 1),
+ FACTOR(CLK_TOP_SGM_REG, "sgm_reg", "sgm_reg_sel", 1, 1),
+ FACTOR(CLK_TOP_F26M, "csw_f26m", "csw_f26m_sel", 1, 1),
+ FACTOR(CLK_TOP_EIP97B, "eip97b", "eip97b_sel", 1, 1),
+ FACTOR(CLK_TOP_USB3_PHY, "usb3_phy", "usb3_phy_sel", 1, 1),
+ FACTOR(CLK_TOP_AUD, "aud", "faud", 1, 1),
+ FACTOR(CLK_TOP_A1SYS, "a1sys", "a1sys_sel", 1, 1),
+ FACTOR(CLK_TOP_AUD_L, "aud_l", "aud_l_sel", 1, 1),
+ FACTOR(CLK_TOP_A_TUNER, "a_tuner", "a_tuner_sel", 1, 1),
+ FACTOR(CLK_TOP_U2U3_REF, "u2u3_ref", "u2u3_sel", 1, 1),
+ FACTOR(CLK_TOP_U2U3_SYS, "u2u3_sys", "u2u3_sys_sel", 1, 1),
+ FACTOR(CLK_TOP_U2U3_XHCI, "u2u3_xhci", "u2u3_xhci_sel", 1, 1),
+ FACTOR(CLK_TOP_USB_FRMCNT, "usb_frmcnt", "usb_frmcnt_sel", 1, 1),
+};
+
+static const char * const nfi1x_parents[] __initconst = {
+ "cb_cksq_40m",
+ "cb_mm_d4",
+ "net1_d8_d2",
+ "cb_net2_d6",
+ "cb_m_d4",
+ "cb_mm_d8",
+ "net1_d8_d4",
+ "cb_m_d8"
+};
+
+static const char * const spinfi_parents[] __initconst = {
+ "cksq_40m_d2",
+ "cb_cksq_40m",
+ "net1_d5_d4",
+ "cb_m_d4",
+ "cb_mm_d8",
+ "net1_d8_d4",
+ "mm_d6_d2",
+ "cb_m_d8"
+};
+
+static const char * const spi_parents[] __initconst = {
+ "cb_cksq_40m",
+ "cb_m_d2",
+ "cb_mm_d4",
+ "net1_d8_d2",
+ "cb_net2_d6",
+ "net1_d5_d4",
+ "cb_m_d4",
+ "net1_d8_d4"
+};
+
+static const char * const uart_parents[] __initconst = {
+ "cb_cksq_40m",
+ "cb_m_d8",
+ "m_d8_d2"
+};
+
+static const char * const pwm_parents[] __initconst = {
+ "cb_cksq_40m",
+ "net1_d8_d2",
+ "net1_d5_d4",
+ "cb_m_d4",
+ "m_d8_d2",
+ "cb_rtc_32k"
+};
+
+static const char * const i2c_parents[] __initconst = {
+ "cb_cksq_40m",
+ "net1_d5_d4",
+ "cb_m_d4",
+ "net1_d8_d4"
+};
+
+static const char * const pextp_tl_ck_parents[] __initconst = {
+ "cb_cksq_40m",
+ "net1_d5_d4",
+ "cb_m_d4",
+ "cb_rtc_32k"
+};
+
+static const char * const emmc_208m_parents[] __initconst = {
+ "cb_cksq_40m",
+ "cb_m_d2",
+ "cb_net2_d4",
+ "cb_apll2_196m",
+ "cb_mm_d4",
+ "net1_d8_d2",
+ "cb_mm_d6"
+};
+
+static const char * const emmc_400m_parents[] __initconst = {
+ "cb_cksq_40m",
+ "cb_net2_d2",
+ "cb_mm_d2",
+ "cb_net2_d2"
+};
+
+static const char * const csw_f26m_parents[] __initconst = {
+ "cksq_40m_d2",
+ "m_d8_d2"
+};
+
+static const char * const dramc_md32_parents[] __initconst = {
+ "cb_cksq_40m",
+ "cb_m_d2",
+ "cb_wedmcu_208m"
+};
+
+static const char * const sysaxi_parents[] __initconst = {
+ "cb_cksq_40m",
+ "net1_d8_d2"
+};
+
+static const char * const sysapb_parents[] __initconst = {
+ "cb_cksq_40m",
+ "m_d3_d2"
+};
+
+static const char * const arm_db_main_parents[] __initconst = {
+ "cb_cksq_40m",
+ "cb_net2_d6"
+};
+
+static const char * const ap2cnn_host_parents[] __initconst = {
+ "cb_cksq_40m",
+ "net1_d8_d4"
+};
+
+static const char * const netsys_parents[] __initconst = {
+ "cb_cksq_40m",
+ "cb_mm_d2"
+};
+
+static const char * const netsys_500m_parents[] __initconst = {
+ "cb_cksq_40m",
+ "cb_net1_d5"
+};
+
+static const char * const netsys_mcu_parents[] __initconst = {
+ "cb_cksq_40m",
+ "cb_mm_720m",
+ "cb_net1_d4",
+ "cb_net1_d5",
+ "cb_m_416m"
+};
+
+static const char * const netsys_2x_parents[] __initconst = {
+ "cb_cksq_40m",
+ "cb_net2_800m",
+ "cb_mm_720m"
+};
+
+static const char * const sgm_325m_parents[] __initconst = {
+ "cb_cksq_40m",
+ "cb_sgm_325m"
+};
+
+static const char * const sgm_reg_parents[] __initconst = {
+ "cb_cksq_40m",
+ "cb_net2_d4"
+};
+
+static const char * const eip97b_parents[] __initconst = {
+ "cb_cksq_40m",
+ "cb_net1_d5",
+ "cb_m_416m",
+ "cb_mm_d2",
+ "net1_d5_d2"
+};
+
+static const char * const aud_parents[] __initconst = {
+ "cb_cksq_40m",
+ "cb_apll2_196m"
+};
+
+static const char * const a1sys_parents[] __initconst = {
+ "cb_cksq_40m",
+ "apll2_d4"
+};
+
+static const char * const aud_l_parents[] __initconst = {
+ "cb_cksq_40m",
+ "cb_apll2_196m",
+ "m_d8_d2"
+};
+
+static const char * const a_tuner_parents[] __initconst = {
+ "cb_cksq_40m",
+ "apll2_d4",
+ "m_d8_d2"
+};
+
+static const char * const u2u3_parents[] __initconst = {
+ "cb_cksq_40m",
+ "m_d8_d2"
+};
+
+static const char * const u2u3_sys_parents[] __initconst = {
+ "cb_cksq_40m",
+ "net1_d5_d4"
+};
+
+static const char * const usb_frmcnt_parents[] __initconst = {
+ "cb_cksq_40m",
+ "cb_mm_d3_d5"
+};
+
+static const struct mtk_mux top_muxes[] = {
+ /* CLK_CFG_0 */
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_NFI1X_SEL, "nfi1x_sel", nfi1x_parents,
+ 0x000, 0x004, 0x008, 0, 3, 7, 0x1C0, 0),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_SPINFI_SEL, "spinfi_sel", spinfi_parents,
+ 0x000, 0x004, 0x008, 8, 3, 15, 0x1C0, 1),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_SPI_SEL, "spi_sel", spi_parents,
+ 0x000, 0x004, 0x008, 16, 3, 23, 0x1C0, 2),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_SPIM_MST_SEL, "spim_mst_sel", spi_parents,
+ 0x000, 0x004, 0x008, 24, 3, 31, 0x1C0, 3),
+ /* CLK_CFG_1 */
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_UART_SEL, "uart_sel", uart_parents,
+ 0x010, 0x014, 0x018, 0, 2, 7, 0x1C0, 4),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_PWM_SEL, "pwm_sel", pwm_parents,
+ 0x010, 0x014, 0x018, 8, 3, 15, 0x1C0, 5),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_I2C_SEL, "i2c_sel", i2c_parents,
+ 0x010, 0x014, 0x018, 16, 2, 23, 0x1C0, 6),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_TL_SEL, "pextp_tl_ck_sel",
+ pextp_tl_ck_parents, 0x010, 0x014, 0x018, 24, 2, 31,
+ 0x1C0, 7),
+ /* CLK_CFG_2 */
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_EMMC_208M_SEL, "emmc_208m_sel",
+ emmc_208m_parents, 0x020, 0x024, 0x028, 0, 3, 7,
+ 0x1C0, 8),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_EMMC_400M_SEL, "emmc_400m_sel",
+ emmc_400m_parents, 0x020, 0x024, 0x028, 8, 2, 15,
+ 0x1C0, 9),
+ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_F26M_SEL, "csw_f26m_sel",
+ csw_f26m_parents, 0x020, 0x024, 0x028, 16, 1, 23,
+ 0x1C0, 10,
+ CLK_IS_CRITICAL | CLK_SET_RATE_PARENT),
+ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_DRAMC_SEL, "dramc_sel",
+ csw_f26m_parents, 0x020, 0x024, 0x028, 24, 1,
+ 31, 0x1C0, 11,
+ CLK_IS_CRITICAL | CLK_SET_RATE_PARENT),
+ /* CLK_CFG_3 */
+ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_DRAMC_MD32_SEL, "dramc_md32_sel",
+ dramc_md32_parents, 0x030, 0x034, 0x038, 0, 2,
+ 7, 0x1C0, 12,
+ CLK_IS_CRITICAL | CLK_SET_RATE_PARENT),
+ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_SYSAXI_SEL, "sysaxi_sel",
+ sysaxi_parents, 0x030, 0x034, 0x038, 8, 1, 15,
+ 0x1C0, 13,
+ CLK_IS_CRITICAL | CLK_SET_RATE_PARENT),
+ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_SYSAPB_SEL, "sysapb_sel",
+ sysapb_parents, 0x030, 0x034, 0x038, 16, 1,
+ 23, 0x1C0, 14,
+ CLK_IS_CRITICAL | CLK_SET_RATE_PARENT),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_ARM_DB_MAIN_SEL, "arm_db_main_sel",
+ arm_db_main_parents, 0x030, 0x034, 0x038, 24, 1, 31,
+ 0x1C0, 15),
+ /* CLK_CFG_4 */
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_AP2CNN_HOST_SEL, "ap2cnn_host_sel",
+ ap2cnn_host_parents, 0x040, 0x044, 0x048, 0, 1, 7,
+ 0x1C0, 16),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_SEL, "netsys_sel", netsys_parents,
+ 0x040, 0x044, 0x048, 8, 1, 15, 0x1C0, 17),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_500M_SEL, "netsys_500m_sel",
+ netsys_500m_parents, 0x040, 0x044, 0x048, 16, 1, 23,
+ 0x1C0, 18),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_MCU_SEL, "netsys_mcu_sel",
+ netsys_mcu_parents, 0x040, 0x044, 0x048, 24, 3, 31,
+ 0x1C0, 19),
+ /* CLK_CFG_5 */
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_2X_SEL, "netsys_2x_sel",
+ netsys_2x_parents, 0x050, 0x054, 0x058, 0, 2, 7,
+ 0x1C0, 20),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_SGM_325M_SEL, "sgm_325m_sel",
+ sgm_325m_parents, 0x050, 0x054, 0x058, 8, 1, 15,
+ 0x1C0, 21),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_SGM_REG_SEL, "sgm_reg_sel", sgm_reg_parents,
+ 0x050, 0x054, 0x058, 16, 1, 23, 0x1C0, 22),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_EIP97B_SEL, "eip97b_sel", eip97b_parents,
+ 0x050, 0x054, 0x058, 24, 3, 31, 0x1C0, 23),
+ /* CLK_CFG_6 */
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_USB3_PHY_SEL, "usb3_phy_sel",
+ csw_f26m_parents, 0x060, 0x064, 0x068, 0, 1,
+ 7, 0x1C0, 24),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_AUD_SEL, "aud_sel", aud_parents, 0x060,
+ 0x064, 0x068, 8, 1, 15, 0x1C0, 25),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_A1SYS_SEL, "a1sys_sel", a1sys_parents,
+ 0x060, 0x064, 0x068, 16, 1, 23, 0x1C0, 26),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_AUD_L_SEL, "aud_l_sel", aud_l_parents,
+ 0x060, 0x064, 0x068, 24, 2, 31, 0x1C0, 27),
+ /* CLK_CFG_7 */
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_A_TUNER_SEL, "a_tuner_sel",
+ a_tuner_parents, 0x070, 0x074, 0x078, 0, 2, 7,
+ 0x1C0, 28),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_U2U3_SEL, "u2u3_sel", u2u3_parents, 0x070,
+ 0x074, 0x078, 8, 1, 15, 0x1C0, 29),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_U2U3_SYS_SEL, "u2u3_sys_sel",
+ u2u3_sys_parents, 0x070, 0x074, 0x078, 16, 1, 23,
+ 0x1C0, 30),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_U2U3_XHCI_SEL, "u2u3_xhci_sel",
+ u2u3_sys_parents, 0x070, 0x074, 0x078, 24, 1, 31,
+ 0x1C4, 0),
+ /* CLK_CFG_8 */
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_FRMCNT_SEL, "usb_frmcnt_sel",
+ usb_frmcnt_parents, 0x080, 0x084, 0x088, 0, 1, 7,
+ 0x1C4, 1),
+};
+
+static struct mtk_composite top_aud_divs[] = {
+ DIV_GATE(CLK_TOP_AUD_I2S_M, "aud_i2s_m", "aud",
+ 0x0420, 0, 0x0420, 8, 8),
+};
+
+static const struct mtk_clk_desc topck_desc = {
+ .factor_clks = top_divs,
+ .num_factor_clks = ARRAY_SIZE(top_divs),
+ .mux_clks = top_muxes,
+ .num_mux_clks = ARRAY_SIZE(top_muxes),
+ .composite_clks = top_aud_divs,
+ .num_composite_clks = ARRAY_SIZE(top_aud_divs),
+ .clk_lock = &mt7981_clk_lock,
+};
+
+static const struct of_device_id of_match_clk_mt7981_topckgen[] = {
+ { .compatible = "mediatek,mt7981-topckgen", .data = &topck_desc },
+ { /* sentinel */ }
+};
+
+static struct platform_driver clk_mt7981_topckgen_drv = {
+ .probe = mtk_clk_simple_probe,
+ .remove = mtk_clk_simple_remove,
+ .driver = {
+ .name = "clk-mt7981-topckgen",
+ .of_match_table = of_match_clk_mt7981_topckgen,
+ },
+};
+builtin_platform_driver(clk_mt7981_topckgen_drv);
diff --git a/drivers/clk/mediatek/clk-mt7986-eth.c b/drivers/clk/mediatek/clk-mt7986-eth.c
index 7868c0728e96..703872239ecc 100644
--- a/drivers/clk/mediatek/clk-mt7986-eth.c
+++ b/drivers/clk/mediatek/clk-mt7986-eth.c
@@ -84,8 +84,8 @@ static void __init mtk_sgmiisys_0_init(struct device_node *node)
clk_data = mtk_alloc_clk_data(ARRAY_SIZE(sgmii0_clks));
- mtk_clk_register_gates(node, sgmii0_clks, ARRAY_SIZE(sgmii0_clks),
- clk_data);
+ mtk_clk_register_gates(NULL, node, sgmii0_clks,
+ ARRAY_SIZE(sgmii0_clks), clk_data);
r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
if (r)
@@ -102,8 +102,8 @@ static void __init mtk_sgmiisys_1_init(struct device_node *node)
clk_data = mtk_alloc_clk_data(ARRAY_SIZE(sgmii1_clks));
- mtk_clk_register_gates(node, sgmii1_clks, ARRAY_SIZE(sgmii1_clks),
- clk_data);
+ mtk_clk_register_gates(NULL, node, sgmii1_clks,
+ ARRAY_SIZE(sgmii1_clks), clk_data);
r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
@@ -121,7 +121,7 @@ static void __init mtk_ethsys_init(struct device_node *node)
clk_data = mtk_alloc_clk_data(ARRAY_SIZE(eth_clks));
- mtk_clk_register_gates(node, eth_clks, ARRAY_SIZE(eth_clks), clk_data);
+ mtk_clk_register_gates(NULL, node, eth_clks, ARRAY_SIZE(eth_clks), clk_data);
r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
diff --git a/drivers/clk/mediatek/clk-mt7986-infracfg.c b/drivers/clk/mediatek/clk-mt7986-infracfg.c
index 49666047bf0e..e80c92167c8f 100644
--- a/drivers/clk/mediatek/clk-mt7986-infracfg.c
+++ b/drivers/clk/mediatek/clk-mt7986-infracfg.c
@@ -190,10 +190,11 @@ static int clk_mt7986_infracfg_probe(struct platform_device *pdev)
return -ENOMEM;
mtk_clk_register_factors(infra_divs, ARRAY_SIZE(infra_divs), clk_data);
- mtk_clk_register_muxes(infra_muxes, ARRAY_SIZE(infra_muxes), node,
+ mtk_clk_register_muxes(&pdev->dev, infra_muxes,
+ ARRAY_SIZE(infra_muxes), node,
&mt7986_clk_lock, clk_data);
- mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks),
- clk_data);
+ mtk_clk_register_gates(&pdev->dev, node, infra_clks,
+ ARRAY_SIZE(infra_clks), clk_data);
r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
if (r) {
diff --git a/drivers/clk/mediatek/clk-mt7986-topckgen.c b/drivers/clk/mediatek/clk-mt7986-topckgen.c
index de5121cf2877..dff9976fa689 100644
--- a/drivers/clk/mediatek/clk-mt7986-topckgen.c
+++ b/drivers/clk/mediatek/clk-mt7986-topckgen.c
@@ -202,16 +202,23 @@ static const struct mtk_mux top_muxes[] = {
MUX_GATE_CLR_SET_UPD(CLK_TOP_F_26M_ADC_SEL, "f_26m_adc_sel",
f_26m_adc_parents, 0x020, 0x024, 0x028, 16, 1, 23,
0x1C0, 10),
- MUX_GATE_CLR_SET_UPD(CLK_TOP_DRAMC_SEL, "dramc_sel", f_26m_adc_parents,
- 0x020, 0x024, 0x028, 24, 1, 31, 0x1C0, 11),
+ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_DRAMC_SEL, "dramc_sel",
+ f_26m_adc_parents, 0x020, 0x024, 0x028,
+ 24, 1, 31, 0x1C0, 11,
+ CLK_IS_CRITICAL | CLK_SET_RATE_PARENT),
/* CLK_CFG_3 */
- MUX_GATE_CLR_SET_UPD(CLK_TOP_DRAMC_MD32_SEL, "dramc_md32_sel",
- dramc_md32_parents, 0x030, 0x034, 0x038, 0, 1, 7,
- 0x1C0, 12),
- MUX_GATE_CLR_SET_UPD(CLK_TOP_SYSAXI_SEL, "sysaxi_sel", sysaxi_parents,
- 0x030, 0x034, 0x038, 8, 2, 15, 0x1C0, 13),
- MUX_GATE_CLR_SET_UPD(CLK_TOP_SYSAPB_SEL, "sysapb_sel", sysapb_parents,
- 0x030, 0x034, 0x038, 16, 2, 23, 0x1C0, 14),
+ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_DRAMC_MD32_SEL, "dramc_md32_sel",
+ dramc_md32_parents, 0x030, 0x034, 0x038,
+ 0, 1, 7, 0x1C0, 12,
+ CLK_IS_CRITICAL | CLK_SET_RATE_PARENT),
+ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_SYSAXI_SEL, "sysaxi_sel",
+ sysaxi_parents, 0x030, 0x034, 0x038,
+ 8, 2, 15, 0x1C0, 13,
+ CLK_IS_CRITICAL | CLK_SET_RATE_PARENT),
+ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_SYSAPB_SEL, "sysapb_sel",
+ sysapb_parents, 0x030, 0x034, 0x038,
+ 16, 2, 23, 0x1C0, 14,
+ CLK_IS_CRITICAL | CLK_SET_RATE_PARENT),
MUX_GATE_CLR_SET_UPD(CLK_TOP_ARM_DB_MAIN_SEL, "arm_db_main_sel",
arm_db_main_parents, 0x030, 0x034, 0x038, 24, 1,
31, 0x1C0, 15),
@@ -234,9 +241,10 @@ static const struct mtk_mux top_muxes[] = {
MUX_GATE_CLR_SET_UPD(CLK_TOP_SGM_325M_SEL, "sgm_325m_sel",
sgm_325m_parents, 0x050, 0x054, 0x058, 8, 1, 15,
0x1C0, 21),
- MUX_GATE_CLR_SET_UPD(CLK_TOP_SGM_REG_SEL, "sgm_reg_sel",
- sgm_reg_parents, 0x050, 0x054, 0x058, 16, 1, 23,
- 0x1C0, 22),
+ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_SGM_REG_SEL, "sgm_reg_sel",
+ sgm_reg_parents, 0x050, 0x054, 0x058,
+ 16, 1, 23, 0x1C0, 22,
+ CLK_IS_CRITICAL | CLK_SET_RATE_PARENT),
MUX_GATE_CLR_SET_UPD(CLK_TOP_A1SYS_SEL, "a1sys_sel", a1sys_parents,
0x050, 0x054, 0x058, 24, 1, 31, 0x1C0, 23),
/* CLK_CFG_6 */
@@ -252,9 +260,10 @@ static const struct mtk_mux top_muxes[] = {
f_26m_adc_parents, 0x060, 0x064, 0x068, 24, 1, 31,
0x1C0, 27),
/* CLK_CFG_7 */
- MUX_GATE_CLR_SET_UPD(CLK_TOP_F26M_SEL, "csw_f26m_sel",
- f_26m_adc_parents, 0x070, 0x074, 0x078, 0, 1, 7,
- 0x1C0, 28),
+ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_F26M_SEL, "csw_f26m_sel",
+ f_26m_adc_parents, 0x070, 0x074, 0x078,
+ 0, 1, 7, 0x1C0, 28,
+ CLK_IS_CRITICAL | CLK_SET_RATE_PARENT),
MUX_GATE_CLR_SET_UPD(CLK_TOP_AUD_L_SEL, "aud_l_sel", aud_l_parents,
0x070, 0x074, 0x078, 8, 2, 15, 0x1C0, 29),
MUX_GATE_CLR_SET_UPD(CLK_TOP_A_TUNER_SEL, "a_tuner_sel",
@@ -281,59 +290,24 @@ static const struct mtk_mux top_muxes[] = {
0x1C4, 5),
};
-static int clk_mt7986_topckgen_probe(struct platform_device *pdev)
-{
- struct clk_hw_onecell_data *clk_data;
- struct device_node *node = pdev->dev.of_node;
- int r;
- void __iomem *base;
- int nr = ARRAY_SIZE(top_fixed_clks) + ARRAY_SIZE(top_divs) +
- ARRAY_SIZE(top_muxes);
-
- base = of_iomap(node, 0);
- if (!base) {
- pr_err("%s(): ioremap failed\n", __func__);
- return -ENOMEM;
- }
-
- clk_data = mtk_alloc_clk_data(nr);
- if (!clk_data)
- return -ENOMEM;
-
- mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks),
- clk_data);
- mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), clk_data);
- mtk_clk_register_muxes(top_muxes, ARRAY_SIZE(top_muxes), node,
- &mt7986_clk_lock, clk_data);
-
- clk_prepare_enable(clk_data->hws[CLK_TOP_SYSAXI_SEL]->clk);
- clk_prepare_enable(clk_data->hws[CLK_TOP_SYSAPB_SEL]->clk);
- clk_prepare_enable(clk_data->hws[CLK_TOP_DRAMC_SEL]->clk);
- clk_prepare_enable(clk_data->hws[CLK_TOP_DRAMC_MD32_SEL]->clk);
- clk_prepare_enable(clk_data->hws[CLK_TOP_F26M_SEL]->clk);
- clk_prepare_enable(clk_data->hws[CLK_TOP_SGM_REG_SEL]->clk);
-
- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
-
- if (r) {
- pr_err("%s(): could not register clock provider: %d\n",
- __func__, r);
- goto free_topckgen_data;
- }
- return r;
-
-free_topckgen_data:
- mtk_free_clk_data(clk_data);
- return r;
-}
+static const struct mtk_clk_desc topck_desc = {
+ .fixed_clks = top_fixed_clks,
+ .num_fixed_clks = ARRAY_SIZE(top_fixed_clks),
+ .factor_clks = top_divs,
+ .num_factor_clks = ARRAY_SIZE(top_divs),
+ .mux_clks = top_muxes,
+ .num_mux_clks = ARRAY_SIZE(top_muxes),
+ .clk_lock = &mt7986_clk_lock,
+};
static const struct of_device_id of_match_clk_mt7986_topckgen[] = {
- { .compatible = "mediatek,mt7986-topckgen", },
- {}
+ { .compatible = "mediatek,mt7986-topckgen", .data = &topck_desc },
+ { /* sentinel */ }
};
static struct platform_driver clk_mt7986_topckgen_drv = {
- .probe = clk_mt7986_topckgen_probe,
+ .probe = mtk_clk_simple_probe,
+ .remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt7986-topckgen",
.of_match_table = of_match_clk_mt7986_topckgen,
diff --git a/drivers/clk/mediatek/clk-mt8135.c b/drivers/clk/mediatek/clk-mt8135.c
index b68888a034c4..2b9c925c2a2b 100644
--- a/drivers/clk/mediatek/clk-mt8135.c
+++ b/drivers/clk/mediatek/clk-mt8135.c
@@ -548,8 +548,9 @@ static void __init mtk_topckgen_init(struct device_node *node)
mtk_clk_register_factors(root_clk_alias, ARRAY_SIZE(root_clk_alias), clk_data);
mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), clk_data);
- mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes), base,
- &mt8135_clk_lock, clk_data);
+ mtk_clk_register_composites(NULL, top_muxes,
+ ARRAY_SIZE(top_muxes), base,
+ &mt8135_clk_lock, clk_data);
clk_prepare_enable(clk_data->hws[CLK_TOP_CCI_SEL]->clk);
@@ -567,8 +568,8 @@ static void __init mtk_infrasys_init(struct device_node *node)
clk_data = mtk_alloc_clk_data(CLK_INFRA_NR_CLK);
- mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks),
- clk_data);
+ mtk_clk_register_gates(NULL, node, infra_clks,
+ ARRAY_SIZE(infra_clks), clk_data);
clk_prepare_enable(clk_data->hws[CLK_INFRA_M4U]->clk);
@@ -595,10 +596,11 @@ static void __init mtk_pericfg_init(struct device_node *node)
clk_data = mtk_alloc_clk_data(CLK_PERI_NR_CLK);
- mtk_clk_register_gates(node, peri_gates, ARRAY_SIZE(peri_gates),
- clk_data);
- mtk_clk_register_composites(peri_clks, ARRAY_SIZE(peri_clks), base,
- &mt8135_clk_lock, clk_data);
+ mtk_clk_register_gates(NULL, node, peri_gates,
+ ARRAY_SIZE(peri_gates), clk_data);
+ mtk_clk_register_composites(NULL, peri_clks,
+ ARRAY_SIZE(peri_clks), base,
+ &mt8135_clk_lock, clk_data);
r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
if (r)
diff --git a/drivers/clk/mediatek/clk-mt8167-aud.c b/drivers/clk/mediatek/clk-mt8167-aud.c
index ce1ae8d243c3..f6bea6e9e6a4 100644
--- a/drivers/clk/mediatek/clk-mt8167-aud.c
+++ b/drivers/clk/mediatek/clk-mt8167-aud.c
@@ -55,7 +55,7 @@ static void __init mtk_audsys_init(struct device_node *node)
clk_data = mtk_alloc_clk_data(CLK_AUD_NR_CLK);
- mtk_clk_register_gates(node, aud_clks, ARRAY_SIZE(aud_clks), clk_data);
+ mtk_clk_register_gates(NULL, node, aud_clks, ARRAY_SIZE(aud_clks), clk_data);
r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
if (r)
diff --git a/drivers/clk/mediatek/clk-mt8167-img.c b/drivers/clk/mediatek/clk-mt8167-img.c
index e359e563d2b7..77db13b177fc 100644
--- a/drivers/clk/mediatek/clk-mt8167-img.c
+++ b/drivers/clk/mediatek/clk-mt8167-img.c
@@ -48,7 +48,7 @@ static void __init mtk_imgsys_init(struct device_node *node)
clk_data = mtk_alloc_clk_data(CLK_IMG_NR_CLK);
- mtk_clk_register_gates(node, img_clks, ARRAY_SIZE(img_clks), clk_data);
+ mtk_clk_register_gates(NULL, node, img_clks, ARRAY_SIZE(img_clks), clk_data);
r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
diff --git a/drivers/clk/mediatek/clk-mt8167-mfgcfg.c b/drivers/clk/mediatek/clk-mt8167-mfgcfg.c
index 4fd82fe87d6e..3c23591b02f7 100644
--- a/drivers/clk/mediatek/clk-mt8167-mfgcfg.c
+++ b/drivers/clk/mediatek/clk-mt8167-mfgcfg.c
@@ -46,7 +46,7 @@ static void __init mtk_mfgcfg_init(struct device_node *node)
clk_data = mtk_alloc_clk_data(CLK_MFG_NR_CLK);
- mtk_clk_register_gates(node, mfg_clks, ARRAY_SIZE(mfg_clks), clk_data);
+ mtk_clk_register_gates(NULL, node, mfg_clks, ARRAY_SIZE(mfg_clks), clk_data);
r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
diff --git a/drivers/clk/mediatek/clk-mt8167-mm.c b/drivers/clk/mediatek/clk-mt8167-mm.c
index 73910060577f..c0b44104c765 100644
--- a/drivers/clk/mediatek/clk-mt8167-mm.c
+++ b/drivers/clk/mediatek/clk-mt8167-mm.c
@@ -110,8 +110,8 @@ static int clk_mt8167_mm_probe(struct platform_device *pdev)
data = &mt8167_mmsys_driver_data;
- ret = mtk_clk_register_gates(node, data->gates_clk, data->gates_num,
- clk_data);
+ ret = mtk_clk_register_gates(&pdev->dev, node, data->gates_clk,
+ data->gates_num, clk_data);
if (ret)
return ret;
diff --git a/drivers/clk/mediatek/clk-mt8167-vdec.c b/drivers/clk/mediatek/clk-mt8167-vdec.c
index ee4fffb6859d..759e5791599f 100644
--- a/drivers/clk/mediatek/clk-mt8167-vdec.c
+++ b/drivers/clk/mediatek/clk-mt8167-vdec.c
@@ -61,7 +61,8 @@ static void __init mtk_vdecsys_init(struct device_node *node)
clk_data = mtk_alloc_clk_data(CLK_VDEC_NR_CLK);
- mtk_clk_register_gates(node, vdec_clks, ARRAY_SIZE(vdec_clks), clk_data);
+ mtk_clk_register_gates(NULL, node, vdec_clks, ARRAY_SIZE(vdec_clks),
+ clk_data);
r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
diff --git a/drivers/clk/mediatek/clk-mt8167.c b/drivers/clk/mediatek/clk-mt8167.c
index f900ac4bf7b8..91669ebafaf9 100644
--- a/drivers/clk/mediatek/clk-mt8167.c
+++ b/drivers/clk/mediatek/clk-mt8167.c
@@ -937,11 +937,12 @@ static void __init mtk_topckgen_init(struct device_node *node)
mtk_clk_register_fixed_clks(fixed_clks, ARRAY_SIZE(fixed_clks),
clk_data);
- mtk_clk_register_gates(node, top_clks, ARRAY_SIZE(top_clks), clk_data);
+ mtk_clk_register_gates(NULL, node, top_clks, ARRAY_SIZE(top_clks), clk_data);
mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), clk_data);
- mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes), base,
- &mt8167_clk_lock, clk_data);
+ mtk_clk_register_composites(NULL, top_muxes,
+ ARRAY_SIZE(top_muxes), base,
+ &mt8167_clk_lock, clk_data);
mtk_clk_register_dividers(top_adj_divs, ARRAY_SIZE(top_adj_divs),
base, &mt8167_clk_lock, clk_data);
@@ -966,8 +967,9 @@ static void __init mtk_infracfg_init(struct device_node *node)
clk_data = mtk_alloc_clk_data(CLK_IFR_NR_CLK);
- mtk_clk_register_composites(ifr_muxes, ARRAY_SIZE(ifr_muxes), base,
- &mt8167_clk_lock, clk_data);
+ mtk_clk_register_composites(NULL, ifr_muxes,
+ ARRAY_SIZE(ifr_muxes), base,
+ &mt8167_clk_lock, clk_data);
r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
if (r)
diff --git a/drivers/clk/mediatek/clk-mt8173-apmixedsys.c b/drivers/clk/mediatek/clk-mt8173-apmixedsys.c
new file mode 100644
index 000000000000..a56c5845d07a
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt8173-apmixedsys.c
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ * Copyright (c) 2022 Collabora Ltd.
+ * Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+ */
+
+#include <dt-bindings/clock/mt8173-clk.h>
+#include <linux/of_address.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include "clk-mtk.h"
+#include "clk-pll.h"
+
+#define REGOFF_REF2USB 0x8
+#define REGOFF_HDMI_REF 0x40
+
+#define MT8173_PLL_FMAX (3000UL * MHZ)
+
+#define CON0_MT8173_RST_BAR BIT(24)
+
+#define PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \
+ _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, \
+ _pcw_shift, _div_table) { \
+ .id = _id, \
+ .name = _name, \
+ .reg = _reg, \
+ .pwr_reg = _pwr_reg, \
+ .en_mask = _en_mask, \
+ .flags = _flags, \
+ .rst_bar_mask = CON0_MT8173_RST_BAR, \
+ .fmax = MT8173_PLL_FMAX, \
+ .pcwbits = _pcwbits, \
+ .pd_reg = _pd_reg, \
+ .pd_shift = _pd_shift, \
+ .tuner_reg = _tuner_reg, \
+ .pcw_reg = _pcw_reg, \
+ .pcw_shift = _pcw_shift, \
+ .div_table = _div_table, \
+ }
+
+#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \
+ _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, \
+ _pcw_shift) \
+ PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \
+ _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift, \
+ NULL)
+
+static const struct mtk_pll_div_table mmpll_div_table[] = {
+ { .div = 0, .freq = MT8173_PLL_FMAX },
+ { .div = 1, .freq = 1000000000 },
+ { .div = 2, .freq = 702000000 },
+ { .div = 3, .freq = 253500000 },
+ { .div = 4, .freq = 126750000 },
+ { } /* sentinel */
+};
+
+static const struct mtk_pll_data plls[] = {
+ PLL(CLK_APMIXED_ARMCA15PLL, "armca15pll", 0x200, 0x20c, 0, PLL_AO,
+ 21, 0x204, 24, 0x0, 0x204, 0),
+ PLL(CLK_APMIXED_ARMCA7PLL, "armca7pll", 0x210, 0x21c, 0, PLL_AO,
+ 21, 0x214, 24, 0x0, 0x214, 0),
+ PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x220, 0x22c, 0xf0000100, HAVE_RST_BAR, 21,
+ 0x220, 4, 0x0, 0x224, 0),
+ PLL(CLK_APMIXED_UNIVPLL, "univpll", 0x230, 0x23c, 0xfe000000, HAVE_RST_BAR, 7,
+ 0x230, 4, 0x0, 0x234, 14),
+ PLL_B(CLK_APMIXED_MMPLL, "mmpll", 0x240, 0x24c, 0, 0, 21, 0x244, 24, 0x0,
+ 0x244, 0, mmpll_div_table),
+ PLL(CLK_APMIXED_MSDCPLL, "msdcpll", 0x250, 0x25c, 0, 0, 21, 0x250, 4, 0x0, 0x254, 0),
+ PLL(CLK_APMIXED_VENCPLL, "vencpll", 0x260, 0x26c, 0, 0, 21, 0x260, 4, 0x0, 0x264, 0),
+ PLL(CLK_APMIXED_TVDPLL, "tvdpll", 0x270, 0x27c, 0, 0, 21, 0x270, 4, 0x0, 0x274, 0),
+ PLL(CLK_APMIXED_MPLL, "mpll", 0x280, 0x28c, 0, 0, 21, 0x280, 4, 0x0, 0x284, 0),
+ PLL(CLK_APMIXED_VCODECPLL, "vcodecpll", 0x290, 0x29c, 0, 0, 21, 0x290, 4, 0x0, 0x294, 0),
+ PLL(CLK_APMIXED_APLL1, "apll1", 0x2a0, 0x2b0, 0, 0, 31, 0x2a0, 4, 0x2a4, 0x2a4, 0),
+ PLL(CLK_APMIXED_APLL2, "apll2", 0x2b4, 0x2c4, 0, 0, 31, 0x2b4, 4, 0x2b8, 0x2b8, 0),
+ PLL(CLK_APMIXED_LVDSPLL, "lvdspll", 0x2d0, 0x2dc, 0, 0, 21, 0x2d0, 4, 0x0, 0x2d4, 0),
+ PLL(CLK_APMIXED_MSDCPLL2, "msdcpll2", 0x2f0, 0x2fc, 0, 0, 21, 0x2f0, 4, 0x0, 0x2f4, 0),
+};
+
+static const struct of_device_id of_match_clk_mt8173_apmixed[] = {
+ { .compatible = "mediatek,mt8173-apmixedsys" },
+ { /* sentinel */ }
+};
+
+static int clk_mt8173_apmixed_probe(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct clk_hw_onecell_data *clk_data;
+ void __iomem *base;
+ struct clk_hw *hw;
+ int r;
+
+ base = of_iomap(node, 0);
+ if (!base)
+ return PTR_ERR(base);
+
+ clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK);
+ if (IS_ERR_OR_NULL(clk_data))
+ return -ENOMEM;
+
+ r = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
+ if (r)
+ goto free_clk_data;
+
+ hw = mtk_clk_register_ref2usb_tx("ref2usb_tx", "clk26m", base + REGOFF_REF2USB);
+ if (IS_ERR(hw)) {
+ r = PTR_ERR(hw);
+ dev_err(&pdev->dev, "Failed to register ref2usb_tx: %d\n", r);
+ goto unregister_plls;
+ }
+ clk_data->hws[CLK_APMIXED_REF2USB_TX] = hw;
+
+ hw = devm_clk_hw_register_divider(&pdev->dev, "hdmi_ref", "tvdpll_594m", 0,
+ base + REGOFF_HDMI_REF, 16, 3,
+ CLK_DIVIDER_POWER_OF_TWO, NULL);
+ clk_data->hws[CLK_APMIXED_HDMI_REF] = hw;
+
+ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+ if (r)
+ goto unregister_ref2usb;
+
+ return 0;
+
+unregister_ref2usb:
+ mtk_clk_unregister_ref2usb_tx(clk_data->hws[CLK_APMIXED_REF2USB_TX]);
+unregister_plls:
+ mtk_clk_unregister_plls(plls, ARRAY_SIZE(plls), clk_data);
+free_clk_data:
+ mtk_free_clk_data(clk_data);
+ return r;
+}
+
+static int clk_mt8173_apmixed_remove(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev);
+
+ of_clk_del_provider(node);
+ mtk_clk_unregister_ref2usb_tx(clk_data->hws[CLK_APMIXED_REF2USB_TX]);
+ mtk_clk_unregister_plls(plls, ARRAY_SIZE(plls), clk_data);
+ mtk_free_clk_data(clk_data);
+
+ return 0;
+}
+
+static struct platform_driver clk_mt8173_apmixed_drv = {
+ .probe = clk_mt8173_apmixed_probe,
+ .remove = clk_mt8173_apmixed_remove,
+ .driver = {
+ .name = "clk-mt8173-apmixed",
+ .of_match_table = of_match_clk_mt8173_apmixed,
+ },
+};
+module_platform_driver(clk_mt8173_apmixed_drv);
+
+MODULE_DESCRIPTION("MediaTek MT8173 apmixed clocks driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/mediatek/clk-mt8173-img.c b/drivers/clk/mediatek/clk-mt8173-img.c
new file mode 100644
index 000000000000..7b50ffb7a8a5
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt8173-img.c
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ * Copyright (c) 2022 Collabora Ltd.
+ * Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+ */
+
+#include <dt-bindings/clock/mt8173-clk.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include "clk-gate.h"
+#include "clk-mtk.h"
+
+static const struct mtk_gate_regs img_cg_regs = {
+ .set_ofs = 0x0004,
+ .clr_ofs = 0x0008,
+ .sta_ofs = 0x0000,
+};
+
+#define GATE_IMG(_id, _name, _parent, _shift) \
+ GATE_MTK(_id, _name, _parent, &img_cg_regs, _shift, &mtk_clk_gate_ops_setclr)
+
+static const struct mtk_gate img_clks[] = {
+ GATE_DUMMY(CLK_DUMMY, "img_dummy"),
+ GATE_IMG(CLK_IMG_LARB2_SMI, "img_larb2_smi", "mm_sel", 0),
+ GATE_IMG(CLK_IMG_CAM_SMI, "img_cam_smi", "mm_sel", 5),
+ GATE_IMG(CLK_IMG_CAM_CAM, "img_cam_cam", "mm_sel", 6),
+ GATE_IMG(CLK_IMG_SEN_TG, "img_sen_tg", "camtg_sel", 7),
+ GATE_IMG(CLK_IMG_SEN_CAM, "img_sen_cam", "mm_sel", 8),
+ GATE_IMG(CLK_IMG_CAM_SV, "img_cam_sv", "mm_sel", 9),
+ GATE_IMG(CLK_IMG_FD, "img_fd", "mm_sel", 11),
+};
+
+static const struct mtk_clk_desc img_desc = {
+ .clks = img_clks,
+ .num_clks = ARRAY_SIZE(img_clks),
+};
+
+static const struct of_device_id of_match_clk_mt8173_imgsys[] = {
+ { .compatible = "mediatek,mt8173-imgsys", .data = &img_desc },
+ { /* sentinel */ }
+};
+
+static struct platform_driver clk_mt8173_vdecsys_drv = {
+ .probe = mtk_clk_simple_probe,
+ .remove = mtk_clk_simple_remove,
+ .driver = {
+ .name = "clk-mt8173-imgsys",
+ .of_match_table = of_match_clk_mt8173_imgsys,
+ },
+};
+module_platform_driver(clk_mt8173_vdecsys_drv);
+
+MODULE_DESCRIPTION("MediaTek MT8173 vdecsys clocks driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/mediatek/clk-mt8173-infracfg.c b/drivers/clk/mediatek/clk-mt8173-infracfg.c
new file mode 100644
index 000000000000..729b3c408c7b
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt8173-infracfg.c
@@ -0,0 +1,155 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ * Copyright (c) 2022 Collabora Ltd.
+ * Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+ */
+
+#include <dt-bindings/clock/mt8173-clk.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include "clk-cpumux.h"
+#include "clk-gate.h"
+#include "clk-mtk.h"
+#include "reset.h"
+
+#define GATE_ICG(_id, _name, _parent, _shift) \
+ GATE_MTK(_id, _name, _parent, &infra_cg_regs, \
+ _shift, &mtk_clk_gate_ops_setclr)
+
+static struct clk_hw_onecell_data *infra_clk_data;
+
+static const struct mtk_gate_regs infra_cg_regs = {
+ .set_ofs = 0x0040,
+ .clr_ofs = 0x0044,
+ .sta_ofs = 0x0048,
+};
+
+static const char * const ca53_parents[] __initconst = {
+ "clk26m",
+ "armca7pll",
+ "mainpll",
+ "univpll"
+};
+
+static const char * const ca72_parents[] __initconst = {
+ "clk26m",
+ "armca15pll",
+ "mainpll",
+ "univpll"
+};
+
+static const struct mtk_composite cpu_muxes[] = {
+ MUX(CLK_INFRA_CA53SEL, "infra_ca53_sel", ca53_parents, 0x0000, 0, 2),
+ MUX(CLK_INFRA_CA72SEL, "infra_ca72_sel", ca72_parents, 0x0000, 2, 2),
+};
+
+static const struct mtk_fixed_factor infra_early_divs[] = {
+ FACTOR(CLK_INFRA_CLK_13M, "clk13m", "clk26m", 1, 2),
+};
+
+static const struct mtk_gate infra_gates[] = {
+ GATE_ICG(CLK_INFRA_DBGCLK, "infra_dbgclk", "axi_sel", 0),
+ GATE_ICG(CLK_INFRA_SMI, "infra_smi", "mm_sel", 1),
+ GATE_ICG(CLK_INFRA_AUDIO, "infra_audio", "aud_intbus_sel", 5),
+ GATE_ICG(CLK_INFRA_GCE, "infra_gce", "axi_sel", 6),
+ GATE_ICG(CLK_INFRA_L2C_SRAM, "infra_l2c_sram", "axi_sel", 7),
+ GATE_ICG(CLK_INFRA_M4U, "infra_m4u", "mem_sel", 8),
+ GATE_ICG(CLK_INFRA_CPUM, "infra_cpum", "cpum_ck", 15),
+ GATE_ICG(CLK_INFRA_KP, "infra_kp", "axi_sel", 16),
+ GATE_ICG(CLK_INFRA_CEC, "infra_cec", "clk26m", 18),
+ GATE_ICG(CLK_INFRA_PMICSPI, "infra_pmicspi", "pmicspi_sel", 22),
+ GATE_ICG(CLK_INFRA_PMICWRAP, "infra_pmicwrap", "axi_sel", 23),
+};
+
+static u16 infrasys_rst_ofs[] = { 0x30, 0x34 };
+
+static const struct mtk_clk_rst_desc clk_rst_desc = {
+ .version = MTK_RST_SIMPLE,
+ .rst_bank_ofs = infrasys_rst_ofs,
+ .rst_bank_nr = ARRAY_SIZE(infrasys_rst_ofs),
+};
+
+static const struct of_device_id of_match_clk_mt8173_infracfg[] = {
+ { .compatible = "mediatek,mt8173-infracfg" },
+ { /* sentinel */ }
+};
+
+static void clk_mt8173_infra_init_early(struct device_node *node)
+{
+ int i;
+
+ infra_clk_data = mtk_alloc_clk_data(CLK_INFRA_NR_CLK);
+ if (!infra_clk_data)
+ return;
+
+ for (i = 0; i < CLK_INFRA_NR_CLK; i++)
+ infra_clk_data->hws[i] = ERR_PTR(-EPROBE_DEFER);
+
+ mtk_clk_register_factors(infra_early_divs,
+ ARRAY_SIZE(infra_early_divs), infra_clk_data);
+
+ of_clk_add_hw_provider(node, of_clk_hw_onecell_get, infra_clk_data);
+}
+CLK_OF_DECLARE_DRIVER(mtk_infrasys, "mediatek,mt8173-infracfg",
+ clk_mt8173_infra_init_early);
+
+static int clk_mt8173_infracfg_probe(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ int r;
+
+ r = mtk_clk_register_gates(&pdev->dev, node, infra_gates,
+ ARRAY_SIZE(infra_gates), infra_clk_data);
+ if (r)
+ return r;
+
+ r = mtk_clk_register_cpumuxes(&pdev->dev, node, cpu_muxes,
+ ARRAY_SIZE(cpu_muxes), infra_clk_data);
+ if (r)
+ goto unregister_gates;
+
+ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, infra_clk_data);
+ if (r)
+ goto unregister_cpumuxes;
+
+ r = mtk_register_reset_controller_with_dev(&pdev->dev, &clk_rst_desc);
+ if (r)
+ goto unregister_clk_hw;
+
+ return 0;
+
+unregister_clk_hw:
+ of_clk_del_provider(node);
+unregister_cpumuxes:
+ mtk_clk_unregister_cpumuxes(cpu_muxes, ARRAY_SIZE(cpu_muxes), infra_clk_data);
+unregister_gates:
+ mtk_clk_unregister_gates(infra_gates, ARRAY_SIZE(infra_gates), infra_clk_data);
+ return r;
+}
+
+static int clk_mt8173_infracfg_remove(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev);
+
+ of_clk_del_provider(node);
+ mtk_clk_unregister_cpumuxes(cpu_muxes, ARRAY_SIZE(cpu_muxes), clk_data);
+ mtk_clk_unregister_gates(infra_gates, ARRAY_SIZE(infra_gates), clk_data);
+ mtk_free_clk_data(clk_data);
+
+ return 0;
+}
+
+static struct platform_driver clk_mt8173_infracfg_drv = {
+ .driver = {
+ .name = "clk-mt8173-infracfg",
+ .of_match_table = of_match_clk_mt8173_infracfg,
+ },
+ .probe = clk_mt8173_infracfg_probe,
+ .remove = clk_mt8173_infracfg_remove,
+};
+module_platform_driver(clk_mt8173_infracfg_drv);
+
+MODULE_DESCRIPTION("MediaTek MT8173 infracfg clocks driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/mediatek/clk-mt8173-mm.c b/drivers/clk/mediatek/clk-mt8173-mm.c
index 8abf42c2030c..315430ad1581 100644
--- a/drivers/clk/mediatek/clk-mt8173-mm.c
+++ b/drivers/clk/mediatek/clk-mt8173-mm.c
@@ -124,8 +124,8 @@ static int clk_mt8173_mm_probe(struct platform_device *pdev)
data = &mt8173_mmsys_driver_data;
- ret = mtk_clk_register_gates(node, data->gates_clk, data->gates_num,
- clk_data);
+ ret = mtk_clk_register_gates(&pdev->dev, node, data->gates_clk,
+ data->gates_num, clk_data);
if (ret)
return ret;
@@ -136,11 +136,29 @@ static int clk_mt8173_mm_probe(struct platform_device *pdev)
return 0;
}
+static int clk_mt8173_mm_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *node = dev->parent->of_node;
+ struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev);
+ const struct clk_mt8173_mm_driver_data *data = &mt8173_mmsys_driver_data;
+
+ of_clk_del_provider(node);
+ mtk_clk_unregister_gates(data->gates_clk, data->gates_num, clk_data);
+ mtk_free_clk_data(clk_data);
+
+ return 0;
+}
+
static struct platform_driver clk_mt8173_mm_drv = {
.driver = {
.name = "clk-mt8173-mm",
},
.probe = clk_mt8173_mm_probe,
+ .remove = clk_mt8173_mm_remove,
};
builtin_platform_driver(clk_mt8173_mm_drv);
+
+MODULE_DESCRIPTION("MediaTek MT8173 MultiMedia clocks driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/mediatek/clk-mt8173-pericfg.c b/drivers/clk/mediatek/clk-mt8173-pericfg.c
new file mode 100644
index 000000000000..e87294b72c2c
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt8173-pericfg.c
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022 Collabora Ltd.
+ * Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+ */
+
+#include <dt-bindings/clock/mt8173-clk.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include "clk-gate.h"
+#include "clk-mtk.h"
+#include "reset.h"
+
+#define GATE_PERI0(_id, _name, _parent, _shift) \
+ GATE_MTK(_id, _name, _parent, &peri0_cg_regs, \
+ _shift, &mtk_clk_gate_ops_setclr)
+
+#define GATE_PERI1(_id, _name, _parent, _shift) \
+ GATE_MTK(_id, _name, _parent, &peri1_cg_regs, \
+ _shift, &mtk_clk_gate_ops_setclr)
+
+static DEFINE_SPINLOCK(mt8173_clk_lock);
+
+static const struct mtk_gate_regs peri0_cg_regs = {
+ .set_ofs = 0x0008,
+ .clr_ofs = 0x0010,
+ .sta_ofs = 0x0018,
+};
+
+static const struct mtk_gate_regs peri1_cg_regs = {
+ .set_ofs = 0x000c,
+ .clr_ofs = 0x0014,
+ .sta_ofs = 0x001c,
+};
+
+static const char * const uart_ck_sel_parents[] = {
+ "clk26m",
+ "uart_sel",
+};
+
+static const struct mtk_composite peri_clks[] = {
+ MUX(CLK_PERI_UART0_SEL, "uart0_ck_sel", uart_ck_sel_parents, 0x40c, 0, 1),
+ MUX(CLK_PERI_UART1_SEL, "uart1_ck_sel", uart_ck_sel_parents, 0x40c, 1, 1),
+ MUX(CLK_PERI_UART2_SEL, "uart2_ck_sel", uart_ck_sel_parents, 0x40c, 2, 1),
+ MUX(CLK_PERI_UART3_SEL, "uart3_ck_sel", uart_ck_sel_parents, 0x40c, 3, 1),
+};
+
+static const struct mtk_gate peri_gates[] = {
+ GATE_DUMMY(CLK_DUMMY, "peri_gate_dummy"),
+ /* PERI0 */
+ GATE_PERI0(CLK_PERI_NFI, "peri_nfi", "axi_sel", 0),
+ GATE_PERI0(CLK_PERI_THERM, "peri_therm", "axi_sel", 1),
+ GATE_PERI0(CLK_PERI_PWM1, "peri_pwm1", "axi_sel", 2),
+ GATE_PERI0(CLK_PERI_PWM2, "peri_pwm2", "axi_sel", 3),
+ GATE_PERI0(CLK_PERI_PWM3, "peri_pwm3", "axi_sel", 4),
+ GATE_PERI0(CLK_PERI_PWM4, "peri_pwm4", "axi_sel", 5),
+ GATE_PERI0(CLK_PERI_PWM5, "peri_pwm5", "axi_sel", 6),
+ GATE_PERI0(CLK_PERI_PWM6, "peri_pwm6", "axi_sel", 7),
+ GATE_PERI0(CLK_PERI_PWM7, "peri_pwm7", "axi_sel", 8),
+ GATE_PERI0(CLK_PERI_PWM, "peri_pwm", "axi_sel", 9),
+ GATE_PERI0(CLK_PERI_USB0, "peri_usb0", "usb20_sel", 10),
+ GATE_PERI0(CLK_PERI_USB1, "peri_usb1", "usb20_sel", 11),
+ GATE_PERI0(CLK_PERI_AP_DMA, "peri_ap_dma", "axi_sel", 12),
+ GATE_PERI0(CLK_PERI_MSDC30_0, "peri_msdc30_0", "msdc50_0_sel", 13),
+ GATE_PERI0(CLK_PERI_MSDC30_1, "peri_msdc30_1", "msdc30_1_sel", 14),
+ GATE_PERI0(CLK_PERI_MSDC30_2, "peri_msdc30_2", "msdc30_2_sel", 15),
+ GATE_PERI0(CLK_PERI_MSDC30_3, "peri_msdc30_3", "msdc30_3_sel", 16),
+ GATE_PERI0(CLK_PERI_NLI_ARB, "peri_nli_arb", "axi_sel", 17),
+ GATE_PERI0(CLK_PERI_IRDA, "peri_irda", "irda_sel", 18),
+ GATE_PERI0(CLK_PERI_UART0, "peri_uart0", "axi_sel", 19),
+ GATE_PERI0(CLK_PERI_UART1, "peri_uart1", "axi_sel", 20),
+ GATE_PERI0(CLK_PERI_UART2, "peri_uart2", "axi_sel", 21),
+ GATE_PERI0(CLK_PERI_UART3, "peri_uart3", "axi_sel", 22),
+ GATE_PERI0(CLK_PERI_I2C0, "peri_i2c0", "axi_sel", 23),
+ GATE_PERI0(CLK_PERI_I2C1, "peri_i2c1", "axi_sel", 24),
+ GATE_PERI0(CLK_PERI_I2C2, "peri_i2c2", "axi_sel", 25),
+ GATE_PERI0(CLK_PERI_I2C3, "peri_i2c3", "axi_sel", 26),
+ GATE_PERI0(CLK_PERI_I2C4, "peri_i2c4", "axi_sel", 27),
+ GATE_PERI0(CLK_PERI_AUXADC, "peri_auxadc", "clk26m", 28),
+ GATE_PERI0(CLK_PERI_SPI0, "peri_spi0", "spi_sel", 29),
+ GATE_PERI0(CLK_PERI_I2C5, "peri_i2c5", "axi_sel", 30),
+ GATE_PERI0(CLK_PERI_NFIECC, "peri_nfiecc", "axi_sel", 31),
+ /* PERI1 */
+ GATE_PERI1(CLK_PERI_SPI, "peri_spi", "spi_sel", 0),
+ GATE_PERI1(CLK_PERI_IRRX, "peri_irrx", "spi_sel", 1),
+ GATE_PERI1(CLK_PERI_I2C6, "peri_i2c6", "axi_sel", 2),
+};
+
+static u16 pericfg_rst_ofs[] = { 0x0, 0x4 };
+
+static const struct mtk_clk_rst_desc clk_rst_desc = {
+ .version = MTK_RST_SIMPLE,
+ .rst_bank_ofs = pericfg_rst_ofs,
+ .rst_bank_nr = ARRAY_SIZE(pericfg_rst_ofs),
+};
+
+static const struct mtk_clk_desc peri_desc = {
+ .clks = peri_gates,
+ .num_clks = ARRAY_SIZE(peri_gates),
+ .composite_clks = peri_clks,
+ .num_composite_clks = ARRAY_SIZE(peri_clks),
+ .clk_lock = &mt8173_clk_lock,
+ .rst_desc = &clk_rst_desc,
+};
+
+static const struct of_device_id of_match_clk_mt8173_pericfg[] = {
+ { .compatible = "mediatek,mt8173-pericfg", .data = &peri_desc },
+ { /* sentinel */ }
+};
+
+static struct platform_driver clk_mt8173_pericfg_drv = {
+ .driver = {
+ .name = "clk-mt8173-pericfg",
+ .of_match_table = of_match_clk_mt8173_pericfg,
+ },
+ .probe = mtk_clk_simple_probe,
+ .remove = mtk_clk_simple_remove,
+};
+module_platform_driver(clk_mt8173_pericfg_drv);
+
+MODULE_DESCRIPTION("MediaTek MT8173 pericfg clocks driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/mediatek/clk-mt8173-topckgen.c b/drivers/clk/mediatek/clk-mt8173-topckgen.c
new file mode 100644
index 000000000000..257961528fe2
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt8173-topckgen.c
@@ -0,0 +1,653 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ * Copyright (c) 2022 Collabora Ltd.
+ * Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+ */
+
+#include <dt-bindings/clock/mt8173-clk.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include "clk-gate.h"
+#include "clk-mtk.h"
+#include "clk-mux.h"
+
+/*
+ * For some clocks, we don't care what their actual rates are. And these
+ * clocks may change their rate on different products or different scenarios.
+ * So we model these clocks' rate as 0, to denote it's not an actual rate.
+ */
+#define DUMMY_RATE 0
+
+#define TOP_MUX_GATE_NOSR(_id, _name, _parents, _reg, _shift, _width, _gate, _flags) \
+ MUX_GATE_CLR_SET_UPD_FLAGS(_id, _name, _parents, _reg, \
+ (_reg + 0x4), (_reg + 0x8), _shift, _width, \
+ _gate, 0, -1, _flags)
+
+#define TOP_MUX_GATE(_id, _name, _parents, _reg, _shift, _width, _gate, _flags) \
+ TOP_MUX_GATE_NOSR(_id, _name, _parents, _reg, _shift, _width, \
+ _gate, CLK_SET_RATE_PARENT | _flags)
+
+static DEFINE_SPINLOCK(mt8173_top_clk_lock);
+
+static const char * const axi_parents[] = {
+ "clk26m",
+ "syspll1_d2",
+ "syspll_d5",
+ "syspll1_d4",
+ "univpll_d5",
+ "univpll2_d2",
+ "dmpll_d2",
+ "dmpll_d4"
+};
+
+static const char * const mem_parents[] = {
+ "clk26m",
+ "dmpll_ck"
+};
+
+static const char * const ddrphycfg_parents[] = {
+ "clk26m",
+ "syspll1_d8"
+};
+
+static const char * const mm_parents[] = {
+ "clk26m",
+ "vencpll_d2",
+ "main_h364m",
+ "syspll1_d2",
+ "syspll_d5",
+ "syspll1_d4",
+ "univpll1_d2",
+ "univpll2_d2",
+ "dmpll_d2"
+};
+
+static const char * const pwm_parents[] = {
+ "clk26m",
+ "univpll2_d4",
+ "univpll3_d2",
+ "univpll1_d4"
+};
+
+static const char * const vdec_parents[] = {
+ "clk26m",
+ "vcodecpll_ck",
+ "tvdpll_445p5m",
+ "univpll_d3",
+ "vencpll_d2",
+ "syspll_d3",
+ "univpll1_d2",
+ "mmpll_d2",
+ "dmpll_d2",
+ "dmpll_d4"
+};
+
+static const char * const venc_parents[] = {
+ "clk26m",
+ "vcodecpll_ck",
+ "tvdpll_445p5m",
+ "univpll_d3",
+ "vencpll_d2",
+ "syspll_d3",
+ "univpll1_d2",
+ "univpll2_d2",
+ "dmpll_d2",
+ "dmpll_d4"
+};
+
+static const char * const mfg_parents[] = {
+ "clk26m",
+ "mmpll_ck",
+ "dmpll_ck",
+ "clk26m",
+ "clk26m",
+ "clk26m",
+ "clk26m",
+ "clk26m",
+ "clk26m",
+ "syspll_d3",
+ "syspll1_d2",
+ "syspll_d5",
+ "univpll_d3",
+ "univpll1_d2",
+ "univpll_d5",
+ "univpll2_d2"
+};
+
+static const char * const camtg_parents[] = {
+ "clk26m",
+ "univpll_d26",
+ "univpll2_d2",
+ "syspll3_d2",
+ "syspll3_d4",
+ "univpll1_d4"
+};
+
+static const char * const uart_parents[] = {
+ "clk26m",
+ "univpll2_d8"
+};
+
+static const char * const spi_parents[] = {
+ "clk26m",
+ "syspll3_d2",
+ "syspll1_d4",
+ "syspll4_d2",
+ "univpll3_d2",
+ "univpll2_d4",
+ "univpll1_d8"
+};
+
+static const char * const usb20_parents[] = {
+ "clk26m",
+ "univpll1_d8",
+ "univpll3_d4"
+};
+
+static const char * const usb30_parents[] = {
+ "clk26m",
+ "univpll3_d2",
+ "usb_syspll_125m",
+ "univpll2_d4"
+};
+
+static const char * const msdc50_0_h_parents[] = {
+ "clk26m",
+ "syspll1_d2",
+ "syspll2_d2",
+ "syspll4_d2",
+ "univpll_d5",
+ "univpll1_d4"
+};
+
+static const char * const msdc50_0_parents[] = {
+ "clk26m",
+ "msdcpll_ck",
+ "msdcpll_d2",
+ "univpll1_d4",
+ "syspll2_d2",
+ "syspll_d7",
+ "msdcpll_d4",
+ "vencpll_d4",
+ "tvdpll_ck",
+ "univpll_d2",
+ "univpll1_d2",
+ "mmpll_ck",
+ "msdcpll2_ck",
+ "msdcpll2_d2",
+ "msdcpll2_d4"
+};
+
+static const char * const msdc30_1_parents[] = {
+ "clk26m",
+ "univpll2_d2",
+ "msdcpll_d4",
+ "univpll1_d4",
+ "syspll2_d2",
+ "syspll_d7",
+ "univpll_d7",
+ "vencpll_d4"
+};
+
+static const char * const msdc30_2_parents[] = {
+ "clk26m",
+ "univpll2_d2",
+ "msdcpll_d4",
+ "univpll1_d4",
+ "syspll2_d2",
+ "syspll_d7",
+ "univpll_d7",
+ "vencpll_d2"
+};
+
+static const char * const msdc30_3_parents[] = {
+ "clk26m",
+ "msdcpll2_ck",
+ "msdcpll2_d2",
+ "univpll2_d2",
+ "msdcpll2_d4",
+ "msdcpll_d4",
+ "univpll1_d4",
+ "syspll2_d2",
+ "syspll_d7",
+ "univpll_d7",
+ "vencpll_d4",
+ "msdcpll_ck",
+ "msdcpll_d2",
+ "msdcpll_d4"
+};
+
+static const char * const audio_parents[] = {
+ "clk26m",
+ "syspll3_d4",
+ "syspll4_d4",
+ "syspll1_d16"
+};
+
+static const char * const aud_intbus_parents[] = {
+ "clk26m",
+ "syspll1_d4",
+ "syspll4_d2",
+ "univpll3_d2",
+ "univpll2_d8",
+ "dmpll_d4",
+ "dmpll_d8"
+};
+
+static const char * const pmicspi_parents[] = {
+ "clk26m",
+ "syspll1_d8",
+ "syspll3_d4",
+ "syspll1_d16",
+ "univpll3_d4",
+ "univpll_d26",
+ "dmpll_d8",
+ "dmpll_d16"
+};
+
+static const char * const scp_parents[] = {
+ "clk26m",
+ "syspll1_d2",
+ "univpll_d5",
+ "syspll_d5",
+ "dmpll_d2",
+ "dmpll_d4"
+};
+
+static const char * const atb_parents[] = {
+ "clk26m",
+ "syspll1_d2",
+ "univpll_d5",
+ "dmpll_d2"
+};
+
+static const char * const venc_lt_parents[] = {
+ "clk26m",
+ "univpll_d3",
+ "vcodecpll_ck",
+ "tvdpll_445p5m",
+ "vencpll_d2",
+ "syspll_d3",
+ "univpll1_d2",
+ "univpll2_d2",
+ "syspll1_d2",
+ "univpll_d5",
+ "vcodecpll_370p5",
+ "dmpll_ck"
+};
+
+static const char * const dpi0_parents[] = {
+ "clk26m",
+ "tvdpll_d2",
+ "tvdpll_d4",
+ "clk26m",
+ "clk26m",
+ "tvdpll_d8",
+ "tvdpll_d16"
+};
+
+static const char * const irda_parents[] = {
+ "clk26m",
+ "univpll2_d4",
+ "syspll2_d4"
+};
+
+static const char * const cci400_parents[] = {
+ "clk26m",
+ "vencpll_ck",
+ "armca7pll_754m",
+ "armca7pll_502m",
+ "univpll_d2",
+ "syspll_d2",
+ "msdcpll_ck",
+ "dmpll_ck"
+};
+
+static const char * const aud_1_parents[] = {
+ "clk26m",
+ "apll1_ck",
+ "univpll2_d4",
+ "univpll2_d8"
+};
+
+static const char * const aud_2_parents[] = {
+ "clk26m",
+ "apll2_ck",
+ "univpll2_d4",
+ "univpll2_d8"
+};
+
+static const char * const mem_mfg_in_parents[] = {
+ "clk26m",
+ "mmpll_ck",
+ "dmpll_ck",
+ "clk26m"
+};
+
+static const char * const axi_mfg_in_parents[] = {
+ "clk26m",
+ "axi_sel",
+ "dmpll_d2"
+};
+
+static const char * const scam_parents[] = {
+ "clk26m",
+ "syspll3_d2",
+ "univpll2_d4",
+ "dmpll_d4"
+};
+
+static const char * const spinfi_ifr_parents[] = {
+ "clk26m",
+ "univpll2_d8",
+ "univpll3_d4",
+ "syspll4_d2",
+ "univpll2_d4",
+ "univpll3_d2",
+ "syspll1_d4",
+ "univpll1_d4"
+};
+
+static const char * const hdmi_parents[] = {
+ "clk26m",
+ "hdmitx_dig_cts",
+ "hdmitxpll_d2",
+ "hdmitxpll_d3"
+};
+
+static const char * const dpilvds_parents[] = {
+ "clk26m",
+ "lvdspll",
+ "lvdspll_d2",
+ "lvdspll_d4",
+ "lvdspll_d8",
+ "fpc_ck"
+};
+
+static const char * const msdc50_2_h_parents[] = {
+ "clk26m",
+ "syspll1_d2",
+ "syspll2_d2",
+ "syspll4_d2",
+ "univpll_d5",
+ "univpll1_d4"
+};
+
+static const char * const hdcp_parents[] = {
+ "clk26m",
+ "syspll4_d2",
+ "syspll3_d4",
+ "univpll2_d4"
+};
+
+static const char * const hdcp_24m_parents[] = {
+ "clk26m",
+ "univpll_d26",
+ "univpll_d52",
+ "univpll2_d8"
+};
+
+static const char * const rtc_parents[] = {
+ "clkrtc_int",
+ "clkrtc_ext",
+ "clk26m",
+ "univpll3_d8"
+};
+
+static const char * const i2s0_m_ck_parents[] = {
+ "apll1_div1",
+ "apll2_div1"
+};
+
+static const char * const i2s1_m_ck_parents[] = {
+ "apll1_div2",
+ "apll2_div2"
+};
+
+static const char * const i2s2_m_ck_parents[] = {
+ "apll1_div3",
+ "apll2_div3"
+};
+
+static const char * const i2s3_m_ck_parents[] = {
+ "apll1_div4",
+ "apll2_div4"
+};
+
+static const char * const i2s3_b_ck_parents[] = {
+ "apll1_div5",
+ "apll2_div5"
+};
+
+static const struct mtk_fixed_clk fixed_clks[] = {
+ FIXED_CLK(CLK_DUMMY, "topck_dummy", "clk26m", DUMMY_RATE),
+ FIXED_CLK(CLK_TOP_CLKPH_MCK_O, "clkph_mck_o", "clk26m", DUMMY_RATE),
+ FIXED_CLK(CLK_TOP_USB_SYSPLL_125M, "usb_syspll_125m", "clk26m", 125 * MHZ),
+ FIXED_CLK(CLK_TOP_DSI0_DIG, "dsi0_dig", "clk26m", DUMMY_RATE),
+ FIXED_CLK(CLK_TOP_DSI1_DIG, "dsi1_dig", "clk26m", DUMMY_RATE),
+ FIXED_CLK(CLK_TOP_LVDS_PXL, "lvds_pxl", "lvdspll", DUMMY_RATE),
+ FIXED_CLK(CLK_TOP_LVDS_CTS, "lvds_cts", "lvdspll", DUMMY_RATE),
+};
+
+static const struct mtk_fixed_factor top_divs[] = {
+ FACTOR(CLK_TOP_ARMCA7PLL_754M, "armca7pll_754m", "armca7pll", 1, 2),
+ FACTOR(CLK_TOP_ARMCA7PLL_502M, "armca7pll_502m", "armca7pll", 1, 3),
+
+ FACTOR_FLAGS(CLK_TOP_MAIN_H546M, "main_h546m", "mainpll", 1, 2, 0),
+ FACTOR_FLAGS(CLK_TOP_MAIN_H364M, "main_h364m", "mainpll", 1, 3, 0),
+ FACTOR_FLAGS(CLK_TOP_MAIN_H218P4M, "main_h218p4m", "mainpll", 1, 5, 0),
+ FACTOR_FLAGS(CLK_TOP_MAIN_H156M, "main_h156m", "mainpll", 1, 7, 0),
+
+ FACTOR(CLK_TOP_TVDPLL_445P5M, "tvdpll_445p5m", "tvdpll", 1, 4),
+ FACTOR(CLK_TOP_TVDPLL_594M, "tvdpll_594m", "tvdpll", 1, 3),
+
+ FACTOR_FLAGS(CLK_TOP_UNIV_624M, "univ_624m", "univpll", 1, 2, 0),
+ FACTOR_FLAGS(CLK_TOP_UNIV_416M, "univ_416m", "univpll", 1, 3, 0),
+ FACTOR_FLAGS(CLK_TOP_UNIV_249P6M, "univ_249p6m", "univpll", 1, 5, 0),
+ FACTOR_FLAGS(CLK_TOP_UNIV_178P3M, "univ_178p3m", "univpll", 1, 7, 0),
+ FACTOR_FLAGS(CLK_TOP_UNIV_48M, "univ_48m", "univpll", 1, 26, 0),
+
+ FACTOR(CLK_TOP_CLKRTC_EXT, "clkrtc_ext", "clk32k", 1, 1),
+ FACTOR(CLK_TOP_CLKRTC_INT, "clkrtc_int", "clk26m", 1, 793),
+ FACTOR(CLK_TOP_FPC, "fpc_ck", "clk26m", 1, 1),
+
+ FACTOR(CLK_TOP_HDMITXPLL_D2, "hdmitxpll_d2", "hdmitx_dig_cts", 1, 2),
+ FACTOR(CLK_TOP_HDMITXPLL_D3, "hdmitxpll_d3", "hdmitx_dig_cts", 1, 3),
+
+ FACTOR(CLK_TOP_ARMCA7PLL_D2, "armca7pll_d2", "armca7pll_754m", 1, 1),
+ FACTOR(CLK_TOP_ARMCA7PLL_D3, "armca7pll_d3", "armca7pll_502m", 1, 1),
+
+ FACTOR(CLK_TOP_APLL1, "apll1_ck", "apll1", 1, 1),
+ FACTOR(CLK_TOP_APLL2, "apll2_ck", "apll2", 1, 1),
+
+ FACTOR(CLK_TOP_DMPLL, "dmpll_ck", "clkph_mck_o", 1, 1),
+ FACTOR(CLK_TOP_DMPLL_D2, "dmpll_d2", "clkph_mck_o", 1, 2),
+ FACTOR(CLK_TOP_DMPLL_D4, "dmpll_d4", "clkph_mck_o", 1, 4),
+ FACTOR(CLK_TOP_DMPLL_D8, "dmpll_d8", "clkph_mck_o", 1, 8),
+ FACTOR(CLK_TOP_DMPLL_D16, "dmpll_d16", "clkph_mck_o", 1, 16),
+
+ FACTOR(CLK_TOP_LVDSPLL_D2, "lvdspll_d2", "lvdspll", 1, 2),
+ FACTOR(CLK_TOP_LVDSPLL_D4, "lvdspll_d4", "lvdspll", 1, 4),
+ FACTOR(CLK_TOP_LVDSPLL_D8, "lvdspll_d8", "lvdspll", 1, 8),
+
+ FACTOR(CLK_TOP_MMPLL, "mmpll_ck", "mmpll", 1, 1),
+ FACTOR(CLK_TOP_MMPLL_D2, "mmpll_d2", "mmpll", 1, 2),
+
+ FACTOR(CLK_TOP_MSDCPLL, "msdcpll_ck", "msdcpll", 1, 1),
+ FACTOR(CLK_TOP_MSDCPLL_D2, "msdcpll_d2", "msdcpll", 1, 2),
+ FACTOR(CLK_TOP_MSDCPLL_D4, "msdcpll_d4", "msdcpll", 1, 4),
+ FACTOR(CLK_TOP_MSDCPLL2, "msdcpll2_ck", "msdcpll2", 1, 1),
+ FACTOR(CLK_TOP_MSDCPLL2_D2, "msdcpll2_d2", "msdcpll2", 1, 2),
+ FACTOR(CLK_TOP_MSDCPLL2_D4, "msdcpll2_d4", "msdcpll2", 1, 4),
+
+ FACTOR_FLAGS(CLK_TOP_SYSPLL_D2, "syspll_d2", "main_h546m", 1, 1, 0),
+ FACTOR_FLAGS(CLK_TOP_SYSPLL1_D2, "syspll1_d2", "main_h546m", 1, 2, 0),
+ FACTOR_FLAGS(CLK_TOP_SYSPLL1_D4, "syspll1_d4", "main_h546m", 1, 4, 0),
+ FACTOR_FLAGS(CLK_TOP_SYSPLL1_D8, "syspll1_d8", "main_h546m", 1, 8, 0),
+ FACTOR_FLAGS(CLK_TOP_SYSPLL1_D16, "syspll1_d16", "main_h546m", 1, 16, 0),
+ FACTOR_FLAGS(CLK_TOP_SYSPLL_D3, "syspll_d3", "main_h364m", 1, 1, 0),
+ FACTOR_FLAGS(CLK_TOP_SYSPLL2_D2, "syspll2_d2", "main_h364m", 1, 2, 0),
+ FACTOR_FLAGS(CLK_TOP_SYSPLL2_D4, "syspll2_d4", "main_h364m", 1, 4, 0),
+ FACTOR_FLAGS(CLK_TOP_SYSPLL_D5, "syspll_d5", "main_h218p4m", 1, 1, 0),
+ FACTOR_FLAGS(CLK_TOP_SYSPLL3_D2, "syspll3_d2", "main_h218p4m", 1, 2, 0),
+ FACTOR_FLAGS(CLK_TOP_SYSPLL3_D4, "syspll3_d4", "main_h218p4m", 1, 4, 0),
+ FACTOR_FLAGS(CLK_TOP_SYSPLL_D7, "syspll_d7", "main_h156m", 1, 1, 0),
+ FACTOR_FLAGS(CLK_TOP_SYSPLL4_D2, "syspll4_d2", "main_h156m", 1, 2, 0),
+ FACTOR_FLAGS(CLK_TOP_SYSPLL4_D4, "syspll4_d4", "main_h156m", 1, 4, 0),
+
+ FACTOR(CLK_TOP_TVDPLL, "tvdpll_ck", "tvdpll_594m", 1, 1),
+ FACTOR(CLK_TOP_TVDPLL_D2, "tvdpll_d2", "tvdpll_594m", 1, 2),
+ FACTOR(CLK_TOP_TVDPLL_D4, "tvdpll_d4", "tvdpll_594m", 1, 4),
+ FACTOR(CLK_TOP_TVDPLL_D8, "tvdpll_d8", "tvdpll_594m", 1, 8),
+ FACTOR(CLK_TOP_TVDPLL_D16, "tvdpll_d16", "tvdpll_594m", 1, 16),
+
+ FACTOR_FLAGS(CLK_TOP_UNIVPLL_D2, "univpll_d2", "univ_624m", 1, 1, 0),
+ FACTOR_FLAGS(CLK_TOP_UNIVPLL1_D2, "univpll1_d2", "univ_624m", 1, 2, 0),
+ FACTOR_FLAGS(CLK_TOP_UNIVPLL1_D4, "univpll1_d4", "univ_624m", 1, 4, 0),
+ FACTOR_FLAGS(CLK_TOP_UNIVPLL1_D8, "univpll1_d8", "univ_624m", 1, 8, 0),
+ FACTOR_FLAGS(CLK_TOP_UNIVPLL_D3, "univpll_d3", "univ_416m", 1, 1, 0),
+ FACTOR_FLAGS(CLK_TOP_UNIVPLL2_D2, "univpll2_d2", "univ_416m", 1, 2, 0),
+ FACTOR_FLAGS(CLK_TOP_UNIVPLL2_D4, "univpll2_d4", "univ_416m", 1, 4, 0),
+ FACTOR_FLAGS(CLK_TOP_UNIVPLL2_D8, "univpll2_d8", "univ_416m", 1, 8, 0),
+ FACTOR_FLAGS(CLK_TOP_UNIVPLL_D5, "univpll_d5", "univ_249p6m", 1, 1, 0),
+ FACTOR_FLAGS(CLK_TOP_UNIVPLL3_D2, "univpll3_d2", "univ_249p6m", 1, 2, 0),
+ FACTOR_FLAGS(CLK_TOP_UNIVPLL3_D4, "univpll3_d4", "univ_249p6m", 1, 4, 0),
+ FACTOR_FLAGS(CLK_TOP_UNIVPLL3_D8, "univpll3_d8", "univ_249p6m", 1, 8, 0),
+ FACTOR_FLAGS(CLK_TOP_UNIVPLL_D7, "univpll_d7", "univ_178p3m", 1, 1, 0),
+ FACTOR_FLAGS(CLK_TOP_UNIVPLL_D26, "univpll_d26", "univ_48m", 1, 1, 0),
+ FACTOR_FLAGS(CLK_TOP_UNIVPLL_D52, "univpll_d52", "univ_48m", 1, 2, 0),
+
+ FACTOR(CLK_TOP_VCODECPLL, "vcodecpll_ck", "vcodecpll", 1, 3),
+ FACTOR(CLK_TOP_VCODECPLL_370P5, "vcodecpll_370p5", "vcodecpll", 1, 4),
+
+ FACTOR(CLK_TOP_VENCPLL, "vencpll_ck", "vencpll", 1, 1),
+ FACTOR(CLK_TOP_VENCPLL_D2, "vencpll_d2", "vencpll", 1, 2),
+ FACTOR(CLK_TOP_VENCPLL_D4, "vencpll_d4", "vencpll", 1, 4),
+};
+
+static const struct mtk_composite top_muxes[] = {
+ /* CLK_CFG_0 */
+ MUX(CLK_TOP_AXI_SEL, "axi_sel", axi_parents, 0x0040, 0, 3),
+ MUX_FLAGS(CLK_TOP_MEM_SEL, "mem_sel", mem_parents, 0x0040, 8, 1,
+ CLK_IS_CRITICAL | CLK_SET_RATE_PARENT),
+ MUX_GATE_FLAGS(CLK_TOP_DDRPHYCFG_SEL, "ddrphycfg_sel",
+ ddrphycfg_parents, 0x0040, 16, 1, 23,
+ CLK_IS_CRITICAL | CLK_SET_RATE_PARENT),
+ MUX_GATE(CLK_TOP_MM_SEL, "mm_sel", mm_parents, 0x0040, 24, 4, 31),
+ /* CLK_CFG_1 */
+ MUX_GATE(CLK_TOP_PWM_SEL, "pwm_sel", pwm_parents, 0x0050, 0, 2, 7),
+ MUX_GATE(CLK_TOP_VDEC_SEL, "vdec_sel", vdec_parents, 0x0050, 8, 4, 15),
+ MUX_GATE(CLK_TOP_VENC_SEL, "venc_sel", venc_parents, 0x0050, 16, 4, 23),
+ MUX_GATE(CLK_TOP_MFG_SEL, "mfg_sel", mfg_parents, 0x0050, 24, 4, 31),
+ /* CLK_CFG_2 */
+ MUX_GATE(CLK_TOP_CAMTG_SEL, "camtg_sel", camtg_parents, 0x0060, 0, 3, 7),
+ MUX_GATE(CLK_TOP_UART_SEL, "uart_sel", uart_parents, 0x0060, 8, 1, 15),
+ MUX_GATE(CLK_TOP_SPI_SEL, "spi_sel", spi_parents, 0x0060, 16, 3, 23),
+ MUX_GATE(CLK_TOP_USB20_SEL, "usb20_sel", usb20_parents, 0x0060, 24, 2, 31),
+ /* CLK_CFG_3 */
+ MUX_GATE(CLK_TOP_USB30_SEL, "usb30_sel", usb30_parents, 0x0070, 0, 2, 7),
+ MUX_GATE(CLK_TOP_MSDC50_0_H_SEL, "msdc50_0_h_sel", msdc50_0_h_parents,
+ 0x0070, 8, 3, 15),
+ MUX_GATE(CLK_TOP_MSDC50_0_SEL, "msdc50_0_sel", msdc50_0_parents,
+ 0x0070, 16, 4, 23),
+ MUX_GATE(CLK_TOP_MSDC30_1_SEL, "msdc30_1_sel", msdc30_1_parents,
+ 0x0070, 24, 3, 31),
+ /* CLK_CFG_4 */
+ MUX_GATE(CLK_TOP_MSDC30_2_SEL, "msdc30_2_sel", msdc30_2_parents,
+ 0x0080, 0, 3, 7),
+ MUX_GATE(CLK_TOP_MSDC30_3_SEL, "msdc30_3_sel", msdc30_3_parents,
+ 0x0080, 8, 4, 15),
+ MUX_GATE(CLK_TOP_AUDIO_SEL, "audio_sel", audio_parents,
+ 0x0080, 16, 2, 23),
+ MUX_GATE(CLK_TOP_AUD_INTBUS_SEL, "aud_intbus_sel", aud_intbus_parents,
+ 0x0080, 24, 3, 31),
+ /* CLK_CFG_5 */
+ MUX_GATE(CLK_TOP_PMICSPI_SEL, "pmicspi_sel", pmicspi_parents,
+ 0x0090, 0, 3, 7 /* 7:5 */),
+ MUX_GATE(CLK_TOP_SCP_SEL, "scp_sel", scp_parents, 0x0090, 8, 3, 15),
+ MUX_GATE(CLK_TOP_ATB_SEL, "atb_sel", atb_parents, 0x0090, 16, 2, 23),
+ MUX_GATE(CLK_TOP_VENC_LT_SEL, "venclt_sel", venc_lt_parents,
+ 0x0090, 24, 4, 31),
+ /* CLK_CFG_6 */
+ /*
+ * The dpi0_sel clock should not propagate rate changes to its parent
+ * clock so the dpi driver can have full control over PLL and divider.
+ */
+ MUX_GATE_FLAGS(CLK_TOP_DPI0_SEL, "dpi0_sel", dpi0_parents,
+ 0x00a0, 0, 3, 7, 0),
+ MUX_GATE(CLK_TOP_IRDA_SEL, "irda_sel", irda_parents, 0x00a0, 8, 2, 15),
+ MUX_GATE_FLAGS(CLK_TOP_CCI400_SEL, "cci400_sel",
+ cci400_parents, 0x00a0, 16, 3, 23,
+ CLK_IS_CRITICAL | CLK_SET_RATE_PARENT),
+ MUX_GATE(CLK_TOP_AUD_1_SEL, "aud_1_sel", aud_1_parents, 0x00a0, 24, 2, 31),
+ /* CLK_CFG_7 */
+ MUX_GATE(CLK_TOP_AUD_2_SEL, "aud_2_sel", aud_2_parents, 0x00b0, 0, 2, 7),
+ MUX_GATE(CLK_TOP_MEM_MFG_IN_SEL, "mem_mfg_in_sel", mem_mfg_in_parents,
+ 0x00b0, 8, 2, 15),
+ MUX_GATE(CLK_TOP_AXI_MFG_IN_SEL, "axi_mfg_in_sel", axi_mfg_in_parents,
+ 0x00b0, 16, 2, 23),
+ MUX_GATE(CLK_TOP_SCAM_SEL, "scam_sel", scam_parents, 0x00b0, 24, 2, 31),
+ /* CLK_CFG_12 */
+ MUX_GATE(CLK_TOP_SPINFI_IFR_SEL, "spinfi_ifr_sel", spinfi_ifr_parents,
+ 0x00c0, 0, 3, 7),
+ MUX_GATE(CLK_TOP_HDMI_SEL, "hdmi_sel", hdmi_parents, 0x00c0, 8, 2, 15),
+ MUX_GATE(CLK_TOP_DPILVDS_SEL, "dpilvds_sel", dpilvds_parents,
+ 0x00c0, 24, 3, 31),
+ /* CLK_CFG_13 */
+ MUX_GATE(CLK_TOP_MSDC50_2_H_SEL, "msdc50_2_h_sel", msdc50_2_h_parents,
+ 0x00d0, 0, 3, 7),
+ MUX_GATE(CLK_TOP_HDCP_SEL, "hdcp_sel", hdcp_parents, 0x00d0, 8, 2, 15),
+ MUX_GATE(CLK_TOP_HDCP_24M_SEL, "hdcp_24m_sel", hdcp_24m_parents,
+ 0x00d0, 16, 2, 23),
+ MUX_FLAGS(CLK_TOP_RTC_SEL, "rtc_sel", rtc_parents, 0x00d0, 24, 2,
+ CLK_IS_CRITICAL | CLK_SET_RATE_PARENT),
+
+ DIV_GATE(CLK_TOP_APLL1_DIV0, "apll1_div0", "aud_1_sel", 0x12c, 8, 0x120, 4, 24),
+ DIV_GATE(CLK_TOP_APLL1_DIV1, "apll1_div1", "aud_1_sel", 0x12c, 9, 0x124, 8, 0),
+ DIV_GATE(CLK_TOP_APLL1_DIV2, "apll1_div2", "aud_1_sel", 0x12c, 10, 0x124, 8, 8),
+ DIV_GATE(CLK_TOP_APLL1_DIV3, "apll1_div3", "aud_1_sel", 0x12c, 11, 0x124, 8, 16),
+ DIV_GATE(CLK_TOP_APLL1_DIV4, "apll1_div4", "aud_1_sel", 0x12c, 12, 0x124, 8, 24),
+ DIV_GATE(CLK_TOP_APLL1_DIV5, "apll1_div5", "apll1_div4", 0x12c, 13, 0x12c, 4, 0),
+
+ DIV_GATE(CLK_TOP_APLL2_DIV0, "apll2_div0", "aud_2_sel", 0x12c, 16, 0x120, 4, 28),
+ DIV_GATE(CLK_TOP_APLL2_DIV1, "apll2_div1", "aud_2_sel", 0x12c, 17, 0x128, 8, 0),
+ DIV_GATE(CLK_TOP_APLL2_DIV2, "apll2_div2", "aud_2_sel", 0x12c, 18, 0x128, 8, 8),
+ DIV_GATE(CLK_TOP_APLL2_DIV3, "apll2_div3", "aud_2_sel", 0x12c, 19, 0x128, 8, 16),
+ DIV_GATE(CLK_TOP_APLL2_DIV4, "apll2_div4", "aud_2_sel", 0x12c, 20, 0x128, 8, 24),
+ DIV_GATE(CLK_TOP_APLL2_DIV5, "apll2_div5", "apll2_div4", 0x12c, 21, 0x12c, 4, 4),
+
+ MUX(CLK_TOP_I2S0_M_SEL, "i2s0_m_ck_sel", i2s0_m_ck_parents, 0x120, 4, 1),
+ MUX(CLK_TOP_I2S1_M_SEL, "i2s1_m_ck_sel", i2s1_m_ck_parents, 0x120, 5, 1),
+ MUX(CLK_TOP_I2S2_M_SEL, "i2s2_m_ck_sel", i2s2_m_ck_parents, 0x120, 6, 1),
+ MUX(CLK_TOP_I2S3_M_SEL, "i2s3_m_ck_sel", i2s3_m_ck_parents, 0x120, 7, 1),
+ MUX(CLK_TOP_I2S3_B_SEL, "i2s3_b_ck_sel", i2s3_b_ck_parents, 0x120, 8, 1),
+};
+
+static const struct mtk_clk_desc topck_desc = {
+ .fixed_clks = fixed_clks,
+ .num_fixed_clks = ARRAY_SIZE(fixed_clks),
+ .factor_clks = top_divs,
+ .num_factor_clks = ARRAY_SIZE(top_divs),
+ .composite_clks = top_muxes,
+ .num_composite_clks = ARRAY_SIZE(top_muxes),
+ .clk_lock = &mt8173_top_clk_lock,
+};
+
+static const struct of_device_id of_match_clk_mt8173_topckgen[] = {
+ { .compatible = "mediatek,mt8173-topckgen", .data = &topck_desc },
+ { /* sentinel */ }
+};
+
+static struct platform_driver clk_mt8173_topckgen_drv = {
+ .driver = {
+ .name = "clk-mt8173-topckgen",
+ .of_match_table = of_match_clk_mt8173_topckgen,
+ },
+ .probe = mtk_clk_simple_probe,
+ .remove = mtk_clk_simple_remove,
+};
+module_platform_driver(clk_mt8173_topckgen_drv);
+
+MODULE_DESCRIPTION("MediaTek MT8173 topckgen clocks driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/mediatek/clk-mt8173-vdecsys.c b/drivers/clk/mediatek/clk-mt8173-vdecsys.c
new file mode 100644
index 000000000000..5105b8e0969d
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt8173-vdecsys.c
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ * Copyright (c) 2022 Collabora Ltd.
+ * Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+ */
+
+#include <dt-bindings/clock/mt8173-clk.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include "clk-gate.h"
+#include "clk-mtk.h"
+
+#define GATE_VDEC(_id, _name, _parent, _regs) \
+ GATE_MTK(_id, _name, _parent, _regs, 0, \
+ &mtk_clk_gate_ops_setclr_inv)
+
+static const struct mtk_gate_regs vdec0_cg_regs = {
+ .set_ofs = 0x0000,
+ .clr_ofs = 0x0004,
+ .sta_ofs = 0x0000,
+};
+
+static const struct mtk_gate_regs vdec1_cg_regs = {
+ .set_ofs = 0x0008,
+ .clr_ofs = 0x000c,
+ .sta_ofs = 0x0008,
+};
+
+static const struct mtk_gate vdec_clks[] = {
+ GATE_DUMMY(CLK_DUMMY, "vdec_dummy"),
+ GATE_VDEC(CLK_VDEC_CKEN, "vdec_cken", "vdec_sel", &vdec0_cg_regs),
+ GATE_VDEC(CLK_VDEC_LARB_CKEN, "vdec_larb_cken", "mm_sel", &vdec1_cg_regs),
+};
+
+static const struct mtk_clk_desc vdec_desc = {
+ .clks = vdec_clks,
+ .num_clks = ARRAY_SIZE(vdec_clks),
+};
+
+static const struct of_device_id of_match_clk_mt8173_vdecsys[] = {
+ { .compatible = "mediatek,mt8173-vdecsys", .data = &vdec_desc },
+ { /* sentinel */ }
+};
+
+static struct platform_driver clk_mt8173_vdecsys_drv = {
+ .probe = mtk_clk_simple_probe,
+ .remove = mtk_clk_simple_remove,
+ .driver = {
+ .name = "clk-mt8173-vdecsys",
+ .of_match_table = of_match_clk_mt8173_vdecsys,
+ },
+};
+module_platform_driver(clk_mt8173_vdecsys_drv);
+
+MODULE_DESCRIPTION("MediaTek MT8173 vdecsys clocks driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/mediatek/clk-mt8173-vencsys.c b/drivers/clk/mediatek/clk-mt8173-vencsys.c
new file mode 100644
index 000000000000..ff4f1cb735de
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt8173-vencsys.c
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ * Copyright (c) 2022 Collabora Ltd.
+ * Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+ */
+
+#include <dt-bindings/clock/mt8173-clk.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include "clk-gate.h"
+#include "clk-mtk.h"
+
+static const struct mtk_gate_regs venc_cg_regs = {
+ .set_ofs = 0x4,
+ .clr_ofs = 0x8,
+ .sta_ofs = 0x0,
+};
+
+#define GATE_VENC(_id, _name, _parent, _shift) \
+ GATE_MTK(_id, _name, _parent, &venc_cg_regs, _shift, &mtk_clk_gate_ops_setclr_inv)
+
+static const struct mtk_gate venc_clks[] = {
+ GATE_DUMMY(CLK_DUMMY, "venc_dummy"),
+ GATE_VENC(CLK_VENC_CKE0, "venc_cke0", "mm_sel", 0),
+ GATE_VENC(CLK_VENC_CKE1, "venc_cke1", "venc_sel", 4),
+ GATE_VENC(CLK_VENC_CKE2, "venc_cke2", "venc_sel", 8),
+ GATE_VENC(CLK_VENC_CKE3, "venc_cke3", "venc_sel", 12),
+};
+
+static const struct mtk_gate venclt_clks[] = {
+ GATE_DUMMY(CLK_DUMMY, "venclt_dummy"),
+ GATE_VENC(CLK_VENCLT_CKE0, "venclt_cke0", "mm_sel", 0),
+ GATE_VENC(CLK_VENCLT_CKE1, "venclt_cke1", "venclt_sel", 4),
+};
+
+static const struct mtk_clk_desc venc_desc = {
+ .clks = venc_clks,
+ .num_clks = ARRAY_SIZE(venc_clks),
+};
+
+static const struct mtk_clk_desc venc_lt_desc = {
+ .clks = venclt_clks,
+ .num_clks = ARRAY_SIZE(venclt_clks),
+};
+
+static const struct of_device_id of_match_clk_mt8173_vencsys[] = {
+ { .compatible = "mediatek,mt8173-vencsys", .data = &venc_desc },
+ { .compatible = "mediatek,mt8173-vencltsys", .data = &venc_lt_desc },
+ { /* sentinel */ }
+};
+
+static struct platform_driver clk_mt8173_vencsys_drv = {
+ .driver = {
+ .name = "clk-mt8173-vencsys",
+ .of_match_table = of_match_clk_mt8173_vencsys,
+ },
+ .probe = mtk_clk_simple_probe,
+ .remove = mtk_clk_simple_remove,
+};
+module_platform_driver(clk_mt8173_vencsys_drv);
+
+MODULE_DESCRIPTION("MediaTek MT8173 vencsys clocks driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/mediatek/clk-mt8173.c b/drivers/clk/mediatek/clk-mt8173.c
deleted file mode 100644
index b57e33cda7a5..000000000000
--- a/drivers/clk/mediatek/clk-mt8173.c
+++ /dev/null
@@ -1,1125 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (c) 2014 MediaTek Inc.
- * Author: James Liao <jamesjj.liao@mediatek.com>
- */
-
-#include <linux/clk.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-
-#include "clk-cpumux.h"
-#include "clk-gate.h"
-#include "clk-mtk.h"
-#include "clk-pll.h"
-
-#include <dt-bindings/clock/mt8173-clk.h>
-
-/*
- * For some clocks, we don't care what their actual rates are. And these
- * clocks may change their rate on different products or different scenarios.
- * So we model these clocks' rate as 0, to denote it's not an actual rate.
- */
-#define DUMMY_RATE 0
-
-static DEFINE_SPINLOCK(mt8173_clk_lock);
-
-static const struct mtk_fixed_clk fixed_clks[] __initconst = {
- FIXED_CLK(CLK_TOP_CLKPH_MCK_O, "clkph_mck_o", "clk26m", DUMMY_RATE),
- FIXED_CLK(CLK_TOP_USB_SYSPLL_125M, "usb_syspll_125m", "clk26m", 125 * MHZ),
- FIXED_CLK(CLK_TOP_DSI0_DIG, "dsi0_dig", "clk26m", DUMMY_RATE),
- FIXED_CLK(CLK_TOP_DSI1_DIG, "dsi1_dig", "clk26m", DUMMY_RATE),
- FIXED_CLK(CLK_TOP_LVDS_PXL, "lvds_pxl", "lvdspll", DUMMY_RATE),
- FIXED_CLK(CLK_TOP_LVDS_CTS, "lvds_cts", "lvdspll", DUMMY_RATE),
-};
-
-static const struct mtk_fixed_factor top_divs[] __initconst = {
- FACTOR(CLK_TOP_ARMCA7PLL_754M, "armca7pll_754m", "armca7pll", 1, 2),
- FACTOR(CLK_TOP_ARMCA7PLL_502M, "armca7pll_502m", "armca7pll", 1, 3),
-
- FACTOR_FLAGS(CLK_TOP_MAIN_H546M, "main_h546m", "mainpll", 1, 2, 0),
- FACTOR_FLAGS(CLK_TOP_MAIN_H364M, "main_h364m", "mainpll", 1, 3, 0),
- FACTOR_FLAGS(CLK_TOP_MAIN_H218P4M, "main_h218p4m", "mainpll", 1, 5, 0),
- FACTOR_FLAGS(CLK_TOP_MAIN_H156M, "main_h156m", "mainpll", 1, 7, 0),
-
- FACTOR(CLK_TOP_TVDPLL_445P5M, "tvdpll_445p5m", "tvdpll", 1, 4),
- FACTOR(CLK_TOP_TVDPLL_594M, "tvdpll_594m", "tvdpll", 1, 3),
-
- FACTOR_FLAGS(CLK_TOP_UNIV_624M, "univ_624m", "univpll", 1, 2, 0),
- FACTOR_FLAGS(CLK_TOP_UNIV_416M, "univ_416m", "univpll", 1, 3, 0),
- FACTOR_FLAGS(CLK_TOP_UNIV_249P6M, "univ_249p6m", "univpll", 1, 5, 0),
- FACTOR_FLAGS(CLK_TOP_UNIV_178P3M, "univ_178p3m", "univpll", 1, 7, 0),
- FACTOR_FLAGS(CLK_TOP_UNIV_48M, "univ_48m", "univpll", 1, 26, 0),
-
- FACTOR(CLK_TOP_CLKRTC_EXT, "clkrtc_ext", "clk32k", 1, 1),
- FACTOR(CLK_TOP_CLKRTC_INT, "clkrtc_int", "clk26m", 1, 793),
- FACTOR(CLK_TOP_FPC, "fpc_ck", "clk26m", 1, 1),
-
- FACTOR(CLK_TOP_HDMITXPLL_D2, "hdmitxpll_d2", "hdmitx_dig_cts", 1, 2),
- FACTOR(CLK_TOP_HDMITXPLL_D3, "hdmitxpll_d3", "hdmitx_dig_cts", 1, 3),
-
- FACTOR(CLK_TOP_ARMCA7PLL_D2, "armca7pll_d2", "armca7pll_754m", 1, 1),
- FACTOR(CLK_TOP_ARMCA7PLL_D3, "armca7pll_d3", "armca7pll_502m", 1, 1),
-
- FACTOR(CLK_TOP_APLL1, "apll1_ck", "apll1", 1, 1),
- FACTOR(CLK_TOP_APLL2, "apll2_ck", "apll2", 1, 1),
-
- FACTOR(CLK_TOP_DMPLL, "dmpll_ck", "clkph_mck_o", 1, 1),
- FACTOR(CLK_TOP_DMPLL_D2, "dmpll_d2", "clkph_mck_o", 1, 2),
- FACTOR(CLK_TOP_DMPLL_D4, "dmpll_d4", "clkph_mck_o", 1, 4),
- FACTOR(CLK_TOP_DMPLL_D8, "dmpll_d8", "clkph_mck_o", 1, 8),
- FACTOR(CLK_TOP_DMPLL_D16, "dmpll_d16", "clkph_mck_o", 1, 16),
-
- FACTOR(CLK_TOP_LVDSPLL_D2, "lvdspll_d2", "lvdspll", 1, 2),
- FACTOR(CLK_TOP_LVDSPLL_D4, "lvdspll_d4", "lvdspll", 1, 4),
- FACTOR(CLK_TOP_LVDSPLL_D8, "lvdspll_d8", "lvdspll", 1, 8),
-
- FACTOR(CLK_TOP_MMPLL, "mmpll_ck", "mmpll", 1, 1),
- FACTOR(CLK_TOP_MMPLL_D2, "mmpll_d2", "mmpll", 1, 2),
-
- FACTOR(CLK_TOP_MSDCPLL, "msdcpll_ck", "msdcpll", 1, 1),
- FACTOR(CLK_TOP_MSDCPLL_D2, "msdcpll_d2", "msdcpll", 1, 2),
- FACTOR(CLK_TOP_MSDCPLL_D4, "msdcpll_d4", "msdcpll", 1, 4),
- FACTOR(CLK_TOP_MSDCPLL2, "msdcpll2_ck", "msdcpll2", 1, 1),
- FACTOR(CLK_TOP_MSDCPLL2_D2, "msdcpll2_d2", "msdcpll2", 1, 2),
- FACTOR(CLK_TOP_MSDCPLL2_D4, "msdcpll2_d4", "msdcpll2", 1, 4),
-
- FACTOR_FLAGS(CLK_TOP_SYSPLL_D2, "syspll_d2", "main_h546m", 1, 1, 0),
- FACTOR_FLAGS(CLK_TOP_SYSPLL1_D2, "syspll1_d2", "main_h546m", 1, 2, 0),
- FACTOR_FLAGS(CLK_TOP_SYSPLL1_D4, "syspll1_d4", "main_h546m", 1, 4, 0),
- FACTOR_FLAGS(CLK_TOP_SYSPLL1_D8, "syspll1_d8", "main_h546m", 1, 8, 0),
- FACTOR_FLAGS(CLK_TOP_SYSPLL1_D16, "syspll1_d16", "main_h546m", 1, 16, 0),
- FACTOR_FLAGS(CLK_TOP_SYSPLL_D3, "syspll_d3", "main_h364m", 1, 1, 0),
- FACTOR_FLAGS(CLK_TOP_SYSPLL2_D2, "syspll2_d2", "main_h364m", 1, 2, 0),
- FACTOR_FLAGS(CLK_TOP_SYSPLL2_D4, "syspll2_d4", "main_h364m", 1, 4, 0),
- FACTOR_FLAGS(CLK_TOP_SYSPLL_D5, "syspll_d5", "main_h218p4m", 1, 1, 0),
- FACTOR_FLAGS(CLK_TOP_SYSPLL3_D2, "syspll3_d2", "main_h218p4m", 1, 2, 0),
- FACTOR_FLAGS(CLK_TOP_SYSPLL3_D4, "syspll3_d4", "main_h218p4m", 1, 4, 0),
- FACTOR_FLAGS(CLK_TOP_SYSPLL_D7, "syspll_d7", "main_h156m", 1, 1, 0),
- FACTOR_FLAGS(CLK_TOP_SYSPLL4_D2, "syspll4_d2", "main_h156m", 1, 2, 0),
- FACTOR_FLAGS(CLK_TOP_SYSPLL4_D4, "syspll4_d4", "main_h156m", 1, 4, 0),
-
- FACTOR(CLK_TOP_TVDPLL, "tvdpll_ck", "tvdpll_594m", 1, 1),
- FACTOR(CLK_TOP_TVDPLL_D2, "tvdpll_d2", "tvdpll_594m", 1, 2),
- FACTOR(CLK_TOP_TVDPLL_D4, "tvdpll_d4", "tvdpll_594m", 1, 4),
- FACTOR(CLK_TOP_TVDPLL_D8, "tvdpll_d8", "tvdpll_594m", 1, 8),
- FACTOR(CLK_TOP_TVDPLL_D16, "tvdpll_d16", "tvdpll_594m", 1, 16),
-
- FACTOR_FLAGS(CLK_TOP_UNIVPLL_D2, "univpll_d2", "univ_624m", 1, 1, 0),
- FACTOR_FLAGS(CLK_TOP_UNIVPLL1_D2, "univpll1_d2", "univ_624m", 1, 2, 0),
- FACTOR_FLAGS(CLK_TOP_UNIVPLL1_D4, "univpll1_d4", "univ_624m", 1, 4, 0),
- FACTOR_FLAGS(CLK_TOP_UNIVPLL1_D8, "univpll1_d8", "univ_624m", 1, 8, 0),
- FACTOR_FLAGS(CLK_TOP_UNIVPLL_D3, "univpll_d3", "univ_416m", 1, 1, 0),
- FACTOR_FLAGS(CLK_TOP_UNIVPLL2_D2, "univpll2_d2", "univ_416m", 1, 2, 0),
- FACTOR_FLAGS(CLK_TOP_UNIVPLL2_D4, "univpll2_d4", "univ_416m", 1, 4, 0),
- FACTOR_FLAGS(CLK_TOP_UNIVPLL2_D8, "univpll2_d8", "univ_416m", 1, 8, 0),
- FACTOR_FLAGS(CLK_TOP_UNIVPLL_D5, "univpll_d5", "univ_249p6m", 1, 1, 0),
- FACTOR_FLAGS(CLK_TOP_UNIVPLL3_D2, "univpll3_d2", "univ_249p6m", 1, 2, 0),
- FACTOR_FLAGS(CLK_TOP_UNIVPLL3_D4, "univpll3_d4", "univ_249p6m", 1, 4, 0),
- FACTOR_FLAGS(CLK_TOP_UNIVPLL3_D8, "univpll3_d8", "univ_249p6m", 1, 8, 0),
- FACTOR_FLAGS(CLK_TOP_UNIVPLL_D7, "univpll_d7", "univ_178p3m", 1, 1, 0),
- FACTOR_FLAGS(CLK_TOP_UNIVPLL_D26, "univpll_d26", "univ_48m", 1, 1, 0),
- FACTOR_FLAGS(CLK_TOP_UNIVPLL_D52, "univpll_d52", "univ_48m", 1, 2, 0),
-
- FACTOR(CLK_TOP_VCODECPLL, "vcodecpll_ck", "vcodecpll", 1, 3),
- FACTOR(CLK_TOP_VCODECPLL_370P5, "vcodecpll_370p5", "vcodecpll", 1, 4),
-
- FACTOR(CLK_TOP_VENCPLL, "vencpll_ck", "vencpll", 1, 1),
- FACTOR(CLK_TOP_VENCPLL_D2, "vencpll_d2", "vencpll", 1, 2),
- FACTOR(CLK_TOP_VENCPLL_D4, "vencpll_d4", "vencpll", 1, 4),
-};
-
-static const char * const axi_parents[] __initconst = {
- "clk26m",
- "syspll1_d2",
- "syspll_d5",
- "syspll1_d4",
- "univpll_d5",
- "univpll2_d2",
- "dmpll_d2",
- "dmpll_d4"
-};
-
-static const char * const mem_parents[] __initconst = {
- "clk26m",
- "dmpll_ck"
-};
-
-static const char * const ddrphycfg_parents[] __initconst = {
- "clk26m",
- "syspll1_d8"
-};
-
-static const char * const mm_parents[] __initconst = {
- "clk26m",
- "vencpll_d2",
- "main_h364m",
- "syspll1_d2",
- "syspll_d5",
- "syspll1_d4",
- "univpll1_d2",
- "univpll2_d2",
- "dmpll_d2"
-};
-
-static const char * const pwm_parents[] __initconst = {
- "clk26m",
- "univpll2_d4",
- "univpll3_d2",
- "univpll1_d4"
-};
-
-static const char * const vdec_parents[] __initconst = {
- "clk26m",
- "vcodecpll_ck",
- "tvdpll_445p5m",
- "univpll_d3",
- "vencpll_d2",
- "syspll_d3",
- "univpll1_d2",
- "mmpll_d2",
- "dmpll_d2",
- "dmpll_d4"
-};
-
-static const char * const venc_parents[] __initconst = {
- "clk26m",
- "vcodecpll_ck",
- "tvdpll_445p5m",
- "univpll_d3",
- "vencpll_d2",
- "syspll_d3",
- "univpll1_d2",
- "univpll2_d2",
- "dmpll_d2",
- "dmpll_d4"
-};
-
-static const char * const mfg_parents[] __initconst = {
- "clk26m",
- "mmpll_ck",
- "dmpll_ck",
- "clk26m",
- "clk26m",
- "clk26m",
- "clk26m",
- "clk26m",
- "clk26m",
- "syspll_d3",
- "syspll1_d2",
- "syspll_d5",
- "univpll_d3",
- "univpll1_d2",
- "univpll_d5",
- "univpll2_d2"
-};
-
-static const char * const camtg_parents[] __initconst = {
- "clk26m",
- "univpll_d26",
- "univpll2_d2",
- "syspll3_d2",
- "syspll3_d4",
- "univpll1_d4"
-};
-
-static const char * const uart_parents[] __initconst = {
- "clk26m",
- "univpll2_d8"
-};
-
-static const char * const spi_parents[] __initconst = {
- "clk26m",
- "syspll3_d2",
- "syspll1_d4",
- "syspll4_d2",
- "univpll3_d2",
- "univpll2_d4",
- "univpll1_d8"
-};
-
-static const char * const usb20_parents[] __initconst = {
- "clk26m",
- "univpll1_d8",
- "univpll3_d4"
-};
-
-static const char * const usb30_parents[] __initconst = {
- "clk26m",
- "univpll3_d2",
- "usb_syspll_125m",
- "univpll2_d4"
-};
-
-static const char * const msdc50_0_h_parents[] __initconst = {
- "clk26m",
- "syspll1_d2",
- "syspll2_d2",
- "syspll4_d2",
- "univpll_d5",
- "univpll1_d4"
-};
-
-static const char * const msdc50_0_parents[] __initconst = {
- "clk26m",
- "msdcpll_ck",
- "msdcpll_d2",
- "univpll1_d4",
- "syspll2_d2",
- "syspll_d7",
- "msdcpll_d4",
- "vencpll_d4",
- "tvdpll_ck",
- "univpll_d2",
- "univpll1_d2",
- "mmpll_ck",
- "msdcpll2_ck",
- "msdcpll2_d2",
- "msdcpll2_d4"
-};
-
-static const char * const msdc30_1_parents[] __initconst = {
- "clk26m",
- "univpll2_d2",
- "msdcpll_d4",
- "univpll1_d4",
- "syspll2_d2",
- "syspll_d7",
- "univpll_d7",
- "vencpll_d4"
-};
-
-static const char * const msdc30_2_parents[] __initconst = {
- "clk26m",
- "univpll2_d2",
- "msdcpll_d4",
- "univpll1_d4",
- "syspll2_d2",
- "syspll_d7",
- "univpll_d7",
- "vencpll_d2"
-};
-
-static const char * const msdc30_3_parents[] __initconst = {
- "clk26m",
- "msdcpll2_ck",
- "msdcpll2_d2",
- "univpll2_d2",
- "msdcpll2_d4",
- "msdcpll_d4",
- "univpll1_d4",
- "syspll2_d2",
- "syspll_d7",
- "univpll_d7",
- "vencpll_d4",
- "msdcpll_ck",
- "msdcpll_d2",
- "msdcpll_d4"
-};
-
-static const char * const audio_parents[] __initconst = {
- "clk26m",
- "syspll3_d4",
- "syspll4_d4",
- "syspll1_d16"
-};
-
-static const char * const aud_intbus_parents[] __initconst = {
- "clk26m",
- "syspll1_d4",
- "syspll4_d2",
- "univpll3_d2",
- "univpll2_d8",
- "dmpll_d4",
- "dmpll_d8"
-};
-
-static const char * const pmicspi_parents[] __initconst = {
- "clk26m",
- "syspll1_d8",
- "syspll3_d4",
- "syspll1_d16",
- "univpll3_d4",
- "univpll_d26",
- "dmpll_d8",
- "dmpll_d16"
-};
-
-static const char * const scp_parents[] __initconst = {
- "clk26m",
- "syspll1_d2",
- "univpll_d5",
- "syspll_d5",
- "dmpll_d2",
- "dmpll_d4"
-};
-
-static const char * const atb_parents[] __initconst = {
- "clk26m",
- "syspll1_d2",
- "univpll_d5",
- "dmpll_d2"
-};
-
-static const char * const venc_lt_parents[] __initconst = {
- "clk26m",
- "univpll_d3",
- "vcodecpll_ck",
- "tvdpll_445p5m",
- "vencpll_d2",
- "syspll_d3",
- "univpll1_d2",
- "univpll2_d2",
- "syspll1_d2",
- "univpll_d5",
- "vcodecpll_370p5",
- "dmpll_ck"
-};
-
-static const char * const dpi0_parents[] __initconst = {
- "clk26m",
- "tvdpll_d2",
- "tvdpll_d4",
- "clk26m",
- "clk26m",
- "tvdpll_d8",
- "tvdpll_d16"
-};
-
-static const char * const irda_parents[] __initconst = {
- "clk26m",
- "univpll2_d4",
- "syspll2_d4"
-};
-
-static const char * const cci400_parents[] __initconst = {
- "clk26m",
- "vencpll_ck",
- "armca7pll_754m",
- "armca7pll_502m",
- "univpll_d2",
- "syspll_d2",
- "msdcpll_ck",
- "dmpll_ck"
-};
-
-static const char * const aud_1_parents[] __initconst = {
- "clk26m",
- "apll1_ck",
- "univpll2_d4",
- "univpll2_d8"
-};
-
-static const char * const aud_2_parents[] __initconst = {
- "clk26m",
- "apll2_ck",
- "univpll2_d4",
- "univpll2_d8"
-};
-
-static const char * const mem_mfg_in_parents[] __initconst = {
- "clk26m",
- "mmpll_ck",
- "dmpll_ck",
- "clk26m"
-};
-
-static const char * const axi_mfg_in_parents[] __initconst = {
- "clk26m",
- "axi_sel",
- "dmpll_d2"
-};
-
-static const char * const scam_parents[] __initconst = {
- "clk26m",
- "syspll3_d2",
- "univpll2_d4",
- "dmpll_d4"
-};
-
-static const char * const spinfi_ifr_parents[] __initconst = {
- "clk26m",
- "univpll2_d8",
- "univpll3_d4",
- "syspll4_d2",
- "univpll2_d4",
- "univpll3_d2",
- "syspll1_d4",
- "univpll1_d4"
-};
-
-static const char * const hdmi_parents[] __initconst = {
- "clk26m",
- "hdmitx_dig_cts",
- "hdmitxpll_d2",
- "hdmitxpll_d3"
-};
-
-static const char * const dpilvds_parents[] __initconst = {
- "clk26m",
- "lvdspll",
- "lvdspll_d2",
- "lvdspll_d4",
- "lvdspll_d8",
- "fpc_ck"
-};
-
-static const char * const msdc50_2_h_parents[] __initconst = {
- "clk26m",
- "syspll1_d2",
- "syspll2_d2",
- "syspll4_d2",
- "univpll_d5",
- "univpll1_d4"
-};
-
-static const char * const hdcp_parents[] __initconst = {
- "clk26m",
- "syspll4_d2",
- "syspll3_d4",
- "univpll2_d4"
-};
-
-static const char * const hdcp_24m_parents[] __initconst = {
- "clk26m",
- "univpll_d26",
- "univpll_d52",
- "univpll2_d8"
-};
-
-static const char * const rtc_parents[] __initconst = {
- "clkrtc_int",
- "clkrtc_ext",
- "clk26m",
- "univpll3_d8"
-};
-
-static const char * const i2s0_m_ck_parents[] __initconst = {
- "apll1_div1",
- "apll2_div1"
-};
-
-static const char * const i2s1_m_ck_parents[] __initconst = {
- "apll1_div2",
- "apll2_div2"
-};
-
-static const char * const i2s2_m_ck_parents[] __initconst = {
- "apll1_div3",
- "apll2_div3"
-};
-
-static const char * const i2s3_m_ck_parents[] __initconst = {
- "apll1_div4",
- "apll2_div4"
-};
-
-static const char * const i2s3_b_ck_parents[] __initconst = {
- "apll1_div5",
- "apll2_div5"
-};
-
-static const char * const ca53_parents[] __initconst = {
- "clk26m",
- "armca7pll",
- "mainpll",
- "univpll"
-};
-
-static const char * const ca72_parents[] __initconst = {
- "clk26m",
- "armca15pll",
- "mainpll",
- "univpll"
-};
-
-static const struct mtk_composite cpu_muxes[] __initconst = {
- MUX(CLK_INFRA_CA53SEL, "infra_ca53_sel", ca53_parents, 0x0000, 0, 2),
- MUX(CLK_INFRA_CA72SEL, "infra_ca72_sel", ca72_parents, 0x0000, 2, 2),
-};
-
-static const struct mtk_composite top_muxes[] __initconst = {
- /* CLK_CFG_0 */
- MUX(CLK_TOP_AXI_SEL, "axi_sel", axi_parents, 0x0040, 0, 3),
- MUX(CLK_TOP_MEM_SEL, "mem_sel", mem_parents, 0x0040, 8, 1),
- MUX_GATE(CLK_TOP_DDRPHYCFG_SEL, "ddrphycfg_sel", ddrphycfg_parents, 0x0040, 16, 1, 23),
- MUX_GATE(CLK_TOP_MM_SEL, "mm_sel", mm_parents, 0x0040, 24, 4, 31),
- /* CLK_CFG_1 */
- MUX_GATE(CLK_TOP_PWM_SEL, "pwm_sel", pwm_parents, 0x0050, 0, 2, 7),
- MUX_GATE(CLK_TOP_VDEC_SEL, "vdec_sel", vdec_parents, 0x0050, 8, 4, 15),
- MUX_GATE(CLK_TOP_VENC_SEL, "venc_sel", venc_parents, 0x0050, 16, 4, 23),
- MUX_GATE(CLK_TOP_MFG_SEL, "mfg_sel", mfg_parents, 0x0050, 24, 4, 31),
- /* CLK_CFG_2 */
- MUX_GATE(CLK_TOP_CAMTG_SEL, "camtg_sel", camtg_parents, 0x0060, 0, 3, 7),
- MUX_GATE(CLK_TOP_UART_SEL, "uart_sel", uart_parents, 0x0060, 8, 1, 15),
- MUX_GATE(CLK_TOP_SPI_SEL, "spi_sel", spi_parents, 0x0060, 16, 3, 23),
- MUX_GATE(CLK_TOP_USB20_SEL, "usb20_sel", usb20_parents, 0x0060, 24, 2, 31),
- /* CLK_CFG_3 */
- MUX_GATE(CLK_TOP_USB30_SEL, "usb30_sel", usb30_parents, 0x0070, 0, 2, 7),
- MUX_GATE(CLK_TOP_MSDC50_0_H_SEL, "msdc50_0_h_sel", msdc50_0_h_parents, 0x0070, 8, 3, 15),
- MUX_GATE(CLK_TOP_MSDC50_0_SEL, "msdc50_0_sel", msdc50_0_parents, 0x0070, 16, 4, 23),
- MUX_GATE(CLK_TOP_MSDC30_1_SEL, "msdc30_1_sel", msdc30_1_parents, 0x0070, 24, 3, 31),
- /* CLK_CFG_4 */
- MUX_GATE(CLK_TOP_MSDC30_2_SEL, "msdc30_2_sel", msdc30_2_parents, 0x0080, 0, 3, 7),
- MUX_GATE(CLK_TOP_MSDC30_3_SEL, "msdc30_3_sel", msdc30_3_parents, 0x0080, 8, 4, 15),
- MUX_GATE(CLK_TOP_AUDIO_SEL, "audio_sel", audio_parents, 0x0080, 16, 2, 23),
- MUX_GATE(CLK_TOP_AUD_INTBUS_SEL, "aud_intbus_sel", aud_intbus_parents, 0x0080, 24, 3, 31),
- /* CLK_CFG_5 */
- MUX_GATE(CLK_TOP_PMICSPI_SEL, "pmicspi_sel", pmicspi_parents, 0x0090, 0, 3, 7 /* 7:5 */),
- MUX_GATE(CLK_TOP_SCP_SEL, "scp_sel", scp_parents, 0x0090, 8, 3, 15),
- MUX_GATE(CLK_TOP_ATB_SEL, "atb_sel", atb_parents, 0x0090, 16, 2, 23),
- MUX_GATE(CLK_TOP_VENC_LT_SEL, "venclt_sel", venc_lt_parents, 0x0090, 24, 4, 31),
- /* CLK_CFG_6 */
- /*
- * The dpi0_sel clock should not propagate rate changes to its parent
- * clock so the dpi driver can have full control over PLL and divider.
- */
- MUX_GATE_FLAGS(CLK_TOP_DPI0_SEL, "dpi0_sel", dpi0_parents, 0x00a0, 0, 3, 7, 0),
- MUX_GATE(CLK_TOP_IRDA_SEL, "irda_sel", irda_parents, 0x00a0, 8, 2, 15),
- MUX_GATE(CLK_TOP_CCI400_SEL, "cci400_sel", cci400_parents, 0x00a0, 16, 3, 23),
- MUX_GATE(CLK_TOP_AUD_1_SEL, "aud_1_sel", aud_1_parents, 0x00a0, 24, 2, 31),
- /* CLK_CFG_7 */
- MUX_GATE(CLK_TOP_AUD_2_SEL, "aud_2_sel", aud_2_parents, 0x00b0, 0, 2, 7),
- MUX_GATE(CLK_TOP_MEM_MFG_IN_SEL, "mem_mfg_in_sel", mem_mfg_in_parents, 0x00b0, 8, 2, 15),
- MUX_GATE(CLK_TOP_AXI_MFG_IN_SEL, "axi_mfg_in_sel", axi_mfg_in_parents, 0x00b0, 16, 2, 23),
- MUX_GATE(CLK_TOP_SCAM_SEL, "scam_sel", scam_parents, 0x00b0, 24, 2, 31),
- /* CLK_CFG_12 */
- MUX_GATE(CLK_TOP_SPINFI_IFR_SEL, "spinfi_ifr_sel", spinfi_ifr_parents, 0x00c0, 0, 3, 7),
- MUX_GATE(CLK_TOP_HDMI_SEL, "hdmi_sel", hdmi_parents, 0x00c0, 8, 2, 15),
- MUX_GATE(CLK_TOP_DPILVDS_SEL, "dpilvds_sel", dpilvds_parents, 0x00c0, 24, 3, 31),
- /* CLK_CFG_13 */
- MUX_GATE(CLK_TOP_MSDC50_2_H_SEL, "msdc50_2_h_sel", msdc50_2_h_parents, 0x00d0, 0, 3, 7),
- MUX_GATE(CLK_TOP_HDCP_SEL, "hdcp_sel", hdcp_parents, 0x00d0, 8, 2, 15),
- MUX_GATE(CLK_TOP_HDCP_24M_SEL, "hdcp_24m_sel", hdcp_24m_parents, 0x00d0, 16, 2, 23),
- MUX(CLK_TOP_RTC_SEL, "rtc_sel", rtc_parents, 0x00d0, 24, 2),
-
- DIV_GATE(CLK_TOP_APLL1_DIV0, "apll1_div0", "aud_1_sel", 0x12c, 8, 0x120, 4, 24),
- DIV_GATE(CLK_TOP_APLL1_DIV1, "apll1_div1", "aud_1_sel", 0x12c, 9, 0x124, 8, 0),
- DIV_GATE(CLK_TOP_APLL1_DIV2, "apll1_div2", "aud_1_sel", 0x12c, 10, 0x124, 8, 8),
- DIV_GATE(CLK_TOP_APLL1_DIV3, "apll1_div3", "aud_1_sel", 0x12c, 11, 0x124, 8, 16),
- DIV_GATE(CLK_TOP_APLL1_DIV4, "apll1_div4", "aud_1_sel", 0x12c, 12, 0x124, 8, 24),
- DIV_GATE(CLK_TOP_APLL1_DIV5, "apll1_div5", "apll1_div4", 0x12c, 13, 0x12c, 4, 0),
-
- DIV_GATE(CLK_TOP_APLL2_DIV0, "apll2_div0", "aud_2_sel", 0x12c, 16, 0x120, 4, 28),
- DIV_GATE(CLK_TOP_APLL2_DIV1, "apll2_div1", "aud_2_sel", 0x12c, 17, 0x128, 8, 0),
- DIV_GATE(CLK_TOP_APLL2_DIV2, "apll2_div2", "aud_2_sel", 0x12c, 18, 0x128, 8, 8),
- DIV_GATE(CLK_TOP_APLL2_DIV3, "apll2_div3", "aud_2_sel", 0x12c, 19, 0x128, 8, 16),
- DIV_GATE(CLK_TOP_APLL2_DIV4, "apll2_div4", "aud_2_sel", 0x12c, 20, 0x128, 8, 24),
- DIV_GATE(CLK_TOP_APLL2_DIV5, "apll2_div5", "apll2_div4", 0x12c, 21, 0x12c, 4, 4),
-
- MUX(CLK_TOP_I2S0_M_SEL, "i2s0_m_ck_sel", i2s0_m_ck_parents, 0x120, 4, 1),
- MUX(CLK_TOP_I2S1_M_SEL, "i2s1_m_ck_sel", i2s1_m_ck_parents, 0x120, 5, 1),
- MUX(CLK_TOP_I2S2_M_SEL, "i2s2_m_ck_sel", i2s2_m_ck_parents, 0x120, 6, 1),
- MUX(CLK_TOP_I2S3_M_SEL, "i2s3_m_ck_sel", i2s3_m_ck_parents, 0x120, 7, 1),
- MUX(CLK_TOP_I2S3_B_SEL, "i2s3_b_ck_sel", i2s3_b_ck_parents, 0x120, 8, 1),
-};
-
-static const struct mtk_gate_regs infra_cg_regs __initconst = {
- .set_ofs = 0x0040,
- .clr_ofs = 0x0044,
- .sta_ofs = 0x0048,
-};
-
-#define GATE_ICG(_id, _name, _parent, _shift) { \
- .id = _id, \
- .name = _name, \
- .parent_name = _parent, \
- .regs = &infra_cg_regs, \
- .shift = _shift, \
- .ops = &mtk_clk_gate_ops_setclr, \
- }
-
-static const struct mtk_gate infra_clks[] __initconst = {
- GATE_ICG(CLK_INFRA_DBGCLK, "infra_dbgclk", "axi_sel", 0),
- GATE_ICG(CLK_INFRA_SMI, "infra_smi", "mm_sel", 1),
- GATE_ICG(CLK_INFRA_AUDIO, "infra_audio", "aud_intbus_sel", 5),
- GATE_ICG(CLK_INFRA_GCE, "infra_gce", "axi_sel", 6),
- GATE_ICG(CLK_INFRA_L2C_SRAM, "infra_l2c_sram", "axi_sel", 7),
- GATE_ICG(CLK_INFRA_M4U, "infra_m4u", "mem_sel", 8),
- GATE_ICG(CLK_INFRA_CPUM, "infra_cpum", "cpum_ck", 15),
- GATE_ICG(CLK_INFRA_KP, "infra_kp", "axi_sel", 16),
- GATE_ICG(CLK_INFRA_CEC, "infra_cec", "clk26m", 18),
- GATE_ICG(CLK_INFRA_PMICSPI, "infra_pmicspi", "pmicspi_sel", 22),
- GATE_ICG(CLK_INFRA_PMICWRAP, "infra_pmicwrap", "axi_sel", 23),
-};
-
-static const struct mtk_fixed_factor infra_divs[] __initconst = {
- FACTOR(CLK_INFRA_CLK_13M, "clk13m", "clk26m", 1, 2),
-};
-
-static const struct mtk_gate_regs peri0_cg_regs __initconst = {
- .set_ofs = 0x0008,
- .clr_ofs = 0x0010,
- .sta_ofs = 0x0018,
-};
-
-static const struct mtk_gate_regs peri1_cg_regs __initconst = {
- .set_ofs = 0x000c,
- .clr_ofs = 0x0014,
- .sta_ofs = 0x001c,
-};
-
-#define GATE_PERI0(_id, _name, _parent, _shift) { \
- .id = _id, \
- .name = _name, \
- .parent_name = _parent, \
- .regs = &peri0_cg_regs, \
- .shift = _shift, \
- .ops = &mtk_clk_gate_ops_setclr, \
- }
-
-#define GATE_PERI1(_id, _name, _parent, _shift) { \
- .id = _id, \
- .name = _name, \
- .parent_name = _parent, \
- .regs = &peri1_cg_regs, \
- .shift = _shift, \
- .ops = &mtk_clk_gate_ops_setclr, \
- }
-
-static const struct mtk_gate peri_gates[] __initconst = {
- /* PERI0 */
- GATE_PERI0(CLK_PERI_NFI, "peri_nfi", "axi_sel", 0),
- GATE_PERI0(CLK_PERI_THERM, "peri_therm", "axi_sel", 1),
- GATE_PERI0(CLK_PERI_PWM1, "peri_pwm1", "axi_sel", 2),
- GATE_PERI0(CLK_PERI_PWM2, "peri_pwm2", "axi_sel", 3),
- GATE_PERI0(CLK_PERI_PWM3, "peri_pwm3", "axi_sel", 4),
- GATE_PERI0(CLK_PERI_PWM4, "peri_pwm4", "axi_sel", 5),
- GATE_PERI0(CLK_PERI_PWM5, "peri_pwm5", "axi_sel", 6),
- GATE_PERI0(CLK_PERI_PWM6, "peri_pwm6", "axi_sel", 7),
- GATE_PERI0(CLK_PERI_PWM7, "peri_pwm7", "axi_sel", 8),
- GATE_PERI0(CLK_PERI_PWM, "peri_pwm", "axi_sel", 9),
- GATE_PERI0(CLK_PERI_USB0, "peri_usb0", "usb20_sel", 10),
- GATE_PERI0(CLK_PERI_USB1, "peri_usb1", "usb20_sel", 11),
- GATE_PERI0(CLK_PERI_AP_DMA, "peri_ap_dma", "axi_sel", 12),
- GATE_PERI0(CLK_PERI_MSDC30_0, "peri_msdc30_0", "msdc50_0_sel", 13),
- GATE_PERI0(CLK_PERI_MSDC30_1, "peri_msdc30_1", "msdc30_1_sel", 14),
- GATE_PERI0(CLK_PERI_MSDC30_2, "peri_msdc30_2", "msdc30_2_sel", 15),
- GATE_PERI0(CLK_PERI_MSDC30_3, "peri_msdc30_3", "msdc30_3_sel", 16),
- GATE_PERI0(CLK_PERI_NLI_ARB, "peri_nli_arb", "axi_sel", 17),
- GATE_PERI0(CLK_PERI_IRDA, "peri_irda", "irda_sel", 18),
- GATE_PERI0(CLK_PERI_UART0, "peri_uart0", "axi_sel", 19),
- GATE_PERI0(CLK_PERI_UART1, "peri_uart1", "axi_sel", 20),
- GATE_PERI0(CLK_PERI_UART2, "peri_uart2", "axi_sel", 21),
- GATE_PERI0(CLK_PERI_UART3, "peri_uart3", "axi_sel", 22),
- GATE_PERI0(CLK_PERI_I2C0, "peri_i2c0", "axi_sel", 23),
- GATE_PERI0(CLK_PERI_I2C1, "peri_i2c1", "axi_sel", 24),
- GATE_PERI0(CLK_PERI_I2C2, "peri_i2c2", "axi_sel", 25),
- GATE_PERI0(CLK_PERI_I2C3, "peri_i2c3", "axi_sel", 26),
- GATE_PERI0(CLK_PERI_I2C4, "peri_i2c4", "axi_sel", 27),
- GATE_PERI0(CLK_PERI_AUXADC, "peri_auxadc", "clk26m", 28),
- GATE_PERI0(CLK_PERI_SPI0, "peri_spi0", "spi_sel", 29),
- GATE_PERI0(CLK_PERI_I2C5, "peri_i2c5", "axi_sel", 30),
- GATE_PERI0(CLK_PERI_NFIECC, "peri_nfiecc", "axi_sel", 31),
- /* PERI1 */
- GATE_PERI1(CLK_PERI_SPI, "peri_spi", "spi_sel", 0),
- GATE_PERI1(CLK_PERI_IRRX, "peri_irrx", "spi_sel", 1),
- GATE_PERI1(CLK_PERI_I2C6, "peri_i2c6", "axi_sel", 2),
-};
-
-static const char * const uart_ck_sel_parents[] __initconst = {
- "clk26m",
- "uart_sel",
-};
-
-static const struct mtk_composite peri_clks[] __initconst = {
- MUX(CLK_PERI_UART0_SEL, "uart0_ck_sel", uart_ck_sel_parents, 0x40c, 0, 1),
- MUX(CLK_PERI_UART1_SEL, "uart1_ck_sel", uart_ck_sel_parents, 0x40c, 1, 1),
- MUX(CLK_PERI_UART2_SEL, "uart2_ck_sel", uart_ck_sel_parents, 0x40c, 2, 1),
- MUX(CLK_PERI_UART3_SEL, "uart3_ck_sel", uart_ck_sel_parents, 0x40c, 3, 1),
-};
-
-static const struct mtk_gate_regs cg_regs_4_8_0 __initconst = {
- .set_ofs = 0x0004,
- .clr_ofs = 0x0008,
- .sta_ofs = 0x0000,
-};
-
-#define GATE_IMG(_id, _name, _parent, _shift) { \
- .id = _id, \
- .name = _name, \
- .parent_name = _parent, \
- .regs = &cg_regs_4_8_0, \
- .shift = _shift, \
- .ops = &mtk_clk_gate_ops_setclr, \
- }
-
-static const struct mtk_gate img_clks[] __initconst = {
- GATE_IMG(CLK_IMG_LARB2_SMI, "img_larb2_smi", "mm_sel", 0),
- GATE_IMG(CLK_IMG_CAM_SMI, "img_cam_smi", "mm_sel", 5),
- GATE_IMG(CLK_IMG_CAM_CAM, "img_cam_cam", "mm_sel", 6),
- GATE_IMG(CLK_IMG_SEN_TG, "img_sen_tg", "camtg_sel", 7),
- GATE_IMG(CLK_IMG_SEN_CAM, "img_sen_cam", "mm_sel", 8),
- GATE_IMG(CLK_IMG_CAM_SV, "img_cam_sv", "mm_sel", 9),
- GATE_IMG(CLK_IMG_FD, "img_fd", "mm_sel", 11),
-};
-
-static const struct mtk_gate_regs vdec0_cg_regs __initconst = {
- .set_ofs = 0x0000,
- .clr_ofs = 0x0004,
- .sta_ofs = 0x0000,
-};
-
-static const struct mtk_gate_regs vdec1_cg_regs __initconst = {
- .set_ofs = 0x0008,
- .clr_ofs = 0x000c,
- .sta_ofs = 0x0008,
-};
-
-#define GATE_VDEC0(_id, _name, _parent, _shift) { \
- .id = _id, \
- .name = _name, \
- .parent_name = _parent, \
- .regs = &vdec0_cg_regs, \
- .shift = _shift, \
- .ops = &mtk_clk_gate_ops_setclr_inv, \
- }
-
-#define GATE_VDEC1(_id, _name, _parent, _shift) { \
- .id = _id, \
- .name = _name, \
- .parent_name = _parent, \
- .regs = &vdec1_cg_regs, \
- .shift = _shift, \
- .ops = &mtk_clk_gate_ops_setclr_inv, \
- }
-
-static const struct mtk_gate vdec_clks[] __initconst = {
- GATE_VDEC0(CLK_VDEC_CKEN, "vdec_cken", "vdec_sel", 0),
- GATE_VDEC1(CLK_VDEC_LARB_CKEN, "vdec_larb_cken", "mm_sel", 0),
-};
-
-#define GATE_VENC(_id, _name, _parent, _shift) { \
- .id = _id, \
- .name = _name, \
- .parent_name = _parent, \
- .regs = &cg_regs_4_8_0, \
- .shift = _shift, \
- .ops = &mtk_clk_gate_ops_setclr_inv, \
- }
-
-static const struct mtk_gate venc_clks[] __initconst = {
- GATE_VENC(CLK_VENC_CKE0, "venc_cke0", "mm_sel", 0),
- GATE_VENC(CLK_VENC_CKE1, "venc_cke1", "venc_sel", 4),
- GATE_VENC(CLK_VENC_CKE2, "venc_cke2", "venc_sel", 8),
- GATE_VENC(CLK_VENC_CKE3, "venc_cke3", "venc_sel", 12),
-};
-
-#define GATE_VENCLT(_id, _name, _parent, _shift) { \
- .id = _id, \
- .name = _name, \
- .parent_name = _parent, \
- .regs = &cg_regs_4_8_0, \
- .shift = _shift, \
- .ops = &mtk_clk_gate_ops_setclr_inv, \
- }
-
-static const struct mtk_gate venclt_clks[] __initconst = {
- GATE_VENCLT(CLK_VENCLT_CKE0, "venclt_cke0", "mm_sel", 0),
- GATE_VENCLT(CLK_VENCLT_CKE1, "venclt_cke1", "venclt_sel", 4),
-};
-
-static u16 infrasys_rst_ofs[] = { 0x30, 0x34, };
-static u16 pericfg_rst_ofs[] = { 0x0, 0x4, };
-
-static const struct mtk_clk_rst_desc clk_rst_desc[] = {
- /* infrasys */
- {
- .version = MTK_RST_SIMPLE,
- .rst_bank_ofs = infrasys_rst_ofs,
- .rst_bank_nr = ARRAY_SIZE(infrasys_rst_ofs),
- },
- /* pericfg */
- {
- .version = MTK_RST_SIMPLE,
- .rst_bank_ofs = pericfg_rst_ofs,
- .rst_bank_nr = ARRAY_SIZE(pericfg_rst_ofs),
- }
-};
-
-static struct clk_hw_onecell_data *mt8173_top_clk_data __initdata;
-static struct clk_hw_onecell_data *mt8173_pll_clk_data __initdata;
-
-static void __init mtk_clk_enable_critical(void)
-{
- if (!mt8173_top_clk_data || !mt8173_pll_clk_data)
- return;
-
- clk_prepare_enable(mt8173_pll_clk_data->hws[CLK_APMIXED_ARMCA15PLL]->clk);
- clk_prepare_enable(mt8173_pll_clk_data->hws[CLK_APMIXED_ARMCA7PLL]->clk);
- clk_prepare_enable(mt8173_top_clk_data->hws[CLK_TOP_MEM_SEL]->clk);
- clk_prepare_enable(mt8173_top_clk_data->hws[CLK_TOP_DDRPHYCFG_SEL]->clk);
- clk_prepare_enable(mt8173_top_clk_data->hws[CLK_TOP_CCI400_SEL]->clk);
- clk_prepare_enable(mt8173_top_clk_data->hws[CLK_TOP_RTC_SEL]->clk);
-}
-
-static void __init mtk_topckgen_init(struct device_node *node)
-{
- struct clk_hw_onecell_data *clk_data;
- void __iomem *base;
- int r;
-
- base = of_iomap(node, 0);
- if (!base) {
- pr_err("%s(): ioremap failed\n", __func__);
- return;
- }
-
- mt8173_top_clk_data = clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK);
-
- mtk_clk_register_fixed_clks(fixed_clks, ARRAY_SIZE(fixed_clks), clk_data);
- mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), clk_data);
- mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes), base,
- &mt8173_clk_lock, clk_data);
-
- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
- if (r)
- pr_err("%s(): could not register clock provider: %d\n",
- __func__, r);
-
- mtk_clk_enable_critical();
-}
-CLK_OF_DECLARE(mtk_topckgen, "mediatek,mt8173-topckgen", mtk_topckgen_init);
-
-static void __init mtk_infrasys_init(struct device_node *node)
-{
- struct clk_hw_onecell_data *clk_data;
- int r;
-
- clk_data = mtk_alloc_clk_data(CLK_INFRA_NR_CLK);
-
- mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks),
- clk_data);
- mtk_clk_register_factors(infra_divs, ARRAY_SIZE(infra_divs), clk_data);
-
- mtk_clk_register_cpumuxes(node, cpu_muxes, ARRAY_SIZE(cpu_muxes),
- clk_data);
-
- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
- if (r)
- pr_err("%s(): could not register clock provider: %d\n",
- __func__, r);
-
- mtk_register_reset_controller(node, &clk_rst_desc[0]);
-}
-CLK_OF_DECLARE(mtk_infrasys, "mediatek,mt8173-infracfg", mtk_infrasys_init);
-
-static void __init mtk_pericfg_init(struct device_node *node)
-{
- struct clk_hw_onecell_data *clk_data;
- int r;
- void __iomem *base;
-
- base = of_iomap(node, 0);
- if (!base) {
- pr_err("%s(): ioremap failed\n", __func__);
- return;
- }
-
- clk_data = mtk_alloc_clk_data(CLK_PERI_NR_CLK);
-
- mtk_clk_register_gates(node, peri_gates, ARRAY_SIZE(peri_gates),
- clk_data);
- mtk_clk_register_composites(peri_clks, ARRAY_SIZE(peri_clks), base,
- &mt8173_clk_lock, clk_data);
-
- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
- if (r)
- pr_err("%s(): could not register clock provider: %d\n",
- __func__, r);
-
- mtk_register_reset_controller(node, &clk_rst_desc[1]);
-}
-CLK_OF_DECLARE(mtk_pericfg, "mediatek,mt8173-pericfg", mtk_pericfg_init);
-
-struct mtk_clk_usb {
- int id;
- const char *name;
- const char *parent;
- u32 reg_ofs;
-};
-
-#define APMIXED_USB(_id, _name, _parent, _reg_ofs) { \
- .id = _id, \
- .name = _name, \
- .parent = _parent, \
- .reg_ofs = _reg_ofs, \
- }
-
-static const struct mtk_clk_usb apmixed_usb[] __initconst = {
- APMIXED_USB(CLK_APMIXED_REF2USB_TX, "ref2usb_tx", "clk26m", 0x8),
-};
-
-#define MT8173_PLL_FMAX (3000UL * MHZ)
-
-#define CON0_MT8173_RST_BAR BIT(24)
-
-#define PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \
- _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, \
- _pcw_shift, _div_table) { \
- .id = _id, \
- .name = _name, \
- .reg = _reg, \
- .pwr_reg = _pwr_reg, \
- .en_mask = _en_mask, \
- .flags = _flags, \
- .rst_bar_mask = CON0_MT8173_RST_BAR, \
- .fmax = MT8173_PLL_FMAX, \
- .pcwbits = _pcwbits, \
- .pd_reg = _pd_reg, \
- .pd_shift = _pd_shift, \
- .tuner_reg = _tuner_reg, \
- .pcw_reg = _pcw_reg, \
- .pcw_shift = _pcw_shift, \
- .div_table = _div_table, \
- }
-
-#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \
- _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, \
- _pcw_shift) \
- PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \
- _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift, \
- NULL)
-
-static const struct mtk_pll_div_table mmpll_div_table[] = {
- { .div = 0, .freq = MT8173_PLL_FMAX },
- { .div = 1, .freq = 1000000000 },
- { .div = 2, .freq = 702000000 },
- { .div = 3, .freq = 253500000 },
- { .div = 4, .freq = 126750000 },
- { } /* sentinel */
-};
-
-static const struct mtk_pll_data plls[] = {
- PLL(CLK_APMIXED_ARMCA15PLL, "armca15pll", 0x200, 0x20c, 0, 0, 21, 0x204, 24, 0x0, 0x204, 0),
- PLL(CLK_APMIXED_ARMCA7PLL, "armca7pll", 0x210, 0x21c, 0, 0, 21, 0x214, 24, 0x0, 0x214, 0),
- PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x220, 0x22c, 0xf0000100, HAVE_RST_BAR, 21, 0x220, 4, 0x0, 0x224, 0),
- PLL(CLK_APMIXED_UNIVPLL, "univpll", 0x230, 0x23c, 0xfe000000, HAVE_RST_BAR, 7, 0x230, 4, 0x0, 0x234, 14),
- PLL_B(CLK_APMIXED_MMPLL, "mmpll", 0x240, 0x24c, 0, 0, 21, 0x244, 24, 0x0, 0x244, 0, mmpll_div_table),
- PLL(CLK_APMIXED_MSDCPLL, "msdcpll", 0x250, 0x25c, 0, 0, 21, 0x250, 4, 0x0, 0x254, 0),
- PLL(CLK_APMIXED_VENCPLL, "vencpll", 0x260, 0x26c, 0, 0, 21, 0x260, 4, 0x0, 0x264, 0),
- PLL(CLK_APMIXED_TVDPLL, "tvdpll", 0x270, 0x27c, 0, 0, 21, 0x270, 4, 0x0, 0x274, 0),
- PLL(CLK_APMIXED_MPLL, "mpll", 0x280, 0x28c, 0, 0, 21, 0x280, 4, 0x0, 0x284, 0),
- PLL(CLK_APMIXED_VCODECPLL, "vcodecpll", 0x290, 0x29c, 0, 0, 21, 0x290, 4, 0x0, 0x294, 0),
- PLL(CLK_APMIXED_APLL1, "apll1", 0x2a0, 0x2b0, 0, 0, 31, 0x2a0, 4, 0x2a4, 0x2a4, 0),
- PLL(CLK_APMIXED_APLL2, "apll2", 0x2b4, 0x2c4, 0, 0, 31, 0x2b4, 4, 0x2b8, 0x2b8, 0),
- PLL(CLK_APMIXED_LVDSPLL, "lvdspll", 0x2d0, 0x2dc, 0, 0, 21, 0x2d0, 4, 0x0, 0x2d4, 0),
- PLL(CLK_APMIXED_MSDCPLL2, "msdcpll2", 0x2f0, 0x2fc, 0, 0, 21, 0x2f0, 4, 0x0, 0x2f4, 0),
-};
-
-static void __init mtk_apmixedsys_init(struct device_node *node)
-{
- struct clk_hw_onecell_data *clk_data;
- void __iomem *base;
- struct clk_hw *hw;
- int r, i;
-
- base = of_iomap(node, 0);
- if (!base) {
- pr_err("%s(): ioremap failed\n", __func__);
- return;
- }
-
- mt8173_pll_clk_data = clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK);
- if (!clk_data) {
- iounmap(base);
- return;
- }
-
- mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
-
- for (i = 0; i < ARRAY_SIZE(apmixed_usb); i++) {
- const struct mtk_clk_usb *cku = &apmixed_usb[i];
-
- hw = mtk_clk_register_ref2usb_tx(cku->name, cku->parent, base + cku->reg_ofs);
- if (IS_ERR(hw)) {
- pr_err("Failed to register clk %s: %ld\n", cku->name, PTR_ERR(hw));
- continue;
- }
-
- clk_data->hws[cku->id] = hw;
- }
-
- hw = clk_hw_register_divider(NULL, "hdmi_ref", "tvdpll_594m", 0,
- base + 0x40, 16, 3, CLK_DIVIDER_POWER_OF_TWO,
- NULL);
- clk_data->hws[CLK_APMIXED_HDMI_REF] = hw;
-
- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
- if (r)
- pr_err("%s(): could not register clock provider: %d\n",
- __func__, r);
-
- mtk_clk_enable_critical();
-}
-CLK_OF_DECLARE(mtk_apmixedsys, "mediatek,mt8173-apmixedsys",
- mtk_apmixedsys_init);
-
-static void __init mtk_imgsys_init(struct device_node *node)
-{
- struct clk_hw_onecell_data *clk_data;
- int r;
-
- clk_data = mtk_alloc_clk_data(CLK_IMG_NR_CLK);
-
- mtk_clk_register_gates(node, img_clks, ARRAY_SIZE(img_clks),
- clk_data);
-
- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
-
- if (r)
- pr_err("%s(): could not register clock provider: %d\n",
- __func__, r);
-}
-CLK_OF_DECLARE(mtk_imgsys, "mediatek,mt8173-imgsys", mtk_imgsys_init);
-
-static void __init mtk_vdecsys_init(struct device_node *node)
-{
- struct clk_hw_onecell_data *clk_data;
- int r;
-
- clk_data = mtk_alloc_clk_data(CLK_VDEC_NR_CLK);
-
- mtk_clk_register_gates(node, vdec_clks, ARRAY_SIZE(vdec_clks),
- clk_data);
-
- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
- if (r)
- pr_err("%s(): could not register clock provider: %d\n",
- __func__, r);
-}
-CLK_OF_DECLARE(mtk_vdecsys, "mediatek,mt8173-vdecsys", mtk_vdecsys_init);
-
-static void __init mtk_vencsys_init(struct device_node *node)
-{
- struct clk_hw_onecell_data *clk_data;
- int r;
-
- clk_data = mtk_alloc_clk_data(CLK_VENC_NR_CLK);
-
- mtk_clk_register_gates(node, venc_clks, ARRAY_SIZE(venc_clks),
- clk_data);
-
- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
- if (r)
- pr_err("%s(): could not register clock provider: %d\n",
- __func__, r);
-}
-CLK_OF_DECLARE(mtk_vencsys, "mediatek,mt8173-vencsys", mtk_vencsys_init);
-
-static void __init mtk_vencltsys_init(struct device_node *node)
-{
- struct clk_hw_onecell_data *clk_data;
- int r;
-
- clk_data = mtk_alloc_clk_data(CLK_VENCLT_NR_CLK);
-
- mtk_clk_register_gates(node, venclt_clks, ARRAY_SIZE(venclt_clks),
- clk_data);
-
- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
- if (r)
- pr_err("%s(): could not register clock provider: %d\n",
- __func__, r);
-}
-CLK_OF_DECLARE(mtk_vencltsys, "mediatek,mt8173-vencltsys", mtk_vencltsys_init);
diff --git a/drivers/clk/mediatek/clk-mt8183-audio.c b/drivers/clk/mediatek/clk-mt8183-audio.c
index b2d7746eddbe..3f1630290b93 100644
--- a/drivers/clk/mediatek/clk-mt8183-audio.c
+++ b/drivers/clk/mediatek/clk-mt8183-audio.c
@@ -67,35 +67,40 @@ static const struct mtk_gate audio_clks[] = {
20),
};
+static const struct mtk_clk_desc audio_desc = {
+ .clks = audio_clks,
+ .num_clks = ARRAY_SIZE(audio_clks),
+};
+
static int clk_mt8183_audio_probe(struct platform_device *pdev)
{
- struct clk_hw_onecell_data *clk_data;
int r;
- struct device_node *node = pdev->dev.of_node;
-
- clk_data = mtk_alloc_clk_data(CLK_AUDIO_NR_CLK);
-
- mtk_clk_register_gates(node, audio_clks, ARRAY_SIZE(audio_clks),
- clk_data);
- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+ r = mtk_clk_simple_probe(pdev);
if (r)
return r;
r = devm_of_platform_populate(&pdev->dev);
if (r)
- of_clk_del_provider(node);
+ mtk_clk_simple_remove(pdev);
return r;
}
+static int clk_mt8183_audio_remove(struct platform_device *pdev)
+{
+ of_platform_depopulate(&pdev->dev);
+ return mtk_clk_simple_remove(pdev);
+}
+
static const struct of_device_id of_match_clk_mt8183_audio[] = {
- { .compatible = "mediatek,mt8183-audiosys", },
- {}
+ { .compatible = "mediatek,mt8183-audiosys", .data = &audio_desc },
+ { /* sentinel */ }
};
static struct platform_driver clk_mt8183_audio_drv = {
.probe = clk_mt8183_audio_probe,
+ .remove = clk_mt8183_audio_remove,
.driver = {
.name = "clk-mt8183-audio",
.of_match_table = of_match_clk_mt8183_audio,
diff --git a/drivers/clk/mediatek/clk-mt8183-mm.c b/drivers/clk/mediatek/clk-mt8183-mm.c
index 11ecc6fb0065..358031530913 100644
--- a/drivers/clk/mediatek/clk-mt8183-mm.c
+++ b/drivers/clk/mediatek/clk-mt8183-mm.c
@@ -90,8 +90,8 @@ static int clk_mt8183_mm_probe(struct platform_device *pdev)
clk_data = mtk_alloc_clk_data(CLK_MM_NR_CLK);
- mtk_clk_register_gates(node, mm_clks, ARRAY_SIZE(mm_clks),
- clk_data);
+ mtk_clk_register_gates(&pdev->dev, node, mm_clks,
+ ARRAY_SIZE(mm_clks), clk_data);
return of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
}
diff --git a/drivers/clk/mediatek/clk-mt8183.c b/drivers/clk/mediatek/clk-mt8183.c
index 23afc9584638..722d913f0b4d 100644
--- a/drivers/clk/mediatek/clk-mt8183.c
+++ b/drivers/clk/mediatek/clk-mt8183.c
@@ -613,21 +613,6 @@ static const char * const apll_i2s5_parents[] = {
"aud_2_sel"
};
-static struct mtk_composite top_aud_muxes[] = {
- MUX(CLK_TOP_MUX_APLL_I2S0, "apll_i2s0_sel", apll_i2s0_parents,
- 0x320, 8, 1),
- MUX(CLK_TOP_MUX_APLL_I2S1, "apll_i2s1_sel", apll_i2s1_parents,
- 0x320, 9, 1),
- MUX(CLK_TOP_MUX_APLL_I2S2, "apll_i2s2_sel", apll_i2s2_parents,
- 0x320, 10, 1),
- MUX(CLK_TOP_MUX_APLL_I2S3, "apll_i2s3_sel", apll_i2s3_parents,
- 0x320, 11, 1),
- MUX(CLK_TOP_MUX_APLL_I2S4, "apll_i2s4_sel", apll_i2s4_parents,
- 0x320, 12, 1),
- MUX(CLK_TOP_MUX_APLL_I2S5, "apll_i2s5_sel", apll_i2s5_parents,
- 0x328, 20, 1),
-};
-
static const char * const mcu_mp0_parents[] = {
"clk26m",
"armpll_ll",
@@ -658,7 +643,19 @@ static struct mtk_composite mcu_muxes[] = {
MUX(CLK_MCU_BUS_SEL, "mcu_bus_sel", mcu_bus_parents, 0x7C0, 9, 2),
};
-static struct mtk_composite top_aud_divs[] = {
+static struct mtk_composite top_aud_comp[] = {
+ MUX(CLK_TOP_MUX_APLL_I2S0, "apll_i2s0_sel", apll_i2s0_parents,
+ 0x320, 8, 1),
+ MUX(CLK_TOP_MUX_APLL_I2S1, "apll_i2s1_sel", apll_i2s1_parents,
+ 0x320, 9, 1),
+ MUX(CLK_TOP_MUX_APLL_I2S2, "apll_i2s2_sel", apll_i2s2_parents,
+ 0x320, 10, 1),
+ MUX(CLK_TOP_MUX_APLL_I2S3, "apll_i2s3_sel", apll_i2s3_parents,
+ 0x320, 11, 1),
+ MUX(CLK_TOP_MUX_APLL_I2S4, "apll_i2s4_sel", apll_i2s4_parents,
+ 0x320, 12, 1),
+ MUX(CLK_TOP_MUX_APLL_I2S5, "apll_i2s5_sel", apll_i2s5_parents,
+ 0x328, 20, 1),
DIV_GATE(CLK_TOP_APLL12_DIV0, "apll12_div0", "apll_i2s0_sel",
0x320, 2, 0x324, 8, 0),
DIV_GATE(CLK_TOP_APLL12_DIV1, "apll12_div1", "apll_i2s1_sel",
@@ -1100,8 +1097,8 @@ static int clk_mt8183_apmixed_probe(struct platform_device *pdev)
mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
- mtk_clk_register_gates(node, apmixed_clks, ARRAY_SIZE(apmixed_clks),
- clk_data);
+ mtk_clk_register_gates(&pdev->dev, node, apmixed_clks,
+ ARRAY_SIZE(apmixed_clks), clk_data);
return of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
}
@@ -1166,17 +1163,16 @@ static int clk_mt8183_top_probe(struct platform_device *pdev)
mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), top_clk_data);
- mtk_clk_register_muxes(top_muxes, ARRAY_SIZE(top_muxes),
- node, &mt8183_clk_lock, top_clk_data);
-
- mtk_clk_register_composites(top_aud_muxes, ARRAY_SIZE(top_aud_muxes),
- base, &mt8183_clk_lock, top_clk_data);
+ mtk_clk_register_muxes(&pdev->dev, top_muxes,
+ ARRAY_SIZE(top_muxes), node,
+ &mt8183_clk_lock, top_clk_data);
- mtk_clk_register_composites(top_aud_divs, ARRAY_SIZE(top_aud_divs),
- base, &mt8183_clk_lock, top_clk_data);
+ mtk_clk_register_composites(&pdev->dev, top_aud_comp,
+ ARRAY_SIZE(top_aud_comp), base,
+ &mt8183_clk_lock, top_clk_data);
- mtk_clk_register_gates(node, top_clks, ARRAY_SIZE(top_clks),
- top_clk_data);
+ mtk_clk_register_gates(&pdev->dev, node, top_clks,
+ ARRAY_SIZE(top_clks), top_clk_data);
ret = clk_mt8183_reg_mfg_mux_notifier(&pdev->dev,
top_clk_data->hws[CLK_TOP_MUX_MFG]->clk);
@@ -1187,43 +1183,6 @@ static int clk_mt8183_top_probe(struct platform_device *pdev)
top_clk_data);
}
-static int clk_mt8183_infra_probe(struct platform_device *pdev)
-{
- struct clk_hw_onecell_data *clk_data;
- struct device_node *node = pdev->dev.of_node;
- int r;
-
- clk_data = mtk_alloc_clk_data(CLK_INFRA_NR_CLK);
-
- mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks),
- clk_data);
-
- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
- if (r) {
- dev_err(&pdev->dev,
- "%s(): could not register clock provider: %d\n",
- __func__, r);
- return r;
- }
-
- mtk_register_reset_controller_with_dev(&pdev->dev, &clk_rst_desc);
-
- return r;
-}
-
-static int clk_mt8183_peri_probe(struct platform_device *pdev)
-{
- struct clk_hw_onecell_data *clk_data;
- struct device_node *node = pdev->dev.of_node;
-
- clk_data = mtk_alloc_clk_data(CLK_PERI_NR_CLK);
-
- mtk_clk_register_gates(node, peri_clks, ARRAY_SIZE(peri_clks),
- clk_data);
-
- return of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
-}
-
static int clk_mt8183_mcu_probe(struct platform_device *pdev)
{
struct clk_hw_onecell_data *clk_data;
@@ -1236,8 +1195,9 @@ static int clk_mt8183_mcu_probe(struct platform_device *pdev)
clk_data = mtk_alloc_clk_data(CLK_MCU_NR_CLK);
- mtk_clk_register_composites(mcu_muxes, ARRAY_SIZE(mcu_muxes), base,
- &mt8183_clk_lock, clk_data);
+ mtk_clk_register_composites(&pdev->dev, mcu_muxes,
+ ARRAY_SIZE(mcu_muxes), base,
+ &mt8183_clk_lock, clk_data);
return of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
}
@@ -1250,12 +1210,6 @@ static const struct of_device_id of_match_clk_mt8183[] = {
.compatible = "mediatek,mt8183-topckgen",
.data = clk_mt8183_top_probe,
}, {
- .compatible = "mediatek,mt8183-infracfg",
- .data = clk_mt8183_infra_probe,
- }, {
- .compatible = "mediatek,mt8183-pericfg",
- .data = clk_mt8183_peri_probe,
- }, {
.compatible = "mediatek,mt8183-mcucfg",
.data = clk_mt8183_mcu_probe,
}, {
@@ -1281,6 +1235,32 @@ static int clk_mt8183_probe(struct platform_device *pdev)
return r;
}
+static const struct mtk_clk_desc infra_desc = {
+ .clks = infra_clks,
+ .num_clks = ARRAY_SIZE(infra_clks),
+ .rst_desc = &clk_rst_desc,
+};
+
+static const struct mtk_clk_desc peri_desc = {
+ .clks = peri_clks,
+ .num_clks = ARRAY_SIZE(peri_clks),
+};
+
+static const struct of_device_id of_match_clk_mt8183_simple[] = {
+ { .compatible = "mediatek,mt8183-infracfg", .data = &infra_desc },
+ { .compatible = "mediatek,mt8183-pericfg", .data = &peri_desc, },
+ { /* sentinel */ }
+};
+
+static struct platform_driver clk_mt8183_simple_drv = {
+ .probe = mtk_clk_simple_probe,
+ .remove = mtk_clk_simple_remove,
+ .driver = {
+ .name = "clk-mt8183-simple",
+ .of_match_table = of_match_clk_mt8183_simple,
+ },
+};
+
static struct platform_driver clk_mt8183_drv = {
.probe = clk_mt8183_probe,
.driver = {
@@ -1291,7 +1271,11 @@ static struct platform_driver clk_mt8183_drv = {
static int __init clk_mt8183_init(void)
{
- return platform_driver_register(&clk_mt8183_drv);
+ int ret = platform_driver_register(&clk_mt8183_drv);
+
+ if (ret)
+ return ret;
+ return platform_driver_register(&clk_mt8183_simple_drv);
}
arch_initcall(clk_mt8183_init);
diff --git a/drivers/clk/mediatek/clk-mt8186-mcu.c b/drivers/clk/mediatek/clk-mt8186-mcu.c
index dfc305c1fc5d..e52a2d986c99 100644
--- a/drivers/clk/mediatek/clk-mt8186-mcu.c
+++ b/drivers/clk/mediatek/clk-mt8186-mcu.c
@@ -65,7 +65,8 @@ static int clk_mt8186_mcu_probe(struct platform_device *pdev)
goto free_mcu_data;
}
- r = mtk_clk_register_composites(mcu_muxes, ARRAY_SIZE(mcu_muxes), base,
+ r = mtk_clk_register_composites(&pdev->dev, mcu_muxes,
+ ARRAY_SIZE(mcu_muxes), base,
NULL, clk_data);
if (r)
goto free_mcu_data;
diff --git a/drivers/clk/mediatek/clk-mt8186-mm.c b/drivers/clk/mediatek/clk-mt8186-mm.c
index 1d33be407947..0b72607777fa 100644
--- a/drivers/clk/mediatek/clk-mt8186-mm.c
+++ b/drivers/clk/mediatek/clk-mt8186-mm.c
@@ -69,7 +69,8 @@ static int clk_mt8186_mm_probe(struct platform_device *pdev)
if (!clk_data)
return -ENOMEM;
- r = mtk_clk_register_gates(node, mm_clks, ARRAY_SIZE(mm_clks), clk_data);
+ r = mtk_clk_register_gates(&pdev->dev, node, mm_clks,
+ ARRAY_SIZE(mm_clks), clk_data);
if (r)
goto free_mm_data;
diff --git a/drivers/clk/mediatek/clk-mt8186-topckgen.c b/drivers/clk/mediatek/clk-mt8186-topckgen.c
index c2beda7ef976..c6786c8b315f 100644
--- a/drivers/clk/mediatek/clk-mt8186-topckgen.c
+++ b/drivers/clk/mediatek/clk-mt8186-topckgen.c
@@ -669,9 +669,6 @@ static struct mtk_composite top_muxes[] = {
MUX(CLK_TOP_APLL_I2S4_MCK_SEL, "apll_i2s4_mck_sel", apll_mck_parents, 0x0320, 19, 1),
MUX(CLK_TOP_APLL_TDMOUT_MCK_SEL, "apll_tdmout_mck_sel", apll_mck_parents,
0x0320, 20, 1),
-};
-
-static const struct mtk_composite top_adj_divs[] = {
DIV_GATE(CLK_TOP_APLL12_CK_DIV0, "apll12_div0", "apll_i2s0_mck_sel",
0x0320, 0, 0x0328, 8, 0),
DIV_GATE(CLK_TOP_APLL12_CK_DIV1, "apll12_div1", "apll_i2s1_mck_sel",
@@ -684,11 +681,6 @@ static const struct mtk_composite top_adj_divs[] = {
0x0320, 4, 0x0334, 8, 0),
};
-static const struct of_device_id of_match_clk_mt8186_topck[] = {
- { .compatible = "mediatek,mt8186-topckgen", },
- {}
-};
-
/* Register mux notifier for MFG mux */
static int clk_mt8186_reg_mfg_mux_notifier(struct device *dev, struct clk *clk)
{
@@ -711,94 +703,28 @@ static int clk_mt8186_reg_mfg_mux_notifier(struct device *dev, struct clk *clk)
return devm_mtk_clk_mux_notifier_register(dev, clk, mfg_mux_nb);
}
-static int clk_mt8186_topck_probe(struct platform_device *pdev)
-{
- struct clk_hw_onecell_data *clk_data;
- struct device_node *node = pdev->dev.of_node;
- int r;
- void __iomem *base;
-
- clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK);
- if (!clk_data)
- return -ENOMEM;
-
- base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(base)) {
- r = PTR_ERR(base);
- goto free_top_data;
- }
-
- r = mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks),
- clk_data);
- if (r)
- goto free_top_data;
-
- r = mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), clk_data);
- if (r)
- goto unregister_fixed_clks;
-
- r = mtk_clk_register_muxes(top_mtk_muxes, ARRAY_SIZE(top_mtk_muxes), node,
- &mt8186_clk_lock, clk_data);
- if (r)
- goto unregister_factors;
-
- r = mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes), base,
- &mt8186_clk_lock, clk_data);
- if (r)
- goto unregister_muxes;
-
- r = mtk_clk_register_composites(top_adj_divs, ARRAY_SIZE(top_adj_divs), base,
- &mt8186_clk_lock, clk_data);
- if (r)
- goto unregister_composite_muxes;
-
- r = clk_mt8186_reg_mfg_mux_notifier(&pdev->dev,
- clk_data->hws[CLK_TOP_MFG]->clk);
- if (r)
- goto unregister_composite_divs;
-
- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
- if (r)
- goto unregister_composite_divs;
-
- platform_set_drvdata(pdev, clk_data);
-
- return r;
-
-unregister_composite_divs:
- mtk_clk_unregister_composites(top_adj_divs, ARRAY_SIZE(top_adj_divs), clk_data);
-unregister_composite_muxes:
- mtk_clk_unregister_composites(top_muxes, ARRAY_SIZE(top_muxes), clk_data);
-unregister_muxes:
- mtk_clk_unregister_muxes(top_mtk_muxes, ARRAY_SIZE(top_mtk_muxes), clk_data);
-unregister_factors:
- mtk_clk_unregister_factors(top_divs, ARRAY_SIZE(top_divs), clk_data);
-unregister_fixed_clks:
- mtk_clk_unregister_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks), clk_data);
-free_top_data:
- mtk_free_clk_data(clk_data);
- return r;
-}
+static const struct mtk_clk_desc topck_desc = {
+ .fixed_clks = top_fixed_clks,
+ .num_fixed_clks = ARRAY_SIZE(top_fixed_clks),
+ .factor_clks = top_divs,
+ .num_factor_clks = ARRAY_SIZE(top_divs),
+ .mux_clks = top_mtk_muxes,
+ .num_mux_clks = ARRAY_SIZE(top_mtk_muxes),
+ .composite_clks = top_muxes,
+ .num_composite_clks = ARRAY_SIZE(top_muxes),
+ .clk_lock = &mt8186_clk_lock,
+ .clk_notifier_func = clk_mt8186_reg_mfg_mux_notifier,
+ .mfg_clk_idx = CLK_TOP_MFG,
+};
-static int clk_mt8186_topck_remove(struct platform_device *pdev)
-{
- struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev);
- struct device_node *node = pdev->dev.of_node;
-
- of_clk_del_provider(node);
- mtk_clk_unregister_composites(top_adj_divs, ARRAY_SIZE(top_adj_divs), clk_data);
- mtk_clk_unregister_composites(top_muxes, ARRAY_SIZE(top_muxes), clk_data);
- mtk_clk_unregister_muxes(top_mtk_muxes, ARRAY_SIZE(top_mtk_muxes), clk_data);
- mtk_clk_unregister_factors(top_divs, ARRAY_SIZE(top_divs), clk_data);
- mtk_clk_unregister_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks), clk_data);
- mtk_free_clk_data(clk_data);
-
- return 0;
-}
+static const struct of_device_id of_match_clk_mt8186_topck[] = {
+ { .compatible = "mediatek,mt8186-topckgen", .data = &topck_desc },
+ { /* sentinel */ }
+};
static struct platform_driver clk_mt8186_topck_drv = {
- .probe = clk_mt8186_topck_probe,
- .remove = clk_mt8186_topck_remove,
+ .probe = mtk_clk_simple_probe,
+ .remove = mtk_clk_simple_remove,
.driver = {
.name = "clk-mt8186-topck",
.of_match_table = of_match_clk_mt8186_topck,
diff --git a/drivers/clk/mediatek/clk-mt8192-aud.c b/drivers/clk/mediatek/clk-mt8192-aud.c
index 8c989bffd8c7..29affb68e854 100644
--- a/drivers/clk/mediatek/clk-mt8192-aud.c
+++ b/drivers/clk/mediatek/clk-mt8192-aud.c
@@ -77,38 +77,40 @@ static const struct mtk_gate aud_clks[] = {
GATE_AUD2(CLK_AUD_I2S9_B, "aud_i2s9_b", "audio_sel", 4),
};
+static const struct mtk_clk_desc aud_desc = {
+ .clks = aud_clks,
+ .num_clks = ARRAY_SIZE(aud_clks),
+};
+
static int clk_mt8192_aud_probe(struct platform_device *pdev)
{
- struct clk_hw_onecell_data *clk_data;
- struct device_node *node = pdev->dev.of_node;
int r;
- clk_data = mtk_alloc_clk_data(CLK_AUD_NR_CLK);
- if (!clk_data)
- return -ENOMEM;
-
- r = mtk_clk_register_gates(node, aud_clks, ARRAY_SIZE(aud_clks), clk_data);
- if (r)
- return r;
-
- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+ r = mtk_clk_simple_probe(pdev);
if (r)
return r;
r = devm_of_platform_populate(&pdev->dev);
if (r)
- of_clk_del_provider(node);
+ mtk_clk_simple_remove(pdev);
return r;
}
+static int clk_mt8192_aud_remove(struct platform_device *pdev)
+{
+ of_platform_depopulate(&pdev->dev);
+ return mtk_clk_simple_remove(pdev);
+}
+
static const struct of_device_id of_match_clk_mt8192_aud[] = {
- { .compatible = "mediatek,mt8192-audsys", },
- {}
+ { .compatible = "mediatek,mt8192-audsys", .data = &aud_desc },
+ { /* sentinel */ }
};
static struct platform_driver clk_mt8192_aud_drv = {
.probe = clk_mt8192_aud_probe,
+ .remove = clk_mt8192_aud_remove,
.driver = {
.name = "clk-mt8192-aud",
.of_match_table = of_match_clk_mt8192_aud,
diff --git a/drivers/clk/mediatek/clk-mt8192-mm.c b/drivers/clk/mediatek/clk-mt8192-mm.c
index 1be3ff4d407d..e9eb4cf8349a 100644
--- a/drivers/clk/mediatek/clk-mt8192-mm.c
+++ b/drivers/clk/mediatek/clk-mt8192-mm.c
@@ -91,7 +91,8 @@ static int clk_mt8192_mm_probe(struct platform_device *pdev)
if (!clk_data)
return -ENOMEM;
- r = mtk_clk_register_gates(node, mm_clks, ARRAY_SIZE(mm_clks), clk_data);
+ r = mtk_clk_register_gates(&pdev->dev, node, mm_clks,
+ ARRAY_SIZE(mm_clks), clk_data);
if (r)
return r;
diff --git a/drivers/clk/mediatek/clk-mt8192.c b/drivers/clk/mediatek/clk-mt8192.c
index 0e88588b2c49..61299960d28a 100644
--- a/drivers/clk/mediatek/clk-mt8192.c
+++ b/drivers/clk/mediatek/clk-mt8192.c
@@ -26,10 +26,6 @@ static const struct mtk_fixed_clk top_fixed_clks[] = {
FIXED_CLK(CLK_TOP_ULPOSC, "ulposc", NULL, 260000000),
};
-static const struct mtk_fixed_factor top_early_divs[] = {
- FACTOR(CLK_TOP_CSW_F26M_D2, "csw_f26m_d2", "clk26m", 1, 2),
-};
-
static const struct mtk_fixed_factor top_divs[] = {
FACTOR_FLAGS(CLK_TOP_MAINPLL_D3, "mainpll_d3", "mainpll", 1, 3, 0),
FACTOR_FLAGS(CLK_TOP_MAINPLL_D4, "mainpll_d4", "mainpll", 1, 4, 0),
@@ -95,6 +91,7 @@ static const struct mtk_fixed_factor top_divs[] = {
FACTOR(CLK_TOP_OSC_D10, "osc_d10", "ulposc", 1, 10),
FACTOR(CLK_TOP_OSC_D16, "osc_d16", "ulposc", 1, 16),
FACTOR(CLK_TOP_OSC_D20, "osc_d20", "ulposc", 1, 20),
+ FACTOR(CLK_TOP_CSW_F26M_D2, "csw_f26m_d2", "clk26m", 1, 2),
FACTOR(CLK_TOP_ADSPPLL, "adsppll_ck", "adsppll", 1, 1),
FACTOR_FLAGS(CLK_TOP_UNIVPLL_192M, "univpll_192m", "univpll", 1, 13, 0),
FACTOR_FLAGS(CLK_TOP_UNIVPLL_192M_D2, "univpll_192m_d2", "univpll_192m", 1, 2, 0),
@@ -701,9 +698,7 @@ static struct mtk_composite top_muxes[] = {
MUX(CLK_TOP_APLL_I2S7_M_SEL, "apll_i2s7_m_sel", apll_i2s_m_parents, 0x320, 23, 1),
MUX(CLK_TOP_APLL_I2S8_M_SEL, "apll_i2s8_m_sel", apll_i2s_m_parents, 0x320, 24, 1),
MUX(CLK_TOP_APLL_I2S9_M_SEL, "apll_i2s9_m_sel", apll_i2s_m_parents, 0x320, 25, 1),
-};
-
-static const struct mtk_composite top_adj_divs[] = {
+ /* APLL_DIV */
DIV_GATE(CLK_TOP_APLL12_DIV0, "apll12_div0", "apll_i2s0_m_sel", 0x320, 0, 0x328, 8, 0),
DIV_GATE(CLK_TOP_APLL12_DIV1, "apll12_div1", "apll_i2s1_m_sel", 0x320, 1, 0x328, 8, 8),
DIV_GATE(CLK_TOP_APLL12_DIV2, "apll12_div2", "apll_i2s2_m_sel", 0x320, 2, 0x328, 8, 16),
@@ -1047,27 +1042,6 @@ static const struct mtk_pll_data plls[] = {
0, 0, 32, 0x0330, 24, 0, 0, 0, 0x0334, 0),
};
-static struct clk_hw_onecell_data *top_clk_data;
-
-static void clk_mt8192_top_init_early(struct device_node *node)
-{
- int i;
-
- top_clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK);
- if (!top_clk_data)
- return;
-
- for (i = 0; i < CLK_TOP_NR_CLK; i++)
- top_clk_data->hws[i] = ERR_PTR(-EPROBE_DEFER);
-
- mtk_clk_register_factors(top_early_divs, ARRAY_SIZE(top_early_divs), top_clk_data);
-
- of_clk_add_hw_provider(node, of_clk_hw_onecell_get, top_clk_data);
-}
-
-CLK_OF_DECLARE_DRIVER(mt8192_topckgen, "mediatek,mt8192-topckgen",
- clk_mt8192_top_init_early);
-
/* Register mux notifier for MFG mux */
static int clk_mt8192_reg_mfg_mux_notifier(struct device *dev, struct clk *clk)
{
@@ -1090,93 +1064,6 @@ static int clk_mt8192_reg_mfg_mux_notifier(struct device *dev, struct clk *clk)
return devm_mtk_clk_mux_notifier_register(dev, clk, mfg_mux_nb);
}
-static int clk_mt8192_top_probe(struct platform_device *pdev)
-{
- struct device_node *node = pdev->dev.of_node;
- int r;
- void __iomem *base;
-
- base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(base))
- return PTR_ERR(base);
-
- mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks), top_clk_data);
- mtk_clk_register_factors(top_early_divs, ARRAY_SIZE(top_early_divs), top_clk_data);
- mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), top_clk_data);
- mtk_clk_register_muxes(top_mtk_muxes, ARRAY_SIZE(top_mtk_muxes), node, &mt8192_clk_lock,
- top_clk_data);
- mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes), base, &mt8192_clk_lock,
- top_clk_data);
- mtk_clk_register_composites(top_adj_divs, ARRAY_SIZE(top_adj_divs), base, &mt8192_clk_lock,
- top_clk_data);
- r = mtk_clk_register_gates(node, top_clks, ARRAY_SIZE(top_clks), top_clk_data);
- if (r)
- return r;
-
- r = clk_mt8192_reg_mfg_mux_notifier(&pdev->dev,
- top_clk_data->hws[CLK_TOP_MFG_PLL_SEL]->clk);
- if (r)
- return r;
-
-
- return of_clk_add_hw_provider(node, of_clk_hw_onecell_get,
- top_clk_data);
-}
-
-static int clk_mt8192_infra_probe(struct platform_device *pdev)
-{
- struct clk_hw_onecell_data *clk_data;
- struct device_node *node = pdev->dev.of_node;
- int r;
-
- clk_data = mtk_alloc_clk_data(CLK_INFRA_NR_CLK);
- if (!clk_data)
- return -ENOMEM;
-
- r = mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks), clk_data);
- if (r)
- goto free_clk_data;
-
- r = mtk_register_reset_controller_with_dev(&pdev->dev, &clk_rst_desc);
- if (r)
- goto free_clk_data;
-
- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
- if (r)
- goto free_clk_data;
-
- return r;
-
-free_clk_data:
- mtk_free_clk_data(clk_data);
- return r;
-}
-
-static int clk_mt8192_peri_probe(struct platform_device *pdev)
-{
- struct clk_hw_onecell_data *clk_data;
- struct device_node *node = pdev->dev.of_node;
- int r;
-
- clk_data = mtk_alloc_clk_data(CLK_PERI_NR_CLK);
- if (!clk_data)
- return -ENOMEM;
-
- r = mtk_clk_register_gates(node, peri_clks, ARRAY_SIZE(peri_clks), clk_data);
- if (r)
- goto free_clk_data;
-
- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
- if (r)
- goto free_clk_data;
-
- return r;
-
-free_clk_data:
- mtk_free_clk_data(clk_data);
- return r;
-}
-
static int clk_mt8192_apmixed_probe(struct platform_device *pdev)
{
struct clk_hw_onecell_data *clk_data;
@@ -1188,16 +1075,19 @@ static int clk_mt8192_apmixed_probe(struct platform_device *pdev)
return -ENOMEM;
mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
- r = mtk_clk_register_gates(node, apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data);
+ r = mtk_clk_register_gates(&pdev->dev, node, apmixed_clks,
+ ARRAY_SIZE(apmixed_clks), clk_data);
if (r)
goto free_clk_data;
r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
if (r)
- goto free_clk_data;
+ goto unregister_gates;
return r;
+unregister_gates:
+ mtk_clk_unregister_gates(apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data);
free_clk_data:
mtk_free_clk_data(clk_data);
return r;
@@ -1208,15 +1098,6 @@ static const struct of_device_id of_match_clk_mt8192[] = {
.compatible = "mediatek,mt8192-apmixedsys",
.data = clk_mt8192_apmixed_probe,
}, {
- .compatible = "mediatek,mt8192-topckgen",
- .data = clk_mt8192_top_probe,
- }, {
- .compatible = "mediatek,mt8192-infracfg",
- .data = clk_mt8192_infra_probe,
- }, {
- .compatible = "mediatek,mt8192-pericfg",
- .data = clk_mt8192_peri_probe,
- }, {
/* sentinel */
}
};
@@ -1237,6 +1118,49 @@ static int clk_mt8192_probe(struct platform_device *pdev)
return r;
}
+static const struct mtk_clk_desc infra_desc = {
+ .clks = infra_clks,
+ .num_clks = ARRAY_SIZE(infra_clks),
+ .rst_desc = &clk_rst_desc,
+};
+
+static const struct mtk_clk_desc peri_desc = {
+ .clks = peri_clks,
+ .num_clks = ARRAY_SIZE(peri_clks),
+};
+
+static const struct mtk_clk_desc topck_desc = {
+ .fixed_clks = top_fixed_clks,
+ .num_fixed_clks = ARRAY_SIZE(top_fixed_clks),
+ .factor_clks = top_divs,
+ .num_factor_clks = ARRAY_SIZE(top_divs),
+ .mux_clks = top_mtk_muxes,
+ .num_mux_clks = ARRAY_SIZE(top_mtk_muxes),
+ .composite_clks = top_muxes,
+ .num_composite_clks = ARRAY_SIZE(top_muxes),
+ .clks = top_clks,
+ .num_clks = ARRAY_SIZE(top_clks),
+ .clk_lock = &mt8192_clk_lock,
+ .clk_notifier_func = clk_mt8192_reg_mfg_mux_notifier,
+ .mfg_clk_idx = CLK_TOP_MFG_PLL_SEL,
+};
+
+static const struct of_device_id of_match_clk_mt8192_simple[] = {
+ { .compatible = "mediatek,mt8192-infracfg", .data = &infra_desc },
+ { .compatible = "mediatek,mt8192-pericfg", .data = &peri_desc },
+ { .compatible = "mediatek,mt8192-topckgen", .data = &topck_desc },
+ { /* sentinel */ }
+};
+
+static struct platform_driver clk_mt8192_simple_drv = {
+ .probe = mtk_clk_simple_probe,
+ .remove = mtk_clk_simple_remove,
+ .driver = {
+ .name = "clk-mt8192-simple",
+ .of_match_table = of_match_clk_mt8192_simple,
+ },
+};
+
static struct platform_driver clk_mt8192_drv = {
.probe = clk_mt8192_probe,
.driver = {
@@ -1247,7 +1171,11 @@ static struct platform_driver clk_mt8192_drv = {
static int __init clk_mt8192_init(void)
{
- return platform_driver_register(&clk_mt8192_drv);
+ int ret = platform_driver_register(&clk_mt8192_drv);
+
+ if (ret)
+ return ret;
+ return platform_driver_register(&clk_mt8192_simple_drv);
}
arch_initcall(clk_mt8192_init);
diff --git a/drivers/clk/mediatek/clk-mt8195-apmixedsys.c b/drivers/clk/mediatek/clk-mt8195-apmixedsys.c
index 0dfed6ec4d15..1bc917f2667e 100644
--- a/drivers/clk/mediatek/clk-mt8195-apmixedsys.c
+++ b/drivers/clk/mediatek/clk-mt8195-apmixedsys.c
@@ -124,7 +124,8 @@ static int clk_mt8195_apmixed_probe(struct platform_device *pdev)
if (r)
goto free_apmixed_data;
- r = mtk_clk_register_gates(node, apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data);
+ r = mtk_clk_register_gates(&pdev->dev, node, apmixed_clks,
+ ARRAY_SIZE(apmixed_clks), clk_data);
if (r)
goto unregister_plls;
diff --git a/drivers/clk/mediatek/clk-mt8195-topckgen.c b/drivers/clk/mediatek/clk-mt8195-topckgen.c
index 93e96419da66..cf520f85de73 100644
--- a/drivers/clk/mediatek/clk-mt8195-topckgen.c
+++ b/drivers/clk/mediatek/clk-mt8195-topckgen.c
@@ -1262,7 +1262,8 @@ static int clk_mt8195_topck_probe(struct platform_device *pdev)
if (r)
goto unregister_fixed_clks;
- r = mtk_clk_register_muxes(top_mtk_muxes, ARRAY_SIZE(top_mtk_muxes), node,
+ r = mtk_clk_register_muxes(&pdev->dev, top_mtk_muxes,
+ ARRAY_SIZE(top_mtk_muxes), node,
&mt8195_clk_lock, top_clk_data);
if (r)
goto unregister_factors;
@@ -1281,12 +1282,14 @@ static int clk_mt8195_topck_probe(struct platform_device *pdev)
if (r)
goto unregister_muxes;
- r = mtk_clk_register_composites(top_adj_divs, ARRAY_SIZE(top_adj_divs), base,
+ r = mtk_clk_register_composites(&pdev->dev, top_adj_divs,
+ ARRAY_SIZE(top_adj_divs), base,
&mt8195_clk_lock, top_clk_data);
if (r)
goto unregister_muxes;
- r = mtk_clk_register_gates(node, top_clks, ARRAY_SIZE(top_clks), top_clk_data);
+ r = mtk_clk_register_gates(&pdev->dev, node, top_clks,
+ ARRAY_SIZE(top_clks), top_clk_data);
if (r)
goto unregister_composite_divs;
diff --git a/drivers/clk/mediatek/clk-mt8195-vdo0.c b/drivers/clk/mediatek/clk-mt8195-vdo0.c
index 07b46bfd5040..839b730688ac 100644
--- a/drivers/clk/mediatek/clk-mt8195-vdo0.c
+++ b/drivers/clk/mediatek/clk-mt8195-vdo0.c
@@ -104,7 +104,8 @@ static int clk_mt8195_vdo0_probe(struct platform_device *pdev)
if (!clk_data)
return -ENOMEM;
- r = mtk_clk_register_gates(node, vdo0_clks, ARRAY_SIZE(vdo0_clks), clk_data);
+ r = mtk_clk_register_gates(&pdev->dev, node, vdo0_clks,
+ ARRAY_SIZE(vdo0_clks), clk_data);
if (r)
goto free_vdo0_data;
diff --git a/drivers/clk/mediatek/clk-mt8195-vdo1.c b/drivers/clk/mediatek/clk-mt8195-vdo1.c
index 835335b9d87b..7df695b28925 100644
--- a/drivers/clk/mediatek/clk-mt8195-vdo1.c
+++ b/drivers/clk/mediatek/clk-mt8195-vdo1.c
@@ -131,7 +131,8 @@ static int clk_mt8195_vdo1_probe(struct platform_device *pdev)
if (!clk_data)
return -ENOMEM;
- r = mtk_clk_register_gates(node, vdo1_clks, ARRAY_SIZE(vdo1_clks), clk_data);
+ r = mtk_clk_register_gates(&pdev->dev, node, vdo1_clks,
+ ARRAY_SIZE(vdo1_clks), clk_data);
if (r)
goto free_vdo1_data;
diff --git a/drivers/clk/mediatek/clk-mt8195-vpp0.c b/drivers/clk/mediatek/clk-mt8195-vpp0.c
index bf2939c3a023..e19664af09b6 100644
--- a/drivers/clk/mediatek/clk-mt8195-vpp0.c
+++ b/drivers/clk/mediatek/clk-mt8195-vpp0.c
@@ -86,26 +86,54 @@ static const struct mtk_gate vpp0_clks[] = {
GATE_VPP0_2(CLK_VPP0_WARP1_MDP_DL_ASYNC, "vpp0_warp1_mdp_dl_async", "top_wpe_vpp", 3),
};
-static const struct mtk_clk_desc vpp0_desc = {
- .clks = vpp0_clks,
- .num_clks = ARRAY_SIZE(vpp0_clks),
-};
+static int clk_mt8195_vpp0_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *node = dev->parent->of_node;
+ struct clk_hw_onecell_data *clk_data;
+ int r;
-static const struct of_device_id of_match_clk_mt8195_vpp0[] = {
- {
- .compatible = "mediatek,mt8195-vppsys0",
- .data = &vpp0_desc,
- }, {
- /* sentinel */
- }
-};
+ clk_data = mtk_alloc_clk_data(CLK_VPP0_NR_CLK);
+ if (!clk_data)
+ return -ENOMEM;
+
+ r = mtk_clk_register_gates(dev, node, vpp0_clks, ARRAY_SIZE(vpp0_clks), clk_data);
+ if (r)
+ goto free_vpp0_data;
+
+ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+ if (r)
+ goto unregister_gates;
+
+ platform_set_drvdata(pdev, clk_data);
+
+ return r;
+
+unregister_gates:
+ mtk_clk_unregister_gates(vpp0_clks, ARRAY_SIZE(vpp0_clks), clk_data);
+free_vpp0_data:
+ mtk_free_clk_data(clk_data);
+ return r;
+}
+
+static int clk_mt8195_vpp0_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *node = dev->parent->of_node;
+ struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev);
+
+ of_clk_del_provider(node);
+ mtk_clk_unregister_gates(vpp0_clks, ARRAY_SIZE(vpp0_clks), clk_data);
+ mtk_free_clk_data(clk_data);
+
+ return 0;
+}
static struct platform_driver clk_mt8195_vpp0_drv = {
- .probe = mtk_clk_simple_probe,
- .remove = mtk_clk_simple_remove,
+ .probe = clk_mt8195_vpp0_probe,
+ .remove = clk_mt8195_vpp0_remove,
.driver = {
.name = "clk-mt8195-vpp0",
- .of_match_table = of_match_clk_mt8195_vpp0,
},
};
builtin_platform_driver(clk_mt8195_vpp0_drv);
diff --git a/drivers/clk/mediatek/clk-mt8195-vpp1.c b/drivers/clk/mediatek/clk-mt8195-vpp1.c
index ffd52c762890..e6c458fc1531 100644
--- a/drivers/clk/mediatek/clk-mt8195-vpp1.c
+++ b/drivers/clk/mediatek/clk-mt8195-vpp1.c
@@ -84,26 +84,54 @@ static const struct mtk_gate vpp1_clks[] = {
GATE_VPP1_1(CLK_VPP1_VPP_SPLIT_26M, "vpp1_vpp_split_26m", "clk26m", 26),
};
-static const struct mtk_clk_desc vpp1_desc = {
- .clks = vpp1_clks,
- .num_clks = ARRAY_SIZE(vpp1_clks),
-};
+static int clk_mt8195_vpp1_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *node = dev->parent->of_node;
+ struct clk_hw_onecell_data *clk_data;
+ int r;
-static const struct of_device_id of_match_clk_mt8195_vpp1[] = {
- {
- .compatible = "mediatek,mt8195-vppsys1",
- .data = &vpp1_desc,
- }, {
- /* sentinel */
- }
-};
+ clk_data = mtk_alloc_clk_data(CLK_VPP1_NR_CLK);
+ if (!clk_data)
+ return -ENOMEM;
+
+ r = mtk_clk_register_gates(dev, node, vpp1_clks, ARRAY_SIZE(vpp1_clks), clk_data);
+ if (r)
+ goto free_vpp1_data;
+
+ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+ if (r)
+ goto unregister_gates;
+
+ platform_set_drvdata(pdev, clk_data);
+
+ return r;
+
+unregister_gates:
+ mtk_clk_unregister_gates(vpp1_clks, ARRAY_SIZE(vpp1_clks), clk_data);
+free_vpp1_data:
+ mtk_free_clk_data(clk_data);
+ return r;
+}
+
+static int clk_mt8195_vpp1_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *node = dev->parent->of_node;
+ struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev);
+
+ of_clk_del_provider(node);
+ mtk_clk_unregister_gates(vpp1_clks, ARRAY_SIZE(vpp1_clks), clk_data);
+ mtk_free_clk_data(clk_data);
+
+ return 0;
+}
static struct platform_driver clk_mt8195_vpp1_drv = {
- .probe = mtk_clk_simple_probe,
- .remove = mtk_clk_simple_remove,
+ .probe = clk_mt8195_vpp1_probe,
+ .remove = clk_mt8195_vpp1_remove,
.driver = {
.name = "clk-mt8195-vpp1",
- .of_match_table = of_match_clk_mt8195_vpp1,
},
};
builtin_platform_driver(clk_mt8195_vpp1_drv);
diff --git a/drivers/clk/mediatek/clk-mt8365-mm.c b/drivers/clk/mediatek/clk-mt8365-mm.c
index 5c8bf18ab1f1..22c75a03a645 100644
--- a/drivers/clk/mediatek/clk-mt8365-mm.c
+++ b/drivers/clk/mediatek/clk-mt8365-mm.c
@@ -81,9 +81,8 @@ static int clk_mt8365_mm_probe(struct platform_device *pdev)
clk_data = mtk_alloc_clk_data(CLK_MM_NR_CLK);
- ret = mtk_clk_register_gates_with_dev(node, mm_clks,
- ARRAY_SIZE(mm_clks), clk_data,
- dev);
+ ret = mtk_clk_register_gates(dev, node, mm_clks,
+ ARRAY_SIZE(mm_clks), clk_data);
if (ret)
goto err_free_clk_data;
diff --git a/drivers/clk/mediatek/clk-mt8365.c b/drivers/clk/mediatek/clk-mt8365.c
index adfecb618f10..c9faa07ec0a6 100644
--- a/drivers/clk/mediatek/clk-mt8365.c
+++ b/drivers/clk/mediatek/clk-mt8365.c
@@ -947,12 +947,13 @@ static int clk_mt8365_top_probe(struct platform_device *pdev)
if (ret)
goto unregister_fixed_clks;
- ret = mtk_clk_register_muxes(top_muxes, ARRAY_SIZE(top_muxes), node,
+ ret = mtk_clk_register_muxes(&pdev->dev, top_muxes,
+ ARRAY_SIZE(top_muxes), node,
&mt8365_clk_lock, clk_data);
if (ret)
goto unregister_factors;
- ret = mtk_clk_register_composites(top_misc_mux_gates,
+ ret = mtk_clk_register_composites(&pdev->dev, top_misc_mux_gates,
ARRAY_SIZE(top_misc_mux_gates), base,
&mt8365_clk_lock, clk_data);
if (ret)
@@ -1019,8 +1020,8 @@ static int clk_mt8365_infra_probe(struct platform_device *pdev)
if (!clk_data)
return -ENOMEM;
- ret = mtk_clk_register_gates(node, ifr_clks, ARRAY_SIZE(ifr_clks),
- clk_data);
+ ret = mtk_clk_register_gates(&pdev->dev, node, ifr_clks,
+ ARRAY_SIZE(ifr_clks), clk_data);
if (ret)
goto free_clk_data;
@@ -1080,8 +1081,9 @@ static int clk_mt8365_mcu_probe(struct platform_device *pdev)
if (!clk_data)
return -ENOMEM;
- ret = mtk_clk_register_composites(mcu_muxes, ARRAY_SIZE(mcu_muxes),
- base, &mt8365_clk_lock, clk_data);
+ ret = mtk_clk_register_composites(&pdev->dev, mcu_muxes,
+ ARRAY_SIZE(mcu_muxes), base,
+ &mt8365_clk_lock, clk_data);
if (ret)
goto free_clk_data;
diff --git a/drivers/clk/mediatek/clk-mt8516-aud.c b/drivers/clk/mediatek/clk-mt8516-aud.c
index 90f48068a8de..00f356fe7c7a 100644
--- a/drivers/clk/mediatek/clk-mt8516-aud.c
+++ b/drivers/clk/mediatek/clk-mt8516-aud.c
@@ -54,7 +54,7 @@ static void __init mtk_audsys_init(struct device_node *node)
clk_data = mtk_alloc_clk_data(CLK_AUD_NR_CLK);
- mtk_clk_register_gates(node, aud_clks, ARRAY_SIZE(aud_clks), clk_data);
+ mtk_clk_register_gates(NULL, node, aud_clks, ARRAY_SIZE(aud_clks), clk_data);
r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
if (r)
diff --git a/drivers/clk/mediatek/clk-mt8516.c b/drivers/clk/mediatek/clk-mt8516.c
index b96db88893e2..2c0cae7b3bcf 100644
--- a/drivers/clk/mediatek/clk-mt8516.c
+++ b/drivers/clk/mediatek/clk-mt8516.c
@@ -691,11 +691,12 @@ static void __init mtk_topckgen_init(struct device_node *node)
mtk_clk_register_fixed_clks(fixed_clks, ARRAY_SIZE(fixed_clks),
clk_data);
- mtk_clk_register_gates(node, top_clks, ARRAY_SIZE(top_clks), clk_data);
+ mtk_clk_register_gates(NULL, node, top_clks, ARRAY_SIZE(top_clks), clk_data);
mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), clk_data);
- mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes), base,
- &mt8516_clk_lock, clk_data);
+ mtk_clk_register_composites(NULL, top_muxes,
+ ARRAY_SIZE(top_muxes), base,
+ &mt8516_clk_lock, clk_data);
mtk_clk_register_dividers(top_adj_divs, ARRAY_SIZE(top_adj_divs),
base, &mt8516_clk_lock, clk_data);
@@ -720,8 +721,9 @@ static void __init mtk_infracfg_init(struct device_node *node)
clk_data = mtk_alloc_clk_data(CLK_IFR_NR_CLK);
- mtk_clk_register_composites(ifr_muxes, ARRAY_SIZE(ifr_muxes), base,
- &mt8516_clk_lock, clk_data);
+ mtk_clk_register_composites(NULL, ifr_muxes,
+ ARRAY_SIZE(ifr_muxes), base,
+ &mt8516_clk_lock, clk_data);
r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
if (r)
diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c
index 3c1ac8d3010f..14e8b64a32a3 100644
--- a/drivers/clk/mediatek/clk-mtk.c
+++ b/drivers/clk/mediatek/clk-mtk.c
@@ -11,12 +11,30 @@
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include "clk-mtk.h"
#include "clk-gate.h"
+#include "clk-mux.h"
+
+const struct mtk_gate_regs cg_regs_dummy = { 0, 0, 0 };
+EXPORT_SYMBOL_GPL(cg_regs_dummy);
+
+static int mtk_clk_dummy_enable(struct clk_hw *hw)
+{
+ return 0;
+}
+
+static void mtk_clk_dummy_disable(struct clk_hw *hw) { }
+
+const struct clk_ops mtk_clk_dummy_ops = {
+ .enable = mtk_clk_dummy_enable,
+ .disable = mtk_clk_dummy_disable,
+};
+EXPORT_SYMBOL_GPL(mtk_clk_dummy_ops);
static void mtk_init_clk_data(struct clk_hw_onecell_data *clk_data,
unsigned int clk_num)
@@ -197,8 +215,8 @@ void mtk_clk_unregister_factors(const struct mtk_fixed_factor *clks, int num,
}
EXPORT_SYMBOL_GPL(mtk_clk_unregister_factors);
-static struct clk_hw *mtk_clk_register_composite(const struct mtk_composite *mc,
- void __iomem *base, spinlock_t *lock)
+static struct clk_hw *mtk_clk_register_composite(struct device *dev,
+ const struct mtk_composite *mc, void __iomem *base, spinlock_t *lock)
{
struct clk_hw *hw;
struct clk_mux *mux = NULL;
@@ -264,7 +282,7 @@ static struct clk_hw *mtk_clk_register_composite(const struct mtk_composite *mc,
div_ops = &clk_divider_ops;
}
- hw = clk_hw_register_composite(NULL, mc->name, parent_names, num_parents,
+ hw = clk_hw_register_composite(dev, mc->name, parent_names, num_parents,
mux_hw, mux_ops,
div_hw, div_ops,
gate_hw, gate_ops,
@@ -308,7 +326,8 @@ static void mtk_clk_unregister_composite(struct clk_hw *hw)
kfree(mux);
}
-int mtk_clk_register_composites(const struct mtk_composite *mcs, int num,
+int mtk_clk_register_composites(struct device *dev,
+ const struct mtk_composite *mcs, int num,
void __iomem *base, spinlock_t *lock,
struct clk_hw_onecell_data *clk_data)
{
@@ -327,7 +346,7 @@ int mtk_clk_register_composites(const struct mtk_composite *mcs, int num,
continue;
}
- hw = mtk_clk_register_composite(mc, base, lock);
+ hw = mtk_clk_register_composite(dev, mc, base, lock);
if (IS_ERR(hw)) {
pr_err("Failed to register clk %s: %pe\n", mc->name,
@@ -449,20 +468,79 @@ int mtk_clk_simple_probe(struct platform_device *pdev)
const struct mtk_clk_desc *mcd;
struct clk_hw_onecell_data *clk_data;
struct device_node *node = pdev->dev.of_node;
- int r;
+ void __iomem *base;
+ int num_clks, r;
mcd = of_device_get_match_data(&pdev->dev);
if (!mcd)
return -EINVAL;
- clk_data = mtk_alloc_clk_data(mcd->num_clks);
+ /* Composite clocks needs us to pass iomem pointer */
+ if (mcd->composite_clks) {
+ if (!mcd->shared_io)
+ base = devm_platform_ioremap_resource(pdev, 0);
+ else
+ base = of_iomap(node, 0);
+
+ if (IS_ERR_OR_NULL(base))
+ return IS_ERR(base) ? PTR_ERR(base) : -ENOMEM;
+ }
+
+ /* Calculate how many clk_hw_onecell_data entries to allocate */
+ num_clks = mcd->num_clks + mcd->num_composite_clks;
+ num_clks += mcd->num_fixed_clks + mcd->num_factor_clks;
+ num_clks += mcd->num_mux_clks;
+
+ clk_data = mtk_alloc_clk_data(num_clks);
if (!clk_data)
return -ENOMEM;
- r = mtk_clk_register_gates_with_dev(node, mcd->clks, mcd->num_clks,
- clk_data, &pdev->dev);
- if (r)
- goto free_data;
+ if (mcd->fixed_clks) {
+ r = mtk_clk_register_fixed_clks(mcd->fixed_clks,
+ mcd->num_fixed_clks, clk_data);
+ if (r)
+ goto free_data;
+ }
+
+ if (mcd->factor_clks) {
+ r = mtk_clk_register_factors(mcd->factor_clks,
+ mcd->num_factor_clks, clk_data);
+ if (r)
+ goto unregister_fixed_clks;
+ }
+
+ if (mcd->mux_clks) {
+ r = mtk_clk_register_muxes(&pdev->dev, mcd->mux_clks,
+ mcd->num_mux_clks, node,
+ mcd->clk_lock, clk_data);
+ if (r)
+ goto unregister_factors;
+ }
+
+ if (mcd->composite_clks) {
+ /* We don't check composite_lock because it's optional */
+ r = mtk_clk_register_composites(&pdev->dev,
+ mcd->composite_clks,
+ mcd->num_composite_clks,
+ base, mcd->clk_lock, clk_data);
+ if (r)
+ goto unregister_muxes;
+ }
+
+ if (mcd->clks) {
+ r = mtk_clk_register_gates(&pdev->dev, node, mcd->clks,
+ mcd->num_clks, clk_data);
+ if (r)
+ goto unregister_composites;
+ }
+
+ if (mcd->clk_notifier_func) {
+ struct clk *mfg_mux = clk_data->hws[mcd->mfg_clk_idx]->clk;
+
+ r = mcd->clk_notifier_func(&pdev->dev, mfg_mux);
+ if (r)
+ goto unregister_clks;
+ }
r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
if (r)
@@ -480,9 +558,28 @@ int mtk_clk_simple_probe(struct platform_device *pdev)
return r;
unregister_clks:
- mtk_clk_unregister_gates(mcd->clks, mcd->num_clks, clk_data);
+ if (mcd->clks)
+ mtk_clk_unregister_gates(mcd->clks, mcd->num_clks, clk_data);
+unregister_composites:
+ if (mcd->composite_clks)
+ mtk_clk_unregister_composites(mcd->composite_clks,
+ mcd->num_composite_clks, clk_data);
+unregister_muxes:
+ if (mcd->mux_clks)
+ mtk_clk_unregister_muxes(mcd->mux_clks,
+ mcd->num_mux_clks, clk_data);
+unregister_factors:
+ if (mcd->factor_clks)
+ mtk_clk_unregister_factors(mcd->factor_clks,
+ mcd->num_factor_clks, clk_data);
+unregister_fixed_clks:
+ if (mcd->fixed_clks)
+ mtk_clk_unregister_fixed_clks(mcd->fixed_clks,
+ mcd->num_fixed_clks, clk_data);
free_data:
mtk_free_clk_data(clk_data);
+ if (mcd->shared_io && base)
+ iounmap(base);
return r;
}
EXPORT_SYMBOL_GPL(mtk_clk_simple_probe);
@@ -494,7 +591,20 @@ int mtk_clk_simple_remove(struct platform_device *pdev)
struct device_node *node = pdev->dev.of_node;
of_clk_del_provider(node);
- mtk_clk_unregister_gates(mcd->clks, mcd->num_clks, clk_data);
+ if (mcd->clks)
+ mtk_clk_unregister_gates(mcd->clks, mcd->num_clks, clk_data);
+ if (mcd->composite_clks)
+ mtk_clk_unregister_composites(mcd->composite_clks,
+ mcd->num_composite_clks, clk_data);
+ if (mcd->mux_clks)
+ mtk_clk_unregister_muxes(mcd->mux_clks,
+ mcd->num_mux_clks, clk_data);
+ if (mcd->factor_clks)
+ mtk_clk_unregister_factors(mcd->factor_clks,
+ mcd->num_factor_clks, clk_data);
+ if (mcd->fixed_clks)
+ mtk_clk_unregister_fixed_clks(mcd->fixed_clks,
+ mcd->num_fixed_clks, clk_data);
mtk_free_clk_data(clk_data);
return 0;
diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h
index f2db6b57d5b5..41f4fa3b0c21 100644
--- a/drivers/clk/mediatek/clk-mtk.h
+++ b/drivers/clk/mediatek/clk-mtk.h
@@ -22,6 +22,25 @@
struct platform_device;
+/*
+ * We need the clock IDs to start from zero but to maintain devicetree
+ * backwards compatibility we can't change bindings to start from zero.
+ * Only a few platforms are affected, so we solve issues given by the
+ * commonized MTK clocks probe function(s) by adding a dummy clock at
+ * the beginning where needed.
+ */
+#define CLK_DUMMY 0
+
+extern const struct clk_ops mtk_clk_dummy_ops;
+extern const struct mtk_gate_regs cg_regs_dummy;
+
+#define GATE_DUMMY(_id, _name) { \
+ .id = _id, \
+ .name = _name, \
+ .regs = &cg_regs_dummy, \
+ .ops = &mtk_clk_dummy_ops, \
+ }
+
struct mtk_fixed_clk {
int id;
const char *name;
@@ -154,7 +173,8 @@ struct mtk_composite {
.flags = 0, \
}
-int mtk_clk_register_composites(const struct mtk_composite *mcs, int num,
+int mtk_clk_register_composites(struct device *dev,
+ const struct mtk_composite *mcs, int num,
void __iomem *base, spinlock_t *lock,
struct clk_hw_onecell_data *clk_data);
void mtk_clk_unregister_composites(const struct mtk_composite *mcs, int num,
@@ -200,7 +220,20 @@ void mtk_clk_unregister_ref2usb_tx(struct clk_hw *hw);
struct mtk_clk_desc {
const struct mtk_gate *clks;
size_t num_clks;
+ const struct mtk_composite *composite_clks;
+ size_t num_composite_clks;
+ const struct mtk_fixed_clk *fixed_clks;
+ size_t num_fixed_clks;
+ const struct mtk_fixed_factor *factor_clks;
+ size_t num_factor_clks;
+ const struct mtk_mux *mux_clks;
+ size_t num_mux_clks;
const struct mtk_clk_rst_desc *rst_desc;
+ spinlock_t *clk_lock;
+ bool shared_io;
+
+ int (*clk_notifier_func)(struct device *dev, struct clk *clk);
+ unsigned int mfg_clk_idx;
};
int mtk_clk_simple_probe(struct platform_device *pdev);
diff --git a/drivers/clk/mediatek/clk-mux.c b/drivers/clk/mediatek/clk-mux.c
index ba1720b9e231..c8593554239d 100644
--- a/drivers/clk/mediatek/clk-mux.c
+++ b/drivers/clk/mediatek/clk-mux.c
@@ -154,9 +154,10 @@ const struct clk_ops mtk_mux_gate_clr_set_upd_ops = {
};
EXPORT_SYMBOL_GPL(mtk_mux_gate_clr_set_upd_ops);
-static struct clk_hw *mtk_clk_register_mux(const struct mtk_mux *mux,
- struct regmap *regmap,
- spinlock_t *lock)
+static struct clk_hw *mtk_clk_register_mux(struct device *dev,
+ const struct mtk_mux *mux,
+ struct regmap *regmap,
+ spinlock_t *lock)
{
struct mtk_clk_mux *clk_mux;
struct clk_init_data init = {};
@@ -177,7 +178,7 @@ static struct clk_hw *mtk_clk_register_mux(const struct mtk_mux *mux,
clk_mux->lock = lock;
clk_mux->hw.init = &init;
- ret = clk_hw_register(NULL, &clk_mux->hw);
+ ret = clk_hw_register(dev, &clk_mux->hw);
if (ret) {
kfree(clk_mux);
return ERR_PTR(ret);
@@ -198,7 +199,8 @@ static void mtk_clk_unregister_mux(struct clk_hw *hw)
kfree(mux);
}
-int mtk_clk_register_muxes(const struct mtk_mux *muxes,
+int mtk_clk_register_muxes(struct device *dev,
+ const struct mtk_mux *muxes,
int num, struct device_node *node,
spinlock_t *lock,
struct clk_hw_onecell_data *clk_data)
@@ -222,7 +224,7 @@ int mtk_clk_register_muxes(const struct mtk_mux *muxes,
continue;
}
- hw = mtk_clk_register_mux(mux, regmap, lock);
+ hw = mtk_clk_register_mux(dev, mux, regmap, lock);
if (IS_ERR(hw)) {
pr_err("Failed to register clk %s: %pe\n", mux->name,
diff --git a/drivers/clk/mediatek/clk-mux.h b/drivers/clk/mediatek/clk-mux.h
index 83ff420f4ebe..7ecb963b0ec6 100644
--- a/drivers/clk/mediatek/clk-mux.h
+++ b/drivers/clk/mediatek/clk-mux.h
@@ -83,7 +83,8 @@ extern const struct clk_ops mtk_mux_gate_clr_set_upd_ops;
0, _upd_ofs, _upd, CLK_SET_RATE_PARENT, \
mtk_mux_clr_set_upd_ops)
-int mtk_clk_register_muxes(const struct mtk_mux *muxes,
+int mtk_clk_register_muxes(struct device *dev,
+ const struct mtk_mux *muxes,
int num, struct device_node *node,
spinlock_t *lock,
struct clk_hw_onecell_data *clk_data);
diff --git a/drivers/clk/meson/clk-cpu-dyndiv.c b/drivers/clk/meson/clk-cpu-dyndiv.c
index 36976927fe82..8778c149d26a 100644
--- a/drivers/clk/meson/clk-cpu-dyndiv.c
+++ b/drivers/clk/meson/clk-cpu-dyndiv.c
@@ -27,14 +27,13 @@ static unsigned long meson_clk_cpu_dyndiv_recalc_rate(struct clk_hw *hw,
NULL, 0, data->div.width);
}
-static long meson_clk_cpu_dyndiv_round_rate(struct clk_hw *hw,
- unsigned long rate,
- unsigned long *prate)
+static int meson_clk_cpu_dyndiv_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct meson_clk_cpu_dyndiv_data *data = meson_clk_cpu_dyndiv_data(clk);
- return divider_round_rate(hw, rate, prate, NULL, data->div.width, 0);
+ return divider_determine_rate(hw, req, NULL, data->div.width, 0);
}
static int meson_clk_cpu_dyndiv_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -63,7 +62,7 @@ static int meson_clk_cpu_dyndiv_set_rate(struct clk_hw *hw, unsigned long rate,
const struct clk_ops meson_clk_cpu_dyndiv_ops = {
.recalc_rate = meson_clk_cpu_dyndiv_recalc_rate,
- .round_rate = meson_clk_cpu_dyndiv_round_rate,
+ .determine_rate = meson_clk_cpu_dyndiv_determine_rate,
.set_rate = meson_clk_cpu_dyndiv_set_rate,
};
EXPORT_SYMBOL_GPL(meson_clk_cpu_dyndiv_ops);
diff --git a/drivers/clk/meson/clk-dualdiv.c b/drivers/clk/meson/clk-dualdiv.c
index c5ca23a5e3e8..feae49a8f6dc 100644
--- a/drivers/clk/meson/clk-dualdiv.c
+++ b/drivers/clk/meson/clk-dualdiv.c
@@ -86,18 +86,23 @@ __dualdiv_get_setting(unsigned long rate, unsigned long parent_rate,
return (struct meson_clk_dualdiv_param *)&table[best_i];
}
-static long meson_clk_dualdiv_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *parent_rate)
+static int meson_clk_dualdiv_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct meson_clk_dualdiv_data *dualdiv = meson_clk_dualdiv_data(clk);
- const struct meson_clk_dualdiv_param *setting =
- __dualdiv_get_setting(rate, *parent_rate, dualdiv);
+ const struct meson_clk_dualdiv_param *setting;
- if (!setting)
- return meson_clk_dualdiv_recalc_rate(hw, *parent_rate);
+ setting = __dualdiv_get_setting(req->rate, req->best_parent_rate,
+ dualdiv);
+ if (setting)
+ req->rate = __dualdiv_param_to_rate(req->best_parent_rate,
+ setting);
+ else
+ req->rate = meson_clk_dualdiv_recalc_rate(hw,
+ req->best_parent_rate);
- return __dualdiv_param_to_rate(*parent_rate, setting);
+ return 0;
}
static int meson_clk_dualdiv_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -122,7 +127,7 @@ static int meson_clk_dualdiv_set_rate(struct clk_hw *hw, unsigned long rate,
const struct clk_ops meson_clk_dualdiv_ops = {
.recalc_rate = meson_clk_dualdiv_recalc_rate,
- .round_rate = meson_clk_dualdiv_round_rate,
+ .determine_rate = meson_clk_dualdiv_determine_rate,
.set_rate = meson_clk_dualdiv_set_rate,
};
EXPORT_SYMBOL_GPL(meson_clk_dualdiv_ops);
diff --git a/drivers/clk/meson/clk-mpll.c b/drivers/clk/meson/clk-mpll.c
index fc9df4860872..20255e129b37 100644
--- a/drivers/clk/meson/clk-mpll.c
+++ b/drivers/clk/meson/clk-mpll.c
@@ -87,16 +87,22 @@ static unsigned long mpll_recalc_rate(struct clk_hw *hw,
return rate < 0 ? 0 : rate;
}
-static long mpll_round_rate(struct clk_hw *hw,
- unsigned long rate,
- unsigned long *parent_rate)
+static int mpll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk);
unsigned int sdm, n2;
+ long rate;
+
+ params_from_rate(req->rate, req->best_parent_rate, &sdm, &n2,
+ mpll->flags);
- params_from_rate(rate, *parent_rate, &sdm, &n2, mpll->flags);
- return rate_from_params(*parent_rate, sdm, n2);
+ rate = rate_from_params(req->best_parent_rate, sdm, n2);
+ if (rate < 0)
+ return rate;
+
+ req->rate = rate;
+ return 0;
}
static int mpll_set_rate(struct clk_hw *hw,
@@ -157,13 +163,13 @@ static int mpll_init(struct clk_hw *hw)
const struct clk_ops meson_clk_mpll_ro_ops = {
.recalc_rate = mpll_recalc_rate,
- .round_rate = mpll_round_rate,
+ .determine_rate = mpll_determine_rate,
};
EXPORT_SYMBOL_GPL(meson_clk_mpll_ro_ops);
const struct clk_ops meson_clk_mpll_ops = {
.recalc_rate = mpll_recalc_rate,
- .round_rate = mpll_round_rate,
+ .determine_rate = mpll_determine_rate,
.set_rate = mpll_set_rate,
.init = mpll_init,
};
diff --git a/drivers/clk/meson/sclk-div.c b/drivers/clk/meson/sclk-div.c
index 76d31c0a3342..d12c45c4c261 100644
--- a/drivers/clk/meson/sclk-div.c
+++ b/drivers/clk/meson/sclk-div.c
@@ -96,16 +96,17 @@ static int sclk_div_bestdiv(struct clk_hw *hw, unsigned long rate,
return bestdiv;
}
-static long sclk_div_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
+static int sclk_div_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
int div;
- div = sclk_div_bestdiv(hw, rate, prate, sclk);
+ div = sclk_div_bestdiv(hw, req->rate, &req->best_parent_rate, sclk);
+ req->rate = DIV_ROUND_UP_ULL((u64)req->best_parent_rate, div);
- return DIV_ROUND_UP_ULL((u64)*prate, div);
+ return 0;
}
static void sclk_apply_ratio(struct clk_regmap *clk,
@@ -237,7 +238,7 @@ static int sclk_div_init(struct clk_hw *hw)
const struct clk_ops meson_sclk_div_ops = {
.recalc_rate = sclk_div_recalc_rate,
- .round_rate = sclk_div_round_rate,
+ .determine_rate = sclk_div_determine_rate,
.set_rate = sclk_div_set_rate,
.enable = sclk_div_enable,
.disable = sclk_div_disable,
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 70d43f0a8919..5ab4b7dfe3c2 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -410,6 +410,15 @@ config SC_DISPCC_8280XP
Say Y if you want to support display devices and functionality such as
splash screen.
+config SA_GCC_8775P
+ tristate "SA8775 Global Clock Controller"
+ select QCOM_GDSC
+ depends on COMMON_CLK_QCOM
+ help
+ Support for the global clock controller on SA8775 devices.
+ Say Y if you want to use peripheral devices such as UART, SPI,
+ I2C, USB, UFS, SDCC, etc.
+
config SC_GCC_7180
tristate "SC7180 Global Clock Controller"
select QCOM_GDSC
@@ -569,6 +578,14 @@ config QCS_Q6SSTOP_404
Say Y if you want to use the Q6SSTOP branch clocks of the WCSS clock
controller to reset the Q6SSTOP subsystem.
+config QDU_GCC_1000
+ tristate "QDU1000/QRU1000 Global Clock Controller"
+ select QCOM_GDSC
+ help
+ Support for the global clock controller on QDU1000 and
+ QRU1000 devices. Say Y if you want to use peripheral
+ devices such as UART, SPI, I2C, USB, SD, PCIe, etc.
+
config SDM_GCC_845
tristate "SDM845/SDM670 Global Clock Controller"
select QCOM_GDSC
@@ -627,6 +644,13 @@ config SDX_GCC_65
Say Y if you want to use peripheral devices such as UART,
SPI, I2C, USB, SD/UFS, PCIe etc.
+config SM_CAMCC_6350
+ tristate "SM6350 Camera Clock Controller"
+ select SM_GCC_6350
+ help
+ Support for the camera clock controller on SM6350 devices.
+ Say Y if you want to support camera devices and camera functionality.
+
config SM_CAMCC_8250
tristate "SM8250 Camera Clock Controller"
select SM_GCC_8250
@@ -695,6 +719,15 @@ config SM_DISPCC_8450
Say Y if you want to support display devices and functionality such as
splash screen.
+config SM_DISPCC_8550
+ tristate "SM8550 Display Clock Controller"
+ depends on SM_GCC_8550
+ help
+ Support for the display clock controller on Qualcomm Technologies, Inc
+ SM8550 devices.
+ Say Y if you want to support display devices and functionality such as
+ splash screen.
+
config SM_GCC_6115
tristate "SM6115 and SM4250 Global Clock Controller"
select QCOM_GDSC
@@ -797,6 +830,13 @@ config SM_GPUCC_8350
Say Y if you want to support graphics controller devices and
functionality such as 3D graphics.
+config SM_TCSRCC_8550
+ tristate "SM8550 TCSR Clock Controller"
+ select QCOM_GDSC
+ help
+ Support for the TCSR clock controller on SM8550 devices.
+ Say Y if you want to use peripheral devices such as SD/UFS.
+
config SM_VIDEOCC_8150
tristate "SM8150 Video Clock Controller"
select SM_GCC_8150
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index f18c446a97ea..c743805a9cbb 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -52,7 +52,7 @@ obj-$(CONFIG_MSM_MMCC_8998) += mmcc-msm8998.o
obj-$(CONFIG_QCOM_A53PLL) += a53-pll.o
obj-$(CONFIG_QCOM_A7PLL) += a7-pll.o
obj-$(CONFIG_QCOM_CLK_APCS_MSM8916) += apcs-msm8916.o
-obj-$(CONFIG_QCOM_CLK_APCC_MSM8996) += clk-cpu-8996.o
+obj-$(CONFIG_QCOM_CLK_APCC_MSM8996) += apcs-msm8996.o clk-cpu-8996.o clk-cbf-8996.o
obj-$(CONFIG_QCOM_CLK_APCS_SDX55) += apcs-sdx55.o
obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o
obj-$(CONFIG_QCOM_CLK_RPMH) += clk-rpmh.o
@@ -62,11 +62,13 @@ obj-$(CONFIG_QCM_DISPCC_2290) += dispcc-qcm2290.o
obj-$(CONFIG_QCS_GCC_404) += gcc-qcs404.o
obj-$(CONFIG_QCS_Q6SSTOP_404) += q6sstop-qcs404.o
obj-$(CONFIG_QCS_TURING_404) += turingcc-qcs404.o
+obj-$(CONFIG_QDU_GCC_1000) += gcc-qdu1000.o
obj-$(CONFIG_SC_CAMCC_7180) += camcc-sc7180.o
obj-$(CONFIG_SC_CAMCC_7280) += camcc-sc7280.o
obj-$(CONFIG_SC_DISPCC_7180) += dispcc-sc7180.o
obj-$(CONFIG_SC_DISPCC_7280) += dispcc-sc7280.o
obj-$(CONFIG_SC_DISPCC_8280XP) += dispcc-sc8280xp.o
+obj-$(CONFIG_SA_GCC_8775P) += gcc-sa8775p.o
obj-$(CONFIG_SC_GCC_7180) += gcc-sc7180.o
obj-$(CONFIG_SC_GCC_7280) += gcc-sc7280.o
obj-$(CONFIG_SC_GCC_8180X) += gcc-sc8180x.o
@@ -91,6 +93,7 @@ obj-$(CONFIG_SDM_LPASSCC_845) += lpasscc-sdm845.o
obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o
obj-$(CONFIG_SDX_GCC_55) += gcc-sdx55.o
obj-$(CONFIG_SDX_GCC_65) += gcc-sdx65.o
+obj-$(CONFIG_SM_CAMCC_6350) += camcc-sm6350.o
obj-$(CONFIG_SM_CAMCC_8250) += camcc-sm8250.o
obj-$(CONFIG_SM_CAMCC_8450) += camcc-sm8450.o
obj-$(CONFIG_SM_DISPCC_6115) += dispcc-sm6115.o
@@ -99,6 +102,7 @@ obj-$(CONFIG_SM_DISPCC_6350) += dispcc-sm6350.o
obj-$(CONFIG_SM_DISPCC_6375) += dispcc-sm6375.o
obj-$(CONFIG_SM_DISPCC_8250) += dispcc-sm8250.o
obj-$(CONFIG_SM_DISPCC_8450) += dispcc-sm8450.o
+obj-$(CONFIG_SM_DISPCC_8550) += dispcc-sm8550.o
obj-$(CONFIG_SM_GCC_6115) += gcc-sm6115.o
obj-$(CONFIG_SM_GCC_6125) += gcc-sm6125.o
obj-$(CONFIG_SM_GCC_6350) += gcc-sm6350.o
@@ -112,6 +116,7 @@ obj-$(CONFIG_SM_GPUCC_6350) += gpucc-sm6350.o
obj-$(CONFIG_SM_GPUCC_8150) += gpucc-sm8150.o
obj-$(CONFIG_SM_GPUCC_8250) += gpucc-sm8250.o
obj-$(CONFIG_SM_GPUCC_8350) += gpucc-sm8350.o
+obj-$(CONFIG_SM_TCSRCC_8550) += tcsrcc-sm8550.o
obj-$(CONFIG_SM_VIDEOCC_8150) += videocc-sm8150.o
obj-$(CONFIG_SM_VIDEOCC_8250) += videocc-sm8250.o
obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o
diff --git a/drivers/clk/qcom/apcs-msm8996.c b/drivers/clk/qcom/apcs-msm8996.c
new file mode 100644
index 000000000000..3e91e9e6da74
--- /dev/null
+++ b/drivers/clk/qcom/apcs-msm8996.c
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Qualcomm APCS clock controller driver
+ *
+ * Copyright (c) 2022, Linaro Limited
+ * Author: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+ */
+
+#include <linux/bits.h>
+#include <linux/bitfield.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define APCS_AUX_OFFSET 0x50
+
+#define APCS_AUX_DIV_MASK GENMASK(17, 16)
+#define APCS_AUX_DIV_2 0x1
+
+static int qcom_apcs_msm8996_clk_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device *parent = dev->parent;
+ struct regmap *regmap;
+ struct clk_hw *hw;
+ unsigned int val;
+ int ret = -ENODEV;
+
+ regmap = dev_get_regmap(parent, NULL);
+ if (!regmap) {
+ dev_err(dev, "failed to get regmap: %d\n", ret);
+ return ret;
+ }
+
+ regmap_read(regmap, APCS_AUX_OFFSET, &val);
+ regmap_update_bits(regmap, APCS_AUX_OFFSET, APCS_AUX_DIV_MASK,
+ FIELD_PREP(APCS_AUX_DIV_MASK, APCS_AUX_DIV_2));
+
+ /*
+ * This clock is used during CPU cluster setup while setting up CPU PLLs.
+ * Add hardware mandated delay to make sure that the sys_apcs_aux clock
+ * is stable (after setting the divider) before continuing
+ * bootstrapping to keep CPUs from ending up in a weird state.
+ */
+ udelay(5);
+
+ /*
+ * As this clocks is a parent of the CPU cluster clocks and is actually
+ * used as a parent during CPU clocks setup, we want for it to register
+ * as early as possible, without letting fw_devlink to delay probing of
+ * either of the drivers.
+ *
+ * The sys_apcs_aux is a child (divider) of gpll0, but we register it
+ * as a fixed rate clock instead to ease bootstrapping procedure. By
+ * doing this we make sure that CPU cluster clocks are able to be setup
+ * early during the boot process (as it is recommended by Qualcomm).
+ */
+ hw = devm_clk_hw_register_fixed_rate(dev, "sys_apcs_aux", NULL, 0, 300000000);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+
+ return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw);
+}
+
+static struct platform_driver qcom_apcs_msm8996_clk_driver = {
+ .probe = qcom_apcs_msm8996_clk_probe,
+ .driver = {
+ .name = "qcom-apcs-msm8996-clk",
+ },
+};
+
+/* Register early enough to fix the clock to be used for other cores */
+static int __init qcom_apcs_msm8996_clk_init(void)
+{
+ return platform_driver_register(&qcom_apcs_msm8996_clk_driver);
+}
+postcore_initcall(qcom_apcs_msm8996_clk_init);
+
+static void __exit qcom_apcs_msm8996_clk_exit(void)
+{
+ platform_driver_unregister(&qcom_apcs_msm8996_clk_driver);
+}
+module_exit(qcom_apcs_msm8996_clk_exit);
+
+MODULE_AUTHOR("Dmitry Baryshkov <dmitry.baryshkov@linaro.org>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Qualcomm MSM8996 APCS clock driver");
diff --git a/drivers/clk/qcom/camcc-sc7280.c b/drivers/clk/qcom/camcc-sc7280.c
index ec163ea769f5..4396fddba7a6 100644
--- a/drivers/clk/qcom/camcc-sc7280.c
+++ b/drivers/clk/qcom/camcc-sc7280.c
@@ -88,8 +88,8 @@ static struct clk_alpha_pll_postdiv cam_cc_pll0_out_even = {
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
.clkr.hw.init = &(struct clk_init_data){
.name = "cam_cc_pll0_out_even",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_pll0.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_pll0.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -111,8 +111,8 @@ static struct clk_alpha_pll_postdiv cam_cc_pll0_out_odd = {
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
.clkr.hw.init = &(struct clk_init_data){
.name = "cam_cc_pll0_out_odd",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_pll0.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_pll0.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -163,8 +163,8 @@ static struct clk_alpha_pll_postdiv cam_cc_pll1_out_even = {
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
.clkr.hw.init = &(struct clk_init_data){
.name = "cam_cc_pll1_out_even",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_pll1.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_pll1.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -213,8 +213,8 @@ static struct clk_alpha_pll_postdiv cam_cc_pll2_out_aux = {
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_ZONDA],
.clkr.hw.init = &(struct clk_init_data){
.name = "cam_cc_pll2_out_aux",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_pll2.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_pll2.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -236,8 +236,8 @@ static struct clk_alpha_pll_postdiv cam_cc_pll2_out_aux2 = {
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_ZONDA],
.clkr.hw.init = &(struct clk_init_data){
.name = "cam_cc_pll2_out_aux2",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_pll2.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_pll2.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -288,8 +288,8 @@ static struct clk_alpha_pll_postdiv cam_cc_pll3_out_even = {
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
.clkr.hw.init = &(struct clk_init_data){
.name = "cam_cc_pll3_out_even",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_pll3.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_pll3.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -340,8 +340,8 @@ static struct clk_alpha_pll_postdiv cam_cc_pll4_out_even = {
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
.clkr.hw.init = &(struct clk_init_data){
.name = "cam_cc_pll4_out_even",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_pll4.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_pll4.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -392,8 +392,8 @@ static struct clk_alpha_pll_postdiv cam_cc_pll5_out_even = {
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
.clkr.hw.init = &(struct clk_init_data){
.name = "cam_cc_pll5_out_even",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_pll5.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_pll5.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -444,8 +444,8 @@ static struct clk_alpha_pll_postdiv cam_cc_pll6_out_even = {
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
.clkr.hw.init = &(struct clk_init_data){
.name = "cam_cc_pll6_out_even",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_pll6.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_pll6.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -467,8 +467,8 @@ static struct clk_alpha_pll_postdiv cam_cc_pll6_out_odd = {
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
.clkr.hw.init = &(struct clk_init_data){
.name = "cam_cc_pll6_out_odd",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_pll6.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_pll6.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1227,8 +1227,8 @@ static struct clk_branch cam_cc_bps_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_bps_ahb_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_slow_ahb_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_slow_ahb_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1245,8 +1245,8 @@ static struct clk_branch cam_cc_bps_areg_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_bps_areg_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_fast_ahb_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_fast_ahb_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1263,8 +1263,8 @@ static struct clk_branch cam_cc_bps_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_bps_axi_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_camnoc_axi_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_camnoc_axi_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1281,8 +1281,8 @@ static struct clk_branch cam_cc_bps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_bps_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_bps_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_bps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1299,8 +1299,8 @@ static struct clk_branch cam_cc_camnoc_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_camnoc_axi_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_camnoc_axi_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_camnoc_axi_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1317,8 +1317,8 @@ static struct clk_branch cam_cc_camnoc_dcd_xo_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_camnoc_dcd_xo_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_xo_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_xo_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1335,8 +1335,8 @@ static struct clk_branch cam_cc_cci_0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_cci_0_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_cci_0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cci_0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1353,8 +1353,8 @@ static struct clk_branch cam_cc_cci_1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_cci_1_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_cci_1_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cci_1_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1371,8 +1371,8 @@ static struct clk_branch cam_cc_core_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_core_ahb_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_slow_ahb_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_slow_ahb_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1389,8 +1389,8 @@ static struct clk_branch cam_cc_cpas_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_cpas_ahb_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_slow_ahb_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_slow_ahb_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1407,8 +1407,8 @@ static struct clk_branch cam_cc_csi0phytimer_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_csi0phytimer_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_csi0phytimer_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_csi0phytimer_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1425,8 +1425,8 @@ static struct clk_branch cam_cc_csi1phytimer_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_csi1phytimer_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_csi1phytimer_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_csi1phytimer_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1443,8 +1443,8 @@ static struct clk_branch cam_cc_csi2phytimer_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_csi2phytimer_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_csi2phytimer_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_csi2phytimer_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1461,8 +1461,8 @@ static struct clk_branch cam_cc_csi3phytimer_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_csi3phytimer_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_csi3phytimer_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_csi3phytimer_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1479,8 +1479,8 @@ static struct clk_branch cam_cc_csi4phytimer_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_csi4phytimer_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_csi4phytimer_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_csi4phytimer_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1497,8 +1497,8 @@ static struct clk_branch cam_cc_csiphy0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_csiphy0_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_cphy_rx_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cphy_rx_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1515,8 +1515,8 @@ static struct clk_branch cam_cc_csiphy1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_csiphy1_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_cphy_rx_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cphy_rx_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1533,8 +1533,8 @@ static struct clk_branch cam_cc_csiphy2_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_csiphy2_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_cphy_rx_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cphy_rx_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1551,8 +1551,8 @@ static struct clk_branch cam_cc_csiphy3_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_csiphy3_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_cphy_rx_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cphy_rx_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1569,8 +1569,8 @@ static struct clk_branch cam_cc_csiphy4_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_csiphy4_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_cphy_rx_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cphy_rx_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1587,8 +1587,8 @@ static struct clk_branch cam_cc_gdsc_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_gdsc_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_xo_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_xo_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_IS_CRITICAL | CLK_SET_RATE_PARENT,
@@ -1605,8 +1605,8 @@ static struct clk_branch cam_cc_icp_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_icp_ahb_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_slow_ahb_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_slow_ahb_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1623,8 +1623,8 @@ static struct clk_branch cam_cc_icp_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_icp_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_icp_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_icp_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1641,8 +1641,8 @@ static struct clk_branch cam_cc_ife_0_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_ife_0_axi_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_camnoc_axi_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_camnoc_axi_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1659,8 +1659,8 @@ static struct clk_branch cam_cc_ife_0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_ife_0_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_ife_0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ife_0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1677,8 +1677,8 @@ static struct clk_branch cam_cc_ife_0_cphy_rx_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_ife_0_cphy_rx_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_cphy_rx_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cphy_rx_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1695,8 +1695,8 @@ static struct clk_branch cam_cc_ife_0_csid_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_ife_0_csid_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_ife_0_csid_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ife_0_csid_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1713,8 +1713,8 @@ static struct clk_branch cam_cc_ife_0_dsp_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_ife_0_dsp_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_ife_0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ife_0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1731,8 +1731,8 @@ static struct clk_branch cam_cc_ife_1_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_ife_1_axi_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_camnoc_axi_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_camnoc_axi_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1749,8 +1749,8 @@ static struct clk_branch cam_cc_ife_1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_ife_1_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_ife_1_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ife_1_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1767,8 +1767,8 @@ static struct clk_branch cam_cc_ife_1_cphy_rx_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_ife_1_cphy_rx_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_cphy_rx_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cphy_rx_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1785,8 +1785,8 @@ static struct clk_branch cam_cc_ife_1_csid_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_ife_1_csid_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_ife_1_csid_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ife_1_csid_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1803,8 +1803,8 @@ static struct clk_branch cam_cc_ife_1_dsp_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_ife_1_dsp_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_ife_1_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ife_1_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1821,8 +1821,8 @@ static struct clk_branch cam_cc_ife_2_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_ife_2_axi_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_camnoc_axi_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_camnoc_axi_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1839,8 +1839,8 @@ static struct clk_branch cam_cc_ife_2_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_ife_2_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_ife_2_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ife_2_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1857,8 +1857,8 @@ static struct clk_branch cam_cc_ife_2_cphy_rx_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_ife_2_cphy_rx_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_cphy_rx_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cphy_rx_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1875,8 +1875,8 @@ static struct clk_branch cam_cc_ife_2_csid_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_ife_2_csid_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_ife_2_csid_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ife_2_csid_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1893,8 +1893,8 @@ static struct clk_branch cam_cc_ife_2_dsp_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_ife_2_dsp_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_ife_2_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ife_2_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1911,8 +1911,8 @@ static struct clk_branch cam_cc_ife_lite_0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_ife_lite_0_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_ife_lite_0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ife_lite_0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1929,8 +1929,8 @@ static struct clk_branch cam_cc_ife_lite_0_cphy_rx_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_ife_lite_0_cphy_rx_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_cphy_rx_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cphy_rx_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1947,8 +1947,8 @@ static struct clk_branch cam_cc_ife_lite_0_csid_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_ife_lite_0_csid_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_ife_lite_0_csid_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ife_lite_0_csid_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1965,8 +1965,8 @@ static struct clk_branch cam_cc_ife_lite_1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_ife_lite_1_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_ife_lite_1_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ife_lite_1_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1983,8 +1983,8 @@ static struct clk_branch cam_cc_ife_lite_1_cphy_rx_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_ife_lite_1_cphy_rx_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_cphy_rx_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cphy_rx_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2001,8 +2001,8 @@ static struct clk_branch cam_cc_ife_lite_1_csid_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_ife_lite_1_csid_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_ife_lite_1_csid_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ife_lite_1_csid_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2019,8 +2019,8 @@ static struct clk_branch cam_cc_ipe_0_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_ipe_0_ahb_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_slow_ahb_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_slow_ahb_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2037,8 +2037,8 @@ static struct clk_branch cam_cc_ipe_0_areg_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_ipe_0_areg_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_fast_ahb_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_fast_ahb_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2055,8 +2055,8 @@ static struct clk_branch cam_cc_ipe_0_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_ipe_0_axi_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_camnoc_axi_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_camnoc_axi_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2073,8 +2073,8 @@ static struct clk_branch cam_cc_ipe_0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_ipe_0_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_ipe_0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ipe_0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2091,8 +2091,8 @@ static struct clk_branch cam_cc_jpeg_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_jpeg_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_jpeg_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_jpeg_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2109,8 +2109,8 @@ static struct clk_branch cam_cc_lrme_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_lrme_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_lrme_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_lrme_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2127,8 +2127,8 @@ static struct clk_branch cam_cc_mclk0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_mclk0_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_mclk0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_mclk0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2145,8 +2145,8 @@ static struct clk_branch cam_cc_mclk1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_mclk1_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_mclk1_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_mclk1_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2163,8 +2163,8 @@ static struct clk_branch cam_cc_mclk2_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_mclk2_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_mclk2_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_mclk2_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2181,8 +2181,8 @@ static struct clk_branch cam_cc_mclk3_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_mclk3_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_mclk3_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_mclk3_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2199,8 +2199,8 @@ static struct clk_branch cam_cc_mclk4_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_mclk4_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_mclk4_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_mclk4_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2217,8 +2217,8 @@ static struct clk_branch cam_cc_mclk5_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_mclk5_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_mclk5_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_mclk5_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2235,8 +2235,8 @@ static struct clk_branch cam_cc_sleep_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "cam_cc_sleep_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &cam_cc_sleep_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_sleep_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
diff --git a/drivers/clk/qcom/camcc-sm6350.c b/drivers/clk/qcom/camcc-sm6350.c
new file mode 100644
index 000000000000..acba9f99d960
--- /dev/null
+++ b/drivers/clk/qcom/camcc-sm6350.c
@@ -0,0 +1,1906 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022, Linaro Limited
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,sm6350-camcc.h>
+
+#include "clk-alpha-pll.h"
+#include "clk-branch.h"
+#include "clk-rcg.h"
+#include "common.h"
+#include "gdsc.h"
+
+enum {
+ DT_BI_TCXO,
+};
+
+enum {
+ P_BI_TCXO,
+ P_CAMCC_PLL0_OUT_EVEN,
+ P_CAMCC_PLL0_OUT_MAIN,
+ P_CAMCC_PLL1_OUT_EVEN,
+ P_CAMCC_PLL1_OUT_MAIN,
+ P_CAMCC_PLL2_OUT_EARLY,
+ P_CAMCC_PLL2_OUT_MAIN,
+ P_CAMCC_PLL3_OUT_MAIN,
+};
+
+static struct pll_vco fabia_vco[] = {
+ { 249600000, 2000000000, 0 },
+};
+
+/* 600MHz configuration */
+static const struct alpha_pll_config camcc_pll0_config = {
+ .l = 0x1f,
+ .alpha = 0x4000,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00002067,
+ .test_ctl_val = 0x40000000,
+ .test_ctl_hi_val = 0x00000002,
+ .user_ctl_val = 0x00000101,
+ .user_ctl_hi_val = 0x00004805,
+};
+
+static struct clk_alpha_pll camcc_pll0 = {
+ .offset = 0x0,
+ .vco_table = fabia_vco,
+ .num_vco = ARRAY_SIZE(fabia_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_pll0",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fabia_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_camcc_pll0_out_even[] = {
+ { 0x1, 2 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv camcc_pll0_out_even = {
+ .offset = 0x0,
+ .post_div_shift = 8,
+ .post_div_table = post_div_table_camcc_pll0_out_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_camcc_pll0_out_even),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_pll0_out_even",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_pll0.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_fabia_ops,
+ },
+};
+
+/* 808MHz configuration */
+static const struct alpha_pll_config camcc_pll1_config = {
+ .l = 0x2a,
+ .alpha = 0x1555,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00002067,
+ .test_ctl_val = 0x40000000,
+ .test_ctl_hi_val = 0x00000000,
+ .user_ctl_val = 0x00000101,
+ .user_ctl_hi_val = 0x00004805,
+};
+
+static struct clk_alpha_pll camcc_pll1 = {
+ .offset = 0x1000,
+ .vco_table = fabia_vco,
+ .num_vco = ARRAY_SIZE(fabia_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_pll1",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fabia_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_camcc_pll1_out_even[] = {
+ { 0x1, 2 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv camcc_pll1_out_even = {
+ .offset = 0x1000,
+ .post_div_shift = 8,
+ .post_div_table = post_div_table_camcc_pll1_out_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_camcc_pll1_out_even),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_pll1_out_even",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_pll1.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_fabia_ops,
+ },
+};
+
+/* 1920MHz configuration */
+static const struct alpha_pll_config camcc_pll2_config = {
+ .l = 0x64,
+ .alpha = 0x0,
+ .post_div_val = 0x3 << 8,
+ .post_div_mask = 0x3 << 8,
+ .aux_output_mask = BIT(1),
+ .main_output_mask = BIT(0),
+ .early_output_mask = BIT(3),
+ .config_ctl_val = 0x20000800,
+ .config_ctl_hi_val = 0x400003d2,
+ .test_ctl_val = 0x04000400,
+ .test_ctl_hi_val = 0x00004000,
+};
+
+static struct clk_alpha_pll camcc_pll2 = {
+ .offset = 0x2000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_AGERA],
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_pll2",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_agera_ops,
+ },
+ },
+};
+
+static struct clk_fixed_factor camcc_pll2_out_early = {
+ .mult = 1,
+ .div = 2,
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_pll2_out_early",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_pll2.clkr.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
+static const struct clk_div_table post_div_table_camcc_pll2_out_main[] = {
+ { 0x1, 2 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv camcc_pll2_out_main = {
+ .offset = 0x2000,
+ .post_div_shift = 8,
+ .post_div_table = post_div_table_camcc_pll2_out_main,
+ .num_post_div = ARRAY_SIZE(post_div_table_camcc_pll2_out_main),
+ .width = 2,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_AGERA],
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_pll2_out_main",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_pll2.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_ops,
+ },
+};
+
+/* 384MHz configuration */
+static const struct alpha_pll_config camcc_pll3_config = {
+ .l = 0x14,
+ .alpha = 0x0,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00002067,
+ .test_ctl_val = 0x40000000,
+ .test_ctl_hi_val = 0x00000002,
+ .user_ctl_val = 0x00000001,
+ .user_ctl_hi_val = 0x00014805,
+};
+
+static struct clk_alpha_pll camcc_pll3 = {
+ .offset = 0x3000,
+ .vco_table = fabia_vco,
+ .num_vco = ARRAY_SIZE(fabia_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_pll3",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fabia_ops,
+ },
+ },
+};
+
+static const struct parent_map camcc_parent_map_0[] = {
+ { P_BI_TCXO, 0 },
+ { P_CAMCC_PLL0_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data camcc_parent_data_0[] = {
+ { .fw_name = "bi_tcxo" },
+ { .hw = &camcc_pll0_out_even.clkr.hw },
+};
+
+static const struct parent_map camcc_parent_map_1[] = {
+ { P_BI_TCXO, 0 },
+ { P_CAMCC_PLL0_OUT_MAIN, 1 },
+ { P_CAMCC_PLL1_OUT_EVEN, 3 },
+ { P_CAMCC_PLL2_OUT_MAIN, 4 },
+};
+
+static const struct clk_parent_data camcc_parent_data_1[] = {
+ { .fw_name = "bi_tcxo" },
+ { .hw = &camcc_pll0.clkr.hw },
+ { .hw = &camcc_pll1_out_even.clkr.hw },
+ { .hw = &camcc_pll2_out_main.clkr.hw },
+};
+
+static const struct parent_map camcc_parent_map_2[] = {
+ { P_BI_TCXO, 0 },
+ { P_CAMCC_PLL0_OUT_MAIN, 1 },
+ { P_CAMCC_PLL3_OUT_MAIN, 5 },
+};
+
+static const struct clk_parent_data camcc_parent_data_2[] = {
+ { .fw_name = "bi_tcxo" },
+ { .hw = &camcc_pll0.clkr.hw },
+ { .hw = &camcc_pll3.clkr.hw },
+};
+
+static const struct parent_map camcc_parent_map_3[] = {
+ { P_BI_TCXO, 0 },
+ { P_CAMCC_PLL2_OUT_EARLY, 3 },
+};
+
+static const struct clk_parent_data camcc_parent_data_3[] = {
+ { .fw_name = "bi_tcxo" },
+ { .hw = &camcc_pll2_out_early.hw },
+};
+
+static const struct parent_map camcc_parent_map_4[] = {
+ { P_BI_TCXO, 0 },
+ { P_CAMCC_PLL0_OUT_MAIN, 1 },
+ { P_CAMCC_PLL1_OUT_EVEN, 3 },
+};
+
+static const struct clk_parent_data camcc_parent_data_4[] = {
+ { .fw_name = "bi_tcxo" },
+ { .hw = &camcc_pll0.clkr.hw },
+ { .hw = &camcc_pll1_out_even.clkr.hw },
+};
+
+static const struct parent_map camcc_parent_map_5[] = {
+ { P_BI_TCXO, 0 },
+ { P_CAMCC_PLL0_OUT_MAIN, 1 },
+ { P_CAMCC_PLL1_OUT_EVEN, 3 },
+ { P_CAMCC_PLL3_OUT_MAIN, 5 },
+};
+
+static const struct clk_parent_data camcc_parent_data_5[] = {
+ { .fw_name = "bi_tcxo" },
+ { .hw = &camcc_pll0.clkr.hw },
+ { .hw = &camcc_pll1_out_even.clkr.hw },
+ { .hw = &camcc_pll3.clkr.hw },
+};
+
+static const struct parent_map camcc_parent_map_6[] = {
+ { P_BI_TCXO, 0 },
+ { P_CAMCC_PLL0_OUT_MAIN, 1 },
+ { P_CAMCC_PLL2_OUT_MAIN, 4 },
+};
+
+static const struct clk_parent_data camcc_parent_data_6[] = {
+ { .fw_name = "bi_tcxo" },
+ { .hw = &camcc_pll0.clkr.hw },
+ { .hw = &camcc_pll2_out_main.clkr.hw },
+};
+
+static const struct parent_map camcc_parent_map_7[] = {
+ { P_BI_TCXO, 0 },
+ { P_CAMCC_PLL0_OUT_MAIN, 1 },
+ { P_CAMCC_PLL1_OUT_MAIN, 2 },
+ { P_CAMCC_PLL2_OUT_MAIN, 4 },
+};
+
+static const struct clk_parent_data camcc_parent_data_7[] = {
+ { .fw_name = "bi_tcxo" },
+ { .hw = &camcc_pll0.clkr.hw },
+ { .hw = &camcc_pll1.clkr.hw },
+ { .hw = &camcc_pll2_out_main.clkr.hw },
+};
+
+static const struct parent_map camcc_parent_map_8[] = {
+ { P_BI_TCXO, 0 },
+ { P_CAMCC_PLL0_OUT_MAIN, 1 },
+ { P_CAMCC_PLL1_OUT_MAIN, 2 },
+};
+
+static const struct clk_parent_data camcc_parent_data_8[] = {
+ { .fw_name = "bi_tcxo" },
+ { .hw = &camcc_pll0.clkr.hw },
+ { .hw = &camcc_pll1.clkr.hw },
+};
+
+static const struct parent_map camcc_parent_map_9[] = {
+ { P_BI_TCXO, 0 },
+ { P_CAMCC_PLL2_OUT_MAIN, 4 },
+};
+
+static const struct clk_parent_data camcc_parent_data_9[] = {
+ { .fw_name = "bi_tcxo" },
+ { .hw = &camcc_pll2_out_main.clkr.hw },
+};
+
+static const struct freq_tbl ftbl_camcc_bps_clk_src[] = {
+ F(200000000, P_CAMCC_PLL0_OUT_MAIN, 3, 0, 0),
+ F(320000000, P_CAMCC_PLL2_OUT_MAIN, 1.5, 0, 0),
+ F(404000000, P_CAMCC_PLL1_OUT_EVEN, 1, 0, 0),
+ F(480000000, P_CAMCC_PLL2_OUT_MAIN, 1, 0, 0),
+ F(600000000, P_CAMCC_PLL0_OUT_MAIN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 camcc_bps_clk_src = {
+ .cmd_rcgr = 0x6010,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_1,
+ .freq_tbl = ftbl_camcc_bps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_bps_clk_src",
+ .parent_data = camcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_1),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_camcc_cci_0_clk_src[] = {
+ F(37500000, P_CAMCC_PLL0_OUT_EVEN, 8, 0, 0),
+ F(50000000, P_CAMCC_PLL0_OUT_EVEN, 6, 0, 0),
+ F(100000000, P_CAMCC_PLL0_OUT_EVEN, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 camcc_cci_0_clk_src = {
+ .cmd_rcgr = 0xf004,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_0,
+ .freq_tbl = ftbl_camcc_cci_0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_cci_0_clk_src",
+ .parent_data = camcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 camcc_cci_1_clk_src = {
+ .cmd_rcgr = 0x10004,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_0,
+ .freq_tbl = ftbl_camcc_cci_0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_cci_1_clk_src",
+ .parent_data = camcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_camcc_cphy_rx_clk_src[] = {
+ F(150000000, P_CAMCC_PLL0_OUT_MAIN, 4, 0, 0),
+ F(300000000, P_CAMCC_PLL0_OUT_MAIN, 2, 0, 0),
+ F(384000000, P_CAMCC_PLL3_OUT_MAIN, 1, 0, 0),
+ F(400000000, P_CAMCC_PLL0_OUT_MAIN, 1.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 camcc_cphy_rx_clk_src = {
+ .cmd_rcgr = 0x9064,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_2,
+ .freq_tbl = ftbl_camcc_cphy_rx_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_cphy_rx_clk_src",
+ .parent_data = camcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_2),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_camcc_csi0phytimer_clk_src[] = {
+ F(300000000, P_CAMCC_PLL0_OUT_EVEN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 camcc_csi0phytimer_clk_src = {
+ .cmd_rcgr = 0x5004,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_0,
+ .freq_tbl = ftbl_camcc_csi0phytimer_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_csi0phytimer_clk_src",
+ .parent_data = camcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 camcc_csi1phytimer_clk_src = {
+ .cmd_rcgr = 0x5028,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_0,
+ .freq_tbl = ftbl_camcc_csi0phytimer_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_csi1phytimer_clk_src",
+ .parent_data = camcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 camcc_csi2phytimer_clk_src = {
+ .cmd_rcgr = 0x504c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_0,
+ .freq_tbl = ftbl_camcc_csi0phytimer_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_csi2phytimer_clk_src",
+ .parent_data = camcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 camcc_csi3phytimer_clk_src = {
+ .cmd_rcgr = 0x5070,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_0,
+ .freq_tbl = ftbl_camcc_csi0phytimer_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_csi3phytimer_clk_src",
+ .parent_data = camcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_camcc_fast_ahb_clk_src[] = {
+ F(100000000, P_CAMCC_PLL0_OUT_MAIN, 6, 0, 0),
+ F(200000000, P_CAMCC_PLL0_OUT_MAIN, 3, 0, 0),
+ F(300000000, P_CAMCC_PLL0_OUT_MAIN, 2, 0, 0),
+ F(404000000, P_CAMCC_PLL1_OUT_EVEN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 camcc_fast_ahb_clk_src = {
+ .cmd_rcgr = 0x603c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_4,
+ .freq_tbl = ftbl_camcc_fast_ahb_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_fast_ahb_clk_src",
+ .parent_data = camcc_parent_data_4,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_4),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_camcc_icp_clk_src[] = {
+ F(240000000, P_CAMCC_PLL0_OUT_MAIN, 2.5, 0, 0),
+ F(384000000, P_CAMCC_PLL3_OUT_MAIN, 1, 0, 0),
+ F(404000000, P_CAMCC_PLL1_OUT_EVEN, 1, 0, 0),
+ F(600000000, P_CAMCC_PLL0_OUT_MAIN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 camcc_icp_clk_src = {
+ .cmd_rcgr = 0xe014,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_5,
+ .freq_tbl = ftbl_camcc_icp_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_icp_clk_src",
+ .parent_data = camcc_parent_data_5,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_5),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_camcc_ife_0_clk_src[] = {
+ F(240000000, P_CAMCC_PLL0_OUT_MAIN, 2.5, 0, 0),
+ F(320000000, P_CAMCC_PLL2_OUT_MAIN, 1.5, 0, 0),
+ F(404000000, P_CAMCC_PLL1_OUT_EVEN, 1, 0, 0),
+ F(480000000, P_CAMCC_PLL2_OUT_MAIN, 1, 0, 0),
+ F(600000000, P_CAMCC_PLL0_OUT_MAIN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 camcc_ife_0_clk_src = {
+ .cmd_rcgr = 0x9010,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_1,
+ .freq_tbl = ftbl_camcc_ife_0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_0_clk_src",
+ .parent_data = camcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 camcc_ife_0_csid_clk_src = {
+ .cmd_rcgr = 0x903c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_2,
+ .freq_tbl = ftbl_camcc_cphy_rx_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_0_csid_clk_src",
+ .parent_data = camcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_2),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 camcc_ife_1_clk_src = {
+ .cmd_rcgr = 0xa010,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_1,
+ .freq_tbl = ftbl_camcc_ife_0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_1_clk_src",
+ .parent_data = camcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 camcc_ife_1_csid_clk_src = {
+ .cmd_rcgr = 0xa034,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_2,
+ .freq_tbl = ftbl_camcc_cphy_rx_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_1_csid_clk_src",
+ .parent_data = camcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_2),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 camcc_ife_2_clk_src = {
+ .cmd_rcgr = 0xb00c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_1,
+ .freq_tbl = ftbl_camcc_ife_0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_2_clk_src",
+ .parent_data = camcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_1),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 camcc_ife_2_csid_clk_src = {
+ .cmd_rcgr = 0xb030,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_2,
+ .freq_tbl = ftbl_camcc_cphy_rx_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_2_csid_clk_src",
+ .parent_data = camcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_2),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_camcc_ife_lite_clk_src[] = {
+ F(320000000, P_CAMCC_PLL2_OUT_MAIN, 1.5, 0, 0),
+ F(400000000, P_CAMCC_PLL0_OUT_MAIN, 1.5, 0, 0),
+ F(480000000, P_CAMCC_PLL2_OUT_MAIN, 1, 0, 0),
+ F(600000000, P_CAMCC_PLL0_OUT_MAIN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 camcc_ife_lite_clk_src = {
+ .cmd_rcgr = 0xc004,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_6,
+ .freq_tbl = ftbl_camcc_ife_lite_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_lite_clk_src",
+ .parent_data = camcc_parent_data_6,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_6),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 camcc_ife_lite_csid_clk_src = {
+ .cmd_rcgr = 0xc024,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_2,
+ .freq_tbl = ftbl_camcc_cphy_rx_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_lite_csid_clk_src",
+ .parent_data = camcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_2),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_camcc_ipe_0_clk_src[] = {
+ F(240000000, P_CAMCC_PLL2_OUT_MAIN, 2, 0, 0),
+ F(320000000, P_CAMCC_PLL2_OUT_MAIN, 1.5, 0, 0),
+ F(404000000, P_CAMCC_PLL1_OUT_MAIN, 2, 0, 0),
+ F(538666667, P_CAMCC_PLL1_OUT_MAIN, 1.5, 0, 0),
+ F(600000000, P_CAMCC_PLL0_OUT_MAIN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 camcc_ipe_0_clk_src = {
+ .cmd_rcgr = 0x7010,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_7,
+ .freq_tbl = ftbl_camcc_ipe_0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_ipe_0_clk_src",
+ .parent_data = camcc_parent_data_7,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_7),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_camcc_jpeg_clk_src[] = {
+ F(66666667, P_CAMCC_PLL0_OUT_MAIN, 9, 0, 0),
+ F(133333333, P_CAMCC_PLL0_OUT_MAIN, 4.5, 0, 0),
+ F(200000000, P_CAMCC_PLL0_OUT_MAIN, 3, 0, 0),
+ F(404000000, P_CAMCC_PLL1_OUT_EVEN, 1, 0, 0),
+ F(480000000, P_CAMCC_PLL2_OUT_MAIN, 1, 0, 0),
+ F(600000000, P_CAMCC_PLL0_OUT_MAIN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 camcc_jpeg_clk_src = {
+ .cmd_rcgr = 0xd004,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_1,
+ .freq_tbl = ftbl_camcc_jpeg_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_jpeg_clk_src",
+ .parent_data = camcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_1),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_camcc_lrme_clk_src[] = {
+ F(200000000, P_CAMCC_PLL0_OUT_MAIN, 3, 0, 0),
+ F(269333333, P_CAMCC_PLL1_OUT_MAIN, 3, 0, 0),
+ F(323200000, P_CAMCC_PLL1_OUT_MAIN, 2.5, 0, 0),
+ F(404000000, P_CAMCC_PLL1_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 camcc_lrme_clk_src = {
+ .cmd_rcgr = 0x11004,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_8,
+ .freq_tbl = ftbl_camcc_lrme_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_lrme_clk_src",
+ .parent_data = camcc_parent_data_8,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_8),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_camcc_mclk0_clk_src[] = {
+ F(19200000, P_CAMCC_PLL2_OUT_EARLY, 1, 1, 50),
+ F(24000000, P_CAMCC_PLL2_OUT_EARLY, 10, 1, 4),
+ F(64000000, P_CAMCC_PLL2_OUT_EARLY, 15, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 camcc_mclk0_clk_src = {
+ .cmd_rcgr = 0x4004,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_3,
+ .freq_tbl = ftbl_camcc_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_mclk0_clk_src",
+ .parent_data = camcc_parent_data_3,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_3),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 camcc_mclk1_clk_src = {
+ .cmd_rcgr = 0x4024,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_3,
+ .freq_tbl = ftbl_camcc_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_mclk1_clk_src",
+ .parent_data = camcc_parent_data_3,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_3),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 camcc_mclk2_clk_src = {
+ .cmd_rcgr = 0x4044,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_3,
+ .freq_tbl = ftbl_camcc_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_mclk2_clk_src",
+ .parent_data = camcc_parent_data_3,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_3),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 camcc_mclk3_clk_src = {
+ .cmd_rcgr = 0x4064,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_3,
+ .freq_tbl = ftbl_camcc_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_mclk3_clk_src",
+ .parent_data = camcc_parent_data_3,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_3),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 camcc_mclk4_clk_src = {
+ .cmd_rcgr = 0x4084,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_3,
+ .freq_tbl = ftbl_camcc_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_mclk4_clk_src",
+ .parent_data = camcc_parent_data_3,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_3),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_camcc_slow_ahb_clk_src[] = {
+ F(80000000, P_CAMCC_PLL2_OUT_MAIN, 6, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 camcc_slow_ahb_clk_src = {
+ .cmd_rcgr = 0x6058,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_9,
+ .freq_tbl = ftbl_camcc_slow_ahb_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_slow_ahb_clk_src",
+ .parent_data = camcc_parent_data_9,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_9),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_branch camcc_bps_ahb_clk = {
+ .halt_reg = 0x6070,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x6070,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_bps_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_slow_ahb_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_bps_areg_clk = {
+ .halt_reg = 0x6054,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x6054,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_bps_areg_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_fast_ahb_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_bps_axi_clk = {
+ .halt_reg = 0x6038,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x6038,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_bps_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_bps_clk = {
+ .halt_reg = 0x6028,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x6028,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_bps_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_bps_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_camnoc_axi_clk = {
+ .halt_reg = 0x13004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x13004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_camnoc_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_cci_0_clk = {
+ .halt_reg = 0xf01c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xf01c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_cci_0_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_cci_0_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_cci_1_clk = {
+ .halt_reg = 0x1001c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1001c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_cci_1_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_cci_1_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_core_ahb_clk = {
+ .halt_reg = 0x14010,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x14010,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_core_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_slow_ahb_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_cpas_ahb_clk = {
+ .halt_reg = 0x12004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x12004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_cpas_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_slow_ahb_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_csi0phytimer_clk = {
+ .halt_reg = 0x501c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x501c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_csi0phytimer_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_csi0phytimer_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_csi1phytimer_clk = {
+ .halt_reg = 0x5040,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5040,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_csi1phytimer_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_csi1phytimer_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_csi2phytimer_clk = {
+ .halt_reg = 0x5064,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5064,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_csi2phytimer_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_csi2phytimer_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_csi3phytimer_clk = {
+ .halt_reg = 0x5088,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5088,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_csi3phytimer_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_csi3phytimer_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_csiphy0_clk = {
+ .halt_reg = 0x5020,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5020,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_csiphy0_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_cphy_rx_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_csiphy1_clk = {
+ .halt_reg = 0x5044,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5044,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_csiphy1_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_cphy_rx_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_csiphy2_clk = {
+ .halt_reg = 0x5068,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5068,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_csiphy2_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_cphy_rx_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_csiphy3_clk = {
+ .halt_reg = 0x508c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x508c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_csiphy3_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_cphy_rx_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_icp_clk = {
+ .halt_reg = 0xe02c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xe02c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_icp_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_icp_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_icp_ts_clk = {
+ .halt_reg = 0xe00c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xe00c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_icp_ts_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_0_axi_clk = {
+ .halt_reg = 0x9080,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x9080,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_0_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_0_clk = {
+ .halt_reg = 0x9028,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x9028,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_0_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_ife_0_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_0_cphy_rx_clk = {
+ .halt_reg = 0x907c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x907c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_0_cphy_rx_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_cphy_rx_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_0_csid_clk = {
+ .halt_reg = 0x9054,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x9054,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_0_csid_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_ife_0_csid_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_0_dsp_clk = {
+ .halt_reg = 0x9038,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x9038,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_0_dsp_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_ife_0_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_1_axi_clk = {
+ .halt_reg = 0xa058,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa058,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_1_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_1_clk = {
+ .halt_reg = 0xa028,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa028,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_1_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_ife_1_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_1_cphy_rx_clk = {
+ .halt_reg = 0xa054,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa054,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_1_cphy_rx_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_cphy_rx_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_1_csid_clk = {
+ .halt_reg = 0xa04c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa04c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_1_csid_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_ife_1_csid_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_1_dsp_clk = {
+ .halt_reg = 0xa030,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa030,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_1_dsp_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_ife_1_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_2_axi_clk = {
+ .halt_reg = 0xb054,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb054,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_2_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_2_clk = {
+ .halt_reg = 0xb024,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb024,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_2_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_ife_2_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_2_cphy_rx_clk = {
+ .halt_reg = 0xb050,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb050,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_2_cphy_rx_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_cphy_rx_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_2_csid_clk = {
+ .halt_reg = 0xb048,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb048,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_2_csid_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_ife_2_csid_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_2_dsp_clk = {
+ .halt_reg = 0xb02c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb02c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_2_dsp_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_ife_2_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_lite_clk = {
+ .halt_reg = 0xc01c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc01c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_lite_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_ife_lite_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_lite_cphy_rx_clk = {
+ .halt_reg = 0xc044,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc044,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_lite_cphy_rx_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_cphy_rx_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_lite_csid_clk = {
+ .halt_reg = 0xc03c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc03c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_lite_csid_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_ife_lite_csid_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ipe_0_ahb_clk = {
+ .halt_reg = 0x7040,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x7040,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ipe_0_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_slow_ahb_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ipe_0_areg_clk = {
+ .halt_reg = 0x703c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x703c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ipe_0_areg_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_fast_ahb_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ipe_0_axi_clk = {
+ .halt_reg = 0x7038,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x7038,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ipe_0_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ipe_0_clk = {
+ .halt_reg = 0x7028,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x7028,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ipe_0_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_ipe_0_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_jpeg_clk = {
+ .halt_reg = 0xd01c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd01c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_jpeg_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_jpeg_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_lrme_clk = {
+ .halt_reg = 0x1101c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1101c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_lrme_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_lrme_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_mclk0_clk = {
+ .halt_reg = 0x401c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x401c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_mclk0_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_mclk0_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_mclk1_clk = {
+ .halt_reg = 0x403c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x403c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_mclk1_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_mclk1_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_mclk2_clk = {
+ .halt_reg = 0x405c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x405c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_mclk2_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_mclk2_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_mclk3_clk = {
+ .halt_reg = 0x407c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x407c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_mclk3_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_mclk3_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_mclk4_clk = {
+ .halt_reg = 0x409c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x409c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_mclk4_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_mclk4_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_soc_ahb_clk = {
+ .halt_reg = 0x1400c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1400c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_soc_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_sys_tmr_clk = {
+ .halt_reg = 0xe034,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xe034,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_sys_tmr_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct gdsc bps_gdsc = {
+ .gdscr = 0x6004,
+ .pd = {
+ .name = "bps_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = VOTABLE,
+};
+
+static struct gdsc ipe_0_gdsc = {
+ .gdscr = 0x7004,
+ .pd = {
+ .name = "ipe_0_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = VOTABLE,
+};
+
+static struct gdsc ife_0_gdsc = {
+ .gdscr = 0x9004,
+ .pd = {
+ .name = "ife_0_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc ife_1_gdsc = {
+ .gdscr = 0xa004,
+ .pd = {
+ .name = "ife_1_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc ife_2_gdsc = {
+ .gdscr = 0xb004,
+ .pd = {
+ .name = "ife_2_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc titan_top_gdsc = {
+ .gdscr = 0x14004,
+ .pd = {
+ .name = "titan_top_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct clk_hw *camcc_sm6350_hws[] = {
+ [CAMCC_PLL2_OUT_EARLY] = &camcc_pll2_out_early.hw,
+};
+
+static struct clk_regmap *camcc_sm6350_clocks[] = {
+ [CAMCC_BPS_AHB_CLK] = &camcc_bps_ahb_clk.clkr,
+ [CAMCC_BPS_AREG_CLK] = &camcc_bps_areg_clk.clkr,
+ [CAMCC_BPS_AXI_CLK] = &camcc_bps_axi_clk.clkr,
+ [CAMCC_BPS_CLK] = &camcc_bps_clk.clkr,
+ [CAMCC_BPS_CLK_SRC] = &camcc_bps_clk_src.clkr,
+ [CAMCC_CAMNOC_AXI_CLK] = &camcc_camnoc_axi_clk.clkr,
+ [CAMCC_CCI_0_CLK] = &camcc_cci_0_clk.clkr,
+ [CAMCC_CCI_0_CLK_SRC] = &camcc_cci_0_clk_src.clkr,
+ [CAMCC_CCI_1_CLK] = &camcc_cci_1_clk.clkr,
+ [CAMCC_CCI_1_CLK_SRC] = &camcc_cci_1_clk_src.clkr,
+ [CAMCC_CORE_AHB_CLK] = &camcc_core_ahb_clk.clkr,
+ [CAMCC_CPAS_AHB_CLK] = &camcc_cpas_ahb_clk.clkr,
+ [CAMCC_CPHY_RX_CLK_SRC] = &camcc_cphy_rx_clk_src.clkr,
+ [CAMCC_CSI0PHYTIMER_CLK] = &camcc_csi0phytimer_clk.clkr,
+ [CAMCC_CSI0PHYTIMER_CLK_SRC] = &camcc_csi0phytimer_clk_src.clkr,
+ [CAMCC_CSI1PHYTIMER_CLK] = &camcc_csi1phytimer_clk.clkr,
+ [CAMCC_CSI1PHYTIMER_CLK_SRC] = &camcc_csi1phytimer_clk_src.clkr,
+ [CAMCC_CSI2PHYTIMER_CLK] = &camcc_csi2phytimer_clk.clkr,
+ [CAMCC_CSI2PHYTIMER_CLK_SRC] = &camcc_csi2phytimer_clk_src.clkr,
+ [CAMCC_CSI3PHYTIMER_CLK] = &camcc_csi3phytimer_clk.clkr,
+ [CAMCC_CSI3PHYTIMER_CLK_SRC] = &camcc_csi3phytimer_clk_src.clkr,
+ [CAMCC_CSIPHY0_CLK] = &camcc_csiphy0_clk.clkr,
+ [CAMCC_CSIPHY1_CLK] = &camcc_csiphy1_clk.clkr,
+ [CAMCC_CSIPHY2_CLK] = &camcc_csiphy2_clk.clkr,
+ [CAMCC_CSIPHY3_CLK] = &camcc_csiphy3_clk.clkr,
+ [CAMCC_FAST_AHB_CLK_SRC] = &camcc_fast_ahb_clk_src.clkr,
+ [CAMCC_ICP_CLK] = &camcc_icp_clk.clkr,
+ [CAMCC_ICP_CLK_SRC] = &camcc_icp_clk_src.clkr,
+ [CAMCC_ICP_TS_CLK] = &camcc_icp_ts_clk.clkr,
+ [CAMCC_IFE_0_AXI_CLK] = &camcc_ife_0_axi_clk.clkr,
+ [CAMCC_IFE_0_CLK] = &camcc_ife_0_clk.clkr,
+ [CAMCC_IFE_0_CLK_SRC] = &camcc_ife_0_clk_src.clkr,
+ [CAMCC_IFE_0_CPHY_RX_CLK] = &camcc_ife_0_cphy_rx_clk.clkr,
+ [CAMCC_IFE_0_CSID_CLK] = &camcc_ife_0_csid_clk.clkr,
+ [CAMCC_IFE_0_CSID_CLK_SRC] = &camcc_ife_0_csid_clk_src.clkr,
+ [CAMCC_IFE_0_DSP_CLK] = &camcc_ife_0_dsp_clk.clkr,
+ [CAMCC_IFE_1_AXI_CLK] = &camcc_ife_1_axi_clk.clkr,
+ [CAMCC_IFE_1_CLK] = &camcc_ife_1_clk.clkr,
+ [CAMCC_IFE_1_CLK_SRC] = &camcc_ife_1_clk_src.clkr,
+ [CAMCC_IFE_1_CPHY_RX_CLK] = &camcc_ife_1_cphy_rx_clk.clkr,
+ [CAMCC_IFE_1_CSID_CLK] = &camcc_ife_1_csid_clk.clkr,
+ [CAMCC_IFE_1_CSID_CLK_SRC] = &camcc_ife_1_csid_clk_src.clkr,
+ [CAMCC_IFE_1_DSP_CLK] = &camcc_ife_1_dsp_clk.clkr,
+ [CAMCC_IFE_2_AXI_CLK] = &camcc_ife_2_axi_clk.clkr,
+ [CAMCC_IFE_2_CLK] = &camcc_ife_2_clk.clkr,
+ [CAMCC_IFE_2_CLK_SRC] = &camcc_ife_2_clk_src.clkr,
+ [CAMCC_IFE_2_CPHY_RX_CLK] = &camcc_ife_2_cphy_rx_clk.clkr,
+ [CAMCC_IFE_2_CSID_CLK] = &camcc_ife_2_csid_clk.clkr,
+ [CAMCC_IFE_2_CSID_CLK_SRC] = &camcc_ife_2_csid_clk_src.clkr,
+ [CAMCC_IFE_2_DSP_CLK] = &camcc_ife_2_dsp_clk.clkr,
+ [CAMCC_IFE_LITE_CLK] = &camcc_ife_lite_clk.clkr,
+ [CAMCC_IFE_LITE_CLK_SRC] = &camcc_ife_lite_clk_src.clkr,
+ [CAMCC_IFE_LITE_CPHY_RX_CLK] = &camcc_ife_lite_cphy_rx_clk.clkr,
+ [CAMCC_IFE_LITE_CSID_CLK] = &camcc_ife_lite_csid_clk.clkr,
+ [CAMCC_IFE_LITE_CSID_CLK_SRC] = &camcc_ife_lite_csid_clk_src.clkr,
+ [CAMCC_IPE_0_AHB_CLK] = &camcc_ipe_0_ahb_clk.clkr,
+ [CAMCC_IPE_0_AREG_CLK] = &camcc_ipe_0_areg_clk.clkr,
+ [CAMCC_IPE_0_AXI_CLK] = &camcc_ipe_0_axi_clk.clkr,
+ [CAMCC_IPE_0_CLK] = &camcc_ipe_0_clk.clkr,
+ [CAMCC_IPE_0_CLK_SRC] = &camcc_ipe_0_clk_src.clkr,
+ [CAMCC_JPEG_CLK] = &camcc_jpeg_clk.clkr,
+ [CAMCC_JPEG_CLK_SRC] = &camcc_jpeg_clk_src.clkr,
+ [CAMCC_LRME_CLK] = &camcc_lrme_clk.clkr,
+ [CAMCC_LRME_CLK_SRC] = &camcc_lrme_clk_src.clkr,
+ [CAMCC_MCLK0_CLK] = &camcc_mclk0_clk.clkr,
+ [CAMCC_MCLK0_CLK_SRC] = &camcc_mclk0_clk_src.clkr,
+ [CAMCC_MCLK1_CLK] = &camcc_mclk1_clk.clkr,
+ [CAMCC_MCLK1_CLK_SRC] = &camcc_mclk1_clk_src.clkr,
+ [CAMCC_MCLK2_CLK] = &camcc_mclk2_clk.clkr,
+ [CAMCC_MCLK2_CLK_SRC] = &camcc_mclk2_clk_src.clkr,
+ [CAMCC_MCLK3_CLK] = &camcc_mclk3_clk.clkr,
+ [CAMCC_MCLK3_CLK_SRC] = &camcc_mclk3_clk_src.clkr,
+ [CAMCC_MCLK4_CLK] = &camcc_mclk4_clk.clkr,
+ [CAMCC_MCLK4_CLK_SRC] = &camcc_mclk4_clk_src.clkr,
+ [CAMCC_PLL0] = &camcc_pll0.clkr,
+ [CAMCC_PLL0_OUT_EVEN] = &camcc_pll0_out_even.clkr,
+ [CAMCC_PLL1] = &camcc_pll1.clkr,
+ [CAMCC_PLL1_OUT_EVEN] = &camcc_pll1_out_even.clkr,
+ [CAMCC_PLL2] = &camcc_pll2.clkr,
+ [CAMCC_PLL2_OUT_MAIN] = &camcc_pll2_out_main.clkr,
+ [CAMCC_PLL3] = &camcc_pll3.clkr,
+ [CAMCC_SLOW_AHB_CLK_SRC] = &camcc_slow_ahb_clk_src.clkr,
+ [CAMCC_SOC_AHB_CLK] = &camcc_soc_ahb_clk.clkr,
+ [CAMCC_SYS_TMR_CLK] = &camcc_sys_tmr_clk.clkr,
+};
+
+static struct gdsc *camcc_sm6350_gdscs[] = {
+ [BPS_GDSC] = &bps_gdsc,
+ [IPE_0_GDSC] = &ipe_0_gdsc,
+ [IFE_0_GDSC] = &ife_0_gdsc,
+ [IFE_1_GDSC] = &ife_1_gdsc,
+ [IFE_2_GDSC] = &ife_2_gdsc,
+ [TITAN_TOP_GDSC] = &titan_top_gdsc,
+};
+
+static const struct regmap_config camcc_sm6350_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x16000,
+ .fast_io = true,
+};
+
+static const struct qcom_cc_desc camcc_sm6350_desc = {
+ .config = &camcc_sm6350_regmap_config,
+ .clk_hws = camcc_sm6350_hws,
+ .num_clk_hws = ARRAY_SIZE(camcc_sm6350_hws),
+ .clks = camcc_sm6350_clocks,
+ .num_clks = ARRAY_SIZE(camcc_sm6350_clocks),
+ .gdscs = camcc_sm6350_gdscs,
+ .num_gdscs = ARRAY_SIZE(camcc_sm6350_gdscs),
+};
+
+static const struct of_device_id camcc_sm6350_match_table[] = {
+ { .compatible = "qcom,sm6350-camcc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, camcc_sm6350_match_table);
+
+static int camcc_sm6350_probe(struct platform_device *pdev)
+{
+ struct regmap *regmap;
+
+ regmap = qcom_cc_map(pdev, &camcc_sm6350_desc);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ clk_fabia_pll_configure(&camcc_pll0, regmap, &camcc_pll0_config);
+ clk_fabia_pll_configure(&camcc_pll1, regmap, &camcc_pll1_config);
+ clk_agera_pll_configure(&camcc_pll2, regmap, &camcc_pll2_config);
+ clk_fabia_pll_configure(&camcc_pll3, regmap, &camcc_pll3_config);
+
+ return qcom_cc_really_probe(pdev, &camcc_sm6350_desc, regmap);
+}
+
+static struct platform_driver camcc_sm6350_driver = {
+ .probe = camcc_sm6350_probe,
+ .driver = {
+ .name = "sm6350-camcc",
+ .of_match_table = camcc_sm6350_match_table,
+ },
+};
+
+static int __init camcc_sm6350_init(void)
+{
+ return platform_driver_register(&camcc_sm6350_driver);
+}
+subsys_initcall(camcc_sm6350_init);
+
+static void __exit camcc_sm6350_exit(void)
+{
+ platform_driver_unregister(&camcc_sm6350_driver);
+}
+module_exit(camcc_sm6350_exit);
+
+MODULE_DESCRIPTION("QTI CAMCC SM6350 Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/qcom/camcc-sm8450.c b/drivers/clk/qcom/camcc-sm8450.c
index e3c09471dadf..51338a2884d2 100644
--- a/drivers/clk/qcom/camcc-sm8450.c
+++ b/drivers/clk/qcom/camcc-sm8450.c
@@ -95,8 +95,8 @@ static struct clk_alpha_pll_postdiv cam_cc_pll0_out_even = {
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],
.clkr.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_pll0_out_even",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_pll0.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_pll0.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -118,8 +118,8 @@ static struct clk_alpha_pll_postdiv cam_cc_pll0_out_odd = {
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],
.clkr.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_pll0_out_odd",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_pll0.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_pll0.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -166,8 +166,8 @@ static struct clk_alpha_pll_postdiv cam_cc_pll1_out_even = {
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],
.clkr.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_pll1_out_even",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_pll1.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_pll1.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -237,8 +237,8 @@ static struct clk_alpha_pll_postdiv cam_cc_pll3_out_even = {
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],
.clkr.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_pll3_out_even",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_pll3.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_pll3.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -285,8 +285,8 @@ static struct clk_alpha_pll_postdiv cam_cc_pll4_out_even = {
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],
.clkr.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_pll4_out_even",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_pll4.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_pll4.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -333,8 +333,8 @@ static struct clk_alpha_pll_postdiv cam_cc_pll5_out_even = {
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],
.clkr.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_pll5_out_even",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_pll5.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_pll5.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -381,8 +381,8 @@ static struct clk_alpha_pll_postdiv cam_cc_pll6_out_even = {
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],
.clkr.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_pll6_out_even",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_pll6.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_pll6.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -429,8 +429,8 @@ static struct clk_alpha_pll_postdiv cam_cc_pll7_out_even = {
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],
.clkr.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_pll7_out_even",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_pll7.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_pll7.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -477,8 +477,8 @@ static struct clk_alpha_pll_postdiv cam_cc_pll8_out_even = {
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],
.clkr.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_pll8_out_even",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_pll8.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_pll8.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1268,8 +1268,8 @@ static struct clk_branch cam_cc_gdsc_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_gdsc_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_xo_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_xo_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_IS_CRITICAL | CLK_SET_RATE_PARENT,
@@ -1286,8 +1286,8 @@ static struct clk_branch cam_cc_bps_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_bps_ahb_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_slow_ahb_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_slow_ahb_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1304,8 +1304,8 @@ static struct clk_branch cam_cc_bps_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_bps_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_bps_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_bps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1322,8 +1322,8 @@ static struct clk_branch cam_cc_bps_fast_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_bps_fast_ahb_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_fast_ahb_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_fast_ahb_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1340,8 +1340,8 @@ static struct clk_branch cam_cc_camnoc_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_camnoc_axi_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_camnoc_axi_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_camnoc_axi_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1358,8 +1358,8 @@ static struct clk_branch cam_cc_camnoc_dcd_xo_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_camnoc_dcd_xo_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_xo_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_xo_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1376,8 +1376,8 @@ static struct clk_branch cam_cc_cci_0_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_cci_0_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_cci_0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cci_0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1394,8 +1394,8 @@ static struct clk_branch cam_cc_cci_1_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_cci_1_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_cci_1_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cci_1_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1412,8 +1412,8 @@ static struct clk_branch cam_cc_core_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_core_ahb_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_slow_ahb_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_slow_ahb_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1430,8 +1430,8 @@ static struct clk_branch cam_cc_cpas_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_cpas_ahb_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_slow_ahb_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_slow_ahb_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1448,8 +1448,8 @@ static struct clk_branch cam_cc_cpas_bps_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_cpas_bps_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_bps_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_bps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1466,8 +1466,8 @@ static struct clk_branch cam_cc_cpas_fast_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_cpas_fast_ahb_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_fast_ahb_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_fast_ahb_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1484,8 +1484,8 @@ static struct clk_branch cam_cc_cpas_ife_0_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_cpas_ife_0_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_ife_0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ife_0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1502,8 +1502,8 @@ static struct clk_branch cam_cc_cpas_ife_1_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_cpas_ife_1_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_ife_1_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ife_1_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1520,8 +1520,8 @@ static struct clk_branch cam_cc_cpas_ife_2_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_cpas_ife_2_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_ife_2_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ife_2_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1538,8 +1538,8 @@ static struct clk_branch cam_cc_cpas_ife_lite_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_cpas_ife_lite_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_ife_lite_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ife_lite_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1556,8 +1556,8 @@ static struct clk_branch cam_cc_cpas_ipe_nps_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_cpas_ipe_nps_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_ipe_nps_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ipe_nps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1574,8 +1574,8 @@ static struct clk_branch cam_cc_cpas_sbi_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_cpas_sbi_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_ife_0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ife_0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1592,8 +1592,8 @@ static struct clk_branch cam_cc_cpas_sfe_0_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_cpas_sfe_0_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_sfe_0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_sfe_0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1610,8 +1610,8 @@ static struct clk_branch cam_cc_cpas_sfe_1_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_cpas_sfe_1_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_sfe_1_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_sfe_1_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1628,8 +1628,8 @@ static struct clk_branch cam_cc_csi0phytimer_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_csi0phytimer_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_csi0phytimer_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_csi0phytimer_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1646,8 +1646,8 @@ static struct clk_branch cam_cc_csi1phytimer_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_csi1phytimer_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_csi1phytimer_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_csi1phytimer_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1664,8 +1664,8 @@ static struct clk_branch cam_cc_csi2phytimer_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_csi2phytimer_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_csi2phytimer_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_csi2phytimer_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1682,8 +1682,8 @@ static struct clk_branch cam_cc_csi3phytimer_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_csi3phytimer_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_csi3phytimer_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_csi3phytimer_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1700,8 +1700,8 @@ static struct clk_branch cam_cc_csi4phytimer_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_csi4phytimer_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_csi4phytimer_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_csi4phytimer_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1718,8 +1718,8 @@ static struct clk_branch cam_cc_csi5phytimer_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_csi5phytimer_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_csi5phytimer_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_csi5phytimer_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1736,8 +1736,8 @@ static struct clk_branch cam_cc_csid_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_csid_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_csid_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_csid_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1754,8 +1754,8 @@ static struct clk_branch cam_cc_csid_csiphy_rx_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_csid_csiphy_rx_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_cphy_rx_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cphy_rx_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1772,8 +1772,8 @@ static struct clk_branch cam_cc_csiphy0_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_csiphy0_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_cphy_rx_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cphy_rx_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1790,8 +1790,8 @@ static struct clk_branch cam_cc_csiphy1_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_csiphy1_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_cphy_rx_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cphy_rx_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1808,8 +1808,8 @@ static struct clk_branch cam_cc_csiphy2_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_csiphy2_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_cphy_rx_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cphy_rx_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1826,8 +1826,8 @@ static struct clk_branch cam_cc_csiphy3_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_csiphy3_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_cphy_rx_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cphy_rx_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1844,8 +1844,8 @@ static struct clk_branch cam_cc_csiphy4_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_csiphy4_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_cphy_rx_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cphy_rx_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1862,8 +1862,8 @@ static struct clk_branch cam_cc_csiphy5_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_csiphy5_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_cphy_rx_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cphy_rx_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1880,8 +1880,8 @@ static struct clk_branch cam_cc_icp_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_icp_ahb_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_slow_ahb_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_slow_ahb_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1898,8 +1898,8 @@ static struct clk_branch cam_cc_icp_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_icp_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_icp_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_icp_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1916,8 +1916,8 @@ static struct clk_branch cam_cc_ife_0_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_ife_0_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_ife_0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ife_0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1934,8 +1934,8 @@ static struct clk_branch cam_cc_ife_0_dsp_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_ife_0_dsp_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_ife_0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ife_0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1952,8 +1952,8 @@ static struct clk_branch cam_cc_ife_0_fast_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_ife_0_fast_ahb_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_fast_ahb_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_fast_ahb_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1970,8 +1970,8 @@ static struct clk_branch cam_cc_ife_1_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_ife_1_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_ife_1_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ife_1_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1988,8 +1988,8 @@ static struct clk_branch cam_cc_ife_1_dsp_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_ife_1_dsp_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_ife_1_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ife_1_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2006,8 +2006,8 @@ static struct clk_branch cam_cc_ife_1_fast_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_ife_1_fast_ahb_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_fast_ahb_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_fast_ahb_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2024,8 +2024,8 @@ static struct clk_branch cam_cc_ife_2_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_ife_2_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_ife_2_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ife_2_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2042,8 +2042,8 @@ static struct clk_branch cam_cc_ife_2_dsp_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_ife_2_dsp_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_ife_2_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ife_2_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2060,8 +2060,8 @@ static struct clk_branch cam_cc_ife_2_fast_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_ife_2_fast_ahb_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_fast_ahb_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_fast_ahb_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2078,8 +2078,8 @@ static struct clk_branch cam_cc_ife_lite_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_ife_lite_ahb_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_slow_ahb_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_slow_ahb_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2096,8 +2096,8 @@ static struct clk_branch cam_cc_ife_lite_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_ife_lite_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_ife_lite_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ife_lite_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2114,8 +2114,8 @@ static struct clk_branch cam_cc_ife_lite_cphy_rx_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_ife_lite_cphy_rx_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_cphy_rx_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cphy_rx_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2132,8 +2132,8 @@ static struct clk_branch cam_cc_ife_lite_csid_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_ife_lite_csid_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_ife_lite_csid_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ife_lite_csid_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2150,8 +2150,8 @@ static struct clk_branch cam_cc_ipe_nps_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_ipe_nps_ahb_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_slow_ahb_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_slow_ahb_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2168,8 +2168,8 @@ static struct clk_branch cam_cc_ipe_nps_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_ipe_nps_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_ipe_nps_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ipe_nps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2186,8 +2186,8 @@ static struct clk_branch cam_cc_ipe_nps_fast_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_ipe_nps_fast_ahb_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_fast_ahb_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_fast_ahb_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2204,8 +2204,8 @@ static struct clk_branch cam_cc_ipe_pps_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_ipe_pps_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_ipe_nps_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ipe_nps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2222,8 +2222,8 @@ static struct clk_branch cam_cc_ipe_pps_fast_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_ipe_pps_fast_ahb_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_fast_ahb_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_fast_ahb_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2240,8 +2240,8 @@ static struct clk_branch cam_cc_jpeg_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_jpeg_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_jpeg_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_jpeg_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2258,8 +2258,8 @@ static struct clk_branch cam_cc_mclk0_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_mclk0_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_mclk0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_mclk0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2276,8 +2276,8 @@ static struct clk_branch cam_cc_mclk1_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_mclk1_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_mclk1_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_mclk1_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2294,8 +2294,8 @@ static struct clk_branch cam_cc_mclk2_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_mclk2_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_mclk2_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_mclk2_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2312,8 +2312,8 @@ static struct clk_branch cam_cc_mclk3_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_mclk3_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_mclk3_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_mclk3_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2330,8 +2330,8 @@ static struct clk_branch cam_cc_mclk4_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_mclk4_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_mclk4_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_mclk4_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2348,8 +2348,8 @@ static struct clk_branch cam_cc_mclk5_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_mclk5_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_mclk5_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_mclk5_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2366,8 +2366,8 @@ static struct clk_branch cam_cc_mclk6_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_mclk6_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_mclk6_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_mclk6_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2384,8 +2384,8 @@ static struct clk_branch cam_cc_mclk7_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_mclk7_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_mclk7_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_mclk7_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2402,8 +2402,8 @@ static struct clk_branch cam_cc_qdss_debug_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_qdss_debug_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_qdss_debug_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_qdss_debug_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2420,8 +2420,8 @@ static struct clk_branch cam_cc_qdss_debug_xo_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_qdss_debug_xo_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_xo_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_xo_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2438,8 +2438,8 @@ static struct clk_branch cam_cc_sbi_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_sbi_ahb_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_slow_ahb_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_slow_ahb_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2456,8 +2456,8 @@ static struct clk_branch cam_cc_sbi_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_sbi_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_ife_0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ife_0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2474,8 +2474,8 @@ static struct clk_branch cam_cc_sfe_0_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_sfe_0_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_sfe_0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_sfe_0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2492,8 +2492,8 @@ static struct clk_branch cam_cc_sfe_0_fast_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_sfe_0_fast_ahb_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_fast_ahb_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_fast_ahb_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2510,8 +2510,8 @@ static struct clk_branch cam_cc_sfe_1_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_sfe_1_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_sfe_1_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_sfe_1_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2528,8 +2528,8 @@ static struct clk_branch cam_cc_sfe_1_fast_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_sfe_1_fast_ahb_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_fast_ahb_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_fast_ahb_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2546,8 +2546,8 @@ static struct clk_branch cam_cc_sleep_clk = {
.enable_mask = BIT(0),
.hw.init = &(const struct clk_init_data) {
.name = "cam_cc_sleep_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &cam_cc_sleep_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_sleep_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c
index f9e4cfd7261c..e266379427f2 100644
--- a/drivers/clk/qcom/clk-alpha-pll.c
+++ b/drivers/clk/qcom/clk-alpha-pll.c
@@ -358,6 +358,11 @@ void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
regmap_update_bits(regmap, PLL_USER_CTL(pll), mask, val);
+ clk_alpha_pll_write_config(regmap, PLL_TEST_CTL(pll),
+ config->test_ctl_val);
+ clk_alpha_pll_write_config(regmap, PLL_TEST_CTL_U(pll),
+ config->test_ctl_hi_val);
+
if (pll->flags & SUPPORTS_FSM_MODE)
qcom_pll_set_fsm_mode(regmap, PLL_MODE(pll), 6, 0);
}
diff --git a/drivers/clk/qcom/clk-alpha-pll.h b/drivers/clk/qcom/clk-alpha-pll.h
index 2bdae362c827..c67cfda27ecb 100644
--- a/drivers/clk/qcom/clk-alpha-pll.h
+++ b/drivers/clk/qcom/clk-alpha-pll.h
@@ -162,6 +162,7 @@ extern const struct clk_ops clk_alpha_pll_zonda_ops;
extern const struct clk_ops clk_alpha_pll_lucid_evo_ops;
extern const struct clk_ops clk_alpha_pll_reset_lucid_evo_ops;
+#define clk_alpha_pll_reset_lucid_ole_ops clk_alpha_pll_reset_lucid_evo_ops
extern const struct clk_ops clk_alpha_pll_fixed_lucid_evo_ops;
#define clk_alpha_pll_fixed_lucid_ole_ops clk_alpha_pll_fixed_lucid_evo_ops
extern const struct clk_ops clk_alpha_pll_postdiv_lucid_evo_ops;
diff --git a/drivers/clk/qcom/clk-cbf-8996.c b/drivers/clk/qcom/clk-cbf-8996.c
new file mode 100644
index 000000000000..cfd567636f4e
--- /dev/null
+++ b/drivers/clk/qcom/clk-cbf-8996.c
@@ -0,0 +1,315 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022, 2023 Linaro Ltd.
+ */
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include "clk-alpha-pll.h"
+#include "clk-regmap.h"
+
+/* Need to match the order of clocks in DT binding */
+enum {
+ DT_XO,
+ DT_APCS_AUX,
+};
+
+enum {
+ CBF_XO_INDEX,
+ CBF_PLL_INDEX,
+ CBF_DIV_INDEX,
+ CBF_APCS_AUX_INDEX,
+};
+
+#define DIV_THRESHOLD 600000000
+
+#define CBF_MUX_OFFSET 0x18
+#define CBF_MUX_PARENT_MASK GENMASK(1, 0)
+#define CBF_MUX_AUTO_CLK_SEL_ALWAYS_ON_MASK GENMASK(5, 4)
+#define CBF_MUX_AUTO_CLK_SEL_ALWAYS_ON_GPLL0_SEL \
+ FIELD_PREP(CBF_MUX_AUTO_CLK_SEL_ALWAYS_ON_MASK, 0x03)
+#define CBF_MUX_AUTO_CLK_SEL_BIT BIT(6)
+
+#define CBF_PLL_OFFSET 0xf000
+
+static const u8 cbf_pll_regs[PLL_OFF_MAX_REGS] = {
+ [PLL_OFF_L_VAL] = 0x08,
+ [PLL_OFF_ALPHA_VAL] = 0x10,
+ [PLL_OFF_USER_CTL] = 0x18,
+ [PLL_OFF_CONFIG_CTL] = 0x20,
+ [PLL_OFF_CONFIG_CTL_U] = 0x24,
+ [PLL_OFF_TEST_CTL] = 0x30,
+ [PLL_OFF_TEST_CTL_U] = 0x34,
+ [PLL_OFF_STATUS] = 0x28,
+};
+
+static const struct alpha_pll_config cbfpll_config = {
+ .l = 72,
+ .config_ctl_val = 0x200d4828,
+ .config_ctl_hi_val = 0x006,
+ .test_ctl_val = 0x1c000000,
+ .test_ctl_hi_val = 0x00004000,
+ .pre_div_mask = BIT(12),
+ .post_div_mask = 0x3 << 8,
+ .post_div_val = 0x1 << 8,
+ .main_output_mask = BIT(0),
+ .early_output_mask = BIT(3),
+};
+
+static struct clk_alpha_pll cbf_pll = {
+ .offset = CBF_PLL_OFFSET,
+ .regs = cbf_pll_regs,
+ .flags = SUPPORTS_DYNAMIC_UPDATE | SUPPORTS_FSM_MODE,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cbf_pll",
+ .parent_data = (const struct clk_parent_data[]) {
+ { .index = DT_XO, },
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_hwfsm_ops,
+ },
+};
+
+static struct clk_fixed_factor cbf_pll_postdiv = {
+ .mult = 1,
+ .div = 2,
+ .hw.init = &(struct clk_init_data){
+ .name = "cbf_pll_postdiv",
+ .parent_hws = (const struct clk_hw*[]){
+ &cbf_pll.clkr.hw
+ },
+ .num_parents = 1,
+ .ops = &clk_fixed_factor_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static const struct clk_parent_data cbf_mux_parent_data[] = {
+ { .index = DT_XO },
+ { .hw = &cbf_pll.clkr.hw },
+ { .hw = &cbf_pll_postdiv.hw },
+ { .index = DT_APCS_AUX },
+};
+
+struct clk_cbf_8996_mux {
+ u32 reg;
+ struct notifier_block nb;
+ struct clk_regmap clkr;
+};
+
+static struct clk_cbf_8996_mux *to_clk_cbf_8996_mux(struct clk_regmap *clkr)
+{
+ return container_of(clkr, struct clk_cbf_8996_mux, clkr);
+}
+
+static int cbf_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
+ void *data);
+
+static u8 clk_cbf_8996_mux_get_parent(struct clk_hw *hw)
+{
+ struct clk_regmap *clkr = to_clk_regmap(hw);
+ struct clk_cbf_8996_mux *mux = to_clk_cbf_8996_mux(clkr);
+ u32 val;
+
+ regmap_read(clkr->regmap, mux->reg, &val);
+
+ return FIELD_GET(CBF_MUX_PARENT_MASK, val);
+}
+
+static int clk_cbf_8996_mux_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct clk_regmap *clkr = to_clk_regmap(hw);
+ struct clk_cbf_8996_mux *mux = to_clk_cbf_8996_mux(clkr);
+ u32 val;
+
+ val = FIELD_PREP(CBF_MUX_PARENT_MASK, index);
+
+ return regmap_update_bits(clkr->regmap, mux->reg, CBF_MUX_PARENT_MASK, val);
+}
+
+static int clk_cbf_8996_mux_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ struct clk_hw *parent;
+
+ if (req->rate < (DIV_THRESHOLD / 2))
+ return -EINVAL;
+
+ if (req->rate < DIV_THRESHOLD)
+ parent = clk_hw_get_parent_by_index(hw, CBF_DIV_INDEX);
+ else
+ parent = clk_hw_get_parent_by_index(hw, CBF_PLL_INDEX);
+
+ if (!parent)
+ return -EINVAL;
+
+ req->best_parent_rate = clk_hw_round_rate(parent, req->rate);
+ req->best_parent_hw = parent;
+
+ return 0;
+}
+
+static const struct clk_ops clk_cbf_8996_mux_ops = {
+ .set_parent = clk_cbf_8996_mux_set_parent,
+ .get_parent = clk_cbf_8996_mux_get_parent,
+ .determine_rate = clk_cbf_8996_mux_determine_rate,
+};
+
+static struct clk_cbf_8996_mux cbf_mux = {
+ .reg = CBF_MUX_OFFSET,
+ .nb.notifier_call = cbf_clk_notifier_cb,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "cbf_mux",
+ .parent_data = cbf_mux_parent_data,
+ .num_parents = ARRAY_SIZE(cbf_mux_parent_data),
+ .ops = &clk_cbf_8996_mux_ops,
+ /* CPU clock is critical and should never be gated */
+ .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
+ },
+};
+
+static int cbf_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
+ void *data)
+{
+ struct clk_notifier_data *cnd = data;
+
+ switch (event) {
+ case PRE_RATE_CHANGE:
+ /*
+ * Avoid overvolting. clk_core_set_rate_nolock() walks from top
+ * to bottom, so it will change the rate of the PLL before
+ * chaging the parent of PMUX. This can result in pmux getting
+ * clocked twice the expected rate.
+ *
+ * Manually switch to PLL/2 here.
+ */
+ if (cnd->old_rate > DIV_THRESHOLD &&
+ cnd->new_rate < DIV_THRESHOLD)
+ clk_cbf_8996_mux_set_parent(&cbf_mux.clkr.hw, CBF_DIV_INDEX);
+ break;
+ case ABORT_RATE_CHANGE:
+ /* Revert manual change */
+ if (cnd->new_rate < DIV_THRESHOLD &&
+ cnd->old_rate > DIV_THRESHOLD)
+ clk_cbf_8996_mux_set_parent(&cbf_mux.clkr.hw, CBF_PLL_INDEX);
+ break;
+ default:
+ break;
+ }
+
+ return notifier_from_errno(0);
+};
+
+static struct clk_hw *cbf_msm8996_hw_clks[] = {
+ &cbf_pll_postdiv.hw,
+};
+
+static struct clk_regmap *cbf_msm8996_clks[] = {
+ &cbf_pll.clkr,
+ &cbf_mux.clkr,
+};
+
+static const struct regmap_config cbf_msm8996_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x10000,
+ .fast_io = true,
+ .val_format_endian = REGMAP_ENDIAN_LITTLE,
+};
+
+static int qcom_msm8996_cbf_probe(struct platform_device *pdev)
+{
+ void __iomem *base;
+ struct regmap *regmap;
+ struct device *dev = &pdev->dev;
+ int i, ret;
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ regmap = devm_regmap_init_mmio(dev, base, &cbf_msm8996_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ /* Select GPLL0 for 300MHz for the CBF clock */
+ regmap_write(regmap, CBF_MUX_OFFSET, 0x3);
+
+ /* Ensure write goes through before PLLs are reconfigured */
+ udelay(5);
+
+ /* Set the auto clock sel always-on source to GPLL0/2 (300MHz) */
+ regmap_update_bits(regmap, CBF_MUX_OFFSET,
+ CBF_MUX_AUTO_CLK_SEL_ALWAYS_ON_MASK,
+ CBF_MUX_AUTO_CLK_SEL_ALWAYS_ON_GPLL0_SEL);
+
+ clk_alpha_pll_configure(&cbf_pll, regmap, &cbfpll_config);
+
+ /* Wait for PLL(s) to lock */
+ udelay(50);
+
+ /* Enable auto clock selection for CBF */
+ regmap_update_bits(regmap, CBF_MUX_OFFSET,
+ CBF_MUX_AUTO_CLK_SEL_BIT,
+ CBF_MUX_AUTO_CLK_SEL_BIT);
+
+ /* Ensure write goes through before muxes are switched */
+ udelay(5);
+
+ /* Switch CBF to use the primary PLL */
+ regmap_update_bits(regmap, CBF_MUX_OFFSET, CBF_MUX_PARENT_MASK, 0x1);
+
+ for (i = 0; i < ARRAY_SIZE(cbf_msm8996_hw_clks); i++) {
+ ret = devm_clk_hw_register(dev, cbf_msm8996_hw_clks[i]);
+ if (ret)
+ return ret;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(cbf_msm8996_clks); i++) {
+ ret = devm_clk_register_regmap(dev, cbf_msm8996_clks[i]);
+ if (ret)
+ return ret;
+ }
+
+ ret = devm_clk_notifier_register(dev, cbf_mux.clkr.hw.clk, &cbf_mux.nb);
+ if (ret)
+ return ret;
+
+ return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, &cbf_mux.clkr.hw);
+}
+
+static const struct of_device_id qcom_msm8996_cbf_match_table[] = {
+ { .compatible = "qcom,msm8996-cbf" },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, qcom_msm8996_cbf_match_table);
+
+static struct platform_driver qcom_msm8996_cbf_driver = {
+ .probe = qcom_msm8996_cbf_probe,
+ .driver = {
+ .name = "qcom-msm8996-cbf",
+ .of_match_table = qcom_msm8996_cbf_match_table,
+ },
+};
+
+/* Register early enough to fix the clock to be used for other cores */
+static int __init qcom_msm8996_cbf_init(void)
+{
+ return platform_driver_register(&qcom_msm8996_cbf_driver);
+}
+postcore_initcall(qcom_msm8996_cbf_init);
+
+static void __exit qcom_msm8996_cbf_exit(void)
+{
+ platform_driver_unregister(&qcom_msm8996_cbf_driver);
+}
+module_exit(qcom_msm8996_cbf_exit);
+
+MODULE_DESCRIPTION("QCOM MSM8996 CPU Bus Fabric Clock Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/qcom/clk-cpu-8996.c b/drivers/clk/qcom/clk-cpu-8996.c
index ee76ef958d31..592c7c3cdeb7 100644
--- a/drivers/clk/qcom/clk-cpu-8996.c
+++ b/drivers/clk/qcom/clk-cpu-8996.c
@@ -12,6 +12,8 @@
* +-------+
* XO | |
* +------------------>0 |
+ * SYS_APCS_AUX | |
+ * +------------------>3 |
* | |
* PLL/2 | SMUX +----+
* +------->1 | |
@@ -58,6 +60,8 @@
#include <linux/regmap.h>
#include <soc/qcom/kryo-l2-accessors.h>
+#include <asm/cputype.h>
+
#include "clk-alpha-pll.h"
#include "clk-regmap.h"
#include "clk-regmap-mux.h"
@@ -74,10 +78,16 @@ enum _pmux_input {
#define PWRCL_REG_OFFSET 0x0
#define PERFCL_REG_OFFSET 0x80000
#define MUX_OFFSET 0x40
+#define CLK_CTL_OFFSET 0x44
+#define CLK_CTL_AUTO_CLK_SEL BIT(8)
#define ALT_PLL_OFFSET 0x100
#define SSSCTL_OFFSET 0x160
+#define PSCTL_OFFSET 0x164
#define PMUX_MASK 0x3
+#define MUX_AUTO_CLK_SEL_ALWAYS_ON_MASK GENMASK(5, 4)
+#define MUX_AUTO_CLK_SEL_ALWAYS_ON_GPLL0_SEL \
+ FIELD_PREP(MUX_AUTO_CLK_SEL_ALWAYS_ON_MASK, 0x03)
static const u8 prim_pll_regs[PLL_OFF_MAX_REGS] = {
[PLL_OFF_L_VAL] = 0x04,
@@ -93,21 +103,20 @@ static const u8 prim_pll_regs[PLL_OFF_MAX_REGS] = {
static const u8 alt_pll_regs[PLL_OFF_MAX_REGS] = {
[PLL_OFF_L_VAL] = 0x04,
[PLL_OFF_ALPHA_VAL] = 0x08,
- [PLL_OFF_ALPHA_VAL_U] = 0x0c,
[PLL_OFF_USER_CTL] = 0x10,
- [PLL_OFF_USER_CTL_U] = 0x14,
[PLL_OFF_CONFIG_CTL] = 0x18,
[PLL_OFF_TEST_CTL] = 0x20,
- [PLL_OFF_TEST_CTL_U] = 0x24,
[PLL_OFF_STATUS] = 0x28,
};
/* PLLs */
static const struct alpha_pll_config hfpll_config = {
- .l = 60,
- .config_ctl_val = 0x200d4aa8,
+ .l = 54,
+ .config_ctl_val = 0x200d4828,
.config_ctl_hi_val = 0x006,
+ .test_ctl_val = 0x1c000000,
+ .test_ctl_hi_val = 0x00004000,
.pre_div_mask = BIT(12),
.post_div_mask = 0x3 << 8,
.post_div_val = 0x1 << 8,
@@ -127,7 +136,7 @@ static struct clk_alpha_pll pwrcl_pll = {
.name = "pwrcl_pll",
.parent_data = pll_parent,
.num_parents = ARRAY_SIZE(pll_parent),
- .ops = &clk_alpha_pll_huayra_ops,
+ .ops = &clk_alpha_pll_hwfsm_ops,
},
};
@@ -139,7 +148,7 @@ static struct clk_alpha_pll perfcl_pll = {
.name = "perfcl_pll",
.parent_data = pll_parent,
.num_parents = ARRAY_SIZE(pll_parent),
- .ops = &clk_alpha_pll_huayra_ops,
+ .ops = &clk_alpha_pll_hwfsm_ops,
},
};
@@ -311,20 +320,29 @@ static const struct clk_ops clk_cpu_8996_pmux_ops = {
.determine_rate = clk_cpu_8996_pmux_determine_rate,
};
+static const struct parent_map smux_parent_map[] = {
+ { .cfg = 0, }, /* xo */
+ { .cfg = 1, }, /* pll */
+ { .cfg = 3, }, /* sys_apcs_aux */
+};
+
static const struct clk_parent_data pwrcl_smux_parents[] = {
{ .fw_name = "xo" },
{ .hw = &pwrcl_pll_postdiv.hw },
+ { .fw_name = "sys_apcs_aux" },
};
static const struct clk_parent_data perfcl_smux_parents[] = {
{ .fw_name = "xo" },
{ .hw = &perfcl_pll_postdiv.hw },
+ { .fw_name = "sys_apcs_aux" },
};
static struct clk_regmap_mux pwrcl_smux = {
.reg = PWRCL_REG_OFFSET + MUX_OFFSET,
.shift = 2,
.width = 2,
+ .parent_map = smux_parent_map,
.clkr.hw.init = &(struct clk_init_data) {
.name = "pwrcl_smux",
.parent_data = pwrcl_smux_parents,
@@ -338,6 +356,7 @@ static struct clk_regmap_mux perfcl_smux = {
.reg = PERFCL_REG_OFFSET + MUX_OFFSET,
.shift = 2,
.width = 2,
+ .parent_map = smux_parent_map,
.clkr.hw.init = &(struct clk_init_data) {
.name = "perfcl_smux",
.parent_data = perfcl_smux_parents,
@@ -414,11 +433,55 @@ static struct clk_regmap *cpu_msm8996_clks[] = {
&perfcl_pmux.clkr,
};
+static void qcom_cpu_clk_msm8996_acd_init(struct regmap *regmap);
+
static int qcom_cpu_clk_msm8996_register_clks(struct device *dev,
struct regmap *regmap)
{
int i, ret;
+ /* Select GPLL0 for 300MHz for both clusters */
+ regmap_write(regmap, PERFCL_REG_OFFSET + MUX_OFFSET, 0xc);
+ regmap_write(regmap, PWRCL_REG_OFFSET + MUX_OFFSET, 0xc);
+
+ /* Ensure write goes through before PLLs are reconfigured */
+ udelay(5);
+
+ /* Set the auto clock sel always-on source to GPLL0/2 (300MHz) */
+ regmap_update_bits(regmap, PWRCL_REG_OFFSET + MUX_OFFSET,
+ MUX_AUTO_CLK_SEL_ALWAYS_ON_MASK,
+ MUX_AUTO_CLK_SEL_ALWAYS_ON_GPLL0_SEL);
+ regmap_update_bits(regmap, PERFCL_REG_OFFSET + MUX_OFFSET,
+ MUX_AUTO_CLK_SEL_ALWAYS_ON_MASK,
+ MUX_AUTO_CLK_SEL_ALWAYS_ON_GPLL0_SEL);
+
+ clk_alpha_pll_configure(&pwrcl_pll, regmap, &hfpll_config);
+ clk_alpha_pll_configure(&perfcl_pll, regmap, &hfpll_config);
+ clk_alpha_pll_configure(&pwrcl_alt_pll, regmap, &altpll_config);
+ clk_alpha_pll_configure(&perfcl_alt_pll, regmap, &altpll_config);
+
+ /* Wait for PLL(s) to lock */
+ udelay(50);
+
+ /* Enable auto clock selection for both clusters */
+ regmap_update_bits(regmap, PWRCL_REG_OFFSET + CLK_CTL_OFFSET,
+ CLK_CTL_AUTO_CLK_SEL, CLK_CTL_AUTO_CLK_SEL);
+ regmap_update_bits(regmap, PERFCL_REG_OFFSET + CLK_CTL_OFFSET,
+ CLK_CTL_AUTO_CLK_SEL, CLK_CTL_AUTO_CLK_SEL);
+
+ /* Ensure write goes through before muxes are switched */
+ udelay(5);
+
+ qcom_cpu_clk_msm8996_acd_init(regmap);
+
+ /* Pulse swallower and soft-start settings */
+ regmap_write(regmap, PWRCL_REG_OFFSET + PSCTL_OFFSET, 0x00030005);
+ regmap_write(regmap, PERFCL_REG_OFFSET + PSCTL_OFFSET, 0x00030005);
+
+ /* Switch clusters to use the ACD leg */
+ regmap_write(regmap, PWRCL_REG_OFFSET + MUX_OFFSET, 0x32);
+ regmap_write(regmap, PERFCL_REG_OFFSET + MUX_OFFSET, 0x32);
+
for (i = 0; i < ARRAY_SIZE(cpu_msm8996_hw_clks); i++) {
ret = devm_clk_hw_register(dev, cpu_msm8996_hw_clks[i]);
if (ret)
@@ -431,11 +494,6 @@ static int qcom_cpu_clk_msm8996_register_clks(struct device *dev,
return ret;
}
- clk_alpha_pll_configure(&pwrcl_pll, regmap, &hfpll_config);
- clk_alpha_pll_configure(&perfcl_pll, regmap, &hfpll_config);
- clk_alpha_pll_configure(&pwrcl_alt_pll, regmap, &altpll_config);
- clk_alpha_pll_configure(&perfcl_alt_pll, regmap, &altpll_config);
-
/* Enable alt PLLs */
clk_prepare_enable(pwrcl_alt_pll.clkr.hw.clk);
clk_prepare_enable(perfcl_alt_pll.clkr.hw.clk);
@@ -446,9 +504,9 @@ static int qcom_cpu_clk_msm8996_register_clks(struct device *dev,
return ret;
}
-#define CPU_AFINITY_MASK 0xFFF
-#define PWRCL_CPU_REG_MASK 0x3
-#define PERFCL_CPU_REG_MASK 0x103
+#define CPU_CLUSTER_AFFINITY_MASK 0xf00
+#define PWRCL_AFFINITY_MASK 0x000
+#define PERFCL_AFFINITY_MASK 0x100
#define L2ACDCR_REG 0x580ULL
#define L2ACDTD_REG 0x581ULL
@@ -456,31 +514,32 @@ static int qcom_cpu_clk_msm8996_register_clks(struct device *dev,
#define L2ACDSSCR_REG 0x589ULL
static DEFINE_SPINLOCK(qcom_clk_acd_lock);
-static void __iomem *base;
-static void qcom_cpu_clk_msm8996_acd_init(void __iomem *base)
+static void qcom_cpu_clk_msm8996_acd_init(struct regmap *regmap)
{
u64 hwid;
+ u32 val;
unsigned long flags;
spin_lock_irqsave(&qcom_clk_acd_lock, flags);
- hwid = read_cpuid_mpidr() & CPU_AFINITY_MASK;
+ val = kryo_l2_get_indirect_reg(L2ACDTD_REG);
+ if (val == 0x00006a11)
+ goto out;
kryo_l2_set_indirect_reg(L2ACDTD_REG, 0x00006a11);
kryo_l2_set_indirect_reg(L2ACDDVMRC_REG, 0x000e0f0f);
kryo_l2_set_indirect_reg(L2ACDSSCR_REG, 0x00000601);
- if (PWRCL_CPU_REG_MASK == (hwid | PWRCL_CPU_REG_MASK)) {
- writel(0xf, base + PWRCL_REG_OFFSET + SSSCTL_OFFSET);
- kryo_l2_set_indirect_reg(L2ACDCR_REG, 0x002c5ffd);
- }
+ kryo_l2_set_indirect_reg(L2ACDCR_REG, 0x002c5ffd);
- if (PERFCL_CPU_REG_MASK == (hwid | PERFCL_CPU_REG_MASK)) {
- kryo_l2_set_indirect_reg(L2ACDCR_REG, 0x002c5ffd);
- writel(0xf, base + PERFCL_REG_OFFSET + SSSCTL_OFFSET);
- }
+ hwid = read_cpuid_mpidr();
+ if ((hwid & CPU_CLUSTER_AFFINITY_MASK) == PWRCL_AFFINITY_MASK)
+ regmap_write(regmap, PWRCL_REG_OFFSET + SSSCTL_OFFSET, 0xf);
+ else
+ regmap_write(regmap, PERFCL_REG_OFFSET + SSSCTL_OFFSET, 0xf);
+out:
spin_unlock_irqrestore(&qcom_clk_acd_lock, flags);
}
@@ -489,31 +548,40 @@ static int cpu_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
{
struct clk_cpu_8996_pmux *cpuclk = to_clk_cpu_8996_pmux_nb(nb);
struct clk_notifier_data *cnd = data;
- int ret;
switch (event) {
case PRE_RATE_CHANGE:
- ret = clk_cpu_8996_pmux_set_parent(&cpuclk->clkr.hw, ALT_INDEX);
- qcom_cpu_clk_msm8996_acd_init(base);
+ qcom_cpu_clk_msm8996_acd_init(cpuclk->clkr.regmap);
+
+ /*
+ * Avoid overvolting. clk_core_set_rate_nolock() walks from top
+ * to bottom, so it will change the rate of the PLL before
+ * chaging the parent of PMUX. This can result in pmux getting
+ * clocked twice the expected rate.
+ *
+ * Manually switch to PLL/2 here.
+ */
+ if (cnd->new_rate < DIV_2_THRESHOLD &&
+ cnd->old_rate > DIV_2_THRESHOLD)
+ clk_cpu_8996_pmux_set_parent(&cpuclk->clkr.hw, SMUX_INDEX);
+
break;
- case POST_RATE_CHANGE:
- if (cnd->new_rate < DIV_2_THRESHOLD)
- ret = clk_cpu_8996_pmux_set_parent(&cpuclk->clkr.hw,
- SMUX_INDEX);
- else
- ret = clk_cpu_8996_pmux_set_parent(&cpuclk->clkr.hw,
- ACD_INDEX);
+ case ABORT_RATE_CHANGE:
+ /* Revert manual change */
+ if (cnd->new_rate < DIV_2_THRESHOLD &&
+ cnd->old_rate > DIV_2_THRESHOLD)
+ clk_cpu_8996_pmux_set_parent(&cpuclk->clkr.hw, ACD_INDEX);
break;
default:
- ret = 0;
break;
}
- return notifier_from_errno(ret);
+ return NOTIFY_OK;
};
static int qcom_cpu_clk_msm8996_driver_probe(struct platform_device *pdev)
{
+ static void __iomem *base;
struct regmap *regmap;
struct clk_hw_onecell_data *data;
struct device *dev = &pdev->dev;
@@ -535,8 +603,6 @@ static int qcom_cpu_clk_msm8996_driver_probe(struct platform_device *pdev)
if (ret)
return ret;
- qcom_cpu_clk_msm8996_acd_init(base);
-
data->hws[0] = &pwrcl_pmux.clkr.hw;
data->hws[1] = &perfcl_pmux.clkr.hw;
data->num = 2;
diff --git a/drivers/clk/qcom/clk-rpmh.c b/drivers/clk/qcom/clk-rpmh.c
index 586a810c682c..45ee370f3307 100644
--- a/drivers/clk/qcom/clk-rpmh.c
+++ b/drivers/clk/qcom/clk-rpmh.c
@@ -366,6 +366,16 @@ DEFINE_CLK_RPMH_VRM(rf_clk2, _d, "rfclkd2", 1);
DEFINE_CLK_RPMH_VRM(rf_clk3, _d, "rfclkd3", 1);
DEFINE_CLK_RPMH_VRM(rf_clk4, _d, "rfclkd4", 1);
+DEFINE_CLK_RPMH_VRM(clk1, _a1, "clka1", 1);
+DEFINE_CLK_RPMH_VRM(clk2, _a1, "clka2", 1);
+DEFINE_CLK_RPMH_VRM(clk3, _a1, "clka3", 1);
+DEFINE_CLK_RPMH_VRM(clk4, _a1, "clka4", 1);
+DEFINE_CLK_RPMH_VRM(clk5, _a1, "clka5", 1);
+
+DEFINE_CLK_RPMH_VRM(clk6, _a2, "clka6", 2);
+DEFINE_CLK_RPMH_VRM(clk7, _a2, "clka7", 2);
+DEFINE_CLK_RPMH_VRM(clk8, _a2, "clka8", 2);
+
DEFINE_CLK_RPMH_VRM(div_clk1, _div2, "divclka1", 2);
DEFINE_CLK_RPMH_BCM(ce, "CE0");
@@ -396,6 +406,22 @@ static const struct clk_rpmh_desc clk_rpmh_sdm845 = {
.num_clks = ARRAY_SIZE(sdm845_rpmh_clocks),
};
+static struct clk_hw *sa8775p_rpmh_clocks[] = {
+ [RPMH_CXO_CLK] = &clk_rpmh_bi_tcxo_div2.hw,
+ [RPMH_CXO_CLK_A] = &clk_rpmh_bi_tcxo_div2_ao.hw,
+ [RPMH_LN_BB_CLK1] = &clk_rpmh_ln_bb_clk1_a2.hw,
+ [RPMH_LN_BB_CLK2] = &clk_rpmh_ln_bb_clk2_a2.hw,
+ [RPMH_LN_BB_CLK2_A] = &clk_rpmh_ln_bb_clk2_a4_ao.hw,
+ [RPMH_IPA_CLK] = &clk_rpmh_ipa.hw,
+ [RPMH_PKA_CLK] = &clk_rpmh_pka.hw,
+ [RPMH_HWKM_CLK] = &clk_rpmh_hwkm.hw,
+};
+
+static const struct clk_rpmh_desc clk_rpmh_sa8775p = {
+ .clks = sa8775p_rpmh_clocks,
+ .num_clks = ARRAY_SIZE(sa8775p_rpmh_clocks),
+};
+
static struct clk_hw *sdm670_rpmh_clocks[] = {
[RPMH_CXO_CLK] = &clk_rpmh_bi_tcxo_div2.hw,
[RPMH_CXO_CLK_A] = &clk_rpmh_bi_tcxo_div2_ao.hw,
@@ -445,6 +471,7 @@ static struct clk_hw *sm8150_rpmh_clocks[] = {
[RPMH_RF_CLK2_A] = &clk_rpmh_rf_clk2_a_ao.hw,
[RPMH_RF_CLK3] = &clk_rpmh_rf_clk3_a.hw,
[RPMH_RF_CLK3_A] = &clk_rpmh_rf_clk3_a_ao.hw,
+ [RPMH_IPA_CLK] = &clk_rpmh_ipa.hw,
};
static const struct clk_rpmh_desc clk_rpmh_sm8150 = {
@@ -484,6 +511,7 @@ static struct clk_hw *sc8180x_rpmh_clocks[] = {
[RPMH_RF_CLK2_A] = &clk_rpmh_rf_clk2_d_ao.hw,
[RPMH_RF_CLK3] = &clk_rpmh_rf_clk3_d.hw,
[RPMH_RF_CLK3_A] = &clk_rpmh_rf_clk3_d_ao.hw,
+ [RPMH_IPA_CLK] = &clk_rpmh_ipa.hw,
};
static const struct clk_rpmh_desc clk_rpmh_sc8180x = {
@@ -504,6 +532,7 @@ static struct clk_hw *sm8250_rpmh_clocks[] = {
[RPMH_RF_CLK1_A] = &clk_rpmh_rf_clk1_a_ao.hw,
[RPMH_RF_CLK3] = &clk_rpmh_rf_clk3_a.hw,
[RPMH_RF_CLK3_A] = &clk_rpmh_rf_clk3_a_ao.hw,
+ [RPMH_IPA_CLK] = &clk_rpmh_ipa.hw,
};
static const struct clk_rpmh_desc clk_rpmh_sm8250 = {
@@ -576,6 +605,31 @@ static const struct clk_rpmh_desc clk_rpmh_sm8450 = {
.num_clks = ARRAY_SIZE(sm8450_rpmh_clocks),
};
+static struct clk_hw *sm8550_rpmh_clocks[] = {
+ [RPMH_CXO_CLK] = &clk_rpmh_bi_tcxo_div2.hw,
+ [RPMH_CXO_CLK_A] = &clk_rpmh_bi_tcxo_div2_ao.hw,
+ [RPMH_LN_BB_CLK1] = &clk_rpmh_clk6_a2.hw,
+ [RPMH_LN_BB_CLK1_A] = &clk_rpmh_clk6_a2_ao.hw,
+ [RPMH_LN_BB_CLK2] = &clk_rpmh_clk7_a2.hw,
+ [RPMH_LN_BB_CLK2_A] = &clk_rpmh_clk7_a2_ao.hw,
+ [RPMH_LN_BB_CLK3] = &clk_rpmh_clk8_a2.hw,
+ [RPMH_LN_BB_CLK3_A] = &clk_rpmh_clk8_a2_ao.hw,
+ [RPMH_RF_CLK1] = &clk_rpmh_clk1_a1.hw,
+ [RPMH_RF_CLK1_A] = &clk_rpmh_clk1_a1_ao.hw,
+ [RPMH_RF_CLK2] = &clk_rpmh_clk2_a1.hw,
+ [RPMH_RF_CLK2_A] = &clk_rpmh_clk2_a1_ao.hw,
+ [RPMH_RF_CLK3] = &clk_rpmh_clk3_a1.hw,
+ [RPMH_RF_CLK3_A] = &clk_rpmh_clk3_a1_ao.hw,
+ [RPMH_RF_CLK4] = &clk_rpmh_clk4_a1.hw,
+ [RPMH_RF_CLK4_A] = &clk_rpmh_clk4_a1_ao.hw,
+ [RPMH_IPA_CLK] = &clk_rpmh_ipa.hw,
+};
+
+static const struct clk_rpmh_desc clk_rpmh_sm8550 = {
+ .clks = sm8550_rpmh_clocks,
+ .num_clks = ARRAY_SIZE(sm8550_rpmh_clocks),
+};
+
static struct clk_hw *sc7280_rpmh_clocks[] = {
[RPMH_CXO_CLK] = &clk_rpmh_bi_tcxo_div4.hw,
[RPMH_CXO_CLK_A] = &clk_rpmh_bi_tcxo_div4_ao.hw,
@@ -730,6 +784,7 @@ static int clk_rpmh_probe(struct platform_device *pdev)
static const struct of_device_id clk_rpmh_match_table[] = {
{ .compatible = "qcom,qdu1000-rpmh-clk", .data = &clk_rpmh_qdu1000},
+ { .compatible = "qcom,sa8775p-rpmh-clk", .data = &clk_rpmh_sa8775p},
{ .compatible = "qcom,sc7180-rpmh-clk", .data = &clk_rpmh_sc7180},
{ .compatible = "qcom,sc8180x-rpmh-clk", .data = &clk_rpmh_sc8180x},
{ .compatible = "qcom,sc8280xp-rpmh-clk", .data = &clk_rpmh_sc8280xp},
@@ -742,6 +797,7 @@ static const struct of_device_id clk_rpmh_match_table[] = {
{ .compatible = "qcom,sm8250-rpmh-clk", .data = &clk_rpmh_sm8250},
{ .compatible = "qcom,sm8350-rpmh-clk", .data = &clk_rpmh_sm8350},
{ .compatible = "qcom,sm8450-rpmh-clk", .data = &clk_rpmh_sm8450},
+ { .compatible = "qcom,sm8550-rpmh-clk", .data = &clk_rpmh_sm8550},
{ .compatible = "qcom,sc7280-rpmh-clk", .data = &clk_rpmh_sc7280},
{ }
};
diff --git a/drivers/clk/qcom/clk-smd-rpm.c b/drivers/clk/qcom/clk-smd-rpm.c
index fea505876855..198886c1b6c8 100644
--- a/drivers/clk/qcom/clk-smd-rpm.c
+++ b/drivers/clk/qcom/clk-smd-rpm.c
@@ -25,107 +25,133 @@
#define QCOM_RPM_SMD_KEY_STATE 0x54415453
#define QCOM_RPM_SCALING_ENABLE_ID 0x2
-#define __DEFINE_CLK_SMD_RPM(_platform, _name, _active, type, r_id, stat_id, \
- key) \
- static struct clk_smd_rpm _platform##_##_active; \
- static struct clk_smd_rpm _platform##_##_name = { \
+#define __DEFINE_CLK_SMD_RPM_PREFIX(_prefix, _name, _active, \
+ type, r_id, key) \
+ static struct clk_smd_rpm clk_smd_rpm_##_prefix##_active; \
+ static struct clk_smd_rpm clk_smd_rpm_##_prefix##_name = { \
.rpm_res_type = (type), \
.rpm_clk_id = (r_id), \
- .rpm_status_id = (stat_id), \
.rpm_key = (key), \
- .peer = &_platform##_##_active, \
+ .peer = &clk_smd_rpm_##_prefix##_active, \
.rate = INT_MAX, \
.hw.init = &(struct clk_init_data){ \
.ops = &clk_smd_rpm_ops, \
.name = #_name, \
- .parent_data = &(const struct clk_parent_data){ \
- .fw_name = "xo", \
- .name = "xo_board", \
- }, \
+ .parent_data = &(const struct clk_parent_data){ \
+ .fw_name = "xo", \
+ .name = "xo_board", \
+ }, \
.num_parents = 1, \
}, \
}; \
- static struct clk_smd_rpm _platform##_##_active = { \
+ static struct clk_smd_rpm clk_smd_rpm_##_prefix##_active = { \
.rpm_res_type = (type), \
.rpm_clk_id = (r_id), \
- .rpm_status_id = (stat_id), \
.active_only = true, \
.rpm_key = (key), \
- .peer = &_platform##_##_name, \
+ .peer = &clk_smd_rpm_##_prefix##_name, \
.rate = INT_MAX, \
.hw.init = &(struct clk_init_data){ \
.ops = &clk_smd_rpm_ops, \
.name = #_active, \
- .parent_data = &(const struct clk_parent_data){ \
- .fw_name = "xo", \
- .name = "xo_board", \
- }, \
+ .parent_data = &(const struct clk_parent_data){ \
+ .fw_name = "xo", \
+ .name = "xo_board", \
+ }, \
.num_parents = 1, \
}, \
}
-#define __DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active, type, r_id, \
- stat_id, r, key) \
- static struct clk_smd_rpm _platform##_##_active; \
- static struct clk_smd_rpm _platform##_##_name = { \
+#define __DEFINE_CLK_SMD_RPM(_name, _active, type, r_id, key) \
+ __DEFINE_CLK_SMD_RPM_PREFIX(/* empty */, _name, _active, \
+ type, r_id, key)
+
+#define __DEFINE_CLK_SMD_RPM_BRANCH_PREFIX(_prefix, _name, _active,\
+ type, r_id, r, key) \
+ static struct clk_smd_rpm clk_smd_rpm_##_prefix##_active; \
+ static struct clk_smd_rpm clk_smd_rpm_##_prefix##_name = { \
.rpm_res_type = (type), \
.rpm_clk_id = (r_id), \
- .rpm_status_id = (stat_id), \
.rpm_key = (key), \
.branch = true, \
- .peer = &_platform##_##_active, \
+ .peer = &clk_smd_rpm_##_prefix##_active, \
.rate = (r), \
.hw.init = &(struct clk_init_data){ \
.ops = &clk_smd_rpm_branch_ops, \
.name = #_name, \
- .parent_data = &(const struct clk_parent_data){ \
- .fw_name = "xo", \
- .name = "xo_board", \
- }, \
+ .parent_data = &(const struct clk_parent_data){ \
+ .fw_name = "xo", \
+ .name = "xo_board", \
+ }, \
.num_parents = 1, \
}, \
}; \
- static struct clk_smd_rpm _platform##_##_active = { \
+ static struct clk_smd_rpm clk_smd_rpm_##_prefix##_active = { \
.rpm_res_type = (type), \
.rpm_clk_id = (r_id), \
- .rpm_status_id = (stat_id), \
.active_only = true, \
.rpm_key = (key), \
.branch = true, \
- .peer = &_platform##_##_name, \
+ .peer = &clk_smd_rpm_##_prefix##_name, \
.rate = (r), \
.hw.init = &(struct clk_init_data){ \
.ops = &clk_smd_rpm_branch_ops, \
.name = #_active, \
- .parent_data = &(const struct clk_parent_data){ \
- .fw_name = "xo", \
- .name = "xo_board", \
- }, \
+ .parent_data = &(const struct clk_parent_data){ \
+ .fw_name = "xo", \
+ .name = "xo_board", \
+ }, \
.num_parents = 1, \
}, \
}
-#define DEFINE_CLK_SMD_RPM(_platform, _name, _active, type, r_id) \
- __DEFINE_CLK_SMD_RPM(_platform, _name, _active, type, r_id, \
- 0, QCOM_RPM_SMD_KEY_RATE)
-
-#define DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active, type, r_id, r) \
- __DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active, type, \
- r_id, 0, r, QCOM_RPM_SMD_KEY_ENABLE)
-
-#define DEFINE_CLK_SMD_RPM_QDSS(_platform, _name, _active, type, r_id) \
- __DEFINE_CLK_SMD_RPM(_platform, _name, _active, type, r_id, \
- 0, QCOM_RPM_SMD_KEY_STATE)
+#define __DEFINE_CLK_SMD_RPM_BRANCH(_name, _active, type, r_id, r, key) \
+ __DEFINE_CLK_SMD_RPM_BRANCH_PREFIX(/* empty */, \
+ _name, _active, type, r_id, r, key)
+
+#define DEFINE_CLK_SMD_RPM(_name, type, r_id) \
+ __DEFINE_CLK_SMD_RPM(_name##_clk, _name##_a_clk, \
+ type, r_id, QCOM_RPM_SMD_KEY_RATE)
+
+#define DEFINE_CLK_SMD_RPM_BUS(_name, r_id) \
+ __DEFINE_CLK_SMD_RPM_PREFIX(bus_##r_id##_, \
+ _name##_clk, _name##_a_clk, QCOM_SMD_RPM_BUS_CLK, r_id, \
+ QCOM_RPM_SMD_KEY_RATE)
+
+#define DEFINE_CLK_SMD_RPM_CLK_SRC(_name, type, r_id) \
+ __DEFINE_CLK_SMD_RPM( \
+ _name##_clk_src, _name##_a_clk_src, \
+ type, r_id, QCOM_RPM_SMD_KEY_RATE)
+
+#define DEFINE_CLK_SMD_RPM_BRANCH(_name, type, r_id, r) \
+ __DEFINE_CLK_SMD_RPM_BRANCH_PREFIX(branch_, \
+ _name##_clk, _name##_a_clk, \
+ type, r_id, r, QCOM_RPM_SMD_KEY_ENABLE)
+
+#define DEFINE_CLK_SMD_RPM_BRANCH_A(_name, type, r_id, r) \
+ __DEFINE_CLK_SMD_RPM_BRANCH_PREFIX(branch_, \
+ _name, _name##_a, type, \
+ r_id, r, QCOM_RPM_SMD_KEY_ENABLE)
+
+#define DEFINE_CLK_SMD_RPM_QDSS(_name, type, r_id) \
+ __DEFINE_CLK_SMD_RPM(_name##_clk, _name##_a_clk, \
+ type, r_id, QCOM_RPM_SMD_KEY_STATE)
+
+#define DEFINE_CLK_SMD_RPM_XO_BUFFER(_name, r_id, r) \
+ __DEFINE_CLK_SMD_RPM_BRANCH(_name, _name##_a, \
+ QCOM_SMD_RPM_CLK_BUF_A, r_id, r, \
+ QCOM_RPM_KEY_SOFTWARE_ENABLE)
-#define DEFINE_CLK_SMD_RPM_XO_BUFFER(_platform, _name, _active, r_id, r) \
- __DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active, \
- QCOM_SMD_RPM_CLK_BUF_A, r_id, 0, r, \
+#define DEFINE_CLK_SMD_RPM_XO_BUFFER_PREFIX(_prefix, _name, r_id, r) \
+ __DEFINE_CLK_SMD_RPM_BRANCH_PREFIX(_prefix, \
+ _name, _name##_a, \
+ QCOM_SMD_RPM_CLK_BUF_A, r_id, r, \
QCOM_RPM_KEY_SOFTWARE_ENABLE)
-#define DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(_platform, _name, _active, \
- r_id, r) \
- __DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active, \
- QCOM_SMD_RPM_CLK_BUF_A, r_id, 0, r, \
+#define DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(_name, r_id, r) \
+ DEFINE_CLK_SMD_RPM_XO_BUFFER(_name, r_id, r); \
+ __DEFINE_CLK_SMD_RPM_BRANCH(_name##_pin, _name##_a##_pin, \
+ QCOM_SMD_RPM_CLK_BUF_A, r_id, r, \
QCOM_RPM_KEY_PIN_CTRL_CLK_BUFFER_ENABLE_KEY)
#define to_clk_smd_rpm(_hw) container_of(_hw, struct clk_smd_rpm, hw)
@@ -134,7 +160,6 @@ struct clk_smd_rpm {
const int rpm_res_type;
const int rpm_key;
const int rpm_clk_id;
- const int rpm_status_id;
const bool active_only;
bool enabled;
bool branch;
@@ -413,48 +438,102 @@ static const struct clk_ops clk_smd_rpm_branch_ops = {
.recalc_rate = clk_smd_rpm_recalc_rate,
};
-DEFINE_CLK_SMD_RPM_BRANCH(sdm660, bi_tcxo, bi_tcxo_a, QCOM_SMD_RPM_MISC_CLK, 0, 19200000);
-DEFINE_CLK_SMD_RPM(msm8916, pcnoc_clk, pcnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 0);
-DEFINE_CLK_SMD_RPM(msm8916, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1);
-DEFINE_CLK_SMD_RPM(msm8916, bimc_clk, bimc_a_clk, QCOM_SMD_RPM_MEM_CLK, 0);
-DEFINE_CLK_SMD_RPM(qcs404, qpic_clk, qpic_a_clk, QCOM_SMD_RPM_QPIC_CLK, 0);
-DEFINE_CLK_SMD_RPM_QDSS(msm8916, qdss_clk, qdss_a_clk, QCOM_SMD_RPM_MISC_CLK, 1);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8916, bb_clk1, bb_clk1_a, 1, 19200000);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8916, bb_clk2, bb_clk2_a, 2, 19200000);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8916, rf_clk1, rf_clk1_a, 4, 19200000);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8916, rf_clk2, rf_clk2_a, 5, 19200000);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8916, bb_clk1_pin, bb_clk1_a_pin, 1, 19200000);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8916, bb_clk2_pin, bb_clk2_a_pin, 2, 19200000);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8916, rf_clk1_pin, rf_clk1_a_pin, 4, 19200000);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8916, rf_clk2_pin, rf_clk2_a_pin, 5, 19200000);
+DEFINE_CLK_SMD_RPM_BRANCH_A(bi_tcxo, QCOM_SMD_RPM_MISC_CLK, 0, 19200000);
+DEFINE_CLK_SMD_RPM_BRANCH(qdss, QCOM_SMD_RPM_MISC_CLK, 1, 19200000);
+DEFINE_CLK_SMD_RPM_QDSS(qdss, QCOM_SMD_RPM_MISC_CLK, 1);
+DEFINE_CLK_SMD_RPM_BRANCH_A(bimc_freq_log, QCOM_SMD_RPM_MISC_CLK, 4, 1);
+
+DEFINE_CLK_SMD_RPM_BRANCH(mss_cfg_ahb, QCOM_SMD_RPM_MCFG_CLK, 0, 19200000);
+
+DEFINE_CLK_SMD_RPM_BRANCH(aggre1_noc, QCOM_SMD_RPM_AGGR_CLK, 1, 1000);
+DEFINE_CLK_SMD_RPM_BRANCH(aggre2_noc, QCOM_SMD_RPM_AGGR_CLK, 2, 1000);
+DEFINE_CLK_SMD_RPM(aggre1_noc, QCOM_SMD_RPM_AGGR_CLK, 1);
+DEFINE_CLK_SMD_RPM(aggre2_noc, QCOM_SMD_RPM_AGGR_CLK, 2);
+
+DEFINE_CLK_SMD_RPM_BUS(pcnoc, 0);
+DEFINE_CLK_SMD_RPM_BUS(snoc, 1);
+DEFINE_CLK_SMD_RPM_BUS(sysmmnoc, 2);
+DEFINE_CLK_SMD_RPM_BUS(cnoc, 2);
+DEFINE_CLK_SMD_RPM_BUS(mmssnoc_ahb, 3);
+DEFINE_CLK_SMD_RPM_BUS(snoc_periph, 0);
+DEFINE_CLK_SMD_RPM_BUS(cnoc, 1);
+DEFINE_CLK_SMD_RPM_BUS(snoc, 2);
+DEFINE_CLK_SMD_RPM_BUS(snoc_lpass, 5);
+
+DEFINE_CLK_SMD_RPM(bimc, QCOM_SMD_RPM_MEM_CLK, 0);
+DEFINE_CLK_SMD_RPM(cpuss_gnoc, QCOM_SMD_RPM_MEM_CLK, 1);
+DEFINE_CLK_SMD_RPM_CLK_SRC(gfx3d, QCOM_SMD_RPM_MEM_CLK, 1);
+DEFINE_CLK_SMD_RPM(ocmemgx, QCOM_SMD_RPM_MEM_CLK, 2);
+DEFINE_CLK_SMD_RPM(bimc_gpu, QCOM_SMD_RPM_MEM_CLK, 2);
+
+DEFINE_CLK_SMD_RPM(ce1, QCOM_SMD_RPM_CE_CLK, 0);
+DEFINE_CLK_SMD_RPM(ce2, QCOM_SMD_RPM_CE_CLK, 1);
+DEFINE_CLK_SMD_RPM(ce3, QCOM_SMD_RPM_CE_CLK, 2);
+
+DEFINE_CLK_SMD_RPM(ipa, QCOM_SMD_RPM_IPA_CLK, 0);
+
+DEFINE_CLK_SMD_RPM(hwkm, QCOM_SMD_RPM_HWKM_CLK, 0);
+
+DEFINE_CLK_SMD_RPM(mmssnoc_axi_rpm, QCOM_SMD_RPM_MMAXI_CLK, 0);
+DEFINE_CLK_SMD_RPM(mmnrt, QCOM_SMD_RPM_MMAXI_CLK, 0);
+DEFINE_CLK_SMD_RPM(mmrt, QCOM_SMD_RPM_MMAXI_CLK, 1);
+
+DEFINE_CLK_SMD_RPM(pka, QCOM_SMD_RPM_PKA_CLK, 0);
+
+DEFINE_CLK_SMD_RPM(qpic, QCOM_SMD_RPM_QPIC_CLK, 0);
+
+DEFINE_CLK_SMD_RPM(qup, QCOM_SMD_RPM_QUP_CLK, 0);
+
+DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(bb_clk1, 1, 19200000);
+DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(bb_clk2, 2, 19200000);
+DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(ln_bb_clk1, 1, 19200000);
+DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(ln_bb_clk2, 2, 19200000);
+DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(ln_bb_clk3, 3, 19200000);
+DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(rf_clk1, 4, 19200000);
+DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(rf_clk2, 5, 19200000);
+DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(rf_clk3, 6, 19200000);
+DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(ln_bb_clk, 8, 19200000);
+
+DEFINE_CLK_SMD_RPM_XO_BUFFER_PREFIX(38m4_, rf_clk3, 6, 38400000);
+
+DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(cxo_d0, 1, 19200000);
+DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(cxo_d1, 2, 19200000);
+DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(cxo_a0, 4, 19200000);
+DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(cxo_a1, 5, 19200000);
+DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(cxo_a2, 6, 19200000);
+
+DEFINE_CLK_SMD_RPM_XO_BUFFER(diff_clk, 7, 19200000);
+DEFINE_CLK_SMD_RPM_XO_BUFFER(div_clk1, 11, 19200000);
+DEFINE_CLK_SMD_RPM_XO_BUFFER(div_clk2, 12, 19200000);
+DEFINE_CLK_SMD_RPM_XO_BUFFER(div_clk3, 13, 19200000);
static struct clk_smd_rpm *msm8909_clks[] = {
- [RPM_SMD_PCNOC_CLK] = &msm8916_pcnoc_clk,
- [RPM_SMD_PCNOC_A_CLK] = &msm8916_pcnoc_a_clk,
- [RPM_SMD_SNOC_CLK] = &msm8916_snoc_clk,
- [RPM_SMD_SNOC_A_CLK] = &msm8916_snoc_a_clk,
- [RPM_SMD_BIMC_CLK] = &msm8916_bimc_clk,
- [RPM_SMD_BIMC_A_CLK] = &msm8916_bimc_a_clk,
- [RPM_SMD_QPIC_CLK] = &qcs404_qpic_clk,
- [RPM_SMD_QPIC_CLK_A] = &qcs404_qpic_a_clk,
- [RPM_SMD_QDSS_CLK] = &msm8916_qdss_clk,
- [RPM_SMD_QDSS_A_CLK] = &msm8916_qdss_a_clk,
- [RPM_SMD_BB_CLK1] = &msm8916_bb_clk1,
- [RPM_SMD_BB_CLK1_A] = &msm8916_bb_clk1_a,
- [RPM_SMD_BB_CLK2] = &msm8916_bb_clk2,
- [RPM_SMD_BB_CLK2_A] = &msm8916_bb_clk2_a,
- [RPM_SMD_RF_CLK1] = &msm8916_rf_clk1,
- [RPM_SMD_RF_CLK1_A] = &msm8916_rf_clk1_a,
- [RPM_SMD_RF_CLK2] = &msm8916_rf_clk2,
- [RPM_SMD_RF_CLK2_A] = &msm8916_rf_clk2_a,
- [RPM_SMD_BB_CLK1_PIN] = &msm8916_bb_clk1_pin,
- [RPM_SMD_BB_CLK1_A_PIN] = &msm8916_bb_clk1_a_pin,
- [RPM_SMD_BB_CLK2_PIN] = &msm8916_bb_clk2_pin,
- [RPM_SMD_BB_CLK2_A_PIN] = &msm8916_bb_clk2_a_pin,
- [RPM_SMD_RF_CLK1_PIN] = &msm8916_rf_clk1_pin,
- [RPM_SMD_RF_CLK1_A_PIN] = &msm8916_rf_clk1_a_pin,
- [RPM_SMD_RF_CLK2_PIN] = &msm8916_rf_clk2_pin,
- [RPM_SMD_RF_CLK2_A_PIN] = &msm8916_rf_clk2_a_pin,
+ [RPM_SMD_PCNOC_CLK] = &clk_smd_rpm_bus_0_pcnoc_clk,
+ [RPM_SMD_PCNOC_A_CLK] = &clk_smd_rpm_bus_0_pcnoc_a_clk,
+ [RPM_SMD_SNOC_CLK] = &clk_smd_rpm_bus_1_snoc_clk,
+ [RPM_SMD_SNOC_A_CLK] = &clk_smd_rpm_bus_1_snoc_a_clk,
+ [RPM_SMD_BIMC_CLK] = &clk_smd_rpm_bimc_clk,
+ [RPM_SMD_BIMC_A_CLK] = &clk_smd_rpm_bimc_a_clk,
+ [RPM_SMD_QPIC_CLK] = &clk_smd_rpm_qpic_clk,
+ [RPM_SMD_QPIC_CLK_A] = &clk_smd_rpm_qpic_a_clk,
+ [RPM_SMD_QDSS_CLK] = &clk_smd_rpm_qdss_clk,
+ [RPM_SMD_QDSS_A_CLK] = &clk_smd_rpm_qdss_a_clk,
+ [RPM_SMD_BB_CLK1] = &clk_smd_rpm_bb_clk1,
+ [RPM_SMD_BB_CLK1_A] = &clk_smd_rpm_bb_clk1_a,
+ [RPM_SMD_BB_CLK2] = &clk_smd_rpm_bb_clk2,
+ [RPM_SMD_BB_CLK2_A] = &clk_smd_rpm_bb_clk2_a,
+ [RPM_SMD_RF_CLK1] = &clk_smd_rpm_rf_clk1,
+ [RPM_SMD_RF_CLK1_A] = &clk_smd_rpm_rf_clk1_a,
+ [RPM_SMD_RF_CLK2] = &clk_smd_rpm_rf_clk2,
+ [RPM_SMD_RF_CLK2_A] = &clk_smd_rpm_rf_clk2_a,
+ [RPM_SMD_BB_CLK1_PIN] = &clk_smd_rpm_bb_clk1_pin,
+ [RPM_SMD_BB_CLK1_A_PIN] = &clk_smd_rpm_bb_clk1_a_pin,
+ [RPM_SMD_BB_CLK2_PIN] = &clk_smd_rpm_bb_clk2_pin,
+ [RPM_SMD_BB_CLK2_A_PIN] = &clk_smd_rpm_bb_clk2_a_pin,
+ [RPM_SMD_RF_CLK1_PIN] = &clk_smd_rpm_rf_clk1_pin,
+ [RPM_SMD_RF_CLK1_A_PIN] = &clk_smd_rpm_rf_clk1_a_pin,
+ [RPM_SMD_RF_CLK2_PIN] = &clk_smd_rpm_rf_clk2_pin,
+ [RPM_SMD_RF_CLK2_A_PIN] = &clk_smd_rpm_rf_clk2_a_pin,
};
static const struct rpm_smd_clk_desc rpm_clk_msm8909 = {
@@ -463,30 +542,30 @@ static const struct rpm_smd_clk_desc rpm_clk_msm8909 = {
};
static struct clk_smd_rpm *msm8916_clks[] = {
- [RPM_SMD_PCNOC_CLK] = &msm8916_pcnoc_clk,
- [RPM_SMD_PCNOC_A_CLK] = &msm8916_pcnoc_a_clk,
- [RPM_SMD_SNOC_CLK] = &msm8916_snoc_clk,
- [RPM_SMD_SNOC_A_CLK] = &msm8916_snoc_a_clk,
- [RPM_SMD_BIMC_CLK] = &msm8916_bimc_clk,
- [RPM_SMD_BIMC_A_CLK] = &msm8916_bimc_a_clk,
- [RPM_SMD_QDSS_CLK] = &msm8916_qdss_clk,
- [RPM_SMD_QDSS_A_CLK] = &msm8916_qdss_a_clk,
- [RPM_SMD_BB_CLK1] = &msm8916_bb_clk1,
- [RPM_SMD_BB_CLK1_A] = &msm8916_bb_clk1_a,
- [RPM_SMD_BB_CLK2] = &msm8916_bb_clk2,
- [RPM_SMD_BB_CLK2_A] = &msm8916_bb_clk2_a,
- [RPM_SMD_RF_CLK1] = &msm8916_rf_clk1,
- [RPM_SMD_RF_CLK1_A] = &msm8916_rf_clk1_a,
- [RPM_SMD_RF_CLK2] = &msm8916_rf_clk2,
- [RPM_SMD_RF_CLK2_A] = &msm8916_rf_clk2_a,
- [RPM_SMD_BB_CLK1_PIN] = &msm8916_bb_clk1_pin,
- [RPM_SMD_BB_CLK1_A_PIN] = &msm8916_bb_clk1_a_pin,
- [RPM_SMD_BB_CLK2_PIN] = &msm8916_bb_clk2_pin,
- [RPM_SMD_BB_CLK2_A_PIN] = &msm8916_bb_clk2_a_pin,
- [RPM_SMD_RF_CLK1_PIN] = &msm8916_rf_clk1_pin,
- [RPM_SMD_RF_CLK1_A_PIN] = &msm8916_rf_clk1_a_pin,
- [RPM_SMD_RF_CLK2_PIN] = &msm8916_rf_clk2_pin,
- [RPM_SMD_RF_CLK2_A_PIN] = &msm8916_rf_clk2_a_pin,
+ [RPM_SMD_PCNOC_CLK] = &clk_smd_rpm_bus_0_pcnoc_clk,
+ [RPM_SMD_PCNOC_A_CLK] = &clk_smd_rpm_bus_0_pcnoc_a_clk,
+ [RPM_SMD_SNOC_CLK] = &clk_smd_rpm_bus_1_snoc_clk,
+ [RPM_SMD_SNOC_A_CLK] = &clk_smd_rpm_bus_1_snoc_a_clk,
+ [RPM_SMD_BIMC_CLK] = &clk_smd_rpm_bimc_clk,
+ [RPM_SMD_BIMC_A_CLK] = &clk_smd_rpm_bimc_a_clk,
+ [RPM_SMD_QDSS_CLK] = &clk_smd_rpm_qdss_clk,
+ [RPM_SMD_QDSS_A_CLK] = &clk_smd_rpm_qdss_a_clk,
+ [RPM_SMD_BB_CLK1] = &clk_smd_rpm_bb_clk1,
+ [RPM_SMD_BB_CLK1_A] = &clk_smd_rpm_bb_clk1_a,
+ [RPM_SMD_BB_CLK2] = &clk_smd_rpm_bb_clk2,
+ [RPM_SMD_BB_CLK2_A] = &clk_smd_rpm_bb_clk2_a,
+ [RPM_SMD_RF_CLK1] = &clk_smd_rpm_rf_clk1,
+ [RPM_SMD_RF_CLK1_A] = &clk_smd_rpm_rf_clk1_a,
+ [RPM_SMD_RF_CLK2] = &clk_smd_rpm_rf_clk2,
+ [RPM_SMD_RF_CLK2_A] = &clk_smd_rpm_rf_clk2_a,
+ [RPM_SMD_BB_CLK1_PIN] = &clk_smd_rpm_bb_clk1_pin,
+ [RPM_SMD_BB_CLK1_A_PIN] = &clk_smd_rpm_bb_clk1_a_pin,
+ [RPM_SMD_BB_CLK2_PIN] = &clk_smd_rpm_bb_clk2_pin,
+ [RPM_SMD_BB_CLK2_A_PIN] = &clk_smd_rpm_bb_clk2_a_pin,
+ [RPM_SMD_RF_CLK1_PIN] = &clk_smd_rpm_rf_clk1_pin,
+ [RPM_SMD_RF_CLK1_A_PIN] = &clk_smd_rpm_rf_clk1_a_pin,
+ [RPM_SMD_RF_CLK2_PIN] = &clk_smd_rpm_rf_clk2_pin,
+ [RPM_SMD_RF_CLK2_A_PIN] = &clk_smd_rpm_rf_clk2_a_pin,
};
static const struct rpm_smd_clk_desc rpm_clk_msm8916 = {
@@ -494,35 +573,35 @@ static const struct rpm_smd_clk_desc rpm_clk_msm8916 = {
.num_clks = ARRAY_SIZE(msm8916_clks),
};
-DEFINE_CLK_SMD_RPM(msm8936, sysmmnoc_clk, sysmmnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 2);
-
static struct clk_smd_rpm *msm8936_clks[] = {
- [RPM_SMD_PCNOC_CLK] = &msm8916_pcnoc_clk,
- [RPM_SMD_PCNOC_A_CLK] = &msm8916_pcnoc_a_clk,
- [RPM_SMD_SNOC_CLK] = &msm8916_snoc_clk,
- [RPM_SMD_SNOC_A_CLK] = &msm8916_snoc_a_clk,
- [RPM_SMD_BIMC_CLK] = &msm8916_bimc_clk,
- [RPM_SMD_BIMC_A_CLK] = &msm8916_bimc_a_clk,
- [RPM_SMD_SYSMMNOC_CLK] = &msm8936_sysmmnoc_clk,
- [RPM_SMD_SYSMMNOC_A_CLK] = &msm8936_sysmmnoc_a_clk,
- [RPM_SMD_QDSS_CLK] = &msm8916_qdss_clk,
- [RPM_SMD_QDSS_A_CLK] = &msm8916_qdss_a_clk,
- [RPM_SMD_BB_CLK1] = &msm8916_bb_clk1,
- [RPM_SMD_BB_CLK1_A] = &msm8916_bb_clk1_a,
- [RPM_SMD_BB_CLK2] = &msm8916_bb_clk2,
- [RPM_SMD_BB_CLK2_A] = &msm8916_bb_clk2_a,
- [RPM_SMD_RF_CLK1] = &msm8916_rf_clk1,
- [RPM_SMD_RF_CLK1_A] = &msm8916_rf_clk1_a,
- [RPM_SMD_RF_CLK2] = &msm8916_rf_clk2,
- [RPM_SMD_RF_CLK2_A] = &msm8916_rf_clk2_a,
- [RPM_SMD_BB_CLK1_PIN] = &msm8916_bb_clk1_pin,
- [RPM_SMD_BB_CLK1_A_PIN] = &msm8916_bb_clk1_a_pin,
- [RPM_SMD_BB_CLK2_PIN] = &msm8916_bb_clk2_pin,
- [RPM_SMD_BB_CLK2_A_PIN] = &msm8916_bb_clk2_a_pin,
- [RPM_SMD_RF_CLK1_PIN] = &msm8916_rf_clk1_pin,
- [RPM_SMD_RF_CLK1_A_PIN] = &msm8916_rf_clk1_a_pin,
- [RPM_SMD_RF_CLK2_PIN] = &msm8916_rf_clk2_pin,
- [RPM_SMD_RF_CLK2_A_PIN] = &msm8916_rf_clk2_a_pin,
+ [RPM_SMD_XO_CLK_SRC] = &clk_smd_rpm_branch_bi_tcxo,
+ [RPM_SMD_XO_A_CLK_SRC] = &clk_smd_rpm_branch_bi_tcxo_a,
+ [RPM_SMD_PCNOC_CLK] = &clk_smd_rpm_bus_0_pcnoc_clk,
+ [RPM_SMD_PCNOC_A_CLK] = &clk_smd_rpm_bus_0_pcnoc_a_clk,
+ [RPM_SMD_SNOC_CLK] = &clk_smd_rpm_bus_1_snoc_clk,
+ [RPM_SMD_SNOC_A_CLK] = &clk_smd_rpm_bus_1_snoc_a_clk,
+ [RPM_SMD_BIMC_CLK] = &clk_smd_rpm_bimc_clk,
+ [RPM_SMD_BIMC_A_CLK] = &clk_smd_rpm_bimc_a_clk,
+ [RPM_SMD_SYSMMNOC_CLK] = &clk_smd_rpm_bus_2_sysmmnoc_clk,
+ [RPM_SMD_SYSMMNOC_A_CLK] = &clk_smd_rpm_bus_2_sysmmnoc_a_clk,
+ [RPM_SMD_QDSS_CLK] = &clk_smd_rpm_qdss_clk,
+ [RPM_SMD_QDSS_A_CLK] = &clk_smd_rpm_qdss_a_clk,
+ [RPM_SMD_BB_CLK1] = &clk_smd_rpm_bb_clk1,
+ [RPM_SMD_BB_CLK1_A] = &clk_smd_rpm_bb_clk1_a,
+ [RPM_SMD_BB_CLK2] = &clk_smd_rpm_bb_clk2,
+ [RPM_SMD_BB_CLK2_A] = &clk_smd_rpm_bb_clk2_a,
+ [RPM_SMD_RF_CLK1] = &clk_smd_rpm_rf_clk1,
+ [RPM_SMD_RF_CLK1_A] = &clk_smd_rpm_rf_clk1_a,
+ [RPM_SMD_RF_CLK2] = &clk_smd_rpm_rf_clk2,
+ [RPM_SMD_RF_CLK2_A] = &clk_smd_rpm_rf_clk2_a,
+ [RPM_SMD_BB_CLK1_PIN] = &clk_smd_rpm_bb_clk1_pin,
+ [RPM_SMD_BB_CLK1_A_PIN] = &clk_smd_rpm_bb_clk1_a_pin,
+ [RPM_SMD_BB_CLK2_PIN] = &clk_smd_rpm_bb_clk2_pin,
+ [RPM_SMD_BB_CLK2_A_PIN] = &clk_smd_rpm_bb_clk2_a_pin,
+ [RPM_SMD_RF_CLK1_PIN] = &clk_smd_rpm_rf_clk1_pin,
+ [RPM_SMD_RF_CLK1_A_PIN] = &clk_smd_rpm_rf_clk1_a_pin,
+ [RPM_SMD_RF_CLK2_PIN] = &clk_smd_rpm_rf_clk2_pin,
+ [RPM_SMD_RF_CLK2_A_PIN] = &clk_smd_rpm_rf_clk2_a_pin,
};
static const struct rpm_smd_clk_desc rpm_clk_msm8936 = {
@@ -530,67 +609,49 @@ static const struct rpm_smd_clk_desc rpm_clk_msm8936 = {
.num_clks = ARRAY_SIZE(msm8936_clks),
};
-DEFINE_CLK_SMD_RPM(msm8974, cnoc_clk, cnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 2);
-DEFINE_CLK_SMD_RPM(msm8974, mmssnoc_ahb_clk, mmssnoc_ahb_a_clk, QCOM_SMD_RPM_BUS_CLK, 3);
-DEFINE_CLK_SMD_RPM(msm8974, gfx3d_clk_src, gfx3d_a_clk_src, QCOM_SMD_RPM_MEM_CLK, 1);
-DEFINE_CLK_SMD_RPM(msm8974, ocmemgx_clk, ocmemgx_a_clk, QCOM_SMD_RPM_MEM_CLK, 2);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, cxo_d0, cxo_d0_a, 1, 19200000);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, cxo_d1, cxo_d1_a, 2, 19200000);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, cxo_a0, cxo_a0_a, 4, 19200000);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, cxo_a1, cxo_a1_a, 5, 19200000);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, cxo_a2, cxo_a2_a, 6, 19200000);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, diff_clk, diff_a_clk, 7, 19200000);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, div_clk1, div_a_clk1, 11, 19200000);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, div_clk2, div_a_clk2, 12, 19200000);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8974, cxo_d0_pin, cxo_d0_a_pin, 1, 19200000);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8974, cxo_d1_pin, cxo_d1_a_pin, 2, 19200000);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8974, cxo_a0_pin, cxo_a0_a_pin, 4, 19200000);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8974, cxo_a1_pin, cxo_a1_a_pin, 5, 19200000);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8974, cxo_a2_pin, cxo_a2_a_pin, 6, 19200000);
-
static struct clk_smd_rpm *msm8974_clks[] = {
- [RPM_SMD_PNOC_CLK] = &msm8916_pcnoc_clk,
- [RPM_SMD_PNOC_A_CLK] = &msm8916_pcnoc_a_clk,
- [RPM_SMD_SNOC_CLK] = &msm8916_snoc_clk,
- [RPM_SMD_SNOC_A_CLK] = &msm8916_snoc_a_clk,
- [RPM_SMD_CNOC_CLK] = &msm8974_cnoc_clk,
- [RPM_SMD_CNOC_A_CLK] = &msm8974_cnoc_a_clk,
- [RPM_SMD_MMSSNOC_AHB_CLK] = &msm8974_mmssnoc_ahb_clk,
- [RPM_SMD_MMSSNOC_AHB_A_CLK] = &msm8974_mmssnoc_ahb_a_clk,
- [RPM_SMD_BIMC_CLK] = &msm8916_bimc_clk,
- [RPM_SMD_GFX3D_CLK_SRC] = &msm8974_gfx3d_clk_src,
- [RPM_SMD_GFX3D_A_CLK_SRC] = &msm8974_gfx3d_a_clk_src,
- [RPM_SMD_BIMC_A_CLK] = &msm8916_bimc_a_clk,
- [RPM_SMD_OCMEMGX_CLK] = &msm8974_ocmemgx_clk,
- [RPM_SMD_OCMEMGX_A_CLK] = &msm8974_ocmemgx_a_clk,
- [RPM_SMD_QDSS_CLK] = &msm8916_qdss_clk,
- [RPM_SMD_QDSS_A_CLK] = &msm8916_qdss_a_clk,
- [RPM_SMD_CXO_D0] = &msm8974_cxo_d0,
- [RPM_SMD_CXO_D0_A] = &msm8974_cxo_d0_a,
- [RPM_SMD_CXO_D1] = &msm8974_cxo_d1,
- [RPM_SMD_CXO_D1_A] = &msm8974_cxo_d1_a,
- [RPM_SMD_CXO_A0] = &msm8974_cxo_a0,
- [RPM_SMD_CXO_A0_A] = &msm8974_cxo_a0_a,
- [RPM_SMD_CXO_A1] = &msm8974_cxo_a1,
- [RPM_SMD_CXO_A1_A] = &msm8974_cxo_a1_a,
- [RPM_SMD_CXO_A2] = &msm8974_cxo_a2,
- [RPM_SMD_CXO_A2_A] = &msm8974_cxo_a2_a,
- [RPM_SMD_DIFF_CLK] = &msm8974_diff_clk,
- [RPM_SMD_DIFF_A_CLK] = &msm8974_diff_a_clk,
- [RPM_SMD_DIV_CLK1] = &msm8974_div_clk1,
- [RPM_SMD_DIV_A_CLK1] = &msm8974_div_a_clk1,
- [RPM_SMD_DIV_CLK2] = &msm8974_div_clk2,
- [RPM_SMD_DIV_A_CLK2] = &msm8974_div_a_clk2,
- [RPM_SMD_CXO_D0_PIN] = &msm8974_cxo_d0_pin,
- [RPM_SMD_CXO_D0_A_PIN] = &msm8974_cxo_d0_a_pin,
- [RPM_SMD_CXO_D1_PIN] = &msm8974_cxo_d1_pin,
- [RPM_SMD_CXO_D1_A_PIN] = &msm8974_cxo_d1_a_pin,
- [RPM_SMD_CXO_A0_PIN] = &msm8974_cxo_a0_pin,
- [RPM_SMD_CXO_A0_A_PIN] = &msm8974_cxo_a0_a_pin,
- [RPM_SMD_CXO_A1_PIN] = &msm8974_cxo_a1_pin,
- [RPM_SMD_CXO_A1_A_PIN] = &msm8974_cxo_a1_a_pin,
- [RPM_SMD_CXO_A2_PIN] = &msm8974_cxo_a2_pin,
- [RPM_SMD_CXO_A2_A_PIN] = &msm8974_cxo_a2_a_pin,
+ [RPM_SMD_PNOC_CLK] = &clk_smd_rpm_bus_0_pcnoc_clk,
+ [RPM_SMD_PNOC_A_CLK] = &clk_smd_rpm_bus_0_pcnoc_a_clk,
+ [RPM_SMD_SNOC_CLK] = &clk_smd_rpm_bus_1_snoc_clk,
+ [RPM_SMD_SNOC_A_CLK] = &clk_smd_rpm_bus_1_snoc_a_clk,
+ [RPM_SMD_CNOC_CLK] = &clk_smd_rpm_bus_2_cnoc_clk,
+ [RPM_SMD_CNOC_A_CLK] = &clk_smd_rpm_bus_2_cnoc_a_clk,
+ [RPM_SMD_MMSSNOC_AHB_CLK] = &clk_smd_rpm_bus_3_mmssnoc_ahb_clk,
+ [RPM_SMD_MMSSNOC_AHB_A_CLK] = &clk_smd_rpm_bus_3_mmssnoc_ahb_a_clk,
+ [RPM_SMD_BIMC_CLK] = &clk_smd_rpm_bimc_clk,
+ [RPM_SMD_GFX3D_CLK_SRC] = &clk_smd_rpm_gfx3d_clk_src,
+ [RPM_SMD_GFX3D_A_CLK_SRC] = &clk_smd_rpm_gfx3d_a_clk_src,
+ [RPM_SMD_BIMC_A_CLK] = &clk_smd_rpm_bimc_a_clk,
+ [RPM_SMD_OCMEMGX_CLK] = &clk_smd_rpm_ocmemgx_clk,
+ [RPM_SMD_OCMEMGX_A_CLK] = &clk_smd_rpm_ocmemgx_a_clk,
+ [RPM_SMD_QDSS_CLK] = &clk_smd_rpm_qdss_clk,
+ [RPM_SMD_QDSS_A_CLK] = &clk_smd_rpm_qdss_a_clk,
+ [RPM_SMD_CXO_D0] = &clk_smd_rpm_cxo_d0,
+ [RPM_SMD_CXO_D0_A] = &clk_smd_rpm_cxo_d0_a,
+ [RPM_SMD_CXO_D1] = &clk_smd_rpm_cxo_d1,
+ [RPM_SMD_CXO_D1_A] = &clk_smd_rpm_cxo_d1_a,
+ [RPM_SMD_CXO_A0] = &clk_smd_rpm_cxo_a0,
+ [RPM_SMD_CXO_A0_A] = &clk_smd_rpm_cxo_a0_a,
+ [RPM_SMD_CXO_A1] = &clk_smd_rpm_cxo_a1,
+ [RPM_SMD_CXO_A1_A] = &clk_smd_rpm_cxo_a1_a,
+ [RPM_SMD_CXO_A2] = &clk_smd_rpm_cxo_a2,
+ [RPM_SMD_CXO_A2_A] = &clk_smd_rpm_cxo_a2_a,
+ [RPM_SMD_DIFF_CLK] = &clk_smd_rpm_diff_clk,
+ [RPM_SMD_DIFF_A_CLK] = &clk_smd_rpm_diff_clk_a,
+ [RPM_SMD_DIV_CLK1] = &clk_smd_rpm_div_clk1,
+ [RPM_SMD_DIV_A_CLK1] = &clk_smd_rpm_div_clk1_a,
+ [RPM_SMD_DIV_CLK2] = &clk_smd_rpm_div_clk2,
+ [RPM_SMD_DIV_A_CLK2] = &clk_smd_rpm_div_clk2_a,
+ [RPM_SMD_CXO_D0_PIN] = &clk_smd_rpm_cxo_d0_pin,
+ [RPM_SMD_CXO_D0_A_PIN] = &clk_smd_rpm_cxo_d0_a_pin,
+ [RPM_SMD_CXO_D1_PIN] = &clk_smd_rpm_cxo_d1_pin,
+ [RPM_SMD_CXO_D1_A_PIN] = &clk_smd_rpm_cxo_d1_a_pin,
+ [RPM_SMD_CXO_A0_PIN] = &clk_smd_rpm_cxo_a0_pin,
+ [RPM_SMD_CXO_A0_A_PIN] = &clk_smd_rpm_cxo_a0_a_pin,
+ [RPM_SMD_CXO_A1_PIN] = &clk_smd_rpm_cxo_a1_pin,
+ [RPM_SMD_CXO_A1_A_PIN] = &clk_smd_rpm_cxo_a1_a_pin,
+ [RPM_SMD_CXO_A2_PIN] = &clk_smd_rpm_cxo_a2_pin,
+ [RPM_SMD_CXO_A2_A_PIN] = &clk_smd_rpm_cxo_a2_a_pin,
};
static const struct rpm_smd_clk_desc rpm_clk_msm8974 = {
@@ -598,35 +659,33 @@ static const struct rpm_smd_clk_desc rpm_clk_msm8974 = {
.num_clks = ARRAY_SIZE(msm8974_clks),
};
-DEFINE_CLK_SMD_RPM(msm8976, ipa_clk, ipa_a_clk, QCOM_SMD_RPM_IPA_CLK, 0);
-
static struct clk_smd_rpm *msm8976_clks[] = {
- [RPM_SMD_XO_CLK_SRC] = &sdm660_bi_tcxo,
- [RPM_SMD_XO_A_CLK_SRC] = &sdm660_bi_tcxo_a,
- [RPM_SMD_PCNOC_CLK] = &msm8916_pcnoc_clk,
- [RPM_SMD_PCNOC_A_CLK] = &msm8916_pcnoc_a_clk,
- [RPM_SMD_SNOC_CLK] = &msm8916_snoc_clk,
- [RPM_SMD_SNOC_A_CLK] = &msm8916_snoc_a_clk,
- [RPM_SMD_BIMC_CLK] = &msm8916_bimc_clk,
- [RPM_SMD_BIMC_A_CLK] = &msm8916_bimc_a_clk,
- [RPM_SMD_SYSMMNOC_CLK] = &msm8936_sysmmnoc_clk,
- [RPM_SMD_SYSMMNOC_A_CLK] = &msm8936_sysmmnoc_a_clk,
- [RPM_SMD_QDSS_CLK] = &msm8916_qdss_clk,
- [RPM_SMD_QDSS_A_CLK] = &msm8916_qdss_a_clk,
- [RPM_SMD_BB_CLK1] = &msm8916_bb_clk1,
- [RPM_SMD_BB_CLK1_A] = &msm8916_bb_clk1_a,
- [RPM_SMD_BB_CLK2] = &msm8916_bb_clk2,
- [RPM_SMD_BB_CLK2_A] = &msm8916_bb_clk2_a,
- [RPM_SMD_RF_CLK2] = &msm8916_rf_clk2,
- [RPM_SMD_RF_CLK2_A] = &msm8916_rf_clk2_a,
- [RPM_SMD_BB_CLK1_PIN] = &msm8916_bb_clk1_pin,
- [RPM_SMD_BB_CLK1_A_PIN] = &msm8916_bb_clk1_a_pin,
- [RPM_SMD_BB_CLK2_PIN] = &msm8916_bb_clk2_pin,
- [RPM_SMD_BB_CLK2_A_PIN] = &msm8916_bb_clk2_a_pin,
- [RPM_SMD_DIV_CLK2] = &msm8974_div_clk2,
- [RPM_SMD_DIV_A_CLK2] = &msm8974_div_a_clk2,
- [RPM_SMD_IPA_CLK] = &msm8976_ipa_clk,
- [RPM_SMD_IPA_A_CLK] = &msm8976_ipa_a_clk,
+ [RPM_SMD_XO_CLK_SRC] = &clk_smd_rpm_branch_bi_tcxo,
+ [RPM_SMD_XO_A_CLK_SRC] = &clk_smd_rpm_branch_bi_tcxo_a,
+ [RPM_SMD_PCNOC_CLK] = &clk_smd_rpm_bus_0_pcnoc_clk,
+ [RPM_SMD_PCNOC_A_CLK] = &clk_smd_rpm_bus_0_pcnoc_a_clk,
+ [RPM_SMD_SNOC_CLK] = &clk_smd_rpm_bus_1_snoc_clk,
+ [RPM_SMD_SNOC_A_CLK] = &clk_smd_rpm_bus_1_snoc_a_clk,
+ [RPM_SMD_BIMC_CLK] = &clk_smd_rpm_bimc_clk,
+ [RPM_SMD_BIMC_A_CLK] = &clk_smd_rpm_bimc_a_clk,
+ [RPM_SMD_SYSMMNOC_CLK] = &clk_smd_rpm_bus_2_sysmmnoc_clk,
+ [RPM_SMD_SYSMMNOC_A_CLK] = &clk_smd_rpm_bus_2_sysmmnoc_a_clk,
+ [RPM_SMD_QDSS_CLK] = &clk_smd_rpm_qdss_clk,
+ [RPM_SMD_QDSS_A_CLK] = &clk_smd_rpm_qdss_a_clk,
+ [RPM_SMD_BB_CLK1] = &clk_smd_rpm_bb_clk1,
+ [RPM_SMD_BB_CLK1_A] = &clk_smd_rpm_bb_clk1_a,
+ [RPM_SMD_BB_CLK2] = &clk_smd_rpm_bb_clk2,
+ [RPM_SMD_BB_CLK2_A] = &clk_smd_rpm_bb_clk2_a,
+ [RPM_SMD_RF_CLK2] = &clk_smd_rpm_rf_clk2,
+ [RPM_SMD_RF_CLK2_A] = &clk_smd_rpm_rf_clk2_a,
+ [RPM_SMD_BB_CLK1_PIN] = &clk_smd_rpm_bb_clk1_pin,
+ [RPM_SMD_BB_CLK1_A_PIN] = &clk_smd_rpm_bb_clk1_a_pin,
+ [RPM_SMD_BB_CLK2_PIN] = &clk_smd_rpm_bb_clk2_pin,
+ [RPM_SMD_BB_CLK2_A_PIN] = &clk_smd_rpm_bb_clk2_a_pin,
+ [RPM_SMD_DIV_CLK2] = &clk_smd_rpm_div_clk2,
+ [RPM_SMD_DIV_A_CLK2] = &clk_smd_rpm_div_clk2_a,
+ [RPM_SMD_IPA_CLK] = &clk_smd_rpm_ipa_clk,
+ [RPM_SMD_IPA_A_CLK] = &clk_smd_rpm_ipa_a_clk,
};
static const struct rpm_smd_clk_desc rpm_clk_msm8976 = {
@@ -634,65 +693,57 @@ static const struct rpm_smd_clk_desc rpm_clk_msm8976 = {
.num_clks = ARRAY_SIZE(msm8976_clks),
};
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8992, div_clk3, div_clk3_a, 13, 19200000);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8992, ln_bb_clk, ln_bb_a_clk, 8, 19200000);
-
-DEFINE_CLK_SMD_RPM(msm8992, ce1_clk, ce1_a_clk, QCOM_SMD_RPM_CE_CLK, 0);
-DEFINE_CLK_SMD_RPM(msm8992, ce2_clk, ce2_a_clk, QCOM_SMD_RPM_CE_CLK, 1);
-
-DEFINE_CLK_SMD_RPM_BRANCH(msm8992, mss_cfg_ahb_clk, mss_cfg_ahb_a_clk,
- QCOM_SMD_RPM_MCFG_CLK, 0, 19200000);
static struct clk_smd_rpm *msm8992_clks[] = {
- [RPM_SMD_XO_CLK_SRC] = &sdm660_bi_tcxo,
- [RPM_SMD_XO_A_CLK_SRC] = &sdm660_bi_tcxo_a,
- [RPM_SMD_PNOC_CLK] = &msm8916_pcnoc_clk,
- [RPM_SMD_PNOC_A_CLK] = &msm8916_pcnoc_a_clk,
- [RPM_SMD_OCMEMGX_CLK] = &msm8974_ocmemgx_clk,
- [RPM_SMD_OCMEMGX_A_CLK] = &msm8974_ocmemgx_a_clk,
- [RPM_SMD_BIMC_CLK] = &msm8916_bimc_clk,
- [RPM_SMD_BIMC_A_CLK] = &msm8916_bimc_a_clk,
- [RPM_SMD_CNOC_CLK] = &msm8974_cnoc_clk,
- [RPM_SMD_CNOC_A_CLK] = &msm8974_cnoc_a_clk,
- [RPM_SMD_GFX3D_CLK_SRC] = &msm8974_gfx3d_clk_src,
- [RPM_SMD_GFX3D_A_CLK_SRC] = &msm8974_gfx3d_a_clk_src,
- [RPM_SMD_SNOC_CLK] = &msm8916_snoc_clk,
- [RPM_SMD_SNOC_A_CLK] = &msm8916_snoc_a_clk,
- [RPM_SMD_BB_CLK1] = &msm8916_bb_clk1,
- [RPM_SMD_BB_CLK1_A] = &msm8916_bb_clk1_a,
- [RPM_SMD_BB_CLK1_PIN] = &msm8916_bb_clk1_pin,
- [RPM_SMD_BB_CLK1_A_PIN] = &msm8916_bb_clk1_a_pin,
- [RPM_SMD_BB_CLK2] = &msm8916_bb_clk2,
- [RPM_SMD_BB_CLK2_A] = &msm8916_bb_clk2_a,
- [RPM_SMD_BB_CLK2_PIN] = &msm8916_bb_clk2_pin,
- [RPM_SMD_BB_CLK2_A_PIN] = &msm8916_bb_clk2_a_pin,
- [RPM_SMD_DIV_CLK1] = &msm8974_div_clk1,
- [RPM_SMD_DIV_A_CLK1] = &msm8974_div_a_clk1,
- [RPM_SMD_DIV_CLK2] = &msm8974_div_clk2,
- [RPM_SMD_DIV_A_CLK2] = &msm8974_div_a_clk2,
- [RPM_SMD_DIV_CLK3] = &msm8992_div_clk3,
- [RPM_SMD_DIV_A_CLK3] = &msm8992_div_clk3_a,
- [RPM_SMD_IPA_CLK] = &msm8976_ipa_clk,
- [RPM_SMD_IPA_A_CLK] = &msm8976_ipa_a_clk,
- [RPM_SMD_LN_BB_CLK] = &msm8992_ln_bb_clk,
- [RPM_SMD_LN_BB_A_CLK] = &msm8992_ln_bb_a_clk,
- [RPM_SMD_MMSSNOC_AHB_CLK] = &msm8974_mmssnoc_ahb_clk,
- [RPM_SMD_MMSSNOC_AHB_A_CLK] = &msm8974_mmssnoc_ahb_a_clk,
- [RPM_SMD_MSS_CFG_AHB_CLK] = &msm8992_mss_cfg_ahb_clk,
- [RPM_SMD_MSS_CFG_AHB_A_CLK] = &msm8992_mss_cfg_ahb_a_clk,
- [RPM_SMD_QDSS_CLK] = &msm8916_qdss_clk,
- [RPM_SMD_QDSS_A_CLK] = &msm8916_qdss_a_clk,
- [RPM_SMD_RF_CLK1] = &msm8916_rf_clk1,
- [RPM_SMD_RF_CLK1_A] = &msm8916_rf_clk1_a,
- [RPM_SMD_RF_CLK2] = &msm8916_rf_clk2,
- [RPM_SMD_RF_CLK2_A] = &msm8916_rf_clk2_a,
- [RPM_SMD_RF_CLK1_PIN] = &msm8916_rf_clk1_pin,
- [RPM_SMD_RF_CLK1_A_PIN] = &msm8916_rf_clk1_a_pin,
- [RPM_SMD_RF_CLK2_PIN] = &msm8916_rf_clk2_pin,
- [RPM_SMD_RF_CLK2_A_PIN] = &msm8916_rf_clk2_a_pin,
- [RPM_SMD_CE1_CLK] = &msm8992_ce1_clk,
- [RPM_SMD_CE1_A_CLK] = &msm8992_ce1_a_clk,
- [RPM_SMD_CE2_CLK] = &msm8992_ce2_clk,
- [RPM_SMD_CE2_A_CLK] = &msm8992_ce2_a_clk,
+ [RPM_SMD_XO_CLK_SRC] = &clk_smd_rpm_branch_bi_tcxo,
+ [RPM_SMD_XO_A_CLK_SRC] = &clk_smd_rpm_branch_bi_tcxo_a,
+ [RPM_SMD_PNOC_CLK] = &clk_smd_rpm_bus_0_pcnoc_clk,
+ [RPM_SMD_PNOC_A_CLK] = &clk_smd_rpm_bus_0_pcnoc_a_clk,
+ [RPM_SMD_OCMEMGX_CLK] = &clk_smd_rpm_ocmemgx_clk,
+ [RPM_SMD_OCMEMGX_A_CLK] = &clk_smd_rpm_ocmemgx_a_clk,
+ [RPM_SMD_BIMC_CLK] = &clk_smd_rpm_bimc_clk,
+ [RPM_SMD_BIMC_A_CLK] = &clk_smd_rpm_bimc_a_clk,
+ [RPM_SMD_CNOC_CLK] = &clk_smd_rpm_bus_2_cnoc_clk,
+ [RPM_SMD_CNOC_A_CLK] = &clk_smd_rpm_bus_2_cnoc_a_clk,
+ [RPM_SMD_GFX3D_CLK_SRC] = &clk_smd_rpm_gfx3d_clk_src,
+ [RPM_SMD_GFX3D_A_CLK_SRC] = &clk_smd_rpm_gfx3d_a_clk_src,
+ [RPM_SMD_SNOC_CLK] = &clk_smd_rpm_bus_1_snoc_clk,
+ [RPM_SMD_SNOC_A_CLK] = &clk_smd_rpm_bus_1_snoc_a_clk,
+ [RPM_SMD_BB_CLK1] = &clk_smd_rpm_bb_clk1,
+ [RPM_SMD_BB_CLK1_A] = &clk_smd_rpm_bb_clk1_a,
+ [RPM_SMD_BB_CLK1_PIN] = &clk_smd_rpm_bb_clk1_pin,
+ [RPM_SMD_BB_CLK1_A_PIN] = &clk_smd_rpm_bb_clk1_a_pin,
+ [RPM_SMD_BB_CLK2] = &clk_smd_rpm_bb_clk2,
+ [RPM_SMD_BB_CLK2_A] = &clk_smd_rpm_bb_clk2_a,
+ [RPM_SMD_BB_CLK2_PIN] = &clk_smd_rpm_bb_clk2_pin,
+ [RPM_SMD_BB_CLK2_A_PIN] = &clk_smd_rpm_bb_clk2_a_pin,
+ [RPM_SMD_DIV_CLK1] = &clk_smd_rpm_div_clk1,
+ [RPM_SMD_DIV_A_CLK1] = &clk_smd_rpm_div_clk1_a,
+ [RPM_SMD_DIV_CLK2] = &clk_smd_rpm_div_clk2,
+ [RPM_SMD_DIV_A_CLK2] = &clk_smd_rpm_div_clk2_a,
+ [RPM_SMD_DIV_CLK3] = &clk_smd_rpm_div_clk3,
+ [RPM_SMD_DIV_A_CLK3] = &clk_smd_rpm_div_clk3_a,
+ [RPM_SMD_IPA_CLK] = &clk_smd_rpm_ipa_clk,
+ [RPM_SMD_IPA_A_CLK] = &clk_smd_rpm_ipa_a_clk,
+ [RPM_SMD_LN_BB_CLK] = &clk_smd_rpm_ln_bb_clk,
+ [RPM_SMD_LN_BB_A_CLK] = &clk_smd_rpm_ln_bb_clk_a,
+ [RPM_SMD_MMSSNOC_AHB_CLK] = &clk_smd_rpm_bus_3_mmssnoc_ahb_clk,
+ [RPM_SMD_MMSSNOC_AHB_A_CLK] = &clk_smd_rpm_bus_3_mmssnoc_ahb_a_clk,
+ [RPM_SMD_MSS_CFG_AHB_CLK] = &clk_smd_rpm_branch_mss_cfg_ahb_clk,
+ [RPM_SMD_MSS_CFG_AHB_A_CLK] = &clk_smd_rpm_branch_mss_cfg_ahb_a_clk,
+ [RPM_SMD_QDSS_CLK] = &clk_smd_rpm_qdss_clk,
+ [RPM_SMD_QDSS_A_CLK] = &clk_smd_rpm_qdss_a_clk,
+ [RPM_SMD_RF_CLK1] = &clk_smd_rpm_rf_clk1,
+ [RPM_SMD_RF_CLK1_A] = &clk_smd_rpm_rf_clk1_a,
+ [RPM_SMD_RF_CLK2] = &clk_smd_rpm_rf_clk2,
+ [RPM_SMD_RF_CLK2_A] = &clk_smd_rpm_rf_clk2_a,
+ [RPM_SMD_RF_CLK1_PIN] = &clk_smd_rpm_rf_clk1_pin,
+ [RPM_SMD_RF_CLK1_A_PIN] = &clk_smd_rpm_rf_clk1_a_pin,
+ [RPM_SMD_RF_CLK2_PIN] = &clk_smd_rpm_rf_clk2_pin,
+ [RPM_SMD_RF_CLK2_A_PIN] = &clk_smd_rpm_rf_clk2_a_pin,
+ [RPM_SMD_CE1_CLK] = &clk_smd_rpm_ce1_clk,
+ [RPM_SMD_CE1_A_CLK] = &clk_smd_rpm_ce1_a_clk,
+ [RPM_SMD_CE2_CLK] = &clk_smd_rpm_ce2_clk,
+ [RPM_SMD_CE2_A_CLK] = &clk_smd_rpm_ce2_a_clk,
};
static const struct rpm_smd_clk_desc rpm_clk_msm8992 = {
@@ -700,61 +751,59 @@ static const struct rpm_smd_clk_desc rpm_clk_msm8992 = {
.num_clks = ARRAY_SIZE(msm8992_clks),
};
-DEFINE_CLK_SMD_RPM(msm8994, ce3_clk, ce3_a_clk, QCOM_SMD_RPM_CE_CLK, 2);
-
static struct clk_smd_rpm *msm8994_clks[] = {
- [RPM_SMD_XO_CLK_SRC] = &sdm660_bi_tcxo,
- [RPM_SMD_XO_A_CLK_SRC] = &sdm660_bi_tcxo_a,
- [RPM_SMD_PNOC_CLK] = &msm8916_pcnoc_clk,
- [RPM_SMD_PNOC_A_CLK] = &msm8916_pcnoc_a_clk,
- [RPM_SMD_OCMEMGX_CLK] = &msm8974_ocmemgx_clk,
- [RPM_SMD_OCMEMGX_A_CLK] = &msm8974_ocmemgx_a_clk,
- [RPM_SMD_BIMC_CLK] = &msm8916_bimc_clk,
- [RPM_SMD_BIMC_A_CLK] = &msm8916_bimc_a_clk,
- [RPM_SMD_CNOC_CLK] = &msm8974_cnoc_clk,
- [RPM_SMD_CNOC_A_CLK] = &msm8974_cnoc_a_clk,
- [RPM_SMD_GFX3D_CLK_SRC] = &msm8974_gfx3d_clk_src,
- [RPM_SMD_GFX3D_A_CLK_SRC] = &msm8974_gfx3d_a_clk_src,
- [RPM_SMD_SNOC_CLK] = &msm8916_snoc_clk,
- [RPM_SMD_SNOC_A_CLK] = &msm8916_snoc_a_clk,
- [RPM_SMD_BB_CLK1] = &msm8916_bb_clk1,
- [RPM_SMD_BB_CLK1_A] = &msm8916_bb_clk1_a,
- [RPM_SMD_BB_CLK1_PIN] = &msm8916_bb_clk1_pin,
- [RPM_SMD_BB_CLK1_A_PIN] = &msm8916_bb_clk1_a_pin,
- [RPM_SMD_BB_CLK2] = &msm8916_bb_clk2,
- [RPM_SMD_BB_CLK2_A] = &msm8916_bb_clk2_a,
- [RPM_SMD_BB_CLK2_PIN] = &msm8916_bb_clk2_pin,
- [RPM_SMD_BB_CLK2_A_PIN] = &msm8916_bb_clk2_a_pin,
- [RPM_SMD_DIV_CLK1] = &msm8974_div_clk1,
- [RPM_SMD_DIV_A_CLK1] = &msm8974_div_a_clk1,
- [RPM_SMD_DIV_CLK2] = &msm8974_div_clk2,
- [RPM_SMD_DIV_A_CLK2] = &msm8974_div_a_clk2,
- [RPM_SMD_DIV_CLK3] = &msm8992_div_clk3,
- [RPM_SMD_DIV_A_CLK3] = &msm8992_div_clk3_a,
- [RPM_SMD_IPA_CLK] = &msm8976_ipa_clk,
- [RPM_SMD_IPA_A_CLK] = &msm8976_ipa_a_clk,
- [RPM_SMD_LN_BB_CLK] = &msm8992_ln_bb_clk,
- [RPM_SMD_LN_BB_A_CLK] = &msm8992_ln_bb_a_clk,
- [RPM_SMD_MMSSNOC_AHB_CLK] = &msm8974_mmssnoc_ahb_clk,
- [RPM_SMD_MMSSNOC_AHB_A_CLK] = &msm8974_mmssnoc_ahb_a_clk,
- [RPM_SMD_MSS_CFG_AHB_CLK] = &msm8992_mss_cfg_ahb_clk,
- [RPM_SMD_MSS_CFG_AHB_A_CLK] = &msm8992_mss_cfg_ahb_a_clk,
- [RPM_SMD_QDSS_CLK] = &msm8916_qdss_clk,
- [RPM_SMD_QDSS_A_CLK] = &msm8916_qdss_a_clk,
- [RPM_SMD_RF_CLK1] = &msm8916_rf_clk1,
- [RPM_SMD_RF_CLK1_A] = &msm8916_rf_clk1_a,
- [RPM_SMD_RF_CLK2] = &msm8916_rf_clk2,
- [RPM_SMD_RF_CLK2_A] = &msm8916_rf_clk2_a,
- [RPM_SMD_RF_CLK1_PIN] = &msm8916_rf_clk1_pin,
- [RPM_SMD_RF_CLK1_A_PIN] = &msm8916_rf_clk1_a_pin,
- [RPM_SMD_RF_CLK2_PIN] = &msm8916_rf_clk2_pin,
- [RPM_SMD_RF_CLK2_A_PIN] = &msm8916_rf_clk2_a_pin,
- [RPM_SMD_CE1_CLK] = &msm8992_ce1_clk,
- [RPM_SMD_CE1_A_CLK] = &msm8992_ce1_a_clk,
- [RPM_SMD_CE2_CLK] = &msm8992_ce2_clk,
- [RPM_SMD_CE2_A_CLK] = &msm8992_ce2_a_clk,
- [RPM_SMD_CE3_CLK] = &msm8994_ce3_clk,
- [RPM_SMD_CE3_A_CLK] = &msm8994_ce3_a_clk,
+ [RPM_SMD_XO_CLK_SRC] = &clk_smd_rpm_branch_bi_tcxo,
+ [RPM_SMD_XO_A_CLK_SRC] = &clk_smd_rpm_branch_bi_tcxo_a,
+ [RPM_SMD_PNOC_CLK] = &clk_smd_rpm_bus_0_pcnoc_clk,
+ [RPM_SMD_PNOC_A_CLK] = &clk_smd_rpm_bus_0_pcnoc_a_clk,
+ [RPM_SMD_OCMEMGX_CLK] = &clk_smd_rpm_ocmemgx_clk,
+ [RPM_SMD_OCMEMGX_A_CLK] = &clk_smd_rpm_ocmemgx_a_clk,
+ [RPM_SMD_BIMC_CLK] = &clk_smd_rpm_bimc_clk,
+ [RPM_SMD_BIMC_A_CLK] = &clk_smd_rpm_bimc_a_clk,
+ [RPM_SMD_CNOC_CLK] = &clk_smd_rpm_bus_2_cnoc_clk,
+ [RPM_SMD_CNOC_A_CLK] = &clk_smd_rpm_bus_2_cnoc_a_clk,
+ [RPM_SMD_GFX3D_CLK_SRC] = &clk_smd_rpm_gfx3d_clk_src,
+ [RPM_SMD_GFX3D_A_CLK_SRC] = &clk_smd_rpm_gfx3d_a_clk_src,
+ [RPM_SMD_SNOC_CLK] = &clk_smd_rpm_bus_1_snoc_clk,
+ [RPM_SMD_SNOC_A_CLK] = &clk_smd_rpm_bus_1_snoc_a_clk,
+ [RPM_SMD_BB_CLK1] = &clk_smd_rpm_bb_clk1,
+ [RPM_SMD_BB_CLK1_A] = &clk_smd_rpm_bb_clk1_a,
+ [RPM_SMD_BB_CLK1_PIN] = &clk_smd_rpm_bb_clk1_pin,
+ [RPM_SMD_BB_CLK1_A_PIN] = &clk_smd_rpm_bb_clk1_a_pin,
+ [RPM_SMD_BB_CLK2] = &clk_smd_rpm_bb_clk2,
+ [RPM_SMD_BB_CLK2_A] = &clk_smd_rpm_bb_clk2_a,
+ [RPM_SMD_BB_CLK2_PIN] = &clk_smd_rpm_bb_clk2_pin,
+ [RPM_SMD_BB_CLK2_A_PIN] = &clk_smd_rpm_bb_clk2_a_pin,
+ [RPM_SMD_DIV_CLK1] = &clk_smd_rpm_div_clk1,
+ [RPM_SMD_DIV_A_CLK1] = &clk_smd_rpm_div_clk1_a,
+ [RPM_SMD_DIV_CLK2] = &clk_smd_rpm_div_clk2,
+ [RPM_SMD_DIV_A_CLK2] = &clk_smd_rpm_div_clk2_a,
+ [RPM_SMD_DIV_CLK3] = &clk_smd_rpm_div_clk3,
+ [RPM_SMD_DIV_A_CLK3] = &clk_smd_rpm_div_clk3_a,
+ [RPM_SMD_IPA_CLK] = &clk_smd_rpm_ipa_clk,
+ [RPM_SMD_IPA_A_CLK] = &clk_smd_rpm_ipa_a_clk,
+ [RPM_SMD_LN_BB_CLK] = &clk_smd_rpm_ln_bb_clk,
+ [RPM_SMD_LN_BB_A_CLK] = &clk_smd_rpm_ln_bb_clk_a,
+ [RPM_SMD_MMSSNOC_AHB_CLK] = &clk_smd_rpm_bus_3_mmssnoc_ahb_clk,
+ [RPM_SMD_MMSSNOC_AHB_A_CLK] = &clk_smd_rpm_bus_3_mmssnoc_ahb_a_clk,
+ [RPM_SMD_MSS_CFG_AHB_CLK] = &clk_smd_rpm_branch_mss_cfg_ahb_clk,
+ [RPM_SMD_MSS_CFG_AHB_A_CLK] = &clk_smd_rpm_branch_mss_cfg_ahb_a_clk,
+ [RPM_SMD_QDSS_CLK] = &clk_smd_rpm_qdss_clk,
+ [RPM_SMD_QDSS_A_CLK] = &clk_smd_rpm_qdss_a_clk,
+ [RPM_SMD_RF_CLK1] = &clk_smd_rpm_rf_clk1,
+ [RPM_SMD_RF_CLK1_A] = &clk_smd_rpm_rf_clk1_a,
+ [RPM_SMD_RF_CLK2] = &clk_smd_rpm_rf_clk2,
+ [RPM_SMD_RF_CLK2_A] = &clk_smd_rpm_rf_clk2_a,
+ [RPM_SMD_RF_CLK1_PIN] = &clk_smd_rpm_rf_clk1_pin,
+ [RPM_SMD_RF_CLK1_A_PIN] = &clk_smd_rpm_rf_clk1_a_pin,
+ [RPM_SMD_RF_CLK2_PIN] = &clk_smd_rpm_rf_clk2_pin,
+ [RPM_SMD_RF_CLK2_A_PIN] = &clk_smd_rpm_rf_clk2_a_pin,
+ [RPM_SMD_CE1_CLK] = &clk_smd_rpm_ce1_clk,
+ [RPM_SMD_CE1_A_CLK] = &clk_smd_rpm_ce1_a_clk,
+ [RPM_SMD_CE2_CLK] = &clk_smd_rpm_ce2_clk,
+ [RPM_SMD_CE2_A_CLK] = &clk_smd_rpm_ce2_a_clk,
+ [RPM_SMD_CE3_CLK] = &clk_smd_rpm_ce3_clk,
+ [RPM_SMD_CE3_A_CLK] = &clk_smd_rpm_ce3_a_clk,
};
static const struct rpm_smd_clk_desc rpm_clk_msm8994 = {
@@ -762,58 +811,53 @@ static const struct rpm_smd_clk_desc rpm_clk_msm8994 = {
.num_clks = ARRAY_SIZE(msm8994_clks),
};
-DEFINE_CLK_SMD_RPM(msm8996, mmssnoc_axi_rpm_clk, mmssnoc_axi_rpm_a_clk,
- QCOM_SMD_RPM_MMAXI_CLK, 0);
-DEFINE_CLK_SMD_RPM_BRANCH(msm8996, aggre1_noc_clk, aggre1_noc_a_clk,
- QCOM_SMD_RPM_AGGR_CLK, 1, 1000);
-DEFINE_CLK_SMD_RPM_BRANCH(msm8996, aggre2_noc_clk, aggre2_noc_a_clk,
- QCOM_SMD_RPM_AGGR_CLK, 2, 1000);
-
static struct clk_smd_rpm *msm8996_clks[] = {
- [RPM_SMD_PCNOC_CLK] = &msm8916_pcnoc_clk,
- [RPM_SMD_PCNOC_A_CLK] = &msm8916_pcnoc_a_clk,
- [RPM_SMD_SNOC_CLK] = &msm8916_snoc_clk,
- [RPM_SMD_SNOC_A_CLK] = &msm8916_snoc_a_clk,
- [RPM_SMD_CNOC_CLK] = &msm8974_cnoc_clk,
- [RPM_SMD_CNOC_A_CLK] = &msm8974_cnoc_a_clk,
- [RPM_SMD_BIMC_CLK] = &msm8916_bimc_clk,
- [RPM_SMD_BIMC_A_CLK] = &msm8916_bimc_a_clk,
- [RPM_SMD_MMAXI_CLK] = &msm8996_mmssnoc_axi_rpm_clk,
- [RPM_SMD_MMAXI_A_CLK] = &msm8996_mmssnoc_axi_rpm_a_clk,
- [RPM_SMD_IPA_CLK] = &msm8976_ipa_clk,
- [RPM_SMD_IPA_A_CLK] = &msm8976_ipa_a_clk,
- [RPM_SMD_CE1_CLK] = &msm8992_ce1_clk,
- [RPM_SMD_CE1_A_CLK] = &msm8992_ce1_a_clk,
- [RPM_SMD_AGGR1_NOC_CLK] = &msm8996_aggre1_noc_clk,
- [RPM_SMD_AGGR1_NOC_A_CLK] = &msm8996_aggre1_noc_a_clk,
- [RPM_SMD_AGGR2_NOC_CLK] = &msm8996_aggre2_noc_clk,
- [RPM_SMD_AGGR2_NOC_A_CLK] = &msm8996_aggre2_noc_a_clk,
- [RPM_SMD_QDSS_CLK] = &msm8916_qdss_clk,
- [RPM_SMD_QDSS_A_CLK] = &msm8916_qdss_a_clk,
- [RPM_SMD_BB_CLK1] = &msm8916_bb_clk1,
- [RPM_SMD_BB_CLK1_A] = &msm8916_bb_clk1_a,
- [RPM_SMD_BB_CLK2] = &msm8916_bb_clk2,
- [RPM_SMD_BB_CLK2_A] = &msm8916_bb_clk2_a,
- [RPM_SMD_RF_CLK1] = &msm8916_rf_clk1,
- [RPM_SMD_RF_CLK1_A] = &msm8916_rf_clk1_a,
- [RPM_SMD_RF_CLK2] = &msm8916_rf_clk2,
- [RPM_SMD_RF_CLK2_A] = &msm8916_rf_clk2_a,
- [RPM_SMD_LN_BB_CLK] = &msm8992_ln_bb_clk,
- [RPM_SMD_LN_BB_A_CLK] = &msm8992_ln_bb_a_clk,
- [RPM_SMD_DIV_CLK1] = &msm8974_div_clk1,
- [RPM_SMD_DIV_A_CLK1] = &msm8974_div_a_clk1,
- [RPM_SMD_DIV_CLK2] = &msm8974_div_clk2,
- [RPM_SMD_DIV_A_CLK2] = &msm8974_div_a_clk2,
- [RPM_SMD_DIV_CLK3] = &msm8992_div_clk3,
- [RPM_SMD_DIV_A_CLK3] = &msm8992_div_clk3_a,
- [RPM_SMD_BB_CLK1_PIN] = &msm8916_bb_clk1_pin,
- [RPM_SMD_BB_CLK1_A_PIN] = &msm8916_bb_clk1_a_pin,
- [RPM_SMD_BB_CLK2_PIN] = &msm8916_bb_clk2_pin,
- [RPM_SMD_BB_CLK2_A_PIN] = &msm8916_bb_clk2_a_pin,
- [RPM_SMD_RF_CLK1_PIN] = &msm8916_rf_clk1_pin,
- [RPM_SMD_RF_CLK1_A_PIN] = &msm8916_rf_clk1_a_pin,
- [RPM_SMD_RF_CLK2_PIN] = &msm8916_rf_clk2_pin,
- [RPM_SMD_RF_CLK2_A_PIN] = &msm8916_rf_clk2_a_pin,
+ [RPM_SMD_XO_CLK_SRC] = &clk_smd_rpm_branch_bi_tcxo,
+ [RPM_SMD_XO_A_CLK_SRC] = &clk_smd_rpm_branch_bi_tcxo_a,
+ [RPM_SMD_PCNOC_CLK] = &clk_smd_rpm_bus_0_pcnoc_clk,
+ [RPM_SMD_PCNOC_A_CLK] = &clk_smd_rpm_bus_0_pcnoc_a_clk,
+ [RPM_SMD_SNOC_CLK] = &clk_smd_rpm_bus_1_snoc_clk,
+ [RPM_SMD_SNOC_A_CLK] = &clk_smd_rpm_bus_1_snoc_a_clk,
+ [RPM_SMD_CNOC_CLK] = &clk_smd_rpm_bus_2_cnoc_clk,
+ [RPM_SMD_CNOC_A_CLK] = &clk_smd_rpm_bus_2_cnoc_a_clk,
+ [RPM_SMD_BIMC_CLK] = &clk_smd_rpm_bimc_clk,
+ [RPM_SMD_BIMC_A_CLK] = &clk_smd_rpm_bimc_a_clk,
+ [RPM_SMD_MMAXI_CLK] = &clk_smd_rpm_mmssnoc_axi_rpm_clk,
+ [RPM_SMD_MMAXI_A_CLK] = &clk_smd_rpm_mmssnoc_axi_rpm_a_clk,
+ [RPM_SMD_IPA_CLK] = &clk_smd_rpm_ipa_clk,
+ [RPM_SMD_IPA_A_CLK] = &clk_smd_rpm_ipa_a_clk,
+ [RPM_SMD_CE1_CLK] = &clk_smd_rpm_ce1_clk,
+ [RPM_SMD_CE1_A_CLK] = &clk_smd_rpm_ce1_a_clk,
+ [RPM_SMD_AGGR1_NOC_CLK] = &clk_smd_rpm_branch_aggre1_noc_clk,
+ [RPM_SMD_AGGR1_NOC_A_CLK] = &clk_smd_rpm_branch_aggre1_noc_a_clk,
+ [RPM_SMD_AGGR2_NOC_CLK] = &clk_smd_rpm_branch_aggre2_noc_clk,
+ [RPM_SMD_AGGR2_NOC_A_CLK] = &clk_smd_rpm_branch_aggre2_noc_a_clk,
+ [RPM_SMD_QDSS_CLK] = &clk_smd_rpm_qdss_clk,
+ [RPM_SMD_QDSS_A_CLK] = &clk_smd_rpm_qdss_a_clk,
+ [RPM_SMD_BB_CLK1] = &clk_smd_rpm_bb_clk1,
+ [RPM_SMD_BB_CLK1_A] = &clk_smd_rpm_bb_clk1_a,
+ [RPM_SMD_BB_CLK2] = &clk_smd_rpm_bb_clk2,
+ [RPM_SMD_BB_CLK2_A] = &clk_smd_rpm_bb_clk2_a,
+ [RPM_SMD_RF_CLK1] = &clk_smd_rpm_rf_clk1,
+ [RPM_SMD_RF_CLK1_A] = &clk_smd_rpm_rf_clk1_a,
+ [RPM_SMD_RF_CLK2] = &clk_smd_rpm_rf_clk2,
+ [RPM_SMD_RF_CLK2_A] = &clk_smd_rpm_rf_clk2_a,
+ [RPM_SMD_LN_BB_CLK] = &clk_smd_rpm_ln_bb_clk,
+ [RPM_SMD_LN_BB_A_CLK] = &clk_smd_rpm_ln_bb_clk_a,
+ [RPM_SMD_DIV_CLK1] = &clk_smd_rpm_div_clk1,
+ [RPM_SMD_DIV_A_CLK1] = &clk_smd_rpm_div_clk1_a,
+ [RPM_SMD_DIV_CLK2] = &clk_smd_rpm_div_clk2,
+ [RPM_SMD_DIV_A_CLK2] = &clk_smd_rpm_div_clk2_a,
+ [RPM_SMD_DIV_CLK3] = &clk_smd_rpm_div_clk3,
+ [RPM_SMD_DIV_A_CLK3] = &clk_smd_rpm_div_clk3_a,
+ [RPM_SMD_BB_CLK1_PIN] = &clk_smd_rpm_bb_clk1_pin,
+ [RPM_SMD_BB_CLK1_A_PIN] = &clk_smd_rpm_bb_clk1_a_pin,
+ [RPM_SMD_BB_CLK2_PIN] = &clk_smd_rpm_bb_clk2_pin,
+ [RPM_SMD_BB_CLK2_A_PIN] = &clk_smd_rpm_bb_clk2_a_pin,
+ [RPM_SMD_RF_CLK1_PIN] = &clk_smd_rpm_rf_clk1_pin,
+ [RPM_SMD_RF_CLK1_A_PIN] = &clk_smd_rpm_rf_clk1_a_pin,
+ [RPM_SMD_RF_CLK2_PIN] = &clk_smd_rpm_rf_clk2_pin,
+ [RPM_SMD_RF_CLK2_A_PIN] = &clk_smd_rpm_rf_clk2_a_pin,
};
static const struct rpm_smd_clk_desc rpm_clk_msm8996 = {
@@ -821,28 +865,27 @@ static const struct rpm_smd_clk_desc rpm_clk_msm8996 = {
.num_clks = ARRAY_SIZE(msm8996_clks),
};
-DEFINE_CLK_SMD_RPM(qcs404, bimc_gpu_clk, bimc_gpu_a_clk, QCOM_SMD_RPM_MEM_CLK, 2);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(qcs404, ln_bb_clk_pin, ln_bb_clk_a_pin, 8, 19200000);
-
static struct clk_smd_rpm *qcs404_clks[] = {
- [RPM_SMD_QDSS_CLK] = &msm8916_qdss_clk,
- [RPM_SMD_QDSS_A_CLK] = &msm8916_qdss_a_clk,
- [RPM_SMD_PNOC_CLK] = &msm8916_pcnoc_clk,
- [RPM_SMD_PNOC_A_CLK] = &msm8916_pcnoc_a_clk,
- [RPM_SMD_SNOC_CLK] = &msm8916_snoc_clk,
- [RPM_SMD_SNOC_A_CLK] = &msm8916_snoc_a_clk,
- [RPM_SMD_BIMC_CLK] = &msm8916_bimc_clk,
- [RPM_SMD_BIMC_A_CLK] = &msm8916_bimc_a_clk,
- [RPM_SMD_BIMC_GPU_CLK] = &qcs404_bimc_gpu_clk,
- [RPM_SMD_BIMC_GPU_A_CLK] = &qcs404_bimc_gpu_a_clk,
- [RPM_SMD_QPIC_CLK] = &qcs404_qpic_clk,
- [RPM_SMD_QPIC_CLK_A] = &qcs404_qpic_a_clk,
- [RPM_SMD_CE1_CLK] = &msm8992_ce1_clk,
- [RPM_SMD_CE1_A_CLK] = &msm8992_ce1_a_clk,
- [RPM_SMD_RF_CLK1] = &msm8916_rf_clk1,
- [RPM_SMD_RF_CLK1_A] = &msm8916_rf_clk1_a,
- [RPM_SMD_LN_BB_CLK] = &msm8992_ln_bb_clk,
- [RPM_SMD_LN_BB_A_CLK] = &msm8992_ln_bb_a_clk,
+ [RPM_SMD_QDSS_CLK] = &clk_smd_rpm_qdss_clk,
+ [RPM_SMD_QDSS_A_CLK] = &clk_smd_rpm_qdss_a_clk,
+ [RPM_SMD_PNOC_CLK] = &clk_smd_rpm_bus_0_pcnoc_clk,
+ [RPM_SMD_PNOC_A_CLK] = &clk_smd_rpm_bus_0_pcnoc_a_clk,
+ [RPM_SMD_SNOC_CLK] = &clk_smd_rpm_bus_1_snoc_clk,
+ [RPM_SMD_SNOC_A_CLK] = &clk_smd_rpm_bus_1_snoc_a_clk,
+ [RPM_SMD_BIMC_CLK] = &clk_smd_rpm_bimc_clk,
+ [RPM_SMD_BIMC_A_CLK] = &clk_smd_rpm_bimc_a_clk,
+ [RPM_SMD_BIMC_GPU_CLK] = &clk_smd_rpm_bimc_gpu_clk,
+ [RPM_SMD_BIMC_GPU_A_CLK] = &clk_smd_rpm_bimc_gpu_a_clk,
+ [RPM_SMD_QPIC_CLK] = &clk_smd_rpm_qpic_clk,
+ [RPM_SMD_QPIC_CLK_A] = &clk_smd_rpm_qpic_a_clk,
+ [RPM_SMD_CE1_CLK] = &clk_smd_rpm_ce1_clk,
+ [RPM_SMD_CE1_A_CLK] = &clk_smd_rpm_ce1_a_clk,
+ [RPM_SMD_RF_CLK1] = &clk_smd_rpm_rf_clk1,
+ [RPM_SMD_RF_CLK1_A] = &clk_smd_rpm_rf_clk1_a,
+ [RPM_SMD_LN_BB_CLK] = &clk_smd_rpm_ln_bb_clk,
+ [RPM_SMD_LN_BB_A_CLK] = &clk_smd_rpm_ln_bb_clk_a,
+ [RPM_SMD_LN_BB_CLK_PIN] = &clk_smd_rpm_ln_bb_clk_pin,
+ [RPM_SMD_LN_BB_A_CLK_PIN] = &clk_smd_rpm_ln_bb_clk_a_pin,
};
static const struct rpm_smd_clk_desc rpm_clk_qcs404 = {
@@ -850,68 +893,59 @@ static const struct rpm_smd_clk_desc rpm_clk_qcs404 = {
.num_clks = ARRAY_SIZE(qcs404_clks),
};
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8998, ln_bb_clk3, ln_bb_clk3_a, 3, 19200000);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8998, ln_bb_clk3_pin, ln_bb_clk3_a_pin, 3, 19200000);
-DEFINE_CLK_SMD_RPM(msm8998, aggre1_noc_clk, aggre1_noc_a_clk,
- QCOM_SMD_RPM_AGGR_CLK, 1);
-DEFINE_CLK_SMD_RPM(msm8998, aggre2_noc_clk, aggre2_noc_a_clk,
- QCOM_SMD_RPM_AGGR_CLK, 2);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8998, rf_clk3, rf_clk3_a, 6, 19200000);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8998, rf_clk3_pin, rf_clk3_a_pin, 6, 19200000);
-
static struct clk_smd_rpm *msm8998_clks[] = {
- [RPM_SMD_XO_CLK_SRC] = &sdm660_bi_tcxo,
- [RPM_SMD_XO_A_CLK_SRC] = &sdm660_bi_tcxo_a,
- [RPM_SMD_BIMC_CLK] = &msm8916_bimc_clk,
- [RPM_SMD_BIMC_A_CLK] = &msm8916_bimc_a_clk,
- [RPM_SMD_PCNOC_CLK] = &msm8916_pcnoc_clk,
- [RPM_SMD_PCNOC_A_CLK] = &msm8916_pcnoc_a_clk,
- [RPM_SMD_SNOC_CLK] = &msm8916_snoc_clk,
- [RPM_SMD_SNOC_A_CLK] = &msm8916_snoc_a_clk,
- [RPM_SMD_CNOC_CLK] = &msm8974_cnoc_clk,
- [RPM_SMD_CNOC_A_CLK] = &msm8974_cnoc_a_clk,
- [RPM_SMD_CE1_CLK] = &msm8992_ce1_clk,
- [RPM_SMD_CE1_A_CLK] = &msm8992_ce1_a_clk,
- [RPM_SMD_DIV_CLK1] = &msm8974_div_clk1,
- [RPM_SMD_DIV_A_CLK1] = &msm8974_div_a_clk1,
- [RPM_SMD_DIV_CLK2] = &msm8974_div_clk2,
- [RPM_SMD_DIV_A_CLK2] = &msm8974_div_a_clk2,
- [RPM_SMD_DIV_CLK3] = &msm8992_div_clk3,
- [RPM_SMD_DIV_A_CLK3] = &msm8992_div_clk3_a,
- [RPM_SMD_IPA_CLK] = &msm8976_ipa_clk,
- [RPM_SMD_IPA_A_CLK] = &msm8976_ipa_a_clk,
- [RPM_SMD_LN_BB_CLK1] = &msm8916_bb_clk1,
- [RPM_SMD_LN_BB_CLK1_A] = &msm8916_bb_clk1_a,
- [RPM_SMD_LN_BB_CLK2] = &msm8916_bb_clk2,
- [RPM_SMD_LN_BB_CLK2_A] = &msm8916_bb_clk2_a,
- [RPM_SMD_LN_BB_CLK3] = &msm8998_ln_bb_clk3,
- [RPM_SMD_LN_BB_CLK3_A] = &msm8998_ln_bb_clk3_a,
- [RPM_SMD_LN_BB_CLK1_PIN] = &msm8916_bb_clk1_pin,
- [RPM_SMD_LN_BB_CLK1_A_PIN] = &msm8916_bb_clk1_a_pin,
- [RPM_SMD_LN_BB_CLK2_PIN] = &msm8916_bb_clk2_pin,
- [RPM_SMD_LN_BB_CLK2_A_PIN] = &msm8916_bb_clk2_a_pin,
- [RPM_SMD_LN_BB_CLK3_PIN] = &msm8998_ln_bb_clk3_pin,
- [RPM_SMD_LN_BB_CLK3_A_PIN] = &msm8998_ln_bb_clk3_a_pin,
- [RPM_SMD_MMAXI_CLK] = &msm8996_mmssnoc_axi_rpm_clk,
- [RPM_SMD_MMAXI_A_CLK] = &msm8996_mmssnoc_axi_rpm_a_clk,
- [RPM_SMD_AGGR1_NOC_CLK] = &msm8998_aggre1_noc_clk,
- [RPM_SMD_AGGR1_NOC_A_CLK] = &msm8998_aggre1_noc_a_clk,
- [RPM_SMD_AGGR2_NOC_CLK] = &msm8998_aggre2_noc_clk,
- [RPM_SMD_AGGR2_NOC_A_CLK] = &msm8998_aggre2_noc_a_clk,
- [RPM_SMD_QDSS_CLK] = &msm8916_qdss_clk,
- [RPM_SMD_QDSS_A_CLK] = &msm8916_qdss_a_clk,
- [RPM_SMD_RF_CLK1] = &msm8916_rf_clk1,
- [RPM_SMD_RF_CLK1_A] = &msm8916_rf_clk1_a,
- [RPM_SMD_RF_CLK2] = &msm8916_rf_clk2,
- [RPM_SMD_RF_CLK2_A] = &msm8916_rf_clk2_a,
- [RPM_SMD_RF_CLK3] = &msm8998_rf_clk3,
- [RPM_SMD_RF_CLK3_A] = &msm8998_rf_clk3_a,
- [RPM_SMD_RF_CLK1_PIN] = &msm8916_rf_clk1_pin,
- [RPM_SMD_RF_CLK1_A_PIN] = &msm8916_rf_clk1_a_pin,
- [RPM_SMD_RF_CLK2_PIN] = &msm8916_rf_clk2_pin,
- [RPM_SMD_RF_CLK2_A_PIN] = &msm8916_rf_clk2_a_pin,
- [RPM_SMD_RF_CLK3_PIN] = &msm8998_rf_clk3_pin,
- [RPM_SMD_RF_CLK3_A_PIN] = &msm8998_rf_clk3_a_pin,
+ [RPM_SMD_XO_CLK_SRC] = &clk_smd_rpm_branch_bi_tcxo,
+ [RPM_SMD_XO_A_CLK_SRC] = &clk_smd_rpm_branch_bi_tcxo_a,
+ [RPM_SMD_BIMC_CLK] = &clk_smd_rpm_bimc_clk,
+ [RPM_SMD_BIMC_A_CLK] = &clk_smd_rpm_bimc_a_clk,
+ [RPM_SMD_PCNOC_CLK] = &clk_smd_rpm_bus_0_pcnoc_clk,
+ [RPM_SMD_PCNOC_A_CLK] = &clk_smd_rpm_bus_0_pcnoc_a_clk,
+ [RPM_SMD_SNOC_CLK] = &clk_smd_rpm_bus_1_snoc_clk,
+ [RPM_SMD_SNOC_A_CLK] = &clk_smd_rpm_bus_1_snoc_a_clk,
+ [RPM_SMD_CNOC_CLK] = &clk_smd_rpm_bus_2_cnoc_clk,
+ [RPM_SMD_CNOC_A_CLK] = &clk_smd_rpm_bus_2_cnoc_a_clk,
+ [RPM_SMD_CE1_CLK] = &clk_smd_rpm_ce1_clk,
+ [RPM_SMD_CE1_A_CLK] = &clk_smd_rpm_ce1_a_clk,
+ [RPM_SMD_DIV_CLK1] = &clk_smd_rpm_div_clk1,
+ [RPM_SMD_DIV_A_CLK1] = &clk_smd_rpm_div_clk1_a,
+ [RPM_SMD_DIV_CLK2] = &clk_smd_rpm_div_clk2,
+ [RPM_SMD_DIV_A_CLK2] = &clk_smd_rpm_div_clk2_a,
+ [RPM_SMD_DIV_CLK3] = &clk_smd_rpm_div_clk3,
+ [RPM_SMD_DIV_A_CLK3] = &clk_smd_rpm_div_clk3_a,
+ [RPM_SMD_IPA_CLK] = &clk_smd_rpm_ipa_clk,
+ [RPM_SMD_IPA_A_CLK] = &clk_smd_rpm_ipa_a_clk,
+ [RPM_SMD_LN_BB_CLK1] = &clk_smd_rpm_ln_bb_clk1,
+ [RPM_SMD_LN_BB_CLK1_A] = &clk_smd_rpm_ln_bb_clk1_a,
+ [RPM_SMD_LN_BB_CLK2] = &clk_smd_rpm_ln_bb_clk2,
+ [RPM_SMD_LN_BB_CLK2_A] = &clk_smd_rpm_ln_bb_clk2_a,
+ [RPM_SMD_LN_BB_CLK3] = &clk_smd_rpm_ln_bb_clk3,
+ [RPM_SMD_LN_BB_CLK3_A] = &clk_smd_rpm_ln_bb_clk3_a,
+ [RPM_SMD_LN_BB_CLK1_PIN] = &clk_smd_rpm_ln_bb_clk1_pin,
+ [RPM_SMD_LN_BB_CLK1_A_PIN] = &clk_smd_rpm_ln_bb_clk1_a_pin,
+ [RPM_SMD_LN_BB_CLK2_PIN] = &clk_smd_rpm_ln_bb_clk2_pin,
+ [RPM_SMD_LN_BB_CLK2_A_PIN] = &clk_smd_rpm_ln_bb_clk2_a_pin,
+ [RPM_SMD_LN_BB_CLK3_PIN] = &clk_smd_rpm_ln_bb_clk3_pin,
+ [RPM_SMD_LN_BB_CLK3_A_PIN] = &clk_smd_rpm_ln_bb_clk3_a_pin,
+ [RPM_SMD_MMAXI_CLK] = &clk_smd_rpm_mmssnoc_axi_rpm_clk,
+ [RPM_SMD_MMAXI_A_CLK] = &clk_smd_rpm_mmssnoc_axi_rpm_a_clk,
+ [RPM_SMD_AGGR1_NOC_CLK] = &clk_smd_rpm_aggre1_noc_clk,
+ [RPM_SMD_AGGR1_NOC_A_CLK] = &clk_smd_rpm_aggre1_noc_a_clk,
+ [RPM_SMD_AGGR2_NOC_CLK] = &clk_smd_rpm_aggre2_noc_clk,
+ [RPM_SMD_AGGR2_NOC_A_CLK] = &clk_smd_rpm_aggre2_noc_a_clk,
+ [RPM_SMD_QDSS_CLK] = &clk_smd_rpm_qdss_clk,
+ [RPM_SMD_QDSS_A_CLK] = &clk_smd_rpm_qdss_a_clk,
+ [RPM_SMD_RF_CLK1] = &clk_smd_rpm_rf_clk1,
+ [RPM_SMD_RF_CLK1_A] = &clk_smd_rpm_rf_clk1_a,
+ [RPM_SMD_RF_CLK2] = &clk_smd_rpm_rf_clk2,
+ [RPM_SMD_RF_CLK2_A] = &clk_smd_rpm_rf_clk2_a,
+ [RPM_SMD_RF_CLK3] = &clk_smd_rpm_rf_clk3,
+ [RPM_SMD_RF_CLK3_A] = &clk_smd_rpm_rf_clk3_a,
+ [RPM_SMD_RF_CLK1_PIN] = &clk_smd_rpm_rf_clk1_pin,
+ [RPM_SMD_RF_CLK1_A_PIN] = &clk_smd_rpm_rf_clk1_a_pin,
+ [RPM_SMD_RF_CLK2_PIN] = &clk_smd_rpm_rf_clk2_pin,
+ [RPM_SMD_RF_CLK2_A_PIN] = &clk_smd_rpm_rf_clk2_a_pin,
+ [RPM_SMD_RF_CLK3_PIN] = &clk_smd_rpm_rf_clk3_pin,
+ [RPM_SMD_RF_CLK3_A_PIN] = &clk_smd_rpm_rf_clk3_a_pin,
};
static const struct rpm_smd_clk_desc rpm_clk_msm8998 = {
@@ -920,44 +954,44 @@ static const struct rpm_smd_clk_desc rpm_clk_msm8998 = {
};
static struct clk_smd_rpm *sdm660_clks[] = {
- [RPM_SMD_XO_CLK_SRC] = &sdm660_bi_tcxo,
- [RPM_SMD_XO_A_CLK_SRC] = &sdm660_bi_tcxo_a,
- [RPM_SMD_SNOC_CLK] = &msm8916_snoc_clk,
- [RPM_SMD_SNOC_A_CLK] = &msm8916_snoc_a_clk,
- [RPM_SMD_CNOC_CLK] = &msm8974_cnoc_clk,
- [RPM_SMD_CNOC_A_CLK] = &msm8974_cnoc_a_clk,
- [RPM_SMD_CNOC_PERIPH_CLK] = &msm8916_pcnoc_clk,
- [RPM_SMD_CNOC_PERIPH_A_CLK] = &msm8916_pcnoc_a_clk,
- [RPM_SMD_BIMC_CLK] = &msm8916_bimc_clk,
- [RPM_SMD_BIMC_A_CLK] = &msm8916_bimc_a_clk,
- [RPM_SMD_MMSSNOC_AXI_CLK] = &msm8996_mmssnoc_axi_rpm_clk,
- [RPM_SMD_MMSSNOC_AXI_CLK_A] = &msm8996_mmssnoc_axi_rpm_a_clk,
- [RPM_SMD_IPA_CLK] = &msm8976_ipa_clk,
- [RPM_SMD_IPA_A_CLK] = &msm8976_ipa_a_clk,
- [RPM_SMD_CE1_CLK] = &msm8992_ce1_clk,
- [RPM_SMD_CE1_A_CLK] = &msm8992_ce1_a_clk,
- [RPM_SMD_AGGR2_NOC_CLK] = &msm8998_aggre2_noc_clk,
- [RPM_SMD_AGGR2_NOC_A_CLK] = &msm8998_aggre2_noc_a_clk,
- [RPM_SMD_QDSS_CLK] = &msm8916_qdss_clk,
- [RPM_SMD_QDSS_A_CLK] = &msm8916_qdss_a_clk,
- [RPM_SMD_RF_CLK1] = &msm8916_rf_clk1,
- [RPM_SMD_RF_CLK1_A] = &msm8916_rf_clk1_a,
- [RPM_SMD_DIV_CLK1] = &msm8974_div_clk1,
- [RPM_SMD_DIV_A_CLK1] = &msm8974_div_a_clk1,
- [RPM_SMD_LN_BB_CLK] = &msm8916_bb_clk1,
- [RPM_SMD_LN_BB_A_CLK] = &msm8916_bb_clk1_a,
- [RPM_SMD_LN_BB_CLK2] = &msm8916_bb_clk2,
- [RPM_SMD_LN_BB_CLK2_A] = &msm8916_bb_clk2_a,
- [RPM_SMD_LN_BB_CLK3] = &msm8998_ln_bb_clk3,
- [RPM_SMD_LN_BB_CLK3_A] = &msm8998_ln_bb_clk3_a,
- [RPM_SMD_RF_CLK1_PIN] = &msm8916_rf_clk1_pin,
- [RPM_SMD_RF_CLK1_A_PIN] = &msm8916_rf_clk1_a_pin,
- [RPM_SMD_LN_BB_CLK1_PIN] = &msm8916_bb_clk1_pin,
- [RPM_SMD_LN_BB_CLK1_A_PIN] = &msm8916_bb_clk1_a_pin,
- [RPM_SMD_LN_BB_CLK2_PIN] = &msm8916_bb_clk2_pin,
- [RPM_SMD_LN_BB_CLK2_A_PIN] = &msm8916_bb_clk2_a_pin,
- [RPM_SMD_LN_BB_CLK3_PIN] = &msm8998_ln_bb_clk3_pin,
- [RPM_SMD_LN_BB_CLK3_A_PIN] = &msm8998_ln_bb_clk3_a_pin,
+ [RPM_SMD_XO_CLK_SRC] = &clk_smd_rpm_branch_bi_tcxo,
+ [RPM_SMD_XO_A_CLK_SRC] = &clk_smd_rpm_branch_bi_tcxo_a,
+ [RPM_SMD_SNOC_CLK] = &clk_smd_rpm_bus_1_snoc_clk,
+ [RPM_SMD_SNOC_A_CLK] = &clk_smd_rpm_bus_1_snoc_a_clk,
+ [RPM_SMD_CNOC_CLK] = &clk_smd_rpm_bus_2_cnoc_clk,
+ [RPM_SMD_CNOC_A_CLK] = &clk_smd_rpm_bus_2_cnoc_a_clk,
+ [RPM_SMD_CNOC_PERIPH_CLK] = &clk_smd_rpm_bus_0_pcnoc_clk,
+ [RPM_SMD_CNOC_PERIPH_A_CLK] = &clk_smd_rpm_bus_0_pcnoc_a_clk,
+ [RPM_SMD_BIMC_CLK] = &clk_smd_rpm_bimc_clk,
+ [RPM_SMD_BIMC_A_CLK] = &clk_smd_rpm_bimc_a_clk,
+ [RPM_SMD_MMSSNOC_AXI_CLK] = &clk_smd_rpm_mmssnoc_axi_rpm_clk,
+ [RPM_SMD_MMSSNOC_AXI_CLK_A] = &clk_smd_rpm_mmssnoc_axi_rpm_a_clk,
+ [RPM_SMD_IPA_CLK] = &clk_smd_rpm_ipa_clk,
+ [RPM_SMD_IPA_A_CLK] = &clk_smd_rpm_ipa_a_clk,
+ [RPM_SMD_CE1_CLK] = &clk_smd_rpm_ce1_clk,
+ [RPM_SMD_CE1_A_CLK] = &clk_smd_rpm_ce1_a_clk,
+ [RPM_SMD_AGGR2_NOC_CLK] = &clk_smd_rpm_aggre2_noc_clk,
+ [RPM_SMD_AGGR2_NOC_A_CLK] = &clk_smd_rpm_aggre2_noc_a_clk,
+ [RPM_SMD_QDSS_CLK] = &clk_smd_rpm_qdss_clk,
+ [RPM_SMD_QDSS_A_CLK] = &clk_smd_rpm_qdss_a_clk,
+ [RPM_SMD_RF_CLK1] = &clk_smd_rpm_rf_clk1,
+ [RPM_SMD_RF_CLK1_A] = &clk_smd_rpm_rf_clk1_a,
+ [RPM_SMD_DIV_CLK1] = &clk_smd_rpm_div_clk1,
+ [RPM_SMD_DIV_A_CLK1] = &clk_smd_rpm_div_clk1_a,
+ [RPM_SMD_LN_BB_CLK] = &clk_smd_rpm_ln_bb_clk1,
+ [RPM_SMD_LN_BB_A_CLK] = &clk_smd_rpm_ln_bb_clk1_a,
+ [RPM_SMD_LN_BB_CLK2] = &clk_smd_rpm_ln_bb_clk2,
+ [RPM_SMD_LN_BB_CLK2_A] = &clk_smd_rpm_ln_bb_clk2_a,
+ [RPM_SMD_LN_BB_CLK3] = &clk_smd_rpm_ln_bb_clk3,
+ [RPM_SMD_LN_BB_CLK3_A] = &clk_smd_rpm_ln_bb_clk3_a,
+ [RPM_SMD_RF_CLK1_PIN] = &clk_smd_rpm_rf_clk1_pin,
+ [RPM_SMD_RF_CLK1_A_PIN] = &clk_smd_rpm_rf_clk1_a_pin,
+ [RPM_SMD_LN_BB_CLK1_PIN] = &clk_smd_rpm_ln_bb_clk1_pin,
+ [RPM_SMD_LN_BB_CLK1_A_PIN] = &clk_smd_rpm_ln_bb_clk1_a_pin,
+ [RPM_SMD_LN_BB_CLK2_PIN] = &clk_smd_rpm_ln_bb_clk2_pin,
+ [RPM_SMD_LN_BB_CLK2_A_PIN] = &clk_smd_rpm_ln_bb_clk2_a_pin,
+ [RPM_SMD_LN_BB_CLK3_PIN] = &clk_smd_rpm_ln_bb_clk3_pin,
+ [RPM_SMD_LN_BB_CLK3_A_PIN] = &clk_smd_rpm_ln_bb_clk3_a_pin,
};
static const struct rpm_smd_clk_desc rpm_clk_sdm660 = {
@@ -966,20 +1000,20 @@ static const struct rpm_smd_clk_desc rpm_clk_sdm660 = {
};
static struct clk_smd_rpm *mdm9607_clks[] = {
- [RPM_SMD_XO_CLK_SRC] = &sdm660_bi_tcxo,
- [RPM_SMD_XO_A_CLK_SRC] = &sdm660_bi_tcxo_a,
- [RPM_SMD_PCNOC_CLK] = &msm8916_pcnoc_clk,
- [RPM_SMD_PCNOC_A_CLK] = &msm8916_pcnoc_a_clk,
- [RPM_SMD_BIMC_CLK] = &msm8916_bimc_clk,
- [RPM_SMD_BIMC_A_CLK] = &msm8916_bimc_a_clk,
- [RPM_SMD_QPIC_CLK] = &qcs404_qpic_clk,
- [RPM_SMD_QPIC_CLK_A] = &qcs404_qpic_a_clk,
- [RPM_SMD_QDSS_CLK] = &msm8916_qdss_clk,
- [RPM_SMD_QDSS_A_CLK] = &msm8916_qdss_a_clk,
- [RPM_SMD_BB_CLK1] = &msm8916_bb_clk1,
- [RPM_SMD_BB_CLK1_A] = &msm8916_bb_clk1_a,
- [RPM_SMD_BB_CLK1_PIN] = &msm8916_bb_clk1_pin,
- [RPM_SMD_BB_CLK1_A_PIN] = &msm8916_bb_clk1_a_pin,
+ [RPM_SMD_XO_CLK_SRC] = &clk_smd_rpm_branch_bi_tcxo,
+ [RPM_SMD_XO_A_CLK_SRC] = &clk_smd_rpm_branch_bi_tcxo_a,
+ [RPM_SMD_PCNOC_CLK] = &clk_smd_rpm_bus_0_pcnoc_clk,
+ [RPM_SMD_PCNOC_A_CLK] = &clk_smd_rpm_bus_0_pcnoc_a_clk,
+ [RPM_SMD_BIMC_CLK] = &clk_smd_rpm_bimc_clk,
+ [RPM_SMD_BIMC_A_CLK] = &clk_smd_rpm_bimc_a_clk,
+ [RPM_SMD_QPIC_CLK] = &clk_smd_rpm_qpic_clk,
+ [RPM_SMD_QPIC_CLK_A] = &clk_smd_rpm_qpic_a_clk,
+ [RPM_SMD_QDSS_CLK] = &clk_smd_rpm_qdss_clk,
+ [RPM_SMD_QDSS_A_CLK] = &clk_smd_rpm_qdss_a_clk,
+ [RPM_SMD_BB_CLK1] = &clk_smd_rpm_bb_clk1,
+ [RPM_SMD_BB_CLK1_A] = &clk_smd_rpm_bb_clk1_a,
+ [RPM_SMD_BB_CLK1_PIN] = &clk_smd_rpm_bb_clk1_pin,
+ [RPM_SMD_BB_CLK1_A_PIN] = &clk_smd_rpm_bb_clk1_a_pin,
};
static const struct rpm_smd_clk_desc rpm_clk_mdm9607 = {
@@ -988,34 +1022,34 @@ static const struct rpm_smd_clk_desc rpm_clk_mdm9607 = {
};
static struct clk_smd_rpm *msm8953_clks[] = {
- [RPM_SMD_XO_CLK_SRC] = &sdm660_bi_tcxo,
- [RPM_SMD_XO_A_CLK_SRC] = &sdm660_bi_tcxo_a,
- [RPM_SMD_PCNOC_CLK] = &msm8916_pcnoc_clk,
- [RPM_SMD_PCNOC_A_CLK] = &msm8916_pcnoc_a_clk,
- [RPM_SMD_SNOC_CLK] = &msm8916_snoc_clk,
- [RPM_SMD_SNOC_A_CLK] = &msm8916_snoc_a_clk,
- [RPM_SMD_BIMC_CLK] = &msm8916_bimc_clk,
- [RPM_SMD_BIMC_A_CLK] = &msm8916_bimc_a_clk,
- [RPM_SMD_IPA_CLK] = &msm8976_ipa_clk,
- [RPM_SMD_IPA_A_CLK] = &msm8976_ipa_a_clk,
- [RPM_SMD_SYSMMNOC_CLK] = &msm8936_sysmmnoc_clk,
- [RPM_SMD_SYSMMNOC_A_CLK] = &msm8936_sysmmnoc_a_clk,
- [RPM_SMD_QDSS_CLK] = &msm8916_qdss_clk,
- [RPM_SMD_QDSS_A_CLK] = &msm8916_qdss_a_clk,
- [RPM_SMD_BB_CLK1] = &msm8916_bb_clk1,
- [RPM_SMD_BB_CLK1_A] = &msm8916_bb_clk1_a,
- [RPM_SMD_BB_CLK2] = &msm8916_bb_clk2,
- [RPM_SMD_BB_CLK2_A] = &msm8916_bb_clk2_a,
- [RPM_SMD_RF_CLK2] = &msm8916_rf_clk2,
- [RPM_SMD_RF_CLK2_A] = &msm8916_rf_clk2_a,
- [RPM_SMD_RF_CLK3] = &msm8992_ln_bb_clk,
- [RPM_SMD_RF_CLK3_A] = &msm8992_ln_bb_a_clk,
- [RPM_SMD_DIV_CLK2] = &msm8974_div_clk2,
- [RPM_SMD_DIV_A_CLK2] = &msm8974_div_a_clk2,
- [RPM_SMD_BB_CLK1_PIN] = &msm8916_bb_clk1_pin,
- [RPM_SMD_BB_CLK1_A_PIN] = &msm8916_bb_clk1_a_pin,
- [RPM_SMD_BB_CLK2_PIN] = &msm8916_bb_clk2_pin,
- [RPM_SMD_BB_CLK2_A_PIN] = &msm8916_bb_clk2_a_pin,
+ [RPM_SMD_XO_CLK_SRC] = &clk_smd_rpm_branch_bi_tcxo,
+ [RPM_SMD_XO_A_CLK_SRC] = &clk_smd_rpm_branch_bi_tcxo_a,
+ [RPM_SMD_PCNOC_CLK] = &clk_smd_rpm_bus_0_pcnoc_clk,
+ [RPM_SMD_PCNOC_A_CLK] = &clk_smd_rpm_bus_0_pcnoc_a_clk,
+ [RPM_SMD_SNOC_CLK] = &clk_smd_rpm_bus_1_snoc_clk,
+ [RPM_SMD_SNOC_A_CLK] = &clk_smd_rpm_bus_1_snoc_a_clk,
+ [RPM_SMD_BIMC_CLK] = &clk_smd_rpm_bimc_clk,
+ [RPM_SMD_BIMC_A_CLK] = &clk_smd_rpm_bimc_a_clk,
+ [RPM_SMD_IPA_CLK] = &clk_smd_rpm_ipa_clk,
+ [RPM_SMD_IPA_A_CLK] = &clk_smd_rpm_ipa_a_clk,
+ [RPM_SMD_SYSMMNOC_CLK] = &clk_smd_rpm_bus_2_sysmmnoc_clk,
+ [RPM_SMD_SYSMMNOC_A_CLK] = &clk_smd_rpm_bus_2_sysmmnoc_a_clk,
+ [RPM_SMD_QDSS_CLK] = &clk_smd_rpm_qdss_clk,
+ [RPM_SMD_QDSS_A_CLK] = &clk_smd_rpm_qdss_a_clk,
+ [RPM_SMD_BB_CLK1] = &clk_smd_rpm_bb_clk1,
+ [RPM_SMD_BB_CLK1_A] = &clk_smd_rpm_bb_clk1_a,
+ [RPM_SMD_BB_CLK2] = &clk_smd_rpm_bb_clk2,
+ [RPM_SMD_BB_CLK2_A] = &clk_smd_rpm_bb_clk2_a,
+ [RPM_SMD_RF_CLK2] = &clk_smd_rpm_rf_clk2,
+ [RPM_SMD_RF_CLK2_A] = &clk_smd_rpm_rf_clk2_a,
+ [RPM_SMD_RF_CLK3] = &clk_smd_rpm_ln_bb_clk,
+ [RPM_SMD_RF_CLK3_A] = &clk_smd_rpm_ln_bb_clk_a,
+ [RPM_SMD_DIV_CLK2] = &clk_smd_rpm_div_clk2,
+ [RPM_SMD_DIV_A_CLK2] = &clk_smd_rpm_div_clk2_a,
+ [RPM_SMD_BB_CLK1_PIN] = &clk_smd_rpm_bb_clk1_pin,
+ [RPM_SMD_BB_CLK1_A_PIN] = &clk_smd_rpm_bb_clk1_a_pin,
+ [RPM_SMD_BB_CLK2_PIN] = &clk_smd_rpm_bb_clk2_pin,
+ [RPM_SMD_BB_CLK2_A_PIN] = &clk_smd_rpm_bb_clk2_a_pin,
};
static const struct rpm_smd_clk_desc rpm_clk_msm8953 = {
@@ -1023,54 +1057,41 @@ static const struct rpm_smd_clk_desc rpm_clk_msm8953 = {
.num_clks = ARRAY_SIZE(msm8953_clks),
};
-/* SM6125 */
-DEFINE_CLK_SMD_RPM(sm6125, cnoc_clk, cnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1);
-DEFINE_CLK_SMD_RPM(sm6125, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 2);
-DEFINE_CLK_SMD_RPM_BRANCH(sm6125, qdss_clk, qdss_a_clk,
- QCOM_SMD_RPM_MISC_CLK, 1, 19200000);
-DEFINE_CLK_SMD_RPM(sm6125, qup_clk, qup_a_clk, QCOM_SMD_RPM_QUP_CLK, 0);
-DEFINE_CLK_SMD_RPM(sm6125, mmnrt_clk, mmnrt_a_clk, QCOM_SMD_RPM_MMAXI_CLK, 0);
-DEFINE_CLK_SMD_RPM(sm6125, mmrt_clk, mmrt_a_clk, QCOM_SMD_RPM_MMAXI_CLK, 1);
-DEFINE_CLK_SMD_RPM(sm6125, snoc_periph_clk, snoc_periph_a_clk,
- QCOM_SMD_RPM_BUS_CLK, 0);
-DEFINE_CLK_SMD_RPM(sm6125, snoc_lpass_clk, snoc_lpass_a_clk,
- QCOM_SMD_RPM_BUS_CLK, 5);
-
static struct clk_smd_rpm *sm6125_clks[] = {
- [RPM_SMD_XO_CLK_SRC] = &sdm660_bi_tcxo,
- [RPM_SMD_XO_A_CLK_SRC] = &sdm660_bi_tcxo_a,
- [RPM_SMD_SNOC_CLK] = &sm6125_snoc_clk,
- [RPM_SMD_SNOC_A_CLK] = &sm6125_snoc_a_clk,
- [RPM_SMD_BIMC_CLK] = &msm8916_bimc_clk,
- [RPM_SMD_BIMC_A_CLK] = &msm8916_bimc_a_clk,
- [RPM_SMD_QDSS_CLK] = &sm6125_qdss_clk,
- [RPM_SMD_QDSS_A_CLK] = &sm6125_qdss_a_clk,
- [RPM_SMD_RF_CLK1] = &msm8916_rf_clk1,
- [RPM_SMD_RF_CLK1_A] = &msm8916_rf_clk1_a,
- [RPM_SMD_RF_CLK2] = &msm8916_rf_clk2,
- [RPM_SMD_RF_CLK2_A] = &msm8916_rf_clk2_a,
- [RPM_SMD_CNOC_CLK] = &sm6125_cnoc_clk,
- [RPM_SMD_CNOC_A_CLK] = &sm6125_cnoc_a_clk,
- [RPM_SMD_IPA_CLK] = &msm8976_ipa_clk,
- [RPM_SMD_IPA_A_CLK] = &msm8976_ipa_a_clk,
- [RPM_SMD_CE1_CLK] = &msm8992_ce1_clk,
- [RPM_SMD_CE1_A_CLK] = &msm8992_ce1_a_clk,
- [RPM_SMD_LN_BB_CLK1] = &msm8916_bb_clk1,
- [RPM_SMD_LN_BB_CLK1_A] = &msm8916_bb_clk1_a,
- [RPM_SMD_LN_BB_CLK2] = &msm8916_bb_clk2,
- [RPM_SMD_LN_BB_CLK2_A] = &msm8916_bb_clk2_a,
- [RPM_SMD_LN_BB_CLK3] = &msm8998_ln_bb_clk3,
- [RPM_SMD_LN_BB_CLK3_A] = &msm8998_ln_bb_clk3_a,
- [RPM_SMD_QUP_CLK] = &sm6125_qup_clk,
- [RPM_SMD_QUP_A_CLK] = &sm6125_qup_a_clk,
- [RPM_SMD_MMRT_CLK] = &sm6125_mmrt_clk,
- [RPM_SMD_MMRT_A_CLK] = &sm6125_mmrt_a_clk,
- [RPM_SMD_MMNRT_CLK] = &sm6125_mmnrt_clk,
- [RPM_SMD_MMNRT_A_CLK] = &sm6125_mmnrt_a_clk,
- [RPM_SMD_SNOC_PERIPH_CLK] = &sm6125_snoc_periph_clk,
- [RPM_SMD_SNOC_PERIPH_A_CLK] = &sm6125_snoc_periph_a_clk,
- [RPM_SMD_SNOC_LPASS_CLK] = &sm6125_snoc_lpass_clk,
- [RPM_SMD_SNOC_LPASS_A_CLK] = &sm6125_snoc_lpass_a_clk,
+ [RPM_SMD_XO_CLK_SRC] = &clk_smd_rpm_branch_bi_tcxo,
+ [RPM_SMD_XO_A_CLK_SRC] = &clk_smd_rpm_branch_bi_tcxo_a,
+ [RPM_SMD_SNOC_CLK] = &clk_smd_rpm_bus_2_snoc_clk,
+ [RPM_SMD_SNOC_A_CLK] = &clk_smd_rpm_bus_2_snoc_a_clk,
+ [RPM_SMD_BIMC_CLK] = &clk_smd_rpm_bimc_clk,
+ [RPM_SMD_BIMC_A_CLK] = &clk_smd_rpm_bimc_a_clk,
+ [RPM_SMD_QDSS_CLK] = &clk_smd_rpm_branch_qdss_clk,
+ [RPM_SMD_QDSS_A_CLK] = &clk_smd_rpm_branch_qdss_a_clk,
+ [RPM_SMD_RF_CLK1] = &clk_smd_rpm_rf_clk1,
+ [RPM_SMD_RF_CLK1_A] = &clk_smd_rpm_rf_clk1_a,
+ [RPM_SMD_RF_CLK2] = &clk_smd_rpm_rf_clk2,
+ [RPM_SMD_RF_CLK2_A] = &clk_smd_rpm_rf_clk2_a,
+ [RPM_SMD_CNOC_CLK] = &clk_smd_rpm_bus_1_cnoc_clk,
+ [RPM_SMD_CNOC_A_CLK] = &clk_smd_rpm_bus_1_cnoc_a_clk,
+ [RPM_SMD_IPA_CLK] = &clk_smd_rpm_ipa_clk,
+ [RPM_SMD_IPA_A_CLK] = &clk_smd_rpm_ipa_a_clk,
+ [RPM_SMD_CE1_CLK] = &clk_smd_rpm_ce1_clk,
+ [RPM_SMD_CE1_A_CLK] = &clk_smd_rpm_ce1_a_clk,
+ [RPM_SMD_LN_BB_CLK1] = &clk_smd_rpm_ln_bb_clk1,
+ [RPM_SMD_LN_BB_CLK1_A] = &clk_smd_rpm_ln_bb_clk1_a,
+ [RPM_SMD_LN_BB_CLK2] = &clk_smd_rpm_ln_bb_clk2,
+ [RPM_SMD_LN_BB_CLK2_A] = &clk_smd_rpm_ln_bb_clk2_a,
+ [RPM_SMD_LN_BB_CLK3] = &clk_smd_rpm_ln_bb_clk3,
+ [RPM_SMD_LN_BB_CLK3_A] = &clk_smd_rpm_ln_bb_clk3_a,
+ [RPM_SMD_QUP_CLK] = &clk_smd_rpm_qup_clk,
+ [RPM_SMD_QUP_A_CLK] = &clk_smd_rpm_qup_a_clk,
+ [RPM_SMD_MMRT_CLK] = &clk_smd_rpm_mmrt_clk,
+ [RPM_SMD_MMRT_A_CLK] = &clk_smd_rpm_mmrt_a_clk,
+ [RPM_SMD_MMNRT_CLK] = &clk_smd_rpm_mmnrt_clk,
+ [RPM_SMD_MMNRT_A_CLK] = &clk_smd_rpm_mmnrt_a_clk,
+ [RPM_SMD_SNOC_PERIPH_CLK] = &clk_smd_rpm_bus_0_snoc_periph_clk,
+ [RPM_SMD_SNOC_PERIPH_A_CLK] = &clk_smd_rpm_bus_0_snoc_periph_a_clk,
+ [RPM_SMD_SNOC_LPASS_CLK] = &clk_smd_rpm_bus_5_snoc_lpass_clk,
+ [RPM_SMD_SNOC_LPASS_A_CLK] = &clk_smd_rpm_bus_5_snoc_lpass_a_clk,
};
static const struct rpm_smd_clk_desc rpm_clk_sm6125 = {
@@ -1080,38 +1101,38 @@ static const struct rpm_smd_clk_desc rpm_clk_sm6125 = {
/* SM6115 */
static struct clk_smd_rpm *sm6115_clks[] = {
- [RPM_SMD_XO_CLK_SRC] = &sdm660_bi_tcxo,
- [RPM_SMD_XO_A_CLK_SRC] = &sdm660_bi_tcxo_a,
- [RPM_SMD_SNOC_CLK] = &sm6125_snoc_clk,
- [RPM_SMD_SNOC_A_CLK] = &sm6125_snoc_a_clk,
- [RPM_SMD_BIMC_CLK] = &msm8916_bimc_clk,
- [RPM_SMD_BIMC_A_CLK] = &msm8916_bimc_a_clk,
- [RPM_SMD_QDSS_CLK] = &sm6125_qdss_clk,
- [RPM_SMD_QDSS_A_CLK] = &sm6125_qdss_a_clk,
- [RPM_SMD_RF_CLK1] = &msm8916_rf_clk1,
- [RPM_SMD_RF_CLK1_A] = &msm8916_rf_clk1_a,
- [RPM_SMD_RF_CLK2] = &msm8916_rf_clk2,
- [RPM_SMD_RF_CLK2_A] = &msm8916_rf_clk2_a,
- [RPM_SMD_CNOC_CLK] = &sm6125_cnoc_clk,
- [RPM_SMD_CNOC_A_CLK] = &sm6125_cnoc_a_clk,
- [RPM_SMD_IPA_CLK] = &msm8976_ipa_clk,
- [RPM_SMD_IPA_A_CLK] = &msm8976_ipa_a_clk,
- [RPM_SMD_CE1_CLK] = &msm8992_ce1_clk,
- [RPM_SMD_CE1_A_CLK] = &msm8992_ce1_a_clk,
- [RPM_SMD_QUP_CLK] = &sm6125_qup_clk,
- [RPM_SMD_QUP_A_CLK] = &sm6125_qup_a_clk,
- [RPM_SMD_MMRT_CLK] = &sm6125_mmrt_clk,
- [RPM_SMD_MMRT_A_CLK] = &sm6125_mmrt_a_clk,
- [RPM_SMD_MMNRT_CLK] = &sm6125_mmnrt_clk,
- [RPM_SMD_MMNRT_A_CLK] = &sm6125_mmnrt_a_clk,
- [RPM_SMD_SNOC_PERIPH_CLK] = &sm6125_snoc_periph_clk,
- [RPM_SMD_SNOC_PERIPH_A_CLK] = &sm6125_snoc_periph_a_clk,
- [RPM_SMD_SNOC_LPASS_CLK] = &sm6125_snoc_lpass_clk,
- [RPM_SMD_SNOC_LPASS_A_CLK] = &sm6125_snoc_lpass_a_clk,
- [RPM_SMD_RF_CLK1_PIN] = &msm8916_rf_clk1_pin,
- [RPM_SMD_RF_CLK1_A_PIN] = &msm8916_rf_clk1_a_pin,
- [RPM_SMD_RF_CLK2_PIN] = &msm8916_rf_clk2_pin,
- [RPM_SMD_RF_CLK2_A_PIN] = &msm8916_rf_clk2_a_pin,
+ [RPM_SMD_XO_CLK_SRC] = &clk_smd_rpm_branch_bi_tcxo,
+ [RPM_SMD_XO_A_CLK_SRC] = &clk_smd_rpm_branch_bi_tcxo_a,
+ [RPM_SMD_SNOC_CLK] = &clk_smd_rpm_bus_2_snoc_clk,
+ [RPM_SMD_SNOC_A_CLK] = &clk_smd_rpm_bus_2_snoc_a_clk,
+ [RPM_SMD_BIMC_CLK] = &clk_smd_rpm_bimc_clk,
+ [RPM_SMD_BIMC_A_CLK] = &clk_smd_rpm_bimc_a_clk,
+ [RPM_SMD_QDSS_CLK] = &clk_smd_rpm_branch_qdss_clk,
+ [RPM_SMD_QDSS_A_CLK] = &clk_smd_rpm_branch_qdss_a_clk,
+ [RPM_SMD_RF_CLK1] = &clk_smd_rpm_rf_clk1,
+ [RPM_SMD_RF_CLK1_A] = &clk_smd_rpm_rf_clk1_a,
+ [RPM_SMD_RF_CLK2] = &clk_smd_rpm_rf_clk2,
+ [RPM_SMD_RF_CLK2_A] = &clk_smd_rpm_rf_clk2_a,
+ [RPM_SMD_CNOC_CLK] = &clk_smd_rpm_bus_1_cnoc_clk,
+ [RPM_SMD_CNOC_A_CLK] = &clk_smd_rpm_bus_1_cnoc_a_clk,
+ [RPM_SMD_IPA_CLK] = &clk_smd_rpm_ipa_clk,
+ [RPM_SMD_IPA_A_CLK] = &clk_smd_rpm_ipa_a_clk,
+ [RPM_SMD_CE1_CLK] = &clk_smd_rpm_ce1_clk,
+ [RPM_SMD_CE1_A_CLK] = &clk_smd_rpm_ce1_a_clk,
+ [RPM_SMD_QUP_CLK] = &clk_smd_rpm_qup_clk,
+ [RPM_SMD_QUP_A_CLK] = &clk_smd_rpm_qup_a_clk,
+ [RPM_SMD_MMRT_CLK] = &clk_smd_rpm_mmrt_clk,
+ [RPM_SMD_MMRT_A_CLK] = &clk_smd_rpm_mmrt_a_clk,
+ [RPM_SMD_MMNRT_CLK] = &clk_smd_rpm_mmnrt_clk,
+ [RPM_SMD_MMNRT_A_CLK] = &clk_smd_rpm_mmnrt_a_clk,
+ [RPM_SMD_SNOC_PERIPH_CLK] = &clk_smd_rpm_bus_0_snoc_periph_clk,
+ [RPM_SMD_SNOC_PERIPH_A_CLK] = &clk_smd_rpm_bus_0_snoc_periph_a_clk,
+ [RPM_SMD_SNOC_LPASS_CLK] = &clk_smd_rpm_bus_5_snoc_lpass_clk,
+ [RPM_SMD_SNOC_LPASS_A_CLK] = &clk_smd_rpm_bus_5_snoc_lpass_a_clk,
+ [RPM_SMD_RF_CLK1_PIN] = &clk_smd_rpm_rf_clk1_pin,
+ [RPM_SMD_RF_CLK1_A_PIN] = &clk_smd_rpm_rf_clk1_a_pin,
+ [RPM_SMD_RF_CLK2_PIN] = &clk_smd_rpm_rf_clk2_pin,
+ [RPM_SMD_RF_CLK2_A_PIN] = &clk_smd_rpm_rf_clk2_a_pin,
};
static const struct rpm_smd_clk_desc rpm_clk_sm6115 = {
@@ -1119,42 +1140,36 @@ static const struct rpm_smd_clk_desc rpm_clk_sm6115 = {
.num_clks = ARRAY_SIZE(sm6115_clks),
};
-/* SM6375 */
-DEFINE_CLK_SMD_RPM(sm6375, mmnrt_clk, mmnrt_a_clk, QCOM_SMD_RPM_MMXI_CLK, 0);
-DEFINE_CLK_SMD_RPM(sm6375, mmrt_clk, mmrt_a_clk, QCOM_SMD_RPM_MMXI_CLK, 1);
-DEFINE_CLK_SMD_RPM(qcm2290, hwkm_clk, hwkm_a_clk, QCOM_SMD_RPM_HWKM_CLK, 0);
-DEFINE_CLK_SMD_RPM(qcm2290, pka_clk, pka_a_clk, QCOM_SMD_RPM_PKA_CLK, 0);
-DEFINE_CLK_SMD_RPM_BRANCH(sm6375, bimc_freq_log, bimc_freq_log_a, QCOM_SMD_RPM_MISC_CLK, 4, 1);
static struct clk_smd_rpm *sm6375_clks[] = {
- [RPM_SMD_XO_CLK_SRC] = &sdm660_bi_tcxo,
- [RPM_SMD_XO_A_CLK_SRC] = &sdm660_bi_tcxo_a,
- [RPM_SMD_SNOC_CLK] = &sm6125_snoc_clk,
- [RPM_SMD_SNOC_A_CLK] = &sm6125_snoc_a_clk,
- [RPM_SMD_BIMC_CLK] = &msm8916_bimc_clk,
- [RPM_SMD_BIMC_A_CLK] = &msm8916_bimc_a_clk,
- [RPM_SMD_QDSS_CLK] = &sm6125_qdss_clk,
- [RPM_SMD_QDSS_A_CLK] = &sm6125_qdss_a_clk,
- [RPM_SMD_CNOC_CLK] = &sm6125_cnoc_clk,
- [RPM_SMD_CNOC_A_CLK] = &sm6125_cnoc_a_clk,
- [RPM_SMD_IPA_CLK] = &msm8976_ipa_clk,
- [RPM_SMD_IPA_A_CLK] = &msm8976_ipa_a_clk,
- [RPM_SMD_QUP_CLK] = &sm6125_qup_clk,
- [RPM_SMD_QUP_A_CLK] = &sm6125_qup_a_clk,
- [RPM_SMD_MMRT_CLK] = &sm6375_mmrt_clk,
- [RPM_SMD_MMRT_A_CLK] = &sm6375_mmrt_a_clk,
- [RPM_SMD_MMNRT_CLK] = &sm6375_mmnrt_clk,
- [RPM_SMD_MMNRT_A_CLK] = &sm6375_mmnrt_a_clk,
- [RPM_SMD_SNOC_PERIPH_CLK] = &sm6125_snoc_periph_clk,
- [RPM_SMD_SNOC_PERIPH_A_CLK] = &sm6125_snoc_periph_a_clk,
- [RPM_SMD_SNOC_LPASS_CLK] = &sm6125_snoc_lpass_clk,
- [RPM_SMD_SNOC_LPASS_A_CLK] = &sm6125_snoc_lpass_a_clk,
- [RPM_SMD_CE1_CLK] = &msm8992_ce1_clk,
- [RPM_SMD_CE1_A_CLK] = &msm8992_ce1_a_clk,
- [RPM_SMD_HWKM_CLK] = &qcm2290_hwkm_clk,
- [RPM_SMD_HWKM_A_CLK] = &qcm2290_hwkm_a_clk,
- [RPM_SMD_PKA_CLK] = &qcm2290_pka_clk,
- [RPM_SMD_PKA_A_CLK] = &qcm2290_pka_a_clk,
- [RPM_SMD_BIMC_FREQ_LOG] = &sm6375_bimc_freq_log,
+ [RPM_SMD_XO_CLK_SRC] = &clk_smd_rpm_branch_bi_tcxo,
+ [RPM_SMD_XO_A_CLK_SRC] = &clk_smd_rpm_branch_bi_tcxo_a,
+ [RPM_SMD_SNOC_CLK] = &clk_smd_rpm_bus_2_snoc_clk,
+ [RPM_SMD_SNOC_A_CLK] = &clk_smd_rpm_bus_2_snoc_a_clk,
+ [RPM_SMD_BIMC_CLK] = &clk_smd_rpm_bimc_clk,
+ [RPM_SMD_BIMC_A_CLK] = &clk_smd_rpm_bimc_a_clk,
+ [RPM_SMD_QDSS_CLK] = &clk_smd_rpm_branch_qdss_clk,
+ [RPM_SMD_QDSS_A_CLK] = &clk_smd_rpm_branch_qdss_a_clk,
+ [RPM_SMD_CNOC_CLK] = &clk_smd_rpm_bus_1_cnoc_clk,
+ [RPM_SMD_CNOC_A_CLK] = &clk_smd_rpm_bus_1_cnoc_a_clk,
+ [RPM_SMD_IPA_CLK] = &clk_smd_rpm_ipa_clk,
+ [RPM_SMD_IPA_A_CLK] = &clk_smd_rpm_ipa_a_clk,
+ [RPM_SMD_QUP_CLK] = &clk_smd_rpm_qup_clk,
+ [RPM_SMD_QUP_A_CLK] = &clk_smd_rpm_qup_a_clk,
+ [RPM_SMD_MMRT_CLK] = &clk_smd_rpm_mmrt_clk,
+ [RPM_SMD_MMRT_A_CLK] = &clk_smd_rpm_mmrt_a_clk,
+ [RPM_SMD_MMNRT_CLK] = &clk_smd_rpm_mmnrt_clk,
+ [RPM_SMD_MMNRT_A_CLK] = &clk_smd_rpm_mmnrt_a_clk,
+ [RPM_SMD_SNOC_PERIPH_CLK] = &clk_smd_rpm_bus_0_snoc_periph_clk,
+ [RPM_SMD_SNOC_PERIPH_A_CLK] = &clk_smd_rpm_bus_0_snoc_periph_a_clk,
+ [RPM_SMD_SNOC_LPASS_CLK] = &clk_smd_rpm_bus_5_snoc_lpass_clk,
+ [RPM_SMD_SNOC_LPASS_A_CLK] = &clk_smd_rpm_bus_5_snoc_lpass_a_clk,
+ [RPM_SMD_CE1_CLK] = &clk_smd_rpm_ce1_clk,
+ [RPM_SMD_CE1_A_CLK] = &clk_smd_rpm_ce1_a_clk,
+ [RPM_SMD_HWKM_CLK] = &clk_smd_rpm_hwkm_clk,
+ [RPM_SMD_HWKM_A_CLK] = &clk_smd_rpm_hwkm_a_clk,
+ [RPM_SMD_PKA_CLK] = &clk_smd_rpm_pka_clk,
+ [RPM_SMD_PKA_A_CLK] = &clk_smd_rpm_pka_a_clk,
+ [RPM_SMD_BIMC_FREQ_LOG] = &clk_smd_rpm_branch_bimc_freq_log,
};
static const struct rpm_smd_clk_desc rpm_clk_sm6375 = {
@@ -1162,55 +1177,45 @@ static const struct rpm_smd_clk_desc rpm_clk_sm6375 = {
.num_clks = ARRAY_SIZE(sm6375_clks),
};
-/* QCM2290 */
-DEFINE_CLK_SMD_RPM_XO_BUFFER(qcm2290, ln_bb_clk2, ln_bb_clk2_a, 0x2, 19200000);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(qcm2290, rf_clk3, rf_clk3_a, 6, 38400000);
-
-DEFINE_CLK_SMD_RPM(qcm2290, qpic_clk, qpic_a_clk, QCOM_SMD_RPM_QPIC_CLK, 0);
-DEFINE_CLK_SMD_RPM(qcm2290, cpuss_gnoc_clk, cpuss_gnoc_a_clk,
- QCOM_SMD_RPM_MEM_CLK, 1);
-DEFINE_CLK_SMD_RPM(qcm2290, bimc_gpu_clk, bimc_gpu_a_clk,
- QCOM_SMD_RPM_MEM_CLK, 2);
-
static struct clk_smd_rpm *qcm2290_clks[] = {
- [RPM_SMD_XO_CLK_SRC] = &sdm660_bi_tcxo,
- [RPM_SMD_XO_A_CLK_SRC] = &sdm660_bi_tcxo_a,
- [RPM_SMD_SNOC_CLK] = &sm6125_snoc_clk,
- [RPM_SMD_SNOC_A_CLK] = &sm6125_snoc_a_clk,
- [RPM_SMD_BIMC_CLK] = &msm8916_bimc_clk,
- [RPM_SMD_BIMC_A_CLK] = &msm8916_bimc_a_clk,
- [RPM_SMD_QDSS_CLK] = &sm6125_qdss_clk,
- [RPM_SMD_QDSS_A_CLK] = &sm6125_qdss_a_clk,
- [RPM_SMD_LN_BB_CLK2] = &qcm2290_ln_bb_clk2,
- [RPM_SMD_LN_BB_CLK2_A] = &qcm2290_ln_bb_clk2_a,
- [RPM_SMD_RF_CLK3] = &qcm2290_rf_clk3,
- [RPM_SMD_RF_CLK3_A] = &qcm2290_rf_clk3_a,
- [RPM_SMD_CNOC_CLK] = &sm6125_cnoc_clk,
- [RPM_SMD_CNOC_A_CLK] = &sm6125_cnoc_a_clk,
- [RPM_SMD_IPA_CLK] = &msm8976_ipa_clk,
- [RPM_SMD_IPA_A_CLK] = &msm8976_ipa_a_clk,
- [RPM_SMD_QUP_CLK] = &sm6125_qup_clk,
- [RPM_SMD_QUP_A_CLK] = &sm6125_qup_a_clk,
- [RPM_SMD_MMRT_CLK] = &sm6125_mmrt_clk,
- [RPM_SMD_MMRT_A_CLK] = &sm6125_mmrt_a_clk,
- [RPM_SMD_MMNRT_CLK] = &sm6125_mmnrt_clk,
- [RPM_SMD_MMNRT_A_CLK] = &sm6125_mmnrt_a_clk,
- [RPM_SMD_SNOC_PERIPH_CLK] = &sm6125_snoc_periph_clk,
- [RPM_SMD_SNOC_PERIPH_A_CLK] = &sm6125_snoc_periph_a_clk,
- [RPM_SMD_SNOC_LPASS_CLK] = &sm6125_snoc_lpass_clk,
- [RPM_SMD_SNOC_LPASS_A_CLK] = &sm6125_snoc_lpass_a_clk,
- [RPM_SMD_CE1_CLK] = &msm8992_ce1_clk,
- [RPM_SMD_CE1_A_CLK] = &msm8992_ce1_a_clk,
- [RPM_SMD_QPIC_CLK] = &qcm2290_qpic_clk,
- [RPM_SMD_QPIC_CLK_A] = &qcm2290_qpic_a_clk,
- [RPM_SMD_HWKM_CLK] = &qcm2290_hwkm_clk,
- [RPM_SMD_HWKM_A_CLK] = &qcm2290_hwkm_a_clk,
- [RPM_SMD_PKA_CLK] = &qcm2290_pka_clk,
- [RPM_SMD_PKA_A_CLK] = &qcm2290_pka_a_clk,
- [RPM_SMD_BIMC_GPU_CLK] = &qcm2290_bimc_gpu_clk,
- [RPM_SMD_BIMC_GPU_A_CLK] = &qcm2290_bimc_gpu_a_clk,
- [RPM_SMD_CPUSS_GNOC_CLK] = &qcm2290_cpuss_gnoc_clk,
- [RPM_SMD_CPUSS_GNOC_A_CLK] = &qcm2290_cpuss_gnoc_a_clk,
+ [RPM_SMD_XO_CLK_SRC] = &clk_smd_rpm_branch_bi_tcxo,
+ [RPM_SMD_XO_A_CLK_SRC] = &clk_smd_rpm_branch_bi_tcxo_a,
+ [RPM_SMD_SNOC_CLK] = &clk_smd_rpm_bus_2_snoc_clk,
+ [RPM_SMD_SNOC_A_CLK] = &clk_smd_rpm_bus_2_snoc_a_clk,
+ [RPM_SMD_BIMC_CLK] = &clk_smd_rpm_bimc_clk,
+ [RPM_SMD_BIMC_A_CLK] = &clk_smd_rpm_bimc_a_clk,
+ [RPM_SMD_QDSS_CLK] = &clk_smd_rpm_branch_qdss_clk,
+ [RPM_SMD_QDSS_A_CLK] = &clk_smd_rpm_branch_qdss_a_clk,
+ [RPM_SMD_LN_BB_CLK2] = &clk_smd_rpm_ln_bb_clk2,
+ [RPM_SMD_LN_BB_CLK2_A] = &clk_smd_rpm_ln_bb_clk2_a,
+ [RPM_SMD_RF_CLK3] = &clk_smd_rpm_38m4_rf_clk3,
+ [RPM_SMD_RF_CLK3_A] = &clk_smd_rpm_38m4_rf_clk3_a,
+ [RPM_SMD_CNOC_CLK] = &clk_smd_rpm_bus_1_cnoc_clk,
+ [RPM_SMD_CNOC_A_CLK] = &clk_smd_rpm_bus_1_cnoc_a_clk,
+ [RPM_SMD_IPA_CLK] = &clk_smd_rpm_ipa_clk,
+ [RPM_SMD_IPA_A_CLK] = &clk_smd_rpm_ipa_a_clk,
+ [RPM_SMD_QUP_CLK] = &clk_smd_rpm_qup_clk,
+ [RPM_SMD_QUP_A_CLK] = &clk_smd_rpm_qup_a_clk,
+ [RPM_SMD_MMRT_CLK] = &clk_smd_rpm_mmrt_clk,
+ [RPM_SMD_MMRT_A_CLK] = &clk_smd_rpm_mmrt_a_clk,
+ [RPM_SMD_MMNRT_CLK] = &clk_smd_rpm_mmnrt_clk,
+ [RPM_SMD_MMNRT_A_CLK] = &clk_smd_rpm_mmnrt_a_clk,
+ [RPM_SMD_SNOC_PERIPH_CLK] = &clk_smd_rpm_bus_0_snoc_periph_clk,
+ [RPM_SMD_SNOC_PERIPH_A_CLK] = &clk_smd_rpm_bus_0_snoc_periph_a_clk,
+ [RPM_SMD_SNOC_LPASS_CLK] = &clk_smd_rpm_bus_5_snoc_lpass_clk,
+ [RPM_SMD_SNOC_LPASS_A_CLK] = &clk_smd_rpm_bus_5_snoc_lpass_a_clk,
+ [RPM_SMD_CE1_CLK] = &clk_smd_rpm_ce1_clk,
+ [RPM_SMD_CE1_A_CLK] = &clk_smd_rpm_ce1_a_clk,
+ [RPM_SMD_QPIC_CLK] = &clk_smd_rpm_qpic_clk,
+ [RPM_SMD_QPIC_CLK_A] = &clk_smd_rpm_qpic_a_clk,
+ [RPM_SMD_HWKM_CLK] = &clk_smd_rpm_hwkm_clk,
+ [RPM_SMD_HWKM_A_CLK] = &clk_smd_rpm_hwkm_a_clk,
+ [RPM_SMD_PKA_CLK] = &clk_smd_rpm_pka_clk,
+ [RPM_SMD_PKA_A_CLK] = &clk_smd_rpm_pka_a_clk,
+ [RPM_SMD_BIMC_GPU_CLK] = &clk_smd_rpm_bimc_gpu_clk,
+ [RPM_SMD_BIMC_GPU_A_CLK] = &clk_smd_rpm_bimc_gpu_a_clk,
+ [RPM_SMD_CPUSS_GNOC_CLK] = &clk_smd_rpm_cpuss_gnoc_clk,
+ [RPM_SMD_CPUSS_GNOC_A_CLK] = &clk_smd_rpm_cpuss_gnoc_a_clk,
};
static const struct rpm_smd_clk_desc rpm_clk_qcm2290 = {
diff --git a/drivers/clk/qcom/clk-spmi-pmic-div.c b/drivers/clk/qcom/clk-spmi-pmic-div.c
index f2cf55cee2fd..f846be285f51 100644
--- a/drivers/clk/qcom/clk-spmi-pmic-div.c
+++ b/drivers/clk/qcom/clk-spmi-pmic-div.c
@@ -204,7 +204,7 @@ static int spmi_pmic_clkdiv_probe(struct platform_device *pdev)
struct regmap *regmap;
struct device *dev = &pdev->dev;
struct device_node *of_node = dev->of_node;
- const char *parent_name;
+ struct clk_parent_data parent_data = { .index = 0, };
int nclks, i, ret, cxo_hz;
char name[20];
u32 start;
@@ -246,14 +246,8 @@ static int spmi_pmic_clkdiv_probe(struct platform_device *pdev)
cxo_hz = clk_get_rate(cxo);
clk_put(cxo);
- parent_name = of_clk_get_parent_name(of_node, 0);
- if (!parent_name) {
- dev_err(dev, "missing parent clock\n");
- return -ENODEV;
- }
-
init.name = name;
- init.parent_names = &parent_name;
+ init.parent_data = &parent_data;
init.num_parents = 1;
init.ops = &clk_spmi_pmic_div_ops;
diff --git a/drivers/clk/qcom/dispcc-qcm2290.c b/drivers/clk/qcom/dispcc-qcm2290.c
index 96b149365912..2ebd9a02b895 100644
--- a/drivers/clk/qcom/dispcc-qcm2290.c
+++ b/drivers/clk/qcom/dispcc-qcm2290.c
@@ -71,7 +71,6 @@ static const struct parent_map disp_cc_parent_map_0[] = {
static const struct clk_parent_data disp_cc_parent_data_0[] = {
{ .fw_name = "bi_tcxo" },
{ .fw_name = "dsi0_phy_pll_out_byteclk" },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct parent_map disp_cc_parent_map_1[] = {
@@ -80,7 +79,6 @@ static const struct parent_map disp_cc_parent_map_1[] = {
static const struct clk_parent_data disp_cc_parent_data_1[] = {
{ .fw_name = "bi_tcxo" },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct parent_map disp_cc_parent_map_2[] = {
@@ -91,7 +89,6 @@ static const struct parent_map disp_cc_parent_map_2[] = {
static const struct clk_parent_data disp_cc_parent_data_2[] = {
{ .fw_name = "bi_tcxo_ao" },
{ .fw_name = "gcc_disp_gpll0_div_clk_src" },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct parent_map disp_cc_parent_map_3[] = {
@@ -104,7 +101,6 @@ static const struct clk_parent_data disp_cc_parent_data_3[] = {
{ .fw_name = "bi_tcxo" },
{ .hw = &disp_cc_pll0.clkr.hw },
{ .fw_name = "gcc_disp_gpll0_clk_src" },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct parent_map disp_cc_parent_map_4[] = {
@@ -117,7 +113,6 @@ static const struct clk_parent_data disp_cc_parent_data_4[] = {
{ .fw_name = "bi_tcxo" },
{ .fw_name = "dsi0_phy_pll_out_dsiclk" },
{ .fw_name = "dsi1_phy_pll_out_dsiclk" },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct parent_map disp_cc_parent_map_5[] = {
@@ -126,7 +121,6 @@ static const struct parent_map disp_cc_parent_map_5[] = {
static const struct clk_parent_data disp_cc_parent_data_5[] = {
{ .fw_name = "sleep_clk" },
- { .fw_name = "core_bi_pll_test_se" },
};
static struct clk_rcg2 disp_cc_mdss_byte0_clk_src = {
diff --git a/drivers/clk/qcom/dispcc-sc7180.c b/drivers/clk/qcom/dispcc-sc7180.c
index 5d2ae297e741..9536bfc72a43 100644
--- a/drivers/clk/qcom/dispcc-sc7180.c
+++ b/drivers/clk/qcom/dispcc-sc7180.c
@@ -351,8 +351,8 @@ static struct clk_regmap_div disp_cc_mdss_byte0_div_clk_src = {
.width = 2,
.clkr.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_byte0_div_clk_src",
- .parent_data = &(const struct clk_parent_data){
- .hw = &disp_cc_mdss_byte0_clk_src.clkr.hw
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_byte0_clk_src.clkr.hw,
},
.num_parents = 1,
.ops = &clk_regmap_div_ops,
@@ -365,8 +365,8 @@ static struct clk_regmap_div disp_cc_mdss_dp_link_div_clk_src = {
.width = 2,
.clkr.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_dp_link_div_clk_src",
- .parent_data = &(const struct clk_parent_data){
- .hw = &disp_cc_mdss_dp_link_clk_src.clkr.hw
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dp_link_clk_src.clkr.hw,
},
.num_parents = 1,
.ops = &clk_regmap_div_ops,
diff --git a/drivers/clk/qcom/dispcc-sm6115.c b/drivers/clk/qcom/dispcc-sm6115.c
index 818bb8f4637c..1937edf23f21 100644
--- a/drivers/clk/qcom/dispcc-sm6115.c
+++ b/drivers/clk/qcom/dispcc-sm6115.c
@@ -466,8 +466,8 @@ static struct clk_branch disp_cc_mdss_rot_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "disp_cc_mdss_rot_clk",
- .parent_names = (const char *[]){
- "disp_cc_mdss_rot_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_rot_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
diff --git a/drivers/clk/qcom/dispcc-sm6125.c b/drivers/clk/qcom/dispcc-sm6125.c
index b921456a2e0d..87b27053ddb6 100644
--- a/drivers/clk/qcom/dispcc-sm6125.c
+++ b/drivers/clk/qcom/dispcc-sm6125.c
@@ -667,7 +667,7 @@ static const struct qcom_cc_desc disp_cc_sm6125_desc = {
};
static const struct of_device_id disp_cc_sm6125_match_table[] = {
- { .compatible = "qcom,dispcc-sm6125" },
+ { .compatible = "qcom,sm6125-dispcc" },
{ }
};
MODULE_DEVICE_TABLE(of, disp_cc_sm6125_match_table);
diff --git a/drivers/clk/qcom/dispcc-sm6375.c b/drivers/clk/qcom/dispcc-sm6375.c
index 5ce9198ad611..caa1b90a5ff2 100644
--- a/drivers/clk/qcom/dispcc-sm6375.c
+++ b/drivers/clk/qcom/dispcc-sm6375.c
@@ -252,8 +252,8 @@ static struct clk_regmap_div disp_cc_mdss_byte0_div_clk_src = {
.width = 4,
.clkr.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_byte0_div_clk_src",
- .parent_data = &(const struct clk_parent_data){
- .hw = &disp_cc_mdss_byte0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_byte0_clk_src.clkr.hw,
},
.num_parents = 1,
.ops = &clk_regmap_div_ops,
diff --git a/drivers/clk/qcom/dispcc-sm8250.c b/drivers/clk/qcom/dispcc-sm8250.c
index 382dbd8ba250..e17bb8b543b5 100644
--- a/drivers/clk/qcom/dispcc-sm8250.c
+++ b/drivers/clk/qcom/dispcc-sm8250.c
@@ -1251,19 +1251,12 @@ static const struct of_device_id disp_cc_sm8250_match_table[] = {
};
MODULE_DEVICE_TABLE(of, disp_cc_sm8250_match_table);
-static void disp_cc_sm8250_pm_runtime_disable(void *data)
-{
- pm_runtime_disable(data);
-}
-
static int disp_cc_sm8250_probe(struct platform_device *pdev)
{
struct regmap *regmap;
int ret;
- pm_runtime_enable(&pdev->dev);
-
- ret = devm_add_action_or_reset(&pdev->dev, disp_cc_sm8250_pm_runtime_disable, &pdev->dev);
+ ret = devm_pm_runtime_enable(&pdev->dev);
if (ret)
return ret;
diff --git a/drivers/clk/qcom/dispcc-sm8450.c b/drivers/clk/qcom/dispcc-sm8450.c
index 0cd7ebe90301..adbfd30bfc96 100644
--- a/drivers/clk/qcom/dispcc-sm8450.c
+++ b/drivers/clk/qcom/dispcc-sm8450.c
@@ -694,8 +694,8 @@ static struct clk_regmap_div disp_cc_mdss_byte0_div_clk_src = {
.width = 4,
.clkr.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_byte0_div_clk_src",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_byte0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_byte0_clk_src.clkr.hw,
},
.num_parents = 1,
.ops = &clk_regmap_div_ops,
@@ -708,8 +708,8 @@ static struct clk_regmap_div disp_cc_mdss_byte1_div_clk_src = {
.width = 4,
.clkr.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_byte1_div_clk_src",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_byte1_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_byte1_clk_src.clkr.hw,
},
.num_parents = 1,
.ops = &clk_regmap_div_ops,
@@ -722,8 +722,8 @@ static struct clk_regmap_div disp_cc_mdss_dptx0_link_div_clk_src = {
.width = 4,
.clkr.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_dptx0_link_div_clk_src",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_dptx0_link_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx0_link_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -737,8 +737,8 @@ static struct clk_regmap_div disp_cc_mdss_dptx1_link_div_clk_src = {
.width = 4,
.clkr.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_dptx1_link_div_clk_src",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_dptx1_link_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx1_link_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -752,8 +752,8 @@ static struct clk_regmap_div disp_cc_mdss_dptx2_link_div_clk_src = {
.width = 4,
.clkr.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_dptx2_link_div_clk_src",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_dptx2_link_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx2_link_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -767,8 +767,8 @@ static struct clk_regmap_div disp_cc_mdss_dptx3_link_div_clk_src = {
.width = 4,
.clkr.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_dptx3_link_div_clk_src",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_dptx3_link_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx3_link_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -784,8 +784,8 @@ static struct clk_branch disp_cc_mdss_ahb1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_ahb1_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_ahb_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_ahb_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -802,8 +802,8 @@ static struct clk_branch disp_cc_mdss_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_ahb_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_ahb_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_ahb_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -820,8 +820,8 @@ static struct clk_branch disp_cc_mdss_byte0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_byte0_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_byte0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_byte0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -838,8 +838,8 @@ static struct clk_branch disp_cc_mdss_byte0_intf_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_byte0_intf_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_byte0_div_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_byte0_div_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -856,8 +856,8 @@ static struct clk_branch disp_cc_mdss_byte1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_byte1_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_byte1_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_byte1_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -874,8 +874,8 @@ static struct clk_branch disp_cc_mdss_byte1_intf_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_byte1_intf_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_byte1_div_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_byte1_div_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -892,8 +892,8 @@ static struct clk_branch disp_cc_mdss_dptx0_aux_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_dptx0_aux_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_dptx0_aux_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx0_aux_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -910,8 +910,8 @@ static struct clk_branch disp_cc_mdss_dptx0_crypto_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_dptx0_crypto_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_dptx0_link_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx0_link_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -928,8 +928,8 @@ static struct clk_branch disp_cc_mdss_dptx0_link_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_dptx0_link_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_dptx0_link_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx0_link_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -946,8 +946,8 @@ static struct clk_branch disp_cc_mdss_dptx0_link_intf_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_dptx0_link_intf_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_dptx0_link_div_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx0_link_div_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -964,8 +964,8 @@ static struct clk_branch disp_cc_mdss_dptx0_pixel0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_dptx0_pixel0_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_dptx0_pixel0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx0_pixel0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -982,8 +982,8 @@ static struct clk_branch disp_cc_mdss_dptx0_pixel1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_dptx0_pixel1_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_dptx0_pixel1_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx0_pixel1_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1000,8 +1000,8 @@ static struct clk_branch disp_cc_mdss_dptx0_usb_router_link_intf_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_dptx0_usb_router_link_intf_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_dptx0_link_div_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx0_link_div_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1018,8 +1018,8 @@ static struct clk_branch disp_cc_mdss_dptx1_aux_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_dptx1_aux_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_dptx1_aux_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx1_aux_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1036,8 +1036,8 @@ static struct clk_branch disp_cc_mdss_dptx1_crypto_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_dptx1_crypto_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_dptx1_link_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx1_link_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1054,8 +1054,8 @@ static struct clk_branch disp_cc_mdss_dptx1_link_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_dptx1_link_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_dptx1_link_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx1_link_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1072,8 +1072,8 @@ static struct clk_branch disp_cc_mdss_dptx1_link_intf_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_dptx1_link_intf_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_dptx1_link_div_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx1_link_div_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1090,8 +1090,8 @@ static struct clk_branch disp_cc_mdss_dptx1_pixel0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_dptx1_pixel0_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_dptx1_pixel0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx1_pixel0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1108,8 +1108,8 @@ static struct clk_branch disp_cc_mdss_dptx1_pixel1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_dptx1_pixel1_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_dptx1_pixel1_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx1_pixel1_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1126,8 +1126,8 @@ static struct clk_branch disp_cc_mdss_dptx1_usb_router_link_intf_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_dptx1_usb_router_link_intf_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_dptx0_link_div_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx0_link_div_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1144,8 +1144,8 @@ static struct clk_branch disp_cc_mdss_dptx2_aux_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_dptx2_aux_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_dptx2_aux_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx2_aux_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1162,8 +1162,8 @@ static struct clk_branch disp_cc_mdss_dptx2_crypto_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_dptx2_crypto_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_dptx2_link_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx2_link_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1180,8 +1180,8 @@ static struct clk_branch disp_cc_mdss_dptx2_link_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_dptx2_link_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_dptx2_link_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx2_link_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1198,8 +1198,8 @@ static struct clk_branch disp_cc_mdss_dptx2_link_intf_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_dptx2_link_intf_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_dptx2_link_div_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx2_link_div_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1216,8 +1216,8 @@ static struct clk_branch disp_cc_mdss_dptx2_pixel0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_dptx2_pixel0_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_dptx2_pixel0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx2_pixel0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1234,8 +1234,8 @@ static struct clk_branch disp_cc_mdss_dptx2_pixel1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_dptx2_pixel1_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_dptx2_pixel1_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx2_pixel1_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1252,8 +1252,8 @@ static struct clk_branch disp_cc_mdss_dptx3_aux_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_dptx3_aux_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_dptx3_aux_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx3_aux_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1270,8 +1270,8 @@ static struct clk_branch disp_cc_mdss_dptx3_crypto_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_dptx3_crypto_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_dptx3_link_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx3_link_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1288,8 +1288,8 @@ static struct clk_branch disp_cc_mdss_dptx3_link_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_dptx3_link_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_dptx3_link_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx3_link_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1306,8 +1306,8 @@ static struct clk_branch disp_cc_mdss_dptx3_link_intf_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_dptx3_link_intf_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_dptx3_link_div_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx3_link_div_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1324,8 +1324,8 @@ static struct clk_branch disp_cc_mdss_dptx3_pixel0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_dptx3_pixel0_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_dptx3_pixel0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx3_pixel0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1342,8 +1342,8 @@ static struct clk_branch disp_cc_mdss_esc0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_esc0_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_esc0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_esc0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1360,8 +1360,8 @@ static struct clk_branch disp_cc_mdss_esc1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_esc1_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_esc1_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_esc1_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1378,8 +1378,8 @@ static struct clk_branch disp_cc_mdss_mdp1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_mdp1_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_mdp_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_mdp_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1396,8 +1396,8 @@ static struct clk_branch disp_cc_mdss_mdp_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_mdp_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_mdp_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_mdp_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1414,8 +1414,8 @@ static struct clk_branch disp_cc_mdss_mdp_lut1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_mdp_lut1_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_mdp_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_mdp_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1432,8 +1432,8 @@ static struct clk_branch disp_cc_mdss_mdp_lut_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_mdp_lut_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_mdp_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_mdp_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1450,8 +1450,8 @@ static struct clk_branch disp_cc_mdss_non_gdsc_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_non_gdsc_ahb_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_ahb_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_ahb_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1468,8 +1468,8 @@ static struct clk_branch disp_cc_mdss_pclk0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_pclk0_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_pclk0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_pclk0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1486,8 +1486,8 @@ static struct clk_branch disp_cc_mdss_pclk1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_pclk1_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_pclk1_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_pclk1_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1504,8 +1504,8 @@ static struct clk_branch disp_cc_mdss_rot1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_rot1_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_rot_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_rot_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1522,8 +1522,8 @@ static struct clk_branch disp_cc_mdss_rot_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_rot_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_rot_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_rot_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1540,8 +1540,8 @@ static struct clk_branch disp_cc_mdss_rscc_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_rscc_ahb_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_ahb_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_ahb_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1558,8 +1558,8 @@ static struct clk_branch disp_cc_mdss_rscc_vsync_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_rscc_vsync_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_vsync_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_vsync_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1576,8 +1576,8 @@ static struct clk_branch disp_cc_mdss_vsync1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_vsync1_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_vsync_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_vsync_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1594,8 +1594,8 @@ static struct clk_branch disp_cc_mdss_vsync_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_mdss_vsync_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_mdss_vsync_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_vsync_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1612,8 +1612,8 @@ static struct clk_branch disp_cc_sleep_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "disp_cc_sleep_clk",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &disp_cc_sleep_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_sleep_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1762,19 +1762,12 @@ static const struct of_device_id disp_cc_sm8450_match_table[] = {
};
MODULE_DEVICE_TABLE(of, disp_cc_sm8450_match_table);
-static void disp_cc_sm8450_pm_runtime_disable(void *data)
-{
- pm_runtime_disable(data);
-}
-
static int disp_cc_sm8450_probe(struct platform_device *pdev)
{
struct regmap *regmap;
int ret;
- pm_runtime_enable(&pdev->dev);
-
- ret = devm_add_action_or_reset(&pdev->dev, disp_cc_sm8450_pm_runtime_disable, &pdev->dev);
+ ret = devm_pm_runtime_enable(&pdev->dev);
if (ret)
return ret;
diff --git a/drivers/clk/qcom/dispcc-sm8550.c b/drivers/clk/qcom/dispcc-sm8550.c
new file mode 100644
index 000000000000..1e5a11081860
--- /dev/null
+++ b/drivers/clk/qcom/dispcc-sm8550.c
@@ -0,0 +1,1807 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023, Linaro Ltd.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/pm_runtime.h>
+
+#include <dt-bindings/clock/qcom,sm8550-dispcc.h>
+
+#include "common.h"
+#include "clk-alpha-pll.h"
+#include "clk-branch.h"
+#include "clk-pll.h"
+#include "clk-rcg.h"
+#include "clk-regmap.h"
+#include "clk-regmap-divider.h"
+#include "clk-regmap-mux.h"
+#include "reset.h"
+#include "gdsc.h"
+
+/* Need to match the order of clocks in DT binding */
+enum {
+ DT_BI_TCXO,
+ DT_BI_TCXO_AO,
+ DT_AHB_CLK,
+ DT_SLEEP_CLK,
+
+ DT_DSI0_PHY_PLL_OUT_BYTECLK,
+ DT_DSI0_PHY_PLL_OUT_DSICLK,
+ DT_DSI1_PHY_PLL_OUT_BYTECLK,
+ DT_DSI1_PHY_PLL_OUT_DSICLK,
+
+ DT_DP0_PHY_PLL_LINK_CLK,
+ DT_DP0_PHY_PLL_VCO_DIV_CLK,
+ DT_DP1_PHY_PLL_LINK_CLK,
+ DT_DP1_PHY_PLL_VCO_DIV_CLK,
+ DT_DP2_PHY_PLL_LINK_CLK,
+ DT_DP2_PHY_PLL_VCO_DIV_CLK,
+ DT_DP3_PHY_PLL_LINK_CLK,
+ DT_DP3_PHY_PLL_VCO_DIV_CLK,
+};
+
+#define DISP_CC_MISC_CMD 0xF000
+
+enum {
+ P_BI_TCXO,
+ P_DISP_CC_PLL0_OUT_MAIN,
+ P_DISP_CC_PLL1_OUT_EVEN,
+ P_DISP_CC_PLL1_OUT_MAIN,
+ P_DP0_PHY_PLL_LINK_CLK,
+ P_DP0_PHY_PLL_VCO_DIV_CLK,
+ P_DP1_PHY_PLL_LINK_CLK,
+ P_DP1_PHY_PLL_VCO_DIV_CLK,
+ P_DP2_PHY_PLL_LINK_CLK,
+ P_DP2_PHY_PLL_VCO_DIV_CLK,
+ P_DP3_PHY_PLL_LINK_CLK,
+ P_DP3_PHY_PLL_VCO_DIV_CLK,
+ P_DSI0_PHY_PLL_OUT_BYTECLK,
+ P_DSI0_PHY_PLL_OUT_DSICLK,
+ P_DSI1_PHY_PLL_OUT_BYTECLK,
+ P_DSI1_PHY_PLL_OUT_DSICLK,
+ P_SLEEP_CLK,
+};
+
+static struct pll_vco lucid_ole_vco[] = {
+ { 249600000, 2000000000, 0 },
+};
+
+static const struct alpha_pll_config disp_cc_pll0_config = {
+ .l = 0xd,
+ .alpha = 0x6492,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00182261,
+ .config_ctl_hi1_val = 0x82aa299c,
+ .user_ctl_val = 0x00000000,
+ .user_ctl_hi_val = 0x00000005,
+};
+
+static struct clk_alpha_pll disp_cc_pll0 = {
+ .offset = 0x0,
+ .vco_table = lucid_ole_vco,
+ .num_vco = ARRAY_SIZE(lucid_ole_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_pll0",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_reset_lucid_ole_ops,
+ },
+ },
+};
+
+static const struct alpha_pll_config disp_cc_pll1_config = {
+ .l = 0x1f,
+ .alpha = 0x4000,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00182261,
+ .config_ctl_hi1_val = 0x82aa299c,
+ .user_ctl_val = 0x00000000,
+ .user_ctl_hi_val = 0x00000005,
+};
+
+static struct clk_alpha_pll disp_cc_pll1 = {
+ .offset = 0x1000,
+ .vco_table = lucid_ole_vco,
+ .num_vco = ARRAY_SIZE(lucid_ole_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_pll1",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_reset_lucid_ole_ops,
+ },
+ },
+};
+
+static const struct parent_map disp_cc_parent_map_0[] = {
+ { P_BI_TCXO, 0 },
+};
+
+static const struct clk_parent_data disp_cc_parent_data_0[] = {
+ { .index = DT_BI_TCXO },
+};
+
+static const struct clk_parent_data disp_cc_parent_data_0_ao[] = {
+ { .index = DT_BI_TCXO_AO },
+};
+
+static const struct parent_map disp_cc_parent_map_1[] = {
+ { P_BI_TCXO, 0 },
+ { P_DP3_PHY_PLL_VCO_DIV_CLK, 3 },
+ { P_DP1_PHY_PLL_VCO_DIV_CLK, 4 },
+ { P_DP2_PHY_PLL_VCO_DIV_CLK, 6 },
+};
+
+static const struct clk_parent_data disp_cc_parent_data_1[] = {
+ { .index = DT_BI_TCXO },
+ { .index = DT_DP3_PHY_PLL_VCO_DIV_CLK },
+ { .index = DT_DP1_PHY_PLL_VCO_DIV_CLK },
+ { .index = DT_DP2_PHY_PLL_VCO_DIV_CLK },
+};
+
+static const struct parent_map disp_cc_parent_map_2[] = {
+ { P_BI_TCXO, 0 },
+ { P_DSI0_PHY_PLL_OUT_DSICLK, 1 },
+ { P_DSI0_PHY_PLL_OUT_BYTECLK, 2 },
+ { P_DSI1_PHY_PLL_OUT_DSICLK, 3 },
+ { P_DSI1_PHY_PLL_OUT_BYTECLK, 4 },
+};
+
+static const struct clk_parent_data disp_cc_parent_data_2[] = {
+ { .index = DT_BI_TCXO },
+ { .index = DT_DSI0_PHY_PLL_OUT_DSICLK },
+ { .index = DT_DSI0_PHY_PLL_OUT_BYTECLK },
+ { .index = DT_DSI1_PHY_PLL_OUT_DSICLK },
+ { .index = DT_DSI1_PHY_PLL_OUT_BYTECLK },
+};
+
+static const struct parent_map disp_cc_parent_map_3[] = {
+ { P_BI_TCXO, 0 },
+ { P_DP1_PHY_PLL_LINK_CLK, 2 },
+ { P_DP2_PHY_PLL_LINK_CLK, 3 },
+ { P_DP3_PHY_PLL_LINK_CLK, 4 },
+};
+
+static const struct clk_parent_data disp_cc_parent_data_3[] = {
+ { .index = DT_BI_TCXO },
+ { .index = DT_DP1_PHY_PLL_LINK_CLK },
+ { .index = DT_DP2_PHY_PLL_LINK_CLK },
+ { .index = DT_DP3_PHY_PLL_LINK_CLK },
+};
+
+static const struct parent_map disp_cc_parent_map_4[] = {
+ { P_BI_TCXO, 0 },
+ { P_DP0_PHY_PLL_LINK_CLK, 1 },
+ { P_DP1_PHY_PLL_VCO_DIV_CLK, 2 },
+ { P_DP3_PHY_PLL_VCO_DIV_CLK, 3 },
+ { P_DP1_PHY_PLL_VCO_DIV_CLK, 4 },
+ { P_DP2_PHY_PLL_VCO_DIV_CLK, 6 },
+};
+
+static const struct clk_parent_data disp_cc_parent_data_4[] = {
+ { .index = DT_BI_TCXO },
+ { .index = DT_DP0_PHY_PLL_LINK_CLK },
+ { .index = DT_DP0_PHY_PLL_VCO_DIV_CLK },
+ { .index = DT_DP3_PHY_PLL_VCO_DIV_CLK },
+ { .index = DT_DP1_PHY_PLL_VCO_DIV_CLK },
+ { .index = DT_DP2_PHY_PLL_VCO_DIV_CLK },
+};
+
+static const struct parent_map disp_cc_parent_map_5[] = {
+ { P_BI_TCXO, 0 },
+ { P_DSI0_PHY_PLL_OUT_BYTECLK, 4 },
+ { P_DSI1_PHY_PLL_OUT_BYTECLK, 4 },
+};
+
+static const struct clk_parent_data disp_cc_parent_data_5[] = {
+ { .index = DT_BI_TCXO },
+ { .index = DT_DSI0_PHY_PLL_OUT_BYTECLK },
+ { .index = DT_DSI1_PHY_PLL_OUT_BYTECLK },
+};
+
+static const struct parent_map disp_cc_parent_map_6[] = {
+ { P_BI_TCXO, 0 },
+ { P_DISP_CC_PLL1_OUT_MAIN, 4 },
+ { P_DISP_CC_PLL1_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data disp_cc_parent_data_6[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &disp_cc_pll1.clkr.hw },
+ { .hw = &disp_cc_pll1.clkr.hw },
+};
+
+static const struct parent_map disp_cc_parent_map_7[] = {
+ { P_BI_TCXO, 0 },
+ { P_DP0_PHY_PLL_LINK_CLK, 1 },
+ { P_DP1_PHY_PLL_LINK_CLK, 2 },
+ { P_DP2_PHY_PLL_LINK_CLK, 3 },
+ { P_DP3_PHY_PLL_LINK_CLK, 4 },
+};
+
+static const struct clk_parent_data disp_cc_parent_data_7[] = {
+ { .index = DT_BI_TCXO },
+ { .index = DT_DP0_PHY_PLL_LINK_CLK },
+ { .index = DT_DP1_PHY_PLL_LINK_CLK },
+ { .index = DT_DP2_PHY_PLL_LINK_CLK },
+ { .index = DT_DP3_PHY_PLL_LINK_CLK },
+};
+
+static const struct parent_map disp_cc_parent_map_8[] = {
+ { P_BI_TCXO, 0 },
+ { P_DISP_CC_PLL0_OUT_MAIN, 1 },
+ { P_DISP_CC_PLL1_OUT_MAIN, 4 },
+ { P_DISP_CC_PLL1_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data disp_cc_parent_data_8[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &disp_cc_pll0.clkr.hw },
+ { .hw = &disp_cc_pll1.clkr.hw },
+ { .hw = &disp_cc_pll1.clkr.hw },
+};
+
+static const struct parent_map disp_cc_parent_map_9[] = {
+ { P_SLEEP_CLK, 0 },
+};
+
+static const struct clk_parent_data disp_cc_parent_data_9[] = {
+ { .index = DT_SLEEP_CLK },
+};
+
+static const struct freq_tbl ftbl_disp_cc_mdss_ahb_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(37500000, P_DISP_CC_PLL1_OUT_MAIN, 16, 0, 0),
+ F(75000000, P_DISP_CC_PLL1_OUT_MAIN, 8, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 disp_cc_mdss_ahb_clk_src = {
+ .cmd_rcgr = 0x82e8,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_6,
+ .freq_tbl = ftbl_disp_cc_mdss_ahb_clk_src,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_ahb_clk_src",
+ .parent_data = disp_cc_parent_data_6,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_6),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_disp_cc_mdss_byte0_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 disp_cc_mdss_byte0_clk_src = {
+ .cmd_rcgr = 0x8108,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_2,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_byte0_clk_src",
+ .parent_data = disp_cc_parent_data_2,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_2),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_byte2_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_byte1_clk_src = {
+ .cmd_rcgr = 0x8124,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_2,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_byte1_clk_src",
+ .parent_data = disp_cc_parent_data_2,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_2),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_byte2_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_dptx0_aux_clk_src = {
+ .cmd_rcgr = 0x81bc,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_0,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx0_aux_clk_src",
+ .parent_data = disp_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_disp_cc_mdss_dptx0_link_clk_src[] = {
+ F(162000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0),
+ F(270000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0),
+ F(540000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0),
+ F(810000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 disp_cc_mdss_dptx0_link_clk_src = {
+ .cmd_rcgr = 0x8170,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_7,
+ .freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx0_link_clk_src",
+ .parent_data = disp_cc_parent_data_7,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_7),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_dptx0_pixel0_clk_src = {
+ .cmd_rcgr = 0x818c,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_4,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx0_pixel0_clk_src",
+ .parent_data = disp_cc_parent_data_4,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_4),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_dp_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_dptx0_pixel1_clk_src = {
+ .cmd_rcgr = 0x81a4,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_4,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx0_pixel1_clk_src",
+ .parent_data = disp_cc_parent_data_4,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_4),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_dp_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_dptx1_aux_clk_src = {
+ .cmd_rcgr = 0x8220,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_0,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx1_aux_clk_src",
+ .parent_data = disp_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_dp_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_dptx1_link_clk_src = {
+ .cmd_rcgr = 0x8204,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_3,
+ .freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx1_link_clk_src",
+ .parent_data = disp_cc_parent_data_3,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_3),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_dptx1_pixel0_clk_src = {
+ .cmd_rcgr = 0x81d4,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_1,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx1_pixel0_clk_src",
+ .parent_data = disp_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_dp_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_dptx1_pixel1_clk_src = {
+ .cmd_rcgr = 0x81ec,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_1,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx1_pixel1_clk_src",
+ .parent_data = disp_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_dp_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_dptx2_aux_clk_src = {
+ .cmd_rcgr = 0x8284,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_0,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx2_aux_clk_src",
+ .parent_data = disp_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_dptx2_link_clk_src = {
+ .cmd_rcgr = 0x8238,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_3,
+ .freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx2_link_clk_src",
+ .parent_data = disp_cc_parent_data_3,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_3),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_dptx2_pixel0_clk_src = {
+ .cmd_rcgr = 0x8254,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_1,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx2_pixel0_clk_src",
+ .parent_data = disp_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_dp_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_dptx2_pixel1_clk_src = {
+ .cmd_rcgr = 0x826c,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_1,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx2_pixel1_clk_src",
+ .parent_data = disp_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_dp_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_dptx3_aux_clk_src = {
+ .cmd_rcgr = 0x82d0,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_0,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx3_aux_clk_src",
+ .parent_data = disp_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_dptx3_link_clk_src = {
+ .cmd_rcgr = 0x82b4,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_3,
+ .freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx3_link_clk_src",
+ .parent_data = disp_cc_parent_data_3,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_3),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_dptx3_pixel0_clk_src = {
+ .cmd_rcgr = 0x829c,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_1,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx3_pixel0_clk_src",
+ .parent_data = disp_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_dp_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_esc0_clk_src = {
+ .cmd_rcgr = 0x8140,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_5,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_esc0_clk_src",
+ .parent_data = disp_cc_parent_data_5,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_5),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_esc1_clk_src = {
+ .cmd_rcgr = 0x8158,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_5,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_esc1_clk_src",
+ .parent_data = disp_cc_parent_data_5,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_5),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_disp_cc_mdss_mdp_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(85714286, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0),
+ F(100000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0),
+ F(150000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0),
+ F(172000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0),
+ F(200000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0),
+ F(325000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0),
+ F(375000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0),
+ F(514000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 disp_cc_mdss_mdp_clk_src = {
+ .cmd_rcgr = 0x80d8,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_8,
+ .freq_tbl = ftbl_disp_cc_mdss_mdp_clk_src,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_mdp_clk_src",
+ .parent_data = disp_cc_parent_data_8,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_8),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_pclk0_clk_src = {
+ .cmd_rcgr = 0x80a8,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_2,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_pclk0_clk_src",
+ .parent_data = disp_cc_parent_data_2,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_2),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_pixel_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_pclk1_clk_src = {
+ .cmd_rcgr = 0x80c0,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_2,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_pclk1_clk_src",
+ .parent_data = disp_cc_parent_data_2,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_2),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_pixel_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_vsync_clk_src = {
+ .cmd_rcgr = 0x80f0,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_0,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_vsync_clk_src",
+ .parent_data = disp_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_disp_cc_sleep_clk_src[] = {
+ F(32000, P_SLEEP_CLK, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 disp_cc_sleep_clk_src = {
+ .cmd_rcgr = 0xe05c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_9,
+ .freq_tbl = ftbl_disp_cc_sleep_clk_src,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_sleep_clk_src",
+ .parent_data = disp_cc_parent_data_9,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_9),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_xo_clk_src = {
+ .cmd_rcgr = 0xe03c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_0,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_xo_clk_src",
+ .parent_data = disp_cc_parent_data_0_ao,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_0_ao),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_regmap_div disp_cc_mdss_byte0_div_clk_src = {
+ .reg = 0x8120,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_byte0_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_byte0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_div_ops,
+ },
+};
+
+static struct clk_regmap_div disp_cc_mdss_byte1_div_clk_src = {
+ .reg = 0x813c,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_byte1_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_byte1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_div_ops,
+ },
+};
+
+static struct clk_regmap_div disp_cc_mdss_dptx0_link_div_clk_src = {
+ .reg = 0x8188,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx0_link_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx0_link_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div disp_cc_mdss_dptx1_link_div_clk_src = {
+ .reg = 0x821c,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx1_link_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx1_link_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div disp_cc_mdss_dptx2_link_div_clk_src = {
+ .reg = 0x8250,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx2_link_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx2_link_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div disp_cc_mdss_dptx3_link_div_clk_src = {
+ .reg = 0x82cc,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx3_link_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx3_link_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_branch disp_cc_mdss_accu_clk = {
+ .halt_reg = 0xe058,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0xe058,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "disp_cc_mdss_accu_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_xo_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_ahb1_clk = {
+ .halt_reg = 0xa020,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa020,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_ahb1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_ahb_clk = {
+ .halt_reg = 0x80a4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x80a4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_byte0_clk = {
+ .halt_reg = 0x8028,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8028,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_byte0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_byte0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_byte0_intf_clk = {
+ .halt_reg = 0x802c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x802c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_byte0_intf_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_byte0_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_byte1_clk = {
+ .halt_reg = 0x8030,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8030,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_byte1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_byte1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_byte1_intf_clk = {
+ .halt_reg = 0x8034,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8034,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_byte1_intf_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_byte1_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx0_aux_clk = {
+ .halt_reg = 0x8058,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8058,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx0_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx0_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx0_crypto_clk = {
+ .halt_reg = 0x804c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x804c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx0_crypto_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx0_link_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx0_link_clk = {
+ .halt_reg = 0x8040,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8040,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx0_link_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx0_link_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx0_link_intf_clk = {
+ .halt_reg = 0x8048,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8048,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx0_link_intf_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx0_link_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx0_pixel0_clk = {
+ .halt_reg = 0x8050,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8050,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx0_pixel0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx0_pixel0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx0_pixel1_clk = {
+ .halt_reg = 0x8054,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8054,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx0_pixel1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx0_pixel1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx0_usb_router_link_intf_clk = {
+ .halt_reg = 0x8044,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8044,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx0_usb_router_link_intf_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx0_link_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx1_aux_clk = {
+ .halt_reg = 0x8074,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8074,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx1_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx1_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx1_crypto_clk = {
+ .halt_reg = 0x8070,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8070,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx1_crypto_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx1_link_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx1_link_clk = {
+ .halt_reg = 0x8064,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8064,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx1_link_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx1_link_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx1_link_intf_clk = {
+ .halt_reg = 0x806c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x806c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx1_link_intf_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx1_link_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx1_pixel0_clk = {
+ .halt_reg = 0x805c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x805c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx1_pixel0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx1_pixel0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx1_pixel1_clk = {
+ .halt_reg = 0x8060,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8060,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx1_pixel1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx1_pixel1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx1_usb_router_link_intf_clk = {
+ .halt_reg = 0x8068,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8068,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx1_usb_router_link_intf_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx0_link_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx2_aux_clk = {
+ .halt_reg = 0x808c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x808c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx2_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx2_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx2_crypto_clk = {
+ .halt_reg = 0x8088,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8088,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx2_crypto_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx2_link_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx2_link_clk = {
+ .halt_reg = 0x8080,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8080,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx2_link_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx2_link_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx2_link_intf_clk = {
+ .halt_reg = 0x8084,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8084,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx2_link_intf_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx2_link_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx2_pixel0_clk = {
+ .halt_reg = 0x8078,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8078,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx2_pixel0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx2_pixel0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx2_pixel1_clk = {
+ .halt_reg = 0x807c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x807c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx2_pixel1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx2_pixel1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx3_aux_clk = {
+ .halt_reg = 0x809c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x809c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx3_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx3_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx3_crypto_clk = {
+ .halt_reg = 0x80a0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x80a0,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx3_crypto_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx3_link_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx3_link_clk = {
+ .halt_reg = 0x8094,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8094,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx3_link_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx3_link_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx3_link_intf_clk = {
+ .halt_reg = 0x8098,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8098,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx3_link_intf_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx3_link_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx3_pixel0_clk = {
+ .halt_reg = 0x8090,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8090,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx3_pixel0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx3_pixel0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_esc0_clk = {
+ .halt_reg = 0x8038,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8038,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_esc0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_esc0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_esc1_clk = {
+ .halt_reg = 0x803c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x803c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_esc1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_esc1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_mdp1_clk = {
+ .halt_reg = 0xa004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_mdp1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_mdp_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_mdp_clk = {
+ .halt_reg = 0x800c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x800c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_mdp_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_mdp_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_mdp_lut1_clk = {
+ .halt_reg = 0xa010,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa010,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_mdp_lut1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_mdp_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_mdp_lut_clk = {
+ .halt_reg = 0x8018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x8018,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_mdp_lut_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_mdp_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_non_gdsc_ahb_clk = {
+ .halt_reg = 0xc004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0xc004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_non_gdsc_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_pclk0_clk = {
+ .halt_reg = 0x8004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_pclk0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_pclk0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_pclk1_clk = {
+ .halt_reg = 0x8008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_pclk1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_pclk1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_rscc_ahb_clk = {
+ .halt_reg = 0xc00c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc00c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_rscc_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_rscc_vsync_clk = {
+ .halt_reg = 0xc008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_rscc_vsync_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_vsync_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_vsync1_clk = {
+ .halt_reg = 0xa01c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa01c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_vsync1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_vsync_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_vsync_clk = {
+ .halt_reg = 0x8024,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8024,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_mdss_vsync_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_vsync_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_sleep_clk = {
+ .halt_reg = 0xe074,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xe074,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data) {
+ .name = "disp_cc_sleep_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_sleep_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct gdsc mdss_gdsc = {
+ .gdscr = 0x9000,
+ .pd = {
+ .name = "mdss_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = HW_CTRL | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc mdss_int2_gdsc = {
+ .gdscr = 0xb000,
+ .pd = {
+ .name = "mdss_int2_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = HW_CTRL | RETAIN_FF_ENABLE,
+};
+
+static struct clk_regmap *disp_cc_sm8550_clocks[] = {
+ [DISP_CC_MDSS_ACCU_CLK] = &disp_cc_mdss_accu_clk.clkr,
+ [DISP_CC_MDSS_AHB1_CLK] = &disp_cc_mdss_ahb1_clk.clkr,
+ [DISP_CC_MDSS_AHB_CLK] = &disp_cc_mdss_ahb_clk.clkr,
+ [DISP_CC_MDSS_AHB_CLK_SRC] = &disp_cc_mdss_ahb_clk_src.clkr,
+ [DISP_CC_MDSS_BYTE0_CLK] = &disp_cc_mdss_byte0_clk.clkr,
+ [DISP_CC_MDSS_BYTE0_CLK_SRC] = &disp_cc_mdss_byte0_clk_src.clkr,
+ [DISP_CC_MDSS_BYTE0_DIV_CLK_SRC] = &disp_cc_mdss_byte0_div_clk_src.clkr,
+ [DISP_CC_MDSS_BYTE0_INTF_CLK] = &disp_cc_mdss_byte0_intf_clk.clkr,
+ [DISP_CC_MDSS_BYTE1_CLK] = &disp_cc_mdss_byte1_clk.clkr,
+ [DISP_CC_MDSS_BYTE1_CLK_SRC] = &disp_cc_mdss_byte1_clk_src.clkr,
+ [DISP_CC_MDSS_BYTE1_DIV_CLK_SRC] = &disp_cc_mdss_byte1_div_clk_src.clkr,
+ [DISP_CC_MDSS_BYTE1_INTF_CLK] = &disp_cc_mdss_byte1_intf_clk.clkr,
+ [DISP_CC_MDSS_DPTX0_AUX_CLK] = &disp_cc_mdss_dptx0_aux_clk.clkr,
+ [DISP_CC_MDSS_DPTX0_AUX_CLK_SRC] = &disp_cc_mdss_dptx0_aux_clk_src.clkr,
+ [DISP_CC_MDSS_DPTX0_CRYPTO_CLK] = &disp_cc_mdss_dptx0_crypto_clk.clkr,
+ [DISP_CC_MDSS_DPTX0_LINK_CLK] = &disp_cc_mdss_dptx0_link_clk.clkr,
+ [DISP_CC_MDSS_DPTX0_LINK_CLK_SRC] = &disp_cc_mdss_dptx0_link_clk_src.clkr,
+ [DISP_CC_MDSS_DPTX0_LINK_DIV_CLK_SRC] = &disp_cc_mdss_dptx0_link_div_clk_src.clkr,
+ [DISP_CC_MDSS_DPTX0_LINK_INTF_CLK] = &disp_cc_mdss_dptx0_link_intf_clk.clkr,
+ [DISP_CC_MDSS_DPTX0_PIXEL0_CLK] = &disp_cc_mdss_dptx0_pixel0_clk.clkr,
+ [DISP_CC_MDSS_DPTX0_PIXEL0_CLK_SRC] = &disp_cc_mdss_dptx0_pixel0_clk_src.clkr,
+ [DISP_CC_MDSS_DPTX0_PIXEL1_CLK] = &disp_cc_mdss_dptx0_pixel1_clk.clkr,
+ [DISP_CC_MDSS_DPTX0_PIXEL1_CLK_SRC] = &disp_cc_mdss_dptx0_pixel1_clk_src.clkr,
+ [DISP_CC_MDSS_DPTX0_USB_ROUTER_LINK_INTF_CLK] =
+ &disp_cc_mdss_dptx0_usb_router_link_intf_clk.clkr,
+ [DISP_CC_MDSS_DPTX1_AUX_CLK] = &disp_cc_mdss_dptx1_aux_clk.clkr,
+ [DISP_CC_MDSS_DPTX1_AUX_CLK_SRC] = &disp_cc_mdss_dptx1_aux_clk_src.clkr,
+ [DISP_CC_MDSS_DPTX1_CRYPTO_CLK] = &disp_cc_mdss_dptx1_crypto_clk.clkr,
+ [DISP_CC_MDSS_DPTX1_LINK_CLK] = &disp_cc_mdss_dptx1_link_clk.clkr,
+ [DISP_CC_MDSS_DPTX1_LINK_CLK_SRC] = &disp_cc_mdss_dptx1_link_clk_src.clkr,
+ [DISP_CC_MDSS_DPTX1_LINK_DIV_CLK_SRC] = &disp_cc_mdss_dptx1_link_div_clk_src.clkr,
+ [DISP_CC_MDSS_DPTX1_LINK_INTF_CLK] = &disp_cc_mdss_dptx1_link_intf_clk.clkr,
+ [DISP_CC_MDSS_DPTX1_PIXEL0_CLK] = &disp_cc_mdss_dptx1_pixel0_clk.clkr,
+ [DISP_CC_MDSS_DPTX1_PIXEL0_CLK_SRC] = &disp_cc_mdss_dptx1_pixel0_clk_src.clkr,
+ [DISP_CC_MDSS_DPTX1_PIXEL1_CLK] = &disp_cc_mdss_dptx1_pixel1_clk.clkr,
+ [DISP_CC_MDSS_DPTX1_PIXEL1_CLK_SRC] = &disp_cc_mdss_dptx1_pixel1_clk_src.clkr,
+ [DISP_CC_MDSS_DPTX1_USB_ROUTER_LINK_INTF_CLK] =
+ &disp_cc_mdss_dptx1_usb_router_link_intf_clk.clkr,
+ [DISP_CC_MDSS_DPTX2_AUX_CLK] = &disp_cc_mdss_dptx2_aux_clk.clkr,
+ [DISP_CC_MDSS_DPTX2_AUX_CLK_SRC] = &disp_cc_mdss_dptx2_aux_clk_src.clkr,
+ [DISP_CC_MDSS_DPTX2_CRYPTO_CLK] = &disp_cc_mdss_dptx2_crypto_clk.clkr,
+ [DISP_CC_MDSS_DPTX2_LINK_CLK] = &disp_cc_mdss_dptx2_link_clk.clkr,
+ [DISP_CC_MDSS_DPTX2_LINK_CLK_SRC] = &disp_cc_mdss_dptx2_link_clk_src.clkr,
+ [DISP_CC_MDSS_DPTX2_LINK_DIV_CLK_SRC] = &disp_cc_mdss_dptx2_link_div_clk_src.clkr,
+ [DISP_CC_MDSS_DPTX2_LINK_INTF_CLK] = &disp_cc_mdss_dptx2_link_intf_clk.clkr,
+ [DISP_CC_MDSS_DPTX2_PIXEL0_CLK] = &disp_cc_mdss_dptx2_pixel0_clk.clkr,
+ [DISP_CC_MDSS_DPTX2_PIXEL0_CLK_SRC] = &disp_cc_mdss_dptx2_pixel0_clk_src.clkr,
+ [DISP_CC_MDSS_DPTX2_PIXEL1_CLK] = &disp_cc_mdss_dptx2_pixel1_clk.clkr,
+ [DISP_CC_MDSS_DPTX2_PIXEL1_CLK_SRC] = &disp_cc_mdss_dptx2_pixel1_clk_src.clkr,
+ [DISP_CC_MDSS_DPTX3_AUX_CLK] = &disp_cc_mdss_dptx3_aux_clk.clkr,
+ [DISP_CC_MDSS_DPTX3_AUX_CLK_SRC] = &disp_cc_mdss_dptx3_aux_clk_src.clkr,
+ [DISP_CC_MDSS_DPTX3_CRYPTO_CLK] = &disp_cc_mdss_dptx3_crypto_clk.clkr,
+ [DISP_CC_MDSS_DPTX3_LINK_CLK] = &disp_cc_mdss_dptx3_link_clk.clkr,
+ [DISP_CC_MDSS_DPTX3_LINK_CLK_SRC] = &disp_cc_mdss_dptx3_link_clk_src.clkr,
+ [DISP_CC_MDSS_DPTX3_LINK_DIV_CLK_SRC] = &disp_cc_mdss_dptx3_link_div_clk_src.clkr,
+ [DISP_CC_MDSS_DPTX3_LINK_INTF_CLK] = &disp_cc_mdss_dptx3_link_intf_clk.clkr,
+ [DISP_CC_MDSS_DPTX3_PIXEL0_CLK] = &disp_cc_mdss_dptx3_pixel0_clk.clkr,
+ [DISP_CC_MDSS_DPTX3_PIXEL0_CLK_SRC] = &disp_cc_mdss_dptx3_pixel0_clk_src.clkr,
+ [DISP_CC_MDSS_ESC0_CLK] = &disp_cc_mdss_esc0_clk.clkr,
+ [DISP_CC_MDSS_ESC0_CLK_SRC] = &disp_cc_mdss_esc0_clk_src.clkr,
+ [DISP_CC_MDSS_ESC1_CLK] = &disp_cc_mdss_esc1_clk.clkr,
+ [DISP_CC_MDSS_ESC1_CLK_SRC] = &disp_cc_mdss_esc1_clk_src.clkr,
+ [DISP_CC_MDSS_MDP1_CLK] = &disp_cc_mdss_mdp1_clk.clkr,
+ [DISP_CC_MDSS_MDP_CLK] = &disp_cc_mdss_mdp_clk.clkr,
+ [DISP_CC_MDSS_MDP_CLK_SRC] = &disp_cc_mdss_mdp_clk_src.clkr,
+ [DISP_CC_MDSS_MDP_LUT1_CLK] = &disp_cc_mdss_mdp_lut1_clk.clkr,
+ [DISP_CC_MDSS_MDP_LUT_CLK] = &disp_cc_mdss_mdp_lut_clk.clkr,
+ [DISP_CC_MDSS_NON_GDSC_AHB_CLK] = &disp_cc_mdss_non_gdsc_ahb_clk.clkr,
+ [DISP_CC_MDSS_PCLK0_CLK] = &disp_cc_mdss_pclk0_clk.clkr,
+ [DISP_CC_MDSS_PCLK0_CLK_SRC] = &disp_cc_mdss_pclk0_clk_src.clkr,
+ [DISP_CC_MDSS_PCLK1_CLK] = &disp_cc_mdss_pclk1_clk.clkr,
+ [DISP_CC_MDSS_PCLK1_CLK_SRC] = &disp_cc_mdss_pclk1_clk_src.clkr,
+ [DISP_CC_MDSS_RSCC_AHB_CLK] = &disp_cc_mdss_rscc_ahb_clk.clkr,
+ [DISP_CC_MDSS_RSCC_VSYNC_CLK] = &disp_cc_mdss_rscc_vsync_clk.clkr,
+ [DISP_CC_MDSS_VSYNC1_CLK] = &disp_cc_mdss_vsync1_clk.clkr,
+ [DISP_CC_MDSS_VSYNC_CLK] = &disp_cc_mdss_vsync_clk.clkr,
+ [DISP_CC_MDSS_VSYNC_CLK_SRC] = &disp_cc_mdss_vsync_clk_src.clkr,
+ [DISP_CC_PLL0] = &disp_cc_pll0.clkr,
+ [DISP_CC_PLL1] = &disp_cc_pll1.clkr,
+ [DISP_CC_SLEEP_CLK] = &disp_cc_sleep_clk.clkr,
+ [DISP_CC_SLEEP_CLK_SRC] = &disp_cc_sleep_clk_src.clkr,
+ [DISP_CC_XO_CLK_SRC] = &disp_cc_xo_clk_src.clkr,
+};
+
+static const struct qcom_reset_map disp_cc_sm8550_resets[] = {
+ [DISP_CC_MDSS_CORE_BCR] = { 0x8000 },
+ [DISP_CC_MDSS_CORE_INT2_BCR] = { 0xa000 },
+ [DISP_CC_MDSS_RSCC_BCR] = { 0xc000 },
+};
+
+static struct gdsc *disp_cc_sm8550_gdscs[] = {
+ [MDSS_GDSC] = &mdss_gdsc,
+ [MDSS_INT2_GDSC] = &mdss_int2_gdsc,
+};
+
+static const struct regmap_config disp_cc_sm8550_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x11008,
+ .fast_io = true,
+};
+
+static struct qcom_cc_desc disp_cc_sm8550_desc = {
+ .config = &disp_cc_sm8550_regmap_config,
+ .clks = disp_cc_sm8550_clocks,
+ .num_clks = ARRAY_SIZE(disp_cc_sm8550_clocks),
+ .resets = disp_cc_sm8550_resets,
+ .num_resets = ARRAY_SIZE(disp_cc_sm8550_resets),
+ .gdscs = disp_cc_sm8550_gdscs,
+ .num_gdscs = ARRAY_SIZE(disp_cc_sm8550_gdscs),
+};
+
+static const struct of_device_id disp_cc_sm8550_match_table[] = {
+ { .compatible = "qcom,sm8550-dispcc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, disp_cc_sm8550_match_table);
+
+static int disp_cc_sm8550_probe(struct platform_device *pdev)
+{
+ struct regmap *regmap;
+ int ret;
+
+ ret = devm_pm_runtime_enable(&pdev->dev);
+ if (ret)
+ return ret;
+
+ ret = pm_runtime_resume_and_get(&pdev->dev);
+ if (ret)
+ return ret;
+
+ regmap = qcom_cc_map(pdev, &disp_cc_sm8550_desc);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ clk_lucid_evo_pll_configure(&disp_cc_pll0, regmap, &disp_cc_pll0_config);
+ clk_lucid_evo_pll_configure(&disp_cc_pll1, regmap, &disp_cc_pll1_config);
+
+ /* Enable clock gating for MDP clocks */
+ regmap_update_bits(regmap, DISP_CC_MISC_CMD, 0x10, 0x10);
+
+ /*
+ * Keep clocks always enabled:
+ * disp_cc_xo_clk
+ */
+ regmap_update_bits(regmap, 0xe054, BIT(0), BIT(0));
+
+ ret = qcom_cc_really_probe(pdev, &disp_cc_sm8550_desc, regmap);
+
+ pm_runtime_put(&pdev->dev);
+
+ return ret;
+}
+
+static struct platform_driver disp_cc_sm8550_driver = {
+ .probe = disp_cc_sm8550_probe,
+ .driver = {
+ .name = "disp_cc-sm8550",
+ .of_match_table = disp_cc_sm8550_match_table,
+ },
+};
+
+static int __init disp_cc_sm8550_init(void)
+{
+ return platform_driver_register(&disp_cc_sm8550_driver);
+}
+subsys_initcall(disp_cc_sm8550_init);
+
+static void __exit disp_cc_sm8550_exit(void)
+{
+ platform_driver_unregister(&disp_cc_sm8550_driver);
+}
+module_exit(disp_cc_sm8550_exit);
+
+MODULE_DESCRIPTION("QTI DISPCC SM8550 Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/qcom/gcc-apq8084.c b/drivers/clk/qcom/gcc-apq8084.c
index ab088d702d7c..7085d2ccae49 100644
--- a/drivers/clk/qcom/gcc-apq8084.c
+++ b/drivers/clk/qcom/gcc-apq8084.c
@@ -36,68 +36,6 @@ enum {
P_SLEEP_CLK,
};
-static const struct parent_map gcc_xo_gpll0_map[] = {
- { P_XO, 0 },
- { P_GPLL0, 1 }
-};
-
-static const char * const gcc_xo_gpll0[] = {
- "xo",
- "gpll0_vote",
-};
-
-static const struct parent_map gcc_xo_gpll0_gpll4_map[] = {
- { P_XO, 0 },
- { P_GPLL0, 1 },
- { P_GPLL4, 5 }
-};
-
-static const char * const gcc_xo_gpll0_gpll4[] = {
- "xo",
- "gpll0_vote",
- "gpll4_vote",
-};
-
-static const struct parent_map gcc_xo_sata_asic0_map[] = {
- { P_XO, 0 },
- { P_SATA_ASIC0_CLK, 2 }
-};
-
-static const char * const gcc_xo_sata_asic0[] = {
- "xo",
- "sata_asic0_clk",
-};
-
-static const struct parent_map gcc_xo_sata_rx_map[] = {
- { P_XO, 0 },
- { P_SATA_RX_CLK, 2}
-};
-
-static const char * const gcc_xo_sata_rx[] = {
- "xo",
- "sata_rx_clk",
-};
-
-static const struct parent_map gcc_xo_pcie_map[] = {
- { P_XO, 0 },
- { P_PCIE_0_1_PIPE_CLK, 2 }
-};
-
-static const char * const gcc_xo_pcie[] = {
- "xo",
- "pcie_pipe",
-};
-
-static const struct parent_map gcc_xo_pcie_sleep_map[] = {
- { P_XO, 0 },
- { P_SLEEP_CLK, 6 }
-};
-
-static const char * const gcc_xo_pcie_sleep[] = {
- "xo",
- "sleep_clk_src",
-};
-
static struct clk_pll gpll0 = {
.l_reg = 0x0004,
.m_reg = 0x0008,
@@ -108,7 +46,9 @@ static struct clk_pll gpll0 = {
.status_bit = 17,
.clkr.hw.init = &(struct clk_init_data){
.name = "gpll0",
- .parent_names = (const char *[]){ "xo" },
+ .parent_data = &(const struct clk_parent_data){
+ .fw_name = "xo", .name = "xo_board",
+ },
.num_parents = 1,
.ops = &clk_pll_ops,
},
@@ -119,48 +59,14 @@ static struct clk_regmap gpll0_vote = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gpll0_vote",
- .parent_names = (const char *[]){ "gpll0" },
+ .parent_hws = (const struct clk_hw*[]){
+ &gpll0.clkr.hw,
+ },
.num_parents = 1,
.ops = &clk_pll_vote_ops,
},
};
-static struct clk_rcg2 config_noc_clk_src = {
- .cmd_rcgr = 0x0150,
- .hid_width = 5,
- .parent_map = gcc_xo_gpll0_map,
- .clkr.hw.init = &(struct clk_init_data){
- .name = "config_noc_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
- .ops = &clk_rcg2_ops,
- },
-};
-
-static struct clk_rcg2 periph_noc_clk_src = {
- .cmd_rcgr = 0x0190,
- .hid_width = 5,
- .parent_map = gcc_xo_gpll0_map,
- .clkr.hw.init = &(struct clk_init_data){
- .name = "periph_noc_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
- .ops = &clk_rcg2_ops,
- },
-};
-
-static struct clk_rcg2 system_noc_clk_src = {
- .cmd_rcgr = 0x0120,
- .hid_width = 5,
- .parent_map = gcc_xo_gpll0_map,
- .clkr.hw.init = &(struct clk_init_data){
- .name = "system_noc_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
- .ops = &clk_rcg2_ops,
- },
-};
-
static struct clk_pll gpll1 = {
.l_reg = 0x0044,
.m_reg = 0x0048,
@@ -171,7 +77,9 @@ static struct clk_pll gpll1 = {
.status_bit = 17,
.clkr.hw.init = &(struct clk_init_data){
.name = "gpll1",
- .parent_names = (const char *[]){ "xo" },
+ .parent_data = &(const struct clk_parent_data){
+ .fw_name = "xo", .name = "xo_board",
+ },
.num_parents = 1,
.ops = &clk_pll_ops,
},
@@ -182,7 +90,9 @@ static struct clk_regmap gpll1_vote = {
.enable_mask = BIT(1),
.hw.init = &(struct clk_init_data){
.name = "gpll1_vote",
- .parent_names = (const char *[]){ "gpll1" },
+ .parent_hws = (const struct clk_hw*[]){
+ &gpll1.clkr.hw,
+ },
.num_parents = 1,
.ops = &clk_pll_vote_ops,
},
@@ -198,7 +108,9 @@ static struct clk_pll gpll4 = {
.status_bit = 17,
.clkr.hw.init = &(struct clk_init_data){
.name = "gpll4",
- .parent_names = (const char *[]){ "xo" },
+ .parent_data = &(const struct clk_parent_data){
+ .fw_name = "xo", .name = "xo_board",
+ },
.num_parents = 1,
.ops = &clk_pll_ops,
},
@@ -209,12 +121,112 @@ static struct clk_regmap gpll4_vote = {
.enable_mask = BIT(4),
.hw.init = &(struct clk_init_data){
.name = "gpll4_vote",
- .parent_names = (const char *[]){ "gpll4" },
+ .parent_hws = (const struct clk_hw*[]){
+ &gpll4.clkr.hw,
+ },
.num_parents = 1,
.ops = &clk_pll_vote_ops,
},
};
+static const struct parent_map gcc_xo_gpll0_map[] = {
+ { P_XO, 0 },
+ { P_GPLL0, 1 }
+};
+
+static const struct clk_parent_data gcc_xo_gpll0[] = {
+ { .fw_name = "xo", .name = "xo_board" },
+ { .hw = &gpll0_vote.hw },
+};
+
+static const struct parent_map gcc_xo_gpll0_gpll4_map[] = {
+ { P_XO, 0 },
+ { P_GPLL0, 1 },
+ { P_GPLL4, 5 }
+};
+
+static const struct clk_parent_data gcc_xo_gpll0_gpll4[] = {
+ { .fw_name = "xo", .name = "xo_board" },
+ { .hw = &gpll0_vote.hw },
+ { .hw = &gpll4_vote.hw },
+};
+
+static const struct parent_map gcc_xo_sata_asic0_map[] = {
+ { P_XO, 0 },
+ { P_SATA_ASIC0_CLK, 2 }
+};
+
+static const struct clk_parent_data gcc_xo_sata_asic0[] = {
+ { .fw_name = "xo", .name = "xo_board" },
+ { .fw_name = "sata_asic0_clk", .name = "sata_asic0_clk" },
+};
+
+static const struct parent_map gcc_xo_sata_rx_map[] = {
+ { P_XO, 0 },
+ { P_SATA_RX_CLK, 2}
+};
+
+static const struct clk_parent_data gcc_xo_sata_rx[] = {
+ { .fw_name = "xo", .name = "xo_board" },
+ { .fw_name = "sata_rx_clk", .name = "sata_rx_clk" },
+};
+
+static const struct parent_map gcc_xo_pcie_map[] = {
+ { P_XO, 0 },
+ { P_PCIE_0_1_PIPE_CLK, 2 }
+};
+
+static const struct clk_parent_data gcc_xo_pcie[] = {
+ { .fw_name = "xo", .name = "xo_board" },
+ { .fw_name = "pcie_pipe", .name = "pcie_pipe" },
+};
+
+static const struct parent_map gcc_xo_pcie_sleep_map[] = {
+ { P_XO, 0 },
+ { P_SLEEP_CLK, 6 }
+};
+
+static const struct clk_parent_data gcc_xo_pcie_sleep[] = {
+ { .fw_name = "xo", .name = "xo_board" },
+ { .fw_name = "sleep_clk", .name = "sleep_clk" },
+};
+
+static struct clk_rcg2 config_noc_clk_src = {
+ .cmd_rcgr = 0x0150,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "config_noc_clk_src",
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 periph_noc_clk_src = {
+ .cmd_rcgr = 0x0190,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "periph_noc_clk_src",
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 system_noc_clk_src = {
+ .cmd_rcgr = 0x0120,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "system_noc_clk_src",
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
static const struct freq_tbl ftbl_gcc_ufs_axi_clk[] = {
F(100000000, P_GPLL0, 6, 0, 0),
F(200000000, P_GPLL0, 3, 0, 0),
@@ -230,8 +242,8 @@ static struct clk_rcg2 ufs_axi_clk_src = {
.freq_tbl = ftbl_gcc_ufs_axi_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "ufs_axi_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -249,8 +261,8 @@ static struct clk_rcg2 usb30_master_clk_src = {
.freq_tbl = ftbl_gcc_usb30_master_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "usb30_master_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -268,8 +280,26 @@ static struct clk_rcg2 usb30_sec_master_clk_src = {
.freq_tbl = ftbl_gcc_usb30_sec_master_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "usb30_sec_master_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_usb30_sec_mock_utmi_clk[] = {
+ F(125000000, P_GPLL0, 1, 5, 24),
+ { }
+};
+
+static struct clk_rcg2 usb30_sec_mock_utmi_clk_src = {
+ .cmd_rcgr = 0x1be8,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_gcc_usb30_sec_mock_utmi_clk,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "usb30_sec_mock_utmi_clk_src",
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -281,8 +311,8 @@ static struct clk_branch gcc_usb30_sec_mock_utmi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb30_sec_mock_utmi_clk",
- .parent_names = (const char *[]){
- "usb30_sec_mock_utmi_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &usb30_sec_mock_utmi_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -298,8 +328,8 @@ static struct clk_branch gcc_usb30_sec_sleep_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb30_sec_sleep_clk",
- .parent_names = (const char *[]){
- "sleep_clk_src",
+ .parent_data = &(const struct clk_parent_data){
+ .fw_name = "sleep_clk", .name = "sleep_clk",
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -321,8 +351,8 @@ static struct clk_rcg2 blsp1_qup1_i2c_apps_clk_src = {
.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_i2c_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp1_qup1_i2c_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -346,8 +376,8 @@ static struct clk_rcg2 blsp1_qup1_spi_apps_clk_src = {
.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_spi_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp1_qup1_spi_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -359,8 +389,8 @@ static struct clk_rcg2 blsp1_qup2_i2c_apps_clk_src = {
.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_i2c_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp1_qup2_i2c_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -373,8 +403,8 @@ static struct clk_rcg2 blsp1_qup2_spi_apps_clk_src = {
.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_spi_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp1_qup2_spi_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -386,8 +416,8 @@ static struct clk_rcg2 blsp1_qup3_i2c_apps_clk_src = {
.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_i2c_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp1_qup3_i2c_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -400,8 +430,8 @@ static struct clk_rcg2 blsp1_qup3_spi_apps_clk_src = {
.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_spi_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp1_qup3_spi_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -413,8 +443,8 @@ static struct clk_rcg2 blsp1_qup4_i2c_apps_clk_src = {
.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_i2c_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp1_qup4_i2c_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -427,8 +457,8 @@ static struct clk_rcg2 blsp1_qup4_spi_apps_clk_src = {
.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_spi_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp1_qup4_spi_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -440,8 +470,8 @@ static struct clk_rcg2 blsp1_qup5_i2c_apps_clk_src = {
.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_i2c_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp1_qup5_i2c_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -454,8 +484,8 @@ static struct clk_rcg2 blsp1_qup5_spi_apps_clk_src = {
.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_spi_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp1_qup5_spi_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -467,8 +497,8 @@ static struct clk_rcg2 blsp1_qup6_i2c_apps_clk_src = {
.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_i2c_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp1_qup6_i2c_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -481,8 +511,8 @@ static struct clk_rcg2 blsp1_qup6_spi_apps_clk_src = {
.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_spi_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp1_qup6_spi_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -514,8 +544,8 @@ static struct clk_rcg2 blsp1_uart1_apps_clk_src = {
.freq_tbl = ftbl_gcc_blsp1_2_uart1_6_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp1_uart1_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -528,8 +558,8 @@ static struct clk_rcg2 blsp1_uart2_apps_clk_src = {
.freq_tbl = ftbl_gcc_blsp1_2_uart1_6_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp1_uart2_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -542,8 +572,8 @@ static struct clk_rcg2 blsp1_uart3_apps_clk_src = {
.freq_tbl = ftbl_gcc_blsp1_2_uart1_6_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp1_uart3_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -556,8 +586,8 @@ static struct clk_rcg2 blsp1_uart4_apps_clk_src = {
.freq_tbl = ftbl_gcc_blsp1_2_uart1_6_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp1_uart4_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -570,8 +600,8 @@ static struct clk_rcg2 blsp1_uart5_apps_clk_src = {
.freq_tbl = ftbl_gcc_blsp1_2_uart1_6_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp1_uart5_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -584,8 +614,8 @@ static struct clk_rcg2 blsp1_uart6_apps_clk_src = {
.freq_tbl = ftbl_gcc_blsp1_2_uart1_6_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp1_uart6_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -597,8 +627,8 @@ static struct clk_rcg2 blsp2_qup1_i2c_apps_clk_src = {
.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_i2c_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp2_qup1_i2c_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -611,8 +641,8 @@ static struct clk_rcg2 blsp2_qup1_spi_apps_clk_src = {
.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_spi_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp2_qup1_spi_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -624,8 +654,8 @@ static struct clk_rcg2 blsp2_qup2_i2c_apps_clk_src = {
.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_i2c_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp2_qup2_i2c_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -638,8 +668,8 @@ static struct clk_rcg2 blsp2_qup2_spi_apps_clk_src = {
.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_spi_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp2_qup2_spi_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -651,8 +681,8 @@ static struct clk_rcg2 blsp2_qup3_i2c_apps_clk_src = {
.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_i2c_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp2_qup3_i2c_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -665,8 +695,8 @@ static struct clk_rcg2 blsp2_qup3_spi_apps_clk_src = {
.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_spi_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp2_qup3_spi_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -678,8 +708,8 @@ static struct clk_rcg2 blsp2_qup4_i2c_apps_clk_src = {
.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_i2c_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp2_qup4_i2c_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -692,8 +722,8 @@ static struct clk_rcg2 blsp2_qup4_spi_apps_clk_src = {
.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_spi_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp2_qup4_spi_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -705,8 +735,8 @@ static struct clk_rcg2 blsp2_qup5_i2c_apps_clk_src = {
.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_i2c_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp2_qup5_i2c_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -719,8 +749,8 @@ static struct clk_rcg2 blsp2_qup5_spi_apps_clk_src = {
.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_spi_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp2_qup5_spi_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -732,8 +762,8 @@ static struct clk_rcg2 blsp2_qup6_i2c_apps_clk_src = {
.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_i2c_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp2_qup6_i2c_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -746,8 +776,8 @@ static struct clk_rcg2 blsp2_qup6_spi_apps_clk_src = {
.freq_tbl = ftbl_gcc_blsp1_2_qup1_6_spi_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp2_qup6_spi_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -760,8 +790,8 @@ static struct clk_rcg2 blsp2_uart1_apps_clk_src = {
.freq_tbl = ftbl_gcc_blsp1_2_uart1_6_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp2_uart1_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -774,8 +804,8 @@ static struct clk_rcg2 blsp2_uart2_apps_clk_src = {
.freq_tbl = ftbl_gcc_blsp1_2_uart1_6_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp2_uart2_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -788,8 +818,8 @@ static struct clk_rcg2 blsp2_uart3_apps_clk_src = {
.freq_tbl = ftbl_gcc_blsp1_2_uart1_6_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp2_uart3_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -802,8 +832,8 @@ static struct clk_rcg2 blsp2_uart4_apps_clk_src = {
.freq_tbl = ftbl_gcc_blsp1_2_uart1_6_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp2_uart4_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -816,8 +846,8 @@ static struct clk_rcg2 blsp2_uart5_apps_clk_src = {
.freq_tbl = ftbl_gcc_blsp1_2_uart1_6_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp2_uart5_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -830,8 +860,8 @@ static struct clk_rcg2 blsp2_uart6_apps_clk_src = {
.freq_tbl = ftbl_gcc_blsp1_2_uart1_6_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp2_uart6_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -851,8 +881,8 @@ static struct clk_rcg2 ce1_clk_src = {
.freq_tbl = ftbl_gcc_ce1_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "ce1_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -872,8 +902,8 @@ static struct clk_rcg2 ce2_clk_src = {
.freq_tbl = ftbl_gcc_ce2_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "ce2_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -893,8 +923,8 @@ static struct clk_rcg2 ce3_clk_src = {
.freq_tbl = ftbl_gcc_ce3_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "ce3_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -914,8 +944,8 @@ static struct clk_rcg2 gp1_clk_src = {
.freq_tbl = ftbl_gcc_gp_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "gp1_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -928,8 +958,8 @@ static struct clk_rcg2 gp2_clk_src = {
.freq_tbl = ftbl_gcc_gp_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "gp2_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -942,8 +972,8 @@ static struct clk_rcg2 gp3_clk_src = {
.freq_tbl = ftbl_gcc_gp_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "gp3_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -961,8 +991,8 @@ static struct clk_rcg2 pcie_0_aux_clk_src = {
.freq_tbl = ftbl_gcc_pcie_0_1_aux_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "pcie_0_aux_clk_src",
- .parent_names = gcc_xo_pcie_sleep,
- .num_parents = 2,
+ .parent_data = gcc_xo_pcie_sleep,
+ .num_parents = ARRAY_SIZE(gcc_xo_pcie_sleep),
.ops = &clk_rcg2_ops,
},
};
@@ -975,8 +1005,8 @@ static struct clk_rcg2 pcie_1_aux_clk_src = {
.freq_tbl = ftbl_gcc_pcie_0_1_aux_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "pcie_1_aux_clk_src",
- .parent_names = gcc_xo_pcie_sleep,
- .num_parents = 2,
+ .parent_data = gcc_xo_pcie_sleep,
+ .num_parents = ARRAY_SIZE(gcc_xo_pcie_sleep),
.ops = &clk_rcg2_ops,
},
};
@@ -994,8 +1024,8 @@ static struct clk_rcg2 pcie_0_pipe_clk_src = {
.freq_tbl = ftbl_gcc_pcie_0_1_pipe_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "pcie_0_pipe_clk_src",
- .parent_names = gcc_xo_pcie,
- .num_parents = 2,
+ .parent_data = gcc_xo_pcie,
+ .num_parents = ARRAY_SIZE(gcc_xo_pcie),
.ops = &clk_rcg2_ops,
},
};
@@ -1007,8 +1037,8 @@ static struct clk_rcg2 pcie_1_pipe_clk_src = {
.freq_tbl = ftbl_gcc_pcie_0_1_pipe_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "pcie_1_pipe_clk_src",
- .parent_names = gcc_xo_pcie,
- .num_parents = 2,
+ .parent_data = gcc_xo_pcie,
+ .num_parents = ARRAY_SIZE(gcc_xo_pcie),
.ops = &clk_rcg2_ops,
},
};
@@ -1025,8 +1055,8 @@ static struct clk_rcg2 pdm2_clk_src = {
.freq_tbl = ftbl_gcc_pdm2_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "pdm2_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -1045,8 +1075,8 @@ static struct clk_rcg2 sata_asic0_clk_src = {
.freq_tbl = ftbl_gcc_sata_asic0_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "sata_asic0_clk_src",
- .parent_names = gcc_xo_sata_asic0,
- .num_parents = 2,
+ .parent_data = gcc_xo_sata_asic0,
+ .num_parents = ARRAY_SIZE(gcc_xo_sata_asic0),
.ops = &clk_rcg2_ops,
},
};
@@ -1065,8 +1095,8 @@ static struct clk_rcg2 sata_pmalive_clk_src = {
.freq_tbl = ftbl_gcc_sata_pmalive_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "sata_pmalive_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -1085,8 +1115,8 @@ static struct clk_rcg2 sata_rx_clk_src = {
.freq_tbl = ftbl_gcc_sata_rx_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "sata_rx_clk_src",
- .parent_names = gcc_xo_sata_rx,
- .num_parents = 2,
+ .parent_data = gcc_xo_sata_rx,
+ .num_parents = ARRAY_SIZE(gcc_xo_sata_rx),
.ops = &clk_rcg2_ops,
},
};
@@ -1103,8 +1133,8 @@ static struct clk_rcg2 sata_rx_oob_clk_src = {
.freq_tbl = ftbl_gcc_sata_rx_oob_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "sata_rx_oob_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -1130,8 +1160,8 @@ static struct clk_rcg2 sdcc1_apps_clk_src = {
.freq_tbl = ftbl_gcc_sdcc1_4_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "sdcc1_apps_clk_src",
- .parent_names = gcc_xo_gpll0_gpll4,
- .num_parents = 3,
+ .parent_data = gcc_xo_gpll0_gpll4,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll4),
.ops = &clk_rcg2_floor_ops,
},
};
@@ -1144,8 +1174,8 @@ static struct clk_rcg2 sdcc2_apps_clk_src = {
.freq_tbl = ftbl_gcc_sdcc1_4_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "sdcc2_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_floor_ops,
},
};
@@ -1158,8 +1188,8 @@ static struct clk_rcg2 sdcc3_apps_clk_src = {
.freq_tbl = ftbl_gcc_sdcc1_4_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "sdcc3_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_floor_ops,
},
};
@@ -1172,8 +1202,8 @@ static struct clk_rcg2 sdcc4_apps_clk_src = {
.freq_tbl = ftbl_gcc_sdcc1_4_apps_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "sdcc4_apps_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_floor_ops,
},
};
@@ -1191,8 +1221,8 @@ static struct clk_rcg2 tsif_ref_clk_src = {
.freq_tbl = ftbl_gcc_tsif_ref_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "tsif_ref_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -1209,26 +1239,8 @@ static struct clk_rcg2 usb30_mock_utmi_clk_src = {
.freq_tbl = ftbl_gcc_usb30_mock_utmi_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "usb30_mock_utmi_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
- .ops = &clk_rcg2_ops,
- },
-};
-
-static const struct freq_tbl ftbl_gcc_usb30_sec_mock_utmi_clk[] = {
- F(125000000, P_GPLL0, 1, 5, 24),
- { }
-};
-
-static struct clk_rcg2 usb30_sec_mock_utmi_clk_src = {
- .cmd_rcgr = 0x1be8,
- .hid_width = 5,
- .parent_map = gcc_xo_gpll0_map,
- .freq_tbl = ftbl_gcc_usb30_sec_mock_utmi_clk,
- .clkr.hw.init = &(struct clk_init_data){
- .name = "usb30_sec_mock_utmi_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -1245,8 +1257,8 @@ static struct clk_rcg2 usb_hs_system_clk_src = {
.freq_tbl = ftbl_gcc_usb_hs_system_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "usb_hs_system_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -1268,9 +1280,9 @@ static struct clk_rcg2 usb_hsic_clk_src = {
.freq_tbl = ftbl_gcc_usb_hsic_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "usb_hsic_clk_src",
- .parent_names = (const char *[]){
- "xo",
- "gpll1_vote",
+ .parent_data = (const struct clk_parent_data[]){
+ { .fw_name = "xo", .name = "xo_board" },
+ { .hw = &gpll1_vote.hw },
},
.num_parents = 2,
.ops = &clk_rcg2_ops,
@@ -1290,9 +1302,9 @@ static struct clk_rcg2 usb_hsic_ahb_clk_src = {
.freq_tbl = ftbl_gcc_usb_hsic_ahb_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "usb_hsic_ahb_clk_src",
- .parent_names = (const char *[]){
- "xo",
- "gpll1_vote",
+ .parent_data = (const struct clk_parent_data[]){
+ { .fw_name = "xo", .name = "xo_board" },
+ { .hw = &gpll1_vote.hw },
},
.num_parents = 2,
.ops = &clk_rcg2_ops,
@@ -1311,29 +1323,12 @@ static struct clk_rcg2 usb_hsic_io_cal_clk_src = {
.freq_tbl = ftbl_gcc_usb_hsic_io_cal_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "usb_hsic_io_cal_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 1,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
-static struct clk_branch gcc_usb_hsic_mock_utmi_clk = {
- .halt_reg = 0x1f14,
- .clkr = {
- .enable_reg = 0x1f14,
- .enable_mask = BIT(0),
- .hw.init = &(struct clk_init_data){
- .name = "gcc_usb_hsic_mock_utmi_clk",
- .parent_names = (const char *[]){
- "usb_hsic_mock_utmi_clk_src",
- },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
- .ops = &clk_branch2_ops,
- },
- },
-};
-
static const struct freq_tbl ftbl_gcc_usb_hsic_mock_utmi_clk[] = {
F(60000000, P_GPLL0, 10, 0, 0),
{ }
@@ -1346,12 +1341,29 @@ static struct clk_rcg2 usb_hsic_mock_utmi_clk_src = {
.freq_tbl = ftbl_gcc_usb_hsic_mock_utmi_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "usb_hsic_mock_utmi_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 1,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
+static struct clk_branch gcc_usb_hsic_mock_utmi_clk = {
+ .halt_reg = 0x1f14,
+ .clkr = {
+ .enable_reg = 0x1f14,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb_hsic_mock_utmi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &usb_hsic_mock_utmi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
static const struct freq_tbl ftbl_gcc_usb_hsic_system_clk[] = {
F(75000000, P_GPLL0, 8, 0, 0),
{ }
@@ -1364,12 +1376,25 @@ static struct clk_rcg2 usb_hsic_system_clk_src = {
.freq_tbl = ftbl_gcc_usb_hsic_system_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "usb_hsic_system_clk_src",
- .parent_names = gcc_xo_gpll0,
- .num_parents = 2,
+ .parent_data = gcc_xo_gpll0,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
.ops = &clk_rcg2_ops,
},
};
+static struct clk_regmap gcc_mmss_gpll0_clk_src = {
+ .enable_reg = 0x1484,
+ .enable_mask = BIT(26),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_gpll0_vote",
+ .parent_hws = (const struct clk_hw*[]){
+ &gpll0_vote.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_branch_simple_ops,
+ },
+};
+
static struct clk_branch gcc_bam_dma_ahb_clk = {
.halt_reg = 0x0d44,
.halt_check = BRANCH_HALT_VOTED,
@@ -1378,8 +1403,8 @@ static struct clk_branch gcc_bam_dma_ahb_clk = {
.enable_mask = BIT(12),
.hw.init = &(struct clk_init_data){
.name = "gcc_bam_dma_ahb_clk",
- .parent_names = (const char *[]){
- "periph_noc_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &periph_noc_clk_src.clkr.hw,
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -1395,8 +1420,8 @@ static struct clk_branch gcc_blsp1_ahb_clk = {
.enable_mask = BIT(17),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_ahb_clk",
- .parent_names = (const char *[]){
- "periph_noc_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &periph_noc_clk_src.clkr.hw,
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -1411,8 +1436,8 @@ static struct clk_branch gcc_blsp1_qup1_i2c_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_qup1_i2c_apps_clk",
- .parent_names = (const char *[]){
- "blsp1_qup1_i2c_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &blsp1_qup1_i2c_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1428,8 +1453,8 @@ static struct clk_branch gcc_blsp1_qup1_spi_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_qup1_spi_apps_clk",
- .parent_names = (const char *[]){
- "blsp1_qup1_spi_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &blsp1_qup1_spi_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1445,8 +1470,8 @@ static struct clk_branch gcc_blsp1_qup2_i2c_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_qup2_i2c_apps_clk",
- .parent_names = (const char *[]){
- "blsp1_qup2_i2c_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &blsp1_qup2_i2c_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1462,8 +1487,8 @@ static struct clk_branch gcc_blsp1_qup2_spi_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_qup2_spi_apps_clk",
- .parent_names = (const char *[]){
- "blsp1_qup2_spi_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &blsp1_qup2_spi_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1479,8 +1504,8 @@ static struct clk_branch gcc_blsp1_qup3_i2c_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_qup3_i2c_apps_clk",
- .parent_names = (const char *[]){
- "blsp1_qup3_i2c_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &blsp1_qup3_i2c_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1496,8 +1521,8 @@ static struct clk_branch gcc_blsp1_qup3_spi_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_qup3_spi_apps_clk",
- .parent_names = (const char *[]){
- "blsp1_qup3_spi_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &blsp1_qup3_spi_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1513,8 +1538,8 @@ static struct clk_branch gcc_blsp1_qup4_i2c_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_qup4_i2c_apps_clk",
- .parent_names = (const char *[]){
- "blsp1_qup4_i2c_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &blsp1_qup4_i2c_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1530,8 +1555,8 @@ static struct clk_branch gcc_blsp1_qup4_spi_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_qup4_spi_apps_clk",
- .parent_names = (const char *[]){
- "blsp1_qup4_spi_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &blsp1_qup4_spi_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1547,8 +1572,8 @@ static struct clk_branch gcc_blsp1_qup5_i2c_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_qup5_i2c_apps_clk",
- .parent_names = (const char *[]){
- "blsp1_qup5_i2c_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &blsp1_qup5_i2c_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1564,8 +1589,8 @@ static struct clk_branch gcc_blsp1_qup5_spi_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_qup5_spi_apps_clk",
- .parent_names = (const char *[]){
- "blsp1_qup5_spi_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &blsp1_qup5_spi_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1581,8 +1606,8 @@ static struct clk_branch gcc_blsp1_qup6_i2c_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_qup6_i2c_apps_clk",
- .parent_names = (const char *[]){
- "blsp1_qup6_i2c_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &blsp1_qup6_i2c_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1598,8 +1623,8 @@ static struct clk_branch gcc_blsp1_qup6_spi_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_qup6_spi_apps_clk",
- .parent_names = (const char *[]){
- "blsp1_qup6_spi_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &blsp1_qup6_spi_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1615,8 +1640,8 @@ static struct clk_branch gcc_blsp1_uart1_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_uart1_apps_clk",
- .parent_names = (const char *[]){
- "blsp1_uart1_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &blsp1_uart1_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1632,8 +1657,8 @@ static struct clk_branch gcc_blsp1_uart2_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_uart2_apps_clk",
- .parent_names = (const char *[]){
- "blsp1_uart2_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &blsp1_uart2_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1649,8 +1674,8 @@ static struct clk_branch gcc_blsp1_uart3_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_uart3_apps_clk",
- .parent_names = (const char *[]){
- "blsp1_uart3_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &blsp1_uart3_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1666,8 +1691,8 @@ static struct clk_branch gcc_blsp1_uart4_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_uart4_apps_clk",
- .parent_names = (const char *[]){
- "blsp1_uart4_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &blsp1_uart4_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1683,8 +1708,8 @@ static struct clk_branch gcc_blsp1_uart5_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_uart5_apps_clk",
- .parent_names = (const char *[]){
- "blsp1_uart5_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &blsp1_uart5_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1700,8 +1725,8 @@ static struct clk_branch gcc_blsp1_uart6_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_uart6_apps_clk",
- .parent_names = (const char *[]){
- "blsp1_uart6_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &blsp1_uart6_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1718,8 +1743,8 @@ static struct clk_branch gcc_blsp2_ahb_clk = {
.enable_mask = BIT(15),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp2_ahb_clk",
- .parent_names = (const char *[]){
- "periph_noc_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &periph_noc_clk_src.clkr.hw,
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -1734,8 +1759,8 @@ static struct clk_branch gcc_blsp2_qup1_i2c_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp2_qup1_i2c_apps_clk",
- .parent_names = (const char *[]){
- "blsp2_qup1_i2c_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &blsp2_qup1_i2c_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1751,8 +1776,8 @@ static struct clk_branch gcc_blsp2_qup1_spi_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp2_qup1_spi_apps_clk",
- .parent_names = (const char *[]){
- "blsp2_qup1_spi_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &blsp2_qup1_spi_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1768,8 +1793,8 @@ static struct clk_branch gcc_blsp2_qup2_i2c_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp2_qup2_i2c_apps_clk",
- .parent_names = (const char *[]){
- "blsp2_qup2_i2c_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &blsp2_qup2_i2c_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1785,8 +1810,8 @@ static struct clk_branch gcc_blsp2_qup2_spi_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp2_qup2_spi_apps_clk",
- .parent_names = (const char *[]){
- "blsp2_qup2_spi_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &blsp2_qup2_spi_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1802,8 +1827,8 @@ static struct clk_branch gcc_blsp2_qup3_i2c_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp2_qup3_i2c_apps_clk",
- .parent_names = (const char *[]){
- "blsp2_qup3_i2c_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &blsp2_qup3_i2c_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1819,8 +1844,8 @@ static struct clk_branch gcc_blsp2_qup3_spi_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp2_qup3_spi_apps_clk",
- .parent_names = (const char *[]){
- "blsp2_qup3_spi_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &blsp2_qup3_spi_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1836,8 +1861,8 @@ static struct clk_branch gcc_blsp2_qup4_i2c_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp2_qup4_i2c_apps_clk",
- .parent_names = (const char *[]){
- "blsp2_qup4_i2c_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &blsp2_qup4_i2c_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1853,8 +1878,8 @@ static struct clk_branch gcc_blsp2_qup4_spi_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp2_qup4_spi_apps_clk",
- .parent_names = (const char *[]){
- "blsp2_qup4_spi_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &blsp2_qup4_spi_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1870,8 +1895,8 @@ static struct clk_branch gcc_blsp2_qup5_i2c_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp2_qup5_i2c_apps_clk",
- .parent_names = (const char *[]){
- "blsp2_qup5_i2c_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &blsp2_qup5_i2c_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1887,8 +1912,8 @@ static struct clk_branch gcc_blsp2_qup5_spi_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp2_qup5_spi_apps_clk",
- .parent_names = (const char *[]){
- "blsp2_qup5_spi_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &blsp2_qup5_spi_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1904,8 +1929,8 @@ static struct clk_branch gcc_blsp2_qup6_i2c_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp2_qup6_i2c_apps_clk",
- .parent_names = (const char *[]){
- "blsp2_qup6_i2c_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &blsp2_qup6_i2c_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1921,8 +1946,8 @@ static struct clk_branch gcc_blsp2_qup6_spi_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp2_qup6_spi_apps_clk",
- .parent_names = (const char *[]){
- "blsp2_qup6_spi_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &blsp2_qup6_spi_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1938,8 +1963,8 @@ static struct clk_branch gcc_blsp2_uart1_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp2_uart1_apps_clk",
- .parent_names = (const char *[]){
- "blsp2_uart1_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &blsp2_uart1_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1955,8 +1980,8 @@ static struct clk_branch gcc_blsp2_uart2_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp2_uart2_apps_clk",
- .parent_names = (const char *[]){
- "blsp2_uart2_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &blsp2_uart2_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1972,8 +1997,8 @@ static struct clk_branch gcc_blsp2_uart3_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp2_uart3_apps_clk",
- .parent_names = (const char *[]){
- "blsp2_uart3_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &blsp2_uart3_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1989,8 +2014,8 @@ static struct clk_branch gcc_blsp2_uart4_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp2_uart4_apps_clk",
- .parent_names = (const char *[]){
- "blsp2_uart4_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &blsp2_uart4_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2006,8 +2031,8 @@ static struct clk_branch gcc_blsp2_uart5_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp2_uart5_apps_clk",
- .parent_names = (const char *[]){
- "blsp2_uart5_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &blsp2_uart5_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2023,8 +2048,8 @@ static struct clk_branch gcc_blsp2_uart6_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp2_uart6_apps_clk",
- .parent_names = (const char *[]){
- "blsp2_uart6_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &blsp2_uart6_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2041,8 +2066,8 @@ static struct clk_branch gcc_boot_rom_ahb_clk = {
.enable_mask = BIT(10),
.hw.init = &(struct clk_init_data){
.name = "gcc_boot_rom_ahb_clk",
- .parent_names = (const char *[]){
- "config_noc_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &config_noc_clk_src.clkr.hw,
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -2058,8 +2083,8 @@ static struct clk_branch gcc_ce1_ahb_clk = {
.enable_mask = BIT(3),
.hw.init = &(struct clk_init_data){
.name = "gcc_ce1_ahb_clk",
- .parent_names = (const char *[]){
- "config_noc_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &config_noc_clk_src.clkr.hw,
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -2075,8 +2100,8 @@ static struct clk_branch gcc_ce1_axi_clk = {
.enable_mask = BIT(4),
.hw.init = &(struct clk_init_data){
.name = "gcc_ce1_axi_clk",
- .parent_names = (const char *[]){
- "system_noc_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &system_noc_clk_src.clkr.hw,
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -2092,8 +2117,8 @@ static struct clk_branch gcc_ce1_clk = {
.enable_mask = BIT(5),
.hw.init = &(struct clk_init_data){
.name = "gcc_ce1_clk",
- .parent_names = (const char *[]){
- "ce1_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &ce1_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2110,8 +2135,8 @@ static struct clk_branch gcc_ce2_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_ce2_ahb_clk",
- .parent_names = (const char *[]){
- "config_noc_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &config_noc_clk_src.clkr.hw,
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -2127,8 +2152,8 @@ static struct clk_branch gcc_ce2_axi_clk = {
.enable_mask = BIT(1),
.hw.init = &(struct clk_init_data){
.name = "gcc_ce2_axi_clk",
- .parent_names = (const char *[]){
- "system_noc_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &system_noc_clk_src.clkr.hw,
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -2144,8 +2169,8 @@ static struct clk_branch gcc_ce2_clk = {
.enable_mask = BIT(2),
.hw.init = &(struct clk_init_data){
.name = "gcc_ce2_clk",
- .parent_names = (const char *[]){
- "ce2_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &ce2_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2162,8 +2187,8 @@ static struct clk_branch gcc_ce3_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_ce3_ahb_clk",
- .parent_names = (const char *[]){
- "config_noc_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &config_noc_clk_src.clkr.hw,
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -2179,8 +2204,8 @@ static struct clk_branch gcc_ce3_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_ce3_axi_clk",
- .parent_names = (const char *[]){
- "system_noc_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &system_noc_clk_src.clkr.hw,
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -2196,8 +2221,8 @@ static struct clk_branch gcc_ce3_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_ce3_clk",
- .parent_names = (const char *[]){
- "ce3_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &ce3_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2213,8 +2238,8 @@ static struct clk_branch gcc_gp1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_gp1_clk",
- .parent_names = (const char *[]){
- "gp1_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &gp1_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2230,8 +2255,8 @@ static struct clk_branch gcc_gp2_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_gp2_clk",
- .parent_names = (const char *[]){
- "gp2_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &gp2_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2247,8 +2272,8 @@ static struct clk_branch gcc_gp3_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_gp3_clk",
- .parent_names = (const char *[]){
- "gp3_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &gp3_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2264,8 +2289,8 @@ static struct clk_branch gcc_ocmem_noc_cfg_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_ocmem_noc_cfg_ahb_clk",
- .parent_names = (const char *[]){
- "config_noc_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &config_noc_clk_src.clkr.hw,
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -2280,8 +2305,8 @@ static struct clk_branch gcc_pcie_0_aux_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_pcie_0_aux_clk",
- .parent_names = (const char *[]){
- "pcie_0_aux_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &pcie_0_aux_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2297,8 +2322,8 @@ static struct clk_branch gcc_pcie_0_cfg_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_pcie_0_cfg_ahb_clk",
- .parent_names = (const char *[]){
- "config_noc_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &config_noc_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2314,8 +2339,8 @@ static struct clk_branch gcc_pcie_0_mstr_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_pcie_0_mstr_axi_clk",
- .parent_names = (const char *[]){
- "config_noc_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &config_noc_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2331,8 +2356,8 @@ static struct clk_branch gcc_pcie_0_pipe_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_pcie_0_pipe_clk",
- .parent_names = (const char *[]){
- "pcie_0_pipe_clk_src",
+ .parent_data = &(const struct clk_parent_data){
+ .hw = &pcie_0_pipe_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2348,8 +2373,8 @@ static struct clk_branch gcc_pcie_0_slv_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_pcie_0_slv_axi_clk",
- .parent_names = (const char *[]){
- "config_noc_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &config_noc_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2365,8 +2390,8 @@ static struct clk_branch gcc_pcie_1_aux_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_pcie_1_aux_clk",
- .parent_names = (const char *[]){
- "pcie_1_aux_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &pcie_1_aux_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2382,8 +2407,8 @@ static struct clk_branch gcc_pcie_1_cfg_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_pcie_1_cfg_ahb_clk",
- .parent_names = (const char *[]){
- "config_noc_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &config_noc_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2399,8 +2424,8 @@ static struct clk_branch gcc_pcie_1_mstr_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_pcie_1_mstr_axi_clk",
- .parent_names = (const char *[]){
- "config_noc_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &config_noc_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2416,8 +2441,8 @@ static struct clk_branch gcc_pcie_1_pipe_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_pcie_1_pipe_clk",
- .parent_names = (const char *[]){
- "pcie_1_pipe_clk_src",
+ .parent_data = &(const struct clk_parent_data){
+ .hw = &pcie_1_pipe_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2433,8 +2458,8 @@ static struct clk_branch gcc_pcie_1_slv_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_pcie_1_slv_axi_clk",
- .parent_names = (const char *[]){
- "config_noc_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &config_noc_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2450,8 +2475,8 @@ static struct clk_branch gcc_pdm2_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_pdm2_clk",
- .parent_names = (const char *[]){
- "pdm2_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &pdm2_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2467,8 +2492,8 @@ static struct clk_branch gcc_pdm_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_pdm_ahb_clk",
- .parent_names = (const char *[]){
- "periph_noc_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &periph_noc_clk_src.clkr.hw,
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -2483,8 +2508,8 @@ static struct clk_branch gcc_periph_noc_usb_hsic_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_periph_noc_usb_hsic_ahb_clk",
- .parent_names = (const char *[]){
- "usb_hsic_ahb_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &usb_hsic_ahb_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2501,8 +2526,8 @@ static struct clk_branch gcc_prng_ahb_clk = {
.enable_mask = BIT(13),
.hw.init = &(struct clk_init_data){
.name = "gcc_prng_ahb_clk",
- .parent_names = (const char *[]){
- "periph_noc_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &periph_noc_clk_src.clkr.hw,
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -2517,8 +2542,8 @@ static struct clk_branch gcc_sata_asic0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_sata_asic0_clk",
- .parent_names = (const char *[]){
- "sata_asic0_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &sata_asic0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2534,8 +2559,8 @@ static struct clk_branch gcc_sata_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_sata_axi_clk",
- .parent_names = (const char *[]){
- "config_noc_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &config_noc_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2551,8 +2576,8 @@ static struct clk_branch gcc_sata_cfg_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_sata_cfg_ahb_clk",
- .parent_names = (const char *[]){
- "config_noc_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &config_noc_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2568,8 +2593,8 @@ static struct clk_branch gcc_sata_pmalive_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_sata_pmalive_clk",
- .parent_names = (const char *[]){
- "sata_pmalive_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &sata_pmalive_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2585,8 +2610,8 @@ static struct clk_branch gcc_sata_rx_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_sata_rx_clk",
- .parent_names = (const char *[]){
- "sata_rx_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &sata_rx_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2602,8 +2627,8 @@ static struct clk_branch gcc_sata_rx_oob_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_sata_rx_oob_clk",
- .parent_names = (const char *[]){
- "sata_rx_oob_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &sata_rx_oob_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2619,8 +2644,8 @@ static struct clk_branch gcc_sdcc1_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_sdcc1_ahb_clk",
- .parent_names = (const char *[]){
- "periph_noc_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &periph_noc_clk_src.clkr.hw,
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -2635,8 +2660,8 @@ static struct clk_branch gcc_sdcc1_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_sdcc1_apps_clk",
- .parent_names = (const char *[]){
- "sdcc1_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &sdcc1_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2652,8 +2677,8 @@ static struct clk_branch gcc_sdcc1_cdccal_ff_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_sdcc1_cdccal_ff_clk",
- .parent_names = (const char *[]){
- "xo"
+ .parent_data = (const struct clk_parent_data[]){
+ { .fw_name = "xo", .name = "xo_board" }
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -2668,8 +2693,8 @@ static struct clk_branch gcc_sdcc1_cdccal_sleep_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_sdcc1_cdccal_sleep_clk",
- .parent_names = (const char *[]){
- "sleep_clk_src"
+ .parent_data = (const struct clk_parent_data[]){
+ { .fw_name = "sleep_clk", .name = "sleep_clk" }
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -2684,8 +2709,8 @@ static struct clk_branch gcc_sdcc2_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_sdcc2_ahb_clk",
- .parent_names = (const char *[]){
- "periph_noc_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &periph_noc_clk_src.clkr.hw,
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -2700,8 +2725,8 @@ static struct clk_branch gcc_sdcc2_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_sdcc2_apps_clk",
- .parent_names = (const char *[]){
- "sdcc2_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &sdcc2_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2717,8 +2742,8 @@ static struct clk_branch gcc_sdcc3_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_sdcc3_ahb_clk",
- .parent_names = (const char *[]){
- "periph_noc_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &periph_noc_clk_src.clkr.hw,
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -2733,8 +2758,8 @@ static struct clk_branch gcc_sdcc3_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_sdcc3_apps_clk",
- .parent_names = (const char *[]){
- "sdcc3_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &sdcc3_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2750,8 +2775,8 @@ static struct clk_branch gcc_sdcc4_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_sdcc4_ahb_clk",
- .parent_names = (const char *[]){
- "periph_noc_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &periph_noc_clk_src.clkr.hw,
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -2766,8 +2791,8 @@ static struct clk_branch gcc_sdcc4_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_sdcc4_apps_clk",
- .parent_names = (const char *[]){
- "sdcc4_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &sdcc4_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2783,8 +2808,8 @@ static struct clk_branch gcc_sys_noc_ufs_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_sys_noc_ufs_axi_clk",
- .parent_names = (const char *[]){
- "ufs_axi_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &ufs_axi_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2800,8 +2825,8 @@ static struct clk_branch gcc_sys_noc_usb3_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_sys_noc_usb3_axi_clk",
- .parent_names = (const char *[]){
- "usb30_master_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &usb30_master_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2817,8 +2842,8 @@ static struct clk_branch gcc_sys_noc_usb3_sec_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_sys_noc_usb3_sec_axi_clk",
- .parent_names = (const char *[]){
- "usb30_sec_master_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &usb30_sec_master_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2834,8 +2859,8 @@ static struct clk_branch gcc_tsif_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_tsif_ahb_clk",
- .parent_names = (const char *[]){
- "periph_noc_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &periph_noc_clk_src.clkr.hw,
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -2850,8 +2875,8 @@ static struct clk_branch gcc_tsif_inactivity_timers_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_tsif_inactivity_timers_clk",
- .parent_names = (const char *[]){
- "sleep_clk_src",
+ .parent_data = &(const struct clk_parent_data){
+ .fw_name = "sleep_clk", .name = "sleep_clk",
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2867,8 +2892,8 @@ static struct clk_branch gcc_tsif_ref_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_tsif_ref_clk",
- .parent_names = (const char *[]){
- "tsif_ref_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &tsif_ref_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2884,8 +2909,8 @@ static struct clk_branch gcc_ufs_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_ufs_ahb_clk",
- .parent_names = (const char *[]){
- "config_noc_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &config_noc_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2901,8 +2926,8 @@ static struct clk_branch gcc_ufs_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_ufs_axi_clk",
- .parent_names = (const char *[]){
- "ufs_axi_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &ufs_axi_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2918,8 +2943,8 @@ static struct clk_branch gcc_ufs_rx_cfg_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_ufs_rx_cfg_clk",
- .parent_names = (const char *[]){
- "ufs_axi_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &ufs_axi_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2935,8 +2960,8 @@ static struct clk_branch gcc_ufs_rx_symbol_0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_ufs_rx_symbol_0_clk",
- .parent_names = (const char *[]){
- "ufs_rx_symbol_0_clk_src",
+ .parent_data = &(const struct clk_parent_data){
+ .fw_name = "ufs_rx_symbol_0_clk_src", .name = "ufs_rx_symbol_0_clk_src",
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2952,8 +2977,8 @@ static struct clk_branch gcc_ufs_rx_symbol_1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_ufs_rx_symbol_1_clk",
- .parent_names = (const char *[]){
- "ufs_rx_symbol_1_clk_src",
+ .parent_data = &(const struct clk_parent_data){
+ .fw_name = "ufs_rx_symbol_1_clk_src", .name = "ufs_rx_symbol_1_clk_src",
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2969,8 +2994,8 @@ static struct clk_branch gcc_ufs_tx_cfg_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_ufs_tx_cfg_clk",
- .parent_names = (const char *[]){
- "ufs_axi_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &ufs_axi_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2986,8 +3011,8 @@ static struct clk_branch gcc_ufs_tx_symbol_0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_ufs_tx_symbol_0_clk",
- .parent_names = (const char *[]){
- "ufs_tx_symbol_0_clk_src",
+ .parent_data = &(const struct clk_parent_data){
+ .fw_name = "ufs_tx_symbol_0_clk_src", .name = "ufs_tx_symbol_0_clk_src",
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -3003,8 +3028,8 @@ static struct clk_branch gcc_ufs_tx_symbol_1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_ufs_tx_symbol_1_clk",
- .parent_names = (const char *[]){
- "ufs_tx_symbol_1_clk_src",
+ .parent_data = &(const struct clk_parent_data){
+ .fw_name = "ufs_tx_symbol_1_clk_src", .name = "ufs_tx_symbol_1_clk_src",
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -3020,8 +3045,8 @@ static struct clk_branch gcc_usb2a_phy_sleep_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb2a_phy_sleep_clk",
- .parent_names = (const char *[]){
- "sleep_clk_src",
+ .parent_data = &(const struct clk_parent_data){
+ .fw_name = "sleep_clk", .name = "sleep_clk",
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -3036,8 +3061,8 @@ static struct clk_branch gcc_usb2b_phy_sleep_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb2b_phy_sleep_clk",
- .parent_names = (const char *[]){
- "sleep_clk_src",
+ .parent_data = &(const struct clk_parent_data){
+ .fw_name = "sleep_clk", .name = "sleep_clk",
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -3052,8 +3077,8 @@ static struct clk_branch gcc_usb30_master_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb30_master_clk",
- .parent_names = (const char *[]){
- "usb30_master_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &usb30_master_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -3069,8 +3094,8 @@ static struct clk_branch gcc_usb30_sec_master_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb30_sec_master_clk",
- .parent_names = (const char *[]){
- "usb30_sec_master_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &usb30_sec_master_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -3086,8 +3111,8 @@ static struct clk_branch gcc_usb30_mock_utmi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb30_mock_utmi_clk",
- .parent_names = (const char *[]){
- "usb30_mock_utmi_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &usb30_mock_utmi_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -3103,8 +3128,8 @@ static struct clk_branch gcc_usb30_sleep_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb30_sleep_clk",
- .parent_names = (const char *[]){
- "sleep_clk_src",
+ .parent_data = &(const struct clk_parent_data){
+ .fw_name = "sleep_clk", .name = "sleep_clk",
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -3119,8 +3144,8 @@ static struct clk_branch gcc_usb_hs_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb_hs_ahb_clk",
- .parent_names = (const char *[]){
- "periph_noc_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &periph_noc_clk_src.clkr.hw,
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -3135,8 +3160,8 @@ static struct clk_branch gcc_usb_hs_inactivity_timers_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb_hs_inactivity_timers_clk",
- .parent_names = (const char *[]){
- "sleep_clk_src",
+ .parent_data = &(const struct clk_parent_data){
+ .fw_name = "sleep_clk", .name = "sleep_clk",
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -3152,8 +3177,8 @@ static struct clk_branch gcc_usb_hs_system_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb_hs_system_clk",
- .parent_names = (const char *[]){
- "usb_hs_system_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &usb_hs_system_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -3169,8 +3194,8 @@ static struct clk_branch gcc_usb_hsic_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb_hsic_ahb_clk",
- .parent_names = (const char *[]){
- "periph_noc_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &periph_noc_clk_src.clkr.hw,
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -3185,8 +3210,8 @@ static struct clk_branch gcc_usb_hsic_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb_hsic_clk",
- .parent_names = (const char *[]){
- "usb_hsic_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &usb_hsic_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -3202,8 +3227,8 @@ static struct clk_branch gcc_usb_hsic_io_cal_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb_hsic_io_cal_clk",
- .parent_names = (const char *[]){
- "usb_hsic_io_cal_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &usb_hsic_io_cal_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -3219,8 +3244,8 @@ static struct clk_branch gcc_usb_hsic_io_cal_sleep_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb_hsic_io_cal_sleep_clk",
- .parent_names = (const char *[]){
- "sleep_clk_src",
+ .parent_data = &(const struct clk_parent_data){
+ .fw_name = "sleep_clk", .name = "sleep_clk",
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -3235,8 +3260,8 @@ static struct clk_branch gcc_usb_hsic_system_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb_hsic_system_clk",
- .parent_names = (const char *[]){
- "usb_hsic_system_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &usb_hsic_system_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -3468,6 +3493,7 @@ static struct clk_regmap *gcc_apq8084_clocks[] = {
[GCC_USB_HSIC_IO_CAL_SLEEP_CLK] = &gcc_usb_hsic_io_cal_sleep_clk.clkr,
[GCC_USB_HSIC_MOCK_UTMI_CLK] = &gcc_usb_hsic_mock_utmi_clk.clkr,
[GCC_USB_HSIC_SYSTEM_CLK] = &gcc_usb_hsic_system_clk.clkr,
+ [GCC_MMSS_GPLL0_CLK_SRC] = &gcc_mmss_gpll0_clk_src,
};
static struct gdsc *gcc_apq8084_gdscs[] = {
diff --git a/drivers/clk/qcom/gcc-ipq8074.c b/drivers/clk/qcom/gcc-ipq8074.c
index 14cc4ad02221..6541d98c0348 100644
--- a/drivers/clk/qcom/gcc-ipq8074.c
+++ b/drivers/clk/qcom/gcc-ipq8074.c
@@ -934,7 +934,7 @@ static struct clk_rcg2 usb0_mock_utmi_clk_src = {
};
static const struct clk_parent_data gcc_usb3phy_0_cc_pipe_clk_xo[] = {
- { .name = "usb3phy_0_cc_pipe_clk" },
+ { .fw_name = "usb3phy_0_cc_pipe_clk", .name = "usb3phy_0_cc_pipe_clk" },
{ .fw_name = "xo", .name = "xo" },
};
@@ -1002,7 +1002,7 @@ static struct clk_rcg2 usb1_mock_utmi_clk_src = {
};
static const struct clk_parent_data gcc_usb3phy_1_cc_pipe_clk_xo[] = {
- { .name = "usb3phy_1_cc_pipe_clk" },
+ { .fw_name = "usb3phy_1_cc_pipe_clk", .name = "usb3phy_1_cc_pipe_clk" },
{ .fw_name = "xo", .name = "xo" },
};
diff --git a/drivers/clk/qcom/gcc-msm8939.c b/drivers/clk/qcom/gcc-msm8939.c
index 712073f9dc69..7f8969a77974 100644
--- a/drivers/clk/qcom/gcc-msm8939.c
+++ b/drivers/clk/qcom/gcc-msm8939.c
@@ -73,8 +73,8 @@ static struct clk_regmap gpll0_vote = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gpll0_vote",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &gpll0.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gpll0.clkr.hw,
},
.num_parents = 1,
.ops = &clk_pll_vote_ops,
@@ -104,8 +104,8 @@ static struct clk_regmap gpll1_vote = {
.enable_mask = BIT(1),
.hw.init = &(struct clk_init_data){
.name = "gpll1_vote",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &gpll1.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gpll1.clkr.hw,
},
.num_parents = 1,
.ops = &clk_pll_vote_ops,
@@ -135,8 +135,8 @@ static struct clk_regmap gpll2_vote = {
.enable_mask = BIT(2),
.hw.init = &(struct clk_init_data){
.name = "gpll2_vote",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &gpll2.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gpll2.clkr.hw,
},
.num_parents = 1,
.ops = &clk_pll_vote_ops,
@@ -166,8 +166,8 @@ static struct clk_regmap bimc_pll_vote = {
.enable_mask = BIT(3),
.hw.init = &(struct clk_init_data){
.name = "bimc_pll_vote",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &bimc_pll.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &bimc_pll.clkr.hw,
},
.num_parents = 1,
.ops = &clk_pll_vote_ops,
@@ -197,8 +197,8 @@ static struct clk_regmap gpll3_vote = {
.enable_mask = BIT(4),
.hw.init = &(struct clk_init_data){
.name = "gpll3_vote",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &gpll3.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gpll3.clkr.hw,
},
.num_parents = 1,
.ops = &clk_pll_vote_ops,
@@ -244,8 +244,8 @@ static struct clk_regmap gpll4_vote = {
.enable_mask = BIT(5),
.hw.init = &(struct clk_init_data){
.name = "gpll4_vote",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &gpll4.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gpll4.clkr.hw,
},
.num_parents = 1,
.ops = &clk_pll_vote_ops,
@@ -290,8 +290,8 @@ static struct clk_regmap gpll5_vote = {
.enable_mask = BIT(6),
.hw.init = &(struct clk_init_data){
.name = "gpll5_vote",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &gpll5.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gpll5.clkr.hw,
},
.num_parents = 1,
.ops = &clk_pll_vote_ops,
@@ -321,8 +321,8 @@ static struct clk_regmap gpll6_vote = {
.enable_mask = BIT(7),
.hw.init = &(struct clk_init_data){
.name = "gpll6_vote",
- .parent_data = &(const struct clk_parent_data) {
- .hw = &gpll6.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gpll6.clkr.hw,
},
.num_parents = 1,
.ops = &clk_pll_vote_ops,
diff --git a/drivers/clk/qcom/gcc-msm8974.c b/drivers/clk/qcom/gcc-msm8974.c
index 025cc9a20dbb..0231c1efd286 100644
--- a/drivers/clk/qcom/gcc-msm8974.c
+++ b/drivers/clk/qcom/gcc-msm8974.c
@@ -2110,7 +2110,7 @@ static struct clk_branch gcc_sdcc1_cdccal_sleep_clk = {
.hw.init = &(struct clk_init_data){
.name = "gcc_sdcc1_cdccal_sleep_clk",
.parent_data = (const struct clk_parent_data[]){
- { .fw_name = "sleep_clk", .name = "sleep_clk_src" }
+ { .fw_name = "sleep_clk", .name = "sleep_clk" }
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -2275,7 +2275,7 @@ static struct clk_branch gcc_usb2a_phy_sleep_clk = {
.hw.init = &(struct clk_init_data){
.name = "gcc_usb2a_phy_sleep_clk",
.parent_data = &(const struct clk_parent_data){
- .fw_name = "sleep_clk", .name = "sleep_clk_src",
+ .fw_name = "sleep_clk", .name = "sleep_clk",
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -2291,7 +2291,7 @@ static struct clk_branch gcc_usb2b_phy_sleep_clk = {
.hw.init = &(struct clk_init_data){
.name = "gcc_usb2b_phy_sleep_clk",
.parent_data = &(const struct clk_parent_data){
- .fw_name = "sleep_clk", .name = "sleep_clk_src",
+ .fw_name = "sleep_clk", .name = "sleep_clk",
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -2341,7 +2341,7 @@ static struct clk_branch gcc_usb30_sleep_clk = {
.hw.init = &(struct clk_init_data){
.name = "gcc_usb30_sleep_clk",
.parent_data = &(const struct clk_parent_data){
- .fw_name = "sleep_clk", .name = "sleep_clk_src",
+ .fw_name = "sleep_clk", .name = "sleep_clk",
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -2440,7 +2440,7 @@ static struct clk_branch gcc_usb_hsic_io_cal_sleep_clk = {
.hw.init = &(struct clk_init_data){
.name = "gcc_usb_hsic_io_cal_sleep_clk",
.parent_data = &(const struct clk_parent_data){
- .fw_name = "sleep_clk", .name = "sleep_clk_src",
+ .fw_name = "sleep_clk", .name = "sleep_clk",
},
.num_parents = 1,
.ops = &clk_branch2_ops,
diff --git a/drivers/clk/qcom/gcc-msm8976.c b/drivers/clk/qcom/gcc-msm8976.c
index 6b112984694c..8beb923c0e19 100644
--- a/drivers/clk/qcom/gcc-msm8976.c
+++ b/drivers/clk/qcom/gcc-msm8976.c
@@ -334,9 +334,9 @@ static const struct parent_map gcc_parent_map_7[] = {
{ P_GPLL6_OUT, 3 },
};
-static const struct clk_parent_data gcc_parent_data_7[] = {
- { .hw = &gpll0_vote.hw },
- { .hw = &gpll6_vote.hw },
+static const struct clk_hw * gcc_parent_hws_7[] = {
+ &gpll0_vote.hw,
+ &gpll6_vote.hw,
};
static const struct parent_map gcc_parent_map_8[] = {
@@ -363,8 +363,8 @@ static const struct parent_map gcc_parent_map_8_gp[] = {
{ P_GPLL0_OUT_MAIN, 1 },
};
-static const struct clk_parent_data gcc_parent_data_8_gp[] = {
- { .hw = &gpll0_vote.hw },
+static const struct clk_hw *gcc_parent_hws_8_gp[] = {
+ &gpll0_vote.hw,
};
static const struct parent_map gcc_parent_map_9[] = {
@@ -952,8 +952,8 @@ static struct clk_rcg2 camss_gp0_clk_src = {
.freq_tbl = ftbl_camss_gp0_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "camss_gp0_clk_src",
- .parent_data = gcc_parent_data_8_gp,
- .num_parents = ARRAY_SIZE(gcc_parent_data_8_gp),
+ .parent_hws = gcc_parent_hws_8_gp,
+ .num_parents = ARRAY_SIZE(gcc_parent_hws_8_gp),
.ops = &clk_rcg2_ops,
},
};
@@ -973,8 +973,8 @@ static struct clk_rcg2 camss_gp1_clk_src = {
.freq_tbl = ftbl_camss_gp1_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "camss_gp1_clk_src",
- .parent_data = gcc_parent_data_8_gp,
- .num_parents = ARRAY_SIZE(gcc_parent_data_8_gp),
+ .parent_hws = gcc_parent_hws_8_gp,
+ .num_parents = ARRAY_SIZE(gcc_parent_hws_8_gp),
.ops = &clk_rcg2_ops,
},
};
@@ -1015,8 +1015,8 @@ static struct clk_rcg2 mclk0_clk_src = {
.freq_tbl = ftbl_mclk_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "mclk0_clk_src",
- .parent_data = gcc_parent_data_7,
- .num_parents = ARRAY_SIZE(gcc_parent_data_7),
+ .parent_hws = gcc_parent_hws_7,
+ .num_parents = ARRAY_SIZE(gcc_parent_hws_7),
.ops = &clk_rcg2_ops,
},
};
@@ -1029,8 +1029,8 @@ static struct clk_rcg2 mclk1_clk_src = {
.freq_tbl = ftbl_mclk_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "mclk1_clk_src",
- .parent_data = gcc_parent_data_7,
- .num_parents = ARRAY_SIZE(gcc_parent_data_7),
+ .parent_hws = gcc_parent_hws_7,
+ .num_parents = ARRAY_SIZE(gcc_parent_hws_7),
.ops = &clk_rcg2_ops,
},
};
@@ -1043,8 +1043,8 @@ static struct clk_rcg2 mclk2_clk_src = {
.freq_tbl = ftbl_mclk_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "mclk2_clk_src",
- .parent_data = gcc_parent_data_7,
- .num_parents = ARRAY_SIZE(gcc_parent_data_7),
+ .parent_hws = gcc_parent_hws_7,
+ .num_parents = ARRAY_SIZE(gcc_parent_hws_7),
.ops = &clk_rcg2_ops,
},
};
diff --git a/drivers/clk/qcom/gcc-msm8998.c b/drivers/clk/qcom/gcc-msm8998.c
index 33473c52eb90..908e996841c2 100644
--- a/drivers/clk/qcom/gcc-msm8998.c
+++ b/drivers/clk/qcom/gcc-msm8998.c
@@ -387,7 +387,6 @@ static struct clk_alpha_pll_postdiv gpll4_out_test = {
enum {
P_AUD_REF_CLK,
- P_CORE_BI_PLL_TEST_SE,
P_GPLL0_OUT_MAIN,
P_GPLL4_OUT_MAIN,
P_PLL0_EARLY_DIV_CLK_SRC,
@@ -399,26 +398,22 @@ static const struct parent_map gcc_parent_map_0[] = {
{ P_XO, 0 },
{ P_GPLL0_OUT_MAIN, 1 },
{ P_PLL0_EARLY_DIV_CLK_SRC, 6 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
};
static const struct clk_parent_data gcc_parent_data_0[] = {
{ .fw_name = "xo" },
{ .hw = &gpll0_out_main.clkr.hw },
{ .hw = &gpll0_out_main.clkr.hw },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct parent_map gcc_parent_map_1[] = {
{ P_XO, 0 },
{ P_GPLL0_OUT_MAIN, 1 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
};
static const struct clk_parent_data gcc_parent_data_1[] = {
{ .fw_name = "xo" },
{ .hw = &gpll0_out_main.clkr.hw },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct parent_map gcc_parent_map_2[] = {
@@ -426,7 +421,6 @@ static const struct parent_map gcc_parent_map_2[] = {
{ P_GPLL0_OUT_MAIN, 1 },
{ P_SLEEP_CLK, 5 },
{ P_PLL0_EARLY_DIV_CLK_SRC, 6 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
};
static const struct clk_parent_data gcc_parent_data_2[] = {
@@ -434,47 +428,40 @@ static const struct clk_parent_data gcc_parent_data_2[] = {
{ .hw = &gpll0_out_main.clkr.hw },
{ .fw_name = "sleep_clk" },
{ .hw = &gpll0_out_main.clkr.hw },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct parent_map gcc_parent_map_3[] = {
{ P_XO, 0 },
{ P_SLEEP_CLK, 5 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
};
static const struct clk_parent_data gcc_parent_data_3[] = {
{ .fw_name = "xo" },
{ .fw_name = "sleep_clk" },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct parent_map gcc_parent_map_4[] = {
{ P_XO, 0 },
{ P_GPLL0_OUT_MAIN, 1 },
{ P_GPLL4_OUT_MAIN, 5 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
};
static const struct clk_parent_data gcc_parent_data_4[] = {
{ .fw_name = "xo" },
{ .hw = &gpll0_out_main.clkr.hw },
{ .hw = &gpll4_out_main.clkr.hw },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct parent_map gcc_parent_map_5[] = {
{ P_XO, 0 },
{ P_GPLL0_OUT_MAIN, 1 },
{ P_AUD_REF_CLK, 2 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
};
static const struct clk_parent_data gcc_parent_data_5[] = {
{ .fw_name = "xo" },
{ .hw = &gpll0_out_main.clkr.hw },
{ .fw_name = "aud_ref_clk" },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct freq_tbl ftbl_blsp1_qup1_i2c_apps_clk_src[] = {
diff --git a/drivers/clk/qcom/gcc-qcs404.c b/drivers/clk/qcom/gcc-qcs404.c
index 46d314d69250..a39c4990b29d 100644
--- a/drivers/clk/qcom/gcc-qcs404.c
+++ b/drivers/clk/qcom/gcc-qcs404.c
@@ -19,17 +19,24 @@
#include "clk-rcg.h"
#include "clk-regmap.h"
#include "common.h"
+#include "gdsc.h"
#include "reset.h"
enum {
- P_CORE_BI_PLL_TEST_SE,
+ DT_XO,
+ DT_SLEEP_CLK,
+ DT_PCIE_0_PIPE_CLK,
+ DT_DSI0_PHY_PLL_OUT_DSICLK,
+ DT_DSI0_PHY_PLL_OUT_BYTECLK,
+ DT_HDMI_PHY_PLL_CLK,
+};
+
+enum {
P_DSI0_PHY_PLL_OUT_BYTECLK,
P_DSI0_PHY_PLL_OUT_DSICLK,
- P_GPLL0_OUT_AUX,
P_GPLL0_OUT_MAIN,
P_GPLL1_OUT_MAIN,
P_GPLL3_OUT_MAIN,
- P_GPLL4_OUT_AUX,
P_GPLL4_OUT_MAIN,
P_GPLL6_OUT_AUX,
P_HDMI_PHY_PLL_CLK,
@@ -38,240 +45,12 @@ enum {
P_XO,
};
-static const struct parent_map gcc_parent_map_0[] = {
- { P_XO, 0 },
- { P_GPLL0_OUT_MAIN, 1 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
-};
-
-static const char * const gcc_parent_names_0[] = {
- "cxo",
- "gpll0_out_main",
- "core_bi_pll_test_se",
-};
-
-static const char * const gcc_parent_names_ao_0[] = {
- "cxo",
- "gpll0_ao_out_main",
- "core_bi_pll_test_se",
-};
-
static const struct parent_map gcc_parent_map_1[] = {
{ P_XO, 0 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
-};
-
-static const char * const gcc_parent_names_1[] = {
- "cxo",
- "core_bi_pll_test_se",
-};
-
-static const struct parent_map gcc_parent_map_2[] = {
- { P_XO, 0 },
- { P_GPLL0_OUT_MAIN, 1 },
- { P_GPLL6_OUT_AUX, 2 },
- { P_SLEEP_CLK, 6 },
-};
-
-static const char * const gcc_parent_names_2[] = {
- "cxo",
- "gpll0_out_main",
- "gpll6_out_aux",
- "sleep_clk",
-};
-
-static const struct parent_map gcc_parent_map_3[] = {
- { P_XO, 0 },
- { P_GPLL0_OUT_MAIN, 1 },
- { P_GPLL6_OUT_AUX, 2 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
-};
-
-static const char * const gcc_parent_names_3[] = {
- "cxo",
- "gpll0_out_main",
- "gpll6_out_aux",
- "core_bi_pll_test_se",
-};
-
-static const struct parent_map gcc_parent_map_4[] = {
- { P_XO, 0 },
- { P_GPLL1_OUT_MAIN, 1 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
-};
-
-static const char * const gcc_parent_names_4[] = {
- "cxo",
- "gpll1_out_main",
- "core_bi_pll_test_se",
-};
-
-static const struct parent_map gcc_parent_map_5[] = {
- { P_XO, 0 },
- { P_DSI0_PHY_PLL_OUT_BYTECLK, 1 },
- { P_GPLL0_OUT_AUX, 2 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
-};
-
-static const char * const gcc_parent_names_5[] = {
- "cxo",
- "dsi0pll_byteclk_src",
- "gpll0_out_aux",
- "core_bi_pll_test_se",
-};
-
-static const struct parent_map gcc_parent_map_6[] = {
- { P_XO, 0 },
- { P_DSI0_PHY_PLL_OUT_BYTECLK, 2 },
- { P_GPLL0_OUT_AUX, 3 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
-};
-
-static const char * const gcc_parent_names_6[] = {
- "cxo",
- "dsi0_phy_pll_out_byteclk",
- "gpll0_out_aux",
- "core_bi_pll_test_se",
-};
-
-static const struct parent_map gcc_parent_map_7[] = {
- { P_XO, 0 },
- { P_GPLL0_OUT_MAIN, 1 },
- { P_GPLL3_OUT_MAIN, 2 },
- { P_GPLL6_OUT_AUX, 3 },
- { P_GPLL4_OUT_AUX, 4 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
-};
-
-static const char * const gcc_parent_names_7[] = {
- "cxo",
- "gpll0_out_main",
- "gpll3_out_main",
- "gpll6_out_aux",
- "gpll4_out_aux",
- "core_bi_pll_test_se",
-};
-
-static const struct parent_map gcc_parent_map_8[] = {
- { P_XO, 0 },
- { P_HDMI_PHY_PLL_CLK, 1 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
-};
-
-static const char * const gcc_parent_names_8[] = {
- "cxo",
- "hdmi_phy_pll_clk",
- "core_bi_pll_test_se",
-};
-
-static const struct parent_map gcc_parent_map_9[] = {
- { P_XO, 0 },
- { P_GPLL0_OUT_MAIN, 1 },
- { P_DSI0_PHY_PLL_OUT_DSICLK, 2 },
- { P_GPLL6_OUT_AUX, 3 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
-};
-
-static const char * const gcc_parent_names_9[] = {
- "cxo",
- "gpll0_out_main",
- "dsi0_phy_pll_out_dsiclk",
- "gpll6_out_aux",
- "core_bi_pll_test_se",
-};
-
-static const struct parent_map gcc_parent_map_10[] = {
- { P_XO, 0 },
- { P_SLEEP_CLK, 1 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
-};
-
-static const char * const gcc_parent_names_10[] = {
- "cxo",
- "sleep_clk",
- "core_bi_pll_test_se",
-};
-
-static const struct parent_map gcc_parent_map_11[] = {
- { P_XO, 0 },
- { P_PCIE_0_PIPE_CLK, 1 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
-};
-
-static const char * const gcc_parent_names_11[] = {
- "cxo",
- "pcie_0_pipe_clk",
- "core_bi_pll_test_se",
-};
-
-static const struct parent_map gcc_parent_map_12[] = {
- { P_XO, 0 },
- { P_DSI0_PHY_PLL_OUT_DSICLK, 1 },
- { P_GPLL0_OUT_AUX, 2 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
-};
-
-static const char * const gcc_parent_names_12[] = {
- "cxo",
- "dsi0pll_pclk_src",
- "gpll0_out_aux",
- "core_bi_pll_test_se",
-};
-
-static const struct parent_map gcc_parent_map_13[] = {
- { P_XO, 0 },
- { P_GPLL0_OUT_MAIN, 1 },
- { P_GPLL4_OUT_MAIN, 2 },
- { P_GPLL6_OUT_AUX, 3 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
-};
-
-static const char * const gcc_parent_names_13[] = {
- "cxo",
- "gpll0_out_main",
- "gpll4_out_main",
- "gpll6_out_aux",
- "core_bi_pll_test_se",
};
-static const struct parent_map gcc_parent_map_14[] = {
- { P_XO, 0 },
- { P_GPLL0_OUT_MAIN, 1 },
- { P_GPLL4_OUT_AUX, 2 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
-};
-
-static const char * const gcc_parent_names_14[] = {
- "cxo",
- "gpll0_out_main",
- "gpll4_out_aux",
- "core_bi_pll_test_se",
-};
-
-static const struct parent_map gcc_parent_map_15[] = {
- { P_XO, 0 },
- { P_GPLL0_OUT_AUX, 2 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
-};
-
-static const char * const gcc_parent_names_15[] = {
- "cxo",
- "gpll0_out_aux",
- "core_bi_pll_test_se",
-};
-
-static const struct parent_map gcc_parent_map_16[] = {
- { P_XO, 0 },
- { P_GPLL0_OUT_MAIN, 1 },
- { P_GPLL0_OUT_AUX, 2 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
-};
-
-static const char * const gcc_parent_names_16[] = {
- "cxo",
- "gpll0_out_main",
- "gpll0_out_aux",
- "core_bi_pll_test_se",
+static const struct clk_parent_data gcc_parent_data_1[] = {
+ { .index = DT_XO, .name = "xo-board" },
};
static struct clk_fixed_factor cxo = {
@@ -279,8 +58,8 @@ static struct clk_fixed_factor cxo = {
.div = 1,
.hw.init = &(struct clk_init_data){
.name = "cxo",
- .parent_names = (const char *[]){ "xo-board" },
- .num_parents = 1,
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
.ops = &clk_fixed_factor_ops,
},
};
@@ -294,8 +73,8 @@ static struct clk_alpha_pll gpll0_sleep_clk_src = {
.enable_is_inverted = true,
.hw.init = &(struct clk_init_data){
.name = "gpll0_sleep_clk_src",
- .parent_names = (const char *[]){ "cxo" },
- .num_parents = 1,
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
.ops = &clk_alpha_pll_ops,
},
},
@@ -310,9 +89,8 @@ static struct clk_alpha_pll gpll0_out_main = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gpll0_out_main",
- .parent_names = (const char *[])
- { "cxo" },
- .num_parents = 1,
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
.ops = &clk_alpha_pll_ops,
},
},
@@ -327,8 +105,8 @@ static struct clk_alpha_pll gpll0_ao_out_main = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gpll0_ao_out_main",
- .parent_names = (const char *[]){ "cxo" },
- .num_parents = 1,
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
.flags = CLK_IS_CRITICAL,
.ops = &clk_alpha_pll_fixed_ops,
},
@@ -343,8 +121,8 @@ static struct clk_alpha_pll gpll1_out_main = {
.enable_mask = BIT(1),
.hw.init = &(struct clk_init_data){
.name = "gpll1_out_main",
- .parent_names = (const char *[]){ "cxo" },
- .num_parents = 1,
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
.ops = &clk_alpha_pll_ops,
},
},
@@ -374,8 +152,8 @@ static struct clk_alpha_pll gpll3_out_main = {
.clkr = {
.hw.init = &(struct clk_init_data){
.name = "gpll3_out_main",
- .parent_names = (const char *[]){ "cxo" },
- .num_parents = 1,
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
.ops = &clk_alpha_pll_ops,
},
},
@@ -389,8 +167,8 @@ static struct clk_alpha_pll gpll4_out_main = {
.enable_mask = BIT(5),
.hw.init = &(struct clk_init_data){
.name = "gpll4_out_main",
- .parent_names = (const char *[]){ "cxo" },
- .num_parents = 1,
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
.ops = &clk_alpha_pll_ops,
},
},
@@ -406,8 +184,8 @@ static struct clk_pll gpll6 = {
.status_bit = 17,
.clkr.hw.init = &(struct clk_init_data){
.name = "gpll6",
- .parent_names = (const char *[]){ "cxo" },
- .num_parents = 1,
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
.ops = &clk_pll_ops,
},
};
@@ -417,12 +195,195 @@ static struct clk_regmap gpll6_out_aux = {
.enable_mask = BIT(7),
.hw.init = &(struct clk_init_data){
.name = "gpll6_out_aux",
- .parent_names = (const char *[]){ "gpll6" },
+ .parent_hws = (const struct clk_hw*[]) {
+ &gpll6.clkr.hw,
+ },
.num_parents = 1,
.ops = &clk_pll_vote_ops,
},
};
+static const struct parent_map gcc_parent_map_0[] = {
+ { P_XO, 0 },
+ { P_GPLL0_OUT_MAIN, 1 },
+};
+
+static const struct clk_parent_data gcc_parent_data_0[] = {
+ { .index = DT_XO, .name = "xo-board" },
+ { .hw = &gpll0_out_main.clkr.hw },
+};
+
+static const struct clk_parent_data gcc_parent_data_ao_0[] = {
+ { .index = DT_XO, .name = "xo-board" },
+ { .hw = &gpll0_ao_out_main.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_2[] = {
+ { P_XO, 0 },
+ { P_GPLL0_OUT_MAIN, 1 },
+ { P_GPLL6_OUT_AUX, 2 },
+ { P_SLEEP_CLK, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_2[] = {
+ { .index = DT_XO, .name = "xo-board" },
+ { .hw = &gpll0_out_main.clkr.hw },
+ { .hw = &gpll6_out_aux.hw },
+ { .index = DT_SLEEP_CLK, .name = "sleep_clk" },
+};
+
+static const struct parent_map gcc_parent_map_3[] = {
+ { P_XO, 0 },
+ { P_GPLL0_OUT_MAIN, 1 },
+ { P_GPLL6_OUT_AUX, 2 },
+};
+
+static const struct clk_parent_data gcc_parent_data_3[] = {
+ { .index = DT_XO, .name = "xo-board" },
+ { .hw = &gpll0_out_main.clkr.hw },
+ { .hw = &gpll6_out_aux.hw },
+};
+
+static const struct parent_map gcc_parent_map_4[] = {
+ { P_XO, 0 },
+ { P_GPLL1_OUT_MAIN, 1 },
+};
+
+static const struct clk_parent_data gcc_parent_data_4[] = {
+ { .index = DT_XO, .name = "xo-board" },
+ { .hw = &gpll1_out_main.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_5[] = {
+ { P_XO, 0 },
+ { P_DSI0_PHY_PLL_OUT_BYTECLK, 1 },
+};
+
+static const struct clk_parent_data gcc_parent_data_5[] = {
+ { .index = DT_XO, .name = "xo-board" },
+ { .index = DT_DSI0_PHY_PLL_OUT_BYTECLK, .name = "dsi0pllbyte" },
+};
+
+static const struct parent_map gcc_parent_map_6[] = {
+ { P_XO, 0 },
+ { P_DSI0_PHY_PLL_OUT_BYTECLK, 2 },
+};
+
+static const struct clk_parent_data gcc_parent_data_6[] = {
+ { .index = DT_XO, .name = "xo-board" },
+ { .index = DT_DSI0_PHY_PLL_OUT_BYTECLK, .name = "dsi0pllbyte" },
+};
+
+static const struct parent_map gcc_parent_map_7[] = {
+ { P_XO, 0 },
+ { P_GPLL0_OUT_MAIN, 1 },
+ { P_GPLL3_OUT_MAIN, 2 },
+ { P_GPLL6_OUT_AUX, 3 },
+};
+
+static const struct clk_parent_data gcc_parent_data_7[] = {
+ { .index = DT_XO, .name = "xo-board" },
+ { .hw = &gpll0_out_main.clkr.hw },
+ { .hw = &gpll3_out_main.clkr.hw },
+ { .hw = &gpll6_out_aux.hw },
+};
+
+static const struct parent_map gcc_parent_map_8[] = {
+ { P_XO, 0 },
+ { P_HDMI_PHY_PLL_CLK, 1 },
+};
+
+static const struct clk_parent_data gcc_parent_data_8[] = {
+ { .index = DT_XO, .name = "xo-board" },
+ { .index = DT_HDMI_PHY_PLL_CLK, .name = "hdmi_pll" },
+};
+
+static const struct parent_map gcc_parent_map_9[] = {
+ { P_XO, 0 },
+ { P_GPLL0_OUT_MAIN, 1 },
+ { P_DSI0_PHY_PLL_OUT_DSICLK, 2 },
+ { P_GPLL6_OUT_AUX, 3 },
+};
+
+static const struct clk_parent_data gcc_parent_data_9[] = {
+ { .index = DT_XO, .name = "xo-board" },
+ { .hw = &gpll0_out_main.clkr.hw },
+ { .index = DT_DSI0_PHY_PLL_OUT_DSICLK, .name = "dsi0pll" },
+ { .hw = &gpll6_out_aux.hw },
+};
+
+static const struct parent_map gcc_parent_map_10[] = {
+ { P_XO, 0 },
+ { P_SLEEP_CLK, 1 },
+};
+
+static const struct clk_parent_data gcc_parent_data_10[] = {
+ { .index = DT_XO, .name = "xo-board" },
+ { .index = DT_SLEEP_CLK, .name = "sleep_clk" },
+};
+
+static const struct parent_map gcc_parent_map_11[] = {
+ { P_XO, 0 },
+ { P_PCIE_0_PIPE_CLK, 1 },
+};
+
+static const struct clk_parent_data gcc_parent_data_11[] = {
+ { .index = DT_XO, .name = "xo-board" },
+ { .fw_name = "pcie_0_pipe_clk", .name = "pcie_0_pipe_clk" },
+};
+
+static const struct parent_map gcc_parent_map_12[] = {
+ { P_XO, 0 },
+ { P_DSI0_PHY_PLL_OUT_DSICLK, 1 },
+};
+
+static const struct clk_parent_data gcc_parent_data_12[] = {
+ { .index = DT_XO, .name = "xo-board" },
+ { .index = DT_DSI0_PHY_PLL_OUT_DSICLK, .name = "dsi0pll" },
+};
+
+static const struct parent_map gcc_parent_map_13[] = {
+ { P_XO, 0 },
+ { P_GPLL0_OUT_MAIN, 1 },
+ { P_GPLL4_OUT_MAIN, 2 },
+ { P_GPLL6_OUT_AUX, 3 },
+};
+
+static const struct clk_parent_data gcc_parent_data_13[] = {
+ { .index = DT_XO, .name = "xo-board" },
+ { .hw = &gpll0_out_main.clkr.hw },
+ { .hw = &gpll4_out_main.clkr.hw },
+ { .hw = &gpll6_out_aux.hw },
+};
+
+static const struct parent_map gcc_parent_map_14[] = {
+ { P_XO, 0 },
+ { P_GPLL0_OUT_MAIN, 1 },
+};
+
+static const struct clk_parent_data gcc_parent_data_14[] = {
+ { .index = DT_XO, .name = "xo-board" },
+ { .hw = &gpll0_out_main.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_15[] = {
+ { P_XO, 0 },
+};
+
+static const struct clk_parent_data gcc_parent_data_15[] = {
+ { .index = DT_XO, .name = "xo-board" },
+};
+
+static const struct parent_map gcc_parent_map_16[] = {
+ { P_XO, 0 },
+ { P_GPLL0_OUT_MAIN, 1 },
+};
+
+static const struct clk_parent_data gcc_parent_data_16[] = {
+ { .index = DT_XO, .name = "xo-board" },
+ { .hw = &gpll0_out_main.clkr.hw },
+};
+
static const struct freq_tbl ftbl_apss_ahb_clk_src[] = {
F(19200000, P_XO, 1, 0, 0),
F(50000000, P_GPLL0_OUT_MAIN, 16, 0, 0),
@@ -439,8 +400,8 @@ static struct clk_rcg2 apss_ahb_clk_src = {
.freq_tbl = ftbl_apss_ahb_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "apss_ahb_clk_src",
- .parent_names = gcc_parent_names_ao_0,
- .num_parents = 3,
+ .parent_data = gcc_parent_data_ao_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_ao_0),
.flags = CLK_IS_CRITICAL,
.ops = &clk_rcg2_ops,
},
@@ -460,8 +421,8 @@ static struct clk_rcg2 blsp1_qup0_i2c_apps_clk_src = {
.freq_tbl = ftbl_blsp1_qup0_i2c_apps_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp1_qup0_i2c_apps_clk_src",
- .parent_names = gcc_parent_names_0,
- .num_parents = 3,
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
.ops = &clk_rcg2_ops,
},
};
@@ -485,8 +446,8 @@ static struct clk_rcg2 blsp1_qup0_spi_apps_clk_src = {
.freq_tbl = ftbl_blsp1_qup0_spi_apps_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp1_qup0_spi_apps_clk_src",
- .parent_names = gcc_parent_names_0,
- .num_parents = 3,
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
.ops = &clk_rcg2_ops,
},
};
@@ -499,8 +460,8 @@ static struct clk_rcg2 blsp1_qup1_i2c_apps_clk_src = {
.freq_tbl = ftbl_blsp1_qup0_i2c_apps_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp1_qup1_i2c_apps_clk_src",
- .parent_names = gcc_parent_names_0,
- .num_parents = 3,
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
.ops = &clk_rcg2_ops,
},
};
@@ -524,8 +485,8 @@ static struct clk_rcg2 blsp1_qup1_spi_apps_clk_src = {
.freq_tbl = ftbl_blsp1_qup1_spi_apps_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp1_qup1_spi_apps_clk_src",
- .parent_names = gcc_parent_names_0,
- .num_parents = 3,
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
.ops = &clk_rcg2_ops,
},
};
@@ -538,8 +499,8 @@ static struct clk_rcg2 blsp1_qup2_i2c_apps_clk_src = {
.freq_tbl = ftbl_blsp1_qup0_i2c_apps_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp1_qup2_i2c_apps_clk_src",
- .parent_names = gcc_parent_names_0,
- .num_parents = 3,
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
.ops = &clk_rcg2_ops,
},
};
@@ -564,8 +525,8 @@ static struct clk_rcg2 blsp1_qup2_spi_apps_clk_src = {
.freq_tbl = ftbl_blsp1_qup2_spi_apps_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp1_qup2_spi_apps_clk_src",
- .parent_names = gcc_parent_names_0,
- .num_parents = 3,
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
.ops = &clk_rcg2_ops,
},
};
@@ -578,8 +539,8 @@ static struct clk_rcg2 blsp1_qup3_i2c_apps_clk_src = {
.freq_tbl = ftbl_blsp1_qup0_i2c_apps_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp1_qup3_i2c_apps_clk_src",
- .parent_names = gcc_parent_names_0,
- .num_parents = 3,
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
.ops = &clk_rcg2_ops,
},
};
@@ -592,8 +553,8 @@ static struct clk_rcg2 blsp1_qup3_spi_apps_clk_src = {
.freq_tbl = ftbl_blsp1_qup0_spi_apps_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp1_qup3_spi_apps_clk_src",
- .parent_names = gcc_parent_names_0,
- .num_parents = 3,
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
.ops = &clk_rcg2_ops,
},
};
@@ -606,8 +567,8 @@ static struct clk_rcg2 blsp1_qup4_i2c_apps_clk_src = {
.freq_tbl = ftbl_blsp1_qup0_i2c_apps_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp1_qup4_i2c_apps_clk_src",
- .parent_names = gcc_parent_names_0,
- .num_parents = 3,
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
.ops = &clk_rcg2_ops,
},
};
@@ -620,8 +581,8 @@ static struct clk_rcg2 blsp1_qup4_spi_apps_clk_src = {
.freq_tbl = ftbl_blsp1_qup0_spi_apps_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp1_qup4_spi_apps_clk_src",
- .parent_names = gcc_parent_names_0,
- .num_parents = 3,
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
.ops = &clk_rcg2_ops,
},
};
@@ -654,8 +615,8 @@ static struct clk_rcg2 blsp1_uart0_apps_clk_src = {
.freq_tbl = ftbl_blsp1_uart0_apps_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp1_uart0_apps_clk_src",
- .parent_names = gcc_parent_names_0,
- .num_parents = 3,
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
.ops = &clk_rcg2_ops,
},
};
@@ -668,8 +629,8 @@ static struct clk_rcg2 blsp1_uart1_apps_clk_src = {
.freq_tbl = ftbl_blsp1_uart0_apps_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp1_uart1_apps_clk_src",
- .parent_names = gcc_parent_names_0,
- .num_parents = 3,
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
.ops = &clk_rcg2_ops,
},
};
@@ -682,8 +643,8 @@ static struct clk_rcg2 blsp1_uart2_apps_clk_src = {
.freq_tbl = ftbl_blsp1_uart0_apps_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp1_uart2_apps_clk_src",
- .parent_names = gcc_parent_names_0,
- .num_parents = 3,
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
.ops = &clk_rcg2_ops,
},
};
@@ -697,8 +658,8 @@ static struct clk_rcg2 blsp1_uart3_apps_clk_src = {
.freq_tbl = ftbl_blsp1_uart0_apps_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp1_uart3_apps_clk_src",
- .parent_names = gcc_parent_names_0,
- .num_parents = 3,
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
.ops = &clk_rcg2_ops,
},
};
@@ -711,8 +672,8 @@ static struct clk_rcg2 blsp2_qup0_i2c_apps_clk_src = {
.freq_tbl = ftbl_blsp1_qup0_i2c_apps_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp2_qup0_i2c_apps_clk_src",
- .parent_names = gcc_parent_names_0,
- .num_parents = 3,
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
.ops = &clk_rcg2_ops,
},
};
@@ -725,8 +686,8 @@ static struct clk_rcg2 blsp2_qup0_spi_apps_clk_src = {
.freq_tbl = ftbl_blsp1_qup0_spi_apps_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp2_qup0_spi_apps_clk_src",
- .parent_names = gcc_parent_names_0,
- .num_parents = 3,
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
.ops = &clk_rcg2_ops,
},
};
@@ -739,8 +700,8 @@ static struct clk_rcg2 blsp2_uart0_apps_clk_src = {
.freq_tbl = ftbl_blsp1_uart0_apps_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "blsp2_uart0_apps_clk_src",
- .parent_names = gcc_parent_names_0,
- .num_parents = 3,
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
.ops = &clk_rcg2_ops,
},
};
@@ -752,8 +713,8 @@ static struct clk_rcg2 byte0_clk_src = {
.parent_map = gcc_parent_map_5,
.clkr.hw.init = &(struct clk_init_data){
.name = "byte0_clk_src",
- .parent_names = gcc_parent_names_5,
- .num_parents = 4,
+ .parent_data = gcc_parent_data_5,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_5),
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_byte2_ops,
},
@@ -775,8 +736,8 @@ static struct clk_rcg2 emac_clk_src = {
.freq_tbl = ftbl_emac_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "emac_clk_src",
- .parent_names = gcc_parent_names_4,
- .num_parents = 3,
+ .parent_data = gcc_parent_data_4,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_4),
.ops = &clk_rcg2_ops,
},
};
@@ -796,8 +757,8 @@ static struct clk_rcg2 emac_ptp_clk_src = {
.freq_tbl = ftbl_emac_ptp_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "emac_ptp_clk_src",
- .parent_names = gcc_parent_names_4,
- .num_parents = 3,
+ .parent_data = gcc_parent_data_4,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_4),
.ops = &clk_rcg2_ops,
},
};
@@ -815,8 +776,8 @@ static struct clk_rcg2 esc0_clk_src = {
.freq_tbl = ftbl_esc0_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "esc0_clk_src",
- .parent_names = gcc_parent_names_6,
- .num_parents = 4,
+ .parent_data = gcc_parent_data_6,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_6),
.ops = &clk_rcg2_ops,
},
};
@@ -849,8 +810,8 @@ static struct clk_rcg2 gfx3d_clk_src = {
.freq_tbl = ftbl_gfx3d_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "gfx3d_clk_src",
- .parent_names = gcc_parent_names_7,
- .num_parents = 6,
+ .parent_data = gcc_parent_data_7,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_7),
.ops = &clk_rcg2_ops,
},
};
@@ -870,8 +831,8 @@ static struct clk_rcg2 gp1_clk_src = {
.freq_tbl = ftbl_gp1_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "gp1_clk_src",
- .parent_names = gcc_parent_names_2,
- .num_parents = 4,
+ .parent_data = gcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_2),
.ops = &clk_rcg2_ops,
},
};
@@ -884,8 +845,8 @@ static struct clk_rcg2 gp2_clk_src = {
.freq_tbl = ftbl_gp1_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "gp2_clk_src",
- .parent_names = gcc_parent_names_2,
- .num_parents = 4,
+ .parent_data = gcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_2),
.ops = &clk_rcg2_ops,
},
};
@@ -898,8 +859,8 @@ static struct clk_rcg2 gp3_clk_src = {
.freq_tbl = ftbl_gp1_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "gp3_clk_src",
- .parent_names = gcc_parent_names_2,
- .num_parents = 4,
+ .parent_data = gcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_2),
.ops = &clk_rcg2_ops,
},
};
@@ -912,8 +873,8 @@ static struct clk_rcg2 hdmi_app_clk_src = {
.freq_tbl = ftbl_esc0_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "hdmi_app_clk_src",
- .parent_names = gcc_parent_names_1,
- .num_parents = 2,
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
.ops = &clk_rcg2_ops,
},
};
@@ -926,8 +887,8 @@ static struct clk_rcg2 hdmi_pclk_clk_src = {
.freq_tbl = ftbl_esc0_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "hdmi_pclk_clk_src",
- .parent_names = gcc_parent_names_8,
- .num_parents = 3,
+ .parent_data = gcc_parent_data_8,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_8),
.ops = &clk_rcg2_ops,
},
};
@@ -953,8 +914,8 @@ static struct clk_rcg2 mdp_clk_src = {
.freq_tbl = ftbl_mdp_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "mdp_clk_src",
- .parent_names = gcc_parent_names_9,
- .num_parents = 5,
+ .parent_data = gcc_parent_data_9,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_9),
.ops = &clk_rcg2_ops,
},
};
@@ -972,8 +933,8 @@ static struct clk_rcg2 pcie_0_aux_clk_src = {
.freq_tbl = ftbl_pcie_0_aux_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "pcie_0_aux_clk_src",
- .parent_names = gcc_parent_names_10,
- .num_parents = 3,
+ .parent_data = gcc_parent_data_10,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_10),
.ops = &clk_rcg2_ops,
},
};
@@ -993,8 +954,8 @@ static struct clk_rcg2 pcie_0_pipe_clk_src = {
.freq_tbl = ftbl_pcie_0_pipe_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "pcie_0_pipe_clk_src",
- .parent_names = gcc_parent_names_11,
- .num_parents = 3,
+ .parent_data = gcc_parent_data_11,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_11),
.ops = &clk_rcg2_ops,
},
};
@@ -1006,8 +967,8 @@ static struct clk_rcg2 pclk0_clk_src = {
.parent_map = gcc_parent_map_12,
.clkr.hw.init = &(struct clk_init_data){
.name = "pclk0_clk_src",
- .parent_names = gcc_parent_names_12,
- .num_parents = 4,
+ .parent_data = gcc_parent_data_12,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_12),
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_pixel_ops,
},
@@ -1027,8 +988,8 @@ static struct clk_rcg2 pdm2_clk_src = {
.freq_tbl = ftbl_pdm2_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "pdm2_clk_src",
- .parent_names = gcc_parent_names_0,
- .num_parents = 3,
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
.ops = &clk_rcg2_ops,
},
};
@@ -1055,8 +1016,8 @@ static struct clk_rcg2 sdcc1_apps_clk_src = {
.freq_tbl = ftbl_sdcc1_apps_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "sdcc1_apps_clk_src",
- .parent_names = gcc_parent_names_13,
- .num_parents = 5,
+ .parent_data = gcc_parent_data_13,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_13),
.ops = &clk_rcg2_floor_ops,
},
};
@@ -1075,8 +1036,8 @@ static struct clk_rcg2 sdcc1_ice_core_clk_src = {
.freq_tbl = ftbl_sdcc1_ice_core_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "sdcc1_ice_core_clk_src",
- .parent_names = gcc_parent_names_3,
- .num_parents = 4,
+ .parent_data = gcc_parent_data_3,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_3),
.ops = &clk_rcg2_ops,
},
};
@@ -1101,8 +1062,8 @@ static struct clk_rcg2 sdcc2_apps_clk_src = {
.freq_tbl = ftbl_sdcc2_apps_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "sdcc2_apps_clk_src",
- .parent_names = gcc_parent_names_14,
- .num_parents = 4,
+ .parent_data = gcc_parent_data_14,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_14),
.ops = &clk_rcg2_floor_ops,
},
};
@@ -1115,8 +1076,8 @@ static struct clk_rcg2 usb20_mock_utmi_clk_src = {
.freq_tbl = ftbl_esc0_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "usb20_mock_utmi_clk_src",
- .parent_names = gcc_parent_names_1,
- .num_parents = 2,
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
.ops = &clk_rcg2_ops,
},
};
@@ -1137,8 +1098,8 @@ static struct clk_rcg2 usb30_master_clk_src = {
.freq_tbl = ftbl_usb30_master_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "usb30_master_clk_src",
- .parent_names = gcc_parent_names_0,
- .num_parents = 3,
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
.ops = &clk_rcg2_ops,
},
};
@@ -1151,8 +1112,8 @@ static struct clk_rcg2 usb30_mock_utmi_clk_src = {
.freq_tbl = ftbl_esc0_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "usb30_mock_utmi_clk_src",
- .parent_names = gcc_parent_names_1,
- .num_parents = 2,
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
.ops = &clk_rcg2_ops,
},
};
@@ -1165,8 +1126,8 @@ static struct clk_rcg2 usb3_phy_aux_clk_src = {
.freq_tbl = ftbl_pcie_0_aux_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "usb3_phy_aux_clk_src",
- .parent_names = gcc_parent_names_1,
- .num_parents = 2,
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
.ops = &clk_rcg2_ops,
},
};
@@ -1188,8 +1149,8 @@ static struct clk_rcg2 usb_hs_system_clk_src = {
.freq_tbl = ftbl_usb_hs_system_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "usb_hs_system_clk_src",
- .parent_names = gcc_parent_names_3,
- .num_parents = 4,
+ .parent_data = gcc_parent_data_3,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_3),
.ops = &clk_rcg2_ops,
},
};
@@ -1202,8 +1163,8 @@ static struct clk_rcg2 vsync_clk_src = {
.freq_tbl = ftbl_esc0_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "vsync_clk_src",
- .parent_names = gcc_parent_names_15,
- .num_parents = 3,
+ .parent_data = gcc_parent_data_15,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_15),
.ops = &clk_rcg2_ops,
},
};
@@ -1224,8 +1185,8 @@ static struct clk_rcg2 cdsp_bimc_clk_src = {
.freq_tbl = ftbl_cdsp_bimc_clk_src,
.clkr.hw.init = &(struct clk_init_data) {
.name = "cdsp_bimc_clk_src",
- .parent_names = gcc_parent_names_16,
- .num_parents = 4,
+ .parent_data = gcc_parent_data_16,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_16),
.ops = &clk_rcg2_ops,
},
};
@@ -1238,8 +1199,8 @@ static struct clk_branch gcc_apss_ahb_clk = {
.enable_mask = BIT(14),
.hw.init = &(struct clk_init_data){
.name = "gcc_apss_ahb_clk",
- .parent_names = (const char *[]){
- "apss_ahb_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &apss_ahb_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1270,8 +1231,8 @@ static struct clk_branch gcc_bimc_gfx_clk = {
.hw.init = &(struct clk_init_data){
.name = "gcc_bimc_gfx_clk",
.ops = &clk_branch2_ops,
- .parent_names = (const char *[]){
- "gcc_apss_tcu_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_apss_tcu_clk.clkr.hw,
},
},
@@ -1299,8 +1260,8 @@ static struct clk_branch gcc_bimc_cdsp_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "gcc_bimc_cdsp_clk",
- .parent_names = (const char *[]) {
- "cdsp_bimc_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cdsp_bimc_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1369,8 +1330,8 @@ static struct clk_branch gcc_blsp1_qup0_i2c_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_qup0_i2c_apps_clk",
- .parent_names = (const char *[]){
- "blsp1_qup0_i2c_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &blsp1_qup0_i2c_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1387,8 +1348,8 @@ static struct clk_branch gcc_blsp1_qup0_spi_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_qup0_spi_apps_clk",
- .parent_names = (const char *[]){
- "blsp1_qup0_spi_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &blsp1_qup0_spi_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1405,8 +1366,8 @@ static struct clk_branch gcc_blsp1_qup1_i2c_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_qup1_i2c_apps_clk",
- .parent_names = (const char *[]){
- "blsp1_qup1_i2c_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &blsp1_qup1_i2c_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1423,8 +1384,8 @@ static struct clk_branch gcc_blsp1_qup1_spi_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_qup1_spi_apps_clk",
- .parent_names = (const char *[]){
- "blsp1_qup1_spi_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &blsp1_qup1_spi_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1441,8 +1402,8 @@ static struct clk_branch gcc_blsp1_qup2_i2c_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_qup2_i2c_apps_clk",
- .parent_names = (const char *[]){
- "blsp1_qup2_i2c_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &blsp1_qup2_i2c_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1459,8 +1420,8 @@ static struct clk_branch gcc_blsp1_qup2_spi_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_qup2_spi_apps_clk",
- .parent_names = (const char *[]){
- "blsp1_qup2_spi_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &blsp1_qup2_spi_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1477,8 +1438,8 @@ static struct clk_branch gcc_blsp1_qup3_i2c_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_qup3_i2c_apps_clk",
- .parent_names = (const char *[]){
- "blsp1_qup3_i2c_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &blsp1_qup3_i2c_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1495,8 +1456,8 @@ static struct clk_branch gcc_blsp1_qup3_spi_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_qup3_spi_apps_clk",
- .parent_names = (const char *[]){
- "blsp1_qup3_spi_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &blsp1_qup3_spi_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1513,8 +1474,8 @@ static struct clk_branch gcc_blsp1_qup4_i2c_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_qup4_i2c_apps_clk",
- .parent_names = (const char *[]){
- "blsp1_qup4_i2c_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &blsp1_qup4_i2c_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1531,8 +1492,8 @@ static struct clk_branch gcc_blsp1_qup4_spi_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_qup4_spi_apps_clk",
- .parent_names = (const char *[]){
- "blsp1_qup4_spi_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &blsp1_qup4_spi_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1549,8 +1510,8 @@ static struct clk_branch gcc_blsp1_uart0_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_uart0_apps_clk",
- .parent_names = (const char *[]){
- "blsp1_uart0_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &blsp1_uart0_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1567,8 +1528,8 @@ static struct clk_branch gcc_blsp1_uart1_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_uart1_apps_clk",
- .parent_names = (const char *[]){
- "blsp1_uart1_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &blsp1_uart1_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1585,8 +1546,8 @@ static struct clk_branch gcc_blsp1_uart2_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_uart2_apps_clk",
- .parent_names = (const char *[]){
- "blsp1_uart2_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &blsp1_uart2_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1603,8 +1564,8 @@ static struct clk_branch gcc_blsp1_uart3_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_uart3_apps_clk",
- .parent_names = (const char *[]){
- "blsp1_uart3_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &blsp1_uart3_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1634,8 +1595,8 @@ static struct clk_branch gcc_blsp2_qup0_i2c_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp2_qup0_i2c_apps_clk",
- .parent_names = (const char *[]){
- "blsp2_qup0_i2c_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &blsp2_qup0_i2c_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1652,8 +1613,8 @@ static struct clk_branch gcc_blsp2_qup0_spi_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp2_qup0_spi_apps_clk",
- .parent_names = (const char *[]){
- "blsp2_qup0_spi_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &blsp2_qup0_spi_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1670,8 +1631,8 @@ static struct clk_branch gcc_blsp2_uart0_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp2_uart0_apps_clk",
- .parent_names = (const char *[]){
- "blsp2_uart0_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &blsp2_uart0_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1753,8 +1714,8 @@ static struct clk_branch gcc_eth_ptp_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_eth_ptp_clk",
- .parent_names = (const char *[]){
- "emac_ptp_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &emac_ptp_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1771,8 +1732,8 @@ static struct clk_branch gcc_eth_rgmii_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_eth_rgmii_clk",
- .parent_names = (const char *[]){
- "emac_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &emac_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1854,8 +1815,8 @@ static struct clk_branch gcc_cdsp_tbu_clk = {
.enable_mask = BIT(9),
.hw.init = &(struct clk_init_data) {
.name = "gcc_cdsp_tbu_clk",
- .parent_names = (const char *[]) {
- "cdsp_bimc_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cdsp_bimc_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1872,8 +1833,8 @@ static struct clk_branch gcc_gp1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_gp1_clk",
- .parent_names = (const char *[]){
- "gp1_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gp1_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1890,8 +1851,8 @@ static struct clk_branch gcc_gp2_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_gp2_clk",
- .parent_names = (const char *[]){
- "gp2_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gp2_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1908,8 +1869,8 @@ static struct clk_branch gcc_gp3_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_gp3_clk",
- .parent_names = (const char *[]){
- "gp3_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gp3_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1978,8 +1939,8 @@ static struct clk_branch gcc_mdss_byte0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_mdss_byte0_clk",
- .parent_names = (const char *[]){
- "byte0_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &byte0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1996,8 +1957,8 @@ static struct clk_branch gcc_mdss_esc0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_mdss_esc0_clk",
- .parent_names = (const char *[]){
- "esc0_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &esc0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2014,8 +1975,8 @@ static struct clk_branch gcc_mdss_hdmi_app_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_mdss_hdmi_app_clk",
- .parent_names = (const char *[]){
- "hdmi_app_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &hdmi_app_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2032,8 +1993,8 @@ static struct clk_branch gcc_mdss_hdmi_pclk_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_mdss_hdmi_pclk_clk",
- .parent_names = (const char *[]){
- "hdmi_pclk_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &hdmi_pclk_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2050,8 +2011,8 @@ static struct clk_branch gcc_mdss_mdp_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_mdss_mdp_clk",
- .parent_names = (const char *[]){
- "mdp_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &mdp_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2068,8 +2029,8 @@ static struct clk_branch gcc_mdss_pclk0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_mdss_pclk0_clk",
- .parent_names = (const char *[]){
- "pclk0_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &pclk0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2086,8 +2047,8 @@ static struct clk_branch gcc_mdss_vsync_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_mdss_vsync_clk",
- .parent_names = (const char *[]){
- "vsync_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &vsync_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2117,8 +2078,8 @@ static struct clk_branch gcc_oxili_gfx3d_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_oxili_gfx3d_clk",
- .parent_names = (const char *[]){
- "gfx3d_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gfx3d_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2135,8 +2096,8 @@ static struct clk_branch gcc_pcie_0_aux_clk = {
.enable_mask = BIT(27),
.hw.init = &(struct clk_init_data){
.name = "gcc_pcie_0_aux_clk",
- .parent_names = (const char *[]){
- "pcie_0_aux_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &pcie_0_aux_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2179,8 +2140,8 @@ static struct clk_branch gcc_pcie_0_pipe_clk = {
.enable_mask = BIT(28),
.hw.init = &(struct clk_init_data){
.name = "gcc_pcie_0_pipe_clk",
- .parent_names = (const char *[]){
- "pcie_0_pipe_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &pcie_0_pipe_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2238,8 +2199,8 @@ static struct clk_branch gcc_pdm2_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_pdm2_clk",
- .parent_names = (const char *[]){
- "pdm2_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &pdm2_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2348,8 +2309,8 @@ static struct clk_branch gcc_sdcc1_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_sdcc1_apps_clk",
- .parent_names = (const char *[]){
- "sdcc1_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &sdcc1_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2366,8 +2327,8 @@ static struct clk_branch gcc_sdcc1_ice_core_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_sdcc1_ice_core_clk",
- .parent_names = (const char *[]){
- "sdcc1_ice_core_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &sdcc1_ice_core_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2410,8 +2371,8 @@ static struct clk_branch gcc_sdcc2_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_sdcc2_apps_clk",
- .parent_names = (const char *[]){
- "sdcc2_apps_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &sdcc2_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2441,8 +2402,8 @@ static struct clk_branch gcc_sys_noc_usb3_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_sys_noc_usb3_clk",
- .parent_names = (const char *[]){
- "usb30_master_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &usb30_master_clk_src.clkr.hw,
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -2471,8 +2432,8 @@ static struct clk_branch gcc_usb20_mock_utmi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb20_mock_utmi_clk",
- .parent_names = (const char *[]){
- "usb20_mock_utmi_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &usb20_mock_utmi_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2502,8 +2463,8 @@ static struct clk_branch gcc_usb30_master_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb30_master_clk",
- .parent_names = (const char *[]){
- "usb30_master_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &usb30_master_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2520,8 +2481,8 @@ static struct clk_branch gcc_usb30_mock_utmi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb30_mock_utmi_clk",
- .parent_names = (const char *[]){
- "usb30_mock_utmi_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &usb30_mock_utmi_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2551,8 +2512,8 @@ static struct clk_branch gcc_usb3_phy_aux_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb3_phy_aux_clk",
- .parent_names = (const char *[]){
- "usb3_phy_aux_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &usb3_phy_aux_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2594,8 +2555,8 @@ static struct clk_branch gcc_usb_hs_system_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb_hs_system_clk",
- .parent_names = (const char *[]){
- "usb_hs_system_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &usb_hs_system_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2630,6 +2591,22 @@ static struct clk_branch gcc_wdsp_q6ss_axim_clk = {
},
};
+static struct gdsc mdss_gdsc = {
+ .gdscr = 0x4d078,
+ .pd = {
+ .name = "mdss",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc oxili_gdsc = {
+ .gdscr = 0x5901c,
+ .pd = {
+ .name = "oxili",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
static struct clk_hw *gcc_qcs404_hws[] = {
&cxo.hw,
};
@@ -2780,6 +2757,11 @@ static struct clk_regmap *gcc_qcs404_clocks[] = {
};
+static struct gdsc *gcc_qcs404_gdscs[] = {
+ [MDSS_GDSC] = &mdss_gdsc,
+ [OXILI_GDSC] = &oxili_gdsc,
+};
+
static const struct qcom_reset_map gcc_qcs404_resets[] = {
[GCC_GENI_IR_BCR] = { 0x0F000 },
[GCC_CDSP_RESTART] = { 0x18000 },
@@ -2822,6 +2804,8 @@ static const struct qcom_cc_desc gcc_qcs404_desc = {
.num_resets = ARRAY_SIZE(gcc_qcs404_resets),
.clk_hws = gcc_qcs404_hws,
.num_clk_hws = ARRAY_SIZE(gcc_qcs404_hws),
+ .gdscs = gcc_qcs404_gdscs,
+ .num_gdscs = ARRAY_SIZE(gcc_qcs404_gdscs),
};
static const struct of_device_id gcc_qcs404_match_table[] = {
diff --git a/drivers/clk/qcom/gcc-qdu1000.c b/drivers/clk/qcom/gcc-qdu1000.c
new file mode 100644
index 000000000000..5051769ad90c
--- /dev/null
+++ b/drivers/clk/qcom/gcc-qdu1000.c
@@ -0,0 +1,2653 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,qdu1000-gcc.h>
+
+#include "clk-alpha-pll.h"
+#include "clk-branch.h"
+#include "clk-rcg.h"
+#include "clk-regmap.h"
+#include "clk-regmap-divider.h"
+#include "clk-regmap-mux.h"
+#include "clk-regmap-phy-mux.h"
+#include "reset.h"
+
+enum {
+ P_BI_TCXO,
+ P_GCC_GPLL0_OUT_EVEN,
+ P_GCC_GPLL0_OUT_MAIN,
+ P_GCC_GPLL1_OUT_MAIN,
+ P_GCC_GPLL2_OUT_MAIN,
+ P_GCC_GPLL3_OUT_MAIN,
+ P_GCC_GPLL4_OUT_MAIN,
+ P_GCC_GPLL5_OUT_MAIN,
+ P_GCC_GPLL6_OUT_MAIN,
+ P_GCC_GPLL7_OUT_MAIN,
+ P_GCC_GPLL8_OUT_MAIN,
+ P_PCIE_0_PHY_AUX_CLK,
+ P_PCIE_0_PIPE_CLK,
+ P_SLEEP_CLK,
+ P_USB3_PHY_WRAPPER_GCC_USB30_PIPE_CLK,
+};
+
+enum {
+ DT_TCXO_IDX,
+ DT_SLEEP_CLK_IDX,
+ DT_PCIE_0_PIPE_CLK_IDX,
+ DT_PCIE_0_PHY_AUX_CLK_IDX,
+ DT_USB3_PHY_WRAPPER_PIPE_CLK_IDX,
+};
+
+static struct clk_alpha_pll gcc_gpll0 = {
+ .offset = 0x0,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],
+ .clkr = {
+ .enable_reg = 0x62018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll0",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_TCXO_IDX,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_lucid_evo_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_gcc_gpll0_out_even[] = {
+ { 0x1, 2 }
+};
+
+static struct clk_alpha_pll_postdiv gcc_gpll0_out_even = {
+ .offset = 0x0,
+ .post_div_shift = 10,
+ .post_div_table = post_div_table_gcc_gpll0_out_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_gcc_gpll0_out_even),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll0_out_even",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gpll0.clkr.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_lucid_evo_ops,
+ },
+};
+
+static struct clk_alpha_pll gcc_gpll1 = {
+ .offset = 0x1000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],
+ .clkr = {
+ .enable_reg = 0x62018,
+ .enable_mask = BIT(1),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll1",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_TCXO_IDX,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_lucid_evo_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll_postdiv gcc_gpll1_out_even = {
+ .offset = 0x1000,
+ .post_div_shift = 10,
+ .post_div_table = post_div_table_gcc_gpll0_out_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_gcc_gpll0_out_even),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll1_out_even",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gpll1.clkr.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_lucid_evo_ops,
+ },
+};
+
+static struct clk_alpha_pll gcc_gpll2 = {
+ .offset = 0x2000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],
+ .clkr = {
+ .enable_reg = 0x62018,
+ .enable_mask = BIT(2),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll2",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_TCXO_IDX,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_lucid_evo_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll_postdiv gcc_gpll2_out_even = {
+ .offset = 0x2000,
+ .post_div_shift = 10,
+ .post_div_table = post_div_table_gcc_gpll0_out_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_gcc_gpll0_out_even),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll2_out_even",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gpll2.clkr.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_lucid_evo_ops,
+ },
+};
+
+static struct clk_alpha_pll gcc_gpll3 = {
+ .offset = 0x3000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],
+ .clkr = {
+ .enable_reg = 0x62018,
+ .enable_mask = BIT(3),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll3",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_TCXO_IDX,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_lucid_evo_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll gcc_gpll4 = {
+ .offset = 0x4000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],
+ .clkr = {
+ .enable_reg = 0x62018,
+ .enable_mask = BIT(4),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll4",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_TCXO_IDX,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_lucid_evo_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll gcc_gpll5 = {
+ .offset = 0x5000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],
+ .clkr = {
+ .enable_reg = 0x62018,
+ .enable_mask = BIT(5),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll5",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_TCXO_IDX,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_lucid_evo_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll_postdiv gcc_gpll5_out_even = {
+ .offset = 0x5000,
+ .post_div_shift = 10,
+ .post_div_table = post_div_table_gcc_gpll0_out_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_gcc_gpll0_out_even),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll5_out_even",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gpll5.clkr.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_lucid_evo_ops,
+ },
+};
+
+static struct clk_alpha_pll gcc_gpll6 = {
+ .offset = 0x6000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],
+ .clkr = {
+ .enable_reg = 0x62018,
+ .enable_mask = BIT(6),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll6",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_TCXO_IDX,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_lucid_evo_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll gcc_gpll7 = {
+ .offset = 0x7000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],
+ .clkr = {
+ .enable_reg = 0x62018,
+ .enable_mask = BIT(7),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll7",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_TCXO_IDX,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_lucid_evo_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll gcc_gpll8 = {
+ .offset = 0x8000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],
+ .clkr = {
+ .enable_reg = 0x62018,
+ .enable_mask = BIT(8),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll8",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_TCXO_IDX,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_lucid_evo_ops,
+ },
+ },
+};
+
+static const struct parent_map gcc_parent_map_0[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_GPLL0_OUT_MAIN, 1 },
+ { P_GCC_GPLL0_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_0[] = {
+ { .index = DT_TCXO_IDX },
+ { .hw = &gcc_gpll0.clkr.hw },
+ { .hw = &gcc_gpll0_out_even.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_1[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_GPLL0_OUT_MAIN, 1 },
+ { P_SLEEP_CLK, 5 },
+ { P_GCC_GPLL0_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_1[] = {
+ { .index = DT_TCXO_IDX },
+ { .hw = &gcc_gpll0.clkr.hw },
+ { .index = DT_SLEEP_CLK_IDX },
+ { .hw = &gcc_gpll0_out_even.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_2[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_GPLL0_OUT_MAIN, 1 },
+ { P_GCC_GPLL5_OUT_MAIN, 3 },
+ { P_GCC_GPLL4_OUT_MAIN, 5 },
+};
+
+static const struct clk_parent_data gcc_parent_data_2[] = {
+ { .index = DT_TCXO_IDX },
+ { .hw = &gcc_gpll0.clkr.hw },
+ { .hw = &gcc_gpll5.clkr.hw },
+ { .hw = &gcc_gpll4.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_3[] = {
+ { P_BI_TCXO, 0 },
+ { P_SLEEP_CLK, 5 },
+};
+
+static const struct clk_parent_data gcc_parent_data_3[] = {
+ { .index = DT_TCXO_IDX },
+ { .index = DT_SLEEP_CLK_IDX },
+};
+
+static const struct parent_map gcc_parent_map_4[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_GPLL0_OUT_MAIN, 1 },
+ { P_GCC_GPLL2_OUT_MAIN, 2 },
+ { P_GCC_GPLL5_OUT_MAIN, 3 },
+ { P_GCC_GPLL1_OUT_MAIN, 4 },
+ { P_GCC_GPLL4_OUT_MAIN, 5 },
+ { P_GCC_GPLL3_OUT_MAIN, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_4[] = {
+ { .index = DT_TCXO_IDX },
+ { .hw = &gcc_gpll0.clkr.hw },
+ { .hw = &gcc_gpll2.clkr.hw },
+ { .hw = &gcc_gpll5.clkr.hw },
+ { .hw = &gcc_gpll1.clkr.hw },
+ { .hw = &gcc_gpll4.clkr.hw },
+ { .hw = &gcc_gpll3.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_5[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_GPLL0_OUT_MAIN, 1 },
+ { P_GCC_GPLL2_OUT_MAIN, 2 },
+ { P_GCC_GPLL6_OUT_MAIN, 3 },
+ { P_GCC_GPLL1_OUT_MAIN, 4 },
+ { P_GCC_GPLL4_OUT_MAIN, 5 },
+ { P_GCC_GPLL3_OUT_MAIN, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_5[] = {
+ { .index = DT_TCXO_IDX },
+ { .hw = &gcc_gpll0.clkr.hw },
+ { .hw = &gcc_gpll2.clkr.hw },
+ { .hw = &gcc_gpll6.clkr.hw },
+ { .hw = &gcc_gpll1.clkr.hw },
+ { .hw = &gcc_gpll4.clkr.hw },
+ { .hw = &gcc_gpll3.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_6[] = {
+ { P_PCIE_0_PHY_AUX_CLK, 0 },
+ { P_BI_TCXO, 2 },
+};
+
+static const struct clk_parent_data gcc_parent_data_6[] = {
+ { .index = DT_PCIE_0_PHY_AUX_CLK_IDX },
+ { .index = DT_TCXO_IDX },
+};
+
+static const struct parent_map gcc_parent_map_7[] = {
+ { P_PCIE_0_PIPE_CLK, 0 },
+ { P_BI_TCXO, 2 },
+};
+
+static const struct clk_parent_data gcc_parent_data_7[] = {
+ { .index = DT_PCIE_0_PIPE_CLK_IDX },
+ { .index = DT_TCXO_IDX },
+};
+
+static const struct parent_map gcc_parent_map_8[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_GPLL0_OUT_MAIN, 1 },
+ { P_GCC_GPLL8_OUT_MAIN, 2 },
+ { P_GCC_GPLL5_OUT_MAIN, 3 },
+ { P_GCC_GPLL4_OUT_MAIN, 5 },
+};
+
+static const struct clk_parent_data gcc_parent_data_8[] = {
+ { .index = DT_TCXO_IDX },
+ { .hw = &gcc_gpll0.clkr.hw },
+ { .hw = &gcc_gpll8.clkr.hw },
+ { .hw = &gcc_gpll5.clkr.hw },
+ { .hw = &gcc_gpll4.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_9[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_GPLL0_OUT_MAIN, 1 },
+ { P_GCC_GPLL2_OUT_MAIN, 2 },
+ { P_GCC_GPLL5_OUT_MAIN, 3 },
+ { P_GCC_GPLL7_OUT_MAIN, 4 },
+ { P_GCC_GPLL4_OUT_MAIN, 5 },
+};
+
+static const struct clk_parent_data gcc_parent_data_9[] = {
+ { .index = DT_TCXO_IDX },
+ { .hw = &gcc_gpll0.clkr.hw },
+ { .hw = &gcc_gpll2.clkr.hw },
+ { .hw = &gcc_gpll5.clkr.hw },
+ { .hw = &gcc_gpll7.clkr.hw },
+ { .hw = &gcc_gpll4.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_10[] = {
+ { P_USB3_PHY_WRAPPER_GCC_USB30_PIPE_CLK, 0 },
+ { P_BI_TCXO, 2 },
+};
+
+static const struct clk_parent_data gcc_parent_data_10[] = {
+ { .index = DT_USB3_PHY_WRAPPER_PIPE_CLK_IDX },
+ { .index = DT_TCXO_IDX },
+};
+
+static struct clk_regmap_mux gcc_pcie_0_phy_aux_clk_src = {
+ .reg = 0x9d080,
+ .shift = 0,
+ .width = 2,
+ .parent_map = gcc_parent_map_6,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_phy_aux_clk_src",
+ .parent_data = gcc_parent_data_6,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_6),
+ .ops = &clk_regmap_mux_closest_ops,
+ },
+ },
+};
+
+static struct clk_regmap_mux gcc_pcie_0_pipe_clk_src = {
+ .reg = 0x9d064,
+ .shift = 0,
+ .width = 2,
+ .parent_map = gcc_parent_map_7,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_pipe_clk_src",
+ .parent_data = gcc_parent_data_7,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_7),
+ .ops = &clk_regmap_phy_mux_ops,
+ },
+ },
+};
+
+static struct clk_regmap_mux gcc_usb3_prim_phy_pipe_clk_src = {
+ .reg = 0x4906c,
+ .shift = 0,
+ .width = 2,
+ .parent_map = gcc_parent_map_10,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb3_prim_phy_pipe_clk_src",
+ .parent_data = gcc_parent_data_10,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_10),
+ .ops = &clk_regmap_mux_closest_ops,
+ },
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_aggre_noc_ecpri_dma_clk_src[] = {
+ F(466500000, P_GCC_GPLL5_OUT_MAIN, 2, 0, 0),
+ F(500000000, P_GCC_GPLL2_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_aggre_noc_ecpri_dma_clk_src = {
+ .cmd_rcgr = 0x92020,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_4,
+ .freq_tbl = ftbl_gcc_aggre_noc_ecpri_dma_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_aggre_noc_ecpri_dma_clk_src",
+ .parent_data = gcc_parent_data_4,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_4),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_aggre_noc_ecpri_gsi_clk_src[] = {
+ F(250000000, P_GCC_GPLL2_OUT_MAIN, 4, 0, 0),
+ F(300000000, P_GCC_GPLL0_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_aggre_noc_ecpri_gsi_clk_src = {
+ .cmd_rcgr = 0x92038,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_5,
+ .freq_tbl = ftbl_gcc_aggre_noc_ecpri_gsi_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_aggre_noc_ecpri_gsi_clk_src",
+ .parent_data = gcc_parent_data_5,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_5),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_gp1_clk_src[] = {
+ F(200000000, P_GCC_GPLL0_OUT_MAIN, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_gp1_clk_src = {
+ .cmd_rcgr = 0x74004,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_gp1_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gp1_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_gp2_clk_src = {
+ .cmd_rcgr = 0x75004,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_gp1_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gp2_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_gp3_clk_src = {
+ .cmd_rcgr = 0x76004,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_gp1_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gp3_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_pcie_0_aux_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_pcie_0_aux_clk_src = {
+ .cmd_rcgr = 0x9d068,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_3,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_aux_clk_src",
+ .parent_data = gcc_parent_data_3,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_3),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_pcie_0_phy_rchng_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_pcie_0_phy_rchng_clk_src = {
+ .cmd_rcgr = 0x9d04c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_phy_rchng_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_pdm2_clk_src[] = {
+ F(60000000, P_GCC_GPLL0_OUT_MAIN, 10, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_pdm2_clk_src = {
+ .cmd_rcgr = 0x43010,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pdm2_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pdm2_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src[] = {
+ F(7372800, P_GCC_GPLL0_OUT_EVEN, 1, 384, 15625),
+ F(14745600, P_GCC_GPLL0_OUT_EVEN, 1, 768, 15625),
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625),
+ F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75),
+ F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25),
+ F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75),
+ F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15),
+ F(96000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 25),
+ F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0),
+ { }
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s0_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s0_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s0_clk_src = {
+ .cmd_rcgr = 0x27154,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s0_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s1_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s1_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s1_clk_src = {
+ .cmd_rcgr = 0x27288,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s1_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s2_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s2_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s2_clk_src = {
+ .cmd_rcgr = 0x273bc,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s2_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s3_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s3_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s3_clk_src = {
+ .cmd_rcgr = 0x274f0,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s3_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s4_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s4_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s4_clk_src = {
+ .cmd_rcgr = 0x27624,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s4_clk_src_init,
+};
+
+static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s5_clk_src[] = {
+ F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0),
+ { }
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s5_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s5_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s5_clk_src = {
+ .cmd_rcgr = 0x27758,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s5_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s5_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s6_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s6_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s6_clk_src = {
+ .cmd_rcgr = 0x2788c,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s6_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s7_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s7_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s7_clk_src = {
+ .cmd_rcgr = 0x279c0,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s7_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s0_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s0_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s0_clk_src = {
+ .cmd_rcgr = 0x28154,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s0_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s1_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s1_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s1_clk_src = {
+ .cmd_rcgr = 0x28288,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s1_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s2_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s2_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s2_clk_src = {
+ .cmd_rcgr = 0x283bc,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s2_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s3_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s3_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s3_clk_src = {
+ .cmd_rcgr = 0x284f0,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s3_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s4_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s4_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s4_clk_src = {
+ .cmd_rcgr = 0x28624,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s4_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s5_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s5_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s5_clk_src = {
+ .cmd_rcgr = 0x28758,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s5_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s6_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s6_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s6_clk_src = {
+ .cmd_rcgr = 0x2888c,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s6_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s7_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s7_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s7_clk_src = {
+ .cmd_rcgr = 0x289c0,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s7_clk_src_init,
+};
+
+static const struct freq_tbl ftbl_gcc_sdcc5_apps_clk_src[] = {
+ F(144000, P_BI_TCXO, 16, 3, 25),
+ F(400000, P_BI_TCXO, 12, 1, 4),
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(20000000, P_GCC_GPLL0_OUT_MAIN, 10, 1, 3),
+ F(25000000, P_GCC_GPLL0_OUT_MAIN, 12, 1, 2),
+ F(50000000, P_GCC_GPLL0_OUT_MAIN, 12, 0, 0),
+ F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0),
+ F(192000000, P_GCC_GPLL8_OUT_MAIN, 4, 0, 0),
+ F(300000000, P_GCC_GPLL0_OUT_MAIN, 2, 0, 0),
+ F(384000000, P_GCC_GPLL8_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_sdcc5_apps_clk_src = {
+ .cmd_rcgr = 0x3b034,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_8,
+ .freq_tbl = ftbl_gcc_sdcc5_apps_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sdcc5_apps_clk_src",
+ .parent_data = gcc_parent_data_8,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_8),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_sdcc5_ice_core_clk_src[] = {
+ F(300000000, P_GCC_GPLL0_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_sdcc5_ice_core_clk_src = {
+ .cmd_rcgr = 0x3b01c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_2,
+ .freq_tbl = ftbl_gcc_sdcc5_ice_core_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sdcc5_ice_core_clk_src",
+ .parent_data = gcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_2),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_sm_bus_xo_clk_src = {
+ .cmd_rcgr = 0x5b00c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_2,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sm_bus_xo_clk_src",
+ .parent_data = gcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_2),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_tsc_clk_src[] = {
+ F(500000000, P_GCC_GPLL7_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_tsc_clk_src = {
+ .cmd_rcgr = 0x57010,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_9,
+ .freq_tbl = ftbl_gcc_tsc_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_tsc_clk_src",
+ .parent_data = gcc_parent_data_9,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_9),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_usb30_prim_master_clk_src[] = {
+ F(200000000, P_GCC_GPLL0_OUT_MAIN, 3, 0, 0),
+ F(240000000, P_GCC_GPLL0_OUT_MAIN, 2.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_usb30_prim_master_clk_src = {
+ .cmd_rcgr = 0x49028,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_usb30_prim_master_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_prim_master_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb30_prim_mock_utmi_clk_src = {
+ .cmd_rcgr = 0x49044,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_prim_mock_utmi_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb3_prim_phy_aux_clk_src = {
+ .cmd_rcgr = 0x49070,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_3,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb3_prim_phy_aux_clk_src",
+ .parent_data = gcc_parent_data_3,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_3),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_regmap_div gcc_usb30_prim_mock_utmi_postdiv_clk_src = {
+ .reg = 0x4905c,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_prim_mock_utmi_postdiv_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_mock_utmi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_branch gcc_aggre_noc_ecpri_dma_clk = {
+ .halt_reg = 0x92008,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x92008,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x92008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_aggre_noc_ecpri_dma_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_aggre_noc_ecpri_dma_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_aggre_noc_ecpri_gsi_clk = {
+ .halt_reg = 0x9201c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x9201c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x9201c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_aggre_noc_ecpri_gsi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_aggre_noc_ecpri_gsi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_boot_rom_ahb_clk = {
+ .halt_reg = 0x48004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x48004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x62000,
+ .enable_mask = BIT(10),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_boot_rom_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cfg_noc_ecpri_cc_ahb_clk = {
+ .halt_reg = 0x3e004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x3e004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x3e004,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_cfg_noc_ecpri_cc_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cfg_noc_usb3_prim_axi_clk = {
+ .halt_reg = 0x8401c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x8401c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x8401c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_cfg_noc_usb3_prim_axi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ddrss_ecpri_dma_clk = {
+ .halt_reg = 0x54030,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x54030,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x54030,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ddrss_ecpri_dma_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_aggre_noc_ecpri_dma_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_aon_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ecpri_ahb_clk = {
+ .halt_reg = 0x3a008,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x3a008,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x3a008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ecpri_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ecpri_cc_gpll0_clk_src = {
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x62010,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ecpri_cc_gpll0_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gpll0.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ecpri_cc_gpll1_even_clk_src = {
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x62010,
+ .enable_mask = BIT(1),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ecpri_cc_gpll1_even_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gpll1_out_even.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ecpri_cc_gpll2_even_clk_src = {
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x62010,
+ .enable_mask = BIT(2),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ecpri_cc_gpll2_even_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gpll2_out_even.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ecpri_cc_gpll3_clk_src = {
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x62010,
+ .enable_mask = BIT(3),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ecpri_cc_gpll3_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gpll3.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ecpri_cc_gpll4_clk_src = {
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x62010,
+ .enable_mask = BIT(4),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ecpri_cc_gpll4_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gpll4.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ecpri_cc_gpll5_even_clk_src = {
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x62010,
+ .enable_mask = BIT(5),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ecpri_cc_gpll5_even_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gpll5_out_even.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ecpri_xo_clk = {
+ .halt_reg = 0x3a004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3a004,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ecpri_xo_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_eth_100g_c2c_hm_apb_clk = {
+ .halt_reg = 0x39010,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x39010,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_eth_100g_c2c_hm_apb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_eth_100g_fh_hm_apb_0_clk = {
+ .halt_reg = 0x39004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x39004,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_eth_100g_fh_hm_apb_0_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_eth_100g_fh_hm_apb_1_clk = {
+ .halt_reg = 0x39008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x39008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_eth_100g_fh_hm_apb_1_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_eth_100g_fh_hm_apb_2_clk = {
+ .halt_reg = 0x3900c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3900c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_eth_100g_fh_hm_apb_2_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_eth_dbg_c2c_hm_apb_clk = {
+ .halt_reg = 0x39014,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x39014,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_eth_dbg_c2c_hm_apb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_eth_dbg_snoc_axi_clk = {
+ .halt_reg = 0x3901c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x3901c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x3901c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_eth_dbg_snoc_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gemnoc_pcie_qx_clk = {
+ .halt_reg = 0x5402c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x5402c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x62008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gemnoc_pcie_qx_clk",
+ .ops = &clk_branch2_aon_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gp1_clk = {
+ .halt_reg = 0x74000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x74000,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gp1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gp1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gp2_clk = {
+ .halt_reg = 0x75000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x75000,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gp2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gp2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gp3_clk = {
+ .halt_reg = 0x76000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x76000,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gp3_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gp3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_aux_clk = {
+ .halt_reg = 0x9d030,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x9d030,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x62000,
+ .enable_mask = BIT(29),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_0_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_cfg_ahb_clk = {
+ .halt_reg = 0x9d02c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x9d02c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x62000,
+ .enable_mask = BIT(28),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_cfg_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_clkref_en = {
+ .halt_reg = 0x9c004,
+ .halt_bit = 31,
+ .halt_check = BRANCH_HALT_ENABLE,
+ .clkr = {
+ .enable_reg = 0x9c004,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_clkref_en",
+ .ops = &clk_branch_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_mstr_axi_clk = {
+ .halt_reg = 0x9d024,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x9d024,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x62000,
+ .enable_mask = BIT(27),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_mstr_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_phy_aux_clk = {
+ .halt_reg = 0x9d038,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x9d038,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x62000,
+ .enable_mask = BIT(24),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_phy_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_0_phy_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_phy_rchng_clk = {
+ .halt_reg = 0x9d048,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x9d048,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x62000,
+ .enable_mask = BIT(23),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_phy_rchng_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_0_phy_rchng_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_pipe_clk = {
+ .halt_reg = 0x9d040,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x9d040,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x62000,
+ .enable_mask = BIT(30),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_pipe_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_0_pipe_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_slv_axi_clk = {
+ .halt_reg = 0x9d01c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x9d01c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x62000,
+ .enable_mask = BIT(26),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_slv_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_slv_q2a_axi_clk = {
+ .halt_reg = 0x9d018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x9d018,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x62000,
+ .enable_mask = BIT(25),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_slv_q2a_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pdm2_clk = {
+ .halt_reg = 0x4300c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4300c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pdm2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pdm2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pdm_ahb_clk = {
+ .halt_reg = 0x43004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x43004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x43004,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pdm_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pdm_xo4_clk = {
+ .halt_reg = 0x43008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x43008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pdm_xo4_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_anoc_pcie_clk = {
+ .halt_reg = 0x84044,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x84044,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x84044,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qmip_anoc_pcie_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_ecpri_dma0_clk = {
+ .halt_reg = 0x84038,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x84038,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x84038,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qmip_ecpri_dma0_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_ecpri_dma1_clk = {
+ .halt_reg = 0x8403c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x8403c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x8403c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qmip_ecpri_dma1_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_ecpri_gsi_clk = {
+ .halt_reg = 0x84040,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x84040,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x84040,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qmip_ecpri_gsi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_core_2x_clk = {
+ .halt_reg = 0x27018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x62008,
+ .enable_mask = BIT(9),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap0_core_2x_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_core_clk = {
+ .halt_reg = 0x2700c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x62008,
+ .enable_mask = BIT(8),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap0_core_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s0_clk = {
+ .halt_reg = 0x2714c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x62008,
+ .enable_mask = BIT(10),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap0_s0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s1_clk = {
+ .halt_reg = 0x27280,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x62008,
+ .enable_mask = BIT(11),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap0_s1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s2_clk = {
+ .halt_reg = 0x273b4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x62008,
+ .enable_mask = BIT(12),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap0_s2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s3_clk = {
+ .halt_reg = 0x274e8,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x62008,
+ .enable_mask = BIT(13),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap0_s3_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s4_clk = {
+ .halt_reg = 0x2761c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x62008,
+ .enable_mask = BIT(14),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap0_s4_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s4_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s5_clk = {
+ .halt_reg = 0x27750,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x62008,
+ .enable_mask = BIT(15),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap0_s5_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s5_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s6_clk = {
+ .halt_reg = 0x27884,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x62008,
+ .enable_mask = BIT(16),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap0_s6_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s6_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s7_clk = {
+ .halt_reg = 0x279b8,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x62008,
+ .enable_mask = BIT(17),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap0_s7_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s7_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_core_2x_clk = {
+ .halt_reg = 0x28018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x62008,
+ .enable_mask = BIT(18),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_core_2x_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_core_clk = {
+ .halt_reg = 0x2800c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x62008,
+ .enable_mask = BIT(19),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_core_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s0_clk = {
+ .halt_reg = 0x2814c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x62008,
+ .enable_mask = BIT(22),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_s0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s1_clk = {
+ .halt_reg = 0x28280,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x62008,
+ .enable_mask = BIT(23),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_s1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s2_clk = {
+ .halt_reg = 0x283b4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x62008,
+ .enable_mask = BIT(24),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_s2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s3_clk = {
+ .halt_reg = 0x284e8,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x62008,
+ .enable_mask = BIT(25),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_s3_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s4_clk = {
+ .halt_reg = 0x2861c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x62008,
+ .enable_mask = BIT(26),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_s4_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s4_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s5_clk = {
+ .halt_reg = 0x28750,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x62008,
+ .enable_mask = BIT(27),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_s5_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s5_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s6_clk = {
+ .halt_reg = 0x28884,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x62008,
+ .enable_mask = BIT(28),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_s6_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s6_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s7_clk = {
+ .halt_reg = 0x289b8,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x62008,
+ .enable_mask = BIT(29),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_s7_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s7_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_0_m_ahb_clk = {
+ .halt_reg = 0x27004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x27004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x62008,
+ .enable_mask = BIT(6),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_0_m_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_0_s_ahb_clk = {
+ .halt_reg = 0x27008,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x27008,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x62008,
+ .enable_mask = BIT(7),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_0_s_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_1_m_ahb_clk = {
+ .halt_reg = 0x28004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x28004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x62008,
+ .enable_mask = BIT(20),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_1_m_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_1_s_ahb_clk = {
+ .halt_reg = 0x28008,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x28008,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x62008,
+ .enable_mask = BIT(21),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_1_s_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc5_ahb_clk = {
+ .halt_reg = 0x3b00c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3b00c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sdcc5_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc5_apps_clk = {
+ .halt_reg = 0x3b004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3b004,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sdcc5_apps_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_sdcc5_apps_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc5_ice_core_clk = {
+ .halt_reg = 0x3b010,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3b010,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sdcc5_ice_core_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_sdcc5_ice_core_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sm_bus_ahb_clk = {
+ .halt_reg = 0x5b004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5b004,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sm_bus_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sm_bus_xo_clk = {
+ .halt_reg = 0x5b008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5b008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sm_bus_xo_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_sm_bus_xo_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_snoc_cnoc_gemnoc_pcie_qx_clk = {
+ .halt_reg = 0x9200c,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x9200c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x62000,
+ .enable_mask = BIT(11),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_snoc_cnoc_gemnoc_pcie_qx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_snoc_cnoc_gemnoc_pcie_south_qx_clk = {
+ .halt_reg = 0x92010,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x92010,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x62000,
+ .enable_mask = BIT(12),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_snoc_cnoc_gemnoc_pcie_south_qx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_snoc_cnoc_pcie_qx_clk = {
+ .halt_reg = 0x84030,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x84030,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_snoc_cnoc_pcie_qx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_snoc_pcie_sf_center_qx_clk = {
+ .halt_reg = 0x92014,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x92014,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x62000,
+ .enable_mask = BIT(19),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_snoc_pcie_sf_center_qx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_snoc_pcie_sf_south_qx_clk = {
+ .halt_reg = 0x92018,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x92018,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x62000,
+ .enable_mask = BIT(22),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_snoc_pcie_sf_south_qx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_tsc_cfg_ahb_clk = {
+ .halt_reg = 0x5700c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5700c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_tsc_cfg_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_tsc_cntr_clk = {
+ .halt_reg = 0x57004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x57004,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_tsc_cntr_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_tsc_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_tsc_etu_clk = {
+ .halt_reg = 0x57008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x57008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_tsc_etu_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_tsc_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb2_clkref_en = {
+ .halt_reg = 0x9c008,
+ .halt_bit = 31,
+ .halt_check = BRANCH_HALT_ENABLE,
+ .clkr = {
+ .enable_reg = 0x9c008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb2_clkref_en",
+ .ops = &clk_branch_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_prim_master_clk = {
+ .halt_reg = 0x49018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x49018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_prim_master_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_prim_mock_utmi_clk = {
+ .halt_reg = 0x49024,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x49024,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_prim_mock_utmi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_mock_utmi_postdiv_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_prim_sleep_clk = {
+ .halt_reg = 0x49020,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x49020,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_prim_sleep_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_prim_phy_aux_clk = {
+ .halt_reg = 0x49060,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x49060,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb3_prim_phy_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb3_prim_phy_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_prim_phy_com_aux_clk = {
+ .halt_reg = 0x49064,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x49064,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb3_prim_phy_com_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb3_prim_phy_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_prim_phy_pipe_clk = {
+ .halt_reg = 0x49068,
+ .halt_check = BRANCH_HALT_DELAY,
+ .hwcg_reg = 0x49068,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x49068,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb3_prim_phy_pipe_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb3_prim_phy_pipe_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_regmap *gcc_qdu1000_clocks[] = {
+ [GCC_AGGRE_NOC_ECPRI_DMA_CLK] = &gcc_aggre_noc_ecpri_dma_clk.clkr,
+ [GCC_AGGRE_NOC_ECPRI_DMA_CLK_SRC] = &gcc_aggre_noc_ecpri_dma_clk_src.clkr,
+ [GCC_AGGRE_NOC_ECPRI_GSI_CLK_SRC] = &gcc_aggre_noc_ecpri_gsi_clk_src.clkr,
+ [GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr,
+ [GCC_CFG_NOC_ECPRI_CC_AHB_CLK] = &gcc_cfg_noc_ecpri_cc_ahb_clk.clkr,
+ [GCC_CFG_NOC_USB3_PRIM_AXI_CLK] = &gcc_cfg_noc_usb3_prim_axi_clk.clkr,
+ [GCC_DDRSS_ECPRI_DMA_CLK] = &gcc_ddrss_ecpri_dma_clk.clkr,
+ [GCC_ECPRI_AHB_CLK] = &gcc_ecpri_ahb_clk.clkr,
+ [GCC_ECPRI_CC_GPLL0_CLK_SRC] = &gcc_ecpri_cc_gpll0_clk_src.clkr,
+ [GCC_ECPRI_CC_GPLL1_EVEN_CLK_SRC] = &gcc_ecpri_cc_gpll1_even_clk_src.clkr,
+ [GCC_ECPRI_CC_GPLL2_EVEN_CLK_SRC] = &gcc_ecpri_cc_gpll2_even_clk_src.clkr,
+ [GCC_ECPRI_CC_GPLL3_CLK_SRC] = &gcc_ecpri_cc_gpll3_clk_src.clkr,
+ [GCC_ECPRI_CC_GPLL4_CLK_SRC] = &gcc_ecpri_cc_gpll4_clk_src.clkr,
+ [GCC_ECPRI_CC_GPLL5_EVEN_CLK_SRC] = &gcc_ecpri_cc_gpll5_even_clk_src.clkr,
+ [GCC_ECPRI_XO_CLK] = &gcc_ecpri_xo_clk.clkr,
+ [GCC_ETH_DBG_SNOC_AXI_CLK] = &gcc_eth_dbg_snoc_axi_clk.clkr,
+ [GCC_GEMNOC_PCIE_QX_CLK] = &gcc_gemnoc_pcie_qx_clk.clkr,
+ [GCC_GP1_CLK] = &gcc_gp1_clk.clkr,
+ [GCC_GP1_CLK_SRC] = &gcc_gp1_clk_src.clkr,
+ [GCC_GP2_CLK] = &gcc_gp2_clk.clkr,
+ [GCC_GP2_CLK_SRC] = &gcc_gp2_clk_src.clkr,
+ [GCC_GP3_CLK] = &gcc_gp3_clk.clkr,
+ [GCC_GP3_CLK_SRC] = &gcc_gp3_clk_src.clkr,
+ [GCC_GPLL0] = &gcc_gpll0.clkr,
+ [GCC_GPLL0_OUT_EVEN] = &gcc_gpll0_out_even.clkr,
+ [GCC_GPLL1] = &gcc_gpll1.clkr,
+ [GCC_GPLL2] = &gcc_gpll2.clkr,
+ [GCC_GPLL2_OUT_EVEN] = &gcc_gpll2_out_even.clkr,
+ [GCC_GPLL3] = &gcc_gpll3.clkr,
+ [GCC_GPLL4] = &gcc_gpll4.clkr,
+ [GCC_GPLL5] = &gcc_gpll5.clkr,
+ [GCC_GPLL5_OUT_EVEN] = &gcc_gpll5_out_even.clkr,
+ [GCC_GPLL6] = &gcc_gpll6.clkr,
+ [GCC_GPLL7] = &gcc_gpll7.clkr,
+ [GCC_GPLL8] = &gcc_gpll8.clkr,
+ [GCC_PCIE_0_AUX_CLK] = &gcc_pcie_0_aux_clk.clkr,
+ [GCC_PCIE_0_AUX_CLK_SRC] = &gcc_pcie_0_aux_clk_src.clkr,
+ [GCC_PCIE_0_CFG_AHB_CLK] = &gcc_pcie_0_cfg_ahb_clk.clkr,
+ [GCC_PCIE_0_CLKREF_EN] = &gcc_pcie_0_clkref_en.clkr,
+ [GCC_PCIE_0_MSTR_AXI_CLK] = &gcc_pcie_0_mstr_axi_clk.clkr,
+ [GCC_PCIE_0_PHY_AUX_CLK] = &gcc_pcie_0_phy_aux_clk.clkr,
+ [GCC_PCIE_0_PHY_RCHNG_CLK] = &gcc_pcie_0_phy_rchng_clk.clkr,
+ [GCC_PCIE_0_PHY_RCHNG_CLK_SRC] = &gcc_pcie_0_phy_rchng_clk_src.clkr,
+ [GCC_PCIE_0_PIPE_CLK] = &gcc_pcie_0_pipe_clk.clkr,
+ [GCC_PCIE_0_SLV_AXI_CLK] = &gcc_pcie_0_slv_axi_clk.clkr,
+ [GCC_PCIE_0_SLV_Q2A_AXI_CLK] = &gcc_pcie_0_slv_q2a_axi_clk.clkr,
+ [GCC_PDM2_CLK] = &gcc_pdm2_clk.clkr,
+ [GCC_PDM2_CLK_SRC] = &gcc_pdm2_clk_src.clkr,
+ [GCC_PDM_AHB_CLK] = &gcc_pdm_ahb_clk.clkr,
+ [GCC_PDM_XO4_CLK] = &gcc_pdm_xo4_clk.clkr,
+ [GCC_QMIP_ANOC_PCIE_CLK] = &gcc_qmip_anoc_pcie_clk.clkr,
+ [GCC_QMIP_ECPRI_DMA0_CLK] = &gcc_qmip_ecpri_dma0_clk.clkr,
+ [GCC_QMIP_ECPRI_DMA1_CLK] = &gcc_qmip_ecpri_dma1_clk.clkr,
+ [GCC_QMIP_ECPRI_GSI_CLK] = &gcc_qmip_ecpri_gsi_clk.clkr,
+ [GCC_QUPV3_WRAP0_CORE_2X_CLK] = &gcc_qupv3_wrap0_core_2x_clk.clkr,
+ [GCC_QUPV3_WRAP0_CORE_CLK] = &gcc_qupv3_wrap0_core_clk.clkr,
+ [GCC_QUPV3_WRAP0_S0_CLK] = &gcc_qupv3_wrap0_s0_clk.clkr,
+ [GCC_QUPV3_WRAP0_S0_CLK_SRC] = &gcc_qupv3_wrap0_s0_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S1_CLK] = &gcc_qupv3_wrap0_s1_clk.clkr,
+ [GCC_QUPV3_WRAP0_S1_CLK_SRC] = &gcc_qupv3_wrap0_s1_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S2_CLK] = &gcc_qupv3_wrap0_s2_clk.clkr,
+ [GCC_QUPV3_WRAP0_S2_CLK_SRC] = &gcc_qupv3_wrap0_s2_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S3_CLK] = &gcc_qupv3_wrap0_s3_clk.clkr,
+ [GCC_QUPV3_WRAP0_S3_CLK_SRC] = &gcc_qupv3_wrap0_s3_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S4_CLK] = &gcc_qupv3_wrap0_s4_clk.clkr,
+ [GCC_QUPV3_WRAP0_S4_CLK_SRC] = &gcc_qupv3_wrap0_s4_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S5_CLK] = &gcc_qupv3_wrap0_s5_clk.clkr,
+ [GCC_QUPV3_WRAP0_S5_CLK_SRC] = &gcc_qupv3_wrap0_s5_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S6_CLK] = &gcc_qupv3_wrap0_s6_clk.clkr,
+ [GCC_QUPV3_WRAP0_S6_CLK_SRC] = &gcc_qupv3_wrap0_s6_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S7_CLK] = &gcc_qupv3_wrap0_s7_clk.clkr,
+ [GCC_QUPV3_WRAP0_S7_CLK_SRC] = &gcc_qupv3_wrap0_s7_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_CORE_2X_CLK] = &gcc_qupv3_wrap1_core_2x_clk.clkr,
+ [GCC_QUPV3_WRAP1_CORE_CLK] = &gcc_qupv3_wrap1_core_clk.clkr,
+ [GCC_QUPV3_WRAP1_S0_CLK] = &gcc_qupv3_wrap1_s0_clk.clkr,
+ [GCC_QUPV3_WRAP1_S0_CLK_SRC] = &gcc_qupv3_wrap1_s0_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S1_CLK] = &gcc_qupv3_wrap1_s1_clk.clkr,
+ [GCC_QUPV3_WRAP1_S1_CLK_SRC] = &gcc_qupv3_wrap1_s1_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S2_CLK] = &gcc_qupv3_wrap1_s2_clk.clkr,
+ [GCC_QUPV3_WRAP1_S2_CLK_SRC] = &gcc_qupv3_wrap1_s2_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S3_CLK] = &gcc_qupv3_wrap1_s3_clk.clkr,
+ [GCC_QUPV3_WRAP1_S3_CLK_SRC] = &gcc_qupv3_wrap1_s3_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S4_CLK] = &gcc_qupv3_wrap1_s4_clk.clkr,
+ [GCC_QUPV3_WRAP1_S4_CLK_SRC] = &gcc_qupv3_wrap1_s4_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S5_CLK] = &gcc_qupv3_wrap1_s5_clk.clkr,
+ [GCC_QUPV3_WRAP1_S5_CLK_SRC] = &gcc_qupv3_wrap1_s5_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S6_CLK] = &gcc_qupv3_wrap1_s6_clk.clkr,
+ [GCC_QUPV3_WRAP1_S6_CLK_SRC] = &gcc_qupv3_wrap1_s6_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S7_CLK] = &gcc_qupv3_wrap1_s7_clk.clkr,
+ [GCC_QUPV3_WRAP1_S7_CLK_SRC] = &gcc_qupv3_wrap1_s7_clk_src.clkr,
+ [GCC_QUPV3_WRAP_0_M_AHB_CLK] = &gcc_qupv3_wrap_0_m_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP_0_S_AHB_CLK] = &gcc_qupv3_wrap_0_s_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP_1_M_AHB_CLK] = &gcc_qupv3_wrap_1_m_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP_1_S_AHB_CLK] = &gcc_qupv3_wrap_1_s_ahb_clk.clkr,
+ [GCC_SDCC5_AHB_CLK] = &gcc_sdcc5_ahb_clk.clkr,
+ [GCC_SDCC5_APPS_CLK] = &gcc_sdcc5_apps_clk.clkr,
+ [GCC_SDCC5_APPS_CLK_SRC] = &gcc_sdcc5_apps_clk_src.clkr,
+ [GCC_SDCC5_ICE_CORE_CLK] = &gcc_sdcc5_ice_core_clk.clkr,
+ [GCC_SDCC5_ICE_CORE_CLK_SRC] = &gcc_sdcc5_ice_core_clk_src.clkr,
+ [GCC_SM_BUS_AHB_CLK] = &gcc_sm_bus_ahb_clk.clkr,
+ [GCC_SM_BUS_XO_CLK] = &gcc_sm_bus_xo_clk.clkr,
+ [GCC_SM_BUS_XO_CLK_SRC] = &gcc_sm_bus_xo_clk_src.clkr,
+ [GCC_SNOC_CNOC_GEMNOC_PCIE_QX_CLK] = &gcc_snoc_cnoc_gemnoc_pcie_qx_clk.clkr,
+ [GCC_SNOC_CNOC_GEMNOC_PCIE_SOUTH_QX_CLK] = &gcc_snoc_cnoc_gemnoc_pcie_south_qx_clk.clkr,
+ [GCC_SNOC_CNOC_PCIE_QX_CLK] = &gcc_snoc_cnoc_pcie_qx_clk.clkr,
+ [GCC_SNOC_PCIE_SF_CENTER_QX_CLK] = &gcc_snoc_pcie_sf_center_qx_clk.clkr,
+ [GCC_SNOC_PCIE_SF_SOUTH_QX_CLK] = &gcc_snoc_pcie_sf_south_qx_clk.clkr,
+ [GCC_TSC_CFG_AHB_CLK] = &gcc_tsc_cfg_ahb_clk.clkr,
+ [GCC_TSC_CLK_SRC] = &gcc_tsc_clk_src.clkr,
+ [GCC_TSC_CNTR_CLK] = &gcc_tsc_cntr_clk.clkr,
+ [GCC_TSC_ETU_CLK] = &gcc_tsc_etu_clk.clkr,
+ [GCC_USB2_CLKREF_EN] = &gcc_usb2_clkref_en.clkr,
+ [GCC_USB30_PRIM_MASTER_CLK] = &gcc_usb30_prim_master_clk.clkr,
+ [GCC_USB30_PRIM_MASTER_CLK_SRC] = &gcc_usb30_prim_master_clk_src.clkr,
+ [GCC_USB30_PRIM_MOCK_UTMI_CLK] = &gcc_usb30_prim_mock_utmi_clk.clkr,
+ [GCC_USB30_PRIM_MOCK_UTMI_CLK_SRC] = &gcc_usb30_prim_mock_utmi_clk_src.clkr,
+ [GCC_USB30_PRIM_MOCK_UTMI_POSTDIV_CLK_SRC] = &gcc_usb30_prim_mock_utmi_postdiv_clk_src.clkr,
+ [GCC_USB30_PRIM_SLEEP_CLK] = &gcc_usb30_prim_sleep_clk.clkr,
+ [GCC_USB3_PRIM_PHY_AUX_CLK] = &gcc_usb3_prim_phy_aux_clk.clkr,
+ [GCC_USB3_PRIM_PHY_AUX_CLK_SRC] = &gcc_usb3_prim_phy_aux_clk_src.clkr,
+ [GCC_USB3_PRIM_PHY_COM_AUX_CLK] = &gcc_usb3_prim_phy_com_aux_clk.clkr,
+ [GCC_USB3_PRIM_PHY_PIPE_CLK] = &gcc_usb3_prim_phy_pipe_clk.clkr,
+ [GCC_USB3_PRIM_PHY_PIPE_CLK_SRC] = &gcc_usb3_prim_phy_pipe_clk_src.clkr,
+ [GCC_ETH_100G_C2C_HM_APB_CLK] = &gcc_eth_100g_c2c_hm_apb_clk.clkr,
+ [GCC_ETH_100G_FH_HM_APB_0_CLK] = &gcc_eth_100g_fh_hm_apb_0_clk.clkr,
+ [GCC_ETH_100G_FH_HM_APB_1_CLK] = &gcc_eth_100g_fh_hm_apb_1_clk.clkr,
+ [GCC_ETH_100G_FH_HM_APB_2_CLK] = &gcc_eth_100g_fh_hm_apb_2_clk.clkr,
+ [GCC_ETH_DBG_C2C_HM_APB_CLK] = &gcc_eth_dbg_c2c_hm_apb_clk.clkr,
+ [GCC_AGGRE_NOC_ECPRI_GSI_CLK] = &gcc_aggre_noc_ecpri_gsi_clk.clkr,
+ [GCC_PCIE_0_PHY_AUX_CLK_SRC] = &gcc_pcie_0_phy_aux_clk_src.clkr,
+ [GCC_PCIE_0_PIPE_CLK_SRC] = &gcc_pcie_0_pipe_clk_src.clkr,
+};
+
+static const struct qcom_reset_map gcc_qdu1000_resets[] = {
+ [GCC_ECPRI_CC_BCR] = { 0x3e000 },
+ [GCC_ECPRI_SS_BCR] = { 0x3a000 },
+ [GCC_ETH_WRAPPER_BCR] = { 0x39000 },
+ [GCC_PCIE_0_BCR] = { 0x9d000 },
+ [GCC_PCIE_0_LINK_DOWN_BCR] = { 0x9e014 },
+ [GCC_PCIE_0_NOCSR_COM_PHY_BCR] = { 0x9e020 },
+ [GCC_PCIE_0_PHY_BCR] = { 0x7c000 },
+ [GCC_PCIE_0_PHY_NOCSR_COM_PHY_BCR] = { 0x9e000 },
+ [GCC_PCIE_PHY_CFG_AHB_BCR] = { 0x7f00c },
+ [GCC_PCIE_PHY_COM_BCR] = { 0x7f010 },
+ [GCC_PDM_BCR] = { 0x43000 },
+ [GCC_QUPV3_WRAPPER_0_BCR] = { 0x27000 },
+ [GCC_QUPV3_WRAPPER_1_BCR] = { 0x28000 },
+ [GCC_QUSB2PHY_PRIM_BCR] = { 0x22000 },
+ [GCC_QUSB2PHY_SEC_BCR] = { 0x22004 },
+ [GCC_SDCC5_BCR] = { 0x3b000 },
+ [GCC_TSC_BCR] = { 0x57000 },
+ [GCC_USB30_PRIM_BCR] = { 0x49000 },
+ [GCC_USB3_DP_PHY_PRIM_BCR] = { 0x60008 },
+ [GCC_USB3_DP_PHY_SEC_BCR] = { 0x60014 },
+ [GCC_USB3_PHY_PRIM_BCR] = { 0x60000 },
+ [GCC_USB3_PHY_SEC_BCR] = { 0x6000c },
+ [GCC_USB3PHY_PHY_PRIM_BCR] = { 0x60004 },
+ [GCC_USB3PHY_PHY_SEC_BCR] = { 0x60010 },
+ [GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x7a000 },
+};
+
+static const struct clk_rcg_dfs_data gcc_dfs_clocks[] = {
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s0_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s1_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s2_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s3_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s4_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s5_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s6_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s7_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s0_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s1_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s2_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s3_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s4_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s5_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s6_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s7_clk_src),
+};
+
+static const struct regmap_config gcc_qdu1000_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x1f41f0,
+ .fast_io = true,
+};
+
+static const struct qcom_cc_desc gcc_qdu1000_desc = {
+ .config = &gcc_qdu1000_regmap_config,
+ .clks = gcc_qdu1000_clocks,
+ .num_clks = ARRAY_SIZE(gcc_qdu1000_clocks),
+ .resets = gcc_qdu1000_resets,
+ .num_resets = ARRAY_SIZE(gcc_qdu1000_resets),
+};
+
+static const struct of_device_id gcc_qdu1000_match_table[] = {
+ { .compatible = "qcom,qdu1000-gcc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, gcc_qdu1000_match_table);
+
+static int gcc_qdu1000_probe(struct platform_device *pdev)
+{
+ struct regmap *regmap;
+ int ret;
+
+ regmap = qcom_cc_map(pdev, &gcc_qdu1000_desc);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ /* Update FORCE_MEM_CORE_ON for gcc_pcie_0_mstr_axi_clk */
+ regmap_update_bits(regmap, 0x9d024, BIT(14), BIT(14));
+
+ ret = qcom_cc_register_rcg_dfs(regmap, gcc_dfs_clocks,
+ ARRAY_SIZE(gcc_dfs_clocks));
+ if (ret)
+ return ret;
+
+ ret = qcom_cc_really_probe(pdev, &gcc_qdu1000_desc, regmap);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "Failed to register GCC clocks\n");
+
+ return ret;
+}
+
+static struct platform_driver gcc_qdu1000_driver = {
+ .probe = gcc_qdu1000_probe,
+ .driver = {
+ .name = "gcc-qdu1000",
+ .of_match_table = gcc_qdu1000_match_table,
+ },
+};
+
+static int __init gcc_qdu1000_init(void)
+{
+ return platform_driver_register(&gcc_qdu1000_driver);
+}
+subsys_initcall(gcc_qdu1000_init);
+
+static void __exit gcc_qdu1000_exit(void)
+{
+ platform_driver_unregister(&gcc_qdu1000_driver);
+}
+module_exit(gcc_qdu1000_exit);
+
+MODULE_DESCRIPTION("QTI GCC QDU1000 Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/qcom/gcc-sa8775p.c b/drivers/clk/qcom/gcc-sa8775p.c
new file mode 100644
index 000000000000..bb94ff367abd
--- /dev/null
+++ b/drivers/clk/qcom/gcc-sa8775p.c
@@ -0,0 +1,4785 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2023, Linaro Limited
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,sa8775p-gcc.h>
+
+#include "clk-alpha-pll.h"
+#include "clk-branch.h"
+#include "clk-rcg.h"
+#include "clk-regmap.h"
+#include "clk-regmap-divider.h"
+#include "clk-regmap-mux.h"
+#include "clk-regmap-phy-mux.h"
+#include "common.h"
+#include "gdsc.h"
+#include "reset.h"
+
+/* Need to match the order of clocks in DT binding */
+enum {
+ DT_BI_TCXO,
+ DT_SLEEP_CLK,
+ DT_UFS_PHY_RX_SYMBOL_0_CLK,
+ DT_UFS_PHY_RX_SYMBOL_1_CLK,
+ DT_UFS_PHY_TX_SYMBOL_0_CLK,
+ DT_UFS_CARD_RX_SYMBOL_0_CLK,
+ DT_UFS_CARD_RX_SYMBOL_1_CLK,
+ DT_UFS_CARD_TX_SYMBOL_0_CLK,
+ DT_USB3_PHY_WRAPPER_GCC_USB30_PRIM_PIPE_CLK,
+ DT_USB3_PHY_WRAPPER_GCC_USB30_SEC_PIPE_CLK,
+ DT_PCIE_0_PIPE_CLK,
+ DT_PCIE_1_PIPE_CLK,
+ DT_PCIE_PHY_AUX_CLK,
+ DT_RXC0_REF_CLK,
+ DT_RXC1_REF_CLK,
+};
+
+enum {
+ P_BI_TCXO,
+ P_GCC_GPLL0_OUT_EVEN,
+ P_GCC_GPLL0_OUT_MAIN,
+ P_GCC_GPLL1_OUT_MAIN,
+ P_GCC_GPLL4_OUT_MAIN,
+ P_GCC_GPLL5_OUT_MAIN,
+ P_GCC_GPLL7_OUT_MAIN,
+ P_GCC_GPLL9_OUT_MAIN,
+ P_PCIE_0_PIPE_CLK,
+ P_PCIE_1_PIPE_CLK,
+ P_PCIE_PHY_AUX_CLK,
+ P_RXC0_REF_CLK,
+ P_RXC1_REF_CLK,
+ P_SLEEP_CLK,
+ P_UFS_CARD_RX_SYMBOL_0_CLK,
+ P_UFS_CARD_RX_SYMBOL_1_CLK,
+ P_UFS_CARD_TX_SYMBOL_0_CLK,
+ P_UFS_PHY_RX_SYMBOL_0_CLK,
+ P_UFS_PHY_RX_SYMBOL_1_CLK,
+ P_UFS_PHY_TX_SYMBOL_0_CLK,
+ P_USB3_PHY_WRAPPER_GCC_USB30_PRIM_PIPE_CLK,
+ P_USB3_PHY_WRAPPER_GCC_USB30_SEC_PIPE_CLK,
+};
+
+static const struct clk_parent_data gcc_parent_data_tcxo = { .index = DT_BI_TCXO };
+
+static struct clk_alpha_pll gcc_gpll0 = {
+ .offset = 0x0,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],
+ .clkr = {
+ .enable_reg = 0x4b028,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_gpll0",
+ .parent_data = &gcc_parent_data_tcxo,
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_lucid_evo_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_gcc_gpll0_out_even[] = {
+ { 0x1, 2 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv gcc_gpll0_out_even = {
+ .offset = 0x0,
+ .post_div_shift = 10,
+ .post_div_table = post_div_table_gcc_gpll0_out_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_gcc_gpll0_out_even),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],
+ .clkr.hw.init = &(const struct clk_init_data){
+ .name = "gcc_gpll0_out_even",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_gpll0.clkr.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_lucid_evo_ops,
+ },
+};
+
+static struct clk_alpha_pll gcc_gpll1 = {
+ .offset = 0x1000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],
+ .clkr = {
+ .enable_reg = 0x4b028,
+ .enable_mask = BIT(1),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_gpll1",
+ .parent_data = &gcc_parent_data_tcxo,
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_lucid_evo_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll gcc_gpll4 = {
+ .offset = 0x4000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],
+ .clkr = {
+ .enable_reg = 0x4b028,
+ .enable_mask = BIT(4),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_gpll4",
+ .parent_data = &gcc_parent_data_tcxo,
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_lucid_evo_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll gcc_gpll5 = {
+ .offset = 0x5000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],
+ .clkr = {
+ .enable_reg = 0x4b028,
+ .enable_mask = BIT(5),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_gpll5",
+ .parent_data = &gcc_parent_data_tcxo,
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_lucid_evo_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll gcc_gpll7 = {
+ .offset = 0x7000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],
+ .clkr = {
+ .enable_reg = 0x4b028,
+ .enable_mask = BIT(7),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_gpll7",
+ .parent_data = &gcc_parent_data_tcxo,
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_lucid_evo_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll gcc_gpll9 = {
+ .offset = 0x9000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],
+ .clkr = {
+ .enable_reg = 0x4b028,
+ .enable_mask = BIT(9),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_gpll9",
+ .parent_data = &gcc_parent_data_tcxo,
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_lucid_evo_ops,
+ },
+ },
+};
+
+static const struct parent_map gcc_parent_map_0[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_GPLL0_OUT_MAIN, 1 },
+ { P_GCC_GPLL0_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_0[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gcc_gpll0.clkr.hw },
+ { .hw = &gcc_gpll0_out_even.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_1[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_GPLL0_OUT_MAIN, 1 },
+ { P_GCC_GPLL4_OUT_MAIN, 5 },
+ { P_GCC_GPLL0_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_1[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gcc_gpll0.clkr.hw },
+ { .hw = &gcc_gpll4.clkr.hw },
+ { .hw = &gcc_gpll0_out_even.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_2[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_GPLL0_OUT_MAIN, 1 },
+ { P_SLEEP_CLK, 5 },
+ { P_GCC_GPLL0_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_2[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gcc_gpll0.clkr.hw },
+ { .index = DT_SLEEP_CLK },
+ { .hw = &gcc_gpll0_out_even.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_3[] = {
+ { P_BI_TCXO, 0 },
+ { P_SLEEP_CLK, 5 },
+};
+
+static const struct clk_parent_data gcc_parent_data_3[] = {
+ { .index = DT_BI_TCXO },
+ { .index = DT_SLEEP_CLK },
+};
+
+static const struct parent_map gcc_parent_map_4[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_GPLL0_OUT_MAIN, 1 },
+ { P_GCC_GPLL1_OUT_MAIN, 4 },
+ { P_GCC_GPLL4_OUT_MAIN, 5 },
+ { P_GCC_GPLL0_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_4[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gcc_gpll0.clkr.hw },
+ { .hw = &gcc_gpll1.clkr.hw },
+ { .hw = &gcc_gpll4.clkr.hw },
+ { .hw = &gcc_gpll0_out_even.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_5[] = {
+ { P_BI_TCXO, 0 },
+};
+
+static const struct clk_parent_data gcc_parent_data_5[] = {
+ { .index = DT_BI_TCXO },
+};
+
+static const struct parent_map gcc_parent_map_6[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_GPLL7_OUT_MAIN, 2 },
+ { P_GCC_GPLL4_OUT_MAIN, 5 },
+ { P_GCC_GPLL0_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_6[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gcc_gpll7.clkr.hw },
+ { .hw = &gcc_gpll4.clkr.hw },
+ { .hw = &gcc_gpll0_out_even.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_7[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_GPLL7_OUT_MAIN, 2 },
+ { P_RXC0_REF_CLK, 3 },
+ { P_GCC_GPLL0_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_7[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gcc_gpll7.clkr.hw },
+ { .index = DT_RXC0_REF_CLK },
+ { .hw = &gcc_gpll0_out_even.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_8[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_GPLL7_OUT_MAIN, 2 },
+ { P_RXC1_REF_CLK, 3 },
+ { P_GCC_GPLL0_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_8[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gcc_gpll7.clkr.hw },
+ { .index = DT_RXC1_REF_CLK },
+ { .hw = &gcc_gpll0_out_even.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_9[] = {
+ { P_PCIE_PHY_AUX_CLK, 1 },
+ { P_BI_TCXO, 2 },
+};
+
+static const struct clk_parent_data gcc_parent_data_9[] = {
+ { .index = DT_PCIE_PHY_AUX_CLK },
+ { .index = DT_BI_TCXO },
+};
+
+static const struct parent_map gcc_parent_map_11[] = {
+ { P_PCIE_PHY_AUX_CLK, 1 },
+ { P_BI_TCXO, 2 },
+};
+
+static const struct clk_parent_data gcc_parent_data_11[] = {
+ { .index = DT_PCIE_PHY_AUX_CLK },
+ { .index = DT_BI_TCXO },
+};
+
+static const struct parent_map gcc_parent_map_13[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_GPLL0_OUT_MAIN, 1 },
+ { P_GCC_GPLL9_OUT_MAIN, 2 },
+ { P_GCC_GPLL4_OUT_MAIN, 5 },
+ { P_GCC_GPLL0_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_13[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gcc_gpll0.clkr.hw },
+ { .hw = &gcc_gpll9.clkr.hw },
+ { .hw = &gcc_gpll4.clkr.hw },
+ { .hw = &gcc_gpll0_out_even.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_14[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_GPLL0_OUT_MAIN, 1 },
+};
+
+static const struct clk_parent_data gcc_parent_data_14[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gcc_gpll0.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_15[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_GPLL7_OUT_MAIN, 2 },
+ { P_GCC_GPLL5_OUT_MAIN, 3 },
+ { P_GCC_GPLL4_OUT_MAIN, 5 },
+ { P_GCC_GPLL0_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_15[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gcc_gpll7.clkr.hw },
+ { .hw = &gcc_gpll5.clkr.hw },
+ { .hw = &gcc_gpll4.clkr.hw },
+ { .hw = &gcc_gpll0_out_even.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_16[] = {
+ { P_UFS_CARD_RX_SYMBOL_0_CLK, 0 },
+ { P_BI_TCXO, 2 },
+};
+
+static const struct clk_parent_data gcc_parent_data_16[] = {
+ { .index = DT_UFS_CARD_RX_SYMBOL_0_CLK },
+ { .index = DT_BI_TCXO },
+};
+
+static const struct parent_map gcc_parent_map_17[] = {
+ { P_UFS_CARD_RX_SYMBOL_1_CLK, 0 },
+ { P_BI_TCXO, 2 },
+};
+
+static const struct clk_parent_data gcc_parent_data_17[] = {
+ { .index = DT_UFS_CARD_RX_SYMBOL_1_CLK },
+ { .index = DT_BI_TCXO },
+};
+
+static const struct parent_map gcc_parent_map_18[] = {
+ { P_UFS_CARD_TX_SYMBOL_0_CLK, 0 },
+ { P_BI_TCXO, 2 },
+};
+
+static const struct clk_parent_data gcc_parent_data_18[] = {
+ { .index = DT_UFS_CARD_TX_SYMBOL_0_CLK },
+ { .index = DT_BI_TCXO },
+};
+
+static const struct parent_map gcc_parent_map_19[] = {
+ { P_UFS_PHY_RX_SYMBOL_0_CLK, 0 },
+ { P_BI_TCXO, 2 },
+};
+
+static const struct clk_parent_data gcc_parent_data_19[] = {
+ { .index = DT_UFS_PHY_RX_SYMBOL_0_CLK },
+ { .index = DT_BI_TCXO },
+};
+
+static const struct parent_map gcc_parent_map_20[] = {
+ { P_UFS_PHY_RX_SYMBOL_1_CLK, 0 },
+ { P_BI_TCXO, 2 },
+};
+
+static const struct clk_parent_data gcc_parent_data_20[] = {
+ { .index = DT_UFS_PHY_RX_SYMBOL_1_CLK },
+ { .index = DT_BI_TCXO },
+};
+
+static const struct parent_map gcc_parent_map_21[] = {
+ { P_UFS_PHY_TX_SYMBOL_0_CLK, 0 },
+ { P_BI_TCXO, 2 },
+};
+
+static const struct clk_parent_data gcc_parent_data_21[] = {
+ { .index = DT_UFS_PHY_TX_SYMBOL_0_CLK },
+ { .index = DT_BI_TCXO },
+};
+
+static const struct parent_map gcc_parent_map_22[] = {
+ { P_USB3_PHY_WRAPPER_GCC_USB30_PRIM_PIPE_CLK, 0 },
+ { P_BI_TCXO, 2 },
+};
+
+static const struct clk_parent_data gcc_parent_data_22[] = {
+ { .index = DT_USB3_PHY_WRAPPER_GCC_USB30_PRIM_PIPE_CLK },
+ { .index = DT_BI_TCXO },
+};
+
+static const struct parent_map gcc_parent_map_23[] = {
+ { P_USB3_PHY_WRAPPER_GCC_USB30_SEC_PIPE_CLK, 0 },
+ { P_BI_TCXO, 2 },
+};
+
+static const struct clk_parent_data gcc_parent_data_23[] = {
+ { .index = DT_USB3_PHY_WRAPPER_GCC_USB30_SEC_PIPE_CLK },
+ { .index = DT_BI_TCXO },
+};
+
+static struct clk_regmap_mux gcc_pcie_0_phy_aux_clk_src = {
+ .reg = 0xa9074,
+ .shift = 0,
+ .width = 2,
+ .parent_map = gcc_parent_map_9,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_pcie_0_phy_aux_clk_src",
+ .parent_data = gcc_parent_data_9,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_9),
+ .ops = &clk_regmap_mux_closest_ops,
+ },
+ },
+};
+
+static struct clk_regmap_phy_mux gcc_pcie_0_pipe_clk_src = {
+ .reg = 0xa906c,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_pcie_0_pipe_clk_src",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_PCIE_0_PIPE_CLK,
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_phy_mux_ops,
+ },
+ },
+};
+
+static struct clk_regmap_mux gcc_pcie_1_phy_aux_clk_src = {
+ .reg = 0x77074,
+ .shift = 0,
+ .width = 2,
+ .parent_map = gcc_parent_map_11,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_pcie_1_phy_aux_clk_src",
+ .parent_data = gcc_parent_data_11,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_11),
+ .ops = &clk_regmap_mux_closest_ops,
+ },
+ },
+};
+
+static struct clk_regmap_phy_mux gcc_pcie_1_pipe_clk_src = {
+ .reg = 0x7706c,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_pcie_1_pipe_clk_src",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_PCIE_1_PIPE_CLK,
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_phy_mux_ops,
+ },
+ },
+};
+
+static struct clk_regmap_mux gcc_ufs_card_rx_symbol_0_clk_src = {
+ .reg = 0x81060,
+ .shift = 0,
+ .width = 2,
+ .parent_map = gcc_parent_map_16,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_ufs_card_rx_symbol_0_clk_src",
+ .parent_data = gcc_parent_data_16,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_16),
+ .ops = &clk_regmap_mux_closest_ops,
+ },
+ },
+};
+
+static struct clk_regmap_mux gcc_ufs_card_rx_symbol_1_clk_src = {
+ .reg = 0x810d0,
+ .shift = 0,
+ .width = 2,
+ .parent_map = gcc_parent_map_17,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_ufs_card_rx_symbol_1_clk_src",
+ .parent_data = gcc_parent_data_17,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_17),
+ .ops = &clk_regmap_mux_closest_ops,
+ },
+ },
+};
+
+static struct clk_regmap_mux gcc_ufs_card_tx_symbol_0_clk_src = {
+ .reg = 0x81050,
+ .shift = 0,
+ .width = 2,
+ .parent_map = gcc_parent_map_18,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_ufs_card_tx_symbol_0_clk_src",
+ .parent_data = gcc_parent_data_18,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_18),
+ .ops = &clk_regmap_mux_closest_ops,
+ },
+ },
+};
+
+static struct clk_regmap_mux gcc_ufs_phy_rx_symbol_0_clk_src = {
+ .reg = 0x83060,
+ .shift = 0,
+ .width = 2,
+ .parent_map = gcc_parent_map_19,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_ufs_phy_rx_symbol_0_clk_src",
+ .parent_data = gcc_parent_data_19,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_19),
+ .ops = &clk_regmap_mux_closest_ops,
+ },
+ },
+};
+
+static struct clk_regmap_mux gcc_ufs_phy_rx_symbol_1_clk_src = {
+ .reg = 0x830d0,
+ .shift = 0,
+ .width = 2,
+ .parent_map = gcc_parent_map_20,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_ufs_phy_rx_symbol_1_clk_src",
+ .parent_data = gcc_parent_data_20,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_20),
+ .ops = &clk_regmap_mux_closest_ops,
+ },
+ },
+};
+
+static struct clk_regmap_mux gcc_ufs_phy_tx_symbol_0_clk_src = {
+ .reg = 0x83050,
+ .shift = 0,
+ .width = 2,
+ .parent_map = gcc_parent_map_21,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_ufs_phy_tx_symbol_0_clk_src",
+ .parent_data = gcc_parent_data_21,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_21),
+ .ops = &clk_regmap_mux_closest_ops,
+ },
+ },
+};
+
+static struct clk_regmap_mux gcc_usb3_prim_phy_pipe_clk_src = {
+ .reg = 0x1b068,
+ .shift = 0,
+ .width = 2,
+ .parent_map = gcc_parent_map_22,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_usb3_prim_phy_pipe_clk_src",
+ .parent_data = gcc_parent_data_22,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_22),
+ .ops = &clk_regmap_mux_closest_ops,
+ },
+ },
+};
+
+static struct clk_regmap_mux gcc_usb3_sec_phy_pipe_clk_src = {
+ .reg = 0x2f068,
+ .shift = 0,
+ .width = 2,
+ .parent_map = gcc_parent_map_23,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_usb3_sec_phy_pipe_clk_src",
+ .parent_data = gcc_parent_data_23,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_23),
+ .ops = &clk_regmap_mux_closest_ops,
+ },
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_emac0_phy_aux_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_emac0_phy_aux_clk_src = {
+ .cmd_rcgr = 0xb6028,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_3,
+ .freq_tbl = ftbl_gcc_emac0_phy_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data){
+ .name = "gcc_emac0_phy_aux_clk_src",
+ .parent_data = gcc_parent_data_3,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_3),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_emac0_ptp_clk_src[] = {
+ F(125000000, P_GCC_GPLL7_OUT_MAIN, 8, 0, 0),
+ F(230400000, P_GCC_GPLL4_OUT_MAIN, 3.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_emac0_ptp_clk_src = {
+ .cmd_rcgr = 0xb6060,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_6,
+ .freq_tbl = ftbl_gcc_emac0_ptp_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data){
+ .name = "gcc_emac0_ptp_clk_src",
+ .parent_data = gcc_parent_data_6,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_6),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_emac0_rgmii_clk_src[] = {
+ F(125000000, P_GCC_GPLL7_OUT_MAIN, 8, 0, 0),
+ F(250000000, P_GCC_GPLL7_OUT_MAIN, 4, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_emac0_rgmii_clk_src = {
+ .cmd_rcgr = 0xb6048,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_7,
+ .freq_tbl = ftbl_gcc_emac0_rgmii_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data){
+ .name = "gcc_emac0_rgmii_clk_src",
+ .parent_data = gcc_parent_data_7,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_7),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_emac1_phy_aux_clk_src = {
+ .cmd_rcgr = 0xb4028,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_3,
+ .freq_tbl = ftbl_gcc_emac0_phy_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data){
+ .name = "gcc_emac1_phy_aux_clk_src",
+ .parent_data = gcc_parent_data_3,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_3),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_emac1_ptp_clk_src = {
+ .cmd_rcgr = 0xb4060,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_6,
+ .freq_tbl = ftbl_gcc_emac0_ptp_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data){
+ .name = "gcc_emac1_ptp_clk_src",
+ .parent_data = gcc_parent_data_6,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_6),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_emac1_rgmii_clk_src = {
+ .cmd_rcgr = 0xb4048,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_8,
+ .freq_tbl = ftbl_gcc_emac0_rgmii_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data){
+ .name = "gcc_emac1_rgmii_clk_src",
+ .parent_data = gcc_parent_data_8,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_8),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_gp1_clk_src[] = {
+ F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0),
+ F(200000000, P_GCC_GPLL0_OUT_MAIN, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_gp1_clk_src = {
+ .cmd_rcgr = 0x70004,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_2,
+ .freq_tbl = ftbl_gcc_gp1_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data){
+ .name = "gcc_gp1_clk_src",
+ .parent_data = gcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_2),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_gp2_clk_src = {
+ .cmd_rcgr = 0x71004,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_2,
+ .freq_tbl = ftbl_gcc_gp1_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data){
+ .name = "gcc_gp2_clk_src",
+ .parent_data = gcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_2),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_gp3_clk_src = {
+ .cmd_rcgr = 0x62004,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_2,
+ .freq_tbl = ftbl_gcc_gp1_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data){
+ .name = "gcc_gp3_clk_src",
+ .parent_data = gcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_2),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_gp4_clk_src = {
+ .cmd_rcgr = 0x1e004,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_2,
+ .freq_tbl = ftbl_gcc_gp1_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data){
+ .name = "gcc_gp4_clk_src",
+ .parent_data = gcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_2),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_gp5_clk_src = {
+ .cmd_rcgr = 0x1f004,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_2,
+ .freq_tbl = ftbl_gcc_gp1_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data){
+ .name = "gcc_gp5_clk_src",
+ .parent_data = gcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_2),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie_0_aux_clk_src = {
+ .cmd_rcgr = 0xa9078,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_3,
+ .freq_tbl = ftbl_gcc_emac0_phy_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data){
+ .name = "gcc_pcie_0_aux_clk_src",
+ .parent_data = gcc_parent_data_3,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_3),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_pcie_0_phy_rchng_clk_src[] = {
+ F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_pcie_0_phy_rchng_clk_src = {
+ .cmd_rcgr = 0xa9054,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data){
+ .name = "gcc_pcie_0_phy_rchng_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie_1_aux_clk_src = {
+ .cmd_rcgr = 0x77078,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_3,
+ .freq_tbl = ftbl_gcc_emac0_phy_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data){
+ .name = "gcc_pcie_1_aux_clk_src",
+ .parent_data = gcc_parent_data_3,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_3),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie_1_phy_rchng_clk_src = {
+ .cmd_rcgr = 0x77054,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data){
+ .name = "gcc_pcie_1_phy_rchng_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_pdm2_clk_src[] = {
+ F(60000000, P_GCC_GPLL0_OUT_MAIN, 10, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_pdm2_clk_src = {
+ .cmd_rcgr = 0x3f010,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pdm2_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data){
+ .name = "gcc_pdm2_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src[] = {
+ F(7372800, P_GCC_GPLL0_OUT_EVEN, 1, 384, 15625),
+ F(14745600, P_GCC_GPLL0_OUT_EVEN, 1, 768, 15625),
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625),
+ F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75),
+ F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25),
+ F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75),
+ F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15),
+ F(96000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 25),
+ F(120000000, P_GCC_GPLL0_OUT_MAIN, 5, 0, 0),
+ { }
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s0_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s0_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s0_clk_src = {
+ .cmd_rcgr = 0x23154,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s0_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s1_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s1_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s1_clk_src = {
+ .cmd_rcgr = 0x23288,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s1_clk_src_init,
+};
+
+static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s2_clk_src[] = {
+ F(7372800, P_GCC_GPLL0_OUT_EVEN, 1, 384, 15625),
+ F(14745600, P_GCC_GPLL0_OUT_EVEN, 1, 768, 15625),
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625),
+ F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75),
+ F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25),
+ F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75),
+ F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15),
+ F(96000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 25),
+ F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0),
+ { }
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s2_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s2_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s2_clk_src = {
+ .cmd_rcgr = 0x233bc,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s2_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s3_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s3_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s3_clk_src = {
+ .cmd_rcgr = 0x234f0,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s3_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s4_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s4_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s4_clk_src = {
+ .cmd_rcgr = 0x23624,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s4_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s5_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s5_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s5_clk_src = {
+ .cmd_rcgr = 0x23758,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s5_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s6_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s6_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s6_clk_src = {
+ .cmd_rcgr = 0x2388c,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s6_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s0_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s0_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s0_clk_src = {
+ .cmd_rcgr = 0x24154,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s0_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s1_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s1_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s1_clk_src = {
+ .cmd_rcgr = 0x24288,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s1_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s2_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s2_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s2_clk_src = {
+ .cmd_rcgr = 0x243bc,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s2_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s3_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s3_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s3_clk_src = {
+ .cmd_rcgr = 0x244f0,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s3_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s4_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s4_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s4_clk_src = {
+ .cmd_rcgr = 0x24624,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s4_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s5_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s5_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s5_clk_src = {
+ .cmd_rcgr = 0x24758,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s5_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s6_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s6_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s6_clk_src = {
+ .cmd_rcgr = 0x2488c,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s6_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap2_s0_clk_src_init = {
+ .name = "gcc_qupv3_wrap2_s0_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap2_s0_clk_src = {
+ .cmd_rcgr = 0x2a154,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap2_s0_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap2_s1_clk_src_init = {
+ .name = "gcc_qupv3_wrap2_s1_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap2_s1_clk_src = {
+ .cmd_rcgr = 0x2a288,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap2_s1_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap2_s2_clk_src_init = {
+ .name = "gcc_qupv3_wrap2_s2_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap2_s2_clk_src = {
+ .cmd_rcgr = 0x2a3bc,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap2_s2_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap2_s3_clk_src_init = {
+ .name = "gcc_qupv3_wrap2_s3_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap2_s3_clk_src = {
+ .cmd_rcgr = 0x2a4f0,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap2_s3_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap2_s4_clk_src_init = {
+ .name = "gcc_qupv3_wrap2_s4_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap2_s4_clk_src = {
+ .cmd_rcgr = 0x2a624,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap2_s4_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap2_s5_clk_src_init = {
+ .name = "gcc_qupv3_wrap2_s5_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap2_s5_clk_src = {
+ .cmd_rcgr = 0x2a758,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap2_s5_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap2_s6_clk_src_init = {
+ .name = "gcc_qupv3_wrap2_s6_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap2_s6_clk_src = {
+ .cmd_rcgr = 0x2a88c,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap2_s6_clk_src_init,
+};
+
+static const struct freq_tbl ftbl_gcc_qupv3_wrap3_s0_clk_src[] = {
+ F(7372800, P_GCC_GPLL0_OUT_EVEN, 1, 384, 15625),
+ F(14745600, P_GCC_GPLL0_OUT_EVEN, 1, 768, 15625),
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625),
+ F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75),
+ F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25),
+ F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75),
+ F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0),
+ F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15),
+ F(96000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 25),
+ F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0),
+ F(403200000, P_GCC_GPLL4_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_init_data gcc_qupv3_wrap3_s0_clk_src_init = {
+ .name = "gcc_qupv3_wrap3_s0_clk_src",
+ .parent_data = gcc_parent_data_4,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_4),
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap3_s0_clk_src = {
+ .cmd_rcgr = 0xc4154,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_4,
+ .freq_tbl = ftbl_gcc_qupv3_wrap3_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap3_s0_clk_src_init,
+};
+
+static const struct freq_tbl ftbl_gcc_sdcc1_apps_clk_src[] = {
+ F(144000, P_BI_TCXO, 16, 3, 25),
+ F(400000, P_BI_TCXO, 12, 1, 4),
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(20000000, P_GCC_GPLL0_OUT_EVEN, 5, 1, 3),
+ F(25000000, P_GCC_GPLL0_OUT_EVEN, 12, 0, 0),
+ F(50000000, P_GCC_GPLL0_OUT_EVEN, 6, 0, 0),
+ F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0),
+ F(192000000, P_GCC_GPLL9_OUT_MAIN, 4, 0, 0),
+ F(384000000, P_GCC_GPLL9_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_sdcc1_apps_clk_src = {
+ .cmd_rcgr = 0x20014,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_13,
+ .freq_tbl = ftbl_gcc_sdcc1_apps_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data){
+ .name = "gcc_sdcc1_apps_clk_src",
+ .parent_data = gcc_parent_data_13,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_13),
+ .ops = &clk_rcg2_floor_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_sdcc1_ice_core_clk_src[] = {
+ F(150000000, P_GCC_GPLL0_OUT_MAIN, 4, 0, 0),
+ F(300000000, P_GCC_GPLL0_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_sdcc1_ice_core_clk_src = {
+ .cmd_rcgr = 0x2002c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_14,
+ .freq_tbl = ftbl_gcc_sdcc1_ice_core_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data){
+ .name = "gcc_sdcc1_ice_core_clk_src",
+ .parent_data = gcc_parent_data_14,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_14),
+ .ops = &clk_rcg2_floor_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_tscss_cntr_clk_src[] = {
+ F(15625000, P_GCC_GPLL7_OUT_MAIN, 16, 1, 4),
+ { }
+};
+
+static struct clk_rcg2 gcc_tscss_cntr_clk_src = {
+ .cmd_rcgr = 0x21008,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_15,
+ .freq_tbl = ftbl_gcc_tscss_cntr_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data){
+ .name = "gcc_tscss_cntr_clk_src",
+ .parent_data = gcc_parent_data_15,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_15),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_ufs_card_axi_clk_src[] = {
+ F(25000000, P_GCC_GPLL0_OUT_EVEN, 12, 0, 0),
+ F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0),
+ F(150000000, P_GCC_GPLL0_OUT_MAIN, 4, 0, 0),
+ F(300000000, P_GCC_GPLL0_OUT_MAIN, 2, 0, 0),
+ F(600000000, P_GCC_GPLL0_OUT_MAIN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_ufs_card_axi_clk_src = {
+ .cmd_rcgr = 0x8102c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_ufs_card_axi_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data){
+ .name = "gcc_ufs_card_axi_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_ufs_card_ice_core_clk_src[] = {
+ F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0),
+ F(150000000, P_GCC_GPLL0_OUT_MAIN, 4, 0, 0),
+ F(300000000, P_GCC_GPLL0_OUT_MAIN, 2, 0, 0),
+ F(600000000, P_GCC_GPLL0_OUT_MAIN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_ufs_card_ice_core_clk_src = {
+ .cmd_rcgr = 0x81074,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_ufs_card_ice_core_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data){
+ .name = "gcc_ufs_card_ice_core_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_ufs_card_phy_aux_clk_src = {
+ .cmd_rcgr = 0x810a8,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_5,
+ .freq_tbl = ftbl_gcc_emac0_phy_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data){
+ .name = "gcc_ufs_card_phy_aux_clk_src",
+ .parent_data = gcc_parent_data_5,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_5),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_ufs_card_unipro_core_clk_src = {
+ .cmd_rcgr = 0x8108c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_ufs_card_ice_core_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data){
+ .name = "gcc_ufs_card_unipro_core_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_ufs_phy_axi_clk_src = {
+ .cmd_rcgr = 0x8302c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_ufs_card_axi_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data){
+ .name = "gcc_ufs_phy_axi_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_ufs_phy_ice_core_clk_src = {
+ .cmd_rcgr = 0x83074,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_ufs_card_ice_core_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data){
+ .name = "gcc_ufs_phy_ice_core_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_ufs_phy_phy_aux_clk_src = {
+ .cmd_rcgr = 0x830a8,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_5,
+ .freq_tbl = ftbl_gcc_emac0_phy_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data){
+ .name = "gcc_ufs_phy_phy_aux_clk_src",
+ .parent_data = gcc_parent_data_5,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_5),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_ufs_phy_unipro_core_clk_src = {
+ .cmd_rcgr = 0x8308c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_ufs_card_ice_core_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data){
+ .name = "gcc_ufs_phy_unipro_core_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_usb20_master_clk_src[] = {
+ F(120000000, P_GCC_GPLL0_OUT_MAIN, 5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_usb20_master_clk_src = {
+ .cmd_rcgr = 0x1c028,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_usb20_master_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data){
+ .name = "gcc_usb20_master_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb20_mock_utmi_clk_src = {
+ .cmd_rcgr = 0x1c040,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_emac0_phy_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data){
+ .name = "gcc_usb20_mock_utmi_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_usb30_prim_master_clk_src[] = {
+ F(133333333, P_GCC_GPLL0_OUT_MAIN, 4.5, 0, 0),
+ F(200000000, P_GCC_GPLL0_OUT_MAIN, 3, 0, 0),
+ F(240000000, P_GCC_GPLL0_OUT_MAIN, 2.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_usb30_prim_master_clk_src = {
+ .cmd_rcgr = 0x1b028,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_usb30_prim_master_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data){
+ .name = "gcc_usb30_prim_master_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb30_prim_mock_utmi_clk_src = {
+ .cmd_rcgr = 0x1b040,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_emac0_phy_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data){
+ .name = "gcc_usb30_prim_mock_utmi_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb30_sec_master_clk_src = {
+ .cmd_rcgr = 0x2f028,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_usb30_prim_master_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data){
+ .name = "gcc_usb30_sec_master_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb30_sec_mock_utmi_clk_src = {
+ .cmd_rcgr = 0x2f040,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_emac0_phy_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data){
+ .name = "gcc_usb30_sec_mock_utmi_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb3_prim_phy_aux_clk_src = {
+ .cmd_rcgr = 0x1b06c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_3,
+ .freq_tbl = ftbl_gcc_emac0_phy_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data){
+ .name = "gcc_usb3_prim_phy_aux_clk_src",
+ .parent_data = gcc_parent_data_3,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_3),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb3_sec_phy_aux_clk_src = {
+ .cmd_rcgr = 0x2f06c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_3,
+ .freq_tbl = ftbl_gcc_emac0_phy_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data){
+ .name = "gcc_usb3_sec_phy_aux_clk_src",
+ .parent_data = gcc_parent_data_3,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_3),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_regmap_div gcc_pcie_0_pipe_div_clk_src = {
+ .reg = 0xa9070,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_pipe_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_pcie_0_pipe_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div gcc_pcie_1_pipe_div_clk_src = {
+ .reg = 0x77070,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_1_pipe_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_pcie_1_pipe_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div gcc_qupv3_wrap3_s0_div_clk_src = {
+ .reg = 0xc4284,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap3_s0_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_qupv3_wrap3_s0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div gcc_usb20_mock_utmi_postdiv_clk_src = {
+ .reg = 0x1c058,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb20_mock_utmi_postdiv_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_usb20_mock_utmi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div gcc_usb30_prim_mock_utmi_postdiv_clk_src = {
+ .reg = 0x1b058,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_prim_mock_utmi_postdiv_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_usb30_prim_mock_utmi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div gcc_usb30_sec_mock_utmi_postdiv_clk_src = {
+ .reg = 0x2f058,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_sec_mock_utmi_postdiv_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_usb30_sec_mock_utmi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_branch gcc_aggre_noc_qupv3_axi_clk = {
+ .halt_reg = 0x8e200,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x8e200,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x4b000,
+ .enable_mask = BIT(28),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_aggre_noc_qupv3_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_aggre_ufs_card_axi_clk = {
+ .halt_reg = 0x810d4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x810d4,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x810d4,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_aggre_ufs_card_axi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_ufs_card_axi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_aggre_ufs_phy_axi_clk = {
+ .halt_reg = 0x830d4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x830d4,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x830d4,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_aggre_ufs_phy_axi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_ufs_phy_axi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_aggre_ufs_phy_axi_hw_ctl_clk = {
+ .halt_reg = 0x830d4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x830d4,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x830d4,
+ .enable_mask = BIT(1),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_aggre_ufs_phy_axi_hw_ctl_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_ufs_phy_axi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_aggre_usb2_prim_axi_clk = {
+ .halt_reg = 0x1c05c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x1c05c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x1c05c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_aggre_usb2_prim_axi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_usb20_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_aggre_usb3_prim_axi_clk = {
+ .halt_reg = 0x1b084,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x1b084,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x1b084,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_aggre_usb3_prim_axi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_usb30_prim_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_aggre_usb3_sec_axi_clk = {
+ .halt_reg = 0x2f088,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x2f088,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x2f088,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_aggre_usb3_sec_axi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_usb30_sec_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ahb2phy0_clk = {
+ .halt_reg = 0x76004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x76004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x76004,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_ahb2phy0_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ahb2phy2_clk = {
+ .halt_reg = 0x76008,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x76008,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x76008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_ahb2phy2_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ahb2phy3_clk = {
+ .halt_reg = 0x7600c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x7600c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x7600c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_ahb2phy3_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_boot_rom_ahb_clk = {
+ .halt_reg = 0x44004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x44004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x4b000,
+ .enable_mask = BIT(10),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_boot_rom_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camera_hf_axi_clk = {
+ .halt_reg = 0x32010,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x32010,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x32010,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_camera_hf_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camera_sf_axi_clk = {
+ .halt_reg = 0x32018,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x32018,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x32018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_camera_sf_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camera_throttle_xo_clk = {
+ .halt_reg = 0x32024,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x32024,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_camera_throttle_xo_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cfg_noc_usb2_prim_axi_clk = {
+ .halt_reg = 0x1c060,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x1c060,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x1c060,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_cfg_noc_usb2_prim_axi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_usb20_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cfg_noc_usb3_prim_axi_clk = {
+ .halt_reg = 0x1b088,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x1b088,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x1b088,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_cfg_noc_usb3_prim_axi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_usb30_prim_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cfg_noc_usb3_sec_axi_clk = {
+ .halt_reg = 0x2f084,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x2f084,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x2f084,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_cfg_noc_usb3_sec_axi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_usb30_sec_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ddrss_gpu_axi_clk = {
+ .halt_reg = 0x7d164,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x7d164,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x7d164,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_ddrss_gpu_axi_clk",
+ .ops = &clk_branch2_aon_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_disp1_hf_axi_clk = {
+ .halt_reg = 0xc7010,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0xc7010,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0xc7010,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_disp1_hf_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_disp_hf_axi_clk = {
+ .halt_reg = 0x33010,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x33010,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x33010,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_disp_hf_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_edp_ref_clkref_en = {
+ .halt_reg = 0x97448,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x97448,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_edp_ref_clkref_en",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_emac0_axi_clk = {
+ .halt_reg = 0xb6018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0xb6018,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0xb6018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_emac0_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_emac0_phy_aux_clk = {
+ .halt_reg = 0xb6024,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb6024,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_emac0_phy_aux_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_emac0_phy_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_emac0_ptp_clk = {
+ .halt_reg = 0xb6040,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb6040,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_emac0_ptp_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_emac0_ptp_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_emac0_rgmii_clk = {
+ .halt_reg = 0xb6044,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb6044,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_emac0_rgmii_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_emac0_rgmii_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_emac0_slv_ahb_clk = {
+ .halt_reg = 0xb6020,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0xb6020,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0xb6020,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_emac0_slv_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_emac1_axi_clk = {
+ .halt_reg = 0xb4018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0xb4018,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0xb4018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_emac1_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_emac1_phy_aux_clk = {
+ .halt_reg = 0xb4024,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb4024,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_emac1_phy_aux_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_emac1_phy_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_emac1_ptp_clk = {
+ .halt_reg = 0xb4040,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb4040,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_emac1_ptp_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_emac1_ptp_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_emac1_rgmii_clk = {
+ .halt_reg = 0xb4044,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb4044,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_emac1_rgmii_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_emac1_rgmii_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_emac1_slv_ahb_clk = {
+ .halt_reg = 0xb4020,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0xb4020,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0xb4020,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_emac1_slv_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gp1_clk = {
+ .halt_reg = 0x70000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x70000,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_gp1_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_gp1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gp2_clk = {
+ .halt_reg = 0x71000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x71000,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_gp2_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_gp2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gp3_clk = {
+ .halt_reg = 0x62000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x62000,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_gp3_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_gp3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gp4_clk = {
+ .halt_reg = 0x1e000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1e000,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_gp4_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_gp4_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gp5_clk = {
+ .halt_reg = 0x1f000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1f000,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_gp5_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_gp5_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_gpll0_clk_src = {
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x4b000,
+ .enable_mask = BIT(15),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_gpu_gpll0_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_gpll0.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_gpll0_div_clk_src = {
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x4b000,
+ .enable_mask = BIT(16),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_gpu_gpll0_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_gpll0_out_even.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_memnoc_gfx_clk = {
+ .halt_reg = 0x7d010,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x7d010,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x7d010,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_gpu_memnoc_gfx_clk",
+ .ops = &clk_branch2_aon_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_snoc_dvm_gfx_clk = {
+ .halt_reg = 0x7d01c,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x7d01c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_gpu_snoc_dvm_gfx_clk",
+ .ops = &clk_branch2_aon_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_tcu_throttle_ahb_clk = {
+ .halt_reg = 0x7d008,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x7d008,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x7d008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_gpu_tcu_throttle_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_tcu_throttle_clk = {
+ .halt_reg = 0x7d014,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x7d014,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x7d014,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_gpu_tcu_throttle_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_aux_clk = {
+ .halt_reg = 0xa9038,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b010,
+ .enable_mask = BIT(16),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_pcie_0_aux_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_pcie_0_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_cfg_ahb_clk = {
+ .halt_reg = 0xa902c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0xa902c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x4b010,
+ .enable_mask = BIT(12),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_pcie_0_cfg_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_mstr_axi_clk = {
+ .halt_reg = 0xa9024,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b010,
+ .enable_mask = BIT(11),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_pcie_0_mstr_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_phy_aux_clk = {
+ .halt_reg = 0xa9030,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b010,
+ .enable_mask = BIT(13),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_pcie_0_phy_aux_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_pcie_0_phy_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_phy_rchng_clk = {
+ .halt_reg = 0xa9050,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b010,
+ .enable_mask = BIT(15),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_pcie_0_phy_rchng_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_pcie_0_phy_rchng_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_pipe_clk = {
+ .halt_reg = 0xa9040,
+ .halt_check = BRANCH_HALT_SKIP,
+ .clkr = {
+ .enable_reg = 0x4b010,
+ .enable_mask = BIT(14),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_pcie_0_pipe_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_pcie_0_pipe_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_pipediv2_clk = {
+ .halt_reg = 0xa9048,
+ .halt_check = BRANCH_HALT_SKIP,
+ .clkr = {
+ .enable_reg = 0x4b018,
+ .enable_mask = BIT(22),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_pcie_0_pipediv2_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_pcie_0_pipe_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_slv_axi_clk = {
+ .halt_reg = 0xa901c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b010,
+ .enable_mask = BIT(10),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_pcie_0_slv_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_slv_q2a_axi_clk = {
+ .halt_reg = 0xa9018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b018,
+ .enable_mask = BIT(12),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_pcie_0_slv_q2a_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_1_aux_clk = {
+ .halt_reg = 0x77038,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b000,
+ .enable_mask = BIT(31),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_pcie_1_aux_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_pcie_1_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_1_cfg_ahb_clk = {
+ .halt_reg = 0x7702c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x7702c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x4b008,
+ .enable_mask = BIT(2),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_pcie_1_cfg_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_1_mstr_axi_clk = {
+ .halt_reg = 0x77024,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b008,
+ .enable_mask = BIT(1),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_pcie_1_mstr_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_1_phy_aux_clk = {
+ .halt_reg = 0x77030,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b008,
+ .enable_mask = BIT(3),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_pcie_1_phy_aux_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_pcie_1_phy_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_1_phy_rchng_clk = {
+ .halt_reg = 0x77050,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b000,
+ .enable_mask = BIT(22),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_pcie_1_phy_rchng_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_pcie_1_phy_rchng_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_1_pipe_clk = {
+ .halt_reg = 0x77040,
+ .halt_check = BRANCH_HALT_SKIP,
+ .clkr = {
+ .enable_reg = 0x4b008,
+ .enable_mask = BIT(4),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_pcie_1_pipe_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_pcie_1_pipe_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_1_pipediv2_clk = {
+ .halt_reg = 0x77048,
+ .halt_check = BRANCH_HALT_SKIP,
+ .clkr = {
+ .enable_reg = 0x4b018,
+ .enable_mask = BIT(16),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_pcie_1_pipediv2_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_pcie_1_pipe_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_1_slv_axi_clk = {
+ .halt_reg = 0x7701c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_pcie_1_slv_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_1_slv_q2a_axi_clk = {
+ .halt_reg = 0x77018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b008,
+ .enable_mask = BIT(5),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_pcie_1_slv_q2a_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_clkref_en = {
+ .halt_reg = 0x9746c,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x9746c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_pcie_clkref_en",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_throttle_cfg_clk = {
+ .halt_reg = 0xb2034,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b020,
+ .enable_mask = BIT(15),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_pcie_throttle_cfg_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pdm2_clk = {
+ .halt_reg = 0x3f00c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3f00c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_pdm2_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_pdm2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pdm_ahb_clk = {
+ .halt_reg = 0x3f004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x3f004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x3f004,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_pdm_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pdm_xo4_clk = {
+ .halt_reg = 0x3f008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3f008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_pdm_xo4_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_camera_nrt_ahb_clk = {
+ .halt_reg = 0x32008,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x32008,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x32008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qmip_camera_nrt_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_camera_rt_ahb_clk = {
+ .halt_reg = 0x3200c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x3200c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x3200c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qmip_camera_rt_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_disp1_ahb_clk = {
+ .halt_reg = 0xc7008,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0xc7008,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0xc7008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qmip_disp1_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_disp1_rot_ahb_clk = {
+ .halt_reg = 0xc700c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0xc700c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qmip_disp1_rot_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_disp_ahb_clk = {
+ .halt_reg = 0x33008,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x33008,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x33008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qmip_disp_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_disp_rot_ahb_clk = {
+ .halt_reg = 0x3300c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x3300c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qmip_disp_rot_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_video_cvp_ahb_clk = {
+ .halt_reg = 0x34008,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x34008,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x34008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qmip_video_cvp_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_video_vcodec_ahb_clk = {
+ .halt_reg = 0x3400c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x3400c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x3400c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qmip_video_vcodec_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_video_vcpu_ahb_clk = {
+ .halt_reg = 0x34010,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x34010,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x34010,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qmip_video_vcpu_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_core_2x_clk = {
+ .halt_reg = 0x23018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b008,
+ .enable_mask = BIT(9),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap0_core_2x_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_core_clk = {
+ .halt_reg = 0x2300c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b008,
+ .enable_mask = BIT(8),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap0_core_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s0_clk = {
+ .halt_reg = 0x2314c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b008,
+ .enable_mask = BIT(10),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap0_s0_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_qupv3_wrap0_s0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s1_clk = {
+ .halt_reg = 0x23280,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b008,
+ .enable_mask = BIT(11),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap0_s1_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_qupv3_wrap0_s1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s2_clk = {
+ .halt_reg = 0x233b4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b008,
+ .enable_mask = BIT(12),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap0_s2_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_qupv3_wrap0_s2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s3_clk = {
+ .halt_reg = 0x234e8,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b008,
+ .enable_mask = BIT(13),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap0_s3_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_qupv3_wrap0_s3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s4_clk = {
+ .halt_reg = 0x2361c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b008,
+ .enable_mask = BIT(14),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap0_s4_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_qupv3_wrap0_s4_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s5_clk = {
+ .halt_reg = 0x23750,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b008,
+ .enable_mask = BIT(15),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap0_s5_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_qupv3_wrap0_s5_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s6_clk = {
+ .halt_reg = 0x23884,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b008,
+ .enable_mask = BIT(16),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap0_s6_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_qupv3_wrap0_s6_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_core_2x_clk = {
+ .halt_reg = 0x24018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b008,
+ .enable_mask = BIT(18),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap1_core_2x_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_core_clk = {
+ .halt_reg = 0x2400c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b008,
+ .enable_mask = BIT(19),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap1_core_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s0_clk = {
+ .halt_reg = 0x2414c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b008,
+ .enable_mask = BIT(22),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap1_s0_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_qupv3_wrap1_s0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s1_clk = {
+ .halt_reg = 0x24280,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b008,
+ .enable_mask = BIT(23),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap1_s1_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_qupv3_wrap1_s1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s2_clk = {
+ .halt_reg = 0x243b4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b008,
+ .enable_mask = BIT(24),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap1_s2_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_qupv3_wrap1_s2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s3_clk = {
+ .halt_reg = 0x244e8,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b008,
+ .enable_mask = BIT(25),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap1_s3_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_qupv3_wrap1_s3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s4_clk = {
+ .halt_reg = 0x2461c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b008,
+ .enable_mask = BIT(26),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap1_s4_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_qupv3_wrap1_s4_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s5_clk = {
+ .halt_reg = 0x24750,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b008,
+ .enable_mask = BIT(27),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap1_s5_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_qupv3_wrap1_s5_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s6_clk = {
+ .halt_reg = 0x24884,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b018,
+ .enable_mask = BIT(27),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap1_s6_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_qupv3_wrap1_s6_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_core_2x_clk = {
+ .halt_reg = 0x2a018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b010,
+ .enable_mask = BIT(3),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap2_core_2x_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_core_clk = {
+ .halt_reg = 0x2a00c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b010,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap2_core_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_s0_clk = {
+ .halt_reg = 0x2a14c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b010,
+ .enable_mask = BIT(4),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap2_s0_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_qupv3_wrap2_s0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_s1_clk = {
+ .halt_reg = 0x2a280,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b010,
+ .enable_mask = BIT(5),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap2_s1_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_qupv3_wrap2_s1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_s2_clk = {
+ .halt_reg = 0x2a3b4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b010,
+ .enable_mask = BIT(6),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap2_s2_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_qupv3_wrap2_s2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_s3_clk = {
+ .halt_reg = 0x2a4e8,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b010,
+ .enable_mask = BIT(7),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap2_s3_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_qupv3_wrap2_s3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_s4_clk = {
+ .halt_reg = 0x2a61c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b010,
+ .enable_mask = BIT(8),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap2_s4_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_qupv3_wrap2_s4_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_s5_clk = {
+ .halt_reg = 0x2a750,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b010,
+ .enable_mask = BIT(9),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap2_s5_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_qupv3_wrap2_s5_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_s6_clk = {
+ .halt_reg = 0x2a884,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b018,
+ .enable_mask = BIT(29),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap2_s6_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_qupv3_wrap2_s6_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap3_core_2x_clk = {
+ .halt_reg = 0xc4018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b000,
+ .enable_mask = BIT(24),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap3_core_2x_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap3_core_clk = {
+ .halt_reg = 0xc400c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b000,
+ .enable_mask = BIT(23),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap3_core_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap3_qspi_clk = {
+ .halt_reg = 0xc4280,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b000,
+ .enable_mask = BIT(26),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap3_qspi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_qupv3_wrap3_s0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap3_s0_clk = {
+ .halt_reg = 0xc414c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x4b000,
+ .enable_mask = BIT(25),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap3_s0_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_qupv3_wrap3_s0_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_0_m_ahb_clk = {
+ .halt_reg = 0x23004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x23004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x4b008,
+ .enable_mask = BIT(6),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap_0_m_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_0_s_ahb_clk = {
+ .halt_reg = 0x23008,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x23008,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x4b008,
+ .enable_mask = BIT(7),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap_0_s_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_1_m_ahb_clk = {
+ .halt_reg = 0x24004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x24004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x4b008,
+ .enable_mask = BIT(20),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap_1_m_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_1_s_ahb_clk = {
+ .halt_reg = 0x24008,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x24008,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x4b008,
+ .enable_mask = BIT(21),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap_1_s_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_2_m_ahb_clk = {
+ .halt_reg = 0x2a004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x2a004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x4b010,
+ .enable_mask = BIT(2),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap_2_m_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_2_s_ahb_clk = {
+ .halt_reg = 0x2a008,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x2a008,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x4b010,
+ .enable_mask = BIT(1),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap_2_s_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_3_m_ahb_clk = {
+ .halt_reg = 0xc4004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0xc4004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x4b000,
+ .enable_mask = BIT(27),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap_3_m_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_3_s_ahb_clk = {
+ .halt_reg = 0xc4008,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0xc4008,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x4b000,
+ .enable_mask = BIT(20),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_qupv3_wrap_3_s_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc1_ahb_clk = {
+ .halt_reg = 0x2000c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2000c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_sdcc1_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc1_apps_clk = {
+ .halt_reg = 0x20004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x20004,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_sdcc1_apps_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_sdcc1_apps_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc1_ice_core_clk = {
+ .halt_reg = 0x20044,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x20044,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x20044,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_sdcc1_ice_core_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_sdcc1_ice_core_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sgmi_clkref_en = {
+ .halt_reg = 0x9c034,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x9c034,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_sgmi_clkref_en",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_tscss_ahb_clk = {
+ .halt_reg = 0x21024,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x21024,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_tscss_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_tscss_etu_clk = {
+ .halt_reg = 0x21020,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x21020,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_tscss_etu_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_tscss_global_cntr_clk = {
+ .halt_reg = 0x21004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x21004,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_tscss_global_cntr_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_tscss_cntr_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_card_ahb_clk = {
+ .halt_reg = 0x81020,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x81020,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x81020,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_ufs_card_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_card_axi_clk = {
+ .halt_reg = 0x81018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x81018,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x81018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_ufs_card_axi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_ufs_card_axi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_card_ice_core_clk = {
+ .halt_reg = 0x8106c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x8106c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x8106c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_ufs_card_ice_core_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_ufs_card_ice_core_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_card_phy_aux_clk = {
+ .halt_reg = 0x810a4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x810a4,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x810a4,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_ufs_card_phy_aux_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_ufs_card_phy_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_card_rx_symbol_0_clk = {
+ .halt_reg = 0x81028,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x81028,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_ufs_card_rx_symbol_0_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_ufs_card_rx_symbol_0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_card_rx_symbol_1_clk = {
+ .halt_reg = 0x810c0,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x810c0,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_ufs_card_rx_symbol_1_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_ufs_card_rx_symbol_1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_card_tx_symbol_0_clk = {
+ .halt_reg = 0x81024,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x81024,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_ufs_card_tx_symbol_0_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_ufs_card_tx_symbol_0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_card_unipro_core_clk = {
+ .halt_reg = 0x81064,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x81064,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x81064,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_ufs_card_unipro_core_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_ufs_card_unipro_core_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_ahb_clk = {
+ .halt_reg = 0x83020,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x83020,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x83020,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_ufs_phy_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_axi_clk = {
+ .halt_reg = 0x83018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x83018,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x83018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_ufs_phy_axi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_ufs_phy_axi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_axi_hw_ctl_clk = {
+ .halt_reg = 0x83018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x83018,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x83018,
+ .enable_mask = BIT(1),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_ufs_phy_axi_hw_ctl_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_ufs_phy_axi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_ice_core_clk = {
+ .halt_reg = 0x8306c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x8306c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x8306c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_ufs_phy_ice_core_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_ufs_phy_ice_core_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_ice_core_hw_ctl_clk = {
+ .halt_reg = 0x8306c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x8306c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x8306c,
+ .enable_mask = BIT(1),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_ufs_phy_ice_core_hw_ctl_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_ufs_phy_ice_core_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_phy_aux_clk = {
+ .halt_reg = 0x830a4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x830a4,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x830a4,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_ufs_phy_phy_aux_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_ufs_phy_phy_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_phy_aux_hw_ctl_clk = {
+ .halt_reg = 0x830a4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x830a4,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x830a4,
+ .enable_mask = BIT(1),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_ufs_phy_phy_aux_hw_ctl_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_ufs_phy_phy_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_rx_symbol_0_clk = {
+ .halt_reg = 0x83028,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x83028,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_ufs_phy_rx_symbol_0_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_ufs_phy_rx_symbol_0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_rx_symbol_1_clk = {
+ .halt_reg = 0x830c0,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x830c0,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_ufs_phy_rx_symbol_1_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_ufs_phy_rx_symbol_1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_tx_symbol_0_clk = {
+ .halt_reg = 0x83024,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x83024,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_ufs_phy_tx_symbol_0_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_ufs_phy_tx_symbol_0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_unipro_core_clk = {
+ .halt_reg = 0x83064,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x83064,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x83064,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_ufs_phy_unipro_core_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_ufs_phy_unipro_core_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_unipro_core_hw_ctl_clk = {
+ .halt_reg = 0x83064,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x83064,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x83064,
+ .enable_mask = BIT(1),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_ufs_phy_unipro_core_hw_ctl_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_ufs_phy_unipro_core_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb20_master_clk = {
+ .halt_reg = 0x1c018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1c018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_usb20_master_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_usb20_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb20_mock_utmi_clk = {
+ .halt_reg = 0x1c024,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1c024,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_usb20_mock_utmi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_usb20_mock_utmi_postdiv_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb20_sleep_clk = {
+ .halt_reg = 0x1c020,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1c020,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_usb20_sleep_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_prim_master_clk = {
+ .halt_reg = 0x1b018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1b018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_usb30_prim_master_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_usb30_prim_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_prim_mock_utmi_clk = {
+ .halt_reg = 0x1b024,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1b024,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_usb30_prim_mock_utmi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_usb30_prim_mock_utmi_postdiv_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_prim_sleep_clk = {
+ .halt_reg = 0x1b020,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1b020,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_usb30_prim_sleep_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_sec_master_clk = {
+ .halt_reg = 0x2f018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2f018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_usb30_sec_master_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_usb30_sec_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_sec_mock_utmi_clk = {
+ .halt_reg = 0x2f024,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2f024,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_usb30_sec_mock_utmi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_usb30_sec_mock_utmi_postdiv_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_sec_sleep_clk = {
+ .halt_reg = 0x2f020,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2f020,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_usb30_sec_sleep_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_prim_phy_aux_clk = {
+ .halt_reg = 0x1b05c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1b05c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_usb3_prim_phy_aux_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_usb3_prim_phy_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_prim_phy_com_aux_clk = {
+ .halt_reg = 0x1b060,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1b060,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_usb3_prim_phy_com_aux_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_usb3_prim_phy_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_prim_phy_pipe_clk = {
+ .halt_reg = 0x1b064,
+ .halt_check = BRANCH_HALT_DELAY,
+ .hwcg_reg = 0x1b064,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x1b064,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_usb3_prim_phy_pipe_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_usb3_prim_phy_pipe_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_sec_phy_aux_clk = {
+ .halt_reg = 0x2f05c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2f05c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_usb3_sec_phy_aux_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_usb3_sec_phy_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_sec_phy_com_aux_clk = {
+ .halt_reg = 0x2f060,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2f060,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_usb3_sec_phy_com_aux_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_usb3_sec_phy_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_sec_phy_pipe_clk = {
+ .halt_reg = 0x2f064,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x2f064,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_usb3_sec_phy_pipe_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gcc_usb3_sec_phy_pipe_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb_clkref_en = {
+ .halt_reg = 0x97468,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x97468,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_usb_clkref_en",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_video_axi0_clk = {
+ .halt_reg = 0x34014,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x34014,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x34014,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_video_axi0_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_video_axi1_clk = {
+ .halt_reg = 0x3401c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x3401c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x3401c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gcc_video_axi1_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct gdsc pcie_0_gdsc = {
+ .gdscr = 0xa9004,
+ .pd = {
+ .name = "pcie_0_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc pcie_1_gdsc = {
+ .gdscr = 0x77004,
+ .pd = {
+ .name = "pcie_1_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc ufs_card_gdsc = {
+ .gdscr = 0x81004,
+ .pd = {
+ .name = "ufs_card_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc ufs_phy_gdsc = {
+ .gdscr = 0x83004,
+ .pd = {
+ .name = "ufs_phy_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc usb20_prim_gdsc = {
+ .gdscr = 0x1c004,
+ .pd = {
+ .name = "usb20_prim_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc usb30_prim_gdsc = {
+ .gdscr = 0x1b004,
+ .pd = {
+ .name = "usb30_prim_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc usb30_sec_gdsc = {
+ .gdscr = 0x2f004,
+ .pd = {
+ .name = "usb30_sec_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc emac0_gdsc = {
+ .gdscr = 0xb6004,
+ .pd = {
+ .name = "emac0_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc emac1_gdsc = {
+ .gdscr = 0xb4004,
+ .pd = {
+ .name = "emac1_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct clk_regmap *gcc_sa8775p_clocks[] = {
+ [GCC_AGGRE_NOC_QUPV3_AXI_CLK] = &gcc_aggre_noc_qupv3_axi_clk.clkr,
+ [GCC_AGGRE_UFS_CARD_AXI_CLK] = &gcc_aggre_ufs_card_axi_clk.clkr,
+ [GCC_AGGRE_UFS_PHY_AXI_CLK] = &gcc_aggre_ufs_phy_axi_clk.clkr,
+ [GCC_AGGRE_UFS_PHY_AXI_HW_CTL_CLK] = &gcc_aggre_ufs_phy_axi_hw_ctl_clk.clkr,
+ [GCC_AGGRE_USB2_PRIM_AXI_CLK] = &gcc_aggre_usb2_prim_axi_clk.clkr,
+ [GCC_AGGRE_USB3_PRIM_AXI_CLK] = &gcc_aggre_usb3_prim_axi_clk.clkr,
+ [GCC_AGGRE_USB3_SEC_AXI_CLK] = &gcc_aggre_usb3_sec_axi_clk.clkr,
+ [GCC_AHB2PHY0_CLK] = &gcc_ahb2phy0_clk.clkr,
+ [GCC_AHB2PHY2_CLK] = &gcc_ahb2phy2_clk.clkr,
+ [GCC_AHB2PHY3_CLK] = &gcc_ahb2phy3_clk.clkr,
+ [GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr,
+ [GCC_CAMERA_HF_AXI_CLK] = &gcc_camera_hf_axi_clk.clkr,
+ [GCC_CAMERA_SF_AXI_CLK] = &gcc_camera_sf_axi_clk.clkr,
+ [GCC_CAMERA_THROTTLE_XO_CLK] = &gcc_camera_throttle_xo_clk.clkr,
+ [GCC_CFG_NOC_USB2_PRIM_AXI_CLK] = &gcc_cfg_noc_usb2_prim_axi_clk.clkr,
+ [GCC_CFG_NOC_USB3_PRIM_AXI_CLK] = &gcc_cfg_noc_usb3_prim_axi_clk.clkr,
+ [GCC_CFG_NOC_USB3_SEC_AXI_CLK] = &gcc_cfg_noc_usb3_sec_axi_clk.clkr,
+ [GCC_DDRSS_GPU_AXI_CLK] = &gcc_ddrss_gpu_axi_clk.clkr,
+ [GCC_DISP1_HF_AXI_CLK] = &gcc_disp1_hf_axi_clk.clkr,
+ [GCC_DISP_HF_AXI_CLK] = &gcc_disp_hf_axi_clk.clkr,
+ [GCC_EDP_REF_CLKREF_EN] = &gcc_edp_ref_clkref_en.clkr,
+ [GCC_EMAC0_AXI_CLK] = &gcc_emac0_axi_clk.clkr,
+ [GCC_EMAC0_PHY_AUX_CLK] = &gcc_emac0_phy_aux_clk.clkr,
+ [GCC_EMAC0_PHY_AUX_CLK_SRC] = &gcc_emac0_phy_aux_clk_src.clkr,
+ [GCC_EMAC0_PTP_CLK] = &gcc_emac0_ptp_clk.clkr,
+ [GCC_EMAC0_PTP_CLK_SRC] = &gcc_emac0_ptp_clk_src.clkr,
+ [GCC_EMAC0_RGMII_CLK] = &gcc_emac0_rgmii_clk.clkr,
+ [GCC_EMAC0_RGMII_CLK_SRC] = &gcc_emac0_rgmii_clk_src.clkr,
+ [GCC_EMAC0_SLV_AHB_CLK] = &gcc_emac0_slv_ahb_clk.clkr,
+ [GCC_EMAC1_AXI_CLK] = &gcc_emac1_axi_clk.clkr,
+ [GCC_EMAC1_PHY_AUX_CLK] = &gcc_emac1_phy_aux_clk.clkr,
+ [GCC_EMAC1_PHY_AUX_CLK_SRC] = &gcc_emac1_phy_aux_clk_src.clkr,
+ [GCC_EMAC1_PTP_CLK] = &gcc_emac1_ptp_clk.clkr,
+ [GCC_EMAC1_PTP_CLK_SRC] = &gcc_emac1_ptp_clk_src.clkr,
+ [GCC_EMAC1_RGMII_CLK] = &gcc_emac1_rgmii_clk.clkr,
+ [GCC_EMAC1_RGMII_CLK_SRC] = &gcc_emac1_rgmii_clk_src.clkr,
+ [GCC_EMAC1_SLV_AHB_CLK] = &gcc_emac1_slv_ahb_clk.clkr,
+ [GCC_GP1_CLK] = &gcc_gp1_clk.clkr,
+ [GCC_GP1_CLK_SRC] = &gcc_gp1_clk_src.clkr,
+ [GCC_GP2_CLK] = &gcc_gp2_clk.clkr,
+ [GCC_GP2_CLK_SRC] = &gcc_gp2_clk_src.clkr,
+ [GCC_GP3_CLK] = &gcc_gp3_clk.clkr,
+ [GCC_GP3_CLK_SRC] = &gcc_gp3_clk_src.clkr,
+ [GCC_GP4_CLK] = &gcc_gp4_clk.clkr,
+ [GCC_GP4_CLK_SRC] = &gcc_gp4_clk_src.clkr,
+ [GCC_GP5_CLK] = &gcc_gp5_clk.clkr,
+ [GCC_GP5_CLK_SRC] = &gcc_gp5_clk_src.clkr,
+ [GCC_GPLL0] = &gcc_gpll0.clkr,
+ [GCC_GPLL0_OUT_EVEN] = &gcc_gpll0_out_even.clkr,
+ [GCC_GPLL1] = &gcc_gpll1.clkr,
+ [GCC_GPLL4] = &gcc_gpll4.clkr,
+ [GCC_GPLL5] = &gcc_gpll5.clkr,
+ [GCC_GPLL7] = &gcc_gpll7.clkr,
+ [GCC_GPLL9] = &gcc_gpll9.clkr,
+ [GCC_GPU_GPLL0_CLK_SRC] = &gcc_gpu_gpll0_clk_src.clkr,
+ [GCC_GPU_GPLL0_DIV_CLK_SRC] = &gcc_gpu_gpll0_div_clk_src.clkr,
+ [GCC_GPU_MEMNOC_GFX_CLK] = &gcc_gpu_memnoc_gfx_clk.clkr,
+ [GCC_GPU_SNOC_DVM_GFX_CLK] = &gcc_gpu_snoc_dvm_gfx_clk.clkr,
+ [GCC_GPU_TCU_THROTTLE_AHB_CLK] = &gcc_gpu_tcu_throttle_ahb_clk.clkr,
+ [GCC_GPU_TCU_THROTTLE_CLK] = &gcc_gpu_tcu_throttle_clk.clkr,
+ [GCC_PCIE_0_AUX_CLK] = &gcc_pcie_0_aux_clk.clkr,
+ [GCC_PCIE_0_AUX_CLK_SRC] = &gcc_pcie_0_aux_clk_src.clkr,
+ [GCC_PCIE_0_CFG_AHB_CLK] = &gcc_pcie_0_cfg_ahb_clk.clkr,
+ [GCC_PCIE_0_MSTR_AXI_CLK] = &gcc_pcie_0_mstr_axi_clk.clkr,
+ [GCC_PCIE_0_PHY_AUX_CLK] = &gcc_pcie_0_phy_aux_clk.clkr,
+ [GCC_PCIE_0_PHY_AUX_CLK_SRC] = &gcc_pcie_0_phy_aux_clk_src.clkr,
+ [GCC_PCIE_0_PHY_RCHNG_CLK] = &gcc_pcie_0_phy_rchng_clk.clkr,
+ [GCC_PCIE_0_PHY_RCHNG_CLK_SRC] = &gcc_pcie_0_phy_rchng_clk_src.clkr,
+ [GCC_PCIE_0_PIPE_CLK] = &gcc_pcie_0_pipe_clk.clkr,
+ [GCC_PCIE_0_PIPE_CLK_SRC] = &gcc_pcie_0_pipe_clk_src.clkr,
+ [GCC_PCIE_0_PIPE_DIV_CLK_SRC] = &gcc_pcie_0_pipe_div_clk_src.clkr,
+ [GCC_PCIE_0_PIPEDIV2_CLK] = &gcc_pcie_0_pipediv2_clk.clkr,
+ [GCC_PCIE_0_SLV_AXI_CLK] = &gcc_pcie_0_slv_axi_clk.clkr,
+ [GCC_PCIE_0_SLV_Q2A_AXI_CLK] = &gcc_pcie_0_slv_q2a_axi_clk.clkr,
+ [GCC_PCIE_1_AUX_CLK] = &gcc_pcie_1_aux_clk.clkr,
+ [GCC_PCIE_1_AUX_CLK_SRC] = &gcc_pcie_1_aux_clk_src.clkr,
+ [GCC_PCIE_1_CFG_AHB_CLK] = &gcc_pcie_1_cfg_ahb_clk.clkr,
+ [GCC_PCIE_1_MSTR_AXI_CLK] = &gcc_pcie_1_mstr_axi_clk.clkr,
+ [GCC_PCIE_1_PHY_AUX_CLK] = &gcc_pcie_1_phy_aux_clk.clkr,
+ [GCC_PCIE_1_PHY_AUX_CLK_SRC] = &gcc_pcie_1_phy_aux_clk_src.clkr,
+ [GCC_PCIE_1_PHY_RCHNG_CLK] = &gcc_pcie_1_phy_rchng_clk.clkr,
+ [GCC_PCIE_1_PHY_RCHNG_CLK_SRC] = &gcc_pcie_1_phy_rchng_clk_src.clkr,
+ [GCC_PCIE_1_PIPE_CLK] = &gcc_pcie_1_pipe_clk.clkr,
+ [GCC_PCIE_1_PIPE_CLK_SRC] = &gcc_pcie_1_pipe_clk_src.clkr,
+ [GCC_PCIE_1_PIPE_DIV_CLK_SRC] = &gcc_pcie_1_pipe_div_clk_src.clkr,
+ [GCC_PCIE_1_PIPEDIV2_CLK] = &gcc_pcie_1_pipediv2_clk.clkr,
+ [GCC_PCIE_1_SLV_AXI_CLK] = &gcc_pcie_1_slv_axi_clk.clkr,
+ [GCC_PCIE_1_SLV_Q2A_AXI_CLK] = &gcc_pcie_1_slv_q2a_axi_clk.clkr,
+ [GCC_PCIE_CLKREF_EN] = &gcc_pcie_clkref_en.clkr,
+ [GCC_PCIE_THROTTLE_CFG_CLK] = &gcc_pcie_throttle_cfg_clk.clkr,
+ [GCC_PDM2_CLK] = &gcc_pdm2_clk.clkr,
+ [GCC_PDM2_CLK_SRC] = &gcc_pdm2_clk_src.clkr,
+ [GCC_PDM_AHB_CLK] = &gcc_pdm_ahb_clk.clkr,
+ [GCC_PDM_XO4_CLK] = &gcc_pdm_xo4_clk.clkr,
+ [GCC_QMIP_CAMERA_NRT_AHB_CLK] = &gcc_qmip_camera_nrt_ahb_clk.clkr,
+ [GCC_QMIP_CAMERA_RT_AHB_CLK] = &gcc_qmip_camera_rt_ahb_clk.clkr,
+ [GCC_QMIP_DISP1_AHB_CLK] = &gcc_qmip_disp1_ahb_clk.clkr,
+ [GCC_QMIP_DISP1_ROT_AHB_CLK] = &gcc_qmip_disp1_rot_ahb_clk.clkr,
+ [GCC_QMIP_DISP_AHB_CLK] = &gcc_qmip_disp_ahb_clk.clkr,
+ [GCC_QMIP_DISP_ROT_AHB_CLK] = &gcc_qmip_disp_rot_ahb_clk.clkr,
+ [GCC_QMIP_VIDEO_CVP_AHB_CLK] = &gcc_qmip_video_cvp_ahb_clk.clkr,
+ [GCC_QMIP_VIDEO_VCODEC_AHB_CLK] = &gcc_qmip_video_vcodec_ahb_clk.clkr,
+ [GCC_QMIP_VIDEO_VCPU_AHB_CLK] = &gcc_qmip_video_vcpu_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP0_CORE_2X_CLK] = &gcc_qupv3_wrap0_core_2x_clk.clkr,
+ [GCC_QUPV3_WRAP0_CORE_CLK] = &gcc_qupv3_wrap0_core_clk.clkr,
+ [GCC_QUPV3_WRAP0_S0_CLK] = &gcc_qupv3_wrap0_s0_clk.clkr,
+ [GCC_QUPV3_WRAP0_S0_CLK_SRC] = &gcc_qupv3_wrap0_s0_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S1_CLK] = &gcc_qupv3_wrap0_s1_clk.clkr,
+ [GCC_QUPV3_WRAP0_S1_CLK_SRC] = &gcc_qupv3_wrap0_s1_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S2_CLK] = &gcc_qupv3_wrap0_s2_clk.clkr,
+ [GCC_QUPV3_WRAP0_S2_CLK_SRC] = &gcc_qupv3_wrap0_s2_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S3_CLK] = &gcc_qupv3_wrap0_s3_clk.clkr,
+ [GCC_QUPV3_WRAP0_S3_CLK_SRC] = &gcc_qupv3_wrap0_s3_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S4_CLK] = &gcc_qupv3_wrap0_s4_clk.clkr,
+ [GCC_QUPV3_WRAP0_S4_CLK_SRC] = &gcc_qupv3_wrap0_s4_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S5_CLK] = &gcc_qupv3_wrap0_s5_clk.clkr,
+ [GCC_QUPV3_WRAP0_S5_CLK_SRC] = &gcc_qupv3_wrap0_s5_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S6_CLK] = &gcc_qupv3_wrap0_s6_clk.clkr,
+ [GCC_QUPV3_WRAP0_S6_CLK_SRC] = &gcc_qupv3_wrap0_s6_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_CORE_2X_CLK] = &gcc_qupv3_wrap1_core_2x_clk.clkr,
+ [GCC_QUPV3_WRAP1_CORE_CLK] = &gcc_qupv3_wrap1_core_clk.clkr,
+ [GCC_QUPV3_WRAP1_S0_CLK] = &gcc_qupv3_wrap1_s0_clk.clkr,
+ [GCC_QUPV3_WRAP1_S0_CLK_SRC] = &gcc_qupv3_wrap1_s0_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S1_CLK] = &gcc_qupv3_wrap1_s1_clk.clkr,
+ [GCC_QUPV3_WRAP1_S1_CLK_SRC] = &gcc_qupv3_wrap1_s1_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S2_CLK] = &gcc_qupv3_wrap1_s2_clk.clkr,
+ [GCC_QUPV3_WRAP1_S2_CLK_SRC] = &gcc_qupv3_wrap1_s2_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S3_CLK] = &gcc_qupv3_wrap1_s3_clk.clkr,
+ [GCC_QUPV3_WRAP1_S3_CLK_SRC] = &gcc_qupv3_wrap1_s3_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S4_CLK] = &gcc_qupv3_wrap1_s4_clk.clkr,
+ [GCC_QUPV3_WRAP1_S4_CLK_SRC] = &gcc_qupv3_wrap1_s4_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S5_CLK] = &gcc_qupv3_wrap1_s5_clk.clkr,
+ [GCC_QUPV3_WRAP1_S5_CLK_SRC] = &gcc_qupv3_wrap1_s5_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S6_CLK] = &gcc_qupv3_wrap1_s6_clk.clkr,
+ [GCC_QUPV3_WRAP1_S6_CLK_SRC] = &gcc_qupv3_wrap1_s6_clk_src.clkr,
+ [GCC_QUPV3_WRAP2_CORE_2X_CLK] = &gcc_qupv3_wrap2_core_2x_clk.clkr,
+ [GCC_QUPV3_WRAP2_CORE_CLK] = &gcc_qupv3_wrap2_core_clk.clkr,
+ [GCC_QUPV3_WRAP2_S0_CLK] = &gcc_qupv3_wrap2_s0_clk.clkr,
+ [GCC_QUPV3_WRAP2_S0_CLK_SRC] = &gcc_qupv3_wrap2_s0_clk_src.clkr,
+ [GCC_QUPV3_WRAP2_S1_CLK] = &gcc_qupv3_wrap2_s1_clk.clkr,
+ [GCC_QUPV3_WRAP2_S1_CLK_SRC] = &gcc_qupv3_wrap2_s1_clk_src.clkr,
+ [GCC_QUPV3_WRAP2_S2_CLK] = &gcc_qupv3_wrap2_s2_clk.clkr,
+ [GCC_QUPV3_WRAP2_S2_CLK_SRC] = &gcc_qupv3_wrap2_s2_clk_src.clkr,
+ [GCC_QUPV3_WRAP2_S3_CLK] = &gcc_qupv3_wrap2_s3_clk.clkr,
+ [GCC_QUPV3_WRAP2_S3_CLK_SRC] = &gcc_qupv3_wrap2_s3_clk_src.clkr,
+ [GCC_QUPV3_WRAP2_S4_CLK] = &gcc_qupv3_wrap2_s4_clk.clkr,
+ [GCC_QUPV3_WRAP2_S4_CLK_SRC] = &gcc_qupv3_wrap2_s4_clk_src.clkr,
+ [GCC_QUPV3_WRAP2_S5_CLK] = &gcc_qupv3_wrap2_s5_clk.clkr,
+ [GCC_QUPV3_WRAP2_S5_CLK_SRC] = &gcc_qupv3_wrap2_s5_clk_src.clkr,
+ [GCC_QUPV3_WRAP2_S6_CLK] = &gcc_qupv3_wrap2_s6_clk.clkr,
+ [GCC_QUPV3_WRAP2_S6_CLK_SRC] = &gcc_qupv3_wrap2_s6_clk_src.clkr,
+ [GCC_QUPV3_WRAP3_CORE_2X_CLK] = &gcc_qupv3_wrap3_core_2x_clk.clkr,
+ [GCC_QUPV3_WRAP3_CORE_CLK] = &gcc_qupv3_wrap3_core_clk.clkr,
+ [GCC_QUPV3_WRAP3_QSPI_CLK] = &gcc_qupv3_wrap3_qspi_clk.clkr,
+ [GCC_QUPV3_WRAP3_S0_CLK] = &gcc_qupv3_wrap3_s0_clk.clkr,
+ [GCC_QUPV3_WRAP3_S0_CLK_SRC] = &gcc_qupv3_wrap3_s0_clk_src.clkr,
+ [GCC_QUPV3_WRAP3_S0_DIV_CLK_SRC] = &gcc_qupv3_wrap3_s0_div_clk_src.clkr,
+ [GCC_QUPV3_WRAP_0_M_AHB_CLK] = &gcc_qupv3_wrap_0_m_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP_0_S_AHB_CLK] = &gcc_qupv3_wrap_0_s_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP_1_M_AHB_CLK] = &gcc_qupv3_wrap_1_m_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP_1_S_AHB_CLK] = &gcc_qupv3_wrap_1_s_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP_2_M_AHB_CLK] = &gcc_qupv3_wrap_2_m_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP_2_S_AHB_CLK] = &gcc_qupv3_wrap_2_s_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP_3_M_AHB_CLK] = &gcc_qupv3_wrap_3_m_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP_3_S_AHB_CLK] = &gcc_qupv3_wrap_3_s_ahb_clk.clkr,
+ [GCC_SDCC1_AHB_CLK] = &gcc_sdcc1_ahb_clk.clkr,
+ [GCC_SDCC1_APPS_CLK] = &gcc_sdcc1_apps_clk.clkr,
+ [GCC_SDCC1_APPS_CLK_SRC] = &gcc_sdcc1_apps_clk_src.clkr,
+ [GCC_SDCC1_ICE_CORE_CLK] = &gcc_sdcc1_ice_core_clk.clkr,
+ [GCC_SDCC1_ICE_CORE_CLK_SRC] = &gcc_sdcc1_ice_core_clk_src.clkr,
+ [GCC_SGMI_CLKREF_EN] = &gcc_sgmi_clkref_en.clkr,
+ [GCC_TSCSS_AHB_CLK] = &gcc_tscss_ahb_clk.clkr,
+ [GCC_TSCSS_CNTR_CLK_SRC] = &gcc_tscss_cntr_clk_src.clkr,
+ [GCC_TSCSS_ETU_CLK] = &gcc_tscss_etu_clk.clkr,
+ [GCC_TSCSS_GLOBAL_CNTR_CLK] = &gcc_tscss_global_cntr_clk.clkr,
+ [GCC_UFS_CARD_AHB_CLK] = &gcc_ufs_card_ahb_clk.clkr,
+ [GCC_UFS_CARD_AXI_CLK] = &gcc_ufs_card_axi_clk.clkr,
+ [GCC_UFS_CARD_AXI_CLK_SRC] = &gcc_ufs_card_axi_clk_src.clkr,
+ [GCC_UFS_CARD_ICE_CORE_CLK] = &gcc_ufs_card_ice_core_clk.clkr,
+ [GCC_UFS_CARD_ICE_CORE_CLK_SRC] = &gcc_ufs_card_ice_core_clk_src.clkr,
+ [GCC_UFS_CARD_PHY_AUX_CLK] = &gcc_ufs_card_phy_aux_clk.clkr,
+ [GCC_UFS_CARD_PHY_AUX_CLK_SRC] = &gcc_ufs_card_phy_aux_clk_src.clkr,
+ [GCC_UFS_CARD_RX_SYMBOL_0_CLK] = &gcc_ufs_card_rx_symbol_0_clk.clkr,
+ [GCC_UFS_CARD_RX_SYMBOL_0_CLK_SRC] = &gcc_ufs_card_rx_symbol_0_clk_src.clkr,
+ [GCC_UFS_CARD_RX_SYMBOL_1_CLK] = &gcc_ufs_card_rx_symbol_1_clk.clkr,
+ [GCC_UFS_CARD_RX_SYMBOL_1_CLK_SRC] = &gcc_ufs_card_rx_symbol_1_clk_src.clkr,
+ [GCC_UFS_CARD_TX_SYMBOL_0_CLK] = &gcc_ufs_card_tx_symbol_0_clk.clkr,
+ [GCC_UFS_CARD_TX_SYMBOL_0_CLK_SRC] = &gcc_ufs_card_tx_symbol_0_clk_src.clkr,
+ [GCC_UFS_CARD_UNIPRO_CORE_CLK] = &gcc_ufs_card_unipro_core_clk.clkr,
+ [GCC_UFS_CARD_UNIPRO_CORE_CLK_SRC] = &gcc_ufs_card_unipro_core_clk_src.clkr,
+ [GCC_UFS_PHY_AHB_CLK] = &gcc_ufs_phy_ahb_clk.clkr,
+ [GCC_UFS_PHY_AXI_CLK] = &gcc_ufs_phy_axi_clk.clkr,
+ [GCC_UFS_PHY_AXI_CLK_SRC] = &gcc_ufs_phy_axi_clk_src.clkr,
+ [GCC_UFS_PHY_AXI_HW_CTL_CLK] = &gcc_ufs_phy_axi_hw_ctl_clk.clkr,
+ [GCC_UFS_PHY_ICE_CORE_CLK] = &gcc_ufs_phy_ice_core_clk.clkr,
+ [GCC_UFS_PHY_ICE_CORE_CLK_SRC] = &gcc_ufs_phy_ice_core_clk_src.clkr,
+ [GCC_UFS_PHY_ICE_CORE_HW_CTL_CLK] = &gcc_ufs_phy_ice_core_hw_ctl_clk.clkr,
+ [GCC_UFS_PHY_PHY_AUX_CLK] = &gcc_ufs_phy_phy_aux_clk.clkr,
+ [GCC_UFS_PHY_PHY_AUX_CLK_SRC] = &gcc_ufs_phy_phy_aux_clk_src.clkr,
+ [GCC_UFS_PHY_PHY_AUX_HW_CTL_CLK] = &gcc_ufs_phy_phy_aux_hw_ctl_clk.clkr,
+ [GCC_UFS_PHY_RX_SYMBOL_0_CLK] = &gcc_ufs_phy_rx_symbol_0_clk.clkr,
+ [GCC_UFS_PHY_RX_SYMBOL_0_CLK_SRC] = &gcc_ufs_phy_rx_symbol_0_clk_src.clkr,
+ [GCC_UFS_PHY_RX_SYMBOL_1_CLK] = &gcc_ufs_phy_rx_symbol_1_clk.clkr,
+ [GCC_UFS_PHY_RX_SYMBOL_1_CLK_SRC] = &gcc_ufs_phy_rx_symbol_1_clk_src.clkr,
+ [GCC_UFS_PHY_TX_SYMBOL_0_CLK] = &gcc_ufs_phy_tx_symbol_0_clk.clkr,
+ [GCC_UFS_PHY_TX_SYMBOL_0_CLK_SRC] = &gcc_ufs_phy_tx_symbol_0_clk_src.clkr,
+ [GCC_UFS_PHY_UNIPRO_CORE_CLK] = &gcc_ufs_phy_unipro_core_clk.clkr,
+ [GCC_UFS_PHY_UNIPRO_CORE_CLK_SRC] = &gcc_ufs_phy_unipro_core_clk_src.clkr,
+ [GCC_UFS_PHY_UNIPRO_CORE_HW_CTL_CLK] = &gcc_ufs_phy_unipro_core_hw_ctl_clk.clkr,
+ [GCC_USB20_MASTER_CLK] = &gcc_usb20_master_clk.clkr,
+ [GCC_USB20_MASTER_CLK_SRC] = &gcc_usb20_master_clk_src.clkr,
+ [GCC_USB20_MOCK_UTMI_CLK] = &gcc_usb20_mock_utmi_clk.clkr,
+ [GCC_USB20_MOCK_UTMI_CLK_SRC] = &gcc_usb20_mock_utmi_clk_src.clkr,
+ [GCC_USB20_MOCK_UTMI_POSTDIV_CLK_SRC] = &gcc_usb20_mock_utmi_postdiv_clk_src.clkr,
+ [GCC_USB20_SLEEP_CLK] = &gcc_usb20_sleep_clk.clkr,
+ [GCC_USB30_PRIM_MASTER_CLK] = &gcc_usb30_prim_master_clk.clkr,
+ [GCC_USB30_PRIM_MASTER_CLK_SRC] = &gcc_usb30_prim_master_clk_src.clkr,
+ [GCC_USB30_PRIM_MOCK_UTMI_CLK] = &gcc_usb30_prim_mock_utmi_clk.clkr,
+ [GCC_USB30_PRIM_MOCK_UTMI_CLK_SRC] = &gcc_usb30_prim_mock_utmi_clk_src.clkr,
+ [GCC_USB30_PRIM_MOCK_UTMI_POSTDIV_CLK_SRC] = &gcc_usb30_prim_mock_utmi_postdiv_clk_src.clkr,
+ [GCC_USB30_PRIM_SLEEP_CLK] = &gcc_usb30_prim_sleep_clk.clkr,
+ [GCC_USB30_SEC_MASTER_CLK] = &gcc_usb30_sec_master_clk.clkr,
+ [GCC_USB30_SEC_MASTER_CLK_SRC] = &gcc_usb30_sec_master_clk_src.clkr,
+ [GCC_USB30_SEC_MOCK_UTMI_CLK] = &gcc_usb30_sec_mock_utmi_clk.clkr,
+ [GCC_USB30_SEC_MOCK_UTMI_CLK_SRC] = &gcc_usb30_sec_mock_utmi_clk_src.clkr,
+ [GCC_USB30_SEC_MOCK_UTMI_POSTDIV_CLK_SRC] = &gcc_usb30_sec_mock_utmi_postdiv_clk_src.clkr,
+ [GCC_USB30_SEC_SLEEP_CLK] = &gcc_usb30_sec_sleep_clk.clkr,
+ [GCC_USB3_PRIM_PHY_AUX_CLK] = &gcc_usb3_prim_phy_aux_clk.clkr,
+ [GCC_USB3_PRIM_PHY_AUX_CLK_SRC] = &gcc_usb3_prim_phy_aux_clk_src.clkr,
+ [GCC_USB3_PRIM_PHY_COM_AUX_CLK] = &gcc_usb3_prim_phy_com_aux_clk.clkr,
+ [GCC_USB3_PRIM_PHY_PIPE_CLK] = &gcc_usb3_prim_phy_pipe_clk.clkr,
+ [GCC_USB3_PRIM_PHY_PIPE_CLK_SRC] = &gcc_usb3_prim_phy_pipe_clk_src.clkr,
+ [GCC_USB3_SEC_PHY_AUX_CLK] = &gcc_usb3_sec_phy_aux_clk.clkr,
+ [GCC_USB3_SEC_PHY_AUX_CLK_SRC] = &gcc_usb3_sec_phy_aux_clk_src.clkr,
+ [GCC_USB3_SEC_PHY_COM_AUX_CLK] = &gcc_usb3_sec_phy_com_aux_clk.clkr,
+ [GCC_USB3_SEC_PHY_PIPE_CLK] = &gcc_usb3_sec_phy_pipe_clk.clkr,
+ [GCC_USB3_SEC_PHY_PIPE_CLK_SRC] = &gcc_usb3_sec_phy_pipe_clk_src.clkr,
+ [GCC_USB_CLKREF_EN] = &gcc_usb_clkref_en.clkr,
+ [GCC_VIDEO_AXI0_CLK] = &gcc_video_axi0_clk.clkr,
+ [GCC_VIDEO_AXI1_CLK] = &gcc_video_axi1_clk.clkr,
+};
+
+static const struct qcom_reset_map gcc_sa8775p_resets[] = {
+ [GCC_CAMERA_BCR] = { 0x32000 },
+ [GCC_DISPLAY1_BCR] = { 0xc7000 },
+ [GCC_DISPLAY_BCR] = { 0x33000 },
+ [GCC_EMAC0_BCR] = { 0xb6000 },
+ [GCC_EMAC1_BCR] = { 0xb4000 },
+ [GCC_GPU_BCR] = { 0x7d000 },
+ [GCC_MMSS_BCR] = { 0x17000 },
+ [GCC_PCIE_0_BCR] = { 0xa9000 },
+ [GCC_PCIE_0_LINK_DOWN_BCR] = { 0xbf000 },
+ [GCC_PCIE_0_NOCSR_COM_PHY_BCR] = { 0xbf008 },
+ [GCC_PCIE_0_PHY_BCR] = { 0xad144 },
+ [GCC_PCIE_0_PHY_NOCSR_COM_PHY_BCR] = { 0xbf00c },
+ [GCC_PCIE_1_BCR] = { 0x77000 },
+ [GCC_PCIE_1_LINK_DOWN_BCR] = { 0xae084 },
+ [GCC_PCIE_1_NOCSR_COM_PHY_BCR] = { 0xae090 },
+ [GCC_PCIE_1_PHY_BCR] = { 0xae08c },
+ [GCC_PCIE_1_PHY_NOCSR_COM_PHY_BCR] = { 0xae094 },
+ [GCC_PDM_BCR] = { 0x3f000 },
+ [GCC_QUPV3_WRAPPER_0_BCR] = { 0x23000 },
+ [GCC_QUPV3_WRAPPER_1_BCR] = { 0x24000 },
+ [GCC_QUPV3_WRAPPER_2_BCR] = { 0x2a000 },
+ [GCC_QUPV3_WRAPPER_3_BCR] = { 0xc4000 },
+ [GCC_SDCC1_BCR] = { 0x20000 },
+ [GCC_TSCSS_BCR] = { 0x21000 },
+ [GCC_UFS_CARD_BCR] = { 0x81000 },
+ [GCC_UFS_PHY_BCR] = { 0x83000 },
+ [GCC_USB20_PRIM_BCR] = { 0x1c000 },
+ [GCC_USB2_PHY_PRIM_BCR] = { 0x5c028 },
+ [GCC_USB2_PHY_SEC_BCR] = { 0x5c02c },
+ [GCC_USB30_PRIM_BCR] = { 0x1b000 },
+ [GCC_USB30_SEC_BCR] = { 0x2f000 },
+ [GCC_USB3_DP_PHY_PRIM_BCR] = { 0x5c008 },
+ [GCC_USB3_DP_PHY_SEC_BCR] = { 0x5c014 },
+ [GCC_USB3_PHY_PRIM_BCR] = { 0x5c000 },
+ [GCC_USB3_PHY_SEC_BCR] = { 0x5c00c },
+ [GCC_USB3_PHY_TERT_BCR] = { 0x5c030 },
+ [GCC_USB3_UNIPHY_MP0_BCR] = { 0x5c018 },
+ [GCC_USB3_UNIPHY_MP1_BCR] = { 0x5c01c },
+ [GCC_USB3PHY_PHY_PRIM_BCR] = { 0x5c004 },
+ [GCC_USB3PHY_PHY_SEC_BCR] = { 0x5c010 },
+ [GCC_USB3UNIPHY_PHY_MP0_BCR] = { 0x5c020 },
+ [GCC_USB3UNIPHY_PHY_MP1_BCR] = { 0x5c024 },
+ [GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x76000 },
+ [GCC_VIDEO_AXI0_CLK_ARES] = { 0x34014, 2 },
+ [GCC_VIDEO_AXI1_CLK_ARES] = { 0x3401c, 2 },
+ [GCC_VIDEO_BCR] = { 0x34000 },
+};
+
+static struct gdsc *gcc_sa8775p_gdscs[] = {
+ [PCIE_0_GDSC] = &pcie_0_gdsc,
+ [PCIE_1_GDSC] = &pcie_1_gdsc,
+ [UFS_CARD_GDSC] = &ufs_card_gdsc,
+ [UFS_PHY_GDSC] = &ufs_phy_gdsc,
+ [USB20_PRIM_GDSC] = &usb20_prim_gdsc,
+ [USB30_PRIM_GDSC] = &usb30_prim_gdsc,
+ [USB30_SEC_GDSC] = &usb30_sec_gdsc,
+ [EMAC0_GDSC] = &emac0_gdsc,
+ [EMAC1_GDSC] = &emac1_gdsc,
+};
+
+static const struct clk_rcg_dfs_data gcc_dfs_clocks[] = {
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s0_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s1_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s2_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s3_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s4_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s5_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s6_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s0_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s1_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s2_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s3_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s4_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s5_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s6_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap2_s0_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap2_s1_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap2_s2_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap2_s3_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap2_s4_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap2_s5_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap2_s6_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap3_s0_clk_src),
+};
+
+static const struct regmap_config gcc_sa8775p_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0xc7018,
+ .fast_io = true,
+};
+
+static const struct qcom_cc_desc gcc_sa8775p_desc = {
+ .config = &gcc_sa8775p_regmap_config,
+ .clks = gcc_sa8775p_clocks,
+ .num_clks = ARRAY_SIZE(gcc_sa8775p_clocks),
+ .resets = gcc_sa8775p_resets,
+ .num_resets = ARRAY_SIZE(gcc_sa8775p_resets),
+ .gdscs = gcc_sa8775p_gdscs,
+ .num_gdscs = ARRAY_SIZE(gcc_sa8775p_gdscs),
+};
+
+static const struct of_device_id gcc_sa8775p_match_table[] = {
+ { .compatible = "qcom,sa8775p-gcc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, gcc_sa8775p_match_table);
+
+static int gcc_sa8775p_probe(struct platform_device *pdev)
+{
+ struct regmap *regmap;
+ int ret;
+
+ regmap = qcom_cc_map(pdev, &gcc_sa8775p_desc);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ ret = qcom_cc_register_rcg_dfs(regmap, gcc_dfs_clocks,
+ ARRAY_SIZE(gcc_dfs_clocks));
+ if (ret)
+ return ret;
+
+ /*
+ * Keep the clocks always-ON
+ * GCC_CAMERA_AHB_CLK, GCC_CAMERA_XO_CLK, GCC_DISP1_AHB_CLK,
+ * GCC_DISP1_XO_CLK, GCC_DISP_AHB_CLK, GCC_DISP_XO_CLK,
+ * GCC_GPU_CFG_AHB_CLK, GCC_VIDEO_AHB_CLK, GCC_VIDEO_XO_CLK.
+ */
+ regmap_update_bits(regmap, 0x32004, BIT(0), BIT(0));
+ regmap_update_bits(regmap, 0x32020, BIT(0), BIT(0));
+ regmap_update_bits(regmap, 0xc7004, BIT(0), BIT(0));
+ regmap_update_bits(regmap, 0xc7018, BIT(0), BIT(0));
+ regmap_update_bits(regmap, 0x33004, BIT(0), BIT(0));
+ regmap_update_bits(regmap, 0x33018, BIT(0), BIT(0));
+ regmap_update_bits(regmap, 0x7d004, BIT(0), BIT(0));
+ regmap_update_bits(regmap, 0x34004, BIT(0), BIT(0));
+ regmap_update_bits(regmap, 0x34024, BIT(0), BIT(0));
+
+ return qcom_cc_really_probe(pdev, &gcc_sa8775p_desc, regmap);
+}
+
+static struct platform_driver gcc_sa8775p_driver = {
+ .probe = gcc_sa8775p_probe,
+ .driver = {
+ .name = "sa8775p-gcc",
+ .of_match_table = gcc_sa8775p_match_table,
+ },
+};
+
+static int __init gcc_sa8775p_init(void)
+{
+ return platform_driver_register(&gcc_sa8775p_driver);
+}
+core_initcall(gcc_sa8775p_init);
+
+static void __exit gcc_sa8775p_exit(void)
+{
+ platform_driver_unregister(&gcc_sa8775p_driver);
+}
+module_exit(gcc_sa8775p_exit);
+
+MODULE_DESCRIPTION("Qualcomm SA8775P GCC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/qcom/gcc-sc7180.c b/drivers/clk/qcom/gcc-sc7180.c
index 2d3980251e78..cef3c77564cf 100644
--- a/drivers/clk/qcom/gcc-sc7180.c
+++ b/drivers/clk/qcom/gcc-sc7180.c
@@ -23,7 +23,6 @@
enum {
P_BI_TCXO,
- P_CORE_BI_PLL_TEST_SE,
P_GPLL0_OUT_EVEN,
P_GPLL0_OUT_MAIN,
P_GPLL1_OUT_MAIN,
@@ -162,21 +161,18 @@ static const struct parent_map gcc_parent_map_0[] = {
{ P_BI_TCXO, 0 },
{ P_GPLL0_OUT_MAIN, 1 },
{ P_GPLL0_OUT_EVEN, 6 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
};
static const struct clk_parent_data gcc_parent_data_0[] = {
{ .fw_name = "bi_tcxo", .name = "bi_tcxo" },
{ .hw = &gpll0.clkr.hw },
{ .hw = &gpll0_out_even.clkr.hw },
- { .fw_name = "core_bi_pll_test_se", .name = "core_bi_pll_test_se" },
};
static const struct clk_parent_data gcc_parent_data_0_ao[] = {
{ .fw_name = "bi_tcxo_ao", .name = "bi_tcxo_ao" },
{ .hw = &gpll0.clkr.hw },
{ .hw = &gpll0_out_even.clkr.hw },
- { .fw_name = "core_bi_pll_test_se", .name = "core_bi_pll_test_se" },
};
static const struct parent_map gcc_parent_map_1[] = {
@@ -184,7 +180,6 @@ static const struct parent_map gcc_parent_map_1[] = {
{ P_GPLL0_OUT_MAIN, 1 },
{ P_GPLL6_OUT_MAIN, 2 },
{ P_GPLL0_OUT_EVEN, 6 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
};
static const struct clk_parent_data gcc_parent_data_1[] = {
@@ -192,7 +187,6 @@ static const struct clk_parent_data gcc_parent_data_1[] = {
{ .hw = &gpll0.clkr.hw },
{ .hw = &gpll6.clkr.hw },
{ .hw = &gpll0_out_even.clkr.hw },
- { .fw_name = "core_bi_pll_test_se", .name = "core_bi_pll_test_se" },
};
static const struct parent_map gcc_parent_map_2[] = {
@@ -201,7 +195,6 @@ static const struct parent_map gcc_parent_map_2[] = {
{ P_GPLL1_OUT_MAIN, 4 },
{ P_GPLL4_OUT_MAIN, 5 },
{ P_GPLL0_OUT_EVEN, 6 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
};
static const struct clk_parent_data gcc_parent_data_2[] = {
@@ -210,19 +203,16 @@ static const struct clk_parent_data gcc_parent_data_2[] = {
{ .hw = &gpll1.clkr.hw },
{ .hw = &gpll4.clkr.hw },
{ .hw = &gpll0_out_even.clkr.hw },
- { .fw_name = "core_bi_pll_test_se", .name = "core_bi_pll_test_se" },
};
static const struct parent_map gcc_parent_map_3[] = {
{ P_BI_TCXO, 0 },
{ P_GPLL0_OUT_MAIN, 1 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
};
static const struct clk_parent_data gcc_parent_data_3[] = {
{ .fw_name = "bi_tcxo", .name = "bi_tcxo" },
{ .hw = &gpll0.clkr.hw },
- { .fw_name = "core_bi_pll_test_se", .name = "core_bi_pll_test_se" },
};
static const struct parent_map gcc_parent_map_4[] = {
@@ -230,7 +220,6 @@ static const struct parent_map gcc_parent_map_4[] = {
{ P_GPLL0_OUT_MAIN, 1 },
{ P_SLEEP_CLK, 5 },
{ P_GPLL0_OUT_EVEN, 6 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
};
static const struct clk_parent_data gcc_parent_data_4[] = {
@@ -238,7 +227,6 @@ static const struct clk_parent_data gcc_parent_data_4[] = {
{ .hw = &gpll0.clkr.hw },
{ .fw_name = "sleep_clk", .name = "sleep_clk" },
{ .hw = &gpll0_out_even.clkr.hw },
- { .fw_name = "core_bi_pll_test_se", .name = "core_bi_pll_test_se" },
};
static const struct parent_map gcc_parent_map_5[] = {
@@ -246,7 +234,6 @@ static const struct parent_map gcc_parent_map_5[] = {
{ P_GPLL0_OUT_MAIN, 1 },
{ P_GPLL7_OUT_MAIN, 3 },
{ P_GPLL0_OUT_EVEN, 6 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
};
static const struct clk_parent_data gcc_parent_data_5[] = {
@@ -254,21 +241,18 @@ static const struct clk_parent_data gcc_parent_data_5[] = {
{ .hw = &gpll0.clkr.hw },
{ .hw = &gpll7.clkr.hw },
{ .hw = &gpll0_out_even.clkr.hw },
- { .fw_name = "core_bi_pll_test_se", .name = "core_bi_pll_test_se" },
};
static const struct parent_map gcc_parent_map_6[] = {
{ P_BI_TCXO, 0 },
{ P_GPLL0_OUT_MAIN, 1 },
{ P_SLEEP_CLK, 5 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
};
static const struct clk_parent_data gcc_parent_data_6[] = {
{ .fw_name = "bi_tcxo", .name = "bi_tcxo" },
{ .hw = &gpll0.clkr.hw },
{ .fw_name = "sleep_clk", .name = "sleep_clk" },
- { .fw_name = "core_bi_pll_test_se", .name = "core_bi_pll_test_se" },
};
static const struct freq_tbl ftbl_gcc_cpuss_ahb_clk_src[] = {
@@ -1987,8 +1971,7 @@ static struct clk_branch gcc_usb30_prim_mock_utmi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb30_prim_mock_utmi_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw =
+ .parent_hws = (const struct clk_hw*[]) {
&gcc_usb30_prim_mock_utmi_clk_src.clkr.hw,
},
.num_parents = 1,
diff --git a/drivers/clk/qcom/gcc-sc7280.c b/drivers/clk/qcom/gcc-sc7280.c
index 46d41ebce2b0..1dc804154031 100644
--- a/drivers/clk/qcom/gcc-sc7280.c
+++ b/drivers/clk/qcom/gcc-sc7280.c
@@ -2760,9 +2760,8 @@ static struct clk_branch gcc_usb30_prim_mock_utmi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb30_prim_mock_utmi_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw =
- &gcc_usb30_prim_mock_utmi_postdiv_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_mock_utmi_postdiv_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2810,9 +2809,8 @@ static struct clk_branch gcc_usb30_sec_mock_utmi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb30_sec_mock_utmi_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw =
- &gcc_usb30_sec_mock_utmi_postdiv_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_sec_mock_utmi_postdiv_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
diff --git a/drivers/clk/qcom/gcc-sdx55.c b/drivers/clk/qcom/gcc-sdx55.c
index 4fca19006a77..d5e17122698c 100644
--- a/drivers/clk/qcom/gcc-sdx55.c
+++ b/drivers/clk/qcom/gcc-sdx55.c
@@ -22,7 +22,6 @@
enum {
P_BI_TCXO,
- P_CORE_BI_PLL_TEST_SE,
P_GPLL0_OUT_EVEN,
P_GPLL0_OUT_MAIN,
P_GPLL4_OUT_EVEN,
@@ -137,21 +136,18 @@ static const struct parent_map gcc_parent_map_0[] = {
{ P_BI_TCXO, 0 },
{ P_GPLL0_OUT_MAIN, 1 },
{ P_GPLL0_OUT_EVEN, 6 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
};
static const struct clk_parent_data gcc_parents_0[] = {
{ .fw_name = "bi_tcxo" },
{ .hw = &gpll0.clkr.hw },
{ .hw = &gpll0_out_even.clkr.hw },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct clk_parent_data gcc_parents_0_ao[] = {
{ .fw_name = "bi_tcxo_ao" },
{ .hw = &gpll0.clkr.hw },
{ .hw = &gpll0_out_even.clkr.hw },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct parent_map gcc_parent_map_2[] = {
@@ -160,7 +156,6 @@ static const struct parent_map gcc_parent_map_2[] = {
{ P_GPLL4_OUT_EVEN, 2 },
{ P_GPLL5_OUT_MAIN, 5 },
{ P_GPLL0_OUT_EVEN, 6 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
};
static const struct clk_parent_data gcc_parents_2[] = {
@@ -169,7 +164,6 @@ static const struct clk_parent_data gcc_parents_2[] = {
{ .hw = &gpll4_out_even.clkr.hw },
{ .hw = &gpll5.clkr.hw },
{ .hw = &gpll0_out_even.clkr.hw },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct parent_map gcc_parent_map_3[] = {
@@ -177,7 +171,6 @@ static const struct parent_map gcc_parent_map_3[] = {
{ P_GPLL0_OUT_MAIN, 1 },
{ P_SLEEP_CLK, 5 },
{ P_GPLL0_OUT_EVEN, 6 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
};
static const struct clk_parent_data gcc_parents_3[] = {
@@ -185,19 +178,16 @@ static const struct clk_parent_data gcc_parents_3[] = {
{ .hw = &gpll0.clkr.hw },
{ .fw_name = "sleep_clk", .name = "sleep_clk" },
{ .hw = &gpll0_out_even.clkr.hw },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct parent_map gcc_parent_map_4[] = {
{ P_BI_TCXO, 0 },
{ P_SLEEP_CLK, 5 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
};
static const struct clk_parent_data gcc_parents_4[] = {
{ .fw_name = "bi_tcxo" },
{ .fw_name = "sleep_clk", .name = "sleep_clk" },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct parent_map gcc_parent_map_5[] = {
@@ -205,7 +195,6 @@ static const struct parent_map gcc_parent_map_5[] = {
{ P_GPLL0_OUT_MAIN, 1 },
{ P_GPLL4_OUT_EVEN, 2 },
{ P_GPLL0_OUT_EVEN, 6 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
};
static const struct clk_parent_data gcc_parents_5[] = {
@@ -213,7 +202,6 @@ static const struct clk_parent_data gcc_parents_5[] = {
{ .hw = &gpll0.clkr.hw },
{ .hw = &gpll4_out_even.clkr.hw },
{ .hw = &gpll0_out_even.clkr.hw },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct freq_tbl ftbl_gcc_blsp1_qup1_i2c_apps_clk_src[] = {
@@ -232,7 +220,7 @@ static struct clk_rcg2 gcc_blsp1_qup1_i2c_apps_clk_src = {
.clkr.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_qup1_i2c_apps_clk_src",
.parent_data = gcc_parents_0,
- .num_parents = 4,
+ .num_parents = ARRAY_SIZE(gcc_parents_0),
.ops = &clk_rcg2_ops,
},
};
@@ -258,7 +246,7 @@ static struct clk_rcg2 gcc_blsp1_qup1_spi_apps_clk_src = {
.clkr.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_qup1_spi_apps_clk_src",
.parent_data = gcc_parents_0,
- .num_parents = 4,
+ .num_parents = ARRAY_SIZE(gcc_parents_0),
.ops = &clk_rcg2_ops,
},
};
@@ -272,7 +260,7 @@ static struct clk_rcg2 gcc_blsp1_qup2_i2c_apps_clk_src = {
.clkr.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_qup2_i2c_apps_clk_src",
.parent_data = gcc_parents_0,
- .num_parents = 4,
+ .num_parents = ARRAY_SIZE(gcc_parents_0),
.ops = &clk_rcg2_ops,
},
};
@@ -286,7 +274,7 @@ static struct clk_rcg2 gcc_blsp1_qup2_spi_apps_clk_src = {
.clkr.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_qup2_spi_apps_clk_src",
.parent_data = gcc_parents_0,
- .num_parents = 4,
+ .num_parents = ARRAY_SIZE(gcc_parents_0),
.ops = &clk_rcg2_ops,
},
};
@@ -300,7 +288,7 @@ static struct clk_rcg2 gcc_blsp1_qup3_i2c_apps_clk_src = {
.clkr.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_qup3_i2c_apps_clk_src",
.parent_data = gcc_parents_0,
- .num_parents = 4,
+ .num_parents = ARRAY_SIZE(gcc_parents_0),
.ops = &clk_rcg2_ops,
},
};
@@ -314,7 +302,7 @@ static struct clk_rcg2 gcc_blsp1_qup3_spi_apps_clk_src = {
.clkr.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_qup3_spi_apps_clk_src",
.parent_data = gcc_parents_0,
- .num_parents = 4,
+ .num_parents = ARRAY_SIZE(gcc_parents_0),
.ops = &clk_rcg2_ops,
},
};
@@ -328,7 +316,7 @@ static struct clk_rcg2 gcc_blsp1_qup4_i2c_apps_clk_src = {
.clkr.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_qup4_i2c_apps_clk_src",
.parent_data = gcc_parents_0,
- .num_parents = 4,
+ .num_parents = ARRAY_SIZE(gcc_parents_0),
.ops = &clk_rcg2_ops,
},
};
@@ -342,7 +330,7 @@ static struct clk_rcg2 gcc_blsp1_qup4_spi_apps_clk_src = {
.clkr.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_qup4_spi_apps_clk_src",
.parent_data = gcc_parents_0,
- .num_parents = 4,
+ .num_parents = ARRAY_SIZE(gcc_parents_0),
.ops = &clk_rcg2_ops,
},
};
@@ -386,7 +374,7 @@ static struct clk_rcg2 gcc_blsp1_uart1_apps_clk_src = {
.clkr.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_uart1_apps_clk_src",
.parent_data = gcc_parents_0,
- .num_parents = 4,
+ .num_parents = ARRAY_SIZE(gcc_parents_0),
.ops = &clk_rcg2_ops,
},
};
@@ -400,7 +388,7 @@ static struct clk_rcg2 gcc_blsp1_uart2_apps_clk_src = {
.clkr.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_uart2_apps_clk_src",
.parent_data = gcc_parents_0,
- .num_parents = 4,
+ .num_parents = ARRAY_SIZE(gcc_parents_0),
.ops = &clk_rcg2_ops,
},
};
@@ -414,7 +402,7 @@ static struct clk_rcg2 gcc_blsp1_uart3_apps_clk_src = {
.clkr.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_uart3_apps_clk_src",
.parent_data = gcc_parents_0,
- .num_parents = 4,
+ .num_parents = ARRAY_SIZE(gcc_parents_0),
.ops = &clk_rcg2_ops,
},
};
@@ -428,7 +416,7 @@ static struct clk_rcg2 gcc_blsp1_uart4_apps_clk_src = {
.clkr.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_uart4_apps_clk_src",
.parent_data = gcc_parents_0,
- .num_parents = 4,
+ .num_parents = ARRAY_SIZE(gcc_parents_0),
.ops = &clk_rcg2_ops,
},
};
@@ -450,7 +438,7 @@ static struct clk_rcg2 gcc_cpuss_ahb_clk_src = {
.clkr.hw.init = &(struct clk_init_data){
.name = "gcc_cpuss_ahb_clk_src",
.parent_data = gcc_parents_0_ao,
- .num_parents = 4,
+ .num_parents = ARRAY_SIZE(gcc_parents_0_ao),
.ops = &clk_rcg2_ops,
},
};
@@ -469,7 +457,7 @@ static struct clk_rcg2 gcc_cpuss_rbcpr_clk_src = {
.clkr.hw.init = &(struct clk_init_data){
.name = "gcc_cpuss_rbcpr_clk_src",
.parent_data = gcc_parents_0_ao,
- .num_parents = 4,
+ .num_parents = ARRAY_SIZE(gcc_parents_0_ao),
.ops = &clk_rcg2_ops,
},
};
@@ -493,7 +481,7 @@ static struct clk_rcg2 gcc_emac_clk_src = {
.clkr.hw.init = &(struct clk_init_data){
.name = "gcc_emac_clk_src",
.parent_data = gcc_parents_5,
- .num_parents = 5,
+ .num_parents = ARRAY_SIZE(gcc_parents_5),
.ops = &clk_rcg2_ops,
},
};
@@ -514,7 +502,7 @@ static struct clk_rcg2 gcc_emac_ptp_clk_src = {
.clkr.hw.init = &(struct clk_init_data){
.name = "gcc_emac_ptp_clk_src",
.parent_data = gcc_parents_2,
- .num_parents = 6,
+ .num_parents = ARRAY_SIZE(gcc_parents_2),
.ops = &clk_rcg2_ops,
},
};
@@ -537,7 +525,7 @@ static struct clk_rcg2 gcc_gp1_clk_src = {
.clkr.hw.init = &(struct clk_init_data){
.name = "gcc_gp1_clk_src",
.parent_data = gcc_parents_3,
- .num_parents = 5,
+ .num_parents = ARRAY_SIZE(gcc_parents_3),
.ops = &clk_rcg2_ops,
},
};
@@ -551,7 +539,7 @@ static struct clk_rcg2 gcc_gp2_clk_src = {
.clkr.hw.init = &(struct clk_init_data){
.name = "gcc_gp2_clk_src",
.parent_data = gcc_parents_3,
- .num_parents = 5,
+ .num_parents = ARRAY_SIZE(gcc_parents_3),
.ops = &clk_rcg2_ops,
},
};
@@ -565,7 +553,7 @@ static struct clk_rcg2 gcc_gp3_clk_src = {
.clkr.hw.init = &(struct clk_init_data){
.name = "gcc_gp3_clk_src",
.parent_data = gcc_parents_3,
- .num_parents = 5,
+ .num_parents = ARRAY_SIZE(gcc_parents_3),
.ops = &clk_rcg2_ops,
},
};
@@ -579,7 +567,7 @@ static struct clk_rcg2 gcc_pcie_aux_phy_clk_src = {
.clkr.hw.init = &(struct clk_init_data){
.name = "gcc_pcie_aux_phy_clk_src",
.parent_data = gcc_parents_4,
- .num_parents = 3,
+ .num_parents = ARRAY_SIZE(gcc_parents_4),
.ops = &clk_rcg2_ops,
},
};
@@ -598,7 +586,7 @@ static struct clk_rcg2 gcc_pcie_rchng_phy_clk_src = {
.clkr.hw.init = &(struct clk_init_data){
.name = "gcc_pcie_rchng_phy_clk_src",
.parent_data = gcc_parents_3,
- .num_parents = 5,
+ .num_parents = ARRAY_SIZE(gcc_parents_3),
.ops = &clk_rcg2_ops,
},
};
@@ -619,7 +607,7 @@ static struct clk_rcg2 gcc_pdm2_clk_src = {
.clkr.hw.init = &(struct clk_init_data){
.name = "gcc_pdm2_clk_src",
.parent_data = gcc_parents_0,
- .num_parents = 4,
+ .num_parents = ARRAY_SIZE(gcc_parents_0),
.ops = &clk_rcg2_ops,
},
};
@@ -633,7 +621,7 @@ static struct clk_rcg2 gcc_sdcc1_apps_clk_src = {
.clkr.hw.init = &(struct clk_init_data){
.name = "gcc_sdcc1_apps_clk_src",
.parent_data = gcc_parents_0,
- .num_parents = 4,
+ .num_parents = ARRAY_SIZE(gcc_parents_0),
.ops = &clk_rcg2_ops,
},
};
@@ -652,7 +640,7 @@ static struct clk_rcg2 gcc_usb30_master_clk_src = {
.clkr.hw.init = &(struct clk_init_data){
.name = "gcc_usb30_master_clk_src",
.parent_data = gcc_parents_0,
- .num_parents = 4,
+ .num_parents = ARRAY_SIZE(gcc_parents_0),
.ops = &clk_rcg2_ops,
},
};
@@ -671,7 +659,7 @@ static struct clk_rcg2 gcc_usb30_mock_utmi_clk_src = {
.clkr.hw.init = &(struct clk_init_data){
.name = "gcc_usb30_mock_utmi_clk_src",
.parent_data = gcc_parents_0,
- .num_parents = 4,
+ .num_parents = ARRAY_SIZE(gcc_parents_0),
.ops = &clk_rcg2_ops,
},
};
@@ -691,7 +679,7 @@ static struct clk_rcg2 gcc_usb3_phy_aux_clk_src = {
.clkr.hw.init = &(struct clk_init_data){
.name = "gcc_usb3_phy_aux_clk_src",
.parent_data = gcc_parents_4,
- .num_parents = 3,
+ .num_parents = ARRAY_SIZE(gcc_parents_4),
.ops = &clk_rcg2_ops,
},
};
diff --git a/drivers/clk/qcom/gcc-sdx65.c b/drivers/clk/qcom/gcc-sdx65.c
index 748ac15b5ed8..b0c17043551d 100644
--- a/drivers/clk/qcom/gcc-sdx65.c
+++ b/drivers/clk/qcom/gcc-sdx65.c
@@ -634,8 +634,8 @@ static struct clk_regmap_div gcc_cpuss_ahb_postdiv_clk_src = {
.width = 4,
.clkr.hw.init = &(struct clk_init_data) {
.name = "gcc_cpuss_ahb_postdiv_clk_src",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_cpuss_ahb_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_cpuss_ahb_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -649,8 +649,8 @@ static struct clk_regmap_div gcc_usb30_mock_utmi_postdiv_clk_src = {
.width = 4,
.clkr.hw.init = &(struct clk_init_data) {
.name = "gcc_usb30_mock_utmi_postdiv_clk_src",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_usb30_mock_utmi_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_mock_utmi_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -692,8 +692,8 @@ static struct clk_branch gcc_blsp1_qup1_i2c_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_qup1_i2c_apps_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_blsp1_qup1_i2c_apps_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_blsp1_qup1_i2c_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -710,8 +710,8 @@ static struct clk_branch gcc_blsp1_qup1_spi_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_qup1_spi_apps_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_blsp1_qup1_spi_apps_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_blsp1_qup1_spi_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -728,8 +728,8 @@ static struct clk_branch gcc_blsp1_qup2_i2c_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_qup2_i2c_apps_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_blsp1_qup2_i2c_apps_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_blsp1_qup2_i2c_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -746,8 +746,8 @@ static struct clk_branch gcc_blsp1_qup2_spi_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_qup2_spi_apps_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_blsp1_qup2_spi_apps_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_blsp1_qup2_spi_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -764,8 +764,8 @@ static struct clk_branch gcc_blsp1_qup3_i2c_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_qup3_i2c_apps_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_blsp1_qup3_i2c_apps_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_blsp1_qup3_i2c_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -782,8 +782,8 @@ static struct clk_branch gcc_blsp1_qup3_spi_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_qup3_spi_apps_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_blsp1_qup3_spi_apps_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_blsp1_qup3_spi_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -800,8 +800,8 @@ static struct clk_branch gcc_blsp1_qup4_i2c_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_qup4_i2c_apps_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_blsp1_qup4_i2c_apps_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_blsp1_qup4_i2c_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -818,8 +818,8 @@ static struct clk_branch gcc_blsp1_qup4_spi_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_qup4_spi_apps_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_blsp1_qup4_spi_apps_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_blsp1_qup4_spi_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -849,8 +849,8 @@ static struct clk_branch gcc_blsp1_uart1_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_uart1_apps_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_blsp1_uart1_apps_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_blsp1_uart1_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -867,8 +867,8 @@ static struct clk_branch gcc_blsp1_uart2_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_uart2_apps_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_blsp1_uart2_apps_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_blsp1_uart2_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -885,8 +885,8 @@ static struct clk_branch gcc_blsp1_uart3_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_uart3_apps_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_blsp1_uart3_apps_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_blsp1_uart3_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -903,8 +903,8 @@ static struct clk_branch gcc_blsp1_uart4_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_blsp1_uart4_apps_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_blsp1_uart4_apps_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_blsp1_uart4_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -936,8 +936,8 @@ static struct clk_branch gcc_gp1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_gp1_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_gp1_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gp1_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -954,8 +954,8 @@ static struct clk_branch gcc_gp2_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_gp2_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_gp2_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gp2_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -972,8 +972,8 @@ static struct clk_branch gcc_gp3_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_gp3_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_gp3_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gp3_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1017,8 +1017,8 @@ static struct clk_branch gcc_pcie_aux_clk = {
.enable_mask = BIT(3),
.hw.init = &(struct clk_init_data){
.name = "gcc_pcie_aux_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_pcie_aux_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_aux_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1073,8 +1073,8 @@ static struct clk_branch gcc_pcie_pipe_clk = {
.enable_mask = BIT(4),
.hw.init = &(struct clk_init_data){
.name = "gcc_pcie_pipe_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_pcie_pipe_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_pipe_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1093,8 +1093,8 @@ static struct clk_branch gcc_pcie_rchng_phy_clk = {
.enable_mask = BIT(7),
.hw.init = &(struct clk_init_data){
.name = "gcc_pcie_rchng_phy_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_pcie_rchng_phy_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_rchng_phy_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1113,8 +1113,8 @@ static struct clk_branch gcc_pcie_sleep_clk = {
.enable_mask = BIT(6),
.hw.init = &(struct clk_init_data){
.name = "gcc_pcie_sleep_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_pcie_aux_phy_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_aux_phy_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1161,8 +1161,8 @@ static struct clk_branch gcc_pdm2_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_pdm2_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_pdm2_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pdm2_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1233,8 +1233,8 @@ static struct clk_branch gcc_sdcc1_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_sdcc1_apps_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_sdcc1_apps_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_sdcc1_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1251,8 +1251,8 @@ static struct clk_branch gcc_usb30_master_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb30_master_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_usb30_master_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_master_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1269,9 +1269,8 @@ static struct clk_branch gcc_usb30_mock_utmi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb30_mock_utmi_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw =
- &gcc_usb30_mock_utmi_postdiv_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_mock_utmi_postdiv_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1327,8 +1326,8 @@ static struct clk_branch gcc_usb3_phy_aux_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb3_phy_aux_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_usb3_phy_aux_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb3_phy_aux_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1369,8 +1368,8 @@ static struct clk_branch gcc_usb3_phy_pipe_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb3_phy_pipe_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_usb3_phy_pipe_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb3_phy_pipe_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
diff --git a/drivers/clk/qcom/gcc-sm6115.c b/drivers/clk/qcom/gcc-sm6115.c
index 565f9912039f..5b8222fea2f7 100644
--- a/drivers/clk/qcom/gcc-sm6115.c
+++ b/drivers/clk/qcom/gcc-sm6115.c
@@ -1258,7 +1258,7 @@ static struct clk_rcg2 gcc_sdcc1_apps_clk_src = {
.name = "gcc_sdcc1_apps_clk_src",
.parent_data = gcc_parents_1,
.num_parents = ARRAY_SIZE(gcc_parents_1),
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_floor_ops,
},
};
@@ -1305,7 +1305,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = {
.name = "gcc_sdcc2_apps_clk_src",
.parent_data = gcc_parents_11,
.num_parents = ARRAY_SIZE(gcc_parents_11),
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_floor_ops,
.flags = CLK_OPS_PARENT_ENABLE,
},
};
diff --git a/drivers/clk/qcom/gcc-sm6375.c b/drivers/clk/qcom/gcc-sm6375.c
index 89a1cc90b145..ad3c4833990d 100644
--- a/drivers/clk/qcom/gcc-sm6375.c
+++ b/drivers/clk/qcom/gcc-sm6375.c
@@ -1766,8 +1766,8 @@ static struct clk_branch gcc_camss_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_camss_axi_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_camss_axi_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_axi_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1784,8 +1784,8 @@ static struct clk_branch gcc_camss_cci_0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_camss_cci_0_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_camss_cci_0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_cci_0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1802,8 +1802,8 @@ static struct clk_branch gcc_camss_cci_1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_camss_cci_1_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_camss_cci_1_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_cci_1_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1820,8 +1820,8 @@ static struct clk_branch gcc_camss_cphy_0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_camss_cphy_0_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_camss_tfe_cphy_rx_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_tfe_cphy_rx_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1838,8 +1838,8 @@ static struct clk_branch gcc_camss_cphy_1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_camss_cphy_1_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_camss_tfe_cphy_rx_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_tfe_cphy_rx_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1856,8 +1856,8 @@ static struct clk_branch gcc_camss_cphy_2_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_camss_cphy_2_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_camss_tfe_cphy_rx_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_tfe_cphy_rx_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1874,8 +1874,8 @@ static struct clk_branch gcc_camss_cphy_3_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_camss_cphy_3_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_camss_tfe_cphy_rx_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_tfe_cphy_rx_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1892,8 +1892,8 @@ static struct clk_branch gcc_camss_csi0phytimer_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_camss_csi0phytimer_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_camss_csi0phytimer_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_csi0phytimer_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1910,8 +1910,8 @@ static struct clk_branch gcc_camss_csi1phytimer_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_camss_csi1phytimer_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_camss_csi1phytimer_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_csi1phytimer_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1928,8 +1928,8 @@ static struct clk_branch gcc_camss_csi2phytimer_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_camss_csi2phytimer_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_camss_csi2phytimer_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_csi2phytimer_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1946,8 +1946,8 @@ static struct clk_branch gcc_camss_csi3phytimer_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_camss_csi3phytimer_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_camss_csi3phytimer_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_csi3phytimer_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1964,8 +1964,8 @@ static struct clk_branch gcc_camss_mclk0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_camss_mclk0_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_camss_mclk0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_mclk0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1982,8 +1982,8 @@ static struct clk_branch gcc_camss_mclk1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_camss_mclk1_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_camss_mclk1_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_mclk1_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2000,8 +2000,8 @@ static struct clk_branch gcc_camss_mclk2_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_camss_mclk2_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_camss_mclk2_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_mclk2_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2018,8 +2018,8 @@ static struct clk_branch gcc_camss_mclk3_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_camss_mclk3_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_camss_mclk3_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_mclk3_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2036,8 +2036,8 @@ static struct clk_branch gcc_camss_mclk4_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_camss_mclk4_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_camss_mclk4_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_mclk4_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2067,8 +2067,8 @@ static struct clk_branch gcc_camss_ope_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_camss_ope_ahb_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_camss_ope_ahb_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_ope_ahb_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2085,8 +2085,8 @@ static struct clk_branch gcc_camss_ope_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_camss_ope_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_camss_ope_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_ope_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2116,8 +2116,8 @@ static struct clk_branch gcc_camss_tfe_0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_camss_tfe_0_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_camss_tfe_0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_tfe_0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2134,8 +2134,8 @@ static struct clk_branch gcc_camss_tfe_0_cphy_rx_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_camss_tfe_0_cphy_rx_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_camss_tfe_cphy_rx_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_tfe_cphy_rx_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2152,8 +2152,8 @@ static struct clk_branch gcc_camss_tfe_0_csid_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_camss_tfe_0_csid_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_camss_tfe_0_csid_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_tfe_0_csid_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2170,8 +2170,8 @@ static struct clk_branch gcc_camss_tfe_1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_camss_tfe_1_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_camss_tfe_1_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_tfe_1_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2188,8 +2188,8 @@ static struct clk_branch gcc_camss_tfe_1_cphy_rx_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_camss_tfe_1_cphy_rx_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_camss_tfe_cphy_rx_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_tfe_cphy_rx_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2206,8 +2206,8 @@ static struct clk_branch gcc_camss_tfe_1_csid_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_camss_tfe_1_csid_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_camss_tfe_1_csid_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_tfe_1_csid_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2224,8 +2224,8 @@ static struct clk_branch gcc_camss_tfe_2_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_camss_tfe_2_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_camss_tfe_2_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_tfe_2_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2242,8 +2242,8 @@ static struct clk_branch gcc_camss_tfe_2_cphy_rx_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_camss_tfe_2_cphy_rx_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_camss_tfe_cphy_rx_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_tfe_cphy_rx_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2260,8 +2260,8 @@ static struct clk_branch gcc_camss_tfe_2_csid_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_camss_tfe_2_csid_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_camss_tfe_2_csid_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_tfe_2_csid_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2278,8 +2278,8 @@ static struct clk_branch gcc_camss_top_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_camss_top_ahb_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_camss_top_ahb_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_camss_top_ahb_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2298,8 +2298,8 @@ static struct clk_branch gcc_cfg_noc_usb3_prim_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_cfg_noc_usb3_prim_axi_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_usb30_prim_master_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_master_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2330,8 +2330,9 @@ static struct clk_regmap_div gcc_disp_gpll0_clk_src = {
.width = 2,
.clkr.hw.init = &(struct clk_init_data) {
.name = "gcc_disp_gpll0_clk_src",
- .parent_names =
- (const char *[]){ "gpll0" },
+ .parent_hws = (const struct clk_hw*[]){
+ &gpll0.clkr.hw,
+ },
.num_parents = 1,
.ops = &clk_regmap_div_ops,
},
@@ -2344,8 +2345,8 @@ static struct clk_branch gcc_disp_gpll0_div_clk_src = {
.enable_mask = BIT(20),
.hw.init = &(struct clk_init_data){
.name = "gcc_disp_gpll0_div_clk_src",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_disp_gpll0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_disp_gpll0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2407,8 +2408,8 @@ static struct clk_branch gcc_gp1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_gp1_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_gp1_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gp1_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2425,8 +2426,8 @@ static struct clk_branch gcc_gp2_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_gp2_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_gp2_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gp2_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2443,8 +2444,8 @@ static struct clk_branch gcc_gp3_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_gp3_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_gp3_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gp3_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2476,8 +2477,8 @@ static struct clk_branch gcc_gpu_gpll0_clk_src = {
.enable_mask = BIT(15),
.hw.init = &(struct clk_init_data){
.name = "gcc_gpu_gpll0_clk_src",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gpll0.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gpll0.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2493,8 +2494,8 @@ static struct clk_branch gcc_gpu_gpll0_div_clk_src = {
.enable_mask = BIT(16),
.hw.init = &(struct clk_init_data){
.name = "gcc_gpu_gpll0_div_clk_src",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gpll0_out_even.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gpll0_out_even.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2554,8 +2555,8 @@ static struct clk_branch gcc_pdm2_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_pdm2_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_pdm2_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pdm2_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2716,8 +2717,8 @@ static struct clk_branch gcc_qupv3_wrap0_s0_clk = {
.enable_mask = BIT(10),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap0_s0_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap0_s0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2734,8 +2735,8 @@ static struct clk_branch gcc_qupv3_wrap0_s1_clk = {
.enable_mask = BIT(11),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap0_s1_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap0_s1_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s1_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2752,8 +2753,8 @@ static struct clk_branch gcc_qupv3_wrap0_s2_clk = {
.enable_mask = BIT(12),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap0_s2_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap0_s2_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s2_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2770,8 +2771,8 @@ static struct clk_branch gcc_qupv3_wrap0_s3_clk = {
.enable_mask = BIT(13),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap0_s3_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap0_s3_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s3_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2788,8 +2789,8 @@ static struct clk_branch gcc_qupv3_wrap0_s4_clk = {
.enable_mask = BIT(14),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap0_s4_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap0_s4_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s4_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2806,8 +2807,8 @@ static struct clk_branch gcc_qupv3_wrap0_s5_clk = {
.enable_mask = BIT(15),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap0_s5_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap0_s5_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s5_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2850,8 +2851,8 @@ static struct clk_branch gcc_qupv3_wrap1_s0_clk = {
.enable_mask = BIT(21),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap1_s0_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap1_s0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2868,8 +2869,8 @@ static struct clk_branch gcc_qupv3_wrap1_s1_clk = {
.enable_mask = BIT(22),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap1_s1_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap1_s1_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s1_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2886,8 +2887,8 @@ static struct clk_branch gcc_qupv3_wrap1_s2_clk = {
.enable_mask = BIT(23),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap1_s2_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap1_s2_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s2_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2904,8 +2905,8 @@ static struct clk_branch gcc_qupv3_wrap1_s3_clk = {
.enable_mask = BIT(24),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap1_s3_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap1_s3_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s3_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2922,8 +2923,8 @@ static struct clk_branch gcc_qupv3_wrap1_s4_clk = {
.enable_mask = BIT(25),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap1_s4_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap1_s4_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s4_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2940,8 +2941,8 @@ static struct clk_branch gcc_qupv3_wrap1_s5_clk = {
.enable_mask = BIT(26),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap1_s5_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap1_s5_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s5_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -3031,8 +3032,8 @@ static struct clk_branch gcc_sdcc1_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_sdcc1_apps_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_sdcc1_apps_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_sdcc1_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -3051,8 +3052,8 @@ static struct clk_branch gcc_sdcc1_ice_core_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_sdcc1_ice_core_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_sdcc1_ice_core_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_sdcc1_ice_core_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -3082,8 +3083,8 @@ static struct clk_branch gcc_sdcc2_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_sdcc2_apps_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_sdcc2_apps_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_sdcc2_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -3102,8 +3103,8 @@ static struct clk_branch gcc_sys_noc_cpuss_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_sys_noc_cpuss_ahb_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_cpuss_ahb_postdiv_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_cpuss_ahb_postdiv_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_IS_CRITICAL | CLK_SET_RATE_PARENT,
@@ -3120,8 +3121,8 @@ static struct clk_branch gcc_sys_noc_ufs_phy_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_sys_noc_ufs_phy_axi_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_ufs_phy_axi_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_axi_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -3140,8 +3141,8 @@ static struct clk_branch gcc_sys_noc_usb3_prim_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_sys_noc_usb3_prim_axi_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_usb30_prim_master_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_master_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -3175,8 +3176,8 @@ static struct clk_branch gcc_ufs_phy_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_ufs_phy_axi_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_ufs_phy_axi_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_axi_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -3195,8 +3196,8 @@ static struct clk_branch gcc_ufs_phy_ice_core_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_ufs_phy_ice_core_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_ufs_phy_ice_core_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_ice_core_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -3215,8 +3216,8 @@ static struct clk_branch gcc_ufs_phy_phy_aux_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_ufs_phy_phy_aux_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_ufs_phy_phy_aux_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_phy_aux_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -3261,8 +3262,8 @@ static struct clk_branch gcc_ufs_phy_unipro_core_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_ufs_phy_unipro_core_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_ufs_phy_unipro_core_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_unipro_core_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -3279,8 +3280,8 @@ static struct clk_branch gcc_usb30_prim_master_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb30_prim_master_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_usb30_prim_master_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_master_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -3297,8 +3298,8 @@ static struct clk_branch gcc_usb30_prim_mock_utmi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb30_prim_mock_utmi_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_usb30_prim_mock_utmi_postdiv_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_mock_utmi_postdiv_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -3367,8 +3368,8 @@ static struct clk_branch gcc_usb3_prim_phy_com_aux_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb3_prim_phy_com_aux_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_usb3_prim_phy_aux_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb3_prim_phy_aux_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -3487,8 +3488,8 @@ static struct clk_branch gcc_video_vcodec0_sys_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_video_vcodec0_sys_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_video_venus_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_video_venus_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -3505,8 +3506,8 @@ static struct clk_branch gcc_video_venus_ctl_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_video_venus_ctl_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_video_venus_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_video_venus_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
diff --git a/drivers/clk/qcom/gcc-sm8150.c b/drivers/clk/qcom/gcc-sm8150.c
index 09cf827addab..70b067f3618c 100644
--- a/drivers/clk/qcom/gcc-sm8150.c
+++ b/drivers/clk/qcom/gcc-sm8150.c
@@ -26,7 +26,6 @@
enum {
P_BI_TCXO,
P_AUD_REF_CLK,
- P_CORE_BI_PLL_TEST_SE,
P_GPLL0_OUT_EVEN,
P_GPLL0_OUT_MAIN,
P_GPLL7_OUT_MAIN,
@@ -117,14 +116,12 @@ static const struct parent_map gcc_parent_map_0[] = {
{ P_BI_TCXO, 0 },
{ P_GPLL0_OUT_MAIN, 1 },
{ P_GPLL0_OUT_EVEN, 6 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
};
static const struct clk_parent_data gcc_parents_0[] = {
{ .fw_name = "bi_tcxo", .name = "bi_tcxo" },
{ .hw = &gpll0.clkr.hw },
{ .hw = &gpll0_out_even.clkr.hw },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct parent_map gcc_parent_map_1[] = {
@@ -132,7 +129,6 @@ static const struct parent_map gcc_parent_map_1[] = {
{ P_GPLL0_OUT_MAIN, 1 },
{ P_SLEEP_CLK, 5 },
{ P_GPLL0_OUT_EVEN, 6 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
};
static const struct clk_parent_data gcc_parents_1[] = {
@@ -140,41 +136,34 @@ static const struct clk_parent_data gcc_parents_1[] = {
{ .hw = &gpll0.clkr.hw },
{ .fw_name = "sleep_clk", .name = "sleep_clk" },
{ .hw = &gpll0_out_even.clkr.hw },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct parent_map gcc_parent_map_2[] = {
{ P_BI_TCXO, 0 },
{ P_SLEEP_CLK, 5 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
};
static const struct clk_parent_data gcc_parents_2[] = {
{ .fw_name = "bi_tcxo", .name = "bi_tcxo" },
{ .fw_name = "sleep_clk", .name = "sleep_clk" },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct parent_map gcc_parent_map_3[] = {
{ P_BI_TCXO, 0 },
{ P_GPLL0_OUT_MAIN, 1 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
};
static const struct clk_parent_data gcc_parents_3[] = {
{ .fw_name = "bi_tcxo", .name = "bi_tcxo" },
{ .hw = &gpll0.clkr.hw },
- { .fw_name = "core_bi_pll_test_se"},
};
static const struct parent_map gcc_parent_map_4[] = {
{ P_BI_TCXO, 0 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
};
static const struct clk_parent_data gcc_parents_4[] = {
{ .fw_name = "bi_tcxo", .name = "bi_tcxo" },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct parent_map gcc_parent_map_5[] = {
@@ -182,7 +171,6 @@ static const struct parent_map gcc_parent_map_5[] = {
{ P_GPLL0_OUT_MAIN, 1 },
{ P_GPLL7_OUT_MAIN, 3 },
{ P_GPLL0_OUT_EVEN, 6 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
};
static const struct clk_parent_data gcc_parents_5[] = {
@@ -190,7 +178,6 @@ static const struct clk_parent_data gcc_parents_5[] = {
{ .hw = &gpll0.clkr.hw },
{ .hw = &gpll7.clkr.hw },
{ .hw = &gpll0_out_even.clkr.hw },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct parent_map gcc_parent_map_6[] = {
@@ -198,7 +185,6 @@ static const struct parent_map gcc_parent_map_6[] = {
{ P_GPLL0_OUT_MAIN, 1 },
{ P_GPLL9_OUT_MAIN, 2 },
{ P_GPLL0_OUT_EVEN, 6 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
};
static const struct clk_parent_data gcc_parents_6[] = {
@@ -206,7 +192,6 @@ static const struct clk_parent_data gcc_parents_6[] = {
{ .hw = &gpll0.clkr.hw },
{ .hw = &gpll9.clkr.hw },
{ .hw = &gpll0_out_even.clkr.hw },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct parent_map gcc_parent_map_7[] = {
@@ -214,7 +199,6 @@ static const struct parent_map gcc_parent_map_7[] = {
{ P_GPLL0_OUT_MAIN, 1 },
{ P_AUD_REF_CLK, 2 },
{ P_GPLL0_OUT_EVEN, 6 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
};
static const struct clk_parent_data gcc_parents_7[] = {
@@ -222,7 +206,6 @@ static const struct clk_parent_data gcc_parents_7[] = {
{ .hw = &gpll0.clkr.hw },
{ .fw_name = "aud_ref_clk", .name = "aud_ref_clk" },
{ .hw = &gpll0_out_even.clkr.hw },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct freq_tbl ftbl_gcc_cpuss_ahb_clk_src[] = {
diff --git a/drivers/clk/qcom/gcc-sm8250.c b/drivers/clk/qcom/gcc-sm8250.c
index a0ba37656b07..b6cf4bc88d4d 100644
--- a/drivers/clk/qcom/gcc-sm8250.c
+++ b/drivers/clk/qcom/gcc-sm8250.c
@@ -2998,9 +2998,8 @@ static struct clk_branch gcc_usb30_prim_mock_utmi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb30_prim_mock_utmi_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw =
- &gcc_usb30_prim_mock_utmi_postdiv_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_mock_utmi_postdiv_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -3048,9 +3047,8 @@ static struct clk_branch gcc_usb30_sec_mock_utmi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb30_sec_mock_utmi_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw =
- &gcc_usb30_sec_mock_utmi_postdiv_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_sec_mock_utmi_postdiv_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
diff --git a/drivers/clk/qcom/gcc-sm8350.c b/drivers/clk/qcom/gcc-sm8350.c
index c3731f96c8e6..af4a1ea28421 100644
--- a/drivers/clk/qcom/gcc-sm8350.c
+++ b/drivers/clk/qcom/gcc-sm8350.c
@@ -22,7 +22,6 @@
enum {
P_BI_TCXO,
- P_CORE_BI_PLL_TEST_SE,
P_GCC_GPLL0_OUT_EVEN,
P_GCC_GPLL0_OUT_MAIN,
P_GCC_GPLL4_OUT_MAIN,
@@ -119,14 +118,12 @@ static const struct parent_map gcc_parent_map_0[] = {
{ P_BI_TCXO, 0 },
{ P_GCC_GPLL0_OUT_MAIN, 1 },
{ P_GCC_GPLL0_OUT_EVEN, 6 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
};
static const struct clk_parent_data gcc_parent_data_0[] = {
{ .fw_name = "bi_tcxo" },
{ .hw = &gcc_gpll0.clkr.hw },
{ .hw = &gcc_gpll0_out_even.clkr.hw },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct parent_map gcc_parent_map_1[] = {
@@ -134,7 +131,6 @@ static const struct parent_map gcc_parent_map_1[] = {
{ P_GCC_GPLL0_OUT_MAIN, 1 },
{ P_SLEEP_CLK, 5 },
{ P_GCC_GPLL0_OUT_EVEN, 6 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
};
static const struct clk_parent_data gcc_parent_data_1[] = {
@@ -142,29 +138,24 @@ static const struct clk_parent_data gcc_parent_data_1[] = {
{ .hw = &gcc_gpll0.clkr.hw },
{ .fw_name = "sleep_clk" },
{ .hw = &gcc_gpll0_out_even.clkr.hw },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct parent_map gcc_parent_map_2[] = {
{ P_BI_TCXO, 0 },
{ P_SLEEP_CLK, 5 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
};
static const struct clk_parent_data gcc_parent_data_2[] = {
{ .fw_name = "bi_tcxo" },
{ .fw_name = "sleep_clk" },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct parent_map gcc_parent_map_3[] = {
{ P_BI_TCXO, 0 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
};
static const struct clk_parent_data gcc_parent_data_3[] = {
{ .fw_name = "bi_tcxo" },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct parent_map gcc_parent_map_4[] = {
@@ -193,7 +184,6 @@ static const struct parent_map gcc_parent_map_6[] = {
{ P_GCC_GPLL9_OUT_MAIN, 2 },
{ P_GCC_GPLL4_OUT_MAIN, 5 },
{ P_GCC_GPLL0_OUT_EVEN, 6 },
- { P_CORE_BI_PLL_TEST_SE, 7 },
};
static const struct clk_parent_data gcc_parent_data_6[] = {
@@ -202,7 +192,6 @@ static const struct clk_parent_data gcc_parent_data_6[] = {
{ .hw = &gcc_gpll9.clkr.hw },
{ .hw = &gcc_gpll4.clkr.hw },
{ .hw = &gcc_gpll0_out_even.clkr.hw },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct parent_map gcc_parent_map_7[] = {
@@ -267,25 +256,21 @@ static const struct clk_parent_data gcc_parent_data_12[] = {
static const struct parent_map gcc_parent_map_13[] = {
{ P_USB3_PHY_WRAPPER_GCC_USB30_PIPE_CLK, 0 },
- { P_CORE_BI_PLL_TEST_SE, 1 },
{ P_BI_TCXO, 2 },
};
static const struct clk_parent_data gcc_parent_data_13[] = {
{ .fw_name = "usb3_phy_wrapper_gcc_usb30_pipe_clk" },
- { .fw_name = "core_bi_pll_test_se" },
{ .fw_name = "bi_tcxo" },
};
static const struct parent_map gcc_parent_map_14[] = {
{ P_USB3_UNI_PHY_SEC_GCC_USB30_PIPE_CLK, 0 },
- { P_CORE_BI_PLL_TEST_SE, 1 },
{ P_BI_TCXO, 2 },
};
static const struct clk_parent_data gcc_parent_data_14[] = {
{ .fw_name = "usb3_uni_phy_sec_gcc_usb30_pipe_clk" },
- { .fw_name = "core_bi_pll_test_se" },
{ .fw_name = "bi_tcxo" },
};
diff --git a/drivers/clk/qcom/gcc-sm8450.c b/drivers/clk/qcom/gcc-sm8450.c
index 666efa5ff978..84764cc3db4f 100644
--- a/drivers/clk/qcom/gcc-sm8450.c
+++ b/drivers/clk/qcom/gcc-sm8450.c
@@ -66,8 +66,8 @@ static struct clk_alpha_pll_postdiv gcc_gpll0_out_even = {
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],
.clkr.hw.init = &(struct clk_init_data){
.name = "gcc_gpll0_out_even",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_gpll0.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gpll0.clkr.hw,
},
.num_parents = 1,
.ops = &clk_alpha_pll_postdiv_lucid_evo_ops,
@@ -1070,8 +1070,8 @@ static struct clk_regmap_div gcc_usb30_prim_mock_utmi_postdiv_clk_src = {
.width = 4,
.clkr.hw.init = &(struct clk_init_data) {
.name = "gcc_usb30_prim_mock_utmi_postdiv_clk_src",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_usb30_prim_mock_utmi_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_mock_utmi_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1119,8 +1119,8 @@ static struct clk_branch gcc_aggre_ufs_phy_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_aggre_ufs_phy_axi_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_ufs_phy_axi_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_axi_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1139,8 +1139,8 @@ static struct clk_branch gcc_aggre_ufs_phy_axi_hw_ctl_clk = {
.enable_mask = BIT(1),
.hw.init = &(struct clk_init_data){
.name = "gcc_aggre_ufs_phy_axi_hw_ctl_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_ufs_phy_axi_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_axi_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1159,8 +1159,8 @@ static struct clk_branch gcc_aggre_usb3_prim_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_aggre_usb3_prim_axi_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_usb30_prim_master_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_master_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1239,8 +1239,8 @@ static struct clk_branch gcc_cfg_noc_usb3_prim_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_cfg_noc_usb3_prim_axi_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_usb30_prim_master_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_master_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1330,8 +1330,8 @@ static struct clk_branch gcc_gp1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_gp1_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_gp1_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gp1_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1348,8 +1348,8 @@ static struct clk_branch gcc_gp2_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_gp2_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_gp2_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gp2_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1366,8 +1366,8 @@ static struct clk_branch gcc_gp3_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_gp3_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_gp3_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gp3_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1383,8 +1383,8 @@ static struct clk_branch gcc_gpu_gpll0_clk_src = {
.enable_mask = BIT(15),
.hw.init = &(struct clk_init_data){
.name = "gcc_gpu_gpll0_clk_src",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_gpll0.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gpll0.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1400,8 +1400,8 @@ static struct clk_branch gcc_gpu_gpll0_div_clk_src = {
.enable_mask = BIT(16),
.hw.init = &(struct clk_init_data){
.name = "gcc_gpu_gpll0_div_clk_src",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_gpll0_out_even.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gpll0_out_even.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1446,8 +1446,8 @@ static struct clk_branch gcc_pcie_0_aux_clk = {
.enable_mask = BIT(3),
.hw.init = &(struct clk_init_data){
.name = "gcc_pcie_0_aux_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_pcie_0_aux_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_0_aux_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1505,8 +1505,8 @@ static struct clk_branch gcc_pcie_0_phy_rchng_clk = {
.enable_mask = BIT(22),
.hw.init = &(struct clk_init_data){
.name = "gcc_pcie_0_phy_rchng_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_pcie_0_phy_rchng_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_0_phy_rchng_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1523,8 +1523,8 @@ static struct clk_branch gcc_pcie_0_pipe_clk = {
.enable_mask = BIT(4),
.hw.init = &(struct clk_init_data){
.name = "gcc_pcie_0_pipe_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_pcie_0_pipe_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_0_pipe_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1569,8 +1569,8 @@ static struct clk_branch gcc_pcie_1_aux_clk = {
.enable_mask = BIT(29),
.hw.init = &(struct clk_init_data){
.name = "gcc_pcie_1_aux_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_pcie_1_aux_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_1_aux_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1628,8 +1628,8 @@ static struct clk_branch gcc_pcie_1_phy_aux_clk = {
.enable_mask = BIT(24),
.hw.init = &(struct clk_init_data){
.name = "gcc_pcie_1_phy_aux_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_pcie_1_phy_aux_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_1_phy_aux_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1646,8 +1646,8 @@ static struct clk_branch gcc_pcie_1_phy_rchng_clk = {
.enable_mask = BIT(23),
.hw.init = &(struct clk_init_data){
.name = "gcc_pcie_1_phy_rchng_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_pcie_1_phy_rchng_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_1_phy_rchng_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1664,8 +1664,8 @@ static struct clk_branch gcc_pcie_1_pipe_clk = {
.enable_mask = BIT(30),
.hw.init = &(struct clk_init_data){
.name = "gcc_pcie_1_pipe_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_pcie_1_pipe_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_1_pipe_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1710,8 +1710,8 @@ static struct clk_branch gcc_pdm2_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_pdm2_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_pdm2_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pdm2_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1917,8 +1917,8 @@ static struct clk_branch gcc_qupv3_wrap0_s0_clk = {
.enable_mask = BIT(10),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap0_s0_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap0_s0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1935,8 +1935,8 @@ static struct clk_branch gcc_qupv3_wrap0_s1_clk = {
.enable_mask = BIT(11),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap0_s1_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap0_s1_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s1_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1953,8 +1953,8 @@ static struct clk_branch gcc_qupv3_wrap0_s2_clk = {
.enable_mask = BIT(12),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap0_s2_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap0_s2_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s2_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1971,8 +1971,8 @@ static struct clk_branch gcc_qupv3_wrap0_s3_clk = {
.enable_mask = BIT(13),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap0_s3_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap0_s3_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s3_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1989,8 +1989,8 @@ static struct clk_branch gcc_qupv3_wrap0_s4_clk = {
.enable_mask = BIT(14),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap0_s4_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap0_s4_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s4_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2007,8 +2007,8 @@ static struct clk_branch gcc_qupv3_wrap0_s5_clk = {
.enable_mask = BIT(15),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap0_s5_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap0_s5_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s5_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2025,8 +2025,8 @@ static struct clk_branch gcc_qupv3_wrap0_s6_clk = {
.enable_mask = BIT(16),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap0_s6_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap0_s6_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s6_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2043,8 +2043,8 @@ static struct clk_branch gcc_qupv3_wrap0_s7_clk = {
.enable_mask = BIT(17),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap0_s7_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap0_s7_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s7_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2087,8 +2087,8 @@ static struct clk_branch gcc_qupv3_wrap1_s0_clk = {
.enable_mask = BIT(22),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap1_s0_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap1_s0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2105,8 +2105,8 @@ static struct clk_branch gcc_qupv3_wrap1_s1_clk = {
.enable_mask = BIT(23),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap1_s1_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap1_s1_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s1_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2123,8 +2123,8 @@ static struct clk_branch gcc_qupv3_wrap1_s2_clk = {
.enable_mask = BIT(24),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap1_s2_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap1_s2_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s2_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2141,8 +2141,8 @@ static struct clk_branch gcc_qupv3_wrap1_s3_clk = {
.enable_mask = BIT(25),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap1_s3_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap1_s3_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s3_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2159,8 +2159,8 @@ static struct clk_branch gcc_qupv3_wrap1_s4_clk = {
.enable_mask = BIT(26),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap1_s4_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap1_s4_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s4_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2177,8 +2177,8 @@ static struct clk_branch gcc_qupv3_wrap1_s5_clk = {
.enable_mask = BIT(27),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap1_s5_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap1_s5_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s5_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2195,8 +2195,8 @@ static struct clk_branch gcc_qupv3_wrap1_s6_clk = {
.enable_mask = BIT(28),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap1_s6_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap1_s6_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s6_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2239,8 +2239,8 @@ static struct clk_branch gcc_qupv3_wrap2_s0_clk = {
.enable_mask = BIT(4),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap2_s0_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap2_s0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2257,8 +2257,8 @@ static struct clk_branch gcc_qupv3_wrap2_s1_clk = {
.enable_mask = BIT(5),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap2_s1_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap2_s1_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s1_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2275,8 +2275,8 @@ static struct clk_branch gcc_qupv3_wrap2_s2_clk = {
.enable_mask = BIT(6),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap2_s2_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap2_s2_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s2_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2293,8 +2293,8 @@ static struct clk_branch gcc_qupv3_wrap2_s3_clk = {
.enable_mask = BIT(7),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap2_s3_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap2_s3_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s3_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2311,8 +2311,8 @@ static struct clk_branch gcc_qupv3_wrap2_s4_clk = {
.enable_mask = BIT(8),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap2_s4_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap2_s4_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s4_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2329,8 +2329,8 @@ static struct clk_branch gcc_qupv3_wrap2_s5_clk = {
.enable_mask = BIT(9),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap2_s5_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap2_s5_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s5_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2347,8 +2347,8 @@ static struct clk_branch gcc_qupv3_wrap2_s6_clk = {
.enable_mask = BIT(10),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap2_s6_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap2_s6_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s6_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2468,8 +2468,8 @@ static struct clk_branch gcc_sdcc2_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_sdcc2_apps_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_sdcc2_apps_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_sdcc2_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2514,8 +2514,8 @@ static struct clk_branch gcc_sdcc4_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_sdcc4_apps_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_sdcc4_apps_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_sdcc4_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2577,8 +2577,8 @@ static struct clk_branch gcc_ufs_phy_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_ufs_phy_axi_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_ufs_phy_axi_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_axi_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2597,8 +2597,8 @@ static struct clk_branch gcc_ufs_phy_axi_hw_ctl_clk = {
.enable_mask = BIT(1),
.hw.init = &(struct clk_init_data){
.name = "gcc_ufs_phy_axi_hw_ctl_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_ufs_phy_axi_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_axi_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2617,8 +2617,8 @@ static struct clk_branch gcc_ufs_phy_ice_core_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_ufs_phy_ice_core_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_ufs_phy_ice_core_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_ice_core_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2637,8 +2637,8 @@ static struct clk_branch gcc_ufs_phy_ice_core_hw_ctl_clk = {
.enable_mask = BIT(1),
.hw.init = &(struct clk_init_data){
.name = "gcc_ufs_phy_ice_core_hw_ctl_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_ufs_phy_ice_core_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_ice_core_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2657,8 +2657,8 @@ static struct clk_branch gcc_ufs_phy_phy_aux_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_ufs_phy_phy_aux_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_ufs_phy_phy_aux_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_phy_aux_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2677,8 +2677,8 @@ static struct clk_branch gcc_ufs_phy_phy_aux_hw_ctl_clk = {
.enable_mask = BIT(1),
.hw.init = &(struct clk_init_data){
.name = "gcc_ufs_phy_phy_aux_hw_ctl_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_ufs_phy_phy_aux_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_phy_aux_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2695,8 +2695,8 @@ static struct clk_branch gcc_ufs_phy_rx_symbol_0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_ufs_phy_rx_symbol_0_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_ufs_phy_rx_symbol_0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_rx_symbol_0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2713,8 +2713,8 @@ static struct clk_branch gcc_ufs_phy_rx_symbol_1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_ufs_phy_rx_symbol_1_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_ufs_phy_rx_symbol_1_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_rx_symbol_1_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2731,8 +2731,8 @@ static struct clk_branch gcc_ufs_phy_tx_symbol_0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_ufs_phy_tx_symbol_0_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_ufs_phy_tx_symbol_0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_tx_symbol_0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2751,8 +2751,8 @@ static struct clk_branch gcc_ufs_phy_unipro_core_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_ufs_phy_unipro_core_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_ufs_phy_unipro_core_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_unipro_core_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2771,8 +2771,8 @@ static struct clk_branch gcc_ufs_phy_unipro_core_hw_ctl_clk = {
.enable_mask = BIT(1),
.hw.init = &(struct clk_init_data){
.name = "gcc_ufs_phy_unipro_core_hw_ctl_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_ufs_phy_unipro_core_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_unipro_core_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2789,8 +2789,8 @@ static struct clk_branch gcc_usb30_prim_master_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb30_prim_master_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_usb30_prim_master_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_master_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2807,8 +2807,8 @@ static struct clk_branch gcc_usb30_prim_mock_utmi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb30_prim_mock_utmi_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_usb30_prim_mock_utmi_postdiv_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_mock_utmi_postdiv_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2851,8 +2851,8 @@ static struct clk_branch gcc_usb3_prim_phy_aux_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb3_prim_phy_aux_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_usb3_prim_phy_aux_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb3_prim_phy_aux_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2869,8 +2869,8 @@ static struct clk_branch gcc_usb3_prim_phy_com_aux_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb3_prim_phy_com_aux_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_usb3_prim_phy_aux_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb3_prim_phy_aux_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2889,8 +2889,8 @@ static struct clk_branch gcc_usb3_prim_phy_pipe_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb3_prim_phy_pipe_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_usb3_prim_phy_pipe_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb3_prim_phy_pipe_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
diff --git a/drivers/clk/qcom/gcc-sm8550.c b/drivers/clk/qcom/gcc-sm8550.c
index 81d630c666d1..277cd4f020ff 100644
--- a/drivers/clk/qcom/gcc-sm8550.c
+++ b/drivers/clk/qcom/gcc-sm8550.c
@@ -82,8 +82,8 @@ static struct clk_alpha_pll_postdiv gcc_gpll0_out_even = {
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
.clkr.hw.init = &(struct clk_init_data){
.name = "gcc_gpll0_out_even",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_gpll0.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gpll0.clkr.hw,
},
.num_parents = 1,
.ops = &clk_alpha_pll_postdiv_lucid_ole_ops,
@@ -1198,8 +1198,8 @@ static struct clk_regmap_div gcc_usb30_prim_mock_utmi_postdiv_clk_src = {
.width = 4,
.clkr.hw.init = &(struct clk_init_data) {
.name = "gcc_usb30_prim_mock_utmi_postdiv_clk_src",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_usb30_prim_mock_utmi_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_mock_utmi_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1232,8 +1232,8 @@ static struct clk_branch gcc_aggre_ufs_phy_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_aggre_ufs_phy_axi_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_ufs_phy_axi_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_axi_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1252,8 +1252,8 @@ static struct clk_branch gcc_aggre_ufs_phy_axi_hw_ctl_clk = {
.enable_mask = BIT(1),
.hw.init = &(struct clk_init_data){
.name = "gcc_aggre_ufs_phy_axi_hw_ctl_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_ufs_phy_axi_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_axi_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1272,8 +1272,8 @@ static struct clk_branch gcc_aggre_usb3_prim_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_aggre_usb3_prim_axi_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_usb30_prim_master_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_master_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1352,8 +1352,8 @@ static struct clk_branch gcc_cfg_noc_usb3_prim_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_cfg_noc_usb3_prim_axi_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_usb30_prim_master_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_master_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1430,8 +1430,8 @@ static struct clk_branch gcc_gp1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_gp1_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_gp1_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gp1_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1448,8 +1448,8 @@ static struct clk_branch gcc_gp2_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_gp2_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_gp2_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gp2_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1466,8 +1466,8 @@ static struct clk_branch gcc_gp3_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_gp3_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_gp3_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gp3_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1483,8 +1483,8 @@ static struct clk_branch gcc_gpu_gpll0_clk_src = {
.enable_mask = BIT(15),
.hw.init = &(struct clk_init_data){
.name = "gcc_gpu_gpll0_clk_src",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_gpll0.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gpll0.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1500,8 +1500,8 @@ static struct clk_branch gcc_gpu_gpll0_div_clk_src = {
.enable_mask = BIT(16),
.hw.init = &(struct clk_init_data){
.name = "gcc_gpu_gpll0_div_clk_src",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_gpll0_out_even.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gpll0_out_even.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1546,8 +1546,8 @@ static struct clk_branch gcc_pcie_0_aux_clk = {
.enable_mask = BIT(3),
.hw.init = &(struct clk_init_data){
.name = "gcc_pcie_0_aux_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_pcie_0_aux_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_0_aux_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1594,8 +1594,8 @@ static struct clk_branch gcc_pcie_0_phy_rchng_clk = {
.enable_mask = BIT(22),
.hw.init = &(struct clk_init_data){
.name = "gcc_pcie_0_phy_rchng_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_pcie_0_phy_rchng_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_0_phy_rchng_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1612,8 +1612,8 @@ static struct clk_branch gcc_pcie_0_pipe_clk = {
.enable_mask = BIT(4),
.hw.init = &(struct clk_init_data){
.name = "gcc_pcie_0_pipe_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_pcie_0_pipe_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_0_pipe_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1658,8 +1658,8 @@ static struct clk_branch gcc_pcie_1_aux_clk = {
.enable_mask = BIT(29),
.hw.init = &(struct clk_init_data){
.name = "gcc_pcie_1_aux_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_pcie_1_aux_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_1_aux_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1706,8 +1706,8 @@ static struct clk_branch gcc_pcie_1_phy_aux_clk = {
.enable_mask = BIT(24),
.hw.init = &(struct clk_init_data){
.name = "gcc_pcie_1_phy_aux_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_pcie_1_phy_aux_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_1_phy_aux_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1724,8 +1724,8 @@ static struct clk_branch gcc_pcie_1_phy_rchng_clk = {
.enable_mask = BIT(23),
.hw.init = &(struct clk_init_data){
.name = "gcc_pcie_1_phy_rchng_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_pcie_1_phy_rchng_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_1_phy_rchng_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1742,8 +1742,8 @@ static struct clk_branch gcc_pcie_1_pipe_clk = {
.enable_mask = BIT(30),
.hw.init = &(struct clk_init_data){
.name = "gcc_pcie_1_pipe_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_pcie_1_pipe_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_1_pipe_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1788,8 +1788,8 @@ static struct clk_branch gcc_pdm2_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_pdm2_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_pdm2_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pdm2_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1982,8 +1982,8 @@ static struct clk_branch gcc_qupv3_i2c_s0_clk = {
.enable_mask = BIT(10),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_i2c_s0_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_i2c_s0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_i2c_s0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2000,8 +2000,8 @@ static struct clk_branch gcc_qupv3_i2c_s1_clk = {
.enable_mask = BIT(11),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_i2c_s1_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_i2c_s1_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_i2c_s1_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2018,8 +2018,8 @@ static struct clk_branch gcc_qupv3_i2c_s2_clk = {
.enable_mask = BIT(12),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_i2c_s2_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_i2c_s2_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_i2c_s2_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2036,8 +2036,8 @@ static struct clk_branch gcc_qupv3_i2c_s3_clk = {
.enable_mask = BIT(13),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_i2c_s3_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_i2c_s3_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_i2c_s3_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2054,8 +2054,8 @@ static struct clk_branch gcc_qupv3_i2c_s4_clk = {
.enable_mask = BIT(14),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_i2c_s4_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_i2c_s4_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_i2c_s4_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2072,8 +2072,8 @@ static struct clk_branch gcc_qupv3_i2c_s5_clk = {
.enable_mask = BIT(15),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_i2c_s5_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_i2c_s5_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_i2c_s5_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2090,8 +2090,8 @@ static struct clk_branch gcc_qupv3_i2c_s6_clk = {
.enable_mask = BIT(16),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_i2c_s6_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_i2c_s6_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_i2c_s6_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2108,8 +2108,8 @@ static struct clk_branch gcc_qupv3_i2c_s7_clk = {
.enable_mask = BIT(17),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_i2c_s7_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_i2c_s7_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_i2c_s7_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2126,8 +2126,8 @@ static struct clk_branch gcc_qupv3_i2c_s8_clk = {
.enable_mask = BIT(14),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_i2c_s8_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_i2c_s8_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_i2c_s8_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2144,8 +2144,8 @@ static struct clk_branch gcc_qupv3_i2c_s9_clk = {
.enable_mask = BIT(15),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_i2c_s9_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_i2c_s9_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_i2c_s9_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2203,8 +2203,8 @@ static struct clk_branch gcc_qupv3_wrap1_s0_clk = {
.enable_mask = BIT(22),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap1_s0_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap1_s0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2221,8 +2221,8 @@ static struct clk_branch gcc_qupv3_wrap1_s1_clk = {
.enable_mask = BIT(23),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap1_s1_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap1_s1_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s1_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2239,8 +2239,8 @@ static struct clk_branch gcc_qupv3_wrap1_s2_clk = {
.enable_mask = BIT(24),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap1_s2_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap1_s2_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s2_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2257,8 +2257,8 @@ static struct clk_branch gcc_qupv3_wrap1_s3_clk = {
.enable_mask = BIT(25),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap1_s3_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap1_s3_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s3_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2275,8 +2275,8 @@ static struct clk_branch gcc_qupv3_wrap1_s4_clk = {
.enable_mask = BIT(26),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap1_s4_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap1_s4_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s4_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2293,8 +2293,8 @@ static struct clk_branch gcc_qupv3_wrap1_s5_clk = {
.enable_mask = BIT(27),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap1_s5_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap1_s5_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s5_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2311,8 +2311,8 @@ static struct clk_branch gcc_qupv3_wrap1_s6_clk = {
.enable_mask = BIT(28),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap1_s6_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap1_s6_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s6_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2329,8 +2329,8 @@ static struct clk_branch gcc_qupv3_wrap1_s7_clk = {
.enable_mask = BIT(16),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap1_s7_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap1_s7_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s7_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2373,8 +2373,8 @@ static struct clk_branch gcc_qupv3_wrap2_s0_clk = {
.enable_mask = BIT(4),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap2_s0_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap2_s0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2391,8 +2391,8 @@ static struct clk_branch gcc_qupv3_wrap2_s1_clk = {
.enable_mask = BIT(5),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap2_s1_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap2_s1_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s1_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2409,8 +2409,8 @@ static struct clk_branch gcc_qupv3_wrap2_s2_clk = {
.enable_mask = BIT(6),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap2_s2_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap2_s2_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s2_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2427,8 +2427,8 @@ static struct clk_branch gcc_qupv3_wrap2_s3_clk = {
.enable_mask = BIT(7),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap2_s3_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap2_s3_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s3_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2445,8 +2445,8 @@ static struct clk_branch gcc_qupv3_wrap2_s4_clk = {
.enable_mask = BIT(8),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap2_s4_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap2_s4_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s4_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2463,8 +2463,8 @@ static struct clk_branch gcc_qupv3_wrap2_s5_clk = {
.enable_mask = BIT(9),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap2_s5_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap2_s5_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s5_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2481,8 +2481,8 @@ static struct clk_branch gcc_qupv3_wrap2_s6_clk = {
.enable_mask = BIT(10),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap2_s6_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap2_s6_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s6_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2499,8 +2499,8 @@ static struct clk_branch gcc_qupv3_wrap2_s7_clk = {
.enable_mask = BIT(17),
.hw.init = &(struct clk_init_data){
.name = "gcc_qupv3_wrap2_s7_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_qupv3_wrap2_s7_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s7_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2590,8 +2590,8 @@ static struct clk_branch gcc_sdcc2_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_sdcc2_apps_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_sdcc2_apps_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_sdcc2_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2621,8 +2621,8 @@ static struct clk_branch gcc_sdcc4_apps_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_sdcc4_apps_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_sdcc4_apps_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_sdcc4_apps_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2656,8 +2656,8 @@ static struct clk_branch gcc_ufs_phy_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_ufs_phy_axi_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_ufs_phy_axi_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_axi_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2676,8 +2676,8 @@ static struct clk_branch gcc_ufs_phy_axi_hw_ctl_clk = {
.enable_mask = BIT(1),
.hw.init = &(struct clk_init_data){
.name = "gcc_ufs_phy_axi_hw_ctl_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_ufs_phy_axi_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_axi_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2696,8 +2696,8 @@ static struct clk_branch gcc_ufs_phy_ice_core_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_ufs_phy_ice_core_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_ufs_phy_ice_core_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_ice_core_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2716,8 +2716,8 @@ static struct clk_branch gcc_ufs_phy_ice_core_hw_ctl_clk = {
.enable_mask = BIT(1),
.hw.init = &(struct clk_init_data){
.name = "gcc_ufs_phy_ice_core_hw_ctl_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_ufs_phy_ice_core_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_ice_core_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2736,8 +2736,8 @@ static struct clk_branch gcc_ufs_phy_phy_aux_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_ufs_phy_phy_aux_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_ufs_phy_phy_aux_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_phy_aux_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2756,8 +2756,8 @@ static struct clk_branch gcc_ufs_phy_phy_aux_hw_ctl_clk = {
.enable_mask = BIT(1),
.hw.init = &(struct clk_init_data){
.name = "gcc_ufs_phy_phy_aux_hw_ctl_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_ufs_phy_phy_aux_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_phy_aux_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2774,8 +2774,8 @@ static struct clk_branch gcc_ufs_phy_rx_symbol_0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_ufs_phy_rx_symbol_0_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_ufs_phy_rx_symbol_0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_rx_symbol_0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2792,8 +2792,8 @@ static struct clk_branch gcc_ufs_phy_rx_symbol_1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_ufs_phy_rx_symbol_1_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_ufs_phy_rx_symbol_1_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_rx_symbol_1_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2810,8 +2810,8 @@ static struct clk_branch gcc_ufs_phy_tx_symbol_0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_ufs_phy_tx_symbol_0_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_ufs_phy_tx_symbol_0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_tx_symbol_0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2830,8 +2830,8 @@ static struct clk_branch gcc_ufs_phy_unipro_core_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_ufs_phy_unipro_core_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_ufs_phy_unipro_core_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_unipro_core_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2850,8 +2850,8 @@ static struct clk_branch gcc_ufs_phy_unipro_core_hw_ctl_clk = {
.enable_mask = BIT(1),
.hw.init = &(struct clk_init_data){
.name = "gcc_ufs_phy_unipro_core_hw_ctl_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_ufs_phy_unipro_core_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_unipro_core_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2868,8 +2868,8 @@ static struct clk_branch gcc_usb30_prim_master_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb30_prim_master_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_usb30_prim_master_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_master_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2886,8 +2886,8 @@ static struct clk_branch gcc_usb30_prim_mock_utmi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb30_prim_mock_utmi_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_usb30_prim_mock_utmi_postdiv_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_mock_utmi_postdiv_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2917,8 +2917,8 @@ static struct clk_branch gcc_usb3_prim_phy_aux_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb3_prim_phy_aux_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_usb3_prim_phy_aux_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb3_prim_phy_aux_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2935,8 +2935,8 @@ static struct clk_branch gcc_usb3_prim_phy_com_aux_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb3_prim_phy_com_aux_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_usb3_prim_phy_aux_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb3_prim_phy_aux_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2955,8 +2955,8 @@ static struct clk_branch gcc_usb3_prim_phy_pipe_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb3_prim_phy_pipe_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gcc_usb3_prim_phy_pipe_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb3_prim_phy_pipe_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c
index 9e4d6ce891aa..5358e28122ab 100644
--- a/drivers/clk/qcom/gdsc.c
+++ b/drivers/clk/qcom/gdsc.c
@@ -136,7 +136,8 @@ static int gdsc_update_collapse_bit(struct gdsc *sc, bool val)
return 0;
}
-static int gdsc_toggle_logic(struct gdsc *sc, enum gdsc_status status)
+static int gdsc_toggle_logic(struct gdsc *sc, enum gdsc_status status,
+ bool wait)
{
int ret;
@@ -149,7 +150,7 @@ static int gdsc_toggle_logic(struct gdsc *sc, enum gdsc_status status)
ret = gdsc_update_collapse_bit(sc, status == GDSC_OFF);
/* If disabling votable gdscs, don't poll on status */
- if ((sc->flags & VOTABLE) && status == GDSC_OFF) {
+ if ((sc->flags & VOTABLE) && status == GDSC_OFF && !wait) {
/*
* Add a short delay here to ensure that an enable
* right after it was disabled does not put it in an
@@ -275,7 +276,7 @@ static int gdsc_enable(struct generic_pm_domain *domain)
gdsc_deassert_clamp_io(sc);
}
- ret = gdsc_toggle_logic(sc, GDSC_ON);
+ ret = gdsc_toggle_logic(sc, GDSC_ON, false);
if (ret)
return ret;
@@ -352,7 +353,7 @@ static int gdsc_disable(struct generic_pm_domain *domain)
if (sc->pwrsts == PWRSTS_RET_ON)
return 0;
- ret = gdsc_toggle_logic(sc, GDSC_OFF);
+ ret = gdsc_toggle_logic(sc, GDSC_OFF, domain->synced_poweroff);
if (ret)
return ret;
@@ -392,7 +393,7 @@ static int gdsc_init(struct gdsc *sc)
/* Force gdsc ON if only ON state is supported */
if (sc->pwrsts == PWRSTS_ON) {
- ret = gdsc_toggle_logic(sc, GDSC_ON);
+ ret = gdsc_toggle_logic(sc, GDSC_ON, false);
if (ret)
return ret;
}
diff --git a/drivers/clk/qcom/gpucc-msm8998.c b/drivers/clk/qcom/gpucc-msm8998.c
index a925ac90018d..f929e0f2333f 100644
--- a/drivers/clk/qcom/gpucc-msm8998.c
+++ b/drivers/clk/qcom/gpucc-msm8998.c
@@ -106,9 +106,9 @@ static const struct parent_map gpu_xo_gpupll0_map[] = {
{ P_GPUPLL0_OUT_EVEN, 1 },
};
-static const struct clk_parent_data gpu_xo_gpupll0[] = {
- { .hw = &gpucc_cxo_clk.clkr.hw },
- { .hw = &gpupll0_out_even.clkr.hw },
+static const struct clk_hw *gpu_xo_gpupll0[] = {
+ &gpucc_cxo_clk.clkr.hw,
+ &gpupll0_out_even.clkr.hw,
};
static const struct freq_tbl ftbl_rbcpr_clk_src[] = {
@@ -142,7 +142,7 @@ static struct clk_rcg2 gfx3d_clk_src = {
.freq_tbl = ftbl_gfx3d_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "gfx3d_clk_src",
- .parent_data = gpu_xo_gpupll0,
+ .parent_hws = gpu_xo_gpupll0,
.num_parents = ARRAY_SIZE(gpu_xo_gpupll0),
.ops = &clk_rcg2_ops,
.flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
diff --git a/drivers/clk/qcom/gpucc-sc7180.c b/drivers/clk/qcom/gpucc-sc7180.c
index d738251cba17..3f92f0b43be6 100644
--- a/drivers/clk/qcom/gpucc-sc7180.c
+++ b/drivers/clk/qcom/gpucc-sc7180.c
@@ -21,8 +21,6 @@
#define CX_GMU_CBCR_SLEEP_SHIFT 4
#define CX_GMU_CBCR_WAKE_MASK 0xF
#define CX_GMU_CBCR_WAKE_SHIFT 8
-#define CLK_DIS_WAIT_SHIFT 12
-#define CLK_DIS_WAIT_MASK (0xf << CLK_DIS_WAIT_SHIFT)
enum {
P_BI_TCXO,
@@ -108,8 +106,8 @@ static struct clk_branch gpu_cc_cx_gmu_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gpu_cc_cx_gmu_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &gpu_cc_gmu_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &gpu_cc_gmu_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -160,6 +158,7 @@ static struct clk_branch gpu_cc_cxo_clk = {
static struct gdsc cx_gdsc = {
.gdscr = 0x106c,
.gds_hw_ctrl = 0x1540,
+ .clk_dis_wait_val = 8,
.pd = {
.name = "cx_gdsc",
},
@@ -242,10 +241,6 @@ static int gpu_cc_sc7180_probe(struct platform_device *pdev)
value = 0xF << CX_GMU_CBCR_WAKE_SHIFT | 0xF << CX_GMU_CBCR_SLEEP_SHIFT;
regmap_update_bits(regmap, 0x1098, mask, value);
- /* Configure clk_dis_wait for gpu_cx_gdsc */
- regmap_update_bits(regmap, 0x106c, CLK_DIS_WAIT_MASK,
- 8 << CLK_DIS_WAIT_SHIFT);
-
return qcom_cc_really_probe(pdev, &gpu_cc_sc7180_desc, regmap);
}
diff --git a/drivers/clk/qcom/gpucc-sdm845.c b/drivers/clk/qcom/gpucc-sdm845.c
index 110b54401bc6..970d7414bdf0 100644
--- a/drivers/clk/qcom/gpucc-sdm845.c
+++ b/drivers/clk/qcom/gpucc-sdm845.c
@@ -22,8 +22,6 @@
#define CX_GMU_CBCR_SLEEP_SHIFT 4
#define CX_GMU_CBCR_WAKE_MASK 0xf
#define CX_GMU_CBCR_WAKE_SHIFT 8
-#define CLK_DIS_WAIT_SHIFT 12
-#define CLK_DIS_WAIT_MASK (0xf << CLK_DIS_WAIT_SHIFT)
enum {
P_BI_TCXO,
@@ -121,6 +119,7 @@ static struct clk_branch gpu_cc_cxo_clk = {
static struct gdsc gpu_cx_gdsc = {
.gdscr = 0x106c,
.gds_hw_ctrl = 0x1540,
+ .clk_dis_wait_val = 0x8,
.pd = {
.name = "gpu_cx_gdsc",
},
@@ -193,10 +192,6 @@ static int gpu_cc_sdm845_probe(struct platform_device *pdev)
value = 0xf << CX_GMU_CBCR_WAKE_SHIFT | 0xf << CX_GMU_CBCR_SLEEP_SHIFT;
regmap_update_bits(regmap, 0x1098, mask, value);
- /* Configure clk_dis_wait for gpu_cx_gdsc */
- regmap_update_bits(regmap, 0x106c, CLK_DIS_WAIT_MASK,
- 8 << CLK_DIS_WAIT_SHIFT);
-
return qcom_cc_really_probe(pdev, &gpu_cc_sdm845_desc, regmap);
}
diff --git a/drivers/clk/qcom/krait-cc.c b/drivers/clk/qcom/krait-cc.c
index 2f9287c263ec..410ae8390f1c 100644
--- a/drivers/clk/qcom/krait-cc.c
+++ b/drivers/clk/qcom/krait-cc.c
@@ -376,8 +376,8 @@ static int krait_cc_probe(struct platform_device *pdev)
for_each_possible_cpu(cpu) {
mux = krait_add_clks(dev, cpu, id->data);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
+ if (IS_ERR(mux))
+ return PTR_ERR(mux);
clks[cpu] = mux->clk;
}
diff --git a/drivers/clk/qcom/lpasscc-sc7280.c b/drivers/clk/qcom/lpasscc-sc7280.c
index 5c1e17bd0d76..48432010ce24 100644
--- a/drivers/clk/qcom/lpasscc-sc7280.c
+++ b/drivers/clk/qcom/lpasscc-sc7280.c
@@ -107,10 +107,13 @@ static int lpass_cc_sc7280_probe(struct platform_device *pdev)
const struct qcom_cc_desc *desc;
int ret;
- pm_runtime_enable(&pdev->dev);
+ ret = devm_pm_runtime_enable(&pdev->dev);
+ if (ret)
+ return ret;
+
ret = pm_clk_create(&pdev->dev);
if (ret)
- goto disable_pm_runtime;
+ return ret;
ret = pm_clk_add(&pdev->dev, "iface");
if (ret < 0) {
@@ -137,9 +140,6 @@ static int lpass_cc_sc7280_probe(struct platform_device *pdev)
destroy_pm_clk:
pm_clk_destroy(&pdev->dev);
-disable_pm_runtime:
- pm_runtime_disable(&pdev->dev);
-
return ret;
}
diff --git a/drivers/clk/qcom/lpasscorecc-sc7180.c b/drivers/clk/qcom/lpasscorecc-sc7180.c
index 33ed91c67e1c..010867dcc2ef 100644
--- a/drivers/clk/qcom/lpasscorecc-sc7180.c
+++ b/drivers/clk/qcom/lpasscorecc-sc7180.c
@@ -93,8 +93,8 @@ static struct clk_alpha_pll_postdiv lpass_lpaaudio_dig_pll_out_odd = {
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
.clkr.hw.init = &(struct clk_init_data){
.name = "lpass_lpaaudio_dig_pll_out_odd",
- .parent_data = &(const struct clk_parent_data){
- .hw = &lpass_lpaaudio_dig_pll.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &lpass_lpaaudio_dig_pll.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -210,8 +210,8 @@ static struct clk_branch lpass_audio_core_ext_mclk0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "lpass_audio_core_ext_mclk0_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &ext_mclk0_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &ext_mclk0_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -230,8 +230,8 @@ static struct clk_branch lpass_audio_core_lpaif_pri_ibit_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "lpass_audio_core_lpaif_pri_ibit_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &lpaif_pri_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &lpaif_pri_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -250,8 +250,8 @@ static struct clk_branch lpass_audio_core_lpaif_sec_ibit_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "lpass_audio_core_lpaif_sec_ibit_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &lpaif_sec_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &lpaif_sec_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -270,8 +270,8 @@ static struct clk_branch lpass_audio_core_sysnoc_mport_core_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "lpass_audio_core_sysnoc_mport_core_clk",
- .parent_data = &(const struct clk_parent_data){
- .hw = &core_clk_src.clkr.hw,
+ .parent_hws = (const struct clk_hw*[]) {
+ &core_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
diff --git a/drivers/clk/qcom/mmcc-apq8084.c b/drivers/clk/qcom/mmcc-apq8084.c
index e9f971359155..02fc21208dd1 100644
--- a/drivers/clk/qcom/mmcc-apq8084.c
+++ b/drivers/clk/qcom/mmcc-apq8084.c
@@ -40,6 +40,120 @@ enum {
P_MMSLEEP,
};
+static struct clk_pll mmpll0 = {
+ .l_reg = 0x0004,
+ .m_reg = 0x0008,
+ .n_reg = 0x000c,
+ .config_reg = 0x0014,
+ .mode_reg = 0x0000,
+ .status_reg = 0x001c,
+ .status_bit = 17,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "mmpll0",
+ .parent_data = (const struct clk_parent_data[]){
+ { .fw_name = "xo", .name = "xo_board" },
+ },
+ .num_parents = 1,
+ .ops = &clk_pll_ops,
+ },
+};
+
+static struct clk_regmap mmpll0_vote = {
+ .enable_reg = 0x0100,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmpll0_vote",
+ .parent_hws = (const struct clk_hw*[]){
+ &mmpll0.clkr.hw
+ },
+ .num_parents = 1,
+ .ops = &clk_pll_vote_ops,
+ },
+};
+
+static struct clk_pll mmpll1 = {
+ .l_reg = 0x0044,
+ .m_reg = 0x0048,
+ .n_reg = 0x004c,
+ .config_reg = 0x0050,
+ .mode_reg = 0x0040,
+ .status_reg = 0x005c,
+ .status_bit = 17,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "mmpll1",
+ .parent_data = (const struct clk_parent_data[]){
+ { .fw_name = "xo", .name = "xo_board" },
+ },
+ .num_parents = 1,
+ .ops = &clk_pll_ops,
+ },
+};
+
+static struct clk_regmap mmpll1_vote = {
+ .enable_reg = 0x0100,
+ .enable_mask = BIT(1),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmpll1_vote",
+ .parent_hws = (const struct clk_hw*[]){
+ &mmpll1.clkr.hw
+ },
+ .num_parents = 1,
+ .ops = &clk_pll_vote_ops,
+ },
+};
+
+static struct clk_pll mmpll2 = {
+ .l_reg = 0x4104,
+ .m_reg = 0x4108,
+ .n_reg = 0x410c,
+ .config_reg = 0x4110,
+ .mode_reg = 0x4100,
+ .status_reg = 0x411c,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "mmpll2",
+ .parent_data = (const struct clk_parent_data[]){
+ { .fw_name = "xo", .name = "xo_board" },
+ },
+ .num_parents = 1,
+ .ops = &clk_pll_ops,
+ },
+};
+
+static struct clk_pll mmpll3 = {
+ .l_reg = 0x0084,
+ .m_reg = 0x0088,
+ .n_reg = 0x008c,
+ .config_reg = 0x0090,
+ .mode_reg = 0x0080,
+ .status_reg = 0x009c,
+ .status_bit = 17,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "mmpll3",
+ .parent_data = (const struct clk_parent_data[]){
+ { .fw_name = "xo", .name = "xo_board" },
+ },
+ .num_parents = 1,
+ .ops = &clk_pll_ops,
+ },
+};
+
+static struct clk_pll mmpll4 = {
+ .l_reg = 0x00a4,
+ .m_reg = 0x00a8,
+ .n_reg = 0x00ac,
+ .config_reg = 0x00b0,
+ .mode_reg = 0x0080,
+ .status_reg = 0x00bc,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "mmpll4",
+ .parent_data = (const struct clk_parent_data[]){
+ { .fw_name = "xo", .name = "xo_board" },
+ },
+ .num_parents = 1,
+ .ops = &clk_pll_ops,
+ },
+};
+
static const struct parent_map mmcc_xo_mmpll0_mmpll1_gpll0_map[] = {
{ P_XO, 0 },
{ P_MMPLL0, 1 },
@@ -47,11 +161,11 @@ static const struct parent_map mmcc_xo_mmpll0_mmpll1_gpll0_map[] = {
{ P_GPLL0, 5 }
};
-static const char * const mmcc_xo_mmpll0_mmpll1_gpll0[] = {
- "xo",
- "mmpll0_vote",
- "mmpll1_vote",
- "mmss_gpll0_vote",
+static const struct clk_parent_data mmcc_xo_mmpll0_mmpll1_gpll0[] = {
+ { .fw_name = "xo", .name = "xo_board" },
+ { .hw = &mmpll0_vote.hw },
+ { .hw = &mmpll1_vote.hw },
+ { .fw_name = "mmss_gpll0_vote", .name = "mmss_gpll0_vote" },
};
static const struct parent_map mmcc_xo_mmpll0_dsi_hdmi_gpll0_map[] = {
@@ -63,13 +177,13 @@ static const struct parent_map mmcc_xo_mmpll0_dsi_hdmi_gpll0_map[] = {
{ P_DSI1PLL, 3 }
};
-static const char * const mmcc_xo_mmpll0_dsi_hdmi_gpll0[] = {
- "xo",
- "mmpll0_vote",
- "hdmipll",
- "mmss_gpll0_vote",
- "dsi0pll",
- "dsi1pll",
+static const struct clk_parent_data mmcc_xo_mmpll0_dsi_hdmi_gpll0[] = {
+ { .fw_name = "xo", .name = "xo_board" },
+ { .hw = &mmpll0_vote.hw },
+ { .fw_name = "hdmipll", .name = "hdmipll" },
+ { .fw_name = "mmss_gpll0_vote", .name = "mmss_gpll0_vote" },
+ { .fw_name = "dsi0pll", .name = "dsi0pll" },
+ { .fw_name = "dsi1pll", .name = "dsi1pll" },
};
static const struct parent_map mmcc_xo_mmpll0_1_2_gpll0_map[] = {
@@ -80,12 +194,12 @@ static const struct parent_map mmcc_xo_mmpll0_1_2_gpll0_map[] = {
{ P_MMPLL2, 3 }
};
-static const char * const mmcc_xo_mmpll0_1_2_gpll0[] = {
- "xo",
- "mmpll0_vote",
- "mmpll1_vote",
- "mmss_gpll0_vote",
- "mmpll2",
+static const struct clk_parent_data mmcc_xo_mmpll0_1_2_gpll0[] = {
+ { .fw_name = "xo", .name = "xo_board" },
+ { .hw = &mmpll0_vote.hw },
+ { .hw = &mmpll1_vote.hw },
+ { .fw_name = "mmss_gpll0_vote", .name = "mmss_gpll0_vote" },
+ { .hw = &mmpll2.clkr.hw },
};
static const struct parent_map mmcc_xo_mmpll0_1_3_gpll0_map[] = {
@@ -96,12 +210,12 @@ static const struct parent_map mmcc_xo_mmpll0_1_3_gpll0_map[] = {
{ P_MMPLL3, 3 }
};
-static const char * const mmcc_xo_mmpll0_1_3_gpll0[] = {
- "xo",
- "mmpll0_vote",
- "mmpll1_vote",
- "mmss_gpll0_vote",
- "mmpll3",
+static const struct clk_parent_data mmcc_xo_mmpll0_1_3_gpll0[] = {
+ { .fw_name = "xo", .name = "xo_board" },
+ { .hw = &mmpll0_vote.hw },
+ { .hw = &mmpll1_vote.hw },
+ { .fw_name = "mmss_gpll0_vote", .name = "mmss_gpll0_vote" },
+ { .hw = &mmpll3.clkr.hw },
};
static const struct parent_map mmcc_xo_dsi_hdmi_edp_map[] = {
@@ -113,13 +227,13 @@ static const struct parent_map mmcc_xo_dsi_hdmi_edp_map[] = {
{ P_DSI1PLL, 2 }
};
-static const char * const mmcc_xo_dsi_hdmi_edp[] = {
- "xo",
- "edp_link_clk",
- "hdmipll",
- "edp_vco_div",
- "dsi0pll",
- "dsi1pll",
+static const struct clk_parent_data mmcc_xo_dsi_hdmi_edp[] = {
+ { .fw_name = "xo", .name = "xo_board" },
+ { .fw_name = "edp_link_clk", .name = "edp_link_clk" },
+ { .fw_name = "hdmipll", .name = "hdmipll" },
+ { .fw_name = "edp_vco_div", .name = "edp_vco_div" },
+ { .fw_name = "dsi0pll", .name = "dsi0pll" },
+ { .fw_name = "dsi1pll", .name = "dsi1pll" },
};
static const struct parent_map mmcc_xo_dsi_hdmi_edp_gpll0_map[] = {
@@ -131,13 +245,13 @@ static const struct parent_map mmcc_xo_dsi_hdmi_edp_gpll0_map[] = {
{ P_DSI1PLL, 2 }
};
-static const char * const mmcc_xo_dsi_hdmi_edp_gpll0[] = {
- "xo",
- "edp_link_clk",
- "hdmipll",
- "gpll0_vote",
- "dsi0pll",
- "dsi1pll",
+static const struct clk_parent_data mmcc_xo_dsi_hdmi_edp_gpll0[] = {
+ { .fw_name = "xo", .name = "xo_board" },
+ { .fw_name = "edp_link_clk", .name = "edp_link_clk" },
+ { .fw_name = "hdmipll", .name = "hdmipll" },
+ { .fw_name = "gpll0_vote", .name = "gpll0_vote" },
+ { .fw_name = "dsi0pll", .name = "dsi0pll" },
+ { .fw_name = "dsi1pll", .name = "dsi1pll" },
};
static const struct parent_map mmcc_xo_dsibyte_hdmi_edp_gpll0_map[] = {
@@ -149,13 +263,13 @@ static const struct parent_map mmcc_xo_dsibyte_hdmi_edp_gpll0_map[] = {
{ P_DSI1PLL_BYTE, 2 }
};
-static const char * const mmcc_xo_dsibyte_hdmi_edp_gpll0[] = {
- "xo",
- "edp_link_clk",
- "hdmipll",
- "gpll0_vote",
- "dsi0pllbyte",
- "dsi1pllbyte",
+static const struct clk_parent_data mmcc_xo_dsibyte_hdmi_edp_gpll0[] = {
+ { .fw_name = "xo", .name = "xo_board" },
+ { .fw_name = "edp_link_clk", .name = "edp_link_clk" },
+ { .fw_name = "hdmipll", .name = "hdmipll" },
+ { .fw_name = "gpll0_vote", .name = "gpll0_vote" },
+ { .fw_name = "dsi0pllbyte", .name = "dsi0pllbyte" },
+ { .fw_name = "dsi1pllbyte", .name = "dsi1pllbyte" },
};
static const struct parent_map mmcc_xo_mmpll0_1_4_gpll0_map[] = {
@@ -166,12 +280,12 @@ static const struct parent_map mmcc_xo_mmpll0_1_4_gpll0_map[] = {
{ P_MMPLL4, 3 }
};
-static const char * const mmcc_xo_mmpll0_1_4_gpll0[] = {
- "xo",
- "mmpll0",
- "mmpll1",
- "mmpll4",
- "gpll0",
+static const struct clk_parent_data mmcc_xo_mmpll0_1_4_gpll0[] = {
+ { .fw_name = "xo", .name = "xo_board" },
+ { .hw = &mmpll0.clkr.hw },
+ { .hw = &mmpll1.clkr.hw },
+ { .hw = &mmpll4.clkr.hw },
+ { .fw_name = "gpll0", .name = "gpll0" },
};
static const struct parent_map mmcc_xo_mmpll0_1_4_gpll1_0_map[] = {
@@ -183,13 +297,13 @@ static const struct parent_map mmcc_xo_mmpll0_1_4_gpll1_0_map[] = {
{ P_GPLL1, 4 }
};
-static const char * const mmcc_xo_mmpll0_1_4_gpll1_0[] = {
- "xo",
- "mmpll0",
- "mmpll1",
- "mmpll4",
- "gpll1",
- "gpll0",
+static const struct clk_parent_data mmcc_xo_mmpll0_1_4_gpll1_0[] = {
+ { .fw_name = "xo", .name = "xo_board" },
+ { .hw = &mmpll0.clkr.hw },
+ { .hw = &mmpll1.clkr.hw },
+ { .hw = &mmpll4.clkr.hw },
+ { .fw_name = "gpll1", .name = "gpll1" },
+ { .fw_name = "gpll0", .name = "gpll0" },
};
static const struct parent_map mmcc_xo_mmpll0_1_4_gpll1_0_sleep_map[] = {
@@ -202,114 +316,14 @@ static const struct parent_map mmcc_xo_mmpll0_1_4_gpll1_0_sleep_map[] = {
{ P_MMSLEEP, 6 }
};
-static const char * const mmcc_xo_mmpll0_1_4_gpll1_0_sleep[] = {
- "xo",
- "mmpll0",
- "mmpll1",
- "mmpll4",
- "gpll1",
- "gpll0",
- "sleep_clk_src",
-};
-
-static struct clk_pll mmpll0 = {
- .l_reg = 0x0004,
- .m_reg = 0x0008,
- .n_reg = 0x000c,
- .config_reg = 0x0014,
- .mode_reg = 0x0000,
- .status_reg = 0x001c,
- .status_bit = 17,
- .clkr.hw.init = &(struct clk_init_data){
- .name = "mmpll0",
- .parent_names = (const char *[]){ "xo" },
- .num_parents = 1,
- .ops = &clk_pll_ops,
- },
-};
-
-static struct clk_regmap mmpll0_vote = {
- .enable_reg = 0x0100,
- .enable_mask = BIT(0),
- .hw.init = &(struct clk_init_data){
- .name = "mmpll0_vote",
- .parent_names = (const char *[]){ "mmpll0" },
- .num_parents = 1,
- .ops = &clk_pll_vote_ops,
- },
-};
-
-static struct clk_pll mmpll1 = {
- .l_reg = 0x0044,
- .m_reg = 0x0048,
- .n_reg = 0x004c,
- .config_reg = 0x0050,
- .mode_reg = 0x0040,
- .status_reg = 0x005c,
- .status_bit = 17,
- .clkr.hw.init = &(struct clk_init_data){
- .name = "mmpll1",
- .parent_names = (const char *[]){ "xo" },
- .num_parents = 1,
- .ops = &clk_pll_ops,
- },
-};
-
-static struct clk_regmap mmpll1_vote = {
- .enable_reg = 0x0100,
- .enable_mask = BIT(1),
- .hw.init = &(struct clk_init_data){
- .name = "mmpll1_vote",
- .parent_names = (const char *[]){ "mmpll1" },
- .num_parents = 1,
- .ops = &clk_pll_vote_ops,
- },
-};
-
-static struct clk_pll mmpll2 = {
- .l_reg = 0x4104,
- .m_reg = 0x4108,
- .n_reg = 0x410c,
- .config_reg = 0x4110,
- .mode_reg = 0x4100,
- .status_reg = 0x411c,
- .clkr.hw.init = &(struct clk_init_data){
- .name = "mmpll2",
- .parent_names = (const char *[]){ "xo" },
- .num_parents = 1,
- .ops = &clk_pll_ops,
- },
-};
-
-static struct clk_pll mmpll3 = {
- .l_reg = 0x0084,
- .m_reg = 0x0088,
- .n_reg = 0x008c,
- .config_reg = 0x0090,
- .mode_reg = 0x0080,
- .status_reg = 0x009c,
- .status_bit = 17,
- .clkr.hw.init = &(struct clk_init_data){
- .name = "mmpll3",
- .parent_names = (const char *[]){ "xo" },
- .num_parents = 1,
- .ops = &clk_pll_ops,
- },
-};
-
-static struct clk_pll mmpll4 = {
- .l_reg = 0x00a4,
- .m_reg = 0x00a8,
- .n_reg = 0x00ac,
- .config_reg = 0x00b0,
- .mode_reg = 0x0080,
- .status_reg = 0x00bc,
- .clkr.hw.init = &(struct clk_init_data){
- .name = "mmpll4",
- .parent_names = (const char *[]){ "xo" },
- .num_parents = 1,
- .ops = &clk_pll_ops,
- },
+static const struct clk_parent_data mmcc_xo_mmpll0_1_4_gpll1_0_sleep[] = {
+ { .fw_name = "xo", .name = "xo_board" },
+ { .hw = &mmpll0.clkr.hw },
+ { .hw = &mmpll1.clkr.hw },
+ { .hw = &mmpll4.clkr.hw },
+ { .fw_name = "gpll1", .name = "gpll1" },
+ { .fw_name = "gpll0", .name = "gpll0" },
+ { .fw_name = "sleep_clk", .name = "sleep_clk" },
};
static struct clk_rcg2 mmss_ahb_clk_src = {
@@ -318,8 +332,8 @@ static struct clk_rcg2 mmss_ahb_clk_src = {
.parent_map = mmcc_xo_mmpll0_mmpll1_gpll0_map,
.clkr.hw.init = &(struct clk_init_data){
.name = "mmss_ahb_clk_src",
- .parent_names = mmcc_xo_mmpll0_mmpll1_gpll0,
- .num_parents = 4,
+ .parent_data = mmcc_xo_mmpll0_mmpll1_gpll0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_mmpll0_mmpll1_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -343,8 +357,8 @@ static struct clk_rcg2 mmss_axi_clk_src = {
.freq_tbl = ftbl_mmss_axi_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "mmss_axi_clk_src",
- .parent_names = mmcc_xo_mmpll0_mmpll1_gpll0,
- .num_parents = 4,
+ .parent_data = mmcc_xo_mmpll0_mmpll1_gpll0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_mmpll0_mmpll1_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -367,8 +381,8 @@ static struct clk_rcg2 ocmemnoc_clk_src = {
.freq_tbl = ftbl_ocmemnoc_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "ocmemnoc_clk_src",
- .parent_names = mmcc_xo_mmpll0_mmpll1_gpll0,
- .num_parents = 4,
+ .parent_data = mmcc_xo_mmpll0_mmpll1_gpll0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_mmpll0_mmpll1_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -386,8 +400,8 @@ static struct clk_rcg2 csi0_clk_src = {
.freq_tbl = ftbl_camss_csi0_3_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "csi0_clk_src",
- .parent_names = mmcc_xo_mmpll0_1_4_gpll0,
- .num_parents = 5,
+ .parent_data = mmcc_xo_mmpll0_1_4_gpll0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_mmpll0_1_4_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -399,8 +413,8 @@ static struct clk_rcg2 csi1_clk_src = {
.freq_tbl = ftbl_camss_csi0_3_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "csi1_clk_src",
- .parent_names = mmcc_xo_mmpll0_1_4_gpll0,
- .num_parents = 5,
+ .parent_data = mmcc_xo_mmpll0_1_4_gpll0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_mmpll0_1_4_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -412,8 +426,8 @@ static struct clk_rcg2 csi2_clk_src = {
.freq_tbl = ftbl_camss_csi0_3_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "csi2_clk_src",
- .parent_names = mmcc_xo_mmpll0_1_4_gpll0,
- .num_parents = 5,
+ .parent_data = mmcc_xo_mmpll0_1_4_gpll0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_mmpll0_1_4_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -425,8 +439,8 @@ static struct clk_rcg2 csi3_clk_src = {
.freq_tbl = ftbl_camss_csi0_3_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "csi3_clk_src",
- .parent_names = mmcc_xo_mmpll0_1_4_gpll0,
- .num_parents = 5,
+ .parent_data = mmcc_xo_mmpll0_1_4_gpll0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_mmpll0_1_4_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -455,8 +469,8 @@ static struct clk_rcg2 vfe0_clk_src = {
.freq_tbl = ftbl_camss_vfe_vfe0_1_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "vfe0_clk_src",
- .parent_names = mmcc_xo_mmpll0_1_4_gpll0,
- .num_parents = 5,
+ .parent_data = mmcc_xo_mmpll0_1_4_gpll0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_mmpll0_1_4_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -468,8 +482,8 @@ static struct clk_rcg2 vfe1_clk_src = {
.freq_tbl = ftbl_camss_vfe_vfe0_1_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "vfe1_clk_src",
- .parent_names = mmcc_xo_mmpll0_1_4_gpll0,
- .num_parents = 5,
+ .parent_data = mmcc_xo_mmpll0_1_4_gpll0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_mmpll0_1_4_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -496,8 +510,8 @@ static struct clk_rcg2 mdp_clk_src = {
.freq_tbl = ftbl_mdss_mdp_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "mdp_clk_src",
- .parent_names = mmcc_xo_mmpll0_dsi_hdmi_gpll0,
- .num_parents = 6,
+ .parent_data = mmcc_xo_mmpll0_dsi_hdmi_gpll0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_mmpll0_dsi_hdmi_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -508,8 +522,8 @@ static struct clk_rcg2 gfx3d_clk_src = {
.parent_map = mmcc_xo_mmpll0_1_2_gpll0_map,
.clkr.hw.init = &(struct clk_init_data){
.name = "gfx3d_clk_src",
- .parent_names = mmcc_xo_mmpll0_1_2_gpll0,
- .num_parents = 5,
+ .parent_data = mmcc_xo_mmpll0_1_2_gpll0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_mmpll0_1_2_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -531,8 +545,8 @@ static struct clk_rcg2 jpeg0_clk_src = {
.freq_tbl = ftbl_camss_jpeg_jpeg0_2_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "jpeg0_clk_src",
- .parent_names = mmcc_xo_mmpll0_1_4_gpll0,
- .num_parents = 5,
+ .parent_data = mmcc_xo_mmpll0_1_4_gpll0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_mmpll0_1_4_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -544,8 +558,8 @@ static struct clk_rcg2 jpeg1_clk_src = {
.freq_tbl = ftbl_camss_jpeg_jpeg0_2_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "jpeg1_clk_src",
- .parent_names = mmcc_xo_mmpll0_1_4_gpll0,
- .num_parents = 5,
+ .parent_data = mmcc_xo_mmpll0_1_4_gpll0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_mmpll0_1_4_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -557,8 +571,8 @@ static struct clk_rcg2 jpeg2_clk_src = {
.freq_tbl = ftbl_camss_jpeg_jpeg0_2_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "jpeg2_clk_src",
- .parent_names = mmcc_xo_mmpll0_1_4_gpll0,
- .num_parents = 5,
+ .parent_data = mmcc_xo_mmpll0_1_4_gpll0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_mmpll0_1_4_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -570,8 +584,8 @@ static struct clk_rcg2 pclk0_clk_src = {
.parent_map = mmcc_xo_dsi_hdmi_edp_gpll0_map,
.clkr.hw.init = &(struct clk_init_data){
.name = "pclk0_clk_src",
- .parent_names = mmcc_xo_dsi_hdmi_edp_gpll0,
- .num_parents = 6,
+ .parent_data = mmcc_xo_dsi_hdmi_edp_gpll0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_dsi_hdmi_edp_gpll0),
.ops = &clk_pixel_ops,
.flags = CLK_SET_RATE_PARENT,
},
@@ -584,8 +598,8 @@ static struct clk_rcg2 pclk1_clk_src = {
.parent_map = mmcc_xo_dsi_hdmi_edp_gpll0_map,
.clkr.hw.init = &(struct clk_init_data){
.name = "pclk1_clk_src",
- .parent_names = mmcc_xo_dsi_hdmi_edp_gpll0,
- .num_parents = 6,
+ .parent_data = mmcc_xo_dsi_hdmi_edp_gpll0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_dsi_hdmi_edp_gpll0),
.ops = &clk_pixel_ops,
.flags = CLK_SET_RATE_PARENT,
},
@@ -609,8 +623,8 @@ static struct clk_rcg2 vcodec0_clk_src = {
.freq_tbl = ftbl_venus0_vcodec0_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "vcodec0_clk_src",
- .parent_names = mmcc_xo_mmpll0_1_3_gpll0,
- .num_parents = 5,
+ .parent_data = mmcc_xo_mmpll0_1_3_gpll0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_mmpll0_1_3_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -628,8 +642,8 @@ static struct clk_rcg2 vp_clk_src = {
.freq_tbl = ftbl_avsync_vp_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "vp_clk_src",
- .parent_names = mmcc_xo_mmpll0_mmpll1_gpll0,
- .num_parents = 4,
+ .parent_data = mmcc_xo_mmpll0_mmpll1_gpll0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_mmpll0_mmpll1_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -647,8 +661,8 @@ static struct clk_rcg2 cci_clk_src = {
.freq_tbl = ftbl_camss_cci_cci_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "cci_clk_src",
- .parent_names = mmcc_xo_mmpll0_1_4_gpll1_0,
- .num_parents = 6,
+ .parent_data = mmcc_xo_mmpll0_1_4_gpll1_0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_mmpll0_1_4_gpll1_0),
.ops = &clk_rcg2_ops,
},
};
@@ -671,8 +685,8 @@ static struct clk_rcg2 camss_gp0_clk_src = {
.freq_tbl = ftbl_camss_gp0_1_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "camss_gp0_clk_src",
- .parent_names = mmcc_xo_mmpll0_1_4_gpll1_0_sleep,
- .num_parents = 7,
+ .parent_data = mmcc_xo_mmpll0_1_4_gpll1_0_sleep,
+ .num_parents = ARRAY_SIZE(mmcc_xo_mmpll0_1_4_gpll1_0_sleep),
.ops = &clk_rcg2_ops,
},
};
@@ -685,8 +699,8 @@ static struct clk_rcg2 camss_gp1_clk_src = {
.freq_tbl = ftbl_camss_gp0_1_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "camss_gp1_clk_src",
- .parent_names = mmcc_xo_mmpll0_1_4_gpll1_0_sleep,
- .num_parents = 7,
+ .parent_data = mmcc_xo_mmpll0_1_4_gpll1_0_sleep,
+ .num_parents = ARRAY_SIZE(mmcc_xo_mmpll0_1_4_gpll1_0_sleep),
.ops = &clk_rcg2_ops,
},
};
@@ -713,8 +727,8 @@ static struct clk_rcg2 mclk0_clk_src = {
.freq_tbl = ftbl_camss_mclk0_3_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "mclk0_clk_src",
- .parent_names = mmcc_xo_mmpll0_1_4_gpll1_0,
- .num_parents = 6,
+ .parent_data = mmcc_xo_mmpll0_1_4_gpll1_0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_mmpll0_1_4_gpll1_0),
.ops = &clk_rcg2_ops,
},
};
@@ -727,8 +741,8 @@ static struct clk_rcg2 mclk1_clk_src = {
.freq_tbl = ftbl_camss_mclk0_3_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "mclk1_clk_src",
- .parent_names = mmcc_xo_mmpll0_1_4_gpll1_0,
- .num_parents = 6,
+ .parent_data = mmcc_xo_mmpll0_1_4_gpll1_0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_mmpll0_1_4_gpll1_0),
.ops = &clk_rcg2_ops,
},
};
@@ -741,8 +755,8 @@ static struct clk_rcg2 mclk2_clk_src = {
.freq_tbl = ftbl_camss_mclk0_3_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "mclk2_clk_src",
- .parent_names = mmcc_xo_mmpll0_1_4_gpll1_0,
- .num_parents = 6,
+ .parent_data = mmcc_xo_mmpll0_1_4_gpll1_0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_mmpll0_1_4_gpll1_0),
.ops = &clk_rcg2_ops,
},
};
@@ -755,8 +769,8 @@ static struct clk_rcg2 mclk3_clk_src = {
.freq_tbl = ftbl_camss_mclk0_3_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "mclk3_clk_src",
- .parent_names = mmcc_xo_mmpll0_1_4_gpll1_0,
- .num_parents = 6,
+ .parent_data = mmcc_xo_mmpll0_1_4_gpll1_0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_mmpll0_1_4_gpll1_0),
.ops = &clk_rcg2_ops,
},
};
@@ -774,8 +788,8 @@ static struct clk_rcg2 csi0phytimer_clk_src = {
.freq_tbl = ftbl_camss_phy0_2_csi0_2phytimer_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "csi0phytimer_clk_src",
- .parent_names = mmcc_xo_mmpll0_1_4_gpll0,
- .num_parents = 5,
+ .parent_data = mmcc_xo_mmpll0_1_4_gpll0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_mmpll0_1_4_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -787,8 +801,8 @@ static struct clk_rcg2 csi1phytimer_clk_src = {
.freq_tbl = ftbl_camss_phy0_2_csi0_2phytimer_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "csi1phytimer_clk_src",
- .parent_names = mmcc_xo_mmpll0_mmpll1_gpll0,
- .num_parents = 5,
+ .parent_data = mmcc_xo_mmpll0_mmpll1_gpll0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_mmpll0_mmpll1_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -800,8 +814,8 @@ static struct clk_rcg2 csi2phytimer_clk_src = {
.freq_tbl = ftbl_camss_phy0_2_csi0_2phytimer_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "csi2phytimer_clk_src",
- .parent_names = mmcc_xo_mmpll0_1_4_gpll0,
- .num_parents = 5,
+ .parent_data = mmcc_xo_mmpll0_1_4_gpll0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_mmpll0_1_4_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -823,8 +837,8 @@ static struct clk_rcg2 cpp_clk_src = {
.freq_tbl = ftbl_camss_vfe_cpp_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "cpp_clk_src",
- .parent_names = mmcc_xo_mmpll0_1_4_gpll0,
- .num_parents = 5,
+ .parent_data = mmcc_xo_mmpll0_1_4_gpll0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_mmpll0_1_4_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -835,8 +849,8 @@ static struct clk_rcg2 byte0_clk_src = {
.parent_map = mmcc_xo_dsibyte_hdmi_edp_gpll0_map,
.clkr.hw.init = &(struct clk_init_data){
.name = "byte0_clk_src",
- .parent_names = mmcc_xo_dsibyte_hdmi_edp_gpll0,
- .num_parents = 6,
+ .parent_data = mmcc_xo_dsibyte_hdmi_edp_gpll0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_dsibyte_hdmi_edp_gpll0),
.ops = &clk_byte2_ops,
.flags = CLK_SET_RATE_PARENT,
},
@@ -848,8 +862,8 @@ static struct clk_rcg2 byte1_clk_src = {
.parent_map = mmcc_xo_dsibyte_hdmi_edp_gpll0_map,
.clkr.hw.init = &(struct clk_init_data){
.name = "byte1_clk_src",
- .parent_names = mmcc_xo_dsibyte_hdmi_edp_gpll0,
- .num_parents = 6,
+ .parent_data = mmcc_xo_dsibyte_hdmi_edp_gpll0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_dsibyte_hdmi_edp_gpll0),
.ops = &clk_byte2_ops,
.flags = CLK_SET_RATE_PARENT,
},
@@ -867,8 +881,8 @@ static struct clk_rcg2 edpaux_clk_src = {
.freq_tbl = ftbl_mdss_edpaux_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "edpaux_clk_src",
- .parent_names = mmcc_xo_mmpll0_mmpll1_gpll0,
- .num_parents = 4,
+ .parent_data = mmcc_xo_mmpll0_mmpll1_gpll0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_mmpll0_mmpll1_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -886,8 +900,8 @@ static struct clk_rcg2 edplink_clk_src = {
.freq_tbl = ftbl_mdss_edplink_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "edplink_clk_src",
- .parent_names = mmcc_xo_dsi_hdmi_edp_gpll0,
- .num_parents = 6,
+ .parent_data = mmcc_xo_dsi_hdmi_edp_gpll0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_dsi_hdmi_edp_gpll0),
.ops = &clk_rcg2_ops,
.flags = CLK_SET_RATE_PARENT,
},
@@ -906,8 +920,8 @@ static struct clk_rcg2 edppixel_clk_src = {
.freq_tbl = edp_pixel_freq_tbl,
.clkr.hw.init = &(struct clk_init_data){
.name = "edppixel_clk_src",
- .parent_names = mmcc_xo_dsi_hdmi_edp,
- .num_parents = 6,
+ .parent_data = mmcc_xo_dsi_hdmi_edp,
+ .num_parents = ARRAY_SIZE(mmcc_xo_dsi_hdmi_edp),
.ops = &clk_edp_pixel_ops,
},
};
@@ -924,8 +938,8 @@ static struct clk_rcg2 esc0_clk_src = {
.freq_tbl = ftbl_mdss_esc0_1_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "esc0_clk_src",
- .parent_names = mmcc_xo_dsibyte_hdmi_edp_gpll0,
- .num_parents = 6,
+ .parent_data = mmcc_xo_dsibyte_hdmi_edp_gpll0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_dsibyte_hdmi_edp_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -937,8 +951,8 @@ static struct clk_rcg2 esc1_clk_src = {
.freq_tbl = ftbl_mdss_esc0_1_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "esc1_clk_src",
- .parent_names = mmcc_xo_dsibyte_hdmi_edp_gpll0,
- .num_parents = 6,
+ .parent_data = mmcc_xo_dsibyte_hdmi_edp_gpll0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_dsibyte_hdmi_edp_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -955,8 +969,8 @@ static struct clk_rcg2 extpclk_clk_src = {
.freq_tbl = extpclk_freq_tbl,
.clkr.hw.init = &(struct clk_init_data){
.name = "extpclk_clk_src",
- .parent_names = mmcc_xo_dsi_hdmi_edp_gpll0,
- .num_parents = 6,
+ .parent_data = mmcc_xo_dsi_hdmi_edp_gpll0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_dsi_hdmi_edp_gpll0),
.ops = &clk_byte_ops,
.flags = CLK_SET_RATE_PARENT,
},
@@ -974,8 +988,8 @@ static struct clk_rcg2 hdmi_clk_src = {
.freq_tbl = ftbl_mdss_hdmi_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "hdmi_clk_src",
- .parent_names = mmcc_xo_mmpll0_mmpll1_gpll0,
- .num_parents = 4,
+ .parent_data = mmcc_xo_mmpll0_mmpll1_gpll0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_mmpll0_mmpll1_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -992,8 +1006,8 @@ static struct clk_rcg2 vsync_clk_src = {
.freq_tbl = ftbl_mdss_vsync_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "vsync_clk_src",
- .parent_names = mmcc_xo_mmpll0_mmpll1_gpll0,
- .num_parents = 4,
+ .parent_data = mmcc_xo_mmpll0_mmpll1_gpll0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_mmpll0_mmpll1_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -1010,8 +1024,8 @@ static struct clk_rcg2 rbcpr_clk_src = {
.freq_tbl = ftbl_mmss_rbcpr_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "rbcpr_clk_src",
- .parent_names = mmcc_xo_mmpll0_mmpll1_gpll0,
- .num_parents = 4,
+ .parent_data = mmcc_xo_mmpll0_mmpll1_gpll0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_mmpll0_mmpll1_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -1028,8 +1042,8 @@ static struct clk_rcg2 rbbmtimer_clk_src = {
.freq_tbl = ftbl_oxili_rbbmtimer_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "rbbmtimer_clk_src",
- .parent_names = mmcc_xo_mmpll0_mmpll1_gpll0,
- .num_parents = 4,
+ .parent_data = mmcc_xo_mmpll0_mmpll1_gpll0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_mmpll0_mmpll1_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -1051,8 +1065,8 @@ static struct clk_rcg2 maple_clk_src = {
.freq_tbl = ftbl_vpu_maple_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "maple_clk_src",
- .parent_names = mmcc_xo_mmpll0_mmpll1_gpll0,
- .num_parents = 4,
+ .parent_data = mmcc_xo_mmpll0_mmpll1_gpll0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_mmpll0_mmpll1_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -1073,8 +1087,8 @@ static struct clk_rcg2 vdp_clk_src = {
.freq_tbl = ftbl_vpu_vdp_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "vdp_clk_src",
- .parent_names = mmcc_xo_mmpll0_mmpll1_gpll0,
- .num_parents = 4,
+ .parent_data = mmcc_xo_mmpll0_mmpll1_gpll0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_mmpll0_mmpll1_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -1092,8 +1106,8 @@ static struct clk_rcg2 vpu_bus_clk_src = {
.freq_tbl = ftbl_vpu_bus_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "vpu_bus_clk_src",
- .parent_names = mmcc_xo_mmpll0_mmpll1_gpll0,
- .num_parents = 4,
+ .parent_data = mmcc_xo_mmpll0_mmpll1_gpll0,
+ .num_parents = ARRAY_SIZE(mmcc_xo_mmpll0_mmpll1_gpll0),
.ops = &clk_rcg2_ops,
},
};
@@ -1105,7 +1119,9 @@ static struct clk_branch mmss_cxo_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mmss_cxo_clk",
- .parent_names = (const char *[]){ "xo" },
+ .parent_data = (const struct clk_parent_data[]){
+ { .fw_name = "xo", .name = "xo_board" },
+ },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
@@ -1120,8 +1136,8 @@ static struct clk_branch mmss_sleepclk_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mmss_sleepclk_clk",
- .parent_names = (const char *[]){
- "sleep_clk_src",
+ .parent_data = (const struct clk_parent_data[]){
+ { .fw_name = "sleep_clk", .name = "sleep_clk" },
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1137,8 +1153,8 @@ static struct clk_branch avsync_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "avsync_ahb_clk",
- .parent_names = (const char *[]){
- "mmss_ahb_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &mmss_ahb_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1154,8 +1170,8 @@ static struct clk_branch avsync_edppixel_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "avsync_edppixel_clk",
- .parent_names = (const char *[]){
- "edppixel_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &edppixel_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1171,8 +1187,8 @@ static struct clk_branch avsync_extpclk_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "avsync_extpclk_clk",
- .parent_names = (const char *[]){
- "extpclk_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &extpclk_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1188,8 +1204,8 @@ static struct clk_branch avsync_pclk0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "avsync_pclk0_clk",
- .parent_names = (const char *[]){
- "pclk0_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &pclk0_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1205,8 +1221,8 @@ static struct clk_branch avsync_pclk1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "avsync_pclk1_clk",
- .parent_names = (const char *[]){
- "pclk1_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &pclk1_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1222,8 +1238,8 @@ static struct clk_branch avsync_vp_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "avsync_vp_clk",
- .parent_names = (const char *[]){
- "vp_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &vp_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1239,8 +1255,8 @@ static struct clk_branch camss_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_ahb_clk",
- .parent_names = (const char *[]){
- "mmss_ahb_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &mmss_ahb_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1256,8 +1272,8 @@ static struct clk_branch camss_cci_cci_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_cci_cci_ahb_clk",
- .parent_names = (const char *[]){
- "mmss_ahb_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &mmss_ahb_clk_src.clkr.hw
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -1272,8 +1288,8 @@ static struct clk_branch camss_cci_cci_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_cci_cci_clk",
- .parent_names = (const char *[]){
- "cci_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &cci_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1289,8 +1305,8 @@ static struct clk_branch camss_csi0_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_csi0_ahb_clk",
- .parent_names = (const char *[]){
- "mmss_ahb_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &mmss_ahb_clk_src.clkr.hw
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -1305,8 +1321,8 @@ static struct clk_branch camss_csi0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_csi0_clk",
- .parent_names = (const char *[]){
- "csi0_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &csi0_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1322,8 +1338,8 @@ static struct clk_branch camss_csi0phy_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_csi0phy_clk",
- .parent_names = (const char *[]){
- "csi0_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &csi0_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1339,8 +1355,8 @@ static struct clk_branch camss_csi0pix_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_csi0pix_clk",
- .parent_names = (const char *[]){
- "csi0_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &csi0_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1356,8 +1372,8 @@ static struct clk_branch camss_csi0rdi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_csi0rdi_clk",
- .parent_names = (const char *[]){
- "csi0_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &csi0_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1373,8 +1389,8 @@ static struct clk_branch camss_csi1_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_csi1_ahb_clk",
- .parent_names = (const char *[]){
- "mmss_ahb_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &mmss_ahb_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1390,8 +1406,8 @@ static struct clk_branch camss_csi1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_csi1_clk",
- .parent_names = (const char *[]){
- "csi1_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &csi1_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1407,8 +1423,8 @@ static struct clk_branch camss_csi1phy_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_csi1phy_clk",
- .parent_names = (const char *[]){
- "csi1_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &csi1_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1424,8 +1440,8 @@ static struct clk_branch camss_csi1pix_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_csi1pix_clk",
- .parent_names = (const char *[]){
- "csi1_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &csi1_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1441,8 +1457,8 @@ static struct clk_branch camss_csi1rdi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_csi1rdi_clk",
- .parent_names = (const char *[]){
- "csi1_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &csi1_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1458,8 +1474,8 @@ static struct clk_branch camss_csi2_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_csi2_ahb_clk",
- .parent_names = (const char *[]){
- "mmss_ahb_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &mmss_ahb_clk_src.clkr.hw
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -1474,8 +1490,8 @@ static struct clk_branch camss_csi2_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_csi2_clk",
- .parent_names = (const char *[]){
- "csi2_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &csi2_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1491,8 +1507,8 @@ static struct clk_branch camss_csi2phy_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_csi2phy_clk",
- .parent_names = (const char *[]){
- "csi2_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &csi2_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1508,8 +1524,8 @@ static struct clk_branch camss_csi2pix_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_csi2pix_clk",
- .parent_names = (const char *[]){
- "csi2_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &csi2_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1525,8 +1541,8 @@ static struct clk_branch camss_csi2rdi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_csi2rdi_clk",
- .parent_names = (const char *[]){
- "csi2_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &csi2_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1542,8 +1558,8 @@ static struct clk_branch camss_csi3_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_csi3_ahb_clk",
- .parent_names = (const char *[]){
- "mmss_ahb_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &mmss_ahb_clk_src.clkr.hw
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -1558,8 +1574,8 @@ static struct clk_branch camss_csi3_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_csi3_clk",
- .parent_names = (const char *[]){
- "csi3_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &csi3_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1575,8 +1591,8 @@ static struct clk_branch camss_csi3phy_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_csi3phy_clk",
- .parent_names = (const char *[]){
- "csi3_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &csi3_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1592,8 +1608,8 @@ static struct clk_branch camss_csi3pix_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_csi3pix_clk",
- .parent_names = (const char *[]){
- "csi3_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &csi3_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1609,8 +1625,8 @@ static struct clk_branch camss_csi3rdi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_csi3rdi_clk",
- .parent_names = (const char *[]){
- "csi3_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &csi3_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1626,8 +1642,8 @@ static struct clk_branch camss_csi_vfe0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_csi_vfe0_clk",
- .parent_names = (const char *[]){
- "vfe0_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &vfe0_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1643,8 +1659,8 @@ static struct clk_branch camss_csi_vfe1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_csi_vfe1_clk",
- .parent_names = (const char *[]){
- "vfe1_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &vfe1_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1660,8 +1676,8 @@ static struct clk_branch camss_gp0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_gp0_clk",
- .parent_names = (const char *[]){
- "camss_gp0_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &camss_gp0_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1677,8 +1693,8 @@ static struct clk_branch camss_gp1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_gp1_clk",
- .parent_names = (const char *[]){
- "camss_gp1_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &camss_gp1_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1694,8 +1710,8 @@ static struct clk_branch camss_ispif_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_ispif_ahb_clk",
- .parent_names = (const char *[]){
- "mmss_ahb_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &mmss_ahb_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1711,8 +1727,8 @@ static struct clk_branch camss_jpeg_jpeg0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_jpeg_jpeg0_clk",
- .parent_names = (const char *[]){
- "jpeg0_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &jpeg0_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1728,8 +1744,8 @@ static struct clk_branch camss_jpeg_jpeg1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_jpeg_jpeg1_clk",
- .parent_names = (const char *[]){
- "jpeg1_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &jpeg1_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1745,8 +1761,8 @@ static struct clk_branch camss_jpeg_jpeg2_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_jpeg_jpeg2_clk",
- .parent_names = (const char *[]){
- "jpeg2_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &jpeg2_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1762,8 +1778,8 @@ static struct clk_branch camss_jpeg_jpeg_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_jpeg_jpeg_ahb_clk",
- .parent_names = (const char *[]){
- "mmss_ahb_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &mmss_ahb_clk_src.clkr.hw
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -1778,8 +1794,8 @@ static struct clk_branch camss_jpeg_jpeg_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_jpeg_jpeg_axi_clk",
- .parent_names = (const char *[]){
- "mmss_axi_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &mmss_axi_clk_src.clkr.hw
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -1794,8 +1810,8 @@ static struct clk_branch camss_mclk0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_mclk0_clk",
- .parent_names = (const char *[]){
- "mclk0_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &mclk0_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1811,8 +1827,8 @@ static struct clk_branch camss_mclk1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_mclk1_clk",
- .parent_names = (const char *[]){
- "mclk1_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &mclk1_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1828,8 +1844,8 @@ static struct clk_branch camss_mclk2_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_mclk2_clk",
- .parent_names = (const char *[]){
- "mclk2_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &mclk2_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1845,8 +1861,8 @@ static struct clk_branch camss_mclk3_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_mclk3_clk",
- .parent_names = (const char *[]){
- "mclk3_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &mclk3_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1862,8 +1878,8 @@ static struct clk_branch camss_micro_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_micro_ahb_clk",
- .parent_names = (const char *[]){
- "mmss_ahb_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &mmss_ahb_clk_src.clkr.hw
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -1878,8 +1894,8 @@ static struct clk_branch camss_phy0_csi0phytimer_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_phy0_csi0phytimer_clk",
- .parent_names = (const char *[]){
- "csi0phytimer_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &csi0phytimer_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1895,8 +1911,8 @@ static struct clk_branch camss_phy1_csi1phytimer_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_phy1_csi1phytimer_clk",
- .parent_names = (const char *[]){
- "csi1phytimer_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &csi1phytimer_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1912,8 +1928,8 @@ static struct clk_branch camss_phy2_csi2phytimer_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_phy2_csi2phytimer_clk",
- .parent_names = (const char *[]){
- "csi2phytimer_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &csi2phytimer_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1929,8 +1945,8 @@ static struct clk_branch camss_top_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_top_ahb_clk",
- .parent_names = (const char *[]){
- "mmss_ahb_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &mmss_ahb_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1946,8 +1962,8 @@ static struct clk_branch camss_vfe_cpp_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_vfe_cpp_ahb_clk",
- .parent_names = (const char *[]){
- "mmss_ahb_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &mmss_ahb_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1963,8 +1979,8 @@ static struct clk_branch camss_vfe_cpp_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_vfe_cpp_clk",
- .parent_names = (const char *[]){
- "cpp_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &cpp_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1980,8 +1996,8 @@ static struct clk_branch camss_vfe_vfe0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_vfe_vfe0_clk",
- .parent_names = (const char *[]){
- "vfe0_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &vfe0_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -1997,8 +2013,8 @@ static struct clk_branch camss_vfe_vfe1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_vfe_vfe1_clk",
- .parent_names = (const char *[]){
- "vfe1_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &vfe1_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2014,8 +2030,8 @@ static struct clk_branch camss_vfe_vfe_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_vfe_vfe_ahb_clk",
- .parent_names = (const char *[]){
- "mmss_ahb_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &mmss_ahb_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2031,8 +2047,8 @@ static struct clk_branch camss_vfe_vfe_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_vfe_vfe_axi_clk",
- .parent_names = (const char *[]){
- "mmss_axi_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &mmss_axi_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2048,8 +2064,8 @@ static struct clk_branch mdss_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mdss_ahb_clk",
- .parent_names = (const char *[]){
- "mmss_ahb_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &mmss_ahb_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2065,8 +2081,8 @@ static struct clk_branch mdss_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mdss_axi_clk",
- .parent_names = (const char *[]){
- "mmss_axi_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &mmss_axi_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2082,8 +2098,8 @@ static struct clk_branch mdss_byte0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mdss_byte0_clk",
- .parent_names = (const char *[]){
- "byte0_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &byte0_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2099,8 +2115,8 @@ static struct clk_branch mdss_byte1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mdss_byte1_clk",
- .parent_names = (const char *[]){
- "byte1_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &byte1_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2116,8 +2132,8 @@ static struct clk_branch mdss_edpaux_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mdss_edpaux_clk",
- .parent_names = (const char *[]){
- "edpaux_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &edpaux_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2133,8 +2149,8 @@ static struct clk_branch mdss_edplink_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mdss_edplink_clk",
- .parent_names = (const char *[]){
- "edplink_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &edplink_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2150,8 +2166,8 @@ static struct clk_branch mdss_edppixel_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mdss_edppixel_clk",
- .parent_names = (const char *[]){
- "edppixel_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &edppixel_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2167,8 +2183,8 @@ static struct clk_branch mdss_esc0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mdss_esc0_clk",
- .parent_names = (const char *[]){
- "esc0_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &esc0_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2184,8 +2200,8 @@ static struct clk_branch mdss_esc1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mdss_esc1_clk",
- .parent_names = (const char *[]){
- "esc1_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &esc1_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2201,8 +2217,8 @@ static struct clk_branch mdss_extpclk_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mdss_extpclk_clk",
- .parent_names = (const char *[]){
- "extpclk_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &extpclk_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2218,8 +2234,8 @@ static struct clk_branch mdss_hdmi_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mdss_hdmi_ahb_clk",
- .parent_names = (const char *[]){
- "mmss_ahb_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &mmss_ahb_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2235,8 +2251,8 @@ static struct clk_branch mdss_hdmi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mdss_hdmi_clk",
- .parent_names = (const char *[]){
- "hdmi_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &hdmi_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2252,8 +2268,8 @@ static struct clk_branch mdss_mdp_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mdss_mdp_clk",
- .parent_names = (const char *[]){
- "mdp_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &mdp_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2269,8 +2285,8 @@ static struct clk_branch mdss_mdp_lut_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mdss_mdp_lut_clk",
- .parent_names = (const char *[]){
- "mdp_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &mdp_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2286,8 +2302,8 @@ static struct clk_branch mdss_pclk0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mdss_pclk0_clk",
- .parent_names = (const char *[]){
- "pclk0_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &pclk0_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2303,8 +2319,8 @@ static struct clk_branch mdss_pclk1_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mdss_pclk1_clk",
- .parent_names = (const char *[]){
- "pclk1_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &pclk1_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2320,8 +2336,8 @@ static struct clk_branch mdss_vsync_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mdss_vsync_clk",
- .parent_names = (const char *[]){
- "vsync_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &vsync_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2337,8 +2353,8 @@ static struct clk_branch mmss_rbcpr_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mmss_rbcpr_ahb_clk",
- .parent_names = (const char *[]){
- "mmss_ahb_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &mmss_ahb_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2354,127 +2370,8 @@ static struct clk_branch mmss_rbcpr_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mmss_rbcpr_clk",
- .parent_names = (const char *[]){
- "rbcpr_clk_src",
- },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
- .ops = &clk_branch2_ops,
- },
- },
-};
-
-static struct clk_branch mmss_spdm_ahb_clk = {
- .halt_reg = 0x0230,
- .clkr = {
- .enable_reg = 0x0230,
- .enable_mask = BIT(0),
- .hw.init = &(struct clk_init_data){
- .name = "mmss_spdm_ahb_clk",
- .parent_names = (const char *[]){
- "mmss_spdm_ahb_div_clk",
- },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
- .ops = &clk_branch2_ops,
- },
- },
-};
-
-static struct clk_branch mmss_spdm_axi_clk = {
- .halt_reg = 0x0210,
- .clkr = {
- .enable_reg = 0x0210,
- .enable_mask = BIT(0),
- .hw.init = &(struct clk_init_data){
- .name = "mmss_spdm_axi_clk",
- .parent_names = (const char *[]){
- "mmss_spdm_axi_div_clk",
- },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
- .ops = &clk_branch2_ops,
- },
- },
-};
-
-static struct clk_branch mmss_spdm_csi0_clk = {
- .halt_reg = 0x023c,
- .clkr = {
- .enable_reg = 0x023c,
- .enable_mask = BIT(0),
- .hw.init = &(struct clk_init_data){
- .name = "mmss_spdm_csi0_clk",
- .parent_names = (const char *[]){
- "mmss_spdm_csi0_div_clk",
- },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
- .ops = &clk_branch2_ops,
- },
- },
-};
-
-static struct clk_branch mmss_spdm_gfx3d_clk = {
- .halt_reg = 0x022c,
- .clkr = {
- .enable_reg = 0x022c,
- .enable_mask = BIT(0),
- .hw.init = &(struct clk_init_data){
- .name = "mmss_spdm_gfx3d_clk",
- .parent_names = (const char *[]){
- "mmss_spdm_gfx3d_div_clk",
- },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
- .ops = &clk_branch2_ops,
- },
- },
-};
-
-static struct clk_branch mmss_spdm_jpeg0_clk = {
- .halt_reg = 0x0204,
- .clkr = {
- .enable_reg = 0x0204,
- .enable_mask = BIT(0),
- .hw.init = &(struct clk_init_data){
- .name = "mmss_spdm_jpeg0_clk",
- .parent_names = (const char *[]){
- "mmss_spdm_jpeg0_div_clk",
- },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
- .ops = &clk_branch2_ops,
- },
- },
-};
-
-static struct clk_branch mmss_spdm_jpeg1_clk = {
- .halt_reg = 0x0208,
- .clkr = {
- .enable_reg = 0x0208,
- .enable_mask = BIT(0),
- .hw.init = &(struct clk_init_data){
- .name = "mmss_spdm_jpeg1_clk",
- .parent_names = (const char *[]){
- "mmss_spdm_jpeg1_div_clk",
- },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
- .ops = &clk_branch2_ops,
- },
- },
-};
-
-static struct clk_branch mmss_spdm_jpeg2_clk = {
- .halt_reg = 0x0224,
- .clkr = {
- .enable_reg = 0x0224,
- .enable_mask = BIT(0),
- .hw.init = &(struct clk_init_data){
- .name = "mmss_spdm_jpeg2_clk",
- .parent_names = (const char *[]){
- "mmss_spdm_jpeg2_div_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &rbcpr_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2483,143 +2380,6 @@ static struct clk_branch mmss_spdm_jpeg2_clk = {
},
};
-static struct clk_branch mmss_spdm_mdp_clk = {
- .halt_reg = 0x020c,
- .clkr = {
- .enable_reg = 0x020c,
- .enable_mask = BIT(0),
- .hw.init = &(struct clk_init_data){
- .name = "mmss_spdm_mdp_clk",
- .parent_names = (const char *[]){
- "mmss_spdm_mdp_div_clk",
- },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
- .ops = &clk_branch2_ops,
- },
- },
-};
-
-static struct clk_branch mmss_spdm_pclk0_clk = {
- .halt_reg = 0x0234,
- .clkr = {
- .enable_reg = 0x0234,
- .enable_mask = BIT(0),
- .hw.init = &(struct clk_init_data){
- .name = "mmss_spdm_pclk0_clk",
- .parent_names = (const char *[]){
- "mmss_spdm_pclk0_div_clk",
- },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
- .ops = &clk_branch2_ops,
- },
- },
-};
-
-static struct clk_branch mmss_spdm_pclk1_clk = {
- .halt_reg = 0x0228,
- .clkr = {
- .enable_reg = 0x0228,
- .enable_mask = BIT(0),
- .hw.init = &(struct clk_init_data){
- .name = "mmss_spdm_pclk1_clk",
- .parent_names = (const char *[]){
- "mmss_spdm_pclk1_div_clk",
- },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
- .ops = &clk_branch2_ops,
- },
- },
-};
-
-static struct clk_branch mmss_spdm_vcodec0_clk = {
- .halt_reg = 0x0214,
- .clkr = {
- .enable_reg = 0x0214,
- .enable_mask = BIT(0),
- .hw.init = &(struct clk_init_data){
- .name = "mmss_spdm_vcodec0_clk",
- .parent_names = (const char *[]){
- "mmss_spdm_vcodec0_div_clk",
- },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
- .ops = &clk_branch2_ops,
- },
- },
-};
-
-static struct clk_branch mmss_spdm_vfe0_clk = {
- .halt_reg = 0x0218,
- .clkr = {
- .enable_reg = 0x0218,
- .enable_mask = BIT(0),
- .hw.init = &(struct clk_init_data){
- .name = "mmss_spdm_vfe0_clk",
- .parent_names = (const char *[]){
- "mmss_spdm_vfe0_div_clk",
- },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
- .ops = &clk_branch2_ops,
- },
- },
-};
-
-static struct clk_branch mmss_spdm_vfe1_clk = {
- .halt_reg = 0x021c,
- .clkr = {
- .enable_reg = 0x021c,
- .enable_mask = BIT(0),
- .hw.init = &(struct clk_init_data){
- .name = "mmss_spdm_vfe1_clk",
- .parent_names = (const char *[]){
- "mmss_spdm_vfe1_div_clk",
- },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
- .ops = &clk_branch2_ops,
- },
- },
-};
-
-static struct clk_branch mmss_spdm_rm_axi_clk = {
- .halt_reg = 0x0304,
- .clkr = {
- .enable_reg = 0x0304,
- .enable_mask = BIT(0),
- .hw.init = &(struct clk_init_data){
- .name = "mmss_spdm_rm_axi_clk",
- .parent_names = (const char *[]){
- "mmss_axi_clk_src",
- },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
- .ops = &clk_branch2_ops,
- },
- },
-};
-
-static struct clk_branch mmss_spdm_rm_ocmemnoc_clk = {
- .halt_reg = 0x0308,
- .clkr = {
- .enable_reg = 0x0308,
- .enable_mask = BIT(0),
- .hw.init = &(struct clk_init_data){
- .name = "mmss_spdm_rm_ocmemnoc_clk",
- .parent_names = (const char *[]){
- "ocmemnoc_clk_src",
- },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
- .ops = &clk_branch2_ops,
- },
- },
-};
-
-
static struct clk_branch mmss_misc_ahb_clk = {
.halt_reg = 0x502c,
.clkr = {
@@ -2627,8 +2387,8 @@ static struct clk_branch mmss_misc_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mmss_misc_ahb_clk",
- .parent_names = (const char *[]){
- "mmss_ahb_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &mmss_ahb_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2644,8 +2404,8 @@ static struct clk_branch mmss_mmssnoc_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mmss_mmssnoc_ahb_clk",
- .parent_names = (const char *[]){
- "mmss_ahb_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &mmss_ahb_clk_src.clkr.hw
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -2661,8 +2421,8 @@ static struct clk_branch mmss_mmssnoc_bto_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mmss_mmssnoc_bto_ahb_clk",
- .parent_names = (const char *[]){
- "mmss_ahb_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &mmss_ahb_clk_src.clkr.hw
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -2678,8 +2438,8 @@ static struct clk_branch mmss_mmssnoc_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mmss_mmssnoc_axi_clk",
- .parent_names = (const char *[]){
- "mmss_axi_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &mmss_axi_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
@@ -2695,8 +2455,8 @@ static struct clk_branch mmss_s0_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mmss_s0_axi_clk",
- .parent_names = (const char *[]){
- "mmss_axi_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &mmss_axi_clk_src.clkr.hw
},
.num_parents = 1,
.ops = &clk_branch2_ops,
@@ -2712,8 +2472,8 @@ static struct clk_branch ocmemcx_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "ocmemcx_ahb_clk",
- .parent_names = (const char *[]){
- "mmss_ahb_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &mmss_ahb_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2729,8 +2489,8 @@ static struct clk_branch ocmemcx_ocmemnoc_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "ocmemcx_ocmemnoc_clk",
- .parent_names = (const char *[]){
- "ocmemnoc_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &ocmemnoc_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2746,8 +2506,8 @@ static struct clk_branch oxili_ocmemgx_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "oxili_ocmemgx_clk",
- .parent_names = (const char *[]){
- "gfx3d_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &gfx3d_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2763,8 +2523,8 @@ static struct clk_branch oxili_gfx3d_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "oxili_gfx3d_clk",
- .parent_names = (const char *[]){
- "gfx3d_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &gfx3d_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2780,8 +2540,8 @@ static struct clk_branch oxili_rbbmtimer_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "oxili_rbbmtimer_clk",
- .parent_names = (const char *[]){
- "rbbmtimer_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &rbbmtimer_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2797,8 +2557,8 @@ static struct clk_branch oxilicx_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "oxilicx_ahb_clk",
- .parent_names = (const char *[]){
- "mmss_ahb_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &mmss_ahb_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2814,8 +2574,8 @@ static struct clk_branch venus0_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "venus0_ahb_clk",
- .parent_names = (const char *[]){
- "mmss_ahb_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &mmss_ahb_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2831,8 +2591,8 @@ static struct clk_branch venus0_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "venus0_axi_clk",
- .parent_names = (const char *[]){
- "mmss_axi_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &mmss_axi_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2848,8 +2608,8 @@ static struct clk_branch venus0_core0_vcodec_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "venus0_core0_vcodec_clk",
- .parent_names = (const char *[]){
- "vcodec0_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &vcodec0_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2865,8 +2625,8 @@ static struct clk_branch venus0_core1_vcodec_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "venus0_core1_vcodec_clk",
- .parent_names = (const char *[]){
- "vcodec0_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &vcodec0_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2882,8 +2642,8 @@ static struct clk_branch venus0_ocmemnoc_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "venus0_ocmemnoc_clk",
- .parent_names = (const char *[]){
- "ocmemnoc_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &ocmemnoc_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2899,8 +2659,8 @@ static struct clk_branch venus0_vcodec0_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "venus0_vcodec0_clk",
- .parent_names = (const char *[]){
- "vcodec0_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &vcodec0_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2916,8 +2676,8 @@ static struct clk_branch vpu_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "vpu_ahb_clk",
- .parent_names = (const char *[]){
- "mmss_ahb_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &mmss_ahb_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2933,8 +2693,8 @@ static struct clk_branch vpu_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "vpu_axi_clk",
- .parent_names = (const char *[]){
- "mmss_axi_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &mmss_axi_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2950,8 +2710,8 @@ static struct clk_branch vpu_bus_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "vpu_bus_clk",
- .parent_names = (const char *[]){
- "vpu_bus_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &vpu_bus_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2967,7 +2727,9 @@ static struct clk_branch vpu_cxo_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "vpu_cxo_clk",
- .parent_names = (const char *[]){ "xo" },
+ .parent_data = (const struct clk_parent_data[]){
+ { .fw_name = "xo", .name = "xo_board" },
+ },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
@@ -2982,8 +2744,8 @@ static struct clk_branch vpu_maple_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "vpu_maple_clk",
- .parent_names = (const char *[]){
- "maple_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &maple_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -2999,8 +2761,8 @@ static struct clk_branch vpu_sleep_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "vpu_sleep_clk",
- .parent_names = (const char *[]){
- "sleep_clk_src",
+ .parent_data = (const struct clk_parent_data[]){
+ { .fw_name = "sleep_clk", .name = "sleep_clk" },
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -3016,8 +2778,8 @@ static struct clk_branch vpu_vdp_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "vpu_vdp_clk",
- .parent_names = (const char *[]){
- "vdp_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &vdp_clk_src.clkr.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
@@ -3252,21 +3014,6 @@ static struct clk_regmap *mmcc_apq8084_clocks[] = {
[MDSS_VSYNC_CLK] = &mdss_vsync_clk.clkr,
[MMSS_RBCPR_AHB_CLK] = &mmss_rbcpr_ahb_clk.clkr,
[MMSS_RBCPR_CLK] = &mmss_rbcpr_clk.clkr,
- [MMSS_SPDM_AHB_CLK] = &mmss_spdm_ahb_clk.clkr,
- [MMSS_SPDM_AXI_CLK] = &mmss_spdm_axi_clk.clkr,
- [MMSS_SPDM_CSI0_CLK] = &mmss_spdm_csi0_clk.clkr,
- [MMSS_SPDM_GFX3D_CLK] = &mmss_spdm_gfx3d_clk.clkr,
- [MMSS_SPDM_JPEG0_CLK] = &mmss_spdm_jpeg0_clk.clkr,
- [MMSS_SPDM_JPEG1_CLK] = &mmss_spdm_jpeg1_clk.clkr,
- [MMSS_SPDM_JPEG2_CLK] = &mmss_spdm_jpeg2_clk.clkr,
- [MMSS_SPDM_MDP_CLK] = &mmss_spdm_mdp_clk.clkr,
- [MMSS_SPDM_PCLK0_CLK] = &mmss_spdm_pclk0_clk.clkr,
- [MMSS_SPDM_PCLK1_CLK] = &mmss_spdm_pclk1_clk.clkr,
- [MMSS_SPDM_VCODEC0_CLK] = &mmss_spdm_vcodec0_clk.clkr,
- [MMSS_SPDM_VFE0_CLK] = &mmss_spdm_vfe0_clk.clkr,
- [MMSS_SPDM_VFE1_CLK] = &mmss_spdm_vfe1_clk.clkr,
- [MMSS_SPDM_RM_AXI_CLK] = &mmss_spdm_rm_axi_clk.clkr,
- [MMSS_SPDM_RM_OCMEMNOC_CLK] = &mmss_spdm_rm_ocmemnoc_clk.clkr,
[MMSS_MISC_AHB_CLK] = &mmss_misc_ahb_clk.clkr,
[MMSS_MMSSNOC_AHB_CLK] = &mmss_mmssnoc_ahb_clk.clkr,
[MMSS_MMSSNOC_BTO_AHB_CLK] = &mmss_mmssnoc_bto_ahb_clk.clkr,
diff --git a/drivers/clk/qcom/mmcc-msm8998.c b/drivers/clk/qcom/mmcc-msm8998.c
index c421b1291651..4490594bde69 100644
--- a/drivers/clk/qcom/mmcc-msm8998.c
+++ b/drivers/clk/qcom/mmcc-msm8998.c
@@ -44,7 +44,6 @@ enum {
P_HDMIPLL,
P_DPVCO,
P_DPLINK,
- P_CORE_BI_PLL_TEST_SE,
};
static struct clk_fixed_factor gpll0_div = {
@@ -303,69 +302,59 @@ static struct clk_alpha_pll_postdiv mmpll10_out_even = {
static const struct parent_map mmss_xo_hdmi_map[] = {
{ P_XO, 0 },
{ P_HDMIPLL, 1 },
- { P_CORE_BI_PLL_TEST_SE, 7 }
};
static const struct clk_parent_data mmss_xo_hdmi[] = {
{ .fw_name = "xo" },
{ .fw_name = "hdmipll" },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct parent_map mmss_xo_dsi0pll_dsi1pll_map[] = {
{ P_XO, 0 },
{ P_DSI0PLL, 1 },
{ P_DSI1PLL, 2 },
- { P_CORE_BI_PLL_TEST_SE, 7 }
};
static const struct clk_parent_data mmss_xo_dsi0pll_dsi1pll[] = {
{ .fw_name = "xo" },
{ .fw_name = "dsi0dsi" },
{ .fw_name = "dsi1dsi" },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct parent_map mmss_xo_dsibyte_map[] = {
{ P_XO, 0 },
{ P_DSI0PLL_BYTE, 1 },
{ P_DSI1PLL_BYTE, 2 },
- { P_CORE_BI_PLL_TEST_SE, 7 }
};
static const struct clk_parent_data mmss_xo_dsibyte[] = {
{ .fw_name = "xo" },
{ .fw_name = "dsi0byte" },
{ .fw_name = "dsi1byte" },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct parent_map mmss_xo_dp_map[] = {
{ P_XO, 0 },
{ P_DPLINK, 1 },
{ P_DPVCO, 2 },
- { P_CORE_BI_PLL_TEST_SE, 7 }
};
static const struct clk_parent_data mmss_xo_dp[] = {
{ .fw_name = "xo" },
{ .fw_name = "dplink" },
{ .fw_name = "dpvco" },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct parent_map mmss_xo_gpll0_gpll0_div_map[] = {
{ P_XO, 0 },
{ P_GPLL0, 5 },
{ P_GPLL0_DIV, 6 },
- { P_CORE_BI_PLL_TEST_SE, 7 }
};
static const struct clk_parent_data mmss_xo_gpll0_gpll0_div[] = {
{ .fw_name = "xo" },
{ .fw_name = "gpll0" },
{ .hw = &gpll0_div.hw },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct parent_map mmss_xo_mmpll0_gpll0_gpll0_div_map[] = {
@@ -373,7 +362,6 @@ static const struct parent_map mmss_xo_mmpll0_gpll0_gpll0_div_map[] = {
{ P_MMPLL0_OUT_EVEN, 1 },
{ P_GPLL0, 5 },
{ P_GPLL0_DIV, 6 },
- { P_CORE_BI_PLL_TEST_SE, 7 }
};
static const struct clk_parent_data mmss_xo_mmpll0_gpll0_gpll0_div[] = {
@@ -381,7 +369,6 @@ static const struct clk_parent_data mmss_xo_mmpll0_gpll0_gpll0_div[] = {
{ .hw = &mmpll0_out_even.clkr.hw },
{ .fw_name = "gpll0" },
{ .hw = &gpll0_div.hw },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct parent_map mmss_xo_mmpll0_mmpll1_gpll0_gpll0_div_map[] = {
@@ -390,7 +377,6 @@ static const struct parent_map mmss_xo_mmpll0_mmpll1_gpll0_gpll0_div_map[] = {
{ P_MMPLL1_OUT_EVEN, 2 },
{ P_GPLL0, 5 },
{ P_GPLL0_DIV, 6 },
- { P_CORE_BI_PLL_TEST_SE, 7 }
};
static const struct clk_parent_data mmss_xo_mmpll0_mmpll1_gpll0_gpll0_div[] = {
@@ -399,7 +385,6 @@ static const struct clk_parent_data mmss_xo_mmpll0_mmpll1_gpll0_gpll0_div[] = {
{ .hw = &mmpll1_out_even.clkr.hw },
{ .fw_name = "gpll0" },
{ .hw = &gpll0_div.hw },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct parent_map mmss_xo_mmpll0_mmpll5_gpll0_gpll0_div_map[] = {
@@ -408,7 +393,6 @@ static const struct parent_map mmss_xo_mmpll0_mmpll5_gpll0_gpll0_div_map[] = {
{ P_MMPLL5_OUT_EVEN, 2 },
{ P_GPLL0, 5 },
{ P_GPLL0_DIV, 6 },
- { P_CORE_BI_PLL_TEST_SE, 7 }
};
static const struct clk_parent_data mmss_xo_mmpll0_mmpll5_gpll0_gpll0_div[] = {
@@ -417,7 +401,6 @@ static const struct clk_parent_data mmss_xo_mmpll0_mmpll5_gpll0_gpll0_div[] = {
{ .hw = &mmpll5_out_even.clkr.hw },
{ .fw_name = "gpll0" },
{ .hw = &gpll0_div.hw },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct parent_map mmss_xo_mmpll0_mmpll3_mmpll6_gpll0_gpll0_div_map[] = {
@@ -427,7 +410,6 @@ static const struct parent_map mmss_xo_mmpll0_mmpll3_mmpll6_gpll0_gpll0_div_map[
{ P_MMPLL6_OUT_EVEN, 4 },
{ P_GPLL0, 5 },
{ P_GPLL0_DIV, 6 },
- { P_CORE_BI_PLL_TEST_SE, 7 }
};
static const struct clk_parent_data mmss_xo_mmpll0_mmpll3_mmpll6_gpll0_gpll0_div[] = {
@@ -437,7 +419,6 @@ static const struct clk_parent_data mmss_xo_mmpll0_mmpll3_mmpll6_gpll0_gpll0_div
{ .hw = &mmpll6_out_even.clkr.hw },
{ .fw_name = "gpll0" },
{ .hw = &gpll0_div.hw },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct parent_map mmss_xo_mmpll4_mmpll7_mmpll10_gpll0_gpll0_div_map[] = {
@@ -447,7 +428,6 @@ static const struct parent_map mmss_xo_mmpll4_mmpll7_mmpll10_gpll0_gpll0_div_map
{ P_MMPLL10_OUT_EVEN, 3 },
{ P_GPLL0, 5 },
{ P_GPLL0_DIV, 6 },
- { P_CORE_BI_PLL_TEST_SE, 7 }
};
static const struct clk_parent_data mmss_xo_mmpll4_mmpll7_mmpll10_gpll0_gpll0_div[] = {
@@ -457,7 +437,6 @@ static const struct clk_parent_data mmss_xo_mmpll4_mmpll7_mmpll10_gpll0_gpll0_di
{ .hw = &mmpll10_out_even.clkr.hw },
{ .fw_name = "gpll0" },
{ .hw = &gpll0_div.hw },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct parent_map mmss_xo_mmpll0_mmpll7_mmpll10_gpll0_gpll0_div_map[] = {
@@ -467,7 +446,6 @@ static const struct parent_map mmss_xo_mmpll0_mmpll7_mmpll10_gpll0_gpll0_div_map
{ P_MMPLL10_OUT_EVEN, 3 },
{ P_GPLL0, 5 },
{ P_GPLL0_DIV, 6 },
- { P_CORE_BI_PLL_TEST_SE, 7 }
};
static const struct clk_parent_data mmss_xo_mmpll0_mmpll7_mmpll10_gpll0_gpll0_div[] = {
@@ -477,7 +455,6 @@ static const struct clk_parent_data mmss_xo_mmpll0_mmpll7_mmpll10_gpll0_gpll0_di
{ .hw = &mmpll10_out_even.clkr.hw },
{ .fw_name = "gpll0" },
{ .hw = &gpll0_div.hw },
- { .fw_name = "core_bi_pll_test_se" },
};
static const struct parent_map mmss_xo_mmpll0_mmpll4_mmpll7_mmpll10_gpll0_gpll0_div_map[] = {
@@ -488,7 +465,6 @@ static const struct parent_map mmss_xo_mmpll0_mmpll4_mmpll7_mmpll10_gpll0_gpll0_
{ P_MMPLL10_OUT_EVEN, 4 },
{ P_GPLL0, 5 },
{ P_GPLL0_DIV, 6 },
- { P_CORE_BI_PLL_TEST_SE, 7 }
};
static const struct clk_parent_data mmss_xo_mmpll0_mmpll4_mmpll7_mmpll10_gpll0_gpll0_div[] = {
@@ -499,7 +475,6 @@ static const struct clk_parent_data mmss_xo_mmpll0_mmpll4_mmpll7_mmpll10_gpll0_g
{ .hw = &mmpll10_out_even.clkr.hw },
{ .fw_name = "gpll0" },
{ .hw = &gpll0_div.hw },
- { .fw_name = "core_bi_pll_test_se" },
};
static struct clk_rcg2 byte0_clk_src = {
diff --git a/drivers/clk/qcom/tcsrcc-sm8550.c b/drivers/clk/qcom/tcsrcc-sm8550.c
new file mode 100644
index 000000000000..2c67ee71c196
--- /dev/null
+++ b/drivers/clk/qcom/tcsrcc-sm8550.c
@@ -0,0 +1,192 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022, Linaro Limited
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,sm8550-tcsr.h>
+
+#include "clk-alpha-pll.h"
+#include "clk-branch.h"
+#include "clk-pll.h"
+#include "clk-rcg.h"
+#include "clk-regmap.h"
+#include "clk-regmap-divider.h"
+#include "clk-regmap-mux.h"
+#include "common.h"
+#include "reset.h"
+
+enum {
+ DT_BI_TCXO_PAD,
+};
+
+static struct clk_branch tcsr_pcie_0_clkref_en = {
+ .halt_reg = 0x15100,
+ .halt_check = BRANCH_HALT_SKIP,
+ .clkr = {
+ .enable_reg = 0x15100,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "tcsr_pcie_0_clkref_en",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_BI_TCXO_PAD,
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch tcsr_pcie_1_clkref_en = {
+ .halt_reg = 0x15114,
+ .halt_check = BRANCH_HALT_SKIP,
+ .clkr = {
+ .enable_reg = 0x15114,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "tcsr_pcie_1_clkref_en",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_BI_TCXO_PAD,
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch tcsr_ufs_clkref_en = {
+ .halt_reg = 0x15110,
+ .halt_check = BRANCH_HALT_SKIP,
+ .clkr = {
+ .enable_reg = 0x15110,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "tcsr_ufs_clkref_en",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_BI_TCXO_PAD,
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch tcsr_ufs_pad_clkref_en = {
+ .halt_reg = 0x15104,
+ .halt_check = BRANCH_HALT_SKIP,
+ .clkr = {
+ .enable_reg = 0x15104,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "tcsr_ufs_pad_clkref_en",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_BI_TCXO_PAD,
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch tcsr_usb2_clkref_en = {
+ .halt_reg = 0x15118,
+ .halt_check = BRANCH_HALT_SKIP,
+ .clkr = {
+ .enable_reg = 0x15118,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "tcsr_usb2_clkref_en",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_BI_TCXO_PAD,
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch tcsr_usb3_clkref_en = {
+ .halt_reg = 0x15108,
+ .halt_check = BRANCH_HALT_SKIP,
+ .clkr = {
+ .enable_reg = 0x15108,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "tcsr_usb3_clkref_en",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_BI_TCXO_PAD,
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_regmap *tcsr_cc_sm8550_clocks[] = {
+ [TCSR_PCIE_0_CLKREF_EN] = &tcsr_pcie_0_clkref_en.clkr,
+ [TCSR_PCIE_1_CLKREF_EN] = &tcsr_pcie_1_clkref_en.clkr,
+ [TCSR_UFS_CLKREF_EN] = &tcsr_ufs_clkref_en.clkr,
+ [TCSR_UFS_PAD_CLKREF_EN] = &tcsr_ufs_pad_clkref_en.clkr,
+ [TCSR_USB2_CLKREF_EN] = &tcsr_usb2_clkref_en.clkr,
+ [TCSR_USB3_CLKREF_EN] = &tcsr_usb3_clkref_en.clkr,
+};
+
+static const struct regmap_config tcsr_cc_sm8550_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x2f000,
+ .fast_io = true,
+};
+
+static const struct qcom_cc_desc tcsr_cc_sm8550_desc = {
+ .config = &tcsr_cc_sm8550_regmap_config,
+ .clks = tcsr_cc_sm8550_clocks,
+ .num_clks = ARRAY_SIZE(tcsr_cc_sm8550_clocks),
+};
+
+static const struct of_device_id tcsr_cc_sm8550_match_table[] = {
+ { .compatible = "qcom,sm8550-tcsr" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, tcsr_cc_sm8550_match_table);
+
+static int tcsr_cc_sm8550_probe(struct platform_device *pdev)
+{
+ struct regmap *regmap;
+
+ regmap = qcom_cc_map(pdev, &tcsr_cc_sm8550_desc);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ return qcom_cc_really_probe(pdev, &tcsr_cc_sm8550_desc, regmap);
+}
+
+static struct platform_driver tcsr_cc_sm8550_driver = {
+ .probe = tcsr_cc_sm8550_probe,
+ .driver = {
+ .name = "tcsr_cc-sm8550",
+ .of_match_table = tcsr_cc_sm8550_match_table,
+ },
+};
+
+static int __init tcsr_cc_sm8550_init(void)
+{
+ return platform_driver_register(&tcsr_cc_sm8550_driver);
+}
+subsys_initcall(tcsr_cc_sm8550_init);
+
+static void __exit tcsr_cc_sm8550_exit(void)
+{
+ platform_driver_unregister(&tcsr_cc_sm8550_driver);
+}
+module_exit(tcsr_cc_sm8550_exit);
+
+MODULE_DESCRIPTION("QTI TCSRCC SM8550 Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/qcom/videocc-sm8250.c b/drivers/clk/qcom/videocc-sm8250.c
index f28f2cb051d7..ad46c4014a40 100644
--- a/drivers/clk/qcom/videocc-sm8250.c
+++ b/drivers/clk/qcom/videocc-sm8250.c
@@ -361,19 +361,12 @@ static const struct of_device_id video_cc_sm8250_match_table[] = {
};
MODULE_DEVICE_TABLE(of, video_cc_sm8250_match_table);
-static void video_cc_sm8250_pm_runtime_disable(void *data)
-{
- pm_runtime_disable(data);
-}
-
static int video_cc_sm8250_probe(struct platform_device *pdev)
{
struct regmap *regmap;
int ret;
- pm_runtime_enable(&pdev->dev);
-
- ret = devm_add_action_or_reset(&pdev->dev, video_cc_sm8250_pm_runtime_disable, &pdev->dev);
+ ret = devm_pm_runtime_enable(&pdev->dev);
if (ret)
return ret;
diff --git a/drivers/clk/ralink/clk-mt7621.c b/drivers/clk/ralink/clk-mt7621.c
index 99256659dd96..d95a33293b0a 100644
--- a/drivers/clk/ralink/clk-mt7621.c
+++ b/drivers/clk/ralink/clk-mt7621.c
@@ -121,7 +121,7 @@ static int mt7621_gate_is_enabled(struct clk_hw *hw)
if (regmap_read(sysc, SYSC_REG_CLKCFG1, &val))
return 0;
- return val & BIT(clk_gate->bit_idx);
+ return val & clk_gate->bit_idx;
}
static const struct clk_ops mt7621_gate_ops = {
@@ -133,8 +133,14 @@ static const struct clk_ops mt7621_gate_ops = {
static int mt7621_gate_ops_init(struct device *dev,
struct mt7621_gate *sclk)
{
+ /*
+ * There are drivers for this SoC that are older
+ * than clock driver and are not prepared for the clock.
+ * We don't want the kernel to disable anything so we
+ * add CLK_IS_CRITICAL flag here.
+ */
struct clk_init_data init = {
- .flags = CLK_SET_RATE_PARENT,
+ .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
.num_parents = 1,
.parent_names = &sclk->parent_name,
.ops = &mt7621_gate_ops,
diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig
index cacaf9b87d26..37632a0659d8 100644
--- a/drivers/clk/renesas/Kconfig
+++ b/drivers/clk/renesas/Kconfig
@@ -22,7 +22,7 @@ config CLK_RENESAS
select CLK_R8A7791 if ARCH_R8A7791 || ARCH_R8A7793
select CLK_R8A7792 if ARCH_R8A7792
select CLK_R8A7794 if ARCH_R8A7794
- select CLK_R8A7795 if ARCH_R8A77950 || ARCH_R8A77951
+ select CLK_R8A7795 if ARCH_R8A77951
select CLK_R8A77960 if ARCH_R8A77960
select CLK_R8A77961 if ARCH_R8A77961
select CLK_R8A77965 if ARCH_R8A77965
diff --git a/drivers/clk/renesas/r8a7795-cpg-mssr.c b/drivers/clk/renesas/r8a7795-cpg-mssr.c
index 301475c74f50..7a585a777d38 100644
--- a/drivers/clk/renesas/r8a7795-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a7795-cpg-mssr.c
@@ -128,7 +128,6 @@ static struct cpg_core_clk r8a7795_core_clks[] __initdata = {
};
static struct mssr_mod_clk r8a7795_mod_clks[] __initdata = {
- DEF_MOD("fdp1-2", 117, R8A7795_CLK_S2D1), /* ES1.x */
DEF_MOD("fdp1-1", 118, R8A7795_CLK_S0D1),
DEF_MOD("fdp1-0", 119, R8A7795_CLK_S0D1),
DEF_MOD("tmu4", 121, R8A7795_CLK_S0D6),
@@ -162,7 +161,6 @@ static struct mssr_mod_clk r8a7795_mod_clks[] __initdata = {
DEF_MOD("pcie1", 318, R8A7795_CLK_S3D1),
DEF_MOD("pcie0", 319, R8A7795_CLK_S3D1),
DEF_MOD("usb-dmac30", 326, R8A7795_CLK_S3D1),
- DEF_MOD("usb3-if1", 327, R8A7795_CLK_S3D1), /* ES1.x */
DEF_MOD("usb3-if0", 328, R8A7795_CLK_S3D1),
DEF_MOD("usb-dmac31", 329, R8A7795_CLK_S3D1),
DEF_MOD("usb-dmac0", 330, R8A7795_CLK_S3D1),
@@ -187,28 +185,21 @@ static struct mssr_mod_clk r8a7795_mod_clks[] __initdata = {
DEF_MOD("hscif0", 520, R8A7795_CLK_S3D1),
DEF_MOD("thermal", 522, R8A7795_CLK_CP),
DEF_MOD("pwm", 523, R8A7795_CLK_S0D12),
- DEF_MOD("fcpvd3", 600, R8A7795_CLK_S2D1), /* ES1.x */
DEF_MOD("fcpvd2", 601, R8A7795_CLK_S0D2),
DEF_MOD("fcpvd1", 602, R8A7795_CLK_S0D2),
DEF_MOD("fcpvd0", 603, R8A7795_CLK_S0D2),
DEF_MOD("fcpvb1", 606, R8A7795_CLK_S0D1),
DEF_MOD("fcpvb0", 607, R8A7795_CLK_S0D1),
- DEF_MOD("fcpvi2", 609, R8A7795_CLK_S2D1), /* ES1.x */
DEF_MOD("fcpvi1", 610, R8A7795_CLK_S0D1),
DEF_MOD("fcpvi0", 611, R8A7795_CLK_S0D1),
- DEF_MOD("fcpf2", 613, R8A7795_CLK_S2D1), /* ES1.x */
DEF_MOD("fcpf1", 614, R8A7795_CLK_S0D1),
DEF_MOD("fcpf0", 615, R8A7795_CLK_S0D1),
- DEF_MOD("fcpci1", 616, R8A7795_CLK_S2D1), /* ES1.x */
- DEF_MOD("fcpci0", 617, R8A7795_CLK_S2D1), /* ES1.x */
DEF_MOD("fcpcs", 619, R8A7795_CLK_S0D1),
- DEF_MOD("vspd3", 620, R8A7795_CLK_S2D1), /* ES1.x */
DEF_MOD("vspd2", 621, R8A7795_CLK_S0D2),
DEF_MOD("vspd1", 622, R8A7795_CLK_S0D2),
DEF_MOD("vspd0", 623, R8A7795_CLK_S0D2),
DEF_MOD("vspbc", 624, R8A7795_CLK_S0D1),
DEF_MOD("vspbd", 626, R8A7795_CLK_S0D1),
- DEF_MOD("vspi2", 629, R8A7795_CLK_S2D1), /* ES1.x */
DEF_MOD("vspi1", 630, R8A7795_CLK_S0D1),
DEF_MOD("vspi0", 631, R8A7795_CLK_S0D1),
DEF_MOD("ehci3", 700, R8A7795_CLK_S3D2),
@@ -221,7 +212,6 @@ static struct mssr_mod_clk r8a7795_mod_clks[] __initdata = {
DEF_MOD("cmm2", 709, R8A7795_CLK_S2D1),
DEF_MOD("cmm1", 710, R8A7795_CLK_S2D1),
DEF_MOD("cmm0", 711, R8A7795_CLK_S2D1),
- DEF_MOD("csi21", 713, R8A7795_CLK_CSI0), /* ES1.x */
DEF_MOD("csi20", 714, R8A7795_CLK_CSI0),
DEF_MOD("csi41", 715, R8A7795_CLK_CSI0),
DEF_MOD("csi40", 716, R8A7795_CLK_CSI0),
@@ -350,103 +340,26 @@ static const struct rcar_gen3_cpg_pll_config cpg_pll_configs[16] __initconst = {
{ 2, 192, 1, 192, 1, 32, },
};
-static const struct soc_device_attribute r8a7795es1[] __initconst = {
+static const struct soc_device_attribute r8a7795_denylist[] __initconst = {
{ .soc_id = "r8a7795", .revision = "ES1.*" },
{ /* sentinel */ }
};
-
- /*
- * Fixups for R-Car H3 ES1.x
- */
-
-static const unsigned int r8a7795es1_mod_nullify[] __initconst = {
- MOD_CLK_ID(326), /* USB-DMAC3-0 */
- MOD_CLK_ID(329), /* USB-DMAC3-1 */
- MOD_CLK_ID(700), /* EHCI/OHCI3 */
- MOD_CLK_ID(705), /* HS-USB-IF3 */
-
-};
-
-static const struct mssr_mod_reparent r8a7795es1_mod_reparent[] __initconst = {
- { MOD_CLK_ID(118), R8A7795_CLK_S2D1 }, /* FDP1-1 */
- { MOD_CLK_ID(119), R8A7795_CLK_S2D1 }, /* FDP1-0 */
- { MOD_CLK_ID(121), R8A7795_CLK_S3D2 }, /* TMU4 */
- { MOD_CLK_ID(217), R8A7795_CLK_S3D1 }, /* SYS-DMAC2 */
- { MOD_CLK_ID(218), R8A7795_CLK_S3D1 }, /* SYS-DMAC1 */
- { MOD_CLK_ID(219), R8A7795_CLK_S3D1 }, /* SYS-DMAC0 */
- { MOD_CLK_ID(408), R8A7795_CLK_S3D1 }, /* INTC-AP */
- { MOD_CLK_ID(501), R8A7795_CLK_S3D1 }, /* AUDMAC1 */
- { MOD_CLK_ID(502), R8A7795_CLK_S3D1 }, /* AUDMAC0 */
- { MOD_CLK_ID(523), R8A7795_CLK_S3D4 }, /* PWM */
- { MOD_CLK_ID(601), R8A7795_CLK_S2D1 }, /* FCPVD2 */
- { MOD_CLK_ID(602), R8A7795_CLK_S2D1 }, /* FCPVD1 */
- { MOD_CLK_ID(603), R8A7795_CLK_S2D1 }, /* FCPVD0 */
- { MOD_CLK_ID(606), R8A7795_CLK_S2D1 }, /* FCPVB1 */
- { MOD_CLK_ID(607), R8A7795_CLK_S2D1 }, /* FCPVB0 */
- { MOD_CLK_ID(610), R8A7795_CLK_S2D1 }, /* FCPVI1 */
- { MOD_CLK_ID(611), R8A7795_CLK_S2D1 }, /* FCPVI0 */
- { MOD_CLK_ID(614), R8A7795_CLK_S2D1 }, /* FCPF1 */
- { MOD_CLK_ID(615), R8A7795_CLK_S2D1 }, /* FCPF0 */
- { MOD_CLK_ID(619), R8A7795_CLK_S2D1 }, /* FCPCS */
- { MOD_CLK_ID(621), R8A7795_CLK_S2D1 }, /* VSPD2 */
- { MOD_CLK_ID(622), R8A7795_CLK_S2D1 }, /* VSPD1 */
- { MOD_CLK_ID(623), R8A7795_CLK_S2D1 }, /* VSPD0 */
- { MOD_CLK_ID(624), R8A7795_CLK_S2D1 }, /* VSPBC */
- { MOD_CLK_ID(626), R8A7795_CLK_S2D1 }, /* VSPBD */
- { MOD_CLK_ID(630), R8A7795_CLK_S2D1 }, /* VSPI1 */
- { MOD_CLK_ID(631), R8A7795_CLK_S2D1 }, /* VSPI0 */
- { MOD_CLK_ID(804), R8A7795_CLK_S2D1 }, /* VIN7 */
- { MOD_CLK_ID(805), R8A7795_CLK_S2D1 }, /* VIN6 */
- { MOD_CLK_ID(806), R8A7795_CLK_S2D1 }, /* VIN5 */
- { MOD_CLK_ID(807), R8A7795_CLK_S2D1 }, /* VIN4 */
- { MOD_CLK_ID(808), R8A7795_CLK_S2D1 }, /* VIN3 */
- { MOD_CLK_ID(809), R8A7795_CLK_S2D1 }, /* VIN2 */
- { MOD_CLK_ID(810), R8A7795_CLK_S2D1 }, /* VIN1 */
- { MOD_CLK_ID(811), R8A7795_CLK_S2D1 }, /* VIN0 */
- { MOD_CLK_ID(812), R8A7795_CLK_S3D2 }, /* EAVB-IF */
- { MOD_CLK_ID(820), R8A7795_CLK_S2D1 }, /* IMR3 */
- { MOD_CLK_ID(821), R8A7795_CLK_S2D1 }, /* IMR2 */
- { MOD_CLK_ID(822), R8A7795_CLK_S2D1 }, /* IMR1 */
- { MOD_CLK_ID(823), R8A7795_CLK_S2D1 }, /* IMR0 */
- { MOD_CLK_ID(905), R8A7795_CLK_CP }, /* GPIO7 */
- { MOD_CLK_ID(906), R8A7795_CLK_CP }, /* GPIO6 */
- { MOD_CLK_ID(907), R8A7795_CLK_CP }, /* GPIO5 */
- { MOD_CLK_ID(908), R8A7795_CLK_CP }, /* GPIO4 */
- { MOD_CLK_ID(909), R8A7795_CLK_CP }, /* GPIO3 */
- { MOD_CLK_ID(910), R8A7795_CLK_CP }, /* GPIO2 */
- { MOD_CLK_ID(911), R8A7795_CLK_CP }, /* GPIO1 */
- { MOD_CLK_ID(912), R8A7795_CLK_CP }, /* GPIO0 */
- { MOD_CLK_ID(918), R8A7795_CLK_S3D2 }, /* I2C6 */
- { MOD_CLK_ID(919), R8A7795_CLK_S3D2 }, /* I2C5 */
- { MOD_CLK_ID(927), R8A7795_CLK_S3D2 }, /* I2C4 */
- { MOD_CLK_ID(928), R8A7795_CLK_S3D2 }, /* I2C3 */
-};
-
-
- /*
- * Fixups for R-Car H3 ES2.x
- */
-
-static const unsigned int r8a7795es2_mod_nullify[] __initconst = {
- MOD_CLK_ID(117), /* FDP1-2 */
- MOD_CLK_ID(327), /* USB3-IF1 */
- MOD_CLK_ID(600), /* FCPVD3 */
- MOD_CLK_ID(609), /* FCPVI2 */
- MOD_CLK_ID(613), /* FCPF2 */
- MOD_CLK_ID(616), /* FCPCI1 */
- MOD_CLK_ID(617), /* FCPCI0 */
- MOD_CLK_ID(620), /* VSPD3 */
- MOD_CLK_ID(629), /* VSPI2 */
- MOD_CLK_ID(713), /* CSI21 */
-};
-
static int __init r8a7795_cpg_mssr_init(struct device *dev)
{
const struct rcar_gen3_cpg_pll_config *cpg_pll_config;
u32 cpg_mode;
int error;
+ /*
+ * We panic here to ensure removed SoCs and clk updates are always in
+ * sync to avoid overclocking damages. The panic can only be seen with
+ * commandline args 'earlycon keep_bootcon'. But these SoCs were for
+ * developers only anyhow.
+ */
+ if (soc_device_match(r8a7795_denylist))
+ panic("SoC not supported anymore!\n");
+
error = rcar_rst_read_mode_pins(&cpg_mode);
if (error)
return error;
@@ -457,25 +370,6 @@ static int __init r8a7795_cpg_mssr_init(struct device *dev)
return -EINVAL;
}
- if (soc_device_match(r8a7795es1)) {
- cpg_core_nullify_range(r8a7795_core_clks,
- ARRAY_SIZE(r8a7795_core_clks),
- R8A7795_CLK_S0D2, R8A7795_CLK_S0D12);
- mssr_mod_nullify(r8a7795_mod_clks,
- ARRAY_SIZE(r8a7795_mod_clks),
- r8a7795es1_mod_nullify,
- ARRAY_SIZE(r8a7795es1_mod_nullify));
- mssr_mod_reparent(r8a7795_mod_clks,
- ARRAY_SIZE(r8a7795_mod_clks),
- r8a7795es1_mod_reparent,
- ARRAY_SIZE(r8a7795es1_mod_reparent));
- } else {
- mssr_mod_nullify(r8a7795_mod_clks,
- ARRAY_SIZE(r8a7795_mod_clks),
- r8a7795es2_mod_nullify,
- ARRAY_SIZE(r8a7795es2_mod_nullify));
- }
-
return rcar_gen3_cpg_init(cpg_pll_config, CLK_EXTALR, cpg_mode);
}
diff --git a/drivers/clk/renesas/r8a779a0-cpg-mssr.c b/drivers/clk/renesas/r8a779a0-cpg-mssr.c
index e02542ca24a0..fcc8279647a6 100644
--- a/drivers/clk/renesas/r8a779a0-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a779a0-cpg-mssr.c
@@ -176,8 +176,8 @@ static const struct mssr_mod_clk r8a779a0_mod_clks[] __initconst = {
DEF_MOD("scif3", 704, R8A779A0_CLK_S1D8),
DEF_MOD("scif4", 705, R8A779A0_CLK_S1D8),
DEF_MOD("sdhi0", 706, R8A779A0_CLK_SD0),
- DEF_MOD("sydm1", 709, R8A779A0_CLK_S1D2),
- DEF_MOD("sydm2", 710, R8A779A0_CLK_S1D2),
+ DEF_MOD("sys-dmac1", 709, R8A779A0_CLK_S1D2),
+ DEF_MOD("sys-dmac2", 710, R8A779A0_CLK_S1D2),
DEF_MOD("tmu0", 713, R8A779A0_CLK_CL16MCK),
DEF_MOD("tmu1", 714, R8A779A0_CLK_S1D4),
DEF_MOD("tmu2", 715, R8A779A0_CLK_S1D4),
diff --git a/drivers/clk/renesas/r8a779g0-cpg-mssr.c b/drivers/clk/renesas/r8a779g0-cpg-mssr.c
index c6337a408e5e..7fca11204f74 100644
--- a/drivers/clk/renesas/r8a779g0-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a779g0-cpg-mssr.c
@@ -66,13 +66,13 @@ static const struct cpg_core_clk r8a779g0_core_clks[] __initconst = {
DEF_INPUT("extalr", CLK_EXTALR),
/* Internal Core Clocks */
- DEF_BASE(".main", CLK_MAIN, CLK_TYPE_GEN4_MAIN, CLK_EXTAL),
- DEF_BASE(".pll1", CLK_PLL1, CLK_TYPE_GEN4_PLL1, CLK_MAIN),
- DEF_BASE(".pll2", CLK_PLL2, CLK_TYPE_GEN4_PLL2, CLK_MAIN),
- DEF_BASE(".pll3", CLK_PLL3, CLK_TYPE_GEN4_PLL3, CLK_MAIN),
- DEF_BASE(".pll4", CLK_PLL4, CLK_TYPE_GEN4_PLL4, CLK_MAIN),
- DEF_BASE(".pll5", CLK_PLL5, CLK_TYPE_GEN4_PLL5, CLK_MAIN),
- DEF_BASE(".pll6", CLK_PLL6, CLK_TYPE_GEN4_PLL6, CLK_MAIN),
+ DEF_BASE(".main", CLK_MAIN, CLK_TYPE_GEN4_MAIN, CLK_EXTAL),
+ DEF_BASE(".pll1", CLK_PLL1, CLK_TYPE_GEN4_PLL1, CLK_MAIN),
+ DEF_BASE(".pll2", CLK_PLL2, CLK_TYPE_GEN4_PLL2_VAR, CLK_MAIN),
+ DEF_BASE(".pll3", CLK_PLL3, CLK_TYPE_GEN4_PLL3, CLK_MAIN),
+ DEF_BASE(".pll4", CLK_PLL4, CLK_TYPE_GEN4_PLL4, CLK_MAIN),
+ DEF_BASE(".pll5", CLK_PLL5, CLK_TYPE_GEN4_PLL5, CLK_MAIN),
+ DEF_BASE(".pll6", CLK_PLL6, CLK_TYPE_GEN4_PLL6, CLK_MAIN),
DEF_FIXED(".pll1_div2", CLK_PLL1_DIV2, CLK_PLL1, 2, 1),
DEF_FIXED(".pll2_div2", CLK_PLL2_DIV2, CLK_PLL2, 2, 1),
@@ -145,6 +145,9 @@ static const struct cpg_core_clk r8a779g0_core_clks[] __initconst = {
DEF_FIXED("viobusd2", R8A779G0_CLK_VIOBUSD2, CLK_VIO, 2, 1),
DEF_FIXED("vcbus", R8A779G0_CLK_VCBUS, CLK_VC, 1, 1),
DEF_FIXED("vcbusd2", R8A779G0_CLK_VCBUSD2, CLK_VC, 2, 1),
+ DEF_DIV6P1("canfd", R8A779G0_CLK_CANFD, CLK_PLL5_DIV4, 0x878),
+ DEF_FIXED("dsiref", R8A779G0_CLK_DSIREF, CLK_PLL5_DIV4, 48, 1),
+ DEF_DIV6P1("dsiext", R8A779G0_CLK_DSIEXT, CLK_PLL5_DIV4, 0x884),
DEF_GEN4_SDH("sd0h", R8A779G0_CLK_SD0H, CLK_SDSRC, 0x870),
DEF_GEN4_SD("sd0", R8A779G0_CLK_SD0, R8A779G0_CLK_SD0H, 0x870),
@@ -161,6 +164,12 @@ static const struct mssr_mod_clk r8a779g0_mod_clks[] __initconst = {
DEF_MOD("avb0", 211, R8A779G0_CLK_S0D4_HSC),
DEF_MOD("avb1", 212, R8A779G0_CLK_S0D4_HSC),
DEF_MOD("avb2", 213, R8A779G0_CLK_S0D4_HSC),
+ DEF_MOD("canfd0", 328, R8A779G0_CLK_SASYNCPERD2),
+ DEF_MOD("dis0", 411, R8A779G0_CLK_VIOBUSD2),
+ DEF_MOD("dsitxlink0", 415, R8A779G0_CLK_VIOBUSD2),
+ DEF_MOD("dsitxlink1", 416, R8A779G0_CLK_VIOBUSD2),
+ DEF_MOD("fcpvd0", 508, R8A779G0_CLK_VIOBUSD2),
+ DEF_MOD("fcpvd1", 509, R8A779G0_CLK_VIOBUSD2),
DEF_MOD("hscif0", 514, R8A779G0_CLK_SASYNCPERD1),
DEF_MOD("hscif1", 515, R8A779G0_CLK_SASYNCPERD1),
DEF_MOD("hscif2", 516, R8A779G0_CLK_SASYNCPERD1),
@@ -185,14 +194,16 @@ static const struct mssr_mod_clk r8a779g0_mod_clks[] __initconst = {
DEF_MOD("scif3", 704, R8A779G0_CLK_SASYNCPERD4),
DEF_MOD("scif4", 705, R8A779G0_CLK_SASYNCPERD4),
DEF_MOD("sdhi", 706, R8A779G0_CLK_SD0),
- DEF_MOD("sydm0", 709, R8A779G0_CLK_S0D6_PER),
- DEF_MOD("sydm1", 710, R8A779G0_CLK_S0D6_PER),
+ DEF_MOD("sys-dmac0", 709, R8A779G0_CLK_S0D6_PER),
+ DEF_MOD("sys-dmac1", 710, R8A779G0_CLK_S0D6_PER),
DEF_MOD("tmu0", 713, R8A779G0_CLK_SASYNCRT),
DEF_MOD("tmu1", 714, R8A779G0_CLK_SASYNCPERD2),
DEF_MOD("tmu2", 715, R8A779G0_CLK_SASYNCPERD2),
DEF_MOD("tmu3", 716, R8A779G0_CLK_SASYNCPERD2),
DEF_MOD("tmu4", 717, R8A779G0_CLK_SASYNCPERD2),
DEF_MOD("tpu0", 718, R8A779G0_CLK_SASYNCPERD4),
+ DEF_MOD("vspd0", 830, R8A779G0_CLK_VIOBUSD2),
+ DEF_MOD("vspd1", 831, R8A779G0_CLK_VIOBUSD2),
DEF_MOD("wdt1:wdt0", 907, R8A779G0_CLK_R),
DEF_MOD("cmt0", 910, R8A779G0_CLK_R),
DEF_MOD("cmt1", 911, R8A779G0_CLK_R),
@@ -211,20 +222,20 @@ static const struct mssr_mod_clk r8a779g0_mod_clks[] __initconst = {
* MD EXTAL PLL1 PLL2 PLL3 PLL4 PLL5 PLL6 OSC
* 14 13 (MHz)
* ------------------------------------------------------------------------
- * 0 0 16.66 / 1 x192 x204 x192 x144 x192 x168 /15
+ * 0 0 16.66 / 1 x192 x204 x192 x144 x192 x168 /16
* 0 1 20 / 1 x160 x170 x160 x120 x160 x140 /19
* 1 0 Prohibited setting
- * 1 1 33.33 / 2 x192 x204 x192 x144 x192 x168 /38
+ * 1 1 33.33 / 2 x192 x204 x192 x144 x192 x168 /32
*/
#define CPG_PLL_CONFIG_INDEX(md) ((((md) & BIT(14)) >> 13) | \
(((md) & BIT(13)) >> 13))
static const struct rcar_gen4_cpg_pll_config cpg_pll_configs[4] = {
/* EXTAL div PLL1 mult/div PLL2 mult/div PLL3 mult/div PLL4 mult/div PLL5 mult/div PLL6 mult/div OSC prediv */
- { 1, 192, 1, 204, 1, 192, 1, 144, 1, 192, 1, 168, 1, 15, },
+ { 1, 192, 1, 204, 1, 192, 1, 144, 1, 192, 1, 168, 1, 16, },
{ 1, 160, 1, 170, 1, 160, 1, 120, 1, 160, 1, 140, 1, 19, },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
- { 2, 192, 1, 204, 1, 192, 1, 144, 1, 192, 1, 168, 1, 38, },
+ { 2, 192, 1, 204, 1, 192, 1, 144, 1, 192, 1, 168, 1, 32, },
};
static int __init r8a779g0_cpg_mssr_init(struct device *dev)
diff --git a/drivers/clk/renesas/r9a06g032-clocks.c b/drivers/clk/renesas/r9a06g032-clocks.c
index 983faa5707b9..087146f2ee06 100644
--- a/drivers/clk/renesas/r9a06g032-clocks.c
+++ b/drivers/clk/renesas/r9a06g032-clocks.c
@@ -25,6 +25,8 @@
#include <linux/spinlock.h>
#include <dt-bindings/clock/r9a06g032-sysctrl.h>
+#define R9A06G032_SYSCTRL_USB 0x00
+#define R9A06G032_SYSCTRL_USB_H2MODE (1<<1)
#define R9A06G032_SYSCTRL_DMAMUX 0xA0
struct r9a06g032_gate {
@@ -918,6 +920,29 @@ static void r9a06g032_clocks_del_clk_provider(void *data)
of_clk_del_provider(data);
}
+static void __init r9a06g032_init_h2mode(struct r9a06g032_priv *clocks)
+{
+ struct device_node *usbf_np = NULL;
+ u32 usb;
+
+ while ((usbf_np = of_find_compatible_node(usbf_np, NULL,
+ "renesas,rzn1-usbf"))) {
+ if (of_device_is_available(usbf_np))
+ break;
+ }
+
+ usb = readl(clocks->reg + R9A06G032_SYSCTRL_USB);
+ if (usbf_np) {
+ /* 1 host and 1 device mode */
+ usb &= ~R9A06G032_SYSCTRL_USB_H2MODE;
+ of_node_put(usbf_np);
+ } else {
+ /* 2 hosts mode */
+ usb |= R9A06G032_SYSCTRL_USB_H2MODE;
+ }
+ writel(usb, clocks->reg + R9A06G032_SYSCTRL_USB);
+}
+
static int __init r9a06g032_clocks_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -947,6 +972,9 @@ static int __init r9a06g032_clocks_probe(struct platform_device *pdev)
clocks->reg = of_iomap(np, 0);
if (WARN_ON(!clocks->reg))
return -ENOMEM;
+
+ r9a06g032_init_h2mode(clocks);
+
for (i = 0; i < ARRAY_SIZE(r9a06g032_clocks); ++i) {
const struct r9a06g032_clkdesc *d = &r9a06g032_clocks[i];
const char *parent_name = d->source ?
diff --git a/drivers/clk/renesas/r9a07g044-cpg.c b/drivers/clk/renesas/r9a07g044-cpg.c
index f5550fccb029..c597414a94d8 100644
--- a/drivers/clk/renesas/r9a07g044-cpg.c
+++ b/drivers/clk/renesas/r9a07g044-cpg.c
@@ -182,7 +182,7 @@ static const struct {
};
static const struct {
- struct rzg2l_mod_clk common[75];
+ struct rzg2l_mod_clk common[79];
#ifdef CONFIG_CLK_R9A07G054
struct rzg2l_mod_clk drp[0];
#endif
@@ -250,6 +250,14 @@ static const struct {
0x558, 1),
DEF_MOD("gpu_ace_clk", R9A07G044_GPU_ACE_CLK, R9A07G044_CLK_P1,
0x558, 2),
+ DEF_MOD("cru_sysclk", R9A07G044_CRU_SYSCLK, CLK_M2_DIV2,
+ 0x564, 0),
+ DEF_MOD("cru_vclk", R9A07G044_CRU_VCLK, R9A07G044_CLK_M2,
+ 0x564, 1),
+ DEF_MOD("cru_pclk", R9A07G044_CRU_PCLK, R9A07G044_CLK_ZT,
+ 0x564, 2),
+ DEF_MOD("cru_aclk", R9A07G044_CRU_ACLK, R9A07G044_CLK_M0,
+ 0x564, 3),
DEF_MOD("dsi_pll_clk", R9A07G044_MIPI_DSI_PLLCLK, R9A07G044_CLK_M1,
0x568, 0),
DEF_MOD("dsi_sys_clk", R9A07G044_MIPI_DSI_SYSCLK, CLK_M2_DIV2,
@@ -368,6 +376,9 @@ static struct rzg2l_reset r9a07g044_resets[] = {
DEF_RST(R9A07G044_GPU_RESETN, 0x858, 0),
DEF_RST(R9A07G044_GPU_AXI_RESETN, 0x858, 1),
DEF_RST(R9A07G044_GPU_ACE_RESETN, 0x858, 2),
+ DEF_RST(R9A07G044_CRU_CMN_RSTB, 0x864, 0),
+ DEF_RST(R9A07G044_CRU_PRESETN, 0x864, 1),
+ DEF_RST(R9A07G044_CRU_ARESETN, 0x864, 2),
DEF_RST(R9A07G044_MIPI_DSI_CMN_RSTB, 0x868, 0),
DEF_RST(R9A07G044_MIPI_DSI_ARESET_N, 0x868, 1),
DEF_RST(R9A07G044_MIPI_DSI_PRESET_N, 0x868, 2),
@@ -412,6 +423,11 @@ static const unsigned int r9a07g044_crit_mod_clks[] __initconst = {
MOD_CLK_BASE + R9A07G044_DMAC_ACLK,
};
+static const unsigned int r9a07g044_no_pm_mod_clks[] = {
+ MOD_CLK_BASE + R9A07G044_CRU_SYSCLK,
+ MOD_CLK_BASE + R9A07G044_CRU_VCLK,
+};
+
#ifdef CONFIG_CLK_R9A07G044
const struct rzg2l_cpg_info r9a07g044_cpg_info = {
/* Core Clocks */
@@ -429,6 +445,10 @@ const struct rzg2l_cpg_info r9a07g044_cpg_info = {
.num_mod_clks = ARRAY_SIZE(mod_clks.common),
.num_hw_mod_clks = R9A07G044_TSU_PCLK + 1,
+ /* No PM Module Clocks */
+ .no_pm_mod_clks = r9a07g044_no_pm_mod_clks,
+ .num_no_pm_mod_clks = ARRAY_SIZE(r9a07g044_no_pm_mod_clks),
+
/* Resets */
.resets = r9a07g044_resets,
.num_resets = R9A07G044_TSU_PRESETN + 1, /* Last reset ID + 1 */
@@ -454,6 +474,10 @@ const struct rzg2l_cpg_info r9a07g054_cpg_info = {
.num_mod_clks = ARRAY_SIZE(mod_clks.common) + ARRAY_SIZE(mod_clks.drp),
.num_hw_mod_clks = R9A07G054_STPAI_ACLK_DRP + 1,
+ /* No PM Module Clocks */
+ .no_pm_mod_clks = r9a07g044_no_pm_mod_clks,
+ .num_no_pm_mod_clks = ARRAY_SIZE(r9a07g044_no_pm_mod_clks),
+
/* Resets */
.resets = r9a07g044_resets,
.num_resets = R9A07G054_STPAI_ARESETN + 1, /* Last reset ID + 1 */
diff --git a/drivers/clk/renesas/r9a09g011-cpg.c b/drivers/clk/renesas/r9a09g011-cpg.c
index fbef1b35d254..3d06baf5061d 100644
--- a/drivers/clk/renesas/r9a09g011-cpg.c
+++ b/drivers/clk/renesas/r9a09g011-cpg.c
@@ -23,11 +23,14 @@
#define DIV_A DDIV_PACK(0x200, 0, 3)
#define DIV_B DDIV_PACK(0x204, 0, 2)
+#define DIV_D DDIV_PACK(0x204, 4, 2)
#define DIV_E DDIV_PACK(0x204, 8, 1)
#define DIV_W DDIV_PACK(0x328, 0, 3)
#define SEL_B SEL_PLL_PACK(0x214, 0, 1)
+#define SEL_D SEL_PLL_PACK(0x214, 1, 1)
#define SEL_E SEL_PLL_PACK(0x214, 2, 1)
+#define SEL_SDI SEL_PLL_PACK(0x300, 0, 1)
#define SEL_W0 SEL_PLL_PACK(0x32C, 0, 1)
enum clk_ids {
@@ -50,11 +53,14 @@ enum clk_ids {
CLK_PLL4,
CLK_DIV_A,
CLK_DIV_B,
+ CLK_DIV_D,
CLK_DIV_E,
CLK_DIV_W,
CLK_SEL_B,
CLK_SEL_B_D2,
+ CLK_SEL_D,
CLK_SEL_E,
+ CLK_SEL_SDI,
CLK_SEL_W0,
/* Module Clocks */
@@ -81,6 +87,14 @@ static const struct clk_div_table dtable_divb[] = {
{0, 0},
};
+static const struct clk_div_table dtable_divd[] = {
+ {0, 1},
+ {1, 2},
+ {2, 4},
+ {0, 0},
+};
+
+
static const struct clk_div_table dtable_divw[] = {
{0, 6},
{1, 7},
@@ -94,8 +108,10 @@ static const struct clk_div_table dtable_divw[] = {
/* Mux clock tables */
static const char * const sel_b[] = { ".main", ".divb" };
+static const char * const sel_d[] = { ".main", ".divd" };
static const char * const sel_e[] = { ".main", ".dive" };
static const char * const sel_w[] = { ".main", ".divw" };
+static const char * const sel_sdi[] = { ".main", ".pll2_200" };
static const struct cpg_core_clk r9a09g011_core_clks[] __initconst = {
/* External Clock Inputs */
@@ -115,11 +131,14 @@ static const struct cpg_core_clk r9a09g011_core_clks[] __initconst = {
DEF_DIV_RO(".diva", CLK_DIV_A, CLK_PLL1, DIV_A, dtable_diva),
DEF_DIV_RO(".divb", CLK_DIV_B, CLK_PLL2_400, DIV_B, dtable_divb),
+ DEF_DIV_RO(".divd", CLK_DIV_D, CLK_PLL2_200, DIV_D, dtable_divd),
DEF_DIV_RO(".dive", CLK_DIV_E, CLK_PLL2_100, DIV_E, NULL),
DEF_DIV_RO(".divw", CLK_DIV_W, CLK_PLL4, DIV_W, dtable_divw),
DEF_MUX_RO(".selb", CLK_SEL_B, SEL_B, sel_b),
+ DEF_MUX_RO(".seld", CLK_SEL_D, SEL_D, sel_d),
DEF_MUX_RO(".sele", CLK_SEL_E, SEL_E, sel_e),
+ DEF_MUX(".selsdi", CLK_SEL_SDI, SEL_SDI, sel_sdi),
DEF_MUX(".selw0", CLK_SEL_W0, SEL_W0, sel_w),
DEF_FIXED(".selb_d2", CLK_SEL_B_D2, CLK_SEL_B, 1, 2),
@@ -128,14 +147,55 @@ static const struct cpg_core_clk r9a09g011_core_clks[] __initconst = {
static const struct rzg2l_mod_clk r9a09g011_mod_clks[] __initconst = {
DEF_MOD("pfc", R9A09G011_PFC_PCLK, CLK_MAIN, 0x400, 2),
DEF_MOD("gic", R9A09G011_GIC_CLK, CLK_SEL_B_D2, 0x400, 5),
+ DEF_MOD("sdi0_aclk", R9A09G011_SDI0_ACLK, CLK_SEL_D, 0x408, 0),
+ DEF_MOD("sdi0_imclk", R9A09G011_SDI0_IMCLK, CLK_SEL_SDI, 0x408, 1),
+ DEF_MOD("sdi0_imclk2", R9A09G011_SDI0_IMCLK2, CLK_SEL_SDI, 0x408, 2),
+ DEF_MOD("sdi0_clk_hs", R9A09G011_SDI0_CLK_HS, CLK_PLL2_800, 0x408, 3),
+ DEF_MOD("sdi1_aclk", R9A09G011_SDI1_ACLK, CLK_SEL_D, 0x408, 4),
+ DEF_MOD("sdi1_imclk", R9A09G011_SDI1_IMCLK, CLK_SEL_SDI, 0x408, 5),
+ DEF_MOD("sdi1_imclk2", R9A09G011_SDI1_IMCLK2, CLK_SEL_SDI, 0x408, 6),
+ DEF_MOD("sdi1_clk_hs", R9A09G011_SDI1_CLK_HS, CLK_PLL2_800, 0x408, 7),
+ DEF_MOD("emm_aclk", R9A09G011_EMM_ACLK, CLK_SEL_D, 0x408, 8),
+ DEF_MOD("emm_imclk", R9A09G011_EMM_IMCLK, CLK_SEL_SDI, 0x408, 9),
+ DEF_MOD("emm_imclk2", R9A09G011_EMM_IMCLK2, CLK_SEL_SDI, 0x408, 10),
+ DEF_MOD("emm_clk_hs", R9A09G011_EMM_CLK_HS, CLK_PLL2_800, 0x408, 11),
DEF_COUPLED("eth_axi", R9A09G011_ETH0_CLK_AXI, CLK_PLL2_200, 0x40c, 8),
DEF_COUPLED("eth_chi", R9A09G011_ETH0_CLK_CHI, CLK_PLL2_100, 0x40c, 8),
DEF_MOD("eth_clk_gptp", R9A09G011_ETH0_GPTP_EXT, CLK_PLL2_100, 0x40c, 9),
+ DEF_MOD("usb_aclk_h", R9A09G011_USB_ACLK_H, CLK_SEL_D, 0x40c, 4),
+ DEF_MOD("usb_aclk_p", R9A09G011_USB_ACLK_P, CLK_SEL_D, 0x40c, 5),
+ DEF_MOD("usb_pclk", R9A09G011_USB_PCLK, CLK_SEL_E, 0x40c, 6),
DEF_MOD("syc_cnt_clk", R9A09G011_SYC_CNT_CLK, CLK_MAIN_24, 0x41c, 12),
DEF_MOD("iic_pclk0", R9A09G011_IIC_PCLK0, CLK_SEL_E, 0x420, 12),
+ DEF_MOD("cperi_grpb", R9A09G011_CPERI_GRPB_PCLK, CLK_SEL_E, 0x424, 0),
+ DEF_MOD("tim_clk_8", R9A09G011_TIM8_CLK, CLK_MAIN_2, 0x424, 4),
+ DEF_MOD("tim_clk_9", R9A09G011_TIM9_CLK, CLK_MAIN_2, 0x424, 5),
+ DEF_MOD("tim_clk_10", R9A09G011_TIM10_CLK, CLK_MAIN_2, 0x424, 6),
+ DEF_MOD("tim_clk_11", R9A09G011_TIM11_CLK, CLK_MAIN_2, 0x424, 7),
+ DEF_MOD("tim_clk_12", R9A09G011_TIM12_CLK, CLK_MAIN_2, 0x424, 8),
+ DEF_MOD("tim_clk_13", R9A09G011_TIM13_CLK, CLK_MAIN_2, 0x424, 9),
+ DEF_MOD("tim_clk_14", R9A09G011_TIM14_CLK, CLK_MAIN_2, 0x424, 10),
+ DEF_MOD("tim_clk_15", R9A09G011_TIM15_CLK, CLK_MAIN_2, 0x424, 11),
DEF_MOD("iic_pclk1", R9A09G011_IIC_PCLK1, CLK_SEL_E, 0x424, 12),
+ DEF_MOD("cperi_grpc", R9A09G011_CPERI_GRPC_PCLK, CLK_SEL_E, 0x428, 0),
+ DEF_MOD("tim_clk_16", R9A09G011_TIM16_CLK, CLK_MAIN_2, 0x428, 4),
+ DEF_MOD("tim_clk_17", R9A09G011_TIM17_CLK, CLK_MAIN_2, 0x428, 5),
+ DEF_MOD("tim_clk_18", R9A09G011_TIM18_CLK, CLK_MAIN_2, 0x428, 6),
+ DEF_MOD("tim_clk_19", R9A09G011_TIM19_CLK, CLK_MAIN_2, 0x428, 7),
+ DEF_MOD("tim_clk_20", R9A09G011_TIM20_CLK, CLK_MAIN_2, 0x428, 8),
+ DEF_MOD("tim_clk_21", R9A09G011_TIM21_CLK, CLK_MAIN_2, 0x428, 9),
+ DEF_MOD("tim_clk_22", R9A09G011_TIM22_CLK, CLK_MAIN_2, 0x428, 10),
+ DEF_MOD("tim_clk_23", R9A09G011_TIM23_CLK, CLK_MAIN_2, 0x428, 11),
DEF_MOD("wdt0_pclk", R9A09G011_WDT0_PCLK, CLK_SEL_E, 0x428, 12),
DEF_MOD("wdt0_clk", R9A09G011_WDT0_CLK, CLK_MAIN, 0x428, 13),
+ DEF_MOD("cperi_grpf", R9A09G011_CPERI_GRPF_PCLK, CLK_SEL_E, 0x434, 0),
+ DEF_MOD("pwm8_clk", R9A09G011_PWM8_CLK, CLK_MAIN, 0x434, 4),
+ DEF_MOD("pwm9_clk", R9A09G011_PWM9_CLK, CLK_MAIN, 0x434, 5),
+ DEF_MOD("pwm10_clk", R9A09G011_PWM10_CLK, CLK_MAIN, 0x434, 6),
+ DEF_MOD("pwm11_clk", R9A09G011_PWM11_CLK, CLK_MAIN, 0x434, 7),
+ DEF_MOD("pwm12_clk", R9A09G011_PWM12_CLK, CLK_MAIN, 0x434, 8),
+ DEF_MOD("pwm13_clk", R9A09G011_PWM13_CLK, CLK_MAIN, 0x434, 9),
+ DEF_MOD("pwm14_clk", R9A09G011_PWM14_CLK, CLK_MAIN, 0x434, 10),
DEF_MOD("urt_pclk", R9A09G011_URT_PCLK, CLK_SEL_E, 0x438, 4),
DEF_MOD("urt0_clk", R9A09G011_URT0_CLK, CLK_SEL_W0, 0x438, 5),
DEF_MOD("ca53", R9A09G011_CA53_CLK, CLK_DIV_A, 0x448, 0),
@@ -143,8 +203,18 @@ static const struct rzg2l_mod_clk r9a09g011_mod_clks[] __initconst = {
static const struct rzg2l_reset r9a09g011_resets[] = {
DEF_RST(R9A09G011_PFC_PRESETN, 0x600, 2),
+ DEF_RST_MON(R9A09G011_SDI0_IXRST, 0x608, 0, 6),
+ DEF_RST_MON(R9A09G011_SDI1_IXRST, 0x608, 1, 7),
+ DEF_RST_MON(R9A09G011_EMM_IXRST, 0x608, 2, 8),
+ DEF_RST(R9A09G011_USB_PRESET_N, 0x608, 7),
+ DEF_RST(R9A09G011_USB_DRD_RESET, 0x608, 8),
+ DEF_RST(R9A09G011_USB_ARESETN_P, 0x608, 9),
+ DEF_RST(R9A09G011_USB_ARESETN_H, 0x608, 10),
DEF_RST_MON(R9A09G011_ETH0_RST_HW_N, 0x608, 11, 11),
DEF_RST_MON(R9A09G011_SYC_RST_N, 0x610, 9, 13),
+ DEF_RST(R9A09G011_TIM_GPB_PRESETN, 0x614, 1),
+ DEF_RST(R9A09G011_TIM_GPC_PRESETN, 0x614, 2),
+ DEF_RST_MON(R9A09G011_PWM_GPF_PRESETN, 0x614, 5, 23),
DEF_RST(R9A09G011_IIC_GPA_PRESETN, 0x614, 8),
DEF_RST(R9A09G011_IIC_GPB_PRESETN, 0x614, 9),
DEF_RST_MON(R9A09G011_WDT0_PRESETN, 0x614, 12, 19),
@@ -152,6 +222,9 @@ static const struct rzg2l_reset r9a09g011_resets[] = {
static const unsigned int r9a09g011_crit_mod_clks[] __initconst = {
MOD_CLK_BASE + R9A09G011_CA53_CLK,
+ MOD_CLK_BASE + R9A09G011_CPERI_GRPB_PCLK,
+ MOD_CLK_BASE + R9A09G011_CPERI_GRPC_PCLK,
+ MOD_CLK_BASE + R9A09G011_CPERI_GRPF_PCLK,
MOD_CLK_BASE + R9A09G011_GIC_CLK,
MOD_CLK_BASE + R9A09G011_SYC_CNT_CLK,
MOD_CLK_BASE + R9A09G011_URT_PCLK,
diff --git a/drivers/clk/renesas/rcar-gen3-cpg.c b/drivers/clk/renesas/rcar-gen3-cpg.c
index e668f23c75e7..b3ef62fa612e 100644
--- a/drivers/clk/renesas/rcar-gen3-cpg.c
+++ b/drivers/clk/renesas/rcar-gen3-cpg.c
@@ -310,20 +310,11 @@ static unsigned int cpg_clk_extalr __initdata;
static u32 cpg_mode __initdata;
static u32 cpg_quirks __initdata;
-#define PLL_ERRATA BIT(0) /* Missing PLL0/2/4 post-divider */
#define RCKCR_CKSEL BIT(1) /* Manual RCLK parent selection */
static const struct soc_device_attribute cpg_quirks_match[] __initconst = {
{
- .soc_id = "r8a7795", .revision = "ES1.0",
- .data = (void *)(PLL_ERRATA | RCKCR_CKSEL),
- },
- {
- .soc_id = "r8a7795", .revision = "ES1.*",
- .data = (void *)(RCKCR_CKSEL),
- },
- {
.soc_id = "r8a7796", .revision = "ES1.0",
.data = (void *)(RCKCR_CKSEL),
},
@@ -355,9 +346,8 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev,
* multiplier when cpufreq changes between normal and boost
* modes.
*/
- mult = (cpg_quirks & PLL_ERRATA) ? 4 : 2;
return cpg_pll_clk_register(core->name, __clk_get_name(parent),
- base, mult, CPG_PLL0CR, 0);
+ base, 2, CPG_PLL0CR, 0);
case CLK_TYPE_GEN3_PLL1:
mult = cpg_pll_config->pll1_mult;
@@ -370,9 +360,8 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev,
* multiplier when cpufreq changes between normal and boost
* modes.
*/
- mult = (cpg_quirks & PLL_ERRATA) ? 4 : 2;
return cpg_pll_clk_register(core->name, __clk_get_name(parent),
- base, mult, CPG_PLL2CR, 2);
+ base, 2, CPG_PLL2CR, 2);
case CLK_TYPE_GEN3_PLL3:
mult = cpg_pll_config->pll3_mult;
@@ -388,8 +377,6 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev,
*/
value = readl(base + CPG_PLL4CR);
mult = (((value >> 24) & 0x7f) + 1) * 2;
- if (cpg_quirks & PLL_ERRATA)
- mult *= 2;
break;
case CLK_TYPE_GEN3_SDH:
diff --git a/drivers/clk/renesas/rcar-gen4-cpg.c b/drivers/clk/renesas/rcar-gen4-cpg.c
index e27832e5114f..c68d8b987054 100644
--- a/drivers/clk/renesas/rcar-gen4-cpg.c
+++ b/drivers/clk/renesas/rcar-gen4-cpg.c
@@ -17,6 +17,7 @@
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/slab.h>
#include "renesas-cpg-mssr.h"
@@ -27,6 +28,152 @@ static const struct rcar_gen4_cpg_pll_config *cpg_pll_config __initdata;
static unsigned int cpg_clk_extalr __initdata;
static u32 cpg_mode __initdata;
+#define CPG_PLLECR 0x0820 /* PLL Enable Control Register */
+
+#define CPG_PLLECR_PLLST(n) BIT(8 + ((n) < 3 ? (n) - 1 : \
+ (n) > 3 ? (n) + 1 : n)) /* PLLn Circuit Status */
+
+#define CPG_PLL1CR0 0x830 /* PLLn Control Registers */
+#define CPG_PLL1CR1 0x8b0
+#define CPG_PLL2CR0 0x834
+#define CPG_PLL2CR1 0x8b8
+#define CPG_PLL3CR0 0x83c
+#define CPG_PLL3CR1 0x8c0
+#define CPG_PLL4CR0 0x844
+#define CPG_PLL4CR1 0x8c8
+#define CPG_PLL6CR0 0x84c
+#define CPG_PLL6CR1 0x8d8
+
+#define CPG_PLLxCR0_KICK BIT(31)
+#define CPG_PLLxCR0_NI GENMASK(27, 20) /* Integer mult. factor */
+#define CPG_PLLxCR0_SSMODE GENMASK(18, 16) /* PLL mode */
+#define CPG_PLLxCR0_SSMODE_FM BIT(18) /* Fractional Multiplication */
+#define CPG_PLLxCR0_SSMODE_DITH BIT(17) /* Frequency Dithering */
+#define CPG_PLLxCR0_SSMODE_CENT BIT(16) /* Center (vs. Down) Spread Dithering */
+#define CPG_PLLxCR0_SSFREQ GENMASK(14, 8) /* SSCG Modulation Frequency */
+#define CPG_PLLxCR0_SSDEPT GENMASK(6, 0) /* SSCG Modulation Depth */
+
+#define SSMODE_FM BIT(2) /* Fractional Multiplication */
+#define SSMODE_DITHER BIT(1) /* Frequency Dithering */
+#define SSMODE_CENTER BIT(0) /* Center (vs. Down) Spread Dithering */
+
+/* PLL Clocks */
+struct cpg_pll_clk {
+ struct clk_hw hw;
+ void __iomem *pllcr0_reg;
+ void __iomem *pllecr_reg;
+ u32 pllecr_pllst_mask;
+};
+
+#define to_pll_clk(_hw) container_of(_hw, struct cpg_pll_clk, hw)
+
+static unsigned long cpg_pll_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct cpg_pll_clk *pll_clk = to_pll_clk(hw);
+ unsigned int mult;
+
+ mult = FIELD_GET(CPG_PLLxCR0_NI, readl(pll_clk->pllcr0_reg)) + 1;
+
+ return parent_rate * mult * 2;
+}
+
+static int cpg_pll_clk_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ unsigned int min_mult, max_mult, mult;
+ unsigned long prate;
+
+ prate = req->best_parent_rate * 2;
+ min_mult = max(div64_ul(req->min_rate, prate), 1ULL);
+ max_mult = min(div64_ul(req->max_rate, prate), 256ULL);
+ if (max_mult < min_mult)
+ return -EINVAL;
+
+ mult = DIV_ROUND_CLOSEST_ULL(req->rate, prate);
+ mult = clamp(mult, min_mult, max_mult);
+
+ req->rate = prate * mult;
+ return 0;
+}
+
+static int cpg_pll_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct cpg_pll_clk *pll_clk = to_pll_clk(hw);
+ unsigned int mult;
+ u32 val;
+
+ mult = DIV_ROUND_CLOSEST_ULL(rate, parent_rate * 2);
+ mult = clamp(mult, 1U, 256U);
+
+ if (readl(pll_clk->pllcr0_reg) & CPG_PLLxCR0_KICK)
+ return -EBUSY;
+
+ cpg_reg_modify(pll_clk->pllcr0_reg, CPG_PLLxCR0_NI,
+ FIELD_PREP(CPG_PLLxCR0_NI, mult - 1));
+
+ /*
+ * Set KICK bit in PLLxCR0 to update hardware setting and wait for
+ * clock change completion.
+ */
+ cpg_reg_modify(pll_clk->pllcr0_reg, 0, CPG_PLLxCR0_KICK);
+
+ /*
+ * Note: There is no HW information about the worst case latency.
+ *
+ * Using experimental measurements, it seems that no more than
+ * ~45 µs are needed, independently of the CPU rate.
+ * Since this value might be dependent on external xtal rate, pll
+ * rate or even the other emulation clocks rate, use 1000 as a
+ * "super" safe value.
+ */
+ return readl_poll_timeout(pll_clk->pllecr_reg, val,
+ val & pll_clk->pllecr_pllst_mask, 0, 1000);
+}
+
+static const struct clk_ops cpg_pll_clk_ops = {
+ .recalc_rate = cpg_pll_clk_recalc_rate,
+ .determine_rate = cpg_pll_clk_determine_rate,
+ .set_rate = cpg_pll_clk_set_rate,
+};
+
+static struct clk * __init cpg_pll_clk_register(const char *name,
+ const char *parent_name,
+ void __iomem *base,
+ unsigned int cr0_offset,
+ unsigned int cr1_offset,
+ unsigned int index)
+
+{
+ struct cpg_pll_clk *pll_clk;
+ struct clk_init_data init = {};
+ struct clk *clk;
+
+ pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL);
+ if (!pll_clk)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &cpg_pll_clk_ops;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ pll_clk->hw.init = &init;
+ pll_clk->pllcr0_reg = base + cr0_offset;
+ pll_clk->pllecr_reg = base + CPG_PLLECR;
+ pll_clk->pllecr_pllst_mask = CPG_PLLECR_PLLST(index);
+
+ /* Disable Fractional Multiplication and Frequency Dithering */
+ writel(0, base + cr1_offset);
+ cpg_reg_modify(pll_clk->pllcr0_reg, CPG_PLLxCR0_SSMODE, 0);
+
+ clk = clk_register(NULL, &pll_clk->hw);
+ if (IS_ERR(clk))
+ kfree(pll_clk);
+
+ return clk;
+}
/*
* Z0 Clock & Z1 Clock
*/
@@ -205,6 +352,15 @@ struct clk * __init rcar_gen4_cpg_clk_register(struct device *dev,
div = cpg_pll_config->pll1_div;
break;
+ case CLK_TYPE_GEN4_PLL2_VAR:
+ /*
+ * PLL2 is implemented as a custom clock, to change the
+ * multiplier when cpufreq changes between normal and boost
+ * modes.
+ */
+ return cpg_pll_clk_register(core->name, __clk_get_name(parent),
+ base, CPG_PLL2CR0, CPG_PLL2CR1, 2);
+
case CLK_TYPE_GEN4_PLL2:
mult = cpg_pll_config->pll2_mult;
div = cpg_pll_config->pll2_div;
diff --git a/drivers/clk/renesas/rcar-gen4-cpg.h b/drivers/clk/renesas/rcar-gen4-cpg.h
index 0b15dcfdca7b..006537e29e4e 100644
--- a/drivers/clk/renesas/rcar-gen4-cpg.h
+++ b/drivers/clk/renesas/rcar-gen4-cpg.h
@@ -13,10 +13,11 @@ enum rcar_gen4_clk_types {
CLK_TYPE_GEN4_MAIN = CLK_TYPE_CUSTOM,
CLK_TYPE_GEN4_PLL1,
CLK_TYPE_GEN4_PLL2,
+ CLK_TYPE_GEN4_PLL2_VAR,
CLK_TYPE_GEN4_PLL2X_3X, /* r8a779a0 only */
CLK_TYPE_GEN4_PLL3,
- CLK_TYPE_GEN4_PLL5,
CLK_TYPE_GEN4_PLL4,
+ CLK_TYPE_GEN4_PLL5,
CLK_TYPE_GEN4_PLL6,
CLK_TYPE_GEN4_SDSRC,
CLK_TYPE_GEN4_SDH,
diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c
index 1a0cdf001b2f..b9f210437ddf 100644
--- a/drivers/clk/renesas/renesas-cpg-mssr.c
+++ b/drivers/clk/renesas/renesas-cpg-mssr.c
@@ -943,9 +943,8 @@ static int cpg_mssr_resume_noirq(struct device *dev)
}
if (!i)
- dev_warn(dev, "Failed to enable %s%u[0x%x]\n",
- priv->reg_layout == CLK_REG_LAYOUT_RZ_A ?
- "STB" : "SMSTP", reg, oldval & mask);
+ dev_warn(dev, "Failed to enable SMSTP%u[0x%x]\n", reg,
+ oldval & mask);
}
return 0;
@@ -989,7 +988,6 @@ static int __init cpg_mssr_common_init(struct device *dev,
goto out_err;
}
- cpg_mssr_priv = priv;
priv->num_core_clks = info->num_total_core_clks;
priv->num_mod_clks = info->num_hw_mod_clks;
priv->last_dt_core_clk = info->last_dt_core_clk;
@@ -1019,6 +1017,8 @@ static int __init cpg_mssr_common_init(struct device *dev,
if (error)
goto out_err;
+ cpg_mssr_priv = priv;
+
return 0;
out_err:
@@ -1113,19 +1113,6 @@ static int __init cpg_mssr_init(void)
subsys_initcall(cpg_mssr_init);
-void __init cpg_core_nullify_range(struct cpg_core_clk *core_clks,
- unsigned int num_core_clks,
- unsigned int first_clk,
- unsigned int last_clk)
-{
- unsigned int i;
-
- for (i = 0; i < num_core_clks; i++)
- if (core_clks[i].id >= first_clk &&
- core_clks[i].id <= last_clk)
- core_clks[i].name = NULL;
-}
-
void __init mssr_mod_nullify(struct mssr_mod_clk *mod_clks,
unsigned int num_mod_clks,
const unsigned int *clks, unsigned int n)
@@ -1139,19 +1126,5 @@ void __init mssr_mod_nullify(struct mssr_mod_clk *mod_clks,
}
}
-void __init mssr_mod_reparent(struct mssr_mod_clk *mod_clks,
- unsigned int num_mod_clks,
- const struct mssr_mod_reparent *clks,
- unsigned int n)
-{
- unsigned int i, j;
-
- for (i = 0, j = 0; i < num_mod_clks && j < n; i++)
- if (mod_clks[i].id == clks[j].clk) {
- mod_clks[i].parent = clks[j].parent;
- j++;
- }
-}
-
MODULE_DESCRIPTION("Renesas CPG/MSSR Driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/renesas/renesas-cpg-mssr.h b/drivers/clk/renesas/renesas-cpg-mssr.h
index 1c3c057d17f5..80c5b462924a 100644
--- a/drivers/clk/renesas/renesas-cpg-mssr.h
+++ b/drivers/clk/renesas/renesas-cpg-mssr.h
@@ -187,21 +187,7 @@ void __init cpg_mssr_early_init(struct device_node *np,
/*
* Helpers for fixing up clock tables depending on SoC revision
*/
-
-struct mssr_mod_reparent {
- unsigned int clk, parent;
-};
-
-
-extern void cpg_core_nullify_range(struct cpg_core_clk *core_clks,
- unsigned int num_core_clks,
- unsigned int first_clk,
- unsigned int last_clk);
extern void mssr_mod_nullify(struct mssr_mod_clk *mod_clks,
unsigned int num_mod_clks,
const unsigned int *clks, unsigned int n);
-extern void mssr_mod_reparent(struct mssr_mod_clk *mod_clks,
- unsigned int num_mod_clks,
- const struct mssr_mod_reparent *clks,
- unsigned int n);
#endif
diff --git a/drivers/clk/sprd/Kconfig b/drivers/clk/sprd/Kconfig
index c744bd9d2f96..2f19c8d58ff2 100644
--- a/drivers/clk/sprd/Kconfig
+++ b/drivers/clk/sprd/Kconfig
@@ -24,6 +24,8 @@ config SPRD_SC9863A_CLK
config SPRD_UMS512_CLK
tristate "Support for the Spreadtrum UMS512 clocks"
+ depends on (ARM64 && ARCH_SPRD) || COMPILE_TEST
+ default ARM64 && ARCH_SPRD
help
Support for the global clock controller on ums512 devices.
Say Y if you want to use peripheral devices on ums512 SoC.
diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig
index 461537679c04..b547198a2c65 100644
--- a/drivers/clk/sunxi-ng/Kconfig
+++ b/drivers/clk/sunxi-ng/Kconfig
@@ -9,112 +9,113 @@ if SUNXI_CCU
config SUNIV_F1C100S_CCU
tristate "Support for the Allwinner newer F1C100s CCU"
- default MACH_SUNIV
+ default y
depends on MACH_SUNIV || COMPILE_TEST
config SUN20I_D1_CCU
- tristate "Support for the Allwinner D1 CCU"
- default RISCV && ARCH_SUNXI
- depends on (RISCV && ARCH_SUNXI) || COMPILE_TEST
+ tristate "Support for the Allwinner D1/R528/T113 CCU"
+ default y
+ depends on MACH_SUN8I || RISCV || COMPILE_TEST
config SUN20I_D1_R_CCU
- tristate "Support for the Allwinner D1 PRCM CCU"
- default RISCV && ARCH_SUNXI
- depends on (RISCV && ARCH_SUNXI) || COMPILE_TEST
+ tristate "Support for the Allwinner D1/R528/T113 PRCM CCU"
+ default y
+ depends on MACH_SUN8I || RISCV || COMPILE_TEST
config SUN50I_A64_CCU
tristate "Support for the Allwinner A64 CCU"
- default ARM64 && ARCH_SUNXI
- depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST
+ default y
+ depends on ARM64 || COMPILE_TEST
config SUN50I_A100_CCU
tristate "Support for the Allwinner A100 CCU"
- default ARM64 && ARCH_SUNXI
- depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST
+ default y
+ depends on ARM64 || COMPILE_TEST
config SUN50I_A100_R_CCU
tristate "Support for the Allwinner A100 PRCM CCU"
- default ARM64 && ARCH_SUNXI
- depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST
+ default y
+ depends on ARM64 || COMPILE_TEST
config SUN50I_H6_CCU
tristate "Support for the Allwinner H6 CCU"
- default ARM64 && ARCH_SUNXI
- depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST
+ default y
+ depends on ARM64 || COMPILE_TEST
config SUN50I_H616_CCU
tristate "Support for the Allwinner H616 CCU"
- default ARM64 && ARCH_SUNXI
- depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST
+ default y
+ depends on ARM64 || COMPILE_TEST
config SUN50I_H6_R_CCU
tristate "Support for the Allwinner H6 and H616 PRCM CCU"
- default ARM64 && ARCH_SUNXI
- depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST
+ default y
+ depends on ARM64 || COMPILE_TEST
config SUN4I_A10_CCU
tristate "Support for the Allwinner A10/A20 CCU"
- default MACH_SUN4I
- default MACH_SUN7I
+ default y
depends on MACH_SUN4I || MACH_SUN7I || COMPILE_TEST
config SUN5I_CCU
bool "Support for the Allwinner sun5i family CCM"
- default MACH_SUN5I
+ default y
depends on MACH_SUN5I || COMPILE_TEST
depends on SUNXI_CCU=y
config SUN6I_A31_CCU
tristate "Support for the Allwinner A31/A31s CCU"
- default MACH_SUN6I
+ default y
depends on MACH_SUN6I || COMPILE_TEST
config SUN6I_RTC_CCU
tristate "Support for the Allwinner H616/R329 RTC CCU"
- default ARCH_SUNXI
- depends on ARCH_SUNXI || COMPILE_TEST
+ default y
+ depends on MACH_SUN8I || ARM64 || RISCV || COMPILE_TEST
config SUN8I_A23_CCU
tristate "Support for the Allwinner A23 CCU"
- default MACH_SUN8I
+ default y
depends on MACH_SUN8I || COMPILE_TEST
config SUN8I_A33_CCU
tristate "Support for the Allwinner A33 CCU"
- default MACH_SUN8I
+ default y
depends on MACH_SUN8I || COMPILE_TEST
config SUN8I_A83T_CCU
tristate "Support for the Allwinner A83T CCU"
- default MACH_SUN8I
+ default y
depends on MACH_SUN8I || COMPILE_TEST
config SUN8I_H3_CCU
tristate "Support for the Allwinner H3 CCU"
- default MACH_SUN8I || (ARM64 && ARCH_SUNXI)
- depends on MACH_SUN8I || (ARM64 && ARCH_SUNXI) || COMPILE_TEST
+ default y
+ depends on MACH_SUN8I || ARM64 || COMPILE_TEST
config SUN8I_V3S_CCU
tristate "Support for the Allwinner V3s CCU"
- default MACH_SUN8I
+ default y
depends on MACH_SUN8I || COMPILE_TEST
config SUN8I_DE2_CCU
tristate "Support for the Allwinner SoCs DE2 CCU"
- default MACH_SUN8I || (ARM64 && ARCH_SUNXI)
+ default y
+ depends on MACH_SUN8I || ARM64 || RISCV || COMPILE_TEST
config SUN8I_R40_CCU
tristate "Support for the Allwinner R40 CCU"
- default MACH_SUN8I
+ default y
depends on MACH_SUN8I || COMPILE_TEST
config SUN9I_A80_CCU
tristate "Support for the Allwinner A80 CCU"
- default MACH_SUN9I
+ default y
depends on MACH_SUN9I || COMPILE_TEST
config SUN8I_R_CCU
tristate "Support for Allwinner SoCs' PRCM CCUs"
- default MACH_SUN8I || (ARCH_SUNXI && ARM64)
+ default y
+ depends on MACH_SUN8I || ARM64 || COMPILE_TEST
endif
diff --git a/drivers/clk/sunxi-ng/ccu-sun20i-d1.c b/drivers/clk/sunxi-ng/ccu-sun20i-d1.c
index 8ef3cdeb7962..48a8fb2c43b7 100644
--- a/drivers/clk/sunxi-ng/ccu-sun20i-d1.c
+++ b/drivers/clk/sunxi-ng/ccu-sun20i-d1.c
@@ -240,7 +240,7 @@ static const struct clk_parent_data cpux_parents[] = {
{ .hw = &pll_periph0_800M_clk.common.hw },
};
static SUNXI_CCU_MUX_DATA(cpux_clk, "cpux", cpux_parents,
- 0x500, 24, 3, CLK_SET_RATE_PARENT);
+ 0x500, 24, 3, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
static const struct clk_hw *cpux_hws[] = { &cpux_clk.common.hw };
static SUNXI_CCU_M_HWS(cpux_axi_clk, "cpux-axi",
@@ -469,6 +469,11 @@ static SUNXI_CCU_GATE_HWS(bus_i2c2_clk, "bus-i2c2", apb1_hws,
static SUNXI_CCU_GATE_HWS(bus_i2c3_clk, "bus-i2c3", apb1_hws,
0x91c, BIT(3), 0);
+static SUNXI_CCU_GATE_HWS(bus_can0_clk, "bus-can0", apb1_hws,
+ 0x92c, BIT(0), 0);
+static SUNXI_CCU_GATE_HWS(bus_can1_clk, "bus-can1", apb1_hws,
+ 0x92c, BIT(1), 0);
+
static const struct clk_parent_data spi_parents[] = {
{ .fw_name = "hosc" },
{ .hw = &pll_periph0_clk.hw },
@@ -997,6 +1002,8 @@ static struct ccu_common *sun20i_d1_ccu_clks[] = {
&bus_i2c1_clk.common,
&bus_i2c2_clk.common,
&bus_i2c3_clk.common,
+ &bus_can0_clk.common,
+ &bus_can1_clk.common,
&spi0_clk.common,
&spi1_clk.common,
&bus_spi0_clk.common,
@@ -1147,6 +1154,8 @@ static struct clk_hw_onecell_data sun20i_d1_hw_clks = {
[CLK_BUS_I2C1] = &bus_i2c1_clk.common.hw,
[CLK_BUS_I2C2] = &bus_i2c2_clk.common.hw,
[CLK_BUS_I2C3] = &bus_i2c3_clk.common.hw,
+ [CLK_BUS_CAN0] = &bus_can0_clk.common.hw,
+ [CLK_BUS_CAN1] = &bus_can1_clk.common.hw,
[CLK_SPI0] = &spi0_clk.common.hw,
[CLK_SPI1] = &spi1_clk.common.hw,
[CLK_BUS_SPI0] = &bus_spi0_clk.common.hw,
@@ -1252,6 +1261,8 @@ static struct ccu_reset_map sun20i_d1_ccu_resets[] = {
[RST_BUS_I2C1] = { 0x91c, BIT(17) },
[RST_BUS_I2C2] = { 0x91c, BIT(18) },
[RST_BUS_I2C3] = { 0x91c, BIT(19) },
+ [RST_BUS_CAN0] = { 0x92c, BIT(16) },
+ [RST_BUS_CAN1] = { 0x92c, BIT(17) },
[RST_BUS_SPI0] = { 0x96c, BIT(16) },
[RST_BUS_SPI1] = { 0x96c, BIT(17) },
[RST_BUS_EMAC] = { 0x97c, BIT(16) },
diff --git a/drivers/clk/sunxi-ng/ccu-sun20i-d1.h b/drivers/clk/sunxi-ng/ccu-sun20i-d1.h
index e303176f0d4e..b14da36e2537 100644
--- a/drivers/clk/sunxi-ng/ccu-sun20i-d1.h
+++ b/drivers/clk/sunxi-ng/ccu-sun20i-d1.h
@@ -10,6 +10,6 @@
#include <dt-bindings/clock/sun20i-d1-ccu.h>
#include <dt-bindings/reset/sun20i-d1-ccu.h>
-#define CLK_NUMBER (CLK_FANOUT2 + 1)
+#define CLK_NUMBER (CLK_BUS_CAN1 + 1)
#endif /* _CCU_SUN20I_D1_H_ */
diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
index d3fcb983c17c..bfebe8dbbe65 100644
--- a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
@@ -434,8 +434,13 @@ static SUNXI_CCU_GATE(usb_ohci2_clk, "usb-ohci2", "osc24M",
static SUNXI_CCU_GATE(usb_ohci3_clk, "usb-ohci3", "osc24M",
0x0cc, BIT(19), 0);
-static const char * const dram_parents[] = { "pll-ddr", "pll-periph0-2x" };
-static SUNXI_CCU_M_WITH_MUX(dram_clk, "dram", dram_parents,
+/* H3 has broken MDFS hardware, so the mux/divider cannot be changed. */
+static CLK_FIXED_FACTOR_HW(h3_dram_clk, "dram",
+ &pll_ddr_clk.common.hw,
+ 1, 1, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
+
+static const char * const h5_dram_parents[] = { "pll-ddr", "pll-periph0-2x" };
+static SUNXI_CCU_M_WITH_MUX(h5_dram_clk, "dram", h5_dram_parents,
0x0f4, 0, 4, 20, 2, CLK_IS_CRITICAL);
static SUNXI_CCU_GATE(dram_ve_clk, "dram-ve", "dram",
@@ -592,7 +597,7 @@ static struct ccu_common *sun8i_h3_ccu_clks[] = {
&usb_ohci1_clk.common,
&usb_ohci2_clk.common,
&usb_ohci3_clk.common,
- &dram_clk.common,
+ &h5_dram_clk.common,
&dram_ve_clk.common,
&dram_csi_clk.common,
&dram_deinterlace_clk.common,
@@ -732,7 +737,7 @@ static struct clk_hw_onecell_data sun8i_h3_hw_clks = {
[CLK_USB_OHCI1] = &usb_ohci1_clk.common.hw,
[CLK_USB_OHCI2] = &usb_ohci2_clk.common.hw,
[CLK_USB_OHCI3] = &usb_ohci3_clk.common.hw,
- [CLK_DRAM] = &dram_clk.common.hw,
+ [CLK_DRAM] = &h3_dram_clk.hw,
[CLK_DRAM_VE] = &dram_ve_clk.common.hw,
[CLK_DRAM_CSI] = &dram_csi_clk.common.hw,
[CLK_DRAM_DEINTERLACE] = &dram_deinterlace_clk.common.hw,
@@ -848,7 +853,7 @@ static struct clk_hw_onecell_data sun50i_h5_hw_clks = {
[CLK_USB_OHCI1] = &usb_ohci1_clk.common.hw,
[CLK_USB_OHCI2] = &usb_ohci2_clk.common.hw,
[CLK_USB_OHCI3] = &usb_ohci3_clk.common.hw,
- [CLK_DRAM] = &dram_clk.common.hw,
+ [CLK_DRAM] = &h5_dram_clk.common.hw,
[CLK_DRAM_VE] = &dram_ve_clk.common.hw,
[CLK_DRAM_CSI] = &dram_csi_clk.common.hw,
[CLK_DRAM_DEINTERLACE] = &dram_deinterlace_clk.common.hw,
diff --git a/drivers/clk/sunxi-ng/ccu_mmc_timing.c b/drivers/clk/sunxi-ng/ccu_mmc_timing.c
index de33414fc5c2..23a8d44e2449 100644
--- a/drivers/clk/sunxi-ng/ccu_mmc_timing.c
+++ b/drivers/clk/sunxi-ng/ccu_mmc_timing.c
@@ -10,11 +10,11 @@
#include "ccu_common.h"
/**
- * sunxi_ccu_set_mmc_timing_mode: Configure the MMC clock timing mode
+ * sunxi_ccu_set_mmc_timing_mode - Configure the MMC clock timing mode
* @clk: clock to be configured
* @new_mode: true for new timing mode introduced in A83T and later
*
- * Returns 0 on success, -ENOTSUPP if the clock does not support
+ * Return: %0 on success, %-ENOTSUPP if the clock does not support
* switching modes.
*/
int sunxi_ccu_set_mmc_timing_mode(struct clk *clk, bool new_mode)
@@ -46,8 +46,8 @@ EXPORT_SYMBOL_GPL(sunxi_ccu_set_mmc_timing_mode);
* sunxi_ccu_set_mmc_timing_mode: Get the current MMC clock timing mode
* @clk: clock to query
*
- * Returns 0 if the clock is in old timing mode, > 0 if it is in
- * new timing mode, and -ENOTSUPP if the clock does not support
+ * Return: %0 if the clock is in old timing mode, > %0 if it is in
+ * new timing mode, and %-ENOTSUPP if the clock does not support
* this function.
*/
int sunxi_ccu_get_mmc_timing_mode(struct clk *clk)
diff --git a/drivers/clk/sunxi-ng/ccu_mp.c b/drivers/clk/sunxi-ng/ccu_mp.c
index 57cf2d615148..cc94a694cb67 100644
--- a/drivers/clk/sunxi-ng/ccu_mp.c
+++ b/drivers/clk/sunxi-ng/ccu_mp.c
@@ -10,9 +10,9 @@
#include "ccu_gate.h"
#include "ccu_mp.h"
-static void ccu_mp_find_best(unsigned long parent, unsigned long rate,
- unsigned int max_m, unsigned int max_p,
- unsigned int *m, unsigned int *p)
+static unsigned long ccu_mp_find_best(unsigned long parent, unsigned long rate,
+ unsigned int max_m, unsigned int max_p,
+ unsigned int *m, unsigned int *p)
{
unsigned long best_rate = 0;
unsigned int best_m = 0, best_p = 0;
@@ -35,6 +35,8 @@ static void ccu_mp_find_best(unsigned long parent, unsigned long rate,
*m = best_m;
*p = best_p;
+
+ return best_rate;
}
static unsigned long ccu_mp_find_best_with_parent_adj(struct clk_hw *hw,
@@ -109,8 +111,7 @@ static unsigned long ccu_mp_round_rate(struct ccu_mux_internal *mux,
max_p = cmp->p.max ?: 1 << ((1 << cmp->p.width) - 1);
if (!clk_hw_can_set_rate_parent(&cmp->common.hw)) {
- ccu_mp_find_best(*parent_rate, rate, max_m, max_p, &m, &p);
- rate = *parent_rate / p / m;
+ rate = ccu_mp_find_best(*parent_rate, rate, max_m, max_p, &m, &p);
} else {
rate = ccu_mp_find_best_with_parent_adj(hw, parent_rate, rate,
max_m, max_p);
diff --git a/drivers/clk/sunxi-ng/ccu_nk.c b/drivers/clk/sunxi-ng/ccu_nk.c
index c4fb82af97e8..8aa35d5804f3 100644
--- a/drivers/clk/sunxi-ng/ccu_nk.c
+++ b/drivers/clk/sunxi-ng/ccu_nk.c
@@ -15,8 +15,8 @@ struct _ccu_nk {
unsigned long k, min_k, max_k;
};
-static void ccu_nk_find_best(unsigned long parent, unsigned long rate,
- struct _ccu_nk *nk)
+static unsigned long ccu_nk_find_best(unsigned long parent, unsigned long rate,
+ struct _ccu_nk *nk)
{
unsigned long best_rate = 0;
unsigned int best_k = 0, best_n = 0;
@@ -39,6 +39,8 @@ static void ccu_nk_find_best(unsigned long parent, unsigned long rate,
nk->k = best_k;
nk->n = best_n;
+
+ return best_rate;
}
static void ccu_nk_disable(struct clk_hw *hw)
@@ -104,8 +106,7 @@ static long ccu_nk_round_rate(struct clk_hw *hw, unsigned long rate,
_nk.min_k = nk->k.min ?: 1;
_nk.max_k = nk->k.max ?: 1 << nk->k.width;
- ccu_nk_find_best(*parent_rate, rate, &_nk);
- rate = *parent_rate * _nk.n * _nk.k;
+ rate = ccu_nk_find_best(*parent_rate, rate, &_nk);
if (nk->common.features & CCU_FEATURE_FIXED_POSTDIV)
rate = rate / nk->fixed_post_div;
diff --git a/drivers/clk/sunxi-ng/ccu_nkm.c b/drivers/clk/sunxi-ng/ccu_nkm.c
index 67da2c189b53..a0978a50edae 100644
--- a/drivers/clk/sunxi-ng/ccu_nkm.c
+++ b/drivers/clk/sunxi-ng/ccu_nkm.c
@@ -16,8 +16,8 @@ struct _ccu_nkm {
unsigned long m, min_m, max_m;
};
-static void ccu_nkm_find_best(unsigned long parent, unsigned long rate,
- struct _ccu_nkm *nkm)
+static unsigned long ccu_nkm_find_best(unsigned long parent, unsigned long rate,
+ struct _ccu_nkm *nkm)
{
unsigned long best_rate = 0;
unsigned long best_n = 0, best_k = 0, best_m = 0;
@@ -45,6 +45,8 @@ static void ccu_nkm_find_best(unsigned long parent, unsigned long rate,
nkm->n = best_n;
nkm->k = best_k;
nkm->m = best_m;
+
+ return best_rate;
}
static void ccu_nkm_disable(struct clk_hw *hw)
@@ -122,9 +124,7 @@ static unsigned long ccu_nkm_round_rate(struct ccu_mux_internal *mux,
if (nkm->common.features & CCU_FEATURE_FIXED_POSTDIV)
rate *= nkm->fixed_post_div;
- ccu_nkm_find_best(*parent_rate, rate, &_nkm);
-
- rate = *parent_rate * _nkm.n * _nkm.k / _nkm.m;
+ rate = ccu_nkm_find_best(*parent_rate, rate, &_nkm);
if (nkm->common.features & CCU_FEATURE_FIXED_POSTDIV)
rate /= nkm->fixed_post_div;
diff --git a/drivers/clk/sunxi-ng/ccu_nkmp.c b/drivers/clk/sunxi-ng/ccu_nkmp.c
index 39413cb0985c..99359a06892d 100644
--- a/drivers/clk/sunxi-ng/ccu_nkmp.c
+++ b/drivers/clk/sunxi-ng/ccu_nkmp.c
@@ -29,8 +29,8 @@ static unsigned long ccu_nkmp_calc_rate(unsigned long parent,
return rate;
}
-static void ccu_nkmp_find_best(unsigned long parent, unsigned long rate,
- struct _ccu_nkmp *nkmp)
+static unsigned long ccu_nkmp_find_best(unsigned long parent, unsigned long rate,
+ struct _ccu_nkmp *nkmp)
{
unsigned long best_rate = 0;
unsigned long best_n = 0, best_k = 0, best_m = 0, best_p = 0;
@@ -65,6 +65,8 @@ static void ccu_nkmp_find_best(unsigned long parent, unsigned long rate,
nkmp->k = best_k;
nkmp->m = best_m;
nkmp->p = best_p;
+
+ return best_rate;
}
static void ccu_nkmp_disable(struct clk_hw *hw)
@@ -150,10 +152,8 @@ static long ccu_nkmp_round_rate(struct clk_hw *hw, unsigned long rate,
_nkmp.min_p = 1;
_nkmp.max_p = nkmp->p.max ?: 1 << ((1 << nkmp->p.width) - 1);
- ccu_nkmp_find_best(*parent_rate, rate, &_nkmp);
+ rate = ccu_nkmp_find_best(*parent_rate, rate, &_nkmp);
- rate = ccu_nkmp_calc_rate(*parent_rate, _nkmp.n, _nkmp.k,
- _nkmp.m, _nkmp.p);
if (nkmp->common.features & CCU_FEATURE_FIXED_POSTDIV)
rate = rate / nkmp->fixed_post_div;
diff --git a/drivers/clk/sunxi-ng/ccu_nm.c b/drivers/clk/sunxi-ng/ccu_nm.c
index 9ca9257f4426..c1fd11542c45 100644
--- a/drivers/clk/sunxi-ng/ccu_nm.c
+++ b/drivers/clk/sunxi-ng/ccu_nm.c
@@ -27,8 +27,8 @@ static unsigned long ccu_nm_calc_rate(unsigned long parent,
return rate;
}
-static void ccu_nm_find_best(unsigned long parent, unsigned long rate,
- struct _ccu_nm *nm)
+static unsigned long ccu_nm_find_best(unsigned long parent, unsigned long rate,
+ struct _ccu_nm *nm)
{
unsigned long best_rate = 0;
unsigned long best_n = 0, best_m = 0;
@@ -52,6 +52,8 @@ static void ccu_nm_find_best(unsigned long parent, unsigned long rate,
nm->n = best_n;
nm->m = best_m;
+
+ return best_rate;
}
static void ccu_nm_disable(struct clk_hw *hw)
@@ -157,8 +159,7 @@ static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate,
_nm.min_m = 1;
_nm.max_m = nm->m.max ?: 1 << nm->m.width;
- ccu_nm_find_best(*parent_rate, rate, &_nm);
- rate = ccu_nm_calc_rate(*parent_rate, _nm.n, _nm.m);
+ rate = ccu_nm_find_best(*parent_rate, rate, &_nm);
if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV)
rate /= nm->fixed_post_div;
diff --git a/drivers/comedi/Kconfig b/drivers/comedi/Kconfig
index 3cb61fa2c5c3..9af280735cba 100644
--- a/drivers/comedi/Kconfig
+++ b/drivers/comedi/Kconfig
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
-config COMEDI
+menuconfig COMEDI
tristate "Data acquisition support (comedi)"
help
Enable support for a wide range of data acquisition devices
diff --git a/drivers/comedi/comedi_fops.c b/drivers/comedi/comedi_fops.c
index e2114bcf815a..b982903aaa46 100644
--- a/drivers/comedi/comedi_fops.c
+++ b/drivers/comedi/comedi_fops.c
@@ -1215,6 +1215,7 @@ static int check_insn_config_length(struct comedi_insn *insn,
case INSN_CONFIG_GET_CLOCK_SRC:
case INSN_CONFIG_SET_OTHER_SRC:
case INSN_CONFIG_GET_COUNTER_STATUS:
+ case INSN_CONFIG_GET_PWM_OUTPUT:
case INSN_CONFIG_PWM_SET_H_BRIDGE:
case INSN_CONFIG_PWM_GET_H_BRIDGE:
case INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE:
diff --git a/drivers/counter/Kconfig b/drivers/counter/Kconfig
index d388bf26f4dc..b5ba8fb02cf7 100644
--- a/drivers/counter/Kconfig
+++ b/drivers/counter/Kconfig
@@ -29,6 +29,28 @@ config 104_QUAD_8
array module parameter. The interrupt line numbers for the devices may
be configured via the irq array module parameter.
+config FTM_QUADDEC
+ tristate "Flex Timer Module Quadrature decoder driver"
+ depends on SOC_LS1021A || COMPILE_TEST
+ depends on HAS_IOMEM && OF
+ help
+ Select this option to enable the Flex Timer Quadrature decoder
+ driver.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ftm-quaddec.
+
+config INTEL_QEP
+ tristate "Intel Quadrature Encoder Peripheral driver"
+ depends on X86
+ depends on PCI
+ help
+ Select this option to enable the Intel Quadrature Encoder Peripheral
+ driver.
+
+ To compile this driver as a module, choose M here: the module
+ will be called intel-qep.
+
config INTERRUPT_CNT
tristate "Interrupt counter driver"
depends on GPIOLIB
@@ -39,15 +61,17 @@ config INTERRUPT_CNT
To compile this driver as a module, choose M here: the
module will be called interrupt-cnt.
-config STM32_TIMER_CNT
- tristate "STM32 Timer encoder counter driver"
- depends on MFD_STM32_TIMERS || COMPILE_TEST
+config MICROCHIP_TCB_CAPTURE
+ tristate "Microchip Timer Counter Capture driver"
+ depends on SOC_AT91SAM9 || SOC_SAM_V7 || COMPILE_TEST
+ depends on HAS_IOMEM && OF
+ select REGMAP_MMIO
help
- Select this option to enable STM32 Timer quadrature encoder
- and counter driver.
+ Select this option to enable the Microchip Timer Counter Block
+ capture driver.
To compile this driver as a module, choose M here: the
- module will be called stm32-timer-cnt.
+ module will be called microchip-tcb-capture.
config STM32_LPTIMER_CNT
tristate "STM32 LP Timer encoder counter driver"
@@ -59,47 +83,15 @@ config STM32_LPTIMER_CNT
To compile this driver as a module, choose M here: the
module will be called stm32-lptimer-cnt.
-config TI_EQEP
- tristate "TI eQEP counter driver"
- depends on (SOC_AM33XX || COMPILE_TEST)
- select REGMAP_MMIO
- help
- Select this option to enable the Texas Instruments Enhanced Quadrature
- Encoder Pulse (eQEP) counter driver.
-
- To compile this driver as a module, choose M here: the module will be
- called ti-eqep.
-
-config FTM_QUADDEC
- tristate "Flex Timer Module Quadrature decoder driver"
- depends on HAS_IOMEM && OF
- help
- Select this option to enable the Flex Timer Quadrature decoder
- driver.
-
- To compile this driver as a module, choose M here: the
- module will be called ftm-quaddec.
-
-config MICROCHIP_TCB_CAPTURE
- tristate "Microchip Timer Counter Capture driver"
- depends on HAS_IOMEM && OF
- select REGMAP_MMIO
+config STM32_TIMER_CNT
+ tristate "STM32 Timer encoder counter driver"
+ depends on MFD_STM32_TIMERS || COMPILE_TEST
help
- Select this option to enable the Microchip Timer Counter Block
- capture driver.
+ Select this option to enable STM32 Timer quadrature encoder
+ and counter driver.
To compile this driver as a module, choose M here: the
- module will be called microchip-tcb-capture.
-
-config INTEL_QEP
- tristate "Intel Quadrature Encoder Peripheral driver"
- depends on PCI
- help
- Select this option to enable the Intel Quadrature Encoder Peripheral
- driver.
-
- To compile this driver as a module, choose M here: the module
- will be called intel-qep.
+ module will be called stm32-timer-cnt.
config TI_ECAP_CAPTURE
tristate "TI eCAP capture driver"
@@ -116,4 +108,15 @@ config TI_ECAP_CAPTURE
To compile this driver as a module, choose M here: the module
will be called ti-ecap-capture.
+config TI_EQEP
+ tristate "TI eQEP counter driver"
+ depends on (SOC_AM33XX || COMPILE_TEST)
+ select REGMAP_MMIO
+ help
+ Select this option to enable the Texas Instruments Enhanced Quadrature
+ Encoder Pulse (eQEP) counter driver.
+
+ To compile this driver as a module, choose M here: the module will be
+ called ti-eqep.
+
endif # COUNTER
diff --git a/drivers/cpuidle/cpuidle-qcom-spm.c b/drivers/cpuidle/cpuidle-qcom-spm.c
index 326bca154ac7..c6e2e91bb4c3 100644
--- a/drivers/cpuidle/cpuidle-qcom-spm.c
+++ b/drivers/cpuidle/cpuidle-qcom-spm.c
@@ -17,7 +17,7 @@
#include <linux/platform_device.h>
#include <linux/cpuidle.h>
#include <linux/cpu_pm.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <soc/qcom/spm.h>
#include <asm/proc-fns.h>
diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c
index 59823ad1d9ae..e4c84433a88a 100644
--- a/drivers/crypto/hisilicon/qm.c
+++ b/drivers/crypto/hisilicon/qm.c
@@ -357,6 +357,16 @@ struct hisi_qm_resource {
struct list_head list;
};
+/**
+ * struct qm_hw_err - Structure describing the device errors
+ * @list: hardware error list
+ * @timestamp: timestamp when the error occurred
+ */
+struct qm_hw_err {
+ struct list_head list;
+ unsigned long long timestamp;
+};
+
struct hisi_qm_hw_ops {
int (*get_vft)(struct hisi_qm *qm, u32 *base, u32 *number);
void (*qm_db)(struct hisi_qm *qm, u16 qn,
@@ -2352,7 +2362,7 @@ static int hisi_qm_uacce_mmap(struct uacce_queue *q,
return -EINVAL;
}
- vma->vm_flags |= VM_IO;
+ vm_flags_set(vma, VM_IO);
return remap_pfn_range(vma, vma->vm_start,
phys_base >> PAGE_SHIFT,
@@ -2458,6 +2468,113 @@ static long hisi_qm_uacce_ioctl(struct uacce_queue *q, unsigned int cmd,
return -EINVAL;
}
+/**
+ * qm_hw_err_isolate() - Try to set the isolation status of the uacce device
+ * according to user's configuration of error threshold.
+ * @qm: the uacce device
+ */
+static int qm_hw_err_isolate(struct hisi_qm *qm)
+{
+ struct qm_hw_err *err, *tmp, *hw_err;
+ struct qm_err_isolate *isolate;
+ u32 count = 0;
+
+ isolate = &qm->isolate_data;
+
+#define SECONDS_PER_HOUR 3600
+
+ /* All the hw errs are processed by PF driver */
+ if (qm->uacce->is_vf || isolate->is_isolate || !isolate->err_threshold)
+ return 0;
+
+ hw_err = kzalloc(sizeof(*hw_err), GFP_KERNEL);
+ if (!hw_err)
+ return -ENOMEM;
+
+ /*
+ * Time-stamp every slot AER error. Then check the AER error log when the
+ * next device AER error occurred. if the device slot AER error count exceeds
+ * the setting error threshold in one hour, the isolated state will be set
+ * to true. And the AER error logs that exceed one hour will be cleared.
+ */
+ mutex_lock(&isolate->isolate_lock);
+ hw_err->timestamp = jiffies;
+ list_for_each_entry_safe(err, tmp, &isolate->qm_hw_errs, list) {
+ if ((hw_err->timestamp - err->timestamp) / HZ >
+ SECONDS_PER_HOUR) {
+ list_del(&err->list);
+ kfree(err);
+ } else {
+ count++;
+ }
+ }
+ list_add(&hw_err->list, &isolate->qm_hw_errs);
+ mutex_unlock(&isolate->isolate_lock);
+
+ if (count >= isolate->err_threshold)
+ isolate->is_isolate = true;
+
+ return 0;
+}
+
+static void qm_hw_err_destroy(struct hisi_qm *qm)
+{
+ struct qm_hw_err *err, *tmp;
+
+ mutex_lock(&qm->isolate_data.isolate_lock);
+ list_for_each_entry_safe(err, tmp, &qm->isolate_data.qm_hw_errs, list) {
+ list_del(&err->list);
+ kfree(err);
+ }
+ mutex_unlock(&qm->isolate_data.isolate_lock);
+}
+
+static enum uacce_dev_state hisi_qm_get_isolate_state(struct uacce_device *uacce)
+{
+ struct hisi_qm *qm = uacce->priv;
+ struct hisi_qm *pf_qm;
+
+ if (uacce->is_vf)
+ pf_qm = pci_get_drvdata(pci_physfn(qm->pdev));
+ else
+ pf_qm = qm;
+
+ return pf_qm->isolate_data.is_isolate ?
+ UACCE_DEV_ISOLATE : UACCE_DEV_NORMAL;
+}
+
+static int hisi_qm_isolate_threshold_write(struct uacce_device *uacce, u32 num)
+{
+ struct hisi_qm *qm = uacce->priv;
+
+ /* Must be set by PF */
+ if (uacce->is_vf)
+ return -EPERM;
+
+ if (qm->isolate_data.is_isolate)
+ return -EPERM;
+
+ qm->isolate_data.err_threshold = num;
+
+ /* After the policy is updated, need to reset the hardware err list */
+ qm_hw_err_destroy(qm);
+
+ return 0;
+}
+
+static u32 hisi_qm_isolate_threshold_read(struct uacce_device *uacce)
+{
+ struct hisi_qm *qm = uacce->priv;
+ struct hisi_qm *pf_qm;
+
+ if (uacce->is_vf) {
+ pf_qm = pci_get_drvdata(pci_physfn(qm->pdev));
+ return pf_qm->isolate_data.err_threshold;
+ }
+
+ return qm->isolate_data.err_threshold;
+}
+
static const struct uacce_ops uacce_qm_ops = {
.get_available_instances = hisi_qm_get_available_instances,
.get_queue = hisi_qm_uacce_get_queue,
@@ -2467,8 +2584,22 @@ static const struct uacce_ops uacce_qm_ops = {
.mmap = hisi_qm_uacce_mmap,
.ioctl = hisi_qm_uacce_ioctl,
.is_q_updated = hisi_qm_is_q_updated,
+ .get_isolate_state = hisi_qm_get_isolate_state,
+ .isolate_err_threshold_write = hisi_qm_isolate_threshold_write,
+ .isolate_err_threshold_read = hisi_qm_isolate_threshold_read,
};
+static void qm_remove_uacce(struct hisi_qm *qm)
+{
+ struct uacce_device *uacce = qm->uacce;
+
+ if (qm->use_sva) {
+ qm_hw_err_destroy(qm);
+ uacce_remove(uacce);
+ qm->uacce = NULL;
+ }
+}
+
static int qm_alloc_uacce(struct hisi_qm *qm)
{
struct pci_dev *pdev = qm->pdev;
@@ -2495,8 +2626,7 @@ static int qm_alloc_uacce(struct hisi_qm *qm)
qm->use_sva = true;
} else {
/* only consider sva case */
- uacce_remove(uacce);
- qm->uacce = NULL;
+ qm_remove_uacce(qm);
return -EINVAL;
}
@@ -2529,6 +2659,8 @@ static int qm_alloc_uacce(struct hisi_qm *qm)
uacce->qf_pg_num[UACCE_QFRT_DUS] = dus_page_nr;
qm->uacce = uacce;
+ INIT_LIST_HEAD(&qm->isolate_data.qm_hw_errs);
+ mutex_init(&qm->isolate_data.isolate_lock);
return 0;
}
@@ -4017,6 +4149,12 @@ static int qm_controller_reset_prepare(struct hisi_qm *qm)
return ret;
}
+ if (qm->use_sva) {
+ ret = qm_hw_err_isolate(qm);
+ if (ret)
+ pci_err(pdev, "failed to isolate hw err!\n");
+ }
+
ret = qm_wait_vf_prepare_finish(qm);
if (ret)
pci_err(pdev, "failed to stop by vfs in soft reset!\n");
@@ -4321,21 +4459,25 @@ static int qm_controller_reset(struct hisi_qm *qm)
qm->err_ini->show_last_dfx_regs(qm);
ret = qm_soft_reset(qm);
- if (ret) {
- pci_err(pdev, "Controller reset failed (%d)\n", ret);
- qm_reset_bit_clear(qm);
- return ret;
- }
+ if (ret)
+ goto err_reset;
ret = qm_controller_reset_done(qm);
- if (ret) {
- qm_reset_bit_clear(qm);
- return ret;
- }
+ if (ret)
+ goto err_reset;
pci_info(pdev, "Controller reset complete\n");
return 0;
+
+err_reset:
+ pci_err(pdev, "Controller reset failed (%d)\n", ret);
+ qm_reset_bit_clear(qm);
+
+ /* if resetting fails, isolate the device */
+ if (qm->use_sva)
+ qm->isolate_data.is_isolate = true;
+ return ret;
}
/**
@@ -5255,10 +5397,7 @@ int hisi_qm_init(struct hisi_qm *qm)
err_free_qm_memory:
hisi_qm_memory_uninit(qm);
err_alloc_uacce:
- if (qm->use_sva) {
- uacce_remove(qm->uacce);
- qm->uacce = NULL;
- }
+ qm_remove_uacce(qm);
err_irq_register:
qm_irqs_unregister(qm);
err_pci_init:
diff --git a/drivers/cxl/Kconfig b/drivers/cxl/Kconfig
index 0ac53c422c31..ff4e78117b31 100644
--- a/drivers/cxl/Kconfig
+++ b/drivers/cxl/Kconfig
@@ -104,19 +104,29 @@ config CXL_SUSPEND
depends on SUSPEND && CXL_MEM
config CXL_REGION
- bool
+ bool "CXL: Region Support"
default CXL_BUS
# For MAX_PHYSMEM_BITS
depends on SPARSEMEM
select MEMREGION
select GET_FREE_REGION
+ help
+ Enable the CXL core to enumerate and provision CXL regions. A CXL
+ region is defined by one or more CXL expanders that decode a given
+ system-physical address range. For CXL regions established by
+ platform-firmware this option enables memory error handling to
+ identify the devices participating in a given interleaved memory
+ range. Otherwise, platform-firmware managed CXL is enabled by being
+ placed in the system address map and does not need a driver.
+
+ If unsure say 'y'
config CXL_REGION_INVALIDATION_TEST
bool "CXL: Region Cache Management Bypass (TEST)"
depends on CXL_REGION
help
CXL Region management and security operations potentially invalidate
- the content of CPU caches without notifiying those caches to
+ the content of CPU caches without notifying those caches to
invalidate the affected cachelines. The CXL Region driver attempts
to invalidate caches when those events occur. If that invalidation
fails the region will fail to enable. Reasons for cache
diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c
index 13cde44c6086..7e1765b09e04 100644
--- a/drivers/cxl/acpi.c
+++ b/drivers/cxl/acpi.c
@@ -19,7 +19,7 @@ struct cxl_cxims_data {
/*
* Find a targets entry (n) in the host bridge interleave list.
- * CXL Specfication 3.0 Table 9-22
+ * CXL Specification 3.0 Table 9-22
*/
static int cxl_xor_calc_n(u64 hpa, struct cxl_cxims_data *cximsd, int iw,
int ig)
@@ -731,7 +731,8 @@ static void __exit cxl_acpi_exit(void)
cxl_bus_drain();
}
-module_init(cxl_acpi_init);
+/* load before dax_hmem sees 'Soft Reserved' CXL ranges */
+subsys_initcall(cxl_acpi_init);
module_exit(cxl_acpi_exit);
MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS(CXL);
diff --git a/drivers/cxl/core/Makefile b/drivers/cxl/core/Makefile
index 79c7257f4107..ca4ae31d8f57 100644
--- a/drivers/cxl/core/Makefile
+++ b/drivers/cxl/core/Makefile
@@ -3,6 +3,8 @@ obj-$(CONFIG_CXL_BUS) += cxl_core.o
obj-$(CONFIG_CXL_SUSPEND) += suspend.o
ccflags-y += -I$(srctree)/drivers/cxl
+CFLAGS_trace.o = -DTRACE_INCLUDE_PATH=. -I$(src)
+
cxl_core-y := port.o
cxl_core-y += pmem.o
cxl_core-y += regs.o
@@ -10,4 +12,5 @@ cxl_core-y += memdev.o
cxl_core-y += mbox.o
cxl_core-y += pci.o
cxl_core-y += hdm.o
+cxl_core-$(CONFIG_TRACING) += trace.o
cxl_core-$(CONFIG_CXL_REGION) += region.o
diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
index 8c04672dca56..cde475e13216 100644
--- a/drivers/cxl/core/core.h
+++ b/drivers/cxl/core/core.h
@@ -11,15 +11,18 @@ extern struct attribute_group cxl_base_attribute_group;
#ifdef CONFIG_CXL_REGION
extern struct device_attribute dev_attr_create_pmem_region;
+extern struct device_attribute dev_attr_create_ram_region;
extern struct device_attribute dev_attr_delete_region;
extern struct device_attribute dev_attr_region;
extern const struct device_type cxl_pmem_region_type;
+extern const struct device_type cxl_dax_region_type;
extern const struct device_type cxl_region_type;
void cxl_decoder_kill_region(struct cxl_endpoint_decoder *cxled);
#define CXL_REGION_ATTR(x) (&dev_attr_##x.attr)
#define CXL_REGION_TYPE(x) (&cxl_region_type)
#define SET_CXL_REGION_ATTR(x) (&dev_attr_##x.attr),
#define CXL_PMEM_REGION_TYPE(x) (&cxl_pmem_region_type)
+#define CXL_DAX_REGION_TYPE(x) (&cxl_dax_region_type)
int cxl_region_init(void);
void cxl_region_exit(void);
#else
@@ -37,6 +40,7 @@ static inline void cxl_region_exit(void)
#define CXL_REGION_TYPE(x) NULL
#define SET_CXL_REGION_ATTR(x)
#define CXL_PMEM_REGION_TYPE(x) NULL
+#define CXL_DAX_REGION_TYPE(x) NULL
#endif
struct cxl_send_command;
@@ -56,9 +60,6 @@ resource_size_t cxl_dpa_size(struct cxl_endpoint_decoder *cxled);
resource_size_t cxl_dpa_resource_start(struct cxl_endpoint_decoder *cxled);
extern struct rw_semaphore cxl_dpa_rwsem;
-bool is_switch_decoder(struct device *dev);
-struct cxl_switch_decoder *to_cxl_switch_decoder(struct device *dev);
-
int cxl_memdev_init(void);
void cxl_memdev_exit(void);
void cxl_mbox_init(void);
diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c
index dcc16d7cb8f3..45deda18ed32 100644
--- a/drivers/cxl/core/hdm.c
+++ b/drivers/cxl/core/hdm.c
@@ -101,11 +101,34 @@ static int map_hdm_decoder_regs(struct cxl_port *port, void __iomem *crb,
BIT(CXL_CM_CAP_CAP_ID_HDM));
}
+static struct cxl_hdm *devm_cxl_setup_emulated_hdm(struct cxl_port *port,
+ struct cxl_endpoint_dvsec_info *info)
+{
+ struct device *dev = &port->dev;
+ struct cxl_hdm *cxlhdm;
+
+ if (!info->mem_enabled)
+ return ERR_PTR(-ENODEV);
+
+ cxlhdm = devm_kzalloc(dev, sizeof(*cxlhdm), GFP_KERNEL);
+ if (!cxlhdm)
+ return ERR_PTR(-ENOMEM);
+
+ cxlhdm->port = port;
+ cxlhdm->decoder_count = info->ranges;
+ cxlhdm->target_count = info->ranges;
+ dev_set_drvdata(&port->dev, cxlhdm);
+
+ return cxlhdm;
+}
+
/**
* devm_cxl_setup_hdm - map HDM decoder component registers
* @port: cxl_port to map
+ * @info: cached DVSEC range register info
*/
-struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port)
+struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port,
+ struct cxl_endpoint_dvsec_info *info)
{
struct device *dev = &port->dev;
struct cxl_hdm *cxlhdm;
@@ -119,6 +142,9 @@ struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port)
cxlhdm->port = port;
crb = ioremap(port->component_reg_phys, CXL_COMPONENT_REG_BLOCK_SIZE);
if (!crb) {
+ if (info && info->mem_enabled)
+ return devm_cxl_setup_emulated_hdm(port, info);
+
dev_err(dev, "No component registers mapped\n");
return ERR_PTR(-ENXIO);
}
@@ -279,7 +305,7 @@ success:
return 0;
}
-static int devm_cxl_dpa_reserve(struct cxl_endpoint_decoder *cxled,
+int devm_cxl_dpa_reserve(struct cxl_endpoint_decoder *cxled,
resource_size_t base, resource_size_t len,
resource_size_t skipped)
{
@@ -295,6 +321,7 @@ static int devm_cxl_dpa_reserve(struct cxl_endpoint_decoder *cxled,
return devm_add_action_or_reset(&port->dev, cxl_dpa_release, cxled);
}
+EXPORT_SYMBOL_NS_GPL(devm_cxl_dpa_reserve, CXL);
resource_size_t cxl_dpa_size(struct cxl_endpoint_decoder *cxled)
{
@@ -676,12 +703,71 @@ static int cxl_decoder_reset(struct cxl_decoder *cxld)
port->commit_end--;
cxld->flags &= ~CXL_DECODER_F_ENABLE;
+ /* Userspace is now responsible for reconfiguring this decoder */
+ if (is_endpoint_decoder(&cxld->dev)) {
+ struct cxl_endpoint_decoder *cxled;
+
+ cxled = to_cxl_endpoint_decoder(&cxld->dev);
+ cxled->state = CXL_DECODER_STATE_MANUAL;
+ }
+
+ return 0;
+}
+
+static int cxl_setup_hdm_decoder_from_dvsec(struct cxl_port *port,
+ struct cxl_decoder *cxld, int which,
+ struct cxl_endpoint_dvsec_info *info)
+{
+ if (!is_cxl_endpoint(port))
+ return -EOPNOTSUPP;
+
+ if (!range_len(&info->dvsec_range[which]))
+ return -ENOENT;
+
+ cxld->target_type = CXL_DECODER_EXPANDER;
+ cxld->commit = NULL;
+ cxld->reset = NULL;
+ cxld->hpa_range = info->dvsec_range[which];
+
+ /*
+ * Set the emulated decoder as locked pending additional support to
+ * change the range registers at run time.
+ */
+ cxld->flags |= CXL_DECODER_F_ENABLE | CXL_DECODER_F_LOCK;
+ port->commit_end = cxld->id;
+
return 0;
}
+static bool should_emulate_decoders(struct cxl_port *port)
+{
+ struct cxl_hdm *cxlhdm = dev_get_drvdata(&port->dev);
+ void __iomem *hdm = cxlhdm->regs.hdm_decoder;
+ u32 ctrl;
+ int i;
+
+ if (!is_cxl_endpoint(cxlhdm->port))
+ return false;
+
+ if (!hdm)
+ return true;
+
+ /*
+ * If any decoders are committed already, there should not be any
+ * emulated DVSEC decoders.
+ */
+ for (i = 0; i < cxlhdm->decoder_count; i++) {
+ ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(i));
+ if (FIELD_GET(CXL_HDM_DECODER0_CTRL_COMMITTED, ctrl))
+ return false;
+ }
+
+ return true;
+}
+
static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
int *target_map, void __iomem *hdm, int which,
- u64 *dpa_base)
+ u64 *dpa_base, struct cxl_endpoint_dvsec_info *info)
{
struct cxl_endpoint_decoder *cxled = NULL;
u64 size, base, skip, dpa_size;
@@ -694,6 +780,9 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
unsigned char target_id[8];
} target_list;
+ if (should_emulate_decoders(port))
+ return cxl_setup_hdm_decoder_from_dvsec(port, cxld, which, info);
+
if (is_endpoint_decoder(&cxld->dev))
cxled = to_cxl_endpoint_decoder(&cxld->dev);
@@ -717,6 +806,9 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
.end = base + size - 1,
};
+ if (cxled && !committed && range_len(&info->dvsec_range[which]))
+ return cxl_setup_hdm_decoder_from_dvsec(port, cxld, which, info);
+
/* decoders are enabled if committed */
if (committed) {
cxld->flags |= CXL_DECODER_F_ENABLE;
@@ -783,21 +875,21 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
return rc;
}
*dpa_base += dpa_size + skip;
+
+ cxled->state = CXL_DECODER_STATE_AUTO;
+
return 0;
}
-/**
- * devm_cxl_enumerate_decoders - add decoder objects per HDM register set
- * @cxlhdm: Structure to populate with HDM capabilities
- */
-int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm)
+static void cxl_settle_decoders(struct cxl_hdm *cxlhdm)
{
void __iomem *hdm = cxlhdm->regs.hdm_decoder;
- struct cxl_port *port = cxlhdm->port;
- int i, committed;
- u64 dpa_base = 0;
+ int committed, i;
u32 ctrl;
+ if (!hdm)
+ return;
+
/*
* Since the register resource was recently claimed via request_region()
* be careful about trusting the "not-committed" status until the commit
@@ -814,6 +906,22 @@ int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm)
/* ensure that future checks of committed can be trusted */
if (committed != cxlhdm->decoder_count)
msleep(20);
+}
+
+/**
+ * devm_cxl_enumerate_decoders - add decoder objects per HDM register set
+ * @cxlhdm: Structure to populate with HDM capabilities
+ * @info: cached DVSEC range register info
+ */
+int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,
+ struct cxl_endpoint_dvsec_info *info)
+{
+ void __iomem *hdm = cxlhdm->regs.hdm_decoder;
+ struct cxl_port *port = cxlhdm->port;
+ int i;
+ u64 dpa_base = 0;
+
+ cxl_settle_decoders(cxlhdm);
for (i = 0; i < cxlhdm->decoder_count; i++) {
int target_map[CXL_DECODER_MAX_INTERLEAVE] = { 0 };
@@ -826,7 +934,8 @@ int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm)
cxled = cxl_endpoint_decoder_alloc(port);
if (IS_ERR(cxled)) {
dev_warn(&port->dev,
- "Failed to allocate the decoder\n");
+ "Failed to allocate decoder%d.%d\n",
+ port->id, i);
return PTR_ERR(cxled);
}
cxld = &cxled->cxld;
@@ -836,21 +945,26 @@ int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm)
cxlsd = cxl_switch_decoder_alloc(port, target_count);
if (IS_ERR(cxlsd)) {
dev_warn(&port->dev,
- "Failed to allocate the decoder\n");
+ "Failed to allocate decoder%d.%d\n",
+ port->id, i);
return PTR_ERR(cxlsd);
}
cxld = &cxlsd->cxld;
}
- rc = init_hdm_decoder(port, cxld, target_map, hdm, i, &dpa_base);
+ rc = init_hdm_decoder(port, cxld, target_map, hdm, i,
+ &dpa_base, info);
if (rc) {
+ dev_warn(&port->dev,
+ "Failed to initialize decoder%d.%d\n",
+ port->id, i);
put_device(&cxld->dev);
return rc;
}
rc = add_hdm_decoder(port, cxld, target_map);
if (rc) {
dev_warn(&port->dev,
- "Failed to add decoder to port\n");
+ "Failed to add decoder%d.%d\n", port->id, i);
return rc;
}
}
diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c
index b03fba212799..f2addb457172 100644
--- a/drivers/cxl/core/mbox.c
+++ b/drivers/cxl/core/mbox.c
@@ -3,11 +3,13 @@
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/security.h>
#include <linux/debugfs.h>
+#include <linux/ktime.h>
#include <linux/mutex.h>
#include <cxlmem.h>
#include <cxl.h>
#include "core.h"
+#include "trace.h"
static bool cxl_raw_allow_all;
@@ -170,6 +172,12 @@ int cxl_internal_send_cmd(struct cxl_dev_state *cxlds,
out_size = mbox_cmd->size_out;
min_out = mbox_cmd->min_out;
rc = cxlds->mbox_send(cxlds, mbox_cmd);
+ /*
+ * EIO is reserved for a payload size mismatch and mbox_send()
+ * may not return this error.
+ */
+ if (WARN_ONCE(rc == -EIO, "Bad return code: -EIO"))
+ return -ENXIO;
if (rc)
return rc;
@@ -445,9 +453,14 @@ int cxl_query_cmd(struct cxl_memdev *cxlmd,
* structures.
*/
cxl_for_each_cmd(cmd) {
- const struct cxl_command_info *info = &cmd->info;
+ struct cxl_command_info info = cmd->info;
- if (copy_to_user(&q->commands[j++], info, sizeof(*info)))
+ if (test_bit(info.id, cxlmd->cxlds->enabled_cmds))
+ info.flags |= CXL_MEM_COMMAND_FLAG_ENABLED;
+ if (test_bit(info.id, cxlmd->cxlds->exclusive_cmds))
+ info.flags |= CXL_MEM_COMMAND_FLAG_EXCLUSIVE;
+
+ if (copy_to_user(&q->commands[j++], &info, sizeof(info)))
return -EFAULT;
if (j == n_commands)
@@ -550,9 +563,9 @@ int cxl_send_cmd(struct cxl_memdev *cxlmd, struct cxl_send_command __user *s)
return 0;
}
-static int cxl_xfer_log(struct cxl_dev_state *cxlds, uuid_t *uuid, u32 size, u8 *out)
+static int cxl_xfer_log(struct cxl_dev_state *cxlds, uuid_t *uuid, u32 *size, u8 *out)
{
- u32 remaining = size;
+ u32 remaining = *size;
u32 offset = 0;
while (remaining) {
@@ -576,6 +589,17 @@ static int cxl_xfer_log(struct cxl_dev_state *cxlds, uuid_t *uuid, u32 size, u8
};
rc = cxl_internal_send_cmd(cxlds, &mbox_cmd);
+
+ /*
+ * The output payload length that indicates the number
+ * of valid bytes can be smaller than the Log buffer
+ * size.
+ */
+ if (rc == -EIO && mbox_cmd.size_out < xfer_size) {
+ offset += mbox_cmd.size_out;
+ break;
+ }
+
if (rc < 0)
return rc;
@@ -584,6 +608,8 @@ static int cxl_xfer_log(struct cxl_dev_state *cxlds, uuid_t *uuid, u32 size, u8
offset += xfer_size;
}
+ *size = offset;
+
return 0;
}
@@ -610,11 +636,12 @@ static void cxl_walk_cel(struct cxl_dev_state *cxlds, size_t size, u8 *cel)
if (!cmd) {
dev_dbg(cxlds->dev,
- "Opcode 0x%04x unsupported by driver", opcode);
+ "Opcode 0x%04x unsupported by driver\n", opcode);
continue;
}
set_bit(cmd->info.id, cxlds->enabled_cmds);
+ dev_dbg(cxlds->dev, "Opcode 0x%04x enabled\n", opcode);
}
}
@@ -694,7 +721,7 @@ int cxl_enumerate_cmds(struct cxl_dev_state *cxlds)
goto out;
}
- rc = cxl_xfer_log(cxlds, &uuid, size, log);
+ rc = cxl_xfer_log(cxlds, &uuid, &size, log);
if (rc) {
kvfree(log);
goto out;
@@ -717,6 +744,203 @@ out:
}
EXPORT_SYMBOL_NS_GPL(cxl_enumerate_cmds, CXL);
+/*
+ * General Media Event Record
+ * CXL rev 3.0 Section 8.2.9.2.1.1; Table 8-43
+ */
+static const uuid_t gen_media_event_uuid =
+ UUID_INIT(0xfbcd0a77, 0xc260, 0x417f,
+ 0x85, 0xa9, 0x08, 0x8b, 0x16, 0x21, 0xeb, 0xa6);
+
+/*
+ * DRAM Event Record
+ * CXL rev 3.0 section 8.2.9.2.1.2; Table 8-44
+ */
+static const uuid_t dram_event_uuid =
+ UUID_INIT(0x601dcbb3, 0x9c06, 0x4eab,
+ 0xb8, 0xaf, 0x4e, 0x9b, 0xfb, 0x5c, 0x96, 0x24);
+
+/*
+ * Memory Module Event Record
+ * CXL rev 3.0 section 8.2.9.2.1.3; Table 8-45
+ */
+static const uuid_t mem_mod_event_uuid =
+ UUID_INIT(0xfe927475, 0xdd59, 0x4339,
+ 0xa5, 0x86, 0x79, 0xba, 0xb1, 0x13, 0xb7, 0x74);
+
+static void cxl_event_trace_record(const struct cxl_memdev *cxlmd,
+ enum cxl_event_log_type type,
+ struct cxl_event_record_raw *record)
+{
+ uuid_t *id = &record->hdr.id;
+
+ if (uuid_equal(id, &gen_media_event_uuid)) {
+ struct cxl_event_gen_media *rec =
+ (struct cxl_event_gen_media *)record;
+
+ trace_cxl_general_media(cxlmd, type, rec);
+ } else if (uuid_equal(id, &dram_event_uuid)) {
+ struct cxl_event_dram *rec = (struct cxl_event_dram *)record;
+
+ trace_cxl_dram(cxlmd, type, rec);
+ } else if (uuid_equal(id, &mem_mod_event_uuid)) {
+ struct cxl_event_mem_module *rec =
+ (struct cxl_event_mem_module *)record;
+
+ trace_cxl_memory_module(cxlmd, type, rec);
+ } else {
+ /* For unknown record types print just the header */
+ trace_cxl_generic_event(cxlmd, type, record);
+ }
+}
+
+static int cxl_clear_event_record(struct cxl_dev_state *cxlds,
+ enum cxl_event_log_type log,
+ struct cxl_get_event_payload *get_pl)
+{
+ struct cxl_mbox_clear_event_payload *payload;
+ u16 total = le16_to_cpu(get_pl->record_count);
+ u8 max_handles = CXL_CLEAR_EVENT_MAX_HANDLES;
+ size_t pl_size = struct_size(payload, handles, max_handles);
+ struct cxl_mbox_cmd mbox_cmd;
+ u16 cnt;
+ int rc = 0;
+ int i;
+
+ /* Payload size may limit the max handles */
+ if (pl_size > cxlds->payload_size) {
+ max_handles = (cxlds->payload_size - sizeof(*payload)) /
+ sizeof(__le16);
+ pl_size = struct_size(payload, handles, max_handles);
+ }
+
+ payload = kvzalloc(pl_size, GFP_KERNEL);
+ if (!payload)
+ return -ENOMEM;
+
+ *payload = (struct cxl_mbox_clear_event_payload) {
+ .event_log = log,
+ };
+
+ mbox_cmd = (struct cxl_mbox_cmd) {
+ .opcode = CXL_MBOX_OP_CLEAR_EVENT_RECORD,
+ .payload_in = payload,
+ .size_in = pl_size,
+ };
+
+ /*
+ * Clear Event Records uses u8 for the handle cnt while Get Event
+ * Record can return up to 0xffff records.
+ */
+ i = 0;
+ for (cnt = 0; cnt < total; cnt++) {
+ payload->handles[i++] = get_pl->records[cnt].hdr.handle;
+ dev_dbg(cxlds->dev, "Event log '%d': Clearing %u\n",
+ log, le16_to_cpu(payload->handles[i]));
+
+ if (i == max_handles) {
+ payload->nr_recs = i;
+ rc = cxl_internal_send_cmd(cxlds, &mbox_cmd);
+ if (rc)
+ goto free_pl;
+ i = 0;
+ }
+ }
+
+ /* Clear what is left if any */
+ if (i) {
+ payload->nr_recs = i;
+ mbox_cmd.size_in = struct_size(payload, handles, i);
+ rc = cxl_internal_send_cmd(cxlds, &mbox_cmd);
+ if (rc)
+ goto free_pl;
+ }
+
+free_pl:
+ kvfree(payload);
+ return rc;
+}
+
+static void cxl_mem_get_records_log(struct cxl_dev_state *cxlds,
+ enum cxl_event_log_type type)
+{
+ struct cxl_get_event_payload *payload;
+ struct cxl_mbox_cmd mbox_cmd;
+ u8 log_type = type;
+ u16 nr_rec;
+
+ mutex_lock(&cxlds->event.log_lock);
+ payload = cxlds->event.buf;
+
+ mbox_cmd = (struct cxl_mbox_cmd) {
+ .opcode = CXL_MBOX_OP_GET_EVENT_RECORD,
+ .payload_in = &log_type,
+ .size_in = sizeof(log_type),
+ .payload_out = payload,
+ .size_out = cxlds->payload_size,
+ .min_out = struct_size(payload, records, 0),
+ };
+
+ do {
+ int rc, i;
+
+ rc = cxl_internal_send_cmd(cxlds, &mbox_cmd);
+ if (rc) {
+ dev_err_ratelimited(cxlds->dev,
+ "Event log '%d': Failed to query event records : %d",
+ type, rc);
+ break;
+ }
+
+ nr_rec = le16_to_cpu(payload->record_count);
+ if (!nr_rec)
+ break;
+
+ for (i = 0; i < nr_rec; i++)
+ cxl_event_trace_record(cxlds->cxlmd, type,
+ &payload->records[i]);
+
+ if (payload->flags & CXL_GET_EVENT_FLAG_OVERFLOW)
+ trace_cxl_overflow(cxlds->cxlmd, type, payload);
+
+ rc = cxl_clear_event_record(cxlds, type, payload);
+ if (rc) {
+ dev_err_ratelimited(cxlds->dev,
+ "Event log '%d': Failed to clear events : %d",
+ type, rc);
+ break;
+ }
+ } while (nr_rec);
+
+ mutex_unlock(&cxlds->event.log_lock);
+}
+
+/**
+ * cxl_mem_get_event_records - Get Event Records from the device
+ * @cxlds: The device data for the operation
+ * @status: Event Status register value identifying which events are available.
+ *
+ * Retrieve all event records available on the device, report them as trace
+ * events, and clear them.
+ *
+ * See CXL rev 3.0 @8.2.9.2.2 Get Event Records
+ * See CXL rev 3.0 @8.2.9.2.3 Clear Event Records
+ */
+void cxl_mem_get_event_records(struct cxl_dev_state *cxlds, u32 status)
+{
+ dev_dbg(cxlds->dev, "Reading event logs: %x\n", status);
+
+ if (status & CXLDEV_EVENT_STATUS_FATAL)
+ cxl_mem_get_records_log(cxlds, CXL_EVENT_TYPE_FATAL);
+ if (status & CXLDEV_EVENT_STATUS_FAIL)
+ cxl_mem_get_records_log(cxlds, CXL_EVENT_TYPE_FAIL);
+ if (status & CXLDEV_EVENT_STATUS_WARN)
+ cxl_mem_get_records_log(cxlds, CXL_EVENT_TYPE_WARN);
+ if (status & CXLDEV_EVENT_STATUS_INFO)
+ cxl_mem_get_records_log(cxlds, CXL_EVENT_TYPE_INFO);
+}
+EXPORT_SYMBOL_NS_GPL(cxl_mem_get_event_records, CXL);
+
/**
* cxl_mem_get_partition_info - Get partition info
* @cxlds: The device data for the operation
@@ -857,6 +1081,32 @@ int cxl_mem_create_range_info(struct cxl_dev_state *cxlds)
}
EXPORT_SYMBOL_NS_GPL(cxl_mem_create_range_info, CXL);
+int cxl_set_timestamp(struct cxl_dev_state *cxlds)
+{
+ struct cxl_mbox_cmd mbox_cmd;
+ struct cxl_mbox_set_timestamp_in pi;
+ int rc;
+
+ pi.timestamp = cpu_to_le64(ktime_get_real_ns());
+ mbox_cmd = (struct cxl_mbox_cmd) {
+ .opcode = CXL_MBOX_OP_SET_TIMESTAMP,
+ .size_in = sizeof(pi),
+ .payload_in = &pi,
+ };
+
+ rc = cxl_internal_send_cmd(cxlds, &mbox_cmd);
+ /*
+ * Command is optional. Devices may have another way of providing
+ * a timestamp, or may return all 0s in timestamp fields.
+ * Don't report an error if this command isn't supported
+ */
+ if (rc && (mbox_cmd.return_code != CXL_MBOX_CMD_RC_UNSUPPORTED))
+ return rc;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cxl_set_timestamp, CXL);
+
struct cxl_dev_state *cxl_dev_state_create(struct device *dev)
{
struct cxl_dev_state *cxlds;
@@ -868,6 +1118,7 @@ struct cxl_dev_state *cxl_dev_state_create(struct device *dev)
}
mutex_init(&cxlds->mbox_mutex);
+ mutex_init(&cxlds->event.log_lock);
cxlds->dev = dev;
return cxlds;
diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c
index a74a93310d26..28a05f2fe32d 100644
--- a/drivers/cxl/core/memdev.c
+++ b/drivers/cxl/core/memdev.c
@@ -27,7 +27,7 @@ static void cxl_memdev_release(struct device *dev)
kfree(cxlmd);
}
-static char *cxl_memdev_devnode(struct device *dev, umode_t *mode, kuid_t *uid,
+static char *cxl_memdev_devnode(const struct device *dev, umode_t *mode, kuid_t *uid,
kgid_t *gid)
{
return kasprintf(GFP_KERNEL, "cxl/%s", dev_name(dev));
@@ -162,7 +162,7 @@ static const struct device_type cxl_memdev_type = {
.groups = cxl_memdev_attribute_groups,
};
-bool is_cxl_memdev(struct device *dev)
+bool is_cxl_memdev(const struct device *dev)
{
return dev->type == &cxl_memdev_type;
}
@@ -242,10 +242,11 @@ static struct cxl_memdev *cxl_memdev_alloc(struct cxl_dev_state *cxlds,
if (!cxlmd)
return ERR_PTR(-ENOMEM);
- rc = ida_alloc_range(&cxl_memdev_ida, 0, CXL_MEM_MAX_DEVS, GFP_KERNEL);
+ rc = ida_alloc_max(&cxl_memdev_ida, CXL_MEM_MAX_DEVS - 1, GFP_KERNEL);
if (rc < 0)
goto err;
cxlmd->id = rc;
+ cxlmd->depth = -1;
dev = &cxlmd->dev;
device_initialize(dev);
diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
index 57764e9cd19d..7328a2552411 100644
--- a/drivers/cxl/core/pci.c
+++ b/drivers/cxl/core/pci.c
@@ -9,6 +9,7 @@
#include <cxlmem.h>
#include <cxl.h>
#include "core.h"
+#include "trace.h"
/**
* DOC: cxl core pci
@@ -141,11 +142,10 @@ int cxl_await_media_ready(struct cxl_dev_state *cxlds)
}
EXPORT_SYMBOL_NS_GPL(cxl_await_media_ready, CXL);
-static int wait_for_valid(struct cxl_dev_state *cxlds)
+static int wait_for_valid(struct pci_dev *pdev, int d)
{
- struct pci_dev *pdev = to_pci_dev(cxlds->dev);
- int d = cxlds->cxl_dvsec, rc;
u32 val;
+ int rc;
/*
* Memory_Info_Valid: When set, indicates that the CXL Range 1 Size high
@@ -213,11 +213,6 @@ static int devm_cxl_enable_mem(struct device *host, struct cxl_dev_state *cxlds)
return devm_add_action_or_reset(host, clear_mem_enable, cxlds);
}
-static bool range_contains(struct range *r1, struct range *r2)
-{
- return r1->start <= r2->start && r1->end >= r2->end;
-}
-
/* require dvsec ranges to be covered by a locked platform window */
static int dvsec_range_allowed(struct device *dev, void *arg)
{
@@ -229,8 +224,6 @@ static int dvsec_range_allowed(struct device *dev, void *arg)
cxld = to_cxl_decoder(dev);
- if (!(cxld->flags & CXL_DECODER_F_LOCK))
- return 0;
if (!(cxld->flags & CXL_DECODER_F_RAM))
return 0;
@@ -260,94 +253,11 @@ static int devm_cxl_enable_hdm(struct device *host, struct cxl_hdm *cxlhdm)
return devm_add_action_or_reset(host, disable_hdm, cxlhdm);
}
-static bool __cxl_hdm_decode_init(struct cxl_dev_state *cxlds,
- struct cxl_hdm *cxlhdm,
- struct cxl_endpoint_dvsec_info *info)
+int cxl_dvsec_rr_decode(struct device *dev, int d,
+ struct cxl_endpoint_dvsec_info *info)
{
- void __iomem *hdm = cxlhdm->regs.hdm_decoder;
- struct cxl_port *port = cxlhdm->port;
- struct device *dev = cxlds->dev;
- struct cxl_port *root;
- int i, rc, allowed;
- u32 global_ctrl;
-
- global_ctrl = readl(hdm + CXL_HDM_DECODER_CTRL_OFFSET);
-
- /*
- * If the HDM Decoder Capability is already enabled then assume
- * that some other agent like platform firmware set it up.
- */
- if (global_ctrl & CXL_HDM_DECODER_ENABLE) {
- rc = devm_cxl_enable_mem(&port->dev, cxlds);
- if (rc)
- return false;
- return true;
- }
-
- root = to_cxl_port(port->dev.parent);
- while (!is_cxl_root(root) && is_cxl_port(root->dev.parent))
- root = to_cxl_port(root->dev.parent);
- if (!is_cxl_root(root)) {
- dev_err(dev, "Failed to acquire root port for HDM enable\n");
- return false;
- }
-
- for (i = 0, allowed = 0; info->mem_enabled && i < info->ranges; i++) {
- struct device *cxld_dev;
-
- cxld_dev = device_find_child(&root->dev, &info->dvsec_range[i],
- dvsec_range_allowed);
- if (!cxld_dev) {
- dev_dbg(dev, "DVSEC Range%d denied by platform\n", i);
- continue;
- }
- dev_dbg(dev, "DVSEC Range%d allowed by platform\n", i);
- put_device(cxld_dev);
- allowed++;
- }
-
- if (!allowed) {
- cxl_set_mem_enable(cxlds, 0);
- info->mem_enabled = 0;
- }
-
- /*
- * Per CXL 2.0 Section 8.1.3.8.3 and 8.1.3.8.4 DVSEC CXL Range 1 Base
- * [High,Low] when HDM operation is enabled the range register values
- * are ignored by the device, but the spec also recommends matching the
- * DVSEC Range 1,2 to HDM Decoder Range 0,1. So, non-zero info->ranges
- * are expected even though Linux does not require or maintain that
- * match. If at least one DVSEC range is enabled and allowed, skip HDM
- * Decoder Capability Enable.
- */
- if (info->mem_enabled)
- return false;
-
- rc = devm_cxl_enable_hdm(&port->dev, cxlhdm);
- if (rc)
- return false;
-
- rc = devm_cxl_enable_mem(&port->dev, cxlds);
- if (rc)
- return false;
-
- return true;
-}
-
-/**
- * cxl_hdm_decode_init() - Setup HDM decoding for the endpoint
- * @cxlds: Device state
- * @cxlhdm: Mapped HDM decoder Capability
- *
- * Try to enable the endpoint's HDM Decoder Capability
- */
-int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm)
-{
- struct pci_dev *pdev = to_pci_dev(cxlds->dev);
- struct cxl_endpoint_dvsec_info info = { 0 };
+ struct pci_dev *pdev = to_pci_dev(dev);
int hdm_count, rc, i, ranges = 0;
- struct device *dev = &pdev->dev;
- int d = cxlds->cxl_dvsec;
u16 cap, ctrl;
if (!d) {
@@ -378,7 +288,7 @@ int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm)
if (!hdm_count || hdm_count > 2)
return -EINVAL;
- rc = wait_for_valid(cxlds);
+ rc = wait_for_valid(pdev, d);
if (rc) {
dev_dbg(dev, "Failure awaiting MEM_INFO_VALID (%d)\n", rc);
return rc;
@@ -389,9 +299,9 @@ int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm)
* disabled, and they will remain moot after the HDM Decoder
* capability is enabled.
*/
- info.mem_enabled = FIELD_GET(CXL_DVSEC_MEM_ENABLE, ctrl);
- if (!info.mem_enabled)
- goto hdm_init;
+ info->mem_enabled = FIELD_GET(CXL_DVSEC_MEM_ENABLE, ctrl);
+ if (!info->mem_enabled)
+ return 0;
for (i = 0; i < hdm_count; i++) {
u64 base, size;
@@ -410,6 +320,13 @@ int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm)
return rc;
size |= temp & CXL_DVSEC_MEM_SIZE_LOW_MASK;
+ if (!size) {
+ info->dvsec_range[i] = (struct range) {
+ .start = 0,
+ .end = CXL_RESOURCE_NONE,
+ };
+ continue;
+ }
rc = pci_read_config_dword(
pdev, d + CXL_DVSEC_RANGE_BASE_HIGH(i), &temp);
@@ -425,29 +342,94 @@ int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm)
base |= temp & CXL_DVSEC_MEM_BASE_LOW_MASK;
- info.dvsec_range[i] = (struct range) {
+ info->dvsec_range[i] = (struct range) {
.start = base,
.end = base + size - 1
};
- if (size)
- ranges++;
+ ranges++;
}
- info.ranges = ranges;
+ info->ranges = ranges;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cxl_dvsec_rr_decode, CXL);
+
+/**
+ * cxl_hdm_decode_init() - Setup HDM decoding for the endpoint
+ * @cxlds: Device state
+ * @cxlhdm: Mapped HDM decoder Capability
+ * @info: Cached DVSEC range registers info
+ *
+ * Try to enable the endpoint's HDM Decoder Capability
+ */
+int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm,
+ struct cxl_endpoint_dvsec_info *info)
+{
+ void __iomem *hdm = cxlhdm->regs.hdm_decoder;
+ struct cxl_port *port = cxlhdm->port;
+ struct device *dev = cxlds->dev;
+ struct cxl_port *root;
+ int i, rc, allowed;
+ u32 global_ctrl = 0;
+
+ if (hdm)
+ global_ctrl = readl(hdm + CXL_HDM_DECODER_CTRL_OFFSET);
/*
- * If DVSEC ranges are being used instead of HDM decoder registers there
- * is no use in trying to manage those.
+ * If the HDM Decoder Capability is already enabled then assume
+ * that some other agent like platform firmware set it up.
*/
-hdm_init:
- if (!__cxl_hdm_decode_init(cxlds, cxlhdm, &info)) {
- dev_err(dev,
- "Legacy range registers configuration prevents HDM operation.\n");
- return -EBUSY;
+ if (global_ctrl & CXL_HDM_DECODER_ENABLE || (!hdm && info->mem_enabled))
+ return devm_cxl_enable_mem(&port->dev, cxlds);
+ else if (!hdm)
+ return -ENODEV;
+
+ root = to_cxl_port(port->dev.parent);
+ while (!is_cxl_root(root) && is_cxl_port(root->dev.parent))
+ root = to_cxl_port(root->dev.parent);
+ if (!is_cxl_root(root)) {
+ dev_err(dev, "Failed to acquire root port for HDM enable\n");
+ return -ENODEV;
}
- return 0;
+ for (i = 0, allowed = 0; info->mem_enabled && i < info->ranges; i++) {
+ struct device *cxld_dev;
+
+ cxld_dev = device_find_child(&root->dev, &info->dvsec_range[i],
+ dvsec_range_allowed);
+ if (!cxld_dev) {
+ dev_dbg(dev, "DVSEC Range%d denied by platform\n", i);
+ continue;
+ }
+ dev_dbg(dev, "DVSEC Range%d allowed by platform\n", i);
+ put_device(cxld_dev);
+ allowed++;
+ }
+
+ if (!allowed) {
+ cxl_set_mem_enable(cxlds, 0);
+ info->mem_enabled = 0;
+ }
+
+ /*
+ * Per CXL 2.0 Section 8.1.3.8.3 and 8.1.3.8.4 DVSEC CXL Range 1 Base
+ * [High,Low] when HDM operation is enabled the range register values
+ * are ignored by the device, but the spec also recommends matching the
+ * DVSEC Range 1,2 to HDM Decoder Range 0,1. So, non-zero info->ranges
+ * are expected even though Linux does not require or maintain that
+ * match. If at least one DVSEC range is enabled and allowed, skip HDM
+ * Decoder Capability Enable.
+ */
+ if (info->mem_enabled)
+ return 0;
+
+ rc = devm_cxl_enable_hdm(&port->dev, cxlhdm);
+ if (rc)
+ return rc;
+
+ return devm_cxl_enable_mem(&port->dev, cxlds);
}
EXPORT_SYMBOL_NS_GPL(cxl_hdm_decode_init, CXL);
@@ -622,3 +604,113 @@ void read_cdat_data(struct cxl_port *port)
}
}
EXPORT_SYMBOL_NS_GPL(read_cdat_data, CXL);
+
+void cxl_cor_error_detected(struct pci_dev *pdev)
+{
+ struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
+ void __iomem *addr;
+ u32 status;
+
+ if (!cxlds->regs.ras)
+ return;
+
+ addr = cxlds->regs.ras + CXL_RAS_CORRECTABLE_STATUS_OFFSET;
+ status = readl(addr);
+ if (status & CXL_RAS_CORRECTABLE_STATUS_MASK) {
+ writel(status & CXL_RAS_CORRECTABLE_STATUS_MASK, addr);
+ trace_cxl_aer_correctable_error(cxlds->cxlmd, status);
+ }
+}
+EXPORT_SYMBOL_NS_GPL(cxl_cor_error_detected, CXL);
+
+/* CXL spec rev3.0 8.2.4.16.1 */
+static void header_log_copy(struct cxl_dev_state *cxlds, u32 *log)
+{
+ void __iomem *addr;
+ u32 *log_addr;
+ int i, log_u32_size = CXL_HEADERLOG_SIZE / sizeof(u32);
+
+ addr = cxlds->regs.ras + CXL_RAS_HEADER_LOG_OFFSET;
+ log_addr = log;
+
+ for (i = 0; i < log_u32_size; i++) {
+ *log_addr = readl(addr);
+ log_addr++;
+ addr += sizeof(u32);
+ }
+}
+
+/*
+ * Log the state of the RAS status registers and prepare them to log the
+ * next error status. Return 1 if reset needed.
+ */
+static bool cxl_report_and_clear(struct cxl_dev_state *cxlds)
+{
+ u32 hl[CXL_HEADERLOG_SIZE_U32];
+ void __iomem *addr;
+ u32 status;
+ u32 fe;
+
+ if (!cxlds->regs.ras)
+ return false;
+
+ addr = cxlds->regs.ras + CXL_RAS_UNCORRECTABLE_STATUS_OFFSET;
+ status = readl(addr);
+ if (!(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK))
+ return false;
+
+ /* If multiple errors, log header points to first error from ctrl reg */
+ if (hweight32(status) > 1) {
+ void __iomem *rcc_addr =
+ cxlds->regs.ras + CXL_RAS_CAP_CONTROL_OFFSET;
+
+ fe = BIT(FIELD_GET(CXL_RAS_CAP_CONTROL_FE_MASK,
+ readl(rcc_addr)));
+ } else {
+ fe = status;
+ }
+
+ header_log_copy(cxlds, hl);
+ trace_cxl_aer_uncorrectable_error(cxlds->cxlmd, status, fe, hl);
+ writel(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK, addr);
+
+ return true;
+}
+
+pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t state)
+{
+ struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
+ struct cxl_memdev *cxlmd = cxlds->cxlmd;
+ struct device *dev = &cxlmd->dev;
+ bool ue;
+
+ /*
+ * A frozen channel indicates an impending reset which is fatal to
+ * CXL.mem operation, and will likely crash the system. On the off
+ * chance the situation is recoverable dump the status of the RAS
+ * capability registers and bounce the active state of the memdev.
+ */
+ ue = cxl_report_and_clear(cxlds);
+
+ switch (state) {
+ case pci_channel_io_normal:
+ if (ue) {
+ device_release_driver(dev);
+ return PCI_ERS_RESULT_NEED_RESET;
+ }
+ return PCI_ERS_RESULT_CAN_RECOVER;
+ case pci_channel_io_frozen:
+ dev_warn(&pdev->dev,
+ "%s: frozen state error detected, disable CXL.mem\n",
+ dev_name(dev));
+ device_release_driver(dev);
+ return PCI_ERS_RESULT_NEED_RESET;
+ case pci_channel_io_perm_failure:
+ dev_warn(&pdev->dev,
+ "failure state error detected, request disconnect\n");
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+ return PCI_ERS_RESULT_NEED_RESET;
+}
+EXPORT_SYMBOL_NS_GPL(cxl_error_detected, CXL);
diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
index b631a0520456..8ee6b6e2e2a4 100644
--- a/drivers/cxl/core/port.c
+++ b/drivers/cxl/core/port.c
@@ -38,7 +38,7 @@ static ssize_t devtype_show(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR_RO(devtype);
-static int cxl_device_id(struct device *dev)
+static int cxl_device_id(const struct device *dev)
{
if (dev->type == &cxl_nvdimm_bridge_type)
return CXL_DEVICE_NVDIMM_BRIDGE;
@@ -46,6 +46,8 @@ static int cxl_device_id(struct device *dev)
return CXL_DEVICE_NVDIMM;
if (dev->type == CXL_PMEM_REGION_TYPE())
return CXL_DEVICE_PMEM_REGION;
+ if (dev->type == CXL_DAX_REGION_TYPE())
+ return CXL_DEVICE_DAX_REGION;
if (is_cxl_port(dev)) {
if (is_cxl_root(to_cxl_port(dev)))
return CXL_DEVICE_ROOT;
@@ -180,17 +182,7 @@ static ssize_t mode_show(struct device *dev, struct device_attribute *attr,
{
struct cxl_endpoint_decoder *cxled = to_cxl_endpoint_decoder(dev);
- switch (cxled->mode) {
- case CXL_DECODER_RAM:
- return sysfs_emit(buf, "ram\n");
- case CXL_DECODER_PMEM:
- return sysfs_emit(buf, "pmem\n");
- case CXL_DECODER_NONE:
- return sysfs_emit(buf, "none\n");
- case CXL_DECODER_MIXED:
- default:
- return sysfs_emit(buf, "mixed\n");
- }
+ return sysfs_emit(buf, "%s\n", cxl_decoder_mode_name(cxled->mode));
}
static ssize_t mode_store(struct device *dev, struct device_attribute *attr,
@@ -304,6 +296,7 @@ static struct attribute *cxl_decoder_root_attrs[] = {
&dev_attr_cap_type3.attr,
&dev_attr_target_list.attr,
SET_CXL_REGION_ATTR(create_pmem_region)
+ SET_CXL_REGION_ATTR(create_ram_region)
SET_CXL_REGION_ATTR(delete_region)
NULL,
};
@@ -315,6 +308,13 @@ static bool can_create_pmem(struct cxl_root_decoder *cxlrd)
return (cxlrd->cxlsd.cxld.flags & flags) == flags;
}
+static bool can_create_ram(struct cxl_root_decoder *cxlrd)
+{
+ unsigned long flags = CXL_DECODER_F_TYPE3 | CXL_DECODER_F_RAM;
+
+ return (cxlrd->cxlsd.cxld.flags & flags) == flags;
+}
+
static umode_t cxl_root_decoder_visible(struct kobject *kobj, struct attribute *a, int n)
{
struct device *dev = kobj_to_dev(kobj);
@@ -323,7 +323,11 @@ static umode_t cxl_root_decoder_visible(struct kobject *kobj, struct attribute *
if (a == CXL_REGION_ATTR(create_pmem_region) && !can_create_pmem(cxlrd))
return 0;
- if (a == CXL_REGION_ATTR(delete_region) && !can_create_pmem(cxlrd))
+ if (a == CXL_REGION_ATTR(create_ram_region) && !can_create_ram(cxlrd))
+ return 0;
+
+ if (a == CXL_REGION_ATTR(delete_region) &&
+ !(can_create_pmem(cxlrd) || can_create_ram(cxlrd)))
return 0;
return a->mode;
@@ -444,6 +448,7 @@ bool is_endpoint_decoder(struct device *dev)
{
return dev->type == &cxl_decoder_endpoint_type;
}
+EXPORT_SYMBOL_NS_GPL(is_endpoint_decoder, CXL);
bool is_root_decoder(struct device *dev)
{
@@ -455,6 +460,7 @@ bool is_switch_decoder(struct device *dev)
{
return is_root_decoder(dev) || dev->type == &cxl_decoder_switch_type;
}
+EXPORT_SYMBOL_NS_GPL(is_switch_decoder, CXL);
struct cxl_decoder *to_cxl_decoder(struct device *dev)
{
@@ -482,6 +488,7 @@ struct cxl_switch_decoder *to_cxl_switch_decoder(struct device *dev)
return NULL;
return container_of(dev, struct cxl_switch_decoder, cxld.dev);
}
+EXPORT_SYMBOL_NS_GPL(to_cxl_switch_decoder, CXL);
static void cxl_ep_release(struct cxl_ep *ep)
{
@@ -523,13 +530,13 @@ static const struct device_type cxl_port_type = {
.groups = cxl_port_attribute_groups,
};
-bool is_cxl_port(struct device *dev)
+bool is_cxl_port(const struct device *dev)
{
return dev->type == &cxl_port_type;
}
EXPORT_SYMBOL_NS_GPL(is_cxl_port, CXL);
-struct cxl_port *to_cxl_port(struct device *dev)
+struct cxl_port *to_cxl_port(const struct device *dev)
{
if (dev_WARN_ONCE(dev, dev->type != &cxl_port_type,
"not a cxl_port device\n"))
@@ -583,6 +590,29 @@ static int devm_cxl_link_uport(struct device *host, struct cxl_port *port)
return devm_add_action_or_reset(host, cxl_unlink_uport, port);
}
+static void cxl_unlink_parent_dport(void *_port)
+{
+ struct cxl_port *port = _port;
+
+ sysfs_remove_link(&port->dev.kobj, "parent_dport");
+}
+
+static int devm_cxl_link_parent_dport(struct device *host,
+ struct cxl_port *port,
+ struct cxl_dport *parent_dport)
+{
+ int rc;
+
+ if (!parent_dport)
+ return 0;
+
+ rc = sysfs_create_link(&port->dev.kobj, &parent_dport->dport->kobj,
+ "parent_dport");
+ if (rc)
+ return rc;
+ return devm_add_action_or_reset(host, cxl_unlink_parent_dport, port);
+}
+
static struct lock_class_key cxl_port_key;
static struct cxl_port *cxl_port_alloc(struct device *uport,
@@ -692,6 +722,10 @@ static struct cxl_port *__devm_cxl_add_port(struct device *host,
if (rc)
return ERR_PTR(rc);
+ rc = devm_cxl_link_parent_dport(host, port, parent_dport);
+ if (rc)
+ return ERR_PTR(rc);
+
return port;
err:
@@ -1137,7 +1171,7 @@ static struct cxl_port *find_cxl_port_at(struct cxl_port *parent_port,
}
/*
- * All users of grandparent() are using it to walk PCIe-like swich port
+ * All users of grandparent() are using it to walk PCIe-like switch port
* hierarchy. A PCIe switch is comprised of a bridge device representing the
* upstream switch port and N bridges representing downstream switch ports. When
* bridges stack the grand-parent of a downstream switch port is another
@@ -1164,6 +1198,7 @@ static void delete_endpoint(void *data)
device_lock(parent);
if (parent->driver && !endpoint->dead) {
+ devm_release_action(parent, cxl_unlink_parent_dport, endpoint);
devm_release_action(parent, cxl_unlink_uport, endpoint);
devm_release_action(parent, unregister_port, endpoint);
}
@@ -1179,6 +1214,7 @@ int cxl_endpoint_autoremove(struct cxl_memdev *cxlmd, struct cxl_port *endpoint)
get_device(&endpoint->dev);
dev_set_drvdata(dev, endpoint);
+ cxlmd->depth = endpoint->depth;
return devm_add_action_or_reset(dev, delete_endpoint, cxlmd);
}
EXPORT_SYMBOL_NS_GPL(cxl_endpoint_autoremove, CXL);
@@ -1194,6 +1230,7 @@ EXPORT_SYMBOL_NS_GPL(cxl_endpoint_autoremove, CXL);
*/
static void delete_switch_port(struct cxl_port *port)
{
+ devm_release_action(port->dev.parent, cxl_unlink_parent_dport, port);
devm_release_action(port->dev.parent, cxl_unlink_uport, port);
devm_release_action(port->dev.parent, unregister_port, port);
}
@@ -1212,50 +1249,55 @@ static void reap_dports(struct cxl_port *port)
}
}
+struct detach_ctx {
+ struct cxl_memdev *cxlmd;
+ int depth;
+};
+
+static int port_has_memdev(struct device *dev, const void *data)
+{
+ const struct detach_ctx *ctx = data;
+ struct cxl_port *port;
+
+ if (!is_cxl_port(dev))
+ return 0;
+
+ port = to_cxl_port(dev);
+ if (port->depth != ctx->depth)
+ return 0;
+
+ return !!cxl_ep_load(port, ctx->cxlmd);
+}
+
static void cxl_detach_ep(void *data)
{
struct cxl_memdev *cxlmd = data;
- struct device *iter;
- for (iter = &cxlmd->dev; iter; iter = grandparent(iter)) {
- struct device *dport_dev = grandparent(iter);
+ for (int i = cxlmd->depth - 1; i >= 1; i--) {
struct cxl_port *port, *parent_port;
+ struct detach_ctx ctx = {
+ .cxlmd = cxlmd,
+ .depth = i,
+ };
+ struct device *dev;
struct cxl_ep *ep;
bool died = false;
- if (!dport_dev)
- break;
-
- port = find_cxl_port(dport_dev, NULL);
- if (!port)
+ dev = bus_find_device(&cxl_bus_type, NULL, &ctx,
+ port_has_memdev);
+ if (!dev)
continue;
-
- if (is_cxl_root(port)) {
- put_device(&port->dev);
- continue;
- }
+ port = to_cxl_port(dev);
parent_port = to_cxl_port(port->dev.parent);
device_lock(&parent_port->dev);
- if (!parent_port->dev.driver) {
- /*
- * The bottom-up race to delete the port lost to a
- * top-down port disable, give up here, because the
- * parent_port ->remove() will have cleaned up all
- * descendants.
- */
- device_unlock(&parent_port->dev);
- put_device(&port->dev);
- continue;
- }
-
device_lock(&port->dev);
ep = cxl_ep_load(port, cxlmd);
dev_dbg(&cxlmd->dev, "disconnect %s from %s\n",
ep ? dev_name(ep->ep) : "", dev_name(&port->dev));
cxl_ep_remove(port, ep);
if (ep && !port->dead && xa_empty(&port->endpoints) &&
- !is_cxl_root(parent_port)) {
+ !is_cxl_root(parent_port) && parent_port->dev.driver) {
/*
* This was the last ep attached to a dynamically
* enumerated port. Block new cxl_add_ep() and garbage
@@ -1591,6 +1633,7 @@ struct cxl_root_decoder *cxl_root_decoder_alloc(struct cxl_port *port,
}
cxlrd->calc_hb = calc_hb;
+ mutex_init(&cxlrd->range_lock);
cxld = &cxlsd->cxld;
cxld->dev.type = &cxl_decoder_root_type;
@@ -1826,7 +1869,7 @@ void cxl_driver_unregister(struct cxl_driver *cxl_drv)
}
EXPORT_SYMBOL_NS_GPL(cxl_driver_unregister, CXL);
-static int cxl_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int cxl_bus_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
return add_uevent_var(env, "MODALIAS=" CXL_MODALIAS_FMT,
cxl_device_id(dev));
@@ -1974,6 +2017,6 @@ static void cxl_core_exit(void)
debugfs_remove_recursive(cxl_debugfs);
}
-module_init(cxl_core_init);
+subsys_initcall(cxl_core_init);
module_exit(cxl_core_exit);
MODULE_LICENSE("GPL v2");
diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
index 940f805b1534..f29028148806 100644
--- a/drivers/cxl/core/region.c
+++ b/drivers/cxl/core/region.c
@@ -6,6 +6,7 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/uuid.h>
+#include <linux/sort.h>
#include <linux/idr.h>
#include <cxlmem.h>
#include <cxl.h>
@@ -45,7 +46,10 @@ static ssize_t uuid_show(struct device *dev, struct device_attribute *attr,
rc = down_read_interruptible(&cxl_region_rwsem);
if (rc)
return rc;
- rc = sysfs_emit(buf, "%pUb\n", &p->uuid);
+ if (cxlr->mode != CXL_DECODER_PMEM)
+ rc = sysfs_emit(buf, "\n");
+ else
+ rc = sysfs_emit(buf, "%pUb\n", &p->uuid);
up_read(&cxl_region_rwsem);
return rc;
@@ -157,6 +161,22 @@ static int cxl_region_decode_reset(struct cxl_region *cxlr, int count)
return 0;
}
+static int commit_decoder(struct cxl_decoder *cxld)
+{
+ struct cxl_switch_decoder *cxlsd = NULL;
+
+ if (cxld->commit)
+ return cxld->commit(cxld);
+
+ if (is_switch_decoder(&cxld->dev))
+ cxlsd = to_cxl_switch_decoder(&cxld->dev);
+
+ if (dev_WARN_ONCE(&cxld->dev, !cxlsd || cxlsd->nr_targets > 1,
+ "->commit() is required\n"))
+ return -ENXIO;
+ return 0;
+}
+
static int cxl_region_decode_commit(struct cxl_region *cxlr)
{
struct cxl_region_params *p = &cxlr->params;
@@ -175,8 +195,7 @@ static int cxl_region_decode_commit(struct cxl_region *cxlr)
iter = to_cxl_port(iter->dev.parent)) {
cxl_rr = cxl_rr_load(iter, cxlr);
cxld = cxl_rr->decoder;
- if (cxld->commit)
- rc = cxld->commit(cxld);
+ rc = commit_decoder(cxld);
if (rc)
break;
}
@@ -287,8 +306,12 @@ static umode_t cxl_region_visible(struct kobject *kobj, struct attribute *a,
struct device *dev = kobj_to_dev(kobj);
struct cxl_region *cxlr = to_cxl_region(dev);
+ /*
+ * Support tooling that expects to find a 'uuid' attribute for all
+ * regions regardless of mode.
+ */
if (a == &dev_attr_uuid.attr && cxlr->mode != CXL_DECODER_PMEM)
- return 0;
+ return 0444;
return a->mode;
}
@@ -401,7 +424,7 @@ static ssize_t interleave_granularity_store(struct device *dev,
* When the host-bridge is interleaved, disallow region granularity !=
* root granularity. Regions with a granularity less than the root
* interleave result in needing multiple endpoints to support a single
- * slot in the interleave (possible to suport in the future). Regions
+ * slot in the interleave (possible to support in the future). Regions
* with a granularity greater than the root interleave result in invalid
* DPA translations (invalid to support).
*/
@@ -445,6 +468,15 @@ static ssize_t resource_show(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR_RO(resource);
+static ssize_t mode_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct cxl_region *cxlr = to_cxl_region(dev);
+
+ return sysfs_emit(buf, "%s\n", cxl_decoder_mode_name(cxlr->mode));
+}
+static DEVICE_ATTR_RO(mode);
+
static int alloc_hpa(struct cxl_region *cxlr, resource_size_t size)
{
struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(cxlr->dev.parent);
@@ -495,7 +527,12 @@ static void cxl_region_iomem_release(struct cxl_region *cxlr)
if (device_is_registered(&cxlr->dev))
lockdep_assert_held_write(&cxl_region_rwsem);
if (p->res) {
- remove_resource(p->res);
+ /*
+ * Autodiscovered regions may not have been able to insert their
+ * resource.
+ */
+ if (p->res->parent)
+ remove_resource(p->res);
kfree(p->res);
p->res = NULL;
}
@@ -572,6 +609,7 @@ static struct attribute *cxl_region_attrs[] = {
&dev_attr_interleave_granularity.attr,
&dev_attr_resource.attr,
&dev_attr_size.attr,
+ &dev_attr_mode.attr,
NULL,
};
@@ -1075,12 +1113,35 @@ static int cxl_port_setup_targets(struct cxl_port *port,
return rc;
}
- cxld->interleave_ways = iw;
- cxld->interleave_granularity = ig;
- cxld->hpa_range = (struct range) {
- .start = p->res->start,
- .end = p->res->end,
- };
+ if (test_bit(CXL_REGION_F_AUTO, &cxlr->flags)) {
+ if (cxld->interleave_ways != iw ||
+ cxld->interleave_granularity != ig ||
+ cxld->hpa_range.start != p->res->start ||
+ cxld->hpa_range.end != p->res->end ||
+ ((cxld->flags & CXL_DECODER_F_ENABLE) == 0)) {
+ dev_err(&cxlr->dev,
+ "%s:%s %s expected iw: %d ig: %d %pr\n",
+ dev_name(port->uport), dev_name(&port->dev),
+ __func__, iw, ig, p->res);
+ dev_err(&cxlr->dev,
+ "%s:%s %s got iw: %d ig: %d state: %s %#llx:%#llx\n",
+ dev_name(port->uport), dev_name(&port->dev),
+ __func__, cxld->interleave_ways,
+ cxld->interleave_granularity,
+ (cxld->flags & CXL_DECODER_F_ENABLE) ?
+ "enabled" :
+ "disabled",
+ cxld->hpa_range.start, cxld->hpa_range.end);
+ return -ENXIO;
+ }
+ } else {
+ cxld->interleave_ways = iw;
+ cxld->interleave_granularity = ig;
+ cxld->hpa_range = (struct range) {
+ .start = p->res->start,
+ .end = p->res->end,
+ };
+ }
dev_dbg(&cxlr->dev, "%s:%s iw: %d ig: %d\n", dev_name(port->uport),
dev_name(&port->dev), iw, ig);
add_target:
@@ -1091,7 +1152,17 @@ add_target:
dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev), pos);
return -ENXIO;
}
- cxlsd->target[cxl_rr->nr_targets_set] = ep->dport;
+ if (test_bit(CXL_REGION_F_AUTO, &cxlr->flags)) {
+ if (cxlsd->target[cxl_rr->nr_targets_set] != ep->dport) {
+ dev_dbg(&cxlr->dev, "%s:%s: %s expected %s at %d\n",
+ dev_name(port->uport), dev_name(&port->dev),
+ dev_name(&cxlsd->cxld.dev),
+ dev_name(ep->dport->dport),
+ cxl_rr->nr_targets_set);
+ return -ENXIO;
+ }
+ } else
+ cxlsd->target[cxl_rr->nr_targets_set] = ep->dport;
inc = 1;
out_target_set:
cxl_rr->nr_targets_set += inc;
@@ -1133,6 +1204,13 @@ static void cxl_region_teardown_targets(struct cxl_region *cxlr)
struct cxl_ep *ep;
int i;
+ /*
+ * In the auto-discovery case skip automatic teardown since the
+ * address space is already active
+ */
+ if (test_bit(CXL_REGION_F_AUTO, &cxlr->flags))
+ return;
+
for (i = 0; i < p->nr_targets; i++) {
cxled = p->targets[i];
cxlmd = cxled_to_memdev(cxled);
@@ -1165,8 +1243,8 @@ static int cxl_region_setup_targets(struct cxl_region *cxlr)
iter = to_cxl_port(iter->dev.parent);
/*
- * Descend the topology tree programming targets while
- * looking for conflicts.
+ * Descend the topology tree programming / validating
+ * targets while looking for conflicts.
*/
for (ep = cxl_ep_load(iter, cxlmd); iter;
iter = ep->next, ep = cxl_ep_load(iter, cxlmd)) {
@@ -1181,29 +1259,13 @@ static int cxl_region_setup_targets(struct cxl_region *cxlr)
return 0;
}
-static int cxl_region_attach(struct cxl_region *cxlr,
- struct cxl_endpoint_decoder *cxled, int pos)
+static int cxl_region_validate_position(struct cxl_region *cxlr,
+ struct cxl_endpoint_decoder *cxled,
+ int pos)
{
- struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(cxlr->dev.parent);
struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
- struct cxl_port *ep_port, *root_port, *iter;
struct cxl_region_params *p = &cxlr->params;
- struct cxl_dport *dport;
- int i, rc = -ENXIO;
-
- if (cxled->mode == CXL_DECODER_DEAD) {
- dev_dbg(&cxlr->dev, "%s dead\n", dev_name(&cxled->cxld.dev));
- return -ENODEV;
- }
-
- /* all full of members, or interleave config not established? */
- if (p->state > CXL_CONFIG_INTERLEAVE_ACTIVE) {
- dev_dbg(&cxlr->dev, "region already active\n");
- return -EBUSY;
- } else if (p->state < CXL_CONFIG_INTERLEAVE_ACTIVE) {
- dev_dbg(&cxlr->dev, "interleave config missing\n");
- return -ENXIO;
- }
+ int i;
if (pos < 0 || pos >= p->interleave_ways) {
dev_dbg(&cxlr->dev, "position %d out of range %d\n", pos,
@@ -1242,6 +1304,256 @@ static int cxl_region_attach(struct cxl_region *cxlr,
}
}
+ return 0;
+}
+
+static int cxl_region_attach_position(struct cxl_region *cxlr,
+ struct cxl_root_decoder *cxlrd,
+ struct cxl_endpoint_decoder *cxled,
+ const struct cxl_dport *dport, int pos)
+{
+ struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
+ struct cxl_port *iter;
+ int rc;
+
+ if (cxlrd->calc_hb(cxlrd, pos) != dport) {
+ dev_dbg(&cxlr->dev, "%s:%s invalid target position for %s\n",
+ dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev),
+ dev_name(&cxlrd->cxlsd.cxld.dev));
+ return -ENXIO;
+ }
+
+ for (iter = cxled_to_port(cxled); !is_cxl_root(iter);
+ iter = to_cxl_port(iter->dev.parent)) {
+ rc = cxl_port_attach_region(iter, cxlr, cxled, pos);
+ if (rc)
+ goto err;
+ }
+
+ return 0;
+
+err:
+ for (iter = cxled_to_port(cxled); !is_cxl_root(iter);
+ iter = to_cxl_port(iter->dev.parent))
+ cxl_port_detach_region(iter, cxlr, cxled);
+ return rc;
+}
+
+static int cxl_region_attach_auto(struct cxl_region *cxlr,
+ struct cxl_endpoint_decoder *cxled, int pos)
+{
+ struct cxl_region_params *p = &cxlr->params;
+
+ if (cxled->state != CXL_DECODER_STATE_AUTO) {
+ dev_err(&cxlr->dev,
+ "%s: unable to add decoder to autodetected region\n",
+ dev_name(&cxled->cxld.dev));
+ return -EINVAL;
+ }
+
+ if (pos >= 0) {
+ dev_dbg(&cxlr->dev, "%s: expected auto position, not %d\n",
+ dev_name(&cxled->cxld.dev), pos);
+ return -EINVAL;
+ }
+
+ if (p->nr_targets >= p->interleave_ways) {
+ dev_err(&cxlr->dev, "%s: no more target slots available\n",
+ dev_name(&cxled->cxld.dev));
+ return -ENXIO;
+ }
+
+ /*
+ * Temporarily record the endpoint decoder into the target array. Yes,
+ * this means that userspace can view devices in the wrong position
+ * before the region activates, and must be careful to understand when
+ * it might be racing region autodiscovery.
+ */
+ pos = p->nr_targets;
+ p->targets[pos] = cxled;
+ cxled->pos = pos;
+ p->nr_targets++;
+
+ return 0;
+}
+
+static struct cxl_port *next_port(struct cxl_port *port)
+{
+ if (!port->parent_dport)
+ return NULL;
+ return port->parent_dport->port;
+}
+
+static int decoder_match_range(struct device *dev, void *data)
+{
+ struct cxl_endpoint_decoder *cxled = data;
+ struct cxl_switch_decoder *cxlsd;
+
+ if (!is_switch_decoder(dev))
+ return 0;
+
+ cxlsd = to_cxl_switch_decoder(dev);
+ return range_contains(&cxlsd->cxld.hpa_range, &cxled->cxld.hpa_range);
+}
+
+static void find_positions(const struct cxl_switch_decoder *cxlsd,
+ const struct cxl_port *iter_a,
+ const struct cxl_port *iter_b, int *a_pos,
+ int *b_pos)
+{
+ int i;
+
+ for (i = 0, *a_pos = -1, *b_pos = -1; i < cxlsd->nr_targets; i++) {
+ if (cxlsd->target[i] == iter_a->parent_dport)
+ *a_pos = i;
+ else if (cxlsd->target[i] == iter_b->parent_dport)
+ *b_pos = i;
+ if (*a_pos >= 0 && *b_pos >= 0)
+ break;
+ }
+}
+
+static int cmp_decode_pos(const void *a, const void *b)
+{
+ struct cxl_endpoint_decoder *cxled_a = *(typeof(cxled_a) *)a;
+ struct cxl_endpoint_decoder *cxled_b = *(typeof(cxled_b) *)b;
+ struct cxl_memdev *cxlmd_a = cxled_to_memdev(cxled_a);
+ struct cxl_memdev *cxlmd_b = cxled_to_memdev(cxled_b);
+ struct cxl_port *port_a = cxled_to_port(cxled_a);
+ struct cxl_port *port_b = cxled_to_port(cxled_b);
+ struct cxl_port *iter_a, *iter_b, *port = NULL;
+ struct cxl_switch_decoder *cxlsd;
+ struct device *dev;
+ int a_pos, b_pos;
+ unsigned int seq;
+
+ /* Exit early if any prior sorting failed */
+ if (cxled_a->pos < 0 || cxled_b->pos < 0)
+ return 0;
+
+ /*
+ * Walk up the hierarchy to find a shared port, find the decoder that
+ * maps the range, compare the relative position of those dport
+ * mappings.
+ */
+ for (iter_a = port_a; iter_a; iter_a = next_port(iter_a)) {
+ struct cxl_port *next_a, *next_b;
+
+ next_a = next_port(iter_a);
+ if (!next_a)
+ break;
+
+ for (iter_b = port_b; iter_b; iter_b = next_port(iter_b)) {
+ next_b = next_port(iter_b);
+ if (next_a != next_b)
+ continue;
+ port = next_a;
+ break;
+ }
+
+ if (port)
+ break;
+ }
+
+ if (!port) {
+ dev_err(cxlmd_a->dev.parent,
+ "failed to find shared port with %s\n",
+ dev_name(cxlmd_b->dev.parent));
+ goto err;
+ }
+
+ dev = device_find_child(&port->dev, cxled_a, decoder_match_range);
+ if (!dev) {
+ struct range *range = &cxled_a->cxld.hpa_range;
+
+ dev_err(port->uport,
+ "failed to find decoder that maps %#llx-%#llx\n",
+ range->start, range->end);
+ goto err;
+ }
+
+ cxlsd = to_cxl_switch_decoder(dev);
+ do {
+ seq = read_seqbegin(&cxlsd->target_lock);
+ find_positions(cxlsd, iter_a, iter_b, &a_pos, &b_pos);
+ } while (read_seqretry(&cxlsd->target_lock, seq));
+
+ put_device(dev);
+
+ if (a_pos < 0 || b_pos < 0) {
+ dev_err(port->uport,
+ "failed to find shared decoder for %s and %s\n",
+ dev_name(cxlmd_a->dev.parent),
+ dev_name(cxlmd_b->dev.parent));
+ goto err;
+ }
+
+ dev_dbg(port->uport, "%s comes %s %s\n", dev_name(cxlmd_a->dev.parent),
+ a_pos - b_pos < 0 ? "before" : "after",
+ dev_name(cxlmd_b->dev.parent));
+
+ return a_pos - b_pos;
+err:
+ cxled_a->pos = -1;
+ return 0;
+}
+
+static int cxl_region_sort_targets(struct cxl_region *cxlr)
+{
+ struct cxl_region_params *p = &cxlr->params;
+ int i, rc = 0;
+
+ sort(p->targets, p->nr_targets, sizeof(p->targets[0]), cmp_decode_pos,
+ NULL);
+
+ for (i = 0; i < p->nr_targets; i++) {
+ struct cxl_endpoint_decoder *cxled = p->targets[i];
+
+ /*
+ * Record that sorting failed, but still continue to restore
+ * cxled->pos with its ->targets[] position so that follow-on
+ * code paths can reliably do p->targets[cxled->pos] to
+ * self-reference their entry.
+ */
+ if (cxled->pos < 0)
+ rc = -ENXIO;
+ cxled->pos = i;
+ }
+
+ dev_dbg(&cxlr->dev, "region sort %s\n", rc ? "failed" : "successful");
+ return rc;
+}
+
+static int cxl_region_attach(struct cxl_region *cxlr,
+ struct cxl_endpoint_decoder *cxled, int pos)
+{
+ struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(cxlr->dev.parent);
+ struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
+ struct cxl_region_params *p = &cxlr->params;
+ struct cxl_port *ep_port, *root_port;
+ struct cxl_dport *dport;
+ int rc = -ENXIO;
+
+ if (cxled->mode != cxlr->mode) {
+ dev_dbg(&cxlr->dev, "%s region mode: %d mismatch: %d\n",
+ dev_name(&cxled->cxld.dev), cxlr->mode, cxled->mode);
+ return -EINVAL;
+ }
+
+ if (cxled->mode == CXL_DECODER_DEAD) {
+ dev_dbg(&cxlr->dev, "%s dead\n", dev_name(&cxled->cxld.dev));
+ return -ENODEV;
+ }
+
+ /* all full of members, or interleave config not established? */
+ if (p->state > CXL_CONFIG_INTERLEAVE_ACTIVE) {
+ dev_dbg(&cxlr->dev, "region already active\n");
+ return -EBUSY;
+ } else if (p->state < CXL_CONFIG_INTERLEAVE_ACTIVE) {
+ dev_dbg(&cxlr->dev, "interleave config missing\n");
+ return -ENXIO;
+ }
+
ep_port = cxled_to_port(cxled);
root_port = cxlrd_to_port(cxlrd);
dport = cxl_find_dport_by_dev(root_port, ep_port->host_bridge);
@@ -1252,13 +1564,6 @@ static int cxl_region_attach(struct cxl_region *cxlr,
return -ENXIO;
}
- if (cxlrd->calc_hb(cxlrd, pos) != dport) {
- dev_dbg(&cxlr->dev, "%s:%s invalid target position for %s\n",
- dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev),
- dev_name(&cxlrd->cxlsd.cxld.dev));
- return -ENXIO;
- }
-
if (cxled->cxld.target_type != cxlr->type) {
dev_dbg(&cxlr->dev, "%s:%s type mismatch: %d vs %d\n",
dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev),
@@ -1282,13 +1587,58 @@ static int cxl_region_attach(struct cxl_region *cxlr,
return -EINVAL;
}
- for (iter = ep_port; !is_cxl_root(iter);
- iter = to_cxl_port(iter->dev.parent)) {
- rc = cxl_port_attach_region(iter, cxlr, cxled, pos);
+ if (test_bit(CXL_REGION_F_AUTO, &cxlr->flags)) {
+ int i;
+
+ rc = cxl_region_attach_auto(cxlr, cxled, pos);
if (rc)
- goto err;
+ return rc;
+
+ /* await more targets to arrive... */
+ if (p->nr_targets < p->interleave_ways)
+ return 0;
+
+ /*
+ * All targets are here, which implies all PCI enumeration that
+ * affects this region has been completed. Walk the topology to
+ * sort the devices into their relative region decode position.
+ */
+ rc = cxl_region_sort_targets(cxlr);
+ if (rc)
+ return rc;
+
+ for (i = 0; i < p->nr_targets; i++) {
+ cxled = p->targets[i];
+ ep_port = cxled_to_port(cxled);
+ dport = cxl_find_dport_by_dev(root_port,
+ ep_port->host_bridge);
+ rc = cxl_region_attach_position(cxlr, cxlrd, cxled,
+ dport, i);
+ if (rc)
+ return rc;
+ }
+
+ rc = cxl_region_setup_targets(cxlr);
+ if (rc)
+ return rc;
+
+ /*
+ * If target setup succeeds in the autodiscovery case
+ * then the region is already committed.
+ */
+ p->state = CXL_CONFIG_COMMIT;
+
+ return 0;
}
+ rc = cxl_region_validate_position(cxlr, cxled, pos);
+ if (rc)
+ return rc;
+
+ rc = cxl_region_attach_position(cxlr, cxlrd, cxled, dport, pos);
+ if (rc)
+ return rc;
+
p->targets[pos] = cxled;
cxled->pos = pos;
p->nr_targets++;
@@ -1311,10 +1661,8 @@ static int cxl_region_attach(struct cxl_region *cxlr,
err_decrement:
p->nr_targets--;
-err:
- for (iter = ep_port; !is_cxl_root(iter);
- iter = to_cxl_port(iter->dev.parent))
- cxl_port_detach_region(iter, cxlr, cxled);
+ cxled->pos = -1;
+ p->targets[pos] = NULL;
return rc;
}
@@ -1386,31 +1734,25 @@ void cxl_decoder_kill_region(struct cxl_endpoint_decoder *cxled)
up_write(&cxl_region_rwsem);
}
-static int attach_target(struct cxl_region *cxlr, const char *decoder, int pos)
+static int attach_target(struct cxl_region *cxlr,
+ struct cxl_endpoint_decoder *cxled, int pos,
+ unsigned int state)
{
- struct device *dev;
- int rc;
-
- dev = bus_find_device_by_name(&cxl_bus_type, NULL, decoder);
- if (!dev)
- return -ENODEV;
-
- if (!is_endpoint_decoder(dev)) {
- put_device(dev);
- return -EINVAL;
- }
+ int rc = 0;
- rc = down_write_killable(&cxl_region_rwsem);
+ if (state == TASK_INTERRUPTIBLE)
+ rc = down_write_killable(&cxl_region_rwsem);
+ else
+ down_write(&cxl_region_rwsem);
if (rc)
- goto out;
+ return rc;
+
down_read(&cxl_dpa_rwsem);
- rc = cxl_region_attach(cxlr, to_cxl_endpoint_decoder(dev), pos);
+ rc = cxl_region_attach(cxlr, cxled, pos);
if (rc == 0)
set_bit(CXL_REGION_F_INCOHERENT, &cxlr->flags);
up_read(&cxl_dpa_rwsem);
up_write(&cxl_region_rwsem);
-out:
- put_device(dev);
return rc;
}
@@ -1448,8 +1790,23 @@ static size_t store_targetN(struct cxl_region *cxlr, const char *buf, int pos,
if (sysfs_streq(buf, "\n"))
rc = detach_target(cxlr, pos);
- else
- rc = attach_target(cxlr, buf, pos);
+ else {
+ struct device *dev;
+
+ dev = bus_find_device_by_name(&cxl_bus_type, NULL, buf);
+ if (!dev)
+ return -ENODEV;
+
+ if (!is_endpoint_decoder(dev)) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ rc = attach_target(cxlr, to_cxl_endpoint_decoder(dev), pos,
+ TASK_INTERRUPTIBLE);
+out:
+ put_device(dev);
+ }
if (rc < 0)
return rc;
@@ -1653,6 +2010,15 @@ static struct cxl_region *devm_cxl_add_region(struct cxl_root_decoder *cxlrd,
struct device *dev;
int rc;
+ switch (mode) {
+ case CXL_DECODER_RAM:
+ case CXL_DECODER_PMEM:
+ break;
+ default:
+ dev_err(&cxlrd->cxlsd.cxld.dev, "unsupported mode %d\n", mode);
+ return ERR_PTR(-EINVAL);
+ }
+
cxlr = cxl_region_alloc(cxlrd, id);
if (IS_ERR(cxlr))
return cxlr;
@@ -1681,12 +2047,38 @@ err:
return ERR_PTR(rc);
}
+static ssize_t __create_region_show(struct cxl_root_decoder *cxlrd, char *buf)
+{
+ return sysfs_emit(buf, "region%u\n", atomic_read(&cxlrd->region_id));
+}
+
static ssize_t create_pmem_region_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev);
+ return __create_region_show(to_cxl_root_decoder(dev), buf);
+}
- return sysfs_emit(buf, "region%u\n", atomic_read(&cxlrd->region_id));
+static ssize_t create_ram_region_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return __create_region_show(to_cxl_root_decoder(dev), buf);
+}
+
+static struct cxl_region *__create_region(struct cxl_root_decoder *cxlrd,
+ enum cxl_decoder_mode mode, int id)
+{
+ int rc;
+
+ rc = memregion_alloc(GFP_KERNEL);
+ if (rc < 0)
+ return ERR_PTR(rc);
+
+ if (atomic_cmpxchg(&cxlrd->region_id, id, rc) != id) {
+ memregion_free(rc);
+ return ERR_PTR(-EBUSY);
+ }
+
+ return devm_cxl_add_region(cxlrd, id, mode, CXL_DECODER_EXPANDER);
}
static ssize_t create_pmem_region_store(struct device *dev,
@@ -1695,29 +2087,39 @@ static ssize_t create_pmem_region_store(struct device *dev,
{
struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev);
struct cxl_region *cxlr;
- int id, rc;
+ int rc, id;
rc = sscanf(buf, "region%d\n", &id);
if (rc != 1)
return -EINVAL;
- rc = memregion_alloc(GFP_KERNEL);
- if (rc < 0)
- return rc;
+ cxlr = __create_region(cxlrd, CXL_DECODER_PMEM, id);
+ if (IS_ERR(cxlr))
+ return PTR_ERR(cxlr);
- if (atomic_cmpxchg(&cxlrd->region_id, id, rc) != id) {
- memregion_free(rc);
- return -EBUSY;
- }
+ return len;
+}
+DEVICE_ATTR_RW(create_pmem_region);
+
+static ssize_t create_ram_region_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev);
+ struct cxl_region *cxlr;
+ int rc, id;
+
+ rc = sscanf(buf, "region%d\n", &id);
+ if (rc != 1)
+ return -EINVAL;
- cxlr = devm_cxl_add_region(cxlrd, id, CXL_DECODER_PMEM,
- CXL_DECODER_EXPANDER);
+ cxlr = __create_region(cxlrd, CXL_DECODER_RAM, id);
if (IS_ERR(cxlr))
return PTR_ERR(cxlr);
return len;
}
-DEVICE_ATTR_RW(create_pmem_region);
+DEVICE_ATTR_RW(create_ram_region);
static ssize_t region_show(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -1878,6 +2280,75 @@ out:
return cxlr_pmem;
}
+static void cxl_dax_region_release(struct device *dev)
+{
+ struct cxl_dax_region *cxlr_dax = to_cxl_dax_region(dev);
+
+ kfree(cxlr_dax);
+}
+
+static const struct attribute_group *cxl_dax_region_attribute_groups[] = {
+ &cxl_base_attribute_group,
+ NULL,
+};
+
+const struct device_type cxl_dax_region_type = {
+ .name = "cxl_dax_region",
+ .release = cxl_dax_region_release,
+ .groups = cxl_dax_region_attribute_groups,
+};
+
+static bool is_cxl_dax_region(struct device *dev)
+{
+ return dev->type == &cxl_dax_region_type;
+}
+
+struct cxl_dax_region *to_cxl_dax_region(struct device *dev)
+{
+ if (dev_WARN_ONCE(dev, !is_cxl_dax_region(dev),
+ "not a cxl_dax_region device\n"))
+ return NULL;
+ return container_of(dev, struct cxl_dax_region, dev);
+}
+EXPORT_SYMBOL_NS_GPL(to_cxl_dax_region, CXL);
+
+static struct lock_class_key cxl_dax_region_key;
+
+static struct cxl_dax_region *cxl_dax_region_alloc(struct cxl_region *cxlr)
+{
+ struct cxl_region_params *p = &cxlr->params;
+ struct cxl_dax_region *cxlr_dax;
+ struct device *dev;
+
+ down_read(&cxl_region_rwsem);
+ if (p->state != CXL_CONFIG_COMMIT) {
+ cxlr_dax = ERR_PTR(-ENXIO);
+ goto out;
+ }
+
+ cxlr_dax = kzalloc(sizeof(*cxlr_dax), GFP_KERNEL);
+ if (!cxlr_dax) {
+ cxlr_dax = ERR_PTR(-ENOMEM);
+ goto out;
+ }
+
+ cxlr_dax->hpa_range.start = p->res->start;
+ cxlr_dax->hpa_range.end = p->res->end;
+
+ dev = &cxlr_dax->dev;
+ cxlr_dax->cxlr = cxlr;
+ device_initialize(dev);
+ lockdep_set_class(&dev->mutex, &cxl_dax_region_key);
+ device_set_pm_not_required(dev);
+ dev->parent = &cxlr->dev;
+ dev->bus = &cxl_bus_type;
+ dev->type = &cxl_dax_region_type;
+out:
+ up_read(&cxl_region_rwsem);
+
+ return cxlr_dax;
+}
+
static void cxlr_pmem_unregister(void *_cxlr_pmem)
{
struct cxl_pmem_region *cxlr_pmem = _cxlr_pmem;
@@ -1962,6 +2433,227 @@ err_bridge:
return rc;
}
+static void cxlr_dax_unregister(void *_cxlr_dax)
+{
+ struct cxl_dax_region *cxlr_dax = _cxlr_dax;
+
+ device_unregister(&cxlr_dax->dev);
+}
+
+static int devm_cxl_add_dax_region(struct cxl_region *cxlr)
+{
+ struct cxl_dax_region *cxlr_dax;
+ struct device *dev;
+ int rc;
+
+ cxlr_dax = cxl_dax_region_alloc(cxlr);
+ if (IS_ERR(cxlr_dax))
+ return PTR_ERR(cxlr_dax);
+
+ dev = &cxlr_dax->dev;
+ rc = dev_set_name(dev, "dax_region%d", cxlr->id);
+ if (rc)
+ goto err;
+
+ rc = device_add(dev);
+ if (rc)
+ goto err;
+
+ dev_dbg(&cxlr->dev, "%s: register %s\n", dev_name(dev->parent),
+ dev_name(dev));
+
+ return devm_add_action_or_reset(&cxlr->dev, cxlr_dax_unregister,
+ cxlr_dax);
+err:
+ put_device(dev);
+ return rc;
+}
+
+static int match_decoder_by_range(struct device *dev, void *data)
+{
+ struct range *r1, *r2 = data;
+ struct cxl_root_decoder *cxlrd;
+
+ if (!is_root_decoder(dev))
+ return 0;
+
+ cxlrd = to_cxl_root_decoder(dev);
+ r1 = &cxlrd->cxlsd.cxld.hpa_range;
+ return range_contains(r1, r2);
+}
+
+static int match_region_by_range(struct device *dev, void *data)
+{
+ struct cxl_region_params *p;
+ struct cxl_region *cxlr;
+ struct range *r = data;
+ int rc = 0;
+
+ if (!is_cxl_region(dev))
+ return 0;
+
+ cxlr = to_cxl_region(dev);
+ p = &cxlr->params;
+
+ down_read(&cxl_region_rwsem);
+ if (p->res && p->res->start == r->start && p->res->end == r->end)
+ rc = 1;
+ up_read(&cxl_region_rwsem);
+
+ return rc;
+}
+
+/* Establish an empty region covering the given HPA range */
+static struct cxl_region *construct_region(struct cxl_root_decoder *cxlrd,
+ struct cxl_endpoint_decoder *cxled)
+{
+ struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
+ struct cxl_port *port = cxlrd_to_port(cxlrd);
+ struct range *hpa = &cxled->cxld.hpa_range;
+ struct cxl_region_params *p;
+ struct cxl_region *cxlr;
+ struct resource *res;
+ int rc;
+
+ do {
+ cxlr = __create_region(cxlrd, cxled->mode,
+ atomic_read(&cxlrd->region_id));
+ } while (IS_ERR(cxlr) && PTR_ERR(cxlr) == -EBUSY);
+
+ if (IS_ERR(cxlr)) {
+ dev_err(cxlmd->dev.parent,
+ "%s:%s: %s failed assign region: %ld\n",
+ dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev),
+ __func__, PTR_ERR(cxlr));
+ return cxlr;
+ }
+
+ down_write(&cxl_region_rwsem);
+ p = &cxlr->params;
+ if (p->state >= CXL_CONFIG_INTERLEAVE_ACTIVE) {
+ dev_err(cxlmd->dev.parent,
+ "%s:%s: %s autodiscovery interrupted\n",
+ dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev),
+ __func__);
+ rc = -EBUSY;
+ goto err;
+ }
+
+ set_bit(CXL_REGION_F_AUTO, &cxlr->flags);
+
+ res = kmalloc(sizeof(*res), GFP_KERNEL);
+ if (!res) {
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ *res = DEFINE_RES_MEM_NAMED(hpa->start, range_len(hpa),
+ dev_name(&cxlr->dev));
+ rc = insert_resource(cxlrd->res, res);
+ if (rc) {
+ /*
+ * Platform-firmware may not have split resources like "System
+ * RAM" on CXL window boundaries see cxl_region_iomem_release()
+ */
+ dev_warn(cxlmd->dev.parent,
+ "%s:%s: %s %s cannot insert resource\n",
+ dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev),
+ __func__, dev_name(&cxlr->dev));
+ }
+
+ p->res = res;
+ p->interleave_ways = cxled->cxld.interleave_ways;
+ p->interleave_granularity = cxled->cxld.interleave_granularity;
+ p->state = CXL_CONFIG_INTERLEAVE_ACTIVE;
+
+ rc = sysfs_update_group(&cxlr->dev.kobj, get_cxl_region_target_group());
+ if (rc)
+ goto err;
+
+ dev_dbg(cxlmd->dev.parent, "%s:%s: %s %s res: %pr iw: %d ig: %d\n",
+ dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev), __func__,
+ dev_name(&cxlr->dev), p->res, p->interleave_ways,
+ p->interleave_granularity);
+
+ /* ...to match put_device() in cxl_add_to_region() */
+ get_device(&cxlr->dev);
+ up_write(&cxl_region_rwsem);
+
+ return cxlr;
+
+err:
+ up_write(&cxl_region_rwsem);
+ devm_release_action(port->uport, unregister_region, cxlr);
+ return ERR_PTR(rc);
+}
+
+int cxl_add_to_region(struct cxl_port *root, struct cxl_endpoint_decoder *cxled)
+{
+ struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
+ struct range *hpa = &cxled->cxld.hpa_range;
+ struct cxl_decoder *cxld = &cxled->cxld;
+ struct device *cxlrd_dev, *region_dev;
+ struct cxl_root_decoder *cxlrd;
+ struct cxl_region_params *p;
+ struct cxl_region *cxlr;
+ bool attach = false;
+ int rc;
+
+ cxlrd_dev = device_find_child(&root->dev, &cxld->hpa_range,
+ match_decoder_by_range);
+ if (!cxlrd_dev) {
+ dev_err(cxlmd->dev.parent,
+ "%s:%s no CXL window for range %#llx:%#llx\n",
+ dev_name(&cxlmd->dev), dev_name(&cxld->dev),
+ cxld->hpa_range.start, cxld->hpa_range.end);
+ return -ENXIO;
+ }
+
+ cxlrd = to_cxl_root_decoder(cxlrd_dev);
+
+ /*
+ * Ensure that if multiple threads race to construct_region() for @hpa
+ * one does the construction and the others add to that.
+ */
+ mutex_lock(&cxlrd->range_lock);
+ region_dev = device_find_child(&cxlrd->cxlsd.cxld.dev, hpa,
+ match_region_by_range);
+ if (!region_dev) {
+ cxlr = construct_region(cxlrd, cxled);
+ region_dev = &cxlr->dev;
+ } else
+ cxlr = to_cxl_region(region_dev);
+ mutex_unlock(&cxlrd->range_lock);
+
+ rc = PTR_ERR_OR_ZERO(cxlr);
+ if (rc)
+ goto out;
+
+ attach_target(cxlr, cxled, -1, TASK_UNINTERRUPTIBLE);
+
+ down_read(&cxl_region_rwsem);
+ p = &cxlr->params;
+ attach = p->state == CXL_CONFIG_COMMIT;
+ up_read(&cxl_region_rwsem);
+
+ if (attach) {
+ /*
+ * If device_attach() fails the range may still be active via
+ * the platform-firmware memory map, otherwise the driver for
+ * regions is local to this file, so driver matching can't fail.
+ */
+ if (device_attach(&cxlr->dev) < 0)
+ dev_err(&cxlr->dev, "failed to enable, range: %pr\n",
+ p->res);
+ }
+
+ put_device(region_dev);
+out:
+ put_device(cxlrd_dev);
+ return rc;
+}
+EXPORT_SYMBOL_NS_GPL(cxl_add_to_region, CXL);
+
static int cxl_region_invalidate_memregion(struct cxl_region *cxlr)
{
if (!test_bit(CXL_REGION_F_INCOHERENT, &cxlr->flags))
@@ -1969,7 +2661,7 @@ static int cxl_region_invalidate_memregion(struct cxl_region *cxlr)
if (!cpu_cache_has_invalidate_memregion()) {
if (IS_ENABLED(CONFIG_CXL_REGION_INVALIDATION_TEST)) {
- dev_warn(
+ dev_warn_once(
&cxlr->dev,
"Bypassing cpu_cache_invalidate_memregion() for testing!\n");
clear_bit(CXL_REGION_F_INCOHERENT, &cxlr->flags);
@@ -1986,6 +2678,15 @@ static int cxl_region_invalidate_memregion(struct cxl_region *cxlr)
return 0;
}
+static int is_system_ram(struct resource *res, void *arg)
+{
+ struct cxl_region *cxlr = arg;
+ struct cxl_region_params *p = &cxlr->params;
+
+ dev_dbg(&cxlr->dev, "%pr has System RAM: %pr\n", p->res, res);
+ return 1;
+}
+
static int cxl_region_probe(struct device *dev)
{
struct cxl_region *cxlr = to_cxl_region(dev);
@@ -2019,6 +2720,17 @@ out:
switch (cxlr->mode) {
case CXL_DECODER_PMEM:
return devm_cxl_add_pmem_region(cxlr);
+ case CXL_DECODER_RAM:
+ /*
+ * The region can not be manged by CXL if any portion of
+ * it is already online as 'System RAM'
+ */
+ if (walk_iomem_res_desc(IORES_DESC_NONE,
+ IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY,
+ p->res->start, p->res->end, cxlr,
+ is_system_ram) > 0)
+ return 0;
+ return devm_cxl_add_dax_region(cxlr);
default:
dev_dbg(&cxlr->dev, "unsupported region mode: %d\n",
cxlr->mode);
diff --git a/drivers/cxl/core/trace.c b/drivers/cxl/core/trace.c
new file mode 100644
index 000000000000..29ae7ce81dc5
--- /dev/null
+++ b/drivers/cxl/core/trace.c
@@ -0,0 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(c) 2022 Intel Corporation. All rights reserved. */
+
+#define CREATE_TRACE_POINTS
+#include "trace.h"
diff --git a/drivers/cxl/core/trace.h b/drivers/cxl/core/trace.h
new file mode 100644
index 000000000000..9b8d3d997834
--- /dev/null
+++ b/drivers/cxl/core/trace.h
@@ -0,0 +1,606 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2022 Intel Corporation. All rights reserved. */
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM cxl
+
+#if !defined(_CXL_EVENTS_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _CXL_EVENTS_H
+
+#include <linux/tracepoint.h>
+#include <asm-generic/unaligned.h>
+
+#include <cxl.h>
+#include <cxlmem.h>
+
+#define CXL_RAS_UC_CACHE_DATA_PARITY BIT(0)
+#define CXL_RAS_UC_CACHE_ADDR_PARITY BIT(1)
+#define CXL_RAS_UC_CACHE_BE_PARITY BIT(2)
+#define CXL_RAS_UC_CACHE_DATA_ECC BIT(3)
+#define CXL_RAS_UC_MEM_DATA_PARITY BIT(4)
+#define CXL_RAS_UC_MEM_ADDR_PARITY BIT(5)
+#define CXL_RAS_UC_MEM_BE_PARITY BIT(6)
+#define CXL_RAS_UC_MEM_DATA_ECC BIT(7)
+#define CXL_RAS_UC_REINIT_THRESH BIT(8)
+#define CXL_RAS_UC_RSVD_ENCODE BIT(9)
+#define CXL_RAS_UC_POISON BIT(10)
+#define CXL_RAS_UC_RECV_OVERFLOW BIT(11)
+#define CXL_RAS_UC_INTERNAL_ERR BIT(14)
+#define CXL_RAS_UC_IDE_TX_ERR BIT(15)
+#define CXL_RAS_UC_IDE_RX_ERR BIT(16)
+
+#define show_uc_errs(status) __print_flags(status, " | ", \
+ { CXL_RAS_UC_CACHE_DATA_PARITY, "Cache Data Parity Error" }, \
+ { CXL_RAS_UC_CACHE_ADDR_PARITY, "Cache Address Parity Error" }, \
+ { CXL_RAS_UC_CACHE_BE_PARITY, "Cache Byte Enable Parity Error" }, \
+ { CXL_RAS_UC_CACHE_DATA_ECC, "Cache Data ECC Error" }, \
+ { CXL_RAS_UC_MEM_DATA_PARITY, "Memory Data Parity Error" }, \
+ { CXL_RAS_UC_MEM_ADDR_PARITY, "Memory Address Parity Error" }, \
+ { CXL_RAS_UC_MEM_BE_PARITY, "Memory Byte Enable Parity Error" }, \
+ { CXL_RAS_UC_MEM_DATA_ECC, "Memory Data ECC Error" }, \
+ { CXL_RAS_UC_REINIT_THRESH, "REINIT Threshold Hit" }, \
+ { CXL_RAS_UC_RSVD_ENCODE, "Received Unrecognized Encoding" }, \
+ { CXL_RAS_UC_POISON, "Received Poison From Peer" }, \
+ { CXL_RAS_UC_RECV_OVERFLOW, "Receiver Overflow" }, \
+ { CXL_RAS_UC_INTERNAL_ERR, "Component Specific Error" }, \
+ { CXL_RAS_UC_IDE_TX_ERR, "IDE Tx Error" }, \
+ { CXL_RAS_UC_IDE_RX_ERR, "IDE Rx Error" } \
+)
+
+TRACE_EVENT(cxl_aer_uncorrectable_error,
+ TP_PROTO(const struct cxl_memdev *cxlmd, u32 status, u32 fe, u32 *hl),
+ TP_ARGS(cxlmd, status, fe, hl),
+ TP_STRUCT__entry(
+ __string(memdev, dev_name(&cxlmd->dev))
+ __string(host, dev_name(cxlmd->dev.parent))
+ __field(u64, serial)
+ __field(u32, status)
+ __field(u32, first_error)
+ __array(u32, header_log, CXL_HEADERLOG_SIZE_U32)
+ ),
+ TP_fast_assign(
+ __assign_str(memdev, dev_name(&cxlmd->dev));
+ __assign_str(host, dev_name(cxlmd->dev.parent));
+ __entry->serial = cxlmd->cxlds->serial;
+ __entry->status = status;
+ __entry->first_error = fe;
+ /*
+ * Embed the 512B headerlog data for user app retrieval and
+ * parsing, but no need to print this in the trace buffer.
+ */
+ memcpy(__entry->header_log, hl, CXL_HEADERLOG_SIZE);
+ ),
+ TP_printk("memdev=%s host=%s serial=%lld: status: '%s' first_error: '%s'",
+ __get_str(memdev), __get_str(host), __entry->serial,
+ show_uc_errs(__entry->status),
+ show_uc_errs(__entry->first_error)
+ )
+);
+
+#define CXL_RAS_CE_CACHE_DATA_ECC BIT(0)
+#define CXL_RAS_CE_MEM_DATA_ECC BIT(1)
+#define CXL_RAS_CE_CRC_THRESH BIT(2)
+#define CLX_RAS_CE_RETRY_THRESH BIT(3)
+#define CXL_RAS_CE_CACHE_POISON BIT(4)
+#define CXL_RAS_CE_MEM_POISON BIT(5)
+#define CXL_RAS_CE_PHYS_LAYER_ERR BIT(6)
+
+#define show_ce_errs(status) __print_flags(status, " | ", \
+ { CXL_RAS_CE_CACHE_DATA_ECC, "Cache Data ECC Error" }, \
+ { CXL_RAS_CE_MEM_DATA_ECC, "Memory Data ECC Error" }, \
+ { CXL_RAS_CE_CRC_THRESH, "CRC Threshold Hit" }, \
+ { CLX_RAS_CE_RETRY_THRESH, "Retry Threshold" }, \
+ { CXL_RAS_CE_CACHE_POISON, "Received Cache Poison From Peer" }, \
+ { CXL_RAS_CE_MEM_POISON, "Received Memory Poison From Peer" }, \
+ { CXL_RAS_CE_PHYS_LAYER_ERR, "Received Error From Physical Layer" } \
+)
+
+TRACE_EVENT(cxl_aer_correctable_error,
+ TP_PROTO(const struct cxl_memdev *cxlmd, u32 status),
+ TP_ARGS(cxlmd, status),
+ TP_STRUCT__entry(
+ __string(memdev, dev_name(&cxlmd->dev))
+ __string(host, dev_name(cxlmd->dev.parent))
+ __field(u64, serial)
+ __field(u32, status)
+ ),
+ TP_fast_assign(
+ __assign_str(memdev, dev_name(&cxlmd->dev));
+ __assign_str(host, dev_name(cxlmd->dev.parent));
+ __entry->serial = cxlmd->cxlds->serial;
+ __entry->status = status;
+ ),
+ TP_printk("memdev=%s host=%s serial=%lld: status: '%s'",
+ __get_str(memdev), __get_str(host), __entry->serial,
+ show_ce_errs(__entry->status)
+ )
+);
+
+#define cxl_event_log_type_str(type) \
+ __print_symbolic(type, \
+ { CXL_EVENT_TYPE_INFO, "Informational" }, \
+ { CXL_EVENT_TYPE_WARN, "Warning" }, \
+ { CXL_EVENT_TYPE_FAIL, "Failure" }, \
+ { CXL_EVENT_TYPE_FATAL, "Fatal" })
+
+TRACE_EVENT(cxl_overflow,
+
+ TP_PROTO(const struct cxl_memdev *cxlmd, enum cxl_event_log_type log,
+ struct cxl_get_event_payload *payload),
+
+ TP_ARGS(cxlmd, log, payload),
+
+ TP_STRUCT__entry(
+ __string(memdev, dev_name(&cxlmd->dev))
+ __string(host, dev_name(cxlmd->dev.parent))
+ __field(int, log)
+ __field(u64, serial)
+ __field(u64, first_ts)
+ __field(u64, last_ts)
+ __field(u16, count)
+ ),
+
+ TP_fast_assign(
+ __assign_str(memdev, dev_name(&cxlmd->dev));
+ __assign_str(host, dev_name(cxlmd->dev.parent));
+ __entry->serial = cxlmd->cxlds->serial;
+ __entry->log = log;
+ __entry->count = le16_to_cpu(payload->overflow_err_count);
+ __entry->first_ts = le64_to_cpu(payload->first_overflow_timestamp);
+ __entry->last_ts = le64_to_cpu(payload->last_overflow_timestamp);
+ ),
+
+ TP_printk("memdev=%s host=%s serial=%lld: log=%s : %u records from %llu to %llu",
+ __get_str(memdev), __get_str(host), __entry->serial,
+ cxl_event_log_type_str(__entry->log), __entry->count,
+ __entry->first_ts, __entry->last_ts)
+
+);
+
+/*
+ * Common Event Record Format
+ * CXL 3.0 section 8.2.9.2.1; Table 8-42
+ */
+#define CXL_EVENT_RECORD_FLAG_PERMANENT BIT(2)
+#define CXL_EVENT_RECORD_FLAG_MAINT_NEEDED BIT(3)
+#define CXL_EVENT_RECORD_FLAG_PERF_DEGRADED BIT(4)
+#define CXL_EVENT_RECORD_FLAG_HW_REPLACE BIT(5)
+#define show_hdr_flags(flags) __print_flags(flags, " | ", \
+ { CXL_EVENT_RECORD_FLAG_PERMANENT, "PERMANENT_CONDITION" }, \
+ { CXL_EVENT_RECORD_FLAG_MAINT_NEEDED, "MAINTENANCE_NEEDED" }, \
+ { CXL_EVENT_RECORD_FLAG_PERF_DEGRADED, "PERFORMANCE_DEGRADED" }, \
+ { CXL_EVENT_RECORD_FLAG_HW_REPLACE, "HARDWARE_REPLACEMENT_NEEDED" } \
+)
+
+/*
+ * Define macros for the common header of each CXL event.
+ *
+ * Tracepoints using these macros must do 3 things:
+ *
+ * 1) Add CXL_EVT_TP_entry to TP_STRUCT__entry
+ * 2) Use CXL_EVT_TP_fast_assign within TP_fast_assign;
+ * pass the dev, log, and CXL event header
+ * 3) Use CXL_EVT_TP_printk() instead of TP_printk()
+ *
+ * See the generic_event tracepoint as an example.
+ */
+#define CXL_EVT_TP_entry \
+ __string(memdev, dev_name(&cxlmd->dev)) \
+ __string(host, dev_name(cxlmd->dev.parent)) \
+ __field(int, log) \
+ __field_struct(uuid_t, hdr_uuid) \
+ __field(u64, serial) \
+ __field(u32, hdr_flags) \
+ __field(u16, hdr_handle) \
+ __field(u16, hdr_related_handle) \
+ __field(u64, hdr_timestamp) \
+ __field(u8, hdr_length) \
+ __field(u8, hdr_maint_op_class)
+
+#define CXL_EVT_TP_fast_assign(cxlmd, l, hdr) \
+ __assign_str(memdev, dev_name(&(cxlmd)->dev)); \
+ __assign_str(host, dev_name((cxlmd)->dev.parent)); \
+ __entry->log = (l); \
+ __entry->serial = (cxlmd)->cxlds->serial; \
+ memcpy(&__entry->hdr_uuid, &(hdr).id, sizeof(uuid_t)); \
+ __entry->hdr_length = (hdr).length; \
+ __entry->hdr_flags = get_unaligned_le24((hdr).flags); \
+ __entry->hdr_handle = le16_to_cpu((hdr).handle); \
+ __entry->hdr_related_handle = le16_to_cpu((hdr).related_handle); \
+ __entry->hdr_timestamp = le64_to_cpu((hdr).timestamp); \
+ __entry->hdr_maint_op_class = (hdr).maint_op_class
+
+#define CXL_EVT_TP_printk(fmt, ...) \
+ TP_printk("memdev=%s host=%s serial=%lld log=%s : time=%llu uuid=%pUb " \
+ "len=%d flags='%s' handle=%x related_handle=%x " \
+ "maint_op_class=%u : " fmt, \
+ __get_str(memdev), __get_str(host), __entry->serial, \
+ cxl_event_log_type_str(__entry->log), \
+ __entry->hdr_timestamp, &__entry->hdr_uuid, __entry->hdr_length,\
+ show_hdr_flags(__entry->hdr_flags), __entry->hdr_handle, \
+ __entry->hdr_related_handle, __entry->hdr_maint_op_class, \
+ ##__VA_ARGS__)
+
+TRACE_EVENT(cxl_generic_event,
+
+ TP_PROTO(const struct cxl_memdev *cxlmd, enum cxl_event_log_type log,
+ struct cxl_event_record_raw *rec),
+
+ TP_ARGS(cxlmd, log, rec),
+
+ TP_STRUCT__entry(
+ CXL_EVT_TP_entry
+ __array(u8, data, CXL_EVENT_RECORD_DATA_LENGTH)
+ ),
+
+ TP_fast_assign(
+ CXL_EVT_TP_fast_assign(cxlmd, log, rec->hdr);
+ memcpy(__entry->data, &rec->data, CXL_EVENT_RECORD_DATA_LENGTH);
+ ),
+
+ CXL_EVT_TP_printk("%s",
+ __print_hex(__entry->data, CXL_EVENT_RECORD_DATA_LENGTH))
+);
+
+/*
+ * Physical Address field masks
+ *
+ * General Media Event Record
+ * CXL rev 3.0 Section 8.2.9.2.1.1; Table 8-43
+ *
+ * DRAM Event Record
+ * CXL rev 3.0 section 8.2.9.2.1.2; Table 8-44
+ */
+#define CXL_DPA_FLAGS_MASK 0x3F
+#define CXL_DPA_MASK (~CXL_DPA_FLAGS_MASK)
+
+#define CXL_DPA_VOLATILE BIT(0)
+#define CXL_DPA_NOT_REPAIRABLE BIT(1)
+#define show_dpa_flags(flags) __print_flags(flags, "|", \
+ { CXL_DPA_VOLATILE, "VOLATILE" }, \
+ { CXL_DPA_NOT_REPAIRABLE, "NOT_REPAIRABLE" } \
+)
+
+/*
+ * General Media Event Record - GMER
+ * CXL rev 3.0 Section 8.2.9.2.1.1; Table 8-43
+ */
+#define CXL_GMER_EVT_DESC_UNCORECTABLE_EVENT BIT(0)
+#define CXL_GMER_EVT_DESC_THRESHOLD_EVENT BIT(1)
+#define CXL_GMER_EVT_DESC_POISON_LIST_OVERFLOW BIT(2)
+#define show_event_desc_flags(flags) __print_flags(flags, "|", \
+ { CXL_GMER_EVT_DESC_UNCORECTABLE_EVENT, "UNCORRECTABLE_EVENT" }, \
+ { CXL_GMER_EVT_DESC_THRESHOLD_EVENT, "THRESHOLD_EVENT" }, \
+ { CXL_GMER_EVT_DESC_POISON_LIST_OVERFLOW, "POISON_LIST_OVERFLOW" } \
+)
+
+#define CXL_GMER_MEM_EVT_TYPE_ECC_ERROR 0x00
+#define CXL_GMER_MEM_EVT_TYPE_INV_ADDR 0x01
+#define CXL_GMER_MEM_EVT_TYPE_DATA_PATH_ERROR 0x02
+#define show_mem_event_type(type) __print_symbolic(type, \
+ { CXL_GMER_MEM_EVT_TYPE_ECC_ERROR, "ECC Error" }, \
+ { CXL_GMER_MEM_EVT_TYPE_INV_ADDR, "Invalid Address" }, \
+ { CXL_GMER_MEM_EVT_TYPE_DATA_PATH_ERROR, "Data Path Error" } \
+)
+
+#define CXL_GMER_TRANS_UNKNOWN 0x00
+#define CXL_GMER_TRANS_HOST_READ 0x01
+#define CXL_GMER_TRANS_HOST_WRITE 0x02
+#define CXL_GMER_TRANS_HOST_SCAN_MEDIA 0x03
+#define CXL_GMER_TRANS_HOST_INJECT_POISON 0x04
+#define CXL_GMER_TRANS_INTERNAL_MEDIA_SCRUB 0x05
+#define CXL_GMER_TRANS_INTERNAL_MEDIA_MANAGEMENT 0x06
+#define show_trans_type(type) __print_symbolic(type, \
+ { CXL_GMER_TRANS_UNKNOWN, "Unknown" }, \
+ { CXL_GMER_TRANS_HOST_READ, "Host Read" }, \
+ { CXL_GMER_TRANS_HOST_WRITE, "Host Write" }, \
+ { CXL_GMER_TRANS_HOST_SCAN_MEDIA, "Host Scan Media" }, \
+ { CXL_GMER_TRANS_HOST_INJECT_POISON, "Host Inject Poison" }, \
+ { CXL_GMER_TRANS_INTERNAL_MEDIA_SCRUB, "Internal Media Scrub" }, \
+ { CXL_GMER_TRANS_INTERNAL_MEDIA_MANAGEMENT, "Internal Media Management" } \
+)
+
+#define CXL_GMER_VALID_CHANNEL BIT(0)
+#define CXL_GMER_VALID_RANK BIT(1)
+#define CXL_GMER_VALID_DEVICE BIT(2)
+#define CXL_GMER_VALID_COMPONENT BIT(3)
+#define show_valid_flags(flags) __print_flags(flags, "|", \
+ { CXL_GMER_VALID_CHANNEL, "CHANNEL" }, \
+ { CXL_GMER_VALID_RANK, "RANK" }, \
+ { CXL_GMER_VALID_DEVICE, "DEVICE" }, \
+ { CXL_GMER_VALID_COMPONENT, "COMPONENT" } \
+)
+
+TRACE_EVENT(cxl_general_media,
+
+ TP_PROTO(const struct cxl_memdev *cxlmd, enum cxl_event_log_type log,
+ struct cxl_event_gen_media *rec),
+
+ TP_ARGS(cxlmd, log, rec),
+
+ TP_STRUCT__entry(
+ CXL_EVT_TP_entry
+ /* General Media */
+ __field(u64, dpa)
+ __field(u8, descriptor)
+ __field(u8, type)
+ __field(u8, transaction_type)
+ __field(u8, channel)
+ __field(u32, device)
+ __array(u8, comp_id, CXL_EVENT_GEN_MED_COMP_ID_SIZE)
+ __field(u16, validity_flags)
+ /* Following are out of order to pack trace record */
+ __field(u8, rank)
+ __field(u8, dpa_flags)
+ ),
+
+ TP_fast_assign(
+ CXL_EVT_TP_fast_assign(cxlmd, log, rec->hdr);
+
+ /* General Media */
+ __entry->dpa = le64_to_cpu(rec->phys_addr);
+ __entry->dpa_flags = __entry->dpa & CXL_DPA_FLAGS_MASK;
+ /* Mask after flags have been parsed */
+ __entry->dpa &= CXL_DPA_MASK;
+ __entry->descriptor = rec->descriptor;
+ __entry->type = rec->type;
+ __entry->transaction_type = rec->transaction_type;
+ __entry->channel = rec->channel;
+ __entry->rank = rec->rank;
+ __entry->device = get_unaligned_le24(rec->device);
+ memcpy(__entry->comp_id, &rec->component_id,
+ CXL_EVENT_GEN_MED_COMP_ID_SIZE);
+ __entry->validity_flags = get_unaligned_le16(&rec->validity_flags);
+ ),
+
+ CXL_EVT_TP_printk("dpa=%llx dpa_flags='%s' " \
+ "descriptor='%s' type='%s' transaction_type='%s' channel=%u rank=%u " \
+ "device=%x comp_id=%s validity_flags='%s'",
+ __entry->dpa, show_dpa_flags(__entry->dpa_flags),
+ show_event_desc_flags(__entry->descriptor),
+ show_mem_event_type(__entry->type),
+ show_trans_type(__entry->transaction_type),
+ __entry->channel, __entry->rank, __entry->device,
+ __print_hex(__entry->comp_id, CXL_EVENT_GEN_MED_COMP_ID_SIZE),
+ show_valid_flags(__entry->validity_flags)
+ )
+);
+
+/*
+ * DRAM Event Record - DER
+ *
+ * CXL rev 3.0 section 8.2.9.2.1.2; Table 8-44
+ */
+/*
+ * DRAM Event Record defines many fields the same as the General Media Event
+ * Record. Reuse those definitions as appropriate.
+ */
+#define CXL_DER_VALID_CHANNEL BIT(0)
+#define CXL_DER_VALID_RANK BIT(1)
+#define CXL_DER_VALID_NIBBLE BIT(2)
+#define CXL_DER_VALID_BANK_GROUP BIT(3)
+#define CXL_DER_VALID_BANK BIT(4)
+#define CXL_DER_VALID_ROW BIT(5)
+#define CXL_DER_VALID_COLUMN BIT(6)
+#define CXL_DER_VALID_CORRECTION_MASK BIT(7)
+#define show_dram_valid_flags(flags) __print_flags(flags, "|", \
+ { CXL_DER_VALID_CHANNEL, "CHANNEL" }, \
+ { CXL_DER_VALID_RANK, "RANK" }, \
+ { CXL_DER_VALID_NIBBLE, "NIBBLE" }, \
+ { CXL_DER_VALID_BANK_GROUP, "BANK GROUP" }, \
+ { CXL_DER_VALID_BANK, "BANK" }, \
+ { CXL_DER_VALID_ROW, "ROW" }, \
+ { CXL_DER_VALID_COLUMN, "COLUMN" }, \
+ { CXL_DER_VALID_CORRECTION_MASK, "CORRECTION MASK" } \
+)
+
+TRACE_EVENT(cxl_dram,
+
+ TP_PROTO(const struct cxl_memdev *cxlmd, enum cxl_event_log_type log,
+ struct cxl_event_dram *rec),
+
+ TP_ARGS(cxlmd, log, rec),
+
+ TP_STRUCT__entry(
+ CXL_EVT_TP_entry
+ /* DRAM */
+ __field(u64, dpa)
+ __field(u8, descriptor)
+ __field(u8, type)
+ __field(u8, transaction_type)
+ __field(u8, channel)
+ __field(u16, validity_flags)
+ __field(u16, column) /* Out of order to pack trace record */
+ __field(u32, nibble_mask)
+ __field(u32, row)
+ __array(u8, cor_mask, CXL_EVENT_DER_CORRECTION_MASK_SIZE)
+ __field(u8, rank) /* Out of order to pack trace record */
+ __field(u8, bank_group) /* Out of order to pack trace record */
+ __field(u8, bank) /* Out of order to pack trace record */
+ __field(u8, dpa_flags) /* Out of order to pack trace record */
+ ),
+
+ TP_fast_assign(
+ CXL_EVT_TP_fast_assign(cxlmd, log, rec->hdr);
+
+ /* DRAM */
+ __entry->dpa = le64_to_cpu(rec->phys_addr);
+ __entry->dpa_flags = __entry->dpa & CXL_DPA_FLAGS_MASK;
+ __entry->dpa &= CXL_DPA_MASK;
+ __entry->descriptor = rec->descriptor;
+ __entry->type = rec->type;
+ __entry->transaction_type = rec->transaction_type;
+ __entry->validity_flags = get_unaligned_le16(rec->validity_flags);
+ __entry->channel = rec->channel;
+ __entry->rank = rec->rank;
+ __entry->nibble_mask = get_unaligned_le24(rec->nibble_mask);
+ __entry->bank_group = rec->bank_group;
+ __entry->bank = rec->bank;
+ __entry->row = get_unaligned_le24(rec->row);
+ __entry->column = get_unaligned_le16(rec->column);
+ memcpy(__entry->cor_mask, &rec->correction_mask,
+ CXL_EVENT_DER_CORRECTION_MASK_SIZE);
+ ),
+
+ CXL_EVT_TP_printk("dpa=%llx dpa_flags='%s' descriptor='%s' type='%s' " \
+ "transaction_type='%s' channel=%u rank=%u nibble_mask=%x " \
+ "bank_group=%u bank=%u row=%u column=%u cor_mask=%s " \
+ "validity_flags='%s'",
+ __entry->dpa, show_dpa_flags(__entry->dpa_flags),
+ show_event_desc_flags(__entry->descriptor),
+ show_mem_event_type(__entry->type),
+ show_trans_type(__entry->transaction_type),
+ __entry->channel, __entry->rank, __entry->nibble_mask,
+ __entry->bank_group, __entry->bank,
+ __entry->row, __entry->column,
+ __print_hex(__entry->cor_mask, CXL_EVENT_DER_CORRECTION_MASK_SIZE),
+ show_dram_valid_flags(__entry->validity_flags)
+ )
+);
+
+/*
+ * Memory Module Event Record - MMER
+ *
+ * CXL res 3.0 section 8.2.9.2.1.3; Table 8-45
+ */
+#define CXL_MMER_HEALTH_STATUS_CHANGE 0x00
+#define CXL_MMER_MEDIA_STATUS_CHANGE 0x01
+#define CXL_MMER_LIFE_USED_CHANGE 0x02
+#define CXL_MMER_TEMP_CHANGE 0x03
+#define CXL_MMER_DATA_PATH_ERROR 0x04
+#define CXL_MMER_LSA_ERROR 0x05
+#define show_dev_evt_type(type) __print_symbolic(type, \
+ { CXL_MMER_HEALTH_STATUS_CHANGE, "Health Status Change" }, \
+ { CXL_MMER_MEDIA_STATUS_CHANGE, "Media Status Change" }, \
+ { CXL_MMER_LIFE_USED_CHANGE, "Life Used Change" }, \
+ { CXL_MMER_TEMP_CHANGE, "Temperature Change" }, \
+ { CXL_MMER_DATA_PATH_ERROR, "Data Path Error" }, \
+ { CXL_MMER_LSA_ERROR, "LSA Error" } \
+)
+
+/*
+ * Device Health Information - DHI
+ *
+ * CXL res 3.0 section 8.2.9.8.3.1; Table 8-100
+ */
+#define CXL_DHI_HS_MAINTENANCE_NEEDED BIT(0)
+#define CXL_DHI_HS_PERFORMANCE_DEGRADED BIT(1)
+#define CXL_DHI_HS_HW_REPLACEMENT_NEEDED BIT(2)
+#define show_health_status_flags(flags) __print_flags(flags, "|", \
+ { CXL_DHI_HS_MAINTENANCE_NEEDED, "MAINTENANCE_NEEDED" }, \
+ { CXL_DHI_HS_PERFORMANCE_DEGRADED, "PERFORMANCE_DEGRADED" }, \
+ { CXL_DHI_HS_HW_REPLACEMENT_NEEDED, "REPLACEMENT_NEEDED" } \
+)
+
+#define CXL_DHI_MS_NORMAL 0x00
+#define CXL_DHI_MS_NOT_READY 0x01
+#define CXL_DHI_MS_WRITE_PERSISTENCY_LOST 0x02
+#define CXL_DHI_MS_ALL_DATA_LOST 0x03
+#define CXL_DHI_MS_WRITE_PERSISTENCY_LOSS_EVENT_POWER_LOSS 0x04
+#define CXL_DHI_MS_WRITE_PERSISTENCY_LOSS_EVENT_SHUTDOWN 0x05
+#define CXL_DHI_MS_WRITE_PERSISTENCY_LOSS_IMMINENT 0x06
+#define CXL_DHI_MS_WRITE_ALL_DATA_LOSS_EVENT_POWER_LOSS 0x07
+#define CXL_DHI_MS_WRITE_ALL_DATA_LOSS_EVENT_SHUTDOWN 0x08
+#define CXL_DHI_MS_WRITE_ALL_DATA_LOSS_IMMINENT 0x09
+#define show_media_status(ms) __print_symbolic(ms, \
+ { CXL_DHI_MS_NORMAL, \
+ "Normal" }, \
+ { CXL_DHI_MS_NOT_READY, \
+ "Not Ready" }, \
+ { CXL_DHI_MS_WRITE_PERSISTENCY_LOST, \
+ "Write Persistency Lost" }, \
+ { CXL_DHI_MS_ALL_DATA_LOST, \
+ "All Data Lost" }, \
+ { CXL_DHI_MS_WRITE_PERSISTENCY_LOSS_EVENT_POWER_LOSS, \
+ "Write Persistency Loss in the Event of Power Loss" }, \
+ { CXL_DHI_MS_WRITE_PERSISTENCY_LOSS_EVENT_SHUTDOWN, \
+ "Write Persistency Loss in Event of Shutdown" }, \
+ { CXL_DHI_MS_WRITE_PERSISTENCY_LOSS_IMMINENT, \
+ "Write Persistency Loss Imminent" }, \
+ { CXL_DHI_MS_WRITE_ALL_DATA_LOSS_EVENT_POWER_LOSS, \
+ "All Data Loss in Event of Power Loss" }, \
+ { CXL_DHI_MS_WRITE_ALL_DATA_LOSS_EVENT_SHUTDOWN, \
+ "All Data loss in the Event of Shutdown" }, \
+ { CXL_DHI_MS_WRITE_ALL_DATA_LOSS_IMMINENT, \
+ "All Data Loss Imminent" } \
+)
+
+#define CXL_DHI_AS_NORMAL 0x0
+#define CXL_DHI_AS_WARNING 0x1
+#define CXL_DHI_AS_CRITICAL 0x2
+#define show_two_bit_status(as) __print_symbolic(as, \
+ { CXL_DHI_AS_NORMAL, "Normal" }, \
+ { CXL_DHI_AS_WARNING, "Warning" }, \
+ { CXL_DHI_AS_CRITICAL, "Critical" } \
+)
+#define show_one_bit_status(as) __print_symbolic(as, \
+ { CXL_DHI_AS_NORMAL, "Normal" }, \
+ { CXL_DHI_AS_WARNING, "Warning" } \
+)
+
+#define CXL_DHI_AS_LIFE_USED(as) (as & 0x3)
+#define CXL_DHI_AS_DEV_TEMP(as) ((as & 0xC) >> 2)
+#define CXL_DHI_AS_COR_VOL_ERR_CNT(as) ((as & 0x10) >> 4)
+#define CXL_DHI_AS_COR_PER_ERR_CNT(as) ((as & 0x20) >> 5)
+
+TRACE_EVENT(cxl_memory_module,
+
+ TP_PROTO(const struct cxl_memdev *cxlmd, enum cxl_event_log_type log,
+ struct cxl_event_mem_module *rec),
+
+ TP_ARGS(cxlmd, log, rec),
+
+ TP_STRUCT__entry(
+ CXL_EVT_TP_entry
+
+ /* Memory Module Event */
+ __field(u8, event_type)
+
+ /* Device Health Info */
+ __field(u8, health_status)
+ __field(u8, media_status)
+ __field(u8, life_used)
+ __field(u32, dirty_shutdown_cnt)
+ __field(u32, cor_vol_err_cnt)
+ __field(u32, cor_per_err_cnt)
+ __field(s16, device_temp)
+ __field(u8, add_status)
+ ),
+
+ TP_fast_assign(
+ CXL_EVT_TP_fast_assign(cxlmd, log, rec->hdr);
+
+ /* Memory Module Event */
+ __entry->event_type = rec->event_type;
+
+ /* Device Health Info */
+ __entry->health_status = rec->info.health_status;
+ __entry->media_status = rec->info.media_status;
+ __entry->life_used = rec->info.life_used;
+ __entry->dirty_shutdown_cnt = get_unaligned_le32(rec->info.dirty_shutdown_cnt);
+ __entry->cor_vol_err_cnt = get_unaligned_le32(rec->info.cor_vol_err_cnt);
+ __entry->cor_per_err_cnt = get_unaligned_le32(rec->info.cor_per_err_cnt);
+ __entry->device_temp = get_unaligned_le16(rec->info.device_temp);
+ __entry->add_status = rec->info.add_status;
+ ),
+
+ CXL_EVT_TP_printk("event_type='%s' health_status='%s' media_status='%s' " \
+ "as_life_used=%s as_dev_temp=%s as_cor_vol_err_cnt=%s " \
+ "as_cor_per_err_cnt=%s life_used=%u device_temp=%d " \
+ "dirty_shutdown_cnt=%u cor_vol_err_cnt=%u cor_per_err_cnt=%u",
+ show_dev_evt_type(__entry->event_type),
+ show_health_status_flags(__entry->health_status),
+ show_media_status(__entry->media_status),
+ show_two_bit_status(CXL_DHI_AS_LIFE_USED(__entry->add_status)),
+ show_two_bit_status(CXL_DHI_AS_DEV_TEMP(__entry->add_status)),
+ show_one_bit_status(CXL_DHI_AS_COR_VOL_ERR_CNT(__entry->add_status)),
+ show_one_bit_status(CXL_DHI_AS_COR_PER_ERR_CNT(__entry->add_status)),
+ __entry->life_used, __entry->device_temp,
+ __entry->dirty_shutdown_cnt, __entry->cor_vol_err_cnt,
+ __entry->cor_per_err_cnt
+ )
+);
+
+#endif /* _CXL_EVENTS_H */
+
+#define TRACE_INCLUDE_FILE trace
+#include <trace/define_trace.h>
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index 1b1cf459ac77..f2b0962a552d 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -130,6 +130,7 @@ static inline int ways_to_eiw(unsigned int ways, u8 *eiw)
#define CXL_RAS_UNCORRECTABLE_STATUS_MASK (GENMASK(16, 14) | GENMASK(11, 0))
#define CXL_RAS_UNCORRECTABLE_MASK_OFFSET 0x4
#define CXL_RAS_UNCORRECTABLE_MASK_MASK (GENMASK(16, 14) | GENMASK(11, 0))
+#define CXL_RAS_UNCORRECTABLE_MASK_F256B_MASK BIT(8)
#define CXL_RAS_UNCORRECTABLE_SEVERITY_OFFSET 0x8
#define CXL_RAS_UNCORRECTABLE_SEVERITY_MASK (GENMASK(16, 14) | GENMASK(11, 0))
#define CXL_RAS_CORRECTABLE_STATUS_OFFSET 0xC
@@ -140,6 +141,8 @@ static inline int ways_to_eiw(unsigned int ways, u8 *eiw)
#define CXL_RAS_CAP_CONTROL_FE_MASK GENMASK(5, 0)
#define CXL_RAS_HEADER_LOG_OFFSET 0x18
#define CXL_RAS_CAPABILITY_LENGTH 0x58
+#define CXL_HEADERLOG_SIZE SZ_512
+#define CXL_HEADERLOG_SIZE_U32 SZ_512 / sizeof(u32)
/* CXL 2.0 8.2.8.1 Device Capabilities Array Register */
#define CXLDEV_CAP_ARRAY_OFFSET 0x0
@@ -154,6 +157,22 @@ static inline int ways_to_eiw(unsigned int ways, u8 *eiw)
#define CXLDEV_CAP_CAP_ID_SECONDARY_MAILBOX 0x3
#define CXLDEV_CAP_CAP_ID_MEMDEV 0x4000
+/* CXL 3.0 8.2.8.3.1 Event Status Register */
+#define CXLDEV_DEV_EVENT_STATUS_OFFSET 0x00
+#define CXLDEV_EVENT_STATUS_INFO BIT(0)
+#define CXLDEV_EVENT_STATUS_WARN BIT(1)
+#define CXLDEV_EVENT_STATUS_FAIL BIT(2)
+#define CXLDEV_EVENT_STATUS_FATAL BIT(3)
+
+#define CXLDEV_EVENT_STATUS_ALL (CXLDEV_EVENT_STATUS_INFO | \
+ CXLDEV_EVENT_STATUS_WARN | \
+ CXLDEV_EVENT_STATUS_FAIL | \
+ CXLDEV_EVENT_STATUS_FATAL)
+
+/* CXL rev 3.0 section 8.2.9.2.4; Table 8-52 */
+#define CXLDEV_EVENT_INT_MODE_MASK GENMASK(1, 0)
+#define CXLDEV_EVENT_INT_MSGNUM_MASK GENMASK(7, 4)
+
/* CXL 2.0 8.2.8.4 Mailbox Registers */
#define CXLDEV_MBOX_CAPS_OFFSET 0x00
#define CXLDEV_MBOX_CAP_PAYLOAD_SIZE_MASK GENMASK(4, 0)
@@ -259,6 +278,8 @@ resource_size_t cxl_rcrb_to_component(struct device *dev,
* cxl_decoder flags that define the type of memory / devices this
* decoder supports as well as configuration lock status See "CXL 2.0
* 8.2.5.12.7 CXL HDM Decoder 0 Control Register" for details.
+ * Additionally indicate whether decoder settings were autodetected,
+ * user customized.
*/
#define CXL_DECODER_F_RAM BIT(0)
#define CXL_DECODER_F_PMEM BIT(1)
@@ -318,12 +339,36 @@ enum cxl_decoder_mode {
CXL_DECODER_DEAD,
};
+static inline const char *cxl_decoder_mode_name(enum cxl_decoder_mode mode)
+{
+ static const char * const names[] = {
+ [CXL_DECODER_NONE] = "none",
+ [CXL_DECODER_RAM] = "ram",
+ [CXL_DECODER_PMEM] = "pmem",
+ [CXL_DECODER_MIXED] = "mixed",
+ };
+
+ if (mode >= CXL_DECODER_NONE && mode <= CXL_DECODER_MIXED)
+ return names[mode];
+ return "mixed";
+}
+
+/*
+ * Track whether this decoder is reserved for region autodiscovery, or
+ * free for userspace provisioning.
+ */
+enum cxl_decoder_state {
+ CXL_DECODER_STATE_MANUAL,
+ CXL_DECODER_STATE_AUTO,
+};
+
/**
* struct cxl_endpoint_decoder - Endpoint / SPA to DPA decoder
* @cxld: base cxl_decoder_object
* @dpa_res: actively claimed DPA span of this decoder
* @skip: offset into @dpa_res where @cxld.hpa_range maps
* @mode: which memory type / access-mode-partition this decoder targets
+ * @state: autodiscovery state
* @pos: interleave position in @cxld.region
*/
struct cxl_endpoint_decoder {
@@ -331,6 +376,7 @@ struct cxl_endpoint_decoder {
struct resource *dpa_res;
resource_size_t skip;
enum cxl_decoder_mode mode;
+ enum cxl_decoder_state state;
int pos;
};
@@ -364,6 +410,7 @@ typedef struct cxl_dport *(*cxl_calc_hb_fn)(struct cxl_root_decoder *cxlrd,
* @region_id: region id for next region provisioning event
* @calc_hb: which host bridge covers the n'th position by granularity
* @platform_data: platform specific configuration data
+ * @range_lock: sync region autodiscovery by address range
* @cxlsd: base cxl switch decoder
*/
struct cxl_root_decoder {
@@ -371,6 +418,7 @@ struct cxl_root_decoder {
atomic_t region_id;
cxl_calc_hb_fn calc_hb;
void *platform_data;
+ struct mutex range_lock;
struct cxl_switch_decoder cxlsd;
};
@@ -420,6 +468,13 @@ struct cxl_region_params {
*/
#define CXL_REGION_F_INCOHERENT 0
+/*
+ * Indicate whether this region has been assembled by autodetection or
+ * userspace assembly. Prevent endpoint decoders outside of automatic
+ * detection from being added to the region.
+ */
+#define CXL_REGION_F_AUTO 1
+
/**
* struct cxl_region - CXL region
* @dev: This region's device
@@ -475,6 +530,12 @@ struct cxl_pmem_region {
struct cxl_pmem_region_mapping mapping[];
};
+struct cxl_dax_region {
+ struct device dev;
+ struct cxl_region *cxlr;
+ struct range hpa_range;
+};
+
/**
* struct cxl_port - logical collection of upstream port devices and
* downstream port devices to construct a CXL memory
@@ -588,8 +649,8 @@ static inline bool is_cxl_root(struct cxl_port *port)
return port->uport == port->dev.parent;
}
-bool is_cxl_port(struct device *dev);
-struct cxl_port *to_cxl_port(struct device *dev);
+bool is_cxl_port(const struct device *dev);
+struct cxl_port *to_cxl_port(const struct device *dev);
struct pci_bus;
int devm_cxl_register_pci_bus(struct device *host, struct device *uport,
struct pci_bus *bus);
@@ -615,8 +676,10 @@ struct cxl_dport *devm_cxl_add_rch_dport(struct cxl_port *port,
struct cxl_decoder *to_cxl_decoder(struct device *dev);
struct cxl_root_decoder *to_cxl_root_decoder(struct device *dev);
+struct cxl_switch_decoder *to_cxl_switch_decoder(struct device *dev);
struct cxl_endpoint_decoder *to_cxl_endpoint_decoder(struct device *dev);
bool is_root_decoder(struct device *dev);
+bool is_switch_decoder(struct device *dev);
bool is_endpoint_decoder(struct device *dev);
struct cxl_root_decoder *cxl_root_decoder_alloc(struct cxl_port *port,
unsigned int nr_targets,
@@ -630,10 +693,26 @@ int cxl_decoder_add_locked(struct cxl_decoder *cxld, int *target_map);
int cxl_decoder_autoremove(struct device *host, struct cxl_decoder *cxld);
int cxl_endpoint_autoremove(struct cxl_memdev *cxlmd, struct cxl_port *endpoint);
+/**
+ * struct cxl_endpoint_dvsec_info - Cached DVSEC info
+ * @mem_enabled: cached value of mem_enabled in the DVSEC, PCIE_DEVICE
+ * @ranges: Number of active HDM ranges this device uses.
+ * @dvsec_range: cached attributes of the ranges in the DVSEC, PCIE_DEVICE
+ */
+struct cxl_endpoint_dvsec_info {
+ bool mem_enabled;
+ int ranges;
+ struct range dvsec_range[2];
+};
+
struct cxl_hdm;
-struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port);
-int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm);
+struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port,
+ struct cxl_endpoint_dvsec_info *info);
+int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,
+ struct cxl_endpoint_dvsec_info *info);
int devm_cxl_add_passthrough_decoder(struct cxl_port *port);
+int cxl_dvsec_rr_decode(struct device *dev, int dvsec,
+ struct cxl_endpoint_dvsec_info *info);
bool is_cxl_region(struct device *dev);
@@ -667,6 +746,7 @@ void cxl_driver_unregister(struct cxl_driver *cxl_drv);
#define CXL_DEVICE_MEMORY_EXPANDER 5
#define CXL_DEVICE_REGION 6
#define CXL_DEVICE_PMEM_REGION 7
+#define CXL_DEVICE_DAX_REGION 8
#define MODULE_ALIAS_CXL(type) MODULE_ALIAS("cxl:t" __stringify(type) "*")
#define CXL_MODALIAS_FMT "cxl:t%d"
@@ -683,6 +763,9 @@ struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct device *dev);
#ifdef CONFIG_CXL_REGION
bool is_cxl_pmem_region(struct device *dev);
struct cxl_pmem_region *to_cxl_pmem_region(struct device *dev);
+int cxl_add_to_region(struct cxl_port *root,
+ struct cxl_endpoint_decoder *cxled);
+struct cxl_dax_region *to_cxl_dax_region(struct device *dev);
#else
static inline bool is_cxl_pmem_region(struct device *dev)
{
@@ -692,6 +775,15 @@ static inline struct cxl_pmem_region *to_cxl_pmem_region(struct device *dev)
{
return NULL;
}
+static inline int cxl_add_to_region(struct cxl_port *root,
+ struct cxl_endpoint_decoder *cxled)
+{
+ return 0;
+}
+static inline struct cxl_dax_region *to_cxl_dax_region(struct device *dev)
+{
+ return NULL;
+}
#endif
/*
diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h
index ab138004f644..090acebba4fa 100644
--- a/drivers/cxl/cxlmem.h
+++ b/drivers/cxl/cxlmem.h
@@ -4,6 +4,7 @@
#define __CXL_MEM_H__
#include <uapi/linux/cxl_mem.h>
#include <linux/cdev.h>
+#include <linux/uuid.h>
#include "cxl.h"
/* CXL 2.0 8.2.8.5.1.1 Memory Device Status Register */
@@ -38,6 +39,7 @@
* @cxl_nvb: coordinate removal of @cxl_nvd if present
* @cxl_nvd: optional bridge to an nvdimm if the device supports pmem
* @id: id number of this memdev instance.
+ * @depth: endpoint port depth
*/
struct cxl_memdev {
struct device dev;
@@ -47,6 +49,7 @@ struct cxl_memdev {
struct cxl_nvdimm_bridge *cxl_nvb;
struct cxl_nvdimm *cxl_nvd;
int id;
+ int depth;
};
static inline struct cxl_memdev *to_cxl_memdev(struct device *dev)
@@ -72,13 +75,16 @@ cxled_to_memdev(struct cxl_endpoint_decoder *cxled)
return to_cxl_memdev(port->uport);
}
-bool is_cxl_memdev(struct device *dev);
+bool is_cxl_memdev(const struct device *dev);
static inline bool is_cxl_endpoint(struct cxl_port *port)
{
return is_cxl_memdev(port->uport);
}
struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds);
+int devm_cxl_dpa_reserve(struct cxl_endpoint_decoder *cxled,
+ resource_size_t base, resource_size_t len,
+ resource_size_t skipped);
static inline struct cxl_ep *cxl_ep_load(struct cxl_port *port,
struct cxl_memdev *cxlmd)
@@ -182,15 +188,31 @@ static inline int cxl_mbox_cmd_rc2errno(struct cxl_mbox_cmd *mbox_cmd)
#define CXL_CAPACITY_MULTIPLIER SZ_256M
/**
- * struct cxl_endpoint_dvsec_info - Cached DVSEC info
- * @mem_enabled: cached value of mem_enabled in the DVSEC, PCIE_DEVICE
- * @ranges: Number of active HDM ranges this device uses.
- * @dvsec_range: cached attributes of the ranges in the DVSEC, PCIE_DEVICE
+ * Event Interrupt Policy
+ *
+ * CXL rev 3.0 section 8.2.9.2.4; Table 8-52
+ */
+enum cxl_event_int_mode {
+ CXL_INT_NONE = 0x00,
+ CXL_INT_MSI_MSIX = 0x01,
+ CXL_INT_FW = 0x02
+};
+struct cxl_event_interrupt_policy {
+ u8 info_settings;
+ u8 warn_settings;
+ u8 failure_settings;
+ u8 fatal_settings;
+} __packed;
+
+/**
+ * struct cxl_event_state - Event log driver state
+ *
+ * @event_buf: Buffer to receive event data
+ * @event_log_lock: Serialize event_buf and log use
*/
-struct cxl_endpoint_dvsec_info {
- bool mem_enabled;
- int ranges;
- struct range dvsec_range[2];
+struct cxl_event_state {
+ struct cxl_get_event_payload *buf;
+ struct mutex log_lock;
};
/**
@@ -228,6 +250,7 @@ struct cxl_endpoint_dvsec_info {
* @info: Cached DVSEC information about the device.
* @serial: PCIe Device Serial Number
* @doe_mbs: PCI DOE mailbox array
+ * @event: event log driver state
* @mbox_send: @dev specific transport for transmitting mailbox commands
*
* See section 8.2.9.5.2 Capacity Configuration and Label Storage for
@@ -266,14 +289,21 @@ struct cxl_dev_state {
struct xarray doe_mbs;
+ struct cxl_event_state event;
+
int (*mbox_send)(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd);
};
enum cxl_opcode {
CXL_MBOX_OP_INVALID = 0x0000,
CXL_MBOX_OP_RAW = CXL_MBOX_OP_INVALID,
+ CXL_MBOX_OP_GET_EVENT_RECORD = 0x0100,
+ CXL_MBOX_OP_CLEAR_EVENT_RECORD = 0x0101,
+ CXL_MBOX_OP_GET_EVT_INT_POLICY = 0x0102,
+ CXL_MBOX_OP_SET_EVT_INT_POLICY = 0x0103,
CXL_MBOX_OP_GET_FW_INFO = 0x0200,
CXL_MBOX_OP_ACTIVATE_FW = 0x0202,
+ CXL_MBOX_OP_SET_TIMESTAMP = 0x0301,
CXL_MBOX_OP_GET_SUPPORTED_LOGS = 0x0400,
CXL_MBOX_OP_GET_LOG = 0x0401,
CXL_MBOX_OP_IDENTIFY = 0x4000,
@@ -347,6 +377,136 @@ struct cxl_mbox_identify {
u8 qos_telemetry_caps;
} __packed;
+/*
+ * Common Event Record Format
+ * CXL rev 3.0 section 8.2.9.2.1; Table 8-42
+ */
+struct cxl_event_record_hdr {
+ uuid_t id;
+ u8 length;
+ u8 flags[3];
+ __le16 handle;
+ __le16 related_handle;
+ __le64 timestamp;
+ u8 maint_op_class;
+ u8 reserved[15];
+} __packed;
+
+#define CXL_EVENT_RECORD_DATA_LENGTH 0x50
+struct cxl_event_record_raw {
+ struct cxl_event_record_hdr hdr;
+ u8 data[CXL_EVENT_RECORD_DATA_LENGTH];
+} __packed;
+
+/*
+ * Get Event Records output payload
+ * CXL rev 3.0 section 8.2.9.2.2; Table 8-50
+ */
+#define CXL_GET_EVENT_FLAG_OVERFLOW BIT(0)
+#define CXL_GET_EVENT_FLAG_MORE_RECORDS BIT(1)
+struct cxl_get_event_payload {
+ u8 flags;
+ u8 reserved1;
+ __le16 overflow_err_count;
+ __le64 first_overflow_timestamp;
+ __le64 last_overflow_timestamp;
+ __le16 record_count;
+ u8 reserved2[10];
+ struct cxl_event_record_raw records[];
+} __packed;
+
+/*
+ * CXL rev 3.0 section 8.2.9.2.2; Table 8-49
+ */
+enum cxl_event_log_type {
+ CXL_EVENT_TYPE_INFO = 0x00,
+ CXL_EVENT_TYPE_WARN,
+ CXL_EVENT_TYPE_FAIL,
+ CXL_EVENT_TYPE_FATAL,
+ CXL_EVENT_TYPE_MAX
+};
+
+/*
+ * Clear Event Records input payload
+ * CXL rev 3.0 section 8.2.9.2.3; Table 8-51
+ */
+struct cxl_mbox_clear_event_payload {
+ u8 event_log; /* enum cxl_event_log_type */
+ u8 clear_flags;
+ u8 nr_recs;
+ u8 reserved[3];
+ __le16 handles[];
+} __packed;
+#define CXL_CLEAR_EVENT_MAX_HANDLES U8_MAX
+
+/*
+ * General Media Event Record
+ * CXL rev 3.0 Section 8.2.9.2.1.1; Table 8-43
+ */
+#define CXL_EVENT_GEN_MED_COMP_ID_SIZE 0x10
+struct cxl_event_gen_media {
+ struct cxl_event_record_hdr hdr;
+ __le64 phys_addr;
+ u8 descriptor;
+ u8 type;
+ u8 transaction_type;
+ u8 validity_flags[2];
+ u8 channel;
+ u8 rank;
+ u8 device[3];
+ u8 component_id[CXL_EVENT_GEN_MED_COMP_ID_SIZE];
+ u8 reserved[46];
+} __packed;
+
+/*
+ * DRAM Event Record - DER
+ * CXL rev 3.0 section 8.2.9.2.1.2; Table 3-44
+ */
+#define CXL_EVENT_DER_CORRECTION_MASK_SIZE 0x20
+struct cxl_event_dram {
+ struct cxl_event_record_hdr hdr;
+ __le64 phys_addr;
+ u8 descriptor;
+ u8 type;
+ u8 transaction_type;
+ u8 validity_flags[2];
+ u8 channel;
+ u8 rank;
+ u8 nibble_mask[3];
+ u8 bank_group;
+ u8 bank;
+ u8 row[3];
+ u8 column[2];
+ u8 correction_mask[CXL_EVENT_DER_CORRECTION_MASK_SIZE];
+ u8 reserved[0x17];
+} __packed;
+
+/*
+ * Get Health Info Record
+ * CXL rev 3.0 section 8.2.9.8.3.1; Table 8-100
+ */
+struct cxl_get_health_info {
+ u8 health_status;
+ u8 media_status;
+ u8 add_status;
+ u8 life_used;
+ u8 device_temp[2];
+ u8 dirty_shutdown_cnt[4];
+ u8 cor_vol_err_cnt[4];
+ u8 cor_per_err_cnt[4];
+} __packed;
+
+/*
+ * Memory Module Event Record
+ * CXL rev 3.0 section 8.2.9.2.1.3; Table 8-45
+ */
+struct cxl_event_mem_module {
+ struct cxl_event_record_hdr hdr;
+ u8 event_type;
+ struct cxl_get_health_info info;
+ u8 reserved[0x3d];
+} __packed;
+
struct cxl_mbox_get_partition_info {
__le64 active_volatile_cap;
__le64 active_persistent_cap;
@@ -372,6 +532,12 @@ struct cxl_mbox_set_partition_info {
#define CXL_SET_PARTITION_IMMEDIATE_FLAG BIT(0)
+/* Set Timestamp CXL 3.0 Spec 8.2.9.4.2 */
+struct cxl_mbox_set_timestamp_in {
+ __le64 timestamp;
+
+} __packed;
+
/**
* struct cxl_mem_command - Driver representation of a memory device command
* @info: Command information as it exists for the UAPI
@@ -393,7 +559,6 @@ struct cxl_mem_command {
struct cxl_command_info info;
enum cxl_opcode opcode;
u32 flags;
-#define CXL_CMD_FLAG_NONE 0
#define CXL_CMD_FLAG_FORCE_ENABLE BIT(0)
};
@@ -441,6 +606,9 @@ int cxl_mem_create_range_info(struct cxl_dev_state *cxlds);
struct cxl_dev_state *cxl_dev_state_create(struct device *dev);
void set_exclusive_cxl_commands(struct cxl_dev_state *cxlds, unsigned long *cmds);
void clear_exclusive_cxl_commands(struct cxl_dev_state *cxlds, unsigned long *cmds);
+void cxl_mem_get_event_records(struct cxl_dev_state *cxlds, u32 status);
+int cxl_set_timestamp(struct cxl_dev_state *cxlds);
+
#ifdef CONFIG_CXL_SUSPEND
void cxl_mem_active_inc(void);
void cxl_mem_active_dec(void);
diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h
index 920909791bb9..be6a2ef3cce3 100644
--- a/drivers/cxl/cxlpci.h
+++ b/drivers/cxl/cxlpci.h
@@ -53,6 +53,12 @@
#define CXL_DVSEC_REG_LOCATOR_BLOCK_ID_MASK GENMASK(15, 8)
#define CXL_DVSEC_REG_LOCATOR_BLOCK_OFF_LOW_MASK GENMASK(31, 16)
+/*
+ * NOTE: Currently all the functions which are enabled for CXL require their
+ * vectors to be in the first 16. Use this as the default max.
+ */
+#define CXL_PCI_DEFAULT_MAX_VECTORS 16
+
/* Register Block Identifier (RBI) */
enum cxl_regloc_type {
CXL_REGLOC_RBI_EMPTY = 0,
@@ -64,6 +70,10 @@ enum cxl_regloc_type {
int devm_cxl_port_enumerate_dports(struct cxl_port *port);
struct cxl_dev_state;
-int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm);
+int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm,
+ struct cxl_endpoint_dvsec_info *info);
void read_cdat_data(struct cxl_port *port);
+void cxl_cor_error_detected(struct pci_dev *pdev);
+pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t state);
#endif /* __CXL_PCI_H__ */
diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
index 258004f34281..60b23624d167 100644
--- a/drivers/cxl/pci.c
+++ b/drivers/cxl/pci.c
@@ -14,8 +14,6 @@
#include "cxlmem.h"
#include "cxlpci.h"
#include "cxl.h"
-#define CREATE_TRACE_POINTS
-#include <trace/events/cxl.h>
/**
* DOC: cxl pci
@@ -162,7 +160,7 @@ static int __cxl_pci_mbox_send_cmd(struct cxl_dev_state *cxlds,
writeq(cmd_reg, cxlds->regs.mbox + CXLDEV_MBOX_CMD_OFFSET);
/* #4 */
- dev_dbg(dev, "Sending command\n");
+ dev_dbg(dev, "Sending command: 0x%04x\n", mbox_cmd->opcode);
writel(CXLDEV_MBOX_CTRL_DOORBELL,
cxlds->regs.mbox + CXLDEV_MBOX_CTRL_OFFSET);
@@ -414,13 +412,295 @@ static bool is_cxl_restricted(struct pci_dev *pdev)
return pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_END;
}
-static void disable_aer(void *pdev)
+/*
+ * CXL v3.0 6.2.3 Table 6-4
+ * The table indicates that if PCIe Flit Mode is set, then CXL is in 256B flits
+ * mode, otherwise it's 68B flits mode.
+ */
+static bool cxl_pci_flit_256(struct pci_dev *pdev)
+{
+ u16 lnksta2;
+
+ pcie_capability_read_word(pdev, PCI_EXP_LNKSTA2, &lnksta2);
+ return lnksta2 & PCI_EXP_LNKSTA2_FLIT;
+}
+
+static int cxl_pci_ras_unmask(struct pci_dev *pdev)
+{
+ struct pci_host_bridge *host_bridge = pci_find_host_bridge(pdev->bus);
+ struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
+ void __iomem *addr;
+ u32 orig_val, val, mask;
+ u16 cap;
+ int rc;
+
+ if (!cxlds->regs.ras) {
+ dev_dbg(&pdev->dev, "No RAS registers.\n");
+ return 0;
+ }
+
+ /* BIOS has CXL error control */
+ if (!host_bridge->native_cxl_error)
+ return -ENXIO;
+
+ rc = pcie_capability_read_word(pdev, PCI_EXP_DEVCTL, &cap);
+ if (rc)
+ return rc;
+
+ if (cap & PCI_EXP_DEVCTL_URRE) {
+ addr = cxlds->regs.ras + CXL_RAS_UNCORRECTABLE_MASK_OFFSET;
+ orig_val = readl(addr);
+
+ mask = CXL_RAS_UNCORRECTABLE_MASK_MASK;
+ if (!cxl_pci_flit_256(pdev))
+ mask &= ~CXL_RAS_UNCORRECTABLE_MASK_F256B_MASK;
+ val = orig_val & ~mask;
+ writel(val, addr);
+ dev_dbg(&pdev->dev,
+ "Uncorrectable RAS Errors Mask: %#x -> %#x\n",
+ orig_val, val);
+ }
+
+ if (cap & PCI_EXP_DEVCTL_CERE) {
+ addr = cxlds->regs.ras + CXL_RAS_CORRECTABLE_MASK_OFFSET;
+ orig_val = readl(addr);
+ val = orig_val & ~CXL_RAS_CORRECTABLE_MASK_MASK;
+ writel(val, addr);
+ dev_dbg(&pdev->dev, "Correctable RAS Errors Mask: %#x -> %#x\n",
+ orig_val, val);
+ }
+
+ return 0;
+}
+
+static void free_event_buf(void *buf)
+{
+ kvfree(buf);
+}
+
+/*
+ * There is a single buffer for reading event logs from the mailbox. All logs
+ * share this buffer protected by the cxlds->event_log_lock.
+ */
+static int cxl_mem_alloc_event_buf(struct cxl_dev_state *cxlds)
+{
+ struct cxl_get_event_payload *buf;
+
+ buf = kvmalloc(cxlds->payload_size, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+ cxlds->event.buf = buf;
+
+ return devm_add_action_or_reset(cxlds->dev, free_event_buf, buf);
+}
+
+static int cxl_alloc_irq_vectors(struct pci_dev *pdev)
+{
+ int nvecs;
+
+ /*
+ * Per CXL 3.0 3.1.1 CXL.io Endpoint a function on a CXL device must
+ * not generate INTx messages if that function participates in
+ * CXL.cache or CXL.mem.
+ *
+ * Additionally pci_alloc_irq_vectors() handles calling
+ * pci_free_irq_vectors() automatically despite not being called
+ * pcim_*. See pci_setup_msi_context().
+ */
+ nvecs = pci_alloc_irq_vectors(pdev, 1, CXL_PCI_DEFAULT_MAX_VECTORS,
+ PCI_IRQ_MSIX | PCI_IRQ_MSI);
+ if (nvecs < 1) {
+ dev_dbg(&pdev->dev, "Failed to alloc irq vectors: %d\n", nvecs);
+ return -ENXIO;
+ }
+ return 0;
+}
+
+struct cxl_dev_id {
+ struct cxl_dev_state *cxlds;
+};
+
+static irqreturn_t cxl_event_thread(int irq, void *id)
+{
+ struct cxl_dev_id *dev_id = id;
+ struct cxl_dev_state *cxlds = dev_id->cxlds;
+ u32 status;
+
+ do {
+ /*
+ * CXL 3.0 8.2.8.3.1: The lower 32 bits are the status;
+ * ignore the reserved upper 32 bits
+ */
+ status = readl(cxlds->regs.status + CXLDEV_DEV_EVENT_STATUS_OFFSET);
+ /* Ignore logs unknown to the driver */
+ status &= CXLDEV_EVENT_STATUS_ALL;
+ if (!status)
+ break;
+ cxl_mem_get_event_records(cxlds, status);
+ cond_resched();
+ } while (status);
+
+ return IRQ_HANDLED;
+}
+
+static int cxl_event_req_irq(struct cxl_dev_state *cxlds, u8 setting)
+{
+ struct device *dev = cxlds->dev;
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct cxl_dev_id *dev_id;
+ int irq;
+
+ if (FIELD_GET(CXLDEV_EVENT_INT_MODE_MASK, setting) != CXL_INT_MSI_MSIX)
+ return -ENXIO;
+
+ /* dev_id must be globally unique and must contain the cxlds */
+ dev_id = devm_kzalloc(dev, sizeof(*dev_id), GFP_KERNEL);
+ if (!dev_id)
+ return -ENOMEM;
+ dev_id->cxlds = cxlds;
+
+ irq = pci_irq_vector(pdev,
+ FIELD_GET(CXLDEV_EVENT_INT_MSGNUM_MASK, setting));
+ if (irq < 0)
+ return irq;
+
+ return devm_request_threaded_irq(dev, irq, NULL, cxl_event_thread,
+ IRQF_SHARED | IRQF_ONESHOT, NULL,
+ dev_id);
+}
+
+static int cxl_event_get_int_policy(struct cxl_dev_state *cxlds,
+ struct cxl_event_interrupt_policy *policy)
+{
+ struct cxl_mbox_cmd mbox_cmd = {
+ .opcode = CXL_MBOX_OP_GET_EVT_INT_POLICY,
+ .payload_out = policy,
+ .size_out = sizeof(*policy),
+ };
+ int rc;
+
+ rc = cxl_internal_send_cmd(cxlds, &mbox_cmd);
+ if (rc < 0)
+ dev_err(cxlds->dev, "Failed to get event interrupt policy : %d",
+ rc);
+
+ return rc;
+}
+
+static int cxl_event_config_msgnums(struct cxl_dev_state *cxlds,
+ struct cxl_event_interrupt_policy *policy)
+{
+ struct cxl_mbox_cmd mbox_cmd;
+ int rc;
+
+ *policy = (struct cxl_event_interrupt_policy) {
+ .info_settings = CXL_INT_MSI_MSIX,
+ .warn_settings = CXL_INT_MSI_MSIX,
+ .failure_settings = CXL_INT_MSI_MSIX,
+ .fatal_settings = CXL_INT_MSI_MSIX,
+ };
+
+ mbox_cmd = (struct cxl_mbox_cmd) {
+ .opcode = CXL_MBOX_OP_SET_EVT_INT_POLICY,
+ .payload_in = policy,
+ .size_in = sizeof(*policy),
+ };
+
+ rc = cxl_internal_send_cmd(cxlds, &mbox_cmd);
+ if (rc < 0) {
+ dev_err(cxlds->dev, "Failed to set event interrupt policy : %d",
+ rc);
+ return rc;
+ }
+
+ /* Retrieve final interrupt settings */
+ return cxl_event_get_int_policy(cxlds, policy);
+}
+
+static int cxl_event_irqsetup(struct cxl_dev_state *cxlds)
+{
+ struct cxl_event_interrupt_policy policy;
+ int rc;
+
+ rc = cxl_event_config_msgnums(cxlds, &policy);
+ if (rc)
+ return rc;
+
+ rc = cxl_event_req_irq(cxlds, policy.info_settings);
+ if (rc) {
+ dev_err(cxlds->dev, "Failed to get interrupt for event Info log\n");
+ return rc;
+ }
+
+ rc = cxl_event_req_irq(cxlds, policy.warn_settings);
+ if (rc) {
+ dev_err(cxlds->dev, "Failed to get interrupt for event Warn log\n");
+ return rc;
+ }
+
+ rc = cxl_event_req_irq(cxlds, policy.failure_settings);
+ if (rc) {
+ dev_err(cxlds->dev, "Failed to get interrupt for event Failure log\n");
+ return rc;
+ }
+
+ rc = cxl_event_req_irq(cxlds, policy.fatal_settings);
+ if (rc) {
+ dev_err(cxlds->dev, "Failed to get interrupt for event Fatal log\n");
+ return rc;
+ }
+
+ return 0;
+}
+
+static bool cxl_event_int_is_fw(u8 setting)
+{
+ u8 mode = FIELD_GET(CXLDEV_EVENT_INT_MODE_MASK, setting);
+
+ return mode == CXL_INT_FW;
+}
+
+static int cxl_event_config(struct pci_host_bridge *host_bridge,
+ struct cxl_dev_state *cxlds)
{
- pci_disable_pcie_error_reporting(pdev);
+ struct cxl_event_interrupt_policy policy;
+ int rc;
+
+ /*
+ * When BIOS maintains CXL error reporting control, it will process
+ * event records. Only one agent can do so.
+ */
+ if (!host_bridge->native_cxl_error)
+ return 0;
+
+ rc = cxl_mem_alloc_event_buf(cxlds);
+ if (rc)
+ return rc;
+
+ rc = cxl_event_get_int_policy(cxlds, &policy);
+ if (rc)
+ return rc;
+
+ if (cxl_event_int_is_fw(policy.info_settings) ||
+ cxl_event_int_is_fw(policy.warn_settings) ||
+ cxl_event_int_is_fw(policy.failure_settings) ||
+ cxl_event_int_is_fw(policy.fatal_settings)) {
+ dev_err(cxlds->dev, "FW still in control of Event Logs despite _OSC settings\n");
+ return -EBUSY;
+ }
+
+ rc = cxl_event_irqsetup(cxlds);
+ if (rc)
+ return rc;
+
+ cxl_mem_get_event_records(cxlds, CXLDEV_EVENT_STATUS_ALL);
+
+ return 0;
}
static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
+ struct pci_host_bridge *host_bridge = pci_find_host_bridge(pdev->bus);
struct cxl_register_map map;
struct cxl_memdev *cxlmd;
struct cxl_dev_state *cxlds;
@@ -436,6 +716,7 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
rc = pcim_enable_device(pdev);
if (rc)
return rc;
+ pci_set_master(pdev);
cxlds = cxl_dev_state_create(&pdev->dev);
if (IS_ERR(cxlds))
@@ -484,6 +765,10 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (rc)
return rc;
+ rc = cxl_set_timestamp(cxlds);
+ if (rc)
+ return rc;
+
rc = cxl_dev_state_identify(cxlds);
if (rc)
return rc;
@@ -492,16 +777,22 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (rc)
return rc;
+ rc = cxl_alloc_irq_vectors(pdev);
+ if (rc)
+ return rc;
+
cxlmd = devm_cxl_add_memdev(cxlds);
if (IS_ERR(cxlmd))
return PTR_ERR(cxlmd);
- if (cxlds->regs.ras) {
- pci_enable_pcie_error_reporting(pdev);
- rc = devm_add_action_or_reset(&pdev->dev, disable_aer, pdev);
- if (rc)
- return rc;
- }
+ rc = cxl_event_config(host_bridge, cxlds);
+ if (rc)
+ return rc;
+
+ rc = cxl_pci_ras_unmask(pdev);
+ if (rc)
+ dev_dbg(&pdev->dev, "No RAS reporting unmasked\n");
+
pci_save_state(pdev);
return rc;
@@ -514,99 +805,6 @@ static const struct pci_device_id cxl_mem_pci_tbl[] = {
};
MODULE_DEVICE_TABLE(pci, cxl_mem_pci_tbl);
-/* CXL spec rev3.0 8.2.4.16.1 */
-static void header_log_copy(struct cxl_dev_state *cxlds, u32 *log)
-{
- void __iomem *addr;
- u32 *log_addr;
- int i, log_u32_size = CXL_HEADERLOG_SIZE / sizeof(u32);
-
- addr = cxlds->regs.ras + CXL_RAS_HEADER_LOG_OFFSET;
- log_addr = log;
-
- for (i = 0; i < log_u32_size; i++) {
- *log_addr = readl(addr);
- log_addr++;
- addr += sizeof(u32);
- }
-}
-
-/*
- * Log the state of the RAS status registers and prepare them to log the
- * next error status. Return 1 if reset needed.
- */
-static bool cxl_report_and_clear(struct cxl_dev_state *cxlds)
-{
- struct cxl_memdev *cxlmd = cxlds->cxlmd;
- struct device *dev = &cxlmd->dev;
- u32 hl[CXL_HEADERLOG_SIZE_U32];
- void __iomem *addr;
- u32 status;
- u32 fe;
-
- if (!cxlds->regs.ras)
- return false;
-
- addr = cxlds->regs.ras + CXL_RAS_UNCORRECTABLE_STATUS_OFFSET;
- status = readl(addr);
- if (!(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK))
- return false;
-
- /* If multiple errors, log header points to first error from ctrl reg */
- if (hweight32(status) > 1) {
- void __iomem *rcc_addr =
- cxlds->regs.ras + CXL_RAS_CAP_CONTROL_OFFSET;
-
- fe = BIT(FIELD_GET(CXL_RAS_CAP_CONTROL_FE_MASK,
- readl(rcc_addr)));
- } else {
- fe = status;
- }
-
- header_log_copy(cxlds, hl);
- trace_cxl_aer_uncorrectable_error(dev, status, fe, hl);
- writel(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK, addr);
-
- return true;
-}
-
-static pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
- pci_channel_state_t state)
-{
- struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
- struct cxl_memdev *cxlmd = cxlds->cxlmd;
- struct device *dev = &cxlmd->dev;
- bool ue;
-
- /*
- * A frozen channel indicates an impending reset which is fatal to
- * CXL.mem operation, and will likely crash the system. On the off
- * chance the situation is recoverable dump the status of the RAS
- * capability registers and bounce the active state of the memdev.
- */
- ue = cxl_report_and_clear(cxlds);
-
- switch (state) {
- case pci_channel_io_normal:
- if (ue) {
- device_release_driver(dev);
- return PCI_ERS_RESULT_NEED_RESET;
- }
- return PCI_ERS_RESULT_CAN_RECOVER;
- case pci_channel_io_frozen:
- dev_warn(&pdev->dev,
- "%s: frozen state error detected, disable CXL.mem\n",
- dev_name(dev));
- device_release_driver(dev);
- return PCI_ERS_RESULT_NEED_RESET;
- case pci_channel_io_perm_failure:
- dev_warn(&pdev->dev,
- "failure state error detected, request disconnect\n");
- return PCI_ERS_RESULT_DISCONNECT;
- }
- return PCI_ERS_RESULT_NEED_RESET;
-}
-
static pci_ers_result_t cxl_slot_reset(struct pci_dev *pdev)
{
struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
@@ -631,25 +829,6 @@ static void cxl_error_resume(struct pci_dev *pdev)
dev->driver ? "successful" : "failed");
}
-static void cxl_cor_error_detected(struct pci_dev *pdev)
-{
- struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
- struct cxl_memdev *cxlmd = cxlds->cxlmd;
- struct device *dev = &cxlmd->dev;
- void __iomem *addr;
- u32 status;
-
- if (!cxlds->regs.ras)
- return;
-
- addr = cxlds->regs.ras + CXL_RAS_CORRECTABLE_STATUS_OFFSET;
- status = readl(addr);
- if (status & CXL_RAS_CORRECTABLE_STATUS_MASK) {
- writel(status & CXL_RAS_CORRECTABLE_STATUS_MASK, addr);
- trace_cxl_aer_correctable_error(dev, status);
- }
-}
-
static const struct pci_error_handlers cxl_error_handlers = {
.error_detected = cxl_error_detected,
.slot_reset = cxl_slot_reset,
diff --git a/drivers/cxl/pmem.c b/drivers/cxl/pmem.c
index 08bbbac9a6d0..71cfa1fdf902 100644
--- a/drivers/cxl/pmem.c
+++ b/drivers/cxl/pmem.c
@@ -76,6 +76,7 @@ static int cxl_nvdimm_probe(struct device *dev)
return rc;
set_bit(NDD_LABELING, &flags);
+ set_bit(NDD_REGISTER_SYNC, &flags);
set_bit(ND_CMD_GET_CONFIG_SIZE, &cmd_mask);
set_bit(ND_CMD_GET_CONFIG_DATA, &cmd_mask);
set_bit(ND_CMD_SET_CONFIG_DATA, &cmd_mask);
diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
index 5453771bf330..1049bb5ea496 100644
--- a/drivers/cxl/port.c
+++ b/drivers/cxl/port.c
@@ -30,57 +30,116 @@ static void schedule_detach(void *cxlmd)
schedule_cxl_memdev_detach(cxlmd);
}
-static int cxl_port_probe(struct device *dev)
+static int discover_region(struct device *dev, void *root)
+{
+ struct cxl_endpoint_decoder *cxled;
+ int rc;
+
+ if (!is_endpoint_decoder(dev))
+ return 0;
+
+ cxled = to_cxl_endpoint_decoder(dev);
+ if ((cxled->cxld.flags & CXL_DECODER_F_ENABLE) == 0)
+ return 0;
+
+ if (cxled->state != CXL_DECODER_STATE_AUTO)
+ return 0;
+
+ /*
+ * Region enumeration is opportunistic, if this add-event fails,
+ * continue to the next endpoint decoder.
+ */
+ rc = cxl_add_to_region(root, cxled);
+ if (rc)
+ dev_dbg(dev, "failed to add to region: %#llx-%#llx\n",
+ cxled->cxld.hpa_range.start, cxled->cxld.hpa_range.end);
+
+ return 0;
+}
+
+static int cxl_switch_port_probe(struct cxl_port *port)
{
- struct cxl_port *port = to_cxl_port(dev);
struct cxl_hdm *cxlhdm;
int rc;
+ rc = devm_cxl_port_enumerate_dports(port);
+ if (rc < 0)
+ return rc;
- if (!is_cxl_endpoint(port)) {
- rc = devm_cxl_port_enumerate_dports(port);
- if (rc < 0)
- return rc;
- if (rc == 1)
- return devm_cxl_add_passthrough_decoder(port);
- }
+ if (rc == 1)
+ return devm_cxl_add_passthrough_decoder(port);
- cxlhdm = devm_cxl_setup_hdm(port);
+ cxlhdm = devm_cxl_setup_hdm(port, NULL);
if (IS_ERR(cxlhdm))
return PTR_ERR(cxlhdm);
- if (is_cxl_endpoint(port)) {
- struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport);
- struct cxl_dev_state *cxlds = cxlmd->cxlds;
+ return devm_cxl_enumerate_decoders(cxlhdm, NULL);
+}
- /* Cache the data early to ensure is_visible() works */
- read_cdat_data(port);
+static int cxl_endpoint_port_probe(struct cxl_port *port)
+{
+ struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport);
+ struct cxl_endpoint_dvsec_info info = { 0 };
+ struct cxl_dev_state *cxlds = cxlmd->cxlds;
+ struct cxl_hdm *cxlhdm;
+ struct cxl_port *root;
+ int rc;
- get_device(&cxlmd->dev);
- rc = devm_add_action_or_reset(dev, schedule_detach, cxlmd);
- if (rc)
- return rc;
+ rc = cxl_dvsec_rr_decode(cxlds->dev, cxlds->cxl_dvsec, &info);
+ if (rc < 0)
+ return rc;
- rc = cxl_hdm_decode_init(cxlds, cxlhdm);
- if (rc)
- return rc;
+ cxlhdm = devm_cxl_setup_hdm(port, &info);
+ if (IS_ERR(cxlhdm))
+ return PTR_ERR(cxlhdm);
- rc = cxl_await_media_ready(cxlds);
- if (rc) {
- dev_err(dev, "Media not active (%d)\n", rc);
- return rc;
- }
- }
+ /* Cache the data early to ensure is_visible() works */
+ read_cdat_data(port);
- rc = devm_cxl_enumerate_decoders(cxlhdm);
+ get_device(&cxlmd->dev);
+ rc = devm_add_action_or_reset(&port->dev, schedule_detach, cxlmd);
+ if (rc)
+ return rc;
+
+ rc = cxl_hdm_decode_init(cxlds, cxlhdm, &info);
+ if (rc)
+ return rc;
+
+ rc = cxl_await_media_ready(cxlds);
if (rc) {
- dev_err(dev, "Couldn't enumerate decoders (%d)\n", rc);
+ dev_err(&port->dev, "Media not active (%d)\n", rc);
return rc;
}
+ rc = devm_cxl_enumerate_decoders(cxlhdm, &info);
+ if (rc)
+ return rc;
+
+ /*
+ * This can't fail in practice as CXL root exit unregisters all
+ * descendant ports and that in turn synchronizes with cxl_port_probe()
+ */
+ root = find_cxl_root(&cxlmd->dev);
+
+ /*
+ * Now that all endpoint decoders are successfully enumerated, try to
+ * assemble regions from committed decoders
+ */
+ device_for_each_child(&port->dev, root, discover_region);
+ put_device(&root->dev);
+
return 0;
}
+static int cxl_port_probe(struct device *dev)
+{
+ struct cxl_port *port = to_cxl_port(dev);
+
+ if (is_cxl_endpoint(port))
+ return cxl_endpoint_port_probe(port);
+ return cxl_switch_port_probe(port);
+}
+
static ssize_t CDAT_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr, char *buf,
loff_t offset, size_t count)
diff --git a/drivers/dax/Kconfig b/drivers/dax/Kconfig
index 2bf5123e4827..a88744244149 100644
--- a/drivers/dax/Kconfig
+++ b/drivers/dax/Kconfig
@@ -44,12 +44,25 @@ config DEV_DAX_HMEM
Say M if unsure.
+config DEV_DAX_CXL
+ tristate "CXL DAX: direct access to CXL RAM regions"
+ depends on CXL_BUS && CXL_REGION && DEV_DAX
+ default CXL_REGION && DEV_DAX
+ help
+ CXL RAM regions are either mapped by platform-firmware
+ and published in the initial system-memory map as "System RAM", mapped
+ by platform-firmware as "Soft Reserved", or dynamically provisioned
+ after boot by the CXL driver. In the latter two cases a device-dax
+ instance is created to access that unmapped-by-default address range.
+ Per usual it can remain as dedicated access via a device interface, or
+ converted to "System RAM" via the dax_kmem facility.
+
config DEV_DAX_HMEM_DEVICES
- depends on DEV_DAX_HMEM && DAX=y
+ depends on DEV_DAX_HMEM && DAX
def_bool y
config DEV_DAX_KMEM
- tristate "KMEM DAX: volatile-use of persistent memory"
+ tristate "KMEM DAX: map dax-devices as System-RAM"
default DEV_DAX
depends on DEV_DAX
depends on MEMORY_HOTPLUG # for add_memory() and friends
diff --git a/drivers/dax/Makefile b/drivers/dax/Makefile
index 90a56ca3b345..5ed5c39857c8 100644
--- a/drivers/dax/Makefile
+++ b/drivers/dax/Makefile
@@ -3,10 +3,12 @@ obj-$(CONFIG_DAX) += dax.o
obj-$(CONFIG_DEV_DAX) += device_dax.o
obj-$(CONFIG_DEV_DAX_KMEM) += kmem.o
obj-$(CONFIG_DEV_DAX_PMEM) += dax_pmem.o
+obj-$(CONFIG_DEV_DAX_CXL) += dax_cxl.o
dax-y := super.o
dax-y += bus.o
device_dax-y := device.o
dax_pmem-y := pmem.o
+dax_cxl-y := cxl.o
obj-y += hmem/
diff --git a/drivers/dax/bus.c b/drivers/dax/bus.c
index 1dad813ee4a6..227800053309 100644
--- a/drivers/dax/bus.c
+++ b/drivers/dax/bus.c
@@ -18,7 +18,7 @@ struct dax_id {
char dev_name[DAX_NAME_LEN];
};
-static int dax_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int dax_bus_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
/*
* We only ever expect to handle device-dax instances, i.e. the
@@ -56,6 +56,25 @@ static int dax_match_id(struct dax_device_driver *dax_drv, struct device *dev)
return match;
}
+static int dax_match_type(struct dax_device_driver *dax_drv, struct device *dev)
+{
+ enum dax_driver_type type = DAXDRV_DEVICE_TYPE;
+ struct dev_dax *dev_dax = to_dev_dax(dev);
+
+ if (dev_dax->region->res.flags & IORESOURCE_DAX_KMEM)
+ type = DAXDRV_KMEM_TYPE;
+
+ if (dax_drv->type == type)
+ return 1;
+
+ /* default to device mode if dax_kmem is disabled */
+ if (dax_drv->type == DAXDRV_DEVICE_TYPE &&
+ !IS_ENABLED(CONFIG_DEV_DAX_KMEM))
+ return 1;
+
+ return 0;
+}
+
enum id_action {
ID_REMOVE,
ID_ADD,
@@ -216,14 +235,9 @@ static int dax_bus_match(struct device *dev, struct device_driver *drv)
{
struct dax_device_driver *dax_drv = to_dax_drv(drv);
- /*
- * All but the 'device-dax' driver, which has 'match_always'
- * set, requires an exact id match.
- */
- if (dax_drv->match_always)
+ if (dax_match_id(dax_drv, dev))
return 1;
-
- return dax_match_id(dax_drv, dev);
+ return dax_match_type(dax_drv, dev);
}
/*
@@ -427,8 +441,8 @@ static void unregister_dev_dax(void *dev)
dev_dbg(dev, "%s\n", __func__);
kill_dev_dax(dev_dax);
- free_dev_dax_ranges(dev_dax);
device_del(dev);
+ free_dev_dax_ranges(dev_dax);
put_device(dev);
}
@@ -1413,13 +1427,10 @@ err_id:
}
EXPORT_SYMBOL_GPL(devm_create_dev_dax);
-static int match_always_count;
-
int __dax_driver_register(struct dax_device_driver *dax_drv,
struct module *module, const char *mod_name)
{
struct device_driver *drv = &dax_drv->drv;
- int rc = 0;
/*
* dax_bus_probe() calls dax_drv->probe() unconditionally.
@@ -1434,26 +1445,7 @@ int __dax_driver_register(struct dax_device_driver *dax_drv,
drv->mod_name = mod_name;
drv->bus = &dax_bus_type;
- /* there can only be one default driver */
- mutex_lock(&dax_bus_lock);
- match_always_count += dax_drv->match_always;
- if (match_always_count > 1) {
- match_always_count--;
- WARN_ON(1);
- rc = -EINVAL;
- }
- mutex_unlock(&dax_bus_lock);
- if (rc)
- return rc;
-
- rc = driver_register(drv);
- if (rc && dax_drv->match_always) {
- mutex_lock(&dax_bus_lock);
- match_always_count -= dax_drv->match_always;
- mutex_unlock(&dax_bus_lock);
- }
-
- return rc;
+ return driver_register(drv);
}
EXPORT_SYMBOL_GPL(__dax_driver_register);
@@ -1463,7 +1455,6 @@ void dax_driver_unregister(struct dax_device_driver *dax_drv)
struct dax_id *dax_id, *_id;
mutex_lock(&dax_bus_lock);
- match_always_count -= dax_drv->match_always;
list_for_each_entry_safe(dax_id, _id, &dax_drv->ids, list) {
list_del(&dax_id->list);
kfree(dax_id);
diff --git a/drivers/dax/bus.h b/drivers/dax/bus.h
index fbb940293d6d..8cd79ab34292 100644
--- a/drivers/dax/bus.h
+++ b/drivers/dax/bus.h
@@ -11,7 +11,10 @@ struct dax_device;
struct dax_region;
void dax_region_put(struct dax_region *dax_region);
-#define IORESOURCE_DAX_STATIC (1UL << 0)
+/* dax bus specific ioresource flags */
+#define IORESOURCE_DAX_STATIC BIT(0)
+#define IORESOURCE_DAX_KMEM BIT(1)
+
struct dax_region *alloc_dax_region(struct device *parent, int region_id,
struct range *range, int target_node, unsigned int align,
unsigned long flags);
@@ -25,10 +28,15 @@ struct dev_dax_data {
struct dev_dax *devm_create_dev_dax(struct dev_dax_data *data);
+enum dax_driver_type {
+ DAXDRV_KMEM_TYPE,
+ DAXDRV_DEVICE_TYPE,
+};
+
struct dax_device_driver {
struct device_driver drv;
struct list_head ids;
- int match_always;
+ enum dax_driver_type type;
int (*probe)(struct dev_dax *dev);
void (*remove)(struct dev_dax *dev);
};
diff --git a/drivers/dax/cxl.c b/drivers/dax/cxl.c
new file mode 100644
index 000000000000..ccdf8de85bd5
--- /dev/null
+++ b/drivers/dax/cxl.c
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(c) 2023 Intel Corporation. All rights reserved. */
+#include <linux/module.h>
+#include <linux/dax.h>
+
+#include "../cxl/cxl.h"
+#include "bus.h"
+
+static int cxl_dax_region_probe(struct device *dev)
+{
+ struct cxl_dax_region *cxlr_dax = to_cxl_dax_region(dev);
+ int nid = phys_to_target_node(cxlr_dax->hpa_range.start);
+ struct cxl_region *cxlr = cxlr_dax->cxlr;
+ struct dax_region *dax_region;
+ struct dev_dax_data data;
+ struct dev_dax *dev_dax;
+
+ if (nid == NUMA_NO_NODE)
+ nid = memory_add_physaddr_to_nid(cxlr_dax->hpa_range.start);
+
+ dax_region = alloc_dax_region(dev, cxlr->id, &cxlr_dax->hpa_range, nid,
+ PMD_SIZE, IORESOURCE_DAX_KMEM);
+ if (!dax_region)
+ return -ENOMEM;
+
+ data = (struct dev_dax_data) {
+ .dax_region = dax_region,
+ .id = -1,
+ .size = range_len(&cxlr_dax->hpa_range),
+ };
+ dev_dax = devm_create_dev_dax(&data);
+ if (IS_ERR(dev_dax))
+ return PTR_ERR(dev_dax);
+
+ /* child dev_dax instances now own the lifetime of the dax_region */
+ dax_region_put(dax_region);
+ return 0;
+}
+
+static struct cxl_driver cxl_dax_region_driver = {
+ .name = "cxl_dax_region",
+ .probe = cxl_dax_region_probe,
+ .id = CXL_DEVICE_DAX_REGION,
+ .drv = {
+ .suppress_bind_attrs = true,
+ },
+};
+
+module_cxl_driver(cxl_dax_region_driver);
+MODULE_ALIAS_CXL(CXL_DEVICE_DAX_REGION);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Intel Corporation");
+MODULE_IMPORT_NS(CXL);
diff --git a/drivers/dax/device.c b/drivers/dax/device.c
index 5494d745ced5..af9930c03c9c 100644
--- a/drivers/dax/device.c
+++ b/drivers/dax/device.c
@@ -308,7 +308,7 @@ static int dax_mmap(struct file *filp, struct vm_area_struct *vma)
return rc;
vma->vm_ops = &dax_vm_ops;
- vma->vm_flags |= VM_HUGEPAGE;
+ vm_flags_set(vma, VM_HUGEPAGE);
return 0;
}
@@ -475,8 +475,7 @@ EXPORT_SYMBOL_GPL(dev_dax_probe);
static struct dax_device_driver device_dax_driver = {
.probe = dev_dax_probe,
- /* all probe actions are unwound by devm, so .remove isn't necessary */
- .match_always = 1,
+ .type = DAXDRV_DEVICE_TYPE,
};
static int __init dax_init(void)
diff --git a/drivers/dax/hmem/Makefile b/drivers/dax/hmem/Makefile
index 57377b4c3d47..d4c4cd6bccd7 100644
--- a/drivers/dax/hmem/Makefile
+++ b/drivers/dax/hmem/Makefile
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_DEV_DAX_HMEM) += dax_hmem.o
+# device_hmem.o deliberately precedes dax_hmem.o for initcall ordering
obj-$(CONFIG_DEV_DAX_HMEM_DEVICES) += device_hmem.o
+obj-$(CONFIG_DEV_DAX_HMEM) += dax_hmem.o
device_hmem-y := device.o
dax_hmem-y := hmem.o
diff --git a/drivers/dax/hmem/device.c b/drivers/dax/hmem/device.c
index 903325aac991..f9e1a76a04a9 100644
--- a/drivers/dax/hmem/device.c
+++ b/drivers/dax/hmem/device.c
@@ -8,6 +8,8 @@
static bool nohmem;
module_param_named(disable, nohmem, bool, 0444);
+static bool platform_initialized;
+static DEFINE_MUTEX(hmem_resource_lock);
static struct resource hmem_active = {
.name = "HMEM devices",
.start = 0,
@@ -15,80 +17,66 @@ static struct resource hmem_active = {
.flags = IORESOURCE_MEM,
};
-void hmem_register_device(int target_nid, struct resource *r)
+int walk_hmem_resources(struct device *host, walk_hmem_fn fn)
+{
+ struct resource *res;
+ int rc = 0;
+
+ mutex_lock(&hmem_resource_lock);
+ for (res = hmem_active.child; res; res = res->sibling) {
+ rc = fn(host, (int) res->desc, res);
+ if (rc)
+ break;
+ }
+ mutex_unlock(&hmem_resource_lock);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(walk_hmem_resources);
+
+static void __hmem_register_resource(int target_nid, struct resource *res)
{
- /* define a clean / non-busy resource for the platform device */
- struct resource res = {
- .start = r->start,
- .end = r->end,
- .flags = IORESOURCE_MEM,
- .desc = IORES_DESC_SOFT_RESERVED,
- };
struct platform_device *pdev;
- struct memregion_info info;
- int rc, id;
+ struct resource *new;
+ int rc;
- if (nohmem)
+ new = __request_region(&hmem_active, res->start, resource_size(res), "",
+ 0);
+ if (!new) {
+ pr_debug("hmem range %pr already active\n", res);
return;
+ }
- rc = region_intersects(res.start, resource_size(&res), IORESOURCE_MEM,
- IORES_DESC_SOFT_RESERVED);
- if (rc != REGION_INTERSECTS)
- return;
+ new->desc = target_nid;
- id = memregion_alloc(GFP_KERNEL);
- if (id < 0) {
- pr_err("memregion allocation failure for %pr\n", &res);
+ if (platform_initialized)
return;
- }
- pdev = platform_device_alloc("hmem", id);
+ pdev = platform_device_alloc("hmem_platform", 0);
if (!pdev) {
- pr_err("hmem device allocation failure for %pr\n", &res);
- goto out_pdev;
- }
-
- if (!__request_region(&hmem_active, res.start, resource_size(&res),
- dev_name(&pdev->dev), 0)) {
- dev_dbg(&pdev->dev, "hmem range %pr already active\n", &res);
- goto out_active;
- }
-
- pdev->dev.numa_node = numa_map_to_online_node(target_nid);
- info = (struct memregion_info) {
- .target_node = target_nid,
- };
- rc = platform_device_add_data(pdev, &info, sizeof(info));
- if (rc < 0) {
- pr_err("hmem memregion_info allocation failure for %pr\n", &res);
- goto out_resource;
- }
-
- rc = platform_device_add_resources(pdev, &res, 1);
- if (rc < 0) {
- pr_err("hmem resource allocation failure for %pr\n", &res);
- goto out_resource;
+ pr_err_once("failed to register device-dax hmem_platform device\n");
+ return;
}
rc = platform_device_add(pdev);
- if (rc < 0) {
- dev_err(&pdev->dev, "device add failed for %pr\n", &res);
- goto out_resource;
- }
+ if (rc)
+ platform_device_put(pdev);
+ else
+ platform_initialized = true;
+}
- return;
+void hmem_register_resource(int target_nid, struct resource *res)
+{
+ if (nohmem)
+ return;
-out_resource:
- __release_region(&hmem_active, res.start, resource_size(&res));
-out_active:
- platform_device_put(pdev);
-out_pdev:
- memregion_free(id);
+ mutex_lock(&hmem_resource_lock);
+ __hmem_register_resource(target_nid, res);
+ mutex_unlock(&hmem_resource_lock);
}
static __init int hmem_register_one(struct resource *res, void *data)
{
- hmem_register_device(phys_to_target_node(res->start), res);
+ hmem_register_resource(phys_to_target_node(res->start), res);
return 0;
}
@@ -104,4 +92,4 @@ static __init int hmem_init(void)
* As this is a fallback for address ranges unclaimed by the ACPI HMAT
* parsing it must be at an initcall level greater than hmat_init().
*/
-late_initcall(hmem_init);
+device_initcall(hmem_init);
diff --git a/drivers/dax/hmem/hmem.c b/drivers/dax/hmem/hmem.c
index 1bf040dbc834..e5fe8b39fb94 100644
--- a/drivers/dax/hmem/hmem.c
+++ b/drivers/dax/hmem/hmem.c
@@ -3,6 +3,7 @@
#include <linux/memregion.h>
#include <linux/module.h>
#include <linux/pfn_t.h>
+#include <linux/dax.h>
#include "../bus.h"
static bool region_idle;
@@ -10,30 +11,32 @@ module_param_named(region_idle, region_idle, bool, 0644);
static int dax_hmem_probe(struct platform_device *pdev)
{
+ unsigned long flags = IORESOURCE_DAX_KMEM;
struct device *dev = &pdev->dev;
struct dax_region *dax_region;
struct memregion_info *mri;
struct dev_dax_data data;
struct dev_dax *dev_dax;
- struct resource *res;
- struct range range;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENOMEM;
+ /*
+ * @region_idle == true indicates that an administrative agent
+ * wants to manipulate the range partitioning before the devices
+ * are created, so do not send them to the dax_kmem driver by
+ * default.
+ */
+ if (region_idle)
+ flags = 0;
mri = dev->platform_data;
- range.start = res->start;
- range.end = res->end;
- dax_region = alloc_dax_region(dev, pdev->id, &range, mri->target_node,
- PMD_SIZE, 0);
+ dax_region = alloc_dax_region(dev, pdev->id, &mri->range,
+ mri->target_node, PMD_SIZE, flags);
if (!dax_region)
return -ENOMEM;
data = (struct dev_dax_data) {
.dax_region = dax_region,
.id = -1,
- .size = region_idle ? 0 : resource_size(res),
+ .size = region_idle ? 0 : range_len(&mri->range),
};
dev_dax = devm_create_dev_dax(&data);
if (IS_ERR(dev_dax))
@@ -44,22 +47,131 @@ static int dax_hmem_probe(struct platform_device *pdev)
return 0;
}
-static int dax_hmem_remove(struct platform_device *pdev)
-{
- /* devm handles teardown */
- return 0;
-}
-
static struct platform_driver dax_hmem_driver = {
.probe = dax_hmem_probe,
- .remove = dax_hmem_remove,
.driver = {
.name = "hmem",
},
};
-module_platform_driver(dax_hmem_driver);
+static void release_memregion(void *data)
+{
+ memregion_free((long) data);
+}
+
+static void release_hmem(void *pdev)
+{
+ platform_device_unregister(pdev);
+}
+
+static int hmem_register_device(struct device *host, int target_nid,
+ const struct resource *res)
+{
+ struct platform_device *pdev;
+ struct memregion_info info;
+ long id;
+ int rc;
+
+ if (IS_ENABLED(CONFIG_CXL_REGION) &&
+ region_intersects(res->start, resource_size(res), IORESOURCE_MEM,
+ IORES_DESC_CXL) != REGION_DISJOINT) {
+ dev_dbg(host, "deferring range to CXL: %pr\n", res);
+ return 0;
+ }
+
+ rc = region_intersects(res->start, resource_size(res), IORESOURCE_MEM,
+ IORES_DESC_SOFT_RESERVED);
+ if (rc != REGION_INTERSECTS)
+ return 0;
+
+ id = memregion_alloc(GFP_KERNEL);
+ if (id < 0) {
+ dev_err(host, "memregion allocation failure for %pr\n", res);
+ return -ENOMEM;
+ }
+ rc = devm_add_action_or_reset(host, release_memregion, (void *) id);
+ if (rc)
+ return rc;
+
+ pdev = platform_device_alloc("hmem", id);
+ if (!pdev) {
+ dev_err(host, "device allocation failure for %pr\n", res);
+ return -ENOMEM;
+ }
+
+ pdev->dev.numa_node = numa_map_to_online_node(target_nid);
+ info = (struct memregion_info) {
+ .target_node = target_nid,
+ .range = {
+ .start = res->start,
+ .end = res->end,
+ },
+ };
+ rc = platform_device_add_data(pdev, &info, sizeof(info));
+ if (rc < 0) {
+ dev_err(host, "memregion_info allocation failure for %pr\n",
+ res);
+ goto out_put;
+ }
+
+ rc = platform_device_add(pdev);
+ if (rc < 0) {
+ dev_err(host, "%s add failed for %pr\n", dev_name(&pdev->dev),
+ res);
+ goto out_put;
+ }
+
+ return devm_add_action_or_reset(host, release_hmem, pdev);
+
+out_put:
+ platform_device_put(pdev);
+ return rc;
+}
+
+static int dax_hmem_platform_probe(struct platform_device *pdev)
+{
+ return walk_hmem_resources(&pdev->dev, hmem_register_device);
+}
+
+static struct platform_driver dax_hmem_platform_driver = {
+ .probe = dax_hmem_platform_probe,
+ .driver = {
+ .name = "hmem_platform",
+ },
+};
+
+static __init int dax_hmem_init(void)
+{
+ int rc;
+
+ rc = platform_driver_register(&dax_hmem_platform_driver);
+ if (rc)
+ return rc;
+
+ rc = platform_driver_register(&dax_hmem_driver);
+ if (rc)
+ platform_driver_unregister(&dax_hmem_platform_driver);
+
+ return rc;
+}
+
+static __exit void dax_hmem_exit(void)
+{
+ platform_driver_unregister(&dax_hmem_driver);
+ platform_driver_unregister(&dax_hmem_platform_driver);
+}
+
+module_init(dax_hmem_init);
+module_exit(dax_hmem_exit);
+
+/* Allow for CXL to define its own dax regions */
+#if IS_ENABLED(CONFIG_CXL_REGION)
+#if IS_MODULE(CONFIG_CXL_ACPI)
+MODULE_SOFTDEP("pre: cxl_acpi");
+#endif
+#endif
MODULE_ALIAS("platform:hmem*");
+MODULE_ALIAS("platform:hmem_platform*");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Intel Corporation");
diff --git a/drivers/dax/kmem.c b/drivers/dax/kmem.c
index 4852a2dbdb27..7b36db6f1cbd 100644
--- a/drivers/dax/kmem.c
+++ b/drivers/dax/kmem.c
@@ -146,7 +146,7 @@ static int dev_dax_kmem_probe(struct dev_dax *dev_dax)
if (rc) {
dev_warn(dev, "mapping%d: %#llx-%#llx memory add failed\n",
i, range.start, range.end);
- release_resource(res);
+ remove_resource(res);
kfree(res);
data->res[i] = NULL;
if (mapped)
@@ -195,7 +195,7 @@ static void dev_dax_kmem_remove(struct dev_dax *dev_dax)
rc = remove_memory(range.start, range_len(&range));
if (rc == 0) {
- release_resource(data->res[i]);
+ remove_resource(data->res[i]);
kfree(data->res[i]);
data->res[i] = NULL;
success++;
@@ -239,6 +239,7 @@ static void dev_dax_kmem_remove(struct dev_dax *dev_dax)
static struct dax_device_driver device_dax_kmem_driver = {
.probe = dev_dax_kmem_probe,
.remove = dev_dax_kmem_remove,
+ .type = DAXDRV_KMEM_TYPE,
};
static int __init dax_kmem_init(void)
diff --git a/drivers/dma-buf/dma-buf-sysfs-stats.c b/drivers/dma-buf/dma-buf-sysfs-stats.c
index fbf725fae7c1..6cfbbf0720bd 100644
--- a/drivers/dma-buf/dma-buf-sysfs-stats.c
+++ b/drivers/dma-buf/dma-buf-sysfs-stats.c
@@ -112,7 +112,7 @@ static void dma_buf_sysfs_release(struct kobject *kobj)
kfree(sysfs_entry);
}
-static struct kobj_type dma_buf_ktype = {
+static const struct kobj_type dma_buf_ktype = {
.sysfs_ops = &dma_buf_stats_sysfs_ops,
.release = dma_buf_sysfs_release,
.default_groups = dma_buf_stats_default_groups,
diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
index e6528767efc7..757c0fb77a6c 100644
--- a/drivers/dma-buf/dma-buf.c
+++ b/drivers/dma-buf/dma-buf.c
@@ -1257,7 +1257,7 @@ EXPORT_SYMBOL_NS_GPL(dma_buf_unmap_attachment_unlocked, DMA_BUF);
*
* @dmabuf: [in] buffer which is moving
*
- * Informs all attachmenst that they need to destroy and recreated all their
+ * Informs all attachments that they need to destroy and recreate all their
* mappings.
*/
void dma_buf_move_notify(struct dma_buf *dmabuf)
@@ -1275,11 +1275,11 @@ EXPORT_SYMBOL_NS_GPL(dma_buf_move_notify, DMA_BUF);
/**
* DOC: cpu access
*
- * There are mutliple reasons for supporting CPU access to a dma buffer object:
+ * There are multiple reasons for supporting CPU access to a dma buffer object:
*
* - Fallback operations in the kernel, for example when a device is connected
* over USB and the kernel needs to shuffle the data around first before
- * sending it away. Cache coherency is handled by braketing any transactions
+ * sending it away. Cache coherency is handled by bracketing any transactions
* with calls to dma_buf_begin_cpu_access() and dma_buf_end_cpu_access()
* access.
*
@@ -1306,7 +1306,7 @@ EXPORT_SYMBOL_NS_GPL(dma_buf_move_notify, DMA_BUF);
* replace ION buffers mmap support was needed.
*
* There is no special interfaces, userspace simply calls mmap on the dma-buf
- * fd. But like for CPU access there's a need to braket the actual access,
+ * fd. But like for CPU access there's a need to bracket the actual access,
* which is handled by the ioctl (DMA_BUF_IOCTL_SYNC). Note that
* DMA_BUF_IOCTL_SYNC can fail with -EAGAIN or -EINTR, in which case it must
* be restarted.
@@ -1380,10 +1380,10 @@ static int __dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
* preparations. Coherency is only guaranteed in the specified range for the
* specified access direction.
* @dmabuf: [in] buffer to prepare cpu access for.
- * @direction: [in] length of range for cpu access.
+ * @direction: [in] direction of access.
*
* After the cpu access is complete the caller should call
- * dma_buf_end_cpu_access(). Only when cpu access is braketed by both calls is
+ * dma_buf_end_cpu_access(). Only when cpu access is bracketed by both calls is
* it guaranteed to be coherent with other DMA access.
*
* This function will also wait for any DMA transactions tracked through
@@ -1423,7 +1423,7 @@ EXPORT_SYMBOL_NS_GPL(dma_buf_begin_cpu_access, DMA_BUF);
* actions. Coherency is only guaranteed in the specified range for the
* specified access direction.
* @dmabuf: [in] buffer to complete cpu access for.
- * @direction: [in] length of range for cpu access.
+ * @direction: [in] direction of access.
*
* This terminates CPU access started with dma_buf_begin_cpu_access().
*
diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c
index 283816fbd72f..740d6e426ee9 100644
--- a/drivers/dma-buf/udmabuf.c
+++ b/drivers/dma-buf/udmabuf.c
@@ -13,6 +13,8 @@
#include <linux/slab.h>
#include <linux/udmabuf.h>
#include <linux/hugetlb.h>
+#include <linux/vmalloc.h>
+#include <linux/iosys-map.h>
static int list_limit = 1024;
module_param(list_limit, int, 0644);
@@ -60,6 +62,30 @@ static int mmap_udmabuf(struct dma_buf *buf, struct vm_area_struct *vma)
return 0;
}
+static int vmap_udmabuf(struct dma_buf *buf, struct iosys_map *map)
+{
+ struct udmabuf *ubuf = buf->priv;
+ void *vaddr;
+
+ dma_resv_assert_held(buf->resv);
+
+ vaddr = vm_map_ram(ubuf->pages, ubuf->pagecount, -1);
+ if (!vaddr)
+ return -EINVAL;
+
+ iosys_map_set_vaddr(map, vaddr);
+ return 0;
+}
+
+static void vunmap_udmabuf(struct dma_buf *buf, struct iosys_map *map)
+{
+ struct udmabuf *ubuf = buf->priv;
+
+ dma_resv_assert_held(buf->resv);
+
+ vm_unmap_ram(map->vaddr, ubuf->pagecount);
+}
+
static struct sg_table *get_sg_table(struct device *dev, struct dma_buf *buf,
enum dma_data_direction direction)
{
@@ -162,6 +188,8 @@ static const struct dma_buf_ops udmabuf_ops = {
.unmap_dma_buf = unmap_udmabuf,
.release = release_udmabuf,
.mmap = mmap_udmabuf,
+ .vmap = vmap_udmabuf,
+ .vunmap = vunmap_udmabuf,
.begin_cpu_access = begin_cpu_udmabuf,
.end_cpu_access = end_cpu_udmabuf,
};
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 2f2a2dd0b95d..fb7073fc034f 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -245,7 +245,7 @@ config FSL_RAID
config HISI_DMA
tristate "HiSilicon DMA Engine support"
- depends on ARM64 || COMPILE_TEST
+ depends on ARCH_HISI || COMPILE_TEST
depends on PCI_MSI
select DMA_ENGINE
select DMA_VIRTUAL_CHANNELS
@@ -716,6 +716,20 @@ config XILINX_DMA
the scatter gather interface with multiple channels independent
configuration support.
+config XILINX_XDMA
+ tristate "Xilinx DMA/Bridge Subsystem DMA Engine"
+ depends on HAS_IOMEM
+ select DMA_ENGINE
+ select DMA_VIRTUAL_CHANNELS
+ select REGMAP_MMIO
+ help
+ Enable support for Xilinx DMA/Bridge Subsystem DMA engine. The DMA
+ provides high performance block data movement between Host memory
+ and the DMA subsystem. These direct memory transfers can be both in
+ the Host to Card (H2C) and Card to Host (C2H) transfers.
+ The core also provides up to 16 user interrupt wires that generate
+ interrupts to the host.
+
config XILINX_ZYNQMP_DMA
tristate "Xilinx ZynqMP DMA Engine"
depends on ARCH_ZYNQ || MICROBLAZE || ARM64 || COMPILE_TEST
diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c
index d6c9781cd46a..1f0fab180f8f 100644
--- a/drivers/dma/at_xdmac.c
+++ b/drivers/dma/at_xdmac.c
@@ -21,6 +21,7 @@
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
+#include <linux/pm_runtime.h>
#include "dmaengine.h"
@@ -240,6 +241,7 @@ struct at_xdmac_chan {
struct at_xdmac {
struct dma_device dma;
void __iomem *regs;
+ struct device *dev;
int irq;
struct clk *clk;
u32 save_gim;
@@ -361,13 +363,65 @@ MODULE_PARM_DESC(init_nr_desc_per_channel,
"initial descriptors per channel (default: 64)");
+static void at_xdmac_runtime_suspend_descriptors(struct at_xdmac_chan *atchan)
+{
+ struct at_xdmac *atxdmac = to_at_xdmac(atchan->chan.device);
+ struct at_xdmac_desc *desc, *_desc;
+
+ list_for_each_entry_safe(desc, _desc, &atchan->xfers_list, xfer_node) {
+ if (!desc->active_xfer)
+ continue;
+
+ pm_runtime_mark_last_busy(atxdmac->dev);
+ pm_runtime_put_autosuspend(atxdmac->dev);
+ }
+}
+
+static int at_xdmac_runtime_resume_descriptors(struct at_xdmac_chan *atchan)
+{
+ struct at_xdmac *atxdmac = to_at_xdmac(atchan->chan.device);
+ struct at_xdmac_desc *desc, *_desc;
+ int ret;
+
+ list_for_each_entry_safe(desc, _desc, &atchan->xfers_list, xfer_node) {
+ if (!desc->active_xfer)
+ continue;
+
+ ret = pm_runtime_resume_and_get(atxdmac->dev);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
static bool at_xdmac_chan_is_enabled(struct at_xdmac_chan *atchan)
{
- return at_xdmac_chan_read(atchan, AT_XDMAC_GS) & atchan->mask;
+ struct at_xdmac *atxdmac = to_at_xdmac(atchan->chan.device);
+ int ret;
+
+ ret = pm_runtime_resume_and_get(atxdmac->dev);
+ if (ret < 0)
+ return false;
+
+ ret = !!(at_xdmac_chan_read(atchan, AT_XDMAC_GS) & atchan->mask);
+
+ pm_runtime_mark_last_busy(atxdmac->dev);
+ pm_runtime_put_autosuspend(atxdmac->dev);
+
+ return ret;
}
static void at_xdmac_off(struct at_xdmac *atxdmac)
{
+ struct dma_chan *chan, *_chan;
+ struct at_xdmac_chan *atchan;
+ int ret;
+
+ ret = pm_runtime_resume_and_get(atxdmac->dev);
+ if (ret < 0)
+ return;
+
at_xdmac_write(atxdmac, AT_XDMAC_GD, -1L);
/* Wait that all chans are disabled. */
@@ -375,6 +429,18 @@ static void at_xdmac_off(struct at_xdmac *atxdmac)
cpu_relax();
at_xdmac_write(atxdmac, AT_XDMAC_GID, -1L);
+
+ /* Decrement runtime PM ref counter for each active descriptor. */
+ if (!list_empty(&atxdmac->dma.channels)) {
+ list_for_each_entry_safe(chan, _chan, &atxdmac->dma.channels,
+ device_node) {
+ atchan = to_at_xdmac_chan(chan);
+ at_xdmac_runtime_suspend_descriptors(atchan);
+ }
+ }
+
+ pm_runtime_mark_last_busy(atxdmac->dev);
+ pm_runtime_put_autosuspend(atxdmac->dev);
}
/* Call with lock hold. */
@@ -383,6 +449,11 @@ static void at_xdmac_start_xfer(struct at_xdmac_chan *atchan,
{
struct at_xdmac *atxdmac = to_at_xdmac(atchan->chan.device);
u32 reg;
+ int ret;
+
+ ret = pm_runtime_resume_and_get(atxdmac->dev);
+ if (ret < 0)
+ return;
dev_vdbg(chan2dev(&atchan->chan), "%s: desc 0x%p\n", __func__, first);
@@ -462,7 +533,6 @@ static void at_xdmac_start_xfer(struct at_xdmac_chan *atchan,
at_xdmac_chan_read(atchan, AT_XDMAC_CSA),
at_xdmac_chan_read(atchan, AT_XDMAC_CDA),
at_xdmac_chan_read(atchan, AT_XDMAC_CUBC));
-
}
static dma_cookie_t at_xdmac_tx_submit(struct dma_async_tx_descriptor *tx)
@@ -1456,14 +1526,14 @@ at_xdmac_prep_dma_memset_sg(struct dma_chan *chan, struct scatterlist *sgl,
static enum dma_status
at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
- struct dma_tx_state *txstate)
+ struct dma_tx_state *txstate)
{
struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan);
struct at_xdmac *atxdmac = to_at_xdmac(atchan->chan.device);
struct at_xdmac_desc *desc, *_desc, *iter;
struct list_head *descs_list;
enum dma_status ret;
- int residue, retry;
+ int residue, retry, pm_status;
u32 cur_nda, check_nda, cur_ubc, mask, value;
u8 dwidth = 0;
unsigned long flags;
@@ -1473,6 +1543,10 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
if (ret == DMA_COMPLETE || !txstate)
return ret;
+ pm_status = pm_runtime_resume_and_get(atxdmac->dev);
+ if (pm_status < 0)
+ return DMA_ERROR;
+
spin_lock_irqsave(&atchan->lock, flags);
desc = list_first_entry(&atchan->xfers_list, struct at_xdmac_desc, xfer_node);
@@ -1590,6 +1664,8 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
spin_unlock:
spin_unlock_irqrestore(&atchan->lock, flags);
+ pm_runtime_mark_last_busy(atxdmac->dev);
+ pm_runtime_put_autosuspend(atxdmac->dev);
return ret;
}
@@ -1636,6 +1712,11 @@ static void at_xdmac_handle_error(struct at_xdmac_chan *atchan)
{
struct at_xdmac *atxdmac = to_at_xdmac(atchan->chan.device);
struct at_xdmac_desc *bad_desc;
+ int ret;
+
+ ret = pm_runtime_resume_and_get(atxdmac->dev);
+ if (ret < 0)
+ return;
/*
* The descriptor currently at the head of the active list is
@@ -1665,12 +1746,16 @@ static void at_xdmac_handle_error(struct at_xdmac_chan *atchan)
__func__, &bad_desc->lld.mbr_sa, &bad_desc->lld.mbr_da,
bad_desc->lld.mbr_ubc);
+ pm_runtime_mark_last_busy(atxdmac->dev);
+ pm_runtime_put_autosuspend(atxdmac->dev);
+
/* Then continue with usual descriptor management */
}
static void at_xdmac_tasklet(struct tasklet_struct *t)
{
struct at_xdmac_chan *atchan = from_tasklet(atchan, t, tasklet);
+ struct at_xdmac *atxdmac = to_at_xdmac(atchan->chan.device);
struct at_xdmac_desc *desc;
struct dma_async_tx_descriptor *txd;
u32 error_mask;
@@ -1720,6 +1805,13 @@ static void at_xdmac_tasklet(struct tasklet_struct *t)
list_splice_tail_init(&desc->descs_list, &atchan->free_descs_list);
at_xdmac_advance_work(atchan);
spin_unlock_irq(&atchan->lock);
+
+ /*
+ * Decrement runtime PM ref counter incremented in
+ * at_xdmac_start_xfer().
+ */
+ pm_runtime_mark_last_busy(atxdmac->dev);
+ pm_runtime_put_autosuspend(atxdmac->dev);
}
static irqreturn_t at_xdmac_interrupt(int irq, void *dev_id)
@@ -1811,19 +1903,31 @@ static int at_xdmac_device_pause(struct dma_chan *chan)
struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan);
struct at_xdmac *atxdmac = to_at_xdmac(atchan->chan.device);
unsigned long flags;
+ int ret;
dev_dbg(chan2dev(chan), "%s\n", __func__);
if (test_and_set_bit(AT_XDMAC_CHAN_IS_PAUSED, &atchan->status))
return 0;
+ ret = pm_runtime_resume_and_get(atxdmac->dev);
+ if (ret < 0)
+ return ret;
+
spin_lock_irqsave(&atchan->lock, flags);
at_xdmac_write(atxdmac, atxdmac->layout->grws, atchan->mask);
while (at_xdmac_chan_read(atchan, AT_XDMAC_CC)
& (AT_XDMAC_CC_WRIP | AT_XDMAC_CC_RDIP))
cpu_relax();
+
+ /* Decrement runtime PM ref counter for each active descriptor. */
+ at_xdmac_runtime_suspend_descriptors(atchan);
+
spin_unlock_irqrestore(&atchan->lock, flags);
+ pm_runtime_mark_last_busy(atxdmac->dev);
+ pm_runtime_put_autosuspend(atxdmac->dev);
+
return 0;
}
@@ -1832,20 +1936,32 @@ static int at_xdmac_device_resume(struct dma_chan *chan)
struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan);
struct at_xdmac *atxdmac = to_at_xdmac(atchan->chan.device);
unsigned long flags;
+ int ret;
dev_dbg(chan2dev(chan), "%s\n", __func__);
+ ret = pm_runtime_resume_and_get(atxdmac->dev);
+ if (ret < 0)
+ return ret;
+
spin_lock_irqsave(&atchan->lock, flags);
- if (!at_xdmac_chan_is_paused(atchan)) {
- spin_unlock_irqrestore(&atchan->lock, flags);
- return 0;
- }
+ if (!at_xdmac_chan_is_paused(atchan))
+ goto unlock;
+
+ /* Increment runtime PM ref counter for each active descriptor. */
+ ret = at_xdmac_runtime_resume_descriptors(atchan);
+ if (ret < 0)
+ goto unlock;
at_xdmac_write(atxdmac, atxdmac->layout->grwr, atchan->mask);
clear_bit(AT_XDMAC_CHAN_IS_PAUSED, &atchan->status);
+
+unlock:
spin_unlock_irqrestore(&atchan->lock, flags);
+ pm_runtime_mark_last_busy(atxdmac->dev);
+ pm_runtime_put_autosuspend(atxdmac->dev);
- return 0;
+ return ret;
}
static int at_xdmac_device_terminate_all(struct dma_chan *chan)
@@ -1854,9 +1970,14 @@ static int at_xdmac_device_terminate_all(struct dma_chan *chan)
struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan);
struct at_xdmac *atxdmac = to_at_xdmac(atchan->chan.device);
unsigned long flags;
+ int ret;
dev_dbg(chan2dev(chan), "%s\n", __func__);
+ ret = pm_runtime_resume_and_get(atxdmac->dev);
+ if (ret < 0)
+ return ret;
+
spin_lock_irqsave(&atchan->lock, flags);
at_xdmac_write(atxdmac, AT_XDMAC_GD, atchan->mask);
while (at_xdmac_read(atxdmac, AT_XDMAC_GS) & atchan->mask)
@@ -1867,12 +1988,24 @@ static int at_xdmac_device_terminate_all(struct dma_chan *chan)
list_del(&desc->xfer_node);
list_splice_tail_init(&desc->descs_list,
&atchan->free_descs_list);
+ /*
+ * We incremented the runtime PM reference count on
+ * at_xdmac_start_xfer() for this descriptor. Now it's time
+ * to release it.
+ */
+ if (desc->active_xfer) {
+ pm_runtime_put_autosuspend(atxdmac->dev);
+ pm_runtime_mark_last_busy(atxdmac->dev);
+ }
}
clear_bit(AT_XDMAC_CHAN_IS_PAUSED, &atchan->status);
clear_bit(AT_XDMAC_CHAN_IS_CYCLIC, &atchan->status);
spin_unlock_irqrestore(&atchan->lock, flags);
+ pm_runtime_mark_last_busy(atxdmac->dev);
+ pm_runtime_put_autosuspend(atxdmac->dev);
+
return 0;
}
@@ -1974,6 +2107,11 @@ static int __maybe_unused atmel_xdmac_suspend(struct device *dev)
{
struct at_xdmac *atxdmac = dev_get_drvdata(dev);
struct dma_chan *chan, *_chan;
+ int ret;
+
+ ret = pm_runtime_resume_and_get(atxdmac->dev);
+ if (ret < 0)
+ return ret;
list_for_each_entry_safe(chan, _chan, &atxdmac->dma.channels, device_node) {
struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan);
@@ -1986,12 +2124,13 @@ static int __maybe_unused atmel_xdmac_suspend(struct device *dev)
atchan->save_cnda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA);
atchan->save_cndc = at_xdmac_chan_read(atchan, AT_XDMAC_CNDC);
}
+
+ at_xdmac_runtime_suspend_descriptors(atchan);
}
atxdmac->save_gim = at_xdmac_read(atxdmac, AT_XDMAC_GIM);
at_xdmac_off(atxdmac);
- clk_disable_unprepare(atxdmac->clk);
- return 0;
+ return pm_runtime_force_suspend(atxdmac->dev);
}
static int __maybe_unused atmel_xdmac_resume(struct device *dev)
@@ -2003,8 +2142,8 @@ static int __maybe_unused atmel_xdmac_resume(struct device *dev)
int i;
int ret;
- ret = clk_prepare_enable(atxdmac->clk);
- if (ret)
+ ret = pm_runtime_force_resume(atxdmac->dev);
+ if (ret < 0)
return ret;
at_xdmac_axi_config(pdev);
@@ -2019,6 +2158,11 @@ static int __maybe_unused atmel_xdmac_resume(struct device *dev)
at_xdmac_write(atxdmac, AT_XDMAC_GIE, atxdmac->save_gim);
list_for_each_entry_safe(chan, _chan, &atxdmac->dma.channels, device_node) {
atchan = to_at_xdmac_chan(chan);
+
+ ret = at_xdmac_runtime_resume_descriptors(atchan);
+ if (ret < 0)
+ return ret;
+
at_xdmac_chan_write(atchan, AT_XDMAC_CC, atchan->save_cc);
if (at_xdmac_chan_is_cyclic(atchan)) {
if (at_xdmac_chan_is_paused(atchan))
@@ -2030,9 +2174,29 @@ static int __maybe_unused atmel_xdmac_resume(struct device *dev)
at_xdmac_write(atxdmac, AT_XDMAC_GE, atchan->mask);
}
}
+
+ pm_runtime_mark_last_busy(atxdmac->dev);
+ pm_runtime_put_autosuspend(atxdmac->dev);
+
+ return 0;
+}
+
+static int __maybe_unused atmel_xdmac_runtime_suspend(struct device *dev)
+{
+ struct at_xdmac *atxdmac = dev_get_drvdata(dev);
+
+ clk_disable(atxdmac->clk);
+
return 0;
}
+static int __maybe_unused atmel_xdmac_runtime_resume(struct device *dev)
+{
+ struct at_xdmac *atxdmac = dev_get_drvdata(dev);
+
+ return clk_enable(atxdmac->clk);
+}
+
static int at_xdmac_probe(struct platform_device *pdev)
{
struct at_xdmac *atxdmac;
@@ -2071,6 +2235,7 @@ static int at_xdmac_probe(struct platform_device *pdev)
atxdmac->regs = base;
atxdmac->irq = irq;
+ atxdmac->dev = &pdev->dev;
atxdmac->layout = of_device_get_match_data(&pdev->dev);
if (!atxdmac->layout)
@@ -2135,11 +2300,20 @@ static int at_xdmac_probe(struct platform_device *pdev)
atxdmac->dma.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
atxdmac->dma.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
- /* Disable all chans and interrupts. */
- at_xdmac_off(atxdmac);
+ platform_set_drvdata(pdev, atxdmac);
+
+ pm_runtime_set_autosuspend_delay(&pdev->dev, 500);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_get_noresume(&pdev->dev);
/* Init channels. */
INIT_LIST_HEAD(&atxdmac->dma.channels);
+
+ /* Disable all chans and interrupts. */
+ at_xdmac_off(atxdmac);
+
for (i = 0; i < nr_channels; i++) {
struct at_xdmac_chan *atchan = &atxdmac->chan[i];
@@ -2159,12 +2333,11 @@ static int at_xdmac_probe(struct platform_device *pdev)
while (at_xdmac_chan_read(atchan, AT_XDMAC_CIS))
cpu_relax();
}
- platform_set_drvdata(pdev, atxdmac);
ret = dma_async_device_register(&atxdmac->dma);
if (ret) {
dev_err(&pdev->dev, "fail to register DMA engine device\n");
- goto err_clk_disable;
+ goto err_pm_disable;
}
ret = of_dma_controller_register(pdev->dev.of_node,
@@ -2179,10 +2352,18 @@ static int at_xdmac_probe(struct platform_device *pdev)
at_xdmac_axi_config(pdev);
+ pm_runtime_mark_last_busy(&pdev->dev);
+ pm_runtime_put_autosuspend(&pdev->dev);
+
return 0;
err_dma_unregister:
dma_async_device_unregister(&atxdmac->dma);
+err_pm_disable:
+ pm_runtime_put_noidle(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
err_clk_disable:
clk_disable_unprepare(atxdmac->clk);
err_free_irq:
@@ -2198,6 +2379,9 @@ static int at_xdmac_remove(struct platform_device *pdev)
at_xdmac_off(atxdmac);
of_dma_controller_free(pdev->dev.of_node);
dma_async_device_unregister(&atxdmac->dma);
+ pm_runtime_disable(atxdmac->dev);
+ pm_runtime_set_suspended(&pdev->dev);
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
clk_disable_unprepare(atxdmac->clk);
free_irq(atxdmac->irq, atxdmac);
@@ -2215,6 +2399,8 @@ static int at_xdmac_remove(struct platform_device *pdev)
static const struct dev_pm_ops __maybe_unused atmel_xdmac_dev_pm_ops = {
.prepare = atmel_xdmac_prepare,
SET_LATE_SYSTEM_SLEEP_PM_OPS(atmel_xdmac_suspend, atmel_xdmac_resume)
+ SET_RUNTIME_PM_OPS(atmel_xdmac_runtime_suspend,
+ atmel_xdmac_runtime_resume, NULL)
};
static const struct of_device_id atmel_xdmac_dt_ids[] = {
diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c
index 630dfbb01a40..0807fb9eb262 100644
--- a/drivers/dma/bcm2835-dma.c
+++ b/drivers/dma/bcm2835-dma.c
@@ -878,7 +878,6 @@ static struct dma_chan *bcm2835_dma_xlate(struct of_phandle_args *spec,
static int bcm2835_dma_probe(struct platform_device *pdev)
{
struct bcm2835_dmadev *od;
- struct resource *res;
void __iomem *base;
int rc;
int i, j;
@@ -902,8 +901,7 @@ static int bcm2835_dma_probe(struct platform_device *pdev)
dma_set_max_seg_size(&pdev->dev, 0x3FFFFFFF);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- base = devm_ioremap_resource(&pdev->dev, res);
+ base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);
diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c
index f30dabc99795..a812b9b00e6b 100644
--- a/drivers/dma/dma-axi-dmac.c
+++ b/drivers/dma/dma-axi-dmac.c
@@ -910,7 +910,6 @@ static int axi_dmac_probe(struct platform_device *pdev)
{
struct dma_device *dma_dev;
struct axi_dmac *dmac;
- struct resource *res;
struct regmap *regmap;
unsigned int version;
int ret;
@@ -925,8 +924,7 @@ static int axi_dmac_probe(struct platform_device *pdev)
if (dmac->irq == 0)
return -EINVAL;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- dmac->base = devm_ioremap_resource(&pdev->dev, res);
+ dmac->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(dmac->base))
return PTR_ERR(dmac->base);
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 8a6e6b60d66f..c24bca210104 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -172,7 +172,7 @@ static ssize_t memcpy_count_show(struct device *dev,
if (chan) {
for_each_possible_cpu(i)
count += per_cpu_ptr(chan->local, i)->memcpy_count;
- err = sprintf(buf, "%lu\n", count);
+ err = sysfs_emit(buf, "%lu\n", count);
} else
err = -ENODEV;
mutex_unlock(&dma_list_mutex);
@@ -194,7 +194,7 @@ static ssize_t bytes_transferred_show(struct device *dev,
if (chan) {
for_each_possible_cpu(i)
count += per_cpu_ptr(chan->local, i)->bytes_transferred;
- err = sprintf(buf, "%lu\n", count);
+ err = sysfs_emit(buf, "%lu\n", count);
} else
err = -ENODEV;
mutex_unlock(&dma_list_mutex);
@@ -212,7 +212,7 @@ static ssize_t in_use_show(struct device *dev, struct device_attribute *attr,
mutex_lock(&dma_list_mutex);
chan = dev_to_dma_chan(dev);
if (chan)
- err = sprintf(buf, "%d\n", chan->client_count);
+ err = sysfs_emit(buf, "%d\n", chan->client_count);
else
err = -ENODEV;
mutex_unlock(&dma_list_mutex);
@@ -1323,11 +1323,8 @@ void dma_async_device_unregister(struct dma_device *device)
}
EXPORT_SYMBOL(dma_async_device_unregister);
-static void dmam_device_release(struct device *dev, void *res)
+static void dmaenginem_async_device_unregister(void *device)
{
- struct dma_device *device;
-
- device = *(struct dma_device **)res;
dma_async_device_unregister(device);
}
@@ -1339,22 +1336,13 @@ static void dmam_device_release(struct device *dev, void *res)
*/
int dmaenginem_async_device_register(struct dma_device *device)
{
- void *p;
int ret;
- p = devres_alloc(dmam_device_release, sizeof(void *), GFP_KERNEL);
- if (!p)
- return -ENOMEM;
-
ret = dma_async_device_register(device);
- if (!ret) {
- *(struct dma_device **)p = device;
- devres_add(device->dev, p);
- } else {
- devres_free(p);
- }
+ if (ret)
+ return ret;
- return ret;
+ return devm_add_action(device->dev, dmaenginem_async_device_unregister, device);
}
EXPORT_SYMBOL(dmaenginem_async_device_register);
diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
index bf85aa0979ec..4169e1d7d5ca 100644
--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
@@ -325,8 +325,6 @@ dma_chan_tx_status(struct dma_chan *dchan, dma_cookie_t cookie,
len = vd_to_axi_desc(vdesc)->hw_desc[0].len;
completed_length = completed_blocks * len;
bytes = length - completed_length;
- } else {
- bytes = vd_to_axi_desc(vdesc)->length;
}
spin_unlock_irqrestore(&chan->vc.lock, flags);
@@ -1371,7 +1369,6 @@ static int dw_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
struct axi_dma_chip *chip;
- struct resource *mem;
struct dw_axi_dma *dw;
struct dw_axi_dma_hcfg *hdata;
u32 i;
@@ -1397,8 +1394,7 @@ static int dw_probe(struct platform_device *pdev)
if (chip->irq < 0)
return chip->irq;
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- chip->regs = devm_ioremap_resource(chip->dev, mem);
+ chip->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(chip->regs))
return PTR_ERR(chip->regs);
diff --git a/drivers/dma/dw-edma/Kconfig b/drivers/dma/dw-edma/Kconfig
index 7ff17b2db6a1..2b6f2679508d 100644
--- a/drivers/dma/dw-edma/Kconfig
+++ b/drivers/dma/dw-edma/Kconfig
@@ -9,11 +9,14 @@ config DW_EDMA
Support the Synopsys DesignWare eDMA controller, normally
implemented on endpoints SoCs.
+if DW_EDMA
+
config DW_EDMA_PCIE
tristate "Synopsys DesignWare eDMA PCIe driver"
depends on PCI && PCI_MSI
- select DW_EDMA
help
Provides a glue-logic between the Synopsys DesignWare
eDMA controller and an endpoint PCIe device. This also serves
as a reference design to whom desires to use this IP.
+
+endif # DW_EDMA
diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index c54b24ff5206..1906a836f0aa 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -39,6 +39,17 @@ struct dw_edma_desc *vd2dw_edma_desc(struct virt_dma_desc *vd)
return container_of(vd, struct dw_edma_desc, vd);
}
+static inline
+u64 dw_edma_get_pci_address(struct dw_edma_chan *chan, phys_addr_t cpu_addr)
+{
+ struct dw_edma_chip *chip = chan->dw->chip;
+
+ if (chip->ops->pci_address)
+ return chip->ops->pci_address(chip->dev, cpu_addr);
+
+ return cpu_addr;
+}
+
static struct dw_edma_burst *dw_edma_alloc_burst(struct dw_edma_chunk *chunk)
{
struct dw_edma_burst *burst;
@@ -197,6 +208,24 @@ static void dw_edma_start_transfer(struct dw_edma_chan *chan)
desc->chunks_alloc--;
}
+static void dw_edma_device_caps(struct dma_chan *dchan,
+ struct dma_slave_caps *caps)
+{
+ struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
+
+ if (chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) {
+ if (chan->dir == EDMA_DIR_READ)
+ caps->directions = BIT(DMA_DEV_TO_MEM);
+ else
+ caps->directions = BIT(DMA_MEM_TO_DEV);
+ } else {
+ if (chan->dir == EDMA_DIR_WRITE)
+ caps->directions = BIT(DMA_DEV_TO_MEM);
+ else
+ caps->directions = BIT(DMA_MEM_TO_DEV);
+ }
+}
+
static int dw_edma_device_config(struct dma_chan *dchan,
struct dma_slave_config *config)
{
@@ -327,11 +356,12 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
{
struct dw_edma_chan *chan = dchan2dw_edma_chan(xfer->dchan);
enum dma_transfer_direction dir = xfer->direction;
- phys_addr_t src_addr, dst_addr;
struct scatterlist *sg = NULL;
struct dw_edma_chunk *chunk;
struct dw_edma_burst *burst;
struct dw_edma_desc *desc;
+ u64 src_addr, dst_addr;
+ size_t fsz = 0;
u32 cnt = 0;
int i;
@@ -381,9 +411,9 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
if (xfer->xfer.sg.len < 1)
return NULL;
} else if (xfer->type == EDMA_XFER_INTERLEAVED) {
- if (!xfer->xfer.il->numf)
+ if (!xfer->xfer.il->numf || xfer->xfer.il->frame_size < 1)
return NULL;
- if (xfer->xfer.il->numf > 0 && xfer->xfer.il->frame_size > 0)
+ if (!xfer->xfer.il->src_inc || !xfer->xfer.il->dst_inc)
return NULL;
} else {
return NULL;
@@ -405,16 +435,19 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
dst_addr = chan->config.dst_addr;
}
+ if (dir == DMA_DEV_TO_MEM)
+ src_addr = dw_edma_get_pci_address(chan, (phys_addr_t)src_addr);
+ else
+ dst_addr = dw_edma_get_pci_address(chan, (phys_addr_t)dst_addr);
+
if (xfer->type == EDMA_XFER_CYCLIC) {
cnt = xfer->xfer.cyclic.cnt;
} else if (xfer->type == EDMA_XFER_SCATTER_GATHER) {
cnt = xfer->xfer.sg.len;
sg = xfer->xfer.sg.sgl;
} else if (xfer->type == EDMA_XFER_INTERLEAVED) {
- if (xfer->xfer.il->numf > 0)
- cnt = xfer->xfer.il->numf;
- else
- cnt = xfer->xfer.il->frame_size;
+ cnt = xfer->xfer.il->numf * xfer->xfer.il->frame_size;
+ fsz = xfer->xfer.il->frame_size;
}
for (i = 0; i < cnt; i++) {
@@ -436,7 +469,7 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
else if (xfer->type == EDMA_XFER_SCATTER_GATHER)
burst->sz = sg_dma_len(sg);
else if (xfer->type == EDMA_XFER_INTERLEAVED)
- burst->sz = xfer->xfer.il->sgl[i].size;
+ burst->sz = xfer->xfer.il->sgl[i % fsz].size;
chunk->ll_region.sz += burst->sz;
desc->alloc_sz += burst->sz;
@@ -455,6 +488,8 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
* and destination addresses are increased
* by the same portion (data length)
*/
+ } else if (xfer->type == EDMA_XFER_INTERLEAVED) {
+ burst->dar = dst_addr;
}
} else {
burst->dar = dst_addr;
@@ -470,25 +505,24 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
* and destination addresses are increased
* by the same portion (data length)
*/
+ } else if (xfer->type == EDMA_XFER_INTERLEAVED) {
+ burst->sar = src_addr;
}
}
if (xfer->type == EDMA_XFER_SCATTER_GATHER) {
sg = sg_next(sg);
- } else if (xfer->type == EDMA_XFER_INTERLEAVED &&
- xfer->xfer.il->frame_size > 0) {
+ } else if (xfer->type == EDMA_XFER_INTERLEAVED) {
struct dma_interleaved_template *il = xfer->xfer.il;
- struct data_chunk *dc = &il->sgl[i];
+ struct data_chunk *dc = &il->sgl[i % fsz];
- if (il->src_sgl) {
- src_addr += burst->sz;
+ src_addr += burst->sz;
+ if (il->src_sgl)
src_addr += dmaengine_get_src_icg(il, dc);
- }
- if (il->dst_sgl) {
- dst_addr += burst->sz;
+ dst_addr += burst->sz;
+ if (il->dst_sgl)
dst_addr += dmaengine_get_dst_icg(il, dc);
- }
}
}
@@ -701,92 +735,76 @@ static void dw_edma_free_chan_resources(struct dma_chan *dchan)
}
}
-static int dw_edma_channel_setup(struct dw_edma *dw, bool write,
- u32 wr_alloc, u32 rd_alloc)
+static int dw_edma_channel_setup(struct dw_edma *dw, u32 wr_alloc, u32 rd_alloc)
{
struct dw_edma_chip *chip = dw->chip;
- struct dw_edma_region *dt_region;
struct device *dev = chip->dev;
struct dw_edma_chan *chan;
struct dw_edma_irq *irq;
struct dma_device *dma;
- u32 alloc, off_alloc;
- u32 i, j, cnt;
- int err = 0;
+ u32 i, ch_cnt;
u32 pos;
- if (write) {
- i = 0;
- cnt = dw->wr_ch_cnt;
- dma = &dw->wr_edma;
- alloc = wr_alloc;
- off_alloc = 0;
- } else {
- i = dw->wr_ch_cnt;
- cnt = dw->rd_ch_cnt;
- dma = &dw->rd_edma;
- alloc = rd_alloc;
- off_alloc = wr_alloc;
- }
+ ch_cnt = dw->wr_ch_cnt + dw->rd_ch_cnt;
+ dma = &dw->dma;
INIT_LIST_HEAD(&dma->channels);
- for (j = 0; (alloc || dw->nr_irqs == 1) && j < cnt; j++, i++) {
+
+ for (i = 0; i < ch_cnt; i++) {
chan = &dw->chan[i];
- dt_region = devm_kzalloc(dev, sizeof(*dt_region), GFP_KERNEL);
- if (!dt_region)
- return -ENOMEM;
+ chan->dw = dw;
- chan->vc.chan.private = dt_region;
+ if (i < dw->wr_ch_cnt) {
+ chan->id = i;
+ chan->dir = EDMA_DIR_WRITE;
+ } else {
+ chan->id = i - dw->wr_ch_cnt;
+ chan->dir = EDMA_DIR_READ;
+ }
- chan->dw = dw;
- chan->id = j;
- chan->dir = write ? EDMA_DIR_WRITE : EDMA_DIR_READ;
chan->configured = false;
chan->request = EDMA_REQ_NONE;
chan->status = EDMA_ST_IDLE;
- if (write)
- chan->ll_max = (chip->ll_region_wr[j].sz / EDMA_LL_SZ);
+ if (chan->dir == EDMA_DIR_WRITE)
+ chan->ll_max = (chip->ll_region_wr[chan->id].sz / EDMA_LL_SZ);
else
- chan->ll_max = (chip->ll_region_rd[j].sz / EDMA_LL_SZ);
+ chan->ll_max = (chip->ll_region_rd[chan->id].sz / EDMA_LL_SZ);
chan->ll_max -= 1;
dev_vdbg(dev, "L. List:\tChannel %s[%u] max_cnt=%u\n",
- write ? "write" : "read", j, chan->ll_max);
+ chan->dir == EDMA_DIR_WRITE ? "write" : "read",
+ chan->id, chan->ll_max);
if (dw->nr_irqs == 1)
pos = 0;
+ else if (chan->dir == EDMA_DIR_WRITE)
+ pos = chan->id % wr_alloc;
else
- pos = off_alloc + (j % alloc);
+ pos = wr_alloc + chan->id % rd_alloc;
irq = &dw->irq[pos];
- if (write)
- irq->wr_mask |= BIT(j);
+ if (chan->dir == EDMA_DIR_WRITE)
+ irq->wr_mask |= BIT(chan->id);
else
- irq->rd_mask |= BIT(j);
+ irq->rd_mask |= BIT(chan->id);
irq->dw = dw;
memcpy(&chan->msi, &irq->msi, sizeof(chan->msi));
dev_vdbg(dev, "MSI:\t\tChannel %s[%u] addr=0x%.8x%.8x, data=0x%.8x\n",
- write ? "write" : "read", j,
+ chan->dir == EDMA_DIR_WRITE ? "write" : "read", chan->id,
chan->msi.address_hi, chan->msi.address_lo,
chan->msi.data);
chan->vc.desc_free = vchan_free_desc;
- vchan_init(&chan->vc, dma);
+ chan->vc.chan.private = chan->dir == EDMA_DIR_WRITE ?
+ &dw->chip->dt_region_wr[chan->id] :
+ &dw->chip->dt_region_rd[chan->id];
- if (write) {
- dt_region->paddr = chip->dt_region_wr[j].paddr;
- dt_region->vaddr = chip->dt_region_wr[j].vaddr;
- dt_region->sz = chip->dt_region_wr[j].sz;
- } else {
- dt_region->paddr = chip->dt_region_rd[j].paddr;
- dt_region->vaddr = chip->dt_region_rd[j].vaddr;
- dt_region->sz = chip->dt_region_rd[j].sz;
- }
+ vchan_init(&chan->vc, dma);
dw_edma_v0_core_device_config(chan);
}
@@ -797,16 +815,16 @@ static int dw_edma_channel_setup(struct dw_edma *dw, bool write,
dma_cap_set(DMA_CYCLIC, dma->cap_mask);
dma_cap_set(DMA_PRIVATE, dma->cap_mask);
dma_cap_set(DMA_INTERLEAVE, dma->cap_mask);
- dma->directions = BIT(write ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV);
+ dma->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
dma->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
dma->dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
dma->residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR;
- dma->chancnt = cnt;
/* Set DMA channel callbacks */
dma->dev = chip->dev;
dma->device_alloc_chan_resources = dw_edma_alloc_chan_resources;
dma->device_free_chan_resources = dw_edma_free_chan_resources;
+ dma->device_caps = dw_edma_device_caps;
dma->device_config = dw_edma_device_config;
dma->device_pause = dw_edma_device_pause;
dma->device_resume = dw_edma_device_resume;
@@ -820,9 +838,7 @@ static int dw_edma_channel_setup(struct dw_edma *dw, bool write,
dma_set_max_seg_size(dma->dev, U32_MAX);
/* Register DMA device */
- err = dma_async_device_register(dma);
-
- return err;
+ return dma_async_device_register(dma);
}
static inline void dw_edma_dec_irq_alloc(int *nr_irqs, u32 *alloc, u16 cnt)
@@ -893,10 +909,8 @@ static int dw_edma_irq_request(struct dw_edma *dw,
dw_edma_interrupt_read,
IRQF_SHARED, dw->name,
&dw->irq[i]);
- if (err) {
- dw->nr_irqs = i;
- return err;
- }
+ if (err)
+ goto err_irq_free;
if (irq_get_msi_desc(irq))
get_cached_msi_msg(irq, &dw->irq[i].msi);
@@ -905,6 +919,14 @@ static int dw_edma_irq_request(struct dw_edma *dw,
dw->nr_irqs = i;
}
+ return 0;
+
+err_irq_free:
+ for (i--; i >= 0; i--) {
+ irq = chip->ops->irq_vector(dev, i);
+ free_irq(irq, &dw->irq[i]);
+ }
+
return err;
}
@@ -951,7 +973,8 @@ int dw_edma_probe(struct dw_edma_chip *chip)
if (!dw->chan)
return -ENOMEM;
- snprintf(dw->name, sizeof(dw->name), "dw-edma-core:%d", chip->id);
+ snprintf(dw->name, sizeof(dw->name), "dw-edma-core:%s",
+ dev_name(chip->dev));
/* Disable eDMA, only to establish the ideal initial conditions */
dw_edma_v0_core_off(dw);
@@ -961,13 +984,8 @@ int dw_edma_probe(struct dw_edma_chip *chip)
if (err)
return err;
- /* Setup write channels */
- err = dw_edma_channel_setup(dw, true, wr_alloc, rd_alloc);
- if (err)
- goto err_irq_free;
-
- /* Setup read channels */
- err = dw_edma_channel_setup(dw, false, wr_alloc, rd_alloc);
+ /* Setup write/read channels */
+ err = dw_edma_channel_setup(dw, wr_alloc, rd_alloc);
if (err)
goto err_irq_free;
@@ -993,6 +1011,10 @@ int dw_edma_remove(struct dw_edma_chip *chip)
struct dw_edma *dw = chip->dw;
int i;
+ /* Skip removal if no private data found */
+ if (!dw)
+ return -ENODEV;
+
/* Disable eDMA */
dw_edma_v0_core_off(dw);
@@ -1001,23 +1023,13 @@ int dw_edma_remove(struct dw_edma_chip *chip)
free_irq(chip->ops->irq_vector(dev, i), &dw->irq[i]);
/* Deregister eDMA device */
- dma_async_device_unregister(&dw->wr_edma);
- list_for_each_entry_safe(chan, _chan, &dw->wr_edma.channels,
+ dma_async_device_unregister(&dw->dma);
+ list_for_each_entry_safe(chan, _chan, &dw->dma.channels,
vc.chan.device_node) {
tasklet_kill(&chan->vc.task);
list_del(&chan->vc.chan.device_node);
}
- dma_async_device_unregister(&dw->rd_edma);
- list_for_each_entry_safe(chan, _chan, &dw->rd_edma.channels,
- vc.chan.device_node) {
- tasklet_kill(&chan->vc.task);
- list_del(&chan->vc.chan.device_node);
- }
-
- /* Turn debugfs off */
- dw_edma_v0_core_debugfs_off(dw);
-
return 0;
}
EXPORT_SYMBOL_GPL(dw_edma_remove);
diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h
index 85df2d511907..0ab2b6dba880 100644
--- a/drivers/dma/dw-edma/dw-edma-core.h
+++ b/drivers/dma/dw-edma/dw-edma-core.h
@@ -96,12 +96,11 @@ struct dw_edma_irq {
};
struct dw_edma {
- char name[20];
+ char name[32];
- struct dma_device wr_edma;
- u16 wr_ch_cnt;
+ struct dma_device dma;
- struct dma_device rd_edma;
+ u16 wr_ch_cnt;
u16 rd_ch_cnt;
struct dw_edma_irq *irq;
@@ -112,9 +111,6 @@ struct dw_edma {
raw_spinlock_t lock; /* Only for legacy */
struct dw_edma_chip *chip;
-#ifdef CONFIG_DEBUG_FS
- struct dentry *debugfs;
-#endif /* CONFIG_DEBUG_FS */
};
struct dw_edma_sg {
diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
index d6b5e2463884..2b40f2b44f5e 100644
--- a/drivers/dma/dw-edma/dw-edma-pcie.c
+++ b/drivers/dma/dw-edma/dw-edma-pcie.c
@@ -95,8 +95,23 @@ static int dw_edma_pcie_irq_vector(struct device *dev, unsigned int nr)
return pci_irq_vector(to_pci_dev(dev), nr);
}
+static u64 dw_edma_pcie_address(struct device *dev, phys_addr_t cpu_addr)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct pci_bus_region region;
+ struct resource res = {
+ .flags = IORESOURCE_MEM,
+ .start = cpu_addr,
+ .end = cpu_addr,
+ };
+
+ pcibios_resource_to_bus(pdev->bus, &region, &res);
+ return region.start;
+}
+
static const struct dw_edma_core_ops dw_edma_pcie_core_ops = {
.irq_vector = dw_edma_pcie_irq_vector,
+ .pci_address = dw_edma_pcie_address,
};
static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
@@ -207,7 +222,6 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
/* Data structure initialization */
chip->dev = dev;
- chip->id = pdev->devfn;
chip->mf = vsec_data.mf;
chip->nr_irqs = nr_irqs;
@@ -226,21 +240,21 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
struct dw_edma_block *ll_block = &vsec_data.ll_wr[i];
struct dw_edma_block *dt_block = &vsec_data.dt_wr[i];
- ll_region->vaddr = pcim_iomap_table(pdev)[ll_block->bar];
- if (!ll_region->vaddr)
+ ll_region->vaddr.io = pcim_iomap_table(pdev)[ll_block->bar];
+ if (!ll_region->vaddr.io)
return -ENOMEM;
- ll_region->vaddr += ll_block->off;
- ll_region->paddr = pdev->resource[ll_block->bar].start;
+ ll_region->vaddr.io += ll_block->off;
+ ll_region->paddr = pci_bus_address(pdev, ll_block->bar);
ll_region->paddr += ll_block->off;
ll_region->sz = ll_block->sz;
- dt_region->vaddr = pcim_iomap_table(pdev)[dt_block->bar];
- if (!dt_region->vaddr)
+ dt_region->vaddr.io = pcim_iomap_table(pdev)[dt_block->bar];
+ if (!dt_region->vaddr.io)
return -ENOMEM;
- dt_region->vaddr += dt_block->off;
- dt_region->paddr = pdev->resource[dt_block->bar].start;
+ dt_region->vaddr.io += dt_block->off;
+ dt_region->paddr = pci_bus_address(pdev, dt_block->bar);
dt_region->paddr += dt_block->off;
dt_region->sz = dt_block->sz;
}
@@ -251,21 +265,21 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
struct dw_edma_block *ll_block = &vsec_data.ll_rd[i];
struct dw_edma_block *dt_block = &vsec_data.dt_rd[i];
- ll_region->vaddr = pcim_iomap_table(pdev)[ll_block->bar];
- if (!ll_region->vaddr)
+ ll_region->vaddr.io = pcim_iomap_table(pdev)[ll_block->bar];
+ if (!ll_region->vaddr.io)
return -ENOMEM;
- ll_region->vaddr += ll_block->off;
- ll_region->paddr = pdev->resource[ll_block->bar].start;
+ ll_region->vaddr.io += ll_block->off;
+ ll_region->paddr = pci_bus_address(pdev, ll_block->bar);
ll_region->paddr += ll_block->off;
ll_region->sz = ll_block->sz;
- dt_region->vaddr = pcim_iomap_table(pdev)[dt_block->bar];
- if (!dt_region->vaddr)
+ dt_region->vaddr.io = pcim_iomap_table(pdev)[dt_block->bar];
+ if (!dt_region->vaddr.io)
return -ENOMEM;
- dt_region->vaddr += dt_block->off;
- dt_region->paddr = pdev->resource[dt_block->bar].start;
+ dt_region->vaddr.io += dt_block->off;
+ dt_region->paddr = pci_bus_address(pdev, dt_block->bar);
dt_region->paddr += dt_block->off;
dt_region->sz = dt_block->sz;
}
@@ -289,24 +303,24 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
pci_dbg(pdev, "L. List:\tWRITE CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
i, vsec_data.ll_wr[i].bar,
vsec_data.ll_wr[i].off, chip->ll_region_wr[i].sz,
- chip->ll_region_wr[i].vaddr, &chip->ll_region_wr[i].paddr);
+ chip->ll_region_wr[i].vaddr.io, &chip->ll_region_wr[i].paddr);
pci_dbg(pdev, "Data:\tWRITE CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
i, vsec_data.dt_wr[i].bar,
vsec_data.dt_wr[i].off, chip->dt_region_wr[i].sz,
- chip->dt_region_wr[i].vaddr, &chip->dt_region_wr[i].paddr);
+ chip->dt_region_wr[i].vaddr.io, &chip->dt_region_wr[i].paddr);
}
for (i = 0; i < chip->ll_rd_cnt; i++) {
pci_dbg(pdev, "L. List:\tREAD CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
i, vsec_data.ll_rd[i].bar,
vsec_data.ll_rd[i].off, chip->ll_region_rd[i].sz,
- chip->ll_region_rd[i].vaddr, &chip->ll_region_rd[i].paddr);
+ chip->ll_region_rd[i].vaddr.io, &chip->ll_region_rd[i].paddr);
pci_dbg(pdev, "Data:\tREAD CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
i, vsec_data.dt_rd[i].bar,
vsec_data.dt_rd[i].off, chip->dt_region_rd[i].sz,
- chip->dt_region_rd[i].vaddr, &chip->dt_region_rd[i].paddr);
+ chip->dt_region_rd[i].vaddr.io, &chip->dt_region_rd[i].paddr);
}
pci_dbg(pdev, "Nr. IRQs:\t%u\n", chip->nr_irqs);
diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c
index 77e6cfe52e0a..72e79a0c0a4e 100644
--- a/drivers/dma/dw-edma/dw-edma-v0-core.c
+++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
@@ -8,6 +8,8 @@
#include <linux/bitfield.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
+
#include "dw-edma-core.h"
#include "dw-edma-v0-core.h"
#include "dw-edma-v0-regs.h"
@@ -53,8 +55,6 @@ static inline struct dw_edma_v0_regs __iomem *__dw_regs(struct dw_edma *dw)
SET_32(dw, rd_##name, value); \
} while (0)
-#ifdef CONFIG_64BIT
-
#define SET_64(dw, name, value) \
writeq(value, &(__dw_regs(dw)->name))
@@ -80,8 +80,6 @@ static inline struct dw_edma_v0_regs __iomem *__dw_regs(struct dw_edma *dw)
SET_64(dw, rd_##name, value); \
} while (0)
-#endif /* CONFIG_64BIT */
-
#define SET_COMPAT(dw, name, value) \
writel(value, &(__dw_regs(dw)->type.unroll.name))
@@ -161,11 +159,6 @@ static inline u32 readl_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
#define GET_CH_32(dw, dir, ch, name) \
readl_ch(dw, dir, ch, &(__dw_ch_regs(dw, dir, ch)->name))
-#define SET_LL_32(ll, value) \
- writel(value, ll)
-
-#ifdef CONFIG_64BIT
-
static inline void writeq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
u64 value, void __iomem *addr)
{
@@ -192,7 +185,7 @@ static inline void writeq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
static inline u64 readq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
const void __iomem *addr)
{
- u32 value;
+ u64 value;
if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
u32 viewport_sel;
@@ -222,11 +215,6 @@ static inline u64 readq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
#define GET_CH_64(dw, dir, ch, name) \
readq_ch(dw, dir, ch, &(__dw_ch_regs(dw, dir, ch)->name))
-#define SET_LL_64(ll, value) \
- writeq(value, ll)
-
-#endif /* CONFIG_64BIT */
-
/* eDMA management callbacks */
void dw_edma_v0_core_off(struct dw_edma *dw)
{
@@ -298,17 +286,53 @@ u32 dw_edma_v0_core_status_abort_int(struct dw_edma *dw, enum dw_edma_dir dir)
GET_RW_32(dw, dir, int_status));
}
+static void dw_edma_v0_write_ll_data(struct dw_edma_chunk *chunk, int i,
+ u32 control, u32 size, u64 sar, u64 dar)
+{
+ ptrdiff_t ofs = i * sizeof(struct dw_edma_v0_lli);
+
+ if (chunk->chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) {
+ struct dw_edma_v0_lli *lli = chunk->ll_region.vaddr.mem + ofs;
+
+ lli->control = control;
+ lli->transfer_size = size;
+ lli->sar.reg = sar;
+ lli->dar.reg = dar;
+ } else {
+ struct dw_edma_v0_lli __iomem *lli = chunk->ll_region.vaddr.io + ofs;
+
+ writel(control, &lli->control);
+ writel(size, &lli->transfer_size);
+ writeq(sar, &lli->sar.reg);
+ writeq(dar, &lli->dar.reg);
+ }
+}
+
+static void dw_edma_v0_write_ll_link(struct dw_edma_chunk *chunk,
+ int i, u32 control, u64 pointer)
+{
+ ptrdiff_t ofs = i * sizeof(struct dw_edma_v0_lli);
+
+ if (chunk->chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) {
+ struct dw_edma_v0_llp *llp = chunk->ll_region.vaddr.mem + ofs;
+
+ llp->control = control;
+ llp->llp.reg = pointer;
+ } else {
+ struct dw_edma_v0_llp __iomem *llp = chunk->ll_region.vaddr.io + ofs;
+
+ writel(control, &llp->control);
+ writeq(pointer, &llp->llp.reg);
+ }
+}
+
static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
{
struct dw_edma_burst *child;
struct dw_edma_chan *chan = chunk->chan;
- struct dw_edma_v0_lli __iomem *lli;
- struct dw_edma_v0_llp __iomem *llp;
u32 control = 0, i = 0;
int j;
- lli = chunk->ll_region.vaddr;
-
if (chunk->cb)
control = DW_EDMA_V0_CB;
@@ -320,41 +344,16 @@ static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
if (!(chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL))
control |= DW_EDMA_V0_RIE;
}
- /* Channel control */
- SET_LL_32(&lli[i].control, control);
- /* Transfer size */
- SET_LL_32(&lli[i].transfer_size, child->sz);
- /* SAR */
- #ifdef CONFIG_64BIT
- SET_LL_64(&lli[i].sar.reg, child->sar);
- #else /* CONFIG_64BIT */
- SET_LL_32(&lli[i].sar.lsb, lower_32_bits(child->sar));
- SET_LL_32(&lli[i].sar.msb, upper_32_bits(child->sar));
- #endif /* CONFIG_64BIT */
- /* DAR */
- #ifdef CONFIG_64BIT
- SET_LL_64(&lli[i].dar.reg, child->dar);
- #else /* CONFIG_64BIT */
- SET_LL_32(&lli[i].dar.lsb, lower_32_bits(child->dar));
- SET_LL_32(&lli[i].dar.msb, upper_32_bits(child->dar));
- #endif /* CONFIG_64BIT */
- i++;
+
+ dw_edma_v0_write_ll_data(chunk, i++, control, child->sz,
+ child->sar, child->dar);
}
- llp = (void __iomem *)&lli[i];
control = DW_EDMA_V0_LLP | DW_EDMA_V0_TCB;
if (!chunk->cb)
control |= DW_EDMA_V0_CB;
- /* Channel control */
- SET_LL_32(&llp->control, control);
- /* Linked list */
- #ifdef CONFIG_64BIT
- SET_LL_64(&llp->llp.reg, chunk->ll_region.paddr);
- #else /* CONFIG_64BIT */
- SET_LL_32(&llp->llp.lsb, lower_32_bits(chunk->ll_region.paddr));
- SET_LL_32(&llp->llp.msb, upper_32_bits(chunk->ll_region.paddr));
- #endif /* CONFIG_64BIT */
+ dw_edma_v0_write_ll_link(chunk, i, control, chunk->ll_region.paddr);
}
void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
@@ -504,8 +503,3 @@ void dw_edma_v0_core_debugfs_on(struct dw_edma *dw)
{
dw_edma_v0_debugfs_on(dw);
}
-
-void dw_edma_v0_core_debugfs_off(struct dw_edma *dw)
-{
- dw_edma_v0_debugfs_off(dw);
-}
diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.h b/drivers/dma/dw-edma/dw-edma-v0-core.h
index 75aec6d31b21..ab96a1f48080 100644
--- a/drivers/dma/dw-edma/dw-edma-v0-core.h
+++ b/drivers/dma/dw-edma/dw-edma-v0-core.h
@@ -23,6 +23,5 @@ void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first);
int dw_edma_v0_core_device_config(struct dw_edma_chan *chan);
/* eDMA debug fs callbacks */
void dw_edma_v0_core_debugfs_on(struct dw_edma *dw);
-void dw_edma_v0_core_debugfs_off(struct dw_edma *dw);
#endif /* _DW_EDMA_V0_CORE_H */
diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
index 5226c9014703..0745d9e7d259 100644
--- a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
+++ b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
@@ -13,76 +13,79 @@
#include "dw-edma-v0-regs.h"
#include "dw-edma-core.h"
-#define REGS_ADDR(name) \
- ((void __force *)&regs->name)
-#define REGISTER(name) \
- { #name, REGS_ADDR(name) }
-
-#define WR_REGISTER(name) \
- { #name, REGS_ADDR(wr_##name) }
-#define RD_REGISTER(name) \
- { #name, REGS_ADDR(rd_##name) }
-
-#define WR_REGISTER_LEGACY(name) \
- { #name, REGS_ADDR(type.legacy.wr_##name) }
+#define REGS_ADDR(dw, name) \
+ ({ \
+ struct dw_edma_v0_regs __iomem *__regs = (dw)->chip->reg_base; \
+ \
+ (void __iomem *)&__regs->name; \
+ })
+
+#define REGS_CH_ADDR(dw, name, _dir, _ch) \
+ ({ \
+ struct dw_edma_v0_ch_regs __iomem *__ch_regs; \
+ \
+ if ((dw)->chip->mf == EDMA_MF_EDMA_LEGACY) \
+ __ch_regs = REGS_ADDR(dw, type.legacy.ch); \
+ else if (_dir == EDMA_DIR_READ) \
+ __ch_regs = REGS_ADDR(dw, type.unroll.ch[_ch].rd); \
+ else \
+ __ch_regs = REGS_ADDR(dw, type.unroll.ch[_ch].wr); \
+ \
+ (void __iomem *)&__ch_regs->name; \
+ })
+
+#define REGISTER(dw, name) \
+ { dw, #name, REGS_ADDR(dw, name) }
+
+#define CTX_REGISTER(dw, name, dir, ch) \
+ { dw, #name, REGS_CH_ADDR(dw, name, dir, ch), dir, ch }
+
+#define WR_REGISTER(dw, name) \
+ { dw, #name, REGS_ADDR(dw, wr_##name) }
+#define RD_REGISTER(dw, name) \
+ { dw, #name, REGS_ADDR(dw, rd_##name) }
+
+#define WR_REGISTER_LEGACY(dw, name) \
+ { dw, #name, REGS_ADDR(dw, type.legacy.wr_##name) }
#define RD_REGISTER_LEGACY(name) \
- { #name, REGS_ADDR(type.legacy.rd_##name) }
+ { dw, #name, REGS_ADDR(dw, type.legacy.rd_##name) }
-#define WR_REGISTER_UNROLL(name) \
- { #name, REGS_ADDR(type.unroll.wr_##name) }
-#define RD_REGISTER_UNROLL(name) \
- { #name, REGS_ADDR(type.unroll.rd_##name) }
+#define WR_REGISTER_UNROLL(dw, name) \
+ { dw, #name, REGS_ADDR(dw, type.unroll.wr_##name) }
+#define RD_REGISTER_UNROLL(dw, name) \
+ { dw, #name, REGS_ADDR(dw, type.unroll.rd_##name) }
#define WRITE_STR "write"
#define READ_STR "read"
#define CHANNEL_STR "channel"
#define REGISTERS_STR "registers"
-static struct dw_edma *dw;
-static struct dw_edma_v0_regs __iomem *regs;
-
-static struct {
- void __iomem *start;
- void __iomem *end;
-} lim[2][EDMA_V0_MAX_NR_CH];
-
-struct debugfs_entries {
+struct dw_edma_debugfs_entry {
+ struct dw_edma *dw;
const char *name;
- dma_addr_t *reg;
+ void __iomem *reg;
+ enum dw_edma_dir dir;
+ u16 ch;
};
static int dw_edma_debugfs_u32_get(void *data, u64 *val)
{
- void __iomem *reg = (void __force __iomem *)data;
+ struct dw_edma_debugfs_entry *entry = data;
+ struct dw_edma *dw = entry->dw;
+ void __iomem *reg = entry->reg;
+
if (dw->chip->mf == EDMA_MF_EDMA_LEGACY &&
- reg >= (void __iomem *)&regs->type.legacy.ch) {
- void __iomem *ptr = &regs->type.legacy.ch;
- u32 viewport_sel = 0;
+ reg >= REGS_ADDR(dw, type.legacy.ch)) {
unsigned long flags;
- u16 ch;
-
- for (ch = 0; ch < dw->wr_ch_cnt; ch++)
- if (lim[0][ch].start >= reg && reg < lim[0][ch].end) {
- ptr += (reg - lim[0][ch].start);
- goto legacy_sel_wr;
- }
-
- for (ch = 0; ch < dw->rd_ch_cnt; ch++)
- if (lim[1][ch].start >= reg && reg < lim[1][ch].end) {
- ptr += (reg - lim[1][ch].start);
- goto legacy_sel_rd;
- }
-
- return 0;
-legacy_sel_rd:
- viewport_sel = BIT(31);
-legacy_sel_wr:
- viewport_sel |= FIELD_PREP(EDMA_V0_VIEWPORT_MASK, ch);
+ u32 viewport_sel;
+
+ viewport_sel = entry->dir == EDMA_DIR_READ ? BIT(31) : 0;
+ viewport_sel |= FIELD_PREP(EDMA_V0_VIEWPORT_MASK, entry->ch);
raw_spin_lock_irqsave(&dw->lock, flags);
- writel(viewport_sel, &regs->type.legacy.viewport_sel);
- *val = readl(ptr);
+ writel(viewport_sel, REGS_ADDR(dw, type.legacy.viewport_sel));
+ *val = readl(reg);
raw_spin_unlock_irqrestore(&dw->lock, flags);
} else {
@@ -93,222 +96,197 @@ legacy_sel_wr:
}
DEFINE_DEBUGFS_ATTRIBUTE(fops_x32, dw_edma_debugfs_u32_get, NULL, "0x%08llx\n");
-static void dw_edma_debugfs_create_x32(const struct debugfs_entries entries[],
- int nr_entries, struct dentry *dir)
+static void dw_edma_debugfs_create_x32(struct dw_edma *dw,
+ const struct dw_edma_debugfs_entry ini[],
+ int nr_entries, struct dentry *dent)
{
+ struct dw_edma_debugfs_entry *entries;
int i;
+ entries = devm_kcalloc(dw->chip->dev, nr_entries, sizeof(*entries),
+ GFP_KERNEL);
+ if (!entries)
+ return;
+
for (i = 0; i < nr_entries; i++) {
- if (!debugfs_create_file_unsafe(entries[i].name, 0444, dir,
- entries[i].reg, &fops_x32))
- break;
+ entries[i] = ini[i];
+
+ debugfs_create_file_unsafe(entries[i].name, 0444, dent,
+ &entries[i], &fops_x32);
}
}
-static void dw_edma_debugfs_regs_ch(struct dw_edma_v0_ch_regs __iomem *regs,
- struct dentry *dir)
+static void dw_edma_debugfs_regs_ch(struct dw_edma *dw, enum dw_edma_dir dir,
+ u16 ch, struct dentry *dent)
{
- int nr_entries;
- const struct debugfs_entries debugfs_regs[] = {
- REGISTER(ch_control1),
- REGISTER(ch_control2),
- REGISTER(transfer_size),
- REGISTER(sar.lsb),
- REGISTER(sar.msb),
- REGISTER(dar.lsb),
- REGISTER(dar.msb),
- REGISTER(llp.lsb),
- REGISTER(llp.msb),
+ struct dw_edma_debugfs_entry debugfs_regs[] = {
+ CTX_REGISTER(dw, ch_control1, dir, ch),
+ CTX_REGISTER(dw, ch_control2, dir, ch),
+ CTX_REGISTER(dw, transfer_size, dir, ch),
+ CTX_REGISTER(dw, sar.lsb, dir, ch),
+ CTX_REGISTER(dw, sar.msb, dir, ch),
+ CTX_REGISTER(dw, dar.lsb, dir, ch),
+ CTX_REGISTER(dw, dar.msb, dir, ch),
+ CTX_REGISTER(dw, llp.lsb, dir, ch),
+ CTX_REGISTER(dw, llp.msb, dir, ch),
};
+ int nr_entries;
nr_entries = ARRAY_SIZE(debugfs_regs);
- dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, dir);
+ dw_edma_debugfs_create_x32(dw, debugfs_regs, nr_entries, dent);
}
-static void dw_edma_debugfs_regs_wr(struct dentry *dir)
+static noinline_for_stack void
+dw_edma_debugfs_regs_wr(struct dw_edma *dw, struct dentry *dent)
{
- const struct debugfs_entries debugfs_regs[] = {
+ const struct dw_edma_debugfs_entry debugfs_regs[] = {
/* eDMA global registers */
- WR_REGISTER(engine_en),
- WR_REGISTER(doorbell),
- WR_REGISTER(ch_arb_weight.lsb),
- WR_REGISTER(ch_arb_weight.msb),
+ WR_REGISTER(dw, engine_en),
+ WR_REGISTER(dw, doorbell),
+ WR_REGISTER(dw, ch_arb_weight.lsb),
+ WR_REGISTER(dw, ch_arb_weight.msb),
/* eDMA interrupts registers */
- WR_REGISTER(int_status),
- WR_REGISTER(int_mask),
- WR_REGISTER(int_clear),
- WR_REGISTER(err_status),
- WR_REGISTER(done_imwr.lsb),
- WR_REGISTER(done_imwr.msb),
- WR_REGISTER(abort_imwr.lsb),
- WR_REGISTER(abort_imwr.msb),
- WR_REGISTER(ch01_imwr_data),
- WR_REGISTER(ch23_imwr_data),
- WR_REGISTER(ch45_imwr_data),
- WR_REGISTER(ch67_imwr_data),
- WR_REGISTER(linked_list_err_en),
+ WR_REGISTER(dw, int_status),
+ WR_REGISTER(dw, int_mask),
+ WR_REGISTER(dw, int_clear),
+ WR_REGISTER(dw, err_status),
+ WR_REGISTER(dw, done_imwr.lsb),
+ WR_REGISTER(dw, done_imwr.msb),
+ WR_REGISTER(dw, abort_imwr.lsb),
+ WR_REGISTER(dw, abort_imwr.msb),
+ WR_REGISTER(dw, ch01_imwr_data),
+ WR_REGISTER(dw, ch23_imwr_data),
+ WR_REGISTER(dw, ch45_imwr_data),
+ WR_REGISTER(dw, ch67_imwr_data),
+ WR_REGISTER(dw, linked_list_err_en),
};
- const struct debugfs_entries debugfs_unroll_regs[] = {
+ const struct dw_edma_debugfs_entry debugfs_unroll_regs[] = {
/* eDMA channel context grouping */
- WR_REGISTER_UNROLL(engine_chgroup),
- WR_REGISTER_UNROLL(engine_hshake_cnt.lsb),
- WR_REGISTER_UNROLL(engine_hshake_cnt.msb),
- WR_REGISTER_UNROLL(ch0_pwr_en),
- WR_REGISTER_UNROLL(ch1_pwr_en),
- WR_REGISTER_UNROLL(ch2_pwr_en),
- WR_REGISTER_UNROLL(ch3_pwr_en),
- WR_REGISTER_UNROLL(ch4_pwr_en),
- WR_REGISTER_UNROLL(ch5_pwr_en),
- WR_REGISTER_UNROLL(ch6_pwr_en),
- WR_REGISTER_UNROLL(ch7_pwr_en),
+ WR_REGISTER_UNROLL(dw, engine_chgroup),
+ WR_REGISTER_UNROLL(dw, engine_hshake_cnt.lsb),
+ WR_REGISTER_UNROLL(dw, engine_hshake_cnt.msb),
+ WR_REGISTER_UNROLL(dw, ch0_pwr_en),
+ WR_REGISTER_UNROLL(dw, ch1_pwr_en),
+ WR_REGISTER_UNROLL(dw, ch2_pwr_en),
+ WR_REGISTER_UNROLL(dw, ch3_pwr_en),
+ WR_REGISTER_UNROLL(dw, ch4_pwr_en),
+ WR_REGISTER_UNROLL(dw, ch5_pwr_en),
+ WR_REGISTER_UNROLL(dw, ch6_pwr_en),
+ WR_REGISTER_UNROLL(dw, ch7_pwr_en),
};
- struct dentry *regs_dir, *ch_dir;
+ struct dentry *regs_dent, *ch_dent;
int nr_entries, i;
char name[16];
- regs_dir = debugfs_create_dir(WRITE_STR, dir);
- if (!regs_dir)
- return;
+ regs_dent = debugfs_create_dir(WRITE_STR, dent);
nr_entries = ARRAY_SIZE(debugfs_regs);
- dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
+ dw_edma_debugfs_create_x32(dw, debugfs_regs, nr_entries, regs_dent);
if (dw->chip->mf == EDMA_MF_HDMA_COMPAT) {
nr_entries = ARRAY_SIZE(debugfs_unroll_regs);
- dw_edma_debugfs_create_x32(debugfs_unroll_regs, nr_entries,
- regs_dir);
+ dw_edma_debugfs_create_x32(dw, debugfs_unroll_regs, nr_entries,
+ regs_dent);
}
for (i = 0; i < dw->wr_ch_cnt; i++) {
snprintf(name, sizeof(name), "%s:%d", CHANNEL_STR, i);
- ch_dir = debugfs_create_dir(name, regs_dir);
- if (!ch_dir)
- return;
-
- dw_edma_debugfs_regs_ch(&regs->type.unroll.ch[i].wr, ch_dir);
+ ch_dent = debugfs_create_dir(name, regs_dent);
- lim[0][i].start = &regs->type.unroll.ch[i].wr;
- lim[0][i].end = &regs->type.unroll.ch[i].padding_1[0];
+ dw_edma_debugfs_regs_ch(dw, EDMA_DIR_WRITE, i, ch_dent);
}
}
-static void dw_edma_debugfs_regs_rd(struct dentry *dir)
+static noinline_for_stack void dw_edma_debugfs_regs_rd(struct dw_edma *dw,
+ struct dentry *dent)
{
- const struct debugfs_entries debugfs_regs[] = {
+ const struct dw_edma_debugfs_entry debugfs_regs[] = {
/* eDMA global registers */
- RD_REGISTER(engine_en),
- RD_REGISTER(doorbell),
- RD_REGISTER(ch_arb_weight.lsb),
- RD_REGISTER(ch_arb_weight.msb),
+ RD_REGISTER(dw, engine_en),
+ RD_REGISTER(dw, doorbell),
+ RD_REGISTER(dw, ch_arb_weight.lsb),
+ RD_REGISTER(dw, ch_arb_weight.msb),
/* eDMA interrupts registers */
- RD_REGISTER(int_status),
- RD_REGISTER(int_mask),
- RD_REGISTER(int_clear),
- RD_REGISTER(err_status.lsb),
- RD_REGISTER(err_status.msb),
- RD_REGISTER(linked_list_err_en),
- RD_REGISTER(done_imwr.lsb),
- RD_REGISTER(done_imwr.msb),
- RD_REGISTER(abort_imwr.lsb),
- RD_REGISTER(abort_imwr.msb),
- RD_REGISTER(ch01_imwr_data),
- RD_REGISTER(ch23_imwr_data),
- RD_REGISTER(ch45_imwr_data),
- RD_REGISTER(ch67_imwr_data),
+ RD_REGISTER(dw, int_status),
+ RD_REGISTER(dw, int_mask),
+ RD_REGISTER(dw, int_clear),
+ RD_REGISTER(dw, err_status.lsb),
+ RD_REGISTER(dw, err_status.msb),
+ RD_REGISTER(dw, linked_list_err_en),
+ RD_REGISTER(dw, done_imwr.lsb),
+ RD_REGISTER(dw, done_imwr.msb),
+ RD_REGISTER(dw, abort_imwr.lsb),
+ RD_REGISTER(dw, abort_imwr.msb),
+ RD_REGISTER(dw, ch01_imwr_data),
+ RD_REGISTER(dw, ch23_imwr_data),
+ RD_REGISTER(dw, ch45_imwr_data),
+ RD_REGISTER(dw, ch67_imwr_data),
};
- const struct debugfs_entries debugfs_unroll_regs[] = {
+ const struct dw_edma_debugfs_entry debugfs_unroll_regs[] = {
/* eDMA channel context grouping */
- RD_REGISTER_UNROLL(engine_chgroup),
- RD_REGISTER_UNROLL(engine_hshake_cnt.lsb),
- RD_REGISTER_UNROLL(engine_hshake_cnt.msb),
- RD_REGISTER_UNROLL(ch0_pwr_en),
- RD_REGISTER_UNROLL(ch1_pwr_en),
- RD_REGISTER_UNROLL(ch2_pwr_en),
- RD_REGISTER_UNROLL(ch3_pwr_en),
- RD_REGISTER_UNROLL(ch4_pwr_en),
- RD_REGISTER_UNROLL(ch5_pwr_en),
- RD_REGISTER_UNROLL(ch6_pwr_en),
- RD_REGISTER_UNROLL(ch7_pwr_en),
+ RD_REGISTER_UNROLL(dw, engine_chgroup),
+ RD_REGISTER_UNROLL(dw, engine_hshake_cnt.lsb),
+ RD_REGISTER_UNROLL(dw, engine_hshake_cnt.msb),
+ RD_REGISTER_UNROLL(dw, ch0_pwr_en),
+ RD_REGISTER_UNROLL(dw, ch1_pwr_en),
+ RD_REGISTER_UNROLL(dw, ch2_pwr_en),
+ RD_REGISTER_UNROLL(dw, ch3_pwr_en),
+ RD_REGISTER_UNROLL(dw, ch4_pwr_en),
+ RD_REGISTER_UNROLL(dw, ch5_pwr_en),
+ RD_REGISTER_UNROLL(dw, ch6_pwr_en),
+ RD_REGISTER_UNROLL(dw, ch7_pwr_en),
};
- struct dentry *regs_dir, *ch_dir;
+ struct dentry *regs_dent, *ch_dent;
int nr_entries, i;
char name[16];
- regs_dir = debugfs_create_dir(READ_STR, dir);
- if (!regs_dir)
- return;
+ regs_dent = debugfs_create_dir(READ_STR, dent);
nr_entries = ARRAY_SIZE(debugfs_regs);
- dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
+ dw_edma_debugfs_create_x32(dw, debugfs_regs, nr_entries, regs_dent);
if (dw->chip->mf == EDMA_MF_HDMA_COMPAT) {
nr_entries = ARRAY_SIZE(debugfs_unroll_regs);
- dw_edma_debugfs_create_x32(debugfs_unroll_regs, nr_entries,
- regs_dir);
+ dw_edma_debugfs_create_x32(dw, debugfs_unroll_regs, nr_entries,
+ regs_dent);
}
for (i = 0; i < dw->rd_ch_cnt; i++) {
snprintf(name, sizeof(name), "%s:%d", CHANNEL_STR, i);
- ch_dir = debugfs_create_dir(name, regs_dir);
- if (!ch_dir)
- return;
-
- dw_edma_debugfs_regs_ch(&regs->type.unroll.ch[i].rd, ch_dir);
+ ch_dent = debugfs_create_dir(name, regs_dent);
- lim[1][i].start = &regs->type.unroll.ch[i].rd;
- lim[1][i].end = &regs->type.unroll.ch[i].padding_2[0];
+ dw_edma_debugfs_regs_ch(dw, EDMA_DIR_READ, i, ch_dent);
}
}
-static void dw_edma_debugfs_regs(void)
+static void dw_edma_debugfs_regs(struct dw_edma *dw)
{
- const struct debugfs_entries debugfs_regs[] = {
- REGISTER(ctrl_data_arb_prior),
- REGISTER(ctrl),
+ const struct dw_edma_debugfs_entry debugfs_regs[] = {
+ REGISTER(dw, ctrl_data_arb_prior),
+ REGISTER(dw, ctrl),
};
- struct dentry *regs_dir;
+ struct dentry *regs_dent;
int nr_entries;
- regs_dir = debugfs_create_dir(REGISTERS_STR, dw->debugfs);
- if (!regs_dir)
- return;
+ regs_dent = debugfs_create_dir(REGISTERS_STR, dw->dma.dbg_dev_root);
nr_entries = ARRAY_SIZE(debugfs_regs);
- dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
+ dw_edma_debugfs_create_x32(dw, debugfs_regs, nr_entries, regs_dent);
- dw_edma_debugfs_regs_wr(regs_dir);
- dw_edma_debugfs_regs_rd(regs_dir);
+ dw_edma_debugfs_regs_wr(dw, regs_dent);
+ dw_edma_debugfs_regs_rd(dw, regs_dent);
}
-void dw_edma_v0_debugfs_on(struct dw_edma *_dw)
+void dw_edma_v0_debugfs_on(struct dw_edma *dw)
{
- dw = _dw;
- if (!dw)
- return;
-
- regs = dw->chip->reg_base;
- if (!regs)
- return;
-
- dw->debugfs = debugfs_create_dir(dw->name, NULL);
- if (!dw->debugfs)
+ if (!debugfs_initialized())
return;
- debugfs_create_u32("mf", 0444, dw->debugfs, &dw->chip->mf);
- debugfs_create_u16("wr_ch_cnt", 0444, dw->debugfs, &dw->wr_ch_cnt);
- debugfs_create_u16("rd_ch_cnt", 0444, dw->debugfs, &dw->rd_ch_cnt);
-
- dw_edma_debugfs_regs();
-}
-
-void dw_edma_v0_debugfs_off(struct dw_edma *_dw)
-{
- dw = _dw;
- if (!dw)
- return;
+ debugfs_create_u32("mf", 0444, dw->dma.dbg_dev_root, &dw->chip->mf);
+ debugfs_create_u16("wr_ch_cnt", 0444, dw->dma.dbg_dev_root, &dw->wr_ch_cnt);
+ debugfs_create_u16("rd_ch_cnt", 0444, dw->dma.dbg_dev_root, &dw->rd_ch_cnt);
- debugfs_remove_recursive(dw->debugfs);
- dw->debugfs = NULL;
+ dw_edma_debugfs_regs(dw);
}
diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.h b/drivers/dma/dw-edma/dw-edma-v0-debugfs.h
index 3391b86edf5a..fb3342d97d6d 100644
--- a/drivers/dma/dw-edma/dw-edma-v0-debugfs.h
+++ b/drivers/dma/dw-edma/dw-edma-v0-debugfs.h
@@ -13,15 +13,10 @@
#ifdef CONFIG_DEBUG_FS
void dw_edma_v0_debugfs_on(struct dw_edma *dw);
-void dw_edma_v0_debugfs_off(struct dw_edma *dw);
#else
static inline void dw_edma_v0_debugfs_on(struct dw_edma *dw)
{
}
-
-static inline void dw_edma_v0_debugfs_off(struct dw_edma *dw)
-{
-}
#endif /* CONFIG_DEBUG_FS */
#endif /* _DW_EDMA_V0_DEBUG_FS_H */
diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c
index 97ba3bfc10b1..5f7d690e3dba 100644
--- a/drivers/dma/dw/core.c
+++ b/drivers/dma/dw/core.c
@@ -889,7 +889,8 @@ static struct dw_desc *dwc_find_desc(struct dw_dma_chan *dwc, dma_cookie_t c)
return NULL;
}
-static u32 dwc_get_residue(struct dw_dma_chan *dwc, dma_cookie_t cookie)
+static u32 dwc_get_residue_and_status(struct dw_dma_chan *dwc, dma_cookie_t cookie,
+ enum dma_status *status)
{
struct dw_desc *desc;
unsigned long flags;
@@ -903,6 +904,8 @@ static u32 dwc_get_residue(struct dw_dma_chan *dwc, dma_cookie_t cookie)
residue = desc->residue;
if (test_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags) && residue)
residue -= dwc_get_sent(dwc);
+ if (test_bit(DW_DMA_IS_PAUSED, &dwc->flags))
+ *status = DMA_PAUSED;
} else {
residue = desc->total_len;
}
@@ -932,11 +935,7 @@ dwc_tx_status(struct dma_chan *chan,
if (ret == DMA_COMPLETE)
return ret;
- dma_set_residue(txstate, dwc_get_residue(dwc, cookie));
-
- if (test_bit(DW_DMA_IS_PAUSED, &dwc->flags) && ret == DMA_IN_PROGRESS)
- return DMA_PAUSED;
-
+ dma_set_residue(txstate, dwc_get_residue_and_status(dwc, cookie, &ret));
return ret;
}
diff --git a/drivers/dma/fsl-edma.c b/drivers/dma/fsl-edma.c
index 76cbf54aec58..e40769666e39 100644
--- a/drivers/dma/fsl-edma.c
+++ b/drivers/dma/fsl-edma.c
@@ -272,7 +272,6 @@ static int fsl_edma_probe(struct platform_device *pdev)
const struct fsl_edma_drvdata *drvdata = NULL;
struct fsl_edma_chan *fsl_chan;
struct edma_regs *regs;
- struct resource *res;
int len, chans;
int ret, i;
@@ -298,8 +297,7 @@ static int fsl_edma_probe(struct platform_device *pdev)
fsl_edma->n_chans = chans;
mutex_init(&fsl_edma->fsl_edma_mutex);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- fsl_edma->membase = devm_ioremap_resource(&pdev->dev, res);
+ fsl_edma->membase = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(fsl_edma->membase))
return PTR_ERR(fsl_edma->membase);
@@ -323,8 +321,8 @@ static int fsl_edma_probe(struct platform_device *pdev)
for (i = 0; i < fsl_edma->drvdata->dmamuxs; i++) {
char clkname[32];
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1 + i);
- fsl_edma->muxbase[i] = devm_ioremap_resource(&pdev->dev, res);
+ fsl_edma->muxbase[i] = devm_platform_ioremap_resource(pdev,
+ 1 + i);
if (IS_ERR(fsl_edma->muxbase[i])) {
/* on error: disable all previously enabled clks */
fsl_disable_clocks(fsl_edma, i);
diff --git a/drivers/dma/fsl-qdma.c b/drivers/dma/fsl-qdma.c
index 045ead46ec8f..eddb2688f234 100644
--- a/drivers/dma/fsl-qdma.c
+++ b/drivers/dma/fsl-qdma.c
@@ -1119,7 +1119,6 @@ static int fsl_qdma_probe(struct platform_device *pdev)
int ret, i;
int blk_num, blk_off;
u32 len, chans, queues;
- struct resource *res;
struct fsl_qdma_chan *fsl_chan;
struct fsl_qdma_engine *fsl_qdma;
struct device_node *np = pdev->dev.of_node;
@@ -1183,18 +1182,15 @@ static int fsl_qdma_probe(struct platform_device *pdev)
if (!fsl_qdma->status[i])
return -ENOMEM;
}
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- fsl_qdma->ctrl_base = devm_ioremap_resource(&pdev->dev, res);
+ fsl_qdma->ctrl_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(fsl_qdma->ctrl_base))
return PTR_ERR(fsl_qdma->ctrl_base);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- fsl_qdma->status_base = devm_ioremap_resource(&pdev->dev, res);
+ fsl_qdma->status_base = devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(fsl_qdma->status_base))
return PTR_ERR(fsl_qdma->status_base);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
- fsl_qdma->block_base = devm_ioremap_resource(&pdev->dev, res);
+ fsl_qdma->block_base = devm_platform_ioremap_resource(pdev, 2);
if (IS_ERR(fsl_qdma->block_base))
return PTR_ERR(fsl_qdma->block_base);
fsl_qdma->queue = fsl_qdma_alloc_queue_resources(pdev, fsl_qdma);
diff --git a/drivers/dma/idma64.c b/drivers/dma/idma64.c
index c33087c5cd02..0ac634a51c5e 100644
--- a/drivers/dma/idma64.c
+++ b/drivers/dma/idma64.c
@@ -137,8 +137,11 @@ static void idma64_chan_irq(struct idma64 *idma64, unsigned short c,
u32 status_err, u32 status_xfer)
{
struct idma64_chan *idma64c = &idma64->chan[c];
+ struct dma_chan_percpu *stat;
struct idma64_desc *desc;
+ stat = this_cpu_ptr(idma64c->vchan.chan.local);
+
spin_lock(&idma64c->vchan.lock);
desc = idma64c->desc;
if (desc) {
@@ -149,6 +152,7 @@ static void idma64_chan_irq(struct idma64 *idma64, unsigned short c,
dma_writel(idma64, CLEAR(XFER), idma64c->mask);
desc->status = DMA_COMPLETE;
vchan_cookie_complete(&desc->vdesc);
+ stat->bytes_transferred += desc->length;
idma64_start_transfer(idma64c);
}
@@ -627,7 +631,6 @@ static int idma64_platform_probe(struct platform_device *pdev)
struct idma64_chip *chip;
struct device *dev = &pdev->dev;
struct device *sysdev = dev->parent;
- struct resource *mem;
int ret;
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
@@ -638,8 +641,7 @@ static int idma64_platform_probe(struct platform_device *pdev)
if (chip->irq < 0)
return chip->irq;
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- chip->regs = devm_ioremap_resource(dev, mem);
+ chip->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(chip->regs))
return PTR_ERR(chip->regs);
diff --git a/drivers/dma/idxd/cdev.c b/drivers/dma/idxd/cdev.c
index e13e92609943..674bfefca088 100644
--- a/drivers/dma/idxd/cdev.c
+++ b/drivers/dma/idxd/cdev.c
@@ -201,7 +201,7 @@ static int idxd_cdev_mmap(struct file *filp, struct vm_area_struct *vma)
if (rc < 0)
return rc;
- vma->vm_flags |= VM_DONTCOPY;
+ vm_flags_set(vma, VM_DONTCOPY);
pfn = (base + idxd_get_wq_portal_full_offset(wq->id,
IDXD_PORTAL_LIMITED)) >> PAGE_SHIFT;
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c
index 29dbb0f52e18..5f321f3b4242 100644
--- a/drivers/dma/idxd/device.c
+++ b/drivers/dma/idxd/device.c
@@ -699,9 +699,13 @@ static void idxd_groups_clear_state(struct idxd_device *idxd)
group->num_engines = 0;
group->num_wqs = 0;
group->use_rdbuf_limit = false;
- group->rdbufs_allowed = 0;
+ /*
+ * The default value is the same as the value of
+ * total read buffers in GRPCAP.
+ */
+ group->rdbufs_allowed = idxd->max_rdbufs;
group->rdbufs_reserved = 0;
- if (idxd->hw.version < DEVICE_VERSION_2 && !tc_override) {
+ if (idxd->hw.version <= DEVICE_VERSION_2 && !tc_override) {
group->tc_a = 1;
group->tc_b = 1;
} else {
@@ -934,11 +938,7 @@ static void idxd_group_flags_setup(struct idxd_device *idxd)
group->grpcfg.flags.tc_b = group->tc_b;
group->grpcfg.flags.use_rdbuf_limit = group->use_rdbuf_limit;
group->grpcfg.flags.rdbufs_reserved = group->rdbufs_reserved;
- if (group->rdbufs_allowed)
- group->grpcfg.flags.rdbufs_allowed = group->rdbufs_allowed;
- else
- group->grpcfg.flags.rdbufs_allowed = idxd->max_rdbufs;
-
+ group->grpcfg.flags.rdbufs_allowed = group->rdbufs_allowed;
group->grpcfg.flags.desc_progress_limit = group->desc_progress_limit;
group->grpcfg.flags.batch_progress_limit = group->batch_progress_limit;
}
diff --git a/drivers/dma/idxd/dma.c b/drivers/dma/idxd/dma.c
index e0874cb4721c..eb35ca313684 100644
--- a/drivers/dma/idxd/dma.c
+++ b/drivers/dma/idxd/dma.c
@@ -63,12 +63,6 @@ static void op_flag_setup(unsigned long flags, u32 *desc_flags)
*desc_flags |= IDXD_OP_FLAG_RCI;
}
-static inline void set_completion_address(struct idxd_desc *desc,
- u64 *compl_addr)
-{
- *compl_addr = desc->compl_dma;
-}
-
static inline void idxd_prep_desc_common(struct idxd_wq *wq,
struct dsa_hw_desc *hw, char opcode,
u64 addr_f1, u64 addr_f2, u64 len,
diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c
index 529ea09c9094..640d3048368e 100644
--- a/drivers/dma/idxd/init.c
+++ b/drivers/dma/idxd/init.c
@@ -295,13 +295,18 @@ static int idxd_setup_groups(struct idxd_device *idxd)
}
idxd->groups[i] = group;
- if (idxd->hw.version < DEVICE_VERSION_2 && !tc_override) {
+ if (idxd->hw.version <= DEVICE_VERSION_2 && !tc_override) {
group->tc_a = 1;
group->tc_b = 1;
} else {
group->tc_a = -1;
group->tc_b = -1;
}
+ /*
+ * The default value is the same as the value of
+ * total read buffers in GRPCAP.
+ */
+ group->rdbufs_allowed = idxd->max_rdbufs;
}
return 0;
diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c
index 3229dfc78650..18cd8151dee0 100644
--- a/drivers/dma/idxd/sysfs.c
+++ b/drivers/dma/idxd/sysfs.c
@@ -387,7 +387,7 @@ static ssize_t group_traffic_class_a_store(struct device *dev,
if (idxd->state == IDXD_DEV_ENABLED)
return -EPERM;
- if (idxd->hw.version < DEVICE_VERSION_2 && !tc_override)
+ if (idxd->hw.version <= DEVICE_VERSION_2 && !tc_override)
return -EPERM;
if (val < 0 || val > 7)
@@ -429,7 +429,7 @@ static ssize_t group_traffic_class_b_store(struct device *dev,
if (idxd->state == IDXD_DEV_ENABLED)
return -EPERM;
- if (idxd->hw.version < DEVICE_VERSION_2 && !tc_override)
+ if (idxd->hw.version <= DEVICE_VERSION_2 && !tc_override)
return -EPERM;
if (val < 0 || val > 7)
diff --git a/drivers/dma/img-mdc-dma.c b/drivers/dma/img-mdc-dma.c
index e4ea107ce78c..ad084552640f 100644
--- a/drivers/dma/img-mdc-dma.c
+++ b/drivers/dma/img-mdc-dma.c
@@ -886,7 +886,6 @@ static int img_mdc_runtime_resume(struct device *dev)
static int mdc_dma_probe(struct platform_device *pdev)
{
struct mdc_dma *mdma;
- struct resource *res;
unsigned int i;
u32 val;
int ret;
@@ -898,8 +897,7 @@ static int mdc_dma_probe(struct platform_device *pdev)
mdma->soc = of_device_get_match_data(&pdev->dev);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- mdma->regs = devm_ioremap_resource(&pdev->dev, res);
+ mdma->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(mdma->regs))
return PTR_ERR(mdma->regs);
diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c
index 65c6094ce063..80086977973f 100644
--- a/drivers/dma/imx-dma.c
+++ b/drivers/dma/imx-dma.c
@@ -1038,7 +1038,6 @@ static struct dma_chan *imxdma_xlate(struct of_phandle_args *dma_spec,
static int __init imxdma_probe(struct platform_device *pdev)
{
struct imxdma_engine *imxdma;
- struct resource *res;
int ret, i;
int irq, irq_err;
@@ -1049,8 +1048,7 @@ static int __init imxdma_probe(struct platform_device *pdev)
imxdma->dev = &pdev->dev;
imxdma->devtype = (uintptr_t)of_device_get_match_data(&pdev->dev);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- imxdma->base = devm_ioremap_resource(&pdev->dev, res);
+ imxdma->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(imxdma->base))
return PTR_ERR(imxdma->base);
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index b926abe4fa43..7a912f90c2a9 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -954,7 +954,10 @@ static irqreturn_t sdma_int_handler(int irq, void *dev_id)
desc = sdmac->desc;
if (desc) {
if (sdmac->flags & IMX_DMA_SG_LOOP) {
- sdma_update_channel_loop(sdmac);
+ if (sdmac->peripheral_type != IMX_DMATYPE_HDMI)
+ sdma_update_channel_loop(sdmac);
+ else
+ vchan_cyclic_callback(&desc->vd);
} else {
mxc_sdma_handle_channel_normal(sdmac);
vchan_cookie_complete(&desc->vd);
@@ -1074,6 +1077,10 @@ static int sdma_get_pc(struct sdma_channel *sdmac,
per_2_emi = sdma->script_addrs->sai_2_mcu_addr;
emi_2_per = sdma->script_addrs->mcu_2_sai_addr;
break;
+ case IMX_DMATYPE_HDMI:
+ emi_2_per = sdma->script_addrs->hdmi_dma_addr;
+ sdmac->is_ram_script = true;
+ break;
default:
dev_err(sdma->dev, "Unsupported transfer type %d\n",
peripheral_type);
@@ -1125,11 +1132,16 @@ static int sdma_load_context(struct sdma_channel *sdmac)
/* Send by context the event mask,base address for peripheral
* and watermark level
*/
- context->gReg[0] = sdmac->event_mask[1];
- context->gReg[1] = sdmac->event_mask[0];
- context->gReg[2] = sdmac->per_addr;
- context->gReg[6] = sdmac->shp_addr;
- context->gReg[7] = sdmac->watermark_level;
+ if (sdmac->peripheral_type == IMX_DMATYPE_HDMI) {
+ context->gReg[4] = sdmac->per_addr;
+ context->gReg[6] = sdmac->shp_addr;
+ } else {
+ context->gReg[0] = sdmac->event_mask[1];
+ context->gReg[1] = sdmac->event_mask[0];
+ context->gReg[2] = sdmac->per_addr;
+ context->gReg[6] = sdmac->shp_addr;
+ context->gReg[7] = sdmac->watermark_level;
+ }
bd0->mode.command = C0_SETDM;
bd0->mode.status = BD_DONE | BD_WRAP | BD_EXTD;
@@ -1513,7 +1525,7 @@ static struct sdma_desc *sdma_transfer_init(struct sdma_channel *sdmac,
desc->sdmac = sdmac;
desc->num_bd = bds;
- if (sdma_alloc_bd(desc))
+ if (bds && sdma_alloc_bd(desc))
goto err_desc_out;
/* No slave_config called in MEMCPY case, so do here */
@@ -1680,13 +1692,16 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
{
struct sdma_channel *sdmac = to_sdma_chan(chan);
struct sdma_engine *sdma = sdmac->sdma;
- int num_periods = buf_len / period_len;
+ int num_periods = 0;
int channel = sdmac->channel;
int i = 0, buf = 0;
struct sdma_desc *desc;
dev_dbg(sdma->dev, "%s channel: %d\n", __func__, channel);
+ if (sdmac->peripheral_type != IMX_DMATYPE_HDMI)
+ num_periods = buf_len / period_len;
+
sdma_config_write(chan, &sdmac->slave_config, direction);
desc = sdma_transfer_init(sdmac, direction, num_periods);
@@ -1703,6 +1718,9 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
goto err_bd_out;
}
+ if (sdmac->peripheral_type == IMX_DMATYPE_HDMI)
+ return vchan_tx_prep(&sdmac->vc, &desc->vd, flags);
+
while (buf < buf_len) {
struct sdma_buffer_descriptor *bd = &desc->bd[i];
int param;
@@ -1763,6 +1781,10 @@ static int sdma_config_write(struct dma_chan *chan,
sdmac->watermark_level |= (dmaengine_cfg->dst_maxburst << 16) &
SDMA_WATERMARK_LEVEL_HWML;
sdmac->word_size = dmaengine_cfg->dst_addr_width;
+ } else if (sdmac->peripheral_type == IMX_DMATYPE_HDMI) {
+ sdmac->per_address = dmaengine_cfg->dst_addr;
+ sdmac->per_address2 = dmaengine_cfg->src_addr;
+ sdmac->watermark_level = 0;
} else {
sdmac->per_address = dmaengine_cfg->dst_addr;
sdmac->watermark_level = dmaengine_cfg->dst_maxburst *
@@ -2169,7 +2191,6 @@ static int sdma_probe(struct platform_device *pdev)
const char *fw_name;
int ret;
int irq;
- struct resource *iores;
struct resource spba_res;
int i;
struct sdma_engine *sdma;
@@ -2192,8 +2213,7 @@ static int sdma_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
- iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- sdma->regs = devm_ioremap_resource(&pdev->dev, iores);
+ sdma->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(sdma->regs))
return PTR_ERR(sdma->regs);
@@ -2234,6 +2254,7 @@ static int sdma_probe(struct platform_device *pdev)
dma_cap_set(DMA_SLAVE, sdma->dma_device.cap_mask);
dma_cap_set(DMA_CYCLIC, sdma->dma_device.cap_mask);
dma_cap_set(DMA_MEMCPY, sdma->dma_device.cap_mask);
+ dma_cap_set(DMA_PRIVATE, sdma->dma_device.cap_mask);
INIT_LIST_HEAD(&sdma->dma_device.channels);
/* Initialize channel parameters */
diff --git a/drivers/dma/mcf-edma.c b/drivers/dma/mcf-edma.c
index e12b754e6398..ebd8733f72ad 100644
--- a/drivers/dma/mcf-edma.c
+++ b/drivers/dma/mcf-edma.c
@@ -182,7 +182,6 @@ static int mcf_edma_probe(struct platform_device *pdev)
struct fsl_edma_engine *mcf_edma;
struct fsl_edma_chan *mcf_chan;
struct edma_regs *regs;
- struct resource *res;
int ret, i, len, chans;
pdata = dev_get_platdata(&pdev->dev);
@@ -210,9 +209,7 @@ static int mcf_edma_probe(struct platform_device *pdev)
mutex_init(&mcf_edma->fsl_edma_mutex);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
- mcf_edma->membase = devm_ioremap_resource(&pdev->dev, res);
+ mcf_edma->membase = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(mcf_edma->membase))
return PTR_ERR(mcf_edma->membase);
diff --git a/drivers/dma/mediatek/mtk-hsdma.c b/drivers/dma/mediatek/mtk-hsdma.c
index f7717c44b887..69cc61c0b262 100644
--- a/drivers/dma/mediatek/mtk-hsdma.c
+++ b/drivers/dma/mediatek/mtk-hsdma.c
@@ -896,7 +896,6 @@ static int mtk_hsdma_probe(struct platform_device *pdev)
struct mtk_hsdma_device *hsdma;
struct mtk_hsdma_vchan *vc;
struct dma_device *dd;
- struct resource *res;
int i, err;
hsdma = devm_kzalloc(&pdev->dev, sizeof(*hsdma), GFP_KERNEL);
@@ -905,8 +904,7 @@ static int mtk_hsdma_probe(struct platform_device *pdev)
dd = &hsdma->ddev;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- hsdma->base = devm_ioremap_resource(&pdev->dev, res);
+ hsdma->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(hsdma->base))
return PTR_ERR(hsdma->base);
diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c
index e8d71b35593e..ebdfdcbb4f7a 100644
--- a/drivers/dma/mmp_pdma.c
+++ b/drivers/dma/mmp_pdma.c
@@ -1022,7 +1022,6 @@ static int mmp_pdma_probe(struct platform_device *op)
struct mmp_pdma_device *pdev;
const struct of_device_id *of_id;
struct mmp_dma_platdata *pdata = dev_get_platdata(&op->dev);
- struct resource *iores;
int i, ret, irq = 0;
int dma_channels = 0, irq_num = 0;
const enum dma_slave_buswidth widths =
@@ -1037,8 +1036,7 @@ static int mmp_pdma_probe(struct platform_device *op)
spin_lock_init(&pdev->phy_lock);
- iores = platform_get_resource(op, IORESOURCE_MEM, 0);
- pdev->base = devm_ioremap_resource(pdev->dev, iores);
+ pdev->base = devm_platform_ioremap_resource(op, 0);
if (IS_ERR(pdev->base))
return PTR_ERR(pdev->base);
diff --git a/drivers/dma/mmp_tdma.c b/drivers/dma/mmp_tdma.c
index d83e608dca05..d49fa6bc6775 100644
--- a/drivers/dma/mmp_tdma.c
+++ b/drivers/dma/mmp_tdma.c
@@ -639,7 +639,6 @@ static int mmp_tdma_probe(struct platform_device *pdev)
enum mmp_tdma_type type;
const struct of_device_id *of_id;
struct mmp_tdma_device *tdev;
- struct resource *iores;
int i, ret;
int irq = 0, irq_num = 0;
int chan_num = TDMA_CHANNEL_NUM;
@@ -663,8 +662,7 @@ static int mmp_tdma_probe(struct platform_device *pdev)
irq_num++;
}
- iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- tdev->base = devm_ioremap_resource(&pdev->dev, iores);
+ tdev->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(tdev->base))
return PTR_ERR(tdev->base);
diff --git a/drivers/dma/moxart-dma.c b/drivers/dma/moxart-dma.c
index 7459382a8353..7565ad98ba66 100644
--- a/drivers/dma/moxart-dma.c
+++ b/drivers/dma/moxart-dma.c
@@ -563,7 +563,6 @@ static int moxart_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *node = dev->of_node;
- struct resource *res;
void __iomem *dma_base_addr;
int ret, i;
unsigned int irq;
@@ -580,8 +579,7 @@ static int moxart_probe(struct platform_device *pdev)
return -EINVAL;
}
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- dma_base_addr = devm_ioremap_resource(dev, res);
+ dma_base_addr = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(dma_base_addr))
return PTR_ERR(dma_base_addr);
diff --git a/drivers/dma/mv_xor_v2.c b/drivers/dma/mv_xor_v2.c
index 113834e1167b..89790beba305 100644
--- a/drivers/dma/mv_xor_v2.c
+++ b/drivers/dma/mv_xor_v2.c
@@ -714,7 +714,6 @@ static int mv_xor_v2_resume(struct platform_device *dev)
static int mv_xor_v2_probe(struct platform_device *pdev)
{
struct mv_xor_v2_device *xor_dev;
- struct resource *res;
int i, ret = 0;
struct dma_device *dma_dev;
struct mv_xor_v2_sw_desc *sw_desc;
@@ -726,13 +725,11 @@ static int mv_xor_v2_probe(struct platform_device *pdev)
if (!xor_dev)
return -ENOMEM;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- xor_dev->dma_base = devm_ioremap_resource(&pdev->dev, res);
+ xor_dev->dma_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(xor_dev->dma_base))
return PTR_ERR(xor_dev->dma_base);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- xor_dev->glob_base = devm_ioremap_resource(&pdev->dev, res);
+ xor_dev->glob_base = devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(xor_dev->glob_base))
return PTR_ERR(xor_dev->glob_base);
diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c
index dc147cc2436e..acc4d53e4630 100644
--- a/drivers/dma/mxs-dma.c
+++ b/drivers/dma/mxs-dma.c
@@ -746,7 +746,6 @@ static int mxs_dma_probe(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node;
const struct mxs_dma_type *dma_type;
struct mxs_dma_engine *mxs_dma;
- struct resource *iores;
int ret, i;
mxs_dma = devm_kzalloc(&pdev->dev, sizeof(*mxs_dma), GFP_KERNEL);
@@ -763,8 +762,7 @@ static int mxs_dma_probe(struct platform_device *pdev)
mxs_dma->type = dma_type->type;
mxs_dma->dev_id = dma_type->id;
- iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- mxs_dma->base = devm_ioremap_resource(&pdev->dev, iores);
+ mxs_dma->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(mxs_dma->base))
return PTR_ERR(mxs_dma->base);
diff --git a/drivers/dma/nbpfaxi.c b/drivers/dma/nbpfaxi.c
index a7063e9cd551..e72e8c10355e 100644
--- a/drivers/dma/nbpfaxi.c
+++ b/drivers/dma/nbpfaxi.c
@@ -1294,7 +1294,6 @@ static int nbpf_probe(struct platform_device *pdev)
struct device_node *np = dev->of_node;
struct nbpf_device *nbpf;
struct dma_device *dma_dev;
- struct resource *iomem;
const struct nbpf_config *cfg;
int num_channels;
int ret, irq, eirq, i;
@@ -1318,8 +1317,7 @@ static int nbpf_probe(struct platform_device *pdev)
dma_dev = &nbpf->dma_dev;
dma_dev->dev = dev;
- iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- nbpf->base = devm_ioremap_resource(dev, iomem);
+ nbpf->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(nbpf->base))
return PTR_ERR(nbpf->base);
diff --git a/drivers/dma/ppc4xx/adma.c b/drivers/dma/ppc4xx/adma.c
index 6b5e91f26afc..686c270ef710 100644
--- a/drivers/dma/ppc4xx/adma.c
+++ b/drivers/dma/ppc4xx/adma.c
@@ -4299,9 +4299,8 @@ static ssize_t devices_show(struct device_driver *dev, char *buf)
for (i = 0; i < PPC440SPE_ADMA_ENGINES_NUM; i++) {
if (ppc440spe_adma_devices[i] == -1)
continue;
- size += scnprintf(buf + size, PAGE_SIZE - size,
- "PPC440SP(E)-ADMA.%d: %s\n", i,
- ppc_adma_errors[ppc440spe_adma_devices[i]]);
+ size += sysfs_emit_at(buf, size, "PPC440SP(E)-ADMA.%d: %s\n",
+ i, ppc_adma_errors[ppc440spe_adma_devices[i]]);
}
return size;
}
@@ -4309,9 +4308,8 @@ static DRIVER_ATTR_RO(devices);
static ssize_t enable_show(struct device_driver *dev, char *buf)
{
- return snprintf(buf, PAGE_SIZE,
- "PPC440SP(e) RAID-6 capabilities are %sABLED.\n",
- ppc440spe_r6_enabled ? "EN" : "DIS");
+ return sysfs_emit(buf, "PPC440SP(e) RAID-6 capabilities are %sABLED.\n",
+ ppc440spe_r6_enabled ? "EN" : "DIS");
}
static ssize_t enable_store(struct device_driver *dev, const char *buf,
@@ -4362,7 +4360,7 @@ static ssize_t poly_show(struct device_driver *dev, char *buf)
reg &= 0xFF;
#endif
- size = snprintf(buf, PAGE_SIZE, "PPC440SP(e) RAID-6 driver "
+ size = sysfs_emit(buf, "PPC440SP(e) RAID-6 driver "
"uses 0x1%02x polynomial.\n", reg);
return size;
}
diff --git a/drivers/dma/ptdma/ptdma-dmaengine.c b/drivers/dma/ptdma/ptdma-dmaengine.c
index cc22d162ce25..1aa65e5de0f3 100644
--- a/drivers/dma/ptdma/ptdma-dmaengine.c
+++ b/drivers/dma/ptdma/ptdma-dmaengine.c
@@ -254,7 +254,7 @@ static void pt_issue_pending(struct dma_chan *dma_chan)
spin_unlock_irqrestore(&chan->vc.lock, flags);
/* If there was nothing active, start processing */
- if (engine_is_idle)
+ if (engine_is_idle && desc)
pt_cmd_callback(desc, 0);
}
diff --git a/drivers/dma/pxa_dma.c b/drivers/dma/pxa_dma.c
index 22a392fe6d32..1b046d9a3a26 100644
--- a/drivers/dma/pxa_dma.c
+++ b/drivers/dma/pxa_dma.c
@@ -1346,7 +1346,6 @@ static int pxad_probe(struct platform_device *op)
const struct of_device_id *of_id;
const struct dma_slave_map *slave_map = NULL;
struct mmp_dma_platdata *pdata = dev_get_platdata(&op->dev);
- struct resource *iores;
int ret, dma_channels = 0, nb_requestors = 0, slave_map_cnt = 0;
const enum dma_slave_buswidth widths =
DMA_SLAVE_BUSWIDTH_1_BYTE | DMA_SLAVE_BUSWIDTH_2_BYTES |
@@ -1358,8 +1357,7 @@ static int pxad_probe(struct platform_device *op)
spin_lock_init(&pdev->phy_lock);
- iores = platform_get_resource(op, IORESOURCE_MEM, 0);
- pdev->base = devm_ioremap_resource(&op->dev, iores);
+ pdev->base = devm_platform_ioremap_resource(op, 0);
if (IS_ERR(pdev->base))
return PTR_ERR(pdev->base);
diff --git a/drivers/dma/qcom/bam_dma.c b/drivers/dma/qcom/bam_dma.c
index 2ff787df513e..1e47d27e1f81 100644
--- a/drivers/dma/qcom/bam_dma.c
+++ b/drivers/dma/qcom/bam_dma.c
@@ -1237,7 +1237,6 @@ static int bam_dma_probe(struct platform_device *pdev)
{
struct bam_device *bdev;
const struct of_device_id *match;
- struct resource *iores;
int ret, i;
bdev = devm_kzalloc(&pdev->dev, sizeof(*bdev), GFP_KERNEL);
@@ -1254,8 +1253,7 @@ static int bam_dma_probe(struct platform_device *pdev)
bdev->layout = match->data;
- iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- bdev->regs = devm_ioremap_resource(&pdev->dev, iores);
+ bdev->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(bdev->regs))
return PTR_ERR(bdev->regs);
diff --git a/drivers/dma/sf-pdma/sf-pdma.c b/drivers/dma/sf-pdma/sf-pdma.c
index 6b524eb6bcf3..d1c6956af452 100644
--- a/drivers/dma/sf-pdma/sf-pdma.c
+++ b/drivers/dma/sf-pdma/sf-pdma.c
@@ -96,7 +96,6 @@ sf_pdma_prep_dma_memcpy(struct dma_chan *dchan, dma_addr_t dest, dma_addr_t src,
if (!desc)
return NULL;
- desc->in_use = true;
desc->dirn = DMA_MEM_TO_MEM;
desc->async_tx = vchan_tx_prep(&chan->vchan, &desc->vdesc, flags);
@@ -290,7 +289,7 @@ static void sf_pdma_free_desc(struct virt_dma_desc *vdesc)
struct sf_pdma_desc *desc;
desc = to_sf_pdma_desc(vdesc);
- desc->in_use = false;
+ kfree(desc);
}
static void sf_pdma_donebh_tasklet(struct tasklet_struct *t)
@@ -494,7 +493,6 @@ static void sf_pdma_setup_chans(struct sf_pdma *pdma)
static int sf_pdma_probe(struct platform_device *pdev)
{
struct sf_pdma *pdma;
- struct resource *res;
int ret, n_chans;
const enum dma_slave_buswidth widths =
DMA_SLAVE_BUSWIDTH_1_BYTE | DMA_SLAVE_BUSWIDTH_2_BYTES |
@@ -519,8 +517,7 @@ static int sf_pdma_probe(struct platform_device *pdev)
pdma->n_chans = n_chans;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- pdma->membase = devm_ioremap_resource(&pdev->dev, res);
+ pdma->membase = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(pdma->membase))
return PTR_ERR(pdma->membase);
diff --git a/drivers/dma/sf-pdma/sf-pdma.h b/drivers/dma/sf-pdma/sf-pdma.h
index dcb3687bd5da..5c398a83b491 100644
--- a/drivers/dma/sf-pdma/sf-pdma.h
+++ b/drivers/dma/sf-pdma/sf-pdma.h
@@ -78,7 +78,6 @@ struct sf_pdma_desc {
u64 src_addr;
struct virt_dma_desc vdesc;
struct sf_pdma_chan *chan;
- bool in_use;
enum dma_transfer_direction dirn;
struct dma_async_tx_descriptor *async_tx;
};
diff --git a/drivers/dma/sh/usb-dmac.c b/drivers/dma/sh/usb-dmac.c
index 5edaeb89d1e6..b14cf350b669 100644
--- a/drivers/dma/sh/usb-dmac.c
+++ b/drivers/dma/sh/usb-dmac.c
@@ -768,7 +768,6 @@ static int usb_dmac_probe(struct platform_device *pdev)
const enum dma_slave_buswidth widths = USB_DMAC_SLAVE_BUSWIDTH;
struct dma_device *engine;
struct usb_dmac *dmac;
- struct resource *mem;
unsigned int i;
int ret;
@@ -789,8 +788,7 @@ static int usb_dmac_probe(struct platform_device *pdev)
return -ENOMEM;
/* Request resources. */
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- dmac->iomem = devm_ioremap_resource(&pdev->dev, mem);
+ dmac->iomem = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(dmac->iomem))
return PTR_ERR(dmac->iomem);
diff --git a/drivers/dma/stm32-dmamux.c b/drivers/dma/stm32-dmamux.c
index ee3cbbf51006..46b884d46188 100644
--- a/drivers/dma/stm32-dmamux.c
+++ b/drivers/dma/stm32-dmamux.c
@@ -179,7 +179,6 @@ static int stm32_dmamux_probe(struct platform_device *pdev)
const struct of_device_id *match;
struct device_node *dma_node;
struct stm32_dmamux_data *stm32_dmamux;
- struct resource *res;
void __iomem *iomem;
struct reset_control *rst;
int i, count, ret;
@@ -238,8 +237,7 @@ static int stm32_dmamux_probe(struct platform_device *pdev)
}
pm_runtime_get_noresume(&pdev->dev);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- iomem = devm_ioremap_resource(&pdev->dev, res);
+ iomem = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(iomem))
return PTR_ERR(iomem);
diff --git a/drivers/dma/stm32-mdma.c b/drivers/dma/stm32-mdma.c
index b9d4c843635f..84e7f4f4a800 100644
--- a/drivers/dma/stm32-mdma.c
+++ b/drivers/dma/stm32-mdma.c
@@ -1580,7 +1580,6 @@ static int stm32_mdma_probe(struct platform_device *pdev)
struct stm32_mdma_device *dmadev;
struct dma_device *dd;
struct device_node *of_node;
- struct resource *res;
struct reset_control *rst;
u32 nr_channels, nr_requests;
int i, count, ret;
@@ -1622,8 +1621,7 @@ static int stm32_mdma_probe(struct platform_device *pdev)
count);
dmadev->nr_ahb_addr_masks = count;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- dmadev->base = devm_ioremap_resource(&pdev->dev, res);
+ dmadev->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(dmadev->base))
return PTR_ERR(dmadev->base);
diff --git a/drivers/dma/sun4i-dma.c b/drivers/dma/sun4i-dma.c
index f291b1b4db32..e86c8829513a 100644
--- a/drivers/dma/sun4i-dma.c
+++ b/drivers/dma/sun4i-dma.c
@@ -1144,15 +1144,13 @@ handle_pending:
static int sun4i_dma_probe(struct platform_device *pdev)
{
struct sun4i_dma_dev *priv;
- struct resource *res;
int i, j, ret;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- priv->base = devm_ioremap_resource(&pdev->dev, res);
+ priv->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c
index b7557f437936..ebfd29888b2f 100644
--- a/drivers/dma/sun6i-dma.c
+++ b/drivers/dma/sun6i-dma.c
@@ -9,6 +9,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/dmapool.h>
#include <linux/interrupt.h>
@@ -1283,7 +1284,6 @@ static int sun6i_dma_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct sun6i_dma_dev *sdc;
- struct resource *res;
int ret, i;
sdc = devm_kzalloc(&pdev->dev, sizeof(*sdc), GFP_KERNEL);
@@ -1294,8 +1294,7 @@ static int sun6i_dma_probe(struct platform_device *pdev)
if (!sdc->cfg)
return -ENODEV;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- sdc->base = devm_ioremap_resource(&pdev->dev, res);
+ sdc->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(sdc->base))
return PTR_ERR(sdc->base);
@@ -1334,6 +1333,8 @@ static int sun6i_dma_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&sdc->pending);
spin_lock_init(&sdc->lock);
+ dma_set_max_seg_size(&pdev->dev, SZ_32M - 1);
+
dma_cap_set(DMA_PRIVATE, sdc->slave.cap_mask);
dma_cap_set(DMA_MEMCPY, sdc->slave.cap_mask);
dma_cap_set(DMA_SLAVE, sdc->slave.cap_mask);
diff --git a/drivers/dma/tegra210-adma.c b/drivers/dma/tegra210-adma.c
index 79da93cc77b6..b97004036071 100644
--- a/drivers/dma/tegra210-adma.c
+++ b/drivers/dma/tegra210-adma.c
@@ -837,7 +837,6 @@ static int tegra_adma_probe(struct platform_device *pdev)
{
const struct tegra_adma_chip_data *cdata;
struct tegra_adma *tdma;
- struct resource *res;
int ret, i;
cdata = of_device_get_match_data(&pdev->dev);
@@ -857,8 +856,7 @@ static int tegra_adma_probe(struct platform_device *pdev)
tdma->nr_channels = cdata->nr_channels;
platform_set_drvdata(pdev, tdma);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- tdma->base_addr = devm_ioremap_resource(&pdev->dev, res);
+ tdma->base_addr = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(tdma->base_addr))
return PTR_ERR(tdma->base_addr);
diff --git a/drivers/dma/ti/Makefile b/drivers/dma/ti/Makefile
index b53d05b11ca5..bd1e07fda559 100644
--- a/drivers/dma/ti/Makefile
+++ b/drivers/dma/ti/Makefile
@@ -10,6 +10,7 @@ k3-psil-lib-objs := k3-psil.o \
k3-psil-j7200.o \
k3-psil-am64.o \
k3-psil-j721s2.o \
- k3-psil-am62.o
+ k3-psil-am62.o \
+ k3-psil-am62a.o
obj-$(CONFIG_TI_K3_PSIL) += k3-psil-lib.o
obj-$(CONFIG_TI_DMA_CROSSBAR) += dma-crossbar.o
diff --git a/drivers/dma/ti/cppi41.c b/drivers/dma/ti/cppi41.c
index 695915dba707..c3555cfb0681 100644
--- a/drivers/dma/ti/cppi41.c
+++ b/drivers/dma/ti/cppi41.c
@@ -1039,7 +1039,6 @@ static int cppi41_dma_probe(struct platform_device *pdev)
struct cppi41_dd *cdd;
struct device *dev = &pdev->dev;
const struct cppi_glue_infos *glue_info;
- struct resource *mem;
int index;
int irq;
int ret;
@@ -1072,18 +1071,15 @@ static int cppi41_dma_probe(struct platform_device *pdev)
if (index < 0)
return index;
- mem = platform_get_resource(pdev, IORESOURCE_MEM, index);
- cdd->ctrl_mem = devm_ioremap_resource(dev, mem);
+ cdd->ctrl_mem = devm_platform_ioremap_resource(pdev, index);
if (IS_ERR(cdd->ctrl_mem))
return PTR_ERR(cdd->ctrl_mem);
- mem = platform_get_resource(pdev, IORESOURCE_MEM, index + 1);
- cdd->sched_mem = devm_ioremap_resource(dev, mem);
+ cdd->sched_mem = devm_platform_ioremap_resource(pdev, index + 1);
if (IS_ERR(cdd->sched_mem))
return PTR_ERR(cdd->sched_mem);
- mem = platform_get_resource(pdev, IORESOURCE_MEM, index + 2);
- cdd->qmgr_mem = devm_ioremap_resource(dev, mem);
+ cdd->qmgr_mem = devm_platform_ioremap_resource(pdev, index + 2);
if (IS_ERR(cdd->qmgr_mem))
return PTR_ERR(cdd->qmgr_mem);
diff --git a/drivers/dma/ti/k3-psil-am62a.c b/drivers/dma/ti/k3-psil-am62a.c
new file mode 100644
index 000000000000..ca9d71f91422
--- /dev/null
+++ b/drivers/dma/ti/k3-psil-am62a.c
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com
+ */
+
+#include <linux/kernel.h>
+
+#include "k3-psil-priv.h"
+
+#define PSIL_PDMA_XY_TR(x) \
+ { \
+ .thread_id = x, \
+ .ep_config = { \
+ .ep_type = PSIL_EP_PDMA_XY, \
+ .mapped_channel_id = -1, \
+ .default_flow_id = -1, \
+ }, \
+ }
+
+#define PSIL_PDMA_XY_PKT(x) \
+ { \
+ .thread_id = x, \
+ .ep_config = { \
+ .ep_type = PSIL_EP_PDMA_XY, \
+ .mapped_channel_id = -1, \
+ .default_flow_id = -1, \
+ .pkt_mode = 1, \
+ }, \
+ }
+
+#define PSIL_ETHERNET(x, ch, flow_base, flow_cnt) \
+ { \
+ .thread_id = x, \
+ .ep_config = { \
+ .ep_type = PSIL_EP_NATIVE, \
+ .pkt_mode = 1, \
+ .needs_epib = 1, \
+ .psd_size = 16, \
+ .mapped_channel_id = ch, \
+ .flow_start = flow_base, \
+ .flow_num = flow_cnt, \
+ .default_flow_id = flow_base, \
+ }, \
+ }
+
+#define PSIL_SAUL(x, ch, flow_base, flow_cnt, default_flow, tx) \
+ { \
+ .thread_id = x, \
+ .ep_config = { \
+ .ep_type = PSIL_EP_NATIVE, \
+ .pkt_mode = 1, \
+ .needs_epib = 1, \
+ .psd_size = 64, \
+ .mapped_channel_id = ch, \
+ .flow_start = flow_base, \
+ .flow_num = flow_cnt, \
+ .default_flow_id = default_flow, \
+ .notdpkt = tx, \
+ }, \
+ }
+
+#define PSIL_PDMA_MCASP(x) \
+ { \
+ .thread_id = x, \
+ .ep_config = { \
+ .ep_type = PSIL_EP_PDMA_XY, \
+ .pdma_acc32 = 1, \
+ .pdma_burst = 1, \
+ }, \
+ }
+
+#define PSIL_CSI2RX(x) \
+ { \
+ .thread_id = x, \
+ .ep_config = { \
+ .ep_type = PSIL_EP_NATIVE, \
+ }, \
+ }
+
+/* PSI-L source thread IDs, used for RX (DMA_DEV_TO_MEM) */
+static struct psil_ep am62a_src_ep_map[] = {
+ /* SAUL */
+ PSIL_SAUL(0x7504, 20, 35, 8, 35, 0),
+ PSIL_SAUL(0x7505, 21, 35, 8, 36, 0),
+ PSIL_SAUL(0x7506, 22, 43, 8, 43, 0),
+ PSIL_SAUL(0x7507, 23, 43, 8, 44, 0),
+ /* PDMA_MAIN0 - SPI0-3 */
+ PSIL_PDMA_XY_PKT(0x4302),
+ PSIL_PDMA_XY_PKT(0x4303),
+ PSIL_PDMA_XY_PKT(0x4304),
+ PSIL_PDMA_XY_PKT(0x4305),
+ PSIL_PDMA_XY_PKT(0x4306),
+ PSIL_PDMA_XY_PKT(0x4307),
+ PSIL_PDMA_XY_PKT(0x4308),
+ PSIL_PDMA_XY_PKT(0x4309),
+ PSIL_PDMA_XY_PKT(0x430a),
+ PSIL_PDMA_XY_PKT(0x430b),
+ PSIL_PDMA_XY_PKT(0x430c),
+ PSIL_PDMA_XY_PKT(0x430d),
+ /* PDMA_MAIN1 - UART0-6 */
+ PSIL_PDMA_XY_PKT(0x4400),
+ PSIL_PDMA_XY_PKT(0x4401),
+ PSIL_PDMA_XY_PKT(0x4402),
+ PSIL_PDMA_XY_PKT(0x4403),
+ PSIL_PDMA_XY_PKT(0x4404),
+ PSIL_PDMA_XY_PKT(0x4405),
+ PSIL_PDMA_XY_PKT(0x4406),
+ /* PDMA_MAIN2 - MCASP0-2 */
+ PSIL_PDMA_MCASP(0x4500),
+ PSIL_PDMA_MCASP(0x4501),
+ PSIL_PDMA_MCASP(0x4502),
+ /* CPSW3G */
+ PSIL_ETHERNET(0x4600, 19, 19, 16),
+ /* CSI2RX */
+ PSIL_CSI2RX(0x5000),
+ PSIL_CSI2RX(0x5001),
+ PSIL_CSI2RX(0x5002),
+ PSIL_CSI2RX(0x5003),
+ PSIL_CSI2RX(0x5004),
+ PSIL_CSI2RX(0x5005),
+ PSIL_CSI2RX(0x5006),
+ PSIL_CSI2RX(0x5007),
+ PSIL_CSI2RX(0x5008),
+ PSIL_CSI2RX(0x5009),
+ PSIL_CSI2RX(0x500a),
+ PSIL_CSI2RX(0x500b),
+ PSIL_CSI2RX(0x500c),
+ PSIL_CSI2RX(0x500d),
+ PSIL_CSI2RX(0x500e),
+ PSIL_CSI2RX(0x500f),
+ PSIL_CSI2RX(0x5010),
+ PSIL_CSI2RX(0x5011),
+ PSIL_CSI2RX(0x5012),
+ PSIL_CSI2RX(0x5013),
+ PSIL_CSI2RX(0x5014),
+ PSIL_CSI2RX(0x5015),
+ PSIL_CSI2RX(0x5016),
+ PSIL_CSI2RX(0x5017),
+ PSIL_CSI2RX(0x5018),
+ PSIL_CSI2RX(0x5019),
+ PSIL_CSI2RX(0x501a),
+ PSIL_CSI2RX(0x501b),
+ PSIL_CSI2RX(0x501c),
+ PSIL_CSI2RX(0x501d),
+ PSIL_CSI2RX(0x501e),
+ PSIL_CSI2RX(0x501f),
+};
+
+/* PSI-L destination thread IDs, used for TX (DMA_MEM_TO_DEV) */
+static struct psil_ep am62a_dst_ep_map[] = {
+ /* SAUL */
+ PSIL_SAUL(0xf500, 27, 83, 8, 83, 1),
+ PSIL_SAUL(0xf501, 28, 91, 8, 91, 1),
+ /* PDMA_MAIN0 - SPI0-3 */
+ PSIL_PDMA_XY_PKT(0xc302),
+ PSIL_PDMA_XY_PKT(0xc303),
+ PSIL_PDMA_XY_PKT(0xc304),
+ PSIL_PDMA_XY_PKT(0xc305),
+ PSIL_PDMA_XY_PKT(0xc306),
+ PSIL_PDMA_XY_PKT(0xc307),
+ PSIL_PDMA_XY_PKT(0xc308),
+ PSIL_PDMA_XY_PKT(0xc309),
+ PSIL_PDMA_XY_PKT(0xc30a),
+ PSIL_PDMA_XY_PKT(0xc30b),
+ PSIL_PDMA_XY_PKT(0xc30c),
+ PSIL_PDMA_XY_PKT(0xc30d),
+ /* PDMA_MAIN1 - UART0-6 */
+ PSIL_PDMA_XY_PKT(0xc400),
+ PSIL_PDMA_XY_PKT(0xc401),
+ PSIL_PDMA_XY_PKT(0xc402),
+ PSIL_PDMA_XY_PKT(0xc403),
+ PSIL_PDMA_XY_PKT(0xc404),
+ PSIL_PDMA_XY_PKT(0xc405),
+ PSIL_PDMA_XY_PKT(0xc406),
+ /* PDMA_MAIN2 - MCASP0-2 */
+ PSIL_PDMA_MCASP(0xc500),
+ PSIL_PDMA_MCASP(0xc501),
+ PSIL_PDMA_MCASP(0xc502),
+ /* CPSW3G */
+ PSIL_ETHERNET(0xc600, 19, 19, 8),
+ PSIL_ETHERNET(0xc601, 20, 27, 8),
+ PSIL_ETHERNET(0xc602, 21, 35, 8),
+ PSIL_ETHERNET(0xc603, 22, 43, 8),
+ PSIL_ETHERNET(0xc604, 23, 51, 8),
+ PSIL_ETHERNET(0xc605, 24, 59, 8),
+ PSIL_ETHERNET(0xc606, 25, 67, 8),
+ PSIL_ETHERNET(0xc607, 26, 75, 8),
+};
+
+struct psil_ep_map am62a_ep_map = {
+ .name = "am62a",
+ .src = am62a_src_ep_map,
+ .src_count = ARRAY_SIZE(am62a_src_ep_map),
+ .dst = am62a_dst_ep_map,
+ .dst_count = ARRAY_SIZE(am62a_dst_ep_map),
+};
diff --git a/drivers/dma/ti/k3-psil-priv.h b/drivers/dma/ti/k3-psil-priv.h
index 74fa9ec02968..abd650bb7600 100644
--- a/drivers/dma/ti/k3-psil-priv.h
+++ b/drivers/dma/ti/k3-psil-priv.h
@@ -43,5 +43,6 @@ extern struct psil_ep_map j7200_ep_map;
extern struct psil_ep_map am64_ep_map;
extern struct psil_ep_map j721s2_ep_map;
extern struct psil_ep_map am62_ep_map;
+extern struct psil_ep_map am62a_ep_map;
#endif /* K3_PSIL_PRIV_H_ */
diff --git a/drivers/dma/ti/k3-psil.c b/drivers/dma/ti/k3-psil.c
index 8b6533a1eeeb..2da6988a0e7b 100644
--- a/drivers/dma/ti/k3-psil.c
+++ b/drivers/dma/ti/k3-psil.c
@@ -24,6 +24,7 @@ static const struct soc_device_attribute k3_soc_devices[] = {
{ .family = "AM64X", .data = &am64_ep_map },
{ .family = "J721S2", .data = &j721s2_ep_map },
{ .family = "AM62X", .data = &am62_ep_map },
+ { .family = "AM62AX", .data = &am62a_ep_map },
{ /* sentinel */ }
};
diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c
index 4c62274e0b33..7e23a6fdef95 100644
--- a/drivers/dma/ti/k3-udma.c
+++ b/drivers/dma/ti/k3-udma.c
@@ -135,6 +135,7 @@ struct udma_match_data {
u32 flags;
u32 statictr_z_mask;
u8 burst_size[3];
+ struct udma_soc_data *soc_data;
};
struct udma_soc_data {
@@ -4296,6 +4297,25 @@ static struct udma_match_data j721e_mcu_data = {
},
};
+static struct udma_soc_data am62a_dmss_csi_soc_data = {
+ .oes = {
+ .bcdma_rchan_data = 0xe00,
+ .bcdma_rchan_ring = 0x1000,
+ },
+};
+
+static struct udma_match_data am62a_bcdma_csirx_data = {
+ .type = DMA_TYPE_BCDMA,
+ .psil_base = 0x3100,
+ .enable_memcpy_support = false,
+ .burst_size = {
+ TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_64_BYTES, /* Normal Channels */
+ 0, /* No H Channels */
+ 0, /* No UH Channels */
+ },
+ .soc_data = &am62a_dmss_csi_soc_data,
+};
+
static struct udma_match_data am64_bcdma_data = {
.type = DMA_TYPE_BCDMA,
.psil_base = 0x2000, /* for tchan and rchan, not applicable to bchan */
@@ -4345,6 +4365,10 @@ static const struct of_device_id udma_of_match[] = {
.compatible = "ti,am64-dmss-pktdma",
.data = &am64_pktdma_data,
},
+ {
+ .compatible = "ti,am62a-dmss-bcdma-csirx",
+ .data = &am62a_bcdma_csirx_data,
+ },
{ /* Sentinel */ },
};
@@ -4387,6 +4411,7 @@ static const struct soc_device_attribute k3_soc_devices[] = {
{ .family = "AM64X", .data = &am64_soc_data },
{ .family = "J721S2", .data = &j721e_soc_data},
{ .family = "AM62X", .data = &am64_soc_data },
+ { .family = "AM62AX", .data = &am64_soc_data },
{ /* sentinel */ }
};
@@ -4775,7 +4800,10 @@ static int bcdma_setup_resources(struct udma_dev *ud)
irq_res.desc[i].num = rm_res->desc[i].num;
}
}
+ } else {
+ i = 0;
}
+
if (ud->tchan_cnt) {
rm_res = tisci_rm->rm_ranges[RM_RANGE_TCHAN];
if (IS_ERR(rm_res)) {
@@ -5271,12 +5299,15 @@ static int udma_probe(struct platform_device *pdev)
}
ud->match_data = match->data;
- soc = soc_device_match(k3_soc_devices);
- if (!soc) {
- dev_err(dev, "No compatible SoC found\n");
- return -ENODEV;
+ ud->soc_data = ud->match_data->soc_data;
+ if (!ud->soc_data) {
+ soc = soc_device_match(k3_soc_devices);
+ if (!soc) {
+ dev_err(dev, "No compatible SoC found\n");
+ return -ENODEV;
+ }
+ ud->soc_data = soc->data;
}
- ud->soc_data = soc->data;
ret = udma_get_mmrs(pdev, ud);
if (ret)
@@ -5345,7 +5376,6 @@ static int udma_probe(struct platform_device *pdev)
dev->msi.domain = of_msi_get_domain(dev, dev->of_node,
DOMAIN_BUS_TI_SCI_INTA_MSI);
if (!dev->msi.domain) {
- dev_err(dev, "Failed to get MSI domain\n");
return -EPROBE_DEFER;
}
diff --git a/drivers/dma/ti/omap-dma.c b/drivers/dma/ti/omap-dma.c
index 27f5019bdc1e..02e1c08c596d 100644
--- a/drivers/dma/ti/omap-dma.c
+++ b/drivers/dma/ti/omap-dma.c
@@ -1658,7 +1658,6 @@ static int omap_dma_probe(struct platform_device *pdev)
{
const struct omap_dma_config *conf;
struct omap_dmadev *od;
- struct resource *res;
int rc, i, irq;
u32 val;
@@ -1666,8 +1665,7 @@ static int omap_dma_probe(struct platform_device *pdev)
if (!od)
return -ENOMEM;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- od->base = devm_ioremap_resource(&pdev->dev, res);
+ od->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(od->base))
return PTR_ERR(od->base);
diff --git a/drivers/dma/xilinx/Makefile b/drivers/dma/xilinx/Makefile
index 767bb45f641f..ebaa93644c94 100644
--- a/drivers/dma/xilinx/Makefile
+++ b/drivers/dma/xilinx/Makefile
@@ -1,4 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_XILINX_DMA) += xilinx_dma.o
+obj-$(CONFIG_XILINX_XDMA) += xdma.o
obj-$(CONFIG_XILINX_ZYNQMP_DMA) += zynqmp_dma.o
obj-$(CONFIG_XILINX_ZYNQMP_DPDMA) += xilinx_dpdma.o
diff --git a/drivers/dma/xilinx/xdma-regs.h b/drivers/dma/xilinx/xdma-regs.h
new file mode 100644
index 000000000000..dd98b4526b90
--- /dev/null
+++ b/drivers/dma/xilinx/xdma-regs.h
@@ -0,0 +1,166 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2017-2020 Xilinx, Inc. All rights reserved.
+ * Copyright (C) 2022, Advanced Micro Devices, Inc.
+ */
+
+#ifndef __DMA_XDMA_REGS_H
+#define __DMA_XDMA_REGS_H
+
+/* The length of register space exposed to host */
+#define XDMA_REG_SPACE_LEN 65536
+
+/*
+ * maximum number of DMA channels for each direction:
+ * Host to Card (H2C) or Card to Host (C2H)
+ */
+#define XDMA_MAX_CHANNELS 4
+
+/*
+ * macros to define the number of descriptor blocks can be used in one
+ * DMA transfer request.
+ * the DMA engine uses a linked list of descriptor blocks that specify the
+ * source, destination, and length of the DMA transfers.
+ */
+#define XDMA_DESC_BLOCK_NUM BIT(7)
+#define XDMA_DESC_BLOCK_MASK (XDMA_DESC_BLOCK_NUM - 1)
+
+/* descriptor definitions */
+#define XDMA_DESC_ADJACENT 32
+#define XDMA_DESC_ADJACENT_MASK (XDMA_DESC_ADJACENT - 1)
+#define XDMA_DESC_ADJACENT_BITS GENMASK(13, 8)
+#define XDMA_DESC_MAGIC 0xad4bUL
+#define XDMA_DESC_MAGIC_BITS GENMASK(31, 16)
+#define XDMA_DESC_FLAGS_BITS GENMASK(7, 0)
+#define XDMA_DESC_STOPPED BIT(0)
+#define XDMA_DESC_COMPLETED BIT(1)
+#define XDMA_DESC_BLEN_BITS 28
+#define XDMA_DESC_BLEN_MAX (BIT(XDMA_DESC_BLEN_BITS) - PAGE_SIZE)
+
+/* macros to construct the descriptor control word */
+#define XDMA_DESC_CONTROL(adjacent, flag) \
+ (FIELD_PREP(XDMA_DESC_MAGIC_BITS, XDMA_DESC_MAGIC) | \
+ FIELD_PREP(XDMA_DESC_ADJACENT_BITS, (adjacent) - 1) | \
+ FIELD_PREP(XDMA_DESC_FLAGS_BITS, (flag)))
+#define XDMA_DESC_CONTROL_LAST \
+ XDMA_DESC_CONTROL(1, XDMA_DESC_STOPPED | XDMA_DESC_COMPLETED)
+
+/*
+ * Descriptor for a single contiguous memory block transfer.
+ *
+ * Multiple descriptors are linked by means of the next pointer. An additional
+ * extra adjacent number gives the amount of extra contiguous descriptors.
+ *
+ * The descriptors are in root complex memory, and the bytes in the 32-bit
+ * words must be in little-endian byte ordering.
+ */
+struct xdma_hw_desc {
+ __le32 control;
+ __le32 bytes;
+ __le64 src_addr;
+ __le64 dst_addr;
+ __le64 next_desc;
+};
+
+#define XDMA_DESC_SIZE sizeof(struct xdma_hw_desc)
+#define XDMA_DESC_BLOCK_SIZE (XDMA_DESC_SIZE * XDMA_DESC_ADJACENT)
+#define XDMA_DESC_BLOCK_ALIGN 4096
+
+/*
+ * Channel registers
+ */
+#define XDMA_CHAN_IDENTIFIER 0x0
+#define XDMA_CHAN_CONTROL 0x4
+#define XDMA_CHAN_CONTROL_W1S 0x8
+#define XDMA_CHAN_CONTROL_W1C 0xc
+#define XDMA_CHAN_STATUS 0x40
+#define XDMA_CHAN_COMPLETED_DESC 0x48
+#define XDMA_CHAN_ALIGNMENTS 0x4c
+#define XDMA_CHAN_INTR_ENABLE 0x90
+#define XDMA_CHAN_INTR_ENABLE_W1S 0x94
+#define XDMA_CHAN_INTR_ENABLE_W1C 0x9c
+
+#define XDMA_CHAN_STRIDE 0x100
+#define XDMA_CHAN_H2C_OFFSET 0x0
+#define XDMA_CHAN_C2H_OFFSET 0x1000
+#define XDMA_CHAN_H2C_TARGET 0x0
+#define XDMA_CHAN_C2H_TARGET 0x1
+
+/* macro to check if channel is available */
+#define XDMA_CHAN_MAGIC 0x1fc0
+#define XDMA_CHAN_CHECK_TARGET(id, target) \
+ (((u32)(id) >> 16) == XDMA_CHAN_MAGIC + (target))
+
+/* bits of the channel control register */
+#define CHAN_CTRL_RUN_STOP BIT(0)
+#define CHAN_CTRL_IE_DESC_STOPPED BIT(1)
+#define CHAN_CTRL_IE_DESC_COMPLETED BIT(2)
+#define CHAN_CTRL_IE_DESC_ALIGN_MISMATCH BIT(3)
+#define CHAN_CTRL_IE_MAGIC_STOPPED BIT(4)
+#define CHAN_CTRL_IE_IDLE_STOPPED BIT(6)
+#define CHAN_CTRL_IE_READ_ERROR GENMASK(13, 9)
+#define CHAN_CTRL_IE_DESC_ERROR GENMASK(23, 19)
+#define CHAN_CTRL_NON_INCR_ADDR BIT(25)
+#define CHAN_CTRL_POLL_MODE_WB BIT(26)
+
+#define CHAN_CTRL_START (CHAN_CTRL_RUN_STOP | \
+ CHAN_CTRL_IE_DESC_STOPPED | \
+ CHAN_CTRL_IE_DESC_COMPLETED | \
+ CHAN_CTRL_IE_DESC_ALIGN_MISMATCH | \
+ CHAN_CTRL_IE_MAGIC_STOPPED | \
+ CHAN_CTRL_IE_READ_ERROR | \
+ CHAN_CTRL_IE_DESC_ERROR)
+
+/* bits of the channel interrupt enable mask */
+#define CHAN_IM_DESC_ERROR BIT(19)
+#define CHAN_IM_READ_ERROR BIT(9)
+#define CHAN_IM_IDLE_STOPPED BIT(6)
+#define CHAN_IM_MAGIC_STOPPED BIT(4)
+#define CHAN_IM_DESC_COMPLETED BIT(2)
+#define CHAN_IM_DESC_STOPPED BIT(1)
+
+#define CHAN_IM_ALL (CHAN_IM_DESC_ERROR | CHAN_IM_READ_ERROR | \
+ CHAN_IM_IDLE_STOPPED | CHAN_IM_MAGIC_STOPPED | \
+ CHAN_IM_DESC_COMPLETED | CHAN_IM_DESC_STOPPED)
+
+/*
+ * Channel SGDMA registers
+ */
+#define XDMA_SGDMA_IDENTIFIER 0x4000
+#define XDMA_SGDMA_DESC_LO 0x4080
+#define XDMA_SGDMA_DESC_HI 0x4084
+#define XDMA_SGDMA_DESC_ADJ 0x4088
+#define XDMA_SGDMA_DESC_CREDIT 0x408c
+
+/* bits of the SG DMA control register */
+#define XDMA_CTRL_RUN_STOP BIT(0)
+#define XDMA_CTRL_IE_DESC_STOPPED BIT(1)
+#define XDMA_CTRL_IE_DESC_COMPLETED BIT(2)
+#define XDMA_CTRL_IE_DESC_ALIGN_MISMATCH BIT(3)
+#define XDMA_CTRL_IE_MAGIC_STOPPED BIT(4)
+#define XDMA_CTRL_IE_IDLE_STOPPED BIT(6)
+#define XDMA_CTRL_IE_READ_ERROR GENMASK(13, 9)
+#define XDMA_CTRL_IE_DESC_ERROR GENMASK(23, 19)
+#define XDMA_CTRL_NON_INCR_ADDR BIT(25)
+#define XDMA_CTRL_POLL_MODE_WB BIT(26)
+
+/*
+ * interrupt registers
+ */
+#define XDMA_IRQ_IDENTIFIER 0x2000
+#define XDMA_IRQ_USER_INT_EN 0x2004
+#define XDMA_IRQ_USER_INT_EN_W1S 0x2008
+#define XDMA_IRQ_USER_INT_EN_W1C 0x200c
+#define XDMA_IRQ_CHAN_INT_EN 0x2010
+#define XDMA_IRQ_CHAN_INT_EN_W1S 0x2014
+#define XDMA_IRQ_CHAN_INT_EN_W1C 0x2018
+#define XDMA_IRQ_USER_INT_REQ 0x2040
+#define XDMA_IRQ_CHAN_INT_REQ 0x2044
+#define XDMA_IRQ_USER_INT_PEND 0x2048
+#define XDMA_IRQ_CHAN_INT_PEND 0x204c
+#define XDMA_IRQ_USER_VEC_NUM 0x2080
+#define XDMA_IRQ_CHAN_VEC_NUM 0x20a0
+
+#define XDMA_IRQ_VEC_SHIFT 8
+
+#endif /* __DMA_XDMA_REGS_H */
diff --git a/drivers/dma/xilinx/xdma.c b/drivers/dma/xilinx/xdma.c
new file mode 100644
index 000000000000..462109c61653
--- /dev/null
+++ b/drivers/dma/xilinx/xdma.c
@@ -0,0 +1,974 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * DMA driver for Xilinx DMA/Bridge Subsystem
+ *
+ * Copyright (C) 2017-2020 Xilinx, Inc. All rights reserved.
+ * Copyright (C) 2022, Advanced Micro Devices, Inc.
+ */
+
+/*
+ * The DMA/Bridge Subsystem for PCI Express allows for the movement of data
+ * between Host memory and the DMA subsystem. It does this by operating on
+ * 'descriptors' that contain information about the source, destination and
+ * amount of data to transfer. These direct memory transfers can be both in
+ * the Host to Card (H2C) and Card to Host (C2H) transfers. The DMA can be
+ * configured to have a single AXI4 Master interface shared by all channels
+ * or one AXI4-Stream interface for each channel enabled. Memory transfers are
+ * specified on a per-channel basis in descriptor linked lists, which the DMA
+ * fetches from host memory and processes. Events such as descriptor completion
+ * and errors are signaled using interrupts. The core also provides up to 16
+ * user interrupt wires that generate interrupts to the host.
+ */
+
+#include <linux/mod_devicetable.h>
+#include <linux/bitfield.h>
+#include <linux/dmapool.h>
+#include <linux/regmap.h>
+#include <linux/dmaengine.h>
+#include <linux/dma/amd_xdma.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/amd_xdma.h>
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+#include "../virt-dma.h"
+#include "xdma-regs.h"
+
+/* mmio regmap config for all XDMA registers */
+static const struct regmap_config xdma_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = XDMA_REG_SPACE_LEN,
+};
+
+/**
+ * struct xdma_desc_block - Descriptor block
+ * @virt_addr: Virtual address of block start
+ * @dma_addr: DMA address of block start
+ */
+struct xdma_desc_block {
+ void *virt_addr;
+ dma_addr_t dma_addr;
+};
+
+/**
+ * struct xdma_chan - Driver specific DMA channel structure
+ * @vchan: Virtual channel
+ * @xdev_hdl: Pointer to DMA device structure
+ * @base: Offset of channel registers
+ * @desc_pool: Descriptor pool
+ * @busy: Busy flag of the channel
+ * @dir: Transferring direction of the channel
+ * @cfg: Transferring config of the channel
+ * @irq: IRQ assigned to the channel
+ */
+struct xdma_chan {
+ struct virt_dma_chan vchan;
+ void *xdev_hdl;
+ u32 base;
+ struct dma_pool *desc_pool;
+ bool busy;
+ enum dma_transfer_direction dir;
+ struct dma_slave_config cfg;
+ u32 irq;
+};
+
+/**
+ * struct xdma_desc - DMA desc structure
+ * @vdesc: Virtual DMA descriptor
+ * @chan: DMA channel pointer
+ * @dir: Transferring direction of the request
+ * @dev_addr: Physical address on DMA device side
+ * @desc_blocks: Hardware descriptor blocks
+ * @dblk_num: Number of hardware descriptor blocks
+ * @desc_num: Number of hardware descriptors
+ * @completed_desc_num: Completed hardware descriptors
+ */
+struct xdma_desc {
+ struct virt_dma_desc vdesc;
+ struct xdma_chan *chan;
+ enum dma_transfer_direction dir;
+ u64 dev_addr;
+ struct xdma_desc_block *desc_blocks;
+ u32 dblk_num;
+ u32 desc_num;
+ u32 completed_desc_num;
+};
+
+#define XDMA_DEV_STATUS_REG_DMA BIT(0)
+#define XDMA_DEV_STATUS_INIT_MSIX BIT(1)
+
+/**
+ * struct xdma_device - DMA device structure
+ * @pdev: Platform device pointer
+ * @dma_dev: DMA device structure
+ * @rmap: MMIO regmap for DMA registers
+ * @h2c_chans: Host to Card channels
+ * @c2h_chans: Card to Host channels
+ * @h2c_chan_num: Number of H2C channels
+ * @c2h_chan_num: Number of C2H channels
+ * @irq_start: Start IRQ assigned to device
+ * @irq_num: Number of IRQ assigned to device
+ * @status: Initialization status
+ */
+struct xdma_device {
+ struct platform_device *pdev;
+ struct dma_device dma_dev;
+ struct regmap *rmap;
+ struct xdma_chan *h2c_chans;
+ struct xdma_chan *c2h_chans;
+ u32 h2c_chan_num;
+ u32 c2h_chan_num;
+ u32 irq_start;
+ u32 irq_num;
+ u32 status;
+};
+
+#define xdma_err(xdev, fmt, args...) \
+ dev_err(&(xdev)->pdev->dev, fmt, ##args)
+#define XDMA_CHAN_NUM(_xd) ({ \
+ typeof(_xd) (xd) = (_xd); \
+ ((xd)->h2c_chan_num + (xd)->c2h_chan_num); })
+
+/* Get the last desc in a desc block */
+static inline void *xdma_blk_last_desc(struct xdma_desc_block *block)
+{
+ return block->virt_addr + (XDMA_DESC_ADJACENT - 1) * XDMA_DESC_SIZE;
+}
+
+/**
+ * xdma_link_desc_blocks - Link descriptor blocks for DMA transfer
+ * @sw_desc: Tx descriptor pointer
+ */
+static void xdma_link_desc_blocks(struct xdma_desc *sw_desc)
+{
+ struct xdma_desc_block *block;
+ u32 last_blk_desc, desc_control;
+ struct xdma_hw_desc *desc;
+ int i;
+
+ desc_control = XDMA_DESC_CONTROL(XDMA_DESC_ADJACENT, 0);
+ for (i = 1; i < sw_desc->dblk_num; i++) {
+ block = &sw_desc->desc_blocks[i - 1];
+ desc = xdma_blk_last_desc(block);
+
+ if (!(i & XDMA_DESC_BLOCK_MASK)) {
+ desc->control = cpu_to_le32(XDMA_DESC_CONTROL_LAST);
+ continue;
+ }
+ desc->control = cpu_to_le32(desc_control);
+ desc->next_desc = cpu_to_le64(block[1].dma_addr);
+ }
+
+ /* update the last block */
+ last_blk_desc = (sw_desc->desc_num - 1) & XDMA_DESC_ADJACENT_MASK;
+ if (((sw_desc->dblk_num - 1) & XDMA_DESC_BLOCK_MASK) > 0) {
+ block = &sw_desc->desc_blocks[sw_desc->dblk_num - 2];
+ desc = xdma_blk_last_desc(block);
+ desc_control = XDMA_DESC_CONTROL(last_blk_desc + 1, 0);
+ desc->control = cpu_to_le32(desc_control);
+ }
+
+ block = &sw_desc->desc_blocks[sw_desc->dblk_num - 1];
+ desc = block->virt_addr + last_blk_desc * XDMA_DESC_SIZE;
+ desc->control = cpu_to_le32(XDMA_DESC_CONTROL_LAST);
+}
+
+static inline struct xdma_chan *to_xdma_chan(struct dma_chan *chan)
+{
+ return container_of(chan, struct xdma_chan, vchan.chan);
+}
+
+static inline struct xdma_desc *to_xdma_desc(struct virt_dma_desc *vdesc)
+{
+ return container_of(vdesc, struct xdma_desc, vdesc);
+}
+
+/**
+ * xdma_channel_init - Initialize DMA channel registers
+ * @chan: DMA channel pointer
+ */
+static int xdma_channel_init(struct xdma_chan *chan)
+{
+ struct xdma_device *xdev = chan->xdev_hdl;
+ int ret;
+
+ ret = regmap_write(xdev->rmap, chan->base + XDMA_CHAN_CONTROL_W1C,
+ CHAN_CTRL_NON_INCR_ADDR);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(xdev->rmap, chan->base + XDMA_CHAN_INTR_ENABLE,
+ CHAN_IM_ALL);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+/**
+ * xdma_free_desc - Free descriptor
+ * @vdesc: Virtual DMA descriptor
+ */
+static void xdma_free_desc(struct virt_dma_desc *vdesc)
+{
+ struct xdma_desc *sw_desc;
+ int i;
+
+ sw_desc = to_xdma_desc(vdesc);
+ for (i = 0; i < sw_desc->dblk_num; i++) {
+ if (!sw_desc->desc_blocks[i].virt_addr)
+ break;
+ dma_pool_free(sw_desc->chan->desc_pool,
+ sw_desc->desc_blocks[i].virt_addr,
+ sw_desc->desc_blocks[i].dma_addr);
+ }
+ kfree(sw_desc->desc_blocks);
+ kfree(sw_desc);
+}
+
+/**
+ * xdma_alloc_desc - Allocate descriptor
+ * @chan: DMA channel pointer
+ * @desc_num: Number of hardware descriptors
+ */
+static struct xdma_desc *
+xdma_alloc_desc(struct xdma_chan *chan, u32 desc_num)
+{
+ struct xdma_desc *sw_desc;
+ struct xdma_hw_desc *desc;
+ dma_addr_t dma_addr;
+ u32 dblk_num;
+ void *addr;
+ int i, j;
+
+ sw_desc = kzalloc(sizeof(*sw_desc), GFP_NOWAIT);
+ if (!sw_desc)
+ return NULL;
+
+ sw_desc->chan = chan;
+ sw_desc->desc_num = desc_num;
+ dblk_num = DIV_ROUND_UP(desc_num, XDMA_DESC_ADJACENT);
+ sw_desc->desc_blocks = kcalloc(dblk_num, sizeof(*sw_desc->desc_blocks),
+ GFP_NOWAIT);
+ if (!sw_desc->desc_blocks)
+ goto failed;
+
+ sw_desc->dblk_num = dblk_num;
+ for (i = 0; i < sw_desc->dblk_num; i++) {
+ addr = dma_pool_alloc(chan->desc_pool, GFP_NOWAIT, &dma_addr);
+ if (!addr)
+ goto failed;
+
+ sw_desc->desc_blocks[i].virt_addr = addr;
+ sw_desc->desc_blocks[i].dma_addr = dma_addr;
+ for (j = 0, desc = addr; j < XDMA_DESC_ADJACENT; j++)
+ desc[j].control = cpu_to_le32(XDMA_DESC_CONTROL(1, 0));
+ }
+
+ xdma_link_desc_blocks(sw_desc);
+
+ return sw_desc;
+
+failed:
+ xdma_free_desc(&sw_desc->vdesc);
+ return NULL;
+}
+
+/**
+ * xdma_xfer_start - Start DMA transfer
+ * @xdma_chan: DMA channel pointer
+ */
+static int xdma_xfer_start(struct xdma_chan *xchan)
+{
+ struct virt_dma_desc *vd = vchan_next_desc(&xchan->vchan);
+ struct xdma_device *xdev = xchan->xdev_hdl;
+ struct xdma_desc_block *block;
+ u32 val, completed_blocks;
+ struct xdma_desc *desc;
+ int ret;
+
+ /*
+ * check if there is not any submitted descriptor or channel is busy.
+ * vchan lock should be held where this function is called.
+ */
+ if (!vd || xchan->busy)
+ return -EINVAL;
+
+ /* clear run stop bit to get ready for transfer */
+ ret = regmap_write(xdev->rmap, xchan->base + XDMA_CHAN_CONTROL_W1C,
+ CHAN_CTRL_RUN_STOP);
+ if (ret)
+ return ret;
+
+ desc = to_xdma_desc(vd);
+ if (desc->dir != xchan->dir) {
+ xdma_err(xdev, "incorrect request direction");
+ return -EINVAL;
+ }
+
+ /* set DMA engine to the first descriptor block */
+ completed_blocks = desc->completed_desc_num / XDMA_DESC_ADJACENT;
+ block = &desc->desc_blocks[completed_blocks];
+ val = lower_32_bits(block->dma_addr);
+ ret = regmap_write(xdev->rmap, xchan->base + XDMA_SGDMA_DESC_LO, val);
+ if (ret)
+ return ret;
+
+ val = upper_32_bits(block->dma_addr);
+ ret = regmap_write(xdev->rmap, xchan->base + XDMA_SGDMA_DESC_HI, val);
+ if (ret)
+ return ret;
+
+ if (completed_blocks + 1 == desc->dblk_num)
+ val = (desc->desc_num - 1) & XDMA_DESC_ADJACENT_MASK;
+ else
+ val = XDMA_DESC_ADJACENT - 1;
+ ret = regmap_write(xdev->rmap, xchan->base + XDMA_SGDMA_DESC_ADJ, val);
+ if (ret)
+ return ret;
+
+ /* kick off DMA transfer */
+ ret = regmap_write(xdev->rmap, xchan->base + XDMA_CHAN_CONTROL,
+ CHAN_CTRL_START);
+ if (ret)
+ return ret;
+
+ xchan->busy = true;
+ return 0;
+}
+
+/**
+ * xdma_alloc_channels - Detect and allocate DMA channels
+ * @xdev: DMA device pointer
+ * @dir: Channel direction
+ */
+static int xdma_alloc_channels(struct xdma_device *xdev,
+ enum dma_transfer_direction dir)
+{
+ struct xdma_platdata *pdata = dev_get_platdata(&xdev->pdev->dev);
+ struct xdma_chan **chans, *xchan;
+ u32 base, identifier, target;
+ u32 *chan_num;
+ int i, j, ret;
+
+ if (dir == DMA_MEM_TO_DEV) {
+ base = XDMA_CHAN_H2C_OFFSET;
+ target = XDMA_CHAN_H2C_TARGET;
+ chans = &xdev->h2c_chans;
+ chan_num = &xdev->h2c_chan_num;
+ } else if (dir == DMA_DEV_TO_MEM) {
+ base = XDMA_CHAN_C2H_OFFSET;
+ target = XDMA_CHAN_C2H_TARGET;
+ chans = &xdev->c2h_chans;
+ chan_num = &xdev->c2h_chan_num;
+ } else {
+ xdma_err(xdev, "invalid direction specified");
+ return -EINVAL;
+ }
+
+ /* detect number of available DMA channels */
+ for (i = 0, *chan_num = 0; i < pdata->max_dma_channels; i++) {
+ ret = regmap_read(xdev->rmap, base + i * XDMA_CHAN_STRIDE,
+ &identifier);
+ if (ret)
+ return ret;
+
+ /* check if it is available DMA channel */
+ if (XDMA_CHAN_CHECK_TARGET(identifier, target))
+ (*chan_num)++;
+ }
+
+ if (!*chan_num) {
+ xdma_err(xdev, "does not probe any channel");
+ return -EINVAL;
+ }
+
+ *chans = devm_kcalloc(&xdev->pdev->dev, *chan_num, sizeof(**chans),
+ GFP_KERNEL);
+ if (!*chans)
+ return -ENOMEM;
+
+ for (i = 0, j = 0; i < pdata->max_dma_channels; i++) {
+ ret = regmap_read(xdev->rmap, base + i * XDMA_CHAN_STRIDE,
+ &identifier);
+ if (ret)
+ return ret;
+
+ if (!XDMA_CHAN_CHECK_TARGET(identifier, target))
+ continue;
+
+ if (j == *chan_num) {
+ xdma_err(xdev, "invalid channel number");
+ return -EIO;
+ }
+
+ /* init channel structure and hardware */
+ xchan = &(*chans)[j];
+ xchan->xdev_hdl = xdev;
+ xchan->base = base + i * XDMA_CHAN_STRIDE;
+ xchan->dir = dir;
+
+ ret = xdma_channel_init(xchan);
+ if (ret)
+ return ret;
+ xchan->vchan.desc_free = xdma_free_desc;
+ vchan_init(&xchan->vchan, &xdev->dma_dev);
+
+ j++;
+ }
+
+ dev_info(&xdev->pdev->dev, "configured %d %s channels", j,
+ (dir == DMA_MEM_TO_DEV) ? "H2C" : "C2H");
+
+ return 0;
+}
+
+/**
+ * xdma_issue_pending - Issue pending transactions
+ * @chan: DMA channel pointer
+ */
+static void xdma_issue_pending(struct dma_chan *chan)
+{
+ struct xdma_chan *xdma_chan = to_xdma_chan(chan);
+ unsigned long flags;
+
+ spin_lock_irqsave(&xdma_chan->vchan.lock, flags);
+ if (vchan_issue_pending(&xdma_chan->vchan))
+ xdma_xfer_start(xdma_chan);
+ spin_unlock_irqrestore(&xdma_chan->vchan.lock, flags);
+}
+
+/**
+ * xdma_prep_device_sg - prepare a descriptor for a DMA transaction
+ * @chan: DMA channel pointer
+ * @sgl: Transfer scatter gather list
+ * @sg_len: Length of scatter gather list
+ * @dir: Transfer direction
+ * @flags: transfer ack flags
+ * @context: APP words of the descriptor
+ */
+static struct dma_async_tx_descriptor *
+xdma_prep_device_sg(struct dma_chan *chan, struct scatterlist *sgl,
+ unsigned int sg_len, enum dma_transfer_direction dir,
+ unsigned long flags, void *context)
+{
+ struct xdma_chan *xdma_chan = to_xdma_chan(chan);
+ struct dma_async_tx_descriptor *tx_desc;
+ u32 desc_num = 0, i, len, rest;
+ struct xdma_desc_block *dblk;
+ struct xdma_hw_desc *desc;
+ struct xdma_desc *sw_desc;
+ u64 dev_addr, *src, *dst;
+ struct scatterlist *sg;
+ u64 addr;
+
+ for_each_sg(sgl, sg, sg_len, i)
+ desc_num += DIV_ROUND_UP(sg_dma_len(sg), XDMA_DESC_BLEN_MAX);
+
+ sw_desc = xdma_alloc_desc(xdma_chan, desc_num);
+ if (!sw_desc)
+ return NULL;
+ sw_desc->dir = dir;
+
+ if (dir == DMA_MEM_TO_DEV) {
+ dev_addr = xdma_chan->cfg.dst_addr;
+ src = &addr;
+ dst = &dev_addr;
+ } else {
+ dev_addr = xdma_chan->cfg.src_addr;
+ src = &dev_addr;
+ dst = &addr;
+ }
+
+ dblk = sw_desc->desc_blocks;
+ desc = dblk->virt_addr;
+ desc_num = 1;
+ for_each_sg(sgl, sg, sg_len, i) {
+ addr = sg_dma_address(sg);
+ rest = sg_dma_len(sg);
+
+ do {
+ len = min_t(u32, rest, XDMA_DESC_BLEN_MAX);
+ /* set hardware descriptor */
+ desc->bytes = cpu_to_le32(len);
+ desc->src_addr = cpu_to_le64(*src);
+ desc->dst_addr = cpu_to_le64(*dst);
+
+ if (!(desc_num & XDMA_DESC_ADJACENT_MASK)) {
+ dblk++;
+ desc = dblk->virt_addr;
+ } else {
+ desc++;
+ }
+
+ desc_num++;
+ dev_addr += len;
+ addr += len;
+ rest -= len;
+ } while (rest);
+ }
+
+ tx_desc = vchan_tx_prep(&xdma_chan->vchan, &sw_desc->vdesc, flags);
+ if (!tx_desc)
+ goto failed;
+
+ return tx_desc;
+
+failed:
+ xdma_free_desc(&sw_desc->vdesc);
+
+ return NULL;
+}
+
+/**
+ * xdma_device_config - Configure the DMA channel
+ * @chan: DMA channel
+ * @cfg: channel configuration
+ */
+static int xdma_device_config(struct dma_chan *chan,
+ struct dma_slave_config *cfg)
+{
+ struct xdma_chan *xdma_chan = to_xdma_chan(chan);
+
+ memcpy(&xdma_chan->cfg, cfg, sizeof(*cfg));
+
+ return 0;
+}
+
+/**
+ * xdma_free_chan_resources - Free channel resources
+ * @chan: DMA channel
+ */
+static void xdma_free_chan_resources(struct dma_chan *chan)
+{
+ struct xdma_chan *xdma_chan = to_xdma_chan(chan);
+
+ vchan_free_chan_resources(&xdma_chan->vchan);
+ dma_pool_destroy(xdma_chan->desc_pool);
+ xdma_chan->desc_pool = NULL;
+}
+
+/**
+ * xdma_alloc_chan_resources - Allocate channel resources
+ * @chan: DMA channel
+ */
+static int xdma_alloc_chan_resources(struct dma_chan *chan)
+{
+ struct xdma_chan *xdma_chan = to_xdma_chan(chan);
+ struct xdma_device *xdev = xdma_chan->xdev_hdl;
+ struct device *dev = xdev->dma_dev.dev;
+
+ while (dev && !dev_is_pci(dev))
+ dev = dev->parent;
+ if (!dev) {
+ xdma_err(xdev, "unable to find pci device");
+ return -EINVAL;
+ }
+
+ xdma_chan->desc_pool = dma_pool_create(dma_chan_name(chan),
+ dev, XDMA_DESC_BLOCK_SIZE,
+ XDMA_DESC_BLOCK_ALIGN, 0);
+ if (!xdma_chan->desc_pool) {
+ xdma_err(xdev, "unable to allocate descriptor pool");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/**
+ * xdma_channel_isr - XDMA channel interrupt handler
+ * @irq: IRQ number
+ * @dev_id: Pointer to the DMA channel structure
+ */
+static irqreturn_t xdma_channel_isr(int irq, void *dev_id)
+{
+ struct xdma_chan *xchan = dev_id;
+ u32 complete_desc_num = 0;
+ struct xdma_device *xdev;
+ struct virt_dma_desc *vd;
+ struct xdma_desc *desc;
+ int ret;
+
+ spin_lock(&xchan->vchan.lock);
+
+ /* get submitted request */
+ vd = vchan_next_desc(&xchan->vchan);
+ if (!vd)
+ goto out;
+
+ xchan->busy = false;
+ desc = to_xdma_desc(vd);
+ xdev = xchan->xdev_hdl;
+
+ ret = regmap_read(xdev->rmap, xchan->base + XDMA_CHAN_COMPLETED_DESC,
+ &complete_desc_num);
+ if (ret)
+ goto out;
+
+ desc->completed_desc_num += complete_desc_num;
+ /*
+ * if all data blocks are transferred, remove and complete the request
+ */
+ if (desc->completed_desc_num == desc->desc_num) {
+ list_del(&vd->node);
+ vchan_cookie_complete(vd);
+ goto out;
+ }
+
+ if (desc->completed_desc_num > desc->desc_num ||
+ complete_desc_num != XDMA_DESC_BLOCK_NUM * XDMA_DESC_ADJACENT)
+ goto out;
+
+ /* transfer the rest of data */
+ xdma_xfer_start(xchan);
+
+out:
+ spin_unlock(&xchan->vchan.lock);
+ return IRQ_HANDLED;
+}
+
+/**
+ * xdma_irq_fini - Uninitialize IRQ
+ * @xdev: DMA device pointer
+ */
+static void xdma_irq_fini(struct xdma_device *xdev)
+{
+ int i;
+
+ /* disable interrupt */
+ regmap_write(xdev->rmap, XDMA_IRQ_CHAN_INT_EN_W1C, ~0);
+
+ /* free irq handler */
+ for (i = 0; i < xdev->h2c_chan_num; i++)
+ free_irq(xdev->h2c_chans[i].irq, &xdev->h2c_chans[i]);
+
+ for (i = 0; i < xdev->c2h_chan_num; i++)
+ free_irq(xdev->c2h_chans[i].irq, &xdev->c2h_chans[i]);
+}
+
+/**
+ * xdma_set_vector_reg - configure hardware IRQ registers
+ * @xdev: DMA device pointer
+ * @vec_tbl_start: Start of IRQ registers
+ * @irq_start: Start of IRQ
+ * @irq_num: Number of IRQ
+ */
+static int xdma_set_vector_reg(struct xdma_device *xdev, u32 vec_tbl_start,
+ u32 irq_start, u32 irq_num)
+{
+ u32 shift, i, val = 0;
+ int ret;
+
+ /* Each IRQ register is 32 bit and contains 4 IRQs */
+ while (irq_num > 0) {
+ for (i = 0; i < 4; i++) {
+ shift = XDMA_IRQ_VEC_SHIFT * i;
+ val |= irq_start << shift;
+ irq_start++;
+ irq_num--;
+ }
+
+ /* write IRQ register */
+ ret = regmap_write(xdev->rmap, vec_tbl_start, val);
+ if (ret)
+ return ret;
+ vec_tbl_start += sizeof(u32);
+ val = 0;
+ }
+
+ return 0;
+}
+
+/**
+ * xdma_irq_init - initialize IRQs
+ * @xdev: DMA device pointer
+ */
+static int xdma_irq_init(struct xdma_device *xdev)
+{
+ u32 irq = xdev->irq_start;
+ u32 user_irq_start;
+ int i, j, ret;
+
+ /* return failure if there are not enough IRQs */
+ if (xdev->irq_num < XDMA_CHAN_NUM(xdev)) {
+ xdma_err(xdev, "not enough irq");
+ return -EINVAL;
+ }
+
+ /* setup H2C interrupt handler */
+ for (i = 0; i < xdev->h2c_chan_num; i++) {
+ ret = request_irq(irq, xdma_channel_isr, 0,
+ "xdma-h2c-channel", &xdev->h2c_chans[i]);
+ if (ret) {
+ xdma_err(xdev, "H2C channel%d request irq%d failed: %d",
+ i, irq, ret);
+ goto failed_init_h2c;
+ }
+ xdev->h2c_chans[i].irq = irq;
+ irq++;
+ }
+
+ /* setup C2H interrupt handler */
+ for (j = 0; j < xdev->c2h_chan_num; j++) {
+ ret = request_irq(irq, xdma_channel_isr, 0,
+ "xdma-c2h-channel", &xdev->c2h_chans[j]);
+ if (ret) {
+ xdma_err(xdev, "H2C channel%d request irq%d failed: %d",
+ j, irq, ret);
+ goto failed_init_c2h;
+ }
+ xdev->c2h_chans[j].irq = irq;
+ irq++;
+ }
+
+ /* config hardware IRQ registers */
+ ret = xdma_set_vector_reg(xdev, XDMA_IRQ_CHAN_VEC_NUM, 0,
+ XDMA_CHAN_NUM(xdev));
+ if (ret) {
+ xdma_err(xdev, "failed to set channel vectors: %d", ret);
+ goto failed_init_c2h;
+ }
+
+ /* config user IRQ registers if needed */
+ user_irq_start = XDMA_CHAN_NUM(xdev);
+ if (xdev->irq_num > user_irq_start) {
+ ret = xdma_set_vector_reg(xdev, XDMA_IRQ_USER_VEC_NUM,
+ user_irq_start,
+ xdev->irq_num - user_irq_start);
+ if (ret) {
+ xdma_err(xdev, "failed to set user vectors: %d", ret);
+ goto failed_init_c2h;
+ }
+ }
+
+ /* enable interrupt */
+ ret = regmap_write(xdev->rmap, XDMA_IRQ_CHAN_INT_EN_W1S, ~0);
+ if (ret)
+ goto failed_init_c2h;
+
+ return 0;
+
+failed_init_c2h:
+ while (j--)
+ free_irq(xdev->c2h_chans[j].irq, &xdev->c2h_chans[j]);
+failed_init_h2c:
+ while (i--)
+ free_irq(xdev->h2c_chans[i].irq, &xdev->h2c_chans[i]);
+
+ return ret;
+}
+
+static bool xdma_filter_fn(struct dma_chan *chan, void *param)
+{
+ struct xdma_chan *xdma_chan = to_xdma_chan(chan);
+ struct xdma_chan_info *chan_info = param;
+
+ return chan_info->dir == xdma_chan->dir;
+}
+
+/**
+ * xdma_disable_user_irq - Disable user interrupt
+ * @pdev: Pointer to the platform_device structure
+ * @irq_num: System IRQ number
+ */
+void xdma_disable_user_irq(struct platform_device *pdev, u32 irq_num)
+{
+ struct xdma_device *xdev = platform_get_drvdata(pdev);
+ u32 index;
+
+ index = irq_num - xdev->irq_start;
+ if (index < XDMA_CHAN_NUM(xdev) || index >= xdev->irq_num) {
+ xdma_err(xdev, "invalid user irq number");
+ return;
+ }
+ index -= XDMA_CHAN_NUM(xdev);
+
+ regmap_write(xdev->rmap, XDMA_IRQ_USER_INT_EN_W1C, 1 << index);
+}
+EXPORT_SYMBOL(xdma_disable_user_irq);
+
+/**
+ * xdma_enable_user_irq - Enable user logic interrupt
+ * @pdev: Pointer to the platform_device structure
+ * @irq_num: System IRQ number
+ */
+int xdma_enable_user_irq(struct platform_device *pdev, u32 irq_num)
+{
+ struct xdma_device *xdev = platform_get_drvdata(pdev);
+ u32 index;
+ int ret;
+
+ index = irq_num - xdev->irq_start;
+ if (index < XDMA_CHAN_NUM(xdev) || index >= xdev->irq_num) {
+ xdma_err(xdev, "invalid user irq number");
+ return -EINVAL;
+ }
+ index -= XDMA_CHAN_NUM(xdev);
+
+ ret = regmap_write(xdev->rmap, XDMA_IRQ_USER_INT_EN_W1S, 1 << index);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+EXPORT_SYMBOL(xdma_enable_user_irq);
+
+/**
+ * xdma_get_user_irq - Get system IRQ number
+ * @pdev: Pointer to the platform_device structure
+ * @user_irq_index: User logic IRQ wire index
+ *
+ * Return: The system IRQ number allocated for the given wire index.
+ */
+int xdma_get_user_irq(struct platform_device *pdev, u32 user_irq_index)
+{
+ struct xdma_device *xdev = platform_get_drvdata(pdev);
+
+ if (XDMA_CHAN_NUM(xdev) + user_irq_index >= xdev->irq_num) {
+ xdma_err(xdev, "invalid user irq index");
+ return -EINVAL;
+ }
+
+ return xdev->irq_start + XDMA_CHAN_NUM(xdev) + user_irq_index;
+}
+EXPORT_SYMBOL(xdma_get_user_irq);
+
+/**
+ * xdma_remove - Driver remove function
+ * @pdev: Pointer to the platform_device structure
+ */
+static int xdma_remove(struct platform_device *pdev)
+{
+ struct xdma_device *xdev = platform_get_drvdata(pdev);
+
+ if (xdev->status & XDMA_DEV_STATUS_INIT_MSIX)
+ xdma_irq_fini(xdev);
+
+ if (xdev->status & XDMA_DEV_STATUS_REG_DMA)
+ dma_async_device_unregister(&xdev->dma_dev);
+
+ return 0;
+}
+
+/**
+ * xdma_probe - Driver probe function
+ * @pdev: Pointer to the platform_device structure
+ */
+static int xdma_probe(struct platform_device *pdev)
+{
+ struct xdma_platdata *pdata = dev_get_platdata(&pdev->dev);
+ struct xdma_device *xdev;
+ void __iomem *reg_base;
+ struct resource *res;
+ int ret = -ENODEV;
+
+ if (pdata->max_dma_channels > XDMA_MAX_CHANNELS) {
+ dev_err(&pdev->dev, "invalid max dma channels %d",
+ pdata->max_dma_channels);
+ return -EINVAL;
+ }
+
+ xdev = devm_kzalloc(&pdev->dev, sizeof(*xdev), GFP_KERNEL);
+ if (!xdev)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, xdev);
+ xdev->pdev = pdev;
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ xdma_err(xdev, "failed to get irq resource");
+ goto failed;
+ }
+ xdev->irq_start = res->start;
+ xdev->irq_num = res->end - res->start + 1;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ xdma_err(xdev, "failed to get io resource");
+ goto failed;
+ }
+
+ reg_base = devm_ioremap_resource(&pdev->dev, res);
+ if (!reg_base) {
+ xdma_err(xdev, "ioremap failed");
+ goto failed;
+ }
+
+ xdev->rmap = devm_regmap_init_mmio(&pdev->dev, reg_base,
+ &xdma_regmap_config);
+ if (!xdev->rmap) {
+ xdma_err(xdev, "config regmap failed: %d", ret);
+ goto failed;
+ }
+ INIT_LIST_HEAD(&xdev->dma_dev.channels);
+
+ ret = xdma_alloc_channels(xdev, DMA_MEM_TO_DEV);
+ if (ret) {
+ xdma_err(xdev, "config H2C channels failed: %d", ret);
+ goto failed;
+ }
+
+ ret = xdma_alloc_channels(xdev, DMA_DEV_TO_MEM);
+ if (ret) {
+ xdma_err(xdev, "config C2H channels failed: %d", ret);
+ goto failed;
+ }
+
+ dma_cap_set(DMA_SLAVE, xdev->dma_dev.cap_mask);
+ dma_cap_set(DMA_PRIVATE, xdev->dma_dev.cap_mask);
+
+ xdev->dma_dev.dev = &pdev->dev;
+ xdev->dma_dev.device_free_chan_resources = xdma_free_chan_resources;
+ xdev->dma_dev.device_alloc_chan_resources = xdma_alloc_chan_resources;
+ xdev->dma_dev.device_tx_status = dma_cookie_status;
+ xdev->dma_dev.device_prep_slave_sg = xdma_prep_device_sg;
+ xdev->dma_dev.device_config = xdma_device_config;
+ xdev->dma_dev.device_issue_pending = xdma_issue_pending;
+ xdev->dma_dev.filter.map = pdata->device_map;
+ xdev->dma_dev.filter.mapcnt = pdata->device_map_cnt;
+ xdev->dma_dev.filter.fn = xdma_filter_fn;
+
+ ret = dma_async_device_register(&xdev->dma_dev);
+ if (ret) {
+ xdma_err(xdev, "failed to register Xilinx XDMA: %d", ret);
+ goto failed;
+ }
+ xdev->status |= XDMA_DEV_STATUS_REG_DMA;
+
+ ret = xdma_irq_init(xdev);
+ if (ret) {
+ xdma_err(xdev, "failed to init msix: %d", ret);
+ goto failed;
+ }
+ xdev->status |= XDMA_DEV_STATUS_INIT_MSIX;
+
+ return 0;
+
+failed:
+ xdma_remove(pdev);
+
+ return ret;
+}
+
+static const struct platform_device_id xdma_id_table[] = {
+ { "xdma", 0},
+ { },
+};
+
+static struct platform_driver xdma_driver = {
+ .driver = {
+ .name = "xdma",
+ },
+ .id_table = xdma_id_table,
+ .probe = xdma_probe,
+ .remove = xdma_remove,
+};
+
+module_platform_driver(xdma_driver);
+
+MODULE_DESCRIPTION("AMD XDMA driver");
+MODULE_AUTHOR("XRT Team <runtimeca39d@amd.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/dma/xilinx/zynqmp_dma.c b/drivers/dma/xilinx/zynqmp_dma.c
index 21472a5d7636..ce359058c638 100644
--- a/drivers/dma/xilinx/zynqmp_dma.c
+++ b/drivers/dma/xilinx/zynqmp_dma.c
@@ -890,7 +890,6 @@ static int zynqmp_dma_chan_probe(struct zynqmp_dma_device *zdev,
struct platform_device *pdev)
{
struct zynqmp_dma_chan *chan;
- struct resource *res;
struct device_node *node = pdev->dev.of_node;
int err;
@@ -900,8 +899,7 @@ static int zynqmp_dma_chan_probe(struct zynqmp_dma_device *zdev,
chan->dev = zdev->dev;
chan->zdev = zdev;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- chan->regs = devm_ioremap_resource(&pdev->dev, res);
+ chan->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(chan->regs))
return PTR_ERR(chan->regs);
diff --git a/drivers/eisa/eisa-bus.c b/drivers/eisa/eisa-bus.c
index 65bffde137e3..713582cc27d1 100644
--- a/drivers/eisa/eisa-bus.c
+++ b/drivers/eisa/eisa-bus.c
@@ -127,9 +127,9 @@ static int eisa_bus_match(struct device *dev, struct device_driver *drv)
return 0;
}
-static int eisa_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int eisa_bus_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct eisa_device *edev = to_eisa_device(dev);
+ const struct eisa_device *edev = to_eisa_device(dev);
add_uevent_var(env, "MODALIAS=" EISA_DEVICE_MODALIAS_FMT, edev->id.sig);
return 0;
diff --git a/drivers/extcon/extcon-intel-cht-wc.c b/drivers/extcon/extcon-intel-cht-wc.c
index 89a6449e3f4a..2c55f06ba699 100644
--- a/drivers/extcon/extcon-intel-cht-wc.c
+++ b/drivers/extcon/extcon-intel-cht-wc.c
@@ -537,6 +537,7 @@ static int cht_wc_extcon_probe(struct platform_device *pdev)
cht_wc_extcon_set_5v_boost(ext, false);
break;
case INTEL_CHT_WC_LENOVO_YOGABOOK1:
+ case INTEL_CHT_WC_LENOVO_YT3_X90:
/* Do this first, as it may very well return -EPROBE_DEFER. */
ret = cht_wc_extcon_get_role_sw_and_regulator(ext);
if (ret)
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c
index 958aa4662ccb..2c16ee8fd842 100644
--- a/drivers/firewire/core-cdev.c
+++ b/drivers/firewire/core-cdev.c
@@ -111,6 +111,7 @@ struct inbound_transaction_resource {
struct client_resource resource;
struct fw_card *card;
struct fw_request *request;
+ bool is_fcp;
void *data;
size_t length;
};
@@ -643,19 +644,14 @@ static int ioctl_send_request(struct client *client, union ioctl_arg *arg)
client->device->max_speed);
}
-static inline bool is_fcp_request(struct fw_request *request)
-{
- return request == NULL;
-}
-
static void release_request(struct client *client,
struct client_resource *resource)
{
struct inbound_transaction_resource *r = container_of(resource,
struct inbound_transaction_resource, resource);
- if (is_fcp_request(r->request))
- kfree(r->data);
+ if (r->is_fcp)
+ fw_request_put(r->request);
else
fw_send_response(r->card, r->request, RCODE_CONFLICT_ERROR);
@@ -669,15 +665,20 @@ static void handle_request(struct fw_card *card, struct fw_request *request,
void *payload, size_t length, void *callback_data)
{
struct address_handler_resource *handler = callback_data;
+ bool is_fcp = is_in_fcp_region(offset, length);
struct inbound_transaction_resource *r;
struct inbound_transaction_event *e;
size_t event_size0;
- void *fcp_frame = NULL;
int ret;
/* card may be different from handler->client->device->card */
fw_card_get(card);
+ // Extend the lifetime of data for request so that its payload is safely accessible in
+ // the process context for the client.
+ if (is_fcp)
+ fw_request_get(request);
+
r = kmalloc(sizeof(*r), GFP_ATOMIC);
e = kmalloc(sizeof(*e), GFP_ATOMIC);
if (r == NULL || e == NULL)
@@ -685,21 +686,10 @@ static void handle_request(struct fw_card *card, struct fw_request *request,
r->card = card;
r->request = request;
+ r->is_fcp = is_fcp;
r->data = payload;
r->length = length;
- if (is_fcp_request(request)) {
- /*
- * FIXME: Let core-transaction.c manage a
- * single reference-counted copy?
- */
- fcp_frame = kmemdup(payload, length, GFP_ATOMIC);
- if (fcp_frame == NULL)
- goto failed;
-
- r->data = fcp_frame;
- }
-
r->resource.release = release_request;
ret = add_client_resource(handler->client, &r->resource, GFP_ATOMIC);
if (ret < 0)
@@ -741,10 +731,11 @@ static void handle_request(struct fw_card *card, struct fw_request *request,
failed:
kfree(r);
kfree(e);
- kfree(fcp_frame);
- if (!is_fcp_request(request))
+ if (!is_fcp)
fw_send_response(card, request, RCODE_CONFLICT_ERROR);
+ else
+ fw_request_put(request);
fw_card_put(card);
}
@@ -819,19 +810,19 @@ static int ioctl_send_response(struct client *client, union ioctl_arg *arg)
r = container_of(resource, struct inbound_transaction_resource,
resource);
- if (is_fcp_request(r->request)) {
- kfree(r->data);
+ if (r->is_fcp) {
+ fw_request_put(r->request);
goto out;
}
if (a->length != fw_get_response_length(r->request)) {
ret = -EINVAL;
- kfree(r->request);
+ fw_request_put(r->request);
goto out;
}
if (copy_from_user(r->data, u64_to_uptr(a->data), a->length)) {
ret = -EFAULT;
- kfree(r->request);
+ fw_request_put(r->request);
goto out;
}
fw_send_response(r->card, r->request, a->rcode);
diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c
index adddd8c45d0c..aa597cda0d88 100644
--- a/drivers/firewire/core-device.c
+++ b/drivers/firewire/core-device.c
@@ -133,7 +133,7 @@ static void get_ids(const u32 *directory, int *id)
}
}
-static void get_modalias_ids(struct fw_unit *unit, int *id)
+static void get_modalias_ids(const struct fw_unit *unit, int *id)
{
get_ids(&fw_parent_device(unit)->config_rom[5], id);
get_ids(unit->directory, id);
@@ -195,7 +195,7 @@ static void fw_unit_remove(struct device *dev)
driver->remove(fw_unit(dev));
}
-static int get_modalias(struct fw_unit *unit, char *buffer, size_t buffer_size)
+static int get_modalias(const struct fw_unit *unit, char *buffer, size_t buffer_size)
{
int id[] = {0, 0, 0, 0};
@@ -206,9 +206,9 @@ static int get_modalias(struct fw_unit *unit, char *buffer, size_t buffer_size)
id[0], id[1], id[2], id[3]);
}
-static int fw_unit_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int fw_unit_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct fw_unit *unit = fw_unit(dev);
+ const struct fw_unit *unit = fw_unit(dev);
char modalias[64];
get_modalias(unit, modalias, sizeof(modalias));
diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c
index af498d767702..a9f70c96323e 100644
--- a/drivers/firewire/core-transaction.c
+++ b/drivers/firewire/core-transaction.c
@@ -535,12 +535,6 @@ const struct fw_address_region fw_unit_space_region =
{ .start = 0xfffff0000900ULL, .end = 0x1000000000000ULL, };
#endif /* 0 */
-static bool is_in_fcp_region(u64 offset, size_t length)
-{
- return offset >= (CSR_REGISTER_BASE | CSR_FCP_COMMAND) &&
- offset + length <= (CSR_REGISTER_BASE | CSR_FCP_END);
-}
-
/**
* fw_core_add_address_handler() - register for incoming requests
* @handler: callback
@@ -617,6 +611,7 @@ void fw_core_remove_address_handler(struct fw_address_handler *handler)
EXPORT_SYMBOL(fw_core_remove_address_handler);
struct fw_request {
+ struct kref kref;
struct fw_packet response;
u32 request_header[4];
int ack;
@@ -625,13 +620,33 @@ struct fw_request {
u32 data[];
};
+void fw_request_get(struct fw_request *request)
+{
+ kref_get(&request->kref);
+}
+
+static void release_request(struct kref *kref)
+{
+ struct fw_request *request = container_of(kref, struct fw_request, kref);
+
+ kfree(request);
+}
+
+void fw_request_put(struct fw_request *request)
+{
+ kref_put(&request->kref, release_request);
+}
+
static void free_response_callback(struct fw_packet *packet,
struct fw_card *card, int status)
{
- struct fw_request *request;
+ struct fw_request *request = container_of(packet, struct fw_request, response);
- request = container_of(packet, struct fw_request, response);
- kfree(request);
+ // Decrease the reference count since not at in-flight.
+ fw_request_put(request);
+
+ // Decrease the reference count to release the object.
+ fw_request_put(request);
}
int fw_get_response_length(struct fw_request *r)
@@ -782,6 +797,7 @@ static struct fw_request *allocate_request(struct fw_card *card,
request = kmalloc(sizeof(*request) + length, GFP_ATOMIC);
if (request == NULL)
return NULL;
+ kref_init(&request->kref);
request->response.speed = p->speed;
request->response.timestamp =
@@ -800,16 +816,22 @@ static struct fw_request *allocate_request(struct fw_card *card,
return request;
}
+/**
+ * fw_send_response: - send response packet for asynchronous transaction.
+ * @card: interface to send the response at.
+ * @request: firewire request data for the transaction.
+ * @rcode: response code to send.
+ *
+ * Submit a response packet into the asynchronous response transmission queue. The @request
+ * is going to be released when the transmission successfully finishes later.
+ */
void fw_send_response(struct fw_card *card,
struct fw_request *request, int rcode)
{
- if (WARN_ONCE(!request, "invalid for FCP address handlers"))
- return;
-
/* unified transaction or broadcast transaction: don't respond */
if (request->ack != ACK_PENDING ||
HEADER_DESTINATION_IS_BROADCAST(request->request_header[0])) {
- kfree(request);
+ fw_request_put(request);
return;
}
@@ -821,6 +843,9 @@ void fw_send_response(struct fw_card *card,
fw_fill_response(&request->response, request->request_header,
rcode, NULL, 0);
+ // Increase the reference count so that the object is kept during in-flight.
+ fw_request_get(request);
+
card->driver->send_response(card, &request->response);
}
EXPORT_SYMBOL(fw_send_response);
@@ -910,7 +935,7 @@ static void handle_fcp_region_request(struct fw_card *card,
rcu_read_lock();
list_for_each_entry_rcu(handler, &address_handler_list, link) {
if (is_enclosing_handler(handler, offset, request->length))
- handler->address_callback(card, NULL, tcode,
+ handler->address_callback(card, request, tcode,
destination, source,
p->generation, offset,
request->data,
diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h
index 71d5f16f311c..eafa4eaae737 100644
--- a/drivers/firewire/core.h
+++ b/drivers/firewire/core.h
@@ -244,6 +244,9 @@ int fw_get_response_length(struct fw_request *request);
void fw_fill_response(struct fw_packet *response, u32 *request_header,
int rcode, void *payload, size_t length);
+void fw_request_get(struct fw_request *request);
+void fw_request_put(struct fw_request *request);
+
#define FW_PHY_CONFIG_NO_NODE_ID -1
#define FW_PHY_CONFIG_CURRENT_GAP_COUNT -1
void fw_send_phy_config(struct fw_card *card,
@@ -254,4 +257,10 @@ static inline bool is_ping_packet(u32 *data)
return (data[0] & 0xc0ffffff) == 0 && ~data[0] == data[1];
}
+static inline bool is_in_fcp_region(u64 offset, size_t length)
+{
+ return offset >= (CSR_REGISTER_BASE | CSR_FCP_COMMAND) &&
+ offset + length <= (CSR_REGISTER_BASE | CSR_FCP_END);
+}
+
#endif /* _FIREWIRE_CORE_H */
diff --git a/drivers/firmware/arm_ffa/bus.c b/drivers/firmware/arm_ffa/bus.c
index 99d439480612..f29d77ecf72d 100644
--- a/drivers/firmware/arm_ffa/bus.c
+++ b/drivers/firmware/arm_ffa/bus.c
@@ -56,9 +56,9 @@ static void ffa_device_remove(struct device *dev)
ffa_drv->remove(to_ffa_dev(dev));
}
-static int ffa_device_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int ffa_device_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct ffa_device *ffa_dev = to_ffa_dev(dev);
+ const struct ffa_device *ffa_dev = to_ffa_dev(dev);
return add_uevent_var(env, "MODALIAS=arm_ffa:%04x:%pUb",
ffa_dev->vm_id, &ffa_dev->uuid);
diff --git a/drivers/firmware/arm_scmi/Kconfig b/drivers/firmware/arm_scmi/Kconfig
index a14f65444b35..ea0f5083ac47 100644
--- a/drivers/firmware/arm_scmi/Kconfig
+++ b/drivers/firmware/arm_scmi/Kconfig
@@ -23,6 +23,38 @@ config ARM_SCMI_PROTOCOL
if ARM_SCMI_PROTOCOL
+config ARM_SCMI_NEED_DEBUGFS
+ bool
+ help
+ This declares whether at least one SCMI facility is configured
+ which needs debugfs support. When selected causess the creation
+ of a common SCMI debugfs root directory.
+
+config ARM_SCMI_RAW_MODE_SUPPORT
+ bool "Enable support for SCMI Raw transmission mode"
+ depends on DEBUG_FS
+ select ARM_SCMI_NEED_DEBUGFS
+ help
+ Enable support for SCMI Raw transmission mode.
+
+ If enabled allows the direct injection and snooping of SCMI bare
+ messages through a dedicated debugfs interface.
+ It is meant to be used by SCMI compliance/testing suites.
+
+ When enabled regular SCMI drivers interactions are inhibited in
+ order to avoid unexpected interactions with the SCMI Raw message
+ flow. If unsure say N.
+
+config ARM_SCMI_RAW_MODE_SUPPORT_COEX
+ bool "Allow SCMI Raw mode coexistence with normal SCMI stack"
+ depends on ARM_SCMI_RAW_MODE_SUPPORT
+ help
+ Allow SCMI Raw transmission mode to coexist with normal SCMI stack.
+
+ This will allow regular SCMI drivers to register with the core and
+ operate normally, thing which could make an SCMI test suite using the
+ SCMI Raw mode support unreliable. If unsure, say N.
+
config ARM_SCMI_HAVE_TRANSPORT
bool
help
diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi/Makefile
index 9ea86f8cc8f7..b31d78fa66cc 100644
--- a/drivers/firmware/arm_scmi/Makefile
+++ b/drivers/firmware/arm_scmi/Makefile
@@ -1,6 +1,9 @@
# SPDX-License-Identifier: GPL-2.0-only
scmi-bus-y = bus.o
+scmi-core-objs := $(scmi-bus-y)
+
scmi-driver-y = driver.o notify.o
+scmi-driver-$(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT) += raw_mode.o
scmi-transport-$(CONFIG_ARM_SCMI_HAVE_SHMEM) = shmem.o
scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_MAILBOX) += mailbox.o
scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_SMC) += smc.o
@@ -8,9 +11,11 @@ scmi-transport-$(CONFIG_ARM_SCMI_HAVE_MSG) += msg.o
scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_VIRTIO) += virtio.o
scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_OPTEE) += optee.o
scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o system.o voltage.o powercap.o
-scmi-module-objs := $(scmi-bus-y) $(scmi-driver-y) $(scmi-protocols-y) \
- $(scmi-transport-y)
+scmi-module-objs := $(scmi-driver-y) $(scmi-protocols-y) $(scmi-transport-y)
+
+obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-core.o
obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-module.o
+
obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o
obj-$(CONFIG_ARM_SCMI_POWER_CONTROL) += scmi_power_control.o
diff --git a/drivers/firmware/arm_scmi/bus.c b/drivers/firmware/arm_scmi/bus.c
index 35bb70724d44..73140b854b31 100644
--- a/drivers/firmware/arm_scmi/bus.c
+++ b/drivers/firmware/arm_scmi/bus.c
@@ -7,17 +7,185 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/atomic.h>
#include <linux/types.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/device.h>
+#include <linux/of.h>
#include "common.h"
+BLOCKING_NOTIFIER_HEAD(scmi_requested_devices_nh);
+EXPORT_SYMBOL_GPL(scmi_requested_devices_nh);
+
static DEFINE_IDA(scmi_bus_id);
-static DEFINE_IDR(scmi_protocols);
-static DEFINE_SPINLOCK(protocol_lock);
+
+static DEFINE_IDR(scmi_requested_devices);
+/* Protect access to scmi_requested_devices */
+static DEFINE_MUTEX(scmi_requested_devices_mtx);
+
+struct scmi_requested_dev {
+ const struct scmi_device_id *id_table;
+ struct list_head node;
+};
+
+/* Track globally the creation of SCMI SystemPower related devices */
+static atomic_t scmi_syspower_registered = ATOMIC_INIT(0);
+
+/**
+ * scmi_protocol_device_request - Helper to request a device
+ *
+ * @id_table: A protocol/name pair descriptor for the device to be created.
+ *
+ * This helper let an SCMI driver request specific devices identified by the
+ * @id_table to be created for each active SCMI instance.
+ *
+ * The requested device name MUST NOT be already existent for any protocol;
+ * at first the freshly requested @id_table is annotated in the IDR table
+ * @scmi_requested_devices and then the requested device is advertised to any
+ * registered party via the @scmi_requested_devices_nh notification chain.
+ *
+ * Return: 0 on Success
+ */
+static int scmi_protocol_device_request(const struct scmi_device_id *id_table)
+{
+ int ret = 0;
+ unsigned int id = 0;
+ struct list_head *head, *phead = NULL;
+ struct scmi_requested_dev *rdev;
+
+ pr_debug("Requesting SCMI device (%s) for protocol %x\n",
+ id_table->name, id_table->protocol_id);
+
+ if (IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT) &&
+ !IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT_COEX)) {
+ pr_warn("SCMI Raw mode active. Rejecting '%s'/0x%02X\n",
+ id_table->name, id_table->protocol_id);
+ return -EINVAL;
+ }
+
+ /*
+ * Search for the matching protocol rdev list and then search
+ * of any existent equally named device...fails if any duplicate found.
+ */
+ mutex_lock(&scmi_requested_devices_mtx);
+ idr_for_each_entry(&scmi_requested_devices, head, id) {
+ if (!phead) {
+ /* A list found registered in the IDR is never empty */
+ rdev = list_first_entry(head, struct scmi_requested_dev,
+ node);
+ if (rdev->id_table->protocol_id ==
+ id_table->protocol_id)
+ phead = head;
+ }
+ list_for_each_entry(rdev, head, node) {
+ if (!strcmp(rdev->id_table->name, id_table->name)) {
+ pr_err("Ignoring duplicate request [%d] %s\n",
+ rdev->id_table->protocol_id,
+ rdev->id_table->name);
+ ret = -EINVAL;
+ goto out;
+ }
+ }
+ }
+
+ /*
+ * No duplicate found for requested id_table, so let's create a new
+ * requested device entry for this new valid request.
+ */
+ rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);
+ if (!rdev) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ rdev->id_table = id_table;
+
+ /*
+ * Append the new requested device table descriptor to the head of the
+ * related protocol list, eventually creating such head if not already
+ * there.
+ */
+ if (!phead) {
+ phead = kzalloc(sizeof(*phead), GFP_KERNEL);
+ if (!phead) {
+ kfree(rdev);
+ ret = -ENOMEM;
+ goto out;
+ }
+ INIT_LIST_HEAD(phead);
+
+ ret = idr_alloc(&scmi_requested_devices, (void *)phead,
+ id_table->protocol_id,
+ id_table->protocol_id + 1, GFP_KERNEL);
+ if (ret != id_table->protocol_id) {
+ pr_err("Failed to save SCMI device - ret:%d\n", ret);
+ kfree(rdev);
+ kfree(phead);
+ ret = -EINVAL;
+ goto out;
+ }
+ ret = 0;
+ }
+ list_add(&rdev->node, phead);
+
+out:
+ mutex_unlock(&scmi_requested_devices_mtx);
+
+ if (!ret)
+ blocking_notifier_call_chain(&scmi_requested_devices_nh,
+ SCMI_BUS_NOTIFY_DEVICE_REQUEST,
+ (void *)rdev->id_table);
+
+ return ret;
+}
+
+/**
+ * scmi_protocol_device_unrequest - Helper to unrequest a device
+ *
+ * @id_table: A protocol/name pair descriptor for the device to be unrequested.
+ *
+ * The unrequested device, described by the provided id_table, is at first
+ * removed from the IDR @scmi_requested_devices and then the removal is
+ * advertised to any registered party via the @scmi_requested_devices_nh
+ * notification chain.
+ */
+static void scmi_protocol_device_unrequest(const struct scmi_device_id *id_table)
+{
+ struct list_head *phead;
+
+ pr_debug("Unrequesting SCMI device (%s) for protocol %x\n",
+ id_table->name, id_table->protocol_id);
+
+ mutex_lock(&scmi_requested_devices_mtx);
+ phead = idr_find(&scmi_requested_devices, id_table->protocol_id);
+ if (phead) {
+ struct scmi_requested_dev *victim, *tmp;
+
+ list_for_each_entry_safe(victim, tmp, phead, node) {
+ if (!strcmp(victim->id_table->name, id_table->name)) {
+ list_del(&victim->node);
+
+ mutex_unlock(&scmi_requested_devices_mtx);
+ blocking_notifier_call_chain(&scmi_requested_devices_nh,
+ SCMI_BUS_NOTIFY_DEVICE_UNREQUEST,
+ (void *)victim->id_table);
+ kfree(victim);
+ mutex_lock(&scmi_requested_devices_mtx);
+ break;
+ }
+ }
+
+ if (list_empty(phead)) {
+ idr_remove(&scmi_requested_devices,
+ id_table->protocol_id);
+ kfree(phead);
+ }
+ }
+ mutex_unlock(&scmi_requested_devices_mtx);
+}
static const struct scmi_device_id *
scmi_dev_match_id(struct scmi_device *scmi_dev, struct scmi_driver *scmi_drv)
@@ -57,11 +225,11 @@ static int scmi_match_by_id_table(struct device *dev, void *data)
struct scmi_device_id *id_table = data;
return sdev->protocol_id == id_table->protocol_id &&
- !strcmp(sdev->name, id_table->name);
+ (id_table->name && !strcmp(sdev->name, id_table->name));
}
-struct scmi_device *scmi_child_dev_find(struct device *parent,
- int prot_id, const char *name)
+static struct scmi_device *scmi_child_dev_find(struct device *parent,
+ int prot_id, const char *name)
{
struct scmi_device_id id_table;
struct device *dev;
@@ -76,30 +244,6 @@ struct scmi_device *scmi_child_dev_find(struct device *parent,
return to_scmi_dev(dev);
}
-const struct scmi_protocol *scmi_protocol_get(int protocol_id)
-{
- const struct scmi_protocol *proto;
-
- proto = idr_find(&scmi_protocols, protocol_id);
- if (!proto || !try_module_get(proto->owner)) {
- pr_warn("SCMI Protocol 0x%x not found!\n", protocol_id);
- return NULL;
- }
-
- pr_debug("Found SCMI Protocol 0x%x\n", protocol_id);
-
- return proto;
-}
-
-void scmi_protocol_put(int protocol_id)
-{
- const struct scmi_protocol *proto;
-
- proto = idr_find(&scmi_protocols, protocol_id);
- if (proto)
- module_put(proto->owner);
-}
-
static int scmi_dev_probe(struct device *dev)
{
struct scmi_driver *scmi_drv = to_scmi_driver(dev->driver);
@@ -120,12 +264,13 @@ static void scmi_dev_remove(struct device *dev)
scmi_drv->remove(scmi_dev);
}
-static struct bus_type scmi_bus_type = {
+struct bus_type scmi_bus_type = {
.name = "scmi_protocol",
.match = scmi_dev_match,
.probe = scmi_dev_probe,
.remove = scmi_dev_remove,
};
+EXPORT_SYMBOL_GPL(scmi_bus_type);
int scmi_driver_register(struct scmi_driver *driver, struct module *owner,
const char *mod_name)
@@ -146,7 +291,7 @@ int scmi_driver_register(struct scmi_driver *driver, struct module *owner,
retval = driver_register(&driver->driver);
if (!retval)
- pr_debug("registered new scmi driver %s\n", driver->name);
+ pr_debug("Registered new scmi driver %s\n", driver->name);
return retval;
}
@@ -164,13 +309,53 @@ static void scmi_device_release(struct device *dev)
kfree(to_scmi_dev(dev));
}
-struct scmi_device *
-scmi_device_create(struct device_node *np, struct device *parent, int protocol,
- const char *name)
+static void __scmi_device_destroy(struct scmi_device *scmi_dev)
+{
+ pr_debug("(%s) Destroying SCMI device '%s' for protocol 0x%x (%s)\n",
+ of_node_full_name(scmi_dev->dev.parent->of_node),
+ dev_name(&scmi_dev->dev), scmi_dev->protocol_id,
+ scmi_dev->name);
+
+ if (scmi_dev->protocol_id == SCMI_PROTOCOL_SYSTEM)
+ atomic_set(&scmi_syspower_registered, 0);
+
+ kfree_const(scmi_dev->name);
+ ida_free(&scmi_bus_id, scmi_dev->id);
+ device_unregister(&scmi_dev->dev);
+}
+
+static struct scmi_device *
+__scmi_device_create(struct device_node *np, struct device *parent,
+ int protocol, const char *name)
{
int id, retval;
struct scmi_device *scmi_dev;
+ /*
+ * If the same protocol/name device already exist under the same parent
+ * (i.e. SCMI instance) just return the existent device.
+ * This avoids any race between the SCMI driver, creating devices for
+ * each DT defined protocol at probe time, and the concurrent
+ * registration of SCMI drivers.
+ */
+ scmi_dev = scmi_child_dev_find(parent, protocol, name);
+ if (scmi_dev)
+ return scmi_dev;
+
+ /*
+ * Ignore any possible subsequent failures while creating the device
+ * since we are doomed anyway at that point; not using a mutex which
+ * spans across this whole function to keep things simple and to avoid
+ * to serialize all the __scmi_device_create calls across possibly
+ * different SCMI server instances (parent)
+ */
+ if (protocol == SCMI_PROTOCOL_SYSTEM &&
+ atomic_cmpxchg(&scmi_syspower_registered, 0, 1)) {
+ dev_warn(parent,
+ "SCMI SystemPower protocol device must be unique !\n");
+ return NULL;
+ }
+
scmi_dev = kzalloc(sizeof(*scmi_dev), GFP_KERNEL);
if (!scmi_dev)
return NULL;
@@ -191,7 +376,7 @@ scmi_device_create(struct device_node *np, struct device *parent, int protocol,
scmi_dev->id = id;
scmi_dev->protocol_id = protocol;
scmi_dev->dev.parent = parent;
- scmi_dev->dev.of_node = np;
+ device_set_node(&scmi_dev->dev, of_fwnode_handle(np));
scmi_dev->dev.bus = &scmi_bus_type;
scmi_dev->dev.release = scmi_device_release;
dev_set_name(&scmi_dev->dev, "scmi_dev.%d", id);
@@ -200,6 +385,10 @@ scmi_device_create(struct device_node *np, struct device *parent, int protocol,
if (retval)
goto put_dev;
+ pr_debug("(%s) Created SCMI device '%s' for protocol 0x%x (%s)\n",
+ of_node_full_name(parent->of_node),
+ dev_name(&scmi_dev->dev), protocol, name);
+
return scmi_dev;
put_dev:
kfree_const(scmi_dev->name);
@@ -208,77 +397,85 @@ put_dev:
return NULL;
}
-void scmi_device_destroy(struct scmi_device *scmi_dev)
-{
- kfree_const(scmi_dev->name);
- scmi_handle_put(scmi_dev->handle);
- ida_free(&scmi_bus_id, scmi_dev->id);
- device_unregister(&scmi_dev->dev);
-}
-
-void scmi_device_link_add(struct device *consumer, struct device *supplier)
-{
- struct device_link *link;
-
- link = device_link_add(consumer, supplier, DL_FLAG_AUTOREMOVE_CONSUMER);
-
- WARN_ON(!link);
-}
-
-void scmi_set_handle(struct scmi_device *scmi_dev)
-{
- scmi_dev->handle = scmi_handle_get(&scmi_dev->dev);
- if (scmi_dev->handle)
- scmi_device_link_add(&scmi_dev->dev, scmi_dev->handle->dev);
-}
-
-int scmi_protocol_register(const struct scmi_protocol *proto)
+/**
+ * scmi_device_create - A method to create one or more SCMI devices
+ *
+ * @np: A reference to the device node to use for the new device(s)
+ * @parent: The parent device to use identifying a specific SCMI instance
+ * @protocol: The SCMI protocol to be associated with this device
+ * @name: The requested-name of the device to be created; this is optional
+ * and if no @name is provided, all the devices currently known to
+ * be requested on the SCMI bus for @protocol will be created.
+ *
+ * This method can be invoked to create a single well-defined device (like
+ * a transport device or a device requested by an SCMI driver loaded after
+ * the core SCMI stack has been probed), or to create all the devices currently
+ * known to have been requested by the loaded SCMI drivers for a specific
+ * protocol (typically during SCMI core protocol enumeration at probe time).
+ *
+ * Return: The created device (or one of them if @name was NOT provided and
+ * multiple devices were created) or NULL if no device was created;
+ * note that NULL indicates an error ONLY in case a specific @name
+ * was provided: when @name param was not provided, a number of devices
+ * could have been potentially created for a whole protocol, unless no
+ * device was found to have been requested for that specific protocol.
+ */
+struct scmi_device *scmi_device_create(struct device_node *np,
+ struct device *parent, int protocol,
+ const char *name)
{
- int ret;
-
- if (!proto) {
- pr_err("invalid protocol\n");
- return -EINVAL;
- }
-
- if (!proto->instance_init) {
- pr_err("missing init for protocol 0x%x\n", proto->id);
- return -EINVAL;
+ struct list_head *phead;
+ struct scmi_requested_dev *rdev;
+ struct scmi_device *scmi_dev = NULL;
+
+ if (name)
+ return __scmi_device_create(np, parent, protocol, name);
+
+ mutex_lock(&scmi_requested_devices_mtx);
+ phead = idr_find(&scmi_requested_devices, protocol);
+ /* Nothing to do. */
+ if (!phead) {
+ mutex_unlock(&scmi_requested_devices_mtx);
+ return scmi_dev;
}
- spin_lock(&protocol_lock);
- ret = idr_alloc(&scmi_protocols, (void *)proto,
- proto->id, proto->id + 1, GFP_ATOMIC);
- spin_unlock(&protocol_lock);
- if (ret != proto->id) {
- pr_err("unable to allocate SCMI idr slot for 0x%x - err %d\n",
- proto->id, ret);
- return ret;
+ /* Walk the list of requested devices for protocol and create them */
+ list_for_each_entry(rdev, phead, node) {
+ struct scmi_device *sdev;
+
+ sdev = __scmi_device_create(np, parent,
+ rdev->id_table->protocol_id,
+ rdev->id_table->name);
+ /* Report errors and carry on... */
+ if (sdev)
+ scmi_dev = sdev;
+ else
+ pr_err("(%s) Failed to create device for protocol 0x%x (%s)\n",
+ of_node_full_name(parent->of_node),
+ rdev->id_table->protocol_id,
+ rdev->id_table->name);
}
+ mutex_unlock(&scmi_requested_devices_mtx);
- pr_debug("Registered SCMI Protocol 0x%x\n", proto->id);
-
- return 0;
+ return scmi_dev;
}
-EXPORT_SYMBOL_GPL(scmi_protocol_register);
+EXPORT_SYMBOL_GPL(scmi_device_create);
-void scmi_protocol_unregister(const struct scmi_protocol *proto)
+void scmi_device_destroy(struct device *parent, int protocol, const char *name)
{
- spin_lock(&protocol_lock);
- idr_remove(&scmi_protocols, proto->id);
- spin_unlock(&protocol_lock);
-
- pr_debug("Unregistered SCMI Protocol 0x%x\n", proto->id);
+ struct scmi_device *scmi_dev;
- return;
+ scmi_dev = scmi_child_dev_find(parent, protocol, name);
+ if (scmi_dev)
+ __scmi_device_destroy(scmi_dev);
}
-EXPORT_SYMBOL_GPL(scmi_protocol_unregister);
+EXPORT_SYMBOL_GPL(scmi_device_destroy);
static int __scmi_devices_unregister(struct device *dev, void *data)
{
struct scmi_device *scmi_dev = to_scmi_dev(dev);
- scmi_device_destroy(scmi_dev);
+ __scmi_device_destroy(scmi_dev);
return 0;
}
@@ -287,20 +484,33 @@ static void scmi_devices_unregister(void)
bus_for_each_dev(&scmi_bus_type, NULL, NULL, __scmi_devices_unregister);
}
-int __init scmi_bus_init(void)
+static int __init scmi_bus_init(void)
{
int retval;
retval = bus_register(&scmi_bus_type);
if (retval)
- pr_err("scmi protocol bus register failed (%d)\n", retval);
+ pr_err("SCMI protocol bus register failed (%d)\n", retval);
+
+ pr_info("SCMI protocol bus registered\n");
return retval;
}
+subsys_initcall(scmi_bus_init);
-void __exit scmi_bus_exit(void)
+static void __exit scmi_bus_exit(void)
{
+ /*
+ * Destroy all remaining devices: just in case the drivers were
+ * manually unbound and at first and then the modules unloaded.
+ */
scmi_devices_unregister();
bus_unregister(&scmi_bus_type);
ida_destroy(&scmi_bus_id);
}
+module_exit(scmi_bus_exit);
+
+MODULE_ALIAS("scmi-core");
+MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
+MODULE_DESCRIPTION("ARM SCMI protocol bus");
+MODULE_LICENSE("GPL");
diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h
index a1c0154c31c6..c46dc5215af7 100644
--- a/drivers/firmware/arm_scmi/common.h
+++ b/drivers/firmware/arm_scmi/common.h
@@ -27,6 +27,48 @@
#include "protocols.h"
#include "notify.h"
+#define SCMI_MAX_CHANNELS 256
+
+#define SCMI_MAX_RESPONSE_TIMEOUT (2 * MSEC_PER_SEC)
+
+enum scmi_error_codes {
+ SCMI_SUCCESS = 0, /* Success */
+ SCMI_ERR_SUPPORT = -1, /* Not supported */
+ SCMI_ERR_PARAMS = -2, /* Invalid Parameters */
+ SCMI_ERR_ACCESS = -3, /* Invalid access/permission denied */
+ SCMI_ERR_ENTRY = -4, /* Not found */
+ SCMI_ERR_RANGE = -5, /* Value out of range */
+ SCMI_ERR_BUSY = -6, /* Device busy */
+ SCMI_ERR_COMMS = -7, /* Communication Error */
+ SCMI_ERR_GENERIC = -8, /* Generic Error */
+ SCMI_ERR_HARDWARE = -9, /* Hardware Error */
+ SCMI_ERR_PROTOCOL = -10,/* Protocol Error */
+};
+
+static const int scmi_linux_errmap[] = {
+ /* better than switch case as long as return value is continuous */
+ 0, /* SCMI_SUCCESS */
+ -EOPNOTSUPP, /* SCMI_ERR_SUPPORT */
+ -EINVAL, /* SCMI_ERR_PARAM */
+ -EACCES, /* SCMI_ERR_ACCESS */
+ -ENOENT, /* SCMI_ERR_ENTRY */
+ -ERANGE, /* SCMI_ERR_RANGE */
+ -EBUSY, /* SCMI_ERR_BUSY */
+ -ECOMM, /* SCMI_ERR_COMMS */
+ -EIO, /* SCMI_ERR_GENERIC */
+ -EREMOTEIO, /* SCMI_ERR_HARDWARE */
+ -EPROTO, /* SCMI_ERR_PROTOCOL */
+};
+
+static inline int scmi_to_linux_errno(int errno)
+{
+ int err_idx = -errno;
+
+ if (err_idx >= SCMI_SUCCESS && err_idx < ARRAY_SIZE(scmi_linux_errmap))
+ return scmi_linux_errmap[err_idx];
+ return -EIO;
+}
+
#define MSG_ID_MASK GENMASK(7, 0)
#define MSG_XTRACT_ID(hdr) FIELD_GET(MSG_ID_MASK, (hdr))
#define MSG_TYPE_MASK GENMASK(9, 8)
@@ -96,18 +138,19 @@ static inline void unpack_scmi_header(u32 msg_hdr, struct scmi_msg_hdr *hdr)
struct scmi_revision_info *
scmi_revision_area_get(const struct scmi_protocol_handle *ph);
-int scmi_handle_put(const struct scmi_handle *handle);
-void scmi_device_link_add(struct device *consumer, struct device *supplier);
-struct scmi_handle *scmi_handle_get(struct device *dev);
-void scmi_set_handle(struct scmi_device *scmi_dev);
void scmi_setup_protocol_implemented(const struct scmi_protocol_handle *ph,
u8 *prot_imp);
-int __init scmi_bus_init(void);
-void __exit scmi_bus_exit(void);
+extern struct bus_type scmi_bus_type;
+
+#define SCMI_BUS_NOTIFY_DEVICE_REQUEST 0
+#define SCMI_BUS_NOTIFY_DEVICE_UNREQUEST 1
+extern struct blocking_notifier_head scmi_requested_devices_nh;
-const struct scmi_protocol *scmi_protocol_get(int protocol_id);
-void scmi_protocol_put(int protocol_id);
+struct scmi_device *scmi_device_create(struct device_node *np,
+ struct device *parent, int protocol,
+ const char *name);
+void scmi_device_destroy(struct device *parent, int protocol, const char *name);
int scmi_protocol_acquire(const struct scmi_handle *handle, u8 protocol_id);
void scmi_protocol_release(const struct scmi_handle *handle, u8 protocol_id);
@@ -116,6 +159,8 @@ void scmi_protocol_release(const struct scmi_handle *handle, u8 protocol_id);
/**
* struct scmi_chan_info - Structure representing a SCMI channel information
*
+ * @id: An identifier for this channel: this matches the protocol number
+ * used to initialize this channel
* @dev: Reference to device in the SCMI hierarchy corresponding to this
* channel
* @rx_timeout_ms: The configured RX timeout in milliseconds.
@@ -127,6 +172,7 @@ void scmi_protocol_release(const struct scmi_handle *handle, u8 protocol_id);
* @transport_info: Transport layer related information
*/
struct scmi_chan_info {
+ int id;
struct device *dev;
unsigned int rx_timeout_ms;
struct scmi_handle *handle;
@@ -153,7 +199,7 @@ struct scmi_chan_info {
*/
struct scmi_transport_ops {
int (*link_supplier)(struct device *dev);
- bool (*chan_available)(struct device *dev, int idx);
+ bool (*chan_available)(struct device_node *of_node, int idx);
int (*chan_setup)(struct scmi_chan_info *cinfo, struct device *dev,
bool tx);
int (*chan_free)(int id, void *p, void *data);
@@ -170,11 +216,6 @@ struct scmi_transport_ops {
bool (*poll_done)(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer);
};
-int scmi_protocol_device_request(const struct scmi_device_id *id_table);
-void scmi_protocol_device_unrequest(const struct scmi_device_id *id_table);
-struct scmi_device *scmi_child_dev_find(struct device *parent,
- int prot_id, const char *name);
-
/**
* struct scmi_desc - Description of SoC integration
*
@@ -215,6 +256,36 @@ struct scmi_desc {
const bool atomic_enabled;
};
+static inline bool is_polling_required(struct scmi_chan_info *cinfo,
+ const struct scmi_desc *desc)
+{
+ return cinfo->no_completion_irq || desc->force_polling;
+}
+
+static inline bool is_transport_polling_capable(const struct scmi_desc *desc)
+{
+ return desc->ops->poll_done || desc->sync_cmds_completed_on_ret;
+}
+
+static inline bool is_polling_enabled(struct scmi_chan_info *cinfo,
+ const struct scmi_desc *desc)
+{
+ return is_polling_required(cinfo, desc) &&
+ is_transport_polling_capable(desc);
+}
+
+void scmi_xfer_raw_put(const struct scmi_handle *handle,
+ struct scmi_xfer *xfer);
+struct scmi_xfer *scmi_xfer_raw_get(const struct scmi_handle *handle);
+struct scmi_chan_info *
+scmi_xfer_raw_channel_get(const struct scmi_handle *handle, u8 protocol_id);
+
+int scmi_xfer_raw_inflight_register(const struct scmi_handle *handle,
+ struct scmi_xfer *xfer);
+
+int scmi_xfer_raw_wait_for_message_response(struct scmi_chan_info *cinfo,
+ struct scmi_xfer *xfer,
+ unsigned int timeout_ms);
#ifdef CONFIG_ARM_SCMI_TRANSPORT_MAILBOX
extern const struct scmi_desc scmi_mailbox_desc;
#endif
@@ -229,7 +300,6 @@ extern const struct scmi_desc scmi_optee_desc;
#endif
void scmi_rx_callback(struct scmi_chan_info *cinfo, u32 msg_hdr, void *priv);
-void scmi_free_channel(struct scmi_chan_info *cinfo, struct idr *idr, int id);
/* shmem related declarations */
struct scmi_shared_mem;
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index ffdad59ec81f..d21c7eafd641 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -14,7 +14,10 @@
* Copyright (C) 2018-2021 ARM Ltd.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/bitmap.h>
+#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/export.h>
#include <linux/idr.h>
@@ -34,22 +37,15 @@
#include "common.h"
#include "notify.h"
+#include "raw_mode.h"
+
#define CREATE_TRACE_POINTS
#include <trace/events/scmi.h>
-enum scmi_error_codes {
- SCMI_SUCCESS = 0, /* Success */
- SCMI_ERR_SUPPORT = -1, /* Not supported */
- SCMI_ERR_PARAMS = -2, /* Invalid Parameters */
- SCMI_ERR_ACCESS = -3, /* Invalid access/permission denied */
- SCMI_ERR_ENTRY = -4, /* Not found */
- SCMI_ERR_RANGE = -5, /* Value out of range */
- SCMI_ERR_BUSY = -6, /* Device busy */
- SCMI_ERR_COMMS = -7, /* Communication Error */
- SCMI_ERR_GENERIC = -8, /* Generic Error */
- SCMI_ERR_HARDWARE = -9, /* Hardware Error */
- SCMI_ERR_PROTOCOL = -10,/* Protocol Error */
-};
+static DEFINE_IDA(scmi_id);
+
+static DEFINE_IDR(scmi_protocols);
+static DEFINE_SPINLOCK(protocol_lock);
/* List of all SCMI devices active in system */
static LIST_HEAD(scmi_list);
@@ -58,18 +54,7 @@ static DEFINE_MUTEX(scmi_list_mutex);
/* Track the unique id for the transfers for debug & profiling purpose */
static atomic_t transfer_last_id;
-static DEFINE_IDR(scmi_requested_devices);
-static DEFINE_MUTEX(scmi_requested_devices_mtx);
-
-/* Track globally the creation of SCMI SystemPower related devices */
-static bool scmi_syspower_registered;
-/* Protect access to scmi_syspower_registered */
-static DEFINE_MUTEX(scmi_syspower_mtx);
-
-struct scmi_requested_dev {
- const struct scmi_device_id *id_table;
- struct list_head node;
-};
+static struct dentry *scmi_top_dentry;
/**
* struct scmi_xfers_info - Structure to manage transfer information
@@ -118,8 +103,23 @@ struct scmi_protocol_instance {
#define ph_to_pi(h) container_of(h, struct scmi_protocol_instance, ph)
/**
+ * struct scmi_debug_info - Debug common info
+ * @top_dentry: A reference to the top debugfs dentry
+ * @name: Name of this SCMI instance
+ * @type: Type of this SCMI instance
+ * @is_atomic: Flag to state if the transport of this instance is atomic
+ */
+struct scmi_debug_info {
+ struct dentry *top_dentry;
+ const char *name;
+ const char *type;
+ bool is_atomic;
+};
+
+/**
* struct scmi_info - Structure representing a SCMI instance
*
+ * @id: A sequence number starting from zero identifying this instance
* @dev: Device pointer
* @desc: SoC description for this instance
* @version: SCMI revision information containing protocol version,
@@ -147,8 +147,15 @@ struct scmi_protocol_instance {
* @notify_priv: Pointer to private data structure specific to notifications.
* @node: List head
* @users: Number of users of this instance
+ * @bus_nb: A notifier to listen for device bind/unbind on the scmi bus
+ * @dev_req_nb: A notifier to listen for device request/unrequest on the scmi
+ * bus
+ * @devreq_mtx: A mutex to serialize device creation for this SCMI instance
+ * @dbg: A pointer to debugfs related data (if any)
+ * @raw: An opaque reference handle used by SCMI Raw mode.
*/
struct scmi_info {
+ int id;
struct device *dev;
const struct scmi_desc *desc;
struct scmi_revision_info version;
@@ -166,32 +173,114 @@ struct scmi_info {
void *notify_priv;
struct list_head node;
int users;
+ struct notifier_block bus_nb;
+ struct notifier_block dev_req_nb;
+ /* Serialize device creation process for this instance */
+ struct mutex devreq_mtx;
+ struct scmi_debug_info *dbg;
+ void *raw;
};
#define handle_to_scmi_info(h) container_of(h, struct scmi_info, handle)
+#define bus_nb_to_scmi_info(nb) container_of(nb, struct scmi_info, bus_nb)
+#define req_nb_to_scmi_info(nb) container_of(nb, struct scmi_info, dev_req_nb)
-static const int scmi_linux_errmap[] = {
- /* better than switch case as long as return value is continuous */
- 0, /* SCMI_SUCCESS */
- -EOPNOTSUPP, /* SCMI_ERR_SUPPORT */
- -EINVAL, /* SCMI_ERR_PARAM */
- -EACCES, /* SCMI_ERR_ACCESS */
- -ENOENT, /* SCMI_ERR_ENTRY */
- -ERANGE, /* SCMI_ERR_RANGE */
- -EBUSY, /* SCMI_ERR_BUSY */
- -ECOMM, /* SCMI_ERR_COMMS */
- -EIO, /* SCMI_ERR_GENERIC */
- -EREMOTEIO, /* SCMI_ERR_HARDWARE */
- -EPROTO, /* SCMI_ERR_PROTOCOL */
-};
+static const struct scmi_protocol *scmi_protocol_get(int protocol_id)
+{
+ const struct scmi_protocol *proto;
+
+ proto = idr_find(&scmi_protocols, protocol_id);
+ if (!proto || !try_module_get(proto->owner)) {
+ pr_warn("SCMI Protocol 0x%x not found!\n", protocol_id);
+ return NULL;
+ }
+
+ pr_debug("Found SCMI Protocol 0x%x\n", protocol_id);
+
+ return proto;
+}
+
+static void scmi_protocol_put(int protocol_id)
+{
+ const struct scmi_protocol *proto;
+
+ proto = idr_find(&scmi_protocols, protocol_id);
+ if (proto)
+ module_put(proto->owner);
+}
+
+int scmi_protocol_register(const struct scmi_protocol *proto)
+{
+ int ret;
+
+ if (!proto) {
+ pr_err("invalid protocol\n");
+ return -EINVAL;
+ }
+
+ if (!proto->instance_init) {
+ pr_err("missing init for protocol 0x%x\n", proto->id);
+ return -EINVAL;
+ }
+
+ spin_lock(&protocol_lock);
+ ret = idr_alloc(&scmi_protocols, (void *)proto,
+ proto->id, proto->id + 1, GFP_ATOMIC);
+ spin_unlock(&protocol_lock);
+ if (ret != proto->id) {
+ pr_err("unable to allocate SCMI idr slot for 0x%x - err %d\n",
+ proto->id, ret);
+ return ret;
+ }
+
+ pr_debug("Registered SCMI Protocol 0x%x\n", proto->id);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(scmi_protocol_register);
+
+void scmi_protocol_unregister(const struct scmi_protocol *proto)
+{
+ spin_lock(&protocol_lock);
+ idr_remove(&scmi_protocols, proto->id);
+ spin_unlock(&protocol_lock);
-static inline int scmi_to_linux_errno(int errno)
+ pr_debug("Unregistered SCMI Protocol 0x%x\n", proto->id);
+}
+EXPORT_SYMBOL_GPL(scmi_protocol_unregister);
+
+/**
+ * scmi_create_protocol_devices - Create devices for all pending requests for
+ * this SCMI instance.
+ *
+ * @np: The device node describing the protocol
+ * @info: The SCMI instance descriptor
+ * @prot_id: The protocol ID
+ * @name: The optional name of the device to be created: if not provided this
+ * call will lead to the creation of all the devices currently requested
+ * for the specified protocol.
+ */
+static void scmi_create_protocol_devices(struct device_node *np,
+ struct scmi_info *info,
+ int prot_id, const char *name)
{
- int err_idx = -errno;
+ struct scmi_device *sdev;
- if (err_idx >= SCMI_SUCCESS && err_idx < ARRAY_SIZE(scmi_linux_errmap))
- return scmi_linux_errmap[err_idx];
- return -EIO;
+ mutex_lock(&info->devreq_mtx);
+ sdev = scmi_device_create(np, info->dev, prot_id, name);
+ if (name && !sdev)
+ dev_err(info->dev,
+ "failed to create device for protocol 0x%X (%s)\n",
+ prot_id, name);
+ mutex_unlock(&info->devreq_mtx);
+}
+
+static void scmi_destroy_protocol_devices(struct scmi_info *info,
+ int prot_id, const char *name)
+{
+ mutex_lock(&info->devreq_mtx);
+ scmi_device_destroy(info->dev, prot_id, name);
+ mutex_unlock(&info->devreq_mtx);
}
void scmi_notification_instance_data_set(const struct scmi_handle *handle,
@@ -311,8 +400,6 @@ static int scmi_xfer_token_set(struct scmi_xfers_info *minfo,
if (xfer_id != next_token)
atomic_add((int)(xfer_id - next_token), &transfer_last_id);
- /* Set in-flight */
- set_bit(xfer_id, minfo->xfer_alloc_table);
xfer->hdr.seq = (u16)xfer_id;
return 0;
@@ -331,32 +418,123 @@ static inline void scmi_xfer_token_clear(struct scmi_xfers_info *minfo,
}
/**
+ * scmi_xfer_inflight_register_unlocked - Register the xfer as in-flight
+ *
+ * @xfer: The xfer to register
+ * @minfo: Pointer to Tx/Rx Message management info based on channel type
+ *
+ * Note that this helper assumes that the xfer to be registered as in-flight
+ * had been built using an xfer sequence number which still corresponds to a
+ * free slot in the xfer_alloc_table.
+ *
+ * Context: Assumes to be called with @xfer_lock already acquired.
+ */
+static inline void
+scmi_xfer_inflight_register_unlocked(struct scmi_xfer *xfer,
+ struct scmi_xfers_info *minfo)
+{
+ /* Set in-flight */
+ set_bit(xfer->hdr.seq, minfo->xfer_alloc_table);
+ hash_add(minfo->pending_xfers, &xfer->node, xfer->hdr.seq);
+ xfer->pending = true;
+}
+
+/**
+ * scmi_xfer_inflight_register - Try to register an xfer as in-flight
+ *
+ * @xfer: The xfer to register
+ * @minfo: Pointer to Tx/Rx Message management info based on channel type
+ *
+ * Note that this helper does NOT assume anything about the sequence number
+ * that was baked into the provided xfer, so it checks at first if it can
+ * be mapped to a free slot and fails with an error if another xfer with the
+ * same sequence number is currently still registered as in-flight.
+ *
+ * Return: 0 on Success or -EBUSY if sequence number embedded in the xfer
+ * could not rbe mapped to a free slot in the xfer_alloc_table.
+ */
+static int scmi_xfer_inflight_register(struct scmi_xfer *xfer,
+ struct scmi_xfers_info *minfo)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&minfo->xfer_lock, flags);
+ if (!test_bit(xfer->hdr.seq, minfo->xfer_alloc_table))
+ scmi_xfer_inflight_register_unlocked(xfer, minfo);
+ else
+ ret = -EBUSY;
+ spin_unlock_irqrestore(&minfo->xfer_lock, flags);
+
+ return ret;
+}
+
+/**
+ * scmi_xfer_raw_inflight_register - An helper to register the given xfer as in
+ * flight on the TX channel, if possible.
+ *
+ * @handle: Pointer to SCMI entity handle
+ * @xfer: The xfer to register
+ *
+ * Return: 0 on Success, error otherwise
+ */
+int scmi_xfer_raw_inflight_register(const struct scmi_handle *handle,
+ struct scmi_xfer *xfer)
+{
+ struct scmi_info *info = handle_to_scmi_info(handle);
+
+ return scmi_xfer_inflight_register(xfer, &info->tx_minfo);
+}
+
+/**
+ * scmi_xfer_pending_set - Pick a proper sequence number and mark the xfer
+ * as pending in-flight
+ *
+ * @xfer: The xfer to act upon
+ * @minfo: Pointer to Tx/Rx Message management info based on channel type
+ *
+ * Return: 0 on Success or error otherwise
+ */
+static inline int scmi_xfer_pending_set(struct scmi_xfer *xfer,
+ struct scmi_xfers_info *minfo)
+{
+ int ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&minfo->xfer_lock, flags);
+ /* Set a new monotonic token as the xfer sequence number */
+ ret = scmi_xfer_token_set(minfo, xfer);
+ if (!ret)
+ scmi_xfer_inflight_register_unlocked(xfer, minfo);
+ spin_unlock_irqrestore(&minfo->xfer_lock, flags);
+
+ return ret;
+}
+
+/**
* scmi_xfer_get() - Allocate one message
*
* @handle: Pointer to SCMI entity handle
* @minfo: Pointer to Tx/Rx Message management info based on channel type
- * @set_pending: If true a monotonic token is picked and the xfer is added to
- * the pending hash table.
*
* Helper function which is used by various message functions that are
* exposed to clients of this driver for allocating a message traffic event.
*
- * Picks an xfer from the free list @free_xfers (if any available) and, if
- * required, sets a monotonically increasing token and stores the inflight xfer
- * into the @pending_xfers hashtable for later retrieval.
+ * Picks an xfer from the free list @free_xfers (if any available) and perform
+ * a basic initialization.
+ *
+ * Note that, at this point, still no sequence number is assigned to the
+ * allocated xfer, nor it is registered as a pending transaction.
*
* The successfully initialized xfer is refcounted.
*
- * Context: Holds @xfer_lock while manipulating @xfer_alloc_table and
- * @free_xfers.
+ * Context: Holds @xfer_lock while manipulating @free_xfers.
*
- * Return: 0 if all went fine, else corresponding error.
+ * Return: An initialized xfer if all went fine, else pointer error.
*/
static struct scmi_xfer *scmi_xfer_get(const struct scmi_handle *handle,
- struct scmi_xfers_info *minfo,
- bool set_pending)
+ struct scmi_xfers_info *minfo)
{
- int ret;
unsigned long flags;
struct scmi_xfer *xfer;
@@ -376,31 +554,71 @@ static struct scmi_xfer *scmi_xfer_get(const struct scmi_handle *handle,
*/
xfer->transfer_id = atomic_inc_return(&transfer_last_id);
- if (set_pending) {
- /* Pick and set monotonic token */
- ret = scmi_xfer_token_set(minfo, xfer);
- if (!ret) {
- hash_add(minfo->pending_xfers, &xfer->node,
- xfer->hdr.seq);
- xfer->pending = true;
- } else {
- dev_err(handle->dev,
- "Failed to get monotonic token %d\n", ret);
- hlist_add_head(&xfer->node, &minfo->free_xfers);
- xfer = ERR_PTR(ret);
- }
- }
-
- if (!IS_ERR(xfer)) {
- refcount_set(&xfer->users, 1);
- atomic_set(&xfer->busy, SCMI_XFER_FREE);
- }
+ refcount_set(&xfer->users, 1);
+ atomic_set(&xfer->busy, SCMI_XFER_FREE);
spin_unlock_irqrestore(&minfo->xfer_lock, flags);
return xfer;
}
/**
+ * scmi_xfer_raw_get - Helper to get a bare free xfer from the TX channel
+ *
+ * @handle: Pointer to SCMI entity handle
+ *
+ * Note that xfer is taken from the TX channel structures.
+ *
+ * Return: A valid xfer on Success, or an error-pointer otherwise
+ */
+struct scmi_xfer *scmi_xfer_raw_get(const struct scmi_handle *handle)
+{
+ struct scmi_xfer *xfer;
+ struct scmi_info *info = handle_to_scmi_info(handle);
+
+ xfer = scmi_xfer_get(handle, &info->tx_minfo);
+ if (!IS_ERR(xfer))
+ xfer->flags |= SCMI_XFER_FLAG_IS_RAW;
+
+ return xfer;
+}
+
+/**
+ * scmi_xfer_raw_channel_get - Helper to get a reference to the proper channel
+ * to use for a specific protocol_id Raw transaction.
+ *
+ * @handle: Pointer to SCMI entity handle
+ * @protocol_id: Identifier of the protocol
+ *
+ * Note that in a regular SCMI stack, usually, a protocol has to be defined in
+ * the DT to have an associated channel and be usable; but in Raw mode any
+ * protocol in range is allowed, re-using the Base channel, so as to enable
+ * fuzzing on any protocol without the need of a fully compiled DT.
+ *
+ * Return: A reference to the channel to use, or an ERR_PTR
+ */
+struct scmi_chan_info *
+scmi_xfer_raw_channel_get(const struct scmi_handle *handle, u8 protocol_id)
+{
+ struct scmi_chan_info *cinfo;
+ struct scmi_info *info = handle_to_scmi_info(handle);
+
+ cinfo = idr_find(&info->tx_idr, protocol_id);
+ if (!cinfo) {
+ if (protocol_id == SCMI_PROTOCOL_BASE)
+ return ERR_PTR(-EINVAL);
+ /* Use Base channel for protocols not defined for DT */
+ cinfo = idr_find(&info->tx_idr, SCMI_PROTOCOL_BASE);
+ if (!cinfo)
+ return ERR_PTR(-EINVAL);
+ dev_warn_once(handle->dev,
+ "Using Base channel for protocol 0x%X\n",
+ protocol_id);
+ }
+
+ return cinfo;
+}
+
+/**
* __scmi_xfer_put() - Release a message
*
* @minfo: Pointer to Tx/Rx Message management info based on channel type
@@ -429,6 +647,24 @@ __scmi_xfer_put(struct scmi_xfers_info *minfo, struct scmi_xfer *xfer)
}
/**
+ * scmi_xfer_raw_put - Release an xfer that was taken by @scmi_xfer_raw_get
+ *
+ * @handle: Pointer to SCMI entity handle
+ * @xfer: A reference to the xfer to put
+ *
+ * Note that as with other xfer_put() handlers the xfer is really effectively
+ * released only if there are no more users on the system.
+ */
+void scmi_xfer_raw_put(const struct scmi_handle *handle, struct scmi_xfer *xfer)
+{
+ struct scmi_info *info = handle_to_scmi_info(handle);
+
+ xfer->flags &= ~SCMI_XFER_FLAG_IS_RAW;
+ xfer->flags &= ~SCMI_XFER_FLAG_CHAN_SET;
+ return __scmi_xfer_put(&info->tx_minfo, xfer);
+}
+
+/**
* scmi_xfer_lookup_unlocked - Helper to lookup an xfer_id
*
* @minfo: Pointer to Tx/Rx Message management info based on channel type
@@ -623,25 +859,6 @@ static inline void scmi_clear_channel(struct scmi_info *info,
info->desc->ops->clear_channel(cinfo);
}
-static inline bool is_polling_required(struct scmi_chan_info *cinfo,
- struct scmi_info *info)
-{
- return cinfo->no_completion_irq || info->desc->force_polling;
-}
-
-static inline bool is_transport_polling_capable(struct scmi_info *info)
-{
- return info->desc->ops->poll_done ||
- info->desc->sync_cmds_completed_on_ret;
-}
-
-static inline bool is_polling_enabled(struct scmi_chan_info *cinfo,
- struct scmi_info *info)
-{
- return is_polling_required(cinfo, info) &&
- is_transport_polling_capable(info);
-}
-
static void scmi_handle_notification(struct scmi_chan_info *cinfo,
u32 msg_hdr, void *priv)
{
@@ -652,7 +869,7 @@ static void scmi_handle_notification(struct scmi_chan_info *cinfo,
ktime_t ts;
ts = ktime_get_boottime();
- xfer = scmi_xfer_get(cinfo->handle, minfo, false);
+ xfer = scmi_xfer_get(cinfo->handle, minfo);
if (IS_ERR(xfer)) {
dev_err(dev, "failed to get free message slot (%ld)\n",
PTR_ERR(xfer));
@@ -667,9 +884,9 @@ static void scmi_handle_notification(struct scmi_chan_info *cinfo,
info->desc->ops->fetch_notification(cinfo, info->desc->max_msg_size,
xfer);
- trace_scmi_msg_dump(xfer->hdr.protocol_id, xfer->hdr.id, "NOTI",
- xfer->hdr.seq, xfer->hdr.status,
- xfer->rx.buf, xfer->rx.len);
+ trace_scmi_msg_dump(info->id, cinfo->id, xfer->hdr.protocol_id,
+ xfer->hdr.id, "NOTI", xfer->hdr.seq,
+ xfer->hdr.status, xfer->rx.buf, xfer->rx.len);
scmi_notify(cinfo->handle, xfer->hdr.protocol_id,
xfer->hdr.id, xfer->rx.buf, xfer->rx.len, ts);
@@ -678,6 +895,12 @@ static void scmi_handle_notification(struct scmi_chan_info *cinfo,
xfer->hdr.protocol_id, xfer->hdr.seq,
MSG_TYPE_NOTIFICATION);
+ if (IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT)) {
+ xfer->hdr.seq = MSG_XTRACT_TOKEN(msg_hdr);
+ scmi_raw_message_report(info->raw, xfer, SCMI_RAW_NOTIF_QUEUE,
+ cinfo->id);
+ }
+
__scmi_xfer_put(minfo, xfer);
scmi_clear_channel(info, cinfo);
@@ -691,6 +914,9 @@ static void scmi_handle_response(struct scmi_chan_info *cinfo,
xfer = scmi_xfer_command_acquire(cinfo, msg_hdr);
if (IS_ERR(xfer)) {
+ if (IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT))
+ scmi_raw_error_report(info->raw, cinfo, msg_hdr, priv);
+
if (MSG_XTRACT_TYPE(msg_hdr) == MSG_TYPE_DELAYED_RESP)
scmi_clear_channel(info, cinfo);
return;
@@ -705,9 +931,11 @@ static void scmi_handle_response(struct scmi_chan_info *cinfo,
smp_store_mb(xfer->priv, priv);
info->desc->ops->fetch_response(cinfo, xfer);
- trace_scmi_msg_dump(xfer->hdr.protocol_id, xfer->hdr.id,
+ trace_scmi_msg_dump(info->id, cinfo->id, xfer->hdr.protocol_id,
+ xfer->hdr.id,
xfer->hdr.type == MSG_TYPE_DELAYED_RESP ?
- "DLYD" : "RESP",
+ (!SCMI_XFER_IS_RAW(xfer) ? "DLYD" : "dlyd") :
+ (!SCMI_XFER_IS_RAW(xfer) ? "RESP" : "resp"),
xfer->hdr.seq, xfer->hdr.status,
xfer->rx.buf, xfer->rx.len);
@@ -722,6 +950,18 @@ static void scmi_handle_response(struct scmi_chan_info *cinfo,
complete(&xfer->done);
}
+ if (IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT)) {
+ /*
+ * When in polling mode avoid to queue the Raw xfer on the IRQ
+ * RX path since it will be already queued at the end of the TX
+ * poll loop.
+ */
+ if (!xfer->hdr.poll_completion)
+ scmi_raw_message_report(info->raw, xfer,
+ SCMI_RAW_REPLY_QUEUE,
+ cinfo->id);
+ }
+
scmi_xfer_command_release(info, xfer);
}
@@ -785,36 +1025,18 @@ static bool scmi_xfer_done_no_timeout(struct scmi_chan_info *cinfo,
ktime_after(ktime_get(), stop);
}
-/**
- * scmi_wait_for_message_response - An helper to group all the possible ways of
- * waiting for a synchronous message response.
- *
- * @cinfo: SCMI channel info
- * @xfer: Reference to the transfer being waited for.
- *
- * Chooses waiting strategy (sleep-waiting vs busy-waiting) depending on
- * configuration flags like xfer->hdr.poll_completion.
- *
- * Return: 0 on Success, error otherwise.
- */
-static int scmi_wait_for_message_response(struct scmi_chan_info *cinfo,
- struct scmi_xfer *xfer)
+static int scmi_wait_for_reply(struct device *dev, const struct scmi_desc *desc,
+ struct scmi_chan_info *cinfo,
+ struct scmi_xfer *xfer, unsigned int timeout_ms)
{
- struct scmi_info *info = handle_to_scmi_info(cinfo->handle);
- struct device *dev = info->dev;
- int ret = 0, timeout_ms = info->desc->max_rx_timeout_ms;
-
- trace_scmi_xfer_response_wait(xfer->transfer_id, xfer->hdr.id,
- xfer->hdr.protocol_id, xfer->hdr.seq,
- timeout_ms,
- xfer->hdr.poll_completion);
+ int ret = 0;
if (xfer->hdr.poll_completion) {
/*
* Real polling is needed only if transport has NOT declared
* itself to support synchronous commands replies.
*/
- if (!info->desc->sync_cmds_completed_on_ret) {
+ if (!desc->sync_cmds_completed_on_ret) {
/*
* Poll on xfer using transport provided .poll_done();
* assumes no completion interrupt was available.
@@ -833,6 +1055,8 @@ static int scmi_wait_for_message_response(struct scmi_chan_info *cinfo,
if (!ret) {
unsigned long flags;
+ struct scmi_info *info =
+ handle_to_scmi_info(cinfo->handle);
/*
* Do not fetch_response if an out-of-order delayed
@@ -840,16 +1064,27 @@ static int scmi_wait_for_message_response(struct scmi_chan_info *cinfo,
*/
spin_lock_irqsave(&xfer->lock, flags);
if (xfer->state == SCMI_XFER_SENT_OK) {
- info->desc->ops->fetch_response(cinfo, xfer);
+ desc->ops->fetch_response(cinfo, xfer);
xfer->state = SCMI_XFER_RESP_OK;
}
spin_unlock_irqrestore(&xfer->lock, flags);
/* Trace polled replies. */
- trace_scmi_msg_dump(xfer->hdr.protocol_id, xfer->hdr.id,
- "RESP",
+ trace_scmi_msg_dump(info->id, cinfo->id,
+ xfer->hdr.protocol_id, xfer->hdr.id,
+ !SCMI_XFER_IS_RAW(xfer) ?
+ "RESP" : "resp",
xfer->hdr.seq, xfer->hdr.status,
xfer->rx.buf, xfer->rx.len);
+
+ if (IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT)) {
+ struct scmi_info *info =
+ handle_to_scmi_info(cinfo->handle);
+
+ scmi_raw_message_report(info->raw, xfer,
+ SCMI_RAW_REPLY_QUEUE,
+ cinfo->id);
+ }
}
} else {
/* And we wait for the response. */
@@ -865,6 +1100,59 @@ static int scmi_wait_for_message_response(struct scmi_chan_info *cinfo,
}
/**
+ * scmi_wait_for_message_response - An helper to group all the possible ways of
+ * waiting for a synchronous message response.
+ *
+ * @cinfo: SCMI channel info
+ * @xfer: Reference to the transfer being waited for.
+ *
+ * Chooses waiting strategy (sleep-waiting vs busy-waiting) depending on
+ * configuration flags like xfer->hdr.poll_completion.
+ *
+ * Return: 0 on Success, error otherwise.
+ */
+static int scmi_wait_for_message_response(struct scmi_chan_info *cinfo,
+ struct scmi_xfer *xfer)
+{
+ struct scmi_info *info = handle_to_scmi_info(cinfo->handle);
+ struct device *dev = info->dev;
+
+ trace_scmi_xfer_response_wait(xfer->transfer_id, xfer->hdr.id,
+ xfer->hdr.protocol_id, xfer->hdr.seq,
+ info->desc->max_rx_timeout_ms,
+ xfer->hdr.poll_completion);
+
+ return scmi_wait_for_reply(dev, info->desc, cinfo, xfer,
+ info->desc->max_rx_timeout_ms);
+}
+
+/**
+ * scmi_xfer_raw_wait_for_message_response - An helper to wait for a message
+ * reply to an xfer raw request on a specific channel for the required timeout.
+ *
+ * @cinfo: SCMI channel info
+ * @xfer: Reference to the transfer being waited for.
+ * @timeout_ms: The maximum timeout in milliseconds
+ *
+ * Return: 0 on Success, error otherwise.
+ */
+int scmi_xfer_raw_wait_for_message_response(struct scmi_chan_info *cinfo,
+ struct scmi_xfer *xfer,
+ unsigned int timeout_ms)
+{
+ int ret;
+ struct scmi_info *info = handle_to_scmi_info(cinfo->handle);
+ struct device *dev = info->dev;
+
+ ret = scmi_wait_for_reply(dev, info->desc, cinfo, xfer, timeout_ms);
+ if (ret)
+ dev_dbg(dev, "timed out in RAW response - HDR:%08X\n",
+ pack_scmi_header(&xfer->hdr));
+
+ return ret;
+}
+
+/**
* do_xfer() - Do one transfer
*
* @ph: Pointer to SCMI protocol handle
@@ -884,7 +1172,8 @@ static int do_xfer(const struct scmi_protocol_handle *ph,
struct scmi_chan_info *cinfo;
/* Check for polling request on custom command xfers at first */
- if (xfer->hdr.poll_completion && !is_transport_polling_capable(info)) {
+ if (xfer->hdr.poll_completion &&
+ !is_transport_polling_capable(info->desc)) {
dev_warn_once(dev,
"Polling mode is not supported by transport.\n");
return -EINVAL;
@@ -895,7 +1184,7 @@ static int do_xfer(const struct scmi_protocol_handle *ph,
return -EINVAL;
/* True ONLY if also supported by transport. */
- if (is_polling_enabled(cinfo, info))
+ if (is_polling_enabled(cinfo, info->desc))
xfer->hdr.poll_completion = true;
/*
@@ -928,9 +1217,9 @@ static int do_xfer(const struct scmi_protocol_handle *ph,
return ret;
}
- trace_scmi_msg_dump(xfer->hdr.protocol_id, xfer->hdr.id, "CMND",
- xfer->hdr.seq, xfer->hdr.status,
- xfer->tx.buf, xfer->tx.len);
+ trace_scmi_msg_dump(info->id, cinfo->id, xfer->hdr.protocol_id,
+ xfer->hdr.id, "CMND", xfer->hdr.seq,
+ xfer->hdr.status, xfer->tx.buf, xfer->tx.len);
ret = scmi_wait_for_message_response(cinfo, xfer);
if (!ret && xfer->hdr.status)
@@ -954,8 +1243,6 @@ static void reset_rx_to_maxsz(const struct scmi_protocol_handle *ph,
xfer->rx.len = info->desc->max_msg_size;
}
-#define SCMI_MAX_RESPONSE_TIMEOUT (2 * MSEC_PER_SEC)
-
/**
* do_xfer_with_response() - Do one transfer and wait until the delayed
* response is received
@@ -1043,13 +1330,22 @@ static int xfer_get_init(const struct scmi_protocol_handle *ph,
tx_size > info->desc->max_msg_size)
return -ERANGE;
- xfer = scmi_xfer_get(pi->handle, minfo, true);
+ xfer = scmi_xfer_get(pi->handle, minfo);
if (IS_ERR(xfer)) {
ret = PTR_ERR(xfer);
dev_err(dev, "failed to get free message slot(%d)\n", ret);
return ret;
}
+ /* Pick a sequence number and register this xfer as in-flight */
+ ret = scmi_xfer_pending_set(xfer, minfo);
+ if (ret) {
+ dev_err(pi->handle->dev,
+ "Failed to get monotonic token %d\n", ret);
+ __scmi_xfer_put(minfo, xfer);
+ return ret;
+ }
+
xfer->tx.len = tx_size;
xfer->rx.len = rx_size ? : info->desc->max_msg_size;
xfer->hdr.type = MSG_TYPE_COMMAND;
@@ -1822,20 +2118,14 @@ static bool scmi_is_transport_atomic(const struct scmi_handle *handle,
bool ret;
struct scmi_info *info = handle_to_scmi_info(handle);
- ret = info->desc->atomic_enabled && is_transport_polling_capable(info);
+ ret = info->desc->atomic_enabled &&
+ is_transport_polling_capable(info->desc);
if (ret && atomic_threshold)
*atomic_threshold = info->atomic_threshold;
return ret;
}
-static inline
-struct scmi_handle *scmi_handle_get_from_info_unlocked(struct scmi_info *info)
-{
- info->users++;
- return &info->handle;
-}
-
/**
* scmi_handle_get() - Get the SCMI handle for a device
*
@@ -1847,7 +2137,7 @@ struct scmi_handle *scmi_handle_get_from_info_unlocked(struct scmi_info *info)
*
* Return: pointer to handle if successful, NULL on error
*/
-struct scmi_handle *scmi_handle_get(struct device *dev)
+static struct scmi_handle *scmi_handle_get(struct device *dev)
{
struct list_head *p;
struct scmi_info *info;
@@ -1857,7 +2147,8 @@ struct scmi_handle *scmi_handle_get(struct device *dev)
list_for_each(p, &scmi_list) {
info = list_entry(p, struct scmi_info, node);
if (dev->parent == info->dev) {
- handle = scmi_handle_get_from_info_unlocked(info);
+ info->users++;
+ handle = &info->handle;
break;
}
}
@@ -1878,7 +2169,7 @@ struct scmi_handle *scmi_handle_get(struct device *dev)
* Return: 0 is successfully released
* if null was passed, it returns -EINVAL;
*/
-int scmi_handle_put(const struct scmi_handle *handle)
+static int scmi_handle_put(const struct scmi_handle *handle)
{
struct scmi_info *info;
@@ -1894,6 +2185,23 @@ int scmi_handle_put(const struct scmi_handle *handle)
return 0;
}
+static void scmi_device_link_add(struct device *consumer,
+ struct device *supplier)
+{
+ struct device_link *link;
+
+ link = device_link_add(consumer, supplier, DL_FLAG_AUTOREMOVE_CONSUMER);
+
+ WARN_ON(!link);
+}
+
+static void scmi_set_handle(struct scmi_device *scmi_dev)
+{
+ scmi_dev->handle = scmi_handle_get(&scmi_dev->dev);
+ if (scmi_dev->handle)
+ scmi_device_link_add(&scmi_dev->dev, scmi_dev->handle->dev);
+}
+
static int __scmi_xfer_info_init(struct scmi_info *sinfo,
struct scmi_xfers_info *info)
{
@@ -1987,23 +2295,20 @@ static int scmi_xfer_info_init(struct scmi_info *sinfo)
return ret;
}
-static int scmi_chan_setup(struct scmi_info *info, struct device *dev,
+static int scmi_chan_setup(struct scmi_info *info, struct device_node *of_node,
int prot_id, bool tx)
{
int ret, idx;
+ char name[32];
struct scmi_chan_info *cinfo;
struct idr *idr;
+ struct scmi_device *tdev = NULL;
/* Transmit channel is first entry i.e. index 0 */
idx = tx ? 0 : 1;
idr = tx ? &info->tx_idr : &info->rx_idr;
- /* check if already allocated, used for multiple device per protocol */
- cinfo = idr_find(idr, prot_id);
- if (cinfo)
- return 0;
-
- if (!info->desc->ops->chan_available(dev, idx)) {
+ if (!info->desc->ops->chan_available(of_node, idx)) {
cinfo = idr_find(idr, SCMI_PROTOCOL_BASE);
if (unlikely(!cinfo)) /* Possible only if platform has no Rx */
return -EINVAL;
@@ -2014,27 +2319,52 @@ static int scmi_chan_setup(struct scmi_info *info, struct device *dev,
if (!cinfo)
return -ENOMEM;
- cinfo->dev = dev;
cinfo->rx_timeout_ms = info->desc->max_rx_timeout_ms;
+ /* Create a unique name for this transport device */
+ snprintf(name, 32, "__scmi_transport_device_%s_%02X",
+ idx ? "rx" : "tx", prot_id);
+ /* Create a uniquely named, dedicated transport device for this chan */
+ tdev = scmi_device_create(of_node, info->dev, prot_id, name);
+ if (!tdev) {
+ dev_err(info->dev,
+ "failed to create transport device (%s)\n", name);
+ devm_kfree(info->dev, cinfo);
+ return -EINVAL;
+ }
+ of_node_get(of_node);
+
+ cinfo->id = prot_id;
+ cinfo->dev = &tdev->dev;
ret = info->desc->ops->chan_setup(cinfo, info->dev, tx);
- if (ret)
+ if (ret) {
+ of_node_put(of_node);
+ scmi_device_destroy(info->dev, prot_id, name);
+ devm_kfree(info->dev, cinfo);
return ret;
+ }
- if (tx && is_polling_required(cinfo, info)) {
- if (is_transport_polling_capable(info))
- dev_info(dev,
+ if (tx && is_polling_required(cinfo, info->desc)) {
+ if (is_transport_polling_capable(info->desc))
+ dev_info(&tdev->dev,
"Enabled polling mode TX channel - prot_id:%d\n",
prot_id);
else
- dev_warn(dev,
+ dev_warn(&tdev->dev,
"Polling mode NOT supported by transport.\n");
}
idr_alloc:
ret = idr_alloc(idr, cinfo, prot_id, prot_id + 1, GFP_KERNEL);
if (ret != prot_id) {
- dev_err(dev, "unable to allocate SCMI idr slot err %d\n", ret);
+ dev_err(info->dev,
+ "unable to allocate SCMI idr slot err %d\n", ret);
+ /* Destroy channel and device only if created by this call. */
+ if (tdev) {
+ of_node_put(of_node);
+ scmi_device_destroy(info->dev, prot_id, name);
+ devm_kfree(info->dev, cinfo);
+ }
return ret;
}
@@ -2043,13 +2373,14 @@ idr_alloc:
}
static inline int
-scmi_txrx_setup(struct scmi_info *info, struct device *dev, int prot_id)
+scmi_txrx_setup(struct scmi_info *info, struct device_node *of_node,
+ int prot_id)
{
- int ret = scmi_chan_setup(info, dev, prot_id, true);
+ int ret = scmi_chan_setup(info, of_node, prot_id, true);
if (!ret) {
/* Rx is optional, report only memory errors */
- ret = scmi_chan_setup(info, dev, prot_id, false);
+ ret = scmi_chan_setup(info, of_node, prot_id, false);
if (ret && ret != -ENOMEM)
ret = 0;
}
@@ -2058,306 +2389,264 @@ scmi_txrx_setup(struct scmi_info *info, struct device *dev, int prot_id)
}
/**
- * scmi_get_protocol_device - Helper to get/create an SCMI device.
- *
- * @np: A device node representing a valid active protocols for the referred
- * SCMI instance.
- * @info: The referred SCMI instance for which we are getting/creating this
- * device.
- * @prot_id: The protocol ID.
- * @name: The device name.
- *
- * Referring to the specific SCMI instance identified by @info, this helper
- * takes care to return a properly initialized device matching the requested
- * @proto_id and @name: if device was still not existent it is created as a
- * child of the specified SCMI instance @info and its transport properly
- * initialized as usual.
- *
- * Return: A properly initialized scmi device, NULL otherwise.
+ * scmi_channels_setup - Helper to initialize all required channels
+ *
+ * @info: The SCMI instance descriptor.
+ *
+ * Initialize all the channels found described in the DT against the underlying
+ * configured transport using custom defined dedicated devices instead of
+ * borrowing devices from the SCMI drivers; this way channels are initialized
+ * upfront during core SCMI stack probing and are no more coupled with SCMI
+ * devices used by SCMI drivers.
+ *
+ * Note that, even though a pair of TX/RX channels is associated to each
+ * protocol defined in the DT, a distinct freshly initialized channel is
+ * created only if the DT node for the protocol at hand describes a dedicated
+ * channel: in all the other cases the common BASE protocol channel is reused.
+ *
+ * Return: 0 on Success
*/
-static inline struct scmi_device *
-scmi_get_protocol_device(struct device_node *np, struct scmi_info *info,
- int prot_id, const char *name)
+static int scmi_channels_setup(struct scmi_info *info)
{
- struct scmi_device *sdev;
+ int ret;
+ struct device_node *child, *top_np = info->dev->of_node;
- /* Already created for this parent SCMI instance ? */
- sdev = scmi_child_dev_find(info->dev, prot_id, name);
- if (sdev)
- return sdev;
+ /* Initialize a common generic channel at first */
+ ret = scmi_txrx_setup(info, top_np, SCMI_PROTOCOL_BASE);
+ if (ret)
+ return ret;
- mutex_lock(&scmi_syspower_mtx);
- if (prot_id == SCMI_PROTOCOL_SYSTEM && scmi_syspower_registered) {
- dev_warn(info->dev,
- "SCMI SystemPower protocol device must be unique !\n");
- mutex_unlock(&scmi_syspower_mtx);
+ for_each_available_child_of_node(top_np, child) {
+ u32 prot_id;
- return NULL;
+ if (of_property_read_u32(child, "reg", &prot_id))
+ continue;
+
+ if (!FIELD_FIT(MSG_PROTOCOL_ID_MASK, prot_id))
+ dev_err(info->dev,
+ "Out of range protocol %d\n", prot_id);
+
+ ret = scmi_txrx_setup(info, child, prot_id);
+ if (ret) {
+ of_node_put(child);
+ return ret;
+ }
}
- pr_debug("Creating SCMI device (%s) for protocol %x\n", name, prot_id);
+ return 0;
+}
- sdev = scmi_device_create(np, info->dev, prot_id, name);
- if (!sdev) {
- dev_err(info->dev, "failed to create %d protocol device\n",
- prot_id);
- mutex_unlock(&scmi_syspower_mtx);
+static int scmi_chan_destroy(int id, void *p, void *idr)
+{
+ struct scmi_chan_info *cinfo = p;
- return NULL;
+ if (cinfo->dev) {
+ struct scmi_info *info = handle_to_scmi_info(cinfo->handle);
+ struct scmi_device *sdev = to_scmi_dev(cinfo->dev);
+
+ of_node_put(cinfo->dev->of_node);
+ scmi_device_destroy(info->dev, id, sdev->name);
+ cinfo->dev = NULL;
}
- if (scmi_txrx_setup(info, &sdev->dev, prot_id)) {
- dev_err(&sdev->dev, "failed to setup transport\n");
- scmi_device_destroy(sdev);
- mutex_unlock(&scmi_syspower_mtx);
+ idr_remove(idr, id);
- return NULL;
- }
+ return 0;
+}
- if (prot_id == SCMI_PROTOCOL_SYSTEM)
- scmi_syspower_registered = true;
+static void scmi_cleanup_channels(struct scmi_info *info, struct idr *idr)
+{
+ /* At first free all channels at the transport layer ... */
+ idr_for_each(idr, info->desc->ops->chan_free, idr);
- mutex_unlock(&scmi_syspower_mtx);
+ /* ...then destroy all underlying devices */
+ idr_for_each(idr, scmi_chan_destroy, idr);
- return sdev;
+ idr_destroy(idr);
}
-static inline void
-scmi_create_protocol_device(struct device_node *np, struct scmi_info *info,
- int prot_id, const char *name)
+static void scmi_cleanup_txrx_channels(struct scmi_info *info)
{
- struct scmi_device *sdev;
-
- sdev = scmi_get_protocol_device(np, info, prot_id, name);
- if (!sdev)
- return;
+ scmi_cleanup_channels(info, &info->tx_idr);
- /* setup handle now as the transport is ready */
- scmi_set_handle(sdev);
+ scmi_cleanup_channels(info, &info->rx_idr);
}
-/**
- * scmi_create_protocol_devices - Create devices for all pending requests for
- * this SCMI instance.
- *
- * @np: The device node describing the protocol
- * @info: The SCMI instance descriptor
- * @prot_id: The protocol ID
- *
- * All devices previously requested for this instance (if any) are found and
- * created by scanning the proper @&scmi_requested_devices entry.
- */
-static void scmi_create_protocol_devices(struct device_node *np,
- struct scmi_info *info, int prot_id)
+static int scmi_bus_notifier(struct notifier_block *nb,
+ unsigned long action, void *data)
{
- struct list_head *phead;
+ struct scmi_info *info = bus_nb_to_scmi_info(nb);
+ struct scmi_device *sdev = to_scmi_dev(data);
- mutex_lock(&scmi_requested_devices_mtx);
- phead = idr_find(&scmi_requested_devices, prot_id);
- if (phead) {
- struct scmi_requested_dev *rdev;
+ /* Skip transport devices and devices of different SCMI instances */
+ if (!strncmp(sdev->name, "__scmi_transport_device", 23) ||
+ sdev->dev.parent != info->dev)
+ return NOTIFY_DONE;
- list_for_each_entry(rdev, phead, node)
- scmi_create_protocol_device(np, info, prot_id,
- rdev->id_table->name);
+ switch (action) {
+ case BUS_NOTIFY_BIND_DRIVER:
+ /* setup handle now as the transport is ready */
+ scmi_set_handle(sdev);
+ break;
+ case BUS_NOTIFY_UNBOUND_DRIVER:
+ scmi_handle_put(sdev->handle);
+ sdev->handle = NULL;
+ break;
+ default:
+ return NOTIFY_DONE;
}
- mutex_unlock(&scmi_requested_devices_mtx);
+
+ dev_dbg(info->dev, "Device %s (%s) is now %s\n", dev_name(&sdev->dev),
+ sdev->name, action == BUS_NOTIFY_BIND_DRIVER ?
+ "about to be BOUND." : "UNBOUND.");
+
+ return NOTIFY_OK;
}
-/**
- * scmi_protocol_device_request - Helper to request a device
- *
- * @id_table: A protocol/name pair descriptor for the device to be created.
- *
- * This helper let an SCMI driver request specific devices identified by the
- * @id_table to be created for each active SCMI instance.
- *
- * The requested device name MUST NOT be already existent for any protocol;
- * at first the freshly requested @id_table is annotated in the IDR table
- * @scmi_requested_devices, then a matching device is created for each already
- * active SCMI instance. (if any)
- *
- * This way the requested device is created straight-away for all the already
- * initialized(probed) SCMI instances (handles) and it remains also annotated
- * as pending creation if the requesting SCMI driver was loaded before some
- * SCMI instance and related transports were available: when such late instance
- * is probed, its probe will take care to scan the list of pending requested
- * devices and create those on its own (see @scmi_create_protocol_devices and
- * its enclosing loop)
- *
- * Return: 0 on Success
- */
-int scmi_protocol_device_request(const struct scmi_device_id *id_table)
+static int scmi_device_request_notifier(struct notifier_block *nb,
+ unsigned long action, void *data)
{
- int ret = 0;
- unsigned int id = 0;
- struct list_head *head, *phead = NULL;
- struct scmi_requested_dev *rdev;
- struct scmi_info *info;
+ struct device_node *np;
+ struct scmi_device_id *id_table = data;
+ struct scmi_info *info = req_nb_to_scmi_info(nb);
- pr_debug("Requesting SCMI device (%s) for protocol %x\n",
- id_table->name, id_table->protocol_id);
+ np = idr_find(&info->active_protocols, id_table->protocol_id);
+ if (!np)
+ return NOTIFY_DONE;
- /*
- * Search for the matching protocol rdev list and then search
- * of any existent equally named device...fails if any duplicate found.
- */
- mutex_lock(&scmi_requested_devices_mtx);
- idr_for_each_entry(&scmi_requested_devices, head, id) {
- if (!phead) {
- /* A list found registered in the IDR is never empty */
- rdev = list_first_entry(head, struct scmi_requested_dev,
- node);
- if (rdev->id_table->protocol_id ==
- id_table->protocol_id)
- phead = head;
- }
- list_for_each_entry(rdev, head, node) {
- if (!strcmp(rdev->id_table->name, id_table->name)) {
- pr_err("Ignoring duplicate request [%d] %s\n",
- rdev->id_table->protocol_id,
- rdev->id_table->name);
- ret = -EINVAL;
- goto out;
- }
- }
- }
+ dev_dbg(info->dev, "%sRequested device (%s) for protocol 0x%x\n",
+ action == SCMI_BUS_NOTIFY_DEVICE_REQUEST ? "" : "UN-",
+ id_table->name, id_table->protocol_id);
- /*
- * No duplicate found for requested id_table, so let's create a new
- * requested device entry for this new valid request.
- */
- rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);
- if (!rdev) {
- ret = -ENOMEM;
- goto out;
+ switch (action) {
+ case SCMI_BUS_NOTIFY_DEVICE_REQUEST:
+ scmi_create_protocol_devices(np, info, id_table->protocol_id,
+ id_table->name);
+ break;
+ case SCMI_BUS_NOTIFY_DEVICE_UNREQUEST:
+ scmi_destroy_protocol_devices(info, id_table->protocol_id,
+ id_table->name);
+ break;
+ default:
+ return NOTIFY_DONE;
}
- rdev->id_table = id_table;
- /*
- * Append the new requested device table descriptor to the head of the
- * related protocol list, eventually creating such head if not already
- * there.
- */
- if (!phead) {
- phead = kzalloc(sizeof(*phead), GFP_KERNEL);
- if (!phead) {
- kfree(rdev);
- ret = -ENOMEM;
- goto out;
- }
- INIT_LIST_HEAD(phead);
-
- ret = idr_alloc(&scmi_requested_devices, (void *)phead,
- id_table->protocol_id,
- id_table->protocol_id + 1, GFP_KERNEL);
- if (ret != id_table->protocol_id) {
- pr_err("Failed to save SCMI device - ret:%d\n", ret);
- kfree(rdev);
- kfree(phead);
- ret = -EINVAL;
- goto out;
- }
- ret = 0;
- }
- list_add(&rdev->node, phead);
+ return NOTIFY_OK;
+}
- /*
- * Now effectively create and initialize the requested device for every
- * already initialized SCMI instance which has registered the requested
- * protocol as a valid active one: i.e. defined in DT and supported by
- * current platform FW.
- */
- mutex_lock(&scmi_list_mutex);
- list_for_each_entry(info, &scmi_list, node) {
- struct device_node *child;
-
- child = idr_find(&info->active_protocols,
- id_table->protocol_id);
- if (child) {
- struct scmi_device *sdev;
-
- sdev = scmi_get_protocol_device(child, info,
- id_table->protocol_id,
- id_table->name);
- if (sdev) {
- /* Set handle if not already set: device existed */
- if (!sdev->handle)
- sdev->handle =
- scmi_handle_get_from_info_unlocked(info);
- /* Relink consumer and suppliers */
- if (sdev->handle)
- scmi_device_link_add(&sdev->dev,
- sdev->handle->dev);
- }
- } else {
- dev_err(info->dev,
- "Failed. SCMI protocol %d not active.\n",
- id_table->protocol_id);
- }
- }
- mutex_unlock(&scmi_list_mutex);
+static void scmi_debugfs_common_cleanup(void *d)
+{
+ struct scmi_debug_info *dbg = d;
-out:
- mutex_unlock(&scmi_requested_devices_mtx);
+ if (!dbg)
+ return;
- return ret;
+ debugfs_remove_recursive(dbg->top_dentry);
+ kfree(dbg->name);
+ kfree(dbg->type);
}
-/**
- * scmi_protocol_device_unrequest - Helper to unrequest a device
- *
- * @id_table: A protocol/name pair descriptor for the device to be unrequested.
- *
- * An helper to let an SCMI driver release its request about devices; note that
- * devices are created and initialized once the first SCMI driver request them
- * but they destroyed only on SCMI core unloading/unbinding.
- *
- * The current SCMI transport layer uses such devices as internal references and
- * as such they could be shared as same transport between multiple drivers so
- * that cannot be safely destroyed till the whole SCMI stack is removed.
- * (unless adding further burden of refcounting.)
- */
-void scmi_protocol_device_unrequest(const struct scmi_device_id *id_table)
+static struct scmi_debug_info *scmi_debugfs_common_setup(struct scmi_info *info)
{
- struct list_head *phead;
+ char top_dir[16];
+ struct dentry *trans, *top_dentry;
+ struct scmi_debug_info *dbg;
+ const char *c_ptr = NULL;
- pr_debug("Unrequesting SCMI device (%s) for protocol %x\n",
- id_table->name, id_table->protocol_id);
+ dbg = devm_kzalloc(info->dev, sizeof(*dbg), GFP_KERNEL);
+ if (!dbg)
+ return NULL;
- mutex_lock(&scmi_requested_devices_mtx);
- phead = idr_find(&scmi_requested_devices, id_table->protocol_id);
- if (phead) {
- struct scmi_requested_dev *victim, *tmp;
+ dbg->name = kstrdup(of_node_full_name(info->dev->of_node), GFP_KERNEL);
+ if (!dbg->name) {
+ devm_kfree(info->dev, dbg);
+ return NULL;
+ }
- list_for_each_entry_safe(victim, tmp, phead, node) {
- if (!strcmp(victim->id_table->name, id_table->name)) {
- list_del(&victim->node);
- kfree(victim);
- break;
- }
- }
+ of_property_read_string(info->dev->of_node, "compatible", &c_ptr);
+ dbg->type = kstrdup(c_ptr, GFP_KERNEL);
+ if (!dbg->type) {
+ kfree(dbg->name);
+ devm_kfree(info->dev, dbg);
+ return NULL;
+ }
- if (list_empty(phead)) {
- idr_remove(&scmi_requested_devices,
- id_table->protocol_id);
- kfree(phead);
- }
+ snprintf(top_dir, 16, "%d", info->id);
+ top_dentry = debugfs_create_dir(top_dir, scmi_top_dentry);
+ trans = debugfs_create_dir("transport", top_dentry);
+
+ dbg->is_atomic = info->desc->atomic_enabled &&
+ is_transport_polling_capable(info->desc);
+
+ debugfs_create_str("instance_name", 0400, top_dentry,
+ (char **)&dbg->name);
+
+ debugfs_create_u32("atomic_threshold_us", 0400, top_dentry,
+ &info->atomic_threshold);
+
+ debugfs_create_str("type", 0400, trans, (char **)&dbg->type);
+
+ debugfs_create_bool("is_atomic", 0400, trans, &dbg->is_atomic);
+
+ debugfs_create_u32("max_rx_timeout_ms", 0400, trans,
+ (u32 *)&info->desc->max_rx_timeout_ms);
+
+ debugfs_create_u32("max_msg_size", 0400, trans,
+ (u32 *)&info->desc->max_msg_size);
+
+ debugfs_create_u32("tx_max_msg", 0400, trans,
+ (u32 *)&info->tx_minfo.max_msg);
+
+ debugfs_create_u32("rx_max_msg", 0400, trans,
+ (u32 *)&info->rx_minfo.max_msg);
+
+ dbg->top_dentry = top_dentry;
+
+ if (devm_add_action_or_reset(info->dev,
+ scmi_debugfs_common_cleanup, dbg)) {
+ scmi_debugfs_common_cleanup(dbg);
+ return NULL;
}
- mutex_unlock(&scmi_requested_devices_mtx);
+
+ return dbg;
}
-static int scmi_cleanup_txrx_channels(struct scmi_info *info)
+static int scmi_debugfs_raw_mode_setup(struct scmi_info *info)
{
- int ret;
- struct idr *idr = &info->tx_idr;
+ int id, num_chans = 0, ret = 0;
+ struct scmi_chan_info *cinfo;
+ u8 channels[SCMI_MAX_CHANNELS] = {};
+ DECLARE_BITMAP(protos, SCMI_MAX_CHANNELS) = {};
+
+ if (!info->dbg)
+ return -EINVAL;
+
+ /* Enumerate all channels to collect their ids */
+ idr_for_each_entry(&info->tx_idr, cinfo, id) {
+ /*
+ * Cannot happen, but be defensive.
+ * Zero as num_chans is ok, warn and carry on.
+ */
+ if (num_chans >= SCMI_MAX_CHANNELS || !cinfo) {
+ dev_warn(info->dev,
+ "SCMI RAW - Error enumerating channels\n");
+ break;
+ }
- ret = idr_for_each(idr, info->desc->ops->chan_free, idr);
- idr_destroy(&info->tx_idr);
+ if (!test_bit(cinfo->id, protos)) {
+ channels[num_chans++] = cinfo->id;
+ set_bit(cinfo->id, protos);
+ }
+ }
- idr = &info->rx_idr;
- ret = idr_for_each(idr, info->desc->ops->chan_free, idr);
- idr_destroy(&info->rx_idr);
+ info->raw = scmi_raw_mode_init(&info->handle, info->dbg->top_dentry,
+ info->id, channels, num_chans,
+ info->desc, info->tx_minfo.max_msg);
+ if (IS_ERR(info->raw)) {
+ dev_err(info->dev, "Failed to initialize SCMI RAW Mode !\n");
+ ret = PTR_ERR(info->raw);
+ info->raw = NULL;
+ }
return ret;
}
@@ -2379,12 +2668,19 @@ static int scmi_probe(struct platform_device *pdev)
if (!info)
return -ENOMEM;
+ info->id = ida_alloc_min(&scmi_id, 0, GFP_KERNEL);
+ if (info->id < 0)
+ return info->id;
+
info->dev = dev;
info->desc = desc;
+ info->bus_nb.notifier_call = scmi_bus_notifier;
+ info->dev_req_nb.notifier_call = scmi_device_request_notifier;
INIT_LIST_HEAD(&info->node);
idr_init(&info->protocols);
mutex_init(&info->protocols_mtx);
idr_init(&info->active_protocols);
+ mutex_init(&info->devreq_mtx);
platform_set_drvdata(pdev, info);
idr_init(&info->tx_idr);
@@ -2408,21 +2704,55 @@ static int scmi_probe(struct platform_device *pdev)
if (desc->ops->link_supplier) {
ret = desc->ops->link_supplier(dev);
if (ret)
- return ret;
+ goto clear_ida;
}
- ret = scmi_txrx_setup(info, dev, SCMI_PROTOCOL_BASE);
+ /* Setup all channels described in the DT at first */
+ ret = scmi_channels_setup(info);
if (ret)
- return ret;
+ goto clear_ida;
- ret = scmi_xfer_info_init(info);
+ ret = bus_register_notifier(&scmi_bus_type, &info->bus_nb);
if (ret)
goto clear_txrx_setup;
+ ret = blocking_notifier_chain_register(&scmi_requested_devices_nh,
+ &info->dev_req_nb);
+ if (ret)
+ goto clear_bus_notifier;
+
+ ret = scmi_xfer_info_init(info);
+ if (ret)
+ goto clear_dev_req_notifier;
+
+ if (scmi_top_dentry) {
+ info->dbg = scmi_debugfs_common_setup(info);
+ if (!info->dbg)
+ dev_warn(dev, "Failed to setup SCMI debugfs.\n");
+
+ if (IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT)) {
+ bool coex =
+ IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT_COEX);
+
+ ret = scmi_debugfs_raw_mode_setup(info);
+ if (!coex) {
+ if (ret)
+ goto clear_dev_req_notifier;
+
+ /* Bail out anyway when coex enabled */
+ return ret;
+ }
+
+ /* Coex enabled, carry on in any case. */
+ dev_info(dev, "SCMI RAW Mode COEX enabled !\n");
+ }
+ }
+
if (scmi_notification_init(handle))
dev_err(dev, "SCMI Notifications NOT available.\n");
- if (info->desc->atomic_enabled && !is_transport_polling_capable(info))
+ if (info->desc->atomic_enabled &&
+ !is_transport_polling_capable(info->desc))
dev_err(dev,
"Transport is not polling capable. Atomic mode not supported.\n");
@@ -2469,29 +2799,36 @@ static int scmi_probe(struct platform_device *pdev)
}
of_node_get(child);
- scmi_create_protocol_devices(child, info, prot_id);
+ scmi_create_protocol_devices(child, info, prot_id, NULL);
}
return 0;
notification_exit:
+ if (IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT))
+ scmi_raw_mode_cleanup(info->raw);
scmi_notification_exit(&info->handle);
+clear_dev_req_notifier:
+ blocking_notifier_chain_unregister(&scmi_requested_devices_nh,
+ &info->dev_req_nb);
+clear_bus_notifier:
+ bus_unregister_notifier(&scmi_bus_type, &info->bus_nb);
clear_txrx_setup:
scmi_cleanup_txrx_channels(info);
+clear_ida:
+ ida_free(&scmi_id, info->id);
return ret;
}
-void scmi_free_channel(struct scmi_chan_info *cinfo, struct idr *idr, int id)
-{
- idr_remove(idr, id);
-}
-
static int scmi_remove(struct platform_device *pdev)
{
- int ret, id;
+ int id;
struct scmi_info *info = platform_get_drvdata(pdev);
struct device_node *child;
+ if (IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT))
+ scmi_raw_mode_cleanup(info->raw);
+
mutex_lock(&scmi_list_mutex);
if (info->users)
dev_warn(&pdev->dev,
@@ -2509,10 +2846,14 @@ static int scmi_remove(struct platform_device *pdev)
of_node_put(child);
idr_destroy(&info->active_protocols);
+ blocking_notifier_chain_unregister(&scmi_requested_devices_nh,
+ &info->dev_req_nb);
+ bus_unregister_notifier(&scmi_bus_type, &info->bus_nb);
+
/* Safe to free channels since no more users */
- ret = scmi_cleanup_txrx_channels(info);
- if (ret)
- dev_warn(&pdev->dev, "Failed to cleanup SCMI channels.\n");
+ scmi_cleanup_txrx_channels(info);
+
+ ida_free(&scmi_id, info->id);
return 0;
}
@@ -2641,6 +2982,19 @@ static void __exit scmi_transports_exit(void)
__scmi_transports_setup(false);
}
+static struct dentry *scmi_debugfs_init(void)
+{
+ struct dentry *d;
+
+ d = debugfs_create_dir("scmi", NULL);
+ if (IS_ERR(d)) {
+ pr_err("Could NOT create SCMI top dentry.\n");
+ return NULL;
+ }
+
+ return d;
+}
+
static int __init scmi_driver_init(void)
{
int ret;
@@ -2649,13 +3003,14 @@ static int __init scmi_driver_init(void)
if (WARN_ON(!IS_ENABLED(CONFIG_ARM_SCMI_HAVE_TRANSPORT)))
return -EINVAL;
- scmi_bus_init();
-
/* Initialize any compiled-in transport which provided an init/exit */
ret = scmi_transports_init();
if (ret)
return ret;
+ if (IS_ENABLED(CONFIG_ARM_SCMI_NEED_DEBUGFS))
+ scmi_top_dentry = scmi_debugfs_init();
+
scmi_base_register();
scmi_clock_register();
@@ -2669,7 +3024,7 @@ static int __init scmi_driver_init(void)
return platform_driver_register(&scmi_driver);
}
-subsys_initcall(scmi_driver_init);
+module_init(scmi_driver_init);
static void __exit scmi_driver_exit(void)
{
@@ -2684,11 +3039,11 @@ static void __exit scmi_driver_exit(void)
scmi_system_unregister();
scmi_powercap_unregister();
- scmi_bus_exit();
-
scmi_transports_exit();
platform_driver_unregister(&scmi_driver);
+
+ debugfs_remove_recursive(scmi_top_dentry);
}
module_exit(scmi_driver_exit);
diff --git a/drivers/firmware/arm_scmi/mailbox.c b/drivers/firmware/arm_scmi/mailbox.c
index 1e40cb035044..0d9c9538b7f4 100644
--- a/drivers/firmware/arm_scmi/mailbox.c
+++ b/drivers/firmware/arm_scmi/mailbox.c
@@ -46,9 +46,9 @@ static void rx_callback(struct mbox_client *cl, void *m)
scmi_rx_callback(smbox->cinfo, shmem_read_header(smbox->shmem), NULL);
}
-static bool mailbox_chan_available(struct device *dev, int idx)
+static bool mailbox_chan_available(struct device_node *of_node, int idx)
{
- return !of_parse_phandle_with_args(dev->of_node, "mboxes",
+ return !of_parse_phandle_with_args(of_node, "mboxes",
"#mbox-cells", idx, NULL);
}
@@ -120,8 +120,6 @@ static int mailbox_chan_free(int id, void *p, void *data)
smbox->cinfo = NULL;
}
- scmi_free_channel(cinfo, data, id);
-
return 0;
}
diff --git a/drivers/firmware/arm_scmi/optee.c b/drivers/firmware/arm_scmi/optee.c
index 2a7aeab40e54..929720387102 100644
--- a/drivers/firmware/arm_scmi/optee.c
+++ b/drivers/firmware/arm_scmi/optee.c
@@ -328,11 +328,11 @@ static int scmi_optee_link_supplier(struct device *dev)
return 0;
}
-static bool scmi_optee_chan_available(struct device *dev, int idx)
+static bool scmi_optee_chan_available(struct device_node *of_node, int idx)
{
u32 channel_id;
- return !of_property_read_u32_index(dev->of_node, "linaro,optee-channel-id",
+ return !of_property_read_u32_index(of_node, "linaro,optee-channel-id",
idx, &channel_id);
}
@@ -481,8 +481,6 @@ static int scmi_optee_chan_free(int id, void *p, void *data)
cinfo->transport_info = NULL;
channel->cinfo = NULL;
- scmi_free_channel(cinfo, data, id);
-
return 0;
}
diff --git a/drivers/firmware/arm_scmi/protocols.h b/drivers/firmware/arm_scmi/protocols.h
index 2f3bf691db7c..78e1a01eb656 100644
--- a/drivers/firmware/arm_scmi/protocols.h
+++ b/drivers/firmware/arm_scmi/protocols.h
@@ -115,6 +115,7 @@ struct scmi_msg_hdr {
* - SCMI_XFER_SENT_OK -> SCMI_XFER_RESP_OK [ -> SCMI_XFER_DRESP_OK ]
* - SCMI_XFER_SENT_OK -> SCMI_XFER_DRESP_OK
* (Missing synchronous response is assumed OK and ignored)
+ * @flags: Optional flags associated to this xfer.
* @lock: A spinlock to protect state and busy fields.
* @priv: A pointer for transport private usage.
*/
@@ -135,6 +136,12 @@ struct scmi_xfer {
#define SCMI_XFER_RESP_OK 1
#define SCMI_XFER_DRESP_OK 2
int state;
+#define SCMI_XFER_FLAG_IS_RAW BIT(0)
+#define SCMI_XFER_IS_RAW(x) ((x)->flags & SCMI_XFER_FLAG_IS_RAW)
+#define SCMI_XFER_FLAG_CHAN_SET BIT(1)
+#define SCMI_XFER_IS_CHAN_SET(x) \
+ ((x)->flags & SCMI_XFER_FLAG_CHAN_SET)
+ int flags;
/* A lock to protect state and busy fields */
spinlock_t lock;
void *priv;
diff --git a/drivers/firmware/arm_scmi/raw_mode.c b/drivers/firmware/arm_scmi/raw_mode.c
new file mode 100644
index 000000000000..d40df099fd51
--- /dev/null
+++ b/drivers/firmware/arm_scmi/raw_mode.c
@@ -0,0 +1,1443 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * System Control and Management Interface (SCMI) Raw mode support
+ *
+ * Copyright (C) 2022 ARM Ltd.
+ */
+/**
+ * DOC: Theory of operation
+ *
+ * When enabled the SCMI Raw mode support exposes a userspace API which allows
+ * to send and receive SCMI commands, replies and notifications from a user
+ * application through injection and snooping of bare SCMI messages in binary
+ * little-endian format.
+ *
+ * Such injected SCMI transactions will then be routed through the SCMI core
+ * stack towards the SCMI backend server using whatever SCMI transport is
+ * currently configured on the system under test.
+ *
+ * It is meant to help in running any sort of SCMI backend server testing, no
+ * matter where the server is placed, as long as it is normally reachable via
+ * the transport configured on the system.
+ *
+ * It is activated by a Kernel configuration option since it is NOT meant to
+ * be used in production but only during development and in CI deployments.
+ *
+ * In order to avoid possible interferences between the SCMI Raw transactions
+ * originated from a test-suite and the normal operations of the SCMI drivers,
+ * when Raw mode is enabled, by default, all the regular SCMI drivers are
+ * inhibited, unless CONFIG_ARM_SCMI_RAW_MODE_SUPPORT_COEX is enabled: in this
+ * latter case the regular SCMI stack drivers will be loaded as usual and it is
+ * up to the user of this interface to take care of manually inhibiting the
+ * regular SCMI drivers in order to avoid interferences during the test runs.
+ *
+ * The exposed API is as follows.
+ *
+ * All SCMI Raw entries are rooted under a common top /raw debugfs top directory
+ * which in turn is rooted under the corresponding underlying SCMI instance.
+ *
+ * /sys/kernel/debug/scmi/
+ * `-- 0
+ * |-- atomic_threshold_us
+ * |-- instance_name
+ * |-- raw
+ * | |-- channels
+ * | | |-- 0x10
+ * | | | |-- message
+ * | | | `-- message_async
+ * | | `-- 0x13
+ * | | |-- message
+ * | | `-- message_async
+ * | |-- errors
+ * | |-- message
+ * | |-- message_async
+ * | |-- notification
+ * | `-- reset
+ * `-- transport
+ * |-- is_atomic
+ * |-- max_msg_size
+ * |-- max_rx_timeout_ms
+ * |-- rx_max_msg
+ * |-- tx_max_msg
+ * `-- type
+ *
+ * where:
+ *
+ * - errors: used to read back timed-out and unexpected replies
+ * - message*: used to send sync/async commands and read back immediate and
+ * delayed reponses (if any)
+ * - notification: used to read any notification being emitted by the system
+ * (if previously enabled by the user app)
+ * - reset: used to flush the queues of messages (of any kind) still pending
+ * to be read; this is useful at test-suite start/stop to get
+ * rid of any unread messages from the previous run.
+ *
+ * with the per-channel entries rooted at /channels being present only on a
+ * system where multiple transport channels have been configured.
+ *
+ * Such per-channel entries can be used to explicitly choose a specific channel
+ * for SCMI bare message injection, in contrast with the general entries above
+ * where, instead, the selection of the proper channel to use is automatically
+ * performed based the protocol embedded in the injected message and on how the
+ * transport is configured on the system.
+ *
+ * Note that other common general entries are available under transport/ to let
+ * the user applications properly make up their expectations in terms of
+ * timeouts and message characteristics.
+ *
+ * Each write to the message* entries causes one command request to be built
+ * and sent while the replies or delayed response are read back from those same
+ * entries one message at time (receiving an EOF at each message boundary).
+ *
+ * The user application running the test is in charge of handling timeouts
+ * on replies and properly choosing SCMI sequence numbers for the outgoing
+ * requests (using the same sequence number is supported but discouraged).
+ *
+ * Injection of multiple in-flight requests is supported as long as the user
+ * application uses properly distinct sequence numbers for concurrent requests
+ * and takes care to properly manage all the related issues about concurrency
+ * and command/reply pairing. Keep in mind that, anyway, the real level of
+ * parallelism attainable in such scenario is dependent on the characteristics
+ * of the underlying transport being used.
+ *
+ * Since the SCMI core regular stack is partially used to deliver and collect
+ * the messages, late replies arrived after timeouts and any other sort of
+ * unexpected message can be identified by the SCMI core as usual and they will
+ * be reported as messages under "errors" for later analysis.
+ */
+
+#include <linux/bitmap.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/export.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/xarray.h>
+
+#include "common.h"
+
+#include "raw_mode.h"
+
+#include <trace/events/scmi.h>
+
+#define SCMI_XFER_RAW_MAX_RETRIES 10
+
+/**
+ * struct scmi_raw_queue - Generic Raw queue descriptor
+ *
+ * @free_bufs: A freelists listhead used to keep unused raw buffers
+ * @free_bufs_lock: Spinlock used to protect access to @free_bufs
+ * @msg_q: A listhead to a queue of snooped messages waiting to be read out
+ * @msg_q_lock: Spinlock used to protect access to @msg_q
+ * @wq: A waitqueue used to wait and poll on related @msg_q
+ */
+struct scmi_raw_queue {
+ struct list_head free_bufs;
+ /* Protect free_bufs[] lists */
+ spinlock_t free_bufs_lock;
+ struct list_head msg_q;
+ /* Protect msg_q[] lists */
+ spinlock_t msg_q_lock;
+ wait_queue_head_t wq;
+};
+
+/**
+ * struct scmi_raw_mode_info - Structure holding SCMI Raw instance data
+ *
+ * @id: Sequential Raw instance ID.
+ * @handle: Pointer to SCMI entity handle to use
+ * @desc: Pointer to the transport descriptor to use
+ * @tx_max_msg: Maximum number of concurrent TX in-flight messages
+ * @q: An array of Raw queue descriptors
+ * @chans_q: An XArray mapping optional additional per-channel queues
+ * @free_waiters: Head of freelist for unused waiters
+ * @free_mtx: A mutex to protect the waiters freelist
+ * @active_waiters: Head of list for currently active and used waiters
+ * @active_mtx: A mutex to protect the active waiters list
+ * @waiters_work: A work descriptor to be used with the workqueue machinery
+ * @wait_wq: A workqueue reference to the created workqueue
+ * @dentry: Top debugfs root dentry for SCMI Raw
+ * @gid: A group ID used for devres accounting
+ *
+ * Note that this descriptor is passed back to the core after SCMI Raw is
+ * initialized as an opaque handle to use by subsequent SCMI Raw call hooks.
+ *
+ */
+struct scmi_raw_mode_info {
+ unsigned int id;
+ const struct scmi_handle *handle;
+ const struct scmi_desc *desc;
+ int tx_max_msg;
+ struct scmi_raw_queue *q[SCMI_RAW_MAX_QUEUE];
+ struct xarray chans_q;
+ struct list_head free_waiters;
+ /* Protect free_waiters list */
+ struct mutex free_mtx;
+ struct list_head active_waiters;
+ /* Protect active_waiters list */
+ struct mutex active_mtx;
+ struct work_struct waiters_work;
+ struct workqueue_struct *wait_wq;
+ struct dentry *dentry;
+ void *gid;
+};
+
+/**
+ * struct scmi_xfer_raw_waiter - Structure to describe an xfer to be waited for
+ *
+ * @start_jiffies: The timestamp in jiffies of when this structure was queued.
+ * @cinfo: A reference to the channel to use for this transaction
+ * @xfer: A reference to the xfer to be waited for
+ * @async_response: A completion to be, optionally, used for async waits: it
+ * will be setup by @scmi_do_xfer_raw_start, if needed, to be
+ * pointed at by xfer->async_done.
+ * @node: A list node.
+ */
+struct scmi_xfer_raw_waiter {
+ unsigned long start_jiffies;
+ struct scmi_chan_info *cinfo;
+ struct scmi_xfer *xfer;
+ struct completion async_response;
+ struct list_head node;
+};
+
+/**
+ * struct scmi_raw_buffer - Structure to hold a full SCMI message
+ *
+ * @max_len: The maximum allowed message size (header included) that can be
+ * stored into @msg
+ * @msg: A message buffer used to collect a full message grabbed from an xfer.
+ * @node: A list node.
+ */
+struct scmi_raw_buffer {
+ size_t max_len;
+ struct scmi_msg msg;
+ struct list_head node;
+};
+
+/**
+ * struct scmi_dbg_raw_data - Structure holding data needed by the debugfs
+ * layer
+ *
+ * @chan_id: The preferred channel to use: if zero the channel is automatically
+ * selected based on protocol.
+ * @raw: A reference to the Raw instance.
+ * @tx: A message buffer used to collect TX message on write.
+ * @tx_size: The effective size of the TX message.
+ * @tx_req_size: The final expected size of the complete TX message.
+ * @rx: A message buffer to collect RX message on read.
+ * @rx_size: The effective size of the RX message.
+ */
+struct scmi_dbg_raw_data {
+ u8 chan_id;
+ struct scmi_raw_mode_info *raw;
+ struct scmi_msg tx;
+ size_t tx_size;
+ size_t tx_req_size;
+ struct scmi_msg rx;
+ size_t rx_size;
+};
+
+static struct scmi_raw_queue *
+scmi_raw_queue_select(struct scmi_raw_mode_info *raw, unsigned int idx,
+ unsigned int chan_id)
+{
+ if (!chan_id)
+ return raw->q[idx];
+
+ return xa_load(&raw->chans_q, chan_id);
+}
+
+static struct scmi_raw_buffer *scmi_raw_buffer_get(struct scmi_raw_queue *q)
+{
+ unsigned long flags;
+ struct scmi_raw_buffer *rb = NULL;
+ struct list_head *head = &q->free_bufs;
+
+ spin_lock_irqsave(&q->free_bufs_lock, flags);
+ if (!list_empty(head)) {
+ rb = list_first_entry(head, struct scmi_raw_buffer, node);
+ list_del_init(&rb->node);
+ }
+ spin_unlock_irqrestore(&q->free_bufs_lock, flags);
+
+ return rb;
+}
+
+static void scmi_raw_buffer_put(struct scmi_raw_queue *q,
+ struct scmi_raw_buffer *rb)
+{
+ unsigned long flags;
+
+ /* Reset to full buffer length */
+ rb->msg.len = rb->max_len;
+
+ spin_lock_irqsave(&q->free_bufs_lock, flags);
+ list_add_tail(&rb->node, &q->free_bufs);
+ spin_unlock_irqrestore(&q->free_bufs_lock, flags);
+}
+
+static void scmi_raw_buffer_enqueue(struct scmi_raw_queue *q,
+ struct scmi_raw_buffer *rb)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&q->msg_q_lock, flags);
+ list_add_tail(&rb->node, &q->msg_q);
+ spin_unlock_irqrestore(&q->msg_q_lock, flags);
+
+ wake_up_interruptible(&q->wq);
+}
+
+static struct scmi_raw_buffer*
+scmi_raw_buffer_dequeue_unlocked(struct scmi_raw_queue *q)
+{
+ struct scmi_raw_buffer *rb = NULL;
+
+ if (!list_empty(&q->msg_q)) {
+ rb = list_first_entry(&q->msg_q, struct scmi_raw_buffer, node);
+ list_del_init(&rb->node);
+ }
+
+ return rb;
+}
+
+static struct scmi_raw_buffer *scmi_raw_buffer_dequeue(struct scmi_raw_queue *q)
+{
+ unsigned long flags;
+ struct scmi_raw_buffer *rb;
+
+ spin_lock_irqsave(&q->msg_q_lock, flags);
+ rb = scmi_raw_buffer_dequeue_unlocked(q);
+ spin_unlock_irqrestore(&q->msg_q_lock, flags);
+
+ return rb;
+}
+
+static void scmi_raw_buffer_queue_flush(struct scmi_raw_queue *q)
+{
+ struct scmi_raw_buffer *rb;
+
+ do {
+ rb = scmi_raw_buffer_dequeue(q);
+ if (rb)
+ scmi_raw_buffer_put(q, rb);
+ } while (rb);
+}
+
+static struct scmi_xfer_raw_waiter *
+scmi_xfer_raw_waiter_get(struct scmi_raw_mode_info *raw, struct scmi_xfer *xfer,
+ struct scmi_chan_info *cinfo, bool async)
+{
+ struct scmi_xfer_raw_waiter *rw = NULL;
+
+ mutex_lock(&raw->free_mtx);
+ if (!list_empty(&raw->free_waiters)) {
+ rw = list_first_entry(&raw->free_waiters,
+ struct scmi_xfer_raw_waiter, node);
+ list_del_init(&rw->node);
+
+ if (async) {
+ reinit_completion(&rw->async_response);
+ xfer->async_done = &rw->async_response;
+ }
+
+ rw->cinfo = cinfo;
+ rw->xfer = xfer;
+ }
+ mutex_unlock(&raw->free_mtx);
+
+ return rw;
+}
+
+static void scmi_xfer_raw_waiter_put(struct scmi_raw_mode_info *raw,
+ struct scmi_xfer_raw_waiter *rw)
+{
+ if (rw->xfer) {
+ rw->xfer->async_done = NULL;
+ rw->xfer = NULL;
+ }
+
+ mutex_lock(&raw->free_mtx);
+ list_add_tail(&rw->node, &raw->free_waiters);
+ mutex_unlock(&raw->free_mtx);
+}
+
+static void scmi_xfer_raw_waiter_enqueue(struct scmi_raw_mode_info *raw,
+ struct scmi_xfer_raw_waiter *rw)
+{
+ /* A timestamp for the deferred worker to know how much this has aged */
+ rw->start_jiffies = jiffies;
+
+ trace_scmi_xfer_response_wait(rw->xfer->transfer_id, rw->xfer->hdr.id,
+ rw->xfer->hdr.protocol_id,
+ rw->xfer->hdr.seq,
+ raw->desc->max_rx_timeout_ms,
+ rw->xfer->hdr.poll_completion);
+
+ mutex_lock(&raw->active_mtx);
+ list_add_tail(&rw->node, &raw->active_waiters);
+ mutex_unlock(&raw->active_mtx);
+
+ /* kick waiter work */
+ queue_work(raw->wait_wq, &raw->waiters_work);
+}
+
+static struct scmi_xfer_raw_waiter *
+scmi_xfer_raw_waiter_dequeue(struct scmi_raw_mode_info *raw)
+{
+ struct scmi_xfer_raw_waiter *rw = NULL;
+
+ mutex_lock(&raw->active_mtx);
+ if (!list_empty(&raw->active_waiters)) {
+ rw = list_first_entry(&raw->active_waiters,
+ struct scmi_xfer_raw_waiter, node);
+ list_del_init(&rw->node);
+ }
+ mutex_unlock(&raw->active_mtx);
+
+ return rw;
+}
+
+/**
+ * scmi_xfer_raw_worker - Work function to wait for Raw xfers completions
+ *
+ * @work: A reference to the work.
+ *
+ * In SCMI Raw mode, once a user-provided injected SCMI message is sent, we
+ * cannot wait to receive its response (if any) in the context of the injection
+ * routines so as not to leave the userspace write syscall, which delivered the
+ * SCMI message to send, pending till eventually a reply is received.
+ * Userspace should and will poll/wait instead on the read syscalls which will
+ * be in charge of reading a received reply (if any).
+ *
+ * Even though reply messages are collected and reported into the SCMI Raw layer
+ * on the RX path, nonetheless we have to properly wait for their completion as
+ * usual (and async_completion too if needed) in order to properly release the
+ * xfer structure at the end: to do this out of the context of the write/send
+ * these waiting jobs are delegated to this deferred worker.
+ *
+ * Any sent xfer, to be waited for, is timestamped and queued for later
+ * consumption by this worker: queue aging is accounted for while choosing a
+ * timeout for the completion, BUT we do not really care here if we end up
+ * accidentally waiting for a bit too long.
+ */
+static void scmi_xfer_raw_worker(struct work_struct *work)
+{
+ struct scmi_raw_mode_info *raw;
+ struct device *dev;
+ unsigned long max_tmo;
+
+ raw = container_of(work, struct scmi_raw_mode_info, waiters_work);
+ dev = raw->handle->dev;
+ max_tmo = msecs_to_jiffies(raw->desc->max_rx_timeout_ms);
+
+ do {
+ int ret = 0;
+ unsigned int timeout_ms;
+ unsigned long aging;
+ struct scmi_xfer *xfer;
+ struct scmi_xfer_raw_waiter *rw;
+ struct scmi_chan_info *cinfo;
+
+ rw = scmi_xfer_raw_waiter_dequeue(raw);
+ if (!rw)
+ return;
+
+ cinfo = rw->cinfo;
+ xfer = rw->xfer;
+ /*
+ * Waiters are queued by wait-deadline at the end, so some of
+ * them could have been already expired when processed, BUT we
+ * have to check the completion status anyway just in case a
+ * virtually expired (aged) transaction was indeed completed
+ * fine and we'll have to wait for the asynchronous part (if
+ * any): for this reason a 1 ms timeout is used for already
+ * expired/aged xfers.
+ */
+ aging = jiffies - rw->start_jiffies;
+ timeout_ms = max_tmo > aging ?
+ jiffies_to_msecs(max_tmo - aging) : 1;
+
+ ret = scmi_xfer_raw_wait_for_message_response(cinfo, xfer,
+ timeout_ms);
+ if (!ret && xfer->hdr.status)
+ ret = scmi_to_linux_errno(xfer->hdr.status);
+
+ if (raw->desc->ops->mark_txdone)
+ raw->desc->ops->mark_txdone(rw->cinfo, ret, xfer);
+
+ trace_scmi_xfer_end(xfer->transfer_id, xfer->hdr.id,
+ xfer->hdr.protocol_id, xfer->hdr.seq, ret);
+
+ /* Wait also for an async delayed response if needed */
+ if (!ret && xfer->async_done) {
+ unsigned long tmo = msecs_to_jiffies(SCMI_MAX_RESPONSE_TIMEOUT);
+
+ if (!wait_for_completion_timeout(xfer->async_done, tmo))
+ dev_err(dev,
+ "timed out in RAW delayed resp - HDR:%08X\n",
+ pack_scmi_header(&xfer->hdr));
+ }
+
+ /* Release waiter and xfer */
+ scmi_xfer_raw_put(raw->handle, xfer);
+ scmi_xfer_raw_waiter_put(raw, rw);
+ } while (1);
+}
+
+static void scmi_xfer_raw_reset(struct scmi_raw_mode_info *raw)
+{
+ int i;
+
+ dev_info(raw->handle->dev, "Resetting SCMI Raw stack.\n");
+
+ for (i = 0; i < SCMI_RAW_MAX_QUEUE; i++)
+ scmi_raw_buffer_queue_flush(raw->q[i]);
+}
+
+/**
+ * scmi_xfer_raw_get_init - An helper to build a valid xfer from the provided
+ * bare SCMI message.
+ *
+ * @raw: A reference to the Raw instance.
+ * @buf: A buffer containing the whole SCMI message to send (including the
+ * header) in little-endian binary formmat.
+ * @len: Length of the message in @buf.
+ * @p: A pointer to return the initialized Raw xfer.
+ *
+ * After an xfer is picked from the TX pool and filled in with the message
+ * content, the xfer is registered as pending with the core in the usual way
+ * using the original sequence number provided by the user with the message.
+ *
+ * Note that, in case the testing user application is NOT using distinct
+ * sequence-numbers between successive SCMI messages such registration could
+ * fail temporarily if the previous message, using the same sequence number,
+ * had still not released; in such a case we just wait and retry.
+ *
+ * Return: 0 on Success
+ */
+static int scmi_xfer_raw_get_init(struct scmi_raw_mode_info *raw, void *buf,
+ size_t len, struct scmi_xfer **p)
+{
+ u32 msg_hdr;
+ size_t tx_size;
+ struct scmi_xfer *xfer;
+ int ret, retry = SCMI_XFER_RAW_MAX_RETRIES;
+ struct device *dev = raw->handle->dev;
+
+ if (!buf || len < sizeof(u32))
+ return -EINVAL;
+
+ tx_size = len - sizeof(u32);
+ /* Ensure we have sane transfer sizes */
+ if (tx_size > raw->desc->max_msg_size)
+ return -ERANGE;
+
+ xfer = scmi_xfer_raw_get(raw->handle);
+ if (IS_ERR(xfer)) {
+ dev_warn(dev, "RAW - Cannot get a free RAW xfer !\n");
+ return PTR_ERR(xfer);
+ }
+
+ /* Build xfer from the provided SCMI bare LE message */
+ msg_hdr = le32_to_cpu(*((__le32 *)buf));
+ unpack_scmi_header(msg_hdr, &xfer->hdr);
+ xfer->hdr.seq = (u16)MSG_XTRACT_TOKEN(msg_hdr);
+ /* Polling not supported */
+ xfer->hdr.poll_completion = false;
+ xfer->hdr.status = SCMI_SUCCESS;
+ xfer->tx.len = tx_size;
+ xfer->rx.len = raw->desc->max_msg_size;
+ /* Clear the whole TX buffer */
+ memset(xfer->tx.buf, 0x00, raw->desc->max_msg_size);
+ if (xfer->tx.len)
+ memcpy(xfer->tx.buf, (u8 *)buf + sizeof(msg_hdr), xfer->tx.len);
+ *p = xfer;
+
+ /*
+ * In flight registration can temporarily fail in case of Raw messages
+ * if the user injects messages without using monotonically increasing
+ * sequence numbers since, in Raw mode, the xfer (and the token) is
+ * finally released later by a deferred worker. Just retry for a while.
+ */
+ do {
+ ret = scmi_xfer_raw_inflight_register(raw->handle, xfer);
+ if (ret) {
+ dev_dbg(dev,
+ "...retrying[%d] inflight registration\n",
+ retry);
+ msleep(raw->desc->max_rx_timeout_ms /
+ SCMI_XFER_RAW_MAX_RETRIES);
+ }
+ } while (ret && --retry);
+
+ if (ret) {
+ dev_warn(dev,
+ "RAW - Could NOT register xfer %d in-flight HDR:0x%08X\n",
+ xfer->hdr.seq, msg_hdr);
+ scmi_xfer_raw_put(raw->handle, xfer);
+ }
+
+ return ret;
+}
+
+/**
+ * scmi_do_xfer_raw_start - An helper to send a valid raw xfer
+ *
+ * @raw: A reference to the Raw instance.
+ * @xfer: The xfer to send
+ * @chan_id: The channel ID to use, if zero the channels is automatically
+ * selected based on the protocol used.
+ * @async: A flag stating if an asynchronous command is required.
+ *
+ * This function send a previously built raw xfer using an appropriate channel
+ * and queues the related waiting work.
+ *
+ * Note that we need to know explicitly if the required command is meant to be
+ * asynchronous in kind since we have to properly setup the waiter.
+ * (and deducing this from the payload is weak and do not scale given there is
+ * NOT a common header-flag stating if the command is asynchronous or not)
+ *
+ * Return: 0 on Success
+ */
+static int scmi_do_xfer_raw_start(struct scmi_raw_mode_info *raw,
+ struct scmi_xfer *xfer, u8 chan_id,
+ bool async)
+{
+ int ret;
+ struct scmi_chan_info *cinfo;
+ struct scmi_xfer_raw_waiter *rw;
+ struct device *dev = raw->handle->dev;
+
+ if (!chan_id)
+ chan_id = xfer->hdr.protocol_id;
+ else
+ xfer->flags |= SCMI_XFER_FLAG_CHAN_SET;
+
+ cinfo = scmi_xfer_raw_channel_get(raw->handle, chan_id);
+ if (IS_ERR(cinfo))
+ return PTR_ERR(cinfo);
+
+ rw = scmi_xfer_raw_waiter_get(raw, xfer, cinfo, async);
+ if (!rw) {
+ dev_warn(dev, "RAW - Cannot get a free waiter !\n");
+ return -ENOMEM;
+ }
+
+ /* True ONLY if also supported by transport. */
+ if (is_polling_enabled(cinfo, raw->desc))
+ xfer->hdr.poll_completion = true;
+
+ reinit_completion(&xfer->done);
+ /* Make sure xfer state update is visible before sending */
+ smp_store_mb(xfer->state, SCMI_XFER_SENT_OK);
+
+ trace_scmi_xfer_begin(xfer->transfer_id, xfer->hdr.id,
+ xfer->hdr.protocol_id, xfer->hdr.seq,
+ xfer->hdr.poll_completion);
+
+ ret = raw->desc->ops->send_message(rw->cinfo, xfer);
+ if (ret) {
+ dev_err(dev, "Failed to send RAW message %d\n", ret);
+ scmi_xfer_raw_waiter_put(raw, rw);
+ return ret;
+ }
+
+ trace_scmi_msg_dump(raw->id, cinfo->id, xfer->hdr.protocol_id,
+ xfer->hdr.id, "cmnd", xfer->hdr.seq,
+ xfer->hdr.status,
+ xfer->tx.buf, xfer->tx.len);
+
+ scmi_xfer_raw_waiter_enqueue(raw, rw);
+
+ return ret;
+}
+
+/**
+ * scmi_raw_message_send - An helper to build and send an SCMI command using
+ * the provided SCMI bare message buffer
+ *
+ * @raw: A reference to the Raw instance.
+ * @buf: A buffer containing the whole SCMI message to send (including the
+ * header) in little-endian binary format.
+ * @len: Length of the message in @buf.
+ * @chan_id: The channel ID to use.
+ * @async: A flag stating if an asynchronous command is required.
+ *
+ * Return: 0 on Success
+ */
+static int scmi_raw_message_send(struct scmi_raw_mode_info *raw,
+ void *buf, size_t len, u8 chan_id, bool async)
+{
+ int ret;
+ struct scmi_xfer *xfer;
+
+ ret = scmi_xfer_raw_get_init(raw, buf, len, &xfer);
+ if (ret)
+ return ret;
+
+ ret = scmi_do_xfer_raw_start(raw, xfer, chan_id, async);
+ if (ret)
+ scmi_xfer_raw_put(raw->handle, xfer);
+
+ return ret;
+}
+
+static struct scmi_raw_buffer *
+scmi_raw_message_dequeue(struct scmi_raw_queue *q, bool o_nonblock)
+{
+ unsigned long flags;
+ struct scmi_raw_buffer *rb;
+
+ spin_lock_irqsave(&q->msg_q_lock, flags);
+ while (list_empty(&q->msg_q)) {
+ spin_unlock_irqrestore(&q->msg_q_lock, flags);
+
+ if (o_nonblock)
+ return ERR_PTR(-EAGAIN);
+
+ if (wait_event_interruptible(q->wq, !list_empty(&q->msg_q)))
+ return ERR_PTR(-ERESTARTSYS);
+
+ spin_lock_irqsave(&q->msg_q_lock, flags);
+ }
+
+ rb = scmi_raw_buffer_dequeue_unlocked(q);
+
+ spin_unlock_irqrestore(&q->msg_q_lock, flags);
+
+ return rb;
+}
+
+/**
+ * scmi_raw_message_receive - An helper to dequeue and report the next
+ * available enqueued raw message payload that has been collected.
+ *
+ * @raw: A reference to the Raw instance.
+ * @buf: A buffer to get hold of the whole SCMI message received and represented
+ * in little-endian binary format.
+ * @len: Length of @buf.
+ * @size: The effective size of the message copied into @buf
+ * @idx: The index of the queue to pick the next queued message from.
+ * @chan_id: The channel ID to use.
+ * @o_nonblock: A flag to request a non-blocking message dequeue.
+ *
+ * Return: 0 on Success
+ */
+static int scmi_raw_message_receive(struct scmi_raw_mode_info *raw,
+ void *buf, size_t len, size_t *size,
+ unsigned int idx, unsigned int chan_id,
+ bool o_nonblock)
+{
+ int ret = 0;
+ struct scmi_raw_buffer *rb;
+ struct scmi_raw_queue *q;
+
+ q = scmi_raw_queue_select(raw, idx, chan_id);
+ if (!q)
+ return -ENODEV;
+
+ rb = scmi_raw_message_dequeue(q, o_nonblock);
+ if (IS_ERR(rb)) {
+ dev_dbg(raw->handle->dev, "RAW - No message available!\n");
+ return PTR_ERR(rb);
+ }
+
+ if (rb->msg.len <= len) {
+ memcpy(buf, rb->msg.buf, rb->msg.len);
+ *size = rb->msg.len;
+ } else {
+ ret = -ENOSPC;
+ }
+
+ scmi_raw_buffer_put(q, rb);
+
+ return ret;
+}
+
+/* SCMI Raw debugfs helpers */
+
+static ssize_t scmi_dbg_raw_mode_common_read(struct file *filp,
+ char __user *buf,
+ size_t count, loff_t *ppos,
+ unsigned int idx)
+{
+ ssize_t cnt;
+ struct scmi_dbg_raw_data *rd = filp->private_data;
+
+ if (!rd->rx_size) {
+ int ret;
+
+ ret = scmi_raw_message_receive(rd->raw, rd->rx.buf, rd->rx.len,
+ &rd->rx_size, idx, rd->chan_id,
+ filp->f_flags & O_NONBLOCK);
+ if (ret) {
+ rd->rx_size = 0;
+ return ret;
+ }
+
+ /* Reset any previous filepos change, including writes */
+ *ppos = 0;
+ } else if (*ppos == rd->rx_size) {
+ /* Return EOF once all the message has been read-out */
+ rd->rx_size = 0;
+ return 0;
+ }
+
+ cnt = simple_read_from_buffer(buf, count, ppos,
+ rd->rx.buf, rd->rx_size);
+
+ return cnt;
+}
+
+static ssize_t scmi_dbg_raw_mode_common_write(struct file *filp,
+ const char __user *buf,
+ size_t count, loff_t *ppos,
+ bool async)
+{
+ int ret;
+ struct scmi_dbg_raw_data *rd = filp->private_data;
+
+ if (count > rd->tx.len - rd->tx_size)
+ return -ENOSPC;
+
+ /* On first write attempt @count carries the total full message size. */
+ if (!rd->tx_size)
+ rd->tx_req_size = count;
+
+ /*
+ * Gather a full message, possibly across multiple interrupted wrrtes,
+ * before sending it with a single RAW xfer.
+ */
+ if (rd->tx_size < rd->tx_req_size) {
+ size_t cnt;
+
+ cnt = simple_write_to_buffer(rd->tx.buf, rd->tx.len, ppos,
+ buf, count);
+ rd->tx_size += cnt;
+ if (cnt < count)
+ return cnt;
+ }
+
+ ret = scmi_raw_message_send(rd->raw, rd->tx.buf, rd->tx_size,
+ rd->chan_id, async);
+
+ /* Reset ppos for next message ... */
+ rd->tx_size = 0;
+ *ppos = 0;
+
+ return ret ?: count;
+}
+
+static __poll_t scmi_test_dbg_raw_common_poll(struct file *filp,
+ struct poll_table_struct *wait,
+ unsigned int idx)
+{
+ unsigned long flags;
+ struct scmi_dbg_raw_data *rd = filp->private_data;
+ struct scmi_raw_queue *q;
+ __poll_t mask = 0;
+
+ q = scmi_raw_queue_select(rd->raw, idx, rd->chan_id);
+ if (!q)
+ return mask;
+
+ poll_wait(filp, &q->wq, wait);
+
+ spin_lock_irqsave(&q->msg_q_lock, flags);
+ if (!list_empty(&q->msg_q))
+ mask = EPOLLIN | EPOLLRDNORM;
+ spin_unlock_irqrestore(&q->msg_q_lock, flags);
+
+ return mask;
+}
+
+static ssize_t scmi_dbg_raw_mode_message_read(struct file *filp,
+ char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ return scmi_dbg_raw_mode_common_read(filp, buf, count, ppos,
+ SCMI_RAW_REPLY_QUEUE);
+}
+
+static ssize_t scmi_dbg_raw_mode_message_write(struct file *filp,
+ const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ return scmi_dbg_raw_mode_common_write(filp, buf, count, ppos, false);
+}
+
+static __poll_t scmi_dbg_raw_mode_message_poll(struct file *filp,
+ struct poll_table_struct *wait)
+{
+ return scmi_test_dbg_raw_common_poll(filp, wait, SCMI_RAW_REPLY_QUEUE);
+}
+
+static int scmi_dbg_raw_mode_open(struct inode *inode, struct file *filp)
+{
+ u8 id;
+ struct scmi_raw_mode_info *raw;
+ struct scmi_dbg_raw_data *rd;
+ const char *id_str = filp->f_path.dentry->d_parent->d_name.name;
+
+ if (!inode->i_private)
+ return -ENODEV;
+
+ raw = inode->i_private;
+ rd = kzalloc(sizeof(*rd), GFP_KERNEL);
+ if (!rd)
+ return -ENOMEM;
+
+ rd->rx.len = raw->desc->max_msg_size + sizeof(u32);
+ rd->rx.buf = kzalloc(rd->rx.len, GFP_KERNEL);
+ if (!rd->rx.buf) {
+ kfree(rd);
+ return -ENOMEM;
+ }
+
+ rd->tx.len = raw->desc->max_msg_size + sizeof(u32);
+ rd->tx.buf = kzalloc(rd->tx.len, GFP_KERNEL);
+ if (!rd->tx.buf) {
+ kfree(rd->rx.buf);
+ kfree(rd);
+ return -ENOMEM;
+ }
+
+ /* Grab channel ID from debugfs entry naming if any */
+ if (!kstrtou8(id_str, 16, &id))
+ rd->chan_id = id;
+
+ rd->raw = raw;
+ filp->private_data = rd;
+
+ return 0;
+}
+
+static int scmi_dbg_raw_mode_release(struct inode *inode, struct file *filp)
+{
+ struct scmi_dbg_raw_data *rd = filp->private_data;
+
+ kfree(rd->rx.buf);
+ kfree(rd->tx.buf);
+ kfree(rd);
+
+ return 0;
+}
+
+static ssize_t scmi_dbg_raw_mode_reset_write(struct file *filp,
+ const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct scmi_dbg_raw_data *rd = filp->private_data;
+
+ scmi_xfer_raw_reset(rd->raw);
+
+ return count;
+}
+
+static const struct file_operations scmi_dbg_raw_mode_reset_fops = {
+ .open = scmi_dbg_raw_mode_open,
+ .release = scmi_dbg_raw_mode_release,
+ .write = scmi_dbg_raw_mode_reset_write,
+ .owner = THIS_MODULE,
+};
+
+static const struct file_operations scmi_dbg_raw_mode_message_fops = {
+ .open = scmi_dbg_raw_mode_open,
+ .release = scmi_dbg_raw_mode_release,
+ .read = scmi_dbg_raw_mode_message_read,
+ .write = scmi_dbg_raw_mode_message_write,
+ .poll = scmi_dbg_raw_mode_message_poll,
+ .owner = THIS_MODULE,
+};
+
+static ssize_t scmi_dbg_raw_mode_message_async_write(struct file *filp,
+ const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ return scmi_dbg_raw_mode_common_write(filp, buf, count, ppos, true);
+}
+
+static const struct file_operations scmi_dbg_raw_mode_message_async_fops = {
+ .open = scmi_dbg_raw_mode_open,
+ .release = scmi_dbg_raw_mode_release,
+ .read = scmi_dbg_raw_mode_message_read,
+ .write = scmi_dbg_raw_mode_message_async_write,
+ .poll = scmi_dbg_raw_mode_message_poll,
+ .owner = THIS_MODULE,
+};
+
+static ssize_t scmi_test_dbg_raw_mode_notif_read(struct file *filp,
+ char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ return scmi_dbg_raw_mode_common_read(filp, buf, count, ppos,
+ SCMI_RAW_NOTIF_QUEUE);
+}
+
+static __poll_t
+scmi_test_dbg_raw_mode_notif_poll(struct file *filp,
+ struct poll_table_struct *wait)
+{
+ return scmi_test_dbg_raw_common_poll(filp, wait, SCMI_RAW_NOTIF_QUEUE);
+}
+
+static const struct file_operations scmi_dbg_raw_mode_notification_fops = {
+ .open = scmi_dbg_raw_mode_open,
+ .release = scmi_dbg_raw_mode_release,
+ .read = scmi_test_dbg_raw_mode_notif_read,
+ .poll = scmi_test_dbg_raw_mode_notif_poll,
+ .owner = THIS_MODULE,
+};
+
+static ssize_t scmi_test_dbg_raw_mode_errors_read(struct file *filp,
+ char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ return scmi_dbg_raw_mode_common_read(filp, buf, count, ppos,
+ SCMI_RAW_ERRS_QUEUE);
+}
+
+static __poll_t
+scmi_test_dbg_raw_mode_errors_poll(struct file *filp,
+ struct poll_table_struct *wait)
+{
+ return scmi_test_dbg_raw_common_poll(filp, wait, SCMI_RAW_ERRS_QUEUE);
+}
+
+static const struct file_operations scmi_dbg_raw_mode_errors_fops = {
+ .open = scmi_dbg_raw_mode_open,
+ .release = scmi_dbg_raw_mode_release,
+ .read = scmi_test_dbg_raw_mode_errors_read,
+ .poll = scmi_test_dbg_raw_mode_errors_poll,
+ .owner = THIS_MODULE,
+};
+
+static struct scmi_raw_queue *
+scmi_raw_queue_init(struct scmi_raw_mode_info *raw)
+{
+ int i;
+ struct scmi_raw_buffer *rb;
+ struct device *dev = raw->handle->dev;
+ struct scmi_raw_queue *q;
+
+ q = devm_kzalloc(dev, sizeof(*q), GFP_KERNEL);
+ if (!q)
+ return ERR_PTR(-ENOMEM);
+
+ rb = devm_kcalloc(dev, raw->tx_max_msg, sizeof(*rb), GFP_KERNEL);
+ if (!rb)
+ return ERR_PTR(-ENOMEM);
+
+ spin_lock_init(&q->free_bufs_lock);
+ INIT_LIST_HEAD(&q->free_bufs);
+ for (i = 0; i < raw->tx_max_msg; i++, rb++) {
+ rb->max_len = raw->desc->max_msg_size + sizeof(u32);
+ rb->msg.buf = devm_kzalloc(dev, rb->max_len, GFP_KERNEL);
+ if (!rb->msg.buf)
+ return ERR_PTR(-ENOMEM);
+ scmi_raw_buffer_put(q, rb);
+ }
+
+ spin_lock_init(&q->msg_q_lock);
+ INIT_LIST_HEAD(&q->msg_q);
+ init_waitqueue_head(&q->wq);
+
+ return q;
+}
+
+static int scmi_xfer_raw_worker_init(struct scmi_raw_mode_info *raw)
+{
+ int i;
+ struct scmi_xfer_raw_waiter *rw;
+ struct device *dev = raw->handle->dev;
+
+ rw = devm_kcalloc(dev, raw->tx_max_msg, sizeof(*rw), GFP_KERNEL);
+ if (!rw)
+ return -ENOMEM;
+
+ raw->wait_wq = alloc_workqueue("scmi-raw-wait-wq-%d",
+ WQ_UNBOUND | WQ_FREEZABLE |
+ WQ_HIGHPRI, WQ_SYSFS, raw->id);
+ if (!raw->wait_wq)
+ return -ENOMEM;
+
+ mutex_init(&raw->free_mtx);
+ INIT_LIST_HEAD(&raw->free_waiters);
+ mutex_init(&raw->active_mtx);
+ INIT_LIST_HEAD(&raw->active_waiters);
+
+ for (i = 0; i < raw->tx_max_msg; i++, rw++) {
+ init_completion(&rw->async_response);
+ scmi_xfer_raw_waiter_put(raw, rw);
+ }
+ INIT_WORK(&raw->waiters_work, scmi_xfer_raw_worker);
+
+ return 0;
+}
+
+static int scmi_raw_mode_setup(struct scmi_raw_mode_info *raw,
+ u8 *channels, int num_chans)
+{
+ int ret, idx;
+ void *gid;
+ struct device *dev = raw->handle->dev;
+
+ gid = devres_open_group(dev, NULL, GFP_KERNEL);
+ if (!gid)
+ return -ENOMEM;
+
+ for (idx = 0; idx < SCMI_RAW_MAX_QUEUE; idx++) {
+ raw->q[idx] = scmi_raw_queue_init(raw);
+ if (IS_ERR(raw->q[idx])) {
+ ret = PTR_ERR(raw->q[idx]);
+ goto err;
+ }
+ }
+
+ xa_init(&raw->chans_q);
+ if (num_chans > 1) {
+ int i;
+
+ for (i = 0; i < num_chans; i++) {
+ void *xret;
+ struct scmi_raw_queue *q;
+
+ q = scmi_raw_queue_init(raw);
+ if (IS_ERR(q)) {
+ ret = PTR_ERR(q);
+ goto err_xa;
+ }
+
+ xret = xa_store(&raw->chans_q, channels[i], q,
+ GFP_KERNEL);
+ if (xa_err(xret)) {
+ dev_err(dev,
+ "Fail to allocate Raw queue 0x%02X\n",
+ channels[i]);
+ ret = xa_err(xret);
+ goto err_xa;
+ }
+ }
+ }
+
+ ret = scmi_xfer_raw_worker_init(raw);
+ if (ret)
+ goto err_xa;
+
+ devres_close_group(dev, gid);
+ raw->gid = gid;
+
+ return 0;
+
+err_xa:
+ xa_destroy(&raw->chans_q);
+err:
+ devres_release_group(dev, gid);
+ return ret;
+}
+
+/**
+ * scmi_raw_mode_init - Function to initialize the SCMI Raw stack
+ *
+ * @handle: Pointer to SCMI entity handle
+ * @top_dentry: A reference to the top Raw debugfs dentry
+ * @instance_id: The ID of the underlying SCMI platform instance represented by
+ * this Raw instance
+ * @channels: The list of the existing channels
+ * @num_chans: The number of entries in @channels
+ * @desc: Reference to the transport operations
+ * @tx_max_msg: Max number of in-flight messages allowed by the transport
+ *
+ * This function prepare the SCMI Raw stack and creates the debugfs API.
+ *
+ * Return: An opaque handle to the Raw instance on Success, an ERR_PTR otherwise
+ */
+void *scmi_raw_mode_init(const struct scmi_handle *handle,
+ struct dentry *top_dentry, int instance_id,
+ u8 *channels, int num_chans,
+ const struct scmi_desc *desc, int tx_max_msg)
+{
+ int ret;
+ struct scmi_raw_mode_info *raw;
+ struct device *dev;
+
+ if (!handle || !desc)
+ return ERR_PTR(-EINVAL);
+
+ dev = handle->dev;
+ raw = devm_kzalloc(dev, sizeof(*raw), GFP_KERNEL);
+ if (!raw)
+ return ERR_PTR(-ENOMEM);
+
+ raw->handle = handle;
+ raw->desc = desc;
+ raw->tx_max_msg = tx_max_msg;
+ raw->id = instance_id;
+
+ ret = scmi_raw_mode_setup(raw, channels, num_chans);
+ if (ret) {
+ devm_kfree(dev, raw);
+ return ERR_PTR(ret);
+ }
+
+ raw->dentry = debugfs_create_dir("raw", top_dentry);
+
+ debugfs_create_file("reset", 0200, raw->dentry, raw,
+ &scmi_dbg_raw_mode_reset_fops);
+
+ debugfs_create_file("message", 0600, raw->dentry, raw,
+ &scmi_dbg_raw_mode_message_fops);
+
+ debugfs_create_file("message_async", 0600, raw->dentry, raw,
+ &scmi_dbg_raw_mode_message_async_fops);
+
+ debugfs_create_file("notification", 0400, raw->dentry, raw,
+ &scmi_dbg_raw_mode_notification_fops);
+
+ debugfs_create_file("errors", 0400, raw->dentry, raw,
+ &scmi_dbg_raw_mode_errors_fops);
+
+ /*
+ * Expose per-channel entries if multiple channels available.
+ * Just ignore errors while setting up these interfaces since we
+ * have anyway already a working core Raw support.
+ */
+ if (num_chans > 1) {
+ int i;
+ struct dentry *top_chans;
+
+ top_chans = debugfs_create_dir("channels", raw->dentry);
+
+ for (i = 0; i < num_chans; i++) {
+ char cdir[8];
+ struct dentry *chd;
+
+ snprintf(cdir, 8, "0x%02X", channels[i]);
+ chd = debugfs_create_dir(cdir, top_chans);
+
+ debugfs_create_file("message", 0600, chd, raw,
+ &scmi_dbg_raw_mode_message_fops);
+
+ debugfs_create_file("message_async", 0600, chd, raw,
+ &scmi_dbg_raw_mode_message_async_fops);
+ }
+ }
+
+ dev_info(dev, "SCMI RAW Mode initialized for instance %d\n", raw->id);
+
+ return raw;
+}
+
+/**
+ * scmi_raw_mode_cleanup - Function to cleanup the SCMI Raw stack
+ *
+ * @r: An opaque handle to an initialized SCMI Raw instance
+ */
+void scmi_raw_mode_cleanup(void *r)
+{
+ struct scmi_raw_mode_info *raw = r;
+
+ if (!raw)
+ return;
+
+ debugfs_remove_recursive(raw->dentry);
+
+ cancel_work_sync(&raw->waiters_work);
+ destroy_workqueue(raw->wait_wq);
+ xa_destroy(&raw->chans_q);
+}
+
+static int scmi_xfer_raw_collect(void *msg, size_t *msg_len,
+ struct scmi_xfer *xfer)
+{
+ __le32 *m;
+ size_t msg_size;
+
+ if (!xfer || !msg || !msg_len)
+ return -EINVAL;
+
+ /* Account for hdr ...*/
+ msg_size = xfer->rx.len + sizeof(u32);
+ /* ... and status if needed */
+ if (xfer->hdr.type != MSG_TYPE_NOTIFICATION)
+ msg_size += sizeof(u32);
+
+ if (msg_size > *msg_len)
+ return -ENOSPC;
+
+ m = msg;
+ *m = cpu_to_le32(pack_scmi_header(&xfer->hdr));
+ if (xfer->hdr.type != MSG_TYPE_NOTIFICATION)
+ *++m = cpu_to_le32(xfer->hdr.status);
+
+ memcpy(++m, xfer->rx.buf, xfer->rx.len);
+
+ *msg_len = msg_size;
+
+ return 0;
+}
+
+/**
+ * scmi_raw_message_report - Helper to report back valid reponses/notifications
+ * to raw message requests.
+ *
+ * @r: An opaque reference to the raw instance configuration
+ * @xfer: The xfer containing the message to be reported
+ * @idx: The index of the queue.
+ * @chan_id: The channel ID to use.
+ *
+ * If Raw mode is enabled, this is called from the SCMI core on the regular RX
+ * path to save and enqueue the response/notification payload carried by this
+ * xfer into a dedicated scmi_raw_buffer for later consumption by the user.
+ *
+ * This way the caller can free the related xfer immediately afterwards and the
+ * user can read back the raw message payload at its own pace (if ever) without
+ * holding an xfer for too long.
+ */
+void scmi_raw_message_report(void *r, struct scmi_xfer *xfer,
+ unsigned int idx, unsigned int chan_id)
+{
+ int ret;
+ unsigned long flags;
+ struct scmi_raw_buffer *rb;
+ struct device *dev;
+ struct scmi_raw_queue *q;
+ struct scmi_raw_mode_info *raw = r;
+
+ if (!raw || (idx == SCMI_RAW_REPLY_QUEUE && !SCMI_XFER_IS_RAW(xfer)))
+ return;
+
+ dev = raw->handle->dev;
+ q = scmi_raw_queue_select(raw, idx,
+ SCMI_XFER_IS_CHAN_SET(xfer) ? chan_id : 0);
+
+ /*
+ * Grab the msg_q_lock upfront to avoid a possible race between
+ * realizing the free list was empty and effectively picking the next
+ * buffer to use from the oldest one enqueued and still unread on this
+ * msg_q.
+ *
+ * Note that nowhere else these locks are taken together, so no risk of
+ * deadlocks du eto inversion.
+ */
+ spin_lock_irqsave(&q->msg_q_lock, flags);
+ rb = scmi_raw_buffer_get(q);
+ if (!rb) {
+ /*
+ * Immediate and delayed replies to previously injected Raw
+ * commands MUST be read back from userspace to free the buffers:
+ * if this is not happening something is seriously broken and
+ * must be fixed at the application level: complain loudly.
+ */
+ if (idx == SCMI_RAW_REPLY_QUEUE) {
+ spin_unlock_irqrestore(&q->msg_q_lock, flags);
+ dev_warn(dev,
+ "RAW[%d] - Buffers exhausted. Dropping report.\n",
+ idx);
+ return;
+ }
+
+ /*
+ * Notifications and errors queues are instead handled in a
+ * circular manner: unread old buffers are just overwritten by
+ * newer ones.
+ *
+ * The main reason for this is that notifications originated
+ * by Raw requests cannot be distinguished from normal ones, so
+ * your Raw buffers queues risk to be flooded and depleted by
+ * notifications if you left it mistakenly enabled or when in
+ * coexistence mode.
+ */
+ rb = scmi_raw_buffer_dequeue_unlocked(q);
+ if (WARN_ON(!rb)) {
+ spin_unlock_irqrestore(&q->msg_q_lock, flags);
+ return;
+ }
+
+ /* Reset to full buffer length */
+ rb->msg.len = rb->max_len;
+
+ dev_warn_once(dev,
+ "RAW[%d] - Buffers exhausted. Re-using oldest.\n",
+ idx);
+ }
+ spin_unlock_irqrestore(&q->msg_q_lock, flags);
+
+ ret = scmi_xfer_raw_collect(rb->msg.buf, &rb->msg.len, xfer);
+ if (ret) {
+ dev_warn(dev, "RAW - Cannot collect xfer into buffer !\n");
+ scmi_raw_buffer_put(q, rb);
+ return;
+ }
+
+ scmi_raw_buffer_enqueue(q, rb);
+}
+
+static void scmi_xfer_raw_fill(struct scmi_raw_mode_info *raw,
+ struct scmi_chan_info *cinfo,
+ struct scmi_xfer *xfer, u32 msg_hdr)
+{
+ /* Unpack received HDR as it is */
+ unpack_scmi_header(msg_hdr, &xfer->hdr);
+ xfer->hdr.seq = MSG_XTRACT_TOKEN(msg_hdr);
+
+ memset(xfer->rx.buf, 0x00, xfer->rx.len);
+
+ raw->desc->ops->fetch_response(cinfo, xfer);
+}
+
+/**
+ * scmi_raw_error_report - Helper to report back timed-out or generally
+ * unexpected replies.
+ *
+ * @r: An opaque reference to the raw instance configuration
+ * @cinfo: A reference to the channel to use to retrieve the broken xfer
+ * @msg_hdr: The SCMI message header of the message to fetch and report
+ * @priv: Any private data related to the xfer.
+ *
+ * If Raw mode is enabled, this is called from the SCMI core on the RX path in
+ * case of errors to save and enqueue the bad message payload carried by the
+ * message that has just been received.
+ *
+ * Note that we have to manually fetch any available payload into a temporary
+ * xfer to be able to save and enqueue the message, since the regular RX error
+ * path which had called this would have not fetched the message payload having
+ * classified it as an error.
+ */
+void scmi_raw_error_report(void *r, struct scmi_chan_info *cinfo,
+ u32 msg_hdr, void *priv)
+{
+ struct scmi_xfer xfer;
+ struct scmi_raw_mode_info *raw = r;
+
+ if (!raw)
+ return;
+
+ xfer.rx.len = raw->desc->max_msg_size;
+ xfer.rx.buf = kzalloc(xfer.rx.len, GFP_ATOMIC);
+ if (!xfer.rx.buf) {
+ dev_info(raw->handle->dev,
+ "Cannot report Raw error for HDR:0x%X - ENOMEM\n",
+ msg_hdr);
+ return;
+ }
+
+ /* Any transport-provided priv must be passed back down to transport */
+ if (priv)
+ /* Ensure priv is visible */
+ smp_store_mb(xfer.priv, priv);
+
+ scmi_xfer_raw_fill(raw, cinfo, &xfer, msg_hdr);
+ scmi_raw_message_report(raw, &xfer, SCMI_RAW_ERRS_QUEUE, 0);
+
+ kfree(xfer.rx.buf);
+}
diff --git a/drivers/firmware/arm_scmi/raw_mode.h b/drivers/firmware/arm_scmi/raw_mode.h
new file mode 100644
index 000000000000..8af756a83fd1
--- /dev/null
+++ b/drivers/firmware/arm_scmi/raw_mode.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * System Control and Management Interface (SCMI) Message Protocol
+ * Raw mode support header.
+ *
+ * Copyright (C) 2022 ARM Ltd.
+ */
+#ifndef _SCMI_RAW_MODE_H
+#define _SCMI_RAW_MODE_H
+
+#include "common.h"
+
+enum {
+ SCMI_RAW_REPLY_QUEUE,
+ SCMI_RAW_NOTIF_QUEUE,
+ SCMI_RAW_ERRS_QUEUE,
+ SCMI_RAW_MAX_QUEUE
+};
+
+void *scmi_raw_mode_init(const struct scmi_handle *handle,
+ struct dentry *top_dentry, int instance_id,
+ u8 *channels, int num_chans,
+ const struct scmi_desc *desc, int tx_max_msg);
+void scmi_raw_mode_cleanup(void *raw);
+
+void scmi_raw_message_report(void *raw, struct scmi_xfer *xfer,
+ unsigned int idx, unsigned int chan_id);
+void scmi_raw_error_report(void *raw, struct scmi_chan_info *cinfo,
+ u32 msg_hdr, void *priv);
+
+#endif /* _SCMI_RAW_MODE_H */
diff --git a/drivers/firmware/arm_scmi/smc.c b/drivers/firmware/arm_scmi/smc.c
index 87a7b13cf868..93272e4bbd12 100644
--- a/drivers/firmware/arm_scmi/smc.c
+++ b/drivers/firmware/arm_scmi/smc.c
@@ -52,9 +52,9 @@ static irqreturn_t smc_msg_done_isr(int irq, void *data)
return IRQ_HANDLED;
}
-static bool smc_chan_available(struct device *dev, int idx)
+static bool smc_chan_available(struct device_node *of_node, int idx)
{
- struct device_node *np = of_parse_phandle(dev->of_node, "shmem", 0);
+ struct device_node *np = of_parse_phandle(of_node, "shmem", 0);
if (!np)
return false;
@@ -171,8 +171,6 @@ static int smc_chan_free(int id, void *p, void *data)
cinfo->transport_info = NULL;
scmi_info->cinfo = NULL;
- scmi_free_channel(cinfo, data, id);
-
return 0;
}
diff --git a/drivers/firmware/arm_scmi/virtio.c b/drivers/firmware/arm_scmi/virtio.c
index 1db975c08896..d68c01cb7aa0 100644
--- a/drivers/firmware/arm_scmi/virtio.c
+++ b/drivers/firmware/arm_scmi/virtio.c
@@ -385,7 +385,7 @@ static int virtio_link_supplier(struct device *dev)
return 0;
}
-static bool virtio_chan_available(struct device *dev, int idx)
+static bool virtio_chan_available(struct device_node *of_node, int idx)
{
struct scmi_vio_channel *channels, *vioch = NULL;
@@ -489,8 +489,6 @@ static int virtio_chan_free(int id, void *p, void *data)
virtio_break_device(vioch->vqueue->vdev);
scmi_vio_channel_cleanup_sync(vioch);
- scmi_free_channel(cinfo, data, id);
-
return 0;
}
diff --git a/drivers/firmware/dmi-sysfs.c b/drivers/firmware/dmi-sysfs.c
index 66727ad3361b..ed5aff0a4204 100644
--- a/drivers/firmware/dmi-sysfs.c
+++ b/drivers/firmware/dmi-sysfs.c
@@ -418,10 +418,10 @@ static ssize_t dmi_sel_raw_read_helper(struct dmi_sysfs_entry *entry,
return dmi_sel_raw_read_phys32(entry, &sel, state->buf,
state->pos, state->count);
case DMI_SEL_ACCESS_METHOD_GPNV:
- pr_info("dmi-sysfs: GPNV support missing.\n");
+ pr_info_ratelimited("dmi-sysfs: GPNV support missing.\n");
return -EIO;
default:
- pr_info("dmi-sysfs: Unknown access method %02x\n",
+ pr_info_ratelimited("dmi-sysfs: Unknown access method %02x\n",
sel.access_method);
return -EIO;
}
@@ -603,16 +603,16 @@ static void __init dmi_sysfs_register_handle(const struct dmi_header *dh,
*ret = kobject_init_and_add(&entry->kobj, &dmi_sysfs_entry_ktype, NULL,
"%d-%d", dh->type, entry->instance);
- if (*ret) {
- kobject_put(&entry->kobj);
- return;
- }
-
/* Thread on the global list for cleanup */
spin_lock(&entry_list_lock);
list_add_tail(&entry->list, &entry_list);
spin_unlock(&entry_list_lock);
+ if (*ret) {
+ kobject_put(&entry->kobj);
+ return;
+ }
+
/* Handle specializations by type */
switch (dh->type) {
case DMI_ENTRY_SYSTEM_EVENT_LOG:
diff --git a/drivers/firmware/efi/cper_cxl.c b/drivers/firmware/efi/cper_cxl.c
index 53e435c4f310..a55771b99a97 100644
--- a/drivers/firmware/efi/cper_cxl.c
+++ b/drivers/firmware/efi/cper_cxl.c
@@ -9,7 +9,6 @@
#include <linux/cper.h>
#include "cper_cxl.h"
-#include <linux/cxl_err.h>
#define PROT_ERR_VALID_AGENT_TYPE BIT_ULL(0)
#define PROT_ERR_VALID_AGENT_ADDRESS BIT_ULL(1)
@@ -19,6 +18,17 @@
#define PROT_ERR_VALID_DVSEC BIT_ULL(5)
#define PROT_ERR_VALID_ERROR_LOG BIT_ULL(6)
+/* CXL RAS Capability Structure, CXL v3.0 sec 8.2.4.16 */
+struct cxl_ras_capability_regs {
+ u32 uncor_status;
+ u32 uncor_mask;
+ u32 uncor_severity;
+ u32 cor_status;
+ u32 cor_mask;
+ u32 cap_control;
+ u32 header_log[16];
+};
+
static const char * const prot_err_agent_type_strs[] = {
"Restricted CXL Device",
"Restricted CXL Host Downstream Port",
diff --git a/drivers/firmware/efi/earlycon.c b/drivers/firmware/efi/earlycon.c
index 4d6c5327471a..f54e6fdf08e2 100644
--- a/drivers/firmware/efi/earlycon.c
+++ b/drivers/firmware/efi/earlycon.c
@@ -10,11 +10,14 @@
#include <linux/kernel.h>
#include <linux/serial_core.h>
#include <linux/screen_info.h>
+#include <linux/string.h>
#include <asm/early_ioremap.h>
static const struct console *earlycon_console __initdata;
static const struct font_desc *font;
+static u16 cur_line_y, max_line_y;
+static u32 efi_x_array[1024];
static u32 efi_x, efi_y;
static u64 fb_base;
static bool fb_wb;
@@ -85,9 +88,17 @@ static void efi_earlycon_clear_scanline(unsigned int y)
static void efi_earlycon_scroll_up(void)
{
unsigned long *dst, *src;
+ u16 maxlen = 0;
u16 len;
u32 i, height;
+ /* Find the cached maximum x coordinate */
+ for (i = 0; i < max_line_y; i++) {
+ if (efi_x_array[i] > maxlen)
+ maxlen = efi_x_array[i];
+ }
+ maxlen *= 4;
+
len = screen_info.lfb_linelength;
height = screen_info.lfb_height;
@@ -102,7 +113,7 @@ static void efi_earlycon_scroll_up(void)
return;
}
- memmove(dst, src, len);
+ memmove(dst, src, maxlen);
efi_earlycon_unmap(src, len);
efi_earlycon_unmap(dst, len);
@@ -135,6 +146,7 @@ static void
efi_earlycon_write(struct console *con, const char *str, unsigned int num)
{
struct screen_info *si;
+ u32 cur_efi_x = efi_x;
unsigned int len;
const char *s;
void *dst;
@@ -143,16 +155,10 @@ efi_earlycon_write(struct console *con, const char *str, unsigned int num)
len = si->lfb_linelength;
while (num) {
- unsigned int linemax;
- unsigned int h, count = 0;
-
- for (s = str; *s && *s != '\n'; s++) {
- if (count == num)
- break;
- count++;
- }
+ unsigned int linemax = (si->lfb_width - efi_x) / font->width;
+ unsigned int h, count;
- linemax = (si->lfb_width - efi_x) / font->width;
+ count = strnchrnul(str, num, '\n') - str;
if (count > linemax)
count = linemax;
@@ -181,6 +187,7 @@ efi_earlycon_write(struct console *con, const char *str, unsigned int num)
str += count;
if (num > 0 && *s == '\n') {
+ cur_efi_x = efi_x;
efi_x = 0;
efi_y += font->height;
str++;
@@ -188,6 +195,7 @@ efi_earlycon_write(struct console *con, const char *str, unsigned int num)
}
if (efi_x + font->width > si->lfb_width) {
+ cur_efi_x = efi_x;
efi_x = 0;
efi_y += font->height;
}
@@ -195,6 +203,9 @@ efi_earlycon_write(struct console *con, const char *str, unsigned int num)
if (efi_y + font->height > si->lfb_height) {
u32 i;
+ efi_x_array[cur_line_y] = cur_efi_x;
+ cur_line_y = (cur_line_y + 1) % max_line_y;
+
efi_y -= font->height;
efi_earlycon_scroll_up();
@@ -235,7 +246,15 @@ static int __init efi_earlycon_setup(struct earlycon_device *device,
if (!font)
return -ENODEV;
- efi_y = rounddown(yres, font->height) - font->height;
+ /* Fill the cache with maximum possible value of x coordinate */
+ memset32(efi_x_array, rounddown(xres, font->width), ARRAY_SIZE(efi_x_array));
+ efi_y = rounddown(yres, font->height);
+
+ /* Make sure we have cache for the x coordinate for the full screen */
+ max_line_y = efi_y / font->height + 1;
+ cur_line_y = 0;
+
+ efi_y -= font->height;
for (i = 0; i < (yres - efi_y) / font->height; i++)
efi_earlycon_scroll_up();
diff --git a/drivers/firmware/efi/efi-init.c b/drivers/firmware/efi/efi-init.c
index 1639159493e3..2c16080e1f71 100644
--- a/drivers/firmware/efi/efi-init.c
+++ b/drivers/firmware/efi/efi-init.c
@@ -92,7 +92,7 @@ static int __init uefi_init(u64 efi_system_table)
if (IS_ENABLED(CONFIG_64BIT))
set_bit(EFI_64BIT, &efi.flags);
- retval = efi_systab_check_header(&systab->hdr, 2);
+ retval = efi_systab_check_header(&systab->hdr);
if (retval)
goto out;
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index 1e0b016fdc2b..abeff7dc0b58 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -187,8 +187,27 @@ static const struct attribute_group efi_subsys_attr_group = {
static struct efivars generic_efivars;
static struct efivar_operations generic_ops;
+static bool generic_ops_supported(void)
+{
+ unsigned long name_size;
+ efi_status_t status;
+ efi_char16_t name;
+ efi_guid_t guid;
+
+ name_size = sizeof(name);
+
+ status = efi.get_next_variable(&name_size, &name, &guid);
+ if (status == EFI_UNSUPPORTED)
+ return false;
+
+ return true;
+}
+
static int generic_ops_register(void)
{
+ if (!generic_ops_supported())
+ return 0;
+
generic_ops.get_variable = efi.get_variable;
generic_ops.get_next_variable = efi.get_next_variable;
generic_ops.query_variable_store = efi_query_variable_store;
@@ -197,11 +216,14 @@ static int generic_ops_register(void)
generic_ops.set_variable = efi.set_variable;
generic_ops.set_variable_nonblocking = efi.set_variable_nonblocking;
}
- return efivars_register(&generic_efivars, &generic_ops, efi_kobj);
+ return efivars_register(&generic_efivars, &generic_ops);
}
static void generic_ops_unregister(void)
{
+ if (!generic_ops.get_variable)
+ return;
+
efivars_unregister(&generic_efivars);
}
@@ -481,7 +503,7 @@ void __init efi_find_mirror(void)
* and if so, populate the supplied memory descriptor with the appropriate
* data.
*/
-int efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md)
+int __efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md)
{
efi_memory_desc_t *md;
@@ -499,6 +521,12 @@ int efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md)
u64 size;
u64 end;
+ /* skip bogus entries (including empty ones) */
+ if ((md->phys_addr & (EFI_PAGE_SIZE - 1)) ||
+ (md->num_pages <= 0) ||
+ (md->num_pages > (U64_MAX - md->phys_addr) >> EFI_PAGE_SHIFT))
+ continue;
+
size = md->num_pages << EFI_PAGE_SHIFT;
end = md->phys_addr + size;
if (phys_addr >= md->phys_addr && phys_addr < end) {
@@ -509,6 +537,9 @@ int efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md)
return -ENOENT;
}
+extern int efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md)
+ __weak __alias(__efi_mem_desc_lookup);
+
/*
* Calculate the highest address of an efi memory descriptor.
*/
@@ -535,6 +566,10 @@ void __init __weak efi_arch_mem_reserve(phys_addr_t addr, u64 size) {}
*/
void __init efi_mem_reserve(phys_addr_t addr, u64 size)
{
+ /* efi_mem_reserve() does not work under Xen */
+ if (WARN_ON_ONCE(efi_enabled(EFI_PARAVIRT)))
+ return;
+
if (!memblock_is_region_reserved(addr, size))
memblock_reserve(addr, size);
@@ -583,13 +618,20 @@ static __init int match_config_table(const efi_guid_t *guid,
int i;
for (i = 0; efi_guidcmp(table_types[i].guid, NULL_GUID); i++) {
- if (!efi_guidcmp(*guid, table_types[i].guid)) {
- *(table_types[i].ptr) = table;
+ if (efi_guidcmp(*guid, table_types[i].guid))
+ continue;
+
+ if (!efi_config_table_is_usable(guid, table)) {
if (table_types[i].name[0])
- pr_cont("%s=0x%lx ",
+ pr_cont("(%s=0x%lx unusable) ",
table_types[i].name, table);
return 1;
}
+
+ *(table_types[i].ptr) = table;
+ if (table_types[i].name[0])
+ pr_cont("%s=0x%lx ", table_types[i].name, table);
+ return 1;
}
return 0;
@@ -720,20 +762,13 @@ int __init efi_config_parse_tables(const efi_config_table_t *config_tables,
return 0;
}
-int __init efi_systab_check_header(const efi_table_hdr_t *systab_hdr,
- int min_major_version)
+int __init efi_systab_check_header(const efi_table_hdr_t *systab_hdr)
{
if (systab_hdr->signature != EFI_SYSTEM_TABLE_SIGNATURE) {
pr_err("System table signature incorrect!\n");
return -EINVAL;
}
- if ((systab_hdr->revision >> 16) < min_major_version)
- pr_err("Warning: System table version %d.%02d, expected %d.00 or greater!\n",
- systab_hdr->revision >> 16,
- systab_hdr->revision & 0xffff,
- min_major_version);
-
return 0;
}
@@ -764,6 +799,7 @@ void __init efi_systab_report_header(const efi_table_hdr_t *systab_hdr,
char vendor[100] = "unknown";
const efi_char16_t *c16;
size_t i;
+ u16 rev;
c16 = map_fw_vendor(fw_vendor, sizeof(vendor) * sizeof(efi_char16_t));
if (c16) {
@@ -774,10 +810,14 @@ void __init efi_systab_report_header(const efi_table_hdr_t *systab_hdr,
unmap_fw_vendor(c16, sizeof(vendor) * sizeof(efi_char16_t));
}
- pr_info("EFI v%u.%.02u by %s\n",
- systab_hdr->revision >> 16,
- systab_hdr->revision & 0xffff,
- vendor);
+ rev = (u16)systab_hdr->revision;
+ pr_info("EFI v%u.%u", systab_hdr->revision >> 16, rev / 10);
+
+ rev %= 10;
+ if (rev)
+ pr_cont(".%u", rev);
+
+ pr_cont(" by %s\n", vendor);
if (IS_ENABLED(CONFIG_X86_64) &&
systab_hdr->revision > EFI_1_10_SYSTEM_TABLE_REVISION &&
diff --git a/drivers/firmware/efi/esrt.c b/drivers/firmware/efi/esrt.c
index 2a2f52b017e7..87729c365be1 100644
--- a/drivers/firmware/efi/esrt.c
+++ b/drivers/firmware/efi/esrt.c
@@ -247,7 +247,7 @@ void __init efi_esrt_init(void)
int rc;
phys_addr_t end;
- if (!efi_enabled(EFI_MEMMAP))
+ if (!efi_enabled(EFI_MEMMAP) && !efi_enabled(EFI_PARAVIRT))
return;
pr_debug("esrt-init: loading.\n");
@@ -258,20 +258,15 @@ void __init efi_esrt_init(void)
if (rc < 0 ||
(!(md.attribute & EFI_MEMORY_RUNTIME) &&
md.type != EFI_BOOT_SERVICES_DATA &&
- md.type != EFI_RUNTIME_SERVICES_DATA)) {
+ md.type != EFI_RUNTIME_SERVICES_DATA &&
+ md.type != EFI_ACPI_RECLAIM_MEMORY &&
+ md.type != EFI_ACPI_MEMORY_NVS)) {
pr_warn("ESRT header is not in the memory map.\n");
return;
}
- max = efi_mem_desc_end(&md);
- if (max < efi.esrt) {
- pr_err("EFI memory descriptor is invalid. (esrt: %p max: %p)\n",
- (void *)efi.esrt, (void *)max);
- return;
- }
-
+ max = efi_mem_desc_end(&md) - efi.esrt;
size = sizeof(*esrt);
- max -= efi.esrt;
if (max < size) {
pr_err("ESRT header doesn't fit on single memory map entry. (size: %zu max: %zu)\n",
diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c
index f5a4bdacac64..1e0203d74691 100644
--- a/drivers/firmware/efi/libstub/efi-stub-helper.c
+++ b/drivers/firmware/efi/libstub/efi-stub-helper.c
@@ -651,3 +651,70 @@ efi_status_t efi_wait_for_key(unsigned long usec, efi_input_key_t *key)
return status;
}
+
+/**
+ * efi_remap_image - Remap a loaded image with the appropriate permissions
+ * for code and data
+ *
+ * @image_base: the base of the image in memory
+ * @alloc_size: the size of the area in memory occupied by the image
+ * @code_size: the size of the leading part of the image containing code
+ * and read-only data
+ *
+ * efi_remap_image() uses the EFI memory attribute protocol to remap the code
+ * region of the loaded image read-only/executable, and the remainder
+ * read-write/non-executable. The code region is assumed to start at the base
+ * of the image, and will therefore cover the PE/COFF header as well.
+ */
+void efi_remap_image(unsigned long image_base, unsigned alloc_size,
+ unsigned long code_size)
+{
+ efi_guid_t guid = EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID;
+ efi_memory_attribute_protocol_t *memattr;
+ efi_status_t status;
+ u64 attr;
+
+ /*
+ * If the firmware implements the EFI_MEMORY_ATTRIBUTE_PROTOCOL, let's
+ * invoke it to remap the text/rodata region of the decompressed image
+ * as read-only and the data/bss region as non-executable.
+ */
+ status = efi_bs_call(locate_protocol, &guid, NULL, (void **)&memattr);
+ if (status != EFI_SUCCESS)
+ return;
+
+ // Get the current attributes for the entire region
+ status = memattr->get_memory_attributes(memattr, image_base,
+ alloc_size, &attr);
+ if (status != EFI_SUCCESS) {
+ efi_warn("Failed to retrieve memory attributes for image region: 0x%lx\n",
+ status);
+ return;
+ }
+
+ // Mark the code region as read-only
+ status = memattr->set_memory_attributes(memattr, image_base, code_size,
+ EFI_MEMORY_RO);
+ if (status != EFI_SUCCESS) {
+ efi_warn("Failed to remap code region read-only\n");
+ return;
+ }
+
+ // If the entire region was already mapped as non-exec, clear the
+ // attribute from the code region. Otherwise, set it on the data
+ // region.
+ if (attr & EFI_MEMORY_XP) {
+ status = memattr->clear_memory_attributes(memattr, image_base,
+ code_size,
+ EFI_MEMORY_XP);
+ if (status != EFI_SUCCESS)
+ efi_warn("Failed to remap code region executable\n");
+ } else {
+ status = memattr->set_memory_attributes(memattr,
+ image_base + code_size,
+ alloc_size - code_size,
+ EFI_MEMORY_XP);
+ if (status != EFI_SUCCESS)
+ efi_warn("Failed to remap data region non-executable\n");
+ }
+}
diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
index 5b8f2c411ed8..6bd3bb86d967 100644
--- a/drivers/firmware/efi/libstub/efistub.h
+++ b/drivers/firmware/efi/libstub/efistub.h
@@ -442,6 +442,26 @@ union efi_dxe_services_table {
} mixed_mode;
};
+typedef union efi_memory_attribute_protocol efi_memory_attribute_protocol_t;
+
+union efi_memory_attribute_protocol {
+ struct {
+ efi_status_t (__efiapi *get_memory_attributes)(
+ efi_memory_attribute_protocol_t *, efi_physical_addr_t, u64, u64 *);
+
+ efi_status_t (__efiapi *set_memory_attributes)(
+ efi_memory_attribute_protocol_t *, efi_physical_addr_t, u64, u64);
+
+ efi_status_t (__efiapi *clear_memory_attributes)(
+ efi_memory_attribute_protocol_t *, efi_physical_addr_t, u64, u64);
+ };
+ struct {
+ u32 get_memory_attributes;
+ u32 set_memory_attributes;
+ u32 clear_memory_attributes;
+ } mixed_mode;
+};
+
typedef union efi_uga_draw_protocol efi_uga_draw_protocol_t;
union efi_uga_draw_protocol {
@@ -1076,4 +1096,7 @@ struct efi_smbios_type1_record {
const u8 *__efi_get_smbios_string(u8 type, int offset, int recsize);
+void efi_remap_image(unsigned long image_base, unsigned alloc_size,
+ unsigned long code_size);
+
#endif
diff --git a/drivers/firmware/efi/libstub/zboot.c b/drivers/firmware/efi/libstub/zboot.c
index 66be5fdc6b58..ba234e062a1a 100644
--- a/drivers/firmware/efi/libstub/zboot.c
+++ b/drivers/firmware/efi/libstub/zboot.c
@@ -137,6 +137,8 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab)
efi_cache_sync_image(image_base, alloc_size, code_size);
+ efi_remap_image(image_base, alloc_size, code_size);
+
status = efi_stub_common(handle, image, image_base, cmdline_ptr);
free_image:
diff --git a/drivers/firmware/efi/memattr.c b/drivers/firmware/efi/memattr.c
index f178b2984dfb..ab85bf8e165a 100644
--- a/drivers/firmware/efi/memattr.c
+++ b/drivers/firmware/efi/memattr.c
@@ -129,6 +129,7 @@ int __init efi_memattr_apply_permissions(struct mm_struct *mm,
efi_memattr_perm_setter fn)
{
efi_memory_attributes_table_t *tbl;
+ bool has_bti = false;
int i, ret;
if (tbl_size <= sizeof(*tbl))
@@ -150,6 +151,10 @@ int __init efi_memattr_apply_permissions(struct mm_struct *mm,
return -ENOMEM;
}
+ if (tbl->version > 1 &&
+ (tbl->flags & EFI_MEMORY_ATTRIBUTES_FLAGS_RT_FORWARD_CONTROL_FLOW_GUARD))
+ has_bti = true;
+
if (efi_enabled(EFI_DBG))
pr_info("Processing EFI Memory Attributes table:\n");
@@ -169,7 +174,7 @@ int __init efi_memattr_apply_permissions(struct mm_struct *mm,
efi_md_typeattr_format(buf, sizeof(buf), &md));
if (valid) {
- ret = fn(mm, &md);
+ ret = fn(mm, &md, has_bti);
if (ret)
pr_err("Error updating mappings, skipping subsequent md's\n");
}
diff --git a/drivers/firmware/efi/sysfb_efi.c b/drivers/firmware/efi/sysfb_efi.c
index 7882d4b3f2be..f06fdacc9bc8 100644
--- a/drivers/firmware/efi/sysfb_efi.c
+++ b/drivers/firmware/efi/sysfb_efi.c
@@ -264,6 +264,14 @@ static const struct dmi_system_id efifb_dmi_swap_width_height[] __initconst = {
"Lenovo ideapad D330-10IGM"),
},
},
+ {
+ /* Lenovo IdeaPad Duet 3 10IGL5 with 1200x1920 portrait screen */
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_VERSION,
+ "IdeaPad Duet 3 10IGL5"),
+ },
+ },
{},
};
diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c
index 0ba9f18312f5..bd75b87f5fc1 100644
--- a/drivers/firmware/efi/vars.c
+++ b/drivers/firmware/efi/vars.c
@@ -6,6 +6,8 @@
* Copyright (C) 2004 Intel Corporation <matthew.e.tolentino@intel.com>
*/
+#define pr_fmt(fmt) "efivars: " fmt
+
#include <linux/types.h>
#include <linux/sizes.h>
#include <linux/errno.h>
@@ -40,45 +42,47 @@ static efi_status_t check_var_size(bool nonblocking, u32 attributes,
}
/**
- * efivars_kobject - get the kobject for the registered efivars
+ * efivar_is_available - check if efivars is available
*
- * If efivars_register() has not been called we return NULL,
- * otherwise return the kobject used at registration time.
+ * @return true iff evivars is currently registered
*/
-struct kobject *efivars_kobject(void)
+bool efivar_is_available(void)
{
- if (!__efivars)
- return NULL;
-
- return __efivars->kobject;
+ return __efivars != NULL;
}
-EXPORT_SYMBOL_GPL(efivars_kobject);
+EXPORT_SYMBOL_GPL(efivar_is_available);
/**
* efivars_register - register an efivars
* @efivars: efivars to register
* @ops: efivars operations
- * @kobject: @efivars-specific kobject
*
* Only a single efivars can be registered at any time.
*/
int efivars_register(struct efivars *efivars,
- const struct efivar_operations *ops,
- struct kobject *kobject)
+ const struct efivar_operations *ops)
{
+ int rv;
+
if (down_interruptible(&efivars_lock))
return -EINTR;
+ if (__efivars) {
+ pr_warn("efivars already registered\n");
+ rv = -EBUSY;
+ goto out;
+ }
+
efivars->ops = ops;
- efivars->kobject = kobject;
__efivars = efivars;
pr_info("Registered efivars operations\n");
-
+ rv = 0;
+out:
up(&efivars_lock);
- return 0;
+ return rv;
}
EXPORT_SYMBOL_GPL(efivars_register);
@@ -97,7 +101,7 @@ int efivars_unregister(struct efivars *efivars)
return -EINTR;
if (!__efivars) {
- printk(KERN_ERR "efivars not registered\n");
+ pr_err("efivars not registered\n");
rv = -EINVAL;
goto out;
}
@@ -117,7 +121,7 @@ out:
}
EXPORT_SYMBOL_GPL(efivars_unregister);
-int efivar_supports_writes(void)
+bool efivar_supports_writes(void)
{
return __efivars && __efivars->ops->set_variable;
}
diff --git a/drivers/firmware/google/Kconfig b/drivers/firmware/google/Kconfig
index 9f190eab43ed..1bc7cbf2f65d 100644
--- a/drivers/firmware/google/Kconfig
+++ b/drivers/firmware/google/Kconfig
@@ -44,14 +44,6 @@ config GOOGLE_COREBOOT_TABLE
device tree node /firmware/coreboot.
If unsure say N.
-config GOOGLE_COREBOOT_TABLE_ACPI
- tristate
- select GOOGLE_COREBOOT_TABLE
-
-config GOOGLE_COREBOOT_TABLE_OF
- tristate
- select GOOGLE_COREBOOT_TABLE
-
config GOOGLE_MEMCONSOLE
tristate
depends on GOOGLE_MEMCONSOLE_X86_LEGACY || GOOGLE_MEMCONSOLE_COREBOOT
diff --git a/drivers/firmware/google/framebuffer-coreboot.c b/drivers/firmware/google/framebuffer-coreboot.c
index c6dcc1ef93ac..c323a818805c 100644
--- a/drivers/firmware/google/framebuffer-coreboot.c
+++ b/drivers/firmware/google/framebuffer-coreboot.c
@@ -43,9 +43,7 @@ static int framebuffer_probe(struct coreboot_device *dev)
fb->green_mask_pos == formats[i].green.offset &&
fb->green_mask_size == formats[i].green.length &&
fb->blue_mask_pos == formats[i].blue.offset &&
- fb->blue_mask_size == formats[i].blue.length &&
- fb->reserved_mask_pos == formats[i].transp.offset &&
- fb->reserved_mask_size == formats[i].transp.length)
+ fb->blue_mask_size == formats[i].blue.length)
pdata.format = formats[i].name;
}
if (!pdata.format)
diff --git a/drivers/firmware/google/gsmi.c b/drivers/firmware/google/gsmi.c
index 871bedf533a8..96ea1fa76d35 100644
--- a/drivers/firmware/google/gsmi.c
+++ b/drivers/firmware/google/gsmi.c
@@ -1030,7 +1030,7 @@ static __init int gsmi_init(void)
}
#ifdef CONFIG_EFI
- ret = efivars_register(&efivars, &efivar_ops, gsmi_kobj);
+ ret = efivars_register(&efivars, &efivar_ops);
if (ret) {
printk(KERN_INFO "gsmi: Failed to register efivars\n");
sysfs_remove_files(gsmi_kobj, gsmi_attrs);
diff --git a/drivers/firmware/meson/meson_sm.c b/drivers/firmware/meson/meson_sm.c
index 77aa5c6398aa..3f5ff9ed668e 100644
--- a/drivers/firmware/meson/meson_sm.c
+++ b/drivers/firmware/meson/meson_sm.c
@@ -82,7 +82,7 @@ static void __iomem *meson_sm_map_shmem(u32 cmd_shmem, unsigned int size)
sm_phy_base = __meson_sm_call(cmd_shmem, 0, 0, 0, 0, 0);
if (!sm_phy_base)
- return 0;
+ return NULL;
return ioremap_cache(sm_phy_base, size);
}
diff --git a/drivers/firmware/qcom_scm-legacy.c b/drivers/firmware/qcom_scm-legacy.c
index 9f918b9e6f8f..029e6d117cb8 100644
--- a/drivers/firmware/qcom_scm-legacy.c
+++ b/drivers/firmware/qcom_scm-legacy.c
@@ -9,7 +9,7 @@
#include <linux/mutex.h>
#include <linux/errno.h>
#include <linux/err.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/arm-smccc.h>
#include <linux/dma-mapping.h>
diff --git a/drivers/firmware/qcom_scm-smc.c b/drivers/firmware/qcom_scm-smc.c
index d111833364ba..16cf88acfa8e 100644
--- a/drivers/firmware/qcom_scm-smc.c
+++ b/drivers/firmware/qcom_scm-smc.c
@@ -8,7 +8,7 @@
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/types.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/arm-smccc.h>
#include <linux/dma-mapping.h>
@@ -52,29 +52,97 @@ static void __scm_smc_do_quirk(const struct arm_smccc_args *smc,
} while (res->a0 == QCOM_SCM_INTERRUPTED);
}
-static void __scm_smc_do(const struct arm_smccc_args *smc,
- struct arm_smccc_res *res, bool atomic)
+static void fill_wq_resume_args(struct arm_smccc_args *resume, u32 smc_call_ctx)
{
- int retry_count = 0;
+ memset(resume->args, 0, sizeof(resume->args[0]) * ARRAY_SIZE(resume->args));
+
+ resume->args[0] = ARM_SMCCC_CALL_VAL(ARM_SMCCC_STD_CALL,
+ ARM_SMCCC_SMC_64, ARM_SMCCC_OWNER_SIP,
+ SCM_SMC_FNID(QCOM_SCM_SVC_WAITQ, QCOM_SCM_WAITQ_RESUME));
+
+ resume->args[1] = QCOM_SCM_ARGS(1);
+
+ resume->args[2] = smc_call_ctx;
+}
+
+int scm_get_wq_ctx(u32 *wq_ctx, u32 *flags, u32 *more_pending)
+{
+ int ret;
+ struct arm_smccc_res get_wq_res;
+ struct arm_smccc_args get_wq_ctx = {0};
+
+ get_wq_ctx.args[0] = ARM_SMCCC_CALL_VAL(ARM_SMCCC_STD_CALL,
+ ARM_SMCCC_SMC_64, ARM_SMCCC_OWNER_SIP,
+ SCM_SMC_FNID(QCOM_SCM_SVC_WAITQ, QCOM_SCM_WAITQ_GET_WQ_CTX));
+
+ /* Guaranteed to return only success or error, no WAITQ_* */
+ __scm_smc_do_quirk(&get_wq_ctx, &get_wq_res);
+ ret = get_wq_res.a0;
+ if (ret)
+ return ret;
+
+ *wq_ctx = get_wq_res.a1;
+ *flags = get_wq_res.a2;
+ *more_pending = get_wq_res.a3;
+
+ return 0;
+}
+
+static int __scm_smc_do_quirk_handle_waitq(struct device *dev, struct arm_smccc_args *waitq,
+ struct arm_smccc_res *res)
+{
+ int ret;
+ u32 wq_ctx, smc_call_ctx;
+ struct arm_smccc_args resume;
+ struct arm_smccc_args *smc = waitq;
+
+ do {
+ __scm_smc_do_quirk(smc, res);
+
+ if (res->a0 == QCOM_SCM_WAITQ_SLEEP) {
+ wq_ctx = res->a1;
+ smc_call_ctx = res->a2;
+
+ ret = qcom_scm_wait_for_wq_completion(wq_ctx);
+ if (ret)
+ return ret;
+
+ fill_wq_resume_args(&resume, smc_call_ctx);
+ smc = &resume;
+ }
+ } while (res->a0 == QCOM_SCM_WAITQ_SLEEP);
+
+ return 0;
+}
+
+static int __scm_smc_do(struct device *dev, struct arm_smccc_args *smc,
+ struct arm_smccc_res *res, bool atomic)
+{
+ int ret, retry_count = 0;
if (atomic) {
__scm_smc_do_quirk(smc, res);
- return;
+ return 0;
}
do {
mutex_lock(&qcom_scm_lock);
- __scm_smc_do_quirk(smc, res);
+ ret = __scm_smc_do_quirk_handle_waitq(dev, smc, res);
mutex_unlock(&qcom_scm_lock);
+ if (ret)
+ return ret;
+
if (res->a0 == QCOM_SCM_V2_EBUSY) {
if (retry_count++ > QCOM_SCM_EBUSY_MAX_RETRY)
break;
msleep(QCOM_SCM_EBUSY_WAIT_MS);
}
} while (res->a0 == QCOM_SCM_V2_EBUSY);
+
+ return 0;
}
@@ -83,7 +151,7 @@ int __scm_smc_call(struct device *dev, const struct qcom_scm_desc *desc,
struct qcom_scm_res *res, bool atomic)
{
int arglen = desc->arginfo & 0xf;
- int i;
+ int i, ret;
dma_addr_t args_phys = 0;
void *args_virt = NULL;
size_t alloc_len;
@@ -135,13 +203,17 @@ int __scm_smc_call(struct device *dev, const struct qcom_scm_desc *desc,
smc.args[SCM_SMC_LAST_REG_IDX] = args_phys;
}
- __scm_smc_do(&smc, &smc_res, atomic);
+ /* ret error check follows after args_virt cleanup*/
+ ret = __scm_smc_do(dev, &smc, &smc_res, atomic);
if (args_virt) {
dma_unmap_single(dev, args_phys, alloc_len, DMA_TO_DEVICE);
kfree(args_virt);
}
+ if (ret)
+ return ret;
+
if (res) {
res->result[0] = smc_res.a1;
res->result[1] = smc_res.a2;
diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c
index cdbfe54c8146..468d4d5ab550 100644
--- a/drivers/firmware/qcom_scm.c
+++ b/drivers/firmware/qcom_scm.c
@@ -4,15 +4,18 @@
*/
#include <linux/platform_device.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
#include <linux/cpumask.h>
#include <linux/export.h>
#include <linux/dma-mapping.h>
#include <linux/interconnect.h>
#include <linux/module.h>
#include <linux/types.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/clk.h>
#include <linux/reset-controller.h>
@@ -33,6 +36,7 @@ struct qcom_scm {
struct clk *iface_clk;
struct clk *bus_clk;
struct icc_path *path;
+ struct completion waitq_comp;
struct reset_controller_dev reset;
/* control access to the interconnect path */
@@ -63,6 +67,9 @@ static const u8 qcom_scm_cpu_warm_bits[QCOM_SCM_BOOT_MAX_CPUS] = {
BIT(2), BIT(1), BIT(4), BIT(6)
};
+#define QCOM_SMC_WAITQ_FLAG_WAKE_ONE BIT(0)
+#define QCOM_SMC_WAITQ_FLAG_WAKE_ALL BIT(1)
+
static const char * const qcom_scm_convention_names[] = {
[SMC_CONVENTION_UNKNOWN] = "unknown",
[SMC_CONVENTION_ARM_32] = "smc arm 32",
@@ -1325,11 +1332,79 @@ bool qcom_scm_is_available(void)
}
EXPORT_SYMBOL(qcom_scm_is_available);
+static int qcom_scm_assert_valid_wq_ctx(u32 wq_ctx)
+{
+ /* FW currently only supports a single wq_ctx (zero).
+ * TODO: Update this logic to include dynamic allocation and lookup of
+ * completion structs when FW supports more wq_ctx values.
+ */
+ if (wq_ctx != 0) {
+ dev_err(__scm->dev, "Firmware unexpectedly passed non-zero wq_ctx\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int qcom_scm_wait_for_wq_completion(u32 wq_ctx)
+{
+ int ret;
+
+ ret = qcom_scm_assert_valid_wq_ctx(wq_ctx);
+ if (ret)
+ return ret;
+
+ wait_for_completion(&__scm->waitq_comp);
+
+ return 0;
+}
+
+static int qcom_scm_waitq_wakeup(struct qcom_scm *scm, unsigned int wq_ctx)
+{
+ int ret;
+
+ ret = qcom_scm_assert_valid_wq_ctx(wq_ctx);
+ if (ret)
+ return ret;
+
+ complete(&__scm->waitq_comp);
+
+ return 0;
+}
+
+static irqreturn_t qcom_scm_irq_handler(int irq, void *data)
+{
+ int ret;
+ struct qcom_scm *scm = data;
+ u32 wq_ctx, flags, more_pending = 0;
+
+ do {
+ ret = scm_get_wq_ctx(&wq_ctx, &flags, &more_pending);
+ if (ret) {
+ dev_err(scm->dev, "GET_WQ_CTX SMC call failed: %d\n", ret);
+ goto out;
+ }
+
+ if (flags != QCOM_SMC_WAITQ_FLAG_WAKE_ONE &&
+ flags != QCOM_SMC_WAITQ_FLAG_WAKE_ALL) {
+ dev_err(scm->dev, "Invalid flags found for wq_ctx: %u\n", flags);
+ goto out;
+ }
+
+ ret = qcom_scm_waitq_wakeup(scm, wq_ctx);
+ if (ret)
+ goto out;
+ } while (more_pending);
+
+out:
+ return IRQ_HANDLED;
+}
+
static int qcom_scm_probe(struct platform_device *pdev)
{
struct qcom_scm *scm;
unsigned long clks;
- int ret;
+ int irq, ret;
scm = devm_kzalloc(&pdev->dev, sizeof(*scm), GFP_KERNEL);
if (!scm)
@@ -1402,6 +1477,19 @@ static int qcom_scm_probe(struct platform_device *pdev)
__scm = scm;
__scm->dev = &pdev->dev;
+ init_completion(&__scm->waitq_comp);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ if (irq != -ENXIO)
+ return irq;
+ } else {
+ ret = devm_request_threaded_irq(__scm->dev, irq, NULL, qcom_scm_irq_handler,
+ IRQF_ONESHOT, "qcom-scm", __scm);
+ if (ret < 0)
+ return dev_err_probe(scm->dev, ret, "Failed to request qcom-scm irq\n");
+ }
+
__get_convention();
/*
diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h
index db3d08a01209..e6e512bd57d1 100644
--- a/drivers/firmware/qcom_scm.h
+++ b/drivers/firmware/qcom_scm.h
@@ -60,6 +60,9 @@ struct qcom_scm_res {
u64 result[MAX_QCOM_SCM_RETS];
};
+int qcom_scm_wait_for_wq_completion(u32 wq_ctx);
+int scm_get_wq_ctx(u32 *wq_ctx, u32 *flags, u32 *more_pending);
+
#define SCM_SMC_FNID(s, c) ((((s) & 0xFF) << 8) | ((c) & 0xFF))
extern int __scm_smc_call(struct device *dev, const struct qcom_scm_desc *desc,
enum qcom_scm_convention qcom_convention,
@@ -129,6 +132,10 @@ extern int scm_legacy_call(struct device *dev, const struct qcom_scm_desc *desc,
#define QCOM_SCM_SMMU_CONFIG_ERRATA1 0x03
#define QCOM_SCM_SMMU_CONFIG_ERRATA1_CLIENT_ALL 0x02
+#define QCOM_SCM_SVC_WAITQ 0x24
+#define QCOM_SCM_WAITQ_RESUME 0x02
+#define QCOM_SCM_WAITQ_GET_WQ_CTX 0x03
+
/* common error codes */
#define QCOM_SCM_V2_EBUSY -12
#define QCOM_SCM_ENOMEM -5
@@ -137,6 +144,7 @@ extern int scm_legacy_call(struct device *dev, const struct qcom_scm_desc *desc,
#define QCOM_SCM_EINVAL_ARG -2
#define QCOM_SCM_ERROR -1
#define QCOM_SCM_INTERRUPTED 1
+#define QCOM_SCM_WAITQ_SLEEP 2
static inline int qcom_scm_remap_error(int err)
{
diff --git a/drivers/firmware/stratix10-svc.c b/drivers/firmware/stratix10-svc.c
index b4081f4d88a3..bde1f543f529 100644
--- a/drivers/firmware/stratix10-svc.c
+++ b/drivers/firmware/stratix10-svc.c
@@ -1138,13 +1138,17 @@ static int stratix10_svc_drv_probe(struct platform_device *pdev)
/* allocate service controller and supporting channel */
controller = devm_kzalloc(dev, sizeof(*controller), GFP_KERNEL);
- if (!controller)
- return -ENOMEM;
+ if (!controller) {
+ ret = -ENOMEM;
+ goto err_destroy_pool;
+ }
chans = devm_kmalloc_array(dev, SVC_NUM_CHANNEL,
sizeof(*chans), GFP_KERNEL | __GFP_ZERO);
- if (!chans)
- return -ENOMEM;
+ if (!chans) {
+ ret = -ENOMEM;
+ goto err_destroy_pool;
+ }
controller->dev = dev;
controller->num_chans = SVC_NUM_CHANNEL;
@@ -1159,7 +1163,7 @@ static int stratix10_svc_drv_probe(struct platform_device *pdev)
ret = kfifo_alloc(&controller->svc_fifo, fifo_size, GFP_KERNEL);
if (ret) {
dev_err(dev, "failed to allocate FIFO\n");
- return ret;
+ goto err_destroy_pool;
}
spin_lock_init(&controller->svc_fifo_lock);
@@ -1198,19 +1202,20 @@ static int stratix10_svc_drv_probe(struct platform_device *pdev)
ret = platform_device_add(svc->stratix10_svc_rsu);
if (ret) {
platform_device_put(svc->stratix10_svc_rsu);
- return ret;
+ goto err_free_kfifo;
}
svc->intel_svc_fcs = platform_device_alloc(INTEL_FCS, 1);
if (!svc->intel_svc_fcs) {
dev_err(dev, "failed to allocate %s device\n", INTEL_FCS);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto err_unregister_dev;
}
ret = platform_device_add(svc->intel_svc_fcs);
if (ret) {
platform_device_put(svc->intel_svc_fcs);
- return ret;
+ goto err_unregister_dev;
}
dev_set_drvdata(dev, svc);
@@ -1219,8 +1224,12 @@ static int stratix10_svc_drv_probe(struct platform_device *pdev)
return 0;
+err_unregister_dev:
+ platform_device_unregister(svc->stratix10_svc_rsu);
err_free_kfifo:
kfifo_free(&controller->svc_fifo);
+err_destroy_pool:
+ gen_pool_destroy(genpool);
return ret;
}
diff --git a/drivers/firmware/sysfb_simplefb.c b/drivers/firmware/sysfb_simplefb.c
index a353e27f83f5..ce9c007ed66f 100644
--- a/drivers/firmware/sysfb_simplefb.c
+++ b/drivers/firmware/sysfb_simplefb.c
@@ -27,25 +27,56 @@ static const struct simplefb_format formats[] = SIMPLEFB_FORMATS;
__init bool sysfb_parse_mode(const struct screen_info *si,
struct simplefb_platform_data *mode)
{
- const struct simplefb_format *f;
__u8 type;
+ u32 bits_per_pixel;
unsigned int i;
type = si->orig_video_isVGA;
if (type != VIDEO_TYPE_VLFB && type != VIDEO_TYPE_EFI)
return false;
+ /*
+ * The meaning of depth and bpp for direct-color formats is
+ * inconsistent:
+ *
+ * - DRM format info specifies depth as the number of color
+ * bits; including alpha, but not including filler bits.
+ * - Linux' EFI platform code computes lfb_depth from the
+ * individual color channels, including the reserved bits.
+ * - VBE 1.1 defines lfb_depth for XRGB1555 as 16, but later
+ * versions use 15.
+ * - On the kernel command line, 'bpp' of 32 is usually
+ * XRGB8888 including the filler bits, but 15 is XRGB1555
+ * not including the filler bit.
+ *
+ * It's not easily possible to fix this in struct screen_info,
+ * as this could break UAPI. The best solution is to compute
+ * bits_per_pixel here and ignore lfb_depth. In the loop below,
+ * ignore simplefb formats with alpha bits, as EFI and VESA
+ * don't specify alpha channels.
+ */
+ if (si->lfb_depth > 8) {
+ bits_per_pixel = max(max3(si->red_size + si->red_pos,
+ si->green_size + si->green_pos,
+ si->blue_size + si->blue_pos),
+ si->rsvd_size + si->rsvd_pos);
+ } else {
+ bits_per_pixel = si->lfb_depth;
+ }
+
for (i = 0; i < ARRAY_SIZE(formats); ++i) {
- f = &formats[i];
- if (si->lfb_depth == f->bits_per_pixel &&
+ const struct simplefb_format *f = &formats[i];
+
+ if (f->transp.length)
+ continue; /* transparent formats are unsupported by VESA/EFI */
+
+ if (bits_per_pixel == f->bits_per_pixel &&
si->red_size == f->red.length &&
si->red_pos == f->red.offset &&
si->green_size == f->green.length &&
si->green_pos == f->green.offset &&
si->blue_size == f->blue.length &&
- si->blue_pos == f->blue.offset &&
- si->rsvd_size == f->transp.length &&
- si->rsvd_pos == f->transp.offset) {
+ si->blue_pos == f->blue.offset) {
mode->format = f->name;
mode->width = si->lfb_width;
mode->height = si->lfb_height;
diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c
index 129f68d7a6f5..acd83d29c866 100644
--- a/drivers/firmware/xilinx/zynqmp.c
+++ b/drivers/firmware/xilinx/zynqmp.c
@@ -738,8 +738,31 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_get_pll_frac_data);
*/
int zynqmp_pm_set_sd_tapdelay(u32 node_id, u32 type, u32 value)
{
- return zynqmp_pm_invoke_fn(PM_IOCTL, node_id, IOCTL_SET_SD_TAPDELAY,
- type, value, NULL);
+ u32 reg = (type == PM_TAPDELAY_INPUT) ? SD_ITAPDLY : SD_OTAPDLYSEL;
+ u32 mask = (node_id == NODE_SD_0) ? GENMASK(15, 0) : GENMASK(31, 16);
+
+ if (value) {
+ return zynqmp_pm_invoke_fn(PM_IOCTL, node_id,
+ IOCTL_SET_SD_TAPDELAY,
+ type, value, NULL);
+ }
+
+ /*
+ * Work around completely misdesigned firmware API on Xilinx ZynqMP.
+ * The IOCTL_SET_SD_TAPDELAY firmware call allows the caller to only
+ * ever set IOU_SLCR SD_ITAPDLY Register SD0_ITAPDLYENA/SD1_ITAPDLYENA
+ * bits, but there is no matching call to clear those bits. If those
+ * bits are not cleared, SDMMC tuning may fail.
+ *
+ * Luckily, there are PM_MMIO_READ/PM_MMIO_WRITE calls which seem to
+ * allow complete unrestricted access to all address space, including
+ * IOU_SLCR SD_ITAPDLY Register and all the other registers, access
+ * to which was supposed to be protected by the current firmware API.
+ *
+ * Use PM_MMIO_READ/PM_MMIO_WRITE to re-implement the missing counter
+ * part of IOCTL_SET_SD_TAPDELAY which clears SDx_ITAPDLYENA bits.
+ */
+ return zynqmp_pm_invoke_fn(PM_MMIO_WRITE, reg, mask, 0, 0, NULL);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_set_sd_tapdelay);
diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
index 6ce143dafd04..0a00763b9f28 100644
--- a/drivers/fpga/Kconfig
+++ b/drivers/fpga/Kconfig
@@ -246,7 +246,7 @@ config FPGA_MGR_VERSAL_FPGA
config FPGA_M10_BMC_SEC_UPDATE
tristate "Intel MAX10 BMC Secure Update driver"
- depends on MFD_INTEL_M10_BMC
+ depends on MFD_INTEL_M10_BMC_CORE
select FW_LOADER
select FW_UPLOAD
help
diff --git a/drivers/fpga/dfl-afu-region.c b/drivers/fpga/dfl-afu-region.c
index 0804b7a0c298..2e7b41629406 100644
--- a/drivers/fpga/dfl-afu-region.c
+++ b/drivers/fpga/dfl-afu-region.c
@@ -39,6 +39,7 @@ static struct dfl_afu_mmio_region *get_region_by_index(struct dfl_afu *afu,
/**
* afu_mmio_region_add - add a mmio region to given feature dev.
*
+ * @pdata: afu platform device's pdata.
* @region_index: region index.
* @region_size: region size.
* @phys: region's physical address of this region.
diff --git a/drivers/fpga/dfl-afu.h b/drivers/fpga/dfl-afu.h
index e5020e2b1f3d..674e9772f0ea 100644
--- a/drivers/fpga/dfl-afu.h
+++ b/drivers/fpga/dfl-afu.h
@@ -41,7 +41,7 @@ struct dfl_afu_mmio_region {
};
/**
- * struct fpga_afu_dma_region - afu DMA region data structure
+ * struct dfl_afu_dma_region - afu DMA region data structure
*
* @user_addr: region userspace virtual address.
* @length: region length.
diff --git a/drivers/fpga/dfl-fme-perf.c b/drivers/fpga/dfl-fme-perf.c
index 587c82be12f7..7422d2bc6f37 100644
--- a/drivers/fpga/dfl-fme-perf.c
+++ b/drivers/fpga/dfl-fme-perf.c
@@ -141,7 +141,7 @@
* @fab_port_id: used to indicate current working mode of fabric counters.
* @fab_lock: lock to protect fabric counters working mode.
* @cpu: active CPU to which the PMU is bound for accesses.
- * @cpuhp_node: node for CPU hotplug notifier link.
+ * @node: node for CPU hotplug notifier link.
* @cpuhp_state: state for CPU hotplug notification;
*/
struct fme_perf_priv {
diff --git a/drivers/fpga/dfl-fme-pr.c b/drivers/fpga/dfl-fme-pr.c
index d61ce9a18879..cdcf6dea4cc9 100644
--- a/drivers/fpga/dfl-fme-pr.c
+++ b/drivers/fpga/dfl-fme-pr.c
@@ -164,7 +164,7 @@ free_exit:
/**
* dfl_fme_create_mgr - create fpga mgr platform device as child device
- *
+ * @feature: sub feature info
* @pdata: fme platform_device's pdata
*
* Return: mgr platform device if successful, and error code otherwise.
@@ -273,7 +273,7 @@ static void dfl_fme_destroy_bridge(struct dfl_fme_bridge *fme_br)
}
/**
- * dfl_fme_destroy_bridge - destroy all fpga bridge platform device
+ * dfl_fme_destroy_bridges - destroy all fpga bridge platform device
* @pdata: fme platform device's pdata
*/
static void dfl_fme_destroy_bridges(struct dfl_feature_platform_data *pdata)
diff --git a/drivers/fpga/dfl-fme-pr.h b/drivers/fpga/dfl-fme-pr.h
index 096a699089d3..761f80f63312 100644
--- a/drivers/fpga/dfl-fme-pr.h
+++ b/drivers/fpga/dfl-fme-pr.h
@@ -58,7 +58,7 @@ struct dfl_fme_bridge {
};
/**
- * struct dfl_fme_bridge_pdata - platform data for FME bridge platform device.
+ * struct dfl_fme_br_pdata - platform data for FME bridge platform device.
*
* @cdev: container device.
* @port_id: port id.
diff --git a/drivers/fpga/dfl.c b/drivers/fpga/dfl.c
index b9aae85ba930..dd7a783d53b5 100644
--- a/drivers/fpga/dfl.c
+++ b/drivers/fpga/dfl.c
@@ -13,6 +13,7 @@
#include <linux/dfl.h>
#include <linux/fpga-dfl.h>
#include <linux/module.h>
+#include <linux/overflow.h>
#include <linux/uaccess.h>
#include "dfl.h"
@@ -45,7 +46,7 @@ static const char *dfl_pdata_key_strings[DFL_ID_MAX] = {
};
/**
- * dfl_dev_info - dfl feature device information.
+ * struct dfl_dev_info - dfl feature device information.
* @name: name string of the feature platform device.
* @dfh_id: id value in Device Feature Header (DFH) register by DFL spec.
* @id: idr id of the feature dev.
@@ -67,7 +68,7 @@ static struct dfl_dev_info dfl_devs[] = {
};
/**
- * dfl_chardev_info - chardev information of dfl feature device
+ * struct dfl_chardev_info - chardev information of dfl feature device
* @name: nmae string of the char device.
* @devt: devt of the char device.
*/
@@ -293,9 +294,9 @@ static void dfl_bus_remove(struct device *dev)
ddrv->remove(ddev);
}
-static int dfl_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int dfl_bus_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct dfl_device *ddev = to_dfl_dev(dev);
+ const struct dfl_device *ddev = to_dfl_dev(dev);
return add_uevent_var(env, "MODALIAS=dfl:t%04Xf%04X",
ddev->type, ddev->feature_id);
@@ -342,6 +343,8 @@ static void release_dfl_dev(struct device *dev)
if (ddev->mmio_res.parent)
release_resource(&ddev->mmio_res);
+ kfree(ddev->params);
+
ida_free(&dfl_device_ida, ddev->id);
kfree(ddev->irqs);
kfree(ddev);
@@ -380,7 +383,16 @@ dfl_dev_add(struct dfl_feature_platform_data *pdata,
ddev->type = feature_dev_id_type(pdev);
ddev->feature_id = feature->id;
ddev->revision = feature->revision;
+ ddev->dfh_version = feature->dfh_version;
ddev->cdev = pdata->dfl_cdev;
+ if (feature->param_size) {
+ ddev->params = kmemdup(feature->params, feature->param_size, GFP_KERNEL);
+ if (!ddev->params) {
+ ret = -ENOMEM;
+ goto put_dev;
+ }
+ ddev->param_size = feature->param_size;
+ }
/* add mmio resource */
parent_res = &pdev->resource[feature->resource_index];
@@ -708,20 +720,27 @@ struct build_feature_devs_info {
* struct dfl_feature_info - sub feature info collected during feature dev build
*
* @fid: id of this sub feature.
+ * @revision: revision of this sub feature
+ * @dfh_version: version of Device Feature Header (DFH)
* @mmio_res: mmio resource of this sub feature.
* @ioaddr: mapped base address of mmio resource.
* @node: node in sub_features linked list.
* @irq_base: start of irq index in this sub feature.
* @nr_irqs: number of irqs of this sub feature.
+ * @param_size: size DFH parameters.
+ * @params: DFH parameter data.
*/
struct dfl_feature_info {
u16 fid;
u8 revision;
+ u8 dfh_version;
struct resource mmio_res;
void __iomem *ioaddr;
struct list_head node;
unsigned int irq_base;
unsigned int nr_irqs;
+ unsigned int param_size;
+ u64 params[];
};
static void dfl_fpga_cdev_add_port_dev(struct dfl_fpga_cdev *cdev,
@@ -797,7 +816,17 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
feature->dev = fdev;
feature->id = finfo->fid;
feature->revision = finfo->revision;
+ feature->dfh_version = finfo->dfh_version;
+
+ if (finfo->param_size) {
+ feature->params = devm_kmemdup(binfo->dev,
+ finfo->params, finfo->param_size,
+ GFP_KERNEL);
+ if (!feature->params)
+ return -ENOMEM;
+ feature->param_size = finfo->param_size;
+ }
/*
* the FIU header feature has some fundamental functions (sriov
* set, port enable/disable) needed for the dfl bus device and
@@ -934,56 +963,115 @@ static u16 feature_id(u64 value)
return 0;
}
+static u64 *find_param(u64 *params, resource_size_t max, int param_id)
+{
+ u64 *end = params + max / sizeof(u64);
+ u64 v, next;
+
+ while (params < end) {
+ v = *params;
+ if (param_id == FIELD_GET(DFHv1_PARAM_HDR_ID, v))
+ return params;
+
+ if (FIELD_GET(DFHv1_PARAM_HDR_NEXT_EOP, v))
+ break;
+
+ next = FIELD_GET(DFHv1_PARAM_HDR_NEXT_OFFSET, v);
+ params += next;
+ }
+
+ return NULL;
+}
+
+/**
+ * dfh_find_param() - find parameter block for the given parameter id
+ * @dfl_dev: dfl device
+ * @param_id: id of dfl parameter
+ * @psize: destination to store size of parameter data in bytes
+ *
+ * Return: pointer to start of parameter data, PTR_ERR otherwise.
+ */
+void *dfh_find_param(struct dfl_device *dfl_dev, int param_id, size_t *psize)
+{
+ u64 *phdr = find_param(dfl_dev->params, dfl_dev->param_size, param_id);
+
+ if (!phdr)
+ return ERR_PTR(-ENOENT);
+
+ if (psize)
+ *psize = (FIELD_GET(DFHv1_PARAM_HDR_NEXT_OFFSET, *phdr) - 1) * sizeof(u64);
+
+ return phdr + 1;
+}
+EXPORT_SYMBOL_GPL(dfh_find_param);
+
static int parse_feature_irqs(struct build_feature_devs_info *binfo,
- resource_size_t ofst, u16 fid,
- unsigned int *irq_base, unsigned int *nr_irqs)
+ resource_size_t ofst, struct dfl_feature_info *finfo)
{
void __iomem *base = binfo->ioaddr + ofst;
unsigned int i, ibase, inr = 0;
+ void *params = finfo->params;
enum dfl_id_type type;
+ u16 fid = finfo->fid;
int virq;
+ u64 *p;
u64 v;
- type = feature_dev_id_type(binfo->feature_dev);
+ switch (finfo->dfh_version) {
+ case 0:
+ /*
+ * DFHv0 only provides MMIO resource information for each feature
+ * in the DFL header. There is no generic interrupt information.
+ * Instead, features with interrupt functionality provide
+ * the information in feature specific registers.
+ */
+ type = feature_dev_id_type(binfo->feature_dev);
+ if (type == PORT_ID) {
+ switch (fid) {
+ case PORT_FEATURE_ID_UINT:
+ v = readq(base + PORT_UINT_CAP);
+ ibase = FIELD_GET(PORT_UINT_CAP_FST_VECT, v);
+ inr = FIELD_GET(PORT_UINT_CAP_INT_NUM, v);
+ break;
+ case PORT_FEATURE_ID_ERROR:
+ v = readq(base + PORT_ERROR_CAP);
+ ibase = FIELD_GET(PORT_ERROR_CAP_INT_VECT, v);
+ inr = FIELD_GET(PORT_ERROR_CAP_SUPP_INT, v);
+ break;
+ }
+ } else if (type == FME_ID) {
+ switch (fid) {
+ case FME_FEATURE_ID_GLOBAL_ERR:
+ v = readq(base + FME_ERROR_CAP);
+ ibase = FIELD_GET(FME_ERROR_CAP_INT_VECT, v);
+ inr = FIELD_GET(FME_ERROR_CAP_SUPP_INT, v);
+ break;
+ }
+ }
+ break;
- /*
- * Ideally DFL framework should only read info from DFL header, but
- * current version DFL only provides mmio resources information for
- * each feature in DFL Header, no field for interrupt resources.
- * Interrupt resource information is provided by specific mmio
- * registers of each private feature which supports interrupt. So in
- * order to parse and assign irq resources, DFL framework has to look
- * into specific capability registers of these private features.
- *
- * Once future DFL version supports generic interrupt resource
- * information in common DFL headers, the generic interrupt parsing
- * code will be added. But in order to be compatible to old version
- * DFL, the driver may still fall back to these quirks.
- */
- if (type == PORT_ID) {
- switch (fid) {
- case PORT_FEATURE_ID_UINT:
- v = readq(base + PORT_UINT_CAP);
- ibase = FIELD_GET(PORT_UINT_CAP_FST_VECT, v);
- inr = FIELD_GET(PORT_UINT_CAP_INT_NUM, v);
- break;
- case PORT_FEATURE_ID_ERROR:
- v = readq(base + PORT_ERROR_CAP);
- ibase = FIELD_GET(PORT_ERROR_CAP_INT_VECT, v);
- inr = FIELD_GET(PORT_ERROR_CAP_SUPP_INT, v);
+ case 1:
+ /*
+ * DFHv1 provides interrupt resource information in DFHv1
+ * parameter blocks.
+ */
+ p = find_param(params, finfo->param_size, DFHv1_PARAM_ID_MSI_X);
+ if (!p)
break;
- }
- } else if (type == FME_ID) {
- if (fid == FME_FEATURE_ID_GLOBAL_ERR) {
- v = readq(base + FME_ERROR_CAP);
- ibase = FIELD_GET(FME_ERROR_CAP_INT_VECT, v);
- inr = FIELD_GET(FME_ERROR_CAP_SUPP_INT, v);
- }
+
+ p++;
+ ibase = FIELD_GET(DFHv1_PARAM_MSI_X_STARTV, *p);
+ inr = FIELD_GET(DFHv1_PARAM_MSI_X_NUMV, *p);
+ break;
+
+ default:
+ dev_warn(binfo->dev, "unexpected DFH version %d\n", finfo->dfh_version);
+ break;
}
if (!inr) {
- *irq_base = 0;
- *nr_irqs = 0;
+ finfo->irq_base = 0;
+ finfo->nr_irqs = 0;
return 0;
}
@@ -1006,12 +1094,37 @@ static int parse_feature_irqs(struct build_feature_devs_info *binfo,
}
}
- *irq_base = ibase;
- *nr_irqs = inr;
+ finfo->irq_base = ibase;
+ finfo->nr_irqs = inr;
return 0;
}
+static int dfh_get_param_size(void __iomem *dfh_base, resource_size_t max)
+{
+ int size = 0;
+ u64 v, next;
+
+ if (!FIELD_GET(DFHv1_CSR_SIZE_GRP_HAS_PARAMS,
+ readq(dfh_base + DFHv1_CSR_SIZE_GRP)))
+ return 0;
+
+ while (size + DFHv1_PARAM_HDR < max) {
+ v = readq(dfh_base + DFHv1_PARAM_HDR + size);
+
+ next = FIELD_GET(DFHv1_PARAM_HDR_NEXT_OFFSET, v);
+ if (!next)
+ return -EINVAL;
+
+ size += next * sizeof(u64);
+
+ if (FIELD_GET(DFHv1_PARAM_HDR_NEXT_EOP, v))
+ return size;
+ }
+
+ return -ENOENT;
+}
+
/*
* when create sub feature instances, for private features, it doesn't need
* to provide resource size and feature id as they could be read from DFH
@@ -1023,39 +1136,69 @@ static int
create_feature_instance(struct build_feature_devs_info *binfo,
resource_size_t ofst, resource_size_t size, u16 fid)
{
- unsigned int irq_base, nr_irqs;
struct dfl_feature_info *finfo;
+ resource_size_t start, end;
+ int dfh_psize = 0;
u8 revision = 0;
+ u64 v, addr_off;
+ u8 dfh_ver = 0;
int ret;
- u64 v;
if (fid != FEATURE_ID_AFU) {
v = readq(binfo->ioaddr + ofst);
revision = FIELD_GET(DFH_REVISION, v);
-
+ dfh_ver = FIELD_GET(DFH_VERSION, v);
/* read feature size and id if inputs are invalid */
size = size ? size : feature_size(v);
fid = fid ? fid : feature_id(v);
+ if (dfh_ver == 1) {
+ dfh_psize = dfh_get_param_size(binfo->ioaddr + ofst, size);
+ if (dfh_psize < 0) {
+ dev_err(binfo->dev,
+ "failed to read size of DFHv1 parameters %d\n",
+ dfh_psize);
+ return dfh_psize;
+ }
+ dev_dbg(binfo->dev, "dfhv1_psize %d\n", dfh_psize);
+ }
}
if (binfo->len - ofst < size)
return -EINVAL;
- ret = parse_feature_irqs(binfo, ofst, fid, &irq_base, &nr_irqs);
- if (ret)
- return ret;
-
- finfo = kzalloc(sizeof(*finfo), GFP_KERNEL);
+ finfo = kzalloc(struct_size(finfo, params, dfh_psize / sizeof(u64)), GFP_KERNEL);
if (!finfo)
return -ENOMEM;
+ memcpy_fromio(finfo->params, binfo->ioaddr + ofst + DFHv1_PARAM_HDR, dfh_psize);
+ finfo->param_size = dfh_psize;
+
finfo->fid = fid;
finfo->revision = revision;
- finfo->mmio_res.start = binfo->start + ofst;
- finfo->mmio_res.end = finfo->mmio_res.start + size - 1;
+ finfo->dfh_version = dfh_ver;
+ if (dfh_ver == 1) {
+ v = readq(binfo->ioaddr + ofst + DFHv1_CSR_ADDR);
+ addr_off = FIELD_GET(DFHv1_CSR_ADDR_MASK, v);
+ if (FIELD_GET(DFHv1_CSR_ADDR_REL, v))
+ start = addr_off << 1;
+ else
+ start = binfo->start + ofst + addr_off;
+
+ v = readq(binfo->ioaddr + ofst + DFHv1_CSR_SIZE_GRP);
+ end = start + FIELD_GET(DFHv1_CSR_SIZE_GRP_SIZE, v) - 1;
+ } else {
+ start = binfo->start + ofst;
+ end = start + size - 1;
+ }
finfo->mmio_res.flags = IORESOURCE_MEM;
- finfo->irq_base = irq_base;
- finfo->nr_irqs = nr_irqs;
+ finfo->mmio_res.start = start;
+ finfo->mmio_res.end = end;
+
+ ret = parse_feature_irqs(binfo, ofst, finfo);
+ if (ret) {
+ kfree(finfo);
+ return ret;
+ }
list_add_tail(&finfo->node, &binfo->sub_features);
binfo->feature_num++;
diff --git a/drivers/fpga/dfl.h b/drivers/fpga/dfl.h
index 06cfcd5e84bb..1d724a28f00a 100644
--- a/drivers/fpga/dfl.h
+++ b/drivers/fpga/dfl.h
@@ -74,11 +74,47 @@
#define DFH_REVISION GENMASK_ULL(15, 12) /* Feature revision */
#define DFH_NEXT_HDR_OFST GENMASK_ULL(39, 16) /* Offset to next DFH */
#define DFH_EOL BIT_ULL(40) /* End of list */
+#define DFH_VERSION GENMASK_ULL(59, 52) /* DFH version */
#define DFH_TYPE GENMASK_ULL(63, 60) /* Feature type */
#define DFH_TYPE_AFU 1
#define DFH_TYPE_PRIVATE 3
#define DFH_TYPE_FIU 4
+/*
+ * DFHv1 Register Offset definitons
+ * In DHFv1, DFH + GUID + CSR_START + CSR_SIZE_GROUP + PARAM_HDR + PARAM_DATA
+ * as common header registers
+ */
+#define DFHv1_CSR_ADDR 0x18 /* CSR Register start address */
+#define DFHv1_CSR_SIZE_GRP 0x20 /* Size of Reg Block and Group/tag */
+#define DFHv1_PARAM_HDR 0x28 /* Optional First Param header */
+
+/*
+ * CSR Rel Bit, 1'b0 = relative (offset from feature DFH start),
+ * 1'b1 = absolute (ARM or other non-PCIe use)
+ */
+#define DFHv1_CSR_ADDR_REL BIT_ULL(0)
+
+/* CSR Header Register Bit Definitions */
+#define DFHv1_CSR_ADDR_MASK GENMASK_ULL(63, 1) /* 63:1 of CSR address */
+
+/* CSR SIZE Goup Register Bit Definitions */
+#define DFHv1_CSR_SIZE_GRP_INSTANCE_ID GENMASK_ULL(15, 0) /* Enumeration instantiated IP */
+#define DFHv1_CSR_SIZE_GRP_GROUPING_ID GENMASK_ULL(30, 16) /* Group Features/interfaces */
+#define DFHv1_CSR_SIZE_GRP_HAS_PARAMS BIT_ULL(31) /* Presence of Parameters */
+#define DFHv1_CSR_SIZE_GRP_SIZE GENMASK_ULL(63, 32) /* Size of CSR Block in bytes */
+
+/* PARAM Header Register Bit Definitions */
+#define DFHv1_PARAM_HDR_ID GENMASK_ULL(15, 0) /* Id of this Param */
+#define DFHv1_PARAM_HDR_VER GENMASK_ULL(31, 16) /* Version Param */
+#define DFHv1_PARAM_HDR_NEXT_OFFSET GENMASK_ULL(63, 35) /* Offset of next Param */
+#define DFHv1_PARAM_HDR_NEXT_EOP BIT_ULL(32)
+#define DFHv1_PARAM_DATA 0x08 /* Offset of Param data from Param header */
+
+#define DFHv1_PARAM_ID_MSI_X 0x1
+#define DFHv1_PARAM_MSI_X_NUMV GENMASK_ULL(63, 32)
+#define DFHv1_PARAM_MSI_X_STARTV GENMASK_ULL(31, 0)
+
/* Next AFU Register Bitfield */
#define NEXT_AFU_NEXT_DFH_OFST GENMASK_ULL(23, 0) /* Offset to next AFU */
@@ -231,6 +267,7 @@ struct dfl_feature_irq_ctx {
*
* @dev: ptr to pdev of the feature device which has the sub feature.
* @id: sub feature id.
+ * @revision: revision of this sub feature.
* @resource_index: each sub feature has one mmio resource for its registers.
* this index is used to find its mmio resource from the
* feature dev (platform device)'s resources.
@@ -240,6 +277,9 @@ struct dfl_feature_irq_ctx {
* @ops: ops of this sub feature.
* @ddev: ptr to the dfl device of this sub feature.
* @priv: priv data of this feature.
+ * @dfh_version: version of the DFH
+ * @param_size: size of dfh parameters
+ * @params: point to memory copy of dfh parameters
*/
struct dfl_feature {
struct platform_device *dev;
@@ -252,6 +292,9 @@ struct dfl_feature {
const struct dfl_feature_ops *ops;
struct dfl_device *ddev;
void *priv;
+ u8 dfh_version;
+ unsigned int param_size;
+ void *params;
};
#define FEATURE_DEV_ID_UNUSED (-1)
diff --git a/drivers/fpga/fpga-bridge.c b/drivers/fpga/fpga-bridge.c
index 727704431f61..5cd40acab5bf 100644
--- a/drivers/fpga/fpga-bridge.c
+++ b/drivers/fpga/fpga-bridge.c
@@ -293,12 +293,15 @@ static ssize_t state_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct fpga_bridge *bridge = to_fpga_bridge(dev);
- int enable = 1;
+ int state = 1;
- if (bridge->br_ops && bridge->br_ops->enable_show)
- enable = bridge->br_ops->enable_show(bridge);
+ if (bridge->br_ops && bridge->br_ops->enable_show) {
+ state = bridge->br_ops->enable_show(bridge);
+ if (state < 0)
+ return state;
+ }
- return sprintf(buf, "%s\n", enable ? "enabled" : "disabled");
+ return sysfs_emit(buf, "%s\n", state ? "enabled" : "disabled");
}
static DEVICE_ATTR_RO(name);
diff --git a/drivers/fpga/intel-m10-bmc-sec-update.c b/drivers/fpga/intel-m10-bmc-sec-update.c
index 03f1bd81c434..f0acedc80182 100644
--- a/drivers/fpga/intel-m10-bmc-sec-update.c
+++ b/drivers/fpga/intel-m10-bmc-sec-update.c
@@ -14,6 +14,12 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
+struct m10bmc_sec;
+
+struct m10bmc_sec_ops {
+ int (*rsu_status)(struct m10bmc_sec *sec);
+};
+
struct m10bmc_sec {
struct device *dev;
struct intel_m10bmc *m10bmc;
@@ -21,6 +27,7 @@ struct m10bmc_sec {
char *fw_name;
u32 fw_name_id;
bool cancel_request;
+ const struct m10bmc_sec_ops *ops;
};
static DEFINE_XARRAY_ALLOC(fw_upload_xa);
@@ -31,6 +38,71 @@ static DEFINE_XARRAY_ALLOC(fw_upload_xa);
#define REH_MAGIC GENMASK(15, 0)
#define REH_SHA_NUM_BYTES GENMASK(31, 16)
+static int m10bmc_sec_write(struct m10bmc_sec *sec, const u8 *buf, u32 offset, u32 size)
+{
+ struct intel_m10bmc *m10bmc = sec->m10bmc;
+ unsigned int stride = regmap_get_reg_stride(m10bmc->regmap);
+ u32 write_count = size / stride;
+ u32 leftover_offset = write_count * stride;
+ u32 leftover_size = size - leftover_offset;
+ u32 leftover_tmp = 0;
+ int ret;
+
+ if (sec->m10bmc->flash_bulk_ops)
+ return sec->m10bmc->flash_bulk_ops->write(m10bmc, buf, offset, size);
+
+ if (WARN_ON_ONCE(stride > sizeof(leftover_tmp)))
+ return -EINVAL;
+
+ ret = regmap_bulk_write(m10bmc->regmap, M10BMC_STAGING_BASE + offset,
+ buf + offset, write_count);
+ if (ret)
+ return ret;
+
+ /* If size is not aligned to stride, handle the remainder bytes with regmap_write() */
+ if (leftover_size) {
+ memcpy(&leftover_tmp, buf + leftover_offset, leftover_size);
+ ret = regmap_write(m10bmc->regmap, M10BMC_STAGING_BASE + offset + leftover_offset,
+ leftover_tmp);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int m10bmc_sec_read(struct m10bmc_sec *sec, u8 *buf, u32 addr, u32 size)
+{
+ struct intel_m10bmc *m10bmc = sec->m10bmc;
+ unsigned int stride = regmap_get_reg_stride(m10bmc->regmap);
+ u32 read_count = size / stride;
+ u32 leftover_offset = read_count * stride;
+ u32 leftover_size = size - leftover_offset;
+ u32 leftover_tmp;
+ int ret;
+
+ if (sec->m10bmc->flash_bulk_ops)
+ return sec->m10bmc->flash_bulk_ops->read(m10bmc, buf, addr, size);
+
+ if (WARN_ON_ONCE(stride > sizeof(leftover_tmp)))
+ return -EINVAL;
+
+ ret = regmap_bulk_read(m10bmc->regmap, addr, buf, read_count);
+ if (ret)
+ return ret;
+
+ /* If size is not aligned to stride, handle the remainder bytes with regmap_read() */
+ if (leftover_size) {
+ ret = regmap_read(m10bmc->regmap, addr + leftover_offset, &leftover_tmp);
+ if (ret)
+ return ret;
+ memcpy(buf + leftover_offset, &leftover_tmp, leftover_size);
+ }
+
+ return 0;
+}
+
+
static ssize_t
show_root_entry_hash(struct device *dev, u32 exp_magic,
u32 prog_addr, u32 reh_addr, char *buf)
@@ -38,11 +110,9 @@ show_root_entry_hash(struct device *dev, u32 exp_magic,
struct m10bmc_sec *sec = dev_get_drvdata(dev);
int sha_num_bytes, i, ret, cnt = 0;
u8 hash[REH_SHA384_SIZE];
- unsigned int stride;
u32 magic;
- stride = regmap_get_reg_stride(sec->m10bmc->regmap);
- ret = m10bmc_raw_read(sec->m10bmc, prog_addr, &magic);
+ ret = m10bmc_sec_read(sec, (u8 *)&magic, prog_addr, sizeof(magic));
if (ret)
return ret;
@@ -50,19 +120,16 @@ show_root_entry_hash(struct device *dev, u32 exp_magic,
return sysfs_emit(buf, "hash not programmed\n");
sha_num_bytes = FIELD_GET(REH_SHA_NUM_BYTES, magic) / 8;
- if ((sha_num_bytes % stride) ||
- (sha_num_bytes != REH_SHA256_SIZE &&
- sha_num_bytes != REH_SHA384_SIZE)) {
+ if (sha_num_bytes != REH_SHA256_SIZE &&
+ sha_num_bytes != REH_SHA384_SIZE) {
dev_err(sec->dev, "%s bad sha num bytes %d\n", __func__,
sha_num_bytes);
return -EINVAL;
}
- ret = regmap_bulk_read(sec->m10bmc->regmap, reh_addr,
- hash, sha_num_bytes / stride);
+ ret = m10bmc_sec_read(sec, hash, reh_addr, sha_num_bytes);
if (ret) {
- dev_err(dev, "failed to read root entry hash: %x cnt %x: %d\n",
- reh_addr, sha_num_bytes / stride, ret);
+ dev_err(dev, "failed to read root entry hash\n");
return ret;
}
@@ -73,16 +140,24 @@ show_root_entry_hash(struct device *dev, u32 exp_magic,
return cnt;
}
-#define DEVICE_ATTR_SEC_REH_RO(_name, _magic, _prog_addr, _reh_addr) \
+#define DEVICE_ATTR_SEC_REH_RO(_name) \
static ssize_t _name##_root_entry_hash_show(struct device *dev, \
struct device_attribute *attr, \
char *buf) \
-{ return show_root_entry_hash(dev, _magic, _prog_addr, _reh_addr, buf); } \
+{ \
+ struct m10bmc_sec *sec = dev_get_drvdata(dev); \
+ const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; \
+ \
+ return show_root_entry_hash(dev, csr_map->_name##_magic, \
+ csr_map->_name##_prog_addr, \
+ csr_map->_name##_reh_addr, \
+ buf); \
+} \
static DEVICE_ATTR_RO(_name##_root_entry_hash)
-DEVICE_ATTR_SEC_REH_RO(bmc, BMC_PROG_MAGIC, BMC_PROG_ADDR, BMC_REH_ADDR);
-DEVICE_ATTR_SEC_REH_RO(sr, SR_PROG_MAGIC, SR_PROG_ADDR, SR_REH_ADDR);
-DEVICE_ATTR_SEC_REH_RO(pr, PR_PROG_MAGIC, PR_PROG_ADDR, PR_REH_ADDR);
+DEVICE_ATTR_SEC_REH_RO(bmc);
+DEVICE_ATTR_SEC_REH_RO(sr);
+DEVICE_ATTR_SEC_REH_RO(pr);
#define CSK_BIT_LEN 128U
#define CSK_32ARRAY_SIZE DIV_ROUND_UP(CSK_BIT_LEN, 32)
@@ -90,27 +165,16 @@ DEVICE_ATTR_SEC_REH_RO(pr, PR_PROG_MAGIC, PR_PROG_ADDR, PR_REH_ADDR);
static ssize_t
show_canceled_csk(struct device *dev, u32 addr, char *buf)
{
- unsigned int i, stride, size = CSK_32ARRAY_SIZE * sizeof(u32);
+ unsigned int i, size = CSK_32ARRAY_SIZE * sizeof(u32);
struct m10bmc_sec *sec = dev_get_drvdata(dev);
DECLARE_BITMAP(csk_map, CSK_BIT_LEN);
__le32 csk_le32[CSK_32ARRAY_SIZE];
u32 csk32[CSK_32ARRAY_SIZE];
int ret;
- stride = regmap_get_reg_stride(sec->m10bmc->regmap);
- if (size % stride) {
- dev_err(sec->dev,
- "CSK vector size (0x%x) not aligned to stride (0x%x)\n",
- size, stride);
- WARN_ON_ONCE(1);
- return -EINVAL;
- }
-
- ret = regmap_bulk_read(sec->m10bmc->regmap, addr, csk_le32,
- size / stride);
+ ret = m10bmc_sec_read(sec, (u8 *)&csk_le32, addr, size);
if (ret) {
- dev_err(sec->dev, "failed to read CSK vector: %x cnt %x: %d\n",
- addr, size / stride, ret);
+ dev_err(sec->dev, "failed to read CSK vector\n");
return ret;
}
@@ -122,18 +186,25 @@ show_canceled_csk(struct device *dev, u32 addr, char *buf)
return bitmap_print_to_pagebuf(1, buf, csk_map, CSK_BIT_LEN);
}
-#define DEVICE_ATTR_SEC_CSK_RO(_name, _addr) \
+#define DEVICE_ATTR_SEC_CSK_RO(_name) \
static ssize_t _name##_canceled_csks_show(struct device *dev, \
struct device_attribute *attr, \
char *buf) \
-{ return show_canceled_csk(dev, _addr, buf); } \
+{ \
+ struct m10bmc_sec *sec = dev_get_drvdata(dev); \
+ const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; \
+ \
+ return show_canceled_csk(dev, \
+ csr_map->_name##_prog_addr + CSK_VEC_OFFSET, \
+ buf); \
+} \
static DEVICE_ATTR_RO(_name##_canceled_csks)
#define CSK_VEC_OFFSET 0x34
-DEVICE_ATTR_SEC_CSK_RO(bmc, BMC_PROG_ADDR + CSK_VEC_OFFSET);
-DEVICE_ATTR_SEC_CSK_RO(sr, SR_PROG_ADDR + CSK_VEC_OFFSET);
-DEVICE_ATTR_SEC_CSK_RO(pr, PR_PROG_ADDR + CSK_VEC_OFFSET);
+DEVICE_ATTR_SEC_CSK_RO(bmc);
+DEVICE_ATTR_SEC_CSK_RO(sr);
+DEVICE_ATTR_SEC_CSK_RO(pr);
#define FLASH_COUNT_SIZE 4096 /* count stored as inverted bit vector */
@@ -141,31 +212,21 @@ static ssize_t flash_count_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct m10bmc_sec *sec = dev_get_drvdata(dev);
- unsigned int stride, num_bits;
+ const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map;
+ unsigned int num_bits;
u8 *flash_buf;
int cnt, ret;
- stride = regmap_get_reg_stride(sec->m10bmc->regmap);
num_bits = FLASH_COUNT_SIZE * 8;
- if (FLASH_COUNT_SIZE % stride) {
- dev_err(sec->dev,
- "FLASH_COUNT_SIZE (0x%x) not aligned to stride (0x%x)\n",
- FLASH_COUNT_SIZE, stride);
- WARN_ON_ONCE(1);
- return -EINVAL;
- }
-
flash_buf = kmalloc(FLASH_COUNT_SIZE, GFP_KERNEL);
if (!flash_buf)
return -ENOMEM;
- ret = regmap_bulk_read(sec->m10bmc->regmap, STAGING_FLASH_COUNT,
- flash_buf, FLASH_COUNT_SIZE / stride);
+ ret = m10bmc_sec_read(sec, flash_buf, csr_map->rsu_update_counter,
+ FLASH_COUNT_SIZE);
if (ret) {
- dev_err(sec->dev,
- "failed to read flash count: %x cnt %x: %d\n",
- STAGING_FLASH_COUNT, FLASH_COUNT_SIZE / stride, ret);
+ dev_err(sec->dev, "failed to read flash count\n");
goto exit_free;
}
cnt = num_bits - bitmap_weight((unsigned long *)flash_buf, num_bits);
@@ -200,25 +261,94 @@ static const struct attribute_group *m10bmc_sec_attr_groups[] = {
static void log_error_regs(struct m10bmc_sec *sec, u32 doorbell)
{
+ const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map;
u32 auth_result;
- dev_err(sec->dev, "RSU error status: 0x%08x\n", doorbell);
+ dev_err(sec->dev, "Doorbell: 0x%08x\n", doorbell);
- if (!m10bmc_sys_read(sec->m10bmc, M10BMC_AUTH_RESULT, &auth_result))
+ if (!m10bmc_sys_read(sec->m10bmc, csr_map->auth_result, &auth_result))
dev_err(sec->dev, "RSU auth result: 0x%08x\n", auth_result);
}
+static int m10bmc_sec_n3000_rsu_status(struct m10bmc_sec *sec)
+{
+ const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map;
+ u32 doorbell;
+ int ret;
+
+ ret = m10bmc_sys_read(sec->m10bmc, csr_map->doorbell, &doorbell);
+ if (ret)
+ return ret;
+
+ return FIELD_GET(DRBL_RSU_STATUS, doorbell);
+}
+
+static int m10bmc_sec_n6000_rsu_status(struct m10bmc_sec *sec)
+{
+ const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map;
+ u32 auth_result;
+ int ret;
+
+ ret = m10bmc_sys_read(sec->m10bmc, csr_map->auth_result, &auth_result);
+ if (ret)
+ return ret;
+
+ return FIELD_GET(AUTH_RESULT_RSU_STATUS, auth_result);
+}
+
+static bool rsu_status_ok(u32 status)
+{
+ return (status == RSU_STAT_NORMAL ||
+ status == RSU_STAT_NIOS_OK ||
+ status == RSU_STAT_USER_OK ||
+ status == RSU_STAT_FACTORY_OK);
+}
+
+static bool rsu_progress_done(u32 progress)
+{
+ return (progress == RSU_PROG_IDLE ||
+ progress == RSU_PROG_RSU_DONE);
+}
+
+static bool rsu_progress_busy(u32 progress)
+{
+ return (progress == RSU_PROG_AUTHENTICATING ||
+ progress == RSU_PROG_COPYING ||
+ progress == RSU_PROG_UPDATE_CANCEL ||
+ progress == RSU_PROG_PROGRAM_KEY_HASH);
+}
+
+static int m10bmc_sec_progress_status(struct m10bmc_sec *sec, u32 *doorbell_reg,
+ u32 *progress, u32 *status)
+{
+ const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map;
+ int ret;
+
+ ret = m10bmc_sys_read(sec->m10bmc, csr_map->doorbell, doorbell_reg);
+ if (ret)
+ return ret;
+
+ ret = sec->ops->rsu_status(sec);
+ if (ret < 0)
+ return ret;
+
+ *status = ret;
+ *progress = rsu_prog(*doorbell_reg);
+
+ return 0;
+}
+
static enum fw_upload_err rsu_check_idle(struct m10bmc_sec *sec)
{
+ const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map;
u32 doorbell;
int ret;
- ret = m10bmc_sys_read(sec->m10bmc, M10BMC_DOORBELL, &doorbell);
+ ret = m10bmc_sys_read(sec->m10bmc, csr_map->doorbell, &doorbell);
if (ret)
return FW_UPLOAD_ERR_RW_ERROR;
- if (rsu_prog(doorbell) != RSU_PROG_IDLE &&
- rsu_prog(doorbell) != RSU_PROG_RSU_DONE) {
+ if (!rsu_progress_done(rsu_prog(doorbell))) {
log_error_regs(sec, doorbell);
return FW_UPLOAD_ERR_BUSY;
}
@@ -226,19 +356,15 @@ static enum fw_upload_err rsu_check_idle(struct m10bmc_sec *sec)
return FW_UPLOAD_ERR_NONE;
}
-static inline bool rsu_start_done(u32 doorbell)
+static inline bool rsu_start_done(u32 doorbell_reg, u32 progress, u32 status)
{
- u32 status, progress;
-
- if (doorbell & DRBL_RSU_REQUEST)
+ if (doorbell_reg & DRBL_RSU_REQUEST)
return false;
- status = rsu_stat(doorbell);
if (status == RSU_STAT_ERASE_FAIL || status == RSU_STAT_WEAROUT)
return true;
- progress = rsu_prog(doorbell);
- if (progress != RSU_PROG_IDLE && progress != RSU_PROG_RSU_DONE)
+ if (!rsu_progress_done(progress))
return true;
return false;
@@ -246,11 +372,12 @@ static inline bool rsu_start_done(u32 doorbell)
static enum fw_upload_err rsu_update_init(struct m10bmc_sec *sec)
{
- u32 doorbell, status;
- int ret;
+ const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map;
+ u32 doorbell_reg, progress, status;
+ int ret, err;
ret = regmap_update_bits(sec->m10bmc->regmap,
- M10BMC_SYS_BASE + M10BMC_DOORBELL,
+ csr_map->base + csr_map->doorbell,
DRBL_RSU_REQUEST | DRBL_HOST_STATUS,
DRBL_RSU_REQUEST |
FIELD_PREP(DRBL_HOST_STATUS,
@@ -258,26 +385,25 @@ static enum fw_upload_err rsu_update_init(struct m10bmc_sec *sec)
if (ret)
return FW_UPLOAD_ERR_RW_ERROR;
- ret = regmap_read_poll_timeout(sec->m10bmc->regmap,
- M10BMC_SYS_BASE + M10BMC_DOORBELL,
- doorbell,
- rsu_start_done(doorbell),
- NIOS_HANDSHAKE_INTERVAL_US,
- NIOS_HANDSHAKE_TIMEOUT_US);
+ ret = read_poll_timeout(m10bmc_sec_progress_status, err,
+ err < 0 || rsu_start_done(doorbell_reg, progress, status),
+ NIOS_HANDSHAKE_INTERVAL_US,
+ NIOS_HANDSHAKE_TIMEOUT_US,
+ false,
+ sec, &doorbell_reg, &progress, &status);
if (ret == -ETIMEDOUT) {
- log_error_regs(sec, doorbell);
+ log_error_regs(sec, doorbell_reg);
return FW_UPLOAD_ERR_TIMEOUT;
- } else if (ret) {
+ } else if (err) {
return FW_UPLOAD_ERR_RW_ERROR;
}
- status = rsu_stat(doorbell);
if (status == RSU_STAT_WEAROUT) {
dev_warn(sec->dev, "Excessive flash update count detected\n");
return FW_UPLOAD_ERR_WEAROUT;
} else if (status == RSU_STAT_ERASE_FAIL) {
- log_error_regs(sec, doorbell);
+ log_error_regs(sec, doorbell_reg);
return FW_UPLOAD_ERR_HW_ERROR;
}
@@ -286,11 +412,12 @@ static enum fw_upload_err rsu_update_init(struct m10bmc_sec *sec)
static enum fw_upload_err rsu_prog_ready(struct m10bmc_sec *sec)
{
+ const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map;
unsigned long poll_timeout;
u32 doorbell, progress;
int ret;
- ret = m10bmc_sys_read(sec->m10bmc, M10BMC_DOORBELL, &doorbell);
+ ret = m10bmc_sys_read(sec->m10bmc, csr_map->doorbell, &doorbell);
if (ret)
return FW_UPLOAD_ERR_RW_ERROR;
@@ -300,7 +427,7 @@ static enum fw_upload_err rsu_prog_ready(struct m10bmc_sec *sec)
if (time_after(jiffies, poll_timeout))
break;
- ret = m10bmc_sys_read(sec->m10bmc, M10BMC_DOORBELL, &doorbell);
+ ret = m10bmc_sys_read(sec->m10bmc, csr_map->doorbell, &doorbell);
if (ret)
return FW_UPLOAD_ERR_RW_ERROR;
}
@@ -319,11 +446,12 @@ static enum fw_upload_err rsu_prog_ready(struct m10bmc_sec *sec)
static enum fw_upload_err rsu_send_data(struct m10bmc_sec *sec)
{
- u32 doorbell;
+ const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map;
+ u32 doorbell_reg, status;
int ret;
ret = regmap_update_bits(sec->m10bmc->regmap,
- M10BMC_SYS_BASE + M10BMC_DOORBELL,
+ csr_map->base + csr_map->doorbell,
DRBL_HOST_STATUS,
FIELD_PREP(DRBL_HOST_STATUS,
HOST_STATUS_WRITE_DONE));
@@ -331,68 +459,58 @@ static enum fw_upload_err rsu_send_data(struct m10bmc_sec *sec)
return FW_UPLOAD_ERR_RW_ERROR;
ret = regmap_read_poll_timeout(sec->m10bmc->regmap,
- M10BMC_SYS_BASE + M10BMC_DOORBELL,
- doorbell,
- rsu_prog(doorbell) != RSU_PROG_READY,
+ csr_map->base + csr_map->doorbell,
+ doorbell_reg,
+ rsu_prog(doorbell_reg) != RSU_PROG_READY,
NIOS_HANDSHAKE_INTERVAL_US,
NIOS_HANDSHAKE_TIMEOUT_US);
if (ret == -ETIMEDOUT) {
- log_error_regs(sec, doorbell);
+ log_error_regs(sec, doorbell_reg);
return FW_UPLOAD_ERR_TIMEOUT;
} else if (ret) {
return FW_UPLOAD_ERR_RW_ERROR;
}
- switch (rsu_stat(doorbell)) {
- case RSU_STAT_NORMAL:
- case RSU_STAT_NIOS_OK:
- case RSU_STAT_USER_OK:
- case RSU_STAT_FACTORY_OK:
- break;
- default:
- log_error_regs(sec, doorbell);
+ ret = sec->ops->rsu_status(sec);
+ if (ret < 0)
+ return ret;
+ status = ret;
+
+ if (!rsu_status_ok(status)) {
+ log_error_regs(sec, doorbell_reg);
return FW_UPLOAD_ERR_HW_ERROR;
}
return FW_UPLOAD_ERR_NONE;
}
-static int rsu_check_complete(struct m10bmc_sec *sec, u32 *doorbell)
+static int rsu_check_complete(struct m10bmc_sec *sec, u32 *doorbell_reg)
{
- if (m10bmc_sys_read(sec->m10bmc, M10BMC_DOORBELL, doorbell))
+ u32 progress, status;
+
+ if (m10bmc_sec_progress_status(sec, doorbell_reg, &progress, &status))
return -EIO;
- switch (rsu_stat(*doorbell)) {
- case RSU_STAT_NORMAL:
- case RSU_STAT_NIOS_OK:
- case RSU_STAT_USER_OK:
- case RSU_STAT_FACTORY_OK:
- break;
- default:
+ if (!rsu_status_ok(status))
return -EINVAL;
- }
- switch (rsu_prog(*doorbell)) {
- case RSU_PROG_IDLE:
- case RSU_PROG_RSU_DONE:
+ if (rsu_progress_done(progress))
return 0;
- case RSU_PROG_AUTHENTICATING:
- case RSU_PROG_COPYING:
- case RSU_PROG_UPDATE_CANCEL:
- case RSU_PROG_PROGRAM_KEY_HASH:
+
+ if (rsu_progress_busy(progress))
return -EAGAIN;
- default:
- return -EINVAL;
- }
+
+ return -EINVAL;
}
static enum fw_upload_err rsu_cancel(struct m10bmc_sec *sec)
{
+ const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map;
u32 doorbell;
int ret;
- ret = m10bmc_sys_read(sec->m10bmc, M10BMC_DOORBELL, &doorbell);
+ ret = m10bmc_sys_read(sec->m10bmc, csr_map->doorbell, &doorbell);
if (ret)
return FW_UPLOAD_ERR_RW_ERROR;
@@ -400,7 +518,7 @@ static enum fw_upload_err rsu_cancel(struct m10bmc_sec *sec)
return FW_UPLOAD_ERR_BUSY;
ret = regmap_update_bits(sec->m10bmc->regmap,
- M10BMC_SYS_BASE + M10BMC_DOORBELL,
+ csr_map->base + csr_map->doorbell,
DRBL_HOST_STATUS,
FIELD_PREP(DRBL_HOST_STATUS,
HOST_STATUS_ABORT_RSU));
@@ -421,39 +539,50 @@ static enum fw_upload_err m10bmc_sec_prepare(struct fw_upload *fwl,
if (!size || size > M10BMC_STAGING_SIZE)
return FW_UPLOAD_ERR_INVALID_SIZE;
+ if (sec->m10bmc->flash_bulk_ops)
+ if (sec->m10bmc->flash_bulk_ops->lock_write(sec->m10bmc))
+ return FW_UPLOAD_ERR_BUSY;
+
ret = rsu_check_idle(sec);
if (ret != FW_UPLOAD_ERR_NONE)
- return ret;
+ goto unlock_flash;
ret = rsu_update_init(sec);
if (ret != FW_UPLOAD_ERR_NONE)
- return ret;
+ goto unlock_flash;
ret = rsu_prog_ready(sec);
if (ret != FW_UPLOAD_ERR_NONE)
- return ret;
+ goto unlock_flash;
- if (sec->cancel_request)
- return rsu_cancel(sec);
+ if (sec->cancel_request) {
+ ret = rsu_cancel(sec);
+ goto unlock_flash;
+ }
return FW_UPLOAD_ERR_NONE;
+
+unlock_flash:
+ if (sec->m10bmc->flash_bulk_ops)
+ sec->m10bmc->flash_bulk_ops->unlock_write(sec->m10bmc);
+ return ret;
}
#define WRITE_BLOCK_SIZE 0x4000 /* Default write-block size is 0x4000 bytes */
-static enum fw_upload_err m10bmc_sec_write(struct fw_upload *fwl, const u8 *data,
- u32 offset, u32 size, u32 *written)
+static enum fw_upload_err m10bmc_sec_fw_write(struct fw_upload *fwl, const u8 *data,
+ u32 offset, u32 size, u32 *written)
{
struct m10bmc_sec *sec = fwl->dd_handle;
- u32 blk_size, doorbell, extra_offset;
- unsigned int stride, extra = 0;
+ const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map;
+ struct intel_m10bmc *m10bmc = sec->m10bmc;
+ u32 blk_size, doorbell;
int ret;
- stride = regmap_get_reg_stride(sec->m10bmc->regmap);
if (sec->cancel_request)
return rsu_cancel(sec);
- ret = m10bmc_sys_read(sec->m10bmc, M10BMC_DOORBELL, &doorbell);
+ ret = m10bmc_sys_read(m10bmc, csr_map->doorbell, &doorbell);
if (ret) {
return FW_UPLOAD_ERR_RW_ERROR;
} else if (rsu_prog(doorbell) != RSU_PROG_READY) {
@@ -461,28 +590,12 @@ static enum fw_upload_err m10bmc_sec_write(struct fw_upload *fwl, const u8 *data
return FW_UPLOAD_ERR_HW_ERROR;
}
- WARN_ON_ONCE(WRITE_BLOCK_SIZE % stride);
+ WARN_ON_ONCE(WRITE_BLOCK_SIZE % regmap_get_reg_stride(m10bmc->regmap));
blk_size = min_t(u32, WRITE_BLOCK_SIZE, size);
- ret = regmap_bulk_write(sec->m10bmc->regmap,
- M10BMC_STAGING_BASE + offset,
- (void *)data + offset,
- blk_size / stride);
+ ret = m10bmc_sec_write(sec, data, offset, blk_size);
if (ret)
return FW_UPLOAD_ERR_RW_ERROR;
- /*
- * If blk_size is not aligned to stride, then handle the extra
- * bytes with regmap_write.
- */
- if (blk_size % stride) {
- extra_offset = offset + ALIGN_DOWN(blk_size, stride);
- memcpy(&extra, (u8 *)(data + extra_offset), blk_size % stride);
- ret = regmap_write(sec->m10bmc->regmap,
- M10BMC_STAGING_BASE + extra_offset, extra);
- if (ret)
- return FW_UPLOAD_ERR_RW_ERROR;
- }
-
*written = blk_size;
return FW_UPLOAD_ERR_NONE;
}
@@ -539,16 +652,27 @@ static void m10bmc_sec_cleanup(struct fw_upload *fwl)
struct m10bmc_sec *sec = fwl->dd_handle;
(void)rsu_cancel(sec);
+
+ if (sec->m10bmc->flash_bulk_ops)
+ sec->m10bmc->flash_bulk_ops->unlock_write(sec->m10bmc);
}
static const struct fw_upload_ops m10bmc_ops = {
.prepare = m10bmc_sec_prepare,
- .write = m10bmc_sec_write,
+ .write = m10bmc_sec_fw_write,
.poll_complete = m10bmc_sec_poll_complete,
.cancel = m10bmc_sec_cancel,
.cleanup = m10bmc_sec_cleanup,
};
+static const struct m10bmc_sec_ops m10sec_n3000_ops = {
+ .rsu_status = m10bmc_sec_n3000_rsu_status,
+};
+
+static const struct m10bmc_sec_ops m10sec_n6000_ops = {
+ .rsu_status = m10bmc_sec_n6000_rsu_status,
+};
+
#define SEC_UPDATE_LEN_MAX 32
static int m10bmc_sec_probe(struct platform_device *pdev)
{
@@ -564,6 +688,7 @@ static int m10bmc_sec_probe(struct platform_device *pdev)
sec->dev = &pdev->dev;
sec->m10bmc = dev_get_drvdata(pdev->dev.parent);
+ sec->ops = (struct m10bmc_sec_ops *)platform_get_device_id(pdev)->driver_data;
dev_set_drvdata(&pdev->dev, sec);
ret = xa_alloc(&fw_upload_xa, &sec->fw_name_id, sec,
@@ -611,9 +736,15 @@ static int m10bmc_sec_remove(struct platform_device *pdev)
static const struct platform_device_id intel_m10bmc_sec_ids[] = {
{
.name = "n3000bmc-sec-update",
+ .driver_data = (kernel_ulong_t)&m10sec_n3000_ops,
},
{
.name = "d5005bmc-sec-update",
+ .driver_data = (kernel_ulong_t)&m10sec_n3000_ops,
+ },
+ {
+ .name = "n6000bmc-sec-update",
+ .driver_data = (kernel_ulong_t)&m10sec_n6000_ops,
},
{ }
};
diff --git a/drivers/fpga/microchip-spi.c b/drivers/fpga/microchip-spi.c
index 7436976ea904..d6070e7f5205 100644
--- a/drivers/fpga/microchip-spi.c
+++ b/drivers/fpga/microchip-spi.c
@@ -6,6 +6,7 @@
#include <asm/unaligned.h>
#include <linux/delay.h>
#include <linux/fpga/fpga-mgr.h>
+#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/spi/spi.h>
@@ -33,7 +34,7 @@
#define MPF_BITS_PER_COMPONENT_SIZE 22
-#define MPF_STATUS_POLL_RETRIES 10000
+#define MPF_STATUS_POLL_TIMEOUT (2 * USEC_PER_SEC)
#define MPF_STATUS_BUSY BIT(0)
#define MPF_STATUS_READY BIT(1)
#define MPF_STATUS_SPI_VIOLATION BIT(2)
@@ -42,46 +43,55 @@
struct mpf_priv {
struct spi_device *spi;
bool program_mode;
+ u8 tx __aligned(ARCH_KMALLOC_MINALIGN);
+ u8 rx;
};
-static int mpf_read_status(struct spi_device *spi)
+static int mpf_read_status(struct mpf_priv *priv)
{
- u8 status = 0, status_command = MPF_SPI_READ_STATUS;
- struct spi_transfer xfers[2] = { 0 };
- int ret;
-
/*
* HW status is returned on MISO in the first byte after CS went
* active. However, first reading can be inadequate, so we submit
* two identical SPI transfers and use result of the later one.
*/
- xfers[0].tx_buf = &status_command;
- xfers[1].tx_buf = &status_command;
- xfers[0].rx_buf = &status;
- xfers[1].rx_buf = &status;
- xfers[0].len = 1;
- xfers[1].len = 1;
- xfers[0].cs_change = 1;
+ struct spi_transfer xfers[2] = {
+ {
+ .tx_buf = &priv->tx,
+ .rx_buf = &priv->rx,
+ .len = 1,
+ .cs_change = 1,
+ }, {
+ .tx_buf = &priv->tx,
+ .rx_buf = &priv->rx,
+ .len = 1,
+ },
+ };
+ u8 status;
+ int ret;
- ret = spi_sync_transfer(spi, xfers, 2);
+ priv->tx = MPF_SPI_READ_STATUS;
+
+ ret = spi_sync_transfer(priv->spi, xfers, 2);
+ if (ret)
+ return ret;
+
+ status = priv->rx;
if ((status & MPF_STATUS_SPI_VIOLATION) ||
(status & MPF_STATUS_SPI_ERROR))
- ret = -EIO;
+ return -EIO;
- return ret ? : status;
+ return status;
}
static enum fpga_mgr_states mpf_ops_state(struct fpga_manager *mgr)
{
struct mpf_priv *priv = mgr->priv;
- struct spi_device *spi;
bool program_mode;
int status;
- spi = priv->spi;
program_mode = priv->program_mode;
- status = mpf_read_status(spi);
+ status = mpf_read_status(priv);
if (!program_mode && !status)
return FPGA_MGR_STATE_OPERATING;
@@ -185,52 +195,53 @@ static int mpf_ops_parse_header(struct fpga_manager *mgr,
return 0;
}
-/* Poll HW status until busy bit is cleared and mask bits are set. */
-static int mpf_poll_status(struct spi_device *spi, u8 mask)
+static int mpf_poll_status(struct mpf_priv *priv, u8 mask)
{
- int status, retries = MPF_STATUS_POLL_RETRIES;
-
- while (retries--) {
- status = mpf_read_status(spi);
- if (status < 0)
- return status;
+ int ret, status;
- if (status & MPF_STATUS_BUSY)
- continue;
-
- if (!mask || (status & mask))
- return status;
- }
+ /*
+ * Busy poll HW status. Polling stops if any of the following
+ * conditions are met:
+ * - timeout is reached
+ * - mpf_read_status() returns an error
+ * - busy bit is cleared AND mask bits are set
+ */
+ ret = read_poll_timeout(mpf_read_status, status,
+ (status < 0) ||
+ ((status & (MPF_STATUS_BUSY | mask)) == mask),
+ 0, MPF_STATUS_POLL_TIMEOUT, false, priv);
+ if (ret < 0)
+ return ret;
- return -EBUSY;
+ return status;
}
-static int mpf_spi_write(struct spi_device *spi, const void *buf, size_t buf_size)
+static int mpf_spi_write(struct mpf_priv *priv, const void *buf, size_t buf_size)
{
- int status = mpf_poll_status(spi, 0);
+ int status = mpf_poll_status(priv, 0);
if (status < 0)
return status;
- return spi_write(spi, buf, buf_size);
+ return spi_write_then_read(priv->spi, buf, buf_size, NULL, 0);
}
-static int mpf_spi_write_then_read(struct spi_device *spi,
+static int mpf_spi_write_then_read(struct mpf_priv *priv,
const void *txbuf, size_t txbuf_size,
void *rxbuf, size_t rxbuf_size)
{
const u8 read_command[] = { MPF_SPI_READ_DATA };
int ret;
- ret = mpf_spi_write(spi, txbuf, txbuf_size);
+ ret = mpf_spi_write(priv, txbuf, txbuf_size);
if (ret)
return ret;
- ret = mpf_poll_status(spi, MPF_STATUS_READY);
+ ret = mpf_poll_status(priv, MPF_STATUS_READY);
if (ret < 0)
return ret;
- return spi_write_then_read(spi, read_command, sizeof(read_command),
+ return spi_write_then_read(priv->spi, read_command, sizeof(read_command),
rxbuf, rxbuf_size);
}
@@ -242,7 +253,6 @@ static int mpf_ops_write_init(struct fpga_manager *mgr,
const u8 isc_en_command[] = { MPF_SPI_ISC_ENABLE };
struct mpf_priv *priv = mgr->priv;
struct device *dev = &mgr->dev;
- struct spi_device *spi;
u32 isc_ret = 0;
int ret;
@@ -251,9 +261,7 @@ static int mpf_ops_write_init(struct fpga_manager *mgr,
return -EOPNOTSUPP;
}
- spi = priv->spi;
-
- ret = mpf_spi_write_then_read(spi, isc_en_command, sizeof(isc_en_command),
+ ret = mpf_spi_write_then_read(priv, isc_en_command, sizeof(isc_en_command),
&isc_ret, sizeof(isc_ret));
if (ret || isc_ret) {
dev_err(dev, "Failed to enable ISC: spi_ret %d, isc_ret %u\n",
@@ -261,7 +269,7 @@ static int mpf_ops_write_init(struct fpga_manager *mgr,
return -EFAULT;
}
- ret = mpf_spi_write(spi, program_mode, sizeof(program_mode));
+ ret = mpf_spi_write(priv, program_mode, sizeof(program_mode));
if (ret) {
dev_err(dev, "Failed to enter program mode: %d\n", ret);
return ret;
@@ -272,13 +280,32 @@ static int mpf_ops_write_init(struct fpga_manager *mgr,
return 0;
}
+static int mpf_spi_frame_write(struct mpf_priv *priv, const char *buf)
+{
+ struct spi_transfer xfers[2] = {
+ {
+ .tx_buf = &priv->tx,
+ .len = 1,
+ }, {
+ .tx_buf = buf,
+ .len = MPF_SPI_FRAME_SIZE,
+ },
+ };
+ int ret;
+
+ ret = mpf_poll_status(priv, 0);
+ if (ret < 0)
+ return ret;
+
+ priv->tx = MPF_SPI_FRAME;
+
+ return spi_sync_transfer(priv->spi, xfers, ARRAY_SIZE(xfers));
+}
+
static int mpf_ops_write(struct fpga_manager *mgr, const char *buf, size_t count)
{
- u8 spi_frame_command[] = { MPF_SPI_FRAME };
- struct spi_transfer xfers[2] = { 0 };
struct mpf_priv *priv = mgr->priv;
struct device *dev = &mgr->dev;
- struct spi_device *spi;
int ret, i;
if (count % MPF_SPI_FRAME_SIZE) {
@@ -287,19 +314,8 @@ static int mpf_ops_write(struct fpga_manager *mgr, const char *buf, size_t count
return -EINVAL;
}
- spi = priv->spi;
-
- xfers[0].tx_buf = spi_frame_command;
- xfers[0].len = sizeof(spi_frame_command);
-
for (i = 0; i < count / MPF_SPI_FRAME_SIZE; i++) {
- xfers[1].tx_buf = buf + i * MPF_SPI_FRAME_SIZE;
- xfers[1].len = MPF_SPI_FRAME_SIZE;
-
- ret = mpf_poll_status(spi, 0);
- if (ret >= 0)
- ret = spi_sync_transfer(spi, xfers, ARRAY_SIZE(xfers));
-
+ ret = mpf_spi_frame_write(priv, buf + i * MPF_SPI_FRAME_SIZE);
if (ret) {
dev_err(dev, "Failed to write bitstream frame %d/%zu\n",
i, count / MPF_SPI_FRAME_SIZE);
@@ -317,12 +333,9 @@ static int mpf_ops_write_complete(struct fpga_manager *mgr,
const u8 release_command[] = { MPF_SPI_RELEASE };
struct mpf_priv *priv = mgr->priv;
struct device *dev = &mgr->dev;
- struct spi_device *spi;
int ret;
- spi = priv->spi;
-
- ret = mpf_spi_write(spi, isc_dis_command, sizeof(isc_dis_command));
+ ret = mpf_spi_write(priv, isc_dis_command, sizeof(isc_dis_command));
if (ret) {
dev_err(dev, "Failed to disable ISC: %d\n", ret);
return ret;
@@ -330,7 +343,7 @@ static int mpf_ops_write_complete(struct fpga_manager *mgr,
usleep_range(1000, 2000);
- ret = mpf_spi_write(spi, release_command, sizeof(release_command));
+ ret = mpf_spi_write(priv, release_command, sizeof(release_command));
if (ret) {
dev_err(dev, "Failed to exit program mode: %d\n", ret);
return ret;
diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
index 694e80c06665..0b927c9f4267 100644
--- a/drivers/fsi/fsi-core.c
+++ b/drivers/fsi/fsi-core.c
@@ -897,10 +897,10 @@ static const struct attribute_group *cfam_attr_groups[] = {
NULL,
};
-static char *cfam_devnode(struct device *dev, umode_t *mode,
+static char *cfam_devnode(const struct device *dev, umode_t *mode,
kuid_t *uid, kgid_t *gid)
{
- struct fsi_slave *slave = to_fsi_slave(dev);
+ const struct fsi_slave *slave = to_fsi_slave(dev);
#ifdef CONFIG_FSI_NEW_DEV_NODE
return kasprintf(GFP_KERNEL, "fsi/cfam%d", slave->cdev_idx);
@@ -915,7 +915,7 @@ static const struct device_type cfam_type = {
.groups = cfam_attr_groups
};
-static char *fsi_cdev_devnode(struct device *dev, umode_t *mode,
+static char *fsi_cdev_devnode(const struct device *dev, umode_t *mode,
kuid_t *uid, kgid_t *gid)
{
#ifdef CONFIG_FSI_NEW_DEV_NODE
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index c85726a6831f..13be729710f2 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -752,7 +752,7 @@ config GPIO_XTENSA
config GPIO_ZEVIO
bool "LSI ZEVIO SoC memory mapped GPIOs"
- depends on ARM && OF_GPIO
+ depends on ARM
help
Say yes here to support the GPIO controller in LSI ZEVIO SoCs.
@@ -821,6 +821,7 @@ menu "Port-mapped I/O GPIO drivers"
config GPIO_I8255
tristate
+ select GPIO_REGMAP
help
Enables support for the i8255 interface library functions. The i8255
interface library provides functions to facilitate communication with
@@ -835,6 +836,8 @@ config GPIO_104_DIO_48E
tristate "ACCES 104-DIO-48E GPIO support"
depends on PC104
select ISA_BUS_API
+ select REGMAP_MMIO
+ select REGMAP_IRQ
select GPIOLIB_IRQCHIP
select GPIO_I8255
help
@@ -860,8 +863,10 @@ config GPIO_104_IDI_48
tristate "ACCES 104-IDI-48 GPIO support"
depends on PC104
select ISA_BUS_API
+ select REGMAP_MMIO
+ select REGMAP_IRQ
select GPIOLIB_IRQCHIP
- select GPIO_I8255
+ select GPIO_REGMAP
help
Enables GPIO support for the ACCES 104-IDI-48 family (104-IDI-48A,
104-IDI-48AC, 104-IDI-48B, 104-IDI-48BC). The base port addresses for
@@ -883,6 +888,7 @@ config GPIO_GPIO_MM
tristate "Diamond Systems GPIO-MM GPIO support"
depends on PC104
select ISA_BUS_API
+ select REGMAP_MMIO
select GPIO_I8255
help
Enables GPIO support for the Diamond Systems GPIO-MM and GPIO-MM-12.
diff --git a/drivers/gpio/TODO b/drivers/gpio/TODO
index 76560744587a..68ada1066941 100644
--- a/drivers/gpio/TODO
+++ b/drivers/gpio/TODO
@@ -61,8 +61,8 @@ Work items:
- Get rid of struct of_mm_gpio_chip altogether: use the generic MMIO
GPIO for all current users (see below). Delete struct of_mm_gpio_chip,
- to_of_mm_gpio_chip(), of_mm_gpiochip_add_data(), of_mm_gpiochip_add()
- of_mm_gpiochip_remove() from the kernel.
+ to_of_mm_gpio_chip(), of_mm_gpiochip_add_data(), of_mm_gpiochip_remove()
+ from the kernel.
- Change all consumer drivers that #include <linux/of_gpio.h> to
#include <linux/gpio/consumer.h> and stop doing custom parsing of the
diff --git a/drivers/gpio/gpio-104-dio-48e.c b/drivers/gpio/gpio-104-dio-48e.c
index 7b8829c8e423..a3846faf3780 100644
--- a/drivers/gpio/gpio-104-dio-48e.c
+++ b/drivers/gpio/gpio-104-dio-48e.c
@@ -8,17 +8,14 @@
*/
#include <linux/bits.h>
#include <linux/device.h>
-#include <linux/errno.h>
-#include <linux/gpio/driver.h>
-#include <linux/io.h>
+#include <linux/err.h>
#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/irqdesc.h>
+#include <linux/irq.h>
#include <linux/isa.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/spinlock.h>
+#include <linux/regmap.h>
#include <linux/types.h>
#include "gpio-i8255.h"
@@ -38,212 +35,101 @@ static unsigned int num_irq;
module_param_hw_array(irq, uint, irq, &num_irq, 0);
MODULE_PARM_DESC(irq, "ACCES 104-DIO-48E interrupt line numbers");
+#define DIO48E_ENABLE_INTERRUPT 0xB
+#define DIO48E_DISABLE_INTERRUPT DIO48E_ENABLE_INTERRUPT
+#define DIO48E_CLEAR_INTERRUPT 0xF
+
#define DIO48E_NUM_PPI 2
-/**
- * struct dio48e_reg - device register structure
- * @ppi: Programmable Peripheral Interface groups
- * @enable_buffer: Enable/Disable Buffer groups
- * @unused1: Unused
- * @enable_interrupt: Write: Enable Interrupt
- * Read: Disable Interrupt
- * @unused2: Unused
- * @enable_counter: Write: Enable Counter/Timer Addressing
- * Read: Disable Counter/Timer Addressing
- * @unused3: Unused
- * @clear_interrupt: Clear Interrupt
- */
-struct dio48e_reg {
- struct i8255 ppi[DIO48E_NUM_PPI];
- u8 enable_buffer[DIO48E_NUM_PPI];
- u8 unused1;
- u8 enable_interrupt;
- u8 unused2;
- u8 enable_counter;
- u8 unused3;
- u8 clear_interrupt;
+static const struct regmap_range dio48e_wr_ranges[] = {
+ regmap_reg_range(0x0, 0x9), regmap_reg_range(0xB, 0xB),
+ regmap_reg_range(0xD, 0xD), regmap_reg_range(0xF, 0xF),
};
-
-/**
- * struct dio48e_gpio - GPIO device private data structure
- * @chip: instance of the gpio_chip
- * @ppi_state: PPI device states
- * @lock: synchronization lock to prevent I/O race conditions
- * @reg: I/O address offset for the device registers
- * @irq_mask: I/O bits affected by interrupts
- */
-struct dio48e_gpio {
- struct gpio_chip chip;
- struct i8255_state ppi_state[DIO48E_NUM_PPI];
- raw_spinlock_t lock;
- struct dio48e_reg __iomem *reg;
- unsigned char irq_mask;
+static const struct regmap_range dio48e_rd_ranges[] = {
+ regmap_reg_range(0x0, 0x2), regmap_reg_range(0x4, 0x6),
+ regmap_reg_range(0xB, 0xB), regmap_reg_range(0xD, 0xD),
+ regmap_reg_range(0xF, 0xF),
+};
+static const struct regmap_range dio48e_volatile_ranges[] = {
+ i8255_volatile_regmap_range(0x0), i8255_volatile_regmap_range(0x4),
+ regmap_reg_range(0xB, 0xB), regmap_reg_range(0xD, 0xD),
+ regmap_reg_range(0xF, 0xF),
+};
+static const struct regmap_range dio48e_precious_ranges[] = {
+ regmap_reg_range(0xB, 0xB), regmap_reg_range(0xD, 0xD),
+ regmap_reg_range(0xF, 0xF),
+};
+static const struct regmap_access_table dio48e_wr_table = {
+ .yes_ranges = dio48e_wr_ranges,
+ .n_yes_ranges = ARRAY_SIZE(dio48e_wr_ranges),
+};
+static const struct regmap_access_table dio48e_rd_table = {
+ .yes_ranges = dio48e_rd_ranges,
+ .n_yes_ranges = ARRAY_SIZE(dio48e_rd_ranges),
+};
+static const struct regmap_access_table dio48e_volatile_table = {
+ .yes_ranges = dio48e_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(dio48e_volatile_ranges),
+};
+static const struct regmap_access_table dio48e_precious_table = {
+ .yes_ranges = dio48e_precious_ranges,
+ .n_yes_ranges = ARRAY_SIZE(dio48e_precious_ranges),
+};
+static const struct regmap_config dio48e_regmap_config = {
+ .reg_bits = 8,
+ .reg_stride = 1,
+ .val_bits = 8,
+ .io_port = true,
+ .max_register = 0xF,
+ .wr_table = &dio48e_wr_table,
+ .rd_table = &dio48e_rd_table,
+ .volatile_table = &dio48e_volatile_table,
+ .precious_table = &dio48e_precious_table,
+ .cache_type = REGCACHE_FLAT,
};
-static int dio48e_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
-{
- struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
-
- if (i8255_get_direction(dio48egpio->ppi_state, offset))
- return GPIO_LINE_DIRECTION_IN;
-
- return GPIO_LINE_DIRECTION_OUT;
-}
-
-static int dio48e_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
-{
- struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
-
- i8255_direction_input(dio48egpio->reg->ppi, dio48egpio->ppi_state,
- offset);
-
- return 0;
-}
-
-static int dio48e_gpio_direction_output(struct gpio_chip *chip, unsigned int offset,
- int value)
-{
- struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
-
- i8255_direction_output(dio48egpio->reg->ppi, dio48egpio->ppi_state,
- offset, value);
-
- return 0;
-}
-
-static int dio48e_gpio_get(struct gpio_chip *chip, unsigned int offset)
-{
- struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
-
- return i8255_get(dio48egpio->reg->ppi, offset);
-}
-
-static int dio48e_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
- unsigned long *bits)
-{
- struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
-
- i8255_get_multiple(dio48egpio->reg->ppi, mask, bits, chip->ngpio);
-
- return 0;
-}
-
-static void dio48e_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
-{
- struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
-
- i8255_set(dio48egpio->reg->ppi, dio48egpio->ppi_state, offset, value);
-}
-
-static void dio48e_gpio_set_multiple(struct gpio_chip *chip,
- unsigned long *mask, unsigned long *bits)
-{
- struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
-
- i8255_set_multiple(dio48egpio->reg->ppi, dio48egpio->ppi_state, mask,
- bits, chip->ngpio);
-}
-
-static void dio48e_irq_ack(struct irq_data *data)
-{
-}
-
-static void dio48e_irq_mask(struct irq_data *data)
-{
- struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
- struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
- const unsigned long offset = irqd_to_hwirq(data);
- unsigned long flags;
-
- /* only bit 3 on each respective Port C supports interrupts */
- if (offset != 19 && offset != 43)
- return;
-
- raw_spin_lock_irqsave(&dio48egpio->lock, flags);
-
- if (offset == 19)
- dio48egpio->irq_mask &= ~BIT(0);
- else
- dio48egpio->irq_mask &= ~BIT(1);
- gpiochip_disable_irq(chip, offset);
-
- if (!dio48egpio->irq_mask)
- /* disable interrupts */
- ioread8(&dio48egpio->reg->enable_interrupt);
-
- raw_spin_unlock_irqrestore(&dio48egpio->lock, flags);
-}
-
-static void dio48e_irq_unmask(struct irq_data *data)
-{
- struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
- struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
- const unsigned long offset = irqd_to_hwirq(data);
- unsigned long flags;
-
- /* only bit 3 on each respective Port C supports interrupts */
- if (offset != 19 && offset != 43)
- return;
-
- raw_spin_lock_irqsave(&dio48egpio->lock, flags);
-
- if (!dio48egpio->irq_mask) {
- /* enable interrupts */
- iowrite8(0x00, &dio48egpio->reg->clear_interrupt);
- iowrite8(0x00, &dio48egpio->reg->enable_interrupt);
+/* only bit 3 on each respective Port C supports interrupts */
+#define DIO48E_REGMAP_IRQ(_ppi) \
+ [19 + (_ppi) * 24] = { \
+ .mask = BIT(_ppi), \
+ .type = { .types_supported = IRQ_TYPE_EDGE_RISING }, \
}
- gpiochip_enable_irq(chip, offset);
- if (offset == 19)
- dio48egpio->irq_mask |= BIT(0);
- else
- dio48egpio->irq_mask |= BIT(1);
-
- raw_spin_unlock_irqrestore(&dio48egpio->lock, flags);
-}
-
-static int dio48e_irq_set_type(struct irq_data *data, unsigned int flow_type)
-{
- const unsigned long offset = irqd_to_hwirq(data);
-
- /* only bit 3 on each respective Port C supports interrupts */
- if (offset != 19 && offset != 43)
- return -EINVAL;
-
- if (flow_type != IRQ_TYPE_NONE && flow_type != IRQ_TYPE_EDGE_RISING)
- return -EINVAL;
-
- return 0;
-}
-
-static const struct irq_chip dio48e_irqchip = {
- .name = "104-dio-48e",
- .irq_ack = dio48e_irq_ack,
- .irq_mask = dio48e_irq_mask,
- .irq_unmask = dio48e_irq_unmask,
- .irq_set_type = dio48e_irq_set_type,
- .flags = IRQCHIP_IMMUTABLE,
- GPIOCHIP_IRQ_RESOURCE_HELPERS,
+static const struct regmap_irq dio48e_regmap_irqs[] = {
+ DIO48E_REGMAP_IRQ(0), DIO48E_REGMAP_IRQ(1),
};
-static irqreturn_t dio48e_irq_handler(int irq, void *dev_id)
+static int dio48e_handle_mask_sync(struct regmap *const map, const int index,
+ const unsigned int mask_buf_def,
+ const unsigned int mask_buf,
+ void *const irq_drv_data)
{
- struct dio48e_gpio *const dio48egpio = dev_id;
- struct gpio_chip *const chip = &dio48egpio->chip;
- const unsigned long irq_mask = dio48egpio->irq_mask;
- unsigned long gpio;
+ unsigned int *const irq_mask = irq_drv_data;
+ const unsigned int prev_mask = *irq_mask;
+ const unsigned int all_masked = GENMASK(1, 0);
+ int err;
+ unsigned int val;
- for_each_set_bit(gpio, &irq_mask, 2)
- generic_handle_domain_irq(chip->irq.domain,
- 19 + gpio*24);
+ /* exit early if no change since the previous mask */
+ if (mask_buf == prev_mask)
+ return 0;
- raw_spin_lock(&dio48egpio->lock);
+ /* remember the current mask for the next mask sync */
+ *irq_mask = mask_buf;
- iowrite8(0x00, &dio48egpio->reg->clear_interrupt);
+ /* if all previously masked, enable interrupts when unmasking */
+ if (prev_mask == all_masked) {
+ err = regmap_write(map, DIO48E_CLEAR_INTERRUPT, 0x00);
+ if (err)
+ return err;
+ return regmap_write(map, DIO48E_ENABLE_INTERRUPT, 0x00);
+ }
- raw_spin_unlock(&dio48egpio->lock);
+ /* if all are currently masked, disable interrupts */
+ if (mask_buf == all_masked)
+ return regmap_read(map, DIO48E_DISABLE_INTERRUPT, &val);
- return IRQ_HANDLED;
+ return 0;
}
#define DIO48E_NGPIO 48
@@ -266,41 +152,24 @@ static const char *dio48e_names[DIO48E_NGPIO] = {
"PPI Group 1 Port C 5", "PPI Group 1 Port C 6", "PPI Group 1 Port C 7"
};
-static int dio48e_irq_init_hw(struct gpio_chip *gc)
+static int dio48e_irq_init_hw(struct regmap *const map)
{
- struct dio48e_gpio *const dio48egpio = gpiochip_get_data(gc);
+ unsigned int val;
/* Disable IRQ by default */
- ioread8(&dio48egpio->reg->enable_interrupt);
-
- return 0;
-}
-
-static void dio48e_init_ppi(struct i8255 __iomem *const ppi,
- struct i8255_state *const ppi_state)
-{
- const unsigned long ngpio = 24;
- const unsigned long mask = GENMASK(ngpio - 1, 0);
- const unsigned long bits = 0;
- unsigned long i;
-
- /* Initialize all GPIO to output 0 */
- for (i = 0; i < DIO48E_NUM_PPI; i++) {
- i8255_mode0_output(&ppi[i]);
- i8255_set_multiple(&ppi[i], &ppi_state[i], &mask, &bits, ngpio);
- }
+ return regmap_read(map, DIO48E_DISABLE_INTERRUPT, &val);
}
static int dio48e_probe(struct device *dev, unsigned int id)
{
- struct dio48e_gpio *dio48egpio;
const char *const name = dev_name(dev);
- struct gpio_irq_chip *girq;
+ struct i8255_regmap_config config = {};
+ void __iomem *regs;
+ struct regmap *map;
int err;
-
- dio48egpio = devm_kzalloc(dev, sizeof(*dio48egpio), GFP_KERNEL);
- if (!dio48egpio)
- return -ENOMEM;
+ struct regmap_irq_chip *chip;
+ unsigned int irq_mask;
+ struct regmap_irq_chip_data *chip_data;
if (!devm_request_region(dev, base[id], DIO48E_EXTENT, name)) {
dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
@@ -308,53 +177,52 @@ static int dio48e_probe(struct device *dev, unsigned int id)
return -EBUSY;
}
- dio48egpio->reg = devm_ioport_map(dev, base[id], DIO48E_EXTENT);
- if (!dio48egpio->reg)
+ regs = devm_ioport_map(dev, base[id], DIO48E_EXTENT);
+ if (!regs)
return -ENOMEM;
- dio48egpio->chip.label = name;
- dio48egpio->chip.parent = dev;
- dio48egpio->chip.owner = THIS_MODULE;
- dio48egpio->chip.base = -1;
- dio48egpio->chip.ngpio = DIO48E_NGPIO;
- dio48egpio->chip.names = dio48e_names;
- dio48egpio->chip.get_direction = dio48e_gpio_get_direction;
- dio48egpio->chip.direction_input = dio48e_gpio_direction_input;
- dio48egpio->chip.direction_output = dio48e_gpio_direction_output;
- dio48egpio->chip.get = dio48e_gpio_get;
- dio48egpio->chip.get_multiple = dio48e_gpio_get_multiple;
- dio48egpio->chip.set = dio48e_gpio_set;
- dio48egpio->chip.set_multiple = dio48e_gpio_set_multiple;
-
- girq = &dio48egpio->chip.irq;
- gpio_irq_chip_set_chip(girq, &dio48e_irqchip);
- /* This will let us handle the parent IRQ in the driver */
- girq->parent_handler = NULL;
- girq->num_parents = 0;
- girq->parents = NULL;
- girq->default_type = IRQ_TYPE_NONE;
- girq->handler = handle_edge_irq;
- girq->init_hw = dio48e_irq_init_hw;
-
- raw_spin_lock_init(&dio48egpio->lock);
-
- i8255_state_init(dio48egpio->ppi_state, DIO48E_NUM_PPI);
- dio48e_init_ppi(dio48egpio->reg->ppi, dio48egpio->ppi_state);
-
- err = devm_gpiochip_add_data(dev, &dio48egpio->chip, dio48egpio);
- if (err) {
- dev_err(dev, "GPIO registering failed (%d)\n", err);
- return err;
- }
+ map = devm_regmap_init_mmio(dev, regs, &dio48e_regmap_config);
+ if (IS_ERR(map))
+ return dev_err_probe(dev, PTR_ERR(map),
+ "Unable to initialize register map\n");
- err = devm_request_irq(dev, irq[id], dio48e_irq_handler, 0, name,
- dio48egpio);
- if (err) {
- dev_err(dev, "IRQ handler registering failed (%d)\n", err);
+ chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->irq_drv_data = devm_kzalloc(dev, sizeof(irq_mask), GFP_KERNEL);
+ if (!chip->irq_drv_data)
+ return -ENOMEM;
+
+ chip->name = name;
+ /* No IRQ status register so use CLEAR_INTERRUPT register instead */
+ chip->status_base = DIO48E_CLEAR_INTERRUPT;
+ chip->mask_base = DIO48E_ENABLE_INTERRUPT;
+ chip->ack_base = DIO48E_CLEAR_INTERRUPT;
+ /* CLEAR_INTERRUPT doubles as status register so we need it cleared */
+ chip->clear_ack = true;
+ chip->status_invert = true;
+ chip->num_regs = 1;
+ chip->irqs = dio48e_regmap_irqs;
+ chip->num_irqs = ARRAY_SIZE(dio48e_regmap_irqs);
+ chip->handle_mask_sync = dio48e_handle_mask_sync;
+
+ /* Initialize to prevent spurious interrupts before we're ready */
+ err = dio48e_irq_init_hw(map);
+ if (err)
return err;
- }
- return 0;
+ err = devm_regmap_add_irq_chip(dev, map, irq[id], 0, 0, chip, &chip_data);
+ if (err)
+ return dev_err_probe(dev, err, "IRQ registration failed\n");
+
+ config.parent = dev;
+ config.map = map;
+ config.num_ppi = DIO48E_NUM_PPI;
+ config.names = dio48e_names;
+ config.domain = regmap_irq_get_domain(chip_data);
+
+ return devm_i8255_regmap_register(dev, &config);
}
static struct isa_driver dio48e_driver = {
diff --git a/drivers/gpio/gpio-104-idi-48.c b/drivers/gpio/gpio-104-idi-48.c
index c5e231fde1af..ca2175b84e24 100644
--- a/drivers/gpio/gpio-104-idi-48.c
+++ b/drivers/gpio/gpio-104-idi-48.c
@@ -8,23 +8,18 @@
*/
#include <linux/bits.h>
#include <linux/device.h>
-#include <linux/errno.h>
-#include <linux/gpio/driver.h>
-#include <linux/io.h>
-#include <linux/ioport.h>
+#include <linux/err.h>
+#include <linux/gpio/regmap.h>
#include <linux/interrupt.h>
-#include <linux/irqdesc.h>
+#include <linux/ioport.h>
+#include <linux/irq.h>
#include <linux/isa.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/spinlock.h>
+#include <linux/regmap.h>
#include <linux/types.h>
-#include "gpio-i8255.h"
-
-MODULE_IMPORT_NS(I8255);
-
#define IDI_48_EXTENT 8
#define MAX_NUM_IDI_48 max_num_isa_dev(IDI_48_EXTENT)
@@ -38,185 +33,83 @@ static unsigned int num_irq;
module_param_hw_array(irq, uint, irq, &num_irq, 0);
MODULE_PARM_DESC(irq, "ACCES 104-IDI-48 interrupt line numbers");
-/**
- * struct idi_48_reg - device register structure
- * @port0: Port 0 Inputs
- * @unused: Unused
- * @port1: Port 1 Inputs
- * @irq: Read: IRQ Status Register/IRQ Clear
- * Write: IRQ Enable/Disable
- */
-struct idi_48_reg {
- u8 port0[3];
- u8 unused;
- u8 port1[3];
- u8 irq;
-};
+#define IDI48_IRQ_STATUS 0x7
+#define IDI48_IRQ_ENABLE IDI48_IRQ_STATUS
-/**
- * struct idi_48_gpio - GPIO device private data structure
- * @chip: instance of the gpio_chip
- * @lock: synchronization lock to prevent I/O race conditions
- * @irq_mask: input bits affected by interrupts
- * @reg: I/O address offset for the device registers
- * @cos_enb: Change-Of-State IRQ enable boundaries mask
- */
-struct idi_48_gpio {
- struct gpio_chip chip;
- spinlock_t lock;
- unsigned char irq_mask[6];
- struct idi_48_reg __iomem *reg;
- unsigned char cos_enb;
-};
-
-static int idi_48_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
+static int idi_48_reg_mask_xlate(struct gpio_regmap *gpio, unsigned int base,
+ unsigned int offset, unsigned int *reg,
+ unsigned int *mask)
{
- return GPIO_LINE_DIRECTION_IN;
-}
+ const unsigned int line = offset % 8;
+ const unsigned int stride = offset / 8;
+ const unsigned int port = (stride / 3) * 4;
+ const unsigned int port_stride = stride % 3;
-static int idi_48_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
-{
- return 0;
-}
-
-static int idi_48_gpio_get(struct gpio_chip *chip, unsigned int offset)
-{
- struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
- void __iomem *const ppi = idi48gpio->reg;
-
- return i8255_get(ppi, offset);
-}
-
-static int idi_48_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
- unsigned long *bits)
-{
- struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
- void __iomem *const ppi = idi48gpio->reg;
-
- i8255_get_multiple(ppi, mask, bits, chip->ngpio);
+ *reg = base + port + port_stride;
+ *mask = BIT(line);
return 0;
}
-static void idi_48_irq_ack(struct irq_data *data)
-{
-}
-
-static void idi_48_irq_mask(struct irq_data *data)
-{
- struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
- struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
- const unsigned int offset = irqd_to_hwirq(data);
- const unsigned long boundary = offset / 8;
- const unsigned long mask = BIT(offset % 8);
- unsigned long flags;
-
- spin_lock_irqsave(&idi48gpio->lock, flags);
-
- idi48gpio->irq_mask[boundary] &= ~mask;
- gpiochip_disable_irq(chip, offset);
-
- /* Exit early if there are still input lines with IRQ unmasked */
- if (idi48gpio->irq_mask[boundary])
- goto exit;
-
- idi48gpio->cos_enb &= ~BIT(boundary);
-
- iowrite8(idi48gpio->cos_enb, &idi48gpio->reg->irq);
-
-exit:
- spin_unlock_irqrestore(&idi48gpio->lock, flags);
-}
-
-static void idi_48_irq_unmask(struct irq_data *data)
-{
- struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
- struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
- const unsigned int offset = irqd_to_hwirq(data);
- const unsigned long boundary = offset / 8;
- const unsigned long mask = BIT(offset % 8);
- unsigned int prev_irq_mask;
- unsigned long flags;
-
- spin_lock_irqsave(&idi48gpio->lock, flags);
-
- prev_irq_mask = idi48gpio->irq_mask[boundary];
-
- gpiochip_enable_irq(chip, offset);
- idi48gpio->irq_mask[boundary] |= mask;
-
- /* Exit early if IRQ was already unmasked for this boundary */
- if (prev_irq_mask)
- goto exit;
-
- idi48gpio->cos_enb |= BIT(boundary);
-
- iowrite8(idi48gpio->cos_enb, &idi48gpio->reg->irq);
-
-exit:
- spin_unlock_irqrestore(&idi48gpio->lock, flags);
-}
-
-static int idi_48_irq_set_type(struct irq_data *data, unsigned int flow_type)
-{
- /* The only valid irq types are none and both-edges */
- if (flow_type != IRQ_TYPE_NONE &&
- (flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH)
- return -EINVAL;
-
- return 0;
-}
-
-static const struct irq_chip idi_48_irqchip = {
- .name = "104-idi-48",
- .irq_ack = idi_48_irq_ack,
- .irq_mask = idi_48_irq_mask,
- .irq_unmask = idi_48_irq_unmask,
- .irq_set_type = idi_48_irq_set_type,
- .flags = IRQCHIP_IMMUTABLE,
- GPIOCHIP_IRQ_RESOURCE_HELPERS,
+static const struct regmap_range idi_48_wr_ranges[] = {
+ regmap_reg_range(0x0, 0x6),
+};
+static const struct regmap_range idi_48_rd_ranges[] = {
+ regmap_reg_range(0x0, 0x2), regmap_reg_range(0x4, 0x7),
+};
+static const struct regmap_range idi_48_precious_ranges[] = {
+ regmap_reg_range(0x7, 0x7),
+};
+static const struct regmap_access_table idi_48_wr_table = {
+ .no_ranges = idi_48_wr_ranges,
+ .n_no_ranges = ARRAY_SIZE(idi_48_wr_ranges),
+};
+static const struct regmap_access_table idi_48_rd_table = {
+ .yes_ranges = idi_48_rd_ranges,
+ .n_yes_ranges = ARRAY_SIZE(idi_48_rd_ranges),
+};
+static const struct regmap_access_table idi_48_precious_table = {
+ .yes_ranges = idi_48_precious_ranges,
+ .n_yes_ranges = ARRAY_SIZE(idi_48_precious_ranges),
+};
+static const struct regmap_config idi48_regmap_config = {
+ .reg_bits = 8,
+ .reg_stride = 1,
+ .val_bits = 8,
+ .io_port = true,
+ .max_register = 0x6,
+ .wr_table = &idi_48_wr_table,
+ .rd_table = &idi_48_rd_table,
+ .precious_table = &idi_48_precious_table,
};
-static irqreturn_t idi_48_irq_handler(int irq, void *dev_id)
-{
- struct idi_48_gpio *const idi48gpio = dev_id;
- unsigned long cos_status;
- unsigned long boundary;
- unsigned long irq_mask;
- unsigned long bit_num;
- unsigned long gpio;
- struct gpio_chip *const chip = &idi48gpio->chip;
-
- spin_lock(&idi48gpio->lock);
-
- cos_status = ioread8(&idi48gpio->reg->irq);
-
- /* IRQ Status (bit 6) is active low (0 = IRQ generated by device) */
- if (cos_status & BIT(6)) {
- spin_unlock(&idi48gpio->lock);
- return IRQ_NONE;
- }
-
- /* Bit 0-5 indicate which Change-Of-State boundary triggered the IRQ */
- cos_status &= 0x3F;
-
- for_each_set_bit(boundary, &cos_status, 6) {
- irq_mask = idi48gpio->irq_mask[boundary];
-
- for_each_set_bit(bit_num, &irq_mask, 8) {
- gpio = bit_num + boundary * 8;
+#define IDI48_NGPIO 48
- generic_handle_domain_irq(chip->irq.domain,
- gpio);
- }
+#define IDI48_REGMAP_IRQ(_id) \
+ [_id] = { \
+ .mask = BIT((_id) / 8), \
+ .type = { .types_supported = IRQ_TYPE_EDGE_BOTH }, \
}
- spin_unlock(&idi48gpio->lock);
-
- return IRQ_HANDLED;
-}
+static const struct regmap_irq idi48_regmap_irqs[IDI48_NGPIO] = {
+ IDI48_REGMAP_IRQ(0), IDI48_REGMAP_IRQ(1), IDI48_REGMAP_IRQ(2), /* 0-2 */
+ IDI48_REGMAP_IRQ(3), IDI48_REGMAP_IRQ(4), IDI48_REGMAP_IRQ(5), /* 3-5 */
+ IDI48_REGMAP_IRQ(6), IDI48_REGMAP_IRQ(7), IDI48_REGMAP_IRQ(8), /* 6-8 */
+ IDI48_REGMAP_IRQ(9), IDI48_REGMAP_IRQ(10), IDI48_REGMAP_IRQ(11), /* 9-11 */
+ IDI48_REGMAP_IRQ(12), IDI48_REGMAP_IRQ(13), IDI48_REGMAP_IRQ(14), /* 12-14 */
+ IDI48_REGMAP_IRQ(15), IDI48_REGMAP_IRQ(16), IDI48_REGMAP_IRQ(17), /* 15-17 */
+ IDI48_REGMAP_IRQ(18), IDI48_REGMAP_IRQ(19), IDI48_REGMAP_IRQ(20), /* 18-20 */
+ IDI48_REGMAP_IRQ(21), IDI48_REGMAP_IRQ(22), IDI48_REGMAP_IRQ(23), /* 21-23 */
+ IDI48_REGMAP_IRQ(24), IDI48_REGMAP_IRQ(25), IDI48_REGMAP_IRQ(26), /* 24-26 */
+ IDI48_REGMAP_IRQ(27), IDI48_REGMAP_IRQ(28), IDI48_REGMAP_IRQ(29), /* 27-29 */
+ IDI48_REGMAP_IRQ(30), IDI48_REGMAP_IRQ(31), IDI48_REGMAP_IRQ(32), /* 30-32 */
+ IDI48_REGMAP_IRQ(33), IDI48_REGMAP_IRQ(34), IDI48_REGMAP_IRQ(35), /* 33-35 */
+ IDI48_REGMAP_IRQ(36), IDI48_REGMAP_IRQ(37), IDI48_REGMAP_IRQ(38), /* 36-38 */
+ IDI48_REGMAP_IRQ(39), IDI48_REGMAP_IRQ(40), IDI48_REGMAP_IRQ(41), /* 39-41 */
+ IDI48_REGMAP_IRQ(42), IDI48_REGMAP_IRQ(43), IDI48_REGMAP_IRQ(44), /* 42-44 */
+ IDI48_REGMAP_IRQ(45), IDI48_REGMAP_IRQ(46), IDI48_REGMAP_IRQ(47), /* 45-47 */
+};
-#define IDI48_NGPIO 48
static const char *idi48_names[IDI48_NGPIO] = {
"Bit 0 A", "Bit 1 A", "Bit 2 A", "Bit 3 A", "Bit 4 A", "Bit 5 A",
"Bit 6 A", "Bit 7 A", "Bit 8 A", "Bit 9 A", "Bit 10 A", "Bit 11 A",
@@ -228,75 +121,58 @@ static const char *idi48_names[IDI48_NGPIO] = {
"Bit 18 B", "Bit 19 B", "Bit 20 B", "Bit 21 B", "Bit 22 B", "Bit 23 B"
};
-static int idi_48_irq_init_hw(struct gpio_chip *gc)
-{
- struct idi_48_gpio *const idi48gpio = gpiochip_get_data(gc);
-
- /* Disable IRQ by default */
- iowrite8(0, &idi48gpio->reg->irq);
- ioread8(&idi48gpio->reg->irq);
-
- return 0;
-}
-
static int idi_48_probe(struct device *dev, unsigned int id)
{
- struct idi_48_gpio *idi48gpio;
const char *const name = dev_name(dev);
- struct gpio_irq_chip *girq;
+ struct gpio_regmap_config config = {};
+ void __iomem *regs;
+ struct regmap *map;
+ struct regmap_irq_chip *chip;
+ struct regmap_irq_chip_data *chip_data;
int err;
- idi48gpio = devm_kzalloc(dev, sizeof(*idi48gpio), GFP_KERNEL);
- if (!idi48gpio)
- return -ENOMEM;
-
if (!devm_request_region(dev, base[id], IDI_48_EXTENT, name)) {
dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
base[id], base[id] + IDI_48_EXTENT);
return -EBUSY;
}
- idi48gpio->reg = devm_ioport_map(dev, base[id], IDI_48_EXTENT);
- if (!idi48gpio->reg)
+ regs = devm_ioport_map(dev, base[id], IDI_48_EXTENT);
+ if (!regs)
return -ENOMEM;
- idi48gpio->chip.label = name;
- idi48gpio->chip.parent = dev;
- idi48gpio->chip.owner = THIS_MODULE;
- idi48gpio->chip.base = -1;
- idi48gpio->chip.ngpio = IDI48_NGPIO;
- idi48gpio->chip.names = idi48_names;
- idi48gpio->chip.get_direction = idi_48_gpio_get_direction;
- idi48gpio->chip.direction_input = idi_48_gpio_direction_input;
- idi48gpio->chip.get = idi_48_gpio_get;
- idi48gpio->chip.get_multiple = idi_48_gpio_get_multiple;
-
- girq = &idi48gpio->chip.irq;
- gpio_irq_chip_set_chip(girq, &idi_48_irqchip);
- /* This will let us handle the parent IRQ in the driver */
- girq->parent_handler = NULL;
- girq->num_parents = 0;
- girq->parents = NULL;
- girq->default_type = IRQ_TYPE_NONE;
- girq->handler = handle_edge_irq;
- girq->init_hw = idi_48_irq_init_hw;
-
- spin_lock_init(&idi48gpio->lock);
+ map = devm_regmap_init_mmio(dev, regs, &idi48_regmap_config);
+ if (IS_ERR(map))
+ return dev_err_probe(dev, PTR_ERR(map),
+ "Unable to initialize register map\n");
- err = devm_gpiochip_add_data(dev, &idi48gpio->chip, idi48gpio);
- if (err) {
- dev_err(dev, "GPIO registering failed (%d)\n", err);
- return err;
- }
-
- err = devm_request_irq(dev, irq[id], idi_48_irq_handler, IRQF_SHARED,
- name, idi48gpio);
- if (err) {
- dev_err(dev, "IRQ handler registering failed (%d)\n", err);
- return err;
- }
+ chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
- return 0;
+ chip->name = name;
+ chip->status_base = IDI48_IRQ_STATUS;
+ chip->unmask_base = IDI48_IRQ_ENABLE;
+ chip->clear_on_unmask = true;
+ chip->num_regs = 1;
+ chip->irqs = idi48_regmap_irqs;
+ chip->num_irqs = ARRAY_SIZE(idi48_regmap_irqs);
+
+ err = devm_regmap_add_irq_chip(dev, map, irq[id], IRQF_SHARED, 0, chip,
+ &chip_data);
+ if (err)
+ return dev_err_probe(dev, err, "IRQ registration failed\n");
+
+ config.parent = dev;
+ config.regmap = map;
+ config.ngpio = IDI48_NGPIO;
+ config.names = idi48_names;
+ config.reg_dat_base = GPIO_REGMAP_ADDR(0x0);
+ config.ngpio_per_reg = 8;
+ config.reg_mask_xlate = idi_48_reg_mask_xlate;
+ config.irq_domain = regmap_irq_get_domain(chip_data);
+
+ return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &config));
}
static struct isa_driver idi_48_driver = {
diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c
index fa51a91afa54..26b1f7465e09 100644
--- a/drivers/gpio/gpio-davinci.c
+++ b/drivers/gpio/gpio-davinci.c
@@ -252,7 +252,6 @@ static int davinci_gpio_probe(struct platform_device *pdev)
chips->chip.base = pdata->no_auto_base ? pdata->base : -1;
#ifdef CONFIG_OF_GPIO
- chips->chip.of_gpio_n_cells = 2;
chips->chip.parent = dev;
chips->chip.request = gpiochip_generic_request;
chips->chip.free = gpiochip_generic_free;
@@ -534,7 +533,7 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev)
}
/*
- * Arrange gpio_to_irq() support, handling either direct IRQs or
+ * Arrange gpiod_to_irq() support, handling either direct IRQs or
* banked IRQs. Having GPIOs in the first GPIO bank use direct
* IRQs, while the others use banked IRQs, would need some setup
* tweaks to recognize hardware which can do that.
diff --git a/drivers/gpio/gpio-ge.c b/drivers/gpio/gpio-ge.c
index f6a3de99f7db..7bd4c2a4cc11 100644
--- a/drivers/gpio/gpio-ge.c
+++ b/drivers/gpio/gpio-ge.c
@@ -81,7 +81,6 @@ static int __init gef_gpio_probe(struct platform_device *pdev)
gc->base = -1;
gc->ngpio = (u16)(uintptr_t)of_device_get_match_data(&pdev->dev);
- gc->of_gpio_n_cells = 2;
/* This function adds a memory mapped GPIO chip */
ret = devm_gpiochip_add_data(&pdev->dev, gc, NULL);
diff --git a/drivers/gpio/gpio-gpio-mm.c b/drivers/gpio/gpio-gpio-mm.c
index 2689671b6b01..43d823a56e59 100644
--- a/drivers/gpio/gpio-gpio-mm.c
+++ b/drivers/gpio/gpio-gpio-mm.c
@@ -8,13 +8,13 @@
*/
#include <linux/device.h>
#include <linux/errno.h>
-#include <linux/gpio/driver.h>
-#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/isa.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
#include "gpio-i8255.h"
@@ -30,83 +30,22 @@ MODULE_PARM_DESC(base, "Diamond Systems GPIO-MM base addresses");
#define GPIOMM_NUM_PPI 2
-/**
- * struct gpiomm_gpio - GPIO device private data structure
- * @chip: instance of the gpio_chip
- * @ppi_state: Programmable Peripheral Interface group states
- * @ppi: Programmable Peripheral Interface groups
- */
-struct gpiomm_gpio {
- struct gpio_chip chip;
- struct i8255_state ppi_state[GPIOMM_NUM_PPI];
- struct i8255 __iomem *ppi;
+static const struct regmap_range gpiomm_volatile_ranges[] = {
+ i8255_volatile_regmap_range(0x0), i8255_volatile_regmap_range(0x4),
+};
+static const struct regmap_access_table gpiomm_volatile_table = {
+ .yes_ranges = gpiomm_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(gpiomm_volatile_ranges),
+};
+static const struct regmap_config gpiomm_regmap_config = {
+ .reg_bits = 8,
+ .reg_stride = 1,
+ .val_bits = 8,
+ .io_port = true,
+ .max_register = 0x7,
+ .volatile_table = &gpiomm_volatile_table,
+ .cache_type = REGCACHE_FLAT,
};
-
-static int gpiomm_gpio_get_direction(struct gpio_chip *chip,
- unsigned int offset)
-{
- struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
-
- if (i8255_get_direction(gpiommgpio->ppi_state, offset))
- return GPIO_LINE_DIRECTION_IN;
-
- return GPIO_LINE_DIRECTION_OUT;
-}
-
-static int gpiomm_gpio_direction_input(struct gpio_chip *chip,
- unsigned int offset)
-{
- struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
-
- i8255_direction_input(gpiommgpio->ppi, gpiommgpio->ppi_state, offset);
-
- return 0;
-}
-
-static int gpiomm_gpio_direction_output(struct gpio_chip *chip,
- unsigned int offset, int value)
-{
- struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
-
- i8255_direction_output(gpiommgpio->ppi, gpiommgpio->ppi_state, offset,
- value);
-
- return 0;
-}
-
-static int gpiomm_gpio_get(struct gpio_chip *chip, unsigned int offset)
-{
- struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
-
- return i8255_get(gpiommgpio->ppi, offset);
-}
-
-static int gpiomm_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
- unsigned long *bits)
-{
- struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
-
- i8255_get_multiple(gpiommgpio->ppi, mask, bits, chip->ngpio);
-
- return 0;
-}
-
-static void gpiomm_gpio_set(struct gpio_chip *chip, unsigned int offset,
- int value)
-{
- struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
-
- i8255_set(gpiommgpio->ppi, gpiommgpio->ppi_state, offset, value);
-}
-
-static void gpiomm_gpio_set_multiple(struct gpio_chip *chip,
- unsigned long *mask, unsigned long *bits)
-{
- struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
-
- i8255_set_multiple(gpiommgpio->ppi, gpiommgpio->ppi_state, mask, bits,
- chip->ngpio);
-}
#define GPIOMM_NGPIO 48
static const char *gpiomm_names[GPIOMM_NGPIO] = {
@@ -120,30 +59,11 @@ static const char *gpiomm_names[GPIOMM_NGPIO] = {
"Port 2C2", "Port 2C3", "Port 2C4", "Port 2C5", "Port 2C6", "Port 2C7",
};
-static void gpiomm_init_dio(struct i8255 __iomem *const ppi,
- struct i8255_state *const ppi_state)
-{
- const unsigned long ngpio = 24;
- const unsigned long mask = GENMASK(ngpio - 1, 0);
- const unsigned long bits = 0;
- unsigned long i;
-
- /* Initialize all GPIO to output 0 */
- for (i = 0; i < GPIOMM_NUM_PPI; i++) {
- i8255_mode0_output(&ppi[i]);
- i8255_set_multiple(&ppi[i], &ppi_state[i], &mask, &bits, ngpio);
- }
-}
-
static int gpiomm_probe(struct device *dev, unsigned int id)
{
- struct gpiomm_gpio *gpiommgpio;
const char *const name = dev_name(dev);
- int err;
-
- gpiommgpio = devm_kzalloc(dev, sizeof(*gpiommgpio), GFP_KERNEL);
- if (!gpiommgpio)
- return -ENOMEM;
+ struct i8255_regmap_config config = {};
+ void __iomem *regs;
if (!devm_request_region(dev, base[id], GPIOMM_EXTENT, name)) {
dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
@@ -151,34 +71,20 @@ static int gpiomm_probe(struct device *dev, unsigned int id)
return -EBUSY;
}
- gpiommgpio->ppi = devm_ioport_map(dev, base[id], GPIOMM_EXTENT);
- if (!gpiommgpio->ppi)
+ regs = devm_ioport_map(dev, base[id], GPIOMM_EXTENT);
+ if (!regs)
return -ENOMEM;
- gpiommgpio->chip.label = name;
- gpiommgpio->chip.parent = dev;
- gpiommgpio->chip.owner = THIS_MODULE;
- gpiommgpio->chip.base = -1;
- gpiommgpio->chip.ngpio = GPIOMM_NGPIO;
- gpiommgpio->chip.names = gpiomm_names;
- gpiommgpio->chip.get_direction = gpiomm_gpio_get_direction;
- gpiommgpio->chip.direction_input = gpiomm_gpio_direction_input;
- gpiommgpio->chip.direction_output = gpiomm_gpio_direction_output;
- gpiommgpio->chip.get = gpiomm_gpio_get;
- gpiommgpio->chip.get_multiple = gpiomm_gpio_get_multiple;
- gpiommgpio->chip.set = gpiomm_gpio_set;
- gpiommgpio->chip.set_multiple = gpiomm_gpio_set_multiple;
-
- i8255_state_init(gpiommgpio->ppi_state, GPIOMM_NUM_PPI);
- gpiomm_init_dio(gpiommgpio->ppi, gpiommgpio->ppi_state);
-
- err = devm_gpiochip_add_data(dev, &gpiommgpio->chip, gpiommgpio);
- if (err) {
- dev_err(dev, "GPIO registering failed (%d)\n", err);
- return err;
- }
+ config.map = devm_regmap_init_mmio(dev, regs, &gpiomm_regmap_config);
+ if (IS_ERR(config.map))
+ return dev_err_probe(dev, PTR_ERR(config.map),
+ "Unable to initialize register map\n");
+
+ config.parent = dev;
+ config.num_ppi = GPIOMM_NUM_PPI;
+ config.names = gpiomm_names;
- return 0;
+ return devm_i8255_regmap_register(dev, &config);
}
static struct isa_driver gpiomm_driver = {
diff --git a/drivers/gpio/gpio-i8255.c b/drivers/gpio/gpio-i8255.c
index 9b97db418df1..64ab80fc4a1e 100644
--- a/drivers/gpio/gpio-i8255.c
+++ b/drivers/gpio/gpio-i8255.c
@@ -3,48 +3,43 @@
* Intel 8255 Programmable Peripheral Interface
* Copyright (C) 2022 William Breathitt Gray
*/
-#include <linux/bitmap.h>
+#include <linux/bits.h>
+#include <linux/device.h>
#include <linux/err.h>
#include <linux/export.h>
-#include <linux/io.h>
+#include <linux/gpio/regmap.h>
#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
+#include <linux/regmap.h>
#include "gpio-i8255.h"
+#define I8255_NGPIO 24
+#define I8255_NGPIO_PER_REG 8
#define I8255_CONTROL_PORTC_LOWER_DIRECTION BIT(0)
#define I8255_CONTROL_PORTB_DIRECTION BIT(1)
#define I8255_CONTROL_PORTC_UPPER_DIRECTION BIT(3)
#define I8255_CONTROL_PORTA_DIRECTION BIT(4)
#define I8255_CONTROL_MODE_SET BIT(7)
-#define I8255_PORTA 0
-#define I8255_PORTB 1
-#define I8255_PORTC 2
-
-static int i8255_get_port(struct i8255 __iomem *const ppi,
- const unsigned long io_port, const unsigned long mask)
-{
- const unsigned long bank = io_port / 3;
- const unsigned long ppi_port = io_port % 3;
-
- return ioread8(&ppi[bank].port[ppi_port]) & mask;
-}
-
-static u8 i8255_direction_mask(const unsigned long offset)
+#define I8255_PORTA 0x0
+#define I8255_PORTB 0x1
+#define I8255_PORTC 0x2
+#define I8255_CONTROL 0x3
+#define I8255_REG_DAT_BASE I8255_PORTA
+#define I8255_REG_DIR_IN_BASE I8255_CONTROL
+
+static int i8255_direction_mask(const unsigned int offset)
{
- const unsigned long port_offset = offset % 8;
- const unsigned long io_port = offset / 8;
- const unsigned long ppi_port = io_port % 3;
+ const unsigned int stride = offset / I8255_NGPIO_PER_REG;
+ const unsigned int line = offset % I8255_NGPIO_PER_REG;
- switch (ppi_port) {
+ switch (stride) {
case I8255_PORTA:
return I8255_CONTROL_PORTA_DIRECTION;
case I8255_PORTB:
return I8255_CONTROL_PORTB_DIRECTION;
case I8255_PORTC:
/* Port C can be configured by nibble */
- if (port_offset >= 4)
+ if (line >= 4)
return I8255_CONTROL_PORTC_UPPER_DIRECTION;
return I8255_CONTROL_PORTC_LOWER_DIRECTION;
default:
@@ -53,234 +48,93 @@ static u8 i8255_direction_mask(const unsigned long offset)
}
}
-static void i8255_set_port(struct i8255 __iomem *const ppi,
- struct i8255_state *const state,
- const unsigned long io_port,
- const unsigned long mask, const unsigned long bits)
+static int i8255_ppi_init(struct regmap *const map, const unsigned int base)
{
- const unsigned long bank = io_port / 3;
- const unsigned long ppi_port = io_port % 3;
- unsigned long flags;
- unsigned long out_state;
-
- spin_lock_irqsave(&state[bank].lock, flags);
-
- out_state = ioread8(&ppi[bank].port[ppi_port]);
- out_state = (out_state & ~mask) | (bits & mask);
- iowrite8(out_state, &ppi[bank].port[ppi_port]);
-
- spin_unlock_irqrestore(&state[bank].lock, flags);
+ int err;
+
+ /* Configure all ports to MODE 0 output mode */
+ err = regmap_write(map, base + I8255_CONTROL, I8255_CONTROL_MODE_SET);
+ if (err)
+ return err;
+
+ /* Initialize all GPIO to output 0 */
+ err = regmap_write(map, base + I8255_PORTA, 0x00);
+ if (err)
+ return err;
+ err = regmap_write(map, base + I8255_PORTB, 0x00);
+ if (err)
+ return err;
+ return regmap_write(map, base + I8255_PORTC, 0x00);
}
-/**
- * i8255_direction_input - configure signal offset as input
- * @ppi: Intel 8255 Programmable Peripheral Interface banks
- * @state: devices states of the respective PPI banks
- * @offset: signal offset to configure as input
- *
- * Configures a signal @offset as input for the respective Intel 8255
- * Programmable Peripheral Interface (@ppi) banks. The @state control_state
- * values are updated to reflect the new configuration.
- */
-void i8255_direction_input(struct i8255 __iomem *const ppi,
- struct i8255_state *const state,
- const unsigned long offset)
+static int i8255_reg_mask_xlate(struct gpio_regmap *gpio, unsigned int base,
+ unsigned int offset, unsigned int *reg,
+ unsigned int *mask)
{
- const unsigned long io_port = offset / 8;
- const unsigned long bank = io_port / 3;
- unsigned long flags;
-
- spin_lock_irqsave(&state[bank].lock, flags);
-
- state[bank].control_state |= I8255_CONTROL_MODE_SET;
- state[bank].control_state |= i8255_direction_mask(offset);
-
- iowrite8(state[bank].control_state, &ppi[bank].control);
-
- spin_unlock_irqrestore(&state[bank].lock, flags);
-}
-EXPORT_SYMBOL_NS_GPL(i8255_direction_input, I8255);
-
-/**
- * i8255_direction_output - configure signal offset as output
- * @ppi: Intel 8255 Programmable Peripheral Interface banks
- * @state: devices states of the respective PPI banks
- * @offset: signal offset to configure as output
- * @value: signal value to output
- *
- * Configures a signal @offset as output for the respective Intel 8255
- * Programmable Peripheral Interface (@ppi) banks and sets the respective signal
- * output to the desired @value. The @state control_state values are updated to
- * reflect the new configuration.
- */
-void i8255_direction_output(struct i8255 __iomem *const ppi,
- struct i8255_state *const state,
- const unsigned long offset,
- const unsigned long value)
-{
- const unsigned long io_port = offset / 8;
- const unsigned long bank = io_port / 3;
- unsigned long flags;
-
- spin_lock_irqsave(&state[bank].lock, flags);
-
- state[bank].control_state |= I8255_CONTROL_MODE_SET;
- state[bank].control_state &= ~i8255_direction_mask(offset);
-
- iowrite8(state[bank].control_state, &ppi[bank].control);
-
- spin_unlock_irqrestore(&state[bank].lock, flags);
-
- i8255_set(ppi, state, offset, value);
-}
-EXPORT_SYMBOL_NS_GPL(i8255_direction_output, I8255);
-
-/**
- * i8255_get - get signal value at signal offset
- * @ppi: Intel 8255 Programmable Peripheral Interface banks
- * @offset: offset of signal to get
- *
- * Returns the signal value (0=low, 1=high) for the signal at @offset for the
- * respective Intel 8255 Programmable Peripheral Interface (@ppi) banks.
- */
-int i8255_get(struct i8255 __iomem *const ppi, const unsigned long offset)
-{
- const unsigned long io_port = offset / 8;
- const unsigned long offset_mask = BIT(offset % 8);
-
- return !!i8255_get_port(ppi, io_port, offset_mask);
-}
-EXPORT_SYMBOL_NS_GPL(i8255_get, I8255);
-
-/**
- * i8255_get_direction - get the I/O direction for a signal offset
- * @state: devices states of the respective PPI banks
- * @offset: offset of signal to get direction
- *
- * Returns the signal direction (0=output, 1=input) for the signal at @offset.
- */
-int i8255_get_direction(const struct i8255_state *const state,
- const unsigned long offset)
-{
- const unsigned long io_port = offset / 8;
- const unsigned long bank = io_port / 3;
-
- return !!(state[bank].control_state & i8255_direction_mask(offset));
-}
-EXPORT_SYMBOL_NS_GPL(i8255_get_direction, I8255);
-
-/**
- * i8255_get_multiple - get multiple signal values at multiple signal offsets
- * @ppi: Intel 8255 Programmable Peripheral Interface banks
- * @mask: mask of signals to get
- * @bits: bitmap to store signal values
- * @ngpio: number of GPIO signals of the respective PPI banks
- *
- * Stores in @bits the values (0=low, 1=high) for the signals defined by @mask
- * for the respective Intel 8255 Programmable Peripheral Interface (@ppi) banks.
- */
-void i8255_get_multiple(struct i8255 __iomem *const ppi,
- const unsigned long *const mask,
- unsigned long *const bits, const unsigned long ngpio)
-{
- unsigned long offset;
- unsigned long port_mask;
- unsigned long io_port;
- unsigned long port_state;
-
- bitmap_zero(bits, ngpio);
-
- for_each_set_clump8(offset, port_mask, mask, ngpio) {
- io_port = offset / 8;
- port_state = i8255_get_port(ppi, io_port, port_mask);
-
- bitmap_set_value8(bits, port_state, offset);
+ const unsigned int ppi = offset / I8255_NGPIO;
+ const unsigned int ppi_offset = offset % I8255_NGPIO;
+ const unsigned int stride = ppi_offset / I8255_NGPIO_PER_REG;
+ const unsigned int line = ppi_offset % I8255_NGPIO_PER_REG;
+
+ switch (base) {
+ case I8255_REG_DAT_BASE:
+ *reg = base + stride + ppi * 4;
+ *mask = BIT(line);
+ return 0;
+ case I8255_REG_DIR_IN_BASE:
+ *reg = base + ppi * 4;
+ *mask = i8255_direction_mask(ppi_offset);
+ return 0;
+ default:
+ /* Should never reach this path */
+ return -EINVAL;
}
}
-EXPORT_SYMBOL_NS_GPL(i8255_get_multiple, I8255);
/**
- * i8255_mode0_output - configure all PPI ports to MODE 0 output mode
- * @ppi: Intel 8255 Programmable Peripheral Interface bank
+ * devm_i8255_regmap_register - Register an i8255 GPIO controller
+ * @dev: device that is registering this i8255 GPIO device
+ * @config: configuration for i8255_regmap_config
*
- * Configures all Intel 8255 Programmable Peripheral Interface (@ppi) ports to
- * MODE 0 (Basic Input/Output) output mode.
+ * Registers an Intel 8255 Programmable Peripheral Interface GPIO controller.
+ * Returns 0 on success and negative error number on failure.
*/
-void i8255_mode0_output(struct i8255 __iomem *const ppi)
+int devm_i8255_regmap_register(struct device *const dev,
+ const struct i8255_regmap_config *const config)
{
- iowrite8(I8255_CONTROL_MODE_SET, &ppi->control);
-}
-EXPORT_SYMBOL_NS_GPL(i8255_mode0_output, I8255);
+ struct gpio_regmap_config gpio_config = {0};
+ unsigned long i;
+ int err;
-/**
- * i8255_set - set signal value at signal offset
- * @ppi: Intel 8255 Programmable Peripheral Interface banks
- * @state: devices states of the respective PPI banks
- * @offset: offset of signal to set
- * @value: value of signal to set
- *
- * Assigns output @value for the signal at @offset for the respective Intel 8255
- * Programmable Peripheral Interface (@ppi) banks.
- */
-void i8255_set(struct i8255 __iomem *const ppi, struct i8255_state *const state,
- const unsigned long offset, const unsigned long value)
-{
- const unsigned long io_port = offset / 8;
- const unsigned long port_offset = offset % 8;
- const unsigned long mask = BIT(port_offset);
- const unsigned long bits = value << port_offset;
+ if (!config->parent)
+ return -EINVAL;
- i8255_set_port(ppi, state, io_port, mask, bits);
-}
-EXPORT_SYMBOL_NS_GPL(i8255_set, I8255);
+ if (!config->map)
+ return -EINVAL;
-/**
- * i8255_set_multiple - set signal values at multiple signal offsets
- * @ppi: Intel 8255 Programmable Peripheral Interface banks
- * @state: devices states of the respective PPI banks
- * @mask: mask of signals to set
- * @bits: bitmap of signal output values
- * @ngpio: number of GPIO signals of the respective PPI banks
- *
- * Assigns output values defined by @bits for the signals defined by @mask for
- * the respective Intel 8255 Programmable Peripheral Interface (@ppi) banks.
- */
-void i8255_set_multiple(struct i8255 __iomem *const ppi,
- struct i8255_state *const state,
- const unsigned long *const mask,
- const unsigned long *const bits,
- const unsigned long ngpio)
-{
- unsigned long offset;
- unsigned long port_mask;
- unsigned long io_port;
- unsigned long value;
+ if (!config->num_ppi)
+ return -EINVAL;
- for_each_set_clump8(offset, port_mask, mask, ngpio) {
- io_port = offset / 8;
- value = bitmap_get_value8(bits, offset);
- i8255_set_port(ppi, state, io_port, port_mask, value);
+ for (i = 0; i < config->num_ppi; i++) {
+ err = i8255_ppi_init(config->map, i * 4);
+ if (err)
+ return err;
}
-}
-EXPORT_SYMBOL_NS_GPL(i8255_set_multiple, I8255);
-
-/**
- * i8255_state_init - initialize i8255_state structure
- * @state: devices states of the respective PPI banks
- * @nbanks: number of Intel 8255 Programmable Peripheral Interface banks
- *
- * Initializes the @state of each Intel 8255 Programmable Peripheral Interface
- * bank for use in i8255 library functions.
- */
-void i8255_state_init(struct i8255_state *const state,
- const unsigned long nbanks)
-{
- unsigned long bank;
- for (bank = 0; bank < nbanks; bank++)
- spin_lock_init(&state[bank].lock);
+ gpio_config.parent = config->parent;
+ gpio_config.regmap = config->map;
+ gpio_config.ngpio = I8255_NGPIO * config->num_ppi;
+ gpio_config.names = config->names;
+ gpio_config.reg_dat_base = GPIO_REGMAP_ADDR(I8255_REG_DAT_BASE);
+ gpio_config.reg_set_base = GPIO_REGMAP_ADDR(I8255_REG_DAT_BASE);
+ gpio_config.reg_dir_in_base = GPIO_REGMAP_ADDR(I8255_REG_DIR_IN_BASE);
+ gpio_config.ngpio_per_reg = I8255_NGPIO_PER_REG;
+ gpio_config.irq_domain = config->domain;
+ gpio_config.reg_mask_xlate = i8255_reg_mask_xlate;
+
+ return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &gpio_config));
}
-EXPORT_SYMBOL_NS_GPL(i8255_state_init, I8255);
+EXPORT_SYMBOL_NS_GPL(devm_i8255_regmap_register, I8255);
MODULE_AUTHOR("William Breathitt Gray");
MODULE_DESCRIPTION("Intel 8255 Programmable Peripheral Interface");
diff --git a/drivers/gpio/gpio-i8255.h b/drivers/gpio/gpio-i8255.h
index d9084aae9446..9dcf639b94df 100644
--- a/drivers/gpio/gpio-i8255.h
+++ b/drivers/gpio/gpio-i8255.h
@@ -3,44 +3,32 @@
#ifndef _I8255_H_
#define _I8255_H_
-#include <linux/spinlock.h>
-#include <linux/types.h>
+struct device;
+struct irq_domain;
+struct regmap;
-/**
- * struct i8255 - Intel 8255 register structure
- * @port: Port A, B, and C
- * @control: Control register
- */
-struct i8255 {
- u8 port[3];
- u8 control;
-};
+#define i8255_volatile_regmap_range(_base) regmap_reg_range(_base, _base + 0x2)
/**
- * struct i8255_state - Intel 8255 state structure
- * @lock: synchronization lock for accessing device state
- * @control_state: Control register state
+ * struct i8255_regmap_config - Configuration for the register map of an i8255
+ * @parent: parent device
+ * @map: regmap for the i8255
+ * @num_ppi: number of i8255 Programmable Peripheral Interface
+ * @names: (optional) array of names for gpios
+ * @domain: (optional) IRQ domain if the controller is interrupt-capable
+ *
+ * Note: The regmap is expected to have cache enabled and i8255 control
+ * registers not marked as volatile.
*/
-struct i8255_state {
- spinlock_t lock;
- u8 control_state;
+struct i8255_regmap_config {
+ struct device *parent;
+ struct regmap *map;
+ int num_ppi;
+ const char *const *names;
+ struct irq_domain *domain;
};
-void i8255_direction_input(struct i8255 __iomem *ppi, struct i8255_state *state,
- unsigned long offset);
-void i8255_direction_output(struct i8255 __iomem *ppi,
- struct i8255_state *state, unsigned long offset,
- unsigned long value);
-int i8255_get(struct i8255 __iomem *ppi, unsigned long offset);
-int i8255_get_direction(const struct i8255_state *state, unsigned long offset);
-void i8255_get_multiple(struct i8255 __iomem *ppi, const unsigned long *mask,
- unsigned long *bits, unsigned long ngpio);
-void i8255_mode0_output(struct i8255 __iomem *const ppi);
-void i8255_set(struct i8255 __iomem *ppi, struct i8255_state *state,
- unsigned long offset, unsigned long value);
-void i8255_set_multiple(struct i8255 __iomem *ppi, struct i8255_state *state,
- const unsigned long *mask, const unsigned long *bits,
- unsigned long ngpio);
-void i8255_state_init(struct i8255_state *const state, unsigned long nbanks);
+int devm_i8255_regmap_register(struct device *dev,
+ const struct i8255_regmap_config *config);
#endif /* _I8255_H_ */
diff --git a/drivers/gpio/gpio-msc313.c b/drivers/gpio/gpio-msc313.c
index 52d7b8d99170..b0773e5652fa 100644
--- a/drivers/gpio/gpio-msc313.c
+++ b/drivers/gpio/gpio-msc313.c
@@ -655,11 +655,6 @@ static int msc313_gpio_probe(struct platform_device *pdev)
return devm_gpiochip_add_data(dev, gpiochip, gpio);
}
-static int msc313_gpio_remove(struct platform_device *pdev)
-{
- return 0;
-}
-
static const struct of_device_id msc313_gpio_of_match[] = {
#ifdef CONFIG_MACH_INFINITY
{
@@ -710,6 +705,5 @@ static struct platform_driver msc313_gpio_driver = {
.pm = &msc313_gpio_ops,
},
.probe = msc313_gpio_probe,
- .remove = msc313_gpio_remove,
};
builtin_platform_driver(msc313_gpio_driver);
diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
index 91a4232ee58c..a68f682aec01 100644
--- a/drivers/gpio/gpio-mvebu.c
+++ b/drivers/gpio/gpio-mvebu.c
@@ -1002,7 +1002,7 @@ static int mvebu_gpio_suspend(struct platform_device *pdev, pm_message_t state)
BUG();
}
- if (IS_ENABLED(CONFIG_PWM))
+ if (IS_REACHABLE(CONFIG_PWM))
mvebu_pwm_suspend(mvchip);
return 0;
@@ -1054,7 +1054,7 @@ static int mvebu_gpio_resume(struct platform_device *pdev)
BUG();
}
- if (IS_ENABLED(CONFIG_PWM))
+ if (IS_REACHABLE(CONFIG_PWM))
mvebu_pwm_resume(mvchip);
return 0;
@@ -1228,7 +1228,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
devm_gpiochip_add_data(&pdev->dev, &mvchip->chip, mvchip);
/* Some MVEBU SoCs have simple PWM support for GPIO lines */
- if (IS_ENABLED(CONFIG_PWM)) {
+ if (IS_REACHABLE(CONFIG_PWM)) {
err = mvebu_pwm_probe(pdev, mvchip, id);
if (err)
return err;
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index 80ddc43fd875..f5f3d4b22452 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -1020,7 +1020,7 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc,
if (!label)
return -ENOMEM;
bank->chip.label = label;
- bank->chip.base = gpio;
+ bank->chip.base = -1;
}
bank->chip.ngpio = bank->width;
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index 5299e5bb76d6..1286b22ef23a 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -306,34 +306,31 @@ static bool pca953x_check_register(struct pca953x_chip *chip, unsigned int reg,
static bool pcal6534_check_register(struct pca953x_chip *chip, unsigned int reg,
u32 checkbank)
{
+ int bank_shift;
int bank;
int offset;
- if (reg >= 0x30) {
- /*
- * Reserved block between 14h and 2Fh does not align on
- * expected bank boundaries like other devices.
- */
- int temp = reg - 0x30;
-
- bank = temp / NBANK(chip);
- offset = temp - (bank * NBANK(chip));
- bank += 8;
- } else if (reg >= 0x54) {
+ if (reg >= 0x54) {
/*
* Handle lack of reserved registers after output port
* configuration register to form a bank.
*/
- int temp = reg - 0x54;
-
- bank = temp / NBANK(chip);
- offset = temp - (bank * NBANK(chip));
- bank += 16;
+ reg -= 0x54;
+ bank_shift = 16;
+ } else if (reg >= 0x30) {
+ /*
+ * Reserved block between 14h and 2Fh does not align on
+ * expected bank boundaries like other devices.
+ */
+ reg -= 0x30;
+ bank_shift = 8;
} else {
- bank = reg / NBANK(chip);
- offset = reg - (bank * NBANK(chip));
+ bank_shift = 0;
}
+ bank = bank_shift + reg / NBANK(chip);
+ offset = reg % NBANK(chip);
+
/* Register is not in the matching bank. */
if (!(BIT(bank) & checkbank))
return false;
@@ -464,7 +461,6 @@ static u8 pcal6534_recalc_addr(struct pca953x_chip *chip, int reg, int off)
case PCAL953X_PULL_SEL:
case PCAL953X_INT_MASK:
case PCAL953X_INT_STAT:
- case PCAL953X_OUT_CONF:
pinctrl = ((reg & PCAL_PINCTRL_MASK) >> 1) + 0x20;
break;
case PCAL6524_INT_EDGE:
diff --git a/drivers/gpio/gpio-pca9570.c b/drivers/gpio/gpio-pca9570.c
index 6c07a8811a7a..6a5a8e593ed5 100644
--- a/drivers/gpio/gpio-pca9570.c
+++ b/drivers/gpio/gpio-pca9570.c
@@ -18,11 +18,11 @@
#define SLG7XL45106_GPO_REG 0xDB
/**
- * struct pca9570_platform_data - GPIO platformdata
+ * struct pca9570_chip_data - GPIO platformdata
* @ngpio: no of gpios
* @command: Command to be sent
*/
-struct pca9570_platform_data {
+struct pca9570_chip_data {
u16 ngpio;
u32 command;
};
@@ -36,7 +36,7 @@ struct pca9570_platform_data {
*/
struct pca9570 {
struct gpio_chip chip;
- const struct pca9570_platform_data *p_data;
+ const struct pca9570_chip_data *chip_data;
struct mutex lock;
u8 out;
};
@@ -46,8 +46,8 @@ static int pca9570_read(struct pca9570 *gpio, u8 *value)
struct i2c_client *client = to_i2c_client(gpio->chip.parent);
int ret;
- if (gpio->p_data->command != 0)
- ret = i2c_smbus_read_byte_data(client, gpio->p_data->command);
+ if (gpio->chip_data->command != 0)
+ ret = i2c_smbus_read_byte_data(client, gpio->chip_data->command);
else
ret = i2c_smbus_read_byte(client);
@@ -62,8 +62,8 @@ static int pca9570_write(struct pca9570 *gpio, u8 value)
{
struct i2c_client *client = to_i2c_client(gpio->chip.parent);
- if (gpio->p_data->command != 0)
- return i2c_smbus_write_byte_data(client, gpio->p_data->command, value);
+ if (gpio->chip_data->command != 0)
+ return i2c_smbus_write_byte_data(client, gpio->chip_data->command, value);
return i2c_smbus_write_byte(client, value);
}
@@ -127,8 +127,8 @@ static int pca9570_probe(struct i2c_client *client)
gpio->chip.get = pca9570_get;
gpio->chip.set = pca9570_set;
gpio->chip.base = -1;
- gpio->p_data = device_get_match_data(&client->dev);
- gpio->chip.ngpio = gpio->p_data->ngpio;
+ gpio->chip_data = device_get_match_data(&client->dev);
+ gpio->chip.ngpio = gpio->chip_data->ngpio;
gpio->chip.can_sleep = true;
mutex_init(&gpio->lock);
@@ -141,15 +141,15 @@ static int pca9570_probe(struct i2c_client *client)
return devm_gpiochip_add_data(&client->dev, &gpio->chip, gpio);
}
-static const struct pca9570_platform_data pca9570_gpio = {
+static const struct pca9570_chip_data pca9570_gpio = {
.ngpio = 4,
};
-static const struct pca9570_platform_data pca9571_gpio = {
+static const struct pca9570_chip_data pca9571_gpio = {
.ngpio = 8,
};
-static const struct pca9570_platform_data slg7xl45106_gpio = {
+static const struct pca9570_chip_data slg7xl45106_gpio = {
.ngpio = 8,
.command = SLG7XL45106_GPO_REG,
};
diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c
index cec2f2c78255..3de1d3ad7472 100644
--- a/drivers/gpio/gpio-pcf857x.c
+++ b/drivers/gpio/gpio-pcf857x.c
@@ -7,18 +7,16 @@
#include <linux/gpio/driver.h>
#include <linux/i2c.h>
-#include <linux/platform_data/pcf857x.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
+#include <linux/property.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
-
static const struct i2c_device_id pcf857x_id[] = {
{ "pcf8574", 8 },
{ "pcf8574a", 8 },
@@ -37,7 +35,6 @@ static const struct i2c_device_id pcf857x_id[] = {
};
MODULE_DEVICE_TABLE(i2c, pcf857x_id);
-#ifdef CONFIG_OF
static const struct of_device_id pcf857x_of_table[] = {
{ .compatible = "nxp,pcf8574" },
{ .compatible = "nxp,pcf8574a" },
@@ -55,7 +52,6 @@ static const struct of_device_id pcf857x_of_table[] = {
{ }
};
MODULE_DEVICE_TABLE(of, pcf857x_of_table);
-#endif
/*
* The pcf857x, pca857x, and pca967x chips only expose one read and one
@@ -73,11 +69,11 @@ struct pcf857x {
struct gpio_chip chip;
struct i2c_client *client;
struct mutex lock; /* protect 'out' */
- unsigned out; /* software latch */
- unsigned status; /* current status */
- unsigned irq_enabled; /* enabled irqs */
+ unsigned int out; /* software latch */
+ unsigned int status; /* current status */
+ unsigned int irq_enabled; /* enabled irqs */
- int (*write)(struct i2c_client *client, unsigned data);
+ int (*write)(struct i2c_client *client, unsigned int data);
int (*read)(struct i2c_client *client);
};
@@ -85,19 +81,19 @@ struct pcf857x {
/* Talk to 8-bit I/O expander */
-static int i2c_write_le8(struct i2c_client *client, unsigned data)
+static int i2c_write_le8(struct i2c_client *client, unsigned int data)
{
return i2c_smbus_write_byte(client, data);
}
static int i2c_read_le8(struct i2c_client *client)
{
- return (int)i2c_smbus_read_byte(client);
+ return i2c_smbus_read_byte(client);
}
/* Talk to 16-bit I/O expander */
-static int i2c_write_le16(struct i2c_client *client, unsigned word)
+static int i2c_write_le16(struct i2c_client *client, unsigned int word)
{
u8 buf[2] = { word & 0xff, word >> 8, };
int status;
@@ -119,10 +115,10 @@ static int i2c_read_le16(struct i2c_client *client)
/*-------------------------------------------------------------------------*/
-static int pcf857x_input(struct gpio_chip *chip, unsigned offset)
+static int pcf857x_input(struct gpio_chip *chip, unsigned int offset)
{
- struct pcf857x *gpio = gpiochip_get_data(chip);
- int status;
+ struct pcf857x *gpio = gpiochip_get_data(chip);
+ int status;
mutex_lock(&gpio->lock);
gpio->out |= (1 << offset);
@@ -132,20 +128,35 @@ static int pcf857x_input(struct gpio_chip *chip, unsigned offset)
return status;
}
-static int pcf857x_get(struct gpio_chip *chip, unsigned offset)
+static int pcf857x_get(struct gpio_chip *chip, unsigned int offset)
{
- struct pcf857x *gpio = gpiochip_get_data(chip);
- int value;
+ struct pcf857x *gpio = gpiochip_get_data(chip);
+ int value;
value = gpio->read(gpio->client);
return (value < 0) ? value : !!(value & (1 << offset));
}
-static int pcf857x_output(struct gpio_chip *chip, unsigned offset, int value)
+static int pcf857x_get_multiple(struct gpio_chip *chip, unsigned long *mask,
+ unsigned long *bits)
{
- struct pcf857x *gpio = gpiochip_get_data(chip);
- unsigned bit = 1 << offset;
- int status;
+ struct pcf857x *gpio = gpiochip_get_data(chip);
+ int value = gpio->read(gpio->client);
+
+ if (value < 0)
+ return value;
+
+ *bits &= ~*mask;
+ *bits |= value & *mask;
+
+ return 0;
+}
+
+static int pcf857x_output(struct gpio_chip *chip, unsigned int offset, int value)
+{
+ struct pcf857x *gpio = gpiochip_get_data(chip);
+ unsigned int bit = 1 << offset;
+ int status;
mutex_lock(&gpio->lock);
if (value)
@@ -158,16 +169,28 @@ static int pcf857x_output(struct gpio_chip *chip, unsigned offset, int value)
return status;
}
-static void pcf857x_set(struct gpio_chip *chip, unsigned offset, int value)
+static void pcf857x_set(struct gpio_chip *chip, unsigned int offset, int value)
{
pcf857x_output(chip, offset, value);
}
+static void pcf857x_set_multiple(struct gpio_chip *chip, unsigned long *mask,
+ unsigned long *bits)
+{
+ struct pcf857x *gpio = gpiochip_get_data(chip);
+
+ mutex_lock(&gpio->lock);
+ gpio->out &= ~*mask;
+ gpio->out |= *bits & *mask;
+ gpio->write(gpio->client, gpio->out);
+ mutex_unlock(&gpio->lock);
+}
+
/*-------------------------------------------------------------------------*/
static irqreturn_t pcf857x_irq(int irq, void *data)
{
- struct pcf857x *gpio = data;
+ struct pcf857x *gpio = data;
unsigned long change, i, status;
status = gpio->read(gpio->client);
@@ -250,18 +273,11 @@ static const struct irq_chip pcf857x_irq_chip = {
static int pcf857x_probe(struct i2c_client *client)
{
const struct i2c_device_id *id = i2c_client_get_device_id(client);
- struct pcf857x_platform_data *pdata = dev_get_platdata(&client->dev);
- struct device_node *np = client->dev.of_node;
- struct pcf857x *gpio;
- unsigned int n_latch = 0;
- int status;
-
- if (IS_ENABLED(CONFIG_OF) && np)
- of_property_read_u32(np, "lines-initial-states", &n_latch);
- else if (pdata)
- n_latch = pdata->n_latch;
- else
- dev_dbg(&client->dev, "no platform data\n");
+ struct pcf857x *gpio;
+ unsigned int n_latch = 0;
+ int status;
+
+ device_property_read_u32(&client->dev, "lines-initial-states", &n_latch);
/* Allocate, initialize, and register this gpio_chip. */
gpio = devm_kzalloc(&client->dev, sizeof(*gpio), GFP_KERNEL);
@@ -270,12 +286,14 @@ static int pcf857x_probe(struct i2c_client *client)
mutex_init(&gpio->lock);
- gpio->chip.base = pdata ? pdata->gpio_base : -1;
+ gpio->chip.base = -1;
gpio->chip.can_sleep = true;
gpio->chip.parent = &client->dev;
gpio->chip.owner = THIS_MODULE;
gpio->chip.get = pcf857x_get;
+ gpio->chip.get_multiple = pcf857x_get_multiple;
gpio->chip.set = pcf857x_set;
+ gpio->chip.set_multiple = pcf857x_set_multiple;
gpio->chip.direction_input = pcf857x_input;
gpio->chip.direction_output = pcf857x_output;
gpio->chip.ngpio = id->driver_data;
@@ -377,17 +395,6 @@ static int pcf857x_probe(struct i2c_client *client)
if (status < 0)
goto fail;
- /* Let platform code set up the GPIOs and their users.
- * Now is the first time anyone could use them.
- */
- if (pdata && pdata->setup) {
- status = pdata->setup(client,
- gpio->chip.base, gpio->chip.ngpio,
- pdata->context);
- if (status < 0)
- dev_warn(&client->dev, "setup --> %d\n", status);
- }
-
dev_info(&client->dev, "probed\n");
return 0;
@@ -399,16 +406,6 @@ fail:
return status;
}
-static void pcf857x_remove(struct i2c_client *client)
-{
- struct pcf857x_platform_data *pdata = dev_get_platdata(&client->dev);
- struct pcf857x *gpio = i2c_get_clientdata(client);
-
- if (pdata && pdata->teardown)
- pdata->teardown(client, gpio->chip.base, gpio->chip.ngpio,
- pdata->context);
-}
-
static void pcf857x_shutdown(struct i2c_client *client)
{
struct pcf857x *gpio = i2c_get_clientdata(client);
@@ -420,10 +417,9 @@ static void pcf857x_shutdown(struct i2c_client *client)
static struct i2c_driver pcf857x_driver = {
.driver = {
.name = "pcf857x",
- .of_match_table = of_match_ptr(pcf857x_of_table),
+ .of_match_table = pcf857x_of_table,
},
.probe_new = pcf857x_probe,
- .remove = pcf857x_remove,
.shutdown = pcf857x_shutdown,
.id_table = pcf857x_id,
};
diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c
index 6383136cbe59..fca17d478984 100644
--- a/drivers/gpio/gpio-regmap.c
+++ b/drivers/gpio/gpio-regmap.c
@@ -111,6 +111,11 @@ static int gpio_regmap_get_direction(struct gpio_chip *chip,
unsigned int base, val, reg, mask;
int invert, ret;
+ if (gpio->reg_dat_base && !gpio->reg_set_base)
+ return GPIO_LINE_DIRECTION_IN;
+ if (gpio->reg_set_base && !gpio->reg_dat_base)
+ return GPIO_LINE_DIRECTION_OUT;
+
if (gpio->reg_dir_out_base) {
base = gpio_regmap_addr(gpio->reg_dir_out_base);
invert = 0;
@@ -249,15 +254,7 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config
chip->ngpio = config->ngpio;
chip->names = config->names;
chip->label = config->label ?: dev_name(config->parent);
-
- /*
- * If our regmap is fast_io we should probably set can_sleep to false.
- * Right now, the regmap doesn't save this property, nor is there any
- * access function for it.
- * The only regmap type which uses fast_io is regmap-mmio. For now,
- * assume a safe default of true here.
- */
- chip->can_sleep = true;
+ chip->can_sleep = regmap_might_sleep(config->regmap);
chip->get = gpio_regmap_get;
if (gpio->reg_set_base && gpio->reg_clr_base)
@@ -265,8 +262,8 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config
else if (gpio->reg_set_base)
chip->set = gpio_regmap_set;
+ chip->get_direction = gpio_regmap_get_direction;
if (gpio->reg_dir_in_base || gpio->reg_dir_out_base) {
- chip->get_direction = gpio_regmap_get_direction;
chip->direction_input = gpio_regmap_direction_input;
chip->direction_output = gpio_regmap_direction_output;
}
diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c
index 200e43a6f4b4..e5de15a2ab9a 100644
--- a/drivers/gpio/gpio-rockchip.c
+++ b/drivers/gpio/gpio-rockchip.c
@@ -299,7 +299,7 @@ static int rockchip_gpio_set_config(struct gpio_chip *gc, unsigned int offset,
}
/*
- * gpiolib gpio_to_irq callback function. Creates a mapping between a GPIO pin
+ * gpiod_to_irq() callback function. Creates a mapping between a GPIO pin
* and a virtual IRQ, if not already present.
*/
static int rockchip_gpio_to_irq(struct gpio_chip *gc, unsigned int offset)
diff --git a/drivers/gpio/gpio-sim.c b/drivers/gpio/gpio-sim.c
index 9e3893b19e4f..e5dfd636c63c 100644
--- a/drivers/gpio/gpio-sim.c
+++ b/drivers/gpio/gpio-sim.c
@@ -377,8 +377,8 @@ static int gpio_sim_add_bank(struct fwnode_handle *swnode, struct device *dev)
ret = fwnode_property_read_string(swnode, "gpio-sim,label", &label);
if (ret) {
- label = devm_kasprintf(dev, GFP_KERNEL, "%s-%s",
- dev_name(dev), fwnode_get_name(swnode));
+ label = devm_kasprintf(dev, GFP_KERNEL, "%s-%pfwP",
+ dev_name(dev), swnode);
if (!label)
return -ENOMEM;
}
@@ -784,10 +784,9 @@ static int gpio_sim_add_hogs(struct gpio_sim_device *dev)
GFP_KERNEL);
else
hog->chip_label = kasprintf(GFP_KERNEL,
- "gpio-sim.%u-%s",
+ "gpio-sim.%u-%pfwP",
dev->id,
- fwnode_get_name(
- bank->swnode));
+ bank->swnode);
if (!hog->chip_label) {
gpio_sim_remove_hogs(dev);
return -ENOMEM;
diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c
index fdc5bdcd5638..14c872b6ad05 100644
--- a/drivers/gpio/gpio-tegra186.c
+++ b/drivers/gpio/gpio-tegra186.c
@@ -670,13 +670,14 @@ static unsigned int tegra186_gpio_child_offset_to_irq(struct gpio_chip *chip,
static const struct of_device_id tegra186_pmc_of_match[] = {
{ .compatible = "nvidia,tegra186-pmc" },
{ .compatible = "nvidia,tegra194-pmc" },
+ { .compatible = "nvidia,tegra234-pmc" },
{ /* sentinel */ }
};
static void tegra186_gpio_init_route_mapping(struct tegra_gpio *gpio)
{
struct device *dev = gpio->gpio.parent;
- unsigned int i, j;
+ unsigned int i;
u32 value;
for (i = 0; i < gpio->soc->num_ports; i++) {
@@ -698,27 +699,23 @@ static void tegra186_gpio_init_route_mapping(struct tegra_gpio *gpio)
* On Tegra194 and later, each pin can be routed to one or more
* interrupts.
*/
- for (j = 0; j < gpio->num_irqs_per_bank; j++) {
- dev_dbg(dev, "programming default interrupt routing for port %s\n",
- port->name);
-
- offset = TEGRA186_GPIO_INT_ROUTE_MAPPING(p, j);
-
- /*
- * By default we only want to route GPIO pins to IRQ 0. This works
- * only under the assumption that we're running as the host kernel
- * and hence all GPIO pins are owned by Linux.
- *
- * For cases where Linux is the guest OS, the hypervisor will have
- * to configure the interrupt routing and pass only the valid
- * interrupts via device tree.
- */
- if (j == 0) {
- value = readl(base + offset);
- value = BIT(port->pins) - 1;
- writel(value, base + offset);
- }
- }
+ dev_dbg(dev, "programming default interrupt routing for port %s\n",
+ port->name);
+
+ offset = TEGRA186_GPIO_INT_ROUTE_MAPPING(p, 0);
+
+ /*
+ * By default we only want to route GPIO pins to IRQ 0. This works
+ * only under the assumption that we're running as the host kernel
+ * and hence all GPIO pins are owned by Linux.
+ *
+ * For cases where Linux is the guest OS, the hypervisor will have
+ * to configure the interrupt routing and pass only the valid
+ * interrupts via device tree.
+ */
+ value = readl(base + offset);
+ value = BIT(port->pins) - 1;
+ writel(value, base + offset);
}
}
}
diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c
index 9033db00c360..d3f3a69d4907 100644
--- a/drivers/gpio/gpio-vf610.c
+++ b/drivers/gpio/gpio-vf610.c
@@ -317,7 +317,7 @@ static int vf610_gpio_probe(struct platform_device *pdev)
gc = &port->gc;
gc->parent = dev;
- gc->label = "vf610-gpio";
+ gc->label = dev_name(dev);
gc->ngpio = VF610_GPIO_PER_PORT;
gc->base = of_alias_get_id(np, "gpio") * VF610_GPIO_PER_PORT;
diff --git a/drivers/gpio/gpio-wcd934x.c b/drivers/gpio/gpio-wcd934x.c
index 97e6caedf1f3..817750e4e033 100644
--- a/drivers/gpio/gpio-wcd934x.c
+++ b/drivers/gpio/gpio-wcd934x.c
@@ -98,7 +98,6 @@ static int wcd_gpio_probe(struct platform_device *pdev)
chip->base = -1;
chip->ngpio = WCD934X_NPINS;
chip->label = dev_name(dev);
- chip->of_gpio_n_cells = 2;
chip->can_sleep = false;
return devm_gpiochip_add_data(dev, chip, data);
diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c
index 2fc6b6ff7f16..e248809965ca 100644
--- a/drivers/gpio/gpio-xilinx.c
+++ b/drivers/gpio/gpio-xilinx.c
@@ -558,7 +558,6 @@ static int xgpio_probe(struct platform_device *pdev)
int status = 0;
struct device_node *np = pdev->dev.of_node;
u32 is_dual = 0;
- u32 cells = 2;
u32 width[2];
u32 state[2];
u32 dir[2];
@@ -591,15 +590,6 @@ static int xgpio_probe(struct platform_device *pdev)
bitmap_from_arr32(chip->dir, dir, 64);
- /* Update cells with gpio-cells value */
- if (of_property_read_u32(np, "#gpio-cells", &cells))
- dev_dbg(&pdev->dev, "Missing gpio-cells property\n");
-
- if (cells != 2) {
- dev_err(&pdev->dev, "#gpio-cells mismatch\n");
- return -EINVAL;
- }
-
/*
* Check device node and parent device node for device width
* and assume default width of 32
@@ -630,7 +620,6 @@ static int xgpio_probe(struct platform_device *pdev)
chip->gc.parent = &pdev->dev;
chip->gc.direction_input = xgpio_dir_in;
chip->gc.direction_output = xgpio_dir_out;
- chip->gc.of_gpio_n_cells = cells;
chip->gc.get = xgpio_get;
chip->gc.set = xgpio_set;
chip->gc.request = xgpio_request;
diff --git a/drivers/gpio/gpio-zevio.c b/drivers/gpio/gpio-zevio.c
index ce9d1282165c..f0f571b323f2 100644
--- a/drivers/gpio/gpio-zevio.c
+++ b/drivers/gpio/gpio-zevio.c
@@ -5,13 +5,15 @@
* Author: Fabian Vogt <fabian@ritter-vogt.de>
*/
-#include <linux/spinlock.h>
+#include <linux/bitops.h>
#include <linux/errno.h>
#include <linux/init.h>
-#include <linux/bitops.h>
#include <linux/io.h>
-#include <linux/of_device.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <linux/spinlock.h>
+
#include <linux/gpio/driver.h>
/*
@@ -162,7 +164,6 @@ static const struct gpio_chip zevio_gpio_chip = {
.base = 0,
.owner = THIS_MODULE,
.ngpio = 32,
- .of_gpio_n_cells = 2,
};
/* Initialization */
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index 34ff048e70d0..d8a421ce26a8 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -1388,16 +1388,6 @@ void acpi_gpiochip_remove(struct gpio_chip *chip)
kfree(acpi_gpio);
}
-void acpi_gpio_dev_init(struct gpio_chip *gc, struct gpio_device *gdev)
-{
- /* Set default fwnode to parent's one if present */
- if (gc->parent)
- ACPI_COMPANION_SET(&gdev->dev, ACPI_COMPANION(gc->parent));
-
- if (gc->fwnode)
- device_set_node(&gdev->dev, gc->fwnode);
-}
-
static int acpi_gpio_package_count(const union acpi_object *obj)
{
const union acpi_object *element = obj->package.elements;
diff --git a/drivers/gpio/gpiolib-acpi.h b/drivers/gpio/gpiolib-acpi.h
index 5a08693b8fb1..90fd6b04f24d 100644
--- a/drivers/gpio/gpiolib-acpi.h
+++ b/drivers/gpio/gpiolib-acpi.h
@@ -25,8 +25,6 @@ struct gpio_device;
void acpi_gpiochip_add(struct gpio_chip *chip);
void acpi_gpiochip_remove(struct gpio_chip *chip);
-void acpi_gpio_dev_init(struct gpio_chip *gc, struct gpio_device *gdev);
-
void acpi_gpiochip_request_interrupts(struct gpio_chip *chip);
void acpi_gpiochip_free_interrupts(struct gpio_chip *chip);
@@ -41,8 +39,6 @@ int acpi_gpio_count(struct device *dev, const char *con_id);
static inline void acpi_gpiochip_add(struct gpio_chip *chip) { }
static inline void acpi_gpiochip_remove(struct gpio_chip *chip) { }
-static inline void acpi_gpio_dev_init(struct gpio_chip *gc, struct gpio_device *gdev) { }
-
static inline void
acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { }
diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c
index e878e3f22b0e..0a33971c964c 100644
--- a/drivers/gpio/gpiolib-cdev.c
+++ b/drivers/gpio/gpiolib-cdev.c
@@ -321,7 +321,7 @@ static void linehandle_free(struct linehandle_state *lh)
if (lh->descs[i])
gpiod_free(lh->descs[i]);
kfree(lh->label);
- put_device(&lh->gdev->dev);
+ gpio_device_put(lh->gdev);
kfree(lh);
}
@@ -363,8 +363,7 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
lh = kzalloc(sizeof(*lh), GFP_KERNEL);
if (!lh)
return -ENOMEM;
- lh->gdev = gdev;
- get_device(&gdev->dev);
+ lh->gdev = gpio_device_get(gdev);
if (handlereq.consumer_label[0] != '\0') {
/* label is only initialized if consumer_label is set */
@@ -1576,7 +1575,7 @@ static void linereq_free(struct linereq *lr)
}
kfifo_free(&lr->events);
kfree(lr->label);
- put_device(&lr->gdev->dev);
+ gpio_device_put(lr->gdev);
kfree(lr);
}
@@ -1646,8 +1645,7 @@ static int linereq_create(struct gpio_device *gdev, void __user *ip)
if (!lr)
return -ENOMEM;
- lr->gdev = gdev;
- get_device(&gdev->dev);
+ lr->gdev = gpio_device_get(gdev);
for (i = 0; i < ulr.num_lines; i++) {
lr->lines[i].req = lr;
@@ -1916,7 +1914,7 @@ static void lineevent_free(struct lineevent_state *le)
if (le->desc)
gpiod_free(le->desc);
kfree(le->label);
- put_device(&le->gdev->dev);
+ gpio_device_put(le->gdev);
kfree(le);
}
@@ -2094,8 +2092,7 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
le = kzalloc(sizeof(*le), GFP_KERNEL);
if (!le)
return -ENOMEM;
- le->gdev = gdev;
- get_device(&gdev->dev);
+ le->gdev = gpio_device_get(gdev);
if (eventreq.consumer_label[0] != '\0') {
/* label is only initialized if consumer_label is set */
@@ -2671,7 +2668,7 @@ static int gpio_chrdev_open(struct inode *inode, struct file *file)
init_waitqueue_head(&cdev->wait);
INIT_KFIFO(cdev->events);
- cdev->gdev = gdev;
+ cdev->gdev = gpio_device_get(gdev);
cdev->lineinfo_changed_nb.notifier_call = lineinfo_changed_notify;
ret = blocking_notifier_chain_register(&gdev->notifier,
@@ -2679,7 +2676,6 @@ static int gpio_chrdev_open(struct inode *inode, struct file *file)
if (ret)
goto out_free_bitmap;
- get_device(&gdev->dev);
file->private_data = cdev;
ret = nonseekable_open(inode, file);
@@ -2694,6 +2690,7 @@ out_unregister_notifier:
blocking_notifier_chain_unregister(&gdev->notifier,
&cdev->lineinfo_changed_nb);
out_free_bitmap:
+ gpio_device_put(gdev);
bitmap_free(cdev->watched_lines);
out_free_cdev:
kfree(cdev);
@@ -2716,7 +2713,7 @@ static int gpio_chrdev_release(struct inode *inode, struct file *file)
bitmap_free(cdev->watched_lines);
blocking_notifier_chain_unregister(&gdev->notifier,
&cdev->lineinfo_changed_nb);
- put_device(&gdev->dev);
+ gpio_device_put(gdev);
kfree(cdev);
return 0;
diff --git a/drivers/gpio/gpiolib-devres.c b/drivers/gpio/gpiolib-devres.c
index 16a696249229..fe9ce6b19f15 100644
--- a/drivers/gpio/gpiolib-devres.c
+++ b/drivers/gpio/gpiolib-devres.c
@@ -130,61 +130,6 @@ struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev,
EXPORT_SYMBOL_GPL(devm_gpiod_get_index);
/**
- * devm_gpiod_get_from_of_node() - obtain a GPIO from an OF node
- * @dev: device for lifecycle management
- * @node: handle of the OF node
- * @propname: name of the DT property representing the GPIO
- * @index: index of the GPIO to obtain for the consumer
- * @dflags: GPIO initialization flags
- * @label: label to attach to the requested GPIO
- *
- * Returns:
- * On successful request the GPIO pin is configured in accordance with
- * provided @dflags.
- *
- * In case of error an ERR_PTR() is returned.
- */
-struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev,
- const struct device_node *node,
- const char *propname, int index,
- enum gpiod_flags dflags,
- const char *label)
-{
- struct gpio_desc **dr;
- struct gpio_desc *desc;
-
- desc = gpiod_get_from_of_node(node, propname, index, dflags, label);
- if (IS_ERR(desc))
- return desc;
-
- /*
- * For non-exclusive GPIO descriptors, check if this descriptor is
- * already under resource management by this device.
- */
- if (dflags & GPIOD_FLAGS_BIT_NONEXCLUSIVE) {
- struct devres *dres;
-
- dres = devres_find(dev, devm_gpiod_release,
- devm_gpiod_match, &desc);
- if (dres)
- return desc;
- }
-
- dr = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc *),
- GFP_KERNEL);
- if (!dr) {
- gpiod_put(desc);
- return ERR_PTR(-ENOMEM);
- }
-
- *dr = desc;
- devres_add(dev, dr);
-
- return desc;
-}
-EXPORT_SYMBOL_GPL(devm_gpiod_get_from_of_node);
-
-/**
* devm_fwnode_gpiod_get_index - get a GPIO descriptor from a given node
* @dev: GPIO consumer
* @fwnode: firmware node containing GPIO reference
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index 4fff7258ee41..266352b1a966 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -23,6 +23,47 @@
#include "gpiolib.h"
#include "gpiolib-of.h"
+/*
+ * This is Linux-specific flags. By default controllers' and Linux' mapping
+ * match, but GPIO controllers are free to translate their own flags to
+ * Linux-specific in their .xlate callback. Though, 1:1 mapping is recommended.
+ */
+enum of_gpio_flags {
+ OF_GPIO_ACTIVE_LOW = 0x1,
+ OF_GPIO_SINGLE_ENDED = 0x2,
+ OF_GPIO_OPEN_DRAIN = 0x4,
+ OF_GPIO_TRANSITORY = 0x8,
+ OF_GPIO_PULL_UP = 0x10,
+ OF_GPIO_PULL_DOWN = 0x20,
+ OF_GPIO_PULL_DISABLE = 0x40,
+};
+
+/**
+ * of_gpio_named_count() - Count GPIOs for a device
+ * @np: device node to count GPIOs for
+ * @propname: property name containing gpio specifier(s)
+ *
+ * The function returns the count of GPIOs specified for a node.
+ * Note that the empty GPIO specifiers count too. Returns either
+ * Number of gpios defined in property,
+ * -EINVAL for an incorrectly formed gpios property, or
+ * -ENOENT for a missing gpios property
+ *
+ * Example:
+ * gpios = <0
+ * &gpio1 1 2
+ * 0
+ * &gpio2 3 4>;
+ *
+ * The above example defines four GPIOs, two of which are not specified.
+ * This function will return '4'
+ */
+static int of_gpio_named_count(const struct device_node *np,
+ const char *propname)
+{
+ return of_count_phandle_with_args(np, propname, "#gpio-cells");
+}
+
/**
* of_gpio_spi_cs_get_count() - special GPIO counting for SPI
* @dev: Consuming device
@@ -50,12 +91,6 @@ static int of_gpio_spi_cs_get_count(struct device *dev, const char *con_id)
return of_gpio_named_count(np, "gpios");
}
-/*
- * This is used by external users of of_gpio_count() from <linux/of_gpio.h>
- *
- * FIXME: get rid of those external users by converting them to GPIO
- * descriptors and let them all use gpiod_count()
- */
int of_gpio_get_count(struct device *dev, const char *con_id)
{
int ret;
@@ -345,19 +380,28 @@ out:
return desc;
}
-int of_get_named_gpio_flags(const struct device_node *np, const char *list_name,
- int index, enum of_gpio_flags *flags)
+/**
+ * of_get_named_gpio() - Get a GPIO number to use with GPIO API
+ * @np: device node to get GPIO from
+ * @propname: Name of property containing gpio specifier(s)
+ * @index: index of the GPIO
+ *
+ * Returns GPIO number to use with Linux generic GPIO API, or one of the errno
+ * value on the error condition.
+ */
+int of_get_named_gpio(const struct device_node *np, const char *propname,
+ int index)
{
struct gpio_desc *desc;
- desc = of_get_named_gpiod_flags(np, list_name, index, flags);
+ desc = of_get_named_gpiod_flags(np, propname, index, NULL);
if (IS_ERR(desc))
return PTR_ERR(desc);
else
return desc_to_gpio(desc);
}
-EXPORT_SYMBOL_GPL(of_get_named_gpio_flags);
+EXPORT_SYMBOL_GPL(of_get_named_gpio);
/* Converts gpio_lookup_flags into bitmask of GPIO_* values */
static unsigned long of_convert_gpio_flags(enum of_gpio_flags flags)
@@ -389,52 +433,6 @@ static unsigned long of_convert_gpio_flags(enum of_gpio_flags flags)
return lflags;
}
-/**
- * gpiod_get_from_of_node() - obtain a GPIO from an OF node
- * @node: handle of the OF node
- * @propname: name of the DT property representing the GPIO
- * @index: index of the GPIO to obtain for the consumer
- * @dflags: GPIO initialization flags
- * @label: label to attach to the requested GPIO
- *
- * Returns:
- * On successful request the GPIO pin is configured in accordance with
- * provided @dflags.
- *
- * In case of error an ERR_PTR() is returned.
- */
-struct gpio_desc *gpiod_get_from_of_node(const struct device_node *node,
- const char *propname, int index,
- enum gpiod_flags dflags,
- const char *label)
-{
- unsigned long lflags;
- struct gpio_desc *desc;
- enum of_gpio_flags of_flags;
- int ret;
-
- desc = of_get_named_gpiod_flags(node, propname, index, &of_flags);
- if (!desc || IS_ERR(desc))
- return desc;
-
- ret = gpiod_request(desc, label);
- if (ret == -EBUSY && (dflags & GPIOD_FLAGS_BIT_NONEXCLUSIVE))
- return desc;
- if (ret)
- return ERR_PTR(ret);
-
- lflags = of_convert_gpio_flags(of_flags);
-
- ret = gpiod_configure_flags(desc, propname, lflags, dflags);
- if (ret < 0) {
- gpiod_put(desc);
- return ERR_PTR(ret);
- }
-
- return desc;
-}
-EXPORT_SYMBOL_GPL(gpiod_get_from_of_node);
-
static struct gpio_desc *of_find_gpio_rename(struct device_node *np,
const char *con_id,
unsigned int idx,
@@ -668,7 +666,7 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np,
u32 tmp;
int ret;
- chip_np = chip->of_node;
+ chip_np = dev_of_node(&chip->gpiodev->dev);
if (!chip_np)
return ERR_PTR(-EINVAL);
@@ -760,7 +758,7 @@ static int of_gpiochip_scan_gpios(struct gpio_chip *chip)
struct device_node *np;
int ret;
- for_each_available_child_of_node(chip->of_node, np) {
+ for_each_available_child_of_node(dev_of_node(&chip->gpiodev->dev), np) {
if (!of_property_read_bool(np, "gpio-hog"))
continue;
@@ -970,22 +968,18 @@ EXPORT_SYMBOL_GPL(of_mm_gpiochip_remove);
#ifdef CONFIG_PINCTRL
static int of_gpiochip_add_pin_range(struct gpio_chip *chip)
{
- struct device_node *np = chip->of_node;
struct of_phandle_args pinspec;
struct pinctrl_dev *pctldev;
+ struct device_node *np;
int index = 0, ret;
const char *name;
static const char group_names_propname[] = "gpio-ranges-group-names";
struct property *group_names;
+ np = dev_of_node(&chip->gpiodev->dev);
if (!np)
return 0;
- if (!of_property_read_bool(np, "gpio-ranges") &&
- chip->of_gpio_ranges_fallback) {
- return chip->of_gpio_ranges_fallback(chip, np);
- }
-
group_names = of_find_property(np, group_names_propname, NULL);
for (;; index++) {
@@ -1063,7 +1057,7 @@ int of_gpiochip_add(struct gpio_chip *chip)
struct device_node *np;
int ret;
- np = to_of_node(dev_fwnode(&chip->gpiodev->dev));
+ np = dev_of_node(&chip->gpiodev->dev);
if (!np)
return 0;
@@ -1092,19 +1086,3 @@ void of_gpiochip_remove(struct gpio_chip *chip)
{
fwnode_handle_put(chip->fwnode);
}
-
-void of_gpio_dev_init(struct gpio_chip *gc, struct gpio_device *gdev)
-{
- /* Set default OF node to parent's one if present */
- if (gc->parent)
- gdev->dev.of_node = gc->parent->of_node;
-
- if (gc->fwnode)
- gc->of_node = to_of_node(gc->fwnode);
-
- /* If the gpiochip has an assigned OF node this takes precedence */
- if (gc->of_node)
- gdev->dev.of_node = gc->of_node;
- else
- gc->of_node = gdev->dev.of_node;
-}
diff --git a/drivers/gpio/gpiolib-of.h b/drivers/gpio/gpiolib-of.h
index a6c593e6766c..e5bb065d82ef 100644
--- a/drivers/gpio/gpiolib-of.h
+++ b/drivers/gpio/gpiolib-of.h
@@ -23,7 +23,6 @@ struct gpio_desc *of_find_gpio(struct device_node *np,
int of_gpiochip_add(struct gpio_chip *gc);
void of_gpiochip_remove(struct gpio_chip *gc);
int of_gpio_get_count(struct device *dev, const char *con_id);
-void of_gpio_dev_init(struct gpio_chip *gc, struct gpio_device *gdev);
#else
static inline struct gpio_desc *of_find_gpio(struct device_node *np,
const char *con_id,
@@ -38,10 +37,6 @@ static inline int of_gpio_get_count(struct device *dev, const char *con_id)
{
return 0;
}
-static inline void of_gpio_dev_init(struct gpio_chip *gc,
- struct gpio_device *gdev)
-{
-}
#endif /* CONFIG_OF_GPIO */
extern struct notifier_block gpio_of_notifier;
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 939c776b9488..19bd23044b01 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1,34 +1,35 @@
// SPDX-License-Identifier: GPL-2.0
+#include <linux/acpi.h>
#include <linux/bitmap.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/spinlock.h>
-#include <linux/list.h>
+#include <linux/compat.h>
+#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/err.h>
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
+#include <linux/file.h>
+#include <linux/fs.h>
#include <linux/gpio.h>
-#include <linux/idr.h>
-#include <linux/slab.h>
-#include <linux/acpi.h>
#include <linux/gpio/driver.h>
#include <linux/gpio/machine.h>
+#include <linux/idr.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
#include <linux/pinctrl/consumer.h>
-#include <linux/fs.h>
-#include <linux/compat.h>
-#include <linux/file.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
#include <uapi/linux/gpio.h>
-#include "gpiolib.h"
-#include "gpiolib-of.h"
#include "gpiolib-acpi.h"
-#include "gpiolib-swnode.h"
#include "gpiolib-cdev.h"
+#include "gpiolib-of.h"
+#include "gpiolib-swnode.h"
#include "gpiolib-sysfs.h"
+#include "gpiolib.h"
#define CREATE_TRACE_POINTS
#include <trace/events/gpio.h>
@@ -531,6 +532,14 @@ static void gpiochip_free_valid_mask(struct gpio_chip *gc)
static int gpiochip_add_pin_ranges(struct gpio_chip *gc)
{
+ /*
+ * Device Tree platforms are supposed to use "gpio-ranges"
+ * property. This check ensures that the ->add_pin_ranges()
+ * won't be called for them.
+ */
+ if (device_property_present(&gc->gpiodev->dev, "gpio-ranges"))
+ return 0;
+
if (gc->add_pin_ranges)
return gc->add_pin_ranges(gc);
@@ -578,6 +587,13 @@ static int gpiochip_setup_dev(struct gpio_device *gdev)
{
int ret;
+ /*
+ * If fwnode doesn't belong to another device, it's safe to clear its
+ * initialized flag.
+ */
+ if (gdev->dev.fwnode && !gdev->dev.fwnode->dev)
+ fwnode_dev_initialized(gdev->dev.fwnode, false);
+
ret = gcdev_register(gdev, gpio_devt);
if (ret)
return ret;
@@ -659,10 +675,12 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
int base = 0;
int ret = 0;
+ /* If the calling driver did not initialize firmware node, do it here */
if (gc->fwnode)
fwnode = gc->fwnode;
else if (gc->parent)
fwnode = dev_fwnode(gc->parent);
+ gc->fwnode = fwnode;
/*
* First: allocate and populate the internal stat container, and
@@ -676,14 +694,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
gdev->chip = gc;
gc->gpiodev = gdev;
- of_gpio_dev_init(gc, gdev);
- acpi_gpio_dev_init(gc, gdev);
-
- /*
- * Assign fwnode depending on the result of the previous calls,
- * if none of them succeed, assign it to the parent's one.
- */
- gc->fwnode = gdev->dev.fwnode = dev_fwnode(&gdev->dev) ?: fwnode;
+ device_set_node(&gdev->dev, gc->fwnode);
gdev->id = ida_alloc(&gpio_ida, GFP_KERNEL);
if (gdev->id < 0) {
@@ -882,7 +893,7 @@ err_free_gpiochip_mask:
gpiochip_free_valid_mask(gc);
if (gdev->dev.release) {
/* release() has been registered by gpiochip_setup_dev() */
- put_device(&gdev->dev);
+ gpio_device_put(gdev);
goto err_print_message;
}
err_remove_from_list:
@@ -972,7 +983,7 @@ void gpiochip_remove(struct gpio_chip *gc)
*/
gcdev_unregister(gdev);
up_write(&gdev->sem);
- put_device(&gdev->dev);
+ gpio_device_put(gdev);
}
EXPORT_SYMBOL_GPL(gpiochip_remove);
@@ -1126,14 +1137,8 @@ static void gpiochip_set_hierarchical_irqchip(struct gpio_chip *gc,
/* Just pick something */
fwspec.param[1] = IRQ_TYPE_EDGE_RISING;
fwspec.param_count = 2;
- ret = __irq_domain_alloc_irqs(gc->irq.domain,
- /* just pick something */
- -1,
- 1,
- NUMA_NO_NODE,
- &fwspec,
- false,
- NULL);
+ ret = irq_domain_alloc_irqs(gc->irq.domain, 1,
+ NUMA_NO_NODE, &fwspec);
if (ret < 0) {
chip_err(gc,
"can not allocate irq for GPIO line %d parent hwirq %d in hierarchy domain: %d\n",
@@ -2063,17 +2068,15 @@ static int validate_desc(const struct gpio_desc *desc, const char *func)
int gpiod_request(struct gpio_desc *desc, const char *label)
{
int ret = -EPROBE_DEFER;
- struct gpio_device *gdev;
VALIDATE_DESC(desc);
- gdev = desc->gdev;
- if (try_module_get(gdev->owner)) {
+ if (try_module_get(desc->gdev->owner)) {
ret = gpiod_request_commit(desc, label);
if (ret)
- module_put(gdev->owner);
+ module_put(desc->gdev->owner);
else
- get_device(&gdev->dev);
+ gpio_device_get(desc->gdev);
}
if (ret)
@@ -2134,7 +2137,7 @@ void gpiod_free(struct gpio_desc *desc)
{
if (desc && desc->gdev && gpiod_free_commit(desc)) {
module_put(desc->gdev->owner);
- put_device(&desc->gdev->dev);
+ gpio_device_put(desc->gdev);
} else {
WARN_ON(extra_checks);
}
diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
index b3c2db6eba80..cca81375f127 100644
--- a/drivers/gpio/gpiolib.h
+++ b/drivers/gpio/gpiolib.h
@@ -82,6 +82,16 @@ static inline struct gpio_device *to_gpio_device(struct device *dev)
return container_of(dev, struct gpio_device, dev);
}
+static inline struct gpio_device *gpio_device_get(struct gpio_device *gdev)
+{
+ return to_gpio_device(get_device(&gdev->dev));
+}
+
+static inline void gpio_device_put(struct gpio_device *gdev)
+{
+ put_device(&gdev->dev);
+}
+
/* gpio suffixes used for ACPI and device tree lookup */
static __maybe_unused const char * const gpio_suffixes[] = { "gpios", "gpio" };
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 9abfb482b615..dc0f94f02a82 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -12,7 +12,6 @@ menuconfig DRM
select HDMI
select FB_CMDLINE
select I2C
- select I2C_ALGOBIT
select DMA_SHARED_BUFFER
select SYNC_FILE
# gallium uses SYS_kcmp for os_same_file_description() to de-duplicate
@@ -64,6 +63,12 @@ config DRM_USE_DYNAMIC_DEBUG
bytes per callsite, the .data costs can be substantial, and
are therefore configurable.
+config DRM_KUNIT_TEST_HELPERS
+ tristate
+ depends on DRM && KUNIT
+ help
+ KUnit Helpers for KMS drivers.
+
config DRM_KUNIT_TEST
tristate "KUnit tests for DRM" if !KUNIT_ALL_TESTS
depends on DRM && KUNIT
@@ -74,6 +79,7 @@ config DRM_KUNIT_TEST
select DRM_KMS_HELPER
select DRM_BUDDY
select DRM_EXPORT_FOR_TESTS if m
+ select DRM_KUNIT_TEST_HELPERS
default KUNIT_ALL_TESTS
help
This builds unit tests for DRM. This option is not useful for
@@ -392,64 +398,7 @@ menuconfig DRM_LEGACY
Unless you have strong reasons to go rogue, say "N".
if DRM_LEGACY
-
-config DRM_TDFX
- tristate "3dfx Banshee/Voodoo3+"
- depends on DRM && PCI
- help
- Choose this option if you have a 3dfx Banshee or Voodoo3 (or later),
- graphics card. If M is selected, the module will be called tdfx.
-
-config DRM_R128
- tristate "ATI Rage 128"
- depends on DRM && PCI
- select FW_LOADER
- help
- Choose this option if you have an ATI Rage 128 graphics card. If M
- is selected, the module will be called r128. AGP support for
- this card is strongly suggested (unless you have a PCI version).
-
-config DRM_I810
- tristate "Intel I810"
- # !PREEMPTION because of missing ioctl locking
- depends on DRM && AGP && AGP_INTEL && (!PREEMPTION || BROKEN)
- help
- Choose this option if you have an Intel I810 graphics card. If M is
- selected, the module will be called i810. AGP support is required
- for this driver to work.
-
-config DRM_MGA
- tristate "Matrox g200/g400"
- depends on DRM && PCI
- select FW_LOADER
- help
- Choose this option if you have a Matrox G200, G400 or G450 graphics
- card. If M is selected, the module will be called mga. AGP
- support is required for this driver to work.
-
-config DRM_SIS
- tristate "SiS video cards"
- depends on DRM && AGP
- depends on FB_SIS || FB_SIS=n
- help
- Choose this option if you have a SiS 630 or compatible video
- chipset. If M is selected the module will be called sis. AGP
- support is required for this driver to work.
-
-config DRM_VIA
- tristate "Via unichrome video cards"
- depends on DRM && PCI
- help
- Choose this option if you have a Via unichrome or compatible video
- chipset. If M is selected the module will be called via.
-
-config DRM_SAVAGE
- tristate "Savage video cards"
- depends on DRM && PCI
- help
- Choose this option if you have a Savage3D/4/SuperSavage/Pro/Twister
- chipset. If M is selected the module will be called savage.
-
+# leave here to list legacy drivers
endif # DRM_LEGACY
config DRM_EXPORT_FOR_TESTS
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index cc637343d87b..ab4460fcd63f 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -126,7 +126,7 @@ obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
# Drivers and the rest
#
-obj-$(CONFIG_DRM_KUNIT_TEST) += tests/
+obj-y += tests/
obj-$(CONFIG_DRM_MIPI_DBI) += drm_mipi_dbi.o
obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o
@@ -134,21 +134,14 @@ obj-y += arm/
obj-y += display/
obj-$(CONFIG_DRM_TTM) += ttm/
obj-$(CONFIG_DRM_SCHED) += scheduler/
-obj-$(CONFIG_DRM_TDFX) += tdfx/
-obj-$(CONFIG_DRM_R128) += r128/
obj-$(CONFIG_DRM_RADEON)+= radeon/
obj-$(CONFIG_DRM_AMDGPU)+= amd/amdgpu/
-obj-$(CONFIG_DRM_MGA) += mga/
-obj-$(CONFIG_DRM_I810) += i810/
obj-$(CONFIG_DRM_I915) += i915/
obj-$(CONFIG_DRM_KMB_DISPLAY) += kmb/
obj-$(CONFIG_DRM_MGAG200) += mgag200/
obj-$(CONFIG_DRM_V3D) += v3d/
obj-$(CONFIG_DRM_VC4) += vc4/
-obj-$(CONFIG_DRM_SIS) += sis/
-obj-$(CONFIG_DRM_SAVAGE)+= savage/
obj-$(CONFIG_DRM_VMWGFX)+= vmwgfx/
-obj-$(CONFIG_DRM_VIA) +=via/
obj-$(CONFIG_DRM_VGEM) += vgem/
obj-$(CONFIG_DRM_VKMS) += vkms/
obj-$(CONFIG_DRM_NOUVEAU) +=nouveau/
diff --git a/drivers/gpu/drm/amd/amdgpu/Kconfig b/drivers/gpu/drm/amd/amdgpu/Kconfig
index 5fcd510f1abb..a82d36ea88e2 100644
--- a/drivers/gpu/drm/amd/amdgpu/Kconfig
+++ b/drivers/gpu/drm/amd/amdgpu/Kconfig
@@ -6,6 +6,7 @@ config DRM_AMDGPU
select FW_LOADER
select DRM_DISPLAY_DP_HELPER
select DRM_DISPLAY_HDMI_HELPER
+ select DRM_DISPLAY_HDCP_HELPER
select DRM_DISPLAY_HELPER
select DRM_KMS_HELPER
select DRM_SCHED
@@ -13,6 +14,8 @@ config DRM_AMDGPU
select DRM_TTM_HELPER
select POWER_SUPPLY
select HWMON
+ select I2C
+ select I2C_ALGOBIT
select BACKLIGHT_CLASS_DEVICE
select INTERVAL_TREE
select DRM_BUDDY
diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile
index 798d0e9a60b7..1d72cbc85348 100644
--- a/drivers/gpu/drm/amd/amdgpu/Makefile
+++ b/drivers/gpu/drm/amd/amdgpu/Makefile
@@ -34,6 +34,7 @@ ccflags-y := -I$(FULL_AMD_PATH)/include/asic_reg \
-I$(FULL_AMD_PATH)/acp/include \
-I$(FULL_AMD_DISPLAY_PATH) \
-I$(FULL_AMD_DISPLAY_PATH)/include \
+ -I$(FULL_AMD_DISPLAY_PATH)/modules/inc \
-I$(FULL_AMD_DISPLAY_PATH)/dc \
-I$(FULL_AMD_DISPLAY_PATH)/amdgpu_dm \
-I$(FULL_AMD_PATH)/amdkfd
@@ -76,12 +77,13 @@ amdgpu-y += \
vi.o mxgpu_vi.o nbio_v6_1.o soc15.o emu_soc.o mxgpu_ai.o nbio_v7_0.o vega10_reg_init.o \
vega20_reg_init.o nbio_v7_4.o nbio_v2_3.o nv.o arct_reg_init.o mxgpu_nv.o \
nbio_v7_2.o hdp_v4_0.o hdp_v5_0.o aldebaran_reg_init.o aldebaran.o soc21.o \
- sienna_cichlid.o nbio_v4_3.o hdp_v6_0.o nbio_v7_7.o hdp_v5_2.o lsdma_v6_0.o
+ sienna_cichlid.o smu_v13_0_10.o nbio_v4_3.o hdp_v6_0.o nbio_v7_7.o hdp_v5_2.o lsdma_v6_0.o
# add DF block
amdgpu-y += \
df_v1_7.o \
- df_v3_6.o
+ df_v3_6.o \
+ df_v4_3.o
# add GMC block
amdgpu-y += \
@@ -136,6 +138,7 @@ amdgpu-y += \
gfx_v10_0.o \
imu_v11_0.o \
gfx_v11_0.o \
+ gfx_v11_0_3.o \
imu_v11_0_3.o
# add async DMA block
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index d148a1bd85e6..164141bc8b4a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -52,8 +52,7 @@
#include <linux/pci.h>
#include <linux/aer.h>
-#include <drm/ttm/ttm_bo_api.h>
-#include <drm/ttm/ttm_bo_driver.h>
+#include <drm/ttm/ttm_bo.h>
#include <drm/ttm/ttm_placement.h>
#include <drm/ttm/ttm_execbuf_util.h>
@@ -150,7 +149,7 @@ struct amdgpu_watchdog_timer
* Modules parameters.
*/
extern int amdgpu_modeset;
-extern int amdgpu_vram_limit;
+extern unsigned int amdgpu_vram_limit;
extern int amdgpu_vis_vram_limit;
extern int amdgpu_gart_size;
extern int amdgpu_gtt_size;
@@ -610,7 +609,7 @@ int amdgpu_cs_wait_fences_ioctl(struct drm_device *dev, void *data,
struct drm_file *filp);
/* VRAM scratch page for HDP bug, default vram page */
-struct amdgpu_vram_scratch {
+struct amdgpu_mem_scratch {
struct amdgpu_bo *robj;
volatile uint32_t *ptr;
u64 gpu_addr;
@@ -757,6 +756,11 @@ struct amdgpu_mqd {
#define AMDGPU_PRODUCT_NAME_LEN 64
struct amdgpu_reset_domain;
+/*
+ * Non-zero (true) if the GPU has VRAM. Zero (false) otherwise.
+ */
+#define AMDGPU_HAS_VRAM(_adev) ((_adev)->gmc.real_vram_size)
+
struct amdgpu_device {
struct device *dev;
struct pci_dev *pdev;
@@ -850,7 +854,7 @@ struct amdgpu_device {
/* memory management */
struct amdgpu_mman mman;
- struct amdgpu_vram_scratch vram_scratch;
+ struct amdgpu_mem_scratch mem_scratch;
struct amdgpu_wb wb;
atomic64_t num_bytes_moved;
atomic64_t num_evictions;
@@ -872,7 +876,7 @@ struct amdgpu_device {
struct amdgpu_vkms_output *amdgpu_vkms_output;
struct amdgpu_mode_info mode_info;
/* For pre-DCE11. DCE11 and later are in "struct amdgpu_device->dm" */
- struct work_struct hotplug_work;
+ struct delayed_work hotplug_work;
struct amdgpu_irq_src crtc_irq;
struct amdgpu_irq_src vline0_irq;
struct amdgpu_irq_src vupdate_irq;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
index 57b5e11446c6..d4196fcb85a0 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
@@ -24,6 +24,7 @@
#include <linux/pci.h>
#include <linux/acpi.h>
+#include <linux/backlight.h>
#include <linux/slab.h>
#include <linux/power_supply.h>
#include <linux/pm_runtime.h>
@@ -31,7 +32,6 @@
#include <acpi/video.h>
#include <acpi/actbl.h>
-#include <drm/drm_crtc_helper.h>
#include "amdgpu.h"
#include "amdgpu_pm.h"
#include "amdgpu_display.h"
@@ -1073,26 +1073,25 @@ bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev)
(pm_suspend_target_state != PM_SUSPEND_TO_IDLE))
return false;
+ if (adev->asic_type < CHIP_RAVEN)
+ return false;
+
/*
* If ACPI_FADT_LOW_POWER_S0 is not set in the FADT, it is generally
* risky to do any special firmware-related preparations for entering
* S0ix even though the system is suspending to idle, so return false
* in that case.
*/
- if (!(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0)) {
+ if (!(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0))
dev_warn_once(adev->dev,
"Power consumption will be higher as BIOS has not been configured for suspend-to-idle.\n"
"To use suspend-to-idle change the sleep mode in BIOS setup.\n");
- return false;
- }
#if !IS_ENABLED(CONFIG_AMD_PMC)
dev_warn_once(adev->dev,
"Power consumption will be higher as the kernel has not been compiled with CONFIG_AMD_PMC.\n");
- return false;
-#else
- return true;
#endif /* CONFIG_AMD_PMC */
+ return true;
}
#endif /* CONFIG_SUSPEND */
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
index 0040deaf8a83..333780491867 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
@@ -97,7 +97,7 @@ struct amdgpu_amdkfd_fence {
struct amdgpu_kfd_dev {
struct kfd_dev *dev;
- uint64_t vram_used;
+ int64_t vram_used;
uint64_t vram_used_aligned;
bool init_complete;
struct work_struct reset_work;
@@ -271,9 +271,9 @@ int amdgpu_amdkfd_get_pcie_bandwidth_mbytes(struct amdgpu_device *adev, bool is_
((struct drm_file *)(drm_priv))->driver_priv)->vm)
int amdgpu_amdkfd_gpuvm_set_vm_pasid(struct amdgpu_device *adev,
- struct file *filp, u32 pasid);
+ struct amdgpu_vm *avm, u32 pasid);
int amdgpu_amdkfd_gpuvm_acquire_process_vm(struct amdgpu_device *adev,
- struct file *filp,
+ struct amdgpu_vm *avm,
void **process_info,
struct dma_fence **ef);
void amdgpu_amdkfd_gpuvm_release_process_vm(struct amdgpu_device *adev,
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
index 3b5c53712d31..d6320c836251 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
@@ -25,6 +25,7 @@
#include <linux/pagemap.h>
#include <linux/sched/mm.h>
#include <linux/sched/task.h>
+#include <drm/ttm/ttm_tt.h>
#include "amdgpu_object.h"
#include "amdgpu_gem.h"
@@ -1430,18 +1431,11 @@ static void amdgpu_amdkfd_gpuvm_unpin_bo(struct amdgpu_bo *bo)
}
int amdgpu_amdkfd_gpuvm_set_vm_pasid(struct amdgpu_device *adev,
- struct file *filp, u32 pasid)
+ struct amdgpu_vm *avm, u32 pasid)
{
- struct amdgpu_fpriv *drv_priv;
- struct amdgpu_vm *avm;
int ret;
- ret = amdgpu_file_to_fpriv(filp, &drv_priv);
- if (ret)
- return ret;
- avm = &drv_priv->vm;
-
/* Free the original amdgpu allocated pasid,
* will be replaced with kfd allocated pasid.
*/
@@ -1458,19 +1452,12 @@ int amdgpu_amdkfd_gpuvm_set_vm_pasid(struct amdgpu_device *adev,
}
int amdgpu_amdkfd_gpuvm_acquire_process_vm(struct amdgpu_device *adev,
- struct file *filp,
+ struct amdgpu_vm *avm,
void **process_info,
struct dma_fence **ef)
{
- struct amdgpu_fpriv *drv_priv;
- struct amdgpu_vm *avm;
int ret;
- ret = amdgpu_file_to_fpriv(filp, &drv_priv);
- if (ret)
- return ret;
- avm = &drv_priv->vm;
-
/* Already a compute VM? */
if (avm->process_info)
return -EINVAL;
@@ -1612,6 +1599,7 @@ int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu(
struct amdgpu_bo *bo;
struct drm_gem_object *gobj = NULL;
u32 domain, alloc_domain;
+ uint64_t aligned_size;
u64 alloc_flags;
int ret;
@@ -1667,22 +1655,23 @@ int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu(
* the memory.
*/
if ((*mem)->aql_queue)
- size = size >> 1;
+ size >>= 1;
+ aligned_size = PAGE_ALIGN(size);
(*mem)->alloc_flags = flags;
amdgpu_sync_create(&(*mem)->sync);
- ret = amdgpu_amdkfd_reserve_mem_limit(adev, size, flags);
+ ret = amdgpu_amdkfd_reserve_mem_limit(adev, aligned_size, flags);
if (ret) {
pr_debug("Insufficient memory\n");
goto err_reserve_limit;
}
pr_debug("\tcreate BO VA 0x%llx size 0x%llx domain %s\n",
- va, size, domain_string(alloc_domain));
+ va, (*mem)->aql_queue ? size << 1 : size, domain_string(alloc_domain));
- ret = amdgpu_gem_object_create(adev, size, 1, alloc_domain, alloc_flags,
+ ret = amdgpu_gem_object_create(adev, aligned_size, 1, alloc_domain, alloc_flags,
bo_type, NULL, &gobj);
if (ret) {
pr_debug("Failed to create BO on domain %s. ret %d\n",
@@ -1739,7 +1728,7 @@ err_node_allow:
/* Don't unreserve system mem limit twice */
goto err_reserve_limit;
err_bo_create:
- amdgpu_amdkfd_unreserve_mem_limit(adev, size, flags);
+ amdgpu_amdkfd_unreserve_mem_limit(adev, aligned_size, flags);
err_reserve_limit:
mutex_destroy(&(*mem)->lock);
if (gobj)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h
index e4d78491bcc7..ededdc01ca28 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h
@@ -28,6 +28,8 @@
struct hmm_range;
+struct drm_file;
+
struct amdgpu_device;
struct amdgpu_bo;
struct amdgpu_bo_va;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c
index f1a050379190..456e385333b6 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c
@@ -411,17 +411,10 @@ static int amdgpu_cgs_get_firmware_info(struct cgs_device *cgs_device,
return -EINVAL;
}
- err = request_firmware(&adev->pm.fw, fw_name, adev->dev);
- if (err) {
- DRM_ERROR("Failed to request firmware\n");
- return err;
- }
-
- err = amdgpu_ucode_validate(adev->pm.fw);
+ err = amdgpu_ucode_request(adev, &adev->pm.fw, fw_name);
if (err) {
DRM_ERROR("Failed to load firmware \"%s\"", fw_name);
- release_firmware(adev->pm.fw);
- adev->pm.fw = NULL;
+ amdgpu_ucode_release(&adev->pm.fw);
return err;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
index 2ebbc6382a06..6be30dcb029d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
@@ -25,7 +25,9 @@
*/
#include <drm/display/drm_dp_helper.h>
+#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_probe_helper.h>
#include <drm/amdgpu_drm.h>
#include "amdgpu.h"
@@ -996,13 +998,33 @@ amdgpu_connector_dvi_detect(struct drm_connector *connector, bool force)
}
}
+ if (amdgpu_connector->detected_hpd_without_ddc) {
+ force = true;
+ amdgpu_connector->detected_hpd_without_ddc = false;
+ }
+
if (!force && amdgpu_connector_check_hpd_status_unchanged(connector)) {
ret = connector->status;
goto exit;
}
- if (amdgpu_connector->ddc_bus)
+ if (amdgpu_connector->ddc_bus) {
dret = amdgpu_display_ddc_probe(amdgpu_connector, false);
+
+ /* Sometimes the pins required for the DDC probe on DVI
+ * connectors don't make contact at the same time that the ones
+ * for HPD do. If the DDC probe fails even though we had an HPD
+ * signal, try again later
+ */
+ if (!dret && !force &&
+ amdgpu_display_hpd_sense(adev, amdgpu_connector->hpd.hpd)) {
+ DRM_DEBUG_KMS("hpd detected without ddc, retrying in 1 second\n");
+ amdgpu_connector->detected_hpd_without_ddc = true;
+ schedule_delayed_work(&adev->hotplug_work,
+ msecs_to_jiffies(1000));
+ goto exit;
+ }
+ }
if (dret) {
amdgpu_connector->detected_by_load = false;
amdgpu_connector_free_edid(connector);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
index 7af3041ccd0e..08eced097bd8 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
@@ -32,6 +32,8 @@
#include <drm/amdgpu_drm.h>
#include <drm/drm_syncobj.h>
+#include <drm/ttm/ttm_tt.h>
+
#include "amdgpu_cs.h"
#include "amdgpu.h"
#include "amdgpu_trace.h"
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.h
index 113f39510a72..fb3e3d56d427 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.h
@@ -23,6 +23,8 @@
#ifndef __AMDGPU_CS_H__
#define __AMDGPU_CS_H__
+#include <linux/ww_mutex.h>
+
#include "amdgpu_job.h"
#include "amdgpu_bo_list.h"
#include "amdgpu_ring.h"
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
index 0f16d3c09309..f60753f97ac5 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
@@ -1717,7 +1717,7 @@ no_preempt:
static int amdgpu_debugfs_ib_preempt(void *data, u64 val)
{
- int r, resched, length;
+ int r, length;
struct amdgpu_ring *ring;
struct dma_fence **fences = NULL;
struct amdgpu_device *adev = (struct amdgpu_device *)data;
@@ -1747,8 +1747,6 @@ static int amdgpu_debugfs_ib_preempt(void *data, u64 val)
/* stop the scheduler */
kthread_park(ring->sched.thread);
- resched = ttm_bo_lock_delayed_workqueue(&adev->mman.bdev);
-
/* preempt the IB */
r = amdgpu_ring_preempt_ib(ring);
if (r) {
@@ -1785,8 +1783,6 @@ failure:
up_read(&adev->reset_domain->sem);
- ttm_bo_unlock_delayed_workqueue(&adev->mman.bdev, resched);
-
pro_end:
kfree(fences);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index fbf2f24169eb..c4a4e2fe6681 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -38,6 +38,7 @@
#include <drm/drm_aperture.h>
#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_probe_helper.h>
#include <drm/amdgpu_drm.h>
@@ -163,7 +164,7 @@ static void amdgpu_device_get_pcie_info(struct amdgpu_device *adev);
*
* The amdgpu driver provides a sysfs API for reporting the product name
* for the device
- * The file serial_number is used for this and returns the product name
+ * The file product_name is used for this and returns the product name
* as returned from the FRU.
* NOTE: This is only available for certain server cards
*/
@@ -185,7 +186,7 @@ static DEVICE_ATTR(product_name, S_IRUGO,
*
* The amdgpu driver provides a sysfs API for reporting the part number
* for the device
- * The file serial_number is used for this and returns the part number
+ * The file product_number is used for this and returns the part number
* as returned from the FRU.
* NOTE: This is only available for certain server cards
*/
@@ -927,32 +928,33 @@ static int amdgpu_device_asic_init(struct amdgpu_device *adev)
}
/**
- * amdgpu_device_vram_scratch_init - allocate the VRAM scratch page
+ * amdgpu_device_mem_scratch_init - allocate the VRAM scratch page
*
* @adev: amdgpu_device pointer
*
* Allocates a scratch page of VRAM for use by various things in the
* driver.
*/
-static int amdgpu_device_vram_scratch_init(struct amdgpu_device *adev)
+static int amdgpu_device_mem_scratch_init(struct amdgpu_device *adev)
{
- return amdgpu_bo_create_kernel(adev, AMDGPU_GPU_PAGE_SIZE,
- PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM,
- &adev->vram_scratch.robj,
- &adev->vram_scratch.gpu_addr,
- (void **)&adev->vram_scratch.ptr);
+ return amdgpu_bo_create_kernel(adev, AMDGPU_GPU_PAGE_SIZE, PAGE_SIZE,
+ AMDGPU_GEM_DOMAIN_VRAM |
+ AMDGPU_GEM_DOMAIN_GTT,
+ &adev->mem_scratch.robj,
+ &adev->mem_scratch.gpu_addr,
+ (void **)&adev->mem_scratch.ptr);
}
/**
- * amdgpu_device_vram_scratch_fini - Free the VRAM scratch page
+ * amdgpu_device_mem_scratch_fini - Free the VRAM scratch page
*
* @adev: amdgpu_device pointer
*
* Frees the VRAM scratch page.
*/
-static void amdgpu_device_vram_scratch_fini(struct amdgpu_device *adev)
+static void amdgpu_device_mem_scratch_fini(struct amdgpu_device *adev)
{
- amdgpu_bo_free_kernel(&adev->vram_scratch.robj, NULL, NULL);
+ amdgpu_bo_free_kernel(&adev->mem_scratch.robj, NULL, NULL);
}
/**
@@ -1984,17 +1986,10 @@ static int amdgpu_device_parse_gpu_info_fw(struct amdgpu_device *adev)
}
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_gpu_info.bin", chip_name);
- err = request_firmware(&adev->firmware.gpu_info_fw, fw_name, adev->dev);
+ err = amdgpu_ucode_request(adev, &adev->firmware.gpu_info_fw, fw_name);
if (err) {
dev_err(adev->dev,
- "Failed to load gpu_info firmware \"%s\"\n",
- fw_name);
- goto out;
- }
- err = amdgpu_ucode_validate(adev->firmware.gpu_info_fw);
- if (err) {
- dev_err(adev->dev,
- "Failed to validate gpu_info firmware \"%s\"\n",
+ "Failed to get gpu_info firmware \"%s\"\n",
fw_name);
goto out;
}
@@ -2081,6 +2076,7 @@ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev)
struct drm_device *dev = adev_to_drm(adev);
struct pci_dev *parent;
int i, r;
+ bool total;
amdgpu_device_enable_virtual_display(adev);
@@ -2164,6 +2160,7 @@ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev)
if (amdgpu_sriov_vf(adev) && adev->asic_type == CHIP_SIENNA_CICHLID)
adev->pm.pp_feature &= ~PP_OVERDRIVE_MASK;
+ total = true;
for (i = 0; i < adev->num_ip_blocks; i++) {
if ((amdgpu_ip_block_mask & (1 << i)) == 0) {
DRM_ERROR("disabled ip block: %d <%s>\n",
@@ -2177,7 +2174,7 @@ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev)
} else if (r) {
DRM_ERROR("early_init of IP block <%s> failed %d\n",
adev->ip_blocks[i].version->funcs->name, r);
- return r;
+ total = false;
} else {
adev->ip_blocks[i].status.valid = true;
}
@@ -2208,6 +2205,8 @@ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev)
}
}
+ if (!total)
+ return -ENODEV;
adev->cg_flags &= amdgpu_cg_mask;
adev->pg_flags &= amdgpu_pg_mask;
@@ -2393,9 +2392,9 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev)
if (amdgpu_sriov_vf(adev))
amdgpu_virt_exchange_data(adev);
- r = amdgpu_device_vram_scratch_init(adev);
+ r = amdgpu_device_mem_scratch_init(adev);
if (r) {
- DRM_ERROR("amdgpu_vram_scratch_init failed %d\n", r);
+ DRM_ERROR("amdgpu_mem_scratch_init failed %d\n", r);
goto init_failed;
}
r = adev->ip_blocks[i].version->funcs->hw_init((void *)adev);
@@ -2413,8 +2412,9 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev)
/* right after GMC hw init, we create CSA */
if (amdgpu_mcbp) {
r = amdgpu_allocate_static_csa(adev, &adev->virt.csa_obj,
- AMDGPU_GEM_DOMAIN_VRAM,
- AMDGPU_CSA_SIZE);
+ AMDGPU_GEM_DOMAIN_VRAM |
+ AMDGPU_GEM_DOMAIN_GTT,
+ AMDGPU_CSA_SIZE);
if (r) {
DRM_ERROR("allocate CSA failed %d\n", r);
goto init_failed;
@@ -2584,9 +2584,10 @@ int amdgpu_device_set_cg_state(struct amdgpu_device *adev,
i = state == AMD_CG_STATE_GATE ? j : adev->num_ip_blocks - j - 1;
if (!adev->ip_blocks[i].status.late_initialized)
continue;
- /* skip CG for GFX on S0ix */
+ /* skip CG for GFX, SDMA on S0ix */
if (adev->in_s0ix &&
- adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GFX)
+ (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GFX ||
+ adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SDMA))
continue;
/* skip CG for VCE/UVD, it's handled specially */
if (adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_UVD &&
@@ -2620,9 +2621,10 @@ int amdgpu_device_set_pg_state(struct amdgpu_device *adev,
i = state == AMD_PG_STATE_GATE ? j : adev->num_ip_blocks - j - 1;
if (!adev->ip_blocks[i].status.late_initialized)
continue;
- /* skip PG for GFX on S0ix */
+ /* skip PG for GFX, SDMA on S0ix */
if (adev->in_s0ix &&
- adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GFX)
+ (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GFX ||
+ adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SDMA))
continue;
/* skip CG for VCE/UVD, it's handled specially */
if (adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_UVD &&
@@ -2874,7 +2876,7 @@ static int amdgpu_device_ip_fini(struct amdgpu_device *adev)
amdgpu_ucode_free_bo(adev);
amdgpu_free_static_csa(&adev->virt.csa_obj);
amdgpu_device_wb_fini(adev);
- amdgpu_device_vram_scratch_fini(adev);
+ amdgpu_device_mem_scratch_fini(adev);
amdgpu_ib_pool_fini(adev);
}
@@ -3030,6 +3032,24 @@ static int amdgpu_device_ip_suspend_phase2(struct amdgpu_device *adev)
adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_MES))
continue;
+ /* SDMA 5.x+ is part of GFX power domain so it's covered by GFXOFF */
+ if (adev->in_s0ix &&
+ (adev->ip_versions[SDMA0_HWIP][0] >= IP_VERSION(5, 0, 0)) &&
+ (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SDMA))
+ continue;
+
+ /* Once swPSP provides the IMU, RLC FW binaries to TOS during cold-boot.
+ * These are in TMR, hence are expected to be reused by PSP-TOS to reload
+ * from this location and RLC Autoload automatically also gets loaded
+ * from here based on PMFW -> PSP message during re-init sequence.
+ * Therefore, the psp suspend & resume should be skipped to avoid destroy
+ * the TMR and reload FWs again for IMU enabled APU ASICs.
+ */
+ if (amdgpu_in_reset(adev) &&
+ (adev->flags & AMD_IS_APU) && adev->gfx.imu.funcs &&
+ adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_PSP)
+ continue;
+
/* XXX handle errors */
r = adev->ip_blocks[i].version->funcs->suspend(adev);
/* XXX handle errors */
@@ -3230,15 +3250,6 @@ static int amdgpu_device_ip_resume_phase2(struct amdgpu_device *adev)
return r;
}
adev->ip_blocks[i].status.hw = true;
-
- if (adev->in_s0ix && adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SMC) {
- /* disable gfxoff for IP resume. The gfxoff will be re-enabled in
- * amdgpu_device_resume() after IP resume.
- */
- amdgpu_gfx_off_ctrl(adev, false);
- DRM_DEBUG("will disable gfxoff for re-initializing other blocks\n");
- }
-
}
return 0;
@@ -3997,10 +4008,8 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev)
}
amdgpu_fence_driver_hw_fini(adev);
- if (adev->mman.initialized) {
- flush_delayed_work(&adev->mman.bdev.wq);
- ttm_bo_lock_delayed_workqueue(&adev->mman.bdev);
- }
+ if (adev->mman.initialized)
+ drain_workqueue(adev->mman.bdev.wq);
if (adev->pm_sysfs_en)
amdgpu_pm_sysfs_fini(adev);
@@ -4022,7 +4031,8 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev)
amdgpu_gart_dummy_page_fini(adev);
- amdgpu_device_unmap_mmio(adev);
+ if (drm_dev_is_unplugged(adev_to_drm(adev)))
+ amdgpu_device_unmap_mmio(adev);
}
@@ -4032,8 +4042,7 @@ void amdgpu_device_fini_sw(struct amdgpu_device *adev)
amdgpu_fence_driver_sw_fini(adev);
amdgpu_device_ip_fini(adev);
- release_firmware(adev->firmware.gpu_info_fw);
- adev->firmware.gpu_info_fw = NULL;
+ amdgpu_ucode_release(&adev->firmware.gpu_info_fw);
adev->accel_working = false;
dma_fence_put(rcu_dereference_protected(adev->gang_submit, true));
@@ -4231,13 +4240,6 @@ exit:
/* Make sure IB tests flushed */
flush_delayed_work(&adev->delayed_init_work);
- if (adev->in_s0ix) {
- /* re-enable gfxoff after IP resume. This re-enables gfxoff after
- * it was disabled for IP resume in amdgpu_device_ip_resume_phase2().
- */
- amdgpu_gfx_off_ctrl(adev, true);
- DRM_DEBUG("will enable gfxoff for the mission mode\n");
- }
if (fbcon)
drm_fb_helper_set_suspend_unlocked(adev_to_drm(adev)->fb_helper, false);
@@ -4621,11 +4623,6 @@ bool amdgpu_device_should_recover_gpu(struct amdgpu_device *adev)
if (!amdgpu_ras_is_poison_mode_supported(adev))
return true;
- if (!amdgpu_device_ip_check_soft_reset(adev)) {
- dev_info(adev->dev,"Timeout, but no hardware hang detected.\n");
- return false;
- }
-
if (amdgpu_sriov_vf(adev))
return true;
@@ -4750,7 +4747,8 @@ int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev,
if (!need_full_reset)
need_full_reset = amdgpu_device_ip_need_full_reset(adev);
- if (!need_full_reset && amdgpu_gpu_recovery) {
+ if (!need_full_reset && amdgpu_gpu_recovery &&
+ amdgpu_device_ip_check_soft_reset(adev)) {
amdgpu_device_ip_pre_soft_reset(adev);
r = amdgpu_device_ip_soft_reset(adev);
amdgpu_device_ip_post_soft_reset(adev);
@@ -5876,8 +5874,8 @@ void amdgpu_device_invalidate_hdp(struct amdgpu_device *adev,
int amdgpu_in_reset(struct amdgpu_device *adev)
{
return atomic_read(&adev->reset_domain->in_gpu_reset);
- }
-
+}
+
/**
* amdgpu_device_halt() - bring hardware to some kind of halt state
*
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
index 1bbd56029a4f..b719852daa07 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
@@ -33,6 +33,7 @@
#include "gmc_v9_0.h"
#include "df_v1_7.h"
#include "df_v3_6.h"
+#include "df_v4_3.h"
#include "nbio_v6_1.h"
#include "nbio_v7_0.h"
#include "nbio_v7_4.h"
@@ -2329,6 +2330,9 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev)
case IP_VERSION(3, 5, 2):
adev->df.funcs = &df_v1_7_funcs;
break;
+ case IP_VERSION(4, 3, 0):
+ adev->df.funcs = &df_v4_3_funcs;
+ break;
default:
break;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
index b22471b3bd63..503f89a766c3 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
@@ -42,6 +42,7 @@
#include <drm/drm_fb_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_fourcc.h>
+#include <drm/drm_modeset_helper.h>
#include <drm/drm_vblank.h>
/**
@@ -63,7 +64,7 @@
void amdgpu_display_hotplug_work_func(struct work_struct *work)
{
struct amdgpu_device *adev = container_of(work, struct amdgpu_device,
- hotplug_work);
+ hotplug_work.work);
struct drm_device *dev = adev_to_drm(adev);
struct drm_mode_config *mode_config = &dev->mode_config;
struct drm_connector *connector;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
index 271e30e34d93..0c001bb8fc2b 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
@@ -37,6 +37,7 @@
#include "amdgpu_dma_buf.h"
#include "amdgpu_xgmi.h"
#include <drm/amdgpu_drm.h>
+#include <drm/ttm/ttm_tt.h>
#include <linux/dma-buf.h>
#include <linux/dma-fence-array.h>
#include <linux/pci-p2pdma.h>
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index 3fe277bc233f..f5ffca24def4 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -38,7 +38,6 @@
#include <linux/mmu_notifier.h>
#include <linux/suspend.h>
#include <linux/cc_platform.h>
-#include <linux/fb.h>
#include <linux/dynamic_debug.h>
#include "amdgpu.h"
@@ -104,13 +103,19 @@
* - 3.46.0 - To enable hot plug amdgpu tests in libdrm
* - 3.47.0 - Add AMDGPU_GEM_CREATE_DISCARDABLE and AMDGPU_VM_NOALLOC flags
* - 3.48.0 - Add IP discovery version info to HW INFO
- * 3.49.0 - Add gang submit into CS IOCTL
+ * - 3.49.0 - Add gang submit into CS IOCTL
+ * - 3.50.0 - Update AMDGPU_INFO_DEV_INFO IOCTL for minimum engine and memory clock
+ * Update AMDGPU_INFO_SENSOR IOCTL for PEAK_PSTATE engine and memory clock
+ * 3.51.0 - Return the PCIe gen and lanes from the INFO ioctl
+ * 3.52.0 - Add AMDGPU_IDS_FLAGS_CONFORMANT_TRUNC_COORD, add device_info fields:
+ * tcp_cache_size, num_sqc_per_wgp, sqc_data_cache_size, sqc_inst_cache_size,
+ * gl1c_cache_size, gl2c_cache_size, mall_size, enabled_rb_pipes_mask_hi
*/
#define KMS_DRIVER_MAJOR 3
-#define KMS_DRIVER_MINOR 49
+#define KMS_DRIVER_MINOR 52
#define KMS_DRIVER_PATCHLEVEL 0
-int amdgpu_vram_limit;
+unsigned int amdgpu_vram_limit = UINT_MAX;
int amdgpu_vis_vram_limit;
int amdgpu_gart_size = -1; /* auto */
int amdgpu_gtt_size = -1; /* auto */
@@ -919,7 +924,7 @@ module_param_named(reset_method, amdgpu_reset_method, int, 0444);
* result in the GPU entering bad status when the number of total
* faulty pages by ECC exceeds the threshold value.
*/
-MODULE_PARM_DESC(bad_page_threshold, "Bad page threshold(-1 = auto(default value), 0 = disable bad page retirement, -2 = ignore bad page threshold)");
+MODULE_PARM_DESC(bad_page_threshold, "Bad page threshold(-1 = ignore threshold (default value), 0 = disable bad page retirement, -2 = driver sets threshold)");
module_param_named(bad_page_threshold, amdgpu_bad_page_threshold, int, 0444);
MODULE_PARM_DESC(num_kcq, "number of kernel compute queue user want to setup (8 if set to greater than 8 or less than 0, only affect gfx 8+)");
@@ -2236,6 +2241,8 @@ amdgpu_pci_remove(struct pci_dev *pdev)
struct drm_device *dev = pci_get_drvdata(pdev);
struct amdgpu_device *adev = drm_to_adev(dev);
+ drm_dev_unplug(dev);
+
if (adev->pm.rpm_mode != AMDGPU_RUNPM_NONE) {
pm_runtime_get_sync(dev->dev);
pm_runtime_forbid(dev->dev);
@@ -2275,8 +2282,6 @@ amdgpu_pci_remove(struct pci_dev *pdev)
amdgpu_driver_unload_kms(dev);
- drm_dev_unplug(dev);
-
/*
* Flush any in flight DMA operations from device.
* Clear the Bus Master Enable bit and then wait on the PCIe Device
@@ -2412,8 +2417,10 @@ static int amdgpu_pmops_suspend(struct device *dev)
if (amdgpu_acpi_is_s0ix_active(adev))
adev->in_s0ix = true;
- else
+ else if (amdgpu_acpi_is_s3_active(adev))
adev->in_s3 = true;
+ if (!adev->in_s0ix && !adev->in_s3)
+ return 0;
return amdgpu_device_suspend(drm_dev, true);
}
@@ -2434,6 +2441,9 @@ static int amdgpu_pmops_resume(struct device *dev)
struct amdgpu_device *adev = drm_to_adev(drm_dev);
int r;
+ if (!adev->in_s0ix && !adev->in_s3)
+ return 0;
+
/* Avoids registers access if device is physically gone */
if (!pci_device_is_present(adev->pdev))
adev->no_hw_access = true;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_encoders.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_encoders.c
index c96e458ed088..27a782a9dc72 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_encoders.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_encoders.c
@@ -24,7 +24,6 @@
* Alex Deucher
*/
-#include <drm/drm_crtc_helper.h>
#include <drm/amdgpu_drm.h>
#include "amdgpu.h"
#include "amdgpu_connectors.h"
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.h
index 41a4c7056729..e86834bfea1d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.h
@@ -30,7 +30,6 @@
#include <linux/rbtree.h>
#include <drm/gpu_scheduler.h>
#include <drm/drm_file.h>
-#include <drm/ttm/ttm_bo_driver.h>
#include <linux/sched/mm.h>
#include "amdgpu_sync.h"
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
index bb7350ea1d75..d8e683688daa 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
@@ -34,6 +34,7 @@
#include <drm/amdgpu_drm.h>
#include <drm/drm_drv.h>
#include <drm/drm_gem_ttm_helper.h>
+#include <drm/ttm/ttm_tt.h>
#include "amdgpu.h"
#include "amdgpu_display.h"
@@ -61,10 +62,10 @@ static vm_fault_t amdgpu_gem_fault(struct vm_fault *vmf)
goto unlock;
}
- ret = ttm_bo_vm_fault_reserved(vmf, vmf->vma->vm_page_prot,
- TTM_BO_VM_NUM_PREFAULT);
+ ret = ttm_bo_vm_fault_reserved(vmf, vmf->vma->vm_page_prot,
+ TTM_BO_VM_NUM_PREFAULT);
- drm_dev_exit(idx);
+ drm_dev_exit(idx);
} else {
ret = ttm_bo_vm_dummy_page(vmf, vmf->vma->vm_page_prot);
}
@@ -257,7 +258,7 @@ static int amdgpu_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_str
*/
if (is_cow_mapping(vma->vm_flags) &&
!(vma->vm_flags & VM_ACCESS_FLAGS))
- vma->vm_flags &= ~VM_MAYWRITE;
+ vm_flags_clear(vma, VM_MAYWRITE);
return drm_gem_ttm_mmap(obj, vma);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
index 3380daf42da8..35ed46b9249c 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
@@ -375,8 +375,11 @@ int amdgpu_gfx_mqd_sw_init(struct amdgpu_device *adev,
* KIQ MQD no matter SRIOV or Bare-metal
*/
r = amdgpu_bo_create_kernel(adev, mqd_size, PAGE_SIZE,
- AMDGPU_GEM_DOMAIN_VRAM, &ring->mqd_obj,
- &ring->mqd_gpu_addr, &ring->mqd_ptr);
+ AMDGPU_GEM_DOMAIN_VRAM |
+ AMDGPU_GEM_DOMAIN_GTT,
+ &ring->mqd_obj,
+ &ring->mqd_gpu_addr,
+ &ring->mqd_ptr);
if (r) {
dev_warn(adev->dev, "failed to create ring mqd ob (%d)", r);
return r;
@@ -696,6 +699,50 @@ late_fini:
return r;
}
+int amdgpu_gfx_ras_sw_init(struct amdgpu_device *adev)
+{
+ int err = 0;
+ struct amdgpu_gfx_ras *ras = NULL;
+
+ /* adev->gfx.ras is NULL, which means gfx does not
+ * support ras function, then do nothing here.
+ */
+ if (!adev->gfx.ras)
+ return 0;
+
+ ras = adev->gfx.ras;
+
+ err = amdgpu_ras_register_ras_block(adev, &ras->ras_block);
+ if (err) {
+ dev_err(adev->dev, "Failed to register gfx ras block!\n");
+ return err;
+ }
+
+ strcpy(ras->ras_block.ras_comm.name, "gfx");
+ ras->ras_block.ras_comm.block = AMDGPU_RAS_BLOCK__GFX;
+ ras->ras_block.ras_comm.type = AMDGPU_RAS_ERROR__MULTI_UNCORRECTABLE;
+ adev->gfx.ras_if = &ras->ras_block.ras_comm;
+
+ /* If not define special ras_late_init function, use gfx default ras_late_init */
+ if (!ras->ras_block.ras_late_init)
+ ras->ras_block.ras_late_init = amdgpu_ras_block_late_init;
+
+ /* If not defined special ras_cb function, use default ras_cb */
+ if (!ras->ras_block.ras_cb)
+ ras->ras_block.ras_cb = amdgpu_gfx_process_ras_data_cb;
+
+ return 0;
+}
+
+int amdgpu_gfx_poison_consumption_handler(struct amdgpu_device *adev,
+ struct amdgpu_iv_entry *entry)
+{
+ if (adev->gfx.ras && adev->gfx.ras->poison_consumption_handler)
+ return adev->gfx.ras->poison_consumption_handler(adev, entry);
+
+ return 0;
+}
+
int amdgpu_gfx_process_ras_data_cb(struct amdgpu_device *adev,
void *err_data,
struct amdgpu_iv_entry *entry)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h
index b3df4787877e..de9e7a00bb15 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h
@@ -178,6 +178,8 @@ struct amdgpu_gfx_config {
uint32_t num_sc_per_sh;
uint32_t num_packer_per_sc;
uint32_t pa_sc_tile_steering_override;
+ /* Whether texture coordinate truncation is conformant. */
+ bool ta_cntl2_truncate_coord_mode;
uint64_t tcc_disabled_mask;
uint32_t gc_num_tcp_per_sa;
uint32_t gc_num_sdp_interface;
@@ -210,6 +212,11 @@ struct amdgpu_gfx_ras {
struct amdgpu_ras_block_object ras_block;
void (*enable_watchdog_timer)(struct amdgpu_device *adev);
bool (*query_utcl2_poison_status)(struct amdgpu_device *adev);
+ int (*rlc_gc_fed_irq)(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *source,
+ struct amdgpu_iv_entry *entry);
+ int (*poison_consumption_handler)(struct amdgpu_device *adev,
+ struct amdgpu_iv_entry *entry);
};
struct amdgpu_gfx_funcs {
@@ -323,6 +330,7 @@ struct amdgpu_gfx {
struct amdgpu_irq_src priv_inst_irq;
struct amdgpu_irq_src cp_ecc_error_irq;
struct amdgpu_irq_src sq_irq;
+ struct amdgpu_irq_src rlc_gc_fed_irq;
struct sq_work sq_work;
/* gfx status */
@@ -432,4 +440,7 @@ void amdgpu_kiq_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v);
int amdgpu_gfx_get_num_kcq(struct amdgpu_device *adev);
void amdgpu_gfx_cp_init_microcode(struct amdgpu_device *adev, uint32_t ucode_id);
+int amdgpu_gfx_ras_sw_init(struct amdgpu_device *adev);
+int amdgpu_gfx_poison_consumption_handler(struct amdgpu_device *adev,
+ struct amdgpu_iv_entry *entry);
#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
index 02a4c93673ce..12a6826caef4 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
@@ -35,6 +35,7 @@
#include "amdgpu_xgmi.h"
#include <drm/drm_drv.h>
+#include <drm/ttm/ttm_tt.h>
/**
* amdgpu_gmc_pdb0_alloc - allocate vram for pdb0
@@ -201,13 +202,20 @@ uint64_t amdgpu_gmc_agp_addr(struct ttm_buffer_object *bo)
void amdgpu_gmc_vram_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc,
u64 base)
{
+ uint64_t vis_limit = (uint64_t)amdgpu_vis_vram_limit << 20;
uint64_t limit = (uint64_t)amdgpu_vram_limit << 20;
mc->vram_start = base;
mc->vram_end = mc->vram_start + mc->mc_vram_size - 1;
- if (limit && limit < mc->real_vram_size)
+ if (limit < mc->real_vram_size)
mc->real_vram_size = limit;
+ if (vis_limit && vis_limit < mc->visible_vram_size)
+ mc->visible_vram_size = vis_limit;
+
+ if (mc->real_vram_size < mc->visible_vram_size)
+ mc->visible_vram_size = mc->real_vram_size;
+
if (mc->xgmi.num_physical_nodes == 0) {
mc->fb_start = mc->vram_start;
mc->fb_end = mc->vram_end;
@@ -544,6 +552,7 @@ void amdgpu_gmc_tmz_set(struct amdgpu_device *adev)
case IP_VERSION(10, 3, 2):
case IP_VERSION(10, 3, 4):
case IP_VERSION(10, 3, 5):
+ case IP_VERSION(10, 3, 6):
/* VANGOGH */
case IP_VERSION(10, 3, 1):
/* YELLOW_CARP*/
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
index a6aef488a822..d0a1cc88832c 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
@@ -45,7 +45,6 @@
#include <linux/irq.h>
#include <linux/pci.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_vblank.h>
#include <drm/amdgpu_drm.h>
#include <drm/drm_drv.h>
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
index 7aa7e52ca784..0efb38539d70 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
@@ -43,6 +43,7 @@
#include "amdgpu_gem.h"
#include "amdgpu_display.h"
#include "amdgpu_ras.h"
+#include "amd_pcie.h"
void amdgpu_unregister_gpu_instance(struct amdgpu_device *adev)
{
@@ -767,6 +768,7 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
case AMDGPU_INFO_DEV_INFO: {
struct drm_amdgpu_info_device *dev_info;
uint64_t vm_size;
+ uint32_t pcie_gen_mask;
int ret;
dev_info = kzalloc(sizeof(*dev_info), GFP_KERNEL);
@@ -785,15 +787,20 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
if (adev->pm.dpm_enabled) {
dev_info->max_engine_clock = amdgpu_dpm_get_sclk(adev, false) * 10;
dev_info->max_memory_clock = amdgpu_dpm_get_mclk(adev, false) * 10;
+ dev_info->min_engine_clock = amdgpu_dpm_get_sclk(adev, true) * 10;
+ dev_info->min_memory_clock = amdgpu_dpm_get_mclk(adev, true) * 10;
} else {
- dev_info->max_engine_clock = adev->clock.default_sclk * 10;
- dev_info->max_memory_clock = adev->clock.default_mclk * 10;
+ dev_info->max_engine_clock =
+ dev_info->min_engine_clock =
+ adev->clock.default_sclk * 10;
+ dev_info->max_memory_clock =
+ dev_info->min_memory_clock =
+ adev->clock.default_mclk * 10;
}
dev_info->enabled_rb_pipes_mask = adev->gfx.config.backend_enable_mask;
dev_info->num_rb_pipes = adev->gfx.config.max_backends_per_se *
adev->gfx.config.max_shader_engines;
dev_info->num_hw_gfx_contexts = adev->gfx.config.max_hw_contexts;
- dev_info->_pad = 0;
dev_info->ids_flags = 0;
if (adev->flags & AMD_IS_APU)
dev_info->ids_flags |= AMDGPU_IDS_FLAGS_FUSION;
@@ -801,6 +808,8 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
dev_info->ids_flags |= AMDGPU_IDS_FLAGS_PREEMPTION;
if (amdgpu_is_tmz(adev))
dev_info->ids_flags |= AMDGPU_IDS_FLAGS_TMZ;
+ if (adev->gfx.config.ta_cntl2_truncate_coord_mode)
+ dev_info->ids_flags |= AMDGPU_IDS_FLAGS_CONFORMANT_TRUNC_COORD;
vm_size = adev->vm_manager.max_pfn * AMDGPU_GPU_PAGE_SIZE;
vm_size -= AMDGPU_VA_RESERVED_SIZE;
@@ -847,6 +856,26 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
dev_info->tcc_disabled_mask = adev->gfx.config.tcc_disabled_mask;
+ /* Combine the chip gen mask with the platform (CPU/mobo) mask. */
+ pcie_gen_mask = adev->pm.pcie_gen_mask & (adev->pm.pcie_gen_mask >> 16);
+ dev_info->pcie_gen = fls(pcie_gen_mask);
+ dev_info->pcie_num_lanes =
+ adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X32 ? 32 :
+ adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X16 ? 16 :
+ adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X12 ? 12 :
+ adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 ? 8 :
+ adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 ? 4 :
+ adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 ? 2 : 1;
+
+ dev_info->tcp_cache_size = adev->gfx.config.gc_tcp_l1_size;
+ dev_info->num_sqc_per_wgp = adev->gfx.config.gc_num_sqc_per_wgp;
+ dev_info->sqc_data_cache_size = adev->gfx.config.gc_l1_data_cache_size_per_sqc;
+ dev_info->sqc_inst_cache_size = adev->gfx.config.gc_l1_instruction_cache_size_per_sqc;
+ dev_info->gl1c_cache_size = adev->gfx.config.gc_gl1c_size_per_instance *
+ adev->gfx.config.gc_gl1c_per_sa;
+ dev_info->gl2c_cache_size = adev->gfx.config.gc_gl2c_per_gpu;
+ dev_info->mall_size = adev->gmc.mall_size;
+
ret = copy_to_user(out, dev_info,
min((size_t)size, sizeof(*dev_info))) ? -EFAULT : 0;
kfree(dev_info);
@@ -1014,6 +1043,24 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
}
ui32 /= 100;
break;
+ case AMDGPU_INFO_SENSOR_PEAK_PSTATE_GFX_SCLK:
+ /* get peak pstate sclk in Mhz */
+ if (amdgpu_dpm_read_sensor(adev,
+ AMDGPU_PP_SENSOR_PEAK_PSTATE_SCLK,
+ (void *)&ui32, &ui32_size)) {
+ return -EINVAL;
+ }
+ ui32 /= 100;
+ break;
+ case AMDGPU_INFO_SENSOR_PEAK_PSTATE_GFX_MCLK:
+ /* get peak pstate mclk in Mhz */
+ if (amdgpu_dpm_read_sensor(adev,
+ AMDGPU_PP_SENSOR_PEAK_PSTATE_MCLK,
+ (void *)&ui32, &ui32_size)) {
+ return -EINVAL;
+ }
+ ui32 /= 100;
+ break;
default:
DRM_DEBUG_KMS("Invalid request %d\n",
info->sensor_info.type);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c
index 0c546245793b..82e27bd4f038 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c
@@ -21,6 +21,8 @@
*
*/
+#include <linux/firmware.h>
+
#include "amdgpu_mes.h"
#include "amdgpu.h"
#include "soc15_common.h"
@@ -1423,3 +1425,60 @@ error_pasid:
kfree(vm);
return 0;
}
+
+int amdgpu_mes_init_microcode(struct amdgpu_device *adev, int pipe)
+{
+ const struct mes_firmware_header_v1_0 *mes_hdr;
+ struct amdgpu_firmware_info *info;
+ char ucode_prefix[30];
+ char fw_name[40];
+ int r;
+
+ amdgpu_ucode_ip_version_decode(adev, GC_HWIP, ucode_prefix, sizeof(ucode_prefix));
+ snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mes%s.bin",
+ ucode_prefix,
+ pipe == AMDGPU_MES_SCHED_PIPE ? "" : "1");
+ r = amdgpu_ucode_request(adev, &adev->mes.fw[pipe], fw_name);
+ if (r)
+ goto out;
+
+ mes_hdr = (const struct mes_firmware_header_v1_0 *)
+ adev->mes.fw[pipe]->data;
+ adev->mes.uc_start_addr[pipe] =
+ le32_to_cpu(mes_hdr->mes_uc_start_addr_lo) |
+ ((uint64_t)(le32_to_cpu(mes_hdr->mes_uc_start_addr_hi)) << 32);
+ adev->mes.data_start_addr[pipe] =
+ le32_to_cpu(mes_hdr->mes_data_start_addr_lo) |
+ ((uint64_t)(le32_to_cpu(mes_hdr->mes_data_start_addr_hi)) << 32);
+
+ if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
+ int ucode, ucode_data;
+
+ if (pipe == AMDGPU_MES_SCHED_PIPE) {
+ ucode = AMDGPU_UCODE_ID_CP_MES;
+ ucode_data = AMDGPU_UCODE_ID_CP_MES_DATA;
+ } else {
+ ucode = AMDGPU_UCODE_ID_CP_MES1;
+ ucode_data = AMDGPU_UCODE_ID_CP_MES1_DATA;
+ }
+
+ info = &adev->firmware.ucode[ucode];
+ info->ucode_id = ucode;
+ info->fw = adev->mes.fw[pipe];
+ adev->firmware.fw_size +=
+ ALIGN(le32_to_cpu(mes_hdr->mes_ucode_size_bytes),
+ PAGE_SIZE);
+
+ info = &adev->firmware.ucode[ucode_data];
+ info->ucode_id = ucode_data;
+ info->fw = adev->mes.fw[pipe];
+ adev->firmware.fw_size +=
+ ALIGN(le32_to_cpu(mes_hdr->mes_ucode_data_size_bytes),
+ PAGE_SIZE);
+ }
+
+ return 0;
+out:
+ amdgpu_ucode_release(&adev->mes.fw[pipe]);
+ return r;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h
index 97c05d08a551..547ec35691fa 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h
@@ -306,6 +306,7 @@ struct amdgpu_mes_funcs {
int amdgpu_mes_ctx_get_offs(struct amdgpu_ring *ring, unsigned int id_offs);
+int amdgpu_mes_init_microcode(struct amdgpu_device *adev, int pipe);
int amdgpu_mes_init(struct amdgpu_device *adev);
void amdgpu_mes_fini(struct amdgpu_device *adev);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
index 8a39300b1a84..32fe05c810c6 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
@@ -35,7 +35,6 @@
#include <drm/drm_edid.h>
#include <drm/drm_encoder.h>
#include <drm/drm_fixed.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_probe_helper.h>
#include <linux/i2c.h>
@@ -534,6 +533,7 @@ struct amdgpu_connector {
void *con_priv;
bool dac_load_detect;
bool detected_by_load; /* if the connection status was determined by load */
+ bool detected_hpd_without_ddc; /* if an HPD signal was detected on DVI, but ddc probing failed */
uint16_t connector_object_id;
struct amdgpu_hpd hpd;
struct amdgpu_router router;
@@ -549,8 +549,8 @@ struct amdgpu_mst_connector {
struct drm_dp_mst_topology_mgr mst_mgr;
struct amdgpu_dm_dp_aux dm_dp_aux;
- struct drm_dp_mst_port *port;
- struct amdgpu_connector *mst_port;
+ struct drm_dp_mst_port *mst_output_port;
+ struct amdgpu_connector *mst_root;
bool is_mst_connector;
struct amdgpu_encoder *mst_encoder;
};
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
index 25a68d8888e0..e3e1ed4314dd 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
@@ -139,7 +139,7 @@ void amdgpu_bo_placement_from_domain(struct amdgpu_bo *abo, u32 domain)
if (flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED)
places[c].lpfn = visible_pfn;
- else
+ else if (adev->gmc.real_vram_size != adev->gmc.visible_vram_size)
places[c].flags |= TTM_PL_FLAG_TOPDOWN;
if (flags & AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS)
@@ -1574,9 +1574,9 @@ u64 amdgpu_bo_print_info(int id, struct amdgpu_bo *bo, struct seq_file *m)
attachment = READ_ONCE(bo->tbo.base.import_attach);
if (attachment)
- seq_printf(m, " imported from %p", dma_buf);
+ seq_printf(m, " imported from ino:%lu", file_inode(dma_buf->file)->i_ino);
else if (dma_buf)
- seq_printf(m, " exported as %p", dma_buf);
+ seq_printf(m, " exported as ino:%lu", file_inode(dma_buf->file)->i_ino);
amdgpu_bo_print_flag(m, bo, CPU_ACCESS_REQUIRED);
amdgpu_bo_print_flag(m, bo, NO_CPU_ACCESS);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
index 7a2fc920739b..28fe6d941054 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
@@ -66,7 +66,8 @@ static int psp_ring_init(struct psp_context *psp,
/* allocate 4k Page of Local Frame Buffer memory for ring */
ring->ring_size = 0x1000;
ret = amdgpu_bo_create_kernel(adev, ring->ring_size, PAGE_SIZE,
- AMDGPU_GEM_DOMAIN_VRAM,
+ AMDGPU_GEM_DOMAIN_VRAM |
+ AMDGPU_GEM_DOMAIN_GTT,
&adev->firmware.rbuf,
&ring->ring_mem_mc_addr,
(void **)&ring->ring_mem);
@@ -122,6 +123,38 @@ static void psp_check_pmfw_centralized_cstate_management(struct psp_context *psp
}
}
+static int psp_init_sriov_microcode(struct psp_context *psp)
+{
+ struct amdgpu_device *adev = psp->adev;
+ char ucode_prefix[30];
+ int ret = 0;
+
+ amdgpu_ucode_ip_version_decode(adev, MP0_HWIP, ucode_prefix, sizeof(ucode_prefix));
+
+ switch (adev->ip_versions[MP0_HWIP][0]) {
+ case IP_VERSION(9, 0, 0):
+ case IP_VERSION(11, 0, 7):
+ case IP_VERSION(11, 0, 9):
+ adev->virt.autoload_ucode_id = AMDGPU_UCODE_ID_CP_MEC2;
+ ret = psp_init_cap_microcode(psp, ucode_prefix);
+ break;
+ case IP_VERSION(13, 0, 2):
+ adev->virt.autoload_ucode_id = AMDGPU_UCODE_ID_CP_MEC2;
+ ret = psp_init_cap_microcode(psp, ucode_prefix);
+ ret &= psp_init_ta_microcode(psp, ucode_prefix);
+ break;
+ case IP_VERSION(13, 0, 0):
+ adev->virt.autoload_ucode_id = 0;
+ break;
+ case IP_VERSION(13, 0, 10):
+ adev->virt.autoload_ucode_id = AMDGPU_UCODE_ID_CP_MES1_DATA;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return ret;
+}
+
static int psp_early_init(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
@@ -192,7 +225,10 @@ static int psp_early_init(void *handle)
psp_check_pmfw_centralized_cstate_management(psp);
- return 0;
+ if (amdgpu_sriov_vf(adev))
+ return psp_init_sriov_microcode(psp);
+ else
+ return psp_init_microcode(psp);
}
void psp_ta_free_shared_buf(struct ta_mem_context *mem_ctx)
@@ -300,7 +336,7 @@ static bool psp_get_runtime_db_entry(struct amdgpu_device *adev,
if (db_header.cookie != PSP_RUNTIME_DB_COOKIE_ID) {
/* runtime db doesn't exist, exit */
- dev_warn(adev->dev, "PSP runtime database doesn't exist\n");
+ dev_dbg(adev->dev, "PSP runtime database doesn't exist\n");
return false;
}
@@ -350,42 +386,6 @@ static bool psp_get_runtime_db_entry(struct amdgpu_device *adev,
return ret;
}
-static int psp_init_sriov_microcode(struct psp_context *psp)
-{
- struct amdgpu_device *adev = psp->adev;
- int ret = 0;
-
- switch (adev->ip_versions[MP0_HWIP][0]) {
- case IP_VERSION(9, 0, 0):
- adev->virt.autoload_ucode_id = AMDGPU_UCODE_ID_CP_MEC2;
- ret = psp_init_cap_microcode(psp, "vega10");
- break;
- case IP_VERSION(11, 0, 9):
- adev->virt.autoload_ucode_id = AMDGPU_UCODE_ID_CP_MEC2;
- ret = psp_init_cap_microcode(psp, "navi12");
- break;
- case IP_VERSION(11, 0, 7):
- adev->virt.autoload_ucode_id = AMDGPU_UCODE_ID_CP_MEC2;
- ret = psp_init_cap_microcode(psp, "sienna_cichlid");
- break;
- case IP_VERSION(13, 0, 2):
- adev->virt.autoload_ucode_id = AMDGPU_UCODE_ID_CP_MEC2;
- ret = psp_init_cap_microcode(psp, "aldebaran");
- ret &= psp_init_ta_microcode(psp, "aldebaran");
- break;
- case IP_VERSION(13, 0, 0):
- adev->virt.autoload_ucode_id = 0;
- break;
- case IP_VERSION(13, 0, 10):
- adev->virt.autoload_ucode_id = AMDGPU_UCODE_ID_CP_MES1_DATA;
- break;
- default:
- BUG();
- break;
- }
- return ret;
-}
-
static int psp_sw_init(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
@@ -401,15 +401,6 @@ static int psp_sw_init(void *handle)
ret = -ENOMEM;
}
- if (amdgpu_sriov_vf(adev))
- ret = psp_init_sriov_microcode(psp);
- else
- ret = psp_init_microcode(psp);
- if (ret) {
- DRM_ERROR("Failed to load psp firmware!\n");
- return ret;
- }
-
adev->psp.xgmi_context.supports_extended_data =
!adev->gmc.xgmi.connected_to_cpu &&
adev->ip_versions[MP0_HWIP][0] == IP_VERSION(13, 0, 2);
@@ -514,20 +505,11 @@ static int psp_sw_fini(void *handle)
psp_memory_training_fini(psp);
- release_firmware(psp->sos_fw);
- psp->sos_fw = NULL;
-
- release_firmware(psp->asd_fw);
- psp->asd_fw = NULL;
-
- release_firmware(psp->ta_fw);
- psp->ta_fw = NULL;
-
- release_firmware(psp->cap_fw);
- psp->cap_fw = NULL;
-
- release_firmware(psp->toc_fw);
- psp->toc_fw = NULL;
+ amdgpu_ucode_release(&psp->sos_fw);
+ amdgpu_ucode_release(&psp->asd_fw);
+ amdgpu_ucode_release(&psp->ta_fw);
+ amdgpu_ucode_release(&psp->cap_fw);
+ amdgpu_ucode_release(&psp->toc_fw);
if (adev->ip_versions[MP0_HWIP][0] == IP_VERSION(11, 0, 0) ||
adev->ip_versions[MP0_HWIP][0] == IP_VERSION(11, 0, 7))
@@ -624,12 +606,22 @@ psp_cmd_submit_buf(struct psp_context *psp,
int timeout = 20000;
bool ras_intr = false;
bool skip_unsupport = false;
+ bool dev_entered;
if (psp->adev->no_hw_access)
return 0;
- if (!drm_dev_enter(adev_to_drm(psp->adev), &idx))
- return 0;
+ dev_entered = drm_dev_enter(adev_to_drm(psp->adev), &idx);
+ /*
+ * We allow sending PSP messages LOAD_ASD and UNLOAD_TA without acquiring
+ * a lock in drm_dev_enter during driver unload because we must call
+ * drm_dev_unplug as the beginning of unload driver sequence . It is very
+ * crucial that userspace can't access device instances anymore.
+ */
+ if (!dev_entered)
+ WARN_ON(psp->cmd_buf_mem->cmd_id != GFX_CMD_ID_LOAD_ASD &&
+ psp->cmd_buf_mem->cmd_id != GFX_CMD_ID_UNLOAD_TA &&
+ psp->cmd_buf_mem->cmd_id != GFX_CMD_ID_INVOKE_CMD);
memset(psp->cmd_buf_mem, 0, PSP_CMD_BUFFER_SIZE);
@@ -694,7 +686,8 @@ psp_cmd_submit_buf(struct psp_context *psp,
}
exit:
- drm_dev_exit(idx);
+ if (dev_entered)
+ drm_dev_exit(idx);
return ret;
}
@@ -797,9 +790,13 @@ static int psp_tmr_init(struct psp_context *psp)
if (!psp->tmr_bo) {
pptr = amdgpu_sriov_vf(psp->adev) ? &tmr_buf : NULL;
- ret = amdgpu_bo_create_kernel(psp->adev, tmr_size, PSP_TMR_ALIGNMENT,
- AMDGPU_GEM_DOMAIN_VRAM,
- &psp->tmr_bo, &psp->tmr_mc_addr, pptr);
+ ret = amdgpu_bo_create_kernel(psp->adev, tmr_size,
+ PSP_TMR_ALIGNMENT,
+ AMDGPU_HAS_VRAM(psp->adev) ?
+ AMDGPU_GEM_DOMAIN_VRAM :
+ AMDGPU_GEM_DOMAIN_GTT,
+ &psp->tmr_bo, &psp->tmr_mc_addr,
+ pptr);
}
return ret;
@@ -1092,7 +1089,8 @@ int psp_ta_init_shared_buf(struct psp_context *psp,
* physical) for ta to host memory
*/
return amdgpu_bo_create_kernel(psp->adev, mem_ctx->shared_mem_size,
- PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM,
+ PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM |
+ AMDGPU_GEM_DOMAIN_GTT,
&mem_ctx->shared_bo,
&mem_ctx->shared_mc_addr,
&mem_ctx->shared_buf);
@@ -1685,7 +1683,7 @@ static int psp_hdcp_initialize(struct psp_context *psp)
psp->hdcp_context.context.mem_context.shared_mem_size = PSP_HDCP_SHARED_MEM_SIZE;
psp->hdcp_context.context.ta_load_type = GFX_CMD_ID_LOAD_TA;
- if (!psp->hdcp_context.context.initialized) {
+ if (!psp->hdcp_context.context.mem_context.shared_buf) {
ret = psp_ta_init_shared_buf(psp, &psp->hdcp_context.context.mem_context);
if (ret)
return ret;
@@ -1752,7 +1750,7 @@ static int psp_dtm_initialize(struct psp_context *psp)
psp->dtm_context.context.mem_context.shared_mem_size = PSP_DTM_SHARED_MEM_SIZE;
psp->dtm_context.context.ta_load_type = GFX_CMD_ID_LOAD_TA;
- if (!psp->dtm_context.context.initialized) {
+ if (!psp->dtm_context.context.mem_context.shared_buf) {
ret = psp_ta_init_shared_buf(psp, &psp->dtm_context.context.mem_context);
if (ret)
return ret;
@@ -1820,7 +1818,7 @@ static int psp_rap_initialize(struct psp_context *psp)
psp->rap_context.context.mem_context.shared_mem_size = PSP_RAP_SHARED_MEM_SIZE;
psp->rap_context.context.ta_load_type = GFX_CMD_ID_LOAD_TA;
- if (!psp->rap_context.context.initialized) {
+ if (!psp->rap_context.context.mem_context.shared_buf) {
ret = psp_ta_init_shared_buf(psp, &psp->rap_context.context.mem_context);
if (ret)
return ret;
@@ -1901,7 +1899,7 @@ out_unlock:
static int psp_securedisplay_initialize(struct psp_context *psp)
{
int ret;
- struct securedisplay_cmd *securedisplay_cmd;
+ struct ta_securedisplay_cmd *securedisplay_cmd;
/*
* TODO: bypass the initialize in sriov for now
@@ -2908,25 +2906,15 @@ int psp_ring_cmd_submit(struct psp_context *psp,
return 0;
}
-int psp_init_asd_microcode(struct psp_context *psp,
- const char *chip_name)
+int psp_init_asd_microcode(struct psp_context *psp, const char *chip_name)
{
struct amdgpu_device *adev = psp->adev;
char fw_name[PSP_FW_NAME_LEN];
const struct psp_firmware_header_v1_0 *asd_hdr;
int err = 0;
- if (!chip_name) {
- dev_err(adev->dev, "invalid chip name for asd microcode\n");
- return -EINVAL;
- }
-
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_asd.bin", chip_name);
- err = request_firmware(&adev->psp.asd_fw, fw_name, adev->dev);
- if (err)
- goto out;
-
- err = amdgpu_ucode_validate(adev->psp.asd_fw);
+ err = amdgpu_ucode_request(adev, &adev->psp.asd_fw, fw_name);
if (err)
goto out;
@@ -2938,31 +2926,19 @@ int psp_init_asd_microcode(struct psp_context *psp,
le32_to_cpu(asd_hdr->header.ucode_array_offset_bytes);
return 0;
out:
- dev_err(adev->dev, "fail to initialize asd microcode\n");
- release_firmware(adev->psp.asd_fw);
- adev->psp.asd_fw = NULL;
+ amdgpu_ucode_release(&adev->psp.asd_fw);
return err;
}
-int psp_init_toc_microcode(struct psp_context *psp,
- const char *chip_name)
+int psp_init_toc_microcode(struct psp_context *psp, const char *chip_name)
{
struct amdgpu_device *adev = psp->adev;
char fw_name[PSP_FW_NAME_LEN];
const struct psp_firmware_header_v1_0 *toc_hdr;
int err = 0;
- if (!chip_name) {
- dev_err(adev->dev, "invalid chip name for toc microcode\n");
- return -EINVAL;
- }
-
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_toc.bin", chip_name);
- err = request_firmware(&adev->psp.toc_fw, fw_name, adev->dev);
- if (err)
- goto out;
-
- err = amdgpu_ucode_validate(adev->psp.toc_fw);
+ err = amdgpu_ucode_request(adev, &adev->psp.toc_fw, fw_name);
if (err)
goto out;
@@ -2974,9 +2950,7 @@ int psp_init_toc_microcode(struct psp_context *psp,
le32_to_cpu(toc_hdr->header.ucode_array_offset_bytes);
return 0;
out:
- dev_err(adev->dev, "fail to request/validate toc microcode\n");
- release_firmware(adev->psp.toc_fw);
- adev->psp.toc_fw = NULL;
+ amdgpu_ucode_release(&adev->psp.toc_fw);
return err;
}
@@ -3107,8 +3081,7 @@ static int psp_init_sos_base_fw(struct amdgpu_device *adev)
return 0;
}
-int psp_init_sos_microcode(struct psp_context *psp,
- const char *chip_name)
+int psp_init_sos_microcode(struct psp_context *psp, const char *chip_name)
{
struct amdgpu_device *adev = psp->adev;
char fw_name[PSP_FW_NAME_LEN];
@@ -3121,17 +3094,8 @@ int psp_init_sos_microcode(struct psp_context *psp,
uint8_t *ucode_array_start_addr;
int fw_index = 0;
- if (!chip_name) {
- dev_err(adev->dev, "invalid chip name for sos microcode\n");
- return -EINVAL;
- }
-
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sos.bin", chip_name);
- err = request_firmware(&adev->psp.sos_fw, fw_name, adev->dev);
- if (err)
- goto out;
-
- err = amdgpu_ucode_validate(adev->psp.sos_fw);
+ err = amdgpu_ucode_request(adev, &adev->psp.sos_fw, fw_name);
if (err)
goto out;
@@ -3203,10 +3167,7 @@ int psp_init_sos_microcode(struct psp_context *psp,
return 0;
out:
- dev_err(adev->dev,
- "failed to init sos firmware\n");
- release_firmware(adev->psp.sos_fw);
- adev->psp.sos_fw = NULL;
+ amdgpu_ucode_release(&adev->psp.sos_fw);
return err;
}
@@ -3272,41 +3233,76 @@ static int parse_ta_bin_descriptor(struct psp_context *psp,
return 0;
}
-int psp_init_ta_microcode(struct psp_context *psp,
- const char *chip_name)
+static int parse_ta_v1_microcode(struct psp_context *psp)
{
+ const struct ta_firmware_header_v1_0 *ta_hdr;
struct amdgpu_device *adev = psp->adev;
- char fw_name[PSP_FW_NAME_LEN];
- const struct ta_firmware_header_v2_0 *ta_hdr;
- int err = 0;
- int ta_index = 0;
- if (!chip_name) {
- dev_err(adev->dev, "invalid chip name for ta microcode\n");
+ ta_hdr = (const struct ta_firmware_header_v1_0 *) adev->psp.ta_fw->data;
+
+ if (le16_to_cpu(ta_hdr->header.header_version_major) != 1)
return -EINVAL;
- }
- snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ta.bin", chip_name);
- err = request_firmware(&adev->psp.ta_fw, fw_name, adev->dev);
- if (err)
- goto out;
+ adev->psp.xgmi_context.context.bin_desc.fw_version =
+ le32_to_cpu(ta_hdr->xgmi.fw_version);
+ adev->psp.xgmi_context.context.bin_desc.size_bytes =
+ le32_to_cpu(ta_hdr->xgmi.size_bytes);
+ adev->psp.xgmi_context.context.bin_desc.start_addr =
+ (uint8_t *)ta_hdr +
+ le32_to_cpu(ta_hdr->header.ucode_array_offset_bytes);
+
+ adev->psp.ras_context.context.bin_desc.fw_version =
+ le32_to_cpu(ta_hdr->ras.fw_version);
+ adev->psp.ras_context.context.bin_desc.size_bytes =
+ le32_to_cpu(ta_hdr->ras.size_bytes);
+ adev->psp.ras_context.context.bin_desc.start_addr =
+ (uint8_t *)adev->psp.xgmi_context.context.bin_desc.start_addr +
+ le32_to_cpu(ta_hdr->ras.offset_bytes);
+
+ adev->psp.hdcp_context.context.bin_desc.fw_version =
+ le32_to_cpu(ta_hdr->hdcp.fw_version);
+ adev->psp.hdcp_context.context.bin_desc.size_bytes =
+ le32_to_cpu(ta_hdr->hdcp.size_bytes);
+ adev->psp.hdcp_context.context.bin_desc.start_addr =
+ (uint8_t *)ta_hdr +
+ le32_to_cpu(ta_hdr->header.ucode_array_offset_bytes);
+
+ adev->psp.dtm_context.context.bin_desc.fw_version =
+ le32_to_cpu(ta_hdr->dtm.fw_version);
+ adev->psp.dtm_context.context.bin_desc.size_bytes =
+ le32_to_cpu(ta_hdr->dtm.size_bytes);
+ adev->psp.dtm_context.context.bin_desc.start_addr =
+ (uint8_t *)adev->psp.hdcp_context.context.bin_desc.start_addr +
+ le32_to_cpu(ta_hdr->dtm.offset_bytes);
+
+ adev->psp.securedisplay_context.context.bin_desc.fw_version =
+ le32_to_cpu(ta_hdr->securedisplay.fw_version);
+ adev->psp.securedisplay_context.context.bin_desc.size_bytes =
+ le32_to_cpu(ta_hdr->securedisplay.size_bytes);
+ adev->psp.securedisplay_context.context.bin_desc.start_addr =
+ (uint8_t *)adev->psp.hdcp_context.context.bin_desc.start_addr +
+ le32_to_cpu(ta_hdr->securedisplay.offset_bytes);
+
+ adev->psp.ta_fw_version = le32_to_cpu(ta_hdr->header.ucode_version);
- err = amdgpu_ucode_validate(adev->psp.ta_fw);
- if (err)
- goto out;
+ return 0;
+}
+
+static int parse_ta_v2_microcode(struct psp_context *psp)
+{
+ const struct ta_firmware_header_v2_0 *ta_hdr;
+ struct amdgpu_device *adev = psp->adev;
+ int err = 0;
+ int ta_index = 0;
ta_hdr = (const struct ta_firmware_header_v2_0 *)adev->psp.ta_fw->data;
- if (le16_to_cpu(ta_hdr->header.header_version_major) != 2) {
- dev_err(adev->dev, "unsupported TA header version\n");
- err = -EINVAL;
- goto out;
- }
+ if (le16_to_cpu(ta_hdr->header.header_version_major) != 2)
+ return -EINVAL;
if (le32_to_cpu(ta_hdr->ta_fw_bin_count) >= UCODE_MAX_PSP_PACKAGING) {
dev_err(adev->dev, "packed TA count exceeds maximum limit\n");
- err = -EINVAL;
- goto out;
+ return -EINVAL;
}
for (ta_index = 0; ta_index < le32_to_cpu(ta_hdr->ta_fw_bin_count); ta_index++) {
@@ -3314,19 +3310,44 @@ int psp_init_ta_microcode(struct psp_context *psp,
&ta_hdr->ta_fw_bin[ta_index],
ta_hdr);
if (err)
- goto out;
+ return err;
}
return 0;
-out:
- dev_err(adev->dev, "fail to initialize ta microcode\n");
- release_firmware(adev->psp.ta_fw);
- adev->psp.ta_fw = NULL;
+}
+
+int psp_init_ta_microcode(struct psp_context *psp, const char *chip_name)
+{
+ const struct common_firmware_header *hdr;
+ struct amdgpu_device *adev = psp->adev;
+ char fw_name[PSP_FW_NAME_LEN];
+ int err;
+
+ snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ta.bin", chip_name);
+ err = amdgpu_ucode_request(adev, &adev->psp.ta_fw, fw_name);
+ if (err)
+ return err;
+
+ hdr = (const struct common_firmware_header *)adev->psp.ta_fw->data;
+ switch (le16_to_cpu(hdr->header_version_major)) {
+ case 1:
+ err = parse_ta_v1_microcode(psp);
+ break;
+ case 2:
+ err = parse_ta_v2_microcode(psp);
+ break;
+ default:
+ dev_err(adev->dev, "unsupported TA header version\n");
+ err = -EINVAL;
+ }
+
+ if (err)
+ amdgpu_ucode_release(&adev->psp.ta_fw);
+
return err;
}
-int psp_init_cap_microcode(struct psp_context *psp,
- const char *chip_name)
+int psp_init_cap_microcode(struct psp_context *psp, const char *chip_name)
{
struct amdgpu_device *adev = psp->adev;
char fw_name[PSP_FW_NAME_LEN];
@@ -3334,28 +3355,20 @@ int psp_init_cap_microcode(struct psp_context *psp,
struct amdgpu_firmware_info *info = NULL;
int err = 0;
- if (!chip_name) {
- dev_err(adev->dev, "invalid chip name for cap microcode\n");
- return -EINVAL;
- }
-
if (!amdgpu_sriov_vf(adev)) {
dev_err(adev->dev, "cap microcode should only be loaded under SRIOV\n");
return -EINVAL;
}
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_cap.bin", chip_name);
- err = request_firmware(&adev->psp.cap_fw, fw_name, adev->dev);
- if (err) {
- dev_warn(adev->dev, "cap microcode does not exist, skip\n");
- err = 0;
- goto out;
- }
-
- err = amdgpu_ucode_validate(adev->psp.cap_fw);
+ err = amdgpu_ucode_request(adev, &adev->psp.cap_fw, fw_name);
if (err) {
+ if (err == -ENODEV) {
+ dev_warn(adev->dev, "cap microcode does not exist, skip\n");
+ err = 0;
+ goto out;
+ }
dev_err(adev->dev, "fail to initialize cap microcode\n");
- goto out;
}
info = &adev->firmware.ucode[AMDGPU_UCODE_ID_CAP];
@@ -3372,8 +3385,7 @@ int psp_init_cap_microcode(struct psp_context *psp,
return 0;
out:
- release_firmware(adev->psp.cap_fw);
- adev->psp.cap_fw = NULL;
+ amdgpu_ucode_release(&adev->psp.cap_fw);
return err;
}
@@ -3444,10 +3456,10 @@ static ssize_t psp_usbc_pd_fw_sysfs_write(struct device *dev,
/* LFB address which is aligned to 1MB boundary per PSP request */
ret = amdgpu_bo_create_kernel(adev, usbc_pd_fw->size, 0x100000,
- AMDGPU_GEM_DOMAIN_VRAM,
- &fw_buf_bo,
- &fw_pri_mc_addr,
- &fw_pri_cpu_addr);
+ AMDGPU_GEM_DOMAIN_VRAM |
+ AMDGPU_GEM_DOMAIN_GTT,
+ &fw_buf_bo, &fw_pri_mc_addr,
+ &fw_pri_cpu_addr);
if (ret)
goto rel_buf;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
index ad490c1e2f57..63dfcc98152d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
@@ -176,7 +176,7 @@ static int amdgpu_reserve_page_direct(struct amdgpu_device *adev, uint64_t addre
if (amdgpu_bad_page_threshold != 0) {
amdgpu_ras_add_bad_pages(adev, err_data.err_addr,
err_data.err_addr_cnt);
- amdgpu_ras_save_bad_pages(adev);
+ amdgpu_ras_save_bad_pages(adev, NULL);
}
dev_warn(adev->dev, "WARNING: THIS IS ONLY FOR TEST PURPOSES AND WILL CORRUPT RAS EEPROM\n");
@@ -706,13 +706,23 @@ static int __amdgpu_ras_feature_enable(struct amdgpu_device *adev,
return 0;
}
+static int amdgpu_ras_check_feature_allowed(struct amdgpu_device *adev,
+ struct ras_common_if *head)
+{
+ if (amdgpu_ras_is_feature_allowed(adev, head) ||
+ amdgpu_ras_is_poison_mode_supported(adev))
+ return 1;
+ else
+ return 0;
+}
+
/* wrapper of psp_ras_enable_features */
int amdgpu_ras_feature_enable(struct amdgpu_device *adev,
struct ras_common_if *head, bool enable)
{
struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
union ta_ras_cmd_input *info;
- int ret;
+ int ret = 0;
if (!con)
return -EINVAL;
@@ -736,7 +746,8 @@ int amdgpu_ras_feature_enable(struct amdgpu_device *adev,
}
/* Do not enable if it is not allowed. */
- WARN_ON(enable && !amdgpu_ras_is_feature_allowed(adev, head));
+ if (enable && !amdgpu_ras_check_feature_allowed(adev, head))
+ goto out;
/* Only enable ras feature operation handle on host side */
if (head->block == AMDGPU_RAS_BLOCK__GFX &&
@@ -754,7 +765,6 @@ int amdgpu_ras_feature_enable(struct amdgpu_device *adev,
/* setup the obj */
__amdgpu_ras_feature_enable(adev, head, enable);
- ret = 0;
out:
if (head->block == AMDGPU_RAS_BLOCK__GFX)
kfree(info);
@@ -910,9 +920,6 @@ static struct amdgpu_ras_block_object *amdgpu_ras_get_ras_block(struct amdgpu_de
if (block >= AMDGPU_RAS_BLOCK__LAST)
return NULL;
- if (!amdgpu_ras_is_supported(adev, block))
- return NULL;
-
list_for_each_entry_safe(node, tmp, &adev->ras_list, node) {
if (!node->ras_obj) {
dev_warn(adev->dev, "Warning: abnormal ras list node.\n");
@@ -1087,6 +1094,10 @@ int amdgpu_ras_error_inject(struct amdgpu_device *adev,
info->head.block,
info->head.sub_block_index);
+ /* inject on guest isn't allowed, return success directly */
+ if (amdgpu_sriov_vf(adev))
+ return 0;
+
if (!obj)
return -EINVAL;
@@ -1122,11 +1133,54 @@ int amdgpu_ras_error_inject(struct amdgpu_device *adev,
}
/**
- * amdgpu_ras_query_error_count -- Get error counts of all IPs
+ * amdgpu_ras_query_error_count_helper -- Get error counter for specific IP
+ * @adev: pointer to AMD GPU device
+ * @ce_count: pointer to an integer to be set to the count of correctible errors.
+ * @ue_count: pointer to an integer to be set to the count of uncorrectible errors.
+ * @query_info: pointer to ras_query_if
+ *
+ * Return 0 for query success or do nothing, otherwise return an error
+ * on failures
+ */
+static int amdgpu_ras_query_error_count_helper(struct amdgpu_device *adev,
+ unsigned long *ce_count,
+ unsigned long *ue_count,
+ struct ras_query_if *query_info)
+{
+ int ret;
+
+ if (!query_info)
+ /* do nothing if query_info is not specified */
+ return 0;
+
+ ret = amdgpu_ras_query_error_status(adev, query_info);
+ if (ret)
+ return ret;
+
+ *ce_count += query_info->ce_count;
+ *ue_count += query_info->ue_count;
+
+ /* some hardware/IP supports read to clear
+ * no need to explictly reset the err status after the query call */
+ if (adev->ip_versions[MP0_HWIP][0] != IP_VERSION(11, 0, 2) &&
+ adev->ip_versions[MP0_HWIP][0] != IP_VERSION(11, 0, 4)) {
+ if (amdgpu_ras_reset_error_status(adev, query_info->head.block))
+ dev_warn(adev->dev,
+ "Failed to reset error counter and error status\n");
+ }
+
+ return 0;
+}
+
+/**
+ * amdgpu_ras_query_error_count -- Get error counts of all IPs or specific IP
* @adev: pointer to AMD GPU device
* @ce_count: pointer to an integer to be set to the count of correctible errors.
* @ue_count: pointer to an integer to be set to the count of uncorrectible
* errors.
+ * @query_info: pointer to ras_query_if if the query request is only for
+ * specific ip block; if info is NULL, then the qurey request is for
+ * all the ip blocks that support query ras error counters/status
*
* If set, @ce_count or @ue_count, count and return the corresponding
* error counts in those integer pointers. Return 0 if the device
@@ -1134,11 +1188,13 @@ int amdgpu_ras_error_inject(struct amdgpu_device *adev,
*/
int amdgpu_ras_query_error_count(struct amdgpu_device *adev,
unsigned long *ce_count,
- unsigned long *ue_count)
+ unsigned long *ue_count,
+ struct ras_query_if *query_info)
{
struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
struct ras_manager *obj;
unsigned long ce, ue;
+ int ret;
if (!adev->ras_enabled || !con)
return -EOPNOTSUPP;
@@ -1150,26 +1206,23 @@ int amdgpu_ras_query_error_count(struct amdgpu_device *adev,
ce = 0;
ue = 0;
- list_for_each_entry(obj, &con->head, node) {
- struct ras_query_if info = {
- .head = obj->head,
- };
- int res;
-
- res = amdgpu_ras_query_error_status(adev, &info);
- if (res)
- return res;
+ if (!query_info) {
+ /* query all the ip blocks that support ras query interface */
+ list_for_each_entry(obj, &con->head, node) {
+ struct ras_query_if info = {
+ .head = obj->head,
+ };
- if (adev->ip_versions[MP0_HWIP][0] != IP_VERSION(11, 0, 2) &&
- adev->ip_versions[MP0_HWIP][0] != IP_VERSION(11, 0, 4)) {
- if (amdgpu_ras_reset_error_status(adev, info.head.block))
- dev_warn(adev->dev, "Failed to reset error counter and error status");
+ ret = amdgpu_ras_query_error_count_helper(adev, &ce, &ue, &info);
}
-
- ce += info.ce_count;
- ue += info.ue_count;
+ } else {
+ /* query specific ip block */
+ ret = amdgpu_ras_query_error_count_helper(adev, &ce, &ue, query_info);
}
+ if (ret)
+ return ret;
+
if (ce_count)
*ce_count = ce;
@@ -1564,14 +1617,14 @@ static void amdgpu_ras_interrupt_poison_consumption_handler(struct ras_manager *
struct amdgpu_ras_block_object *block_obj =
amdgpu_ras_get_ras_block(adev, obj->head.block, 0);
- if (!block_obj || !block_obj->hw_ops)
+ if (!block_obj)
return;
/* both query_poison_status and handle_poison_consumption are optional,
* but at least one of them should be implemented if we need poison
* consumption handler
*/
- if (block_obj->hw_ops->query_poison_status) {
+ if (block_obj->hw_ops && block_obj->hw_ops->query_poison_status) {
poison_stat = block_obj->hw_ops->query_poison_status(adev);
if (!poison_stat) {
/* Not poison consumption interrupt, no need to handle it */
@@ -1585,7 +1638,7 @@ static void amdgpu_ras_interrupt_poison_consumption_handler(struct ras_manager *
if (!adev->gmc.xgmi.connected_to_cpu)
amdgpu_umc_poison_handler(adev, false);
- if (block_obj->hw_ops->handle_poison_consumption)
+ if (block_obj->hw_ops && block_obj->hw_ops->handle_poison_consumption)
poison_stat = block_obj->hw_ops->handle_poison_consumption(adev);
/* gpu reset is fallback for failed and default cases */
@@ -1593,6 +1646,8 @@ static void amdgpu_ras_interrupt_poison_consumption_handler(struct ras_manager *
dev_info(adev->dev, "GPU reset for %s RAS poison consumption is issued!\n",
block_obj->ras_comm.name);
amdgpu_ras_reset_gpu(adev);
+ } else {
+ amdgpu_gfx_poison_consumption_handler(adev, entry);
}
}
@@ -2029,22 +2084,32 @@ out:
/*
* write error record array to eeprom, the function should be
* protected by recovery_lock
+ * new_cnt: new added UE count, excluding reserved bad pages, can be NULL
*/
-int amdgpu_ras_save_bad_pages(struct amdgpu_device *adev)
+int amdgpu_ras_save_bad_pages(struct amdgpu_device *adev,
+ unsigned long *new_cnt)
{
struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
struct ras_err_handler_data *data;
struct amdgpu_ras_eeprom_control *control;
int save_count;
- if (!con || !con->eh_data)
+ if (!con || !con->eh_data) {
+ if (new_cnt)
+ *new_cnt = 0;
+
return 0;
+ }
mutex_lock(&con->recovery_lock);
control = &con->eeprom_control;
data = con->eh_data;
save_count = data->count - control->ras_num_recs;
mutex_unlock(&con->recovery_lock);
+
+ if (new_cnt)
+ *new_cnt = save_count / adev->umc.retire_unit;
+
/* only new entries are saved */
if (save_count > 0) {
if (amdgpu_ras_eeprom_append(control,
@@ -2131,11 +2196,12 @@ static void amdgpu_ras_validate_threshold(struct amdgpu_device *adev,
/*
* Justification of value bad_page_cnt_threshold in ras structure
*
- * Generally, -1 <= amdgpu_bad_page_threshold <= max record length
- * in eeprom, and introduce two scenarios accordingly.
+ * Generally, 0 <= amdgpu_bad_page_threshold <= max record length
+ * in eeprom or amdgpu_bad_page_threshold == -2, introduce two
+ * scenarios accordingly.
*
* Bad page retirement enablement:
- * - If amdgpu_bad_page_threshold = -1,
+ * - If amdgpu_bad_page_threshold = -2,
* bad_page_cnt_threshold = typical value by formula.
*
* - When the value from user is 0 < amdgpu_bad_page_threshold <
@@ -2344,22 +2410,24 @@ static void amdgpu_ras_check_supported(struct amdgpu_device *adev)
if (amdgpu_atomfirmware_sram_ecc_supported(adev)) {
dev_info(adev->dev, "SRAM ECC is active.\n");
- if (!amdgpu_sriov_vf(adev)) {
+ if (!amdgpu_sriov_vf(adev))
adev->ras_hw_enabled |= ~(1 << AMDGPU_RAS_BLOCK__UMC |
1 << AMDGPU_RAS_BLOCK__DF);
-
- if (adev->ip_versions[VCN_HWIP][0] == IP_VERSION(2, 6, 0) ||
- adev->ip_versions[VCN_HWIP][0] == IP_VERSION(4, 0, 0))
- adev->ras_hw_enabled |= (1 << AMDGPU_RAS_BLOCK__VCN |
- 1 << AMDGPU_RAS_BLOCK__JPEG);
- else
- adev->ras_hw_enabled &= ~(1 << AMDGPU_RAS_BLOCK__VCN |
- 1 << AMDGPU_RAS_BLOCK__JPEG);
- } else {
+ else
adev->ras_hw_enabled |= (1 << AMDGPU_RAS_BLOCK__PCIE_BIF |
1 << AMDGPU_RAS_BLOCK__SDMA |
1 << AMDGPU_RAS_BLOCK__GFX);
- }
+
+ /* VCN/JPEG RAS can be supported on both bare metal and
+ * SRIOV environment
+ */
+ if (adev->ip_versions[VCN_HWIP][0] == IP_VERSION(2, 6, 0) ||
+ adev->ip_versions[VCN_HWIP][0] == IP_VERSION(4, 0, 0))
+ adev->ras_hw_enabled |= (1 << AMDGPU_RAS_BLOCK__VCN |
+ 1 << AMDGPU_RAS_BLOCK__JPEG);
+ else
+ adev->ras_hw_enabled &= ~(1 << AMDGPU_RAS_BLOCK__VCN |
+ 1 << AMDGPU_RAS_BLOCK__JPEG);
} else {
dev_info(adev->dev, "SRAM ECC is not presented.\n");
}
@@ -2395,7 +2463,7 @@ static void amdgpu_ras_counte_dw(struct work_struct *work)
/* Cache new values.
*/
- if (amdgpu_ras_query_error_count(adev, &ce_count, &ue_count) == 0) {
+ if (amdgpu_ras_query_error_count(adev, &ce_count, &ue_count, NULL) == 0) {
atomic_set(&con->ras_ce_count, ce_count);
atomic_set(&con->ras_ue_count, ue_count);
}
@@ -2405,11 +2473,42 @@ Out:
pm_runtime_put_autosuspend(dev->dev);
}
+static void amdgpu_ras_query_poison_mode(struct amdgpu_device *adev)
+{
+ struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
+ bool df_poison, umc_poison;
+
+ /* poison setting is useless on SRIOV guest */
+ if (amdgpu_sriov_vf(adev) || !con)
+ return;
+
+ /* Init poison supported flag, the default value is false */
+ if (adev->gmc.xgmi.connected_to_cpu) {
+ /* enabled by default when GPU is connected to CPU */
+ con->poison_supported = true;
+ } else if (adev->df.funcs &&
+ adev->df.funcs->query_ras_poison_mode &&
+ adev->umc.ras &&
+ adev->umc.ras->query_ras_poison_mode) {
+ df_poison =
+ adev->df.funcs->query_ras_poison_mode(adev);
+ umc_poison =
+ adev->umc.ras->query_ras_poison_mode(adev);
+
+ /* Only poison is set in both DF and UMC, we can support it */
+ if (df_poison && umc_poison)
+ con->poison_supported = true;
+ else if (df_poison != umc_poison)
+ dev_warn(adev->dev,
+ "Poison setting is inconsistent in DF/UMC(%d:%d)!\n",
+ df_poison, umc_poison);
+ }
+}
+
int amdgpu_ras_init(struct amdgpu_device *adev)
{
struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
int r;
- bool df_poison, umc_poison;
if (con)
return 0;
@@ -2484,26 +2583,7 @@ int amdgpu_ras_init(struct amdgpu_device *adev)
goto release_con;
}
- /* Init poison supported flag, the default value is false */
- if (adev->gmc.xgmi.connected_to_cpu) {
- /* enabled by default when GPU is connected to CPU */
- con->poison_supported = true;
- }
- else if (adev->df.funcs &&
- adev->df.funcs->query_ras_poison_mode &&
- adev->umc.ras &&
- adev->umc.ras->query_ras_poison_mode) {
- df_poison =
- adev->df.funcs->query_ras_poison_mode(adev);
- umc_poison =
- adev->umc.ras->query_ras_poison_mode(adev);
- /* Only poison is set in both DF and UMC, we can support it */
- if (df_poison && umc_poison)
- con->poison_supported = true;
- else if (df_poison != umc_poison)
- dev_warn(adev->dev, "Poison setting is inconsistent in DF/UMC(%d:%d)!\n",
- df_poison, umc_poison);
- }
+ amdgpu_ras_query_poison_mode(adev);
if (amdgpu_ras_fs_init(adev)) {
r = -EINVAL;
@@ -2564,6 +2644,7 @@ int amdgpu_ras_block_late_init(struct amdgpu_device *adev,
{
struct amdgpu_ras_block_object *ras_obj = NULL;
struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
+ struct ras_query_if *query_info;
unsigned long ue_count, ce_count;
int r;
@@ -2605,11 +2686,17 @@ int amdgpu_ras_block_late_init(struct amdgpu_device *adev,
/* Those are the cached values at init.
*/
- if (amdgpu_ras_query_error_count(adev, &ce_count, &ue_count) == 0) {
+ query_info = kzalloc(sizeof(struct ras_query_if), GFP_KERNEL);
+ if (!query_info)
+ return -ENOMEM;
+ memcpy(&query_info->head, ras_block, sizeof(struct ras_common_if));
+
+ if (amdgpu_ras_query_error_count(adev, &ce_count, &ue_count, query_info) == 0) {
atomic_set(&con->ras_ce_count, ce_count);
atomic_set(&con->ras_ue_count, ue_count);
}
+ kfree(query_info);
return 0;
interrupt:
@@ -2946,11 +3033,26 @@ int amdgpu_ras_set_context(struct amdgpu_device *adev, struct amdgpu_ras *ras_co
int amdgpu_ras_is_supported(struct amdgpu_device *adev,
unsigned int block)
{
+ int ret = 0;
struct amdgpu_ras *ras = amdgpu_ras_get_context(adev);
if (block >= AMDGPU_RAS_BLOCK_COUNT)
return 0;
- return ras && (adev->ras_enabled & (1 << block));
+
+ ret = ras && (adev->ras_enabled & (1 << block));
+
+ /* For the special asic with mem ecc enabled but sram ecc
+ * not enabled, even if the ras block is not supported on
+ * .ras_enabled, if the asic supports poison mode and the
+ * ras block has ras configuration, it can be considered
+ * that the ras block supports ras function.
+ */
+ if (!ret &&
+ amdgpu_ras_is_poison_mode_supported(adev) &&
+ amdgpu_ras_get_ras_block(adev, block, 0))
+ ret = 1;
+
+ return ret;
}
int amdgpu_ras_reset_gpu(struct amdgpu_device *adev)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h
index bf5a95104ec1..ef38f4c93df0 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h
@@ -540,13 +540,15 @@ void amdgpu_ras_suspend(struct amdgpu_device *adev);
int amdgpu_ras_query_error_count(struct amdgpu_device *adev,
unsigned long *ce_count,
- unsigned long *ue_count);
+ unsigned long *ue_count,
+ struct ras_query_if *query_info);
/* error handling functions */
int amdgpu_ras_add_bad_pages(struct amdgpu_device *adev,
struct eeprom_table_record *bps, int pages);
-int amdgpu_ras_save_bad_pages(struct amdgpu_device *adev);
+int amdgpu_ras_save_bad_pages(struct amdgpu_device *adev,
+ unsigned long *new_cnt);
static inline enum ta_ras_block
amdgpu_ras_block_to_ta(enum amdgpu_ras_block block) {
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c
index 2d9f3f4cd79e..2e08fce87521 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c
@@ -417,7 +417,8 @@ bool amdgpu_ras_eeprom_check_err_threshold(struct amdgpu_device *adev)
{
struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
- if (!__is_ras_eeprom_supported(adev))
+ if (!__is_ras_eeprom_supported(adev) ||
+ !amdgpu_bad_page_threshold)
return false;
/* skip check eeprom table for VEGA20 Gaming */
@@ -428,10 +429,18 @@ bool amdgpu_ras_eeprom_check_err_threshold(struct amdgpu_device *adev)
return false;
if (con->eeprom_control.tbl_hdr.header == RAS_TABLE_HDR_BAD) {
- dev_warn(adev->dev, "This GPU is in BAD status.");
- dev_warn(adev->dev, "Please retire it or set a larger "
- "threshold value when reloading driver.\n");
- return true;
+ if (amdgpu_bad_page_threshold == -1) {
+ dev_warn(adev->dev, "RAS records:%d exceed threshold:%d",
+ con->eeprom_control.ras_num_recs, con->bad_page_cnt_threshold);
+ dev_warn(adev->dev,
+ "But GPU can be operated due to bad_page_threshold = -1.\n");
+ return false;
+ } else {
+ dev_warn(adev->dev, "This GPU is in BAD status.");
+ dev_warn(adev->dev, "Please retire it or set a larger "
+ "threshold value when reloading driver.\n");
+ return true;
+ }
}
return false;
@@ -1191,8 +1200,8 @@ int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control,
} else {
dev_err(adev->dev, "RAS records:%d exceed threshold:%d",
control->ras_num_recs, ras->bad_page_cnt_threshold);
- if (amdgpu_bad_page_threshold == -2) {
- dev_warn(adev->dev, "GPU will be initialized due to bad_page_threshold = -2.");
+ if (amdgpu_bad_page_threshold == -1) {
+ dev_warn(adev->dev, "GPU will be initialized due to bad_page_threshold = -1.");
res = 0;
} else {
*exceed_err_limit = true;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c
index f778466bb9db..6437ead87e5f 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c
@@ -24,6 +24,7 @@
#include "amdgpu_reset.h"
#include "aldebaran.h"
#include "sienna_cichlid.h"
+#include "smu_v13_0_10.h"
int amdgpu_reset_add_handler(struct amdgpu_reset_control *reset_ctl,
struct amdgpu_reset_handler *handler)
@@ -44,6 +45,9 @@ int amdgpu_reset_init(struct amdgpu_device *adev)
case IP_VERSION(11, 0, 7):
ret = sienna_cichlid_reset_init(adev);
break;
+ case IP_VERSION(13, 0, 10):
+ ret = smu_v13_0_10_reset_init(adev);
+ break;
default:
break;
}
@@ -62,6 +66,9 @@ int amdgpu_reset_fini(struct amdgpu_device *adev)
case IP_VERSION(11, 0, 7):
ret = sienna_cichlid_reset_fini(adev);
break;
+ case IP_VERSION(13, 0, 10):
+ ret = smu_v13_0_10_reset_fini(adev);
+ break;
default:
break;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c
index 012b72d00e04..85fb730d9fc8 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c
@@ -93,7 +93,8 @@ int amdgpu_gfx_rlc_init_sr(struct amdgpu_device *adev, u32 dws)
/* allocate save restore block */
r = amdgpu_bo_create_reserved(adev, dws * 4, PAGE_SIZE,
- AMDGPU_GEM_DOMAIN_VRAM,
+ AMDGPU_GEM_DOMAIN_VRAM |
+ AMDGPU_GEM_DOMAIN_GTT,
&adev->gfx.rlc.save_restore_obj,
&adev->gfx.rlc.save_restore_gpu_addr,
(void **)&adev->gfx.rlc.sr_ptr);
@@ -130,7 +131,8 @@ int amdgpu_gfx_rlc_init_csb(struct amdgpu_device *adev)
/* allocate clear state block */
adev->gfx.rlc.clear_state_size = dws = adev->gfx.rlc.funcs->get_csb_size(adev);
r = amdgpu_bo_create_kernel(adev, dws * 4, PAGE_SIZE,
- AMDGPU_GEM_DOMAIN_VRAM,
+ AMDGPU_GEM_DOMAIN_VRAM |
+ AMDGPU_GEM_DOMAIN_GTT,
&adev->gfx.rlc.clear_state_obj,
&adev->gfx.rlc.clear_state_gpu_addr,
(void **)&adev->gfx.rlc.cs_ptr);
@@ -156,7 +158,8 @@ int amdgpu_gfx_rlc_init_cpt(struct amdgpu_device *adev)
int r;
r = amdgpu_bo_create_reserved(adev, adev->gfx.rlc.cp_table_size,
- PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM,
+ PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM |
+ AMDGPU_GEM_DOMAIN_GTT,
&adev->gfx.rlc.cp_table_obj,
&adev->gfx.rlc.cp_table_gpu_addr,
(void **)&adev->gfx.rlc.cp_table_ptr);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c
index ea5278f094c0..231ca06bc9c7 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c
@@ -154,16 +154,11 @@ int amdgpu_sdma_process_ecc_irq(struct amdgpu_device *adev,
static int amdgpu_sdma_init_inst_ctx(struct amdgpu_sdma_instance *sdma_inst)
{
- int err = 0;
uint16_t version_major;
const struct common_firmware_header *header = NULL;
const struct sdma_firmware_header_v1_0 *hdr;
const struct sdma_firmware_header_v2_0 *hdr_v2;
- err = amdgpu_ucode_validate(sdma_inst->fw);
- if (err)
- return err;
-
header = (const struct common_firmware_header *)
sdma_inst->fw->data;
version_major = le16_to_cpu(header->header_version_major);
@@ -195,7 +190,7 @@ void amdgpu_sdma_destroy_inst_ctx(struct amdgpu_device *adev,
int i;
for (i = 0; i < adev->sdma.num_instances; i++) {
- release_firmware(adev->sdma.instance[i].fw);
+ amdgpu_ucode_release(&adev->sdma.instance[i].fw);
if (duplicate)
break;
}
@@ -205,16 +200,22 @@ void amdgpu_sdma_destroy_inst_ctx(struct amdgpu_device *adev,
}
int amdgpu_sdma_init_microcode(struct amdgpu_device *adev,
- char *fw_name, u32 instance,
- bool duplicate)
+ u32 instance, bool duplicate)
{
struct amdgpu_firmware_info *info = NULL;
const struct common_firmware_header *header = NULL;
- int err = 0, i;
+ int err, i;
const struct sdma_firmware_header_v2_0 *sdma_hdr;
uint16_t version_major;
-
- err = request_firmware(&adev->sdma.instance[instance].fw, fw_name, adev->dev);
+ char ucode_prefix[30];
+ char fw_name[40];
+
+ amdgpu_ucode_ip_version_decode(adev, SDMA0_HWIP, ucode_prefix, sizeof(ucode_prefix));
+ if (instance == 0)
+ snprintf(fw_name, sizeof(fw_name), "amdgpu/%s.bin", ucode_prefix);
+ else
+ snprintf(fw_name, sizeof(fw_name), "amdgpu/%s%d.bin", ucode_prefix, instance);
+ err = amdgpu_ucode_request(adev, &adev->sdma.instance[instance].fw, fw_name);
if (err)
goto out;
@@ -279,10 +280,8 @@ int amdgpu_sdma_init_microcode(struct amdgpu_device *adev,
}
out:
- if (err) {
- DRM_ERROR("SDMA: Failed to init firmware \"%s\"\n", fw_name);
+ if (err)
amdgpu_sdma_destroy_inst_ctx(adev, duplicate);
- }
return err;
}
@@ -306,3 +305,38 @@ void amdgpu_sdma_unset_buffer_funcs_helper(struct amdgpu_device *adev)
}
}
}
+
+int amdgpu_sdma_ras_sw_init(struct amdgpu_device *adev)
+{
+ int err = 0;
+ struct amdgpu_sdma_ras *ras = NULL;
+
+ /* adev->sdma.ras is NULL, which means sdma does not
+ * support ras function, then do nothing here.
+ */
+ if (!adev->sdma.ras)
+ return 0;
+
+ ras = adev->sdma.ras;
+
+ err = amdgpu_ras_register_ras_block(adev, &ras->ras_block);
+ if (err) {
+ dev_err(adev->dev, "Failed to register sdma ras block!\n");
+ return err;
+ }
+
+ strcpy(ras->ras_block.ras_comm.name, "sdma");
+ ras->ras_block.ras_comm.block = AMDGPU_RAS_BLOCK__SDMA;
+ ras->ras_block.ras_comm.type = AMDGPU_RAS_ERROR__MULTI_UNCORRECTABLE;
+ adev->sdma.ras_if = &ras->ras_block.ras_comm;
+
+ /* If not define special ras_late_init function, use default ras_late_init */
+ if (!ras->ras_block.ras_late_init)
+ ras->ras_block.ras_late_init = amdgpu_sdma_ras_late_init;
+
+ /* If not defined special ras_cb function, use default ras_cb */
+ if (!ras->ras_block.ras_cb)
+ ras->ras_block.ras_cb = amdgpu_sdma_process_ras_data_cb;
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h
index 7d99205c2e01..fc8528812598 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h
@@ -124,10 +124,11 @@ int amdgpu_sdma_process_ras_data_cb(struct amdgpu_device *adev,
int amdgpu_sdma_process_ecc_irq(struct amdgpu_device *adev,
struct amdgpu_irq_src *source,
struct amdgpu_iv_entry *entry);
-int amdgpu_sdma_init_microcode(struct amdgpu_device *adev,
- char *fw_name, u32 instance, bool duplicate);
+int amdgpu_sdma_init_microcode(struct amdgpu_device *adev, u32 instance,
+ bool duplicate);
void amdgpu_sdma_destroy_inst_ctx(struct amdgpu_device *adev,
bool duplicate);
void amdgpu_sdma_unset_buffer_funcs_helper(struct amdgpu_device *adev);
+int amdgpu_sdma_ras_sw_init(struct amdgpu_device *adev);
#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_securedisplay.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_securedisplay.c
index 2c1d82fc4c34..8ed0e073656f 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_securedisplay.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_securedisplay.c
@@ -77,11 +77,11 @@ void psp_securedisplay_parse_resp_status(struct psp_context *psp,
}
}
-void psp_prep_securedisplay_cmd_buf(struct psp_context *psp, struct securedisplay_cmd **cmd,
+void psp_prep_securedisplay_cmd_buf(struct psp_context *psp, struct ta_securedisplay_cmd **cmd,
enum ta_securedisplay_command command_id)
{
- *cmd = (struct securedisplay_cmd *)psp->securedisplay_context.context.mem_context.shared_buf;
- memset(*cmd, 0, sizeof(struct securedisplay_cmd));
+ *cmd = (struct ta_securedisplay_cmd *)psp->securedisplay_context.context.mem_context.shared_buf;
+ memset(*cmd, 0, sizeof(struct ta_securedisplay_cmd));
(*cmd)->status = TA_SECUREDISPLAY_STATUS__GENERIC_FAILURE;
(*cmd)->cmd_id = command_id;
}
@@ -93,7 +93,7 @@ static ssize_t amdgpu_securedisplay_debugfs_write(struct file *f, const char __u
{
struct amdgpu_device *adev = (struct amdgpu_device *)file_inode(f)->i_private;
struct psp_context *psp = &adev->psp;
- struct securedisplay_cmd *securedisplay_cmd;
+ struct ta_securedisplay_cmd *securedisplay_cmd;
struct drm_device *dev = adev_to_drm(adev);
uint32_t phy_id;
uint32_t op;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_securedisplay.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_securedisplay.h
index fe98574748f4..456ad68ed4b2 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_securedisplay.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_securedisplay.h
@@ -30,7 +30,7 @@
void amdgpu_securedisplay_debugfs_init(struct amdgpu_device *adev);
void psp_securedisplay_parse_resp_status(struct psp_context *psp,
enum ta_securedisplay_status status);
-void psp_prep_securedisplay_cmd_buf(struct psp_context *psp, struct securedisplay_cmd **cmd,
+void psp_prep_securedisplay_cmd_buf(struct psp_context *psp, struct ta_securedisplay_cmd **cmd,
enum ta_securedisplay_command command_id);
#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h
index 677ad2016976..98d91ebf5c26 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h
@@ -153,10 +153,10 @@ TRACE_EVENT(amdgpu_cs,
TP_fast_assign(
__entry->bo_list = p->bo_list;
- __entry->ring = to_amdgpu_ring(job->base.sched)->idx;
+ __entry->ring = to_amdgpu_ring(job->base.entity->rq->sched)->idx;
__entry->dw = ib->length_dw;
__entry->fences = amdgpu_fence_count_emitted(
- to_amdgpu_ring(job->base.sched));
+ to_amdgpu_ring(job->base.entity->rq->sched));
),
TP_printk("bo_list=%p, ring=%u, dw=%u, fences=%u",
__entry->bo_list, __entry->ring, __entry->dw,
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
index 55e0284b2bdd..c5ef7f7bdc15 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
@@ -44,10 +44,10 @@
#include <linux/module.h>
#include <drm/drm_drv.h>
-#include <drm/ttm/ttm_bo_api.h>
-#include <drm/ttm/ttm_bo_driver.h>
+#include <drm/ttm/ttm_bo.h>
#include <drm/ttm/ttm_placement.h>
#include <drm/ttm/ttm_range_manager.h>
+#include <drm/ttm/ttm_tt.h>
#include <drm/amdgpu_drm.h>
#include <drm/drm_drv.h>
@@ -1679,10 +1679,10 @@ static int amdgpu_ttm_reserve_tmr(struct amdgpu_device *adev)
/* reserve vram for mem train according to TMR location */
amdgpu_ttm_training_data_block_init(adev);
ret = amdgpu_bo_create_kernel_at(adev,
- ctx->c2p_train_data_offset,
- ctx->train_data_size,
- &ctx->c2p_bo,
- NULL);
+ ctx->c2p_train_data_offset,
+ ctx->train_data_size,
+ &ctx->c2p_bo,
+ NULL);
if (ret) {
DRM_ERROR("alloc c2p_bo failed(%d)!\n", ret);
amdgpu_ttm_training_reserve_vram_fini(adev);
@@ -1692,10 +1692,10 @@ static int amdgpu_ttm_reserve_tmr(struct amdgpu_device *adev)
}
ret = amdgpu_bo_create_kernel_at(adev,
- adev->gmc.real_vram_size - adev->mman.discovery_tmr_size,
- adev->mman.discovery_tmr_size,
- &adev->mman.discovery_memory,
- NULL);
+ adev->gmc.real_vram_size - adev->mman.discovery_tmr_size,
+ adev->mman.discovery_tmr_size,
+ &adev->mman.discovery_memory,
+ NULL);
if (ret) {
DRM_ERROR("alloc tmr failed(%d)!\n", ret);
amdgpu_bo_free_kernel(&adev->mman.discovery_memory, NULL, NULL);
@@ -1718,7 +1718,6 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
{
uint64_t gtt_size;
int r;
- u64 vis_vram_limit;
mutex_init(&adev->mman.gtt_window_lock);
@@ -1741,12 +1740,6 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
return r;
}
- /* Reduce size of CPU-visible VRAM if requested */
- vis_vram_limit = (u64)amdgpu_vis_vram_limit * 1024 * 1024;
- if (amdgpu_vis_vram_limit > 0 &&
- vis_vram_limit <= adev->gmc.visible_vram_size)
- adev->gmc.visible_vram_size = vis_vram_limit;
-
/* Change the size here instead of the init above so only lpfn is affected */
amdgpu_ttm_set_buffer_funcs_status(adev, false);
#ifdef CONFIG_64BIT
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c
index 5cb62e6249c2..380b89114341 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c
@@ -504,7 +504,7 @@ void amdgpu_ucode_print_gpu_info_hdr(const struct common_firmware_header *hdr)
}
}
-int amdgpu_ucode_validate(const struct firmware *fw)
+static int amdgpu_ucode_validate(const struct firmware *fw)
{
const struct common_firmware_header *hdr =
(const struct common_firmware_header *)fw->data;
@@ -1059,12 +1059,229 @@ int amdgpu_ucode_init_bo(struct amdgpu_device *adev)
return 0;
}
+static const char *amdgpu_ucode_legacy_naming(struct amdgpu_device *adev, int block_type)
+{
+ if (block_type == MP0_HWIP) {
+ switch (adev->ip_versions[MP0_HWIP][0]) {
+ case IP_VERSION(9, 0, 0):
+ switch (adev->asic_type) {
+ case CHIP_VEGA10:
+ return "vega10";
+ case CHIP_VEGA12:
+ return "vega12";
+ default:
+ return NULL;
+ }
+ case IP_VERSION(10, 0, 0):
+ case IP_VERSION(10, 0, 1):
+ if (adev->asic_type == CHIP_RAVEN) {
+ if (adev->apu_flags & AMD_APU_IS_RAVEN2)
+ return "raven2";
+ else if (adev->apu_flags & AMD_APU_IS_PICASSO)
+ return "picasso";
+ return "raven";
+ }
+ break;
+ case IP_VERSION(11, 0, 0):
+ return "navi10";
+ case IP_VERSION(11, 0, 2):
+ return "vega20";
+ case IP_VERSION(11, 0, 3):
+ return "renoir";
+ case IP_VERSION(11, 0, 4):
+ return "arcturus";
+ case IP_VERSION(11, 0, 5):
+ return "navi14";
+ case IP_VERSION(11, 0, 7):
+ return "sienna_cichlid";
+ case IP_VERSION(11, 0, 9):
+ return "navi12";
+ case IP_VERSION(11, 0, 11):
+ return "navy_flounder";
+ case IP_VERSION(11, 0, 12):
+ return "dimgrey_cavefish";
+ case IP_VERSION(11, 0, 13):
+ return "beige_goby";
+ case IP_VERSION(11, 5, 0):
+ return "vangogh";
+ case IP_VERSION(12, 0, 1):
+ return "green_sardine";
+ case IP_VERSION(13, 0, 2):
+ return "aldebaran";
+ case IP_VERSION(13, 0, 1):
+ case IP_VERSION(13, 0, 3):
+ return "yellow_carp";
+ }
+ } else if (block_type == MP1_HWIP) {
+ switch (adev->ip_versions[MP1_HWIP][0]) {
+ case IP_VERSION(9, 0, 0):
+ case IP_VERSION(10, 0, 0):
+ case IP_VERSION(10, 0, 1):
+ case IP_VERSION(11, 0, 2):
+ if (adev->asic_type == CHIP_ARCTURUS)
+ return "arcturus_smc";
+ return NULL;
+ case IP_VERSION(11, 0, 0):
+ return "navi10_smc";
+ case IP_VERSION(11, 0, 5):
+ return "navi14_smc";
+ case IP_VERSION(11, 0, 9):
+ return "navi12_smc";
+ case IP_VERSION(11, 0, 7):
+ return "sienna_cichlid_smc";
+ case IP_VERSION(11, 0, 11):
+ return "navy_flounder_smc";
+ case IP_VERSION(11, 0, 12):
+ return "dimgrey_cavefish_smc";
+ case IP_VERSION(11, 0, 13):
+ return "beige_goby_smc";
+ case IP_VERSION(13, 0, 2):
+ return "aldebaran_smc";
+ }
+ } else if (block_type == SDMA0_HWIP) {
+ switch (adev->ip_versions[SDMA0_HWIP][0]) {
+ case IP_VERSION(4, 0, 0):
+ return "vega10_sdma";
+ case IP_VERSION(4, 0, 1):
+ return "vega12_sdma";
+ case IP_VERSION(4, 1, 0):
+ case IP_VERSION(4, 1, 1):
+ if (adev->apu_flags & AMD_APU_IS_RAVEN2)
+ return "raven2_sdma";
+ else if (adev->apu_flags & AMD_APU_IS_PICASSO)
+ return "picasso_sdma";
+ return "raven_sdma";
+ case IP_VERSION(4, 1, 2):
+ if (adev->apu_flags & AMD_APU_IS_RENOIR)
+ return "renoir_sdma";
+ return "green_sardine_sdma";
+ case IP_VERSION(4, 2, 0):
+ return "vega20_sdma";
+ case IP_VERSION(4, 2, 2):
+ return "arcturus_sdma";
+ case IP_VERSION(4, 4, 0):
+ return "aldebaran_sdma";
+ case IP_VERSION(5, 0, 0):
+ return "navi10_sdma";
+ case IP_VERSION(5, 0, 1):
+ return "cyan_skillfish2_sdma";
+ case IP_VERSION(5, 0, 2):
+ return "navi14_sdma";
+ case IP_VERSION(5, 0, 5):
+ return "navi12_sdma";
+ case IP_VERSION(5, 2, 0):
+ return "sienna_cichlid_sdma";
+ case IP_VERSION(5, 2, 2):
+ return "navy_flounder_sdma";
+ case IP_VERSION(5, 2, 4):
+ return "dimgrey_cavefish_sdma";
+ case IP_VERSION(5, 2, 5):
+ return "beige_goby_sdma";
+ case IP_VERSION(5, 2, 3):
+ return "yellow_carp_sdma";
+ case IP_VERSION(5, 2, 1):
+ return "vangogh_sdma";
+ }
+ } else if (block_type == UVD_HWIP) {
+ switch (adev->ip_versions[UVD_HWIP][0]) {
+ case IP_VERSION(1, 0, 0):
+ case IP_VERSION(1, 0, 1):
+ if (adev->apu_flags & AMD_APU_IS_RAVEN2)
+ return "raven2_vcn";
+ else if (adev->apu_flags & AMD_APU_IS_PICASSO)
+ return "picasso_vcn";
+ return "raven_vcn";
+ case IP_VERSION(2, 5, 0):
+ return "arcturus_vcn";
+ case IP_VERSION(2, 2, 0):
+ if (adev->apu_flags & AMD_APU_IS_RENOIR)
+ return "renoir_vcn";
+ return "green_sardine_vcn";
+ case IP_VERSION(2, 6, 0):
+ return "aldebaran_vcn";
+ case IP_VERSION(2, 0, 0):
+ return "navi10_vcn";
+ case IP_VERSION(2, 0, 2):
+ if (adev->asic_type == CHIP_NAVI12)
+ return "navi12_vcn";
+ return "navi14_vcn";
+ case IP_VERSION(3, 0, 0):
+ case IP_VERSION(3, 0, 64):
+ case IP_VERSION(3, 0, 192):
+ if (adev->ip_versions[GC_HWIP][0] == IP_VERSION(10, 3, 0))
+ return "sienna_cichlid_vcn";
+ return "navy_flounder_vcn";
+ case IP_VERSION(3, 0, 2):
+ return "vangogh_vcn";
+ case IP_VERSION(3, 0, 16):
+ return "dimgrey_cavefish_vcn";
+ case IP_VERSION(3, 0, 33):
+ return "beige_goby_vcn";
+ case IP_VERSION(3, 1, 1):
+ return "yellow_carp_vcn";
+ }
+ } else if (block_type == GC_HWIP) {
+ switch (adev->ip_versions[GC_HWIP][0]) {
+ case IP_VERSION(9, 0, 1):
+ return "vega10";
+ case IP_VERSION(9, 2, 1):
+ return "vega12";
+ case IP_VERSION(9, 4, 0):
+ return "vega20";
+ case IP_VERSION(9, 2, 2):
+ case IP_VERSION(9, 1, 0):
+ if (adev->apu_flags & AMD_APU_IS_RAVEN2)
+ return "raven2";
+ else if (adev->apu_flags & AMD_APU_IS_PICASSO)
+ return "picasso";
+ return "raven";
+ case IP_VERSION(9, 4, 1):
+ return "arcturus";
+ case IP_VERSION(9, 3, 0):
+ if (adev->apu_flags & AMD_APU_IS_RENOIR)
+ return "renoir";
+ return "green_sardine";
+ case IP_VERSION(9, 4, 2):
+ return "aldebaran";
+ case IP_VERSION(10, 1, 10):
+ return "navi10";
+ case IP_VERSION(10, 1, 1):
+ return "navi14";
+ case IP_VERSION(10, 1, 2):
+ return "navi12";
+ case IP_VERSION(10, 3, 0):
+ return "sienna_cichlid";
+ case IP_VERSION(10, 3, 2):
+ return "navy_flounder";
+ case IP_VERSION(10, 3, 1):
+ return "vangogh";
+ case IP_VERSION(10, 3, 4):
+ return "dimgrey_cavefish";
+ case IP_VERSION(10, 3, 5):
+ return "beige_goby";
+ case IP_VERSION(10, 3, 3):
+ return "yellow_carp";
+ case IP_VERSION(10, 1, 3):
+ case IP_VERSION(10, 1, 4):
+ return "cyan_skillfish2";
+ }
+ }
+ return NULL;
+}
+
void amdgpu_ucode_ip_version_decode(struct amdgpu_device *adev, int block_type, char *ucode_prefix, int len)
{
int maj, min, rev;
char *ip_name;
+ const char *legacy;
uint32_t version = adev->ip_versions[block_type][0];
+ legacy = amdgpu_ucode_legacy_naming(adev, block_type);
+ if (legacy) {
+ snprintf(ucode_prefix, len, "%s", legacy);
+ return;
+ }
+
switch (block_type) {
case GC_HWIP:
ip_name = "gc";
@@ -1091,3 +1308,39 @@ void amdgpu_ucode_ip_version_decode(struct amdgpu_device *adev, int block_type,
snprintf(ucode_prefix, len, "%s_%d_%d_%d", ip_name, maj, min, rev);
}
+
+/*
+ * amdgpu_ucode_request - Fetch and validate amdgpu microcode
+ *
+ * @adev: amdgpu device
+ * @fw: pointer to load firmware to
+ * @fw_name: firmware to load
+ *
+ * This is a helper that will use request_firmware and amdgpu_ucode_validate
+ * to load and run basic validation on firmware. If the load fails, remap
+ * the error code to -ENODEV, so that early_init functions will fail to load.
+ */
+int amdgpu_ucode_request(struct amdgpu_device *adev, const struct firmware **fw,
+ const char *fw_name)
+{
+ int err = request_firmware(fw, fw_name, adev->dev);
+
+ if (err)
+ return -ENODEV;
+ err = amdgpu_ucode_validate(*fw);
+ if (err)
+ dev_dbg(adev->dev, "\"%s\" failed to validate\n", fw_name);
+
+ return err;
+}
+
+/*
+ * amdgpu_ucode_release - Release firmware microcode
+ *
+ * @fw: pointer to firmware to release
+ */
+void amdgpu_ucode_release(const struct firmware **fw)
+{
+ release_firmware(*fw);
+ *fw = NULL;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h
index 552e06929229..b03321e7d2d8 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h
@@ -538,12 +538,15 @@ struct amdgpu_firmware {
void amdgpu_ucode_print_mc_hdr(const struct common_firmware_header *hdr);
void amdgpu_ucode_print_smc_hdr(const struct common_firmware_header *hdr);
+void amdgpu_ucode_print_imu_hdr(const struct common_firmware_header *hdr);
void amdgpu_ucode_print_gfx_hdr(const struct common_firmware_header *hdr);
void amdgpu_ucode_print_rlc_hdr(const struct common_firmware_header *hdr);
void amdgpu_ucode_print_sdma_hdr(const struct common_firmware_header *hdr);
void amdgpu_ucode_print_psp_hdr(const struct common_firmware_header *hdr);
void amdgpu_ucode_print_gpu_info_hdr(const struct common_firmware_header *hdr);
-int amdgpu_ucode_validate(const struct firmware *fw);
+int amdgpu_ucode_request(struct amdgpu_device *adev, const struct firmware **fw,
+ const char *fw_name);
+void amdgpu_ucode_release(const struct firmware **fw);
bool amdgpu_ucode_hdr_version(union amdgpu_firmware_header *hdr,
uint16_t hdr_major, uint16_t hdr_minor);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c
index f76c19fc0392..1b8574bc4463 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c
@@ -68,7 +68,7 @@ int amdgpu_umc_page_retirement_mca(struct amdgpu_device *adev,
if (amdgpu_bad_page_threshold != 0) {
amdgpu_ras_add_bad_pages(adev, err_data.err_addr,
err_data.err_addr_cnt);
- amdgpu_ras_save_bad_pages(adev);
+ amdgpu_ras_save_bad_pages(adev, NULL);
}
out:
@@ -147,7 +147,7 @@ static int amdgpu_umc_do_page_retirement(struct amdgpu_device *adev,
err_data->err_addr_cnt) {
amdgpu_ras_add_bad_pages(adev, err_data->err_addr,
err_data->err_addr_cnt);
- amdgpu_ras_save_bad_pages(adev);
+ amdgpu_ras_save_bad_pages(adev, &(err_data->ue_count));
amdgpu_dpm_send_hbm_bad_pages_num(adev, con->eeprom_control.ras_num_recs);
@@ -169,25 +169,33 @@ int amdgpu_umc_poison_handler(struct amdgpu_device *adev, bool reset)
{
int ret = AMDGPU_RAS_SUCCESS;
- if (!adev->gmc.xgmi.connected_to_cpu) {
- struct ras_err_data err_data = {0, 0, 0, NULL};
- struct ras_common_if head = {
- .block = AMDGPU_RAS_BLOCK__UMC,
- };
- struct ras_manager *obj = amdgpu_ras_find_obj(adev, &head);
+ if (!amdgpu_sriov_vf(adev)) {
+ if (!adev->gmc.xgmi.connected_to_cpu) {
+ struct ras_err_data err_data = {0, 0, 0, NULL};
+ struct ras_common_if head = {
+ .block = AMDGPU_RAS_BLOCK__UMC,
+ };
+ struct ras_manager *obj = amdgpu_ras_find_obj(adev, &head);
- ret = amdgpu_umc_do_page_retirement(adev, &err_data, NULL, reset);
+ ret = amdgpu_umc_do_page_retirement(adev, &err_data, NULL, reset);
- if (ret == AMDGPU_RAS_SUCCESS && obj) {
- obj->err_data.ue_count += err_data.ue_count;
- obj->err_data.ce_count += err_data.ce_count;
+ if (ret == AMDGPU_RAS_SUCCESS && obj) {
+ obj->err_data.ue_count += err_data.ue_count;
+ obj->err_data.ce_count += err_data.ce_count;
+ }
+ } else if (reset) {
+ /* MCA poison handler is only responsible for GPU reset,
+ * let MCA notifier do page retirement.
+ */
+ kgd2kfd_set_sram_ecc_flag(adev->kfd.dev);
+ amdgpu_ras_reset_gpu(adev);
}
- } else if (reset) {
- /* MCA poison handler is only responsible for GPU reset,
- * let MCA notifier do page retirement.
- */
- kgd2kfd_set_sram_ecc_flag(adev->kfd.dev);
- amdgpu_ras_reset_gpu(adev);
+ } else {
+ if (adev->virt.ops && adev->virt.ops->ras_poison_handler)
+ adev->virt.ops->ras_poison_handler(adev);
+ else
+ dev_warn(adev->dev,
+ "No ras_poison_handler interface in SRIOV!\n");
}
return ret;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h
index a6951160f13a..f2bf979af588 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h
@@ -74,6 +74,8 @@ struct amdgpu_umc {
/* UMC regiser per channel offset */
uint32_t channel_offs;
+ /* how many pages are retired in one UE */
+ uint32_t retire_unit;
/* channel index table of interleaved memory */
const uint32_t *channel_idx_tbl;
struct ras_common_if *ras_if;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
index e00bb654e24b..632a6ded5735 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
@@ -260,19 +260,11 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev)
return -EINVAL;
}
- r = request_firmware(&adev->uvd.fw, fw_name, adev->dev);
- if (r) {
- dev_err(adev->dev, "amdgpu_uvd: Can't load firmware \"%s\"\n",
- fw_name);
- return r;
- }
-
- r = amdgpu_ucode_validate(adev->uvd.fw);
+ r = amdgpu_ucode_request(adev, &adev->uvd.fw, fw_name);
if (r) {
dev_err(adev->dev, "amdgpu_uvd: Can't validate firmware \"%s\"\n",
fw_name);
- release_firmware(adev->uvd.fw);
- adev->uvd.fw = NULL;
+ amdgpu_ucode_release(&adev->uvd.fw);
return r;
}
@@ -331,8 +323,11 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev)
if (adev->uvd.harvest_config & (1 << j))
continue;
r = amdgpu_bo_create_kernel(adev, bo_size, PAGE_SIZE,
- AMDGPU_GEM_DOMAIN_VRAM, &adev->uvd.inst[j].vcpu_bo,
- &adev->uvd.inst[j].gpu_addr, &adev->uvd.inst[j].cpu_addr);
+ AMDGPU_GEM_DOMAIN_VRAM |
+ AMDGPU_GEM_DOMAIN_GTT,
+ &adev->uvd.inst[j].vcpu_bo,
+ &adev->uvd.inst[j].gpu_addr,
+ &adev->uvd.inst[j].cpu_addr);
if (r) {
dev_err(adev->dev, "(%d) failed to allocate UVD bo\n", r);
return r;
@@ -394,7 +389,7 @@ int amdgpu_uvd_sw_fini(struct amdgpu_device *adev)
amdgpu_ring_fini(&adev->uvd.inst[j].ring_enc[i]);
}
amdgpu_bo_free_kernel(&adev->uvd.ib_bo, NULL, &addr);
- release_firmware(adev->uvd.fw);
+ amdgpu_ucode_release(&adev->uvd.fw);
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
index b239e874f2d5..2fb61410b1c0 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
@@ -158,19 +158,11 @@ int amdgpu_vce_sw_init(struct amdgpu_device *adev, unsigned long size)
return -EINVAL;
}
- r = request_firmware(&adev->vce.fw, fw_name, adev->dev);
- if (r) {
- dev_err(adev->dev, "amdgpu_vce: Can't load firmware \"%s\"\n",
- fw_name);
- return r;
- }
-
- r = amdgpu_ucode_validate(adev->vce.fw);
+ r = amdgpu_ucode_request(adev, &adev->vce.fw, fw_name);
if (r) {
dev_err(adev->dev, "amdgpu_vce: Can't validate firmware \"%s\"\n",
fw_name);
- release_firmware(adev->vce.fw);
- adev->vce.fw = NULL;
+ amdgpu_ucode_release(&adev->vce.fw);
return r;
}
@@ -186,7 +178,9 @@ int amdgpu_vce_sw_init(struct amdgpu_device *adev, unsigned long size)
(binary_id << 8));
r = amdgpu_bo_create_kernel(adev, size, PAGE_SIZE,
- AMDGPU_GEM_DOMAIN_VRAM, &adev->vce.vcpu_bo,
+ AMDGPU_GEM_DOMAIN_VRAM |
+ AMDGPU_GEM_DOMAIN_GTT,
+ &adev->vce.vcpu_bo,
&adev->vce.gpu_addr, &adev->vce.cpu_addr);
if (r) {
dev_err(adev->dev, "(%d) failed to allocate VCE bo\n", r);
@@ -226,7 +220,7 @@ int amdgpu_vce_sw_fini(struct amdgpu_device *adev)
for (i = 0; i < adev->vce.num_rings; i++)
amdgpu_ring_fini(&adev->vce.ring[i]);
- release_firmware(adev->vce.fw);
+ amdgpu_ucode_release(&adev->vce.fw);
mutex_destroy(&adev->vce.idle_mutex);
return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c
index b1622ac9949f..25217b05c0ea 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c
@@ -36,26 +36,26 @@
#include "soc15d.h"
/* Firmware Names */
-#define FIRMWARE_RAVEN "amdgpu/raven_vcn.bin"
-#define FIRMWARE_PICASSO "amdgpu/picasso_vcn.bin"
-#define FIRMWARE_RAVEN2 "amdgpu/raven2_vcn.bin"
-#define FIRMWARE_ARCTURUS "amdgpu/arcturus_vcn.bin"
-#define FIRMWARE_RENOIR "amdgpu/renoir_vcn.bin"
-#define FIRMWARE_GREEN_SARDINE "amdgpu/green_sardine_vcn.bin"
-#define FIRMWARE_NAVI10 "amdgpu/navi10_vcn.bin"
-#define FIRMWARE_NAVI14 "amdgpu/navi14_vcn.bin"
-#define FIRMWARE_NAVI12 "amdgpu/navi12_vcn.bin"
-#define FIRMWARE_SIENNA_CICHLID "amdgpu/sienna_cichlid_vcn.bin"
-#define FIRMWARE_NAVY_FLOUNDER "amdgpu/navy_flounder_vcn.bin"
-#define FIRMWARE_VANGOGH "amdgpu/vangogh_vcn.bin"
+#define FIRMWARE_RAVEN "amdgpu/raven_vcn.bin"
+#define FIRMWARE_PICASSO "amdgpu/picasso_vcn.bin"
+#define FIRMWARE_RAVEN2 "amdgpu/raven2_vcn.bin"
+#define FIRMWARE_ARCTURUS "amdgpu/arcturus_vcn.bin"
+#define FIRMWARE_RENOIR "amdgpu/renoir_vcn.bin"
+#define FIRMWARE_GREEN_SARDINE "amdgpu/green_sardine_vcn.bin"
+#define FIRMWARE_NAVI10 "amdgpu/navi10_vcn.bin"
+#define FIRMWARE_NAVI14 "amdgpu/navi14_vcn.bin"
+#define FIRMWARE_NAVI12 "amdgpu/navi12_vcn.bin"
+#define FIRMWARE_SIENNA_CICHLID "amdgpu/sienna_cichlid_vcn.bin"
+#define FIRMWARE_NAVY_FLOUNDER "amdgpu/navy_flounder_vcn.bin"
+#define FIRMWARE_VANGOGH "amdgpu/vangogh_vcn.bin"
#define FIRMWARE_DIMGREY_CAVEFISH "amdgpu/dimgrey_cavefish_vcn.bin"
-#define FIRMWARE_ALDEBARAN "amdgpu/aldebaran_vcn.bin"
-#define FIRMWARE_BEIGE_GOBY "amdgpu/beige_goby_vcn.bin"
-#define FIRMWARE_YELLOW_CARP "amdgpu/yellow_carp_vcn.bin"
-#define FIRMWARE_VCN_3_1_2 "amdgpu/vcn_3_1_2.bin"
-#define FIRMWARE_VCN4_0_0 "amdgpu/vcn_4_0_0.bin"
-#define FIRMWARE_VCN4_0_2 "amdgpu/vcn_4_0_2.bin"
-#define FIRMWARE_VCN4_0_4 "amdgpu/vcn_4_0_4.bin"
+#define FIRMWARE_ALDEBARAN "amdgpu/aldebaran_vcn.bin"
+#define FIRMWARE_BEIGE_GOBY "amdgpu/beige_goby_vcn.bin"
+#define FIRMWARE_YELLOW_CARP "amdgpu/yellow_carp_vcn.bin"
+#define FIRMWARE_VCN_3_1_2 "amdgpu/vcn_3_1_2.bin"
+#define FIRMWARE_VCN4_0_0 "amdgpu/vcn_4_0_0.bin"
+#define FIRMWARE_VCN4_0_2 "amdgpu/vcn_4_0_2.bin"
+#define FIRMWARE_VCN4_0_4 "amdgpu/vcn_4_0_4.bin"
MODULE_FIRMWARE(FIRMWARE_RAVEN);
MODULE_FIRMWARE(FIRMWARE_PICASSO);
@@ -80,10 +80,24 @@ MODULE_FIRMWARE(FIRMWARE_VCN4_0_4);
static void amdgpu_vcn_idle_work_handler(struct work_struct *work);
+int amdgpu_vcn_early_init(struct amdgpu_device *adev)
+{
+ char ucode_prefix[30];
+ char fw_name[40];
+ int r;
+
+ amdgpu_ucode_ip_version_decode(adev, UVD_HWIP, ucode_prefix, sizeof(ucode_prefix));
+ snprintf(fw_name, sizeof(fw_name), "amdgpu/%s.bin", ucode_prefix);
+ r = amdgpu_ucode_request(adev, &adev->vcn.fw, fw_name);
+ if (r)
+ amdgpu_ucode_release(&adev->vcn.fw);
+
+ return r;
+}
+
int amdgpu_vcn_sw_init(struct amdgpu_device *adev)
{
unsigned long bo_size;
- const char *fw_name;
const struct common_firmware_header *hdr;
unsigned char fw_check;
unsigned int fw_shared_size, log_offset;
@@ -96,131 +110,9 @@ int amdgpu_vcn_sw_init(struct amdgpu_device *adev)
for (i = 0; i < adev->vcn.num_vcn_inst; i++)
atomic_set(&adev->vcn.inst[i].dpg_enc_submission_cnt, 0);
- switch (adev->ip_versions[UVD_HWIP][0]) {
- case IP_VERSION(1, 0, 0):
- case IP_VERSION(1, 0, 1):
- if (adev->apu_flags & AMD_APU_IS_RAVEN2)
- fw_name = FIRMWARE_RAVEN2;
- else if (adev->apu_flags & AMD_APU_IS_PICASSO)
- fw_name = FIRMWARE_PICASSO;
- else
- fw_name = FIRMWARE_RAVEN;
- break;
- case IP_VERSION(2, 5, 0):
- fw_name = FIRMWARE_ARCTURUS;
- if ((adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) &&
- (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG))
- adev->vcn.indirect_sram = true;
- break;
- case IP_VERSION(2, 2, 0):
- if (adev->apu_flags & AMD_APU_IS_RENOIR)
- fw_name = FIRMWARE_RENOIR;
- else
- fw_name = FIRMWARE_GREEN_SARDINE;
-
- if ((adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) &&
- (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG))
- adev->vcn.indirect_sram = true;
- break;
- case IP_VERSION(2, 6, 0):
- fw_name = FIRMWARE_ALDEBARAN;
- if ((adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) &&
- (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG))
- adev->vcn.indirect_sram = true;
- break;
- case IP_VERSION(2, 0, 0):
- fw_name = FIRMWARE_NAVI10;
- if ((adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) &&
- (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG))
- adev->vcn.indirect_sram = true;
- break;
- case IP_VERSION(2, 0, 2):
- if (adev->asic_type == CHIP_NAVI12)
- fw_name = FIRMWARE_NAVI12;
- else
- fw_name = FIRMWARE_NAVI14;
- if ((adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) &&
- (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG))
- adev->vcn.indirect_sram = true;
- break;
- case IP_VERSION(3, 0, 0):
- case IP_VERSION(3, 0, 64):
- case IP_VERSION(3, 0, 192):
- if (adev->ip_versions[GC_HWIP][0] == IP_VERSION(10, 3, 0))
- fw_name = FIRMWARE_SIENNA_CICHLID;
- else
- fw_name = FIRMWARE_NAVY_FLOUNDER;
- if ((adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) &&
- (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG))
- adev->vcn.indirect_sram = true;
- break;
- case IP_VERSION(3, 0, 2):
- fw_name = FIRMWARE_VANGOGH;
- if ((adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) &&
- (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG))
- adev->vcn.indirect_sram = true;
- break;
- case IP_VERSION(3, 0, 16):
- fw_name = FIRMWARE_DIMGREY_CAVEFISH;
- if ((adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) &&
- (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG))
- adev->vcn.indirect_sram = true;
- break;
- case IP_VERSION(3, 0, 33):
- fw_name = FIRMWARE_BEIGE_GOBY;
- if ((adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) &&
- (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG))
- adev->vcn.indirect_sram = true;
- break;
- case IP_VERSION(3, 1, 1):
- fw_name = FIRMWARE_YELLOW_CARP;
- if ((adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) &&
- (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG))
- adev->vcn.indirect_sram = true;
- break;
- case IP_VERSION(3, 1, 2):
- fw_name = FIRMWARE_VCN_3_1_2;
- if ((adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) &&
- (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG))
- adev->vcn.indirect_sram = true;
- break;
- case IP_VERSION(4, 0, 0):
- fw_name = FIRMWARE_VCN4_0_0;
- if ((adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) &&
- (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG))
- adev->vcn.indirect_sram = true;
- break;
- case IP_VERSION(4, 0, 2):
- fw_name = FIRMWARE_VCN4_0_2;
- if ((adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) &&
- (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG))
- adev->vcn.indirect_sram = true;
- break;
- case IP_VERSION(4, 0, 4):
- fw_name = FIRMWARE_VCN4_0_4;
- if ((adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) &&
- (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG))
- adev->vcn.indirect_sram = true;
- break;
- default:
- return -EINVAL;
- }
-
- r = request_firmware(&adev->vcn.fw, fw_name, adev->dev);
- if (r) {
- dev_err(adev->dev, "amdgpu_vcn: Can't load firmware \"%s\"\n",
- fw_name);
- return r;
- }
-
- r = amdgpu_ucode_validate(adev->vcn.fw);
- if (r) {
- dev_err(adev->dev, "amdgpu_vcn: Can't validate firmware \"%s\"\n",
- fw_name);
- release_firmware(adev->vcn.fw);
- adev->vcn.fw = NULL;
- return r;
- }
+ if ((adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) &&
+ (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG))
+ adev->vcn.indirect_sram = true;
hdr = (const struct common_firmware_header *)adev->vcn.fw->data;
adev->vcn.fw_version = le32_to_cpu(hdr->ucode_version);
@@ -274,8 +166,11 @@ int amdgpu_vcn_sw_init(struct amdgpu_device *adev)
continue;
r = amdgpu_bo_create_kernel(adev, bo_size, PAGE_SIZE,
- AMDGPU_GEM_DOMAIN_VRAM, &adev->vcn.inst[i].vcpu_bo,
- &adev->vcn.inst[i].gpu_addr, &adev->vcn.inst[i].cpu_addr);
+ AMDGPU_GEM_DOMAIN_VRAM |
+ AMDGPU_GEM_DOMAIN_GTT,
+ &adev->vcn.inst[i].vcpu_bo,
+ &adev->vcn.inst[i].gpu_addr,
+ &adev->vcn.inst[i].cpu_addr);
if (r) {
dev_err(adev->dev, "(%d) failed to allocate vcn bo\n", r);
return r;
@@ -296,8 +191,11 @@ int amdgpu_vcn_sw_init(struct amdgpu_device *adev)
if (adev->vcn.indirect_sram) {
r = amdgpu_bo_create_kernel(adev, 64 * 2 * 4, PAGE_SIZE,
- AMDGPU_GEM_DOMAIN_VRAM, &adev->vcn.inst[i].dpg_sram_bo,
- &adev->vcn.inst[i].dpg_sram_gpu_addr, &adev->vcn.inst[i].dpg_sram_cpu_addr);
+ AMDGPU_GEM_DOMAIN_VRAM |
+ AMDGPU_GEM_DOMAIN_GTT,
+ &adev->vcn.inst[i].dpg_sram_bo,
+ &adev->vcn.inst[i].dpg_sram_gpu_addr,
+ &adev->vcn.inst[i].dpg_sram_cpu_addr);
if (r) {
dev_err(adev->dev, "VCN %d (%d) failed to allocate DPG bo\n", i, r);
return r;
@@ -333,7 +231,7 @@ int amdgpu_vcn_sw_fini(struct amdgpu_device *adev)
amdgpu_ring_fini(&adev->vcn.inst[j].ring_enc[i]);
}
- release_firmware(adev->vcn.fw);
+ amdgpu_ucode_release(&adev->vcn.fw);
mutex_destroy(&adev->vcn.vcn1_jpeg1_workaround);
mutex_destroy(&adev->vcn.vcn_pg_lock);
@@ -1250,8 +1148,16 @@ int amdgpu_vcn_process_poison_irq(struct amdgpu_device *adev,
if (!ras_if)
return 0;
- ih_data.head = *ras_if;
- amdgpu_ras_interrupt_dispatch(adev, &ih_data);
+ if (!amdgpu_sriov_vf(adev)) {
+ ih_data.head = *ras_if;
+ amdgpu_ras_interrupt_dispatch(adev, &ih_data);
+ } else {
+ if (adev->virt.ops && adev->virt.ops->ras_poison_handler)
+ adev->virt.ops->ras_poison_handler(adev);
+ else
+ dev_warn(adev->dev,
+ "No ras_poison_handler interface in SRIOV for VCN!\n");
+ }
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h
index dbb8d68a30c6..d3e2af902907 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h
@@ -369,6 +369,7 @@ enum vcn_ring_type {
VCN_UNIFIED_RING,
};
+int amdgpu_vcn_early_init(struct amdgpu_device *adev);
int amdgpu_vcn_sw_init(struct amdgpu_device *adev);
int amdgpu_vcn_sw_fini(struct amdgpu_device *adev);
int amdgpu_vcn_suspend(struct amdgpu_device *adev);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c
index 2994b9db196f..f2e2cbaa7fde 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c
@@ -232,7 +232,8 @@ int amdgpu_virt_alloc_mm_table(struct amdgpu_device *adev)
return 0;
r = amdgpu_bo_create_kernel(adev, PAGE_SIZE, PAGE_SIZE,
- AMDGPU_GEM_DOMAIN_VRAM,
+ AMDGPU_GEM_DOMAIN_VRAM |
+ AMDGPU_GEM_DOMAIN_GTT,
&adev->virt.mm_table.bo,
&adev->virt.mm_table.gpu_addr,
(void *)&adev->virt.mm_table.cpu_addr);
@@ -982,11 +983,13 @@ static u32 amdgpu_virt_rlcg_reg_rw(struct amdgpu_device *adev, u32 offset, u32 v
if (offset == reg_access_ctrl->grbm_cntl) {
/* if the target reg offset is grbm_cntl, write to scratch_reg2 */
writel(v, scratch_reg2);
- writel(v, ((void __iomem *)adev->rmmio) + (offset * 4));
+ if (flag == AMDGPU_RLCG_GC_WRITE_LEGACY)
+ writel(v, ((void __iomem *)adev->rmmio) + (offset * 4));
} else if (offset == reg_access_ctrl->grbm_idx) {
/* if the target reg offset is grbm_idx, write to scratch_reg3 */
writel(v, scratch_reg3);
- writel(v, ((void __iomem *)adev->rmmio) + (offset * 4));
+ if (flag == AMDGPU_RLCG_GC_WRITE_LEGACY)
+ writel(v, ((void __iomem *)adev->rmmio) + (offset * 4));
} else {
/*
* SCRATCH_REG0 = read/write value
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h
index 2b9d806e23af..b9e9480448af 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h
@@ -88,6 +88,7 @@ struct amdgpu_virt_ops {
int (*wait_reset)(struct amdgpu_device *adev);
void (*trans_msg)(struct amdgpu_device *adev, enum idh_request req,
u32 data1, u32 data2, u32 data3);
+ void (*ras_poison_handler)(struct amdgpu_device *adev);
};
/*
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
index dc379dc22c77..b9441ab457ea 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
@@ -33,6 +33,7 @@
#include <drm/amdgpu_drm.h>
#include <drm/drm_drv.h>
+#include <drm/ttm/ttm_tt.h>
#include "amdgpu.h"
#include "amdgpu_trace.h"
#include "amdgpu_amdkfd.h"
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
index 094bb4807303..856a64bc7a89 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
@@ -29,7 +29,7 @@
#include <linux/rbtree.h>
#include <drm/gpu_scheduler.h>
#include <drm/drm_file.h>
-#include <drm/ttm/ttm_bo_driver.h>
+#include <drm/ttm/ttm_bo.h>
#include <linux/sched/mm.h>
#include "amdgpu_sync.h"
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
index 9fa1d814508a..43d6a9d6a538 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
@@ -453,7 +453,8 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man,
/* Limit maximum size to 2GiB due to SG table limitations */
size = min(remaining_size, 2ULL << 30);
- if (size >= (u64)pages_per_block << PAGE_SHIFT)
+ if ((size >= (u64)pages_per_block << PAGE_SHIFT) &&
+ !(size & (((u64)pages_per_block << PAGE_SHIFT) - 1)))
min_block_size = (u64)pages_per_block << PAGE_SHIFT;
cur_size = size;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c
index 4b9e7b050ccd..4340d08f7607 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c
@@ -29,13 +29,16 @@
#include "df/df_3_6_offset.h"
#include "xgmi/xgmi_4_0_0_smn.h"
#include "xgmi/xgmi_4_0_0_sh_mask.h"
+#include "xgmi/xgmi_6_1_0_sh_mask.h"
#include "wafl/wafl2_4_0_0_smn.h"
#include "wafl/wafl2_4_0_0_sh_mask.h"
#include "amdgpu_reset.h"
#define smnPCS_XGMI3X16_PCS_ERROR_STATUS 0x11a0020c
+#define smnPCS_XGMI3X16_PCS_ERROR_NONCORRECTABLE_MASK 0x11a00218
#define smnPCS_GOPX1_PCS_ERROR_STATUS 0x12200210
+#define smnPCS_GOPX1_PCS_ERROR_NONCORRECTABLE_MASK 0x12200218
static DEFINE_MUTEX(xgmi_mutex);
@@ -79,11 +82,27 @@ static const int xgmi3x16_pcs_err_status_reg_aldebaran[] = {
smnPCS_XGMI3X16_PCS_ERROR_STATUS + 0x700000
};
+static const int xgmi3x16_pcs_err_noncorrectable_mask_reg_aldebaran[] = {
+ smnPCS_XGMI3X16_PCS_ERROR_NONCORRECTABLE_MASK,
+ smnPCS_XGMI3X16_PCS_ERROR_NONCORRECTABLE_MASK + 0x100000,
+ smnPCS_XGMI3X16_PCS_ERROR_NONCORRECTABLE_MASK + 0x200000,
+ smnPCS_XGMI3X16_PCS_ERROR_NONCORRECTABLE_MASK + 0x300000,
+ smnPCS_XGMI3X16_PCS_ERROR_NONCORRECTABLE_MASK + 0x400000,
+ smnPCS_XGMI3X16_PCS_ERROR_NONCORRECTABLE_MASK + 0x500000,
+ smnPCS_XGMI3X16_PCS_ERROR_NONCORRECTABLE_MASK + 0x600000,
+ smnPCS_XGMI3X16_PCS_ERROR_NONCORRECTABLE_MASK + 0x700000
+};
+
static const int walf_pcs_err_status_reg_aldebaran[] = {
smnPCS_GOPX1_PCS_ERROR_STATUS,
smnPCS_GOPX1_PCS_ERROR_STATUS + 0x100000
};
+static const int walf_pcs_err_noncorrectable_mask_reg_aldebaran[] = {
+ smnPCS_GOPX1_PCS_ERROR_NONCORRECTABLE_MASK,
+ smnPCS_GOPX1_PCS_ERROR_NONCORRECTABLE_MASK + 0x100000
+};
+
static const struct amdgpu_pcs_ras_field xgmi_pcs_ras_fields[] = {
{"XGMI PCS DataLossErr",
SOC15_REG_FIELD(XGMI0_PCS_GOPX16_PCS_ERROR_STATUS, DataLossErr)},
@@ -162,6 +181,67 @@ static const struct amdgpu_pcs_ras_field wafl_pcs_ras_fields[] = {
SOC15_REG_FIELD(PCS_GOPX1_0_PCS_GOPX1_PCS_ERROR_STATUS, RecoveryRelockAttemptErr)},
};
+static const struct amdgpu_pcs_ras_field xgmi3x16_pcs_ras_fields[] = {
+ {"XGMI3X16 PCS DataLossErr",
+ SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, DataLossErr)},
+ {"XGMI3X16 PCS TrainingErr",
+ SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, TrainingErr)},
+ {"XGMI3X16 PCS FlowCtrlAckErr",
+ SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, FlowCtrlAckErr)},
+ {"XGMI3X16 PCS RxFifoUnderflowErr",
+ SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, RxFifoUnderflowErr)},
+ {"XGMI3X16 PCS RxFifoOverflowErr",
+ SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, RxFifoOverflowErr)},
+ {"XGMI3X16 PCS CRCErr",
+ SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, CRCErr)},
+ {"XGMI3X16 PCS BERExceededErr",
+ SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, BERExceededErr)},
+ {"XGMI3X16 PCS TxVcidDataErr",
+ SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, TxVcidDataErr)},
+ {"XGMI3X16 PCS ReplayBufParityErr",
+ SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, ReplayBufParityErr)},
+ {"XGMI3X16 PCS DataParityErr",
+ SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, DataParityErr)},
+ {"XGMI3X16 PCS ReplayFifoOverflowErr",
+ SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, ReplayFifoOverflowErr)},
+ {"XGMI3X16 PCS ReplayFifoUnderflowErr",
+ SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, ReplayFifoUnderflowErr)},
+ {"XGMI3X16 PCS ElasticFifoOverflowErr",
+ SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, ElasticFifoOverflowErr)},
+ {"XGMI3X16 PCS DeskewErr",
+ SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, DeskewErr)},
+ {"XGMI3X16 PCS FlowCtrlCRCErr",
+ SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, FlowCtrlCRCErr)},
+ {"XGMI3X16 PCS DataStartupLimitErr",
+ SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, DataStartupLimitErr)},
+ {"XGMI3X16 PCS FCInitTimeoutErr",
+ SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, FCInitTimeoutErr)},
+ {"XGMI3X16 PCS RecoveryTimeoutErr",
+ SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, RecoveryTimeoutErr)},
+ {"XGMI3X16 PCS ReadySerialTimeoutErr",
+ SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, ReadySerialTimeoutErr)},
+ {"XGMI3X16 PCS ReadySerialAttemptErr",
+ SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, ReadySerialAttemptErr)},
+ {"XGMI3X16 PCS RecoveryAttemptErr",
+ SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, RecoveryAttemptErr)},
+ {"XGMI3X16 PCS RecoveryRelockAttemptErr",
+ SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, RecoveryRelockAttemptErr)},
+ {"XGMI3X16 PCS ReplayAttemptErr",
+ SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, ReplayAttemptErr)},
+ {"XGMI3X16 PCS SyncHdrErr",
+ SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, SyncHdrErr)},
+ {"XGMI3X16 PCS TxReplayTimeoutErr",
+ SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, TxReplayTimeoutErr)},
+ {"XGMI3X16 PCS RxReplayTimeoutErr",
+ SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, RxReplayTimeoutErr)},
+ {"XGMI3X16 PCS LinkSubTxTimeoutErr",
+ SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, LinkSubTxTimeoutErr)},
+ {"XGMI3X16 PCS LinkSubRxTimeoutErr",
+ SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, LinkSubRxTimeoutErr)},
+ {"XGMI3X16 PCS RxCMDPktErr",
+ SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, RxCMDPktErr)},
+};
+
/**
* DOC: AMDGPU XGMI Support
*
@@ -809,39 +889,47 @@ static void amdgpu_xgmi_reset_ras_error_count(struct amdgpu_device *adev)
static int amdgpu_xgmi_query_pcs_error_status(struct amdgpu_device *adev,
uint32_t value,
+ uint32_t mask_value,
uint32_t *ue_count,
uint32_t *ce_count,
- bool is_xgmi_pcs)
+ bool is_xgmi_pcs,
+ bool check_mask)
{
int i;
- int ue_cnt;
+ int ue_cnt = 0;
+ const struct amdgpu_pcs_ras_field *pcs_ras_fields = NULL;
+ uint32_t field_array_size = 0;
if (is_xgmi_pcs) {
- /* query xgmi pcs error status,
- * only ue is supported */
- for (i = 0; i < ARRAY_SIZE(xgmi_pcs_ras_fields); i ++) {
- ue_cnt = (value &
- xgmi_pcs_ras_fields[i].pcs_err_mask) >>
- xgmi_pcs_ras_fields[i].pcs_err_shift;
- if (ue_cnt) {
- dev_info(adev->dev, "%s detected\n",
- xgmi_pcs_ras_fields[i].err_name);
- *ue_count += ue_cnt;
- }
+ if (adev->ip_versions[XGMI_HWIP][0] == IP_VERSION(6, 1, 0)) {
+ pcs_ras_fields = &xgmi3x16_pcs_ras_fields[0];
+ field_array_size = ARRAY_SIZE(xgmi3x16_pcs_ras_fields);
+ } else {
+ pcs_ras_fields = &xgmi_pcs_ras_fields[0];
+ field_array_size = ARRAY_SIZE(xgmi_pcs_ras_fields);
}
} else {
- /* query wafl pcs error status,
- * only ue is supported */
- for (i = 0; i < ARRAY_SIZE(wafl_pcs_ras_fields); i++) {
- ue_cnt = (value &
- wafl_pcs_ras_fields[i].pcs_err_mask) >>
- wafl_pcs_ras_fields[i].pcs_err_shift;
- if (ue_cnt) {
- dev_info(adev->dev, "%s detected\n",
- wafl_pcs_ras_fields[i].err_name);
- *ue_count += ue_cnt;
- }
+ pcs_ras_fields = &wafl_pcs_ras_fields[0];
+ field_array_size = ARRAY_SIZE(wafl_pcs_ras_fields);
+ }
+
+ if (check_mask)
+ value = value & ~mask_value;
+
+ /* query xgmi/walf pcs error status,
+ * only ue is supported */
+ for (i = 0; value && i < field_array_size; i++) {
+ ue_cnt = (value &
+ pcs_ras_fields[i].pcs_err_mask) >>
+ pcs_ras_fields[i].pcs_err_shift;
+ if (ue_cnt) {
+ dev_info(adev->dev, "%s detected\n",
+ pcs_ras_fields[i].err_name);
+ *ue_count += ue_cnt;
}
+
+ /* reset bit value if the bit is checked */
+ value &= ~(pcs_ras_fields[i].pcs_err_mask);
}
return 0;
@@ -852,7 +940,7 @@ static void amdgpu_xgmi_query_ras_error_count(struct amdgpu_device *adev,
{
struct ras_err_data *err_data = (struct ras_err_data *)ras_error_status;
int i;
- uint32_t data;
+ uint32_t data, mask_data = 0;
uint32_t ue_cnt = 0, ce_cnt = 0;
if (!amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__XGMI_WAFL))
@@ -867,15 +955,15 @@ static void amdgpu_xgmi_query_ras_error_count(struct amdgpu_device *adev,
for (i = 0; i < ARRAY_SIZE(xgmi_pcs_err_status_reg_arct); i++) {
data = RREG32_PCIE(xgmi_pcs_err_status_reg_arct[i]);
if (data)
- amdgpu_xgmi_query_pcs_error_status(adev,
- data, &ue_cnt, &ce_cnt, true);
+ amdgpu_xgmi_query_pcs_error_status(adev, data,
+ mask_data, &ue_cnt, &ce_cnt, true, false);
}
/* check wafl pcs error */
for (i = 0; i < ARRAY_SIZE(wafl_pcs_err_status_reg_arct); i++) {
data = RREG32_PCIE(wafl_pcs_err_status_reg_arct[i]);
if (data)
- amdgpu_xgmi_query_pcs_error_status(adev,
- data, &ue_cnt, &ce_cnt, false);
+ amdgpu_xgmi_query_pcs_error_status(adev, data,
+ mask_data, &ue_cnt, &ce_cnt, false, false);
}
break;
case CHIP_VEGA20:
@@ -883,31 +971,35 @@ static void amdgpu_xgmi_query_ras_error_count(struct amdgpu_device *adev,
for (i = 0; i < ARRAY_SIZE(xgmi_pcs_err_status_reg_vg20); i++) {
data = RREG32_PCIE(xgmi_pcs_err_status_reg_vg20[i]);
if (data)
- amdgpu_xgmi_query_pcs_error_status(adev,
- data, &ue_cnt, &ce_cnt, true);
+ amdgpu_xgmi_query_pcs_error_status(adev, data,
+ mask_data, &ue_cnt, &ce_cnt, true, false);
}
/* check wafl pcs error */
for (i = 0; i < ARRAY_SIZE(wafl_pcs_err_status_reg_vg20); i++) {
data = RREG32_PCIE(wafl_pcs_err_status_reg_vg20[i]);
if (data)
- amdgpu_xgmi_query_pcs_error_status(adev,
- data, &ue_cnt, &ce_cnt, false);
+ amdgpu_xgmi_query_pcs_error_status(adev, data,
+ mask_data, &ue_cnt, &ce_cnt, false, false);
}
break;
case CHIP_ALDEBARAN:
/* check xgmi3x16 pcs error */
for (i = 0; i < ARRAY_SIZE(xgmi3x16_pcs_err_status_reg_aldebaran); i++) {
data = RREG32_PCIE(xgmi3x16_pcs_err_status_reg_aldebaran[i]);
+ mask_data =
+ RREG32_PCIE(xgmi3x16_pcs_err_noncorrectable_mask_reg_aldebaran[i]);
if (data)
- amdgpu_xgmi_query_pcs_error_status(adev,
- data, &ue_cnt, &ce_cnt, true);
+ amdgpu_xgmi_query_pcs_error_status(adev, data,
+ mask_data, &ue_cnt, &ce_cnt, true, true);
}
/* check wafl pcs error */
for (i = 0; i < ARRAY_SIZE(walf_pcs_err_status_reg_aldebaran); i++) {
data = RREG32_PCIE(walf_pcs_err_status_reg_aldebaran[i]);
+ mask_data =
+ RREG32_PCIE(walf_pcs_err_noncorrectable_mask_reg_aldebaran[i]);
if (data)
- amdgpu_xgmi_query_pcs_error_status(adev,
- data, &ue_cnt, &ce_cnt, false);
+ amdgpu_xgmi_query_pcs_error_status(adev, data,
+ mask_data, &ue_cnt, &ce_cnt, false, true);
}
break;
default:
diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_crtc.c b/drivers/gpu/drm/amd/amdgpu/atombios_crtc.c
index afad094f84c2..10098fdd33fc 100644
--- a/drivers/gpu/drm/amd/amdgpu/atombios_crtc.c
+++ b/drivers/gpu/drm/amd/amdgpu/atombios_crtc.c
@@ -24,7 +24,6 @@
* Alex Deucher
*/
-#include <drm/drm_crtc_helper.h>
#include <drm/amdgpu_drm.h>
#include <drm/drm_fixed.h>
#include "amdgpu.h"
diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c b/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c
index 18ae9433e463..d95b2dc78063 100644
--- a/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c
+++ b/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c
@@ -28,7 +28,6 @@
#include <acpi/video.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/amdgpu_drm.h>
#include "amdgpu.h"
#include "amdgpu_connectors.h"
diff --git a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c
index cbca9866645c..67d16236b216 100644
--- a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c
+++ b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c
@@ -73,10 +73,9 @@ u32 amdgpu_cik_gpu_check_soft_reset(struct amdgpu_device *adev);
static void cik_sdma_free_microcode(struct amdgpu_device *adev)
{
int i;
- for (i = 0; i < adev->sdma.num_instances; i++) {
- release_firmware(adev->sdma.instance[i].fw);
- adev->sdma.instance[i].fw = NULL;
- }
+
+ for (i = 0; i < adev->sdma.num_instances; i++)
+ amdgpu_ucode_release(&adev->sdma.instance[i].fw);
}
/*
@@ -137,18 +136,15 @@ static int cik_sdma_init_microcode(struct amdgpu_device *adev)
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sdma.bin", chip_name);
else
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sdma1.bin", chip_name);
- err = request_firmware(&adev->sdma.instance[i].fw, fw_name, adev->dev);
+ err = amdgpu_ucode_request(adev, &adev->sdma.instance[i].fw, fw_name);
if (err)
goto out;
- err = amdgpu_ucode_validate(adev->sdma.instance[i].fw);
}
out:
if (err) {
pr_err("cik_sdma: Failed to load firmware \"%s\"\n", fw_name);
- for (i = 0; i < adev->sdma.num_instances; i++) {
- release_firmware(adev->sdma.instance[i].fw);
- adev->sdma.instance[i].fw = NULL;
- }
+ for (i = 0; i < adev->sdma.num_instances; i++)
+ amdgpu_ucode_release(&adev->sdma.instance[i].fw);
}
return err;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
index 248f1a4e915f..9a24ed463abd 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
@@ -21,8 +21,9 @@
*
*/
-#include <drm/drm_fb_helper.h>
#include <drm/drm_fourcc.h>
+#include <drm/drm_modeset_helper.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_vblank.h>
#include "amdgpu.h"
@@ -2837,7 +2838,7 @@ static int dce_v10_0_sw_init(void *handle)
if (r)
return r;
- INIT_WORK(&adev->hotplug_work,
+ INIT_DELAYED_WORK(&adev->hotplug_work,
amdgpu_display_hotplug_work_func);
drm_kms_helper_poll_init(adev_to_drm(adev));
@@ -2902,7 +2903,7 @@ static int dce_v10_0_hw_fini(void *handle)
dce_v10_0_pageflip_interrupt_fini(adev);
- flush_work(&adev->hotplug_work);
+ flush_delayed_work(&adev->hotplug_work);
return 0;
}
@@ -3302,7 +3303,7 @@ static int dce_v10_0_hpd_irq(struct amdgpu_device *adev,
if (disp_int & mask) {
dce_v10_0_hpd_int_ack(adev, hpd);
- schedule_work(&adev->hotplug_work);
+ schedule_delayed_work(&adev->hotplug_work, 0);
DRM_DEBUG("IH: HPD%d\n", hpd + 1);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
index cd9c19060d89..c14b70350a51 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
@@ -21,8 +21,9 @@
*
*/
-#include <drm/drm_fb_helper.h>
#include <drm/drm_fourcc.h>
+#include <drm/drm_modeset_helper.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_vblank.h>
#include "amdgpu.h"
@@ -2956,7 +2957,7 @@ static int dce_v11_0_sw_init(void *handle)
if (r)
return r;
- INIT_WORK(&adev->hotplug_work,
+ INIT_DELAYED_WORK(&adev->hotplug_work,
amdgpu_display_hotplug_work_func);
drm_kms_helper_poll_init(adev_to_drm(adev));
@@ -3032,7 +3033,7 @@ static int dce_v11_0_hw_fini(void *handle)
dce_v11_0_pageflip_interrupt_fini(adev);
- flush_work(&adev->hotplug_work);
+ flush_delayed_work(&adev->hotplug_work);
return 0;
}
@@ -3426,7 +3427,7 @@ static int dce_v11_0_hpd_irq(struct amdgpu_device *adev,
if (disp_int & mask) {
dce_v11_0_hpd_int_ack(adev, hpd);
- schedule_work(&adev->hotplug_work);
+ schedule_delayed_work(&adev->hotplug_work, 0);
DRM_DEBUG("IH: HPD%d\n", hpd + 1);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
index 76323deecc58..7f85ba5b726f 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
@@ -23,8 +23,9 @@
#include <linux/pci.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_fourcc.h>
+#include <drm/drm_modeset_helper.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_vblank.h>
#include "amdgpu.h"
@@ -2715,7 +2716,7 @@ static int dce_v6_0_sw_init(void *handle)
return r;
/* Pre-DCE11 */
- INIT_WORK(&adev->hotplug_work,
+ INIT_DELAYED_WORK(&adev->hotplug_work,
amdgpu_display_hotplug_work_func);
drm_kms_helper_poll_init(adev_to_drm(adev));
@@ -2776,7 +2777,7 @@ static int dce_v6_0_hw_fini(void *handle)
dce_v6_0_pageflip_interrupt_fini(adev);
- flush_work(&adev->hotplug_work);
+ flush_delayed_work(&adev->hotplug_work);
return 0;
}
@@ -3103,7 +3104,7 @@ static int dce_v6_0_hpd_irq(struct amdgpu_device *adev,
tmp = RREG32(mmDC_HPD1_INT_CONTROL + hpd_offsets[hpd]);
tmp |= DC_HPD1_INT_CONTROL__DC_HPD1_INT_ACK_MASK;
WREG32(mmDC_HPD1_INT_CONTROL + hpd_offsets[hpd], tmp);
- schedule_work(&adev->hotplug_work);
+ schedule_delayed_work(&adev->hotplug_work, 0);
DRM_DEBUG("IH: HPD%d\n", hpd + 1);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
index 01cf3ab111cb..d421a268c9ff 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
@@ -21,8 +21,9 @@
*
*/
-#include <drm/drm_fb_helper.h>
#include <drm/drm_fourcc.h>
+#include <drm/drm_modeset_helper.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_vblank.h>
#include "amdgpu.h"
@@ -2739,7 +2740,7 @@ static int dce_v8_0_sw_init(void *handle)
return r;
/* Pre-DCE11 */
- INIT_WORK(&adev->hotplug_work,
+ INIT_DELAYED_WORK(&adev->hotplug_work,
amdgpu_display_hotplug_work_func);
drm_kms_helper_poll_init(adev_to_drm(adev));
@@ -2802,7 +2803,7 @@ static int dce_v8_0_hw_fini(void *handle)
dce_v8_0_pageflip_interrupt_fini(adev);
- flush_work(&adev->hotplug_work);
+ flush_delayed_work(&adev->hotplug_work);
return 0;
}
@@ -3195,7 +3196,7 @@ static int dce_v8_0_hpd_irq(struct amdgpu_device *adev,
tmp = RREG32(mmDC_HPD1_INT_CONTROL + hpd_offsets[hpd]);
tmp |= DC_HPD1_INT_CONTROL__DC_HPD1_INT_ACK_MASK;
WREG32(mmDC_HPD1_INT_CONTROL + hpd_offsets[hpd], tmp);
- schedule_work(&adev->hotplug_work);
+ schedule_delayed_work(&adev->hotplug_work, 0);
DRM_DEBUG("IH: HPD%d\n", hpd + 1);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/df_v1_7.c b/drivers/gpu/drm/amd/amdgpu/df_v1_7.c
index b991609f46c1..5dfab80ffff2 100644
--- a/drivers/gpu/drm/amd/amdgpu/df_v1_7.c
+++ b/drivers/gpu/drm/amd/amdgpu/df_v1_7.c
@@ -94,7 +94,7 @@ static void df_v1_7_update_medium_grain_clock_gating(struct amdgpu_device *adev,
WREG32_SOC15(DF, 0, mmDF_PIE_AON0_DfGlobalClkGater, tmp);
}
- /* Exit boradcast mode */
+ /* Exit broadcast mode */
adev->df.funcs->enable_broadcast_mode(adev, false);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/df_v4_3.c b/drivers/gpu/drm/amd/amdgpu/df_v4_3.c
new file mode 100644
index 000000000000..e8b9e19ede2e
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/df_v4_3.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ */
+#include "amdgpu.h"
+#include "df_v4_3.h"
+
+#include "df/df_4_3_offset.h"
+#include "df/df_4_3_sh_mask.h"
+
+static bool df_v4_3_query_ras_poison_mode(struct amdgpu_device *adev)
+{
+ uint32_t hw_assert_msklo, hw_assert_mskhi;
+ uint32_t v0, v1, v28, v31;
+
+ hw_assert_msklo = RREG32_SOC15(DF, 0,
+ regDF_CS_UMC_AON0_HardwareAssertMaskLow);
+ hw_assert_mskhi = RREG32_SOC15(DF, 0,
+ regDF_NCS_PG0_HardwareAssertMaskHigh);
+
+ v0 = REG_GET_FIELD(hw_assert_msklo,
+ DF_CS_UMC_AON0_HardwareAssertMaskLow, HWAssertMsk0);
+ v1 = REG_GET_FIELD(hw_assert_msklo,
+ DF_CS_UMC_AON0_HardwareAssertMaskLow, HWAssertMsk1);
+ v28 = REG_GET_FIELD(hw_assert_mskhi,
+ DF_NCS_PG0_HardwareAssertMaskHigh, HWAssertMsk28);
+ v31 = REG_GET_FIELD(hw_assert_mskhi,
+ DF_NCS_PG0_HardwareAssertMaskHigh, HWAssertMsk31);
+
+ if (v0 && v1 && v28 && v31)
+ return true;
+ else if (!v0 && !v1 && !v28 && !v31)
+ return false;
+ else {
+ dev_warn(adev->dev, "DF poison setting is inconsistent(%d:%d:%d:%d)!\n",
+ v0, v1, v28, v31);
+ return false;
+ }
+}
+
+const struct amdgpu_df_funcs df_v4_3_funcs = {
+ .query_ras_poison_mode = df_v4_3_query_ras_poison_mode,
+};
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_frl.h b/drivers/gpu/drm/amd/amdgpu/df_v4_3.h
index ea8d9760132f..06ef0724edd3 100644
--- a/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_frl.h
+++ b/drivers/gpu/drm/amd/amdgpu/df_v4_3.h
@@ -19,16 +19,13 @@
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
- * Authors: AMD
- *
*/
-#ifndef __LINK_HWSS_HPO_FRL_H__
-#define __LINK_HWSS_HPO_FRL_H__
-#include "link_hwss.h"
+#ifndef __DF_V4_3_H__
+#define __DF_V4_3_H__
+
+#include "soc15_common.h"
-bool can_use_hpo_frl_link_hwss(const struct dc_link *link,
- const struct link_resource *link_res);
-const struct link_hwss *get_hpo_frl_link_hwss(void);
+extern const struct amdgpu_df_funcs df_v4_3_funcs;
-#endif /* __LINK_HWSS_HPO_FRL_H__ */
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
index 49d34c7bbf20..6983acc456b2 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
@@ -3891,18 +3891,12 @@ err1:
static void gfx_v10_0_free_microcode(struct amdgpu_device *adev)
{
- release_firmware(adev->gfx.pfp_fw);
- adev->gfx.pfp_fw = NULL;
- release_firmware(adev->gfx.me_fw);
- adev->gfx.me_fw = NULL;
- release_firmware(adev->gfx.ce_fw);
- adev->gfx.ce_fw = NULL;
- release_firmware(adev->gfx.rlc_fw);
- adev->gfx.rlc_fw = NULL;
- release_firmware(adev->gfx.mec_fw);
- adev->gfx.mec_fw = NULL;
- release_firmware(adev->gfx.mec2_fw);
- adev->gfx.mec2_fw = NULL;
+ amdgpu_ucode_release(&adev->gfx.pfp_fw);
+ amdgpu_ucode_release(&adev->gfx.me_fw);
+ amdgpu_ucode_release(&adev->gfx.ce_fw);
+ amdgpu_ucode_release(&adev->gfx.rlc_fw);
+ amdgpu_ucode_release(&adev->gfx.mec_fw);
+ amdgpu_ucode_release(&adev->gfx.mec2_fw);
kfree(adev->gfx.rlc.register_list_format);
}
@@ -3974,9 +3968,9 @@ static void gfx_v10_0_check_gfxoff_flag(struct amdgpu_device *adev)
static int gfx_v10_0_init_microcode(struct amdgpu_device *adev)
{
- const char *chip_name;
char fw_name[40];
- char *wks = "";
+ char ucode_prefix[30];
+ const char *wks = "";
int err;
const struct rlc_firmware_header_v2_0 *rlc_hdr;
uint16_t version_major;
@@ -3984,90 +3978,40 @@ static int gfx_v10_0_init_microcode(struct amdgpu_device *adev)
DRM_DEBUG("\n");
- switch (adev->ip_versions[GC_HWIP][0]) {
- case IP_VERSION(10, 1, 10):
- chip_name = "navi10";
- break;
- case IP_VERSION(10, 1, 1):
- chip_name = "navi14";
- if (!(adev->pdev->device == 0x7340 &&
- adev->pdev->revision != 0x00))
- wks = "_wks";
- break;
- case IP_VERSION(10, 1, 2):
- chip_name = "navi12";
- break;
- case IP_VERSION(10, 3, 0):
- chip_name = "sienna_cichlid";
- break;
- case IP_VERSION(10, 3, 2):
- chip_name = "navy_flounder";
- break;
- case IP_VERSION(10, 3, 1):
- chip_name = "vangogh";
- break;
- case IP_VERSION(10, 3, 4):
- chip_name = "dimgrey_cavefish";
- break;
- case IP_VERSION(10, 3, 5):
- chip_name = "beige_goby";
- break;
- case IP_VERSION(10, 3, 3):
- chip_name = "yellow_carp";
- break;
- case IP_VERSION(10, 3, 6):
- chip_name = "gc_10_3_6";
- break;
- case IP_VERSION(10, 1, 3):
- case IP_VERSION(10, 1, 4):
- chip_name = "cyan_skillfish2";
- break;
- case IP_VERSION(10, 3, 7):
- chip_name = "gc_10_3_7";
- break;
- default:
- BUG();
- }
+ if (adev->ip_versions[GC_HWIP][0] == IP_VERSION(10, 1, 1) &&
+ (!(adev->pdev->device == 0x7340 && adev->pdev->revision != 0x00)))
+ wks = "_wks";
+ amdgpu_ucode_ip_version_decode(adev, GC_HWIP, ucode_prefix, sizeof(ucode_prefix));
- snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_pfp%s.bin", chip_name, wks);
- err = request_firmware(&adev->gfx.pfp_fw, fw_name, adev->dev);
- if (err)
- goto out;
- err = amdgpu_ucode_validate(adev->gfx.pfp_fw);
+ snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_pfp%s.bin", ucode_prefix, wks);
+ err = amdgpu_ucode_request(adev, &adev->gfx.pfp_fw, fw_name);
if (err)
goto out;
amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_PFP);
- snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_me%s.bin", chip_name, wks);
- err = request_firmware(&adev->gfx.me_fw, fw_name, adev->dev);
- if (err)
- goto out;
- err = amdgpu_ucode_validate(adev->gfx.me_fw);
+ snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_me%s.bin", ucode_prefix, wks);
+ err = amdgpu_ucode_request(adev, &adev->gfx.me_fw, fw_name);
if (err)
goto out;
amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_ME);
- snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ce%s.bin", chip_name, wks);
- err = request_firmware(&adev->gfx.ce_fw, fw_name, adev->dev);
- if (err)
- goto out;
- err = amdgpu_ucode_validate(adev->gfx.ce_fw);
+ snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ce%s.bin", ucode_prefix, wks);
+ err = amdgpu_ucode_request(adev, &adev->gfx.ce_fw, fw_name);
if (err)
goto out;
amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_CE);
if (!amdgpu_sriov_vf(adev)) {
- snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_rlc.bin", chip_name);
- err = request_firmware(&adev->gfx.rlc_fw, fw_name, adev->dev);
- if (err)
- goto out;
+ snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_rlc.bin", ucode_prefix);
+ err = amdgpu_ucode_request(adev, &adev->gfx.rlc_fw, fw_name);
/* don't check this. There are apparently firmwares in the wild with
* incorrect size in the header
*/
- err = amdgpu_ucode_validate(adev->gfx.rlc_fw);
+ if (err == -ENODEV)
+ goto out;
if (err)
dev_dbg(adev->dev,
- "gfx10: amdgpu_ucode_validate() failed \"%s\"\n",
+ "gfx10: amdgpu_ucode_request() failed \"%s\"\n",
fw_name);
rlc_hdr = (const struct rlc_firmware_header_v2_0 *)adev->gfx.rlc_fw->data;
version_major = le16_to_cpu(rlc_hdr->header.header_version_major);
@@ -4077,47 +4021,34 @@ static int gfx_v10_0_init_microcode(struct amdgpu_device *adev)
goto out;
}
- snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec%s.bin", chip_name, wks);
- err = request_firmware(&adev->gfx.mec_fw, fw_name, adev->dev);
- if (err)
- goto out;
- err = amdgpu_ucode_validate(adev->gfx.mec_fw);
+ snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec%s.bin", ucode_prefix, wks);
+ err = amdgpu_ucode_request(adev, &adev->gfx.mec_fw, fw_name);
if (err)
goto out;
amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC1);
amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC1_JT);
- snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec2%s.bin", chip_name, wks);
- err = request_firmware(&adev->gfx.mec2_fw, fw_name, adev->dev);
+ snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec2%s.bin", ucode_prefix, wks);
+ err = amdgpu_ucode_request(adev, &adev->gfx.mec2_fw, fw_name);
if (!err) {
- err = amdgpu_ucode_validate(adev->gfx.mec2_fw);
- if (err)
- goto out;
amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC2);
amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC2_JT);
} else {
err = 0;
adev->gfx.mec2_fw = NULL;
}
+ amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC2);
+ amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC2_JT);
gfx_v10_0_check_fw_write_wait(adev);
out:
if (err) {
- dev_err(adev->dev,
- "gfx10: Failed to init firmware \"%s\"\n",
- fw_name);
- release_firmware(adev->gfx.pfp_fw);
- adev->gfx.pfp_fw = NULL;
- release_firmware(adev->gfx.me_fw);
- adev->gfx.me_fw = NULL;
- release_firmware(adev->gfx.ce_fw);
- adev->gfx.ce_fw = NULL;
- release_firmware(adev->gfx.rlc_fw);
- adev->gfx.rlc_fw = NULL;
- release_firmware(adev->gfx.mec_fw);
- adev->gfx.mec_fw = NULL;
- release_firmware(adev->gfx.mec2_fw);
- adev->gfx.mec2_fw = NULL;
+ amdgpu_ucode_release(&adev->gfx.pfp_fw);
+ amdgpu_ucode_release(&adev->gfx.me_fw);
+ amdgpu_ucode_release(&adev->gfx.ce_fw);
+ amdgpu_ucode_release(&adev->gfx.rlc_fw);
+ amdgpu_ucode_release(&adev->gfx.mec_fw);
+ amdgpu_ucode_release(&adev->gfx.mec2_fw);
}
gfx_v10_0_check_gfxoff_flag(adev);
@@ -4270,19 +4201,11 @@ static void gfx_v10_0_mec_fini(struct amdgpu_device *adev)
amdgpu_bo_free_kernel(&adev->gfx.mec.mec_fw_obj, NULL, NULL);
}
-static int gfx_v10_0_me_init(struct amdgpu_device *adev)
+static void gfx_v10_0_me_init(struct amdgpu_device *adev)
{
- int r;
-
bitmap_zero(adev->gfx.me.queue_bitmap, AMDGPU_MAX_GFX_QUEUES);
amdgpu_gfx_graphics_queue_acquire(adev);
-
- r = gfx_v10_0_init_microcode(adev);
- if (r)
- DRM_ERROR("Failed to load gfx firmware!\n");
-
- return r;
}
static int gfx_v10_0_mec_init(struct amdgpu_device *adev)
@@ -4650,9 +4573,7 @@ static int gfx_v10_0_sw_init(void *handle)
adev->gfx.gfx_current_status = AMDGPU_GFX_NORMAL_MODE;
- r = gfx_v10_0_me_init(adev);
- if (r)
- return r;
+ gfx_v10_0_me_init(adev);
if (adev->gfx.rlc.funcs) {
if (adev->gfx.rlc.funcs->init) {
@@ -7630,7 +7551,7 @@ static int gfx_v10_0_early_init(void *handle)
/* init rlcg reg access ctrl */
gfx_v10_0_init_rlcg_reg_access_ctrl(adev);
- return 0;
+ return gfx_v10_0_init_microcode(adev);
}
static int gfx_v10_0_late_init(void *handle)
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
index 66eb102cd88f..3bf697a80cf2 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
@@ -46,6 +46,7 @@
#include "clearstate_gfx11.h"
#include "v11_structs.h"
#include "gfx_v11_0.h"
+#include "gfx_v11_0_3.h"
#include "nbio_v4_3.h"
#include "mes_v11_0.h"
@@ -431,18 +432,37 @@ err1:
static void gfx_v11_0_free_microcode(struct amdgpu_device *adev)
{
- release_firmware(adev->gfx.pfp_fw);
- adev->gfx.pfp_fw = NULL;
- release_firmware(adev->gfx.me_fw);
- adev->gfx.me_fw = NULL;
- release_firmware(adev->gfx.rlc_fw);
- adev->gfx.rlc_fw = NULL;
- release_firmware(adev->gfx.mec_fw);
- adev->gfx.mec_fw = NULL;
+ amdgpu_ucode_release(&adev->gfx.pfp_fw);
+ amdgpu_ucode_release(&adev->gfx.me_fw);
+ amdgpu_ucode_release(&adev->gfx.rlc_fw);
+ amdgpu_ucode_release(&adev->gfx.mec_fw);
kfree(adev->gfx.rlc.register_list_format);
}
+static int gfx_v11_0_init_toc_microcode(struct amdgpu_device *adev, const char *ucode_prefix)
+{
+ const struct psp_firmware_header_v1_0 *toc_hdr;
+ int err = 0;
+ char fw_name[40];
+
+ snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_toc.bin", ucode_prefix);
+ err = amdgpu_ucode_request(adev, &adev->psp.toc_fw, fw_name);
+ if (err)
+ goto out;
+
+ toc_hdr = (const struct psp_firmware_header_v1_0 *)adev->psp.toc_fw->data;
+ adev->psp.toc.fw_version = le32_to_cpu(toc_hdr->header.ucode_version);
+ adev->psp.toc.feature_version = le32_to_cpu(toc_hdr->sos.fw_version);
+ adev->psp.toc.size_bytes = le32_to_cpu(toc_hdr->header.ucode_size_bytes);
+ adev->psp.toc.start_addr = (uint8_t *)toc_hdr +
+ le32_to_cpu(toc_hdr->header.ucode_array_offset_bytes);
+ return 0;
+out:
+ amdgpu_ucode_release(&adev->psp.toc_fw);
+ return err;
+}
+
static int gfx_v11_0_init_microcode(struct amdgpu_device *adev)
{
char fw_name[40];
@@ -457,10 +477,7 @@ static int gfx_v11_0_init_microcode(struct amdgpu_device *adev)
amdgpu_ucode_ip_version_decode(adev, GC_HWIP, ucode_prefix, sizeof(ucode_prefix));
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_pfp.bin", ucode_prefix);
- err = request_firmware(&adev->gfx.pfp_fw, fw_name, adev->dev);
- if (err)
- goto out;
- err = amdgpu_ucode_validate(adev->gfx.pfp_fw);
+ err = amdgpu_ucode_request(adev, &adev->gfx.pfp_fw, fw_name);
if (err)
goto out;
/* check pfp fw hdr version to decide if enable rs64 for gfx11.*/
@@ -477,10 +494,7 @@ static int gfx_v11_0_init_microcode(struct amdgpu_device *adev)
}
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_me.bin", ucode_prefix);
- err = request_firmware(&adev->gfx.me_fw, fw_name, adev->dev);
- if (err)
- goto out;
- err = amdgpu_ucode_validate(adev->gfx.me_fw);
+ err = amdgpu_ucode_request(adev, &adev->gfx.me_fw, fw_name);
if (err)
goto out;
if (adev->gfx.rs64_enable) {
@@ -493,10 +507,7 @@ static int gfx_v11_0_init_microcode(struct amdgpu_device *adev)
if (!amdgpu_sriov_vf(adev)) {
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_rlc.bin", ucode_prefix);
- err = request_firmware(&adev->gfx.rlc_fw, fw_name, adev->dev);
- if (err)
- goto out;
- err = amdgpu_ucode_validate(adev->gfx.rlc_fw);
+ err = amdgpu_ucode_request(adev, &adev->gfx.rlc_fw, fw_name);
if (err)
goto out;
rlc_hdr = (const struct rlc_firmware_header_v2_0 *)adev->gfx.rlc_fw->data;
@@ -508,10 +519,7 @@ static int gfx_v11_0_init_microcode(struct amdgpu_device *adev)
}
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec.bin", ucode_prefix);
- err = request_firmware(&adev->gfx.mec_fw, fw_name, adev->dev);
- if (err)
- goto out;
- err = amdgpu_ucode_validate(adev->gfx.mec_fw);
+ err = amdgpu_ucode_request(adev, &adev->gfx.mec_fw, fw_name);
if (err)
goto out;
if (adev->gfx.rs64_enable) {
@@ -525,59 +533,23 @@ static int gfx_v11_0_init_microcode(struct amdgpu_device *adev)
amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC1_JT);
}
+ if (adev->firmware.load_type == AMDGPU_FW_LOAD_RLC_BACKDOOR_AUTO)
+ err = gfx_v11_0_init_toc_microcode(adev, ucode_prefix);
+
/* only one MEC for gfx 11.0.0. */
adev->gfx.mec2_fw = NULL;
out:
if (err) {
- dev_err(adev->dev,
- "gfx11: Failed to init firmware \"%s\"\n",
- fw_name);
- release_firmware(adev->gfx.pfp_fw);
- adev->gfx.pfp_fw = NULL;
- release_firmware(adev->gfx.me_fw);
- adev->gfx.me_fw = NULL;
- release_firmware(adev->gfx.rlc_fw);
- adev->gfx.rlc_fw = NULL;
- release_firmware(adev->gfx.mec_fw);
- adev->gfx.mec_fw = NULL;
+ amdgpu_ucode_release(&adev->gfx.pfp_fw);
+ amdgpu_ucode_release(&adev->gfx.me_fw);
+ amdgpu_ucode_release(&adev->gfx.rlc_fw);
+ amdgpu_ucode_release(&adev->gfx.mec_fw);
}
return err;
}
-static int gfx_v11_0_init_toc_microcode(struct amdgpu_device *adev)
-{
- const struct psp_firmware_header_v1_0 *toc_hdr;
- int err = 0;
- char fw_name[40];
- char ucode_prefix[30];
-
- amdgpu_ucode_ip_version_decode(adev, GC_HWIP, ucode_prefix, sizeof(ucode_prefix));
-
- snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_toc.bin", ucode_prefix);
- err = request_firmware(&adev->psp.toc_fw, fw_name, adev->dev);
- if (err)
- goto out;
-
- err = amdgpu_ucode_validate(adev->psp.toc_fw);
- if (err)
- goto out;
-
- toc_hdr = (const struct psp_firmware_header_v1_0 *)adev->psp.toc_fw->data;
- adev->psp.toc.fw_version = le32_to_cpu(toc_hdr->header.ucode_version);
- adev->psp.toc.feature_version = le32_to_cpu(toc_hdr->sos.fw_version);
- adev->psp.toc.size_bytes = le32_to_cpu(toc_hdr->header.ucode_size_bytes);
- adev->psp.toc.start_addr = (uint8_t *)toc_hdr +
- le32_to_cpu(toc_hdr->header.ucode_array_offset_bytes);
- return 0;
-out:
- dev_err(adev->dev, "Failed to load TOC microcode\n");
- release_firmware(adev->psp.toc_fw);
- adev->psp.toc_fw = NULL;
- return err;
-}
-
static u32 gfx_v11_0_get_csb_size(struct amdgpu_device *adev)
{
u32 count = 0;
@@ -714,19 +686,11 @@ static void gfx_v11_0_mec_fini(struct amdgpu_device *adev)
amdgpu_bo_free_kernel(&adev->gfx.mec.mec_fw_data_obj, NULL, NULL);
}
-static int gfx_v11_0_me_init(struct amdgpu_device *adev)
+static void gfx_v11_0_me_init(struct amdgpu_device *adev)
{
- int r;
-
bitmap_zero(adev->gfx.me.queue_bitmap, AMDGPU_MAX_GFX_QUEUES);
amdgpu_gfx_graphics_queue_acquire(adev);
-
- r = gfx_v11_0_init_microcode(adev);
- if (r)
- DRM_ERROR("Failed to load gfx firmware!\n");
-
- return r;
}
static int gfx_v11_0_mec_init(struct amdgpu_device *adev)
@@ -852,7 +816,14 @@ static int gfx_v11_0_gpu_early_init(struct amdgpu_device *adev)
switch (adev->ip_versions[GC_HWIP][0]) {
case IP_VERSION(11, 0, 0):
case IP_VERSION(11, 0, 2):
+ adev->gfx.config.max_hw_contexts = 8;
+ adev->gfx.config.sc_prim_fifo_size_frontend = 0x20;
+ adev->gfx.config.sc_prim_fifo_size_backend = 0x100;
+ adev->gfx.config.sc_hiz_tile_fifo_size = 0;
+ adev->gfx.config.sc_earlyz_tile_fifo_size = 0x4C0;
+ break;
case IP_VERSION(11, 0, 3):
+ adev->gfx.ras = &gfx_v11_0_3_ras;
adev->gfx.config.max_hw_contexts = 8;
adev->gfx.config.sc_prim_fifo_size_frontend = 0x20;
adev->gfx.config.sc_prim_fifo_size_backend = 0x100;
@@ -987,10 +958,11 @@ static int gfx_v11_0_rlc_autoload_buffer_init(struct amdgpu_device *adev)
total_size = gfx_v11_0_calc_toc_total_size(adev);
r = amdgpu_bo_create_reserved(adev, total_size, 64 * 1024,
- AMDGPU_GEM_DOMAIN_VRAM,
- &adev->gfx.rlc.rlc_autoload_bo,
- &adev->gfx.rlc.rlc_autoload_gpu_addr,
- (void **)&adev->gfx.rlc.rlc_autoload_ptr);
+ AMDGPU_GEM_DOMAIN_VRAM |
+ AMDGPU_GEM_DOMAIN_GTT,
+ &adev->gfx.rlc.rlc_autoload_bo,
+ &adev->gfx.rlc.rlc_autoload_gpu_addr,
+ (void **)&adev->gfx.rlc.rlc_autoload_ptr);
if (r) {
dev_err(adev->dev, "(%d) failed to create fw autoload bo\n", r);
@@ -1336,6 +1308,20 @@ static int gfx_v11_0_sw_init(void *handle)
if (r)
return r;
+ /* ECC error */
+ r = amdgpu_irq_add_id(adev, SOC21_IH_CLIENTID_GRBM_CP,
+ GFX_11_0_0__SRCID__CP_ECC_ERROR,
+ &adev->gfx.cp_ecc_error_irq);
+ if (r)
+ return r;
+
+ /* FED error */
+ r = amdgpu_irq_add_id(adev, SOC21_IH_CLIENTID_GFX,
+ GFX_11_0_0__SRCID__RLC_GC_FED_INTERRUPT,
+ &adev->gfx.rlc_gc_fed_irq);
+ if (r)
+ return r;
+
adev->gfx.gfx_current_status = AMDGPU_GFX_NORMAL_MODE;
if (adev->gfx.imu.funcs) {
@@ -1346,9 +1332,7 @@ static int gfx_v11_0_sw_init(void *handle)
}
}
- r = gfx_v11_0_me_init(adev);
- if (r)
- return r;
+ gfx_v11_0_me_init(adev);
r = gfx_v11_0_rlc_init(adev);
if (r) {
@@ -1416,9 +1400,6 @@ static int gfx_v11_0_sw_init(void *handle)
/* allocate visible FB for rlc auto-loading fw */
if (adev->firmware.load_type == AMDGPU_FW_LOAD_RLC_BACKDOOR_AUTO) {
- r = gfx_v11_0_init_toc_microcode(adev);
- if (r)
- dev_err(adev->dev, "Failed to load toc firmware!\n");
r = gfx_v11_0_rlc_autoload_buffer_init(adev);
if (r)
return r;
@@ -1428,6 +1409,11 @@ static int gfx_v11_0_sw_init(void *handle)
if (r)
return r;
+ if (amdgpu_gfx_ras_sw_init(adev)) {
+ dev_err(adev->dev, "Failed to initialize gfx ras block!\n");
+ return -EINVAL;
+ }
+
return 0;
}
@@ -1517,44 +1503,70 @@ static void gfx_v11_0_select_se_sh(struct amdgpu_device *adev, u32 se_num,
WREG32_SOC15(GC, 0, regGRBM_GFX_INDEX, data);
}
-static u32 gfx_v11_0_get_rb_active_bitmap(struct amdgpu_device *adev)
+static u32 gfx_v11_0_get_sa_active_bitmap(struct amdgpu_device *adev)
{
- u32 data, mask;
+ u32 gc_disabled_sa_mask, gc_user_disabled_sa_mask, sa_mask;
- data = RREG32_SOC15(GC, 0, regCC_RB_BACKEND_DISABLE);
- data |= RREG32_SOC15(GC, 0, regGC_USER_RB_BACKEND_DISABLE);
+ gc_disabled_sa_mask = RREG32_SOC15(GC, 0, regCC_GC_SA_UNIT_DISABLE);
+ gc_disabled_sa_mask = REG_GET_FIELD(gc_disabled_sa_mask,
+ CC_GC_SA_UNIT_DISABLE,
+ SA_DISABLE);
+ gc_user_disabled_sa_mask = RREG32_SOC15(GC, 0, regGC_USER_SA_UNIT_DISABLE);
+ gc_user_disabled_sa_mask = REG_GET_FIELD(gc_user_disabled_sa_mask,
+ GC_USER_SA_UNIT_DISABLE,
+ SA_DISABLE);
+ sa_mask = amdgpu_gfx_create_bitmask(adev->gfx.config.max_sh_per_se *
+ adev->gfx.config.max_shader_engines);
- data &= CC_RB_BACKEND_DISABLE__BACKEND_DISABLE_MASK;
- data >>= GC_USER_RB_BACKEND_DISABLE__BACKEND_DISABLE__SHIFT;
+ return sa_mask & (~(gc_disabled_sa_mask | gc_user_disabled_sa_mask));
+}
- mask = amdgpu_gfx_create_bitmask(adev->gfx.config.max_backends_per_se /
- adev->gfx.config.max_sh_per_se);
+static u32 gfx_v11_0_get_rb_active_bitmap(struct amdgpu_device *adev)
+{
+ u32 gc_disabled_rb_mask, gc_user_disabled_rb_mask;
+ u32 rb_mask;
+
+ gc_disabled_rb_mask = RREG32_SOC15(GC, 0, regCC_RB_BACKEND_DISABLE);
+ gc_disabled_rb_mask = REG_GET_FIELD(gc_disabled_rb_mask,
+ CC_RB_BACKEND_DISABLE,
+ BACKEND_DISABLE);
+ gc_user_disabled_rb_mask = RREG32_SOC15(GC, 0, regGC_USER_RB_BACKEND_DISABLE);
+ gc_user_disabled_rb_mask = REG_GET_FIELD(gc_user_disabled_rb_mask,
+ GC_USER_RB_BACKEND_DISABLE,
+ BACKEND_DISABLE);
+ rb_mask = amdgpu_gfx_create_bitmask(adev->gfx.config.max_backends_per_se *
+ adev->gfx.config.max_shader_engines);
- return (~data) & mask;
+ return rb_mask & (~(gc_disabled_rb_mask | gc_user_disabled_rb_mask));
}
static void gfx_v11_0_setup_rb(struct amdgpu_device *adev)
{
- int i, j;
- u32 data;
- u32 active_rbs = 0;
- u32 rb_bitmap_width_per_sh = adev->gfx.config.max_backends_per_se /
- adev->gfx.config.max_sh_per_se;
+ u32 rb_bitmap_width_per_sa;
+ u32 max_sa;
+ u32 active_sa_bitmap;
+ u32 global_active_rb_bitmap;
+ u32 active_rb_bitmap = 0;
+ u32 i;
- mutex_lock(&adev->grbm_idx_mutex);
- for (i = 0; i < adev->gfx.config.max_shader_engines; i++) {
- for (j = 0; j < adev->gfx.config.max_sh_per_se; j++) {
- gfx_v11_0_select_se_sh(adev, i, j, 0xffffffff);
- data = gfx_v11_0_get_rb_active_bitmap(adev);
- active_rbs |= data << ((i * adev->gfx.config.max_sh_per_se + j) *
- rb_bitmap_width_per_sh);
- }
+ /* query sa bitmap from SA_UNIT_DISABLE registers */
+ active_sa_bitmap = gfx_v11_0_get_sa_active_bitmap(adev);
+ /* query rb bitmap from RB_BACKEND_DISABLE registers */
+ global_active_rb_bitmap = gfx_v11_0_get_rb_active_bitmap(adev);
+
+ /* generate active rb bitmap according to active sa bitmap */
+ max_sa = adev->gfx.config.max_shader_engines *
+ adev->gfx.config.max_sh_per_se;
+ rb_bitmap_width_per_sa = adev->gfx.config.max_backends_per_se /
+ adev->gfx.config.max_sh_per_se;
+ for (i = 0; i < max_sa; i++) {
+ if (active_sa_bitmap & (1 << i))
+ active_rb_bitmap |= (0x3 << (i * rb_bitmap_width_per_sa));
}
- gfx_v11_0_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff);
- mutex_unlock(&adev->grbm_idx_mutex);
- adev->gfx.config.backend_enable_mask = active_rbs;
- adev->gfx.config.num_rbs = hweight32(active_rbs);
+ active_rb_bitmap |= global_active_rb_bitmap;
+ adev->gfx.config.backend_enable_mask = active_rb_bitmap;
+ adev->gfx.config.num_rbs = hweight32(active_rb_bitmap);
}
#define DEFAULT_SH_MEM_BASES (0x6000)
@@ -1647,6 +1659,11 @@ static void gfx_v11_0_constants_init(struct amdgpu_device *adev)
gfx_v11_0_get_tcc_info(adev);
adev->gfx.config.pa_sc_tile_steering_override = 0;
+ /* Set whether texture coordinate truncation is conformant. */
+ tmp = RREG32_SOC15(GC, 0, regTA_CNTL2);
+ adev->gfx.config.ta_cntl2_truncate_coord_mode =
+ REG_GET_FIELD(tmp, TA_CNTL2, TRUNCATE_COORD_MODE);
+
/* XXX SH_MEM regs */
/* where to put LDS, scratch, GPUVM in FSA64 space */
mutex_lock(&adev->srbm_mutex);
@@ -2656,7 +2673,9 @@ static int gfx_v11_0_cp_gfx_load_pfp_microcode_rs64(struct amdgpu_device *adev)
/* 64kb align */
r = amdgpu_bo_create_reserved(adev, fw_ucode_size,
- 64 * 1024, AMDGPU_GEM_DOMAIN_VRAM,
+ 64 * 1024,
+ AMDGPU_GEM_DOMAIN_VRAM |
+ AMDGPU_GEM_DOMAIN_GTT,
&adev->gfx.pfp.pfp_fw_obj,
&adev->gfx.pfp.pfp_fw_gpu_addr,
(void **)&adev->gfx.pfp.pfp_fw_ptr);
@@ -2667,7 +2686,9 @@ static int gfx_v11_0_cp_gfx_load_pfp_microcode_rs64(struct amdgpu_device *adev)
}
r = amdgpu_bo_create_reserved(adev, fw_data_size,
- 64 * 1024, AMDGPU_GEM_DOMAIN_VRAM,
+ 64 * 1024,
+ AMDGPU_GEM_DOMAIN_VRAM |
+ AMDGPU_GEM_DOMAIN_GTT,
&adev->gfx.pfp.pfp_fw_data_obj,
&adev->gfx.pfp.pfp_fw_data_gpu_addr,
(void **)&adev->gfx.pfp.pfp_fw_data_ptr);
@@ -2870,7 +2891,9 @@ static int gfx_v11_0_cp_gfx_load_me_microcode_rs64(struct amdgpu_device *adev)
/* 64kb align*/
r = amdgpu_bo_create_reserved(adev, fw_ucode_size,
- 64 * 1024, AMDGPU_GEM_DOMAIN_VRAM,
+ 64 * 1024,
+ AMDGPU_GEM_DOMAIN_VRAM |
+ AMDGPU_GEM_DOMAIN_GTT,
&adev->gfx.me.me_fw_obj,
&adev->gfx.me.me_fw_gpu_addr,
(void **)&adev->gfx.me.me_fw_ptr);
@@ -2881,7 +2904,9 @@ static int gfx_v11_0_cp_gfx_load_me_microcode_rs64(struct amdgpu_device *adev)
}
r = amdgpu_bo_create_reserved(adev, fw_data_size,
- 64 * 1024, AMDGPU_GEM_DOMAIN_VRAM,
+ 64 * 1024,
+ AMDGPU_GEM_DOMAIN_VRAM |
+ AMDGPU_GEM_DOMAIN_GTT,
&adev->gfx.me.me_fw_data_obj,
&adev->gfx.me.me_fw_data_gpu_addr,
(void **)&adev->gfx.me.me_fw_data_ptr);
@@ -3387,7 +3412,9 @@ static int gfx_v11_0_cp_compute_load_microcode_rs64(struct amdgpu_device *adev)
fw_data_size = le32_to_cpu(mec_hdr->data_size_bytes);
r = amdgpu_bo_create_reserved(adev, fw_ucode_size,
- 64 * 1024, AMDGPU_GEM_DOMAIN_VRAM,
+ 64 * 1024,
+ AMDGPU_GEM_DOMAIN_VRAM |
+ AMDGPU_GEM_DOMAIN_GTT,
&adev->gfx.mec.mec_fw_obj,
&adev->gfx.mec.mec_fw_gpu_addr,
(void **)&fw_ucode_ptr);
@@ -3398,7 +3425,9 @@ static int gfx_v11_0_cp_compute_load_microcode_rs64(struct amdgpu_device *adev)
}
r = amdgpu_bo_create_reserved(adev, fw_data_size,
- 64 * 1024, AMDGPU_GEM_DOMAIN_VRAM,
+ 64 * 1024,
+ AMDGPU_GEM_DOMAIN_VRAM |
+ AMDGPU_GEM_DOMAIN_GTT,
&adev->gfx.mec.mec_fw_data_obj,
&adev->gfx.mec.mec_fw_data_gpu_addr,
(void **)&fw_data_ptr);
@@ -4408,6 +4437,7 @@ static int gfx_v11_0_hw_fini(void *handle)
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
int r;
+ amdgpu_irq_put(adev, &adev->gfx.cp_ecc_error_irq, 0);
amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0);
amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0);
@@ -4687,7 +4717,7 @@ static int gfx_v11_0_early_init(void *handle)
gfx_v11_0_init_rlcg_reg_access_ctrl(adev);
- return 0;
+ return gfx_v11_0_init_microcode(adev);
}
static int gfx_v11_0_ras_late_init(void *handle)
@@ -5839,6 +5869,36 @@ static void gfx_v11_0_set_compute_eop_interrupt_state(struct amdgpu_device *adev
}
}
+#define CP_ME1_PIPE_INST_ADDR_INTERVAL 0x1
+#define SET_ECC_ME_PIPE_STATE(reg_addr, state) \
+ do { \
+ uint32_t tmp = RREG32_SOC15_IP(GC, reg_addr); \
+ tmp = REG_SET_FIELD(tmp, CP_ME1_PIPE0_INT_CNTL, CP_ECC_ERROR_INT_ENABLE, state); \
+ WREG32_SOC15_IP(GC, reg_addr, tmp); \
+ } while (0)
+
+static int gfx_v11_0_set_cp_ecc_error_state(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *source,
+ unsigned type,
+ enum amdgpu_interrupt_state state)
+{
+ uint32_t ecc_irq_state = 0;
+ uint32_t pipe0_int_cntl_addr = 0;
+ int i = 0;
+
+ ecc_irq_state = (state == AMDGPU_IRQ_STATE_ENABLE) ? 1 : 0;
+
+ pipe0_int_cntl_addr = SOC15_REG_OFFSET(GC, 0, regCP_ME1_PIPE0_INT_CNTL);
+
+ WREG32_FIELD15_PREREG(GC, 0, CP_INT_CNTL_RING0, CP_ECC_ERROR_INT_ENABLE, ecc_irq_state);
+
+ for (i = 0; i < adev->gfx.mec.num_pipe_per_mec; i++)
+ SET_ECC_ME_PIPE_STATE(pipe0_int_cntl_addr + i * CP_ME1_PIPE_INST_ADDR_INTERVAL,
+ ecc_irq_state);
+
+ return 0;
+}
+
static int gfx_v11_0_set_eop_interrupt_state(struct amdgpu_device *adev,
struct amdgpu_irq_src *src,
unsigned type,
@@ -6015,6 +6075,16 @@ static int gfx_v11_0_priv_inst_irq(struct amdgpu_device *adev,
return 0;
}
+static int gfx_v11_0_rlc_gc_fed_irq(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *source,
+ struct amdgpu_iv_entry *entry)
+{
+ if (adev->gfx.ras && adev->gfx.ras->rlc_gc_fed_irq)
+ return adev->gfx.ras->rlc_gc_fed_irq(adev, source, entry);
+
+ return 0;
+}
+
#if 0
static int gfx_v11_0_kiq_set_interrupt_state(struct amdgpu_device *adev,
struct amdgpu_irq_src *src,
@@ -6245,6 +6315,15 @@ static const struct amdgpu_irq_src_funcs gfx_v11_0_priv_inst_irq_funcs = {
.process = gfx_v11_0_priv_inst_irq,
};
+static const struct amdgpu_irq_src_funcs gfx_v11_0_cp_ecc_error_irq_funcs = {
+ .set = gfx_v11_0_set_cp_ecc_error_state,
+ .process = amdgpu_gfx_cp_ecc_error_irq,
+};
+
+static const struct amdgpu_irq_src_funcs gfx_v11_0_rlc_gc_fed_irq_funcs = {
+ .process = gfx_v11_0_rlc_gc_fed_irq,
+};
+
static void gfx_v11_0_set_irq_funcs(struct amdgpu_device *adev)
{
adev->gfx.eop_irq.num_types = AMDGPU_CP_IRQ_LAST;
@@ -6255,6 +6334,13 @@ static void gfx_v11_0_set_irq_funcs(struct amdgpu_device *adev)
adev->gfx.priv_inst_irq.num_types = 1;
adev->gfx.priv_inst_irq.funcs = &gfx_v11_0_priv_inst_irq_funcs;
+
+ adev->gfx.cp_ecc_error_irq.num_types = 1; /* CP ECC error */
+ adev->gfx.cp_ecc_error_irq.funcs = &gfx_v11_0_cp_ecc_error_irq_funcs;
+
+ adev->gfx.rlc_gc_fed_irq.num_types = 1; /* 0x80 FED error */
+ adev->gfx.rlc_gc_fed_irq.funcs = &gfx_v11_0_rlc_gc_fed_irq_funcs;
+
}
static void gfx_v11_0_set_imu_funcs(struct amdgpu_device *adev)
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0_3.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0_3.c
new file mode 100644
index 000000000000..b07a72ca25d9
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0_3.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2023 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ */
+
+#include "amdgpu.h"
+#include "soc21.h"
+#include "gc/gc_11_0_3_offset.h"
+#include "gc/gc_11_0_3_sh_mask.h"
+#include "ivsrcid/gfx/irqsrcs_gfx_11_0_0.h"
+#include "soc15.h"
+#include "soc15d.h"
+#include "gfx_v11_0.h"
+
+
+static int gfx_v11_0_3_rlc_gc_fed_irq(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *source,
+ struct amdgpu_iv_entry *entry)
+{
+ uint32_t rlc_status0 = 0, rlc_status1 = 0;
+ struct ras_common_if *ras_if = NULL;
+ struct ras_dispatch_if ih_data = {
+ .entry = entry,
+ };
+
+ rlc_status0 = RREG32(SOC15_REG_OFFSET(GC, 0, regRLC_RLCS_FED_STATUS_0));
+ rlc_status1 = RREG32(SOC15_REG_OFFSET(GC, 0, regRLC_RLCS_FED_STATUS_1));
+
+ if (!rlc_status0 && !rlc_status1) {
+ dev_warn(adev->dev, "RLC_GC_FED irq is generated, but rlc_status0 and rlc_status1 are empty!\n");
+ return 0;
+ }
+
+ /* Use RLC_RLCS_FED_STATUS_0/1 to distinguish FED error block. */
+ if (REG_GET_FIELD(rlc_status0, RLC_RLCS_FED_STATUS_0, SDMA0_FED_ERR) ||
+ REG_GET_FIELD(rlc_status0, RLC_RLCS_FED_STATUS_0, SDMA1_FED_ERR))
+ ras_if = adev->sdma.ras_if;
+ else
+ ras_if = adev->gfx.ras_if;
+
+ if (!ras_if) {
+ dev_err(adev->dev, "Gfx or sdma ras block not initialized, rlc_status0:0x%x.\n",
+ rlc_status0);
+ return -EINVAL;
+ }
+
+ ih_data.head = *ras_if;
+
+ dev_warn(adev->dev, "RLC %s FED IRQ\n", ras_if->name);
+ amdgpu_ras_interrupt_dispatch(adev, &ih_data);
+
+ return 0;
+}
+
+static int gfx_v11_0_3_poison_consumption_handler(struct amdgpu_device *adev,
+ struct amdgpu_iv_entry *entry)
+{
+ /* Workaround: when vmid and pasid are both zero, trigger gpu reset in KGD. */
+ if (entry && (entry->client_id == SOC21_IH_CLIENTID_GFX) &&
+ (entry->src_id == GFX_11_0_0__SRCID__RLC_GC_FED_INTERRUPT) &&
+ !entry->vmid && !entry->pasid)
+ amdgpu_ras_reset_gpu(adev);
+
+ return 0;
+}
+
+struct amdgpu_gfx_ras gfx_v11_0_3_ras = {
+ .rlc_gc_fed_irq = gfx_v11_0_3_rlc_gc_fed_irq,
+ .poison_consumption_handler = gfx_v11_0_3_poison_consumption_handler,
+};
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0_3.h b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0_3.h
new file mode 100644
index 000000000000..672c7920b3d0
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0_3.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2023 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ */
+
+#ifndef __GFX_V11_0_3_H__
+#define __GFX_V11_0_3_H__
+
+extern struct amdgpu_gfx_ras gfx_v11_0_3_ras;
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
index 204b246f0e3f..c41219e23151 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c
@@ -338,10 +338,7 @@ static int gfx_v6_0_init_microcode(struct amdgpu_device *adev)
}
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_pfp.bin", chip_name);
- err = request_firmware(&adev->gfx.pfp_fw, fw_name, adev->dev);
- if (err)
- goto out;
- err = amdgpu_ucode_validate(adev->gfx.pfp_fw);
+ err = amdgpu_ucode_request(adev, &adev->gfx.pfp_fw, fw_name);
if (err)
goto out;
cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.pfp_fw->data;
@@ -349,10 +346,7 @@ static int gfx_v6_0_init_microcode(struct amdgpu_device *adev)
adev->gfx.pfp_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version);
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_me.bin", chip_name);
- err = request_firmware(&adev->gfx.me_fw, fw_name, adev->dev);
- if (err)
- goto out;
- err = amdgpu_ucode_validate(adev->gfx.me_fw);
+ err = amdgpu_ucode_request(adev, &adev->gfx.me_fw, fw_name);
if (err)
goto out;
cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.me_fw->data;
@@ -360,10 +354,7 @@ static int gfx_v6_0_init_microcode(struct amdgpu_device *adev)
adev->gfx.me_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version);
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ce.bin", chip_name);
- err = request_firmware(&adev->gfx.ce_fw, fw_name, adev->dev);
- if (err)
- goto out;
- err = amdgpu_ucode_validate(adev->gfx.ce_fw);
+ err = amdgpu_ucode_request(adev, &adev->gfx.ce_fw, fw_name);
if (err)
goto out;
cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.ce_fw->data;
@@ -371,10 +362,9 @@ static int gfx_v6_0_init_microcode(struct amdgpu_device *adev)
adev->gfx.ce_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version);
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_rlc.bin", chip_name);
- err = request_firmware(&adev->gfx.rlc_fw, fw_name, adev->dev);
+ err = amdgpu_ucode_request(adev, &adev->gfx.rlc_fw, fw_name);
if (err)
goto out;
- err = amdgpu_ucode_validate(adev->gfx.rlc_fw);
rlc_hdr = (const struct rlc_firmware_header_v1_0 *)adev->gfx.rlc_fw->data;
adev->gfx.rlc_fw_version = le32_to_cpu(rlc_hdr->header.ucode_version);
adev->gfx.rlc_feature_version = le32_to_cpu(rlc_hdr->ucode_feature_version);
@@ -382,14 +372,10 @@ static int gfx_v6_0_init_microcode(struct amdgpu_device *adev)
out:
if (err) {
pr_err("gfx6: Failed to load firmware \"%s\"\n", fw_name);
- release_firmware(adev->gfx.pfp_fw);
- adev->gfx.pfp_fw = NULL;
- release_firmware(adev->gfx.me_fw);
- adev->gfx.me_fw = NULL;
- release_firmware(adev->gfx.ce_fw);
- adev->gfx.ce_fw = NULL;
- release_firmware(adev->gfx.rlc_fw);
- adev->gfx.rlc_fw = NULL;
+ amdgpu_ucode_release(&adev->gfx.pfp_fw);
+ amdgpu_ucode_release(&adev->gfx.me_fw);
+ amdgpu_ucode_release(&adev->gfx.ce_fw);
+ amdgpu_ucode_release(&adev->gfx.rlc_fw);
}
return err;
}
@@ -2375,7 +2361,8 @@ static int gfx_v6_0_rlc_init(struct amdgpu_device *adev)
dws = adev->gfx.rlc.clear_state_size + (256 / 4);
r = amdgpu_bo_create_reserved(adev, dws * 4, PAGE_SIZE,
- AMDGPU_GEM_DOMAIN_VRAM,
+ AMDGPU_GEM_DOMAIN_VRAM |
+ AMDGPU_GEM_DOMAIN_GTT,
&adev->gfx.rlc.clear_state_obj,
&adev->gfx.rlc.clear_state_gpu_addr,
(void **)&adev->gfx.rlc.cs_ptr);
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c
index 0f2976507e48..9d5c1e29b4a3 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c
@@ -887,6 +887,16 @@ static void gfx_v7_0_get_csb_buffer(struct amdgpu_device *adev, volatile u32 *bu
static void gfx_v7_0_init_pg(struct amdgpu_device *adev);
static void gfx_v7_0_get_cu_info(struct amdgpu_device *adev);
+static void gfx_v7_0_free_microcode(struct amdgpu_device *adev)
+{
+ amdgpu_ucode_release(&adev->gfx.pfp_fw);
+ amdgpu_ucode_release(&adev->gfx.me_fw);
+ amdgpu_ucode_release(&adev->gfx.ce_fw);
+ amdgpu_ucode_release(&adev->gfx.mec_fw);
+ amdgpu_ucode_release(&adev->gfx.mec2_fw);
+ amdgpu_ucode_release(&adev->gfx.rlc_fw);
+}
+
/*
* Core functions
*/
@@ -927,88 +937,44 @@ static int gfx_v7_0_init_microcode(struct amdgpu_device *adev)
}
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_pfp.bin", chip_name);
- err = request_firmware(&adev->gfx.pfp_fw, fw_name, adev->dev);
- if (err)
- goto out;
- err = amdgpu_ucode_validate(adev->gfx.pfp_fw);
+ err = amdgpu_ucode_request(adev, &adev->gfx.pfp_fw, fw_name);
if (err)
goto out;
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_me.bin", chip_name);
- err = request_firmware(&adev->gfx.me_fw, fw_name, adev->dev);
- if (err)
- goto out;
- err = amdgpu_ucode_validate(adev->gfx.me_fw);
+ err = amdgpu_ucode_request(adev, &adev->gfx.me_fw, fw_name);
if (err)
goto out;
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ce.bin", chip_name);
- err = request_firmware(&adev->gfx.ce_fw, fw_name, adev->dev);
- if (err)
- goto out;
- err = amdgpu_ucode_validate(adev->gfx.ce_fw);
+ err = amdgpu_ucode_request(adev, &adev->gfx.ce_fw, fw_name);
if (err)
goto out;
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec.bin", chip_name);
- err = request_firmware(&adev->gfx.mec_fw, fw_name, adev->dev);
- if (err)
- goto out;
- err = amdgpu_ucode_validate(adev->gfx.mec_fw);
+ err = amdgpu_ucode_request(adev, &adev->gfx.mec_fw, fw_name);
if (err)
goto out;
if (adev->asic_type == CHIP_KAVERI) {
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec2.bin", chip_name);
- err = request_firmware(&adev->gfx.mec2_fw, fw_name, adev->dev);
- if (err)
- goto out;
- err = amdgpu_ucode_validate(adev->gfx.mec2_fw);
+ err = amdgpu_ucode_request(adev, &adev->gfx.mec2_fw, fw_name);
if (err)
goto out;
}
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_rlc.bin", chip_name);
- err = request_firmware(&adev->gfx.rlc_fw, fw_name, adev->dev);
+ err = amdgpu_ucode_request(adev, &adev->gfx.rlc_fw, fw_name);
if (err)
goto out;
- err = amdgpu_ucode_validate(adev->gfx.rlc_fw);
-
out:
if (err) {
pr_err("gfx7: Failed to load firmware \"%s\"\n", fw_name);
- release_firmware(adev->gfx.pfp_fw);
- adev->gfx.pfp_fw = NULL;
- release_firmware(adev->gfx.me_fw);
- adev->gfx.me_fw = NULL;
- release_firmware(adev->gfx.ce_fw);
- adev->gfx.ce_fw = NULL;
- release_firmware(adev->gfx.mec_fw);
- adev->gfx.mec_fw = NULL;
- release_firmware(adev->gfx.mec2_fw);
- adev->gfx.mec2_fw = NULL;
- release_firmware(adev->gfx.rlc_fw);
- adev->gfx.rlc_fw = NULL;
+ gfx_v7_0_free_microcode(adev);
}
return err;
}
-static void gfx_v7_0_free_microcode(struct amdgpu_device *adev)
-{
- release_firmware(adev->gfx.pfp_fw);
- adev->gfx.pfp_fw = NULL;
- release_firmware(adev->gfx.me_fw);
- adev->gfx.me_fw = NULL;
- release_firmware(adev->gfx.ce_fw);
- adev->gfx.ce_fw = NULL;
- release_firmware(adev->gfx.mec_fw);
- adev->gfx.mec_fw = NULL;
- release_firmware(adev->gfx.mec2_fw);
- adev->gfx.mec2_fw = NULL;
- release_firmware(adev->gfx.rlc_fw);
- adev->gfx.rlc_fw = NULL;
-}
-
/**
* gfx_v7_0_tiling_mode_table_init - init the hw tiling table
*
@@ -2772,7 +2738,8 @@ static int gfx_v7_0_mec_init(struct amdgpu_device *adev)
* GFX7_MEC_HPD_SIZE * 2;
r = amdgpu_bo_create_reserved(adev, mec_hpd_size, PAGE_SIZE,
- AMDGPU_GEM_DOMAIN_VRAM,
+ AMDGPU_GEM_DOMAIN_VRAM |
+ AMDGPU_GEM_DOMAIN_GTT,
&adev->gfx.mec.hpd_eop_obj,
&adev->gfx.mec.hpd_eop_gpu_addr,
(void **)&hpd);
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
index d47135606e3e..b1f2684d854a 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
@@ -924,20 +924,14 @@ err1:
static void gfx_v8_0_free_microcode(struct amdgpu_device *adev)
{
- release_firmware(adev->gfx.pfp_fw);
- adev->gfx.pfp_fw = NULL;
- release_firmware(adev->gfx.me_fw);
- adev->gfx.me_fw = NULL;
- release_firmware(adev->gfx.ce_fw);
- adev->gfx.ce_fw = NULL;
- release_firmware(adev->gfx.rlc_fw);
- adev->gfx.rlc_fw = NULL;
- release_firmware(adev->gfx.mec_fw);
- adev->gfx.mec_fw = NULL;
+ amdgpu_ucode_release(&adev->gfx.pfp_fw);
+ amdgpu_ucode_release(&adev->gfx.me_fw);
+ amdgpu_ucode_release(&adev->gfx.ce_fw);
+ amdgpu_ucode_release(&adev->gfx.rlc_fw);
+ amdgpu_ucode_release(&adev->gfx.mec_fw);
if ((adev->asic_type != CHIP_STONEY) &&
(adev->asic_type != CHIP_TOPAZ))
- release_firmware(adev->gfx.mec2_fw);
- adev->gfx.mec2_fw = NULL;
+ amdgpu_ucode_release(&adev->gfx.mec2_fw);
kfree(adev->gfx.rlc.register_list_format);
}
@@ -989,40 +983,34 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev)
if (adev->asic_type >= CHIP_POLARIS10 && adev->asic_type <= CHIP_POLARIS12) {
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_pfp_2.bin", chip_name);
- err = request_firmware(&adev->gfx.pfp_fw, fw_name, adev->dev);
- if (err == -ENOENT) {
+ err = amdgpu_ucode_request(adev, &adev->gfx.pfp_fw, fw_name);
+ if (err == -ENODEV) {
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_pfp.bin", chip_name);
- err = request_firmware(&adev->gfx.pfp_fw, fw_name, adev->dev);
+ err = amdgpu_ucode_request(adev, &adev->gfx.pfp_fw, fw_name);
}
} else {
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_pfp.bin", chip_name);
- err = request_firmware(&adev->gfx.pfp_fw, fw_name, adev->dev);
+ err = amdgpu_ucode_request(adev, &adev->gfx.pfp_fw, fw_name);
}
if (err)
goto out;
- err = amdgpu_ucode_validate(adev->gfx.pfp_fw);
- if (err)
- goto out;
cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.pfp_fw->data;
adev->gfx.pfp_fw_version = le32_to_cpu(cp_hdr->header.ucode_version);
adev->gfx.pfp_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version);
if (adev->asic_type >= CHIP_POLARIS10 && adev->asic_type <= CHIP_POLARIS12) {
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_me_2.bin", chip_name);
- err = request_firmware(&adev->gfx.me_fw, fw_name, adev->dev);
- if (err == -ENOENT) {
+ err = amdgpu_ucode_request(adev, &adev->gfx.me_fw, fw_name);
+ if (err == -ENODEV) {
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_me.bin", chip_name);
- err = request_firmware(&adev->gfx.me_fw, fw_name, adev->dev);
+ err = amdgpu_ucode_request(adev, &adev->gfx.me_fw, fw_name);
}
} else {
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_me.bin", chip_name);
- err = request_firmware(&adev->gfx.me_fw, fw_name, adev->dev);
+ err = amdgpu_ucode_request(adev, &adev->gfx.me_fw, fw_name);
}
if (err)
goto out;
- err = amdgpu_ucode_validate(adev->gfx.me_fw);
- if (err)
- goto out;
cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.me_fw->data;
adev->gfx.me_fw_version = le32_to_cpu(cp_hdr->header.ucode_version);
@@ -1030,20 +1018,17 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev)
if (adev->asic_type >= CHIP_POLARIS10 && adev->asic_type <= CHIP_POLARIS12) {
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ce_2.bin", chip_name);
- err = request_firmware(&adev->gfx.ce_fw, fw_name, adev->dev);
- if (err == -ENOENT) {
+ err = amdgpu_ucode_request(adev, &adev->gfx.ce_fw, fw_name);
+ if (err == -ENODEV) {
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ce.bin", chip_name);
- err = request_firmware(&adev->gfx.ce_fw, fw_name, adev->dev);
+ err = amdgpu_ucode_request(adev, &adev->gfx.ce_fw, fw_name);
}
} else {
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ce.bin", chip_name);
- err = request_firmware(&adev->gfx.ce_fw, fw_name, adev->dev);
+ err = amdgpu_ucode_request(adev, &adev->gfx.ce_fw, fw_name);
}
if (err)
goto out;
- err = amdgpu_ucode_validate(adev->gfx.ce_fw);
- if (err)
- goto out;
cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.ce_fw->data;
adev->gfx.ce_fw_version = le32_to_cpu(cp_hdr->header.ucode_version);
adev->gfx.ce_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version);
@@ -1060,10 +1045,9 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev)
adev->virt.chained_ib_support = false;
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_rlc.bin", chip_name);
- err = request_firmware(&adev->gfx.rlc_fw, fw_name, adev->dev);
+ err = amdgpu_ucode_request(adev, &adev->gfx.rlc_fw, fw_name);
if (err)
goto out;
- err = amdgpu_ucode_validate(adev->gfx.rlc_fw);
rlc_hdr = (const struct rlc_firmware_header_v2_0 *)adev->gfx.rlc_fw->data;
adev->gfx.rlc_fw_version = le32_to_cpu(rlc_hdr->header.ucode_version);
adev->gfx.rlc_feature_version = le32_to_cpu(rlc_hdr->ucode_feature_version);
@@ -1110,20 +1094,17 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev)
if (adev->asic_type >= CHIP_POLARIS10 && adev->asic_type <= CHIP_POLARIS12) {
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec_2.bin", chip_name);
- err = request_firmware(&adev->gfx.mec_fw, fw_name, adev->dev);
- if (err == -ENOENT) {
+ err = amdgpu_ucode_request(adev, &adev->gfx.mec_fw, fw_name);
+ if (err == -ENODEV) {
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec.bin", chip_name);
- err = request_firmware(&adev->gfx.mec_fw, fw_name, adev->dev);
+ err = amdgpu_ucode_request(adev, &adev->gfx.mec_fw, fw_name);
}
} else {
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec.bin", chip_name);
- err = request_firmware(&adev->gfx.mec_fw, fw_name, adev->dev);
+ err = amdgpu_ucode_request(adev, &adev->gfx.mec_fw, fw_name);
}
if (err)
goto out;
- err = amdgpu_ucode_validate(adev->gfx.mec_fw);
- if (err)
- goto out;
cp_hdr = (const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data;
adev->gfx.mec_fw_version = le32_to_cpu(cp_hdr->header.ucode_version);
adev->gfx.mec_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version);
@@ -1132,19 +1113,16 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev)
(adev->asic_type != CHIP_TOPAZ)) {
if (adev->asic_type >= CHIP_POLARIS10 && adev->asic_type <= CHIP_POLARIS12) {
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec2_2.bin", chip_name);
- err = request_firmware(&adev->gfx.mec2_fw, fw_name, adev->dev);
- if (err == -ENOENT) {
+ err = amdgpu_ucode_request(adev, &adev->gfx.mec2_fw, fw_name);
+ if (err == -ENODEV) {
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec2.bin", chip_name);
- err = request_firmware(&adev->gfx.mec2_fw, fw_name, adev->dev);
+ err = amdgpu_ucode_request(adev, &adev->gfx.mec2_fw, fw_name);
}
} else {
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec2.bin", chip_name);
- err = request_firmware(&adev->gfx.mec2_fw, fw_name, adev->dev);
+ err = amdgpu_ucode_request(adev, &adev->gfx.mec2_fw, fw_name);
}
if (!err) {
- err = amdgpu_ucode_validate(adev->gfx.mec2_fw);
- if (err)
- goto out;
cp_hdr = (const struct gfx_firmware_header_v1_0 *)
adev->gfx.mec2_fw->data;
adev->gfx.mec2_fw_version =
@@ -1219,18 +1197,12 @@ out:
dev_err(adev->dev,
"gfx8: Failed to load firmware \"%s\"\n",
fw_name);
- release_firmware(adev->gfx.pfp_fw);
- adev->gfx.pfp_fw = NULL;
- release_firmware(adev->gfx.me_fw);
- adev->gfx.me_fw = NULL;
- release_firmware(adev->gfx.ce_fw);
- adev->gfx.ce_fw = NULL;
- release_firmware(adev->gfx.rlc_fw);
- adev->gfx.rlc_fw = NULL;
- release_firmware(adev->gfx.mec_fw);
- adev->gfx.mec_fw = NULL;
- release_firmware(adev->gfx.mec2_fw);
- adev->gfx.mec2_fw = NULL;
+ amdgpu_ucode_release(&adev->gfx.pfp_fw);
+ amdgpu_ucode_release(&adev->gfx.me_fw);
+ amdgpu_ucode_release(&adev->gfx.ce_fw);
+ amdgpu_ucode_release(&adev->gfx.rlc_fw);
+ amdgpu_ucode_release(&adev->gfx.mec_fw);
+ amdgpu_ucode_release(&adev->gfx.mec2_fw);
}
return err;
}
@@ -1340,7 +1312,8 @@ static int gfx_v8_0_mec_init(struct amdgpu_device *adev)
mec_hpd_size = adev->gfx.num_compute_rings * GFX8_MEC_HPD_SIZE;
if (mec_hpd_size) {
r = amdgpu_bo_create_reserved(adev, mec_hpd_size, PAGE_SIZE,
- AMDGPU_GEM_DOMAIN_VRAM,
+ AMDGPU_GEM_DOMAIN_VRAM |
+ AMDGPU_GEM_DOMAIN_GTT,
&adev->gfx.mec.hpd_eop_obj,
&adev->gfx.mec.hpd_eop_gpu_addr,
(void **)&hpd);
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
index 5dde6f82a1ca..ae09fc1cfe6b 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
@@ -1078,18 +1078,12 @@ err1:
static void gfx_v9_0_free_microcode(struct amdgpu_device *adev)
{
- release_firmware(adev->gfx.pfp_fw);
- adev->gfx.pfp_fw = NULL;
- release_firmware(adev->gfx.me_fw);
- adev->gfx.me_fw = NULL;
- release_firmware(adev->gfx.ce_fw);
- adev->gfx.ce_fw = NULL;
- release_firmware(adev->gfx.rlc_fw);
- adev->gfx.rlc_fw = NULL;
- release_firmware(adev->gfx.mec_fw);
- adev->gfx.mec_fw = NULL;
- release_firmware(adev->gfx.mec2_fw);
- adev->gfx.mec2_fw = NULL;
+ amdgpu_ucode_release(&adev->gfx.pfp_fw);
+ amdgpu_ucode_release(&adev->gfx.me_fw);
+ amdgpu_ucode_release(&adev->gfx.ce_fw);
+ amdgpu_ucode_release(&adev->gfx.rlc_fw);
+ amdgpu_ucode_release(&adev->gfx.mec_fw);
+ amdgpu_ucode_release(&adev->gfx.mec2_fw);
kfree(adev->gfx.rlc.register_list_format);
}
@@ -1251,55 +1245,40 @@ static void gfx_v9_0_check_if_need_gfxoff(struct amdgpu_device *adev)
}
static int gfx_v9_0_init_cp_gfx_microcode(struct amdgpu_device *adev,
- const char *chip_name)
+ char *chip_name)
{
char fw_name[30];
int err;
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_pfp.bin", chip_name);
- err = request_firmware(&adev->gfx.pfp_fw, fw_name, adev->dev);
- if (err)
- goto out;
- err = amdgpu_ucode_validate(adev->gfx.pfp_fw);
+ err = amdgpu_ucode_request(adev, &adev->gfx.pfp_fw, fw_name);
if (err)
goto out;
amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_PFP);
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_me.bin", chip_name);
- err = request_firmware(&adev->gfx.me_fw, fw_name, adev->dev);
- if (err)
- goto out;
- err = amdgpu_ucode_validate(adev->gfx.me_fw);
+ err = amdgpu_ucode_request(adev, &adev->gfx.me_fw, fw_name);
if (err)
goto out;
amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_ME);
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ce.bin", chip_name);
- err = request_firmware(&adev->gfx.ce_fw, fw_name, adev->dev);
- if (err)
- goto out;
- err = amdgpu_ucode_validate(adev->gfx.ce_fw);
+ err = amdgpu_ucode_request(adev, &adev->gfx.ce_fw, fw_name);
if (err)
goto out;
amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_CE);
out:
if (err) {
- dev_err(adev->dev,
- "gfx9: Failed to init firmware \"%s\"\n",
- fw_name);
- release_firmware(adev->gfx.pfp_fw);
- adev->gfx.pfp_fw = NULL;
- release_firmware(adev->gfx.me_fw);
- adev->gfx.me_fw = NULL;
- release_firmware(adev->gfx.ce_fw);
- adev->gfx.ce_fw = NULL;
+ amdgpu_ucode_release(&adev->gfx.pfp_fw);
+ amdgpu_ucode_release(&adev->gfx.me_fw);
+ amdgpu_ucode_release(&adev->gfx.ce_fw);
}
return err;
}
static int gfx_v9_0_init_rlc_microcode(struct amdgpu_device *adev,
- const char *chip_name)
+ char *chip_name)
{
char fw_name[30];
int err;
@@ -1328,10 +1307,7 @@ static int gfx_v9_0_init_rlc_microcode(struct amdgpu_device *adev,
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_kicker_rlc.bin", chip_name);
else
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_rlc.bin", chip_name);
- err = request_firmware(&adev->gfx.rlc_fw, fw_name, adev->dev);
- if (err)
- goto out;
- err = amdgpu_ucode_validate(adev->gfx.rlc_fw);
+ err = amdgpu_ucode_request(adev, &adev->gfx.rlc_fw, fw_name);
if (err)
goto out;
rlc_hdr = (const struct rlc_firmware_header_v2_0 *)adev->gfx.rlc_fw->data;
@@ -1340,13 +1316,9 @@ static int gfx_v9_0_init_rlc_microcode(struct amdgpu_device *adev,
version_minor = le16_to_cpu(rlc_hdr->header.header_version_minor);
err = amdgpu_gfx_rlc_init_microcode(adev, version_major, version_minor);
out:
- if (err) {
- dev_err(adev->dev,
- "gfx9: Failed to init firmware \"%s\"\n",
- fw_name);
- release_firmware(adev->gfx.rlc_fw);
- adev->gfx.rlc_fw = NULL;
- }
+ if (err)
+ amdgpu_ucode_release(&adev->gfx.rlc_fw);
+
return err;
}
@@ -1361,7 +1333,7 @@ static bool gfx_v9_0_load_mec2_fw_bin_support(struct amdgpu_device *adev)
}
static int gfx_v9_0_init_cp_compute_microcode(struct amdgpu_device *adev,
- const char *chip_name)
+ char *chip_name)
{
char fw_name[30];
int err;
@@ -1371,10 +1343,7 @@ static int gfx_v9_0_init_cp_compute_microcode(struct amdgpu_device *adev,
else
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec.bin", chip_name);
- err = request_firmware(&adev->gfx.mec_fw, fw_name, adev->dev);
- if (err)
- goto out;
- err = amdgpu_ucode_validate(adev->gfx.mec_fw);
+ err = amdgpu_ucode_request(adev, &adev->gfx.mec_fw, fw_name);
if (err)
goto out;
amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC1);
@@ -1386,91 +1355,49 @@ static int gfx_v9_0_init_cp_compute_microcode(struct amdgpu_device *adev,
else
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec2.bin", chip_name);
- err = request_firmware(&adev->gfx.mec2_fw, fw_name, adev->dev);
+ /* ignore failures to load */
+ err = amdgpu_ucode_request(adev, &adev->gfx.mec2_fw, fw_name);
if (!err) {
- err = amdgpu_ucode_validate(adev->gfx.mec2_fw);
- if (err)
- goto out;
amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC2);
amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC2_JT);
} else {
err = 0;
- adev->gfx.mec2_fw = NULL;
+ amdgpu_ucode_release(&adev->gfx.mec2_fw);
}
} else {
adev->gfx.mec2_fw_version = adev->gfx.mec_fw_version;
adev->gfx.mec2_feature_version = adev->gfx.mec_feature_version;
}
-out:
gfx_v9_0_check_if_need_gfxoff(adev);
gfx_v9_0_check_fw_write_wait(adev);
- if (err) {
- dev_err(adev->dev,
- "gfx9: Failed to init firmware \"%s\"\n",
- fw_name);
- release_firmware(adev->gfx.mec_fw);
- adev->gfx.mec_fw = NULL;
- release_firmware(adev->gfx.mec2_fw);
- adev->gfx.mec2_fw = NULL;
- }
+
+out:
+ if (err)
+ amdgpu_ucode_release(&adev->gfx.mec_fw);
return err;
}
static int gfx_v9_0_init_microcode(struct amdgpu_device *adev)
{
- const char *chip_name;
+ char ucode_prefix[30];
int r;
DRM_DEBUG("\n");
-
- switch (adev->ip_versions[GC_HWIP][0]) {
- case IP_VERSION(9, 0, 1):
- chip_name = "vega10";
- break;
- case IP_VERSION(9, 2, 1):
- chip_name = "vega12";
- break;
- case IP_VERSION(9, 4, 0):
- chip_name = "vega20";
- break;
- case IP_VERSION(9, 2, 2):
- case IP_VERSION(9, 1, 0):
- if (adev->apu_flags & AMD_APU_IS_RAVEN2)
- chip_name = "raven2";
- else if (adev->apu_flags & AMD_APU_IS_PICASSO)
- chip_name = "picasso";
- else
- chip_name = "raven";
- break;
- case IP_VERSION(9, 4, 1):
- chip_name = "arcturus";
- break;
- case IP_VERSION(9, 3, 0):
- if (adev->apu_flags & AMD_APU_IS_RENOIR)
- chip_name = "renoir";
- else
- chip_name = "green_sardine";
- break;
- case IP_VERSION(9, 4, 2):
- chip_name = "aldebaran";
- break;
- default:
- BUG();
- }
+ amdgpu_ucode_ip_version_decode(adev, GC_HWIP, ucode_prefix, sizeof(ucode_prefix));
/* No CPG in Arcturus */
if (adev->gfx.num_gfx_rings) {
- r = gfx_v9_0_init_cp_gfx_microcode(adev, chip_name);
+ r = gfx_v9_0_init_cp_gfx_microcode(adev, ucode_prefix);
if (r)
return r;
}
- r = gfx_v9_0_init_rlc_microcode(adev, chip_name);
+ r = gfx_v9_0_init_rlc_microcode(adev, ucode_prefix);
if (r)
return r;
- r = gfx_v9_0_init_cp_compute_microcode(adev, chip_name);
+ r = gfx_v9_0_init_cp_compute_microcode(adev, ucode_prefix);
if (r)
return r;
@@ -1783,7 +1710,8 @@ static int gfx_v9_0_mec_init(struct amdgpu_device *adev)
mec_hpd_size = adev->gfx.num_compute_rings * GFX9_MEC_HPD_SIZE;
if (mec_hpd_size) {
r = amdgpu_bo_create_reserved(adev, mec_hpd_size, PAGE_SIZE,
- AMDGPU_GEM_DOMAIN_VRAM,
+ AMDGPU_GEM_DOMAIN_VRAM |
+ AMDGPU_GEM_DOMAIN_GTT,
&adev->gfx.mec.hpd_eop_obj,
&adev->gfx.mec.hpd_eop_gpu_addr,
(void **)&hpd);
@@ -2008,27 +1936,6 @@ static int gfx_v9_0_gpu_early_init(struct amdgpu_device *adev)
break;
}
- if (adev->gfx.ras) {
- err = amdgpu_ras_register_ras_block(adev, &adev->gfx.ras->ras_block);
- if (err) {
- DRM_ERROR("Failed to register gfx ras block!\n");
- return err;
- }
-
- strcpy(adev->gfx.ras->ras_block.ras_comm.name, "gfx");
- adev->gfx.ras->ras_block.ras_comm.block = AMDGPU_RAS_BLOCK__GFX;
- adev->gfx.ras->ras_block.ras_comm.type = AMDGPU_RAS_ERROR__MULTI_UNCORRECTABLE;
- adev->gfx.ras_if = &adev->gfx.ras->ras_block.ras_comm;
-
- /* If not define special ras_late_init function, use gfx default ras_late_init */
- if (!adev->gfx.ras->ras_block.ras_late_init)
- adev->gfx.ras->ras_block.ras_late_init = amdgpu_gfx_ras_late_init;
-
- /* If not defined special ras_cb function, use default ras_cb */
- if (!adev->gfx.ras->ras_block.ras_cb)
- adev->gfx.ras->ras_block.ras_cb = amdgpu_gfx_process_ras_data_cb;
- }
-
adev->gfx.config.gb_addr_config = gb_addr_config;
adev->gfx.config.gb_addr_config_fields.num_pipes = 1 <<
@@ -2158,12 +2065,6 @@ static int gfx_v9_0_sw_init(void *handle)
adev->gfx.gfx_current_status = AMDGPU_GFX_NORMAL_MODE;
- r = gfx_v9_0_init_microcode(adev);
- if (r) {
- DRM_ERROR("Failed to load gfx firmware!\n");
- return r;
- }
-
if (adev->gfx.rlc.funcs) {
if (adev->gfx.rlc.funcs->init) {
r = adev->gfx.rlc.funcs->init(adev);
@@ -2276,6 +2177,11 @@ static int gfx_v9_0_sw_init(void *handle)
if (r)
return r;
+ if (amdgpu_gfx_ras_sw_init(adev)) {
+ dev_err(adev->dev, "Failed to initialize gfx ras block!\n");
+ return -EINVAL;
+ }
+
return 0;
}
@@ -4605,7 +4511,7 @@ static int gfx_v9_0_early_init(void *handle)
/* init rlcg reg access ctrl */
gfx_v9_0_init_rlcg_reg_access_ctrl(adev);
- return 0;
+ return gfx_v9_0_init_microcode(adev);
}
static int gfx_v9_0_ecc_late_init(void *handle)
diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c
index ec4d5e15b766..ab2325f6c7ac 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c
@@ -120,7 +120,7 @@ static void gfxhub_v1_0_init_system_aperture_regs(struct amdgpu_device *adev)
max(adev->gmc.fb_end, adev->gmc.agp_end) >> 18);
/* Set default page address. */
- value = amdgpu_gmc_vram_mc2pa(adev, adev->vram_scratch.gpu_addr);
+ value = amdgpu_gmc_vram_mc2pa(adev, adev->mem_scratch.gpu_addr);
WREG32_SOC15(GC, 0, mmMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB,
(u32)(value >> 12));
WREG32_SOC15(GC, 0, mmMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB,
diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_0.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_0.c
index 34513e8e1519..9b3a02527318 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_0.c
@@ -165,7 +165,7 @@ static void gfxhub_v2_0_init_system_aperture_regs(struct amdgpu_device *adev)
max(adev->gmc.fb_end, adev->gmc.agp_end) >> 18);
/* Set default page address. */
- value = amdgpu_gmc_vram_mc2pa(adev, adev->vram_scratch.gpu_addr);
+ value = amdgpu_gmc_vram_mc2pa(adev, adev->mem_scratch.gpu_addr);
WREG32_SOC15(GC, 0, mmGCMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB,
(u32)(value >> 12));
WREG32_SOC15(GC, 0, mmGCMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB,
diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_1.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_1.c
index 3f8676d23a5e..4aacbbec31e2 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v2_1.c
@@ -167,7 +167,7 @@ static void gfxhub_v2_1_init_system_aperture_regs(struct amdgpu_device *adev)
max(adev->gmc.fb_end, adev->gmc.agp_end) >> 18);
/* Set default page address. */
- value = amdgpu_gmc_vram_mc2pa(adev, adev->vram_scratch.gpu_addr);
+ value = amdgpu_gmc_vram_mc2pa(adev, adev->mem_scratch.gpu_addr);
WREG32_SOC15(GC, 0, mmGCMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB,
(u32)(value >> 12));
WREG32_SOC15(GC, 0, mmGCMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB,
diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0.c
index 0e13370c2057..be0d0f47415e 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0.c
@@ -151,19 +151,20 @@ static void gfxhub_v3_0_init_system_aperture_regs(struct amdgpu_device *adev)
{
uint64_t value;
- /* Disable AGP. */
+ /* Program the AGP BAR */
WREG32_SOC15(GC, 0, regGCMC_VM_AGP_BASE, 0);
- WREG32_SOC15(GC, 0, regGCMC_VM_AGP_TOP, 0);
- WREG32_SOC15(GC, 0, regGCMC_VM_AGP_BOT, 0x00FFFFFF);
+ WREG32_SOC15(GC, 0, regGCMC_VM_AGP_BOT, adev->gmc.agp_start >> 24);
+ WREG32_SOC15(GC, 0, regGCMC_VM_AGP_TOP, adev->gmc.agp_end >> 24);
+
/* Program the system aperture low logical page number. */
WREG32_SOC15(GC, 0, regGCMC_VM_SYSTEM_APERTURE_LOW_ADDR,
- adev->gmc.vram_start >> 18);
+ min(adev->gmc.fb_start, adev->gmc.agp_start) >> 18);
WREG32_SOC15(GC, 0, regGCMC_VM_SYSTEM_APERTURE_HIGH_ADDR,
- adev->gmc.vram_end >> 18);
+ max(adev->gmc.fb_end, adev->gmc.agp_end) >> 18);
/* Set default page address. */
- value = adev->vram_scratch.gpu_addr - adev->gmc.vram_start
+ value = adev->mem_scratch.gpu_addr - adev->gmc.vram_start
+ adev->vm_manager.vram_base_offset;
WREG32_SOC15(GC, 0, regGCMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB,
(u32)(value >> 12));
diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0_3.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0_3.c
index 080ff11ca305..6e0bd628c889 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0_3.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v3_0_3.c
@@ -159,17 +159,17 @@ static void gfxhub_v3_0_3_init_system_aperture_regs(struct amdgpu_device *adev)
/* Disable AGP. */
WREG32_SOC15(GC, 0, regGCMC_VM_AGP_BASE, 0);
- WREG32_SOC15(GC, 0, regGCMC_VM_AGP_TOP, 0);
- WREG32_SOC15(GC, 0, regGCMC_VM_AGP_BOT, 0x00FFFFFF);
+ WREG32_SOC15(GC, 0, regGCMC_VM_AGP_BOT, adev->gmc.agp_start >> 24);
+ WREG32_SOC15(GC, 0, regGCMC_VM_AGP_TOP, adev->gmc.agp_end >> 24);
/* Program the system aperture low logical page number. */
WREG32_SOC15(GC, 0, regGCMC_VM_SYSTEM_APERTURE_LOW_ADDR,
- adev->gmc.vram_start >> 18);
+ min(adev->gmc.fb_start, adev->gmc.agp_start) >> 18);
WREG32_SOC15(GC, 0, regGCMC_VM_SYSTEM_APERTURE_HIGH_ADDR,
- adev->gmc.vram_end >> 18);
+ max(adev->gmc.fb_end, adev->gmc.agp_end) >> 18);
/* Set default page address. */
- value = adev->vram_scratch.gpu_addr - adev->gmc.vram_start
+ value = adev->mem_scratch.gpu_addr - adev->gmc.vram_start
+ adev->vm_manager.vram_base_offset;
WREG32_SOC15(GC, 0, regGCMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB,
(u32)(value >> 12));
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
index 21e46817d82d..ab2556ca984e 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
@@ -78,13 +78,25 @@ gmc_v10_0_vm_fault_interrupt_state(struct amdgpu_device *adev,
/* MM HUB */
amdgpu_gmc_set_vm_fault_masks(adev, AMDGPU_MMHUB_0, false);
/* GFX HUB */
- amdgpu_gmc_set_vm_fault_masks(adev, AMDGPU_GFXHUB_0, false);
+ /* This works because this interrupt is only
+ * enabled at init/resume and disabled in
+ * fini/suspend, so the overall state doesn't
+ * change over the course of suspend/resume.
+ */
+ if (!adev->in_s0ix)
+ amdgpu_gmc_set_vm_fault_masks(adev, AMDGPU_GFXHUB_0, false);
break;
case AMDGPU_IRQ_STATE_ENABLE:
/* MM HUB */
amdgpu_gmc_set_vm_fault_masks(adev, AMDGPU_MMHUB_0, true);
/* GFX HUB */
- amdgpu_gmc_set_vm_fault_masks(adev, AMDGPU_GFXHUB_0, true);
+ /* This works because this interrupt is only
+ * enabled at init/resume and disabled in
+ * fini/suspend, so the overall state doesn't
+ * change over the course of suspend/resume.
+ */
+ if (!adev->in_s0ix)
+ amdgpu_gmc_set_vm_fault_masks(adev, AMDGPU_GFXHUB_0, true);
break;
default:
break;
@@ -680,6 +692,7 @@ static void gmc_v10_0_set_umc_funcs(struct amdgpu_device *adev)
adev->umc.channel_inst_num = UMC_V8_7_CHANNEL_INSTANCE_NUM;
adev->umc.umc_inst_num = UMC_V8_7_UMC_INSTANCE_NUM;
adev->umc.channel_offs = UMC_V8_7_PER_CHANNEL_OFFSET_SIENNA;
+ adev->umc.retire_unit = 1;
adev->umc.channel_idx_tbl = &umc_v8_7_channel_idx_tbl[0][0];
adev->umc.ras = &umc_v8_7_ras;
break;
@@ -835,10 +848,7 @@ static int gmc_v10_0_mc_init(struct amdgpu_device *adev)
}
#endif
- /* In case the PCI BAR is larger than the actual amount of vram */
adev->gmc.visible_vram_size = adev->gmc.aper_size;
- if (adev->gmc.visible_vram_size > adev->gmc.real_vram_size)
- adev->gmc.visible_vram_size = adev->gmc.real_vram_size;
/* set the gart size */
if (amdgpu_gart_size == -1) {
@@ -1061,9 +1071,12 @@ static int gmc_v10_0_gart_enable(struct amdgpu_device *adev)
}
amdgpu_gtt_mgr_recover(&adev->mman.gtt_mgr);
- r = adev->gfxhub.funcs->gart_enable(adev);
- if (r)
- return r;
+
+ if (!adev->in_s0ix) {
+ r = adev->gfxhub.funcs->gart_enable(adev);
+ if (r)
+ return r;
+ }
r = adev->mmhub.funcs->gart_enable(adev);
if (r)
@@ -1077,10 +1090,12 @@ static int gmc_v10_0_gart_enable(struct amdgpu_device *adev)
value = (amdgpu_vm_fault_stop == AMDGPU_VM_FAULT_STOP_ALWAYS) ?
false : true;
- adev->gfxhub.funcs->set_fault_enable_default(adev, value);
+ if (!adev->in_s0ix)
+ adev->gfxhub.funcs->set_fault_enable_default(adev, value);
adev->mmhub.funcs->set_fault_enable_default(adev, value);
gmc_v10_0_flush_gpu_tlb(adev, 0, AMDGPU_MMHUB_0, 0);
- gmc_v10_0_flush_gpu_tlb(adev, 0, AMDGPU_GFXHUB_0, 0);
+ if (!adev->in_s0ix)
+ gmc_v10_0_flush_gpu_tlb(adev, 0, AMDGPU_GFXHUB_0, 0);
DRM_INFO("PCIE GART of %uM enabled (table at 0x%016llX).\n",
(unsigned)(adev->gmc.gart_size >> 20),
@@ -1101,7 +1116,7 @@ static int gmc_v10_0_hw_init(void *handle)
* harvestable groups in gc_utcl2 need to be programmed before any GFX block
* register setup within GMC, or else system hang when harvesting SA.
*/
- if (adev->gfxhub.funcs && adev->gfxhub.funcs->utcl2_harvest)
+ if (!adev->in_s0ix && adev->gfxhub.funcs && adev->gfxhub.funcs->utcl2_harvest)
adev->gfxhub.funcs->utcl2_harvest(adev);
r = gmc_v10_0_gart_enable(adev);
@@ -1129,7 +1144,8 @@ static int gmc_v10_0_hw_init(void *handle)
*/
static void gmc_v10_0_gart_disable(struct amdgpu_device *adev)
{
- adev->gfxhub.funcs->gart_disable(adev);
+ if (!adev->in_s0ix)
+ adev->gfxhub.funcs->gart_disable(adev);
adev->mmhub.funcs->gart_disable(adev);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c
index 4326078689cd..85e0afc3d4f7 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c
@@ -64,13 +64,25 @@ gmc_v11_0_vm_fault_interrupt_state(struct amdgpu_device *adev,
/* MM HUB */
amdgpu_gmc_set_vm_fault_masks(adev, AMDGPU_MMHUB_0, false);
/* GFX HUB */
- amdgpu_gmc_set_vm_fault_masks(adev, AMDGPU_GFXHUB_0, false);
+ /* This works because this interrupt is only
+ * enabled at init/resume and disabled in
+ * fini/suspend, so the overall state doesn't
+ * change over the course of suspend/resume.
+ */
+ if (!adev->in_s0ix)
+ amdgpu_gmc_set_vm_fault_masks(adev, AMDGPU_GFXHUB_0, false);
break;
case AMDGPU_IRQ_STATE_ENABLE:
/* MM HUB */
amdgpu_gmc_set_vm_fault_masks(adev, AMDGPU_MMHUB_0, true);
/* GFX HUB */
- amdgpu_gmc_set_vm_fault_masks(adev, AMDGPU_GFXHUB_0, true);
+ /* This works because this interrupt is only
+ * enabled at init/resume and disabled in
+ * fini/suspend, so the overall state doesn't
+ * change over the course of suspend/resume.
+ */
+ if (!adev->in_s0ix)
+ amdgpu_gmc_set_vm_fault_masks(adev, AMDGPU_GFXHUB_0, true);
break;
default:
break;
@@ -558,6 +570,7 @@ static void gmc_v11_0_set_umc_funcs(struct amdgpu_device *adev)
adev->umc.node_inst_num = adev->gmc.num_umc;
adev->umc.max_ras_err_cnt_per_query = UMC_V8_10_TOTAL_CHANNEL_NUM(adev);
adev->umc.channel_offs = UMC_V8_10_PER_CHANNEL_OFFSET;
+ adev->umc.retire_unit = UMC_V8_10_NA_COL_2BITS_POWER_OF_2_NUM;
if (adev->umc.node_inst_num == 4)
adev->umc.channel_idx_tbl = &umc_v8_10_channel_idx_tbl_ext0[0][0][0];
else
@@ -661,6 +674,7 @@ static void gmc_v11_0_vram_gtt_location(struct amdgpu_device *adev,
amdgpu_gmc_vram_location(adev, &adev->gmc, base);
amdgpu_gmc_gart_location(adev, mc);
+ amdgpu_gmc_agp_location(adev, mc);
/* base offset of vram pages */
if (amdgpu_sriov_vf(adev))
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
index ec291d28edff..b7dad4e67813 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
@@ -131,19 +131,12 @@ static int gmc_v6_0_init_microcode(struct amdgpu_device *adev)
snprintf(fw_name, sizeof(fw_name), "amdgpu/si58_mc.bin");
else
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mc.bin", chip_name);
- err = request_firmware(&adev->gmc.fw, fw_name, adev->dev);
- if (err)
- goto out;
-
- err = amdgpu_ucode_validate(adev->gmc.fw);
-
-out:
+ err = amdgpu_ucode_request(adev, &adev->gmc.fw, fw_name);
if (err) {
dev_err(adev->dev,
"si_mc: Failed to load firmware \"%s\"\n",
fw_name);
- release_firmware(adev->gmc.fw);
- adev->gmc.fw = NULL;
+ amdgpu_ucode_release(&adev->gmc.fw);
}
return err;
}
@@ -258,7 +251,7 @@ static void gmc_v6_0_mc_program(struct amdgpu_device *adev)
WREG32(mmMC_VM_SYSTEM_APERTURE_HIGH_ADDR,
adev->gmc.vram_end >> 12);
WREG32(mmMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR,
- adev->vram_scratch.gpu_addr >> 12);
+ adev->mem_scratch.gpu_addr >> 12);
WREG32(mmMC_VM_AGP_BASE, 0);
WREG32(mmMC_VM_AGP_TOP, 0x0FFFFFFF);
WREG32(mmMC_VM_AGP_BOT, 0x0FFFFFFF);
@@ -894,8 +887,7 @@ static int gmc_v6_0_sw_fini(void *handle)
amdgpu_vm_manager_fini(adev);
amdgpu_gart_table_vram_free(adev);
amdgpu_bo_fini(adev);
- release_firmware(adev->gmc.fw);
- adev->gmc.fw = NULL;
+ amdgpu_ucode_release(&adev->gmc.fw);
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
index 979da6f510e8..402960b0174e 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
@@ -156,16 +156,10 @@ static int gmc_v7_0_init_microcode(struct amdgpu_device *adev)
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mc.bin", chip_name);
- err = request_firmware(&adev->gmc.fw, fw_name, adev->dev);
- if (err)
- goto out;
- err = amdgpu_ucode_validate(adev->gmc.fw);
-
-out:
+ err = amdgpu_ucode_request(adev, &adev->gmc.fw, fw_name);
if (err) {
pr_err("cik_mc: Failed to load firmware \"%s\"\n", fw_name);
- release_firmware(adev->gmc.fw);
- adev->gmc.fw = NULL;
+ amdgpu_ucode_release(&adev->gmc.fw);
}
return err;
}
@@ -292,7 +286,7 @@ static void gmc_v7_0_mc_program(struct amdgpu_device *adev)
WREG32(mmMC_VM_SYSTEM_APERTURE_HIGH_ADDR,
adev->gmc.vram_end >> 12);
WREG32(mmMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR,
- adev->vram_scratch.gpu_addr >> 12);
+ adev->mem_scratch.gpu_addr >> 12);
WREG32(mmMC_VM_AGP_BASE, 0);
WREG32(mmMC_VM_AGP_TOP, 0x0FFFFFFF);
WREG32(mmMC_VM_AGP_BOT, 0x0FFFFFFF);
@@ -389,10 +383,7 @@ static int gmc_v7_0_mc_init(struct amdgpu_device *adev)
}
#endif
- /* In case the PCI BAR is larger than the actual amount of vram */
adev->gmc.visible_vram_size = adev->gmc.aper_size;
- if (adev->gmc.visible_vram_size > adev->gmc.real_vram_size)
- adev->gmc.visible_vram_size = adev->gmc.real_vram_size;
/* set the gart size */
if (amdgpu_gart_size == -1) {
@@ -1081,8 +1072,7 @@ static int gmc_v7_0_sw_fini(void *handle)
kfree(adev->gmc.vm_fault_info);
amdgpu_gart_table_vram_free(adev);
amdgpu_bo_fini(adev);
- release_firmware(adev->gmc.fw);
- adev->gmc.fw = NULL;
+ amdgpu_ucode_release(&adev->gmc.fw);
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
index 382dde1ce74c..504c1b34dab7 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
@@ -264,16 +264,10 @@ static int gmc_v8_0_init_microcode(struct amdgpu_device *adev)
}
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mc.bin", chip_name);
- err = request_firmware(&adev->gmc.fw, fw_name, adev->dev);
- if (err)
- goto out;
- err = amdgpu_ucode_validate(adev->gmc.fw);
-
-out:
+ err = amdgpu_ucode_request(adev, &adev->gmc.fw, fw_name);
if (err) {
pr_err("mc: Failed to load firmware \"%s\"\n", fw_name);
- release_firmware(adev->gmc.fw);
- adev->gmc.fw = NULL;
+ amdgpu_ucode_release(&adev->gmc.fw);
}
return err;
}
@@ -474,7 +468,7 @@ static void gmc_v8_0_mc_program(struct amdgpu_device *adev)
WREG32(mmMC_VM_SYSTEM_APERTURE_HIGH_ADDR,
adev->gmc.vram_end >> 12);
WREG32(mmMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR,
- adev->vram_scratch.gpu_addr >> 12);
+ adev->mem_scratch.gpu_addr >> 12);
if (amdgpu_sriov_vf(adev)) {
tmp = ((adev->gmc.vram_end >> 24) & 0xFFFF) << 16;
@@ -587,10 +581,7 @@ static int gmc_v8_0_mc_init(struct amdgpu_device *adev)
}
#endif
- /* In case the PCI BAR is larger than the actual amount of vram */
adev->gmc.visible_vram_size = adev->gmc.aper_size;
- if (adev->gmc.visible_vram_size > adev->gmc.real_vram_size)
- adev->gmc.visible_vram_size = adev->gmc.real_vram_size;
/* set the gart size */
if (amdgpu_gart_size == -1) {
@@ -1203,8 +1194,7 @@ static int gmc_v8_0_sw_fini(void *handle)
kfree(adev->gmc.vm_fault_info);
amdgpu_gart_table_vram_free(adev);
amdgpu_bo_fini(adev);
- release_firmware(adev->gmc.fw);
- adev->gmc.fw = NULL;
+ amdgpu_ucode_release(&adev->gmc.fw);
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
index 08d6cf79fb15..b06170c00dfc 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
@@ -484,6 +484,14 @@ static int gmc_v9_0_vm_fault_interrupt_state(struct amdgpu_device *adev,
for (i = 0; i < 16; i++) {
reg = hub->vm_context0_cntl + i;
+ /* This works because this interrupt is only
+ * enabled at init/resume and disabled in
+ * fini/suspend, so the overall state doesn't
+ * change over the course of suspend/resume.
+ */
+ if (adev->in_s0ix && (j == AMDGPU_GFXHUB_0))
+ continue;
+
if (j == AMDGPU_GFXHUB_0)
tmp = RREG32_SOC15_IP(GC, reg);
else
@@ -504,6 +512,14 @@ static int gmc_v9_0_vm_fault_interrupt_state(struct amdgpu_device *adev,
for (i = 0; i < 16; i++) {
reg = hub->vm_context0_cntl + i;
+ /* This works because this interrupt is only
+ * enabled at init/resume and disabled in
+ * fini/suspend, so the overall state doesn't
+ * change over the course of suspend/resume.
+ */
+ if (adev->in_s0ix && (j == AMDGPU_GFXHUB_0))
+ continue;
+
if (j == AMDGPU_GFXHUB_0)
tmp = RREG32_SOC15_IP(GC, reg);
else
@@ -1272,6 +1288,7 @@ static void gmc_v9_0_set_umc_funcs(struct amdgpu_device *adev)
adev->umc.channel_inst_num = UMC_V6_1_CHANNEL_INSTANCE_NUM;
adev->umc.umc_inst_num = UMC_V6_1_UMC_INSTANCE_NUM;
adev->umc.channel_offs = UMC_V6_1_PER_CHANNEL_OFFSET_VG20;
+ adev->umc.retire_unit = 1;
adev->umc.channel_idx_tbl = &umc_v6_1_channel_idx_tbl[0][0];
adev->umc.ras = &umc_v6_1_ras;
break;
@@ -1280,6 +1297,7 @@ static void gmc_v9_0_set_umc_funcs(struct amdgpu_device *adev)
adev->umc.channel_inst_num = UMC_V6_1_CHANNEL_INSTANCE_NUM;
adev->umc.umc_inst_num = UMC_V6_1_UMC_INSTANCE_NUM;
adev->umc.channel_offs = UMC_V6_1_PER_CHANNEL_OFFSET_ARCT;
+ adev->umc.retire_unit = 1;
adev->umc.channel_idx_tbl = &umc_v6_1_channel_idx_tbl[0][0];
adev->umc.ras = &umc_v6_1_ras;
break;
@@ -1289,6 +1307,7 @@ static void gmc_v9_0_set_umc_funcs(struct amdgpu_device *adev)
adev->umc.channel_inst_num = UMC_V6_7_CHANNEL_INSTANCE_NUM;
adev->umc.umc_inst_num = UMC_V6_7_UMC_INSTANCE_NUM;
adev->umc.channel_offs = UMC_V6_7_PER_CHANNEL_OFFSET;
+ adev->umc.retire_unit = (UMC_V6_7_NA_MAP_PA_NUM * 2);
if (!adev->gmc.xgmi.connected_to_cpu)
adev->umc.ras = &umc_v6_7_ras;
if (1 & adev->smuio.funcs->get_die_id(adev))
@@ -1536,10 +1555,7 @@ static int gmc_v9_0_mc_init(struct amdgpu_device *adev)
}
#endif
- /* In case the PCI BAR is larger than the actual amount of vram */
adev->gmc.visible_vram_size = adev->gmc.aper_size;
- if (adev->gmc.visible_vram_size > adev->gmc.real_vram_size)
- adev->gmc.visible_vram_size = adev->gmc.real_vram_size;
/* set the gart size */
if (amdgpu_gart_size == -1) {
@@ -1862,9 +1878,12 @@ static int gmc_v9_0_gart_enable(struct amdgpu_device *adev)
}
amdgpu_gtt_mgr_recover(&adev->mman.gtt_mgr);
- r = adev->gfxhub.funcs->gart_enable(adev);
- if (r)
- return r;
+
+ if (!adev->in_s0ix) {
+ r = adev->gfxhub.funcs->gart_enable(adev);
+ if (r)
+ return r;
+ }
r = adev->mmhub.funcs->gart_enable(adev);
if (r)
@@ -1911,11 +1930,15 @@ static int gmc_v9_0_hw_init(void *handle)
value = true;
if (!amdgpu_sriov_vf(adev)) {
- adev->gfxhub.funcs->set_fault_enable_default(adev, value);
+ if (!adev->in_s0ix)
+ adev->gfxhub.funcs->set_fault_enable_default(adev, value);
adev->mmhub.funcs->set_fault_enable_default(adev, value);
}
- for (i = 0; i < adev->num_vmhubs; ++i)
+ for (i = 0; i < adev->num_vmhubs; ++i) {
+ if (adev->in_s0ix && (i == AMDGPU_GFXHUB_0))
+ continue;
gmc_v9_0_flush_gpu_tlb(adev, 0, i, 0);
+ }
if (adev->umc.funcs && adev->umc.funcs->init_registers)
adev->umc.funcs->init_registers(adev);
@@ -1939,7 +1962,8 @@ static int gmc_v9_0_hw_init(void *handle)
*/
static void gmc_v9_0_gart_disable(struct amdgpu_device *adev)
{
- adev->gfxhub.funcs->gart_disable(adev);
+ if (!adev->in_s0ix)
+ adev->gfxhub.funcs->gart_disable(adev);
adev->mmhub.funcs->gart_disable(adev);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/imu_v11_0.c b/drivers/gpu/drm/amd/amdgpu/imu_v11_0.c
index 077c53c6cc08..4ab90c7852c3 100644
--- a/drivers/gpu/drm/amd/amdgpu/imu_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/imu_v11_0.c
@@ -50,10 +50,7 @@ static int imu_v11_0_init_microcode(struct amdgpu_device *adev)
amdgpu_ucode_ip_version_decode(adev, GC_HWIP, ucode_prefix, sizeof(ucode_prefix));
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_imu.bin", ucode_prefix);
- err = request_firmware(&adev->gfx.imu_fw, fw_name, adev->dev);
- if (err)
- goto out;
- err = amdgpu_ucode_validate(adev->gfx.imu_fw);
+ err = amdgpu_ucode_request(adev, &adev->gfx.imu_fw, fw_name);
if (err)
goto out;
imu_hdr = (const struct imu_firmware_header_v1_0 *)adev->gfx.imu_fw->data;
@@ -78,7 +75,7 @@ out:
dev_err(adev->dev,
"gfx11: Failed to load firmware \"%s\"\n",
fw_name);
- release_firmware(adev->gfx.imu_fw);
+ amdgpu_ucode_release(&adev->gfx.imu_fw);
}
return err;
diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v10_1.c b/drivers/gpu/drm/amd/amdgpu/mes_v10_1.c
index 614394118a53..2e2062636d5f 100644
--- a/drivers/gpu/drm/amd/amdgpu/mes_v10_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/mes_v10_1.c
@@ -379,89 +379,6 @@ static const struct amdgpu_mes_funcs mes_v10_1_funcs = {
.resume_gang = mes_v10_1_resume_gang,
};
-static int mes_v10_1_init_microcode(struct amdgpu_device *adev,
- enum admgpu_mes_pipe pipe)
-{
- const char *chip_name;
- char fw_name[30];
- int err;
- const struct mes_firmware_header_v1_0 *mes_hdr;
- struct amdgpu_firmware_info *info;
-
- switch (adev->ip_versions[GC_HWIP][0]) {
- case IP_VERSION(10, 1, 10):
- chip_name = "navi10";
- break;
- case IP_VERSION(10, 3, 0):
- chip_name = "sienna_cichlid";
- break;
- default:
- BUG();
- }
-
- if (pipe == AMDGPU_MES_SCHED_PIPE)
- snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mes.bin",
- chip_name);
- else
- snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mes1.bin",
- chip_name);
-
- err = request_firmware(&adev->mes.fw[pipe], fw_name, adev->dev);
- if (err)
- return err;
-
- err = amdgpu_ucode_validate(adev->mes.fw[pipe]);
- if (err) {
- release_firmware(adev->mes.fw[pipe]);
- adev->mes.fw[pipe] = NULL;
- return err;
- }
-
- mes_hdr = (const struct mes_firmware_header_v1_0 *)
- adev->mes.fw[pipe]->data;
- adev->mes.uc_start_addr[pipe] =
- le32_to_cpu(mes_hdr->mes_uc_start_addr_lo) |
- ((uint64_t)(le32_to_cpu(mes_hdr->mes_uc_start_addr_hi)) << 32);
- adev->mes.data_start_addr[pipe] =
- le32_to_cpu(mes_hdr->mes_data_start_addr_lo) |
- ((uint64_t)(le32_to_cpu(mes_hdr->mes_data_start_addr_hi)) << 32);
-
- if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
- int ucode, ucode_data;
-
- if (pipe == AMDGPU_MES_SCHED_PIPE) {
- ucode = AMDGPU_UCODE_ID_CP_MES;
- ucode_data = AMDGPU_UCODE_ID_CP_MES_DATA;
- } else {
- ucode = AMDGPU_UCODE_ID_CP_MES1;
- ucode_data = AMDGPU_UCODE_ID_CP_MES1_DATA;
- }
-
- info = &adev->firmware.ucode[ucode];
- info->ucode_id = ucode;
- info->fw = adev->mes.fw[pipe];
- adev->firmware.fw_size +=
- ALIGN(le32_to_cpu(mes_hdr->mes_ucode_size_bytes),
- PAGE_SIZE);
-
- info = &adev->firmware.ucode[ucode_data];
- info->ucode_id = ucode_data;
- info->fw = adev->mes.fw[pipe];
- adev->firmware.fw_size +=
- ALIGN(le32_to_cpu(mes_hdr->mes_ucode_data_size_bytes),
- PAGE_SIZE);
- }
-
- return 0;
-}
-
-static void mes_v10_1_free_microcode(struct amdgpu_device *adev,
- enum admgpu_mes_pipe pipe)
-{
- release_firmware(adev->mes.fw[pipe]);
- adev->mes.fw[pipe] = NULL;
-}
-
static int mes_v10_1_allocate_ucode_buffer(struct amdgpu_device *adev,
enum admgpu_mes_pipe pipe)
{
@@ -1007,7 +924,6 @@ static int mes_v10_1_sw_init(void *handle)
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
int pipe, r;
- adev->mes.adev = adev;
adev->mes.funcs = &mes_v10_1_funcs;
adev->mes.kiq_hw_init = &mes_v10_1_kiq_hw_init;
@@ -1019,10 +935,6 @@ static int mes_v10_1_sw_init(void *handle)
if (!adev->enable_mes_kiq && pipe == AMDGPU_MES_KIQ_PIPE)
continue;
- r = mes_v10_1_init_microcode(adev, pipe);
- if (r)
- return r;
-
r = mes_v10_1_allocate_eop_buf(adev, pipe);
if (r)
return r;
@@ -1059,8 +971,7 @@ static int mes_v10_1_sw_fini(void *handle)
amdgpu_bo_free_kernel(&adev->mes.eop_gpu_obj[pipe],
&adev->mes.eop_gpu_addr[pipe],
NULL);
-
- mes_v10_1_free_microcode(adev, pipe);
+ amdgpu_ucode_release(&adev->mes.fw[pipe]);
}
amdgpu_bo_free_kernel(&adev->gfx.kiq.ring.mqd_obj,
@@ -1229,6 +1140,22 @@ static int mes_v10_1_resume(void *handle)
return amdgpu_mes_resume(adev);
}
+static int mes_v10_0_early_init(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ int pipe, r;
+
+ for (pipe = 0; pipe < AMDGPU_MAX_MES_PIPES; pipe++) {
+ if (!adev->enable_mes_kiq && pipe == AMDGPU_MES_KIQ_PIPE)
+ continue;
+ r = amdgpu_mes_init_microcode(adev, pipe);
+ if (r)
+ return r;
+ }
+
+ return 0;
+}
+
static int mes_v10_0_late_init(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
@@ -1241,6 +1168,7 @@ static int mes_v10_0_late_init(void *handle)
static const struct amd_ip_funcs mes_v10_1_ip_funcs = {
.name = "mes_v10_1",
+ .early_init = mes_v10_0_early_init,
.late_init = mes_v10_0_late_init,
.sw_init = mes_v10_1_sw_init,
.sw_fini = mes_v10_1_sw_fini,
diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c
index 1c4787000a5f..5826eac270d7 100644
--- a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c
@@ -460,80 +460,6 @@ static const struct amdgpu_mes_funcs mes_v11_0_funcs = {
.misc_op = mes_v11_0_misc_op,
};
-static int mes_v11_0_init_microcode(struct amdgpu_device *adev,
- enum admgpu_mes_pipe pipe)
-{
- char fw_name[30];
- char ucode_prefix[30];
- int err;
- const struct mes_firmware_header_v1_0 *mes_hdr;
- struct amdgpu_firmware_info *info;
-
- amdgpu_ucode_ip_version_decode(adev, GC_HWIP, ucode_prefix, sizeof(ucode_prefix));
-
- if (pipe == AMDGPU_MES_SCHED_PIPE)
- snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mes.bin",
- ucode_prefix);
- else
- snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mes1.bin",
- ucode_prefix);
-
- err = request_firmware(&adev->mes.fw[pipe], fw_name, adev->dev);
- if (err)
- return err;
-
- err = amdgpu_ucode_validate(adev->mes.fw[pipe]);
- if (err) {
- release_firmware(adev->mes.fw[pipe]);
- adev->mes.fw[pipe] = NULL;
- return err;
- }
-
- mes_hdr = (const struct mes_firmware_header_v1_0 *)
- adev->mes.fw[pipe]->data;
- adev->mes.uc_start_addr[pipe] =
- le32_to_cpu(mes_hdr->mes_uc_start_addr_lo) |
- ((uint64_t)(le32_to_cpu(mes_hdr->mes_uc_start_addr_hi)) << 32);
- adev->mes.data_start_addr[pipe] =
- le32_to_cpu(mes_hdr->mes_data_start_addr_lo) |
- ((uint64_t)(le32_to_cpu(mes_hdr->mes_data_start_addr_hi)) << 32);
-
- if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
- int ucode, ucode_data;
-
- if (pipe == AMDGPU_MES_SCHED_PIPE) {
- ucode = AMDGPU_UCODE_ID_CP_MES;
- ucode_data = AMDGPU_UCODE_ID_CP_MES_DATA;
- } else {
- ucode = AMDGPU_UCODE_ID_CP_MES1;
- ucode_data = AMDGPU_UCODE_ID_CP_MES1_DATA;
- }
-
- info = &adev->firmware.ucode[ucode];
- info->ucode_id = ucode;
- info->fw = adev->mes.fw[pipe];
- adev->firmware.fw_size +=
- ALIGN(le32_to_cpu(mes_hdr->mes_ucode_size_bytes),
- PAGE_SIZE);
-
- info = &adev->firmware.ucode[ucode_data];
- info->ucode_id = ucode_data;
- info->fw = adev->mes.fw[pipe];
- adev->firmware.fw_size +=
- ALIGN(le32_to_cpu(mes_hdr->mes_ucode_data_size_bytes),
- PAGE_SIZE);
- }
-
- return 0;
-}
-
-static void mes_v11_0_free_microcode(struct amdgpu_device *adev,
- enum admgpu_mes_pipe pipe)
-{
- release_firmware(adev->mes.fw[pipe]);
- adev->mes.fw[pipe] = NULL;
-}
-
static int mes_v11_0_allocate_ucode_buffer(struct amdgpu_device *adev,
enum admgpu_mes_pipe pipe)
{
@@ -550,7 +476,9 @@ static int mes_v11_0_allocate_ucode_buffer(struct amdgpu_device *adev,
fw_size = le32_to_cpu(mes_hdr->mes_ucode_size_bytes);
r = amdgpu_bo_create_reserved(adev, fw_size,
- PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM,
+ PAGE_SIZE,
+ AMDGPU_GEM_DOMAIN_VRAM |
+ AMDGPU_GEM_DOMAIN_GTT,
&adev->mes.ucode_fw_obj[pipe],
&adev->mes.ucode_fw_gpu_addr[pipe],
(void **)&adev->mes.ucode_fw_ptr[pipe]);
@@ -583,7 +511,9 @@ static int mes_v11_0_allocate_ucode_data_buffer(struct amdgpu_device *adev,
fw_size = le32_to_cpu(mes_hdr->mes_ucode_data_size_bytes);
r = amdgpu_bo_create_reserved(adev, fw_size,
- 64 * 1024, AMDGPU_GEM_DOMAIN_VRAM,
+ 64 * 1024,
+ AMDGPU_GEM_DOMAIN_VRAM |
+ AMDGPU_GEM_DOMAIN_GTT,
&adev->mes.data_fw_obj[pipe],
&adev->mes.data_fw_gpu_addr[pipe],
(void **)&adev->mes.data_fw_ptr[pipe]);
@@ -1088,7 +1018,6 @@ static int mes_v11_0_sw_init(void *handle)
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
int pipe, r;
- adev->mes.adev = adev;
adev->mes.funcs = &mes_v11_0_funcs;
adev->mes.kiq_hw_init = &mes_v11_0_kiq_hw_init;
adev->mes.kiq_hw_fini = &mes_v11_0_kiq_hw_fini;
@@ -1101,10 +1030,6 @@ static int mes_v11_0_sw_init(void *handle)
if (!adev->enable_mes_kiq && pipe == AMDGPU_MES_KIQ_PIPE)
continue;
- r = mes_v11_0_init_microcode(adev, pipe);
- if (r)
- return r;
-
r = mes_v11_0_allocate_eop_buf(adev, pipe);
if (r)
return r;
@@ -1141,8 +1066,7 @@ static int mes_v11_0_sw_fini(void *handle)
amdgpu_bo_free_kernel(&adev->mes.eop_gpu_obj[pipe],
&adev->mes.eop_gpu_addr[pipe],
NULL);
-
- mes_v11_0_free_microcode(adev, pipe);
+ amdgpu_ucode_release(&adev->mes.fw[pipe]);
}
amdgpu_bo_free_kernel(&adev->gfx.kiq.ring.mqd_obj,
@@ -1339,6 +1263,22 @@ static int mes_v11_0_resume(void *handle)
return amdgpu_mes_resume(adev);
}
+static int mes_v11_0_early_init(void *handle)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ int pipe, r;
+
+ for (pipe = 0; pipe < AMDGPU_MAX_MES_PIPES; pipe++) {
+ if (!adev->enable_mes_kiq && pipe == AMDGPU_MES_KIQ_PIPE)
+ continue;
+ r = amdgpu_mes_init_microcode(adev, pipe);
+ if (r)
+ return r;
+ }
+
+ return 0;
+}
+
static int mes_v11_0_late_init(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
@@ -1353,6 +1293,7 @@ static int mes_v11_0_late_init(void *handle)
static const struct amd_ip_funcs mes_v11_0_ip_funcs = {
.name = "mes_v11_0",
+ .early_init = mes_v11_0_early_init,
.late_init = mes_v11_0_late_init,
.sw_init = mes_v11_0_sw_init,
.sw_fini = mes_v11_0_sw_fini,
diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c
index 3e51e773f92b..15e7cbeae75b 100644
--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c
@@ -114,7 +114,7 @@ static void mmhub_v1_0_init_system_aperture_regs(struct amdgpu_device *adev)
return;
/* Set default page address. */
- value = amdgpu_gmc_vram_mc2pa(adev, adev->vram_scratch.gpu_addr);
+ value = amdgpu_gmc_vram_mc2pa(adev, adev->mem_scratch.gpu_addr);
WREG32_SOC15(MMHUB, 0, mmMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB,
(u32)(value >> 12));
WREG32_SOC15(MMHUB, 0, mmMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB,
diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_7.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_7.c
index 6fa7090bc6cb..73afbf2facc9 100644
--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_7.c
+++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_7.c
@@ -134,7 +134,7 @@ static void mmhub_v1_7_init_system_aperture_regs(struct amdgpu_device *adev)
}
/* Set default page address. */
- value = amdgpu_gmc_vram_mc2pa(adev, adev->vram_scratch.gpu_addr);
+ value = amdgpu_gmc_vram_mc2pa(adev, adev->mem_scratch.gpu_addr);
WREG32_SOC15(MMHUB, 0, regMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB,
(u32)(value >> 12));
WREG32_SOC15(MMHUB, 0, regMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB,
diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c
index 0e664d0cc8d5..278e32db878d 100644
--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v2_0.c
@@ -234,7 +234,7 @@ static void mmhub_v2_0_init_system_aperture_regs(struct amdgpu_device *adev)
}
/* Set default page address. */
- value = amdgpu_gmc_vram_mc2pa(adev, adev->vram_scratch.gpu_addr);
+ value = amdgpu_gmc_vram_mc2pa(adev, adev->mem_scratch.gpu_addr);
WREG32_SOC15(MMHUB, 0, mmMMMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB,
(u32)(value >> 12));
WREG32_SOC15(MMHUB, 0, mmMMMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB,
diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v2_3.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v2_3.c
index 4638ea7c2eec..fcf2813e70db 100644
--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v2_3.c
+++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v2_3.c
@@ -164,7 +164,7 @@ static void mmhub_v2_3_init_system_aperture_regs(struct amdgpu_device *adev)
max(adev->gmc.fb_end, adev->gmc.agp_end) >> 18);
/* Set default page address. */
- value = amdgpu_gmc_vram_mc2pa(adev, adev->vram_scratch.gpu_addr);
+ value = amdgpu_gmc_vram_mc2pa(adev, adev->mem_scratch.gpu_addr);
WREG32_SOC15(MMHUB, 0, mmMMMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB,
(u32)(value >> 12));
WREG32_SOC15(MMHUB, 0, mmMMMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB,
diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0.c
index 16cc82215e2e..164948c50ac3 100644
--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0.c
@@ -169,26 +169,27 @@ static void mmhub_v3_0_init_system_aperture_regs(struct amdgpu_device *adev)
uint64_t value;
uint32_t tmp;
- if (!amdgpu_sriov_vf(adev)) {
- /*
- * the new L1 policy will block SRIOV guest from writing
- * these regs, and they will be programed at host.
- * so skip programing these regs.
- */
- /* Disable AGP. */
- WREG32_SOC15(MMHUB, 0, regMMMC_VM_AGP_BASE, 0);
- WREG32_SOC15(MMHUB, 0, regMMMC_VM_AGP_TOP, 0);
- WREG32_SOC15(MMHUB, 0, regMMMC_VM_AGP_BOT, 0x00FFFFFF);
-
- /* Program the system aperture low logical page number. */
- WREG32_SOC15(MMHUB, 0, regMMMC_VM_SYSTEM_APERTURE_LOW_ADDR,
- adev->gmc.vram_start >> 18);
- WREG32_SOC15(MMHUB, 0, regMMMC_VM_SYSTEM_APERTURE_HIGH_ADDR,
- adev->gmc.vram_end >> 18);
- }
+ if (amdgpu_sriov_vf(adev))
+ return;
+
+ /*
+ * the new L1 policy will block SRIOV guest from writing
+ * these regs, and they will be programed at host.
+ * so skip programing these regs.
+ */
+ /* Program the AGP BAR */
+ WREG32_SOC15(MMHUB, 0, regMMMC_VM_AGP_BASE, 0);
+ WREG32_SOC15(MMHUB, 0, regMMMC_VM_AGP_BOT, adev->gmc.agp_start >> 24);
+ WREG32_SOC15(MMHUB, 0, regMMMC_VM_AGP_TOP, adev->gmc.agp_end >> 24);
+
+ /* Program the system aperture low logical page number. */
+ WREG32_SOC15(MMHUB, 0, regMMMC_VM_SYSTEM_APERTURE_LOW_ADDR,
+ min(adev->gmc.fb_start, adev->gmc.agp_start) >> 18);
+ WREG32_SOC15(MMHUB, 0, regMMMC_VM_SYSTEM_APERTURE_HIGH_ADDR,
+ max(adev->gmc.fb_end, adev->gmc.agp_end) >> 18);
/* Set default page address. */
- value = adev->vram_scratch.gpu_addr - adev->gmc.vram_start +
+ value = adev->mem_scratch.gpu_addr - adev->gmc.vram_start +
adev->vm_manager.vram_base_offset;
WREG32_SOC15(MMHUB, 0, regMMMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB,
(u32)(value >> 12));
diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_1.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_1.c
index 6bdf2ef0298d..26509b6b8c24 100644
--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_1.c
@@ -183,12 +183,12 @@ static void mmhub_v3_0_1_init_system_aperture_regs(struct amdgpu_device *adev)
*/
/* Program the system aperture low logical page number. */
WREG32_SOC15(MMHUB, 0, regMMMC_VM_SYSTEM_APERTURE_LOW_ADDR,
- adev->gmc.vram_start >> 18);
+ min(adev->gmc.fb_start, adev->gmc.agp_start) >> 18);
WREG32_SOC15(MMHUB, 0, regMMMC_VM_SYSTEM_APERTURE_HIGH_ADDR,
- adev->gmc.vram_end >> 18);
+ max(adev->gmc.fb_end, adev->gmc.agp_end) >> 18);
/* Set default page address. */
- value = adev->vram_scratch.gpu_addr - adev->gmc.vram_start +
+ value = adev->mem_scratch.gpu_addr - adev->gmc.vram_start +
adev->vm_manager.vram_base_offset;
WREG32_SOC15(MMHUB, 0, regMMMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB,
(u32)(value >> 12));
diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_2.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_2.c
index 45465acaa943..26abbc6a47ab 100644
--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_2.c
+++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v3_0_2.c
@@ -162,10 +162,10 @@ static void mmhub_v3_0_2_init_system_aperture_regs(struct amdgpu_device *adev)
uint64_t value;
uint32_t tmp;
- /* Disable AGP. */
+ /* Program the AGP BAR */
WREG32_SOC15(MMHUB, 0, regMMMC_VM_AGP_BASE, 0);
- WREG32_SOC15(MMHUB, 0, regMMMC_VM_AGP_TOP, 0);
- WREG32_SOC15(MMHUB, 0, regMMMC_VM_AGP_BOT, 0x00FFFFFF);
+ WREG32_SOC15(MMHUB, 0, regMMMC_VM_AGP_BOT, adev->gmc.agp_start >> 24);
+ WREG32_SOC15(MMHUB, 0, regMMMC_VM_AGP_TOP, adev->gmc.agp_end >> 24);
if (!amdgpu_sriov_vf(adev)) {
/*
@@ -175,13 +175,13 @@ static void mmhub_v3_0_2_init_system_aperture_regs(struct amdgpu_device *adev)
*/
/* Program the system aperture low logical page number. */
WREG32_SOC15(MMHUB, 0, regMMMC_VM_SYSTEM_APERTURE_LOW_ADDR,
- adev->gmc.vram_start >> 18);
+ min(adev->gmc.fb_start, adev->gmc.agp_start) >> 18);
WREG32_SOC15(MMHUB, 0, regMMMC_VM_SYSTEM_APERTURE_HIGH_ADDR,
- adev->gmc.vram_end >> 18);
+ max(adev->gmc.fb_end, adev->gmc.agp_end) >> 18);
}
/* Set default page address. */
- value = adev->vram_scratch.gpu_addr - adev->gmc.vram_start +
+ value = adev->mem_scratch.gpu_addr - adev->gmc.vram_start +
adev->vm_manager.vram_base_offset;
WREG32_SOC15(MMHUB, 0, regMMMC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB,
(u32)(value >> 12));
diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c
index 445cb06b9d26..72083e96222f 100644
--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c
+++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v9_4.c
@@ -136,7 +136,7 @@ static void mmhub_v9_4_init_system_aperture_regs(struct amdgpu_device *adev,
max(adev->gmc.fb_end, adev->gmc.agp_end) >> 18);
/* Set default page address. */
- value = amdgpu_gmc_vram_mc2pa(adev, adev->vram_scratch.gpu_addr);
+ value = amdgpu_gmc_vram_mc2pa(adev, adev->mem_scratch.gpu_addr);
WREG32_SOC15_OFFSET(
MMHUB, 0,
mmVMSHAREDPF0_MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB,
diff --git a/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c b/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c
index 12906ba74462..63725b2ebc03 100644
--- a/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c
+++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c
@@ -404,6 +404,11 @@ static int xgpu_ai_request_init_data(struct amdgpu_device *adev)
return xgpu_ai_send_access_requests(adev, IDH_REQ_GPU_INIT_DATA);
}
+static void xgpu_ai_ras_poison_handler(struct amdgpu_device *adev)
+{
+ xgpu_ai_send_access_requests(adev, IDH_RAS_POISON);
+}
+
const struct amdgpu_virt_ops xgpu_ai_virt_ops = {
.req_full_gpu = xgpu_ai_request_full_gpu_access,
.rel_full_gpu = xgpu_ai_release_full_gpu_access,
@@ -411,4 +416,5 @@ const struct amdgpu_virt_ops xgpu_ai_virt_ops = {
.wait_reset = NULL,
.trans_msg = xgpu_ai_mailbox_trans_msg,
.req_init_data = xgpu_ai_request_init_data,
+ .ras_poison_handler = xgpu_ai_ras_poison_handler,
};
diff --git a/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.h b/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.h
index fa7e13e0459e..af1a784696bd 100644
--- a/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.h
+++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.h
@@ -39,6 +39,7 @@ enum idh_request {
IDH_LOG_VF_ERROR = 200,
IDH_READY_TO_RESET = 201,
+ IDH_RAS_POISON = 202,
};
enum idh_event {
diff --git a/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c b/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c
index e07757eea7ad..cae1aaa4ddb6 100644
--- a/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c
+++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c
@@ -426,6 +426,11 @@ void xgpu_nv_mailbox_put_irq(struct amdgpu_device *adev)
amdgpu_irq_put(adev, &adev->virt.rcv_irq, 0);
}
+static void xgpu_nv_ras_poison_handler(struct amdgpu_device *adev)
+{
+ xgpu_nv_send_access_requests(adev, IDH_RAS_POISON);
+}
+
const struct amdgpu_virt_ops xgpu_nv_virt_ops = {
.req_full_gpu = xgpu_nv_request_full_gpu_access,
.rel_full_gpu = xgpu_nv_release_full_gpu_access,
@@ -433,4 +438,5 @@ const struct amdgpu_virt_ops xgpu_nv_virt_ops = {
.reset_gpu = xgpu_nv_request_reset,
.wait_reset = NULL,
.trans_msg = xgpu_nv_mailbox_trans_msg,
+ .ras_poison_handler = xgpu_nv_ras_poison_handler,
};
diff --git a/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.h b/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.h
index 73887b0aa1d6..d0221ce08769 100644
--- a/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.h
+++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.h
@@ -39,6 +39,7 @@ enum idh_request {
IDH_LOG_VF_ERROR = 200,
IDH_READY_TO_RESET = 201,
+ IDH_RAS_POISON = 202,
};
enum idh_event {
diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v7_2.c b/drivers/gpu/drm/amd/amdgpu/nbio_v7_2.c
index 31776b12e4c4..4b0d563c6522 100644
--- a/drivers/gpu/drm/amd/amdgpu/nbio_v7_2.c
+++ b/drivers/gpu/drm/amd/amdgpu/nbio_v7_2.c
@@ -382,6 +382,11 @@ static void nbio_v7_2_init_registers(struct amdgpu_device *adev)
if (def != data)
WREG32_PCIE_PORT(SOC15_REG_OFFSET(NBIO, 0, regBIF1_PCIE_MST_CTRL_3), data);
break;
+ case IP_VERSION(7, 5, 1):
+ data = RREG32_SOC15(NBIO, 0, regRCC_DEV2_EPF0_STRAP2);
+ data &= ~RCC_DEV2_EPF0_STRAP2__STRAP_NO_SOFT_RESET_DEV2_F0_MASK;
+ WREG32_SOC15(NBIO, 0, regRCC_DEV2_EPF0_STRAP2, data);
+ fallthrough;
default:
def = data = RREG32_PCIE_PORT(SOC15_REG_OFFSET(NBIO, 0, regPCIE_CONFIG_CNTL));
data = REG_SET_FIELD(data, PCIE_CONFIG_CNTL,
diff --git a/drivers/gpu/drm/amd/amdgpu/nv.c b/drivers/gpu/drm/amd/amdgpu/nv.c
index 6853b93ac82e..d972025f0d20 100644
--- a/drivers/gpu/drm/amd/amdgpu/nv.c
+++ b/drivers/gpu/drm/amd/amdgpu/nv.c
@@ -98,7 +98,7 @@ static const struct amdgpu_video_codecs nv_video_codecs_decode =
};
/* Sienna Cichlid */
-static const struct amdgpu_video_codec_info sc_video_codecs_decode_array[] =
+static const struct amdgpu_video_codec_info sc_video_codecs_decode_array_vcn0[] =
{
{codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 4096, 4096, 3)},
{codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4, 4096, 4096, 5)},
@@ -110,10 +110,27 @@ static const struct amdgpu_video_codec_info sc_video_codecs_decode_array[] =
{codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_AV1, 8192, 4352, 0)},
};
-static const struct amdgpu_video_codecs sc_video_codecs_decode =
+static const struct amdgpu_video_codec_info sc_video_codecs_decode_array_vcn1[] =
{
- .codec_count = ARRAY_SIZE(sc_video_codecs_decode_array),
- .codec_array = sc_video_codecs_decode_array,
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 4096, 4096, 3)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4, 4096, 4096, 5)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4096, 52)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VC1, 4096, 4096, 4)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 8192, 4352, 186)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 4096, 4096, 0)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VP9, 8192, 4352, 0)},
+};
+
+static const struct amdgpu_video_codecs sc_video_codecs_decode_vcn0 =
+{
+ .codec_count = ARRAY_SIZE(sc_video_codecs_decode_array_vcn0),
+ .codec_array = sc_video_codecs_decode_array_vcn0,
+};
+
+static const struct amdgpu_video_codecs sc_video_codecs_decode_vcn1 =
+{
+ .codec_count = ARRAY_SIZE(sc_video_codecs_decode_array_vcn1),
+ .codec_array = sc_video_codecs_decode_array_vcn1,
};
/* SRIOV Sienna Cichlid, not const since data is controlled by host */
@@ -123,7 +140,7 @@ static struct amdgpu_video_codec_info sriov_sc_video_codecs_encode_array[] =
{codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 4096, 2304, 0)},
};
-static struct amdgpu_video_codec_info sriov_sc_video_codecs_decode_array[] =
+static struct amdgpu_video_codec_info sriov_sc_video_codecs_decode_array_vcn0[] =
{
{codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 4096, 4096, 3)},
{codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4, 4096, 4096, 5)},
@@ -135,16 +152,33 @@ static struct amdgpu_video_codec_info sriov_sc_video_codecs_decode_array[] =
{codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_AV1, 8192, 4352, 0)},
};
+static struct amdgpu_video_codec_info sriov_sc_video_codecs_decode_array_vcn1[] =
+{
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2, 4096, 4096, 3)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4, 4096, 4096, 5)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4096, 52)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VC1, 4096, 4096, 4)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 8192, 4352, 186)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 4096, 4096, 0)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VP9, 8192, 4352, 0)},
+};
+
static struct amdgpu_video_codecs sriov_sc_video_codecs_encode =
{
.codec_count = ARRAY_SIZE(sriov_sc_video_codecs_encode_array),
.codec_array = sriov_sc_video_codecs_encode_array,
};
-static struct amdgpu_video_codecs sriov_sc_video_codecs_decode =
+static struct amdgpu_video_codecs sriov_sc_video_codecs_decode_vcn0 =
{
- .codec_count = ARRAY_SIZE(sriov_sc_video_codecs_decode_array),
- .codec_array = sriov_sc_video_codecs_decode_array,
+ .codec_count = ARRAY_SIZE(sriov_sc_video_codecs_decode_array_vcn0),
+ .codec_array = sriov_sc_video_codecs_decode_array_vcn0,
+};
+
+static struct amdgpu_video_codecs sriov_sc_video_codecs_decode_vcn1 =
+{
+ .codec_count = ARRAY_SIZE(sriov_sc_video_codecs_decode_array_vcn1),
+ .codec_array = sriov_sc_video_codecs_decode_array_vcn1,
};
/* Beige Goby*/
@@ -181,20 +215,37 @@ static const struct amdgpu_video_codecs yc_video_codecs_decode = {
static int nv_query_video_codecs(struct amdgpu_device *adev, bool encode,
const struct amdgpu_video_codecs **codecs)
{
+ if (adev->vcn.num_vcn_inst == hweight8(adev->vcn.harvest_config))
+ return -EINVAL;
+
switch (adev->ip_versions[UVD_HWIP][0]) {
case IP_VERSION(3, 0, 0):
case IP_VERSION(3, 0, 64):
case IP_VERSION(3, 0, 192):
if (amdgpu_sriov_vf(adev)) {
- if (encode)
- *codecs = &sriov_sc_video_codecs_encode;
- else
- *codecs = &sriov_sc_video_codecs_decode;
+ if (adev->vcn.harvest_config & AMDGPU_VCN_HARVEST_VCN0) {
+ if (encode)
+ *codecs = &sriov_sc_video_codecs_encode;
+ else
+ *codecs = &sriov_sc_video_codecs_decode_vcn1;
+ } else {
+ if (encode)
+ *codecs = &sriov_sc_video_codecs_encode;
+ else
+ *codecs = &sriov_sc_video_codecs_decode_vcn0;
+ }
} else {
- if (encode)
- *codecs = &nv_video_codecs_encode;
- else
- *codecs = &sc_video_codecs_decode;
+ if (adev->vcn.harvest_config & AMDGPU_VCN_HARVEST_VCN0) {
+ if (encode)
+ *codecs = &nv_video_codecs_encode;
+ else
+ *codecs = &sc_video_codecs_decode_vcn1;
+ } else {
+ if (encode)
+ *codecs = &nv_video_codecs_encode;
+ else
+ *codecs = &sc_video_codecs_decode_vcn0;
+ }
}
return 0;
case IP_VERSION(3, 0, 16):
@@ -202,7 +253,7 @@ static int nv_query_video_codecs(struct amdgpu_device *adev, bool encode,
if (encode)
*codecs = &nv_video_codecs_encode;
else
- *codecs = &sc_video_codecs_decode;
+ *codecs = &sc_video_codecs_decode_vcn0;
return 0;
case IP_VERSION(3, 1, 1):
case IP_VERSION(3, 1, 2):
@@ -993,9 +1044,19 @@ static int nv_common_late_init(void *handle)
if (amdgpu_sriov_vf(adev)) {
xgpu_nv_mailbox_get_irq(adev);
- amdgpu_virt_update_sriov_video_codec(adev,
- sriov_sc_video_codecs_encode_array, ARRAY_SIZE(sriov_sc_video_codecs_encode_array),
- sriov_sc_video_codecs_decode_array, ARRAY_SIZE(sriov_sc_video_codecs_decode_array));
+ if (adev->vcn.harvest_config & AMDGPU_VCN_HARVEST_VCN0) {
+ amdgpu_virt_update_sriov_video_codec(adev,
+ sriov_sc_video_codecs_encode_array,
+ ARRAY_SIZE(sriov_sc_video_codecs_encode_array),
+ sriov_sc_video_codecs_decode_array_vcn1,
+ ARRAY_SIZE(sriov_sc_video_codecs_decode_array_vcn1));
+ } else {
+ amdgpu_virt_update_sriov_video_codec(adev,
+ sriov_sc_video_codecs_encode_array,
+ ARRAY_SIZE(sriov_sc_video_codecs_encode_array),
+ sriov_sc_video_codecs_decode_array_vcn1,
+ ARRAY_SIZE(sriov_sc_video_codecs_decode_array_vcn1));
+ }
}
return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c
index 9de46fa8f46c..e1b7fca09666 100644
--- a/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c
@@ -47,83 +47,17 @@ MODULE_FIRMWARE("amdgpu/raven_ta.bin");
static int psp_v10_0_init_microcode(struct psp_context *psp)
{
struct amdgpu_device *adev = psp->adev;
- const char *chip_name;
- char fw_name[30];
+ char ucode_prefix[30];
int err = 0;
- const struct ta_firmware_header_v1_0 *ta_hdr;
DRM_DEBUG("\n");
- switch (adev->asic_type) {
- case CHIP_RAVEN:
- if (adev->apu_flags & AMD_APU_IS_RAVEN2)
- chip_name = "raven2";
- else if (adev->apu_flags & AMD_APU_IS_PICASSO)
- chip_name = "picasso";
- else
- chip_name = "raven";
- break;
- default: BUG();
- }
-
- err = psp_init_asd_microcode(psp, chip_name);
+ amdgpu_ucode_ip_version_decode(adev, MP0_HWIP, ucode_prefix, sizeof(ucode_prefix));
+
+ err = psp_init_asd_microcode(psp, ucode_prefix);
if (err)
- goto out;
-
- snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ta.bin", chip_name);
- err = request_firmware(&adev->psp.ta_fw, fw_name, adev->dev);
- if (err) {
- release_firmware(adev->psp.ta_fw);
- adev->psp.ta_fw = NULL;
- dev_info(adev->dev,
- "psp v10.0: Failed to load firmware \"%s\"\n",
- fw_name);
- } else {
- err = amdgpu_ucode_validate(adev->psp.ta_fw);
- if (err)
- goto out2;
-
- ta_hdr = (const struct ta_firmware_header_v1_0 *)
- adev->psp.ta_fw->data;
- adev->psp.hdcp_context.context.bin_desc.fw_version =
- le32_to_cpu(ta_hdr->hdcp.fw_version);
- adev->psp.hdcp_context.context.bin_desc.size_bytes =
- le32_to_cpu(ta_hdr->hdcp.size_bytes);
- adev->psp.hdcp_context.context.bin_desc.start_addr =
- (uint8_t *)ta_hdr +
- le32_to_cpu(ta_hdr->header.ucode_array_offset_bytes);
-
- adev->psp.dtm_context.context.bin_desc.fw_version =
- le32_to_cpu(ta_hdr->dtm.fw_version);
- adev->psp.dtm_context.context.bin_desc.size_bytes =
- le32_to_cpu(ta_hdr->dtm.size_bytes);
- adev->psp.dtm_context.context.bin_desc.start_addr =
- (uint8_t *)adev->psp.hdcp_context.context.bin_desc.start_addr +
- le32_to_cpu(ta_hdr->dtm.offset_bytes);
-
- adev->psp.securedisplay_context.context.bin_desc.fw_version =
- le32_to_cpu(ta_hdr->securedisplay.fw_version);
- adev->psp.securedisplay_context.context.bin_desc.size_bytes =
- le32_to_cpu(ta_hdr->securedisplay.size_bytes);
- adev->psp.securedisplay_context.context.bin_desc.start_addr =
- (uint8_t *)adev->psp.hdcp_context.context.bin_desc.start_addr +
- le32_to_cpu(ta_hdr->securedisplay.offset_bytes);
-
- adev->psp.ta_fw_version = le32_to_cpu(ta_hdr->header.ucode_version);
- }
-
- return 0;
-
-out2:
- release_firmware(adev->psp.ta_fw);
- adev->psp.ta_fw = NULL;
-out:
- if (err) {
- dev_err(adev->dev,
- "psp v10.0: Failed to load firmware \"%s\"\n",
- fw_name);
- }
-
- return err;
+ return err;
+
+ return psp_init_ta_microcode(psp, ucode_prefix);
}
static int psp_v10_0_ring_create(struct psp_context *psp,
diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
index bd3e3e23a939..8f84fe40abbb 100644
--- a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
@@ -88,159 +88,56 @@ MODULE_FIRMWARE("amdgpu/beige_goby_ta.bin");
static int psp_v11_0_init_microcode(struct psp_context *psp)
{
struct amdgpu_device *adev = psp->adev;
- const char *chip_name;
- char fw_name[PSP_FW_NAME_LEN];
+ char ucode_prefix[30];
int err = 0;
- const struct ta_firmware_header_v1_0 *ta_hdr;
DRM_DEBUG("\n");
- switch (adev->ip_versions[MP0_HWIP][0]) {
- case IP_VERSION(11, 0, 2):
- chip_name = "vega20";
- break;
- case IP_VERSION(11, 0, 0):
- chip_name = "navi10";
- break;
- case IP_VERSION(11, 0, 5):
- chip_name = "navi14";
- break;
- case IP_VERSION(11, 0, 9):
- chip_name = "navi12";
- break;
- case IP_VERSION(11, 0, 4):
- chip_name = "arcturus";
- break;
- case IP_VERSION(11, 0, 7):
- chip_name = "sienna_cichlid";
- break;
- case IP_VERSION(11, 0, 11):
- chip_name = "navy_flounder";
- break;
- case IP_VERSION(11, 5, 0):
- chip_name = "vangogh";
- break;
- case IP_VERSION(11, 0, 12):
- chip_name = "dimgrey_cavefish";
- break;
- case IP_VERSION(11, 0, 13):
- chip_name = "beige_goby";
- break;
- default:
- BUG();
- }
-
+ amdgpu_ucode_ip_version_decode(adev, MP0_HWIP, ucode_prefix, sizeof(ucode_prefix));
switch (adev->ip_versions[MP0_HWIP][0]) {
case IP_VERSION(11, 0, 2):
case IP_VERSION(11, 0, 4):
- err = psp_init_sos_microcode(psp, chip_name);
+ err = psp_init_sos_microcode(psp, ucode_prefix);
if (err)
return err;
- err = psp_init_asd_microcode(psp, chip_name);
+ err = psp_init_asd_microcode(psp, ucode_prefix);
if (err)
return err;
- snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ta.bin", chip_name);
- err = request_firmware(&adev->psp.ta_fw, fw_name, adev->dev);
- if (err) {
- release_firmware(adev->psp.ta_fw);
- adev->psp.ta_fw = NULL;
- dev_info(adev->dev,
- "psp v11.0: Failed to load firmware \"%s\"\n", fw_name);
- } else {
- err = amdgpu_ucode_validate(adev->psp.ta_fw);
- if (err)
- goto out2;
-
- ta_hdr = (const struct ta_firmware_header_v1_0 *)adev->psp.ta_fw->data;
- adev->psp.xgmi_context.context.bin_desc.fw_version =
- le32_to_cpu(ta_hdr->xgmi.fw_version);
- adev->psp.xgmi_context.context.bin_desc.size_bytes =
- le32_to_cpu(ta_hdr->xgmi.size_bytes);
- adev->psp.xgmi_context.context.bin_desc.start_addr =
- (uint8_t *)ta_hdr +
- le32_to_cpu(ta_hdr->header.ucode_array_offset_bytes);
- adev->psp.ta_fw_version = le32_to_cpu(ta_hdr->header.ucode_version);
- adev->psp.ras_context.context.bin_desc.fw_version =
- le32_to_cpu(ta_hdr->ras.fw_version);
- adev->psp.ras_context.context.bin_desc.size_bytes =
- le32_to_cpu(ta_hdr->ras.size_bytes);
- adev->psp.ras_context.context.bin_desc.start_addr =
- (uint8_t *)adev->psp.xgmi_context.context.bin_desc.start_addr +
- le32_to_cpu(ta_hdr->ras.offset_bytes);
- }
+ err = psp_init_ta_microcode(psp, ucode_prefix);
+ adev->psp.securedisplay_context.context.bin_desc.size_bytes = 0;
break;
case IP_VERSION(11, 0, 0):
case IP_VERSION(11, 0, 5):
case IP_VERSION(11, 0, 9):
- err = psp_init_sos_microcode(psp, chip_name);
+ err = psp_init_sos_microcode(psp, ucode_prefix);
if (err)
return err;
- err = psp_init_asd_microcode(psp, chip_name);
+ err = psp_init_asd_microcode(psp, ucode_prefix);
if (err)
return err;
- snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ta.bin", chip_name);
- err = request_firmware(&adev->psp.ta_fw, fw_name, adev->dev);
- if (err) {
- release_firmware(adev->psp.ta_fw);
- adev->psp.ta_fw = NULL;
- dev_info(adev->dev,
- "psp v11.0: Failed to load firmware \"%s\"\n", fw_name);
- } else {
- err = amdgpu_ucode_validate(adev->psp.ta_fw);
- if (err)
- goto out2;
-
- ta_hdr = (const struct ta_firmware_header_v1_0 *)adev->psp.ta_fw->data;
- adev->psp.hdcp_context.context.bin_desc.fw_version =
- le32_to_cpu(ta_hdr->hdcp.fw_version);
- adev->psp.hdcp_context.context.bin_desc.size_bytes =
- le32_to_cpu(ta_hdr->hdcp.size_bytes);
- adev->psp.hdcp_context.context.bin_desc.start_addr =
- (uint8_t *)ta_hdr +
- le32_to_cpu(
- ta_hdr->header.ucode_array_offset_bytes);
-
- adev->psp.ta_fw_version = le32_to_cpu(ta_hdr->header.ucode_version);
-
- adev->psp.dtm_context.context.bin_desc.fw_version =
- le32_to_cpu(ta_hdr->dtm.fw_version);
- adev->psp.dtm_context.context.bin_desc.size_bytes =
- le32_to_cpu(ta_hdr->dtm.size_bytes);
- adev->psp.dtm_context.context.bin_desc.start_addr =
- (uint8_t *)adev->psp.hdcp_context.context
- .bin_desc.start_addr +
- le32_to_cpu(ta_hdr->dtm.offset_bytes);
- }
+ err = psp_init_ta_microcode(psp, ucode_prefix);
+ adev->psp.securedisplay_context.context.bin_desc.size_bytes = 0;
break;
case IP_VERSION(11, 0, 7):
case IP_VERSION(11, 0, 11):
case IP_VERSION(11, 0, 12):
case IP_VERSION(11, 0, 13):
- err = psp_init_sos_microcode(psp, chip_name);
- if (err)
- return err;
- err = psp_init_ta_microcode(psp, chip_name);
+ err = psp_init_sos_microcode(psp, ucode_prefix);
if (err)
return err;
+ err = psp_init_ta_microcode(psp, ucode_prefix);
break;
case IP_VERSION(11, 5, 0):
- err = psp_init_asd_microcode(psp, chip_name);
- if (err)
- return err;
- err = psp_init_toc_microcode(psp, chip_name);
+ err = psp_init_asd_microcode(psp, ucode_prefix);
if (err)
return err;
+ err = psp_init_toc_microcode(psp, ucode_prefix);
break;
default:
BUG();
}
- return 0;
-
-out2:
- release_firmware(adev->psp.ta_fw);
- adev->psp.ta_fw = NULL;
return err;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
index 8ed2281b6557..fcd708eae75c 100644
--- a/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
@@ -48,83 +48,25 @@ MODULE_FIRMWARE("amdgpu/green_sardine_ta.bin");
static int psp_v12_0_init_microcode(struct psp_context *psp)
{
struct amdgpu_device *adev = psp->adev;
- const char *chip_name;
- char fw_name[30];
+ char ucode_prefix[30];
int err = 0;
- const struct ta_firmware_header_v1_0 *ta_hdr;
DRM_DEBUG("\n");
- switch (adev->asic_type) {
- case CHIP_RENOIR:
- if (adev->apu_flags & AMD_APU_IS_RENOIR)
- chip_name = "renoir";
- else
- chip_name = "green_sardine";
- break;
- default:
- BUG();
- }
+ amdgpu_ucode_ip_version_decode(adev, MP0_HWIP, ucode_prefix, sizeof(ucode_prefix));
- err = psp_init_asd_microcode(psp, chip_name);
+ err = psp_init_asd_microcode(psp, ucode_prefix);
if (err)
return err;
- snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ta.bin", chip_name);
- err = request_firmware(&adev->psp.ta_fw, fw_name, adev->dev);
- if (err) {
- release_firmware(adev->psp.ta_fw);
- adev->psp.ta_fw = NULL;
- dev_info(adev->dev,
- "psp v12.0: Failed to load firmware \"%s\"\n",
- fw_name);
- } else {
- err = amdgpu_ucode_validate(adev->psp.ta_fw);
- if (err)
- goto out;
-
- ta_hdr = (const struct ta_firmware_header_v1_0 *)
- adev->psp.ta_fw->data;
- adev->psp.hdcp_context.context.bin_desc.fw_version =
- le32_to_cpu(ta_hdr->hdcp.fw_version);
- adev->psp.hdcp_context.context.bin_desc.size_bytes =
- le32_to_cpu(ta_hdr->hdcp.size_bytes);
- adev->psp.hdcp_context.context.bin_desc.start_addr =
- (uint8_t *)ta_hdr +
- le32_to_cpu(ta_hdr->header.ucode_array_offset_bytes);
-
- adev->psp.ta_fw_version = le32_to_cpu(ta_hdr->header.ucode_version);
-
- adev->psp.dtm_context.context.bin_desc.fw_version =
- le32_to_cpu(ta_hdr->dtm.fw_version);
- adev->psp.dtm_context.context.bin_desc.size_bytes =
- le32_to_cpu(ta_hdr->dtm.size_bytes);
- adev->psp.dtm_context.context.bin_desc.start_addr =
- (uint8_t *)adev->psp.hdcp_context.context.bin_desc.start_addr +
- le32_to_cpu(ta_hdr->dtm.offset_bytes);
-
- if (adev->apu_flags & AMD_APU_IS_RENOIR) {
- adev->psp.securedisplay_context.context.bin_desc.fw_version =
- le32_to_cpu(ta_hdr->securedisplay.fw_version);
- adev->psp.securedisplay_context.context.bin_desc.size_bytes =
- le32_to_cpu(ta_hdr->securedisplay.size_bytes);
- adev->psp.securedisplay_context.context.bin_desc.start_addr =
- (uint8_t *)adev->psp.hdcp_context.context.bin_desc.start_addr +
- le32_to_cpu(ta_hdr->securedisplay.offset_bytes);
- }
- }
-
- return 0;
+ err = psp_init_ta_microcode(psp, ucode_prefix);
+ if (err)
+ return err;
-out:
- release_firmware(adev->psp.ta_fw);
- adev->psp.ta_fw = NULL;
- if (err) {
- dev_err(adev->dev,
- "psp v12.0: Failed to load firmware \"%s\"\n",
- fw_name);
- }
+ /* only supported on renoir */
+ if (!(adev->apu_flags & AMD_APU_IS_RENOIR))
+ adev->psp.securedisplay_context.context.bin_desc.size_bytes = 0;
- return err;
+ return 0;
}
static int psp_v12_0_bootloader_load_sysdrv(struct psp_context *psp)
diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c
index e6a26a7e5e5e..d62fcc77af95 100644
--- a/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c
@@ -70,32 +70,19 @@ MODULE_FIRMWARE("amdgpu/psp_13_0_11_ta.bin");
static int psp_v13_0_init_microcode(struct psp_context *psp)
{
struct amdgpu_device *adev = psp->adev;
- const char *chip_name;
char ucode_prefix[30];
int err = 0;
- switch (adev->ip_versions[MP0_HWIP][0]) {
- case IP_VERSION(13, 0, 2):
- chip_name = "aldebaran";
- break;
- case IP_VERSION(13, 0, 1):
- case IP_VERSION(13, 0, 3):
- chip_name = "yellow_carp";
- break;
- default:
- amdgpu_ucode_ip_version_decode(adev, MP0_HWIP, ucode_prefix, sizeof(ucode_prefix));
- chip_name = ucode_prefix;
- break;
- }
+ amdgpu_ucode_ip_version_decode(adev, MP0_HWIP, ucode_prefix, sizeof(ucode_prefix));
switch (adev->ip_versions[MP0_HWIP][0]) {
case IP_VERSION(13, 0, 2):
- err = psp_init_sos_microcode(psp, chip_name);
+ err = psp_init_sos_microcode(psp, ucode_prefix);
if (err)
return err;
/* It's not necessary to load ras ta on Guest side */
if (!amdgpu_sriov_vf(adev)) {
- err = psp_init_ta_microcode(&adev->psp, chip_name);
+ err = psp_init_ta_microcode(psp, ucode_prefix);
if (err)
return err;
}
@@ -105,21 +92,21 @@ static int psp_v13_0_init_microcode(struct psp_context *psp)
case IP_VERSION(13, 0, 5):
case IP_VERSION(13, 0, 8):
case IP_VERSION(13, 0, 11):
- err = psp_init_toc_microcode(psp, chip_name);
+ err = psp_init_toc_microcode(psp, ucode_prefix);
if (err)
return err;
- err = psp_init_ta_microcode(psp, chip_name);
+ err = psp_init_ta_microcode(psp, ucode_prefix);
if (err)
return err;
break;
case IP_VERSION(13, 0, 0):
case IP_VERSION(13, 0, 7):
case IP_VERSION(13, 0, 10):
- err = psp_init_sos_microcode(psp, chip_name);
+ err = psp_init_sos_microcode(psp, ucode_prefix);
if (err)
return err;
/* It's not necessary to load ras ta on Guest side */
- err = psp_init_ta_microcode(psp, chip_name);
+ err = psp_init_ta_microcode(psp, ucode_prefix);
if (err)
return err;
break;
diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v13_0_4.c b/drivers/gpu/drm/amd/amdgpu/psp_v13_0_4.c
index 9d4e24e518e8..d5ba58eba3e2 100644
--- a/drivers/gpu/drm/amd/amdgpu/psp_v13_0_4.c
+++ b/drivers/gpu/drm/amd/amdgpu/psp_v13_0_4.c
@@ -35,25 +35,17 @@ MODULE_FIRMWARE("amdgpu/psp_13_0_4_ta.bin");
static int psp_v13_0_4_init_microcode(struct psp_context *psp)
{
struct amdgpu_device *adev = psp->adev;
- const char *chip_name;
char ucode_prefix[30];
int err = 0;
- switch (adev->ip_versions[MP0_HWIP][0]) {
- case IP_VERSION(13, 0, 4):
- amdgpu_ucode_ip_version_decode(adev, MP0_HWIP, ucode_prefix, sizeof(ucode_prefix));
- chip_name = ucode_prefix;
- break;
- default:
- BUG();
- }
+ amdgpu_ucode_ip_version_decode(adev, MP0_HWIP, ucode_prefix, sizeof(ucode_prefix));
switch (adev->ip_versions[MP0_HWIP][0]) {
case IP_VERSION(13, 0, 4):
- err = psp_init_toc_microcode(psp, chip_name);
+ err = psp_init_toc_microcode(psp, ucode_prefix);
if (err)
return err;
- err = psp_init_ta_microcode(psp, chip_name);
+ err = psp_init_ta_microcode(psp, ucode_prefix);
if (err)
return err;
break;
diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
index 157147c6c94e..f6b75e3e47ff 100644
--- a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
@@ -57,26 +57,18 @@ static int psp_v3_1_ring_stop(struct psp_context *psp,
static int psp_v3_1_init_microcode(struct psp_context *psp)
{
struct amdgpu_device *adev = psp->adev;
- const char *chip_name;
+ char ucode_prefix[30];
int err = 0;
DRM_DEBUG("\n");
- switch (adev->asic_type) {
- case CHIP_VEGA10:
- chip_name = "vega10";
- break;
- case CHIP_VEGA12:
- chip_name = "vega12";
- break;
- default: BUG();
- }
+ amdgpu_ucode_ip_version_decode(adev, MP0_HWIP, ucode_prefix, sizeof(ucode_prefix));
- err = psp_init_sos_microcode(psp, chip_name);
+ err = psp_init_sos_microcode(psp, ucode_prefix);
if (err)
return err;
- err = psp_init_asd_microcode(psp, chip_name);
+ err = psp_init_asd_microcode(psp, ucode_prefix);
if (err)
return err;
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c
index c52d246a1d96..fd2a7b66ac56 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c
@@ -113,10 +113,9 @@ static void sdma_v2_4_init_golden_registers(struct amdgpu_device *adev)
static void sdma_v2_4_free_microcode(struct amdgpu_device *adev)
{
int i;
- for (i = 0; i < adev->sdma.num_instances; i++) {
- release_firmware(adev->sdma.instance[i].fw);
- adev->sdma.instance[i].fw = NULL;
- }
+
+ for (i = 0; i < adev->sdma.num_instances; i++)
+ amdgpu_ucode_release(&adev->sdma.instance[i].fw);
}
/**
@@ -151,10 +150,7 @@ static int sdma_v2_4_init_microcode(struct amdgpu_device *adev)
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sdma.bin", chip_name);
else
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sdma1.bin", chip_name);
- err = request_firmware(&adev->sdma.instance[i].fw, fw_name, adev->dev);
- if (err)
- goto out;
- err = amdgpu_ucode_validate(adev->sdma.instance[i].fw);
+ err = amdgpu_ucode_request(adev, &adev->sdma.instance[i].fw, fw_name);
if (err)
goto out;
hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma.instance[i].fw->data;
@@ -176,10 +172,8 @@ static int sdma_v2_4_init_microcode(struct amdgpu_device *adev)
out:
if (err) {
pr_err("sdma_v2_4: Failed to load firmware \"%s\"\n", fw_name);
- for (i = 0; i < adev->sdma.num_instances; i++) {
- release_firmware(adev->sdma.instance[i].fw);
- adev->sdma.instance[i].fw = NULL;
- }
+ for (i = 0; i < adev->sdma.num_instances; i++)
+ amdgpu_ucode_release(&adev->sdma.instance[i].fw);
}
return err;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c
index 486d9b5c1b9e..e572389089d2 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c
@@ -250,10 +250,9 @@ static void sdma_v3_0_init_golden_registers(struct amdgpu_device *adev)
static void sdma_v3_0_free_microcode(struct amdgpu_device *adev)
{
int i;
- for (i = 0; i < adev->sdma.num_instances; i++) {
- release_firmware(adev->sdma.instance[i].fw);
- adev->sdma.instance[i].fw = NULL;
- }
+
+ for (i = 0; i < adev->sdma.num_instances; i++)
+ amdgpu_ucode_release(&adev->sdma.instance[i].fw);
}
/**
@@ -309,10 +308,7 @@ static int sdma_v3_0_init_microcode(struct amdgpu_device *adev)
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sdma.bin", chip_name);
else
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sdma1.bin", chip_name);
- err = request_firmware(&adev->sdma.instance[i].fw, fw_name, adev->dev);
- if (err)
- goto out;
- err = amdgpu_ucode_validate(adev->sdma.instance[i].fw);
+ err = amdgpu_ucode_request(adev, &adev->sdma.instance[i].fw, fw_name);
if (err)
goto out;
hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma.instance[i].fw->data;
@@ -332,10 +328,8 @@ static int sdma_v3_0_init_microcode(struct amdgpu_device *adev)
out:
if (err) {
pr_err("sdma_v3_0: Failed to load firmware \"%s\"\n", fw_name);
- for (i = 0; i < adev->sdma.num_instances; i++) {
- release_firmware(adev->sdma.instance[i].fw);
- adev->sdma.instance[i].fw = NULL;
- }
+ for (i = 0; i < adev->sdma.num_instances; i++)
+ amdgpu_ucode_release(&adev->sdma.instance[i].fw);
}
return err;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
index 4d780e4430e7..b5affba22156 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
@@ -575,60 +575,17 @@ static void sdma_v4_0_setup_ulv(struct amdgpu_device *adev)
// vega10 real chip need to use PSP to load firmware
static int sdma_v4_0_init_microcode(struct amdgpu_device *adev)
{
- const char *chip_name;
- char fw_name[30];
int ret, i;
- DRM_DEBUG("\n");
-
- switch (adev->ip_versions[SDMA0_HWIP][0]) {
- case IP_VERSION(4, 0, 0):
- chip_name = "vega10";
- break;
- case IP_VERSION(4, 0, 1):
- chip_name = "vega12";
- break;
- case IP_VERSION(4, 2, 0):
- chip_name = "vega20";
- break;
- case IP_VERSION(4, 1, 0):
- case IP_VERSION(4, 1, 1):
- if (adev->apu_flags & AMD_APU_IS_RAVEN2)
- chip_name = "raven2";
- else if (adev->apu_flags & AMD_APU_IS_PICASSO)
- chip_name = "picasso";
- else
- chip_name = "raven";
- break;
- case IP_VERSION(4, 2, 2):
- chip_name = "arcturus";
- break;
- case IP_VERSION(4, 1, 2):
- if (adev->apu_flags & AMD_APU_IS_RENOIR)
- chip_name = "renoir";
- else
- chip_name = "green_sardine";
- break;
- case IP_VERSION(4, 4, 0):
- chip_name = "aldebaran";
- break;
- default:
- BUG();
- }
-
for (i = 0; i < adev->sdma.num_instances; i++) {
- if (i == 0)
- snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sdma.bin", chip_name);
- else
- snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sdma%d.bin", chip_name, i);
if (adev->ip_versions[SDMA0_HWIP][0] == IP_VERSION(4, 2, 2) ||
adev->ip_versions[SDMA0_HWIP][0] == IP_VERSION(4, 4, 0)) {
/* Acturus & Aldebaran will leverage the same FW memory
for every SDMA instance */
- ret = amdgpu_sdma_init_microcode(adev, fw_name, 0, true);
+ ret = amdgpu_sdma_init_microcode(adev, 0, true);
break;
} else {
- ret = amdgpu_sdma_init_microcode(adev, fw_name, i, false);
+ ret = amdgpu_sdma_init_microcode(adev, i, false);
if (ret)
return ret;
}
@@ -1894,6 +1851,11 @@ static int sdma_v4_0_sw_init(void *handle)
}
}
+ if (amdgpu_sdma_ras_sw_init(adev)) {
+ dev_err(adev->dev, "Failed to initialize sdma ras block!\n");
+ return -EINVAL;
+ }
+
return r;
}
@@ -2731,22 +2693,6 @@ static void sdma_v4_0_set_ras_funcs(struct amdgpu_device *adev)
break;
}
- if (adev->sdma.ras) {
- amdgpu_ras_register_ras_block(adev, &adev->sdma.ras->ras_block);
-
- strcpy(adev->sdma.ras->ras_block.ras_comm.name, "sdma");
- adev->sdma.ras->ras_block.ras_comm.block = AMDGPU_RAS_BLOCK__SDMA;
- adev->sdma.ras->ras_block.ras_comm.type = AMDGPU_RAS_ERROR__MULTI_UNCORRECTABLE;
- adev->sdma.ras_if = &adev->sdma.ras->ras_block.ras_comm;
-
- /* If don't define special ras_late_init function, use default ras_late_init */
- if (!adev->sdma.ras->ras_block.ras_late_init)
- adev->sdma.ras->ras_block.ras_late_init = amdgpu_sdma_ras_late_init;
-
- /* If not defined special ras_cb function, use default ras_cb */
- if (!adev->sdma.ras->ras_block.ras_cb)
- adev->sdma.ras->ras_block.ras_cb = amdgpu_sdma_process_ras_data_cb;
- }
}
const struct amdgpu_ip_block_version sdma_v4_0_ip_block = {
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c
index d4d9f196db83..1941b3b7c5d9 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c
@@ -237,39 +237,13 @@ static void sdma_v5_0_init_golden_registers(struct amdgpu_device *adev)
// emulation only, won't work on real chip
// navi10 real chip need to use PSP to load firmware
static int sdma_v5_0_init_microcode(struct amdgpu_device *adev)
-{
- const char *chip_name;
- char fw_name[40];
- int ret, i;
+{ int ret, i;
if (amdgpu_sriov_vf(adev) && (adev->ip_versions[SDMA0_HWIP][0] == IP_VERSION(5, 0, 5)))
return 0;
- DRM_DEBUG("\n");
-
- switch (adev->ip_versions[SDMA0_HWIP][0]) {
- case IP_VERSION(5, 0, 0):
- chip_name = "navi10";
- break;
- case IP_VERSION(5, 0, 2):
- chip_name = "navi14";
- break;
- case IP_VERSION(5, 0, 5):
- chip_name = "navi12";
- break;
- case IP_VERSION(5, 0, 1):
- chip_name = "cyan_skillfish2";
- break;
- default:
- BUG();
- }
-
for (i = 0; i < adev->sdma.num_instances; i++) {
- if (i == 0)
- snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sdma.bin", chip_name);
- else
- snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_sdma1.bin", chip_name);
- ret = amdgpu_sdma_init_microcode(adev, fw_name, i, false);
+ ret = amdgpu_sdma_init_microcode(adev, i, false);
if (ret)
return ret;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c b/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c
index 809eca54fc61..8e445eb9dd49 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c
@@ -89,59 +89,6 @@ static u32 sdma_v5_2_get_reg_offset(struct amdgpu_device *adev, u32 instance, u3
return base + internal_offset;
}
-/**
- * sdma_v5_2_init_microcode - load ucode images from disk
- *
- * @adev: amdgpu_device pointer
- *
- * Use the firmware interface to load the ucode images into
- * the driver (not loaded into hw).
- * Returns 0 on success, error on failure.
- */
-
-// emulation only, won't work on real chip
-// navi10 real chip need to use PSP to load firmware
-static int sdma_v5_2_init_microcode(struct amdgpu_device *adev)
-{
- const char *chip_name;
- char fw_name[40];
-
- DRM_DEBUG("\n");
-
- switch (adev->ip_versions[SDMA0_HWIP][0]) {
- case IP_VERSION(5, 2, 0):
- chip_name = "sienna_cichlid_sdma";
- break;
- case IP_VERSION(5, 2, 2):
- chip_name = "navy_flounder_sdma";
- break;
- case IP_VERSION(5, 2, 1):
- chip_name = "vangogh_sdma";
- break;
- case IP_VERSION(5, 2, 4):
- chip_name = "dimgrey_cavefish_sdma";
- break;
- case IP_VERSION(5, 2, 5):
- chip_name = "beige_goby_sdma";
- break;
- case IP_VERSION(5, 2, 3):
- chip_name = "yellow_carp_sdma";
- break;
- case IP_VERSION(5, 2, 6):
- chip_name = "sdma_5_2_6";
- break;
- case IP_VERSION(5, 2, 7):
- chip_name = "sdma_5_2_7";
- break;
- default:
- BUG();
- }
-
- snprintf(fw_name, sizeof(fw_name), "amdgpu/%s.bin", chip_name);
-
- return amdgpu_sdma_init_microcode(adev, fw_name, 0, true);
-}
-
static unsigned sdma_v5_2_ring_init_cond_exec(struct amdgpu_ring *ring)
{
unsigned ret;
@@ -809,12 +756,6 @@ static int sdma_v5_2_start(struct amdgpu_device *adev)
msleep(1000);
}
- /* TODO: check whether can submit a doorbell request to raise
- * a doorbell fence to exit gfxoff.
- */
- if (adev->in_s0ix)
- amdgpu_gfx_off_ctrl(adev, false);
-
sdma_v5_2_soft_reset(adev);
/* unhalt the MEs */
sdma_v5_2_enable(adev, true);
@@ -823,8 +764,6 @@ static int sdma_v5_2_start(struct amdgpu_device *adev)
/* start the gfx rings and rlc compute queues */
r = sdma_v5_2_gfx_resume(adev);
- if (adev->in_s0ix)
- amdgpu_gfx_off_ctrl(adev, true);
if (r)
return r;
r = sdma_v5_2_rlc_resume(adev);
@@ -1296,7 +1235,7 @@ static int sdma_v5_2_sw_init(void *handle)
return r;
}
- r = sdma_v5_2_init_microcode(adev);
+ r = amdgpu_sdma_init_microcode(adev, 0, true);
if (r) {
DRM_ERROR("Failed to load sdma firmware!\n");
return r;
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c
index 049c26a45d85..40e6b22daa22 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c
@@ -78,29 +78,6 @@ static u32 sdma_v6_0_get_reg_offset(struct amdgpu_device *adev, u32 instance, u3
return base + internal_offset;
}
-/**
- * sdma_v6_0_init_microcode - load ucode images from disk
- *
- * @adev: amdgpu_device pointer
- *
- * Use the firmware interface to load the ucode images into
- * the driver (not loaded into hw).
- * Returns 0 on success, error on failure.
- */
-static int sdma_v6_0_init_microcode(struct amdgpu_device *adev)
-{
- char fw_name[30];
- char ucode_prefix[30];
-
- DRM_DEBUG("\n");
-
- amdgpu_ucode_ip_version_decode(adev, SDMA0_HWIP, ucode_prefix, sizeof(ucode_prefix));
-
- snprintf(fw_name, sizeof(fw_name), "amdgpu/%s.bin", ucode_prefix);
-
- return amdgpu_sdma_init_microcode(adev, fw_name, 0, true);
-}
-
static unsigned sdma_v6_0_ring_init_cond_exec(struct amdgpu_ring *ring)
{
unsigned ret;
@@ -296,8 +273,6 @@ static void sdma_v6_0_ring_emit_ib(struct amdgpu_ring *ring,
* sdma_v6_0_ring_emit_mem_sync - flush the IB by graphics cache rinse
*
* @ring: amdgpu ring pointer
- * @job: job to retrieve vmid from
- * @ib: IB object to schedule
*
* flush the IB by graphics cache rinse.
*/
@@ -349,7 +324,9 @@ static void sdma_v6_0_ring_emit_hdp_flush(struct amdgpu_ring *ring)
* sdma_v6_0_ring_emit_fence - emit a fence on the DMA ring
*
* @ring: amdgpu ring pointer
- * @fence: amdgpu fence object
+ * @addr: address
+ * @seq: fence seq number
+ * @flags: fence flags
*
* Add a DMA fence packet to the ring to write
* the fence seq number and DMA trap packet to generate
@@ -1083,10 +1060,9 @@ static void sdma_v6_0_vm_copy_pte(struct amdgpu_ib *ib,
*
* @ib: indirect buffer to fill with commands
* @pe: addr of the page entry
- * @addr: dst addr to write into pe
+ * @value: dst addr to write into pe
* @count: number of page entries to update
* @incr: increase next addr by incr bytes
- * @flags: access flags
*
* Update PTEs by writing them manually using sDMA.
*/
@@ -1190,7 +1166,6 @@ static void sdma_v6_0_ring_emit_pipeline_sync(struct amdgpu_ring *ring)
* sdma_v6_0_ring_emit_vm_flush - vm flush using sDMA
*
* @ring: amdgpu_ring pointer
- * @vm: amdgpu_vm pointer
*
* Update the page table base and flush the VM TLB
* using sDMA.
@@ -1234,6 +1209,24 @@ static void sdma_v6_0_ring_emit_reg_write_reg_wait(struct amdgpu_ring *ring,
amdgpu_ring_emit_reg_wait(ring, reg1, mask, mask);
}
+static struct amdgpu_sdma_ras sdma_v6_0_3_ras = {
+ .ras_block = {
+ .ras_late_init = amdgpu_ras_block_late_init,
+ },
+};
+
+static void sdma_v6_0_set_ras_funcs(struct amdgpu_device *adev)
+{
+ switch (adev->ip_versions[SDMA0_HWIP][0]) {
+ case IP_VERSION(6, 0, 3):
+ adev->sdma.ras = &sdma_v6_0_3_ras;
+ break;
+ default:
+ break;
+ }
+
+}
+
static int sdma_v6_0_early_init(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
@@ -1243,6 +1236,7 @@ static int sdma_v6_0_early_init(void *handle)
sdma_v6_0_set_vm_pte_funcs(adev);
sdma_v6_0_set_irq_funcs(adev);
sdma_v6_0_set_mqd_funcs(adev);
+ sdma_v6_0_set_ras_funcs(adev);
return 0;
}
@@ -1260,7 +1254,7 @@ static int sdma_v6_0_sw_init(void *handle)
if (r)
return r;
- r = sdma_v6_0_init_microcode(adev);
+ r = amdgpu_sdma_init_microcode(adev, 0, true);
if (r) {
DRM_ERROR("Failed to load sdma firmware!\n");
return r;
@@ -1287,6 +1281,11 @@ static int sdma_v6_0_sw_init(void *handle)
return r;
}
+ if (amdgpu_sdma_ras_sw_init(adev)) {
+ dev_err(adev->dev, "Failed to initialize sdma ras block!\n");
+ return -EINVAL;
+ }
+
return r;
}
@@ -1426,10 +1425,12 @@ static int sdma_v6_0_set_trap_irq_state(struct amdgpu_device *adev,
u32 reg_offset = sdma_v6_0_get_reg_offset(adev, type, regSDMA0_CNTL);
- sdma_cntl = RREG32(reg_offset);
- sdma_cntl = REG_SET_FIELD(sdma_cntl, SDMA0_CNTL, TRAP_ENABLE,
- state == AMDGPU_IRQ_STATE_ENABLE ? 1 : 0);
- WREG32(reg_offset, sdma_cntl);
+ if (!amdgpu_sriov_vf(adev)) {
+ sdma_cntl = RREG32(reg_offset);
+ sdma_cntl = REG_SET_FIELD(sdma_cntl, SDMA0_CNTL, TRAP_ENABLE,
+ state == AMDGPU_IRQ_STATE_ENABLE ? 1 : 0);
+ WREG32(reg_offset, sdma_cntl);
+ }
return 0;
}
@@ -1588,10 +1589,11 @@ static void sdma_v6_0_set_irq_funcs(struct amdgpu_device *adev)
/**
* sdma_v6_0_emit_copy_buffer - copy buffer using the sDMA engine
*
- * @ring: amdgpu_ring structure holding ring information
+ * @ib: indirect buffer to fill with commands
* @src_offset: src GPU address
* @dst_offset: dst GPU address
* @byte_count: number of bytes to xfer
+ * @tmz: if a secure copy should be used
*
* Copy GPU buffers using the DMA engine.
* Used by the amdgpu ttm implementation to move pages if
@@ -1617,7 +1619,7 @@ static void sdma_v6_0_emit_copy_buffer(struct amdgpu_ib *ib,
/**
* sdma_v6_0_emit_fill_buffer - fill buffer using the sDMA engine
*
- * @ring: amdgpu_ring structure holding ring information
+ * @ib: indirect buffer to fill
* @src_data: value to write to buffer
* @dst_offset: dst GPU address
* @byte_count: number of bytes to xfer
diff --git a/drivers/gpu/drm/amd/amdgpu/smu_v13_0_10.c b/drivers/gpu/drm/amd/amdgpu/smu_v13_0_10.c
new file mode 100644
index 000000000000..ae29620b1ea4
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/smu_v13_0_10.c
@@ -0,0 +1,303 @@
+/*
+ * Copyright 2023 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ */
+
+#include "smu_v13_0_10.h"
+#include "amdgpu_reset.h"
+#include "amdgpu_dpm.h"
+#include "amdgpu_job.h"
+#include "amdgpu_ring.h"
+#include "amdgpu_ras.h"
+#include "amdgpu_psp.h"
+
+static bool smu_v13_0_10_is_mode2_default(struct amdgpu_reset_control *reset_ctl)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)reset_ctl->handle;
+ if (adev->pm.fw_version >= 0x00502005 && !amdgpu_sriov_vf(adev))
+ return true;
+
+ return false;
+}
+
+static struct amdgpu_reset_handler *
+smu_v13_0_10_get_reset_handler(struct amdgpu_reset_control *reset_ctl,
+ struct amdgpu_reset_context *reset_context)
+{
+ struct amdgpu_reset_handler *handler;
+ struct amdgpu_device *adev = (struct amdgpu_device *)reset_ctl->handle;
+
+ if (reset_context->method != AMD_RESET_METHOD_NONE) {
+ list_for_each_entry(handler, &reset_ctl->reset_handlers,
+ handler_list) {
+ if (handler->reset_method == reset_context->method)
+ return handler;
+ }
+ }
+
+ if (smu_v13_0_10_is_mode2_default(reset_ctl) &&
+ amdgpu_asic_reset_method(adev) == AMD_RESET_METHOD_MODE2) {
+ list_for_each_entry (handler, &reset_ctl->reset_handlers,
+ handler_list) {
+ if (handler->reset_method == AMD_RESET_METHOD_MODE2)
+ return handler;
+ }
+ }
+
+ return NULL;
+}
+
+static int smu_v13_0_10_mode2_suspend_ip(struct amdgpu_device *adev)
+{
+ int r, i;
+
+ amdgpu_device_set_pg_state(adev, AMD_PG_STATE_UNGATE);
+ amdgpu_device_set_cg_state(adev, AMD_CG_STATE_UNGATE);
+
+ for (i = adev->num_ip_blocks - 1; i >= 0; i--) {
+ if (!(adev->ip_blocks[i].version->type ==
+ AMD_IP_BLOCK_TYPE_GFX ||
+ adev->ip_blocks[i].version->type ==
+ AMD_IP_BLOCK_TYPE_SDMA ||
+ adev->ip_blocks[i].version->type ==
+ AMD_IP_BLOCK_TYPE_MES))
+ continue;
+
+ r = adev->ip_blocks[i].version->funcs->suspend(adev);
+
+ if (r) {
+ dev_err(adev->dev,
+ "suspend of IP block <%s> failed %d\n",
+ adev->ip_blocks[i].version->funcs->name, r);
+ return r;
+ }
+ adev->ip_blocks[i].status.hw = false;
+ }
+
+ return r;
+}
+
+static int
+smu_v13_0_10_mode2_prepare_hwcontext(struct amdgpu_reset_control *reset_ctl,
+ struct amdgpu_reset_context *reset_context)
+{
+ int r = 0;
+ struct amdgpu_device *adev = (struct amdgpu_device *)reset_ctl->handle;
+
+ if (!amdgpu_sriov_vf(adev))
+ r = smu_v13_0_10_mode2_suspend_ip(adev);
+
+ return r;
+}
+
+static int smu_v13_0_10_mode2_reset(struct amdgpu_device *adev)
+{
+ return amdgpu_dpm_mode2_reset(adev);
+}
+
+static void smu_v13_0_10_async_reset(struct work_struct *work)
+{
+ struct amdgpu_reset_handler *handler;
+ struct amdgpu_reset_control *reset_ctl =
+ container_of(work, struct amdgpu_reset_control, reset_work);
+ struct amdgpu_device *adev = (struct amdgpu_device *)reset_ctl->handle;
+
+ list_for_each_entry(handler, &reset_ctl->reset_handlers,
+ handler_list) {
+ if (handler->reset_method == reset_ctl->active_reset) {
+ dev_dbg(adev->dev, "Resetting device\n");
+ handler->do_reset(adev);
+ break;
+ }
+ }
+}
+static int
+smu_v13_0_10_mode2_perform_reset(struct amdgpu_reset_control *reset_ctl,
+ struct amdgpu_reset_context *reset_context)
+{
+ struct amdgpu_device *adev = (struct amdgpu_device *)reset_ctl->handle;
+ int r;
+
+ r = smu_v13_0_10_mode2_reset(adev);
+ if (r) {
+ dev_err(adev->dev,
+ "ASIC reset failed with error, %d ", r);
+ }
+ return r;
+}
+
+static int smu_v13_0_10_mode2_restore_ip(struct amdgpu_device *adev)
+{
+ int i, r;
+ struct psp_context *psp = &adev->psp;
+ struct amdgpu_firmware_info *ucode;
+ struct amdgpu_firmware_info *ucode_list[2];
+ int ucode_count = 0;
+
+ for (i = 0; i < adev->firmware.max_ucodes; i++) {
+ ucode = &adev->firmware.ucode[i];
+
+ switch (ucode->ucode_id) {
+ case AMDGPU_UCODE_ID_IMU_I:
+ case AMDGPU_UCODE_ID_IMU_D:
+ ucode_list[ucode_count++] = ucode;
+ break;
+ default:
+ break;
+ }
+ }
+
+ r = psp_load_fw_list(psp, ucode_list, ucode_count);
+ if (r) {
+ dev_err(adev->dev, "IMU ucode load failed after mode2 reset\n");
+ return r;
+ }
+
+ r = psp_rlc_autoload_start(psp);
+ if (r) {
+ DRM_ERROR("Failed to start rlc autoload after mode2 reset\n");
+ return r;
+ }
+
+ amdgpu_dpm_enable_gfx_features(adev);
+
+ for (i = 0; i < adev->num_ip_blocks; i++) {
+ if (!(adev->ip_blocks[i].version->type ==
+ AMD_IP_BLOCK_TYPE_GFX ||
+ adev->ip_blocks[i].version->type ==
+ AMD_IP_BLOCK_TYPE_MES ||
+ adev->ip_blocks[i].version->type ==
+ AMD_IP_BLOCK_TYPE_SDMA))
+ continue;
+ r = adev->ip_blocks[i].version->funcs->resume(adev);
+ if (r) {
+ dev_err(adev->dev,
+ "resume of IP block <%s> failed %d\n",
+ adev->ip_blocks[i].version->funcs->name, r);
+ return r;
+ }
+
+ adev->ip_blocks[i].status.hw = true;
+ }
+
+ for (i = 0; i < adev->num_ip_blocks; i++) {
+ if (!(adev->ip_blocks[i].version->type ==
+ AMD_IP_BLOCK_TYPE_GFX ||
+ adev->ip_blocks[i].version->type ==
+ AMD_IP_BLOCK_TYPE_MES ||
+ adev->ip_blocks[i].version->type ==
+ AMD_IP_BLOCK_TYPE_SDMA))
+ continue;
+
+ if (adev->ip_blocks[i].version->funcs->late_init) {
+ r = adev->ip_blocks[i].version->funcs->late_init(
+ (void *)adev);
+ if (r) {
+ dev_err(adev->dev,
+ "late_init of IP block <%s> failed %d after reset\n",
+ adev->ip_blocks[i].version->funcs->name,
+ r);
+ return r;
+ }
+ }
+ adev->ip_blocks[i].status.late_initialized = true;
+ }
+
+ amdgpu_device_set_cg_state(adev, AMD_CG_STATE_GATE);
+ amdgpu_device_set_pg_state(adev, AMD_PG_STATE_GATE);
+
+ return r;
+}
+
+static int
+smu_v13_0_10_mode2_restore_hwcontext(struct amdgpu_reset_control *reset_ctl,
+ struct amdgpu_reset_context *reset_context)
+{
+ int r;
+ struct amdgpu_device *tmp_adev = (struct amdgpu_device *)reset_ctl->handle;
+
+ dev_info(tmp_adev->dev,
+ "GPU reset succeeded, trying to resume\n");
+ r = smu_v13_0_10_mode2_restore_ip(tmp_adev);
+ if (r)
+ goto end;
+
+ amdgpu_register_gpu_instance(tmp_adev);
+
+ /* Resume RAS */
+ amdgpu_ras_resume(tmp_adev);
+
+ amdgpu_irq_gpu_reset_resume_helper(tmp_adev);
+
+ r = amdgpu_ib_ring_tests(tmp_adev);
+ if (r) {
+ dev_err(tmp_adev->dev,
+ "ib ring test failed (%d).\n", r);
+ r = -EAGAIN;
+ goto end;
+ }
+
+end:
+ if (r)
+ return -EAGAIN;
+ else
+ return r;
+}
+
+static struct amdgpu_reset_handler smu_v13_0_10_mode2_handler = {
+ .reset_method = AMD_RESET_METHOD_MODE2,
+ .prepare_env = NULL,
+ .prepare_hwcontext = smu_v13_0_10_mode2_prepare_hwcontext,
+ .perform_reset = smu_v13_0_10_mode2_perform_reset,
+ .restore_hwcontext = smu_v13_0_10_mode2_restore_hwcontext,
+ .restore_env = NULL,
+ .do_reset = smu_v13_0_10_mode2_reset,
+};
+
+int smu_v13_0_10_reset_init(struct amdgpu_device *adev)
+{
+ struct amdgpu_reset_control *reset_ctl;
+
+ reset_ctl = kzalloc(sizeof(*reset_ctl), GFP_KERNEL);
+ if (!reset_ctl)
+ return -ENOMEM;
+
+ reset_ctl->handle = adev;
+ reset_ctl->async_reset = smu_v13_0_10_async_reset;
+ reset_ctl->active_reset = AMD_RESET_METHOD_NONE;
+ reset_ctl->get_reset_handler = smu_v13_0_10_get_reset_handler;
+
+ INIT_LIST_HEAD(&reset_ctl->reset_handlers);
+ INIT_WORK(&reset_ctl->reset_work, reset_ctl->async_reset);
+ /* Only mode2 is handled through reset control now */
+ amdgpu_reset_add_handler(reset_ctl, &smu_v13_0_10_mode2_handler);
+
+ adev->reset_cntl = reset_ctl;
+
+ return 0;
+}
+
+int smu_v13_0_10_reset_fini(struct amdgpu_device *adev)
+{
+ kfree(adev->reset_cntl);
+ adev->reset_cntl = NULL;
+ return 0;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/smu_v13_0_10.h b/drivers/gpu/drm/amd/amdgpu/smu_v13_0_10.h
new file mode 100644
index 000000000000..e0cb72a0eec6
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/smu_v13_0_10.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2023 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ */
+
+#ifndef __SMU_V13_0_10_H__
+#define __SMU_V13_0_10_H__
+
+#include "amdgpu.h"
+
+int smu_v13_0_10_reset_init(struct amdgpu_device *adev);
+int smu_v13_0_10_reset_fini(struct amdgpu_device *adev);
+
+#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/soc21.c b/drivers/gpu/drm/amd/amdgpu/soc21.c
index 7050238c4c48..620f7409825d 100644
--- a/drivers/gpu/drm/amd/amdgpu/soc21.c
+++ b/drivers/gpu/drm/amd/amdgpu/soc21.c
@@ -48,19 +48,32 @@
static const struct amd_ip_funcs soc21_common_ip_funcs;
/* SOC21 */
-static const struct amdgpu_video_codec_info vcn_4_0_0_video_codecs_encode_array[] =
+static const struct amdgpu_video_codec_info vcn_4_0_0_video_codecs_encode_array_vcn0[] =
+{
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 2304, 0)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 4096, 2304, 0)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_AV1, 8192, 4352, 0)},
+};
+
+static const struct amdgpu_video_codec_info vcn_4_0_0_video_codecs_encode_array_vcn1[] =
{
{codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 2304, 0)},
{codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 4096, 2304, 0)},
};
-static const struct amdgpu_video_codecs vcn_4_0_0_video_codecs_encode =
+static const struct amdgpu_video_codecs vcn_4_0_0_video_codecs_encode_vcn0 =
{
- .codec_count = ARRAY_SIZE(vcn_4_0_0_video_codecs_encode_array),
- .codec_array = vcn_4_0_0_video_codecs_encode_array,
+ .codec_count = ARRAY_SIZE(vcn_4_0_0_video_codecs_encode_array_vcn0),
+ .codec_array = vcn_4_0_0_video_codecs_encode_array_vcn0,
};
-static const struct amdgpu_video_codec_info vcn_4_0_0_video_codecs_decode_array[] =
+static const struct amdgpu_video_codecs vcn_4_0_0_video_codecs_encode_vcn1 =
+{
+ .codec_count = ARRAY_SIZE(vcn_4_0_0_video_codecs_encode_array_vcn1),
+ .codec_array = vcn_4_0_0_video_codecs_encode_array_vcn1,
+};
+
+static const struct amdgpu_video_codec_info vcn_4_0_0_video_codecs_decode_array_vcn0[] =
{
{codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4096, 52)},
{codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 8192, 4352, 186)},
@@ -69,23 +82,46 @@ static const struct amdgpu_video_codec_info vcn_4_0_0_video_codecs_decode_array[
{codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_AV1, 8192, 4352, 0)},
};
-static const struct amdgpu_video_codecs vcn_4_0_0_video_codecs_decode =
+static const struct amdgpu_video_codec_info vcn_4_0_0_video_codecs_decode_array_vcn1[] =
{
- .codec_count = ARRAY_SIZE(vcn_4_0_0_video_codecs_decode_array),
- .codec_array = vcn_4_0_0_video_codecs_decode_array,
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC, 4096, 4096, 52)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC, 8192, 4352, 186)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG, 4096, 4096, 0)},
+ {codec_info_build(AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VP9, 8192, 4352, 0)},
+};
+
+static const struct amdgpu_video_codecs vcn_4_0_0_video_codecs_decode_vcn0 =
+{
+ .codec_count = ARRAY_SIZE(vcn_4_0_0_video_codecs_decode_array_vcn0),
+ .codec_array = vcn_4_0_0_video_codecs_decode_array_vcn0,
+};
+
+static const struct amdgpu_video_codecs vcn_4_0_0_video_codecs_decode_vcn1 =
+{
+ .codec_count = ARRAY_SIZE(vcn_4_0_0_video_codecs_decode_array_vcn1),
+ .codec_array = vcn_4_0_0_video_codecs_decode_array_vcn1,
};
static int soc21_query_video_codecs(struct amdgpu_device *adev, bool encode,
const struct amdgpu_video_codecs **codecs)
{
- switch (adev->ip_versions[UVD_HWIP][0]) {
+ if (adev->vcn.num_vcn_inst == hweight8(adev->vcn.harvest_config))
+ return -EINVAL;
+ switch (adev->ip_versions[UVD_HWIP][0]) {
case IP_VERSION(4, 0, 0):
case IP_VERSION(4, 0, 2):
- if (encode)
- *codecs = &vcn_4_0_0_video_codecs_encode;
- else
- *codecs = &vcn_4_0_0_video_codecs_decode;
+ if (adev->vcn.harvest_config & AMDGPU_VCN_HARVEST_VCN0) {
+ if (encode)
+ *codecs = &vcn_4_0_0_video_codecs_encode_vcn1;
+ else
+ *codecs = &vcn_4_0_0_video_codecs_decode_vcn1;
+ } else {
+ if (encode)
+ *codecs = &vcn_4_0_0_video_codecs_encode_vcn0;
+ else
+ *codecs = &vcn_4_0_0_video_codecs_decode_vcn0;
+ }
return 0;
default:
return -EINVAL;
diff --git a/drivers/gpu/drm/amd/amdgpu/ta_secureDisplay_if.h b/drivers/gpu/drm/amd/amdgpu/ta_secureDisplay_if.h
index cf8ff064dc72..00d8bdb8254f 100644
--- a/drivers/gpu/drm/amd/amdgpu/ta_secureDisplay_if.h
+++ b/drivers/gpu/drm/amd/amdgpu/ta_secureDisplay_if.h
@@ -55,10 +55,10 @@ enum ta_securedisplay_status {
TA_SECUREDISPLAY_STATUS__MAX = 0x7FFFFFFF,/* Maximum Value for status*/
};
-/** @enum ta_securedisplay_max_phy
+/** @enum ta_securedisplay_phy_ID
* Physical ID number to use for reading corresponding DIO Scratch register for ROI
*/
-enum ta_securedisplay_max_phy {
+enum ta_securedisplay_phy_ID {
TA_SECUREDISPLAY_PHY0 = 0,
TA_SECUREDISPLAY_PHY1 = 1,
TA_SECUREDISPLAY_PHY2 = 2,
@@ -139,16 +139,16 @@ union ta_securedisplay_cmd_output {
uint32_t reserved[4];
};
-/** @struct securedisplay_cmd
- * Secure Display Command which is shared buffer memory
- */
-struct securedisplay_cmd {
- uint32_t cmd_id; /* +0 Bytes Command ID */
- enum ta_securedisplay_status status; /* +4 Bytes Status of Secure Display TA */
- uint32_t reserved[2]; /* +8 Bytes Reserved */
- union ta_securedisplay_cmd_input securedisplay_in_message; /* +16 Bytes Input Buffer */
- union ta_securedisplay_cmd_output securedisplay_out_message;/* +32 Bytes Output Buffer */
- /**@note Total 48 Bytes */
+/** @struct ta_securedisplay_cmd
+* Secure display command which is shared buffer memory
+*/
+struct ta_securedisplay_cmd {
+ uint32_t cmd_id; /**< +0 Bytes Command ID */
+ enum ta_securedisplay_status status; /**< +4 Bytes Status code returned by the secure display TA */
+ uint32_t reserved[2]; /**< +8 Bytes Reserved */
+ union ta_securedisplay_cmd_input securedisplay_in_message; /**< +16 Bytes Command input buffer */
+ union ta_securedisplay_cmd_output securedisplay_out_message; /**< +32 Bytes Command output buffer */
+ /**@note Total 48 Bytes */
};
#endif //_TA_SECUREDISPLAY_IF_H
diff --git a/drivers/gpu/drm/amd/amdgpu/umc_v6_7.c b/drivers/gpu/drm/amd/amdgpu/umc_v6_7.c
index 72fd963f178b..e08e25a3a1a9 100644
--- a/drivers/gpu/drm/amd/amdgpu/umc_v6_7.c
+++ b/drivers/gpu/drm/amd/amdgpu/umc_v6_7.c
@@ -57,13 +57,6 @@ static inline uint32_t get_umc_v6_7_reg_offset(struct amdgpu_device *adev,
return adev->umc.channel_offs * ch_inst + UMC_V6_7_INST_DIST * umc_inst;
}
-static inline uint32_t get_umc_v6_7_channel_index(struct amdgpu_device *adev,
- uint32_t umc_inst,
- uint32_t ch_inst)
-{
- return adev->umc.channel_idx_tbl[umc_inst * adev->umc.channel_inst_num + ch_inst];
-}
-
static void umc_v6_7_query_error_status_helper(struct amdgpu_device *adev,
uint64_t mc_umc_status, uint32_t umc_reg_offset)
{
diff --git a/drivers/gpu/drm/amd/amdgpu/umc_v8_10.c b/drivers/gpu/drm/amd/amdgpu/umc_v8_10.c
index b7da4528cf0a..fb55e8cb9967 100644
--- a/drivers/gpu/drm/amd/amdgpu/umc_v8_10.c
+++ b/drivers/gpu/drm/amd/amdgpu/umc_v8_10.c
@@ -209,6 +209,45 @@ static int umc_v8_10_swizzle_mode_na_to_pa(struct amdgpu_device *adev,
return 0;
}
+static void umc_v8_10_convert_error_address(struct amdgpu_device *adev,
+ struct ras_err_data *err_data, uint64_t err_addr,
+ uint32_t ch_inst, uint32_t umc_inst,
+ uint32_t node_inst, uint64_t mc_umc_status)
+{
+ uint64_t na_err_addr_base;
+ uint64_t na_err_addr, retired_page_addr;
+ uint32_t channel_index, addr_lsb, col = 0;
+ int ret = 0;
+
+ channel_index =
+ adev->umc.channel_idx_tbl[node_inst * adev->umc.umc_inst_num *
+ adev->umc.channel_inst_num +
+ umc_inst * adev->umc.channel_inst_num +
+ ch_inst];
+
+ /* the lowest lsb bits should be ignored */
+ addr_lsb = REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, AddrLsb);
+ err_addr &= ~((0x1ULL << addr_lsb) - 1);
+ na_err_addr_base = err_addr & ~(0x3ULL << UMC_V8_10_NA_C5_BIT);
+
+ /* loop for all possibilities of [C6 C5] in normal address. */
+ for (col = 0; col < UMC_V8_10_NA_COL_2BITS_POWER_OF_2_NUM; col++) {
+ na_err_addr = na_err_addr_base | (col << UMC_V8_10_NA_C5_BIT);
+
+ /* Mapping normal error address to retired soc physical address. */
+ ret = umc_v8_10_swizzle_mode_na_to_pa(adev, channel_index,
+ na_err_addr, &retired_page_addr);
+ if (ret) {
+ dev_err(adev->dev, "Failed to map pa from umc na.\n");
+ break;
+ }
+ dev_info(adev->dev, "Error Address(PA): 0x%llx\n",
+ retired_page_addr);
+ amdgpu_umc_fill_error_record(err_data, na_err_addr,
+ retired_page_addr, channel_index, umc_inst);
+ }
+}
+
static void umc_v8_10_query_error_address(struct amdgpu_device *adev,
struct ras_err_data *err_data,
uint32_t umc_reg_offset,
@@ -218,10 +257,7 @@ static void umc_v8_10_query_error_address(struct amdgpu_device *adev,
{
uint64_t mc_umc_status_addr;
uint64_t mc_umc_status, err_addr;
- uint64_t mc_umc_addrt0, na_err_addr_base;
- uint64_t na_err_addr, retired_page_addr;
- uint32_t channel_index, addr_lsb, col = 0;
- int ret = 0;
+ uint64_t mc_umc_addrt0;
mc_umc_status_addr =
SOC15_REG_OFFSET(UMC, 0, regMCA_UMC_UMC0_MCUMC_STATUST0);
@@ -236,12 +272,6 @@ static void umc_v8_10_query_error_address(struct amdgpu_device *adev,
return;
}
- channel_index =
- adev->umc.channel_idx_tbl[node_inst * adev->umc.umc_inst_num *
- adev->umc.channel_inst_num +
- umc_inst * adev->umc.channel_inst_num +
- ch_inst];
-
/* calculate error address if ue error is detected */
if (REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, Val) == 1 &&
REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, AddrV) == 1 &&
@@ -251,27 +281,8 @@ static void umc_v8_10_query_error_address(struct amdgpu_device *adev,
err_addr = RREG64_PCIE((mc_umc_addrt0 + umc_reg_offset) * 4);
err_addr = REG_GET_FIELD(err_addr, MCA_UMC_UMC0_MCUMC_ADDRT0, ErrorAddr);
- /* the lowest lsb bits should be ignored */
- addr_lsb = REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, AddrLsb);
- err_addr &= ~((0x1ULL << addr_lsb) - 1);
- na_err_addr_base = err_addr & ~(0x3ULL << UMC_V8_10_NA_C5_BIT);
-
- /* loop for all possibilities of [C6 C5] in normal address. */
- for (col = 0; col < UMC_V8_10_NA_COL_2BITS_POWER_OF_2_NUM; col++) {
- na_err_addr = na_err_addr_base | (col << UMC_V8_10_NA_C5_BIT);
-
- /* Mapping normal error address to retired soc physical address. */
- ret = umc_v8_10_swizzle_mode_na_to_pa(adev, channel_index,
- na_err_addr, &retired_page_addr);
- if (ret) {
- dev_err(adev->dev, "Failed to map pa from umc na.\n");
- break;
- }
- dev_info(adev->dev, "Error Address(PA): 0x%llx\n",
- retired_page_addr);
- amdgpu_umc_fill_error_record(err_data, na_err_addr,
- retired_page_addr, channel_index, umc_inst);
- }
+ umc_v8_10_convert_error_address(adev, err_data, err_addr,
+ ch_inst, umc_inst, node_inst, mc_umc_status);
}
/* clear umc status */
@@ -340,29 +351,140 @@ static void umc_v8_10_err_cnt_init(struct amdgpu_device *adev)
}
}
-static uint32_t umc_v8_10_query_ras_poison_mode_per_channel(
- struct amdgpu_device *adev,
- uint32_t umc_reg_offset)
+static bool umc_v8_10_query_ras_poison_mode(struct amdgpu_device *adev)
{
- uint32_t ecc_ctrl_addr, ecc_ctrl;
+ /*
+ * Force return true, because UMCCH0_0_GeccCtrl
+ * is not accessible from host side
+ */
+ return true;
+}
- ecc_ctrl_addr =
- SOC15_REG_OFFSET(UMC, 0, regUMCCH0_0_GeccCtrl);
- ecc_ctrl = RREG32_PCIE((ecc_ctrl_addr +
- umc_reg_offset) * 4);
+static void umc_v8_10_ecc_info_query_correctable_error_count(struct amdgpu_device *adev,
+ uint32_t node_inst, uint32_t umc_inst, uint32_t ch_inst,
+ unsigned long *error_count)
+{
+ uint64_t mc_umc_status;
+ uint32_t eccinfo_table_idx;
+ struct amdgpu_ras *ras = amdgpu_ras_get_context(adev);
+
+ eccinfo_table_idx = node_inst * adev->umc.umc_inst_num *
+ adev->umc.channel_inst_num +
+ umc_inst * adev->umc.channel_inst_num +
+ ch_inst;
- return REG_GET_FIELD(ecc_ctrl, UMCCH0_0_GeccCtrl, UCFatalEn);
+ /* check the MCUMC_STATUS */
+ mc_umc_status = ras->umc_ecc.ecc[eccinfo_table_idx].mca_umc_status;
+ if (REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, Val) == 1 &&
+ REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, CECC) == 1) {
+ *error_count += 1;
+ }
}
-static bool umc_v8_10_query_ras_poison_mode(struct amdgpu_device *adev)
+static void umc_v8_10_ecc_info_query_uncorrectable_error_count(struct amdgpu_device *adev,
+ uint32_t node_inst, uint32_t umc_inst, uint32_t ch_inst,
+ unsigned long *error_count)
{
- uint32_t umc_reg_offset = 0;
+ uint64_t mc_umc_status;
+ uint32_t eccinfo_table_idx;
+ struct amdgpu_ras *ras = amdgpu_ras_get_context(adev);
- /* Enabling fatal error in umc node0 instance0 channel0 will be
- * considered as fatal error mode
+ eccinfo_table_idx = node_inst * adev->umc.umc_inst_num *
+ adev->umc.channel_inst_num +
+ umc_inst * adev->umc.channel_inst_num +
+ ch_inst;
+
+ /* check the MCUMC_STATUS */
+ mc_umc_status = ras->umc_ecc.ecc[eccinfo_table_idx].mca_umc_status;
+ if ((REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, Val) == 1) &&
+ (REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, Deferred) == 1 ||
+ REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, UECC) == 1 ||
+ REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, PCC) == 1 ||
+ REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, UC) == 1 ||
+ REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, TCC) == 1)) {
+ *error_count += 1;
+ }
+}
+
+static void umc_v8_10_ecc_info_query_ras_error_count(struct amdgpu_device *adev,
+ void *ras_error_status)
+{
+ struct ras_err_data *err_data = (struct ras_err_data *)ras_error_status;
+
+ uint32_t node_inst = 0;
+ uint32_t umc_inst = 0;
+ uint32_t ch_inst = 0;
+
+ /* TODO: driver needs to toggle DF Cstate to ensure
+ * safe access of UMC registers. Will add the protection
+ */
+ LOOP_UMC_EACH_NODE_INST_AND_CH(node_inst, umc_inst, ch_inst) {
+ umc_v8_10_ecc_info_query_correctable_error_count(adev,
+ node_inst, umc_inst, ch_inst,
+ &(err_data->ce_count));
+ umc_v8_10_ecc_info_query_uncorrectable_error_count(adev,
+ node_inst, umc_inst, ch_inst,
+ &(err_data->ue_count));
+ }
+}
+
+static void umc_v8_10_ecc_info_query_error_address(struct amdgpu_device *adev,
+ struct ras_err_data *err_data,
+ uint32_t ch_inst,
+ uint32_t umc_inst,
+ uint32_t node_inst)
+{
+ uint32_t eccinfo_table_idx;
+ uint64_t mc_umc_status, err_addr;
+
+ struct amdgpu_ras *ras = amdgpu_ras_get_context(adev);
+
+ eccinfo_table_idx = node_inst * adev->umc.umc_inst_num *
+ adev->umc.channel_inst_num +
+ umc_inst * adev->umc.channel_inst_num +
+ ch_inst;
+
+ mc_umc_status = ras->umc_ecc.ecc[eccinfo_table_idx].mca_umc_status;
+
+ if (mc_umc_status == 0)
+ return;
+
+ if (!err_data->err_addr)
+ return;
+
+ /* calculate error address if ue error is detected */
+ if (REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, Val) == 1 &&
+ REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, AddrV) == 1 &&
+ (REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, UECC) == 1)) {
+
+ err_addr = ras->umc_ecc.ecc[eccinfo_table_idx].mca_umc_addr;
+ err_addr = REG_GET_FIELD(err_addr, MCA_UMC_UMC0_MCUMC_ADDRT0, ErrorAddr);
+
+ umc_v8_10_convert_error_address(adev, err_data, err_addr,
+ ch_inst, umc_inst, node_inst, mc_umc_status);
+ }
+}
+
+static void umc_v8_10_ecc_info_query_ras_error_address(struct amdgpu_device *adev,
+ void *ras_error_status)
+{
+ struct ras_err_data *err_data = (struct ras_err_data *)ras_error_status;
+
+ uint32_t node_inst = 0;
+ uint32_t umc_inst = 0;
+ uint32_t ch_inst = 0;
+
+ /* TODO: driver needs to toggle DF Cstate to ensure
+ * safe access of UMC resgisters. Will add the protection
+ * when firmware interface is ready
*/
- umc_reg_offset = get_umc_v8_10_reg_offset(adev, 0, 0, 0);
- return !umc_v8_10_query_ras_poison_mode_per_channel(adev, umc_reg_offset);
+ LOOP_UMC_EACH_NODE_INST_AND_CH(node_inst, umc_inst, ch_inst) {
+ umc_v8_10_ecc_info_query_error_address(adev,
+ err_data,
+ ch_inst,
+ umc_inst,
+ node_inst);
+ }
}
const struct amdgpu_ras_block_hw_ops umc_v8_10_ras_hw_ops = {
@@ -376,4 +498,6 @@ struct amdgpu_umc_ras umc_v8_10_ras = {
},
.err_cnt_init = umc_v8_10_err_cnt_init,
.query_ras_poison_mode = umc_v8_10_query_ras_poison_mode,
+ .ecc_info_query_ras_error_count = umc_v8_10_ecc_info_query_ras_error_count,
+ .ecc_info_query_ras_error_address = umc_v8_10_ecc_info_query_ras_error_address,
};
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c
index f0fbcda76f5e..c305b2cb8490 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c
@@ -57,11 +57,12 @@ static void vcn_v1_0_idle_work_handler(struct work_struct *work);
static void vcn_v1_0_ring_begin_use(struct amdgpu_ring *ring);
/**
- * vcn_v1_0_early_init - set function pointers
+ * vcn_v1_0_early_init - set function pointers and load microcode
*
* @handle: amdgpu_device pointer
*
* Set ring and irq function pointers
+ * Load microcode from filesystem
*/
static int vcn_v1_0_early_init(void *handle)
{
@@ -75,7 +76,7 @@ static int vcn_v1_0_early_init(void *handle)
jpeg_v1_0_early_init(handle);
- return 0;
+ return amdgpu_vcn_early_init(adev);
}
/**
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c
index 08871bad9994..4b4cd88414e0 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c
@@ -62,11 +62,12 @@ static int vcn_v2_0_pause_dpg_mode(struct amdgpu_device *adev,
int inst_idx, struct dpg_pause_state *new_state);
static int vcn_v2_0_start_sriov(struct amdgpu_device *adev);
/**
- * vcn_v2_0_early_init - set function pointers
+ * vcn_v2_0_early_init - set function pointers and load microcode
*
* @handle: amdgpu_device pointer
*
* Set ring and irq function pointers
+ * Load microcode from filesystem
*/
static int vcn_v2_0_early_init(void *handle)
{
@@ -81,7 +82,7 @@ static int vcn_v2_0_early_init(void *handle)
vcn_v2_0_set_enc_ring_funcs(adev);
vcn_v2_0_set_irq_funcs(adev);
- return 0;
+ return amdgpu_vcn_early_init(adev);
}
/**
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
index ec87b00f2e05..b0b0e69c6a94 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
@@ -71,11 +71,12 @@ static int amdgpu_ih_clientid_vcns[] = {
};
/**
- * vcn_v2_5_early_init - set function pointers
+ * vcn_v2_5_early_init - set function pointers and load microcode
*
* @handle: amdgpu_device pointer
*
* Set ring and irq function pointers
+ * Load microcode from filesystem
*/
static int vcn_v2_5_early_init(void *handle)
{
@@ -107,7 +108,7 @@ static int vcn_v2_5_early_init(void *handle)
vcn_v2_5_set_irq_funcs(adev);
vcn_v2_5_set_ras_funcs(adev);
- return 0;
+ return amdgpu_vcn_early_init(adev);
}
/**
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
index 9c8b5fd99037..66439388faee 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
@@ -78,11 +78,12 @@ static void vcn_v3_0_dec_ring_set_wptr(struct amdgpu_ring *ring);
static void vcn_v3_0_enc_ring_set_wptr(struct amdgpu_ring *ring);
/**
- * vcn_v3_0_early_init - set function pointers
+ * vcn_v3_0_early_init - set function pointers and load microcode
*
* @handle: amdgpu_device pointer
*
* Set ring and irq function pointers
+ * Load microcode from filesystem
*/
static int vcn_v3_0_early_init(void *handle)
{
@@ -109,7 +110,7 @@ static int vcn_v3_0_early_init(void *handle)
vcn_v3_0_set_enc_ring_funcs(adev);
vcn_v3_0_set_irq_funcs(adev);
- return 0;
+ return amdgpu_vcn_early_init(adev);
}
/**
@@ -1770,6 +1771,10 @@ static int vcn_v3_0_limit_sched(struct amdgpu_cs_parser *p,
if (atomic_read(&job->base.entity->fence_seq))
return -EINVAL;
+ /* if VCN0 is harvested, we can't support AV1 */
+ if (p->adev->vcn.harvest_config & AMDGPU_VCN_HARVEST_VCN0)
+ return -EINVAL;
+
scheds = p->adev->gpu_sched[AMDGPU_HW_IP_VCN_DEC]
[AMDGPU_RING_PRIO_DEFAULT].sched;
drm_sched_entity_modify_sched(job->base.entity, scheds, 1);
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
index 1e2b22299975..43d587404c3e 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
@@ -68,18 +68,27 @@ static void vcn_v4_0_unified_ring_set_wptr(struct amdgpu_ring *ring);
static void vcn_v4_0_set_ras_funcs(struct amdgpu_device *adev);
/**
- * vcn_v4_0_early_init - set function pointers
+ * vcn_v4_0_early_init - set function pointers and load microcode
*
* @handle: amdgpu_device pointer
*
* Set ring and irq function pointers
+ * Load microcode from filesystem
*/
static int vcn_v4_0_early_init(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+ int i;
- if (amdgpu_sriov_vf(adev))
+ if (amdgpu_sriov_vf(adev)) {
adev->vcn.harvest_config = VCN_HARVEST_MMSCH;
+ for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
+ if (amdgpu_vcn_is_disabled_vcn(adev, VCN_ENCODE_RING, i)) {
+ adev->vcn.harvest_config |= 1 << i;
+ dev_info(adev->dev, "VCN%d is disabled by hypervisor\n", i);
+ }
+ }
+ }
/* re-use enc ring as unified ring */
adev->vcn.num_enc_rings = 1;
@@ -88,7 +97,7 @@ static int vcn_v4_0_early_init(void *handle)
vcn_v4_0_set_irq_funcs(adev);
vcn_v4_0_set_ras_funcs(adev);
- return 0;
+ return amdgpu_vcn_early_init(adev);
}
/**
@@ -237,16 +246,11 @@ static int vcn_v4_0_hw_init(void *handle)
continue;
ring = &adev->vcn.inst[i].ring_enc[0];
- if (amdgpu_vcn_is_disabled_vcn(adev, VCN_ENCODE_RING, i)) {
- ring->sched.ready = false;
- ring->no_scheduler = true;
- dev_info(adev->dev, "ring %s is disabled by hypervisor\n", ring->name);
- } else {
- ring->wptr = 0;
- ring->wptr_old = 0;
- vcn_v4_0_unified_ring_set_wptr(ring);
- ring->sched.ready = true;
- }
+ ring->wptr = 0;
+ ring->wptr_old = 0;
+ vcn_v4_0_unified_ring_set_wptr(ring);
+ ring->sched.ready = true;
+
}
} else {
for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
@@ -1631,6 +1635,10 @@ static int vcn_v4_0_limit_sched(struct amdgpu_cs_parser *p,
if (atomic_read(&job->base.entity->fence_seq))
return -EINVAL;
+ /* if VCN0 is harvested, we can't support AV1 */
+ if (p->adev->vcn.harvest_config & AMDGPU_VCN_HARVEST_VCN0)
+ return -EINVAL;
+
scheds = p->adev->gpu_sched[AMDGPU_HW_IP_VCN_ENC]
[AMDGPU_RING_PRIO_0].sched;
drm_sched_entity_modify_sched(job->base.entity, scheds, 1);
@@ -1705,7 +1713,7 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
create = ptr + addr + offset - start;
- /* H246, HEVC and VP9 can run on any instance */
+ /* H264, HEVC and VP9 can run on any instance */
if (create[0] == 0x7 || create[0] == 0x10 || create[0] == 0x11)
continue;
@@ -1719,7 +1727,29 @@ out:
return r;
}
-#define RADEON_VCN_ENGINE_TYPE_DECODE (0x00000003)
+#define RADEON_VCN_ENGINE_TYPE_ENCODE (0x00000002)
+#define RADEON_VCN_ENGINE_TYPE_DECODE (0x00000003)
+
+#define RADEON_VCN_ENGINE_INFO (0x30000001)
+#define RADEON_VCN_ENGINE_INFO_MAX_OFFSET 16
+
+#define RENCODE_ENCODE_STANDARD_AV1 2
+#define RENCODE_IB_PARAM_SESSION_INIT 0x00000003
+#define RENCODE_IB_PARAM_SESSION_INIT_MAX_OFFSET 64
+
+/* return the offset in ib if id is found, -1 otherwise
+ * to speed up the searching we only search upto max_offset
+ */
+static int vcn_v4_0_enc_find_ib_param(struct amdgpu_ib *ib, uint32_t id, int max_offset)
+{
+ int i;
+
+ for (i = 0; i < ib->length_dw && i < max_offset && ib->ptr[i] >= 8; i += ib->ptr[i]/4) {
+ if (ib->ptr[i + 1] == id)
+ return i;
+ }
+ return -1;
+}
static int vcn_v4_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p,
struct amdgpu_job *job,
@@ -1729,27 +1759,35 @@ static int vcn_v4_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p,
struct amdgpu_vcn_decode_buffer *decode_buffer;
uint64_t addr;
uint32_t val;
+ int idx;
/* The first instance can decode anything */
if (!ring->me)
return 0;
- /* unified queue ib header has 8 double words. */
- if (ib->length_dw < 8)
+ /* RADEON_VCN_ENGINE_INFO is at the top of ib block */
+ idx = vcn_v4_0_enc_find_ib_param(ib, RADEON_VCN_ENGINE_INFO,
+ RADEON_VCN_ENGINE_INFO_MAX_OFFSET);
+ if (idx < 0) /* engine info is missing */
return 0;
- val = amdgpu_ib_get_value(ib, 6); //RADEON_VCN_ENGINE_TYPE
- if (val != RADEON_VCN_ENGINE_TYPE_DECODE)
- return 0;
-
- decode_buffer = (struct amdgpu_vcn_decode_buffer *)&ib->ptr[10];
-
- if (!(decode_buffer->valid_buf_flag & 0x1))
- return 0;
-
- addr = ((u64)decode_buffer->msg_buffer_address_hi) << 32 |
- decode_buffer->msg_buffer_address_lo;
- return vcn_v4_0_dec_msg(p, job, addr);
+ val = amdgpu_ib_get_value(ib, idx + 2); /* RADEON_VCN_ENGINE_TYPE */
+ if (val == RADEON_VCN_ENGINE_TYPE_DECODE) {
+ decode_buffer = (struct amdgpu_vcn_decode_buffer *)&ib->ptr[idx + 6];
+
+ if (!(decode_buffer->valid_buf_flag & 0x1))
+ return 0;
+
+ addr = ((u64)decode_buffer->msg_buffer_address_hi) << 32 |
+ decode_buffer->msg_buffer_address_lo;
+ return vcn_v4_0_dec_msg(p, job, addr);
+ } else if (val == RADEON_VCN_ENGINE_TYPE_ENCODE) {
+ idx = vcn_v4_0_enc_find_ib_param(ib, RENCODE_IB_PARAM_SESSION_INIT,
+ RENCODE_IB_PARAM_SESSION_INIT_MAX_OFFSET);
+ if (idx >= 0 && ib->ptr[idx + 2] == RENCODE_ENCODE_STANDARD_AV1)
+ return vcn_v4_0_limit_sched(p, job);
+ }
+ return 0;
}
static const struct amdgpu_ring_funcs vcn_v4_0_unified_ring_vm_funcs = {
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
index 6d291aa6386b..a0e30f21e12e 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
@@ -1065,6 +1065,20 @@ static int kfd_ioctl_alloc_memory_of_gpu(struct file *filep,
mutex_unlock(&p->svms.lock);
return -EADDRINUSE;
}
+
+ /* When register user buffer check if it has been registered by svm by
+ * buffer cpu virtual address.
+ */
+ if ((flags & KFD_IOC_ALLOC_MEM_FLAGS_USERPTR) &&
+ interval_tree_iter_first(&p->svms.objects,
+ args->mmap_offset >> PAGE_SHIFT,
+ (args->mmap_offset + args->size - 1) >> PAGE_SHIFT)) {
+ pr_err("User Buffer Address: 0x%llx already allocated by SVM\n",
+ args->mmap_offset);
+ mutex_unlock(&p->svms.lock);
+ return -EADDRINUSE;
+ }
+
mutex_unlock(&p->svms.lock);
#endif
mutex_lock(&p->mutex);
@@ -1127,8 +1141,13 @@ static int kfd_ioctl_alloc_memory_of_gpu(struct file *filep,
}
/* Update the VRAM usage count */
- if (flags & KFD_IOC_ALLOC_MEM_FLAGS_VRAM)
- WRITE_ONCE(pdd->vram_usage, pdd->vram_usage + args->size);
+ if (flags & KFD_IOC_ALLOC_MEM_FLAGS_VRAM) {
+ uint64_t size = args->size;
+
+ if (flags & KFD_IOC_ALLOC_MEM_FLAGS_AQL_QUEUE_MEM)
+ size >>= 1;
+ WRITE_ONCE(pdd->vram_usage, pdd->vram_usage + PAGE_ALIGN(size));
+ }
mutex_unlock(&p->mutex);
@@ -2879,8 +2898,8 @@ static int kfd_mmio_mmap(struct kfd_dev *dev, struct kfd_process *process,
address = dev->adev->rmmio_remap.bus_addr;
- vma->vm_flags |= VM_IO | VM_DONTCOPY | VM_DONTEXPAND | VM_NORESERVE |
- VM_DONTDUMP | VM_PFNMAP;
+ vm_flags_set(vma, VM_IO | VM_DONTCOPY | VM_DONTEXPAND | VM_NORESERVE |
+ VM_DONTDUMP | VM_PFNMAP);
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
index b8936340742b..3de7f616a001 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
@@ -262,23 +262,12 @@ struct kfd_dev *kgd2kfd_probe(struct amdgpu_device *adev, bool vf)
f2g = &gfx_v8_kfd2kgd;
break;
case CHIP_FIJI:
- gfx_target_version = 80003;
- f2g = &gfx_v8_kfd2kgd;
- break;
case CHIP_POLARIS10:
gfx_target_version = 80003;
f2g = &gfx_v8_kfd2kgd;
break;
case CHIP_POLARIS11:
- gfx_target_version = 80003;
- if (!vf)
- f2g = &gfx_v8_kfd2kgd;
- break;
case CHIP_POLARIS12:
- gfx_target_version = 80003;
- if (!vf)
- f2g = &gfx_v8_kfd2kgd;
- break;
case CHIP_VEGAM:
gfx_target_version = 80003;
if (!vf)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
index c06ada0844ba..7a95698d83f7 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
@@ -2373,7 +2373,7 @@ struct device_queue_manager *device_queue_manager_init(struct kfd_dev *dev)
if (init_mqd_managers(dqm))
goto out_free;
- if (allocate_hiq_sdma_mqd(dqm)) {
+ if (!dev->shared_resources.enable_mes && allocate_hiq_sdma_mqd(dqm)) {
pr_err("Failed to allocate hiq sdma mqd trunk buffer\n");
goto out_free;
}
@@ -2397,7 +2397,8 @@ static void deallocate_hiq_sdma_mqd(struct kfd_dev *dev,
void device_queue_manager_uninit(struct device_queue_manager *dqm)
{
dqm->ops.uninitialize(dqm);
- deallocate_hiq_sdma_mqd(dqm->dev, &dqm->hiq_sdma_mqd);
+ if (!dqm->dev->shared_resources.enable_mes)
+ deallocate_hiq_sdma_mqd(dqm->dev, &dqm->hiq_sdma_mqd);
kfree(dqm);
}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v9.c
index d119070956fb..8b2dd2670ab7 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v9.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_v9.c
@@ -59,30 +59,27 @@ static int update_qpd_v9(struct device_queue_manager *dqm,
/* check if sh_mem_config register already configured */
if (qpd->sh_mem_config == 0) {
- qpd->sh_mem_config =
- SH_MEM_ALIGNMENT_MODE_UNALIGNED <<
+ qpd->sh_mem_config = SH_MEM_ALIGNMENT_MODE_UNALIGNED <<
SH_MEM_CONFIG__ALIGNMENT_MODE__SHIFT;
- if (KFD_GC_VERSION(dqm->dev) == IP_VERSION(9, 4, 2)) {
- /* Aldebaran can safely support different XNACK modes
- * per process
- */
- if (!pdd->process->xnack_enabled)
- qpd->sh_mem_config |=
- 1 << SH_MEM_CONFIG__RETRY_DISABLE__SHIFT;
- } else if (dqm->dev->noretry &&
- !dqm->dev->use_iommu_v2) {
- qpd->sh_mem_config |=
- 1 << SH_MEM_CONFIG__RETRY_DISABLE__SHIFT;
- }
+ if (dqm->dev->noretry && !dqm->dev->use_iommu_v2)
+ qpd->sh_mem_config |= 1 << SH_MEM_CONFIG__RETRY_DISABLE__SHIFT;
qpd->sh_mem_ape1_limit = 0;
qpd->sh_mem_ape1_base = 0;
}
+ if (KFD_SUPPORT_XNACK_PER_PROCESS(dqm->dev)) {
+ if (!pdd->process->xnack_enabled)
+ qpd->sh_mem_config |= 1 << SH_MEM_CONFIG__RETRY_DISABLE__SHIFT;
+ else
+ qpd->sh_mem_config &= ~(1 << SH_MEM_CONFIG__RETRY_DISABLE__SHIFT);
+ }
+
qpd->sh_mem_bases = compute_sh_mem_bases_64bit(pdd);
- pr_debug("sh_mem_bases 0x%X\n", qpd->sh_mem_bases);
+ pr_debug("sh_mem_bases 0x%X sh_mem_config 0x%X\n", qpd->sh_mem_bases,
+ qpd->sh_mem_config);
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c b/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
index cd4e61bf0493..cbef2e147da5 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
@@ -159,8 +159,8 @@ int kfd_doorbell_mmap(struct kfd_dev *dev, struct kfd_process *process,
address = kfd_get_process_doorbells(pdd);
if (!address)
return -ENOMEM;
- vma->vm_flags |= VM_IO | VM_DONTCOPY | VM_DONTEXPAND | VM_NORESERVE |
- VM_DONTDUMP | VM_PFNMAP;
+ vm_flags_set(vma, VM_IO | VM_DONTCOPY | VM_DONTEXPAND | VM_NORESERVE |
+ VM_DONTDUMP | VM_PFNMAP);
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_events.c
index 729d26d648af..c894cf8f7c50 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_events.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_events.c
@@ -778,16 +778,13 @@ static struct kfd_event_waiter *alloc_event_waiters(uint32_t num_events)
struct kfd_event_waiter *event_waiters;
uint32_t i;
- event_waiters = kmalloc_array(num_events,
- sizeof(struct kfd_event_waiter),
- GFP_KERNEL);
+ event_waiters = kcalloc(num_events, sizeof(struct kfd_event_waiter),
+ GFP_KERNEL);
if (!event_waiters)
return NULL;
- for (i = 0; (event_waiters) && (i < num_events) ; i++) {
+ for (i = 0; i < num_events; i++)
init_wait(&event_waiters[i].wait);
- event_waiters[i].activated = false;
- }
return event_waiters;
}
@@ -1052,8 +1049,8 @@ int kfd_event_mmap(struct kfd_process *p, struct vm_area_struct *vma)
pfn = __pa(page->kernel_address);
pfn >>= PAGE_SHIFT;
- vma->vm_flags |= VM_IO | VM_DONTCOPY | VM_DONTEXPAND | VM_NORESERVE
- | VM_DONTDUMP | VM_PFNMAP;
+ vm_flags_set(vma, VM_IO | VM_DONTCOPY | VM_DONTEXPAND | VM_NORESERVE
+ | VM_DONTDUMP | VM_PFNMAP);
pr_debug("Mapping signal page\n");
pr_debug(" start user address == 0x%08lx\n", vma->vm_start);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
index 10048ce16aea..de8ce72344fc 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
@@ -1027,8 +1027,7 @@ int svm_migrate_init(struct amdgpu_device *adev)
/* Disable SVM support capability */
pgmap->type = 0;
if (pgmap->type == MEMORY_DEVICE_PRIVATE)
- devm_release_mem_region(adev->dev, res->start,
- res->end - res->start + 1);
+ devm_release_mem_region(adev->dev, res->start, resource_size(res));
return PTR_ERR(r);
}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c
index 4f6390f3236e..4a9af800b1f1 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c
@@ -308,11 +308,16 @@ static void init_mqd_sdma(struct mqd_manager *mm, void **mqd,
struct queue_properties *q)
{
struct v11_sdma_mqd *m;
+ int size;
m = (struct v11_sdma_mqd *) mqd_mem_obj->cpu_ptr;
- memset(m, 0, sizeof(struct v11_sdma_mqd));
+ if (mm->dev->shared_resources.enable_mes)
+ size = PAGE_SIZE;
+ else
+ size = sizeof(struct v11_sdma_mqd);
+ memset(m, 0, size);
*mqd = m;
if (gart_addr)
*gart_addr = mqd_mem_obj->gpu_addr;
@@ -443,6 +448,14 @@ struct mqd_manager *mqd_manager_init_v11(enum KFD_MQD_TYPE type,
#if defined(CONFIG_DEBUG_FS)
mqd->debugfs_show_mqd = debugfs_show_mqd_sdma;
#endif
+ /*
+ * To allocate SDMA MQDs by generic functions
+ * when MES is enabled.
+ */
+ if (dev->shared_resources.enable_mes) {
+ mqd->allocate_mqd = allocate_mqd;
+ mqd->free_mqd = kfd_free_mqd_cp;
+ }
pr_debug("%s@%i\n", __func__, __LINE__);
break;
default:
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
index 552c3ac85a13..bfa30d12406b 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
@@ -206,6 +206,8 @@ enum cache_policy {
#define KFD_GC_VERSION(dev) ((dev)->adev->ip_versions[GC_HWIP][0])
#define KFD_IS_SOC15(dev) ((KFD_GC_VERSION(dev)) >= (IP_VERSION(9, 0, 1)))
+#define KFD_SUPPORT_XNACK_PER_PROCESS(dev)\
+ (KFD_GC_VERSION(dev) == IP_VERSION(9, 4, 2))
struct kfd_event_interrupt_class {
bool (*interrupt_isr)(struct kfd_dev *dev,
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
index 51b1683ac5c1..7acd55a814b2 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
@@ -1330,7 +1330,7 @@ bool kfd_process_xnack_mode(struct kfd_process *p, bool supported)
* per-process XNACK mode selection. But let the dev->noretry
* setting still influence the default XNACK mode.
*/
- if (supported && KFD_GC_VERSION(dev) == IP_VERSION(9, 4, 2))
+ if (supported && KFD_SUPPORT_XNACK_PER_PROCESS(dev))
continue;
/* GFXv10 and later GPUs do not support shader preemption
@@ -1563,6 +1563,8 @@ err_free_pdd:
int kfd_process_device_init_vm(struct kfd_process_device *pdd,
struct file *drm_file)
{
+ struct amdgpu_fpriv *drv_priv;
+ struct amdgpu_vm *avm;
struct kfd_process *p;
struct kfd_dev *dev;
int ret;
@@ -1573,10 +1575,15 @@ int kfd_process_device_init_vm(struct kfd_process_device *pdd,
if (pdd->drm_priv)
return -EBUSY;
+ ret = amdgpu_file_to_fpriv(drm_file, &drv_priv);
+ if (ret)
+ return ret;
+ avm = &drv_priv->vm;
+
p = pdd->process;
dev = pdd->dev;
- ret = amdgpu_amdkfd_gpuvm_acquire_process_vm(dev->adev, drm_file,
+ ret = amdgpu_amdkfd_gpuvm_acquire_process_vm(dev->adev, avm,
&p->kgd_process_info,
&p->ef);
if (ret) {
@@ -1593,7 +1600,7 @@ int kfd_process_device_init_vm(struct kfd_process_device *pdd,
if (ret)
goto err_init_cwsr;
- ret = amdgpu_amdkfd_gpuvm_set_vm_pasid(dev->adev, drm_file, p->pasid);
+ ret = amdgpu_amdkfd_gpuvm_set_vm_pasid(dev->adev, avm, p->pasid);
if (ret)
goto err_set_pasid;
@@ -1607,6 +1614,7 @@ err_init_cwsr:
kfd_process_device_destroy_ib_mem(pdd);
err_reserve_ib_mem:
pdd->drm_priv = NULL;
+ amdgpu_amdkfd_gpuvm_destroy_cb(dev->adev, avm);
return ret;
}
@@ -1978,8 +1986,8 @@ int kfd_reserved_mem_mmap(struct kfd_dev *dev, struct kfd_process *process,
return -ENOMEM;
}
- vma->vm_flags |= VM_IO | VM_DONTCOPY | VM_DONTEXPAND
- | VM_NORESERVE | VM_DONTDUMP | VM_PFNMAP;
+ vm_flags_set(vma, VM_IO | VM_DONTCOPY | VM_DONTEXPAND
+ | VM_NORESERVE | VM_DONTDUMP | VM_PFNMAP);
/* Mapping pages to user process */
return remap_pfn_range(vma, vma->vm_start,
PFN_DOWN(__pa(qpd->cwsr_kaddr)),
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
index b94d2c1422ad..dc6fd6967050 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
@@ -23,6 +23,7 @@
#include <linux/types.h>
#include <linux/sched/task.h>
+#include <drm/ttm/ttm_tt.h>
#include "amdgpu_sync.h"
#include "amdgpu_object.h"
#include "amdgpu_vm.h"
diff --git a/drivers/gpu/drm/amd/display/Kconfig b/drivers/gpu/drm/amd/display/Kconfig
index 2efe93f74f84..0c9bd0a53e60 100644
--- a/drivers/gpu/drm/amd/display/Kconfig
+++ b/drivers/gpu/drm/amd/display/Kconfig
@@ -28,7 +28,6 @@ config DRM_AMD_DC_DCN
config DRM_AMD_DC_HDCP
bool "Enable HDCP support in DC"
depends on DRM_AMD_DC
- select DRM_DISPLAY_HDCP_HELPER
help
Choose this option if you want to support HDCP authentication.
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 9c7b69d377bd..009ef917dad4 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -28,7 +28,6 @@
#include "dm_services_types.h"
#include "dc.h"
-#include "dc_link_dp.h"
#include "link_enc_cfg.h"
#include "dc/inc/core_types.h"
#include "dal_asic_id.h"
@@ -39,6 +38,11 @@
#include "dc/dc_edid_parser.h"
#include "dc/dc_stat.h"
#include "amdgpu_dm_trace.h"
+#include "dpcd_defs.h"
+#include "link/protocols/link_dpcd.h"
+#include "link_service_types.h"
+#include "link/protocols/link_dp_capability.h"
+#include "link/protocols/link_ddc.h"
#include "vid.h"
#include "amdgpu.h"
@@ -66,7 +70,7 @@
#include "ivsrcid/ivsrcid_vislands30.h"
-#include "i2caux_interface.h"
+#include <linux/backlight.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -104,7 +108,6 @@
#include "modules/inc/mod_freesync.h"
#include "modules/power/power_helpers.h"
-#include "modules/inc/mod_info_packet.h"
#define FIRMWARE_RENOIR_DMUB "amdgpu/renoir_dmcub.bin"
MODULE_FIRMWARE(FIRMWARE_RENOIR_DMUB);
@@ -210,7 +213,7 @@ static void amdgpu_dm_destroy_drm_device(struct amdgpu_display_manager *dm);
static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm,
struct amdgpu_dm_connector *amdgpu_dm_connector,
- uint32_t link_index,
+ u32 link_index,
struct amdgpu_encoder *amdgpu_encoder);
static int amdgpu_dm_encoder_init(struct drm_device *dev,
struct amdgpu_encoder *aencoder,
@@ -262,7 +265,7 @@ static u32 dm_vblank_get_counter(struct amdgpu_device *adev, int crtc)
static int dm_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc,
u32 *vbl, u32 *position)
{
- uint32_t v_blank_start, v_blank_end, h_position, v_position;
+ u32 v_blank_start, v_blank_end, h_position, v_position;
if ((crtc < 0) || (crtc >= adev->mode_info.num_crtc))
return -EINVAL;
@@ -361,7 +364,7 @@ static void dm_pflip_high_irq(void *interrupt_params)
struct amdgpu_device *adev = irq_params->adev;
unsigned long flags;
struct drm_pending_vblank_event *e;
- uint32_t vpos, hpos, v_blank_start, v_blank_end;
+ u32 vpos, hpos, v_blank_start, v_blank_end;
bool vrr_active;
amdgpu_crtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_PFLIP);
@@ -648,7 +651,7 @@ static void dmub_hpd_callback(struct amdgpu_device *adev,
struct drm_connector *connector;
struct drm_connector_list_iter iter;
struct dc_link *link;
- uint8_t link_index = 0;
+ u8 link_index = 0;
struct drm_device *dev;
if (adev == NULL)
@@ -749,7 +752,7 @@ static void dm_dmub_outbox1_low_irq(void *interrupt_params)
struct amdgpu_device *adev = irq_params->adev;
struct amdgpu_display_manager *dm = &adev->dm;
struct dmcub_trace_buf_entry entry = { 0 };
- uint32_t count = 0;
+ u32 count = 0;
struct dmub_hpd_work *dmub_hpd_wrk;
struct dc_link *plink = NULL;
@@ -1015,7 +1018,7 @@ static int dm_dmub_hw_init(struct amdgpu_device *adev)
struct dmub_srv_hw_params hw_params;
enum dmub_status status;
const unsigned char *fw_inst_const, *fw_bss_data;
- uint32_t i, fw_inst_const_size, fw_bss_data_size;
+ u32 i, fw_inst_const_size, fw_bss_data_size;
bool has_hw_support;
if (!dmub_srv)
@@ -1176,10 +1179,10 @@ static void dm_dmub_hw_resume(struct amdgpu_device *adev)
static void mmhub_read_system_context(struct amdgpu_device *adev, struct dc_phy_addr_space_config *pa_config)
{
- uint64_t pt_base;
- uint32_t logical_addr_low;
- uint32_t logical_addr_high;
- uint32_t agp_base, agp_bot, agp_top;
+ u64 pt_base;
+ u32 logical_addr_low;
+ u32 logical_addr_high;
+ u32 agp_base, agp_bot, agp_top;
PHYSICAL_ADDRESS_LOC page_table_start, page_table_end, page_table_base;
memset(pa_config, 0, sizeof(*pa_config));
@@ -1190,7 +1193,7 @@ static void mmhub_read_system_context(struct amdgpu_device *adev, struct dc_phy_
/* AGP aperture is disabled */
if (agp_bot == agp_top) {
- logical_addr_low = adev->gmc.vram_start >> 18;
+ logical_addr_low = adev->gmc.fb_start >> 18;
if (adev->apu_flags & AMD_APU_IS_RAVEN2)
/*
* Raven2 has a HW issue that it is unable to use the vram which
@@ -1200,9 +1203,9 @@ static void mmhub_read_system_context(struct amdgpu_device *adev, struct dc_phy_
*/
logical_addr_high = (adev->gmc.fb_end >> 18) + 0x1;
else
- logical_addr_high = adev->gmc.vram_end >> 18;
+ logical_addr_high = adev->gmc.fb_end >> 18;
} else {
- logical_addr_low = min(adev->gmc.fb_start, adev->gmc.agp_start) >> 18;
+ logical_addr_low = min(adev->gmc.fb_start, adev->gmc.agp_start) >> 18;
if (adev->apu_flags & AMD_APU_IS_RAVEN2)
/*
* Raven2 has a HW issue that it is unable to use the vram which
@@ -1239,10 +1242,25 @@ static void mmhub_read_system_context(struct amdgpu_device *adev, struct dc_phy_
pa_config->gart_config.page_table_end_addr = page_table_end.quad_part << 12;
pa_config->gart_config.page_table_base_addr = page_table_base.quad_part;
- pa_config->is_hvm_enabled = 0;
+ pa_config->is_hvm_enabled = adev->mode_info.gpu_vm_support;
}
+static void force_connector_state(
+ struct amdgpu_dm_connector *aconnector,
+ enum drm_connector_force force_state)
+{
+ struct drm_connector *connector = &aconnector->base;
+
+ mutex_lock(&connector->dev->mode_config.mutex);
+ aconnector->base.force = force_state;
+ mutex_unlock(&connector->dev->mode_config.mutex);
+
+ mutex_lock(&aconnector->hpd_lock);
+ drm_kms_helper_connector_hotplug_event(connector);
+ mutex_unlock(&aconnector->hpd_lock);
+}
+
static void dm_handle_hpd_rx_offload_work(struct work_struct *work)
{
struct hpd_rx_irq_offload_work *offload_work;
@@ -1251,6 +1269,9 @@ static void dm_handle_hpd_rx_offload_work(struct work_struct *work)
struct amdgpu_device *adev;
enum dc_connection_type new_connection_type = dc_connection_none;
unsigned long flags;
+ union test_response test_response;
+
+ memset(&test_response, 0, sizeof(test_response));
offload_work = container_of(work, struct hpd_rx_irq_offload_work, work);
aconnector = offload_work->offload_wq->aconnector;
@@ -1264,7 +1285,7 @@ static void dm_handle_hpd_rx_offload_work(struct work_struct *work)
dc_link = aconnector->dc_link;
mutex_lock(&aconnector->hpd_lock);
- if (!dc_link_detect_sink(dc_link, &new_connection_type))
+ if (!dc_link_detect_connection_type(dc_link, &new_connection_type))
DRM_ERROR("KMS: Failed to detect connector\n");
mutex_unlock(&aconnector->hpd_lock);
@@ -1275,15 +1296,49 @@ static void dm_handle_hpd_rx_offload_work(struct work_struct *work)
goto skip;
mutex_lock(&adev->dm.dc_lock);
- if (offload_work->data.bytes.device_service_irq.bits.AUTOMATED_TEST)
+ if (offload_work->data.bytes.device_service_irq.bits.AUTOMATED_TEST) {
dc_link_dp_handle_automated_test(dc_link);
+
+ if (aconnector->timing_changed) {
+ /* force connector disconnect and reconnect */
+ force_connector_state(aconnector, DRM_FORCE_OFF);
+ msleep(100);
+ force_connector_state(aconnector, DRM_FORCE_UNSPECIFIED);
+ }
+
+ test_response.bits.ACK = 1;
+
+ core_link_write_dpcd(
+ dc_link,
+ DP_TEST_RESPONSE,
+ &test_response.raw,
+ sizeof(test_response));
+ }
else if ((dc_link->connector_signal != SIGNAL_TYPE_EDP) &&
- hpd_rx_irq_check_link_loss_status(dc_link, &offload_work->data) &&
+ dc_link_check_link_loss_status(dc_link, &offload_work->data) &&
dc_link_dp_allow_hpd_rx_irq(dc_link)) {
- dc_link_dp_handle_link_loss(dc_link);
+ /* offload_work->data is from handle_hpd_rx_irq->
+ * schedule_hpd_rx_offload_work.this is defer handle
+ * for hpd short pulse. upon here, link status may be
+ * changed, need get latest link status from dpcd
+ * registers. if link status is good, skip run link
+ * training again.
+ */
+ union hpd_irq_data irq_data;
+
+ memset(&irq_data, 0, sizeof(irq_data));
+
+ /* before dc_link_dp_handle_link_loss, allow new link lost handle
+ * request be added to work queue if link lost at end of dc_link_
+ * dp_handle_link_loss
+ */
spin_lock_irqsave(&offload_work->offload_wq->offload_lock, flags);
offload_work->offload_wq->is_handling_link_loss = false;
spin_unlock_irqrestore(&offload_work->offload_wq->offload_lock, flags);
+
+ if ((dc_link_dp_read_hpd_rx_irq_data(dc_link, &irq_data) == DC_OK) &&
+ dc_link_check_link_loss_status(dc_link, &irq_data))
+ dc_link_dp_handle_link_loss(dc_link);
}
mutex_unlock(&adev->dm.dc_lock);
@@ -1551,6 +1606,11 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
if (amdgpu_dc_feature_mask & DC_DISABLE_LTTPR_DP2_0)
init_data.flags.allow_lttpr_non_transparent_mode.bits.DP2_0 = true;
+ /* Disable SubVP + DRR config by default */
+ init_data.flags.disable_subvp_drr = true;
+ if (amdgpu_dc_feature_mask & DC_ENABLE_SUBVP_DRR)
+ init_data.flags.disable_subvp_drr = false;
+
init_data.flags.seamless_boot_edp_requested = false;
if (check_seamless_boot_capability(adev)) {
@@ -1606,6 +1666,26 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
/* TODO: Remove after DP2 receiver gets proper support of Cable ID feature */
adev->dm.dc->debug.ignore_cable_id = true;
+ /* TODO: There is a new drm mst change where the freedom of
+ * vc_next_start_slot update is revoked/moved into drm, instead of in
+ * driver. This forces us to make sure to get vc_next_start_slot updated
+ * in drm function each time without considering if mst_state is active
+ * or not. Otherwise, next time hotplug will give wrong start_slot
+ * number. We are implementing a temporary solution to even notify drm
+ * mst deallocation when link is no longer of MST type when uncommitting
+ * the stream so we will have more time to work on a proper solution.
+ * Ideally when dm_helpers_dp_mst_stop_top_mgr message is triggered, we
+ * should notify drm to do a complete "reset" of its states and stop
+ * calling further drm mst functions when link is no longer of an MST
+ * type. This could happen when we unplug an MST hubs/displays. When
+ * uncommit stream comes later after unplug, we should just reset
+ * hardware states only.
+ */
+ adev->dm.dc->debug.temp_mst_deallocation_sequence = true;
+
+ if (adev->dm.dc->caps.dp_hdmi21_pcon_support)
+ DRM_INFO("DP-HDMI FRL PCON supported\n");
+
r = dm_dmub_hw_init(adev);
if (r) {
DRM_ERROR("DMUB interface failed to initialize: status=%d\n", r);
@@ -1659,7 +1739,10 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
}
#endif
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
- adev->dm.crc_rd_wrk = amdgpu_dm_crtc_secure_display_create_work();
+ adev->dm.secure_display_ctxs = amdgpu_dm_crtc_secure_display_create_contexts(adev);
+ if (!adev->dm.secure_display_ctxs) {
+ DRM_ERROR("amdgpu: failed to initialize secure_display_ctxs.\n");
+ }
#endif
if (dc_is_dmub_outbox_supported(adev->dm.dc)) {
init_completion(&adev->dm.dmub_aux_transfer_done);
@@ -1750,10 +1833,15 @@ static void amdgpu_dm_fini(struct amdgpu_device *adev)
amdgpu_dm_destroy_drm_device(&adev->dm);
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
- if (adev->dm.crc_rd_wrk) {
- flush_work(&adev->dm.crc_rd_wrk->notify_ta_work);
- kfree(adev->dm.crc_rd_wrk);
- adev->dm.crc_rd_wrk = NULL;
+ if (adev->dm.secure_display_ctxs) {
+ for (i = 0; i < adev->mode_info.num_crtc; i++) {
+ if (adev->dm.secure_display_ctxs[i].crtc) {
+ flush_work(&adev->dm.secure_display_ctxs[i].notify_ta_work);
+ flush_work(&adev->dm.secure_display_ctxs[i].forward_roi_work);
+ }
+ }
+ kfree(adev->dm.secure_display_ctxs);
+ adev->dm.secure_display_ctxs = NULL;
}
#endif
#ifdef CONFIG_DRM_AMD_DC_HDCP
@@ -1888,25 +1976,17 @@ static int load_dmcu_fw(struct amdgpu_device *adev)
return 0;
}
- r = request_firmware_direct(&adev->dm.fw_dmcu, fw_name_dmcu, adev->dev);
- if (r == -ENOENT) {
+ r = amdgpu_ucode_request(adev, &adev->dm.fw_dmcu, fw_name_dmcu);
+ if (r == -ENODEV) {
/* DMCU firmware is not necessary, so don't raise a fuss if it's missing */
DRM_DEBUG_KMS("dm: DMCU firmware not found\n");
adev->dm.fw_dmcu = NULL;
return 0;
}
if (r) {
- dev_err(adev->dev, "amdgpu_dm: Can't load firmware \"%s\"\n",
- fw_name_dmcu);
- return r;
- }
-
- r = amdgpu_ucode_validate(adev->dm.fw_dmcu);
- if (r) {
dev_err(adev->dev, "amdgpu_dm: Can't validate firmware \"%s\"\n",
fw_name_dmcu);
- release_firmware(adev->dm.fw_dmcu);
- adev->dm.fw_dmcu = NULL;
+ amdgpu_ucode_release(&adev->dm.fw_dmcu);
return r;
}
@@ -1952,7 +2032,6 @@ static int dm_dmub_sw_init(struct amdgpu_device *adev)
struct dmub_srv_fb_info *fb_info;
struct dmub_srv *dmub_srv;
const struct dmcub_firmware_header_v1_0 *hdr;
- const char *fw_name_dmub;
enum dmub_asic dmub_asic;
enum dmub_status status;
int r;
@@ -1960,73 +2039,43 @@ static int dm_dmub_sw_init(struct amdgpu_device *adev)
switch (adev->ip_versions[DCE_HWIP][0]) {
case IP_VERSION(2, 1, 0):
dmub_asic = DMUB_ASIC_DCN21;
- fw_name_dmub = FIRMWARE_RENOIR_DMUB;
- if (ASICREV_IS_GREEN_SARDINE(adev->external_rev_id))
- fw_name_dmub = FIRMWARE_GREEN_SARDINE_DMUB;
break;
case IP_VERSION(3, 0, 0):
- if (adev->ip_versions[GC_HWIP][0] == IP_VERSION(10, 3, 0)) {
- dmub_asic = DMUB_ASIC_DCN30;
- fw_name_dmub = FIRMWARE_SIENNA_CICHLID_DMUB;
- } else {
- dmub_asic = DMUB_ASIC_DCN30;
- fw_name_dmub = FIRMWARE_NAVY_FLOUNDER_DMUB;
- }
+ dmub_asic = DMUB_ASIC_DCN30;
break;
case IP_VERSION(3, 0, 1):
dmub_asic = DMUB_ASIC_DCN301;
- fw_name_dmub = FIRMWARE_VANGOGH_DMUB;
break;
case IP_VERSION(3, 0, 2):
dmub_asic = DMUB_ASIC_DCN302;
- fw_name_dmub = FIRMWARE_DIMGREY_CAVEFISH_DMUB;
break;
case IP_VERSION(3, 0, 3):
dmub_asic = DMUB_ASIC_DCN303;
- fw_name_dmub = FIRMWARE_BEIGE_GOBY_DMUB;
break;
case IP_VERSION(3, 1, 2):
case IP_VERSION(3, 1, 3):
dmub_asic = (adev->external_rev_id == YELLOW_CARP_B0) ? DMUB_ASIC_DCN31B : DMUB_ASIC_DCN31;
- fw_name_dmub = FIRMWARE_YELLOW_CARP_DMUB;
break;
case IP_VERSION(3, 1, 4):
dmub_asic = DMUB_ASIC_DCN314;
- fw_name_dmub = FIRMWARE_DCN_314_DMUB;
break;
case IP_VERSION(3, 1, 5):
dmub_asic = DMUB_ASIC_DCN315;
- fw_name_dmub = FIRMWARE_DCN_315_DMUB;
break;
case IP_VERSION(3, 1, 6):
dmub_asic = DMUB_ASIC_DCN316;
- fw_name_dmub = FIRMWARE_DCN316_DMUB;
break;
case IP_VERSION(3, 2, 0):
dmub_asic = DMUB_ASIC_DCN32;
- fw_name_dmub = FIRMWARE_DCN_V3_2_0_DMCUB;
break;
case IP_VERSION(3, 2, 1):
dmub_asic = DMUB_ASIC_DCN321;
- fw_name_dmub = FIRMWARE_DCN_V3_2_1_DMCUB;
break;
default:
/* ASIC doesn't support DMUB. */
return 0;
}
- r = request_firmware_direct(&adev->dm.dmub_fw, fw_name_dmub, adev->dev);
- if (r) {
- DRM_ERROR("DMUB firmware loading failed: %d\n", r);
- return 0;
- }
-
- r = amdgpu_ucode_validate(adev->dm.dmub_fw);
- if (r) {
- DRM_ERROR("Couldn't validate DMUB firmware: %d\n", r);
- return 0;
- }
-
hdr = (const struct dmcub_firmware_header_v1_0 *)adev->dm.dmub_fw->data;
adev->dm.dmcub_fw_version = le32_to_cpu(hdr->header.ucode_version);
@@ -2093,7 +2142,9 @@ static int dm_dmub_sw_init(struct amdgpu_device *adev)
* TODO: Move this into GART.
*/
r = amdgpu_bo_create_kernel(adev, region_info.fb_size, PAGE_SIZE,
- AMDGPU_GEM_DOMAIN_VRAM, &adev->dm.dmub_bo,
+ AMDGPU_GEM_DOMAIN_VRAM |
+ AMDGPU_GEM_DOMAIN_GTT,
+ &adev->dm.dmub_bo,
&adev->dm.dmub_bo_gpu_addr,
&adev->dm.dmub_bo_cpu_addr);
if (r)
@@ -2148,11 +2199,8 @@ static int dm_sw_fini(void *handle)
adev->dm.dmub_srv = NULL;
}
- release_firmware(adev->dm.dmub_fw);
- adev->dm.dmub_fw = NULL;
-
- release_firmware(adev->dm.fw_dmcu);
- adev->dm.fw_dmcu = NULL;
+ amdgpu_ucode_release(&adev->dm.dmub_fw);
+ amdgpu_ucode_release(&adev->dm.fw_dmcu);
return 0;
}
@@ -2178,6 +2226,8 @@ static int detect_mst_link_for_all_connectors(struct drm_device *dev)
DRM_ERROR("DM_MST: Failed to start MST\n");
aconnector->dc_link->type =
dc_connection_single;
+ ret = dm_helpers_dp_mst_stop_top_mgr(aconnector->dc_link->ctx,
+ aconnector->dc_link);
break;
}
}
@@ -2246,7 +2296,7 @@ static void s3_handle_mst(struct drm_device *dev, bool suspend)
drm_for_each_connector_iter(connector, &iter) {
aconnector = to_amdgpu_dm_connector(connector);
if (aconnector->dc_link->type != dc_connection_mst_branch ||
- aconnector->mst_port)
+ aconnector->mst_root)
continue;
mgr = &aconnector->mst_mgr;
@@ -2254,6 +2304,14 @@ static void s3_handle_mst(struct drm_device *dev, bool suspend)
if (suspend) {
drm_dp_mst_topology_mgr_suspend(mgr);
} else {
+ /* if extended timeout is supported in hardware,
+ * default to LTTPR timeout (3.2ms) first as a W/A for DP link layer
+ * CTS 4.2.1.1 regression introduced by CTS specs requirement update.
+ */
+ try_to_configure_aux_timeout(aconnector->dc_link->ddc, LINK_AUX_DEFAULT_LTTPR_TIMEOUT_PERIOD);
+ if (!dp_is_lttpr_present(aconnector->dc_link))
+ try_to_configure_aux_timeout(aconnector->dc_link->ddc, LINK_AUX_DEFAULT_TIMEOUT_PERIOD);
+
ret = drm_dp_mst_topology_mgr_resume(mgr, true);
if (ret < 0) {
dm_helpers_dp_mst_stop_top_mgr(aconnector->dc_link->ctx,
@@ -2499,7 +2557,7 @@ struct amdgpu_dm_connector *
amdgpu_dm_find_first_crtc_matching_connector(struct drm_atomic_state *state,
struct drm_crtc *crtc)
{
- uint32_t i;
+ u32 i;
struct drm_connector_state *new_con_state;
struct drm_connector *connector;
struct drm_crtc *crtc_from_state;
@@ -2747,16 +2805,18 @@ static int dm_resume(void *handle)
drm_for_each_connector_iter(connector, &iter) {
aconnector = to_amdgpu_dm_connector(connector);
+ if (!aconnector->dc_link)
+ continue;
+
/*
* this is the case when traversing through already created
* MST connectors, should be skipped
*/
- if (aconnector->dc_link &&
- aconnector->dc_link->type == dc_connection_mst_branch)
+ if (aconnector->dc_link->type == dc_connection_mst_branch)
continue;
mutex_lock(&aconnector->hpd_lock);
- if (!dc_link_detect_sink(aconnector->dc_link, &new_connection_type))
+ if (!dc_link_detect_connection_type(aconnector->dc_link, &new_connection_type))
DRM_ERROR("KMS: Failed to detect connector\n");
if (aconnector->base.force && new_connection_type == dc_connection_none) {
@@ -3034,6 +3094,10 @@ void amdgpu_dm_update_connector_after_detect(
aconnector->edid);
}
+ aconnector->timing_requested = kzalloc(sizeof(struct dc_crtc_timing), GFP_KERNEL);
+ if (!aconnector->timing_requested)
+ dm_error("%s: failed to create aconnector->requested_timing\n", __func__);
+
drm_connector_update_edid_property(connector, aconnector->edid);
amdgpu_dm_update_freesync_caps(connector, aconnector->edid);
update_connector_ext_caps(aconnector);
@@ -3045,6 +3109,8 @@ void amdgpu_dm_update_connector_after_detect(
dc_sink_release(aconnector->dc_sink);
aconnector->dc_sink = NULL;
aconnector->edid = NULL;
+ kfree(aconnector->timing_requested);
+ aconnector->timing_requested = NULL;
#ifdef CONFIG_DRM_AMD_DC_HDCP
/* Set CP to DESIRED if it was ENABLED, so we can re-enable it again on hotplug */
if (connector->state->content_protection == DRM_MODE_CONTENT_PROTECTION_ENABLED)
@@ -3089,7 +3155,9 @@ static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector)
if (aconnector->fake_enable)
aconnector->fake_enable = false;
- if (!dc_link_detect_sink(aconnector->dc_link, &new_connection_type))
+ aconnector->timing_changed = false;
+
+ if (!dc_link_detect_connection_type(aconnector->dc_link, &new_connection_type))
DRM_ERROR("KMS: Failed to detect connector\n");
if (aconnector->base.force && new_connection_type == dc_connection_none) {
@@ -3130,8 +3198,8 @@ static void handle_hpd_irq(void *param)
static void dm_handle_mst_sideband_msg(struct amdgpu_dm_connector *aconnector)
{
- uint8_t esi[DP_PSR_ERROR_STATUS - DP_SINK_COUNT_ESI] = { 0 };
- uint8_t dret;
+ u8 esi[DP_PSR_ERROR_STATUS - DP_SINK_COUNT_ESI] = { 0 };
+ u8 dret;
bool new_irq_handled = false;
int dpcd_addr;
int dpcd_bytes_to_read;
@@ -3159,7 +3227,7 @@ static void dm_handle_mst_sideband_msg(struct amdgpu_dm_connector *aconnector)
while (dret == dpcd_bytes_to_read &&
process_count < max_process_count) {
- uint8_t retry;
+ u8 retry;
dret = 0;
process_count++;
@@ -3178,7 +3246,7 @@ static void dm_handle_mst_sideband_msg(struct amdgpu_dm_connector *aconnector)
dpcd_bytes_to_read - 1;
for (retry = 0; retry < 3; retry++) {
- uint8_t wret;
+ u8 wret;
wret = drm_dp_dpcd_write(
&aconnector->dm_dp_aux.aux,
@@ -3238,7 +3306,7 @@ static void handle_hpd_rx_irq(void *param)
union hpd_irq_data hpd_irq_data;
bool link_loss = false;
bool has_left_work = false;
- int idx = aconnector->base.index;
+ int idx = dc_link->link_index;
struct hpd_rx_irq_offload_work_queue *offload_wq = &adev->dm.hpd_rx_offload_wq[idx];
memset(&hpd_irq_data, 0, sizeof(hpd_irq_data));
@@ -3292,7 +3360,7 @@ static void handle_hpd_rx_irq(void *param)
out:
if (result && !is_mst_root_connector) {
/* Downstream Port status changed. */
- if (!dc_link_detect_sink(dc_link, &new_connection_type))
+ if (!dc_link_detect_connection_type(dc_link, &new_connection_type))
DRM_ERROR("KMS: Failed to detect connector\n");
if (aconnector->base.force && new_connection_type == dc_connection_none) {
@@ -3380,7 +3448,7 @@ static void register_hpd_handlers(struct amdgpu_device *adev)
(void *) aconnector);
if (adev->dm.hpd_rx_offload_wq)
- adev->dm.hpd_rx_offload_wq[connector->index].aconnector =
+ adev->dm.hpd_rx_offload_wq[dc_link->link_index].aconnector =
aconnector;
}
}
@@ -4192,20 +4260,23 @@ static void amdgpu_set_panel_orientation(struct drm_connector *connector);
static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
{
struct amdgpu_display_manager *dm = &adev->dm;
- int32_t i;
+ s32 i;
struct amdgpu_dm_connector *aconnector = NULL;
struct amdgpu_encoder *aencoder = NULL;
struct amdgpu_mode_info *mode_info = &adev->mode_info;
- uint32_t link_cnt;
- int32_t primary_planes;
+ u32 link_cnt;
+ s32 primary_planes;
enum dc_connection_type new_connection_type = dc_connection_none;
const struct dc_plane_cap *plane;
bool psr_feature_enabled = false;
+ int max_overlay = dm->dc->caps.max_slave_planes;
dm->display_indexes_num = dm->dc->caps.max_streams;
/* Update the actual used number of crtc */
adev->mode_info.num_crtc = adev->dm.display_indexes_num;
+ amdgpu_dm_set_irq_funcs(adev);
+
link_cnt = dm->dc->caps.max_links;
if (amdgpu_dm_mode_config_init(dm->adev)) {
DRM_ERROR("DM: Failed to initialize mode config\n");
@@ -4255,14 +4326,14 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
if (!plane->pixel_format_support.argb8888)
continue;
+ if (max_overlay-- == 0)
+ break;
+
if (initialize_plane(dm, NULL, primary_planes + i,
DRM_PLANE_TYPE_OVERLAY, plane)) {
DRM_ERROR("KMS: Failed to initialize overlay plane\n");
goto fail;
}
-
- /* Only create one overlay plane. */
- break;
}
for (i = 0; i < dm->dc->caps.max_streams; i++)
@@ -4341,7 +4412,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
link = dc_get_link_at_index(dm->dc, i);
- if (!dc_link_detect_sink(link, &new_connection_type))
+ if (!dc_link_detect_connection_type(link, &new_connection_type))
DRM_ERROR("KMS: Failed to detect connector\n");
if (aconnector->base.force && new_connection_type == dc_connection_none) {
@@ -4517,6 +4588,61 @@ DEVICE_ATTR_WO(s3_debug);
#endif
+static int dm_init_microcode(struct amdgpu_device *adev)
+{
+ char *fw_name_dmub;
+ int r;
+
+ switch (adev->ip_versions[DCE_HWIP][0]) {
+ case IP_VERSION(2, 1, 0):
+ fw_name_dmub = FIRMWARE_RENOIR_DMUB;
+ if (ASICREV_IS_GREEN_SARDINE(adev->external_rev_id))
+ fw_name_dmub = FIRMWARE_GREEN_SARDINE_DMUB;
+ break;
+ case IP_VERSION(3, 0, 0):
+ if (adev->ip_versions[GC_HWIP][0] == IP_VERSION(10, 3, 0))
+ fw_name_dmub = FIRMWARE_SIENNA_CICHLID_DMUB;
+ else
+ fw_name_dmub = FIRMWARE_NAVY_FLOUNDER_DMUB;
+ break;
+ case IP_VERSION(3, 0, 1):
+ fw_name_dmub = FIRMWARE_VANGOGH_DMUB;
+ break;
+ case IP_VERSION(3, 0, 2):
+ fw_name_dmub = FIRMWARE_DIMGREY_CAVEFISH_DMUB;
+ break;
+ case IP_VERSION(3, 0, 3):
+ fw_name_dmub = FIRMWARE_BEIGE_GOBY_DMUB;
+ break;
+ case IP_VERSION(3, 1, 2):
+ case IP_VERSION(3, 1, 3):
+ fw_name_dmub = FIRMWARE_YELLOW_CARP_DMUB;
+ break;
+ case IP_VERSION(3, 1, 4):
+ fw_name_dmub = FIRMWARE_DCN_314_DMUB;
+ break;
+ case IP_VERSION(3, 1, 5):
+ fw_name_dmub = FIRMWARE_DCN_315_DMUB;
+ break;
+ case IP_VERSION(3, 1, 6):
+ fw_name_dmub = FIRMWARE_DCN316_DMUB;
+ break;
+ case IP_VERSION(3, 2, 0):
+ fw_name_dmub = FIRMWARE_DCN_V3_2_0_DMCUB;
+ break;
+ case IP_VERSION(3, 2, 1):
+ fw_name_dmub = FIRMWARE_DCN_V3_2_1_DMCUB;
+ break;
+ default:
+ /* ASIC doesn't support DMUB. */
+ return 0;
+ }
+ r = amdgpu_ucode_request(adev, &adev->dm.dmub_fw, fw_name_dmub);
+ if (r)
+ DRM_ERROR("DMUB firmware loading failed: %d\n", r);
+ return r;
+}
+
static int dm_early_init(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
@@ -4643,8 +4769,6 @@ static int dm_early_init(void *handle)
break;
}
- amdgpu_dm_set_irq_funcs(adev);
-
if (adev->mode_info.funcs == NULL)
adev->mode_info.funcs = &dm_display_funcs;
@@ -4660,7 +4784,7 @@ static int dm_early_init(void *handle)
#endif
adev->dc_enabled = true;
- return 0;
+ return dm_init_microcode(adev);
}
static bool modereset_required(struct drm_crtc_state *crtc_state)
@@ -4725,7 +4849,7 @@ fill_plane_color_attributes(const struct drm_plane_state *plane_state,
static int
fill_dc_plane_info_and_addr(struct amdgpu_device *adev,
const struct drm_plane_state *plane_state,
- const uint64_t tiling_flags,
+ const u64 tiling_flags,
struct dc_plane_info *plane_info,
struct dc_plane_address *address,
bool tmz_surface,
@@ -4900,7 +5024,7 @@ static int fill_dc_plane_attributes(struct amdgpu_device *adev,
static inline void fill_dc_dirty_rect(struct drm_plane *plane,
struct rect *dirty_rect, int32_t x,
- int32_t y, int32_t width, int32_t height,
+ s32 y, s32 width, s32 height,
int *i, bool ffu)
{
if (*i > DC_MAX_DIRTY_RECTS)
@@ -4936,6 +5060,7 @@ out:
* @new_plane_state: New state of @plane
* @crtc_state: New state of CRTC connected to the @plane
* @flip_addrs: DC flip tracking struct, which also tracts dirty rects
+ * @dirty_regions_changed: dirty regions changed
*
* For PSR SU, DC informs the DMUB uController of dirty rectangle regions
* (referred to as "damage clips" in DRM nomenclature) that require updating on
@@ -4952,15 +5077,17 @@ static void fill_dc_dirty_rects(struct drm_plane *plane,
struct drm_plane_state *old_plane_state,
struct drm_plane_state *new_plane_state,
struct drm_crtc_state *crtc_state,
- struct dc_flip_addrs *flip_addrs)
+ struct dc_flip_addrs *flip_addrs,
+ bool *dirty_regions_changed)
{
struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(crtc_state);
struct rect *dirty_rects = flip_addrs->dirty_rects;
- uint32_t num_clips;
+ u32 num_clips;
struct drm_mode_rect *clips;
bool bb_changed;
bool fb_changed;
- uint32_t i = 0;
+ u32 i = 0;
+ *dirty_regions_changed = false;
/*
* Cursor plane has it's own dirty rect update interface. See
@@ -5005,6 +5132,8 @@ static void fill_dc_dirty_rects(struct drm_plane *plane,
new_plane_state->plane->base.id,
bb_changed, fb_changed, num_clips);
+ *dirty_regions_changed = bb_changed;
+
if (bb_changed) {
fill_dc_dirty_rect(new_plane_state->plane, &dirty_rects[i],
new_plane_state->crtc_x,
@@ -5106,7 +5235,7 @@ static enum dc_color_depth
convert_color_depth_from_display_info(const struct drm_connector *connector,
bool is_y420, int requested_bpc)
{
- uint8_t bpc;
+ u8 bpc;
if (is_y420) {
bpc = 8;
@@ -5650,8 +5779,8 @@ static void apply_dsc_policy_for_edp(struct amdgpu_dm_connector *aconnector,
uint32_t max_dsc_target_bpp_limit_override)
{
const struct dc_link_settings *verified_link_cap = NULL;
- uint32_t link_bw_in_kbps;
- uint32_t edp_min_bpp_x16, edp_max_bpp_x16;
+ u32 link_bw_in_kbps;
+ u32 edp_min_bpp_x16, edp_max_bpp_x16;
struct dc *dc = sink->ctx->dc;
struct dc_dsc_bw_range bw_range = {0};
struct dc_dsc_config dsc_cfg = {0};
@@ -5708,11 +5837,11 @@ static void apply_dsc_policy_for_stream(struct amdgpu_dm_connector *aconnector,
struct dsc_dec_dpcd_caps *dsc_caps)
{
struct drm_connector *drm_connector = &aconnector->base;
- uint32_t link_bandwidth_kbps;
+ u32 link_bandwidth_kbps;
struct dc *dc = sink->ctx->dc;
- uint32_t max_supported_bw_in_kbps, timing_bw_in_kbps;
- uint32_t dsc_max_supported_bw_in_kbps;
- uint32_t max_dsc_target_bpp_limit_override =
+ u32 max_supported_bw_in_kbps, timing_bw_in_kbps;
+ u32 dsc_max_supported_bw_in_kbps;
+ u32 max_dsc_target_bpp_limit_override =
drm_connector->display_info.max_dsc_bpp;
link_bandwidth_kbps = dc_link_bandwidth_kbps(aconnector->dc_link,
@@ -5891,6 +6020,14 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
stream, &mode, &aconnector->base, con_state, old_stream,
requested_bpc);
+ if (aconnector->timing_changed) {
+ DC_LOG_DEBUG("%s: overriding timing for automated test, bpc %d, changing to %d\n",
+ __func__,
+ stream->timing.display_color_depth,
+ aconnector->timing_requested->display_color_depth);
+ stream->timing = *aconnector->timing_requested;
+ }
+
#if defined(CONFIG_DRM_AMD_DC_DCN)
/* SST DSC determination policy */
update_dsc_caps(aconnector, sink, stream, &dsc_caps);
@@ -6083,15 +6220,12 @@ static void amdgpu_dm_connector_destroy(struct drm_connector *connector)
if (aconnector->mst_mgr.dev)
drm_dp_mst_topology_mgr_destroy(&aconnector->mst_mgr);
-#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) ||\
- defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)
for (i = 0; i < dm->num_of_edps; i++) {
if ((link == dm->backlight_link[i]) && dm->backlight_dev[i]) {
backlight_device_unregister(dm->backlight_dev[i]);
dm->backlight_dev[i] = NULL;
}
}
-#endif
if (aconnector->dc_em_sink)
dc_sink_release(aconnector->dc_em_sink);
@@ -6285,7 +6419,6 @@ static enum dc_status dm_validate_stream_and_context(struct dc *dc,
dc_plane_state->plane_size.surface_size.width = stream->src.width;
dc_plane_state->plane_size.chroma_size.height = stream->src.height;
dc_plane_state->plane_size.chroma_size.width = stream->src.width;
- dc_plane_state->tiling_info.gfx9.swizzle = DC_SW_UNKNOWN;
dc_plane_state->format = SURFACE_PIXEL_FORMAT_GRPH_ARGB8888;
dc_plane_state->tiling_info.gfx9.swizzle = DC_SW_UNKNOWN;
dc_plane_state->rotation = ROTATION_ANGLE_0;
@@ -6583,11 +6716,11 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder,
int clock, bpp = 0;
bool is_y420 = false;
- if (!aconnector->port || !aconnector->dc_sink)
+ if (!aconnector->mst_output_port || !aconnector->dc_sink)
return 0;
- mst_port = aconnector->port;
- mst_mgr = &aconnector->mst_port->mst_mgr;
+ mst_port = aconnector->mst_output_port;
+ mst_mgr = &aconnector->mst_root->mst_mgr;
if (!crtc_state->connectors_changed && !crtc_state->mode_changed)
return 0;
@@ -6597,7 +6730,7 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder,
return PTR_ERR(mst_state);
if (!mst_state->pbn_div)
- mst_state->pbn_div = dm_mst_get_pbn_divider(aconnector->mst_port->dc_link);
+ mst_state->pbn_div = dm_mst_get_pbn_divider(aconnector->mst_root->dc_link);
if (!state->duplicated) {
int max_bpc = conn_state->max_requested_bpc;
@@ -6643,7 +6776,7 @@ static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_state *state,
aconnector = to_amdgpu_dm_connector(connector);
- if (!aconnector->port)
+ if (!aconnector->mst_output_port)
continue;
if (!new_con_state || !new_con_state->crtc)
@@ -6683,7 +6816,7 @@ static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_state *state,
dm_conn_state->pbn = pbn;
dm_conn_state->vcpi_slots = slot_num;
- ret = drm_dp_mst_atomic_enable_dsc(state, aconnector->port,
+ ret = drm_dp_mst_atomic_enable_dsc(state, aconnector->mst_output_port,
dm_conn_state->pbn, false);
if (ret < 0)
return ret;
@@ -6691,7 +6824,7 @@ static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_state *state,
continue;
}
- vcpi = drm_dp_mst_atomic_enable_dsc(state, aconnector->port, pbn, true);
+ vcpi = drm_dp_mst_atomic_enable_dsc(state, aconnector->mst_output_port, pbn, true);
if (vcpi < 0)
return vcpi;
@@ -6934,7 +7067,7 @@ static uint add_fs_modes(struct amdgpu_dm_connector *aconnector)
const struct drm_display_mode *m;
struct drm_display_mode *new_mode;
uint i;
- uint32_t new_modes_count = 0;
+ u32 new_modes_count = 0;
/* Standard FPS values
*
@@ -6948,7 +7081,7 @@ static uint add_fs_modes(struct amdgpu_dm_connector *aconnector)
* 60 - Commonly used
* 48,72,96,120 - Multiples of 24
*/
- static const uint32_t common_rates[] = {
+ static const u32 common_rates[] = {
23976, 24000, 25000, 29970, 30000,
48000, 50000, 60000, 72000, 96000, 120000
};
@@ -6964,8 +7097,8 @@ static uint add_fs_modes(struct amdgpu_dm_connector *aconnector)
return 0;
for (i = 0; i < ARRAY_SIZE(common_rates); i++) {
- uint64_t target_vtotal, target_vtotal_diff;
- uint64_t num, den;
+ u64 target_vtotal, target_vtotal_diff;
+ u64 num, den;
if (drm_mode_vrefresh(m) * 1000 < common_rates[i])
continue;
@@ -7064,6 +7197,9 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
aconnector->base.dpms = DRM_MODE_DPMS_OFF;
aconnector->hpd.hpd = AMDGPU_HPD_NONE; /* not used */
aconnector->audio_inst = -1;
+ aconnector->pack_sdp_v1_3 = false;
+ aconnector->as_type = ADAPTIVE_SYNC_TYPE_NONE;
+ memset(&aconnector->vsdb_info, 0, sizeof(aconnector->vsdb_info));
mutex_init(&aconnector->hpd_lock);
/*
@@ -7105,11 +7241,11 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
adev->mode_info.underscan_vborder_property,
0);
- if (!aconnector->mst_port)
+ if (!aconnector->mst_root)
drm_connector_attach_max_bpc_property(&aconnector->base, 8, 16);
/* This defaults to the max in the range, but we want 8bpc for non-edp. */
- aconnector->base.state->max_bpc = (connector_type == DRM_MODE_CONNECTOR_eDP) ? 16 : 8;
+ aconnector->base.state->max_bpc = 16;
aconnector->base.state->max_requested_bpc = aconnector->base.state->max_bpc;
if (connector_type == DRM_MODE_CONNECTOR_eDP &&
@@ -7123,7 +7259,7 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
connector_type == DRM_MODE_CONNECTOR_eDP) {
drm_connector_attach_hdr_output_metadata_property(&aconnector->base);
- if (!aconnector->mst_port)
+ if (!aconnector->mst_root)
drm_connector_attach_vrr_capable_property(&aconnector->base);
#ifdef CONFIG_DRM_AMD_DC_HDCP
@@ -7207,7 +7343,7 @@ create_i2c(struct ddc_service *ddc_service,
*/
static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm,
struct amdgpu_dm_connector *aconnector,
- uint32_t link_index,
+ u32 link_index,
struct amdgpu_encoder *aencoder)
{
int res = 0;
@@ -7392,27 +7528,55 @@ is_scaling_state_different(const struct dm_connector_state *dm_state,
}
#ifdef CONFIG_DRM_AMD_DC_HDCP
-static bool is_content_protection_different(struct drm_connector_state *state,
- const struct drm_connector_state *old_state,
- const struct drm_connector *connector, struct hdcp_workqueue *hdcp_w)
+static bool is_content_protection_different(struct drm_crtc_state *new_crtc_state,
+ struct drm_crtc_state *old_crtc_state,
+ struct drm_connector_state *new_conn_state,
+ struct drm_connector_state *old_conn_state,
+ const struct drm_connector *connector,
+ struct hdcp_workqueue *hdcp_w)
{
struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
struct dm_connector_state *dm_con_state = to_dm_connector_state(connector->state);
- /* Handle: Type0/1 change */
- if (old_state->hdcp_content_type != state->hdcp_content_type &&
- state->content_protection != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
- state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+ pr_debug("[HDCP_DM] connector->index: %x connect_status: %x dpms: %x\n",
+ connector->index, connector->status, connector->dpms);
+ pr_debug("[HDCP_DM] state protection old: %x new: %x\n",
+ old_conn_state->content_protection, new_conn_state->content_protection);
+
+ if (old_crtc_state)
+ pr_debug("[HDCP_DM] old crtc en: %x a: %x m: %x a-chg: %x c-chg: %x\n",
+ old_crtc_state->enable,
+ old_crtc_state->active,
+ old_crtc_state->mode_changed,
+ old_crtc_state->active_changed,
+ old_crtc_state->connectors_changed);
+
+ if (new_crtc_state)
+ pr_debug("[HDCP_DM] NEW crtc en: %x a: %x m: %x a-chg: %x c-chg: %x\n",
+ new_crtc_state->enable,
+ new_crtc_state->active,
+ new_crtc_state->mode_changed,
+ new_crtc_state->active_changed,
+ new_crtc_state->connectors_changed);
+
+ /* hdcp content type change */
+ if (old_conn_state->hdcp_content_type != new_conn_state->hdcp_content_type &&
+ new_conn_state->content_protection != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
+ new_conn_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+ pr_debug("[HDCP_DM] Type0/1 change %s :true\n", __func__);
return true;
}
- /* CP is being re enabled, ignore this
- *
- * Handles: ENABLED -> DESIRED
- */
- if (old_state->content_protection == DRM_MODE_CONTENT_PROTECTION_ENABLED &&
- state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED) {
- state->content_protection = DRM_MODE_CONTENT_PROTECTION_ENABLED;
+ /* CP is being re enabled, ignore this */
+ if (old_conn_state->content_protection == DRM_MODE_CONTENT_PROTECTION_ENABLED &&
+ new_conn_state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED) {
+ if (new_crtc_state && new_crtc_state->mode_changed) {
+ new_conn_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+ pr_debug("[HDCP_DM] ENABLED->DESIRED & mode_changed %s :true\n", __func__);
+ return true;
+ }
+ new_conn_state->content_protection = DRM_MODE_CONTENT_PROTECTION_ENABLED;
+ pr_debug("[HDCP_DM] ENABLED -> DESIRED %s :false\n", __func__);
return false;
}
@@ -7420,9 +7584,9 @@ static bool is_content_protection_different(struct drm_connector_state *state,
*
* Handles: UNDESIRED -> ENABLED
*/
- if (old_state->content_protection == DRM_MODE_CONTENT_PROTECTION_UNDESIRED &&
- state->content_protection == DRM_MODE_CONTENT_PROTECTION_ENABLED)
- state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+ if (old_conn_state->content_protection == DRM_MODE_CONTENT_PROTECTION_UNDESIRED &&
+ new_conn_state->content_protection == DRM_MODE_CONTENT_PROTECTION_ENABLED)
+ new_conn_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
/* Stream removed and re-enabled
*
@@ -7432,10 +7596,12 @@ static bool is_content_protection_different(struct drm_connector_state *state,
*
* Handles: DESIRED -> DESIRED (Special case)
*/
- if (!(old_state->crtc && old_state->crtc->enabled) &&
- state->crtc && state->crtc->enabled &&
+ if (!(old_conn_state->crtc && old_conn_state->crtc->enabled) &&
+ new_conn_state->crtc && new_conn_state->crtc->enabled &&
connector->state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED) {
dm_con_state->update_hdcp = false;
+ pr_debug("[HDCP_DM] DESIRED->DESIRED (Stream removed and re-enabled) %s :true\n",
+ __func__);
return true;
}
@@ -7447,35 +7613,42 @@ static bool is_content_protection_different(struct drm_connector_state *state,
*
* Handles: DESIRED -> DESIRED (Special case)
*/
- if (dm_con_state->update_hdcp && state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED &&
- connector->dpms == DRM_MODE_DPMS_ON && aconnector->dc_sink != NULL) {
+ if (dm_con_state->update_hdcp &&
+ new_conn_state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED &&
+ connector->dpms == DRM_MODE_DPMS_ON && aconnector->dc_sink != NULL) {
dm_con_state->update_hdcp = false;
+ pr_debug("[HDCP_DM] DESIRED->DESIRED (Hot-plug, headless s3, dpms) %s :true\n",
+ __func__);
return true;
}
- /*
- * Handles: UNDESIRED -> UNDESIRED
- * DESIRED -> DESIRED
- * ENABLED -> ENABLED
- */
- if (old_state->content_protection == state->content_protection)
+ if (old_conn_state->content_protection == new_conn_state->content_protection) {
+ if (new_conn_state->content_protection >= DRM_MODE_CONTENT_PROTECTION_DESIRED) {
+ if (new_crtc_state && new_crtc_state->mode_changed) {
+ pr_debug("[HDCP_DM] DESIRED->DESIRED or ENABLE->ENABLE mode_change %s :true\n",
+ __func__);
+ return true;
+ }
+ pr_debug("[HDCP_DM] DESIRED->DESIRED & ENABLE->ENABLE %s :false\n",
+ __func__);
+ return false;
+ }
+
+ pr_debug("[HDCP_DM] UNDESIRED->UNDESIRED %s :false\n", __func__);
return false;
+ }
- /*
- * Handles: UNDESIRED -> DESIRED
- * DESIRED -> UNDESIRED
- * ENABLED -> UNDESIRED
- */
- if (state->content_protection != DRM_MODE_CONTENT_PROTECTION_ENABLED)
+ if (new_conn_state->content_protection != DRM_MODE_CONTENT_PROTECTION_ENABLED) {
+ pr_debug("[HDCP_DM] UNDESIRED->DESIRED or DESIRED->UNDESIRED or ENABLED->UNDESIRED %s :true\n",
+ __func__);
return true;
+ }
- /*
- * Handles: DESIRED -> ENABLED
- */
+ pr_debug("[HDCP_DM] DESIRED->ENABLED %s :false\n", __func__);
return false;
}
-
#endif
+
static void remove_stream(struct amdgpu_device *adev,
struct amdgpu_crtc *acrtc,
struct dc_stream_state *stream)
@@ -7517,6 +7690,8 @@ static void update_freesync_state_on_stream(
struct amdgpu_crtc *acrtc = to_amdgpu_crtc(new_crtc_state->base.crtc);
unsigned long flags;
bool pack_sdp_v1_3 = false;
+ struct amdgpu_dm_connector *aconn;
+ enum vrr_packet_type packet_type = PACKET_TYPE_VRR;
if (!new_stream)
return;
@@ -7552,11 +7727,27 @@ static void update_freesync_state_on_stream(
}
}
+ aconn = (struct amdgpu_dm_connector *)new_stream->dm_stream_context;
+
+ if (aconn && aconn->as_type == FREESYNC_TYPE_PCON_IN_WHITELIST) {
+ pack_sdp_v1_3 = aconn->pack_sdp_v1_3;
+
+ if (aconn->vsdb_info.amd_vsdb_version == 1)
+ packet_type = PACKET_TYPE_FS_V1;
+ else if (aconn->vsdb_info.amd_vsdb_version == 2)
+ packet_type = PACKET_TYPE_FS_V2;
+ else if (aconn->vsdb_info.amd_vsdb_version == 3)
+ packet_type = PACKET_TYPE_FS_V3;
+
+ mod_build_adaptive_sync_infopacket(new_stream, aconn->as_type, NULL,
+ &new_stream->adaptive_sync_infopacket);
+ }
+
mod_freesync_build_vrr_infopacket(
dm->freesync_module,
new_stream,
&vrr_params,
- PACKET_TYPE_VRR,
+ packet_type,
TRANSFER_FUNC_UNKNOWN,
&vrr_infopacket,
pack_sdp_v1_3);
@@ -7570,6 +7761,7 @@ static void update_freesync_state_on_stream(
new_crtc_state->vrr_infopacket = vrr_infopacket;
new_stream->vrr_infopacket = vrr_infopacket;
+ new_stream->allow_freesync = mod_freesync_get_freesync_enabled(&vrr_params);
if (new_crtc_state->freesync_vrr_info_changed)
DRM_DEBUG_KMS("VRR packet update: crtc=%u enabled=%d state=%d",
@@ -7691,8 +7883,8 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
struct drm_crtc *pcrtc,
bool wait_for_vblank)
{
- uint32_t i;
- uint64_t timestamp_ns;
+ u32 i;
+ u64 timestamp_ns = ktime_get_ns();
struct drm_plane *plane;
struct drm_plane_state *old_plane_state, *new_plane_state;
struct amdgpu_crtc *acrtc_attach = to_amdgpu_crtc(pcrtc);
@@ -7703,10 +7895,11 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
to_dm_crtc_state(drm_atomic_get_old_crtc_state(state, pcrtc));
int planes_count = 0, vpos, hpos;
unsigned long flags;
- uint32_t target_vblank, last_flip_vblank;
+ u32 target_vblank, last_flip_vblank;
bool vrr_active = amdgpu_dm_vrr_active(acrtc_state);
bool cursor_update = false;
bool pflip_present = false;
+ bool dirty_rects_changed = false;
struct {
struct dc_surface_update surface_updates[MAX_SURFACES];
struct dc_plane_info plane_infos[MAX_SURFACES];
@@ -7794,10 +7987,32 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
bundle->surface_updates[planes_count].plane_info =
&bundle->plane_infos[planes_count];
- if (acrtc_state->stream->link->psr_settings.psr_feature_enabled)
+ if (acrtc_state->stream->link->psr_settings.psr_feature_enabled) {
fill_dc_dirty_rects(plane, old_plane_state,
new_plane_state, new_crtc_state,
- &bundle->flip_addrs[planes_count]);
+ &bundle->flip_addrs[planes_count],
+ &dirty_rects_changed);
+
+ /*
+ * If the dirty regions changed, PSR-SU need to be disabled temporarily
+ * and enabled it again after dirty regions are stable to avoid video glitch.
+ * PSR-SU will be enabled in vblank_control_worker() if user pause the video
+ * during the PSR-SU was disabled.
+ */
+ if (acrtc_state->stream->link->psr_settings.psr_version >= DC_PSR_VERSION_SU_1 &&
+ acrtc_attach->dm_irq_params.allow_psr_entry &&
+#ifdef CONFIG_DRM_AMD_SECURE_DISPLAY
+ !amdgpu_dm_crc_window_is_activated(acrtc_state->base.crtc) &&
+#endif
+ dirty_rects_changed) {
+ mutex_lock(&dm->dc_lock);
+ acrtc_state->stream->link->psr_settings.psr_dirty_rects_change_timestamp_ns =
+ timestamp_ns;
+ if (acrtc_state->stream->link->psr_settings.psr_allow_active)
+ amdgpu_dm_psr_disable(acrtc_state->stream);
+ mutex_unlock(&dm->dc_lock);
+ }
+ }
/*
* Only allow immediate flips for fast updates that don't
@@ -8016,7 +8231,10 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
#ifdef CONFIG_DRM_AMD_SECURE_DISPLAY
!amdgpu_dm_crc_window_is_activated(acrtc_state->base.crtc) &&
#endif
- !acrtc_state->stream->link->psr_settings.psr_allow_active)
+ !acrtc_state->stream->link->psr_settings.psr_allow_active &&
+ (timestamp_ns -
+ acrtc_state->stream->link->psr_settings.psr_dirty_rects_change_timestamp_ns) >
+ 500000000)
amdgpu_dm_psr_enable(acrtc_state->stream);
} else {
acrtc_attach->dm_irq_params.allow_psr_entry = false;
@@ -8141,7 +8359,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
struct amdgpu_display_manager *dm = &adev->dm;
struct dm_atomic_state *dm_state;
struct dc_state *dc_state = NULL, *dc_state_temp = NULL;
- uint32_t i, j;
+ u32 i, j;
struct drm_crtc *crtc;
struct drm_crtc_state *old_crtc_state, *new_crtc_state;
unsigned long flags;
@@ -8315,10 +8533,61 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
struct amdgpu_crtc *acrtc = to_amdgpu_crtc(dm_new_con_state->base.crtc);
struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
+ pr_debug("[HDCP_DM] -------------- i : %x ----------\n", i);
+
+ if (!connector)
+ continue;
+
+ pr_debug("[HDCP_DM] connector->index: %x connect_status: %x dpms: %x\n",
+ connector->index, connector->status, connector->dpms);
+ pr_debug("[HDCP_DM] state protection old: %x new: %x\n",
+ old_con_state->content_protection, new_con_state->content_protection);
+
+ if (aconnector->dc_sink) {
+ if (aconnector->dc_sink->sink_signal != SIGNAL_TYPE_VIRTUAL &&
+ aconnector->dc_sink->sink_signal != SIGNAL_TYPE_NONE) {
+ pr_debug("[HDCP_DM] pipe_ctx dispname=%s\n",
+ aconnector->dc_sink->edid_caps.display_name);
+ }
+ }
+
+ new_crtc_state = NULL;
+ old_crtc_state = NULL;
+
+ if (acrtc) {
+ new_crtc_state = drm_atomic_get_new_crtc_state(state, &acrtc->base);
+ old_crtc_state = drm_atomic_get_old_crtc_state(state, &acrtc->base);
+ }
+
+ if (old_crtc_state)
+ pr_debug("old crtc en: %x a: %x m: %x a-chg: %x c-chg: %x\n",
+ old_crtc_state->enable,
+ old_crtc_state->active,
+ old_crtc_state->mode_changed,
+ old_crtc_state->active_changed,
+ old_crtc_state->connectors_changed);
+
+ if (new_crtc_state)
+ pr_debug("NEW crtc en: %x a: %x m: %x a-chg: %x c-chg: %x\n",
+ new_crtc_state->enable,
+ new_crtc_state->active,
+ new_crtc_state->mode_changed,
+ new_crtc_state->active_changed,
+ new_crtc_state->connectors_changed);
+ }
+
+ for_each_oldnew_connector_in_state(state, connector, old_con_state, new_con_state, i) {
+ struct dm_connector_state *dm_new_con_state = to_dm_connector_state(new_con_state);
+ struct amdgpu_crtc *acrtc = to_amdgpu_crtc(dm_new_con_state->base.crtc);
+ struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
+
new_crtc_state = NULL;
+ old_crtc_state = NULL;
- if (acrtc)
+ if (acrtc) {
new_crtc_state = drm_atomic_get_new_crtc_state(state, &acrtc->base);
+ old_crtc_state = drm_atomic_get_old_crtc_state(state, &acrtc->base);
+ }
dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
@@ -8330,11 +8599,44 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
continue;
}
- if (is_content_protection_different(new_con_state, old_con_state, connector, adev->dm.hdcp_workqueue))
+ if (is_content_protection_different(new_crtc_state, old_crtc_state, new_con_state,
+ old_con_state, connector, adev->dm.hdcp_workqueue)) {
+ /* when display is unplugged from mst hub, connctor will
+ * be destroyed within dm_dp_mst_connector_destroy. connector
+ * hdcp perperties, like type, undesired, desired, enabled,
+ * will be lost. So, save hdcp properties into hdcp_work within
+ * amdgpu_dm_atomic_commit_tail. if the same display is
+ * plugged back with same display index, its hdcp properties
+ * will be retrieved from hdcp_work within dm_dp_mst_get_modes
+ */
+
+ bool enable_encryption = false;
+
+ if (new_con_state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED)
+ enable_encryption = true;
+
+ if (aconnector->dc_link && aconnector->dc_sink &&
+ aconnector->dc_link->type == dc_connection_mst_branch) {
+ struct hdcp_workqueue *hdcp_work = adev->dm.hdcp_workqueue;
+ struct hdcp_workqueue *hdcp_w =
+ &hdcp_work[aconnector->dc_link->link_index];
+
+ hdcp_w->hdcp_content_type[connector->index] =
+ new_con_state->hdcp_content_type;
+ hdcp_w->content_protection[connector->index] =
+ new_con_state->content_protection;
+ }
+
+ if (new_crtc_state && new_crtc_state->mode_changed &&
+ new_con_state->content_protection >= DRM_MODE_CONTENT_PROTECTION_DESIRED)
+ enable_encryption = true;
+
+ DRM_INFO("[HDCP_DM] hdcp_update_display enable_encryption = %x\n", enable_encryption);
+
hdcp_update_display(
adev->dm.hdcp_workqueue, aconnector->dc_link->link_index, aconnector,
- new_con_state->hdcp_content_type,
- new_con_state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED);
+ new_con_state->hdcp_content_type, enable_encryption);
+ }
}
#endif
@@ -8432,9 +8734,6 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
#ifdef CONFIG_DEBUG_FS
enum amdgpu_dm_pipe_crc_source cur_crc_src;
-#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
- struct crc_rd_work *crc_rd_wrk;
-#endif
#endif
/* Count number of newly disabled CRTCs for dropping PM refs later. */
if (old_crtc_state->active && !new_crtc_state->active)
@@ -8447,9 +8746,6 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
update_stream_irq_parameters(dm, dm_new_crtc_state);
#ifdef CONFIG_DEBUG_FS
-#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
- crc_rd_wrk = dm->crc_rd_wrk;
-#endif
spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags);
cur_crc_src = acrtc->dm_irq_params.crc_src;
spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
@@ -8478,10 +8774,12 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
if (amdgpu_dm_crc_window_is_activated(crtc)) {
spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags);
acrtc->dm_irq_params.window_param.update_win = true;
+
+ /**
+ * It takes 2 frames for HW to stably generate CRC when
+ * resuming from suspend, so we set skip_frame_cnt 2.
+ */
acrtc->dm_irq_params.window_param.skip_frame_cnt = 2;
- spin_lock_irq(&crc_rd_wrk->crc_rd_work_lock);
- crc_rd_wrk->crtc = crtc;
- spin_unlock_irq(&crc_rd_wrk->crc_rd_work_lock);
spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
}
#endif
@@ -8772,7 +9070,7 @@ is_timing_unchanged_for_freesync(struct drm_crtc_state *old_crtc_state,
}
static void set_freesync_fixed_config(struct dm_crtc_state *dm_new_crtc_state) {
- uint64_t num, den, res;
+ u64 num, den, res;
struct drm_crtc_state *new_crtc_state = &dm_new_crtc_state->base;
dm_new_crtc_state->freesync_config.state = VRR_STATE_ACTIVE_FIXED;
@@ -9228,7 +9526,8 @@ static int dm_update_plane_state(struct dc *dc,
struct drm_plane_state *old_plane_state,
struct drm_plane_state *new_plane_state,
bool enable,
- bool *lock_and_validation_needed)
+ bool *lock_and_validation_needed,
+ bool *is_top_most_overlay)
{
struct dm_atomic_state *dm_state = NULL;
@@ -9336,6 +9635,14 @@ static int dm_update_plane_state(struct dc *dc,
if (!dc_new_plane_state)
return -ENOMEM;
+ /* Block top most plane from being a video plane */
+ if (plane->type == DRM_PLANE_TYPE_OVERLAY) {
+ if (is_video_format(new_plane_state->fb->format->format) && *is_top_most_overlay)
+ return -EINVAL;
+ else
+ *is_top_most_overlay = false;
+ }
+
DRM_DEBUG_ATOMIC("Enabling DRM plane: %d on DRM crtc %d\n",
plane->base.id, new_plane_crtc->base.id);
@@ -9479,7 +9786,7 @@ static int add_affected_mst_dsc_crtcs(struct drm_atomic_state *state, struct drm
continue;
aconnector = to_amdgpu_dm_connector(connector);
- if (!aconnector->port || !aconnector->mst_port)
+ if (!aconnector->mst_output_port || !aconnector->mst_root)
aconnector = NULL;
else
break;
@@ -9488,7 +9795,7 @@ static int add_affected_mst_dsc_crtcs(struct drm_atomic_state *state, struct drm
if (!aconnector)
return 0;
- return drm_dp_mst_add_affected_dsc_crtcs(state, &aconnector->mst_port->mst_mgr);
+ return drm_dp_mst_add_affected_dsc_crtcs(state, &aconnector->mst_root->mst_mgr);
}
#endif
@@ -9532,6 +9839,7 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
enum dc_status status;
int ret, i;
bool lock_and_validation_needed = false;
+ bool is_top_most_overlay = true;
struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state;
#if defined(CONFIG_DRM_AMD_DC_DCN)
struct drm_dp_mst_topology_mgr *mgr;
@@ -9670,7 +9978,8 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
old_plane_state,
new_plane_state,
false,
- &lock_and_validation_needed);
+ &lock_and_validation_needed,
+ &is_top_most_overlay);
if (ret) {
DRM_DEBUG_DRIVER("dm_update_plane_state() failed\n");
goto fail;
@@ -9709,7 +10018,8 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
old_plane_state,
new_plane_state,
true,
- &lock_and_validation_needed);
+ &lock_and_validation_needed,
+ &is_top_most_overlay);
if (ret) {
DRM_DEBUG_DRIVER("dm_update_plane_state() failed\n");
goto fail;
@@ -9944,7 +10254,7 @@ fail:
static bool is_dp_capable_without_timing_msa(struct dc *dc,
struct amdgpu_dm_connector *amdgpu_dm_connector)
{
- uint8_t dpcd_data;
+ u8 dpcd_data;
bool capable = false;
if (amdgpu_dm_connector->dc_link &&
@@ -9963,7 +10273,7 @@ static bool is_dp_capable_without_timing_msa(struct dc *dc,
static bool dm_edid_parser_send_cea(struct amdgpu_display_manager *dm,
unsigned int offset,
unsigned int total_length,
- uint8_t *data,
+ u8 *data,
unsigned int length,
struct amdgpu_hdmi_vsdb_info *vsdb)
{
@@ -10018,7 +10328,7 @@ static bool dm_edid_parser_send_cea(struct amdgpu_display_manager *dm,
}
static bool parse_edid_cea_dmcu(struct amdgpu_display_manager *dm,
- uint8_t *edid_ext, int len,
+ u8 *edid_ext, int len,
struct amdgpu_hdmi_vsdb_info *vsdb_info)
{
int i;
@@ -10059,7 +10369,7 @@ static bool parse_edid_cea_dmcu(struct amdgpu_display_manager *dm,
}
static bool parse_edid_cea_dmub(struct amdgpu_display_manager *dm,
- uint8_t *edid_ext, int len,
+ u8 *edid_ext, int len,
struct amdgpu_hdmi_vsdb_info *vsdb_info)
{
int i;
@@ -10075,21 +10385,25 @@ static bool parse_edid_cea_dmub(struct amdgpu_display_manager *dm,
}
static bool parse_edid_cea(struct amdgpu_dm_connector *aconnector,
- uint8_t *edid_ext, int len,
+ u8 *edid_ext, int len,
struct amdgpu_hdmi_vsdb_info *vsdb_info)
{
struct amdgpu_device *adev = drm_to_adev(aconnector->base.dev);
+ bool ret;
+ mutex_lock(&adev->dm.dc_lock);
if (adev->dm.dmub_srv)
- return parse_edid_cea_dmub(&adev->dm, edid_ext, len, vsdb_info);
+ ret = parse_edid_cea_dmub(&adev->dm, edid_ext, len, vsdb_info);
else
- return parse_edid_cea_dmcu(&adev->dm, edid_ext, len, vsdb_info);
+ ret = parse_edid_cea_dmcu(&adev->dm, edid_ext, len, vsdb_info);
+ mutex_unlock(&adev->dm.dc_lock);
+ return ret;
}
static int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector,
struct edid *edid, struct amdgpu_hdmi_vsdb_info *vsdb_info)
{
- uint8_t *edid_ext = NULL;
+ u8 *edid_ext = NULL;
int i;
bool valid_vsdb_found = false;
@@ -10144,6 +10458,7 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
struct amdgpu_device *adev = drm_to_adev(dev);
struct amdgpu_hdmi_vsdb_info vsdb_info = {0};
bool freesync_capable = false;
+ enum adaptive_sync_type as_type = ADAPTIVE_SYNC_TYPE_NONE;
if (!connector->state) {
DRM_ERROR("%s - Connector has no state", __func__);
@@ -10236,6 +10551,26 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
}
}
+ as_type = dm_get_adaptive_sync_support_type(amdgpu_dm_connector->dc_link);
+
+ if (as_type == FREESYNC_TYPE_PCON_IN_WHITELIST) {
+ i = parse_hdmi_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info);
+ if (i >= 0 && vsdb_info.freesync_supported && vsdb_info.amd_vsdb_version > 0) {
+
+ amdgpu_dm_connector->pack_sdp_v1_3 = true;
+ amdgpu_dm_connector->as_type = as_type;
+ amdgpu_dm_connector->vsdb_info = vsdb_info;
+
+ amdgpu_dm_connector->min_vfreq = vsdb_info.min_refresh_rate_hz;
+ amdgpu_dm_connector->max_vfreq = vsdb_info.max_refresh_rate_hz;
+ if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10)
+ freesync_capable = true;
+
+ connector->display_info.monitor_range.min_vfreq = vsdb_info.min_refresh_rate_hz;
+ connector->display_info.monitor_range.max_vfreq = vsdb_info.max_refresh_rate_hz;
+ }
+ }
+
update:
if (dm_con_state)
dm_con_state->freesync_capable = freesync_capable;
@@ -10265,7 +10600,7 @@ void amdgpu_dm_trigger_timing_sync(struct drm_device *dev)
}
void dm_write_reg_func(const struct dc_context *ctx, uint32_t address,
- uint32_t value, const char *func_name)
+ u32 value, const char *func_name)
{
#ifdef DM_CHECK_ADDR_0
if (address == 0) {
@@ -10280,7 +10615,7 @@ void dm_write_reg_func(const struct dc_context *ctx, uint32_t address,
uint32_t dm_read_reg_func(const struct dc_context *ctx, uint32_t address,
const char *func_name)
{
- uint32_t value;
+ u32 value;
#ifdef DM_CHECK_ADDR_0
if (address == 0) {
DC_ERR("invalid register read; address = 0\n");
@@ -10359,6 +10694,7 @@ int amdgpu_dm_process_dmub_aux_transfer_sync(
ret = p_notify->aux_reply.length;
*operation_result = p_notify->result;
out:
+ reinit_completion(&adev->dm.dmub_aux_transfer_done);
mutex_unlock(&adev->dm.dpia_aux_lock);
return ret;
}
@@ -10386,6 +10722,8 @@ int amdgpu_dm_process_dmub_set_config_sync(
*operation_result = SET_CONFIG_UNKNOWN_ERROR;
}
+ if (!is_cmd_complete)
+ reinit_completion(&adev->dm.dmub_aux_transfer_done);
mutex_unlock(&adev->dm.dpia_aux_lock);
return ret;
}
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index df3c25e32c65..ed5cbe9da40c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -31,6 +31,7 @@
#include <drm/drm_connector.h>
#include <drm/drm_crtc.h>
#include <drm/drm_plane.h>
+#include "link_service_types.h"
/*
* This file contains the definition for amdgpu_display_manager
@@ -58,6 +59,7 @@
#include "irq_types.h"
#include "signal_types.h"
#include "amdgpu_dm_crc.h"
+#include "mod_info_packet.h"
struct aux_payload;
struct set_config_cmd_payload;
enum aux_return_code_type;
@@ -494,11 +496,12 @@ struct amdgpu_display_manager {
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
/**
- * @crc_rd_wrk:
+ * @secure_display_ctxs:
*
- * Work to be executed in a separate thread to communicate with PSP.
+ * Store the ROI information and the work_struct to command dmub and psp for
+ * all crtcs.
*/
- struct crc_rd_work *crc_rd_wrk;
+ struct secure_display_context *secure_display_ctxs;
#endif
/**
* @hpd_rx_offload_wq:
@@ -575,6 +578,36 @@ enum mst_progress_status {
MST_CLEAR_ALLOCATED_PAYLOAD = BIT(3),
};
+/**
+ * struct amdgpu_hdmi_vsdb_info - Keep track of the VSDB info
+ *
+ * AMDGPU supports FreeSync over HDMI by using the VSDB section, and this
+ * struct is useful to keep track of the display-specific information about
+ * FreeSync.
+ */
+struct amdgpu_hdmi_vsdb_info {
+ /**
+ * @amd_vsdb_version: Vendor Specific Data Block Version, should be
+ * used to determine which Vendor Specific InfoFrame (VSIF) to send.
+ */
+ unsigned int amd_vsdb_version;
+
+ /**
+ * @freesync_supported: FreeSync Supported.
+ */
+ bool freesync_supported;
+
+ /**
+ * @min_refresh_rate_hz: FreeSync Minimum Refresh Rate in Hz.
+ */
+ unsigned int min_refresh_rate_hz;
+
+ /**
+ * @max_refresh_rate_hz: FreeSync Maximum Refresh Rate in Hz
+ */
+ unsigned int max_refresh_rate_hz;
+};
+
struct amdgpu_dm_connector {
struct drm_connector base;
@@ -603,8 +636,8 @@ struct amdgpu_dm_connector {
/* DM only */
struct drm_dp_mst_topology_mgr mst_mgr;
struct amdgpu_dm_dp_aux dm_dp_aux;
- struct drm_dp_mst_port *port;
- struct amdgpu_dm_connector *mst_port;
+ struct drm_dp_mst_port *mst_output_port;
+ struct amdgpu_dm_connector *mst_root;
struct drm_dp_aux *dsc_aux;
/* TODO see if we can merge with ddc_bus or make a dm_connector */
struct amdgpu_i2c_adapter *i2c;
@@ -643,6 +676,15 @@ struct amdgpu_dm_connector {
/* Record progress status of mst*/
uint8_t mst_status;
+
+ /* Automated testing */
+ bool timing_changed;
+ struct dc_crtc_timing *timing_requested;
+
+ /* Adaptive Sync */
+ bool pack_sdp_v1_3;
+ enum adaptive_sync_type as_type;
+ struct amdgpu_hdmi_vsdb_info vsdb_info;
};
static inline void amdgpu_dm_set_mst_status(uint8_t *status,
@@ -713,37 +755,6 @@ struct dm_connector_state {
uint64_t pbn;
};
-/**
- * struct amdgpu_hdmi_vsdb_info - Keep track of the VSDB info
- *
- * AMDGPU supports FreeSync over HDMI by using the VSDB section, and this
- * struct is useful to keep track of the display-specific information about
- * FreeSync.
- */
-struct amdgpu_hdmi_vsdb_info {
- /**
- * @amd_vsdb_version: Vendor Specific Data Block Version, should be
- * used to determine which Vendor Specific InfoFrame (VSIF) to send.
- */
- unsigned int amd_vsdb_version;
-
- /**
- * @freesync_supported: FreeSync Supported.
- */
- bool freesync_supported;
-
- /**
- * @min_refresh_rate_hz: FreeSync Minimum Refresh Rate in Hz.
- */
- unsigned int min_refresh_rate_hz;
-
- /**
- * @max_refresh_rate_hz: FreeSync Maximum Refresh Rate in Hz
- */
- unsigned int max_refresh_rate_hz;
-};
-
-
#define to_dm_connector_state(x)\
container_of((x), struct dm_connector_state, base)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
index 66df2394d7e4..27711743c22c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
@@ -101,35 +101,44 @@ static void amdgpu_dm_set_crc_window_default(struct drm_crtc *crtc)
static void amdgpu_dm_crtc_notify_ta_to_read(struct work_struct *work)
{
- struct crc_rd_work *crc_rd_wrk;
- struct amdgpu_device *adev;
+ struct secure_display_context *secure_display_ctx;
struct psp_context *psp;
- struct securedisplay_cmd *securedisplay_cmd;
+ struct ta_securedisplay_cmd *securedisplay_cmd;
struct drm_crtc *crtc;
- uint8_t phy_id;
+ struct dc_stream_state *stream;
+ uint8_t phy_inst;
int ret;
- crc_rd_wrk = container_of(work, struct crc_rd_work, notify_ta_work);
- spin_lock_irq(&crc_rd_wrk->crc_rd_work_lock);
- crtc = crc_rd_wrk->crtc;
+ secure_display_ctx = container_of(work, struct secure_display_context, notify_ta_work);
+ crtc = secure_display_ctx->crtc;
if (!crtc) {
- spin_unlock_irq(&crc_rd_wrk->crc_rd_work_lock);
return;
}
- adev = drm_to_adev(crtc->dev);
- psp = &adev->psp;
- phy_id = crc_rd_wrk->phy_inst;
- spin_unlock_irq(&crc_rd_wrk->crc_rd_work_lock);
+ psp = &drm_to_adev(crtc->dev)->psp;
+
+ if (!psp->securedisplay_context.context.initialized) {
+ DRM_DEBUG_DRIVER("Secure Display fails to notify PSP TA\n");
+ return;
+ }
+
+ stream = to_amdgpu_crtc(crtc)->dm_irq_params.stream;
+ phy_inst = stream->link->link_enc_hw_inst;
+ /* need lock for multiple crtcs to use the command buffer */
mutex_lock(&psp->securedisplay_context.mutex);
psp_prep_securedisplay_cmd_buf(psp, &securedisplay_cmd,
TA_SECUREDISPLAY_COMMAND__SEND_ROI_CRC);
- securedisplay_cmd->securedisplay_in_message.send_roi_crc.phy_id =
- phy_id;
+
+ securedisplay_cmd->securedisplay_in_message.send_roi_crc.phy_id = phy_inst;
+
+ /* PSP TA is expected to finish data transmission over I2C within current frame,
+ * even there are up to 4 crtcs request to send in this frame.
+ */
ret = psp_securedisplay_invoke(psp, TA_SECUREDISPLAY_COMMAND__SEND_ROI_CRC);
+
if (!ret) {
if (securedisplay_cmd->status != TA_SECUREDISPLAY_STATUS__SUCCESS) {
psp_securedisplay_parse_resp_status(psp, securedisplay_cmd->status);
@@ -142,17 +151,23 @@ static void amdgpu_dm_crtc_notify_ta_to_read(struct work_struct *work)
static void
amdgpu_dm_forward_crc_window(struct work_struct *work)
{
- struct crc_fw_work *crc_fw_wrk;
+ struct secure_display_context *secure_display_ctx;
struct amdgpu_display_manager *dm;
+ struct drm_crtc *crtc;
+ struct dc_stream_state *stream;
- crc_fw_wrk = container_of(work, struct crc_fw_work, forward_roi_work);
- dm = crc_fw_wrk->dm;
+ secure_display_ctx = container_of(work, struct secure_display_context, forward_roi_work);
+ crtc = secure_display_ctx->crtc;
+
+ if (!crtc)
+ return;
+
+ dm = &drm_to_adev(crtc->dev)->dm;
+ stream = to_amdgpu_crtc(crtc)->dm_irq_params.stream;
mutex_lock(&dm->dc_lock);
- dc_stream_forward_crc_window(dm->dc, &crc_fw_wrk->rect, crc_fw_wrk->stream, crc_fw_wrk->is_stop_cmd);
+ dc_stream_forward_crc_window(stream, &secure_display_ctx->rect, false);
mutex_unlock(&dm->dc_lock);
-
- kfree(crc_fw_wrk);
}
bool amdgpu_dm_crc_window_is_activated(struct drm_crtc *crtc)
@@ -189,6 +204,9 @@ int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc,
struct dm_crtc_state *dm_crtc_state,
enum amdgpu_dm_pipe_crc_source source)
{
+#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
+ int i;
+#endif
struct amdgpu_device *adev = drm_to_adev(crtc->dev);
struct dc_stream_state *stream_state = dm_crtc_state->stream;
bool enable = amdgpu_dm_is_valid_crc_source(source);
@@ -200,21 +218,18 @@ int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc,
mutex_lock(&adev->dm.dc_lock);
- /* Enable CRTC CRC generation if necessary. */
+ /* Enable or disable CRTC CRC generation */
if (dm_is_crc_source_crtc(source) || source == AMDGPU_DM_PIPE_CRC_SOURCE_NONE) {
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
+ /* Disable secure_display if it was enabled */
if (!enable) {
- if (adev->dm.crc_rd_wrk) {
- flush_work(&adev->dm.crc_rd_wrk->notify_ta_work);
- spin_lock_irq(&adev->dm.crc_rd_wrk->crc_rd_work_lock);
-
- if (adev->dm.crc_rd_wrk->crtc == crtc) {
+ for (i = 0; i < adev->mode_info.num_crtc; i++) {
+ if (adev->dm.secure_display_ctxs[i].crtc == crtc) {
/* stop ROI update on this crtc */
- dc_stream_forward_crc_window(stream_state->ctx->dc,
- NULL, stream_state, true);
- adev->dm.crc_rd_wrk->crtc = NULL;
+ flush_work(&adev->dm.secure_display_ctxs[i].notify_ta_work);
+ flush_work(&adev->dm.secure_display_ctxs[i].forward_roi_work);
+ dc_stream_forward_crc_window(stream_state, NULL, true);
}
- spin_unlock_irq(&adev->dm.crc_rd_wrk->crc_rd_work_lock);
}
}
#endif
@@ -329,7 +344,7 @@ int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name)
goto cleanup;
}
- aux = (aconn->port) ? &aconn->port->aux : &aconn->dm_dp_aux.aux;
+ aux = (aconn->mst_output_port) ? &aconn->mst_output_port->aux : &aconn->dm_dp_aux.aux;
if (!aux) {
DRM_DEBUG_DRIVER("No dp aux for amd connector\n");
@@ -347,6 +362,7 @@ int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name)
}
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
+ /* Reset secure_display when we change crc source from debugfs */
amdgpu_dm_set_crc_window_default(crtc);
#endif
@@ -456,14 +472,12 @@ void amdgpu_dm_crtc_handle_crc_irq(struct drm_crtc *crtc)
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
void amdgpu_dm_crtc_handle_crc_window_irq(struct drm_crtc *crtc)
{
- struct dc_stream_state *stream_state;
struct drm_device *drm_dev = NULL;
enum amdgpu_dm_pipe_crc_source cur_crc_src;
struct amdgpu_crtc *acrtc = NULL;
struct amdgpu_device *adev = NULL;
- struct crc_rd_work *crc_rd_wrk;
- struct crc_fw_work *crc_fw_wrk;
- unsigned long flags1, flags2;
+ struct secure_display_context *secure_display_ctx = NULL;
+ unsigned long flags1;
if (crtc == NULL)
return;
@@ -473,75 +487,76 @@ void amdgpu_dm_crtc_handle_crc_window_irq(struct drm_crtc *crtc)
drm_dev = crtc->dev;
spin_lock_irqsave(&drm_dev->event_lock, flags1);
- stream_state = acrtc->dm_irq_params.stream;
cur_crc_src = acrtc->dm_irq_params.crc_src;
/* Early return if CRC capture is not enabled. */
- if (!amdgpu_dm_is_valid_crc_source(cur_crc_src))
+ if (!amdgpu_dm_is_valid_crc_source(cur_crc_src) ||
+ !dm_is_crc_source_crtc(cur_crc_src))
goto cleanup;
- if (!dm_is_crc_source_crtc(cur_crc_src))
+ if (!acrtc->dm_irq_params.window_param.activated)
goto cleanup;
- if (!acrtc->dm_irq_params.window_param.activated)
+ if (acrtc->dm_irq_params.window_param.skip_frame_cnt) {
+ acrtc->dm_irq_params.window_param.skip_frame_cnt -= 1;
goto cleanup;
+ }
- if (acrtc->dm_irq_params.window_param.update_win) {
- if (acrtc->dm_irq_params.window_param.skip_frame_cnt) {
- acrtc->dm_irq_params.window_param.skip_frame_cnt -= 1;
- goto cleanup;
- }
+ secure_display_ctx = &adev->dm.secure_display_ctxs[acrtc->crtc_id];
+ if (WARN_ON(secure_display_ctx->crtc != crtc)) {
+ /* We have set the crtc when creating secure_display_context,
+ * don't expect it to be changed here.
+ */
+ secure_display_ctx->crtc = crtc;
+ }
+ if (acrtc->dm_irq_params.window_param.update_win) {
/* prepare work for dmub to update ROI */
- crc_fw_wrk = kzalloc(sizeof(*crc_fw_wrk), GFP_ATOMIC);
- if (!crc_fw_wrk)
- goto cleanup;
-
- INIT_WORK(&crc_fw_wrk->forward_roi_work, amdgpu_dm_forward_crc_window);
- crc_fw_wrk->dm = &adev->dm;
- crc_fw_wrk->stream = stream_state;
- crc_fw_wrk->rect.x = acrtc->dm_irq_params.window_param.x_start;
- crc_fw_wrk->rect.y = acrtc->dm_irq_params.window_param.y_start;
- crc_fw_wrk->rect.width = acrtc->dm_irq_params.window_param.x_end -
+ secure_display_ctx->rect.x = acrtc->dm_irq_params.window_param.x_start;
+ secure_display_ctx->rect.y = acrtc->dm_irq_params.window_param.y_start;
+ secure_display_ctx->rect.width = acrtc->dm_irq_params.window_param.x_end -
acrtc->dm_irq_params.window_param.x_start;
- crc_fw_wrk->rect.height = acrtc->dm_irq_params.window_param.y_end -
+ secure_display_ctx->rect.height = acrtc->dm_irq_params.window_param.y_end -
acrtc->dm_irq_params.window_param.y_start;
- schedule_work(&crc_fw_wrk->forward_roi_work);
+ schedule_work(&secure_display_ctx->forward_roi_work);
acrtc->dm_irq_params.window_param.update_win = false;
+
+ /* Statically skip 1 frame, because we may need to wait below things
+ * before sending ROI to dmub:
+ * 1. We defer the work by using system workqueue.
+ * 2. We may need to wait for dc_lock before accessing dmub.
+ */
acrtc->dm_irq_params.window_param.skip_frame_cnt = 1;
} else {
- if (acrtc->dm_irq_params.window_param.skip_frame_cnt) {
- acrtc->dm_irq_params.window_param.skip_frame_cnt -= 1;
- goto cleanup;
- }
-
- if (adev->dm.crc_rd_wrk) {
- crc_rd_wrk = adev->dm.crc_rd_wrk;
- spin_lock_irqsave(&crc_rd_wrk->crc_rd_work_lock, flags2);
- crc_rd_wrk->phy_inst = stream_state->link->link_enc_hw_inst;
- spin_unlock_irqrestore(&crc_rd_wrk->crc_rd_work_lock, flags2);
- schedule_work(&crc_rd_wrk->notify_ta_work);
- }
+ /* prepare work for psp to read ROI/CRC and send to I2C */
+ schedule_work(&secure_display_ctx->notify_ta_work);
}
cleanup:
spin_unlock_irqrestore(&drm_dev->event_lock, flags1);
}
-struct crc_rd_work *amdgpu_dm_crtc_secure_display_create_work(void)
+struct secure_display_context *
+amdgpu_dm_crtc_secure_display_create_contexts(struct amdgpu_device *adev)
{
- struct crc_rd_work *crc_rd_wrk = NULL;
+ struct secure_display_context *secure_display_ctxs = NULL;
+ int i;
- crc_rd_wrk = kzalloc(sizeof(*crc_rd_wrk), GFP_KERNEL);
+ secure_display_ctxs = kcalloc(adev->mode_info.num_crtc,
+ sizeof(struct secure_display_context),
+ GFP_KERNEL);
- if (!crc_rd_wrk)
+ if (!secure_display_ctxs)
return NULL;
- spin_lock_init(&crc_rd_wrk->crc_rd_work_lock);
- INIT_WORK(&crc_rd_wrk->notify_ta_work, amdgpu_dm_crtc_notify_ta_to_read);
+ for (i = 0; i < adev->mode_info.num_crtc; i++) {
+ INIT_WORK(&secure_display_ctxs[i].forward_roi_work, amdgpu_dm_forward_crc_window);
+ INIT_WORK(&secure_display_ctxs[i].notify_ta_work, amdgpu_dm_crtc_notify_ta_to_read);
+ secure_display_ctxs[i].crtc = &adev->mode_info.crtcs[i]->base;
+ }
- return crc_rd_wrk;
+ return secure_display_ctxs;
}
#endif
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h
index 71bce608d751..935adca6f048 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h
@@ -45,7 +45,7 @@ struct crc_window_param {
uint16_t y_start;
uint16_t x_end;
uint16_t y_end;
- /* CRC windwo is activated or not*/
+ /* CRC window is activated or not*/
bool activated;
/* Update crc window during vertical blank or not */
bool update_win;
@@ -53,22 +53,17 @@ struct crc_window_param {
int skip_frame_cnt;
};
-/* read_work for driver to call PSP to read */
-struct crc_rd_work {
+struct secure_display_context {
+ /* work to notify PSP TA*/
struct work_struct notify_ta_work;
- /* To protect crc_rd_work carried fields*/
- spinlock_t crc_rd_work_lock;
- struct drm_crtc *crtc;
- uint8_t phy_inst;
-};
-/* forward_work for driver to forward ROI to dmu */
-struct crc_fw_work {
+ /* work to forward ROI to dmcu/dmub */
struct work_struct forward_roi_work;
- struct amdgpu_display_manager *dm;
- struct dc_stream_state *stream;
+
+ struct drm_crtc *crtc;
+
+ /* Region of Interest (ROI) */
struct rect rect;
- bool is_stop_cmd;
};
#endif
@@ -100,11 +95,12 @@ void amdgpu_dm_crtc_handle_crc_irq(struct drm_crtc *crtc);
#ifdef CONFIG_DRM_AMD_SECURE_DISPLAY
bool amdgpu_dm_crc_window_is_activated(struct drm_crtc *crtc);
void amdgpu_dm_crtc_handle_crc_window_irq(struct drm_crtc *crtc);
-struct crc_rd_work *amdgpu_dm_crtc_secure_display_create_work(void);
+struct secure_display_context *amdgpu_dm_crtc_secure_display_create_contexts(
+ struct amdgpu_device *adev);
#else
#define amdgpu_dm_crc_window_is_activated(x)
#define amdgpu_dm_crtc_handle_crc_window_irq(x)
-#define amdgpu_dm_crtc_secure_display_create_work()
+#define amdgpu_dm_crtc_secure_display_create_contexts()
#endif
#endif /* AMD_DAL_DEV_AMDGPU_DM_AMDGPU_DM_CRC_H_ */
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
index 22125daf9dcf..dc4f37240beb 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
@@ -77,6 +77,9 @@ int dm_set_vupdate_irq(struct drm_crtc *crtc, bool enable)
struct amdgpu_device *adev = drm_to_adev(crtc->dev);
int rc;
+ if (acrtc->otg_inst == -1)
+ return 0;
+
irq_source = IRQ_TYPE_VUPDATE + acrtc->otg_inst;
rc = dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY;
@@ -105,8 +108,7 @@ static void vblank_control_worker(struct work_struct *work)
else if (dm->active_vblank_irq_count)
dm->active_vblank_irq_count--;
- dc_allow_idle_optimizations(
- dm->dc, dm->active_vblank_irq_count == 0 ? true : false);
+ dc_allow_idle_optimizations(dm->dc, dm->active_vblank_irq_count == 0);
DRM_DEBUG_KMS("Allow idle optimizations (MALL): %d\n", dm->active_vblank_irq_count == 0);
@@ -152,6 +154,9 @@ static inline int dm_set_vblank(struct drm_crtc *crtc, bool enable)
struct vblank_control_work *work;
int rc = 0;
+ if (acrtc->otg_inst == -1)
+ goto skip;
+
if (enable) {
/* vblank irq on -> Only need vupdate irq in vrr mode */
if (amdgpu_dm_vrr_active(acrtc_state))
@@ -169,6 +174,7 @@ static inline int dm_set_vblank(struct drm_crtc *crtc, bool enable)
if (!dc_interrupt_set(adev->dm.dc, irq_source, enable))
return -EBUSY;
+skip:
if (amdgpu_in_reset(adev))
return 0;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
index 461037a3dd75..09a3efa517da 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
@@ -34,9 +34,9 @@
#include "dmub/dmub_srv.h"
#include "resource.h"
#include "dsc.h"
-#include "dc_link_dp.h"
#include "link_hwss.h"
#include "dc/dc_dmub_srv.h"
+#include "link/protocols/link_dp_capability.h"
#ifdef CONFIG_DRM_AMD_SECURE_DISPLAY
#include "amdgpu_dm_psr.h"
@@ -419,67 +419,38 @@ static ssize_t dp_phy_settings_read(struct file *f, char __user *buf,
return result;
}
-static int dp_lttpr_status_show(struct seq_file *m, void *d)
+static int dp_lttpr_status_show(struct seq_file *m, void *unused)
{
- char *data;
- struct amdgpu_dm_connector *connector = file_inode(m->file)->i_private;
- struct dc_link *link = connector->dc_link;
- uint32_t read_size = 1;
- uint8_t repeater_count = 0;
+ struct drm_connector *connector = m->private;
+ struct amdgpu_dm_connector *aconnector =
+ to_amdgpu_dm_connector(connector);
+ struct dc_lttpr_caps caps = aconnector->dc_link->dpcd_caps.lttpr_caps;
- data = kzalloc(read_size, GFP_KERNEL);
- if (!data)
- return 0;
+ if (connector->status != connector_status_connected)
+ return -ENODEV;
- dm_helpers_dp_read_dpcd(link->ctx, link, 0xF0002, data, read_size);
+ seq_printf(m, "phy repeater count: %u (raw: 0x%x)\n",
+ dp_parse_lttpr_repeater_count(caps.phy_repeater_cnt),
+ caps.phy_repeater_cnt);
- switch ((uint8_t)*data) {
- case 0x80:
- repeater_count = 1;
- break;
- case 0x40:
- repeater_count = 2;
- break;
- case 0x20:
- repeater_count = 3;
- break;
- case 0x10:
- repeater_count = 4;
- break;
- case 0x8:
- repeater_count = 5;
- break;
- case 0x4:
- repeater_count = 6;
- break;
- case 0x2:
- repeater_count = 7;
+ seq_puts(m, "phy repeater mode: ");
+
+ switch (caps.mode) {
+ case DP_PHY_REPEATER_MODE_TRANSPARENT:
+ seq_puts(m, "transparent");
break;
- case 0x1:
- repeater_count = 8;
+ case DP_PHY_REPEATER_MODE_NON_TRANSPARENT:
+ seq_puts(m, "non-transparent");
break;
- case 0x0:
- repeater_count = 0;
+ case 0x00:
+ seq_puts(m, "non lttpr");
break;
default:
- repeater_count = (uint8_t)*data;
+ seq_printf(m, "read error (raw: 0x%x)", caps.mode);
break;
}
- seq_printf(m, "phy repeater count: %d\n", repeater_count);
-
- dm_helpers_dp_read_dpcd(link->ctx, link, 0xF0003, data, read_size);
-
- if ((uint8_t)*data == 0x55)
- seq_printf(m, "phy repeater mode: transparent\n");
- else if ((uint8_t)*data == 0xAA)
- seq_printf(m, "phy repeater mode: non-transparent\n");
- else if ((uint8_t)*data == 0x00)
- seq_printf(m, "phy repeater mode: non lttpr\n");
- else
- seq_printf(m, "phy repeater mode: read error\n");
-
- kfree(data);
+ seq_puts(m, "\n");
return 0;
}
@@ -1192,7 +1163,7 @@ static int dp_dsc_fec_support_show(struct seq_file *m, void *data)
break;
}
dpcd_caps = aconnector->dc_link->dpcd_caps;
- if (aconnector->port) {
+ if (aconnector->mst_output_port) {
/* aconnector sets dsc_aux during get_modes call
* if MST connector has it means it can either
* enable DSC on the sink device or on MST branch
@@ -1279,14 +1250,14 @@ static ssize_t trigger_hotplug(struct file *f, const char __user *buf,
mutex_lock(&aconnector->hpd_lock);
/* Don't support for mst end device*/
- if (aconnector->mst_port) {
+ if (aconnector->mst_root) {
mutex_unlock(&aconnector->hpd_lock);
return -EINVAL;
}
if (param[0] == 1) {
- if (!dc_link_detect_sink(aconnector->dc_link, &new_connection_type) &&
+ if (!dc_link_detect_connection_type(aconnector->dc_link, &new_connection_type) &&
new_connection_type != dc_connection_none)
goto unlock;
@@ -1323,7 +1294,7 @@ static ssize_t trigger_hotplug(struct file *f, const char __user *buf,
/* If the aconnector is the root node in mst topology */
if (aconnector->mst_mgr.mst_state == true)
- reset_cur_dp_mst_topology(link);
+ dc_link_reset_cur_dp_mst_topology(link);
drm_modeset_lock_all(dev);
dm_restore_drm_connector_state(dev, connector);
@@ -1375,16 +1346,11 @@ static ssize_t dp_dsc_clock_en_read(struct file *f, char __user *buf,
for (i = 0; i < MAX_PIPES; i++) {
pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i];
- if (pipe_ctx && pipe_ctx->stream &&
+ if (pipe_ctx->stream &&
pipe_ctx->stream->link == aconnector->dc_link)
break;
}
- if (!pipe_ctx) {
- kfree(rd_buf);
- return -ENXIO;
- }
-
dsc = pipe_ctx->stream_res.dsc;
if (dsc)
dsc->funcs->dsc_read_state(dsc, &dsc_state);
@@ -1481,12 +1447,12 @@ static ssize_t dp_dsc_clock_en_write(struct file *f, const char __user *buf,
for (i = 0; i < MAX_PIPES; i++) {
pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i];
- if (pipe_ctx && pipe_ctx->stream &&
+ if (pipe_ctx->stream &&
pipe_ctx->stream->link == aconnector->dc_link)
break;
}
- if (!pipe_ctx || !pipe_ctx->stream)
+ if (!pipe_ctx->stream)
goto done;
// Get CRTC state
@@ -1566,16 +1532,11 @@ static ssize_t dp_dsc_slice_width_read(struct file *f, char __user *buf,
for (i = 0; i < MAX_PIPES; i++) {
pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i];
- if (pipe_ctx && pipe_ctx->stream &&
+ if (pipe_ctx->stream &&
pipe_ctx->stream->link == aconnector->dc_link)
break;
}
- if (!pipe_ctx) {
- kfree(rd_buf);
- return -ENXIO;
- }
-
dsc = pipe_ctx->stream_res.dsc;
if (dsc)
dsc->funcs->dsc_read_state(dsc, &dsc_state);
@@ -1670,12 +1631,12 @@ static ssize_t dp_dsc_slice_width_write(struct file *f, const char __user *buf,
for (i = 0; i < MAX_PIPES; i++) {
pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i];
- if (pipe_ctx && pipe_ctx->stream &&
+ if (pipe_ctx->stream &&
pipe_ctx->stream->link == aconnector->dc_link)
break;
}
- if (!pipe_ctx || !pipe_ctx->stream)
+ if (!pipe_ctx->stream)
goto done;
// Safely get CRTC state
@@ -1755,16 +1716,11 @@ static ssize_t dp_dsc_slice_height_read(struct file *f, char __user *buf,
for (i = 0; i < MAX_PIPES; i++) {
pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i];
- if (pipe_ctx && pipe_ctx->stream &&
+ if (pipe_ctx->stream &&
pipe_ctx->stream->link == aconnector->dc_link)
break;
}
- if (!pipe_ctx) {
- kfree(rd_buf);
- return -ENXIO;
- }
-
dsc = pipe_ctx->stream_res.dsc;
if (dsc)
dsc->funcs->dsc_read_state(dsc, &dsc_state);
@@ -1859,12 +1815,12 @@ static ssize_t dp_dsc_slice_height_write(struct file *f, const char __user *buf,
for (i = 0; i < MAX_PIPES; i++) {
pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i];
- if (pipe_ctx && pipe_ctx->stream &&
+ if (pipe_ctx->stream &&
pipe_ctx->stream->link == aconnector->dc_link)
break;
}
- if (!pipe_ctx || !pipe_ctx->stream)
+ if (!pipe_ctx->stream)
goto done;
// Get CRTC state
@@ -1940,16 +1896,11 @@ static ssize_t dp_dsc_bits_per_pixel_read(struct file *f, char __user *buf,
for (i = 0; i < MAX_PIPES; i++) {
pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i];
- if (pipe_ctx && pipe_ctx->stream &&
+ if (pipe_ctx->stream &&
pipe_ctx->stream->link == aconnector->dc_link)
break;
}
- if (!pipe_ctx) {
- kfree(rd_buf);
- return -ENXIO;
- }
-
dsc = pipe_ctx->stream_res.dsc;
if (dsc)
dsc->funcs->dsc_read_state(dsc, &dsc_state);
@@ -2041,12 +1992,12 @@ static ssize_t dp_dsc_bits_per_pixel_write(struct file *f, const char __user *bu
for (i = 0; i < MAX_PIPES; i++) {
pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i];
- if (pipe_ctx && pipe_ctx->stream &&
+ if (pipe_ctx->stream &&
pipe_ctx->stream->link == aconnector->dc_link)
break;
}
- if (!pipe_ctx || !pipe_ctx->stream)
+ if (!pipe_ctx->stream)
goto done;
// Get CRTC state
@@ -2120,16 +2071,11 @@ static ssize_t dp_dsc_pic_width_read(struct file *f, char __user *buf,
for (i = 0; i < MAX_PIPES; i++) {
pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i];
- if (pipe_ctx && pipe_ctx->stream &&
+ if (pipe_ctx->stream &&
pipe_ctx->stream->link == aconnector->dc_link)
break;
}
- if (!pipe_ctx) {
- kfree(rd_buf);
- return -ENXIO;
- }
-
dsc = pipe_ctx->stream_res.dsc;
if (dsc)
dsc->funcs->dsc_read_state(dsc, &dsc_state);
@@ -2181,16 +2127,11 @@ static ssize_t dp_dsc_pic_height_read(struct file *f, char __user *buf,
for (i = 0; i < MAX_PIPES; i++) {
pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i];
- if (pipe_ctx && pipe_ctx->stream &&
+ if (pipe_ctx->stream &&
pipe_ctx->stream->link == aconnector->dc_link)
break;
}
- if (!pipe_ctx) {
- kfree(rd_buf);
- return -ENXIO;
- }
-
dsc = pipe_ctx->stream_res.dsc;
if (dsc)
dsc->funcs->dsc_read_state(dsc, &dsc_state);
@@ -2257,16 +2198,11 @@ static ssize_t dp_dsc_chunk_size_read(struct file *f, char __user *buf,
for (i = 0; i < MAX_PIPES; i++) {
pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i];
- if (pipe_ctx && pipe_ctx->stream &&
+ if (pipe_ctx->stream &&
pipe_ctx->stream->link == aconnector->dc_link)
break;
}
- if (!pipe_ctx) {
- kfree(rd_buf);
- return -ENXIO;
- }
-
dsc = pipe_ctx->stream_res.dsc;
if (dsc)
dsc->funcs->dsc_read_state(dsc, &dsc_state);
@@ -2333,16 +2269,11 @@ static ssize_t dp_dsc_slice_bpg_offset_read(struct file *f, char __user *buf,
for (i = 0; i < MAX_PIPES; i++) {
pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i];
- if (pipe_ctx && pipe_ctx->stream &&
+ if (pipe_ctx->stream &&
pipe_ctx->stream->link == aconnector->dc_link)
break;
}
- if (!pipe_ctx) {
- kfree(rd_buf);
- return -ENXIO;
- }
-
dsc = pipe_ctx->stream_res.dsc;
if (dsc)
dsc->funcs->dsc_read_state(dsc, &dsc_state);
@@ -2578,13 +2509,13 @@ static int dp_is_mst_connector_show(struct seq_file *m, void *unused)
if (aconnector->mst_mgr.mst_state) {
role = "root";
- } else if (aconnector->mst_port &&
- aconnector->mst_port->mst_mgr.mst_state) {
+ } else if (aconnector->mst_root &&
+ aconnector->mst_root->mst_mgr.mst_state) {
role = "end";
- mgr = &aconnector->mst_port->mst_mgr;
- port = aconnector->port;
+ mgr = &aconnector->mst_root->mst_mgr;
+ port = aconnector->mst_output_port;
drm_modeset_lock(&mgr->base.lock, NULL);
if (port->pdt == DP_PEER_DEVICE_MST_BRANCHING &&
@@ -3245,46 +3176,24 @@ DEFINE_DEBUGFS_ATTRIBUTE(crc_win_y_end_fops, crc_win_y_end_get,
*/
static int crc_win_update_set(void *data, u64 val)
{
- struct drm_crtc *new_crtc = data;
- struct drm_crtc *old_crtc = NULL;
- struct amdgpu_crtc *new_acrtc, *old_acrtc;
- struct amdgpu_device *adev = drm_to_adev(new_crtc->dev);
- struct crc_rd_work *crc_rd_wrk = adev->dm.crc_rd_wrk;
-
- if (!crc_rd_wrk)
- return 0;
+ struct drm_crtc *crtc = data;
+ struct amdgpu_crtc *acrtc;
+ struct amdgpu_device *adev = drm_to_adev(crtc->dev);
if (val) {
- new_acrtc = to_amdgpu_crtc(new_crtc);
+ acrtc = to_amdgpu_crtc(crtc);
mutex_lock(&adev->dm.dc_lock);
/* PSR may write to OTG CRC window control register,
* so close it before starting secure_display.
*/
- amdgpu_dm_psr_disable(new_acrtc->dm_irq_params.stream);
+ amdgpu_dm_psr_disable(acrtc->dm_irq_params.stream);
spin_lock_irq(&adev_to_drm(adev)->event_lock);
- spin_lock_irq(&crc_rd_wrk->crc_rd_work_lock);
- if (crc_rd_wrk->crtc) {
- old_crtc = crc_rd_wrk->crtc;
- old_acrtc = to_amdgpu_crtc(old_crtc);
- }
- if (old_crtc && old_crtc != new_crtc) {
- old_acrtc->dm_irq_params.window_param.activated = false;
- old_acrtc->dm_irq_params.window_param.update_win = false;
- old_acrtc->dm_irq_params.window_param.skip_frame_cnt = 0;
+ acrtc->dm_irq_params.window_param.activated = true;
+ acrtc->dm_irq_params.window_param.update_win = true;
+ acrtc->dm_irq_params.window_param.skip_frame_cnt = 0;
- new_acrtc->dm_irq_params.window_param.activated = true;
- new_acrtc->dm_irq_params.window_param.update_win = true;
- new_acrtc->dm_irq_params.window_param.skip_frame_cnt = 0;
- crc_rd_wrk->crtc = new_crtc;
- } else {
- new_acrtc->dm_irq_params.window_param.activated = true;
- new_acrtc->dm_irq_params.window_param.update_win = true;
- new_acrtc->dm_irq_params.window_param.skip_frame_cnt = 0;
- crc_rd_wrk->crtc = new_crtc;
- }
- spin_unlock_irq(&crc_rd_wrk->crc_rd_work_lock);
spin_unlock_irq(&adev_to_drm(adev)->event_lock);
mutex_unlock(&adev->dm.dc_lock);
}
@@ -3453,12 +3362,12 @@ static int trigger_hpd_mst_set(void *data, u64 val)
if (!aconnector->dc_link)
continue;
- if (!aconnector->mst_port)
+ if (!aconnector->mst_root)
continue;
link = aconnector->dc_link;
- dp_receiver_power_ctrl(link, false);
- drm_dp_mst_topology_mgr_set_mst(&aconnector->mst_port->mst_mgr, false);
+ dc_link_dp_receiver_power_ctrl(link, false);
+ drm_dp_mst_topology_mgr_set_mst(&aconnector->mst_root->mst_mgr, false);
link->mst_stream_alloc_table.stream_count = 0;
memset(link->mst_stream_alloc_table.stream_allocations, 0,
sizeof(link->mst_stream_alloc_table.stream_allocations));
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
index a7fd98f57f94..8e572f07ec47 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
@@ -170,9 +170,10 @@ void hdcp_update_display(struct hdcp_workqueue *hdcp_work,
struct mod_hdcp_display *display = &hdcp_work[link_index].display;
struct mod_hdcp_link *link = &hdcp_work[link_index].link;
struct mod_hdcp_display_query query;
+ unsigned int conn_index = aconnector->base.index;
mutex_lock(&hdcp_w->mutex);
- hdcp_w->aconnector = aconnector;
+ hdcp_w->aconnector[conn_index] = aconnector;
query.display = NULL;
mod_hdcp_query_display(&hdcp_w->hdcp, aconnector->base.index, &query);
@@ -204,7 +205,7 @@ void hdcp_update_display(struct hdcp_workqueue *hdcp_work,
msecs_to_jiffies(DRM_HDCP_CHECK_PERIOD_MS));
} else {
display->adjust.disable = MOD_HDCP_DISPLAY_DISABLE_AUTHENTICATION;
- hdcp_w->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
+ hdcp_w->encryption_status[conn_index] = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
cancel_delayed_work(&hdcp_w->property_validate_dwork);
}
@@ -223,9 +224,10 @@ static void hdcp_remove_display(struct hdcp_workqueue *hdcp_work,
{
struct hdcp_workqueue *hdcp_w = &hdcp_work[link_index];
struct drm_connector_state *conn_state = aconnector->base.state;
+ unsigned int conn_index = aconnector->base.index;
mutex_lock(&hdcp_w->mutex);
- hdcp_w->aconnector = aconnector;
+ hdcp_w->aconnector[conn_index] = aconnector;
/* the removal of display will invoke auth reset -> hdcp destroy and
* we'd expect the Content Protection (CP) property changed back to
@@ -247,13 +249,18 @@ static void hdcp_remove_display(struct hdcp_workqueue *hdcp_work,
void hdcp_reset_display(struct hdcp_workqueue *hdcp_work, unsigned int link_index)
{
struct hdcp_workqueue *hdcp_w = &hdcp_work[link_index];
+ unsigned int conn_index;
mutex_lock(&hdcp_w->mutex);
mod_hdcp_reset_connection(&hdcp_w->hdcp, &hdcp_w->output);
cancel_delayed_work(&hdcp_w->property_validate_dwork);
- hdcp_w->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
+
+ for (conn_index = 0; conn_index < AMDGPU_DM_MAX_DISPLAY_INDEX; conn_index++) {
+ hdcp_w->encryption_status[conn_index] =
+ MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
+ }
process_output(hdcp_w);
@@ -290,49 +297,80 @@ static void event_callback(struct work_struct *work)
}
+
static void event_property_update(struct work_struct *work)
{
-
struct hdcp_workqueue *hdcp_work = container_of(work, struct hdcp_workqueue, property_update_work);
- struct amdgpu_dm_connector *aconnector = hdcp_work->aconnector;
- struct drm_device *dev = hdcp_work->aconnector->base.dev;
+ struct amdgpu_dm_connector *aconnector = NULL;
+ struct drm_device *dev;
long ret;
+ unsigned int conn_index;
+ struct drm_connector *connector;
+ struct drm_connector_state *conn_state;
- drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
- mutex_lock(&hdcp_work->mutex);
+ for (conn_index = 0; conn_index < AMDGPU_DM_MAX_DISPLAY_INDEX; conn_index++) {
+ aconnector = hdcp_work->aconnector[conn_index];
+ if (!aconnector)
+ continue;
- if (aconnector->base.state && aconnector->base.state->commit) {
- ret = wait_for_completion_interruptible_timeout(&aconnector->base.state->commit->hw_done, 10 * HZ);
+ connector = &aconnector->base;
- if (ret == 0) {
- DRM_ERROR("HDCP state unknown! Setting it to DESIRED");
- hdcp_work->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
- }
- }
+ /* check if display connected */
+ if (connector->status != connector_status_connected)
+ continue;
- if (aconnector->base.state) {
- if (hdcp_work->encryption_status != MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF) {
- if (aconnector->base.state->hdcp_content_type ==
+ conn_state = aconnector->base.state;
+
+ if (!conn_state)
+ continue;
+
+ dev = connector->dev;
+
+ if (!dev)
+ continue;
+
+ drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
+ mutex_lock(&hdcp_work->mutex);
+
+ if (conn_state->commit) {
+ ret = wait_for_completion_interruptible_timeout(
+ &conn_state->commit->hw_done, 10 * HZ);
+ if (ret == 0) {
+ DRM_ERROR(
+ "HDCP state unknown! Setting it to DESIRED");
+ hdcp_work->encryption_status[conn_index] =
+ MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
+ }
+ }
+ if (hdcp_work->encryption_status[conn_index] !=
+ MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF) {
+ if (conn_state->hdcp_content_type ==
DRM_MODE_HDCP_CONTENT_TYPE0 &&
- hdcp_work->encryption_status <=
- MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE0_ON)
- drm_hdcp_update_content_protection(&aconnector->base,
+ hdcp_work->encryption_status[conn_index] <=
+ MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE0_ON) {
+
+ DRM_DEBUG_DRIVER("[HDCP_DM] DRM_MODE_CONTENT_PROTECTION_ENABLED\n");
+ drm_hdcp_update_content_protection(
+ connector,
DRM_MODE_CONTENT_PROTECTION_ENABLED);
- else if (aconnector->base.state->hdcp_content_type ==
+ } else if (conn_state->hdcp_content_type ==
DRM_MODE_HDCP_CONTENT_TYPE1 &&
- hdcp_work->encryption_status ==
- MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE1_ON)
- drm_hdcp_update_content_protection(&aconnector->base,
+ hdcp_work->encryption_status[conn_index] ==
+ MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE1_ON) {
+ drm_hdcp_update_content_protection(
+ connector,
DRM_MODE_CONTENT_PROTECTION_ENABLED);
+ }
} else {
- drm_hdcp_update_content_protection(&aconnector->base,
- DRM_MODE_CONTENT_PROTECTION_DESIRED);
+ DRM_DEBUG_DRIVER("[HDCP_DM] DRM_MODE_CONTENT_PROTECTION_DESIRED\n");
+ drm_hdcp_update_content_protection(
+ connector, DRM_MODE_CONTENT_PROTECTION_DESIRED);
+
}
+ mutex_unlock(&hdcp_work->mutex);
+ drm_modeset_unlock(&dev->mode_config.connection_mutex);
}
-
- mutex_unlock(&hdcp_work->mutex);
- drm_modeset_unlock(&dev->mode_config.connection_mutex);
}
static void event_property_validate(struct work_struct *work)
@@ -340,19 +378,47 @@ static void event_property_validate(struct work_struct *work)
struct hdcp_workqueue *hdcp_work =
container_of(to_delayed_work(work), struct hdcp_workqueue, property_validate_dwork);
struct mod_hdcp_display_query query;
- struct amdgpu_dm_connector *aconnector = hdcp_work->aconnector;
-
- if (!aconnector)
- return;
+ struct amdgpu_dm_connector *aconnector;
+ unsigned int conn_index;
mutex_lock(&hdcp_work->mutex);
- query.encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
- mod_hdcp_query_display(&hdcp_work->hdcp, aconnector->base.index, &query);
+ for (conn_index = 0; conn_index < AMDGPU_DM_MAX_DISPLAY_INDEX;
+ conn_index++) {
+ aconnector = hdcp_work->aconnector[conn_index];
+
+ if (!aconnector)
+ continue;
+
+ /* check if display connected */
+ if (aconnector->base.status != connector_status_connected)
+ continue;
- if (query.encryption_status != hdcp_work->encryption_status) {
- hdcp_work->encryption_status = query.encryption_status;
- schedule_work(&hdcp_work->property_update_work);
+ if (!aconnector->base.state)
+ continue;
+
+ query.encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
+ mod_hdcp_query_display(&hdcp_work->hdcp, aconnector->base.index,
+ &query);
+
+ DRM_DEBUG_DRIVER("[HDCP_DM] disp %d, connector->CP %u, (query, work): (%d, %d)\n",
+ aconnector->base.index,
+ aconnector->base.state->content_protection,
+ query.encryption_status,
+ hdcp_work->encryption_status[conn_index]);
+
+ if (query.encryption_status !=
+ hdcp_work->encryption_status[conn_index]) {
+ DRM_DEBUG_DRIVER("[HDCP_DM] encryption_status change from %x to %x\n",
+ hdcp_work->encryption_status[conn_index], query.encryption_status);
+
+ hdcp_work->encryption_status[conn_index] =
+ query.encryption_status;
+
+ DRM_DEBUG_DRIVER("[HDCP_DM] trigger property_update_work\n");
+
+ schedule_work(&hdcp_work->property_update_work);
+ }
}
mutex_unlock(&hdcp_work->mutex);
@@ -686,6 +752,13 @@ struct hdcp_workqueue *hdcp_create_workqueue(struct amdgpu_device *adev, struct
hdcp_work[i].hdcp.config.ddc.funcs.read_i2c = lp_read_i2c;
hdcp_work[i].hdcp.config.ddc.funcs.write_dpcd = lp_write_dpcd;
hdcp_work[i].hdcp.config.ddc.funcs.read_dpcd = lp_read_dpcd;
+
+ memset(hdcp_work[i].aconnector, 0,
+ sizeof(struct amdgpu_dm_connector *) *
+ AMDGPU_DM_MAX_DISPLAY_INDEX);
+ memset(hdcp_work[i].encryption_status, 0,
+ sizeof(enum mod_hdcp_encryption_status) *
+ AMDGPU_DM_MAX_DISPLAY_INDEX);
}
cp_psp->funcs.update_stream_config = update_config;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h
index 09294ff122fe..69b445b011c8 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h
@@ -43,7 +43,7 @@ struct hdcp_workqueue {
struct delayed_work callback_dwork;
struct delayed_work watchdog_timer_dwork;
struct delayed_work property_validate_dwork;
- struct amdgpu_dm_connector *aconnector;
+ struct amdgpu_dm_connector *aconnector[AMDGPU_DM_MAX_DISPLAY_INDEX];
struct mutex mutex;
struct mod_hdcp hdcp;
@@ -51,7 +51,20 @@ struct hdcp_workqueue {
struct mod_hdcp_display display;
struct mod_hdcp_link link;
- enum mod_hdcp_encryption_status encryption_status;
+ enum mod_hdcp_encryption_status encryption_status[AMDGPU_DM_MAX_DISPLAY_INDEX];
+ /* when display is unplugged from mst hub, connctor will be
+ * destroyed within dm_dp_mst_connector_destroy. connector
+ * hdcp perperties, like type, undesired, desired, enabled,
+ * will be lost. So, save hdcp properties into hdcp_work within
+ * amdgpu_dm_atomic_commit_tail. if the same display is
+ * plugged back with same display index, its hdcp properties
+ * will be retrieved from hdcp_work within dm_dp_mst_get_modes
+ */
+ /* un-desired, desired, enabled */
+ unsigned int content_protection[AMDGPU_DM_MAX_DISPLAY_INDEX];
+ /* hdcp1.x, hdcp2.x */
+ unsigned int hdcp_content_type[AMDGPU_DM_MAX_DISPLAY_INDEX];
+
uint8_t max_link;
uint8_t *srm;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
index 5cff56bb8f56..1583157da355 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
@@ -38,6 +38,8 @@
#include "amdgpu_dm.h"
#include "amdgpu_dm_irq.h"
#include "amdgpu_dm_mst_types.h"
+#include "dpcd_defs.h"
+#include "dc/inc/core_types.h"
#include "dm_helpers.h"
#include "ddc_service_types.h"
@@ -195,18 +197,18 @@ bool dm_helpers_dp_mst_write_payload_allocation_table(
* that blocks before commit guaranteeing that the state
* is not gonna be swapped while still in use in commit tail */
- if (!aconnector || !aconnector->mst_port)
+ if (!aconnector || !aconnector->mst_root)
return false;
- mst_mgr = &aconnector->mst_port->mst_mgr;
+ mst_mgr = &aconnector->mst_root->mst_mgr;
mst_state = to_drm_dp_mst_topology_state(mst_mgr->base.state);
/* It's OK for this to fail */
- payload = drm_atomic_get_mst_payload_state(mst_state, aconnector->port);
+ payload = drm_atomic_get_mst_payload_state(mst_state, aconnector->mst_output_port);
if (enable)
drm_dp_add_payload_part1(mst_mgr, mst_state, payload);
else
- drm_dp_remove_payload(mst_mgr, mst_state, payload);
+ drm_dp_remove_payload(mst_mgr, mst_state, payload, payload);
/* mst_mgr->->payloads are VC payload notify MST branch using DPCD or
* AUX message. The sequence is slot 1-63 allocated sequence for each
@@ -247,10 +249,10 @@ enum act_return_status dm_helpers_dp_mst_poll_for_allocation_change_trigger(
aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context;
- if (!aconnector || !aconnector->mst_port)
+ if (!aconnector || !aconnector->mst_root)
return ACT_FAILED;
- mst_mgr = &aconnector->mst_port->mst_mgr;
+ mst_mgr = &aconnector->mst_root->mst_mgr;
if (!mst_mgr->mst_state)
return ACT_FAILED;
@@ -274,22 +276,27 @@ bool dm_helpers_dp_mst_send_payload_allocation(
struct drm_dp_mst_atomic_payload *payload;
enum mst_progress_status set_flag = MST_ALLOCATE_NEW_PAYLOAD;
enum mst_progress_status clr_flag = MST_CLEAR_ALLOCATED_PAYLOAD;
+ int ret = 0;
aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context;
- if (!aconnector || !aconnector->mst_port)
+ if (!aconnector || !aconnector->mst_root)
return false;
- mst_mgr = &aconnector->mst_port->mst_mgr;
+ mst_mgr = &aconnector->mst_root->mst_mgr;
mst_state = to_drm_dp_mst_topology_state(mst_mgr->base.state);
- payload = drm_atomic_get_mst_payload_state(mst_state, aconnector->port);
+ payload = drm_atomic_get_mst_payload_state(mst_state, aconnector->mst_output_port);
+
if (!enable) {
set_flag = MST_CLEAR_ALLOCATED_PAYLOAD;
clr_flag = MST_ALLOCATE_NEW_PAYLOAD;
}
- if (enable && drm_dp_add_payload_part2(mst_mgr, mst_state->base.state, payload)) {
+ if (enable)
+ ret = drm_dp_add_payload_part2(mst_mgr, mst_state->base.state, payload);
+
+ if (ret) {
amdgpu_dm_set_mst_status(&aconnector->mst_status,
set_flag, false);
} else {
@@ -396,6 +403,7 @@ bool dm_helpers_dp_mst_start_top_mgr(
bool boot)
{
struct amdgpu_dm_connector *aconnector = link->priv;
+ int ret;
if (!aconnector) {
DRM_ERROR("Failed to find connector for link!");
@@ -411,7 +419,16 @@ bool dm_helpers_dp_mst_start_top_mgr(
DRM_INFO("DM_MST: starting TM on aconnector: %p [id: %d]\n",
aconnector, aconnector->base.base.id);
- return (drm_dp_mst_topology_mgr_set_mst(&aconnector->mst_mgr, true) == 0);
+ ret = drm_dp_mst_topology_mgr_set_mst(&aconnector->mst_mgr, true);
+ if (ret < 0) {
+ DRM_ERROR("DM_MST: Failed to set the device into MST mode!");
+ return false;
+ }
+
+ DRM_INFO("DM_MST: DP%x, %d-lane link detected\n", aconnector->mst_mgr.dpcd[0],
+ aconnector->mst_mgr.dpcd[2] & DP_MAX_LANE_COUNT_MASK);
+
+ return true;
}
bool dm_helpers_dp_mst_stop_top_mgr(
@@ -710,7 +727,7 @@ bool dm_helpers_dp_write_dsc_enable(
aconnector->dsc_aux, stream, enable_dsc);
#endif
- port = aconnector->port;
+ port = aconnector->mst_output_port;
if (enable) {
if (port->passthrough_aux) {
@@ -987,6 +1004,128 @@ void dm_helpers_mst_enable_stream_features(const struct dc_stream_state *stream)
sizeof(new_downspread));
}
+bool dm_helpers_dp_handle_test_pattern_request(
+ struct dc_context *ctx,
+ const struct dc_link *link,
+ union link_test_pattern dpcd_test_pattern,
+ union test_misc dpcd_test_params)
+{
+ enum dp_test_pattern test_pattern;
+ enum dp_test_pattern_color_space test_pattern_color_space =
+ DP_TEST_PATTERN_COLOR_SPACE_UNDEFINED;
+ enum dc_color_depth requestColorDepth = COLOR_DEPTH_UNDEFINED;
+ enum dc_pixel_encoding requestPixelEncoding = PIXEL_ENCODING_UNDEFINED;
+ struct pipe_ctx *pipes = link->dc->current_state->res_ctx.pipe_ctx;
+ struct pipe_ctx *pipe_ctx = NULL;
+ struct amdgpu_dm_connector *aconnector = link->priv;
+ int i;
+
+ for (i = 0; i < MAX_PIPES; i++) {
+ if (pipes[i].stream == NULL)
+ continue;
+
+ if (pipes[i].stream->link == link && !pipes[i].top_pipe &&
+ !pipes[i].prev_odm_pipe) {
+ pipe_ctx = &pipes[i];
+ break;
+ }
+ }
+
+ if (pipe_ctx == NULL)
+ return false;
+
+ switch (dpcd_test_pattern.bits.PATTERN) {
+ case LINK_TEST_PATTERN_COLOR_RAMP:
+ test_pattern = DP_TEST_PATTERN_COLOR_RAMP;
+ break;
+ case LINK_TEST_PATTERN_VERTICAL_BARS:
+ test_pattern = DP_TEST_PATTERN_VERTICAL_BARS;
+ break; /* black and white */
+ case LINK_TEST_PATTERN_COLOR_SQUARES:
+ test_pattern = (dpcd_test_params.bits.DYN_RANGE ==
+ TEST_DYN_RANGE_VESA ?
+ DP_TEST_PATTERN_COLOR_SQUARES :
+ DP_TEST_PATTERN_COLOR_SQUARES_CEA);
+ break;
+ default:
+ test_pattern = DP_TEST_PATTERN_VIDEO_MODE;
+ break;
+ }
+
+ if (dpcd_test_params.bits.CLR_FORMAT == 0)
+ test_pattern_color_space = DP_TEST_PATTERN_COLOR_SPACE_RGB;
+ else
+ test_pattern_color_space = dpcd_test_params.bits.YCBCR_COEFS ?
+ DP_TEST_PATTERN_COLOR_SPACE_YCBCR709 :
+ DP_TEST_PATTERN_COLOR_SPACE_YCBCR601;
+
+ switch (dpcd_test_params.bits.BPC) {
+ case 0: // 6 bits
+ requestColorDepth = COLOR_DEPTH_666;
+ break;
+ case 1: // 8 bits
+ requestColorDepth = COLOR_DEPTH_888;
+ break;
+ case 2: // 10 bits
+ requestColorDepth = COLOR_DEPTH_101010;
+ break;
+ case 3: // 12 bits
+ requestColorDepth = COLOR_DEPTH_121212;
+ break;
+ default:
+ break;
+ }
+
+ switch (dpcd_test_params.bits.CLR_FORMAT) {
+ case 0:
+ requestPixelEncoding = PIXEL_ENCODING_RGB;
+ break;
+ case 1:
+ requestPixelEncoding = PIXEL_ENCODING_YCBCR422;
+ break;
+ case 2:
+ requestPixelEncoding = PIXEL_ENCODING_YCBCR444;
+ break;
+ default:
+ requestPixelEncoding = PIXEL_ENCODING_RGB;
+ break;
+ }
+
+ if ((requestColorDepth != COLOR_DEPTH_UNDEFINED
+ && pipe_ctx->stream->timing.display_color_depth != requestColorDepth)
+ || (requestPixelEncoding != PIXEL_ENCODING_UNDEFINED
+ && pipe_ctx->stream->timing.pixel_encoding != requestPixelEncoding)) {
+ DC_LOG_DEBUG("%s: original bpc %d pix encoding %d, changing to %d %d\n",
+ __func__,
+ pipe_ctx->stream->timing.display_color_depth,
+ pipe_ctx->stream->timing.pixel_encoding,
+ requestColorDepth,
+ requestPixelEncoding);
+ pipe_ctx->stream->timing.display_color_depth = requestColorDepth;
+ pipe_ctx->stream->timing.pixel_encoding = requestPixelEncoding;
+
+ dc_link_update_dsc_config(pipe_ctx);
+
+ aconnector->timing_changed = true;
+ /* store current timing */
+ if (aconnector->timing_requested)
+ *aconnector->timing_requested = pipe_ctx->stream->timing;
+ else
+ DC_LOG_ERROR("%s: timing storage failed\n", __func__);
+
+ }
+
+ dc_link_dp_set_test_pattern(
+ (struct dc_link *) link,
+ test_pattern,
+ test_pattern_color_space,
+ NULL,
+ NULL,
+ 0);
+
+ return false;
+}
+
void dm_set_phyd32clk(struct dc_context *ctx, int freq_khz)
{
// TODO
@@ -1004,3 +1143,38 @@ void dm_helpers_dp_mst_update_branch_bandwidth(
// TODO
}
+static bool dm_is_freesync_pcon_whitelist(const uint32_t branch_dev_id)
+{
+ bool ret_val = false;
+
+ switch (branch_dev_id) {
+ case DP_BRANCH_DEVICE_ID_0060AD:
+ case DP_BRANCH_DEVICE_ID_00E04C:
+ case DP_BRANCH_DEVICE_ID_90CC24:
+ ret_val = true;
+ break;
+ default:
+ break;
+ }
+
+ return ret_val;
+}
+
+enum adaptive_sync_type dm_get_adaptive_sync_support_type(struct dc_link *link)
+{
+ struct dpcd_caps *dpcd_caps = &link->dpcd_caps;
+ enum adaptive_sync_type as_type = ADAPTIVE_SYNC_TYPE_NONE;
+
+ switch (dpcd_caps->dongle_type) {
+ case DISPLAY_DONGLE_DP_HDMI_CONVERTER:
+ if (dpcd_caps->adaptive_sync_caps.dp_adap_sync_caps.bits.ADAPTIVE_SYNC_SDP_SUPPORT == true &&
+ dpcd_caps->allow_invalid_MSA_timing_param == true &&
+ dm_is_freesync_pcon_whitelist(dpcd_caps->branch_dev_id))
+ as_type = FREESYNC_TYPE_PCON_IN_WHITELIST;
+ break;
+ default:
+ break;
+ }
+
+ return as_type;
+}
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
index abdbd4352f6f..e25e1b2bf194 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
@@ -32,15 +32,16 @@
#include "amdgpu_dm.h"
#include "amdgpu_dm_mst_types.h"
+#ifdef CONFIG_DRM_AMD_DC_HDCP
+#include "amdgpu_dm_hdcp.h"
+#endif
+
#include "dc.h"
#include "dm_helpers.h"
-#include "dc_link_ddc.h"
-#include "dc_link_dp.h"
#include "ddc_service_types.h"
#include "dpcd_defs.h"
-#include "i2caux_interface.h"
#include "dmub_cmd.h"
#if defined(CONFIG_DEBUG_FS)
#include "amdgpu_dm_debugfs.h"
@@ -49,7 +50,7 @@
#include "dc/dcn20/dcn20_resource.h"
bool is_timing_changed(struct dc_stream_state *cur_stream,
struct dc_stream_state *new_stream);
-
+#define PEAK_FACTOR_X1000 1006
static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux,
struct drm_dp_aux_msg *msg)
@@ -132,7 +133,7 @@ dm_dp_mst_connector_destroy(struct drm_connector *connector)
kfree(aconnector->edid);
drm_connector_cleanup(connector);
- drm_dp_mst_put_port_malloc(aconnector->port);
+ drm_dp_mst_put_port_malloc(aconnector->mst_output_port);
kfree(aconnector);
}
@@ -144,7 +145,7 @@ amdgpu_dm_mst_connector_late_register(struct drm_connector *connector)
int r;
r = drm_dp_mst_connector_late_register(connector,
- amdgpu_dm_connector->port);
+ amdgpu_dm_connector->mst_output_port);
if (r < 0)
return r;
@@ -160,8 +161,8 @@ amdgpu_dm_mst_connector_early_unregister(struct drm_connector *connector)
{
struct amdgpu_dm_connector *aconnector =
to_amdgpu_dm_connector(connector);
- struct drm_dp_mst_port *port = aconnector->port;
- struct amdgpu_dm_connector *root = aconnector->mst_port;
+ struct drm_dp_mst_port *port = aconnector->mst_output_port;
+ struct amdgpu_dm_connector *root = aconnector->mst_root;
struct dc_link *dc_link = aconnector->dc_link;
struct dc_sink *dc_sink = aconnector->dc_sink;
@@ -176,6 +177,9 @@ amdgpu_dm_mst_connector_early_unregister(struct drm_connector *connector)
if (dc_link->sink_count)
dc_link_remove_remote_sink(dc_link, dc_sink);
+ DC_LOG_MST("DM_MST: remove remote sink 0x%p, %d remaining\n",
+ dc_sink, dc_link->sink_count);
+
dc_sink_release(dc_sink);
aconnector->dc_sink = NULL;
aconnector->edid = NULL;
@@ -211,7 +215,7 @@ bool needs_dsc_aux_workaround(struct dc_link *link)
static bool validate_dsc_caps_on_connector(struct amdgpu_dm_connector *aconnector)
{
struct dc_sink *dc_sink = aconnector->dc_sink;
- struct drm_dp_mst_port *port = aconnector->port;
+ struct drm_dp_mst_port *port = aconnector->mst_output_port;
u8 dsc_caps[16] = { 0 };
u8 dsc_branch_dec_caps_raw[3] = { 0 }; // DSC branch decoder caps 0xA0 ~ 0xA2
u8 *dsc_branch_dec_caps = NULL;
@@ -229,7 +233,7 @@ static bool validate_dsc_caps_on_connector(struct amdgpu_dm_connector *aconnecto
*/
if (!aconnector->dsc_aux && !port->parent->port_parent &&
needs_dsc_aux_workaround(aconnector->dc_link))
- aconnector->dsc_aux = &aconnector->mst_port->dm_dp_aux.aux;
+ aconnector->dsc_aux = &aconnector->mst_root->dm_dp_aux.aux;
if (!aconnector->dsc_aux)
return false;
@@ -279,7 +283,7 @@ static int dm_dp_mst_get_modes(struct drm_connector *connector)
if (!aconnector->edid) {
struct edid *edid;
- edid = drm_dp_mst_get_edid(connector, &aconnector->mst_port->mst_mgr, aconnector->port);
+ edid = drm_dp_mst_get_edid(connector, &aconnector->mst_root->mst_mgr, aconnector->mst_output_port);
if (!edid) {
amdgpu_dm_set_mst_status(&aconnector->mst_status,
@@ -307,6 +311,9 @@ static int dm_dp_mst_get_modes(struct drm_connector *connector)
return 0;
}
+ DC_LOG_MST("DM_MST: add remote sink 0x%p, %d remaining\n",
+ dc_sink, aconnector->dc_link->sink_count);
+
dc_sink->priv = aconnector;
aconnector->dc_sink = dc_sink;
}
@@ -340,10 +347,35 @@ static int dm_dp_mst_get_modes(struct drm_connector *connector)
return 0;
}
+ DC_LOG_MST("DM_MST: add remote sink 0x%p, %d remaining\n",
+ dc_sink, aconnector->dc_link->sink_count);
+
dc_sink->priv = aconnector;
/* dc_link_add_remote_sink returns a new reference */
aconnector->dc_sink = dc_sink;
+ /* when display is unplugged from mst hub, connctor will be
+ * destroyed within dm_dp_mst_connector_destroy. connector
+ * hdcp perperties, like type, undesired, desired, enabled,
+ * will be lost. So, save hdcp properties into hdcp_work within
+ * amdgpu_dm_atomic_commit_tail. if the same display is
+ * plugged back with same display index, its hdcp properties
+ * will be retrieved from hdcp_work within dm_dp_mst_get_modes
+ */
+#ifdef CONFIG_DRM_AMD_DC_HDCP
+ if (aconnector->dc_sink && connector->state) {
+ struct drm_device *dev = connector->dev;
+ struct amdgpu_device *adev = drm_to_adev(dev);
+ struct hdcp_workqueue *hdcp_work = adev->dm.hdcp_workqueue;
+ struct hdcp_workqueue *hdcp_w = &hdcp_work[aconnector->dc_link->link_index];
+
+ connector->state->hdcp_content_type =
+ hdcp_w->hdcp_content_type[connector->index];
+ connector->state->content_protection =
+ hdcp_w->content_protection[connector->index];
+ }
+#endif
+
if (aconnector->dc_sink) {
amdgpu_dm_update_freesync_caps(
connector, aconnector->edid);
@@ -386,15 +418,15 @@ dm_dp_mst_detect(struct drm_connector *connector,
struct drm_modeset_acquire_ctx *ctx, bool force)
{
struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
- struct amdgpu_dm_connector *master = aconnector->mst_port;
- struct drm_dp_mst_port *port = aconnector->port;
+ struct amdgpu_dm_connector *master = aconnector->mst_root;
+ struct drm_dp_mst_port *port = aconnector->mst_output_port;
int connection_status;
if (drm_connector_is_unregistered(connector))
return connector_status_disconnected;
connection_status = drm_dp_mst_detect_port(connector, ctx, &master->mst_mgr,
- aconnector->port);
+ aconnector->mst_output_port);
if (port->pdt != DP_PEER_DEVICE_NONE && !port->dpcd_rev) {
uint8_t dpcd_rev;
@@ -435,6 +467,9 @@ dm_dp_mst_detect(struct drm_connector *connector,
if (aconnector->dc_link->sink_count)
dc_link_remove_remote_sink(aconnector->dc_link, aconnector->dc_sink);
+ DC_LOG_MST("DM_MST: remove remote sink 0x%p, %d remaining\n",
+ aconnector->dc_link, aconnector->dc_link->sink_count);
+
dc_sink_release(aconnector->dc_sink);
aconnector->dc_sink = NULL;
aconnector->edid = NULL;
@@ -451,8 +486,8 @@ static int dm_dp_mst_atomic_check(struct drm_connector *connector,
struct drm_atomic_state *state)
{
struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
- struct drm_dp_mst_topology_mgr *mst_mgr = &aconnector->mst_port->mst_mgr;
- struct drm_dp_mst_port *mst_port = aconnector->port;
+ struct drm_dp_mst_topology_mgr *mst_mgr = &aconnector->mst_root->mst_mgr;
+ struct drm_dp_mst_port *mst_port = aconnector->mst_output_port;
return drm_dp_atomic_release_time_slots(state, mst_mgr, mst_port);
}
@@ -514,8 +549,8 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
return NULL;
connector = &aconnector->base;
- aconnector->port = port;
- aconnector->mst_port = master;
+ aconnector->mst_output_port = port;
+ aconnector->mst_root = master;
amdgpu_dm_set_mst_status(&aconnector->mst_status,
MST_PROBE, true);
@@ -916,7 +951,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,
if (!aconnector)
continue;
- if (!aconnector->port)
+ if (!aconnector->mst_output_port)
continue;
stream->timing.flags.DSC = 0;
@@ -924,7 +959,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,
params[count].timing = &stream->timing;
params[count].sink = stream->sink;
params[count].aconnector = aconnector;
- params[count].port = aconnector->port;
+ params[count].port = aconnector->mst_output_port;
params[count].clock_force_enable = aconnector->dsc_settings.dsc_force_enable;
if (params[count].clock_force_enable == DSC_CLK_FORCE_ENABLE)
debugfs_overwrite = true;
@@ -1133,7 +1168,7 @@ int compute_mst_dsc_configs_for_state(struct drm_atomic_state *state,
aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context;
- if (!aconnector || !aconnector->dc_sink || !aconnector->port)
+ if (!aconnector || !aconnector->dc_sink || !aconnector->mst_output_port)
continue;
if (!aconnector->dc_sink->dsc_caps.dsc_dec_caps.is_dsc_supported)
@@ -1148,7 +1183,7 @@ int compute_mst_dsc_configs_for_state(struct drm_atomic_state *state,
if (!is_dsc_need_re_compute(state, dc_state, stream->link))
continue;
- mst_mgr = aconnector->port->mgr;
+ mst_mgr = aconnector->mst_output_port->mgr;
ret = compute_mst_dsc_configs_for_link(state, dc_state, stream->link, vars, mst_mgr,
&link_vars_start_index);
if (ret != 0)
@@ -1194,7 +1229,7 @@ static int pre_compute_mst_dsc_configs_for_state(struct drm_atomic_state *state,
aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context;
- if (!aconnector || !aconnector->dc_sink || !aconnector->port)
+ if (!aconnector || !aconnector->dc_sink || !aconnector->mst_output_port)
continue;
if (!aconnector->dc_sink->dsc_caps.dsc_dec_caps.is_dsc_supported)
@@ -1206,7 +1241,7 @@ static int pre_compute_mst_dsc_configs_for_state(struct drm_atomic_state *state,
if (!is_dsc_need_re_compute(state, dc_state, stream->link))
continue;
- mst_mgr = aconnector->port->mgr;
+ mst_mgr = aconnector->mst_output_port->mgr;
ret = compute_mst_dsc_configs_for_link(state, dc_state, stream->link, vars, mst_mgr,
&link_vars_start_index);
if (ret != 0)
@@ -1421,8 +1456,8 @@ enum dc_status dm_dp_mst_is_port_support_mode(
* with DSC enabled.
*/
if (is_dsc_common_config_possible(stream, &bw_range) &&
- aconnector->port->passthrough_aux) {
- mst_mgr = aconnector->port->mgr;
+ aconnector->mst_output_port->passthrough_aux) {
+ mst_mgr = aconnector->mst_output_port->mgr;
mutex_lock(&mst_mgr->lock);
cur_link_settings = stream->link->verified_link_cap;
@@ -1430,7 +1465,7 @@ enum dc_status dm_dp_mst_is_port_support_mode(
upper_link_bw_in_kbps = dc_link_bandwidth_kbps(aconnector->dc_link,
&cur_link_settings
);
- down_link_bw_in_kbps = kbps_from_pbn(aconnector->port->full_pbn);
+ down_link_bw_in_kbps = kbps_from_pbn(aconnector->mst_output_port->full_pbn);
/* pick the bottleneck */
end_to_end_bw_in_kbps = min(upper_link_bw_in_kbps,
@@ -1454,7 +1489,7 @@ enum dc_status dm_dp_mst_is_port_support_mode(
bpp = convert_dc_color_depth_into_bpc(stream->timing.display_color_depth) * 3;
pbn = drm_dp_calc_pbn_mode(stream->timing.pix_clk_100hz / 10, bpp, false);
- if (pbn > aconnector->port->full_pbn)
+ if (pbn > aconnector->mst_output_port->full_pbn)
return DC_FAIL_BANDWIDTH_VALIDATE;
#if defined(CONFIG_DRM_AMD_DC_DCN)
}
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
index 3c50b3ff7954..28fb1f02591a 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
@@ -67,7 +67,16 @@ static const uint32_t overlay_formats[] = {
DRM_FORMAT_RGBA8888,
DRM_FORMAT_XBGR8888,
DRM_FORMAT_ABGR8888,
- DRM_FORMAT_RGB565
+ DRM_FORMAT_RGB565,
+ DRM_FORMAT_NV21,
+ DRM_FORMAT_NV12,
+ DRM_FORMAT_P010
+};
+
+static const uint32_t video_formats[] = {
+ DRM_FORMAT_NV21,
+ DRM_FORMAT_NV12,
+ DRM_FORMAT_P010
};
static const u32 cursor_formats[] = {
@@ -1616,3 +1625,14 @@ int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,
return 0;
}
+bool is_video_format(uint32_t format)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(video_formats); i++)
+ if (format == video_formats[i])
+ return true;
+
+ return false;
+}
+
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h
index 286981a2dd40..a4bee8528a51 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h
@@ -62,4 +62,5 @@ void fill_blending_from_plane_state(const struct drm_plane_state *plane_state,
bool *per_pixel_alpha, bool *pre_multiplied_alpha,
bool *global_alpha, int *global_alpha_value);
+bool is_video_format(uint32_t format);
#endif
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c
index 26291db0a3cf..d647f68fd563 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c
@@ -122,6 +122,9 @@ bool amdgpu_dm_link_setup_psr(struct dc_stream_state *stream)
psr_config.allow_multi_disp_optimizations =
(amdgpu_dc_feature_mask & DC_PSR_ALLOW_MULTI_DISP_OPT);
+ if (!psr_su_set_dsc_slice_height(dc, link, stream, &psr_config))
+ return false;
+
ret = dc_link_setup_psr(link, stream, &psr_config, &psr_context);
}
diff --git a/drivers/gpu/drm/amd/display/dc/Makefile b/drivers/gpu/drm/amd/display/dc/Makefile
index b9effadfc4bb..94f156d57220 100644
--- a/drivers/gpu/drm/amd/display/dc/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/Makefile
@@ -64,9 +64,8 @@ AMD_DC = $(addsuffix /Makefile, $(addprefix $(FULL_AMD_DISPLAY_PATH)/dc/,$(DC_LI
include $(AMD_DC)
-DISPLAY_CORE = dc.o dc_stat.o dc_link.o dc_resource.o dc_hw_sequencer.o dc_sink.o \
-dc_surface.o dc_link_dp.o dc_link_ddc.o dc_debug.o dc_stream.o \
-dc_link_enc_cfg.o dc_link_dpia.o dc_link_dpcd.o
+DISPLAY_CORE = dc.o dc_stat.o dc_resource.o dc_hw_sequencer.o dc_sink.o \
+dc_surface.o dc_debug.o dc_stream.o dc_link_enc_cfg.o dc_link_exports.o
DISPLAY_CORE += dc_vm_helper.o
diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c
index a1a00f432168..27af9d3c2b73 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c
+++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c
@@ -33,7 +33,6 @@
#include "include/gpio_service_interface.h"
#include "include/grph_object_ctrl_defs.h"
#include "include/bios_parser_interface.h"
-#include "include/i2caux_interface.h"
#include "include/logger_interface.h"
#include "command_table.h"
diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c
index 074e70a5c458..e381de2429fa 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c
+++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c
@@ -32,7 +32,6 @@
#include "dc_bios_types.h"
#include "include/grph_object_ctrl_defs.h"
#include "include/bios_parser_interface.h"
-#include "include/i2caux_interface.h"
#include "include/logger_interface.h"
#include "command_table2.h"
@@ -1698,14 +1697,15 @@ static enum bp_result bios_parser_enable_disp_power_gating(
static enum bp_result bios_parser_enable_lvtma_control(
struct dc_bios *dcb,
uint8_t uc_pwr_on,
- uint8_t panel_instance)
+ uint8_t panel_instance,
+ uint8_t bypass_panel_control_wait)
{
struct bios_parser *bp = BP_FROM_DCB(dcb);
if (!bp->cmd_tbl.enable_lvtma_control)
return BP_RESULT_FAILURE;
- return bp->cmd_tbl.enable_lvtma_control(bp, uc_pwr_on, panel_instance);
+ return bp->cmd_tbl.enable_lvtma_control(bp, uc_pwr_on, panel_instance, bypass_panel_control_wait);
}
static bool bios_parser_is_accelerated_mode(
@@ -2929,7 +2929,6 @@ static enum bp_result construct_integrated_info(
struct atom_common_table_header *header;
struct atom_data_revision revision;
- struct clock_voltage_caps temp = {0, 0};
uint32_t i;
uint32_t j;
@@ -3032,14 +3031,8 @@ static enum bp_result construct_integrated_info(
for (i = 1; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
for (j = i; j > 0; --j) {
if (info->disp_clk_voltage[j].max_supported_clk <
- info->disp_clk_voltage[j-1].max_supported_clk
- ) {
- /* swap j and j - 1*/
- temp = info->disp_clk_voltage[j-1];
- info->disp_clk_voltage[j-1] =
- info->disp_clk_voltage[j];
- info->disp_clk_voltage[j] = temp;
- }
+ info->disp_clk_voltage[j-1].max_supported_clk)
+ swap(info->disp_clk_voltage[j-1], info->disp_clk_voltage[j]);
}
}
diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c
index f52f7ff7ead4..1ef9e4053bb7 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c
+++ b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c
@@ -986,7 +986,8 @@ static unsigned int get_smu_clock_info_v3_1(struct bios_parser *bp, uint8_t id)
static enum bp_result enable_lvtma_control(
struct bios_parser *bp,
uint8_t uc_pwr_on,
- uint8_t panel_instance);
+ uint8_t panel_instance,
+ uint8_t bypass_panel_control_wait);
static void init_enable_lvtma_control(struct bios_parser *bp)
{
@@ -998,7 +999,8 @@ static void init_enable_lvtma_control(struct bios_parser *bp)
static void enable_lvtma_control_dmcub(
struct dc_dmub_srv *dmcub,
uint8_t uc_pwr_on,
- uint8_t panel_instance)
+ uint8_t panel_instance,
+ uint8_t bypass_panel_control_wait)
{
union dmub_rb_cmd cmd;
@@ -1012,6 +1014,8 @@ static void enable_lvtma_control_dmcub(
uc_pwr_on;
cmd.lvtma_control.data.panel_inst =
panel_instance;
+ cmd.lvtma_control.data.bypass_panel_control_wait =
+ bypass_panel_control_wait;
dc_dmub_srv_cmd_queue(dmcub, &cmd);
dc_dmub_srv_cmd_execute(dmcub);
dc_dmub_srv_wait_idle(dmcub);
@@ -1021,7 +1025,8 @@ static void enable_lvtma_control_dmcub(
static enum bp_result enable_lvtma_control(
struct bios_parser *bp,
uint8_t uc_pwr_on,
- uint8_t panel_instance)
+ uint8_t panel_instance,
+ uint8_t bypass_panel_control_wait)
{
enum bp_result result = BP_RESULT_FAILURE;
@@ -1029,7 +1034,8 @@ static enum bp_result enable_lvtma_control(
bp->base.ctx->dc->debug.dmub_command_table) {
enable_lvtma_control_dmcub(bp->base.ctx->dmub_srv,
uc_pwr_on,
- panel_instance);
+ panel_instance,
+ bypass_panel_control_wait);
return BP_RESULT_OK;
}
return result;
diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table2.h b/drivers/gpu/drm/amd/display/dc/bios/command_table2.h
index be060b4b87db..b6d09bf6cf72 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/command_table2.h
+++ b/drivers/gpu/drm/amd/display/dc/bios/command_table2.h
@@ -96,7 +96,8 @@ struct cmd_tbl {
struct bios_parser *bp, uint8_t id);
enum bp_result (*enable_lvtma_control)(struct bios_parser *bp,
uint8_t uc_pwr_on,
- uint8_t panel_instance);
+ uint8_t panel_instance,
+ uint8_t bypass_panel_control_wait);
};
void dal_firmware_parser_init_cmd_tbl(struct bios_parser *bp);
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c
index f276abb63bcd..69691daf4dbb 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c
@@ -29,6 +29,7 @@
#include "dc_types.h"
#include "dccg.h"
#include "clk_mgr_internal.h"
+#include "link.h"
#include "dce100/dce_clk_mgr.h"
#include "dce110/dce110_clk_mgr.h"
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c
index 3ce0ee0d012f..694a9d3d92ae 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c
@@ -577,8 +577,7 @@ void dcn3_clk_mgr_construct(
void dcn3_clk_mgr_destroy(struct clk_mgr_internal *clk_mgr)
{
- if (clk_mgr->base.bw_params)
- kfree(clk_mgr->base.bw_params);
+ kfree(clk_mgr->base.bw_params);
if (clk_mgr->wm_range_table)
dm_helpers_free_gpu_mem(clk_mgr->base.ctx, DC_MEM_ALLOC_TYPE_GART,
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c
index 1c0569b1dc8f..f9e2e0c3095e 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c
@@ -47,6 +47,7 @@
#include "dcn30/dcn30_clk_mgr.h"
#include "dc_dmub_srv.h"
+#include "link.h"
#include "logger_types.h"
#undef DC_LOGGER
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c
index 20a06c04e4a1..89df7244b272 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c
@@ -48,7 +48,7 @@
#include "dcn31/dcn31_clk_mgr.h"
#include "dc_dmub_srv.h"
-#include "dc_link_dp.h"
+#include "link.h"
#include "dcn314_smu.h"
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_smu.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_smu.c
index f47cfe6b42bd..0765334f0825 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_smu.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_smu.c
@@ -146,6 +146,9 @@ static int dcn314_smu_send_msg_with_param(struct clk_mgr_internal *clk_mgr,
if (msg_id == VBIOSSMC_MSG_TransferTableDram2Smu &&
param == TABLE_WATERMARKS)
DC_LOG_WARNING("Watermarks table not configured properly by SMU");
+ else if (msg_id == VBIOSSMC_MSG_SetHardMinDcfclkByFreq ||
+ msg_id == VBIOSSMC_MSG_SetMinDeepSleepDcfclk)
+ DC_LOG_WARNING("DCFCLK_DPM is not enabled by BIOS");
else
ASSERT(0);
REG_WRITE(MP1_SMN_C2PMSG_91, VBIOSSMC_Result_OK);
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c
index 07edd9777edf..a737782b2840 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c
@@ -46,7 +46,7 @@
#define DC_LOGGER \
clk_mgr->base.base.ctx->logger
-#include "dc_link_dp.h"
+#include "link.h"
#define TO_CLK_MGR_DCN315(clk_mgr)\
container_of(clk_mgr, struct clk_mgr_dcn315, base)
@@ -87,6 +87,16 @@ static int dcn315_get_active_display_cnt_wa(
return display_count;
}
+static bool should_disable_otg(struct pipe_ctx *pipe)
+{
+ bool ret = true;
+
+ if (pipe->stream->link->link_enc && pipe->stream->link->link_enc->funcs->is_dig_enabled &&
+ pipe->stream->link->link_enc->funcs->is_dig_enabled(pipe->stream->link->link_enc))
+ ret = false;
+ return ret;
+}
+
static void dcn315_disable_otg_wa(struct clk_mgr *clk_mgr_base, struct dc_state *context, bool disable)
{
struct dc *dc = clk_mgr_base->ctx->dc;
@@ -98,12 +108,16 @@ static void dcn315_disable_otg_wa(struct clk_mgr *clk_mgr_base, struct dc_state
if (pipe->top_pipe || pipe->prev_odm_pipe)
continue;
if (pipe->stream && (pipe->stream->dpms_off || pipe->plane_state == NULL ||
- dc_is_virtual_signal(pipe->stream->signal))) {
- if (disable) {
- pipe->stream_res.tg->funcs->immediate_disable_crtc(pipe->stream_res.tg);
- reset_sync_context_for_pipe(dc, context, i);
- } else
- pipe->stream_res.tg->funcs->enable_crtc(pipe->stream_res.tg);
+ dc_is_virtual_signal(pipe->stream->signal))) {
+
+ /* This w/a should not trigger when we have a dig active */
+ if (should_disable_otg(pipe)) {
+ if (disable) {
+ pipe->stream_res.tg->funcs->immediate_disable_crtc(pipe->stream_res.tg);
+ reset_sync_context_for_pipe(dc, context, i);
+ } else
+ pipe->stream_res.tg->funcs->enable_crtc(pipe->stream_res.tg);
+ }
}
}
}
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c
index 3edc81e2d417..93db4dbee713 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c
@@ -39,7 +39,7 @@
#include "dcn316_smu.h"
#include "dm_helpers.h"
#include "dc_dmub_srv.h"
-#include "dc_link_dp.h"
+#include "link.h"
// DCN316 this is CLK1 instance
#define MAX_INSTANCE 7
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c
index 200fcec19186..61768bf726f8 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c
@@ -33,7 +33,7 @@
#include "reg_helper.h"
#include "core_types.h"
#include "dm_helpers.h"
-#include "dc_link_dp.h"
+#include "link.h"
#include "atomfirmware.h"
#include "smu13_driver_if.h"
@@ -255,6 +255,94 @@ static void dcn32_update_dppclk_dispclk_freq(struct clk_mgr_internal *clk_mgr, s
}
}
+static void dcn32_update_clocks_update_dentist(
+ struct clk_mgr_internal *clk_mgr,
+ struct dc_state *context,
+ uint32_t old_dispclk_khz)
+{
+ uint32_t new_disp_divider = 0;
+ uint32_t old_disp_divider = 0;
+ uint32_t new_dispclk_wdivider = 0;
+ uint32_t old_dispclk_wdivider = 0;
+ uint32_t i;
+
+ if (old_dispclk_khz == 0 || clk_mgr->base.clks.dispclk_khz == 0)
+ return;
+
+ new_disp_divider = DENTIST_DIVIDER_RANGE_SCALE_FACTOR
+ * clk_mgr->base.dentist_vco_freq_khz / clk_mgr->base.clks.dispclk_khz;
+ old_disp_divider = DENTIST_DIVIDER_RANGE_SCALE_FACTOR
+ * clk_mgr->base.dentist_vco_freq_khz / old_dispclk_khz;
+
+ new_dispclk_wdivider = dentist_get_did_from_divider(new_disp_divider);
+ old_dispclk_wdivider = dentist_get_did_from_divider(old_disp_divider);
+
+ /* When changing divider to or from 127, some extra programming is required to prevent corruption */
+ if (old_dispclk_wdivider == 127 && new_dispclk_wdivider != 127) {
+ for (i = 0; i < clk_mgr->base.ctx->dc->res_pool->pipe_count; i++) {
+ struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
+ uint32_t fifo_level;
+ struct dccg *dccg = clk_mgr->base.ctx->dc->res_pool->dccg;
+ struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc;
+ int32_t N;
+ int32_t j;
+
+ if (!pipe_ctx->stream)
+ continue;
+ /* Virtual encoders don't have this function */
+ if (!stream_enc->funcs->get_fifo_cal_average_level)
+ continue;
+ fifo_level = stream_enc->funcs->get_fifo_cal_average_level(
+ stream_enc);
+ N = fifo_level / 4;
+ dccg->funcs->set_fifo_errdet_ovr_en(
+ dccg,
+ true);
+ for (j = 0; j < N - 4; j++)
+ dccg->funcs->otg_drop_pixel(
+ dccg,
+ pipe_ctx->stream_res.tg->inst);
+ dccg->funcs->set_fifo_errdet_ovr_en(
+ dccg,
+ false);
+ }
+ } else if (new_dispclk_wdivider == 127 && old_dispclk_wdivider != 127) {
+ /* request clock with 126 divider first */
+ uint32_t temp_disp_divider = dentist_get_divider_from_did(126);
+ uint32_t temp_dispclk_khz = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR * clk_mgr->base.dentist_vco_freq_khz) / temp_disp_divider;
+
+ if (clk_mgr->smu_present)
+ dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_DISPCLK, khz_to_mhz_ceil(temp_dispclk_khz));
+
+ for (i = 0; i < clk_mgr->base.ctx->dc->res_pool->pipe_count; i++) {
+ struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
+ struct dccg *dccg = clk_mgr->base.ctx->dc->res_pool->dccg;
+ struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc;
+ uint32_t fifo_level;
+ int32_t N;
+ int32_t j;
+
+ if (!pipe_ctx->stream)
+ continue;
+ /* Virtual encoders don't have this function */
+ if (!stream_enc->funcs->get_fifo_cal_average_level)
+ continue;
+ fifo_level = stream_enc->funcs->get_fifo_cal_average_level(
+ stream_enc);
+ N = fifo_level / 4;
+ dccg->funcs->set_fifo_errdet_ovr_en(dccg, true);
+ for (j = 0; j < 12 - N; j++)
+ dccg->funcs->otg_add_pixel(dccg,
+ pipe_ctx->stream_res.tg->inst);
+ dccg->funcs->set_fifo_errdet_ovr_en(dccg, false);
+ }
+ }
+
+ /* do requested DISPCLK updates*/
+ if (clk_mgr->smu_present)
+ dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_DISPCLK, khz_to_mhz_ceil(clk_mgr->base.clks.dispclk_khz));
+}
+
static void dcn32_update_clocks(struct clk_mgr *clk_mgr_base,
struct dc_state *context,
bool safe_to_lower)
@@ -273,6 +361,7 @@ static void dcn32_update_clocks(struct clk_mgr *clk_mgr_base,
bool p_state_change_support;
bool fclk_p_state_change_support;
int total_plane_count;
+ int old_dispclk_khz = clk_mgr_base->clks.dispclk_khz;
if (dc->work_arounds.skip_clock_update)
return;
@@ -396,9 +485,6 @@ static void dcn32_update_clocks(struct clk_mgr *clk_mgr_base,
if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) {
clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz;
- if (clk_mgr->smu_present)
- dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_DISPCLK, khz_to_mhz_ceil(clk_mgr_base->clks.dispclk_khz));
-
update_dispclk = true;
}
@@ -418,13 +504,13 @@ static void dcn32_update_clocks(struct clk_mgr *clk_mgr_base,
if (dpp_clock_lowered) {
/* if clock is being lowered, increase DTO before lowering refclk */
dcn20_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower);
- dcn20_update_clocks_update_dentist(clk_mgr, context);
+ dcn32_update_clocks_update_dentist(clk_mgr, context, old_dispclk_khz);
if (clk_mgr->smu_present)
dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_DPPCLK, khz_to_mhz_ceil(clk_mgr_base->clks.dppclk_khz));
} else {
/* if clock is being raised, increase refclk before lowering DTO */
if (update_dppclk || update_dispclk)
- dcn20_update_clocks_update_dentist(clk_mgr, context);
+ dcn32_update_clocks_update_dentist(clk_mgr, context, old_dispclk_khz);
/* There is a check inside dcn20_update_clocks_update_dpp_dto which ensures
* that we do not lower dto when it is not safe to lower. We do not need to
* compare the current and new dppclk before calling this function.
@@ -783,8 +869,7 @@ void dcn32_clk_mgr_construct(
void dcn32_clk_mgr_destroy(struct clk_mgr_internal *clk_mgr)
{
- if (clk_mgr->base.bw_params)
- kfree(clk_mgr->base.bw_params);
+ kfree(clk_mgr->base.bw_params);
if (clk_mgr->wm_range_table)
dm_helpers_free_gpu_mem(clk_mgr->base.ctx, DC_MEM_ALLOC_TYPE_GART,
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index 0cb8d1f934d1..1c218c526650 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -33,6 +33,7 @@
#include "resource.h"
+#include "gpio_service_interface.h"
#include "clk_mgr.h"
#include "clock_source.h"
#include "dc_bios_types.h"
@@ -53,11 +54,10 @@
#include "link_enc_cfg.h"
#include "dc_link.h"
-#include "dc_link_ddc.h"
+#include "link.h"
#include "dm_helpers.h"
#include "mem_input.h"
-#include "dc_link_dp.h"
#include "dc_dmub_srv.h"
#include "dsc.h"
@@ -68,8 +68,6 @@
#include "dmub/dmub_srv.h"
-#include "i2caux_interface.h"
-
#include "dce/dmub_psr.h"
#include "dce/dmub_hw_lock_mgr.h"
@@ -382,16 +380,18 @@ static void dc_perf_trace_destroy(struct dc_perf_trace **perf_trace)
}
/**
- * dc_stream_adjust_vmin_vmax:
+ * dc_stream_adjust_vmin_vmax - look up pipe context & update parts of DRR
+ * @dc: dc reference
+ * @stream: Initial dc stream state
+ * @adjust: Updated parameters for vertical_total_min and vertical_total_max
*
* Looks up the pipe context of dc_stream_state and updates the
* vertical_total_min and vertical_total_max of the DRR, Dynamic Refresh
* Rate, which is a power-saving feature that targets reducing panel
* refresh rate while the screen is static
*
- * @dc: dc reference
- * @stream: Initial dc stream state
- * @adjust: Updated parameters for vertical_total_min and vertical_total_max
+ * Return: %true if the pipe context is found and adjusted;
+ * %false if the pipe context is not found.
*/
bool dc_stream_adjust_vmin_vmax(struct dc *dc,
struct dc_stream_state *stream,
@@ -419,14 +419,17 @@ bool dc_stream_adjust_vmin_vmax(struct dc *dc,
}
/**
- * dc_stream_get_last_used_drr_vtotal - dc_stream_get_last_vrr_vtotal
+ * dc_stream_get_last_used_drr_vtotal - Looks up the pipe context of
+ * dc_stream_state and gets the last VTOTAL used by DRR (Dynamic Refresh Rate)
*
* @dc: [in] dc reference
* @stream: [in] Initial dc stream state
- * @adjust: [in] Updated parameters for vertical_total_min and
+ * @refresh_rate: [in] new refresh_rate
*
- * Looks up the pipe context of dc_stream_state and gets the last VTOTAL used
- * by DRR (Dynamic Refresh Rate)
+ * Return: %true if the pipe context is found and there is an associated
+ * timing_generator for the DC;
+ * %false if the pipe context is not found or there is no
+ * timing_generator for the DC.
*/
bool dc_stream_get_last_used_drr_vtotal(struct dc *dc,
struct dc_stream_state *stream,
@@ -518,14 +521,15 @@ dc_stream_forward_dmcu_crc_window(struct dmcu *dmcu,
}
bool
-dc_stream_forward_crc_window(struct dc *dc,
- struct rect *rect, struct dc_stream_state *stream, bool is_stop)
+dc_stream_forward_crc_window(struct dc_stream_state *stream,
+ struct rect *rect, bool is_stop)
{
struct dmcu *dmcu;
struct dc_dmub_srv *dmub_srv;
struct otg_phy_mux mux_mapping;
struct pipe_ctx *pipe;
int i;
+ struct dc *dc = stream->ctx->dc;
for (i = 0; i < MAX_PIPES; i++) {
pipe = &dc->current_state->res_ctx.pipe_ctx[i];
@@ -566,7 +570,10 @@ dc_stream_forward_crc_window(struct dc *dc,
* once.
*
* By default, only CRC0 is configured, and the entire frame is used to
- * calculate the crc.
+ * calculate the CRC.
+ *
+ * Return: %false if the stream is not found or CRC capture is not supported;
+ * %true if the stream has been configured.
*/
bool dc_stream_configure_crc(struct dc *dc, struct dc_stream_state *stream,
struct crc_params *crc_window, bool enable, bool continuous)
@@ -635,7 +642,7 @@ bool dc_stream_configure_crc(struct dc *dc, struct dc_stream_state *stream,
* dc_stream_configure_crc needs to be called beforehand to enable CRCs.
*
* Return:
- * false if stream is not found, or if CRCs are not enabled.
+ * %false if stream is not found, or if CRCs are not enabled.
*/
bool dc_stream_get_crc(struct dc *dc, struct dc_stream_state *stream,
uint32_t *r_cr, uint32_t *g_y, uint32_t *b_cb)
@@ -862,6 +869,7 @@ static bool dc_construct_ctx(struct dc *dc,
dc_ctx->perf_trace = dc_perf_trace_create();
if (!dc_ctx->perf_trace) {
+ kfree(dc_ctx);
ASSERT_CRITICAL(false);
return false;
}
@@ -1191,7 +1199,7 @@ static void disable_vbios_mode_if_required(
pipe->stream_res.pix_clk_params.requested_pix_clk_100hz;
if (pix_clk_100hz != requested_pix_clk_100hz) {
- core_link_disable_stream(pipe);
+ link_set_dpms_off(pipe);
pipe->stream->dpms_off = false;
}
}
@@ -1299,7 +1307,7 @@ static void detect_edp_presence(struct dc *dc)
if (dc->config.edp_not_connected) {
edp_link->edp_sink_present = false;
} else {
- dc_link_detect_sink(edp_link, &type);
+ dc_link_detect_connection_type(edp_link, &type);
edp_link->edp_sink_present = (type != dc_connection_none);
}
}
@@ -1650,7 +1658,7 @@ bool dc_validate_boot_timing(const struct dc *dc,
return false;
}
- if (is_edp_ilr_optimization_required(link, crtc_timing)) {
+ if (link_is_edp_ilr_optimization_required(link, crtc_timing)) {
DC_LOG_EVENT_LINK_TRAINING("Seamless boot disabled to optimize eDP link rate\n");
return false;
}
@@ -1740,6 +1748,8 @@ void dc_z10_save_init(struct dc *dc)
*
* Applies given context to the hardware and copy it into current context.
* It's up to the user to release the src context afterwards.
+ *
+ * Return: an enum dc_status result code for the operation
*/
static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *context)
{
@@ -2007,8 +2017,9 @@ bool dc_commit_state(struct dc *dc, struct dc_state *context)
return result == DC_OK;
}
- if (!streams_changed(dc, context->streams, context->stream_count))
+ if (!streams_changed(dc, context->streams, context->stream_count)) {
return DC_OK;
+ }
DC_LOG_DC("%s: %d streams\n",
__func__, context->stream_count);
@@ -2948,6 +2959,9 @@ static void copy_stream_update_to_stream(struct dc *dc,
if (update->vsp_infopacket)
stream->vsp_infopacket = *update->vsp_infopacket;
+ if (update->adaptive_sync_infopacket)
+ stream->adaptive_sync_infopacket = *update->adaptive_sync_infopacket;
+
if (update->dither_option)
stream->dither_option = *update->dither_option;
@@ -3153,12 +3167,13 @@ static void commit_planes_do_stream_update(struct dc *dc,
stream_update->vsc_infopacket ||
stream_update->vsp_infopacket ||
stream_update->hfvsif_infopacket ||
+ stream_update->adaptive_sync_infopacket ||
stream_update->vtem_infopacket) {
resource_build_info_frame(pipe_ctx);
dc->hwss.update_info_frame(pipe_ctx);
if (dc_is_dp_signal(pipe_ctx->stream->signal))
- dp_source_sequence_trace(pipe_ctx->stream->link, DPCD_SOURCE_SEQ_AFTER_UPDATE_INFO_FRAME);
+ link_dp_source_sequence_trace(pipe_ctx->stream->link, DPCD_SOURCE_SEQ_AFTER_UPDATE_INFO_FRAME);
}
if (stream_update->hdr_static_metadata &&
@@ -3194,14 +3209,14 @@ static void commit_planes_do_stream_update(struct dc *dc,
continue;
if (stream_update->dsc_config)
- dp_update_dsc_config(pipe_ctx);
+ link_update_dsc_config(pipe_ctx);
if (stream_update->mst_bw_update) {
if (stream_update->mst_bw_update->is_increase)
- dc_link_increase_mst_payload(pipe_ctx, stream_update->mst_bw_update->mst_stream_bw);
- else
- dc_link_reduce_mst_payload(pipe_ctx, stream_update->mst_bw_update->mst_stream_bw);
- }
+ link_increase_mst_payload(pipe_ctx, stream_update->mst_bw_update->mst_stream_bw);
+ else
+ link_reduce_mst_payload(pipe_ctx, stream_update->mst_bw_update->mst_stream_bw);
+ }
if (stream_update->pending_test_pattern) {
dc_link_dp_set_test_pattern(stream->link,
@@ -3214,7 +3229,7 @@ static void commit_planes_do_stream_update(struct dc *dc,
if (stream_update->dpms_off) {
if (*stream_update->dpms_off) {
- core_link_disable_stream(pipe_ctx);
+ link_set_dpms_off(pipe_ctx);
/* for dpms, keep acquired resources*/
if (pipe_ctx->stream_res.audio && !dc->debug.az_endpoint_mute_only)
pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio);
@@ -3224,7 +3239,7 @@ static void commit_planes_do_stream_update(struct dc *dc,
} else {
if (get_seamless_boot_stream_count(context) == 0)
dc->hwss.prepare_bandwidth(dc, dc->current_state);
- core_link_enable_stream(dc->current_state, pipe_ctx);
+ link_set_dpms_on(dc->current_state, pipe_ctx);
}
}
@@ -3325,6 +3340,7 @@ static void commit_planes_for_stream(struct dc *dc,
struct pipe_ctx *top_pipe_to_program = NULL;
bool should_lock_all_pipes = (update_type != UPDATE_TYPE_FAST);
bool subvp_prev_use = false;
+ bool subvp_curr_use = false;
// Once we apply the new subvp context to hardware it won't be in the
// dc->current_state anymore, so we have to cache it before we apply
@@ -3334,6 +3350,21 @@ static void commit_planes_for_stream(struct dc *dc,
dc_z10_restore(dc);
+ if (update_type == UPDATE_TYPE_FULL) {
+ /* wait for all double-buffer activity to clear on all pipes */
+ int pipe_idx;
+
+ for (pipe_idx = 0; pipe_idx < dc->res_pool->pipe_count; pipe_idx++) {
+ struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[pipe_idx];
+
+ if (!pipe_ctx->stream)
+ continue;
+
+ if (pipe_ctx->stream_res.tg->funcs->wait_drr_doublebuffer_pending_clear)
+ pipe_ctx->stream_res.tg->funcs->wait_drr_doublebuffer_pending_clear(pipe_ctx->stream_res.tg);
+ }
+ }
+
if (get_seamless_boot_stream_count(context) > 0 && surface_count > 0) {
/* Optimize seamless boot flag keeps clocks and watermarks high until
* first flip. After first flip, optimization is required to lower
@@ -3381,6 +3412,15 @@ static void commit_planes_for_stream(struct dc *dc,
break;
}
+ for (i = 0; i < dc->res_pool->pipe_count; i++) {
+ struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
+
+ if (pipe->stream && pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) {
+ subvp_curr_use = true;
+ break;
+ }
+ }
+
if (stream->test_pattern.type != DP_TEST_PATTERN_VIDEO_MODE) {
struct pipe_ctx *mpcc_pipe;
struct pipe_ctx *odm_pipe;
@@ -3652,42 +3692,22 @@ static void commit_planes_for_stream(struct dc *dc,
top_pipe_to_program->stream_res.tg);
}
- /* For phantom pipe OTG enable, it has to be done after any previous pipe
- * that was in use has already been programmed at gotten its double buffer
- * update for "disable".
- */
- if (update_type != UPDATE_TYPE_FAST) {
- for (i = 0; i < dc->res_pool->pipe_count; i++) {
- struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
- struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i];
-
- /* If an active, non-phantom pipe is being transitioned into a phantom
- * pipe, wait for the double buffer update to complete first before we do
- * ANY phantom pipe programming.
- */
- if (pipe->stream && pipe->stream->mall_stream_config.type == SUBVP_PHANTOM &&
- old_pipe->stream && old_pipe->stream->mall_stream_config.type != SUBVP_PHANTOM) {
- old_pipe->stream_res.tg->funcs->wait_for_state(
- old_pipe->stream_res.tg,
- CRTC_STATE_VBLANK);
- old_pipe->stream_res.tg->funcs->wait_for_state(
- old_pipe->stream_res.tg,
- CRTC_STATE_VACTIVE);
- }
+ if (subvp_curr_use) {
+ /* If enabling subvp or transitioning from subvp->subvp, enable the
+ * phantom streams before we program front end for the phantom pipes.
+ */
+ if (update_type != UPDATE_TYPE_FAST) {
+ if (dc->hwss.enable_phantom_streams)
+ dc->hwss.enable_phantom_streams(dc, context);
}
- for (i = 0; i < dc->res_pool->pipe_count; i++) {
- struct pipe_ctx *new_pipe = &context->res_ctx.pipe_ctx[i];
+ }
- if ((new_pipe->stream && new_pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) ||
- subvp_prev_use) {
- // If old context or new context has phantom pipes, apply
- // the phantom timings now. We can't change the phantom
- // pipe configuration safely without driver acquiring
- // the DMCUB lock first.
- dc->hwss.apply_ctx_to_hw(dc, context);
- break;
- }
- }
+ if (subvp_prev_use && !subvp_curr_use) {
+ /* If disabling subvp, disable phantom streams after front end
+ * programming has completed (we turn on phantom OTG in order
+ * to complete the plane disable for phantom pipes).
+ */
+ dc->hwss.apply_ctx_to_hw(dc, context);
}
if (update_type != UPDATE_TYPE_FAST)
@@ -4285,7 +4305,7 @@ void dc_resume(struct dc *dc)
uint32_t i;
for (i = 0; i < dc->link_count; i++)
- core_link_resume(dc->links[i]);
+ link_resume(dc->links[i]);
}
bool dc_is_dmcu_initialized(struct dc *dc)
@@ -4704,7 +4724,7 @@ bool dc_enable_dmub_notifications(struct dc *dc)
/**
* dc_enable_dmub_outbox - Enables DMUB unsolicited notification
*
- * dc: [in] dc structure
+ * @dc: [in] dc structure
*
* Enables DMUB unsolicited notifications to x86 via outbox.
*/
@@ -4905,8 +4925,8 @@ enum dc_status dc_process_dmub_set_mst_slots(const struct dc *dc,
/**
* dc_process_dmub_dpia_hpd_int_enable - Submits DPIA DPD interruption
*
- * @dc [in]: dc structure
- * @hpd_int_enable [in]: 1 for hpd int enable, 0 to disable
+ * @dc: [in] dc structure
+ * @hpd_int_enable: [in] 1 for hpd int enable, 0 to disable
*
* Submits dpia hpd int enable command to dmub via inbox message
*/
@@ -4987,7 +5007,7 @@ void dc_notify_vsync_int_state(struct dc *dc, struct dc_stream_state *stream, bo
}
/**
- * dc_extended_blank_supported 0 Decide whether extended blank is supported
+ * dc_extended_blank_supported - Decide whether extended blank is supported
*
* @dc: [in] Current DC state
*
@@ -4996,7 +5016,7 @@ void dc_notify_vsync_int_state(struct dc *dc, struct dc_stream_state *stream, bo
* ability to enter z9/z10.
*
* Return:
- * Indicate whether extended blank is supported (true or false)
+ * Indicate whether extended blank is supported (%true or %false)
*/
bool dc_extended_blank_supported(struct dc *dc)
{
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
index c88f044666fe..c26e7258a91c 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
@@ -23,4949 +23,5 @@
*
*/
-#include <linux/slab.h>
-
-#include "dm_services.h"
-#include "atomfirmware.h"
-#include "dm_helpers.h"
-#include "dc.h"
-#include "grph_object_id.h"
-#include "gpio_service_interface.h"
-#include "core_status.h"
-#include "dc_link_dp.h"
-#include "dc_link_dpia.h"
-#include "dc_link_ddc.h"
-#include "link_hwss.h"
-#include "opp.h"
-
-#include "link_encoder.h"
-#include "hw_sequencer.h"
-#include "resource.h"
-#include "abm.h"
-#include "fixed31_32.h"
-#include "dpcd_defs.h"
-#include "dmcu.h"
-#include "hw/clk_mgr.h"
-#include "dce/dmub_psr.h"
-#include "dmub/dmub_srv.h"
-#include "inc/hw/panel_cntl.h"
-#include "inc/link_enc_cfg.h"
-#include "inc/link_dpcd.h"
-#include "link/link_dp_trace.h"
-
-#include "dc/dcn30/dcn30_vpg.h"
-
-#define DC_LOGGER_INIT(logger)
-
-#define LINK_INFO(...) \
- DC_LOG_HW_HOTPLUG( \
- __VA_ARGS__)
-
-#define RETIMER_REDRIVER_INFO(...) \
- DC_LOG_RETIMER_REDRIVER( \
- __VA_ARGS__)
-
-/*******************************************************************************
- * Private functions
- ******************************************************************************/
-static void dc_link_destruct(struct dc_link *link)
-{
- int i;
-
- if (link->hpd_gpio) {
- dal_gpio_destroy_irq(&link->hpd_gpio);
- link->hpd_gpio = NULL;
- }
-
- if (link->ddc)
- dal_ddc_service_destroy(&link->ddc);
-
- if (link->panel_cntl)
- link->panel_cntl->funcs->destroy(&link->panel_cntl);
-
- if (link->link_enc) {
- /* Update link encoder resource tracking variables. These are used for
- * the dynamic assignment of link encoders to streams. Virtual links
- * are not assigned encoder resources on creation.
- */
- if (link->link_id.id != CONNECTOR_ID_VIRTUAL) {
- link->dc->res_pool->link_encoders[link->eng_id - ENGINE_ID_DIGA] = NULL;
- link->dc->res_pool->dig_link_enc_count--;
- }
- link->link_enc->funcs->destroy(&link->link_enc);
- }
-
- if (link->local_sink)
- dc_sink_release(link->local_sink);
-
- for (i = 0; i < link->sink_count; ++i)
- dc_sink_release(link->remote_sinks[i]);
-}
-
-struct gpio *get_hpd_gpio(struct dc_bios *dcb,
- struct graphics_object_id link_id,
- struct gpio_service *gpio_service)
-{
- enum bp_result bp_result;
- struct graphics_object_hpd_info hpd_info;
- struct gpio_pin_info pin_info;
-
- if (dcb->funcs->get_hpd_info(dcb, link_id, &hpd_info) != BP_RESULT_OK)
- return NULL;
-
- bp_result = dcb->funcs->get_gpio_pin_info(dcb,
- hpd_info.hpd_int_gpio_uid, &pin_info);
-
- if (bp_result != BP_RESULT_OK) {
- ASSERT(bp_result == BP_RESULT_NORECORD);
- return NULL;
- }
-
- return dal_gpio_service_create_irq(gpio_service,
- pin_info.offset,
- pin_info.mask);
-}
-
-/*
- * Function: program_hpd_filter
- *
- * @brief
- * Programs HPD filter on associated HPD line
- *
- * @param [in] delay_on_connect_in_ms: Connect filter timeout
- * @param [in] delay_on_disconnect_in_ms: Disconnect filter timeout
- *
- * @return
- * true on success, false otherwise
- */
-static bool program_hpd_filter(const struct dc_link *link)
-{
- bool result = false;
- struct gpio *hpd;
- int delay_on_connect_in_ms = 0;
- int delay_on_disconnect_in_ms = 0;
-
- if (link->is_hpd_filter_disabled)
- return false;
- /* Verify feature is supported */
- switch (link->connector_signal) {
- case SIGNAL_TYPE_DVI_SINGLE_LINK:
- case SIGNAL_TYPE_DVI_DUAL_LINK:
- case SIGNAL_TYPE_HDMI_TYPE_A:
- /* Program hpd filter */
- delay_on_connect_in_ms = 500;
- delay_on_disconnect_in_ms = 100;
- break;
- case SIGNAL_TYPE_DISPLAY_PORT:
- case SIGNAL_TYPE_DISPLAY_PORT_MST:
- /* Program hpd filter to allow DP signal to settle */
- /* 500: not able to detect MST <-> SST switch as HPD is low for
- * only 100ms on DELL U2413
- * 0: some passive dongle still show aux mode instead of i2c
- * 20-50: not enough to hide bouncing HPD with passive dongle.
- * also see intermittent i2c read issues.
- */
- delay_on_connect_in_ms = 80;
- delay_on_disconnect_in_ms = 0;
- break;
- case SIGNAL_TYPE_LVDS:
- case SIGNAL_TYPE_EDP:
- default:
- /* Don't program hpd filter */
- return false;
- }
-
- /* Obtain HPD handle */
- hpd = get_hpd_gpio(link->ctx->dc_bios, link->link_id,
- link->ctx->gpio_service);
-
- if (!hpd)
- return result;
-
- /* Setup HPD filtering */
- if (dal_gpio_open(hpd, GPIO_MODE_INTERRUPT) == GPIO_RESULT_OK) {
- struct gpio_hpd_config config;
-
- config.delay_on_connect = delay_on_connect_in_ms;
- config.delay_on_disconnect = delay_on_disconnect_in_ms;
-
- dal_irq_setup_hpd_filter(hpd, &config);
-
- dal_gpio_close(hpd);
-
- result = true;
- } else {
- ASSERT_CRITICAL(false);
- }
-
- /* Release HPD handle */
- dal_gpio_destroy_irq(&hpd);
-
- return result;
-}
-
-bool dc_link_wait_for_t12(struct dc_link *link)
-{
- if (link->connector_signal == SIGNAL_TYPE_EDP && link->dc->hwss.edp_wait_for_T12) {
- link->dc->hwss.edp_wait_for_T12(link);
-
- return true;
- }
-
- return false;
-}
-
-/**
- * dc_link_detect_sink() - Determine if there is a sink connected
- *
- * @link: pointer to the dc link
- * @type: Returned connection type
- * Does not detect downstream devices, such as MST sinks
- * or display connected through active dongles
- */
-bool dc_link_detect_sink(struct dc_link *link, enum dc_connection_type *type)
-{
- uint32_t is_hpd_high = 0;
- struct gpio *hpd_pin;
-
- if (link->connector_signal == SIGNAL_TYPE_LVDS) {
- *type = dc_connection_single;
- return true;
- }
-
- if (link->connector_signal == SIGNAL_TYPE_EDP) {
- /*in case it is not on*/
- if (!link->dc->config.edp_no_power_sequencing)
- link->dc->hwss.edp_power_control(link, true);
- link->dc->hwss.edp_wait_for_hpd_ready(link, true);
- }
-
- /* Link may not have physical HPD pin. */
- if (link->ep_type != DISPLAY_ENDPOINT_PHY) {
- if (link->is_hpd_pending || !dc_link_dpia_query_hpd_status(link))
- *type = dc_connection_none;
- else
- *type = dc_connection_single;
-
- return true;
- }
-
- /* todo: may need to lock gpio access */
- hpd_pin = get_hpd_gpio(link->ctx->dc_bios, link->link_id,
- link->ctx->gpio_service);
- if (!hpd_pin)
- goto hpd_gpio_failure;
-
- dal_gpio_open(hpd_pin, GPIO_MODE_INTERRUPT);
- dal_gpio_get_value(hpd_pin, &is_hpd_high);
- dal_gpio_close(hpd_pin);
- dal_gpio_destroy_irq(&hpd_pin);
-
- if (is_hpd_high) {
- *type = dc_connection_single;
- /* TODO: need to do the actual detection */
- } else {
- *type = dc_connection_none;
- }
-
- return true;
-
-hpd_gpio_failure:
- return false;
-}
-
-static enum ddc_transaction_type get_ddc_transaction_type(enum signal_type sink_signal)
-{
- enum ddc_transaction_type transaction_type = DDC_TRANSACTION_TYPE_NONE;
-
- switch (sink_signal) {
- case SIGNAL_TYPE_DVI_SINGLE_LINK:
- case SIGNAL_TYPE_DVI_DUAL_LINK:
- case SIGNAL_TYPE_HDMI_TYPE_A:
- case SIGNAL_TYPE_LVDS:
- case SIGNAL_TYPE_RGB:
- transaction_type = DDC_TRANSACTION_TYPE_I2C;
- break;
-
- case SIGNAL_TYPE_DISPLAY_PORT:
- case SIGNAL_TYPE_EDP:
- transaction_type = DDC_TRANSACTION_TYPE_I2C_OVER_AUX;
- break;
-
- case SIGNAL_TYPE_DISPLAY_PORT_MST:
- /* MST does not use I2COverAux, but there is the
- * SPECIAL use case for "immediate dwnstrm device
- * access" (EPR#370830).
- */
- transaction_type = DDC_TRANSACTION_TYPE_I2C_OVER_AUX;
- break;
-
- default:
- break;
- }
-
- return transaction_type;
-}
-
-static enum signal_type get_basic_signal_type(struct graphics_object_id encoder,
- struct graphics_object_id downstream)
-{
- if (downstream.type == OBJECT_TYPE_CONNECTOR) {
- switch (downstream.id) {
- case CONNECTOR_ID_SINGLE_LINK_DVII:
- switch (encoder.id) {
- case ENCODER_ID_INTERNAL_DAC1:
- case ENCODER_ID_INTERNAL_KLDSCP_DAC1:
- case ENCODER_ID_INTERNAL_DAC2:
- case ENCODER_ID_INTERNAL_KLDSCP_DAC2:
- return SIGNAL_TYPE_RGB;
- default:
- return SIGNAL_TYPE_DVI_SINGLE_LINK;
- }
- break;
- case CONNECTOR_ID_DUAL_LINK_DVII:
- {
- switch (encoder.id) {
- case ENCODER_ID_INTERNAL_DAC1:
- case ENCODER_ID_INTERNAL_KLDSCP_DAC1:
- case ENCODER_ID_INTERNAL_DAC2:
- case ENCODER_ID_INTERNAL_KLDSCP_DAC2:
- return SIGNAL_TYPE_RGB;
- default:
- return SIGNAL_TYPE_DVI_DUAL_LINK;
- }
- }
- break;
- case CONNECTOR_ID_SINGLE_LINK_DVID:
- return SIGNAL_TYPE_DVI_SINGLE_LINK;
- case CONNECTOR_ID_DUAL_LINK_DVID:
- return SIGNAL_TYPE_DVI_DUAL_LINK;
- case CONNECTOR_ID_VGA:
- return SIGNAL_TYPE_RGB;
- case CONNECTOR_ID_HDMI_TYPE_A:
- return SIGNAL_TYPE_HDMI_TYPE_A;
- case CONNECTOR_ID_LVDS:
- return SIGNAL_TYPE_LVDS;
- case CONNECTOR_ID_DISPLAY_PORT:
- case CONNECTOR_ID_USBC:
- return SIGNAL_TYPE_DISPLAY_PORT;
- case CONNECTOR_ID_EDP:
- return SIGNAL_TYPE_EDP;
- default:
- return SIGNAL_TYPE_NONE;
- }
- } else if (downstream.type == OBJECT_TYPE_ENCODER) {
- switch (downstream.id) {
- case ENCODER_ID_EXTERNAL_NUTMEG:
- case ENCODER_ID_EXTERNAL_TRAVIS:
- return SIGNAL_TYPE_DISPLAY_PORT;
- default:
- return SIGNAL_TYPE_NONE;
- }
- }
-
- return SIGNAL_TYPE_NONE;
-}
-
-/*
- * dc_link_is_dp_sink_present() - Check if there is a native DP
- * or passive DP-HDMI dongle connected
- */
-bool dc_link_is_dp_sink_present(struct dc_link *link)
-{
- enum gpio_result gpio_result;
- uint32_t clock_pin = 0;
- uint8_t retry = 0;
- struct ddc *ddc;
-
- enum connector_id connector_id =
- dal_graphics_object_id_get_connector_id(link->link_id);
-
- bool present =
- ((connector_id == CONNECTOR_ID_DISPLAY_PORT) ||
- (connector_id == CONNECTOR_ID_EDP) ||
- (connector_id == CONNECTOR_ID_USBC));
-
- ddc = dal_ddc_service_get_ddc_pin(link->ddc);
-
- if (!ddc) {
- BREAK_TO_DEBUGGER();
- return present;
- }
-
- /* Open GPIO and set it to I2C mode */
- /* Note: this GpioMode_Input will be converted
- * to GpioConfigType_I2cAuxDualMode in GPIO component,
- * which indicates we need additional delay
- */
-
- if (dal_ddc_open(ddc, GPIO_MODE_INPUT,
- GPIO_DDC_CONFIG_TYPE_MODE_I2C) != GPIO_RESULT_OK) {
- dal_ddc_close(ddc);
-
- return present;
- }
-
- /*
- * Read GPIO: DP sink is present if both clock and data pins are zero
- *
- * [W/A] plug-unplug DP cable, sometimes customer board has
- * one short pulse on clk_pin(1V, < 1ms). DP will be config to HDMI/DVI
- * then monitor can't br light up. Add retry 3 times
- * But in real passive dongle, it need additional 3ms to detect
- */
- do {
- gpio_result = dal_gpio_get_value(ddc->pin_clock, &clock_pin);
- ASSERT(gpio_result == GPIO_RESULT_OK);
- if (clock_pin)
- udelay(1000);
- else
- break;
- } while (retry++ < 3);
-
- present = (gpio_result == GPIO_RESULT_OK) && !clock_pin;
-
- dal_ddc_close(ddc);
-
- return present;
-}
-
-/*
- * @brief
- * Detect output sink type
- */
-static enum signal_type link_detect_sink(struct dc_link *link,
- enum dc_detect_reason reason)
-{
- enum signal_type result;
- struct graphics_object_id enc_id;
-
- if (link->is_dig_mapping_flexible)
- enc_id = (struct graphics_object_id){.id = ENCODER_ID_UNKNOWN};
- else
- enc_id = link->link_enc->id;
- result = get_basic_signal_type(enc_id, link->link_id);
-
- /* Use basic signal type for link without physical connector. */
- if (link->ep_type != DISPLAY_ENDPOINT_PHY)
- return result;
-
- /* Internal digital encoder will detect only dongles
- * that require digital signal
- */
-
- /* Detection mechanism is different
- * for different native connectors.
- * LVDS connector supports only LVDS signal;
- * PCIE is a bus slot, the actual connector needs to be detected first;
- * eDP connector supports only eDP signal;
- * HDMI should check straps for audio
- */
-
- /* PCIE detects the actual connector on add-on board */
- if (link->link_id.id == CONNECTOR_ID_PCIE) {
- /* ZAZTODO implement PCIE add-on card detection */
- }
-
- switch (link->link_id.id) {
- case CONNECTOR_ID_HDMI_TYPE_A: {
- /* check audio support:
- * if native HDMI is not supported, switch to DVI
- */
- struct audio_support *aud_support =
- &link->dc->res_pool->audio_support;
-
- if (!aud_support->hdmi_audio_native)
- if (link->link_id.id == CONNECTOR_ID_HDMI_TYPE_A)
- result = SIGNAL_TYPE_DVI_SINGLE_LINK;
- }
- break;
- case CONNECTOR_ID_DISPLAY_PORT:
- case CONNECTOR_ID_USBC: {
- /* DP HPD short pulse. Passive DP dongle will not
- * have short pulse
- */
- if (reason != DETECT_REASON_HPDRX) {
- /* Check whether DP signal detected: if not -
- * we assume signal is DVI; it could be corrected
- * to HDMI after dongle detection
- */
- if (!dm_helpers_is_dp_sink_present(link))
- result = SIGNAL_TYPE_DVI_SINGLE_LINK;
- }
- }
- break;
- default:
- break;
- }
-
- return result;
-}
-
-static enum signal_type decide_signal_from_strap_and_dongle_type(enum display_dongle_type dongle_type,
- struct audio_support *audio_support)
-{
- enum signal_type signal = SIGNAL_TYPE_NONE;
-
- switch (dongle_type) {
- case DISPLAY_DONGLE_DP_HDMI_DONGLE:
- if (audio_support->hdmi_audio_on_dongle)
- signal = SIGNAL_TYPE_HDMI_TYPE_A;
- else
- signal = SIGNAL_TYPE_DVI_SINGLE_LINK;
- break;
- case DISPLAY_DONGLE_DP_DVI_DONGLE:
- signal = SIGNAL_TYPE_DVI_SINGLE_LINK;
- break;
- case DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE:
- if (audio_support->hdmi_audio_native)
- signal = SIGNAL_TYPE_HDMI_TYPE_A;
- else
- signal = SIGNAL_TYPE_DVI_SINGLE_LINK;
- break;
- default:
- signal = SIGNAL_TYPE_NONE;
- break;
- }
-
- return signal;
-}
-
-static enum signal_type dp_passive_dongle_detection(struct ddc_service *ddc,
- struct display_sink_capability *sink_cap,
- struct audio_support *audio_support)
-{
- dal_ddc_service_i2c_query_dp_dual_mode_adaptor(ddc, sink_cap);
-
- return decide_signal_from_strap_and_dongle_type(sink_cap->dongle_type,
- audio_support);
-}
-
-static void link_disconnect_sink(struct dc_link *link)
-{
- if (link->local_sink) {
- dc_sink_release(link->local_sink);
- link->local_sink = NULL;
- }
-
- link->dpcd_sink_count = 0;
- //link->dpcd_caps.dpcd_rev.raw = 0;
-}
-
-static void link_disconnect_remap(struct dc_sink *prev_sink, struct dc_link *link)
-{
- dc_sink_release(link->local_sink);
- link->local_sink = prev_sink;
-}
-
-#if defined(CONFIG_DRM_AMD_DC_HDCP)
-bool dc_link_is_hdcp14(struct dc_link *link, enum signal_type signal)
-{
- bool ret = false;
-
- switch (signal) {
- case SIGNAL_TYPE_DISPLAY_PORT:
- case SIGNAL_TYPE_DISPLAY_PORT_MST:
- ret = link->hdcp_caps.bcaps.bits.HDCP_CAPABLE;
- break;
- case SIGNAL_TYPE_DVI_SINGLE_LINK:
- case SIGNAL_TYPE_DVI_DUAL_LINK:
- case SIGNAL_TYPE_HDMI_TYPE_A:
- /* HDMI doesn't tell us its HDCP(1.4) capability, so assume to always be capable,
- * we can poll for bksv but some displays have an issue with this. Since its so rare
- * for a display to not be 1.4 capable, this assumtion is ok
- */
- ret = true;
- break;
- default:
- break;
- }
- return ret;
-}
-
-bool dc_link_is_hdcp22(struct dc_link *link, enum signal_type signal)
-{
- bool ret = false;
-
- switch (signal) {
- case SIGNAL_TYPE_DISPLAY_PORT:
- case SIGNAL_TYPE_DISPLAY_PORT_MST:
- ret = (link->hdcp_caps.bcaps.bits.HDCP_CAPABLE &&
- link->hdcp_caps.rx_caps.fields.byte0.hdcp_capable &&
- (link->hdcp_caps.rx_caps.fields.version == 0x2)) ? 1 : 0;
- break;
- case SIGNAL_TYPE_DVI_SINGLE_LINK:
- case SIGNAL_TYPE_DVI_DUAL_LINK:
- case SIGNAL_TYPE_HDMI_TYPE_A:
- ret = (link->hdcp_caps.rx_caps.fields.version == 0x4) ? 1:0;
- break;
- default:
- break;
- }
-
- return ret;
-}
-
-static void query_hdcp_capability(enum signal_type signal, struct dc_link *link)
-{
- struct hdcp_protection_message msg22;
- struct hdcp_protection_message msg14;
-
- memset(&msg22, 0, sizeof(struct hdcp_protection_message));
- memset(&msg14, 0, sizeof(struct hdcp_protection_message));
- memset(link->hdcp_caps.rx_caps.raw, 0,
- sizeof(link->hdcp_caps.rx_caps.raw));
-
- if ((link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT &&
- link->ddc->transaction_type ==
- DDC_TRANSACTION_TYPE_I2C_OVER_AUX) ||
- link->connector_signal == SIGNAL_TYPE_EDP) {
- msg22.data = link->hdcp_caps.rx_caps.raw;
- msg22.length = sizeof(link->hdcp_caps.rx_caps.raw);
- msg22.msg_id = HDCP_MESSAGE_ID_RX_CAPS;
- } else {
- msg22.data = &link->hdcp_caps.rx_caps.fields.version;
- msg22.length = sizeof(link->hdcp_caps.rx_caps.fields.version);
- msg22.msg_id = HDCP_MESSAGE_ID_HDCP2VERSION;
- }
- msg22.version = HDCP_VERSION_22;
- msg22.link = HDCP_LINK_PRIMARY;
- msg22.max_retries = 5;
- dc_process_hdcp_msg(signal, link, &msg22);
-
- if (signal == SIGNAL_TYPE_DISPLAY_PORT || signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
- msg14.data = &link->hdcp_caps.bcaps.raw;
- msg14.length = sizeof(link->hdcp_caps.bcaps.raw);
- msg14.msg_id = HDCP_MESSAGE_ID_READ_BCAPS;
- msg14.version = HDCP_VERSION_14;
- msg14.link = HDCP_LINK_PRIMARY;
- msg14.max_retries = 5;
-
- dc_process_hdcp_msg(signal, link, &msg14);
- }
-
-}
-#endif
-
-static void read_current_link_settings_on_detect(struct dc_link *link)
-{
- union lane_count_set lane_count_set = {0};
- uint8_t link_bw_set;
- uint8_t link_rate_set;
- uint32_t read_dpcd_retry_cnt = 10;
- enum dc_status status = DC_ERROR_UNEXPECTED;
- int i;
- union max_down_spread max_down_spread = {0};
-
- // Read DPCD 00101h to find out the number of lanes currently set
- for (i = 0; i < read_dpcd_retry_cnt; i++) {
- status = core_link_read_dpcd(link,
- DP_LANE_COUNT_SET,
- &lane_count_set.raw,
- sizeof(lane_count_set));
- /* First DPCD read after VDD ON can fail if the particular board
- * does not have HPD pin wired correctly. So if DPCD read fails,
- * which it should never happen, retry a few times. Target worst
- * case scenario of 80 ms.
- */
- if (status == DC_OK) {
- link->cur_link_settings.lane_count =
- lane_count_set.bits.LANE_COUNT_SET;
- break;
- }
-
- msleep(8);
- }
-
- // Read DPCD 00100h to find if standard link rates are set
- core_link_read_dpcd(link, DP_LINK_BW_SET,
- &link_bw_set, sizeof(link_bw_set));
-
- if (link_bw_set == 0) {
- if (link->connector_signal == SIGNAL_TYPE_EDP) {
- /* If standard link rates are not being used,
- * Read DPCD 00115h to find the edp link rate set used
- */
- core_link_read_dpcd(link, DP_LINK_RATE_SET,
- &link_rate_set, sizeof(link_rate_set));
-
- // edp_supported_link_rates_count = 0 for DP
- if (link_rate_set < link->dpcd_caps.edp_supported_link_rates_count) {
- link->cur_link_settings.link_rate =
- link->dpcd_caps.edp_supported_link_rates[link_rate_set];
- link->cur_link_settings.link_rate_set = link_rate_set;
- link->cur_link_settings.use_link_rate_set = true;
- }
- } else {
- // Link Rate not found. Seamless boot may not work.
- ASSERT(false);
- }
- } else {
- link->cur_link_settings.link_rate = link_bw_set;
- link->cur_link_settings.use_link_rate_set = false;
- }
- // Read DPCD 00003h to find the max down spread.
- core_link_read_dpcd(link, DP_MAX_DOWNSPREAD,
- &max_down_spread.raw, sizeof(max_down_spread));
- link->cur_link_settings.link_spread =
- max_down_spread.bits.MAX_DOWN_SPREAD ?
- LINK_SPREAD_05_DOWNSPREAD_30KHZ : LINK_SPREAD_DISABLED;
-}
-
-static bool detect_dp(struct dc_link *link,
- struct display_sink_capability *sink_caps,
- enum dc_detect_reason reason)
-{
- struct audio_support *audio_support = &link->dc->res_pool->audio_support;
-
- sink_caps->signal = link_detect_sink(link, reason);
- sink_caps->transaction_type =
- get_ddc_transaction_type(sink_caps->signal);
-
- if (sink_caps->transaction_type == DDC_TRANSACTION_TYPE_I2C_OVER_AUX) {
- sink_caps->signal = SIGNAL_TYPE_DISPLAY_PORT;
- if (!detect_dp_sink_caps(link))
- return false;
-
- if (is_dp_branch_device(link))
- /* DP SST branch */
- link->type = dc_connection_sst_branch;
- } else {
- /* DP passive dongles */
- sink_caps->signal = dp_passive_dongle_detection(link->ddc,
- sink_caps,
- audio_support);
- link->dpcd_caps.dongle_type = sink_caps->dongle_type;
- link->dpcd_caps.is_dongle_type_one = sink_caps->is_dongle_type_one;
- link->dpcd_caps.dpcd_rev.raw = 0;
- }
-
- return true;
-}
-
-static bool is_same_edid(struct dc_edid *old_edid, struct dc_edid *new_edid)
-{
- if (old_edid->length != new_edid->length)
- return false;
-
- if (new_edid->length == 0)
- return false;
-
- return (memcmp(old_edid->raw_edid,
- new_edid->raw_edid, new_edid->length) == 0);
-}
-
-static bool wait_for_entering_dp_alt_mode(struct dc_link *link)
-{
- /**
- * something is terribly wrong if time out is > 200ms. (5Hz)
- * 500 microseconds * 400 tries us 200 ms
- **/
- unsigned int sleep_time_in_microseconds = 500;
- unsigned int tries_allowed = 400;
- bool is_in_alt_mode;
- unsigned long long enter_timestamp;
- unsigned long long finish_timestamp;
- unsigned long long time_taken_in_ns;
- int tries_taken;
-
- DC_LOGGER_INIT(link->ctx->logger);
-
- if (!link->link_enc->funcs->is_in_alt_mode)
- return true;
-
- is_in_alt_mode = link->link_enc->funcs->is_in_alt_mode(link->link_enc);
- DC_LOG_WARNING("DP Alt mode state on HPD: %d\n", is_in_alt_mode);
-
- if (is_in_alt_mode)
- return true;
-
- enter_timestamp = dm_get_timestamp(link->ctx);
-
- for (tries_taken = 0; tries_taken < tries_allowed; tries_taken++) {
- udelay(sleep_time_in_microseconds);
- /* ask the link if alt mode is enabled, if so return ok */
- if (link->link_enc->funcs->is_in_alt_mode(link->link_enc)) {
- finish_timestamp = dm_get_timestamp(link->ctx);
- time_taken_in_ns =
- dm_get_elapse_time_in_ns(link->ctx,
- finish_timestamp,
- enter_timestamp);
- DC_LOG_WARNING("Alt mode entered finished after %llu ms\n",
- div_u64(time_taken_in_ns, 1000000));
- return true;
- }
- }
- finish_timestamp = dm_get_timestamp(link->ctx);
- time_taken_in_ns = dm_get_elapse_time_in_ns(link->ctx, finish_timestamp,
- enter_timestamp);
- DC_LOG_WARNING("Alt mode has timed out after %llu ms\n",
- div_u64(time_taken_in_ns, 1000000));
- return false;
-}
-
-static void apply_dpia_mst_dsc_always_on_wa(struct dc_link *link)
-{
- /* Apply work around for tunneled MST on certain USB4 docks. Always use DSC if dock
- * reports DSC support.
- */
- if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA &&
- link->type == dc_connection_mst_branch &&
- link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_90CC24 &&
- link->dpcd_caps.branch_hw_revision == DP_BRANCH_HW_REV_20 &&
- link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_SUPPORT &&
- !link->dc->debug.dpia_debug.bits.disable_mst_dsc_work_around)
- link->wa_flags.dpia_mst_dsc_always_on = true;
-}
-
-static void revert_dpia_mst_dsc_always_on_wa(struct dc_link *link)
-{
- /* Disable work around which keeps DSC on for tunneled MST on certain USB4 docks. */
- if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA)
- link->wa_flags.dpia_mst_dsc_always_on = false;
-}
-
-static bool discover_dp_mst_topology(struct dc_link *link, enum dc_detect_reason reason)
-{
- DC_LOGGER_INIT(link->ctx->logger);
-
- LINK_INFO("link=%d, mst branch is now Connected\n",
- link->link_index);
-
- link->type = dc_connection_mst_branch;
- apply_dpia_mst_dsc_always_on_wa(link);
-
- dm_helpers_dp_update_branch_info(link->ctx, link);
- if (dm_helpers_dp_mst_start_top_mgr(link->ctx,
- link, (reason == DETECT_REASON_BOOT || reason == DETECT_REASON_RESUMEFROMS3S4))) {
- link_disconnect_sink(link);
- } else {
- link->type = dc_connection_sst_branch;
- }
-
- return link->type == dc_connection_mst_branch;
-}
-
-bool reset_cur_dp_mst_topology(struct dc_link *link)
-{
- DC_LOGGER_INIT(link->ctx->logger);
-
- LINK_INFO("link=%d, mst branch is now Disconnected\n",
- link->link_index);
-
- revert_dpia_mst_dsc_always_on_wa(link);
- return dm_helpers_dp_mst_stop_top_mgr(link->ctx, link);
-}
-
-static bool should_prepare_phy_clocks_for_link_verification(const struct dc *dc,
- enum dc_detect_reason reason)
-{
- int i;
- bool can_apply_seamless_boot = false;
-
- for (i = 0; i < dc->current_state->stream_count; i++) {
- if (dc->current_state->streams[i]->apply_seamless_boot_optimization) {
- can_apply_seamless_boot = true;
- break;
- }
- }
-
- return !can_apply_seamless_boot && reason != DETECT_REASON_BOOT;
-}
-
-static void prepare_phy_clocks_for_destructive_link_verification(const struct dc *dc)
-{
- dc_z10_restore(dc);
- clk_mgr_exit_optimized_pwr_state(dc, dc->clk_mgr);
-}
-
-static void restore_phy_clocks_for_destructive_link_verification(const struct dc *dc)
-{
- clk_mgr_optimize_pwr_state(dc, dc->clk_mgr);
-}
-
-static void set_all_streams_dpms_off_for_link(struct dc_link *link)
-{
- int i;
- struct pipe_ctx *pipe_ctx;
- struct dc_stream_update stream_update;
- bool dpms_off = true;
- struct link_resource link_res = {0};
-
- memset(&stream_update, 0, sizeof(stream_update));
- stream_update.dpms_off = &dpms_off;
-
- for (i = 0; i < MAX_PIPES; i++) {
- pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i];
- if (pipe_ctx && pipe_ctx->stream && !pipe_ctx->stream->dpms_off &&
- pipe_ctx->stream->link == link && !pipe_ctx->prev_odm_pipe) {
- stream_update.stream = pipe_ctx->stream;
- dc_commit_updates_for_stream(link->ctx->dc, NULL, 0,
- pipe_ctx->stream, &stream_update,
- link->ctx->dc->current_state);
- }
- }
-
- /* link can be also enabled by vbios. In this case it is not recorded
- * in pipe_ctx. Disable link phy here to make sure it is completely off
- */
- dp_disable_link_phy(link, &link_res, link->connector_signal);
-}
-
-static void verify_link_capability_destructive(struct dc_link *link,
- struct dc_sink *sink,
- enum dc_detect_reason reason)
-{
- bool should_prepare_phy_clocks =
- should_prepare_phy_clocks_for_link_verification(link->dc, reason);
-
- if (should_prepare_phy_clocks)
- prepare_phy_clocks_for_destructive_link_verification(link->dc);
-
- if (dc_is_dp_signal(link->local_sink->sink_signal)) {
- struct dc_link_settings known_limit_link_setting =
- dp_get_max_link_cap(link);
- set_all_streams_dpms_off_for_link(link);
- dp_verify_link_cap_with_retries(
- link, &known_limit_link_setting,
- LINK_TRAINING_MAX_VERIFY_RETRY);
- } else {
- ASSERT(0);
- }
-
- if (should_prepare_phy_clocks)
- restore_phy_clocks_for_destructive_link_verification(link->dc);
-}
-
-static void verify_link_capability_non_destructive(struct dc_link *link)
-{
- if (dc_is_dp_signal(link->local_sink->sink_signal)) {
- if (dc_is_embedded_signal(link->local_sink->sink_signal) ||
- link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA)
- /* TODO - should we check link encoder's max link caps here?
- * How do we know which link encoder to check from?
- */
- link->verified_link_cap = link->reported_link_cap;
- else
- link->verified_link_cap = dp_get_max_link_cap(link);
- }
-}
-
-static bool should_verify_link_capability_destructively(struct dc_link *link,
- enum dc_detect_reason reason)
-{
- bool destrictive = false;
- struct dc_link_settings max_link_cap;
- bool is_link_enc_unavailable = link->link_enc &&
- link->dc->res_pool->funcs->link_encs_assign &&
- !link_enc_cfg_is_link_enc_avail(
- link->ctx->dc,
- link->link_enc->preferred_engine,
- link);
-
- if (dc_is_dp_signal(link->local_sink->sink_signal)) {
- max_link_cap = dp_get_max_link_cap(link);
- destrictive = true;
-
- if (link->dc->debug.skip_detection_link_training ||
- dc_is_embedded_signal(link->local_sink->sink_signal) ||
- link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) {
- destrictive = false;
- } else if (dp_get_link_encoding_format(&max_link_cap) ==
- DP_8b_10b_ENCODING) {
- if (link->dpcd_caps.is_mst_capable ||
- is_link_enc_unavailable) {
- destrictive = false;
- }
- }
- }
-
- return destrictive;
-}
-
-static void verify_link_capability(struct dc_link *link, struct dc_sink *sink,
- enum dc_detect_reason reason)
-{
- if (should_verify_link_capability_destructively(link, reason))
- verify_link_capability_destructive(link, sink, reason);
- else
- verify_link_capability_non_destructive(link);
-}
-
-
-/**
- * detect_link_and_local_sink() - Detect if a sink is attached to a given link
- *
- * link->local_sink is created or destroyed as needed.
- *
- * This does not create remote sinks.
- */
-static bool detect_link_and_local_sink(struct dc_link *link,
- enum dc_detect_reason reason)
-{
- struct dc_sink_init_data sink_init_data = { 0 };
- struct display_sink_capability sink_caps = { 0 };
- uint32_t i;
- bool converter_disable_audio = false;
- struct audio_support *aud_support = &link->dc->res_pool->audio_support;
- bool same_edid = false;
- enum dc_edid_status edid_status;
- struct dc_context *dc_ctx = link->ctx;
- struct dc *dc = dc_ctx->dc;
- struct dc_sink *sink = NULL;
- struct dc_sink *prev_sink = NULL;
- struct dpcd_caps prev_dpcd_caps;
- enum dc_connection_type new_connection_type = dc_connection_none;
- const uint32_t post_oui_delay = 30; // 30ms
-
- DC_LOGGER_INIT(link->ctx->logger);
-
- if (dc_is_virtual_signal(link->connector_signal))
- return false;
-
- if (((link->connector_signal == SIGNAL_TYPE_LVDS ||
- link->connector_signal == SIGNAL_TYPE_EDP) &&
- (!link->dc->config.allow_edp_hotplug_detection)) &&
- link->local_sink) {
- // need to re-write OUI and brightness in resume case
- if (link->connector_signal == SIGNAL_TYPE_EDP &&
- (link->dpcd_sink_ext_caps.bits.oled == 1)) {
- dpcd_set_source_specific_data(link);
- msleep(post_oui_delay);
- dc_link_set_default_brightness_aux(link);
- //TODO: use cached
- }
-
- return true;
- }
-
- if (!dc_link_detect_sink(link, &new_connection_type)) {
- BREAK_TO_DEBUGGER();
- return false;
- }
-
- prev_sink = link->local_sink;
- if (prev_sink) {
- dc_sink_retain(prev_sink);
- memcpy(&prev_dpcd_caps, &link->dpcd_caps, sizeof(struct dpcd_caps));
- }
-
- link_disconnect_sink(link);
- if (new_connection_type != dc_connection_none) {
- link->type = new_connection_type;
- link->link_state_valid = false;
-
- /* From Disconnected-to-Connected. */
- switch (link->connector_signal) {
- case SIGNAL_TYPE_HDMI_TYPE_A: {
- sink_caps.transaction_type = DDC_TRANSACTION_TYPE_I2C;
- if (aud_support->hdmi_audio_native)
- sink_caps.signal = SIGNAL_TYPE_HDMI_TYPE_A;
- else
- sink_caps.signal = SIGNAL_TYPE_DVI_SINGLE_LINK;
- break;
- }
-
- case SIGNAL_TYPE_DVI_SINGLE_LINK: {
- sink_caps.transaction_type = DDC_TRANSACTION_TYPE_I2C;
- sink_caps.signal = SIGNAL_TYPE_DVI_SINGLE_LINK;
- break;
- }
-
- case SIGNAL_TYPE_DVI_DUAL_LINK: {
- sink_caps.transaction_type = DDC_TRANSACTION_TYPE_I2C;
- sink_caps.signal = SIGNAL_TYPE_DVI_DUAL_LINK;
- break;
- }
-
- case SIGNAL_TYPE_LVDS: {
- sink_caps.transaction_type = DDC_TRANSACTION_TYPE_I2C;
- sink_caps.signal = SIGNAL_TYPE_LVDS;
- break;
- }
-
- case SIGNAL_TYPE_EDP: {
- read_current_link_settings_on_detect(link);
-
- detect_edp_sink_caps(link);
- read_current_link_settings_on_detect(link);
-
- /* Disable power sequence on MIPI panel + converter
- */
- if (dc->config.enable_mipi_converter_optimization &&
- dc_ctx->dce_version == DCN_VERSION_3_01 &&
- link->dpcd_caps.sink_dev_id == DP_BRANCH_DEVICE_ID_0022B9 &&
- memcmp(&link->dpcd_caps.branch_dev_name, DP_SINK_BRANCH_DEV_NAME_7580,
- sizeof(link->dpcd_caps.branch_dev_name)) == 0) {
- dc->config.edp_no_power_sequencing = true;
-
- if (!link->dpcd_caps.set_power_state_capable_edp)
- link->wa_flags.dp_keep_receiver_powered = true;
- }
-
- sink_caps.transaction_type = DDC_TRANSACTION_TYPE_I2C_OVER_AUX;
- sink_caps.signal = SIGNAL_TYPE_EDP;
- break;
- }
-
- case SIGNAL_TYPE_DISPLAY_PORT: {
- /* wa HPD high coming too early*/
- if (link->ep_type == DISPLAY_ENDPOINT_PHY &&
- link->link_enc->features.flags.bits.DP_IS_USB_C == 1) {
- /* if alt mode times out, return false */
- if (!wait_for_entering_dp_alt_mode(link))
- return false;
- }
-
- if (!detect_dp(link, &sink_caps, reason)) {
- if (prev_sink)
- dc_sink_release(prev_sink);
- return false;
- }
-
- /* Active SST downstream branch device unplug*/
- if (link->type == dc_connection_sst_branch &&
- link->dpcd_caps.sink_count.bits.SINK_COUNT == 0) {
- if (prev_sink)
- /* Downstream unplug */
- dc_sink_release(prev_sink);
- return true;
- }
-
- /* disable audio for non DP to HDMI active sst converter */
- if (link->type == dc_connection_sst_branch &&
- is_dp_active_dongle(link) &&
- (link->dpcd_caps.dongle_type !=
- DISPLAY_DONGLE_DP_HDMI_CONVERTER))
- converter_disable_audio = true;
- break;
- }
-
- default:
- DC_ERROR("Invalid connector type! signal:%d\n",
- link->connector_signal);
- if (prev_sink)
- dc_sink_release(prev_sink);
- return false;
- } /* switch() */
-
- if (link->dpcd_caps.sink_count.bits.SINK_COUNT)
- link->dpcd_sink_count =
- link->dpcd_caps.sink_count.bits.SINK_COUNT;
- else
- link->dpcd_sink_count = 1;
-
- dal_ddc_service_set_transaction_type(link->ddc,
- sink_caps.transaction_type);
-
- link->aux_mode =
- dal_ddc_service_is_in_aux_transaction_mode(link->ddc);
-
- sink_init_data.link = link;
- sink_init_data.sink_signal = sink_caps.signal;
-
- sink = dc_sink_create(&sink_init_data);
- if (!sink) {
- DC_ERROR("Failed to create sink!\n");
- if (prev_sink)
- dc_sink_release(prev_sink);
- return false;
- }
-
- sink->link->dongle_max_pix_clk = sink_caps.max_hdmi_pixel_clock;
- sink->converter_disable_audio = converter_disable_audio;
-
- /* dc_sink_create returns a new reference */
- link->local_sink = sink;
-
- edid_status = dm_helpers_read_local_edid(link->ctx,
- link, sink);
-
- switch (edid_status) {
- case EDID_BAD_CHECKSUM:
- DC_LOG_ERROR("EDID checksum invalid.\n");
- break;
- case EDID_PARTIAL_VALID:
- DC_LOG_ERROR("Partial EDID valid, abandon invalid blocks.\n");
- break;
- case EDID_NO_RESPONSE:
- DC_LOG_ERROR("No EDID read.\n");
- /*
- * Abort detection for non-DP connectors if we have
- * no EDID
- *
- * DP needs to report as connected if HDP is high
- * even if we have no EDID in order to go to
- * fail-safe mode
- */
- if (dc_is_hdmi_signal(link->connector_signal) ||
- dc_is_dvi_signal(link->connector_signal)) {
- if (prev_sink)
- dc_sink_release(prev_sink);
-
- return false;
- }
-
- if (link->type == dc_connection_sst_branch &&
- link->dpcd_caps.dongle_type ==
- DISPLAY_DONGLE_DP_VGA_CONVERTER &&
- reason == DETECT_REASON_HPDRX) {
- /* Abort detection for DP-VGA adapters when EDID
- * can't be read and detection reason is VGA-side
- * hotplug
- */
- if (prev_sink)
- dc_sink_release(prev_sink);
- link_disconnect_sink(link);
-
- return true;
- }
-
- break;
- default:
- break;
- }
-
- // Check if edid is the same
- if ((prev_sink) &&
- (edid_status == EDID_THE_SAME || edid_status == EDID_OK))
- same_edid = is_same_edid(&prev_sink->dc_edid,
- &sink->dc_edid);
-
- if (sink->edid_caps.panel_patch.skip_scdc_overwrite)
- link->ctx->dc->debug.hdmi20_disable = true;
-
- if (link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT &&
- sink_caps.transaction_type ==
- DDC_TRANSACTION_TYPE_I2C_OVER_AUX) {
- /*
- * TODO debug why Dell 2413 doesn't like
- * two link trainings
- */
-#if defined(CONFIG_DRM_AMD_DC_HDCP)
- query_hdcp_capability(sink->sink_signal, link);
-#endif
- } else {
- // If edid is the same, then discard new sink and revert back to original sink
- if (same_edid) {
- link_disconnect_remap(prev_sink, link);
- sink = prev_sink;
- prev_sink = NULL;
- }
-#if defined(CONFIG_DRM_AMD_DC_HDCP)
- query_hdcp_capability(sink->sink_signal, link);
-#endif
- }
-
- /* HDMI-DVI Dongle */
- if (sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A &&
- !sink->edid_caps.edid_hdmi)
- sink->sink_signal = SIGNAL_TYPE_DVI_SINGLE_LINK;
-
- if (link->local_sink && dc_is_dp_signal(sink_caps.signal))
- dp_trace_init(link);
-
- /* Connectivity log: detection */
- for (i = 0; i < sink->dc_edid.length / DC_EDID_BLOCK_SIZE; i++) {
- CONN_DATA_DETECT(link,
- &sink->dc_edid.raw_edid[i * DC_EDID_BLOCK_SIZE],
- DC_EDID_BLOCK_SIZE,
- "%s: [Block %d] ", sink->edid_caps.display_name, i);
- }
-
- DC_LOG_DETECTION_EDID_PARSER("%s: "
- "manufacturer_id = %X, "
- "product_id = %X, "
- "serial_number = %X, "
- "manufacture_week = %d, "
- "manufacture_year = %d, "
- "display_name = %s, "
- "speaker_flag = %d, "
- "audio_mode_count = %d\n",
- __func__,
- sink->edid_caps.manufacturer_id,
- sink->edid_caps.product_id,
- sink->edid_caps.serial_number,
- sink->edid_caps.manufacture_week,
- sink->edid_caps.manufacture_year,
- sink->edid_caps.display_name,
- sink->edid_caps.speaker_flags,
- sink->edid_caps.audio_mode_count);
-
- for (i = 0; i < sink->edid_caps.audio_mode_count; i++) {
- DC_LOG_DETECTION_EDID_PARSER("%s: mode number = %d, "
- "format_code = %d, "
- "channel_count = %d, "
- "sample_rate = %d, "
- "sample_size = %d\n",
- __func__,
- i,
- sink->edid_caps.audio_modes[i].format_code,
- sink->edid_caps.audio_modes[i].channel_count,
- sink->edid_caps.audio_modes[i].sample_rate,
- sink->edid_caps.audio_modes[i].sample_size);
- }
-
- if (link->connector_signal == SIGNAL_TYPE_EDP) {
- /* Init dc_panel_config by HW config */
- if (dc_ctx->dc->res_pool->funcs->get_panel_config_defaults)
- dc_ctx->dc->res_pool->funcs->get_panel_config_defaults(&link->panel_config);
- /* Pickup base DM settings */
- dm_helpers_init_panel_settings(dc_ctx, &link->panel_config, sink);
- // Override dc_panel_config if system has specific settings
- dm_helpers_override_panel_settings(dc_ctx, &link->panel_config);
- }
-
- } else {
- /* From Connected-to-Disconnected. */
- link->type = dc_connection_none;
- sink_caps.signal = SIGNAL_TYPE_NONE;
- /* When we unplug a passive DP-HDMI dongle connection, dongle_max_pix_clk
- * is not cleared. If we emulate a DP signal on this connection, it thinks
- * the dongle is still there and limits the number of modes we can emulate.
- * Clear dongle_max_pix_clk on disconnect to fix this
- */
- link->dongle_max_pix_clk = 0;
-
- dc_link_clear_dprx_states(link);
- dp_trace_reset(link);
- }
-
- LINK_INFO("link=%d, dc_sink_in=%p is now %s prev_sink=%p edid same=%d\n",
- link->link_index, sink,
- (sink_caps.signal ==
- SIGNAL_TYPE_NONE ? "Disconnected" : "Connected"),
- prev_sink, same_edid);
-
- if (prev_sink)
- dc_sink_release(prev_sink);
-
- return true;
-}
-
-bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason)
-{
- bool is_local_sink_detect_success;
- bool is_delegated_to_mst_top_mgr = false;
- enum dc_connection_type pre_link_type = link->type;
-
- is_local_sink_detect_success = detect_link_and_local_sink(link, reason);
-
- if (is_local_sink_detect_success && link->local_sink)
- verify_link_capability(link, link->local_sink, reason);
-
- if (is_local_sink_detect_success && link->local_sink &&
- dc_is_dp_signal(link->local_sink->sink_signal) &&
- link->dpcd_caps.is_mst_capable)
- is_delegated_to_mst_top_mgr = discover_dp_mst_topology(link, reason);
-
- if (is_local_sink_detect_success &&
- pre_link_type == dc_connection_mst_branch &&
- link->type != dc_connection_mst_branch)
- is_delegated_to_mst_top_mgr = reset_cur_dp_mst_topology(link);
-
- return is_local_sink_detect_success && !is_delegated_to_mst_top_mgr;
-}
-
-bool dc_link_get_hpd_state(struct dc_link *dc_link)
-{
- uint32_t state;
-
- dal_gpio_lock_pin(dc_link->hpd_gpio);
- dal_gpio_get_value(dc_link->hpd_gpio, &state);
- dal_gpio_unlock_pin(dc_link->hpd_gpio);
-
- return state;
-}
-
-static enum hpd_source_id get_hpd_line(struct dc_link *link)
-{
- struct gpio *hpd;
- enum hpd_source_id hpd_id;
-
- hpd_id = HPD_SOURCEID_UNKNOWN;
-
- hpd = get_hpd_gpio(link->ctx->dc_bios, link->link_id,
- link->ctx->gpio_service);
-
- if (hpd) {
- switch (dal_irq_get_source(hpd)) {
- case DC_IRQ_SOURCE_HPD1:
- hpd_id = HPD_SOURCEID1;
- break;
- case DC_IRQ_SOURCE_HPD2:
- hpd_id = HPD_SOURCEID2;
- break;
- case DC_IRQ_SOURCE_HPD3:
- hpd_id = HPD_SOURCEID3;
- break;
- case DC_IRQ_SOURCE_HPD4:
- hpd_id = HPD_SOURCEID4;
- break;
- case DC_IRQ_SOURCE_HPD5:
- hpd_id = HPD_SOURCEID5;
- break;
- case DC_IRQ_SOURCE_HPD6:
- hpd_id = HPD_SOURCEID6;
- break;
- default:
- BREAK_TO_DEBUGGER();
- break;
- }
-
- dal_gpio_destroy_irq(&hpd);
- }
-
- return hpd_id;
-}
-
-static enum channel_id get_ddc_line(struct dc_link *link)
-{
- struct ddc *ddc;
- enum channel_id channel;
-
- channel = CHANNEL_ID_UNKNOWN;
-
- ddc = dal_ddc_service_get_ddc_pin(link->ddc);
-
- if (ddc) {
- switch (dal_ddc_get_line(ddc)) {
- case GPIO_DDC_LINE_DDC1:
- channel = CHANNEL_ID_DDC1;
- break;
- case GPIO_DDC_LINE_DDC2:
- channel = CHANNEL_ID_DDC2;
- break;
- case GPIO_DDC_LINE_DDC3:
- channel = CHANNEL_ID_DDC3;
- break;
- case GPIO_DDC_LINE_DDC4:
- channel = CHANNEL_ID_DDC4;
- break;
- case GPIO_DDC_LINE_DDC5:
- channel = CHANNEL_ID_DDC5;
- break;
- case GPIO_DDC_LINE_DDC6:
- channel = CHANNEL_ID_DDC6;
- break;
- case GPIO_DDC_LINE_DDC_VGA:
- channel = CHANNEL_ID_DDC_VGA;
- break;
- case GPIO_DDC_LINE_I2C_PAD:
- channel = CHANNEL_ID_I2C_PAD;
- break;
- default:
- BREAK_TO_DEBUGGER();
- break;
- }
- }
-
- return channel;
-}
-
-static enum transmitter translate_encoder_to_transmitter(struct graphics_object_id encoder)
-{
- switch (encoder.id) {
- case ENCODER_ID_INTERNAL_UNIPHY:
- switch (encoder.enum_id) {
- case ENUM_ID_1:
- return TRANSMITTER_UNIPHY_A;
- case ENUM_ID_2:
- return TRANSMITTER_UNIPHY_B;
- default:
- return TRANSMITTER_UNKNOWN;
- }
- break;
- case ENCODER_ID_INTERNAL_UNIPHY1:
- switch (encoder.enum_id) {
- case ENUM_ID_1:
- return TRANSMITTER_UNIPHY_C;
- case ENUM_ID_2:
- return TRANSMITTER_UNIPHY_D;
- default:
- return TRANSMITTER_UNKNOWN;
- }
- break;
- case ENCODER_ID_INTERNAL_UNIPHY2:
- switch (encoder.enum_id) {
- case ENUM_ID_1:
- return TRANSMITTER_UNIPHY_E;
- case ENUM_ID_2:
- return TRANSMITTER_UNIPHY_F;
- default:
- return TRANSMITTER_UNKNOWN;
- }
- break;
- case ENCODER_ID_INTERNAL_UNIPHY3:
- switch (encoder.enum_id) {
- case ENUM_ID_1:
- return TRANSMITTER_UNIPHY_G;
- default:
- return TRANSMITTER_UNKNOWN;
- }
- break;
- case ENCODER_ID_EXTERNAL_NUTMEG:
- switch (encoder.enum_id) {
- case ENUM_ID_1:
- return TRANSMITTER_NUTMEG_CRT;
- default:
- return TRANSMITTER_UNKNOWN;
- }
- break;
- case ENCODER_ID_EXTERNAL_TRAVIS:
- switch (encoder.enum_id) {
- case ENUM_ID_1:
- return TRANSMITTER_TRAVIS_CRT;
- case ENUM_ID_2:
- return TRANSMITTER_TRAVIS_LCD;
- default:
- return TRANSMITTER_UNKNOWN;
- }
- break;
- default:
- return TRANSMITTER_UNKNOWN;
- }
-}
-
-static bool dc_link_construct_legacy(struct dc_link *link,
- const struct link_init_data *init_params)
-{
- uint8_t i;
- struct ddc_service_init_data ddc_service_init_data = { 0 };
- struct dc_context *dc_ctx = init_params->ctx;
- struct encoder_init_data enc_init_data = { 0 };
- struct panel_cntl_init_data panel_cntl_init_data = { 0 };
- struct integrated_info *info;
- struct dc_bios *bios = init_params->dc->ctx->dc_bios;
- const struct dc_vbios_funcs *bp_funcs = bios->funcs;
- struct bp_disp_connector_caps_info disp_connect_caps_info = { 0 };
-
- DC_LOGGER_INIT(dc_ctx->logger);
-
- info = kzalloc(sizeof(*info), GFP_KERNEL);
- if (!info)
- goto create_fail;
-
- link->irq_source_hpd = DC_IRQ_SOURCE_INVALID;
- link->irq_source_hpd_rx = DC_IRQ_SOURCE_INVALID;
-
- link->link_status.dpcd_caps = &link->dpcd_caps;
-
- link->dc = init_params->dc;
- link->ctx = dc_ctx;
- link->link_index = init_params->link_index;
-
- memset(&link->preferred_training_settings, 0,
- sizeof(struct dc_link_training_overrides));
- memset(&link->preferred_link_setting, 0,
- sizeof(struct dc_link_settings));
-
- link->link_id =
- bios->funcs->get_connector_id(bios, init_params->connector_index);
-
- link->ep_type = DISPLAY_ENDPOINT_PHY;
-
- DC_LOG_DC("BIOS object table - link_id: %d", link->link_id.id);
-
- if (bios->funcs->get_disp_connector_caps_info) {
- bios->funcs->get_disp_connector_caps_info(bios, link->link_id, &disp_connect_caps_info);
- link->is_internal_display = disp_connect_caps_info.INTERNAL_DISPLAY;
- DC_LOG_DC("BIOS object table - is_internal_display: %d", link->is_internal_display);
- }
-
- if (link->link_id.type != OBJECT_TYPE_CONNECTOR) {
- dm_output_to_console("%s: Invalid Connector ObjectID from Adapter Service for connector index:%d! type %d expected %d\n",
- __func__, init_params->connector_index,
- link->link_id.type, OBJECT_TYPE_CONNECTOR);
- goto create_fail;
- }
-
- if (link->dc->res_pool->funcs->link_init)
- link->dc->res_pool->funcs->link_init(link);
-
- link->hpd_gpio = get_hpd_gpio(link->ctx->dc_bios, link->link_id,
- link->ctx->gpio_service);
-
- if (link->hpd_gpio) {
- dal_gpio_open(link->hpd_gpio, GPIO_MODE_INTERRUPT);
- dal_gpio_unlock_pin(link->hpd_gpio);
- link->irq_source_hpd = dal_irq_get_source(link->hpd_gpio);
-
- DC_LOG_DC("BIOS object table - hpd_gpio id: %d", link->hpd_gpio->id);
- DC_LOG_DC("BIOS object table - hpd_gpio en: %d", link->hpd_gpio->en);
- }
-
- switch (link->link_id.id) {
- case CONNECTOR_ID_HDMI_TYPE_A:
- link->connector_signal = SIGNAL_TYPE_HDMI_TYPE_A;
-
- break;
- case CONNECTOR_ID_SINGLE_LINK_DVID:
- case CONNECTOR_ID_SINGLE_LINK_DVII:
- link->connector_signal = SIGNAL_TYPE_DVI_SINGLE_LINK;
- break;
- case CONNECTOR_ID_DUAL_LINK_DVID:
- case CONNECTOR_ID_DUAL_LINK_DVII:
- link->connector_signal = SIGNAL_TYPE_DVI_DUAL_LINK;
- break;
- case CONNECTOR_ID_DISPLAY_PORT:
- case CONNECTOR_ID_USBC:
- link->connector_signal = SIGNAL_TYPE_DISPLAY_PORT;
-
- if (link->hpd_gpio)
- link->irq_source_hpd_rx =
- dal_irq_get_rx_source(link->hpd_gpio);
-
- break;
- case CONNECTOR_ID_EDP:
- link->connector_signal = SIGNAL_TYPE_EDP;
-
- if (link->hpd_gpio) {
- if (!link->dc->config.allow_edp_hotplug_detection)
- link->irq_source_hpd = DC_IRQ_SOURCE_INVALID;
-
- switch (link->dc->config.allow_edp_hotplug_detection) {
- case 1: // only the 1st eDP handles hotplug
- if (link->link_index == 0)
- link->irq_source_hpd_rx =
- dal_irq_get_rx_source(link->hpd_gpio);
- else
- link->irq_source_hpd = DC_IRQ_SOURCE_INVALID;
- break;
- case 2: // only the 2nd eDP handles hotplug
- if (link->link_index == 1)
- link->irq_source_hpd_rx =
- dal_irq_get_rx_source(link->hpd_gpio);
- else
- link->irq_source_hpd = DC_IRQ_SOURCE_INVALID;
- break;
- default:
- break;
- }
- }
-
- break;
- case CONNECTOR_ID_LVDS:
- link->connector_signal = SIGNAL_TYPE_LVDS;
- break;
- default:
- DC_LOG_WARNING("Unsupported Connector type:%d!\n",
- link->link_id.id);
- goto create_fail;
- }
-
- /* TODO: #DAL3 Implement id to str function.*/
- LINK_INFO("Connector[%d] description:"
- "signal %d\n",
- init_params->connector_index,
- link->connector_signal);
-
- ddc_service_init_data.ctx = link->ctx;
- ddc_service_init_data.id = link->link_id;
- ddc_service_init_data.link = link;
- link->ddc = dal_ddc_service_create(&ddc_service_init_data);
-
- if (!link->ddc) {
- DC_ERROR("Failed to create ddc_service!\n");
- goto ddc_create_fail;
- }
-
- if (!link->ddc->ddc_pin) {
- DC_ERROR("Failed to get I2C info for connector!\n");
- goto ddc_create_fail;
- }
-
- link->ddc_hw_inst =
- dal_ddc_get_line(dal_ddc_service_get_ddc_pin(link->ddc));
-
-
- if (link->dc->res_pool->funcs->panel_cntl_create &&
- (link->link_id.id == CONNECTOR_ID_EDP ||
- link->link_id.id == CONNECTOR_ID_LVDS)) {
- panel_cntl_init_data.ctx = dc_ctx;
- panel_cntl_init_data.inst =
- panel_cntl_init_data.ctx->dc_edp_id_count;
- link->panel_cntl =
- link->dc->res_pool->funcs->panel_cntl_create(
- &panel_cntl_init_data);
- panel_cntl_init_data.ctx->dc_edp_id_count++;
-
- if (link->panel_cntl == NULL) {
- DC_ERROR("Failed to create link panel_cntl!\n");
- goto panel_cntl_create_fail;
- }
- }
-
- enc_init_data.ctx = dc_ctx;
- bp_funcs->get_src_obj(dc_ctx->dc_bios, link->link_id, 0,
- &enc_init_data.encoder);
- enc_init_data.connector = link->link_id;
- enc_init_data.channel = get_ddc_line(link);
- enc_init_data.hpd_source = get_hpd_line(link);
-
- link->hpd_src = enc_init_data.hpd_source;
-
- enc_init_data.transmitter =
- translate_encoder_to_transmitter(enc_init_data.encoder);
- link->link_enc =
- link->dc->res_pool->funcs->link_enc_create(dc_ctx, &enc_init_data);
-
- if (!link->link_enc) {
- DC_ERROR("Failed to create link encoder!\n");
- goto link_enc_create_fail;
- }
-
- DC_LOG_DC("BIOS object table - DP_IS_USB_C: %d", link->link_enc->features.flags.bits.DP_IS_USB_C);
- DC_LOG_DC("BIOS object table - IS_DP2_CAPABLE: %d", link->link_enc->features.flags.bits.IS_DP2_CAPABLE);
-
- /* Update link encoder tracking variables. These are used for the dynamic
- * assignment of link encoders to streams.
- */
- link->eng_id = link->link_enc->preferred_engine;
- link->dc->res_pool->link_encoders[link->eng_id - ENGINE_ID_DIGA] = link->link_enc;
- link->dc->res_pool->dig_link_enc_count++;
-
- link->link_enc_hw_inst = link->link_enc->transmitter;
-
- for (i = 0; i < 4; i++) {
- if (bp_funcs->get_device_tag(dc_ctx->dc_bios,
- link->link_id, i,
- &link->device_tag) != BP_RESULT_OK) {
- DC_ERROR("Failed to find device tag!\n");
- goto device_tag_fail;
- }
-
- /* Look for device tag that matches connector signal,
- * CRT for rgb, LCD for other supported signal tyes
- */
- if (!bp_funcs->is_device_id_supported(dc_ctx->dc_bios,
- link->device_tag.dev_id))
- continue;
- if (link->device_tag.dev_id.device_type == DEVICE_TYPE_CRT &&
- link->connector_signal != SIGNAL_TYPE_RGB)
- continue;
- if (link->device_tag.dev_id.device_type == DEVICE_TYPE_LCD &&
- link->connector_signal == SIGNAL_TYPE_RGB)
- continue;
-
- DC_LOG_DC("BIOS object table - device_tag.acpi_device: %d", link->device_tag.acpi_device);
- DC_LOG_DC("BIOS object table - device_tag.dev_id.device_type: %d", link->device_tag.dev_id.device_type);
- DC_LOG_DC("BIOS object table - device_tag.dev_id.enum_id: %d", link->device_tag.dev_id.enum_id);
- break;
- }
-
- if (bios->integrated_info)
- memcpy(info, bios->integrated_info, sizeof(*info));
-
- /* Look for channel mapping corresponding to connector and device tag */
- for (i = 0; i < MAX_NUMBER_OF_EXT_DISPLAY_PATH; i++) {
- struct external_display_path *path =
- &info->ext_disp_conn_info.path[i];
-
- if (path->device_connector_id.enum_id == link->link_id.enum_id &&
- path->device_connector_id.id == link->link_id.id &&
- path->device_connector_id.type == link->link_id.type) {
- if (link->device_tag.acpi_device != 0 &&
- path->device_acpi_enum == link->device_tag.acpi_device) {
- link->ddi_channel_mapping = path->channel_mapping;
- link->chip_caps = path->caps;
- DC_LOG_DC("BIOS object table - ddi_channel_mapping: 0x%04X", link->ddi_channel_mapping.raw);
- DC_LOG_DC("BIOS object table - chip_caps: %d", link->chip_caps);
- } else if (path->device_tag ==
- link->device_tag.dev_id.raw_device_tag) {
- link->ddi_channel_mapping = path->channel_mapping;
- link->chip_caps = path->caps;
- DC_LOG_DC("BIOS object table - ddi_channel_mapping: 0x%04X", link->ddi_channel_mapping.raw);
- DC_LOG_DC("BIOS object table - chip_caps: %d", link->chip_caps);
- }
-
- if (link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) {
- link->bios_forced_drive_settings.VOLTAGE_SWING =
- (info->ext_disp_conn_info.fixdpvoltageswing & 0x3);
- link->bios_forced_drive_settings.PRE_EMPHASIS =
- ((info->ext_disp_conn_info.fixdpvoltageswing >> 2) & 0x3);
- }
-
- break;
- }
- }
-
- if (bios->funcs->get_atom_dc_golden_table)
- bios->funcs->get_atom_dc_golden_table(bios);
-
- /*
- * TODO check if GPIO programmed correctly
- *
- * If GPIO isn't programmed correctly HPD might not rise or drain
- * fast enough, leading to bounces.
- */
- program_hpd_filter(link);
-
- link->psr_settings.psr_vtotal_control_support = false;
- link->psr_settings.psr_version = DC_PSR_VERSION_UNSUPPORTED;
-
- DC_LOG_DC("BIOS object table - %s finished successfully.\n", __func__);
- kfree(info);
- return true;
-device_tag_fail:
- link->link_enc->funcs->destroy(&link->link_enc);
-link_enc_create_fail:
- if (link->panel_cntl != NULL)
- link->panel_cntl->funcs->destroy(&link->panel_cntl);
-panel_cntl_create_fail:
- dal_ddc_service_destroy(&link->ddc);
-ddc_create_fail:
-create_fail:
-
- if (link->hpd_gpio) {
- dal_gpio_destroy_irq(&link->hpd_gpio);
- link->hpd_gpio = NULL;
- }
-
- DC_LOG_DC("BIOS object table - %s failed.\n", __func__);
- kfree(info);
-
- return false;
-}
-
-static bool dc_link_construct_dpia(struct dc_link *link,
- const struct link_init_data *init_params)
-{
- struct ddc_service_init_data ddc_service_init_data = { 0 };
- struct dc_context *dc_ctx = init_params->ctx;
-
- DC_LOGGER_INIT(dc_ctx->logger);
-
- /* Initialized irq source for hpd and hpd rx */
- link->irq_source_hpd = DC_IRQ_SOURCE_INVALID;
- link->irq_source_hpd_rx = DC_IRQ_SOURCE_INVALID;
- link->link_status.dpcd_caps = &link->dpcd_caps;
-
- link->dc = init_params->dc;
- link->ctx = dc_ctx;
- link->link_index = init_params->link_index;
-
- memset(&link->preferred_training_settings, 0,
- sizeof(struct dc_link_training_overrides));
- memset(&link->preferred_link_setting, 0,
- sizeof(struct dc_link_settings));
-
- /* Dummy Init for linkid */
- link->link_id.type = OBJECT_TYPE_CONNECTOR;
- link->link_id.id = CONNECTOR_ID_DISPLAY_PORT;
- link->link_id.enum_id = ENUM_ID_1 + init_params->connector_index;
- link->is_internal_display = false;
- link->connector_signal = SIGNAL_TYPE_DISPLAY_PORT;
- LINK_INFO("Connector[%d] description:signal %d\n",
- init_params->connector_index,
- link->connector_signal);
-
- link->ep_type = DISPLAY_ENDPOINT_USB4_DPIA;
- link->is_dig_mapping_flexible = true;
-
- /* TODO: Initialize link : funcs->link_init */
-
- ddc_service_init_data.ctx = link->ctx;
- ddc_service_init_data.id = link->link_id;
- ddc_service_init_data.link = link;
- /* Set indicator for dpia link so that ddc won't be created */
- ddc_service_init_data.is_dpia_link = true;
-
- link->ddc = dal_ddc_service_create(&ddc_service_init_data);
- if (!link->ddc) {
- DC_ERROR("Failed to create ddc_service!\n");
- goto ddc_create_fail;
- }
-
- /* Set dpia port index : 0 to number of dpia ports */
- link->ddc_hw_inst = init_params->connector_index;
-
- /* TODO: Create link encoder */
-
- link->psr_settings.psr_version = DC_PSR_VERSION_UNSUPPORTED;
-
- /* Some docks seem to NAK I2C writes to segment pointer with mot=0. */
- link->wa_flags.dp_mot_reset_segment = true;
-
- return true;
-
-ddc_create_fail:
- return false;
-}
-
-static bool dc_link_construct(struct dc_link *link,
- const struct link_init_data *init_params)
-{
- /* Handle dpia case */
- if (init_params->is_dpia_link)
- return dc_link_construct_dpia(link, init_params);
- else
- return dc_link_construct_legacy(link, init_params);
-}
-/*******************************************************************************
- * Public functions
- ******************************************************************************/
-struct dc_link *link_create(const struct link_init_data *init_params)
-{
- struct dc_link *link =
- kzalloc(sizeof(*link), GFP_KERNEL);
-
- if (NULL == link)
- goto alloc_fail;
-
- if (false == dc_link_construct(link, init_params))
- goto construct_fail;
-
- /*
- * Must use preferred_link_setting, not reported_link_cap or verified_link_cap,
- * since struct preferred_link_setting won't be reset after S3.
- */
- link->preferred_link_setting.dpcd_source_device_specific_field_support = true;
-
- return link;
-
-construct_fail:
- kfree(link);
-
-alloc_fail:
- return NULL;
-}
-
-void link_destroy(struct dc_link **link)
-{
- dc_link_destruct(*link);
- kfree(*link);
- *link = NULL;
-}
-
-static void enable_stream_features(struct pipe_ctx *pipe_ctx)
-{
- struct dc_stream_state *stream = pipe_ctx->stream;
-
- if (pipe_ctx->stream->signal != SIGNAL_TYPE_DISPLAY_PORT_MST) {
- struct dc_link *link = stream->link;
- union down_spread_ctrl old_downspread;
- union down_spread_ctrl new_downspread;
-
- memset(&old_downspread, 0, sizeof(old_downspread));
-
- core_link_read_dpcd(link, DP_DOWNSPREAD_CTRL,
- &old_downspread.raw, sizeof(old_downspread));
-
- new_downspread.raw = old_downspread.raw;
-
- new_downspread.bits.IGNORE_MSA_TIMING_PARAM =
- (stream->ignore_msa_timing_param) ? 1 : 0;
-
- if (new_downspread.raw != old_downspread.raw) {
- core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL,
- &new_downspread.raw, sizeof(new_downspread));
- }
-
- } else {
- dm_helpers_mst_enable_stream_features(stream);
- }
-}
-
-static enum dc_status enable_link_dp(struct dc_state *state,
- struct pipe_ctx *pipe_ctx)
-{
- struct dc_stream_state *stream = pipe_ctx->stream;
- enum dc_status status;
- bool skip_video_pattern;
- struct dc_link *link = stream->link;
- const struct dc_link_settings *link_settings =
- &pipe_ctx->link_config.dp_link_settings;
- bool fec_enable;
- int i;
- bool apply_seamless_boot_optimization = false;
- uint32_t bl_oled_enable_delay = 50; // in ms
- uint32_t post_oui_delay = 30; // 30ms
- /* Reduce link bandwidth between failed link training attempts. */
- bool do_fallback = false;
-
- // check for seamless boot
- for (i = 0; i < state->stream_count; i++) {
- if (state->streams[i]->apply_seamless_boot_optimization) {
- apply_seamless_boot_optimization = true;
- break;
- }
- }
-
- /* Train with fallback when enabling DPIA link. Conventional links are
- * trained with fallback during sink detection.
- */
- if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA)
- do_fallback = true;
-
- /*
- * Temporary w/a to get DP2.0 link rates to work with SST.
- * TODO DP2.0 - Workaround: Remove w/a if and when the issue is resolved.
- */
- if (dp_get_link_encoding_format(link_settings) == DP_128b_132b_ENCODING &&
- pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT &&
- link->dc->debug.set_mst_en_for_sst) {
- dp_enable_mst_on_sink(link, true);
- }
-
- if (pipe_ctx->stream->signal == SIGNAL_TYPE_EDP) {
- /*in case it is not on*/
- if (!link->dc->config.edp_no_power_sequencing)
- link->dc->hwss.edp_power_control(link, true);
- link->dc->hwss.edp_wait_for_hpd_ready(link, true);
- }
-
- if (dp_get_link_encoding_format(link_settings) == DP_128b_132b_ENCODING) {
- /* TODO - DP2.0 HW: calculate 32 symbol clock for HPO encoder */
- } else {
- pipe_ctx->stream_res.pix_clk_params.requested_sym_clk =
- link_settings->link_rate * LINK_RATE_REF_FREQ_IN_KHZ;
- if (state->clk_mgr && !apply_seamless_boot_optimization)
- state->clk_mgr->funcs->update_clocks(state->clk_mgr,
- state, false);
- }
-
- // during mode switch we do DP_SET_POWER off then on, and OUI is lost
- dpcd_set_source_specific_data(link);
- if (link->dpcd_sink_ext_caps.raw != 0) {
- post_oui_delay += link->panel_config.pps.extra_post_OUI_ms;
- msleep(post_oui_delay);
- }
-
- // similarly, mode switch can cause loss of cable ID
- dpcd_write_cable_id_to_dprx(link);
-
- skip_video_pattern = true;
-
- if (link_settings->link_rate == LINK_RATE_LOW)
- skip_video_pattern = false;
-
- if (perform_link_training_with_retries(link_settings,
- skip_video_pattern,
- LINK_TRAINING_ATTEMPTS,
- pipe_ctx,
- pipe_ctx->stream->signal,
- do_fallback)) {
- status = DC_OK;
- } else {
- status = DC_FAIL_DP_LINK_TRAINING;
- }
-
- if (link->preferred_training_settings.fec_enable)
- fec_enable = *link->preferred_training_settings.fec_enable;
- else
- fec_enable = true;
-
- if (dp_get_link_encoding_format(link_settings) == DP_8b_10b_ENCODING)
- dp_set_fec_enable(link, fec_enable);
-
- // during mode set we do DP_SET_POWER off then on, aux writes are lost
- if (link->dpcd_sink_ext_caps.bits.oled == 1 ||
- link->dpcd_sink_ext_caps.bits.sdr_aux_backlight_control == 1 ||
- link->dpcd_sink_ext_caps.bits.hdr_aux_backlight_control == 1) {
- dc_link_set_default_brightness_aux(link); // TODO: use cached if known
- if (link->dpcd_sink_ext_caps.bits.oled == 1)
- msleep(bl_oled_enable_delay);
- dc_link_backlight_enable_aux(link, true);
- }
-
- return status;
-}
-
-static enum dc_status enable_link_edp(
- struct dc_state *state,
- struct pipe_ctx *pipe_ctx)
-{
- return enable_link_dp(state, pipe_ctx);
-}
-
-static enum dc_status enable_link_dp_mst(
- struct dc_state *state,
- struct pipe_ctx *pipe_ctx)
-{
- struct dc_link *link = pipe_ctx->stream->link;
-
- /* sink signal type after MST branch is MST. Multiple MST sinks
- * share one link. Link DP PHY is enable or training only once.
- */
- if (link->link_status.link_active)
- return DC_OK;
-
- /* clear payload table */
- dm_helpers_dp_mst_clear_payload_allocation_table(link->ctx, link);
-
- /* to make sure the pending down rep can be processed
- * before enabling the link
- */
- dm_helpers_dp_mst_poll_pending_down_reply(link->ctx, link);
-
- /* set the sink to MST mode before enabling the link */
- dp_enable_mst_on_sink(link, true);
-
- return enable_link_dp(state, pipe_ctx);
-}
-
-void dc_link_blank_all_dp_displays(struct dc *dc)
-{
- unsigned int i;
- uint8_t dpcd_power_state = '\0';
- enum dc_status status = DC_ERROR_UNEXPECTED;
-
- for (i = 0; i < dc->link_count; i++) {
- if ((dc->links[i]->connector_signal != SIGNAL_TYPE_DISPLAY_PORT) ||
- (dc->links[i]->priv == NULL) || (dc->links[i]->local_sink == NULL))
- continue;
-
- /* DP 2.0 spec requires that we read LTTPR caps first */
- dp_retrieve_lttpr_cap(dc->links[i]);
- /* if any of the displays are lit up turn them off */
- status = core_link_read_dpcd(dc->links[i], DP_SET_POWER,
- &dpcd_power_state, sizeof(dpcd_power_state));
-
- if (status == DC_OK && dpcd_power_state == DP_POWER_STATE_D0)
- dc_link_blank_dp_stream(dc->links[i], true);
- }
-
-}
-
-void dc_link_blank_all_edp_displays(struct dc *dc)
-{
- unsigned int i;
- uint8_t dpcd_power_state = '\0';
- enum dc_status status = DC_ERROR_UNEXPECTED;
-
- for (i = 0; i < dc->link_count; i++) {
- if ((dc->links[i]->connector_signal != SIGNAL_TYPE_EDP) ||
- (!dc->links[i]->edp_sink_present))
- continue;
-
- /* if any of the displays are lit up turn them off */
- status = core_link_read_dpcd(dc->links[i], DP_SET_POWER,
- &dpcd_power_state, sizeof(dpcd_power_state));
-
- if (status == DC_OK && dpcd_power_state == DP_POWER_STATE_D0)
- dc_link_blank_dp_stream(dc->links[i], true);
- }
-}
-
-void dc_link_blank_dp_stream(struct dc_link *link, bool hw_init)
-{
- unsigned int j;
- struct dc *dc = link->ctx->dc;
- enum signal_type signal = link->connector_signal;
-
- if ((signal == SIGNAL_TYPE_EDP) ||
- (signal == SIGNAL_TYPE_DISPLAY_PORT)) {
- if (link->ep_type == DISPLAY_ENDPOINT_PHY &&
- link->link_enc->funcs->get_dig_frontend &&
- link->link_enc->funcs->is_dig_enabled(link->link_enc)) {
- unsigned int fe = link->link_enc->funcs->get_dig_frontend(link->link_enc);
-
- if (fe != ENGINE_ID_UNKNOWN)
- for (j = 0; j < dc->res_pool->stream_enc_count; j++) {
- if (fe == dc->res_pool->stream_enc[j]->id) {
- dc->res_pool->stream_enc[j]->funcs->dp_blank(link,
- dc->res_pool->stream_enc[j]);
- break;
- }
- }
- }
-
- if ((!link->wa_flags.dp_keep_receiver_powered) || hw_init)
- dp_receiver_power_ctrl(link, false);
- }
-}
-
-static bool get_ext_hdmi_settings(struct pipe_ctx *pipe_ctx,
- enum engine_id eng_id,
- struct ext_hdmi_settings *settings)
-{
- bool result = false;
- int i = 0;
- struct integrated_info *integrated_info =
- pipe_ctx->stream->ctx->dc_bios->integrated_info;
-
- if (integrated_info == NULL)
- return false;
-
- /*
- * Get retimer settings from sbios for passing SI eye test for DCE11
- * The setting values are varied based on board revision and port id
- * Therefore the setting values of each ports is passed by sbios.
- */
-
- // Check if current bios contains ext Hdmi settings
- if (integrated_info->gpu_cap_info & 0x20) {
- switch (eng_id) {
- case ENGINE_ID_DIGA:
- settings->slv_addr = integrated_info->dp0_ext_hdmi_slv_addr;
- settings->reg_num = integrated_info->dp0_ext_hdmi_6g_reg_num;
- settings->reg_num_6g = integrated_info->dp0_ext_hdmi_6g_reg_num;
- memmove(settings->reg_settings,
- integrated_info->dp0_ext_hdmi_reg_settings,
- sizeof(integrated_info->dp0_ext_hdmi_reg_settings));
- memmove(settings->reg_settings_6g,
- integrated_info->dp0_ext_hdmi_6g_reg_settings,
- sizeof(integrated_info->dp0_ext_hdmi_6g_reg_settings));
- result = true;
- break;
- case ENGINE_ID_DIGB:
- settings->slv_addr = integrated_info->dp1_ext_hdmi_slv_addr;
- settings->reg_num = integrated_info->dp1_ext_hdmi_6g_reg_num;
- settings->reg_num_6g = integrated_info->dp1_ext_hdmi_6g_reg_num;
- memmove(settings->reg_settings,
- integrated_info->dp1_ext_hdmi_reg_settings,
- sizeof(integrated_info->dp1_ext_hdmi_reg_settings));
- memmove(settings->reg_settings_6g,
- integrated_info->dp1_ext_hdmi_6g_reg_settings,
- sizeof(integrated_info->dp1_ext_hdmi_6g_reg_settings));
- result = true;
- break;
- case ENGINE_ID_DIGC:
- settings->slv_addr = integrated_info->dp2_ext_hdmi_slv_addr;
- settings->reg_num = integrated_info->dp2_ext_hdmi_6g_reg_num;
- settings->reg_num_6g = integrated_info->dp2_ext_hdmi_6g_reg_num;
- memmove(settings->reg_settings,
- integrated_info->dp2_ext_hdmi_reg_settings,
- sizeof(integrated_info->dp2_ext_hdmi_reg_settings));
- memmove(settings->reg_settings_6g,
- integrated_info->dp2_ext_hdmi_6g_reg_settings,
- sizeof(integrated_info->dp2_ext_hdmi_6g_reg_settings));
- result = true;
- break;
- case ENGINE_ID_DIGD:
- settings->slv_addr = integrated_info->dp3_ext_hdmi_slv_addr;
- settings->reg_num = integrated_info->dp3_ext_hdmi_6g_reg_num;
- settings->reg_num_6g = integrated_info->dp3_ext_hdmi_6g_reg_num;
- memmove(settings->reg_settings,
- integrated_info->dp3_ext_hdmi_reg_settings,
- sizeof(integrated_info->dp3_ext_hdmi_reg_settings));
- memmove(settings->reg_settings_6g,
- integrated_info->dp3_ext_hdmi_6g_reg_settings,
- sizeof(integrated_info->dp3_ext_hdmi_6g_reg_settings));
- result = true;
- break;
- default:
- break;
- }
-
- if (result == true) {
- // Validate settings from bios integrated info table
- if (settings->slv_addr == 0)
- return false;
- if (settings->reg_num > 9)
- return false;
- if (settings->reg_num_6g > 3)
- return false;
-
- for (i = 0; i < settings->reg_num; i++) {
- if (settings->reg_settings[i].i2c_reg_index > 0x20)
- return false;
- }
-
- for (i = 0; i < settings->reg_num_6g; i++) {
- if (settings->reg_settings_6g[i].i2c_reg_index > 0x20)
- return false;
- }
- }
- }
-
- return result;
-}
-
-static bool i2c_write(struct pipe_ctx *pipe_ctx,
- uint8_t address, uint8_t *buffer, uint32_t length)
-{
- struct i2c_command cmd = {0};
- struct i2c_payload payload = {0};
-
- memset(&payload, 0, sizeof(payload));
- memset(&cmd, 0, sizeof(cmd));
-
- cmd.number_of_payloads = 1;
- cmd.engine = I2C_COMMAND_ENGINE_DEFAULT;
- cmd.speed = pipe_ctx->stream->ctx->dc->caps.i2c_speed_in_khz;
-
- payload.address = address;
- payload.data = buffer;
- payload.length = length;
- payload.write = true;
- cmd.payloads = &payload;
-
- if (dm_helpers_submit_i2c(pipe_ctx->stream->ctx,
- pipe_ctx->stream->link, &cmd))
- return true;
-
- return false;
-}
-
-static void write_i2c_retimer_setting(
- struct pipe_ctx *pipe_ctx,
- bool is_vga_mode,
- bool is_over_340mhz,
- struct ext_hdmi_settings *settings)
-{
- uint8_t slave_address = (settings->slv_addr >> 1);
- uint8_t buffer[2];
- const uint8_t apply_rx_tx_change = 0x4;
- uint8_t offset = 0xA;
- uint8_t value = 0;
- int i = 0;
- bool i2c_success = false;
- DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
-
- memset(&buffer, 0, sizeof(buffer));
-
- /* Start Ext-Hdmi programming*/
-
- for (i = 0; i < settings->reg_num; i++) {
- /* Apply 3G settings */
- if (settings->reg_settings[i].i2c_reg_index <= 0x20) {
-
- buffer[0] = settings->reg_settings[i].i2c_reg_index;
- buffer[1] = settings->reg_settings[i].i2c_reg_val;
- i2c_success = i2c_write(pipe_ctx, slave_address,
- buffer, sizeof(buffer));
- RETIMER_REDRIVER_INFO("retimer write to slave_address = 0x%x,\
- offset = 0x%x, reg_val= 0x%x, i2c_success = %d\n",
- slave_address, buffer[0], buffer[1], i2c_success?1:0);
-
- if (!i2c_success)
- goto i2c_write_fail;
-
- /* Based on DP159 specs, APPLY_RX_TX_CHANGE bit in 0x0A
- * needs to be set to 1 on every 0xA-0xC write.
- */
- if (settings->reg_settings[i].i2c_reg_index == 0xA ||
- settings->reg_settings[i].i2c_reg_index == 0xB ||
- settings->reg_settings[i].i2c_reg_index == 0xC) {
-
- /* Query current value from offset 0xA */
- if (settings->reg_settings[i].i2c_reg_index == 0xA)
- value = settings->reg_settings[i].i2c_reg_val;
- else {
- i2c_success =
- dal_ddc_service_query_ddc_data(
- pipe_ctx->stream->link->ddc,
- slave_address, &offset, 1, &value, 1);
- if (!i2c_success)
- goto i2c_write_fail;
- }
-
- buffer[0] = offset;
- /* Set APPLY_RX_TX_CHANGE bit to 1 */
- buffer[1] = value | apply_rx_tx_change;
- i2c_success = i2c_write(pipe_ctx, slave_address,
- buffer, sizeof(buffer));
- RETIMER_REDRIVER_INFO("retimer write to slave_address = 0x%x,\
- offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
- slave_address, buffer[0], buffer[1], i2c_success?1:0);
- if (!i2c_success)
- goto i2c_write_fail;
- }
- }
- }
-
- /* Apply 3G settings */
- if (is_over_340mhz) {
- for (i = 0; i < settings->reg_num_6g; i++) {
- /* Apply 3G settings */
- if (settings->reg_settings[i].i2c_reg_index <= 0x20) {
-
- buffer[0] = settings->reg_settings_6g[i].i2c_reg_index;
- buffer[1] = settings->reg_settings_6g[i].i2c_reg_val;
- i2c_success = i2c_write(pipe_ctx, slave_address,
- buffer, sizeof(buffer));
- RETIMER_REDRIVER_INFO("above 340Mhz: retimer write to slave_address = 0x%x,\
- offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
- slave_address, buffer[0], buffer[1], i2c_success?1:0);
-
- if (!i2c_success)
- goto i2c_write_fail;
-
- /* Based on DP159 specs, APPLY_RX_TX_CHANGE bit in 0x0A
- * needs to be set to 1 on every 0xA-0xC write.
- */
- if (settings->reg_settings_6g[i].i2c_reg_index == 0xA ||
- settings->reg_settings_6g[i].i2c_reg_index == 0xB ||
- settings->reg_settings_6g[i].i2c_reg_index == 0xC) {
-
- /* Query current value from offset 0xA */
- if (settings->reg_settings_6g[i].i2c_reg_index == 0xA)
- value = settings->reg_settings_6g[i].i2c_reg_val;
- else {
- i2c_success =
- dal_ddc_service_query_ddc_data(
- pipe_ctx->stream->link->ddc,
- slave_address, &offset, 1, &value, 1);
- if (!i2c_success)
- goto i2c_write_fail;
- }
-
- buffer[0] = offset;
- /* Set APPLY_RX_TX_CHANGE bit to 1 */
- buffer[1] = value | apply_rx_tx_change;
- i2c_success = i2c_write(pipe_ctx, slave_address,
- buffer, sizeof(buffer));
- RETIMER_REDRIVER_INFO("retimer write to slave_address = 0x%x,\
- offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
- slave_address, buffer[0], buffer[1], i2c_success?1:0);
- if (!i2c_success)
- goto i2c_write_fail;
- }
- }
- }
- }
-
- if (is_vga_mode) {
- /* Program additional settings if using 640x480 resolution */
-
- /* Write offset 0xFF to 0x01 */
- buffer[0] = 0xff;
- buffer[1] = 0x01;
- i2c_success = i2c_write(pipe_ctx, slave_address,
- buffer, sizeof(buffer));
- RETIMER_REDRIVER_INFO("retimer write to slave_address = 0x%x,\
- offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
- slave_address, buffer[0], buffer[1], i2c_success?1:0);
- if (!i2c_success)
- goto i2c_write_fail;
-
- /* Write offset 0x00 to 0x23 */
- buffer[0] = 0x00;
- buffer[1] = 0x23;
- i2c_success = i2c_write(pipe_ctx, slave_address,
- buffer, sizeof(buffer));
- RETIMER_REDRIVER_INFO("retimer write to slave_address = 0x%x,\
- offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
- slave_address, buffer[0], buffer[1], i2c_success?1:0);
- if (!i2c_success)
- goto i2c_write_fail;
-
- /* Write offset 0xff to 0x00 */
- buffer[0] = 0xff;
- buffer[1] = 0x00;
- i2c_success = i2c_write(pipe_ctx, slave_address,
- buffer, sizeof(buffer));
- RETIMER_REDRIVER_INFO("retimer write to slave_address = 0x%x,\
- offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
- slave_address, buffer[0], buffer[1], i2c_success?1:0);
- if (!i2c_success)
- goto i2c_write_fail;
-
- }
-
- return;
-
-i2c_write_fail:
- DC_LOG_DEBUG("Set retimer failed");
-}
-
-static void write_i2c_default_retimer_setting(
- struct pipe_ctx *pipe_ctx,
- bool is_vga_mode,
- bool is_over_340mhz)
-{
- uint8_t slave_address = (0xBA >> 1);
- uint8_t buffer[2];
- bool i2c_success = false;
- DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
-
- memset(&buffer, 0, sizeof(buffer));
-
- /* Program Slave Address for tuning single integrity */
- /* Write offset 0x0A to 0x13 */
- buffer[0] = 0x0A;
- buffer[1] = 0x13;
- i2c_success = i2c_write(pipe_ctx, slave_address,
- buffer, sizeof(buffer));
- RETIMER_REDRIVER_INFO("retimer writes default setting to slave_address = 0x%x,\
- offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
- slave_address, buffer[0], buffer[1], i2c_success?1:0);
- if (!i2c_success)
- goto i2c_write_fail;
-
- /* Write offset 0x0A to 0x17 */
- buffer[0] = 0x0A;
- buffer[1] = 0x17;
- i2c_success = i2c_write(pipe_ctx, slave_address,
- buffer, sizeof(buffer));
- RETIMER_REDRIVER_INFO("retimer write to slave_addr = 0x%x,\
- offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
- slave_address, buffer[0], buffer[1], i2c_success?1:0);
- if (!i2c_success)
- goto i2c_write_fail;
-
- /* Write offset 0x0B to 0xDA or 0xD8 */
- buffer[0] = 0x0B;
- buffer[1] = is_over_340mhz ? 0xDA : 0xD8;
- i2c_success = i2c_write(pipe_ctx, slave_address,
- buffer, sizeof(buffer));
- RETIMER_REDRIVER_INFO("retimer write to slave_addr = 0x%x,\
- offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
- slave_address, buffer[0], buffer[1], i2c_success?1:0);
- if (!i2c_success)
- goto i2c_write_fail;
-
- /* Write offset 0x0A to 0x17 */
- buffer[0] = 0x0A;
- buffer[1] = 0x17;
- i2c_success = i2c_write(pipe_ctx, slave_address,
- buffer, sizeof(buffer));
- RETIMER_REDRIVER_INFO("retimer write to slave_addr = 0x%x,\
- offset = 0x%x, reg_val= 0x%x, i2c_success = %d\n",
- slave_address, buffer[0], buffer[1], i2c_success?1:0);
- if (!i2c_success)
- goto i2c_write_fail;
-
- /* Write offset 0x0C to 0x1D or 0x91 */
- buffer[0] = 0x0C;
- buffer[1] = is_over_340mhz ? 0x1D : 0x91;
- i2c_success = i2c_write(pipe_ctx, slave_address,
- buffer, sizeof(buffer));
- RETIMER_REDRIVER_INFO("retimer write to slave_addr = 0x%x,\
- offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
- slave_address, buffer[0], buffer[1], i2c_success?1:0);
- if (!i2c_success)
- goto i2c_write_fail;
-
- /* Write offset 0x0A to 0x17 */
- buffer[0] = 0x0A;
- buffer[1] = 0x17;
- i2c_success = i2c_write(pipe_ctx, slave_address,
- buffer, sizeof(buffer));
- RETIMER_REDRIVER_INFO("retimer write to slave_addr = 0x%x,\
- offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
- slave_address, buffer[0], buffer[1], i2c_success?1:0);
- if (!i2c_success)
- goto i2c_write_fail;
-
-
- if (is_vga_mode) {
- /* Program additional settings if using 640x480 resolution */
-
- /* Write offset 0xFF to 0x01 */
- buffer[0] = 0xff;
- buffer[1] = 0x01;
- i2c_success = i2c_write(pipe_ctx, slave_address,
- buffer, sizeof(buffer));
- RETIMER_REDRIVER_INFO("retimer write to slave_addr = 0x%x,\
- offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
- slave_address, buffer[0], buffer[1], i2c_success?1:0);
- if (!i2c_success)
- goto i2c_write_fail;
-
- /* Write offset 0x00 to 0x23 */
- buffer[0] = 0x00;
- buffer[1] = 0x23;
- i2c_success = i2c_write(pipe_ctx, slave_address,
- buffer, sizeof(buffer));
- RETIMER_REDRIVER_INFO("retimer write to slave_addr = 0x%x,\
- offset = 0x%x, reg_val= 0x%x, i2c_success = %d\n",
- slave_address, buffer[0], buffer[1], i2c_success?1:0);
- if (!i2c_success)
- goto i2c_write_fail;
-
- /* Write offset 0xff to 0x00 */
- buffer[0] = 0xff;
- buffer[1] = 0x00;
- i2c_success = i2c_write(pipe_ctx, slave_address,
- buffer, sizeof(buffer));
- RETIMER_REDRIVER_INFO("retimer write default setting to slave_addr = 0x%x,\
- offset = 0x%x, reg_val= 0x%x, i2c_success = %d end here\n",
- slave_address, buffer[0], buffer[1], i2c_success?1:0);
- if (!i2c_success)
- goto i2c_write_fail;
- }
-
- return;
-
-i2c_write_fail:
- DC_LOG_DEBUG("Set default retimer failed");
-}
-
-static void write_i2c_redriver_setting(
- struct pipe_ctx *pipe_ctx,
- bool is_over_340mhz)
-{
- uint8_t slave_address = (0xF0 >> 1);
- uint8_t buffer[16];
- bool i2c_success = false;
- DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
-
- memset(&buffer, 0, sizeof(buffer));
-
- // Program Slave Address for tuning single integrity
- buffer[3] = 0x4E;
- buffer[4] = 0x4E;
- buffer[5] = 0x4E;
- buffer[6] = is_over_340mhz ? 0x4E : 0x4A;
-
- i2c_success = i2c_write(pipe_ctx, slave_address,
- buffer, sizeof(buffer));
- RETIMER_REDRIVER_INFO("redriver write 0 to all 16 reg offset expect following:\n\
- \t slave_addr = 0x%x, offset[3] = 0x%x, offset[4] = 0x%x,\
- offset[5] = 0x%x,offset[6] is_over_340mhz = 0x%x,\
- i2c_success = %d\n",
- slave_address, buffer[3], buffer[4], buffer[5], buffer[6], i2c_success?1:0);
-
- if (!i2c_success)
- DC_LOG_DEBUG("Set redriver failed");
-}
-
-static void disable_link(struct dc_link *link, const struct link_resource *link_res,
- enum signal_type signal)
-{
- /*
- * TODO: implement call for dp_set_hw_test_pattern
- * it is needed for compliance testing
- */
-
- /* Here we need to specify that encoder output settings
- * need to be calculated as for the set mode,
- * it will lead to querying dynamic link capabilities
- * which should be done before enable output
- */
-
- if (dc_is_dp_signal(signal)) {
- /* SST DP, eDP */
- struct dc_link_settings link_settings = link->cur_link_settings;
- if (dc_is_dp_sst_signal(signal))
- dp_disable_link_phy(link, link_res, signal);
- else
- dp_disable_link_phy_mst(link, link_res, signal);
-
- if (dc_is_dp_sst_signal(signal) ||
- link->mst_stream_alloc_table.stream_count == 0) {
- if (dp_get_link_encoding_format(&link_settings) == DP_8b_10b_ENCODING) {
- dp_set_fec_enable(link, false);
- dp_set_fec_ready(link, link_res, false);
- }
- }
- } else if (signal != SIGNAL_TYPE_VIRTUAL) {
- link->dc->hwss.disable_link_output(link, link_res, signal);
- }
-
- if (signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
- /* MST disable link only when no stream use the link */
- if (link->mst_stream_alloc_table.stream_count <= 0)
- link->link_status.link_active = false;
- } else {
- link->link_status.link_active = false;
- }
-}
-
-static void enable_link_hdmi(struct pipe_ctx *pipe_ctx)
-{
- struct dc_stream_state *stream = pipe_ctx->stream;
- struct dc_link *link = stream->link;
- enum dc_color_depth display_color_depth;
- enum engine_id eng_id;
- struct ext_hdmi_settings settings = {0};
- bool is_over_340mhz = false;
- bool is_vga_mode = (stream->timing.h_addressable == 640)
- && (stream->timing.v_addressable == 480);
- struct dc *dc = pipe_ctx->stream->ctx->dc;
-
- if (stream->phy_pix_clk == 0)
- stream->phy_pix_clk = stream->timing.pix_clk_100hz / 10;
- if (stream->phy_pix_clk > 340000)
- is_over_340mhz = true;
-
- if (dc_is_hdmi_signal(pipe_ctx->stream->signal)) {
- unsigned short masked_chip_caps = pipe_ctx->stream->link->chip_caps &
- EXT_DISPLAY_PATH_CAPS__EXT_CHIP_MASK;
- if (masked_chip_caps == EXT_DISPLAY_PATH_CAPS__HDMI20_TISN65DP159RSBT) {
- /* DP159, Retimer settings */
- eng_id = pipe_ctx->stream_res.stream_enc->id;
-
- if (get_ext_hdmi_settings(pipe_ctx, eng_id, &settings)) {
- write_i2c_retimer_setting(pipe_ctx,
- is_vga_mode, is_over_340mhz, &settings);
- } else {
- write_i2c_default_retimer_setting(pipe_ctx,
- is_vga_mode, is_over_340mhz);
- }
- } else if (masked_chip_caps == EXT_DISPLAY_PATH_CAPS__HDMI20_PI3EQX1204) {
- /* PI3EQX1204, Redriver settings */
- write_i2c_redriver_setting(pipe_ctx, is_over_340mhz);
- }
- }
-
- if (dc_is_hdmi_signal(pipe_ctx->stream->signal))
- dal_ddc_service_write_scdc_data(
- stream->link->ddc,
- stream->phy_pix_clk,
- stream->timing.flags.LTE_340MCSC_SCRAMBLE);
-
- memset(&stream->link->cur_link_settings, 0,
- sizeof(struct dc_link_settings));
-
- display_color_depth = stream->timing.display_color_depth;
- if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR422)
- display_color_depth = COLOR_DEPTH_888;
-
- dc->hwss.enable_tmds_link_output(
- link,
- &pipe_ctx->link_res,
- pipe_ctx->stream->signal,
- pipe_ctx->clock_source->id,
- display_color_depth,
- stream->phy_pix_clk);
-
- if (dc_is_hdmi_signal(pipe_ctx->stream->signal))
- dal_ddc_service_read_scdc_data(link->ddc);
-}
-
-static void enable_link_lvds(struct pipe_ctx *pipe_ctx)
-{
- struct dc_stream_state *stream = pipe_ctx->stream;
- struct dc_link *link = stream->link;
- struct dc *dc = stream->ctx->dc;
-
- if (stream->phy_pix_clk == 0)
- stream->phy_pix_clk = stream->timing.pix_clk_100hz / 10;
-
- memset(&stream->link->cur_link_settings, 0,
- sizeof(struct dc_link_settings));
- dc->hwss.enable_lvds_link_output(
- link,
- &pipe_ctx->link_res,
- pipe_ctx->clock_source->id,
- stream->phy_pix_clk);
-
-}
-
-bool dc_power_alpm_dpcd_enable(struct dc_link *link, bool enable)
-{
- bool ret = false;
- union dpcd_alpm_configuration alpm_config;
-
- if (link->psr_settings.psr_version == DC_PSR_VERSION_SU_1) {
- memset(&alpm_config, 0, sizeof(alpm_config));
-
- alpm_config.bits.ENABLE = (enable ? true : false);
- ret = dm_helpers_dp_write_dpcd(link->ctx, link,
- DP_RECEIVER_ALPM_CONFIG, &alpm_config.raw,
- sizeof(alpm_config.raw));
- }
- return ret;
-}
-
-/****************************enable_link***********************************/
-static enum dc_status enable_link(
- struct dc_state *state,
- struct pipe_ctx *pipe_ctx)
-{
- enum dc_status status = DC_ERROR_UNEXPECTED;
- struct dc_stream_state *stream = pipe_ctx->stream;
- struct dc_link *link = stream->link;
-
- /* There's some scenarios where driver is unloaded with display
- * still enabled. When driver is reloaded, it may cause a display
- * to not light up if there is a mismatch between old and new
- * link settings. Need to call disable first before enabling at
- * new link settings.
- */
- if (link->link_status.link_active) {
- disable_link(link, &pipe_ctx->link_res, pipe_ctx->stream->signal);
- }
-
- switch (pipe_ctx->stream->signal) {
- case SIGNAL_TYPE_DISPLAY_PORT:
- status = enable_link_dp(state, pipe_ctx);
- break;
- case SIGNAL_TYPE_EDP:
- status = enable_link_edp(state, pipe_ctx);
- break;
- case SIGNAL_TYPE_DISPLAY_PORT_MST:
- status = enable_link_dp_mst(state, pipe_ctx);
- msleep(200);
- break;
- case SIGNAL_TYPE_DVI_SINGLE_LINK:
- case SIGNAL_TYPE_DVI_DUAL_LINK:
- case SIGNAL_TYPE_HDMI_TYPE_A:
- enable_link_hdmi(pipe_ctx);
- status = DC_OK;
- break;
- case SIGNAL_TYPE_LVDS:
- enable_link_lvds(pipe_ctx);
- status = DC_OK;
- break;
- case SIGNAL_TYPE_VIRTUAL:
- status = DC_OK;
- break;
- default:
- break;
- }
-
- if (status == DC_OK)
- pipe_ctx->stream->link->link_status.link_active = true;
-
- return status;
-}
-
-static uint32_t get_timing_pixel_clock_100hz(const struct dc_crtc_timing *timing)
-{
-
- uint32_t pxl_clk = timing->pix_clk_100hz;
-
- if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420)
- pxl_clk /= 2;
- else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR422)
- pxl_clk = pxl_clk * 2 / 3;
-
- if (timing->display_color_depth == COLOR_DEPTH_101010)
- pxl_clk = pxl_clk * 10 / 8;
- else if (timing->display_color_depth == COLOR_DEPTH_121212)
- pxl_clk = pxl_clk * 12 / 8;
-
- return pxl_clk;
-}
-
-static bool dp_active_dongle_validate_timing(
- const struct dc_crtc_timing *timing,
- const struct dpcd_caps *dpcd_caps)
-{
- const struct dc_dongle_caps *dongle_caps = &dpcd_caps->dongle_caps;
-
- switch (dpcd_caps->dongle_type) {
- case DISPLAY_DONGLE_DP_VGA_CONVERTER:
- case DISPLAY_DONGLE_DP_DVI_CONVERTER:
- case DISPLAY_DONGLE_DP_DVI_DONGLE:
- if (timing->pixel_encoding == PIXEL_ENCODING_RGB)
- return true;
- else
- return false;
- default:
- break;
- }
-
- if (dpcd_caps->dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER &&
- dongle_caps->extendedCapValid == true) {
- /* Check Pixel Encoding */
- switch (timing->pixel_encoding) {
- case PIXEL_ENCODING_RGB:
- case PIXEL_ENCODING_YCBCR444:
- break;
- case PIXEL_ENCODING_YCBCR422:
- if (!dongle_caps->is_dp_hdmi_ycbcr422_pass_through)
- return false;
- break;
- case PIXEL_ENCODING_YCBCR420:
- if (!dongle_caps->is_dp_hdmi_ycbcr420_pass_through)
- return false;
- break;
- default:
- /* Invalid Pixel Encoding*/
- return false;
- }
-
- switch (timing->display_color_depth) {
- case COLOR_DEPTH_666:
- case COLOR_DEPTH_888:
- /*888 and 666 should always be supported*/
- break;
- case COLOR_DEPTH_101010:
- if (dongle_caps->dp_hdmi_max_bpc < 10)
- return false;
- break;
- case COLOR_DEPTH_121212:
- if (dongle_caps->dp_hdmi_max_bpc < 12)
- return false;
- break;
- case COLOR_DEPTH_141414:
- case COLOR_DEPTH_161616:
- default:
- /* These color depths are currently not supported */
- return false;
- }
-
- /* Check 3D format */
- switch (timing->timing_3d_format) {
- case TIMING_3D_FORMAT_NONE:
- case TIMING_3D_FORMAT_FRAME_ALTERNATE:
- /*Only frame alternate 3D is supported on active dongle*/
- break;
- default:
- /*other 3D formats are not supported due to bad infoframe translation */
- return false;
- }
-
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- if (dongle_caps->dp_hdmi_frl_max_link_bw_in_kbps > 0) { // DP to HDMI FRL converter
- struct dc_crtc_timing outputTiming = *timing;
-
- if (timing->flags.DSC && !timing->dsc_cfg.is_frl)
- /* DP input has DSC, HDMI FRL output doesn't have DSC, remove DSC from output timing */
- outputTiming.flags.DSC = 0;
- if (dc_bandwidth_in_kbps_from_timing(&outputTiming) > dongle_caps->dp_hdmi_frl_max_link_bw_in_kbps)
- return false;
- } else { // DP to HDMI TMDS converter
- if (get_timing_pixel_clock_100hz(timing) > (dongle_caps->dp_hdmi_max_pixel_clk_in_khz * 10))
- return false;
- }
-#else
- if (get_timing_pixel_clock_100hz(timing) > (dongle_caps->dp_hdmi_max_pixel_clk_in_khz * 10))
- return false;
-#endif
- }
-
- if (dpcd_caps->channel_coding_cap.bits.DP_128b_132b_SUPPORTED == 0 &&
- dpcd_caps->dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_PASSTHROUGH_SUPPORT == 0 &&
- dongle_caps->dfp_cap_ext.supported) {
-
- if (dongle_caps->dfp_cap_ext.max_pixel_rate_in_mps < (timing->pix_clk_100hz / 10000))
- return false;
-
- if (dongle_caps->dfp_cap_ext.max_video_h_active_width < timing->h_addressable)
- return false;
-
- if (dongle_caps->dfp_cap_ext.max_video_v_active_height < timing->v_addressable)
- return false;
-
- if (timing->pixel_encoding == PIXEL_ENCODING_RGB) {
- if (!dongle_caps->dfp_cap_ext.encoding_format_caps.support_rgb)
- return false;
- if (timing->display_color_depth == COLOR_DEPTH_666 &&
- !dongle_caps->dfp_cap_ext.rgb_color_depth_caps.support_6bpc)
- return false;
- else if (timing->display_color_depth == COLOR_DEPTH_888 &&
- !dongle_caps->dfp_cap_ext.rgb_color_depth_caps.support_8bpc)
- return false;
- else if (timing->display_color_depth == COLOR_DEPTH_101010 &&
- !dongle_caps->dfp_cap_ext.rgb_color_depth_caps.support_10bpc)
- return false;
- else if (timing->display_color_depth == COLOR_DEPTH_121212 &&
- !dongle_caps->dfp_cap_ext.rgb_color_depth_caps.support_12bpc)
- return false;
- else if (timing->display_color_depth == COLOR_DEPTH_161616 &&
- !dongle_caps->dfp_cap_ext.rgb_color_depth_caps.support_16bpc)
- return false;
- } else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR444) {
- if (!dongle_caps->dfp_cap_ext.encoding_format_caps.support_rgb)
- return false;
- if (timing->display_color_depth == COLOR_DEPTH_888 &&
- !dongle_caps->dfp_cap_ext.ycbcr444_color_depth_caps.support_8bpc)
- return false;
- else if (timing->display_color_depth == COLOR_DEPTH_101010 &&
- !dongle_caps->dfp_cap_ext.ycbcr444_color_depth_caps.support_10bpc)
- return false;
- else if (timing->display_color_depth == COLOR_DEPTH_121212 &&
- !dongle_caps->dfp_cap_ext.ycbcr444_color_depth_caps.support_12bpc)
- return false;
- else if (timing->display_color_depth == COLOR_DEPTH_161616 &&
- !dongle_caps->dfp_cap_ext.ycbcr444_color_depth_caps.support_16bpc)
- return false;
- } else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
- if (!dongle_caps->dfp_cap_ext.encoding_format_caps.support_rgb)
- return false;
- if (timing->display_color_depth == COLOR_DEPTH_888 &&
- !dongle_caps->dfp_cap_ext.ycbcr422_color_depth_caps.support_8bpc)
- return false;
- else if (timing->display_color_depth == COLOR_DEPTH_101010 &&
- !dongle_caps->dfp_cap_ext.ycbcr422_color_depth_caps.support_10bpc)
- return false;
- else if (timing->display_color_depth == COLOR_DEPTH_121212 &&
- !dongle_caps->dfp_cap_ext.ycbcr422_color_depth_caps.support_12bpc)
- return false;
- else if (timing->display_color_depth == COLOR_DEPTH_161616 &&
- !dongle_caps->dfp_cap_ext.ycbcr422_color_depth_caps.support_16bpc)
- return false;
- } else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) {
- if (!dongle_caps->dfp_cap_ext.encoding_format_caps.support_rgb)
- return false;
- if (timing->display_color_depth == COLOR_DEPTH_888 &&
- !dongle_caps->dfp_cap_ext.ycbcr420_color_depth_caps.support_8bpc)
- return false;
- else if (timing->display_color_depth == COLOR_DEPTH_101010 &&
- !dongle_caps->dfp_cap_ext.ycbcr420_color_depth_caps.support_10bpc)
- return false;
- else if (timing->display_color_depth == COLOR_DEPTH_121212 &&
- !dongle_caps->dfp_cap_ext.ycbcr420_color_depth_caps.support_12bpc)
- return false;
- else if (timing->display_color_depth == COLOR_DEPTH_161616 &&
- !dongle_caps->dfp_cap_ext.ycbcr420_color_depth_caps.support_16bpc)
- return false;
- }
- }
-
- return true;
-}
-
-enum dc_status dc_link_validate_mode_timing(
- const struct dc_stream_state *stream,
- struct dc_link *link,
- const struct dc_crtc_timing *timing)
-{
- uint32_t max_pix_clk = stream->link->dongle_max_pix_clk * 10;
- struct dpcd_caps *dpcd_caps = &link->dpcd_caps;
-
- /* A hack to avoid failing any modes for EDID override feature on
- * topology change such as lower quality cable for DP or different dongle
- */
- if (link->remote_sinks[0] && link->remote_sinks[0]->sink_signal == SIGNAL_TYPE_VIRTUAL)
- return DC_OK;
-
- /* Passive Dongle */
- if (max_pix_clk != 0 && get_timing_pixel_clock_100hz(timing) > max_pix_clk)
- return DC_EXCEED_DONGLE_CAP;
-
- /* Active Dongle*/
- if (!dp_active_dongle_validate_timing(timing, dpcd_caps))
- return DC_EXCEED_DONGLE_CAP;
-
- switch (stream->signal) {
- case SIGNAL_TYPE_EDP:
- case SIGNAL_TYPE_DISPLAY_PORT:
- if (!dp_validate_mode_timing(
- link,
- timing))
- return DC_NO_DP_LINK_BANDWIDTH;
- break;
-
- default:
- break;
- }
-
- return DC_OK;
-}
-
-static struct abm *get_abm_from_stream_res(const struct dc_link *link)
-{
- int i;
- struct dc *dc = NULL;
- struct abm *abm = NULL;
-
- if (!link || !link->ctx)
- return NULL;
-
- dc = link->ctx->dc;
-
- for (i = 0; i < MAX_PIPES; i++) {
- struct pipe_ctx pipe_ctx = dc->current_state->res_ctx.pipe_ctx[i];
- struct dc_stream_state *stream = pipe_ctx.stream;
-
- if (stream && stream->link == link) {
- abm = pipe_ctx.stream_res.abm;
- break;
- }
- }
- return abm;
-}
-
-int dc_link_get_backlight_level(const struct dc_link *link)
-{
- struct abm *abm = get_abm_from_stream_res(link);
- struct panel_cntl *panel_cntl = link->panel_cntl;
- struct dc *dc = link->ctx->dc;
- struct dmcu *dmcu = dc->res_pool->dmcu;
- bool fw_set_brightness = true;
-
- if (dmcu)
- fw_set_brightness = dmcu->funcs->is_dmcu_initialized(dmcu);
-
- if (!fw_set_brightness && panel_cntl->funcs->get_current_backlight)
- return panel_cntl->funcs->get_current_backlight(panel_cntl);
- else if (abm != NULL && abm->funcs->get_current_backlight != NULL)
- return (int) abm->funcs->get_current_backlight(abm);
- else
- return DC_ERROR_UNEXPECTED;
-}
-
-int dc_link_get_target_backlight_pwm(const struct dc_link *link)
-{
- struct abm *abm = get_abm_from_stream_res(link);
-
- if (abm == NULL || abm->funcs->get_target_backlight == NULL)
- return DC_ERROR_UNEXPECTED;
-
- return (int) abm->funcs->get_target_backlight(abm);
-}
-
-static struct pipe_ctx *get_pipe_from_link(const struct dc_link *link)
-{
- int i;
- struct dc *dc = link->ctx->dc;
- struct pipe_ctx *pipe_ctx = NULL;
-
- for (i = 0; i < MAX_PIPES; i++) {
- if (dc->current_state->res_ctx.pipe_ctx[i].stream) {
- if (dc->current_state->res_ctx.pipe_ctx[i].stream->link == link) {
- pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
- break;
- }
- }
- }
-
- return pipe_ctx;
-}
-
-bool dc_link_set_backlight_level(const struct dc_link *link,
- uint32_t backlight_pwm_u16_16,
- uint32_t frame_ramp)
-{
- struct dc *dc = link->ctx->dc;
-
- DC_LOGGER_INIT(link->ctx->logger);
- DC_LOG_BACKLIGHT("New Backlight level: %d (0x%X)\n",
- backlight_pwm_u16_16, backlight_pwm_u16_16);
-
- if (dc_is_embedded_signal(link->connector_signal)) {
- struct pipe_ctx *pipe_ctx = get_pipe_from_link(link);
-
- if (pipe_ctx) {
- /* Disable brightness ramping when the display is blanked
- * as it can hang the DMCU
- */
- if (pipe_ctx->plane_state == NULL)
- frame_ramp = 0;
- } else {
- return false;
- }
-
- dc->hwss.set_backlight_level(
- pipe_ctx,
- backlight_pwm_u16_16,
- frame_ramp);
- }
- return true;
-}
-
-bool dc_link_set_psr_allow_active(struct dc_link *link, const bool *allow_active,
- bool wait, bool force_static, const unsigned int *power_opts)
-{
- struct dc *dc = link->ctx->dc;
- struct dmcu *dmcu = dc->res_pool->dmcu;
- struct dmub_psr *psr = dc->res_pool->psr;
- unsigned int panel_inst;
-
- if (psr == NULL && force_static)
- return false;
-
- if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst))
- return false;
-
- if ((allow_active != NULL) && (*allow_active == true) && (link->type == dc_connection_none)) {
- // Don't enter PSR if panel is not connected
- return false;
- }
-
- /* Set power optimization flag */
- if (power_opts && link->psr_settings.psr_power_opt != *power_opts) {
- link->psr_settings.psr_power_opt = *power_opts;
-
- if (psr != NULL && link->psr_settings.psr_feature_enabled && psr->funcs->psr_set_power_opt)
- psr->funcs->psr_set_power_opt(psr, link->psr_settings.psr_power_opt, panel_inst);
- }
-
- if (psr != NULL && link->psr_settings.psr_feature_enabled &&
- force_static && psr->funcs->psr_force_static)
- psr->funcs->psr_force_static(psr, panel_inst);
-
- /* Enable or Disable PSR */
- if (allow_active && link->psr_settings.psr_allow_active != *allow_active) {
- link->psr_settings.psr_allow_active = *allow_active;
-
- if (!link->psr_settings.psr_allow_active)
- dc_z10_restore(dc);
-
- if (psr != NULL && link->psr_settings.psr_feature_enabled) {
- psr->funcs->psr_enable(psr, link->psr_settings.psr_allow_active, wait, panel_inst);
- } else if ((dmcu != NULL && dmcu->funcs->is_dmcu_initialized(dmcu)) &&
- link->psr_settings.psr_feature_enabled)
- dmcu->funcs->set_psr_enable(dmcu, link->psr_settings.psr_allow_active, wait);
- else
- return false;
- }
-
- return true;
-}
-
-bool dc_link_get_psr_state(const struct dc_link *link, enum dc_psr_state *state)
-{
- struct dc *dc = link->ctx->dc;
- struct dmcu *dmcu = dc->res_pool->dmcu;
- struct dmub_psr *psr = dc->res_pool->psr;
- unsigned int panel_inst;
-
- if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst))
- return false;
-
- if (psr != NULL && link->psr_settings.psr_feature_enabled)
- psr->funcs->psr_get_state(psr, state, panel_inst);
- else if (dmcu != NULL && link->psr_settings.psr_feature_enabled)
- dmcu->funcs->get_psr_state(dmcu, state);
-
- return true;
-}
-
-static inline enum physical_phy_id
-transmitter_to_phy_id(enum transmitter transmitter_value)
-{
- switch (transmitter_value) {
- case TRANSMITTER_UNIPHY_A:
- return PHYLD_0;
- case TRANSMITTER_UNIPHY_B:
- return PHYLD_1;
- case TRANSMITTER_UNIPHY_C:
- return PHYLD_2;
- case TRANSMITTER_UNIPHY_D:
- return PHYLD_3;
- case TRANSMITTER_UNIPHY_E:
- return PHYLD_4;
- case TRANSMITTER_UNIPHY_F:
- return PHYLD_5;
- case TRANSMITTER_NUTMEG_CRT:
- return PHYLD_6;
- case TRANSMITTER_TRAVIS_CRT:
- return PHYLD_7;
- case TRANSMITTER_TRAVIS_LCD:
- return PHYLD_8;
- case TRANSMITTER_UNIPHY_G:
- return PHYLD_9;
- case TRANSMITTER_COUNT:
- return PHYLD_COUNT;
- case TRANSMITTER_UNKNOWN:
- return PHYLD_UNKNOWN;
- default:
- WARN_ONCE(1, "Unknown transmitter value %d\n",
- transmitter_value);
- return PHYLD_UNKNOWN;
- }
-}
-
-bool dc_link_setup_psr(struct dc_link *link,
- const struct dc_stream_state *stream, struct psr_config *psr_config,
- struct psr_context *psr_context)
-{
- struct dc *dc;
- struct dmcu *dmcu;
- struct dmub_psr *psr;
- int i;
- unsigned int panel_inst;
- /* updateSinkPsrDpcdConfig*/
- union dpcd_psr_configuration psr_configuration;
- union dpcd_sink_active_vtotal_control_mode vtotal_control = {0};
-
- psr_context->controllerId = CONTROLLER_ID_UNDEFINED;
-
- if (!link)
- return false;
-
- dc = link->ctx->dc;
- dmcu = dc->res_pool->dmcu;
- psr = dc->res_pool->psr;
-
- if (!dmcu && !psr)
- return false;
-
- if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst))
- return false;
-
-
- memset(&psr_configuration, 0, sizeof(psr_configuration));
-
- psr_configuration.bits.ENABLE = 1;
- psr_configuration.bits.CRC_VERIFICATION = 1;
- psr_configuration.bits.FRAME_CAPTURE_INDICATION =
- psr_config->psr_frame_capture_indication_req;
-
- /* Check for PSR v2*/
- if (link->psr_settings.psr_version == DC_PSR_VERSION_SU_1) {
- /* For PSR v2 selective update.
- * Indicates whether sink should start capturing
- * immediately following active scan line,
- * or starting with the 2nd active scan line.
- */
- psr_configuration.bits.LINE_CAPTURE_INDICATION = 0;
- /*For PSR v2, determines whether Sink should generate
- * IRQ_HPD when CRC mismatch is detected.
- */
- psr_configuration.bits.IRQ_HPD_WITH_CRC_ERROR = 1;
- /* For PSR v2, set the bit when the Source device will
- * be enabling PSR2 operation.
- */
- psr_configuration.bits.ENABLE_PSR2 = 1;
- /* For PSR v2, the Sink device must be able to receive
- * SU region updates early in the frame time.
- */
- psr_configuration.bits.EARLY_TRANSPORT_ENABLE = 1;
- }
-
- dm_helpers_dp_write_dpcd(
- link->ctx,
- link,
- 368,
- &psr_configuration.raw,
- sizeof(psr_configuration.raw));
-
- if (link->psr_settings.psr_version == DC_PSR_VERSION_SU_1) {
- dc_power_alpm_dpcd_enable(link, true);
- psr_context->su_granularity_required =
- psr_config->su_granularity_required;
- psr_context->su_y_granularity =
- psr_config->su_y_granularity;
- psr_context->line_time_in_us =
- psr_config->line_time_in_us;
-
- if (link->psr_settings.psr_vtotal_control_support) {
- psr_context->rate_control_caps = psr_config->rate_control_caps;
- vtotal_control.bits.ENABLE = true;
- core_link_write_dpcd(link, DP_SINK_PSR_ACTIVE_VTOTAL_CONTROL_MODE,
- &vtotal_control.raw, sizeof(vtotal_control.raw));
- }
- }
-
- psr_context->channel = link->ddc->ddc_pin->hw_info.ddc_channel;
- psr_context->transmitterId = link->link_enc->transmitter;
- psr_context->engineId = link->link_enc->preferred_engine;
-
- for (i = 0; i < MAX_PIPES; i++) {
- if (dc->current_state->res_ctx.pipe_ctx[i].stream
- == stream) {
- /* dmcu -1 for all controller id values,
- * therefore +1 here
- */
- psr_context->controllerId =
- dc->current_state->res_ctx.
- pipe_ctx[i].stream_res.tg->inst + 1;
- break;
- }
- }
-
- /* Hardcoded for now. Can be Pcie or Uniphy (or Unknown)*/
- psr_context->phyType = PHY_TYPE_UNIPHY;
- /*PhyId is associated with the transmitter id*/
- psr_context->smuPhyId =
- transmitter_to_phy_id(link->link_enc->transmitter);
-
- psr_context->crtcTimingVerticalTotal = stream->timing.v_total;
- psr_context->vsync_rate_hz = div64_u64(div64_u64((stream->
- timing.pix_clk_100hz * 100),
- stream->timing.v_total),
- stream->timing.h_total);
-
- psr_context->psrSupportedDisplayConfig = true;
- psr_context->psrExitLinkTrainingRequired =
- psr_config->psr_exit_link_training_required;
- psr_context->sdpTransmitLineNumDeadline =
- psr_config->psr_sdp_transmit_line_num_deadline;
- psr_context->psrFrameCaptureIndicationReq =
- psr_config->psr_frame_capture_indication_req;
-
- psr_context->skipPsrWaitForPllLock = 0; /* only = 1 in KV */
-
- psr_context->numberOfControllers =
- link->dc->res_pool->timing_generator_count;
-
- psr_context->rfb_update_auto_en = true;
-
- /* 2 frames before enter PSR. */
- psr_context->timehyst_frames = 2;
- /* half a frame
- * (units in 100 lines, i.e. a value of 1 represents 100 lines)
- */
- psr_context->hyst_lines = stream->timing.v_total / 2 / 100;
- psr_context->aux_repeats = 10;
-
- psr_context->psr_level.u32all = 0;
-
- /*skip power down the single pipe since it blocks the cstate*/
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- if (link->ctx->asic_id.chip_family >= FAMILY_RV) {
- switch(link->ctx->asic_id.chip_family) {
- case FAMILY_YELLOW_CARP:
- case AMDGPU_FAMILY_GC_10_3_6:
- case AMDGPU_FAMILY_GC_11_0_1:
- if (dc->debug.disable_z10 || dc->debug.psr_skip_crtc_disable)
- psr_context->psr_level.bits.SKIP_CRTC_DISABLE = true;
- break;
- default:
- psr_context->psr_level.bits.SKIP_CRTC_DISABLE = true;
- break;
- }
- }
-#else
- if (link->ctx->asic_id.chip_family >= FAMILY_RV)
- psr_context->psr_level.bits.SKIP_CRTC_DISABLE = true;
-#endif
-
- /* SMU will perform additional powerdown sequence.
- * For unsupported ASICs, set psr_level flag to skip PSR
- * static screen notification to SMU.
- * (Always set for DAL2, did not check ASIC)
- */
- psr_context->allow_smu_optimizations = psr_config->allow_smu_optimizations;
- psr_context->allow_multi_disp_optimizations = psr_config->allow_multi_disp_optimizations;
-
- /* Complete PSR entry before aborting to prevent intermittent
- * freezes on certain eDPs
- */
- psr_context->psr_level.bits.DISABLE_PSR_ENTRY_ABORT = 1;
-
- /* enable ALPM */
- psr_context->psr_level.bits.DISABLE_ALPM = 0;
- psr_context->psr_level.bits.ALPM_DEFAULT_PD_MODE = 1;
-
- /* Controls additional delay after remote frame capture before
- * continuing power down, default = 0
- */
- psr_context->frame_delay = 0;
-
- if (psr) {
- link->psr_settings.psr_feature_enabled = psr->funcs->psr_copy_settings(psr,
- link, psr_context, panel_inst);
- link->psr_settings.psr_power_opt = 0;
- link->psr_settings.psr_allow_active = 0;
- }
- else
- link->psr_settings.psr_feature_enabled = dmcu->funcs->setup_psr(dmcu, link, psr_context);
-
- /* psr_enabled == 0 indicates setup_psr did not succeed, but this
- * should not happen since firmware should be running at this point
- */
- if (link->psr_settings.psr_feature_enabled == 0)
- ASSERT(0);
-
- return true;
-
-}
-
-void dc_link_get_psr_residency(const struct dc_link *link, uint32_t *residency)
-{
- struct dc *dc = link->ctx->dc;
- struct dmub_psr *psr = dc->res_pool->psr;
- unsigned int panel_inst;
-
- if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst))
- return;
-
- /* PSR residency measurements only supported on DMCUB */
- if (psr != NULL && link->psr_settings.psr_feature_enabled)
- psr->funcs->psr_get_residency(psr, residency, panel_inst);
- else
- *residency = 0;
-}
-
-bool dc_link_set_sink_vtotal_in_psr_active(const struct dc_link *link, uint16_t psr_vtotal_idle, uint16_t psr_vtotal_su)
-{
- struct dc *dc = link->ctx->dc;
- struct dmub_psr *psr = dc->res_pool->psr;
-
- if (psr == NULL || !link->psr_settings.psr_feature_enabled || !link->psr_settings.psr_vtotal_control_support)
- return false;
-
- psr->funcs->psr_set_sink_vtotal_in_psr_active(psr, psr_vtotal_idle, psr_vtotal_su);
-
- return true;
-}
-
-const struct dc_link_status *dc_link_get_status(const struct dc_link *link)
-{
- return &link->link_status;
-}
-
-void core_link_resume(struct dc_link *link)
-{
- if (link->connector_signal != SIGNAL_TYPE_VIRTUAL)
- program_hpd_filter(link);
-}
-
-static struct fixed31_32 get_pbn_per_slot(struct dc_stream_state *stream)
-{
- struct fixed31_32 mbytes_per_sec;
- uint32_t link_rate_in_mbytes_per_sec = dc_link_bandwidth_kbps(stream->link,
- &stream->link->cur_link_settings);
- link_rate_in_mbytes_per_sec /= 8000; /* Kbits to MBytes */
-
- mbytes_per_sec = dc_fixpt_from_int(link_rate_in_mbytes_per_sec);
-
- return dc_fixpt_div_int(mbytes_per_sec, 54);
-}
-
-static struct fixed31_32 get_pbn_from_bw_in_kbps(uint64_t kbps)
-{
- struct fixed31_32 peak_kbps;
- uint32_t numerator = 0;
- uint32_t denominator = 1;
-
- /*
- * margin 5300ppm + 300ppm ~ 0.6% as per spec, factor is 1.006
- * The unit of 54/64Mbytes/sec is an arbitrary unit chosen based on
- * common multiplier to render an integer PBN for all link rate/lane
- * counts combinations
- * calculate
- * peak_kbps *= (1006/1000)
- * peak_kbps *= (64/54)
- * peak_kbps *= 8 convert to bytes
- */
-
- numerator = 64 * PEAK_FACTOR_X1000;
- denominator = 54 * 8 * 1000 * 1000;
- kbps *= numerator;
- peak_kbps = dc_fixpt_from_fraction(kbps, denominator);
-
- return peak_kbps;
-}
-
-static struct fixed31_32 get_pbn_from_timing(struct pipe_ctx *pipe_ctx)
-{
- uint64_t kbps;
-
- kbps = dc_bandwidth_in_kbps_from_timing(&pipe_ctx->stream->timing);
- return get_pbn_from_bw_in_kbps(kbps);
-}
-
-static void update_mst_stream_alloc_table(
- struct dc_link *link,
- struct stream_encoder *stream_enc,
- struct hpo_dp_stream_encoder *hpo_dp_stream_enc, // TODO: Rename stream_enc to dio_stream_enc?
- const struct dc_dp_mst_stream_allocation_table *proposed_table)
-{
- struct link_mst_stream_allocation work_table[MAX_CONTROLLER_NUM] = { 0 };
- struct link_mst_stream_allocation *dc_alloc;
-
- int i;
- int j;
-
- /* if DRM proposed_table has more than one new payload */
- ASSERT(proposed_table->stream_count -
- link->mst_stream_alloc_table.stream_count < 2);
-
- /* copy proposed_table to link, add stream encoder */
- for (i = 0; i < proposed_table->stream_count; i++) {
-
- for (j = 0; j < link->mst_stream_alloc_table.stream_count; j++) {
- dc_alloc =
- &link->mst_stream_alloc_table.stream_allocations[j];
-
- if (dc_alloc->vcp_id ==
- proposed_table->stream_allocations[i].vcp_id) {
-
- work_table[i] = *dc_alloc;
- work_table[i].slot_count = proposed_table->stream_allocations[i].slot_count;
- break; /* exit j loop */
- }
- }
-
- /* new vcp_id */
- if (j == link->mst_stream_alloc_table.stream_count) {
- work_table[i].vcp_id =
- proposed_table->stream_allocations[i].vcp_id;
- work_table[i].slot_count =
- proposed_table->stream_allocations[i].slot_count;
- work_table[i].stream_enc = stream_enc;
- work_table[i].hpo_dp_stream_enc = hpo_dp_stream_enc;
- }
- }
-
- /* update link->mst_stream_alloc_table with work_table */
- link->mst_stream_alloc_table.stream_count =
- proposed_table->stream_count;
- for (i = 0; i < MAX_CONTROLLER_NUM; i++)
- link->mst_stream_alloc_table.stream_allocations[i] =
- work_table[i];
-}
-
-static void remove_stream_from_alloc_table(
- struct dc_link *link,
- struct stream_encoder *dio_stream_enc,
- struct hpo_dp_stream_encoder *hpo_dp_stream_enc)
-{
- int i = 0;
- struct link_mst_stream_allocation_table *table =
- &link->mst_stream_alloc_table;
-
- if (hpo_dp_stream_enc) {
- for (; i < table->stream_count; i++)
- if (hpo_dp_stream_enc == table->stream_allocations[i].hpo_dp_stream_enc)
- break;
- } else {
- for (; i < table->stream_count; i++)
- if (dio_stream_enc == table->stream_allocations[i].stream_enc)
- break;
- }
-
- if (i < table->stream_count) {
- i++;
- for (; i < table->stream_count; i++)
- table->stream_allocations[i-1] = table->stream_allocations[i];
- memset(&table->stream_allocations[table->stream_count-1], 0,
- sizeof(struct link_mst_stream_allocation));
- table->stream_count--;
- }
-}
-
-static void dc_log_vcp_x_y(const struct dc_link *link, struct fixed31_32 avg_time_slots_per_mtp)
-{
- const uint32_t VCP_Y_PRECISION = 1000;
- uint64_t vcp_x, vcp_y;
-
- // Add 0.5*(1/VCP_Y_PRECISION) to round up to decimal precision
- avg_time_slots_per_mtp = dc_fixpt_add(
- avg_time_slots_per_mtp, dc_fixpt_from_fraction(1, 2 * VCP_Y_PRECISION));
-
- vcp_x = dc_fixpt_floor(avg_time_slots_per_mtp);
- vcp_y = dc_fixpt_floor(
- dc_fixpt_mul_int(
- dc_fixpt_sub_int(avg_time_slots_per_mtp, dc_fixpt_floor(avg_time_slots_per_mtp)),
- VCP_Y_PRECISION));
-
- if (link->type == dc_connection_mst_branch)
- DC_LOG_DP2("MST Update Payload: set_throttled_vcp_size slot X.Y for MST stream "
- "X: %lld Y: %lld/%d", vcp_x, vcp_y, VCP_Y_PRECISION);
- else
- DC_LOG_DP2("SST Update Payload: set_throttled_vcp_size slot X.Y for SST stream "
- "X: %lld Y: %lld/%d", vcp_x, vcp_y, VCP_Y_PRECISION);
-}
-
-/*
- * Payload allocation/deallocation for SST introduced in DP2.0
- */
-static enum dc_status dc_link_update_sst_payload(struct pipe_ctx *pipe_ctx,
- bool allocate)
-{
- struct dc_stream_state *stream = pipe_ctx->stream;
- struct dc_link *link = stream->link;
- struct link_mst_stream_allocation_table proposed_table = {0};
- struct fixed31_32 avg_time_slots_per_mtp;
- const struct dc_link_settings empty_link_settings = {0};
- const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
- DC_LOGGER_INIT(link->ctx->logger);
-
- /* slot X.Y for SST payload deallocate */
- if (!allocate) {
- avg_time_slots_per_mtp = dc_fixpt_from_int(0);
-
- dc_log_vcp_x_y(link, avg_time_slots_per_mtp);
-
- if (link_hwss->ext.set_throttled_vcp_size)
- link_hwss->ext.set_throttled_vcp_size(pipe_ctx,
- avg_time_slots_per_mtp);
- if (link_hwss->ext.set_hblank_min_symbol_width)
- link_hwss->ext.set_hblank_min_symbol_width(pipe_ctx,
- &empty_link_settings,
- avg_time_slots_per_mtp);
- }
-
- /* calculate VC payload and update branch with new payload allocation table*/
- if (!dpcd_write_128b_132b_sst_payload_allocation_table(
- stream,
- link,
- &proposed_table,
- allocate)) {
- DC_LOG_ERROR("SST Update Payload: Failed to update "
- "allocation table for "
- "pipe idx: %d\n",
- pipe_ctx->pipe_idx);
- return DC_FAIL_DP_PAYLOAD_ALLOCATION;
- }
-
- proposed_table.stream_allocations[0].hpo_dp_stream_enc = pipe_ctx->stream_res.hpo_dp_stream_enc;
-
- ASSERT(proposed_table.stream_count == 1);
-
- //TODO - DP2.0 Logging: Instead of hpo_dp_stream_enc pointer, log instance id
- DC_LOG_DP2("SST Update Payload: hpo_dp_stream_enc: %p "
- "vcp_id: %d "
- "slot_count: %d\n",
- (void *) proposed_table.stream_allocations[0].hpo_dp_stream_enc,
- proposed_table.stream_allocations[0].vcp_id,
- proposed_table.stream_allocations[0].slot_count);
-
- /* program DP source TX for payload */
- link_hwss->ext.update_stream_allocation_table(link, &pipe_ctx->link_res,
- &proposed_table);
-
- /* poll for ACT handled */
- if (!dpcd_poll_for_allocation_change_trigger(link)) {
- // Failures will result in blackscreen and errors logged
- BREAK_TO_DEBUGGER();
- }
-
- /* slot X.Y for SST payload allocate */
- if (allocate && dp_get_link_encoding_format(&link->cur_link_settings) ==
- DP_128b_132b_ENCODING) {
- avg_time_slots_per_mtp = calculate_sst_avg_time_slots_per_mtp(stream, link);
-
- dc_log_vcp_x_y(link, avg_time_slots_per_mtp);
-
- if (link_hwss->ext.set_throttled_vcp_size)
- link_hwss->ext.set_throttled_vcp_size(pipe_ctx,
- avg_time_slots_per_mtp);
- if (link_hwss->ext.set_hblank_min_symbol_width)
- link_hwss->ext.set_hblank_min_symbol_width(pipe_ctx,
- &link->cur_link_settings,
- avg_time_slots_per_mtp);
- }
-
- /* Always return DC_OK.
- * If part of sequence fails, log failure(s) and show blackscreen
- */
- return DC_OK;
-}
-
-/* convert link_mst_stream_alloc_table to dm dp_mst_stream_alloc_table
- * because stream_encoder is not exposed to dm
- */
-enum dc_status dc_link_allocate_mst_payload(struct pipe_ctx *pipe_ctx)
-{
- struct dc_stream_state *stream = pipe_ctx->stream;
- struct dc_link *link = stream->link;
- struct dc_dp_mst_stream_allocation_table proposed_table = {0};
- struct fixed31_32 avg_time_slots_per_mtp;
- struct fixed31_32 pbn;
- struct fixed31_32 pbn_per_slot;
- int i;
- enum act_return_status ret;
- const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
- DC_LOGGER_INIT(link->ctx->logger);
-
- /* enable_link_dp_mst already check link->enabled_stream_count
- * and stream is in link->stream[]. This is called during set mode,
- * stream_enc is available.
- */
-
- /* get calculate VC payload for stream: stream_alloc */
- if (dm_helpers_dp_mst_write_payload_allocation_table(
- stream->ctx,
- stream,
- &proposed_table,
- true))
- update_mst_stream_alloc_table(
- link,
- pipe_ctx->stream_res.stream_enc,
- pipe_ctx->stream_res.hpo_dp_stream_enc,
- &proposed_table);
- else
- DC_LOG_WARNING("Failed to update"
- "MST allocation table for"
- "pipe idx:%d\n",
- pipe_ctx->pipe_idx);
-
- DC_LOG_MST("%s "
- "stream_count: %d: \n ",
- __func__,
- link->mst_stream_alloc_table.stream_count);
-
- for (i = 0; i < MAX_CONTROLLER_NUM; i++) {
- DC_LOG_MST("stream_enc[%d]: %p "
- "stream[%d].hpo_dp_stream_enc: %p "
- "stream[%d].vcp_id: %d "
- "stream[%d].slot_count: %d\n",
- i,
- (void *) link->mst_stream_alloc_table.stream_allocations[i].stream_enc,
- i,
- (void *) link->mst_stream_alloc_table.stream_allocations[i].hpo_dp_stream_enc,
- i,
- link->mst_stream_alloc_table.stream_allocations[i].vcp_id,
- i,
- link->mst_stream_alloc_table.stream_allocations[i].slot_count);
- }
-
- ASSERT(proposed_table.stream_count > 0);
-
- /* program DP source TX for payload */
- if (link_hwss->ext.update_stream_allocation_table == NULL ||
- dp_get_link_encoding_format(&link->cur_link_settings) == DP_UNKNOWN_ENCODING) {
- DC_LOG_ERROR("Failure: unknown encoding format\n");
- return DC_ERROR_UNEXPECTED;
- }
-
- link_hwss->ext.update_stream_allocation_table(link,
- &pipe_ctx->link_res,
- &link->mst_stream_alloc_table);
-
- /* send down message */
- ret = dm_helpers_dp_mst_poll_for_allocation_change_trigger(
- stream->ctx,
- stream);
-
- if (ret != ACT_LINK_LOST) {
- dm_helpers_dp_mst_send_payload_allocation(
- stream->ctx,
- stream,
- true);
- }
-
- /* slot X.Y for only current stream */
- pbn_per_slot = get_pbn_per_slot(stream);
- if (pbn_per_slot.value == 0) {
- DC_LOG_ERROR("Failure: pbn_per_slot==0 not allowed. Cannot continue, returning DC_UNSUPPORTED_VALUE.\n");
- return DC_UNSUPPORTED_VALUE;
- }
- pbn = get_pbn_from_timing(pipe_ctx);
- avg_time_slots_per_mtp = dc_fixpt_div(pbn, pbn_per_slot);
-
- dc_log_vcp_x_y(link, avg_time_slots_per_mtp);
-
- if (link_hwss->ext.set_throttled_vcp_size)
- link_hwss->ext.set_throttled_vcp_size(pipe_ctx, avg_time_slots_per_mtp);
- if (link_hwss->ext.set_hblank_min_symbol_width)
- link_hwss->ext.set_hblank_min_symbol_width(pipe_ctx,
- &link->cur_link_settings,
- avg_time_slots_per_mtp);
-
- return DC_OK;
-
-}
-
-enum dc_status dc_link_reduce_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t bw_in_kbps)
-{
- struct dc_stream_state *stream = pipe_ctx->stream;
- struct dc_link *link = stream->link;
- struct fixed31_32 avg_time_slots_per_mtp;
- struct fixed31_32 pbn;
- struct fixed31_32 pbn_per_slot;
- struct dc_dp_mst_stream_allocation_table proposed_table = {0};
- uint8_t i;
- const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
- DC_LOGGER_INIT(link->ctx->logger);
-
- /* decrease throttled vcp size */
- pbn_per_slot = get_pbn_per_slot(stream);
- pbn = get_pbn_from_bw_in_kbps(bw_in_kbps);
- avg_time_slots_per_mtp = dc_fixpt_div(pbn, pbn_per_slot);
-
- if (link_hwss->ext.set_throttled_vcp_size)
- link_hwss->ext.set_throttled_vcp_size(pipe_ctx, avg_time_slots_per_mtp);
- if (link_hwss->ext.set_hblank_min_symbol_width)
- link_hwss->ext.set_hblank_min_symbol_width(pipe_ctx,
- &link->cur_link_settings,
- avg_time_slots_per_mtp);
-
- /* send ALLOCATE_PAYLOAD sideband message with updated pbn */
- dm_helpers_dp_mst_send_payload_allocation(
- stream->ctx,
- stream,
- true);
-
- /* notify immediate branch device table update */
- if (dm_helpers_dp_mst_write_payload_allocation_table(
- stream->ctx,
- stream,
- &proposed_table,
- true)) {
- /* update mst stream allocation table software state */
- update_mst_stream_alloc_table(
- link,
- pipe_ctx->stream_res.stream_enc,
- pipe_ctx->stream_res.hpo_dp_stream_enc,
- &proposed_table);
- } else {
- DC_LOG_WARNING("Failed to update"
- "MST allocation table for"
- "pipe idx:%d\n",
- pipe_ctx->pipe_idx);
- }
-
- DC_LOG_MST("%s "
- "stream_count: %d: \n ",
- __func__,
- link->mst_stream_alloc_table.stream_count);
-
- for (i = 0; i < MAX_CONTROLLER_NUM; i++) {
- DC_LOG_MST("stream_enc[%d]: %p "
- "stream[%d].hpo_dp_stream_enc: %p "
- "stream[%d].vcp_id: %d "
- "stream[%d].slot_count: %d\n",
- i,
- (void *) link->mst_stream_alloc_table.stream_allocations[i].stream_enc,
- i,
- (void *) link->mst_stream_alloc_table.stream_allocations[i].hpo_dp_stream_enc,
- i,
- link->mst_stream_alloc_table.stream_allocations[i].vcp_id,
- i,
- link->mst_stream_alloc_table.stream_allocations[i].slot_count);
- }
-
- ASSERT(proposed_table.stream_count > 0);
-
- /* update mst stream allocation table hardware state */
- if (link_hwss->ext.update_stream_allocation_table == NULL ||
- dp_get_link_encoding_format(&link->cur_link_settings) == DP_UNKNOWN_ENCODING) {
- DC_LOG_ERROR("Failure: unknown encoding format\n");
- return DC_ERROR_UNEXPECTED;
- }
-
- link_hwss->ext.update_stream_allocation_table(link, &pipe_ctx->link_res,
- &link->mst_stream_alloc_table);
-
- /* poll for immediate branch device ACT handled */
- dm_helpers_dp_mst_poll_for_allocation_change_trigger(
- stream->ctx,
- stream);
-
- return DC_OK;
-}
-
-enum dc_status dc_link_increase_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t bw_in_kbps)
-{
- struct dc_stream_state *stream = pipe_ctx->stream;
- struct dc_link *link = stream->link;
- struct fixed31_32 avg_time_slots_per_mtp;
- struct fixed31_32 pbn;
- struct fixed31_32 pbn_per_slot;
- struct dc_dp_mst_stream_allocation_table proposed_table = {0};
- uint8_t i;
- enum act_return_status ret;
- const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
- DC_LOGGER_INIT(link->ctx->logger);
-
- /* notify immediate branch device table update */
- if (dm_helpers_dp_mst_write_payload_allocation_table(
- stream->ctx,
- stream,
- &proposed_table,
- true)) {
- /* update mst stream allocation table software state */
- update_mst_stream_alloc_table(
- link,
- pipe_ctx->stream_res.stream_enc,
- pipe_ctx->stream_res.hpo_dp_stream_enc,
- &proposed_table);
- }
-
- DC_LOG_MST("%s "
- "stream_count: %d: \n ",
- __func__,
- link->mst_stream_alloc_table.stream_count);
-
- for (i = 0; i < MAX_CONTROLLER_NUM; i++) {
- DC_LOG_MST("stream_enc[%d]: %p "
- "stream[%d].hpo_dp_stream_enc: %p "
- "stream[%d].vcp_id: %d "
- "stream[%d].slot_count: %d\n",
- i,
- (void *) link->mst_stream_alloc_table.stream_allocations[i].stream_enc,
- i,
- (void *) link->mst_stream_alloc_table.stream_allocations[i].hpo_dp_stream_enc,
- i,
- link->mst_stream_alloc_table.stream_allocations[i].vcp_id,
- i,
- link->mst_stream_alloc_table.stream_allocations[i].slot_count);
- }
-
- ASSERT(proposed_table.stream_count > 0);
-
- /* update mst stream allocation table hardware state */
- if (link_hwss->ext.update_stream_allocation_table == NULL ||
- dp_get_link_encoding_format(&link->cur_link_settings) == DP_UNKNOWN_ENCODING) {
- DC_LOG_ERROR("Failure: unknown encoding format\n");
- return DC_ERROR_UNEXPECTED;
- }
-
- link_hwss->ext.update_stream_allocation_table(link, &pipe_ctx->link_res,
- &link->mst_stream_alloc_table);
-
- /* poll for immediate branch device ACT handled */
- ret = dm_helpers_dp_mst_poll_for_allocation_change_trigger(
- stream->ctx,
- stream);
-
- if (ret != ACT_LINK_LOST) {
- /* send ALLOCATE_PAYLOAD sideband message with updated pbn */
- dm_helpers_dp_mst_send_payload_allocation(
- stream->ctx,
- stream,
- true);
- }
-
- /* increase throttled vcp size */
- pbn = get_pbn_from_bw_in_kbps(bw_in_kbps);
- pbn_per_slot = get_pbn_per_slot(stream);
- avg_time_slots_per_mtp = dc_fixpt_div(pbn, pbn_per_slot);
-
- if (link_hwss->ext.set_throttled_vcp_size)
- link_hwss->ext.set_throttled_vcp_size(pipe_ctx, avg_time_slots_per_mtp);
- if (link_hwss->ext.set_hblank_min_symbol_width)
- link_hwss->ext.set_hblank_min_symbol_width(pipe_ctx,
- &link->cur_link_settings,
- avg_time_slots_per_mtp);
-
- return DC_OK;
-}
-
-static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx)
-{
- struct dc_stream_state *stream = pipe_ctx->stream;
- struct dc_link *link = stream->link;
- struct dc_dp_mst_stream_allocation_table proposed_table = {0};
- struct fixed31_32 avg_time_slots_per_mtp = dc_fixpt_from_int(0);
- int i;
- bool mst_mode = (link->type == dc_connection_mst_branch);
- /* adjust for drm changes*/
- bool update_drm_mst_state = true;
- const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
- const struct dc_link_settings empty_link_settings = {0};
- DC_LOGGER_INIT(link->ctx->logger);
-
-
- /* deallocate_mst_payload is called before disable link. When mode or
- * disable/enable monitor, new stream is created which is not in link
- * stream[] yet. For this, payload is not allocated yet, so de-alloc
- * should not done. For new mode set, map_resources will get engine
- * for new stream, so stream_enc->id should be validated until here.
- */
-
- /* slot X.Y */
- if (link_hwss->ext.set_throttled_vcp_size)
- link_hwss->ext.set_throttled_vcp_size(pipe_ctx, avg_time_slots_per_mtp);
- if (link_hwss->ext.set_hblank_min_symbol_width)
- link_hwss->ext.set_hblank_min_symbol_width(pipe_ctx,
- &empty_link_settings,
- avg_time_slots_per_mtp);
-
- if (mst_mode || update_drm_mst_state) {
- /* when link is in mst mode, reply on mst manager to remove
- * payload
- */
- if (dm_helpers_dp_mst_write_payload_allocation_table(
- stream->ctx,
- stream,
- &proposed_table,
- false))
-
- update_mst_stream_alloc_table(
- link,
- pipe_ctx->stream_res.stream_enc,
- pipe_ctx->stream_res.hpo_dp_stream_enc,
- &proposed_table);
- else
- DC_LOG_WARNING("Failed to update"
- "MST allocation table for"
- "pipe idx:%d\n",
- pipe_ctx->pipe_idx);
- } else {
- /* when link is no longer in mst mode (mst hub unplugged),
- * remove payload with default dc logic
- */
- remove_stream_from_alloc_table(link, pipe_ctx->stream_res.stream_enc,
- pipe_ctx->stream_res.hpo_dp_stream_enc);
- }
-
- DC_LOG_MST("%s"
- "stream_count: %d: ",
- __func__,
- link->mst_stream_alloc_table.stream_count);
-
- for (i = 0; i < MAX_CONTROLLER_NUM; i++) {
- DC_LOG_MST("stream_enc[%d]: %p "
- "stream[%d].hpo_dp_stream_enc: %p "
- "stream[%d].vcp_id: %d "
- "stream[%d].slot_count: %d\n",
- i,
- (void *) link->mst_stream_alloc_table.stream_allocations[i].stream_enc,
- i,
- (void *) link->mst_stream_alloc_table.stream_allocations[i].hpo_dp_stream_enc,
- i,
- link->mst_stream_alloc_table.stream_allocations[i].vcp_id,
- i,
- link->mst_stream_alloc_table.stream_allocations[i].slot_count);
- }
-
- /* update mst stream allocation table hardware state */
- if (link_hwss->ext.update_stream_allocation_table == NULL ||
- dp_get_link_encoding_format(&link->cur_link_settings) == DP_UNKNOWN_ENCODING) {
- DC_LOG_DEBUG("Unknown encoding format\n");
- return DC_ERROR_UNEXPECTED;
- }
-
- link_hwss->ext.update_stream_allocation_table(link, &pipe_ctx->link_res,
- &link->mst_stream_alloc_table);
-
- if (mst_mode) {
- dm_helpers_dp_mst_poll_for_allocation_change_trigger(
- stream->ctx,
- stream);
-
- if (!update_drm_mst_state)
- dm_helpers_dp_mst_send_payload_allocation(
- stream->ctx,
- stream,
- false);
- }
-
- if (update_drm_mst_state)
- dm_helpers_dp_mst_send_payload_allocation(
- stream->ctx,
- stream,
- false);
-
- return DC_OK;
-}
-
-
-#if defined(CONFIG_DRM_AMD_DC_HDCP)
-static void update_psp_stream_config(struct pipe_ctx *pipe_ctx, bool dpms_off)
-{
- struct cp_psp *cp_psp = &pipe_ctx->stream->ctx->cp_psp;
- struct link_encoder *link_enc = NULL;
- struct cp_psp_stream_config config = {0};
- enum dp_panel_mode panel_mode =
- dp_get_panel_mode(pipe_ctx->stream->link);
-
- if (cp_psp == NULL || cp_psp->funcs.update_stream_config == NULL)
- return;
-
- link_enc = link_enc_cfg_get_link_enc(pipe_ctx->stream->link);
- ASSERT(link_enc);
- if (link_enc == NULL)
- return;
-
- /* otg instance */
- config.otg_inst = (uint8_t) pipe_ctx->stream_res.tg->inst;
-
- /* dig front end */
- config.dig_fe = (uint8_t) pipe_ctx->stream_res.stream_enc->stream_enc_inst;
-
- /* stream encoder index */
- config.stream_enc_idx = pipe_ctx->stream_res.stream_enc->id - ENGINE_ID_DIGA;
- if (is_dp_128b_132b_signal(pipe_ctx))
- config.stream_enc_idx =
- pipe_ctx->stream_res.hpo_dp_stream_enc->id - ENGINE_ID_HPO_DP_0;
-
- /* dig back end */
- config.dig_be = pipe_ctx->stream->link->link_enc_hw_inst;
-
- /* link encoder index */
- config.link_enc_idx = link_enc->transmitter - TRANSMITTER_UNIPHY_A;
- if (is_dp_128b_132b_signal(pipe_ctx))
- config.link_enc_idx = pipe_ctx->link_res.hpo_dp_link_enc->inst;
-
- /* dio output index is dpia index for DPIA endpoint & dcio index by default */
- if (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA)
- config.dio_output_idx = pipe_ctx->stream->link->link_id.enum_id - ENUM_ID_1;
- else
- config.dio_output_idx = link_enc->transmitter - TRANSMITTER_UNIPHY_A;
-
-
- /* phy index */
- config.phy_idx = resource_transmitter_to_phy_idx(
- pipe_ctx->stream->link->dc, link_enc->transmitter);
- if (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA)
- /* USB4 DPIA doesn't use PHY in our soc, initialize it to 0 */
- config.phy_idx = 0;
-
- /* stream properties */
- config.assr_enabled = (panel_mode == DP_PANEL_MODE_EDP) ? 1 : 0;
- config.mst_enabled = (pipe_ctx->stream->signal ==
- SIGNAL_TYPE_DISPLAY_PORT_MST) ? 1 : 0;
- config.dp2_enabled = is_dp_128b_132b_signal(pipe_ctx) ? 1 : 0;
- config.usb4_enabled = (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) ?
- 1 : 0;
- config.dpms_off = dpms_off;
-
- /* dm stream context */
- config.dm_stream_ctx = pipe_ctx->stream->dm_stream_context;
-
- cp_psp->funcs.update_stream_config(cp_psp->handle, &config);
-}
-#endif
-
-static void fpga_dp_hpo_enable_link_and_stream(struct dc_state *state, struct pipe_ctx *pipe_ctx)
-{
- struct dc *dc = pipe_ctx->stream->ctx->dc;
- struct dc_stream_state *stream = pipe_ctx->stream;
- struct link_mst_stream_allocation_table proposed_table = {0};
- struct fixed31_32 avg_time_slots_per_mtp;
- uint8_t req_slot_count = 0;
- uint8_t vc_id = 1; /// VC ID always 1 for SST
- struct dc_link_settings link_settings = pipe_ctx->link_config.dp_link_settings;
- const struct link_hwss *link_hwss = get_link_hwss(stream->link, &pipe_ctx->link_res);
- DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
-
- stream->link->cur_link_settings = link_settings;
-
- if (link_hwss->ext.enable_dp_link_output)
- link_hwss->ext.enable_dp_link_output(stream->link, &pipe_ctx->link_res,
- stream->signal, pipe_ctx->clock_source->id,
- &link_settings);
-
-#ifdef DIAGS_BUILD
- /* Workaround for FPGA HPO capture DP link data:
- * HPO capture will set link to active mode
- * This workaround is required to get a capture from start of frame
- */
- if (!dc->debug.fpga_hpo_capture_en) {
- struct encoder_set_dp_phy_pattern_param params = {0};
- params.dp_phy_pattern = DP_TEST_PATTERN_VIDEO_MODE;
-
- /* Set link active */
- stream->link->hpo_dp_link_enc->funcs->set_link_test_pattern(
- stream->link->hpo_dp_link_enc,
- &params);
- }
-#endif
-
- /* Enable DP_STREAM_ENC */
- dc->hwss.enable_stream(pipe_ctx);
-
- /* Set DPS PPS SDP (AKA "info frames") */
- if (pipe_ctx->stream->timing.flags.DSC) {
- dp_set_dsc_pps_sdp(pipe_ctx, true, true);
- }
-
- /* Allocate Payload */
- if ((stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) && (state->stream_count > 1)) {
- // MST case
- uint8_t i;
-
- proposed_table.stream_count = state->stream_count;
- for (i = 0; i < state->stream_count; i++) {
- avg_time_slots_per_mtp = calculate_sst_avg_time_slots_per_mtp(state->streams[i], state->streams[i]->link);
- req_slot_count = dc_fixpt_ceil(avg_time_slots_per_mtp);
- proposed_table.stream_allocations[i].slot_count = req_slot_count;
- proposed_table.stream_allocations[i].vcp_id = i+1;
- /* NOTE: This makes assumption that pipe_ctx index is same as stream index */
- proposed_table.stream_allocations[i].hpo_dp_stream_enc = state->res_ctx.pipe_ctx[i].stream_res.hpo_dp_stream_enc;
- }
- } else {
- // SST case
- avg_time_slots_per_mtp = calculate_sst_avg_time_slots_per_mtp(stream, stream->link);
- req_slot_count = dc_fixpt_ceil(avg_time_slots_per_mtp);
- proposed_table.stream_count = 1; /// Always 1 stream for SST
- proposed_table.stream_allocations[0].slot_count = req_slot_count;
- proposed_table.stream_allocations[0].vcp_id = vc_id;
- proposed_table.stream_allocations[0].hpo_dp_stream_enc = pipe_ctx->stream_res.hpo_dp_stream_enc;
- }
-
- link_hwss->ext.update_stream_allocation_table(stream->link,
- &pipe_ctx->link_res,
- &proposed_table);
-
- if (link_hwss->ext.set_throttled_vcp_size)
- link_hwss->ext.set_throttled_vcp_size(pipe_ctx, avg_time_slots_per_mtp);
-
- dc->hwss.unblank_stream(pipe_ctx, &stream->link->cur_link_settings);
- dc->hwss.enable_audio_stream(pipe_ctx);
-}
-
-void core_link_enable_stream(
- struct dc_state *state,
- struct pipe_ctx *pipe_ctx)
-{
- struct dc *dc = pipe_ctx->stream->ctx->dc;
- struct dc_stream_state *stream = pipe_ctx->stream;
- struct dc_link *link = stream->sink->link;
- enum dc_status status;
- struct link_encoder *link_enc;
- enum otg_out_mux_dest otg_out_dest = OUT_MUX_DIO;
- struct vpg *vpg = pipe_ctx->stream_res.stream_enc->vpg;
- const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
-
- if (is_dp_128b_132b_signal(pipe_ctx))
- vpg = pipe_ctx->stream_res.hpo_dp_stream_enc->vpg;
-
- DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
-
- if (pipe_ctx->stream->sink) {
- if (pipe_ctx->stream->sink->sink_signal != SIGNAL_TYPE_VIRTUAL &&
- pipe_ctx->stream->sink->sink_signal != SIGNAL_TYPE_NONE) {
- DC_LOG_DC("%s pipe_ctx dispname=%s signal=%x\n", __func__,
- pipe_ctx->stream->sink->edid_caps.display_name,
- pipe_ctx->stream->signal);
- }
- }
-
- if (!IS_DIAG_DC(dc->ctx->dce_environment) &&
- dc_is_virtual_signal(pipe_ctx->stream->signal))
- return;
-
- link_enc = link_enc_cfg_get_link_enc(link);
- ASSERT(link_enc);
-
- if (!dc_is_virtual_signal(pipe_ctx->stream->signal)
- && !is_dp_128b_132b_signal(pipe_ctx)) {
- if (link_enc)
- link_enc->funcs->setup(
- link_enc,
- pipe_ctx->stream->signal);
- }
-
- pipe_ctx->stream->link->link_state_valid = true;
-
- if (pipe_ctx->stream_res.tg->funcs->set_out_mux) {
- if (is_dp_128b_132b_signal(pipe_ctx))
- otg_out_dest = OUT_MUX_HPO_DP;
- else
- otg_out_dest = OUT_MUX_DIO;
- pipe_ctx->stream_res.tg->funcs->set_out_mux(pipe_ctx->stream_res.tg, otg_out_dest);
- }
-
- link_hwss->setup_stream_attribute(pipe_ctx);
-
- if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
- bool apply_edp_fast_boot_optimization =
- pipe_ctx->stream->apply_edp_fast_boot_optimization;
-
- pipe_ctx->stream->apply_edp_fast_boot_optimization = false;
-
- // Enable VPG before building infoframe
- if (vpg && vpg->funcs->vpg_poweron)
- vpg->funcs->vpg_poweron(vpg);
-
- resource_build_info_frame(pipe_ctx);
- dc->hwss.update_info_frame(pipe_ctx);
-
- if (dc_is_dp_signal(pipe_ctx->stream->signal))
- dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_UPDATE_INFO_FRAME);
-
- /* Do not touch link on seamless boot optimization. */
- if (pipe_ctx->stream->apply_seamless_boot_optimization) {
- pipe_ctx->stream->dpms_off = false;
-
- /* Still enable stream features & audio on seamless boot for DP external displays */
- if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT) {
- enable_stream_features(pipe_ctx);
- dc->hwss.enable_audio_stream(pipe_ctx);
- }
-
-#if defined(CONFIG_DRM_AMD_DC_HDCP)
- update_psp_stream_config(pipe_ctx, false);
-#endif
- return;
- }
-
- /* eDP lit up by bios already, no need to enable again. */
- if (pipe_ctx->stream->signal == SIGNAL_TYPE_EDP &&
- apply_edp_fast_boot_optimization &&
- !pipe_ctx->stream->timing.flags.DSC &&
- !pipe_ctx->next_odm_pipe) {
- pipe_ctx->stream->dpms_off = false;
-#if defined(CONFIG_DRM_AMD_DC_HDCP)
- update_psp_stream_config(pipe_ctx, false);
-#endif
- return;
- }
-
- if (pipe_ctx->stream->dpms_off)
- return;
-
- /* Have to setup DSC before DIG FE and BE are connected (which happens before the
- * link training). This is to make sure the bandwidth sent to DIG BE won't be
- * bigger than what the link and/or DIG BE can handle. VBID[6]/CompressedStream_flag
- * will be automatically set at a later time when the video is enabled
- * (DP_VID_STREAM_EN = 1).
- */
- if (pipe_ctx->stream->timing.flags.DSC) {
- if (dc_is_dp_signal(pipe_ctx->stream->signal) ||
- dc_is_virtual_signal(pipe_ctx->stream->signal))
- dp_set_dsc_enable(pipe_ctx, true);
-
- }
-
- status = enable_link(state, pipe_ctx);
-
- if (status != DC_OK) {
- DC_LOG_WARNING("enabling link %u failed: %d\n",
- pipe_ctx->stream->link->link_index,
- status);
-
- /* Abort stream enable *unless* the failure was due to
- * DP link training - some DP monitors will recover and
- * show the stream anyway. But MST displays can't proceed
- * without link training.
- */
- if (status != DC_FAIL_DP_LINK_TRAINING ||
- pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
- if (false == stream->link->link_status.link_active)
- disable_link(stream->link, &pipe_ctx->link_res,
- pipe_ctx->stream->signal);
- BREAK_TO_DEBUGGER();
- return;
- }
- }
-
- /* turn off otg test pattern if enable */
- if (pipe_ctx->stream_res.tg->funcs->set_test_pattern)
- pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg,
- CONTROLLER_DP_TEST_PATTERN_VIDEOMODE,
- COLOR_DEPTH_UNDEFINED);
-
- /* This second call is needed to reconfigure the DIG
- * as a workaround for the incorrect value being applied
- * from transmitter control.
- */
- if (!(dc_is_virtual_signal(pipe_ctx->stream->signal) ||
- is_dp_128b_132b_signal(pipe_ctx)))
- if (link_enc)
- link_enc->funcs->setup(
- link_enc,
- pipe_ctx->stream->signal);
-
- dc->hwss.enable_stream(pipe_ctx);
-
- /* Set DPS PPS SDP (AKA "info frames") */
- if (pipe_ctx->stream->timing.flags.DSC) {
- if (dc_is_dp_signal(pipe_ctx->stream->signal) ||
- dc_is_virtual_signal(pipe_ctx->stream->signal)) {
- dp_set_dsc_on_rx(pipe_ctx, true);
- dp_set_dsc_pps_sdp(pipe_ctx, true, true);
- }
- }
-
- if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
- dc_link_allocate_mst_payload(pipe_ctx);
- else if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT &&
- is_dp_128b_132b_signal(pipe_ctx))
- dc_link_update_sst_payload(pipe_ctx, true);
-
- dc->hwss.unblank_stream(pipe_ctx,
- &pipe_ctx->stream->link->cur_link_settings);
-
- if (stream->sink_patches.delay_ignore_msa > 0)
- msleep(stream->sink_patches.delay_ignore_msa);
-
- if (dc_is_dp_signal(pipe_ctx->stream->signal))
- enable_stream_features(pipe_ctx);
-#if defined(CONFIG_DRM_AMD_DC_HDCP)
- update_psp_stream_config(pipe_ctx, false);
-#endif
-
- dc->hwss.enable_audio_stream(pipe_ctx);
-
- } else { // if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
- if (is_dp_128b_132b_signal(pipe_ctx))
- fpga_dp_hpo_enable_link_and_stream(state, pipe_ctx);
- if (dc_is_dp_signal(pipe_ctx->stream->signal) ||
- dc_is_virtual_signal(pipe_ctx->stream->signal))
- dp_set_dsc_enable(pipe_ctx, true);
- }
-
- if (dc_is_hdmi_signal(pipe_ctx->stream->signal)) {
- core_link_set_avmute(pipe_ctx, false);
- }
-}
-
-void core_link_disable_stream(struct pipe_ctx *pipe_ctx)
-{
- struct dc *dc = pipe_ctx->stream->ctx->dc;
- struct dc_stream_state *stream = pipe_ctx->stream;
- struct dc_link *link = stream->sink->link;
- struct vpg *vpg = pipe_ctx->stream_res.stream_enc->vpg;
-
- if (is_dp_128b_132b_signal(pipe_ctx))
- vpg = pipe_ctx->stream_res.hpo_dp_stream_enc->vpg;
-
- DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
-
- if (pipe_ctx->stream->sink) {
- if (pipe_ctx->stream->sink->sink_signal != SIGNAL_TYPE_VIRTUAL &&
- pipe_ctx->stream->sink->sink_signal != SIGNAL_TYPE_NONE) {
- DC_LOG_DC("%s pipe_ctx dispname=%s signal=%x\n", __func__,
- pipe_ctx->stream->sink->edid_caps.display_name,
- pipe_ctx->stream->signal);
- }
- }
-
- if (!IS_DIAG_DC(dc->ctx->dce_environment) &&
- dc_is_virtual_signal(pipe_ctx->stream->signal))
- return;
-
- if (!pipe_ctx->stream->sink->edid_caps.panel_patch.skip_avmute) {
- if (dc_is_hdmi_signal(pipe_ctx->stream->signal))
- core_link_set_avmute(pipe_ctx, true);
- }
-
- dc->hwss.disable_audio_stream(pipe_ctx);
-
-#if defined(CONFIG_DRM_AMD_DC_HDCP)
- update_psp_stream_config(pipe_ctx, true);
-#endif
- dc->hwss.blank_stream(pipe_ctx);
-
- if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
- deallocate_mst_payload(pipe_ctx);
- else if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT &&
- is_dp_128b_132b_signal(pipe_ctx))
- dc_link_update_sst_payload(pipe_ctx, false);
-
- if (dc_is_hdmi_signal(pipe_ctx->stream->signal)) {
- struct ext_hdmi_settings settings = {0};
- enum engine_id eng_id = pipe_ctx->stream_res.stream_enc->id;
-
- unsigned short masked_chip_caps = link->chip_caps &
- EXT_DISPLAY_PATH_CAPS__EXT_CHIP_MASK;
- //Need to inform that sink is going to use legacy HDMI mode.
- dal_ddc_service_write_scdc_data(
- link->ddc,
- 165000,//vbios only handles 165Mhz.
- false);
- if (masked_chip_caps == EXT_DISPLAY_PATH_CAPS__HDMI20_TISN65DP159RSBT) {
- /* DP159, Retimer settings */
- if (get_ext_hdmi_settings(pipe_ctx, eng_id, &settings))
- write_i2c_retimer_setting(pipe_ctx,
- false, false, &settings);
- else
- write_i2c_default_retimer_setting(pipe_ctx,
- false, false);
- } else if (masked_chip_caps == EXT_DISPLAY_PATH_CAPS__HDMI20_PI3EQX1204) {
- /* PI3EQX1204, Redriver settings */
- write_i2c_redriver_setting(pipe_ctx, false);
- }
- }
-
- if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT &&
- !is_dp_128b_132b_signal(pipe_ctx)) {
-
- /* In DP1.x SST mode, our encoder will go to TPS1
- * when link is on but stream is off.
- * Disabling link before stream will avoid exposing TPS1 pattern
- * during the disable sequence as it will confuse some receivers
- * state machine.
- * In DP2 or MST mode, our encoder will stay video active
- */
- disable_link(pipe_ctx->stream->link, &pipe_ctx->link_res, pipe_ctx->stream->signal);
- dc->hwss.disable_stream(pipe_ctx);
- } else {
- dc->hwss.disable_stream(pipe_ctx);
- disable_link(pipe_ctx->stream->link, &pipe_ctx->link_res, pipe_ctx->stream->signal);
- }
-
- if (pipe_ctx->stream->timing.flags.DSC) {
- if (dc_is_dp_signal(pipe_ctx->stream->signal))
- dp_set_dsc_enable(pipe_ctx, false);
- }
- if (is_dp_128b_132b_signal(pipe_ctx)) {
- if (pipe_ctx->stream_res.tg->funcs->set_out_mux)
- pipe_ctx->stream_res.tg->funcs->set_out_mux(pipe_ctx->stream_res.tg, OUT_MUX_DIO);
- }
-
- if (vpg && vpg->funcs->vpg_powerdown)
- vpg->funcs->vpg_powerdown(vpg);
-}
-
-void core_link_set_avmute(struct pipe_ctx *pipe_ctx, bool enable)
-{
- struct dc *dc = pipe_ctx->stream->ctx->dc;
-
- if (!dc_is_hdmi_signal(pipe_ctx->stream->signal))
- return;
-
- dc->hwss.set_avmute(pipe_ctx, enable);
-}
-
-/**
- * dc_link_enable_hpd_filter:
- * If enable is true, programs HPD filter on associated HPD line using
- * delay_on_disconnect/delay_on_connect values dependent on
- * link->connector_signal
- *
- * If enable is false, programs HPD filter on associated HPD line with no
- * delays on connect or disconnect
- *
- * @link: pointer to the dc link
- * @enable: boolean specifying whether to enable hbd
- */
-void dc_link_enable_hpd_filter(struct dc_link *link, bool enable)
-{
- struct gpio *hpd;
-
- if (enable) {
- link->is_hpd_filter_disabled = false;
- program_hpd_filter(link);
- } else {
- link->is_hpd_filter_disabled = true;
- /* Obtain HPD handle */
- hpd = get_hpd_gpio(link->ctx->dc_bios, link->link_id, link->ctx->gpio_service);
-
- if (!hpd)
- return;
-
- /* Setup HPD filtering */
- if (dal_gpio_open(hpd, GPIO_MODE_INTERRUPT) == GPIO_RESULT_OK) {
- struct gpio_hpd_config config;
-
- config.delay_on_connect = 0;
- config.delay_on_disconnect = 0;
-
- dal_irq_setup_hpd_filter(hpd, &config);
-
- dal_gpio_close(hpd);
- } else {
- ASSERT_CRITICAL(false);
- }
- /* Release HPD handle */
- dal_gpio_destroy_irq(&hpd);
- }
-}
-
-void dc_link_set_drive_settings(struct dc *dc,
- struct link_training_settings *lt_settings,
- const struct dc_link *link)
-{
-
- int i;
- struct link_resource link_res;
-
- for (i = 0; i < dc->link_count; i++)
- if (dc->links[i] == link)
- break;
-
- if (i >= dc->link_count)
- ASSERT_CRITICAL(false);
-
- dc_link_get_cur_link_res(link, &link_res);
- dc_link_dp_set_drive_settings(dc->links[i], &link_res, lt_settings);
-}
-
-void dc_link_set_preferred_link_settings(struct dc *dc,
- struct dc_link_settings *link_setting,
- struct dc_link *link)
-{
- int i;
- struct pipe_ctx *pipe;
- struct dc_stream_state *link_stream;
- struct dc_link_settings store_settings = *link_setting;
-
- link->preferred_link_setting = store_settings;
-
- /* Retrain with preferred link settings only relevant for
- * DP signal type
- * Check for non-DP signal or if passive dongle present
- */
- if (!dc_is_dp_signal(link->connector_signal) ||
- link->dongle_max_pix_clk > 0)
- return;
-
- for (i = 0; i < MAX_PIPES; i++) {
- pipe = &dc->current_state->res_ctx.pipe_ctx[i];
- if (pipe->stream && pipe->stream->link) {
- if (pipe->stream->link == link) {
- link_stream = pipe->stream;
- break;
- }
- }
- }
-
- /* Stream not found */
- if (i == MAX_PIPES)
- return;
-
- /* Cannot retrain link if backend is off */
- if (link_stream->dpms_off)
- return;
-
- if (decide_link_settings(link_stream, &store_settings))
- dp_retrain_link_dp_test(link, &store_settings, false);
-}
-
-void dc_link_set_preferred_training_settings(struct dc *dc,
- struct dc_link_settings *link_setting,
- struct dc_link_training_overrides *lt_overrides,
- struct dc_link *link,
- bool skip_immediate_retrain)
-{
- if (lt_overrides != NULL)
- link->preferred_training_settings = *lt_overrides;
- else
- memset(&link->preferred_training_settings, 0, sizeof(link->preferred_training_settings));
-
- if (link_setting != NULL) {
- link->preferred_link_setting = *link_setting;
- if (dp_get_link_encoding_format(link_setting) == DP_128b_132b_ENCODING)
- /* TODO: add dc update for acquiring link res */
- skip_immediate_retrain = true;
- } else {
- link->preferred_link_setting.lane_count = LANE_COUNT_UNKNOWN;
- link->preferred_link_setting.link_rate = LINK_RATE_UNKNOWN;
- }
-
- if (link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT &&
- link->type == dc_connection_mst_branch)
- dm_helpers_dp_mst_update_branch_bandwidth(dc->ctx, link);
-
- /* Retrain now, or wait until next stream update to apply */
- if (skip_immediate_retrain == false)
- dc_link_set_preferred_link_settings(dc, &link->preferred_link_setting, link);
-}
-
-void dc_link_enable_hpd(const struct dc_link *link)
-{
- dc_link_dp_enable_hpd(link);
-}
-
-void dc_link_disable_hpd(const struct dc_link *link)
-{
- dc_link_dp_disable_hpd(link);
-}
-
-void dc_link_set_test_pattern(struct dc_link *link,
- enum dp_test_pattern test_pattern,
- enum dp_test_pattern_color_space test_pattern_color_space,
- const struct link_training_settings *p_link_settings,
- const unsigned char *p_custom_pattern,
- unsigned int cust_pattern_size)
-{
- if (link != NULL)
- dc_link_dp_set_test_pattern(
- link,
- test_pattern,
- test_pattern_color_space,
- p_link_settings,
- p_custom_pattern,
- cust_pattern_size);
-}
-
-uint32_t dc_link_bandwidth_kbps(
- const struct dc_link *link,
- const struct dc_link_settings *link_setting)
-{
- uint32_t total_data_bw_efficiency_x10000 = 0;
- uint32_t link_rate_per_lane_kbps = 0;
-
- switch (dp_get_link_encoding_format(link_setting)) {
- case DP_8b_10b_ENCODING:
- /* For 8b/10b encoding:
- * link rate is defined in the unit of LINK_RATE_REF_FREQ_IN_KHZ per DP byte per lane.
- * data bandwidth efficiency is 80% with additional 3% overhead if FEC is supported.
- */
- link_rate_per_lane_kbps = link_setting->link_rate * LINK_RATE_REF_FREQ_IN_KHZ * BITS_PER_DP_BYTE;
- total_data_bw_efficiency_x10000 = DATA_EFFICIENCY_8b_10b_x10000;
- if (dc_link_should_enable_fec(link)) {
- total_data_bw_efficiency_x10000 /= 100;
- total_data_bw_efficiency_x10000 *= DATA_EFFICIENCY_8b_10b_FEC_EFFICIENCY_x100;
- }
- break;
- case DP_128b_132b_ENCODING:
- /* For 128b/132b encoding:
- * link rate is defined in the unit of 10mbps per lane.
- * total data bandwidth efficiency is always 96.71%.
- */
- link_rate_per_lane_kbps = link_setting->link_rate * 10000;
- total_data_bw_efficiency_x10000 = DATA_EFFICIENCY_128b_132b_x10000;
- break;
- default:
- break;
- }
-
- /* overall effective link bandwidth = link rate per lane * lane count * total data bandwidth efficiency */
- return link_rate_per_lane_kbps * link_setting->lane_count / 10000 * total_data_bw_efficiency_x10000;
-}
-
-const struct dc_link_settings *dc_link_get_link_cap(
- const struct dc_link *link)
-{
- if (link->preferred_link_setting.lane_count != LANE_COUNT_UNKNOWN &&
- link->preferred_link_setting.link_rate != LINK_RATE_UNKNOWN)
- return &link->preferred_link_setting;
- return &link->verified_link_cap;
-}
-
-void dc_link_overwrite_extended_receiver_cap(
- struct dc_link *link)
-{
- dp_overwrite_extended_receiver_cap(link);
-}
-
-bool dc_link_is_fec_supported(const struct dc_link *link)
-{
- /* TODO - use asic cap instead of link_enc->features
- * we no longer know which link enc to use for this link before commit
- */
- struct link_encoder *link_enc = NULL;
-
- link_enc = link_enc_cfg_get_link_enc(link);
- ASSERT(link_enc);
-
- return (dc_is_dp_signal(link->connector_signal) && link_enc &&
- link_enc->features.fec_supported &&
- link->dpcd_caps.fec_cap.bits.FEC_CAPABLE &&
- !IS_FPGA_MAXIMUS_DC(link->ctx->dce_environment));
-}
-
-bool dc_link_should_enable_fec(const struct dc_link *link)
-{
- bool force_disable = false;
-
- if (link->fec_state == dc_link_fec_enabled)
- force_disable = false;
- else if (link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT_MST &&
- link->local_sink &&
- link->local_sink->edid_caps.panel_patch.disable_fec)
- force_disable = true;
- else if (link->connector_signal == SIGNAL_TYPE_EDP
- && (link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.
- dsc_support.DSC_SUPPORT == false
- || link->panel_config.dsc.disable_dsc_edp
- || !link->dc->caps.edp_dsc_support))
- force_disable = true;
-
- return !force_disable && dc_link_is_fec_supported(link);
-}
-
-uint32_t dc_bandwidth_in_kbps_from_timing(
- const struct dc_crtc_timing *timing)
-{
- uint32_t bits_per_channel = 0;
- uint32_t kbps;
-
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- if (timing->flags.DSC)
- return dc_dsc_stream_bandwidth_in_kbps(timing,
- timing->dsc_cfg.bits_per_pixel,
- timing->dsc_cfg.num_slices_h,
- timing->dsc_cfg.is_dp);
-#endif /* CONFIG_DRM_AMD_DC_DCN */
-
- switch (timing->display_color_depth) {
- case COLOR_DEPTH_666:
- bits_per_channel = 6;
- break;
- case COLOR_DEPTH_888:
- bits_per_channel = 8;
- break;
- case COLOR_DEPTH_101010:
- bits_per_channel = 10;
- break;
- case COLOR_DEPTH_121212:
- bits_per_channel = 12;
- break;
- case COLOR_DEPTH_141414:
- bits_per_channel = 14;
- break;
- case COLOR_DEPTH_161616:
- bits_per_channel = 16;
- break;
- default:
- ASSERT(bits_per_channel != 0);
- bits_per_channel = 8;
- break;
- }
-
- kbps = timing->pix_clk_100hz / 10;
- kbps *= bits_per_channel;
-
- if (timing->flags.Y_ONLY != 1) {
- /*Only YOnly make reduce bandwidth by 1/3 compares to RGB*/
- kbps *= 3;
- if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420)
- kbps /= 2;
- else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR422)
- kbps = kbps * 2 / 3;
- }
-
- return kbps;
-
-}
-
-void dc_link_get_cur_link_res(const struct dc_link *link,
- struct link_resource *link_res)
-{
- int i;
- struct pipe_ctx *pipe = NULL;
-
- memset(link_res, 0, sizeof(*link_res));
-
- for (i = 0; i < MAX_PIPES; i++) {
- pipe = &link->dc->current_state->res_ctx.pipe_ctx[i];
- if (pipe->stream && pipe->stream->link && pipe->top_pipe == NULL) {
- if (pipe->stream->link == link) {
- *link_res = pipe->link_res;
- break;
- }
- }
- }
-
-}
-
-/**
- * dc_get_cur_link_res_map() - take a snapshot of current link resource allocation state
- * @dc: pointer to dc of the dm calling this
- * @map: a dc link resource snapshot defined internally to dc.
- *
- * DM needs to capture a snapshot of current link resource allocation mapping
- * and store it in its persistent storage.
- *
- * Some of the link resource is using first come first serve policy.
- * The allocation mapping depends on original hotplug order. This information
- * is lost after driver is loaded next time. The snapshot is used in order to
- * restore link resource to its previous state so user will get consistent
- * link capability allocation across reboot.
- *
- * Return: none (void function)
- *
- */
-void dc_get_cur_link_res_map(const struct dc *dc, uint32_t *map)
-{
- struct dc_link *link;
- uint32_t i;
- uint32_t hpo_dp_recycle_map = 0;
-
- *map = 0;
-
- if (dc->caps.dp_hpo) {
- for (i = 0; i < dc->caps.max_links; i++) {
- link = dc->links[i];
- if (link->link_status.link_active &&
- dp_get_link_encoding_format(&link->reported_link_cap) == DP_128b_132b_ENCODING &&
- dp_get_link_encoding_format(&link->cur_link_settings) != DP_128b_132b_ENCODING)
- /* hpo dp link encoder is considered as recycled, when RX reports 128b/132b encoding capability
- * but current link doesn't use it.
- */
- hpo_dp_recycle_map |= (1 << i);
- }
- *map |= (hpo_dp_recycle_map << LINK_RES_HPO_DP_REC_MAP__SHIFT);
- }
-}
-
-/**
- * dc_restore_link_res_map() - restore link resource allocation state from a snapshot
- * @dc: pointer to dc of the dm calling this
- * @map: a dc link resource snapshot defined internally to dc.
- *
- * DM needs to call this function after initial link detection on boot and
- * before first commit streams to restore link resource allocation state
- * from previous boot session.
- *
- * Some of the link resource is using first come first serve policy.
- * The allocation mapping depends on original hotplug order. This information
- * is lost after driver is loaded next time. The snapshot is used in order to
- * restore link resource to its previous state so user will get consistent
- * link capability allocation across reboot.
- *
- * Return: none (void function)
- *
- */
-void dc_restore_link_res_map(const struct dc *dc, uint32_t *map)
-{
- struct dc_link *link;
- uint32_t i;
- unsigned int available_hpo_dp_count;
- uint32_t hpo_dp_recycle_map = (*map & LINK_RES_HPO_DP_REC_MAP__MASK)
- >> LINK_RES_HPO_DP_REC_MAP__SHIFT;
-
- if (dc->caps.dp_hpo) {
- available_hpo_dp_count = dc->res_pool->hpo_dp_link_enc_count;
- /* remove excess 128b/132b encoding support for not recycled links */
- for (i = 0; i < dc->caps.max_links; i++) {
- if ((hpo_dp_recycle_map & (1 << i)) == 0) {
- link = dc->links[i];
- if (link->type != dc_connection_none &&
- dp_get_link_encoding_format(&link->verified_link_cap) == DP_128b_132b_ENCODING) {
- if (available_hpo_dp_count > 0)
- available_hpo_dp_count--;
- else
- /* remove 128b/132b encoding capability by limiting verified link rate to HBR3 */
- link->verified_link_cap.link_rate = LINK_RATE_HIGH3;
- }
- }
- }
- /* remove excess 128b/132b encoding support for recycled links */
- for (i = 0; i < dc->caps.max_links; i++) {
- if ((hpo_dp_recycle_map & (1 << i)) != 0) {
- link = dc->links[i];
- if (link->type != dc_connection_none &&
- dp_get_link_encoding_format(&link->verified_link_cap) == DP_128b_132b_ENCODING) {
- if (available_hpo_dp_count > 0)
- available_hpo_dp_count--;
- else
- /* remove 128b/132b encoding capability by limiting verified link rate to HBR3 */
- link->verified_link_cap.link_rate = LINK_RATE_HIGH3;
- }
- }
- }
- }
-}
+// TODO - remove this file after external build dependencies is resolved.
+/* NOTE: This file is pending to be removed, do not add new code to this file */ \ No newline at end of file
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
deleted file mode 100644
index dedd1246ce58..000000000000
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
+++ /dev/null
@@ -1,7553 +0,0 @@
-/*
- * Copyright 2015 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
- *
- * Authors: AMD
- */
-#include "dm_services.h"
-#include "dc.h"
-#include "dc_link_dp.h"
-#include "dm_helpers.h"
-#include "opp.h"
-#include "dsc.h"
-#include "clk_mgr.h"
-#include "resource.h"
-
-#include "inc/core_types.h"
-#include "link_hwss.h"
-#include "dc_link_ddc.h"
-#include "core_status.h"
-#include "dpcd_defs.h"
-#include "dc_dmub_srv.h"
-#include "dce/dmub_hw_lock_mgr.h"
-#include "inc/dc_link_dpia.h"
-#include "inc/link_enc_cfg.h"
-#include "link/link_dp_trace.h"
-
-/*Travis*/
-static const uint8_t DP_VGA_LVDS_CONVERTER_ID_2[] = "sivarT";
-/*Nutmeg*/
-static const uint8_t DP_VGA_LVDS_CONVERTER_ID_3[] = "dnomlA";
-
-#define DC_LOGGER \
- link->ctx->logger
-#define DC_TRACE_LEVEL_MESSAGE(...) /* do nothing */
-
-#include "link_dpcd.h"
-
-#ifndef MAX
-#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
-#endif
-#ifndef MIN
-#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
-#endif
-
- /* maximum pre emphasis level allowed for each voltage swing level*/
- static const enum dc_pre_emphasis
- voltage_swing_to_pre_emphasis[] = { PRE_EMPHASIS_LEVEL3,
- PRE_EMPHASIS_LEVEL2,
- PRE_EMPHASIS_LEVEL1,
- PRE_EMPHASIS_DISABLED };
-
-enum {
- POST_LT_ADJ_REQ_LIMIT = 6,
- POST_LT_ADJ_REQ_TIMEOUT = 200
-};
-
-struct dp_lt_fallback_entry {
- enum dc_lane_count lane_count;
- enum dc_link_rate link_rate;
-};
-
-static const struct dp_lt_fallback_entry dp_lt_fallbacks[] = {
- /* This link training fallback array is ordered by
- * link bandwidth from highest to lowest.
- * DP specs makes it a normative policy to always
- * choose the next highest link bandwidth during
- * link training fallback.
- */
- {LANE_COUNT_FOUR, LINK_RATE_UHBR20},
- {LANE_COUNT_FOUR, LINK_RATE_UHBR13_5},
- {LANE_COUNT_TWO, LINK_RATE_UHBR20},
- {LANE_COUNT_FOUR, LINK_RATE_UHBR10},
- {LANE_COUNT_TWO, LINK_RATE_UHBR13_5},
- {LANE_COUNT_FOUR, LINK_RATE_HIGH3},
- {LANE_COUNT_ONE, LINK_RATE_UHBR20},
- {LANE_COUNT_TWO, LINK_RATE_UHBR10},
- {LANE_COUNT_FOUR, LINK_RATE_HIGH2},
- {LANE_COUNT_ONE, LINK_RATE_UHBR13_5},
- {LANE_COUNT_TWO, LINK_RATE_HIGH3},
- {LANE_COUNT_ONE, LINK_RATE_UHBR10},
- {LANE_COUNT_TWO, LINK_RATE_HIGH2},
- {LANE_COUNT_FOUR, LINK_RATE_HIGH},
- {LANE_COUNT_ONE, LINK_RATE_HIGH3},
- {LANE_COUNT_FOUR, LINK_RATE_LOW},
- {LANE_COUNT_ONE, LINK_RATE_HIGH2},
- {LANE_COUNT_TWO, LINK_RATE_HIGH},
- {LANE_COUNT_TWO, LINK_RATE_LOW},
- {LANE_COUNT_ONE, LINK_RATE_HIGH},
- {LANE_COUNT_ONE, LINK_RATE_LOW},
-};
-
-static const struct dc_link_settings fail_safe_link_settings = {
- .lane_count = LANE_COUNT_ONE,
- .link_rate = LINK_RATE_LOW,
- .link_spread = LINK_SPREAD_DISABLED,
-};
-
-static bool decide_fallback_link_setting(
- struct dc_link *link,
- struct dc_link_settings *max,
- struct dc_link_settings *cur,
- enum link_training_result training_result);
-static void maximize_lane_settings(const struct link_training_settings *lt_settings,
- struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]);
-static void override_lane_settings(const struct link_training_settings *lt_settings,
- struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]);
-
-static uint32_t get_cr_training_aux_rd_interval(struct dc_link *link,
- const struct dc_link_settings *link_settings)
-{
- union training_aux_rd_interval training_rd_interval;
- uint32_t wait_in_micro_secs = 100;
-
- memset(&training_rd_interval, 0, sizeof(training_rd_interval));
- if (dp_get_link_encoding_format(link_settings) == DP_8b_10b_ENCODING &&
- link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_12) {
- core_link_read_dpcd(
- link,
- DP_TRAINING_AUX_RD_INTERVAL,
- (uint8_t *)&training_rd_interval,
- sizeof(training_rd_interval));
- if (training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL)
- wait_in_micro_secs = training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL * 4000;
- }
-
- return wait_in_micro_secs;
-}
-
-static uint32_t get_eq_training_aux_rd_interval(
- struct dc_link *link,
- const struct dc_link_settings *link_settings)
-{
- union training_aux_rd_interval training_rd_interval;
-
- memset(&training_rd_interval, 0, sizeof(training_rd_interval));
- if (dp_get_link_encoding_format(link_settings) == DP_128b_132b_ENCODING) {
- core_link_read_dpcd(
- link,
- DP_128b_132b_TRAINING_AUX_RD_INTERVAL,
- (uint8_t *)&training_rd_interval,
- sizeof(training_rd_interval));
- } else if (dp_get_link_encoding_format(link_settings) == DP_8b_10b_ENCODING &&
- link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_12) {
- core_link_read_dpcd(
- link,
- DP_TRAINING_AUX_RD_INTERVAL,
- (uint8_t *)&training_rd_interval,
- sizeof(training_rd_interval));
- }
-
- switch (training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL) {
- case 0: return 400;
- case 1: return 4000;
- case 2: return 8000;
- case 3: return 12000;
- case 4: return 16000;
- case 5: return 32000;
- case 6: return 64000;
- default: return 400;
- }
-}
-
-void dp_wait_for_training_aux_rd_interval(
- struct dc_link *link,
- uint32_t wait_in_micro_secs)
-{
- if (wait_in_micro_secs > 1000)
- msleep(wait_in_micro_secs/1000);
- else
- udelay(wait_in_micro_secs);
-
- DC_LOG_HW_LINK_TRAINING("%s:\n wait = %d\n",
- __func__,
- wait_in_micro_secs);
-}
-
-enum dpcd_training_patterns
- dc_dp_training_pattern_to_dpcd_training_pattern(
- struct dc_link *link,
- enum dc_dp_training_pattern pattern)
-{
- enum dpcd_training_patterns dpcd_tr_pattern =
- DPCD_TRAINING_PATTERN_VIDEOIDLE;
-
- switch (pattern) {
- case DP_TRAINING_PATTERN_SEQUENCE_1:
- dpcd_tr_pattern = DPCD_TRAINING_PATTERN_1;
- break;
- case DP_TRAINING_PATTERN_SEQUENCE_2:
- dpcd_tr_pattern = DPCD_TRAINING_PATTERN_2;
- break;
- case DP_TRAINING_PATTERN_SEQUENCE_3:
- dpcd_tr_pattern = DPCD_TRAINING_PATTERN_3;
- break;
- case DP_TRAINING_PATTERN_SEQUENCE_4:
- dpcd_tr_pattern = DPCD_TRAINING_PATTERN_4;
- break;
- case DP_128b_132b_TPS1:
- dpcd_tr_pattern = DPCD_128b_132b_TPS1;
- break;
- case DP_128b_132b_TPS2:
- dpcd_tr_pattern = DPCD_128b_132b_TPS2;
- break;
- case DP_128b_132b_TPS2_CDS:
- dpcd_tr_pattern = DPCD_128b_132b_TPS2_CDS;
- break;
- case DP_TRAINING_PATTERN_VIDEOIDLE:
- dpcd_tr_pattern = DPCD_TRAINING_PATTERN_VIDEOIDLE;
- break;
- default:
- ASSERT(0);
- DC_LOG_HW_LINK_TRAINING("%s: Invalid HW Training pattern: %d\n",
- __func__, pattern);
- break;
- }
-
- return dpcd_tr_pattern;
-}
-
-static void dpcd_set_training_pattern(
- struct dc_link *link,
- enum dc_dp_training_pattern training_pattern)
-{
- union dpcd_training_pattern dpcd_pattern = {0};
-
- dpcd_pattern.v1_4.TRAINING_PATTERN_SET =
- dc_dp_training_pattern_to_dpcd_training_pattern(
- link, training_pattern);
-
- core_link_write_dpcd(
- link,
- DP_TRAINING_PATTERN_SET,
- &dpcd_pattern.raw,
- 1);
-
- DC_LOG_HW_LINK_TRAINING("%s\n %x pattern = %x\n",
- __func__,
- DP_TRAINING_PATTERN_SET,
- dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
-}
-
-static enum dc_dp_training_pattern decide_cr_training_pattern(
- const struct dc_link_settings *link_settings)
-{
- switch (dp_get_link_encoding_format(link_settings)) {
- case DP_8b_10b_ENCODING:
- default:
- return DP_TRAINING_PATTERN_SEQUENCE_1;
- case DP_128b_132b_ENCODING:
- return DP_128b_132b_TPS1;
- }
-}
-
-static enum dc_dp_training_pattern decide_eq_training_pattern(struct dc_link *link,
- const struct dc_link_settings *link_settings)
-{
- struct link_encoder *link_enc;
- struct encoder_feature_support *enc_caps;
- struct dpcd_caps *rx_caps = &link->dpcd_caps;
- enum dc_dp_training_pattern pattern = DP_TRAINING_PATTERN_SEQUENCE_2;
-
- link_enc = link_enc_cfg_get_link_enc(link);
- ASSERT(link_enc);
- enc_caps = &link_enc->features;
-
- switch (dp_get_link_encoding_format(link_settings)) {
- case DP_8b_10b_ENCODING:
- if (enc_caps->flags.bits.IS_TPS4_CAPABLE &&
- rx_caps->max_down_spread.bits.TPS4_SUPPORTED)
- pattern = DP_TRAINING_PATTERN_SEQUENCE_4;
- else if (enc_caps->flags.bits.IS_TPS3_CAPABLE &&
- rx_caps->max_ln_count.bits.TPS3_SUPPORTED)
- pattern = DP_TRAINING_PATTERN_SEQUENCE_3;
- else
- pattern = DP_TRAINING_PATTERN_SEQUENCE_2;
- break;
- case DP_128b_132b_ENCODING:
- pattern = DP_128b_132b_TPS2;
- break;
- default:
- pattern = DP_TRAINING_PATTERN_SEQUENCE_2;
- break;
- }
- return pattern;
-}
-
-static uint8_t get_dpcd_link_rate(const struct dc_link_settings *link_settings)
-{
- uint8_t link_rate = 0;
- enum dp_link_encoding encoding = dp_get_link_encoding_format(link_settings);
-
- if (encoding == DP_128b_132b_ENCODING)
- switch (link_settings->link_rate) {
- case LINK_RATE_UHBR10:
- link_rate = 0x1;
- break;
- case LINK_RATE_UHBR20:
- link_rate = 0x2;
- break;
- case LINK_RATE_UHBR13_5:
- link_rate = 0x4;
- break;
- default:
- link_rate = 0;
- break;
- }
- else if (encoding == DP_8b_10b_ENCODING)
- link_rate = (uint8_t) link_settings->link_rate;
- else
- link_rate = 0;
-
- return link_rate;
-}
-
-static void dp_fixed_vs_pe_read_lane_adjust(
- struct dc_link *link,
- union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX])
-{
- const uint8_t vendor_lttpr_write_data_vs[3] = {0x0, 0x53, 0x63};
- const uint8_t vendor_lttpr_write_data_pe[3] = {0x0, 0x54, 0x63};
- const uint8_t offset = dp_convert_to_count(
- link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
- uint32_t vendor_lttpr_write_address = 0xF004F;
- uint32_t vendor_lttpr_read_address = 0xF0053;
- uint8_t dprx_vs = 0;
- uint8_t dprx_pe = 0;
- uint8_t lane;
-
- if (offset != 0xFF) {
- vendor_lttpr_write_address +=
- ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
- vendor_lttpr_read_address +=
- ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
- }
-
- /* W/A to read lane settings requested by DPRX */
- core_link_write_dpcd(
- link,
- vendor_lttpr_write_address,
- &vendor_lttpr_write_data_vs[0],
- sizeof(vendor_lttpr_write_data_vs));
- core_link_read_dpcd(
- link,
- vendor_lttpr_read_address,
- &dprx_vs,
- 1);
- core_link_write_dpcd(
- link,
- vendor_lttpr_write_address,
- &vendor_lttpr_write_data_pe[0],
- sizeof(vendor_lttpr_write_data_pe));
- core_link_read_dpcd(
- link,
- vendor_lttpr_read_address,
- &dprx_pe,
- 1);
-
- for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
- dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_SET = (dprx_vs >> (2 * lane)) & 0x3;
- dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_SET = (dprx_pe >> (2 * lane)) & 0x3;
- }
-}
-
-static void dp_fixed_vs_pe_set_retimer_lane_settings(
- struct dc_link *link,
- const union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX],
- uint8_t lane_count)
-{
- const uint8_t offset = dp_convert_to_count(
- link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
- const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF};
- uint32_t vendor_lttpr_write_address = 0xF004F;
- uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0};
- uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0};
- uint8_t lane = 0;
-
- if (offset != 0xFF) {
- vendor_lttpr_write_address +=
- ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
- }
-
- for (lane = 0; lane < lane_count; lane++) {
- vendor_lttpr_write_data_vs[3] |=
- dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
- vendor_lttpr_write_data_pe[3] |=
- dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
- }
-
- /* Force LTTPR to output desired VS and PE */
- core_link_write_dpcd(
- link,
- vendor_lttpr_write_address,
- &vendor_lttpr_write_data_reset[0],
- sizeof(vendor_lttpr_write_data_reset));
- core_link_write_dpcd(
- link,
- vendor_lttpr_write_address,
- &vendor_lttpr_write_data_vs[0],
- sizeof(vendor_lttpr_write_data_vs));
- core_link_write_dpcd(
- link,
- vendor_lttpr_write_address,
- &vendor_lttpr_write_data_pe[0],
- sizeof(vendor_lttpr_write_data_pe));
-}
-
-enum dc_status dpcd_set_link_settings(
- struct dc_link *link,
- const struct link_training_settings *lt_settings)
-{
- uint8_t rate;
- enum dc_status status;
-
- union down_spread_ctrl downspread = {0};
- union lane_count_set lane_count_set = {0};
-
- downspread.raw = (uint8_t)
- (lt_settings->link_settings.link_spread);
-
- lane_count_set.bits.LANE_COUNT_SET =
- lt_settings->link_settings.lane_count;
-
- lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
- lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
-
-
- if (link->ep_type == DISPLAY_ENDPOINT_PHY &&
- lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) {
- lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED =
- link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED;
- }
-
- status = core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL,
- &downspread.raw, sizeof(downspread));
-
- status = core_link_write_dpcd(link, DP_LANE_COUNT_SET,
- &lane_count_set.raw, 1);
-
- if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_13 &&
- lt_settings->link_settings.use_link_rate_set == true) {
- rate = 0;
- /* WA for some MUX chips that will power down with eDP and lose supported
- * link rate set for eDP 1.4. Source reads DPCD 0x010 again to ensure
- * MUX chip gets link rate set back before link training.
- */
- if (link->connector_signal == SIGNAL_TYPE_EDP) {
- uint8_t supported_link_rates[16];
-
- core_link_read_dpcd(link, DP_SUPPORTED_LINK_RATES,
- supported_link_rates, sizeof(supported_link_rates));
- }
- status = core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1);
- status = core_link_write_dpcd(link, DP_LINK_RATE_SET,
- &lt_settings->link_settings.link_rate_set, 1);
- } else {
- rate = get_dpcd_link_rate(&lt_settings->link_settings);
-
- status = core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1);
- }
-
- if (rate) {
- DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
- __func__,
- DP_LINK_BW_SET,
- lt_settings->link_settings.link_rate,
- DP_LANE_COUNT_SET,
- lt_settings->link_settings.lane_count,
- lt_settings->enhanced_framing,
- DP_DOWNSPREAD_CTRL,
- lt_settings->link_settings.link_spread);
- } else {
- DC_LOG_HW_LINK_TRAINING("%s\n %x rate set = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
- __func__,
- DP_LINK_RATE_SET,
- lt_settings->link_settings.link_rate_set,
- DP_LANE_COUNT_SET,
- lt_settings->link_settings.lane_count,
- lt_settings->enhanced_framing,
- DP_DOWNSPREAD_CTRL,
- lt_settings->link_settings.link_spread);
- }
-
- return status;
-}
-
-uint8_t dc_dp_initialize_scrambling_data_symbols(
- struct dc_link *link,
- enum dc_dp_training_pattern pattern)
-{
- uint8_t disable_scrabled_data_symbols = 0;
-
- switch (pattern) {
- case DP_TRAINING_PATTERN_SEQUENCE_1:
- case DP_TRAINING_PATTERN_SEQUENCE_2:
- case DP_TRAINING_PATTERN_SEQUENCE_3:
- disable_scrabled_data_symbols = 1;
- break;
- case DP_TRAINING_PATTERN_SEQUENCE_4:
- case DP_128b_132b_TPS1:
- case DP_128b_132b_TPS2:
- disable_scrabled_data_symbols = 0;
- break;
- default:
- ASSERT(0);
- DC_LOG_HW_LINK_TRAINING("%s: Invalid HW Training pattern: %d\n",
- __func__, pattern);
- break;
- }
- return disable_scrabled_data_symbols;
-}
-
-static inline bool is_repeater(const struct link_training_settings *lt_settings, uint32_t offset)
-{
- return (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) && (offset != 0);
-}
-
-static void dpcd_set_lt_pattern_and_lane_settings(
- struct dc_link *link,
- const struct link_training_settings *lt_settings,
- enum dc_dp_training_pattern pattern,
- uint32_t offset)
-{
- uint32_t dpcd_base_lt_offset;
-
- uint8_t dpcd_lt_buffer[5] = {0};
- union dpcd_training_pattern dpcd_pattern = {0};
- uint32_t size_in_bytes;
- bool edp_workaround = false; /* TODO link_prop.INTERNAL */
- dpcd_base_lt_offset = DP_TRAINING_PATTERN_SET;
-
- if (is_repeater(lt_settings, offset))
- dpcd_base_lt_offset = DP_TRAINING_PATTERN_SET_PHY_REPEATER1 +
- ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
-
- /*****************************************************************
- * DpcdAddress_TrainingPatternSet
- *****************************************************************/
- dpcd_pattern.v1_4.TRAINING_PATTERN_SET =
- dc_dp_training_pattern_to_dpcd_training_pattern(link, pattern);
-
- dpcd_pattern.v1_4.SCRAMBLING_DISABLE =
- dc_dp_initialize_scrambling_data_symbols(link, pattern);
-
- dpcd_lt_buffer[DP_TRAINING_PATTERN_SET - DP_TRAINING_PATTERN_SET]
- = dpcd_pattern.raw;
-
- if (is_repeater(lt_settings, offset)) {
- DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Repeater ID: %d\n 0x%X pattern = %x\n",
- __func__,
- offset,
- dpcd_base_lt_offset,
- dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
- } else {
- DC_LOG_HW_LINK_TRAINING("%s\n 0x%X pattern = %x\n",
- __func__,
- dpcd_base_lt_offset,
- dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
- }
-
- /* concatenate everything into one buffer*/
- size_in_bytes = lt_settings->link_settings.lane_count *
- sizeof(lt_settings->dpcd_lane_settings[0]);
-
- // 0x00103 - 0x00102
- memmove(
- &dpcd_lt_buffer[DP_TRAINING_LANE0_SET - DP_TRAINING_PATTERN_SET],
- lt_settings->dpcd_lane_settings,
- size_in_bytes);
-
- if (is_repeater(lt_settings, offset)) {
- if (dp_get_link_encoding_format(&lt_settings->link_settings) ==
- DP_128b_132b_ENCODING)
- DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"
- " 0x%X TX_FFE_PRESET_VALUE = %x\n",
- __func__,
- offset,
- dpcd_base_lt_offset,
- lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE);
- else if (dp_get_link_encoding_format(&lt_settings->link_settings) ==
- DP_8b_10b_ENCODING)
- DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"
- " 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n",
- __func__,
- offset,
- dpcd_base_lt_offset,
- lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET,
- lt_settings->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET,
- lt_settings->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,
- lt_settings->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED);
- } else {
- if (dp_get_link_encoding_format(&lt_settings->link_settings) ==
- DP_128b_132b_ENCODING)
- DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X TX_FFE_PRESET_VALUE = %x\n",
- __func__,
- dpcd_base_lt_offset,
- lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE);
- else if (dp_get_link_encoding_format(&lt_settings->link_settings) ==
- DP_8b_10b_ENCODING)
- DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n",
- __func__,
- dpcd_base_lt_offset,
- lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET,
- lt_settings->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET,
- lt_settings->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,
- lt_settings->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED);
- }
- if (edp_workaround) {
- /* for eDP write in 2 parts because the 5-byte burst is
- * causing issues on some eDP panels (EPR#366724)
- */
- core_link_write_dpcd(
- link,
- DP_TRAINING_PATTERN_SET,
- &dpcd_pattern.raw,
- sizeof(dpcd_pattern.raw));
-
- core_link_write_dpcd(
- link,
- DP_TRAINING_LANE0_SET,
- (uint8_t *)(lt_settings->dpcd_lane_settings),
- size_in_bytes);
-
- } else if (dp_get_link_encoding_format(&lt_settings->link_settings) ==
- DP_128b_132b_ENCODING) {
- core_link_write_dpcd(
- link,
- dpcd_base_lt_offset,
- dpcd_lt_buffer,
- sizeof(dpcd_lt_buffer));
- } else
- /* write it all in (1 + number-of-lanes)-byte burst*/
- core_link_write_dpcd(
- link,
- dpcd_base_lt_offset,
- dpcd_lt_buffer,
- size_in_bytes + sizeof(dpcd_pattern.raw));
-}
-
-bool dp_is_cr_done(enum dc_lane_count ln_count,
- union lane_status *dpcd_lane_status)
-{
- uint32_t lane;
- /*LANEx_CR_DONE bits All 1's?*/
- for (lane = 0; lane < (uint32_t)(ln_count); lane++) {
- if (!dpcd_lane_status[lane].bits.CR_DONE_0)
- return false;
- }
- return true;
-}
-
-bool dp_is_ch_eq_done(enum dc_lane_count ln_count,
- union lane_status *dpcd_lane_status)
-{
- bool done = true;
- uint32_t lane;
- for (lane = 0; lane < (uint32_t)(ln_count); lane++)
- if (!dpcd_lane_status[lane].bits.CHANNEL_EQ_DONE_0)
- done = false;
- return done;
-}
-
-bool dp_is_symbol_locked(enum dc_lane_count ln_count,
- union lane_status *dpcd_lane_status)
-{
- bool locked = true;
- uint32_t lane;
- for (lane = 0; lane < (uint32_t)(ln_count); lane++)
- if (!dpcd_lane_status[lane].bits.SYMBOL_LOCKED_0)
- locked = false;
- return locked;
-}
-
-bool dp_is_interlane_aligned(union lane_align_status_updated align_status)
-{
- return align_status.bits.INTERLANE_ALIGN_DONE == 1;
-}
-
-void dp_hw_to_dpcd_lane_settings(
- const struct link_training_settings *lt_settings,
- const struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX],
- union dpcd_training_lane dpcd_lane_settings[])
-{
- uint8_t lane = 0;
-
- for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
- if (dp_get_link_encoding_format(&lt_settings->link_settings) ==
- DP_8b_10b_ENCODING) {
- dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET =
- (uint8_t)(hw_lane_settings[lane].VOLTAGE_SWING);
- dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET =
- (uint8_t)(hw_lane_settings[lane].PRE_EMPHASIS);
- dpcd_lane_settings[lane].bits.MAX_SWING_REACHED =
- (hw_lane_settings[lane].VOLTAGE_SWING ==
- VOLTAGE_SWING_MAX_LEVEL ? 1 : 0);
- dpcd_lane_settings[lane].bits.MAX_PRE_EMPHASIS_REACHED =
- (hw_lane_settings[lane].PRE_EMPHASIS ==
- PRE_EMPHASIS_MAX_LEVEL ? 1 : 0);
- }
- else if (dp_get_link_encoding_format(&lt_settings->link_settings) ==
- DP_128b_132b_ENCODING) {
- dpcd_lane_settings[lane].tx_ffe.PRESET_VALUE =
- hw_lane_settings[lane].FFE_PRESET.settings.level;
- }
- }
-}
-
-void dp_decide_lane_settings(
- const struct link_training_settings *lt_settings,
- const union lane_adjust ln_adjust[LANE_COUNT_DP_MAX],
- struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX],
- union dpcd_training_lane dpcd_lane_settings[])
-{
- uint32_t lane;
-
- for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
- if (dp_get_link_encoding_format(&lt_settings->link_settings) ==
- DP_8b_10b_ENCODING) {
- hw_lane_settings[lane].VOLTAGE_SWING =
- (enum dc_voltage_swing)(ln_adjust[lane].bits.
- VOLTAGE_SWING_LANE);
- hw_lane_settings[lane].PRE_EMPHASIS =
- (enum dc_pre_emphasis)(ln_adjust[lane].bits.
- PRE_EMPHASIS_LANE);
- }
- else if (dp_get_link_encoding_format(&lt_settings->link_settings) ==
- DP_128b_132b_ENCODING) {
- hw_lane_settings[lane].FFE_PRESET.raw =
- ln_adjust[lane].tx_ffe.PRESET_VALUE;
- }
- }
- dp_hw_to_dpcd_lane_settings(lt_settings, hw_lane_settings, dpcd_lane_settings);
-
- if (lt_settings->disallow_per_lane_settings) {
- /* we find the maximum of the requested settings across all lanes*/
- /* and set this maximum for all lanes*/
- maximize_lane_settings(lt_settings, hw_lane_settings);
- override_lane_settings(lt_settings, hw_lane_settings);
-
- if (lt_settings->always_match_dpcd_with_hw_lane_settings)
- dp_hw_to_dpcd_lane_settings(lt_settings, hw_lane_settings, dpcd_lane_settings);
- }
-
-}
-
-static uint8_t get_nibble_at_index(const uint8_t *buf,
- uint32_t index)
-{
- uint8_t nibble;
- nibble = buf[index / 2];
-
- if (index % 2)
- nibble >>= 4;
- else
- nibble &= 0x0F;
-
- return nibble;
-}
-
-static enum dc_pre_emphasis get_max_pre_emphasis_for_voltage_swing(
- enum dc_voltage_swing voltage)
-{
- enum dc_pre_emphasis pre_emphasis;
- pre_emphasis = PRE_EMPHASIS_MAX_LEVEL;
-
- if (voltage <= VOLTAGE_SWING_MAX_LEVEL)
- pre_emphasis = voltage_swing_to_pre_emphasis[voltage];
-
- return pre_emphasis;
-
-}
-
-static void maximize_lane_settings(const struct link_training_settings *lt_settings,
- struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX])
-{
- uint32_t lane;
- struct dc_lane_settings max_requested;
-
- max_requested.VOLTAGE_SWING = lane_settings[0].VOLTAGE_SWING;
- max_requested.PRE_EMPHASIS = lane_settings[0].PRE_EMPHASIS;
- max_requested.FFE_PRESET = lane_settings[0].FFE_PRESET;
-
- /* Determine what the maximum of the requested settings are*/
- for (lane = 1; lane < lt_settings->link_settings.lane_count; lane++) {
- if (lane_settings[lane].VOLTAGE_SWING > max_requested.VOLTAGE_SWING)
- max_requested.VOLTAGE_SWING = lane_settings[lane].VOLTAGE_SWING;
-
- if (lane_settings[lane].PRE_EMPHASIS > max_requested.PRE_EMPHASIS)
- max_requested.PRE_EMPHASIS = lane_settings[lane].PRE_EMPHASIS;
- if (lane_settings[lane].FFE_PRESET.settings.level >
- max_requested.FFE_PRESET.settings.level)
- max_requested.FFE_PRESET.settings.level =
- lane_settings[lane].FFE_PRESET.settings.level;
- }
-
- /* make sure the requested settings are
- * not higher than maximum settings*/
- if (max_requested.VOLTAGE_SWING > VOLTAGE_SWING_MAX_LEVEL)
- max_requested.VOLTAGE_SWING = VOLTAGE_SWING_MAX_LEVEL;
-
- if (max_requested.PRE_EMPHASIS > PRE_EMPHASIS_MAX_LEVEL)
- max_requested.PRE_EMPHASIS = PRE_EMPHASIS_MAX_LEVEL;
- if (max_requested.FFE_PRESET.settings.level > DP_FFE_PRESET_MAX_LEVEL)
- max_requested.FFE_PRESET.settings.level = DP_FFE_PRESET_MAX_LEVEL;
-
- /* make sure the pre-emphasis matches the voltage swing*/
- if (max_requested.PRE_EMPHASIS >
- get_max_pre_emphasis_for_voltage_swing(
- max_requested.VOLTAGE_SWING))
- max_requested.PRE_EMPHASIS =
- get_max_pre_emphasis_for_voltage_swing(
- max_requested.VOLTAGE_SWING);
-
- for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
- lane_settings[lane].VOLTAGE_SWING = max_requested.VOLTAGE_SWING;
- lane_settings[lane].PRE_EMPHASIS = max_requested.PRE_EMPHASIS;
- lane_settings[lane].FFE_PRESET = max_requested.FFE_PRESET;
- }
-}
-
-static void override_lane_settings(const struct link_training_settings *lt_settings,
- struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX])
-{
- uint32_t lane;
-
- if (lt_settings->voltage_swing == NULL &&
- lt_settings->pre_emphasis == NULL &&
- lt_settings->ffe_preset == NULL &&
- lt_settings->post_cursor2 == NULL)
-
- return;
-
- for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
- if (lt_settings->voltage_swing)
- lane_settings[lane].VOLTAGE_SWING = *lt_settings->voltage_swing;
- if (lt_settings->pre_emphasis)
- lane_settings[lane].PRE_EMPHASIS = *lt_settings->pre_emphasis;
- if (lt_settings->post_cursor2)
- lane_settings[lane].POST_CURSOR2 = *lt_settings->post_cursor2;
- if (lt_settings->ffe_preset)
- lane_settings[lane].FFE_PRESET = *lt_settings->ffe_preset;
- }
-}
-
-enum dc_status dp_get_lane_status_and_lane_adjust(
- struct dc_link *link,
- const struct link_training_settings *link_training_setting,
- union lane_status ln_status[LANE_COUNT_DP_MAX],
- union lane_align_status_updated *ln_align,
- union lane_adjust ln_adjust[LANE_COUNT_DP_MAX],
- uint32_t offset)
-{
- unsigned int lane01_status_address = DP_LANE0_1_STATUS;
- uint8_t lane_adjust_offset = 4;
- unsigned int lane01_adjust_address;
- uint8_t dpcd_buf[6] = {0};
- uint32_t lane;
- enum dc_status status;
-
- if (is_repeater(link_training_setting, offset)) {
- lane01_status_address =
- DP_LANE0_1_STATUS_PHY_REPEATER1 +
- ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
- lane_adjust_offset = 3;
- }
-
- status = core_link_read_dpcd(
- link,
- lane01_status_address,
- (uint8_t *)(dpcd_buf),
- sizeof(dpcd_buf));
-
- if (status != DC_OK) {
- DC_LOG_HW_LINK_TRAINING("%s:\n Failed to read from address 0x%X,"
- " keep current lane status and lane adjust unchanged",
- __func__,
- lane01_status_address);
- return status;
- }
-
- for (lane = 0; lane <
- (uint32_t)(link_training_setting->link_settings.lane_count);
- lane++) {
-
- ln_status[lane].raw =
- get_nibble_at_index(&dpcd_buf[0], lane);
- ln_adjust[lane].raw =
- get_nibble_at_index(&dpcd_buf[lane_adjust_offset], lane);
- }
-
- ln_align->raw = dpcd_buf[2];
-
- if (is_repeater(link_training_setting, offset)) {
- DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"
- " 0x%X Lane01Status = %x\n 0x%X Lane23Status = %x\n ",
- __func__,
- offset,
- lane01_status_address, dpcd_buf[0],
- lane01_status_address + 1, dpcd_buf[1]);
-
- lane01_adjust_address = DP_ADJUST_REQUEST_LANE0_1_PHY_REPEATER1 +
- ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
-
- DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"
- " 0x%X Lane01AdjustRequest = %x\n 0x%X Lane23AdjustRequest = %x\n",
- __func__,
- offset,
- lane01_adjust_address,
- dpcd_buf[lane_adjust_offset],
- lane01_adjust_address + 1,
- dpcd_buf[lane_adjust_offset + 1]);
- } else {
- DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X Lane01Status = %x\n 0x%X Lane23Status = %x\n ",
- __func__,
- lane01_status_address, dpcd_buf[0],
- lane01_status_address + 1, dpcd_buf[1]);
-
- lane01_adjust_address = DP_ADJUST_REQUEST_LANE0_1;
-
- DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X Lane01AdjustRequest = %x\n 0x%X Lane23AdjustRequest = %x\n",
- __func__,
- lane01_adjust_address,
- dpcd_buf[lane_adjust_offset],
- lane01_adjust_address + 1,
- dpcd_buf[lane_adjust_offset + 1]);
- }
-
- return status;
-}
-
-static enum dc_status dpcd_128b_132b_set_lane_settings(
- struct dc_link *link,
- const struct link_training_settings *link_training_setting)
-{
- enum dc_status status = core_link_write_dpcd(link,
- DP_TRAINING_LANE0_SET,
- (uint8_t *)(link_training_setting->dpcd_lane_settings),
- sizeof(link_training_setting->dpcd_lane_settings));
-
- DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X TX_FFE_PRESET_VALUE = %x\n",
- __func__,
- DP_TRAINING_LANE0_SET,
- link_training_setting->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE);
- return status;
-}
-
-
-enum dc_status dpcd_set_lane_settings(
- struct dc_link *link,
- const struct link_training_settings *link_training_setting,
- uint32_t offset)
-{
- unsigned int lane0_set_address;
- enum dc_status status;
-
- lane0_set_address = DP_TRAINING_LANE0_SET;
-
- if (is_repeater(link_training_setting, offset))
- lane0_set_address = DP_TRAINING_LANE0_SET_PHY_REPEATER1 +
- ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
-
- status = core_link_write_dpcd(link,
- lane0_set_address,
- (uint8_t *)(link_training_setting->dpcd_lane_settings),
- link_training_setting->link_settings.lane_count);
-
- if (is_repeater(link_training_setting, offset)) {
- DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Repeater ID: %d\n"
- " 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n",
- __func__,
- offset,
- lane0_set_address,
- link_training_setting->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET,
- link_training_setting->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET,
- link_training_setting->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,
- link_training_setting->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED);
-
- } else {
- DC_LOG_HW_LINK_TRAINING("%s\n 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n",
- __func__,
- lane0_set_address,
- link_training_setting->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET,
- link_training_setting->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET,
- link_training_setting->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,
- link_training_setting->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED);
- }
-
- return status;
-}
-
-bool dp_is_max_vs_reached(
- const struct link_training_settings *lt_settings)
-{
- uint32_t lane;
- for (lane = 0; lane <
- (uint32_t)(lt_settings->link_settings.lane_count);
- lane++) {
- if (lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET
- == VOLTAGE_SWING_MAX_LEVEL)
- return true;
- }
- return false;
-
-}
-
-static bool perform_post_lt_adj_req_sequence(
- struct dc_link *link,
- const struct link_resource *link_res,
- struct link_training_settings *lt_settings)
-{
- enum dc_lane_count lane_count =
- lt_settings->link_settings.lane_count;
-
- uint32_t adj_req_count;
- uint32_t adj_req_timer;
- bool req_drv_setting_changed;
- uint32_t lane;
- union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
- union lane_align_status_updated dpcd_lane_status_updated = {0};
- union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
-
- req_drv_setting_changed = false;
- for (adj_req_count = 0; adj_req_count < POST_LT_ADJ_REQ_LIMIT;
- adj_req_count++) {
-
- req_drv_setting_changed = false;
-
- for (adj_req_timer = 0;
- adj_req_timer < POST_LT_ADJ_REQ_TIMEOUT;
- adj_req_timer++) {
-
- dp_get_lane_status_and_lane_adjust(
- link,
- lt_settings,
- dpcd_lane_status,
- &dpcd_lane_status_updated,
- dpcd_lane_adjust,
- DPRX);
-
- if (dpcd_lane_status_updated.bits.
- POST_LT_ADJ_REQ_IN_PROGRESS == 0)
- return true;
-
- if (!dp_is_cr_done(lane_count, dpcd_lane_status))
- return false;
-
- if (!dp_is_ch_eq_done(lane_count, dpcd_lane_status) ||
- !dp_is_symbol_locked(lane_count, dpcd_lane_status) ||
- !dp_is_interlane_aligned(dpcd_lane_status_updated))
- return false;
-
- for (lane = 0; lane < (uint32_t)(lane_count); lane++) {
-
- if (lt_settings->
- dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET !=
- dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_LANE ||
- lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET !=
- dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_LANE) {
-
- req_drv_setting_changed = true;
- break;
- }
- }
-
- if (req_drv_setting_changed) {
- dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
- lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
-
- dc_link_dp_set_drive_settings(link,
- link_res,
- lt_settings);
- break;
- }
-
- msleep(1);
- }
-
- if (!req_drv_setting_changed) {
- DC_LOG_WARNING("%s: Post Link Training Adjust Request Timed out\n",
- __func__);
-
- ASSERT(0);
- return true;
- }
- }
- DC_LOG_WARNING("%s: Post Link Training Adjust Request limit reached\n",
- __func__);
-
- ASSERT(0);
- return true;
-
-}
-
-/* Only used for channel equalization */
-uint32_t dp_translate_training_aux_read_interval(uint32_t dpcd_aux_read_interval)
-{
- unsigned int aux_rd_interval_us = 400;
-
- switch (dpcd_aux_read_interval) {
- case 0x01:
- aux_rd_interval_us = 4000;
- break;
- case 0x02:
- aux_rd_interval_us = 8000;
- break;
- case 0x03:
- aux_rd_interval_us = 12000;
- break;
- case 0x04:
- aux_rd_interval_us = 16000;
- break;
- case 0x05:
- aux_rd_interval_us = 32000;
- break;
- case 0x06:
- aux_rd_interval_us = 64000;
- break;
- default:
- break;
- }
-
- return aux_rd_interval_us;
-}
-
-enum link_training_result dp_get_cr_failure(enum dc_lane_count ln_count,
- union lane_status *dpcd_lane_status)
-{
- enum link_training_result result = LINK_TRAINING_SUCCESS;
-
- if (ln_count >= LANE_COUNT_ONE && !dpcd_lane_status[0].bits.CR_DONE_0)
- result = LINK_TRAINING_CR_FAIL_LANE0;
- else if (ln_count >= LANE_COUNT_TWO && !dpcd_lane_status[1].bits.CR_DONE_0)
- result = LINK_TRAINING_CR_FAIL_LANE1;
- else if (ln_count >= LANE_COUNT_FOUR && !dpcd_lane_status[2].bits.CR_DONE_0)
- result = LINK_TRAINING_CR_FAIL_LANE23;
- else if (ln_count >= LANE_COUNT_FOUR && !dpcd_lane_status[3].bits.CR_DONE_0)
- result = LINK_TRAINING_CR_FAIL_LANE23;
- return result;
-}
-
-static enum link_training_result perform_channel_equalization_sequence(
- struct dc_link *link,
- const struct link_resource *link_res,
- struct link_training_settings *lt_settings,
- uint32_t offset)
-{
- enum dc_dp_training_pattern tr_pattern;
- uint32_t retries_ch_eq;
- uint32_t wait_time_microsec;
- enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
- union lane_align_status_updated dpcd_lane_status_updated = {0};
- union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
- union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
-
- /* Note: also check that TPS4 is a supported feature*/
- tr_pattern = lt_settings->pattern_for_eq;
-
- if (is_repeater(lt_settings, offset) && dp_get_link_encoding_format(&lt_settings->link_settings) == DP_8b_10b_ENCODING)
- tr_pattern = DP_TRAINING_PATTERN_SEQUENCE_4;
-
- dp_set_hw_training_pattern(link, link_res, tr_pattern, offset);
-
- for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT;
- retries_ch_eq++) {
-
- dp_set_hw_lane_settings(link, link_res, lt_settings, offset);
-
- /* 2. update DPCD*/
- if (!retries_ch_eq)
- /* EPR #361076 - write as a 5-byte burst,
- * but only for the 1-st iteration
- */
-
- dpcd_set_lt_pattern_and_lane_settings(
- link,
- lt_settings,
- tr_pattern, offset);
- else
- dpcd_set_lane_settings(link, lt_settings, offset);
-
- /* 3. wait for receiver to lock-on*/
- wait_time_microsec = lt_settings->eq_pattern_time;
-
- if (is_repeater(lt_settings, offset))
- wait_time_microsec =
- dp_translate_training_aux_read_interval(
- link->dpcd_caps.lttpr_caps.aux_rd_interval[offset - 1]);
-
- dp_wait_for_training_aux_rd_interval(
- link,
- wait_time_microsec);
-
- /* 4. Read lane status and requested
- * drive settings as set by the sink*/
-
- dp_get_lane_status_and_lane_adjust(
- link,
- lt_settings,
- dpcd_lane_status,
- &dpcd_lane_status_updated,
- dpcd_lane_adjust,
- offset);
-
- /* 5. check CR done*/
- if (!dp_is_cr_done(lane_count, dpcd_lane_status))
- return dpcd_lane_status[0].bits.CR_DONE_0 ?
- LINK_TRAINING_EQ_FAIL_CR_PARTIAL :
- LINK_TRAINING_EQ_FAIL_CR;
-
- /* 6. check CHEQ done*/
- if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) &&
- dp_is_symbol_locked(lane_count, dpcd_lane_status) &&
- dp_is_interlane_aligned(dpcd_lane_status_updated))
- return LINK_TRAINING_SUCCESS;
-
- /* 7. update VS/PE/PC2 in lt_settings*/
- dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
- lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
- }
-
- return LINK_TRAINING_EQ_FAIL_EQ;
-
-}
-
-static void start_clock_recovery_pattern_early(struct dc_link *link,
- const struct link_resource *link_res,
- struct link_training_settings *lt_settings,
- uint32_t offset)
-{
- DC_LOG_HW_LINK_TRAINING("%s\n GPU sends TPS1. Wait 400us.\n",
- __func__);
- dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_cr, offset);
- dp_set_hw_lane_settings(link, link_res, lt_settings, offset);
- udelay(400);
-}
-
-static enum link_training_result perform_clock_recovery_sequence(
- struct dc_link *link,
- const struct link_resource *link_res,
- struct link_training_settings *lt_settings,
- uint32_t offset)
-{
- uint32_t retries_cr;
- uint32_t retry_count;
- uint32_t wait_time_microsec;
- enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
- union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX];
- union lane_align_status_updated dpcd_lane_status_updated;
- union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
-
- retries_cr = 0;
- retry_count = 0;
-
- memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status));
- memset(&dpcd_lane_status_updated, '\0',
- sizeof(dpcd_lane_status_updated));
-
- if (!link->ctx->dc->work_arounds.lt_early_cr_pattern)
- dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_cr, offset);
-
- /* najeeb - The synaptics MST hub can put the LT in
- * infinite loop by switching the VS
- */
- /* between level 0 and level 1 continuously, here
- * we try for CR lock for LinkTrainingMaxCRRetry count*/
- while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
- (retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
-
-
- /* 1. call HWSS to set lane settings*/
- dp_set_hw_lane_settings(
- link,
- link_res,
- lt_settings,
- offset);
-
- /* 2. update DPCD of the receiver*/
- if (!retry_count)
- /* EPR #361076 - write as a 5-byte burst,
- * but only for the 1-st iteration.*/
- dpcd_set_lt_pattern_and_lane_settings(
- link,
- lt_settings,
- lt_settings->pattern_for_cr,
- offset);
- else
- dpcd_set_lane_settings(
- link,
- lt_settings,
- offset);
-
- /* 3. wait receiver to lock-on*/
- wait_time_microsec = lt_settings->cr_pattern_time;
-
- dp_wait_for_training_aux_rd_interval(
- link,
- wait_time_microsec);
-
- /* 4. Read lane status and requested drive
- * settings as set by the sink
- */
- dp_get_lane_status_and_lane_adjust(
- link,
- lt_settings,
- dpcd_lane_status,
- &dpcd_lane_status_updated,
- dpcd_lane_adjust,
- offset);
-
- /* 5. check CR done*/
- if (dp_is_cr_done(lane_count, dpcd_lane_status))
- return LINK_TRAINING_SUCCESS;
-
- /* 6. max VS reached*/
- if ((dp_get_link_encoding_format(&lt_settings->link_settings) ==
- DP_8b_10b_ENCODING) &&
- dp_is_max_vs_reached(lt_settings))
- break;
-
- /* 7. same lane settings*/
- /* Note: settings are the same for all lanes,
- * so comparing first lane is sufficient*/
- if ((dp_get_link_encoding_format(&lt_settings->link_settings) == DP_8b_10b_ENCODING) &&
- lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET ==
- dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE)
- retries_cr++;
- else if ((dp_get_link_encoding_format(&lt_settings->link_settings) == DP_128b_132b_ENCODING) &&
- lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE ==
- dpcd_lane_adjust[0].tx_ffe.PRESET_VALUE)
- retries_cr++;
- else
- retries_cr = 0;
-
- /* 8. update VS/PE/PC2 in lt_settings*/
- dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
- lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
- retry_count++;
- }
-
- if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) {
- ASSERT(0);
- DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue",
- __func__,
- LINK_TRAINING_MAX_CR_RETRY);
-
- }
-
- return dp_get_cr_failure(lane_count, dpcd_lane_status);
-}
-
-static inline enum link_training_result dp_transition_to_video_idle(
- struct dc_link *link,
- const struct link_resource *link_res,
- struct link_training_settings *lt_settings,
- enum link_training_result status)
-{
- union lane_count_set lane_count_set = {0};
-
- /* 4. mainlink output idle pattern*/
- dp_set_hw_test_pattern(link, link_res, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0);
-
- /*
- * 5. post training adjust if required
- * If the upstream DPTX and downstream DPRX both support TPS4,
- * TPS4 must be used instead of POST_LT_ADJ_REQ.
- */
- if (link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED != 1 ||
- lt_settings->pattern_for_eq >= DP_TRAINING_PATTERN_SEQUENCE_4) {
- /* delay 5ms after Main Link output idle pattern and then check
- * DPCD 0202h.
- */
- if (link->connector_signal != SIGNAL_TYPE_EDP && status == LINK_TRAINING_SUCCESS) {
- msleep(5);
- status = dp_check_link_loss_status(link, lt_settings);
- }
- return status;
- }
-
- if (status == LINK_TRAINING_SUCCESS &&
- perform_post_lt_adj_req_sequence(link, link_res, lt_settings) == false)
- status = LINK_TRAINING_LQA_FAIL;
-
- lane_count_set.bits.LANE_COUNT_SET = lt_settings->link_settings.lane_count;
- lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
- lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
-
- core_link_write_dpcd(
- link,
- DP_LANE_COUNT_SET,
- &lane_count_set.raw,
- sizeof(lane_count_set));
-
- return status;
-}
-
-enum link_training_result dp_check_link_loss_status(
- struct dc_link *link,
- const struct link_training_settings *link_training_setting)
-{
- enum link_training_result status = LINK_TRAINING_SUCCESS;
- union lane_status lane_status;
- uint8_t dpcd_buf[6] = {0};
- uint32_t lane;
-
- core_link_read_dpcd(
- link,
- DP_SINK_COUNT,
- (uint8_t *)(dpcd_buf),
- sizeof(dpcd_buf));
-
- /*parse lane status*/
- for (lane = 0; lane < link->cur_link_settings.lane_count; lane++) {
- /*
- * check lanes status
- */
- lane_status.raw = get_nibble_at_index(&dpcd_buf[2], lane);
-
- if (!lane_status.bits.CHANNEL_EQ_DONE_0 ||
- !lane_status.bits.CR_DONE_0 ||
- !lane_status.bits.SYMBOL_LOCKED_0) {
- /* if one of the channel equalization, clock
- * recovery or symbol lock is dropped
- * consider it as (link has been
- * dropped) dp sink status has changed
- */
- status = LINK_TRAINING_LINK_LOSS;
- break;
- }
- }
-
- return status;
-}
-
-static inline void decide_8b_10b_training_settings(
- struct dc_link *link,
- const struct dc_link_settings *link_setting,
- struct link_training_settings *lt_settings)
-{
- memset(lt_settings, '\0', sizeof(struct link_training_settings));
-
- /* Initialize link settings */
- lt_settings->link_settings.use_link_rate_set = link_setting->use_link_rate_set;
- lt_settings->link_settings.link_rate_set = link_setting->link_rate_set;
- lt_settings->link_settings.link_rate = link_setting->link_rate;
- lt_settings->link_settings.lane_count = link_setting->lane_count;
- /* TODO hard coded to SS for now
- * lt_settings.link_settings.link_spread =
- * dal_display_path_is_ss_supported(
- * path_mode->display_path) ?
- * LINK_SPREAD_05_DOWNSPREAD_30KHZ :
- * LINK_SPREAD_DISABLED;
- */
- lt_settings->link_settings.link_spread = link->dp_ss_off ?
- LINK_SPREAD_DISABLED : LINK_SPREAD_05_DOWNSPREAD_30KHZ;
- lt_settings->cr_pattern_time = get_cr_training_aux_rd_interval(link, link_setting);
- lt_settings->eq_pattern_time = get_eq_training_aux_rd_interval(link, link_setting);
- lt_settings->pattern_for_cr = decide_cr_training_pattern(link_setting);
- lt_settings->pattern_for_eq = decide_eq_training_pattern(link, link_setting);
- lt_settings->enhanced_framing = 1;
- lt_settings->should_set_fec_ready = true;
- lt_settings->disallow_per_lane_settings = true;
- lt_settings->always_match_dpcd_with_hw_lane_settings = true;
- lt_settings->lttpr_mode = dp_decide_8b_10b_lttpr_mode(link);
- dp_hw_to_dpcd_lane_settings(lt_settings, lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
-}
-
-static inline void decide_128b_132b_training_settings(struct dc_link *link,
- const struct dc_link_settings *link_settings,
- struct link_training_settings *lt_settings)
-{
- memset(lt_settings, 0, sizeof(*lt_settings));
-
- lt_settings->link_settings = *link_settings;
- /* TODO: should decide link spread when populating link_settings */
- lt_settings->link_settings.link_spread = link->dp_ss_off ? LINK_SPREAD_DISABLED :
- LINK_SPREAD_05_DOWNSPREAD_30KHZ;
-
- lt_settings->pattern_for_cr = decide_cr_training_pattern(link_settings);
- lt_settings->pattern_for_eq = decide_eq_training_pattern(link, link_settings);
- lt_settings->eq_pattern_time = 2500;
- lt_settings->eq_wait_time_limit = 400000;
- lt_settings->eq_loop_count_limit = 20;
- lt_settings->pattern_for_cds = DP_128b_132b_TPS2_CDS;
- lt_settings->cds_pattern_time = 2500;
- lt_settings->cds_wait_time_limit = (dp_convert_to_count(
- link->dpcd_caps.lttpr_caps.phy_repeater_cnt) + 1) * 20000;
- lt_settings->disallow_per_lane_settings = true;
- lt_settings->lttpr_mode = dp_decide_128b_132b_lttpr_mode(link);
- dp_hw_to_dpcd_lane_settings(lt_settings,
- lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
-}
-
-void dp_decide_training_settings(
- struct dc_link *link,
- const struct dc_link_settings *link_settings,
- struct link_training_settings *lt_settings)
-{
- if (dp_get_link_encoding_format(link_settings) == DP_8b_10b_ENCODING)
- decide_8b_10b_training_settings(link, link_settings, lt_settings);
- else if (dp_get_link_encoding_format(link_settings) == DP_128b_132b_ENCODING)
- decide_128b_132b_training_settings(link, link_settings, lt_settings);
-}
-
-static void override_training_settings(
- struct dc_link *link,
- const struct dc_link_training_overrides *overrides,
- struct link_training_settings *lt_settings)
-{
- uint32_t lane;
-
- /* Override link spread */
- if (!link->dp_ss_off && overrides->downspread != NULL)
- lt_settings->link_settings.link_spread = *overrides->downspread ?
- LINK_SPREAD_05_DOWNSPREAD_30KHZ
- : LINK_SPREAD_DISABLED;
-
- /* Override lane settings */
- if (overrides->voltage_swing != NULL)
- lt_settings->voltage_swing = overrides->voltage_swing;
- if (overrides->pre_emphasis != NULL)
- lt_settings->pre_emphasis = overrides->pre_emphasis;
- if (overrides->post_cursor2 != NULL)
- lt_settings->post_cursor2 = overrides->post_cursor2;
- if (overrides->ffe_preset != NULL)
- lt_settings->ffe_preset = overrides->ffe_preset;
- /* Override HW lane settings with BIOS forced values if present */
- if (link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN &&
- lt_settings->lttpr_mode == LTTPR_MODE_TRANSPARENT) {
- lt_settings->voltage_swing = &link->bios_forced_drive_settings.VOLTAGE_SWING;
- lt_settings->pre_emphasis = &link->bios_forced_drive_settings.PRE_EMPHASIS;
- lt_settings->always_match_dpcd_with_hw_lane_settings = false;
- }
- for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
- lt_settings->hw_lane_settings[lane].VOLTAGE_SWING =
- lt_settings->voltage_swing != NULL ?
- *lt_settings->voltage_swing :
- VOLTAGE_SWING_LEVEL0;
- lt_settings->hw_lane_settings[lane].PRE_EMPHASIS =
- lt_settings->pre_emphasis != NULL ?
- *lt_settings->pre_emphasis
- : PRE_EMPHASIS_DISABLED;
- lt_settings->hw_lane_settings[lane].POST_CURSOR2 =
- lt_settings->post_cursor2 != NULL ?
- *lt_settings->post_cursor2
- : POST_CURSOR2_DISABLED;
- }
-
- if (lt_settings->always_match_dpcd_with_hw_lane_settings)
- dp_hw_to_dpcd_lane_settings(lt_settings,
- lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
-
- /* Initialize training timings */
- if (overrides->cr_pattern_time != NULL)
- lt_settings->cr_pattern_time = *overrides->cr_pattern_time;
-
- if (overrides->eq_pattern_time != NULL)
- lt_settings->eq_pattern_time = *overrides->eq_pattern_time;
-
- if (overrides->pattern_for_cr != NULL)
- lt_settings->pattern_for_cr = *overrides->pattern_for_cr;
- if (overrides->pattern_for_eq != NULL)
- lt_settings->pattern_for_eq = *overrides->pattern_for_eq;
-
- if (overrides->enhanced_framing != NULL)
- lt_settings->enhanced_framing = *overrides->enhanced_framing;
-
- if (link->preferred_training_settings.fec_enable != NULL)
- lt_settings->should_set_fec_ready = *link->preferred_training_settings.fec_enable;
-
- #if defined(CONFIG_DRM_AMD_DC_DCN)
- /* Check DP tunnel LTTPR mode debug option. */
- if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA && link->dc->debug.dpia_debug.bits.force_non_lttpr)
- lt_settings->lttpr_mode = LTTPR_MODE_NON_LTTPR;
-
-#endif
- dp_get_lttpr_mode_override(link, &lt_settings->lttpr_mode);
-
-}
-
-uint8_t dp_convert_to_count(uint8_t lttpr_repeater_count)
-{
- switch (lttpr_repeater_count) {
- case 0x80: // 1 lttpr repeater
- return 1;
- case 0x40: // 2 lttpr repeaters
- return 2;
- case 0x20: // 3 lttpr repeaters
- return 3;
- case 0x10: // 4 lttpr repeaters
- return 4;
- case 0x08: // 5 lttpr repeaters
- return 5;
- case 0x04: // 6 lttpr repeaters
- return 6;
- case 0x02: // 7 lttpr repeaters
- return 7;
- case 0x01: // 8 lttpr repeaters
- return 8;
- default:
- break;
- }
- return 0; // invalid value
-}
-
-static enum dc_status configure_lttpr_mode_transparent(struct dc_link *link)
-{
- uint8_t repeater_mode = DP_PHY_REPEATER_MODE_TRANSPARENT;
-
- DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Transparent Mode\n", __func__);
- return core_link_write_dpcd(link,
- DP_PHY_REPEATER_MODE,
- (uint8_t *)&repeater_mode,
- sizeof(repeater_mode));
-}
-
-static enum dc_status configure_lttpr_mode_non_transparent(
- struct dc_link *link,
- const struct link_training_settings *lt_settings)
-{
- /* aux timeout is already set to extended */
- /* RESET/SET lttpr mode to enable non transparent mode */
- uint8_t repeater_cnt;
- uint32_t aux_interval_address;
- uint8_t repeater_id;
- enum dc_status result = DC_ERROR_UNEXPECTED;
- uint8_t repeater_mode = DP_PHY_REPEATER_MODE_TRANSPARENT;
-
- enum dp_link_encoding encoding = dp_get_link_encoding_format(&lt_settings->link_settings);
-
- if (encoding == DP_8b_10b_ENCODING) {
- DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Transparent Mode\n", __func__);
- result = core_link_write_dpcd(link,
- DP_PHY_REPEATER_MODE,
- (uint8_t *)&repeater_mode,
- sizeof(repeater_mode));
-
- }
-
- if (result == DC_OK) {
- link->dpcd_caps.lttpr_caps.mode = repeater_mode;
- }
-
- if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
-
- DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Non Transparent Mode\n", __func__);
-
- repeater_mode = DP_PHY_REPEATER_MODE_NON_TRANSPARENT;
- result = core_link_write_dpcd(link,
- DP_PHY_REPEATER_MODE,
- (uint8_t *)&repeater_mode,
- sizeof(repeater_mode));
-
- if (result == DC_OK) {
- link->dpcd_caps.lttpr_caps.mode = repeater_mode;
- }
-
- if (encoding == DP_8b_10b_ENCODING) {
- repeater_cnt = dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
-
- /* Driver does not need to train the first hop. Skip DPCD read and clear
- * AUX_RD_INTERVAL for DPTX-to-DPIA hop.
- */
- if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA)
- link->dpcd_caps.lttpr_caps.aux_rd_interval[--repeater_cnt] = 0;
-
- for (repeater_id = repeater_cnt; repeater_id > 0; repeater_id--) {
- aux_interval_address = DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1 +
- ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (repeater_id - 1));
- core_link_read_dpcd(
- link,
- aux_interval_address,
- (uint8_t *)&link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1],
- sizeof(link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1]));
- link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1] &= 0x7F;
- }
- }
- }
-
- return result;
-}
-
-static void repeater_training_done(struct dc_link *link, uint32_t offset)
-{
- union dpcd_training_pattern dpcd_pattern = {0};
-
- const uint32_t dpcd_base_lt_offset =
- DP_TRAINING_PATTERN_SET_PHY_REPEATER1 +
- ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
- /* Set training not in progress*/
- dpcd_pattern.v1_4.TRAINING_PATTERN_SET = DPCD_TRAINING_PATTERN_VIDEOIDLE;
-
- core_link_write_dpcd(
- link,
- dpcd_base_lt_offset,
- &dpcd_pattern.raw,
- 1);
-
- DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Id: %d 0x%X pattern = %x\n",
- __func__,
- offset,
- dpcd_base_lt_offset,
- dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
-}
-
-static void print_status_message(
- struct dc_link *link,
- const struct link_training_settings *lt_settings,
- enum link_training_result status)
-{
- char *link_rate = "Unknown";
- char *lt_result = "Unknown";
- char *lt_spread = "Disabled";
-
- switch (lt_settings->link_settings.link_rate) {
- case LINK_RATE_LOW:
- link_rate = "RBR";
- break;
- case LINK_RATE_RATE_2:
- link_rate = "R2";
- break;
- case LINK_RATE_RATE_3:
- link_rate = "R3";
- break;
- case LINK_RATE_HIGH:
- link_rate = "HBR";
- break;
- case LINK_RATE_RBR2:
- link_rate = "RBR2";
- break;
- case LINK_RATE_RATE_6:
- link_rate = "R6";
- break;
- case LINK_RATE_HIGH2:
- link_rate = "HBR2";
- break;
- case LINK_RATE_HIGH3:
- link_rate = "HBR3";
- break;
- case LINK_RATE_UHBR10:
- link_rate = "UHBR10";
- break;
- case LINK_RATE_UHBR13_5:
- link_rate = "UHBR13.5";
- break;
- case LINK_RATE_UHBR20:
- link_rate = "UHBR20";
- break;
- default:
- break;
- }
-
- switch (status) {
- case LINK_TRAINING_SUCCESS:
- lt_result = "pass";
- break;
- case LINK_TRAINING_CR_FAIL_LANE0:
- lt_result = "CR failed lane0";
- break;
- case LINK_TRAINING_CR_FAIL_LANE1:
- lt_result = "CR failed lane1";
- break;
- case LINK_TRAINING_CR_FAIL_LANE23:
- lt_result = "CR failed lane23";
- break;
- case LINK_TRAINING_EQ_FAIL_CR:
- lt_result = "CR failed in EQ";
- break;
- case LINK_TRAINING_EQ_FAIL_CR_PARTIAL:
- lt_result = "CR failed in EQ partially";
- break;
- case LINK_TRAINING_EQ_FAIL_EQ:
- lt_result = "EQ failed";
- break;
- case LINK_TRAINING_LQA_FAIL:
- lt_result = "LQA failed";
- break;
- case LINK_TRAINING_LINK_LOSS:
- lt_result = "Link loss";
- break;
- case DP_128b_132b_LT_FAILED:
- lt_result = "LT_FAILED received";
- break;
- case DP_128b_132b_MAX_LOOP_COUNT_REACHED:
- lt_result = "max loop count reached";
- break;
- case DP_128b_132b_CHANNEL_EQ_DONE_TIMEOUT:
- lt_result = "channel EQ timeout";
- break;
- case DP_128b_132b_CDS_DONE_TIMEOUT:
- lt_result = "CDS timeout";
- break;
- default:
- break;
- }
-
- switch (lt_settings->link_settings.link_spread) {
- case LINK_SPREAD_DISABLED:
- lt_spread = "Disabled";
- break;
- case LINK_SPREAD_05_DOWNSPREAD_30KHZ:
- lt_spread = "0.5% 30KHz";
- break;
- case LINK_SPREAD_05_DOWNSPREAD_33KHZ:
- lt_spread = "0.5% 33KHz";
- break;
- default:
- break;
- }
-
- /* Connectivity log: link training */
-
- /* TODO - DP2.0 Log: add connectivity log for FFE PRESET */
-
- CONN_MSG_LT(link, "%sx%d %s VS=%d, PE=%d, DS=%s",
- link_rate,
- lt_settings->link_settings.lane_count,
- lt_result,
- lt_settings->hw_lane_settings[0].VOLTAGE_SWING,
- lt_settings->hw_lane_settings[0].PRE_EMPHASIS,
- lt_spread);
-}
-
-void dc_link_dp_set_drive_settings(
- struct dc_link *link,
- const struct link_resource *link_res,
- struct link_training_settings *lt_settings)
-{
- /* program ASIC PHY settings*/
- dp_set_hw_lane_settings(link, link_res, lt_settings, DPRX);
-
- dp_hw_to_dpcd_lane_settings(lt_settings,
- lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
-
- /* Notify DP sink the PHY settings from source */
- dpcd_set_lane_settings(link, lt_settings, DPRX);
-}
-
-bool dc_link_dp_perform_link_training_skip_aux(
- struct dc_link *link,
- const struct link_resource *link_res,
- const struct dc_link_settings *link_setting)
-{
- struct link_training_settings lt_settings = {0};
-
- dp_decide_training_settings(
- link,
- link_setting,
- &lt_settings);
- override_training_settings(
- link,
- &link->preferred_training_settings,
- &lt_settings);
-
- /* 1. Perform_clock_recovery_sequence. */
-
- /* transmit training pattern for clock recovery */
- dp_set_hw_training_pattern(link, link_res, lt_settings.pattern_for_cr, DPRX);
-
- /* call HWSS to set lane settings*/
- dp_set_hw_lane_settings(link, link_res, &lt_settings, DPRX);
-
- /* wait receiver to lock-on*/
- dp_wait_for_training_aux_rd_interval(link, lt_settings.cr_pattern_time);
-
- /* 2. Perform_channel_equalization_sequence. */
-
- /* transmit training pattern for channel equalization. */
- dp_set_hw_training_pattern(link, link_res, lt_settings.pattern_for_eq, DPRX);
-
- /* call HWSS to set lane settings*/
- dp_set_hw_lane_settings(link, link_res, &lt_settings, DPRX);
-
- /* wait receiver to lock-on. */
- dp_wait_for_training_aux_rd_interval(link, lt_settings.eq_pattern_time);
-
- /* 3. Perform_link_training_int. */
-
- /* Mainlink output idle pattern. */
- dp_set_hw_test_pattern(link, link_res, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0);
-
- print_status_message(link, &lt_settings, LINK_TRAINING_SUCCESS);
-
- return true;
-}
-
-enum dc_status dpcd_configure_lttpr_mode(struct dc_link *link, struct link_training_settings *lt_settings)
-{
- enum dc_status status = DC_OK;
-
- if (lt_settings->lttpr_mode == LTTPR_MODE_TRANSPARENT)
- status = configure_lttpr_mode_transparent(link);
-
- else if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT)
- status = configure_lttpr_mode_non_transparent(link, lt_settings);
-
- return status;
-}
-
-static void dpcd_exit_training_mode(struct dc_link *link, enum dp_link_encoding encoding)
-{
- uint8_t sink_status = 0;
- uint8_t i;
-
- /* clear training pattern set */
- dpcd_set_training_pattern(link, DP_TRAINING_PATTERN_VIDEOIDLE);
-
- if (encoding == DP_128b_132b_ENCODING) {
- /* poll for intra-hop disable */
- for (i = 0; i < 10; i++) {
- if ((core_link_read_dpcd(link, DP_SINK_STATUS, &sink_status, 1) == DC_OK) &&
- (sink_status & DP_INTRA_HOP_AUX_REPLY_INDICATION) == 0)
- break;
- udelay(1000);
- }
- }
-}
-
-enum dc_status dpcd_configure_channel_coding(struct dc_link *link,
- struct link_training_settings *lt_settings)
-{
- enum dp_link_encoding encoding =
- dp_get_link_encoding_format(
- &lt_settings->link_settings);
- enum dc_status status;
-
- status = core_link_write_dpcd(
- link,
- DP_MAIN_LINK_CHANNEL_CODING_SET,
- (uint8_t *) &encoding,
- 1);
- DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X MAIN_LINK_CHANNEL_CODING_SET = %x\n",
- __func__,
- DP_MAIN_LINK_CHANNEL_CODING_SET,
- encoding);
-
- return status;
-}
-
-static void dpcd_128b_132b_get_aux_rd_interval(struct dc_link *link,
- uint32_t *interval_in_us)
-{
- union dp_128b_132b_training_aux_rd_interval dpcd_interval;
- uint32_t interval_unit = 0;
-
- dpcd_interval.raw = 0;
- core_link_read_dpcd(link, DP_128b_132b_TRAINING_AUX_RD_INTERVAL,
- &dpcd_interval.raw, sizeof(dpcd_interval.raw));
- interval_unit = dpcd_interval.bits.UNIT ? 1 : 2; /* 0b = 2 ms, 1b = 1 ms */
- /* (128b/132b_TRAINING_AUX_RD_INTERVAL value + 1) *
- * INTERVAL_UNIT. The maximum is 256 ms
- */
- *interval_in_us = (dpcd_interval.bits.VALUE + 1) * interval_unit * 1000;
-}
-
-static enum link_training_result dp_perform_128b_132b_channel_eq_done_sequence(
- struct dc_link *link,
- const struct link_resource *link_res,
- struct link_training_settings *lt_settings)
-{
- uint8_t loop_count;
- uint32_t aux_rd_interval = 0;
- uint32_t wait_time = 0;
- union lane_align_status_updated dpcd_lane_status_updated = {0};
- union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
- enum dc_status status = DC_OK;
- enum link_training_result result = LINK_TRAINING_SUCCESS;
- union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
-
- /* Transmit 128b/132b_TPS1 over Main-Link */
- dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_cr, DPRX);
- /* Set TRAINING_PATTERN_SET to 01h */
- dpcd_set_training_pattern(link, lt_settings->pattern_for_cr);
-
- /* Adjust TX_FFE_PRESET_VALUE and Transmit 128b/132b_TPS2 over Main-Link */
- dpcd_128b_132b_get_aux_rd_interval(link, &aux_rd_interval);
- dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status,
- &dpcd_lane_status_updated, dpcd_lane_adjust, DPRX);
- dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
- lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
- dp_set_hw_lane_settings(link, link_res, lt_settings, DPRX);
- dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_eq, DPRX);
-
- /* Set loop counter to start from 1 */
- loop_count = 1;
-
- /* Set TRAINING_PATTERN_SET to 02h and TX_FFE_PRESET_VALUE in one AUX transaction */
- dpcd_set_lt_pattern_and_lane_settings(link, lt_settings,
- lt_settings->pattern_for_eq, DPRX);
-
- /* poll for channel EQ done */
- while (result == LINK_TRAINING_SUCCESS) {
- dp_wait_for_training_aux_rd_interval(link, aux_rd_interval);
- wait_time += aux_rd_interval;
- status = dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status,
- &dpcd_lane_status_updated, dpcd_lane_adjust, DPRX);
- dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
- lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
- dpcd_128b_132b_get_aux_rd_interval(link, &aux_rd_interval);
- if (status != DC_OK) {
- result = LINK_TRAINING_ABORT;
- } else if (dp_is_ch_eq_done(lt_settings->link_settings.lane_count,
- dpcd_lane_status)) {
- /* pass */
- break;
- } else if (loop_count >= lt_settings->eq_loop_count_limit) {
- result = DP_128b_132b_MAX_LOOP_COUNT_REACHED;
- } else if (dpcd_lane_status_updated.bits.LT_FAILED_128b_132b) {
- result = DP_128b_132b_LT_FAILED;
- } else {
- dp_set_hw_lane_settings(link, link_res, lt_settings, DPRX);
- dpcd_128b_132b_set_lane_settings(link, lt_settings);
- }
- loop_count++;
- }
-
- /* poll for EQ interlane align done */
- while (result == LINK_TRAINING_SUCCESS) {
- if (status != DC_OK) {
- result = LINK_TRAINING_ABORT;
- } else if (dpcd_lane_status_updated.bits.EQ_INTERLANE_ALIGN_DONE_128b_132b) {
- /* pass */
- break;
- } else if (wait_time >= lt_settings->eq_wait_time_limit) {
- result = DP_128b_132b_CHANNEL_EQ_DONE_TIMEOUT;
- } else if (dpcd_lane_status_updated.bits.LT_FAILED_128b_132b) {
- result = DP_128b_132b_LT_FAILED;
- } else {
- dp_wait_for_training_aux_rd_interval(link,
- lt_settings->eq_pattern_time);
- wait_time += lt_settings->eq_pattern_time;
- status = dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status,
- &dpcd_lane_status_updated, dpcd_lane_adjust, DPRX);
- }
- }
-
- return result;
-}
-
-static enum link_training_result dp_perform_128b_132b_cds_done_sequence(
- struct dc_link *link,
- const struct link_resource *link_res,
- struct link_training_settings *lt_settings)
-{
- /* Assumption: assume hardware has transmitted eq pattern */
- enum dc_status status = DC_OK;
- enum link_training_result result = LINK_TRAINING_SUCCESS;
- union lane_align_status_updated dpcd_lane_status_updated = {0};
- union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
- union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
- uint32_t wait_time = 0;
-
- /* initiate CDS done sequence */
- dpcd_set_training_pattern(link, lt_settings->pattern_for_cds);
-
- /* poll for CDS interlane align done and symbol lock */
- while (result == LINK_TRAINING_SUCCESS) {
- dp_wait_for_training_aux_rd_interval(link,
- lt_settings->cds_pattern_time);
- wait_time += lt_settings->cds_pattern_time;
- status = dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status,
- &dpcd_lane_status_updated, dpcd_lane_adjust, DPRX);
- if (status != DC_OK) {
- result = LINK_TRAINING_ABORT;
- } else if (dp_is_symbol_locked(lt_settings->link_settings.lane_count, dpcd_lane_status) &&
- dpcd_lane_status_updated.bits.CDS_INTERLANE_ALIGN_DONE_128b_132b) {
- /* pass */
- break;
- } else if (dpcd_lane_status_updated.bits.LT_FAILED_128b_132b) {
- result = DP_128b_132b_LT_FAILED;
- } else if (wait_time >= lt_settings->cds_wait_time_limit) {
- result = DP_128b_132b_CDS_DONE_TIMEOUT;
- }
- }
-
- return result;
-}
-
-static enum link_training_result dp_perform_8b_10b_link_training(
- struct dc_link *link,
- const struct link_resource *link_res,
- struct link_training_settings *lt_settings)
-{
- enum link_training_result status = LINK_TRAINING_SUCCESS;
-
- uint8_t repeater_cnt;
- uint8_t repeater_id;
- uint8_t lane = 0;
-
- if (link->ctx->dc->work_arounds.lt_early_cr_pattern)
- start_clock_recovery_pattern_early(link, link_res, lt_settings, DPRX);
-
- /* 1. set link rate, lane count and spread. */
- dpcd_set_link_settings(link, lt_settings);
-
- if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
-
- /* 2. perform link training (set link training done
- * to false is done as well)
- */
- repeater_cnt = dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
-
- for (repeater_id = repeater_cnt; (repeater_id > 0 && status == LINK_TRAINING_SUCCESS);
- repeater_id--) {
- status = perform_clock_recovery_sequence(link, link_res, lt_settings, repeater_id);
-
- if (status != LINK_TRAINING_SUCCESS) {
- repeater_training_done(link, repeater_id);
- break;
- }
-
- status = perform_channel_equalization_sequence(link,
- link_res,
- lt_settings,
- repeater_id);
-
- repeater_training_done(link, repeater_id);
-
- if (status != LINK_TRAINING_SUCCESS)
- break;
-
- for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
- lt_settings->dpcd_lane_settings[lane].raw = 0;
- lt_settings->hw_lane_settings[lane].VOLTAGE_SWING = 0;
- lt_settings->hw_lane_settings[lane].PRE_EMPHASIS = 0;
- }
- }
- }
-
- if (status == LINK_TRAINING_SUCCESS) {
- status = perform_clock_recovery_sequence(link, link_res, lt_settings, DPRX);
- if (status == LINK_TRAINING_SUCCESS) {
- status = perform_channel_equalization_sequence(link,
- link_res,
- lt_settings,
- DPRX);
- }
- }
-
- return status;
-}
-
-static enum link_training_result dp_perform_128b_132b_link_training(
- struct dc_link *link,
- const struct link_resource *link_res,
- struct link_training_settings *lt_settings)
-{
- enum link_training_result result = LINK_TRAINING_SUCCESS;
-
- /* TODO - DP2.0 Link: remove legacy_dp2_lt logic */
- if (link->dc->debug.legacy_dp2_lt) {
- struct link_training_settings legacy_settings;
-
- decide_8b_10b_training_settings(link,
- &lt_settings->link_settings,
- &legacy_settings);
- return dp_perform_8b_10b_link_training(link, link_res, &legacy_settings);
- }
-
- dpcd_set_link_settings(link, lt_settings);
-
- if (result == LINK_TRAINING_SUCCESS)
- result = dp_perform_128b_132b_channel_eq_done_sequence(link, link_res, lt_settings);
-
- if (result == LINK_TRAINING_SUCCESS)
- result = dp_perform_128b_132b_cds_done_sequence(link, link_res, lt_settings);
-
- return result;
-}
-
-static enum link_training_result perform_fixed_vs_pe_nontransparent_training_sequence(
- struct dc_link *link,
- const struct link_resource *link_res,
- struct link_training_settings *lt_settings)
-{
- enum link_training_result status = LINK_TRAINING_SUCCESS;
- uint8_t lane = 0;
- uint8_t toggle_rate = 0x6;
- uint8_t target_rate = 0x6;
- bool apply_toggle_rate_wa = false;
- uint8_t repeater_cnt;
- uint8_t repeater_id;
-
- /* Fixed VS/PE specific: Force CR AUX RD Interval to at least 16ms */
- if (lt_settings->cr_pattern_time < 16000)
- lt_settings->cr_pattern_time = 16000;
-
- /* Fixed VS/PE specific: Toggle link rate */
- apply_toggle_rate_wa = (link->vendor_specific_lttpr_link_rate_wa == target_rate);
- target_rate = get_dpcd_link_rate(&lt_settings->link_settings);
- toggle_rate = (target_rate == 0x6) ? 0xA : 0x6;
-
- if (apply_toggle_rate_wa)
- lt_settings->link_settings.link_rate = toggle_rate;
-
- if (link->ctx->dc->work_arounds.lt_early_cr_pattern)
- start_clock_recovery_pattern_early(link, link_res, lt_settings, DPRX);
-
- /* 1. set link rate, lane count and spread. */
- dpcd_set_link_settings(link, lt_settings);
-
- /* Fixed VS/PE specific: Toggle link rate back*/
- if (apply_toggle_rate_wa) {
- core_link_write_dpcd(
- link,
- DP_LINK_BW_SET,
- &target_rate,
- 1);
- }
-
- link->vendor_specific_lttpr_link_rate_wa = target_rate;
-
- if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
-
- /* 2. perform link training (set link training done
- * to false is done as well)
- */
- repeater_cnt = dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
-
- for (repeater_id = repeater_cnt; (repeater_id > 0 && status == LINK_TRAINING_SUCCESS);
- repeater_id--) {
- status = perform_clock_recovery_sequence(link, link_res, lt_settings, repeater_id);
-
- if (status != LINK_TRAINING_SUCCESS) {
- repeater_training_done(link, repeater_id);
- break;
- }
-
- status = perform_channel_equalization_sequence(link,
- link_res,
- lt_settings,
- repeater_id);
-
- repeater_training_done(link, repeater_id);
-
- if (status != LINK_TRAINING_SUCCESS)
- break;
-
- for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
- lt_settings->dpcd_lane_settings[lane].raw = 0;
- lt_settings->hw_lane_settings[lane].VOLTAGE_SWING = 0;
- lt_settings->hw_lane_settings[lane].PRE_EMPHASIS = 0;
- }
- }
- }
-
- if (status == LINK_TRAINING_SUCCESS) {
- status = perform_clock_recovery_sequence(link, link_res, lt_settings, DPRX);
- if (status == LINK_TRAINING_SUCCESS) {
- status = perform_channel_equalization_sequence(link,
- link_res,
- lt_settings,
- DPRX);
- }
- }
-
- return status;
-}
-
-static enum link_training_result dp_perform_fixed_vs_pe_training_sequence(
- struct dc_link *link,
- const struct link_resource *link_res,
- struct link_training_settings *lt_settings)
-{
- const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF};
- const uint8_t offset = dp_convert_to_count(
- link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
- const uint8_t vendor_lttpr_write_data_intercept_en[4] = {0x1, 0x55, 0x63, 0x0};
- const uint8_t vendor_lttpr_write_data_intercept_dis[4] = {0x1, 0x55, 0x63, 0x68};
- uint32_t pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa;
- uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0};
- uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0};
- uint32_t vendor_lttpr_write_address = 0xF004F;
- enum link_training_result status = LINK_TRAINING_SUCCESS;
- uint8_t lane = 0;
- union down_spread_ctrl downspread = {0};
- union lane_count_set lane_count_set = {0};
- uint8_t toggle_rate;
- uint8_t rate;
-
- /* Only 8b/10b is supported */
- ASSERT(dp_get_link_encoding_format(&lt_settings->link_settings) ==
- DP_8b_10b_ENCODING);
-
- if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
- status = perform_fixed_vs_pe_nontransparent_training_sequence(link, link_res, lt_settings);
- return status;
- }
-
- if (offset != 0xFF) {
- vendor_lttpr_write_address +=
- ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
-
- /* Certain display and cable configuration require extra delay */
- if (offset > 2)
- pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa * 2;
- }
-
- /* Vendor specific: Reset lane settings */
- core_link_write_dpcd(
- link,
- vendor_lttpr_write_address,
- &vendor_lttpr_write_data_reset[0],
- sizeof(vendor_lttpr_write_data_reset));
- core_link_write_dpcd(
- link,
- vendor_lttpr_write_address,
- &vendor_lttpr_write_data_vs[0],
- sizeof(vendor_lttpr_write_data_vs));
- core_link_write_dpcd(
- link,
- vendor_lttpr_write_address,
- &vendor_lttpr_write_data_pe[0],
- sizeof(vendor_lttpr_write_data_pe));
-
- /* Vendor specific: Enable intercept */
- core_link_write_dpcd(
- link,
- vendor_lttpr_write_address,
- &vendor_lttpr_write_data_intercept_en[0],
- sizeof(vendor_lttpr_write_data_intercept_en));
-
- /* 1. set link rate, lane count and spread. */
-
- downspread.raw = (uint8_t)(lt_settings->link_settings.link_spread);
-
- lane_count_set.bits.LANE_COUNT_SET =
- lt_settings->link_settings.lane_count;
-
- lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
- lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
-
-
- if (lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) {
- lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED =
- link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED;
- }
-
- core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL,
- &downspread.raw, sizeof(downspread));
-
- core_link_write_dpcd(link, DP_LANE_COUNT_SET,
- &lane_count_set.raw, 1);
-
- rate = get_dpcd_link_rate(&lt_settings->link_settings);
-
- /* Vendor specific: Toggle link rate */
- toggle_rate = (rate == 0x6) ? 0xA : 0x6;
-
- if (link->vendor_specific_lttpr_link_rate_wa == rate) {
- core_link_write_dpcd(
- link,
- DP_LINK_BW_SET,
- &toggle_rate,
- 1);
- }
-
- link->vendor_specific_lttpr_link_rate_wa = rate;
-
- core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1);
-
- DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
- __func__,
- DP_LINK_BW_SET,
- lt_settings->link_settings.link_rate,
- DP_LANE_COUNT_SET,
- lt_settings->link_settings.lane_count,
- lt_settings->enhanced_framing,
- DP_DOWNSPREAD_CTRL,
- lt_settings->link_settings.link_spread);
-
- /* 2. Perform link training */
-
- /* Perform Clock Recovery Sequence */
- if (status == LINK_TRAINING_SUCCESS) {
- const uint8_t max_vendor_dpcd_retries = 10;
- uint32_t retries_cr;
- uint32_t retry_count;
- uint32_t wait_time_microsec;
- enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
- union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX];
- union lane_align_status_updated dpcd_lane_status_updated;
- union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
- enum dc_status dpcd_status = DC_OK;
- uint8_t i = 0;
-
- retries_cr = 0;
- retry_count = 0;
-
- memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status));
- memset(&dpcd_lane_status_updated, '\0',
- sizeof(dpcd_lane_status_updated));
-
- while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
- (retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
-
-
- /* 1. call HWSS to set lane settings */
- dp_set_hw_lane_settings(
- link,
- link_res,
- lt_settings,
- 0);
-
- /* 2. update DPCD of the receiver */
- if (!retry_count) {
- /* EPR #361076 - write as a 5-byte burst,
- * but only for the 1-st iteration.
- */
- dpcd_set_lt_pattern_and_lane_settings(
- link,
- lt_settings,
- lt_settings->pattern_for_cr,
- 0);
- /* Vendor specific: Disable intercept */
- for (i = 0; i < max_vendor_dpcd_retries; i++) {
- msleep(pre_disable_intercept_delay_ms);
- dpcd_status = core_link_write_dpcd(
- link,
- vendor_lttpr_write_address,
- &vendor_lttpr_write_data_intercept_dis[0],
- sizeof(vendor_lttpr_write_data_intercept_dis));
-
- if (dpcd_status == DC_OK)
- break;
-
- core_link_write_dpcd(
- link,
- vendor_lttpr_write_address,
- &vendor_lttpr_write_data_intercept_en[0],
- sizeof(vendor_lttpr_write_data_intercept_en));
- }
- } else {
- vendor_lttpr_write_data_vs[3] = 0;
- vendor_lttpr_write_data_pe[3] = 0;
-
- for (lane = 0; lane < lane_count; lane++) {
- vendor_lttpr_write_data_vs[3] |=
- lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
- vendor_lttpr_write_data_pe[3] |=
- lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
- }
-
- /* Vendor specific: Update VS and PE to DPRX requested value */
- core_link_write_dpcd(
- link,
- vendor_lttpr_write_address,
- &vendor_lttpr_write_data_vs[0],
- sizeof(vendor_lttpr_write_data_vs));
- core_link_write_dpcd(
- link,
- vendor_lttpr_write_address,
- &vendor_lttpr_write_data_pe[0],
- sizeof(vendor_lttpr_write_data_pe));
-
- dpcd_set_lane_settings(
- link,
- lt_settings,
- 0);
- }
-
- /* 3. wait receiver to lock-on*/
- wait_time_microsec = lt_settings->cr_pattern_time;
-
- dp_wait_for_training_aux_rd_interval(
- link,
- wait_time_microsec);
-
- /* 4. Read lane status and requested drive
- * settings as set by the sink
- */
- dp_get_lane_status_and_lane_adjust(
- link,
- lt_settings,
- dpcd_lane_status,
- &dpcd_lane_status_updated,
- dpcd_lane_adjust,
- 0);
-
- /* 5. check CR done*/
- if (dp_is_cr_done(lane_count, dpcd_lane_status)) {
- status = LINK_TRAINING_SUCCESS;
- break;
- }
-
- /* 6. max VS reached*/
- if (dp_is_max_vs_reached(lt_settings))
- break;
-
- /* 7. same lane settings */
- /* Note: settings are the same for all lanes,
- * so comparing first lane is sufficient
- */
- if (lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET ==
- dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE)
- retries_cr++;
- else
- retries_cr = 0;
-
- /* 8. update VS/PE/PC2 in lt_settings*/
- dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
- lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
- retry_count++;
- }
-
- if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) {
- ASSERT(0);
- DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue",
- __func__,
- LINK_TRAINING_MAX_CR_RETRY);
-
- }
-
- status = dp_get_cr_failure(lane_count, dpcd_lane_status);
- }
-
- /* Perform Channel EQ Sequence */
- if (status == LINK_TRAINING_SUCCESS) {
- enum dc_dp_training_pattern tr_pattern;
- uint32_t retries_ch_eq;
- uint32_t wait_time_microsec;
- enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
- union lane_align_status_updated dpcd_lane_status_updated = {0};
- union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
- union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
-
- /* Note: also check that TPS4 is a supported feature*/
- tr_pattern = lt_settings->pattern_for_eq;
-
- dp_set_hw_training_pattern(link, link_res, tr_pattern, 0);
-
- status = LINK_TRAINING_EQ_FAIL_EQ;
-
- for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT;
- retries_ch_eq++) {
-
- dp_set_hw_lane_settings(link, link_res, lt_settings, 0);
-
- vendor_lttpr_write_data_vs[3] = 0;
- vendor_lttpr_write_data_pe[3] = 0;
-
- for (lane = 0; lane < lane_count; lane++) {
- vendor_lttpr_write_data_vs[3] |=
- lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
- vendor_lttpr_write_data_pe[3] |=
- lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
- }
-
- /* Vendor specific: Update VS and PE to DPRX requested value */
- core_link_write_dpcd(
- link,
- vendor_lttpr_write_address,
- &vendor_lttpr_write_data_vs[0],
- sizeof(vendor_lttpr_write_data_vs));
- core_link_write_dpcd(
- link,
- vendor_lttpr_write_address,
- &vendor_lttpr_write_data_pe[0],
- sizeof(vendor_lttpr_write_data_pe));
-
- /* 2. update DPCD*/
- if (!retries_ch_eq)
- /* EPR #361076 - write as a 5-byte burst,
- * but only for the 1-st iteration
- */
-
- dpcd_set_lt_pattern_and_lane_settings(
- link,
- lt_settings,
- tr_pattern, 0);
- else
- dpcd_set_lane_settings(link, lt_settings, 0);
-
- /* 3. wait for receiver to lock-on*/
- wait_time_microsec = lt_settings->eq_pattern_time;
-
- dp_wait_for_training_aux_rd_interval(
- link,
- wait_time_microsec);
-
- /* 4. Read lane status and requested
- * drive settings as set by the sink
- */
- dp_get_lane_status_and_lane_adjust(
- link,
- lt_settings,
- dpcd_lane_status,
- &dpcd_lane_status_updated,
- dpcd_lane_adjust,
- 0);
-
- /* 5. check CR done*/
- if (!dp_is_cr_done(lane_count, dpcd_lane_status)) {
- status = LINK_TRAINING_EQ_FAIL_CR;
- break;
- }
-
- /* 6. check CHEQ done*/
- if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) &&
- dp_is_symbol_locked(lane_count, dpcd_lane_status) &&
- dp_is_interlane_aligned(dpcd_lane_status_updated)) {
- status = LINK_TRAINING_SUCCESS;
- break;
- }
-
- /* 7. update VS/PE/PC2 in lt_settings*/
- dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
- lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
- }
- }
-
- return status;
-}
-
-
-enum link_training_result dc_link_dp_perform_link_training(
- struct dc_link *link,
- const struct link_resource *link_res,
- const struct dc_link_settings *link_settings,
- bool skip_video_pattern)
-{
- enum link_training_result status = LINK_TRAINING_SUCCESS;
- struct link_training_settings lt_settings = {0};
- enum dp_link_encoding encoding =
- dp_get_link_encoding_format(link_settings);
-
- /* decide training settings */
- dp_decide_training_settings(
- link,
- link_settings,
- &lt_settings);
-
- override_training_settings(
- link,
- &link->preferred_training_settings,
- &lt_settings);
-
- /* reset previous training states */
- dpcd_exit_training_mode(link, encoding);
-
- /* configure link prior to entering training mode */
- dpcd_configure_lttpr_mode(link, &lt_settings);
- dp_set_fec_ready(link, link_res, lt_settings.should_set_fec_ready);
- dpcd_configure_channel_coding(link, &lt_settings);
-
- /* enter training mode:
- * Per DP specs starting from here, DPTX device shall not issue
- * Non-LT AUX transactions inside training mode.
- */
- if (link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN && encoding == DP_8b_10b_ENCODING)
- status = dp_perform_fixed_vs_pe_training_sequence(link, link_res, &lt_settings);
- else if (encoding == DP_8b_10b_ENCODING)
- status = dp_perform_8b_10b_link_training(link, link_res, &lt_settings);
- else if (encoding == DP_128b_132b_ENCODING)
- status = dp_perform_128b_132b_link_training(link, link_res, &lt_settings);
- else
- ASSERT(0);
-
- /* exit training mode */
- dpcd_exit_training_mode(link, encoding);
-
- /* switch to video idle */
- if ((status == LINK_TRAINING_SUCCESS) || !skip_video_pattern)
- status = dp_transition_to_video_idle(link,
- link_res,
- &lt_settings,
- status);
-
- /* dump debug data */
- print_status_message(link, &lt_settings, status);
- if (status != LINK_TRAINING_SUCCESS)
- link->ctx->dc->debug_data.ltFailCount++;
- return status;
-}
-
-bool perform_link_training_with_retries(
- const struct dc_link_settings *link_setting,
- bool skip_video_pattern,
- int attempts,
- struct pipe_ctx *pipe_ctx,
- enum signal_type signal,
- bool do_fallback)
-{
- int j;
- uint8_t delay_between_attempts = LINK_TRAINING_RETRY_DELAY;
- struct dc_stream_state *stream = pipe_ctx->stream;
- struct dc_link *link = stream->link;
- enum dp_panel_mode panel_mode = dp_get_panel_mode(link);
- enum link_training_result status = LINK_TRAINING_CR_FAIL_LANE0;
- struct dc_link_settings cur_link_settings = *link_setting;
- struct dc_link_settings max_link_settings = *link_setting;
- const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
- int fail_count = 0;
- bool is_link_bw_low = false; /* link bandwidth < stream bandwidth */
- bool is_link_bw_min = /* RBR x 1 */
- (cur_link_settings.link_rate <= LINK_RATE_LOW) &&
- (cur_link_settings.lane_count <= LANE_COUNT_ONE);
-
- dp_trace_commit_lt_init(link);
-
- if (dp_get_link_encoding_format(&cur_link_settings) == DP_8b_10b_ENCODING)
- /* We need to do this before the link training to ensure the idle
- * pattern in SST mode will be sent right after the link training
- */
- link_hwss->setup_stream_encoder(pipe_ctx);
-
- dp_trace_set_lt_start_timestamp(link, false);
- j = 0;
- while (j < attempts && fail_count < (attempts * 10)) {
-
- DC_LOG_HW_LINK_TRAINING("%s: Beginning link(%d) training attempt %u of %d @ rate(%d) x lane(%d)\n",
- __func__, link->link_index, (unsigned int)j + 1, attempts, cur_link_settings.link_rate,
- cur_link_settings.lane_count);
-
- dp_enable_link_phy(
- link,
- &pipe_ctx->link_res,
- signal,
- pipe_ctx->clock_source->id,
- &cur_link_settings);
-
- if (stream->sink_patches.dppowerup_delay > 0) {
- int delay_dp_power_up_in_ms = stream->sink_patches.dppowerup_delay;
-
- msleep(delay_dp_power_up_in_ms);
- }
-
-#ifdef CONFIG_DRM_AMD_DC_HDCP
- if (panel_mode == DP_PANEL_MODE_EDP) {
- struct cp_psp *cp_psp = &stream->ctx->cp_psp;
-
- if (cp_psp && cp_psp->funcs.enable_assr)
- /* ASSR is bound to fail with unsigned PSP
- * verstage used during devlopment phase.
- * Report and continue with eDP panel mode to
- * perform eDP link training with right settings
- */
- cp_psp->funcs.enable_assr(cp_psp->handle, link);
- }
-#endif
-
- dp_set_panel_mode(link, panel_mode);
-
- if (link->aux_access_disabled) {
- dc_link_dp_perform_link_training_skip_aux(link, &pipe_ctx->link_res, &cur_link_settings);
- return true;
- } else {
- /** @todo Consolidate USB4 DP and DPx.x training. */
- if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) {
- status = dc_link_dpia_perform_link_training(link,
- &pipe_ctx->link_res,
- &cur_link_settings,
- skip_video_pattern);
-
- /* Transmit idle pattern once training successful. */
- if (status == LINK_TRAINING_SUCCESS && !is_link_bw_low) {
- dp_set_hw_test_pattern(link, &pipe_ctx->link_res, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0);
- /* Update verified link settings to current one
- * Because DPIA LT might fallback to lower link setting.
- */
- if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
- link->verified_link_cap.link_rate = link->cur_link_settings.link_rate;
- link->verified_link_cap.lane_count = link->cur_link_settings.lane_count;
- dm_helpers_dp_mst_update_branch_bandwidth(link->ctx, link);
- }
- }
- } else {
- status = dc_link_dp_perform_link_training(link,
- &pipe_ctx->link_res,
- &cur_link_settings,
- skip_video_pattern);
- }
-
- dp_trace_lt_total_count_increment(link, false);
- dp_trace_lt_result_update(link, status, false);
- dp_trace_set_lt_end_timestamp(link, false);
- if (status == LINK_TRAINING_SUCCESS && !is_link_bw_low)
- return true;
- }
-
- fail_count++;
- dp_trace_lt_fail_count_update(link, fail_count, false);
- if (link->ep_type == DISPLAY_ENDPOINT_PHY) {
- /* latest link training still fail or link training is aborted
- * skip delay and keep PHY on
- */
- if (j == (attempts - 1) || (status == LINK_TRAINING_ABORT))
- break;
- }
-
- DC_LOG_WARNING("%s: Link(%d) training attempt %u of %d failed @ rate(%d) x lane(%d) : fail reason:(%d)\n",
- __func__, link->link_index, (unsigned int)j + 1, attempts, cur_link_settings.link_rate,
- cur_link_settings.lane_count, status);
-
- dp_disable_link_phy(link, &pipe_ctx->link_res, signal);
-
- /* Abort link training if failure due to sink being unplugged. */
- if (status == LINK_TRAINING_ABORT) {
- enum dc_connection_type type = dc_connection_none;
-
- dc_link_detect_sink(link, &type);
- if (type == dc_connection_none) {
- DC_LOG_HW_LINK_TRAINING("%s: Aborting training because sink unplugged\n", __func__);
- break;
- }
- }
-
- /* Try to train again at original settings if:
- * - not falling back between training attempts;
- * - aborted previous attempt due to reasons other than sink unplug;
- * - successfully trained but at a link rate lower than that required by stream;
- * - reached minimum link bandwidth.
- */
- if (!do_fallback || (status == LINK_TRAINING_ABORT) ||
- (status == LINK_TRAINING_SUCCESS && is_link_bw_low) ||
- is_link_bw_min) {
- j++;
- cur_link_settings = *link_setting;
- delay_between_attempts += LINK_TRAINING_RETRY_DELAY;
- is_link_bw_low = false;
- is_link_bw_min = (cur_link_settings.link_rate <= LINK_RATE_LOW) &&
- (cur_link_settings.lane_count <= LANE_COUNT_ONE);
-
- } else if (do_fallback) { /* Try training at lower link bandwidth if doing fallback. */
- uint32_t req_bw;
- uint32_t link_bw;
-
- decide_fallback_link_setting(link, &max_link_settings,
- &cur_link_settings, status);
- /* Fail link training if reduced link bandwidth no longer meets
- * stream requirements.
- */
- req_bw = dc_bandwidth_in_kbps_from_timing(&stream->timing);
- link_bw = dc_link_bandwidth_kbps(link, &cur_link_settings);
- is_link_bw_low = (req_bw > link_bw);
- is_link_bw_min = ((cur_link_settings.link_rate <= LINK_RATE_LOW) &&
- (cur_link_settings.lane_count <= LANE_COUNT_ONE));
- if (is_link_bw_low)
- DC_LOG_WARNING(
- "%s: Link(%d) bandwidth too low after fallback req_bw(%d) > link_bw(%d)\n",
- __func__, link->link_index, req_bw, link_bw);
- }
-
- msleep(delay_between_attempts);
- }
- return false;
-}
-
-static enum clock_source_id get_clock_source_id(struct dc_link *link)
-{
- enum clock_source_id dp_cs_id = CLOCK_SOURCE_ID_UNDEFINED;
- struct clock_source *dp_cs = link->dc->res_pool->dp_clock_source;
-
- if (dp_cs != NULL) {
- dp_cs_id = dp_cs->id;
- } else {
- /*
- * dp clock source is not initialized for some reason.
- * Should not happen, CLOCK_SOURCE_ID_EXTERNAL will be used
- */
- ASSERT(dp_cs);
- }
-
- return dp_cs_id;
-}
-
-static void set_dp_mst_mode(struct dc_link *link, const struct link_resource *link_res,
- bool mst_enable)
-{
- if (mst_enable == false &&
- link->type == dc_connection_mst_branch) {
- /* Disable MST on link. Use only local sink. */
- dp_disable_link_phy_mst(link, link_res, link->connector_signal);
-
- link->type = dc_connection_single;
- link->local_sink = link->remote_sinks[0];
- link->local_sink->sink_signal = SIGNAL_TYPE_DISPLAY_PORT;
- dc_sink_retain(link->local_sink);
- dm_helpers_dp_mst_stop_top_mgr(link->ctx, link);
- } else if (mst_enable == true &&
- link->type == dc_connection_single &&
- link->remote_sinks[0] != NULL) {
- /* Re-enable MST on link. */
- dp_disable_link_phy(link, link_res, link->connector_signal);
- dp_enable_mst_on_sink(link, true);
-
- link->type = dc_connection_mst_branch;
- link->local_sink->sink_signal = SIGNAL_TYPE_DISPLAY_PORT_MST;
- }
-}
-
-bool dc_link_dp_sync_lt_begin(struct dc_link *link)
-{
- /* Begin Sync LT. During this time,
- * DPCD:600h must not be powered down.
- */
- link->sync_lt_in_progress = true;
-
- /*Clear any existing preferred settings.*/
- memset(&link->preferred_training_settings, 0,
- sizeof(struct dc_link_training_overrides));
- memset(&link->preferred_link_setting, 0,
- sizeof(struct dc_link_settings));
-
- return true;
-}
-
-enum link_training_result dc_link_dp_sync_lt_attempt(
- struct dc_link *link,
- const struct link_resource *link_res,
- struct dc_link_settings *link_settings,
- struct dc_link_training_overrides *lt_overrides)
-{
- struct link_training_settings lt_settings = {0};
- enum link_training_result lt_status = LINK_TRAINING_SUCCESS;
- enum dp_panel_mode panel_mode = DP_PANEL_MODE_DEFAULT;
- enum clock_source_id dp_cs_id = CLOCK_SOURCE_ID_EXTERNAL;
- bool fec_enable = false;
-
- dp_decide_training_settings(
- link,
- link_settings,
- &lt_settings);
- override_training_settings(
- link,
- lt_overrides,
- &lt_settings);
- /* Setup MST Mode */
- if (lt_overrides->mst_enable)
- set_dp_mst_mode(link, link_res, *lt_overrides->mst_enable);
-
- /* Disable link */
- dp_disable_link_phy(link, link_res, link->connector_signal);
-
- /* Enable link */
- dp_cs_id = get_clock_source_id(link);
- dp_enable_link_phy(link, link_res, link->connector_signal,
- dp_cs_id, link_settings);
-
- /* Set FEC enable */
- if (dp_get_link_encoding_format(link_settings) == DP_8b_10b_ENCODING) {
- fec_enable = lt_overrides->fec_enable && *lt_overrides->fec_enable;
- dp_set_fec_ready(link, NULL, fec_enable);
- }
-
- if (lt_overrides->alternate_scrambler_reset) {
- if (*lt_overrides->alternate_scrambler_reset)
- panel_mode = DP_PANEL_MODE_EDP;
- else
- panel_mode = DP_PANEL_MODE_DEFAULT;
- } else
- panel_mode = dp_get_panel_mode(link);
-
- dp_set_panel_mode(link, panel_mode);
-
- /* Attempt to train with given link training settings */
- if (link->ctx->dc->work_arounds.lt_early_cr_pattern)
- start_clock_recovery_pattern_early(link, link_res, &lt_settings, DPRX);
-
- /* Set link rate, lane count and spread. */
- dpcd_set_link_settings(link, &lt_settings);
-
- /* 2. perform link training (set link training done
- * to false is done as well)
- */
- lt_status = perform_clock_recovery_sequence(link, link_res, &lt_settings, DPRX);
- if (lt_status == LINK_TRAINING_SUCCESS) {
- lt_status = perform_channel_equalization_sequence(link,
- link_res,
- &lt_settings,
- DPRX);
- }
-
- /* 3. Sync LT must skip TRAINING_PATTERN_SET:0 (video pattern)*/
- /* 4. print status message*/
- print_status_message(link, &lt_settings, lt_status);
-
- return lt_status;
-}
-
-bool dc_link_dp_sync_lt_end(struct dc_link *link, bool link_down)
-{
- /* If input parameter is set, shut down phy.
- * Still shouldn't turn off dp_receiver (DPCD:600h)
- */
- if (link_down == true) {
- struct dc_link_settings link_settings = link->cur_link_settings;
- dp_disable_link_phy(link, NULL, link->connector_signal);
- if (dp_get_link_encoding_format(&link_settings) == DP_8b_10b_ENCODING)
- dp_set_fec_ready(link, NULL, false);
- }
-
- link->sync_lt_in_progress = false;
- return true;
-}
-
-static enum dc_link_rate get_lttpr_max_link_rate(struct dc_link *link)
-{
- enum dc_link_rate lttpr_max_link_rate = link->dpcd_caps.lttpr_caps.max_link_rate;
-
- if (link->dpcd_caps.lttpr_caps.supported_128b_132b_rates.bits.UHBR20)
- lttpr_max_link_rate = LINK_RATE_UHBR20;
- else if (link->dpcd_caps.lttpr_caps.supported_128b_132b_rates.bits.UHBR13_5)
- lttpr_max_link_rate = LINK_RATE_UHBR13_5;
- else if (link->dpcd_caps.lttpr_caps.supported_128b_132b_rates.bits.UHBR10)
- lttpr_max_link_rate = LINK_RATE_UHBR10;
-
- return lttpr_max_link_rate;
-}
-
-static enum dc_link_rate get_cable_max_link_rate(struct dc_link *link)
-{
- enum dc_link_rate cable_max_link_rate = LINK_RATE_UNKNOWN;
-
- if (link->dpcd_caps.cable_id.bits.UHBR10_20_CAPABILITY & DP_UHBR20)
- cable_max_link_rate = LINK_RATE_UHBR20;
- else if (link->dpcd_caps.cable_id.bits.UHBR13_5_CAPABILITY)
- cable_max_link_rate = LINK_RATE_UHBR13_5;
- else if (link->dpcd_caps.cable_id.bits.UHBR10_20_CAPABILITY & DP_UHBR10)
- cable_max_link_rate = LINK_RATE_UHBR10;
-
- return cable_max_link_rate;
-}
-
-bool dc_link_dp_get_max_link_enc_cap(const struct dc_link *link, struct dc_link_settings *max_link_enc_cap)
-{
- struct link_encoder *link_enc = NULL;
-
- if (!max_link_enc_cap) {
- DC_LOG_ERROR("%s: Could not return max link encoder caps", __func__);
- return false;
- }
-
- link_enc = link_enc_cfg_get_link_enc(link);
- ASSERT(link_enc);
-
- if (link_enc && link_enc->funcs->get_max_link_cap) {
- link_enc->funcs->get_max_link_cap(link_enc, max_link_enc_cap);
- return true;
- }
-
- DC_LOG_ERROR("%s: Max link encoder caps unknown", __func__);
- max_link_enc_cap->lane_count = 1;
- max_link_enc_cap->link_rate = 6;
- return false;
-}
-
-
-struct dc_link_settings dp_get_max_link_cap(struct dc_link *link)
-{
- struct dc_link_settings max_link_cap = {0};
- enum dc_link_rate lttpr_max_link_rate;
- enum dc_link_rate cable_max_link_rate;
- struct link_encoder *link_enc = NULL;
-
-
- link_enc = link_enc_cfg_get_link_enc(link);
- ASSERT(link_enc);
-
- /* get max link encoder capability */
- if (link_enc)
- link_enc->funcs->get_max_link_cap(link_enc, &max_link_cap);
-
- /* Lower link settings based on sink's link cap */
- if (link->reported_link_cap.lane_count < max_link_cap.lane_count)
- max_link_cap.lane_count =
- link->reported_link_cap.lane_count;
- if (link->reported_link_cap.link_rate < max_link_cap.link_rate)
- max_link_cap.link_rate =
- link->reported_link_cap.link_rate;
- if (link->reported_link_cap.link_spread <
- max_link_cap.link_spread)
- max_link_cap.link_spread =
- link->reported_link_cap.link_spread;
-
- /* Lower link settings based on cable attributes
- * Cable ID is a DP2 feature to identify max certified link rate that
- * a cable can carry. The cable identification method requires both
- * cable and display hardware support. Since the specs comes late, it is
- * anticipated that the first round of DP2 cables and displays may not
- * be fully compatible to reliably return cable ID data. Therefore the
- * decision of our cable id policy is that if the cable can return non
- * zero cable id data, we will take cable's link rate capability into
- * account. However if we get zero data, the cable link rate capability
- * is considered inconclusive. In this case, we will not take cable's
- * capability into account to avoid of over limiting hardware capability
- * from users. The max overall link rate capability is still determined
- * after actual dp pre-training. Cable id is considered as an auxiliary
- * method of determining max link bandwidth capability.
- */
- cable_max_link_rate = get_cable_max_link_rate(link);
-
- if (!link->dc->debug.ignore_cable_id &&
- cable_max_link_rate != LINK_RATE_UNKNOWN &&
- cable_max_link_rate < max_link_cap.link_rate)
- max_link_cap.link_rate = cable_max_link_rate;
-
- /* account for lttpr repeaters cap
- * notes: repeaters do not snoop in the DPRX Capabilities addresses (3.6.3).
- */
- if (dp_is_lttpr_present(link)) {
- if (link->dpcd_caps.lttpr_caps.max_lane_count < max_link_cap.lane_count)
- max_link_cap.lane_count = link->dpcd_caps.lttpr_caps.max_lane_count;
- lttpr_max_link_rate = get_lttpr_max_link_rate(link);
-
- if (lttpr_max_link_rate < max_link_cap.link_rate)
- max_link_cap.link_rate = lttpr_max_link_rate;
-
- DC_LOG_HW_LINK_TRAINING("%s\n Training with LTTPR, max_lane count %d max_link rate %d \n",
- __func__,
- max_link_cap.lane_count,
- max_link_cap.link_rate);
- }
-
- if (dp_get_link_encoding_format(&max_link_cap) == DP_128b_132b_ENCODING &&
- link->dc->debug.disable_uhbr)
- max_link_cap.link_rate = LINK_RATE_HIGH3;
-
- return max_link_cap;
-}
-
-static enum dc_status read_hpd_rx_irq_data(
- struct dc_link *link,
- union hpd_irq_data *irq_data)
-{
- static enum dc_status retval;
-
- /* The HW reads 16 bytes from 200h on HPD,
- * but if we get an AUX_DEFER, the HW cannot retry
- * and this causes the CTS tests 4.3.2.1 - 3.2.4 to
- * fail, so we now explicitly read 6 bytes which is
- * the req from the above mentioned test cases.
- *
- * For DP 1.4 we need to read those from 2002h range.
- */
- if (link->dpcd_caps.dpcd_rev.raw < DPCD_REV_14)
- retval = core_link_read_dpcd(
- link,
- DP_SINK_COUNT,
- irq_data->raw,
- sizeof(union hpd_irq_data));
- else {
- /* Read 14 bytes in a single read and then copy only the required fields.
- * This is more efficient than doing it in two separate AUX reads. */
-
- uint8_t tmp[DP_SINK_STATUS_ESI - DP_SINK_COUNT_ESI + 1];
-
- retval = core_link_read_dpcd(
- link,
- DP_SINK_COUNT_ESI,
- tmp,
- sizeof(tmp));
-
- if (retval != DC_OK)
- return retval;
-
- irq_data->bytes.sink_cnt.raw = tmp[DP_SINK_COUNT_ESI - DP_SINK_COUNT_ESI];
- irq_data->bytes.device_service_irq.raw = tmp[DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0 - DP_SINK_COUNT_ESI];
- irq_data->bytes.lane01_status.raw = tmp[DP_LANE0_1_STATUS_ESI - DP_SINK_COUNT_ESI];
- irq_data->bytes.lane23_status.raw = tmp[DP_LANE2_3_STATUS_ESI - DP_SINK_COUNT_ESI];
- irq_data->bytes.lane_status_updated.raw = tmp[DP_LANE_ALIGN_STATUS_UPDATED_ESI - DP_SINK_COUNT_ESI];
- irq_data->bytes.sink_status.raw = tmp[DP_SINK_STATUS_ESI - DP_SINK_COUNT_ESI];
- }
-
- return retval;
-}
-
-bool hpd_rx_irq_check_link_loss_status(
- struct dc_link *link,
- union hpd_irq_data *hpd_irq_dpcd_data)
-{
- uint8_t irq_reg_rx_power_state = 0;
- enum dc_status dpcd_result = DC_ERROR_UNEXPECTED;
- union lane_status lane_status;
- uint32_t lane;
- bool sink_status_changed;
- bool return_code;
-
- sink_status_changed = false;
- return_code = false;
-
- if (link->cur_link_settings.lane_count == 0)
- return return_code;
-
- /*1. Check that Link Status changed, before re-training.*/
-
- /*parse lane status*/
- for (lane = 0; lane < link->cur_link_settings.lane_count; lane++) {
- /* check status of lanes 0,1
- * changed DpcdAddress_Lane01Status (0x202)
- */
- lane_status.raw = get_nibble_at_index(
- &hpd_irq_dpcd_data->bytes.lane01_status.raw,
- lane);
-
- if (!lane_status.bits.CHANNEL_EQ_DONE_0 ||
- !lane_status.bits.CR_DONE_0 ||
- !lane_status.bits.SYMBOL_LOCKED_0) {
- /* if one of the channel equalization, clock
- * recovery or symbol lock is dropped
- * consider it as (link has been
- * dropped) dp sink status has changed
- */
- sink_status_changed = true;
- break;
- }
- }
-
- /* Check interlane align.*/
- if (sink_status_changed ||
- !hpd_irq_dpcd_data->bytes.lane_status_updated.bits.INTERLANE_ALIGN_DONE) {
-
- DC_LOG_HW_HPD_IRQ("%s: Link Status changed.\n", __func__);
-
- return_code = true;
-
- /*2. Check that we can handle interrupt: Not in FS DOS,
- * Not in "Display Timeout" state, Link is trained.
- */
- dpcd_result = core_link_read_dpcd(link,
- DP_SET_POWER,
- &irq_reg_rx_power_state,
- sizeof(irq_reg_rx_power_state));
-
- if (dpcd_result != DC_OK) {
- DC_LOG_HW_HPD_IRQ("%s: DPCD read failed to obtain power state.\n",
- __func__);
- } else {
- if (irq_reg_rx_power_state != DP_SET_POWER_D0)
- return_code = false;
- }
- }
-
- return return_code;
-}
-
-static bool dp_verify_link_cap(
- struct dc_link *link,
- struct dc_link_settings *known_limit_link_setting,
- int *fail_count)
-{
- struct dc_link_settings cur_link_settings = {0};
- struct dc_link_settings max_link_settings = *known_limit_link_setting;
- bool success = false;
- bool skip_video_pattern;
- enum clock_source_id dp_cs_id = get_clock_source_id(link);
- enum link_training_result status = LINK_TRAINING_SUCCESS;
- union hpd_irq_data irq_data;
- struct link_resource link_res;
-
- memset(&irq_data, 0, sizeof(irq_data));
- cur_link_settings = max_link_settings;
-
- /* Grant extended timeout request */
- if (dp_is_lttpr_present(link) && link->dpcd_caps.lttpr_caps.max_ext_timeout > 0) {
- uint8_t grant = link->dpcd_caps.lttpr_caps.max_ext_timeout & 0x80;
-
- core_link_write_dpcd(link, DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT, &grant, sizeof(grant));
- }
-
- do {
- if (!get_temp_dp_link_res(link, &link_res, &cur_link_settings))
- continue;
-
- skip_video_pattern = cur_link_settings.link_rate != LINK_RATE_LOW;
- dp_enable_link_phy(
- link,
- &link_res,
- link->connector_signal,
- dp_cs_id,
- &cur_link_settings);
-
- status = dc_link_dp_perform_link_training(
- link,
- &link_res,
- &cur_link_settings,
- skip_video_pattern);
-
- if (status == LINK_TRAINING_SUCCESS) {
- success = true;
- udelay(1000);
- if (read_hpd_rx_irq_data(link, &irq_data) == DC_OK &&
- hpd_rx_irq_check_link_loss_status(
- link,
- &irq_data))
- (*fail_count)++;
-
- } else {
- (*fail_count)++;
- }
- dp_trace_lt_total_count_increment(link, true);
- dp_trace_lt_result_update(link, status, true);
- dp_disable_link_phy(link, &link_res, link->connector_signal);
- } while (!success && decide_fallback_link_setting(link,
- &max_link_settings, &cur_link_settings, status));
-
- link->verified_link_cap = success ?
- cur_link_settings : fail_safe_link_settings;
- return success;
-}
-
-static void apply_usbc_combo_phy_reset_wa(struct dc_link *link,
- struct dc_link_settings *link_settings)
-{
- /* Temporary Renoir-specific workaround PHY will sometimes be in bad
- * state on hotplugging display from certain USB-C dongle, so add extra
- * cycle of enabling and disabling the PHY before first link training.
- */
- struct link_resource link_res = {0};
- enum clock_source_id dp_cs_id = get_clock_source_id(link);
-
- dp_enable_link_phy(link, &link_res, link->connector_signal,
- dp_cs_id, link_settings);
- dp_disable_link_phy(link, &link_res, link->connector_signal);
-}
-
-bool dp_verify_link_cap_with_retries(
- struct dc_link *link,
- struct dc_link_settings *known_limit_link_setting,
- int attempts)
-{
- int i = 0;
- bool success = false;
- int fail_count = 0;
-
- dp_trace_detect_lt_init(link);
-
- if (link->link_enc && link->link_enc->features.flags.bits.DP_IS_USB_C &&
- link->dc->debug.usbc_combo_phy_reset_wa)
- apply_usbc_combo_phy_reset_wa(link, known_limit_link_setting);
-
- dp_trace_set_lt_start_timestamp(link, false);
- for (i = 0; i < attempts; i++) {
- enum dc_connection_type type = dc_connection_none;
-
- memset(&link->verified_link_cap, 0,
- sizeof(struct dc_link_settings));
- if (!dc_link_detect_sink(link, &type) || type == dc_connection_none) {
- link->verified_link_cap = fail_safe_link_settings;
- break;
- } else if (dp_verify_link_cap(link, known_limit_link_setting,
- &fail_count) && fail_count == 0) {
- success = true;
- break;
- }
- msleep(10);
- }
-
- dp_trace_lt_fail_count_update(link, fail_count, true);
- dp_trace_set_lt_end_timestamp(link, true);
-
- return success;
-}
-
-/* in DP compliance test, DPR-120 may have
- * a random value in its MAX_LINK_BW dpcd field.
- * We map it to the maximum supported link rate that
- * is smaller than MAX_LINK_BW in this case.
- */
-static enum dc_link_rate get_link_rate_from_max_link_bw(
- uint8_t max_link_bw)
-{
- enum dc_link_rate link_rate;
-
- if (max_link_bw >= LINK_RATE_HIGH3) {
- link_rate = LINK_RATE_HIGH3;
- } else if (max_link_bw < LINK_RATE_HIGH3
- && max_link_bw >= LINK_RATE_HIGH2) {
- link_rate = LINK_RATE_HIGH2;
- } else if (max_link_bw < LINK_RATE_HIGH2
- && max_link_bw >= LINK_RATE_HIGH) {
- link_rate = LINK_RATE_HIGH;
- } else if (max_link_bw < LINK_RATE_HIGH
- && max_link_bw >= LINK_RATE_LOW) {
- link_rate = LINK_RATE_LOW;
- } else {
- link_rate = LINK_RATE_UNKNOWN;
- }
-
- return link_rate;
-}
-
-static inline bool reached_minimum_lane_count(enum dc_lane_count lane_count)
-{
- return lane_count <= LANE_COUNT_ONE;
-}
-
-static inline bool reached_minimum_link_rate(enum dc_link_rate link_rate)
-{
- return link_rate <= LINK_RATE_LOW;
-}
-
-static enum dc_lane_count reduce_lane_count(enum dc_lane_count lane_count)
-{
- switch (lane_count) {
- case LANE_COUNT_FOUR:
- return LANE_COUNT_TWO;
- case LANE_COUNT_TWO:
- return LANE_COUNT_ONE;
- case LANE_COUNT_ONE:
- return LANE_COUNT_UNKNOWN;
- default:
- return LANE_COUNT_UNKNOWN;
- }
-}
-
-static enum dc_link_rate reduce_link_rate(enum dc_link_rate link_rate)
-{
- switch (link_rate) {
- case LINK_RATE_UHBR20:
- return LINK_RATE_UHBR13_5;
- case LINK_RATE_UHBR13_5:
- return LINK_RATE_UHBR10;
- case LINK_RATE_UHBR10:
- return LINK_RATE_HIGH3;
- case LINK_RATE_HIGH3:
- return LINK_RATE_HIGH2;
- case LINK_RATE_HIGH2:
- return LINK_RATE_HIGH;
- case LINK_RATE_HIGH:
- return LINK_RATE_LOW;
- case LINK_RATE_LOW:
- return LINK_RATE_UNKNOWN;
- default:
- return LINK_RATE_UNKNOWN;
- }
-}
-
-static enum dc_lane_count increase_lane_count(enum dc_lane_count lane_count)
-{
- switch (lane_count) {
- case LANE_COUNT_ONE:
- return LANE_COUNT_TWO;
- case LANE_COUNT_TWO:
- return LANE_COUNT_FOUR;
- default:
- return LANE_COUNT_UNKNOWN;
- }
-}
-
-static enum dc_link_rate increase_link_rate(struct dc_link *link,
- enum dc_link_rate link_rate)
-{
- switch (link_rate) {
- case LINK_RATE_LOW:
- return LINK_RATE_HIGH;
- case LINK_RATE_HIGH:
- return LINK_RATE_HIGH2;
- case LINK_RATE_HIGH2:
- return LINK_RATE_HIGH3;
- case LINK_RATE_HIGH3:
- return LINK_RATE_UHBR10;
- case LINK_RATE_UHBR10:
- /* upto DP2.x specs UHBR13.5 is the only link rate that could be
- * not supported by DPRX when higher link rate is supported.
- * so we treat it as a special case for code simplicity. When we
- * have new specs with more link rates like this, we should
- * consider a more generic solution to handle discrete link
- * rate capabilities.
- */
- return link->dpcd_caps.dp_128b_132b_supported_link_rates.bits.UHBR13_5 ?
- LINK_RATE_UHBR13_5 : LINK_RATE_UHBR20;
- case LINK_RATE_UHBR13_5:
- return LINK_RATE_UHBR20;
- default:
- return LINK_RATE_UNKNOWN;
- }
-}
-
-static bool decide_fallback_link_setting_max_bw_policy(
- struct dc_link *link,
- const struct dc_link_settings *max,
- struct dc_link_settings *cur,
- enum link_training_result training_result)
-{
- uint8_t cur_idx = 0, next_idx;
- bool found = false;
-
- if (training_result == LINK_TRAINING_ABORT)
- return false;
-
- while (cur_idx < ARRAY_SIZE(dp_lt_fallbacks))
- /* find current index */
- if (dp_lt_fallbacks[cur_idx].lane_count == cur->lane_count &&
- dp_lt_fallbacks[cur_idx].link_rate == cur->link_rate)
- break;
- else
- cur_idx++;
-
- next_idx = cur_idx + 1;
-
- while (next_idx < ARRAY_SIZE(dp_lt_fallbacks))
- /* find next index */
- if (dp_lt_fallbacks[next_idx].lane_count > max->lane_count ||
- dp_lt_fallbacks[next_idx].link_rate > max->link_rate)
- next_idx++;
- else if (dp_lt_fallbacks[next_idx].link_rate == LINK_RATE_UHBR13_5 &&
- link->dpcd_caps.dp_128b_132b_supported_link_rates.bits.UHBR13_5 == 0)
- /* upto DP2.x specs UHBR13.5 is the only link rate that
- * could be not supported by DPRX when higher link rate
- * is supported. so we treat it as a special case for
- * code simplicity. When we have new specs with more
- * link rates like this, we should consider a more
- * generic solution to handle discrete link rate
- * capabilities.
- */
- next_idx++;
- else
- break;
-
- if (next_idx < ARRAY_SIZE(dp_lt_fallbacks)) {
- cur->lane_count = dp_lt_fallbacks[next_idx].lane_count;
- cur->link_rate = dp_lt_fallbacks[next_idx].link_rate;
- found = true;
- }
-
- return found;
-}
-
-/*
- * function: set link rate and lane count fallback based
- * on current link setting and last link training result
- * return value:
- * true - link setting could be set
- * false - has reached minimum setting
- * and no further fallback could be done
- */
-static bool decide_fallback_link_setting(
- struct dc_link *link,
- struct dc_link_settings *max,
- struct dc_link_settings *cur,
- enum link_training_result training_result)
-{
- if (dp_get_link_encoding_format(max) == DP_128b_132b_ENCODING ||
- link->dc->debug.force_dp2_lt_fallback_method)
- return decide_fallback_link_setting_max_bw_policy(link, max, cur,
- training_result);
-
- switch (training_result) {
- case LINK_TRAINING_CR_FAIL_LANE0:
- case LINK_TRAINING_CR_FAIL_LANE1:
- case LINK_TRAINING_CR_FAIL_LANE23:
- case LINK_TRAINING_LQA_FAIL:
- {
- if (!reached_minimum_link_rate(cur->link_rate)) {
- cur->link_rate = reduce_link_rate(cur->link_rate);
- } else if (!reached_minimum_lane_count(cur->lane_count)) {
- cur->link_rate = max->link_rate;
- if (training_result == LINK_TRAINING_CR_FAIL_LANE0)
- return false;
- else if (training_result == LINK_TRAINING_CR_FAIL_LANE1)
- cur->lane_count = LANE_COUNT_ONE;
- else if (training_result == LINK_TRAINING_CR_FAIL_LANE23)
- cur->lane_count = LANE_COUNT_TWO;
- else
- cur->lane_count = reduce_lane_count(cur->lane_count);
- } else {
- return false;
- }
- break;
- }
- case LINK_TRAINING_EQ_FAIL_EQ:
- case LINK_TRAINING_EQ_FAIL_CR_PARTIAL:
- {
- if (!reached_minimum_lane_count(cur->lane_count)) {
- cur->lane_count = reduce_lane_count(cur->lane_count);
- } else if (!reached_minimum_link_rate(cur->link_rate)) {
- cur->link_rate = reduce_link_rate(cur->link_rate);
- /* Reduce max link rate to avoid potential infinite loop.
- * Needed so that any subsequent CR_FAIL fallback can't
- * re-set the link rate higher than the link rate from
- * the latest EQ_FAIL fallback.
- */
- max->link_rate = cur->link_rate;
- cur->lane_count = max->lane_count;
- } else {
- return false;
- }
- break;
- }
- case LINK_TRAINING_EQ_FAIL_CR:
- {
- if (!reached_minimum_link_rate(cur->link_rate)) {
- cur->link_rate = reduce_link_rate(cur->link_rate);
- /* Reduce max link rate to avoid potential infinite loop.
- * Needed so that any subsequent CR_FAIL fallback can't
- * re-set the link rate higher than the link rate from
- * the latest EQ_FAIL fallback.
- */
- max->link_rate = cur->link_rate;
- cur->lane_count = max->lane_count;
- } else {
- return false;
- }
- break;
- }
- default:
- return false;
- }
- return true;
-}
-
-bool dp_validate_mode_timing(
- struct dc_link *link,
- const struct dc_crtc_timing *timing)
-{
- uint32_t req_bw;
- uint32_t max_bw;
-
- const struct dc_link_settings *link_setting;
-
- /* According to spec, VSC SDP should be used if pixel format is YCbCr420 */
- if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420 &&
- !link->dpcd_caps.dprx_feature.bits.VSC_SDP_COLORIMETRY_SUPPORTED &&
- dal_graphics_object_id_get_connector_id(link->link_id) != CONNECTOR_ID_VIRTUAL)
- return false;
-
- /*always DP fail safe mode*/
- if ((timing->pix_clk_100hz / 10) == (uint32_t) 25175 &&
- timing->h_addressable == (uint32_t) 640 &&
- timing->v_addressable == (uint32_t) 480)
- return true;
-
- link_setting = dc_link_get_link_cap(link);
-
- /* TODO: DYNAMIC_VALIDATION needs to be implemented */
- /*if (flags.DYNAMIC_VALIDATION == 1 &&
- link->verified_link_cap.lane_count != LANE_COUNT_UNKNOWN)
- link_setting = &link->verified_link_cap;
- */
-
- req_bw = dc_bandwidth_in_kbps_from_timing(timing);
- max_bw = dc_link_bandwidth_kbps(link, link_setting);
-
- if (req_bw <= max_bw) {
- /* remember the biggest mode here, during
- * initial link training (to get
- * verified_link_cap), LS sends event about
- * cannot train at reported cap to upper
- * layer and upper layer will re-enumerate modes.
- * this is not necessary if the lower
- * verified_link_cap is enough to drive
- * all the modes */
-
- /* TODO: DYNAMIC_VALIDATION needs to be implemented */
- /* if (flags.DYNAMIC_VALIDATION == 1)
- dpsst->max_req_bw_for_verified_linkcap = dal_max(
- dpsst->max_req_bw_for_verified_linkcap, req_bw); */
- return true;
- } else
- return false;
-}
-
-static bool decide_dp_link_settings(struct dc_link *link, struct dc_link_settings *link_setting, uint32_t req_bw)
-{
- struct dc_link_settings initial_link_setting = {
- LANE_COUNT_ONE, LINK_RATE_LOW, LINK_SPREAD_DISABLED, false, 0};
- struct dc_link_settings current_link_setting =
- initial_link_setting;
- uint32_t link_bw;
-
- if (req_bw > dc_link_bandwidth_kbps(link, &link->verified_link_cap))
- return false;
-
- /* search for the minimum link setting that:
- * 1. is supported according to the link training result
- * 2. could support the b/w requested by the timing
- */
- while (current_link_setting.link_rate <=
- link->verified_link_cap.link_rate) {
- link_bw = dc_link_bandwidth_kbps(
- link,
- &current_link_setting);
- if (req_bw <= link_bw) {
- *link_setting = current_link_setting;
- return true;
- }
-
- if (current_link_setting.lane_count <
- link->verified_link_cap.lane_count) {
- current_link_setting.lane_count =
- increase_lane_count(
- current_link_setting.lane_count);
- } else {
- current_link_setting.link_rate =
- increase_link_rate(link,
- current_link_setting.link_rate);
- current_link_setting.lane_count =
- initial_link_setting.lane_count;
- }
- }
-
- return false;
-}
-
-bool decide_edp_link_settings(struct dc_link *link, struct dc_link_settings *link_setting, uint32_t req_bw)
-{
- struct dc_link_settings initial_link_setting;
- struct dc_link_settings current_link_setting;
- uint32_t link_bw;
-
- /*
- * edp_supported_link_rates_count is only valid for eDP v1.4 or higher.
- * Per VESA eDP spec, "The DPCD revision for eDP v1.4 is 13h"
- */
- if (link->dpcd_caps.dpcd_rev.raw < DPCD_REV_13 ||
- link->dpcd_caps.edp_supported_link_rates_count == 0) {
- *link_setting = link->verified_link_cap;
- return true;
- }
-
- memset(&initial_link_setting, 0, sizeof(initial_link_setting));
- initial_link_setting.lane_count = LANE_COUNT_ONE;
- initial_link_setting.link_rate = link->dpcd_caps.edp_supported_link_rates[0];
- initial_link_setting.link_spread = LINK_SPREAD_DISABLED;
- initial_link_setting.use_link_rate_set = true;
- initial_link_setting.link_rate_set = 0;
- current_link_setting = initial_link_setting;
-
- /* search for the minimum link setting that:
- * 1. is supported according to the link training result
- * 2. could support the b/w requested by the timing
- */
- while (current_link_setting.link_rate <=
- link->verified_link_cap.link_rate) {
- link_bw = dc_link_bandwidth_kbps(
- link,
- &current_link_setting);
- if (req_bw <= link_bw) {
- *link_setting = current_link_setting;
- return true;
- }
-
- if (current_link_setting.lane_count <
- link->verified_link_cap.lane_count) {
- current_link_setting.lane_count =
- increase_lane_count(
- current_link_setting.lane_count);
- } else {
- if (current_link_setting.link_rate_set < link->dpcd_caps.edp_supported_link_rates_count) {
- current_link_setting.link_rate_set++;
- current_link_setting.link_rate =
- link->dpcd_caps.edp_supported_link_rates[current_link_setting.link_rate_set];
- current_link_setting.lane_count =
- initial_link_setting.lane_count;
- } else
- break;
- }
- }
- return false;
-}
-
-static bool decide_edp_link_settings_with_dsc(struct dc_link *link,
- struct dc_link_settings *link_setting,
- uint32_t req_bw,
- enum dc_link_rate max_link_rate)
-{
- struct dc_link_settings initial_link_setting;
- struct dc_link_settings current_link_setting;
- uint32_t link_bw;
-
- unsigned int policy = 0;
-
- policy = link->panel_config.dsc.force_dsc_edp_policy;
- if (max_link_rate == LINK_RATE_UNKNOWN)
- max_link_rate = link->verified_link_cap.link_rate;
- /*
- * edp_supported_link_rates_count is only valid for eDP v1.4 or higher.
- * Per VESA eDP spec, "The DPCD revision for eDP v1.4 is 13h"
- */
- if ((link->dpcd_caps.dpcd_rev.raw < DPCD_REV_13 ||
- link->dpcd_caps.edp_supported_link_rates_count == 0)) {
- /* for DSC enabled case, we search for minimum lane count */
- memset(&initial_link_setting, 0, sizeof(initial_link_setting));
- initial_link_setting.lane_count = LANE_COUNT_ONE;
- initial_link_setting.link_rate = LINK_RATE_LOW;
- initial_link_setting.link_spread = LINK_SPREAD_DISABLED;
- initial_link_setting.use_link_rate_set = false;
- initial_link_setting.link_rate_set = 0;
- current_link_setting = initial_link_setting;
- if (req_bw > dc_link_bandwidth_kbps(link, &link->verified_link_cap))
- return false;
-
- /* search for the minimum link setting that:
- * 1. is supported according to the link training result
- * 2. could support the b/w requested by the timing
- */
- while (current_link_setting.link_rate <=
- max_link_rate) {
- link_bw = dc_link_bandwidth_kbps(
- link,
- &current_link_setting);
- if (req_bw <= link_bw) {
- *link_setting = current_link_setting;
- return true;
- }
- if (policy) {
- /* minimize lane */
- if (current_link_setting.link_rate < max_link_rate) {
- current_link_setting.link_rate =
- increase_link_rate(link,
- current_link_setting.link_rate);
- } else {
- if (current_link_setting.lane_count <
- link->verified_link_cap.lane_count) {
- current_link_setting.lane_count =
- increase_lane_count(
- current_link_setting.lane_count);
- current_link_setting.link_rate = initial_link_setting.link_rate;
- } else
- break;
- }
- } else {
- /* minimize link rate */
- if (current_link_setting.lane_count <
- link->verified_link_cap.lane_count) {
- current_link_setting.lane_count =
- increase_lane_count(
- current_link_setting.lane_count);
- } else {
- current_link_setting.link_rate =
- increase_link_rate(link,
- current_link_setting.link_rate);
- current_link_setting.lane_count =
- initial_link_setting.lane_count;
- }
- }
- }
- return false;
- }
-
- /* if optimize edp link is supported */
- memset(&initial_link_setting, 0, sizeof(initial_link_setting));
- initial_link_setting.lane_count = LANE_COUNT_ONE;
- initial_link_setting.link_rate = link->dpcd_caps.edp_supported_link_rates[0];
- initial_link_setting.link_spread = LINK_SPREAD_DISABLED;
- initial_link_setting.use_link_rate_set = true;
- initial_link_setting.link_rate_set = 0;
- current_link_setting = initial_link_setting;
-
- /* search for the minimum link setting that:
- * 1. is supported according to the link training result
- * 2. could support the b/w requested by the timing
- */
- while (current_link_setting.link_rate <=
- max_link_rate) {
- link_bw = dc_link_bandwidth_kbps(
- link,
- &current_link_setting);
- if (req_bw <= link_bw) {
- *link_setting = current_link_setting;
- return true;
- }
- if (policy) {
- /* minimize lane */
- if (current_link_setting.link_rate_set <
- link->dpcd_caps.edp_supported_link_rates_count
- && current_link_setting.link_rate < max_link_rate) {
- current_link_setting.link_rate_set++;
- current_link_setting.link_rate =
- link->dpcd_caps.edp_supported_link_rates[current_link_setting.link_rate_set];
- } else {
- if (current_link_setting.lane_count < link->verified_link_cap.lane_count) {
- current_link_setting.lane_count =
- increase_lane_count(
- current_link_setting.lane_count);
- current_link_setting.link_rate_set = initial_link_setting.link_rate_set;
- current_link_setting.link_rate =
- link->dpcd_caps.edp_supported_link_rates[current_link_setting.link_rate_set];
- } else
- break;
- }
- } else {
- /* minimize link rate */
- if (current_link_setting.lane_count <
- link->verified_link_cap.lane_count) {
- current_link_setting.lane_count =
- increase_lane_count(
- current_link_setting.lane_count);
- } else {
- if (current_link_setting.link_rate_set < link->dpcd_caps.edp_supported_link_rates_count) {
- current_link_setting.link_rate_set++;
- current_link_setting.link_rate =
- link->dpcd_caps.edp_supported_link_rates[current_link_setting.link_rate_set];
- current_link_setting.lane_count =
- initial_link_setting.lane_count;
- } else
- break;
- }
- }
- }
- return false;
-}
-
-static bool decide_mst_link_settings(const struct dc_link *link, struct dc_link_settings *link_setting)
-{
- *link_setting = link->verified_link_cap;
- return true;
-}
-
-bool decide_link_settings(struct dc_stream_state *stream,
- struct dc_link_settings *link_setting)
-{
- struct dc_link *link = stream->link;
- uint32_t req_bw = dc_bandwidth_in_kbps_from_timing(&stream->timing);
-
- memset(link_setting, 0, sizeof(*link_setting));
-
- /* if preferred is specified through AMDDP, use it, if it's enough
- * to drive the mode
- */
- if (link->preferred_link_setting.lane_count !=
- LANE_COUNT_UNKNOWN &&
- link->preferred_link_setting.link_rate !=
- LINK_RATE_UNKNOWN) {
- *link_setting = link->preferred_link_setting;
- return true;
- }
-
- /* MST doesn't perform link training for now
- * TODO: add MST specific link training routine
- */
- if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
- decide_mst_link_settings(link, link_setting);
- } else if (link->connector_signal == SIGNAL_TYPE_EDP) {
- /* enable edp link optimization for DSC eDP case */
- if (stream->timing.flags.DSC) {
- enum dc_link_rate max_link_rate = LINK_RATE_UNKNOWN;
-
- if (link->panel_config.dsc.force_dsc_edp_policy) {
- /* calculate link max link rate cap*/
- struct dc_link_settings tmp_link_setting;
- struct dc_crtc_timing tmp_timing = stream->timing;
- uint32_t orig_req_bw;
-
- tmp_link_setting.link_rate = LINK_RATE_UNKNOWN;
- tmp_timing.flags.DSC = 0;
- orig_req_bw = dc_bandwidth_in_kbps_from_timing(&tmp_timing);
- decide_edp_link_settings(link, &tmp_link_setting, orig_req_bw);
- max_link_rate = tmp_link_setting.link_rate;
- }
- decide_edp_link_settings_with_dsc(link, link_setting, req_bw, max_link_rate);
- } else {
- decide_edp_link_settings(link, link_setting, req_bw);
- }
- } else {
- decide_dp_link_settings(link, link_setting, req_bw);
- }
-
- return link_setting->lane_count != LANE_COUNT_UNKNOWN &&
- link_setting->link_rate != LINK_RATE_UNKNOWN;
-}
-
-/*************************Short Pulse IRQ***************************/
-bool dc_link_dp_allow_hpd_rx_irq(const struct dc_link *link)
-{
- /*
- * Don't handle RX IRQ unless one of following is met:
- * 1) The link is established (cur_link_settings != unknown)
- * 2) We know we're dealing with a branch device, SST or MST
- */
-
- if ((link->cur_link_settings.lane_count != LANE_COUNT_UNKNOWN) ||
- is_dp_branch_device(link))
- return true;
-
- return false;
-}
-
-static bool handle_hpd_irq_psr_sink(struct dc_link *link)
-{
- union dpcd_psr_configuration psr_configuration;
-
- if (!link->psr_settings.psr_feature_enabled)
- return false;
-
- dm_helpers_dp_read_dpcd(
- link->ctx,
- link,
- 368,/*DpcdAddress_PSR_Enable_Cfg*/
- &psr_configuration.raw,
- sizeof(psr_configuration.raw));
-
- if (psr_configuration.bits.ENABLE) {
- unsigned char dpcdbuf[3] = {0};
- union psr_error_status psr_error_status;
- union psr_sink_psr_status psr_sink_psr_status;
-
- dm_helpers_dp_read_dpcd(
- link->ctx,
- link,
- 0x2006, /*DpcdAddress_PSR_Error_Status*/
- (unsigned char *) dpcdbuf,
- sizeof(dpcdbuf));
-
- /*DPCD 2006h ERROR STATUS*/
- psr_error_status.raw = dpcdbuf[0];
- /*DPCD 2008h SINK PANEL SELF REFRESH STATUS*/
- psr_sink_psr_status.raw = dpcdbuf[2];
-
- if (psr_error_status.bits.LINK_CRC_ERROR ||
- psr_error_status.bits.RFB_STORAGE_ERROR ||
- psr_error_status.bits.VSC_SDP_ERROR) {
- bool allow_active;
-
- /* Acknowledge and clear error bits */
- dm_helpers_dp_write_dpcd(
- link->ctx,
- link,
- 8198,/*DpcdAddress_PSR_Error_Status*/
- &psr_error_status.raw,
- sizeof(psr_error_status.raw));
-
- /* PSR error, disable and re-enable PSR */
- if (link->psr_settings.psr_allow_active) {
- allow_active = false;
- dc_link_set_psr_allow_active(link, &allow_active, true, false, NULL);
- allow_active = true;
- dc_link_set_psr_allow_active(link, &allow_active, true, false, NULL);
- }
-
- return true;
- } else if (psr_sink_psr_status.bits.SINK_SELF_REFRESH_STATUS ==
- PSR_SINK_STATE_ACTIVE_DISPLAY_FROM_SINK_RFB){
- /* No error is detect, PSR is active.
- * We should return with IRQ_HPD handled without
- * checking for loss of sync since PSR would have
- * powered down main link.
- */
- return true;
- }
- }
- return false;
-}
-
-static enum dc_link_rate get_link_rate_from_test_link_rate(uint8_t test_rate)
-{
- switch (test_rate) {
- case DP_TEST_LINK_RATE_RBR:
- return LINK_RATE_LOW;
- case DP_TEST_LINK_RATE_HBR:
- return LINK_RATE_HIGH;
- case DP_TEST_LINK_RATE_HBR2:
- return LINK_RATE_HIGH2;
- case DP_TEST_LINK_RATE_HBR3:
- return LINK_RATE_HIGH3;
- case DP_TEST_LINK_RATE_UHBR10:
- return LINK_RATE_UHBR10;
- case DP_TEST_LINK_RATE_UHBR20:
- return LINK_RATE_UHBR20;
- case DP_TEST_LINK_RATE_UHBR13_5:
- return LINK_RATE_UHBR13_5;
- default:
- return LINK_RATE_UNKNOWN;
- }
-}
-
-static void dp_test_send_link_training(struct dc_link *link)
-{
- struct dc_link_settings link_settings = {0};
- uint8_t test_rate = 0;
-
- core_link_read_dpcd(
- link,
- DP_TEST_LANE_COUNT,
- (unsigned char *)(&link_settings.lane_count),
- 1);
- core_link_read_dpcd(
- link,
- DP_TEST_LINK_RATE,
- &test_rate,
- 1);
- link_settings.link_rate = get_link_rate_from_test_link_rate(test_rate);
-
- /* Set preferred link settings */
- link->verified_link_cap.lane_count = link_settings.lane_count;
- link->verified_link_cap.link_rate = link_settings.link_rate;
-
- dp_retrain_link_dp_test(link, &link_settings, false);
-}
-
-/* TODO Raven hbr2 compliance eye output is unstable
- * (toggling on and off) with debugger break
- * This caueses intermittent PHY automation failure
- * Need to look into the root cause */
-static void dp_test_send_phy_test_pattern(struct dc_link *link)
-{
- union phy_test_pattern dpcd_test_pattern;
- union lane_adjust dpcd_lane_adjustment[2];
- unsigned char dpcd_post_cursor_2_adjustment = 0;
- unsigned char test_pattern_buffer[
- (DP_TEST_264BIT_CUSTOM_PATTERN_263_256 -
- DP_TEST_264BIT_CUSTOM_PATTERN_7_0)+1] = {0};
- unsigned int test_pattern_size = 0;
- enum dp_test_pattern test_pattern;
- union lane_adjust dpcd_lane_adjust;
- unsigned int lane;
- struct link_training_settings link_training_settings;
-
- dpcd_test_pattern.raw = 0;
- memset(dpcd_lane_adjustment, 0, sizeof(dpcd_lane_adjustment));
- memset(&link_training_settings, 0, sizeof(link_training_settings));
-
- /* get phy test pattern and pattern parameters from DP receiver */
- core_link_read_dpcd(
- link,
- DP_PHY_TEST_PATTERN,
- &dpcd_test_pattern.raw,
- sizeof(dpcd_test_pattern));
- core_link_read_dpcd(
- link,
- DP_ADJUST_REQUEST_LANE0_1,
- &dpcd_lane_adjustment[0].raw,
- sizeof(dpcd_lane_adjustment));
-
- /* prepare link training settings */
- link_training_settings.link_settings = link->cur_link_settings;
-
- link_training_settings.lttpr_mode = dp_decide_lttpr_mode(link, &link->cur_link_settings);
-
- if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) &&
- link_training_settings.lttpr_mode == LTTPR_MODE_TRANSPARENT)
- dp_fixed_vs_pe_read_lane_adjust(
- link,
- link_training_settings.dpcd_lane_settings);
-
- /*get post cursor 2 parameters
- * For DP 1.1a or eariler, this DPCD register's value is 0
- * For DP 1.2 or later:
- * Bits 1:0 = POST_CURSOR2_LANE0; Bits 3:2 = POST_CURSOR2_LANE1
- * Bits 5:4 = POST_CURSOR2_LANE2; Bits 7:6 = POST_CURSOR2_LANE3
- */
- core_link_read_dpcd(
- link,
- DP_ADJUST_REQUEST_POST_CURSOR2,
- &dpcd_post_cursor_2_adjustment,
- sizeof(dpcd_post_cursor_2_adjustment));
-
- /* translate request */
- switch (dpcd_test_pattern.bits.PATTERN) {
- case PHY_TEST_PATTERN_D10_2:
- test_pattern = DP_TEST_PATTERN_D102;
- break;
- case PHY_TEST_PATTERN_SYMBOL_ERROR:
- test_pattern = DP_TEST_PATTERN_SYMBOL_ERROR;
- break;
- case PHY_TEST_PATTERN_PRBS7:
- test_pattern = DP_TEST_PATTERN_PRBS7;
- break;
- case PHY_TEST_PATTERN_80BIT_CUSTOM:
- test_pattern = DP_TEST_PATTERN_80BIT_CUSTOM;
- break;
- case PHY_TEST_PATTERN_CP2520_1:
- /* CP2520 pattern is unstable, temporarily use TPS4 instead */
- test_pattern = (link->dc->caps.force_dp_tps4_for_cp2520 == 1) ?
- DP_TEST_PATTERN_TRAINING_PATTERN4 :
- DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE;
- break;
- case PHY_TEST_PATTERN_CP2520_2:
- /* CP2520 pattern is unstable, temporarily use TPS4 instead */
- test_pattern = (link->dc->caps.force_dp_tps4_for_cp2520 == 1) ?
- DP_TEST_PATTERN_TRAINING_PATTERN4 :
- DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE;
- break;
- case PHY_TEST_PATTERN_CP2520_3:
- test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN4;
- break;
- case PHY_TEST_PATTERN_128b_132b_TPS1:
- test_pattern = DP_TEST_PATTERN_128b_132b_TPS1;
- break;
- case PHY_TEST_PATTERN_128b_132b_TPS2:
- test_pattern = DP_TEST_PATTERN_128b_132b_TPS2;
- break;
- case PHY_TEST_PATTERN_PRBS9:
- test_pattern = DP_TEST_PATTERN_PRBS9;
- break;
- case PHY_TEST_PATTERN_PRBS11:
- test_pattern = DP_TEST_PATTERN_PRBS11;
- break;
- case PHY_TEST_PATTERN_PRBS15:
- test_pattern = DP_TEST_PATTERN_PRBS15;
- break;
- case PHY_TEST_PATTERN_PRBS23:
- test_pattern = DP_TEST_PATTERN_PRBS23;
- break;
- case PHY_TEST_PATTERN_PRBS31:
- test_pattern = DP_TEST_PATTERN_PRBS31;
- break;
- case PHY_TEST_PATTERN_264BIT_CUSTOM:
- test_pattern = DP_TEST_PATTERN_264BIT_CUSTOM;
- break;
- case PHY_TEST_PATTERN_SQUARE_PULSE:
- test_pattern = DP_TEST_PATTERN_SQUARE_PULSE;
- break;
- default:
- test_pattern = DP_TEST_PATTERN_VIDEO_MODE;
- break;
- }
-
- if (test_pattern == DP_TEST_PATTERN_80BIT_CUSTOM) {
- test_pattern_size = (DP_TEST_80BIT_CUSTOM_PATTERN_79_72 -
- DP_TEST_80BIT_CUSTOM_PATTERN_7_0) + 1;
- core_link_read_dpcd(
- link,
- DP_TEST_80BIT_CUSTOM_PATTERN_7_0,
- test_pattern_buffer,
- test_pattern_size);
- }
-
- if (test_pattern == DP_TEST_PATTERN_SQUARE_PULSE) {
- test_pattern_size = 1; // Square pattern data is 1 byte (DP spec)
- core_link_read_dpcd(
- link,
- DP_PHY_SQUARE_PATTERN,
- test_pattern_buffer,
- test_pattern_size);
- }
-
- if (test_pattern == DP_TEST_PATTERN_264BIT_CUSTOM) {
- test_pattern_size = (DP_TEST_264BIT_CUSTOM_PATTERN_263_256-
- DP_TEST_264BIT_CUSTOM_PATTERN_7_0) + 1;
- core_link_read_dpcd(
- link,
- DP_TEST_264BIT_CUSTOM_PATTERN_7_0,
- test_pattern_buffer,
- test_pattern_size);
- }
-
- for (lane = 0; lane <
- (unsigned int)(link->cur_link_settings.lane_count);
- lane++) {
- dpcd_lane_adjust.raw =
- get_nibble_at_index(&dpcd_lane_adjustment[0].raw, lane);
- if (dp_get_link_encoding_format(&link->cur_link_settings) ==
- DP_8b_10b_ENCODING) {
- link_training_settings.hw_lane_settings[lane].VOLTAGE_SWING =
- (enum dc_voltage_swing)
- (dpcd_lane_adjust.bits.VOLTAGE_SWING_LANE);
- link_training_settings.hw_lane_settings[lane].PRE_EMPHASIS =
- (enum dc_pre_emphasis)
- (dpcd_lane_adjust.bits.PRE_EMPHASIS_LANE);
- link_training_settings.hw_lane_settings[lane].POST_CURSOR2 =
- (enum dc_post_cursor2)
- ((dpcd_post_cursor_2_adjustment >> (lane * 2)) & 0x03);
- } else if (dp_get_link_encoding_format(&link->cur_link_settings) ==
- DP_128b_132b_ENCODING) {
- link_training_settings.hw_lane_settings[lane].FFE_PRESET.raw =
- dpcd_lane_adjust.tx_ffe.PRESET_VALUE;
- }
- }
-
- dp_hw_to_dpcd_lane_settings(&link_training_settings,
- link_training_settings.hw_lane_settings,
- link_training_settings.dpcd_lane_settings);
- /*Usage: Measure DP physical lane signal
- * by DP SI test equipment automatically.
- * PHY test pattern request is generated by equipment via HPD interrupt.
- * HPD needs to be active all the time. HPD should be active
- * all the time. Do not touch it.
- * forward request to DS
- */
- dc_link_dp_set_test_pattern(
- link,
- test_pattern,
- DP_TEST_PATTERN_COLOR_SPACE_UNDEFINED,
- &link_training_settings,
- test_pattern_buffer,
- test_pattern_size);
-}
-
-static void dp_test_send_link_test_pattern(struct dc_link *link)
-{
- union link_test_pattern dpcd_test_pattern;
- union test_misc dpcd_test_params;
- enum dp_test_pattern test_pattern;
- enum dp_test_pattern_color_space test_pattern_color_space =
- DP_TEST_PATTERN_COLOR_SPACE_UNDEFINED;
- enum dc_color_depth requestColorDepth = COLOR_DEPTH_UNDEFINED;
- struct pipe_ctx *pipes = link->dc->current_state->res_ctx.pipe_ctx;
- struct pipe_ctx *pipe_ctx = NULL;
- int i;
-
- memset(&dpcd_test_pattern, 0, sizeof(dpcd_test_pattern));
- memset(&dpcd_test_params, 0, sizeof(dpcd_test_params));
-
- for (i = 0; i < MAX_PIPES; i++) {
- if (pipes[i].stream == NULL)
- continue;
-
- if (pipes[i].stream->link == link && !pipes[i].top_pipe && !pipes[i].prev_odm_pipe) {
- pipe_ctx = &pipes[i];
- break;
- }
- }
-
- if (pipe_ctx == NULL)
- return;
-
- /* get link test pattern and pattern parameters */
- core_link_read_dpcd(
- link,
- DP_TEST_PATTERN,
- &dpcd_test_pattern.raw,
- sizeof(dpcd_test_pattern));
- core_link_read_dpcd(
- link,
- DP_TEST_MISC0,
- &dpcd_test_params.raw,
- sizeof(dpcd_test_params));
-
- switch (dpcd_test_pattern.bits.PATTERN) {
- case LINK_TEST_PATTERN_COLOR_RAMP:
- test_pattern = DP_TEST_PATTERN_COLOR_RAMP;
- break;
- case LINK_TEST_PATTERN_VERTICAL_BARS:
- test_pattern = DP_TEST_PATTERN_VERTICAL_BARS;
- break; /* black and white */
- case LINK_TEST_PATTERN_COLOR_SQUARES:
- test_pattern = (dpcd_test_params.bits.DYN_RANGE ==
- TEST_DYN_RANGE_VESA ?
- DP_TEST_PATTERN_COLOR_SQUARES :
- DP_TEST_PATTERN_COLOR_SQUARES_CEA);
- break;
- default:
- test_pattern = DP_TEST_PATTERN_VIDEO_MODE;
- break;
- }
-
- if (dpcd_test_params.bits.CLR_FORMAT == 0)
- test_pattern_color_space = DP_TEST_PATTERN_COLOR_SPACE_RGB;
- else
- test_pattern_color_space = dpcd_test_params.bits.YCBCR_COEFS ?
- DP_TEST_PATTERN_COLOR_SPACE_YCBCR709 :
- DP_TEST_PATTERN_COLOR_SPACE_YCBCR601;
-
- switch (dpcd_test_params.bits.BPC) {
- case 0: // 6 bits
- requestColorDepth = COLOR_DEPTH_666;
- break;
- case 1: // 8 bits
- requestColorDepth = COLOR_DEPTH_888;
- break;
- case 2: // 10 bits
- requestColorDepth = COLOR_DEPTH_101010;
- break;
- case 3: // 12 bits
- requestColorDepth = COLOR_DEPTH_121212;
- break;
- default:
- break;
- }
-
- switch (dpcd_test_params.bits.CLR_FORMAT) {
- case 0:
- pipe_ctx->stream->timing.pixel_encoding = PIXEL_ENCODING_RGB;
- break;
- case 1:
- pipe_ctx->stream->timing.pixel_encoding = PIXEL_ENCODING_YCBCR422;
- break;
- case 2:
- pipe_ctx->stream->timing.pixel_encoding = PIXEL_ENCODING_YCBCR444;
- break;
- default:
- pipe_ctx->stream->timing.pixel_encoding = PIXEL_ENCODING_RGB;
- break;
- }
-
-
- if (requestColorDepth != COLOR_DEPTH_UNDEFINED
- && pipe_ctx->stream->timing.display_color_depth != requestColorDepth) {
- DC_LOG_DEBUG("%s: original bpc %d, changing to %d\n",
- __func__,
- pipe_ctx->stream->timing.display_color_depth,
- requestColorDepth);
- pipe_ctx->stream->timing.display_color_depth = requestColorDepth;
- }
-
- dp_update_dsc_config(pipe_ctx);
-
- dc_link_dp_set_test_pattern(
- link,
- test_pattern,
- test_pattern_color_space,
- NULL,
- NULL,
- 0);
-}
-
-static void dp_test_get_audio_test_data(struct dc_link *link, bool disable_video)
-{
- union audio_test_mode dpcd_test_mode = {0};
- struct audio_test_pattern_type dpcd_pattern_type = {0};
- union audio_test_pattern_period dpcd_pattern_period[AUDIO_CHANNELS_COUNT] = {0};
- enum dp_test_pattern test_pattern = DP_TEST_PATTERN_AUDIO_OPERATOR_DEFINED;
-
- struct pipe_ctx *pipes = link->dc->current_state->res_ctx.pipe_ctx;
- struct pipe_ctx *pipe_ctx = &pipes[0];
- unsigned int channel_count;
- unsigned int channel = 0;
- unsigned int modes = 0;
- unsigned int sampling_rate_in_hz = 0;
-
- // get audio test mode and test pattern parameters
- core_link_read_dpcd(
- link,
- DP_TEST_AUDIO_MODE,
- &dpcd_test_mode.raw,
- sizeof(dpcd_test_mode));
-
- core_link_read_dpcd(
- link,
- DP_TEST_AUDIO_PATTERN_TYPE,
- &dpcd_pattern_type.value,
- sizeof(dpcd_pattern_type));
-
- channel_count = min(dpcd_test_mode.bits.channel_count + 1, AUDIO_CHANNELS_COUNT);
-
- // read pattern periods for requested channels when sawTooth pattern is requested
- if (dpcd_pattern_type.value == AUDIO_TEST_PATTERN_SAWTOOTH ||
- dpcd_pattern_type.value == AUDIO_TEST_PATTERN_OPERATOR_DEFINED) {
-
- test_pattern = (dpcd_pattern_type.value == AUDIO_TEST_PATTERN_SAWTOOTH) ?
- DP_TEST_PATTERN_AUDIO_SAWTOOTH : DP_TEST_PATTERN_AUDIO_OPERATOR_DEFINED;
- // read period for each channel
- for (channel = 0; channel < channel_count; channel++) {
- core_link_read_dpcd(
- link,
- DP_TEST_AUDIO_PERIOD_CH1 + channel,
- &dpcd_pattern_period[channel].raw,
- sizeof(dpcd_pattern_period[channel]));
- }
- }
-
- // translate sampling rate
- switch (dpcd_test_mode.bits.sampling_rate) {
- case AUDIO_SAMPLING_RATE_32KHZ:
- sampling_rate_in_hz = 32000;
- break;
- case AUDIO_SAMPLING_RATE_44_1KHZ:
- sampling_rate_in_hz = 44100;
- break;
- case AUDIO_SAMPLING_RATE_48KHZ:
- sampling_rate_in_hz = 48000;
- break;
- case AUDIO_SAMPLING_RATE_88_2KHZ:
- sampling_rate_in_hz = 88200;
- break;
- case AUDIO_SAMPLING_RATE_96KHZ:
- sampling_rate_in_hz = 96000;
- break;
- case AUDIO_SAMPLING_RATE_176_4KHZ:
- sampling_rate_in_hz = 176400;
- break;
- case AUDIO_SAMPLING_RATE_192KHZ:
- sampling_rate_in_hz = 192000;
- break;
- default:
- sampling_rate_in_hz = 0;
- break;
- }
-
- link->audio_test_data.flags.test_requested = 1;
- link->audio_test_data.flags.disable_video = disable_video;
- link->audio_test_data.sampling_rate = sampling_rate_in_hz;
- link->audio_test_data.channel_count = channel_count;
- link->audio_test_data.pattern_type = test_pattern;
-
- if (test_pattern == DP_TEST_PATTERN_AUDIO_SAWTOOTH) {
- for (modes = 0; modes < pipe_ctx->stream->audio_info.mode_count; modes++) {
- link->audio_test_data.pattern_period[modes] = dpcd_pattern_period[modes].bits.pattern_period;
- }
- }
-}
-
-void dc_link_dp_handle_automated_test(struct dc_link *link)
-{
- union test_request test_request;
- union test_response test_response;
-
- memset(&test_request, 0, sizeof(test_request));
- memset(&test_response, 0, sizeof(test_response));
-
- core_link_read_dpcd(
- link,
- DP_TEST_REQUEST,
- &test_request.raw,
- sizeof(union test_request));
- if (test_request.bits.LINK_TRAINING) {
- /* ACK first to let DP RX test box monitor LT sequence */
- test_response.bits.ACK = 1;
- core_link_write_dpcd(
- link,
- DP_TEST_RESPONSE,
- &test_response.raw,
- sizeof(test_response));
- dp_test_send_link_training(link);
- /* no acknowledge request is needed again */
- test_response.bits.ACK = 0;
- }
- if (test_request.bits.LINK_TEST_PATTRN) {
- dp_test_send_link_test_pattern(link);
- test_response.bits.ACK = 1;
- }
-
- if (test_request.bits.AUDIO_TEST_PATTERN) {
- dp_test_get_audio_test_data(link, test_request.bits.TEST_AUDIO_DISABLED_VIDEO);
- test_response.bits.ACK = 1;
- }
-
- if (test_request.bits.PHY_TEST_PATTERN) {
- dp_test_send_phy_test_pattern(link);
- test_response.bits.ACK = 1;
- }
-
- /* send request acknowledgment */
- if (test_response.bits.ACK)
- core_link_write_dpcd(
- link,
- DP_TEST_RESPONSE,
- &test_response.raw,
- sizeof(test_response));
-}
-
-void dc_link_dp_handle_link_loss(struct dc_link *link)
-{
- int i;
- struct pipe_ctx *pipe_ctx;
-
- for (i = 0; i < MAX_PIPES; i++) {
- pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i];
- if (pipe_ctx && pipe_ctx->stream && pipe_ctx->stream->link == link)
- break;
- }
-
- if (pipe_ctx == NULL || pipe_ctx->stream == NULL)
- return;
-
- for (i = 0; i < MAX_PIPES; i++) {
- pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i];
- if (pipe_ctx && pipe_ctx->stream && !pipe_ctx->stream->dpms_off &&
- pipe_ctx->stream->link == link && !pipe_ctx->prev_odm_pipe)
- core_link_disable_stream(pipe_ctx);
- }
-
- for (i = 0; i < MAX_PIPES; i++) {
- pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i];
- if (pipe_ctx && pipe_ctx->stream && !pipe_ctx->stream->dpms_off
- && pipe_ctx->stream->link == link && !pipe_ctx->prev_odm_pipe) {
- // Always use max settings here for DP 1.4a LL Compliance CTS
- if (link->is_automated) {
- pipe_ctx->link_config.dp_link_settings.lane_count =
- link->verified_link_cap.lane_count;
- pipe_ctx->link_config.dp_link_settings.link_rate =
- link->verified_link_cap.link_rate;
- pipe_ctx->link_config.dp_link_settings.link_spread =
- link->verified_link_cap.link_spread;
- }
- core_link_enable_stream(link->dc->current_state, pipe_ctx);
- }
- }
-}
-
-bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd_irq_dpcd_data, bool *out_link_loss,
- bool defer_handling, bool *has_left_work)
-{
- union hpd_irq_data hpd_irq_dpcd_data = {0};
- union device_service_irq device_service_clear = {0};
- enum dc_status result;
- bool status = false;
-
- if (out_link_loss)
- *out_link_loss = false;
-
- if (has_left_work)
- *has_left_work = false;
- /* For use cases related to down stream connection status change,
- * PSR and device auto test, refer to function handle_sst_hpd_irq
- * in DAL2.1*/
-
- DC_LOG_HW_HPD_IRQ("%s: Got short pulse HPD on link %d\n",
- __func__, link->link_index);
-
-
- /* All the "handle_hpd_irq_xxx()" methods
- * should be called only after
- * dal_dpsst_ls_read_hpd_irq_data
- * Order of calls is important too
- */
- result = read_hpd_rx_irq_data(link, &hpd_irq_dpcd_data);
- if (out_hpd_irq_dpcd_data)
- *out_hpd_irq_dpcd_data = hpd_irq_dpcd_data;
-
- if (result != DC_OK) {
- DC_LOG_HW_HPD_IRQ("%s: DPCD read failed to obtain irq data\n",
- __func__);
- return false;
- }
-
- if (hpd_irq_dpcd_data.bytes.device_service_irq.bits.AUTOMATED_TEST) {
- // Workaround for DP 1.4a LL Compliance CTS as USB4 has to share encoders unlike DP and USBC
- link->is_automated = true;
- device_service_clear.bits.AUTOMATED_TEST = 1;
- core_link_write_dpcd(
- link,
- DP_DEVICE_SERVICE_IRQ_VECTOR,
- &device_service_clear.raw,
- sizeof(device_service_clear.raw));
- device_service_clear.raw = 0;
- if (defer_handling && has_left_work)
- *has_left_work = true;
- else
- dc_link_dp_handle_automated_test(link);
- return false;
- }
-
- if (!dc_link_dp_allow_hpd_rx_irq(link)) {
- DC_LOG_HW_HPD_IRQ("%s: skipping HPD handling on %d\n",
- __func__, link->link_index);
- return false;
- }
-
- if (handle_hpd_irq_psr_sink(link))
- /* PSR-related error was detected and handled */
- return true;
-
- /* If PSR-related error handled, Main link may be off,
- * so do not handle as a normal sink status change interrupt.
- */
-
- if (hpd_irq_dpcd_data.bytes.device_service_irq.bits.UP_REQ_MSG_RDY) {
- if (defer_handling && has_left_work)
- *has_left_work = true;
- return true;
- }
-
- /* check if we have MST msg and return since we poll for it */
- if (hpd_irq_dpcd_data.bytes.device_service_irq.bits.DOWN_REP_MSG_RDY) {
- if (defer_handling && has_left_work)
- *has_left_work = true;
- return false;
- }
-
- /* For now we only handle 'Downstream port status' case.
- * If we got sink count changed it means
- * Downstream port status changed,
- * then DM should call DC to do the detection.
- * NOTE: Do not handle link loss on eDP since it is internal link*/
- if ((link->connector_signal != SIGNAL_TYPE_EDP) &&
- hpd_rx_irq_check_link_loss_status(
- link,
- &hpd_irq_dpcd_data)) {
- /* Connectivity log: link loss */
- CONN_DATA_LINK_LOSS(link,
- hpd_irq_dpcd_data.raw,
- sizeof(hpd_irq_dpcd_data),
- "Status: ");
-
- if (defer_handling && has_left_work)
- *has_left_work = true;
- else
- dc_link_dp_handle_link_loss(link);
-
- status = false;
- if (out_link_loss)
- *out_link_loss = true;
-
- dp_trace_link_loss_increment(link);
- }
-
- if (link->type == dc_connection_sst_branch &&
- hpd_irq_dpcd_data.bytes.sink_cnt.bits.SINK_COUNT
- != link->dpcd_sink_count)
- status = true;
-
- /* reasons for HPD RX:
- * 1. Link Loss - ie Re-train the Link
- * 2. MST sideband message
- * 3. Automated Test - ie. Internal Commit
- * 4. CP (copy protection) - (not interesting for DM???)
- * 5. DRR
- * 6. Downstream Port status changed
- * -ie. Detect - this the only one
- * which is interesting for DM because
- * it must call dc_link_detect.
- */
- return status;
-}
-
-/*query dpcd for version and mst cap addresses*/
-bool is_mst_supported(struct dc_link *link)
-{
- bool mst = false;
- enum dc_status st = DC_OK;
- union dpcd_rev rev;
- union mstm_cap cap;
-
- if (link->preferred_training_settings.mst_enable &&
- *link->preferred_training_settings.mst_enable == false) {
- return false;
- }
-
- rev.raw = 0;
- cap.raw = 0;
-
- st = core_link_read_dpcd(link, DP_DPCD_REV, &rev.raw,
- sizeof(rev));
-
- if (st == DC_OK && rev.raw >= DPCD_REV_12) {
-
- st = core_link_read_dpcd(link, DP_MSTM_CAP,
- &cap.raw, sizeof(cap));
- if (st == DC_OK && cap.bits.MST_CAP == 1)
- mst = true;
- }
- return mst;
-
-}
-
-bool is_dp_active_dongle(const struct dc_link *link)
-{
- return (link->dpcd_caps.dongle_type >= DISPLAY_DONGLE_DP_VGA_CONVERTER) &&
- (link->dpcd_caps.dongle_type <= DISPLAY_DONGLE_DP_HDMI_CONVERTER);
-}
-
-bool is_dp_branch_device(const struct dc_link *link)
-{
- return link->dpcd_caps.is_branch_dev;
-}
-
-static int translate_dpcd_max_bpc(enum dpcd_downstream_port_max_bpc bpc)
-{
- switch (bpc) {
- case DOWN_STREAM_MAX_8BPC:
- return 8;
- case DOWN_STREAM_MAX_10BPC:
- return 10;
- case DOWN_STREAM_MAX_12BPC:
- return 12;
- case DOWN_STREAM_MAX_16BPC:
- return 16;
- default:
- break;
- }
-
- return -1;
-}
-
-#if defined(CONFIG_DRM_AMD_DC_DCN)
-uint32_t dc_link_bw_kbps_from_raw_frl_link_rate_data(uint8_t bw)
-{
- switch (bw) {
- case 0b001:
- return 9000000;
- case 0b010:
- return 18000000;
- case 0b011:
- return 24000000;
- case 0b100:
- return 32000000;
- case 0b101:
- return 40000000;
- case 0b110:
- return 48000000;
- }
-
- return 0;
-}
-
-/*
- * Return PCON's post FRL link training supported BW if its non-zero, otherwise return max_supported_frl_bw.
- */
-static uint32_t intersect_frl_link_bw_support(
- const uint32_t max_supported_frl_bw_in_kbps,
- const union hdmi_encoded_link_bw hdmi_encoded_link_bw)
-{
- uint32_t supported_bw_in_kbps = max_supported_frl_bw_in_kbps;
-
- // HDMI_ENCODED_LINK_BW bits are only valid if HDMI Link Configuration bit is 1 (FRL mode)
- if (hdmi_encoded_link_bw.bits.FRL_MODE) {
- if (hdmi_encoded_link_bw.bits.BW_48Gbps)
- supported_bw_in_kbps = 48000000;
- else if (hdmi_encoded_link_bw.bits.BW_40Gbps)
- supported_bw_in_kbps = 40000000;
- else if (hdmi_encoded_link_bw.bits.BW_32Gbps)
- supported_bw_in_kbps = 32000000;
- else if (hdmi_encoded_link_bw.bits.BW_24Gbps)
- supported_bw_in_kbps = 24000000;
- else if (hdmi_encoded_link_bw.bits.BW_18Gbps)
- supported_bw_in_kbps = 18000000;
- else if (hdmi_encoded_link_bw.bits.BW_9Gbps)
- supported_bw_in_kbps = 9000000;
- }
-
- return supported_bw_in_kbps;
-}
-#endif
-
-static void read_dp_device_vendor_id(struct dc_link *link)
-{
- struct dp_device_vendor_id dp_id;
-
- /* read IEEE branch device id */
- core_link_read_dpcd(
- link,
- DP_BRANCH_OUI,
- (uint8_t *)&dp_id,
- sizeof(dp_id));
-
- link->dpcd_caps.branch_dev_id =
- (dp_id.ieee_oui[0] << 16) +
- (dp_id.ieee_oui[1] << 8) +
- dp_id.ieee_oui[2];
-
- memmove(
- link->dpcd_caps.branch_dev_name,
- dp_id.ieee_device_id,
- sizeof(dp_id.ieee_device_id));
-}
-
-
-
-static void get_active_converter_info(
- uint8_t data, struct dc_link *link)
-{
- union dp_downstream_port_present ds_port = { .byte = data };
- memset(&link->dpcd_caps.dongle_caps, 0, sizeof(link->dpcd_caps.dongle_caps));
-
- /* decode converter info*/
- if (!ds_port.fields.PORT_PRESENT) {
- link->dpcd_caps.dongle_type = DISPLAY_DONGLE_NONE;
- ddc_service_set_dongle_type(link->ddc,
- link->dpcd_caps.dongle_type);
- link->dpcd_caps.is_branch_dev = false;
- return;
- }
-
- /* DPCD 0x5 bit 0 = 1, it indicate it's branch device */
- link->dpcd_caps.is_branch_dev = ds_port.fields.PORT_PRESENT;
-
- switch (ds_port.fields.PORT_TYPE) {
- case DOWNSTREAM_VGA:
- link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_VGA_CONVERTER;
- break;
- case DOWNSTREAM_DVI_HDMI_DP_PLUS_PLUS:
- /* At this point we don't know is it DVI or HDMI or DP++,
- * assume DVI.*/
- link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_DVI_CONVERTER;
- break;
- default:
- link->dpcd_caps.dongle_type = DISPLAY_DONGLE_NONE;
- break;
- }
-
- if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_11) {
- uint8_t det_caps[16]; /* CTS 4.2.2.7 expects source to read Detailed Capabilities Info : 00080h-0008F.*/
- union dwnstream_port_caps_byte0 *port_caps =
- (union dwnstream_port_caps_byte0 *)det_caps;
- if (core_link_read_dpcd(link, DP_DOWNSTREAM_PORT_0,
- det_caps, sizeof(det_caps)) == DC_OK) {
-
- switch (port_caps->bits.DWN_STRM_PORTX_TYPE) {
- /*Handle DP case as DONGLE_NONE*/
- case DOWN_STREAM_DETAILED_DP:
- link->dpcd_caps.dongle_type = DISPLAY_DONGLE_NONE;
- break;
- case DOWN_STREAM_DETAILED_VGA:
- link->dpcd_caps.dongle_type =
- DISPLAY_DONGLE_DP_VGA_CONVERTER;
- break;
- case DOWN_STREAM_DETAILED_DVI:
- link->dpcd_caps.dongle_type =
- DISPLAY_DONGLE_DP_DVI_CONVERTER;
- break;
- case DOWN_STREAM_DETAILED_HDMI:
- case DOWN_STREAM_DETAILED_DP_PLUS_PLUS:
- /*Handle DP++ active converter case, process DP++ case as HDMI case according DP1.4 spec*/
- link->dpcd_caps.dongle_type =
- DISPLAY_DONGLE_DP_HDMI_CONVERTER;
-
- link->dpcd_caps.dongle_caps.dongle_type = link->dpcd_caps.dongle_type;
- if (ds_port.fields.DETAILED_CAPS) {
-
- union dwnstream_port_caps_byte3_hdmi
- hdmi_caps = {.raw = det_caps[3] };
- union dwnstream_port_caps_byte2
- hdmi_color_caps = {.raw = det_caps[2] };
- link->dpcd_caps.dongle_caps.dp_hdmi_max_pixel_clk_in_khz =
- det_caps[1] * 2500;
-
- link->dpcd_caps.dongle_caps.is_dp_hdmi_s3d_converter =
- hdmi_caps.bits.FRAME_SEQ_TO_FRAME_PACK;
- /*YCBCR capability only for HDMI case*/
- if (port_caps->bits.DWN_STRM_PORTX_TYPE
- == DOWN_STREAM_DETAILED_HDMI) {
- link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr422_pass_through =
- hdmi_caps.bits.YCrCr422_PASS_THROUGH;
- link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr420_pass_through =
- hdmi_caps.bits.YCrCr420_PASS_THROUGH;
- link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr422_converter =
- hdmi_caps.bits.YCrCr422_CONVERSION;
- link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr420_converter =
- hdmi_caps.bits.YCrCr420_CONVERSION;
- }
-
- link->dpcd_caps.dongle_caps.dp_hdmi_max_bpc =
- translate_dpcd_max_bpc(
- hdmi_color_caps.bits.MAX_BITS_PER_COLOR_COMPONENT);
-
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- if (link->dc->caps.dp_hdmi21_pcon_support) {
- union hdmi_encoded_link_bw hdmi_encoded_link_bw;
-
- link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps =
- dc_link_bw_kbps_from_raw_frl_link_rate_data(
- hdmi_color_caps.bits.MAX_ENCODED_LINK_BW_SUPPORT);
-
- // Intersect reported max link bw support with the supported link rate post FRL link training
- if (core_link_read_dpcd(link, DP_PCON_HDMI_POST_FRL_STATUS,
- &hdmi_encoded_link_bw.raw, sizeof(hdmi_encoded_link_bw)) == DC_OK) {
- link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps = intersect_frl_link_bw_support(
- link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps,
- hdmi_encoded_link_bw);
- }
-
- if (link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps > 0)
- link->dpcd_caps.dongle_caps.extendedCapValid = true;
- }
-#endif
-
- if (link->dpcd_caps.dongle_caps.dp_hdmi_max_pixel_clk_in_khz != 0)
- link->dpcd_caps.dongle_caps.extendedCapValid = true;
- }
-
- break;
- }
- }
- }
-
- ddc_service_set_dongle_type(link->ddc, link->dpcd_caps.dongle_type);
-
- {
- struct dp_sink_hw_fw_revision dp_hw_fw_revision;
-
- core_link_read_dpcd(
- link,
- DP_BRANCH_REVISION_START,
- (uint8_t *)&dp_hw_fw_revision,
- sizeof(dp_hw_fw_revision));
-
- link->dpcd_caps.branch_hw_revision =
- dp_hw_fw_revision.ieee_hw_rev;
-
- memmove(
- link->dpcd_caps.branch_fw_revision,
- dp_hw_fw_revision.ieee_fw_rev,
- sizeof(dp_hw_fw_revision.ieee_fw_rev));
- }
- if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_14 &&
- link->dpcd_caps.dongle_type != DISPLAY_DONGLE_NONE) {
- union dp_dfp_cap_ext dfp_cap_ext;
- memset(&dfp_cap_ext, '\0', sizeof (dfp_cap_ext));
- core_link_read_dpcd(
- link,
- DP_DFP_CAPABILITY_EXTENSION_SUPPORT,
- dfp_cap_ext.raw,
- sizeof(dfp_cap_ext.raw));
- link->dpcd_caps.dongle_caps.dfp_cap_ext.supported = dfp_cap_ext.fields.supported;
- link->dpcd_caps.dongle_caps.dfp_cap_ext.max_pixel_rate_in_mps =
- dfp_cap_ext.fields.max_pixel_rate_in_mps[0] +
- (dfp_cap_ext.fields.max_pixel_rate_in_mps[1] << 8);
- link->dpcd_caps.dongle_caps.dfp_cap_ext.max_video_h_active_width =
- dfp_cap_ext.fields.max_video_h_active_width[0] +
- (dfp_cap_ext.fields.max_video_h_active_width[1] << 8);
- link->dpcd_caps.dongle_caps.dfp_cap_ext.max_video_v_active_height =
- dfp_cap_ext.fields.max_video_v_active_height[0] +
- (dfp_cap_ext.fields.max_video_v_active_height[1] << 8);
- link->dpcd_caps.dongle_caps.dfp_cap_ext.encoding_format_caps =
- dfp_cap_ext.fields.encoding_format_caps;
- link->dpcd_caps.dongle_caps.dfp_cap_ext.rgb_color_depth_caps =
- dfp_cap_ext.fields.rgb_color_depth_caps;
- link->dpcd_caps.dongle_caps.dfp_cap_ext.ycbcr444_color_depth_caps =
- dfp_cap_ext.fields.ycbcr444_color_depth_caps;
- link->dpcd_caps.dongle_caps.dfp_cap_ext.ycbcr422_color_depth_caps =
- dfp_cap_ext.fields.ycbcr422_color_depth_caps;
- link->dpcd_caps.dongle_caps.dfp_cap_ext.ycbcr420_color_depth_caps =
- dfp_cap_ext.fields.ycbcr420_color_depth_caps;
- DC_LOG_DP2("DFP capability extension is read at link %d", link->link_index);
- DC_LOG_DP2("\tdfp_cap_ext.supported = %s", link->dpcd_caps.dongle_caps.dfp_cap_ext.supported ? "true" : "false");
- DC_LOG_DP2("\tdfp_cap_ext.max_pixel_rate_in_mps = %d", link->dpcd_caps.dongle_caps.dfp_cap_ext.max_pixel_rate_in_mps);
- DC_LOG_DP2("\tdfp_cap_ext.max_video_h_active_width = %d", link->dpcd_caps.dongle_caps.dfp_cap_ext.max_video_h_active_width);
- DC_LOG_DP2("\tdfp_cap_ext.max_video_v_active_height = %d", link->dpcd_caps.dongle_caps.dfp_cap_ext.max_video_v_active_height);
- }
-}
-
-static void dp_wa_power_up_0010FA(struct dc_link *link, uint8_t *dpcd_data,
- int length)
-{
- int retry = 0;
-
- if (!link->dpcd_caps.dpcd_rev.raw) {
- do {
- dp_receiver_power_ctrl(link, true);
- core_link_read_dpcd(link, DP_DPCD_REV,
- dpcd_data, length);
- link->dpcd_caps.dpcd_rev.raw = dpcd_data[
- DP_DPCD_REV -
- DP_DPCD_REV];
- } while (retry++ < 4 && !link->dpcd_caps.dpcd_rev.raw);
- }
-
- if (link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_VGA_CONVERTER) {
- switch (link->dpcd_caps.branch_dev_id) {
- /* 0010FA active dongles (DP-VGA, DP-DLDVI converters) power down
- * all internal circuits including AUX communication preventing
- * reading DPCD table and EDID (spec violation).
- * Encoder will skip DP RX power down on disable_output to
- * keep receiver powered all the time.*/
- case DP_BRANCH_DEVICE_ID_0010FA:
- case DP_BRANCH_DEVICE_ID_0080E1:
- case DP_BRANCH_DEVICE_ID_00E04C:
- link->wa_flags.dp_keep_receiver_powered = true;
- break;
-
- /* TODO: May need work around for other dongles. */
- default:
- link->wa_flags.dp_keep_receiver_powered = false;
- break;
- }
- } else
- link->wa_flags.dp_keep_receiver_powered = false;
-}
-
-/* Read additional sink caps defined in source specific DPCD area
- * This function currently only reads from SinkCapability address (DP_SOURCE_SINK_CAP)
- */
-static bool dpcd_read_sink_ext_caps(struct dc_link *link)
-{
- uint8_t dpcd_data;
-
- if (!link)
- return false;
-
- if (core_link_read_dpcd(link, DP_SOURCE_SINK_CAP, &dpcd_data, 1) != DC_OK)
- return false;
-
- link->dpcd_sink_ext_caps.raw = dpcd_data;
- return true;
-}
-
-enum dc_status dp_retrieve_lttpr_cap(struct dc_link *link)
-{
- uint8_t lttpr_dpcd_data[8];
- enum dc_status status = DC_ERROR_UNEXPECTED;
- bool is_lttpr_present = false;
-
- /* Logic to determine LTTPR support*/
- bool vbios_lttpr_interop = link->dc->caps.vbios_lttpr_aware;
-
- if (!vbios_lttpr_interop || !link->dc->caps.extended_aux_timeout_support)
- return false;
-
- /* By reading LTTPR capability, RX assumes that we will enable
- * LTTPR extended aux timeout if LTTPR is present.
- */
- status = core_link_read_dpcd(link,
- DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV,
- lttpr_dpcd_data,
- sizeof(lttpr_dpcd_data));
-
- link->dpcd_caps.lttpr_caps.revision.raw =
- lttpr_dpcd_data[DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV -
- DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
-
- link->dpcd_caps.lttpr_caps.max_link_rate =
- lttpr_dpcd_data[DP_MAX_LINK_RATE_PHY_REPEATER -
- DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
-
- link->dpcd_caps.lttpr_caps.phy_repeater_cnt =
- lttpr_dpcd_data[DP_PHY_REPEATER_CNT -
- DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
-
- link->dpcd_caps.lttpr_caps.max_lane_count =
- lttpr_dpcd_data[DP_MAX_LANE_COUNT_PHY_REPEATER -
- DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
-
- link->dpcd_caps.lttpr_caps.mode =
- lttpr_dpcd_data[DP_PHY_REPEATER_MODE -
- DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
-
- link->dpcd_caps.lttpr_caps.max_ext_timeout =
- lttpr_dpcd_data[DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT -
- DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
- link->dpcd_caps.lttpr_caps.main_link_channel_coding.raw =
- lttpr_dpcd_data[DP_MAIN_LINK_CHANNEL_CODING_PHY_REPEATER -
- DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
-
- link->dpcd_caps.lttpr_caps.supported_128b_132b_rates.raw =
- lttpr_dpcd_data[DP_PHY_REPEATER_128B132B_RATES -
- DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
-
- /* If this chip cap is set, at least one retimer must exist in the chain
- * Override count to 1 if we receive a known bad count (0 or an invalid value)
- */
- if (link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN &&
- (dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) == 0)) {
- ASSERT(0);
- link->dpcd_caps.lttpr_caps.phy_repeater_cnt = 0x80;
- DC_LOG_DC("lttpr_caps forced phy_repeater_cnt = %d\n", link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
- }
-
- /* Attempt to train in LTTPR transparent mode if repeater count exceeds 8. */
- is_lttpr_present = dp_is_lttpr_present(link);
-
- if (is_lttpr_present)
- CONN_DATA_DETECT(link, lttpr_dpcd_data, sizeof(lttpr_dpcd_data), "LTTPR Caps: ");
-
- DC_LOG_DC("is_lttpr_present = %d\n", is_lttpr_present);
- return status;
-}
-
-bool dp_is_lttpr_present(struct dc_link *link)
-{
- return (dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) != 0 &&
- link->dpcd_caps.lttpr_caps.max_lane_count > 0 &&
- link->dpcd_caps.lttpr_caps.max_lane_count <= 4 &&
- link->dpcd_caps.lttpr_caps.revision.raw >= 0x14);
-}
-
-enum lttpr_mode dp_decide_lttpr_mode(struct dc_link *link, struct dc_link_settings *link_setting)
-{
- enum dp_link_encoding encoding = dp_get_link_encoding_format(link_setting);
-
- if (encoding == DP_8b_10b_ENCODING)
- return dp_decide_8b_10b_lttpr_mode(link);
- else if (encoding == DP_128b_132b_ENCODING)
- return dp_decide_128b_132b_lttpr_mode(link);
-
- ASSERT(0);
- return LTTPR_MODE_NON_LTTPR;
-}
-
-void dp_get_lttpr_mode_override(struct dc_link *link, enum lttpr_mode *override)
-{
- if (!dp_is_lttpr_present(link))
- return;
-
- if (link->dc->debug.lttpr_mode_override == LTTPR_MODE_TRANSPARENT) {
- *override = LTTPR_MODE_TRANSPARENT;
- } else if (link->dc->debug.lttpr_mode_override == LTTPR_MODE_NON_TRANSPARENT) {
- *override = LTTPR_MODE_NON_TRANSPARENT;
- } else if (link->dc->debug.lttpr_mode_override == LTTPR_MODE_NON_LTTPR) {
- *override = LTTPR_MODE_NON_LTTPR;
- }
- DC_LOG_DC("lttpr_mode_override chose LTTPR_MODE = %d\n", (uint8_t)(*override));
-}
-
-enum lttpr_mode dp_decide_8b_10b_lttpr_mode(struct dc_link *link)
-{
- bool is_lttpr_present = dp_is_lttpr_present(link);
- bool vbios_lttpr_force_non_transparent = link->dc->caps.vbios_lttpr_enable;
- bool vbios_lttpr_aware = link->dc->caps.vbios_lttpr_aware;
-
- if (!is_lttpr_present)
- return LTTPR_MODE_NON_LTTPR;
-
- if (vbios_lttpr_aware) {
- if (vbios_lttpr_force_non_transparent) {
- DC_LOG_DC("chose LTTPR_MODE_NON_TRANSPARENT due to VBIOS DCE_INFO_CAPS_LTTPR_SUPPORT_ENABLE set to 1.\n");
- return LTTPR_MODE_NON_TRANSPARENT;
- } else {
- DC_LOG_DC("chose LTTPR_MODE_NON_TRANSPARENT by default due to VBIOS not set DCE_INFO_CAPS_LTTPR_SUPPORT_ENABLE set to 1.\n");
- return LTTPR_MODE_TRANSPARENT;
- }
- }
-
- if (link->dc->config.allow_lttpr_non_transparent_mode.bits.DP1_4A &&
- link->dc->caps.extended_aux_timeout_support) {
- DC_LOG_DC("chose LTTPR_MODE_NON_TRANSPARENT by default and dc->config.allow_lttpr_non_transparent_mode.bits.DP1_4A set to 1.\n");
- return LTTPR_MODE_NON_TRANSPARENT;
- }
-
- DC_LOG_DC("chose LTTPR_MODE_NON_LTTPR.\n");
- return LTTPR_MODE_NON_LTTPR;
-}
-
-enum lttpr_mode dp_decide_128b_132b_lttpr_mode(struct dc_link *link)
-{
- enum lttpr_mode mode = LTTPR_MODE_NON_LTTPR;
-
- if (dp_is_lttpr_present(link))
- mode = LTTPR_MODE_NON_TRANSPARENT;
-
- DC_LOG_DC("128b_132b chose LTTPR_MODE %d.\n", mode);
- return mode;
-}
-
-static bool get_usbc_cable_id(struct dc_link *link, union dp_cable_id *cable_id)
-{
- union dmub_rb_cmd cmd;
-
- if (!link->ctx->dmub_srv ||
- link->ep_type != DISPLAY_ENDPOINT_PHY ||
- link->link_enc->features.flags.bits.DP_IS_USB_C == 0)
- return false;
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.cable_id.header.type = DMUB_CMD_GET_USBC_CABLE_ID;
- cmd.cable_id.header.payload_bytes = sizeof(cmd.cable_id.data);
- cmd.cable_id.data.input.phy_inst = resource_transmitter_to_phy_idx(
- link->dc, link->link_enc->transmitter);
- if (dc_dmub_srv_cmd_with_reply_data(link->ctx->dmub_srv, &cmd) &&
- cmd.cable_id.header.ret_status == 1) {
- cable_id->raw = cmd.cable_id.data.output_raw;
- DC_LOG_DC("usbc_cable_id = %d.\n", cable_id->raw);
- }
- return cmd.cable_id.header.ret_status == 1;
-}
-
-static union dp_cable_id intersect_cable_id(
- union dp_cable_id *a, union dp_cable_id *b)
-{
- union dp_cable_id out;
-
- out.bits.UHBR10_20_CAPABILITY = MIN(a->bits.UHBR10_20_CAPABILITY,
- b->bits.UHBR10_20_CAPABILITY);
- out.bits.UHBR13_5_CAPABILITY = MIN(a->bits.UHBR13_5_CAPABILITY,
- b->bits.UHBR13_5_CAPABILITY);
- out.bits.CABLE_TYPE = MAX(a->bits.CABLE_TYPE, b->bits.CABLE_TYPE);
-
- return out;
-}
-
-static void retrieve_cable_id(struct dc_link *link)
-{
- union dp_cable_id usbc_cable_id;
-
- link->dpcd_caps.cable_id.raw = 0;
- core_link_read_dpcd(link, DP_CABLE_ATTRIBUTES_UPDATED_BY_DPRX,
- &link->dpcd_caps.cable_id.raw, sizeof(uint8_t));
-
- if (get_usbc_cable_id(link, &usbc_cable_id))
- link->dpcd_caps.cable_id = intersect_cable_id(
- &link->dpcd_caps.cable_id, &usbc_cable_id);
-}
-
-static enum dc_status wake_up_aux_channel(struct dc_link *link)
-{
- enum dc_status status = DC_ERROR_UNEXPECTED;
- uint32_t aux_channel_retry_cnt = 0;
- uint8_t dpcd_power_state = '\0';
-
- while (status != DC_OK && aux_channel_retry_cnt < 10) {
- status = core_link_read_dpcd(link, DP_SET_POWER,
- &dpcd_power_state, sizeof(dpcd_power_state));
-
- /* Delay 1 ms if AUX CH is in power down state. Based on spec
- * section 2.3.1.2, if AUX CH may be powered down due to
- * write to DPCD 600h = 2. Sink AUX CH is monitoring differential
- * signal and may need up to 1 ms before being able to reply.
- */
- if (status != DC_OK || dpcd_power_state == DP_SET_POWER_D3) {
- udelay(1000);
- aux_channel_retry_cnt++;
- }
- }
-
- if (status != DC_OK) {
- dpcd_power_state = DP_SET_POWER_D0;
- status = core_link_write_dpcd(
- link,
- DP_SET_POWER,
- &dpcd_power_state,
- sizeof(dpcd_power_state));
-
- dpcd_power_state = DP_SET_POWER_D3;
- status = core_link_write_dpcd(
- link,
- DP_SET_POWER,
- &dpcd_power_state,
- sizeof(dpcd_power_state));
- return DC_ERROR_UNEXPECTED;
- }
-
- return DC_OK;
-}
-
-static bool retrieve_link_cap(struct dc_link *link)
-{
- /* DP_ADAPTER_CAP - DP_DPCD_REV + 1 == 16 and also DP_DSC_BITS_PER_PIXEL_INC - DP_DSC_SUPPORT + 1 == 16,
- * which means size 16 will be good for both of those DPCD register block reads
- */
- uint8_t dpcd_data[16];
- /*Only need to read 1 byte starting from DP_DPRX_FEATURE_ENUMERATION_LIST.
- */
- uint8_t dpcd_dprx_data = '\0';
-
- struct dp_device_vendor_id sink_id;
- union down_stream_port_count down_strm_port_count;
- union edp_configuration_cap edp_config_cap;
- union dp_downstream_port_present ds_port = { 0 };
- enum dc_status status = DC_ERROR_UNEXPECTED;
- uint32_t read_dpcd_retry_cnt = 3;
- int i;
- struct dp_sink_hw_fw_revision dp_hw_fw_revision;
- const uint32_t post_oui_delay = 30; // 30ms
-
- memset(dpcd_data, '\0', sizeof(dpcd_data));
- memset(&down_strm_port_count,
- '\0', sizeof(union down_stream_port_count));
- memset(&edp_config_cap, '\0',
- sizeof(union edp_configuration_cap));
-
- /* if extended timeout is supported in hardware,
- * default to LTTPR timeout (3.2ms) first as a W/A for DP link layer
- * CTS 4.2.1.1 regression introduced by CTS specs requirement update.
- */
- dc_link_aux_try_to_configure_timeout(link->ddc,
- LINK_AUX_DEFAULT_LTTPR_TIMEOUT_PERIOD);
-
- status = dp_retrieve_lttpr_cap(link);
-
- if (status != DC_OK) {
- status = wake_up_aux_channel(link);
- if (status == DC_OK)
- dp_retrieve_lttpr_cap(link);
- else
- return false;
- }
-
- if (dp_is_lttpr_present(link))
- configure_lttpr_mode_transparent(link);
-
- /* Read DP tunneling information. */
- status = dpcd_get_tunneling_device_data(link);
-
- dpcd_set_source_specific_data(link);
- /* Sink may need to configure internals based on vendor, so allow some
- * time before proceeding with possibly vendor specific transactions
- */
- msleep(post_oui_delay);
-
- for (i = 0; i < read_dpcd_retry_cnt; i++) {
- status = core_link_read_dpcd(
- link,
- DP_DPCD_REV,
- dpcd_data,
- sizeof(dpcd_data));
- if (status == DC_OK)
- break;
- }
-
- if (status != DC_OK) {
- dm_error("%s: Read receiver caps dpcd data failed.\n", __func__);
- return false;
- }
-
- if (!dp_is_lttpr_present(link))
- dc_link_aux_try_to_configure_timeout(link->ddc, LINK_AUX_DEFAULT_TIMEOUT_PERIOD);
-
- {
- union training_aux_rd_interval aux_rd_interval;
-
- aux_rd_interval.raw =
- dpcd_data[DP_TRAINING_AUX_RD_INTERVAL];
-
- link->dpcd_caps.ext_receiver_cap_field_present =
- aux_rd_interval.bits.EXT_RECEIVER_CAP_FIELD_PRESENT == 1;
-
- if (aux_rd_interval.bits.EXT_RECEIVER_CAP_FIELD_PRESENT == 1) {
- uint8_t ext_cap_data[16];
-
- memset(ext_cap_data, '\0', sizeof(ext_cap_data));
- for (i = 0; i < read_dpcd_retry_cnt; i++) {
- status = core_link_read_dpcd(
- link,
- DP_DP13_DPCD_REV,
- ext_cap_data,
- sizeof(ext_cap_data));
- if (status == DC_OK) {
- memcpy(dpcd_data, ext_cap_data, sizeof(dpcd_data));
- break;
- }
- }
- if (status != DC_OK)
- dm_error("%s: Read extend caps data failed, use cap from dpcd 0.\n", __func__);
- }
- }
-
- link->dpcd_caps.dpcd_rev.raw =
- dpcd_data[DP_DPCD_REV - DP_DPCD_REV];
-
- if (link->dpcd_caps.ext_receiver_cap_field_present) {
- for (i = 0; i < read_dpcd_retry_cnt; i++) {
- status = core_link_read_dpcd(
- link,
- DP_DPRX_FEATURE_ENUMERATION_LIST,
- &dpcd_dprx_data,
- sizeof(dpcd_dprx_data));
- if (status == DC_OK)
- break;
- }
-
- link->dpcd_caps.dprx_feature.raw = dpcd_dprx_data;
-
- if (status != DC_OK)
- dm_error("%s: Read DPRX caps data failed.\n", __func__);
- }
-
- else {
- link->dpcd_caps.dprx_feature.raw = 0;
- }
-
-
- /* Error condition checking...
- * It is impossible for Sink to report Max Lane Count = 0.
- * It is possible for Sink to report Max Link Rate = 0, if it is
- * an eDP device that is reporting specialized link rates in the
- * SUPPORTED_LINK_RATE table.
- */
- if (dpcd_data[DP_MAX_LANE_COUNT - DP_DPCD_REV] == 0)
- return false;
-
- ds_port.byte = dpcd_data[DP_DOWNSTREAMPORT_PRESENT -
- DP_DPCD_REV];
-
- read_dp_device_vendor_id(link);
-
- /* TODO - decouple raw mst capability from policy decision */
- link->dpcd_caps.is_mst_capable = is_mst_supported(link);
-
- get_active_converter_info(ds_port.byte, link);
-
- dp_wa_power_up_0010FA(link, dpcd_data, sizeof(dpcd_data));
-
- down_strm_port_count.raw = dpcd_data[DP_DOWN_STREAM_PORT_COUNT -
- DP_DPCD_REV];
-
- link->dpcd_caps.allow_invalid_MSA_timing_param =
- down_strm_port_count.bits.IGNORE_MSA_TIMING_PARAM;
-
- link->dpcd_caps.max_ln_count.raw = dpcd_data[
- DP_MAX_LANE_COUNT - DP_DPCD_REV];
-
- link->dpcd_caps.max_down_spread.raw = dpcd_data[
- DP_MAX_DOWNSPREAD - DP_DPCD_REV];
-
- link->reported_link_cap.lane_count =
- link->dpcd_caps.max_ln_count.bits.MAX_LANE_COUNT;
- link->reported_link_cap.link_rate = get_link_rate_from_max_link_bw(
- dpcd_data[DP_MAX_LINK_RATE - DP_DPCD_REV]);
- link->reported_link_cap.link_spread =
- link->dpcd_caps.max_down_spread.bits.MAX_DOWN_SPREAD ?
- LINK_SPREAD_05_DOWNSPREAD_30KHZ : LINK_SPREAD_DISABLED;
-
- edp_config_cap.raw = dpcd_data[
- DP_EDP_CONFIGURATION_CAP - DP_DPCD_REV];
- link->dpcd_caps.panel_mode_edp =
- edp_config_cap.bits.ALT_SCRAMBLER_RESET;
- link->dpcd_caps.dpcd_display_control_capable =
- edp_config_cap.bits.DPCD_DISPLAY_CONTROL_CAPABLE;
- link->dpcd_caps.channel_coding_cap.raw =
- dpcd_data[DP_MAIN_LINK_CHANNEL_CODING - DP_DPCD_REV];
- link->test_pattern_enabled = false;
- link->compliance_test_state.raw = 0;
-
- /* read sink count */
- core_link_read_dpcd(link,
- DP_SINK_COUNT,
- &link->dpcd_caps.sink_count.raw,
- sizeof(link->dpcd_caps.sink_count.raw));
-
- /* read sink ieee oui */
- core_link_read_dpcd(link,
- DP_SINK_OUI,
- (uint8_t *)(&sink_id),
- sizeof(sink_id));
-
- link->dpcd_caps.sink_dev_id =
- (sink_id.ieee_oui[0] << 16) +
- (sink_id.ieee_oui[1] << 8) +
- (sink_id.ieee_oui[2]);
-
- memmove(
- link->dpcd_caps.sink_dev_id_str,
- sink_id.ieee_device_id,
- sizeof(sink_id.ieee_device_id));
-
- /* Quirk Apple MBP 2017 15" Retina panel: Wrong DP_MAX_LINK_RATE */
- {
- uint8_t str_mbp_2017[] = { 101, 68, 21, 101, 98, 97 };
-
- if ((link->dpcd_caps.sink_dev_id == 0x0010fa) &&
- !memcmp(link->dpcd_caps.sink_dev_id_str, str_mbp_2017,
- sizeof(str_mbp_2017))) {
- link->reported_link_cap.link_rate = 0x0c;
- }
- }
-
- core_link_read_dpcd(
- link,
- DP_SINK_HW_REVISION_START,
- (uint8_t *)&dp_hw_fw_revision,
- sizeof(dp_hw_fw_revision));
-
- link->dpcd_caps.sink_hw_revision =
- dp_hw_fw_revision.ieee_hw_rev;
-
- memmove(
- link->dpcd_caps.sink_fw_revision,
- dp_hw_fw_revision.ieee_fw_rev,
- sizeof(dp_hw_fw_revision.ieee_fw_rev));
-
- /* Quirk for Apple MBP 2018 15" Retina panels: wrong DP_MAX_LINK_RATE */
- {
- uint8_t str_mbp_2018[] = { 101, 68, 21, 103, 98, 97 };
- uint8_t fwrev_mbp_2018[] = { 7, 4 };
- uint8_t fwrev_mbp_2018_vega[] = { 8, 4 };
-
- /* We also check for the firmware revision as 16,1 models have an
- * identical device id and are incorrectly quirked otherwise.
- */
- if ((link->dpcd_caps.sink_dev_id == 0x0010fa) &&
- !memcmp(link->dpcd_caps.sink_dev_id_str, str_mbp_2018,
- sizeof(str_mbp_2018)) &&
- (!memcmp(link->dpcd_caps.sink_fw_revision, fwrev_mbp_2018,
- sizeof(fwrev_mbp_2018)) ||
- !memcmp(link->dpcd_caps.sink_fw_revision, fwrev_mbp_2018_vega,
- sizeof(fwrev_mbp_2018_vega)))) {
- link->reported_link_cap.link_rate = LINK_RATE_RBR2;
- }
- }
-
- memset(&link->dpcd_caps.dsc_caps, '\0',
- sizeof(link->dpcd_caps.dsc_caps));
- memset(&link->dpcd_caps.fec_cap, '\0', sizeof(link->dpcd_caps.fec_cap));
- /* Read DSC and FEC sink capabilities if DP revision is 1.4 and up */
- if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_14) {
- status = core_link_read_dpcd(
- link,
- DP_FEC_CAPABILITY,
- &link->dpcd_caps.fec_cap.raw,
- sizeof(link->dpcd_caps.fec_cap.raw));
- status = core_link_read_dpcd(
- link,
- DP_DSC_SUPPORT,
- link->dpcd_caps.dsc_caps.dsc_basic_caps.raw,
- sizeof(link->dpcd_caps.dsc_caps.dsc_basic_caps.raw));
- if (link->dpcd_caps.dongle_type != DISPLAY_DONGLE_NONE) {
- status = core_link_read_dpcd(
- link,
- DP_DSC_BRANCH_OVERALL_THROUGHPUT_0,
- link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.raw,
- sizeof(link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.raw));
- DC_LOG_DSC("DSC branch decoder capability is read at link %d", link->link_index);
- DC_LOG_DSC("\tBRANCH_OVERALL_THROUGHPUT_0 = 0x%02x",
- link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.fields.BRANCH_OVERALL_THROUGHPUT_0);
- DC_LOG_DSC("\tBRANCH_OVERALL_THROUGHPUT_1 = 0x%02x",
- link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.fields.BRANCH_OVERALL_THROUGHPUT_1);
- DC_LOG_DSC("\tBRANCH_MAX_LINE_WIDTH 0x%02x",
- link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.fields.BRANCH_MAX_LINE_WIDTH);
- }
-
- /* Apply work around to disable FEC and DSC for USB4 tunneling in TBT3 compatibility mode
- * only if required.
- */
- if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA &&
- link->dc->debug.dpia_debug.bits.enable_force_tbt3_work_around &&
- link->dpcd_caps.is_branch_dev &&
- link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_90CC24 &&
- link->dpcd_caps.branch_hw_revision == DP_BRANCH_HW_REV_10 &&
- (link->dpcd_caps.fec_cap.bits.FEC_CAPABLE ||
- link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_SUPPORT)) {
- /* A TBT3 device is expected to report no support for FEC or DSC to a USB4 DPIA.
- * Clear FEC and DSC capabilities as a work around if that is not the case.
- */
- link->wa_flags.dpia_forced_tbt3_mode = true;
- memset(&link->dpcd_caps.dsc_caps, '\0', sizeof(link->dpcd_caps.dsc_caps));
- memset(&link->dpcd_caps.fec_cap, '\0', sizeof(link->dpcd_caps.fec_cap));
- DC_LOG_DSC("Clear DSC SUPPORT for USB4 link(%d) in TBT3 compatibility mode", link->link_index);
- } else
- link->wa_flags.dpia_forced_tbt3_mode = false;
- }
-
- if (!dpcd_read_sink_ext_caps(link))
- link->dpcd_sink_ext_caps.raw = 0;
-
- if (link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED) {
- DC_LOG_DP2("128b/132b encoding is supported at link %d", link->link_index);
-
- core_link_read_dpcd(link,
- DP_128b_132b_SUPPORTED_LINK_RATES,
- &link->dpcd_caps.dp_128b_132b_supported_link_rates.raw,
- sizeof(link->dpcd_caps.dp_128b_132b_supported_link_rates.raw));
- if (link->dpcd_caps.dp_128b_132b_supported_link_rates.bits.UHBR20)
- link->reported_link_cap.link_rate = LINK_RATE_UHBR20;
- else if (link->dpcd_caps.dp_128b_132b_supported_link_rates.bits.UHBR13_5)
- link->reported_link_cap.link_rate = LINK_RATE_UHBR13_5;
- else if (link->dpcd_caps.dp_128b_132b_supported_link_rates.bits.UHBR10)
- link->reported_link_cap.link_rate = LINK_RATE_UHBR10;
- else
- dm_error("%s: Invalid RX 128b_132b_supported_link_rates\n", __func__);
- DC_LOG_DP2("128b/132b supported link rates is read at link %d", link->link_index);
- DC_LOG_DP2("\tmax 128b/132b link rate support is %d.%d GHz",
- link->reported_link_cap.link_rate / 100,
- link->reported_link_cap.link_rate % 100);
-
- core_link_read_dpcd(link,
- DP_SINK_VIDEO_FALLBACK_FORMATS,
- &link->dpcd_caps.fallback_formats.raw,
- sizeof(link->dpcd_caps.fallback_formats.raw));
- DC_LOG_DP2("sink video fallback format is read at link %d", link->link_index);
- if (link->dpcd_caps.fallback_formats.bits.dp_1920x1080_60Hz_24bpp_support)
- DC_LOG_DP2("\t1920x1080@60Hz 24bpp fallback format supported");
- if (link->dpcd_caps.fallback_formats.bits.dp_1280x720_60Hz_24bpp_support)
- DC_LOG_DP2("\t1280x720@60Hz 24bpp fallback format supported");
- if (link->dpcd_caps.fallback_formats.bits.dp_1024x768_60Hz_24bpp_support)
- DC_LOG_DP2("\t1024x768@60Hz 24bpp fallback format supported");
- if (link->dpcd_caps.fallback_formats.raw == 0) {
- DC_LOG_DP2("\tno supported fallback formats, assume 1920x1080@60Hz 24bpp is supported");
- link->dpcd_caps.fallback_formats.bits.dp_1920x1080_60Hz_24bpp_support = 1;
- }
-
- core_link_read_dpcd(link,
- DP_FEC_CAPABILITY_1,
- &link->dpcd_caps.fec_cap1.raw,
- sizeof(link->dpcd_caps.fec_cap1.raw));
- DC_LOG_DP2("FEC CAPABILITY 1 is read at link %d", link->link_index);
- if (link->dpcd_caps.fec_cap1.bits.AGGREGATED_ERROR_COUNTERS_CAPABLE)
- DC_LOG_DP2("\tFEC aggregated error counters are supported");
- }
-
- retrieve_cable_id(link);
- dpcd_write_cable_id_to_dprx(link);
-
- /* Connectivity log: detection */
- CONN_DATA_DETECT(link, dpcd_data, sizeof(dpcd_data), "Rx Caps: ");
-
- return true;
-}
-
-bool dp_overwrite_extended_receiver_cap(struct dc_link *link)
-{
- uint8_t dpcd_data[16];
- uint32_t read_dpcd_retry_cnt = 3;
- enum dc_status status = DC_ERROR_UNEXPECTED;
- union dp_downstream_port_present ds_port = { 0 };
- union down_stream_port_count down_strm_port_count;
- union edp_configuration_cap edp_config_cap;
-
- int i;
-
- for (i = 0; i < read_dpcd_retry_cnt; i++) {
- status = core_link_read_dpcd(
- link,
- DP_DPCD_REV,
- dpcd_data,
- sizeof(dpcd_data));
- if (status == DC_OK)
- break;
- }
-
- link->dpcd_caps.dpcd_rev.raw =
- dpcd_data[DP_DPCD_REV - DP_DPCD_REV];
-
- if (dpcd_data[DP_MAX_LANE_COUNT - DP_DPCD_REV] == 0)
- return false;
-
- ds_port.byte = dpcd_data[DP_DOWNSTREAMPORT_PRESENT -
- DP_DPCD_REV];
-
- get_active_converter_info(ds_port.byte, link);
-
- down_strm_port_count.raw = dpcd_data[DP_DOWN_STREAM_PORT_COUNT -
- DP_DPCD_REV];
-
- link->dpcd_caps.allow_invalid_MSA_timing_param =
- down_strm_port_count.bits.IGNORE_MSA_TIMING_PARAM;
-
- link->dpcd_caps.max_ln_count.raw = dpcd_data[
- DP_MAX_LANE_COUNT - DP_DPCD_REV];
-
- link->dpcd_caps.max_down_spread.raw = dpcd_data[
- DP_MAX_DOWNSPREAD - DP_DPCD_REV];
-
- link->reported_link_cap.lane_count =
- link->dpcd_caps.max_ln_count.bits.MAX_LANE_COUNT;
- link->reported_link_cap.link_rate = dpcd_data[
- DP_MAX_LINK_RATE - DP_DPCD_REV];
- link->reported_link_cap.link_spread =
- link->dpcd_caps.max_down_spread.bits.MAX_DOWN_SPREAD ?
- LINK_SPREAD_05_DOWNSPREAD_30KHZ : LINK_SPREAD_DISABLED;
-
- edp_config_cap.raw = dpcd_data[
- DP_EDP_CONFIGURATION_CAP - DP_DPCD_REV];
- link->dpcd_caps.panel_mode_edp =
- edp_config_cap.bits.ALT_SCRAMBLER_RESET;
- link->dpcd_caps.dpcd_display_control_capable =
- edp_config_cap.bits.DPCD_DISPLAY_CONTROL_CAPABLE;
-
- return true;
-}
-
-bool detect_dp_sink_caps(struct dc_link *link)
-{
- return retrieve_link_cap(link);
-}
-
-static enum dc_link_rate linkRateInKHzToLinkRateMultiplier(uint32_t link_rate_in_khz)
-{
- enum dc_link_rate link_rate;
- // LinkRate is normally stored as a multiplier of 0.27 Gbps per lane. Do the translation.
- switch (link_rate_in_khz) {
- case 1620000:
- link_rate = LINK_RATE_LOW; // Rate_1 (RBR) - 1.62 Gbps/Lane
- break;
- case 2160000:
- link_rate = LINK_RATE_RATE_2; // Rate_2 - 2.16 Gbps/Lane
- break;
- case 2430000:
- link_rate = LINK_RATE_RATE_3; // Rate_3 - 2.43 Gbps/Lane
- break;
- case 2700000:
- link_rate = LINK_RATE_HIGH; // Rate_4 (HBR) - 2.70 Gbps/Lane
- break;
- case 3240000:
- link_rate = LINK_RATE_RBR2; // Rate_5 (RBR2) - 3.24 Gbps/Lane
- break;
- case 4320000:
- link_rate = LINK_RATE_RATE_6; // Rate_6 - 4.32 Gbps/Lane
- break;
- case 5400000:
- link_rate = LINK_RATE_HIGH2; // Rate_7 (HBR2) - 5.40 Gbps/Lane
- break;
- case 8100000:
- link_rate = LINK_RATE_HIGH3; // Rate_8 (HBR3) - 8.10 Gbps/Lane
- break;
- default:
- link_rate = LINK_RATE_UNKNOWN;
- break;
- }
- return link_rate;
-}
-
-void detect_edp_sink_caps(struct dc_link *link)
-{
- uint8_t supported_link_rates[16];
- uint32_t entry;
- uint32_t link_rate_in_khz;
- enum dc_link_rate link_rate = LINK_RATE_UNKNOWN;
- uint8_t backlight_adj_cap;
- uint8_t general_edp_cap;
-
- retrieve_link_cap(link);
- link->dpcd_caps.edp_supported_link_rates_count = 0;
- memset(supported_link_rates, 0, sizeof(supported_link_rates));
-
- /*
- * edp_supported_link_rates_count is only valid for eDP v1.4 or higher.
- * Per VESA eDP spec, "The DPCD revision for eDP v1.4 is 13h"
- */
- if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_13 &&
- (link->panel_config.ilr.optimize_edp_link_rate ||
- link->reported_link_cap.link_rate == LINK_RATE_UNKNOWN)) {
- // Read DPCD 00010h - 0001Fh 16 bytes at one shot
- core_link_read_dpcd(link, DP_SUPPORTED_LINK_RATES,
- supported_link_rates, sizeof(supported_link_rates));
-
- for (entry = 0; entry < 16; entry += 2) {
- // DPCD register reports per-lane link rate = 16-bit link rate capability
- // value X 200 kHz. Need multiplier to find link rate in kHz.
- link_rate_in_khz = (supported_link_rates[entry+1] * 0x100 +
- supported_link_rates[entry]) * 200;
-
- if (link_rate_in_khz != 0) {
- link_rate = linkRateInKHzToLinkRateMultiplier(link_rate_in_khz);
- link->dpcd_caps.edp_supported_link_rates[link->dpcd_caps.edp_supported_link_rates_count] = link_rate;
- link->dpcd_caps.edp_supported_link_rates_count++;
-
- if (link->reported_link_cap.link_rate < link_rate)
- link->reported_link_cap.link_rate = link_rate;
- }
- }
- }
- core_link_read_dpcd(link, DP_EDP_BACKLIGHT_ADJUSTMENT_CAP,
- &backlight_adj_cap, sizeof(backlight_adj_cap));
-
- link->dpcd_caps.dynamic_backlight_capable_edp =
- (backlight_adj_cap & DP_EDP_DYNAMIC_BACKLIGHT_CAP) ? true:false;
-
- core_link_read_dpcd(link, DP_EDP_GENERAL_CAP_1,
- &general_edp_cap, sizeof(general_edp_cap));
-
- link->dpcd_caps.set_power_state_capable_edp =
- (general_edp_cap & DP_EDP_SET_POWER_CAP) ? true:false;
-
- dc_link_set_default_brightness_aux(link);
-
- core_link_read_dpcd(link, DP_EDP_DPCD_REV,
- &link->dpcd_caps.edp_rev,
- sizeof(link->dpcd_caps.edp_rev));
- /*
- * PSR is only valid for eDP v1.3 or higher.
- */
- if (link->dpcd_caps.edp_rev >= DP_EDP_13) {
- core_link_read_dpcd(link, DP_PSR_SUPPORT,
- &link->dpcd_caps.psr_info.psr_version,
- sizeof(link->dpcd_caps.psr_info.psr_version));
- if (link->dpcd_caps.sink_dev_id == DP_BRANCH_DEVICE_ID_001CF8)
- core_link_read_dpcd(link, DP_FORCE_PSRSU_CAPABILITY,
- &link->dpcd_caps.psr_info.force_psrsu_cap,
- sizeof(link->dpcd_caps.psr_info.force_psrsu_cap));
- core_link_read_dpcd(link, DP_PSR_CAPS,
- &link->dpcd_caps.psr_info.psr_dpcd_caps.raw,
- sizeof(link->dpcd_caps.psr_info.psr_dpcd_caps.raw));
- if (link->dpcd_caps.psr_info.psr_dpcd_caps.bits.Y_COORDINATE_REQUIRED) {
- core_link_read_dpcd(link, DP_PSR2_SU_Y_GRANULARITY,
- &link->dpcd_caps.psr_info.psr2_su_y_granularity_cap,
- sizeof(link->dpcd_caps.psr_info.psr2_su_y_granularity_cap));
- }
- }
-
- /*
- * ALPM is only valid for eDP v1.4 or higher.
- */
- if (link->dpcd_caps.dpcd_rev.raw >= DP_EDP_14)
- core_link_read_dpcd(link, DP_RECEIVER_ALPM_CAP,
- &link->dpcd_caps.alpm_caps.raw,
- sizeof(link->dpcd_caps.alpm_caps.raw));
-}
-
-void dc_link_dp_enable_hpd(const struct dc_link *link)
-{
- struct link_encoder *encoder = link->link_enc;
-
- if (encoder != NULL && encoder->funcs->enable_hpd != NULL)
- encoder->funcs->enable_hpd(encoder);
-}
-
-void dc_link_dp_disable_hpd(const struct dc_link *link)
-{
- struct link_encoder *encoder = link->link_enc;
-
- if (encoder != NULL && encoder->funcs->enable_hpd != NULL)
- encoder->funcs->disable_hpd(encoder);
-}
-
-static bool is_dp_phy_pattern(enum dp_test_pattern test_pattern)
-{
- if ((DP_TEST_PATTERN_PHY_PATTERN_BEGIN <= test_pattern &&
- test_pattern <= DP_TEST_PATTERN_PHY_PATTERN_END) ||
- test_pattern == DP_TEST_PATTERN_VIDEO_MODE)
- return true;
- else
- return false;
-}
-
-static void set_crtc_test_pattern(struct dc_link *link,
- struct pipe_ctx *pipe_ctx,
- enum dp_test_pattern test_pattern,
- enum dp_test_pattern_color_space test_pattern_color_space)
-{
- enum controller_dp_test_pattern controller_test_pattern;
- enum dc_color_depth color_depth = pipe_ctx->
- stream->timing.display_color_depth;
- struct bit_depth_reduction_params params;
- struct output_pixel_processor *opp = pipe_ctx->stream_res.opp;
- int width = pipe_ctx->stream->timing.h_addressable +
- pipe_ctx->stream->timing.h_border_left +
- pipe_ctx->stream->timing.h_border_right;
- int height = pipe_ctx->stream->timing.v_addressable +
- pipe_ctx->stream->timing.v_border_bottom +
- pipe_ctx->stream->timing.v_border_top;
-
- memset(&params, 0, sizeof(params));
-
- switch (test_pattern) {
- case DP_TEST_PATTERN_COLOR_SQUARES:
- controller_test_pattern =
- CONTROLLER_DP_TEST_PATTERN_COLORSQUARES;
- break;
- case DP_TEST_PATTERN_COLOR_SQUARES_CEA:
- controller_test_pattern =
- CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA;
- break;
- case DP_TEST_PATTERN_VERTICAL_BARS:
- controller_test_pattern =
- CONTROLLER_DP_TEST_PATTERN_VERTICALBARS;
- break;
- case DP_TEST_PATTERN_HORIZONTAL_BARS:
- controller_test_pattern =
- CONTROLLER_DP_TEST_PATTERN_HORIZONTALBARS;
- break;
- case DP_TEST_PATTERN_COLOR_RAMP:
- controller_test_pattern =
- CONTROLLER_DP_TEST_PATTERN_COLORRAMP;
- break;
- default:
- controller_test_pattern =
- CONTROLLER_DP_TEST_PATTERN_VIDEOMODE;
- break;
- }
-
- switch (test_pattern) {
- case DP_TEST_PATTERN_COLOR_SQUARES:
- case DP_TEST_PATTERN_COLOR_SQUARES_CEA:
- case DP_TEST_PATTERN_VERTICAL_BARS:
- case DP_TEST_PATTERN_HORIZONTAL_BARS:
- case DP_TEST_PATTERN_COLOR_RAMP:
- {
- /* disable bit depth reduction */
- pipe_ctx->stream->bit_depth_params = params;
- opp->funcs->opp_program_bit_depth_reduction(opp, &params);
- if (pipe_ctx->stream_res.tg->funcs->set_test_pattern)
- pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg,
- controller_test_pattern, color_depth);
- else if (link->dc->hwss.set_disp_pattern_generator) {
- struct pipe_ctx *odm_pipe;
- enum controller_dp_color_space controller_color_space;
- int opp_cnt = 1;
- int offset = 0;
- int dpg_width = width;
-
- switch (test_pattern_color_space) {
- case DP_TEST_PATTERN_COLOR_SPACE_RGB:
- controller_color_space = CONTROLLER_DP_COLOR_SPACE_RGB;
- break;
- case DP_TEST_PATTERN_COLOR_SPACE_YCBCR601:
- controller_color_space = CONTROLLER_DP_COLOR_SPACE_YCBCR601;
- break;
- case DP_TEST_PATTERN_COLOR_SPACE_YCBCR709:
- controller_color_space = CONTROLLER_DP_COLOR_SPACE_YCBCR709;
- break;
- case DP_TEST_PATTERN_COLOR_SPACE_UNDEFINED:
- default:
- controller_color_space = CONTROLLER_DP_COLOR_SPACE_UDEFINED;
- DC_LOG_ERROR("%s: Color space must be defined for test pattern", __func__);
- ASSERT(0);
- break;
- }
-
- for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
- opp_cnt++;
- dpg_width = width / opp_cnt;
- offset = dpg_width;
-
- link->dc->hwss.set_disp_pattern_generator(link->dc,
- pipe_ctx,
- controller_test_pattern,
- controller_color_space,
- color_depth,
- NULL,
- dpg_width,
- height,
- 0);
-
- for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
- struct output_pixel_processor *odm_opp = odm_pipe->stream_res.opp;
-
- odm_opp->funcs->opp_program_bit_depth_reduction(odm_opp, &params);
- link->dc->hwss.set_disp_pattern_generator(link->dc,
- odm_pipe,
- controller_test_pattern,
- controller_color_space,
- color_depth,
- NULL,
- dpg_width,
- height,
- offset);
- offset += offset;
- }
- }
- }
- break;
- case DP_TEST_PATTERN_VIDEO_MODE:
- {
- /* restore bitdepth reduction */
- resource_build_bit_depth_reduction_params(pipe_ctx->stream, &params);
- pipe_ctx->stream->bit_depth_params = params;
- opp->funcs->opp_program_bit_depth_reduction(opp, &params);
- if (pipe_ctx->stream_res.tg->funcs->set_test_pattern)
- pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg,
- CONTROLLER_DP_TEST_PATTERN_VIDEOMODE,
- color_depth);
- else if (link->dc->hwss.set_disp_pattern_generator) {
- struct pipe_ctx *odm_pipe;
- int opp_cnt = 1;
- int dpg_width;
-
- for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
- opp_cnt++;
-
- dpg_width = width / opp_cnt;
- for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
- struct output_pixel_processor *odm_opp = odm_pipe->stream_res.opp;
-
- odm_opp->funcs->opp_program_bit_depth_reduction(odm_opp, &params);
- link->dc->hwss.set_disp_pattern_generator(link->dc,
- odm_pipe,
- CONTROLLER_DP_TEST_PATTERN_VIDEOMODE,
- CONTROLLER_DP_COLOR_SPACE_UDEFINED,
- color_depth,
- NULL,
- dpg_width,
- height,
- 0);
- }
- link->dc->hwss.set_disp_pattern_generator(link->dc,
- pipe_ctx,
- CONTROLLER_DP_TEST_PATTERN_VIDEOMODE,
- CONTROLLER_DP_COLOR_SPACE_UDEFINED,
- color_depth,
- NULL,
- dpg_width,
- height,
- 0);
- }
- }
- break;
-
- default:
- break;
- }
-}
-
-bool dc_link_dp_set_test_pattern(
- struct dc_link *link,
- enum dp_test_pattern test_pattern,
- enum dp_test_pattern_color_space test_pattern_color_space,
- const struct link_training_settings *p_link_settings,
- const unsigned char *p_custom_pattern,
- unsigned int cust_pattern_size)
-{
- struct pipe_ctx *pipes = link->dc->current_state->res_ctx.pipe_ctx;
- struct pipe_ctx *pipe_ctx = NULL;
- unsigned int lane;
- unsigned int i;
- unsigned char link_qual_pattern[LANE_COUNT_DP_MAX] = {0};
- union dpcd_training_pattern training_pattern;
- enum dpcd_phy_test_patterns pattern;
-
- memset(&training_pattern, 0, sizeof(training_pattern));
-
- for (i = 0; i < MAX_PIPES; i++) {
- if (pipes[i].stream == NULL)
- continue;
-
- if (pipes[i].stream->link == link && !pipes[i].top_pipe && !pipes[i].prev_odm_pipe) {
- pipe_ctx = &pipes[i];
- break;
- }
- }
-
- if (pipe_ctx == NULL)
- return false;
-
- /* Reset CRTC Test Pattern if it is currently running and request is VideoMode */
- if (link->test_pattern_enabled && test_pattern ==
- DP_TEST_PATTERN_VIDEO_MODE) {
- /* Set CRTC Test Pattern */
- set_crtc_test_pattern(link, pipe_ctx, test_pattern, test_pattern_color_space);
- dp_set_hw_test_pattern(link, &pipe_ctx->link_res, test_pattern,
- (uint8_t *)p_custom_pattern,
- (uint32_t)cust_pattern_size);
-
- /* Unblank Stream */
- link->dc->hwss.unblank_stream(
- pipe_ctx,
- &link->verified_link_cap);
- /* TODO:m_pHwss->MuteAudioEndpoint
- * (pPathMode->pDisplayPath, false);
- */
-
- /* Reset Test Pattern state */
- link->test_pattern_enabled = false;
-
- return true;
- }
-
- /* Check for PHY Test Patterns */
- if (is_dp_phy_pattern(test_pattern)) {
- /* Set DPCD Lane Settings before running test pattern */
- if (p_link_settings != NULL) {
- if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) &&
- p_link_settings->lttpr_mode == LTTPR_MODE_TRANSPARENT) {
- dp_fixed_vs_pe_set_retimer_lane_settings(
- link,
- p_link_settings->dpcd_lane_settings,
- p_link_settings->link_settings.lane_count);
- } else {
- dp_set_hw_lane_settings(link, &pipe_ctx->link_res, p_link_settings, DPRX);
- }
- dpcd_set_lane_settings(link, p_link_settings, DPRX);
- }
-
- /* Blank stream if running test pattern */
- if (test_pattern != DP_TEST_PATTERN_VIDEO_MODE) {
- /*TODO:
- * m_pHwss->
- * MuteAudioEndpoint(pPathMode->pDisplayPath, true);
- */
- /* Blank stream */
- pipes->stream_res.stream_enc->funcs->dp_blank(link, pipe_ctx->stream_res.stream_enc);
- }
-
- dp_set_hw_test_pattern(link, &pipe_ctx->link_res, test_pattern,
- (uint8_t *)p_custom_pattern,
- (uint32_t)cust_pattern_size);
-
- if (test_pattern != DP_TEST_PATTERN_VIDEO_MODE) {
- /* Set Test Pattern state */
- link->test_pattern_enabled = true;
- if (p_link_settings != NULL)
- dpcd_set_link_settings(link,
- p_link_settings);
- }
-
- switch (test_pattern) {
- case DP_TEST_PATTERN_VIDEO_MODE:
- pattern = PHY_TEST_PATTERN_NONE;
- break;
- case DP_TEST_PATTERN_D102:
- pattern = PHY_TEST_PATTERN_D10_2;
- break;
- case DP_TEST_PATTERN_SYMBOL_ERROR:
- pattern = PHY_TEST_PATTERN_SYMBOL_ERROR;
- break;
- case DP_TEST_PATTERN_PRBS7:
- pattern = PHY_TEST_PATTERN_PRBS7;
- break;
- case DP_TEST_PATTERN_80BIT_CUSTOM:
- pattern = PHY_TEST_PATTERN_80BIT_CUSTOM;
- break;
- case DP_TEST_PATTERN_CP2520_1:
- pattern = PHY_TEST_PATTERN_CP2520_1;
- break;
- case DP_TEST_PATTERN_CP2520_2:
- pattern = PHY_TEST_PATTERN_CP2520_2;
- break;
- case DP_TEST_PATTERN_CP2520_3:
- pattern = PHY_TEST_PATTERN_CP2520_3;
- break;
- case DP_TEST_PATTERN_128b_132b_TPS1:
- pattern = PHY_TEST_PATTERN_128b_132b_TPS1;
- break;
- case DP_TEST_PATTERN_128b_132b_TPS2:
- pattern = PHY_TEST_PATTERN_128b_132b_TPS2;
- break;
- case DP_TEST_PATTERN_PRBS9:
- pattern = PHY_TEST_PATTERN_PRBS9;
- break;
- case DP_TEST_PATTERN_PRBS11:
- pattern = PHY_TEST_PATTERN_PRBS11;
- break;
- case DP_TEST_PATTERN_PRBS15:
- pattern = PHY_TEST_PATTERN_PRBS15;
- break;
- case DP_TEST_PATTERN_PRBS23:
- pattern = PHY_TEST_PATTERN_PRBS23;
- break;
- case DP_TEST_PATTERN_PRBS31:
- pattern = PHY_TEST_PATTERN_PRBS31;
- break;
- case DP_TEST_PATTERN_264BIT_CUSTOM:
- pattern = PHY_TEST_PATTERN_264BIT_CUSTOM;
- break;
- case DP_TEST_PATTERN_SQUARE_PULSE:
- pattern = PHY_TEST_PATTERN_SQUARE_PULSE;
- break;
- default:
- return false;
- }
-
- if (test_pattern == DP_TEST_PATTERN_VIDEO_MODE
- /*TODO:&& !pPathMode->pDisplayPath->IsTargetPoweredOn()*/)
- return false;
-
- if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_12) {
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- if (test_pattern == DP_TEST_PATTERN_SQUARE_PULSE)
- core_link_write_dpcd(link,
- DP_LINK_SQUARE_PATTERN,
- p_custom_pattern,
- 1);
-
-#endif
- /* tell receiver that we are sending qualification
- * pattern DP 1.2 or later - DP receiver's link quality
- * pattern is set using DPCD LINK_QUAL_LANEx_SET
- * register (0x10B~0x10E)\
- */
- for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++)
- link_qual_pattern[lane] =
- (unsigned char)(pattern);
-
- core_link_write_dpcd(link,
- DP_LINK_QUAL_LANE0_SET,
- link_qual_pattern,
- sizeof(link_qual_pattern));
- } else if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_10 ||
- link->dpcd_caps.dpcd_rev.raw == 0) {
- /* tell receiver that we are sending qualification
- * pattern DP 1.1a or earlier - DP receiver's link
- * quality pattern is set using
- * DPCD TRAINING_PATTERN_SET -> LINK_QUAL_PATTERN_SET
- * register (0x102). We will use v_1.3 when we are
- * setting test pattern for DP 1.1.
- */
- core_link_read_dpcd(link, DP_TRAINING_PATTERN_SET,
- &training_pattern.raw,
- sizeof(training_pattern));
- training_pattern.v1_3.LINK_QUAL_PATTERN_SET = pattern;
- core_link_write_dpcd(link, DP_TRAINING_PATTERN_SET,
- &training_pattern.raw,
- sizeof(training_pattern));
- }
- } else {
- enum dc_color_space color_space = COLOR_SPACE_UNKNOWN;
-
- switch (test_pattern_color_space) {
- case DP_TEST_PATTERN_COLOR_SPACE_RGB:
- color_space = COLOR_SPACE_SRGB;
- if (test_pattern == DP_TEST_PATTERN_COLOR_SQUARES_CEA)
- color_space = COLOR_SPACE_SRGB_LIMITED;
- break;
-
- case DP_TEST_PATTERN_COLOR_SPACE_YCBCR601:
- color_space = COLOR_SPACE_YCBCR601;
- if (test_pattern == DP_TEST_PATTERN_COLOR_SQUARES_CEA)
- color_space = COLOR_SPACE_YCBCR601_LIMITED;
- break;
- case DP_TEST_PATTERN_COLOR_SPACE_YCBCR709:
- color_space = COLOR_SPACE_YCBCR709;
- if (test_pattern == DP_TEST_PATTERN_COLOR_SQUARES_CEA)
- color_space = COLOR_SPACE_YCBCR709_LIMITED;
- break;
- default:
- break;
- }
-
- if (pipe_ctx->stream_res.tg->funcs->lock_doublebuffer_enable) {
- if (pipe_ctx->stream && should_use_dmub_lock(pipe_ctx->stream->link)) {
- union dmub_hw_lock_flags hw_locks = { 0 };
- struct dmub_hw_lock_inst_flags inst_flags = { 0 };
-
- hw_locks.bits.lock_dig = 1;
- inst_flags.dig_inst = pipe_ctx->stream_res.tg->inst;
-
- dmub_hw_lock_mgr_cmd(link->ctx->dmub_srv,
- true,
- &hw_locks,
- &inst_flags);
- } else
- pipe_ctx->stream_res.tg->funcs->lock_doublebuffer_enable(
- pipe_ctx->stream_res.tg);
- }
-
- pipe_ctx->stream_res.tg->funcs->lock(pipe_ctx->stream_res.tg);
- /* update MSA to requested color space */
- pipe_ctx->stream_res.stream_enc->funcs->dp_set_stream_attribute(pipe_ctx->stream_res.stream_enc,
- &pipe_ctx->stream->timing,
- color_space,
- pipe_ctx->stream->use_vsc_sdp_for_colorimetry,
- link->dpcd_caps.dprx_feature.bits.SST_SPLIT_SDP_CAP);
-
- if (pipe_ctx->stream->use_vsc_sdp_for_colorimetry) {
- if (test_pattern == DP_TEST_PATTERN_COLOR_SQUARES_CEA)
- pipe_ctx->stream->vsc_infopacket.sb[17] |= (1 << 7); // sb17 bit 7 Dynamic Range: 0 = VESA range, 1 = CTA range
- else
- pipe_ctx->stream->vsc_infopacket.sb[17] &= ~(1 << 7);
- resource_build_info_frame(pipe_ctx);
- link->dc->hwss.update_info_frame(pipe_ctx);
- }
-
- /* CRTC Patterns */
- set_crtc_test_pattern(link, pipe_ctx, test_pattern, test_pattern_color_space);
- pipe_ctx->stream_res.tg->funcs->unlock(pipe_ctx->stream_res.tg);
- pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg,
- CRTC_STATE_VACTIVE);
- pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg,
- CRTC_STATE_VBLANK);
- pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg,
- CRTC_STATE_VACTIVE);
-
- if (pipe_ctx->stream_res.tg->funcs->lock_doublebuffer_disable) {
- if (pipe_ctx->stream && should_use_dmub_lock(pipe_ctx->stream->link)) {
- union dmub_hw_lock_flags hw_locks = { 0 };
- struct dmub_hw_lock_inst_flags inst_flags = { 0 };
-
- hw_locks.bits.lock_dig = 1;
- inst_flags.dig_inst = pipe_ctx->stream_res.tg->inst;
-
- dmub_hw_lock_mgr_cmd(link->ctx->dmub_srv,
- false,
- &hw_locks,
- &inst_flags);
- } else
- pipe_ctx->stream_res.tg->funcs->lock_doublebuffer_disable(
- pipe_ctx->stream_res.tg);
- }
-
- /* Set Test Pattern state */
- link->test_pattern_enabled = true;
- }
-
- return true;
-}
-
-void dp_enable_mst_on_sink(struct dc_link *link, bool enable)
-{
- unsigned char mstmCntl;
-
- core_link_read_dpcd(link, DP_MSTM_CTRL, &mstmCntl, 1);
- if (enable)
- mstmCntl |= DP_MST_EN;
- else
- mstmCntl &= (~DP_MST_EN);
-
- core_link_write_dpcd(link, DP_MSTM_CTRL, &mstmCntl, 1);
-}
-
-void dp_set_panel_mode(struct dc_link *link, enum dp_panel_mode panel_mode)
-{
- union dpcd_edp_config edp_config_set;
- bool panel_mode_edp = false;
-
- memset(&edp_config_set, '\0', sizeof(union dpcd_edp_config));
-
- if (panel_mode != DP_PANEL_MODE_DEFAULT) {
-
- switch (panel_mode) {
- case DP_PANEL_MODE_EDP:
- case DP_PANEL_MODE_SPECIAL:
- panel_mode_edp = true;
- break;
-
- default:
- break;
- }
-
- /*set edp panel mode in receiver*/
- core_link_read_dpcd(
- link,
- DP_EDP_CONFIGURATION_SET,
- &edp_config_set.raw,
- sizeof(edp_config_set.raw));
-
- if (edp_config_set.bits.PANEL_MODE_EDP
- != panel_mode_edp) {
- enum dc_status result;
-
- edp_config_set.bits.PANEL_MODE_EDP =
- panel_mode_edp;
- result = core_link_write_dpcd(
- link,
- DP_EDP_CONFIGURATION_SET,
- &edp_config_set.raw,
- sizeof(edp_config_set.raw));
-
- ASSERT(result == DC_OK);
- }
- }
- DC_LOG_DETECTION_DP_CAPS("Link: %d eDP panel mode supported: %d "
- "eDP panel mode enabled: %d \n",
- link->link_index,
- link->dpcd_caps.panel_mode_edp,
- panel_mode_edp);
-}
-
-enum dp_panel_mode dp_get_panel_mode(struct dc_link *link)
-{
- /* We need to explicitly check that connector
- * is not DP. Some Travis_VGA get reported
- * by video bios as DP.
- */
- if (link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT) {
-
- switch (link->dpcd_caps.branch_dev_id) {
- case DP_BRANCH_DEVICE_ID_0022B9:
- /* alternate scrambler reset is required for Travis
- * for the case when external chip does not
- * provide sink device id, alternate scrambler
- * scheme will be overriden later by querying
- * Encoder features
- */
- if (strncmp(
- link->dpcd_caps.branch_dev_name,
- DP_VGA_LVDS_CONVERTER_ID_2,
- sizeof(
- link->dpcd_caps.
- branch_dev_name)) == 0) {
- return DP_PANEL_MODE_SPECIAL;
- }
- break;
- case DP_BRANCH_DEVICE_ID_00001A:
- /* alternate scrambler reset is required for Travis
- * for the case when external chip does not provide
- * sink device id, alternate scrambler scheme will
- * be overriden later by querying Encoder feature
- */
- if (strncmp(link->dpcd_caps.branch_dev_name,
- DP_VGA_LVDS_CONVERTER_ID_3,
- sizeof(
- link->dpcd_caps.
- branch_dev_name)) == 0) {
- return DP_PANEL_MODE_SPECIAL;
- }
- break;
- default:
- break;
- }
- }
-
- if (link->dpcd_caps.panel_mode_edp &&
- (link->connector_signal == SIGNAL_TYPE_EDP ||
- (link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT &&
- link->is_internal_display))) {
- return DP_PANEL_MODE_EDP;
- }
-
- return DP_PANEL_MODE_DEFAULT;
-}
-
-enum dc_status dp_set_fec_ready(struct dc_link *link, const struct link_resource *link_res, bool ready)
-{
- /* FEC has to be "set ready" before the link training.
- * The policy is to always train with FEC
- * if the sink supports it and leave it enabled on link.
- * If FEC is not supported, disable it.
- */
- struct link_encoder *link_enc = NULL;
- enum dc_status status = DC_OK;
- uint8_t fec_config = 0;
-
- link_enc = link_enc_cfg_get_link_enc(link);
- ASSERT(link_enc);
-
- if (!dc_link_should_enable_fec(link))
- return status;
-
- if (link_enc->funcs->fec_set_ready &&
- link->dpcd_caps.fec_cap.bits.FEC_CAPABLE) {
- if (ready) {
- fec_config = 1;
- status = core_link_write_dpcd(link,
- DP_FEC_CONFIGURATION,
- &fec_config,
- sizeof(fec_config));
- if (status == DC_OK) {
- link_enc->funcs->fec_set_ready(link_enc, true);
- link->fec_state = dc_link_fec_ready;
- } else {
- link_enc->funcs->fec_set_ready(link_enc, false);
- link->fec_state = dc_link_fec_not_ready;
- dm_error("dpcd write failed to set fec_ready");
- }
- } else if (link->fec_state == dc_link_fec_ready) {
- fec_config = 0;
- status = core_link_write_dpcd(link,
- DP_FEC_CONFIGURATION,
- &fec_config,
- sizeof(fec_config));
- link_enc->funcs->fec_set_ready(link_enc, false);
- link->fec_state = dc_link_fec_not_ready;
- }
- }
-
- return status;
-}
-
-void dp_set_fec_enable(struct dc_link *link, bool enable)
-{
- struct link_encoder *link_enc = NULL;
-
- link_enc = link_enc_cfg_get_link_enc(link);
- ASSERT(link_enc);
-
- if (!dc_link_should_enable_fec(link))
- return;
-
- if (link_enc->funcs->fec_set_enable &&
- link->dpcd_caps.fec_cap.bits.FEC_CAPABLE) {
- if (link->fec_state == dc_link_fec_ready && enable) {
- /* Accord to DP spec, FEC enable sequence can first
- * be transmitted anytime after 1000 LL codes have
- * been transmitted on the link after link training
- * completion. Using 1 lane RBR should have the maximum
- * time for transmitting 1000 LL codes which is 6.173 us.
- * So use 7 microseconds delay instead.
- */
- udelay(7);
- link_enc->funcs->fec_set_enable(link_enc, true);
- link->fec_state = dc_link_fec_enabled;
- } else if (link->fec_state == dc_link_fec_enabled && !enable) {
- link_enc->funcs->fec_set_enable(link_enc, false);
- link->fec_state = dc_link_fec_ready;
- }
- }
-}
-
-void dpcd_set_source_specific_data(struct dc_link *link)
-{
- if (!link->dc->vendor_signature.is_valid) {
- enum dc_status __maybe_unused result_write_min_hblank = DC_NOT_SUPPORTED;
- struct dpcd_amd_signature amd_signature = {0};
- struct dpcd_amd_device_id amd_device_id = {0};
-
- amd_device_id.device_id_byte1 =
- (uint8_t)(link->ctx->asic_id.chip_id);
- amd_device_id.device_id_byte2 =
- (uint8_t)(link->ctx->asic_id.chip_id >> 8);
- amd_device_id.dce_version =
- (uint8_t)(link->ctx->dce_version);
- amd_device_id.dal_version_byte1 = 0x0; // needed? where to get?
- amd_device_id.dal_version_byte2 = 0x0; // needed? where to get?
-
- core_link_read_dpcd(link, DP_SOURCE_OUI,
- (uint8_t *)(&amd_signature),
- sizeof(amd_signature));
-
- if (!((amd_signature.AMD_IEEE_TxSignature_byte1 == 0x0) &&
- (amd_signature.AMD_IEEE_TxSignature_byte2 == 0x0) &&
- (amd_signature.AMD_IEEE_TxSignature_byte3 == 0x1A))) {
-
- amd_signature.AMD_IEEE_TxSignature_byte1 = 0x0;
- amd_signature.AMD_IEEE_TxSignature_byte2 = 0x0;
- amd_signature.AMD_IEEE_TxSignature_byte3 = 0x1A;
-
- core_link_write_dpcd(link, DP_SOURCE_OUI,
- (uint8_t *)(&amd_signature),
- sizeof(amd_signature));
- }
-
- core_link_write_dpcd(link, DP_SOURCE_OUI+0x03,
- (uint8_t *)(&amd_device_id),
- sizeof(amd_device_id));
-
- if (link->ctx->dce_version >= DCN_VERSION_2_0 &&
- link->dc->caps.min_horizontal_blanking_period != 0) {
-
- uint8_t hblank_size = (uint8_t)link->dc->caps.min_horizontal_blanking_period;
-
- if (link->preferred_link_setting.dpcd_source_device_specific_field_support) {
- result_write_min_hblank = core_link_write_dpcd(link,
- DP_SOURCE_MINIMUM_HBLANK_SUPPORTED, (uint8_t *)(&hblank_size),
- sizeof(hblank_size));
-
- if (result_write_min_hblank == DC_ERROR_UNEXPECTED)
- link->preferred_link_setting.dpcd_source_device_specific_field_support = false;
- } else {
- DC_LOG_DC("Sink device does not support 00340h DPCD write. Skipping on purpose.\n");
- }
- }
-
- DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION,
- WPP_BIT_FLAG_DC_DETECTION_DP_CAPS,
- "result=%u link_index=%u enum dce_version=%d DPCD=0x%04X min_hblank=%u branch_dev_id=0x%x branch_dev_name='%c%c%c%c%c%c'",
- result_write_min_hblank,
- link->link_index,
- link->ctx->dce_version,
- DP_SOURCE_MINIMUM_HBLANK_SUPPORTED,
- link->dc->caps.min_horizontal_blanking_period,
- link->dpcd_caps.branch_dev_id,
- link->dpcd_caps.branch_dev_name[0],
- link->dpcd_caps.branch_dev_name[1],
- link->dpcd_caps.branch_dev_name[2],
- link->dpcd_caps.branch_dev_name[3],
- link->dpcd_caps.branch_dev_name[4],
- link->dpcd_caps.branch_dev_name[5]);
- } else {
- core_link_write_dpcd(link, DP_SOURCE_OUI,
- link->dc->vendor_signature.data.raw,
- sizeof(link->dc->vendor_signature.data.raw));
- }
-}
-
-void dpcd_write_cable_id_to_dprx(struct dc_link *link)
-{
- if (!link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED ||
- link->dpcd_caps.cable_id.raw == 0 ||
- link->dprx_states.cable_id_written)
- return;
-
- core_link_write_dpcd(link, DP_CABLE_ATTRIBUTES_UPDATED_BY_DPTX,
- &link->dpcd_caps.cable_id.raw,
- sizeof(link->dpcd_caps.cable_id.raw));
-
- link->dprx_states.cable_id_written = 1;
-}
-
-bool dc_link_set_backlight_level_nits(struct dc_link *link,
- bool isHDR,
- uint32_t backlight_millinits,
- uint32_t transition_time_in_ms)
-{
- struct dpcd_source_backlight_set dpcd_backlight_set;
- uint8_t backlight_control = isHDR ? 1 : 0;
-
- if (!link || (link->connector_signal != SIGNAL_TYPE_EDP &&
- link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT))
- return false;
-
- // OLEDs have no PWM, they can only use AUX
- if (link->dpcd_sink_ext_caps.bits.oled == 1)
- backlight_control = 1;
-
- *(uint32_t *)&dpcd_backlight_set.backlight_level_millinits = backlight_millinits;
- *(uint16_t *)&dpcd_backlight_set.backlight_transition_time_ms = (uint16_t)transition_time_in_ms;
-
-
- if (core_link_write_dpcd(link, DP_SOURCE_BACKLIGHT_LEVEL,
- (uint8_t *)(&dpcd_backlight_set),
- sizeof(dpcd_backlight_set)) != DC_OK)
- return false;
-
- if (core_link_write_dpcd(link, DP_SOURCE_BACKLIGHT_CONTROL,
- &backlight_control, 1) != DC_OK)
- return false;
-
- return true;
-}
-
-bool dc_link_get_backlight_level_nits(struct dc_link *link,
- uint32_t *backlight_millinits_avg,
- uint32_t *backlight_millinits_peak)
-{
- union dpcd_source_backlight_get dpcd_backlight_get;
-
- memset(&dpcd_backlight_get, 0, sizeof(union dpcd_source_backlight_get));
-
- if (!link || (link->connector_signal != SIGNAL_TYPE_EDP &&
- link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT))
- return false;
-
- if (core_link_read_dpcd(link, DP_SOURCE_BACKLIGHT_CURRENT_PEAK,
- dpcd_backlight_get.raw,
- sizeof(union dpcd_source_backlight_get)) != DC_OK)
- return false;
-
- *backlight_millinits_avg =
- dpcd_backlight_get.bytes.backlight_millinits_avg;
- *backlight_millinits_peak =
- dpcd_backlight_get.bytes.backlight_millinits_peak;
-
- /* On non-supported panels dpcd_read usually succeeds with 0 returned */
- if (*backlight_millinits_avg == 0 ||
- *backlight_millinits_avg > *backlight_millinits_peak)
- return false;
-
- return true;
-}
-
-bool dc_link_backlight_enable_aux(struct dc_link *link, bool enable)
-{
- uint8_t backlight_enable = enable ? 1 : 0;
-
- if (!link || (link->connector_signal != SIGNAL_TYPE_EDP &&
- link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT))
- return false;
-
- if (core_link_write_dpcd(link, DP_SOURCE_BACKLIGHT_ENABLE,
- &backlight_enable, 1) != DC_OK)
- return false;
-
- return true;
-}
-
-// we read default from 0x320 because we expect BIOS wrote it there
-// regular get_backlight_nit reads from panel set at 0x326
-bool dc_link_read_default_bl_aux(struct dc_link *link, uint32_t *backlight_millinits)
-{
- if (!link || (link->connector_signal != SIGNAL_TYPE_EDP &&
- link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT))
- return false;
-
- if (core_link_read_dpcd(link, DP_SOURCE_BACKLIGHT_LEVEL,
- (uint8_t *) backlight_millinits,
- sizeof(uint32_t)) != DC_OK)
- return false;
-
- return true;
-}
-
-bool dc_link_set_default_brightness_aux(struct dc_link *link)
-{
- uint32_t default_backlight;
-
- if (link && link->dpcd_sink_ext_caps.bits.oled == 1) {
- if (!dc_link_read_default_bl_aux(link, &default_backlight))
- default_backlight = 150000;
- // if < 5 nits or > 5000, it might be wrong readback
- if (default_backlight < 5000 || default_backlight > 5000000)
- default_backlight = 150000; //
-
- return dc_link_set_backlight_level_nits(link, true,
- default_backlight, 0);
- }
- return false;
-}
-
-bool is_edp_ilr_optimization_required(struct dc_link *link, struct dc_crtc_timing *crtc_timing)
-{
- struct dc_link_settings link_setting;
- uint8_t link_bw_set;
- uint8_t link_rate_set;
- uint32_t req_bw;
- union lane_count_set lane_count_set = {0};
-
- ASSERT(link || crtc_timing); // invalid input
-
- if (link->dpcd_caps.edp_supported_link_rates_count == 0 ||
- !link->panel_config.ilr.optimize_edp_link_rate)
- return false;
-
-
- // Read DPCD 00100h to find if standard link rates are set
- core_link_read_dpcd(link, DP_LINK_BW_SET,
- &link_bw_set, sizeof(link_bw_set));
-
- if (link_bw_set) {
- DC_LOG_EVENT_LINK_TRAINING("eDP ILR: Optimization required, VBIOS used link_bw_set\n");
- return true;
- }
-
- // Read DPCD 00115h to find the edp link rate set used
- core_link_read_dpcd(link, DP_LINK_RATE_SET,
- &link_rate_set, sizeof(link_rate_set));
-
- // Read DPCD 00101h to find out the number of lanes currently set
- core_link_read_dpcd(link, DP_LANE_COUNT_SET,
- &lane_count_set.raw, sizeof(lane_count_set));
-
- req_bw = dc_bandwidth_in_kbps_from_timing(crtc_timing);
-
- if (!crtc_timing->flags.DSC)
- decide_edp_link_settings(link, &link_setting, req_bw);
- else
- decide_edp_link_settings_with_dsc(link, &link_setting, req_bw, LINK_RATE_UNKNOWN);
-
- if (link->dpcd_caps.edp_supported_link_rates[link_rate_set] != link_setting.link_rate ||
- lane_count_set.bits.LANE_COUNT_SET != link_setting.lane_count) {
- DC_LOG_EVENT_LINK_TRAINING("eDP ILR: Optimization required, VBIOS link_rate_set not optimal\n");
- return true;
- }
-
- DC_LOG_EVENT_LINK_TRAINING("eDP ILR: No optimization required, VBIOS set optimal link_rate_set\n");
- return false;
-}
-
-enum dp_link_encoding dp_get_link_encoding_format(const struct dc_link_settings *link_settings)
-{
- if ((link_settings->link_rate >= LINK_RATE_LOW) &&
- (link_settings->link_rate <= LINK_RATE_HIGH3))
- return DP_8b_10b_ENCODING;
- else if ((link_settings->link_rate >= LINK_RATE_UHBR10) &&
- (link_settings->link_rate <= LINK_RATE_UHBR20))
- return DP_128b_132b_ENCODING;
- return DP_UNKNOWN_ENCODING;
-}
-
-enum dp_link_encoding dc_link_dp_mst_decide_link_encoding_format(const struct dc_link *link)
-{
- struct dc_link_settings link_settings = {0};
-
- if (!dc_is_dp_signal(link->connector_signal))
- return DP_UNKNOWN_ENCODING;
-
- if (link->preferred_link_setting.lane_count !=
- LANE_COUNT_UNKNOWN &&
- link->preferred_link_setting.link_rate !=
- LINK_RATE_UNKNOWN) {
- link_settings = link->preferred_link_setting;
- } else {
- decide_mst_link_settings(link, &link_settings);
- }
-
- return dp_get_link_encoding_format(&link_settings);
-}
-
-// TODO - DP2.0 Link: Fix get_lane_status to handle LTTPR offset (SST and MST)
-static void get_lane_status(
- struct dc_link *link,
- uint32_t lane_count,
- union lane_status *status,
- union lane_align_status_updated *status_updated)
-{
- unsigned int lane;
- uint8_t dpcd_buf[3] = {0};
-
- if (status == NULL || status_updated == NULL) {
- return;
- }
-
- core_link_read_dpcd(
- link,
- DP_LANE0_1_STATUS,
- dpcd_buf,
- sizeof(dpcd_buf));
-
- for (lane = 0; lane < lane_count; lane++) {
- status[lane].raw = get_nibble_at_index(&dpcd_buf[0], lane);
- }
-
- status_updated->raw = dpcd_buf[2];
-}
-
-bool dpcd_write_128b_132b_sst_payload_allocation_table(
- const struct dc_stream_state *stream,
- struct dc_link *link,
- struct link_mst_stream_allocation_table *proposed_table,
- bool allocate)
-{
- const uint8_t vc_id = 1; /// VC ID always 1 for SST
- const uint8_t start_time_slot = 0; /// Always start at time slot 0 for SST
- bool result = false;
- uint8_t req_slot_count = 0;
- struct fixed31_32 avg_time_slots_per_mtp = { 0 };
- union payload_table_update_status update_status = { 0 };
- const uint32_t max_retries = 30;
- uint32_t retries = 0;
-
- if (allocate) {
- avg_time_slots_per_mtp = calculate_sst_avg_time_slots_per_mtp(stream, link);
- req_slot_count = dc_fixpt_ceil(avg_time_slots_per_mtp);
- /// Validation should filter out modes that exceed link BW
- ASSERT(req_slot_count <= MAX_MTP_SLOT_COUNT);
- if (req_slot_count > MAX_MTP_SLOT_COUNT)
- return false;
- } else {
- /// Leave req_slot_count = 0 if allocate is false.
- }
-
- proposed_table->stream_count = 1; /// Always 1 stream for SST
- proposed_table->stream_allocations[0].slot_count = req_slot_count;
- proposed_table->stream_allocations[0].vcp_id = vc_id;
-
- if (link->aux_access_disabled)
- return true;
-
- /// Write DPCD 2C0 = 1 to start updating
- update_status.bits.VC_PAYLOAD_TABLE_UPDATED = 1;
- core_link_write_dpcd(
- link,
- DP_PAYLOAD_TABLE_UPDATE_STATUS,
- &update_status.raw,
- 1);
-
- /// Program the changes in DPCD 1C0 - 1C2
- ASSERT(vc_id == 1);
- core_link_write_dpcd(
- link,
- DP_PAYLOAD_ALLOCATE_SET,
- &vc_id,
- 1);
-
- ASSERT(start_time_slot == 0);
- core_link_write_dpcd(
- link,
- DP_PAYLOAD_ALLOCATE_START_TIME_SLOT,
- &start_time_slot,
- 1);
-
- core_link_write_dpcd(
- link,
- DP_PAYLOAD_ALLOCATE_TIME_SLOT_COUNT,
- &req_slot_count,
- 1);
-
- /// Poll till DPCD 2C0 read 1
- /// Try for at least 150ms (30 retries, with 5ms delay after each attempt)
-
- while (retries < max_retries) {
- if (core_link_read_dpcd(
- link,
- DP_PAYLOAD_TABLE_UPDATE_STATUS,
- &update_status.raw,
- 1) == DC_OK) {
- if (update_status.bits.VC_PAYLOAD_TABLE_UPDATED == 1) {
- DC_LOG_DP2("SST Update Payload: downstream payload table updated.");
- result = true;
- break;
- }
- } else {
- union dpcd_rev dpcdRev;
-
- if (core_link_read_dpcd(
- link,
- DP_DPCD_REV,
- &dpcdRev.raw,
- 1) != DC_OK) {
- DC_LOG_ERROR("SST Update Payload: Unable to read DPCD revision "
- "of sink while polling payload table "
- "updated status bit.");
- break;
- }
- }
- retries++;
- msleep(5);
- }
-
- if (!result && retries == max_retries) {
- DC_LOG_ERROR("SST Update Payload: Payload table not updated after retries, "
- "continue on. Something is wrong with the branch.");
- // TODO - DP2.0 Payload: Read and log the payload table from downstream branch
- }
-
- return result;
-}
-
-bool dpcd_poll_for_allocation_change_trigger(struct dc_link *link)
-{
- /*
- * wait for ACT handled
- */
- int i;
- const int act_retries = 30;
- enum act_return_status result = ACT_FAILED;
- union payload_table_update_status update_status = {0};
- union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX];
- union lane_align_status_updated lane_status_updated;
-
- if (link->aux_access_disabled)
- return true;
- for (i = 0; i < act_retries; i++) {
- get_lane_status(link, link->cur_link_settings.lane_count, dpcd_lane_status, &lane_status_updated);
-
- if (!dp_is_cr_done(link->cur_link_settings.lane_count, dpcd_lane_status) ||
- !dp_is_ch_eq_done(link->cur_link_settings.lane_count, dpcd_lane_status) ||
- !dp_is_symbol_locked(link->cur_link_settings.lane_count, dpcd_lane_status) ||
- !dp_is_interlane_aligned(lane_status_updated)) {
- DC_LOG_ERROR("SST Update Payload: Link loss occurred while "
- "polling for ACT handled.");
- result = ACT_LINK_LOST;
- break;
- }
- core_link_read_dpcd(
- link,
- DP_PAYLOAD_TABLE_UPDATE_STATUS,
- &update_status.raw,
- 1);
-
- if (update_status.bits.ACT_HANDLED == 1) {
- DC_LOG_DP2("SST Update Payload: ACT handled by downstream.");
- result = ACT_SUCCESS;
- break;
- }
-
- msleep(5);
- }
-
- if (result == ACT_FAILED) {
- DC_LOG_ERROR("SST Update Payload: ACT still not handled after retries, "
- "continue on. Something is wrong with the branch.");
- }
-
- return (result == ACT_SUCCESS);
-}
-
-struct fixed31_32 calculate_sst_avg_time_slots_per_mtp(
- const struct dc_stream_state *stream,
- const struct dc_link *link)
-{
- struct fixed31_32 link_bw_effective =
- dc_fixpt_from_int(
- dc_link_bandwidth_kbps(link, &link->cur_link_settings));
- struct fixed31_32 timeslot_bw_effective =
- dc_fixpt_div_int(link_bw_effective, MAX_MTP_SLOT_COUNT);
- struct fixed31_32 timing_bw =
- dc_fixpt_from_int(
- dc_bandwidth_in_kbps_from_timing(&stream->timing));
- struct fixed31_32 avg_time_slots_per_mtp =
- dc_fixpt_div(timing_bw, timeslot_bw_effective);
-
- return avg_time_slots_per_mtp;
-}
-
-bool is_dp_128b_132b_signal(struct pipe_ctx *pipe_ctx)
-{
- /* If this assert is hit then we have a link encoder dynamic management issue */
- ASSERT(pipe_ctx->stream_res.hpo_dp_stream_enc ? pipe_ctx->link_res.hpo_dp_link_enc != NULL : true);
- return (pipe_ctx->stream_res.hpo_dp_stream_enc &&
- pipe_ctx->link_res.hpo_dp_link_enc &&
- dc_is_dp_signal(pipe_ctx->stream->signal));
-}
-
-void edp_panel_backlight_power_on(struct dc_link *link, bool wait_for_hpd)
-{
- if (link->connector_signal != SIGNAL_TYPE_EDP)
- return;
-
- link->dc->hwss.edp_power_control(link, true);
- if (wait_for_hpd)
- link->dc->hwss.edp_wait_for_hpd_ready(link, true);
- if (link->dc->hwss.edp_backlight_control)
- link->dc->hwss.edp_backlight_control(link, true);
-}
-
-void dc_link_clear_dprx_states(struct dc_link *link)
-{
- memset(&link->dprx_states, 0, sizeof(link->dprx_states));
-}
-
-void dp_receiver_power_ctrl(struct dc_link *link, bool on)
-{
- uint8_t state;
-
- state = on ? DP_POWER_STATE_D0 : DP_POWER_STATE_D3;
-
- if (link->sync_lt_in_progress)
- return;
-
- core_link_write_dpcd(link, DP_SET_POWER, &state,
- sizeof(state));
-
-}
-
-void dp_source_sequence_trace(struct dc_link *link, uint8_t dp_test_mode)
-{
- if (link != NULL && link->dc->debug.enable_driver_sequence_debug)
- core_link_write_dpcd(link, DP_SOURCE_SEQUENCE,
- &dp_test_mode, sizeof(dp_test_mode));
-}
-
-
-static uint8_t convert_to_count(uint8_t lttpr_repeater_count)
-{
- switch (lttpr_repeater_count) {
- case 0x80: // 1 lttpr repeater
- return 1;
- case 0x40: // 2 lttpr repeaters
- return 2;
- case 0x20: // 3 lttpr repeaters
- return 3;
- case 0x10: // 4 lttpr repeaters
- return 4;
- case 0x08: // 5 lttpr repeaters
- return 5;
- case 0x04: // 6 lttpr repeaters
- return 6;
- case 0x02: // 7 lttpr repeaters
- return 7;
- case 0x01: // 8 lttpr repeaters
- return 8;
- default:
- break;
- }
- return 0; // invalid value
-}
-
-static inline bool is_immediate_downstream(struct dc_link *link, uint32_t offset)
-{
- return (convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) == offset);
-}
-
-void dp_enable_link_phy(
- struct dc_link *link,
- const struct link_resource *link_res,
- enum signal_type signal,
- enum clock_source_id clock_source,
- const struct dc_link_settings *link_settings)
-{
- link->cur_link_settings = *link_settings;
- link->dc->hwss.enable_dp_link_output(link, link_res, signal,
- clock_source, link_settings);
- dp_receiver_power_ctrl(link, true);
-}
-
-void edp_add_delay_for_T9(struct dc_link *link)
-{
- if (link && link->panel_config.pps.extra_delay_backlight_off > 0)
- udelay(link->panel_config.pps.extra_delay_backlight_off * 1000);
-}
-
-bool edp_receiver_ready_T9(struct dc_link *link)
-{
- unsigned int tries = 0;
- unsigned char sinkstatus = 0;
- unsigned char edpRev = 0;
- enum dc_status result = DC_OK;
-
- result = core_link_read_dpcd(link, DP_EDP_DPCD_REV, &edpRev, sizeof(edpRev));
-
- /* start from eDP version 1.2, SINK_STAUS indicate the sink is ready.*/
- if (result == DC_OK && edpRev >= DP_EDP_12) {
- do {
- sinkstatus = 1;
- result = core_link_read_dpcd(link, DP_SINK_STATUS, &sinkstatus, sizeof(sinkstatus));
- if (sinkstatus == 0)
- break;
- if (result != DC_OK)
- break;
- udelay(100); //MAx T9
- } while (++tries < 50);
- }
-
- return result;
-}
-bool edp_receiver_ready_T7(struct dc_link *link)
-{
- unsigned char sinkstatus = 0;
- unsigned char edpRev = 0;
- enum dc_status result = DC_OK;
-
- /* use absolute time stamp to constrain max T7*/
- unsigned long long enter_timestamp = 0;
- unsigned long long finish_timestamp = 0;
- unsigned long long time_taken_in_ns = 0;
-
- result = core_link_read_dpcd(link, DP_EDP_DPCD_REV, &edpRev, sizeof(edpRev));
-
- if (result == DC_OK && edpRev >= DP_EDP_12) {
- /* start from eDP version 1.2, SINK_STAUS indicate the sink is ready.*/
- enter_timestamp = dm_get_timestamp(link->ctx);
- do {
- sinkstatus = 0;
- result = core_link_read_dpcd(link, DP_SINK_STATUS, &sinkstatus, sizeof(sinkstatus));
- if (sinkstatus == 1)
- break;
- if (result != DC_OK)
- break;
- udelay(25);
- finish_timestamp = dm_get_timestamp(link->ctx);
- time_taken_in_ns = dm_get_elapse_time_in_ns(link->ctx, finish_timestamp, enter_timestamp);
- } while (time_taken_in_ns < 50 * 1000000); //MAx T7 is 50ms
- }
-
- if (link && link->panel_config.pps.extra_t7_ms > 0)
- udelay(link->panel_config.pps.extra_t7_ms * 1000);
-
- return result;
-}
-
-void dp_disable_link_phy(struct dc_link *link, const struct link_resource *link_res,
- enum signal_type signal)
-{
- struct dc *dc = link->ctx->dc;
-
- if (!link->wa_flags.dp_keep_receiver_powered)
- dp_receiver_power_ctrl(link, false);
-
- dc->hwss.disable_link_output(link, link_res, signal);
- /* Clear current link setting.*/
- memset(&link->cur_link_settings, 0,
- sizeof(link->cur_link_settings));
-
- if (dc->clk_mgr->funcs->notify_link_rate_change)
- dc->clk_mgr->funcs->notify_link_rate_change(dc->clk_mgr, link);
-}
-
-void dp_disable_link_phy_mst(struct dc_link *link, const struct link_resource *link_res,
- enum signal_type signal)
-{
- /* MST disable link only when no stream use the link */
- if (link->mst_stream_alloc_table.stream_count > 0)
- return;
-
- dp_disable_link_phy(link, link_res, signal);
-
- /* set the sink to SST mode after disabling the link */
- dp_enable_mst_on_sink(link, false);
-}
-
-bool dp_set_hw_training_pattern(
- struct dc_link *link,
- const struct link_resource *link_res,
- enum dc_dp_training_pattern pattern,
- uint32_t offset)
-{
- enum dp_test_pattern test_pattern = DP_TEST_PATTERN_UNSUPPORTED;
-
- switch (pattern) {
- case DP_TRAINING_PATTERN_SEQUENCE_1:
- test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN1;
- break;
- case DP_TRAINING_PATTERN_SEQUENCE_2:
- test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN2;
- break;
- case DP_TRAINING_PATTERN_SEQUENCE_3:
- test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN3;
- break;
- case DP_TRAINING_PATTERN_SEQUENCE_4:
- test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN4;
- break;
- case DP_128b_132b_TPS1:
- test_pattern = DP_TEST_PATTERN_128b_132b_TPS1_TRAINING_MODE;
- break;
- case DP_128b_132b_TPS2:
- test_pattern = DP_TEST_PATTERN_128b_132b_TPS2_TRAINING_MODE;
- break;
- default:
- break;
- }
-
- dp_set_hw_test_pattern(link, link_res, test_pattern, NULL, 0);
-
- return true;
-}
-
-void dp_set_hw_lane_settings(
- struct dc_link *link,
- const struct link_resource *link_res,
- const struct link_training_settings *link_settings,
- uint32_t offset)
-{
- const struct link_hwss *link_hwss = get_link_hwss(link, link_res);
-
- if ((link_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) && !is_immediate_downstream(link, offset))
- return;
-
- if (link_hwss->ext.set_dp_lane_settings)
- link_hwss->ext.set_dp_lane_settings(link, link_res,
- &link_settings->link_settings,
- link_settings->hw_lane_settings);
-
- memmove(link->cur_lane_setting,
- link_settings->hw_lane_settings,
- sizeof(link->cur_lane_setting));
-}
-
-void dp_set_hw_test_pattern(
- struct dc_link *link,
- const struct link_resource *link_res,
- enum dp_test_pattern test_pattern,
- uint8_t *custom_pattern,
- uint32_t custom_pattern_size)
-{
- const struct link_hwss *link_hwss = get_link_hwss(link, link_res);
- struct encoder_set_dp_phy_pattern_param pattern_param = {0};
-
- pattern_param.dp_phy_pattern = test_pattern;
- pattern_param.custom_pattern = custom_pattern;
- pattern_param.custom_pattern_size = custom_pattern_size;
- pattern_param.dp_panel_mode = dp_get_panel_mode(link);
-
- if (link_hwss->ext.set_dp_link_test_pattern)
- link_hwss->ext.set_dp_link_test_pattern(link, link_res, &pattern_param);
-}
-
-void dp_retrain_link_dp_test(struct dc_link *link,
- struct dc_link_settings *link_setting,
- bool skip_video_pattern)
-{
- struct pipe_ctx *pipes =
- &link->dc->current_state->res_ctx.pipe_ctx[0];
- unsigned int i;
- bool do_fallback = false;
-
-
- for (i = 0; i < MAX_PIPES; i++) {
- if (pipes[i].stream != NULL &&
- !pipes[i].top_pipe && !pipes[i].prev_odm_pipe &&
- pipes[i].stream->link != NULL &&
- pipes[i].stream_res.stream_enc != NULL &&
- pipes[i].stream->link == link) {
- udelay(100);
-
- pipes[i].stream_res.stream_enc->funcs->dp_blank(link,
- pipes[i].stream_res.stream_enc);
-
- /* disable any test pattern that might be active */
- dp_set_hw_test_pattern(link, &pipes[i].link_res,
- DP_TEST_PATTERN_VIDEO_MODE, NULL, 0);
-
- dp_receiver_power_ctrl(link, false);
-
- link->dc->hwss.disable_stream(&pipes[i]);
- if ((&pipes[i])->stream_res.audio && !link->dc->debug.az_endpoint_mute_only)
- (&pipes[i])->stream_res.audio->funcs->az_disable((&pipes[i])->stream_res.audio);
-
- if (link->link_enc)
- link->link_enc->funcs->disable_output(
- link->link_enc,
- SIGNAL_TYPE_DISPLAY_PORT);
-
- /* Clear current link setting. */
- memset(&link->cur_link_settings, 0,
- sizeof(link->cur_link_settings));
-
- if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA)
- do_fallback = true;
-
- perform_link_training_with_retries(
- link_setting,
- skip_video_pattern,
- LINK_TRAINING_ATTEMPTS,
- &pipes[i],
- SIGNAL_TYPE_DISPLAY_PORT,
- do_fallback);
-
- link->dc->hwss.enable_stream(&pipes[i]);
-
- link->dc->hwss.unblank_stream(&pipes[i],
- link_setting);
-
- link->dc->hwss.enable_audio_stream(&pipes[i]);
- }
- }
-}
-
-#undef DC_LOGGER
-#define DC_LOGGER \
- dsc->ctx->logger
-static void dsc_optc_config_log(struct display_stream_compressor *dsc,
- struct dsc_optc_config *config)
-{
- uint32_t precision = 1 << 28;
- uint32_t bytes_per_pixel_int = config->bytes_per_pixel / precision;
- uint32_t bytes_per_pixel_mod = config->bytes_per_pixel % precision;
- uint64_t ll_bytes_per_pix_fraq = bytes_per_pixel_mod;
-
- /* 7 fractional digits decimal precision for bytes per pixel is enough because DSC
- * bits per pixel precision is 1/16th of a pixel, which means bytes per pixel precision is
- * 1/16/8 = 1/128 of a byte, or 0.0078125 decimal
- */
- ll_bytes_per_pix_fraq *= 10000000;
- ll_bytes_per_pix_fraq /= precision;
-
- DC_LOG_DSC("\tbytes_per_pixel 0x%08x (%d.%07d)",
- config->bytes_per_pixel, bytes_per_pixel_int, (uint32_t)ll_bytes_per_pix_fraq);
- DC_LOG_DSC("\tis_pixel_format_444 %d", config->is_pixel_format_444);
- DC_LOG_DSC("\tslice_width %d", config->slice_width);
-}
-
-bool dp_set_dsc_on_rx(struct pipe_ctx *pipe_ctx, bool enable)
-{
- struct dc *dc = pipe_ctx->stream->ctx->dc;
- struct dc_stream_state *stream = pipe_ctx->stream;
- bool result = false;
-
- if (dc_is_virtual_signal(stream->signal) || IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
- result = true;
- else
- result = dm_helpers_dp_write_dsc_enable(dc->ctx, stream, enable);
- return result;
-}
-
-/* The stream with these settings can be sent (unblanked) only after DSC was enabled on RX first,
- * i.e. after dp_enable_dsc_on_rx() had been called
- */
-void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
-{
- struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
- struct dc *dc = pipe_ctx->stream->ctx->dc;
- struct dc_stream_state *stream = pipe_ctx->stream;
- struct pipe_ctx *odm_pipe;
- int opp_cnt = 1;
-
- for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
- opp_cnt++;
-
- if (enable) {
- struct dsc_config dsc_cfg;
- struct dsc_optc_config dsc_optc_cfg;
- enum optc_dsc_mode optc_dsc_mode;
-
- /* Enable DSC hw block */
- dsc_cfg.pic_width = (stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right) / opp_cnt;
- dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom;
- dsc_cfg.pixel_encoding = stream->timing.pixel_encoding;
- dsc_cfg.color_depth = stream->timing.display_color_depth;
- dsc_cfg.is_odm = pipe_ctx->next_odm_pipe ? true : false;
- dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg;
- ASSERT(dsc_cfg.dc_dsc_cfg.num_slices_h % opp_cnt == 0);
- dsc_cfg.dc_dsc_cfg.num_slices_h /= opp_cnt;
-
- dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg);
- dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst);
- for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
- struct display_stream_compressor *odm_dsc = odm_pipe->stream_res.dsc;
-
- odm_dsc->funcs->dsc_set_config(odm_dsc, &dsc_cfg, &dsc_optc_cfg);
- odm_dsc->funcs->dsc_enable(odm_dsc, odm_pipe->stream_res.opp->inst);
- }
- dsc_cfg.dc_dsc_cfg.num_slices_h *= opp_cnt;
- dsc_cfg.pic_width *= opp_cnt;
-
- optc_dsc_mode = dsc_optc_cfg.is_pixel_format_444 ? OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED;
-
- /* Enable DSC in encoder */
- if (dc_is_dp_signal(stream->signal) && !IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)
- && !is_dp_128b_132b_signal(pipe_ctx)) {
- DC_LOG_DSC("Setting stream encoder DSC config for engine %d:", (int)pipe_ctx->stream_res.stream_enc->id);
- dsc_optc_config_log(dsc, &dsc_optc_cfg);
- pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config(pipe_ctx->stream_res.stream_enc,
- optc_dsc_mode,
- dsc_optc_cfg.bytes_per_pixel,
- dsc_optc_cfg.slice_width);
-
- /* PPS SDP is set elsewhere because it has to be done after DIG FE is connected to DIG BE */
- }
-
- /* Enable DSC in OPTC */
- DC_LOG_DSC("Setting optc DSC config for tg instance %d:", pipe_ctx->stream_res.tg->inst);
- dsc_optc_config_log(dsc, &dsc_optc_cfg);
- pipe_ctx->stream_res.tg->funcs->set_dsc_config(pipe_ctx->stream_res.tg,
- optc_dsc_mode,
- dsc_optc_cfg.bytes_per_pixel,
- dsc_optc_cfg.slice_width);
- } else {
- /* disable DSC in OPTC */
- pipe_ctx->stream_res.tg->funcs->set_dsc_config(
- pipe_ctx->stream_res.tg,
- OPTC_DSC_DISABLED, 0, 0);
-
- /* disable DSC in stream encoder */
- if (dc_is_dp_signal(stream->signal)) {
- if (is_dp_128b_132b_signal(pipe_ctx))
- pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_set_dsc_pps_info_packet(
- pipe_ctx->stream_res.hpo_dp_stream_enc,
- false,
- NULL,
- true);
- else if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
- pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config(
- pipe_ctx->stream_res.stream_enc,
- OPTC_DSC_DISABLED, 0, 0);
- pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet(
- pipe_ctx->stream_res.stream_enc, false, NULL, true);
- }
- }
-
- /* disable DSC block */
- pipe_ctx->stream_res.dsc->funcs->dsc_disable(pipe_ctx->stream_res.dsc);
- for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
- odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc);
- }
-}
-
-bool dp_set_dsc_enable(struct pipe_ctx *pipe_ctx, bool enable)
-{
- struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
- bool result = false;
-
- if (!pipe_ctx->stream->timing.flags.DSC)
- goto out;
- if (!dsc)
- goto out;
-
- if (enable) {
- {
- dp_set_dsc_on_stream(pipe_ctx, true);
- result = true;
- }
- } else {
- dp_set_dsc_on_rx(pipe_ctx, false);
- dp_set_dsc_on_stream(pipe_ctx, false);
- result = true;
- }
-out:
- return result;
-}
-
-/*
- * For dynamic bpp change case, dsc is programmed with MASTER_UPDATE_LOCK enabled;
- * hence PPS info packet update need to use frame update instead of immediate update.
- * Added parameter immediate_update for this purpose.
- * The decision to use frame update is hard-coded in function dp_update_dsc_config(),
- * which is the only place where a "false" would be passed in for param immediate_update.
- *
- * immediate_update is only applicable when DSC is enabled.
- */
-bool dp_set_dsc_pps_sdp(struct pipe_ctx *pipe_ctx, bool enable, bool immediate_update)
-{
- struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
- struct dc_stream_state *stream = pipe_ctx->stream;
-
- if (!pipe_ctx->stream->timing.flags.DSC || !dsc)
- return false;
-
- if (enable) {
- struct dsc_config dsc_cfg;
- uint8_t dsc_packed_pps[128];
-
- memset(&dsc_cfg, 0, sizeof(dsc_cfg));
- memset(dsc_packed_pps, 0, 128);
-
- /* Enable DSC hw block */
- dsc_cfg.pic_width = stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right;
- dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom;
- dsc_cfg.pixel_encoding = stream->timing.pixel_encoding;
- dsc_cfg.color_depth = stream->timing.display_color_depth;
- dsc_cfg.is_odm = pipe_ctx->next_odm_pipe ? true : false;
- dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg;
-
- DC_LOG_DSC(" ");
- dsc->funcs->dsc_get_packed_pps(dsc, &dsc_cfg, &dsc_packed_pps[0]);
- memcpy(&stream->dsc_packed_pps[0], &dsc_packed_pps[0], sizeof(stream->dsc_packed_pps));
- if (dc_is_dp_signal(stream->signal)) {
- DC_LOG_DSC("Setting stream encoder DSC PPS SDP for engine %d\n", (int)pipe_ctx->stream_res.stream_enc->id);
- if (is_dp_128b_132b_signal(pipe_ctx))
- pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_set_dsc_pps_info_packet(
- pipe_ctx->stream_res.hpo_dp_stream_enc,
- true,
- &dsc_packed_pps[0],
- immediate_update);
- else
- pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet(
- pipe_ctx->stream_res.stream_enc,
- true,
- &dsc_packed_pps[0],
- immediate_update);
- }
- } else {
- /* disable DSC PPS in stream encoder */
- memset(&stream->dsc_packed_pps[0], 0, sizeof(stream->dsc_packed_pps));
- if (dc_is_dp_signal(stream->signal)) {
- if (is_dp_128b_132b_signal(pipe_ctx))
- pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_set_dsc_pps_info_packet(
- pipe_ctx->stream_res.hpo_dp_stream_enc,
- false,
- NULL,
- true);
- else
- pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet(
- pipe_ctx->stream_res.stream_enc, false, NULL, true);
- }
- }
-
- return true;
-}
-
-
-bool dp_update_dsc_config(struct pipe_ctx *pipe_ctx)
-{
- struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
-
- if (!pipe_ctx->stream->timing.flags.DSC)
- return false;
- if (!dsc)
- return false;
-
- dp_set_dsc_on_stream(pipe_ctx, true);
- dp_set_dsc_pps_sdp(pipe_ctx, true, false);
- return true;
-}
-
-#undef DC_LOGGER
-#define DC_LOGGER \
- link->ctx->logger
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c
index 614f022d1cff..74e465ba158d 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c
@@ -24,7 +24,7 @@
#include "link_enc_cfg.h"
#include "resource.h"
-#include "dc_link_dp.h"
+#include "link.h"
#define DC_LOGGER dc->ctx->logger
@@ -48,7 +48,7 @@ static bool is_dig_link_enc_stream(struct dc_stream_state *stream)
/* DIGs do not support DP2.0 streams with 128b/132b encoding. */
struct dc_link_settings link_settings = {0};
- decide_link_settings(stream, &link_settings);
+ link_decide_link_settings(stream, &link_settings);
if ((link_settings.link_rate >= LINK_RATE_LOW) &&
link_settings.link_rate <= LINK_RATE_HIGH3) {
is_dig_stream = true;
@@ -305,15 +305,17 @@ void link_enc_cfg_link_encs_assign(
for (i = 0; i < stream_count; i++) {
struct dc_stream_state *stream = streams[i];
+ /* skip it if the link is mappable endpoint. */
+ if (stream->link->is_dig_mapping_flexible)
+ continue;
+
/* Skip stream if not supported by DIG link encoder. */
if (!is_dig_link_enc_stream(stream))
continue;
/* Physical endpoints have a fixed mapping to DIG link encoders. */
- if (!stream->link->is_dig_mapping_flexible) {
- eng_id = stream->link->eng_id;
- add_link_enc_assignment(state, stream, eng_id);
- }
+ eng_id = stream->link->eng_id;
+ add_link_enc_assignment(state, stream, eng_id);
}
/* (b) Retain previous assignments for mappable endpoints if encoders still available. */
@@ -325,11 +327,12 @@ void link_enc_cfg_link_encs_assign(
for (i = 0; i < stream_count; i++) {
struct dc_stream_state *stream = state->streams[i];
- /* Skip stream if not supported by DIG link encoder. */
- if (!is_dig_link_enc_stream(stream))
+ /* Skip it if the link is NOT mappable endpoint. */
+ if (!stream->link->is_dig_mapping_flexible)
continue;
- if (!stream->link->is_dig_mapping_flexible)
+ /* Skip stream if not supported by DIG link encoder. */
+ if (!is_dig_link_enc_stream(stream))
continue;
for (j = 0; j < prev_state->stream_count; j++) {
@@ -338,6 +341,7 @@ void link_enc_cfg_link_encs_assign(
if (stream == prev_stream && stream->link == prev_stream->link &&
prev_state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[j].valid) {
eng_id = prev_state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[j].eng_id;
+
if (is_avail_link_enc(state, eng_id, stream))
add_link_enc_assignment(state, stream, eng_id);
}
@@ -350,6 +354,15 @@ void link_enc_cfg_link_encs_assign(
for (i = 0; i < stream_count; i++) {
struct dc_stream_state *stream = streams[i];
+ struct link_encoder *link_enc = NULL;
+
+ /* Skip it if the link is NOT mappable endpoint. */
+ if (!stream->link->is_dig_mapping_flexible)
+ continue;
+
+ /* Skip if encoder assignment retained in step (b) above. */
+ if (stream->link_enc)
+ continue;
/* Skip stream if not supported by DIG link encoder. */
if (!is_dig_link_enc_stream(stream)) {
@@ -358,24 +371,18 @@ void link_enc_cfg_link_encs_assign(
}
/* Mappable endpoints have a flexible mapping to DIG link encoders. */
- if (stream->link->is_dig_mapping_flexible) {
- struct link_encoder *link_enc = NULL;
- /* Skip if encoder assignment retained in step (b) above. */
- if (stream->link_enc)
- continue;
+ /* For MST, multiple streams will share the same link / display
+ * endpoint. These streams should use the same link encoder
+ * assigned to that endpoint.
+ */
+ link_enc = get_link_enc_used_by_link(state, stream->link);
+ if (link_enc == NULL)
+ eng_id = find_first_avail_link_enc(stream->ctx, state);
+ else
+ eng_id = link_enc->preferred_engine;
- /* For MST, multiple streams will share the same link / display
- * endpoint. These streams should use the same link encoder
- * assigned to that endpoint.
- */
- link_enc = get_link_enc_used_by_link(state, stream->link);
- if (link_enc == NULL)
- eng_id = find_first_avail_link_enc(stream->ctx, state);
- else
- eng_id = link_enc->preferred_engine;
- add_link_enc_assignment(state, stream, eng_id);
- }
+ add_link_enc_assignment(state, stream, eng_id);
}
link_enc_cfg_validate(dc, state);
@@ -420,10 +427,6 @@ void link_enc_cfg_link_enc_unassign(
{
enum engine_id eng_id = ENGINE_ID_UNKNOWN;
- /* Only DIG link encoders. */
- if (!is_dig_link_enc_stream(stream))
- return;
-
if (stream->link_enc)
eng_id = stream->link_enc->preferred_engine;
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c
new file mode 100644
index 000000000000..a951e10416ee
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2023 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+
+/* FILE POLICY AND INTENDED USAGE:
+ * This file provides single entrance to link functionality declared in dc
+ * public headers. The file is intended to be used as a thin translation layer
+ * that directly calls link internal functions without adding new functional
+ * behavior.
+ *
+ * When exporting a new link related dc function, add function declaration in
+ * dc.h with detail interface documentation, then add function implementation
+ * in this file which calls link functions.
+ */
+#include "link.h"
+
+bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason)
+{
+ return link_detect(link, reason);
+}
+
+bool dc_link_detect_connection_type(struct dc_link *link,
+ enum dc_connection_type *type)
+{
+ return link_detect_connection_type(link, type);
+}
+
+const struct dc_link_status *dc_link_get_status(const struct dc_link *link)
+{
+ return link_get_status(link);
+}
+#ifdef CONFIG_DRM_AMD_DC_HDCP
+
+/* return true if the connected receiver supports the hdcp version */
+bool dc_link_is_hdcp14(struct dc_link *link, enum signal_type signal)
+{
+ return link_is_hdcp14(link, signal);
+}
+
+bool dc_link_is_hdcp22(struct dc_link *link, enum signal_type signal)
+{
+ return link_is_hdcp22(link, signal);
+}
+#endif
+
+void dc_link_clear_dprx_states(struct dc_link *link)
+{
+ link_clear_dprx_states(link);
+}
+
+bool dc_link_reset_cur_dp_mst_topology(struct dc_link *link)
+{
+ return link_reset_cur_dp_mst_topology(link);
+}
+
+uint32_t dc_link_bandwidth_kbps(
+ const struct dc_link *link,
+ const struct dc_link_settings *link_settings)
+{
+ return dp_link_bandwidth_kbps(link, link_settings);
+}
+
+uint32_t dc_bandwidth_in_kbps_from_timing(
+ const struct dc_crtc_timing *timing)
+{
+ return link_timing_bandwidth_kbps(timing);
+}
+
+void dc_get_cur_link_res_map(const struct dc *dc, uint32_t *map)
+{
+ link_get_cur_res_map(dc, map);
+}
+
+void dc_restore_link_res_map(const struct dc *dc, uint32_t *map)
+{
+ link_restore_res_map(dc, map);
+}
+
+bool dc_link_update_dsc_config(struct pipe_ctx *pipe_ctx)
+{
+ return link_update_dsc_config(pipe_ctx);
+}
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
index da164685547d..d9f2ef242b0f 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
@@ -40,11 +40,11 @@
#include "virtual/virtual_stream_encoder.h"
#include "dpcd_defs.h"
#include "link_enc_cfg.h"
-#include "dc_link_dp.h"
+#include "link.h"
#include "virtual/virtual_link_hwss.h"
-#include "link/link_hwss_dio.h"
-#include "link/link_hwss_dpia.h"
-#include "link/link_hwss_hpo_dp.h"
+#include "link/hwss/link_hwss_dio.h"
+#include "link/hwss/link_hwss_dpia.h"
+#include "link/hwss/link_hwss_hpo_dp.h"
#if defined(CONFIG_DRM_AMD_DC_SI)
#include "dce60/dce60_resource.h"
@@ -2213,7 +2213,7 @@ enum dc_status dc_remove_stream_from_ctx(
del_pipe->stream_res.stream_enc,
false);
- if (is_dp_128b_132b_signal(del_pipe)) {
+ if (link_is_dp_128b_132b_signal(del_pipe)) {
update_hpo_dp_stream_engine_usage(
&new_ctx->res_ctx, dc->res_pool,
del_pipe->stream_res.hpo_dp_stream_enc,
@@ -2513,9 +2513,9 @@ enum dc_status resource_map_pool_resources(
* and link settings
*/
if (dc_is_dp_signal(stream->signal)) {
- if (!decide_link_settings(stream, &pipe_ctx->link_config.dp_link_settings))
+ if (!link_decide_link_settings(stream, &pipe_ctx->link_config.dp_link_settings))
return DC_FAIL_DP_LINK_BANDWIDTH;
- if (dp_get_link_encoding_format(&pipe_ctx->link_config.dp_link_settings) == DP_128b_132b_ENCODING) {
+ if (link_dp_get_encoding_format(&pipe_ctx->link_config.dp_link_settings) == DP_128b_132b_ENCODING) {
pipe_ctx->stream_res.hpo_dp_stream_enc =
find_first_free_match_hpo_dp_stream_enc_for_link(
&context->res_ctx, pool, stream);
@@ -3269,6 +3269,50 @@ static void set_hfvs_info_packet(
*info_packet = stream->hfvsif_infopacket;
}
+static void adaptive_sync_override_dp_info_packets_sdp_line_num(
+ const struct dc_crtc_timing *timing,
+ struct enc_sdp_line_num *sdp_line_num,
+ struct _vcs_dpi_display_pipe_dest_params_st *pipe_dlg_param)
+{
+ uint32_t asic_blank_start = 0;
+ uint32_t asic_blank_end = 0;
+ uint32_t v_update = 0;
+
+ const struct dc_crtc_timing *tg = timing;
+
+ /* blank_start = frame end - front porch */
+ asic_blank_start = tg->v_total - tg->v_front_porch;
+
+ /* blank_end = blank_start - active */
+ asic_blank_end = (asic_blank_start - tg->v_border_bottom -
+ tg->v_addressable - tg->v_border_top);
+
+ if (pipe_dlg_param->vstartup_start > asic_blank_end) {
+ v_update = (tg->v_total - (pipe_dlg_param->vstartup_start - asic_blank_end));
+ sdp_line_num->adaptive_sync_line_num_valid = true;
+ sdp_line_num->adaptive_sync_line_num = (tg->v_total - v_update - 1);
+ } else {
+ sdp_line_num->adaptive_sync_line_num_valid = false;
+ sdp_line_num->adaptive_sync_line_num = 0;
+ }
+}
+
+static void set_adaptive_sync_info_packet(
+ struct dc_info_packet *info_packet,
+ const struct dc_stream_state *stream,
+ struct encoder_info_frame *info_frame,
+ struct _vcs_dpi_display_pipe_dest_params_st *pipe_dlg_param)
+{
+ if (!stream->adaptive_sync_infopacket.valid)
+ return;
+
+ adaptive_sync_override_dp_info_packets_sdp_line_num(
+ &stream->timing,
+ &info_frame->sdp_line_num,
+ pipe_dlg_param);
+
+ *info_packet = stream->adaptive_sync_infopacket;
+}
static void set_vtem_info_packet(
struct dc_info_packet *info_packet,
@@ -3361,6 +3405,7 @@ void resource_build_info_frame(struct pipe_ctx *pipe_ctx)
info->vsc.valid = false;
info->hfvsif.valid = false;
info->vtem.valid = false;
+ info->adaptive_sync.valid = false;
signal = pipe_ctx->stream->signal;
/* HDMi and DP have different info packets*/
@@ -3381,6 +3426,10 @@ void resource_build_info_frame(struct pipe_ctx *pipe_ctx)
set_spd_info_packet(&info->spd, pipe_ctx->stream);
set_hdr_static_info_packet(&info->hdrsmd, pipe_ctx->stream);
+ set_adaptive_sync_info_packet(&info->adaptive_sync,
+ pipe_ctx->stream,
+ info,
+ &pipe_ctx->pipe_dlg_param);
}
patch_gamut_packet_checksum(&info->gamut);
@@ -3636,7 +3685,7 @@ enum dc_status dc_validate_stream(struct dc *dc, struct dc_stream_state *stream)
/* TODO: validate audio ASIC caps, encoder */
if (res == DC_OK)
- res = dc_link_validate_mode_timing(stream,
+ res = link_validate_mode_timing(stream,
link,
&stream->timing);
@@ -3763,7 +3812,7 @@ bool get_temp_dp_link_res(struct dc_link *link,
memset(link_res, 0, sizeof(*link_res));
- if (dp_get_link_encoding_format(link_settings) == DP_128b_132b_ENCODING) {
+ if (link_dp_get_encoding_format(link_settings) == DP_128b_132b_ENCODING) {
link_res->hpo_dp_link_enc = get_temp_hpo_dp_link_enc(res_ctx,
dc->res_pool, link);
if (!link_res->hpo_dp_link_enc)
@@ -3820,9 +3869,20 @@ void check_syncd_pipes_for_disabled_master_pipe(struct dc *dc,
pipe_ctx_check = &context->res_ctx.pipe_ctx[i];
if ((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx_check) == disabled_master_pipe_idx) &&
- IS_PIPE_SYNCD_VALID(pipe_ctx_check) && (i != disabled_master_pipe_idx))
+ IS_PIPE_SYNCD_VALID(pipe_ctx_check) && (i != disabled_master_pipe_idx)) {
+ struct pipe_ctx *first_pipe = pipe_ctx_check;
+
+ while (first_pipe->prev_odm_pipe)
+ first_pipe = first_pipe->prev_odm_pipe;
+ /* When ODM combine is enabled, this case is expected. If the disabled pipe
+ * is part of the ODM tree, then we should not print an error.
+ * */
+ if (first_pipe->pipe_idx == disabled_master_pipe_idx)
+ continue;
+
DC_ERR("DC: Failure: pipe_idx[%d] syncd with disabled master pipe_idx[%d]\n",
- i, disabled_master_pipe_idx);
+ i, disabled_master_pipe_idx);
+ }
}
}
@@ -3981,3 +4041,42 @@ bool dc_resource_acquire_secondary_pipe_for_mpc_odm(
return true;
}
+
+enum dc_status update_dp_encoder_resources_for_test_harness(const struct dc *dc,
+ struct dc_state *context,
+ struct pipe_ctx *pipe_ctx)
+{
+ if (link_dp_get_encoding_format(&pipe_ctx->link_config.dp_link_settings) == DP_128b_132b_ENCODING) {
+ if (pipe_ctx->stream_res.hpo_dp_stream_enc == NULL) {
+ pipe_ctx->stream_res.hpo_dp_stream_enc =
+ find_first_free_match_hpo_dp_stream_enc_for_link(
+ &context->res_ctx, dc->res_pool, pipe_ctx->stream);
+
+ if (!pipe_ctx->stream_res.hpo_dp_stream_enc)
+ return DC_NO_STREAM_ENC_RESOURCE;
+
+ update_hpo_dp_stream_engine_usage(
+ &context->res_ctx, dc->res_pool,
+ pipe_ctx->stream_res.hpo_dp_stream_enc,
+ true);
+ }
+
+ if (pipe_ctx->link_res.hpo_dp_link_enc == NULL) {
+ if (!add_hpo_dp_link_enc_to_ctx(&context->res_ctx, dc->res_pool, pipe_ctx, pipe_ctx->stream))
+ return DC_NO_LINK_ENC_RESOURCE;
+ }
+ } else {
+ if (pipe_ctx->stream_res.hpo_dp_stream_enc) {
+ update_hpo_dp_stream_engine_usage(
+ &context->res_ctx, dc->res_pool,
+ pipe_ctx->stream_res.hpo_dp_stream_enc,
+ false);
+ pipe_ctx->stream_res.hpo_dp_stream_enc = NULL;
+ }
+ if (pipe_ctx->link_res.hpo_dp_link_enc)
+ remove_hpo_dp_link_enc_from_ctx(&context->res_ctx, pipe_ctx, pipe_ctx->stream);
+ }
+
+ return DC_OK;
+}
+
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stat.c b/drivers/gpu/drm/amd/display/dc/core/dc_stat.c
index 4b372aa52801..6c06587dd88c 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_stat.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_stat.c
@@ -65,6 +65,7 @@ void dc_stat_get_dmub_notification(const struct dc *dc, struct dmub_notification
/* For HPD/HPD RX, convert dpia port index into link index */
if (notify->type == DMUB_NOTIFICATION_HPD ||
notify->type == DMUB_NOTIFICATION_HPD_IRQ ||
+ notify->type == DMUB_NOTIFICATION_DPIA_NOTIFICATION ||
notify->type == DMUB_NOTIFICATION_SET_CONFIG_REPLY) {
notify->link_index =
get_link_index_from_dpia_port_index(dc, notify->link_index);
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
index 20e534f73513..72b261ad9587 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
@@ -408,7 +408,7 @@ bool dc_stream_set_cursor_position(
struct dc_stream_state *stream,
const struct dc_cursor_position *position)
{
- struct dc *dc = stream->ctx->dc;
+ struct dc *dc;
bool reset_idle_optimizations = false;
if (NULL == stream) {
@@ -481,6 +481,7 @@ bool dc_stream_add_writeback(struct dc *dc,
}
if (!isDrc) {
+ ASSERT(stream->num_wb_info + 1 <= MAX_DWB_PIPES);
stream->writeback_info[stream->num_wb_info++] = *wb_info;
}
@@ -526,6 +527,11 @@ bool dc_stream_remove_writeback(struct dc *dc,
return false;
}
+ if (stream->num_wb_info > MAX_DWB_PIPES) {
+ dm_error("DC: num_wb_info is invalid!\n");
+ return false;
+ }
+
// stream->writeback_info[dwb_pipe_inst].wb_enabled = false;
for (i = 0; i < stream->num_wb_info; i++) {
/*dynamic update*/
@@ -540,7 +546,8 @@ bool dc_stream_remove_writeback(struct dc *dc,
if (stream->writeback_info[i].wb_enabled) {
if (j < i)
/* trim the array */
- stream->writeback_info[j] = stream->writeback_info[i];
+ memcpy(&stream->writeback_info[j], &stream->writeback_info[i],
+ sizeof(struct dc_writeback_info));
j++;
}
}
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index 85ebeaa2de18..1fde43378689 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -47,12 +47,11 @@ struct aux_payload;
struct set_config_cmd_payload;
struct dmub_notification;
-#define DC_VER "3.2.215"
+#define DC_VER "3.2.223"
#define MAX_SURFACES 3
#define MAX_PLANES 6
#define MAX_STREAMS 6
-#define MAX_SINKS_PER_LINK 4
#define MIN_VIEWPORT_SIZE 12
#define MAX_NUM_EDP 2
@@ -410,7 +409,7 @@ struct dc_config {
bool force_bios_enable_lttpr;
uint8_t force_bios_fixed_vs;
int sdpif_request_limit_words_per_umc;
-
+ bool disable_subvp_drr;
};
enum visual_confirm {
@@ -872,6 +871,9 @@ struct dc_debug_options {
enum lttpr_mode lttpr_mode_override;
unsigned int dsc_delay_factor_wa_x1000;
unsigned int min_prefetch_in_strobe_ns;
+ bool disable_unbounded_requesting;
+ bool dig_fifo_off_in_blank;
+ bool temp_mst_deallocation_sequence;
};
struct gpu_info_soc_bounding_box_v1_0;
@@ -1369,108 +1371,128 @@ struct dc_state *dc_copy_state(struct dc_state *src_ctx);
void dc_retain_state(struct dc_state *context);
void dc_release_state(struct dc_state *context);
+struct dc_plane_state *dc_get_surface_for_mpcc(struct dc *dc,
+ struct dc_stream_state *stream,
+ int mpcc_inst);
+
+
+uint32_t dc_get_opp_for_plane(struct dc *dc, struct dc_plane_state *plane);
+
/* Link Interfaces */
+/* TODO: remove this after resolving external dependencies */
+#include "dc_link.h"
-struct dpcd_caps {
- union dpcd_rev dpcd_rev;
- union max_lane_count max_ln_count;
- union max_down_spread max_down_spread;
- union dprx_feature dprx_feature;
-
- /* valid only for eDP v1.4 or higher*/
- uint8_t edp_supported_link_rates_count;
- enum dc_link_rate edp_supported_link_rates[8];
-
- /* dongle type (DP converter, CV smart dongle) */
- enum display_dongle_type dongle_type;
- bool is_dongle_type_one;
- /* branch device or sink device */
- bool is_branch_dev;
- /* Dongle's downstream count. */
- union sink_count sink_count;
- bool is_mst_capable;
- /* If dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER,
- indicates 'Frame Sequential-to-lllFrame Pack' conversion capability.*/
- struct dc_dongle_caps dongle_caps;
-
- uint32_t sink_dev_id;
- int8_t sink_dev_id_str[6];
- int8_t sink_hw_revision;
- int8_t sink_fw_revision[2];
-
- uint32_t branch_dev_id;
- int8_t branch_dev_name[6];
- int8_t branch_hw_revision;
- int8_t branch_fw_revision[2];
-
- bool allow_invalid_MSA_timing_param;
- bool panel_mode_edp;
- bool dpcd_display_control_capable;
- bool ext_receiver_cap_field_present;
- bool set_power_state_capable_edp;
- bool dynamic_backlight_capable_edp;
- union dpcd_fec_capability fec_cap;
- struct dpcd_dsc_capabilities dsc_caps;
- struct dc_lttpr_caps lttpr_caps;
- struct dpcd_usb4_dp_tunneling_info usb4_dp_tun_info;
-
- union dp_128b_132b_supported_link_rates dp_128b_132b_supported_link_rates;
- union dp_main_line_channel_coding_cap channel_coding_cap;
- union dp_sink_video_fallback_formats fallback_formats;
- union dp_fec_capability1 fec_cap1;
- union dp_cable_id cable_id;
- uint8_t edp_rev;
- union edp_alpm_caps alpm_caps;
- struct edp_psr_info psr_info;
-};
-
-union dpcd_sink_ext_caps {
- struct {
- /* 0 - Sink supports backlight adjust via PWM during SDR/HDR mode
- * 1 - Sink supports backlight adjust via AUX during SDR/HDR mode.
- */
- uint8_t sdr_aux_backlight_control : 1;
- uint8_t hdr_aux_backlight_control : 1;
- uint8_t reserved_1 : 2;
- uint8_t oled : 1;
- uint8_t reserved : 3;
- } bits;
- uint8_t raw;
-};
+/* The function initiates detection handshake over the given link. It first
+ * determines if there are display connections over the link. If so it initiates
+ * detection protocols supported by the connected receiver device. The function
+ * contains protocol specific handshake sequences which are sometimes mandatory
+ * to establish a proper connection between TX and RX. So it is always
+ * recommended to call this function as the first link operation upon HPD event
+ * or power up event. Upon completion, the function will update link structure
+ * in place based on latest RX capabilities. The function may also cause dpms
+ * to be reset to off for all currently enabled streams to the link. It is DM's
+ * responsibility to serialize detection and DPMS updates.
+ *
+ * @reason - Indicate which event triggers this detection. dc may customize
+ * detection flow depending on the triggering events.
+ * return false - if detection is not fully completed. This could happen when
+ * there is an unrecoverable error during detection or detection is partially
+ * completed (detection has been delegated to dm mst manager ie.
+ * link->connection_type == dc_connection_mst_branch when returning false).
+ * return true - detection is completed, link has been fully updated with latest
+ * detection result.
+ */
+bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason);
-#if defined(CONFIG_DRM_AMD_DC_HDCP)
-union hdcp_rx_caps {
- struct {
- uint8_t version;
- uint8_t reserved;
- struct {
- uint8_t repeater : 1;
- uint8_t hdcp_capable : 1;
- uint8_t reserved : 6;
- } byte0;
- } fields;
- uint8_t raw[3];
-};
+/* determine if there is a sink connected to the link
+ *
+ * @type - dc_connection_single if connected, dc_connection_none otherwise.
+ * return - false if an unexpected error occurs, true otherwise.
+ *
+ * NOTE: This function doesn't detect downstream sink connections i.e
+ * dc_connection_mst_branch, dc_connection_sst_branch. In this case, it will
+ * return dc_connection_single if the branch device is connected despite of
+ * downstream sink's connection status.
+ */
+bool dc_link_detect_connection_type(struct dc_link *link,
+ enum dc_connection_type *type);
-union hdcp_bcaps {
- struct {
- uint8_t HDCP_CAPABLE:1;
- uint8_t REPEATER:1;
- uint8_t RESERVED:6;
- } bits;
- uint8_t raw;
-};
+/* Getter for cached link status from given link */
+const struct dc_link_status *dc_link_get_status(const struct dc_link *link);
-struct hdcp_caps {
- union hdcp_rx_caps rx_caps;
- union hdcp_bcaps bcaps;
-};
+#ifdef CONFIG_DRM_AMD_DC_HDCP
+/* return true if the connected receiver supports the hdcp version */
+bool dc_link_is_hdcp14(struct dc_link *link, enum signal_type signal);
+bool dc_link_is_hdcp22(struct dc_link *link, enum signal_type signal);
#endif
-#include "dc_link.h"
+/* The function clears recorded DP RX states in the link. DM should call this
+ * function when it is resuming from S3 power state to previously connected links.
+ *
+ * TODO - in the future we should consider to expand link resume interface to
+ * support clearing previous rx states. So we don't have to rely on dm to call
+ * this interface explicitly.
+ */
+void dc_link_clear_dprx_states(struct dc_link *link);
-uint32_t dc_get_opp_for_plane(struct dc *dc, struct dc_plane_state *plane);
+/* Destruct the mst topology of the link and reset the allocated payload table
+ *
+ * NOTE: this should only be called if DM chooses not to call dc_link_detect but
+ * still wants to reset MST topology on an unplug event */
+bool dc_link_reset_cur_dp_mst_topology(struct dc_link *link);
+
+/* The function calculates effective DP link bandwidth when a given link is
+ * using the given link settings.
+ *
+ * return - total effective link bandwidth in kbps.
+ */
+uint32_t dc_link_bandwidth_kbps(
+ const struct dc_link *link,
+ const struct dc_link_settings *link_setting);
+
+/* The function returns minimum bandwidth required to drive a given timing
+ * return - minimum required timing bandwidth in kbps.
+ */
+uint32_t dc_bandwidth_in_kbps_from_timing(
+ const struct dc_crtc_timing *timing);
+/* The function takes a snapshot of current link resource allocation state
+ * @dc: pointer to dc of the dm calling this
+ * @map: a dc link resource snapshot defined internally to dc.
+ *
+ * DM needs to capture a snapshot of current link resource allocation mapping
+ * and store it in its persistent storage.
+ *
+ * Some of the link resource is using first come first serve policy.
+ * The allocation mapping depends on original hotplug order. This information
+ * is lost after driver is loaded next time. The snapshot is used in order to
+ * restore link resource to its previous state so user will get consistent
+ * link capability allocation across reboot.
+ *
+ */
+void dc_get_cur_link_res_map(const struct dc *dc, uint32_t *map);
+
+/* This function restores link resource allocation state from a snapshot
+ * @dc: pointer to dc of the dm calling this
+ * @map: a dc link resource snapshot defined internally to dc.
+ *
+ * DM needs to call this function after initial link detection on boot and
+ * before first commit streams to restore link resource allocation state
+ * from previous boot session.
+ *
+ * Some of the link resource is using first come first serve policy.
+ * The allocation mapping depends on original hotplug order. This information
+ * is lost after driver is loaded next time. The snapshot is used in order to
+ * restore link resource to its previous state so user will get consistent
+ * link capability allocation across reboot.
+ *
+ */
+void dc_restore_link_res_map(const struct dc *dc, uint32_t *map);
+
+/* TODO: this is not meant to be exposed to DM. Should switch to stream update
+ * interface i.e stream_update->dsc_config
+ */
+bool dc_link_update_dsc_config(struct pipe_ctx *pipe_ctx);
/* Sink Interfaces - A sink corresponds to a display output device */
struct dc_container_id {
@@ -1502,6 +1524,11 @@ struct dc_sink_fec_caps {
bool is_topology_fec_supported;
};
+struct scdc_caps {
+ union hdmi_scdc_manufacturer_OUI_data manufacturer_OUI;
+ union hdmi_scdc_device_id_data device_id;
+};
+
/*
* The sink structure contains EDID and other display device properties
*/
@@ -1515,6 +1542,7 @@ struct dc_sink {
struct stereo_3d_features features_3d[TIMING_3D_FORMAT_MAX];
bool converter_disable_audio;
+ struct scdc_caps scdc_caps;
struct dc_sink_dsc_caps dsc_caps;
struct dc_sink_fec_caps fec_caps;
diff --git a/drivers/gpu/drm/amd/display/dc/dc_bios_types.h b/drivers/gpu/drm/amd/display/dc/dc_bios_types.h
index 260ac4458870..be9aa1a71847 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_bios_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_bios_types.h
@@ -140,7 +140,8 @@ struct dc_vbios_funcs {
enum bp_result (*enable_lvtma_control)(
struct dc_bios *bios,
uint8_t uc_pwr_on,
- uint8_t panel_instance);
+ uint8_t panel_instance,
+ uint8_t bypass_panel_control_wait);
enum bp_result (*get_soc_bb_info)(
struct dc_bios *dcb,
diff --git a/drivers/gpu/drm/amd/display/dc/dc_ddc_types.h b/drivers/gpu/drm/amd/display/dc/dc_ddc_types.h
index 7769bd099a5a..428e3a9ab65a 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_ddc_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_ddc_types.h
@@ -77,6 +77,32 @@ struct aux_reply_transaction_data {
uint8_t *data;
};
+struct aux_payload {
+ /* set following flag to read/write I2C data,
+ * reset it to read/write DPCD data */
+ bool i2c_over_aux;
+ /* set following flag to write data,
+ * reset it to read data */
+ bool write;
+ bool mot;
+ bool write_status_update;
+
+ uint32_t address;
+ uint32_t length;
+ uint8_t *data;
+ /*
+ * used to return the reply type of the transaction
+ * ignored if NULL
+ */
+ uint8_t *reply;
+ /* expressed in milliseconds
+ * zero means "use default value"
+ */
+ uint32_t defer_delay;
+
+};
+#define DEFAULT_AUX_MAX_DATA_SIZE 16
+
struct i2c_payload {
bool write;
uint8_t address;
@@ -90,6 +116,8 @@ enum i2c_command_engine {
I2C_COMMAND_ENGINE_HW
};
+#define DDC_I2C_COMMAND_ENGINE I2C_COMMAND_ENGINE_SW
+
struct i2c_command {
struct i2c_payload *payloads;
uint8_t number_of_payloads;
@@ -150,6 +178,9 @@ enum display_dongle_type {
DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE,
};
+#define DC_MAX_EDID_BUFFER_SIZE 2048
+#define DC_EDID_BLOCK_SIZE 128
+
struct ddc_service {
struct ddc *ddc_pin;
struct ddc_flags flags;
diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
index 6ccf477d1c4d..c2092775ca88 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
+++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
@@ -698,7 +698,7 @@ static void populate_subvp_cmd_pipe_info(struct dc *dc,
*
* @dc: [in] current dc state
* @context: [in] new dc state
- * @cmd: [in] DMUB cmd to be populated with SubVP info
+ * @enable: [in] if true enables the pipes population
*
* This function loops through each pipe and populates the DMUB SubVP CMD info
* based on the pipe (e.g. SubVP, VBLANK).
diff --git a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
index 2c54b6e0498b..809a1851f196 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
@@ -27,6 +27,7 @@
#define DC_DP_TYPES_H
#include "os_types.h"
+#include "dc_ddc_types.h"
enum dc_lane_count {
LANE_COUNT_UNKNOWN = 0,
@@ -149,7 +150,6 @@ struct dc_link_settings {
enum dc_link_spread link_spread;
bool use_link_rate_set;
uint8_t link_rate_set;
- bool dpcd_source_device_specific_field_support;
};
union dc_dp_ffe_preset {
@@ -362,14 +362,10 @@ enum dpcd_downstream_port_detailed_type {
union dwnstream_port_caps_byte2 {
struct {
uint8_t MAX_BITS_PER_COLOR_COMPONENT:2;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
uint8_t MAX_ENCODED_LINK_BW_SUPPORT:3;
uint8_t SOURCE_CONTROL_MODE_SUPPORT:1;
uint8_t CONCURRENT_LINK_BRING_UP_SEQ_SUPPORT:1;
uint8_t RESERVED:1;
-#else
- uint8_t RESERVED:6;
-#endif
} bits;
uint8_t raw;
};
@@ -407,7 +403,6 @@ union dwnstream_port_caps_byte3_hdmi {
uint8_t raw;
};
-#if defined(CONFIG_DRM_AMD_DC_DCN)
union hdmi_sink_encoded_link_bw_support {
struct {
uint8_t HDMI_SINK_ENCODED_LINK_BW_SUPPORT:3;
@@ -429,7 +424,6 @@ union hdmi_encoded_link_bw {
} bits;
uint8_t raw;
};
-#endif
/*4-byte structure for detailed capabilities of a down-stream port
(DP-to-TMDS converter).*/
@@ -509,7 +503,11 @@ union down_spread_ctrl {
1 = Main link signal is downspread <= 0.5%
with frequency in the range of 30kHz ~ 33kHz*/
uint8_t SPREAD_AMP:1;
- uint8_t RESERVED2:2;/*Bit 6:5 = RESERVED. Read all 0s*/
+ uint8_t RESERVED2:1;/*Bit 5 = RESERVED. Read all 0s*/
+ /* Bit 6 = FIXED_VTOTAL_AS_SDP_EN_IN_PR_ACTIVE.
+ 0 = FIXED_VTOTAL_AS_SDP_EN_IN_PR_ACTIVE is not enabled by the Source device (default)
+ 1 = FIXED_VTOTAL_AS_SDP_EN_IN_PR_ACTIVE is enabled by Source device */
+ uint8_t FIXED_VTOTAL_AS_SDP_EN_IN_PR_ACTIVE:1;
/*Bit 7 = MSA_TIMING_PAR_IGNORE_EN
0 = Source device will send valid data for the MSA Timing Params
1 = Source device may send invalid data for these MSA Timing Params*/
@@ -865,6 +863,21 @@ struct psr_caps {
unsigned int psr_power_opt_flag;
};
+union dpcd_dprx_feature_enumeration_list_cont_1 {
+ struct {
+ uint8_t ADAPTIVE_SYNC_SDP_SUPPORT:1;
+ uint8_t AS_SDP_FIRST_HALF_LINE_OR_3840_PIXEL_CYCLE_WINDOW_NOT_SUPPORTED: 1;
+ uint8_t RESERVED0: 2;
+ uint8_t VSC_EXT_SDP_VER1_SUPPORT: 1;
+ uint8_t RESERVED1: 3;
+ } bits;
+ uint8_t raw;
+};
+
+struct adaptive_sync_caps {
+ union dpcd_dprx_feature_enumeration_list_cont_1 dp_adap_sync_caps;
+};
+
/* Length of router topology ID read from DPCD in bytes. */
#define DPCD_USB4_TOPOLOGY_ID_LEN 5
@@ -926,6 +939,9 @@ struct dpcd_usb4_dp_tunneling_info {
#ifndef DP_128b_132b_TRAINING_AUX_RD_INTERVAL
#define DP_128b_132b_TRAINING_AUX_RD_INTERVAL 0x2216
#endif
+#ifndef DP_LINK_SQUARE_PATTERN
+#define DP_LINK_SQUARE_PATTERN 0x10F
+#endif
#ifndef DP_CABLE_ATTRIBUTES_UPDATED_BY_DPRX
#define DP_CABLE_ATTRIBUTES_UPDATED_BY_DPRX 0x2217
#endif
@@ -973,6 +989,9 @@ struct dpcd_usb4_dp_tunneling_info {
/* TODO - Use DRM header to replace above once available */
#endif // DP_INTRA_HOP_AUX_REPLY_INDICATION
+#ifndef DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE
+#define DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE 0x50
+#endif
union dp_main_line_channel_coding_cap {
struct {
uint8_t DP_8b_10b_SUPPORTED :1;
@@ -1107,4 +1126,139 @@ struct edp_psr_info {
uint8_t force_psrsu_cap;
};
+struct dprx_states {
+ bool cable_id_written;
+};
+
+enum dpcd_downstream_port_max_bpc {
+ DOWN_STREAM_MAX_8BPC = 0,
+ DOWN_STREAM_MAX_10BPC,
+ DOWN_STREAM_MAX_12BPC,
+ DOWN_STREAM_MAX_16BPC
+};
+
+enum link_training_offset {
+ DPRX = 0,
+ LTTPR_PHY_REPEATER1 = 1,
+ LTTPR_PHY_REPEATER2 = 2,
+ LTTPR_PHY_REPEATER3 = 3,
+ LTTPR_PHY_REPEATER4 = 4,
+ LTTPR_PHY_REPEATER5 = 5,
+ LTTPR_PHY_REPEATER6 = 6,
+ LTTPR_PHY_REPEATER7 = 7,
+ LTTPR_PHY_REPEATER8 = 8
+};
+
+#define MAX_REPEATER_CNT 8
+
+struct dc_lttpr_caps {
+ union dpcd_rev revision;
+ uint8_t mode;
+ uint8_t max_lane_count;
+ uint8_t max_link_rate;
+ uint8_t phy_repeater_cnt;
+ uint8_t max_ext_timeout;
+ union dp_main_link_channel_coding_lttpr_cap main_link_channel_coding;
+ union dp_128b_132b_supported_lttpr_link_rates supported_128b_132b_rates;
+ uint8_t aux_rd_interval[MAX_REPEATER_CNT - 1];
+};
+
+struct dc_dongle_dfp_cap_ext {
+ bool supported;
+ uint16_t max_pixel_rate_in_mps;
+ uint16_t max_video_h_active_width;
+ uint16_t max_video_v_active_height;
+ struct dp_encoding_format_caps encoding_format_caps;
+ struct dp_color_depth_caps rgb_color_depth_caps;
+ struct dp_color_depth_caps ycbcr444_color_depth_caps;
+ struct dp_color_depth_caps ycbcr422_color_depth_caps;
+ struct dp_color_depth_caps ycbcr420_color_depth_caps;
+};
+
+struct dc_dongle_caps {
+ /* dongle type (DP converter, CV smart dongle) */
+ enum display_dongle_type dongle_type;
+ bool extendedCapValid;
+ /* If dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER,
+ indicates 'Frame Sequential-to-lllFrame Pack' conversion capability.*/
+ bool is_dp_hdmi_s3d_converter;
+ bool is_dp_hdmi_ycbcr422_pass_through;
+ bool is_dp_hdmi_ycbcr420_pass_through;
+ bool is_dp_hdmi_ycbcr422_converter;
+ bool is_dp_hdmi_ycbcr420_converter;
+ uint32_t dp_hdmi_max_bpc;
+ uint32_t dp_hdmi_max_pixel_clk_in_khz;
+ uint32_t dp_hdmi_frl_max_link_bw_in_kbps;
+ struct dc_dongle_dfp_cap_ext dfp_cap_ext;
+};
+
+struct dpcd_caps {
+ union dpcd_rev dpcd_rev;
+ union max_lane_count max_ln_count;
+ union max_down_spread max_down_spread;
+ union dprx_feature dprx_feature;
+
+ /* valid only for eDP v1.4 or higher*/
+ uint8_t edp_supported_link_rates_count;
+ enum dc_link_rate edp_supported_link_rates[8];
+
+ /* dongle type (DP converter, CV smart dongle) */
+ enum display_dongle_type dongle_type;
+ bool is_dongle_type_one;
+ /* branch device or sink device */
+ bool is_branch_dev;
+ /* Dongle's downstream count. */
+ union sink_count sink_count;
+ bool is_mst_capable;
+ /* If dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER,
+ indicates 'Frame Sequential-to-lllFrame Pack' conversion capability.*/
+ struct dc_dongle_caps dongle_caps;
+
+ uint32_t sink_dev_id;
+ int8_t sink_dev_id_str[6];
+ int8_t sink_hw_revision;
+ int8_t sink_fw_revision[2];
+
+ uint32_t branch_dev_id;
+ int8_t branch_dev_name[6];
+ int8_t branch_hw_revision;
+ int8_t branch_fw_revision[2];
+
+ bool allow_invalid_MSA_timing_param;
+ bool panel_mode_edp;
+ bool dpcd_display_control_capable;
+ bool ext_receiver_cap_field_present;
+ bool set_power_state_capable_edp;
+ bool dynamic_backlight_capable_edp;
+ union dpcd_fec_capability fec_cap;
+ struct dpcd_dsc_capabilities dsc_caps;
+ struct dc_lttpr_caps lttpr_caps;
+ struct adaptive_sync_caps adaptive_sync_caps;
+ struct dpcd_usb4_dp_tunneling_info usb4_dp_tun_info;
+
+ union dp_128b_132b_supported_link_rates dp_128b_132b_supported_link_rates;
+ union dp_main_line_channel_coding_cap channel_coding_cap;
+ union dp_sink_video_fallback_formats fallback_formats;
+ union dp_fec_capability1 fec_cap1;
+ union dp_cable_id cable_id;
+ uint8_t edp_rev;
+ union edp_alpm_caps alpm_caps;
+ struct edp_psr_info psr_info;
+};
+
+union dpcd_sink_ext_caps {
+ struct {
+ /* 0 - Sink supports backlight adjust via PWM during SDR/HDR mode
+ * 1 - Sink supports backlight adjust via AUX during SDR/HDR mode.
+ */
+ uint8_t sdr_aux_backlight_control : 1;
+ uint8_t hdr_aux_backlight_control : 1;
+ uint8_t reserved_1 : 2;
+ uint8_t oled : 1;
+ uint8_t reserved_2 : 1;
+ uint8_t miniled : 1;
+ uint8_t reserved : 1;
+ } bits;
+ uint8_t raw;
+};
#endif /* DC_DP_TYPES_H */
diff --git a/drivers/gpu/drm/amd/display/dc/dc_hdmi_types.h b/drivers/gpu/drm/amd/display/dc/dc_hdmi_types.h
new file mode 100644
index 000000000000..c364744b4c83
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dc_hdmi_types.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef DC_HDMI_TYPES_H
+#define DC_HDMI_TYPES_H
+
+#include "os_types.h"
+
+/* Address range from 0x00 to 0x1F.*/
+#define DP_ADAPTOR_TYPE2_SIZE 0x20
+#define DP_ADAPTOR_TYPE2_REG_ID 0x10
+#define DP_ADAPTOR_TYPE2_REG_MAX_TMDS_CLK 0x1D
+/* Identifies adaptor as Dual-mode adaptor */
+#define DP_ADAPTOR_TYPE2_ID 0xA0
+/* MHz*/
+#define DP_ADAPTOR_TYPE2_MAX_TMDS_CLK 600
+/* MHz*/
+#define DP_ADAPTOR_TYPE2_MIN_TMDS_CLK 25
+/* kHZ*/
+#define DP_ADAPTOR_DVI_MAX_TMDS_CLK 165000
+/* kHZ*/
+#define DP_ADAPTOR_HDMI_SAFE_MAX_TMDS_CLK 165000
+
+struct dp_hdmi_dongle_signature_data {
+ int8_t id[15];/* "DP-HDMI ADAPTOR"*/
+ uint8_t eot;/* end of transmition '\x4' */
+};
+
+/* DP-HDMI dongle slave address for retrieving dongle signature*/
+#define DP_HDMI_DONGLE_ADDRESS 0x40
+static const uint8_t dp_hdmi_dongle_signature_str[] = "DP-HDMI ADAPTOR";
+#define DP_HDMI_DONGLE_SIGNATURE_EOT 0x04
+
+
+/* SCDC Address defines (HDMI 2.0)*/
+#define HDMI_SCDC_WRITE_UPDATE_0_ARRAY 3
+#define HDMI_SCDC_ADDRESS 0x54
+#define HDMI_SCDC_SINK_VERSION 0x01
+#define HDMI_SCDC_SOURCE_VERSION 0x02
+#define HDMI_SCDC_UPDATE_0 0x10
+#define HDMI_SCDC_TMDS_CONFIG 0x20
+#define HDMI_SCDC_SCRAMBLER_STATUS 0x21
+#define HDMI_SCDC_CONFIG_0 0x30
+#define HDMI_SCDC_CONFIG_1 0x31
+#define HDMI_SCDC_SOURCE_TEST_REQ 0x35
+#define HDMI_SCDC_STATUS_FLAGS 0x40
+#define HDMI_SCDC_ERR_DETECT 0x50
+#define HDMI_SCDC_TEST_CONFIG 0xC0
+
+#define HDMI_SCDC_MANUFACTURER_OUI 0xD0
+#define HDMI_SCDC_DEVICE_ID 0xDB
+
+union hdmi_scdc_update_read_data {
+ uint8_t byte[2];
+ struct {
+ uint8_t STATUS_UPDATE:1;
+ uint8_t CED_UPDATE:1;
+ uint8_t RR_TEST:1;
+ uint8_t RESERVED:5;
+ uint8_t RESERVED2:8;
+ } fields;
+};
+
+union hdmi_scdc_status_flags_data {
+ uint8_t byte;
+ struct {
+ uint8_t CLOCK_DETECTED:1;
+ uint8_t CH0_LOCKED:1;
+ uint8_t CH1_LOCKED:1;
+ uint8_t CH2_LOCKED:1;
+ uint8_t RESERVED:4;
+ } fields;
+};
+
+union hdmi_scdc_ced_data {
+ uint8_t byte[11];
+ struct {
+ uint8_t CH0_8LOW:8;
+ uint8_t CH0_7HIGH:7;
+ uint8_t CH0_VALID:1;
+ uint8_t CH1_8LOW:8;
+ uint8_t CH1_7HIGH:7;
+ uint8_t CH1_VALID:1;
+ uint8_t CH2_8LOW:8;
+ uint8_t CH2_7HIGH:7;
+ uint8_t CH2_VALID:1;
+ uint8_t CHECKSUM:8;
+ uint8_t RESERVED:8;
+ uint8_t RESERVED2:8;
+ uint8_t RESERVED3:8;
+ uint8_t RESERVED4:4;
+ } fields;
+};
+
+union hdmi_scdc_manufacturer_OUI_data {
+ uint8_t byte[3];
+ struct {
+ uint8_t Manufacturer_OUI_1:8;
+ uint8_t Manufacturer_OUI_2:8;
+ uint8_t Manufacturer_OUI_3:8;
+ } fields;
+};
+
+union hdmi_scdc_device_id_data {
+ uint8_t byte;
+ struct {
+ uint8_t Hardware_Minor_Rev:4;
+ uint8_t Hardware_Major_Rev:4;
+ } fields;
+};
+
+#endif /* DC_HDMI_TYPES_H */
diff --git a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h
index 848db8676adf..cc3d6fb39364 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h
@@ -797,6 +797,29 @@ enum dc_timing_3d_format {
TIMING_3D_FORMAT_MAX,
};
+#define DC_DSC_QP_SET_SIZE 15
+#define DC_DSC_RC_BUF_THRESH_SIZE 14
+struct dc_dsc_rc_params_override {
+ int32_t rc_model_size;
+ int32_t rc_buf_thresh[DC_DSC_RC_BUF_THRESH_SIZE];
+ int32_t rc_minqp[DC_DSC_QP_SET_SIZE];
+ int32_t rc_maxqp[DC_DSC_QP_SET_SIZE];
+ int32_t rc_offset[DC_DSC_QP_SET_SIZE];
+
+ int32_t rc_tgt_offset_hi;
+ int32_t rc_tgt_offset_lo;
+ int32_t rc_edge_factor;
+ int32_t rc_quant_incr_limit0;
+ int32_t rc_quant_incr_limit1;
+
+ int32_t initial_fullness_offset;
+ int32_t initial_delay;
+
+ int32_t flatness_min_qp;
+ int32_t flatness_max_qp;
+ int32_t flatness_det_thresh;
+};
+
struct dc_dsc_config {
uint32_t num_slices_h; /* Number of DSC slices - horizontal */
uint32_t num_slices_v; /* Number of DSC slices - vertical */
@@ -811,6 +834,7 @@ struct dc_dsc_config {
#endif
bool is_dp; /* indicate if DSC is applied based on DP's capability */
uint32_t mst_pbn; /* pbn of display on dsc mst hub */
+ const struct dc_dsc_rc_params_override *rc_params_ovrd; /* DM owned memory. If not NULL, apply custom dsc rc params */
};
/**
diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h
index 2e18bcf6b11a..cecd807f5ed8 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_link.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_link.h
@@ -31,6 +31,7 @@
#include "grph_object_defs.h"
struct link_resource;
+enum aux_return_code_type;
enum dc_link_fec_state {
dc_link_fec_not_ready,
@@ -38,15 +39,6 @@ enum dc_link_fec_state {
dc_link_fec_enabled
};
-struct dc_link_status {
- bool link_active;
- struct dpcd_caps *dpcd_caps;
-};
-
-struct dprx_states {
- bool cable_id_written;
-};
-
/* DP MST stream allocation (payload bandwidth number) */
struct link_mst_stream_allocation {
/* DIG front */
@@ -101,6 +93,7 @@ struct psr_settings {
bool psr_allow_active; // PSR is currently active
enum dc_psr_version psr_version; // Internal PSR version, determined based on DPCD
bool psr_vtotal_control_support; // Vtotal control is supported by sink
+ unsigned long long psr_dirty_rects_change_timestamp_ns; // for delay of enabling PSR-SU
/* These parameters are calculated in Driver,
* based on display timing and Sink capabilities.
@@ -158,13 +151,15 @@ struct dc_panel_config {
struct dc_dpia_bw_alloc {
int sink_verified_bw; // The Verified BW that sink can allocated and use that has been verified already
int sink_allocated_bw; // The Actual Allocated BW that sink currently allocated
- int padding_bw; // The Padding "Un-used" BW allocated by CM for padding reasons
int sink_max_bw; // The Max BW that sink can require/support
int estimated_bw; // The estimated available BW for this DPIA
int bw_granularity; // BW Granularity
bool bw_alloc_enabled; // The BW Alloc Mode Support is turned ON for all 3: DP-Tx & Dpia & CM
+ bool response_ready; // Response ready from the CM side
};
+#define MAX_SINKS_PER_LINK 4
+
/*
* A link contains one or more sinks and their connected status.
* The currently active signal type (HDMI, DP-SST, DP-MST) is also reported.
@@ -279,6 +274,7 @@ struct dc_link {
bool dp_keep_receiver_powered;
bool dp_skip_DID2;
bool dp_skip_reset_segment;
+ bool dp_skip_fs_144hz;
bool dp_mot_reset_segment;
/* Some USB4 docks do not handle turning off MST DSC once it has been enabled. */
bool dpia_mst_dsc_always_on;
@@ -293,11 +289,12 @@ struct dc_link {
struct gpio *hpd_gpio;
enum dc_link_fec_state fec_state;
+ bool link_powered_externally; // Used to bypass hardware sequencing delays when panel is powered down forcibly
+
struct dc_panel_config panel_config;
struct phy_state phy_state;
};
-const struct dc_link_status *dc_link_get_status(const struct dc_link *dc_link);
/**
* dc_get_link_at_index() - Return an enumerated dc_link.
@@ -335,15 +332,17 @@ static inline bool dc_get_edp_link_panel_inst(const struct dc *dc,
unsigned int *inst_out)
{
struct dc_link *edp_links[MAX_NUM_EDP];
- int edp_num;
+ int edp_num, i;
+ *inst_out = 0;
if (link->connector_signal != SIGNAL_TYPE_EDP)
return false;
get_edp_links(dc, edp_links, &edp_num);
- if ((edp_num > 1) && (link->link_index > edp_links[0]->link_index))
- *inst_out = 1;
- else
- *inst_out = 0;
+ for (i = 0; i < edp_num; i++) {
+ if (link == edp_links[i])
+ break;
+ (*inst_out)++;
+ }
return true;
}
@@ -365,11 +364,6 @@ bool dc_link_get_backlight_level_nits(struct dc_link *link,
uint32_t *backlight_millinits,
uint32_t *backlight_millinits_peak);
-bool dc_link_backlight_enable_aux(struct dc_link *link, bool enable);
-
-bool dc_link_read_default_bl_aux(struct dc_link *link, uint32_t *backlight_millinits);
-bool dc_link_set_default_brightness_aux(struct dc_link *link);
-
int dc_link_get_backlight_level(const struct dc_link *dc_link);
int dc_link_get_target_backlight_pwm(const struct dc_link *link);
@@ -383,38 +377,7 @@ bool dc_link_setup_psr(struct dc_link *dc_link,
const struct dc_stream_state *stream, struct psr_config *psr_config,
struct psr_context *psr_context);
-bool dc_power_alpm_dpcd_enable(struct dc_link *link, bool enable);
-
-void dc_link_get_psr_residency(const struct dc_link *link, uint32_t *residency);
-
-void dc_link_blank_all_dp_displays(struct dc *dc);
-void dc_link_blank_all_edp_displays(struct dc *dc);
-
-void dc_link_blank_dp_stream(struct dc_link *link, bool hw_init);
-bool dc_link_set_sink_vtotal_in_psr_active(const struct dc_link *link,
- uint16_t psr_vtotal_idle, uint16_t psr_vtotal_su);
-
-/* Request DC to detect if there is a Panel connected.
- * boot - If this call is during initial boot.
- * Return false for any type of detection failure or MST detection
- * true otherwise. True meaning further action is required (status update
- * and OS notification).
- */
-enum dc_detect_reason {
- DETECT_REASON_BOOT,
- DETECT_REASON_RESUMEFROMS3S4,
- DETECT_REASON_HPD,
- DETECT_REASON_HPDRX,
- DETECT_REASON_FALLBACK,
- DETECT_REASON_RETRAIN,
- DETECT_REASON_TDR,
-};
-
-bool dc_link_detect(struct dc_link *dc_link, enum dc_detect_reason reason);
bool dc_link_get_hpd_state(struct dc_link *dc_link);
-enum dc_status dc_link_allocate_mst_payload(struct pipe_ctx *pipe_ctx);
-enum dc_status dc_link_reduce_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t req_pbn);
-enum dc_status dc_link_increase_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t req_pbn);
/* Notify DC about DP RX Interrupt (aka Short Pulse Interrupt).
* Return:
@@ -436,7 +399,11 @@ bool dc_link_wait_for_t12(struct dc_link *link);
void dc_link_dp_handle_automated_test(struct dc_link *link);
void dc_link_dp_handle_link_loss(struct dc_link *link);
bool dc_link_dp_allow_hpd_rx_irq(const struct dc_link *link);
-
+bool dc_link_check_link_loss_status(struct dc_link *link,
+ union hpd_irq_data *hpd_irq_dpcd_data);
+enum dc_status dc_link_dp_read_hpd_rx_irq_data(
+ struct dc_link *link,
+ union hpd_irq_data *irq_data);
struct dc_sink_init_data;
struct dc_sink *dc_link_add_remote_sink(
@@ -451,36 +418,6 @@ void dc_link_remove_remote_sink(
/* Used by diagnostics for virtual link at the moment */
-void dc_link_dp_set_drive_settings(
- struct dc_link *link,
- const struct link_resource *link_res,
- struct link_training_settings *lt_settings);
-
-bool dc_link_dp_perform_link_training_skip_aux(
- struct dc_link *link,
- const struct link_resource *link_res,
- const struct dc_link_settings *link_setting);
-
-enum link_training_result dc_link_dp_perform_link_training(
- struct dc_link *link,
- const struct link_resource *link_res,
- const struct dc_link_settings *link_settings,
- bool skip_video_pattern);
-
-bool dc_link_dp_sync_lt_begin(struct dc_link *link);
-
-enum link_training_result dc_link_dp_sync_lt_attempt(
- struct dc_link *link,
- const struct link_resource *link_res,
- struct dc_link_settings *link_setting,
- struct dc_link_training_overrides *lt_settings);
-
-bool dc_link_dp_sync_lt_end(struct dc_link *link, bool link_down);
-
-void dc_link_dp_enable_hpd(const struct dc_link *link);
-
-void dc_link_dp_disable_hpd(const struct dc_link *link);
-
bool dc_link_dp_set_test_pattern(
struct dc_link *link,
enum dp_test_pattern test_pattern,
@@ -491,19 +428,28 @@ bool dc_link_dp_set_test_pattern(
bool dc_link_dp_get_max_link_enc_cap(const struct dc_link *link, struct dc_link_settings *max_link_enc_cap);
+/**
+ *****************************************************************************
+ * Function: dc_link_enable_hpd_filter
+ *
+ * @brief
+ * If enable is true, programs HPD filter on associated HPD line to default
+ * values dependent on link->connector_signal
+ *
+ * If enable is false, programs HPD filter on associated HPD line with no
+ * delays on connect or disconnect
+ *
+ * @param [in] link: pointer to the dc link
+ * @param [in] enable: boolean specifying whether to enable hbd
+ *****************************************************************************
+ */
void dc_link_enable_hpd_filter(struct dc_link *link, bool enable);
bool dc_link_is_dp_sink_present(struct dc_link *link);
-
-bool dc_link_detect_sink(struct dc_link *link, enum dc_connection_type *type);
/*
* DPCD access interfaces
*/
-#ifdef CONFIG_DRM_AMD_DC_HDCP
-bool dc_link_is_hdcp14(struct dc_link *link, enum signal_type signal);
-bool dc_link_is_hdcp22(struct dc_link *link, enum signal_type signal);
-#endif
void dc_link_set_drive_settings(struct dc *dc,
struct link_training_settings *lt_settings,
const struct dc_link *link);
@@ -523,9 +469,6 @@ void dc_link_set_test_pattern(struct dc_link *link,
const struct link_training_settings *p_link_settings,
const unsigned char *p_custom_pattern,
unsigned int cust_pattern_size);
-uint32_t dc_link_bandwidth_kbps(
- const struct dc_link *link,
- const struct dc_link_settings *link_setting);
const struct dc_link_settings *dc_link_get_link_cap(
const struct dc_link *link);
@@ -547,25 +490,16 @@ bool dc_submit_i2c_oem(
struct dc *dc,
struct i2c_command *cmd);
-uint32_t dc_bandwidth_in_kbps_from_timing(
- const struct dc_crtc_timing *timing);
-
bool dc_link_is_fec_supported(const struct dc_link *link);
bool dc_link_should_enable_fec(const struct dc_link *link);
uint32_t dc_link_bw_kbps_from_raw_frl_link_rate_data(uint8_t bw);
enum dp_link_encoding dc_link_dp_mst_decide_link_encoding_format(const struct dc_link *link);
-void dc_link_get_cur_link_res(const struct dc_link *link,
- struct link_resource *link_res);
/* take a snapshot of current link resource allocation state */
void dc_get_cur_link_res_map(const struct dc *dc, uint32_t *map);
/* restore link resource allocation state from a snapshot */
void dc_restore_link_res_map(const struct dc *dc, uint32_t *map);
-void dc_link_clear_dprx_states(struct dc_link *link);
-struct gpio *get_hpd_gpio(struct dc_bios *dcb,
- struct graphics_object_id link_id,
- struct gpio_service *gpio_service);
void dp_trace_reset(struct dc_link *link);
bool dc_dp_trace_is_initialized(struct dc_link *link);
unsigned long long dc_dp_trace_get_lt_end_timestamp(struct dc_link *link,
@@ -579,6 +513,65 @@ struct dp_trace_lt_counts *dc_dp_trace_get_lt_counts(struct dc_link *link,
bool in_detection);
unsigned int dc_dp_trace_get_link_loss_count(struct dc_link *link);
-/* Destruct the mst topology of the link and reset the allocated payload table */
-bool reset_cur_dp_mst_topology(struct dc_link *link);
+/* Attempt to transfer the given aux payload. This function does not perform
+ * retries or handle error states. The reply is returned in the payload->reply
+ * and the result through operation_result. Returns the number of bytes
+ * transferred,or -1 on a failure.
+ */
+int dc_link_aux_transfer_raw(struct ddc_service *ddc,
+ struct aux_payload *payload,
+ enum aux_return_code_type *operation_result);
+
+enum lttpr_mode dc_link_decide_lttpr_mode(struct dc_link *link,
+ struct dc_link_settings *link_setting);
+void dc_link_dp_receiver_power_ctrl(struct dc_link *link, bool on);
+bool dc_link_decide_edp_link_settings(struct dc_link *link,
+ struct dc_link_settings *link_setting,
+ uint32_t req_bw);
+void dc_link_edp_panel_backlight_power_on(struct dc_link *link,
+ bool wait_for_hpd);
+
+/*
+ * USB4 DPIA BW ALLOCATION PUBLIC FUNCTIONS
+ */
+/*
+ * Send a request from DP-Tx requesting to allocate BW remotely after
+ * allocating it locally. This will get processed by CM and a CB function
+ * will be called.
+ *
+ * @link: pointer to the dc_link struct instance
+ * @req_bw: The requested bw in Kbyte to allocated
+ *
+ * return: none
+ */
+void dc_link_set_usb4_req_bw_req(struct dc_link *link, int req_bw);
+
+/*
+ * CB function for when the status of the Req above is complete. We will
+ * find out the result of allocating on CM and update structs accordingly
+ *
+ * @link: pointer to the dc_link struct instance
+ * @bw: Allocated or Estimated BW depending on the result
+ * @result: Response type
+ *
+ * return: none
+ */
+void dc_link_get_usb4_req_bw_resp(struct dc_link *link, uint8_t bw, uint8_t result);
+
+/*
+ * Handle the USB4 BW Allocation related functionality here:
+ * Plug => Try to allocate max bw from timing parameters supported by the sink
+ * Unplug => de-allocate bw
+ *
+ * @link: pointer to the dc_link struct instance
+ * @peak_bw: Peak bw used by the link/sink
+ *
+ * return: allocated bw else return 0
+ */
+int dc_link_dp_dpia_handle_usb4_bandwidth_allocation_for_link(struct dc_link *link, int peak_bw);
+
+/* TODO: this is not meant to be exposed to DM. Should switch to stream update
+ * interface i.e stream_update->dsc_config
+ */
+bool dc_link_update_dsc_config(struct pipe_ctx *pipe_ctx);
#endif /* DC_LINK_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h
index dfd3df1d2f7e..567452599659 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_stream.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h
@@ -190,6 +190,7 @@ struct dc_stream_state {
struct dc_info_packet vsp_infopacket;
struct dc_info_packet hfvsif_infopacket;
struct dc_info_packet vtem_infopacket;
+ struct dc_info_packet adaptive_sync_infopacket;
uint8_t dsc_packed_pps[128];
struct rect src; /* composition area */
struct rect dst; /* stream addressable area */
@@ -313,6 +314,7 @@ struct dc_stream_update {
struct dc_info_packet *vsp_infopacket;
struct dc_info_packet *hfvsif_infopacket;
struct dc_info_packet *vtem_infopacket;
+ struct dc_info_packet *adaptive_sync_infopacket;
bool *dpms_off;
bool integer_scaling_update;
bool *allow_freesync;
@@ -543,9 +545,8 @@ bool dc_stream_get_crtc_position(struct dc *dc,
unsigned int *nom_v_pos);
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
-bool dc_stream_forward_crc_window(struct dc *dc,
+bool dc_stream_forward_crc_window(struct dc_stream_state *stream,
struct rect *rect,
- struct dc_stream_state *stream,
bool is_stop);
#endif
diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h
index dc78e2404b48..27d0242d6cbd 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_types.h
@@ -32,7 +32,9 @@
#include "os_types.h"
#include "fixed31_32.h"
#include "irq_types.h"
+#include "dc_ddc_types.h"
#include "dc_dp_types.h"
+#include "dc_hdmi_types.h"
#include "dc_hw_types.h"
#include "dal_types.h"
#include "grph_object_defs.h"
@@ -82,13 +84,8 @@ struct dc_perf_trace {
unsigned long last_entry_write;
};
-#define DC_MAX_EDID_BUFFER_SIZE 2048
-#define DC_EDID_BLOCK_SIZE 128
#define MAX_SURFACE_NUM 4
#define NUM_PIXEL_FORMATS 10
-#define MAX_REPEATER_CNT 8
-
-#include "dc_ddc_types.h"
enum tiling_mode {
TILING_MODE_INVALID,
@@ -374,66 +371,6 @@ struct dc_csc_adjustments {
struct fixed31_32 hue;
};
-enum dpcd_downstream_port_max_bpc {
- DOWN_STREAM_MAX_8BPC = 0,
- DOWN_STREAM_MAX_10BPC,
- DOWN_STREAM_MAX_12BPC,
- DOWN_STREAM_MAX_16BPC
-};
-
-
-enum link_training_offset {
- DPRX = 0,
- LTTPR_PHY_REPEATER1 = 1,
- LTTPR_PHY_REPEATER2 = 2,
- LTTPR_PHY_REPEATER3 = 3,
- LTTPR_PHY_REPEATER4 = 4,
- LTTPR_PHY_REPEATER5 = 5,
- LTTPR_PHY_REPEATER6 = 6,
- LTTPR_PHY_REPEATER7 = 7,
- LTTPR_PHY_REPEATER8 = 8
-};
-
-struct dc_lttpr_caps {
- union dpcd_rev revision;
- uint8_t mode;
- uint8_t max_lane_count;
- uint8_t max_link_rate;
- uint8_t phy_repeater_cnt;
- uint8_t max_ext_timeout;
- union dp_main_link_channel_coding_lttpr_cap main_link_channel_coding;
- union dp_128b_132b_supported_lttpr_link_rates supported_128b_132b_rates;
- uint8_t aux_rd_interval[MAX_REPEATER_CNT - 1];
-};
-
-struct dc_dongle_dfp_cap_ext {
- bool supported;
- uint16_t max_pixel_rate_in_mps;
- uint16_t max_video_h_active_width;
- uint16_t max_video_v_active_height;
- struct dp_encoding_format_caps encoding_format_caps;
- struct dp_color_depth_caps rgb_color_depth_caps;
- struct dp_color_depth_caps ycbcr444_color_depth_caps;
- struct dp_color_depth_caps ycbcr422_color_depth_caps;
- struct dp_color_depth_caps ycbcr420_color_depth_caps;
-};
-
-struct dc_dongle_caps {
- /* dongle type (DP converter, CV smart dongle) */
- enum display_dongle_type dongle_type;
- bool extendedCapValid;
- /* If dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER,
- indicates 'Frame Sequential-to-lllFrame Pack' conversion capability.*/
- bool is_dp_hdmi_s3d_converter;
- bool is_dp_hdmi_ycbcr422_pass_through;
- bool is_dp_hdmi_ycbcr420_pass_through;
- bool is_dp_hdmi_ycbcr422_converter;
- bool is_dp_hdmi_ycbcr420_converter;
- uint32_t dp_hdmi_max_bpc;
- uint32_t dp_hdmi_max_pixel_clk_in_khz;
- uint32_t dp_hdmi_frl_max_link_bw_in_kbps;
- struct dc_dongle_dfp_cap_ext dfp_cap_ext;
-};
/* Scaling format */
enum scaling_transformation {
SCALING_TRANSFORMATION_UNINITIALIZED,
@@ -690,6 +627,7 @@ struct psr_config {
uint8_t su_y_granularity;
unsigned int line_time_in_us;
uint8_t rate_control_caps;
+ uint16_t dsc_slice_height;
};
union dmcu_psr_level {
@@ -801,6 +739,7 @@ struct psr_context {
uint8_t su_y_granularity;
unsigned int line_time_in_us;
uint8_t rate_control_caps;
+ uint16_t dsc_slice_height;
};
struct colorspace_transform {
@@ -1000,4 +939,47 @@ struct otg_phy_mux {
};
#endif
+enum dc_detect_reason {
+ DETECT_REASON_BOOT,
+ DETECT_REASON_RESUMEFROMS3S4,
+ DETECT_REASON_HPD,
+ DETECT_REASON_HPDRX,
+ DETECT_REASON_FALLBACK,
+ DETECT_REASON_RETRAIN,
+ DETECT_REASON_TDR,
+};
+
+struct dc_link_status {
+ bool link_active;
+ struct dpcd_caps *dpcd_caps;
+};
+
+#if defined(CONFIG_DRM_AMD_DC_HDCP)
+union hdcp_rx_caps {
+ struct {
+ uint8_t version;
+ uint8_t reserved;
+ struct {
+ uint8_t repeater : 1;
+ uint8_t hdcp_capable : 1;
+ uint8_t reserved : 6;
+ } byte0;
+ } fields;
+ uint8_t raw[3];
+};
+
+union hdcp_bcaps {
+ struct {
+ uint8_t HDCP_CAPABLE:1;
+ uint8_t REPEATER:1;
+ uint8_t RESERVED:6;
+ } bits;
+ uint8_t raw;
+};
+
+struct hdcp_caps {
+ union hdcp_rx_caps rx_caps;
+ union hdcp_bcaps bcaps;
+};
+#endif
#endif /* DC_TYPES_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h
index e69f1899fbf0..c850ed49281f 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h
@@ -26,7 +26,7 @@
#ifndef __DAL_AUX_ENGINE_DCE110_H__
#define __DAL_AUX_ENGINE_DCE110_H__
-#include "i2caux_interface.h"
+#include "gpio_service_interface.h"
#include "inc/hw/aux_engine.h"
enum aux_return_code_type;
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c
index 09260c23c3bd..fa314493ffc5 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c
@@ -29,7 +29,6 @@
#include "link_encoder.h"
#include "dce_link_encoder.h"
#include "stream_encoder.h"
-#include "i2caux_interface.h"
#include "dc_bios_types.h"
#include "gpio_service_interface.h"
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c
index 2d3201b77d6a..1e2d2cbe2c37 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c
@@ -417,6 +417,7 @@ static bool dmub_psr_copy_settings(struct dmub_psr *dmub,
copy_settings_data->relock_delay_frame_cnt = 0;
if (link->dpcd_caps.sink_dev_id == DP_BRANCH_DEVICE_ID_001CF8)
copy_settings_data->relock_delay_frame_cnt = 2;
+ copy_settings_data->dsc_slice_height = psr_context->dsc_slice_height;
dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd);
dc_dmub_srv_cmd_execute(dc->dmub_srv);
diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
index 913a1fe6b3da..0d4d3d586166 100644
--- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
+++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
@@ -46,7 +46,7 @@
#include "link_encoder.h"
#include "link_enc_cfg.h"
#include "link_hwss.h"
-#include "dc_link_dp.h"
+#include "link.h"
#include "dccg.h"
#include "clock_source.h"
#include "clk_mgr.h"
@@ -54,7 +54,6 @@
#include "audio.h"
#include "reg_helper.h"
#include "panel_cntl.h"
-#include "inc/link_dpcd.h"
#include "dpcd_defs.h"
/* include DCE11 register header files */
#include "dce/dce_11_0_d.h"
@@ -65,7 +64,6 @@
#include "dcn10/dcn10_hw_sequencer.h"
-#include "link/link_dp_trace.h"
#include "dce110_hw_sequencer.h"
#define GAMMA_HW_POINTS_NUM 256
@@ -653,10 +651,16 @@ void dce110_update_info_frame(struct pipe_ctx *pipe_ctx)
pipe_ctx->stream_res.stream_enc->funcs->update_hdmi_info_packets(
pipe_ctx->stream_res.stream_enc,
&pipe_ctx->stream_res.encoder_info_frame);
- else
+ else {
+ if (pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets_sdp_line_num)
+ pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets_sdp_line_num(
+ pipe_ctx->stream_res.stream_enc,
+ &pipe_ctx->stream_res.encoder_info_frame);
+
pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets(
pipe_ctx->stream_res.stream_enc,
&pipe_ctx->stream_res.encoder_info_frame);
+ }
}
void dce110_enable_stream(struct pipe_ctx *pipe_ctx)
@@ -737,7 +741,7 @@ void dce110_edp_wait_for_hpd_ready(
/* obtain HPD */
/* TODO what to do with this? */
- hpd = get_hpd_gpio(ctx->dc_bios, connector, ctx->gpio_service);
+ hpd = link_get_hpd_gpio(ctx->dc_bios, connector, ctx->gpio_service);
if (!hpd) {
BREAK_TO_DEBUGGER();
@@ -775,10 +779,8 @@ void dce110_edp_wait_for_hpd_ready(
dal_gpio_destroy_irq(&hpd);
- if (false == edp_hpd_high) {
- DC_LOG_WARNING(
- "%s: wait timed out!\n", __func__);
- }
+ /* ensure that the panel is detected */
+ ASSERT(edp_hpd_high);
}
void dce110_edp_power_control(
@@ -807,19 +809,19 @@ void dce110_edp_power_control(
div64_u64(dm_get_elapse_time_in_ns(
ctx,
current_ts,
- dp_trace_get_edp_poweroff_timestamp(link)), 1000000);
+ link_dp_trace_get_edp_poweroff_timestamp(link)), 1000000);
unsigned long long time_since_edp_poweron_ms =
div64_u64(dm_get_elapse_time_in_ns(
ctx,
current_ts,
- dp_trace_get_edp_poweron_timestamp(link)), 1000000);
+ link_dp_trace_get_edp_poweron_timestamp(link)), 1000000);
DC_LOG_HW_RESUME_S3(
"%s: transition: power_up=%d current_ts=%llu edp_poweroff=%llu edp_poweron=%llu time_since_edp_poweroff_ms=%llu time_since_edp_poweron_ms=%llu",
__func__,
power_up,
current_ts,
- dp_trace_get_edp_poweroff_timestamp(link),
- dp_trace_get_edp_poweron_timestamp(link),
+ link_dp_trace_get_edp_poweroff_timestamp(link),
+ link_dp_trace_get_edp_poweron_timestamp(link),
time_since_edp_poweroff_ms,
time_since_edp_poweron_ms);
@@ -834,7 +836,7 @@ void dce110_edp_power_control(
link->panel_config.pps.extra_t12_ms;
/* Adjust remaining_min_edp_poweroff_time_ms if this is not the first time. */
- if (dp_trace_get_edp_poweroff_timestamp(link) != 0) {
+ if (link_dp_trace_get_edp_poweroff_timestamp(link) != 0) {
if (time_since_edp_poweroff_ms < remaining_min_edp_poweroff_time_ms)
remaining_min_edp_poweroff_time_ms =
remaining_min_edp_poweroff_time_ms - time_since_edp_poweroff_ms;
@@ -875,14 +877,16 @@ void dce110_edp_power_control(
if (ctx->dc->ctx->dmub_srv &&
ctx->dc->debug.dmub_command_table) {
- if (cntl.action == TRANSMITTER_CONTROL_POWER_ON)
+
+ if (cntl.action == TRANSMITTER_CONTROL_POWER_ON) {
bp_result = ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios,
LVTMA_CONTROL_POWER_ON,
- panel_instance);
- else
+ panel_instance, link->link_powered_externally);
+ } else {
bp_result = ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios,
LVTMA_CONTROL_POWER_OFF,
- panel_instance);
+ panel_instance, link->link_powered_externally);
+ }
}
bp_result = link_transmitter_control(ctx->dc_bios, &cntl);
@@ -892,13 +896,13 @@ void dce110_edp_power_control(
__func__, (power_up ? "On":"Off"),
bp_result);
- dp_trace_set_edp_power_timestamp(link, power_up);
+ link_dp_trace_set_edp_power_timestamp(link, power_up);
DC_LOG_HW_RESUME_S3(
"%s: updated values: edp_poweroff=%llu edp_poweron=%llu\n",
__func__,
- dp_trace_get_edp_poweroff_timestamp(link),
- dp_trace_get_edp_poweron_timestamp(link));
+ link_dp_trace_get_edp_poweroff_timestamp(link),
+ link_dp_trace_get_edp_poweron_timestamp(link));
if (bp_result != BP_RESULT_OK)
DC_LOG_ERROR(
@@ -926,14 +930,14 @@ void dce110_edp_wait_for_T12(
return;
if (!link->panel_cntl->funcs->is_panel_powered_on(link->panel_cntl) &&
- dp_trace_get_edp_poweroff_timestamp(link) != 0) {
+ link_dp_trace_get_edp_poweroff_timestamp(link) != 0) {
unsigned int t12_duration = 500; // Default T12 as per spec
unsigned long long current_ts = dm_get_timestamp(ctx);
unsigned long long time_since_edp_poweroff_ms =
div64_u64(dm_get_elapse_time_in_ns(
ctx,
current_ts,
- dp_trace_get_edp_poweroff_timestamp(link)), 1000000);
+ link_dp_trace_get_edp_poweroff_timestamp(link)), 1000000);
t12_duration += link->panel_config.pps.extra_t12_ms; // Add extra T12
@@ -941,7 +945,6 @@ void dce110_edp_wait_for_T12(
msleep(t12_duration - time_since_edp_poweroff_ms);
}
}
-
/*todo: cloned in stream enc, fix*/
/*
* @brief
@@ -1015,21 +1018,25 @@ void dce110_edp_backlight_control(
* we shouldn't be doing power-sequencing, hence we can skip
* waiting for T7-ready.
*/
- edp_receiver_ready_T7(link);
+ link_edp_receiver_ready_T7(link);
else
DC_LOG_DC("edp_receiver_ready_T7 skipped\n");
}
+ /* Setting link_powered_externally will bypass delays in the backlight
+ * as they are not required if the link is being powered by a different
+ * source.
+ */
if (ctx->dc->ctx->dmub_srv &&
ctx->dc->debug.dmub_command_table) {
if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_ON)
ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios,
LVTMA_CONTROL_LCD_BLON,
- panel_instance);
+ panel_instance, link->link_powered_externally);
else
ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios,
LVTMA_CONTROL_LCD_BLOFF,
- panel_instance);
+ panel_instance, link->link_powered_externally);
}
link_transmitter_control(ctx->dc_bios, &cntl);
@@ -1042,7 +1049,7 @@ void dce110_edp_backlight_control(
if (link->dpcd_sink_ext_caps.bits.oled ||
link->dpcd_sink_ext_caps.bits.hdr_aux_backlight_control == 1 ||
link->dpcd_sink_ext_caps.bits.sdr_aux_backlight_control == 1)
- dc_link_backlight_enable_aux(link, enable);
+ link_backlight_enable_aux(link, enable);
/*edp 1.2*/
if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_OFF) {
@@ -1054,7 +1061,7 @@ void dce110_edp_backlight_control(
* we shouldn't be doing power-sequencing, hence we can skip
* waiting for T9-ready.
*/
- edp_add_delay_for_T9(link);
+ link_edp_add_delay_for_T9(link);
else
DC_LOG_DC("edp_receiver_ready_T9 skipped\n");
}
@@ -1142,6 +1149,10 @@ void dce110_disable_stream(struct pipe_ctx *pipe_ctx)
struct dc_link *link = stream->link;
struct dc *dc = pipe_ctx->stream->ctx->dc;
const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
+ struct dccg *dccg = dc->res_pool->dccg;
+ struct timing_generator *tg = pipe_ctx->stream_res.tg;
+ struct dtbclk_dto_params dto_params = {0};
+ int dp_hpo_inst;
if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal)) {
pipe_ctx->stream_res.stream_enc->funcs->stop_hdmi_info_packets(
@@ -1150,7 +1161,7 @@ void dce110_disable_stream(struct pipe_ctx *pipe_ctx)
pipe_ctx->stream_res.stream_enc);
}
- if (is_dp_128b_132b_signal(pipe_ctx)) {
+ if (link_is_dp_128b_132b_signal(pipe_ctx)) {
pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->stop_dp_info_packets(
pipe_ctx->stream_res.hpo_dp_stream_enc);
} else if (dc_is_dp_signal(pipe_ctx->stream->signal))
@@ -1161,7 +1172,16 @@ void dce110_disable_stream(struct pipe_ctx *pipe_ctx)
link_hwss->reset_stream_encoder(pipe_ctx);
- if (is_dp_128b_132b_signal(pipe_ctx)) {
+ if (link_is_dp_128b_132b_signal(pipe_ctx)) {
+ dto_params.otg_inst = tg->inst;
+ dto_params.timing = &pipe_ctx->stream->timing;
+ dp_hpo_inst = pipe_ctx->stream_res.hpo_dp_stream_enc->inst;
+ dccg->funcs->set_dtbclk_dto(dccg, &dto_params);
+ dccg->funcs->disable_symclk32_se(dccg, dp_hpo_inst);
+ dccg->funcs->set_dpstreamclk(dccg, REFCLK, tg->inst, dp_hpo_inst);
+ }
+
+ if (link_is_dp_128b_132b_signal(pipe_ctx)) {
/* TODO: This looks like a bug to me as we are disabling HPO IO when
* we are just disabling a single HPO stream. Shouldn't we disable HPO
* HW control only when HPOs for all streams are disabled?
@@ -1203,7 +1223,7 @@ void dce110_blank_stream(struct pipe_ctx *pipe_ctx)
link->dc->hwss.set_abm_immediate_disable(pipe_ctx);
}
- if (is_dp_128b_132b_signal(pipe_ctx)) {
+ if (link_is_dp_128b_132b_signal(pipe_ctx)) {
/* TODO - DP2.0 HW: Set ODM mode in dp hpo encoder here */
pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_blank(
pipe_ctx->stream_res.hpo_dp_stream_enc);
@@ -1225,7 +1245,7 @@ void dce110_blank_stream(struct pipe_ctx *pipe_ctx)
* we shouldn't be doing power-sequencing, hence we can skip
* waiting for T9-ready.
*/
- edp_receiver_ready_T9(link);
+ link_edp_receiver_ready_T9(link);
}
}
}
@@ -1408,7 +1428,7 @@ static enum dc_status dce110_enable_stream_timing(
if (false == pipe_ctx->clock_source->funcs->program_pix_clk(
pipe_ctx->clock_source,
&pipe_ctx->stream_res.pix_clk_params,
- dp_get_link_encoding_format(&pipe_ctx->link_config.dp_link_settings),
+ link_dp_get_encoding_format(&pipe_ctx->link_config.dp_link_settings),
&pipe_ctx->pll_settings)) {
BREAK_TO_DEBUGGER();
return DC_ERROR_UNEXPECTED;
@@ -1512,7 +1532,7 @@ static enum dc_status apply_single_controller_ctx_to_hw(
* To do so, move calling function enable_stream_timing to only be done AFTER calling
* function core_link_enable_stream
*/
- if (!(hws->wa.dp_hpo_and_otg_sequence && is_dp_128b_132b_signal(pipe_ctx)))
+ if (!(hws->wa.dp_hpo_and_otg_sequence && link_is_dp_128b_132b_signal(pipe_ctx)))
/* */
/* Do not touch stream timing on seamless boot optimization. */
if (!pipe_ctx->stream->apply_seamless_boot_optimization)
@@ -1544,17 +1564,17 @@ static enum dc_status apply_single_controller_ctx_to_hw(
pipe_ctx->stream_res.tg->inst);
if (dc_is_dp_signal(pipe_ctx->stream->signal))
- dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_CONNECT_DIG_FE_OTG);
+ link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_CONNECT_DIG_FE_OTG);
if (!stream->dpms_off)
- core_link_enable_stream(context, pipe_ctx);
+ link_set_dpms_on(context, pipe_ctx);
/* DCN3.1 FPGA Workaround
* Need to enable HPO DP Stream Encoder before setting OTG master enable.
* To do so, move calling function enable_stream_timing to only be done AFTER calling
* function core_link_enable_stream
*/
- if (hws->wa.dp_hpo_and_otg_sequence && is_dp_128b_132b_signal(pipe_ctx)) {
+ if (hws->wa.dp_hpo_and_otg_sequence && link_is_dp_128b_132b_signal(pipe_ctx)) {
if (!pipe_ctx->stream->apply_seamless_boot_optimization)
hws->funcs.enable_stream_timing(pipe_ctx, context, dc);
}
@@ -1580,7 +1600,7 @@ static void power_down_encoders(struct dc *dc)
for (i = 0; i < dc->link_count; i++) {
enum signal_type signal = dc->links[i]->connector_signal;
- dc_link_blank_dp_stream(dc->links[i], false);
+ link_blank_dp_stream(dc->links[i], false);
if (signal != SIGNAL_TYPE_EDP)
signal = SIGNAL_TYPE_NONE;
@@ -2063,7 +2083,7 @@ static void dce110_reset_hw_ctx_wrap(
* disabled already, no need to disable again.
*/
if (!pipe_ctx->stream || !pipe_ctx->stream->dpms_off) {
- core_link_disable_stream(pipe_ctx_old);
+ link_set_dpms_off(pipe_ctx_old);
/* free acquired resources*/
if (pipe_ctx_old->stream_res.audio) {
@@ -3034,13 +3054,13 @@ void dce110_enable_dp_link_output(
pipes[i].clock_source->funcs->program_pix_clk(
pipes[i].clock_source,
&pipes[i].stream_res.pix_clk_params,
- dp_get_link_encoding_format(link_settings),
+ link_dp_get_encoding_format(link_settings),
&pipes[i].pll_settings);
}
}
}
- if (dp_get_link_encoding_format(link_settings) == DP_8b_10b_ENCODING) {
+ if (link_dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING) {
if (dc->clk_mgr->funcs->notify_link_rate_change)
dc->clk_mgr->funcs->notify_link_rate_change(dc->clk_mgr, link);
}
@@ -3057,7 +3077,7 @@ void dce110_enable_dp_link_output(
if (dmcu != NULL && dmcu->funcs->unlock_phy)
dmcu->funcs->unlock_phy(dmcu);
- dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_LINK_PHY);
+ link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_LINK_PHY);
}
void dce110_disable_link_output(struct dc_link *link,
@@ -3082,7 +3102,7 @@ void dce110_disable_link_output(struct dc_link *link,
link->dc->hwss.edp_power_control(link, false);
else if (dmcu != NULL && dmcu->funcs->lock_phy)
dmcu->funcs->unlock_phy(dmcu);
- dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY);
+ link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY);
}
static const struct hw_sequencer_funcs dce110_funcs = {
diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h
index 758f4b3b0087..394d83a97f33 100644
--- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h
+++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h
@@ -71,7 +71,7 @@ void dce110_optimize_bandwidth(
struct dc *dc,
struct dc_state *context);
-void dp_receiver_power_ctrl(struct dc_link *link, bool on);
+void dc_link_dp_receiver_power_ctrl(struct dc_link *link, bool on);
void dce110_edp_power_control(
struct dc_link *link,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c
index f607a0e28f14..f62368da875d 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c
@@ -581,7 +581,7 @@ static void dpp1_dscl_set_manual_ratio_init(
* dpp1_dscl_set_recout - Set the first pixel of RECOUT in the OTG active area
*
* @dpp: DPP data struct
- * @recount: Rectangle information
+ * @recout: Rectangle information
*
* This function sets the MPC RECOUT_START and RECOUT_SIZE registers based on
* the values specified in the recount parameter.
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h
index ba1c0621f0f8..e8752077571a 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h
@@ -172,6 +172,10 @@ struct dcn_hubbub_registers {
uint32_t DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_C;
uint32_t DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_D;
uint32_t SDPIF_REQUEST_RATE_LIMIT;
+ uint32_t DCHUBBUB_SDPIF_CFG0;
+ uint32_t DCHUBBUB_SDPIF_CFG1;
+ uint32_t DCHUBBUB_CLOCK_CNTL;
+ uint32_t DCHUBBUB_MEM_PWR_MODE_CTRL;
};
#define HUBBUB_REG_FIELD_LIST_DCN32(type) \
@@ -362,7 +366,13 @@ struct dcn_hubbub_registers {
type DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_C;\
type DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_D;\
type DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_D;\
- type SDPIF_REQUEST_RATE_LIMIT
+ type SDPIF_REQUEST_RATE_LIMIT;\
+ type DISPCLK_R_DCHUBBUB_GATE_DIS;\
+ type DCFCLK_R_DCHUBBUB_GATE_DIS;\
+ type SDPIF_MAX_NUM_OUTSTANDING;\
+ type DCHUBBUB_ARB_MAX_REQ_OUTSTAND;\
+ type SDPIF_PORT_CONTROL;\
+ type DET_MEM_PWR_LS_MODE
struct dcn_hubbub_shift {
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
index 8f894c1d1d1e..a1a29c508394 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
@@ -45,7 +45,6 @@
#include "dcn10_hubp.h"
#include "dcn10_hubbub.h"
#include "dcn10_cm_common.h"
-#include "dc_link_dp.h"
#include "dccg.h"
#include "clk_mgr.h"
#include "link_hwss.h"
@@ -56,8 +55,7 @@
#include "dce/dmub_hw_lock_mgr.h"
#include "dc_trace.h"
#include "dce/dmub_outbox.h"
-#include "inc/dc_link_dp.h"
-#include "inc/link_dpcd.h"
+#include "link.h"
#define DC_LOGGER_INIT(logger)
@@ -921,7 +919,7 @@ enum dc_status dcn10_enable_stream_timing(
if (false == pipe_ctx->clock_source->funcs->program_pix_clk(
pipe_ctx->clock_source,
&pipe_ctx->stream_res.pix_clk_params,
- dp_get_link_encoding_format(&pipe_ctx->link_config.dp_link_settings),
+ link_dp_get_encoding_format(&pipe_ctx->link_config.dp_link_settings),
&pipe_ctx->pll_settings)) {
BREAK_TO_DEBUGGER();
return DC_ERROR_UNEXPECTED;
@@ -1019,7 +1017,7 @@ static void dcn10_reset_back_end_for_pipe(
* VBIOS lit up eDP, so check link status too.
*/
if (!pipe_ctx->stream->dpms_off || link->link_status.link_active)
- core_link_disable_stream(pipe_ctx);
+ link_set_dpms_off(pipe_ctx);
else if (pipe_ctx->stream_res.audio)
dc->hwss.disable_audio_stream(pipe_ctx);
@@ -1566,7 +1564,7 @@ void dcn10_init_hw(struct dc *dc)
}
/* we want to turn off all dp displays before doing detection */
- dc_link_blank_all_dp_displays(dc);
+ link_blank_all_dp_displays(dc);
if (hws->funcs.enable_power_gating_plane)
hws->funcs.enable_power_gating_plane(dc->hwseq, true);
@@ -2901,7 +2899,7 @@ void dcn10_blank_pixel_data(
dc->hwss.set_pipe(pipe_ctx);
stream_res->abm->funcs->set_abm_level(stream_res->abm, stream->abm_level);
}
- } else if (blank) {
+ } else {
dc->hwss.set_abm_immediate_disable(pipe_ctx);
if (stream_res->tg->funcs->set_blank) {
stream_res->tg->funcs->wait_for_state(stream_res->tg, CRTC_STATE_VBLANK);
@@ -3225,12 +3223,16 @@ static void dcn10_config_stereo_parameters(
timing_3d_format == TIMING_3D_FORMAT_INBAND_FA ||
timing_3d_format == TIMING_3D_FORMAT_DP_HDMI_INBAND_FA ||
timing_3d_format == TIMING_3D_FORMAT_SIDEBAND_FA) {
- enum display_dongle_type dongle = \
- stream->link->ddc->dongle_type;
- if (dongle == DISPLAY_DONGLE_DP_VGA_CONVERTER ||
- dongle == DISPLAY_DONGLE_DP_DVI_CONVERTER ||
- dongle == DISPLAY_DONGLE_DP_HDMI_CONVERTER)
- flags->DISABLE_STEREO_DP_SYNC = 1;
+
+ if (stream->link && stream->link->ddc) {
+ enum display_dongle_type dongle = \
+ stream->link->ddc->dongle_type;
+
+ if (dongle == DISPLAY_DONGLE_DP_VGA_CONVERTER ||
+ dongle == DISPLAY_DONGLE_DP_DVI_CONVERTER ||
+ dongle == DISPLAY_DONGLE_DP_HDMI_CONVERTER)
+ flags->DISABLE_STEREO_DP_SYNC = 1;
+ }
}
flags->RIGHT_EYE_POLARITY =\
stream->timing.flags.RIGHT_EYE_3D_POLARITY;
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c
index fbccb7263ad2..c4287147b853 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c
@@ -29,7 +29,6 @@
#include "link_encoder.h"
#include "dcn10_link_encoder.h"
#include "stream_encoder.h"
-#include "i2caux_interface.h"
#include "dc_bios_types.h"
#include "gpio_service_interface.h"
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h
index 88ac5f6f4c96..0b37bb0e184b 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h
@@ -519,7 +519,8 @@ struct dcn_optc_registers {
type OTG_CRC_DATA_STREAM_COMBINE_MODE;\
type OTG_CRC_DATA_STREAM_SPLIT_MODE;\
type OTG_CRC_DATA_FORMAT;\
- type OTG_V_TOTAL_LAST_USED_BY_DRR;
+ type OTG_V_TOTAL_LAST_USED_BY_DRR;\
+ type OTG_DRR_TIMING_DBUF_UPDATE_PENDING;
#define TG_REG_FIELD_LIST_DCN3_2(type) \
type OTG_H_TIMING_DIV_MODE_MANUAL;
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c
index 484e7cdf00b8..3c451ab5d3ca 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c
@@ -28,7 +28,7 @@
#include "dcn10_stream_encoder.h"
#include "reg_helper.h"
#include "hw_shared.h"
-#include "inc/link_dpcd.h"
+#include "link.h"
#include "dpcd_defs.h"
#include "dcn30/dcn30_afmt.h"
@@ -753,12 +753,19 @@ void enc1_stream_encoder_update_dp_info_packets(
* use other packetIndex (such as 5,6) for other info packet
*/
+ if (info_frame->adaptive_sync.valid)
+ enc1_update_generic_info_packet(
+ enc1,
+ 5, /* packetIndex */
+ &info_frame->adaptive_sync);
+
/* enable/disable transmission of packet(s).
* If enabled, packet transmission begins on the next frame
*/
REG_UPDATE(DP_SEC_CNTL, DP_SEC_GSP0_ENABLE, info_frame->vsc.valid);
REG_UPDATE(DP_SEC_CNTL, DP_SEC_GSP2_ENABLE, info_frame->spd.valid);
REG_UPDATE(DP_SEC_CNTL, DP_SEC_GSP3_ENABLE, info_frame->hdrsmd.valid);
+ REG_UPDATE(DP_SEC_CNTL, DP_SEC_GSP5_ENABLE, info_frame->adaptive_sync.valid);
/* This bit is the master enable bit.
* When enabling secondary stream engine,
@@ -926,7 +933,7 @@ void enc1_stream_encoder_dp_blank(
/* disable DP stream */
REG_UPDATE(DP_VID_STREAM_CNTL, DP_VID_STREAM_ENABLE, 0);
- dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_DP_VID_STREAM);
+ link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_DP_VID_STREAM);
/* the encoder stops sending the video stream
* at the start of the vertical blanking.
@@ -945,7 +952,7 @@ void enc1_stream_encoder_dp_blank(
REG_UPDATE(DP_STEER_FIFO, DP_STEER_FIFO_RESET, true);
- dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_FIFO_STEER_RESET);
+ link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_FIFO_STEER_RESET);
}
/* output video stream to link encoder */
@@ -1018,7 +1025,7 @@ void enc1_stream_encoder_dp_unblank(
REG_UPDATE(DP_VID_STREAM_CNTL, DP_VID_STREAM_ENABLE, true);
- dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_DP_VID_STREAM);
+ link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_DP_VID_STREAM);
}
void enc1_stream_encoder_set_avmute(
diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c
index 784a8b6f360d..42344aec60d6 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c
@@ -28,6 +28,7 @@
#include "reg_helper.h"
#include "dcn20_dsc.h"
#include "dsc/dscc_types.h"
+#include "dsc/rc_calc.h"
static void dsc_log_pps(struct display_stream_compressor *dsc, struct drm_dsc_config *pps);
static bool dsc_prepare_config(const struct dsc_config *dsc_cfg, struct dsc_reg_values *dsc_reg_vals,
@@ -200,7 +201,6 @@ static void dsc2_set_config(struct display_stream_compressor *dsc, const struct
bool is_config_ok;
struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc);
- DC_LOG_DSC(" ");
DC_LOG_DSC("Setting DSC Config at DSC inst %d", dsc->inst);
dsc_config_log(dsc, dsc_cfg);
is_config_ok = dsc_prepare_config(dsc_cfg, &dsc20->reg_vals, dsc_optc_cfg);
@@ -345,10 +345,38 @@ static void dsc_log_pps(struct display_stream_compressor *dsc, struct drm_dsc_co
}
}
+static void dsc_override_rc_params(struct rc_params *rc, const struct dc_dsc_rc_params_override *override)
+{
+ uint8_t i;
+
+ rc->rc_model_size = override->rc_model_size;
+ for (i = 0; i < DC_DSC_RC_BUF_THRESH_SIZE; i++)
+ rc->rc_buf_thresh[i] = override->rc_buf_thresh[i];
+ for (i = 0; i < DC_DSC_QP_SET_SIZE; i++) {
+ rc->qp_min[i] = override->rc_minqp[i];
+ rc->qp_max[i] = override->rc_maxqp[i];
+ rc->ofs[i] = override->rc_offset[i];
+ }
+
+ rc->rc_tgt_offset_hi = override->rc_tgt_offset_hi;
+ rc->rc_tgt_offset_lo = override->rc_tgt_offset_lo;
+ rc->rc_edge_factor = override->rc_edge_factor;
+ rc->rc_quant_incr_limit0 = override->rc_quant_incr_limit0;
+ rc->rc_quant_incr_limit1 = override->rc_quant_incr_limit1;
+
+ rc->initial_fullness_offset = override->initial_fullness_offset;
+ rc->initial_xmit_delay = override->initial_delay;
+
+ rc->flatness_min_qp = override->flatness_min_qp;
+ rc->flatness_max_qp = override->flatness_max_qp;
+ rc->flatness_det_thresh = override->flatness_det_thresh;
+}
+
static bool dsc_prepare_config(const struct dsc_config *dsc_cfg, struct dsc_reg_values *dsc_reg_vals,
struct dsc_optc_config *dsc_optc_cfg)
{
struct dsc_parameters dsc_params;
+ struct rc_params rc;
/* Validate input parameters */
ASSERT(dsc_cfg->dc_dsc_cfg.num_slices_h);
@@ -413,7 +441,12 @@ static bool dsc_prepare_config(const struct dsc_config *dsc_cfg, struct dsc_reg_
dsc_reg_vals->pps.native_420 = (dsc_reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR420);
dsc_reg_vals->pps.simple_422 = (dsc_reg_vals->pixel_format == DSC_PIXFMT_SIMPLE_YCBCR422);
- if (dscc_compute_dsc_parameters(&dsc_reg_vals->pps, &dsc_params)) {
+ calc_rc_params(&rc, &dsc_reg_vals->pps);
+
+ if (dsc_cfg->dc_dsc_cfg.rc_params_ovrd)
+ dsc_override_rc_params(&rc, dsc_cfg->dc_dsc_cfg.rc_params_ovrd);
+
+ if (dscc_compute_dsc_parameters(&dsc_reg_vals->pps, &rc, &dsc_params)) {
dm_output_to_console("%s: DSC config failed\n", __func__);
return false;
}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
index 6291a241158a..b83873a3a534 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
@@ -46,16 +46,15 @@
#include "dchubbub.h"
#include "reg_helper.h"
#include "dcn10/dcn10_cm_common.h"
-#include "dc_link_dp.h"
#include "vm_helper.h"
#include "dccg.h"
#include "dc_dmub_srv.h"
#include "dce/dmub_hw_lock_mgr.h"
#include "hw_sequencer.h"
-#include "inc/link_dpcd.h"
#include "dpcd_defs.h"
#include "inc/link_enc_cfg.h"
#include "link_hwss.h"
+#include "link.h"
#define DC_LOGGER_INIT(logger)
@@ -582,6 +581,9 @@ void dcn20_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx)
if (pipe_ctx->stream_res.gsl_group != 0)
dcn20_setup_gsl_group_as_lock(dc, pipe_ctx, false);
+ if (hubp->funcs->hubp_update_mall_sel)
+ hubp->funcs->hubp_update_mall_sel(hubp, 0, false);
+
dc->hwss.set_flip_control_gsl(pipe_ctx, false);
hubp->funcs->hubp_clk_cntl(hubp, false);
@@ -605,6 +607,9 @@ void dcn20_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx)
void dcn20_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx)
{
+ bool is_phantom = pipe_ctx->plane_state && pipe_ctx->plane_state->is_phantom;
+ struct timing_generator *tg = is_phantom ? pipe_ctx->stream_res.tg : NULL;
+
DC_LOGGER_INIT(dc->ctx->logger);
if (!pipe_ctx->plane_res.hubp || pipe_ctx->plane_res.hubp->power_gated)
@@ -612,6 +617,12 @@ void dcn20_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx)
dcn20_plane_atomic_disable(dc, pipe_ctx);
+ /* Turn back off the phantom OTG after the phantom plane is fully disabled
+ */
+ if (is_phantom)
+ if (tg && tg->funcs->disable_phantom_crtc)
+ tg->funcs->disable_phantom_crtc(tg);
+
DC_LOG_DC("Power down front end %d\n",
pipe_ctx->pipe_idx);
}
@@ -700,7 +711,7 @@ enum dc_status dcn20_enable_stream_timing(
if (false == pipe_ctx->clock_source->funcs->program_pix_clk(
pipe_ctx->clock_source,
&pipe_ctx->stream_res.pix_clk_params,
- dp_get_link_encoding_format(&pipe_ctx->link_config.dp_link_settings),
+ link_dp_get_encoding_format(&pipe_ctx->link_config.dp_link_settings),
&pipe_ctx->pll_settings)) {
BREAK_TO_DEBUGGER();
return DC_ERROR_UNEXPECTED;
@@ -1766,6 +1777,15 @@ static void dcn20_program_pipe(
&pipe_ctx->stream->bit_depth_params,
&pipe_ctx->stream->clamping);
}
+
+ /* Set ABM pipe after other pipe configurations done */
+ if (pipe_ctx->plane_state->visible) {
+ if (pipe_ctx->stream_res.abm) {
+ dc->hwss.set_pipe(pipe_ctx);
+ pipe_ctx->stream_res.abm->funcs->set_abm_level(pipe_ctx->stream_res.abm,
+ pipe_ctx->stream->abm_level);
+ }
+ }
}
void dcn20_program_front_end_for_ctx(
@@ -1803,6 +1823,20 @@ void dcn20_program_front_end_for_ctx(
dcn20_detect_pipe_changes(&dc->current_state->res_ctx.pipe_ctx[i],
&context->res_ctx.pipe_ctx[i]);
+ /* When disabling phantom pipes, turn on phantom OTG first (so we can get double
+ * buffer updates properly)
+ */
+ for (i = 0; i < dc->res_pool->pipe_count; i++) {
+ struct dc_stream_state *stream = dc->current_state->res_ctx.pipe_ctx[i].stream;
+
+ if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable && stream &&
+ dc->current_state->res_ctx.pipe_ctx[i].stream->mall_stream_config.type == SUBVP_PHANTOM) {
+ struct timing_generator *tg = dc->current_state->res_ctx.pipe_ctx[i].stream_res.tg;
+
+ if (tg->funcs->enable_crtc)
+ tg->funcs->enable_crtc(tg);
+ }
+ }
/* OTG blank before disabling all front ends */
for (i = 0; i < dc->res_pool->pipe_count; i++)
if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable
@@ -1999,8 +2033,11 @@ void dcn20_prepare_bandwidth(
}
}
- /* program dchubbub watermarks */
- dc->wm_optimized_required = hubbub->funcs->program_watermarks(hubbub,
+ /* program dchubbub watermarks:
+ * For assigning wm_optimized_required, use |= operator since we don't want
+ * to clear the value if the optimize has not happened yet
+ */
+ dc->wm_optimized_required |= hubbub->funcs->program_watermarks(hubbub,
&context->bw_ctx.bw.dcn.watermarks,
dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000,
false);
@@ -2359,7 +2396,7 @@ void dcn20_unblank_stream(struct pipe_ctx *pipe_ctx,
params.link_settings.link_rate = link_settings->link_rate;
- if (is_dp_128b_132b_signal(pipe_ctx)) {
+ if (link_is_dp_128b_132b_signal(pipe_ctx)) {
/* TODO - DP2.0 HW: Set ODM mode in dp hpo encoder here */
pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_unblank(
pipe_ctx->stream_res.hpo_dp_stream_enc,
@@ -2412,7 +2449,7 @@ static void dcn20_reset_back_end_for_pipe(
* VBIOS lit up eDP, so check link status too.
*/
if (!pipe_ctx->stream->dpms_off || link->link_status.link_active)
- core_link_disable_stream(pipe_ctx);
+ link_set_dpms_off(pipe_ctx);
else if (pipe_ctx->stream_res.audio)
dc->hwss.disable_audio_stream(pipe_ctx);
@@ -2432,7 +2469,7 @@ static void dcn20_reset_back_end_for_pipe(
}
}
else if (pipe_ctx->stream_res.dsc) {
- dp_set_dsc_enable(pipe_ctx, false);
+ link_set_dsc_enable(pipe_ctx, false);
}
/* by upper caller loop, parent pipe: pipe0, will be reset last.
@@ -2615,6 +2652,37 @@ void dcn20_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx)
hubp->mpcc_id = mpcc_id;
}
+static enum phyd32clk_clock_source get_phyd32clk_src(struct dc_link *link)
+{
+ switch (link->link_enc->transmitter) {
+ case TRANSMITTER_UNIPHY_A:
+ return PHYD32CLKA;
+ case TRANSMITTER_UNIPHY_B:
+ return PHYD32CLKB;
+ case TRANSMITTER_UNIPHY_C:
+ return PHYD32CLKC;
+ case TRANSMITTER_UNIPHY_D:
+ return PHYD32CLKD;
+ case TRANSMITTER_UNIPHY_E:
+ return PHYD32CLKE;
+ default:
+ return PHYD32CLKA;
+ }
+}
+
+static int get_odm_segment_count(struct pipe_ctx *pipe_ctx)
+{
+ struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe;
+ int count = 1;
+
+ while (odm_pipe != NULL) {
+ count++;
+ odm_pipe = odm_pipe->next_odm_pipe;
+ }
+
+ return count;
+}
+
void dcn20_enable_stream(struct pipe_ctx *pipe_ctx)
{
enum dc_lane_count lane_count =
@@ -2628,12 +2696,43 @@ void dcn20_enable_stream(struct pipe_ctx *pipe_ctx)
struct timing_generator *tg = pipe_ctx->stream_res.tg;
const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
struct dc *dc = pipe_ctx->stream->ctx->dc;
+ struct dtbclk_dto_params dto_params = {0};
+ struct dccg *dccg = dc->res_pool->dccg;
+ enum phyd32clk_clock_source phyd32clk;
+ int dp_hpo_inst;
+ struct dce_hwseq *hws = dc->hwseq;
+ unsigned int k1_div = PIXEL_RATE_DIV_NA;
+ unsigned int k2_div = PIXEL_RATE_DIV_NA;
- if (is_dp_128b_132b_signal(pipe_ctx)) {
+ if (link_is_dp_128b_132b_signal(pipe_ctx)) {
if (dc->hwseq->funcs.setup_hpo_hw_control)
dc->hwseq->funcs.setup_hpo_hw_control(dc->hwseq, true);
}
+ if (link_is_dp_128b_132b_signal(pipe_ctx)) {
+ dp_hpo_inst = pipe_ctx->stream_res.hpo_dp_stream_enc->inst;
+ dccg->funcs->set_dpstreamclk(dccg, DTBCLK0, tg->inst, dp_hpo_inst);
+
+ phyd32clk = get_phyd32clk_src(link);
+ dccg->funcs->enable_symclk32_se(dccg, dp_hpo_inst, phyd32clk);
+
+ dto_params.otg_inst = tg->inst;
+ dto_params.pixclk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10;
+ dto_params.num_odm_segments = get_odm_segment_count(pipe_ctx);
+ dto_params.timing = &pipe_ctx->stream->timing;
+ dto_params.ref_dtbclk_khz = dc->clk_mgr->funcs->get_dtb_ref_clk_frequency(dc->clk_mgr);
+ dccg->funcs->set_dtbclk_dto(dccg, &dto_params);
+ }
+
+ if (hws->funcs.calculate_dccg_k1_k2_values && dc->res_pool->dccg->funcs->set_pixel_rate_div) {
+ hws->funcs.calculate_dccg_k1_k2_values(pipe_ctx, &k1_div, &k2_div);
+
+ dc->res_pool->dccg->funcs->set_pixel_rate_div(
+ dc->res_pool->dccg,
+ pipe_ctx->stream_res.tg->inst,
+ k1_div, k2_div);
+ }
+
link_hwss->setup_stream_encoder(pipe_ctx);
if (pipe_ctx->plane_state && pipe_ctx->plane_state->flip_immediate != 1) {
@@ -2644,7 +2743,7 @@ void dcn20_enable_stream(struct pipe_ctx *pipe_ctx)
dc->hwss.update_info_frame(pipe_ctx);
if (dc_is_dp_signal(pipe_ctx->stream->signal))
- dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_UPDATE_INFO_FRAME);
+ link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_UPDATE_INFO_FRAME);
/* enable early control to avoid corruption on DP monitor*/
active_total_with_borders =
diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.c
index 2f9bfaeaba8d..51a57dae1811 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.c
@@ -29,7 +29,6 @@
#include "link_encoder.h"
#include "dcn20_link_encoder.h"
#include "stream_encoder.h"
-#include "i2caux_interface.h"
#include "dc_bios_types.h"
#include "gpio_service_interface.h"
diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
index 8a0dd0d7134b..3af24ef9cb2d 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
@@ -62,7 +62,6 @@
#include "dml/display_mode_vba.h"
#include "dcn20_dccg.h"
#include "dcn20_vmid.h"
-#include "dc_link_ddc.h"
#include "dce/dce_panel_cntl.h"
#include "navi10_ip_offset.h"
@@ -90,6 +89,7 @@
#include "amdgpu_socbb.h"
+#include "link.h"
#define DC_LOGGER_INIT(logger)
#ifndef mmDP0_DP_DPHY_INTERNAL_CTRL
@@ -1214,7 +1214,7 @@ static void dcn20_resource_destruct(struct dcn20_resource_pool *pool)
dcn20_pp_smu_destroy(&pool->base.pp_smu);
if (pool->base.oem_device != NULL)
- dal_ddc_service_destroy(&pool->base.oem_device);
+ link_destroy_ddc_service(&pool->base.oem_device);
}
struct hubp *dcn20_hubp_create(
@@ -1389,6 +1389,9 @@ enum dc_status dcn20_add_dsc_to_stream_resource(struct dc *dc,
for (i = 0; i < dc->res_pool->pipe_count; i++) {
struct pipe_ctx *pipe_ctx = &dc_ctx->res_ctx.pipe_ctx[i];
+ if (pipe_ctx->top_pipe)
+ continue;
+
if (pipe_ctx->stream != dc_stream)
continue;
@@ -2222,14 +2225,10 @@ enum dc_status dcn20_patch_unknown_plane_state(struct dc_plane_state *plane_stat
enum surface_pixel_format surf_pix_format = plane_state->format;
unsigned int bpp = resource_pixel_format_to_bpp(surf_pix_format);
- enum swizzle_mode_values swizzle = DC_SW_LINEAR;
-
+ plane_state->tiling_info.gfx9.swizzle = DC_SW_64KB_S;
if (bpp == 64)
- swizzle = DC_SW_64KB_D;
- else
- swizzle = DC_SW_64KB_S;
+ plane_state->tiling_info.gfx9.swizzle = DC_SW_64KB_D;
- plane_state->tiling_info.gfx9.swizzle = swizzle;
return DC_OK;
}
@@ -2766,7 +2765,7 @@ static bool dcn20_resource_construct(
ddc_init_data.id.id = dc->ctx->dc_bios->fw_info.oem_i2c_obj_id;
ddc_init_data.id.enum_id = 0;
ddc_init_data.id.type = OBJECT_TYPE_GENERIC;
- pool->base.oem_device = dal_ddc_service_create(&ddc_init_data);
+ pool->base.oem_device = link_create_ddc_service(&ddc_init_data);
} else {
pool->base.oem_device = NULL;
}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c
index b40489e678f9..42865d6c0cdd 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c
@@ -29,7 +29,7 @@
#include "dcn20_stream_encoder.h"
#include "reg_helper.h"
#include "hw_shared.h"
-#include "inc/link_dpcd.h"
+#include "link.h"
#include "dpcd_defs.h"
#define DC_LOGGER \
@@ -423,6 +423,22 @@ void enc2_set_dynamic_metadata(struct stream_encoder *enc,
}
}
+static void enc2_stream_encoder_update_dp_info_packets_sdp_line_num(
+ struct stream_encoder *enc,
+ struct encoder_info_frame *info_frame)
+{
+ struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
+
+ if (info_frame->adaptive_sync.valid == true &&
+ info_frame->sdp_line_num.adaptive_sync_line_num_valid == true) {
+ //00: REFER_TO_DP_SOF, 01: REFER_TO_OTG_SOF
+ REG_UPDATE(DP_SEC_CNTL1, DP_SEC_GSP5_LINE_REFERENCE, 1);
+
+ REG_UPDATE(DP_SEC_CNTL5, DP_SEC_GSP5_LINE_NUM,
+ info_frame->sdp_line_num.adaptive_sync_line_num);
+ }
+}
+
static void enc2_stream_encoder_update_dp_info_packets(
struct stream_encoder *enc,
const struct encoder_info_frame *info_frame)
@@ -530,7 +546,7 @@ void enc2_stream_encoder_dp_unblank(
REG_UPDATE(DP_VID_STREAM_CNTL, DP_VID_STREAM_ENABLE, true);
- dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_DP_VID_STREAM);
+ link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_DP_VID_STREAM);
}
static void enc2_dp_set_odm_combine(
@@ -587,6 +603,8 @@ static const struct stream_encoder_funcs dcn20_str_enc_funcs = {
enc2_stream_encoder_update_hdmi_info_packets,
.stop_hdmi_info_packets =
enc2_stream_encoder_stop_hdmi_info_packets,
+ .update_dp_info_packets_sdp_line_num =
+ enc2_stream_encoder_update_dp_info_packets_sdp_line_num,
.update_dp_info_packets =
enc2_stream_encoder_update_dp_info_packets,
.send_immediate_sdp_message =
diff --git a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_link_encoder.c
index 7f9ec59ef443..8d31fa131cd6 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_link_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_link_encoder.c
@@ -29,7 +29,6 @@
#include "link_encoder.h"
#include "dcn201_link_encoder.h"
#include "stream_encoder.h"
-#include "i2caux_interface.h"
#include "dc_bios_types.h"
#include "gpio_service_interface.h"
diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hwseq.c
index 69cc192a7e71..15475c7e2cf9 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hwseq.c
@@ -35,7 +35,7 @@
#include "hw/clk_mgr.h"
#include "dc_dmub_srv.h"
#include "abm.h"
-
+#include "link.h"
#define DC_LOGGER_INIT(logger)
@@ -132,8 +132,8 @@ void dcn21_PLAT_58856_wa(struct dc_state *context, struct pipe_ctx *pipe_ctx)
return;
pipe_ctx->stream->dpms_off = false;
- core_link_enable_stream(context, pipe_ctx);
- core_link_disable_stream(pipe_ctx);
+ link_set_dpms_on(context, pipe_ctx);
+ link_set_dpms_off(pipe_ctx);
pipe_ctx->stream->dpms_off = true;
}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_link_encoder.c
index 0a1ba6e7081c..eb9abb9f9698 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_link_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_link_encoder.c
@@ -31,7 +31,6 @@
#include "dcn21_link_encoder.h"
#include "stream_encoder.h"
-#include "i2caux_interface.h"
#include "dc_bios_types.h"
#include "gpio_service_interface.h"
diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c
index fbcf0afeae0d..8f9244fe5c86 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c
@@ -1393,15 +1393,13 @@ static uint32_t read_pipe_fuses(struct dc_context *ctx)
static enum dc_status dcn21_patch_unknown_plane_state(struct dc_plane_state *plane_state)
{
- enum dc_status result = DC_OK;
-
if (plane_state->ctx->dc->debug.disable_dcc == DCC_ENABLE) {
plane_state->dcc.enable = 1;
/* align to our worst case block width */
plane_state->dcc.meta_pitch = ((plane_state->src_rect.width + 1023) / 1024) * 1024;
}
- result = dcn20_patch_unknown_plane_state(plane_state);
- return result;
+
+ return dcn20_patch_unknown_plane_state(plane_state);
}
static const struct resource_funcs dcn21_res_pool_funcs = {
diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_link_encoder.c
index 6f3c2fb60790..1fb8fd7afc95 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_link_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_link_encoder.c
@@ -29,7 +29,6 @@
#include "link_encoder.h"
#include "dcn30_dio_link_encoder.h"
#include "stream_encoder.h"
-#include "i2caux_interface.h"
#include "dc_bios_types.h"
/* #include "dcn3ag/dcn3ag_phy_fw.h" */
diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_stream_encoder.c
index 17df53793c92..5f9079d3943a 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_stream_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_stream_encoder.c
@@ -404,6 +404,22 @@ static void enc3_read_state(struct stream_encoder *enc, struct enc_state *s)
}
}
+void enc3_stream_encoder_update_dp_info_packets_sdp_line_num(
+ struct stream_encoder *enc,
+ struct encoder_info_frame *info_frame)
+{
+ struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
+
+ if (info_frame->adaptive_sync.valid == true &&
+ info_frame->sdp_line_num.adaptive_sync_line_num_valid == true) {
+ //00: REFER_TO_DP_SOF, 01: REFER_TO_OTG_SOF
+ REG_UPDATE(DP_SEC_CNTL1, DP_SEC_GSP5_LINE_REFERENCE, 1);
+
+ REG_UPDATE(DP_SEC_CNTL5, DP_SEC_GSP5_LINE_NUM,
+ info_frame->sdp_line_num.adaptive_sync_line_num);
+ }
+}
+
void enc3_stream_encoder_update_dp_info_packets(
struct stream_encoder *enc,
const struct encoder_info_frame *info_frame)
@@ -452,12 +468,20 @@ void enc3_stream_encoder_update_dp_info_packets(
* use other packetIndex (such as 5,6) for other info packet
*/
+ if (info_frame->adaptive_sync.valid)
+ enc->vpg->funcs->update_generic_info_packet(
+ enc->vpg,
+ 5, /* packetIndex */
+ &info_frame->adaptive_sync,
+ true);
+
/* enable/disable transmission of packet(s).
* If enabled, packet transmission begins on the next frame
*/
REG_UPDATE(DP_SEC_CNTL, DP_SEC_GSP0_ENABLE, info_frame->vsc.valid);
REG_UPDATE(DP_SEC_CNTL, DP_SEC_GSP2_ENABLE, info_frame->spd.valid);
REG_UPDATE(DP_SEC_CNTL, DP_SEC_GSP3_ENABLE, info_frame->hdrsmd.valid);
+ REG_UPDATE(DP_SEC_CNTL, DP_SEC_GSP5_ENABLE, info_frame->adaptive_sync.valid);
/* This bit is the master enable bit.
* When enabling secondary stream engine,
@@ -803,6 +827,8 @@ static const struct stream_encoder_funcs dcn30_str_enc_funcs = {
enc3_stream_encoder_update_hdmi_info_packets,
.stop_hdmi_info_packets =
enc3_stream_encoder_stop_hdmi_info_packets,
+ .update_dp_info_packets_sdp_line_num =
+ enc3_stream_encoder_update_dp_info_packets_sdp_line_num,
.update_dp_info_packets =
enc3_stream_encoder_update_dp_info_packets,
.stop_dp_info_packets =
diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_stream_encoder.h b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_stream_encoder.h
index 54ee230e7f98..06310973ded2 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_stream_encoder.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_stream_encoder.h
@@ -292,6 +292,10 @@ void enc3_stream_encoder_update_hdmi_info_packets(
void enc3_stream_encoder_stop_hdmi_info_packets(
struct stream_encoder *enc);
+void enc3_stream_encoder_update_dp_info_packets_sdp_line_num(
+ struct stream_encoder *enc,
+ struct encoder_info_frame *info_frame);
+
void enc3_stream_encoder_update_dp_info_packets(
struct stream_encoder *enc,
const struct encoder_info_frame *info_frame);
diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c
index 8c5045711264..3b4d4d68359b 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c
@@ -50,8 +50,7 @@
#include "dpcd_defs.h"
#include "../dcn20/dcn20_hwseq.h"
#include "dcn30_resource.h"
-#include "inc/dc_link_dp.h"
-#include "inc/link_dpcd.h"
+#include "link.h"
@@ -91,8 +90,8 @@ bool dcn30_set_blend_lut(
return result;
}
-static bool dcn30_set_mpc_shaper_3dlut(
- struct pipe_ctx *pipe_ctx, const struct dc_stream_state *stream)
+static bool dcn30_set_mpc_shaper_3dlut(struct pipe_ctx *pipe_ctx,
+ const struct dc_stream_state *stream)
{
struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
int mpcc_id = pipe_ctx->plane_res.hubp->inst;
@@ -104,19 +103,18 @@ static bool dcn30_set_mpc_shaper_3dlut(
const struct pwl_params *shaper_lut = NULL;
//get the shaper lut params
if (stream->func_shaper) {
- if (stream->func_shaper->type == TF_TYPE_HWPWL)
+ if (stream->func_shaper->type == TF_TYPE_HWPWL) {
shaper_lut = &stream->func_shaper->pwl;
- else if (stream->func_shaper->type == TF_TYPE_DISTRIBUTED_POINTS) {
- cm_helper_translate_curve_to_hw_format(
- stream->func_shaper,
- &dpp_base->shaper_params, true);
+ } else if (stream->func_shaper->type == TF_TYPE_DISTRIBUTED_POINTS) {
+ cm_helper_translate_curve_to_hw_format(stream->func_shaper,
+ &dpp_base->shaper_params, true);
shaper_lut = &dpp_base->shaper_params;
}
}
if (stream->lut3d_func &&
- stream->lut3d_func->state.bits.initialized == 1 &&
- stream->lut3d_func->state.bits.rmu_idx_valid == 1) {
+ stream->lut3d_func->state.bits.initialized == 1 &&
+ stream->lut3d_func->state.bits.rmu_idx_valid == 1) {
if (stream->lut3d_func->state.bits.rmu_mux_num == 0)
mpcc_id_projected = stream->lut3d_func->state.bits.mpc_rmu0_mux;
else if (stream->lut3d_func->state.bits.rmu_mux_num == 1)
@@ -125,20 +123,22 @@ static bool dcn30_set_mpc_shaper_3dlut(
mpcc_id_projected = stream->lut3d_func->state.bits.mpc_rmu2_mux;
if (mpcc_id_projected != mpcc_id)
BREAK_TO_DEBUGGER();
- /*find the reason why logical layer assigned a differant mpcc_id into acquire_post_bldn_3dlut*/
+ /* find the reason why logical layer assigned a different
+ * mpcc_id into acquire_post_bldn_3dlut
+ */
acquired_rmu = mpc->funcs->acquire_rmu(mpc, mpcc_id,
- stream->lut3d_func->state.bits.rmu_mux_num);
+ stream->lut3d_func->state.bits.rmu_mux_num);
if (acquired_rmu != stream->lut3d_func->state.bits.rmu_mux_num)
BREAK_TO_DEBUGGER();
- result = mpc->funcs->program_3dlut(mpc,
- &stream->lut3d_func->lut_3d,
- stream->lut3d_func->state.bits.rmu_mux_num);
+
+ result = mpc->funcs->program_3dlut(mpc, &stream->lut3d_func->lut_3d,
+ stream->lut3d_func->state.bits.rmu_mux_num);
result = mpc->funcs->program_shaper(mpc, shaper_lut,
- stream->lut3d_func->state.bits.rmu_mux_num);
- } else
- /*loop through the available mux and release the requested mpcc_id*/
+ stream->lut3d_func->state.bits.rmu_mux_num);
+ } else {
+ // loop through the available mux and release the requested mpcc_id
mpc->funcs->release_rmu(mpc, mpcc_id);
-
+ }
return result;
}
@@ -540,7 +540,7 @@ void dcn30_init_hw(struct dc *dc)
hws->funcs.dsc_pg_control(hws, res_pool->dscs[i]->inst, false);
/* we want to turn off all dp displays before doing detection */
- dc_link_blank_all_dp_displays(dc);
+ link_blank_all_dp_displays(dc);
if (hws->funcs.enable_power_gating_plane)
hws->funcs.enable_power_gating_plane(dc->hwseq, true);
@@ -675,10 +675,16 @@ void dcn30_update_info_frame(struct pipe_ctx *pipe_ctx)
pipe_ctx->stream_res.stream_enc->funcs->update_hdmi_info_packets(
pipe_ctx->stream_res.stream_enc,
&pipe_ctx->stream_res.encoder_info_frame);
- else
+ else {
+ if (pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets_sdp_line_num)
+ pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets_sdp_line_num(
+ pipe_ctx->stream_res.stream_enc,
+ &pipe_ctx->stream_res.encoder_info_frame);
+
pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets(
pipe_ctx->stream_res.stream_enc,
&pipe_ctx->stream_res.encoder_info_frame);
+ }
}
void dcn30_program_dmdata_engine(struct pipe_ctx *pipe_ctx)
diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c
index 867d60151aeb..08b92715e2e6 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c
@@ -291,6 +291,14 @@ static void optc3_set_timing_double_buffer(struct timing_generator *optc, bool e
OTG_DRR_TIMING_DBUF_UPDATE_MODE, mode);
}
+void optc3_wait_drr_doublebuffer_pending_clear(struct timing_generator *optc)
+{
+ struct optc *optc1 = DCN10TG_FROM_TG(optc);
+
+ REG_WAIT(OTG_DOUBLE_BUFFER_CONTROL, OTG_DRR_TIMING_DBUF_UPDATE_PENDING, 0, 2, 100000); /* 1 vupdate at 5hz */
+
+}
+
void optc3_set_vtotal_min_max(struct timing_generator *optc, int vtotal_min, int vtotal_max)
{
optc1_set_vtotal_min_max(optc, vtotal_min, vtotal_max);
@@ -360,6 +368,7 @@ static struct timing_generator_funcs dcn30_tg_funcs = {
.program_manual_trigger = optc2_program_manual_trigger,
.setup_manual_trigger = optc2_setup_manual_trigger,
.get_hw_timing = optc1_get_hw_timing,
+ .wait_drr_doublebuffer_pending_clear = optc3_wait_drr_doublebuffer_pending_clear,
};
void dcn30_timing_generator_init(struct optc *optc1)
diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.h b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.h
index dd45a5499b07..fb06dc9a4893 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.h
@@ -279,6 +279,7 @@
SF(OTG0_OTG_DRR_TRIGGER_WINDOW, OTG_DRR_TRIGGER_WINDOW_END_X, mask_sh),\
SF(OTG0_OTG_DRR_V_TOTAL_CHANGE, OTG_DRR_V_TOTAL_CHANGE_LIMIT, mask_sh),\
SF(OTG0_OTG_H_TIMING_CNTL, OTG_H_TIMING_DIV_BY2, mask_sh),\
+ SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_DRR_TIMING_DBUF_UPDATE_PENDING, mask_sh),\
SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_DRR_TIMING_DBUF_UPDATE_MODE, mask_sh),\
SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_BLANK_DATA_DOUBLE_BUFFER_EN, mask_sh)
@@ -317,6 +318,7 @@
SF(OTG0_OTG_DRR_TRIGGER_WINDOW, OTG_DRR_TRIGGER_WINDOW_END_X, mask_sh),\
SF(OTG0_OTG_DRR_V_TOTAL_CHANGE, OTG_DRR_V_TOTAL_CHANGE_LIMIT, mask_sh),\
SF(OTG0_OTG_H_TIMING_CNTL, OTG_H_TIMING_DIV_MODE, mask_sh),\
+ SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_DRR_TIMING_DBUF_UPDATE_PENDING, mask_sh),\
SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_DRR_TIMING_DBUF_UPDATE_MODE, mask_sh)
void dcn30_timing_generator_init(struct optc *optc1);
diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c
index c18c52a60100..b5b5320c7bef 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c
@@ -60,7 +60,7 @@
#include "dml/display_mode_vba.h"
#include "dcn30/dcn30_dccg.h"
#include "dcn10/dcn10_resource.h"
-#include "dc_link_ddc.h"
+#include "link.h"
#include "dce/dce_panel_cntl.h"
#include "dcn30/dcn30_dwb.h"
@@ -1208,7 +1208,7 @@ static void dcn30_resource_destruct(struct dcn30_resource_pool *pool)
dcn_dccg_destroy(&pool->base.dccg);
if (pool->base.oem_device != NULL)
- dal_ddc_service_destroy(&pool->base.oem_device);
+ link_destroy_ddc_service(&pool->base.oem_device);
}
static struct hubp *dcn30_hubp_create(
@@ -1477,8 +1477,8 @@ bool dcn30_acquire_post_bldn_3dlut(
state->bits.mpc_rmu2_mux = mpcc_id;
ret = true;
break;
- }
}
+ }
return ret;
}
@@ -1648,7 +1648,8 @@ noinline bool dcn30_internal_validate_bw(
display_e2e_pipe_params_st *pipes,
int *pipe_cnt_out,
int *vlevel_out,
- bool fast_validate)
+ bool fast_validate,
+ bool allow_self_refresh_only)
{
bool out = false;
bool repopulate_pipes = false;
@@ -1675,7 +1676,7 @@ noinline bool dcn30_internal_validate_bw(
dml_log_pipe_params(&context->bw_ctx.dml, pipes, pipe_cnt);
- if (!fast_validate) {
+ if (!fast_validate || !allow_self_refresh_only) {
/*
* DML favors voltage over p-state, but we're more interested in
* supporting p-state over voltage. We can't support p-state in
@@ -1688,11 +1689,12 @@ noinline bool dcn30_internal_validate_bw(
if (vlevel < context->bw_ctx.dml.soc.num_states)
vlevel = dcn20_validate_apply_pipe_split_flags(dc, context, vlevel, split, merge);
}
- if (fast_validate || vlevel == context->bw_ctx.dml.soc.num_states ||
- vba->DRAMClockChangeSupport[vlevel][vba->maxMpcComb] == dm_dram_clock_change_unsupported) {
+ if (allow_self_refresh_only &&
+ (fast_validate || vlevel == context->bw_ctx.dml.soc.num_states ||
+ vba->DRAMClockChangeSupport[vlevel][vba->maxMpcComb] == dm_dram_clock_change_unsupported)) {
/*
- * If mode is unsupported or there's still no p-state support then
- * fall back to favoring voltage.
+ * If mode is unsupported or there's still no p-state support
+ * then fall back to favoring voltage.
*
* We don't actually support prefetch mode 2, so require that we
* at least support prefetch mode 1.
@@ -2063,7 +2065,7 @@ bool dcn30_validate_bandwidth(struct dc *dc,
BW_VAL_TRACE_COUNT();
DC_FP_START();
- out = dcn30_internal_validate_bw(dc, context, pipes, &pipe_cnt, &vlevel, fast_validate);
+ out = dcn30_internal_validate_bw(dc, context, pipes, &pipe_cnt, &vlevel, fast_validate, true);
DC_FP_END();
if (pipe_cnt == 0)
@@ -2590,7 +2592,7 @@ static bool dcn30_resource_construct(
ddc_init_data.id.id = dc->ctx->dc_bios->fw_info.oem_i2c_obj_id;
ddc_init_data.id.enum_id = 0;
ddc_init_data.id.type = OBJECT_TYPE_GENERIC;
- pool->base.oem_device = dal_ddc_service_create(&ddc_init_data);
+ pool->base.oem_device = link_create_ddc_service(&ddc_init_data);
} else {
pool->base.oem_device = NULL;
}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.h b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.h
index 7d063c7d6a4b..8e6b8b7368fd 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.h
@@ -64,7 +64,8 @@ bool dcn30_internal_validate_bw(
display_e2e_pipe_params_st *pipes,
int *pipe_cnt_out,
int *vlevel_out,
- bool fast_validate);
+ bool fast_validate,
+ bool allow_self_refresh_only);
void dcn30_calculate_wm_and_dlg(
struct dc *dc, struct dc_state *context,
display_e2e_pipe_params_st *pipes,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_dio_link_encoder.c
index c9fbaed23965..1b39a6e8a1ac 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_dio_link_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_dio_link_encoder.c
@@ -29,7 +29,6 @@
#include "link_encoder.h"
#include "dcn301_dio_link_encoder.h"
#include "stream_encoder.h"
-#include "i2caux_interface.h"
#include "dc_bios_types.h"
#include "gpio_service_interface.h"
diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c
index 8cf10351f271..ee62ae3eb98f 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c
@@ -1414,7 +1414,8 @@ static struct resource_funcs dcn301_res_pool_funcs = {
.find_first_free_match_stream_enc_for_link = dcn10_find_first_free_match_stream_enc_for_link,
.acquire_post_bldn_3dlut = dcn30_acquire_post_bldn_3dlut,
.release_post_bldn_3dlut = dcn30_release_post_bldn_3dlut,
- .update_bw_bounding_box = dcn301_update_bw_bounding_box
+ .update_bw_bounding_box = dcn301_update_bw_bounding_box,
+ .patch_unknown_plane_state = dcn20_patch_unknown_plane_state
};
static bool dcn301_resource_construct(
diff --git a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c b/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c
index 47cffd0e6830..03ddf4f5f065 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c
@@ -47,6 +47,7 @@
#include "dcn10/dcn10_resource.h"
+#include "link.h"
#include "dce/dce_abm.h"
#include "dce/dce_audio.h"
#include "dce/dce_aux.h"
@@ -1125,6 +1126,9 @@ static void dcn302_resource_destruct(struct resource_pool *pool)
if (pool->dccg != NULL)
dcn_dccg_destroy(&pool->dccg);
+
+ if (pool->oem_device != NULL)
+ link_destroy_ddc_service(&pool->oem_device);
}
static void dcn302_destroy_resource_pool(struct resource_pool **pool)
@@ -1216,6 +1220,7 @@ static bool dcn302_resource_construct(
int i;
struct dc_context *ctx = dc->ctx;
struct irq_service_init_data init_data;
+ struct ddc_service_init_data ddc_init_data = {0};
ctx->dc_bios->regs = &bios_regs;
@@ -1497,6 +1502,17 @@ static bool dcn302_resource_construct(
dc->cap_funcs = cap_funcs;
+ if (dc->ctx->dc_bios->fw_info.oem_i2c_present) {
+ ddc_init_data.ctx = dc->ctx;
+ ddc_init_data.link = NULL;
+ ddc_init_data.id.id = dc->ctx->dc_bios->fw_info.oem_i2c_obj_id;
+ ddc_init_data.id.enum_id = 0;
+ ddc_init_data.id.type = OBJECT_TYPE_GENERIC;
+ pool->oem_device = link_create_ddc_service(&ddc_init_data);
+ } else {
+ pool->oem_device = NULL;
+ }
+
return true;
create_fail:
diff --git a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c
index c14d35894b2e..31e212064168 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c
@@ -29,7 +29,7 @@
#include "dcn10/dcn10_resource.h"
-#include "dc_link_ddc.h"
+#include "link.h"
#include "dce/dce_abm.h"
#include "dce/dce_audio.h"
@@ -1054,7 +1054,7 @@ static void dcn303_resource_destruct(struct resource_pool *pool)
dcn_dccg_destroy(&pool->dccg);
if (pool->oem_device != NULL)
- dal_ddc_service_destroy(&pool->oem_device);
+ link_destroy_ddc_service(&pool->oem_device);
}
static void dcn303_destroy_resource_pool(struct resource_pool **pool)
@@ -1421,7 +1421,7 @@ static bool dcn303_resource_construct(
ddc_init_data.id.id = dc->ctx->dc_bios->fw_info.oem_i2c_obj_id;
ddc_init_data.id.enum_id = 0;
ddc_init_data.id.type = OBJECT_TYPE_GENERIC;
- pool->oem_device = dal_ddc_service_create(&ddc_init_data);
+ pool->oem_device = link_create_ddc_service(&ddc_init_data);
} else {
pool->oem_device = NULL;
}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c
index ab70ebd8f223..275e78c06dee 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c
@@ -30,7 +30,6 @@
#include "link_encoder.h"
#include "dcn31_dio_link_encoder.h"
#include "stream_encoder.h"
-#include "i2caux_interface.h"
#include "dc_bios_types.h"
#include "gpio_service_interface.h"
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_link_encoder.c
index 80dfaa4d4d81..0b317ed31f91 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_link_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_link_encoder.c
@@ -242,7 +242,10 @@ void dcn31_hpo_dp_link_enc_set_link_test_pattern(
REG_UPDATE(DP_DPHY_SYM32_CONTROL,
MODE, DP2_TEST_PATTERN);
break;
- case DP_TEST_PATTERN_SQUARE_PULSE:
+ case DP_TEST_PATTERN_SQUARE:
+ case DP_TEST_PATTERN_SQUARE_PRESHOOT_DISABLED:
+ case DP_TEST_PATTERN_SQUARE_DEEMPHASIS_DISABLED:
+ case DP_TEST_PATTERN_SQUARE_PRESHOOT_DEEMPHASIS_DISABLED:
REG_SET(DP_DPHY_SYM32_TP_SQ_PULSE, 0,
TP_SQ_PULSE_WIDTH, tp_params->custom_pattern[0]);
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.c
index 16639bd03adf..d76f55a12eb4 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.c
@@ -430,6 +430,22 @@ static void dcn31_hpo_dp_stream_enc_set_stream_attribute(
MSA_DATA_LANE_3, 0);
}
+static void dcn31_hpo_dp_stream_enc_update_dp_info_packets_sdp_line_num(
+ struct hpo_dp_stream_encoder *enc,
+ struct encoder_info_frame *info_frame)
+{
+ struct dcn31_hpo_dp_stream_encoder *enc3 = DCN3_1_HPO_DP_STREAM_ENC_FROM_HPO_STREAM_ENC(enc);
+
+ if (info_frame->adaptive_sync.valid == true &&
+ info_frame->sdp_line_num.adaptive_sync_line_num_valid == true) {
+ //00: REFER_TO_DP_SOF, 01: REFER_TO_OTG_SOF
+ REG_UPDATE(DP_SYM32_ENC_SDP_GSP_CONTROL5, GSP_SOF_REFERENCE, 1);
+
+ REG_UPDATE(DP_SYM32_ENC_SDP_GSP_CONTROL5, GSP_TRANSMISSION_LINE_NUMBER,
+ info_frame->sdp_line_num.adaptive_sync_line_num);
+ }
+}
+
static void dcn31_hpo_dp_stream_enc_update_dp_info_packets(
struct hpo_dp_stream_encoder *enc,
const struct encoder_info_frame *info_frame)
@@ -458,12 +474,20 @@ static void dcn31_hpo_dp_stream_enc_update_dp_info_packets(
&info_frame->hdrsmd,
true);
+ if (info_frame->adaptive_sync.valid)
+ enc->vpg->funcs->update_generic_info_packet(
+ enc->vpg,
+ 5, /* packetIndex */
+ &info_frame->adaptive_sync,
+ true);
+
/* enable/disable transmission of packet(s).
* If enabled, packet transmission begins on the next frame
*/
REG_UPDATE(DP_SYM32_ENC_SDP_GSP_CONTROL0, GSP_VIDEO_CONTINUOUS_TRANSMISSION_ENABLE, info_frame->vsc.valid);
REG_UPDATE(DP_SYM32_ENC_SDP_GSP_CONTROL2, GSP_VIDEO_CONTINUOUS_TRANSMISSION_ENABLE, info_frame->spd.valid);
REG_UPDATE(DP_SYM32_ENC_SDP_GSP_CONTROL3, GSP_VIDEO_CONTINUOUS_TRANSMISSION_ENABLE, info_frame->hdrsmd.valid);
+ REG_UPDATE(DP_SYM32_ENC_SDP_GSP_CONTROL5, GSP_VIDEO_CONTINUOUS_TRANSMISSION_ENABLE, info_frame->adaptive_sync.valid);
/* check if dynamic metadata packet transmission is enabled */
REG_GET(DP_SYM32_ENC_SDP_METADATA_PACKET_CONTROL,
@@ -714,6 +738,7 @@ static const struct hpo_dp_stream_encoder_funcs dcn30_str_enc_funcs = {
.dp_blank = dcn31_hpo_dp_stream_enc_dp_blank,
.disable = dcn31_hpo_dp_stream_enc_disable,
.set_stream_attribute = dcn31_hpo_dp_stream_enc_set_stream_attribute,
+ .update_dp_info_packets_sdp_line_num = dcn31_hpo_dp_stream_enc_update_dp_info_packets_sdp_line_num,
.update_dp_info_packets = dcn31_hpo_dp_stream_enc_update_dp_info_packets,
.stop_dp_info_packets = dcn31_hpo_dp_stream_enc_stop_dp_info_packets,
.dp_set_dsc_pps_info_packet = dcn31_hpo_dp_stream_enc_set_dsc_pps_info_packet,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c
index 6360dc9502e7..7e7cd5b64e6a 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c
@@ -1008,6 +1008,24 @@ static bool hubbub31_verify_allow_pstate_change_high(struct hubbub *hubbub)
return false;
}
+void hubbub31_init(struct hubbub *hubbub)
+{
+ struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
+
+ /*Enable clock gate*/
+ if (hubbub->ctx->dc->debug.disable_clock_gate) {
+ /*done in hwseq*/
+ /*REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);*/
+ REG_UPDATE_2(DCHUBBUB_CLOCK_CNTL,
+ DISPCLK_R_DCHUBBUB_GATE_DIS, 0,
+ DCFCLK_R_DCHUBBUB_GATE_DIS, 0);
+ }
+
+ /*
+ only the DCN will determine when to connect the SDP port
+ */
+ REG_UPDATE(DCHUBBUB_SDPIF_CFG0, SDPIF_PORT_CONTROL, 1);
+}
static const struct hubbub_funcs hubbub31_funcs = {
.update_dchub = hubbub2_update_dchub,
.init_dchub_sys_ctx = hubbub31_init_dchub_sys_ctx,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.h
index 70c60de448ac..89d6208287b5 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.h
@@ -42,6 +42,10 @@
SR(DCHUBBUB_COMPBUF_CTRL),\
SR(COMPBUF_RESERVED_SPACE),\
SR(DCHUBBUB_DEBUG_CTRL_0),\
+ SR(DCHUBBUB_CLOCK_CNTL),\
+ SR(DCHUBBUB_SDPIF_CFG0),\
+ SR(DCHUBBUB_SDPIF_CFG1),\
+ SR(DCHUBBUB_MEM_PWR_MODE_CTRL),\
SR(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_A),\
SR(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_A),\
SR(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_B),\
@@ -120,11 +124,17 @@
HUBBUB_SF(DCN_VM_FAULT_STATUS, DCN_VM_ERROR_VMID, mask_sh), \
HUBBUB_SF(DCN_VM_FAULT_STATUS, DCN_VM_ERROR_TABLE_LEVEL, mask_sh), \
HUBBUB_SF(DCN_VM_FAULT_STATUS, DCN_VM_ERROR_PIPE, mask_sh), \
- HUBBUB_SF(DCN_VM_FAULT_STATUS, DCN_VM_ERROR_INTERRUPT_STATUS, mask_sh)
+ HUBBUB_SF(DCN_VM_FAULT_STATUS, DCN_VM_ERROR_INTERRUPT_STATUS, mask_sh),\
+ HUBBUB_SF(DCHUBBUB_CLOCK_CNTL, DISPCLK_R_DCHUBBUB_GATE_DIS, mask_sh),\
+ HUBBUB_SF(DCHUBBUB_CLOCK_CNTL, DCFCLK_R_DCHUBBUB_GATE_DIS, mask_sh),\
+ HUBBUB_SF(DCHUBBUB_SDPIF_CFG0, SDPIF_PORT_CONTROL, mask_sh),\
+ HUBBUB_SF(DCHUBBUB_MEM_PWR_MODE_CTRL, DET_MEM_PWR_LS_MODE, mask_sh)
int hubbub31_init_dchub_sys_ctx(struct hubbub *hubbub,
struct dcn_hubbub_phys_addr_config *pa_config);
+void hubbub31_init(struct hubbub *hubbub);
+
void hubbub31_construct(struct dcn20_hubbub *hubbub3,
struct dc_context *ctx,
const struct dcn_hubbub_registers *hubbub_regs,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c
index 4226a051df41..d13e46eeee3c 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c
@@ -45,8 +45,7 @@
#include "link_hwss.h"
#include "dpcd_defs.h"
#include "dce/dmub_outbox.h"
-#include "dc_link_dp.h"
-#include "inc/link_dpcd.h"
+#include "link.h"
#include "dcn10/dcn10_hw_sequencer.h"
#include "inc/link_enc_cfg.h"
#include "dcn30/dcn30_vpg.h"
@@ -203,7 +202,7 @@ void dcn31_init_hw(struct dc *dc)
dmub_enable_outbox_notification(dc->ctx->dmub_srv);
/* we want to turn off all dp displays before doing detection */
- dc_link_blank_all_dp_displays(dc);
+ link_blank_all_dp_displays(dc);
if (hws->funcs.enable_power_gating_plane)
hws->funcs.enable_power_gating_plane(dc->hwseq, true);
@@ -231,7 +230,7 @@ void dcn31_init_hw(struct dc *dc)
}
if (num_opps > 1) {
- dc_link_blank_all_edp_displays(dc);
+ link_blank_all_edp_displays(dc);
break;
}
}
@@ -415,7 +414,17 @@ void dcn31_update_info_frame(struct pipe_ctx *pipe_ctx)
pipe_ctx->stream_res.stream_enc->funcs->update_hdmi_info_packets(
pipe_ctx->stream_res.stream_enc,
&pipe_ctx->stream_res.encoder_info_frame);
- else {
+ else if (link_is_dp_128b_132b_signal(pipe_ctx)) {
+ pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->update_dp_info_packets(
+ pipe_ctx->stream_res.hpo_dp_stream_enc,
+ &pipe_ctx->stream_res.encoder_info_frame);
+ return;
+ } else {
+ if (pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets_sdp_line_num)
+ pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets_sdp_line_num(
+ pipe_ctx->stream_res.stream_enc,
+ &pipe_ctx->stream_res.encoder_info_frame);
+
pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets(
pipe_ctx->stream_res.stream_enc,
&pipe_ctx->stream_res.encoder_info_frame);
@@ -556,7 +565,7 @@ static void dcn31_reset_back_end_for_pipe(
* VBIOS lit up eDP, so check link status too.
*/
if (!pipe_ctx->stream->dpms_off || link->link_status.link_active)
- core_link_disable_stream(pipe_ctx);
+ link_set_dpms_off(pipe_ctx);
else if (pipe_ctx->stream_res.audio)
dc->hwss.disable_audio_stream(pipe_ctx);
@@ -575,7 +584,7 @@ static void dcn31_reset_back_end_for_pipe(
}
}
} else if (pipe_ctx->stream_res.dsc) {
- dp_set_dsc_enable(pipe_ctx, false);
+ link_set_dsc_enable(pipe_ctx, false);
}
pipe_ctx->stream = NULL;
@@ -623,43 +632,3 @@ void dcn31_setup_hpo_hw_control(const struct dce_hwseq *hws, bool enable)
if (hws->ctx->dc->debug.hpo_optimization)
REG_UPDATE(HPO_TOP_HW_CONTROL, HPO_IO_EN, !!enable);
}
-void dcn31_set_drr(struct pipe_ctx **pipe_ctx,
- int num_pipes, struct dc_crtc_timing_adjust adjust)
-{
- int i = 0;
- struct drr_params params = {0};
- unsigned int event_triggers = 0x2;/*Bit[1]: OTG_TRIG_A*/
- unsigned int num_frames = 2;
- params.vertical_total_max = adjust.v_total_max;
- params.vertical_total_min = adjust.v_total_min;
- params.vertical_total_mid = adjust.v_total_mid;
- params.vertical_total_mid_frame_num = adjust.v_total_mid_frame_num;
- for (i = 0; i < num_pipes; i++) {
- if ((pipe_ctx[i]->stream_res.tg != NULL) && pipe_ctx[i]->stream_res.tg->funcs) {
- if (pipe_ctx[i]->stream_res.tg->funcs->set_drr)
- pipe_ctx[i]->stream_res.tg->funcs->set_drr(
- pipe_ctx[i]->stream_res.tg, &params);
- if (adjust.v_total_max != 0 && adjust.v_total_min != 0)
- if (pipe_ctx[i]->stream_res.tg->funcs->set_static_screen_control)
- pipe_ctx[i]->stream_res.tg->funcs->set_static_screen_control(
- pipe_ctx[i]->stream_res.tg,
- event_triggers, num_frames);
- }
- }
-}
-void dcn31_set_static_screen_control(struct pipe_ctx **pipe_ctx,
- int num_pipes, const struct dc_static_screen_params *params)
-{
- unsigned int i;
- unsigned int triggers = 0;
- if (params->triggers.surface_update)
- triggers |= 0x600;/*bit 9 and bit10 : 110 0000 0000*/
- if (params->triggers.cursor_update)
- triggers |= 0x10;/*bit4*/
- if (params->triggers.force_trigger)
- triggers |= 0x1;
- for (i = 0; i < num_pipes; i++)
- pipe_ctx[i]->stream_res.tg->funcs->
- set_static_screen_control(pipe_ctx[i]->stream_res.tg,
- triggers, params->num_frames);
-}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.h
index e7e03a8722e0..edfc01d6ad73 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.h
@@ -56,8 +56,4 @@ bool dcn31_is_abm_supported(struct dc *dc,
void dcn31_init_pipes(struct dc *dc, struct dc_state *context);
void dcn31_setup_hpo_hw_control(const struct dce_hwseq *hws, bool enable);
-void dcn31_set_static_screen_control(struct pipe_ctx **pipe_ctx,
- int num_pipes, const struct dc_static_screen_params *params);
-void dcn31_set_drr(struct pipe_ctx **pipe_ctx,
- int num_pipes, struct dc_crtc_timing_adjust adjust);
#endif /* __DC_HWSS_DCN31_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c
index 7c2da70ffe21..3a32810bbe38 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c
@@ -64,9 +64,9 @@ static const struct hw_sequencer_funcs dcn31_funcs = {
.prepare_bandwidth = dcn20_prepare_bandwidth,
.optimize_bandwidth = dcn20_optimize_bandwidth,
.update_bandwidth = dcn20_update_bandwidth,
- .set_drr = dcn31_set_drr,
+ .set_drr = dcn10_set_drr,
.get_position = dcn10_get_position,
- .set_static_screen_control = dcn31_set_static_screen_control,
+ .set_static_screen_control = dcn10_set_static_screen_control,
.setup_stereo = dcn10_setup_stereo,
.set_avmute = dcn30_set_avmute,
.log_hw_state = dcn10_log_hw_state,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.c
index fe449f7aa771..63a677c8ee27 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.c
@@ -40,7 +40,6 @@
#define FN(reg_name, field_name) \
optc1->tg_shift->field_name, optc1->tg_mask->field_name
-#define STATIC_SCREEN_EVENT_MASK_DRR_DOUBLE_BUFFER_UPDATE_EN 0x2000 /*bit 13*/
static void optc31_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt,
struct dc_crtc_timing *timing)
{
@@ -232,32 +231,6 @@ void optc3_init_odm(struct timing_generator *optc)
OPTC_MEM_SEL, 0);
optc1->opp_count = 1;
}
-void optc31_set_static_screen_control(
- struct timing_generator *optc,
- uint32_t event_triggers,
- uint32_t num_frames)
-{
- struct optc *optc1 = DCN10TG_FROM_TG(optc);
- uint32_t framecount;
- uint32_t events;
-
- if (num_frames > 0xFF)
- num_frames = 0xFF;
- REG_GET_2(OTG_STATIC_SCREEN_CONTROL,
- OTG_STATIC_SCREEN_EVENT_MASK, &events,
- OTG_STATIC_SCREEN_FRAME_COUNT, &framecount);
-
- if (events == event_triggers && num_frames == framecount)
- return;
- if ((event_triggers & STATIC_SCREEN_EVENT_MASK_DRR_DOUBLE_BUFFER_UPDATE_EN)
- != 0)
- event_triggers = event_triggers &
- ~STATIC_SCREEN_EVENT_MASK_DRR_DOUBLE_BUFFER_UPDATE_EN;
-
- REG_UPDATE_2(OTG_STATIC_SCREEN_CONTROL,
- OTG_STATIC_SCREEN_EVENT_MASK, event_triggers,
- OTG_STATIC_SCREEN_FRAME_COUNT, num_frames);
-}
static struct timing_generator_funcs dcn31_tg_funcs = {
.validate_timing = optc1_validate_timing,
@@ -293,7 +266,7 @@ static struct timing_generator_funcs dcn31_tg_funcs = {
.set_drr = optc31_set_drr,
.get_last_used_drr_vtotal = optc2_get_last_used_drr_vtotal,
.set_vtotal_min_max = optc1_set_vtotal_min_max,
- .set_static_screen_control = optc31_set_static_screen_control,
+ .set_static_screen_control = optc1_set_static_screen_control,
.program_stereo = optc1_program_stereo,
.is_stereo_left_eye = optc1_is_stereo_left_eye,
.tg_init = optc3_tg_init,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.h
index 5fc6c63580d7..30b81a448ce2 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.h
@@ -263,8 +263,5 @@ bool optc31_immediate_disable_crtc(struct timing_generator *optc);
void optc31_set_drr(struct timing_generator *optc, const struct drr_params *params);
void optc3_init_odm(struct timing_generator *optc);
-void optc31_set_static_screen_control(
- struct timing_generator *optc,
- uint32_t event_triggers,
- uint32_t num_frames);
+
#endif /* __DC_OPTC_DCN31_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
index 3ca517dcc82d..d3918a10773a 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
@@ -1795,7 +1795,7 @@ bool dcn31_validate_bandwidth(struct dc *dc,
BW_VAL_TRACE_COUNT();
DC_FP_START();
- out = dcn30_internal_validate_bw(dc, context, pipes, &pipe_cnt, &vlevel, fast_validate);
+ out = dcn30_internal_validate_bw(dc, context, pipes, &pipe_cnt, &vlevel, fast_validate, true);
DC_FP_END();
// Disable fast_validate to set min dcfclk in alculate_wm_and_dlg
diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dio_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dio_stream_encoder.c
index 38842f938bed..962a2c02b422 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dio_stream_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dio_stream_encoder.c
@@ -30,7 +30,7 @@
#include "dcn314_dio_stream_encoder.h"
#include "reg_helper.h"
#include "hw_shared.h"
-#include "inc/link_dpcd.h"
+#include "link.h"
#include "dpcd_defs.h"
#define DC_LOGGER \
@@ -278,10 +278,11 @@ static void enc314_stream_encoder_dp_blank(
struct dc_link *link,
struct stream_encoder *enc)
{
- /* New to DCN314 - disable the FIFO before VID stream disable. */
- enc314_disable_fifo(enc);
-
enc1_stream_encoder_dp_blank(link, enc);
+
+ /* Disable FIFO after the DP vid stream is disabled to avoid corruption. */
+ if (enc->ctx->dc->debug.dig_fifo_off_in_blank)
+ enc314_disable_fifo(enc);
}
static void enc314_stream_encoder_dp_unblank(
@@ -365,7 +366,7 @@ static void enc314_stream_encoder_dp_unblank(
*/
enc314_enable_fifo(enc);
- dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_DP_VID_STREAM);
+ link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_DP_VID_STREAM);
}
/* Set DSC-related configuration.
@@ -428,6 +429,8 @@ static const struct stream_encoder_funcs dcn314_str_enc_funcs = {
enc3_stream_encoder_update_hdmi_info_packets,
.stop_hdmi_info_packets =
enc3_stream_encoder_stop_hdmi_info_packets,
+ .update_dp_info_packets_sdp_line_num =
+ enc3_stream_encoder_update_dp_info_packets_sdp_line_num,
.update_dp_info_packets =
enc3_stream_encoder_update_dp_info_packets,
.stop_dp_info_packets =
diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dio_stream_encoder.h b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dio_stream_encoder.h
index 33dfdf8b4100..ed0772387903 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dio_stream_encoder.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dio_stream_encoder.h
@@ -280,6 +280,10 @@ void enc3_stream_encoder_update_hdmi_info_packets(
void enc3_stream_encoder_stop_hdmi_info_packets(
struct stream_encoder *enc);
+void enc3_stream_encoder_update_dp_info_packets_sdp_line_num(
+ struct stream_encoder *enc,
+ struct encoder_info_frame *info_frame);
+
void enc3_stream_encoder_update_dp_info_packets(
struct stream_encoder *enc,
const struct encoder_info_frame *info_frame);
diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c
index a0741794db62..575d3501c848 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c
@@ -46,9 +46,7 @@
#include "link_hwss.h"
#include "dpcd_defs.h"
#include "dce/dmub_outbox.h"
-#include "dc_link_dp.h"
-#include "inc/dc_link_dp.h"
-#include "inc/link_dpcd.h"
+#include "link.h"
#include "dcn10/dcn10_hw_sequencer.h"
#include "inc/link_enc_cfg.h"
#include "dcn30/dcn30_vpg.h"
@@ -348,7 +346,7 @@ unsigned int dcn314_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsig
two_pix_per_container = optc2_is_two_pixels_per_containter(&stream->timing);
odm_combine_factor = get_odm_config(pipe_ctx, NULL);
- if (is_dp_128b_132b_signal(pipe_ctx)) {
+ if (link_is_dp_128b_132b_signal(pipe_ctx)) {
*k1_div = PIXEL_RATE_DIV_BY_1;
*k2_div = PIXEL_RATE_DIV_BY_1;
} else if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal) || dc_is_dvi_signal(pipe_ctx->stream->signal)) {
@@ -391,3 +389,27 @@ void dcn314_set_pixels_per_cycle(struct pipe_ctx *pipe_ctx)
pipe_ctx->stream_res.stream_enc->funcs->set_input_mode(pipe_ctx->stream_res.stream_enc,
pix_per_cycle);
}
+
+void dcn314_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool power_on)
+{
+ struct dc_context *ctx = hws->ctx;
+ union dmub_rb_cmd cmd;
+
+ if (hws->ctx->dc->debug.disable_hubp_power_gate)
+ return;
+
+ PERF_TRACE();
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.domain_control.header.type = DMUB_CMD__VBIOS;
+ cmd.domain_control.header.sub_type = DMUB_CMD__VBIOS_DOMAIN_CONTROL;
+ cmd.domain_control.header.payload_bytes = sizeof(cmd.domain_control.data);
+ cmd.domain_control.data.inst = hubp_inst;
+ cmd.domain_control.data.power_gate = !power_on;
+
+ dc_dmub_srv_cmd_queue(ctx->dmub_srv, &cmd);
+ dc_dmub_srv_cmd_execute(ctx->dmub_srv);
+ dc_dmub_srv_wait_idle(ctx->dmub_srv);
+
+ PERF_TRACE();
+}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.h b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.h
index 244280298212..c419d3dbdfee 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.h
@@ -41,4 +41,6 @@ unsigned int dcn314_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsig
void dcn314_set_pixels_per_cycle(struct pipe_ctx *pipe_ctx);
+void dcn314_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool power_on);
+
#endif /* __DC_HWSS_DCN314_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c
index 31feb4b0edee..343f4d9dd5e3 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c
@@ -66,9 +66,9 @@ static const struct hw_sequencer_funcs dcn314_funcs = {
.prepare_bandwidth = dcn20_prepare_bandwidth,
.optimize_bandwidth = dcn20_optimize_bandwidth,
.update_bandwidth = dcn20_update_bandwidth,
- .set_drr = dcn31_set_drr,
+ .set_drr = dcn10_set_drr,
.get_position = dcn10_get_position,
- .set_static_screen_control = dcn31_set_static_screen_control,
+ .set_static_screen_control = dcn10_set_static_screen_control,
.setup_stereo = dcn10_setup_stereo,
.set_avmute = dcn30_set_avmute,
.log_hw_state = dcn10_log_hw_state,
@@ -137,7 +137,7 @@ static const struct hwseq_private_funcs dcn314_private_funcs = {
.plane_atomic_disable = dcn20_plane_atomic_disable,
.plane_atomic_power_down = dcn10_plane_atomic_power_down,
.enable_power_gating_plane = dcn314_enable_power_gating_plane,
- .hubp_pg_control = dcn31_hubp_pg_control,
+ .hubp_pg_control = dcn314_hubp_pg_control,
.program_all_writeback_pipes_in_tree = dcn30_program_all_writeback_pipes_in_tree,
.update_odm = dcn314_update_odm,
.dsc_pg_control = dcn314_dsc_pg_control,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_optc.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_optc.c
index 41edbd64ea21..0086cafb0f7a 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_optc.c
@@ -228,7 +228,7 @@ static struct timing_generator_funcs dcn314_tg_funcs = {
.set_drr = optc31_set_drr,
.get_last_used_drr_vtotal = optc2_get_last_used_drr_vtotal,
.set_vtotal_min_max = optc1_set_vtotal_min_max,
- .set_static_screen_control = optc31_set_static_screen_control,
+ .set_static_screen_control = optc1_set_static_screen_control,
.program_stereo = optc1_program_stereo,
.is_stereo_left_eye = optc1_is_stereo_left_eye,
.tg_init = optc3_tg_init,
@@ -241,7 +241,6 @@ static struct timing_generator_funcs dcn314_tg_funcs = {
.set_dsc_config = optc3_set_dsc_config,
.get_dsc_status = optc2_get_dsc_status,
.set_dwb_source = NULL,
- .set_odm_combine = optc314_set_odm_combine,
.get_optc_source = optc2_get_optc_source,
.set_out_mux = optc3_set_out_mux,
.set_drr_trigger_window = optc3_set_drr_trigger_window,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c
index 79850a68f62a..54ed3de869d3 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c
@@ -892,6 +892,8 @@ static const struct dc_debug_options debug_defaults_drv = {
.force_abm_enable = false,
.timing_trace = false,
.clock_trace = true,
+ .disable_dpp_power_gate = true,
+ .disable_hubp_power_gate = true,
.disable_pplib_clock_request = false,
.pipe_split_policy = MPC_SPLIT_DYNAMIC,
.force_single_disp_pipe_split = false,
@@ -901,7 +903,7 @@ static const struct dc_debug_options debug_defaults_drv = {
.max_downscale_src_width = 4096,/*upto true 4k*/
.disable_pplib_wm_range = false,
.scl_reset_length10 = true,
- .sanity_checks = false,
+ .sanity_checks = true,
.underflow_assert_delay_us = 0xFFFFFFFF,
.dwb_fi_phase = -1, // -1 = disable,
.dmub_command_table = true,
@@ -1695,6 +1697,61 @@ static void dcn314_get_panel_config_defaults(struct dc_panel_config *panel_confi
*panel_config = panel_config_defaults;
}
+bool dcn314_validate_bandwidth(struct dc *dc,
+ struct dc_state *context,
+ bool fast_validate)
+{
+ bool out = false;
+
+ BW_VAL_TRACE_SETUP();
+
+ int vlevel = 0;
+ int pipe_cnt = 0;
+ display_e2e_pipe_params_st *pipes = kzalloc(dc->res_pool->pipe_count * sizeof(display_e2e_pipe_params_st), GFP_KERNEL);
+ DC_LOGGER_INIT(dc->ctx->logger);
+
+ BW_VAL_TRACE_COUNT();
+
+ DC_FP_START();
+ // do not support self refresh only
+ out = dcn30_internal_validate_bw(dc, context, pipes, &pipe_cnt, &vlevel, fast_validate, false);
+ DC_FP_END();
+
+ // Disable fast_validate to set min dcfclk in calculate_wm_and_dlg
+ if (pipe_cnt == 0)
+ fast_validate = false;
+
+ if (!out)
+ goto validate_fail;
+
+ BW_VAL_TRACE_END_VOLTAGE_LEVEL();
+
+ if (fast_validate) {
+ BW_VAL_TRACE_SKIP(fast);
+ goto validate_out;
+ }
+
+ dc->res_pool->funcs->calculate_wm_and_dlg(dc, context, pipes, pipe_cnt, vlevel);
+
+ BW_VAL_TRACE_END_WATERMARKS();
+
+ goto validate_out;
+
+validate_fail:
+ DC_LOG_WARNING("Mode Validation Warning: %s failed validation.\n",
+ dml_get_status_message(context->bw_ctx.dml.vba.ValidationStatus[context->bw_ctx.dml.vba.soc.num_states]));
+
+ BW_VAL_TRACE_SKIP(fail);
+ out = false;
+
+validate_out:
+ kfree(pipes);
+
+ BW_VAL_TRACE_FINISH();
+
+ return out;
+}
+
static struct resource_funcs dcn314_res_pool_funcs = {
.destroy = dcn314_destroy_resource_pool,
.link_enc_create = dcn31_link_encoder_create,
@@ -1702,7 +1759,7 @@ static struct resource_funcs dcn314_res_pool_funcs = {
.link_encs_assign = link_enc_cfg_link_encs_assign,
.link_enc_unassign = link_enc_cfg_link_enc_unassign,
.panel_cntl_create = dcn31_panel_cntl_create,
- .validate_bandwidth = dcn31_validate_bandwidth,
+ .validate_bandwidth = dcn314_validate_bandwidth,
.calculate_wm_and_dlg = dcn31_calculate_wm_and_dlg,
.update_soc_for_wm_a = dcn31_update_soc_for_wm_a,
.populate_dml_pipes = dcn314_populate_dml_pipes_from_context,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.h b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.h
index 0dd3153aa5c1..49ffe71018df 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.h
@@ -39,6 +39,10 @@ struct dcn314_resource_pool {
struct resource_pool base;
};
+bool dcn314_validate_bandwidth(struct dc *dc,
+ struct dc_state *context,
+ bool fast_validate);
+
struct resource_pool *dcn314_create_resource_pool(
const struct dc_init_data *init_data,
struct dc *dc);
diff --git a/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c b/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c
index b4d5076e124c..dc0b49506275 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c
@@ -1776,7 +1776,7 @@ static bool dcn316_resource_construct(
pool->base.mpcc_count = pool->base.res_cap->num_timing_generator;
dc->caps.max_downscale_ratio = 600;
dc->caps.i2c_speed_in_khz = 100;
- dc->caps.i2c_speed_in_khz_hdcp = 100;
+ dc->caps.i2c_speed_in_khz_hdcp = 5; /*1.5 w/a applied by default*/
dc->caps.max_cursor_size = 256;
dc->caps.min_horizontal_blanking_period = 80;
dc->caps.dmdata_alloc_size = 2048;
diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dio_link_encoder.c
index 076969d928af..501388014855 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dio_link_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dio_link_encoder.c
@@ -31,7 +31,6 @@
#include "dcn31/dcn31_dio_link_encoder.h"
#include "dcn32_dio_link_encoder.h"
#include "stream_encoder.h"
-#include "i2caux_interface.h"
#include "dc_bios_types.h"
#include "link_enc_cfg.h"
diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dio_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dio_stream_encoder.c
index d19fc93dbc75..36e6f5657942 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dio_stream_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dio_stream_encoder.c
@@ -29,7 +29,7 @@
#include "dcn32_dio_stream_encoder.h"
#include "reg_helper.h"
#include "hw_shared.h"
-#include "inc/link_dpcd.h"
+#include "link.h"
#include "dpcd_defs.h"
#define DC_LOGGER \
@@ -373,7 +373,7 @@ static void enc32_stream_encoder_dp_unblank(
REG_UPDATE(DP_VID_STREAM_CNTL, DP_VID_STREAM_ENABLE, true);
- dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_DP_VID_STREAM);
+ link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_DP_VID_STREAM);
}
/* Set DSC-related configuration.
@@ -421,6 +421,33 @@ static void enc32_set_dig_input_mode(struct stream_encoder *enc, unsigned int pi
REG_UPDATE(DIG_FIFO_CTRL0, DIG_FIFO_OUTPUT_PIXEL_MODE, pix_per_container == 2 ? 0x1 : 0x0);
}
+static void enc32_reset_fifo(struct stream_encoder *enc, bool reset)
+{
+ struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
+ uint32_t reset_val = reset ? 1 : 0;
+ uint32_t is_symclk_on;
+
+ REG_UPDATE(DIG_FIFO_CTRL0, DIG_FIFO_RESET, reset_val);
+ REG_GET(DIG_FE_CNTL, DIG_SYMCLK_FE_ON, &is_symclk_on);
+
+ if (is_symclk_on)
+ REG_WAIT(DIG_FIFO_CTRL0, DIG_FIFO_RESET_DONE, reset_val, 10, 5000);
+ else
+ udelay(10);
+}
+
+static void enc32_enable_fifo(struct stream_encoder *enc)
+{
+ struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
+
+ REG_UPDATE(DIG_FIFO_CTRL0, DIG_FIFO_READ_START_LEVEL, 0x7);
+
+ enc32_reset_fifo(enc, true);
+ enc32_reset_fifo(enc, false);
+
+ REG_UPDATE(DIG_FIFO_CTRL0, DIG_FIFO_ENABLE, 1);
+}
+
static const struct stream_encoder_funcs dcn32_str_enc_funcs = {
.dp_set_odm_combine =
enc32_dp_set_odm_combine,
@@ -436,6 +463,8 @@ static const struct stream_encoder_funcs dcn32_str_enc_funcs = {
enc3_stream_encoder_update_hdmi_info_packets,
.stop_hdmi_info_packets =
enc3_stream_encoder_stop_hdmi_info_packets,
+ .update_dp_info_packets_sdp_line_num =
+ enc3_stream_encoder_update_dp_info_packets_sdp_line_num,
.update_dp_info_packets =
enc3_stream_encoder_update_dp_info_packets,
.stop_dp_info_packets =
@@ -466,6 +495,7 @@ static const struct stream_encoder_funcs dcn32_str_enc_funcs = {
.hdmi_reset_stream_attribute = enc1_reset_hdmi_stream_attribute,
.set_input_mode = enc32_set_dig_input_mode,
+ .enable_fifo = enc32_enable_fifo,
};
void dcn32_dio_stream_encoder_construct(
diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.c
index 9501403a48a9..eb08ccc38e79 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.c
@@ -945,6 +945,35 @@ void hubbub32_force_wm_propagate_to_pipes(struct hubbub *hubbub)
DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value);
}
+void hubbub32_init(struct hubbub *hubbub)
+{
+ struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
+
+ /* Enable clock gate*/
+ if (hubbub->ctx->dc->debug.disable_clock_gate) {
+ /*done in hwseq*/
+ /*REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);*/
+
+ REG_UPDATE_2(DCHUBBUB_CLOCK_CNTL,
+ DISPCLK_R_DCHUBBUB_GATE_DIS, 0,
+ DCFCLK_R_DCHUBBUB_GATE_DIS, 0);
+ }
+ /*
+ ignore the "df_pre_cstate_req" from the SDP port control.
+ only the DCN will determine when to connect the SDP port
+ */
+ REG_UPDATE(DCHUBBUB_SDPIF_CFG0,
+ SDPIF_PORT_CONTROL, 1);
+ /*Set SDP's max outstanding request to 512
+ must set the register back to 0 (max outstanding = 256) in zero frame buffer mode*/
+ REG_UPDATE(DCHUBBUB_SDPIF_CFG1,
+ SDPIF_MAX_NUM_OUTSTANDING, 1);
+ /*must set the registers back to 256 in zero frame buffer mode*/
+ REG_UPDATE_2(DCHUBBUB_ARB_DF_REQ_OUTSTAND,
+ DCHUBBUB_ARB_MAX_REQ_OUTSTAND, 512,
+ DCHUBBUB_ARB_MIN_REQ_OUTSTAND, 512);
+}
+
static const struct hubbub_funcs hubbub32_funcs = {
.update_dchub = hubbub2_update_dchub,
.init_dchub_sys_ctx = hubbub3_init_dchub_sys_ctx,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.h b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.h
index 786f9ce07f92..b20eb04724bb 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubbub.h
@@ -83,7 +83,12 @@
SR(DCN_VM_FAULT_ADDR_LSB),\
SR(DCN_VM_FAULT_CNTL),\
SR(DCN_VM_FAULT_STATUS),\
- SR(SDPIF_REQUEST_RATE_LIMIT)
+ SR(SDPIF_REQUEST_RATE_LIMIT),\
+ SR(DCHUBBUB_CLOCK_CNTL),\
+ SR(DCHUBBUB_SDPIF_CFG0),\
+ SR(DCHUBBUB_SDPIF_CFG1),\
+ SR(DCHUBBUB_MEM_PWR_MODE_CTRL)
+
#define HUBBUB_MASK_SH_LIST_DCN32(mask_sh)\
HUBBUB_SF(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, mask_sh), \
@@ -96,6 +101,7 @@
HUBBUB_SF(DCHUBBUB_ARB_DRAM_STATE_CNTL, DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_ENABLE, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_SAT_LEVEL, DCHUBBUB_ARB_SAT_LEVEL, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_DF_REQ_OUTSTAND, DCHUBBUB_ARB_MIN_REQ_OUTSTAND, mask_sh), \
+ HUBBUB_SF(DCHUBBUB_ARB_DF_REQ_OUTSTAND, DCHUBBUB_ARB_MAX_REQ_OUTSTAND, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, mask_sh), \
@@ -161,7 +167,14 @@
HUBBUB_SF(DCN_VM_FAULT_STATUS, DCN_VM_ERROR_TABLE_LEVEL, mask_sh), \
HUBBUB_SF(DCN_VM_FAULT_STATUS, DCN_VM_ERROR_PIPE, mask_sh), \
HUBBUB_SF(DCN_VM_FAULT_STATUS, DCN_VM_ERROR_INTERRUPT_STATUS, mask_sh),\
- HUBBUB_SF(SDPIF_REQUEST_RATE_LIMIT, SDPIF_REQUEST_RATE_LIMIT, mask_sh)
+ HUBBUB_SF(SDPIF_REQUEST_RATE_LIMIT, SDPIF_REQUEST_RATE_LIMIT, mask_sh),\
+ HUBBUB_SF(DCHUBBUB_CLOCK_CNTL, DISPCLK_R_DCHUBBUB_GATE_DIS, mask_sh),\
+ HUBBUB_SF(DCHUBBUB_CLOCK_CNTL, DCFCLK_R_DCHUBBUB_GATE_DIS, mask_sh),\
+ HUBBUB_SF(DCHUBBUB_SDPIF_CFG0, SDPIF_PORT_CONTROL, mask_sh),\
+ HUBBUB_SF(DCHUBBUB_SDPIF_CFG1, SDPIF_MAX_NUM_OUTSTANDING, mask_sh),\
+ HUBBUB_SF(DCHUBBUB_MEM_PWR_MODE_CTRL, DET_MEM_PWR_LS_MODE, mask_sh)
+
+
bool hubbub32_program_urgent_watermarks(
struct hubbub *hubbub,
@@ -191,6 +204,8 @@ void hubbub32_force_usr_retraining_allow(struct hubbub *hubbub, bool allow);
void hubbub32_force_wm_propagate_to_pipes(struct hubbub *hubbub);
+void hubbub32_init(struct hubbub *hubbub);
+
void dcn32_program_det_size(struct hubbub *hubbub, int hubp_inst, unsigned int det_buffer_size_in_kbyte);
void hubbub32_construct(struct dcn20_hubbub *hubbub2,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubp.c
index ac1c6458dd55..fe0cd177744c 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubp.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubp.c
@@ -155,7 +155,11 @@ void hubp32_cursor_set_attributes(
else
REG_UPDATE(DCHUBP_MALL_CONFIG, USE_MALL_FOR_CURSOR, false);
}
-
+void hubp32_init(struct hubp *hubp)
+{
+ struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp);
+ REG_WRITE(HUBPREQ_DEBUG_DB, 1 << 8);
+}
static struct hubp_funcs dcn32_hubp_funcs = {
.hubp_enable_tripleBuffer = hubp2_enable_triplebuffer,
.hubp_is_triplebuffer_enabled = hubp2_is_triplebuffer_enabled,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubp.h b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubp.h
index 56ef71151536..4cdbf63c952b 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubp.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubp.h
@@ -61,6 +61,8 @@ void hubp32_phantom_hubp_post_enable(struct hubp *hubp);
void hubp32_cursor_set_attributes(struct hubp *hubp,
const struct dc_cursor_attributes *attr);
+void hubp32_init(struct hubp *hubp);
+
bool hubp32_construct(
struct dcn20_hubp *hubp2,
struct dc_context *ctx,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c
index b8767be1e4c5..16f892125b6f 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c
@@ -50,7 +50,7 @@
#include "dmub_subvp_state.h"
#include "dce/dmub_hw_lock_mgr.h"
#include "dcn32_resource.h"
-#include "dc_link_dp.h"
+#include "link.h"
#include "dmub/inc/dmub_subvp_state.h"
#define DC_LOGGER_INIT(logger)
@@ -188,7 +188,8 @@ static bool dcn32_check_no_memory_request_for_cab(struct dc *dc)
/* First, check no-memory-request case */
for (i = 0; i < dc->current_state->stream_count; i++) {
- if (dc->current_state->stream_status[i].plane_count)
+ if ((dc->current_state->stream_status[i].plane_count) &&
+ (dc->current_state->streams[i]->link->psr_settings.psr_version == DC_PSR_VERSION_UNSUPPORTED))
/* Fail eligibility on a visible stream */
break;
}
@@ -206,151 +207,31 @@ static bool dcn32_check_no_memory_request_for_cab(struct dc *dc)
*/
static uint32_t dcn32_calculate_cab_allocation(struct dc *dc, struct dc_state *ctx)
{
- int i, j;
- struct dc_stream_state *stream = NULL;
- struct dc_plane_state *plane = NULL;
- uint32_t cursor_size = 0;
- uint32_t total_lines = 0;
- uint32_t lines_per_way = 0;
+ int i;
uint8_t num_ways = 0;
- uint8_t bytes_per_pixel = 0;
- uint8_t cursor_bpp = 0;
- uint16_t mblk_width = 0;
- uint16_t mblk_height = 0;
- uint16_t mall_alloc_width_blk_aligned = 0;
- uint16_t mall_alloc_height_blk_aligned = 0;
- uint16_t num_mblks = 0;
- uint32_t bytes_in_mall = 0;
- uint32_t cache_lines_used = 0;
- uint32_t cache_lines_per_plane = 0;
+ uint32_t mall_ss_size_bytes = 0;
+ mall_ss_size_bytes = ctx->bw_ctx.bw.dcn.mall_ss_size_bytes;
+ // TODO add additional logic for PSR active stream exclusion optimization
+ // mall_ss_psr_active_size_bytes = ctx->bw_ctx.bw.dcn.mall_ss_psr_active_size_bytes;
+
+ // Include cursor size for CAB allocation
for (i = 0; i < dc->res_pool->pipe_count; i++) {
- struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i];
+ struct pipe_ctx *pipe = &ctx->res_ctx.pipe_ctx[i];
- /* If PSR is supported on an eDP panel that's connected, but that panel is
- * not in PSR at the time of trying to enter MALL SS, we have to include it
- * in the static screen CAB calculation
- */
- if (!pipe->stream || !pipe->plane_state ||
- (pipe->stream->link->psr_settings.psr_version != DC_PSR_VERSION_UNSUPPORTED &&
- pipe->stream->link->psr_settings.psr_allow_active) ||
- pipe->stream->mall_stream_config.type == SUBVP_PHANTOM)
+ if (!pipe->stream || !pipe->plane_state)
continue;
- bytes_per_pixel = pipe->plane_state->format >= SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 ? 8 : 4;
- mblk_width = DCN3_2_MBLK_WIDTH;
- mblk_height = bytes_per_pixel == 4 ? DCN3_2_MBLK_HEIGHT_4BPE : DCN3_2_MBLK_HEIGHT_8BPE;
-
- /* full_vp_width_blk_aligned = FLOOR(vp_x_start + full_vp_width + blk_width - 1, blk_width) -
- * FLOOR(vp_x_start, blk_width)
- *
- * mall_alloc_width_blk_aligned_l/c = full_vp_width_blk_aligned_l/c
- */
- mall_alloc_width_blk_aligned = ((pipe->plane_res.scl_data.viewport.x +
- pipe->plane_res.scl_data.viewport.width + mblk_width - 1) / mblk_width * mblk_width) -
- (pipe->plane_res.scl_data.viewport.x / mblk_width * mblk_width);
-
- /* full_vp_height_blk_aligned = FLOOR(vp_y_start + full_vp_height + blk_height - 1, blk_height) -
- * FLOOR(vp_y_start, blk_height)
- *
- * mall_alloc_height_blk_aligned_l/c = full_vp_height_blk_aligned_l/c
- */
- mall_alloc_height_blk_aligned = ((pipe->plane_res.scl_data.viewport.y +
- pipe->plane_res.scl_data.viewport.height + mblk_height - 1) / mblk_height * mblk_height) -
- (pipe->plane_res.scl_data.viewport.y / mblk_height * mblk_height);
-
- num_mblks = ((mall_alloc_width_blk_aligned + mblk_width - 1) / mblk_width) *
- ((mall_alloc_height_blk_aligned + mblk_height - 1) / mblk_height);
-
- /*For DCC:
- * meta_num_mblk = CEILING(meta_pitch*full_vp_height*Bpe/256/mblk_bytes, 1)
- */
- if (pipe->plane_state->dcc.enable)
- num_mblks += (pipe->plane_state->dcc.meta_pitch * pipe->plane_res.scl_data.viewport.height * bytes_per_pixel +
- (256 * DCN3_2_MALL_MBLK_SIZE_BYTES) - 1) / (256 * DCN3_2_MALL_MBLK_SIZE_BYTES);
-
- bytes_in_mall = num_mblks * DCN3_2_MALL_MBLK_SIZE_BYTES;
-
- /* (cache lines used is total bytes / cache_line size. Add +2 for worst case alignment
- * (MALL is 64-byte aligned)
- */
- cache_lines_per_plane = bytes_in_mall / dc->caps.cache_line_size + 2;
- cache_lines_used += cache_lines_per_plane;
- }
-
- // Include cursor size for CAB allocation
- for (j = 0; j < dc->res_pool->pipe_count; j++) {
- struct pipe_ctx *pipe = &ctx->res_ctx.pipe_ctx[j];
- struct hubp *hubp = pipe->plane_res.hubp;
-
- if (pipe->stream && pipe->plane_state && hubp)
- /* Find the cursor plane and use the exact size instead of
- using the max for calculation */
-
- if (hubp->curs_attr.width > 0) {
- cursor_size = hubp->curs_attr.pitch * hubp->curs_attr.height;
-
- switch (pipe->stream->cursor_attributes.color_format) {
- case CURSOR_MODE_MONO:
- cursor_size /= 2;
- cursor_bpp = 4;
- break;
- case CURSOR_MODE_COLOR_1BIT_AND:
- case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA:
- case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA:
- cursor_size *= 4;
- cursor_bpp = 4;
- break;
-
- case CURSOR_MODE_COLOR_64BIT_FP_PRE_MULTIPLIED:
- case CURSOR_MODE_COLOR_64BIT_FP_UN_PRE_MULTIPLIED:
- cursor_size *= 8;
- cursor_bpp = 8;
- break;
- }
-
- if (pipe->stream->cursor_position.enable && !dc->debug.alloc_extra_way_for_cursor &&
- cursor_size > 16384) {
- /* cursor_num_mblk = CEILING(num_cursors*cursor_width*cursor_width*cursor_Bpe/mblk_bytes, 1)
- */
- cache_lines_used += (((cursor_size + DCN3_2_MALL_MBLK_SIZE_BYTES - 1) /
- DCN3_2_MALL_MBLK_SIZE_BYTES) * DCN3_2_MALL_MBLK_SIZE_BYTES) /
- dc->caps.cache_line_size + 2;
- break;
- }
- }
+ mall_ss_size_bytes += dcn32_helper_calculate_mall_bytes_for_cursor(dc, pipe, false);
}
// Convert number of cache lines required to number of ways
- total_lines = dc->caps.max_cab_allocation_bytes / dc->caps.cache_line_size;
- lines_per_way = total_lines / dc->caps.cache_num_ways;
- num_ways = cache_lines_used / lines_per_way;
-
- if (cache_lines_used % lines_per_way > 0)
- num_ways++;
-
- for (i = 0; i < ctx->stream_count; i++) {
- stream = ctx->streams[i];
- for (j = 0; j < ctx->stream_status[i].plane_count; j++) {
- plane = ctx->stream_status[i].plane_states[j];
-
- if (stream->cursor_position.enable && plane &&
- dc->debug.alloc_extra_way_for_cursor &&
- cursor_size > 16384) {
- /* Cursor caching is not supported since it won't be on the same line.
- * So we need an extra line to accommodate it. With large cursors and a single 4k monitor
- * this case triggers corruption. If we're at the edge, then dont trigger display refresh
- * from MALL. We only need to cache cursor if its greater that 64x64 at 4 bpp.
- */
- num_ways++;
- /* We only expect one cursor plane */
- break;
- }
- }
- }
if (dc->debug.force_mall_ss_num_ways > 0) {
num_ways = dc->debug.force_mall_ss_num_ways;
+ } else {
+ num_ways = dcn32_helper_mall_bytes_to_ways(dc, mall_ss_size_bytes);
}
+
return num_ways;
}
@@ -365,6 +246,13 @@ bool dcn32_apply_idle_power_optimizations(struct dc *dc, bool enable)
if (!dc->ctx->dmub_srv)
return false;
+ for (i = 0; i < dc->current_state->stream_count; i++) {
+ /* MALL SS messaging is not supported with PSR at this time */
+ if (dc->current_state->streams[i] != NULL &&
+ dc->current_state->streams[i]->link->psr_settings.psr_version != DC_PSR_VERSION_UNSUPPORTED)
+ return false;
+ }
+
if (enable) {
if (dc->current_state) {
@@ -803,6 +691,26 @@ void dcn32_program_mall_pipe_config(struct dc *dc, struct dc_state *context)
}
}
+static void dcn32_initialize_min_clocks(struct dc *dc)
+{
+ struct dc_clocks *clocks = &dc->current_state->bw_ctx.bw.dcn.clk;
+
+ clocks->dcfclk_deep_sleep_khz = DCN3_2_DCFCLK_DS_INIT_KHZ;
+ clocks->dcfclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dcfclk_mhz * 1000;
+ clocks->socclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].socclk_mhz * 1000;
+ clocks->dramclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].memclk_mhz * 1000;
+ clocks->dppclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dppclk_mhz * 1000;
+ clocks->dispclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dispclk_mhz * 1000;
+ clocks->ref_dtbclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dtbclk_mhz * 1000;
+ clocks->fclk_p_state_change_support = true;
+ clocks->p_state_change_support = true;
+
+ dc->clk_mgr->funcs->update_clocks(
+ dc->clk_mgr,
+ dc->current_state,
+ true);
+}
+
void dcn32_init_hw(struct dc *dc)
{
struct abm **abms = dc->res_pool->multiple_abms;
@@ -884,7 +792,7 @@ void dcn32_init_hw(struct dc *dc)
hws->funcs.dsc_pg_control(hws, res_pool->dscs[i]->inst, false);
/* we want to turn off all dp displays before doing detection */
- dc_link_blank_all_dp_displays(dc);
+ link_blank_all_dp_displays(dc);
/* If taking control over from VBIOS, we may want to optimize our first
* mode set, so we need to skip powering down pipes until we know which
@@ -897,6 +805,18 @@ void dcn32_init_hw(struct dc *dc)
if (dc->res_pool->hubbub->funcs->allow_self_refresh_control)
dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub,
!dc->res_pool->hubbub->ctx->dc->debug.disable_stutter);
+
+ dcn32_initialize_min_clocks(dc);
+
+ /* On HW init, allow idle optimizations after pipes have been turned off.
+ *
+ * In certain D3 cases (i.e. BOCO / BOMACO) it's possible that hardware state
+ * is reset (i.e. not in idle at the time hw init is called), but software state
+ * still has idle_optimizations = true, so we must disable idle optimizations first
+ * (i.e. set false), then re-enable (set true).
+ */
+ dc_allow_idle_optimizations(dc, false);
+ dc_allow_idle_optimizations(dc, true);
}
/* In headless boot cases, DIG may be turned
@@ -1175,16 +1095,16 @@ unsigned int dcn32_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsign
two_pix_per_container = optc2_is_two_pixels_per_containter(&stream->timing);
odm_combine_factor = get_odm_config(pipe_ctx, NULL);
- if (is_dp_128b_132b_signal(pipe_ctx)) {
+ if (link_is_dp_128b_132b_signal(pipe_ctx)) {
*k1_div = PIXEL_RATE_DIV_BY_1;
*k2_div = PIXEL_RATE_DIV_BY_1;
- } else if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal) || dc_is_dvi_signal(pipe_ctx->stream->signal)) {
+ } else if (dc_is_hdmi_tmds_signal(stream->signal) || dc_is_dvi_signal(stream->signal)) {
*k1_div = PIXEL_RATE_DIV_BY_1;
if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420)
*k2_div = PIXEL_RATE_DIV_BY_2;
else
*k2_div = PIXEL_RATE_DIV_BY_4;
- } else if (dc_is_dp_signal(pipe_ctx->stream->signal) || dc_is_virtual_signal(pipe_ctx->stream->signal)) {
+ } else if (dc_is_dp_signal(stream->signal) || dc_is_virtual_signal(stream->signal)) {
if (two_pix_per_container) {
*k1_div = PIXEL_RATE_DIV_BY_1;
*k2_div = PIXEL_RATE_DIV_BY_2;
@@ -1239,7 +1159,7 @@ void dcn32_unblank_stream(struct pipe_ctx *pipe_ctx,
params.link_settings.link_rate = link_settings->link_rate;
- if (is_dp_128b_132b_signal(pipe_ctx)) {
+ if (link_is_dp_128b_132b_signal(pipe_ctx)) {
/* TODO - DP2.0 HW: Set ODM mode in dp hpo encoder here */
pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_unblank(
pipe_ctx->stream_res.hpo_dp_stream_enc,
@@ -1266,7 +1186,7 @@ bool dcn32_is_dp_dig_pixel_rate_div_policy(struct pipe_ctx *pipe_ctx)
if (!is_h_timing_divisible_by_2(pipe_ctx->stream))
return false;
- if (dc_is_dp_signal(pipe_ctx->stream->signal) && !is_dp_128b_132b_signal(pipe_ctx) &&
+ if (dc_is_dp_signal(pipe_ctx->stream->signal) && !link_is_dp_128b_132b_signal(pipe_ctx) &&
dc->debug.enable_dp_dig_pixel_rate_div_policy)
return true;
return false;
@@ -1300,7 +1220,7 @@ static void apply_symclk_on_tx_off_wa(struct dc_link *link)
pipe_ctx->clock_source->funcs->program_pix_clk(
pipe_ctx->clock_source,
&pipe_ctx->stream_res.pix_clk_params,
- dp_get_link_encoding_format(&pipe_ctx->link_config.dp_link_settings),
+ link_dp_get_encoding_format(&pipe_ctx->link_config.dp_link_settings),
&pipe_ctx->pll_settings);
link->phy_state.symclk_state = SYMCLK_ON_TX_OFF;
break;
@@ -1332,7 +1252,7 @@ void dcn32_disable_link_output(struct dc_link *link,
else if (dmcu != NULL && dmcu->funcs->lock_phy)
dmcu->funcs->unlock_phy(dmcu);
- dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY);
+ link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY);
apply_symclk_on_tx_off_wa(link);
}
@@ -1450,3 +1370,39 @@ void dcn32_update_dsc_pg(struct dc *dc,
}
}
}
+
+void dcn32_enable_phantom_streams(struct dc *dc, struct dc_state *context)
+{
+ unsigned int i;
+
+ for (i = 0; i < dc->res_pool->pipe_count; i++) {
+ struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
+ struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i];
+
+ /* If an active, non-phantom pipe is being transitioned into a phantom
+ * pipe, wait for the double buffer update to complete first before we do
+ * ANY phantom pipe programming.
+ */
+ if (pipe->stream && pipe->stream->mall_stream_config.type == SUBVP_PHANTOM &&
+ old_pipe->stream && old_pipe->stream->mall_stream_config.type != SUBVP_PHANTOM) {
+ old_pipe->stream_res.tg->funcs->wait_for_state(
+ old_pipe->stream_res.tg,
+ CRTC_STATE_VBLANK);
+ old_pipe->stream_res.tg->funcs->wait_for_state(
+ old_pipe->stream_res.tg,
+ CRTC_STATE_VACTIVE);
+ }
+ }
+ for (i = 0; i < dc->res_pool->pipe_count; i++) {
+ struct pipe_ctx *new_pipe = &context->res_ctx.pipe_ctx[i];
+
+ if (new_pipe->stream && new_pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) {
+ // If old context or new context has phantom pipes, apply
+ // the phantom timings now. We can't change the phantom
+ // pipe configuration safely without driver acquiring
+ // the DMCUB lock first.
+ dc->hwss.apply_ctx_to_hw(dc, context);
+ break;
+ }
+ }
+}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h
index 7de36529cf99..e9e9534f3668 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h
@@ -102,4 +102,6 @@ void dcn32_update_dsc_pg(struct dc *dc,
struct dc_state *context,
bool safe_to_disable);
+void dcn32_enable_phantom_streams(struct dc *dc, struct dc_state *context);
+
#endif /* __DC_HWSS_DCN32_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c
index a4e9fd5307c6..0694fa3a3680 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c
@@ -30,6 +30,7 @@
#include "dcn30/dcn30_hwseq.h"
#include "dcn31/dcn31_hwseq.h"
#include "dcn32_hwseq.h"
+#include "dcn32_init.h"
static const struct hw_sequencer_funcs dcn32_funcs = {
.program_gamut_remap = dcn10_program_gamut_remap,
@@ -106,6 +107,7 @@ static const struct hw_sequencer_funcs dcn32_funcs = {
.set_disp_pattern_generator = dcn30_set_disp_pattern_generator,
.get_dcc_en_bits = dcn10_get_dcc_en_bits,
.commit_subvp_config = dcn32_commit_subvp_config,
+ .enable_phantom_streams = dcn32_enable_phantom_streams,
.subvp_pipe_control_lock = dcn32_subvp_pipe_control_lock,
.update_visual_confirm_color = dcn20_update_visual_confirm_color,
.update_phantom_vp_position = dcn32_update_phantom_vp_position,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
index e4dbc8353ea3..74e50c09bb62 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
@@ -57,7 +57,6 @@
#include "dcn31/dcn31_hpo_dp_stream_encoder.h"
#include "dcn31/dcn31_hpo_dp_link_encoder.h"
#include "dcn32/dcn32_hpo_dp_link_encoder.h"
-#include "dc_link_dp.h"
#include "dcn31/dcn31_apg.h"
#include "dcn31/dcn31_dio_link_encoder.h"
#include "dcn32/dcn32_dio_link_encoder.h"
@@ -69,7 +68,7 @@
#include "dml/display_mode_vba.h"
#include "dcn32/dcn32_dccg.h"
#include "dcn10/dcn10_resource.h"
-#include "dc_link_ddc.h"
+#include "link.h"
#include "dcn31/dcn31_panel_cntl.h"
#include "dcn30/dcn30_dwb.h"
@@ -726,6 +725,7 @@ static const struct dc_debug_options debug_defaults_drv = {
.allow_sw_cursor_fallback = false, // Linux can't do SW cursor "fallback"
.alloc_extra_way_for_cursor = true,
.min_prefetch_in_strobe_ns = 60000, // 60us
+ .disable_unbounded_requesting = false,
};
static const struct dc_debug_options debug_defaults_diags = {
@@ -1507,7 +1507,7 @@ static void dcn32_resource_destruct(struct dcn32_resource_pool *pool)
dcn_dccg_destroy(&pool->base.dccg);
if (pool->base.oem_device != NULL)
- dal_ddc_service_destroy(&pool->base.oem_device);
+ link_destroy_ddc_service(&pool->base.oem_device);
}
@@ -2149,13 +2149,19 @@ static bool dcn32_resource_construct(
dc->caps.max_cursor_size = 64;
dc->caps.min_horizontal_blanking_period = 80;
dc->caps.dmdata_alloc_size = 2048;
- dc->caps.mall_size_per_mem_channel = 0;
+ dc->caps.mall_size_per_mem_channel = 4;
dc->caps.mall_size_total = 0;
dc->caps.cursor_cache_size = dc->caps.max_cursor_size * dc->caps.max_cursor_size * 8;
dc->caps.cache_line_size = 64;
dc->caps.cache_num_ways = 16;
- dc->caps.max_cab_allocation_bytes = 67108864; // 64MB = 1024 * 1024 * 64
+
+ /* Calculate the available MALL space */
+ dc->caps.max_cab_allocation_bytes = dcn32_calc_num_avail_chans_for_mall(
+ dc, dc->ctx->dc_bios->vram_info.num_chans) *
+ dc->caps.mall_size_per_mem_channel * 1024 * 1024;
+ dc->caps.mall_size_total = dc->caps.max_cab_allocation_bytes;
+
dc->caps.subvp_fw_processing_delay_us = 15;
dc->caps.subvp_drr_max_vblank_margin_us = 40;
dc->caps.subvp_prefetch_end_to_mall_start_us = 15;
@@ -2449,7 +2455,7 @@ static bool dcn32_resource_construct(
ddc_init_data.id.id = dc->ctx->dc_bios->fw_info.oem_i2c_obj_id;
ddc_init_data.id.enum_id = 0;
ddc_init_data.id.type = OBJECT_TYPE_GENERIC;
- pool->base.oem_device = dal_ddc_service_create(&ddc_init_data);
+ pool->base.oem_device = link_create_ddc_service(&ddc_init_data);
} else {
pool->base.oem_device = NULL;
}
@@ -2592,3 +2598,55 @@ struct pipe_ctx *dcn32_acquire_idle_pipe_for_head_pipe_in_layer(
return idle_pipe;
}
+
+unsigned int dcn32_calc_num_avail_chans_for_mall(struct dc *dc, int num_chans)
+{
+ /*
+ * DCN32 and DCN321 SKUs may have different sizes for MALL
+ * but we may not be able to access all the MALL space.
+ * If the num_chans is power of 2, then we can access all
+ * of the available MALL space. Otherwise, we can only
+ * access:
+ *
+ * max_cab_size_in_bytes = total_cache_size_in_bytes *
+ * ((2^floor(log2(num_chans)))/num_chans)
+ *
+ * Calculating the MALL sizes for all available SKUs, we
+ * have come up with the follow simplified check.
+ * - we have max_chans which provides the max MALL size.
+ * Each chans supports 4MB of MALL so:
+ *
+ * total_cache_size_in_bytes = max_chans * 4 MB
+ *
+ * - we have avail_chans which shows the number of channels
+ * we can use if we can't access the entire MALL space.
+ * It is generally half of max_chans
+ * - so we use the following checks:
+ *
+ * if (num_chans == max_chans), return max_chans
+ * if (num_chans < max_chans), return avail_chans
+ *
+ * - exception is GC_11_0_0 where we can't access max_chans,
+ * so we define max_avail_chans as the maximum available
+ * MALL space
+ *
+ */
+ int gc_11_0_0_max_chans = 48;
+ int gc_11_0_0_max_avail_chans = 32;
+ int gc_11_0_0_avail_chans = 16;
+ int gc_11_0_3_max_chans = 16;
+ int gc_11_0_3_avail_chans = 8;
+ int gc_11_0_2_max_chans = 8;
+ int gc_11_0_2_avail_chans = 4;
+
+ if (ASICREV_IS_GC_11_0_0(dc->ctx->asic_id.hw_internal_rev)) {
+ return (num_chans == gc_11_0_0_max_chans) ?
+ gc_11_0_0_max_avail_chans : gc_11_0_0_avail_chans;
+ } else if (ASICREV_IS_GC_11_0_2(dc->ctx->asic_id.hw_internal_rev)) {
+ return (num_chans == gc_11_0_2_max_chans) ?
+ gc_11_0_2_max_chans : gc_11_0_2_avail_chans;
+ } else { // if (ASICREV_IS_GC_11_0_3(dc->ctx->asic_id.hw_internal_rev)) {
+ return (num_chans == gc_11_0_3_max_chans) ?
+ gc_11_0_3_max_chans : gc_11_0_3_avail_chans;
+ }
+}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h
index 13fbc574910b..aca928edc4e3 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h
@@ -38,6 +38,7 @@
#define DCN3_2_MBLK_HEIGHT_4BPE 128
#define DCN3_2_MBLK_HEIGHT_8BPE 64
#define DCN3_2_VMIN_DISPCLK_HZ 717000000
+#define DCN3_2_DCFCLK_DS_INIT_KHZ 10000 // Choose 10Mhz for init DCFCLK DS freq
#define TO_DCN32_RES_POOL(pool)\
container_of(pool, struct dcn32_resource_pool, base)
@@ -96,8 +97,17 @@ void dcn32_calculate_wm_and_dlg(
int pipe_cnt,
int vlevel);
-uint32_t dcn32_helper_calculate_num_ways_for_subvp
- (struct dc *dc,
+uint32_t dcn32_helper_mall_bytes_to_ways(
+ struct dc *dc,
+ uint32_t total_size_in_mall_bytes);
+
+uint32_t dcn32_helper_calculate_mall_bytes_for_cursor(
+ struct dc *dc,
+ struct pipe_ctx *pipe_ctx,
+ bool ignore_cursor_buf);
+
+uint32_t dcn32_helper_calculate_num_ways_for_subvp(
+ struct dc *dc,
struct dc_state *context);
void dcn32_merge_pipes_for_subvp(struct dc *dc,
@@ -112,6 +122,8 @@ bool dcn32_subvp_in_use(struct dc *dc,
bool dcn32_mpo_in_use(struct dc_state *context);
bool dcn32_any_surfaces_rotated(struct dc *dc, struct dc_state *context);
+bool dcn32_is_center_timing(struct pipe_ctx *pipe);
+bool dcn32_is_psr_capable(struct pipe_ctx *pipe);
struct pipe_ctx *dcn32_acquire_idle_pipe_for_head_pipe_in_layer(
struct dc_state *state,
@@ -134,6 +146,12 @@ void dcn32_restore_mall_state(struct dc *dc,
struct dc_state *context,
struct mall_temp_config *temp_config);
+bool dcn32_allow_subvp_with_active_margin(struct pipe_ctx *pipe);
+
+unsigned int dcn32_calc_num_avail_chans_for_mall(struct dc *dc, int num_chans);
+
+double dcn32_determine_max_vratio_prefetch(struct dc *dc, struct dc_state *context);
+
/* definitions for run time init of reg offsets */
/* CLK SRC */
diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c
index 783935c4e664..3a2d7bcc4b6d 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c
@@ -33,13 +33,75 @@ static bool is_dual_plane(enum surface_pixel_format format)
return format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN || format == SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA;
}
+
+uint32_t dcn32_helper_mall_bytes_to_ways(
+ struct dc *dc,
+ uint32_t total_size_in_mall_bytes)
+{
+ uint32_t cache_lines_used, lines_per_way, total_cache_lines, num_ways;
+
+ /* add 2 lines for worst case alignment */
+ cache_lines_used = total_size_in_mall_bytes / dc->caps.cache_line_size + 2;
+
+ total_cache_lines = dc->caps.max_cab_allocation_bytes / dc->caps.cache_line_size;
+ lines_per_way = total_cache_lines / dc->caps.cache_num_ways;
+ num_ways = cache_lines_used / lines_per_way;
+ if (cache_lines_used % lines_per_way > 0)
+ num_ways++;
+
+ return num_ways;
+}
+
+uint32_t dcn32_helper_calculate_mall_bytes_for_cursor(
+ struct dc *dc,
+ struct pipe_ctx *pipe_ctx,
+ bool ignore_cursor_buf)
+{
+ struct hubp *hubp = pipe_ctx->plane_res.hubp;
+ uint32_t cursor_size = hubp->curs_attr.pitch * hubp->curs_attr.height;
+ uint32_t cursor_bpp = 4;
+ uint32_t cursor_mall_size_bytes = 0;
+
+ switch (pipe_ctx->stream->cursor_attributes.color_format) {
+ case CURSOR_MODE_MONO:
+ cursor_size /= 2;
+ cursor_bpp = 4;
+ break;
+ case CURSOR_MODE_COLOR_1BIT_AND:
+ case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA:
+ case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA:
+ cursor_size *= 4;
+ cursor_bpp = 4;
+ break;
+
+ case CURSOR_MODE_COLOR_64BIT_FP_PRE_MULTIPLIED:
+ case CURSOR_MODE_COLOR_64BIT_FP_UN_PRE_MULTIPLIED:
+ cursor_size *= 8;
+ cursor_bpp = 8;
+ break;
+ }
+
+ /* only count if cursor is enabled, and if additional allocation needed outside of the
+ * DCN cursor buffer
+ */
+ if (pipe_ctx->stream->cursor_position.enable && (ignore_cursor_buf ||
+ cursor_size > 16384)) {
+ /* cursor_num_mblk = CEILING(num_cursors*cursor_width*cursor_width*cursor_Bpe/mblk_bytes, 1)
+ * Note: add 1 mblk in case of cursor misalignment
+ */
+ cursor_mall_size_bytes = ((cursor_size + DCN3_2_MALL_MBLK_SIZE_BYTES - 1) /
+ DCN3_2_MALL_MBLK_SIZE_BYTES + 1) * DCN3_2_MALL_MBLK_SIZE_BYTES;
+ }
+
+ return cursor_mall_size_bytes;
+}
+
/**
* ********************************************************************************************
* dcn32_helper_calculate_num_ways_for_subvp: Calculate number of ways needed for SubVP
*
- * This function first checks the bytes required per pixel on the SubVP pipe, then calculates
- * the total number of pixels required in the SubVP MALL region. These are used to calculate
- * the number of cache lines used (then number of ways required) for SubVP MCLK switching.
+ * Gets total allocation required for the phantom viewport calculated by DML in bytes and
+ * converts to number of cache ways.
*
* @param [in] dc: current dc state
* @param [in] context: new dc state
@@ -48,106 +110,19 @@ static bool is_dual_plane(enum surface_pixel_format format)
*
* ********************************************************************************************
*/
-uint32_t dcn32_helper_calculate_num_ways_for_subvp(struct dc *dc, struct dc_state *context)
+uint32_t dcn32_helper_calculate_num_ways_for_subvp(
+ struct dc *dc,
+ struct dc_state *context)
{
- uint32_t num_ways = 0;
- uint32_t bytes_per_pixel = 0;
- uint32_t cache_lines_used = 0;
- uint32_t lines_per_way = 0;
- uint32_t total_cache_lines = 0;
- uint32_t bytes_in_mall = 0;
- uint32_t num_mblks = 0;
- uint32_t cache_lines_per_plane = 0;
- uint32_t i = 0, j = 0;
- uint16_t mblk_width = 0;
- uint16_t mblk_height = 0;
- uint32_t full_vp_width_blk_aligned = 0;
- uint32_t full_vp_height_blk_aligned = 0;
- uint32_t mall_alloc_width_blk_aligned = 0;
- uint32_t mall_alloc_height_blk_aligned = 0;
- uint16_t full_vp_height = 0;
- bool subvp_in_use = false;
-
- for (i = 0; i < dc->res_pool->pipe_count; i++) {
- struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
-
- /* Find the phantom pipes.
- * - For pipe split case we need to loop through the bottom and next ODM
- * pipes or only half the viewport size is counted
- */
- if (pipe->stream && pipe->plane_state &&
- pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) {
- struct pipe_ctx *main_pipe = NULL;
-
- subvp_in_use = true;
- /* Get full viewport height from main pipe (required for MBLK calculation) */
- for (j = 0; j < dc->res_pool->pipe_count; j++) {
- main_pipe = &context->res_ctx.pipe_ctx[j];
- if (main_pipe->stream == pipe->stream->mall_stream_config.paired_stream) {
- full_vp_height = main_pipe->plane_res.scl_data.viewport.height;
- break;
- }
- }
-
- bytes_per_pixel = pipe->plane_state->format >= SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 ? 8 : 4;
- mblk_width = DCN3_2_MBLK_WIDTH;
- mblk_height = bytes_per_pixel == 4 ? DCN3_2_MBLK_HEIGHT_4BPE : DCN3_2_MBLK_HEIGHT_8BPE;
-
- /* full_vp_width_blk_aligned = FLOOR(vp_x_start + full_vp_width + blk_width - 1, blk_width) -
- * FLOOR(vp_x_start, blk_width)
- */
- full_vp_width_blk_aligned = ((pipe->plane_res.scl_data.viewport.x +
- pipe->plane_res.scl_data.viewport.width + mblk_width - 1) / mblk_width * mblk_width) -
- (pipe->plane_res.scl_data.viewport.x / mblk_width * mblk_width);
-
- /* full_vp_height_blk_aligned = FLOOR(vp_y_start + full_vp_height + blk_height - 1, blk_height) -
- * FLOOR(vp_y_start, blk_height)
- */
- full_vp_height_blk_aligned = ((pipe->plane_res.scl_data.viewport.y +
- full_vp_height + mblk_height - 1) / mblk_height * mblk_height) -
- (pipe->plane_res.scl_data.viewport.y / mblk_height * mblk_height);
-
- /* mall_alloc_width_blk_aligned_l/c = full_vp_width_blk_aligned_l/c */
- mall_alloc_width_blk_aligned = full_vp_width_blk_aligned;
-
- /* mall_alloc_height_blk_aligned_l/c = CEILING(sub_vp_height_l/c - 1, blk_height_l/c) + blk_height_l/c */
- mall_alloc_height_blk_aligned = (pipe->plane_res.scl_data.viewport.height - 1 + mblk_height - 1) /
- mblk_height * mblk_height + mblk_height;
-
- /* full_mblk_width_ub_l/c = mall_alloc_width_blk_aligned_l/c;
- * full_mblk_height_ub_l/c = mall_alloc_height_blk_aligned_l/c;
- * num_mblk_l/c = (full_mblk_width_ub_l/c / mblk_width_l/c) * (full_mblk_height_ub_l/c / mblk_height_l/c);
- * (Should be divisible, but round up if not)
- */
- num_mblks = ((mall_alloc_width_blk_aligned + mblk_width - 1) / mblk_width) *
- ((mall_alloc_height_blk_aligned + mblk_height - 1) / mblk_height);
-
- /*For DCC:
- * meta_num_mblk = CEILING(meta_pitch*full_vp_height*Bpe/256/mblk_bytes, 1)
- */
- if (pipe->plane_state->dcc.enable)
- num_mblks += (pipe->plane_state->dcc.meta_pitch * pipe->plane_res.scl_data.viewport.height * bytes_per_pixel +
- (256 * DCN3_2_MALL_MBLK_SIZE_BYTES) - 1) / (256 * DCN3_2_MALL_MBLK_SIZE_BYTES);
-
- bytes_in_mall = num_mblks * DCN3_2_MALL_MBLK_SIZE_BYTES;
- // cache lines used is total bytes / cache_line size. Add +2 for worst case alignment
- // (MALL is 64-byte aligned)
- cache_lines_per_plane = bytes_in_mall / dc->caps.cache_line_size + 2;
-
- cache_lines_used += cache_lines_per_plane;
+ if (context->bw_ctx.bw.dcn.mall_subvp_size_bytes > 0) {
+ if (dc->debug.force_subvp_num_ways) {
+ return dc->debug.force_subvp_num_ways;
+ } else {
+ return dcn32_helper_mall_bytes_to_ways(dc, context->bw_ctx.bw.dcn.mall_subvp_size_bytes);
}
+ } else {
+ return 0;
}
-
- total_cache_lines = dc->caps.max_cab_allocation_bytes / dc->caps.cache_line_size;
- lines_per_way = total_cache_lines / dc->caps.cache_num_ways;
- num_ways = cache_lines_used / lines_per_way;
- if (cache_lines_used % lines_per_way > 0)
- num_ways++;
-
- if (subvp_in_use && dc->debug.force_subvp_num_ways > 0)
- num_ways = dc->debug.force_subvp_num_ways;
-
- return num_ways;
}
void dcn32_merge_pipes_for_subvp(struct dc *dc,
@@ -255,6 +230,37 @@ bool dcn32_any_surfaces_rotated(struct dc *dc, struct dc_state *context)
return false;
}
+bool dcn32_is_center_timing(struct pipe_ctx *pipe)
+{
+ bool is_center_timing = false;
+
+ if (pipe->stream) {
+ if (pipe->stream->timing.v_addressable != pipe->stream->dst.height ||
+ pipe->stream->timing.v_addressable != pipe->stream->src.height) {
+ is_center_timing = true;
+ }
+ }
+
+ if (pipe->plane_state) {
+ if (pipe->stream->timing.v_addressable != pipe->plane_state->dst_rect.height &&
+ pipe->stream->timing.v_addressable != pipe->plane_state->src_rect.height) {
+ is_center_timing = true;
+ }
+ }
+
+ return is_center_timing;
+}
+
+bool dcn32_is_psr_capable(struct pipe_ctx *pipe)
+{
+ bool psr_capable = false;
+
+ if (pipe->stream && pipe->stream->link->psr_settings.psr_version != DC_PSR_VERSION_UNSUPPORTED) {
+ psr_capable = true;
+ }
+ return psr_capable;
+}
+
/**
* *******************************************************************************************
* dcn32_determine_det_override: Determine DET allocation for each pipe
@@ -357,6 +363,7 @@ void dcn32_set_det_allocations(struct dc *dc, struct dc_state *context,
int i, pipe_cnt;
struct resource_context *res_ctx = &context->res_ctx;
struct pipe_ctx *pipe;
+ bool disable_unbounded_requesting = dc->debug.disable_z9_mpc || dc->debug.disable_unbounded_requesting;
for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) {
@@ -373,7 +380,7 @@ void dcn32_set_det_allocations(struct dc *dc, struct dc_state *context,
*/
if (pipe_cnt == 1) {
pipes[0].pipe.src.det_size_override = DCN3_2_MAX_DET_SIZE;
- if (pipe->plane_state && !dc->debug.disable_z9_mpc && pipe->plane_state->tiling_info.gfx9.swizzle != DC_SW_LINEAR) {
+ if (pipe->plane_state && !disable_unbounded_requesting && pipe->plane_state->tiling_info.gfx9.swizzle != DC_SW_LINEAR) {
if (!is_dual_plane(pipe->plane_state->format)) {
pipes[0].pipe.src.det_size_override = DCN3_2_DEFAULT_DET_SIZE;
pipes[0].pipe.src.unbounded_req_mode = true;
diff --git a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_dio_link_encoder.c
index fa9b6603cfd3..13be5f06d987 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_dio_link_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_dio_link_encoder.c
@@ -31,7 +31,6 @@
#include "dcn321_dio_link_encoder.h"
#include "dcn31/dcn31_dio_link_encoder.h"
#include "stream_encoder.h"
-#include "i2caux_interface.h"
#include "dc_bios_types.h"
#include "gpio_service_interface.h"
diff --git a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c
index d1f36df03c2e..55f918b44077 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c
@@ -60,7 +60,6 @@
#include "dcn31/dcn31_hpo_dp_stream_encoder.h"
#include "dcn31/dcn31_hpo_dp_link_encoder.h"
#include "dcn32/dcn32_hpo_dp_link_encoder.h"
-#include "dc_link_dp.h"
#include "dcn31/dcn31_apg.h"
#include "dcn31/dcn31_dio_link_encoder.h"
#include "dcn32/dcn32_dio_link_encoder.h"
@@ -73,7 +72,7 @@
#include "dml/display_mode_vba.h"
#include "dcn32/dcn32_dccg.h"
#include "dcn10/dcn10_resource.h"
-#include "dc_link_ddc.h"
+#include "link.h"
#include "dcn31/dcn31_panel_cntl.h"
#include "dcn30/dcn30_dwb.h"
@@ -724,6 +723,7 @@ static const struct dc_debug_options debug_defaults_drv = {
.allow_sw_cursor_fallback = false, // Linux can't do SW cursor "fallback"
.alloc_extra_way_for_cursor = true,
.min_prefetch_in_strobe_ns = 60000, // 60us
+ .disable_unbounded_requesting = false,
};
static const struct dc_debug_options debug_defaults_diags = {
@@ -1492,7 +1492,7 @@ static void dcn321_resource_destruct(struct dcn321_resource_pool *pool)
dcn_dccg_destroy(&pool->base.dccg);
if (pool->base.oem_device != NULL)
- dal_ddc_service_destroy(&pool->base.oem_device);
+ link_destroy_ddc_service(&pool->base.oem_device);
}
@@ -1702,12 +1702,18 @@ static bool dcn321_resource_construct(
dc->caps.max_cursor_size = 64;
dc->caps.min_horizontal_blanking_period = 80;
dc->caps.dmdata_alloc_size = 2048;
- dc->caps.mall_size_per_mem_channel = 0;
+ dc->caps.mall_size_per_mem_channel = 4;
dc->caps.mall_size_total = 0;
dc->caps.cursor_cache_size = dc->caps.max_cursor_size * dc->caps.max_cursor_size * 8;
dc->caps.cache_line_size = 64;
dc->caps.cache_num_ways = 16;
- dc->caps.max_cab_allocation_bytes = 33554432; // 32MB = 1024 * 1024 * 32
+
+ /* Calculate the available MALL space */
+ dc->caps.max_cab_allocation_bytes = dcn32_calc_num_avail_chans_for_mall(
+ dc, dc->ctx->dc_bios->vram_info.num_chans) *
+ dc->caps.mall_size_per_mem_channel * 1024 * 1024;
+ dc->caps.mall_size_total = dc->caps.max_cab_allocation_bytes;
+
dc->caps.subvp_fw_processing_delay_us = 15;
dc->caps.subvp_drr_max_vblank_margin_us = 40;
dc->caps.subvp_prefetch_end_to_mall_start_us = 15;
@@ -1990,7 +1996,7 @@ static bool dcn321_resource_construct(
ddc_init_data.id.id = dc->ctx->dc_bios->fw_info.oem_i2c_obj_id;
ddc_init_data.id.enum_id = 0;
ddc_init_data.id.type = OBJECT_TYPE_GENERIC;
- pool->base.oem_device = dal_ddc_service_create(&ddc_init_data);
+ pool->base.oem_device = link_create_ddc_service(&ddc_init_data);
} else {
pool->base.oem_device = NULL;
}
diff --git a/drivers/gpu/drm/amd/display/dc/dm_helpers.h b/drivers/gpu/drm/amd/display/dc/dm_helpers.h
index af1c50ed905a..7ce9a5b6c33b 100644
--- a/drivers/gpu/drm/amd/display/dc/dm_helpers.h
+++ b/drivers/gpu/drm/amd/display/dc/dm_helpers.h
@@ -161,6 +161,12 @@ enum dc_edid_status dm_helpers_read_local_edid(
struct dc_link *link,
struct dc_sink *sink);
+bool dm_helpers_dp_handle_test_pattern_request(
+ struct dc_context *ctx,
+ const struct dc_link *link,
+ union link_test_pattern dpcd_test_pattern,
+ union test_misc dpcd_test_params);
+
void dm_set_dcn_clocks(
struct dc_context *ctx,
struct dc_clocks *clks);
@@ -193,6 +199,7 @@ int dm_helpers_dmub_set_config_sync(struct dc_context *ctx,
const struct dc_link *link,
struct set_config_cmd_payload *payload,
enum set_config_status *operation_result);
+enum adaptive_sync_type dm_get_adaptive_sync_support_type(struct dc_link *link);
enum dc_edid_status dm_helpers_get_sbios_edid(struct dc_link *link, struct dc_edid *edid);
diff --git a/drivers/gpu/drm/amd/display/dc/dml/Makefile b/drivers/gpu/drm/amd/display/dc/dml/Makefile
index 0ecea87cf48f..9d0f79dff2e3 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/dml/Makefile
@@ -26,7 +26,8 @@
# subcomponents.
ifdef CONFIG_X86
-dml_ccflags := -mhard-float -msse
+dml_ccflags-$(CONFIG_CC_IS_GCC) := -mhard-float
+dml_ccflags := $(dml_ccflags-y) -msse
endif
ifdef CONFIG_PPC64
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c
index c26da3bb2892..d3ba65efe1d2 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c
@@ -26,12 +26,12 @@
#include "resource.h"
#include "clk_mgr.h"
-#include "dc_link_dp.h"
#include "dchubbub.h"
#include "dcn20/dcn20_resource.h"
#include "dcn21/dcn21_resource.h"
#include "clk_mgr/dcn21/rn_clk_mgr.h"
+#include "link.h"
#include "dcn20_fpu.h"
#define DC_LOGGER_INIT(logger)
@@ -938,7 +938,7 @@ static bool is_dtbclk_required(struct dc *dc, struct dc_state *context)
for (i = 0; i < dc->res_pool->pipe_count; i++) {
if (!context->res_ctx.pipe_ctx[i].stream)
continue;
- if (is_dp_128b_132b_signal(&context->res_ctx.pipe_ctx[i]))
+ if (link_is_dp_128b_132b_signal(&context->res_ctx.pipe_ctx[i]))
return true;
}
return false;
@@ -949,7 +949,6 @@ static enum dcn_zstate_support_state decide_zstate_support(struct dc *dc, struc
int plane_count;
int i;
unsigned int optimized_min_dst_y_next_start_us;
- bool allow_z8 = context->bw_ctx.dml.vba.StutterPeriod > 1000.0;
plane_count = 0;
optimized_min_dst_y_next_start_us = 0;
@@ -974,6 +973,8 @@ static enum dcn_zstate_support_state decide_zstate_support(struct dc *dc, struc
else if (context->stream_count == 1 && context->streams[0]->signal == SIGNAL_TYPE_EDP) {
struct dc_link *link = context->streams[0]->sink->link;
struct dc_stream_status *stream_status = &context->stream_status[0];
+ bool allow_z8 = context->bw_ctx.dml.vba.StutterPeriod > 1000.0;
+ bool is_pwrseq0 = link->link_index == 0;
if (dc_extended_blank_supported(dc)) {
for (i = 0; i < dc->res_pool->pipe_count; i++) {
@@ -986,23 +987,55 @@ static enum dcn_zstate_support_state decide_zstate_support(struct dc *dc, struc
}
}
}
- /* zstate only supported on PWRSEQ0 and when there's <2 planes*/
- if (link->link_index != 0 || stream_status->plane_count > 1)
+
+ /* Don't support multi-plane configurations */
+ if (stream_status->plane_count > 1)
return DCN_ZSTATE_SUPPORT_DISALLOW;
- if (context->bw_ctx.dml.vba.StutterPeriod > 5000.0 || optimized_min_dst_y_next_start_us > 5000)
+ if (is_pwrseq0 && (context->bw_ctx.dml.vba.StutterPeriod > 5000.0 || optimized_min_dst_y_next_start_us > 5000))
return DCN_ZSTATE_SUPPORT_ALLOW;
- else if (link->psr_settings.psr_version == DC_PSR_VERSION_1 && !link->panel_config.psr.disable_psr)
+ else if (is_pwrseq0 && link->psr_settings.psr_version == DC_PSR_VERSION_1 && !link->panel_config.psr.disable_psr)
return allow_z8 ? DCN_ZSTATE_SUPPORT_ALLOW_Z8_Z10_ONLY : DCN_ZSTATE_SUPPORT_ALLOW_Z10_ONLY;
else
return allow_z8 ? DCN_ZSTATE_SUPPORT_ALLOW_Z8_ONLY : DCN_ZSTATE_SUPPORT_DISALLOW;
- } else if (allow_z8) {
- return DCN_ZSTATE_SUPPORT_ALLOW_Z8_ONLY;
} else {
return DCN_ZSTATE_SUPPORT_DISALLOW;
}
}
+static void dcn20_adjust_freesync_v_startup(
+ const struct dc_crtc_timing *dc_crtc_timing, int *vstartup_start)
+{
+ struct dc_crtc_timing patched_crtc_timing;
+ uint32_t asic_blank_end = 0;
+ uint32_t asic_blank_start = 0;
+ uint32_t newVstartup = 0;
+
+ patched_crtc_timing = *dc_crtc_timing;
+
+ if (patched_crtc_timing.flags.INTERLACE == 1) {
+ if (patched_crtc_timing.v_front_porch < 2)
+ patched_crtc_timing.v_front_porch = 2;
+ } else {
+ if (patched_crtc_timing.v_front_porch < 1)
+ patched_crtc_timing.v_front_porch = 1;
+ }
+
+ /* blank_start = frame end - front porch */
+ asic_blank_start = patched_crtc_timing.v_total -
+ patched_crtc_timing.v_front_porch;
+
+ /* blank_end = blank_start - active */
+ asic_blank_end = asic_blank_start -
+ patched_crtc_timing.v_border_bottom -
+ patched_crtc_timing.v_addressable -
+ patched_crtc_timing.v_border_top;
+
+ newVstartup = asic_blank_end + (patched_crtc_timing.v_total - asic_blank_start);
+
+ *vstartup_start = ((newVstartup > *vstartup_start) ? newVstartup : *vstartup_start);
+}
+
void dcn20_calculate_dlg_params(
struct dc *dc, struct dc_state *context,
display_e2e_pipe_params_st *pipes,
@@ -1062,6 +1095,11 @@ void dcn20_calculate_dlg_params(
context->res_ctx.pipe_ctx[i].plane_res.bw.dppclk_khz =
pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000;
context->res_ctx.pipe_ctx[i].pipe_dlg_param = pipes[pipe_idx].pipe.dest;
+ if (context->res_ctx.pipe_ctx[i].stream->adaptive_sync_infopacket.valid)
+ dcn20_adjust_freesync_v_startup(
+ &context->res_ctx.pipe_ctx[i].stream->timing,
+ &context->res_ctx.pipe_ctx[i].pipe_dlg_param.vstartup_start);
+
pipe_idx++;
}
/*save a original dppclock copy*/
@@ -1302,7 +1340,7 @@ int dcn20_populate_dml_pipes_from_context(
case SIGNAL_TYPE_DISPLAY_PORT_MST:
case SIGNAL_TYPE_DISPLAY_PORT:
pipes[pipe_cnt].dout.output_type = dm_dp;
- if (is_dp_128b_132b_signal(&res_ctx->pipe_ctx[i]))
+ if (link_is_dp_128b_132b_signal(&res_ctx->pipe_ctx[i]))
pipes[pipe_cnt].dout.output_type = dm_dp2p0;
break;
case SIGNAL_TYPE_EDP:
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20.c
index d3b5b6fedf04..6266b0788387 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20.c
@@ -3897,14 +3897,14 @@ void dml20_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
mode_lib->vba.PlaneRequiredDISPCLKWithODMCombine = mode_lib->vba.PixelClock[k] / 2
* (1 + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading / 100.0);
- locals->ODMCombineEnablePerState[i][k] = false;
+ locals->ODMCombineEnablePerState[i][k] = dm_odm_combine_mode_disabled;
mode_lib->vba.PlaneRequiredDISPCLK = mode_lib->vba.PlaneRequiredDISPCLKWithoutODMCombine;
if (mode_lib->vba.ODMCapability) {
if (locals->PlaneRequiredDISPCLKWithoutODMCombine > mode_lib->vba.MaxDispclkRoundedDownToDFSGranularity) {
- locals->ODMCombineEnablePerState[i][k] = true;
+ locals->ODMCombineEnablePerState[i][k] = dm_odm_combine_mode_2to1;
mode_lib->vba.PlaneRequiredDISPCLK = mode_lib->vba.PlaneRequiredDISPCLKWithODMCombine;
} else if (locals->HActive[k] > DCN20_MAX_420_IMAGE_WIDTH && locals->OutputFormat[k] == dm_420) {
- locals->ODMCombineEnablePerState[i][k] = true;
+ locals->ODMCombineEnablePerState[i][k] = dm_odm_combine_mode_2to1;
mode_lib->vba.PlaneRequiredDISPCLK = mode_lib->vba.PlaneRequiredDISPCLKWithODMCombine;
}
}
@@ -3957,7 +3957,7 @@ void dml20_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
locals->RequiredDISPCLK[i][j] = 0.0;
locals->DISPCLK_DPPCLK_Support[i][j] = true;
for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) {
- locals->ODMCombineEnablePerState[i][k] = false;
+ locals->ODMCombineEnablePerState[i][k] = dm_odm_combine_mode_disabled;
if (locals->SwathWidthYSingleDPP[k] <= locals->MaximumSwathWidth[k]) {
locals->NoOfDPP[i][j][k] = 1;
locals->RequiredDPPCLK[i][j][k] = locals->MinDPPCLKUsingSingleDPP[k]
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20v2.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20v2.c
index edd098c7eb92..989d83ee3842 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20v2.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20v2.c
@@ -4008,17 +4008,17 @@ void dml20v2_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode
mode_lib->vba.PlaneRequiredDISPCLKWithODMCombine = mode_lib->vba.PixelClock[k] / 2
* (1 + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading / 100.0);
- locals->ODMCombineEnablePerState[i][k] = false;
+ locals->ODMCombineEnablePerState[i][k] = dm_odm_combine_mode_disabled;
mode_lib->vba.PlaneRequiredDISPCLK = mode_lib->vba.PlaneRequiredDISPCLKWithoutODMCombine;
if (mode_lib->vba.ODMCapability) {
if (locals->PlaneRequiredDISPCLKWithoutODMCombine > MaxMaxDispclkRoundedDown) {
- locals->ODMCombineEnablePerState[i][k] = true;
+ locals->ODMCombineEnablePerState[i][k] = dm_odm_combine_mode_2to1;
mode_lib->vba.PlaneRequiredDISPCLK = mode_lib->vba.PlaneRequiredDISPCLKWithODMCombine;
} else if (locals->DSCEnabled[k] && (locals->HActive[k] > DCN20_MAX_DSC_IMAGE_WIDTH)) {
- locals->ODMCombineEnablePerState[i][k] = true;
+ locals->ODMCombineEnablePerState[i][k] = dm_odm_combine_mode_2to1;
mode_lib->vba.PlaneRequiredDISPCLK = mode_lib->vba.PlaneRequiredDISPCLKWithODMCombine;
} else if (locals->HActive[k] > DCN20_MAX_420_IMAGE_WIDTH && locals->OutputFormat[k] == dm_420) {
- locals->ODMCombineEnablePerState[i][k] = true;
+ locals->ODMCombineEnablePerState[i][k] = dm_odm_combine_mode_2to1;
mode_lib->vba.PlaneRequiredDISPCLK = mode_lib->vba.PlaneRequiredDISPCLKWithODMCombine;
}
}
@@ -4071,7 +4071,7 @@ void dml20v2_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode
locals->RequiredDISPCLK[i][j] = 0.0;
locals->DISPCLK_DPPCLK_Support[i][j] = true;
for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) {
- locals->ODMCombineEnablePerState[i][k] = false;
+ locals->ODMCombineEnablePerState[i][k] = dm_odm_combine_mode_disabled;
if (locals->SwathWidthYSingleDPP[k] <= locals->MaximumSwathWidth[k]) {
locals->NoOfDPP[i][j][k] = 1;
locals->RequiredDPPCLK[i][j][k] = locals->MinDPPCLKUsingSingleDPP[k]
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_mode_vba_21.c b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_mode_vba_21.c
index 1d84ae50311d..b7c2844d0cbe 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_mode_vba_21.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_mode_vba_21.c
@@ -4102,17 +4102,17 @@ void dml21_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
mode_lib->vba.PlaneRequiredDISPCLKWithODMCombine = mode_lib->vba.PixelClock[k] / 2
* (1 + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading / 100.0);
- locals->ODMCombineEnablePerState[i][k] = false;
+ locals->ODMCombineEnablePerState[i][k] = dm_odm_combine_mode_disabled;
mode_lib->vba.PlaneRequiredDISPCLK = mode_lib->vba.PlaneRequiredDISPCLKWithoutODMCombine;
if (mode_lib->vba.ODMCapability) {
if (locals->PlaneRequiredDISPCLKWithoutODMCombine > MaxMaxDispclkRoundedDown) {
- locals->ODMCombineEnablePerState[i][k] = true;
+ locals->ODMCombineEnablePerState[i][k] = dm_odm_combine_mode_2to1;
mode_lib->vba.PlaneRequiredDISPCLK = mode_lib->vba.PlaneRequiredDISPCLKWithODMCombine;
} else if (locals->DSCEnabled[k] && (locals->HActive[k] > DCN21_MAX_DSC_IMAGE_WIDTH)) {
- locals->ODMCombineEnablePerState[i][k] = true;
+ locals->ODMCombineEnablePerState[i][k] = dm_odm_combine_mode_2to1;
mode_lib->vba.PlaneRequiredDISPCLK = mode_lib->vba.PlaneRequiredDISPCLKWithODMCombine;
} else if (locals->HActive[k] > DCN21_MAX_420_IMAGE_WIDTH && locals->OutputFormat[k] == dm_420) {
- locals->ODMCombineEnablePerState[i][k] = true;
+ locals->ODMCombineEnablePerState[i][k] = dm_odm_combine_mode_2to1;
mode_lib->vba.PlaneRequiredDISPCLK = mode_lib->vba.PlaneRequiredDISPCLKWithODMCombine;
}
}
@@ -4165,7 +4165,7 @@ void dml21_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
locals->RequiredDISPCLK[i][j] = 0.0;
locals->DISPCLK_DPPCLK_Support[i][j] = true;
for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) {
- locals->ODMCombineEnablePerState[i][k] = false;
+ locals->ODMCombineEnablePerState[i][k] = dm_odm_combine_mode_disabled;
if (locals->SwathWidthYSingleDPP[k] <= locals->MaximumSwathWidth[k]) {
locals->NoOfDPP[i][j][k] = 1;
locals->RequiredDPPCLK[i][j][k] = locals->MinDPPCLKUsingSingleDPP[k]
@@ -5230,7 +5230,7 @@ void dml21_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
mode_lib->vba.ODMCombineEnabled[k] =
locals->ODMCombineEnablePerState[mode_lib->vba.VoltageLevel][k];
} else {
- mode_lib->vba.ODMCombineEnabled[k] = false;
+ mode_lib->vba.ODMCombineEnabled[k] = dm_odm_combine_mode_disabled;
}
mode_lib->vba.DSCEnabled[k] =
locals->RequiresDSC[mode_lib->vba.VoltageLevel][k];
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c
index d4c0f9cdac8e..4fa636364793 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c
@@ -634,7 +634,7 @@ int dcn30_find_dummy_latency_index_for_fw_based_mclk_switch(struct dc *dc,
while (dummy_latency_index < max_latency_table_entries) {
context->bw_ctx.dml.soc.dram_clock_change_latency_us =
dc->clk_mgr->bw_params->dummy_pstate_table[dummy_latency_index].dummy_pstate_latency_us;
- dcn30_internal_validate_bw(dc, context, pipes, &pipe_cnt, &vlevel, false);
+ dcn30_internal_validate_bw(dc, context, pipes, &pipe_cnt, &vlevel, false, true);
if (context->bw_ctx.dml.soc.allow_dram_self_refresh_or_dram_clock_change_in_vblank ==
dm_allow_self_refresh_and_mclk_switch)
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c
index 379729b02847..c3d75e56410c 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c
@@ -1802,7 +1802,10 @@ static unsigned int CalculateVMAndRowBytes(
}
if (SurfaceTiling == dm_sw_linear) {
- *dpte_row_height = dml_min(128, 1 << (unsigned int) dml_floor(dml_log2(PTEBufferSizeInRequests * *PixelPTEReqWidth / Pitch), 1));
+ if (PTEBufferSizeInRequests == 0)
+ *dpte_row_height = 1;
+ else
+ *dpte_row_height = dml_min(128, 1 << (unsigned int) dml_floor(dml_log2(PTEBufferSizeInRequests * *PixelPTEReqWidth / Pitch), 1));
*dpte_row_width_ub = (dml_ceil(((double) SwathWidth - 1) / *PixelPTEReqWidth, 1) + 1) * *PixelPTEReqWidth;
*PixelPTEBytesPerRow = *dpte_row_width_ub / *PixelPTEReqWidth * *PTERequestSize;
} else if (ScanDirection != dm_vert) {
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c
index ec351c8418cb..27f488405335 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c
@@ -878,7 +878,9 @@ static bool CalculatePrefetchSchedule(
double DSTTotalPixelsAfterScaler;
double LineTime;
double dst_y_prefetch_equ;
+#ifdef __DML_VBA_DEBUG__
double Tsw_oto;
+#endif
double prefetch_bw_oto;
double prefetch_bw_pr;
double Tvm_oto;
@@ -1060,7 +1062,9 @@ static bool CalculatePrefetchSchedule(
min_Lsw = dml_max(1, dml_max(PrefetchSourceLinesY, PrefetchSourceLinesC) / max_vratio_pre);
Lsw_oto = dml_ceil(4 * dml_max(prefetch_sw_bytes / prefetch_bw_oto / LineTime, min_Lsw), 1) / 4;
+#ifdef __DML_VBA_DEBUG__
Tsw_oto = Lsw_oto * LineTime;
+#endif
#ifdef __DML_VBA_DEBUG__
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c
index 6a1cf6adea77..acda3e1babd4 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn314/dcn314_fpu.c
@@ -149,8 +149,8 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_14_soc = {
.num_states = 5,
.sr_exit_time_us = 16.5,
.sr_enter_plus_exit_time_us = 18.5,
- .sr_exit_z8_time_us = 280.0,
- .sr_enter_plus_exit_z8_time_us = 350.0,
+ .sr_exit_z8_time_us = 210.0,
+ .sr_enter_plus_exit_z8_time_us = 310.0,
.writeback_latency_us = 12.0,
.dram_channel_width_bytes = 4,
.round_trip_ping_latency_dcfclk_cycles = 106,
@@ -346,7 +346,8 @@ int dcn314_populate_dml_pipes_from_context_fpu(struct dc *dc, struct dc_state *c
context->bw_ctx.dml.ip.det_buffer_size_kbytes = DCN3_14_DEFAULT_DET_SIZE;
dc->config.enable_4to1MPC = false;
- if (pipe_cnt == 1 && pipe->plane_state && !dc->debug.disable_z9_mpc) {
+ if (pipe_cnt == 1 && pipe->plane_state
+ && pipe->plane_state->rotation == ROTATION_ANGLE_0 && !dc->debug.disable_z9_mpc) {
if (is_dual_plane(pipe->plane_state->format)
&& pipe->plane_state->src_rect.width <= 1920 && pipe->plane_state->src_rect.height <= 1080) {
dc->config.enable_4to1MPC = true;
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c b/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c
index cb7c0c878423..c843b394aeb4 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c
@@ -900,7 +900,9 @@ static bool CalculatePrefetchSchedule(
double DSTTotalPixelsAfterScaler;
double LineTime;
double dst_y_prefetch_equ;
+#ifdef __DML_VBA_DEBUG__
double Tsw_oto;
+#endif
double prefetch_bw_oto;
double prefetch_bw_pr;
double Tvm_oto;
@@ -1082,7 +1084,9 @@ static bool CalculatePrefetchSchedule(
min_Lsw = dml_max(1, dml_max(PrefetchSourceLinesY, PrefetchSourceLinesC) / max_vratio_pre);
Lsw_oto = dml_ceil(4 * dml_max(prefetch_sw_bytes / prefetch_bw_oto / LineTime, min_Lsw), 1) / 4;
+#ifdef __DML_VBA_DEBUG__
Tsw_oto = Lsw_oto * LineTime;
+#endif
#ifdef __DML_VBA_DEBUG__
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_rq_dlg_calc_314.c b/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_rq_dlg_calc_314.c
index 61ee9ba063a7..6576b897a512 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_rq_dlg_calc_314.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_rq_dlg_calc_314.c
@@ -51,7 +51,7 @@ static bool CalculateBytePerPixelAnd256BBlockSizes(
*BytePerPixelDETC = 0;
*BytePerPixelY = 4;
*BytePerPixelC = 0;
- } else if (SourcePixelFormat == dm_444_16 || SourcePixelFormat == dm_444_16) {
+ } else if (SourcePixelFormat == dm_444_16) {
*BytePerPixelDETY = 2;
*BytePerPixelDETC = 0;
*BytePerPixelY = 2;
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
index f94abd124021..e47828e3b6d5 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
@@ -24,13 +24,14 @@
*
*/
#include "dcn32_fpu.h"
-#include "dc_link_dp.h"
#include "dcn32/dcn32_resource.h"
#include "dcn20/dcn20_resource.h"
#include "display_mode_vba_util_32.h"
+#include "dml/dcn32/display_mode_vba_32.h"
// We need this includes for WATERMARKS_* defines
#include "clk_mgr/dcn32/dcn32_smu13_driver_if.h"
#include "dcn30/dcn30_resource.h"
+#include "link.h"
#define DC_LOGGER_INIT(logger)
@@ -691,9 +692,11 @@ static bool dcn32_assign_subvp_pipe(struct dc *dc,
* to combine this with SubVP can cause issues with the scheduling).
* - Not TMZ surface
*/
- if (pipe->plane_state && !pipe->top_pipe &&
+ if (pipe->plane_state && !pipe->top_pipe && !dcn32_is_center_timing(pipe) && !dcn32_is_psr_capable(pipe) &&
pipe->stream->mall_stream_config.type == SUBVP_NONE && refresh_rate < 120 && !pipe->plane_state->address.tmz_surface &&
- vba->ActiveDRAMClockChangeLatencyMarginPerState[vba->VoltageLevel][vba->maxMpcComb][vba->pipe_plane[pipe_idx]] <= 0) {
+ (vba->ActiveDRAMClockChangeLatencyMarginPerState[vba->VoltageLevel][vba->maxMpcComb][vba->pipe_plane[pipe_idx]] <= 0 ||
+ (vba->ActiveDRAMClockChangeLatencyMarginPerState[vba->VoltageLevel][vba->maxMpcComb][vba->pipe_plane[pipe_idx]] > 0 &&
+ dcn32_allow_subvp_with_active_margin(pipe)))) {
while (pipe) {
num_pipes++;
pipe = pipe->bottom_pipe;
@@ -877,6 +880,10 @@ static bool subvp_drr_schedulable(struct dc *dc, struct dc_state *context, struc
int16_t stretched_drr_us = 0;
int16_t drr_stretched_vblank_us = 0;
int16_t max_vblank_mallregion = 0;
+ const struct dc_config *config = &dc->config;
+
+ if (config->disable_subvp_drr)
+ return false;
// Find SubVP pipe
for (i = 0; i < dc->res_pool->pipe_count; i++) {
@@ -977,10 +984,12 @@ static bool subvp_vblank_schedulable(struct dc *dc, struct dc_state *context)
if (!subvp_pipe && pipe->stream->mall_stream_config.type == SUBVP_MAIN)
subvp_pipe = pipe;
}
- // Use ignore_msa_timing_param flag to identify as DRR
- if (found && context->res_ctx.pipe_ctx[vblank_index].stream->ignore_msa_timing_param) {
- // SUBVP + DRR case
- schedulable = subvp_drr_schedulable(dc, context, &context->res_ctx.pipe_ctx[vblank_index]);
+ // Use ignore_msa_timing_param and VRR active, or Freesync flag to identify as DRR On
+ if (found && context->res_ctx.pipe_ctx[vblank_index].stream->ignore_msa_timing_param &&
+ (context->res_ctx.pipe_ctx[vblank_index].stream->allow_freesync ||
+ context->res_ctx.pipe_ctx[vblank_index].stream->vrr_active_variable)) {
+ // SUBVP + DRR case -- only allowed if run through DRR validation path
+ schedulable = false;
} else if (found) {
main_timing = &subvp_pipe->stream->timing;
phantom_timing = &subvp_pipe->stream->mall_stream_config.paired_stream->timing;
@@ -1084,12 +1093,12 @@ static void dcn32_full_validate_bw_helper(struct dc *dc,
{
struct vba_vars_st *vba = &context->bw_ctx.dml.vba;
unsigned int dc_pipe_idx = 0;
+ int i = 0;
bool found_supported_config = false;
struct pipe_ctx *pipe = NULL;
uint32_t non_subvp_pipes = 0;
bool drr_pipe_found = false;
uint32_t drr_pipe_index = 0;
- uint32_t i = 0;
dc_assert_fp_enabled();
@@ -1169,15 +1178,25 @@ static void dcn32_full_validate_bw_helper(struct dc *dc,
pipes[0].clks_cfg.dppclk_mhz = get_dppclk_calculated(&context->bw_ctx.dml, pipes, *pipe_cnt, 0);
*vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, *pipe_cnt);
+ /* Check that vlevel requested supports pstate or not
+ * if not, select the lowest vlevel that supports it
+ */
+ for (i = *vlevel; i < context->bw_ctx.dml.soc.num_states; i++) {
+ if (vba->DRAMClockChangeSupport[i][vba->maxMpcComb] != dm_dram_clock_change_unsupported) {
+ *vlevel = i;
+ break;
+ }
+ }
+
if (*vlevel < context->bw_ctx.dml.soc.num_states &&
vba->DRAMClockChangeSupport[*vlevel][vba->maxMpcComb] != dm_dram_clock_change_unsupported
&& subvp_validate_static_schedulability(dc, context, *vlevel)) {
found_supported_config = true;
- } else if (*vlevel < context->bw_ctx.dml.soc.num_states &&
- vba->DRAMClockChangeSupport[*vlevel][vba->maxMpcComb] == dm_dram_clock_change_unsupported) {
- /* Case where 1 SubVP is added, and DML reports MCLK unsupported. This handles
- * the case for SubVP + DRR, where the DRR display does not support MCLK switch
- * at it's native refresh rate / timing.
+ } else if (*vlevel < context->bw_ctx.dml.soc.num_states) {
+ /* Case where 1 SubVP is added, and DML reports MCLK unsupported or DRR is allowed.
+ * This handles the case for SubVP + DRR, where the DRR display does not support MCLK
+ * switch at it's native refresh rate / timing, or DRR is allowed for the non-subvp
+ * display.
*/
for (i = 0; i < dc->res_pool->pipe_count; i++) {
pipe = &context->res_ctx.pipe_ctx[i];
@@ -1185,7 +1204,7 @@ static void dcn32_full_validate_bw_helper(struct dc *dc,
pipe->stream->mall_stream_config.type == SUBVP_NONE) {
non_subvp_pipes++;
// Use ignore_msa_timing_param flag to identify as DRR
- if (pipe->stream->ignore_msa_timing_param) {
+ if (pipe->stream->ignore_msa_timing_param && pipe->stream->allow_freesync) {
drr_pipe_found = true;
drr_pipe_index = i;
}
@@ -1194,6 +1213,15 @@ static void dcn32_full_validate_bw_helper(struct dc *dc,
// If there is only 1 remaining non SubVP pipe that is DRR, check static
// schedulability for SubVP + DRR.
if (non_subvp_pipes == 1 && drr_pipe_found) {
+ /* find lowest vlevel that supports the config */
+ for (i = *vlevel; i >= 0; i--) {
+ if (vba->ModeSupport[i][vba->maxMpcComb]) {
+ *vlevel = i;
+ } else {
+ break;
+ }
+ }
+
found_supported_config = subvp_drr_schedulable(dc, context,
&context->res_ctx.pipe_ctx[drr_pipe_index]);
}
@@ -1242,12 +1270,44 @@ static bool is_dtbclk_required(struct dc *dc, struct dc_state *context)
for (i = 0; i < dc->res_pool->pipe_count; i++) {
if (!context->res_ctx.pipe_ctx[i].stream)
continue;
- if (is_dp_128b_132b_signal(&context->res_ctx.pipe_ctx[i]))
+ if (link_is_dp_128b_132b_signal(&context->res_ctx.pipe_ctx[i]))
return true;
}
return false;
}
+static void dcn20_adjust_freesync_v_startup(const struct dc_crtc_timing *dc_crtc_timing, int *vstartup_start)
+{
+ struct dc_crtc_timing patched_crtc_timing;
+ uint32_t asic_blank_end = 0;
+ uint32_t asic_blank_start = 0;
+ uint32_t newVstartup = 0;
+
+ patched_crtc_timing = *dc_crtc_timing;
+
+ if (patched_crtc_timing.flags.INTERLACE == 1) {
+ if (patched_crtc_timing.v_front_porch < 2)
+ patched_crtc_timing.v_front_porch = 2;
+ } else {
+ if (patched_crtc_timing.v_front_porch < 1)
+ patched_crtc_timing.v_front_porch = 1;
+ }
+
+ /* blank_start = frame end - front porch */
+ asic_blank_start = patched_crtc_timing.v_total -
+ patched_crtc_timing.v_front_porch;
+
+ /* blank_end = blank_start - active */
+ asic_blank_end = asic_blank_start -
+ patched_crtc_timing.v_border_bottom -
+ patched_crtc_timing.v_addressable -
+ patched_crtc_timing.v_border_top;
+
+ newVstartup = asic_blank_end + (patched_crtc_timing.v_total - asic_blank_start);
+
+ *vstartup_start = ((newVstartup > *vstartup_start) ? newVstartup : *vstartup_start);
+}
+
static void dcn32_calculate_dlg_params(struct dc *dc, struct dc_state *context,
display_e2e_pipe_params_st *pipes,
int pipe_cnt, int vlevel)
@@ -1270,7 +1330,6 @@ static void dcn32_calculate_dlg_params(struct dc *dc, struct dc_state *context,
context->bw_ctx.bw.dcn.clk.p_state_change_support =
context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][context->bw_ctx.dml.vba.maxMpcComb]
!= dm_dram_clock_change_unsupported;
- context->bw_ctx.bw.dcn.clk.num_ways = dcn32_helper_calculate_num_ways_for_subvp(dc, context);
context->bw_ctx.bw.dcn.clk.dppclk_khz = 0;
context->bw_ctx.bw.dcn.clk.dtbclk_en = is_dtbclk_required(dc, context);
@@ -1294,6 +1353,10 @@ static void dcn32_calculate_dlg_params(struct dc *dc, struct dc_state *context,
unbounded_req_enabled = false;
}
+ context->bw_ctx.bw.dcn.mall_ss_size_bytes = 0;
+ context->bw_ctx.bw.dcn.mall_ss_psr_active_size_bytes = 0;
+ context->bw_ctx.bw.dcn.mall_subvp_size_bytes = 0;
+
for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) {
if (!context->res_ctx.pipe_ctx[i].stream)
continue;
@@ -1325,6 +1388,34 @@ static void dcn32_calculate_dlg_params(struct dc *dc, struct dc_state *context,
else
context->res_ctx.pipe_ctx[i].plane_res.bw.dppclk_khz = 0;
context->res_ctx.pipe_ctx[i].pipe_dlg_param = pipes[pipe_idx].pipe.dest;
+
+ context->res_ctx.pipe_ctx[i].surface_size_in_mall_bytes = get_surface_size_in_mall(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx);
+
+ /* MALL Allocation Sizes */
+ /* count from active, top pipes per plane only */
+ if (context->res_ctx.pipe_ctx[i].stream && context->res_ctx.pipe_ctx[i].plane_state &&
+ (context->res_ctx.pipe_ctx[i].top_pipe == NULL ||
+ context->res_ctx.pipe_ctx[i].plane_state != context->res_ctx.pipe_ctx[i].top_pipe->plane_state) &&
+ context->res_ctx.pipe_ctx[i].prev_odm_pipe == NULL) {
+ /* SS: all active surfaces stored in MALL */
+ if (context->res_ctx.pipe_ctx[i].stream->mall_stream_config.type != SUBVP_PHANTOM) {
+ context->bw_ctx.bw.dcn.mall_ss_size_bytes += context->res_ctx.pipe_ctx[i].surface_size_in_mall_bytes;
+
+ if (context->res_ctx.pipe_ctx[i].stream->link->psr_settings.psr_version == DC_PSR_VERSION_UNSUPPORTED) {
+ /* SS PSR On: all active surfaces part of streams not supporting PSR stored in MALL */
+ context->bw_ctx.bw.dcn.mall_ss_psr_active_size_bytes += context->res_ctx.pipe_ctx[i].surface_size_in_mall_bytes;
+ }
+ } else {
+ /* SUBVP: phantom surfaces only stored in MALL */
+ context->bw_ctx.bw.dcn.mall_subvp_size_bytes += context->res_ctx.pipe_ctx[i].surface_size_in_mall_bytes;
+ }
+ }
+
+ if (context->res_ctx.pipe_ctx[i].stream->adaptive_sync_infopacket.valid)
+ dcn20_adjust_freesync_v_startup(
+ &context->res_ctx.pipe_ctx[i].stream->timing,
+ &context->res_ctx.pipe_ctx[i].pipe_dlg_param.vstartup_start);
+
pipe_idx++;
}
/* If DCN isn't making memory requests we can allow pstate change and lower clocks */
@@ -1345,6 +1436,8 @@ static void dcn32_calculate_dlg_params(struct dc *dc, struct dc_state *context,
context->bw_ctx.bw.dcn.clk.max_supported_dispclk_khz = context->bw_ctx.dml.soc.clock_limits[vlevel].dispclk_mhz
* 1000;
+ context->bw_ctx.bw.dcn.clk.num_ways = dcn32_helper_calculate_num_ways_for_subvp(dc, context);
+
context->bw_ctx.bw.dcn.compbuf_size_kb = context->bw_ctx.dml.ip.config_return_buffer_size_in_kbytes;
for (i = 0; i < dc->res_pool->pipe_count; i++) {
@@ -1530,6 +1623,7 @@ bool dcn32_internal_validate_bw(struct dc *dc,
}
dml_log_pipe_params(&context->bw_ctx.dml, pipes, pipe_cnt);
+ context->bw_ctx.dml.soc.max_vratio_pre = dcn32_determine_max_vratio_prefetch(dc, context);
if (!fast_validate)
dcn32_full_validate_bw_helper(dc, context, pipes, &vlevel, split, merge, &pipe_cnt);
@@ -1549,16 +1643,12 @@ bool dcn32_internal_validate_bw(struct dc *dc,
* to support with Prefetch mode 1 (dm_prefetch_support_fclk_and_stutter == 2)
*/
context->bw_ctx.dml.soc.allow_for_pstate_or_stutter_in_vblank_final =
- dm_prefetch_support_fclk_and_stutter;
+ dm_prefetch_support_none;
+ context->bw_ctx.dml.validate_max_state = fast_validate;
vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, pipe_cnt);
- /* Last attempt with Prefetch mode 2 (dm_prefetch_support_stutter == 3) */
- if (vlevel == context->bw_ctx.dml.soc.num_states) {
- context->bw_ctx.dml.soc.allow_for_pstate_or_stutter_in_vblank_final =
- dm_prefetch_support_stutter;
- vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, pipe_cnt);
- }
+ context->bw_ctx.dml.validate_max_state = false;
if (vlevel < context->bw_ctx.dml.soc.num_states) {
memset(split, 0, sizeof(split));
@@ -1645,6 +1735,7 @@ bool dcn32_internal_validate_bw(struct dc *dc,
dcn20_release_dsc(&context->res_ctx, dc->res_pool, &pipe->stream_res.dsc);
memset(&pipe->plane_res, 0, sizeof(pipe->plane_res));
memset(&pipe->stream_res, 0, sizeof(pipe->stream_res));
+ memset(&pipe->link_res, 0, sizeof(pipe->link_res));
repopulate_pipes = true;
} else if (pipe->top_pipe && pipe->top_pipe->plane_state == pipe->plane_state) {
struct pipe_ctx *top_pipe = pipe->top_pipe;
@@ -1660,6 +1751,7 @@ bool dcn32_internal_validate_bw(struct dc *dc,
pipe->stream = NULL;
memset(&pipe->plane_res, 0, sizeof(pipe->plane_res));
memset(&pipe->stream_res, 0, sizeof(pipe->stream_res));
+ memset(&pipe->link_res, 0, sizeof(pipe->link_res));
repopulate_pipes = true;
} else
ASSERT(0); /* Should never try to merge master pipe */
@@ -1834,7 +1926,7 @@ void dcn32_calculate_wm_and_dlg_fpu(struct dc *dc, struct dc_state *context,
bool subvp_in_use = dcn32_subvp_in_use(dc, context);
unsigned int min_dram_speed_mts_margin;
bool need_fclk_lat_as_dummy = false;
- bool is_subvp_p_drr = true;
+ bool is_subvp_p_drr = false;
dc_assert_fp_enabled();
@@ -1842,7 +1934,8 @@ void dcn32_calculate_wm_and_dlg_fpu(struct dc *dc, struct dc_state *context,
if (subvp_in_use) {
/* Override DRAMClockChangeSupport for SubVP + DRR case where the DRR cannot switch without stretching it's VBLANK */
if (!pstate_en) {
- context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][context->bw_ctx.dml.vba.maxMpcComb] = dm_dram_clock_change_vblank_w_mall_sub_vp;
+ context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][maxMpcComb] = dm_dram_clock_change_vblank_w_mall_sub_vp;
+ context->bw_ctx.dml.soc.allow_for_pstate_or_stutter_in_vblank_final = dm_prefetch_support_fclk_and_stutter;
pstate_en = true;
is_subvp_p_drr = true;
}
@@ -1860,8 +1953,9 @@ void dcn32_calculate_wm_and_dlg_fpu(struct dc *dc, struct dc_state *context,
context->bw_ctx.dml.soc.dram_clock_change_latency_us =
dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.pstate_latency_us;
dcn32_internal_validate_bw(dc, context, pipes, &pipe_cnt, &vlevel, false);
+ maxMpcComb = context->bw_ctx.dml.vba.maxMpcComb;
if (is_subvp_p_drr) {
- context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][context->bw_ctx.dml.vba.maxMpcComb] = dm_dram_clock_change_vblank_w_mall_sub_vp;
+ context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][maxMpcComb] = dm_dram_clock_change_vblank_w_mall_sub_vp;
}
}
@@ -2038,6 +2132,10 @@ void dcn32_calculate_wm_and_dlg_fpu(struct dc *dc, struct dc_state *context,
*/
context->bw_ctx.bw.dcn.watermarks.a = context->bw_ctx.bw.dcn.watermarks.c;
context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = 0;
+ /* Calculate FCLK p-state change watermark based on FCLK pstate change latency in case
+ * UCLK p-state is not supported, to avoid underflow in case FCLK pstate is supported
+ */
+ context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.fclk_pstate_change_ns = get_fclk_watermark(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
} else {
/* Set A:
* All clocks min.
@@ -2443,8 +2541,11 @@ void dcn32_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_pa
}
/* Override from VBIOS for num_chan */
- if (dc->ctx->dc_bios->vram_info.num_chans)
+ if (dc->ctx->dc_bios->vram_info.num_chans) {
dcn3_2_soc.num_chans = dc->ctx->dc_bios->vram_info.num_chans;
+ dcn3_2_soc.mall_allocated_for_dcn_mbytes = (double)(dcn32_calc_num_avail_chans_for_mall(dc,
+ dc->ctx->dc_bios->vram_info.num_chans) * dc->caps.mall_size_per_mem_channel);
+ }
if (dc->ctx->dc_bios->vram_info.dram_channel_width_bytes)
dcn3_2_soc.dram_channel_width_bytes = dc->ctx->dc_bios->vram_info.dram_channel_width_bytes;
@@ -2622,3 +2723,60 @@ void dcn32_zero_pipe_dcc_fraction(display_e2e_pipe_params_st *pipes,
pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_luma = 0;
pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_chroma = 0;
}
+
+bool dcn32_allow_subvp_with_active_margin(struct pipe_ctx *pipe)
+{
+ bool allow = false;
+ uint32_t refresh_rate = 0;
+
+ /* Allow subvp on displays that have active margin for 2560x1440@60hz displays
+ * only for now. There must be no scaling as well.
+ *
+ * For now we only enable on 2560x1440@60hz displays to enable 4K60 + 1440p60 configs
+ * for p-state switching.
+ */
+ if (pipe->stream && pipe->plane_state) {
+ refresh_rate = (pipe->stream->timing.pix_clk_100hz * 100 +
+ pipe->stream->timing.v_total * pipe->stream->timing.h_total - 1)
+ / (double)(pipe->stream->timing.v_total * pipe->stream->timing.h_total);
+ if (pipe->stream->timing.v_addressable == 1440 &&
+ pipe->stream->timing.h_addressable == 2560 &&
+ refresh_rate >= 55 && refresh_rate <= 65 &&
+ pipe->plane_state->src_rect.height == 1440 &&
+ pipe->plane_state->src_rect.width == 2560 &&
+ pipe->plane_state->dst_rect.height == 1440 &&
+ pipe->plane_state->dst_rect.width == 2560)
+ allow = true;
+ }
+ return allow;
+}
+
+/**
+ * *******************************************************************************************
+ * dcn32_determine_max_vratio_prefetch: Determine max Vratio for prefetch by driver policy
+ *
+ * @param [in]: dc: Current DC state
+ * @param [in]: context: New DC state to be programmed
+ *
+ * @return: Max vratio for prefetch
+ *
+ * *******************************************************************************************
+ */
+double dcn32_determine_max_vratio_prefetch(struct dc *dc, struct dc_state *context)
+{
+ double max_vratio_pre = __DML_MAX_BW_RATIO_PRE__; // Default value is 4
+ int i;
+
+ /* For single display MPO configs, allow the max vratio to be 8
+ * if any plane is YUV420 format
+ */
+ if (context->stream_count == 1 && context->stream_status[0].plane_count > 1) {
+ for (i = 0; i < context->stream_status[0].plane_count; i++) {
+ if (context->stream_status[0].plane_states[i]->format == SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr ||
+ context->stream_status[0].plane_states[i]->format == SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb) {
+ max_vratio_pre = __DML_MAX_VRATIO_PRE__;
+ }
+ }
+ }
+ return max_vratio_pre;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c
index 4b8f5fa0f0ad..3b2a014ccf8f 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c
@@ -387,6 +387,7 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman
mode_lib->vba.NumberOfActiveSurfaces,
mode_lib->vba.MALLAllocatedForDCNFinal,
mode_lib->vba.UseMALLForStaticScreen,
+ mode_lib->vba.UsesMALLForPStateChange,
mode_lib->vba.DCCEnable,
mode_lib->vba.ViewportStationary,
mode_lib->vba.ViewportXStartY,
@@ -411,6 +412,8 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman
v->BlockWidthC,
v->BlockHeightY,
v->BlockHeightC,
+ mode_lib->vba.DCCMetaPitchY,
+ mode_lib->vba.DCCMetaPitchC,
/* Output */
v->SurfaceSizeInMALL,
@@ -893,8 +896,8 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman
if (v->DestinationLinesForPrefetch[k] < 2)
DestinationLineTimesForPrefetchLessThan2 = true;
- if (v->VRatioPrefetchY[k] > __DML_MAX_VRATIO_PRE__
- || v->VRatioPrefetchC[k] > __DML_MAX_VRATIO_PRE__)
+ if (v->VRatioPrefetchY[k] > v->MaxVRatioPre
+ || v->VRatioPrefetchC[k] > v->MaxVRatioPre)
VRatioPrefetchMoreThanMax = true;
//bool DestinationLinesToRequestVMInVBlankEqualOrMoreThan32 = false;
@@ -939,6 +942,9 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman
v->UrgBurstFactorLumaPre,
v->UrgBurstFactorChromaPre,
v->UrgBurstFactorCursorPre,
+ v->PrefetchBandwidth,
+ v->VRatio,
+ v->MaxVRatioPre,
/* output */
&MaxTotalRDBandwidth,
@@ -969,6 +975,9 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman
v->dummy_vars.DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation.dummy_unit_vector,
v->dummy_vars.DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation.dummy_unit_vector,
v->dummy_vars.DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation.dummy_unit_vector,
+ v->PrefetchBandwidth,
+ v->VRatio,
+ v->MaxVRatioPre,
/* output */
&v->dummy_vars.DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation.dummy_single[0],
@@ -1636,9 +1645,14 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman
static void mode_support_configuration(struct vba_vars_st *v,
struct display_mode_lib *mode_lib)
{
- int i, j;
+ int i, j, start_state;
+
+ if (mode_lib->validate_max_state)
+ start_state = v->soc.num_states - 1;
+ else
+ start_state = 0;
- for (i = v->soc.num_states - 1; i >= 0; i--) {
+ for (i = v->soc.num_states - 1; i >= start_state; i--) {
for (j = 0; j < 2; j++) {
if (mode_lib->vba.ScaleRatioAndTapsSupport == true
&& mode_lib->vba.SourceFormatPixelAndScanSupport == true
@@ -1707,7 +1721,7 @@ static void mode_support_configuration(struct vba_vars_st *v,
void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_lib)
{
struct vba_vars_st *v = &mode_lib->vba;
- int i, j;
+ int i, j, start_state;
unsigned int k, m;
unsigned int MaximumMPCCombine;
unsigned int NumberOfNonCombinedSurfaceOfMaximumBandwidth;
@@ -1720,6 +1734,10 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
#endif
/*MODE SUPPORT, VOLTAGE STATE AND SOC CONFIGURATION*/
+ if (mode_lib->validate_max_state)
+ start_state = v->soc.num_states - 1;
+ else
+ start_state = 0;
/*Scale Ratio, taps Support Check*/
@@ -2009,7 +2027,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
mode_lib->vba.MPCCombineMethodIncompatible = v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.MPCCombineMethodAsNeededForPStateChangeAndVoltage
&& v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.MPCCombineMethodAsPossible;
- for (i = 0; i < v->soc.num_states; i++) {
+ for (i = start_state; i < v->soc.num_states; i++) {
for (j = 0; j < 2; j++) {
mode_lib->vba.TotalNumberOfActiveDPP[i][j] = 0;
mode_lib->vba.TotalAvailablePipesSupport[i][j] = true;
@@ -2286,7 +2304,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
}
}
- for (i = 0; i < v->soc.num_states; ++i) {
+ for (i = start_state; i < v->soc.num_states; ++i) {
mode_lib->vba.ExceededMultistreamSlots[i] = false;
for (k = 0; k < mode_lib->vba.NumberOfActiveSurfaces; ++k) {
if (mode_lib->vba.OutputMultistreamEn[k] == true && mode_lib->vba.OutputMultistreamId[k] == k) {
@@ -2335,8 +2353,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
if (mode_lib->vba.DSCEnable[k] && mode_lib->vba.ForcedOutputLinkBPP[k] != 0)
mode_lib->vba.DSCOnlyIfNecessaryWithBPP = true;
- if ((mode_lib->vba.DSCEnable[k] || mode_lib->vba.DSCEnable[k])
- && mode_lib->vba.OutputFormat[k] == dm_n422
+ if (mode_lib->vba.DSCEnable[k] && mode_lib->vba.OutputFormat[k] == dm_n422
&& !mode_lib->vba.DSC422NativeSupport)
mode_lib->vba.DSC422NativeNotSupported = true;
@@ -2386,7 +2403,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
}
}
- for (i = 0; i < v->soc.num_states; ++i) {
+ for (i = start_state; i < v->soc.num_states; ++i) {
mode_lib->vba.DTBCLKRequiredMoreThanSupported[i] = false;
for (k = 0; k < mode_lib->vba.NumberOfActiveSurfaces; ++k) {
if (mode_lib->vba.BlendingAndTiming[k] == k
@@ -2403,7 +2420,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
}
}
- for (i = 0; i < v->soc.num_states; ++i) {
+ for (i = start_state; i < v->soc.num_states; ++i) {
mode_lib->vba.ODMCombine2To1SupportCheckOK[i] = true;
mode_lib->vba.ODMCombine4To1SupportCheckOK[i] = true;
for (k = 0; k < mode_lib->vba.NumberOfActiveSurfaces; ++k) {
@@ -2421,7 +2438,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
}
}
- for (i = 0; i < v->soc.num_states; i++) {
+ for (i = start_state; i < v->soc.num_states; i++) {
mode_lib->vba.DSCCLKRequiredMoreThanSupported[i] = false;
for (k = 0; k <= mode_lib->vba.NumberOfActiveSurfaces - 1; k++) {
if (mode_lib->vba.BlendingAndTiming[k] == k) {
@@ -2458,7 +2475,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
/* Check DSC Unit and Slices Support */
v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.TotalDSCUnitsRequired = 0;
- for (i = 0; i < v->soc.num_states; ++i) {
+ for (i = start_state; i < v->soc.num_states; ++i) {
mode_lib->vba.NotEnoughDSCUnits[i] = false;
mode_lib->vba.NotEnoughDSCSlices[i] = false;
v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.TotalDSCUnitsRequired = 0;
@@ -2493,7 +2510,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
}
/*DSC Delay per state*/
- for (i = 0; i < v->soc.num_states; ++i) {
+ for (i = start_state; i < v->soc.num_states; ++i) {
for (k = 0; k < mode_lib->vba.NumberOfActiveSurfaces; ++k) {
mode_lib->vba.DSCDelayPerState[i][k] = dml32_DSCDelayRequirement(
mode_lib->vba.RequiresDSC[i][k], mode_lib->vba.ODMCombineEnablePerState[i][k],
@@ -2520,7 +2537,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
//Calculate Swath, DET Configuration, DCFCLKDeepSleep
//
- for (i = 0; i < (int) v->soc.num_states; ++i) {
+ for (i = start_state; i < (int) v->soc.num_states; ++i) {
for (j = 0; j <= 1; ++j) {
for (k = 0; k < mode_lib->vba.NumberOfActiveSurfaces; ++k) {
mode_lib->vba.RequiredDPPCLKThisState[k] = mode_lib->vba.RequiredDPPCLK[i][j][k];
@@ -2626,6 +2643,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
mode_lib->vba.NumberOfActiveSurfaces,
mode_lib->vba.MALLAllocatedForDCNFinal,
mode_lib->vba.UseMALLForStaticScreen,
+ mode_lib->vba.UsesMALLForPStateChange,
mode_lib->vba.DCCEnable,
mode_lib->vba.ViewportStationary,
mode_lib->vba.ViewportXStartY,
@@ -2650,12 +2668,14 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
mode_lib->vba.MacroTileWidthC,
mode_lib->vba.MacroTileHeightY,
mode_lib->vba.MacroTileHeightC,
+ mode_lib->vba.DCCMetaPitchY,
+ mode_lib->vba.DCCMetaPitchC,
/* Output */
mode_lib->vba.SurfaceSizeInMALL,
&mode_lib->vba.ExceededMALLSize);
- for (i = 0; i < v->soc.num_states; i++) {
+ for (i = start_state; i < v->soc.num_states; i++) {
for (j = 0; j < 2; j++) {
for (k = 0; k <= mode_lib->vba.NumberOfActiveSurfaces - 1; k++) {
mode_lib->vba.swath_width_luma_ub_this_state[k] =
@@ -2882,7 +2902,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
}
//Calculate Return BW
- for (i = 0; i < (int) v->soc.num_states; ++i) {
+ for (i = start_state; i < (int) v->soc.num_states; ++i) {
for (j = 0; j <= 1; ++j) {
for (k = 0; k <= mode_lib->vba.NumberOfActiveSurfaces - 1; k++) {
if (mode_lib->vba.BlendingAndTiming[k] == k) {
@@ -2961,7 +2981,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
&mode_lib->vba.MinPrefetchMode,
&mode_lib->vba.MaxPrefetchMode);
- for (i = 0; i < (int) v->soc.num_states; ++i) {
+ for (i = start_state; i < (int) v->soc.num_states; ++i) {
for (j = 0; j <= 1; ++j)
mode_lib->vba.DCFCLKState[i][j] = mode_lib->vba.DCFCLKPerState[i];
}
@@ -3083,7 +3103,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
mode_lib->vba.DCFCLKState);
} // UseMinimumRequiredDCFCLK == true
- for (i = 0; i < (int) v->soc.num_states; ++i) {
+ for (i = start_state; i < (int) v->soc.num_states; ++i) {
for (j = 0; j <= 1; ++j) {
mode_lib->vba.ReturnBWPerState[i][j] = dml32_get_return_bw_mbps(&mode_lib->vba.soc, i,
mode_lib->vba.HostVMEnable, mode_lib->vba.DCFCLKState[i][j],
@@ -3092,7 +3112,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
}
//Re-ordering Buffer Support Check
- for (i = 0; i < (int) v->soc.num_states; ++i) {
+ for (i = start_state; i < (int) v->soc.num_states; ++i) {
for (j = 0; j <= 1; ++j) {
if ((mode_lib->vba.ROBBufferSizeInKByte - mode_lib->vba.PixelChunkSizeInKByte) * 1024
/ mode_lib->vba.ReturnBWPerState[i][j]
@@ -3114,7 +3134,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
+ mode_lib->vba.ReadBandwidthChroma[k];
}
- for (i = 0; i < (int) v->soc.num_states; ++i) {
+ for (i = start_state; i < (int) v->soc.num_states; ++i) {
for (j = 0; j <= 1; ++j) {
mode_lib->vba.MaxTotalVerticalActiveAvailableBandwidth[i][j] =
dml_min3(mode_lib->vba.ReturnBusWidth * mode_lib->vba.DCFCLKState[i][j]
@@ -3138,7 +3158,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
/* Prefetch Check */
- for (i = 0; i < (int) v->soc.num_states; ++i) {
+ for (i = start_state; i < (int) v->soc.num_states; ++i) {
for (j = 0; j <= 1; ++j) {
mode_lib->vba.TimeCalc = 24 / mode_lib->vba.ProjectedDCFCLKDeepSleep[i][j];
@@ -3358,6 +3378,9 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
mode_lib->vba.UrgentBurstFactorLumaPre,
mode_lib->vba.UrgentBurstFactorChromaPre,
mode_lib->vba.UrgentBurstFactorCursorPre,
+ v->PrefetchBW,
+ v->VRatio,
+ v->MaxVRatioPre,
/* output */
&v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.dummy_single[0], // Single *PrefetchBandwidth
@@ -3382,8 +3405,8 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
mode_lib->vba.VRatioInPrefetchSupported[i][j] = true;
for (k = 0; k <= mode_lib->vba.NumberOfActiveSurfaces - 1; k++) {
- if (mode_lib->vba.VRatioPreY[i][j][k] > __DML_MAX_VRATIO_PRE__
- || mode_lib->vba.VRatioPreC[i][j][k] > __DML_MAX_VRATIO_PRE__
+ if (mode_lib->vba.VRatioPreY[i][j][k] > mode_lib->vba.MaxVRatioPre
+ || mode_lib->vba.VRatioPreC[i][j][k] > mode_lib->vba.MaxVRatioPre
|| mode_lib->vba.NoTimeForPrefetch[i][j][k] == true) {
mode_lib->vba.VRatioInPrefetchSupported[i][j] = false;
}
@@ -3639,7 +3662,6 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
if (mode_lib->vba.SourcePixelFormat[k] != dm_444_64
&& mode_lib->vba.SourcePixelFormat[k] != dm_444_32
&& mode_lib->vba.SourcePixelFormat[k] != dm_444_16
- && mode_lib->vba.SourcePixelFormat[k] != dm_444_16
&& mode_lib->vba.SourcePixelFormat[k] != dm_444_8
&& mode_lib->vba.SourcePixelFormat[k] != dm_rgbe) {
if (mode_lib->vba.ViewportWidthChroma[k] > mode_lib->vba.SurfaceWidthC[k]
@@ -3656,7 +3678,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
MaximumMPCCombine = 0;
- for (i = v->soc.num_states; i >= 0; i--) {
+ for (i = v->soc.num_states; i >= start_state; i--) {
if (i == v->soc.num_states || mode_lib->vba.ModeSupport[i][0] == true ||
mode_lib->vba.ModeSupport[i][1] == true) {
mode_lib->vba.VoltageLevel = i;
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.h b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.h
index c8b28c83ddf4..500b3dd6052d 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.h
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.h
@@ -44,7 +44,8 @@
#define __DML_MIN_DCFCLK_FACTOR__ 1.15
// Prefetch schedule max vratio
-#define __DML_MAX_VRATIO_PRE__ 4.0
+#define __DML_MAX_VRATIO_PRE__ 7.9
+#define __DML_MAX_BW_RATIO_PRE__ 4.0
#define __DML_VBA_MAX_DST_Y_PRE__ 63.75
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c
index b53feeaf5cf1..d1000aa4c481 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c
@@ -1772,6 +1772,7 @@ void dml32_CalculateSurfaceSizeInMall(
unsigned int NumberOfActiveSurfaces,
unsigned int MALLAllocatedForDCN,
enum dm_use_mall_for_static_screen_mode UseMALLForStaticScreen[],
+ enum dm_use_mall_for_pstate_change_mode UsesMALLForPStateChange[],
bool DCCEnable[],
bool ViewportStationary[],
unsigned int ViewportXStartY[],
@@ -1796,13 +1797,17 @@ void dml32_CalculateSurfaceSizeInMall(
unsigned int ReadBlockWidthC[],
unsigned int ReadBlockHeightY[],
unsigned int ReadBlockHeightC[],
+ unsigned int DCCMetaPitchY[],
+ unsigned int DCCMetaPitchC[],
/* Output */
unsigned int SurfaceSizeInMALL[],
bool *ExceededMALLSize)
{
- unsigned int TotalSurfaceSizeInMALL = 0;
unsigned int k;
+ unsigned int TotalSurfaceSizeInMALLForSS = 0;
+ unsigned int TotalSurfaceSizeInMALLForSubVP = 0;
+ unsigned int MALLAllocatedForDCNInBytes = MALLAllocatedForDCN * 1024 * 1024;
for (k = 0; k < NumberOfActiveSurfaces; ++k) {
if (ViewportStationary[k]) {
@@ -1828,18 +1833,18 @@ void dml32_CalculateSurfaceSizeInMall(
}
if (DCCEnable[k] == true) {
SurfaceSizeInMALL[k] = SurfaceSizeInMALL[k] +
- dml_min(dml_ceil(SurfaceWidthY[k], 8 * Read256BytesBlockWidthY[k]),
+ (dml_min(dml_ceil(DCCMetaPitchY[k], 8 * Read256BytesBlockWidthY[k]),
dml_floor(ViewportXStartY[k] + ViewportWidthY[k] + 8 *
Read256BytesBlockWidthY[k] - 1, 8 * Read256BytesBlockWidthY[k])
- dml_floor(ViewportXStartY[k], 8 * Read256BytesBlockWidthY[k]))
* dml_min(dml_ceil(SurfaceHeightY[k], 8 *
Read256BytesBlockHeightY[k]), dml_floor(ViewportYStartY[k] +
ViewportHeightY[k] + 8 * Read256BytesBlockHeightY[k] - 1, 8 *
- Read256BytesBlockHeightY[k]) - dml_floor(ViewportYStartY[k], 8
- * Read256BytesBlockHeightY[k])) * BytesPerPixelY[k] / 256;
+ Read256BytesBlockHeightY[k]) - dml_floor(ViewportYStartY[k], 8 *
+ Read256BytesBlockHeightY[k])) * BytesPerPixelY[k] / 256) + (64 * 1024);
if (Read256BytesBlockWidthC[k] > 0) {
SurfaceSizeInMALL[k] = SurfaceSizeInMALL[k] +
- dml_min(dml_ceil(SurfaceWidthC[k], 8 *
+ dml_min(dml_ceil(DCCMetaPitchC[k], 8 *
Read256BytesBlockWidthC[k]),
dml_floor(ViewportXStartC[k] + ViewportWidthC[k] + 8
* Read256BytesBlockWidthC[k] - 1, 8 *
@@ -1872,16 +1877,16 @@ void dml32_CalculateSurfaceSizeInMall(
}
if (DCCEnable[k] == true) {
SurfaceSizeInMALL[k] = SurfaceSizeInMALL[k] +
- dml_ceil(dml_min(SurfaceWidthY[k], ViewportWidthY[k] + 8 *
+ (dml_ceil(dml_min(DCCMetaPitchY[k], ViewportWidthY[k] + 8 *
Read256BytesBlockWidthY[k] - 1), 8 *
Read256BytesBlockWidthY[k]) *
dml_ceil(dml_min(SurfaceHeightY[k], ViewportHeightY[k] + 8 *
Read256BytesBlockHeightY[k] - 1), 8 *
- Read256BytesBlockHeightY[k]) * BytesPerPixelY[k] / 256;
+ Read256BytesBlockHeightY[k]) * BytesPerPixelY[k] / 256) + (64 * 1024);
if (Read256BytesBlockWidthC[k] > 0) {
SurfaceSizeInMALL[k] = SurfaceSizeInMALL[k] +
- dml_ceil(dml_min(SurfaceWidthC[k], ViewportWidthC[k] + 8 *
+ dml_ceil(dml_min(DCCMetaPitchC[k], ViewportWidthC[k] + 8 *
Read256BytesBlockWidthC[k] - 1), 8 *
Read256BytesBlockWidthC[k]) *
dml_ceil(dml_min(SurfaceHeightC[k], ViewportHeightC[k] + 8 *
@@ -1894,10 +1899,14 @@ void dml32_CalculateSurfaceSizeInMall(
}
for (k = 0; k < NumberOfActiveSurfaces; ++k) {
- if (UseMALLForStaticScreen[k] == dm_use_mall_static_screen_enable)
- TotalSurfaceSizeInMALL = TotalSurfaceSizeInMALL + SurfaceSizeInMALL[k];
+ /* SS and Subvp counted separate as they are never used at the same time */
+ if (UsesMALLForPStateChange[k] == dm_use_mall_pstate_change_phantom_pipe)
+ TotalSurfaceSizeInMALLForSubVP = TotalSurfaceSizeInMALLForSubVP + SurfaceSizeInMALL[k];
+ else if (UseMALLForStaticScreen[k] == dm_use_mall_static_screen_enable)
+ TotalSurfaceSizeInMALLForSS = TotalSurfaceSizeInMALLForSS + SurfaceSizeInMALL[k];
}
- *ExceededMALLSize = (TotalSurfaceSizeInMALL > MALLAllocatedForDCN * 1024 * 1024);
+ *ExceededMALLSize = (TotalSurfaceSizeInMALLForSS > MALLAllocatedForDCNInBytes) ||
+ (TotalSurfaceSizeInMALLForSubVP > MALLAllocatedForDCNInBytes);
} // CalculateSurfaceSizeInMall
void dml32_CalculateVMRowAndSwath(
@@ -3471,7 +3480,7 @@ bool dml32_CalculatePrefetchSchedule(
double prefetch_sw_bytes;
double bytes_pp;
double dep_bytes;
- unsigned int max_vratio_pre = __DML_MAX_VRATIO_PRE__;
+ unsigned int max_vratio_pre = v->MaxVRatioPre;
double min_Lsw;
double Tsw_est1 = 0;
double Tsw_est3 = 0;
@@ -6134,29 +6143,46 @@ void dml32_CalculatePrefetchBandwithSupport(unsigned int NumberOfActiveSurfaces,
double UrgentBurstFactorLumaPre[],
double UrgentBurstFactorChromaPre[],
double UrgentBurstFactorCursorPre[],
+ double PrefetchBW[],
+ double VRatio[],
+ double MaxVRatioPre,
/* output */
- double *PrefetchBandwidth,
+ double *MaxPrefetchBandwidth,
double *FractionOfUrgentBandwidth,
bool *PrefetchBandwidthSupport)
{
unsigned int k;
+ double ActiveBandwidthPerSurface;
bool NotEnoughUrgentLatencyHiding = false;
+ double TotalActiveBandwidth = 0;
+ double TotalPrefetchBandwidth = 0;
+
for (k = 0; k < NumberOfActiveSurfaces; ++k) {
if (NotUrgentLatencyHiding[k]) {
NotEnoughUrgentLatencyHiding = true;
}
}
- *PrefetchBandwidth = 0;
+ *MaxPrefetchBandwidth = 0;
for (k = 0; k < NumberOfActiveSurfaces; ++k) {
- *PrefetchBandwidth = *PrefetchBandwidth + dml_max3(NumberOfDPP[k] * prefetch_vmrow_bw[k],
- ReadBandwidthLuma[k] * UrgentBurstFactorLuma[k] + ReadBandwidthChroma[k] * UrgentBurstFactorChroma[k] + cursor_bw[k] * UrgentBurstFactorCursor[k] + NumberOfDPP[k] * (meta_row_bandwidth[k] + dpte_row_bandwidth[k]),
+ ActiveBandwidthPerSurface = ReadBandwidthLuma[k] * UrgentBurstFactorLuma[k] + ReadBandwidthChroma[k] * UrgentBurstFactorChroma[k] + cursor_bw[k] * UrgentBurstFactorCursor[k] + NumberOfDPP[k] * (meta_row_bandwidth[k] + dpte_row_bandwidth[k]);
+
+ TotalActiveBandwidth += ActiveBandwidthPerSurface;
+
+ TotalPrefetchBandwidth = TotalPrefetchBandwidth + PrefetchBW[k] * VRatio[k];
+
+ *MaxPrefetchBandwidth = *MaxPrefetchBandwidth + dml_max3(NumberOfDPP[k] * prefetch_vmrow_bw[k],
+ ActiveBandwidthPerSurface,
NumberOfDPP[k] * (PrefetchBandwidthLuma[k] * UrgentBurstFactorLumaPre[k] + PrefetchBandwidthChroma[k] * UrgentBurstFactorChromaPre[k]) + cursor_bw_pre[k] * UrgentBurstFactorCursorPre[k]);
}
- *PrefetchBandwidthSupport = (*PrefetchBandwidth <= ReturnBW) && !NotEnoughUrgentLatencyHiding;
- *FractionOfUrgentBandwidth = *PrefetchBandwidth / ReturnBW;
+ if (MaxVRatioPre == __DML_MAX_VRATIO_PRE__)
+ *PrefetchBandwidthSupport = (*MaxPrefetchBandwidth <= ReturnBW) && (TotalPrefetchBandwidth <= TotalActiveBandwidth * __DML_MAX_BW_RATIO_PRE__) && !NotEnoughUrgentLatencyHiding;
+ else
+ *PrefetchBandwidthSupport = (*MaxPrefetchBandwidth <= ReturnBW) && !NotEnoughUrgentLatencyHiding;
+
+ *FractionOfUrgentBandwidth = *MaxPrefetchBandwidth / ReturnBW;
}
double dml32_CalculateBandwidthAvailableForImmediateFlip(unsigned int NumberOfActiveSurfaces,
@@ -6245,7 +6271,7 @@ bool dml32_CalculateDETSwathFillLatencyHiding(unsigned int NumberOfActiveSurface
double PixelClock[],
double VRatioY[],
double VRatioC[],
- enum dm_use_mall_for_pstate_change_mode UsesMALLForPStateChange[DC__NUM_DPP__MAX])
+ enum dm_use_mall_for_pstate_change_mode UsesMALLForPStateChange[])
{
int k;
double SwathSizeAllSurfaces = 0;
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.h b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.h
index 779c6805f599..9ba792c633a5 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.h
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.h
@@ -334,6 +334,7 @@ void dml32_CalculateSurfaceSizeInMall(
unsigned int NumberOfActiveSurfaces,
unsigned int MALLAllocatedForDCN,
enum dm_use_mall_for_static_screen_mode UseMALLForStaticScreen[],
+ enum dm_use_mall_for_pstate_change_mode UsesMALLForPStateChange[],
bool DCCEnable[],
bool ViewportStationary[],
unsigned int ViewportXStartY[],
@@ -358,6 +359,8 @@ void dml32_CalculateSurfaceSizeInMall(
unsigned int ReadBlockWidthC[],
unsigned int ReadBlockHeightY[],
unsigned int ReadBlockHeightC[],
+ unsigned int DCCMetaPitchY[],
+ unsigned int DCCMetaPitchC[],
/* Output */
unsigned int SurfaceSizeInMALL[],
@@ -1093,9 +1096,12 @@ void dml32_CalculatePrefetchBandwithSupport(unsigned int NumberOfActiveSurfaces,
double UrgentBurstFactorLumaPre[],
double UrgentBurstFactorChromaPre[],
double UrgentBurstFactorCursorPre[],
+ double PrefetchBW[],
+ double VRatio[],
+ double MaxVRatioPre,
/* output */
- double *PrefetchBandwidth,
+ double *MaxPrefetchBandwidth,
double *FractionOfUrgentBandwidth,
bool *PrefetchBandwidthSupport);
@@ -1157,6 +1163,6 @@ bool dml32_CalculateDETSwathFillLatencyHiding(unsigned int NumberOfActiveSurface
double PixelClock[],
double VRatioY[],
double VRatioC[],
- enum dm_use_mall_for_pstate_change_mode UsesMALLForPStateChange[DC__NUM_DPP__MAX]);
+ enum dm_use_mall_for_pstate_change_mode UsesMALLForPStateChange[]);
#endif
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c
index f4b176599be7..b80cef70fa60 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c
@@ -136,7 +136,7 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_21_soc = {
.urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096,
.urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096,
.urgent_out_of_order_return_per_channel_vm_only_bytes = 4096,
- .pct_ideal_sdp_bw_after_urgent = 100.0,
+ .pct_ideal_sdp_bw_after_urgent = 90.0,
.pct_ideal_fabric_bw_after_urgent = 67.0,
.pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 20.0,
.pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 60.0, // N/A, for now keep as is until DML implemented
@@ -534,8 +534,11 @@ void dcn321_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_p
}
/* Override from VBIOS for num_chan */
- if (dc->ctx->dc_bios->vram_info.num_chans)
+ if (dc->ctx->dc_bios->vram_info.num_chans) {
dcn3_21_soc.num_chans = dc->ctx->dc_bios->vram_info.num_chans;
+ dcn3_21_soc.mall_allocated_for_dcn_mbytes = (double)(dcn32_calc_num_avail_chans_for_mall(dc,
+ dc->ctx->dc_bios->vram_info.num_chans) * dc->caps.mall_size_per_mem_channel);
+ }
if (dc->ctx->dc_bios->vram_info.dram_channel_width_bytes)
dcn3_21_soc.dram_channel_width_bytes = dc->ctx->dc_bios->vram_info.dram_channel_width_bytes;
diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h
index 3d643d50c3eb..a9d49ef58fb5 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h
+++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h
@@ -91,6 +91,7 @@ struct display_mode_lib {
struct dal_logger *logger;
struct dml_funcs funcs;
struct _vcs_dpi_display_e2e_pipe_params_st dml_pipe_state[6];
+ bool validate_max_state;
};
void dml_init_instance(struct display_mode_lib *lib,
diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h
index 64d602e6412f..3c077164f362 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h
+++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h
@@ -246,6 +246,7 @@ struct _vcs_dpi_soc_bounding_box_st {
bool disable_dram_clock_change_vactive_support;
bool allow_dram_clock_one_display_vactive;
enum self_refresh_affinity allow_dram_self_refresh_or_dram_clock_change_in_vblank;
+ double max_vratio_pre;
};
/**
diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c
index 8e6585dab20e..f9653f511baa 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c
@@ -202,6 +202,7 @@ dml_get_pipe_attr_func(vm_group_size_in_bytes, mode_lib->vba.vm_group_bytes);
dml_get_pipe_attr_func(dpte_row_height_linear_l, mode_lib->vba.dpte_row_height_linear);
dml_get_pipe_attr_func(pte_buffer_mode, mode_lib->vba.PTE_BUFFER_MODE);
dml_get_pipe_attr_func(subviewport_lines_needed_in_mall, mode_lib->vba.SubViewportLinesNeededInMALL);
+dml_get_pipe_attr_func(surface_size_in_mall, mode_lib->vba.SurfaceSizeInMALL)
double get_total_immediate_flip_bytes(
struct display_mode_lib *mode_lib,
@@ -411,6 +412,7 @@ static void fetch_socbb_params(struct display_mode_lib *mode_lib)
soc->urgent_latency_adjustment_fabric_clock_component_us;
mode_lib->vba.UrgentLatencyAdjustmentFabricClockReference =
soc->urgent_latency_adjustment_fabric_clock_reference_mhz;
+ mode_lib->vba.MaxVRatioPre = soc->max_vratio_pre;
}
static void fetch_ip_params(struct display_mode_lib *mode_lib)
diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h
index 81e53e67cd0b..07993741f5e6 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h
+++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h
@@ -143,6 +143,7 @@ dml_get_pipe_attr_decl(vready_at_or_after_vsync);
dml_get_pipe_attr_decl(min_dst_y_next_start);
dml_get_pipe_attr_decl(vstartup_calculated);
dml_get_pipe_attr_decl(subviewport_lines_needed_in_mall);
+dml_get_pipe_attr_decl(surface_size_in_mall);
double get_total_immediate_flip_bytes(
struct display_mode_lib *mode_lib,
@@ -262,6 +263,7 @@ struct vba_vars_st {
int maxMpcComb;
bool UseMaximumVStartup;
+ double MaxVRatioPre;
double WritebackDISPCLK;
double DPPCLKUsingSingleDPPLuma;
double DPPCLKUsingSingleDPPChroma;
diff --git a/drivers/gpu/drm/amd/display/dc/dsc/dscc_types.h b/drivers/gpu/drm/amd/display/dc/dsc/dscc_types.h
index ad80bde9bc0f..31574940ccc7 100644
--- a/drivers/gpu/drm/amd/display/dc/dsc/dscc_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dsc/dscc_types.h
@@ -46,7 +46,10 @@ struct dsc_parameters {
uint32_t rc_buffer_model_size;
};
-int dscc_compute_dsc_parameters(const struct drm_dsc_config *pps, struct dsc_parameters *dsc_params);
+struct rc_params;
+int dscc_compute_dsc_parameters(const struct drm_dsc_config *pps,
+ const struct rc_params *rc,
+ struct dsc_parameters *dsc_params);
#endif
diff --git a/drivers/gpu/drm/amd/display/dc/dsc/rc_calc_dpi.c b/drivers/gpu/drm/amd/display/dc/dsc/rc_calc_dpi.c
index f0aea988fef0..36d6c1646a51 100644
--- a/drivers/gpu/drm/amd/display/dc/dsc/rc_calc_dpi.c
+++ b/drivers/gpu/drm/amd/display/dc/dsc/rc_calc_dpi.c
@@ -95,19 +95,19 @@ static void copy_rc_to_cfg(struct drm_dsc_config *dsc_cfg, const struct rc_param
dsc_cfg->rc_buf_thresh[i] = rc->rc_buf_thresh[i];
}
-int dscc_compute_dsc_parameters(const struct drm_dsc_config *pps, struct dsc_parameters *dsc_params)
+int dscc_compute_dsc_parameters(const struct drm_dsc_config *pps,
+ const struct rc_params *rc,
+ struct dsc_parameters *dsc_params)
{
int ret;
- struct rc_params rc;
struct drm_dsc_config dsc_cfg;
unsigned long long tmp;
- calc_rc_params(&rc, pps);
dsc_params->pps = *pps;
- dsc_params->pps.initial_scale_value = 8 * rc.rc_model_size / (rc.rc_model_size - rc.initial_fullness_offset);
+ dsc_params->pps.initial_scale_value = 8 * rc->rc_model_size / (rc->rc_model_size - rc->initial_fullness_offset);
copy_pps_fields(&dsc_cfg, &dsc_params->pps);
- copy_rc_to_cfg(&dsc_cfg, &rc);
+ copy_rc_to_cfg(&dsc_cfg, rc);
dsc_cfg.mux_word_size = dsc_params->pps.bits_per_component <= 10 ? 48 : 64;
diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_factory_dcn20.c b/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_factory_dcn20.c
index 9b63c6c0cc84..e0bd0c722e00 100644
--- a/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_factory_dcn20.c
+++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_factory_dcn20.c
@@ -138,7 +138,8 @@ static const struct ddc_sh_mask ddc_shift[] = {
DDC_MASK_SH_LIST_DCN2(__SHIFT, 3),
DDC_MASK_SH_LIST_DCN2(__SHIFT, 4),
DDC_MASK_SH_LIST_DCN2(__SHIFT, 5),
- DDC_MASK_SH_LIST_DCN2(__SHIFT, 6)
+ DDC_MASK_SH_LIST_DCN2(__SHIFT, 6),
+ DDC_MASK_SH_LIST_DCN2_VGA(__SHIFT)
};
static const struct ddc_sh_mask ddc_mask[] = {
@@ -147,7 +148,8 @@ static const struct ddc_sh_mask ddc_mask[] = {
DDC_MASK_SH_LIST_DCN2(_MASK, 3),
DDC_MASK_SH_LIST_DCN2(_MASK, 4),
DDC_MASK_SH_LIST_DCN2(_MASK, 5),
- DDC_MASK_SH_LIST_DCN2(_MASK, 6)
+ DDC_MASK_SH_LIST_DCN2(_MASK, 6),
+ DDC_MASK_SH_LIST_DCN2_VGA(_MASK)
};
#include "../generic_regs.h"
diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn30/hw_factory_dcn30.c b/drivers/gpu/drm/amd/display/dc/gpio/dcn30/hw_factory_dcn30.c
index 687d4f128480..36a5736c58c9 100644
--- a/drivers/gpu/drm/amd/display/dc/gpio/dcn30/hw_factory_dcn30.c
+++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn30/hw_factory_dcn30.c
@@ -145,7 +145,8 @@ static const struct ddc_sh_mask ddc_shift[] = {
DDC_MASK_SH_LIST_DCN2(__SHIFT, 3),
DDC_MASK_SH_LIST_DCN2(__SHIFT, 4),
DDC_MASK_SH_LIST_DCN2(__SHIFT, 5),
- DDC_MASK_SH_LIST_DCN2(__SHIFT, 6)
+ DDC_MASK_SH_LIST_DCN2(__SHIFT, 6),
+ DDC_MASK_SH_LIST_DCN2_VGA(__SHIFT)
};
static const struct ddc_sh_mask ddc_mask[] = {
@@ -154,7 +155,8 @@ static const struct ddc_sh_mask ddc_mask[] = {
DDC_MASK_SH_LIST_DCN2(_MASK, 3),
DDC_MASK_SH_LIST_DCN2(_MASK, 4),
DDC_MASK_SH_LIST_DCN2(_MASK, 5),
- DDC_MASK_SH_LIST_DCN2(_MASK, 6)
+ DDC_MASK_SH_LIST_DCN2(_MASK, 6),
+ DDC_MASK_SH_LIST_DCN2_VGA(_MASK)
};
#include "../generic_regs.h"
diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn32/hw_factory_dcn32.c b/drivers/gpu/drm/amd/display/dc/gpio/dcn32/hw_factory_dcn32.c
index 9fd8b269dd79..985f10b39750 100644
--- a/drivers/gpu/drm/amd/display/dc/gpio/dcn32/hw_factory_dcn32.c
+++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn32/hw_factory_dcn32.c
@@ -149,7 +149,8 @@ static const struct ddc_sh_mask ddc_shift[] = {
DDC_MASK_SH_LIST_DCN2(__SHIFT, 3),
DDC_MASK_SH_LIST_DCN2(__SHIFT, 4),
DDC_MASK_SH_LIST_DCN2(__SHIFT, 5),
- DDC_MASK_SH_LIST_DCN2(__SHIFT, 6)
+ DDC_MASK_SH_LIST_DCN2(__SHIFT, 6),
+ DDC_MASK_SH_LIST_DCN2_VGA(__SHIFT)
};
static const struct ddc_sh_mask ddc_mask[] = {
@@ -158,7 +159,8 @@ static const struct ddc_sh_mask ddc_mask[] = {
DDC_MASK_SH_LIST_DCN2(_MASK, 3),
DDC_MASK_SH_LIST_DCN2(_MASK, 4),
DDC_MASK_SH_LIST_DCN2(_MASK, 5),
- DDC_MASK_SH_LIST_DCN2(_MASK, 6)
+ DDC_MASK_SH_LIST_DCN2(_MASK, 6),
+ DDC_MASK_SH_LIST_DCN2_VGA(_MASK)
};
#include "../generic_regs.h"
diff --git a/drivers/gpu/drm/amd/display/dc/gpio/ddc_regs.h b/drivers/gpu/drm/amd/display/dc/gpio/ddc_regs.h
index 308a543178a5..59884ef651b3 100644
--- a/drivers/gpu/drm/amd/display/dc/gpio/ddc_regs.h
+++ b/drivers/gpu/drm/amd/display/dc/gpio/ddc_regs.h
@@ -113,6 +113,13 @@
(PHY_AUX_CNTL__AUX## cd ##_PAD_RXSEL## mask_sh),\
(DC_GPIO_AUX_CTRL_5__DDC_PAD## cd ##_I2CMODE## mask_sh)}
+#define DDC_MASK_SH_LIST_DCN2_VGA(mask_sh) \
+ {DDC_MASK_SH_LIST_COMMON(mask_sh),\
+ 0,\
+ 0,\
+ 0,\
+ 0}
+
struct ddc_registers {
struct gpio_registers gpio;
uint32_t ddc_setup;
diff --git a/drivers/gpu/drm/amd/display/dc/hdcp/hdcp_msg.c b/drivers/gpu/drm/amd/display/dc/hdcp/hdcp_msg.c
index 4233955e3c47..e1422e5e86c9 100644
--- a/drivers/gpu/drm/amd/display/dc/hdcp/hdcp_msg.c
+++ b/drivers/gpu/drm/amd/display/dc/hdcp/hdcp_msg.c
@@ -28,12 +28,11 @@
#include "dm_services.h"
#include "dm_helpers.h"
#include "include/hdcp_types.h"
-#include "include/i2caux_interface.h"
#include "include/signal_types.h"
#include "core_types.h"
-#include "dc_link_ddc.h"
+#include "link.h"
#include "link_hwss.h"
-#include "inc/link_dpcd.h"
+#include "link/protocols/link_dpcd.h"
#define DC_LOGGER \
link->ctx->logger
diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h
index 525f8f0b8732..ed3c03108da6 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h
@@ -56,33 +56,6 @@ void enable_surface_flip_reporting(struct dc_plane_state *plane_state,
#endif
#include "link_hwss.h"
-/************ link *****************/
-struct link_init_data {
- const struct dc *dc;
- struct dc_context *ctx; /* TODO: remove 'dal' when DC is complete. */
- uint32_t connector_index; /* this will be mapped to the HPD pins */
- uint32_t link_index; /* this is mapped to DAL display_index
- TODO: remove it when DC is complete. */
- bool is_dpia_link;
-};
-
-struct dc_link *link_create(const struct link_init_data *init_params);
-void link_destroy(struct dc_link **link);
-
-enum dc_status dc_link_validate_mode_timing(
- const struct dc_stream_state *stream,
- struct dc_link *link,
- const struct dc_crtc_timing *timing);
-
-void core_link_resume(struct dc_link *link);
-
-void core_link_enable_stream(
- struct dc_state *state,
- struct pipe_ctx *pipe_ctx);
-
-void core_link_disable_stream(struct pipe_ctx *pipe_ctx);
-
-void core_link_set_avmute(struct pipe_ctx *pipe_ctx, bool enable);
/********** DAL Core*********************/
#include "transform.h"
#include "dpp.h"
@@ -450,10 +423,11 @@ struct pipe_ctx {
struct _vcs_dpi_display_e2e_pipe_params_st dml_input;
int det_buffer_size_kb;
bool unbounded_req;
+ unsigned int surface_size_in_mall_bytes;
- union pipe_update_flags update_flags;
struct dwbc *dwbc;
struct mcif_wb *mcif_wb;
+ union pipe_update_flags update_flags;
};
/* Data used for dynamic link encoder assignment.
@@ -507,6 +481,9 @@ struct dcn_bw_output {
struct dcn_watermark_set watermarks;
struct dcn_bw_writeback bw_writeback;
int compbuf_size_kb;
+ unsigned int mall_ss_size_bytes;
+ unsigned int mall_ss_psr_active_size_bytes;
+ unsigned int mall_subvp_size_bytes;
unsigned int legacy_svp_drr_stream_index;
bool legacy_svp_drr_stream_index_valid;
};
@@ -547,15 +524,6 @@ struct dc_state {
struct resource_context res_ctx;
/**
- * @bw_ctx: The output from bandwidth and watermark calculations and the DML
- *
- * Each context must have its own instance of VBA, and in order to
- * initialize and obtain IP and SOC, the base DML instance from DC is
- * initially copied into every context.
- */
- struct bw_context bw_ctx;
-
- /**
* @pp_display_cfg: PowerPlay clocks and settings
* Note: this is a big struct, do *not* put on stack!
*/
@@ -570,6 +538,15 @@ struct dc_state {
struct clk_mgr *clk_mgr;
/**
+ * @bw_ctx: The output from bandwidth and watermark calculations and the DML
+ *
+ * Each context must have its own instance of VBA, and in order to
+ * initialize and obtain IP and SOC, the base DML instance from DC is
+ * initially copied into every context.
+ */
+ struct bw_context bw_ctx;
+
+ /**
* @refcount: refcount reference
*
* Notice that dc_state is used around the code to capture the current
diff --git a/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h b/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h
deleted file mode 100644
index 95fb61d62778..000000000000
--- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright 2012-15 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
- *
- * Authors: AMD
- *
- */
-
-#ifndef __DAL_DDC_SERVICE_H__
-#define __DAL_DDC_SERVICE_H__
-
-#include "include/ddc_service_types.h"
-#include "include/i2caux_interface.h"
-
-#define EDID_SEGMENT_SIZE 256
-
-/* Address range from 0x00 to 0x1F.*/
-#define DP_ADAPTOR_TYPE2_SIZE 0x20
-#define DP_ADAPTOR_TYPE2_REG_ID 0x10
-#define DP_ADAPTOR_TYPE2_REG_MAX_TMDS_CLK 0x1D
-/* Identifies adaptor as Dual-mode adaptor */
-#define DP_ADAPTOR_TYPE2_ID 0xA0
-/* MHz*/
-#define DP_ADAPTOR_TYPE2_MAX_TMDS_CLK 600
-/* MHz*/
-#define DP_ADAPTOR_TYPE2_MIN_TMDS_CLK 25
-/* kHZ*/
-#define DP_ADAPTOR_DVI_MAX_TMDS_CLK 165000
-/* kHZ*/
-#define DP_ADAPTOR_HDMI_SAFE_MAX_TMDS_CLK 165000
-
-#define DDC_I2C_COMMAND_ENGINE I2C_COMMAND_ENGINE_SW
-
-struct ddc_service;
-struct graphics_object_id;
-enum ddc_result;
-struct av_sync_data;
-struct dp_receiver_id_info;
-
-struct i2c_payloads;
-struct aux_payloads;
-enum aux_return_code_type;
-
-void dal_ddc_i2c_payloads_add(
- struct i2c_payloads *payloads,
- uint32_t address,
- uint32_t len,
- uint8_t *data,
- bool write);
-
-struct ddc_service_init_data {
- struct graphics_object_id id;
- struct dc_context *ctx;
- struct dc_link *link;
- bool is_dpia_link;
-};
-
-struct ddc_service *dal_ddc_service_create(
- struct ddc_service_init_data *ddc_init_data);
-
-void dal_ddc_service_destroy(struct ddc_service **ddc);
-
-enum ddc_service_type dal_ddc_service_get_type(struct ddc_service *ddc);
-
-void dal_ddc_service_set_transaction_type(
- struct ddc_service *ddc,
- enum ddc_transaction_type type);
-
-bool dal_ddc_service_is_in_aux_transaction_mode(struct ddc_service *ddc);
-
-void dal_ddc_service_i2c_query_dp_dual_mode_adaptor(
- struct ddc_service *ddc,
- struct display_sink_capability *sink_cap);
-
-bool dal_ddc_service_query_ddc_data(
- struct ddc_service *ddc,
- uint32_t address,
- uint8_t *write_buf,
- uint32_t write_size,
- uint8_t *read_buf,
- uint32_t read_size);
-
-bool dal_ddc_submit_aux_command(struct ddc_service *ddc,
- struct aux_payload *payload);
-
-int dc_link_aux_transfer_raw(struct ddc_service *ddc,
- struct aux_payload *payload,
- enum aux_return_code_type *operation_result);
-
-bool dc_link_aux_transfer_with_retries(struct ddc_service *ddc,
- struct aux_payload *payload);
-
-bool dc_link_aux_try_to_configure_timeout(struct ddc_service *ddc,
- uint32_t timeout);
-
-void dal_ddc_service_write_scdc_data(
- struct ddc_service *ddc_service,
- uint32_t pix_clk,
- bool lte_340_scramble);
-
-void dal_ddc_service_read_scdc_data(
- struct ddc_service *ddc_service);
-
-void ddc_service_set_dongle_type(struct ddc_service *ddc,
- enum display_dongle_type dongle_type);
-
-void dal_ddc_service_set_ddc_pin(
- struct ddc_service *ddc_service,
- struct ddc *ddc);
-
-struct ddc *dal_ddc_service_get_ddc_pin(struct ddc_service *ddc_service);
-
-uint32_t get_defer_delay(struct ddc_service *ddc);
-
-#endif /* __DAL_DDC_SERVICE_H__ */
-
diff --git a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h
deleted file mode 100644
index e8d8c5cb1309..000000000000
--- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * Copyright 2015 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
- *
- * Authors: AMD
- *
- */
-
-#ifndef __DC_LINK_DP_H__
-#define __DC_LINK_DP_H__
-
-#define LINK_TRAINING_ATTEMPTS 4
-#define LINK_TRAINING_RETRY_DELAY 50 /* ms */
-#define LINK_AUX_DEFAULT_LTTPR_TIMEOUT_PERIOD 3200 /*us*/
-#define LINK_AUX_DEFAULT_TIMEOUT_PERIOD 552 /*us*/
-#define MAX_MTP_SLOT_COUNT 64
-#define DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE 0x50
-#define TRAINING_AUX_RD_INTERVAL 100 //us
-#define LINK_AUX_WAKE_TIMEOUT_MS 1500 // Timeout when trying to wake unresponsive DPRX.
-
-struct dc_link;
-struct dc_stream_state;
-struct dc_link_settings;
-
-enum {
- LINK_TRAINING_MAX_RETRY_COUNT = 5,
- /* to avoid infinite loop where-in the receiver
- * switches between different VS
- */
- LINK_TRAINING_MAX_CR_RETRY = 100,
- /*
- * Some receivers fail to train on first try and are good
- * on subsequent tries. 2 retries should be plenty. If we
- * don't have a successful training then we don't expect to
- * ever get one.
- */
- LINK_TRAINING_MAX_VERIFY_RETRY = 2,
- PEAK_FACTOR_X1000 = 1006,
-};
-
-struct dc_link_settings dp_get_max_link_cap(struct dc_link *link);
-
-bool dp_verify_link_cap_with_retries(
- struct dc_link *link,
- struct dc_link_settings *known_limit_link_setting,
- int attempts);
-
-bool dp_validate_mode_timing(
- struct dc_link *link,
- const struct dc_crtc_timing *timing);
-
-bool decide_edp_link_settings(struct dc_link *link,
- struct dc_link_settings *link_setting,
- uint32_t req_bw);
-
-bool decide_link_settings(
- struct dc_stream_state *stream,
- struct dc_link_settings *link_setting);
-
-bool perform_link_training_with_retries(
- const struct dc_link_settings *link_setting,
- bool skip_video_pattern,
- int attempts,
- struct pipe_ctx *pipe_ctx,
- enum signal_type signal,
- bool do_fallback);
-
-bool hpd_rx_irq_check_link_loss_status(
- struct dc_link *link,
- union hpd_irq_data *hpd_irq_dpcd_data);
-
-bool is_mst_supported(struct dc_link *link);
-
-bool detect_dp_sink_caps(struct dc_link *link);
-
-void detect_edp_sink_caps(struct dc_link *link);
-
-bool is_dp_active_dongle(const struct dc_link *link);
-
-bool is_dp_branch_device(const struct dc_link *link);
-
-bool is_edp_ilr_optimization_required(struct dc_link *link, struct dc_crtc_timing *crtc_timing);
-
-void dp_enable_mst_on_sink(struct dc_link *link, bool enable);
-
-enum dp_panel_mode dp_get_panel_mode(struct dc_link *link);
-void dp_set_panel_mode(struct dc_link *link, enum dp_panel_mode panel_mode);
-
-bool dp_overwrite_extended_receiver_cap(struct dc_link *link);
-
-void dpcd_set_source_specific_data(struct dc_link *link);
-
-void dpcd_write_cable_id_to_dprx(struct dc_link *link);
-
-/* Write DPCD link configuration data. */
-enum dc_status dpcd_set_link_settings(
- struct dc_link *link,
- const struct link_training_settings *lt_settings);
-/* Write DPCD drive settings. */
-enum dc_status dpcd_set_lane_settings(
- struct dc_link *link,
- const struct link_training_settings *link_training_setting,
- uint32_t offset);
-/* Read training status and adjustment requests from DPCD. */
-enum dc_status dp_get_lane_status_and_lane_adjust(
- struct dc_link *link,
- const struct link_training_settings *link_training_setting,
- union lane_status ln_status[LANE_COUNT_DP_MAX],
- union lane_align_status_updated *ln_align,
- union lane_adjust ln_adjust[LANE_COUNT_DP_MAX],
- uint32_t offset);
-
-void dp_wait_for_training_aux_rd_interval(
- struct dc_link *link,
- uint32_t wait_in_micro_secs);
-
-bool dp_is_cr_done(enum dc_lane_count ln_count,
- union lane_status *dpcd_lane_status);
-
-enum link_training_result dp_get_cr_failure(enum dc_lane_count ln_count,
- union lane_status *dpcd_lane_status);
-
-bool dp_is_ch_eq_done(enum dc_lane_count ln_count,
- union lane_status *dpcd_lane_status);
-bool dp_is_symbol_locked(enum dc_lane_count ln_count,
- union lane_status *dpcd_lane_status);
-bool dp_is_interlane_aligned(union lane_align_status_updated align_status);
-
-bool dp_is_max_vs_reached(
- const struct link_training_settings *lt_settings);
-void dp_hw_to_dpcd_lane_settings(
- const struct link_training_settings *lt_settings,
- const struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX],
- union dpcd_training_lane dpcd_lane_settings[]);
-void dp_decide_lane_settings(
- const struct link_training_settings *lt_settings,
- const union lane_adjust ln_adjust[LANE_COUNT_DP_MAX],
- struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX],
- union dpcd_training_lane dpcd_lane_settings[]);
-
-uint32_t dp_translate_training_aux_read_interval(uint32_t dpcd_aux_read_interval);
-
-enum dpcd_training_patterns
- dc_dp_training_pattern_to_dpcd_training_pattern(
- struct dc_link *link,
- enum dc_dp_training_pattern pattern);
-
-uint8_t dc_dp_initialize_scrambling_data_symbols(
- struct dc_link *link,
- enum dc_dp_training_pattern pattern);
-
-enum dc_status dp_set_fec_ready(struct dc_link *link, const struct link_resource *link_res, bool ready);
-void dp_set_fec_enable(struct dc_link *link, bool enable);
-bool dp_set_dsc_enable(struct pipe_ctx *pipe_ctx, bool enable);
-bool dp_set_dsc_pps_sdp(struct pipe_ctx *pipe_ctx, bool enable, bool immediate_update);
-void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable);
-bool dp_update_dsc_config(struct pipe_ctx *pipe_ctx);
-bool dp_set_dsc_on_rx(struct pipe_ctx *pipe_ctx, bool enable);
-
-/* Initialize output parameter lt_settings. */
-void dp_decide_training_settings(
- struct dc_link *link,
- const struct dc_link_settings *link_setting,
- struct link_training_settings *lt_settings);
-
-/* Convert PHY repeater count read from DPCD uint8_t. */
-uint8_t dp_convert_to_count(uint8_t lttpr_repeater_count);
-
-/* Check DPCD training status registers to detect link loss. */
-enum link_training_result dp_check_link_loss_status(
- struct dc_link *link,
- const struct link_training_settings *link_training_setting);
-
-enum dc_status dpcd_configure_lttpr_mode(
- struct dc_link *link,
- struct link_training_settings *lt_settings);
-
-enum dp_link_encoding dp_get_link_encoding_format(const struct dc_link_settings *link_settings);
-enum dc_status dp_retrieve_lttpr_cap(struct dc_link *link);
-bool dp_is_lttpr_present(struct dc_link *link);
-enum lttpr_mode dp_decide_lttpr_mode(struct dc_link *link, struct dc_link_settings *link_setting);
-void dp_get_lttpr_mode_override(struct dc_link *link, enum lttpr_mode *override);
-enum lttpr_mode dp_decide_8b_10b_lttpr_mode(struct dc_link *link);
-enum lttpr_mode dp_decide_128b_132b_lttpr_mode(struct dc_link *link);
-bool dpcd_write_128b_132b_sst_payload_allocation_table(
- const struct dc_stream_state *stream,
- struct dc_link *link,
- struct link_mst_stream_allocation_table *proposed_table,
- bool allocate);
-
-enum dc_status dpcd_configure_channel_coding(
- struct dc_link *link,
- struct link_training_settings *lt_settings);
-
-bool dpcd_poll_for_allocation_change_trigger(struct dc_link *link);
-
-struct fixed31_32 calculate_sst_avg_time_slots_per_mtp(
- const struct dc_stream_state *stream,
- const struct dc_link *link);
-void enable_dp_hpo_output(struct dc_link *link,
- const struct link_resource *link_res,
- const struct dc_link_settings *link_settings);
-void disable_dp_hpo_output(struct dc_link *link,
- const struct link_resource *link_res,
- enum signal_type signal);
-
-void setup_dp_hpo_stream(struct pipe_ctx *pipe_ctx, bool enable);
-bool is_dp_128b_132b_signal(struct pipe_ctx *pipe_ctx);
-void edp_panel_backlight_power_on(struct dc_link *link, bool wait_for_hpd);
-void dp_receiver_power_ctrl(struct dc_link *link, bool on);
-void dp_source_sequence_trace(struct dc_link *link, uint8_t dp_test_mode);
-void dp_enable_link_phy(
- struct dc_link *link,
- const struct link_resource *link_res,
- enum signal_type signal,
- enum clock_source_id clock_source,
- const struct dc_link_settings *link_settings);
-void edp_add_delay_for_T9(struct dc_link *link);
-bool edp_receiver_ready_T9(struct dc_link *link);
-bool edp_receiver_ready_T7(struct dc_link *link);
-
-void dp_disable_link_phy(struct dc_link *link, const struct link_resource *link_res,
- enum signal_type signal);
-
-void dp_disable_link_phy_mst(struct dc_link *link, const struct link_resource *link_res,
- enum signal_type signal);
-
-bool dp_set_hw_training_pattern(
- struct dc_link *link,
- const struct link_resource *link_res,
- enum dc_dp_training_pattern pattern,
- uint32_t offset);
-
-void dp_set_hw_lane_settings(
- struct dc_link *link,
- const struct link_resource *link_res,
- const struct link_training_settings *link_settings,
- uint32_t offset);
-
-void dp_set_hw_test_pattern(
- struct dc_link *link,
- const struct link_resource *link_res,
- enum dp_test_pattern test_pattern,
- uint8_t *custom_pattern,
- uint32_t custom_pattern_size);
-
-void dp_retrain_link_dp_test(struct dc_link *link,
- struct dc_link_settings *link_setting,
- bool skip_video_pattern);
-#endif /* __DC_LINK_DP_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dpia.h b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dpia.h
deleted file mode 100644
index 39c1d1d07357..000000000000
--- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dpia.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright 2021 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
- *
- * Authors: AMD
- *
- */
-
-#ifndef __DC_LINK_DPIA_H__
-#define __DC_LINK_DPIA_H__
-
-/* This module implements functionality for training DPIA links. */
-
-struct dc_link;
-struct dc_link_settings;
-
-/* The approximate time (us) it takes to transmit 9 USB4 DP clock sync packets. */
-#define DPIA_CLK_SYNC_DELAY 16000
-
-/* Extend interval between training status checks for manual testing. */
-#define DPIA_DEBUG_EXTENDED_AUX_RD_INTERVAL_US 60000000
-
-/** @note Can remove once DP tunneling registers in upstream include/drm/drm_dp_helper.h */
-/* DPCD DP Tunneling over USB4 */
-#define DP_TUNNELING_CAPABILITIES_SUPPORT 0xe000d
-#define DP_IN_ADAPTER_INFO 0xe000e
-#define DP_USB4_DRIVER_ID 0xe000f
-#define DP_USB4_ROUTER_TOPOLOGY_ID 0xe001b
-
-/* SET_CONFIG message types sent by driver. */
-enum dpia_set_config_type {
- DPIA_SET_CFG_SET_LINK = 0x01,
- DPIA_SET_CFG_SET_PHY_TEST_MODE = 0x05,
- DPIA_SET_CFG_SET_TRAINING = 0x18,
- DPIA_SET_CFG_SET_VSPE = 0x19
-};
-
-/* Training stages (TS) in SET_CONFIG(SET_TRAINING) message. */
-enum dpia_set_config_ts {
- DPIA_TS_DPRX_DONE = 0x00, /* Done training DPRX. */
- DPIA_TS_TPS1 = 0x01,
- DPIA_TS_TPS2 = 0x02,
- DPIA_TS_TPS3 = 0x03,
- DPIA_TS_TPS4 = 0x07,
- DPIA_TS_UFP_DONE = 0xff /* Done training DPTX-to-DPIA hop. */
-};
-
-/* SET_CONFIG message data associated with messages sent by driver. */
-union dpia_set_config_data {
- struct {
- uint8_t mode : 1;
- uint8_t reserved : 7;
- } set_link;
- struct {
- uint8_t stage;
- } set_training;
- struct {
- uint8_t swing : 2;
- uint8_t max_swing_reached : 1;
- uint8_t pre_emph : 2;
- uint8_t max_pre_emph_reached : 1;
- uint8_t reserved : 2;
- } set_vspe;
- uint8_t raw;
-};
-
-/* Read tunneling device capability from DPCD and update link capability
- * accordingly.
- */
-enum dc_status dpcd_get_tunneling_device_data(struct dc_link *link);
-
-/* Query hot plug status of USB4 DP tunnel.
- * Returns true if HPD high.
- */
-bool dc_link_dpia_query_hpd_status(struct dc_link *link);
-
-/* Train DP tunneling link for USB4 DPIA display endpoint.
- * DPIA equivalent of dc_link_dp_perfrorm_link_training.
- * Aborts link training upon detection of sink unplug.
- */
-enum link_training_result dc_link_dpia_perform_link_training(
- struct dc_link *link,
- const struct link_resource *link_res,
- const struct dc_link_settings *link_setting,
- bool skip_video_pattern);
-
-#endif /* __DC_LINK_DPIA_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/aux_engine.h b/drivers/gpu/drm/amd/display/dc/inc/hw/aux_engine.h
index 2ae630bf2aee..7254182b7c72 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/aux_engine.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/aux_engine.h
@@ -27,7 +27,6 @@
#define __DAL_AUX_ENGINE_H__
#include "dc_ddc_types.h"
-#include "include/i2caux_interface.h"
enum aux_return_code_type;
@@ -81,7 +80,12 @@ enum i2c_default_speed {
I2CAUX_DEFAULT_I2C_SW_SPEED = 50
};
-union aux_config;
+union aux_config {
+ struct {
+ uint32_t ALLOW_AUX_WHEN_HPD_LOW:1;
+ } bits;
+ uint32_t raw;
+};
struct aux_engine {
uint32_t inst;
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h
index 5b0265c0df61..beb26dc8a07f 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h
@@ -187,6 +187,7 @@ struct hubbub_funcs {
void (*init_crb)(struct hubbub *hubbub);
void (*force_usr_retraining_allow)(struct hubbub *hubbub, bool allow);
void (*set_request_limit)(struct hubbub *hubbub, int memory_channel_count, int words_per_channel);
+ void (*dchubbub_init)(struct hubbub *hubbub);
};
struct hubbub {
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h
index 42db4b7b79fd..bb5ad70d4266 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h
@@ -72,6 +72,12 @@ enum dynamic_metadata_mode {
dmdata_dolby_vision
};
+struct enc_sdp_line_num {
+ /* Adaptive Sync SDP */
+ bool adaptive_sync_line_num_valid;
+ uint32_t adaptive_sync_line_num;
+};
+
struct encoder_info_frame {
/* auxiliary video information */
struct dc_info_packet avi;
@@ -85,6 +91,9 @@ struct encoder_info_frame {
struct dc_info_packet vsc;
/* HDR Static MetaData */
struct dc_info_packet hdrsmd;
+ /* Adaptive Sync SDP*/
+ struct dc_info_packet adaptive_sync;
+ struct enc_sdp_line_num sdp_line_num;
};
struct encoder_unblank_param {
@@ -154,6 +163,10 @@ struct stream_encoder_funcs {
void (*stop_hdmi_info_packets)(
struct stream_encoder *enc);
+ void (*update_dp_info_packets_sdp_line_num)(
+ struct stream_encoder *enc,
+ struct encoder_info_frame *info_frame);
+
void (*update_dp_info_packets)(
struct stream_encoder *enc,
const struct encoder_info_frame *info_frame);
@@ -302,6 +315,10 @@ struct hpo_dp_stream_encoder_funcs {
bool compressed_format,
bool double_buffer_en);
+ void (*update_dp_info_packets_sdp_line_num)(
+ struct hpo_dp_stream_encoder *enc,
+ struct encoder_info_frame *info_frame);
+
void (*update_dp_info_packets)(
struct hpo_dp_stream_encoder *enc,
const struct encoder_info_frame *info_frame);
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h
index 0e42e721dd15..1d9f9c53d2bd 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h
@@ -331,6 +331,7 @@ struct timing_generator_funcs {
uint32_t vtotal_change_limit);
void (*init_odm)(struct timing_generator *tg);
+ void (*wait_drr_doublebuffer_pending_clear)(struct timing_generator *tg);
};
#endif
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h
index c43523f9ff6d..88ac723d10aa 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h
@@ -266,6 +266,7 @@ struct hw_sequencer_funcs {
void (*apply_update_flags_for_phantom)(struct pipe_ctx *phantom_pipe);
void (*commit_subvp_config)(struct dc *dc, struct dc_state *context);
+ void (*enable_phantom_streams)(struct dc *dc, struct dc_state *context);
void (*subvp_pipe_control_lock)(struct dc *dc,
struct dc_state *context,
bool lock,
diff --git a/drivers/gpu/drm/amd/display/dc/inc/link.h b/drivers/gpu/drm/amd/display/dc/inc/link.h
new file mode 100644
index 000000000000..e70fa0059223
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/inc/link.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DC_LINK_H__
+#define __DC_LINK_H__
+
+/* FILE POLICY AND INTENDED USAGE:
+ *
+ * This header declares link functions exposed to dc. All functions must have
+ * "link_" as prefix. For example link_run_my_function. This header is strictly
+ * private in dc and should never be included in other header files. dc
+ * components should include this header in their .c files in order to access
+ * functions in link folder. This file should never include any header files in
+ * link folder. If there is a need to expose a function declared in one of
+ * header files in side link folder, you need to move the function declaration
+ * into this file and prefix it with "link_".
+ */
+#include "core_types.h"
+#include "dc_link.h"
+
+struct link_init_data {
+ const struct dc *dc;
+ struct dc_context *ctx; /* TODO: remove 'dal' when DC is complete. */
+ uint32_t connector_index; /* this will be mapped to the HPD pins */
+ uint32_t link_index; /* this is mapped to DAL display_index
+ TODO: remove it when DC is complete. */
+ bool is_dpia_link;
+};
+
+struct dc_link *link_create(const struct link_init_data *init_params);
+void link_destroy(struct dc_link **link);
+
+// TODO - convert any function declarations below to function pointers
+struct gpio *link_get_hpd_gpio(struct dc_bios *dcb,
+ struct graphics_object_id link_id,
+ struct gpio_service *gpio_service);
+
+struct ddc_service_init_data {
+ struct graphics_object_id id;
+ struct dc_context *ctx;
+ struct dc_link *link;
+ bool is_dpia_link;
+};
+
+struct ddc_service *link_create_ddc_service(
+ struct ddc_service_init_data *ddc_init_data);
+
+void link_destroy_ddc_service(struct ddc_service **ddc);
+
+bool link_is_in_aux_transaction_mode(struct ddc_service *ddc);
+
+bool link_query_ddc_data(
+ struct ddc_service *ddc,
+ uint32_t address,
+ uint8_t *write_buf,
+ uint32_t write_size,
+ uint8_t *read_buf,
+ uint32_t read_size);
+
+
+/* Attempt to submit an aux payload, retrying on timeouts, defers, and busy
+ * states as outlined in the DP spec. Returns true if the request was
+ * successful.
+ *
+ * NOTE: The function requires explicit mutex on DM side in order to prevent
+ * potential race condition. DC components should call the dpcd read/write
+ * function in dm_helpers in order to access dpcd safely
+ */
+bool link_aux_transfer_with_retries_no_mutex(struct ddc_service *ddc,
+ struct aux_payload *payload);
+
+uint32_t link_get_aux_defer_delay(struct ddc_service *ddc);
+
+bool link_is_dp_128b_132b_signal(struct pipe_ctx *pipe_ctx);
+
+enum dp_link_encoding link_dp_get_encoding_format(
+ const struct dc_link_settings *link_settings);
+
+bool link_decide_link_settings(
+ struct dc_stream_state *stream,
+ struct dc_link_settings *link_setting);
+
+void link_dp_trace_set_edp_power_timestamp(struct dc_link *link,
+ bool power_up);
+uint64_t link_dp_trace_get_edp_poweron_timestamp(struct dc_link *link);
+uint64_t link_dp_trace_get_edp_poweroff_timestamp(struct dc_link *link);
+
+bool link_is_edp_ilr_optimization_required(struct dc_link *link,
+ struct dc_crtc_timing *crtc_timing);
+
+bool link_backlight_enable_aux(struct dc_link *link, bool enable);
+void link_edp_add_delay_for_T9(struct dc_link *link);
+bool link_edp_receiver_ready_T9(struct dc_link *link);
+bool link_edp_receiver_ready_T7(struct dc_link *link);
+bool link_power_alpm_dpcd_enable(struct dc_link *link, bool enable);
+bool link_set_sink_vtotal_in_psr_active(const struct dc_link *link,
+ uint16_t psr_vtotal_idle, uint16_t psr_vtotal_su);
+void link_get_psr_residency(const struct dc_link *link, uint32_t *residency);
+enum dc_status link_increase_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t req_pbn);
+enum dc_status link_reduce_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t req_pbn);
+void link_blank_all_dp_displays(struct dc *dc);
+void link_blank_all_edp_displays(struct dc *dc);
+void link_blank_dp_stream(struct dc_link *link, bool hw_init);
+void link_resume(struct dc_link *link);
+void link_set_dpms_on(
+ struct dc_state *state,
+ struct pipe_ctx *pipe_ctx);
+void link_set_dpms_off(struct pipe_ctx *pipe_ctx);
+void link_dp_source_sequence_trace(struct dc_link *link, uint8_t dp_test_mode);
+void link_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable);
+bool link_set_dsc_enable(struct pipe_ctx *pipe_ctx, bool enable);
+bool link_update_dsc_config(struct pipe_ctx *pipe_ctx);
+enum dc_status link_validate_mode_timing(
+ const struct dc_stream_state *stream,
+ struct dc_link *link,
+ const struct dc_crtc_timing *timing);
+bool link_detect(struct dc_link *link, enum dc_detect_reason reason);
+bool link_detect_connection_type(struct dc_link *link,
+ enum dc_connection_type *type);
+const struct dc_link_status *link_get_status(const struct dc_link *link);
+#ifdef CONFIG_DRM_AMD_DC_HDCP
+/* return true if the connected receiver supports the hdcp version */
+bool link_is_hdcp14(struct dc_link *link, enum signal_type signal);
+bool link_is_hdcp22(struct dc_link *link, enum signal_type signal);
+#endif
+void link_clear_dprx_states(struct dc_link *link);
+bool link_reset_cur_dp_mst_topology(struct dc_link *link);
+uint32_t dp_link_bandwidth_kbps(
+ const struct dc_link *link,
+ const struct dc_link_settings *link_settings);
+uint32_t link_timing_bandwidth_kbps(const struct dc_crtc_timing *timing);
+void link_get_cur_res_map(const struct dc *dc, uint32_t *map);
+void link_restore_res_map(const struct dc *dc, uint32_t *map);
+
+#endif /* __DC_LINK_HPD_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/inc/resource.h b/drivers/gpu/drm/amd/display/dc/inc/resource.h
index 5040836f404d..fa6da93caa88 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/resource.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/resource.h
@@ -165,10 +165,6 @@ bool resource_validate_attach_surfaces(
struct dc_state *context,
const struct resource_pool *pool);
-void resource_validate_ctx_update_pointer_after_copy(
- const struct dc_state *src_ctx,
- struct dc_state *dst_ctx);
-
enum dc_status resource_map_clock_resources(
const struct dc *dc,
struct dc_state *context,
@@ -236,4 +232,13 @@ bool dc_resource_acquire_secondary_pipe_for_mpc_odm(
struct pipe_ctx *pri_pipe,
struct pipe_ctx *sec_pipe,
bool odm);
+
+/* A test harness interface that modifies dp encoder resources in the given dc
+ * state and bypasses the need to revalidate. The interface assumes that the
+ * test harness interface is called with pre-validated link config stored in the
+ * pipe_ctx and updates dp encoder resources according to the link config.
+ */
+enum dc_status update_dp_encoder_resources_for_test_harness(const struct dc *dc,
+ struct dc_state *context,
+ struct pipe_ctx *pipe_ctx);
#endif /* DRIVERS_GPU_DRM_AMD_DC_DEV_DC_INC_RESOURCE_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn201/irq_service_dcn201.c b/drivers/gpu/drm/amd/display/dc/irq/dcn201/irq_service_dcn201.c
index 5f4f6dd79511..3c7cb3dc046b 100644
--- a/drivers/gpu/drm/amd/display/dc/irq/dcn201/irq_service_dcn201.c
+++ b/drivers/gpu/drm/amd/display/dc/irq/dcn201/irq_service_dcn201.c
@@ -37,7 +37,7 @@
#include "soc15_hw_ip.h"
#include "ivsrcid/dcn/irqsrcs_dcn_1_0.h"
-enum dc_irq_source to_dal_irq_source_dcn201(
+static enum dc_irq_source to_dal_irq_source_dcn201(
struct irq_service *irq_service,
uint32_t src_id,
uint32_t ext_id)
@@ -136,11 +136,6 @@ static const struct irq_source_info_funcs vupdate_no_lock_irq_info_funcs = {
.ack = NULL
};
-static const struct irq_source_info_funcs dmub_outbox_irq_info_funcs = {
- .set = NULL,
- .ack = NULL
-};
-
#undef BASE_INNER
#define BASE_INNER(seg) DMU_BASE__INST0_SEG ## seg
diff --git a/drivers/gpu/drm/amd/display/dc/link/Makefile b/drivers/gpu/drm/amd/display/dc/link/Makefile
index 054c2a727eb2..40352d8d7648 100644
--- a/drivers/gpu/drm/amd/display/dc/link/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/link/Makefile
@@ -23,8 +23,41 @@
# It abstracts the control and status of back end pipe such as DIO, HPO, DPIA,
# PHY, HPD, DDC and etc).
-LINK = link_hwss_dio.o link_hwss_dpia.o link_hwss_hpo_dp.o link_dp_trace.o
+LINK = link_detection.o link_dpms.o link_factory.o link_resource.o \
+link_validation.o
-AMD_DAL_LINK = $(addprefix $(AMDDALPATH)/dc/link/,$(LINK))
+AMD_DAL_LINK = $(addprefix $(AMDDALPATH)/dc/link/, \
+$(LINK))
AMD_DISPLAY_FILES += $(AMD_DAL_LINK)
+###############################################################################
+# accessories
+###############################################################################
+LINK_ACCESSORIES = link_dp_trace.o link_dp_cts.o link_fpga.o
+
+AMD_DAL_LINK_ACCESSORIES = $(addprefix $(AMDDALPATH)/dc/link/accessories/, \
+$(LINK_ACCESSORIES))
+
+AMD_DISPLAY_FILES += $(AMD_DAL_LINK_ACCESSORIES)
+###############################################################################
+# hwss
+###############################################################################
+LINK_HWSS = link_hwss_dio.o link_hwss_dpia.o link_hwss_hpo_dp.o
+
+AMD_DAL_LINK_HWSS = $(addprefix $(AMDDALPATH)/dc/link/hwss/, \
+$(LINK_HWSS))
+
+AMD_DISPLAY_FILES += $(AMD_DAL_LINK_HWSS)
+###############################################################################
+# protocols
+###############################################################################
+LINK_PROTOCOLS = link_hpd.o link_ddc.o link_dpcd.o link_dp_dpia.o \
+link_dp_training.o link_dp_training_8b_10b.o link_dp_training_128b_132b.o \
+link_dp_training_dpia.o link_dp_training_auxless.o \
+link_dp_training_fixed_vs_pe_retimer.o link_dp_phy.o link_dp_capability.o \
+link_edp_panel_control.o link_dp_irq_handler.o
+
+AMD_DAL_LINK_PROTOCOLS = $(addprefix $(AMDDALPATH)/dc/link/protocols/, \
+$(LINK_PROTOCOLS))
+
+AMD_DISPLAY_FILES += $(AMD_DAL_LINK_PROTOCOLS) \ No newline at end of file
diff --git a/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c
new file mode 100644
index 000000000000..942300e0bd92
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c
@@ -0,0 +1,1046 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+#include "link_dp_cts.h"
+#include "link/link_resource.h"
+#include "link/protocols/link_dpcd.h"
+#include "link/protocols/link_dp_training.h"
+#include "link/protocols/link_dp_phy.h"
+#include "link/protocols/link_dp_training_fixed_vs_pe_retimer.h"
+#include "link/link_dpms.h"
+#include "resource.h"
+#include "dm_helpers.h"
+#include "dc_dmub_srv.h"
+#include "dce/dmub_hw_lock_mgr.h"
+
+#define DC_LOGGER \
+ link->ctx->logger
+
+static enum dc_link_rate get_link_rate_from_test_link_rate(uint8_t test_rate)
+{
+ switch (test_rate) {
+ case DP_TEST_LINK_RATE_RBR:
+ return LINK_RATE_LOW;
+ case DP_TEST_LINK_RATE_HBR:
+ return LINK_RATE_HIGH;
+ case DP_TEST_LINK_RATE_HBR2:
+ return LINK_RATE_HIGH2;
+ case DP_TEST_LINK_RATE_HBR3:
+ return LINK_RATE_HIGH3;
+ case DP_TEST_LINK_RATE_UHBR10:
+ return LINK_RATE_UHBR10;
+ case DP_TEST_LINK_RATE_UHBR20:
+ return LINK_RATE_UHBR20;
+ case DP_TEST_LINK_RATE_UHBR13_5:
+ return LINK_RATE_UHBR13_5;
+ default:
+ return LINK_RATE_UNKNOWN;
+ }
+}
+
+static bool is_dp_phy_sqaure_pattern(enum dp_test_pattern test_pattern)
+{
+ return (DP_TEST_PATTERN_SQUARE_BEGIN <= test_pattern &&
+ test_pattern <= DP_TEST_PATTERN_SQUARE_END);
+}
+
+static bool is_dp_phy_pattern(enum dp_test_pattern test_pattern)
+{
+ if ((DP_TEST_PATTERN_PHY_PATTERN_BEGIN <= test_pattern &&
+ test_pattern <= DP_TEST_PATTERN_PHY_PATTERN_END) ||
+ test_pattern == DP_TEST_PATTERN_VIDEO_MODE)
+ return true;
+ else
+ return false;
+}
+
+void dp_retrain_link_dp_test(struct dc_link *link,
+ struct dc_link_settings *link_setting,
+ bool skip_video_pattern)
+{
+ struct pipe_ctx *pipes[MAX_PIPES];
+ struct dc_state *state = link->dc->current_state;
+ uint8_t count;
+ int i;
+
+ udelay(100);
+
+ link_get_master_pipes_with_dpms_on(link, state, &count, pipes);
+
+ for (i = 0; i < count; i++) {
+ link_set_dpms_off(pipes[i]);
+ pipes[i]->link_config.dp_link_settings = *link_setting;
+ update_dp_encoder_resources_for_test_harness(
+ link->dc,
+ state,
+ pipes[i]);
+ }
+
+ for (i = count-1; i >= 0; i--)
+ link_set_dpms_on(state, pipes[i]);
+}
+
+static void dp_test_send_link_training(struct dc_link *link)
+{
+ struct dc_link_settings link_settings = {0};
+ uint8_t test_rate = 0;
+
+ core_link_read_dpcd(
+ link,
+ DP_TEST_LANE_COUNT,
+ (unsigned char *)(&link_settings.lane_count),
+ 1);
+ core_link_read_dpcd(
+ link,
+ DP_TEST_LINK_RATE,
+ &test_rate,
+ 1);
+ link_settings.link_rate = get_link_rate_from_test_link_rate(test_rate);
+
+ /* Set preferred link settings */
+ link->verified_link_cap.lane_count = link_settings.lane_count;
+ link->verified_link_cap.link_rate = link_settings.link_rate;
+
+ dp_retrain_link_dp_test(link, &link_settings, false);
+}
+
+static void dp_test_get_audio_test_data(struct dc_link *link, bool disable_video)
+{
+ union audio_test_mode dpcd_test_mode = {0};
+ struct audio_test_pattern_type dpcd_pattern_type = {0};
+ union audio_test_pattern_period dpcd_pattern_period[AUDIO_CHANNELS_COUNT] = {0};
+ enum dp_test_pattern test_pattern = DP_TEST_PATTERN_AUDIO_OPERATOR_DEFINED;
+
+ struct pipe_ctx *pipes = link->dc->current_state->res_ctx.pipe_ctx;
+ struct pipe_ctx *pipe_ctx = &pipes[0];
+ unsigned int channel_count;
+ unsigned int channel = 0;
+ unsigned int modes = 0;
+ unsigned int sampling_rate_in_hz = 0;
+
+ // get audio test mode and test pattern parameters
+ core_link_read_dpcd(
+ link,
+ DP_TEST_AUDIO_MODE,
+ &dpcd_test_mode.raw,
+ sizeof(dpcd_test_mode));
+
+ core_link_read_dpcd(
+ link,
+ DP_TEST_AUDIO_PATTERN_TYPE,
+ &dpcd_pattern_type.value,
+ sizeof(dpcd_pattern_type));
+
+ channel_count = min(dpcd_test_mode.bits.channel_count + 1, AUDIO_CHANNELS_COUNT);
+
+ // read pattern periods for requested channels when sawTooth pattern is requested
+ if (dpcd_pattern_type.value == AUDIO_TEST_PATTERN_SAWTOOTH ||
+ dpcd_pattern_type.value == AUDIO_TEST_PATTERN_OPERATOR_DEFINED) {
+
+ test_pattern = (dpcd_pattern_type.value == AUDIO_TEST_PATTERN_SAWTOOTH) ?
+ DP_TEST_PATTERN_AUDIO_SAWTOOTH : DP_TEST_PATTERN_AUDIO_OPERATOR_DEFINED;
+ // read period for each channel
+ for (channel = 0; channel < channel_count; channel++) {
+ core_link_read_dpcd(
+ link,
+ DP_TEST_AUDIO_PERIOD_CH1 + channel,
+ &dpcd_pattern_period[channel].raw,
+ sizeof(dpcd_pattern_period[channel]));
+ }
+ }
+
+ // translate sampling rate
+ switch (dpcd_test_mode.bits.sampling_rate) {
+ case AUDIO_SAMPLING_RATE_32KHZ:
+ sampling_rate_in_hz = 32000;
+ break;
+ case AUDIO_SAMPLING_RATE_44_1KHZ:
+ sampling_rate_in_hz = 44100;
+ break;
+ case AUDIO_SAMPLING_RATE_48KHZ:
+ sampling_rate_in_hz = 48000;
+ break;
+ case AUDIO_SAMPLING_RATE_88_2KHZ:
+ sampling_rate_in_hz = 88200;
+ break;
+ case AUDIO_SAMPLING_RATE_96KHZ:
+ sampling_rate_in_hz = 96000;
+ break;
+ case AUDIO_SAMPLING_RATE_176_4KHZ:
+ sampling_rate_in_hz = 176400;
+ break;
+ case AUDIO_SAMPLING_RATE_192KHZ:
+ sampling_rate_in_hz = 192000;
+ break;
+ default:
+ sampling_rate_in_hz = 0;
+ break;
+ }
+
+ link->audio_test_data.flags.test_requested = 1;
+ link->audio_test_data.flags.disable_video = disable_video;
+ link->audio_test_data.sampling_rate = sampling_rate_in_hz;
+ link->audio_test_data.channel_count = channel_count;
+ link->audio_test_data.pattern_type = test_pattern;
+
+ if (test_pattern == DP_TEST_PATTERN_AUDIO_SAWTOOTH) {
+ for (modes = 0; modes < pipe_ctx->stream->audio_info.mode_count; modes++) {
+ link->audio_test_data.pattern_period[modes] = dpcd_pattern_period[modes].bits.pattern_period;
+ }
+ }
+}
+
+/* TODO Raven hbr2 compliance eye output is unstable
+ * (toggling on and off) with debugger break
+ * This caueses intermittent PHY automation failure
+ * Need to look into the root cause */
+static void dp_test_send_phy_test_pattern(struct dc_link *link)
+{
+ union phy_test_pattern dpcd_test_pattern;
+ union lane_adjust dpcd_lane_adjustment[2];
+ unsigned char dpcd_post_cursor_2_adjustment = 0;
+ unsigned char test_pattern_buffer[
+ (DP_TEST_264BIT_CUSTOM_PATTERN_263_256 -
+ DP_TEST_264BIT_CUSTOM_PATTERN_7_0)+1] = {0};
+ unsigned int test_pattern_size = 0;
+ enum dp_test_pattern test_pattern;
+ union lane_adjust dpcd_lane_adjust;
+ unsigned int lane;
+ struct link_training_settings link_training_settings;
+ unsigned char no_preshoot = 0;
+ unsigned char no_deemphasis = 0;
+
+ dpcd_test_pattern.raw = 0;
+ memset(dpcd_lane_adjustment, 0, sizeof(dpcd_lane_adjustment));
+ memset(&link_training_settings, 0, sizeof(link_training_settings));
+
+ /* get phy test pattern and pattern parameters from DP receiver */
+ core_link_read_dpcd(
+ link,
+ DP_PHY_TEST_PATTERN,
+ &dpcd_test_pattern.raw,
+ sizeof(dpcd_test_pattern));
+ core_link_read_dpcd(
+ link,
+ DP_ADJUST_REQUEST_LANE0_1,
+ &dpcd_lane_adjustment[0].raw,
+ sizeof(dpcd_lane_adjustment));
+
+ /* prepare link training settings */
+ link_training_settings.link_settings = link->cur_link_settings;
+
+ link_training_settings.lttpr_mode = dc_link_decide_lttpr_mode(link, &link->cur_link_settings);
+
+ if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) &&
+ link_training_settings.lttpr_mode == LTTPR_MODE_TRANSPARENT)
+ dp_fixed_vs_pe_read_lane_adjust(
+ link,
+ link_training_settings.dpcd_lane_settings);
+
+ /*get post cursor 2 parameters
+ * For DP 1.1a or eariler, this DPCD register's value is 0
+ * For DP 1.2 or later:
+ * Bits 1:0 = POST_CURSOR2_LANE0; Bits 3:2 = POST_CURSOR2_LANE1
+ * Bits 5:4 = POST_CURSOR2_LANE2; Bits 7:6 = POST_CURSOR2_LANE3
+ */
+ core_link_read_dpcd(
+ link,
+ DP_ADJUST_REQUEST_POST_CURSOR2,
+ &dpcd_post_cursor_2_adjustment,
+ sizeof(dpcd_post_cursor_2_adjustment));
+
+ /* translate request */
+ switch (dpcd_test_pattern.bits.PATTERN) {
+ case PHY_TEST_PATTERN_D10_2:
+ test_pattern = DP_TEST_PATTERN_D102;
+ break;
+ case PHY_TEST_PATTERN_SYMBOL_ERROR:
+ test_pattern = DP_TEST_PATTERN_SYMBOL_ERROR;
+ break;
+ case PHY_TEST_PATTERN_PRBS7:
+ test_pattern = DP_TEST_PATTERN_PRBS7;
+ break;
+ case PHY_TEST_PATTERN_80BIT_CUSTOM:
+ test_pattern = DP_TEST_PATTERN_80BIT_CUSTOM;
+ break;
+ case PHY_TEST_PATTERN_CP2520_1:
+ /* CP2520 pattern is unstable, temporarily use TPS4 instead */
+ test_pattern = (link->dc->caps.force_dp_tps4_for_cp2520 == 1) ?
+ DP_TEST_PATTERN_TRAINING_PATTERN4 :
+ DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE;
+ break;
+ case PHY_TEST_PATTERN_CP2520_2:
+ /* CP2520 pattern is unstable, temporarily use TPS4 instead */
+ test_pattern = (link->dc->caps.force_dp_tps4_for_cp2520 == 1) ?
+ DP_TEST_PATTERN_TRAINING_PATTERN4 :
+ DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE;
+ break;
+ case PHY_TEST_PATTERN_CP2520_3:
+ test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN4;
+ break;
+ case PHY_TEST_PATTERN_128b_132b_TPS1:
+ test_pattern = DP_TEST_PATTERN_128b_132b_TPS1;
+ break;
+ case PHY_TEST_PATTERN_128b_132b_TPS2:
+ test_pattern = DP_TEST_PATTERN_128b_132b_TPS2;
+ break;
+ case PHY_TEST_PATTERN_PRBS9:
+ test_pattern = DP_TEST_PATTERN_PRBS9;
+ break;
+ case PHY_TEST_PATTERN_PRBS11:
+ test_pattern = DP_TEST_PATTERN_PRBS11;
+ break;
+ case PHY_TEST_PATTERN_PRBS15:
+ test_pattern = DP_TEST_PATTERN_PRBS15;
+ break;
+ case PHY_TEST_PATTERN_PRBS23:
+ test_pattern = DP_TEST_PATTERN_PRBS23;
+ break;
+ case PHY_TEST_PATTERN_PRBS31:
+ test_pattern = DP_TEST_PATTERN_PRBS31;
+ break;
+ case PHY_TEST_PATTERN_264BIT_CUSTOM:
+ test_pattern = DP_TEST_PATTERN_264BIT_CUSTOM;
+ break;
+ case PHY_TEST_PATTERN_SQUARE:
+ test_pattern = DP_TEST_PATTERN_SQUARE;
+ break;
+ case PHY_TEST_PATTERN_SQUARE_PRESHOOT_DISABLED:
+ test_pattern = DP_TEST_PATTERN_SQUARE_PRESHOOT_DISABLED;
+ no_preshoot = 1;
+ break;
+ case PHY_TEST_PATTERN_SQUARE_DEEMPHASIS_DISABLED:
+ test_pattern = DP_TEST_PATTERN_SQUARE_DEEMPHASIS_DISABLED;
+ no_deemphasis = 1;
+ break;
+ case PHY_TEST_PATTERN_SQUARE_PRESHOOT_DEEMPHASIS_DISABLED:
+ test_pattern = DP_TEST_PATTERN_SQUARE_PRESHOOT_DEEMPHASIS_DISABLED;
+ no_preshoot = 1;
+ no_deemphasis = 1;
+ break;
+ default:
+ test_pattern = DP_TEST_PATTERN_VIDEO_MODE;
+ break;
+ }
+
+ if (test_pattern == DP_TEST_PATTERN_80BIT_CUSTOM) {
+ test_pattern_size = (DP_TEST_80BIT_CUSTOM_PATTERN_79_72 -
+ DP_TEST_80BIT_CUSTOM_PATTERN_7_0) + 1;
+ core_link_read_dpcd(
+ link,
+ DP_TEST_80BIT_CUSTOM_PATTERN_7_0,
+ test_pattern_buffer,
+ test_pattern_size);
+ }
+
+ if (is_dp_phy_sqaure_pattern(test_pattern)) {
+ test_pattern_size = 1; // Square pattern data is 1 byte (DP spec)
+ core_link_read_dpcd(
+ link,
+ DP_PHY_SQUARE_PATTERN,
+ test_pattern_buffer,
+ test_pattern_size);
+ }
+
+ if (test_pattern == DP_TEST_PATTERN_264BIT_CUSTOM) {
+ test_pattern_size = (DP_TEST_264BIT_CUSTOM_PATTERN_263_256-
+ DP_TEST_264BIT_CUSTOM_PATTERN_7_0) + 1;
+ core_link_read_dpcd(
+ link,
+ DP_TEST_264BIT_CUSTOM_PATTERN_7_0,
+ test_pattern_buffer,
+ test_pattern_size);
+ }
+
+ for (lane = 0; lane <
+ (unsigned int)(link->cur_link_settings.lane_count);
+ lane++) {
+ dpcd_lane_adjust.raw =
+ dp_get_nibble_at_index(&dpcd_lane_adjustment[0].raw, lane);
+ if (link_dp_get_encoding_format(&link->cur_link_settings) ==
+ DP_8b_10b_ENCODING) {
+ link_training_settings.hw_lane_settings[lane].VOLTAGE_SWING =
+ (enum dc_voltage_swing)
+ (dpcd_lane_adjust.bits.VOLTAGE_SWING_LANE);
+ link_training_settings.hw_lane_settings[lane].PRE_EMPHASIS =
+ (enum dc_pre_emphasis)
+ (dpcd_lane_adjust.bits.PRE_EMPHASIS_LANE);
+ link_training_settings.hw_lane_settings[lane].POST_CURSOR2 =
+ (enum dc_post_cursor2)
+ ((dpcd_post_cursor_2_adjustment >> (lane * 2)) & 0x03);
+ } else if (link_dp_get_encoding_format(&link->cur_link_settings) ==
+ DP_128b_132b_ENCODING) {
+ link_training_settings.hw_lane_settings[lane].FFE_PRESET.settings.level =
+ dpcd_lane_adjust.tx_ffe.PRESET_VALUE;
+ link_training_settings.hw_lane_settings[lane].FFE_PRESET.settings.no_preshoot = no_preshoot;
+ link_training_settings.hw_lane_settings[lane].FFE_PRESET.settings.no_deemphasis = no_deemphasis;
+ }
+ }
+
+ dp_hw_to_dpcd_lane_settings(&link_training_settings,
+ link_training_settings.hw_lane_settings,
+ link_training_settings.dpcd_lane_settings);
+ /*Usage: Measure DP physical lane signal
+ * by DP SI test equipment automatically.
+ * PHY test pattern request is generated by equipment via HPD interrupt.
+ * HPD needs to be active all the time. HPD should be active
+ * all the time. Do not touch it.
+ * forward request to DS
+ */
+ dc_link_dp_set_test_pattern(
+ link,
+ test_pattern,
+ DP_TEST_PATTERN_COLOR_SPACE_UNDEFINED,
+ &link_training_settings,
+ test_pattern_buffer,
+ test_pattern_size);
+}
+
+static void set_crtc_test_pattern(struct dc_link *link,
+ struct pipe_ctx *pipe_ctx,
+ enum dp_test_pattern test_pattern,
+ enum dp_test_pattern_color_space test_pattern_color_space)
+{
+ enum controller_dp_test_pattern controller_test_pattern;
+ enum dc_color_depth color_depth = pipe_ctx->
+ stream->timing.display_color_depth;
+ struct bit_depth_reduction_params params;
+ struct output_pixel_processor *opp = pipe_ctx->stream_res.opp;
+ int width = pipe_ctx->stream->timing.h_addressable +
+ pipe_ctx->stream->timing.h_border_left +
+ pipe_ctx->stream->timing.h_border_right;
+ int height = pipe_ctx->stream->timing.v_addressable +
+ pipe_ctx->stream->timing.v_border_bottom +
+ pipe_ctx->stream->timing.v_border_top;
+
+ memset(&params, 0, sizeof(params));
+
+ switch (test_pattern) {
+ case DP_TEST_PATTERN_COLOR_SQUARES:
+ controller_test_pattern =
+ CONTROLLER_DP_TEST_PATTERN_COLORSQUARES;
+ break;
+ case DP_TEST_PATTERN_COLOR_SQUARES_CEA:
+ controller_test_pattern =
+ CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA;
+ break;
+ case DP_TEST_PATTERN_VERTICAL_BARS:
+ controller_test_pattern =
+ CONTROLLER_DP_TEST_PATTERN_VERTICALBARS;
+ break;
+ case DP_TEST_PATTERN_HORIZONTAL_BARS:
+ controller_test_pattern =
+ CONTROLLER_DP_TEST_PATTERN_HORIZONTALBARS;
+ break;
+ case DP_TEST_PATTERN_COLOR_RAMP:
+ controller_test_pattern =
+ CONTROLLER_DP_TEST_PATTERN_COLORRAMP;
+ break;
+ default:
+ controller_test_pattern =
+ CONTROLLER_DP_TEST_PATTERN_VIDEOMODE;
+ break;
+ }
+
+ switch (test_pattern) {
+ case DP_TEST_PATTERN_COLOR_SQUARES:
+ case DP_TEST_PATTERN_COLOR_SQUARES_CEA:
+ case DP_TEST_PATTERN_VERTICAL_BARS:
+ case DP_TEST_PATTERN_HORIZONTAL_BARS:
+ case DP_TEST_PATTERN_COLOR_RAMP:
+ {
+ /* disable bit depth reduction */
+ pipe_ctx->stream->bit_depth_params = params;
+ opp->funcs->opp_program_bit_depth_reduction(opp, &params);
+ if (pipe_ctx->stream_res.tg->funcs->set_test_pattern)
+ pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg,
+ controller_test_pattern, color_depth);
+ else if (link->dc->hwss.set_disp_pattern_generator) {
+ struct pipe_ctx *odm_pipe;
+ enum controller_dp_color_space controller_color_space;
+ int opp_cnt = 1;
+ int offset = 0;
+ int dpg_width = width;
+
+ switch (test_pattern_color_space) {
+ case DP_TEST_PATTERN_COLOR_SPACE_RGB:
+ controller_color_space = CONTROLLER_DP_COLOR_SPACE_RGB;
+ break;
+ case DP_TEST_PATTERN_COLOR_SPACE_YCBCR601:
+ controller_color_space = CONTROLLER_DP_COLOR_SPACE_YCBCR601;
+ break;
+ case DP_TEST_PATTERN_COLOR_SPACE_YCBCR709:
+ controller_color_space = CONTROLLER_DP_COLOR_SPACE_YCBCR709;
+ break;
+ case DP_TEST_PATTERN_COLOR_SPACE_UNDEFINED:
+ default:
+ controller_color_space = CONTROLLER_DP_COLOR_SPACE_UDEFINED;
+ DC_LOG_ERROR("%s: Color space must be defined for test pattern", __func__);
+ ASSERT(0);
+ break;
+ }
+
+ for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
+ opp_cnt++;
+ dpg_width = width / opp_cnt;
+ offset = dpg_width;
+
+ link->dc->hwss.set_disp_pattern_generator(link->dc,
+ pipe_ctx,
+ controller_test_pattern,
+ controller_color_space,
+ color_depth,
+ NULL,
+ dpg_width,
+ height,
+ 0);
+
+ for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
+ struct output_pixel_processor *odm_opp = odm_pipe->stream_res.opp;
+
+ odm_opp->funcs->opp_program_bit_depth_reduction(odm_opp, &params);
+ link->dc->hwss.set_disp_pattern_generator(link->dc,
+ odm_pipe,
+ controller_test_pattern,
+ controller_color_space,
+ color_depth,
+ NULL,
+ dpg_width,
+ height,
+ offset);
+ offset += offset;
+ }
+ }
+ }
+ break;
+ case DP_TEST_PATTERN_VIDEO_MODE:
+ {
+ /* restore bitdepth reduction */
+ resource_build_bit_depth_reduction_params(pipe_ctx->stream, &params);
+ pipe_ctx->stream->bit_depth_params = params;
+ opp->funcs->opp_program_bit_depth_reduction(opp, &params);
+ if (pipe_ctx->stream_res.tg->funcs->set_test_pattern)
+ pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg,
+ CONTROLLER_DP_TEST_PATTERN_VIDEOMODE,
+ color_depth);
+ else if (link->dc->hwss.set_disp_pattern_generator) {
+ struct pipe_ctx *odm_pipe;
+ int opp_cnt = 1;
+ int dpg_width;
+
+ for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
+ opp_cnt++;
+
+ dpg_width = width / opp_cnt;
+ for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
+ struct output_pixel_processor *odm_opp = odm_pipe->stream_res.opp;
+
+ odm_opp->funcs->opp_program_bit_depth_reduction(odm_opp, &params);
+ link->dc->hwss.set_disp_pattern_generator(link->dc,
+ odm_pipe,
+ CONTROLLER_DP_TEST_PATTERN_VIDEOMODE,
+ CONTROLLER_DP_COLOR_SPACE_UDEFINED,
+ color_depth,
+ NULL,
+ dpg_width,
+ height,
+ 0);
+ }
+ link->dc->hwss.set_disp_pattern_generator(link->dc,
+ pipe_ctx,
+ CONTROLLER_DP_TEST_PATTERN_VIDEOMODE,
+ CONTROLLER_DP_COLOR_SPACE_UDEFINED,
+ color_depth,
+ NULL,
+ dpg_width,
+ height,
+ 0);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void dc_link_dp_handle_automated_test(struct dc_link *link)
+{
+ union test_request test_request;
+ union test_response test_response;
+
+ memset(&test_request, 0, sizeof(test_request));
+ memset(&test_response, 0, sizeof(test_response));
+
+ core_link_read_dpcd(
+ link,
+ DP_TEST_REQUEST,
+ &test_request.raw,
+ sizeof(union test_request));
+ if (test_request.bits.LINK_TRAINING) {
+ /* ACK first to let DP RX test box monitor LT sequence */
+ test_response.bits.ACK = 1;
+ core_link_write_dpcd(
+ link,
+ DP_TEST_RESPONSE,
+ &test_response.raw,
+ sizeof(test_response));
+ dp_test_send_link_training(link);
+ /* no acknowledge request is needed again */
+ test_response.bits.ACK = 0;
+ }
+ if (test_request.bits.LINK_TEST_PATTRN) {
+ union test_misc dpcd_test_params;
+ union link_test_pattern dpcd_test_pattern;
+
+ memset(&dpcd_test_pattern, 0, sizeof(dpcd_test_pattern));
+ memset(&dpcd_test_params, 0, sizeof(dpcd_test_params));
+
+ /* get link test pattern and pattern parameters */
+ core_link_read_dpcd(
+ link,
+ DP_TEST_PATTERN,
+ &dpcd_test_pattern.raw,
+ sizeof(dpcd_test_pattern));
+ core_link_read_dpcd(
+ link,
+ DP_TEST_MISC0,
+ &dpcd_test_params.raw,
+ sizeof(dpcd_test_params));
+ test_response.bits.ACK = dm_helpers_dp_handle_test_pattern_request(link->ctx, link,
+ dpcd_test_pattern, dpcd_test_params) ? 1 : 0;
+ }
+
+ if (test_request.bits.AUDIO_TEST_PATTERN) {
+ dp_test_get_audio_test_data(link, test_request.bits.TEST_AUDIO_DISABLED_VIDEO);
+ test_response.bits.ACK = 1;
+ }
+
+ if (test_request.bits.PHY_TEST_PATTERN) {
+ dp_test_send_phy_test_pattern(link);
+ test_response.bits.ACK = 1;
+ }
+
+ /* send request acknowledgment */
+ if (test_response.bits.ACK)
+ core_link_write_dpcd(
+ link,
+ DP_TEST_RESPONSE,
+ &test_response.raw,
+ sizeof(test_response));
+}
+
+bool dc_link_dp_set_test_pattern(
+ struct dc_link *link,
+ enum dp_test_pattern test_pattern,
+ enum dp_test_pattern_color_space test_pattern_color_space,
+ const struct link_training_settings *p_link_settings,
+ const unsigned char *p_custom_pattern,
+ unsigned int cust_pattern_size)
+{
+ struct pipe_ctx *pipes = link->dc->current_state->res_ctx.pipe_ctx;
+ struct pipe_ctx *pipe_ctx = NULL;
+ unsigned int lane;
+ unsigned int i;
+ unsigned char link_qual_pattern[LANE_COUNT_DP_MAX] = {0};
+ union dpcd_training_pattern training_pattern;
+ enum dpcd_phy_test_patterns pattern;
+
+ memset(&training_pattern, 0, sizeof(training_pattern));
+
+ for (i = 0; i < MAX_PIPES; i++) {
+ if (pipes[i].stream == NULL)
+ continue;
+
+ if (pipes[i].stream->link == link && !pipes[i].top_pipe && !pipes[i].prev_odm_pipe) {
+ pipe_ctx = &pipes[i];
+ break;
+ }
+ }
+
+ if (pipe_ctx == NULL)
+ return false;
+
+ /* Reset CRTC Test Pattern if it is currently running and request is VideoMode */
+ if (link->test_pattern_enabled && test_pattern ==
+ DP_TEST_PATTERN_VIDEO_MODE) {
+ /* Set CRTC Test Pattern */
+ set_crtc_test_pattern(link, pipe_ctx, test_pattern, test_pattern_color_space);
+ dp_set_hw_test_pattern(link, &pipe_ctx->link_res, test_pattern,
+ (uint8_t *)p_custom_pattern,
+ (uint32_t)cust_pattern_size);
+
+ /* Unblank Stream */
+ link->dc->hwss.unblank_stream(
+ pipe_ctx,
+ &link->verified_link_cap);
+ /* TODO:m_pHwss->MuteAudioEndpoint
+ * (pPathMode->pDisplayPath, false);
+ */
+
+ /* Reset Test Pattern state */
+ link->test_pattern_enabled = false;
+
+ return true;
+ }
+
+ /* Check for PHY Test Patterns */
+ if (is_dp_phy_pattern(test_pattern)) {
+ /* Set DPCD Lane Settings before running test pattern */
+ if (p_link_settings != NULL) {
+ if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) &&
+ p_link_settings->lttpr_mode == LTTPR_MODE_TRANSPARENT) {
+ dp_fixed_vs_pe_set_retimer_lane_settings(
+ link,
+ p_link_settings->dpcd_lane_settings,
+ p_link_settings->link_settings.lane_count);
+ } else {
+ dp_set_hw_lane_settings(link, &pipe_ctx->link_res, p_link_settings, DPRX);
+ }
+ dpcd_set_lane_settings(link, p_link_settings, DPRX);
+ }
+
+ /* Blank stream if running test pattern */
+ if (test_pattern != DP_TEST_PATTERN_VIDEO_MODE) {
+ /*TODO:
+ * m_pHwss->
+ * MuteAudioEndpoint(pPathMode->pDisplayPath, true);
+ */
+ /* Blank stream */
+ link->dc->hwss.blank_stream(pipe_ctx);
+ }
+
+ dp_set_hw_test_pattern(link, &pipe_ctx->link_res, test_pattern,
+ (uint8_t *)p_custom_pattern,
+ (uint32_t)cust_pattern_size);
+
+ if (test_pattern != DP_TEST_PATTERN_VIDEO_MODE) {
+ /* Set Test Pattern state */
+ link->test_pattern_enabled = true;
+ if (p_link_settings != NULL)
+ dpcd_set_link_settings(link,
+ p_link_settings);
+ }
+
+ switch (test_pattern) {
+ case DP_TEST_PATTERN_VIDEO_MODE:
+ pattern = PHY_TEST_PATTERN_NONE;
+ break;
+ case DP_TEST_PATTERN_D102:
+ pattern = PHY_TEST_PATTERN_D10_2;
+ break;
+ case DP_TEST_PATTERN_SYMBOL_ERROR:
+ pattern = PHY_TEST_PATTERN_SYMBOL_ERROR;
+ break;
+ case DP_TEST_PATTERN_PRBS7:
+ pattern = PHY_TEST_PATTERN_PRBS7;
+ break;
+ case DP_TEST_PATTERN_80BIT_CUSTOM:
+ pattern = PHY_TEST_PATTERN_80BIT_CUSTOM;
+ break;
+ case DP_TEST_PATTERN_CP2520_1:
+ pattern = PHY_TEST_PATTERN_CP2520_1;
+ break;
+ case DP_TEST_PATTERN_CP2520_2:
+ pattern = PHY_TEST_PATTERN_CP2520_2;
+ break;
+ case DP_TEST_PATTERN_CP2520_3:
+ pattern = PHY_TEST_PATTERN_CP2520_3;
+ break;
+ case DP_TEST_PATTERN_128b_132b_TPS1:
+ pattern = PHY_TEST_PATTERN_128b_132b_TPS1;
+ break;
+ case DP_TEST_PATTERN_128b_132b_TPS2:
+ pattern = PHY_TEST_PATTERN_128b_132b_TPS2;
+ break;
+ case DP_TEST_PATTERN_PRBS9:
+ pattern = PHY_TEST_PATTERN_PRBS9;
+ break;
+ case DP_TEST_PATTERN_PRBS11:
+ pattern = PHY_TEST_PATTERN_PRBS11;
+ break;
+ case DP_TEST_PATTERN_PRBS15:
+ pattern = PHY_TEST_PATTERN_PRBS15;
+ break;
+ case DP_TEST_PATTERN_PRBS23:
+ pattern = PHY_TEST_PATTERN_PRBS23;
+ break;
+ case DP_TEST_PATTERN_PRBS31:
+ pattern = PHY_TEST_PATTERN_PRBS31;
+ break;
+ case DP_TEST_PATTERN_264BIT_CUSTOM:
+ pattern = PHY_TEST_PATTERN_264BIT_CUSTOM;
+ break;
+ case DP_TEST_PATTERN_SQUARE:
+ pattern = PHY_TEST_PATTERN_SQUARE;
+ break;
+ case DP_TEST_PATTERN_SQUARE_PRESHOOT_DISABLED:
+ pattern = PHY_TEST_PATTERN_SQUARE_PRESHOOT_DISABLED;
+ break;
+ case DP_TEST_PATTERN_SQUARE_DEEMPHASIS_DISABLED:
+ pattern = PHY_TEST_PATTERN_SQUARE_DEEMPHASIS_DISABLED;
+ break;
+ case DP_TEST_PATTERN_SQUARE_PRESHOOT_DEEMPHASIS_DISABLED:
+ pattern = PHY_TEST_PATTERN_SQUARE_PRESHOOT_DEEMPHASIS_DISABLED;
+ break;
+ default:
+ return false;
+ }
+
+ if (test_pattern == DP_TEST_PATTERN_VIDEO_MODE
+ /*TODO:&& !pPathMode->pDisplayPath->IsTargetPoweredOn()*/)
+ return false;
+
+ if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_12) {
+ if (is_dp_phy_sqaure_pattern(test_pattern))
+ core_link_write_dpcd(link,
+ DP_LINK_SQUARE_PATTERN,
+ p_custom_pattern,
+ 1);
+
+ /* tell receiver that we are sending qualification
+ * pattern DP 1.2 or later - DP receiver's link quality
+ * pattern is set using DPCD LINK_QUAL_LANEx_SET
+ * register (0x10B~0x10E)\
+ */
+ for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++)
+ link_qual_pattern[lane] =
+ (unsigned char)(pattern);
+
+ core_link_write_dpcd(link,
+ DP_LINK_QUAL_LANE0_SET,
+ link_qual_pattern,
+ sizeof(link_qual_pattern));
+ } else if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_10 ||
+ link->dpcd_caps.dpcd_rev.raw == 0) {
+ /* tell receiver that we are sending qualification
+ * pattern DP 1.1a or earlier - DP receiver's link
+ * quality pattern is set using
+ * DPCD TRAINING_PATTERN_SET -> LINK_QUAL_PATTERN_SET
+ * register (0x102). We will use v_1.3 when we are
+ * setting test pattern for DP 1.1.
+ */
+ core_link_read_dpcd(link, DP_TRAINING_PATTERN_SET,
+ &training_pattern.raw,
+ sizeof(training_pattern));
+ training_pattern.v1_3.LINK_QUAL_PATTERN_SET = pattern;
+ core_link_write_dpcd(link, DP_TRAINING_PATTERN_SET,
+ &training_pattern.raw,
+ sizeof(training_pattern));
+ }
+ } else {
+ enum dc_color_space color_space = COLOR_SPACE_UNKNOWN;
+
+ switch (test_pattern_color_space) {
+ case DP_TEST_PATTERN_COLOR_SPACE_RGB:
+ color_space = COLOR_SPACE_SRGB;
+ if (test_pattern == DP_TEST_PATTERN_COLOR_SQUARES_CEA)
+ color_space = COLOR_SPACE_SRGB_LIMITED;
+ break;
+
+ case DP_TEST_PATTERN_COLOR_SPACE_YCBCR601:
+ color_space = COLOR_SPACE_YCBCR601;
+ if (test_pattern == DP_TEST_PATTERN_COLOR_SQUARES_CEA)
+ color_space = COLOR_SPACE_YCBCR601_LIMITED;
+ break;
+ case DP_TEST_PATTERN_COLOR_SPACE_YCBCR709:
+ color_space = COLOR_SPACE_YCBCR709;
+ if (test_pattern == DP_TEST_PATTERN_COLOR_SQUARES_CEA)
+ color_space = COLOR_SPACE_YCBCR709_LIMITED;
+ break;
+ default:
+ break;
+ }
+
+ if (pipe_ctx->stream_res.tg->funcs->lock_doublebuffer_enable) {
+ if (pipe_ctx->stream && should_use_dmub_lock(pipe_ctx->stream->link)) {
+ union dmub_hw_lock_flags hw_locks = { 0 };
+ struct dmub_hw_lock_inst_flags inst_flags = { 0 };
+
+ hw_locks.bits.lock_dig = 1;
+ inst_flags.dig_inst = pipe_ctx->stream_res.tg->inst;
+
+ dmub_hw_lock_mgr_cmd(link->ctx->dmub_srv,
+ true,
+ &hw_locks,
+ &inst_flags);
+ } else
+ pipe_ctx->stream_res.tg->funcs->lock_doublebuffer_enable(
+ pipe_ctx->stream_res.tg);
+ }
+
+ pipe_ctx->stream_res.tg->funcs->lock(pipe_ctx->stream_res.tg);
+ /* update MSA to requested color space */
+ pipe_ctx->stream_res.stream_enc->funcs->dp_set_stream_attribute(pipe_ctx->stream_res.stream_enc,
+ &pipe_ctx->stream->timing,
+ color_space,
+ pipe_ctx->stream->use_vsc_sdp_for_colorimetry,
+ link->dpcd_caps.dprx_feature.bits.SST_SPLIT_SDP_CAP);
+
+ if (pipe_ctx->stream->use_vsc_sdp_for_colorimetry) {
+ if (test_pattern == DP_TEST_PATTERN_COLOR_SQUARES_CEA)
+ pipe_ctx->stream->vsc_infopacket.sb[17] |= (1 << 7); // sb17 bit 7 Dynamic Range: 0 = VESA range, 1 = CTA range
+ else
+ pipe_ctx->stream->vsc_infopacket.sb[17] &= ~(1 << 7);
+ resource_build_info_frame(pipe_ctx);
+ link->dc->hwss.update_info_frame(pipe_ctx);
+ }
+
+ /* CRTC Patterns */
+ set_crtc_test_pattern(link, pipe_ctx, test_pattern, test_pattern_color_space);
+ pipe_ctx->stream_res.tg->funcs->unlock(pipe_ctx->stream_res.tg);
+ pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg,
+ CRTC_STATE_VACTIVE);
+ pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg,
+ CRTC_STATE_VBLANK);
+ pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg,
+ CRTC_STATE_VACTIVE);
+
+ if (pipe_ctx->stream_res.tg->funcs->lock_doublebuffer_disable) {
+ if (pipe_ctx->stream && should_use_dmub_lock(pipe_ctx->stream->link)) {
+ union dmub_hw_lock_flags hw_locks = { 0 };
+ struct dmub_hw_lock_inst_flags inst_flags = { 0 };
+
+ hw_locks.bits.lock_dig = 1;
+ inst_flags.dig_inst = pipe_ctx->stream_res.tg->inst;
+
+ dmub_hw_lock_mgr_cmd(link->ctx->dmub_srv,
+ false,
+ &hw_locks,
+ &inst_flags);
+ } else
+ pipe_ctx->stream_res.tg->funcs->lock_doublebuffer_disable(
+ pipe_ctx->stream_res.tg);
+ }
+
+ /* Set Test Pattern state */
+ link->test_pattern_enabled = true;
+ }
+
+ return true;
+}
+
+void dc_link_set_drive_settings(struct dc *dc,
+ struct link_training_settings *lt_settings,
+ const struct dc_link *link)
+{
+
+ int i;
+ struct link_resource link_res;
+
+ for (i = 0; i < dc->link_count; i++)
+ if (dc->links[i] == link)
+ break;
+
+ if (i >= dc->link_count)
+ ASSERT_CRITICAL(false);
+
+ link_get_cur_link_res(link, &link_res);
+ dp_set_drive_settings(dc->links[i], &link_res, lt_settings);
+}
+
+void dc_link_set_preferred_link_settings(struct dc *dc,
+ struct dc_link_settings *link_setting,
+ struct dc_link *link)
+{
+ int i;
+ struct pipe_ctx *pipe;
+ struct dc_stream_state *link_stream;
+ struct dc_link_settings store_settings = *link_setting;
+
+ link->preferred_link_setting = store_settings;
+
+ /* Retrain with preferred link settings only relevant for
+ * DP signal type
+ * Check for non-DP signal or if passive dongle present
+ */
+ if (!dc_is_dp_signal(link->connector_signal) ||
+ link->dongle_max_pix_clk > 0)
+ return;
+
+ for (i = 0; i < MAX_PIPES; i++) {
+ pipe = &dc->current_state->res_ctx.pipe_ctx[i];
+ if (pipe->stream && pipe->stream->link) {
+ if (pipe->stream->link == link) {
+ link_stream = pipe->stream;
+ break;
+ }
+ }
+ }
+
+ /* Stream not found */
+ if (i == MAX_PIPES)
+ return;
+
+ /* Cannot retrain link if backend is off */
+ if (link_stream->dpms_off)
+ return;
+
+ if (link_decide_link_settings(link_stream, &store_settings))
+ dp_retrain_link_dp_test(link, &store_settings, false);
+}
+
+void dc_link_set_preferred_training_settings(struct dc *dc,
+ struct dc_link_settings *link_setting,
+ struct dc_link_training_overrides *lt_overrides,
+ struct dc_link *link,
+ bool skip_immediate_retrain)
+{
+ if (lt_overrides != NULL)
+ link->preferred_training_settings = *lt_overrides;
+ else
+ memset(&link->preferred_training_settings, 0, sizeof(link->preferred_training_settings));
+
+ if (link_setting != NULL) {
+ link->preferred_link_setting = *link_setting;
+ } else {
+ link->preferred_link_setting.lane_count = LANE_COUNT_UNKNOWN;
+ link->preferred_link_setting.link_rate = LINK_RATE_UNKNOWN;
+ }
+
+ if (link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT &&
+ link->type == dc_connection_mst_branch)
+ dm_helpers_dp_mst_update_branch_bandwidth(dc->ctx, link);
+
+ /* Retrain now, or wait until next stream update to apply */
+ if (skip_immediate_retrain == false)
+ dc_link_set_preferred_link_settings(dc, &link->preferred_link_setting, link);
+}
+
+void dc_link_set_test_pattern(struct dc_link *link,
+ enum dp_test_pattern test_pattern,
+ enum dp_test_pattern_color_space test_pattern_color_space,
+ const struct link_training_settings *p_link_settings,
+ const unsigned char *p_custom_pattern,
+ unsigned int cust_pattern_size)
+{
+ if (link != NULL)
+ dc_link_dp_set_test_pattern(
+ link,
+ test_pattern,
+ test_pattern_color_space,
+ p_link_settings,
+ p_custom_pattern,
+ cust_pattern_size);
+}
diff --git a/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.h b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.h
new file mode 100644
index 000000000000..7f17838b653b
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2023 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+#ifndef __LINK_DP_CTS_H__
+#define __LINK_DP_CTS_H__
+#include "link.h"
+
+void dp_retrain_link_dp_test(struct dc_link *link,
+ struct dc_link_settings *link_setting,
+ bool skip_video_pattern);
+
+#endif /* __LINK_DP_CTS_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_trace.c b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_trace.c
index 2c1a3bfcdb50..459b362ed374 100644
--- a/drivers/gpu/drm/amd/display/dc/link/link_dp_trace.c
+++ b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_trace.c
@@ -22,8 +22,9 @@
* Authors: AMD
*
*/
-#include "dc_link.h"
#include "link_dp_trace.h"
+#include "link/protocols/link_dpcd.h"
+#include "link.h"
void dp_trace_init(struct dc_link *link)
{
@@ -145,7 +146,7 @@ unsigned int dc_dp_trace_get_link_loss_count(struct dc_link *link)
return link->dp_trace.link_loss_count;
}
-void dp_trace_set_edp_power_timestamp(struct dc_link *link,
+void link_dp_trace_set_edp_power_timestamp(struct dc_link *link,
bool power_up)
{
if (!power_up)
@@ -155,12 +156,19 @@ void dp_trace_set_edp_power_timestamp(struct dc_link *link,
link->dp_trace.edp_trace_power_timestamps.poweron = dm_get_timestamp(link->dc->ctx);
}
-uint64_t dp_trace_get_edp_poweron_timestamp(struct dc_link *link)
+uint64_t link_dp_trace_get_edp_poweron_timestamp(struct dc_link *link)
{
return link->dp_trace.edp_trace_power_timestamps.poweron;
}
-uint64_t dp_trace_get_edp_poweroff_timestamp(struct dc_link *link)
+uint64_t link_dp_trace_get_edp_poweroff_timestamp(struct dc_link *link)
{
return link->dp_trace.edp_trace_power_timestamps.poweroff;
-} \ No newline at end of file
+}
+
+void link_dp_source_sequence_trace(struct dc_link *link, uint8_t dp_test_mode)
+{
+ if (link != NULL && link->dc->debug.enable_driver_sequence_debug)
+ core_link_write_dpcd(link, DP_SOURCE_SEQUENCE,
+ &dp_test_mode, sizeof(dp_test_mode));
+}
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_trace.h b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_trace.h
index 26700e3cd65e..89feea1b2692 100644
--- a/drivers/gpu/drm/amd/display/dc/link/link_dp_trace.h
+++ b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_trace.h
@@ -24,6 +24,7 @@
*/
#ifndef __LINK_DP_TRACE_H__
#define __LINK_DP_TRACE_H__
+#include "link.h"
void dp_trace_init(struct dc_link *link);
void dp_trace_reset(struct dc_link *link);
@@ -54,9 +55,4 @@ struct dp_trace_lt_counts *dc_dp_trace_get_lt_counts(struct dc_link *link,
bool in_detection);
unsigned int dc_dp_trace_get_link_loss_count(struct dc_link *link);
-void dp_trace_set_edp_power_timestamp(struct dc_link *link,
- bool power_up);
-uint64_t dp_trace_get_edp_poweron_timestamp(struct dc_link *link);
-uint64_t dp_trace_get_edp_poweroff_timestamp(struct dc_link *link);
-
#endif /* __LINK_DP_TRACE_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/accessories/link_fpga.c b/drivers/gpu/drm/amd/display/dc/link/accessories/link_fpga.c
new file mode 100644
index 000000000000..d3cc604eed67
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/accessories/link_fpga.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2023 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+#include "link_fpga.h"
+#include "link/link_dpms.h"
+#include "dm_helpers.h"
+#include "link_hwss.h"
+#include "dccg.h"
+#include "resource.h"
+
+#define DC_LOGGER_INIT(logger)
+
+void dp_fpga_hpo_enable_link_and_stream(struct dc_state *state, struct pipe_ctx *pipe_ctx)
+{
+ struct dc *dc = pipe_ctx->stream->ctx->dc;
+ struct dc_stream_state *stream = pipe_ctx->stream;
+ struct link_mst_stream_allocation_table proposed_table = {0};
+ struct fixed31_32 avg_time_slots_per_mtp;
+ uint8_t req_slot_count = 0;
+ uint8_t vc_id = 1; /// VC ID always 1 for SST
+ struct dc_link_settings link_settings = pipe_ctx->link_config.dp_link_settings;
+ const struct link_hwss *link_hwss = get_link_hwss(stream->link, &pipe_ctx->link_res);
+ DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
+
+ stream->link->cur_link_settings = link_settings;
+
+ if (link_hwss->ext.enable_dp_link_output)
+ link_hwss->ext.enable_dp_link_output(stream->link, &pipe_ctx->link_res,
+ stream->signal, pipe_ctx->clock_source->id,
+ &link_settings);
+
+ /* Enable DP_STREAM_ENC */
+ dc->hwss.enable_stream(pipe_ctx);
+
+ /* Set DPS PPS SDP (AKA "info frames") */
+ if (pipe_ctx->stream->timing.flags.DSC) {
+ link_set_dsc_pps_packet(pipe_ctx, true, true);
+ }
+
+ /* Allocate Payload */
+ if ((stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) && (state->stream_count > 1)) {
+ // MST case
+ uint8_t i;
+
+ proposed_table.stream_count = state->stream_count;
+ for (i = 0; i < state->stream_count; i++) {
+ avg_time_slots_per_mtp = link_calculate_sst_avg_time_slots_per_mtp(state->streams[i], state->streams[i]->link);
+ req_slot_count = dc_fixpt_ceil(avg_time_slots_per_mtp);
+ proposed_table.stream_allocations[i].slot_count = req_slot_count;
+ proposed_table.stream_allocations[i].vcp_id = i+1;
+ /* NOTE: This makes assumption that pipe_ctx index is same as stream index */
+ proposed_table.stream_allocations[i].hpo_dp_stream_enc = state->res_ctx.pipe_ctx[i].stream_res.hpo_dp_stream_enc;
+ }
+ } else {
+ // SST case
+ avg_time_slots_per_mtp = link_calculate_sst_avg_time_slots_per_mtp(stream, stream->link);
+ req_slot_count = dc_fixpt_ceil(avg_time_slots_per_mtp);
+ proposed_table.stream_count = 1; /// Always 1 stream for SST
+ proposed_table.stream_allocations[0].slot_count = req_slot_count;
+ proposed_table.stream_allocations[0].vcp_id = vc_id;
+ proposed_table.stream_allocations[0].hpo_dp_stream_enc = pipe_ctx->stream_res.hpo_dp_stream_enc;
+ }
+
+ link_hwss->ext.update_stream_allocation_table(stream->link,
+ &pipe_ctx->link_res,
+ &proposed_table);
+
+ if (link_hwss->ext.set_throttled_vcp_size)
+ link_hwss->ext.set_throttled_vcp_size(pipe_ctx, avg_time_slots_per_mtp);
+
+ dc->hwss.unblank_stream(pipe_ctx, &stream->link->cur_link_settings);
+ dc->hwss.enable_audio_stream(pipe_ctx);
+}
+
diff --git a/drivers/gpu/drm/amd/display/dc/link/accessories/link_fpga.h b/drivers/gpu/drm/amd/display/dc/link/accessories/link_fpga.h
new file mode 100644
index 000000000000..3a80f5595943
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/accessories/link_fpga.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2023 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+#ifndef __LINK_FPGA_H__
+#define __LINK_FPGA_H__
+#include "link.h"
+void dp_fpga_hpo_enable_link_and_stream(struct dc_state *state,
+ struct pipe_ctx *pipe_ctx);
+#endif /* __LINK_FPGA_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.c b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dio.c
index 33148b753c03..b092b00b3599 100644
--- a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.c
+++ b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dio.c
@@ -24,7 +24,6 @@
*/
#include "link_hwss_dio.h"
#include "core_types.h"
-#include "dc_link_dp.h"
#include "link_enc_cfg.h"
void set_dio_throttled_vcp_size(struct pipe_ctx *pipe_ctx,
@@ -45,7 +44,7 @@ void setup_dio_stream_encoder(struct pipe_ctx *pipe_ctx)
link_enc->funcs->connect_dig_be_to_fe(link_enc,
pipe_ctx->stream_res.stream_enc->id, true);
if (dc_is_dp_signal(pipe_ctx->stream->signal))
- dp_source_sequence_trace(pipe_ctx->stream->link,
+ link_dp_source_sequence_trace(pipe_ctx->stream->link,
DPCD_SOURCE_SEQ_AFTER_CONNECT_DIG_FE_BE);
if (stream_enc->funcs->enable_fifo)
stream_enc->funcs->enable_fifo(stream_enc);
@@ -64,7 +63,7 @@ void reset_dio_stream_encoder(struct pipe_ctx *pipe_ctx)
pipe_ctx->stream_res.stream_enc->id,
false);
if (dc_is_dp_signal(pipe_ctx->stream->signal))
- dp_source_sequence_trace(pipe_ctx->stream->link,
+ link_dp_source_sequence_trace(pipe_ctx->stream->link,
DPCD_SOURCE_SEQ_AFTER_DISCONNECT_DIG_FE_BE);
}
@@ -106,7 +105,7 @@ void setup_dio_stream_attribute(struct pipe_ctx *pipe_ctx)
&stream->timing);
if (dc_is_dp_signal(stream->signal))
- dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DP_STREAM_ATTR);
+ link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DP_STREAM_ATTR);
}
void enable_dio_dp_link_output(struct dc_link *link,
@@ -127,7 +126,7 @@ void enable_dio_dp_link_output(struct dc_link *link,
link_enc,
link_settings,
clock_source);
- dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_LINK_PHY);
+ link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_LINK_PHY);
}
void disable_dio_link_output(struct dc_link *link,
@@ -137,7 +136,7 @@ void disable_dio_link_output(struct dc_link *link,
struct link_encoder *link_enc = link_enc_cfg_get_link_enc(link);
link_enc->funcs->disable_output(link_enc, signal);
- dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY);
+ link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY);
}
void set_dio_dp_link_test_pattern(struct dc_link *link,
@@ -147,7 +146,7 @@ void set_dio_dp_link_test_pattern(struct dc_link *link,
struct link_encoder *link_enc = link_enc_cfg_get_link_enc(link);
link_enc->funcs->dp_set_phy_pattern(link_enc, tp_params);
- dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_SET_SOURCE_PATTERN);
+ link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_SET_SOURCE_PATTERN);
}
void set_dio_dp_lane_settings(struct dc_link *link,
@@ -196,7 +195,7 @@ void enable_dio_audio_packet(struct pipe_ctx *pipe_ctx)
pipe_ctx->stream_res.stream_enc, false);
if (dc_is_dp_signal(pipe_ctx->stream->signal))
- dp_source_sequence_trace(pipe_ctx->stream->link,
+ link_dp_source_sequence_trace(pipe_ctx->stream->link,
DPCD_SOURCE_SEQ_AFTER_ENABLE_AUDIO_STREAM);
}
@@ -215,7 +214,7 @@ void disable_dio_audio_packet(struct pipe_ctx *pipe_ctx)
}
if (dc_is_dp_signal(pipe_ctx->stream->signal))
- dp_source_sequence_trace(pipe_ctx->stream->link,
+ link_dp_source_sequence_trace(pipe_ctx->stream->link,
DPCD_SOURCE_SEQ_AFTER_DISABLE_AUDIO_STREAM);
}
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.h b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dio.h
index 9a108c3d7831..8b8a099feeb0 100644
--- a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.h
+++ b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dio.h
@@ -26,6 +26,7 @@
#define __LINK_HWSS_DIO_H__
#include "link_hwss.h"
+#include "link.h"
const struct link_hwss *get_dio_link_hwss(void);
bool can_use_dio_link_hwss(const struct dc_link *link,
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dpia.c b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dpia.c
index 861f3cd5b356..861f3cd5b356 100644
--- a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dpia.c
+++ b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dpia.c
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dpia.h b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dpia.h
index ad16ec5d9bb7..ad16ec5d9bb7 100644
--- a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dpia.h
+++ b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dpia.h
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.c b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.c
index 2f46e1ac4ce0..aa1c5e253b43 100644
--- a/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.c
+++ b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.c
@@ -26,7 +26,6 @@
#include "dm_helpers.h"
#include "core_types.h"
#include "dccg.h"
-#include "dc_link_dp.h"
#include "clk_mgr.h"
static enum phyd32clk_clock_source get_phyd32clk_src(struct dc_link *link)
@@ -87,57 +86,20 @@ static void set_hpo_dp_hblank_min_symbol_width(struct pipe_ctx *pipe_ctx,
hblank_min_symbol_width);
}
-static int get_odm_segment_count(struct pipe_ctx *pipe_ctx)
-{
- struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe;
- int count = 1;
-
- while (odm_pipe != NULL) {
- count++;
- odm_pipe = odm_pipe->next_odm_pipe;
- }
-
- return count;
-}
-
static void setup_hpo_dp_stream_encoder(struct pipe_ctx *pipe_ctx)
{
- struct dc *dc = pipe_ctx->stream->ctx->dc;
struct hpo_dp_stream_encoder *stream_enc = pipe_ctx->stream_res.hpo_dp_stream_enc;
struct hpo_dp_link_encoder *link_enc = pipe_ctx->link_res.hpo_dp_link_enc;
- struct dccg *dccg = dc->res_pool->dccg;
- struct timing_generator *tg = pipe_ctx->stream_res.tg;
- struct dtbclk_dto_params dto_params = {0};
- enum phyd32clk_clock_source phyd32clk = get_phyd32clk_src(pipe_ctx->stream->link);
- dto_params.otg_inst = tg->inst;
- dto_params.pixclk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10;
- dto_params.num_odm_segments = get_odm_segment_count(pipe_ctx);
- dto_params.timing = &pipe_ctx->stream->timing;
- dto_params.ref_dtbclk_khz = dc->clk_mgr->funcs->get_dtb_ref_clk_frequency(dc->clk_mgr);
-
- dccg->funcs->set_dpstreamclk(dccg, DTBCLK0, tg->inst, stream_enc->inst);
- dccg->funcs->enable_symclk32_se(dccg, stream_enc->inst, phyd32clk);
- dccg->funcs->set_dtbclk_dto(dccg, &dto_params);
stream_enc->funcs->enable_stream(stream_enc);
stream_enc->funcs->map_stream_to_link(stream_enc, stream_enc->inst, link_enc->inst);
}
static void reset_hpo_dp_stream_encoder(struct pipe_ctx *pipe_ctx)
{
- struct dc *dc = pipe_ctx->stream->ctx->dc;
struct hpo_dp_stream_encoder *stream_enc = pipe_ctx->stream_res.hpo_dp_stream_enc;
- struct dccg *dccg = dc->res_pool->dccg;
- struct timing_generator *tg = pipe_ctx->stream_res.tg;
- struct dtbclk_dto_params dto_params = {0};
-
- dto_params.otg_inst = tg->inst;
- dto_params.timing = &pipe_ctx->stream->timing;
stream_enc->funcs->disable(stream_enc);
- dccg->funcs->set_dtbclk_dto(dccg, &dto_params);
- dccg->funcs->disable_symclk32_se(dccg, stream_enc->inst);
- dccg->funcs->set_dpstreamclk(dccg, REFCLK, tg->inst, stream_enc->inst);
}
static void setup_hpo_dp_stream_attribute(struct pipe_ctx *pipe_ctx)
@@ -153,7 +115,7 @@ static void setup_hpo_dp_stream_attribute(struct pipe_ctx *pipe_ctx)
stream->use_vsc_sdp_for_colorimetry,
stream->timing.flags.DSC,
false);
- dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DP_STREAM_ATTR);
+ link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DP_STREAM_ATTR);
}
static void enable_hpo_dp_fpga_link_output(struct dc_link *link,
@@ -239,7 +201,7 @@ static void set_hpo_dp_link_test_pattern(struct dc_link *link,
{
link_res->hpo_dp_link_enc->funcs->set_link_test_pattern(
link_res->hpo_dp_link_enc, tp_params);
- dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_SET_SOURCE_PATTERN);
+ link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_SET_SOURCE_PATTERN);
}
static void set_hpo_dp_lane_settings(struct dc_link *link,
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.h b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.h
index 57d447ec27b8..3cbb94b41a23 100644
--- a/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.h
+++ b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.h
@@ -26,6 +26,7 @@
#define __LINK_HWSS_HPO_DP_H__
#include "link_hwss.h"
+#include "link.h"
bool can_use_hpo_dp_link_hwss(const struct dc_link *link,
const struct link_resource *link_res);
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_detection.c b/drivers/gpu/drm/amd/display/dc/link/link_detection.c
new file mode 100644
index 000000000000..38216c789d77
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/link_detection.c
@@ -0,0 +1,1323 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+
+/* FILE POLICY AND INTENDED USAGE:
+ * This file manages link detection states and receiver states by using various
+ * link protocols. It also provides helper functions to interpret certain
+ * capabilities or status based on the states it manages or retrieve them
+ * directly from connected receivers.
+ */
+
+#include "link_dpms.h"
+#include "link_detection.h"
+#include "link_hwss.h"
+#include "protocols/link_edp_panel_control.h"
+#include "protocols/link_ddc.h"
+#include "protocols/link_hpd.h"
+#include "protocols/link_dpcd.h"
+#include "protocols/link_dp_capability.h"
+#include "protocols/link_dp_dpia.h"
+#include "protocols/link_dp_phy.h"
+#include "protocols/link_dp_training.h"
+#include "accessories/link_dp_trace.h"
+
+#include "link_enc_cfg.h"
+#include "dm_helpers.h"
+#include "clk_mgr.h"
+
+#define DC_LOGGER_INIT(logger)
+
+#define LINK_INFO(...) \
+ DC_LOG_HW_HOTPLUG( \
+ __VA_ARGS__)
+/*
+ * Some receivers fail to train on first try and are good
+ * on subsequent tries. 2 retries should be plenty. If we
+ * don't have a successful training then we don't expect to
+ * ever get one.
+ */
+#define LINK_TRAINING_MAX_VERIFY_RETRY 2
+
+static enum ddc_transaction_type get_ddc_transaction_type(enum signal_type sink_signal)
+{
+ enum ddc_transaction_type transaction_type = DDC_TRANSACTION_TYPE_NONE;
+
+ switch (sink_signal) {
+ case SIGNAL_TYPE_DVI_SINGLE_LINK:
+ case SIGNAL_TYPE_DVI_DUAL_LINK:
+ case SIGNAL_TYPE_HDMI_TYPE_A:
+ case SIGNAL_TYPE_LVDS:
+ case SIGNAL_TYPE_RGB:
+ transaction_type = DDC_TRANSACTION_TYPE_I2C;
+ break;
+
+ case SIGNAL_TYPE_DISPLAY_PORT:
+ case SIGNAL_TYPE_EDP:
+ transaction_type = DDC_TRANSACTION_TYPE_I2C_OVER_AUX;
+ break;
+
+ case SIGNAL_TYPE_DISPLAY_PORT_MST:
+ /* MST does not use I2COverAux, but there is the
+ * SPECIAL use case for "immediate dwnstrm device
+ * access" (EPR#370830).
+ */
+ transaction_type = DDC_TRANSACTION_TYPE_I2C_OVER_AUX;
+ break;
+
+ default:
+ break;
+ }
+
+ return transaction_type;
+}
+
+static enum signal_type get_basic_signal_type(struct graphics_object_id encoder,
+ struct graphics_object_id downstream)
+{
+ if (downstream.type == OBJECT_TYPE_CONNECTOR) {
+ switch (downstream.id) {
+ case CONNECTOR_ID_SINGLE_LINK_DVII:
+ switch (encoder.id) {
+ case ENCODER_ID_INTERNAL_DAC1:
+ case ENCODER_ID_INTERNAL_KLDSCP_DAC1:
+ case ENCODER_ID_INTERNAL_DAC2:
+ case ENCODER_ID_INTERNAL_KLDSCP_DAC2:
+ return SIGNAL_TYPE_RGB;
+ default:
+ return SIGNAL_TYPE_DVI_SINGLE_LINK;
+ }
+ break;
+ case CONNECTOR_ID_DUAL_LINK_DVII:
+ {
+ switch (encoder.id) {
+ case ENCODER_ID_INTERNAL_DAC1:
+ case ENCODER_ID_INTERNAL_KLDSCP_DAC1:
+ case ENCODER_ID_INTERNAL_DAC2:
+ case ENCODER_ID_INTERNAL_KLDSCP_DAC2:
+ return SIGNAL_TYPE_RGB;
+ default:
+ return SIGNAL_TYPE_DVI_DUAL_LINK;
+ }
+ }
+ break;
+ case CONNECTOR_ID_SINGLE_LINK_DVID:
+ return SIGNAL_TYPE_DVI_SINGLE_LINK;
+ case CONNECTOR_ID_DUAL_LINK_DVID:
+ return SIGNAL_TYPE_DVI_DUAL_LINK;
+ case CONNECTOR_ID_VGA:
+ return SIGNAL_TYPE_RGB;
+ case CONNECTOR_ID_HDMI_TYPE_A:
+ return SIGNAL_TYPE_HDMI_TYPE_A;
+ case CONNECTOR_ID_LVDS:
+ return SIGNAL_TYPE_LVDS;
+ case CONNECTOR_ID_DISPLAY_PORT:
+ case CONNECTOR_ID_USBC:
+ return SIGNAL_TYPE_DISPLAY_PORT;
+ case CONNECTOR_ID_EDP:
+ return SIGNAL_TYPE_EDP;
+ default:
+ return SIGNAL_TYPE_NONE;
+ }
+ } else if (downstream.type == OBJECT_TYPE_ENCODER) {
+ switch (downstream.id) {
+ case ENCODER_ID_EXTERNAL_NUTMEG:
+ case ENCODER_ID_EXTERNAL_TRAVIS:
+ return SIGNAL_TYPE_DISPLAY_PORT;
+ default:
+ return SIGNAL_TYPE_NONE;
+ }
+ }
+
+ return SIGNAL_TYPE_NONE;
+}
+
+/*
+ * @brief
+ * Detect output sink type
+ */
+static enum signal_type link_detect_sink_signal_type(struct dc_link *link,
+ enum dc_detect_reason reason)
+{
+ enum signal_type result;
+ struct graphics_object_id enc_id;
+
+ if (link->is_dig_mapping_flexible)
+ enc_id = (struct graphics_object_id){.id = ENCODER_ID_UNKNOWN};
+ else
+ enc_id = link->link_enc->id;
+ result = get_basic_signal_type(enc_id, link->link_id);
+
+ /* Use basic signal type for link without physical connector. */
+ if (link->ep_type != DISPLAY_ENDPOINT_PHY)
+ return result;
+
+ /* Internal digital encoder will detect only dongles
+ * that require digital signal
+ */
+
+ /* Detection mechanism is different
+ * for different native connectors.
+ * LVDS connector supports only LVDS signal;
+ * PCIE is a bus slot, the actual connector needs to be detected first;
+ * eDP connector supports only eDP signal;
+ * HDMI should check straps for audio
+ */
+
+ /* PCIE detects the actual connector on add-on board */
+ if (link->link_id.id == CONNECTOR_ID_PCIE) {
+ /* ZAZTODO implement PCIE add-on card detection */
+ }
+
+ switch (link->link_id.id) {
+ case CONNECTOR_ID_HDMI_TYPE_A: {
+ /* check audio support:
+ * if native HDMI is not supported, switch to DVI
+ */
+ struct audio_support *aud_support =
+ &link->dc->res_pool->audio_support;
+
+ if (!aud_support->hdmi_audio_native)
+ if (link->link_id.id == CONNECTOR_ID_HDMI_TYPE_A)
+ result = SIGNAL_TYPE_DVI_SINGLE_LINK;
+ }
+ break;
+ case CONNECTOR_ID_DISPLAY_PORT:
+ case CONNECTOR_ID_USBC: {
+ /* DP HPD short pulse. Passive DP dongle will not
+ * have short pulse
+ */
+ if (reason != DETECT_REASON_HPDRX) {
+ /* Check whether DP signal detected: if not -
+ * we assume signal is DVI; it could be corrected
+ * to HDMI after dongle detection
+ */
+ if (!dm_helpers_is_dp_sink_present(link))
+ result = SIGNAL_TYPE_DVI_SINGLE_LINK;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return result;
+}
+
+static enum signal_type decide_signal_from_strap_and_dongle_type(enum display_dongle_type dongle_type,
+ struct audio_support *audio_support)
+{
+ enum signal_type signal = SIGNAL_TYPE_NONE;
+
+ switch (dongle_type) {
+ case DISPLAY_DONGLE_DP_HDMI_DONGLE:
+ if (audio_support->hdmi_audio_on_dongle)
+ signal = SIGNAL_TYPE_HDMI_TYPE_A;
+ else
+ signal = SIGNAL_TYPE_DVI_SINGLE_LINK;
+ break;
+ case DISPLAY_DONGLE_DP_DVI_DONGLE:
+ signal = SIGNAL_TYPE_DVI_SINGLE_LINK;
+ break;
+ case DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE:
+ if (audio_support->hdmi_audio_native)
+ signal = SIGNAL_TYPE_HDMI_TYPE_A;
+ else
+ signal = SIGNAL_TYPE_DVI_SINGLE_LINK;
+ break;
+ default:
+ signal = SIGNAL_TYPE_NONE;
+ break;
+ }
+
+ return signal;
+}
+
+static void read_scdc_caps(struct ddc_service *ddc_service,
+ struct dc_sink *sink)
+{
+ uint8_t slave_address = HDMI_SCDC_ADDRESS;
+ uint8_t offset = HDMI_SCDC_MANUFACTURER_OUI;
+
+ link_query_ddc_data(ddc_service, slave_address, &offset,
+ sizeof(offset), sink->scdc_caps.manufacturer_OUI.byte,
+ sizeof(sink->scdc_caps.manufacturer_OUI.byte));
+
+ offset = HDMI_SCDC_DEVICE_ID;
+
+ link_query_ddc_data(ddc_service, slave_address, &offset,
+ sizeof(offset), &(sink->scdc_caps.device_id.byte),
+ sizeof(sink->scdc_caps.device_id.byte));
+}
+
+static bool i2c_read(
+ struct ddc_service *ddc,
+ uint32_t address,
+ uint8_t *buffer,
+ uint32_t len)
+{
+ uint8_t offs_data = 0;
+ struct i2c_payload payloads[2] = {
+ {
+ .write = true,
+ .address = address,
+ .length = 1,
+ .data = &offs_data },
+ {
+ .write = false,
+ .address = address,
+ .length = len,
+ .data = buffer } };
+
+ struct i2c_command command = {
+ .payloads = payloads,
+ .number_of_payloads = 2,
+ .engine = DDC_I2C_COMMAND_ENGINE,
+ .speed = ddc->ctx->dc->caps.i2c_speed_in_khz };
+
+ return dm_helpers_submit_i2c(
+ ddc->ctx,
+ ddc->link,
+ &command);
+}
+
+enum {
+ DP_SINK_CAP_SIZE =
+ DP_EDP_CONFIGURATION_CAP - DP_DPCD_REV + 1
+};
+
+static void query_dp_dual_mode_adaptor(
+ struct ddc_service *ddc,
+ struct display_sink_capability *sink_cap)
+{
+ uint8_t i;
+ bool is_valid_hdmi_signature;
+ enum display_dongle_type *dongle = &sink_cap->dongle_type;
+ uint8_t type2_dongle_buf[DP_ADAPTOR_TYPE2_SIZE];
+ bool is_type2_dongle = false;
+ int retry_count = 2;
+ struct dp_hdmi_dongle_signature_data *dongle_signature;
+
+ /* Assume we have no valid DP passive dongle connected */
+ *dongle = DISPLAY_DONGLE_NONE;
+ sink_cap->max_hdmi_pixel_clock = DP_ADAPTOR_HDMI_SAFE_MAX_TMDS_CLK;
+
+ /* Read DP-HDMI dongle I2c (no response interpreted as DP-DVI dongle)*/
+ if (!i2c_read(
+ ddc,
+ DP_HDMI_DONGLE_ADDRESS,
+ type2_dongle_buf,
+ sizeof(type2_dongle_buf))) {
+ /* Passive HDMI dongles can sometimes fail here without retrying*/
+ while (retry_count > 0) {
+ if (i2c_read(ddc,
+ DP_HDMI_DONGLE_ADDRESS,
+ type2_dongle_buf,
+ sizeof(type2_dongle_buf)))
+ break;
+ retry_count--;
+ }
+ if (retry_count == 0) {
+ *dongle = DISPLAY_DONGLE_DP_DVI_DONGLE;
+ sink_cap->max_hdmi_pixel_clock = DP_ADAPTOR_DVI_MAX_TMDS_CLK;
+
+ CONN_DATA_DETECT(ddc->link, type2_dongle_buf, sizeof(type2_dongle_buf),
+ "DP-DVI passive dongle %dMhz: ",
+ DP_ADAPTOR_DVI_MAX_TMDS_CLK / 1000);
+ return;
+ }
+ }
+
+ /* Check if Type 2 dongle.*/
+ if (type2_dongle_buf[DP_ADAPTOR_TYPE2_REG_ID] == DP_ADAPTOR_TYPE2_ID)
+ is_type2_dongle = true;
+
+ dongle_signature =
+ (struct dp_hdmi_dongle_signature_data *)type2_dongle_buf;
+
+ is_valid_hdmi_signature = true;
+
+ /* Check EOT */
+ if (dongle_signature->eot != DP_HDMI_DONGLE_SIGNATURE_EOT) {
+ is_valid_hdmi_signature = false;
+ }
+
+ /* Check signature */
+ for (i = 0; i < sizeof(dongle_signature->id); ++i) {
+ /* If its not the right signature,
+ * skip mismatch in subversion byte.*/
+ if (dongle_signature->id[i] !=
+ dp_hdmi_dongle_signature_str[i] && i != 3) {
+
+ if (is_type2_dongle) {
+ is_valid_hdmi_signature = false;
+ break;
+ }
+
+ }
+ }
+
+ if (is_type2_dongle) {
+ uint32_t max_tmds_clk =
+ type2_dongle_buf[DP_ADAPTOR_TYPE2_REG_MAX_TMDS_CLK];
+
+ max_tmds_clk = max_tmds_clk * 2 + max_tmds_clk / 2;
+
+ if (0 == max_tmds_clk ||
+ max_tmds_clk < DP_ADAPTOR_TYPE2_MIN_TMDS_CLK ||
+ max_tmds_clk > DP_ADAPTOR_TYPE2_MAX_TMDS_CLK) {
+ *dongle = DISPLAY_DONGLE_DP_DVI_DONGLE;
+
+ CONN_DATA_DETECT(ddc->link, type2_dongle_buf,
+ sizeof(type2_dongle_buf),
+ "DP-DVI passive dongle %dMhz: ",
+ DP_ADAPTOR_DVI_MAX_TMDS_CLK / 1000);
+ } else {
+ if (is_valid_hdmi_signature == true) {
+ *dongle = DISPLAY_DONGLE_DP_HDMI_DONGLE;
+
+ CONN_DATA_DETECT(ddc->link, type2_dongle_buf,
+ sizeof(type2_dongle_buf),
+ "Type 2 DP-HDMI passive dongle %dMhz: ",
+ max_tmds_clk);
+ } else {
+ *dongle = DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE;
+
+ CONN_DATA_DETECT(ddc->link, type2_dongle_buf,
+ sizeof(type2_dongle_buf),
+ "Type 2 DP-HDMI passive dongle (no signature) %dMhz: ",
+ max_tmds_clk);
+
+ }
+
+ /* Multiply by 1000 to convert to kHz. */
+ sink_cap->max_hdmi_pixel_clock =
+ max_tmds_clk * 1000;
+ }
+ sink_cap->is_dongle_type_one = false;
+
+ } else {
+ if (is_valid_hdmi_signature == true) {
+ *dongle = DISPLAY_DONGLE_DP_HDMI_DONGLE;
+
+ CONN_DATA_DETECT(ddc->link, type2_dongle_buf,
+ sizeof(type2_dongle_buf),
+ "Type 1 DP-HDMI passive dongle %dMhz: ",
+ sink_cap->max_hdmi_pixel_clock / 1000);
+ } else {
+ *dongle = DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE;
+
+ CONN_DATA_DETECT(ddc->link, type2_dongle_buf,
+ sizeof(type2_dongle_buf),
+ "Type 1 DP-HDMI passive dongle (no signature) %dMhz: ",
+ sink_cap->max_hdmi_pixel_clock / 1000);
+ }
+ sink_cap->is_dongle_type_one = true;
+ }
+
+ return;
+}
+
+static enum signal_type dp_passive_dongle_detection(struct ddc_service *ddc,
+ struct display_sink_capability *sink_cap,
+ struct audio_support *audio_support)
+{
+ query_dp_dual_mode_adaptor(ddc, sink_cap);
+
+ return decide_signal_from_strap_and_dongle_type(sink_cap->dongle_type,
+ audio_support);
+}
+
+static void link_disconnect_sink(struct dc_link *link)
+{
+ if (link->local_sink) {
+ dc_sink_release(link->local_sink);
+ link->local_sink = NULL;
+ }
+
+ link->dpcd_sink_count = 0;
+ //link->dpcd_caps.dpcd_rev.raw = 0;
+}
+
+static void link_disconnect_remap(struct dc_sink *prev_sink, struct dc_link *link)
+{
+ dc_sink_release(link->local_sink);
+ link->local_sink = prev_sink;
+}
+
+#if defined(CONFIG_DRM_AMD_DC_HDCP)
+static void query_hdcp_capability(enum signal_type signal, struct dc_link *link)
+{
+ struct hdcp_protection_message msg22;
+ struct hdcp_protection_message msg14;
+
+ memset(&msg22, 0, sizeof(struct hdcp_protection_message));
+ memset(&msg14, 0, sizeof(struct hdcp_protection_message));
+ memset(link->hdcp_caps.rx_caps.raw, 0,
+ sizeof(link->hdcp_caps.rx_caps.raw));
+
+ if ((link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT &&
+ link->ddc->transaction_type ==
+ DDC_TRANSACTION_TYPE_I2C_OVER_AUX) ||
+ link->connector_signal == SIGNAL_TYPE_EDP) {
+ msg22.data = link->hdcp_caps.rx_caps.raw;
+ msg22.length = sizeof(link->hdcp_caps.rx_caps.raw);
+ msg22.msg_id = HDCP_MESSAGE_ID_RX_CAPS;
+ } else {
+ msg22.data = &link->hdcp_caps.rx_caps.fields.version;
+ msg22.length = sizeof(link->hdcp_caps.rx_caps.fields.version);
+ msg22.msg_id = HDCP_MESSAGE_ID_HDCP2VERSION;
+ }
+ msg22.version = HDCP_VERSION_22;
+ msg22.link = HDCP_LINK_PRIMARY;
+ msg22.max_retries = 5;
+ dc_process_hdcp_msg(signal, link, &msg22);
+
+ if (signal == SIGNAL_TYPE_DISPLAY_PORT || signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
+ enum hdcp_message_status status = HDCP_MESSAGE_UNSUPPORTED;
+
+ msg14.data = &link->hdcp_caps.bcaps.raw;
+ msg14.length = sizeof(link->hdcp_caps.bcaps.raw);
+ msg14.msg_id = HDCP_MESSAGE_ID_READ_BCAPS;
+ msg14.version = HDCP_VERSION_14;
+ msg14.link = HDCP_LINK_PRIMARY;
+ msg14.max_retries = 5;
+
+ status = dc_process_hdcp_msg(signal, link, &msg14);
+ }
+
+}
+#endif // CONFIG_DRM_AMD_DC_HDCP
+static void read_current_link_settings_on_detect(struct dc_link *link)
+{
+ union lane_count_set lane_count_set = {0};
+ uint8_t link_bw_set;
+ uint8_t link_rate_set;
+ uint32_t read_dpcd_retry_cnt = 10;
+ enum dc_status status = DC_ERROR_UNEXPECTED;
+ int i;
+ union max_down_spread max_down_spread = {0};
+
+ // Read DPCD 00101h to find out the number of lanes currently set
+ for (i = 0; i < read_dpcd_retry_cnt; i++) {
+ status = core_link_read_dpcd(link,
+ DP_LANE_COUNT_SET,
+ &lane_count_set.raw,
+ sizeof(lane_count_set));
+ /* First DPCD read after VDD ON can fail if the particular board
+ * does not have HPD pin wired correctly. So if DPCD read fails,
+ * which it should never happen, retry a few times. Target worst
+ * case scenario of 80 ms.
+ */
+ if (status == DC_OK) {
+ link->cur_link_settings.lane_count =
+ lane_count_set.bits.LANE_COUNT_SET;
+ break;
+ }
+
+ msleep(8);
+ }
+
+ // Read DPCD 00100h to find if standard link rates are set
+ core_link_read_dpcd(link, DP_LINK_BW_SET,
+ &link_bw_set, sizeof(link_bw_set));
+
+ if (link_bw_set == 0) {
+ if (link->connector_signal == SIGNAL_TYPE_EDP) {
+ /* If standard link rates are not being used,
+ * Read DPCD 00115h to find the edp link rate set used
+ */
+ core_link_read_dpcd(link, DP_LINK_RATE_SET,
+ &link_rate_set, sizeof(link_rate_set));
+
+ // edp_supported_link_rates_count = 0 for DP
+ if (link_rate_set < link->dpcd_caps.edp_supported_link_rates_count) {
+ link->cur_link_settings.link_rate =
+ link->dpcd_caps.edp_supported_link_rates[link_rate_set];
+ link->cur_link_settings.link_rate_set = link_rate_set;
+ link->cur_link_settings.use_link_rate_set = true;
+ }
+ } else {
+ // Link Rate not found. Seamless boot may not work.
+ ASSERT(false);
+ }
+ } else {
+ link->cur_link_settings.link_rate = link_bw_set;
+ link->cur_link_settings.use_link_rate_set = false;
+ }
+ // Read DPCD 00003h to find the max down spread.
+ core_link_read_dpcd(link, DP_MAX_DOWNSPREAD,
+ &max_down_spread.raw, sizeof(max_down_spread));
+ link->cur_link_settings.link_spread =
+ max_down_spread.bits.MAX_DOWN_SPREAD ?
+ LINK_SPREAD_05_DOWNSPREAD_30KHZ : LINK_SPREAD_DISABLED;
+}
+
+static bool detect_dp(struct dc_link *link,
+ struct display_sink_capability *sink_caps,
+ enum dc_detect_reason reason)
+{
+ struct audio_support *audio_support = &link->dc->res_pool->audio_support;
+
+ sink_caps->signal = link_detect_sink_signal_type(link, reason);
+ sink_caps->transaction_type =
+ get_ddc_transaction_type(sink_caps->signal);
+
+ if (sink_caps->transaction_type == DDC_TRANSACTION_TYPE_I2C_OVER_AUX) {
+ sink_caps->signal = SIGNAL_TYPE_DISPLAY_PORT;
+ if (!detect_dp_sink_caps(link))
+ return false;
+
+ if (is_dp_branch_device(link))
+ /* DP SST branch */
+ link->type = dc_connection_sst_branch;
+ } else {
+ /* DP passive dongles */
+ sink_caps->signal = dp_passive_dongle_detection(link->ddc,
+ sink_caps,
+ audio_support);
+ link->dpcd_caps.dongle_type = sink_caps->dongle_type;
+ link->dpcd_caps.is_dongle_type_one = sink_caps->is_dongle_type_one;
+ link->dpcd_caps.dpcd_rev.raw = 0;
+ }
+
+ return true;
+}
+
+static bool is_same_edid(struct dc_edid *old_edid, struct dc_edid *new_edid)
+{
+ if (old_edid->length != new_edid->length)
+ return false;
+
+ if (new_edid->length == 0)
+ return false;
+
+ return (memcmp(old_edid->raw_edid,
+ new_edid->raw_edid, new_edid->length) == 0);
+}
+
+static bool wait_for_entering_dp_alt_mode(struct dc_link *link)
+{
+
+ /**
+ * something is terribly wrong if time out is > 200ms. (5Hz)
+ * 500 microseconds * 400 tries us 200 ms
+ **/
+ unsigned int sleep_time_in_microseconds = 500;
+ unsigned int tries_allowed = 400;
+ bool is_in_alt_mode;
+ unsigned long long enter_timestamp;
+ unsigned long long finish_timestamp;
+ unsigned long long time_taken_in_ns;
+ int tries_taken;
+
+ DC_LOGGER_INIT(link->ctx->logger);
+
+ /**
+ * this function will only exist if we are on dcn21 (is_in_alt_mode is a
+ * function pointer, so checking to see if it is equal to 0 is the same
+ * as checking to see if it is null
+ **/
+ if (!link->link_enc->funcs->is_in_alt_mode)
+ return true;
+
+ is_in_alt_mode = link->link_enc->funcs->is_in_alt_mode(link->link_enc);
+ DC_LOG_DC("DP Alt mode state on HPD: %d\n", is_in_alt_mode);
+
+ if (is_in_alt_mode)
+ return true;
+
+ enter_timestamp = dm_get_timestamp(link->ctx);
+
+ for (tries_taken = 0; tries_taken < tries_allowed; tries_taken++) {
+ udelay(sleep_time_in_microseconds);
+ /* ask the link if alt mode is enabled, if so return ok */
+ if (link->link_enc->funcs->is_in_alt_mode(link->link_enc)) {
+ finish_timestamp = dm_get_timestamp(link->ctx);
+ time_taken_in_ns =
+ dm_get_elapse_time_in_ns(link->ctx,
+ finish_timestamp,
+ enter_timestamp);
+ DC_LOG_WARNING("Alt mode entered finished after %llu ms\n",
+ div_u64(time_taken_in_ns, 1000000));
+ return true;
+ }
+ }
+ finish_timestamp = dm_get_timestamp(link->ctx);
+ time_taken_in_ns = dm_get_elapse_time_in_ns(link->ctx, finish_timestamp,
+ enter_timestamp);
+ DC_LOG_WARNING("Alt mode has timed out after %llu ms\n",
+ div_u64(time_taken_in_ns, 1000000));
+ return false;
+}
+
+static void apply_dpia_mst_dsc_always_on_wa(struct dc_link *link)
+{
+ /* Apply work around for tunneled MST on certain USB4 docks. Always use DSC if dock
+ * reports DSC support.
+ */
+ if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA &&
+ link->type == dc_connection_mst_branch &&
+ link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_90CC24 &&
+ link->dpcd_caps.branch_hw_revision == DP_BRANCH_HW_REV_20 &&
+ link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_SUPPORT &&
+ !link->dc->debug.dpia_debug.bits.disable_mst_dsc_work_around)
+ link->wa_flags.dpia_mst_dsc_always_on = true;
+}
+
+static void revert_dpia_mst_dsc_always_on_wa(struct dc_link *link)
+{
+ /* Disable work around which keeps DSC on for tunneled MST on certain USB4 docks. */
+ if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA)
+ link->wa_flags.dpia_mst_dsc_always_on = false;
+}
+
+static bool discover_dp_mst_topology(struct dc_link *link, enum dc_detect_reason reason)
+{
+ DC_LOGGER_INIT(link->ctx->logger);
+
+ LINK_INFO("link=%d, mst branch is now Connected\n",
+ link->link_index);
+
+ link->type = dc_connection_mst_branch;
+ apply_dpia_mst_dsc_always_on_wa(link);
+
+ dm_helpers_dp_update_branch_info(link->ctx, link);
+ if (dm_helpers_dp_mst_start_top_mgr(link->ctx,
+ link, (reason == DETECT_REASON_BOOT || reason == DETECT_REASON_RESUMEFROMS3S4))) {
+ link_disconnect_sink(link);
+ } else {
+ link->type = dc_connection_sst_branch;
+ }
+
+ return link->type == dc_connection_mst_branch;
+}
+
+bool link_reset_cur_dp_mst_topology(struct dc_link *link)
+{
+ DC_LOGGER_INIT(link->ctx->logger);
+
+ LINK_INFO("link=%d, mst branch is now Disconnected\n",
+ link->link_index);
+
+ revert_dpia_mst_dsc_always_on_wa(link);
+ return dm_helpers_dp_mst_stop_top_mgr(link->ctx, link);
+}
+
+static bool should_prepare_phy_clocks_for_link_verification(const struct dc *dc,
+ enum dc_detect_reason reason)
+{
+ int i;
+ bool can_apply_seamless_boot = false;
+
+ for (i = 0; i < dc->current_state->stream_count; i++) {
+ if (dc->current_state->streams[i]->apply_seamless_boot_optimization) {
+ can_apply_seamless_boot = true;
+ break;
+ }
+ }
+
+ return !can_apply_seamless_boot && reason != DETECT_REASON_BOOT;
+}
+
+static void prepare_phy_clocks_for_destructive_link_verification(const struct dc *dc)
+{
+ dc_z10_restore(dc);
+ clk_mgr_exit_optimized_pwr_state(dc, dc->clk_mgr);
+}
+
+static void restore_phy_clocks_for_destructive_link_verification(const struct dc *dc)
+{
+ clk_mgr_optimize_pwr_state(dc, dc->clk_mgr);
+}
+
+static void verify_link_capability_destructive(struct dc_link *link,
+ struct dc_sink *sink,
+ enum dc_detect_reason reason)
+{
+ bool should_prepare_phy_clocks =
+ should_prepare_phy_clocks_for_link_verification(link->dc, reason);
+
+ if (should_prepare_phy_clocks)
+ prepare_phy_clocks_for_destructive_link_verification(link->dc);
+
+ if (dc_is_dp_signal(link->local_sink->sink_signal)) {
+ struct dc_link_settings known_limit_link_setting =
+ dp_get_max_link_cap(link);
+ link_set_all_streams_dpms_off_for_link(link);
+ dp_verify_link_cap_with_retries(
+ link, &known_limit_link_setting,
+ LINK_TRAINING_MAX_VERIFY_RETRY);
+ } else {
+ ASSERT(0);
+ }
+
+ if (should_prepare_phy_clocks)
+ restore_phy_clocks_for_destructive_link_verification(link->dc);
+}
+
+static void verify_link_capability_non_destructive(struct dc_link *link)
+{
+ if (dc_is_dp_signal(link->local_sink->sink_signal)) {
+ if (dc_is_embedded_signal(link->local_sink->sink_signal) ||
+ link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA)
+ /* TODO - should we check link encoder's max link caps here?
+ * How do we know which link encoder to check from?
+ */
+ link->verified_link_cap = link->reported_link_cap;
+ else
+ link->verified_link_cap = dp_get_max_link_cap(link);
+ }
+}
+
+static bool should_verify_link_capability_destructively(struct dc_link *link,
+ enum dc_detect_reason reason)
+{
+ bool destrictive = false;
+ struct dc_link_settings max_link_cap;
+ bool is_link_enc_unavailable = link->link_enc &&
+ link->dc->res_pool->funcs->link_encs_assign &&
+ !link_enc_cfg_is_link_enc_avail(
+ link->ctx->dc,
+ link->link_enc->preferred_engine,
+ link);
+
+ if (dc_is_dp_signal(link->local_sink->sink_signal)) {
+ max_link_cap = dp_get_max_link_cap(link);
+ destrictive = true;
+
+ if (link->dc->debug.skip_detection_link_training ||
+ dc_is_embedded_signal(link->local_sink->sink_signal) ||
+ link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) {
+ destrictive = false;
+ } else if (link_dp_get_encoding_format(&max_link_cap) ==
+ DP_8b_10b_ENCODING) {
+ if (link->dpcd_caps.is_mst_capable ||
+ is_link_enc_unavailable) {
+ destrictive = false;
+ }
+ }
+ }
+
+ return destrictive;
+}
+
+static void verify_link_capability(struct dc_link *link, struct dc_sink *sink,
+ enum dc_detect_reason reason)
+{
+ if (should_verify_link_capability_destructively(link, reason))
+ verify_link_capability_destructive(link, sink, reason);
+ else
+ verify_link_capability_non_destructive(link);
+}
+
+/**
+ * detect_link_and_local_sink() - Detect if a sink is attached to a given link
+ *
+ * link->local_sink is created or destroyed as needed.
+ *
+ * This does not create remote sinks.
+ */
+static bool detect_link_and_local_sink(struct dc_link *link,
+ enum dc_detect_reason reason)
+{
+ struct dc_sink_init_data sink_init_data = { 0 };
+ struct display_sink_capability sink_caps = { 0 };
+ uint32_t i;
+ bool converter_disable_audio = false;
+ struct audio_support *aud_support = &link->dc->res_pool->audio_support;
+ bool same_edid = false;
+ enum dc_edid_status edid_status;
+ struct dc_context *dc_ctx = link->ctx;
+ struct dc *dc = dc_ctx->dc;
+ struct dc_sink *sink = NULL;
+ struct dc_sink *prev_sink = NULL;
+ struct dpcd_caps prev_dpcd_caps;
+ enum dc_connection_type new_connection_type = dc_connection_none;
+ const uint32_t post_oui_delay = 30; // 30ms
+
+ DC_LOGGER_INIT(link->ctx->logger);
+
+ if (dc_is_virtual_signal(link->connector_signal))
+ return false;
+
+ if (((link->connector_signal == SIGNAL_TYPE_LVDS ||
+ link->connector_signal == SIGNAL_TYPE_EDP) &&
+ (!link->dc->config.allow_edp_hotplug_detection)) &&
+ link->local_sink) {
+ // need to re-write OUI and brightness in resume case
+ if (link->connector_signal == SIGNAL_TYPE_EDP &&
+ (link->dpcd_sink_ext_caps.bits.oled == 1)) {
+ dpcd_set_source_specific_data(link);
+ msleep(post_oui_delay);
+ set_default_brightness_aux(link);
+ //TODO: use cached
+ }
+
+ return true;
+ }
+
+ if (!dc_link_detect_connection_type(link, &new_connection_type)) {
+ BREAK_TO_DEBUGGER();
+ return false;
+ }
+
+ prev_sink = link->local_sink;
+ if (prev_sink) {
+ dc_sink_retain(prev_sink);
+ memcpy(&prev_dpcd_caps, &link->dpcd_caps, sizeof(struct dpcd_caps));
+ }
+
+ link_disconnect_sink(link);
+ if (new_connection_type != dc_connection_none) {
+ link->type = new_connection_type;
+ link->link_state_valid = false;
+
+ /* From Disconnected-to-Connected. */
+ switch (link->connector_signal) {
+ case SIGNAL_TYPE_HDMI_TYPE_A: {
+ sink_caps.transaction_type = DDC_TRANSACTION_TYPE_I2C;
+ if (aud_support->hdmi_audio_native)
+ sink_caps.signal = SIGNAL_TYPE_HDMI_TYPE_A;
+ else
+ sink_caps.signal = SIGNAL_TYPE_DVI_SINGLE_LINK;
+ break;
+ }
+
+ case SIGNAL_TYPE_DVI_SINGLE_LINK: {
+ sink_caps.transaction_type = DDC_TRANSACTION_TYPE_I2C;
+ sink_caps.signal = SIGNAL_TYPE_DVI_SINGLE_LINK;
+ break;
+ }
+
+ case SIGNAL_TYPE_DVI_DUAL_LINK: {
+ sink_caps.transaction_type = DDC_TRANSACTION_TYPE_I2C;
+ sink_caps.signal = SIGNAL_TYPE_DVI_DUAL_LINK;
+ break;
+ }
+
+ case SIGNAL_TYPE_LVDS: {
+ sink_caps.transaction_type = DDC_TRANSACTION_TYPE_I2C;
+ sink_caps.signal = SIGNAL_TYPE_LVDS;
+ break;
+ }
+
+ case SIGNAL_TYPE_EDP: {
+ detect_edp_sink_caps(link);
+ read_current_link_settings_on_detect(link);
+
+ /* Disable power sequence on MIPI panel + converter
+ */
+ if (dc->config.enable_mipi_converter_optimization &&
+ dc_ctx->dce_version == DCN_VERSION_3_01 &&
+ link->dpcd_caps.sink_dev_id == DP_BRANCH_DEVICE_ID_0022B9 &&
+ memcmp(&link->dpcd_caps.branch_dev_name, DP_SINK_BRANCH_DEV_NAME_7580,
+ sizeof(link->dpcd_caps.branch_dev_name)) == 0) {
+ dc->config.edp_no_power_sequencing = true;
+
+ if (!link->dpcd_caps.set_power_state_capable_edp)
+ link->wa_flags.dp_keep_receiver_powered = true;
+ }
+
+ sink_caps.transaction_type = DDC_TRANSACTION_TYPE_I2C_OVER_AUX;
+ sink_caps.signal = SIGNAL_TYPE_EDP;
+ break;
+ }
+
+ case SIGNAL_TYPE_DISPLAY_PORT: {
+
+ /* wa HPD high coming too early*/
+ if (link->ep_type == DISPLAY_ENDPOINT_PHY &&
+ link->link_enc->features.flags.bits.DP_IS_USB_C == 1) {
+
+ /* if alt mode times out, return false */
+ if (!wait_for_entering_dp_alt_mode(link))
+ return false;
+ }
+
+ if (!detect_dp(link, &sink_caps, reason)) {
+ if (prev_sink)
+ dc_sink_release(prev_sink);
+ return false;
+ }
+
+ /* Active SST downstream branch device unplug*/
+ if (link->type == dc_connection_sst_branch &&
+ link->dpcd_caps.sink_count.bits.SINK_COUNT == 0) {
+ if (prev_sink)
+ /* Downstream unplug */
+ dc_sink_release(prev_sink);
+ return true;
+ }
+
+ /* disable audio for non DP to HDMI active sst converter */
+ if (link->type == dc_connection_sst_branch &&
+ is_dp_active_dongle(link) &&
+ (link->dpcd_caps.dongle_type !=
+ DISPLAY_DONGLE_DP_HDMI_CONVERTER))
+ converter_disable_audio = true;
+ break;
+ }
+
+ default:
+ DC_ERROR("Invalid connector type! signal:%d\n",
+ link->connector_signal);
+ if (prev_sink)
+ dc_sink_release(prev_sink);
+ return false;
+ } /* switch() */
+
+ if (link->dpcd_caps.sink_count.bits.SINK_COUNT)
+ link->dpcd_sink_count =
+ link->dpcd_caps.sink_count.bits.SINK_COUNT;
+ else
+ link->dpcd_sink_count = 1;
+
+ set_ddc_transaction_type(link->ddc,
+ sink_caps.transaction_type);
+
+ link->aux_mode =
+ link_is_in_aux_transaction_mode(link->ddc);
+
+ sink_init_data.link = link;
+ sink_init_data.sink_signal = sink_caps.signal;
+
+ sink = dc_sink_create(&sink_init_data);
+ if (!sink) {
+ DC_ERROR("Failed to create sink!\n");
+ if (prev_sink)
+ dc_sink_release(prev_sink);
+ return false;
+ }
+
+ sink->link->dongle_max_pix_clk = sink_caps.max_hdmi_pixel_clock;
+ sink->converter_disable_audio = converter_disable_audio;
+
+ /* dc_sink_create returns a new reference */
+ link->local_sink = sink;
+
+ edid_status = dm_helpers_read_local_edid(link->ctx,
+ link, sink);
+
+ switch (edid_status) {
+ case EDID_BAD_CHECKSUM:
+ DC_LOG_ERROR("EDID checksum invalid.\n");
+ break;
+ case EDID_PARTIAL_VALID:
+ DC_LOG_ERROR("Partial EDID valid, abandon invalid blocks.\n");
+ break;
+ case EDID_NO_RESPONSE:
+ DC_LOG_ERROR("No EDID read.\n");
+ /*
+ * Abort detection for non-DP connectors if we have
+ * no EDID
+ *
+ * DP needs to report as connected if HDP is high
+ * even if we have no EDID in order to go to
+ * fail-safe mode
+ */
+ if (dc_is_hdmi_signal(link->connector_signal) ||
+ dc_is_dvi_signal(link->connector_signal)) {
+ if (prev_sink)
+ dc_sink_release(prev_sink);
+
+ return false;
+ }
+
+ if (link->type == dc_connection_sst_branch &&
+ link->dpcd_caps.dongle_type ==
+ DISPLAY_DONGLE_DP_VGA_CONVERTER &&
+ reason == DETECT_REASON_HPDRX) {
+ /* Abort detection for DP-VGA adapters when EDID
+ * can't be read and detection reason is VGA-side
+ * hotplug
+ */
+ if (prev_sink)
+ dc_sink_release(prev_sink);
+ link_disconnect_sink(link);
+
+ return true;
+ }
+
+ break;
+ default:
+ break;
+ }
+
+ // Check if edid is the same
+ if ((prev_sink) &&
+ (edid_status == EDID_THE_SAME || edid_status == EDID_OK))
+ same_edid = is_same_edid(&prev_sink->dc_edid,
+ &sink->dc_edid);
+
+ if (sink->edid_caps.panel_patch.skip_scdc_overwrite)
+ link->ctx->dc->debug.hdmi20_disable = true;
+
+ if (dc_is_hdmi_signal(link->connector_signal))
+ read_scdc_caps(link->ddc, link->local_sink);
+
+ if (link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT &&
+ sink_caps.transaction_type ==
+ DDC_TRANSACTION_TYPE_I2C_OVER_AUX) {
+ /*
+ * TODO debug why certain monitors don't like
+ * two link trainings
+ */
+#if defined(CONFIG_DRM_AMD_DC_HDCP)
+ query_hdcp_capability(sink->sink_signal, link);
+#endif
+ } else {
+ // If edid is the same, then discard new sink and revert back to original sink
+ if (same_edid) {
+ link_disconnect_remap(prev_sink, link);
+ sink = prev_sink;
+ prev_sink = NULL;
+ }
+#if defined(CONFIG_DRM_AMD_DC_HDCP)
+ query_hdcp_capability(sink->sink_signal, link);
+#endif
+ }
+
+ /* HDMI-DVI Dongle */
+ if (sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A &&
+ !sink->edid_caps.edid_hdmi)
+ sink->sink_signal = SIGNAL_TYPE_DVI_SINGLE_LINK;
+
+ if (link->local_sink && dc_is_dp_signal(sink_caps.signal))
+ dp_trace_init(link);
+
+ /* Connectivity log: detection */
+ for (i = 0; i < sink->dc_edid.length / DC_EDID_BLOCK_SIZE; i++) {
+ CONN_DATA_DETECT(link,
+ &sink->dc_edid.raw_edid[i * DC_EDID_BLOCK_SIZE],
+ DC_EDID_BLOCK_SIZE,
+ "%s: [Block %d] ", sink->edid_caps.display_name, i);
+ }
+
+ DC_LOG_DETECTION_EDID_PARSER("%s: "
+ "manufacturer_id = %X, "
+ "product_id = %X, "
+ "serial_number = %X, "
+ "manufacture_week = %d, "
+ "manufacture_year = %d, "
+ "display_name = %s, "
+ "speaker_flag = %d, "
+ "audio_mode_count = %d\n",
+ __func__,
+ sink->edid_caps.manufacturer_id,
+ sink->edid_caps.product_id,
+ sink->edid_caps.serial_number,
+ sink->edid_caps.manufacture_week,
+ sink->edid_caps.manufacture_year,
+ sink->edid_caps.display_name,
+ sink->edid_caps.speaker_flags,
+ sink->edid_caps.audio_mode_count);
+
+ for (i = 0; i < sink->edid_caps.audio_mode_count; i++) {
+ DC_LOG_DETECTION_EDID_PARSER("%s: mode number = %d, "
+ "format_code = %d, "
+ "channel_count = %d, "
+ "sample_rate = %d, "
+ "sample_size = %d\n",
+ __func__,
+ i,
+ sink->edid_caps.audio_modes[i].format_code,
+ sink->edid_caps.audio_modes[i].channel_count,
+ sink->edid_caps.audio_modes[i].sample_rate,
+ sink->edid_caps.audio_modes[i].sample_size);
+ }
+
+ if (link->connector_signal == SIGNAL_TYPE_EDP) {
+ // Init dc_panel_config by HW config
+ if (dc_ctx->dc->res_pool->funcs->get_panel_config_defaults)
+ dc_ctx->dc->res_pool->funcs->get_panel_config_defaults(&link->panel_config);
+ // Pickup base DM settings
+ dm_helpers_init_panel_settings(dc_ctx, &link->panel_config, sink);
+ // Override dc_panel_config if system has specific settings
+ dm_helpers_override_panel_settings(dc_ctx, &link->panel_config);
+ }
+
+ } else {
+ /* From Connected-to-Disconnected. */
+ link->type = dc_connection_none;
+ sink_caps.signal = SIGNAL_TYPE_NONE;
+#if defined(CONFIG_DRM_AMD_DC_HDCP)
+ memset(&link->hdcp_caps, 0, sizeof(struct hdcp_caps));
+#endif
+ /* When we unplug a passive DP-HDMI dongle connection, dongle_max_pix_clk
+ * is not cleared. If we emulate a DP signal on this connection, it thinks
+ * the dongle is still there and limits the number of modes we can emulate.
+ * Clear dongle_max_pix_clk on disconnect to fix this
+ */
+ link->dongle_max_pix_clk = 0;
+
+ dc_link_clear_dprx_states(link);
+ dp_trace_reset(link);
+ }
+
+ LINK_INFO("link=%d, dc_sink_in=%p is now %s prev_sink=%p edid same=%d\n",
+ link->link_index, sink,
+ (sink_caps.signal ==
+ SIGNAL_TYPE_NONE ? "Disconnected" : "Connected"),
+ prev_sink, same_edid);
+
+ if (prev_sink)
+ dc_sink_release(prev_sink);
+
+ return true;
+}
+
+/**
+ * dc_link_detect_connection_type() - Determine if there is a sink connected
+ *
+ * @type: Returned connection type
+ * Does not detect downstream devices, such as MST sinks
+ * or display connected through active dongles
+ */
+bool link_detect_connection_type(struct dc_link *link, enum dc_connection_type *type)
+{
+ uint32_t is_hpd_high = 0;
+
+ if (link->connector_signal == SIGNAL_TYPE_LVDS) {
+ *type = dc_connection_single;
+ return true;
+ }
+
+ if (link->connector_signal == SIGNAL_TYPE_EDP) {
+ /*in case it is not on*/
+ if (!link->dc->config.edp_no_power_sequencing)
+ link->dc->hwss.edp_power_control(link, true);
+ link->dc->hwss.edp_wait_for_hpd_ready(link, true);
+ }
+
+ /* Link may not have physical HPD pin. */
+ if (link->ep_type != DISPLAY_ENDPOINT_PHY) {
+ if (link->is_hpd_pending || !dc_link_dpia_query_hpd_status(link))
+ *type = dc_connection_none;
+ else
+ *type = dc_connection_single;
+
+ return true;
+ }
+
+
+ if (!query_hpd_status(link, &is_hpd_high))
+ goto hpd_gpio_failure;
+
+ if (is_hpd_high) {
+ *type = dc_connection_single;
+ /* TODO: need to do the actual detection */
+ } else {
+ *type = dc_connection_none;
+ }
+
+ return true;
+
+hpd_gpio_failure:
+ return false;
+}
+
+bool link_detect(struct dc_link *link, enum dc_detect_reason reason)
+{
+ bool is_local_sink_detect_success;
+ bool is_delegated_to_mst_top_mgr = false;
+ enum dc_connection_type pre_link_type = link->type;
+
+ is_local_sink_detect_success = detect_link_and_local_sink(link, reason);
+
+ if (is_local_sink_detect_success && link->local_sink)
+ verify_link_capability(link, link->local_sink, reason);
+
+ if (is_local_sink_detect_success && link->local_sink &&
+ dc_is_dp_signal(link->local_sink->sink_signal) &&
+ link->dpcd_caps.is_mst_capable)
+ is_delegated_to_mst_top_mgr = discover_dp_mst_topology(link, reason);
+
+ if (is_local_sink_detect_success &&
+ pre_link_type == dc_connection_mst_branch &&
+ link->type != dc_connection_mst_branch)
+ is_delegated_to_mst_top_mgr = link_reset_cur_dp_mst_topology(link);
+
+ return is_local_sink_detect_success && !is_delegated_to_mst_top_mgr;
+}
+
+void link_clear_dprx_states(struct dc_link *link)
+{
+ memset(&link->dprx_states, 0, sizeof(link->dprx_states));
+}
+#if defined(CONFIG_DRM_AMD_DC_HDCP)
+
+bool link_is_hdcp14(struct dc_link *link, enum signal_type signal)
+{
+ bool ret = false;
+
+ switch (signal) {
+ case SIGNAL_TYPE_DISPLAY_PORT:
+ case SIGNAL_TYPE_DISPLAY_PORT_MST:
+ ret = link->hdcp_caps.bcaps.bits.HDCP_CAPABLE;
+ break;
+ case SIGNAL_TYPE_DVI_SINGLE_LINK:
+ case SIGNAL_TYPE_DVI_DUAL_LINK:
+ case SIGNAL_TYPE_HDMI_TYPE_A:
+ /* HDMI doesn't tell us its HDCP(1.4) capability, so assume to always be capable,
+ * we can poll for bksv but some displays have an issue with this. Since its so rare
+ * for a display to not be 1.4 capable, this assumtion is ok
+ */
+ ret = true;
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+bool link_is_hdcp22(struct dc_link *link, enum signal_type signal)
+{
+ bool ret = false;
+
+ switch (signal) {
+ case SIGNAL_TYPE_DISPLAY_PORT:
+ case SIGNAL_TYPE_DISPLAY_PORT_MST:
+ ret = (link->hdcp_caps.bcaps.bits.HDCP_CAPABLE &&
+ link->hdcp_caps.rx_caps.fields.byte0.hdcp_capable &&
+ (link->hdcp_caps.rx_caps.fields.version == 0x2)) ? 1 : 0;
+ break;
+ case SIGNAL_TYPE_DVI_SINGLE_LINK:
+ case SIGNAL_TYPE_DVI_DUAL_LINK:
+ case SIGNAL_TYPE_HDMI_TYPE_A:
+ ret = (link->hdcp_caps.rx_caps.fields.version == 0x4) ? 1:0;
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+#endif // CONFIG_DRM_AMD_DC_HDCP
+
+const struct dc_link_status *link_get_status(const struct dc_link *link)
+{
+ return &link->link_status;
+}
+
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_detection.h b/drivers/gpu/drm/amd/display/dc/link/link_detection.h
new file mode 100644
index 000000000000..1831636516fb
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/link_detection.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2023 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DC_LINK_DETECTION_H__
+#define __DC_LINK_DETECTION_H__
+#include "link.h"
+
+#endif /* __DC_LINK_DETECTION_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c
new file mode 100644
index 000000000000..257e1c3ba00a
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c
@@ -0,0 +1,2528 @@
+/*
+ * Copyright 2023 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+
+/* FILE POLICY AND INTENDED USAGE:
+ * This file owns the programming sequence of stream's dpms state associated
+ * with the link and link's enable/disable sequences as result of the stream's
+ * dpms state change.
+ *
+ * TODO - The reason link owns stream's dpms programming sequence is
+ * because dpms programming sequence is highly dependent on underlying signal
+ * specific link protocols. This unfortunately causes link to own a portion of
+ * stream state programming sequence. This creates a gray area where the
+ * boundary between link and stream is not clearly defined.
+ */
+
+#include "link_dpms.h"
+#include "link_hwss.h"
+#include "accessories/link_fpga.h"
+#include "accessories/link_dp_trace.h"
+#include "protocols/link_dpcd.h"
+#include "protocols/link_ddc.h"
+#include "protocols/link_hpd.h"
+#include "protocols/link_dp_phy.h"
+#include "protocols/link_dp_capability.h"
+#include "protocols/link_dp_training.h"
+#include "protocols/link_edp_panel_control.h"
+
+#include "dm_helpers.h"
+#include "link_enc_cfg.h"
+#include "resource.h"
+#include "dsc.h"
+#include "dccg.h"
+#include "clk_mgr.h"
+#include "atomfirmware.h"
+#define DC_LOGGER_INIT(logger)
+
+#define LINK_INFO(...) \
+ DC_LOG_HW_HOTPLUG( \
+ __VA_ARGS__)
+
+#define RETIMER_REDRIVER_INFO(...) \
+ DC_LOG_RETIMER_REDRIVER( \
+ __VA_ARGS__)
+#include "dc/dcn30/dcn30_vpg.h"
+
+#define MAX_MTP_SLOT_COUNT 64
+#define LINK_TRAINING_ATTEMPTS 4
+#define PEAK_FACTOR_X1000 1006
+
+void link_blank_all_dp_displays(struct dc *dc)
+{
+ unsigned int i;
+ uint8_t dpcd_power_state = '\0';
+ enum dc_status status = DC_ERROR_UNEXPECTED;
+
+ for (i = 0; i < dc->link_count; i++) {
+ if ((dc->links[i]->connector_signal != SIGNAL_TYPE_DISPLAY_PORT) ||
+ (dc->links[i]->priv == NULL) || (dc->links[i]->local_sink == NULL))
+ continue;
+
+ /* DP 2.0 spec requires that we read LTTPR caps first */
+ dp_retrieve_lttpr_cap(dc->links[i]);
+ /* if any of the displays are lit up turn them off */
+ status = core_link_read_dpcd(dc->links[i], DP_SET_POWER,
+ &dpcd_power_state, sizeof(dpcd_power_state));
+
+ if (status == DC_OK && dpcd_power_state == DP_POWER_STATE_D0)
+ link_blank_dp_stream(dc->links[i], true);
+ }
+
+}
+
+void link_blank_all_edp_displays(struct dc *dc)
+{
+ unsigned int i;
+ uint8_t dpcd_power_state = '\0';
+ enum dc_status status = DC_ERROR_UNEXPECTED;
+
+ for (i = 0; i < dc->link_count; i++) {
+ if ((dc->links[i]->connector_signal != SIGNAL_TYPE_EDP) ||
+ (!dc->links[i]->edp_sink_present))
+ continue;
+
+ /* if any of the displays are lit up turn them off */
+ status = core_link_read_dpcd(dc->links[i], DP_SET_POWER,
+ &dpcd_power_state, sizeof(dpcd_power_state));
+
+ if (status == DC_OK && dpcd_power_state == DP_POWER_STATE_D0)
+ link_blank_dp_stream(dc->links[i], true);
+ }
+}
+
+void link_blank_dp_stream(struct dc_link *link, bool hw_init)
+{
+ unsigned int j;
+ struct dc *dc = link->ctx->dc;
+ enum signal_type signal = link->connector_signal;
+
+ if ((signal == SIGNAL_TYPE_EDP) ||
+ (signal == SIGNAL_TYPE_DISPLAY_PORT)) {
+ if (link->ep_type == DISPLAY_ENDPOINT_PHY &&
+ link->link_enc->funcs->get_dig_frontend &&
+ link->link_enc->funcs->is_dig_enabled(link->link_enc)) {
+ unsigned int fe = link->link_enc->funcs->get_dig_frontend(link->link_enc);
+
+ if (fe != ENGINE_ID_UNKNOWN)
+ for (j = 0; j < dc->res_pool->stream_enc_count; j++) {
+ if (fe == dc->res_pool->stream_enc[j]->id) {
+ dc->res_pool->stream_enc[j]->funcs->dp_blank(link,
+ dc->res_pool->stream_enc[j]);
+ break;
+ }
+ }
+ }
+
+ if ((!link->wa_flags.dp_keep_receiver_powered) || hw_init)
+ dc_link_dp_receiver_power_ctrl(link, false);
+ }
+}
+
+void link_set_all_streams_dpms_off_for_link(struct dc_link *link)
+{
+ struct pipe_ctx *pipes[MAX_PIPES];
+ struct dc_state *state = link->dc->current_state;
+ uint8_t count;
+ int i;
+ struct dc_stream_update stream_update;
+ bool dpms_off = true;
+ struct link_resource link_res = {0};
+
+ memset(&stream_update, 0, sizeof(stream_update));
+ stream_update.dpms_off = &dpms_off;
+
+ link_get_master_pipes_with_dpms_on(link, state, &count, pipes);
+
+ for (i = 0; i < count; i++) {
+ stream_update.stream = pipes[i]->stream;
+ dc_commit_updates_for_stream(link->ctx->dc, NULL, 0,
+ pipes[i]->stream, &stream_update,
+ state);
+ }
+
+ /* link can be also enabled by vbios. In this case it is not recorded
+ * in pipe_ctx. Disable link phy here to make sure it is completely off
+ */
+ dp_disable_link_phy(link, &link_res, link->connector_signal);
+}
+
+void link_resume(struct dc_link *link)
+{
+ if (link->connector_signal != SIGNAL_TYPE_VIRTUAL)
+ program_hpd_filter(link);
+}
+
+/* This function returns true if the pipe is used to feed video signal directly
+ * to the link.
+ */
+static bool is_master_pipe_for_link(const struct dc_link *link,
+ const struct pipe_ctx *pipe)
+{
+ return (pipe->stream &&
+ pipe->stream->link &&
+ pipe->stream->link == link &&
+ pipe->top_pipe == NULL &&
+ pipe->prev_odm_pipe == NULL);
+}
+
+/*
+ * This function finds all master pipes feeding to a given link with dpms set to
+ * on in given dc state.
+ */
+void link_get_master_pipes_with_dpms_on(const struct dc_link *link,
+ struct dc_state *state,
+ uint8_t *count,
+ struct pipe_ctx *pipes[MAX_PIPES])
+{
+ int i;
+ struct pipe_ctx *pipe = NULL;
+
+ *count = 0;
+ for (i = 0; i < MAX_PIPES; i++) {
+ pipe = &state->res_ctx.pipe_ctx[i];
+
+ if (is_master_pipe_for_link(link, pipe) &&
+ pipe->stream->dpms_off == false) {
+ pipes[(*count)++] = pipe;
+ }
+ }
+}
+
+static bool get_ext_hdmi_settings(struct pipe_ctx *pipe_ctx,
+ enum engine_id eng_id,
+ struct ext_hdmi_settings *settings)
+{
+ bool result = false;
+ int i = 0;
+ struct integrated_info *integrated_info =
+ pipe_ctx->stream->ctx->dc_bios->integrated_info;
+
+ if (integrated_info == NULL)
+ return false;
+
+ /*
+ * Get retimer settings from sbios for passing SI eye test for DCE11
+ * The setting values are varied based on board revision and port id
+ * Therefore the setting values of each ports is passed by sbios.
+ */
+
+ // Check if current bios contains ext Hdmi settings
+ if (integrated_info->gpu_cap_info & 0x20) {
+ switch (eng_id) {
+ case ENGINE_ID_DIGA:
+ settings->slv_addr = integrated_info->dp0_ext_hdmi_slv_addr;
+ settings->reg_num = integrated_info->dp0_ext_hdmi_6g_reg_num;
+ settings->reg_num_6g = integrated_info->dp0_ext_hdmi_6g_reg_num;
+ memmove(settings->reg_settings,
+ integrated_info->dp0_ext_hdmi_reg_settings,
+ sizeof(integrated_info->dp0_ext_hdmi_reg_settings));
+ memmove(settings->reg_settings_6g,
+ integrated_info->dp0_ext_hdmi_6g_reg_settings,
+ sizeof(integrated_info->dp0_ext_hdmi_6g_reg_settings));
+ result = true;
+ break;
+ case ENGINE_ID_DIGB:
+ settings->slv_addr = integrated_info->dp1_ext_hdmi_slv_addr;
+ settings->reg_num = integrated_info->dp1_ext_hdmi_6g_reg_num;
+ settings->reg_num_6g = integrated_info->dp1_ext_hdmi_6g_reg_num;
+ memmove(settings->reg_settings,
+ integrated_info->dp1_ext_hdmi_reg_settings,
+ sizeof(integrated_info->dp1_ext_hdmi_reg_settings));
+ memmove(settings->reg_settings_6g,
+ integrated_info->dp1_ext_hdmi_6g_reg_settings,
+ sizeof(integrated_info->dp1_ext_hdmi_6g_reg_settings));
+ result = true;
+ break;
+ case ENGINE_ID_DIGC:
+ settings->slv_addr = integrated_info->dp2_ext_hdmi_slv_addr;
+ settings->reg_num = integrated_info->dp2_ext_hdmi_6g_reg_num;
+ settings->reg_num_6g = integrated_info->dp2_ext_hdmi_6g_reg_num;
+ memmove(settings->reg_settings,
+ integrated_info->dp2_ext_hdmi_reg_settings,
+ sizeof(integrated_info->dp2_ext_hdmi_reg_settings));
+ memmove(settings->reg_settings_6g,
+ integrated_info->dp2_ext_hdmi_6g_reg_settings,
+ sizeof(integrated_info->dp2_ext_hdmi_6g_reg_settings));
+ result = true;
+ break;
+ case ENGINE_ID_DIGD:
+ settings->slv_addr = integrated_info->dp3_ext_hdmi_slv_addr;
+ settings->reg_num = integrated_info->dp3_ext_hdmi_6g_reg_num;
+ settings->reg_num_6g = integrated_info->dp3_ext_hdmi_6g_reg_num;
+ memmove(settings->reg_settings,
+ integrated_info->dp3_ext_hdmi_reg_settings,
+ sizeof(integrated_info->dp3_ext_hdmi_reg_settings));
+ memmove(settings->reg_settings_6g,
+ integrated_info->dp3_ext_hdmi_6g_reg_settings,
+ sizeof(integrated_info->dp3_ext_hdmi_6g_reg_settings));
+ result = true;
+ break;
+ default:
+ break;
+ }
+
+ if (result == true) {
+ // Validate settings from bios integrated info table
+ if (settings->slv_addr == 0)
+ return false;
+ if (settings->reg_num > 9)
+ return false;
+ if (settings->reg_num_6g > 3)
+ return false;
+
+ for (i = 0; i < settings->reg_num; i++) {
+ if (settings->reg_settings[i].i2c_reg_index > 0x20)
+ return false;
+ }
+
+ for (i = 0; i < settings->reg_num_6g; i++) {
+ if (settings->reg_settings_6g[i].i2c_reg_index > 0x20)
+ return false;
+ }
+ }
+ }
+
+ return result;
+}
+
+static bool write_i2c(struct pipe_ctx *pipe_ctx,
+ uint8_t address, uint8_t *buffer, uint32_t length)
+{
+ struct i2c_command cmd = {0};
+ struct i2c_payload payload = {0};
+
+ memset(&payload, 0, sizeof(payload));
+ memset(&cmd, 0, sizeof(cmd));
+
+ cmd.number_of_payloads = 1;
+ cmd.engine = I2C_COMMAND_ENGINE_DEFAULT;
+ cmd.speed = pipe_ctx->stream->ctx->dc->caps.i2c_speed_in_khz;
+
+ payload.address = address;
+ payload.data = buffer;
+ payload.length = length;
+ payload.write = true;
+ cmd.payloads = &payload;
+
+ if (dm_helpers_submit_i2c(pipe_ctx->stream->ctx,
+ pipe_ctx->stream->link, &cmd))
+ return true;
+
+ return false;
+}
+
+static void write_i2c_retimer_setting(
+ struct pipe_ctx *pipe_ctx,
+ bool is_vga_mode,
+ bool is_over_340mhz,
+ struct ext_hdmi_settings *settings)
+{
+ uint8_t slave_address = (settings->slv_addr >> 1);
+ uint8_t buffer[2];
+ const uint8_t apply_rx_tx_change = 0x4;
+ uint8_t offset = 0xA;
+ uint8_t value = 0;
+ int i = 0;
+ bool i2c_success = false;
+ DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
+
+ memset(&buffer, 0, sizeof(buffer));
+
+ /* Start Ext-Hdmi programming*/
+
+ for (i = 0; i < settings->reg_num; i++) {
+ /* Apply 3G settings */
+ if (settings->reg_settings[i].i2c_reg_index <= 0x20) {
+
+ buffer[0] = settings->reg_settings[i].i2c_reg_index;
+ buffer[1] = settings->reg_settings[i].i2c_reg_val;
+ i2c_success = write_i2c(pipe_ctx, slave_address,
+ buffer, sizeof(buffer));
+ RETIMER_REDRIVER_INFO("retimer write to slave_address = 0x%x,\
+ offset = 0x%x, reg_val= 0x%x, i2c_success = %d\n",
+ slave_address, buffer[0], buffer[1], i2c_success?1:0);
+
+ if (!i2c_success)
+ goto i2c_write_fail;
+
+ /* Based on DP159 specs, APPLY_RX_TX_CHANGE bit in 0x0A
+ * needs to be set to 1 on every 0xA-0xC write.
+ */
+ if (settings->reg_settings[i].i2c_reg_index == 0xA ||
+ settings->reg_settings[i].i2c_reg_index == 0xB ||
+ settings->reg_settings[i].i2c_reg_index == 0xC) {
+
+ /* Query current value from offset 0xA */
+ if (settings->reg_settings[i].i2c_reg_index == 0xA)
+ value = settings->reg_settings[i].i2c_reg_val;
+ else {
+ i2c_success =
+ link_query_ddc_data(
+ pipe_ctx->stream->link->ddc,
+ slave_address, &offset, 1, &value, 1);
+ if (!i2c_success)
+ goto i2c_write_fail;
+ }
+
+ buffer[0] = offset;
+ /* Set APPLY_RX_TX_CHANGE bit to 1 */
+ buffer[1] = value | apply_rx_tx_change;
+ i2c_success = write_i2c(pipe_ctx, slave_address,
+ buffer, sizeof(buffer));
+ RETIMER_REDRIVER_INFO("retimer write to slave_address = 0x%x,\
+ offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
+ slave_address, buffer[0], buffer[1], i2c_success?1:0);
+ if (!i2c_success)
+ goto i2c_write_fail;
+ }
+ }
+ }
+
+ /* Apply 3G settings */
+ if (is_over_340mhz) {
+ for (i = 0; i < settings->reg_num_6g; i++) {
+ /* Apply 3G settings */
+ if (settings->reg_settings[i].i2c_reg_index <= 0x20) {
+
+ buffer[0] = settings->reg_settings_6g[i].i2c_reg_index;
+ buffer[1] = settings->reg_settings_6g[i].i2c_reg_val;
+ i2c_success = write_i2c(pipe_ctx, slave_address,
+ buffer, sizeof(buffer));
+ RETIMER_REDRIVER_INFO("above 340Mhz: retimer write to slave_address = 0x%x,\
+ offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
+ slave_address, buffer[0], buffer[1], i2c_success?1:0);
+
+ if (!i2c_success)
+ goto i2c_write_fail;
+
+ /* Based on DP159 specs, APPLY_RX_TX_CHANGE bit in 0x0A
+ * needs to be set to 1 on every 0xA-0xC write.
+ */
+ if (settings->reg_settings_6g[i].i2c_reg_index == 0xA ||
+ settings->reg_settings_6g[i].i2c_reg_index == 0xB ||
+ settings->reg_settings_6g[i].i2c_reg_index == 0xC) {
+
+ /* Query current value from offset 0xA */
+ if (settings->reg_settings_6g[i].i2c_reg_index == 0xA)
+ value = settings->reg_settings_6g[i].i2c_reg_val;
+ else {
+ i2c_success =
+ link_query_ddc_data(
+ pipe_ctx->stream->link->ddc,
+ slave_address, &offset, 1, &value, 1);
+ if (!i2c_success)
+ goto i2c_write_fail;
+ }
+
+ buffer[0] = offset;
+ /* Set APPLY_RX_TX_CHANGE bit to 1 */
+ buffer[1] = value | apply_rx_tx_change;
+ i2c_success = write_i2c(pipe_ctx, slave_address,
+ buffer, sizeof(buffer));
+ RETIMER_REDRIVER_INFO("retimer write to slave_address = 0x%x,\
+ offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
+ slave_address, buffer[0], buffer[1], i2c_success?1:0);
+ if (!i2c_success)
+ goto i2c_write_fail;
+ }
+ }
+ }
+ }
+
+ if (is_vga_mode) {
+ /* Program additional settings if using 640x480 resolution */
+
+ /* Write offset 0xFF to 0x01 */
+ buffer[0] = 0xff;
+ buffer[1] = 0x01;
+ i2c_success = write_i2c(pipe_ctx, slave_address,
+ buffer, sizeof(buffer));
+ RETIMER_REDRIVER_INFO("retimer write to slave_address = 0x%x,\
+ offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
+ slave_address, buffer[0], buffer[1], i2c_success?1:0);
+ if (!i2c_success)
+ goto i2c_write_fail;
+
+ /* Write offset 0x00 to 0x23 */
+ buffer[0] = 0x00;
+ buffer[1] = 0x23;
+ i2c_success = write_i2c(pipe_ctx, slave_address,
+ buffer, sizeof(buffer));
+ RETIMER_REDRIVER_INFO("retimer write to slave_address = 0x%x,\
+ offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
+ slave_address, buffer[0], buffer[1], i2c_success?1:0);
+ if (!i2c_success)
+ goto i2c_write_fail;
+
+ /* Write offset 0xff to 0x00 */
+ buffer[0] = 0xff;
+ buffer[1] = 0x00;
+ i2c_success = write_i2c(pipe_ctx, slave_address,
+ buffer, sizeof(buffer));
+ RETIMER_REDRIVER_INFO("retimer write to slave_address = 0x%x,\
+ offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
+ slave_address, buffer[0], buffer[1], i2c_success?1:0);
+ if (!i2c_success)
+ goto i2c_write_fail;
+
+ }
+
+ return;
+
+i2c_write_fail:
+ DC_LOG_DEBUG("Set retimer failed");
+}
+
+static void write_i2c_default_retimer_setting(
+ struct pipe_ctx *pipe_ctx,
+ bool is_vga_mode,
+ bool is_over_340mhz)
+{
+ uint8_t slave_address = (0xBA >> 1);
+ uint8_t buffer[2];
+ bool i2c_success = false;
+ DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
+
+ memset(&buffer, 0, sizeof(buffer));
+
+ /* Program Slave Address for tuning single integrity */
+ /* Write offset 0x0A to 0x13 */
+ buffer[0] = 0x0A;
+ buffer[1] = 0x13;
+ i2c_success = write_i2c(pipe_ctx, slave_address,
+ buffer, sizeof(buffer));
+ RETIMER_REDRIVER_INFO("retimer writes default setting to slave_address = 0x%x,\
+ offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
+ slave_address, buffer[0], buffer[1], i2c_success?1:0);
+ if (!i2c_success)
+ goto i2c_write_fail;
+
+ /* Write offset 0x0A to 0x17 */
+ buffer[0] = 0x0A;
+ buffer[1] = 0x17;
+ i2c_success = write_i2c(pipe_ctx, slave_address,
+ buffer, sizeof(buffer));
+ RETIMER_REDRIVER_INFO("retimer write to slave_addr = 0x%x,\
+ offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
+ slave_address, buffer[0], buffer[1], i2c_success?1:0);
+ if (!i2c_success)
+ goto i2c_write_fail;
+
+ /* Write offset 0x0B to 0xDA or 0xD8 */
+ buffer[0] = 0x0B;
+ buffer[1] = is_over_340mhz ? 0xDA : 0xD8;
+ i2c_success = write_i2c(pipe_ctx, slave_address,
+ buffer, sizeof(buffer));
+ RETIMER_REDRIVER_INFO("retimer write to slave_addr = 0x%x,\
+ offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
+ slave_address, buffer[0], buffer[1], i2c_success?1:0);
+ if (!i2c_success)
+ goto i2c_write_fail;
+
+ /* Write offset 0x0A to 0x17 */
+ buffer[0] = 0x0A;
+ buffer[1] = 0x17;
+ i2c_success = write_i2c(pipe_ctx, slave_address,
+ buffer, sizeof(buffer));
+ RETIMER_REDRIVER_INFO("retimer write to slave_addr = 0x%x,\
+ offset = 0x%x, reg_val= 0x%x, i2c_success = %d\n",
+ slave_address, buffer[0], buffer[1], i2c_success?1:0);
+ if (!i2c_success)
+ goto i2c_write_fail;
+
+ /* Write offset 0x0C to 0x1D or 0x91 */
+ buffer[0] = 0x0C;
+ buffer[1] = is_over_340mhz ? 0x1D : 0x91;
+ i2c_success = write_i2c(pipe_ctx, slave_address,
+ buffer, sizeof(buffer));
+ RETIMER_REDRIVER_INFO("retimer write to slave_addr = 0x%x,\
+ offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
+ slave_address, buffer[0], buffer[1], i2c_success?1:0);
+ if (!i2c_success)
+ goto i2c_write_fail;
+
+ /* Write offset 0x0A to 0x17 */
+ buffer[0] = 0x0A;
+ buffer[1] = 0x17;
+ i2c_success = write_i2c(pipe_ctx, slave_address,
+ buffer, sizeof(buffer));
+ RETIMER_REDRIVER_INFO("retimer write to slave_addr = 0x%x,\
+ offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
+ slave_address, buffer[0], buffer[1], i2c_success?1:0);
+ if (!i2c_success)
+ goto i2c_write_fail;
+
+
+ if (is_vga_mode) {
+ /* Program additional settings if using 640x480 resolution */
+
+ /* Write offset 0xFF to 0x01 */
+ buffer[0] = 0xff;
+ buffer[1] = 0x01;
+ i2c_success = write_i2c(pipe_ctx, slave_address,
+ buffer, sizeof(buffer));
+ RETIMER_REDRIVER_INFO("retimer write to slave_addr = 0x%x,\
+ offset = 0x%x, reg_val = 0x%x, i2c_success = %d\n",
+ slave_address, buffer[0], buffer[1], i2c_success?1:0);
+ if (!i2c_success)
+ goto i2c_write_fail;
+
+ /* Write offset 0x00 to 0x23 */
+ buffer[0] = 0x00;
+ buffer[1] = 0x23;
+ i2c_success = write_i2c(pipe_ctx, slave_address,
+ buffer, sizeof(buffer));
+ RETIMER_REDRIVER_INFO("retimer write to slave_addr = 0x%x,\
+ offset = 0x%x, reg_val= 0x%x, i2c_success = %d\n",
+ slave_address, buffer[0], buffer[1], i2c_success?1:0);
+ if (!i2c_success)
+ goto i2c_write_fail;
+
+ /* Write offset 0xff to 0x00 */
+ buffer[0] = 0xff;
+ buffer[1] = 0x00;
+ i2c_success = write_i2c(pipe_ctx, slave_address,
+ buffer, sizeof(buffer));
+ RETIMER_REDRIVER_INFO("retimer write default setting to slave_addr = 0x%x,\
+ offset = 0x%x, reg_val= 0x%x, i2c_success = %d end here\n",
+ slave_address, buffer[0], buffer[1], i2c_success?1:0);
+ if (!i2c_success)
+ goto i2c_write_fail;
+ }
+
+ return;
+
+i2c_write_fail:
+ DC_LOG_DEBUG("Set default retimer failed");
+}
+
+static void write_i2c_redriver_setting(
+ struct pipe_ctx *pipe_ctx,
+ bool is_over_340mhz)
+{
+ uint8_t slave_address = (0xF0 >> 1);
+ uint8_t buffer[16];
+ bool i2c_success = false;
+ DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
+
+ memset(&buffer, 0, sizeof(buffer));
+
+ // Program Slave Address for tuning single integrity
+ buffer[3] = 0x4E;
+ buffer[4] = 0x4E;
+ buffer[5] = 0x4E;
+ buffer[6] = is_over_340mhz ? 0x4E : 0x4A;
+
+ i2c_success = write_i2c(pipe_ctx, slave_address,
+ buffer, sizeof(buffer));
+ RETIMER_REDRIVER_INFO("redriver write 0 to all 16 reg offset expect following:\n\
+ \t slave_addr = 0x%x, offset[3] = 0x%x, offset[4] = 0x%x,\
+ offset[5] = 0x%x,offset[6] is_over_340mhz = 0x%x,\
+ i2c_success = %d\n",
+ slave_address, buffer[3], buffer[4], buffer[5], buffer[6], i2c_success?1:0);
+
+ if (!i2c_success)
+ DC_LOG_DEBUG("Set redriver failed");
+}
+#if defined(CONFIG_DRM_AMD_DC_HDCP)
+
+static void update_psp_stream_config(struct pipe_ctx *pipe_ctx, bool dpms_off)
+{
+ struct cp_psp *cp_psp = &pipe_ctx->stream->ctx->cp_psp;
+ struct link_encoder *link_enc = NULL;
+ struct cp_psp_stream_config config = {0};
+ enum dp_panel_mode panel_mode =
+ dp_get_panel_mode(pipe_ctx->stream->link);
+
+ if (cp_psp == NULL || cp_psp->funcs.update_stream_config == NULL)
+ return;
+
+ link_enc = link_enc_cfg_get_link_enc(pipe_ctx->stream->link);
+ ASSERT(link_enc);
+ if (link_enc == NULL)
+ return;
+
+ /* otg instance */
+ config.otg_inst = (uint8_t) pipe_ctx->stream_res.tg->inst;
+
+ /* dig front end */
+ config.dig_fe = (uint8_t) pipe_ctx->stream_res.stream_enc->stream_enc_inst;
+
+ /* stream encoder index */
+ config.stream_enc_idx = pipe_ctx->stream_res.stream_enc->id - ENGINE_ID_DIGA;
+ if (link_is_dp_128b_132b_signal(pipe_ctx))
+ config.stream_enc_idx =
+ pipe_ctx->stream_res.hpo_dp_stream_enc->id - ENGINE_ID_HPO_DP_0;
+
+ /* dig back end */
+ config.dig_be = pipe_ctx->stream->link->link_enc_hw_inst;
+
+ /* link encoder index */
+ config.link_enc_idx = link_enc->transmitter - TRANSMITTER_UNIPHY_A;
+ if (link_is_dp_128b_132b_signal(pipe_ctx))
+ config.link_enc_idx = pipe_ctx->link_res.hpo_dp_link_enc->inst;
+
+ /* dio output index is dpia index for DPIA endpoint & dcio index by default */
+ if (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA)
+ config.dio_output_idx = pipe_ctx->stream->link->link_id.enum_id - ENUM_ID_1;
+ else
+ config.dio_output_idx = link_enc->transmitter - TRANSMITTER_UNIPHY_A;
+
+
+ /* phy index */
+ config.phy_idx = resource_transmitter_to_phy_idx(
+ pipe_ctx->stream->link->dc, link_enc->transmitter);
+ if (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA)
+ /* USB4 DPIA doesn't use PHY in our soc, initialize it to 0 */
+ config.phy_idx = 0;
+
+ /* stream properties */
+ config.assr_enabled = (panel_mode == DP_PANEL_MODE_EDP) ? 1 : 0;
+ config.mst_enabled = (pipe_ctx->stream->signal ==
+ SIGNAL_TYPE_DISPLAY_PORT_MST) ? 1 : 0;
+ config.dp2_enabled = link_is_dp_128b_132b_signal(pipe_ctx) ? 1 : 0;
+ config.usb4_enabled = (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) ?
+ 1 : 0;
+ config.dpms_off = dpms_off;
+
+ /* dm stream context */
+ config.dm_stream_ctx = pipe_ctx->stream->dm_stream_context;
+
+ cp_psp->funcs.update_stream_config(cp_psp->handle, &config);
+}
+#endif
+
+static void set_avmute(struct pipe_ctx *pipe_ctx, bool enable)
+{
+ struct dc *dc = pipe_ctx->stream->ctx->dc;
+
+ if (!dc_is_hdmi_signal(pipe_ctx->stream->signal))
+ return;
+
+ dc->hwss.set_avmute(pipe_ctx, enable);
+}
+
+static void enable_mst_on_sink(struct dc_link *link, bool enable)
+{
+ unsigned char mstmCntl;
+
+ core_link_read_dpcd(link, DP_MSTM_CTRL, &mstmCntl, 1);
+ if (enable)
+ mstmCntl |= DP_MST_EN;
+ else
+ mstmCntl &= (~DP_MST_EN);
+
+ core_link_write_dpcd(link, DP_MSTM_CTRL, &mstmCntl, 1);
+}
+
+static void dsc_optc_config_log(struct display_stream_compressor *dsc,
+ struct dsc_optc_config *config)
+{
+ uint32_t precision = 1 << 28;
+ uint32_t bytes_per_pixel_int = config->bytes_per_pixel / precision;
+ uint32_t bytes_per_pixel_mod = config->bytes_per_pixel % precision;
+ uint64_t ll_bytes_per_pix_fraq = bytes_per_pixel_mod;
+ DC_LOGGER_INIT(dsc->ctx->logger);
+
+ /* 7 fractional digits decimal precision for bytes per pixel is enough because DSC
+ * bits per pixel precision is 1/16th of a pixel, which means bytes per pixel precision is
+ * 1/16/8 = 1/128 of a byte, or 0.0078125 decimal
+ */
+ ll_bytes_per_pix_fraq *= 10000000;
+ ll_bytes_per_pix_fraq /= precision;
+
+ DC_LOG_DSC("\tbytes_per_pixel 0x%08x (%d.%07d)",
+ config->bytes_per_pixel, bytes_per_pixel_int, (uint32_t)ll_bytes_per_pix_fraq);
+ DC_LOG_DSC("\tis_pixel_format_444 %d", config->is_pixel_format_444);
+ DC_LOG_DSC("\tslice_width %d", config->slice_width);
+}
+
+static bool dp_set_dsc_on_rx(struct pipe_ctx *pipe_ctx, bool enable)
+{
+ struct dc *dc = pipe_ctx->stream->ctx->dc;
+ struct dc_stream_state *stream = pipe_ctx->stream;
+ bool result = false;
+
+ if (dc_is_virtual_signal(stream->signal) || IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
+ result = true;
+ else
+ result = dm_helpers_dp_write_dsc_enable(dc->ctx, stream, enable);
+ return result;
+}
+
+/* The stream with these settings can be sent (unblanked) only after DSC was enabled on RX first,
+ * i.e. after dp_enable_dsc_on_rx() had been called
+ */
+void link_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
+{
+ struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
+ struct dc *dc = pipe_ctx->stream->ctx->dc;
+ struct dc_stream_state *stream = pipe_ctx->stream;
+ struct pipe_ctx *odm_pipe;
+ int opp_cnt = 1;
+ DC_LOGGER_INIT(dsc->ctx->logger);
+
+ for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
+ opp_cnt++;
+
+ if (enable) {
+ struct dsc_config dsc_cfg;
+ struct dsc_optc_config dsc_optc_cfg;
+ enum optc_dsc_mode optc_dsc_mode;
+
+ /* Enable DSC hw block */
+ dsc_cfg.pic_width = (stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right) / opp_cnt;
+ dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom;
+ dsc_cfg.pixel_encoding = stream->timing.pixel_encoding;
+ dsc_cfg.color_depth = stream->timing.display_color_depth;
+ dsc_cfg.is_odm = pipe_ctx->next_odm_pipe ? true : false;
+ dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg;
+ ASSERT(dsc_cfg.dc_dsc_cfg.num_slices_h % opp_cnt == 0);
+ dsc_cfg.dc_dsc_cfg.num_slices_h /= opp_cnt;
+
+ dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg);
+ dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst);
+ for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
+ struct display_stream_compressor *odm_dsc = odm_pipe->stream_res.dsc;
+
+ odm_dsc->funcs->dsc_set_config(odm_dsc, &dsc_cfg, &dsc_optc_cfg);
+ odm_dsc->funcs->dsc_enable(odm_dsc, odm_pipe->stream_res.opp->inst);
+ }
+ dsc_cfg.dc_dsc_cfg.num_slices_h *= opp_cnt;
+ dsc_cfg.pic_width *= opp_cnt;
+
+ optc_dsc_mode = dsc_optc_cfg.is_pixel_format_444 ? OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED;
+
+ /* Enable DSC in encoder */
+ if (dc_is_dp_signal(stream->signal) && !IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)
+ && !link_is_dp_128b_132b_signal(pipe_ctx)) {
+ DC_LOG_DSC("Setting stream encoder DSC config for engine %d:", (int)pipe_ctx->stream_res.stream_enc->id);
+ dsc_optc_config_log(dsc, &dsc_optc_cfg);
+ pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config(pipe_ctx->stream_res.stream_enc,
+ optc_dsc_mode,
+ dsc_optc_cfg.bytes_per_pixel,
+ dsc_optc_cfg.slice_width);
+
+ /* PPS SDP is set elsewhere because it has to be done after DIG FE is connected to DIG BE */
+ }
+
+ /* Enable DSC in OPTC */
+ DC_LOG_DSC("Setting optc DSC config for tg instance %d:", pipe_ctx->stream_res.tg->inst);
+ dsc_optc_config_log(dsc, &dsc_optc_cfg);
+ pipe_ctx->stream_res.tg->funcs->set_dsc_config(pipe_ctx->stream_res.tg,
+ optc_dsc_mode,
+ dsc_optc_cfg.bytes_per_pixel,
+ dsc_optc_cfg.slice_width);
+ } else {
+ /* disable DSC in OPTC */
+ pipe_ctx->stream_res.tg->funcs->set_dsc_config(
+ pipe_ctx->stream_res.tg,
+ OPTC_DSC_DISABLED, 0, 0);
+
+ /* disable DSC in stream encoder */
+ if (dc_is_dp_signal(stream->signal)) {
+ if (link_is_dp_128b_132b_signal(pipe_ctx))
+ pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_set_dsc_pps_info_packet(
+ pipe_ctx->stream_res.hpo_dp_stream_enc,
+ false,
+ NULL,
+ true);
+ else if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
+ pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config(
+ pipe_ctx->stream_res.stream_enc,
+ OPTC_DSC_DISABLED, 0, 0);
+ pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet(
+ pipe_ctx->stream_res.stream_enc, false, NULL, true);
+ }
+ }
+
+ /* disable DSC block */
+ pipe_ctx->stream_res.dsc->funcs->dsc_disable(pipe_ctx->stream_res.dsc);
+ for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
+ odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc);
+ }
+}
+
+/*
+ * For dynamic bpp change case, dsc is programmed with MASTER_UPDATE_LOCK enabled;
+ * hence PPS info packet update need to use frame update instead of immediate update.
+ * Added parameter immediate_update for this purpose.
+ * The decision to use frame update is hard-coded in function dp_update_dsc_config(),
+ * which is the only place where a "false" would be passed in for param immediate_update.
+ *
+ * immediate_update is only applicable when DSC is enabled.
+ */
+bool link_set_dsc_pps_packet(struct pipe_ctx *pipe_ctx, bool enable, bool immediate_update)
+{
+ struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
+ struct dc_stream_state *stream = pipe_ctx->stream;
+ DC_LOGGER_INIT(dsc->ctx->logger);
+
+ if (!pipe_ctx->stream->timing.flags.DSC || !dsc)
+ return false;
+
+ if (enable) {
+ struct dsc_config dsc_cfg;
+ uint8_t dsc_packed_pps[128];
+
+ memset(&dsc_cfg, 0, sizeof(dsc_cfg));
+ memset(dsc_packed_pps, 0, 128);
+
+ /* Enable DSC hw block */
+ dsc_cfg.pic_width = stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right;
+ dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom;
+ dsc_cfg.pixel_encoding = stream->timing.pixel_encoding;
+ dsc_cfg.color_depth = stream->timing.display_color_depth;
+ dsc_cfg.is_odm = pipe_ctx->next_odm_pipe ? true : false;
+ dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg;
+
+ dsc->funcs->dsc_get_packed_pps(dsc, &dsc_cfg, &dsc_packed_pps[0]);
+ memcpy(&stream->dsc_packed_pps[0], &dsc_packed_pps[0], sizeof(stream->dsc_packed_pps));
+ if (dc_is_dp_signal(stream->signal)) {
+ DC_LOG_DSC("Setting stream encoder DSC PPS SDP for engine %d\n", (int)pipe_ctx->stream_res.stream_enc->id);
+ if (link_is_dp_128b_132b_signal(pipe_ctx))
+ pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_set_dsc_pps_info_packet(
+ pipe_ctx->stream_res.hpo_dp_stream_enc,
+ true,
+ &dsc_packed_pps[0],
+ immediate_update);
+ else
+ pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet(
+ pipe_ctx->stream_res.stream_enc,
+ true,
+ &dsc_packed_pps[0],
+ immediate_update);
+ }
+ } else {
+ /* disable DSC PPS in stream encoder */
+ memset(&stream->dsc_packed_pps[0], 0, sizeof(stream->dsc_packed_pps));
+ if (dc_is_dp_signal(stream->signal)) {
+ if (link_is_dp_128b_132b_signal(pipe_ctx))
+ pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_set_dsc_pps_info_packet(
+ pipe_ctx->stream_res.hpo_dp_stream_enc,
+ false,
+ NULL,
+ true);
+ else
+ pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet(
+ pipe_ctx->stream_res.stream_enc, false, NULL, true);
+ }
+ }
+
+ return true;
+}
+
+bool link_set_dsc_enable(struct pipe_ctx *pipe_ctx, bool enable)
+{
+ struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
+ bool result = false;
+
+ if (!pipe_ctx->stream->timing.flags.DSC)
+ goto out;
+ if (!dsc)
+ goto out;
+
+ if (enable) {
+ {
+ link_set_dsc_on_stream(pipe_ctx, true);
+ result = true;
+ }
+ } else {
+ dp_set_dsc_on_rx(pipe_ctx, false);
+ link_set_dsc_on_stream(pipe_ctx, false);
+ result = true;
+ }
+out:
+ return result;
+}
+
+bool link_update_dsc_config(struct pipe_ctx *pipe_ctx)
+{
+ struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
+
+ if (!pipe_ctx->stream->timing.flags.DSC)
+ return false;
+ if (!dsc)
+ return false;
+
+ link_set_dsc_on_stream(pipe_ctx, true);
+ link_set_dsc_pps_packet(pipe_ctx, true, false);
+ return true;
+}
+
+static void enable_stream_features(struct pipe_ctx *pipe_ctx)
+{
+ struct dc_stream_state *stream = pipe_ctx->stream;
+
+ if (pipe_ctx->stream->signal != SIGNAL_TYPE_DISPLAY_PORT_MST) {
+ struct dc_link *link = stream->link;
+ union down_spread_ctrl old_downspread;
+ union down_spread_ctrl new_downspread;
+
+ memset(&old_downspread, 0, sizeof(old_downspread));
+
+ core_link_read_dpcd(link, DP_DOWNSPREAD_CTRL,
+ &old_downspread.raw, sizeof(old_downspread));
+
+ new_downspread.raw = old_downspread.raw;
+
+ new_downspread.bits.IGNORE_MSA_TIMING_PARAM =
+ (stream->ignore_msa_timing_param) ? 1 : 0;
+
+ if (new_downspread.raw != old_downspread.raw) {
+ core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL,
+ &new_downspread.raw, sizeof(new_downspread));
+ }
+
+ } else {
+ dm_helpers_mst_enable_stream_features(stream);
+ }
+}
+
+static void dc_log_vcp_x_y(const struct dc_link *link, struct fixed31_32 avg_time_slots_per_mtp)
+{
+ const uint32_t VCP_Y_PRECISION = 1000;
+ uint64_t vcp_x, vcp_y;
+ DC_LOGGER_INIT(link->ctx->logger);
+
+ // Add 0.5*(1/VCP_Y_PRECISION) to round up to decimal precision
+ avg_time_slots_per_mtp = dc_fixpt_add(
+ avg_time_slots_per_mtp,
+ dc_fixpt_from_fraction(
+ 1,
+ 2*VCP_Y_PRECISION));
+
+ vcp_x = dc_fixpt_floor(
+ avg_time_slots_per_mtp);
+ vcp_y = dc_fixpt_floor(
+ dc_fixpt_mul_int(
+ dc_fixpt_sub_int(
+ avg_time_slots_per_mtp,
+ dc_fixpt_floor(
+ avg_time_slots_per_mtp)),
+ VCP_Y_PRECISION));
+
+
+ if (link->type == dc_connection_mst_branch)
+ DC_LOG_DP2("MST Update Payload: set_throttled_vcp_size slot X.Y for MST stream "
+ "X: %llu "
+ "Y: %llu/%d",
+ vcp_x,
+ vcp_y,
+ VCP_Y_PRECISION);
+ else
+ DC_LOG_DP2("SST Update Payload: set_throttled_vcp_size slot X.Y for SST stream "
+ "X: %llu "
+ "Y: %llu/%d",
+ vcp_x,
+ vcp_y,
+ VCP_Y_PRECISION);
+}
+
+static struct fixed31_32 get_pbn_per_slot(struct dc_stream_state *stream)
+{
+ struct fixed31_32 mbytes_per_sec;
+ uint32_t link_rate_in_mbytes_per_sec = dc_link_bandwidth_kbps(stream->link,
+ &stream->link->cur_link_settings);
+ link_rate_in_mbytes_per_sec /= 8000; /* Kbits to MBytes */
+
+ mbytes_per_sec = dc_fixpt_from_int(link_rate_in_mbytes_per_sec);
+
+ return dc_fixpt_div_int(mbytes_per_sec, 54);
+}
+
+static struct fixed31_32 get_pbn_from_bw_in_kbps(uint64_t kbps)
+{
+ struct fixed31_32 peak_kbps;
+ uint32_t numerator = 0;
+ uint32_t denominator = 1;
+
+ /*
+ * margin 5300ppm + 300ppm ~ 0.6% as per spec, factor is 1.006
+ * The unit of 54/64Mbytes/sec is an arbitrary unit chosen based on
+ * common multiplier to render an integer PBN for all link rate/lane
+ * counts combinations
+ * calculate
+ * peak_kbps *= (1006/1000)
+ * peak_kbps *= (64/54)
+ * peak_kbps *= 8 convert to bytes
+ */
+
+ numerator = 64 * PEAK_FACTOR_X1000;
+ denominator = 54 * 8 * 1000 * 1000;
+ kbps *= numerator;
+ peak_kbps = dc_fixpt_from_fraction(kbps, denominator);
+
+ return peak_kbps;
+}
+
+static struct fixed31_32 get_pbn_from_timing(struct pipe_ctx *pipe_ctx)
+{
+ uint64_t kbps;
+
+ kbps = dc_bandwidth_in_kbps_from_timing(&pipe_ctx->stream->timing);
+ return get_pbn_from_bw_in_kbps(kbps);
+}
+
+
+// TODO - DP2.0 Link: Fix get_lane_status to handle LTTPR offset (SST and MST)
+static void get_lane_status(
+ struct dc_link *link,
+ uint32_t lane_count,
+ union lane_status *status,
+ union lane_align_status_updated *status_updated)
+{
+ unsigned int lane;
+ uint8_t dpcd_buf[3] = {0};
+
+ if (status == NULL || status_updated == NULL) {
+ return;
+ }
+
+ core_link_read_dpcd(
+ link,
+ DP_LANE0_1_STATUS,
+ dpcd_buf,
+ sizeof(dpcd_buf));
+
+ for (lane = 0; lane < lane_count; lane++) {
+ status[lane].raw = dp_get_nibble_at_index(&dpcd_buf[0], lane);
+ }
+
+ status_updated->raw = dpcd_buf[2];
+}
+
+static bool poll_for_allocation_change_trigger(struct dc_link *link)
+{
+ /*
+ * wait for ACT handled
+ */
+ int i;
+ const int act_retries = 30;
+ enum act_return_status result = ACT_FAILED;
+ union payload_table_update_status update_status = {0};
+ union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX];
+ union lane_align_status_updated lane_status_updated;
+ DC_LOGGER_INIT(link->ctx->logger);
+
+ if (link->aux_access_disabled)
+ return true;
+ for (i = 0; i < act_retries; i++) {
+ get_lane_status(link, link->cur_link_settings.lane_count, dpcd_lane_status, &lane_status_updated);
+
+ if (!dp_is_cr_done(link->cur_link_settings.lane_count, dpcd_lane_status) ||
+ !dp_is_ch_eq_done(link->cur_link_settings.lane_count, dpcd_lane_status) ||
+ !dp_is_symbol_locked(link->cur_link_settings.lane_count, dpcd_lane_status) ||
+ !dp_is_interlane_aligned(lane_status_updated)) {
+ DC_LOG_ERROR("SST Update Payload: Link loss occurred while "
+ "polling for ACT handled.");
+ result = ACT_LINK_LOST;
+ break;
+ }
+ core_link_read_dpcd(
+ link,
+ DP_PAYLOAD_TABLE_UPDATE_STATUS,
+ &update_status.raw,
+ 1);
+
+ if (update_status.bits.ACT_HANDLED == 1) {
+ DC_LOG_DP2("SST Update Payload: ACT handled by downstream.");
+ result = ACT_SUCCESS;
+ break;
+ }
+
+ msleep(5);
+ }
+
+ if (result == ACT_FAILED) {
+ DC_LOG_ERROR("SST Update Payload: ACT still not handled after retries, "
+ "continue on. Something is wrong with the branch.");
+ }
+
+ return (result == ACT_SUCCESS);
+}
+
+static void update_mst_stream_alloc_table(
+ struct dc_link *link,
+ struct stream_encoder *stream_enc,
+ struct hpo_dp_stream_encoder *hpo_dp_stream_enc, // TODO: Rename stream_enc to dio_stream_enc?
+ const struct dc_dp_mst_stream_allocation_table *proposed_table)
+{
+ struct link_mst_stream_allocation work_table[MAX_CONTROLLER_NUM] = { 0 };
+ struct link_mst_stream_allocation *dc_alloc;
+
+ int i;
+ int j;
+
+ /* if DRM proposed_table has more than one new payload */
+ ASSERT(proposed_table->stream_count -
+ link->mst_stream_alloc_table.stream_count < 2);
+
+ /* copy proposed_table to link, add stream encoder */
+ for (i = 0; i < proposed_table->stream_count; i++) {
+
+ for (j = 0; j < link->mst_stream_alloc_table.stream_count; j++) {
+ dc_alloc =
+ &link->mst_stream_alloc_table.stream_allocations[j];
+
+ if (dc_alloc->vcp_id ==
+ proposed_table->stream_allocations[i].vcp_id) {
+
+ work_table[i] = *dc_alloc;
+ work_table[i].slot_count = proposed_table->stream_allocations[i].slot_count;
+ break; /* exit j loop */
+ }
+ }
+
+ /* new vcp_id */
+ if (j == link->mst_stream_alloc_table.stream_count) {
+ work_table[i].vcp_id =
+ proposed_table->stream_allocations[i].vcp_id;
+ work_table[i].slot_count =
+ proposed_table->stream_allocations[i].slot_count;
+ work_table[i].stream_enc = stream_enc;
+ work_table[i].hpo_dp_stream_enc = hpo_dp_stream_enc;
+ }
+ }
+
+ /* update link->mst_stream_alloc_table with work_table */
+ link->mst_stream_alloc_table.stream_count =
+ proposed_table->stream_count;
+ for (i = 0; i < MAX_CONTROLLER_NUM; i++)
+ link->mst_stream_alloc_table.stream_allocations[i] =
+ work_table[i];
+}
+
+static void remove_stream_from_alloc_table(
+ struct dc_link *link,
+ struct stream_encoder *dio_stream_enc,
+ struct hpo_dp_stream_encoder *hpo_dp_stream_enc)
+{
+ int i = 0;
+ struct link_mst_stream_allocation_table *table =
+ &link->mst_stream_alloc_table;
+
+ if (hpo_dp_stream_enc) {
+ for (; i < table->stream_count; i++)
+ if (hpo_dp_stream_enc == table->stream_allocations[i].hpo_dp_stream_enc)
+ break;
+ } else {
+ for (; i < table->stream_count; i++)
+ if (dio_stream_enc == table->stream_allocations[i].stream_enc)
+ break;
+ }
+
+ if (i < table->stream_count) {
+ i++;
+ for (; i < table->stream_count; i++)
+ table->stream_allocations[i-1] = table->stream_allocations[i];
+ memset(&table->stream_allocations[table->stream_count-1], 0,
+ sizeof(struct link_mst_stream_allocation));
+ table->stream_count--;
+ }
+}
+
+static enum dc_status deallocate_mst_payload_with_temp_drm_wa(
+ struct pipe_ctx *pipe_ctx)
+{
+ struct dc_stream_state *stream = pipe_ctx->stream;
+ struct dc_link *link = stream->link;
+ struct dc_dp_mst_stream_allocation_table proposed_table = {0};
+ struct fixed31_32 avg_time_slots_per_mtp = dc_fixpt_from_int(0);
+ int i;
+ bool mst_mode = (link->type == dc_connection_mst_branch);
+ /* adjust for drm changes*/
+ const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
+ const struct dc_link_settings empty_link_settings = {0};
+ DC_LOGGER_INIT(link->ctx->logger);
+
+ if (link_hwss->ext.set_throttled_vcp_size)
+ link_hwss->ext.set_throttled_vcp_size(pipe_ctx, avg_time_slots_per_mtp);
+ if (link_hwss->ext.set_hblank_min_symbol_width)
+ link_hwss->ext.set_hblank_min_symbol_width(pipe_ctx,
+ &empty_link_settings,
+ avg_time_slots_per_mtp);
+
+ if (dm_helpers_dp_mst_write_payload_allocation_table(
+ stream->ctx,
+ stream,
+ &proposed_table,
+ false))
+ update_mst_stream_alloc_table(
+ link,
+ pipe_ctx->stream_res.stream_enc,
+ pipe_ctx->stream_res.hpo_dp_stream_enc,
+ &proposed_table);
+ else
+ DC_LOG_WARNING("Failed to update"
+ "MST allocation table for"
+ "pipe idx:%d\n",
+ pipe_ctx->pipe_idx);
+
+ DC_LOG_MST("%s"
+ "stream_count: %d: ",
+ __func__,
+ link->mst_stream_alloc_table.stream_count);
+
+ for (i = 0; i < MAX_CONTROLLER_NUM; i++) {
+ DC_LOG_MST("stream_enc[%d]: %p "
+ "stream[%d].hpo_dp_stream_enc: %p "
+ "stream[%d].vcp_id: %d "
+ "stream[%d].slot_count: %d\n",
+ i,
+ (void *) link->mst_stream_alloc_table.stream_allocations[i].stream_enc,
+ i,
+ (void *) link->mst_stream_alloc_table.stream_allocations[i].hpo_dp_stream_enc,
+ i,
+ link->mst_stream_alloc_table.stream_allocations[i].vcp_id,
+ i,
+ link->mst_stream_alloc_table.stream_allocations[i].slot_count);
+ }
+
+ if (link_hwss->ext.update_stream_allocation_table == NULL ||
+ link_dp_get_encoding_format(&link->cur_link_settings) == DP_UNKNOWN_ENCODING) {
+ DC_LOG_DEBUG("Unknown encoding format\n");
+ return DC_ERROR_UNEXPECTED;
+ }
+
+ link_hwss->ext.update_stream_allocation_table(link, &pipe_ctx->link_res,
+ &link->mst_stream_alloc_table);
+
+ if (mst_mode) {
+ dm_helpers_dp_mst_poll_for_allocation_change_trigger(
+ stream->ctx,
+ stream);
+ }
+
+ dm_helpers_dp_mst_send_payload_allocation(
+ stream->ctx,
+ stream,
+ false);
+
+ return DC_OK;
+}
+
+static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx)
+{
+ struct dc_stream_state *stream = pipe_ctx->stream;
+ struct dc_link *link = stream->link;
+ struct dc_dp_mst_stream_allocation_table proposed_table = {0};
+ struct fixed31_32 avg_time_slots_per_mtp = dc_fixpt_from_int(0);
+ int i;
+ bool mst_mode = (link->type == dc_connection_mst_branch);
+ const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
+ const struct dc_link_settings empty_link_settings = {0};
+ DC_LOGGER_INIT(link->ctx->logger);
+
+ if (link->dc->debug.temp_mst_deallocation_sequence)
+ return deallocate_mst_payload_with_temp_drm_wa(pipe_ctx);
+
+ /* deallocate_mst_payload is called before disable link. When mode or
+ * disable/enable monitor, new stream is created which is not in link
+ * stream[] yet. For this, payload is not allocated yet, so de-alloc
+ * should not done. For new mode set, map_resources will get engine
+ * for new stream, so stream_enc->id should be validated until here.
+ */
+
+ /* slot X.Y */
+ if (link_hwss->ext.set_throttled_vcp_size)
+ link_hwss->ext.set_throttled_vcp_size(pipe_ctx, avg_time_slots_per_mtp);
+ if (link_hwss->ext.set_hblank_min_symbol_width)
+ link_hwss->ext.set_hblank_min_symbol_width(pipe_ctx,
+ &empty_link_settings,
+ avg_time_slots_per_mtp);
+
+ if (mst_mode) {
+ /* when link is in mst mode, reply on mst manager to remove
+ * payload
+ */
+ if (dm_helpers_dp_mst_write_payload_allocation_table(
+ stream->ctx,
+ stream,
+ &proposed_table,
+ false))
+ update_mst_stream_alloc_table(
+ link,
+ pipe_ctx->stream_res.stream_enc,
+ pipe_ctx->stream_res.hpo_dp_stream_enc,
+ &proposed_table);
+ else
+ DC_LOG_WARNING("Failed to update"
+ "MST allocation table for"
+ "pipe idx:%d\n",
+ pipe_ctx->pipe_idx);
+ } else {
+ /* when link is no longer in mst mode (mst hub unplugged),
+ * remove payload with default dc logic
+ */
+ remove_stream_from_alloc_table(link, pipe_ctx->stream_res.stream_enc,
+ pipe_ctx->stream_res.hpo_dp_stream_enc);
+ }
+
+ DC_LOG_MST("%s"
+ "stream_count: %d: ",
+ __func__,
+ link->mst_stream_alloc_table.stream_count);
+
+ for (i = 0; i < MAX_CONTROLLER_NUM; i++) {
+ DC_LOG_MST("stream_enc[%d]: %p "
+ "stream[%d].hpo_dp_stream_enc: %p "
+ "stream[%d].vcp_id: %d "
+ "stream[%d].slot_count: %d\n",
+ i,
+ (void *) link->mst_stream_alloc_table.stream_allocations[i].stream_enc,
+ i,
+ (void *) link->mst_stream_alloc_table.stream_allocations[i].hpo_dp_stream_enc,
+ i,
+ link->mst_stream_alloc_table.stream_allocations[i].vcp_id,
+ i,
+ link->mst_stream_alloc_table.stream_allocations[i].slot_count);
+ }
+
+ /* update mst stream allocation table hardware state */
+ if (link_hwss->ext.update_stream_allocation_table == NULL ||
+ link_dp_get_encoding_format(&link->cur_link_settings) == DP_UNKNOWN_ENCODING) {
+ DC_LOG_DEBUG("Unknown encoding format\n");
+ return DC_ERROR_UNEXPECTED;
+ }
+
+ link_hwss->ext.update_stream_allocation_table(link, &pipe_ctx->link_res,
+ &link->mst_stream_alloc_table);
+
+ if (mst_mode) {
+ dm_helpers_dp_mst_poll_for_allocation_change_trigger(
+ stream->ctx,
+ stream);
+
+ dm_helpers_dp_mst_send_payload_allocation(
+ stream->ctx,
+ stream,
+ false);
+ }
+
+ return DC_OK;
+}
+
+/* convert link_mst_stream_alloc_table to dm dp_mst_stream_alloc_table
+ * because stream_encoder is not exposed to dm
+ */
+static enum dc_status allocate_mst_payload(struct pipe_ctx *pipe_ctx)
+{
+ struct dc_stream_state *stream = pipe_ctx->stream;
+ struct dc_link *link = stream->link;
+ struct dc_dp_mst_stream_allocation_table proposed_table = {0};
+ struct fixed31_32 avg_time_slots_per_mtp;
+ struct fixed31_32 pbn;
+ struct fixed31_32 pbn_per_slot;
+ int i;
+ enum act_return_status ret;
+ const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
+ DC_LOGGER_INIT(link->ctx->logger);
+
+ /* enable_link_dp_mst already check link->enabled_stream_count
+ * and stream is in link->stream[]. This is called during set mode,
+ * stream_enc is available.
+ */
+
+ /* get calculate VC payload for stream: stream_alloc */
+ if (dm_helpers_dp_mst_write_payload_allocation_table(
+ stream->ctx,
+ stream,
+ &proposed_table,
+ true))
+ update_mst_stream_alloc_table(
+ link,
+ pipe_ctx->stream_res.stream_enc,
+ pipe_ctx->stream_res.hpo_dp_stream_enc,
+ &proposed_table);
+ else
+ DC_LOG_WARNING("Failed to update"
+ "MST allocation table for"
+ "pipe idx:%d\n",
+ pipe_ctx->pipe_idx);
+
+ DC_LOG_MST("%s "
+ "stream_count: %d: \n ",
+ __func__,
+ link->mst_stream_alloc_table.stream_count);
+
+ for (i = 0; i < MAX_CONTROLLER_NUM; i++) {
+ DC_LOG_MST("stream_enc[%d]: %p "
+ "stream[%d].hpo_dp_stream_enc: %p "
+ "stream[%d].vcp_id: %d "
+ "stream[%d].slot_count: %d\n",
+ i,
+ (void *) link->mst_stream_alloc_table.stream_allocations[i].stream_enc,
+ i,
+ (void *) link->mst_stream_alloc_table.stream_allocations[i].hpo_dp_stream_enc,
+ i,
+ link->mst_stream_alloc_table.stream_allocations[i].vcp_id,
+ i,
+ link->mst_stream_alloc_table.stream_allocations[i].slot_count);
+ }
+
+ ASSERT(proposed_table.stream_count > 0);
+
+ /* program DP source TX for payload */
+ if (link_hwss->ext.update_stream_allocation_table == NULL ||
+ link_dp_get_encoding_format(&link->cur_link_settings) == DP_UNKNOWN_ENCODING) {
+ DC_LOG_ERROR("Failure: unknown encoding format\n");
+ return DC_ERROR_UNEXPECTED;
+ }
+
+ link_hwss->ext.update_stream_allocation_table(link,
+ &pipe_ctx->link_res,
+ &link->mst_stream_alloc_table);
+
+ /* send down message */
+ ret = dm_helpers_dp_mst_poll_for_allocation_change_trigger(
+ stream->ctx,
+ stream);
+
+ if (ret != ACT_LINK_LOST) {
+ dm_helpers_dp_mst_send_payload_allocation(
+ stream->ctx,
+ stream,
+ true);
+ }
+
+ /* slot X.Y for only current stream */
+ pbn_per_slot = get_pbn_per_slot(stream);
+ if (pbn_per_slot.value == 0) {
+ DC_LOG_ERROR("Failure: pbn_per_slot==0 not allowed. Cannot continue, returning DC_UNSUPPORTED_VALUE.\n");
+ return DC_UNSUPPORTED_VALUE;
+ }
+ pbn = get_pbn_from_timing(pipe_ctx);
+ avg_time_slots_per_mtp = dc_fixpt_div(pbn, pbn_per_slot);
+
+ dc_log_vcp_x_y(link, avg_time_slots_per_mtp);
+
+ if (link_hwss->ext.set_throttled_vcp_size)
+ link_hwss->ext.set_throttled_vcp_size(pipe_ctx, avg_time_slots_per_mtp);
+ if (link_hwss->ext.set_hblank_min_symbol_width)
+ link_hwss->ext.set_hblank_min_symbol_width(pipe_ctx,
+ &link->cur_link_settings,
+ avg_time_slots_per_mtp);
+
+ return DC_OK;
+}
+
+struct fixed31_32 link_calculate_sst_avg_time_slots_per_mtp(
+ const struct dc_stream_state *stream,
+ const struct dc_link *link)
+{
+ struct fixed31_32 link_bw_effective =
+ dc_fixpt_from_int(
+ dc_link_bandwidth_kbps(link, &link->cur_link_settings));
+ struct fixed31_32 timeslot_bw_effective =
+ dc_fixpt_div_int(link_bw_effective, MAX_MTP_SLOT_COUNT);
+ struct fixed31_32 timing_bw =
+ dc_fixpt_from_int(
+ dc_bandwidth_in_kbps_from_timing(&stream->timing));
+ struct fixed31_32 avg_time_slots_per_mtp =
+ dc_fixpt_div(timing_bw, timeslot_bw_effective);
+
+ return avg_time_slots_per_mtp;
+}
+
+
+static bool write_128b_132b_sst_payload_allocation_table(
+ const struct dc_stream_state *stream,
+ struct dc_link *link,
+ struct link_mst_stream_allocation_table *proposed_table,
+ bool allocate)
+{
+ const uint8_t vc_id = 1; /// VC ID always 1 for SST
+ const uint8_t start_time_slot = 0; /// Always start at time slot 0 for SST
+ bool result = false;
+ uint8_t req_slot_count = 0;
+ struct fixed31_32 avg_time_slots_per_mtp = { 0 };
+ union payload_table_update_status update_status = { 0 };
+ const uint32_t max_retries = 30;
+ uint32_t retries = 0;
+ DC_LOGGER_INIT(link->ctx->logger);
+
+ if (allocate) {
+ avg_time_slots_per_mtp = link_calculate_sst_avg_time_slots_per_mtp(stream, link);
+ req_slot_count = dc_fixpt_ceil(avg_time_slots_per_mtp);
+ /// Validation should filter out modes that exceed link BW
+ ASSERT(req_slot_count <= MAX_MTP_SLOT_COUNT);
+ if (req_slot_count > MAX_MTP_SLOT_COUNT)
+ return false;
+ } else {
+ /// Leave req_slot_count = 0 if allocate is false.
+ }
+
+ proposed_table->stream_count = 1; /// Always 1 stream for SST
+ proposed_table->stream_allocations[0].slot_count = req_slot_count;
+ proposed_table->stream_allocations[0].vcp_id = vc_id;
+
+ if (link->aux_access_disabled)
+ return true;
+
+ /// Write DPCD 2C0 = 1 to start updating
+ update_status.bits.VC_PAYLOAD_TABLE_UPDATED = 1;
+ core_link_write_dpcd(
+ link,
+ DP_PAYLOAD_TABLE_UPDATE_STATUS,
+ &update_status.raw,
+ 1);
+
+ /// Program the changes in DPCD 1C0 - 1C2
+ ASSERT(vc_id == 1);
+ core_link_write_dpcd(
+ link,
+ DP_PAYLOAD_ALLOCATE_SET,
+ &vc_id,
+ 1);
+
+ ASSERT(start_time_slot == 0);
+ core_link_write_dpcd(
+ link,
+ DP_PAYLOAD_ALLOCATE_START_TIME_SLOT,
+ &start_time_slot,
+ 1);
+
+ core_link_write_dpcd(
+ link,
+ DP_PAYLOAD_ALLOCATE_TIME_SLOT_COUNT,
+ &req_slot_count,
+ 1);
+
+ /// Poll till DPCD 2C0 read 1
+ /// Try for at least 150ms (30 retries, with 5ms delay after each attempt)
+
+ while (retries < max_retries) {
+ if (core_link_read_dpcd(
+ link,
+ DP_PAYLOAD_TABLE_UPDATE_STATUS,
+ &update_status.raw,
+ 1) == DC_OK) {
+ if (update_status.bits.VC_PAYLOAD_TABLE_UPDATED == 1) {
+ DC_LOG_DP2("SST Update Payload: downstream payload table updated.");
+ result = true;
+ break;
+ }
+ } else {
+ union dpcd_rev dpcdRev;
+
+ if (core_link_read_dpcd(
+ link,
+ DP_DPCD_REV,
+ &dpcdRev.raw,
+ 1) != DC_OK) {
+ DC_LOG_ERROR("SST Update Payload: Unable to read DPCD revision "
+ "of sink while polling payload table "
+ "updated status bit.");
+ break;
+ }
+ }
+ retries++;
+ msleep(5);
+ }
+
+ if (!result && retries == max_retries) {
+ DC_LOG_ERROR("SST Update Payload: Payload table not updated after retries, "
+ "continue on. Something is wrong with the branch.");
+ // TODO - DP2.0 Payload: Read and log the payload table from downstream branch
+ }
+
+ return result;
+}
+
+/*
+ * Payload allocation/deallocation for SST introduced in DP2.0
+ */
+static enum dc_status update_sst_payload(struct pipe_ctx *pipe_ctx,
+ bool allocate)
+{
+ struct dc_stream_state *stream = pipe_ctx->stream;
+ struct dc_link *link = stream->link;
+ struct link_mst_stream_allocation_table proposed_table = {0};
+ struct fixed31_32 avg_time_slots_per_mtp;
+ const struct dc_link_settings empty_link_settings = {0};
+ const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
+ DC_LOGGER_INIT(link->ctx->logger);
+
+ /* slot X.Y for SST payload deallocate */
+ if (!allocate) {
+ avg_time_slots_per_mtp = dc_fixpt_from_int(0);
+
+ dc_log_vcp_x_y(link, avg_time_slots_per_mtp);
+
+ if (link_hwss->ext.set_throttled_vcp_size)
+ link_hwss->ext.set_throttled_vcp_size(pipe_ctx,
+ avg_time_slots_per_mtp);
+ if (link_hwss->ext.set_hblank_min_symbol_width)
+ link_hwss->ext.set_hblank_min_symbol_width(pipe_ctx,
+ &empty_link_settings,
+ avg_time_slots_per_mtp);
+ }
+
+ /* calculate VC payload and update branch with new payload allocation table*/
+ if (!write_128b_132b_sst_payload_allocation_table(
+ stream,
+ link,
+ &proposed_table,
+ allocate)) {
+ DC_LOG_ERROR("SST Update Payload: Failed to update "
+ "allocation table for "
+ "pipe idx: %d\n",
+ pipe_ctx->pipe_idx);
+ return DC_FAIL_DP_PAYLOAD_ALLOCATION;
+ }
+
+ proposed_table.stream_allocations[0].hpo_dp_stream_enc = pipe_ctx->stream_res.hpo_dp_stream_enc;
+
+ ASSERT(proposed_table.stream_count == 1);
+
+ //TODO - DP2.0 Logging: Instead of hpo_dp_stream_enc pointer, log instance id
+ DC_LOG_DP2("SST Update Payload: hpo_dp_stream_enc: %p "
+ "vcp_id: %d "
+ "slot_count: %d\n",
+ (void *) proposed_table.stream_allocations[0].hpo_dp_stream_enc,
+ proposed_table.stream_allocations[0].vcp_id,
+ proposed_table.stream_allocations[0].slot_count);
+
+ /* program DP source TX for payload */
+ link_hwss->ext.update_stream_allocation_table(link, &pipe_ctx->link_res,
+ &proposed_table);
+
+ /* poll for ACT handled */
+ if (!poll_for_allocation_change_trigger(link)) {
+ // Failures will result in blackscreen and errors logged
+ BREAK_TO_DEBUGGER();
+ }
+
+ /* slot X.Y for SST payload allocate */
+ if (allocate && link_dp_get_encoding_format(&link->cur_link_settings) ==
+ DP_128b_132b_ENCODING) {
+ avg_time_slots_per_mtp = link_calculate_sst_avg_time_slots_per_mtp(stream, link);
+
+ dc_log_vcp_x_y(link, avg_time_slots_per_mtp);
+
+ if (link_hwss->ext.set_throttled_vcp_size)
+ link_hwss->ext.set_throttled_vcp_size(pipe_ctx,
+ avg_time_slots_per_mtp);
+ if (link_hwss->ext.set_hblank_min_symbol_width)
+ link_hwss->ext.set_hblank_min_symbol_width(pipe_ctx,
+ &link->cur_link_settings,
+ avg_time_slots_per_mtp);
+ }
+
+ /* Always return DC_OK.
+ * If part of sequence fails, log failure(s) and show blackscreen
+ */
+ return DC_OK;
+}
+
+enum dc_status link_reduce_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t bw_in_kbps)
+{
+ struct dc_stream_state *stream = pipe_ctx->stream;
+ struct dc_link *link = stream->link;
+ struct fixed31_32 avg_time_slots_per_mtp;
+ struct fixed31_32 pbn;
+ struct fixed31_32 pbn_per_slot;
+ struct dc_dp_mst_stream_allocation_table proposed_table = {0};
+ uint8_t i;
+ const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
+ DC_LOGGER_INIT(link->ctx->logger);
+
+ /* decrease throttled vcp size */
+ pbn_per_slot = get_pbn_per_slot(stream);
+ pbn = get_pbn_from_bw_in_kbps(bw_in_kbps);
+ avg_time_slots_per_mtp = dc_fixpt_div(pbn, pbn_per_slot);
+
+ if (link_hwss->ext.set_throttled_vcp_size)
+ link_hwss->ext.set_throttled_vcp_size(pipe_ctx, avg_time_slots_per_mtp);
+ if (link_hwss->ext.set_hblank_min_symbol_width)
+ link_hwss->ext.set_hblank_min_symbol_width(pipe_ctx,
+ &link->cur_link_settings,
+ avg_time_slots_per_mtp);
+
+ /* send ALLOCATE_PAYLOAD sideband message with updated pbn */
+ dm_helpers_dp_mst_send_payload_allocation(
+ stream->ctx,
+ stream,
+ true);
+
+ /* notify immediate branch device table update */
+ if (dm_helpers_dp_mst_write_payload_allocation_table(
+ stream->ctx,
+ stream,
+ &proposed_table,
+ true)) {
+ /* update mst stream allocation table software state */
+ update_mst_stream_alloc_table(
+ link,
+ pipe_ctx->stream_res.stream_enc,
+ pipe_ctx->stream_res.hpo_dp_stream_enc,
+ &proposed_table);
+ } else {
+ DC_LOG_WARNING("Failed to update"
+ "MST allocation table for"
+ "pipe idx:%d\n",
+ pipe_ctx->pipe_idx);
+ }
+
+ DC_LOG_MST("%s "
+ "stream_count: %d: \n ",
+ __func__,
+ link->mst_stream_alloc_table.stream_count);
+
+ for (i = 0; i < MAX_CONTROLLER_NUM; i++) {
+ DC_LOG_MST("stream_enc[%d]: %p "
+ "stream[%d].hpo_dp_stream_enc: %p "
+ "stream[%d].vcp_id: %d "
+ "stream[%d].slot_count: %d\n",
+ i,
+ (void *) link->mst_stream_alloc_table.stream_allocations[i].stream_enc,
+ i,
+ (void *) link->mst_stream_alloc_table.stream_allocations[i].hpo_dp_stream_enc,
+ i,
+ link->mst_stream_alloc_table.stream_allocations[i].vcp_id,
+ i,
+ link->mst_stream_alloc_table.stream_allocations[i].slot_count);
+ }
+
+ ASSERT(proposed_table.stream_count > 0);
+
+ /* update mst stream allocation table hardware state */
+ if (link_hwss->ext.update_stream_allocation_table == NULL ||
+ link_dp_get_encoding_format(&link->cur_link_settings) == DP_UNKNOWN_ENCODING) {
+ DC_LOG_ERROR("Failure: unknown encoding format\n");
+ return DC_ERROR_UNEXPECTED;
+ }
+
+ link_hwss->ext.update_stream_allocation_table(link, &pipe_ctx->link_res,
+ &link->mst_stream_alloc_table);
+
+ /* poll for immediate branch device ACT handled */
+ dm_helpers_dp_mst_poll_for_allocation_change_trigger(
+ stream->ctx,
+ stream);
+
+ return DC_OK;
+}
+
+enum dc_status link_increase_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t bw_in_kbps)
+{
+ struct dc_stream_state *stream = pipe_ctx->stream;
+ struct dc_link *link = stream->link;
+ struct fixed31_32 avg_time_slots_per_mtp;
+ struct fixed31_32 pbn;
+ struct fixed31_32 pbn_per_slot;
+ struct dc_dp_mst_stream_allocation_table proposed_table = {0};
+ uint8_t i;
+ enum act_return_status ret;
+ const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
+ DC_LOGGER_INIT(link->ctx->logger);
+
+ /* notify immediate branch device table update */
+ if (dm_helpers_dp_mst_write_payload_allocation_table(
+ stream->ctx,
+ stream,
+ &proposed_table,
+ true)) {
+ /* update mst stream allocation table software state */
+ update_mst_stream_alloc_table(
+ link,
+ pipe_ctx->stream_res.stream_enc,
+ pipe_ctx->stream_res.hpo_dp_stream_enc,
+ &proposed_table);
+ }
+
+ DC_LOG_MST("%s "
+ "stream_count: %d: \n ",
+ __func__,
+ link->mst_stream_alloc_table.stream_count);
+
+ for (i = 0; i < MAX_CONTROLLER_NUM; i++) {
+ DC_LOG_MST("stream_enc[%d]: %p "
+ "stream[%d].hpo_dp_stream_enc: %p "
+ "stream[%d].vcp_id: %d "
+ "stream[%d].slot_count: %d\n",
+ i,
+ (void *) link->mst_stream_alloc_table.stream_allocations[i].stream_enc,
+ i,
+ (void *) link->mst_stream_alloc_table.stream_allocations[i].hpo_dp_stream_enc,
+ i,
+ link->mst_stream_alloc_table.stream_allocations[i].vcp_id,
+ i,
+ link->mst_stream_alloc_table.stream_allocations[i].slot_count);
+ }
+
+ ASSERT(proposed_table.stream_count > 0);
+
+ /* update mst stream allocation table hardware state */
+ if (link_hwss->ext.update_stream_allocation_table == NULL ||
+ link_dp_get_encoding_format(&link->cur_link_settings) == DP_UNKNOWN_ENCODING) {
+ DC_LOG_ERROR("Failure: unknown encoding format\n");
+ return DC_ERROR_UNEXPECTED;
+ }
+
+ link_hwss->ext.update_stream_allocation_table(link, &pipe_ctx->link_res,
+ &link->mst_stream_alloc_table);
+
+ /* poll for immediate branch device ACT handled */
+ ret = dm_helpers_dp_mst_poll_for_allocation_change_trigger(
+ stream->ctx,
+ stream);
+
+ if (ret != ACT_LINK_LOST) {
+ /* send ALLOCATE_PAYLOAD sideband message with updated pbn */
+ dm_helpers_dp_mst_send_payload_allocation(
+ stream->ctx,
+ stream,
+ true);
+ }
+
+ /* increase throttled vcp size */
+ pbn = get_pbn_from_bw_in_kbps(bw_in_kbps);
+ pbn_per_slot = get_pbn_per_slot(stream);
+ avg_time_slots_per_mtp = dc_fixpt_div(pbn, pbn_per_slot);
+
+ if (link_hwss->ext.set_throttled_vcp_size)
+ link_hwss->ext.set_throttled_vcp_size(pipe_ctx, avg_time_slots_per_mtp);
+ if (link_hwss->ext.set_hblank_min_symbol_width)
+ link_hwss->ext.set_hblank_min_symbol_width(pipe_ctx,
+ &link->cur_link_settings,
+ avg_time_slots_per_mtp);
+
+ return DC_OK;
+}
+
+static void disable_link_dp(struct dc_link *link,
+ const struct link_resource *link_res,
+ enum signal_type signal)
+{
+ struct dc_link_settings link_settings = link->cur_link_settings;
+
+ if (signal == SIGNAL_TYPE_DISPLAY_PORT_MST &&
+ link->mst_stream_alloc_table.stream_count > 0)
+ /* disable MST link only when last vc payload is deallocated */
+ return;
+
+ dp_disable_link_phy(link, link_res, signal);
+
+ if (signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
+ /* set the sink to SST mode after disabling the link */
+ enable_mst_on_sink(link, false);
+
+ if (link_dp_get_encoding_format(&link_settings) ==
+ DP_8b_10b_ENCODING) {
+ dp_set_fec_enable(link, false);
+ dp_set_fec_ready(link, link_res, false);
+ }
+}
+
+static void disable_link(struct dc_link *link,
+ const struct link_resource *link_res,
+ enum signal_type signal)
+{
+ if (dc_is_dp_signal(signal)) {
+ disable_link_dp(link, link_res, signal);
+ } else if (signal != SIGNAL_TYPE_VIRTUAL) {
+ link->dc->hwss.disable_link_output(link, link_res, signal);
+ }
+
+ if (signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
+ /* MST disable link only when no stream use the link */
+ if (link->mst_stream_alloc_table.stream_count <= 0)
+ link->link_status.link_active = false;
+ } else {
+ link->link_status.link_active = false;
+ }
+}
+
+static void enable_link_hdmi(struct pipe_ctx *pipe_ctx)
+{
+ struct dc_stream_state *stream = pipe_ctx->stream;
+ struct dc_link *link = stream->link;
+ enum dc_color_depth display_color_depth;
+ enum engine_id eng_id;
+ struct ext_hdmi_settings settings = {0};
+ bool is_over_340mhz = false;
+ bool is_vga_mode = (stream->timing.h_addressable == 640)
+ && (stream->timing.v_addressable == 480);
+ struct dc *dc = pipe_ctx->stream->ctx->dc;
+
+ if (stream->phy_pix_clk == 0)
+ stream->phy_pix_clk = stream->timing.pix_clk_100hz / 10;
+ if (stream->phy_pix_clk > 340000)
+ is_over_340mhz = true;
+
+ if (dc_is_hdmi_signal(pipe_ctx->stream->signal)) {
+ unsigned short masked_chip_caps = pipe_ctx->stream->link->chip_caps &
+ EXT_DISPLAY_PATH_CAPS__EXT_CHIP_MASK;
+ if (masked_chip_caps == EXT_DISPLAY_PATH_CAPS__HDMI20_TISN65DP159RSBT) {
+ /* DP159, Retimer settings */
+ eng_id = pipe_ctx->stream_res.stream_enc->id;
+
+ if (get_ext_hdmi_settings(pipe_ctx, eng_id, &settings)) {
+ write_i2c_retimer_setting(pipe_ctx,
+ is_vga_mode, is_over_340mhz, &settings);
+ } else {
+ write_i2c_default_retimer_setting(pipe_ctx,
+ is_vga_mode, is_over_340mhz);
+ }
+ } else if (masked_chip_caps == EXT_DISPLAY_PATH_CAPS__HDMI20_PI3EQX1204) {
+ /* PI3EQX1204, Redriver settings */
+ write_i2c_redriver_setting(pipe_ctx, is_over_340mhz);
+ }
+ }
+
+ if (dc_is_hdmi_signal(pipe_ctx->stream->signal))
+ write_scdc_data(
+ stream->link->ddc,
+ stream->phy_pix_clk,
+ stream->timing.flags.LTE_340MCSC_SCRAMBLE);
+
+ memset(&stream->link->cur_link_settings, 0,
+ sizeof(struct dc_link_settings));
+
+ display_color_depth = stream->timing.display_color_depth;
+ if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR422)
+ display_color_depth = COLOR_DEPTH_888;
+
+ dc->hwss.enable_tmds_link_output(
+ link,
+ &pipe_ctx->link_res,
+ pipe_ctx->stream->signal,
+ pipe_ctx->clock_source->id,
+ display_color_depth,
+ stream->phy_pix_clk);
+
+ if (dc_is_hdmi_signal(pipe_ctx->stream->signal))
+ read_scdc_data(link->ddc);
+}
+
+static enum dc_status enable_link_dp(struct dc_state *state,
+ struct pipe_ctx *pipe_ctx)
+{
+ struct dc_stream_state *stream = pipe_ctx->stream;
+ enum dc_status status;
+ bool skip_video_pattern;
+ struct dc_link *link = stream->link;
+ const struct dc_link_settings *link_settings =
+ &pipe_ctx->link_config.dp_link_settings;
+ bool fec_enable;
+ int i;
+ bool apply_seamless_boot_optimization = false;
+ uint32_t bl_oled_enable_delay = 50; // in ms
+ uint32_t post_oui_delay = 30; // 30ms
+ /* Reduce link bandwidth between failed link training attempts. */
+ bool do_fallback = false;
+
+ // check for seamless boot
+ for (i = 0; i < state->stream_count; i++) {
+ if (state->streams[i]->apply_seamless_boot_optimization) {
+ apply_seamless_boot_optimization = true;
+ break;
+ }
+ }
+
+ /* Train with fallback when enabling DPIA link. Conventional links are
+ * trained with fallback during sink detection.
+ */
+ if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA)
+ do_fallback = true;
+
+ /*
+ * Temporary w/a to get DP2.0 link rates to work with SST.
+ * TODO DP2.0 - Workaround: Remove w/a if and when the issue is resolved.
+ */
+ if (link_dp_get_encoding_format(link_settings) == DP_128b_132b_ENCODING &&
+ pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT &&
+ link->dc->debug.set_mst_en_for_sst) {
+ enable_mst_on_sink(link, true);
+ }
+ if (pipe_ctx->stream->signal == SIGNAL_TYPE_EDP) {
+ /*in case it is not on*/
+ if (!link->dc->config.edp_no_power_sequencing)
+ link->dc->hwss.edp_power_control(link, true);
+ link->dc->hwss.edp_wait_for_hpd_ready(link, true);
+ }
+
+ if (link_dp_get_encoding_format(link_settings) == DP_128b_132b_ENCODING) {
+ /* TODO - DP2.0 HW: calculate 32 symbol clock for HPO encoder */
+ } else {
+ pipe_ctx->stream_res.pix_clk_params.requested_sym_clk =
+ link_settings->link_rate * LINK_RATE_REF_FREQ_IN_KHZ;
+ if (state->clk_mgr && !apply_seamless_boot_optimization)
+ state->clk_mgr->funcs->update_clocks(state->clk_mgr,
+ state, false);
+ }
+
+ // during mode switch we do DP_SET_POWER off then on, and OUI is lost
+ dpcd_set_source_specific_data(link);
+ if (link->dpcd_sink_ext_caps.raw != 0) {
+ post_oui_delay += link->panel_config.pps.extra_post_OUI_ms;
+ msleep(post_oui_delay);
+ }
+
+ // similarly, mode switch can cause loss of cable ID
+ dpcd_write_cable_id_to_dprx(link);
+
+ skip_video_pattern = true;
+
+ if (link_settings->link_rate == LINK_RATE_LOW)
+ skip_video_pattern = false;
+
+ if (perform_link_training_with_retries(link_settings,
+ skip_video_pattern,
+ LINK_TRAINING_ATTEMPTS,
+ pipe_ctx,
+ pipe_ctx->stream->signal,
+ do_fallback)) {
+ status = DC_OK;
+ } else {
+ status = DC_FAIL_DP_LINK_TRAINING;
+ }
+
+ if (link->preferred_training_settings.fec_enable)
+ fec_enable = *link->preferred_training_settings.fec_enable;
+ else
+ fec_enable = true;
+
+ if (link_dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING)
+ dp_set_fec_enable(link, fec_enable);
+
+ // during mode set we do DP_SET_POWER off then on, aux writes are lost
+ if (link->dpcd_sink_ext_caps.bits.oled == 1 ||
+ link->dpcd_sink_ext_caps.bits.sdr_aux_backlight_control == 1 ||
+ link->dpcd_sink_ext_caps.bits.hdr_aux_backlight_control == 1) {
+ set_default_brightness_aux(link); // TODO: use cached if known
+ if (link->dpcd_sink_ext_caps.bits.oled == 1)
+ msleep(bl_oled_enable_delay);
+ link_backlight_enable_aux(link, true);
+ }
+
+ return status;
+}
+
+static enum dc_status enable_link_edp(
+ struct dc_state *state,
+ struct pipe_ctx *pipe_ctx)
+{
+ return enable_link_dp(state, pipe_ctx);
+}
+
+static void enable_link_lvds(struct pipe_ctx *pipe_ctx)
+{
+ struct dc_stream_state *stream = pipe_ctx->stream;
+ struct dc_link *link = stream->link;
+ struct dc *dc = stream->ctx->dc;
+
+ if (stream->phy_pix_clk == 0)
+ stream->phy_pix_clk = stream->timing.pix_clk_100hz / 10;
+
+ memset(&stream->link->cur_link_settings, 0,
+ sizeof(struct dc_link_settings));
+ dc->hwss.enable_lvds_link_output(
+ link,
+ &pipe_ctx->link_res,
+ pipe_ctx->clock_source->id,
+ stream->phy_pix_clk);
+
+}
+
+static enum dc_status enable_link_dp_mst(
+ struct dc_state *state,
+ struct pipe_ctx *pipe_ctx)
+{
+ struct dc_link *link = pipe_ctx->stream->link;
+
+ /* sink signal type after MST branch is MST. Multiple MST sinks
+ * share one link. Link DP PHY is enable or training only once.
+ */
+ if (link->link_status.link_active)
+ return DC_OK;
+
+ /* clear payload table */
+ dm_helpers_dp_mst_clear_payload_allocation_table(link->ctx, link);
+
+ /* to make sure the pending down rep can be processed
+ * before enabling the link
+ */
+ dm_helpers_dp_mst_poll_pending_down_reply(link->ctx, link);
+
+ /* set the sink to MST mode before enabling the link */
+ enable_mst_on_sink(link, true);
+
+ return enable_link_dp(state, pipe_ctx);
+}
+
+static enum dc_status enable_link(
+ struct dc_state *state,
+ struct pipe_ctx *pipe_ctx)
+{
+ enum dc_status status = DC_ERROR_UNEXPECTED;
+ struct dc_stream_state *stream = pipe_ctx->stream;
+ struct dc_link *link = stream->link;
+
+ /* There's some scenarios where driver is unloaded with display
+ * still enabled. When driver is reloaded, it may cause a display
+ * to not light up if there is a mismatch between old and new
+ * link settings. Need to call disable first before enabling at
+ * new link settings.
+ */
+ if (link->link_status.link_active) {
+ disable_link(link, &pipe_ctx->link_res, pipe_ctx->stream->signal);
+ }
+
+ switch (pipe_ctx->stream->signal) {
+ case SIGNAL_TYPE_DISPLAY_PORT:
+ status = enable_link_dp(state, pipe_ctx);
+ break;
+ case SIGNAL_TYPE_EDP:
+ status = enable_link_edp(state, pipe_ctx);
+ break;
+ case SIGNAL_TYPE_DISPLAY_PORT_MST:
+ status = enable_link_dp_mst(state, pipe_ctx);
+ msleep(200);
+ break;
+ case SIGNAL_TYPE_DVI_SINGLE_LINK:
+ case SIGNAL_TYPE_DVI_DUAL_LINK:
+ case SIGNAL_TYPE_HDMI_TYPE_A:
+ enable_link_hdmi(pipe_ctx);
+ status = DC_OK;
+ break;
+ case SIGNAL_TYPE_LVDS:
+ enable_link_lvds(pipe_ctx);
+ status = DC_OK;
+ break;
+ case SIGNAL_TYPE_VIRTUAL:
+ status = DC_OK;
+ break;
+ default:
+ break;
+ }
+
+ if (status == DC_OK) {
+ pipe_ctx->stream->link->link_status.link_active = true;
+ }
+
+ return status;
+}
+
+void link_set_dpms_off(struct pipe_ctx *pipe_ctx)
+{
+ struct dc *dc = pipe_ctx->stream->ctx->dc;
+ struct dc_stream_state *stream = pipe_ctx->stream;
+ struct dc_link *link = stream->sink->link;
+ struct vpg *vpg = pipe_ctx->stream_res.stream_enc->vpg;
+
+ ASSERT(is_master_pipe_for_link(link, pipe_ctx));
+
+ if (link_is_dp_128b_132b_signal(pipe_ctx))
+ vpg = pipe_ctx->stream_res.hpo_dp_stream_enc->vpg;
+
+ DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
+
+ if (pipe_ctx->stream->sink) {
+ if (pipe_ctx->stream->sink->sink_signal != SIGNAL_TYPE_VIRTUAL &&
+ pipe_ctx->stream->sink->sink_signal != SIGNAL_TYPE_NONE) {
+ DC_LOG_DC("%s pipe_ctx dispname=%s signal=%x\n", __func__,
+ pipe_ctx->stream->sink->edid_caps.display_name,
+ pipe_ctx->stream->signal);
+ }
+ }
+
+ if (!IS_DIAG_DC(dc->ctx->dce_environment) &&
+ dc_is_virtual_signal(pipe_ctx->stream->signal))
+ return;
+
+ if (!pipe_ctx->stream->sink->edid_caps.panel_patch.skip_avmute) {
+ if (dc_is_hdmi_signal(pipe_ctx->stream->signal))
+ set_avmute(pipe_ctx, true);
+ }
+
+ dc->hwss.disable_audio_stream(pipe_ctx);
+
+#if defined(CONFIG_DRM_AMD_DC_HDCP)
+ update_psp_stream_config(pipe_ctx, true);
+#endif
+ dc->hwss.blank_stream(pipe_ctx);
+
+ if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
+ deallocate_mst_payload(pipe_ctx);
+ else if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT &&
+ link_is_dp_128b_132b_signal(pipe_ctx))
+ update_sst_payload(pipe_ctx, false);
+
+ if (dc_is_hdmi_signal(pipe_ctx->stream->signal)) {
+ struct ext_hdmi_settings settings = {0};
+ enum engine_id eng_id = pipe_ctx->stream_res.stream_enc->id;
+
+ unsigned short masked_chip_caps = link->chip_caps &
+ EXT_DISPLAY_PATH_CAPS__EXT_CHIP_MASK;
+ //Need to inform that sink is going to use legacy HDMI mode.
+ write_scdc_data(
+ link->ddc,
+ 165000,//vbios only handles 165Mhz.
+ false);
+ if (masked_chip_caps == EXT_DISPLAY_PATH_CAPS__HDMI20_TISN65DP159RSBT) {
+ /* DP159, Retimer settings */
+ if (get_ext_hdmi_settings(pipe_ctx, eng_id, &settings))
+ write_i2c_retimer_setting(pipe_ctx,
+ false, false, &settings);
+ else
+ write_i2c_default_retimer_setting(pipe_ctx,
+ false, false);
+ } else if (masked_chip_caps == EXT_DISPLAY_PATH_CAPS__HDMI20_PI3EQX1204) {
+ /* PI3EQX1204, Redriver settings */
+ write_i2c_redriver_setting(pipe_ctx, false);
+ }
+ }
+
+ if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT &&
+ !link_is_dp_128b_132b_signal(pipe_ctx)) {
+
+ /* In DP1.x SST mode, our encoder will go to TPS1
+ * when link is on but stream is off.
+ * Disabling link before stream will avoid exposing TPS1 pattern
+ * during the disable sequence as it will confuse some receivers
+ * state machine.
+ * In DP2 or MST mode, our encoder will stay video active
+ */
+ disable_link(pipe_ctx->stream->link, &pipe_ctx->link_res, pipe_ctx->stream->signal);
+ dc->hwss.disable_stream(pipe_ctx);
+ } else {
+ dc->hwss.disable_stream(pipe_ctx);
+ disable_link(pipe_ctx->stream->link, &pipe_ctx->link_res, pipe_ctx->stream->signal);
+ }
+
+ if (pipe_ctx->stream->timing.flags.DSC) {
+ if (dc_is_dp_signal(pipe_ctx->stream->signal))
+ link_set_dsc_enable(pipe_ctx, false);
+ }
+ if (link_is_dp_128b_132b_signal(pipe_ctx)) {
+ if (pipe_ctx->stream_res.tg->funcs->set_out_mux)
+ pipe_ctx->stream_res.tg->funcs->set_out_mux(pipe_ctx->stream_res.tg, OUT_MUX_DIO);
+ }
+
+ if (vpg && vpg->funcs->vpg_powerdown)
+ vpg->funcs->vpg_powerdown(vpg);
+}
+
+void link_set_dpms_on(
+ struct dc_state *state,
+ struct pipe_ctx *pipe_ctx)
+{
+ struct dc *dc = pipe_ctx->stream->ctx->dc;
+ struct dc_stream_state *stream = pipe_ctx->stream;
+ struct dc_link *link = stream->sink->link;
+ enum dc_status status;
+ struct link_encoder *link_enc;
+ enum otg_out_mux_dest otg_out_dest = OUT_MUX_DIO;
+ struct vpg *vpg = pipe_ctx->stream_res.stream_enc->vpg;
+ const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
+
+ ASSERT(is_master_pipe_for_link(link, pipe_ctx));
+
+ if (link_is_dp_128b_132b_signal(pipe_ctx))
+ vpg = pipe_ctx->stream_res.hpo_dp_stream_enc->vpg;
+
+ DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
+
+ if (pipe_ctx->stream->sink) {
+ if (pipe_ctx->stream->sink->sink_signal != SIGNAL_TYPE_VIRTUAL &&
+ pipe_ctx->stream->sink->sink_signal != SIGNAL_TYPE_NONE) {
+ DC_LOG_DC("%s pipe_ctx dispname=%s signal=%x\n", __func__,
+ pipe_ctx->stream->sink->edid_caps.display_name,
+ pipe_ctx->stream->signal);
+ }
+ }
+
+ if (!IS_DIAG_DC(dc->ctx->dce_environment) &&
+ dc_is_virtual_signal(pipe_ctx->stream->signal))
+ return;
+
+ link_enc = link_enc_cfg_get_link_enc(link);
+ ASSERT(link_enc);
+
+ if (!dc_is_virtual_signal(pipe_ctx->stream->signal)
+ && !link_is_dp_128b_132b_signal(pipe_ctx)) {
+ if (link_enc)
+ link_enc->funcs->setup(
+ link_enc,
+ pipe_ctx->stream->signal);
+ }
+
+ pipe_ctx->stream->link->link_state_valid = true;
+
+ if (pipe_ctx->stream_res.tg->funcs->set_out_mux) {
+ if (link_is_dp_128b_132b_signal(pipe_ctx))
+ otg_out_dest = OUT_MUX_HPO_DP;
+ else
+ otg_out_dest = OUT_MUX_DIO;
+ pipe_ctx->stream_res.tg->funcs->set_out_mux(pipe_ctx->stream_res.tg, otg_out_dest);
+ }
+
+ link_hwss->setup_stream_attribute(pipe_ctx);
+
+ if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
+ bool apply_edp_fast_boot_optimization =
+ pipe_ctx->stream->apply_edp_fast_boot_optimization;
+
+ pipe_ctx->stream->apply_edp_fast_boot_optimization = false;
+
+ // Enable VPG before building infoframe
+ if (vpg && vpg->funcs->vpg_poweron)
+ vpg->funcs->vpg_poweron(vpg);
+
+ resource_build_info_frame(pipe_ctx);
+ dc->hwss.update_info_frame(pipe_ctx);
+
+ if (dc_is_dp_signal(pipe_ctx->stream->signal))
+ link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_UPDATE_INFO_FRAME);
+
+ /* Do not touch link on seamless boot optimization. */
+ if (pipe_ctx->stream->apply_seamless_boot_optimization) {
+ pipe_ctx->stream->dpms_off = false;
+
+ /* Still enable stream features & audio on seamless boot for DP external displays */
+ if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT) {
+ enable_stream_features(pipe_ctx);
+ dc->hwss.enable_audio_stream(pipe_ctx);
+ }
+
+#if defined(CONFIG_DRM_AMD_DC_HDCP)
+ update_psp_stream_config(pipe_ctx, false);
+#endif
+ return;
+ }
+
+ /* eDP lit up by bios already, no need to enable again. */
+ if (pipe_ctx->stream->signal == SIGNAL_TYPE_EDP &&
+ apply_edp_fast_boot_optimization &&
+ !pipe_ctx->stream->timing.flags.DSC &&
+ !pipe_ctx->next_odm_pipe) {
+ pipe_ctx->stream->dpms_off = false;
+#if defined(CONFIG_DRM_AMD_DC_HDCP)
+ update_psp_stream_config(pipe_ctx, false);
+#endif
+ return;
+ }
+
+ if (pipe_ctx->stream->dpms_off)
+ return;
+
+ /* Have to setup DSC before DIG FE and BE are connected (which happens before the
+ * link training). This is to make sure the bandwidth sent to DIG BE won't be
+ * bigger than what the link and/or DIG BE can handle. VBID[6]/CompressedStream_flag
+ * will be automatically set at a later time when the video is enabled
+ * (DP_VID_STREAM_EN = 1).
+ */
+ if (pipe_ctx->stream->timing.flags.DSC) {
+ if (dc_is_dp_signal(pipe_ctx->stream->signal) ||
+ dc_is_virtual_signal(pipe_ctx->stream->signal))
+ link_set_dsc_enable(pipe_ctx, true);
+
+ }
+
+ status = enable_link(state, pipe_ctx);
+
+ if (status != DC_OK) {
+ DC_LOG_WARNING("enabling link %u failed: %d\n",
+ pipe_ctx->stream->link->link_index,
+ status);
+
+ /* Abort stream enable *unless* the failure was due to
+ * DP link training - some DP monitors will recover and
+ * show the stream anyway. But MST displays can't proceed
+ * without link training.
+ */
+ if (status != DC_FAIL_DP_LINK_TRAINING ||
+ pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
+ if (false == stream->link->link_status.link_active)
+ disable_link(stream->link, &pipe_ctx->link_res,
+ pipe_ctx->stream->signal);
+ BREAK_TO_DEBUGGER();
+ return;
+ }
+ }
+
+ /* turn off otg test pattern if enable */
+ if (pipe_ctx->stream_res.tg->funcs->set_test_pattern)
+ pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg,
+ CONTROLLER_DP_TEST_PATTERN_VIDEOMODE,
+ COLOR_DEPTH_UNDEFINED);
+
+ /* This second call is needed to reconfigure the DIG
+ * as a workaround for the incorrect value being applied
+ * from transmitter control.
+ */
+ if (!(dc_is_virtual_signal(pipe_ctx->stream->signal) ||
+ link_is_dp_128b_132b_signal(pipe_ctx)))
+ if (link_enc)
+ link_enc->funcs->setup(
+ link_enc,
+ pipe_ctx->stream->signal);
+
+ dc->hwss.enable_stream(pipe_ctx);
+
+ /* Set DPS PPS SDP (AKA "info frames") */
+ if (pipe_ctx->stream->timing.flags.DSC) {
+ if (dc_is_dp_signal(pipe_ctx->stream->signal) ||
+ dc_is_virtual_signal(pipe_ctx->stream->signal)) {
+ dp_set_dsc_on_rx(pipe_ctx, true);
+ link_set_dsc_pps_packet(pipe_ctx, true, true);
+ }
+ }
+
+ if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
+ allocate_mst_payload(pipe_ctx);
+ else if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT &&
+ link_is_dp_128b_132b_signal(pipe_ctx))
+ update_sst_payload(pipe_ctx, true);
+
+ dc->hwss.unblank_stream(pipe_ctx,
+ &pipe_ctx->stream->link->cur_link_settings);
+
+ if (stream->sink_patches.delay_ignore_msa > 0)
+ msleep(stream->sink_patches.delay_ignore_msa);
+
+ if (dc_is_dp_signal(pipe_ctx->stream->signal))
+ enable_stream_features(pipe_ctx);
+#if defined(CONFIG_DRM_AMD_DC_HDCP)
+ update_psp_stream_config(pipe_ctx, false);
+#endif
+
+ dc->hwss.enable_audio_stream(pipe_ctx);
+
+ } else { // if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
+ if (link_is_dp_128b_132b_signal(pipe_ctx))
+ dp_fpga_hpo_enable_link_and_stream(state, pipe_ctx);
+ if (dc_is_dp_signal(pipe_ctx->stream->signal) ||
+ dc_is_virtual_signal(pipe_ctx->stream->signal))
+ link_set_dsc_enable(pipe_ctx, true);
+ }
+
+ if (dc_is_hdmi_signal(pipe_ctx->stream->signal)) {
+ set_avmute(pipe_ctx, false);
+ }
+}
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dpms.h b/drivers/gpu/drm/amd/display/dc/link/link_dpms.h
new file mode 100644
index 000000000000..33d312dabdb8
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/link_dpms.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2023 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DC_LINK_DPMS_H__
+#define __DC_LINK_DPMS_H__
+
+#include "link.h"
+bool link_set_dsc_pps_packet(struct pipe_ctx *pipe_ctx,
+ bool enable, bool immediate_update);
+struct fixed31_32 link_calculate_sst_avg_time_slots_per_mtp(
+ const struct dc_stream_state *stream,
+ const struct dc_link *link);
+void link_set_all_streams_dpms_off_for_link(struct dc_link *link);
+void link_get_master_pipes_with_dpms_on(const struct dc_link *link,
+ struct dc_state *state,
+ uint8_t *count,
+ struct pipe_ctx *pipes[MAX_PIPES]);
+#endif /* __DC_LINK_DPMS_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_factory.c b/drivers/gpu/drm/amd/display/dc/link/link_factory.c
new file mode 100644
index 000000000000..aeb26a4d539e
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/link_factory.c
@@ -0,0 +1,577 @@
+/*
+ * Copyright 2023 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+
+/* FILE POLICY AND INTENDED USAGE:
+ * This file owns the creation/destruction of link structure.
+ */
+#include "link_factory.h"
+#include "protocols/link_ddc.h"
+#include "protocols/link_edp_panel_control.h"
+#include "protocols/link_hpd.h"
+#include "gpio_service_interface.h"
+#include "atomfirmware.h"
+
+#define DC_LOGGER_INIT(logger)
+
+#define LINK_INFO(...) \
+ DC_LOG_HW_HOTPLUG( \
+ __VA_ARGS__)
+
+static enum transmitter translate_encoder_to_transmitter(struct graphics_object_id encoder)
+{
+ switch (encoder.id) {
+ case ENCODER_ID_INTERNAL_UNIPHY:
+ switch (encoder.enum_id) {
+ case ENUM_ID_1:
+ return TRANSMITTER_UNIPHY_A;
+ case ENUM_ID_2:
+ return TRANSMITTER_UNIPHY_B;
+ default:
+ return TRANSMITTER_UNKNOWN;
+ }
+ break;
+ case ENCODER_ID_INTERNAL_UNIPHY1:
+ switch (encoder.enum_id) {
+ case ENUM_ID_1:
+ return TRANSMITTER_UNIPHY_C;
+ case ENUM_ID_2:
+ return TRANSMITTER_UNIPHY_D;
+ default:
+ return TRANSMITTER_UNKNOWN;
+ }
+ break;
+ case ENCODER_ID_INTERNAL_UNIPHY2:
+ switch (encoder.enum_id) {
+ case ENUM_ID_1:
+ return TRANSMITTER_UNIPHY_E;
+ case ENUM_ID_2:
+ return TRANSMITTER_UNIPHY_F;
+ default:
+ return TRANSMITTER_UNKNOWN;
+ }
+ break;
+ case ENCODER_ID_INTERNAL_UNIPHY3:
+ switch (encoder.enum_id) {
+ case ENUM_ID_1:
+ return TRANSMITTER_UNIPHY_G;
+ default:
+ return TRANSMITTER_UNKNOWN;
+ }
+ break;
+ case ENCODER_ID_EXTERNAL_NUTMEG:
+ switch (encoder.enum_id) {
+ case ENUM_ID_1:
+ return TRANSMITTER_NUTMEG_CRT;
+ default:
+ return TRANSMITTER_UNKNOWN;
+ }
+ break;
+ case ENCODER_ID_EXTERNAL_TRAVIS:
+ switch (encoder.enum_id) {
+ case ENUM_ID_1:
+ return TRANSMITTER_TRAVIS_CRT;
+ case ENUM_ID_2:
+ return TRANSMITTER_TRAVIS_LCD;
+ default:
+ return TRANSMITTER_UNKNOWN;
+ }
+ break;
+ default:
+ return TRANSMITTER_UNKNOWN;
+ }
+}
+
+static void link_destruct(struct dc_link *link)
+{
+ int i;
+
+ if (link->hpd_gpio) {
+ dal_gpio_destroy_irq(&link->hpd_gpio);
+ link->hpd_gpio = NULL;
+ }
+
+ if (link->ddc)
+ link_destroy_ddc_service(&link->ddc);
+
+ if (link->panel_cntl)
+ link->panel_cntl->funcs->destroy(&link->panel_cntl);
+
+ if (link->link_enc) {
+ /* Update link encoder resource tracking variables. These are used for
+ * the dynamic assignment of link encoders to streams. Virtual links
+ * are not assigned encoder resources on creation.
+ */
+ if (link->link_id.id != CONNECTOR_ID_VIRTUAL) {
+ link->dc->res_pool->link_encoders[link->eng_id - ENGINE_ID_DIGA] = NULL;
+ link->dc->res_pool->dig_link_enc_count--;
+ }
+ link->link_enc->funcs->destroy(&link->link_enc);
+ }
+
+ if (link->local_sink)
+ dc_sink_release(link->local_sink);
+
+ for (i = 0; i < link->sink_count; ++i)
+ dc_sink_release(link->remote_sinks[i]);
+}
+
+static enum channel_id get_ddc_line(struct dc_link *link)
+{
+ struct ddc *ddc;
+ enum channel_id channel;
+
+ channel = CHANNEL_ID_UNKNOWN;
+
+ ddc = get_ddc_pin(link->ddc);
+
+ if (ddc) {
+ switch (dal_ddc_get_line(ddc)) {
+ case GPIO_DDC_LINE_DDC1:
+ channel = CHANNEL_ID_DDC1;
+ break;
+ case GPIO_DDC_LINE_DDC2:
+ channel = CHANNEL_ID_DDC2;
+ break;
+ case GPIO_DDC_LINE_DDC3:
+ channel = CHANNEL_ID_DDC3;
+ break;
+ case GPIO_DDC_LINE_DDC4:
+ channel = CHANNEL_ID_DDC4;
+ break;
+ case GPIO_DDC_LINE_DDC5:
+ channel = CHANNEL_ID_DDC5;
+ break;
+ case GPIO_DDC_LINE_DDC6:
+ channel = CHANNEL_ID_DDC6;
+ break;
+ case GPIO_DDC_LINE_DDC_VGA:
+ channel = CHANNEL_ID_DDC_VGA;
+ break;
+ case GPIO_DDC_LINE_I2C_PAD:
+ channel = CHANNEL_ID_I2C_PAD;
+ break;
+ default:
+ BREAK_TO_DEBUGGER();
+ break;
+ }
+ }
+
+ return channel;
+}
+
+static bool dc_link_construct_phy(struct dc_link *link,
+ const struct link_init_data *init_params)
+{
+ uint8_t i;
+ struct ddc_service_init_data ddc_service_init_data = { 0 };
+ struct dc_context *dc_ctx = init_params->ctx;
+ struct encoder_init_data enc_init_data = { 0 };
+ struct panel_cntl_init_data panel_cntl_init_data = { 0 };
+ struct integrated_info info = { 0 };
+ struct dc_bios *bios = init_params->dc->ctx->dc_bios;
+ const struct dc_vbios_funcs *bp_funcs = bios->funcs;
+ struct bp_disp_connector_caps_info disp_connect_caps_info = { 0 };
+
+ DC_LOGGER_INIT(dc_ctx->logger);
+
+ link->irq_source_hpd = DC_IRQ_SOURCE_INVALID;
+ link->irq_source_hpd_rx = DC_IRQ_SOURCE_INVALID;
+ link->link_status.dpcd_caps = &link->dpcd_caps;
+
+ link->dc = init_params->dc;
+ link->ctx = dc_ctx;
+ link->link_index = init_params->link_index;
+
+ memset(&link->preferred_training_settings, 0,
+ sizeof(struct dc_link_training_overrides));
+ memset(&link->preferred_link_setting, 0,
+ sizeof(struct dc_link_settings));
+
+ link->link_id =
+ bios->funcs->get_connector_id(bios, init_params->connector_index);
+
+ link->ep_type = DISPLAY_ENDPOINT_PHY;
+
+ DC_LOG_DC("BIOS object table - link_id: %d", link->link_id.id);
+
+ if (bios->funcs->get_disp_connector_caps_info) {
+ bios->funcs->get_disp_connector_caps_info(bios, link->link_id, &disp_connect_caps_info);
+ link->is_internal_display = disp_connect_caps_info.INTERNAL_DISPLAY;
+ DC_LOG_DC("BIOS object table - is_internal_display: %d", link->is_internal_display);
+ }
+
+ if (link->link_id.type != OBJECT_TYPE_CONNECTOR) {
+ dm_output_to_console("%s: Invalid Connector ObjectID from Adapter Service for connector index:%d! type %d expected %d\n",
+ __func__, init_params->connector_index,
+ link->link_id.type, OBJECT_TYPE_CONNECTOR);
+ goto create_fail;
+ }
+
+ if (link->dc->res_pool->funcs->link_init)
+ link->dc->res_pool->funcs->link_init(link);
+
+ link->hpd_gpio = link_get_hpd_gpio(link->ctx->dc_bios, link->link_id,
+ link->ctx->gpio_service);
+
+ if (link->hpd_gpio) {
+ dal_gpio_open(link->hpd_gpio, GPIO_MODE_INTERRUPT);
+ dal_gpio_unlock_pin(link->hpd_gpio);
+ link->irq_source_hpd = dal_irq_get_source(link->hpd_gpio);
+
+ DC_LOG_DC("BIOS object table - hpd_gpio id: %d", link->hpd_gpio->id);
+ DC_LOG_DC("BIOS object table - hpd_gpio en: %d", link->hpd_gpio->en);
+ }
+
+ switch (link->link_id.id) {
+ case CONNECTOR_ID_HDMI_TYPE_A:
+ link->connector_signal = SIGNAL_TYPE_HDMI_TYPE_A;
+
+ break;
+ case CONNECTOR_ID_SINGLE_LINK_DVID:
+ case CONNECTOR_ID_SINGLE_LINK_DVII:
+ link->connector_signal = SIGNAL_TYPE_DVI_SINGLE_LINK;
+ break;
+ case CONNECTOR_ID_DUAL_LINK_DVID:
+ case CONNECTOR_ID_DUAL_LINK_DVII:
+ link->connector_signal = SIGNAL_TYPE_DVI_DUAL_LINK;
+ break;
+ case CONNECTOR_ID_DISPLAY_PORT:
+ case CONNECTOR_ID_USBC:
+ link->connector_signal = SIGNAL_TYPE_DISPLAY_PORT;
+
+ if (link->hpd_gpio)
+ link->irq_source_hpd_rx =
+ dal_irq_get_rx_source(link->hpd_gpio);
+
+ break;
+ case CONNECTOR_ID_EDP:
+ link->connector_signal = SIGNAL_TYPE_EDP;
+
+ if (link->hpd_gpio) {
+ if (!link->dc->config.allow_edp_hotplug_detection)
+ link->irq_source_hpd = DC_IRQ_SOURCE_INVALID;
+
+ switch (link->dc->config.allow_edp_hotplug_detection) {
+ case 1: // only the 1st eDP handles hotplug
+ if (link->link_index == 0)
+ link->irq_source_hpd_rx =
+ dal_irq_get_rx_source(link->hpd_gpio);
+ else
+ link->irq_source_hpd = DC_IRQ_SOURCE_INVALID;
+ break;
+ case 2: // only the 2nd eDP handles hotplug
+ if (link->link_index == 1)
+ link->irq_source_hpd_rx =
+ dal_irq_get_rx_source(link->hpd_gpio);
+ else
+ link->irq_source_hpd = DC_IRQ_SOURCE_INVALID;
+ break;
+ default:
+ break;
+ }
+ }
+
+ break;
+ case CONNECTOR_ID_LVDS:
+ link->connector_signal = SIGNAL_TYPE_LVDS;
+ break;
+ default:
+ DC_LOG_WARNING("Unsupported Connector type:%d!\n",
+ link->link_id.id);
+ goto create_fail;
+ }
+
+ /* TODO: #DAL3 Implement id to str function.*/
+ LINK_INFO("Connector[%d] description:"
+ "signal %d\n",
+ init_params->connector_index,
+ link->connector_signal);
+
+ ddc_service_init_data.ctx = link->ctx;
+ ddc_service_init_data.id = link->link_id;
+ ddc_service_init_data.link = link;
+ link->ddc = link_create_ddc_service(&ddc_service_init_data);
+
+ if (!link->ddc) {
+ DC_ERROR("Failed to create ddc_service!\n");
+ goto ddc_create_fail;
+ }
+
+ if (!link->ddc->ddc_pin) {
+ DC_ERROR("Failed to get I2C info for connector!\n");
+ goto ddc_create_fail;
+ }
+
+ link->ddc_hw_inst =
+ dal_ddc_get_line(get_ddc_pin(link->ddc));
+
+
+ if (link->dc->res_pool->funcs->panel_cntl_create &&
+ (link->link_id.id == CONNECTOR_ID_EDP ||
+ link->link_id.id == CONNECTOR_ID_LVDS)) {
+ panel_cntl_init_data.ctx = dc_ctx;
+ panel_cntl_init_data.inst =
+ panel_cntl_init_data.ctx->dc_edp_id_count;
+ link->panel_cntl =
+ link->dc->res_pool->funcs->panel_cntl_create(
+ &panel_cntl_init_data);
+ panel_cntl_init_data.ctx->dc_edp_id_count++;
+
+ if (link->panel_cntl == NULL) {
+ DC_ERROR("Failed to create link panel_cntl!\n");
+ goto panel_cntl_create_fail;
+ }
+ }
+
+ enc_init_data.ctx = dc_ctx;
+ bp_funcs->get_src_obj(dc_ctx->dc_bios, link->link_id, 0,
+ &enc_init_data.encoder);
+ enc_init_data.connector = link->link_id;
+ enc_init_data.channel = get_ddc_line(link);
+ enc_init_data.hpd_source = get_hpd_line(link);
+
+ link->hpd_src = enc_init_data.hpd_source;
+
+ enc_init_data.transmitter =
+ translate_encoder_to_transmitter(enc_init_data.encoder);
+ link->link_enc =
+ link->dc->res_pool->funcs->link_enc_create(dc_ctx, &enc_init_data);
+
+ DC_LOG_DC("BIOS object table - DP_IS_USB_C: %d", link->link_enc->features.flags.bits.DP_IS_USB_C);
+ DC_LOG_DC("BIOS object table - IS_DP2_CAPABLE: %d", link->link_enc->features.flags.bits.IS_DP2_CAPABLE);
+
+ if (!link->link_enc) {
+ DC_ERROR("Failed to create link encoder!\n");
+ goto link_enc_create_fail;
+ }
+
+ /* Update link encoder tracking variables. These are used for the dynamic
+ * assignment of link encoders to streams.
+ */
+ link->eng_id = link->link_enc->preferred_engine;
+ link->dc->res_pool->link_encoders[link->eng_id - ENGINE_ID_DIGA] = link->link_enc;
+ link->dc->res_pool->dig_link_enc_count++;
+
+ link->link_enc_hw_inst = link->link_enc->transmitter;
+ for (i = 0; i < 4; i++) {
+ if (bp_funcs->get_device_tag(dc_ctx->dc_bios,
+ link->link_id, i,
+ &link->device_tag) != BP_RESULT_OK) {
+ DC_ERROR("Failed to find device tag!\n");
+ goto device_tag_fail;
+ }
+
+ /* Look for device tag that matches connector signal,
+ * CRT for rgb, LCD for other supported signal tyes
+ */
+ if (!bp_funcs->is_device_id_supported(dc_ctx->dc_bios,
+ link->device_tag.dev_id))
+ continue;
+ if (link->device_tag.dev_id.device_type == DEVICE_TYPE_CRT &&
+ link->connector_signal != SIGNAL_TYPE_RGB)
+ continue;
+ if (link->device_tag.dev_id.device_type == DEVICE_TYPE_LCD &&
+ link->connector_signal == SIGNAL_TYPE_RGB)
+ continue;
+
+ DC_LOG_DC("BIOS object table - device_tag.acpi_device: %d", link->device_tag.acpi_device);
+ DC_LOG_DC("BIOS object table - device_tag.dev_id.device_type: %d", link->device_tag.dev_id.device_type);
+ DC_LOG_DC("BIOS object table - device_tag.dev_id.enum_id: %d", link->device_tag.dev_id.enum_id);
+ break;
+ }
+
+ if (bios->integrated_info)
+ info = *bios->integrated_info;
+
+ /* Look for channel mapping corresponding to connector and device tag */
+ for (i = 0; i < MAX_NUMBER_OF_EXT_DISPLAY_PATH; i++) {
+ struct external_display_path *path =
+ &info.ext_disp_conn_info.path[i];
+
+ if (path->device_connector_id.enum_id == link->link_id.enum_id &&
+ path->device_connector_id.id == link->link_id.id &&
+ path->device_connector_id.type == link->link_id.type) {
+ if (link->device_tag.acpi_device != 0 &&
+ path->device_acpi_enum == link->device_tag.acpi_device) {
+ link->ddi_channel_mapping = path->channel_mapping;
+ link->chip_caps = path->caps;
+ DC_LOG_DC("BIOS object table - ddi_channel_mapping: 0x%04X", link->ddi_channel_mapping.raw);
+ DC_LOG_DC("BIOS object table - chip_caps: %d", link->chip_caps);
+ } else if (path->device_tag ==
+ link->device_tag.dev_id.raw_device_tag) {
+ link->ddi_channel_mapping = path->channel_mapping;
+ link->chip_caps = path->caps;
+ DC_LOG_DC("BIOS object table - ddi_channel_mapping: 0x%04X", link->ddi_channel_mapping.raw);
+ DC_LOG_DC("BIOS object table - chip_caps: %d", link->chip_caps);
+ }
+
+ if (link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) {
+ link->bios_forced_drive_settings.VOLTAGE_SWING =
+ (info.ext_disp_conn_info.fixdpvoltageswing & 0x3);
+ link->bios_forced_drive_settings.PRE_EMPHASIS =
+ ((info.ext_disp_conn_info.fixdpvoltageswing >> 2) & 0x3);
+ }
+
+ break;
+ }
+ }
+
+ if (bios->funcs->get_atom_dc_golden_table)
+ bios->funcs->get_atom_dc_golden_table(bios);
+
+ /*
+ * TODO check if GPIO programmed correctly
+ *
+ * If GPIO isn't programmed correctly HPD might not rise or drain
+ * fast enough, leading to bounces.
+ */
+ program_hpd_filter(link);
+
+ link->psr_settings.psr_vtotal_control_support = false;
+ link->psr_settings.psr_version = DC_PSR_VERSION_UNSUPPORTED;
+
+ DC_LOG_DC("BIOS object table - %s finished successfully.\n", __func__);
+ return true;
+device_tag_fail:
+ link->link_enc->funcs->destroy(&link->link_enc);
+link_enc_create_fail:
+ if (link->panel_cntl != NULL)
+ link->panel_cntl->funcs->destroy(&link->panel_cntl);
+panel_cntl_create_fail:
+ link_destroy_ddc_service(&link->ddc);
+ddc_create_fail:
+create_fail:
+
+ if (link->hpd_gpio) {
+ dal_gpio_destroy_irq(&link->hpd_gpio);
+ link->hpd_gpio = NULL;
+ }
+
+ DC_LOG_DC("BIOS object table - %s failed.\n", __func__);
+ return false;
+}
+
+static bool dc_link_construct_dpia(struct dc_link *link,
+ const struct link_init_data *init_params)
+{
+ struct ddc_service_init_data ddc_service_init_data = { 0 };
+ struct dc_context *dc_ctx = init_params->ctx;
+
+ DC_LOGGER_INIT(dc_ctx->logger);
+
+ /* Initialized irq source for hpd and hpd rx */
+ link->irq_source_hpd = DC_IRQ_SOURCE_INVALID;
+ link->irq_source_hpd_rx = DC_IRQ_SOURCE_INVALID;
+ link->link_status.dpcd_caps = &link->dpcd_caps;
+
+ link->dc = init_params->dc;
+ link->ctx = dc_ctx;
+ link->link_index = init_params->link_index;
+
+ memset(&link->preferred_training_settings, 0,
+ sizeof(struct dc_link_training_overrides));
+ memset(&link->preferred_link_setting, 0,
+ sizeof(struct dc_link_settings));
+
+ /* Dummy Init for linkid */
+ link->link_id.type = OBJECT_TYPE_CONNECTOR;
+ link->link_id.id = CONNECTOR_ID_DISPLAY_PORT;
+ link->link_id.enum_id = ENUM_ID_1 + init_params->connector_index;
+ link->is_internal_display = false;
+ link->connector_signal = SIGNAL_TYPE_DISPLAY_PORT;
+ LINK_INFO("Connector[%d] description:signal %d\n",
+ init_params->connector_index,
+ link->connector_signal);
+
+ link->ep_type = DISPLAY_ENDPOINT_USB4_DPIA;
+ link->is_dig_mapping_flexible = true;
+
+ /* TODO: Initialize link : funcs->link_init */
+
+ ddc_service_init_data.ctx = link->ctx;
+ ddc_service_init_data.id = link->link_id;
+ ddc_service_init_data.link = link;
+ /* Set indicator for dpia link so that ddc wont be created */
+ ddc_service_init_data.is_dpia_link = true;
+
+ link->ddc = link_create_ddc_service(&ddc_service_init_data);
+ if (!link->ddc) {
+ DC_ERROR("Failed to create ddc_service!\n");
+ goto ddc_create_fail;
+ }
+
+ /* Set dpia port index : 0 to number of dpia ports */
+ link->ddc_hw_inst = init_params->connector_index;
+
+ /* TODO: Create link encoder */
+
+ link->psr_settings.psr_version = DC_PSR_VERSION_UNSUPPORTED;
+
+ /* Some docks seem to NAK I2C writes to segment pointer with mot=0. */
+ link->wa_flags.dp_mot_reset_segment = true;
+
+ return true;
+
+ddc_create_fail:
+ return false;
+}
+
+static bool link_construct(struct dc_link *link,
+ const struct link_init_data *init_params)
+{
+ /* Handle dpia case */
+ if (init_params->is_dpia_link == true)
+ return dc_link_construct_dpia(link, init_params);
+ else
+ return dc_link_construct_phy(link, init_params);
+}
+
+struct dc_link *link_create(const struct link_init_data *init_params)
+{
+ struct dc_link *link =
+ kzalloc(sizeof(*link), GFP_KERNEL);
+
+ if (NULL == link)
+ goto alloc_fail;
+
+ if (false == link_construct(link, init_params))
+ goto construct_fail;
+
+ return link;
+
+construct_fail:
+ kfree(link);
+
+alloc_fail:
+ return NULL;
+}
+
+void link_destroy(struct dc_link **link)
+{
+ link_destruct(*link);
+ kfree(*link);
+ *link = NULL;
+}
+
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_factory.h b/drivers/gpu/drm/amd/display/dc/link/link_factory.h
new file mode 100644
index 000000000000..5b846147c4a6
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/link_factory.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2023 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+#ifndef __LINK_FACTORY_H__
+#define __LINK_FACTORY_H__
+#include "link.h"
+
+#endif /* __LINK_FACTORY_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_resource.c b/drivers/gpu/drm/amd/display/dc/link/link_resource.c
new file mode 100644
index 000000000000..bd42bb273c0c
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/link_resource.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2023 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+/* FILE POLICY AND INTENDED USAGE:
+ * This file implements accessors to link resource.
+ */
+
+#include "link_resource.h"
+#include "protocols/link_dp_capability.h"
+
+void link_get_cur_link_res(const struct dc_link *link,
+ struct link_resource *link_res)
+{
+ int i;
+ struct pipe_ctx *pipe = NULL;
+
+ memset(link_res, 0, sizeof(*link_res));
+
+ for (i = 0; i < MAX_PIPES; i++) {
+ pipe = &link->dc->current_state->res_ctx.pipe_ctx[i];
+ if (pipe->stream && pipe->stream->link && pipe->top_pipe == NULL) {
+ if (pipe->stream->link == link) {
+ *link_res = pipe->link_res;
+ break;
+ }
+ }
+ }
+
+}
+
+void link_get_cur_res_map(const struct dc *dc, uint32_t *map)
+{
+ struct dc_link *link;
+ uint32_t i;
+ uint32_t hpo_dp_recycle_map = 0;
+
+ *map = 0;
+
+ if (dc->caps.dp_hpo) {
+ for (i = 0; i < dc->caps.max_links; i++) {
+ link = dc->links[i];
+ if (link->link_status.link_active &&
+ link_dp_get_encoding_format(&link->reported_link_cap) == DP_128b_132b_ENCODING &&
+ link_dp_get_encoding_format(&link->cur_link_settings) != DP_128b_132b_ENCODING)
+ /* hpo dp link encoder is considered as recycled, when RX reports 128b/132b encoding capability
+ * but current link doesn't use it.
+ */
+ hpo_dp_recycle_map |= (1 << i);
+ }
+ *map |= (hpo_dp_recycle_map << LINK_RES_HPO_DP_REC_MAP__SHIFT);
+ }
+}
+
+void link_restore_res_map(const struct dc *dc, uint32_t *map)
+{
+ struct dc_link *link;
+ uint32_t i;
+ unsigned int available_hpo_dp_count;
+ uint32_t hpo_dp_recycle_map = (*map & LINK_RES_HPO_DP_REC_MAP__MASK)
+ >> LINK_RES_HPO_DP_REC_MAP__SHIFT;
+
+ if (dc->caps.dp_hpo) {
+ available_hpo_dp_count = dc->res_pool->hpo_dp_link_enc_count;
+ /* remove excess 128b/132b encoding support for not recycled links */
+ for (i = 0; i < dc->caps.max_links; i++) {
+ if ((hpo_dp_recycle_map & (1 << i)) == 0) {
+ link = dc->links[i];
+ if (link->type != dc_connection_none &&
+ link_dp_get_encoding_format(&link->verified_link_cap) == DP_128b_132b_ENCODING) {
+ if (available_hpo_dp_count > 0)
+ available_hpo_dp_count--;
+ else
+ /* remove 128b/132b encoding capability by limiting verified link rate to HBR3 */
+ link->verified_link_cap.link_rate = LINK_RATE_HIGH3;
+ }
+ }
+ }
+ /* remove excess 128b/132b encoding support for recycled links */
+ for (i = 0; i < dc->caps.max_links; i++) {
+ if ((hpo_dp_recycle_map & (1 << i)) != 0) {
+ link = dc->links[i];
+ if (link->type != dc_connection_none &&
+ link_dp_get_encoding_format(&link->verified_link_cap) == DP_128b_132b_ENCODING) {
+ if (available_hpo_dp_count > 0)
+ available_hpo_dp_count--;
+ else
+ /* remove 128b/132b encoding capability by limiting verified link rate to HBR3 */
+ link->verified_link_cap.link_rate = LINK_RATE_HIGH3;
+ }
+ }
+ }
+ }
+}
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_resource.h b/drivers/gpu/drm/amd/display/dc/link/link_resource.h
new file mode 100644
index 000000000000..45554d30adf0
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/link_resource.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2023 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+#ifndef __LINK_RESOURCE_H__
+#define __LINK_RESOURCE_H__
+#include "link.h"
+void link_get_cur_link_res(const struct dc_link *link,
+ struct link_resource *link_res);
+
+#endif /* __LINK_RESOURCE_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_validation.c b/drivers/gpu/drm/amd/display/dc/link/link_validation.c
new file mode 100644
index 000000000000..d4f6ee6ca948
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/link_validation.c
@@ -0,0 +1,398 @@
+/*
+ * Copyright 2023 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+
+/* FILE POLICY AND INTENDED USAGE:
+ * This file owns timing validation against various link limitations. (ex.
+ * link bandwidth, receiver capability or our hardware capability) It also
+ * provides helper functions exposing bandwidth formulas used in validation.
+ */
+#include "link_validation.h"
+#include "resource.h"
+
+#define DC_LOGGER_INIT(logger)
+
+static uint32_t get_tmds_output_pixel_clock_100hz(const struct dc_crtc_timing *timing)
+{
+
+ uint32_t pxl_clk = timing->pix_clk_100hz;
+
+ if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420)
+ pxl_clk /= 2;
+ else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR422)
+ pxl_clk = pxl_clk * 2 / 3;
+
+ if (timing->display_color_depth == COLOR_DEPTH_101010)
+ pxl_clk = pxl_clk * 10 / 8;
+ else if (timing->display_color_depth == COLOR_DEPTH_121212)
+ pxl_clk = pxl_clk * 12 / 8;
+
+ return pxl_clk;
+}
+
+static bool dp_active_dongle_validate_timing(
+ const struct dc_crtc_timing *timing,
+ const struct dpcd_caps *dpcd_caps)
+{
+ const struct dc_dongle_caps *dongle_caps = &dpcd_caps->dongle_caps;
+
+ switch (dpcd_caps->dongle_type) {
+ case DISPLAY_DONGLE_DP_VGA_CONVERTER:
+ case DISPLAY_DONGLE_DP_DVI_CONVERTER:
+ case DISPLAY_DONGLE_DP_DVI_DONGLE:
+ if (timing->pixel_encoding == PIXEL_ENCODING_RGB)
+ return true;
+ else
+ return false;
+ default:
+ break;
+ }
+
+ if (dpcd_caps->dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER &&
+ dongle_caps->extendedCapValid == true) {
+ /* Check Pixel Encoding */
+ switch (timing->pixel_encoding) {
+ case PIXEL_ENCODING_RGB:
+ case PIXEL_ENCODING_YCBCR444:
+ break;
+ case PIXEL_ENCODING_YCBCR422:
+ if (!dongle_caps->is_dp_hdmi_ycbcr422_pass_through)
+ return false;
+ break;
+ case PIXEL_ENCODING_YCBCR420:
+ if (!dongle_caps->is_dp_hdmi_ycbcr420_pass_through)
+ return false;
+ break;
+ default:
+ /* Invalid Pixel Encoding*/
+ return false;
+ }
+
+ switch (timing->display_color_depth) {
+ case COLOR_DEPTH_666:
+ case COLOR_DEPTH_888:
+ /*888 and 666 should always be supported*/
+ break;
+ case COLOR_DEPTH_101010:
+ if (dongle_caps->dp_hdmi_max_bpc < 10)
+ return false;
+ break;
+ case COLOR_DEPTH_121212:
+ if (dongle_caps->dp_hdmi_max_bpc < 12)
+ return false;
+ break;
+ case COLOR_DEPTH_141414:
+ case COLOR_DEPTH_161616:
+ default:
+ /* These color depths are currently not supported */
+ return false;
+ }
+
+ /* Check 3D format */
+ switch (timing->timing_3d_format) {
+ case TIMING_3D_FORMAT_NONE:
+ case TIMING_3D_FORMAT_FRAME_ALTERNATE:
+ /*Only frame alternate 3D is supported on active dongle*/
+ break;
+ default:
+ /*other 3D formats are not supported due to bad infoframe translation */
+ return false;
+ }
+
+ if (dongle_caps->dp_hdmi_frl_max_link_bw_in_kbps > 0) { // DP to HDMI FRL converter
+ struct dc_crtc_timing outputTiming = *timing;
+
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (timing->flags.DSC && !timing->dsc_cfg.is_frl)
+ /* DP input has DSC, HDMI FRL output doesn't have DSC, remove DSC from output timing */
+ outputTiming.flags.DSC = 0;
+#endif
+ if (dc_bandwidth_in_kbps_from_timing(&outputTiming) > dongle_caps->dp_hdmi_frl_max_link_bw_in_kbps)
+ return false;
+ } else { // DP to HDMI TMDS converter
+ if (get_tmds_output_pixel_clock_100hz(timing) > (dongle_caps->dp_hdmi_max_pixel_clk_in_khz * 10))
+ return false;
+ }
+ }
+
+ if (dpcd_caps->channel_coding_cap.bits.DP_128b_132b_SUPPORTED == 0 &&
+ dpcd_caps->dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_PASSTHROUGH_SUPPORT == 0 &&
+ dongle_caps->dfp_cap_ext.supported) {
+
+ if (dongle_caps->dfp_cap_ext.max_pixel_rate_in_mps < (timing->pix_clk_100hz / 10000))
+ return false;
+
+ if (dongle_caps->dfp_cap_ext.max_video_h_active_width < timing->h_addressable)
+ return false;
+
+ if (dongle_caps->dfp_cap_ext.max_video_v_active_height < timing->v_addressable)
+ return false;
+
+ if (timing->pixel_encoding == PIXEL_ENCODING_RGB) {
+ if (!dongle_caps->dfp_cap_ext.encoding_format_caps.support_rgb)
+ return false;
+ if (timing->display_color_depth == COLOR_DEPTH_666 &&
+ !dongle_caps->dfp_cap_ext.rgb_color_depth_caps.support_6bpc)
+ return false;
+ else if (timing->display_color_depth == COLOR_DEPTH_888 &&
+ !dongle_caps->dfp_cap_ext.rgb_color_depth_caps.support_8bpc)
+ return false;
+ else if (timing->display_color_depth == COLOR_DEPTH_101010 &&
+ !dongle_caps->dfp_cap_ext.rgb_color_depth_caps.support_10bpc)
+ return false;
+ else if (timing->display_color_depth == COLOR_DEPTH_121212 &&
+ !dongle_caps->dfp_cap_ext.rgb_color_depth_caps.support_12bpc)
+ return false;
+ else if (timing->display_color_depth == COLOR_DEPTH_161616 &&
+ !dongle_caps->dfp_cap_ext.rgb_color_depth_caps.support_16bpc)
+ return false;
+ } else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR444) {
+ if (!dongle_caps->dfp_cap_ext.encoding_format_caps.support_rgb)
+ return false;
+ if (timing->display_color_depth == COLOR_DEPTH_888 &&
+ !dongle_caps->dfp_cap_ext.ycbcr444_color_depth_caps.support_8bpc)
+ return false;
+ else if (timing->display_color_depth == COLOR_DEPTH_101010 &&
+ !dongle_caps->dfp_cap_ext.ycbcr444_color_depth_caps.support_10bpc)
+ return false;
+ else if (timing->display_color_depth == COLOR_DEPTH_121212 &&
+ !dongle_caps->dfp_cap_ext.ycbcr444_color_depth_caps.support_12bpc)
+ return false;
+ else if (timing->display_color_depth == COLOR_DEPTH_161616 &&
+ !dongle_caps->dfp_cap_ext.ycbcr444_color_depth_caps.support_16bpc)
+ return false;
+ } else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
+ if (!dongle_caps->dfp_cap_ext.encoding_format_caps.support_rgb)
+ return false;
+ if (timing->display_color_depth == COLOR_DEPTH_888 &&
+ !dongle_caps->dfp_cap_ext.ycbcr422_color_depth_caps.support_8bpc)
+ return false;
+ else if (timing->display_color_depth == COLOR_DEPTH_101010 &&
+ !dongle_caps->dfp_cap_ext.ycbcr422_color_depth_caps.support_10bpc)
+ return false;
+ else if (timing->display_color_depth == COLOR_DEPTH_121212 &&
+ !dongle_caps->dfp_cap_ext.ycbcr422_color_depth_caps.support_12bpc)
+ return false;
+ else if (timing->display_color_depth == COLOR_DEPTH_161616 &&
+ !dongle_caps->dfp_cap_ext.ycbcr422_color_depth_caps.support_16bpc)
+ return false;
+ } else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) {
+ if (!dongle_caps->dfp_cap_ext.encoding_format_caps.support_rgb)
+ return false;
+ if (timing->display_color_depth == COLOR_DEPTH_888 &&
+ !dongle_caps->dfp_cap_ext.ycbcr420_color_depth_caps.support_8bpc)
+ return false;
+ else if (timing->display_color_depth == COLOR_DEPTH_101010 &&
+ !dongle_caps->dfp_cap_ext.ycbcr420_color_depth_caps.support_10bpc)
+ return false;
+ else if (timing->display_color_depth == COLOR_DEPTH_121212 &&
+ !dongle_caps->dfp_cap_ext.ycbcr420_color_depth_caps.support_12bpc)
+ return false;
+ else if (timing->display_color_depth == COLOR_DEPTH_161616 &&
+ !dongle_caps->dfp_cap_ext.ycbcr420_color_depth_caps.support_16bpc)
+ return false;
+ }
+ }
+
+ return true;
+}
+
+uint32_t dp_link_bandwidth_kbps(
+ const struct dc_link *link,
+ const struct dc_link_settings *link_settings)
+{
+ uint32_t total_data_bw_efficiency_x10000 = 0;
+ uint32_t link_rate_per_lane_kbps = 0;
+
+ switch (link_dp_get_encoding_format(link_settings)) {
+ case DP_8b_10b_ENCODING:
+ /* For 8b/10b encoding:
+ * link rate is defined in the unit of LINK_RATE_REF_FREQ_IN_KHZ per DP byte per lane.
+ * data bandwidth efficiency is 80% with additional 3% overhead if FEC is supported.
+ */
+ link_rate_per_lane_kbps = link_settings->link_rate * LINK_RATE_REF_FREQ_IN_KHZ * BITS_PER_DP_BYTE;
+ total_data_bw_efficiency_x10000 = DATA_EFFICIENCY_8b_10b_x10000;
+ if (dc_link_should_enable_fec(link)) {
+ total_data_bw_efficiency_x10000 /= 100;
+ total_data_bw_efficiency_x10000 *= DATA_EFFICIENCY_8b_10b_FEC_EFFICIENCY_x100;
+ }
+ break;
+ case DP_128b_132b_ENCODING:
+ /* For 128b/132b encoding:
+ * link rate is defined in the unit of 10mbps per lane.
+ * total data bandwidth efficiency is always 96.71%.
+ */
+ link_rate_per_lane_kbps = link_settings->link_rate * 10000;
+ total_data_bw_efficiency_x10000 = DATA_EFFICIENCY_128b_132b_x10000;
+ break;
+ default:
+ break;
+ }
+
+ /* overall effective link bandwidth = link rate per lane * lane count * total data bandwidth efficiency */
+ return link_rate_per_lane_kbps * link_settings->lane_count / 10000 * total_data_bw_efficiency_x10000;
+}
+
+uint32_t link_timing_bandwidth_kbps(
+ const struct dc_crtc_timing *timing)
+{
+ uint32_t bits_per_channel = 0;
+ uint32_t kbps;
+
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (timing->flags.DSC)
+ return dc_dsc_stream_bandwidth_in_kbps(timing,
+ timing->dsc_cfg.bits_per_pixel,
+ timing->dsc_cfg.num_slices_h,
+ timing->dsc_cfg.is_dp);
+#endif /* CONFIG_DRM_AMD_DC_DCN */
+
+ switch (timing->display_color_depth) {
+ case COLOR_DEPTH_666:
+ bits_per_channel = 6;
+ break;
+ case COLOR_DEPTH_888:
+ bits_per_channel = 8;
+ break;
+ case COLOR_DEPTH_101010:
+ bits_per_channel = 10;
+ break;
+ case COLOR_DEPTH_121212:
+ bits_per_channel = 12;
+ break;
+ case COLOR_DEPTH_141414:
+ bits_per_channel = 14;
+ break;
+ case COLOR_DEPTH_161616:
+ bits_per_channel = 16;
+ break;
+ default:
+ ASSERT(bits_per_channel != 0);
+ bits_per_channel = 8;
+ break;
+ }
+
+ kbps = timing->pix_clk_100hz / 10;
+ kbps *= bits_per_channel;
+
+ if (timing->flags.Y_ONLY != 1) {
+ /*Only YOnly make reduce bandwidth by 1/3 compares to RGB*/
+ kbps *= 3;
+ if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420)
+ kbps /= 2;
+ else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR422)
+ kbps = kbps * 2 / 3;
+ }
+
+ return kbps;
+}
+
+static bool dp_validate_mode_timing(
+ struct dc_link *link,
+ const struct dc_crtc_timing *timing)
+{
+ uint32_t req_bw;
+ uint32_t max_bw;
+
+ const struct dc_link_settings *link_setting;
+
+ /* According to spec, VSC SDP should be used if pixel format is YCbCr420 */
+ if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420 &&
+ !link->dpcd_caps.dprx_feature.bits.VSC_SDP_COLORIMETRY_SUPPORTED &&
+ dal_graphics_object_id_get_connector_id(link->link_id) != CONNECTOR_ID_VIRTUAL)
+ return false;
+
+ /*always DP fail safe mode*/
+ if ((timing->pix_clk_100hz / 10) == (uint32_t) 25175 &&
+ timing->h_addressable == (uint32_t) 640 &&
+ timing->v_addressable == (uint32_t) 480)
+ return true;
+
+ link_setting = dc_link_get_link_cap(link);
+
+ /* TODO: DYNAMIC_VALIDATION needs to be implemented */
+ /*if (flags.DYNAMIC_VALIDATION == 1 &&
+ link->verified_link_cap.lane_count != LANE_COUNT_UNKNOWN)
+ link_setting = &link->verified_link_cap;
+ */
+
+ req_bw = dc_bandwidth_in_kbps_from_timing(timing);
+ max_bw = dc_link_bandwidth_kbps(link, link_setting);
+
+ if (req_bw <= max_bw) {
+ /* remember the biggest mode here, during
+ * initial link training (to get
+ * verified_link_cap), LS sends event about
+ * cannot train at reported cap to upper
+ * layer and upper layer will re-enumerate modes.
+ * this is not necessary if the lower
+ * verified_link_cap is enough to drive
+ * all the modes */
+
+ /* TODO: DYNAMIC_VALIDATION needs to be implemented */
+ /* if (flags.DYNAMIC_VALIDATION == 1)
+ dpsst->max_req_bw_for_verified_linkcap = dal_max(
+ dpsst->max_req_bw_for_verified_linkcap, req_bw); */
+ return true;
+ } else
+ return false;
+}
+
+enum dc_status link_validate_mode_timing(
+ const struct dc_stream_state *stream,
+ struct dc_link *link,
+ const struct dc_crtc_timing *timing)
+{
+ uint32_t max_pix_clk = stream->link->dongle_max_pix_clk * 10;
+ struct dpcd_caps *dpcd_caps = &link->dpcd_caps;
+
+ /* A hack to avoid failing any modes for EDID override feature on
+ * topology change such as lower quality cable for DP or different dongle
+ */
+ if (link->remote_sinks[0] && link->remote_sinks[0]->sink_signal == SIGNAL_TYPE_VIRTUAL)
+ return DC_OK;
+
+ /* Passive Dongle */
+ if (max_pix_clk != 0 && get_tmds_output_pixel_clock_100hz(timing) > max_pix_clk)
+ return DC_EXCEED_DONGLE_CAP;
+
+ /* Active Dongle*/
+ if (!dp_active_dongle_validate_timing(timing, dpcd_caps))
+ return DC_EXCEED_DONGLE_CAP;
+
+ switch (stream->signal) {
+ case SIGNAL_TYPE_EDP:
+ case SIGNAL_TYPE_DISPLAY_PORT:
+ if (!dp_validate_mode_timing(
+ link,
+ timing))
+ return DC_NO_DP_LINK_BANDWIDTH;
+ break;
+
+ default:
+ break;
+ }
+
+ return DC_OK;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_validation.h b/drivers/gpu/drm/amd/display/dc/link/link_validation.h
new file mode 100644
index 000000000000..ab6a44f50032
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/link_validation.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2023 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+#ifndef __LINK_VALIDATION_H__
+#define __LINK_VALIDATION_H__
+#include "link.h"
+#endif /* __LINK_VALIDATION_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_ddc.c
index ce8d6a54ca54..5269125bc2a4 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_ddc.c
@@ -23,20 +23,20 @@
*
*/
-#include "dm_services.h"
-#include "dm_helpers.h"
-#include "gpio_service_interface.h"
-#include "include/ddc_service_types.h"
-#include "include/grph_object_id.h"
-#include "include/dpcd_defs.h"
-#include "include/logger_interface.h"
-#include "include/vector.h"
-#include "core_types.h"
-#include "dc_link_ddc.h"
+/* FILE POLICY AND INTENDED USAGE:
+ *
+ * This file implements generic display communication protocols such as i2c, aux
+ * and scdc. The file should not contain any specific applications of these
+ * protocols such as display capability query, detection, or handshaking such as
+ * link training.
+ */
+#include "link_ddc.h"
+#include "vector.h"
#include "dce/dce_aux.h"
-#include "dmub/inc/dmub_cmd.h"
+#include "dal_asic_id.h"
#include "link_dpcd.h"
-#include "include/dal_asic_id.h"
+#include "dm_helpers.h"
+#include "atomfirmware.h"
#define DC_LOGGER_INIT(logger)
@@ -45,87 +45,6 @@ static const uint8_t DP_VGA_DONGLE_BRANCH_DEV_NAME[] = "DpVga";
static const uint8_t DP_DVI_CONVERTER_ID_4[] = "m2DVIa";
static const uint8_t DP_DVI_CONVERTER_ID_5[] = "3393N2";
-#define AUX_POWER_UP_WA_DELAY 500
-#define I2C_OVER_AUX_DEFER_WA_DELAY 70
-#define DPVGA_DONGLE_AUX_DEFER_WA_DELAY 40
-#define I2C_OVER_AUX_DEFER_WA_DELAY_1MS 1
-
-/* CV smart dongle slave address for retrieving supported HDTV modes*/
-#define CV_SMART_DONGLE_ADDRESS 0x20
-/* DVI-HDMI dongle slave address for retrieving dongle signature*/
-#define DVI_HDMI_DONGLE_ADDRESS 0x68
-struct dvi_hdmi_dongle_signature_data {
- int8_t vendor[3];/* "AMD" */
- uint8_t version[2];
- uint8_t size;
- int8_t id[11];/* "6140063500G"*/
-};
-/* DP-HDMI dongle slave address for retrieving dongle signature*/
-#define DP_HDMI_DONGLE_ADDRESS 0x40
-static const uint8_t dp_hdmi_dongle_signature_str[] = "DP-HDMI ADAPTOR";
-#define DP_HDMI_DONGLE_SIGNATURE_EOT 0x04
-
-struct dp_hdmi_dongle_signature_data {
- int8_t id[15];/* "DP-HDMI ADAPTOR"*/
- uint8_t eot;/* end of transmition '\x4' */
-};
-
-/* SCDC Address defines (HDMI 2.0)*/
-#define HDMI_SCDC_WRITE_UPDATE_0_ARRAY 3
-#define HDMI_SCDC_ADDRESS 0x54
-#define HDMI_SCDC_SINK_VERSION 0x01
-#define HDMI_SCDC_SOURCE_VERSION 0x02
-#define HDMI_SCDC_UPDATE_0 0x10
-#define HDMI_SCDC_TMDS_CONFIG 0x20
-#define HDMI_SCDC_SCRAMBLER_STATUS 0x21
-#define HDMI_SCDC_CONFIG_0 0x30
-#define HDMI_SCDC_STATUS_FLAGS 0x40
-#define HDMI_SCDC_ERR_DETECT 0x50
-#define HDMI_SCDC_TEST_CONFIG 0xC0
-#define HDMI_SCDC_DEVICE_ID 0xD3
-
-union hdmi_scdc_update_read_data {
- uint8_t byte[2];
- struct {
- uint8_t STATUS_UPDATE:1;
- uint8_t CED_UPDATE:1;
- uint8_t RR_TEST:1;
- uint8_t RESERVED:5;
- uint8_t RESERVED2:8;
- } fields;
-};
-
-union hdmi_scdc_status_flags_data {
- uint8_t byte;
- struct {
- uint8_t CLOCK_DETECTED:1;
- uint8_t CH0_LOCKED:1;
- uint8_t CH1_LOCKED:1;
- uint8_t CH2_LOCKED:1;
- uint8_t RESERVED:4;
- } fields;
-};
-
-union hdmi_scdc_ced_data {
- uint8_t byte[7];
- struct {
- uint8_t CH0_8LOW:8;
- uint8_t CH0_7HIGH:7;
- uint8_t CH0_VALID:1;
- uint8_t CH1_8LOW:8;
- uint8_t CH1_7HIGH:7;
- uint8_t CH1_VALID:1;
- uint8_t CH2_8LOW:8;
- uint8_t CH2_7HIGH:7;
- uint8_t CH2_VALID:1;
- uint8_t CHECKSUM:8;
- uint8_t RESERVED:8;
- uint8_t RESERVED2:8;
- uint8_t RESERVED3:8;
- uint8_t RESERVED4:4;
- } fields;
-};
-
struct i2c_payloads {
struct vector payloads;
};
@@ -158,7 +77,7 @@ static uint32_t dal_ddc_i2c_payloads_get_count(struct i2c_payloads *p)
#define DDC_MIN(a, b) (((a) < (b)) ? (a) : (b))
-void dal_ddc_i2c_payloads_add(
+static void i2c_payloads_add(
struct i2c_payloads *payloads,
uint32_t address,
uint32_t len,
@@ -226,7 +145,7 @@ static void ddc_service_construct(
ddc_service->wa.raw = 0;
}
-struct ddc_service *dal_ddc_service_create(
+struct ddc_service *link_create_ddc_service(
struct ddc_service_init_data *init_data)
{
struct ddc_service *ddc_service;
@@ -246,7 +165,7 @@ static void ddc_service_destruct(struct ddc_service *ddc)
dal_gpio_destroy_ddc(&ddc->ddc_pin);
}
-void dal_ddc_service_destroy(struct ddc_service **ddc)
+void link_destroy_ddc_service(struct ddc_service **ddc)
{
if (!ddc || !*ddc) {
BREAK_TO_DEBUGGER();
@@ -257,19 +176,14 @@ void dal_ddc_service_destroy(struct ddc_service **ddc)
*ddc = NULL;
}
-enum ddc_service_type dal_ddc_service_get_type(struct ddc_service *ddc)
-{
- return DDC_SERVICE_TYPE_CONNECTOR;
-}
-
-void dal_ddc_service_set_transaction_type(
+void set_ddc_transaction_type(
struct ddc_service *ddc,
enum ddc_transaction_type type)
{
ddc->transaction_type = type;
}
-bool dal_ddc_service_is_in_aux_transaction_mode(struct ddc_service *ddc)
+bool link_is_in_aux_transaction_mode(struct ddc_service *ddc)
{
switch (ddc->transaction_type) {
case DDC_TRANSACTION_TYPE_I2C_OVER_AUX:
@@ -282,7 +196,7 @@ bool dal_ddc_service_is_in_aux_transaction_mode(struct ddc_service *ddc)
return false;
}
-void ddc_service_set_dongle_type(struct ddc_service *ddc,
+void set_dongle_type(struct ddc_service *ddc,
enum display_dongle_type dongle_type)
{
ddc->dongle_type = dongle_type;
@@ -324,7 +238,7 @@ static uint32_t defer_delay_converter_wa(
#define DP_TRANSLATOR_DELAY 5
-uint32_t get_defer_delay(struct ddc_service *ddc)
+uint32_t link_get_aux_defer_delay(struct ddc_service *ddc)
{
uint32_t defer_delay = 0;
@@ -352,175 +266,45 @@ uint32_t get_defer_delay(struct ddc_service *ddc)
return defer_delay;
}
-static bool i2c_read(
- struct ddc_service *ddc,
- uint32_t address,
- uint8_t *buffer,
- uint32_t len)
-{
- uint8_t offs_data = 0;
- struct i2c_payload payloads[2] = {
- {
- .write = true,
- .address = address,
- .length = 1,
- .data = &offs_data },
- {
- .write = false,
- .address = address,
- .length = len,
- .data = buffer } };
-
- struct i2c_command command = {
- .payloads = payloads,
- .number_of_payloads = 2,
- .engine = DDC_I2C_COMMAND_ENGINE,
- .speed = ddc->ctx->dc->caps.i2c_speed_in_khz };
-
- return dm_helpers_submit_i2c(
- ddc->ctx,
- ddc->link,
- &command);
-}
-
-void dal_ddc_service_i2c_query_dp_dual_mode_adaptor(
- struct ddc_service *ddc,
- struct display_sink_capability *sink_cap)
+static bool submit_aux_command(struct ddc_service *ddc,
+ struct aux_payload *payload)
{
- uint8_t i;
- bool is_valid_hdmi_signature;
- enum display_dongle_type *dongle = &sink_cap->dongle_type;
- uint8_t type2_dongle_buf[DP_ADAPTOR_TYPE2_SIZE];
- bool is_type2_dongle = false;
- int retry_count = 2;
- struct dp_hdmi_dongle_signature_data *dongle_signature;
-
- /* Assume we have no valid DP passive dongle connected */
- *dongle = DISPLAY_DONGLE_NONE;
- sink_cap->max_hdmi_pixel_clock = DP_ADAPTOR_HDMI_SAFE_MAX_TMDS_CLK;
-
- /* Read DP-HDMI dongle I2c (no response interpreted as DP-DVI dongle)*/
- if (!i2c_read(
- ddc,
- DP_HDMI_DONGLE_ADDRESS,
- type2_dongle_buf,
- sizeof(type2_dongle_buf))) {
- /* Passive HDMI dongles can sometimes fail here without retrying*/
- while (retry_count > 0) {
- if (i2c_read(ddc,
- DP_HDMI_DONGLE_ADDRESS,
- type2_dongle_buf,
- sizeof(type2_dongle_buf)))
- break;
- retry_count--;
- }
- if (retry_count == 0) {
- *dongle = DISPLAY_DONGLE_DP_DVI_DONGLE;
- sink_cap->max_hdmi_pixel_clock = DP_ADAPTOR_DVI_MAX_TMDS_CLK;
-
- CONN_DATA_DETECT(ddc->link, type2_dongle_buf, sizeof(type2_dongle_buf),
- "DP-DVI passive dongle %dMhz: ",
- DP_ADAPTOR_DVI_MAX_TMDS_CLK / 1000);
- return;
- }
- }
-
- /* Check if Type 2 dongle.*/
- if (type2_dongle_buf[DP_ADAPTOR_TYPE2_REG_ID] == DP_ADAPTOR_TYPE2_ID)
- is_type2_dongle = true;
-
- dongle_signature =
- (struct dp_hdmi_dongle_signature_data *)type2_dongle_buf;
+ uint32_t retrieved = 0;
+ bool ret = false;
- is_valid_hdmi_signature = true;
+ if (!ddc)
+ return false;
- /* Check EOT */
- if (dongle_signature->eot != DP_HDMI_DONGLE_SIGNATURE_EOT) {
- is_valid_hdmi_signature = false;
- }
+ if (!payload)
+ return false;
- /* Check signature */
- for (i = 0; i < sizeof(dongle_signature->id); ++i) {
- /* If its not the right signature,
- * skip mismatch in subversion byte.*/
- if (dongle_signature->id[i] !=
- dp_hdmi_dongle_signature_str[i] && i != 3) {
+ do {
+ struct aux_payload current_payload;
+ bool is_end_of_payload = (retrieved + DEFAULT_AUX_MAX_DATA_SIZE) >=
+ payload->length;
+ uint32_t payload_length = is_end_of_payload ?
+ payload->length - retrieved : DEFAULT_AUX_MAX_DATA_SIZE;
- if (is_type2_dongle) {
- is_valid_hdmi_signature = false;
- break;
- }
+ current_payload.address = payload->address;
+ current_payload.data = &payload->data[retrieved];
+ current_payload.defer_delay = payload->defer_delay;
+ current_payload.i2c_over_aux = payload->i2c_over_aux;
+ current_payload.length = payload_length;
+ /* set mot (middle of transaction) to false if it is the last payload */
+ current_payload.mot = is_end_of_payload ? payload->mot:true;
+ current_payload.write_status_update = false;
+ current_payload.reply = payload->reply;
+ current_payload.write = payload->write;
- }
- }
+ ret = link_aux_transfer_with_retries_no_mutex(ddc, &current_payload);
- if (is_type2_dongle) {
- uint32_t max_tmds_clk =
- type2_dongle_buf[DP_ADAPTOR_TYPE2_REG_MAX_TMDS_CLK];
-
- max_tmds_clk = max_tmds_clk * 2 + max_tmds_clk / 2;
-
- if (0 == max_tmds_clk ||
- max_tmds_clk < DP_ADAPTOR_TYPE2_MIN_TMDS_CLK ||
- max_tmds_clk > DP_ADAPTOR_TYPE2_MAX_TMDS_CLK) {
- *dongle = DISPLAY_DONGLE_DP_DVI_DONGLE;
-
- CONN_DATA_DETECT(ddc->link, type2_dongle_buf,
- sizeof(type2_dongle_buf),
- "DP-DVI passive dongle %dMhz: ",
- DP_ADAPTOR_DVI_MAX_TMDS_CLK / 1000);
- } else {
- if (is_valid_hdmi_signature == true) {
- *dongle = DISPLAY_DONGLE_DP_HDMI_DONGLE;
-
- CONN_DATA_DETECT(ddc->link, type2_dongle_buf,
- sizeof(type2_dongle_buf),
- "Type 2 DP-HDMI passive dongle %dMhz: ",
- max_tmds_clk);
- } else {
- *dongle = DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE;
-
- CONN_DATA_DETECT(ddc->link, type2_dongle_buf,
- sizeof(type2_dongle_buf),
- "Type 2 DP-HDMI passive dongle (no signature) %dMhz: ",
- max_tmds_clk);
-
- }
-
- /* Multiply by 1000 to convert to kHz. */
- sink_cap->max_hdmi_pixel_clock =
- max_tmds_clk * 1000;
- }
- sink_cap->is_dongle_type_one = false;
-
- } else {
- if (is_valid_hdmi_signature == true) {
- *dongle = DISPLAY_DONGLE_DP_HDMI_DONGLE;
-
- CONN_DATA_DETECT(ddc->link, type2_dongle_buf,
- sizeof(type2_dongle_buf),
- "Type 1 DP-HDMI passive dongle %dMhz: ",
- sink_cap->max_hdmi_pixel_clock / 1000);
- } else {
- *dongle = DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE;
-
- CONN_DATA_DETECT(ddc->link, type2_dongle_buf,
- sizeof(type2_dongle_buf),
- "Type 1 DP-HDMI passive dongle (no signature) %dMhz: ",
- sink_cap->max_hdmi_pixel_clock / 1000);
- }
- sink_cap->is_dongle_type_one = true;
- }
+ retrieved += payload_length;
+ } while (retrieved < payload->length && ret == true);
- return;
+ return ret;
}
-enum {
- DP_SINK_CAP_SIZE =
- DP_EDP_CONFIGURATION_CAP - DP_DPCD_REV + 1
-};
-
-bool dal_ddc_service_query_ddc_data(
+bool link_query_ddc_data(
struct ddc_service *ddc,
uint32_t address,
uint8_t *write_buf,
@@ -530,7 +314,7 @@ bool dal_ddc_service_query_ddc_data(
{
bool success = true;
uint32_t payload_size =
- dal_ddc_service_is_in_aux_transaction_mode(ddc) ?
+ link_is_in_aux_transaction_mode(ddc) ?
DEFAULT_AUX_MAX_DATA_SIZE : EDID_SEGMENT_SIZE;
uint32_t write_payloads =
@@ -544,13 +328,13 @@ bool dal_ddc_service_query_ddc_data(
if (!payloads_num)
return false;
- if (dal_ddc_service_is_in_aux_transaction_mode(ddc)) {
+ if (link_is_in_aux_transaction_mode(ddc)) {
struct aux_payload payload;
payload.i2c_over_aux = true;
payload.address = address;
payload.reply = NULL;
- payload.defer_delay = get_defer_delay(ddc);
+ payload.defer_delay = link_get_aux_defer_delay(ddc);
payload.write_status_update = false;
if (write_size != 0) {
@@ -562,7 +346,7 @@ bool dal_ddc_service_query_ddc_data(
payload.length = write_size;
payload.data = write_buf;
- success = dal_ddc_submit_aux_command(ddc, &payload);
+ success = submit_aux_command(ddc, &payload);
}
if (read_size != 0 && success) {
@@ -574,7 +358,7 @@ bool dal_ddc_service_query_ddc_data(
payload.length = read_size;
payload.data = read_buf;
- success = dal_ddc_submit_aux_command(ddc, &payload);
+ success = submit_aux_command(ddc, &payload);
}
} else {
struct i2c_command command = {0};
@@ -588,10 +372,10 @@ bool dal_ddc_service_query_ddc_data(
command.engine = DDC_I2C_COMMAND_ENGINE;
command.speed = ddc->ctx->dc->caps.i2c_speed_in_khz;
- dal_ddc_i2c_payloads_add(
+ i2c_payloads_add(
&payloads, address, write_size, write_buf, true);
- dal_ddc_i2c_payloads_add(
+ i2c_payloads_add(
&payloads, address, read_size, read_buf, false);
command.number_of_payloads =
@@ -608,51 +392,6 @@ bool dal_ddc_service_query_ddc_data(
return success;
}
-bool dal_ddc_submit_aux_command(struct ddc_service *ddc,
- struct aux_payload *payload)
-{
- uint32_t retrieved = 0;
- bool ret = false;
-
- if (!ddc)
- return false;
-
- if (!payload)
- return false;
-
- do {
- struct aux_payload current_payload;
- bool is_end_of_payload = (retrieved + DEFAULT_AUX_MAX_DATA_SIZE) >=
- payload->length;
- uint32_t payload_length = is_end_of_payload ?
- payload->length - retrieved : DEFAULT_AUX_MAX_DATA_SIZE;
-
- current_payload.address = payload->address;
- current_payload.data = &payload->data[retrieved];
- current_payload.defer_delay = payload->defer_delay;
- current_payload.i2c_over_aux = payload->i2c_over_aux;
- current_payload.length = payload_length;
- /* set mot (middle of transaction) to false if it is the last payload */
- current_payload.mot = is_end_of_payload ? payload->mot:true;
- current_payload.write_status_update = false;
- current_payload.reply = payload->reply;
- current_payload.write = payload->write;
-
- ret = dc_link_aux_transfer_with_retries(ddc, &current_payload);
-
- retrieved += payload_length;
- } while (retrieved < payload->length && ret == true);
-
- return ret;
-}
-
-/* dc_link_aux_transfer_raw() - Attempt to transfer
- * the given aux payload. This function does not perform
- * retries or handle error states. The reply is returned
- * in the payload->reply and the result through
- * *operation_result. Returns the number of bytes transferred,
- * or -1 on a failure.
- */
int dc_link_aux_transfer_raw(struct ddc_service *ddc,
struct aux_payload *payload,
enum aux_return_code_type *operation_result)
@@ -665,22 +404,14 @@ int dc_link_aux_transfer_raw(struct ddc_service *ddc,
}
}
-/* dc_link_aux_transfer_with_retries() - Attempt to submit an
- * aux payload, retrying on timeouts, defers, and busy states
- * as outlined in the DP spec. Returns true if the request
- * was successful.
- *
- * Unless you want to implement your own retry semantics, this
- * is probably the one you want.
- */
-bool dc_link_aux_transfer_with_retries(struct ddc_service *ddc,
+bool link_aux_transfer_with_retries_no_mutex(struct ddc_service *ddc,
struct aux_payload *payload)
{
return dce_aux_transfer_with_retries(ddc, payload);
}
-bool dc_link_aux_try_to_configure_timeout(struct ddc_service *ddc,
+bool try_to_configure_aux_timeout(struct ddc_service *ddc,
uint32_t timeout)
{
bool result = false;
@@ -713,20 +444,12 @@ bool dc_link_aux_try_to_configure_timeout(struct ddc_service *ddc,
return result;
}
-/*test only function*/
-void dal_ddc_service_set_ddc_pin(
- struct ddc_service *ddc_service,
- struct ddc *ddc)
-{
- ddc_service->ddc_pin = ddc;
-}
-
-struct ddc *dal_ddc_service_get_ddc_pin(struct ddc_service *ddc_service)
+struct ddc *get_ddc_pin(struct ddc_service *ddc_service)
{
return ddc_service->ddc_pin;
}
-void dal_ddc_service_write_scdc_data(struct ddc_service *ddc_service,
+void write_scdc_data(struct ddc_service *ddc_service,
uint32_t pix_clk,
bool lte_340_scramble)
{
@@ -741,13 +464,13 @@ void dal_ddc_service_write_scdc_data(struct ddc_service *ddc_service,
ddc_service->link->local_sink->edid_caps.panel_patch.skip_scdc_overwrite)
return;
- dal_ddc_service_query_ddc_data(ddc_service, slave_address, &offset,
+ link_query_ddc_data(ddc_service, slave_address, &offset,
sizeof(offset), &sink_version, sizeof(sink_version));
if (sink_version == 1) {
/*Source Version = 1*/
write_buffer[0] = HDMI_SCDC_SOURCE_VERSION;
write_buffer[1] = 1;
- dal_ddc_service_query_ddc_data(ddc_service, slave_address,
+ link_query_ddc_data(ddc_service, slave_address,
write_buffer, sizeof(write_buffer), NULL, 0);
/*Read Request from SCDC caps*/
}
@@ -760,11 +483,11 @@ void dal_ddc_service_write_scdc_data(struct ddc_service *ddc_service,
} else {
write_buffer[1] = 0;
}
- dal_ddc_service_query_ddc_data(ddc_service, slave_address, write_buffer,
+ link_query_ddc_data(ddc_service, slave_address, write_buffer,
sizeof(write_buffer), NULL, 0);
}
-void dal_ddc_service_read_scdc_data(struct ddc_service *ddc_service)
+void read_scdc_data(struct ddc_service *ddc_service)
{
uint8_t slave_address = HDMI_SCDC_ADDRESS;
uint8_t offset = HDMI_SCDC_TMDS_CONFIG;
@@ -774,20 +497,19 @@ void dal_ddc_service_read_scdc_data(struct ddc_service *ddc_service)
ddc_service->link->local_sink->edid_caps.panel_patch.skip_scdc_overwrite)
return;
- dal_ddc_service_query_ddc_data(ddc_service, slave_address, &offset,
+ link_query_ddc_data(ddc_service, slave_address, &offset,
sizeof(offset), &tmds_config, sizeof(tmds_config));
if (tmds_config & 0x1) {
union hdmi_scdc_status_flags_data status_data = {0};
uint8_t scramble_status = 0;
offset = HDMI_SCDC_SCRAMBLER_STATUS;
- dal_ddc_service_query_ddc_data(ddc_service, slave_address,
+ link_query_ddc_data(ddc_service, slave_address,
&offset, sizeof(offset), &scramble_status,
sizeof(scramble_status));
offset = HDMI_SCDC_STATUS_FLAGS;
- dal_ddc_service_query_ddc_data(ddc_service, slave_address,
+ link_query_ddc_data(ddc_service, slave_address,
&offset, sizeof(offset), &status_data.byte,
sizeof(status_data.byte));
}
}
-
diff --git a/drivers/gpu/drm/amd/display/include/i2caux_interface.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_ddc.h
index 418fbf8c5c3a..aaa5064408ba 100644
--- a/drivers/gpu/drm/amd/display/include/i2caux_interface.h
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_ddc.h
@@ -23,60 +23,39 @@
*
*/
-#ifndef __DAL_I2CAUX_INTERFACE_H__
-#define __DAL_I2CAUX_INTERFACE_H__
+#ifndef __DAL_DDC_SERVICE_H__
+#define __DAL_DDC_SERVICE_H__
-#include "dc_types.h"
-#include "gpio_service_interface.h"
+#include "link.h"
+#define AUX_POWER_UP_WA_DELAY 500
+#define I2C_OVER_AUX_DEFER_WA_DELAY 70
+#define DPVGA_DONGLE_AUX_DEFER_WA_DELAY 40
+#define I2C_OVER_AUX_DEFER_WA_DELAY_1MS 1
+#define LINK_AUX_DEFAULT_LTTPR_TIMEOUT_PERIOD 3200 /*us*/
+#define LINK_AUX_DEFAULT_TIMEOUT_PERIOD 552 /*us*/
-#define DEFAULT_AUX_MAX_DATA_SIZE 16
-#define AUX_MAX_DEFER_WRITE_RETRY 20
+#define EDID_SEGMENT_SIZE 256
-struct aux_payload {
- /* set following flag to read/write I2C data,
- * reset it to read/write DPCD data */
- bool i2c_over_aux;
- /* set following flag to write data,
- * reset it to read data */
- bool write;
- bool mot;
- bool write_status_update;
+void set_ddc_transaction_type(
+ struct ddc_service *ddc,
+ enum ddc_transaction_type type);
- uint32_t address;
- uint32_t length;
- uint8_t *data;
- /*
- * used to return the reply type of the transaction
- * ignored if NULL
- */
- uint8_t *reply;
- /* expressed in milliseconds
- * zero means "use default value"
- */
- uint32_t defer_delay;
+bool try_to_configure_aux_timeout(struct ddc_service *ddc,
+ uint32_t timeout);
-};
+void write_scdc_data(
+ struct ddc_service *ddc_service,
+ uint32_t pix_clk,
+ bool lte_340_scramble);
-struct aux_command {
- struct aux_payload *payloads;
- uint8_t number_of_payloads;
+void read_scdc_data(
+ struct ddc_service *ddc_service);
- /* expressed in milliseconds
- * zero means "use default value" */
- uint32_t defer_delay;
+void set_dongle_type(struct ddc_service *ddc,
+ enum display_dongle_type dongle_type);
- /* zero means "use default value" */
- uint32_t max_defer_write_retry;
+struct ddc *get_ddc_pin(struct ddc_service *ddc_service);
- enum i2c_mot_mode mot;
-};
+#endif /* __DAL_DDC_SERVICE_H__ */
-union aux_config {
- struct {
- uint32_t ALLOW_AUX_WHEN_HPD_LOW:1;
- } bits;
- uint32_t raw;
-};
-
-#endif
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c
new file mode 100644
index 000000000000..d4370856f164
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c
@@ -0,0 +1,2244 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+
+/* FILE POLICY AND INTENDED USAGE:
+ * This file implements dp specific link capability retrieval sequence. It is
+ * responsible for retrieving, parsing, overriding, deciding capability obtained
+ * from dp link. Link capability consists of encoders, DPRXs, cables, retimers,
+ * usb and all other possible backend capabilities. Other components should
+ * include this header file in order to access link capability. Accessing link
+ * capability by dereferencing dc_link outside dp_link_capability is not a
+ * recommended method as it makes the component dependent on the underlying data
+ * structure used to represent link capability instead of function interfaces.
+ */
+
+#include "link_dp_capability.h"
+#include "link_ddc.h"
+#include "link_dpcd.h"
+#include "link_dp_dpia.h"
+#include "link_dp_phy.h"
+#include "link_edp_panel_control.h"
+#include "link_dp_irq_handler.h"
+#include "link/accessories/link_dp_trace.h"
+#include "link_dp_training.h"
+#include "atomfirmware.h"
+#include "resource.h"
+#include "link_enc_cfg.h"
+#include "dc_dmub_srv.h"
+#include "gpio_service_interface.h"
+
+#define DC_LOGGER \
+ link->ctx->logger
+#define DC_TRACE_LEVEL_MESSAGE(...) /* do nothing */
+
+#ifndef MAX
+#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
+#endif
+#ifndef MIN
+#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
+#endif
+
+struct dp_lt_fallback_entry {
+ enum dc_lane_count lane_count;
+ enum dc_link_rate link_rate;
+};
+
+static const struct dp_lt_fallback_entry dp_lt_fallbacks[] = {
+ /* This link training fallback array is ordered by
+ * link bandwidth from highest to lowest.
+ * DP specs makes it a normative policy to always
+ * choose the next highest link bandwidth during
+ * link training fallback.
+ */
+ {LANE_COUNT_FOUR, LINK_RATE_UHBR20},
+ {LANE_COUNT_FOUR, LINK_RATE_UHBR13_5},
+ {LANE_COUNT_TWO, LINK_RATE_UHBR20},
+ {LANE_COUNT_FOUR, LINK_RATE_UHBR10},
+ {LANE_COUNT_TWO, LINK_RATE_UHBR13_5},
+ {LANE_COUNT_FOUR, LINK_RATE_HIGH3},
+ {LANE_COUNT_ONE, LINK_RATE_UHBR20},
+ {LANE_COUNT_TWO, LINK_RATE_UHBR10},
+ {LANE_COUNT_FOUR, LINK_RATE_HIGH2},
+ {LANE_COUNT_ONE, LINK_RATE_UHBR13_5},
+ {LANE_COUNT_TWO, LINK_RATE_HIGH3},
+ {LANE_COUNT_ONE, LINK_RATE_UHBR10},
+ {LANE_COUNT_TWO, LINK_RATE_HIGH2},
+ {LANE_COUNT_FOUR, LINK_RATE_HIGH},
+ {LANE_COUNT_ONE, LINK_RATE_HIGH3},
+ {LANE_COUNT_FOUR, LINK_RATE_LOW},
+ {LANE_COUNT_ONE, LINK_RATE_HIGH2},
+ {LANE_COUNT_TWO, LINK_RATE_HIGH},
+ {LANE_COUNT_TWO, LINK_RATE_LOW},
+ {LANE_COUNT_ONE, LINK_RATE_HIGH},
+ {LANE_COUNT_ONE, LINK_RATE_LOW},
+};
+
+static const struct dc_link_settings fail_safe_link_settings = {
+ .lane_count = LANE_COUNT_ONE,
+ .link_rate = LINK_RATE_LOW,
+ .link_spread = LINK_SPREAD_DISABLED,
+};
+
+bool is_dp_active_dongle(const struct dc_link *link)
+{
+ return (link->dpcd_caps.dongle_type >= DISPLAY_DONGLE_DP_VGA_CONVERTER) &&
+ (link->dpcd_caps.dongle_type <= DISPLAY_DONGLE_DP_HDMI_CONVERTER);
+}
+
+bool is_dp_branch_device(const struct dc_link *link)
+{
+ return link->dpcd_caps.is_branch_dev;
+}
+
+static int translate_dpcd_max_bpc(enum dpcd_downstream_port_max_bpc bpc)
+{
+ switch (bpc) {
+ case DOWN_STREAM_MAX_8BPC:
+ return 8;
+ case DOWN_STREAM_MAX_10BPC:
+ return 10;
+ case DOWN_STREAM_MAX_12BPC:
+ return 12;
+ case DOWN_STREAM_MAX_16BPC:
+ return 16;
+ default:
+ break;
+ }
+
+ return -1;
+}
+
+uint8_t dp_parse_lttpr_repeater_count(uint8_t lttpr_repeater_count)
+{
+ switch (lttpr_repeater_count) {
+ case 0x80: // 1 lttpr repeater
+ return 1;
+ case 0x40: // 2 lttpr repeaters
+ return 2;
+ case 0x20: // 3 lttpr repeaters
+ return 3;
+ case 0x10: // 4 lttpr repeaters
+ return 4;
+ case 0x08: // 5 lttpr repeaters
+ return 5;
+ case 0x04: // 6 lttpr repeaters
+ return 6;
+ case 0x02: // 7 lttpr repeaters
+ return 7;
+ case 0x01: // 8 lttpr repeaters
+ return 8;
+ default:
+ break;
+ }
+ return 0; // invalid value
+}
+
+uint32_t dc_link_bw_kbps_from_raw_frl_link_rate_data(uint8_t bw)
+{
+ switch (bw) {
+ case 0b001:
+ return 9000000;
+ case 0b010:
+ return 18000000;
+ case 0b011:
+ return 24000000;
+ case 0b100:
+ return 32000000;
+ case 0b101:
+ return 40000000;
+ case 0b110:
+ return 48000000;
+ }
+
+ return 0;
+}
+
+static enum dc_link_rate linkRateInKHzToLinkRateMultiplier(uint32_t link_rate_in_khz)
+{
+ enum dc_link_rate link_rate;
+ // LinkRate is normally stored as a multiplier of 0.27 Gbps per lane. Do the translation.
+ switch (link_rate_in_khz) {
+ case 1620000:
+ link_rate = LINK_RATE_LOW; // Rate_1 (RBR) - 1.62 Gbps/Lane
+ break;
+ case 2160000:
+ link_rate = LINK_RATE_RATE_2; // Rate_2 - 2.16 Gbps/Lane
+ break;
+ case 2430000:
+ link_rate = LINK_RATE_RATE_3; // Rate_3 - 2.43 Gbps/Lane
+ break;
+ case 2700000:
+ link_rate = LINK_RATE_HIGH; // Rate_4 (HBR) - 2.70 Gbps/Lane
+ break;
+ case 3240000:
+ link_rate = LINK_RATE_RBR2; // Rate_5 (RBR2)- 3.24 Gbps/Lane
+ break;
+ case 4320000:
+ link_rate = LINK_RATE_RATE_6; // Rate_6 - 4.32 Gbps/Lane
+ break;
+ case 5400000:
+ link_rate = LINK_RATE_HIGH2; // Rate_7 (HBR2)- 5.40 Gbps/Lane
+ break;
+ case 8100000:
+ link_rate = LINK_RATE_HIGH3; // Rate_8 (HBR3)- 8.10 Gbps/Lane
+ break;
+ default:
+ link_rate = LINK_RATE_UNKNOWN;
+ break;
+ }
+ return link_rate;
+}
+
+static union dp_cable_id intersect_cable_id(
+ union dp_cable_id *a, union dp_cable_id *b)
+{
+ union dp_cable_id out;
+
+ out.bits.UHBR10_20_CAPABILITY = MIN(a->bits.UHBR10_20_CAPABILITY,
+ b->bits.UHBR10_20_CAPABILITY);
+ out.bits.UHBR13_5_CAPABILITY = MIN(a->bits.UHBR13_5_CAPABILITY,
+ b->bits.UHBR13_5_CAPABILITY);
+ out.bits.CABLE_TYPE = MAX(a->bits.CABLE_TYPE, b->bits.CABLE_TYPE);
+
+ return out;
+}
+
+/*
+ * Return PCON's post FRL link training supported BW if its non-zero, otherwise return max_supported_frl_bw.
+ */
+static uint32_t intersect_frl_link_bw_support(
+ const uint32_t max_supported_frl_bw_in_kbps,
+ const union hdmi_encoded_link_bw hdmi_encoded_link_bw)
+{
+ uint32_t supported_bw_in_kbps = max_supported_frl_bw_in_kbps;
+
+ // HDMI_ENCODED_LINK_BW bits are only valid if HDMI Link Configuration bit is 1 (FRL mode)
+ if (hdmi_encoded_link_bw.bits.FRL_MODE) {
+ if (hdmi_encoded_link_bw.bits.BW_48Gbps)
+ supported_bw_in_kbps = 48000000;
+ else if (hdmi_encoded_link_bw.bits.BW_40Gbps)
+ supported_bw_in_kbps = 40000000;
+ else if (hdmi_encoded_link_bw.bits.BW_32Gbps)
+ supported_bw_in_kbps = 32000000;
+ else if (hdmi_encoded_link_bw.bits.BW_24Gbps)
+ supported_bw_in_kbps = 24000000;
+ else if (hdmi_encoded_link_bw.bits.BW_18Gbps)
+ supported_bw_in_kbps = 18000000;
+ else if (hdmi_encoded_link_bw.bits.BW_9Gbps)
+ supported_bw_in_kbps = 9000000;
+ }
+
+ return supported_bw_in_kbps;
+}
+
+static enum clock_source_id get_clock_source_id(struct dc_link *link)
+{
+ enum clock_source_id dp_cs_id = CLOCK_SOURCE_ID_UNDEFINED;
+ struct clock_source *dp_cs = link->dc->res_pool->dp_clock_source;
+
+ if (dp_cs != NULL) {
+ dp_cs_id = dp_cs->id;
+ } else {
+ /*
+ * dp clock source is not initialized for some reason.
+ * Should not happen, CLOCK_SOURCE_ID_EXTERNAL will be used
+ */
+ ASSERT(dp_cs);
+ }
+
+ return dp_cs_id;
+}
+
+static void dp_wa_power_up_0010FA(struct dc_link *link, uint8_t *dpcd_data,
+ int length)
+{
+ int retry = 0;
+
+ if (!link->dpcd_caps.dpcd_rev.raw) {
+ do {
+ dc_link_dp_receiver_power_ctrl(link, true);
+ core_link_read_dpcd(link, DP_DPCD_REV,
+ dpcd_data, length);
+ link->dpcd_caps.dpcd_rev.raw = dpcd_data[
+ DP_DPCD_REV -
+ DP_DPCD_REV];
+ } while (retry++ < 4 && !link->dpcd_caps.dpcd_rev.raw);
+ }
+
+ if (link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_VGA_CONVERTER) {
+ switch (link->dpcd_caps.branch_dev_id) {
+ /* 0010FA active dongles (DP-VGA, DP-DLDVI converters) power down
+ * all internal circuits including AUX communication preventing
+ * reading DPCD table and EDID (spec violation).
+ * Encoder will skip DP RX power down on disable_output to
+ * keep receiver powered all the time.*/
+ case DP_BRANCH_DEVICE_ID_0010FA:
+ case DP_BRANCH_DEVICE_ID_0080E1:
+ case DP_BRANCH_DEVICE_ID_00E04C:
+ link->wa_flags.dp_keep_receiver_powered = true;
+ break;
+
+ /* TODO: May need work around for other dongles. */
+ default:
+ link->wa_flags.dp_keep_receiver_powered = false;
+ break;
+ }
+ } else
+ link->wa_flags.dp_keep_receiver_powered = false;
+}
+
+bool dc_link_is_fec_supported(const struct dc_link *link)
+{
+ /* TODO - use asic cap instead of link_enc->features
+ * we no longer know which link enc to use for this link before commit
+ */
+ struct link_encoder *link_enc = NULL;
+
+ link_enc = link_enc_cfg_get_link_enc(link);
+ ASSERT(link_enc);
+
+ return (dc_is_dp_signal(link->connector_signal) && link_enc &&
+ link_enc->features.fec_supported &&
+ link->dpcd_caps.fec_cap.bits.FEC_CAPABLE &&
+ !IS_FPGA_MAXIMUS_DC(link->ctx->dce_environment));
+}
+
+bool dc_link_should_enable_fec(const struct dc_link *link)
+{
+ bool force_disable = false;
+
+ if (link->fec_state == dc_link_fec_enabled)
+ force_disable = false;
+ else if (link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT_MST &&
+ link->local_sink &&
+ link->local_sink->edid_caps.panel_patch.disable_fec)
+ force_disable = true;
+ else if (link->connector_signal == SIGNAL_TYPE_EDP
+ && (link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.
+ dsc_support.DSC_SUPPORT == false
+ || link->panel_config.dsc.disable_dsc_edp
+ || !link->dc->caps.edp_dsc_support))
+ force_disable = true;
+
+ return !force_disable && dc_link_is_fec_supported(link);
+}
+
+bool link_is_dp_128b_132b_signal(struct pipe_ctx *pipe_ctx)
+{
+ /* If this assert is hit then we have a link encoder dynamic management issue */
+ ASSERT(pipe_ctx->stream_res.hpo_dp_stream_enc ? pipe_ctx->link_res.hpo_dp_link_enc != NULL : true);
+ return (pipe_ctx->stream_res.hpo_dp_stream_enc &&
+ pipe_ctx->link_res.hpo_dp_link_enc &&
+ dc_is_dp_signal(pipe_ctx->stream->signal));
+}
+
+bool dp_is_lttpr_present(struct dc_link *link)
+{
+ return (dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) != 0 &&
+ link->dpcd_caps.lttpr_caps.max_lane_count > 0 &&
+ link->dpcd_caps.lttpr_caps.max_lane_count <= 4 &&
+ link->dpcd_caps.lttpr_caps.revision.raw >= 0x14);
+}
+
+/* in DP compliance test, DPR-120 may have
+ * a random value in its MAX_LINK_BW dpcd field.
+ * We map it to the maximum supported link rate that
+ * is smaller than MAX_LINK_BW in this case.
+ */
+static enum dc_link_rate get_link_rate_from_max_link_bw(
+ uint8_t max_link_bw)
+{
+ enum dc_link_rate link_rate;
+
+ if (max_link_bw >= LINK_RATE_HIGH3) {
+ link_rate = LINK_RATE_HIGH3;
+ } else if (max_link_bw < LINK_RATE_HIGH3
+ && max_link_bw >= LINK_RATE_HIGH2) {
+ link_rate = LINK_RATE_HIGH2;
+ } else if (max_link_bw < LINK_RATE_HIGH2
+ && max_link_bw >= LINK_RATE_HIGH) {
+ link_rate = LINK_RATE_HIGH;
+ } else if (max_link_bw < LINK_RATE_HIGH
+ && max_link_bw >= LINK_RATE_LOW) {
+ link_rate = LINK_RATE_LOW;
+ } else {
+ link_rate = LINK_RATE_UNKNOWN;
+ }
+
+ return link_rate;
+}
+
+static enum dc_link_rate get_lttpr_max_link_rate(struct dc_link *link)
+{
+ enum dc_link_rate lttpr_max_link_rate = link->dpcd_caps.lttpr_caps.max_link_rate;
+
+ if (link->dpcd_caps.lttpr_caps.supported_128b_132b_rates.bits.UHBR20)
+ lttpr_max_link_rate = LINK_RATE_UHBR20;
+ else if (link->dpcd_caps.lttpr_caps.supported_128b_132b_rates.bits.UHBR13_5)
+ lttpr_max_link_rate = LINK_RATE_UHBR13_5;
+ else if (link->dpcd_caps.lttpr_caps.supported_128b_132b_rates.bits.UHBR10)
+ lttpr_max_link_rate = LINK_RATE_UHBR10;
+
+ return lttpr_max_link_rate;
+}
+
+static enum dc_link_rate get_cable_max_link_rate(struct dc_link *link)
+{
+ enum dc_link_rate cable_max_link_rate = LINK_RATE_UNKNOWN;
+
+ if (link->dpcd_caps.cable_id.bits.UHBR10_20_CAPABILITY & DP_UHBR20)
+ cable_max_link_rate = LINK_RATE_UHBR20;
+ else if (link->dpcd_caps.cable_id.bits.UHBR13_5_CAPABILITY)
+ cable_max_link_rate = LINK_RATE_UHBR13_5;
+ else if (link->dpcd_caps.cable_id.bits.UHBR10_20_CAPABILITY & DP_UHBR10)
+ cable_max_link_rate = LINK_RATE_UHBR10;
+
+ return cable_max_link_rate;
+}
+
+static inline bool reached_minimum_lane_count(enum dc_lane_count lane_count)
+{
+ return lane_count <= LANE_COUNT_ONE;
+}
+
+static inline bool reached_minimum_link_rate(enum dc_link_rate link_rate)
+{
+ return link_rate <= LINK_RATE_LOW;
+}
+
+static enum dc_lane_count reduce_lane_count(enum dc_lane_count lane_count)
+{
+ switch (lane_count) {
+ case LANE_COUNT_FOUR:
+ return LANE_COUNT_TWO;
+ case LANE_COUNT_TWO:
+ return LANE_COUNT_ONE;
+ case LANE_COUNT_ONE:
+ return LANE_COUNT_UNKNOWN;
+ default:
+ return LANE_COUNT_UNKNOWN;
+ }
+}
+
+static enum dc_link_rate reduce_link_rate(enum dc_link_rate link_rate)
+{
+ switch (link_rate) {
+ case LINK_RATE_UHBR20:
+ return LINK_RATE_UHBR13_5;
+ case LINK_RATE_UHBR13_5:
+ return LINK_RATE_UHBR10;
+ case LINK_RATE_UHBR10:
+ return LINK_RATE_HIGH3;
+ case LINK_RATE_HIGH3:
+ return LINK_RATE_HIGH2;
+ case LINK_RATE_HIGH2:
+ return LINK_RATE_HIGH;
+ case LINK_RATE_HIGH:
+ return LINK_RATE_LOW;
+ case LINK_RATE_LOW:
+ return LINK_RATE_UNKNOWN;
+ default:
+ return LINK_RATE_UNKNOWN;
+ }
+}
+
+static enum dc_lane_count increase_lane_count(enum dc_lane_count lane_count)
+{
+ switch (lane_count) {
+ case LANE_COUNT_ONE:
+ return LANE_COUNT_TWO;
+ case LANE_COUNT_TWO:
+ return LANE_COUNT_FOUR;
+ default:
+ return LANE_COUNT_UNKNOWN;
+ }
+}
+
+static enum dc_link_rate increase_link_rate(struct dc_link *link,
+ enum dc_link_rate link_rate)
+{
+ switch (link_rate) {
+ case LINK_RATE_LOW:
+ return LINK_RATE_HIGH;
+ case LINK_RATE_HIGH:
+ return LINK_RATE_HIGH2;
+ case LINK_RATE_HIGH2:
+ return LINK_RATE_HIGH3;
+ case LINK_RATE_HIGH3:
+ return LINK_RATE_UHBR10;
+ case LINK_RATE_UHBR10:
+ /* upto DP2.x specs UHBR13.5 is the only link rate that could be
+ * not supported by DPRX when higher link rate is supported.
+ * so we treat it as a special case for code simplicity. When we
+ * have new specs with more link rates like this, we should
+ * consider a more generic solution to handle discrete link
+ * rate capabilities.
+ */
+ return link->dpcd_caps.dp_128b_132b_supported_link_rates.bits.UHBR13_5 ?
+ LINK_RATE_UHBR13_5 : LINK_RATE_UHBR20;
+ case LINK_RATE_UHBR13_5:
+ return LINK_RATE_UHBR20;
+ default:
+ return LINK_RATE_UNKNOWN;
+ }
+}
+
+static bool decide_fallback_link_setting_max_bw_policy(
+ struct dc_link *link,
+ const struct dc_link_settings *max,
+ struct dc_link_settings *cur,
+ enum link_training_result training_result)
+{
+ uint8_t cur_idx = 0, next_idx;
+ bool found = false;
+
+ if (training_result == LINK_TRAINING_ABORT)
+ return false;
+
+ while (cur_idx < ARRAY_SIZE(dp_lt_fallbacks))
+ /* find current index */
+ if (dp_lt_fallbacks[cur_idx].lane_count == cur->lane_count &&
+ dp_lt_fallbacks[cur_idx].link_rate == cur->link_rate)
+ break;
+ else
+ cur_idx++;
+
+ next_idx = cur_idx + 1;
+
+ while (next_idx < ARRAY_SIZE(dp_lt_fallbacks))
+ /* find next index */
+ if (dp_lt_fallbacks[next_idx].lane_count > max->lane_count ||
+ dp_lt_fallbacks[next_idx].link_rate > max->link_rate)
+ next_idx++;
+ else if (dp_lt_fallbacks[next_idx].link_rate == LINK_RATE_UHBR13_5 &&
+ link->dpcd_caps.dp_128b_132b_supported_link_rates.bits.UHBR13_5 == 0)
+ /* upto DP2.x specs UHBR13.5 is the only link rate that
+ * could be not supported by DPRX when higher link rate
+ * is supported. so we treat it as a special case for
+ * code simplicity. When we have new specs with more
+ * link rates like this, we should consider a more
+ * generic solution to handle discrete link rate
+ * capabilities.
+ */
+ next_idx++;
+ else
+ break;
+
+ if (next_idx < ARRAY_SIZE(dp_lt_fallbacks)) {
+ cur->lane_count = dp_lt_fallbacks[next_idx].lane_count;
+ cur->link_rate = dp_lt_fallbacks[next_idx].link_rate;
+ found = true;
+ }
+
+ return found;
+}
+
+/*
+ * function: set link rate and lane count fallback based
+ * on current link setting and last link training result
+ * return value:
+ * true - link setting could be set
+ * false - has reached minimum setting
+ * and no further fallback could be done
+ */
+bool decide_fallback_link_setting(
+ struct dc_link *link,
+ struct dc_link_settings *max,
+ struct dc_link_settings *cur,
+ enum link_training_result training_result)
+{
+ if (link_dp_get_encoding_format(max) == DP_128b_132b_ENCODING ||
+ link->dc->debug.force_dp2_lt_fallback_method)
+ return decide_fallback_link_setting_max_bw_policy(link, max,
+ cur, training_result);
+
+ switch (training_result) {
+ case LINK_TRAINING_CR_FAIL_LANE0:
+ case LINK_TRAINING_CR_FAIL_LANE1:
+ case LINK_TRAINING_CR_FAIL_LANE23:
+ case LINK_TRAINING_LQA_FAIL:
+ {
+ if (!reached_minimum_link_rate(cur->link_rate)) {
+ cur->link_rate = reduce_link_rate(cur->link_rate);
+ } else if (!reached_minimum_lane_count(cur->lane_count)) {
+ cur->link_rate = max->link_rate;
+ if (training_result == LINK_TRAINING_CR_FAIL_LANE0)
+ return false;
+ else if (training_result == LINK_TRAINING_CR_FAIL_LANE1)
+ cur->lane_count = LANE_COUNT_ONE;
+ else if (training_result == LINK_TRAINING_CR_FAIL_LANE23)
+ cur->lane_count = LANE_COUNT_TWO;
+ else
+ cur->lane_count = reduce_lane_count(cur->lane_count);
+ } else {
+ return false;
+ }
+ break;
+ }
+ case LINK_TRAINING_EQ_FAIL_EQ:
+ case LINK_TRAINING_EQ_FAIL_CR_PARTIAL:
+ {
+ if (!reached_minimum_lane_count(cur->lane_count)) {
+ cur->lane_count = reduce_lane_count(cur->lane_count);
+ } else if (!reached_minimum_link_rate(cur->link_rate)) {
+ cur->link_rate = reduce_link_rate(cur->link_rate);
+ /* Reduce max link rate to avoid potential infinite loop.
+ * Needed so that any subsequent CR_FAIL fallback can't
+ * re-set the link rate higher than the link rate from
+ * the latest EQ_FAIL fallback.
+ */
+ max->link_rate = cur->link_rate;
+ cur->lane_count = max->lane_count;
+ } else {
+ return false;
+ }
+ break;
+ }
+ case LINK_TRAINING_EQ_FAIL_CR:
+ {
+ if (!reached_minimum_link_rate(cur->link_rate)) {
+ cur->link_rate = reduce_link_rate(cur->link_rate);
+ /* Reduce max link rate to avoid potential infinite loop.
+ * Needed so that any subsequent CR_FAIL fallback can't
+ * re-set the link rate higher than the link rate from
+ * the latest EQ_FAIL fallback.
+ */
+ max->link_rate = cur->link_rate;
+ cur->lane_count = max->lane_count;
+ } else {
+ return false;
+ }
+ break;
+ }
+ default:
+ return false;
+ }
+ return true;
+}
+static bool decide_dp_link_settings(struct dc_link *link, struct dc_link_settings *link_setting, uint32_t req_bw)
+{
+ struct dc_link_settings initial_link_setting = {
+ LANE_COUNT_ONE, LINK_RATE_LOW, LINK_SPREAD_DISABLED, false, 0};
+ struct dc_link_settings current_link_setting =
+ initial_link_setting;
+ uint32_t link_bw;
+
+ if (req_bw > dc_link_bandwidth_kbps(link, &link->verified_link_cap))
+ return false;
+
+ /* search for the minimum link setting that:
+ * 1. is supported according to the link training result
+ * 2. could support the b/w requested by the timing
+ */
+ while (current_link_setting.link_rate <=
+ link->verified_link_cap.link_rate) {
+ link_bw = dc_link_bandwidth_kbps(
+ link,
+ &current_link_setting);
+ if (req_bw <= link_bw) {
+ *link_setting = current_link_setting;
+ return true;
+ }
+
+ if (current_link_setting.lane_count <
+ link->verified_link_cap.lane_count) {
+ current_link_setting.lane_count =
+ increase_lane_count(
+ current_link_setting.lane_count);
+ } else {
+ current_link_setting.link_rate =
+ increase_link_rate(link,
+ current_link_setting.link_rate);
+ current_link_setting.lane_count =
+ initial_link_setting.lane_count;
+ }
+ }
+
+ return false;
+}
+
+bool dc_link_decide_edp_link_settings(struct dc_link *link, struct dc_link_settings *link_setting, uint32_t req_bw)
+{
+ struct dc_link_settings initial_link_setting;
+ struct dc_link_settings current_link_setting;
+ uint32_t link_bw;
+
+ /*
+ * edp_supported_link_rates_count is only valid for eDP v1.4 or higher.
+ * Per VESA eDP spec, "The DPCD revision for eDP v1.4 is 13h"
+ */
+ if (link->dpcd_caps.dpcd_rev.raw < DPCD_REV_13 ||
+ link->dpcd_caps.edp_supported_link_rates_count == 0) {
+ *link_setting = link->verified_link_cap;
+ return true;
+ }
+
+ memset(&initial_link_setting, 0, sizeof(initial_link_setting));
+ initial_link_setting.lane_count = LANE_COUNT_ONE;
+ initial_link_setting.link_rate = link->dpcd_caps.edp_supported_link_rates[0];
+ initial_link_setting.link_spread = LINK_SPREAD_DISABLED;
+ initial_link_setting.use_link_rate_set = true;
+ initial_link_setting.link_rate_set = 0;
+ current_link_setting = initial_link_setting;
+
+ /* search for the minimum link setting that:
+ * 1. is supported according to the link training result
+ * 2. could support the b/w requested by the timing
+ */
+ while (current_link_setting.link_rate <=
+ link->verified_link_cap.link_rate) {
+ link_bw = dc_link_bandwidth_kbps(
+ link,
+ &current_link_setting);
+ if (req_bw <= link_bw) {
+ *link_setting = current_link_setting;
+ return true;
+ }
+
+ if (current_link_setting.lane_count <
+ link->verified_link_cap.lane_count) {
+ current_link_setting.lane_count =
+ increase_lane_count(
+ current_link_setting.lane_count);
+ } else {
+ if (current_link_setting.link_rate_set < link->dpcd_caps.edp_supported_link_rates_count) {
+ current_link_setting.link_rate_set++;
+ current_link_setting.link_rate =
+ link->dpcd_caps.edp_supported_link_rates[current_link_setting.link_rate_set];
+ current_link_setting.lane_count =
+ initial_link_setting.lane_count;
+ } else
+ break;
+ }
+ }
+ return false;
+}
+
+bool decide_edp_link_settings_with_dsc(struct dc_link *link,
+ struct dc_link_settings *link_setting,
+ uint32_t req_bw,
+ enum dc_link_rate max_link_rate)
+{
+ struct dc_link_settings initial_link_setting;
+ struct dc_link_settings current_link_setting;
+ uint32_t link_bw;
+
+ unsigned int policy = 0;
+
+ policy = link->panel_config.dsc.force_dsc_edp_policy;
+ if (max_link_rate == LINK_RATE_UNKNOWN)
+ max_link_rate = link->verified_link_cap.link_rate;
+ /*
+ * edp_supported_link_rates_count is only valid for eDP v1.4 or higher.
+ * Per VESA eDP spec, "The DPCD revision for eDP v1.4 is 13h"
+ */
+ if ((link->dpcd_caps.dpcd_rev.raw < DPCD_REV_13 ||
+ link->dpcd_caps.edp_supported_link_rates_count == 0)) {
+ /* for DSC enabled case, we search for minimum lane count */
+ memset(&initial_link_setting, 0, sizeof(initial_link_setting));
+ initial_link_setting.lane_count = LANE_COUNT_ONE;
+ initial_link_setting.link_rate = LINK_RATE_LOW;
+ initial_link_setting.link_spread = LINK_SPREAD_DISABLED;
+ initial_link_setting.use_link_rate_set = false;
+ initial_link_setting.link_rate_set = 0;
+ current_link_setting = initial_link_setting;
+ if (req_bw > dc_link_bandwidth_kbps(link, &link->verified_link_cap))
+ return false;
+
+ /* search for the minimum link setting that:
+ * 1. is supported according to the link training result
+ * 2. could support the b/w requested by the timing
+ */
+ while (current_link_setting.link_rate <=
+ max_link_rate) {
+ link_bw = dc_link_bandwidth_kbps(
+ link,
+ &current_link_setting);
+ if (req_bw <= link_bw) {
+ *link_setting = current_link_setting;
+ return true;
+ }
+ if (policy) {
+ /* minimize lane */
+ if (current_link_setting.link_rate < max_link_rate) {
+ current_link_setting.link_rate =
+ increase_link_rate(link,
+ current_link_setting.link_rate);
+ } else {
+ if (current_link_setting.lane_count <
+ link->verified_link_cap.lane_count) {
+ current_link_setting.lane_count =
+ increase_lane_count(
+ current_link_setting.lane_count);
+ current_link_setting.link_rate = initial_link_setting.link_rate;
+ } else
+ break;
+ }
+ } else {
+ /* minimize link rate */
+ if (current_link_setting.lane_count <
+ link->verified_link_cap.lane_count) {
+ current_link_setting.lane_count =
+ increase_lane_count(
+ current_link_setting.lane_count);
+ } else {
+ current_link_setting.link_rate =
+ increase_link_rate(link,
+ current_link_setting.link_rate);
+ current_link_setting.lane_count =
+ initial_link_setting.lane_count;
+ }
+ }
+ }
+ return false;
+ }
+
+ /* if optimize edp link is supported */
+ memset(&initial_link_setting, 0, sizeof(initial_link_setting));
+ initial_link_setting.lane_count = LANE_COUNT_ONE;
+ initial_link_setting.link_rate = link->dpcd_caps.edp_supported_link_rates[0];
+ initial_link_setting.link_spread = LINK_SPREAD_DISABLED;
+ initial_link_setting.use_link_rate_set = true;
+ initial_link_setting.link_rate_set = 0;
+ current_link_setting = initial_link_setting;
+
+ /* search for the minimum link setting that:
+ * 1. is supported according to the link training result
+ * 2. could support the b/w requested by the timing
+ */
+ while (current_link_setting.link_rate <=
+ max_link_rate) {
+ link_bw = dc_link_bandwidth_kbps(
+ link,
+ &current_link_setting);
+ if (req_bw <= link_bw) {
+ *link_setting = current_link_setting;
+ return true;
+ }
+ if (policy) {
+ /* minimize lane */
+ if (current_link_setting.link_rate_set <
+ link->dpcd_caps.edp_supported_link_rates_count
+ && current_link_setting.link_rate < max_link_rate) {
+ current_link_setting.link_rate_set++;
+ current_link_setting.link_rate =
+ link->dpcd_caps.edp_supported_link_rates[current_link_setting.link_rate_set];
+ } else {
+ if (current_link_setting.lane_count < link->verified_link_cap.lane_count) {
+ current_link_setting.lane_count =
+ increase_lane_count(
+ current_link_setting.lane_count);
+ current_link_setting.link_rate_set = initial_link_setting.link_rate_set;
+ current_link_setting.link_rate =
+ link->dpcd_caps.edp_supported_link_rates[current_link_setting.link_rate_set];
+ } else
+ break;
+ }
+ } else {
+ /* minimize link rate */
+ if (current_link_setting.lane_count <
+ link->verified_link_cap.lane_count) {
+ current_link_setting.lane_count =
+ increase_lane_count(
+ current_link_setting.lane_count);
+ } else {
+ if (current_link_setting.link_rate_set < link->dpcd_caps.edp_supported_link_rates_count) {
+ current_link_setting.link_rate_set++;
+ current_link_setting.link_rate =
+ link->dpcd_caps.edp_supported_link_rates[current_link_setting.link_rate_set];
+ current_link_setting.lane_count =
+ initial_link_setting.lane_count;
+ } else
+ break;
+ }
+ }
+ }
+ return false;
+}
+
+static bool decide_mst_link_settings(const struct dc_link *link, struct dc_link_settings *link_setting)
+{
+ *link_setting = link->verified_link_cap;
+ return true;
+}
+
+bool link_decide_link_settings(struct dc_stream_state *stream,
+ struct dc_link_settings *link_setting)
+{
+ struct dc_link *link = stream->link;
+ uint32_t req_bw = dc_bandwidth_in_kbps_from_timing(&stream->timing);
+
+ memset(link_setting, 0, sizeof(*link_setting));
+
+ /* if preferred is specified through AMDDP, use it, if it's enough
+ * to drive the mode
+ */
+ if (link->preferred_link_setting.lane_count !=
+ LANE_COUNT_UNKNOWN &&
+ link->preferred_link_setting.link_rate !=
+ LINK_RATE_UNKNOWN) {
+ *link_setting = link->preferred_link_setting;
+ return true;
+ }
+
+ /* MST doesn't perform link training for now
+ * TODO: add MST specific link training routine
+ */
+ if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
+ decide_mst_link_settings(link, link_setting);
+ } else if (link->connector_signal == SIGNAL_TYPE_EDP) {
+ /* enable edp link optimization for DSC eDP case */
+ if (stream->timing.flags.DSC) {
+ enum dc_link_rate max_link_rate = LINK_RATE_UNKNOWN;
+
+ if (link->panel_config.dsc.force_dsc_edp_policy) {
+ /* calculate link max link rate cap*/
+ struct dc_link_settings tmp_link_setting;
+ struct dc_crtc_timing tmp_timing = stream->timing;
+ uint32_t orig_req_bw;
+
+ tmp_link_setting.link_rate = LINK_RATE_UNKNOWN;
+ tmp_timing.flags.DSC = 0;
+ orig_req_bw = dc_bandwidth_in_kbps_from_timing(&tmp_timing);
+ dc_link_decide_edp_link_settings(link, &tmp_link_setting, orig_req_bw);
+ max_link_rate = tmp_link_setting.link_rate;
+ }
+ decide_edp_link_settings_with_dsc(link, link_setting, req_bw, max_link_rate);
+ } else {
+ dc_link_decide_edp_link_settings(link, link_setting, req_bw);
+ }
+ } else {
+ decide_dp_link_settings(link, link_setting, req_bw);
+ }
+
+ return link_setting->lane_count != LANE_COUNT_UNKNOWN &&
+ link_setting->link_rate != LINK_RATE_UNKNOWN;
+}
+
+enum dp_link_encoding link_dp_get_encoding_format(const struct dc_link_settings *link_settings)
+{
+ if ((link_settings->link_rate >= LINK_RATE_LOW) &&
+ (link_settings->link_rate <= LINK_RATE_HIGH3))
+ return DP_8b_10b_ENCODING;
+ else if ((link_settings->link_rate >= LINK_RATE_UHBR10) &&
+ (link_settings->link_rate <= LINK_RATE_UHBR20))
+ return DP_128b_132b_ENCODING;
+ return DP_UNKNOWN_ENCODING;
+}
+
+enum dp_link_encoding dc_link_dp_mst_decide_link_encoding_format(const struct dc_link *link)
+{
+ struct dc_link_settings link_settings = {0};
+
+ if (!dc_is_dp_signal(link->connector_signal))
+ return DP_UNKNOWN_ENCODING;
+
+ if (link->preferred_link_setting.lane_count !=
+ LANE_COUNT_UNKNOWN &&
+ link->preferred_link_setting.link_rate !=
+ LINK_RATE_UNKNOWN) {
+ link_settings = link->preferred_link_setting;
+ } else {
+ decide_mst_link_settings(link, &link_settings);
+ }
+
+ return link_dp_get_encoding_format(&link_settings);
+}
+
+static void read_dp_device_vendor_id(struct dc_link *link)
+{
+ struct dp_device_vendor_id dp_id;
+
+ /* read IEEE branch device id */
+ core_link_read_dpcd(
+ link,
+ DP_BRANCH_OUI,
+ (uint8_t *)&dp_id,
+ sizeof(dp_id));
+
+ link->dpcd_caps.branch_dev_id =
+ (dp_id.ieee_oui[0] << 16) +
+ (dp_id.ieee_oui[1] << 8) +
+ dp_id.ieee_oui[2];
+
+ memmove(
+ link->dpcd_caps.branch_dev_name,
+ dp_id.ieee_device_id,
+ sizeof(dp_id.ieee_device_id));
+}
+
+static enum dc_status wake_up_aux_channel(struct dc_link *link)
+{
+ enum dc_status status = DC_ERROR_UNEXPECTED;
+ uint32_t aux_channel_retry_cnt = 0;
+ uint8_t dpcd_power_state = '\0';
+
+ while (status != DC_OK && aux_channel_retry_cnt < 10) {
+ status = core_link_read_dpcd(link, DP_SET_POWER,
+ &dpcd_power_state, sizeof(dpcd_power_state));
+
+ /* Delay 1 ms if AUX CH is in power down state. Based on spec
+ * section 2.3.1.2, if AUX CH may be powered down due to
+ * write to DPCD 600h = 2. Sink AUX CH is monitoring differential
+ * signal and may need up to 1 ms before being able to reply.
+ */
+ if (status != DC_OK || dpcd_power_state == DP_SET_POWER_D3) {
+ udelay(1000);
+ aux_channel_retry_cnt++;
+ }
+ }
+
+ if (status != DC_OK) {
+ dpcd_power_state = DP_SET_POWER_D0;
+ status = core_link_write_dpcd(
+ link,
+ DP_SET_POWER,
+ &dpcd_power_state,
+ sizeof(dpcd_power_state));
+
+ dpcd_power_state = DP_SET_POWER_D3;
+ status = core_link_write_dpcd(
+ link,
+ DP_SET_POWER,
+ &dpcd_power_state,
+ sizeof(dpcd_power_state));
+ return DC_ERROR_UNEXPECTED;
+ }
+
+ return DC_OK;
+}
+
+static void get_active_converter_info(
+ uint8_t data, struct dc_link *link)
+{
+ union dp_downstream_port_present ds_port = { .byte = data };
+ memset(&link->dpcd_caps.dongle_caps, 0, sizeof(link->dpcd_caps.dongle_caps));
+
+ /* decode converter info*/
+ if (!ds_port.fields.PORT_PRESENT) {
+ link->dpcd_caps.dongle_type = DISPLAY_DONGLE_NONE;
+ set_dongle_type(link->ddc,
+ link->dpcd_caps.dongle_type);
+ link->dpcd_caps.is_branch_dev = false;
+ return;
+ }
+
+ /* DPCD 0x5 bit 0 = 1, it indicate it's branch device */
+ link->dpcd_caps.is_branch_dev = ds_port.fields.PORT_PRESENT;
+
+ switch (ds_port.fields.PORT_TYPE) {
+ case DOWNSTREAM_VGA:
+ link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_VGA_CONVERTER;
+ break;
+ case DOWNSTREAM_DVI_HDMI_DP_PLUS_PLUS:
+ /* At this point we don't know is it DVI or HDMI or DP++,
+ * assume DVI.*/
+ link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_DVI_CONVERTER;
+ break;
+ default:
+ link->dpcd_caps.dongle_type = DISPLAY_DONGLE_NONE;
+ break;
+ }
+
+ if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_11) {
+ uint8_t det_caps[16]; /* CTS 4.2.2.7 expects source to read Detailed Capabilities Info : 00080h-0008F.*/
+ union dwnstream_port_caps_byte0 *port_caps =
+ (union dwnstream_port_caps_byte0 *)det_caps;
+ if (core_link_read_dpcd(link, DP_DOWNSTREAM_PORT_0,
+ det_caps, sizeof(det_caps)) == DC_OK) {
+
+ switch (port_caps->bits.DWN_STRM_PORTX_TYPE) {
+ /*Handle DP case as DONGLE_NONE*/
+ case DOWN_STREAM_DETAILED_DP:
+ link->dpcd_caps.dongle_type = DISPLAY_DONGLE_NONE;
+ break;
+ case DOWN_STREAM_DETAILED_VGA:
+ link->dpcd_caps.dongle_type =
+ DISPLAY_DONGLE_DP_VGA_CONVERTER;
+ break;
+ case DOWN_STREAM_DETAILED_DVI:
+ link->dpcd_caps.dongle_type =
+ DISPLAY_DONGLE_DP_DVI_CONVERTER;
+ break;
+ case DOWN_STREAM_DETAILED_HDMI:
+ case DOWN_STREAM_DETAILED_DP_PLUS_PLUS:
+ /*Handle DP++ active converter case, process DP++ case as HDMI case according DP1.4 spec*/
+ link->dpcd_caps.dongle_type =
+ DISPLAY_DONGLE_DP_HDMI_CONVERTER;
+
+ link->dpcd_caps.dongle_caps.dongle_type = link->dpcd_caps.dongle_type;
+ if (ds_port.fields.DETAILED_CAPS) {
+
+ union dwnstream_port_caps_byte3_hdmi
+ hdmi_caps = {.raw = det_caps[3] };
+ union dwnstream_port_caps_byte2
+ hdmi_color_caps = {.raw = det_caps[2] };
+ link->dpcd_caps.dongle_caps.dp_hdmi_max_pixel_clk_in_khz =
+ det_caps[1] * 2500;
+
+ link->dpcd_caps.dongle_caps.is_dp_hdmi_s3d_converter =
+ hdmi_caps.bits.FRAME_SEQ_TO_FRAME_PACK;
+ /*YCBCR capability only for HDMI case*/
+ if (port_caps->bits.DWN_STRM_PORTX_TYPE
+ == DOWN_STREAM_DETAILED_HDMI) {
+ link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr422_pass_through =
+ hdmi_caps.bits.YCrCr422_PASS_THROUGH;
+ link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr420_pass_through =
+ hdmi_caps.bits.YCrCr420_PASS_THROUGH;
+ link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr422_converter =
+ hdmi_caps.bits.YCrCr422_CONVERSION;
+ link->dpcd_caps.dongle_caps.is_dp_hdmi_ycbcr420_converter =
+ hdmi_caps.bits.YCrCr420_CONVERSION;
+ }
+
+ link->dpcd_caps.dongle_caps.dp_hdmi_max_bpc =
+ translate_dpcd_max_bpc(
+ hdmi_color_caps.bits.MAX_BITS_PER_COLOR_COMPONENT);
+
+ if (link->dc->caps.dp_hdmi21_pcon_support) {
+ union hdmi_encoded_link_bw hdmi_encoded_link_bw;
+
+ link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps =
+ dc_link_bw_kbps_from_raw_frl_link_rate_data(
+ hdmi_color_caps.bits.MAX_ENCODED_LINK_BW_SUPPORT);
+
+ // Intersect reported max link bw support with the supported link rate post FRL link training
+ if (core_link_read_dpcd(link, DP_PCON_HDMI_POST_FRL_STATUS,
+ &hdmi_encoded_link_bw.raw, sizeof(hdmi_encoded_link_bw)) == DC_OK) {
+ link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps = intersect_frl_link_bw_support(
+ link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps,
+ hdmi_encoded_link_bw);
+ }
+
+ if (link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps > 0)
+ link->dpcd_caps.dongle_caps.extendedCapValid = true;
+ }
+
+ if (link->dpcd_caps.dongle_caps.dp_hdmi_max_pixel_clk_in_khz != 0)
+ link->dpcd_caps.dongle_caps.extendedCapValid = true;
+ }
+
+ break;
+ }
+ }
+ }
+
+ set_dongle_type(link->ddc, link->dpcd_caps.dongle_type);
+
+ {
+ struct dp_sink_hw_fw_revision dp_hw_fw_revision;
+
+ core_link_read_dpcd(
+ link,
+ DP_BRANCH_REVISION_START,
+ (uint8_t *)&dp_hw_fw_revision,
+ sizeof(dp_hw_fw_revision));
+
+ link->dpcd_caps.branch_hw_revision =
+ dp_hw_fw_revision.ieee_hw_rev;
+
+ memmove(
+ link->dpcd_caps.branch_fw_revision,
+ dp_hw_fw_revision.ieee_fw_rev,
+ sizeof(dp_hw_fw_revision.ieee_fw_rev));
+ }
+ if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_14 &&
+ link->dpcd_caps.dongle_type != DISPLAY_DONGLE_NONE) {
+ union dp_dfp_cap_ext dfp_cap_ext;
+ memset(&dfp_cap_ext, '\0', sizeof (dfp_cap_ext));
+ core_link_read_dpcd(
+ link,
+ DP_DFP_CAPABILITY_EXTENSION_SUPPORT,
+ dfp_cap_ext.raw,
+ sizeof(dfp_cap_ext.raw));
+ link->dpcd_caps.dongle_caps.dfp_cap_ext.supported = dfp_cap_ext.fields.supported;
+ link->dpcd_caps.dongle_caps.dfp_cap_ext.max_pixel_rate_in_mps =
+ dfp_cap_ext.fields.max_pixel_rate_in_mps[0] +
+ (dfp_cap_ext.fields.max_pixel_rate_in_mps[1] << 8);
+ link->dpcd_caps.dongle_caps.dfp_cap_ext.max_video_h_active_width =
+ dfp_cap_ext.fields.max_video_h_active_width[0] +
+ (dfp_cap_ext.fields.max_video_h_active_width[1] << 8);
+ link->dpcd_caps.dongle_caps.dfp_cap_ext.max_video_v_active_height =
+ dfp_cap_ext.fields.max_video_v_active_height[0] +
+ (dfp_cap_ext.fields.max_video_v_active_height[1] << 8);
+ link->dpcd_caps.dongle_caps.dfp_cap_ext.encoding_format_caps =
+ dfp_cap_ext.fields.encoding_format_caps;
+ link->dpcd_caps.dongle_caps.dfp_cap_ext.rgb_color_depth_caps =
+ dfp_cap_ext.fields.rgb_color_depth_caps;
+ link->dpcd_caps.dongle_caps.dfp_cap_ext.ycbcr444_color_depth_caps =
+ dfp_cap_ext.fields.ycbcr444_color_depth_caps;
+ link->dpcd_caps.dongle_caps.dfp_cap_ext.ycbcr422_color_depth_caps =
+ dfp_cap_ext.fields.ycbcr422_color_depth_caps;
+ link->dpcd_caps.dongle_caps.dfp_cap_ext.ycbcr420_color_depth_caps =
+ dfp_cap_ext.fields.ycbcr420_color_depth_caps;
+ DC_LOG_DP2("DFP capability extension is read at link %d", link->link_index);
+ DC_LOG_DP2("\tdfp_cap_ext.supported = %s", link->dpcd_caps.dongle_caps.dfp_cap_ext.supported ? "true" : "false");
+ DC_LOG_DP2("\tdfp_cap_ext.max_pixel_rate_in_mps = %d", link->dpcd_caps.dongle_caps.dfp_cap_ext.max_pixel_rate_in_mps);
+ DC_LOG_DP2("\tdfp_cap_ext.max_video_h_active_width = %d", link->dpcd_caps.dongle_caps.dfp_cap_ext.max_video_h_active_width);
+ DC_LOG_DP2("\tdfp_cap_ext.max_video_v_active_height = %d", link->dpcd_caps.dongle_caps.dfp_cap_ext.max_video_v_active_height);
+ }
+}
+
+static void apply_usbc_combo_phy_reset_wa(struct dc_link *link,
+ struct dc_link_settings *link_settings)
+{
+ /* Temporary Renoir-specific workaround PHY will sometimes be in bad
+ * state on hotplugging display from certain USB-C dongle, so add extra
+ * cycle of enabling and disabling the PHY before first link training.
+ */
+ struct link_resource link_res = {0};
+ enum clock_source_id dp_cs_id = get_clock_source_id(link);
+
+ dp_enable_link_phy(link, &link_res, link->connector_signal,
+ dp_cs_id, link_settings);
+ dp_disable_link_phy(link, &link_res, link->connector_signal);
+}
+
+static bool dp_overwrite_extended_receiver_cap(struct dc_link *link)
+{
+ uint8_t dpcd_data[16];
+ uint32_t read_dpcd_retry_cnt = 3;
+ enum dc_status status = DC_ERROR_UNEXPECTED;
+ union dp_downstream_port_present ds_port = { 0 };
+ union down_stream_port_count down_strm_port_count;
+ union edp_configuration_cap edp_config_cap;
+
+ int i;
+
+ for (i = 0; i < read_dpcd_retry_cnt; i++) {
+ status = core_link_read_dpcd(
+ link,
+ DP_DPCD_REV,
+ dpcd_data,
+ sizeof(dpcd_data));
+ if (status == DC_OK)
+ break;
+ }
+
+ link->dpcd_caps.dpcd_rev.raw =
+ dpcd_data[DP_DPCD_REV - DP_DPCD_REV];
+
+ if (dpcd_data[DP_MAX_LANE_COUNT - DP_DPCD_REV] == 0)
+ return false;
+
+ ds_port.byte = dpcd_data[DP_DOWNSTREAMPORT_PRESENT -
+ DP_DPCD_REV];
+
+ get_active_converter_info(ds_port.byte, link);
+
+ down_strm_port_count.raw = dpcd_data[DP_DOWN_STREAM_PORT_COUNT -
+ DP_DPCD_REV];
+
+ link->dpcd_caps.allow_invalid_MSA_timing_param =
+ down_strm_port_count.bits.IGNORE_MSA_TIMING_PARAM;
+
+ link->dpcd_caps.max_ln_count.raw = dpcd_data[
+ DP_MAX_LANE_COUNT - DP_DPCD_REV];
+
+ link->dpcd_caps.max_down_spread.raw = dpcd_data[
+ DP_MAX_DOWNSPREAD - DP_DPCD_REV];
+
+ link->reported_link_cap.lane_count =
+ link->dpcd_caps.max_ln_count.bits.MAX_LANE_COUNT;
+ link->reported_link_cap.link_rate = dpcd_data[
+ DP_MAX_LINK_RATE - DP_DPCD_REV];
+ link->reported_link_cap.link_spread =
+ link->dpcd_caps.max_down_spread.bits.MAX_DOWN_SPREAD ?
+ LINK_SPREAD_05_DOWNSPREAD_30KHZ : LINK_SPREAD_DISABLED;
+
+ edp_config_cap.raw = dpcd_data[
+ DP_EDP_CONFIGURATION_CAP - DP_DPCD_REV];
+ link->dpcd_caps.panel_mode_edp =
+ edp_config_cap.bits.ALT_SCRAMBLER_RESET;
+ link->dpcd_caps.dpcd_display_control_capable =
+ edp_config_cap.bits.DPCD_DISPLAY_CONTROL_CAPABLE;
+
+ return true;
+}
+
+void dc_link_overwrite_extended_receiver_cap(
+ struct dc_link *link)
+{
+ dp_overwrite_extended_receiver_cap(link);
+}
+
+void dpcd_set_source_specific_data(struct dc_link *link)
+{
+ if (!link->dc->vendor_signature.is_valid) {
+ enum dc_status result_write_min_hblank = DC_NOT_SUPPORTED;
+ struct dpcd_amd_signature amd_signature = {0};
+ struct dpcd_amd_device_id amd_device_id = {0};
+
+ amd_device_id.device_id_byte1 =
+ (uint8_t)(link->ctx->asic_id.chip_id);
+ amd_device_id.device_id_byte2 =
+ (uint8_t)(link->ctx->asic_id.chip_id >> 8);
+ amd_device_id.dce_version =
+ (uint8_t)(link->ctx->dce_version);
+ amd_device_id.dal_version_byte1 = 0x0; // needed? where to get?
+ amd_device_id.dal_version_byte2 = 0x0; // needed? where to get?
+
+ core_link_read_dpcd(link, DP_SOURCE_OUI,
+ (uint8_t *)(&amd_signature),
+ sizeof(amd_signature));
+
+ if (!((amd_signature.AMD_IEEE_TxSignature_byte1 == 0x0) &&
+ (amd_signature.AMD_IEEE_TxSignature_byte2 == 0x0) &&
+ (amd_signature.AMD_IEEE_TxSignature_byte3 == 0x1A))) {
+
+ amd_signature.AMD_IEEE_TxSignature_byte1 = 0x0;
+ amd_signature.AMD_IEEE_TxSignature_byte2 = 0x0;
+ amd_signature.AMD_IEEE_TxSignature_byte3 = 0x1A;
+
+ core_link_write_dpcd(link, DP_SOURCE_OUI,
+ (uint8_t *)(&amd_signature),
+ sizeof(amd_signature));
+ }
+
+ core_link_write_dpcd(link, DP_SOURCE_OUI+0x03,
+ (uint8_t *)(&amd_device_id),
+ sizeof(amd_device_id));
+
+ if (link->ctx->dce_version >= DCN_VERSION_2_0 &&
+ link->dc->caps.min_horizontal_blanking_period != 0) {
+
+ uint8_t hblank_size = (uint8_t)link->dc->caps.min_horizontal_blanking_period;
+
+ result_write_min_hblank = core_link_write_dpcd(link,
+ DP_SOURCE_MINIMUM_HBLANK_SUPPORTED, (uint8_t *)(&hblank_size),
+ sizeof(hblank_size));
+ }
+ DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION,
+ WPP_BIT_FLAG_DC_DETECTION_DP_CAPS,
+ "result=%u link_index=%u enum dce_version=%d DPCD=0x%04X min_hblank=%u branch_dev_id=0x%x branch_dev_name='%c%c%c%c%c%c'",
+ result_write_min_hblank,
+ link->link_index,
+ link->ctx->dce_version,
+ DP_SOURCE_MINIMUM_HBLANK_SUPPORTED,
+ link->dc->caps.min_horizontal_blanking_period,
+ link->dpcd_caps.branch_dev_id,
+ link->dpcd_caps.branch_dev_name[0],
+ link->dpcd_caps.branch_dev_name[1],
+ link->dpcd_caps.branch_dev_name[2],
+ link->dpcd_caps.branch_dev_name[3],
+ link->dpcd_caps.branch_dev_name[4],
+ link->dpcd_caps.branch_dev_name[5]);
+ } else {
+ core_link_write_dpcd(link, DP_SOURCE_OUI,
+ link->dc->vendor_signature.data.raw,
+ sizeof(link->dc->vendor_signature.data.raw));
+ }
+}
+
+void dpcd_write_cable_id_to_dprx(struct dc_link *link)
+{
+ if (!link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED ||
+ link->dpcd_caps.cable_id.raw == 0 ||
+ link->dprx_states.cable_id_written)
+ return;
+
+ core_link_write_dpcd(link, DP_CABLE_ATTRIBUTES_UPDATED_BY_DPTX,
+ &link->dpcd_caps.cable_id.raw,
+ sizeof(link->dpcd_caps.cable_id.raw));
+
+ link->dprx_states.cable_id_written = 1;
+}
+
+static bool get_usbc_cable_id(struct dc_link *link, union dp_cable_id *cable_id)
+{
+ union dmub_rb_cmd cmd;
+
+ if (!link->ctx->dmub_srv ||
+ link->ep_type != DISPLAY_ENDPOINT_PHY ||
+ link->link_enc->features.flags.bits.DP_IS_USB_C == 0)
+ return false;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.cable_id.header.type = DMUB_CMD_GET_USBC_CABLE_ID;
+ cmd.cable_id.header.payload_bytes = sizeof(cmd.cable_id.data);
+ cmd.cable_id.data.input.phy_inst = resource_transmitter_to_phy_idx(
+ link->dc, link->link_enc->transmitter);
+ if (dc_dmub_srv_cmd_with_reply_data(link->ctx->dmub_srv, &cmd) &&
+ cmd.cable_id.header.ret_status == 1) {
+ cable_id->raw = cmd.cable_id.data.output_raw;
+ DC_LOG_DC("usbc_cable_id = %d.\n", cable_id->raw);
+ }
+ return cmd.cable_id.header.ret_status == 1;
+}
+
+static void retrieve_cable_id(struct dc_link *link)
+{
+ union dp_cable_id usbc_cable_id;
+
+ link->dpcd_caps.cable_id.raw = 0;
+ core_link_read_dpcd(link, DP_CABLE_ATTRIBUTES_UPDATED_BY_DPRX,
+ &link->dpcd_caps.cable_id.raw, sizeof(uint8_t));
+
+ if (get_usbc_cable_id(link, &usbc_cable_id))
+ link->dpcd_caps.cable_id = intersect_cable_id(
+ &link->dpcd_caps.cable_id, &usbc_cable_id);
+}
+
+bool read_is_mst_supported(struct dc_link *link)
+{
+ bool mst = false;
+ enum dc_status st = DC_OK;
+ union dpcd_rev rev;
+ union mstm_cap cap;
+
+ if (link->preferred_training_settings.mst_enable &&
+ *link->preferred_training_settings.mst_enable == false) {
+ return false;
+ }
+
+ rev.raw = 0;
+ cap.raw = 0;
+
+ st = core_link_read_dpcd(link, DP_DPCD_REV, &rev.raw,
+ sizeof(rev));
+
+ if (st == DC_OK && rev.raw >= DPCD_REV_12) {
+
+ st = core_link_read_dpcd(link, DP_MSTM_CAP,
+ &cap.raw, sizeof(cap));
+ if (st == DC_OK && cap.bits.MST_CAP == 1)
+ mst = true;
+ }
+ return mst;
+
+}
+
+/* Read additional sink caps defined in source specific DPCD area
+ * This function currently only reads from SinkCapability address (DP_SOURCE_SINK_CAP)
+ * TODO: Add FS caps and read from DP_SOURCE_SINK_FS_CAP as well
+ */
+static bool dpcd_read_sink_ext_caps(struct dc_link *link)
+{
+ uint8_t dpcd_data;
+
+ if (!link)
+ return false;
+
+ if (core_link_read_dpcd(link, DP_SOURCE_SINK_CAP, &dpcd_data, 1) != DC_OK)
+ return false;
+
+ link->dpcd_sink_ext_caps.raw = dpcd_data;
+ return true;
+}
+
+enum dc_status dp_retrieve_lttpr_cap(struct dc_link *link)
+{
+ uint8_t lttpr_dpcd_data[8];
+ enum dc_status status;
+ bool is_lttpr_present;
+
+ /* Logic to determine LTTPR support*/
+ bool vbios_lttpr_interop = link->dc->caps.vbios_lttpr_aware;
+
+ if (!vbios_lttpr_interop || !link->dc->caps.extended_aux_timeout_support)
+ return DC_NOT_SUPPORTED;
+
+ /* By reading LTTPR capability, RX assumes that we will enable
+ * LTTPR extended aux timeout if LTTPR is present.
+ */
+ status = core_link_read_dpcd(
+ link,
+ DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV,
+ lttpr_dpcd_data,
+ sizeof(lttpr_dpcd_data));
+
+ link->dpcd_caps.lttpr_caps.revision.raw =
+ lttpr_dpcd_data[DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV -
+ DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
+
+ link->dpcd_caps.lttpr_caps.max_link_rate =
+ lttpr_dpcd_data[DP_MAX_LINK_RATE_PHY_REPEATER -
+ DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
+
+ link->dpcd_caps.lttpr_caps.phy_repeater_cnt =
+ lttpr_dpcd_data[DP_PHY_REPEATER_CNT -
+ DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
+
+ link->dpcd_caps.lttpr_caps.max_lane_count =
+ lttpr_dpcd_data[DP_MAX_LANE_COUNT_PHY_REPEATER -
+ DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
+
+ link->dpcd_caps.lttpr_caps.mode =
+ lttpr_dpcd_data[DP_PHY_REPEATER_MODE -
+ DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
+
+ link->dpcd_caps.lttpr_caps.max_ext_timeout =
+ lttpr_dpcd_data[DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT -
+ DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
+ link->dpcd_caps.lttpr_caps.main_link_channel_coding.raw =
+ lttpr_dpcd_data[DP_MAIN_LINK_CHANNEL_CODING_PHY_REPEATER -
+ DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
+
+ link->dpcd_caps.lttpr_caps.supported_128b_132b_rates.raw =
+ lttpr_dpcd_data[DP_PHY_REPEATER_128B132B_RATES -
+ DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
+
+ /* If this chip cap is set, at least one retimer must exist in the chain
+ * Override count to 1 if we receive a known bad count (0 or an invalid value) */
+ if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) &&
+ (dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) == 0)) {
+ ASSERT(0);
+ link->dpcd_caps.lttpr_caps.phy_repeater_cnt = 0x80;
+ DC_LOG_DC("lttpr_caps forced phy_repeater_cnt = %d\n", link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
+ }
+
+ /* Attempt to train in LTTPR transparent mode if repeater count exceeds 8. */
+ is_lttpr_present = dp_is_lttpr_present(link);
+
+ if (is_lttpr_present)
+ CONN_DATA_DETECT(link, lttpr_dpcd_data, sizeof(lttpr_dpcd_data), "LTTPR Caps: ");
+
+ DC_LOG_DC("is_lttpr_present = %d\n", is_lttpr_present);
+ return status;
+}
+
+static bool retrieve_link_cap(struct dc_link *link)
+{
+ /* DP_ADAPTER_CAP - DP_DPCD_REV + 1 == 16 and also DP_DSC_BITS_PER_PIXEL_INC - DP_DSC_SUPPORT + 1 == 16,
+ * which means size 16 will be good for both of those DPCD register block reads
+ */
+ uint8_t dpcd_data[16];
+ /*Only need to read 1 byte starting from DP_DPRX_FEATURE_ENUMERATION_LIST.
+ */
+ uint8_t dpcd_dprx_data = '\0';
+
+ struct dp_device_vendor_id sink_id;
+ union down_stream_port_count down_strm_port_count;
+ union edp_configuration_cap edp_config_cap;
+ union dp_downstream_port_present ds_port = { 0 };
+ enum dc_status status = DC_ERROR_UNEXPECTED;
+ uint32_t read_dpcd_retry_cnt = 3;
+ int i;
+ struct dp_sink_hw_fw_revision dp_hw_fw_revision;
+ const uint32_t post_oui_delay = 30; // 30ms
+
+ memset(dpcd_data, '\0', sizeof(dpcd_data));
+ memset(&down_strm_port_count,
+ '\0', sizeof(union down_stream_port_count));
+ memset(&edp_config_cap, '\0',
+ sizeof(union edp_configuration_cap));
+
+ /* if extended timeout is supported in hardware,
+ * default to LTTPR timeout (3.2ms) first as a W/A for DP link layer
+ * CTS 4.2.1.1 regression introduced by CTS specs requirement update.
+ */
+ try_to_configure_aux_timeout(link->ddc,
+ LINK_AUX_DEFAULT_LTTPR_TIMEOUT_PERIOD);
+
+ status = dp_retrieve_lttpr_cap(link);
+
+ if (status != DC_OK) {
+ status = wake_up_aux_channel(link);
+ if (status == DC_OK)
+ dp_retrieve_lttpr_cap(link);
+ else
+ return false;
+ }
+
+ if (dp_is_lttpr_present(link))
+ configure_lttpr_mode_transparent(link);
+
+ /* Read DP tunneling information. */
+ status = dpcd_get_tunneling_device_data(link);
+
+ dpcd_set_source_specific_data(link);
+ /* Sink may need to configure internals based on vendor, so allow some
+ * time before proceeding with possibly vendor specific transactions
+ */
+ msleep(post_oui_delay);
+
+ for (i = 0; i < read_dpcd_retry_cnt; i++) {
+ status = core_link_read_dpcd(
+ link,
+ DP_DPCD_REV,
+ dpcd_data,
+ sizeof(dpcd_data));
+ if (status == DC_OK)
+ break;
+ }
+
+
+ if (status != DC_OK) {
+ dm_error("%s: Read receiver caps dpcd data failed.\n", __func__);
+ return false;
+ }
+
+ if (!dp_is_lttpr_present(link))
+ try_to_configure_aux_timeout(link->ddc, LINK_AUX_DEFAULT_TIMEOUT_PERIOD);
+
+
+ {
+ union training_aux_rd_interval aux_rd_interval;
+
+ aux_rd_interval.raw =
+ dpcd_data[DP_TRAINING_AUX_RD_INTERVAL];
+
+ link->dpcd_caps.ext_receiver_cap_field_present =
+ aux_rd_interval.bits.EXT_RECEIVER_CAP_FIELD_PRESENT == 1;
+
+ if (aux_rd_interval.bits.EXT_RECEIVER_CAP_FIELD_PRESENT == 1) {
+ uint8_t ext_cap_data[16];
+
+ memset(ext_cap_data, '\0', sizeof(ext_cap_data));
+ for (i = 0; i < read_dpcd_retry_cnt; i++) {
+ status = core_link_read_dpcd(
+ link,
+ DP_DP13_DPCD_REV,
+ ext_cap_data,
+ sizeof(ext_cap_data));
+ if (status == DC_OK) {
+ memcpy(dpcd_data, ext_cap_data, sizeof(dpcd_data));
+ break;
+ }
+ }
+ if (status != DC_OK)
+ dm_error("%s: Read extend caps data failed, use cap from dpcd 0.\n", __func__);
+ }
+ }
+
+ link->dpcd_caps.dpcd_rev.raw =
+ dpcd_data[DP_DPCD_REV - DP_DPCD_REV];
+
+ if (link->dpcd_caps.ext_receiver_cap_field_present) {
+ for (i = 0; i < read_dpcd_retry_cnt; i++) {
+ status = core_link_read_dpcd(
+ link,
+ DP_DPRX_FEATURE_ENUMERATION_LIST,
+ &dpcd_dprx_data,
+ sizeof(dpcd_dprx_data));
+ if (status == DC_OK)
+ break;
+ }
+
+ link->dpcd_caps.dprx_feature.raw = dpcd_dprx_data;
+
+ if (status != DC_OK)
+ dm_error("%s: Read DPRX caps data failed.\n", __func__);
+
+ /* AdaptiveSyncCapability */
+ dpcd_dprx_data = 0;
+ for (i = 0; i < read_dpcd_retry_cnt; i++) {
+ status = core_link_read_dpcd(
+ link, DP_DPRX_FEATURE_ENUMERATION_LIST_CONT_1,
+ &dpcd_dprx_data, sizeof(dpcd_dprx_data));
+ if (status == DC_OK)
+ break;
+ }
+
+ link->dpcd_caps.adaptive_sync_caps.dp_adap_sync_caps.raw = dpcd_dprx_data;
+
+ if (status != DC_OK)
+ dm_error("%s: Read DPRX caps data failed. Addr:%#x\n",
+ __func__, DP_DPRX_FEATURE_ENUMERATION_LIST_CONT_1);
+ }
+
+ else {
+ link->dpcd_caps.dprx_feature.raw = 0;
+ }
+
+
+ /* Error condition checking...
+ * It is impossible for Sink to report Max Lane Count = 0.
+ * It is possible for Sink to report Max Link Rate = 0, if it is
+ * an eDP device that is reporting specialized link rates in the
+ * SUPPORTED_LINK_RATE table.
+ */
+ if (dpcd_data[DP_MAX_LANE_COUNT - DP_DPCD_REV] == 0)
+ return false;
+
+ ds_port.byte = dpcd_data[DP_DOWNSTREAMPORT_PRESENT -
+ DP_DPCD_REV];
+
+ read_dp_device_vendor_id(link);
+
+ /* TODO - decouple raw mst capability from policy decision */
+ link->dpcd_caps.is_mst_capable = read_is_mst_supported(link);
+
+ get_active_converter_info(ds_port.byte, link);
+
+ dp_wa_power_up_0010FA(link, dpcd_data, sizeof(dpcd_data));
+
+ down_strm_port_count.raw = dpcd_data[DP_DOWN_STREAM_PORT_COUNT -
+ DP_DPCD_REV];
+
+ link->dpcd_caps.allow_invalid_MSA_timing_param =
+ down_strm_port_count.bits.IGNORE_MSA_TIMING_PARAM;
+
+ link->dpcd_caps.max_ln_count.raw = dpcd_data[
+ DP_MAX_LANE_COUNT - DP_DPCD_REV];
+
+ link->dpcd_caps.max_down_spread.raw = dpcd_data[
+ DP_MAX_DOWNSPREAD - DP_DPCD_REV];
+
+ link->reported_link_cap.lane_count =
+ link->dpcd_caps.max_ln_count.bits.MAX_LANE_COUNT;
+ link->reported_link_cap.link_rate = get_link_rate_from_max_link_bw(
+ dpcd_data[DP_MAX_LINK_RATE - DP_DPCD_REV]);
+ link->reported_link_cap.link_spread =
+ link->dpcd_caps.max_down_spread.bits.MAX_DOWN_SPREAD ?
+ LINK_SPREAD_05_DOWNSPREAD_30KHZ : LINK_SPREAD_DISABLED;
+
+ edp_config_cap.raw = dpcd_data[
+ DP_EDP_CONFIGURATION_CAP - DP_DPCD_REV];
+ link->dpcd_caps.panel_mode_edp =
+ edp_config_cap.bits.ALT_SCRAMBLER_RESET;
+ link->dpcd_caps.dpcd_display_control_capable =
+ edp_config_cap.bits.DPCD_DISPLAY_CONTROL_CAPABLE;
+ link->dpcd_caps.channel_coding_cap.raw =
+ dpcd_data[DP_MAIN_LINK_CHANNEL_CODING - DP_DPCD_REV];
+ link->test_pattern_enabled = false;
+ link->compliance_test_state.raw = 0;
+
+ /* read sink count */
+ core_link_read_dpcd(link,
+ DP_SINK_COUNT,
+ &link->dpcd_caps.sink_count.raw,
+ sizeof(link->dpcd_caps.sink_count.raw));
+
+ /* read sink ieee oui */
+ core_link_read_dpcd(link,
+ DP_SINK_OUI,
+ (uint8_t *)(&sink_id),
+ sizeof(sink_id));
+
+ link->dpcd_caps.sink_dev_id =
+ (sink_id.ieee_oui[0] << 16) +
+ (sink_id.ieee_oui[1] << 8) +
+ (sink_id.ieee_oui[2]);
+
+ memmove(
+ link->dpcd_caps.sink_dev_id_str,
+ sink_id.ieee_device_id,
+ sizeof(sink_id.ieee_device_id));
+
+ core_link_read_dpcd(
+ link,
+ DP_SINK_HW_REVISION_START,
+ (uint8_t *)&dp_hw_fw_revision,
+ sizeof(dp_hw_fw_revision));
+
+ link->dpcd_caps.sink_hw_revision =
+ dp_hw_fw_revision.ieee_hw_rev;
+
+ memmove(
+ link->dpcd_caps.sink_fw_revision,
+ dp_hw_fw_revision.ieee_fw_rev,
+ sizeof(dp_hw_fw_revision.ieee_fw_rev));
+
+ /* Quirk for Retina panels: wrong DP_MAX_LINK_RATE */
+ {
+ uint8_t str_mbp_2018[] = { 101, 68, 21, 103, 98, 97 };
+ uint8_t fwrev_mbp_2018[] = { 7, 4 };
+ uint8_t fwrev_mbp_2018_vega[] = { 8, 4 };
+
+ /* We also check for the firmware revision as 16,1 models have an
+ * identical device id and are incorrectly quirked otherwise.
+ */
+ if ((link->dpcd_caps.sink_dev_id == 0x0010fa) &&
+ !memcmp(link->dpcd_caps.sink_dev_id_str, str_mbp_2018,
+ sizeof(str_mbp_2018)) &&
+ (!memcmp(link->dpcd_caps.sink_fw_revision, fwrev_mbp_2018,
+ sizeof(fwrev_mbp_2018)) ||
+ !memcmp(link->dpcd_caps.sink_fw_revision, fwrev_mbp_2018_vega,
+ sizeof(fwrev_mbp_2018_vega)))) {
+ link->reported_link_cap.link_rate = LINK_RATE_RBR2;
+ }
+ }
+
+ memset(&link->dpcd_caps.dsc_caps, '\0',
+ sizeof(link->dpcd_caps.dsc_caps));
+ memset(&link->dpcd_caps.fec_cap, '\0', sizeof(link->dpcd_caps.fec_cap));
+ /* Read DSC and FEC sink capabilities if DP revision is 1.4 and up */
+ if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_14) {
+ status = core_link_read_dpcd(
+ link,
+ DP_FEC_CAPABILITY,
+ &link->dpcd_caps.fec_cap.raw,
+ sizeof(link->dpcd_caps.fec_cap.raw));
+ status = core_link_read_dpcd(
+ link,
+ DP_DSC_SUPPORT,
+ link->dpcd_caps.dsc_caps.dsc_basic_caps.raw,
+ sizeof(link->dpcd_caps.dsc_caps.dsc_basic_caps.raw));
+ if (link->dpcd_caps.dongle_type != DISPLAY_DONGLE_NONE) {
+ status = core_link_read_dpcd(
+ link,
+ DP_DSC_BRANCH_OVERALL_THROUGHPUT_0,
+ link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.raw,
+ sizeof(link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.raw));
+ DC_LOG_DSC("DSC branch decoder capability is read at link %d", link->link_index);
+ DC_LOG_DSC("\tBRANCH_OVERALL_THROUGHPUT_0 = 0x%02x",
+ link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.fields.BRANCH_OVERALL_THROUGHPUT_0);
+ DC_LOG_DSC("\tBRANCH_OVERALL_THROUGHPUT_1 = 0x%02x",
+ link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.fields.BRANCH_OVERALL_THROUGHPUT_1);
+ DC_LOG_DSC("\tBRANCH_MAX_LINE_WIDTH 0x%02x",
+ link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.fields.BRANCH_MAX_LINE_WIDTH);
+ }
+
+ /* Apply work around to disable FEC and DSC for USB4 tunneling in TBT3 compatibility mode
+ * only if required.
+ */
+ if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA &&
+ link->dc->debug.dpia_debug.bits.enable_force_tbt3_work_around &&
+ link->dpcd_caps.is_branch_dev &&
+ link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_90CC24 &&
+ link->dpcd_caps.branch_hw_revision == DP_BRANCH_HW_REV_10 &&
+ (link->dpcd_caps.fec_cap.bits.FEC_CAPABLE ||
+ link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_SUPPORT)) {
+ /* A TBT3 device is expected to report no support for FEC or DSC to a USB4 DPIA.
+ * Clear FEC and DSC capabilities as a work around if that is not the case.
+ */
+ link->wa_flags.dpia_forced_tbt3_mode = true;
+ memset(&link->dpcd_caps.dsc_caps, '\0', sizeof(link->dpcd_caps.dsc_caps));
+ memset(&link->dpcd_caps.fec_cap, '\0', sizeof(link->dpcd_caps.fec_cap));
+ DC_LOG_DSC("Clear DSC SUPPORT for USB4 link(%d) in TBT3 compatibility mode", link->link_index);
+ } else
+ link->wa_flags.dpia_forced_tbt3_mode = false;
+ }
+
+ if (!dpcd_read_sink_ext_caps(link))
+ link->dpcd_sink_ext_caps.raw = 0;
+
+ if (link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED) {
+ DC_LOG_DP2("128b/132b encoding is supported at link %d", link->link_index);
+
+ core_link_read_dpcd(link,
+ DP_128B132B_SUPPORTED_LINK_RATES,
+ &link->dpcd_caps.dp_128b_132b_supported_link_rates.raw,
+ sizeof(link->dpcd_caps.dp_128b_132b_supported_link_rates.raw));
+ if (link->dpcd_caps.dp_128b_132b_supported_link_rates.bits.UHBR20)
+ link->reported_link_cap.link_rate = LINK_RATE_UHBR20;
+ else if (link->dpcd_caps.dp_128b_132b_supported_link_rates.bits.UHBR13_5)
+ link->reported_link_cap.link_rate = LINK_RATE_UHBR13_5;
+ else if (link->dpcd_caps.dp_128b_132b_supported_link_rates.bits.UHBR10)
+ link->reported_link_cap.link_rate = LINK_RATE_UHBR10;
+ else
+ dm_error("%s: Invalid RX 128b_132b_supported_link_rates\n", __func__);
+ DC_LOG_DP2("128b/132b supported link rates is read at link %d", link->link_index);
+ DC_LOG_DP2("\tmax 128b/132b link rate support is %d.%d GHz",
+ link->reported_link_cap.link_rate / 100,
+ link->reported_link_cap.link_rate % 100);
+
+ core_link_read_dpcd(link,
+ DP_SINK_VIDEO_FALLBACK_FORMATS,
+ &link->dpcd_caps.fallback_formats.raw,
+ sizeof(link->dpcd_caps.fallback_formats.raw));
+ DC_LOG_DP2("sink video fallback format is read at link %d", link->link_index);
+ if (link->dpcd_caps.fallback_formats.bits.dp_1920x1080_60Hz_24bpp_support)
+ DC_LOG_DP2("\t1920x1080@60Hz 24bpp fallback format supported");
+ if (link->dpcd_caps.fallback_formats.bits.dp_1280x720_60Hz_24bpp_support)
+ DC_LOG_DP2("\t1280x720@60Hz 24bpp fallback format supported");
+ if (link->dpcd_caps.fallback_formats.bits.dp_1024x768_60Hz_24bpp_support)
+ DC_LOG_DP2("\t1024x768@60Hz 24bpp fallback format supported");
+ if (link->dpcd_caps.fallback_formats.raw == 0) {
+ DC_LOG_DP2("\tno supported fallback formats, assume 1920x1080@60Hz 24bpp is supported");
+ link->dpcd_caps.fallback_formats.bits.dp_1920x1080_60Hz_24bpp_support = 1;
+ }
+
+ core_link_read_dpcd(link,
+ DP_FEC_CAPABILITY_1,
+ &link->dpcd_caps.fec_cap1.raw,
+ sizeof(link->dpcd_caps.fec_cap1.raw));
+ DC_LOG_DP2("FEC CAPABILITY 1 is read at link %d", link->link_index);
+ if (link->dpcd_caps.fec_cap1.bits.AGGREGATED_ERROR_COUNTERS_CAPABLE)
+ DC_LOG_DP2("\tFEC aggregated error counters are supported");
+ }
+
+ retrieve_cable_id(link);
+ dpcd_write_cable_id_to_dprx(link);
+
+ /* Connectivity log: detection */
+ CONN_DATA_DETECT(link, dpcd_data, sizeof(dpcd_data), "Rx Caps: ");
+
+ return true;
+}
+
+bool detect_dp_sink_caps(struct dc_link *link)
+{
+ return retrieve_link_cap(link);
+}
+
+void detect_edp_sink_caps(struct dc_link *link)
+{
+ uint8_t supported_link_rates[16];
+ uint32_t entry;
+ uint32_t link_rate_in_khz;
+ enum dc_link_rate link_rate = LINK_RATE_UNKNOWN;
+ uint8_t backlight_adj_cap;
+ uint8_t general_edp_cap;
+
+ retrieve_link_cap(link);
+ link->dpcd_caps.edp_supported_link_rates_count = 0;
+ memset(supported_link_rates, 0, sizeof(supported_link_rates));
+
+ /*
+ * edp_supported_link_rates_count is only valid for eDP v1.4 or higher.
+ * Per VESA eDP spec, "The DPCD revision for eDP v1.4 is 13h"
+ */
+ if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_13 &&
+ (link->panel_config.ilr.optimize_edp_link_rate ||
+ link->reported_link_cap.link_rate == LINK_RATE_UNKNOWN)) {
+ // Read DPCD 00010h - 0001Fh 16 bytes at one shot
+ core_link_read_dpcd(link, DP_SUPPORTED_LINK_RATES,
+ supported_link_rates, sizeof(supported_link_rates));
+
+ for (entry = 0; entry < 16; entry += 2) {
+ // DPCD register reports per-lane link rate = 16-bit link rate capability
+ // value X 200 kHz. Need multiplier to find link rate in kHz.
+ link_rate_in_khz = (supported_link_rates[entry+1] * 0x100 +
+ supported_link_rates[entry]) * 200;
+
+ if (link_rate_in_khz != 0) {
+ link_rate = linkRateInKHzToLinkRateMultiplier(link_rate_in_khz);
+ link->dpcd_caps.edp_supported_link_rates[link->dpcd_caps.edp_supported_link_rates_count] = link_rate;
+ link->dpcd_caps.edp_supported_link_rates_count++;
+
+ if (link->reported_link_cap.link_rate < link_rate)
+ link->reported_link_cap.link_rate = link_rate;
+ }
+ }
+ }
+ core_link_read_dpcd(link, DP_EDP_BACKLIGHT_ADJUSTMENT_CAP,
+ &backlight_adj_cap, sizeof(backlight_adj_cap));
+
+ link->dpcd_caps.dynamic_backlight_capable_edp =
+ (backlight_adj_cap & DP_EDP_DYNAMIC_BACKLIGHT_CAP) ? true:false;
+
+ core_link_read_dpcd(link, DP_EDP_GENERAL_CAP_1,
+ &general_edp_cap, sizeof(general_edp_cap));
+
+ link->dpcd_caps.set_power_state_capable_edp =
+ (general_edp_cap & DP_EDP_SET_POWER_CAP) ? true:false;
+
+ set_default_brightness_aux(link);
+
+ core_link_read_dpcd(link, DP_EDP_DPCD_REV,
+ &link->dpcd_caps.edp_rev,
+ sizeof(link->dpcd_caps.edp_rev));
+ /*
+ * PSR is only valid for eDP v1.3 or higher.
+ */
+ if (link->dpcd_caps.edp_rev >= DP_EDP_13) {
+ core_link_read_dpcd(link, DP_PSR_SUPPORT,
+ &link->dpcd_caps.psr_info.psr_version,
+ sizeof(link->dpcd_caps.psr_info.psr_version));
+ if (link->dpcd_caps.sink_dev_id == DP_BRANCH_DEVICE_ID_001CF8)
+ core_link_read_dpcd(link, DP_FORCE_PSRSU_CAPABILITY,
+ &link->dpcd_caps.psr_info.force_psrsu_cap,
+ sizeof(link->dpcd_caps.psr_info.force_psrsu_cap));
+ core_link_read_dpcd(link, DP_PSR_CAPS,
+ &link->dpcd_caps.psr_info.psr_dpcd_caps.raw,
+ sizeof(link->dpcd_caps.psr_info.psr_dpcd_caps.raw));
+ if (link->dpcd_caps.psr_info.psr_dpcd_caps.bits.Y_COORDINATE_REQUIRED) {
+ core_link_read_dpcd(link, DP_PSR2_SU_Y_GRANULARITY,
+ &link->dpcd_caps.psr_info.psr2_su_y_granularity_cap,
+ sizeof(link->dpcd_caps.psr_info.psr2_su_y_granularity_cap));
+ }
+ }
+
+ /*
+ * ALPM is only valid for eDP v1.4 or higher.
+ */
+ if (link->dpcd_caps.dpcd_rev.raw >= DP_EDP_14)
+ core_link_read_dpcd(link, DP_RECEIVER_ALPM_CAP,
+ &link->dpcd_caps.alpm_caps.raw,
+ sizeof(link->dpcd_caps.alpm_caps.raw));
+}
+
+bool dc_link_dp_get_max_link_enc_cap(const struct dc_link *link, struct dc_link_settings *max_link_enc_cap)
+{
+ struct link_encoder *link_enc = NULL;
+
+ if (!max_link_enc_cap) {
+ DC_LOG_ERROR("%s: Could not return max link encoder caps", __func__);
+ return false;
+ }
+
+ link_enc = link_enc_cfg_get_link_enc(link);
+ ASSERT(link_enc);
+
+ if (link_enc && link_enc->funcs->get_max_link_cap) {
+ link_enc->funcs->get_max_link_cap(link_enc, max_link_enc_cap);
+ return true;
+ }
+
+ DC_LOG_ERROR("%s: Max link encoder caps unknown", __func__);
+ max_link_enc_cap->lane_count = 1;
+ max_link_enc_cap->link_rate = 6;
+ return false;
+}
+
+const struct dc_link_settings *dc_link_get_link_cap(
+ const struct dc_link *link)
+{
+ if (link->preferred_link_setting.lane_count != LANE_COUNT_UNKNOWN &&
+ link->preferred_link_setting.link_rate != LINK_RATE_UNKNOWN)
+ return &link->preferred_link_setting;
+ return &link->verified_link_cap;
+}
+
+struct dc_link_settings dp_get_max_link_cap(struct dc_link *link)
+{
+ struct dc_link_settings max_link_cap = {0};
+ enum dc_link_rate lttpr_max_link_rate;
+ enum dc_link_rate cable_max_link_rate;
+ struct link_encoder *link_enc = NULL;
+
+
+ link_enc = link_enc_cfg_get_link_enc(link);
+ ASSERT(link_enc);
+
+ /* get max link encoder capability */
+ if (link_enc)
+ link_enc->funcs->get_max_link_cap(link_enc, &max_link_cap);
+
+ /* Lower link settings based on sink's link cap */
+ if (link->reported_link_cap.lane_count < max_link_cap.lane_count)
+ max_link_cap.lane_count =
+ link->reported_link_cap.lane_count;
+ if (link->reported_link_cap.link_rate < max_link_cap.link_rate)
+ max_link_cap.link_rate =
+ link->reported_link_cap.link_rate;
+ if (link->reported_link_cap.link_spread <
+ max_link_cap.link_spread)
+ max_link_cap.link_spread =
+ link->reported_link_cap.link_spread;
+
+ /* Lower link settings based on cable attributes
+ * Cable ID is a DP2 feature to identify max certified link rate that
+ * a cable can carry. The cable identification method requires both
+ * cable and display hardware support. Since the specs comes late, it is
+ * anticipated that the first round of DP2 cables and displays may not
+ * be fully compatible to reliably return cable ID data. Therefore the
+ * decision of our cable id policy is that if the cable can return non
+ * zero cable id data, we will take cable's link rate capability into
+ * account. However if we get zero data, the cable link rate capability
+ * is considered inconclusive. In this case, we will not take cable's
+ * capability into account to avoid of over limiting hardware capability
+ * from users. The max overall link rate capability is still determined
+ * after actual dp pre-training. Cable id is considered as an auxiliary
+ * method of determining max link bandwidth capability.
+ */
+ cable_max_link_rate = get_cable_max_link_rate(link);
+
+ if (!link->dc->debug.ignore_cable_id &&
+ cable_max_link_rate != LINK_RATE_UNKNOWN &&
+ cable_max_link_rate < max_link_cap.link_rate)
+ max_link_cap.link_rate = cable_max_link_rate;
+
+ /* account for lttpr repeaters cap
+ * notes: repeaters do not snoop in the DPRX Capabilities addresses (3.6.3).
+ */
+ if (dp_is_lttpr_present(link)) {
+ if (link->dpcd_caps.lttpr_caps.max_lane_count < max_link_cap.lane_count)
+ max_link_cap.lane_count = link->dpcd_caps.lttpr_caps.max_lane_count;
+ lttpr_max_link_rate = get_lttpr_max_link_rate(link);
+
+ if (lttpr_max_link_rate < max_link_cap.link_rate)
+ max_link_cap.link_rate = lttpr_max_link_rate;
+
+ DC_LOG_HW_LINK_TRAINING("%s\n Training with LTTPR, max_lane count %d max_link rate %d \n",
+ __func__,
+ max_link_cap.lane_count,
+ max_link_cap.link_rate);
+ }
+
+ if (link_dp_get_encoding_format(&max_link_cap) == DP_128b_132b_ENCODING &&
+ link->dc->debug.disable_uhbr)
+ max_link_cap.link_rate = LINK_RATE_HIGH3;
+
+ return max_link_cap;
+}
+
+static bool dp_verify_link_cap(
+ struct dc_link *link,
+ struct dc_link_settings *known_limit_link_setting,
+ int *fail_count)
+{
+ struct dc_link_settings cur_link_settings = {0};
+ struct dc_link_settings max_link_settings = *known_limit_link_setting;
+ bool success = false;
+ bool skip_video_pattern;
+ enum clock_source_id dp_cs_id = get_clock_source_id(link);
+ enum link_training_result status = LINK_TRAINING_SUCCESS;
+ union hpd_irq_data irq_data;
+ struct link_resource link_res;
+
+ memset(&irq_data, 0, sizeof(irq_data));
+ cur_link_settings = max_link_settings;
+
+ /* Grant extended timeout request */
+ if (dp_is_lttpr_present(link) && link->dpcd_caps.lttpr_caps.max_ext_timeout > 0) {
+ uint8_t grant = link->dpcd_caps.lttpr_caps.max_ext_timeout & 0x80;
+
+ core_link_write_dpcd(link, DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT, &grant, sizeof(grant));
+ }
+
+ do {
+ if (!get_temp_dp_link_res(link, &link_res, &cur_link_settings))
+ continue;
+
+ skip_video_pattern = cur_link_settings.link_rate != LINK_RATE_LOW;
+ dp_enable_link_phy(
+ link,
+ &link_res,
+ link->connector_signal,
+ dp_cs_id,
+ &cur_link_settings);
+
+ status = dp_perform_link_training(
+ link,
+ &link_res,
+ &cur_link_settings,
+ skip_video_pattern);
+
+ if (status == LINK_TRAINING_SUCCESS) {
+ success = true;
+ udelay(1000);
+ if (dc_link_dp_read_hpd_rx_irq_data(link, &irq_data) == DC_OK &&
+ dc_link_check_link_loss_status(
+ link,
+ &irq_data))
+ (*fail_count)++;
+
+ } else {
+ (*fail_count)++;
+ }
+ dp_trace_lt_total_count_increment(link, true);
+ dp_trace_lt_result_update(link, status, true);
+ dp_disable_link_phy(link, &link_res, link->connector_signal);
+ } while (!success && decide_fallback_link_setting(link,
+ &max_link_settings, &cur_link_settings, status));
+
+ link->verified_link_cap = success ?
+ cur_link_settings : fail_safe_link_settings;
+ return success;
+}
+
+bool dp_verify_link_cap_with_retries(
+ struct dc_link *link,
+ struct dc_link_settings *known_limit_link_setting,
+ int attempts)
+{
+ int i = 0;
+ bool success = false;
+ int fail_count = 0;
+
+ dp_trace_detect_lt_init(link);
+
+ if (link->link_enc && link->link_enc->features.flags.bits.DP_IS_USB_C &&
+ link->dc->debug.usbc_combo_phy_reset_wa)
+ apply_usbc_combo_phy_reset_wa(link, known_limit_link_setting);
+
+ dp_trace_set_lt_start_timestamp(link, false);
+ for (i = 0; i < attempts; i++) {
+ enum dc_connection_type type = dc_connection_none;
+
+ memset(&link->verified_link_cap, 0,
+ sizeof(struct dc_link_settings));
+ if (!dc_link_detect_connection_type(link, &type) || type == dc_connection_none) {
+ link->verified_link_cap = fail_safe_link_settings;
+ break;
+ } else if (dp_verify_link_cap(link, known_limit_link_setting,
+ &fail_count) && fail_count == 0) {
+ success = true;
+ break;
+ }
+ msleep(10);
+ }
+
+ dp_trace_lt_fail_count_update(link, fail_count, true);
+ dp_trace_set_lt_end_timestamp(link, true);
+
+ return success;
+}
+
+/**
+ * dc_link_is_dp_sink_present() - Check if there is a native DP
+ * or passive DP-HDMI dongle connected
+ */
+bool dc_link_is_dp_sink_present(struct dc_link *link)
+{
+ enum gpio_result gpio_result;
+ uint32_t clock_pin = 0;
+ uint8_t retry = 0;
+ struct ddc *ddc;
+
+ enum connector_id connector_id =
+ dal_graphics_object_id_get_connector_id(link->link_id);
+
+ bool present =
+ ((connector_id == CONNECTOR_ID_DISPLAY_PORT) ||
+ (connector_id == CONNECTOR_ID_EDP) ||
+ (connector_id == CONNECTOR_ID_USBC));
+
+ ddc = get_ddc_pin(link->ddc);
+
+ if (!ddc) {
+ BREAK_TO_DEBUGGER();
+ return present;
+ }
+
+ /* Open GPIO and set it to I2C mode */
+ /* Note: this GpioMode_Input will be converted
+ * to GpioConfigType_I2cAuxDualMode in GPIO component,
+ * which indicates we need additional delay
+ */
+
+ if (dal_ddc_open(ddc, GPIO_MODE_INPUT,
+ GPIO_DDC_CONFIG_TYPE_MODE_I2C) != GPIO_RESULT_OK) {
+ dal_ddc_close(ddc);
+
+ return present;
+ }
+
+ /*
+ * Read GPIO: DP sink is present if both clock and data pins are zero
+ *
+ * [W/A] plug-unplug DP cable, sometimes customer board has
+ * one short pulse on clk_pin(1V, < 1ms). DP will be config to HDMI/DVI
+ * then monitor can't br light up. Add retry 3 times
+ * But in real passive dongle, it need additional 3ms to detect
+ */
+ do {
+ gpio_result = dal_gpio_get_value(ddc->pin_clock, &clock_pin);
+ ASSERT(gpio_result == GPIO_RESULT_OK);
+ if (clock_pin)
+ udelay(1000);
+ else
+ break;
+ } while (retry++ < 3);
+
+ present = (gpio_result == GPIO_RESULT_OK) && !clock_pin;
+
+ dal_ddc_close(ddc);
+
+ return present;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.h
new file mode 100644
index 000000000000..f79e4a4a9db6
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DC_LINK_DP_CAPABILITY_H__
+#define __DC_LINK_DP_CAPABILITY_H__
+
+#include "link.h"
+
+bool detect_dp_sink_caps(struct dc_link *link);
+
+void detect_edp_sink_caps(struct dc_link *link);
+
+struct dc_link_settings dp_get_max_link_cap(struct dc_link *link);
+
+
+enum dc_status dp_retrieve_lttpr_cap(struct dc_link *link);
+
+/* Convert PHY repeater count read from DPCD uint8_t. */
+uint8_t dp_parse_lttpr_repeater_count(uint8_t lttpr_repeater_count);
+
+bool dp_is_lttpr_present(struct dc_link *link);
+
+bool is_dp_active_dongle(const struct dc_link *link);
+
+bool is_dp_branch_device(const struct dc_link *link);
+
+void dpcd_write_cable_id_to_dprx(struct dc_link *link);
+
+/* Initialize output parameter lt_settings. */
+void dp_decide_training_settings(
+ struct dc_link *link,
+ const struct dc_link_settings *link_setting,
+ struct link_training_settings *lt_settings);
+
+
+bool decide_edp_link_settings_with_dsc(struct dc_link *link,
+ struct dc_link_settings *link_setting,
+ uint32_t req_bw,
+ enum dc_link_rate max_link_rate);
+
+void dpcd_set_source_specific_data(struct dc_link *link);
+
+/*query dpcd for version and mst cap addresses*/
+bool read_is_mst_supported(struct dc_link *link);
+
+bool decide_fallback_link_setting(
+ struct dc_link *link,
+ struct dc_link_settings *max,
+ struct dc_link_settings *cur,
+ enum link_training_result training_result);
+
+bool dp_verify_link_cap_with_retries(
+ struct dc_link *link,
+ struct dc_link_settings *known_limit_link_setting,
+ int attempts);
+
+#endif /* __DC_LINK_DP_CAPABILITY_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia.c
new file mode 100644
index 000000000000..32f48a48e9dd
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia.c
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright 2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+
+#include "dc.h"
+#include "inc/core_status.h"
+#include "dc_link.h"
+#include "dpcd_defs.h"
+
+#include "link_dp_dpia.h"
+#include "link_hwss.h"
+#include "dm_helpers.h"
+#include "dmub/inc/dmub_cmd.h"
+#include "link_dpcd.h"
+#include "link_dp_training.h"
+#include "dc_dmub_srv.h"
+
+#define DC_LOGGER \
+ link->ctx->logger
+
+/** @note Can remove once DP tunneling registers in upstream include/drm/drm_dp_helper.h */
+/* DPCD DP Tunneling over USB4 */
+#define DP_TUNNELING_CAPABILITIES_SUPPORT 0xe000d
+#define DP_IN_ADAPTER_INFO 0xe000e
+#define DP_USB4_DRIVER_ID 0xe000f
+#define DP_USB4_ROUTER_TOPOLOGY_ID 0xe001b
+
+enum dc_status dpcd_get_tunneling_device_data(struct dc_link *link)
+{
+ enum dc_status status = DC_OK;
+ uint8_t dpcd_dp_tun_data[3] = {0};
+ uint8_t dpcd_topology_data[DPCD_USB4_TOPOLOGY_ID_LEN] = {0};
+ uint8_t i = 0;
+
+ status = core_link_read_dpcd(
+ link,
+ DP_TUNNELING_CAPABILITIES_SUPPORT,
+ dpcd_dp_tun_data,
+ sizeof(dpcd_dp_tun_data));
+
+ status = core_link_read_dpcd(
+ link,
+ DP_USB4_ROUTER_TOPOLOGY_ID,
+ dpcd_topology_data,
+ sizeof(dpcd_topology_data));
+
+ link->dpcd_caps.usb4_dp_tun_info.dp_tun_cap.raw =
+ dpcd_dp_tun_data[DP_TUNNELING_CAPABILITIES_SUPPORT - DP_TUNNELING_CAPABILITIES_SUPPORT];
+ link->dpcd_caps.usb4_dp_tun_info.dpia_info.raw =
+ dpcd_dp_tun_data[DP_IN_ADAPTER_INFO - DP_TUNNELING_CAPABILITIES_SUPPORT];
+ link->dpcd_caps.usb4_dp_tun_info.usb4_driver_id =
+ dpcd_dp_tun_data[DP_USB4_DRIVER_ID - DP_TUNNELING_CAPABILITIES_SUPPORT];
+
+ for (i = 0; i < DPCD_USB4_TOPOLOGY_ID_LEN; i++)
+ link->dpcd_caps.usb4_dp_tun_info.usb4_topology_id[i] = dpcd_topology_data[i];
+
+ return status;
+}
+
+bool dc_link_dpia_query_hpd_status(struct dc_link *link)
+{
+ union dmub_rb_cmd cmd = {0};
+ struct dc_dmub_srv *dmub_srv = link->ctx->dmub_srv;
+ bool is_hpd_high = false;
+
+ /* prepare QUERY_HPD command */
+ cmd.query_hpd.header.type = DMUB_CMD__QUERY_HPD_STATE;
+ cmd.query_hpd.data.instance = link->link_id.enum_id - ENUM_ID_1;
+ cmd.query_hpd.data.ch_type = AUX_CHANNEL_DPIA;
+
+ /* Return HPD status reported by DMUB if query successfully executed. */
+ if (dc_dmub_srv_cmd_with_reply_data(dmub_srv, &cmd) && cmd.query_hpd.data.status == AUX_RET_SUCCESS)
+ is_hpd_high = cmd.query_hpd.data.result;
+
+ DC_LOG_DEBUG("%s: link(%d) dpia(%d) cmd_status(%d) result(%d)\n",
+ __func__,
+ link->link_index,
+ link->link_id.enum_id - ENUM_ID_1,
+ cmd.query_hpd.data.status,
+ cmd.query_hpd.data.result);
+
+ return is_hpd_high;
+}
+
diff --git a/drivers/gpu/drm/tdfx/tdfx_drv.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia.h
index 84204ec1b046..98935cc10bb7 100644
--- a/drivers/gpu/drm/tdfx/tdfx_drv.h
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia.h
@@ -1,9 +1,6 @@
-/* tdfx.h -- 3dfx DRM template customization -*- linux-c -*-
- * Created: Wed Feb 14 12:32:32 2001 by gareth@valinux.com
- */
+/* SPDX-License-Identifier: MIT */
/*
- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * All Rights Reserved.
+ * Copyright 2021 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@@ -12,36 +9,35 @@
* 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 (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
+ * 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
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
*
- * Authors:
- * Gareth Hughes <gareth@valinux.com>
+ * Authors: AMD
+ *
*/
-#ifndef __TDFX_H__
-#define __TDFX_H__
+#ifndef __DC_LINK_DPIA_H__
+#define __DC_LINK_DPIA_H__
-/* General customization:
- */
+#include "link.h"
-#define DRIVER_AUTHOR "VA Linux Systems Inc."
+/* Read tunneling device capability from DPCD and update link capability
+ * accordingly.
+ */
+enum dc_status dpcd_get_tunneling_device_data(struct dc_link *link);
-#define DRIVER_NAME "tdfx"
-#define DRIVER_DESC "3dfx Banshee/Voodoo3+"
-#define DRIVER_DATE "20010216"
+/* Query hot plug status of USB4 DP tunnel.
+ * Returns true if HPD high.
+ */
+bool dc_link_dpia_query_hpd_status(struct dc_link *link);
-#define DRIVER_MAJOR 1
-#define DRIVER_MINOR 0
-#define DRIVER_PATCHLEVEL 0
-#endif
+#endif /* __DC_LINK_DPIA_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.c
new file mode 100644
index 000000000000..f69e681b3b5b
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.c
@@ -0,0 +1,441 @@
+
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+/*********************************************************************/
+// USB4 DPIA BANDWIDTH ALLOCATION LOGIC
+/*********************************************************************/
+#include "dc.h"
+#include "dc_link.h"
+#include "link_dp_dpia_bw.h"
+#include "drm_dp_helper_dc.h"
+#include "link_dpcd.h"
+
+#define Kbps_TO_Gbps (1000 * 1000)
+
+// ------------------------------------------------------------------
+// PRIVATE FUNCTIONS
+// ------------------------------------------------------------------
+/*
+ * Always Check the following:
+ * - Is it USB4 link?
+ * - Is HPD HIGH?
+ * - Is BW Allocation Support Mode enabled on DP-Tx?
+ */
+static bool get_bw_alloc_proceed_flag(struct dc_link *tmp)
+{
+ return (tmp && DISPLAY_ENDPOINT_USB4_DPIA == tmp->ep_type
+ && tmp->hpd_status
+ && tmp->dpia_bw_alloc_config.bw_alloc_enabled);
+}
+static void reset_bw_alloc_struct(struct dc_link *link)
+{
+ link->dpia_bw_alloc_config.bw_alloc_enabled = false;
+ link->dpia_bw_alloc_config.sink_verified_bw = 0;
+ link->dpia_bw_alloc_config.sink_max_bw = 0;
+ link->dpia_bw_alloc_config.estimated_bw = 0;
+ link->dpia_bw_alloc_config.bw_granularity = 0;
+ link->dpia_bw_alloc_config.response_ready = false;
+}
+static uint8_t get_bw_granularity(struct dc_link *link)
+{
+ uint8_t bw_granularity = 0;
+
+ core_link_read_dpcd(
+ link,
+ DP_BW_GRANULALITY,
+ &bw_granularity,
+ sizeof(uint8_t));
+
+ switch (bw_granularity & 0x3) {
+ case 0:
+ bw_granularity = 4;
+ break;
+ case 1:
+ default:
+ bw_granularity = 2;
+ break;
+ }
+
+ return bw_granularity;
+}
+static int get_estimated_bw(struct dc_link *link)
+{
+ uint8_t bw_estimated_bw = 0;
+
+ if (core_link_read_dpcd(
+ link,
+ ESTIMATED_BW,
+ &bw_estimated_bw,
+ sizeof(uint8_t)) != DC_OK)
+ dm_output_to_console("%s: AUX W/R ERROR @ 0x%x\n", __func__, ESTIMATED_BW);
+
+ return bw_estimated_bw * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity);
+}
+static bool allocate_usb4_bw(int *stream_allocated_bw, int bw_needed, struct dc_link *link)
+{
+ if (bw_needed > 0)
+ *stream_allocated_bw += bw_needed;
+
+ return true;
+}
+static bool deallocate_usb4_bw(int *stream_allocated_bw, int bw_to_dealloc, struct dc_link *link)
+{
+ bool ret = false;
+
+ if (*stream_allocated_bw > 0) {
+ *stream_allocated_bw -= bw_to_dealloc;
+ ret = true;
+ } else {
+ //Do nothing for now
+ ret = true;
+ }
+
+ // Unplug so reset values
+ if (!link->hpd_status)
+ reset_bw_alloc_struct(link);
+
+ return ret;
+}
+/*
+ * Read all New BW alloc configuration ex: estimated_bw, allocated_bw,
+ * granuality, Driver_ID, CM_Group, & populate the BW allocation structs
+ * for host router and dpia
+ */
+static void init_usb4_bw_struct(struct dc_link *link)
+{
+ // Init the known values
+ link->dpia_bw_alloc_config.bw_granularity = get_bw_granularity(link);
+ link->dpia_bw_alloc_config.estimated_bw = get_estimated_bw(link);
+}
+static uint8_t get_lowest_dpia_index(struct dc_link *link)
+{
+ const struct dc *dc_struct = link->dc;
+ uint8_t idx = 0xFF;
+
+ for (int i = 0; i < MAX_PIPES * 2; ++i) {
+
+ if (!dc_struct->links[i] ||
+ dc_struct->links[i]->ep_type != DISPLAY_ENDPOINT_USB4_DPIA)
+ continue;
+
+ if (idx > dc_struct->links[i]->link_index)
+ idx = dc_struct->links[i]->link_index;
+ }
+
+ return idx;
+}
+/*
+ * Get the Max Available BW or Max Estimated BW for each Host Router
+ *
+ * @link: pointer to the dc_link struct instance
+ * @type: ESTIMATD BW or MAX AVAILABLE BW
+ *
+ * return: response_ready flag from dc_link struct
+ */
+static int get_host_router_total_bw(struct dc_link *link, uint8_t type)
+{
+ const struct dc *dc_struct = link->dc;
+ uint8_t lowest_dpia_index = get_lowest_dpia_index(link);
+ uint8_t idx = (link->link_index - lowest_dpia_index) / 2, idx_temp = 0;
+ struct dc_link *link_temp;
+ int total_bw = 0;
+
+ for (int i = 0; i < MAX_PIPES * 2; ++i) {
+
+ if (!dc_struct->links[i] || dc_struct->links[i]->ep_type != DISPLAY_ENDPOINT_USB4_DPIA)
+ continue;
+
+ link_temp = dc_struct->links[i];
+ if (!link_temp || !link_temp->hpd_status)
+ continue;
+
+ idx_temp = (link_temp->link_index - lowest_dpia_index) / 2;
+
+ if (idx_temp == idx) {
+
+ if (type == HOST_ROUTER_BW_ESTIMATED)
+ total_bw += link_temp->dpia_bw_alloc_config.estimated_bw;
+ else if (type == HOST_ROUTER_BW_ALLOCATED)
+ total_bw += link_temp->dpia_bw_alloc_config.sink_allocated_bw;
+ }
+ }
+
+ return total_bw;
+}
+/*
+ * Cleanup function for when the dpia is unplugged to reset struct
+ * and perform any required clean up
+ *
+ * @link: pointer to the dc_link struct instance
+ *
+ * return: none
+ */
+static bool dpia_bw_alloc_unplug(struct dc_link *link)
+{
+ bool ret = false;
+
+ if (!link)
+ return true;
+
+ return deallocate_usb4_bw(&link->dpia_bw_alloc_config.sink_allocated_bw,
+ link->dpia_bw_alloc_config.sink_allocated_bw, link);
+}
+static void dc_link_set_usb4_req_bw_req(struct dc_link *link, int req_bw)
+{
+ uint8_t requested_bw;
+ uint32_t temp;
+
+ // 1. Add check for this corner case #1
+ if (req_bw > link->dpia_bw_alloc_config.estimated_bw)
+ req_bw = link->dpia_bw_alloc_config.estimated_bw;
+
+ temp = req_bw * link->dpia_bw_alloc_config.bw_granularity;
+ requested_bw = temp / Kbps_TO_Gbps;
+
+ // Always make sure to add more to account for floating points
+ if (temp % Kbps_TO_Gbps)
+ ++requested_bw;
+
+ // 2. Add check for this corner case #2
+ req_bw = requested_bw * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity);
+ if (req_bw == link->dpia_bw_alloc_config.sink_allocated_bw)
+ return;
+
+ if (core_link_write_dpcd(
+ link,
+ REQUESTED_BW,
+ &requested_bw,
+ sizeof(uint8_t)) != DC_OK)
+ dm_output_to_console("%s: AUX W/R ERROR @ 0x%x\n", __func__, REQUESTED_BW);
+ else
+ link->dpia_bw_alloc_config.response_ready = false; // Reset flag
+}
+/*
+ * Return the response_ready flag from dc_link struct
+ *
+ * @link: pointer to the dc_link struct instance
+ *
+ * return: response_ready flag from dc_link struct
+ */
+static bool get_cm_response_ready_flag(struct dc_link *link)
+{
+ return link->dpia_bw_alloc_config.response_ready;
+}
+// ------------------------------------------------------------------
+// PUBLIC FUNCTIONS
+// ------------------------------------------------------------------
+bool set_dptx_usb4_bw_alloc_support(struct dc_link *link)
+{
+ bool ret = false;
+ uint8_t response = 0,
+ bw_support_dpia = 0,
+ bw_support_cm = 0;
+
+ if (!(link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA && link->hpd_status))
+ goto out;
+
+ if (core_link_read_dpcd(
+ link,
+ DP_TUNNELING_CAPABILITIES,
+ &response,
+ sizeof(uint8_t)) != DC_OK)
+ dm_output_to_console("%s: AUX W/R ERROR @ 0x%x\n", __func__, DP_TUNNELING_CAPABILITIES);
+
+ bw_support_dpia = (response >> 7) & 1;
+
+ if (core_link_read_dpcd(
+ link,
+ USB4_DRIVER_BW_CAPABILITY,
+ &response,
+ sizeof(uint8_t)) != DC_OK)
+ dm_output_to_console("%s: AUX W/R ERROR @ 0x%x\n", __func__, DP_TUNNELING_CAPABILITIES);
+
+ bw_support_cm = (response >> 7) & 1;
+
+ /* Send request acknowledgment to Turn ON DPTX support */
+ if (bw_support_cm && bw_support_dpia) {
+
+ response = 0x80;
+ if (core_link_write_dpcd(
+ link,
+ DPTX_BW_ALLOCATION_MODE_CONTROL,
+ &response,
+ sizeof(uint8_t)) != DC_OK)
+ dm_output_to_console("%s: AUX W/R ERROR @ 0x%x\n",
+ "**** FAILURE Enabling DPtx BW Allocation Mode Support ***\n",
+ __func__, DP_TUNNELING_CAPABILITIES);
+ else {
+
+ // SUCCESS Enabled DPtx BW Allocation Mode Support
+ link->dpia_bw_alloc_config.bw_alloc_enabled = true;
+ dm_output_to_console("**** SUCCESS Enabling DPtx BW Allocation Mode Support ***\n");
+
+ ret = true;
+ init_usb4_bw_struct(link);
+ }
+ }
+
+out:
+ return ret;
+}
+void dc_link_get_usb4_req_bw_resp(struct dc_link *link, uint8_t bw, uint8_t result)
+{
+ if (!get_bw_alloc_proceed_flag((link)))
+ return;
+
+ switch (result) {
+
+ case DPIA_BW_REQ_FAILED:
+
+ dm_output_to_console("%s: *** *** BW REQ FAILURE for DP-TX Request *** ***\n", __func__);
+
+ // Update the new Estimated BW value updated by CM
+ link->dpia_bw_alloc_config.estimated_bw =
+ bw * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity);
+
+ dc_link_set_usb4_req_bw_req(link, link->dpia_bw_alloc_config.estimated_bw);
+ link->dpia_bw_alloc_config.response_ready = false;
+
+ /*
+ * If FAIL then it is either:
+ * 1. Due to DP-Tx trying to allocate more than available i.e. it failed locally
+ * => get estimated and allocate that
+ * 2. Due to the fact that DP-Tx tried to allocated ESTIMATED BW and failed then
+ * CM will have to update 0xE0023 with new ESTIMATED BW value.
+ */
+ break;
+
+ case DPIA_BW_REQ_SUCCESS:
+
+ dm_output_to_console("%s: *** BW REQ SUCCESS for DP-TX Request ***\n", __func__);
+
+ // 1. SUCCESS 1st time before any Pruning is done
+ // 2. SUCCESS after prev. FAIL before any Pruning is done
+ // 3. SUCCESS after Pruning is done but before enabling link
+
+ int needed = bw * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity);
+
+ // 1.
+ if (!link->dpia_bw_alloc_config.sink_allocated_bw) {
+
+ allocate_usb4_bw(&link->dpia_bw_alloc_config.sink_allocated_bw, needed, link);
+ link->dpia_bw_alloc_config.sink_verified_bw =
+ link->dpia_bw_alloc_config.sink_allocated_bw;
+
+ // SUCCESS from first attempt
+ if (link->dpia_bw_alloc_config.sink_allocated_bw >
+ link->dpia_bw_alloc_config.sink_max_bw)
+ link->dpia_bw_alloc_config.sink_verified_bw =
+ link->dpia_bw_alloc_config.sink_max_bw;
+ }
+ // 3.
+ else if (link->dpia_bw_alloc_config.sink_allocated_bw) {
+
+ // Find out how much do we need to de-alloc
+ if (link->dpia_bw_alloc_config.sink_allocated_bw > needed)
+ deallocate_usb4_bw(&link->dpia_bw_alloc_config.sink_allocated_bw,
+ link->dpia_bw_alloc_config.sink_allocated_bw - needed, link);
+ else
+ allocate_usb4_bw(&link->dpia_bw_alloc_config.sink_allocated_bw,
+ needed - link->dpia_bw_alloc_config.sink_allocated_bw, link);
+ }
+
+ // 4. If this is the 2nd sink then any unused bw will be reallocated to master DPIA
+ // => check if estimated_bw changed
+
+ link->dpia_bw_alloc_config.response_ready = true;
+ break;
+
+ case DPIA_EST_BW_CHANGED:
+
+ dm_output_to_console("%s: *** ESTIMATED BW CHANGED for DP-TX Request ***\n", __func__);
+
+ int available = 0, estimated = bw * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity);
+ int host_router_total_estimated_bw = get_host_router_total_bw(link, HOST_ROUTER_BW_ESTIMATED);
+
+ // 1. If due to unplug of other sink
+ if (estimated == host_router_total_estimated_bw) {
+
+ // First update the estimated & max_bw fields
+ if (link->dpia_bw_alloc_config.estimated_bw < estimated) {
+ available = estimated - link->dpia_bw_alloc_config.estimated_bw;
+ link->dpia_bw_alloc_config.estimated_bw = estimated;
+ }
+ }
+ // 2. If due to realloc bw btw 2 dpia due to plug OR realloc unused Bw
+ else {
+
+ // We took from another unplugged/problematic sink to give to us
+ if (link->dpia_bw_alloc_config.estimated_bw < estimated)
+ available = estimated - link->dpia_bw_alloc_config.estimated_bw;
+
+ // We lost estimated bw usually due to plug event of other dpia
+ link->dpia_bw_alloc_config.estimated_bw = estimated;
+ }
+ break;
+
+ case DPIA_BW_ALLOC_CAPS_CHANGED:
+
+ dm_output_to_console("%s: *** BW ALLOC CAPABILITY CHANGED for DP-TX Request ***\n", __func__);
+ link->dpia_bw_alloc_config.bw_alloc_enabled = false;
+ break;
+ }
+}
+int dc_link_dp_dpia_handle_usb4_bandwidth_allocation_for_link(struct dc_link *link, int peak_bw)
+{
+ int ret = 0;
+ uint8_t timeout = 10;
+
+ if (!(link && DISPLAY_ENDPOINT_USB4_DPIA == link->ep_type
+ && link->dpia_bw_alloc_config.bw_alloc_enabled))
+ goto out;
+
+ //1. Hot Plug
+ if (link->hpd_status && peak_bw > 0) {
+
+ // If DP over USB4 then we need to check BW allocation
+ link->dpia_bw_alloc_config.sink_max_bw = peak_bw;
+ dc_link_set_usb4_req_bw_req(link, link->dpia_bw_alloc_config.sink_max_bw);
+
+ do {
+ if (!timeout > 0)
+ timeout--;
+ else
+ break;
+ udelay(10 * 1000);
+ } while (!get_cm_response_ready_flag(link));
+
+ if (!timeout)
+ ret = 0;// ERROR TIMEOUT waiting for response for allocating bw
+ else if (link->dpia_bw_alloc_config.sink_allocated_bw > 0)
+ ret = get_host_router_total_bw(link, HOST_ROUTER_BW_ALLOCATED);
+ }
+ //2. Cold Unplug
+ else if (!link->hpd_status)
+ dpia_bw_alloc_unplug(link);
+
+out:
+ return ret;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_dpia_bw.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.h
index 669e995f825f..c2c3049adcd1 100644
--- a/drivers/gpu/drm/amd/display/dc/link/link_dp_dpia_bw.h
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.h
@@ -26,13 +26,13 @@
#ifndef DC_INC_LINK_DP_DPIA_BW_H_
#define DC_INC_LINK_DP_DPIA_BW_H_
-// XXX: TODO: Re-add for Phase 2
-/* Number of Host Routers per motherboard is 2 and 2 DPIA per host router */
-#define MAX_HR_NUM 2
-
-struct dc_host_router_bw_alloc {
- int max_bw[MAX_HR_NUM]; // The Max BW that each Host Router has available to be shared btw DPIAs
- int total_estimated_bw[MAX_HR_NUM]; // The Total Verified and available BW that Host Router has
+/*
+ * Host Router BW type
+ */
+enum bw_type {
+ HOST_ROUTER_BW_ESTIMATED,
+ HOST_ROUTER_BW_ALLOCATED,
+ HOST_ROUTER_BW_INVALID,
};
/*
@@ -44,26 +44,4 @@ struct dc_host_router_bw_alloc {
*/
bool set_dptx_usb4_bw_alloc_support(struct dc_link *link);
-/*
- * Send a request from DP-Tx requesting to allocate BW remotely after
- * allocating it locally. This will get processed by CM and a CB function
- * will be called.
- *
- * @link: pointer to the dc_link struct instance
- * @req_bw: The requested bw in Kbyte to allocated
- *
- * return: none
- */
-void set_usb4_req_bw_req(struct dc_link *link, int req_bw);
-
-/*
- * CB function for when the status of the Req above is complete. We will
- * find out the result of allocating on CM and update structs accordingly
- *
- * @link: pointer to the dc_link struct instance
- *
- * return: none
- */
-void get_usb4_req_bw_resp(struct dc_link *link);
-
#endif /* DC_INC_LINK_DP_DPIA_BW_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c
new file mode 100644
index 000000000000..9d80427520cf
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c
@@ -0,0 +1,389 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+
+/* FILE POLICY AND INTENDED USAGE:
+ * This file implements DP HPD short pulse handling sequence according to DP
+ * specifications
+ *
+ */
+
+#include "link_dp_irq_handler.h"
+#include "link_dpcd.h"
+#include "link_dp_training.h"
+#include "link_dp_capability.h"
+#include "link/accessories/link_dp_trace.h"
+#include "link/link_dpms.h"
+#include "dm_helpers.h"
+
+#define DC_LOGGER_INIT(logger)
+
+bool dc_link_check_link_loss_status(
+ struct dc_link *link,
+ union hpd_irq_data *hpd_irq_dpcd_data)
+{
+ uint8_t irq_reg_rx_power_state = 0;
+ enum dc_status dpcd_result = DC_ERROR_UNEXPECTED;
+ union lane_status lane_status;
+ uint32_t lane;
+ bool sink_status_changed;
+ bool return_code;
+
+ sink_status_changed = false;
+ return_code = false;
+
+ if (link->cur_link_settings.lane_count == 0)
+ return return_code;
+
+ /*1. Check that Link Status changed, before re-training.*/
+
+ /*parse lane status*/
+ for (lane = 0; lane < link->cur_link_settings.lane_count; lane++) {
+ /* check status of lanes 0,1
+ * changed DpcdAddress_Lane01Status (0x202)
+ */
+ lane_status.raw = dp_get_nibble_at_index(
+ &hpd_irq_dpcd_data->bytes.lane01_status.raw,
+ lane);
+
+ if (!lane_status.bits.CHANNEL_EQ_DONE_0 ||
+ !lane_status.bits.CR_DONE_0 ||
+ !lane_status.bits.SYMBOL_LOCKED_0) {
+ /* if one of the channel equalization, clock
+ * recovery or symbol lock is dropped
+ * consider it as (link has been
+ * dropped) dp sink status has changed
+ */
+ sink_status_changed = true;
+ break;
+ }
+ }
+
+ /* Check interlane align.*/
+ if (sink_status_changed ||
+ !hpd_irq_dpcd_data->bytes.lane_status_updated.bits.INTERLANE_ALIGN_DONE) {
+
+ DC_LOG_HW_HPD_IRQ("%s: Link Status changed.\n", __func__);
+
+ return_code = true;
+
+ /*2. Check that we can handle interrupt: Not in FS DOS,
+ * Not in "Display Timeout" state, Link is trained.
+ */
+ dpcd_result = core_link_read_dpcd(link,
+ DP_SET_POWER,
+ &irq_reg_rx_power_state,
+ sizeof(irq_reg_rx_power_state));
+
+ if (dpcd_result != DC_OK) {
+ DC_LOG_HW_HPD_IRQ("%s: DPCD read failed to obtain power state.\n",
+ __func__);
+ } else {
+ if (irq_reg_rx_power_state != DP_SET_POWER_D0)
+ return_code = false;
+ }
+ }
+
+ return return_code;
+}
+
+static bool handle_hpd_irq_psr_sink(struct dc_link *link)
+{
+ union dpcd_psr_configuration psr_configuration;
+
+ if (!link->psr_settings.psr_feature_enabled)
+ return false;
+
+ dm_helpers_dp_read_dpcd(
+ link->ctx,
+ link,
+ 368,/*DpcdAddress_PSR_Enable_Cfg*/
+ &psr_configuration.raw,
+ sizeof(psr_configuration.raw));
+
+ if (psr_configuration.bits.ENABLE) {
+ unsigned char dpcdbuf[3] = {0};
+ union psr_error_status psr_error_status;
+ union psr_sink_psr_status psr_sink_psr_status;
+
+ dm_helpers_dp_read_dpcd(
+ link->ctx,
+ link,
+ 0x2006, /*DpcdAddress_PSR_Error_Status*/
+ (unsigned char *) dpcdbuf,
+ sizeof(dpcdbuf));
+
+ /*DPCD 2006h ERROR STATUS*/
+ psr_error_status.raw = dpcdbuf[0];
+ /*DPCD 2008h SINK PANEL SELF REFRESH STATUS*/
+ psr_sink_psr_status.raw = dpcdbuf[2];
+
+ if (psr_error_status.bits.LINK_CRC_ERROR ||
+ psr_error_status.bits.RFB_STORAGE_ERROR ||
+ psr_error_status.bits.VSC_SDP_ERROR) {
+ bool allow_active;
+
+ /* Acknowledge and clear error bits */
+ dm_helpers_dp_write_dpcd(
+ link->ctx,
+ link,
+ 8198,/*DpcdAddress_PSR_Error_Status*/
+ &psr_error_status.raw,
+ sizeof(psr_error_status.raw));
+
+ /* PSR error, disable and re-enable PSR */
+ if (link->psr_settings.psr_allow_active) {
+ allow_active = false;
+ dc_link_set_psr_allow_active(link, &allow_active, true, false, NULL);
+ allow_active = true;
+ dc_link_set_psr_allow_active(link, &allow_active, true, false, NULL);
+ }
+
+ return true;
+ } else if (psr_sink_psr_status.bits.SINK_SELF_REFRESH_STATUS ==
+ PSR_SINK_STATE_ACTIVE_DISPLAY_FROM_SINK_RFB){
+ /* No error is detect, PSR is active.
+ * We should return with IRQ_HPD handled without
+ * checking for loss of sync since PSR would have
+ * powered down main link.
+ */
+ return true;
+ }
+ }
+ return false;
+}
+
+void dc_link_dp_handle_link_loss(struct dc_link *link)
+{
+ struct pipe_ctx *pipes[MAX_PIPES];
+ struct dc_state *state = link->dc->current_state;
+ uint8_t count;
+ int i;
+
+ link_get_master_pipes_with_dpms_on(link, state, &count, pipes);
+
+ for (i = 0; i < count; i++)
+ link_set_dpms_off(pipes[i]);
+
+ for (i = count - 1; i >= 0; i--) {
+ // Always use max settings here for DP 1.4a LL Compliance CTS
+ if (link->is_automated) {
+ pipes[i]->link_config.dp_link_settings.lane_count =
+ link->verified_link_cap.lane_count;
+ pipes[i]->link_config.dp_link_settings.link_rate =
+ link->verified_link_cap.link_rate;
+ pipes[i]->link_config.dp_link_settings.link_spread =
+ link->verified_link_cap.link_spread;
+ }
+ link_set_dpms_on(link->dc->current_state, pipes[i]);
+ }
+}
+
+enum dc_status dc_link_dp_read_hpd_rx_irq_data(
+ struct dc_link *link,
+ union hpd_irq_data *irq_data)
+{
+ static enum dc_status retval;
+
+ /* The HW reads 16 bytes from 200h on HPD,
+ * but if we get an AUX_DEFER, the HW cannot retry
+ * and this causes the CTS tests 4.3.2.1 - 3.2.4 to
+ * fail, so we now explicitly read 6 bytes which is
+ * the req from the above mentioned test cases.
+ *
+ * For DP 1.4 we need to read those from 2002h range.
+ */
+ if (link->dpcd_caps.dpcd_rev.raw < DPCD_REV_14)
+ retval = core_link_read_dpcd(
+ link,
+ DP_SINK_COUNT,
+ irq_data->raw,
+ sizeof(union hpd_irq_data));
+ else {
+ /* Read 14 bytes in a single read and then copy only the required fields.
+ * This is more efficient than doing it in two separate AUX reads. */
+
+ uint8_t tmp[DP_SINK_STATUS_ESI - DP_SINK_COUNT_ESI + 1];
+
+ retval = core_link_read_dpcd(
+ link,
+ DP_SINK_COUNT_ESI,
+ tmp,
+ sizeof(tmp));
+
+ if (retval != DC_OK)
+ return retval;
+
+ irq_data->bytes.sink_cnt.raw = tmp[DP_SINK_COUNT_ESI - DP_SINK_COUNT_ESI];
+ irq_data->bytes.device_service_irq.raw = tmp[DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0 - DP_SINK_COUNT_ESI];
+ irq_data->bytes.lane01_status.raw = tmp[DP_LANE0_1_STATUS_ESI - DP_SINK_COUNT_ESI];
+ irq_data->bytes.lane23_status.raw = tmp[DP_LANE2_3_STATUS_ESI - DP_SINK_COUNT_ESI];
+ irq_data->bytes.lane_status_updated.raw = tmp[DP_LANE_ALIGN_STATUS_UPDATED_ESI - DP_SINK_COUNT_ESI];
+ irq_data->bytes.sink_status.raw = tmp[DP_SINK_STATUS_ESI - DP_SINK_COUNT_ESI];
+ }
+
+ return retval;
+}
+
+/*************************Short Pulse IRQ***************************/
+bool dc_link_dp_allow_hpd_rx_irq(const struct dc_link *link)
+{
+ /*
+ * Don't handle RX IRQ unless one of following is met:
+ * 1) The link is established (cur_link_settings != unknown)
+ * 2) We know we're dealing with a branch device, SST or MST
+ */
+
+ if ((link->cur_link_settings.lane_count != LANE_COUNT_UNKNOWN) ||
+ is_dp_branch_device(link))
+ return true;
+
+ return false;
+}
+
+bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd_irq_dpcd_data, bool *out_link_loss,
+ bool defer_handling, bool *has_left_work)
+{
+ union hpd_irq_data hpd_irq_dpcd_data = {0};
+ union device_service_irq device_service_clear = {0};
+ enum dc_status result;
+ bool status = false;
+
+ if (out_link_loss)
+ *out_link_loss = false;
+
+ if (has_left_work)
+ *has_left_work = false;
+ /* For use cases related to down stream connection status change,
+ * PSR and device auto test, refer to function handle_sst_hpd_irq
+ * in DAL2.1*/
+
+ DC_LOG_HW_HPD_IRQ("%s: Got short pulse HPD on link %d\n",
+ __func__, link->link_index);
+
+
+ /* All the "handle_hpd_irq_xxx()" methods
+ * should be called only after
+ * dal_dpsst_ls_read_hpd_irq_data
+ * Order of calls is important too
+ */
+ result = dc_link_dp_read_hpd_rx_irq_data(link, &hpd_irq_dpcd_data);
+ if (out_hpd_irq_dpcd_data)
+ *out_hpd_irq_dpcd_data = hpd_irq_dpcd_data;
+
+ if (result != DC_OK) {
+ DC_LOG_HW_HPD_IRQ("%s: DPCD read failed to obtain irq data\n",
+ __func__);
+ return false;
+ }
+
+ if (hpd_irq_dpcd_data.bytes.device_service_irq.bits.AUTOMATED_TEST) {
+ // Workaround for DP 1.4a LL Compliance CTS as USB4 has to share encoders unlike DP and USBC
+ link->is_automated = true;
+ device_service_clear.bits.AUTOMATED_TEST = 1;
+ core_link_write_dpcd(
+ link,
+ DP_DEVICE_SERVICE_IRQ_VECTOR,
+ &device_service_clear.raw,
+ sizeof(device_service_clear.raw));
+ device_service_clear.raw = 0;
+ if (defer_handling && has_left_work)
+ *has_left_work = true;
+ else
+ dc_link_dp_handle_automated_test(link);
+ return false;
+ }
+
+ if (!dc_link_dp_allow_hpd_rx_irq(link)) {
+ DC_LOG_HW_HPD_IRQ("%s: skipping HPD handling on %d\n",
+ __func__, link->link_index);
+ return false;
+ }
+
+ if (handle_hpd_irq_psr_sink(link))
+ /* PSR-related error was detected and handled */
+ return true;
+
+ /* If PSR-related error handled, Main link may be off,
+ * so do not handle as a normal sink status change interrupt.
+ */
+
+ if (hpd_irq_dpcd_data.bytes.device_service_irq.bits.UP_REQ_MSG_RDY) {
+ if (defer_handling && has_left_work)
+ *has_left_work = true;
+ return true;
+ }
+
+ /* check if we have MST msg and return since we poll for it */
+ if (hpd_irq_dpcd_data.bytes.device_service_irq.bits.DOWN_REP_MSG_RDY) {
+ if (defer_handling && has_left_work)
+ *has_left_work = true;
+ return false;
+ }
+
+ /* For now we only handle 'Downstream port status' case.
+ * If we got sink count changed it means
+ * Downstream port status changed,
+ * then DM should call DC to do the detection.
+ * NOTE: Do not handle link loss on eDP since it is internal link*/
+ if ((link->connector_signal != SIGNAL_TYPE_EDP) &&
+ dc_link_check_link_loss_status(
+ link,
+ &hpd_irq_dpcd_data)) {
+ /* Connectivity log: link loss */
+ CONN_DATA_LINK_LOSS(link,
+ hpd_irq_dpcd_data.raw,
+ sizeof(hpd_irq_dpcd_data),
+ "Status: ");
+
+ if (defer_handling && has_left_work)
+ *has_left_work = true;
+ else
+ dc_link_dp_handle_link_loss(link);
+
+ status = false;
+ if (out_link_loss)
+ *out_link_loss = true;
+
+ dp_trace_link_loss_increment(link);
+ }
+
+ if (link->type == dc_connection_sst_branch &&
+ hpd_irq_dpcd_data.bytes.sink_cnt.bits.SINK_COUNT
+ != link->dpcd_sink_count)
+ status = true;
+
+ /* reasons for HPD RX:
+ * 1. Link Loss - ie Re-train the Link
+ * 2. MST sideband message
+ * 3. Automated Test - ie. Internal Commit
+ * 4. CP (copy protection) - (not interesting for DM???)
+ * 5. DRR
+ * 6. Downstream Port status changed
+ * -ie. Detect - this the only one
+ * which is interesting for DM because
+ * it must call dc_link_detect.
+ */
+ return status;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_dpia_bw.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.h
index 801a95b34e8c..39b2e51ea79d 100644
--- a/drivers/gpu/drm/amd/display/dc/link/link_dp_dpia_bw.c
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.h
@@ -1,4 +1,3 @@
-
/*
* Copyright 2022 Advanced Micro Devices, Inc.
*
@@ -23,6 +22,10 @@
* Authors: AMD
*
*/
-/*********************************************************************/
-// USB4 DPIA BANDWIDTH ALLOCATION LOGIC
-/*********************************************************************/
+
+#ifndef __DC_LINK_DP_IRQ_HANDLER_H__
+#define __DC_LINK_DP_IRQ_HANDLER_H__
+
+#include "link.h"
+
+#endif /* __DC_LINK_DP_IRQ_HANDLER_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.c
new file mode 100644
index 000000000000..cd9fb8126bcf
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+
+/* FILE POLICY AND INTENDED USAGE:
+ * This file implements basic dp phy functionality such as enable/disable phy
+ * output and set lane/drive settings. This file is responsible for maintaining
+ * and update software state representing current phy status such as current
+ * link settings.
+ */
+
+#include "link_dp_phy.h"
+#include "link_dpcd.h"
+#include "link_dp_training.h"
+#include "link_dp_capability.h"
+#include "clk_mgr.h"
+#include "resource.h"
+#include "link_enc_cfg.h"
+#define DC_LOGGER \
+ link->ctx->logger
+
+void dc_link_dp_receiver_power_ctrl(struct dc_link *link, bool on)
+{
+ uint8_t state;
+
+ state = on ? DP_POWER_STATE_D0 : DP_POWER_STATE_D3;
+
+ if (link->sync_lt_in_progress)
+ return;
+
+ core_link_write_dpcd(link, DP_SET_POWER, &state,
+ sizeof(state));
+
+}
+
+void dp_enable_link_phy(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ enum signal_type signal,
+ enum clock_source_id clock_source,
+ const struct dc_link_settings *link_settings)
+{
+ link->cur_link_settings = *link_settings;
+ link->dc->hwss.enable_dp_link_output(link, link_res, signal,
+ clock_source, link_settings);
+ dc_link_dp_receiver_power_ctrl(link, true);
+}
+
+void dp_disable_link_phy(struct dc_link *link,
+ const struct link_resource *link_res,
+ enum signal_type signal)
+{
+ struct dc *dc = link->ctx->dc;
+
+ if (!link->wa_flags.dp_keep_receiver_powered)
+ dc_link_dp_receiver_power_ctrl(link, false);
+
+ dc->hwss.disable_link_output(link, link_res, signal);
+ /* Clear current link setting.*/
+ memset(&link->cur_link_settings, 0,
+ sizeof(link->cur_link_settings));
+
+ if (dc->clk_mgr->funcs->notify_link_rate_change)
+ dc->clk_mgr->funcs->notify_link_rate_change(dc->clk_mgr, link);
+}
+
+static inline bool is_immediate_downstream(struct dc_link *link, uint32_t offset)
+{
+ return (dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) ==
+ offset);
+}
+
+void dp_set_hw_lane_settings(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ const struct link_training_settings *link_settings,
+ uint32_t offset)
+{
+ const struct link_hwss *link_hwss = get_link_hwss(link, link_res);
+
+ if ((link_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) &&
+ !is_immediate_downstream(link, offset))
+ return;
+
+ if (link_hwss->ext.set_dp_lane_settings)
+ link_hwss->ext.set_dp_lane_settings(link, link_res,
+ &link_settings->link_settings,
+ link_settings->hw_lane_settings);
+
+ memmove(link->cur_lane_setting,
+ link_settings->hw_lane_settings,
+ sizeof(link->cur_lane_setting));
+}
+
+void dp_set_drive_settings(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ struct link_training_settings *lt_settings)
+{
+ /* program ASIC PHY settings*/
+ dp_set_hw_lane_settings(link, link_res, lt_settings, DPRX);
+
+ dp_hw_to_dpcd_lane_settings(lt_settings,
+ lt_settings->hw_lane_settings,
+ lt_settings->dpcd_lane_settings);
+
+ /* Notify DP sink the PHY settings from source */
+ dpcd_set_lane_settings(link, lt_settings, DPRX);
+}
+
+enum dc_status dp_set_fec_ready(struct dc_link *link, const struct link_resource *link_res, bool ready)
+{
+ /* FEC has to be "set ready" before the link training.
+ * The policy is to always train with FEC
+ * if the sink supports it and leave it enabled on link.
+ * If FEC is not supported, disable it.
+ */
+ struct link_encoder *link_enc = NULL;
+ enum dc_status status = DC_OK;
+ uint8_t fec_config = 0;
+
+ link_enc = link_enc_cfg_get_link_enc(link);
+ ASSERT(link_enc);
+
+ if (!dc_link_should_enable_fec(link))
+ return status;
+
+ if (link_enc->funcs->fec_set_ready &&
+ link->dpcd_caps.fec_cap.bits.FEC_CAPABLE) {
+ if (ready) {
+ fec_config = 1;
+ status = core_link_write_dpcd(link,
+ DP_FEC_CONFIGURATION,
+ &fec_config,
+ sizeof(fec_config));
+ if (status == DC_OK) {
+ link_enc->funcs->fec_set_ready(link_enc, true);
+ link->fec_state = dc_link_fec_ready;
+ } else {
+ link_enc->funcs->fec_set_ready(link_enc, false);
+ link->fec_state = dc_link_fec_not_ready;
+ dm_error("dpcd write failed to set fec_ready");
+ }
+ } else if (link->fec_state == dc_link_fec_ready) {
+ fec_config = 0;
+ status = core_link_write_dpcd(link,
+ DP_FEC_CONFIGURATION,
+ &fec_config,
+ sizeof(fec_config));
+ link_enc->funcs->fec_set_ready(link_enc, false);
+ link->fec_state = dc_link_fec_not_ready;
+ }
+ }
+
+ return status;
+}
+
+void dp_set_fec_enable(struct dc_link *link, bool enable)
+{
+ struct link_encoder *link_enc = NULL;
+
+ link_enc = link_enc_cfg_get_link_enc(link);
+ ASSERT(link_enc);
+
+ if (!dc_link_should_enable_fec(link))
+ return;
+
+ if (link_enc->funcs->fec_set_enable &&
+ link->dpcd_caps.fec_cap.bits.FEC_CAPABLE) {
+ if (link->fec_state == dc_link_fec_ready && enable) {
+ /* Accord to DP spec, FEC enable sequence can first
+ * be transmitted anytime after 1000 LL codes have
+ * been transmitted on the link after link training
+ * completion. Using 1 lane RBR should have the maximum
+ * time for transmitting 1000 LL codes which is 6.173 us.
+ * So use 7 microseconds delay instead.
+ */
+ udelay(7);
+ link_enc->funcs->fec_set_enable(link_enc, true);
+ link->fec_state = dc_link_fec_enabled;
+ } else if (link->fec_state == dc_link_fec_enabled && !enable) {
+ link_enc->funcs->fec_set_enable(link_enc, false);
+ link->fec_state = dc_link_fec_ready;
+ }
+ }
+}
+
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.h
new file mode 100644
index 000000000000..dba1f29df319
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DC_LINK_DP_PHY_H__
+#define __DC_LINK_DP_PHY_H__
+
+#include "link.h"
+void dp_enable_link_phy(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ enum signal_type signal,
+ enum clock_source_id clock_source,
+ const struct dc_link_settings *link_settings);
+
+void dp_disable_link_phy(struct dc_link *link,
+ const struct link_resource *link_res,
+ enum signal_type signal);
+
+void dp_set_hw_lane_settings(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ const struct link_training_settings *link_settings,
+ uint32_t offset);
+
+void dp_set_drive_settings(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ struct link_training_settings *lt_settings);
+
+enum dc_status dp_set_fec_ready(struct dc_link *link,
+ const struct link_resource *link_res, bool ready);
+void dp_set_fec_enable(struct dc_link *link, bool enable);
+
+#endif /* __DC_LINK_DP_PHY_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c
new file mode 100644
index 000000000000..b48d4d822991
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c
@@ -0,0 +1,1701 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+
+/* FILE POLICY AND INTENDED USAGE:
+ * This file implements all generic dp link training helper functions and top
+ * level generic training sequence. All variations of dp link training sequence
+ * should be called inside the top level training functions in this file to
+ * ensure the integrity of our overall training procedure across different types
+ * of link encoding and back end hardware.
+ */
+#include "link_dp_training.h"
+#include "link_dp_training_8b_10b.h"
+#include "link_dp_training_128b_132b.h"
+#include "link_dp_training_auxless.h"
+#include "link_dp_training_dpia.h"
+#include "link_dp_training_fixed_vs_pe_retimer.h"
+#include "link_dpcd.h"
+#include "link/accessories/link_dp_trace.h"
+#include "link_dp_phy.h"
+#include "link_dp_capability.h"
+#include "link_edp_panel_control.h"
+#include "atomfirmware.h"
+#include "link_enc_cfg.h"
+#include "resource.h"
+#include "dm_helpers.h"
+
+#define DC_LOGGER \
+ link->ctx->logger
+
+#define POST_LT_ADJ_REQ_LIMIT 6
+#define POST_LT_ADJ_REQ_TIMEOUT 200
+#define LINK_TRAINING_RETRY_DELAY 50 /* ms */
+
+void dp_log_training_result(
+ struct dc_link *link,
+ const struct link_training_settings *lt_settings,
+ enum link_training_result status)
+{
+ char *link_rate = "Unknown";
+ char *lt_result = "Unknown";
+ char *lt_spread = "Disabled";
+
+ switch (lt_settings->link_settings.link_rate) {
+ case LINK_RATE_LOW:
+ link_rate = "RBR";
+ break;
+ case LINK_RATE_RATE_2:
+ link_rate = "R2";
+ break;
+ case LINK_RATE_RATE_3:
+ link_rate = "R3";
+ break;
+ case LINK_RATE_HIGH:
+ link_rate = "HBR";
+ break;
+ case LINK_RATE_RBR2:
+ link_rate = "RBR2";
+ break;
+ case LINK_RATE_RATE_6:
+ link_rate = "R6";
+ break;
+ case LINK_RATE_HIGH2:
+ link_rate = "HBR2";
+ break;
+ case LINK_RATE_HIGH3:
+ link_rate = "HBR3";
+ break;
+ case LINK_RATE_UHBR10:
+ link_rate = "UHBR10";
+ break;
+ case LINK_RATE_UHBR13_5:
+ link_rate = "UHBR13.5";
+ break;
+ case LINK_RATE_UHBR20:
+ link_rate = "UHBR20";
+ break;
+ default:
+ break;
+ }
+
+ switch (status) {
+ case LINK_TRAINING_SUCCESS:
+ lt_result = "pass";
+ break;
+ case LINK_TRAINING_CR_FAIL_LANE0:
+ lt_result = "CR failed lane0";
+ break;
+ case LINK_TRAINING_CR_FAIL_LANE1:
+ lt_result = "CR failed lane1";
+ break;
+ case LINK_TRAINING_CR_FAIL_LANE23:
+ lt_result = "CR failed lane23";
+ break;
+ case LINK_TRAINING_EQ_FAIL_CR:
+ lt_result = "CR failed in EQ";
+ break;
+ case LINK_TRAINING_EQ_FAIL_CR_PARTIAL:
+ lt_result = "CR failed in EQ partially";
+ break;
+ case LINK_TRAINING_EQ_FAIL_EQ:
+ lt_result = "EQ failed";
+ break;
+ case LINK_TRAINING_LQA_FAIL:
+ lt_result = "LQA failed";
+ break;
+ case LINK_TRAINING_LINK_LOSS:
+ lt_result = "Link loss";
+ break;
+ case DP_128b_132b_LT_FAILED:
+ lt_result = "LT_FAILED received";
+ break;
+ case DP_128b_132b_MAX_LOOP_COUNT_REACHED:
+ lt_result = "max loop count reached";
+ break;
+ case DP_128b_132b_CHANNEL_EQ_DONE_TIMEOUT:
+ lt_result = "channel EQ timeout";
+ break;
+ case DP_128b_132b_CDS_DONE_TIMEOUT:
+ lt_result = "CDS timeout";
+ break;
+ default:
+ break;
+ }
+
+ switch (lt_settings->link_settings.link_spread) {
+ case LINK_SPREAD_DISABLED:
+ lt_spread = "Disabled";
+ break;
+ case LINK_SPREAD_05_DOWNSPREAD_30KHZ:
+ lt_spread = "0.5% 30KHz";
+ break;
+ case LINK_SPREAD_05_DOWNSPREAD_33KHZ:
+ lt_spread = "0.5% 33KHz";
+ break;
+ default:
+ break;
+ }
+
+ /* Connectivity log: link training */
+
+ /* TODO - DP2.0 Log: add connectivity log for FFE PRESET */
+
+ CONN_MSG_LT(link, "%sx%d %s VS=%d, PE=%d, DS=%s",
+ link_rate,
+ lt_settings->link_settings.lane_count,
+ lt_result,
+ lt_settings->hw_lane_settings[0].VOLTAGE_SWING,
+ lt_settings->hw_lane_settings[0].PRE_EMPHASIS,
+ lt_spread);
+}
+
+uint8_t dp_initialize_scrambling_data_symbols(
+ struct dc_link *link,
+ enum dc_dp_training_pattern pattern)
+{
+ uint8_t disable_scrabled_data_symbols = 0;
+
+ switch (pattern) {
+ case DP_TRAINING_PATTERN_SEQUENCE_1:
+ case DP_TRAINING_PATTERN_SEQUENCE_2:
+ case DP_TRAINING_PATTERN_SEQUENCE_3:
+ disable_scrabled_data_symbols = 1;
+ break;
+ case DP_TRAINING_PATTERN_SEQUENCE_4:
+ case DP_128b_132b_TPS1:
+ case DP_128b_132b_TPS2:
+ disable_scrabled_data_symbols = 0;
+ break;
+ default:
+ ASSERT(0);
+ DC_LOG_HW_LINK_TRAINING("%s: Invalid HW Training pattern: %d\n",
+ __func__, pattern);
+ break;
+ }
+ return disable_scrabled_data_symbols;
+}
+
+enum dpcd_training_patterns
+ dp_training_pattern_to_dpcd_training_pattern(
+ struct dc_link *link,
+ enum dc_dp_training_pattern pattern)
+{
+ enum dpcd_training_patterns dpcd_tr_pattern =
+ DPCD_TRAINING_PATTERN_VIDEOIDLE;
+
+ switch (pattern) {
+ case DP_TRAINING_PATTERN_SEQUENCE_1:
+ dpcd_tr_pattern = DPCD_TRAINING_PATTERN_1;
+ break;
+ case DP_TRAINING_PATTERN_SEQUENCE_2:
+ dpcd_tr_pattern = DPCD_TRAINING_PATTERN_2;
+ break;
+ case DP_TRAINING_PATTERN_SEQUENCE_3:
+ dpcd_tr_pattern = DPCD_TRAINING_PATTERN_3;
+ break;
+ case DP_TRAINING_PATTERN_SEQUENCE_4:
+ dpcd_tr_pattern = DPCD_TRAINING_PATTERN_4;
+ break;
+ case DP_128b_132b_TPS1:
+ dpcd_tr_pattern = DPCD_128b_132b_TPS1;
+ break;
+ case DP_128b_132b_TPS2:
+ dpcd_tr_pattern = DPCD_128b_132b_TPS2;
+ break;
+ case DP_128b_132b_TPS2_CDS:
+ dpcd_tr_pattern = DPCD_128b_132b_TPS2_CDS;
+ break;
+ case DP_TRAINING_PATTERN_VIDEOIDLE:
+ dpcd_tr_pattern = DPCD_TRAINING_PATTERN_VIDEOIDLE;
+ break;
+ default:
+ ASSERT(0);
+ DC_LOG_HW_LINK_TRAINING("%s: Invalid HW Training pattern: %d\n",
+ __func__, pattern);
+ break;
+ }
+
+ return dpcd_tr_pattern;
+}
+
+uint8_t dp_get_nibble_at_index(const uint8_t *buf,
+ uint32_t index)
+{
+ uint8_t nibble;
+ nibble = buf[index / 2];
+
+ if (index % 2)
+ nibble >>= 4;
+ else
+ nibble &= 0x0F;
+
+ return nibble;
+}
+
+void dp_wait_for_training_aux_rd_interval(
+ struct dc_link *link,
+ uint32_t wait_in_micro_secs)
+{
+ if (wait_in_micro_secs > 1000)
+ msleep(wait_in_micro_secs/1000);
+ else
+ udelay(wait_in_micro_secs);
+
+ DC_LOG_HW_LINK_TRAINING("%s:\n wait = %d\n",
+ __func__,
+ wait_in_micro_secs);
+}
+
+/* maximum pre emphasis level allowed for each voltage swing level*/
+static const enum dc_pre_emphasis voltage_swing_to_pre_emphasis[] = {
+ PRE_EMPHASIS_LEVEL3,
+ PRE_EMPHASIS_LEVEL2,
+ PRE_EMPHASIS_LEVEL1,
+ PRE_EMPHASIS_DISABLED };
+
+static enum dc_pre_emphasis get_max_pre_emphasis_for_voltage_swing(
+ enum dc_voltage_swing voltage)
+{
+ enum dc_pre_emphasis pre_emphasis;
+ pre_emphasis = PRE_EMPHASIS_MAX_LEVEL;
+
+ if (voltage <= VOLTAGE_SWING_MAX_LEVEL)
+ pre_emphasis = voltage_swing_to_pre_emphasis[voltage];
+
+ return pre_emphasis;
+
+}
+
+static void maximize_lane_settings(const struct link_training_settings *lt_settings,
+ struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX])
+{
+ uint32_t lane;
+ struct dc_lane_settings max_requested;
+
+ max_requested.VOLTAGE_SWING = lane_settings[0].VOLTAGE_SWING;
+ max_requested.PRE_EMPHASIS = lane_settings[0].PRE_EMPHASIS;
+ max_requested.FFE_PRESET = lane_settings[0].FFE_PRESET;
+
+ /* Determine what the maximum of the requested settings are*/
+ for (lane = 1; lane < lt_settings->link_settings.lane_count; lane++) {
+ if (lane_settings[lane].VOLTAGE_SWING > max_requested.VOLTAGE_SWING)
+ max_requested.VOLTAGE_SWING = lane_settings[lane].VOLTAGE_SWING;
+
+ if (lane_settings[lane].PRE_EMPHASIS > max_requested.PRE_EMPHASIS)
+ max_requested.PRE_EMPHASIS = lane_settings[lane].PRE_EMPHASIS;
+ if (lane_settings[lane].FFE_PRESET.settings.level >
+ max_requested.FFE_PRESET.settings.level)
+ max_requested.FFE_PRESET.settings.level =
+ lane_settings[lane].FFE_PRESET.settings.level;
+ }
+
+ /* make sure the requested settings are
+ * not higher than maximum settings*/
+ if (max_requested.VOLTAGE_SWING > VOLTAGE_SWING_MAX_LEVEL)
+ max_requested.VOLTAGE_SWING = VOLTAGE_SWING_MAX_LEVEL;
+
+ if (max_requested.PRE_EMPHASIS > PRE_EMPHASIS_MAX_LEVEL)
+ max_requested.PRE_EMPHASIS = PRE_EMPHASIS_MAX_LEVEL;
+ if (max_requested.FFE_PRESET.settings.level > DP_FFE_PRESET_MAX_LEVEL)
+ max_requested.FFE_PRESET.settings.level = DP_FFE_PRESET_MAX_LEVEL;
+
+ /* make sure the pre-emphasis matches the voltage swing*/
+ if (max_requested.PRE_EMPHASIS >
+ get_max_pre_emphasis_for_voltage_swing(
+ max_requested.VOLTAGE_SWING))
+ max_requested.PRE_EMPHASIS =
+ get_max_pre_emphasis_for_voltage_swing(
+ max_requested.VOLTAGE_SWING);
+
+ for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
+ lane_settings[lane].VOLTAGE_SWING = max_requested.VOLTAGE_SWING;
+ lane_settings[lane].PRE_EMPHASIS = max_requested.PRE_EMPHASIS;
+ lane_settings[lane].FFE_PRESET = max_requested.FFE_PRESET;
+ }
+}
+
+void dp_hw_to_dpcd_lane_settings(
+ const struct link_training_settings *lt_settings,
+ const struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX],
+ union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX])
+{
+ uint8_t lane = 0;
+
+ for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
+ if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
+ DP_8b_10b_ENCODING) {
+ dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET =
+ (uint8_t)(hw_lane_settings[lane].VOLTAGE_SWING);
+ dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET =
+ (uint8_t)(hw_lane_settings[lane].PRE_EMPHASIS);
+ dpcd_lane_settings[lane].bits.MAX_SWING_REACHED =
+ (hw_lane_settings[lane].VOLTAGE_SWING ==
+ VOLTAGE_SWING_MAX_LEVEL ? 1 : 0);
+ dpcd_lane_settings[lane].bits.MAX_PRE_EMPHASIS_REACHED =
+ (hw_lane_settings[lane].PRE_EMPHASIS ==
+ PRE_EMPHASIS_MAX_LEVEL ? 1 : 0);
+ } else if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
+ DP_128b_132b_ENCODING) {
+ dpcd_lane_settings[lane].tx_ffe.PRESET_VALUE =
+ hw_lane_settings[lane].FFE_PRESET.settings.level;
+ }
+ }
+}
+
+uint8_t get_dpcd_link_rate(const struct dc_link_settings *link_settings)
+{
+ uint8_t link_rate = 0;
+ enum dp_link_encoding encoding = link_dp_get_encoding_format(link_settings);
+
+ if (encoding == DP_128b_132b_ENCODING)
+ switch (link_settings->link_rate) {
+ case LINK_RATE_UHBR10:
+ link_rate = 0x1;
+ break;
+ case LINK_RATE_UHBR20:
+ link_rate = 0x2;
+ break;
+ case LINK_RATE_UHBR13_5:
+ link_rate = 0x4;
+ break;
+ default:
+ link_rate = 0;
+ break;
+ }
+ else if (encoding == DP_8b_10b_ENCODING)
+ link_rate = (uint8_t) link_settings->link_rate;
+ else
+ link_rate = 0;
+
+ return link_rate;
+}
+
+/* Only used for channel equalization */
+uint32_t dp_translate_training_aux_read_interval(uint32_t dpcd_aux_read_interval)
+{
+ unsigned int aux_rd_interval_us = 400;
+
+ switch (dpcd_aux_read_interval) {
+ case 0x01:
+ aux_rd_interval_us = 4000;
+ break;
+ case 0x02:
+ aux_rd_interval_us = 8000;
+ break;
+ case 0x03:
+ aux_rd_interval_us = 12000;
+ break;
+ case 0x04:
+ aux_rd_interval_us = 16000;
+ break;
+ case 0x05:
+ aux_rd_interval_us = 32000;
+ break;
+ case 0x06:
+ aux_rd_interval_us = 64000;
+ break;
+ default:
+ break;
+ }
+
+ return aux_rd_interval_us;
+}
+
+enum link_training_result dp_get_cr_failure(enum dc_lane_count ln_count,
+ union lane_status *dpcd_lane_status)
+{
+ enum link_training_result result = LINK_TRAINING_SUCCESS;
+
+ if (ln_count >= LANE_COUNT_ONE && !dpcd_lane_status[0].bits.CR_DONE_0)
+ result = LINK_TRAINING_CR_FAIL_LANE0;
+ else if (ln_count >= LANE_COUNT_TWO && !dpcd_lane_status[1].bits.CR_DONE_0)
+ result = LINK_TRAINING_CR_FAIL_LANE1;
+ else if (ln_count >= LANE_COUNT_FOUR && !dpcd_lane_status[2].bits.CR_DONE_0)
+ result = LINK_TRAINING_CR_FAIL_LANE23;
+ else if (ln_count >= LANE_COUNT_FOUR && !dpcd_lane_status[3].bits.CR_DONE_0)
+ result = LINK_TRAINING_CR_FAIL_LANE23;
+ return result;
+}
+
+bool is_repeater(const struct link_training_settings *lt_settings, uint32_t offset)
+{
+ return (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) && (offset != 0);
+}
+
+bool dp_is_max_vs_reached(
+ const struct link_training_settings *lt_settings)
+{
+ uint32_t lane;
+ for (lane = 0; lane <
+ (uint32_t)(lt_settings->link_settings.lane_count);
+ lane++) {
+ if (lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET
+ == VOLTAGE_SWING_MAX_LEVEL)
+ return true;
+ }
+ return false;
+
+}
+
+bool dp_is_cr_done(enum dc_lane_count ln_count,
+ union lane_status *dpcd_lane_status)
+{
+ bool done = true;
+ uint32_t lane;
+ /*LANEx_CR_DONE bits All 1's?*/
+ for (lane = 0; lane < (uint32_t)(ln_count); lane++) {
+ if (!dpcd_lane_status[lane].bits.CR_DONE_0)
+ done = false;
+ }
+ return done;
+
+}
+
+bool dp_is_ch_eq_done(enum dc_lane_count ln_count,
+ union lane_status *dpcd_lane_status)
+{
+ bool done = true;
+ uint32_t lane;
+ for (lane = 0; lane < (uint32_t)(ln_count); lane++)
+ if (!dpcd_lane_status[lane].bits.CHANNEL_EQ_DONE_0)
+ done = false;
+ return done;
+}
+
+bool dp_is_symbol_locked(enum dc_lane_count ln_count,
+ union lane_status *dpcd_lane_status)
+{
+ bool locked = true;
+ uint32_t lane;
+ for (lane = 0; lane < (uint32_t)(ln_count); lane++)
+ if (!dpcd_lane_status[lane].bits.SYMBOL_LOCKED_0)
+ locked = false;
+ return locked;
+}
+
+bool dp_is_interlane_aligned(union lane_align_status_updated align_status)
+{
+ return align_status.bits.INTERLANE_ALIGN_DONE == 1;
+}
+
+enum link_training_result dp_check_link_loss_status(
+ struct dc_link *link,
+ const struct link_training_settings *link_training_setting)
+{
+ enum link_training_result status = LINK_TRAINING_SUCCESS;
+ union lane_status lane_status;
+ uint8_t dpcd_buf[6] = {0};
+ uint32_t lane;
+
+ core_link_read_dpcd(
+ link,
+ DP_SINK_COUNT,
+ (uint8_t *)(dpcd_buf),
+ sizeof(dpcd_buf));
+
+ /*parse lane status*/
+ for (lane = 0; lane < link->cur_link_settings.lane_count; lane++) {
+ /*
+ * check lanes status
+ */
+ lane_status.raw = dp_get_nibble_at_index(&dpcd_buf[2], lane);
+
+ if (!lane_status.bits.CHANNEL_EQ_DONE_0 ||
+ !lane_status.bits.CR_DONE_0 ||
+ !lane_status.bits.SYMBOL_LOCKED_0) {
+ /* if one of the channel equalization, clock
+ * recovery or symbol lock is dropped
+ * consider it as (link has been
+ * dropped) dp sink status has changed
+ */
+ status = LINK_TRAINING_LINK_LOSS;
+ break;
+ }
+ }
+
+ return status;
+}
+
+enum dc_status dp_get_lane_status_and_lane_adjust(
+ struct dc_link *link,
+ const struct link_training_settings *link_training_setting,
+ union lane_status ln_status[LANE_COUNT_DP_MAX],
+ union lane_align_status_updated *ln_align,
+ union lane_adjust ln_adjust[LANE_COUNT_DP_MAX],
+ uint32_t offset)
+{
+ unsigned int lane01_status_address = DP_LANE0_1_STATUS;
+ uint8_t lane_adjust_offset = 4;
+ unsigned int lane01_adjust_address;
+ uint8_t dpcd_buf[6] = {0};
+ uint32_t lane;
+ enum dc_status status;
+
+ if (is_repeater(link_training_setting, offset)) {
+ lane01_status_address =
+ DP_LANE0_1_STATUS_PHY_REPEATER1 +
+ ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
+ lane_adjust_offset = 3;
+ }
+
+ status = core_link_read_dpcd(
+ link,
+ lane01_status_address,
+ (uint8_t *)(dpcd_buf),
+ sizeof(dpcd_buf));
+
+ if (status != DC_OK) {
+ DC_LOG_HW_LINK_TRAINING("%s:\n Failed to read from address 0x%X,"
+ " keep current lane status and lane adjust unchanged",
+ __func__,
+ lane01_status_address);
+ return status;
+ }
+
+ for (lane = 0; lane <
+ (uint32_t)(link_training_setting->link_settings.lane_count);
+ lane++) {
+
+ ln_status[lane].raw =
+ dp_get_nibble_at_index(&dpcd_buf[0], lane);
+ ln_adjust[lane].raw =
+ dp_get_nibble_at_index(&dpcd_buf[lane_adjust_offset], lane);
+ }
+
+ ln_align->raw = dpcd_buf[2];
+
+ if (is_repeater(link_training_setting, offset)) {
+ DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"
+ " 0x%X Lane01Status = %x\n 0x%X Lane23Status = %x\n ",
+ __func__,
+ offset,
+ lane01_status_address, dpcd_buf[0],
+ lane01_status_address + 1, dpcd_buf[1]);
+
+ lane01_adjust_address = DP_ADJUST_REQUEST_LANE0_1_PHY_REPEATER1 +
+ ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
+
+ DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"
+ " 0x%X Lane01AdjustRequest = %x\n 0x%X Lane23AdjustRequest = %x\n",
+ __func__,
+ offset,
+ lane01_adjust_address,
+ dpcd_buf[lane_adjust_offset],
+ lane01_adjust_address + 1,
+ dpcd_buf[lane_adjust_offset + 1]);
+ } else {
+ DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X Lane01Status = %x\n 0x%X Lane23Status = %x\n ",
+ __func__,
+ lane01_status_address, dpcd_buf[0],
+ lane01_status_address + 1, dpcd_buf[1]);
+
+ lane01_adjust_address = DP_ADJUST_REQUEST_LANE0_1;
+
+ DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X Lane01AdjustRequest = %x\n 0x%X Lane23AdjustRequest = %x\n",
+ __func__,
+ lane01_adjust_address,
+ dpcd_buf[lane_adjust_offset],
+ lane01_adjust_address + 1,
+ dpcd_buf[lane_adjust_offset + 1]);
+ }
+
+ return status;
+}
+
+static void override_lane_settings(const struct link_training_settings *lt_settings,
+ struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX])
+{
+ uint32_t lane;
+
+ if (lt_settings->voltage_swing == NULL &&
+ lt_settings->pre_emphasis == NULL &&
+ lt_settings->ffe_preset == NULL &&
+ lt_settings->post_cursor2 == NULL)
+
+ return;
+
+ for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
+ if (lt_settings->voltage_swing)
+ lane_settings[lane].VOLTAGE_SWING = *lt_settings->voltage_swing;
+ if (lt_settings->pre_emphasis)
+ lane_settings[lane].PRE_EMPHASIS = *lt_settings->pre_emphasis;
+ if (lt_settings->post_cursor2)
+ lane_settings[lane].POST_CURSOR2 = *lt_settings->post_cursor2;
+ if (lt_settings->ffe_preset)
+ lane_settings[lane].FFE_PRESET = *lt_settings->ffe_preset;
+ }
+}
+
+void dp_get_lttpr_mode_override(struct dc_link *link, enum lttpr_mode *override)
+{
+ if (!dp_is_lttpr_present(link))
+ return;
+
+ if (link->dc->debug.lttpr_mode_override == LTTPR_MODE_TRANSPARENT) {
+ *override = LTTPR_MODE_TRANSPARENT;
+ } else if (link->dc->debug.lttpr_mode_override == LTTPR_MODE_NON_TRANSPARENT) {
+ *override = LTTPR_MODE_NON_TRANSPARENT;
+ } else if (link->dc->debug.lttpr_mode_override == LTTPR_MODE_NON_LTTPR) {
+ *override = LTTPR_MODE_NON_LTTPR;
+ }
+ DC_LOG_DC("lttpr_mode_override chose LTTPR_MODE = %d\n", (uint8_t)(*override));
+}
+
+void override_training_settings(
+ struct dc_link *link,
+ const struct dc_link_training_overrides *overrides,
+ struct link_training_settings *lt_settings)
+{
+ uint32_t lane;
+
+ /* Override link spread */
+ if (!link->dp_ss_off && overrides->downspread != NULL)
+ lt_settings->link_settings.link_spread = *overrides->downspread ?
+ LINK_SPREAD_05_DOWNSPREAD_30KHZ
+ : LINK_SPREAD_DISABLED;
+
+ /* Override lane settings */
+ if (overrides->voltage_swing != NULL)
+ lt_settings->voltage_swing = overrides->voltage_swing;
+ if (overrides->pre_emphasis != NULL)
+ lt_settings->pre_emphasis = overrides->pre_emphasis;
+ if (overrides->post_cursor2 != NULL)
+ lt_settings->post_cursor2 = overrides->post_cursor2;
+ if (overrides->ffe_preset != NULL)
+ lt_settings->ffe_preset = overrides->ffe_preset;
+ /* Override HW lane settings with BIOS forced values if present */
+ if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) &&
+ lt_settings->lttpr_mode == LTTPR_MODE_TRANSPARENT) {
+ lt_settings->voltage_swing = &link->bios_forced_drive_settings.VOLTAGE_SWING;
+ lt_settings->pre_emphasis = &link->bios_forced_drive_settings.PRE_EMPHASIS;
+ lt_settings->always_match_dpcd_with_hw_lane_settings = false;
+ }
+ for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
+ lt_settings->hw_lane_settings[lane].VOLTAGE_SWING =
+ lt_settings->voltage_swing != NULL ?
+ *lt_settings->voltage_swing :
+ VOLTAGE_SWING_LEVEL0;
+ lt_settings->hw_lane_settings[lane].PRE_EMPHASIS =
+ lt_settings->pre_emphasis != NULL ?
+ *lt_settings->pre_emphasis
+ : PRE_EMPHASIS_DISABLED;
+ lt_settings->hw_lane_settings[lane].POST_CURSOR2 =
+ lt_settings->post_cursor2 != NULL ?
+ *lt_settings->post_cursor2
+ : POST_CURSOR2_DISABLED;
+ }
+
+ if (lt_settings->always_match_dpcd_with_hw_lane_settings)
+ dp_hw_to_dpcd_lane_settings(lt_settings,
+ lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
+
+ /* Override training timings */
+ if (overrides->cr_pattern_time != NULL)
+ lt_settings->cr_pattern_time = *overrides->cr_pattern_time;
+ if (overrides->eq_pattern_time != NULL)
+ lt_settings->eq_pattern_time = *overrides->eq_pattern_time;
+ if (overrides->pattern_for_cr != NULL)
+ lt_settings->pattern_for_cr = *overrides->pattern_for_cr;
+ if (overrides->pattern_for_eq != NULL)
+ lt_settings->pattern_for_eq = *overrides->pattern_for_eq;
+ if (overrides->enhanced_framing != NULL)
+ lt_settings->enhanced_framing = *overrides->enhanced_framing;
+ if (link->preferred_training_settings.fec_enable != NULL)
+ lt_settings->should_set_fec_ready = *link->preferred_training_settings.fec_enable;
+
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ /* Check DP tunnel LTTPR mode debug option. */
+ if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA && link->dc->debug.dpia_debug.bits.force_non_lttpr)
+ lt_settings->lttpr_mode = LTTPR_MODE_NON_LTTPR;
+
+#endif
+ dp_get_lttpr_mode_override(link, &lt_settings->lttpr_mode);
+
+}
+
+enum dc_dp_training_pattern decide_cr_training_pattern(
+ const struct dc_link_settings *link_settings)
+{
+ switch (link_dp_get_encoding_format(link_settings)) {
+ case DP_8b_10b_ENCODING:
+ default:
+ return DP_TRAINING_PATTERN_SEQUENCE_1;
+ case DP_128b_132b_ENCODING:
+ return DP_128b_132b_TPS1;
+ }
+}
+
+enum dc_dp_training_pattern decide_eq_training_pattern(struct dc_link *link,
+ const struct dc_link_settings *link_settings)
+{
+ struct link_encoder *link_enc;
+ struct encoder_feature_support *enc_caps;
+ struct dpcd_caps *rx_caps = &link->dpcd_caps;
+ enum dc_dp_training_pattern pattern = DP_TRAINING_PATTERN_SEQUENCE_2;
+
+ link_enc = link_enc_cfg_get_link_enc(link);
+ ASSERT(link_enc);
+ enc_caps = &link_enc->features;
+
+ switch (link_dp_get_encoding_format(link_settings)) {
+ case DP_8b_10b_ENCODING:
+ if (enc_caps->flags.bits.IS_TPS4_CAPABLE &&
+ rx_caps->max_down_spread.bits.TPS4_SUPPORTED)
+ pattern = DP_TRAINING_PATTERN_SEQUENCE_4;
+ else if (enc_caps->flags.bits.IS_TPS3_CAPABLE &&
+ rx_caps->max_ln_count.bits.TPS3_SUPPORTED)
+ pattern = DP_TRAINING_PATTERN_SEQUENCE_3;
+ else
+ pattern = DP_TRAINING_PATTERN_SEQUENCE_2;
+ break;
+ case DP_128b_132b_ENCODING:
+ pattern = DP_128b_132b_TPS2;
+ break;
+ default:
+ pattern = DP_TRAINING_PATTERN_SEQUENCE_2;
+ break;
+ }
+ return pattern;
+}
+
+enum lttpr_mode dc_link_decide_lttpr_mode(struct dc_link *link,
+ struct dc_link_settings *link_setting)
+{
+ enum dp_link_encoding encoding = link_dp_get_encoding_format(link_setting);
+
+ if (encoding == DP_8b_10b_ENCODING)
+ return dp_decide_8b_10b_lttpr_mode(link);
+ else if (encoding == DP_128b_132b_ENCODING)
+ return dp_decide_128b_132b_lttpr_mode(link);
+
+ ASSERT(0);
+ return LTTPR_MODE_NON_LTTPR;
+}
+
+void dp_decide_lane_settings(
+ const struct link_training_settings *lt_settings,
+ const union lane_adjust ln_adjust[LANE_COUNT_DP_MAX],
+ struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX],
+ union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX])
+{
+ uint32_t lane;
+
+ for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
+ if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
+ DP_8b_10b_ENCODING) {
+ hw_lane_settings[lane].VOLTAGE_SWING =
+ (enum dc_voltage_swing)(ln_adjust[lane].bits.
+ VOLTAGE_SWING_LANE);
+ hw_lane_settings[lane].PRE_EMPHASIS =
+ (enum dc_pre_emphasis)(ln_adjust[lane].bits.
+ PRE_EMPHASIS_LANE);
+ } else if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
+ DP_128b_132b_ENCODING) {
+ hw_lane_settings[lane].FFE_PRESET.raw =
+ ln_adjust[lane].tx_ffe.PRESET_VALUE;
+ }
+ }
+ dp_hw_to_dpcd_lane_settings(lt_settings, hw_lane_settings, dpcd_lane_settings);
+
+ if (lt_settings->disallow_per_lane_settings) {
+ /* we find the maximum of the requested settings across all lanes*/
+ /* and set this maximum for all lanes*/
+ maximize_lane_settings(lt_settings, hw_lane_settings);
+ override_lane_settings(lt_settings, hw_lane_settings);
+
+ if (lt_settings->always_match_dpcd_with_hw_lane_settings)
+ dp_hw_to_dpcd_lane_settings(lt_settings, hw_lane_settings, dpcd_lane_settings);
+ }
+
+}
+
+void dp_decide_training_settings(
+ struct dc_link *link,
+ const struct dc_link_settings *link_settings,
+ struct link_training_settings *lt_settings)
+{
+ if (link_dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING)
+ decide_8b_10b_training_settings(link, link_settings, lt_settings);
+ else if (link_dp_get_encoding_format(link_settings) == DP_128b_132b_ENCODING)
+ decide_128b_132b_training_settings(link, link_settings, lt_settings);
+}
+
+
+enum dc_status configure_lttpr_mode_transparent(struct dc_link *link)
+{
+ uint8_t repeater_mode = DP_PHY_REPEATER_MODE_TRANSPARENT;
+
+ DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Transparent Mode\n", __func__);
+ return core_link_write_dpcd(link,
+ DP_PHY_REPEATER_MODE,
+ (uint8_t *)&repeater_mode,
+ sizeof(repeater_mode));
+}
+
+static enum dc_status configure_lttpr_mode_non_transparent(
+ struct dc_link *link,
+ const struct link_training_settings *lt_settings)
+{
+ /* aux timeout is already set to extended */
+ /* RESET/SET lttpr mode to enable non transparent mode */
+ uint8_t repeater_cnt;
+ uint32_t aux_interval_address;
+ uint8_t repeater_id;
+ enum dc_status result = DC_ERROR_UNEXPECTED;
+ uint8_t repeater_mode = DP_PHY_REPEATER_MODE_TRANSPARENT;
+
+ enum dp_link_encoding encoding = link_dp_get_encoding_format(&lt_settings->link_settings);
+
+ if (encoding == DP_8b_10b_ENCODING) {
+ DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Transparent Mode\n", __func__);
+ result = core_link_write_dpcd(link,
+ DP_PHY_REPEATER_MODE,
+ (uint8_t *)&repeater_mode,
+ sizeof(repeater_mode));
+
+ }
+
+ if (result == DC_OK) {
+ link->dpcd_caps.lttpr_caps.mode = repeater_mode;
+ }
+
+ if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
+
+ DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Non Transparent Mode\n", __func__);
+
+ repeater_mode = DP_PHY_REPEATER_MODE_NON_TRANSPARENT;
+ result = core_link_write_dpcd(link,
+ DP_PHY_REPEATER_MODE,
+ (uint8_t *)&repeater_mode,
+ sizeof(repeater_mode));
+
+ if (result == DC_OK) {
+ link->dpcd_caps.lttpr_caps.mode = repeater_mode;
+ }
+
+ if (encoding == DP_8b_10b_ENCODING) {
+ repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
+
+ /* Driver does not need to train the first hop. Skip DPCD read and clear
+ * AUX_RD_INTERVAL for DPTX-to-DPIA hop.
+ */
+ if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA)
+ link->dpcd_caps.lttpr_caps.aux_rd_interval[--repeater_cnt] = 0;
+
+ for (repeater_id = repeater_cnt; repeater_id > 0; repeater_id--) {
+ aux_interval_address = DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1 +
+ ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (repeater_id - 1));
+ core_link_read_dpcd(
+ link,
+ aux_interval_address,
+ (uint8_t *)&link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1],
+ sizeof(link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1]));
+ link->dpcd_caps.lttpr_caps.aux_rd_interval[repeater_id - 1] &= 0x7F;
+ }
+ }
+ }
+
+ return result;
+}
+
+enum dc_status dpcd_configure_lttpr_mode(struct dc_link *link, struct link_training_settings *lt_settings)
+{
+ enum dc_status status = DC_OK;
+
+ if (lt_settings->lttpr_mode == LTTPR_MODE_TRANSPARENT)
+ status = configure_lttpr_mode_transparent(link);
+
+ else if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT)
+ status = configure_lttpr_mode_non_transparent(link, lt_settings);
+
+ return status;
+}
+
+void repeater_training_done(struct dc_link *link, uint32_t offset)
+{
+ union dpcd_training_pattern dpcd_pattern = {0};
+
+ const uint32_t dpcd_base_lt_offset =
+ DP_TRAINING_PATTERN_SET_PHY_REPEATER1 +
+ ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
+ /* Set training not in progress*/
+ dpcd_pattern.v1_4.TRAINING_PATTERN_SET = DPCD_TRAINING_PATTERN_VIDEOIDLE;
+
+ core_link_write_dpcd(
+ link,
+ dpcd_base_lt_offset,
+ &dpcd_pattern.raw,
+ 1);
+
+ DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Id: %d 0x%X pattern = %x\n",
+ __func__,
+ offset,
+ dpcd_base_lt_offset,
+ dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
+}
+
+static void dpcd_exit_training_mode(struct dc_link *link, enum dp_link_encoding encoding)
+{
+ uint8_t sink_status = 0;
+ uint8_t i;
+
+ /* clear training pattern set */
+ dpcd_set_training_pattern(link, DP_TRAINING_PATTERN_VIDEOIDLE);
+
+ if (encoding == DP_128b_132b_ENCODING) {
+ /* poll for intra-hop disable */
+ for (i = 0; i < 10; i++) {
+ if ((core_link_read_dpcd(link, DP_SINK_STATUS, &sink_status, 1) == DC_OK) &&
+ (sink_status & DP_INTRA_HOP_AUX_REPLY_INDICATION) == 0)
+ break;
+ udelay(1000);
+ }
+ }
+}
+
+enum dc_status dpcd_configure_channel_coding(struct dc_link *link,
+ struct link_training_settings *lt_settings)
+{
+ enum dp_link_encoding encoding =
+ link_dp_get_encoding_format(
+ &lt_settings->link_settings);
+ enum dc_status status;
+
+ status = core_link_write_dpcd(
+ link,
+ DP_MAIN_LINK_CHANNEL_CODING_SET,
+ (uint8_t *) &encoding,
+ 1);
+ DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X MAIN_LINK_CHANNEL_CODING_SET = %x\n",
+ __func__,
+ DP_MAIN_LINK_CHANNEL_CODING_SET,
+ encoding);
+
+ return status;
+}
+
+void dpcd_set_training_pattern(
+ struct dc_link *link,
+ enum dc_dp_training_pattern training_pattern)
+{
+ union dpcd_training_pattern dpcd_pattern = {0};
+
+ dpcd_pattern.v1_4.TRAINING_PATTERN_SET =
+ dp_training_pattern_to_dpcd_training_pattern(
+ link, training_pattern);
+
+ core_link_write_dpcd(
+ link,
+ DP_TRAINING_PATTERN_SET,
+ &dpcd_pattern.raw,
+ 1);
+
+ DC_LOG_HW_LINK_TRAINING("%s\n %x pattern = %x\n",
+ __func__,
+ DP_TRAINING_PATTERN_SET,
+ dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
+}
+
+enum dc_status dpcd_set_link_settings(
+ struct dc_link *link,
+ const struct link_training_settings *lt_settings)
+{
+ uint8_t rate;
+ enum dc_status status;
+
+ union down_spread_ctrl downspread = {0};
+ union lane_count_set lane_count_set = {0};
+
+ downspread.raw = (uint8_t)
+ (lt_settings->link_settings.link_spread);
+
+ lane_count_set.bits.LANE_COUNT_SET =
+ lt_settings->link_settings.lane_count;
+
+ lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
+ lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
+
+
+ if (link->ep_type == DISPLAY_ENDPOINT_PHY &&
+ lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) {
+ lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED =
+ link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED;
+ }
+
+ status = core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL,
+ &downspread.raw, sizeof(downspread));
+
+ status = core_link_write_dpcd(link, DP_LANE_COUNT_SET,
+ &lane_count_set.raw, 1);
+
+ if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_13 &&
+ lt_settings->link_settings.use_link_rate_set == true) {
+ rate = 0;
+ /* WA for some MUX chips that will power down with eDP and lose supported
+ * link rate set for eDP 1.4. Source reads DPCD 0x010 again to ensure
+ * MUX chip gets link rate set back before link training.
+ */
+ if (link->connector_signal == SIGNAL_TYPE_EDP) {
+ uint8_t supported_link_rates[16];
+
+ core_link_read_dpcd(link, DP_SUPPORTED_LINK_RATES,
+ supported_link_rates, sizeof(supported_link_rates));
+ }
+ status = core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1);
+ status = core_link_write_dpcd(link, DP_LINK_RATE_SET,
+ &lt_settings->link_settings.link_rate_set, 1);
+ } else {
+ rate = get_dpcd_link_rate(&lt_settings->link_settings);
+
+ status = core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1);
+ }
+
+ if (rate) {
+ DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
+ __func__,
+ DP_LINK_BW_SET,
+ lt_settings->link_settings.link_rate,
+ DP_LANE_COUNT_SET,
+ lt_settings->link_settings.lane_count,
+ lt_settings->enhanced_framing,
+ DP_DOWNSPREAD_CTRL,
+ lt_settings->link_settings.link_spread);
+ } else {
+ DC_LOG_HW_LINK_TRAINING("%s\n %x rate set = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
+ __func__,
+ DP_LINK_RATE_SET,
+ lt_settings->link_settings.link_rate_set,
+ DP_LANE_COUNT_SET,
+ lt_settings->link_settings.lane_count,
+ lt_settings->enhanced_framing,
+ DP_DOWNSPREAD_CTRL,
+ lt_settings->link_settings.link_spread);
+ }
+
+ return status;
+}
+
+enum dc_status dpcd_set_lane_settings(
+ struct dc_link *link,
+ const struct link_training_settings *link_training_setting,
+ uint32_t offset)
+{
+ unsigned int lane0_set_address;
+ enum dc_status status;
+ lane0_set_address = DP_TRAINING_LANE0_SET;
+
+ if (is_repeater(link_training_setting, offset))
+ lane0_set_address = DP_TRAINING_LANE0_SET_PHY_REPEATER1 +
+ ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
+
+ status = core_link_write_dpcd(link,
+ lane0_set_address,
+ (uint8_t *)(link_training_setting->dpcd_lane_settings),
+ link_training_setting->link_settings.lane_count);
+
+ if (is_repeater(link_training_setting, offset)) {
+ DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Repeater ID: %d\n"
+ " 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n",
+ __func__,
+ offset,
+ lane0_set_address,
+ link_training_setting->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET,
+ link_training_setting->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET,
+ link_training_setting->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,
+ link_training_setting->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED);
+
+ } else {
+ DC_LOG_HW_LINK_TRAINING("%s\n 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n",
+ __func__,
+ lane0_set_address,
+ link_training_setting->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET,
+ link_training_setting->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET,
+ link_training_setting->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,
+ link_training_setting->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED);
+ }
+
+ return status;
+}
+
+void dpcd_set_lt_pattern_and_lane_settings(
+ struct dc_link *link,
+ const struct link_training_settings *lt_settings,
+ enum dc_dp_training_pattern pattern,
+ uint32_t offset)
+{
+ uint32_t dpcd_base_lt_offset;
+ uint8_t dpcd_lt_buffer[5] = {0};
+ union dpcd_training_pattern dpcd_pattern = {0};
+ uint32_t size_in_bytes;
+ bool edp_workaround = false; /* TODO link_prop.INTERNAL */
+ dpcd_base_lt_offset = DP_TRAINING_PATTERN_SET;
+
+ if (is_repeater(lt_settings, offset))
+ dpcd_base_lt_offset = DP_TRAINING_PATTERN_SET_PHY_REPEATER1 +
+ ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
+
+ /*****************************************************************
+ * DpcdAddress_TrainingPatternSet
+ *****************************************************************/
+ dpcd_pattern.v1_4.TRAINING_PATTERN_SET =
+ dp_training_pattern_to_dpcd_training_pattern(link, pattern);
+
+ dpcd_pattern.v1_4.SCRAMBLING_DISABLE =
+ dp_initialize_scrambling_data_symbols(link, pattern);
+
+ dpcd_lt_buffer[DP_TRAINING_PATTERN_SET - DP_TRAINING_PATTERN_SET]
+ = dpcd_pattern.raw;
+
+ if (is_repeater(lt_settings, offset)) {
+ DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Repeater ID: %d\n 0x%X pattern = %x\n",
+ __func__,
+ offset,
+ dpcd_base_lt_offset,
+ dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
+ } else {
+ DC_LOG_HW_LINK_TRAINING("%s\n 0x%X pattern = %x\n",
+ __func__,
+ dpcd_base_lt_offset,
+ dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
+ }
+
+ /* concatenate everything into one buffer*/
+ size_in_bytes = lt_settings->link_settings.lane_count *
+ sizeof(lt_settings->dpcd_lane_settings[0]);
+
+ // 0x00103 - 0x00102
+ memmove(
+ &dpcd_lt_buffer[DP_TRAINING_LANE0_SET - DP_TRAINING_PATTERN_SET],
+ lt_settings->dpcd_lane_settings,
+ size_in_bytes);
+
+ if (is_repeater(lt_settings, offset)) {
+ if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
+ DP_128b_132b_ENCODING)
+ DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"
+ " 0x%X TX_FFE_PRESET_VALUE = %x\n",
+ __func__,
+ offset,
+ dpcd_base_lt_offset,
+ lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE);
+ else if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
+ DP_8b_10b_ENCODING)
+ DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"
+ " 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n",
+ __func__,
+ offset,
+ dpcd_base_lt_offset,
+ lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET,
+ lt_settings->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET,
+ lt_settings->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,
+ lt_settings->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED);
+ } else {
+ if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
+ DP_128b_132b_ENCODING)
+ DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X TX_FFE_PRESET_VALUE = %x\n",
+ __func__,
+ dpcd_base_lt_offset,
+ lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE);
+ else if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
+ DP_8b_10b_ENCODING)
+ DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n",
+ __func__,
+ dpcd_base_lt_offset,
+ lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET,
+ lt_settings->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET,
+ lt_settings->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,
+ lt_settings->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED);
+ }
+ if (edp_workaround) {
+ /* for eDP write in 2 parts because the 5-byte burst is
+ * causing issues on some eDP panels (EPR#366724)
+ */
+ core_link_write_dpcd(
+ link,
+ DP_TRAINING_PATTERN_SET,
+ &dpcd_pattern.raw,
+ sizeof(dpcd_pattern.raw));
+
+ core_link_write_dpcd(
+ link,
+ DP_TRAINING_LANE0_SET,
+ (uint8_t *)(lt_settings->dpcd_lane_settings),
+ size_in_bytes);
+
+ } else if (link_dp_get_encoding_format(&lt_settings->link_settings) ==
+ DP_128b_132b_ENCODING) {
+ core_link_write_dpcd(
+ link,
+ dpcd_base_lt_offset,
+ dpcd_lt_buffer,
+ sizeof(dpcd_lt_buffer));
+ } else
+ /* write it all in (1 + number-of-lanes)-byte burst*/
+ core_link_write_dpcd(
+ link,
+ dpcd_base_lt_offset,
+ dpcd_lt_buffer,
+ size_in_bytes + sizeof(dpcd_pattern.raw));
+}
+
+void start_clock_recovery_pattern_early(struct dc_link *link,
+ const struct link_resource *link_res,
+ struct link_training_settings *lt_settings,
+ uint32_t offset)
+{
+ DC_LOG_HW_LINK_TRAINING("%s\n GPU sends TPS1. Wait 400us.\n",
+ __func__);
+ dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_cr, offset);
+ dp_set_hw_lane_settings(link, link_res, lt_settings, offset);
+ udelay(400);
+}
+
+void dp_set_hw_test_pattern(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ enum dp_test_pattern test_pattern,
+ uint8_t *custom_pattern,
+ uint32_t custom_pattern_size)
+{
+ const struct link_hwss *link_hwss = get_link_hwss(link, link_res);
+ struct encoder_set_dp_phy_pattern_param pattern_param = {0};
+
+ pattern_param.dp_phy_pattern = test_pattern;
+ pattern_param.custom_pattern = custom_pattern;
+ pattern_param.custom_pattern_size = custom_pattern_size;
+ pattern_param.dp_panel_mode = dp_get_panel_mode(link);
+
+ if (link_hwss->ext.set_dp_link_test_pattern)
+ link_hwss->ext.set_dp_link_test_pattern(link, link_res, &pattern_param);
+}
+
+bool dp_set_hw_training_pattern(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ enum dc_dp_training_pattern pattern,
+ uint32_t offset)
+{
+ enum dp_test_pattern test_pattern = DP_TEST_PATTERN_UNSUPPORTED;
+
+ switch (pattern) {
+ case DP_TRAINING_PATTERN_SEQUENCE_1:
+ test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN1;
+ break;
+ case DP_TRAINING_PATTERN_SEQUENCE_2:
+ test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN2;
+ break;
+ case DP_TRAINING_PATTERN_SEQUENCE_3:
+ test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN3;
+ break;
+ case DP_TRAINING_PATTERN_SEQUENCE_4:
+ test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN4;
+ break;
+ case DP_128b_132b_TPS1:
+ test_pattern = DP_TEST_PATTERN_128b_132b_TPS1_TRAINING_MODE;
+ break;
+ case DP_128b_132b_TPS2:
+ test_pattern = DP_TEST_PATTERN_128b_132b_TPS2_TRAINING_MODE;
+ break;
+ default:
+ break;
+ }
+
+ dp_set_hw_test_pattern(link, link_res, test_pattern, NULL, 0);
+
+ return true;
+}
+
+static bool perform_post_lt_adj_req_sequence(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ struct link_training_settings *lt_settings)
+{
+ enum dc_lane_count lane_count =
+ lt_settings->link_settings.lane_count;
+
+ uint32_t adj_req_count;
+ uint32_t adj_req_timer;
+ bool req_drv_setting_changed;
+ uint32_t lane;
+ union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
+ union lane_align_status_updated dpcd_lane_status_updated = {0};
+ union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
+
+ req_drv_setting_changed = false;
+ for (adj_req_count = 0; adj_req_count < POST_LT_ADJ_REQ_LIMIT;
+ adj_req_count++) {
+
+ req_drv_setting_changed = false;
+
+ for (adj_req_timer = 0;
+ adj_req_timer < POST_LT_ADJ_REQ_TIMEOUT;
+ adj_req_timer++) {
+
+ dp_get_lane_status_and_lane_adjust(
+ link,
+ lt_settings,
+ dpcd_lane_status,
+ &dpcd_lane_status_updated,
+ dpcd_lane_adjust,
+ DPRX);
+
+ if (dpcd_lane_status_updated.bits.
+ POST_LT_ADJ_REQ_IN_PROGRESS == 0)
+ return true;
+
+ if (!dp_is_cr_done(lane_count, dpcd_lane_status))
+ return false;
+
+ if (!dp_is_ch_eq_done(lane_count, dpcd_lane_status) ||
+ !dp_is_symbol_locked(lane_count, dpcd_lane_status) ||
+ !dp_is_interlane_aligned(dpcd_lane_status_updated))
+ return false;
+
+ for (lane = 0; lane < (uint32_t)(lane_count); lane++) {
+
+ if (lt_settings->
+ dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET !=
+ dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_LANE ||
+ lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET !=
+ dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_LANE) {
+
+ req_drv_setting_changed = true;
+ break;
+ }
+ }
+
+ if (req_drv_setting_changed) {
+ dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
+ lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
+
+ dp_set_drive_settings(link,
+ link_res,
+ lt_settings);
+ break;
+ }
+
+ msleep(1);
+ }
+
+ if (!req_drv_setting_changed) {
+ DC_LOG_WARNING("%s: Post Link Training Adjust Request Timed out\n",
+ __func__);
+
+ ASSERT(0);
+ return true;
+ }
+ }
+ DC_LOG_WARNING("%s: Post Link Training Adjust Request limit reached\n",
+ __func__);
+
+ ASSERT(0);
+ return true;
+
+}
+
+static enum link_training_result dp_transition_to_video_idle(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ struct link_training_settings *lt_settings,
+ enum link_training_result status)
+{
+ union lane_count_set lane_count_set = {0};
+
+ /* 4. mainlink output idle pattern*/
+ dp_set_hw_test_pattern(link, link_res, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0);
+
+ /*
+ * 5. post training adjust if required
+ * If the upstream DPTX and downstream DPRX both support TPS4,
+ * TPS4 must be used instead of POST_LT_ADJ_REQ.
+ */
+ if (link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED != 1 ||
+ lt_settings->pattern_for_eq >= DP_TRAINING_PATTERN_SEQUENCE_4) {
+ /* delay 5ms after Main Link output idle pattern and then check
+ * DPCD 0202h.
+ */
+ if (link->connector_signal != SIGNAL_TYPE_EDP && status == LINK_TRAINING_SUCCESS) {
+ msleep(5);
+ status = dp_check_link_loss_status(link, lt_settings);
+ }
+ return status;
+ }
+
+ if (status == LINK_TRAINING_SUCCESS &&
+ perform_post_lt_adj_req_sequence(link, link_res, lt_settings) == false)
+ status = LINK_TRAINING_LQA_FAIL;
+
+ lane_count_set.bits.LANE_COUNT_SET = lt_settings->link_settings.lane_count;
+ lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
+ lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
+
+ core_link_write_dpcd(
+ link,
+ DP_LANE_COUNT_SET,
+ &lane_count_set.raw,
+ sizeof(lane_count_set));
+
+ return status;
+}
+
+enum link_training_result dp_perform_link_training(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ const struct dc_link_settings *link_settings,
+ bool skip_video_pattern)
+{
+ enum link_training_result status = LINK_TRAINING_SUCCESS;
+ struct link_training_settings lt_settings = {0};
+ enum dp_link_encoding encoding =
+ link_dp_get_encoding_format(link_settings);
+
+ /* decide training settings */
+ dp_decide_training_settings(
+ link,
+ link_settings,
+ &lt_settings);
+
+ override_training_settings(
+ link,
+ &link->preferred_training_settings,
+ &lt_settings);
+
+ /* reset previous training states */
+ dpcd_exit_training_mode(link, encoding);
+
+ /* configure link prior to entering training mode */
+ dpcd_configure_lttpr_mode(link, &lt_settings);
+ dp_set_fec_ready(link, link_res, lt_settings.should_set_fec_ready);
+ dpcd_configure_channel_coding(link, &lt_settings);
+
+ /* enter training mode:
+ * Per DP specs starting from here, DPTX device shall not issue
+ * Non-LT AUX transactions inside training mode.
+ */
+ if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && encoding == DP_8b_10b_ENCODING)
+ status = dp_perform_fixed_vs_pe_training_sequence(link, link_res, &lt_settings);
+ else if (encoding == DP_8b_10b_ENCODING)
+ status = dp_perform_8b_10b_link_training(link, link_res, &lt_settings);
+ else if (encoding == DP_128b_132b_ENCODING)
+ status = dp_perform_128b_132b_link_training(link, link_res, &lt_settings);
+ else
+ ASSERT(0);
+
+ /* exit training mode */
+ dpcd_exit_training_mode(link, encoding);
+
+ /* switch to video idle */
+ if ((status == LINK_TRAINING_SUCCESS) || !skip_video_pattern)
+ status = dp_transition_to_video_idle(link,
+ link_res,
+ &lt_settings,
+ status);
+
+ /* dump debug data */
+ dp_log_training_result(link, &lt_settings, status);
+ if (status != LINK_TRAINING_SUCCESS)
+ link->ctx->dc->debug_data.ltFailCount++;
+ return status;
+}
+
+bool perform_link_training_with_retries(
+ const struct dc_link_settings *link_setting,
+ bool skip_video_pattern,
+ int attempts,
+ struct pipe_ctx *pipe_ctx,
+ enum signal_type signal,
+ bool do_fallback)
+{
+ int j;
+ uint8_t delay_between_attempts = LINK_TRAINING_RETRY_DELAY;
+ struct dc_stream_state *stream = pipe_ctx->stream;
+ struct dc_link *link = stream->link;
+ enum dp_panel_mode panel_mode = dp_get_panel_mode(link);
+ enum link_training_result status = LINK_TRAINING_CR_FAIL_LANE0;
+ struct dc_link_settings cur_link_settings = *link_setting;
+ struct dc_link_settings max_link_settings = *link_setting;
+ const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
+ int fail_count = 0;
+ bool is_link_bw_low = false; /* link bandwidth < stream bandwidth */
+ bool is_link_bw_min = /* RBR x 1 */
+ (cur_link_settings.link_rate <= LINK_RATE_LOW) &&
+ (cur_link_settings.lane_count <= LANE_COUNT_ONE);
+
+ dp_trace_commit_lt_init(link);
+
+
+ if (link_dp_get_encoding_format(&cur_link_settings) == DP_8b_10b_ENCODING)
+ /* We need to do this before the link training to ensure the idle
+ * pattern in SST mode will be sent right after the link training
+ */
+ link_hwss->setup_stream_encoder(pipe_ctx);
+
+ dp_trace_set_lt_start_timestamp(link, false);
+ j = 0;
+ while (j < attempts && fail_count < (attempts * 10)) {
+
+ DC_LOG_HW_LINK_TRAINING("%s: Beginning link(%d) training attempt %u of %d @ rate(%d) x lane(%d)\n",
+ __func__, link->link_index, (unsigned int)j + 1, attempts, cur_link_settings.link_rate,
+ cur_link_settings.lane_count);
+
+ dp_enable_link_phy(
+ link,
+ &pipe_ctx->link_res,
+ signal,
+ pipe_ctx->clock_source->id,
+ &cur_link_settings);
+
+ if (stream->sink_patches.dppowerup_delay > 0) {
+ int delay_dp_power_up_in_ms = stream->sink_patches.dppowerup_delay;
+
+ msleep(delay_dp_power_up_in_ms);
+ }
+
+#ifdef CONFIG_DRM_AMD_DC_HDCP
+ if (panel_mode == DP_PANEL_MODE_EDP) {
+ struct cp_psp *cp_psp = &stream->ctx->cp_psp;
+
+ if (cp_psp && cp_psp->funcs.enable_assr) {
+ /* ASSR is bound to fail with unsigned PSP
+ * verstage used during devlopment phase.
+ * Report and continue with eDP panel mode to
+ * perform eDP link training with right settings
+ */
+ bool result;
+ result = cp_psp->funcs.enable_assr(cp_psp->handle, link);
+ }
+ }
+#endif
+
+ dp_set_panel_mode(link, panel_mode);
+
+ if (link->aux_access_disabled) {
+ dc_link_dp_perform_link_training_skip_aux(link, &pipe_ctx->link_res, &cur_link_settings);
+ return true;
+ } else {
+ /** @todo Consolidate USB4 DP and DPx.x training. */
+ if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) {
+ status = dc_link_dpia_perform_link_training(
+ link,
+ &pipe_ctx->link_res,
+ &cur_link_settings,
+ skip_video_pattern);
+
+ /* Transmit idle pattern once training successful. */
+ if (status == LINK_TRAINING_SUCCESS && !is_link_bw_low) {
+ dp_set_hw_test_pattern(link, &pipe_ctx->link_res, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0);
+ // Update verified link settings to current one
+ // Because DPIA LT might fallback to lower link setting.
+ if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
+ link->verified_link_cap.link_rate = link->cur_link_settings.link_rate;
+ link->verified_link_cap.lane_count = link->cur_link_settings.lane_count;
+ dm_helpers_dp_mst_update_branch_bandwidth(link->ctx, link);
+ }
+ }
+ } else {
+ status = dp_perform_link_training(
+ link,
+ &pipe_ctx->link_res,
+ &cur_link_settings,
+ skip_video_pattern);
+ }
+
+ dp_trace_lt_total_count_increment(link, false);
+ dp_trace_lt_result_update(link, status, false);
+ dp_trace_set_lt_end_timestamp(link, false);
+ if (status == LINK_TRAINING_SUCCESS && !is_link_bw_low)
+ return true;
+ }
+
+ fail_count++;
+ dp_trace_lt_fail_count_update(link, fail_count, false);
+ if (link->ep_type == DISPLAY_ENDPOINT_PHY) {
+ /* latest link training still fail or link training is aborted
+ * skip delay and keep PHY on
+ */
+ if (j == (attempts - 1) || (status == LINK_TRAINING_ABORT))
+ break;
+ }
+
+ DC_LOG_WARNING("%s: Link(%d) training attempt %u of %d failed @ rate(%d) x lane(%d) : fail reason:(%d)\n",
+ __func__, link->link_index, (unsigned int)j + 1, attempts, cur_link_settings.link_rate,
+ cur_link_settings.lane_count, status);
+
+ dp_disable_link_phy(link, &pipe_ctx->link_res, signal);
+
+ /* Abort link training if failure due to sink being unplugged. */
+ if (status == LINK_TRAINING_ABORT) {
+ enum dc_connection_type type = dc_connection_none;
+
+ dc_link_detect_connection_type(link, &type);
+ if (type == dc_connection_none) {
+ DC_LOG_HW_LINK_TRAINING("%s: Aborting training because sink unplugged\n", __func__);
+ break;
+ }
+ }
+
+ /* Try to train again at original settings if:
+ * - not falling back between training attempts;
+ * - aborted previous attempt due to reasons other than sink unplug;
+ * - successfully trained but at a link rate lower than that required by stream;
+ * - reached minimum link bandwidth.
+ */
+ if (!do_fallback || (status == LINK_TRAINING_ABORT) ||
+ (status == LINK_TRAINING_SUCCESS && is_link_bw_low) ||
+ is_link_bw_min) {
+ j++;
+ cur_link_settings = *link_setting;
+ delay_between_attempts += LINK_TRAINING_RETRY_DELAY;
+ is_link_bw_low = false;
+ is_link_bw_min = (cur_link_settings.link_rate <= LINK_RATE_LOW) &&
+ (cur_link_settings.lane_count <= LANE_COUNT_ONE);
+
+ } else if (do_fallback) { /* Try training at lower link bandwidth if doing fallback. */
+ uint32_t req_bw;
+ uint32_t link_bw;
+
+ decide_fallback_link_setting(link, &max_link_settings,
+ &cur_link_settings, status);
+ /* Flag if reduced link bandwidth no longer meets stream requirements or fallen back to
+ * minimum link bandwidth.
+ */
+ req_bw = dc_bandwidth_in_kbps_from_timing(&stream->timing);
+ link_bw = dc_link_bandwidth_kbps(link, &cur_link_settings);
+ is_link_bw_low = (req_bw > link_bw);
+ is_link_bw_min = ((cur_link_settings.link_rate <= LINK_RATE_LOW) &&
+ (cur_link_settings.lane_count <= LANE_COUNT_ONE));
+
+ if (is_link_bw_low)
+ DC_LOG_WARNING(
+ "%s: Link(%d) bandwidth too low after fallback req_bw(%d) > link_bw(%d)\n",
+ __func__, link->link_index, req_bw, link_bw);
+ }
+
+ msleep(delay_between_attempts);
+ }
+
+ return false;
+}
+
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.h
new file mode 100644
index 000000000000..a04948635369
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.h
@@ -0,0 +1,182 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+
+
+#ifndef __DC_LINK_DP_TRAINING_H__
+#define __DC_LINK_DP_TRAINING_H__
+#include "link.h"
+
+bool perform_link_training_with_retries(
+ const struct dc_link_settings *link_setting,
+ bool skip_video_pattern,
+ int attempts,
+ struct pipe_ctx *pipe_ctx,
+ enum signal_type signal,
+ bool do_fallback);
+
+enum link_training_result dp_perform_link_training(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ const struct dc_link_settings *link_settings,
+ bool skip_video_pattern);
+
+bool dp_set_hw_training_pattern(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ enum dc_dp_training_pattern pattern,
+ uint32_t offset);
+
+void dp_set_hw_test_pattern(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ enum dp_test_pattern test_pattern,
+ uint8_t *custom_pattern,
+ uint32_t custom_pattern_size);
+
+void dpcd_set_training_pattern(
+ struct dc_link *link,
+ enum dc_dp_training_pattern training_pattern);
+
+/* Write DPCD drive settings. */
+enum dc_status dpcd_set_lane_settings(
+ struct dc_link *link,
+ const struct link_training_settings *link_training_setting,
+ uint32_t offset);
+
+/* Write DPCD link configuration data. */
+enum dc_status dpcd_set_link_settings(
+ struct dc_link *link,
+ const struct link_training_settings *lt_settings);
+
+void dpcd_set_lt_pattern_and_lane_settings(
+ struct dc_link *link,
+ const struct link_training_settings *lt_settings,
+ enum dc_dp_training_pattern pattern,
+ uint32_t offset);
+
+/* Read training status and adjustment requests from DPCD. */
+enum dc_status dp_get_lane_status_and_lane_adjust(
+ struct dc_link *link,
+ const struct link_training_settings *link_training_setting,
+ union lane_status ln_status[LANE_COUNT_DP_MAX],
+ union lane_align_status_updated *ln_align,
+ union lane_adjust ln_adjust[LANE_COUNT_DP_MAX],
+ uint32_t offset);
+
+enum dc_status dpcd_configure_lttpr_mode(
+ struct dc_link *link,
+ struct link_training_settings *lt_settings);
+
+enum dc_status configure_lttpr_mode_transparent(struct dc_link *link);
+
+enum dc_status dpcd_configure_channel_coding(
+ struct dc_link *link,
+ struct link_training_settings *lt_settings);
+
+void repeater_training_done(struct dc_link *link, uint32_t offset);
+
+void start_clock_recovery_pattern_early(struct dc_link *link,
+ const struct link_resource *link_res,
+ struct link_training_settings *lt_settings,
+ uint32_t offset);
+
+void dp_decide_training_settings(
+ struct dc_link *link,
+ const struct dc_link_settings *link_settings,
+ struct link_training_settings *lt_settings);
+
+void dp_decide_lane_settings(
+ const struct link_training_settings *lt_settings,
+ const union lane_adjust ln_adjust[LANE_COUNT_DP_MAX],
+ struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX],
+ union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX]);
+
+enum dc_dp_training_pattern decide_cr_training_pattern(
+ const struct dc_link_settings *link_settings);
+
+enum dc_dp_training_pattern decide_eq_training_pattern(struct dc_link *link,
+ const struct dc_link_settings *link_settings);
+
+void dp_get_lttpr_mode_override(struct dc_link *link,
+ enum lttpr_mode *override);
+
+void override_training_settings(
+ struct dc_link *link,
+ const struct dc_link_training_overrides *overrides,
+ struct link_training_settings *lt_settings);
+
+/* Check DPCD training status registers to detect link loss. */
+enum link_training_result dp_check_link_loss_status(
+ struct dc_link *link,
+ const struct link_training_settings *link_training_setting);
+
+bool dp_is_cr_done(enum dc_lane_count ln_count,
+ union lane_status *dpcd_lane_status);
+
+bool dp_is_ch_eq_done(enum dc_lane_count ln_count,
+ union lane_status *dpcd_lane_status);
+bool dp_is_symbol_locked(enum dc_lane_count ln_count,
+ union lane_status *dpcd_lane_status);
+bool dp_is_interlane_aligned(union lane_align_status_updated align_status);
+
+bool is_repeater(const struct link_training_settings *lt_settings, uint32_t offset);
+
+bool dp_is_max_vs_reached(
+ const struct link_training_settings *lt_settings);
+
+uint8_t get_dpcd_link_rate(const struct dc_link_settings *link_settings);
+
+enum link_training_result dp_get_cr_failure(enum dc_lane_count ln_count,
+ union lane_status *dpcd_lane_status);
+
+void dp_hw_to_dpcd_lane_settings(
+ const struct link_training_settings *lt_settings,
+ const struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX],
+ union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX]);
+
+void dp_wait_for_training_aux_rd_interval(
+ struct dc_link *link,
+ uint32_t wait_in_micro_secs);
+
+enum dpcd_training_patterns
+ dp_training_pattern_to_dpcd_training_pattern(
+ struct dc_link *link,
+ enum dc_dp_training_pattern pattern);
+
+uint8_t dp_initialize_scrambling_data_symbols(
+ struct dc_link *link,
+ enum dc_dp_training_pattern pattern);
+
+void dp_log_training_result(
+ struct dc_link *link,
+ const struct link_training_settings *lt_settings,
+ enum link_training_result status);
+
+uint32_t dp_translate_training_aux_read_interval(
+ uint32_t dpcd_aux_read_interval);
+
+uint8_t dp_get_nibble_at_index(const uint8_t *buf,
+ uint32_t index);
+#endif /* __DC_LINK_DP_TRAINING_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_128b_132b.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_128b_132b.c
new file mode 100644
index 000000000000..23d380f09a21
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_128b_132b.c
@@ -0,0 +1,259 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+
+/* FILE POLICY AND INTENDED USAGE:
+ * This file implements dp 128b/132b link training software policies and
+ * sequences.
+ */
+#include "link_dp_training_128b_132b.h"
+#include "link_dp_training_8b_10b.h"
+#include "link_dpcd.h"
+#include "link_dp_phy.h"
+#include "link_dp_capability.h"
+
+#define DC_LOGGER \
+ link->ctx->logger
+
+static enum dc_status dpcd_128b_132b_set_lane_settings(
+ struct dc_link *link,
+ const struct link_training_settings *link_training_setting)
+{
+ enum dc_status status = core_link_write_dpcd(link,
+ DP_TRAINING_LANE0_SET,
+ (uint8_t *)(link_training_setting->dpcd_lane_settings),
+ sizeof(link_training_setting->dpcd_lane_settings));
+
+ DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X TX_FFE_PRESET_VALUE = %x\n",
+ __func__,
+ DP_TRAINING_LANE0_SET,
+ link_training_setting->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE);
+ return status;
+}
+
+static void dpcd_128b_132b_get_aux_rd_interval(struct dc_link *link,
+ uint32_t *interval_in_us)
+{
+ union dp_128b_132b_training_aux_rd_interval dpcd_interval;
+ uint32_t interval_unit = 0;
+
+ dpcd_interval.raw = 0;
+ core_link_read_dpcd(link, DP_128B132B_TRAINING_AUX_RD_INTERVAL,
+ &dpcd_interval.raw, sizeof(dpcd_interval.raw));
+ interval_unit = dpcd_interval.bits.UNIT ? 1 : 2; /* 0b = 2 ms, 1b = 1 ms */
+ /* (128b/132b_TRAINING_AUX_RD_INTERVAL value + 1) *
+ * INTERVAL_UNIT. The maximum is 256 ms
+ */
+ *interval_in_us = (dpcd_interval.bits.VALUE + 1) * interval_unit * 1000;
+}
+
+static enum link_training_result dp_perform_128b_132b_channel_eq_done_sequence(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ struct link_training_settings *lt_settings)
+{
+ uint8_t loop_count;
+ uint32_t aux_rd_interval = 0;
+ uint32_t wait_time = 0;
+ union lane_align_status_updated dpcd_lane_status_updated = {0};
+ union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
+ union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
+ enum dc_status status = DC_OK;
+ enum link_training_result result = LINK_TRAINING_SUCCESS;
+
+ /* Transmit 128b/132b_TPS1 over Main-Link */
+ dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_cr, DPRX);
+
+ /* Set TRAINING_PATTERN_SET to 01h */
+ dpcd_set_training_pattern(link, lt_settings->pattern_for_cr);
+
+ /* Adjust TX_FFE_PRESET_VALUE and Transmit 128b/132b_TPS2 over Main-Link */
+ dpcd_128b_132b_get_aux_rd_interval(link, &aux_rd_interval);
+ dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status,
+ &dpcd_lane_status_updated, dpcd_lane_adjust, DPRX);
+ dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
+ lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
+ dp_set_hw_lane_settings(link, link_res, lt_settings, DPRX);
+ dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_eq, DPRX);
+
+ /* Set loop counter to start from 1 */
+ loop_count = 1;
+
+ /* Set TRAINING_PATTERN_SET to 02h and TX_FFE_PRESET_VALUE in one AUX transaction */
+ dpcd_set_lt_pattern_and_lane_settings(link, lt_settings,
+ lt_settings->pattern_for_eq, DPRX);
+
+ /* poll for channel EQ done */
+ while (result == LINK_TRAINING_SUCCESS) {
+ dp_wait_for_training_aux_rd_interval(link, aux_rd_interval);
+ wait_time += aux_rd_interval;
+ status = dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status,
+ &dpcd_lane_status_updated, dpcd_lane_adjust, DPRX);
+ dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
+ lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
+ dpcd_128b_132b_get_aux_rd_interval(link, &aux_rd_interval);
+ if (status != DC_OK) {
+ result = LINK_TRAINING_ABORT;
+ } else if (dp_is_ch_eq_done(lt_settings->link_settings.lane_count,
+ dpcd_lane_status)) {
+ /* pass */
+ break;
+ } else if (loop_count >= lt_settings->eq_loop_count_limit) {
+ result = DP_128b_132b_MAX_LOOP_COUNT_REACHED;
+ } else if (dpcd_lane_status_updated.bits.LT_FAILED_128b_132b) {
+ result = DP_128b_132b_LT_FAILED;
+ } else {
+ dp_set_hw_lane_settings(link, link_res, lt_settings, DPRX);
+ dpcd_128b_132b_set_lane_settings(link, lt_settings);
+ }
+ loop_count++;
+ }
+
+ /* poll for EQ interlane align done */
+ while (result == LINK_TRAINING_SUCCESS) {
+ if (status != DC_OK) {
+ result = LINK_TRAINING_ABORT;
+ } else if (dpcd_lane_status_updated.bits.EQ_INTERLANE_ALIGN_DONE_128b_132b) {
+ /* pass */
+ break;
+ } else if (wait_time >= lt_settings->eq_wait_time_limit) {
+ result = DP_128b_132b_CHANNEL_EQ_DONE_TIMEOUT;
+ } else if (dpcd_lane_status_updated.bits.LT_FAILED_128b_132b) {
+ result = DP_128b_132b_LT_FAILED;
+ } else {
+ dp_wait_for_training_aux_rd_interval(link,
+ lt_settings->eq_pattern_time);
+ wait_time += lt_settings->eq_pattern_time;
+ status = dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status,
+ &dpcd_lane_status_updated, dpcd_lane_adjust, DPRX);
+ }
+ }
+
+ return result;
+}
+
+static enum link_training_result dp_perform_128b_132b_cds_done_sequence(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ struct link_training_settings *lt_settings)
+{
+ /* Assumption: assume hardware has transmitted eq pattern */
+ enum dc_status status = DC_OK;
+ enum link_training_result result = LINK_TRAINING_SUCCESS;
+ union lane_align_status_updated dpcd_lane_status_updated = {0};
+ union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
+ union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
+ uint32_t wait_time = 0;
+
+ /* initiate CDS done sequence */
+ dpcd_set_training_pattern(link, lt_settings->pattern_for_cds);
+
+ /* poll for CDS interlane align done and symbol lock */
+ while (result == LINK_TRAINING_SUCCESS) {
+ dp_wait_for_training_aux_rd_interval(link,
+ lt_settings->cds_pattern_time);
+ wait_time += lt_settings->cds_pattern_time;
+ status = dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status,
+ &dpcd_lane_status_updated, dpcd_lane_adjust, DPRX);
+ if (status != DC_OK) {
+ result = LINK_TRAINING_ABORT;
+ } else if (dp_is_symbol_locked(lt_settings->link_settings.lane_count, dpcd_lane_status) &&
+ dpcd_lane_status_updated.bits.CDS_INTERLANE_ALIGN_DONE_128b_132b) {
+ /* pass */
+ break;
+ } else if (dpcd_lane_status_updated.bits.LT_FAILED_128b_132b) {
+ result = DP_128b_132b_LT_FAILED;
+ } else if (wait_time >= lt_settings->cds_wait_time_limit) {
+ result = DP_128b_132b_CDS_DONE_TIMEOUT;
+ }
+ }
+
+ return result;
+}
+
+enum link_training_result dp_perform_128b_132b_link_training(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ struct link_training_settings *lt_settings)
+{
+ enum link_training_result result = LINK_TRAINING_SUCCESS;
+
+ /* TODO - DP2.0 Link: remove legacy_dp2_lt logic */
+ if (link->dc->debug.legacy_dp2_lt) {
+ struct link_training_settings legacy_settings;
+
+ decide_8b_10b_training_settings(link,
+ &lt_settings->link_settings,
+ &legacy_settings);
+ return dp_perform_8b_10b_link_training(link, link_res, &legacy_settings);
+ }
+
+ dpcd_set_link_settings(link, lt_settings);
+
+ if (result == LINK_TRAINING_SUCCESS)
+ result = dp_perform_128b_132b_channel_eq_done_sequence(link, link_res, lt_settings);
+
+ if (result == LINK_TRAINING_SUCCESS)
+ result = dp_perform_128b_132b_cds_done_sequence(link, link_res, lt_settings);
+
+ return result;
+}
+
+void decide_128b_132b_training_settings(struct dc_link *link,
+ const struct dc_link_settings *link_settings,
+ struct link_training_settings *lt_settings)
+{
+ memset(lt_settings, 0, sizeof(*lt_settings));
+
+ lt_settings->link_settings = *link_settings;
+ /* TODO: should decide link spread when populating link_settings */
+ lt_settings->link_settings.link_spread = link->dp_ss_off ? LINK_SPREAD_DISABLED :
+ LINK_SPREAD_05_DOWNSPREAD_30KHZ;
+
+ lt_settings->pattern_for_cr = decide_cr_training_pattern(link_settings);
+ lt_settings->pattern_for_eq = decide_eq_training_pattern(link, link_settings);
+ lt_settings->eq_pattern_time = 2500;
+ lt_settings->eq_wait_time_limit = 400000;
+ lt_settings->eq_loop_count_limit = 20;
+ lt_settings->pattern_for_cds = DP_128b_132b_TPS2_CDS;
+ lt_settings->cds_pattern_time = 2500;
+ lt_settings->cds_wait_time_limit = (dp_parse_lttpr_repeater_count(
+ link->dpcd_caps.lttpr_caps.phy_repeater_cnt) + 1) * 20000;
+ lt_settings->disallow_per_lane_settings = true;
+ lt_settings->lttpr_mode = dp_decide_128b_132b_lttpr_mode(link);
+ dp_hw_to_dpcd_lane_settings(lt_settings,
+ lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
+}
+
+enum lttpr_mode dp_decide_128b_132b_lttpr_mode(struct dc_link *link)
+{
+ enum lttpr_mode mode = LTTPR_MODE_NON_LTTPR;
+
+ if (dp_is_lttpr_present(link))
+ mode = LTTPR_MODE_NON_TRANSPARENT;
+
+ DC_LOG_DC("128b_132b chose LTTPR_MODE %d.\n", mode);
+ return mode;
+}
+
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_128b_132b.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_128b_132b.h
new file mode 100644
index 000000000000..2147f24efc8b
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_128b_132b.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+
+
+#ifndef __DC_LINK_DP_TRAINING_128B_132B_H__
+#define __DC_LINK_DP_TRAINING_128B_132B_H__
+#include "link_dp_training.h"
+
+enum link_training_result dp_perform_128b_132b_link_training(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ struct link_training_settings *lt_settings);
+
+void decide_128b_132b_training_settings(struct dc_link *link,
+ const struct dc_link_settings *link_settings,
+ struct link_training_settings *lt_settings);
+
+enum lttpr_mode dp_decide_128b_132b_lttpr_mode(struct dc_link *link);
+
+#endif /* __DC_LINK_DP_TRAINING_128B_132B_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_8b_10b.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_8b_10b.c
new file mode 100644
index 000000000000..14b98e096d39
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_8b_10b.c
@@ -0,0 +1,414 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+
+/* FILE POLICY AND INTENDED USAGE:
+ * This file implements dp 8b/10b link training software policies and
+ * sequences.
+ */
+#include "link_dp_training_8b_10b.h"
+#include "link_dpcd.h"
+#include "link_dp_phy.h"
+#include "link_dp_capability.h"
+
+#define DC_LOGGER \
+ link->ctx->logger
+
+static int32_t get_cr_training_aux_rd_interval(struct dc_link *link,
+ const struct dc_link_settings *link_settings)
+{
+ union training_aux_rd_interval training_rd_interval;
+ uint32_t wait_in_micro_secs = 100;
+
+ memset(&training_rd_interval, 0, sizeof(training_rd_interval));
+ if (link_dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING &&
+ link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_12) {
+ core_link_read_dpcd(
+ link,
+ DP_TRAINING_AUX_RD_INTERVAL,
+ (uint8_t *)&training_rd_interval,
+ sizeof(training_rd_interval));
+ if (training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL)
+ wait_in_micro_secs = training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL * 4000;
+ }
+ return wait_in_micro_secs;
+}
+
+static uint32_t get_eq_training_aux_rd_interval(
+ struct dc_link *link,
+ const struct dc_link_settings *link_settings)
+{
+ union training_aux_rd_interval training_rd_interval;
+
+ memset(&training_rd_interval, 0, sizeof(training_rd_interval));
+ if (link_dp_get_encoding_format(link_settings) == DP_128b_132b_ENCODING) {
+ core_link_read_dpcd(
+ link,
+ DP_128B132B_TRAINING_AUX_RD_INTERVAL,
+ (uint8_t *)&training_rd_interval,
+ sizeof(training_rd_interval));
+ } else if (link_dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING &&
+ link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_12) {
+ core_link_read_dpcd(
+ link,
+ DP_TRAINING_AUX_RD_INTERVAL,
+ (uint8_t *)&training_rd_interval,
+ sizeof(training_rd_interval));
+ }
+
+ switch (training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL) {
+ case 0: return 400;
+ case 1: return 4000;
+ case 2: return 8000;
+ case 3: return 12000;
+ case 4: return 16000;
+ case 5: return 32000;
+ case 6: return 64000;
+ default: return 400;
+ }
+}
+
+void decide_8b_10b_training_settings(
+ struct dc_link *link,
+ const struct dc_link_settings *link_setting,
+ struct link_training_settings *lt_settings)
+{
+ memset(lt_settings, '\0', sizeof(struct link_training_settings));
+
+ /* Initialize link settings */
+ lt_settings->link_settings.use_link_rate_set = link_setting->use_link_rate_set;
+ lt_settings->link_settings.link_rate_set = link_setting->link_rate_set;
+ lt_settings->link_settings.link_rate = link_setting->link_rate;
+ lt_settings->link_settings.lane_count = link_setting->lane_count;
+ /* TODO hard coded to SS for now
+ * lt_settings.link_settings.link_spread =
+ * dal_display_path_is_ss_supported(
+ * path_mode->display_path) ?
+ * LINK_SPREAD_05_DOWNSPREAD_30KHZ :
+ * LINK_SPREAD_DISABLED;
+ */
+ lt_settings->link_settings.link_spread = link->dp_ss_off ?
+ LINK_SPREAD_DISABLED : LINK_SPREAD_05_DOWNSPREAD_30KHZ;
+ lt_settings->cr_pattern_time = get_cr_training_aux_rd_interval(link, link_setting);
+ lt_settings->eq_pattern_time = get_eq_training_aux_rd_interval(link, link_setting);
+ lt_settings->pattern_for_cr = decide_cr_training_pattern(link_setting);
+ lt_settings->pattern_for_eq = decide_eq_training_pattern(link, link_setting);
+ lt_settings->enhanced_framing = 1;
+ lt_settings->should_set_fec_ready = true;
+ lt_settings->disallow_per_lane_settings = true;
+ lt_settings->always_match_dpcd_with_hw_lane_settings = true;
+ lt_settings->lttpr_mode = dp_decide_8b_10b_lttpr_mode(link);
+ dp_hw_to_dpcd_lane_settings(lt_settings, lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
+}
+
+enum lttpr_mode dp_decide_8b_10b_lttpr_mode(struct dc_link *link)
+{
+ bool is_lttpr_present = dp_is_lttpr_present(link);
+ bool vbios_lttpr_force_non_transparent = link->dc->caps.vbios_lttpr_enable;
+ bool vbios_lttpr_aware = link->dc->caps.vbios_lttpr_aware;
+
+ if (!is_lttpr_present)
+ return LTTPR_MODE_NON_LTTPR;
+
+ if (vbios_lttpr_aware) {
+ if (vbios_lttpr_force_non_transparent) {
+ DC_LOG_DC("chose LTTPR_MODE_NON_TRANSPARENT due to VBIOS DCE_INFO_CAPS_LTTPR_SUPPORT_ENABLE set to 1.\n");
+ return LTTPR_MODE_NON_TRANSPARENT;
+ } else {
+ DC_LOG_DC("chose LTTPR_MODE_NON_TRANSPARENT by default due to VBIOS not set DCE_INFO_CAPS_LTTPR_SUPPORT_ENABLE set to 1.\n");
+ return LTTPR_MODE_TRANSPARENT;
+ }
+ }
+
+ if (link->dc->config.allow_lttpr_non_transparent_mode.bits.DP1_4A &&
+ link->dc->caps.extended_aux_timeout_support) {
+ DC_LOG_DC("chose LTTPR_MODE_NON_TRANSPARENT by default and dc->config.allow_lttpr_non_transparent_mode.bits.DP1_4A set to 1.\n");
+ return LTTPR_MODE_NON_TRANSPARENT;
+ }
+
+ DC_LOG_DC("chose LTTPR_MODE_NON_LTTPR.\n");
+ return LTTPR_MODE_NON_LTTPR;
+}
+
+enum link_training_result perform_8b_10b_clock_recovery_sequence(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ struct link_training_settings *lt_settings,
+ uint32_t offset)
+{
+ uint32_t retries_cr;
+ uint32_t retry_count;
+ uint32_t wait_time_microsec;
+ enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
+ union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX];
+ union lane_align_status_updated dpcd_lane_status_updated;
+ union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
+
+ retries_cr = 0;
+ retry_count = 0;
+
+ memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status));
+ memset(&dpcd_lane_status_updated, '\0',
+ sizeof(dpcd_lane_status_updated));
+
+ if (!link->ctx->dc->work_arounds.lt_early_cr_pattern)
+ dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_cr, offset);
+
+ /* najeeb - The synaptics MST hub can put the LT in
+ * infinite loop by switching the VS
+ */
+ /* between level 0 and level 1 continuously, here
+ * we try for CR lock for LinkTrainingMaxCRRetry count*/
+ while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
+ (retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
+
+
+ /* 1. call HWSS to set lane settings*/
+ dp_set_hw_lane_settings(
+ link,
+ link_res,
+ lt_settings,
+ offset);
+
+ /* 2. update DPCD of the receiver*/
+ if (!retry_count)
+ /* EPR #361076 - write as a 5-byte burst,
+ * but only for the 1-st iteration.*/
+ dpcd_set_lt_pattern_and_lane_settings(
+ link,
+ lt_settings,
+ lt_settings->pattern_for_cr,
+ offset);
+ else
+ dpcd_set_lane_settings(
+ link,
+ lt_settings,
+ offset);
+
+ /* 3. wait receiver to lock-on*/
+ wait_time_microsec = lt_settings->cr_pattern_time;
+
+ dp_wait_for_training_aux_rd_interval(
+ link,
+ wait_time_microsec);
+
+ /* 4. Read lane status and requested drive
+ * settings as set by the sink
+ */
+ dp_get_lane_status_and_lane_adjust(
+ link,
+ lt_settings,
+ dpcd_lane_status,
+ &dpcd_lane_status_updated,
+ dpcd_lane_adjust,
+ offset);
+
+ /* 5. check CR done*/
+ if (dp_is_cr_done(lane_count, dpcd_lane_status))
+ return LINK_TRAINING_SUCCESS;
+
+ /* 6. max VS reached*/
+ if ((link_dp_get_encoding_format(&lt_settings->link_settings) ==
+ DP_8b_10b_ENCODING) &&
+ dp_is_max_vs_reached(lt_settings))
+ break;
+
+ /* 7. same lane settings*/
+ /* Note: settings are the same for all lanes,
+ * so comparing first lane is sufficient*/
+ if ((link_dp_get_encoding_format(&lt_settings->link_settings) == DP_8b_10b_ENCODING) &&
+ lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET ==
+ dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE)
+ retries_cr++;
+ else if ((link_dp_get_encoding_format(&lt_settings->link_settings) == DP_128b_132b_ENCODING) &&
+ lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE ==
+ dpcd_lane_adjust[0].tx_ffe.PRESET_VALUE)
+ retries_cr++;
+ else
+ retries_cr = 0;
+
+ /* 8. update VS/PE/PC2 in lt_settings*/
+ dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
+ lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
+ retry_count++;
+ }
+
+ if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) {
+ ASSERT(0);
+ DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue",
+ __func__,
+ LINK_TRAINING_MAX_CR_RETRY);
+
+ }
+
+ return dp_get_cr_failure(lane_count, dpcd_lane_status);
+}
+
+enum link_training_result perform_8b_10b_channel_equalization_sequence(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ struct link_training_settings *lt_settings,
+ uint32_t offset)
+{
+ enum dc_dp_training_pattern tr_pattern;
+ uint32_t retries_ch_eq;
+ uint32_t wait_time_microsec;
+ enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
+ union lane_align_status_updated dpcd_lane_status_updated = {0};
+ union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
+ union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
+
+ /* Note: also check that TPS4 is a supported feature*/
+ tr_pattern = lt_settings->pattern_for_eq;
+
+ if (is_repeater(lt_settings, offset) && link_dp_get_encoding_format(&lt_settings->link_settings) == DP_8b_10b_ENCODING)
+ tr_pattern = DP_TRAINING_PATTERN_SEQUENCE_4;
+
+ dp_set_hw_training_pattern(link, link_res, tr_pattern, offset);
+
+ for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT;
+ retries_ch_eq++) {
+
+ dp_set_hw_lane_settings(link, link_res, lt_settings, offset);
+
+ /* 2. update DPCD*/
+ if (!retries_ch_eq)
+ /* EPR #361076 - write as a 5-byte burst,
+ * but only for the 1-st iteration
+ */
+
+ dpcd_set_lt_pattern_and_lane_settings(
+ link,
+ lt_settings,
+ tr_pattern, offset);
+ else
+ dpcd_set_lane_settings(link, lt_settings, offset);
+
+ /* 3. wait for receiver to lock-on*/
+ wait_time_microsec = lt_settings->eq_pattern_time;
+
+ if (is_repeater(lt_settings, offset))
+ wait_time_microsec =
+ dp_translate_training_aux_read_interval(
+ link->dpcd_caps.lttpr_caps.aux_rd_interval[offset - 1]);
+
+ dp_wait_for_training_aux_rd_interval(
+ link,
+ wait_time_microsec);
+
+ /* 4. Read lane status and requested
+ * drive settings as set by the sink*/
+
+ dp_get_lane_status_and_lane_adjust(
+ link,
+ lt_settings,
+ dpcd_lane_status,
+ &dpcd_lane_status_updated,
+ dpcd_lane_adjust,
+ offset);
+
+ /* 5. check CR done*/
+ if (!dp_is_cr_done(lane_count, dpcd_lane_status))
+ return dpcd_lane_status[0].bits.CR_DONE_0 ?
+ LINK_TRAINING_EQ_FAIL_CR_PARTIAL :
+ LINK_TRAINING_EQ_FAIL_CR;
+
+ /* 6. check CHEQ done*/
+ if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) &&
+ dp_is_symbol_locked(lane_count, dpcd_lane_status) &&
+ dp_is_interlane_aligned(dpcd_lane_status_updated))
+ return LINK_TRAINING_SUCCESS;
+
+ /* 7. update VS/PE/PC2 in lt_settings*/
+ dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
+ lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
+ }
+
+ return LINK_TRAINING_EQ_FAIL_EQ;
+
+}
+
+enum link_training_result dp_perform_8b_10b_link_training(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ struct link_training_settings *lt_settings)
+{
+ enum link_training_result status = LINK_TRAINING_SUCCESS;
+
+ uint8_t repeater_cnt;
+ uint8_t repeater_id;
+ uint8_t lane = 0;
+
+ if (link->ctx->dc->work_arounds.lt_early_cr_pattern)
+ start_clock_recovery_pattern_early(link, link_res, lt_settings, DPRX);
+
+ /* 1. set link rate, lane count and spread. */
+ dpcd_set_link_settings(link, lt_settings);
+
+ if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
+
+ /* 2. perform link training (set link training done
+ * to false is done as well)
+ */
+ repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
+
+ for (repeater_id = repeater_cnt; (repeater_id > 0 && status == LINK_TRAINING_SUCCESS);
+ repeater_id--) {
+ status = perform_8b_10b_clock_recovery_sequence(link, link_res, lt_settings, repeater_id);
+
+ if (status != LINK_TRAINING_SUCCESS) {
+ repeater_training_done(link, repeater_id);
+ break;
+ }
+
+ status = perform_8b_10b_channel_equalization_sequence(link,
+ link_res,
+ lt_settings,
+ repeater_id);
+
+ repeater_training_done(link, repeater_id);
+
+ if (status != LINK_TRAINING_SUCCESS)
+ break;
+
+ for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
+ lt_settings->dpcd_lane_settings[lane].raw = 0;
+ lt_settings->hw_lane_settings[lane].VOLTAGE_SWING = 0;
+ lt_settings->hw_lane_settings[lane].PRE_EMPHASIS = 0;
+ }
+ }
+ }
+
+ if (status == LINK_TRAINING_SUCCESS) {
+ status = perform_8b_10b_clock_recovery_sequence(link, link_res, lt_settings, DPRX);
+ if (status == LINK_TRAINING_SUCCESS) {
+ status = perform_8b_10b_channel_equalization_sequence(link,
+ link_res,
+ lt_settings,
+ DPRX);
+ }
+ }
+
+ return status;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_8b_10b.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_8b_10b.h
new file mode 100644
index 000000000000..d26de15ce954
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_8b_10b.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+
+
+#ifndef __DC_LINK_DP_TRAINING_8B_10B_H__
+#define __DC_LINK_DP_TRAINING_8B_10B_H__
+#include "link_dp_training.h"
+
+/* to avoid infinite loop where-in the receiver
+ * switches between different VS
+ */
+#define LINK_TRAINING_MAX_CR_RETRY 100
+#define LINK_TRAINING_MAX_RETRY_COUNT 5
+
+enum link_training_result dp_perform_8b_10b_link_training(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ struct link_training_settings *lt_settings);
+
+enum link_training_result perform_8b_10b_clock_recovery_sequence(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ struct link_training_settings *lt_settings,
+ uint32_t offset);
+
+enum link_training_result perform_8b_10b_channel_equalization_sequence(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ struct link_training_settings *lt_settings,
+ uint32_t offset);
+
+enum lttpr_mode dp_decide_8b_10b_lttpr_mode(struct dc_link *link);
+
+void decide_8b_10b_training_settings(
+ struct dc_link *link,
+ const struct dc_link_settings *link_setting,
+ struct link_training_settings *lt_settings);
+
+#endif /* __DC_LINK_DP_TRAINING_8B_10B_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_auxless.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_auxless.c
new file mode 100644
index 000000000000..e50ec5012559
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_auxless.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+
+/* FILE POLICY AND INTENDED USAGE:
+ *
+ */
+#include "link_dp_training_auxless.h"
+#include "link_dp_phy.h"
+#define DC_LOGGER \
+ link->ctx->logger
+bool dc_link_dp_perform_link_training_skip_aux(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ const struct dc_link_settings *link_setting)
+{
+ struct link_training_settings lt_settings = {0};
+
+ dp_decide_training_settings(
+ link,
+ link_setting,
+ &lt_settings);
+ override_training_settings(
+ link,
+ &link->preferred_training_settings,
+ &lt_settings);
+
+ /* 1. Perform_clock_recovery_sequence. */
+
+ /* transmit training pattern for clock recovery */
+ dp_set_hw_training_pattern(link, link_res, lt_settings.pattern_for_cr, DPRX);
+
+ /* call HWSS to set lane settings*/
+ dp_set_hw_lane_settings(link, link_res, &lt_settings, DPRX);
+
+ /* wait receiver to lock-on*/
+ dp_wait_for_training_aux_rd_interval(link, lt_settings.cr_pattern_time);
+
+ /* 2. Perform_channel_equalization_sequence. */
+
+ /* transmit training pattern for channel equalization. */
+ dp_set_hw_training_pattern(link, link_res, lt_settings.pattern_for_eq, DPRX);
+
+ /* call HWSS to set lane settings*/
+ dp_set_hw_lane_settings(link, link_res, &lt_settings, DPRX);
+
+ /* wait receiver to lock-on. */
+ dp_wait_for_training_aux_rd_interval(link, lt_settings.eq_pattern_time);
+
+ /* 3. Perform_link_training_int. */
+
+ /* Mainlink output idle pattern. */
+ dp_set_hw_test_pattern(link, link_res, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0);
+
+ dp_log_training_result(link, &lt_settings, LINK_TRAINING_SUCCESS);
+
+ return true;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_auxless.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_auxless.h
new file mode 100644
index 000000000000..413999cd03c4
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_auxless.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+
+
+#ifndef __DC_LINK_DP_TRAINING_AUXLESS_H__
+#define __DC_LINK_DP_TRAINING_AUXLESS_H__
+#include "link_dp_training.h"
+
+bool dc_link_dp_perform_link_training_skip_aux(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ const struct dc_link_settings *link_setting);
+#endif /* __DC_LINK_DP_TRAINING_AUXLESS_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dpia.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.c
index d130d58ac08e..e60da0532c53 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dpia.c
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.c
@@ -1,6 +1,5 @@
-// SPDX-License-Identifier: MIT
/*
- * Copyright 2021 Advanced Micro Devices, Inc.
+ * Copyright 2022 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@@ -24,76 +23,72 @@
*
*/
+/* FILE POLICY AND INTENDED USAGE:
+ * This module implements functionality for training DPIA links.
+ */
+#include "link_dp_training_dpia.h"
#include "dc.h"
-#include "dc_link_dpia.h"
#include "inc/core_status.h"
#include "dc_link.h"
-#include "dc_link_dp.h"
#include "dpcd_defs.h"
+
+#include "link_dp_dpia.h"
#include "link_hwss.h"
#include "dm_helpers.h"
#include "dmub/inc/dmub_cmd.h"
-#include "inc/link_dpcd.h"
+#include "link_dpcd.h"
+#include "link_dp_phy.h"
+#include "link_dp_training_8b_10b.h"
+#include "link_dp_capability.h"
#include "dc_dmub_srv.h"
-
#define DC_LOGGER \
link->ctx->logger
-enum dc_status dpcd_get_tunneling_device_data(struct dc_link *link)
-{
- enum dc_status status = DC_OK;
- uint8_t dpcd_dp_tun_data[3] = {0};
- uint8_t dpcd_topology_data[DPCD_USB4_TOPOLOGY_ID_LEN] = {0};
- uint8_t i = 0;
-
- status = core_link_read_dpcd(link,
- DP_TUNNELING_CAPABILITIES_SUPPORT,
- dpcd_dp_tun_data,
- sizeof(dpcd_dp_tun_data));
-
- status = core_link_read_dpcd(link,
- DP_USB4_ROUTER_TOPOLOGY_ID,
- dpcd_topology_data,
- sizeof(dpcd_topology_data));
-
- link->dpcd_caps.usb4_dp_tun_info.dp_tun_cap.raw =
- dpcd_dp_tun_data[DP_TUNNELING_CAPABILITIES_SUPPORT -
- DP_TUNNELING_CAPABILITIES_SUPPORT];
- link->dpcd_caps.usb4_dp_tun_info.dpia_info.raw =
- dpcd_dp_tun_data[DP_IN_ADAPTER_INFO - DP_TUNNELING_CAPABILITIES_SUPPORT];
- link->dpcd_caps.usb4_dp_tun_info.usb4_driver_id =
- dpcd_dp_tun_data[DP_USB4_DRIVER_ID - DP_TUNNELING_CAPABILITIES_SUPPORT];
-
- for (i = 0; i < DPCD_USB4_TOPOLOGY_ID_LEN; i++)
- link->dpcd_caps.usb4_dp_tun_info.usb4_topology_id[i] = dpcd_topology_data[i];
-
- return status;
-}
-
-bool dc_link_dpia_query_hpd_status(struct dc_link *link)
-{
- union dmub_rb_cmd cmd = {0};
- struct dc_dmub_srv *dmub_srv = link->ctx->dmub_srv;
- bool is_hpd_high = false;
-
- /* prepare QUERY_HPD command */
- cmd.query_hpd.header.type = DMUB_CMD__QUERY_HPD_STATE;
- cmd.query_hpd.data.instance = link->link_id.enum_id - ENUM_ID_1;
- cmd.query_hpd.data.ch_type = AUX_CHANNEL_DPIA;
-
- /* Return HPD status reported by DMUB if query successfully executed. */
- if (dc_dmub_srv_cmd_with_reply_data(dmub_srv, &cmd) && cmd.query_hpd.data.status == AUX_RET_SUCCESS)
- is_hpd_high = cmd.query_hpd.data.result;
+/* The approximate time (us) it takes to transmit 9 USB4 DP clock sync packets. */
+#define DPIA_CLK_SYNC_DELAY 16000
+
+/* Extend interval between training status checks for manual testing. */
+#define DPIA_DEBUG_EXTENDED_AUX_RD_INTERVAL_US 60000000
+
+#define TRAINING_AUX_RD_INTERVAL 100 //us
+
+/* SET_CONFIG message types sent by driver. */
+enum dpia_set_config_type {
+ DPIA_SET_CFG_SET_LINK = 0x01,
+ DPIA_SET_CFG_SET_PHY_TEST_MODE = 0x05,
+ DPIA_SET_CFG_SET_TRAINING = 0x18,
+ DPIA_SET_CFG_SET_VSPE = 0x19
+};
+
+/* Training stages (TS) in SET_CONFIG(SET_TRAINING) message. */
+enum dpia_set_config_ts {
+ DPIA_TS_DPRX_DONE = 0x00, /* Done training DPRX. */
+ DPIA_TS_TPS1 = 0x01,
+ DPIA_TS_TPS2 = 0x02,
+ DPIA_TS_TPS3 = 0x03,
+ DPIA_TS_TPS4 = 0x07,
+ DPIA_TS_UFP_DONE = 0xff /* Done training DPTX-to-DPIA hop. */
+};
+
+/* SET_CONFIG message data associated with messages sent by driver. */
+union dpia_set_config_data {
+ struct {
+ uint8_t mode : 1;
+ uint8_t reserved : 7;
+ } set_link;
+ struct {
+ uint8_t stage;
+ } set_training;
+ struct {
+ uint8_t swing : 2;
+ uint8_t max_swing_reached : 1;
+ uint8_t pre_emph : 2;
+ uint8_t max_pre_emph_reached : 1;
+ uint8_t reserved : 2;
+ } set_vspe;
+ uint8_t raw;
+};
- DC_LOG_DEBUG("%s: link(%d) dpia(%d) cmd_status(%d) result(%d)\n",
- __func__,
- link->link_index,
- link->link_id.enum_id - ENUM_ID_1,
- cmd.query_hpd.data.status,
- cmd.query_hpd.data.result);
-
- return is_hpd_high;
-}
/* Configure link as prescribed in link_setting; set LTTPR mode; and
* Initialize link training settings.
@@ -113,11 +108,12 @@ static enum link_training_result dpia_configure_link(
bool fec_enable;
DC_LOG_HW_LINK_TRAINING("%s\n DPIA(%d) configuring\n - LTTPR mode(%d)\n",
- __func__,
- link->link_id.enum_id - ENUM_ID_1,
- lt_settings->lttpr_mode);
+ __func__,
+ link->link_id.enum_id - ENUM_ID_1,
+ lt_settings->lttpr_mode);
- dp_decide_training_settings(link,
+ dp_decide_training_settings(
+ link,
link_setting,
lt_settings);
@@ -137,7 +133,7 @@ static enum link_training_result dpia_configure_link(
if (status != DC_OK && link->is_hpd_pending)
return LINK_TRAINING_ABORT;
- if (link->preferred_training_settings.fec_enable)
+ if (link->preferred_training_settings.fec_enable != NULL)
fec_enable = *link->preferred_training_settings.fec_enable;
else
fec_enable = true;
@@ -148,7 +144,8 @@ static enum link_training_result dpia_configure_link(
return LINK_TRAINING_SUCCESS;
}
-static enum dc_status core_link_send_set_config(struct dc_link *link,
+static enum dc_status core_link_send_set_config(
+ struct dc_link *link,
uint8_t msg_type,
uint8_t msg_data)
{
@@ -160,8 +157,8 @@ static enum dc_status core_link_send_set_config(struct dc_link *link,
payload.msg_data = msg_data;
if (!link->ddc->ddc_pin && !link->aux_access_disabled &&
- (dm_helpers_dmub_set_config_sync(link->ctx, link,
- &payload, &set_config_result) == -1)) {
+ (dm_helpers_dmub_set_config_sync(link->ctx,
+ link, &payload, &set_config_result) == -1)) {
return DC_ERROR_UNEXPECTED;
}
@@ -170,7 +167,8 @@ static enum dc_status core_link_send_set_config(struct dc_link *link,
}
/* Build SET_CONFIG message data payload for specified message type. */
-static uint8_t dpia_build_set_config_data(enum dpia_set_config_type type,
+static uint8_t dpia_build_set_config_data(
+ enum dpia_set_config_type type,
struct dc_link *link,
struct link_training_settings *lt_settings)
{
@@ -189,11 +187,9 @@ static uint8_t dpia_build_set_config_data(enum dpia_set_config_type type,
data.set_vspe.swing = lt_settings->hw_lane_settings[0].VOLTAGE_SWING;
data.set_vspe.pre_emph = lt_settings->hw_lane_settings[0].PRE_EMPHASIS;
data.set_vspe.max_swing_reached =
- lt_settings->hw_lane_settings[0].VOLTAGE_SWING ==
- VOLTAGE_SWING_MAX_LEVEL ? 1 : 0;
+ lt_settings->hw_lane_settings[0].VOLTAGE_SWING == VOLTAGE_SWING_MAX_LEVEL ? 1 : 0;
data.set_vspe.max_pre_emph_reached =
- lt_settings->hw_lane_settings[0].PRE_EMPHASIS ==
- PRE_EMPHASIS_MAX_LEVEL ? 1 : 0;
+ lt_settings->hw_lane_settings[0].PRE_EMPHASIS == PRE_EMPHASIS_MAX_LEVEL ? 1 : 0;
break;
default:
ASSERT(false); /* Message type not supported by helper function. */
@@ -235,7 +231,8 @@ static enum dc_status convert_trng_ptn_to_trng_stg(enum dc_dp_training_pattern t
}
/* Write training pattern to DPCD. */
-static enum dc_status dpcd_set_lt_pattern(struct dc_link *link,
+static enum dc_status dpcd_set_lt_pattern(
+ struct dc_link *link,
enum dc_dp_training_pattern pattern,
uint32_t hop)
{
@@ -249,28 +246,29 @@ static enum dc_status dpcd_set_lt_pattern(struct dc_link *link,
/* DpcdAddress_TrainingPatternSet */
dpcd_pattern.v1_4.TRAINING_PATTERN_SET =
- dc_dp_training_pattern_to_dpcd_training_pattern(link, pattern);
+ dp_training_pattern_to_dpcd_training_pattern(link, pattern);
dpcd_pattern.v1_4.SCRAMBLING_DISABLE =
- dc_dp_initialize_scrambling_data_symbols(link, pattern);
+ dp_initialize_scrambling_data_symbols(link, pattern);
if (hop != DPRX) {
DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Repeater ID: %d\n 0x%X pattern = %x\n",
- __func__,
- hop,
- dpcd_tps_offset,
- dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
+ __func__,
+ hop,
+ dpcd_tps_offset,
+ dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
} else {
DC_LOG_HW_LINK_TRAINING("%s\n 0x%X pattern = %x\n",
- __func__,
- dpcd_tps_offset,
- dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
+ __func__,
+ dpcd_tps_offset,
+ dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
}
- status = core_link_write_dpcd(link,
- dpcd_tps_offset,
- &dpcd_pattern.raw,
- sizeof(dpcd_pattern.raw));
+ status = core_link_write_dpcd(
+ link,
+ dpcd_tps_offset,
+ &dpcd_pattern.raw,
+ sizeof(dpcd_pattern.raw));
return status;
}
@@ -284,7 +282,7 @@ static enum dc_status dpcd_set_lt_pattern(struct dc_link *link,
*
* @param link DPIA link being trained.
* @param lt_settings link_setting and drive settings (voltage swing and pre-emphasis).
- * @param hop The Hop in display path. DPRX = 0.
+ * @param hop Hop in display path. DPRX = 0.
*/
static enum link_training_result dpia_training_cr_non_transparent(
struct dc_link *link,
@@ -297,8 +295,7 @@ static enum link_training_result dpia_training_cr_non_transparent(
enum dc_status status;
uint32_t retries_cr = 0; /* Number of consecutive attempts with same VS or PE. */
uint32_t retry_count = 0;
- /* From DP spec, CR read interval is always 100us. */
- uint32_t wait_time_microsec = TRAINING_AUX_RD_INTERVAL;
+ uint32_t wait_time_microsec = TRAINING_AUX_RD_INTERVAL; /* From DP spec, CR read interval is always 100us. */
enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
union lane_align_status_updated dpcd_lane_status_updated = {0};
@@ -306,7 +303,7 @@ static enum link_training_result dpia_training_cr_non_transparent(
uint8_t set_cfg_data;
enum dpia_set_config_ts ts;
- repeater_cnt = dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
+ repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
/* Cap of LINK_TRAINING_MAX_CR_RETRY attempts at clock recovery.
* Fix inherited from perform_clock_recovery_sequence() -
@@ -316,17 +313,20 @@ static enum link_training_result dpia_training_cr_non_transparent(
* continuously.
*/
while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
- (retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
+ (retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
+
/* DPTX-to-DPIA */
if (hop == repeater_cnt) {
/* Send SET_CONFIG(SET_LINK:LC,LR,LTTPR) to notify DPOA that
* non-transparent link training has started.
* This also enables the transmission of clk_sync packets.
*/
- set_cfg_data = dpia_build_set_config_data(DPIA_SET_CFG_SET_LINK,
+ set_cfg_data = dpia_build_set_config_data(
+ DPIA_SET_CFG_SET_LINK,
link,
lt_settings);
- status = core_link_send_set_config(link,
+ status = core_link_send_set_config(
+ link,
DPIA_SET_CFG_SET_LINK,
set_cfg_data);
/* CR for this hop is considered successful as long as
@@ -347,6 +347,14 @@ static enum link_training_result dpia_training_cr_non_transparent(
result = LINK_TRAINING_ABORT;
break;
}
+ status = core_link_send_set_config(
+ link,
+ DPIA_SET_CFG_SET_TRAINING,
+ ts);
+ if (status != DC_OK) {
+ result = LINK_TRAINING_ABORT;
+ break;
+ }
status = dpcd_set_lt_pattern(link, lt_settings->pattern_for_cr, hop);
if (status != DC_OK) {
result = LINK_TRAINING_ABORT;
@@ -358,10 +366,12 @@ static enum link_training_result dpia_training_cr_non_transparent(
* drive settings for hops immediately downstream.
*/
if (hop == repeater_cnt - 1) {
- set_cfg_data = dpia_build_set_config_data(DPIA_SET_CFG_SET_VSPE,
+ set_cfg_data = dpia_build_set_config_data(
+ DPIA_SET_CFG_SET_VSPE,
link,
lt_settings);
- status = core_link_send_set_config(link,
+ status = core_link_send_set_config(
+ link,
DPIA_SET_CFG_SET_VSPE,
set_cfg_data);
if (status != DC_OK) {
@@ -468,7 +478,8 @@ static enum link_training_result dpia_training_cr_transparent(
* continuously.
*/
while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
- (retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
+ (retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
+
/* Write TPS1 (not VS or PE) to DPCD to start CR phase.
* DPIA sends SET_CONFIG(SET_LINK) to notify DPOA to
* start link training.
@@ -529,8 +540,7 @@ static enum link_training_result dpia_training_cr_transparent(
if (link->is_hpd_pending)
result = LINK_TRAINING_ABORT;
- DC_LOG_HW_LINK_TRAINING("%s\n DPIA(%d) clock recovery\n"
- " -hop(%d)\n - result(%d)\n - retries(%d)\n",
+ DC_LOG_HW_LINK_TRAINING("%s\n DPIA(%d) clock recovery\n -hop(%d)\n - result(%d)\n - retries(%d)\n",
__func__,
link->link_id.enum_id - ENUM_ID_1,
DPRX,
@@ -545,7 +555,7 @@ static enum link_training_result dpia_training_cr_transparent(
*
* @param link DPIA link being trained.
* @param lt_settings link_setting and drive settings (voltage swing and pre-emphasis).
- * @param hop The Hop in display path. DPRX = 0.
+ * @param hop Hop in display path. DPRX = 0.
*/
static enum link_training_result dpia_training_cr_phase(
struct dc_link *link,
@@ -564,7 +574,8 @@ static enum link_training_result dpia_training_cr_phase(
}
/* Return status read interval during equalization phase. */
-static uint32_t dpia_get_eq_aux_rd_interval(const struct dc_link *link,
+static uint32_t dpia_get_eq_aux_rd_interval(
+ const struct dc_link *link,
const struct link_training_settings *lt_settings,
uint32_t hop)
{
@@ -590,12 +601,11 @@ static uint32_t dpia_get_eq_aux_rd_interval(const struct dc_link *link,
* - TPSx is transmitted for any hops downstream of DPOA.
* - Drive (VS/PE) only transmitted for the hop immediately downstream of DPOA.
* - EQ for the first hop (DPTX-to-DPIA) is assumed to be successful.
- * - DPRX EQ only reported successful when both DPRX and DPIA requirements
- * (clk sync packets sent) fulfilled.
+ * - DPRX EQ only reported successful when both DPRX and DPIA requirements (clk sync packets sent) fulfilled.
*
* @param link DPIA link being trained.
* @param lt_settings link_setting and drive settings (voltage swing and pre-emphasis).
- * @param hop The Hop in display path. DPRX = 0.
+ * @param hop Hop in display path. DPRX = 0.
*/
static enum link_training_result dpia_training_eq_non_transparent(
struct dc_link *link,
@@ -624,9 +634,10 @@ static enum link_training_result dpia_training_eq_non_transparent(
else
tr_pattern = DP_TRAINING_PATTERN_SEQUENCE_4;
- repeater_cnt = dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
+ repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
for (retries_eq = 0; retries_eq < LINK_TRAINING_MAX_RETRY_COUNT; retries_eq++) {
+
/* DPTX-to-DPIA equalization always successful. */
if (hop == repeater_cnt) {
result = LINK_TRAINING_SUCCESS;
@@ -640,7 +651,8 @@ static enum link_training_result dpia_training_eq_non_transparent(
result = LINK_TRAINING_ABORT;
break;
}
- status = core_link_send_set_config(link,
+ status = core_link_send_set_config(
+ link,
DPIA_SET_CFG_SET_TRAINING,
ts);
if (status != DC_OK) {
@@ -658,12 +670,14 @@ static enum link_training_result dpia_training_eq_non_transparent(
* drive settings for hop immediately downstream.
*/
if (hop == repeater_cnt - 1) {
- set_cfg_data = dpia_build_set_config_data(DPIA_SET_CFG_SET_VSPE,
- link,
- lt_settings);
- status = core_link_send_set_config(link,
- DPIA_SET_CFG_SET_VSPE,
- set_cfg_data);
+ set_cfg_data = dpia_build_set_config_data(
+ DPIA_SET_CFG_SET_VSPE,
+ link,
+ lt_settings);
+ status = core_link_send_set_config(
+ link,
+ DPIA_SET_CFG_SET_VSPE,
+ set_cfg_data);
if (status != DC_OK) {
result = LINK_TRAINING_ABORT;
break;
@@ -679,7 +693,7 @@ static enum link_training_result dpia_training_eq_non_transparent(
* ensure clock sync packets have been sent.
*/
if (hop == DPRX && retries_eq == 1)
- wait_time_microsec = max(wait_time_microsec, (uint32_t)DPIA_CLK_SYNC_DELAY);
+ wait_time_microsec = max(wait_time_microsec, (uint32_t) DPIA_CLK_SYNC_DELAY);
else
wait_time_microsec = dpia_get_eq_aux_rd_interval(link, lt_settings, hop);
@@ -705,8 +719,8 @@ static enum link_training_result dpia_training_eq_non_transparent(
}
if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) &&
- dp_is_symbol_locked(link->cur_link_settings.lane_count, dpcd_lane_status) &&
- dp_is_interlane_aligned(dpcd_lane_status_updated)) {
+ dp_is_symbol_locked(link->cur_link_settings.lane_count, dpcd_lane_status) &&
+ dp_is_interlane_aligned(dpcd_lane_status_updated)) {
result = LINK_TRAINING_SUCCESS;
break;
}
@@ -741,7 +755,7 @@ static enum link_training_result dpia_training_eq_non_transparent(
*
* @param link DPIA link being trained.
* @param lt_settings link_setting and drive settings (voltage swing and pre-emphasis).
- * @param hop The Hop in display path. DPRX = 0.
+ * @param hop Hop in display path. DPRX = 0.
*/
static enum link_training_result dpia_training_eq_transparent(
struct dc_link *link,
@@ -761,6 +775,7 @@ static enum link_training_result dpia_training_eq_transparent(
wait_time_microsec = dpia_get_eq_aux_rd_interval(link, lt_settings, DPRX);
for (retries_eq = 0; retries_eq < LINK_TRAINING_MAX_RETRY_COUNT; retries_eq++) {
+
if (retries_eq == 0) {
status = dpcd_set_lt_pattern(link, tr_pattern, DPRX);
if (status != DC_OK) {
@@ -810,8 +825,7 @@ static enum link_training_result dpia_training_eq_transparent(
if (link->is_hpd_pending)
result = LINK_TRAINING_ABORT;
- DC_LOG_HW_LINK_TRAINING("%s\n DPIA(%d) equalization\n"
- " - hop(%d)\n - result(%d)\n - retries(%d)\n",
+ DC_LOG_HW_LINK_TRAINING("%s\n DPIA(%d) equalization\n - hop(%d)\n - result(%d)\n - retries(%d)\n",
__func__,
link->link_id.enum_id - ENUM_ID_1,
DPRX,
@@ -826,7 +840,7 @@ static enum link_training_result dpia_training_eq_transparent(
*
* @param link DPIA link being trained.
* @param lt_settings link_setting and drive settings (voltage swing and pre-emphasis).
- * @param hop The Hop in display path. DPRX = 0.
+ * @param hop Hop in display path. DPRX = 0.
*/
static enum link_training_result dpia_training_eq_phase(
struct dc_link *link,
@@ -845,7 +859,9 @@ static enum link_training_result dpia_training_eq_phase(
}
/* End training of specified hop in display path. */
-static enum dc_status dpcd_clear_lt_pattern(struct dc_link *link, uint32_t hop)
+static enum dc_status dpcd_clear_lt_pattern(
+ struct dc_link *link,
+ uint32_t hop)
{
union dpcd_training_pattern dpcd_pattern = {0};
uint32_t dpcd_tps_offset = DP_TRAINING_PATTERN_SET;
@@ -855,7 +871,8 @@ static enum dc_status dpcd_clear_lt_pattern(struct dc_link *link, uint32_t hop)
dpcd_tps_offset = DP_TRAINING_PATTERN_SET_PHY_REPEATER1 +
((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (hop - 1));
- status = core_link_write_dpcd(link,
+ status = core_link_write_dpcd(
+ link,
dpcd_tps_offset,
&dpcd_pattern.raw,
sizeof(dpcd_pattern.raw));
@@ -873,9 +890,10 @@ static enum dc_status dpcd_clear_lt_pattern(struct dc_link *link, uint32_t hop)
* (DPTX-to-DPIA) and last hop (DPRX).
*
* @param link DPIA link being trained.
- * @param hop The Hop in display path. DPRX = 0.
+ * @param hop Hop in display path. DPRX = 0.
*/
-static enum link_training_result dpia_training_end(struct dc_link *link,
+static enum link_training_result dpia_training_end(
+ struct dc_link *link,
struct link_training_settings *lt_settings,
uint32_t hop)
{
@@ -884,13 +902,15 @@ static enum link_training_result dpia_training_end(struct dc_link *link,
enum dc_status status;
if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
- repeater_cnt = dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
+
+ repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
if (hop == repeater_cnt) { /* DPTX-to-DPIA */
/* Send SET_CONFIG(SET_TRAINING:0xff) to notify DPOA that
* DPTX-to-DPIA hop trained. No DPCD write needed for first hop.
*/
- status = core_link_send_set_config(link,
+ status = core_link_send_set_config(
+ link,
DPIA_SET_CFG_SET_TRAINING,
DPIA_TS_UFP_DONE);
if (status != DC_OK)
@@ -904,7 +924,8 @@ static enum link_training_result dpia_training_end(struct dc_link *link,
/* Notify DPOA that non-transparent link training of DPRX done. */
if (hop == DPRX && result != LINK_TRAINING_ABORT) {
- status = core_link_send_set_config(link,
+ status = core_link_send_set_config(
+ link,
DPIA_SET_CFG_SET_TRAINING,
DPIA_TS_DPRX_DONE);
if (status != DC_OK)
@@ -912,18 +933,20 @@ static enum link_training_result dpia_training_end(struct dc_link *link,
}
} else { /* non-LTTPR or transparent LTTPR. */
+
/* Write 0x0 to TRAINING_PATTERN_SET */
status = dpcd_clear_lt_pattern(link, hop);
if (status != DC_OK)
result = LINK_TRAINING_ABORT;
+
}
DC_LOG_HW_LINK_TRAINING("%s\n DPIA(%d) end\n - hop(%d)\n - result(%d)\n - LTTPR mode(%d)\n",
- __func__,
- link->link_id.enum_id - ENUM_ID_1,
- hop,
- result,
- lt_settings->lttpr_mode);
+ __func__,
+ link->link_id.enum_id - ENUM_ID_1,
+ hop,
+ result,
+ lt_settings->lttpr_mode);
return result;
}
@@ -933,20 +956,21 @@ static enum link_training_result dpia_training_end(struct dc_link *link,
* - Sending SET_CONFIG(SET_LINK) with lane count and link rate set to 0.
*
* @param link DPIA link being trained.
- * @param hop The Hop in display path. DPRX = 0.
+ * @param hop Hop in display path. DPRX = 0.
*/
-static void dpia_training_abort(struct dc_link *link,
- struct link_training_settings *lt_settings,
- uint32_t hop)
+static void dpia_training_abort(
+ struct dc_link *link,
+ struct link_training_settings *lt_settings,
+ uint32_t hop)
{
uint8_t data = 0;
uint32_t dpcd_tps_offset = DP_TRAINING_PATTERN_SET;
DC_LOG_HW_LINK_TRAINING("%s\n DPIA(%d) aborting\n - LTTPR mode(%d)\n - HPD(%d)\n",
- __func__,
- link->link_id.enum_id - ENUM_ID_1,
- lt_settings->lttpr_mode,
- link->is_hpd_pending);
+ __func__,
+ link->link_id.enum_id - ENUM_ID_1,
+ lt_settings->lttpr_mode,
+ link->is_hpd_pending);
/* Abandon clean-up if sink unplugged. */
if (link->is_hpd_pending)
@@ -975,7 +999,7 @@ enum link_training_result dc_link_dpia_perform_link_training(
struct dc_link_settings link_settings = *link_setting; // non-const copy to pass in
- lt_settings.lttpr_mode = dp_decide_lttpr_mode(link, &link_settings);
+ lt_settings.lttpr_mode = dc_link_decide_lttpr_mode(link, &link_settings);
/* Configure link as prescribed in link_setting and set LTTPR mode. */
result = dpia_configure_link(link, link_res, link_setting, &lt_settings);
@@ -983,7 +1007,7 @@ enum link_training_result dc_link_dpia_perform_link_training(
return result;
if (lt_settings.lttpr_mode == LTTPR_MODE_NON_TRANSPARENT)
- repeater_cnt = dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
+ repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
/* Train each hop in turn starting with the one closest to DPTX.
* In transparent or non-LTTPR mode, train only the final hop (DPRX).
@@ -1014,10 +1038,10 @@ enum link_training_result dc_link_dpia_perform_link_training(
msleep(5);
if (!link->is_automated)
result = dp_check_link_loss_status(link, &lt_settings);
- } else if (result == LINK_TRAINING_ABORT) {
+ } else if (result == LINK_TRAINING_ABORT)
dpia_training_abort(link, &lt_settings, repeater_id);
- } else {
+ else
dpia_training_end(link, &lt_settings, repeater_id);
- }
+
return result;
}
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.h
new file mode 100644
index 000000000000..0150f2916421
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+
+
+#ifndef __DC_LINK_DP_TRAINING_DPIA_H__
+#define __DC_LINK_DP_TRAINING_DPIA_H__
+#include "link_dp_training.h"
+
+/* Train DP tunneling link for USB4 DPIA display endpoint.
+ * DPIA equivalent of dc_link_dp_perfrorm_link_training.
+ * Aborts link training upon detection of sink unplug.
+ */
+enum link_training_result dc_link_dpia_perform_link_training(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ const struct dc_link_settings *link_setting,
+ bool skip_video_pattern);
+
+#endif /* __DC_LINK_DP_TRAINING_DPIA_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c
new file mode 100644
index 000000000000..a4071d2959a0
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c
@@ -0,0 +1,579 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+
+/* FILE POLICY AND INTENDED USAGE:
+ * This file implements 8b/10b link training specially modified to support an
+ * embedded retimer chip. This retimer chip is referred as fixed vs pe retimer.
+ * Unlike native dp connection this chip requires a modified link training
+ * protocol based on 8b/10b link training. Since this is a non standard sequence
+ * and we must support this hardware, we decided to isolate it in its own
+ * training sequence inside its own file.
+ */
+#include "link_dp_training_fixed_vs_pe_retimer.h"
+#include "link_dp_training_8b_10b.h"
+#include "link_dpcd.h"
+#include "link_dp_phy.h"
+#include "link_dp_capability.h"
+
+#define DC_LOGGER \
+ link->ctx->logger
+
+void dp_fixed_vs_pe_read_lane_adjust(
+ struct dc_link *link,
+ union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX])
+{
+ const uint8_t vendor_lttpr_write_data_vs[3] = {0x0, 0x53, 0x63};
+ const uint8_t vendor_lttpr_write_data_pe[3] = {0x0, 0x54, 0x63};
+ const uint8_t offset = dp_parse_lttpr_repeater_count(
+ link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
+ uint32_t vendor_lttpr_write_address = 0xF004F;
+ uint32_t vendor_lttpr_read_address = 0xF0053;
+ uint8_t dprx_vs = 0;
+ uint8_t dprx_pe = 0;
+ uint8_t lane;
+
+ if (offset != 0xFF) {
+ vendor_lttpr_write_address +=
+ ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
+ vendor_lttpr_read_address +=
+ ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
+ }
+
+ /* W/A to read lane settings requested by DPRX */
+ core_link_write_dpcd(
+ link,
+ vendor_lttpr_write_address,
+ &vendor_lttpr_write_data_vs[0],
+ sizeof(vendor_lttpr_write_data_vs));
+ core_link_read_dpcd(
+ link,
+ vendor_lttpr_read_address,
+ &dprx_vs,
+ 1);
+ core_link_write_dpcd(
+ link,
+ vendor_lttpr_write_address,
+ &vendor_lttpr_write_data_pe[0],
+ sizeof(vendor_lttpr_write_data_pe));
+ core_link_read_dpcd(
+ link,
+ vendor_lttpr_read_address,
+ &dprx_pe,
+ 1);
+
+ for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
+ dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_SET = (dprx_vs >> (2 * lane)) & 0x3;
+ dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_SET = (dprx_pe >> (2 * lane)) & 0x3;
+ }
+}
+
+
+void dp_fixed_vs_pe_set_retimer_lane_settings(
+ struct dc_link *link,
+ const union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX],
+ uint8_t lane_count)
+{
+ const uint8_t offset = dp_parse_lttpr_repeater_count(
+ link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
+ const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF};
+ uint32_t vendor_lttpr_write_address = 0xF004F;
+ uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0};
+ uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0};
+ uint8_t lane = 0;
+
+ if (offset != 0xFF) {
+ vendor_lttpr_write_address +=
+ ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
+ }
+
+ for (lane = 0; lane < lane_count; lane++) {
+ vendor_lttpr_write_data_vs[3] |=
+ dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
+ vendor_lttpr_write_data_pe[3] |=
+ dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
+ }
+
+ /* Force LTTPR to output desired VS and PE */
+ core_link_write_dpcd(
+ link,
+ vendor_lttpr_write_address,
+ &vendor_lttpr_write_data_reset[0],
+ sizeof(vendor_lttpr_write_data_reset));
+ core_link_write_dpcd(
+ link,
+ vendor_lttpr_write_address,
+ &vendor_lttpr_write_data_vs[0],
+ sizeof(vendor_lttpr_write_data_vs));
+ core_link_write_dpcd(
+ link,
+ vendor_lttpr_write_address,
+ &vendor_lttpr_write_data_pe[0],
+ sizeof(vendor_lttpr_write_data_pe));
+}
+
+static enum link_training_result perform_fixed_vs_pe_nontransparent_training_sequence(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ struct link_training_settings *lt_settings)
+{
+ enum link_training_result status = LINK_TRAINING_SUCCESS;
+ uint8_t lane = 0;
+ uint8_t toggle_rate = 0x6;
+ uint8_t target_rate = 0x6;
+ bool apply_toggle_rate_wa = false;
+ uint8_t repeater_cnt;
+ uint8_t repeater_id;
+
+ /* Fixed VS/PE specific: Force CR AUX RD Interval to at least 16ms */
+ if (lt_settings->cr_pattern_time < 16000)
+ lt_settings->cr_pattern_time = 16000;
+
+ /* Fixed VS/PE specific: Toggle link rate */
+ apply_toggle_rate_wa = (link->vendor_specific_lttpr_link_rate_wa == target_rate);
+ target_rate = get_dpcd_link_rate(&lt_settings->link_settings);
+ toggle_rate = (target_rate == 0x6) ? 0xA : 0x6;
+
+ if (apply_toggle_rate_wa)
+ lt_settings->link_settings.link_rate = toggle_rate;
+
+ if (link->ctx->dc->work_arounds.lt_early_cr_pattern)
+ start_clock_recovery_pattern_early(link, link_res, lt_settings, DPRX);
+
+ /* 1. set link rate, lane count and spread. */
+ dpcd_set_link_settings(link, lt_settings);
+
+ /* Fixed VS/PE specific: Toggle link rate back*/
+ if (apply_toggle_rate_wa) {
+ core_link_write_dpcd(
+ link,
+ DP_LINK_BW_SET,
+ &target_rate,
+ 1);
+ }
+
+ link->vendor_specific_lttpr_link_rate_wa = target_rate;
+
+ if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
+
+ /* 2. perform link training (set link training done
+ * to false is done as well)
+ */
+ repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
+
+ for (repeater_id = repeater_cnt; (repeater_id > 0 && status == LINK_TRAINING_SUCCESS);
+ repeater_id--) {
+ status = perform_8b_10b_clock_recovery_sequence(link, link_res, lt_settings, repeater_id);
+
+ if (status != LINK_TRAINING_SUCCESS) {
+ repeater_training_done(link, repeater_id);
+ break;
+ }
+
+ status = perform_8b_10b_channel_equalization_sequence(link,
+ link_res,
+ lt_settings,
+ repeater_id);
+
+ repeater_training_done(link, repeater_id);
+
+ if (status != LINK_TRAINING_SUCCESS)
+ break;
+
+ for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
+ lt_settings->dpcd_lane_settings[lane].raw = 0;
+ lt_settings->hw_lane_settings[lane].VOLTAGE_SWING = 0;
+ lt_settings->hw_lane_settings[lane].PRE_EMPHASIS = 0;
+ }
+ }
+ }
+
+ if (status == LINK_TRAINING_SUCCESS) {
+ status = perform_8b_10b_clock_recovery_sequence(link, link_res, lt_settings, DPRX);
+ if (status == LINK_TRAINING_SUCCESS) {
+ status = perform_8b_10b_channel_equalization_sequence(link,
+ link_res,
+ lt_settings,
+ DPRX);
+ }
+ }
+
+ return status;
+}
+
+
+enum link_training_result dp_perform_fixed_vs_pe_training_sequence(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ struct link_training_settings *lt_settings)
+{
+ const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF};
+ const uint8_t offset = dp_parse_lttpr_repeater_count(
+ link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
+ const uint8_t vendor_lttpr_write_data_intercept_en[4] = {0x1, 0x55, 0x63, 0x0};
+ const uint8_t vendor_lttpr_write_data_intercept_dis[4] = {0x1, 0x55, 0x63, 0x68};
+ uint32_t pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa;
+ uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0};
+ uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0};
+ uint32_t vendor_lttpr_write_address = 0xF004F;
+ enum link_training_result status = LINK_TRAINING_SUCCESS;
+ uint8_t lane = 0;
+ union down_spread_ctrl downspread = {0};
+ union lane_count_set lane_count_set = {0};
+ uint8_t toggle_rate;
+ uint8_t rate;
+
+ /* Only 8b/10b is supported */
+ ASSERT(link_dp_get_encoding_format(&lt_settings->link_settings) ==
+ DP_8b_10b_ENCODING);
+
+ if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
+ status = perform_fixed_vs_pe_nontransparent_training_sequence(link, link_res, lt_settings);
+ return status;
+ }
+
+ if (offset != 0xFF) {
+ vendor_lttpr_write_address +=
+ ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
+
+ /* Certain display and cable configuration require extra delay */
+ if (offset > 2)
+ pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa * 2;
+ }
+
+ /* Vendor specific: Reset lane settings */
+ core_link_write_dpcd(
+ link,
+ vendor_lttpr_write_address,
+ &vendor_lttpr_write_data_reset[0],
+ sizeof(vendor_lttpr_write_data_reset));
+ core_link_write_dpcd(
+ link,
+ vendor_lttpr_write_address,
+ &vendor_lttpr_write_data_vs[0],
+ sizeof(vendor_lttpr_write_data_vs));
+ core_link_write_dpcd(
+ link,
+ vendor_lttpr_write_address,
+ &vendor_lttpr_write_data_pe[0],
+ sizeof(vendor_lttpr_write_data_pe));
+
+ /* Vendor specific: Enable intercept */
+ core_link_write_dpcd(
+ link,
+ vendor_lttpr_write_address,
+ &vendor_lttpr_write_data_intercept_en[0],
+ sizeof(vendor_lttpr_write_data_intercept_en));
+
+ /* 1. set link rate, lane count and spread. */
+
+ downspread.raw = (uint8_t)(lt_settings->link_settings.link_spread);
+
+ lane_count_set.bits.LANE_COUNT_SET =
+ lt_settings->link_settings.lane_count;
+
+ lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
+ lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
+
+
+ if (lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) {
+ lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED =
+ link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED;
+ }
+
+ core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL,
+ &downspread.raw, sizeof(downspread));
+
+ core_link_write_dpcd(link, DP_LANE_COUNT_SET,
+ &lane_count_set.raw, 1);
+
+ rate = get_dpcd_link_rate(&lt_settings->link_settings);
+
+ /* Vendor specific: Toggle link rate */
+ toggle_rate = (rate == 0x6) ? 0xA : 0x6;
+
+ if (link->vendor_specific_lttpr_link_rate_wa == rate) {
+ core_link_write_dpcd(
+ link,
+ DP_LINK_BW_SET,
+ &toggle_rate,
+ 1);
+ }
+
+ link->vendor_specific_lttpr_link_rate_wa = rate;
+
+ core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1);
+
+ DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
+ __func__,
+ DP_LINK_BW_SET,
+ lt_settings->link_settings.link_rate,
+ DP_LANE_COUNT_SET,
+ lt_settings->link_settings.lane_count,
+ lt_settings->enhanced_framing,
+ DP_DOWNSPREAD_CTRL,
+ lt_settings->link_settings.link_spread);
+
+ /* 2. Perform link training */
+
+ /* Perform Clock Recovery Sequence */
+ if (status == LINK_TRAINING_SUCCESS) {
+ const uint8_t max_vendor_dpcd_retries = 10;
+ uint32_t retries_cr;
+ uint32_t retry_count;
+ uint32_t wait_time_microsec;
+ enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
+ union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX];
+ union lane_align_status_updated dpcd_lane_status_updated;
+ union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
+ enum dc_status dpcd_status = DC_OK;
+ uint8_t i = 0;
+
+ retries_cr = 0;
+ retry_count = 0;
+
+ memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status));
+ memset(&dpcd_lane_status_updated, '\0',
+ sizeof(dpcd_lane_status_updated));
+
+ while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
+ (retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
+
+
+ /* 1. call HWSS to set lane settings */
+ dp_set_hw_lane_settings(
+ link,
+ link_res,
+ lt_settings,
+ 0);
+
+ /* 2. update DPCD of the receiver */
+ if (!retry_count) {
+ /* EPR #361076 - write as a 5-byte burst,
+ * but only for the 1-st iteration.
+ */
+ dpcd_set_lt_pattern_and_lane_settings(
+ link,
+ lt_settings,
+ lt_settings->pattern_for_cr,
+ 0);
+ /* Vendor specific: Disable intercept */
+ for (i = 0; i < max_vendor_dpcd_retries; i++) {
+ msleep(pre_disable_intercept_delay_ms);
+ dpcd_status = core_link_write_dpcd(
+ link,
+ vendor_lttpr_write_address,
+ &vendor_lttpr_write_data_intercept_dis[0],
+ sizeof(vendor_lttpr_write_data_intercept_dis));
+
+ if (dpcd_status == DC_OK)
+ break;
+
+ core_link_write_dpcd(
+ link,
+ vendor_lttpr_write_address,
+ &vendor_lttpr_write_data_intercept_en[0],
+ sizeof(vendor_lttpr_write_data_intercept_en));
+ }
+ } else {
+ vendor_lttpr_write_data_vs[3] = 0;
+ vendor_lttpr_write_data_pe[3] = 0;
+
+ for (lane = 0; lane < lane_count; lane++) {
+ vendor_lttpr_write_data_vs[3] |=
+ lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
+ vendor_lttpr_write_data_pe[3] |=
+ lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
+ }
+
+ /* Vendor specific: Update VS and PE to DPRX requested value */
+ core_link_write_dpcd(
+ link,
+ vendor_lttpr_write_address,
+ &vendor_lttpr_write_data_vs[0],
+ sizeof(vendor_lttpr_write_data_vs));
+ core_link_write_dpcd(
+ link,
+ vendor_lttpr_write_address,
+ &vendor_lttpr_write_data_pe[0],
+ sizeof(vendor_lttpr_write_data_pe));
+
+ dpcd_set_lane_settings(
+ link,
+ lt_settings,
+ 0);
+ }
+
+ /* 3. wait receiver to lock-on*/
+ wait_time_microsec = lt_settings->cr_pattern_time;
+
+ dp_wait_for_training_aux_rd_interval(
+ link,
+ wait_time_microsec);
+
+ /* 4. Read lane status and requested drive
+ * settings as set by the sink
+ */
+ dp_get_lane_status_and_lane_adjust(
+ link,
+ lt_settings,
+ dpcd_lane_status,
+ &dpcd_lane_status_updated,
+ dpcd_lane_adjust,
+ 0);
+
+ /* 5. check CR done*/
+ if (dp_is_cr_done(lane_count, dpcd_lane_status)) {
+ status = LINK_TRAINING_SUCCESS;
+ break;
+ }
+
+ /* 6. max VS reached*/
+ if (dp_is_max_vs_reached(lt_settings))
+ break;
+
+ /* 7. same lane settings */
+ /* Note: settings are the same for all lanes,
+ * so comparing first lane is sufficient
+ */
+ if (lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET ==
+ dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE)
+ retries_cr++;
+ else
+ retries_cr = 0;
+
+ /* 8. update VS/PE/PC2 in lt_settings*/
+ dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
+ lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
+ retry_count++;
+ }
+
+ if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) {
+ ASSERT(0);
+ DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue",
+ __func__,
+ LINK_TRAINING_MAX_CR_RETRY);
+
+ }
+
+ status = dp_get_cr_failure(lane_count, dpcd_lane_status);
+ }
+
+ /* Perform Channel EQ Sequence */
+ if (status == LINK_TRAINING_SUCCESS) {
+ enum dc_dp_training_pattern tr_pattern;
+ uint32_t retries_ch_eq;
+ uint32_t wait_time_microsec;
+ enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
+ union lane_align_status_updated dpcd_lane_status_updated = {0};
+ union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
+ union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
+
+ /* Note: also check that TPS4 is a supported feature*/
+ tr_pattern = lt_settings->pattern_for_eq;
+
+ dp_set_hw_training_pattern(link, link_res, tr_pattern, 0);
+
+ status = LINK_TRAINING_EQ_FAIL_EQ;
+
+ for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT;
+ retries_ch_eq++) {
+
+ dp_set_hw_lane_settings(link, link_res, lt_settings, 0);
+
+ vendor_lttpr_write_data_vs[3] = 0;
+ vendor_lttpr_write_data_pe[3] = 0;
+
+ for (lane = 0; lane < lane_count; lane++) {
+ vendor_lttpr_write_data_vs[3] |=
+ lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
+ vendor_lttpr_write_data_pe[3] |=
+ lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
+ }
+
+ /* Vendor specific: Update VS and PE to DPRX requested value */
+ core_link_write_dpcd(
+ link,
+ vendor_lttpr_write_address,
+ &vendor_lttpr_write_data_vs[0],
+ sizeof(vendor_lttpr_write_data_vs));
+ core_link_write_dpcd(
+ link,
+ vendor_lttpr_write_address,
+ &vendor_lttpr_write_data_pe[0],
+ sizeof(vendor_lttpr_write_data_pe));
+
+ /* 2. update DPCD*/
+ if (!retries_ch_eq)
+ /* EPR #361076 - write as a 5-byte burst,
+ * but only for the 1-st iteration
+ */
+
+ dpcd_set_lt_pattern_and_lane_settings(
+ link,
+ lt_settings,
+ tr_pattern, 0);
+ else
+ dpcd_set_lane_settings(link, lt_settings, 0);
+
+ /* 3. wait for receiver to lock-on*/
+ wait_time_microsec = lt_settings->eq_pattern_time;
+
+ dp_wait_for_training_aux_rd_interval(
+ link,
+ wait_time_microsec);
+
+ /* 4. Read lane status and requested
+ * drive settings as set by the sink
+ */
+ dp_get_lane_status_and_lane_adjust(
+ link,
+ lt_settings,
+ dpcd_lane_status,
+ &dpcd_lane_status_updated,
+ dpcd_lane_adjust,
+ 0);
+
+ /* 5. check CR done*/
+ if (!dp_is_cr_done(lane_count, dpcd_lane_status)) {
+ status = LINK_TRAINING_EQ_FAIL_CR;
+ break;
+ }
+
+ /* 6. check CHEQ done*/
+ if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) &&
+ dp_is_symbol_locked(lane_count, dpcd_lane_status) &&
+ dp_is_interlane_aligned(dpcd_lane_status_updated)) {
+ status = LINK_TRAINING_SUCCESS;
+ break;
+ }
+
+ /* 7. update VS/PE/PC2 in lt_settings*/
+ dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
+ lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
+ }
+ }
+
+ return status;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.h
new file mode 100644
index 000000000000..e61970e27661
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+
+
+#ifndef __DC_LINK_DP_FIXED_VS_PE_RETIMER_H__
+#define __DC_LINK_DP_FIXED_VS_PE_RETIMER_H__
+#include "link_dp_training.h"
+
+enum link_training_result dp_perform_fixed_vs_pe_training_sequence(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ struct link_training_settings *lt_settings);
+
+void dp_fixed_vs_pe_set_retimer_lane_settings(
+ struct dc_link *link,
+ const union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX],
+ uint8_t lane_count);
+
+void dp_fixed_vs_pe_read_lane_adjust(
+ struct dc_link *link,
+ union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX]);
+
+#endif /* __DC_LINK_DP_FIXED_VS_PE_RETIMER_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dpcd.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dpcd.c
index af110bf9470f..5c9a30211c10 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dpcd.c
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dpcd.c
@@ -23,11 +23,14 @@
*
*/
-#include <inc/core_status.h>
-#include <dc_link.h>
-#include <inc/link_hwss.h>
-#include <inc/link_dpcd.h>
-#include <dc_dp_types.h>
+/* FILE POLICY AND INTENDED USAGE:
+ *
+ * This file implements basic dpcd read/write functionality. It also does basic
+ * dpcd range check to ensure that every dpcd request is compliant with specs
+ * range requirements.
+ */
+
+#include "link_dpcd.h"
#include <drm/display/drm_dp_helper.h>
#include "dm_helpers.h"
diff --git a/drivers/gpu/drm/amd/display/dc/inc/link_dpcd.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dpcd.h
index d561f86d503c..08d787a1e451 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/link_dpcd.h
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dpcd.h
@@ -25,9 +25,8 @@
#ifndef __LINK_DPCD_H__
#define __LINK_DPCD_H__
-#include <inc/core_status.h>
-#include <dc_link.h>
-#include <dc_link_dp.h>
+#include "link.h"
+#include "dpcd_defs.h"
enum dc_status core_link_read_dpcd(
struct dc_link *link,
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c
new file mode 100644
index 000000000000..97e02b5b21ae
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c
@@ -0,0 +1,833 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+
+/* FILE POLICY AND INTENDED USAGE:
+ * This file implements retrieval and configuration of eDP panel features such
+ * as PSR and ABM and it also manages specs defined eDP panel power sequences.
+ */
+
+#include "link_edp_panel_control.h"
+#include "link_dpcd.h"
+#include "link_dp_capability.h"
+#include "dm_helpers.h"
+#include "dal_asic_id.h"
+#include "dce/dmub_psr.h"
+#include "abm.h"
+#define DC_LOGGER_INIT(logger)
+
+void dp_set_panel_mode(struct dc_link *link, enum dp_panel_mode panel_mode)
+{
+ union dpcd_edp_config edp_config_set;
+ bool panel_mode_edp = false;
+
+ memset(&edp_config_set, '\0', sizeof(union dpcd_edp_config));
+
+ if (panel_mode != DP_PANEL_MODE_DEFAULT) {
+
+ switch (panel_mode) {
+ case DP_PANEL_MODE_EDP:
+ case DP_PANEL_MODE_SPECIAL:
+ panel_mode_edp = true;
+ break;
+
+ default:
+ break;
+ }
+
+ /*set edp panel mode in receiver*/
+ core_link_read_dpcd(
+ link,
+ DP_EDP_CONFIGURATION_SET,
+ &edp_config_set.raw,
+ sizeof(edp_config_set.raw));
+
+ if (edp_config_set.bits.PANEL_MODE_EDP
+ != panel_mode_edp) {
+ enum dc_status result;
+
+ edp_config_set.bits.PANEL_MODE_EDP =
+ panel_mode_edp;
+ result = core_link_write_dpcd(
+ link,
+ DP_EDP_CONFIGURATION_SET,
+ &edp_config_set.raw,
+ sizeof(edp_config_set.raw));
+
+ ASSERT(result == DC_OK);
+ }
+ }
+ DC_LOG_DETECTION_DP_CAPS("Link: %d eDP panel mode supported: %d "
+ "eDP panel mode enabled: %d \n",
+ link->link_index,
+ link->dpcd_caps.panel_mode_edp,
+ panel_mode_edp);
+}
+
+enum dp_panel_mode dp_get_panel_mode(struct dc_link *link)
+{
+ /* We need to explicitly check that connector
+ * is not DP. Some Travis_VGA get reported
+ * by video bios as DP.
+ */
+ if (link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT) {
+
+ switch (link->dpcd_caps.branch_dev_id) {
+ case DP_BRANCH_DEVICE_ID_0022B9:
+ /* alternate scrambler reset is required for Travis
+ * for the case when external chip does not
+ * provide sink device id, alternate scrambler
+ * scheme will be overriden later by querying
+ * Encoder features
+ */
+ if (strncmp(
+ link->dpcd_caps.branch_dev_name,
+ DP_VGA_LVDS_CONVERTER_ID_2,
+ sizeof(
+ link->dpcd_caps.
+ branch_dev_name)) == 0) {
+ return DP_PANEL_MODE_SPECIAL;
+ }
+ break;
+ case DP_BRANCH_DEVICE_ID_00001A:
+ /* alternate scrambler reset is required for Travis
+ * for the case when external chip does not provide
+ * sink device id, alternate scrambler scheme will
+ * be overriden later by querying Encoder feature
+ */
+ if (strncmp(link->dpcd_caps.branch_dev_name,
+ DP_VGA_LVDS_CONVERTER_ID_3,
+ sizeof(
+ link->dpcd_caps.
+ branch_dev_name)) == 0) {
+ return DP_PANEL_MODE_SPECIAL;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (link->dpcd_caps.panel_mode_edp &&
+ (link->connector_signal == SIGNAL_TYPE_EDP ||
+ (link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT &&
+ link->is_internal_display))) {
+ return DP_PANEL_MODE_EDP;
+ }
+
+ return DP_PANEL_MODE_DEFAULT;
+}
+
+bool dc_link_set_backlight_level_nits(struct dc_link *link,
+ bool isHDR,
+ uint32_t backlight_millinits,
+ uint32_t transition_time_in_ms)
+{
+ struct dpcd_source_backlight_set dpcd_backlight_set;
+ uint8_t backlight_control = isHDR ? 1 : 0;
+
+ if (!link || (link->connector_signal != SIGNAL_TYPE_EDP &&
+ link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT))
+ return false;
+
+ // OLEDs have no PWM, they can only use AUX
+ if (link->dpcd_sink_ext_caps.bits.oled == 1)
+ backlight_control = 1;
+
+ *(uint32_t *)&dpcd_backlight_set.backlight_level_millinits = backlight_millinits;
+ *(uint16_t *)&dpcd_backlight_set.backlight_transition_time_ms = (uint16_t)transition_time_in_ms;
+
+
+ if (core_link_write_dpcd(link, DP_SOURCE_BACKLIGHT_LEVEL,
+ (uint8_t *)(&dpcd_backlight_set),
+ sizeof(dpcd_backlight_set)) != DC_OK)
+ return false;
+
+ if (core_link_write_dpcd(link, DP_SOURCE_BACKLIGHT_CONTROL,
+ &backlight_control, 1) != DC_OK)
+ return false;
+
+ return true;
+}
+
+bool dc_link_get_backlight_level_nits(struct dc_link *link,
+ uint32_t *backlight_millinits_avg,
+ uint32_t *backlight_millinits_peak)
+{
+ union dpcd_source_backlight_get dpcd_backlight_get;
+
+ memset(&dpcd_backlight_get, 0, sizeof(union dpcd_source_backlight_get));
+
+ if (!link || (link->connector_signal != SIGNAL_TYPE_EDP &&
+ link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT))
+ return false;
+
+ if (!core_link_read_dpcd(link, DP_SOURCE_BACKLIGHT_CURRENT_PEAK,
+ dpcd_backlight_get.raw,
+ sizeof(union dpcd_source_backlight_get)))
+ return false;
+
+ *backlight_millinits_avg =
+ dpcd_backlight_get.bytes.backlight_millinits_avg;
+ *backlight_millinits_peak =
+ dpcd_backlight_get.bytes.backlight_millinits_peak;
+
+ /* On non-supported panels dpcd_read usually succeeds with 0 returned */
+ if (*backlight_millinits_avg == 0 ||
+ *backlight_millinits_avg > *backlight_millinits_peak)
+ return false;
+
+ return true;
+}
+
+bool link_backlight_enable_aux(struct dc_link *link, bool enable)
+{
+ uint8_t backlight_enable = enable ? 1 : 0;
+
+ if (!link || (link->connector_signal != SIGNAL_TYPE_EDP &&
+ link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT))
+ return false;
+
+ if (core_link_write_dpcd(link, DP_SOURCE_BACKLIGHT_ENABLE,
+ &backlight_enable, 1) != DC_OK)
+ return false;
+
+ return true;
+}
+
+// we read default from 0x320 because we expect BIOS wrote it there
+// regular get_backlight_nit reads from panel set at 0x326
+static bool read_default_bl_aux(struct dc_link *link, uint32_t *backlight_millinits)
+{
+ if (!link || (link->connector_signal != SIGNAL_TYPE_EDP &&
+ link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT))
+ return false;
+
+ if (!core_link_read_dpcd(link, DP_SOURCE_BACKLIGHT_LEVEL,
+ (uint8_t *) backlight_millinits,
+ sizeof(uint32_t)))
+ return false;
+
+ return true;
+}
+
+bool set_default_brightness_aux(struct dc_link *link)
+{
+ uint32_t default_backlight;
+
+ if (link && link->dpcd_sink_ext_caps.bits.oled == 1) {
+ if (!read_default_bl_aux(link, &default_backlight))
+ default_backlight = 150000;
+ // if < 5 nits or > 5000, it might be wrong readback
+ if (default_backlight < 5000 || default_backlight > 5000000)
+ default_backlight = 150000; //
+
+ return dc_link_set_backlight_level_nits(link, true,
+ default_backlight, 0);
+ }
+ return false;
+}
+
+bool link_is_edp_ilr_optimization_required(struct dc_link *link,
+ struct dc_crtc_timing *crtc_timing)
+{
+ struct dc_link_settings link_setting;
+ uint8_t link_bw_set;
+ uint8_t link_rate_set;
+ uint32_t req_bw;
+ union lane_count_set lane_count_set = {0};
+
+ ASSERT(link || crtc_timing); // invalid input
+
+ if (link->dpcd_caps.edp_supported_link_rates_count == 0 ||
+ !link->panel_config.ilr.optimize_edp_link_rate)
+ return false;
+
+
+ // Read DPCD 00100h to find if standard link rates are set
+ core_link_read_dpcd(link, DP_LINK_BW_SET,
+ &link_bw_set, sizeof(link_bw_set));
+
+ if (link_bw_set) {
+ DC_LOG_EVENT_LINK_TRAINING("eDP ILR: Optimization required, VBIOS used link_bw_set\n");
+ return true;
+ }
+
+ // Read DPCD 00115h to find the edp link rate set used
+ core_link_read_dpcd(link, DP_LINK_RATE_SET,
+ &link_rate_set, sizeof(link_rate_set));
+
+ // Read DPCD 00101h to find out the number of lanes currently set
+ core_link_read_dpcd(link, DP_LANE_COUNT_SET,
+ &lane_count_set.raw, sizeof(lane_count_set));
+
+ req_bw = dc_bandwidth_in_kbps_from_timing(crtc_timing);
+
+ if (!crtc_timing->flags.DSC)
+ dc_link_decide_edp_link_settings(link, &link_setting, req_bw);
+ else
+ decide_edp_link_settings_with_dsc(link, &link_setting, req_bw, LINK_RATE_UNKNOWN);
+
+ if (link->dpcd_caps.edp_supported_link_rates[link_rate_set] != link_setting.link_rate ||
+ lane_count_set.bits.LANE_COUNT_SET != link_setting.lane_count) {
+ DC_LOG_EVENT_LINK_TRAINING("eDP ILR: Optimization required, VBIOS link_rate_set not optimal\n");
+ return true;
+ }
+
+ DC_LOG_EVENT_LINK_TRAINING("eDP ILR: No optimization required, VBIOS set optimal link_rate_set\n");
+ return false;
+}
+
+void dc_link_edp_panel_backlight_power_on(struct dc_link *link, bool wait_for_hpd)
+{
+ if (link->connector_signal != SIGNAL_TYPE_EDP)
+ return;
+
+ link->dc->hwss.edp_power_control(link, true);
+ if (wait_for_hpd)
+ link->dc->hwss.edp_wait_for_hpd_ready(link, true);
+ if (link->dc->hwss.edp_backlight_control)
+ link->dc->hwss.edp_backlight_control(link, true);
+}
+
+bool dc_link_wait_for_t12(struct dc_link *link)
+{
+ if (link->connector_signal == SIGNAL_TYPE_EDP && link->dc->hwss.edp_wait_for_T12) {
+ link->dc->hwss.edp_wait_for_T12(link);
+
+ return true;
+ }
+
+ return false;
+}
+
+void link_edp_add_delay_for_T9(struct dc_link *link)
+{
+ if (link && link->panel_config.pps.extra_delay_backlight_off > 0)
+ udelay(link->panel_config.pps.extra_delay_backlight_off * 1000);
+}
+
+bool link_edp_receiver_ready_T9(struct dc_link *link)
+{
+ unsigned int tries = 0;
+ unsigned char sinkstatus = 0;
+ unsigned char edpRev = 0;
+ enum dc_status result = DC_OK;
+
+ result = core_link_read_dpcd(link, DP_EDP_DPCD_REV, &edpRev, sizeof(edpRev));
+
+ /* start from eDP version 1.2, SINK_STAUS indicate the sink is ready.*/
+ if (result == DC_OK && edpRev >= DP_EDP_12) {
+ do {
+ sinkstatus = 1;
+ result = core_link_read_dpcd(link, DP_SINK_STATUS, &sinkstatus, sizeof(sinkstatus));
+ if (sinkstatus == 0)
+ break;
+ if (result != DC_OK)
+ break;
+ udelay(100); //MAx T9
+ } while (++tries < 50);
+ }
+
+ return result;
+}
+
+bool link_edp_receiver_ready_T7(struct dc_link *link)
+{
+ unsigned char sinkstatus = 0;
+ unsigned char edpRev = 0;
+ enum dc_status result = DC_OK;
+
+ /* use absolute time stamp to constrain max T7*/
+ unsigned long long enter_timestamp = 0;
+ unsigned long long finish_timestamp = 0;
+ unsigned long long time_taken_in_ns = 0;
+
+ result = core_link_read_dpcd(link, DP_EDP_DPCD_REV, &edpRev, sizeof(edpRev));
+
+ if (result == DC_OK && edpRev >= DP_EDP_12) {
+ /* start from eDP version 1.2, SINK_STAUS indicate the sink is ready.*/
+ enter_timestamp = dm_get_timestamp(link->ctx);
+ do {
+ sinkstatus = 0;
+ result = core_link_read_dpcd(link, DP_SINK_STATUS, &sinkstatus, sizeof(sinkstatus));
+ if (sinkstatus == 1)
+ break;
+ if (result != DC_OK)
+ break;
+ udelay(25);
+ finish_timestamp = dm_get_timestamp(link->ctx);
+ time_taken_in_ns = dm_get_elapse_time_in_ns(link->ctx, finish_timestamp, enter_timestamp);
+ } while (time_taken_in_ns < 50 * 1000000); //MAx T7 is 50ms
+ }
+
+ if (link && link->panel_config.pps.extra_t7_ms > 0)
+ udelay(link->panel_config.pps.extra_t7_ms * 1000);
+
+ return result;
+}
+
+bool link_power_alpm_dpcd_enable(struct dc_link *link, bool enable)
+{
+ bool ret = false;
+ union dpcd_alpm_configuration alpm_config;
+
+ if (link->psr_settings.psr_version == DC_PSR_VERSION_SU_1) {
+ memset(&alpm_config, 0, sizeof(alpm_config));
+
+ alpm_config.bits.ENABLE = (enable ? true : false);
+ ret = dm_helpers_dp_write_dpcd(link->ctx, link,
+ DP_RECEIVER_ALPM_CONFIG, &alpm_config.raw,
+ sizeof(alpm_config.raw));
+ }
+ return ret;
+}
+
+static struct pipe_ctx *get_pipe_from_link(const struct dc_link *link)
+{
+ int i;
+ struct dc *dc = link->ctx->dc;
+ struct pipe_ctx *pipe_ctx = NULL;
+
+ for (i = 0; i < MAX_PIPES; i++) {
+ if (dc->current_state->res_ctx.pipe_ctx[i].stream) {
+ if (dc->current_state->res_ctx.pipe_ctx[i].stream->link == link) {
+ pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
+ break;
+ }
+ }
+ }
+
+ return pipe_ctx;
+}
+
+bool dc_link_set_backlight_level(const struct dc_link *link,
+ uint32_t backlight_pwm_u16_16,
+ uint32_t frame_ramp)
+{
+ struct dc *dc = link->ctx->dc;
+
+ DC_LOGGER_INIT(link->ctx->logger);
+ DC_LOG_BACKLIGHT("New Backlight level: %d (0x%X)\n",
+ backlight_pwm_u16_16, backlight_pwm_u16_16);
+
+ if (dc_is_embedded_signal(link->connector_signal)) {
+ struct pipe_ctx *pipe_ctx = get_pipe_from_link(link);
+
+ if (pipe_ctx) {
+ /* Disable brightness ramping when the display is blanked
+ * as it can hang the DMCU
+ */
+ if (pipe_ctx->plane_state == NULL)
+ frame_ramp = 0;
+ } else {
+ return false;
+ }
+
+ dc->hwss.set_backlight_level(
+ pipe_ctx,
+ backlight_pwm_u16_16,
+ frame_ramp);
+ }
+ return true;
+}
+
+bool dc_link_set_psr_allow_active(struct dc_link *link, const bool *allow_active,
+ bool wait, bool force_static, const unsigned int *power_opts)
+{
+ struct dc *dc = link->ctx->dc;
+ struct dmcu *dmcu = dc->res_pool->dmcu;
+ struct dmub_psr *psr = dc->res_pool->psr;
+ unsigned int panel_inst;
+
+ if (psr == NULL && force_static)
+ return false;
+
+ if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst))
+ return false;
+
+ if ((allow_active != NULL) && (*allow_active == true) && (link->type == dc_connection_none)) {
+ // Don't enter PSR if panel is not connected
+ return false;
+ }
+
+ /* Set power optimization flag */
+ if (power_opts && link->psr_settings.psr_power_opt != *power_opts) {
+ link->psr_settings.psr_power_opt = *power_opts;
+
+ if (psr != NULL && link->psr_settings.psr_feature_enabled && psr->funcs->psr_set_power_opt)
+ psr->funcs->psr_set_power_opt(psr, link->psr_settings.psr_power_opt, panel_inst);
+ }
+
+ if (psr != NULL && link->psr_settings.psr_feature_enabled &&
+ force_static && psr->funcs->psr_force_static)
+ psr->funcs->psr_force_static(psr, panel_inst);
+
+ /* Enable or Disable PSR */
+ if (allow_active && link->psr_settings.psr_allow_active != *allow_active) {
+ link->psr_settings.psr_allow_active = *allow_active;
+
+ if (!link->psr_settings.psr_allow_active)
+ dc_z10_restore(dc);
+
+ if (psr != NULL && link->psr_settings.psr_feature_enabled) {
+ psr->funcs->psr_enable(psr, link->psr_settings.psr_allow_active, wait, panel_inst);
+ } else if ((dmcu != NULL && dmcu->funcs->is_dmcu_initialized(dmcu)) &&
+ link->psr_settings.psr_feature_enabled)
+ dmcu->funcs->set_psr_enable(dmcu, link->psr_settings.psr_allow_active, wait);
+ else
+ return false;
+ }
+ return true;
+}
+
+bool dc_link_get_psr_state(const struct dc_link *link, enum dc_psr_state *state)
+{
+ struct dc *dc = link->ctx->dc;
+ struct dmcu *dmcu = dc->res_pool->dmcu;
+ struct dmub_psr *psr = dc->res_pool->psr;
+ unsigned int panel_inst;
+
+ if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst))
+ return false;
+
+ if (psr != NULL && link->psr_settings.psr_feature_enabled)
+ psr->funcs->psr_get_state(psr, state, panel_inst);
+ else if (dmcu != NULL && link->psr_settings.psr_feature_enabled)
+ dmcu->funcs->get_psr_state(dmcu, state);
+
+ return true;
+}
+
+static inline enum physical_phy_id
+transmitter_to_phy_id(struct dc_link *link)
+{
+ struct dc_context *dc_ctx = link->ctx;
+ enum transmitter transmitter_value = link->link_enc->transmitter;
+
+ switch (transmitter_value) {
+ case TRANSMITTER_UNIPHY_A:
+ return PHYLD_0;
+ case TRANSMITTER_UNIPHY_B:
+ return PHYLD_1;
+ case TRANSMITTER_UNIPHY_C:
+ return PHYLD_2;
+ case TRANSMITTER_UNIPHY_D:
+ return PHYLD_3;
+ case TRANSMITTER_UNIPHY_E:
+ return PHYLD_4;
+ case TRANSMITTER_UNIPHY_F:
+ return PHYLD_5;
+ case TRANSMITTER_NUTMEG_CRT:
+ return PHYLD_6;
+ case TRANSMITTER_TRAVIS_CRT:
+ return PHYLD_7;
+ case TRANSMITTER_TRAVIS_LCD:
+ return PHYLD_8;
+ case TRANSMITTER_UNIPHY_G:
+ return PHYLD_9;
+ case TRANSMITTER_COUNT:
+ return PHYLD_COUNT;
+ case TRANSMITTER_UNKNOWN:
+ return PHYLD_UNKNOWN;
+ default:
+ DC_ERROR("Unknown transmitter value %d\n", transmitter_value);
+ return PHYLD_UNKNOWN;
+ }
+}
+
+bool dc_link_setup_psr(struct dc_link *link,
+ const struct dc_stream_state *stream, struct psr_config *psr_config,
+ struct psr_context *psr_context)
+{
+ struct dc *dc;
+ struct dmcu *dmcu;
+ struct dmub_psr *psr;
+ int i;
+ unsigned int panel_inst;
+ /* updateSinkPsrDpcdConfig*/
+ union dpcd_psr_configuration psr_configuration;
+ union dpcd_sink_active_vtotal_control_mode vtotal_control = {0};
+
+ psr_context->controllerId = CONTROLLER_ID_UNDEFINED;
+
+ if (!link)
+ return false;
+
+ dc = link->ctx->dc;
+ dmcu = dc->res_pool->dmcu;
+ psr = dc->res_pool->psr;
+
+ if (!dmcu && !psr)
+ return false;
+
+ if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst))
+ return false;
+
+
+ memset(&psr_configuration, 0, sizeof(psr_configuration));
+
+ psr_configuration.bits.ENABLE = 1;
+ psr_configuration.bits.CRC_VERIFICATION = 1;
+ psr_configuration.bits.FRAME_CAPTURE_INDICATION =
+ psr_config->psr_frame_capture_indication_req;
+
+ /* Check for PSR v2*/
+ if (link->psr_settings.psr_version == DC_PSR_VERSION_SU_1) {
+ /* For PSR v2 selective update.
+ * Indicates whether sink should start capturing
+ * immediately following active scan line,
+ * or starting with the 2nd active scan line.
+ */
+ psr_configuration.bits.LINE_CAPTURE_INDICATION = 0;
+ /*For PSR v2, determines whether Sink should generate
+ * IRQ_HPD when CRC mismatch is detected.
+ */
+ psr_configuration.bits.IRQ_HPD_WITH_CRC_ERROR = 1;
+ /* For PSR v2, set the bit when the Source device will
+ * be enabling PSR2 operation.
+ */
+ psr_configuration.bits.ENABLE_PSR2 = 1;
+ /* For PSR v2, the Sink device must be able to receive
+ * SU region updates early in the frame time.
+ */
+ psr_configuration.bits.EARLY_TRANSPORT_ENABLE = 1;
+ }
+
+ dm_helpers_dp_write_dpcd(
+ link->ctx,
+ link,
+ 368,
+ &psr_configuration.raw,
+ sizeof(psr_configuration.raw));
+
+ if (link->psr_settings.psr_version == DC_PSR_VERSION_SU_1) {
+ link_power_alpm_dpcd_enable(link, true);
+ psr_context->su_granularity_required =
+ psr_config->su_granularity_required;
+ psr_context->su_y_granularity =
+ psr_config->su_y_granularity;
+ psr_context->line_time_in_us = psr_config->line_time_in_us;
+
+ /* linux must be able to expose AMD Source DPCD definition
+ * in order to support FreeSync PSR
+ */
+ if (link->psr_settings.psr_vtotal_control_support) {
+ psr_context->rate_control_caps = psr_config->rate_control_caps;
+ vtotal_control.bits.ENABLE = true;
+ core_link_write_dpcd(link, DP_SINK_PSR_ACTIVE_VTOTAL_CONTROL_MODE,
+ &vtotal_control.raw, sizeof(vtotal_control.raw));
+ }
+ }
+
+ psr_context->channel = link->ddc->ddc_pin->hw_info.ddc_channel;
+ psr_context->transmitterId = link->link_enc->transmitter;
+ psr_context->engineId = link->link_enc->preferred_engine;
+
+ for (i = 0; i < MAX_PIPES; i++) {
+ if (dc->current_state->res_ctx.pipe_ctx[i].stream
+ == stream) {
+ /* dmcu -1 for all controller id values,
+ * therefore +1 here
+ */
+ psr_context->controllerId =
+ dc->current_state->res_ctx.
+ pipe_ctx[i].stream_res.tg->inst + 1;
+ break;
+ }
+ }
+
+ /* Hardcoded for now. Can be Pcie or Uniphy (or Unknown)*/
+ psr_context->phyType = PHY_TYPE_UNIPHY;
+ /*PhyId is associated with the transmitter id*/
+ psr_context->smuPhyId = transmitter_to_phy_id(link);
+
+ psr_context->crtcTimingVerticalTotal = stream->timing.v_total;
+ psr_context->vsync_rate_hz = div64_u64(div64_u64((stream->
+ timing.pix_clk_100hz * 100),
+ stream->timing.v_total),
+ stream->timing.h_total);
+
+ psr_context->psrSupportedDisplayConfig = true;
+ psr_context->psrExitLinkTrainingRequired =
+ psr_config->psr_exit_link_training_required;
+ psr_context->sdpTransmitLineNumDeadline =
+ psr_config->psr_sdp_transmit_line_num_deadline;
+ psr_context->psrFrameCaptureIndicationReq =
+ psr_config->psr_frame_capture_indication_req;
+
+ psr_context->skipPsrWaitForPllLock = 0; /* only = 1 in KV */
+
+ psr_context->numberOfControllers =
+ link->dc->res_pool->timing_generator_count;
+
+ psr_context->rfb_update_auto_en = true;
+
+ /* 2 frames before enter PSR. */
+ psr_context->timehyst_frames = 2;
+ /* half a frame
+ * (units in 100 lines, i.e. a value of 1 represents 100 lines)
+ */
+ psr_context->hyst_lines = stream->timing.v_total / 2 / 100;
+ psr_context->aux_repeats = 10;
+
+ psr_context->psr_level.u32all = 0;
+
+ /*skip power down the single pipe since it blocks the cstate*/
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (link->ctx->asic_id.chip_family >= FAMILY_RV) {
+ switch (link->ctx->asic_id.chip_family) {
+ case FAMILY_YELLOW_CARP:
+ case AMDGPU_FAMILY_GC_10_3_6:
+ case AMDGPU_FAMILY_GC_11_0_1:
+ if (dc->debug.disable_z10 || dc->debug.psr_skip_crtc_disable)
+ psr_context->psr_level.bits.SKIP_CRTC_DISABLE = true;
+ break;
+ default:
+ psr_context->psr_level.bits.SKIP_CRTC_DISABLE = true;
+ break;
+ }
+ }
+#else
+ if (link->ctx->asic_id.chip_family >= FAMILY_RV)
+ psr_context->psr_level.bits.SKIP_CRTC_DISABLE = true;
+#endif
+
+ /* SMU will perform additional powerdown sequence.
+ * For unsupported ASICs, set psr_level flag to skip PSR
+ * static screen notification to SMU.
+ * (Always set for DAL2, did not check ASIC)
+ */
+ psr_context->allow_smu_optimizations = psr_config->allow_smu_optimizations;
+ psr_context->allow_multi_disp_optimizations = psr_config->allow_multi_disp_optimizations;
+
+ /* Complete PSR entry before aborting to prevent intermittent
+ * freezes on certain eDPs
+ */
+ psr_context->psr_level.bits.DISABLE_PSR_ENTRY_ABORT = 1;
+
+ /* Disable ALPM first for compatible non-ALPM panel now */
+ psr_context->psr_level.bits.DISABLE_ALPM = 0;
+ psr_context->psr_level.bits.ALPM_DEFAULT_PD_MODE = 1;
+
+ /* Controls additional delay after remote frame capture before
+ * continuing power down, default = 0
+ */
+ psr_context->frame_delay = 0;
+
+ psr_context->dsc_slice_height = psr_config->dsc_slice_height;
+
+ if (psr) {
+ link->psr_settings.psr_feature_enabled = psr->funcs->psr_copy_settings(psr,
+ link, psr_context, panel_inst);
+ link->psr_settings.psr_power_opt = 0;
+ link->psr_settings.psr_allow_active = 0;
+ } else {
+ link->psr_settings.psr_feature_enabled = dmcu->funcs->setup_psr(dmcu, link, psr_context);
+ }
+
+ /* psr_enabled == 0 indicates setup_psr did not succeed, but this
+ * should not happen since firmware should be running at this point
+ */
+ if (link->psr_settings.psr_feature_enabled == 0)
+ ASSERT(0);
+
+ return true;
+
+}
+
+void link_get_psr_residency(const struct dc_link *link, uint32_t *residency)
+{
+ struct dc *dc = link->ctx->dc;
+ struct dmub_psr *psr = dc->res_pool->psr;
+ unsigned int panel_inst;
+
+ if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst))
+ return;
+
+ // PSR residency measurements only supported on DMCUB
+ if (psr != NULL && link->psr_settings.psr_feature_enabled)
+ psr->funcs->psr_get_residency(psr, residency, panel_inst);
+ else
+ *residency = 0;
+}
+bool link_set_sink_vtotal_in_psr_active(const struct dc_link *link, uint16_t psr_vtotal_idle, uint16_t psr_vtotal_su)
+{
+ struct dc *dc = link->ctx->dc;
+ struct dmub_psr *psr = dc->res_pool->psr;
+
+ if (psr == NULL || !link->psr_settings.psr_feature_enabled || !link->psr_settings.psr_vtotal_control_support)
+ return false;
+
+ psr->funcs->psr_set_sink_vtotal_in_psr_active(psr, psr_vtotal_idle, psr_vtotal_su);
+
+ return true;
+}
+
+static struct abm *get_abm_from_stream_res(const struct dc_link *link)
+{
+ int i;
+ struct dc *dc = link->ctx->dc;
+ struct abm *abm = NULL;
+
+ for (i = 0; i < MAX_PIPES; i++) {
+ struct pipe_ctx pipe_ctx = dc->current_state->res_ctx.pipe_ctx[i];
+ struct dc_stream_state *stream = pipe_ctx.stream;
+
+ if (stream && stream->link == link) {
+ abm = pipe_ctx.stream_res.abm;
+ break;
+ }
+ }
+ return abm;
+}
+
+int dc_link_get_backlight_level(const struct dc_link *link)
+{
+ struct abm *abm = get_abm_from_stream_res(link);
+ struct panel_cntl *panel_cntl = link->panel_cntl;
+ struct dc *dc = link->ctx->dc;
+ struct dmcu *dmcu = dc->res_pool->dmcu;
+ bool fw_set_brightness = true;
+
+ if (dmcu)
+ fw_set_brightness = dmcu->funcs->is_dmcu_initialized(dmcu);
+
+ if (!fw_set_brightness && panel_cntl->funcs->get_current_backlight)
+ return panel_cntl->funcs->get_current_backlight(panel_cntl);
+ else if (abm != NULL && abm->funcs->get_current_backlight != NULL)
+ return (int) abm->funcs->get_current_backlight(abm);
+ else
+ return DC_ERROR_UNEXPECTED;
+}
+
+int dc_link_get_target_backlight_pwm(const struct dc_link *link)
+{
+ struct abm *abm = get_abm_from_stream_res(link);
+
+ if (abm == NULL || abm->funcs->get_target_backlight == NULL)
+ return DC_ERROR_UNEXPECTED;
+
+ return (int) abm->funcs->get_target_backlight(abm);
+}
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h
new file mode 100644
index 000000000000..7f91a564b089
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DC_LINK_EDP_PANEL_CONTROL_H__
+#define __DC_LINK_EDP_PANEL_CONTROL_H__
+#include "link.h"
+
+enum dp_panel_mode dp_get_panel_mode(struct dc_link *link);
+void dp_set_panel_mode(struct dc_link *link, enum dp_panel_mode panel_mode);
+bool set_default_brightness_aux(struct dc_link *link);
+#endif /* __DC_LINK_EDP_POWER_CONTROL_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_hpd.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_hpd.c
new file mode 100644
index 000000000000..5f39dfe06e9a
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_hpd.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+
+/* FILE POLICY AND INTENDED USAGE:
+ *
+ * This file implements functions that manage basic HPD components such as gpio.
+ * It also provides wrapper functions to execute HPD related programming. This
+ * file only manages basic HPD functionality. It doesn't manage detection or
+ * feature or signal specific HPD behaviors.
+ */
+#include "link_hpd.h"
+#include "gpio_service_interface.h"
+
+bool dc_link_get_hpd_state(struct dc_link *dc_link)
+{
+ uint32_t state;
+
+ dal_gpio_lock_pin(dc_link->hpd_gpio);
+ dal_gpio_get_value(dc_link->hpd_gpio, &state);
+ dal_gpio_unlock_pin(dc_link->hpd_gpio);
+
+ return state;
+}
+
+void dc_link_enable_hpd(const struct dc_link *link)
+{
+ struct link_encoder *encoder = link->link_enc;
+
+ if (encoder != NULL && encoder->funcs->enable_hpd != NULL)
+ encoder->funcs->enable_hpd(encoder);
+}
+
+void dc_link_disable_hpd(const struct dc_link *link)
+{
+ struct link_encoder *encoder = link->link_enc;
+
+ if (encoder != NULL && encoder->funcs->enable_hpd != NULL)
+ encoder->funcs->disable_hpd(encoder);
+}
+
+void dc_link_enable_hpd_filter(struct dc_link *link, bool enable)
+{
+ struct gpio *hpd;
+
+ if (enable) {
+ link->is_hpd_filter_disabled = false;
+ program_hpd_filter(link);
+ } else {
+ link->is_hpd_filter_disabled = true;
+ /* Obtain HPD handle */
+ hpd = link_get_hpd_gpio(link->ctx->dc_bios, link->link_id, link->ctx->gpio_service);
+
+ if (!hpd)
+ return;
+
+ /* Setup HPD filtering */
+ if (dal_gpio_open(hpd, GPIO_MODE_INTERRUPT) == GPIO_RESULT_OK) {
+ struct gpio_hpd_config config;
+
+ config.delay_on_connect = 0;
+ config.delay_on_disconnect = 0;
+
+ dal_irq_setup_hpd_filter(hpd, &config);
+
+ dal_gpio_close(hpd);
+ } else {
+ ASSERT_CRITICAL(false);
+ }
+ /* Release HPD handle */
+ dal_gpio_destroy_irq(&hpd);
+ }
+}
+
+struct gpio *link_get_hpd_gpio(struct dc_bios *dcb,
+ struct graphics_object_id link_id,
+ struct gpio_service *gpio_service)
+{
+ enum bp_result bp_result;
+ struct graphics_object_hpd_info hpd_info;
+ struct gpio_pin_info pin_info;
+
+ if (dcb->funcs->get_hpd_info(dcb, link_id, &hpd_info) != BP_RESULT_OK)
+ return NULL;
+
+ bp_result = dcb->funcs->get_gpio_pin_info(dcb,
+ hpd_info.hpd_int_gpio_uid, &pin_info);
+
+ if (bp_result != BP_RESULT_OK) {
+ ASSERT(bp_result == BP_RESULT_NORECORD);
+ return NULL;
+ }
+
+ return dal_gpio_service_create_irq(gpio_service,
+ pin_info.offset,
+ pin_info.mask);
+}
+
+bool query_hpd_status(struct dc_link *link, uint32_t *is_hpd_high)
+{
+ struct gpio *hpd_pin = link_get_hpd_gpio(
+ link->ctx->dc_bios, link->link_id,
+ link->ctx->gpio_service);
+ if (!hpd_pin)
+ return false;
+
+ dal_gpio_open(hpd_pin, GPIO_MODE_INTERRUPT);
+ dal_gpio_get_value(hpd_pin, is_hpd_high);
+ dal_gpio_close(hpd_pin);
+ dal_gpio_destroy_irq(&hpd_pin);
+ return true;
+}
+
+enum hpd_source_id get_hpd_line(struct dc_link *link)
+{
+ struct gpio *hpd;
+ enum hpd_source_id hpd_id;
+
+ hpd_id = HPD_SOURCEID_UNKNOWN;
+
+ hpd = link_get_hpd_gpio(link->ctx->dc_bios, link->link_id,
+ link->ctx->gpio_service);
+
+ if (hpd) {
+ switch (dal_irq_get_source(hpd)) {
+ case DC_IRQ_SOURCE_HPD1:
+ hpd_id = HPD_SOURCEID1;
+ break;
+ case DC_IRQ_SOURCE_HPD2:
+ hpd_id = HPD_SOURCEID2;
+ break;
+ case DC_IRQ_SOURCE_HPD3:
+ hpd_id = HPD_SOURCEID3;
+ break;
+ case DC_IRQ_SOURCE_HPD4:
+ hpd_id = HPD_SOURCEID4;
+ break;
+ case DC_IRQ_SOURCE_HPD5:
+ hpd_id = HPD_SOURCEID5;
+ break;
+ case DC_IRQ_SOURCE_HPD6:
+ hpd_id = HPD_SOURCEID6;
+ break;
+ default:
+ BREAK_TO_DEBUGGER();
+ break;
+ }
+
+ dal_gpio_destroy_irq(&hpd);
+ }
+
+ return hpd_id;
+}
+
+bool program_hpd_filter(const struct dc_link *link)
+{
+ bool result = false;
+ struct gpio *hpd;
+ int delay_on_connect_in_ms = 0;
+ int delay_on_disconnect_in_ms = 0;
+
+ if (link->is_hpd_filter_disabled)
+ return false;
+ /* Verify feature is supported */
+ switch (link->connector_signal) {
+ case SIGNAL_TYPE_DVI_SINGLE_LINK:
+ case SIGNAL_TYPE_DVI_DUAL_LINK:
+ case SIGNAL_TYPE_HDMI_TYPE_A:
+ /* Program hpd filter */
+ delay_on_connect_in_ms = 500;
+ delay_on_disconnect_in_ms = 100;
+ break;
+ case SIGNAL_TYPE_DISPLAY_PORT:
+ case SIGNAL_TYPE_DISPLAY_PORT_MST:
+ /* Program hpd filter to allow DP signal to settle */
+ /* 500: not able to detect MST <-> SST switch as HPD is low for
+ * only 100ms on DELL U2413
+ * 0: some passive dongle still show aux mode instead of i2c
+ * 20-50: not enough to hide bouncing HPD with passive dongle.
+ * also see intermittent i2c read issues.
+ */
+ delay_on_connect_in_ms = 80;
+ delay_on_disconnect_in_ms = 0;
+ break;
+ case SIGNAL_TYPE_LVDS:
+ case SIGNAL_TYPE_EDP:
+ default:
+ /* Don't program hpd filter */
+ return false;
+ }
+
+ /* Obtain HPD handle */
+ hpd = link_get_hpd_gpio(link->ctx->dc_bios, link->link_id,
+ link->ctx->gpio_service);
+
+ if (!hpd)
+ return result;
+
+ /* Setup HPD filtering */
+ if (dal_gpio_open(hpd, GPIO_MODE_INTERRUPT) == GPIO_RESULT_OK) {
+ struct gpio_hpd_config config;
+
+ config.delay_on_connect = delay_on_connect_in_ms;
+ config.delay_on_disconnect = delay_on_disconnect_in_ms;
+
+ dal_irq_setup_hpd_filter(hpd, &config);
+
+ dal_gpio_close(hpd);
+
+ result = true;
+ } else {
+ ASSERT_CRITICAL(false);
+ }
+
+ /* Release HPD handle */
+ dal_gpio_destroy_irq(&hpd);
+
+ return result;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_hpd.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_hpd.h
new file mode 100644
index 000000000000..3d122def0c88
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_hpd.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: AMD
+ *
+ */
+
+
+#ifndef __DC_LINK_HPD_H__
+#define __DC_LINK_HPD_H__
+#include "link.h"
+
+enum hpd_source_id get_hpd_line(struct dc_link *link);
+/*
+ * Function: program_hpd_filter
+ *
+ * @brief
+ * Programs HPD filter on associated HPD line to default values.
+ *
+ * @return
+ * true on success, false otherwise
+ */
+bool program_hpd_filter(const struct dc_link *link);
+/* Query hot plug status of USB4 DP tunnel.
+ * Returns true if HPD high.
+ */
+bool dpia_query_hpd_status(struct dc_link *link);
+bool query_hpd_status(struct dc_link *link, uint32_t *is_hpd_high);
+#endif /* __DC_LINK_HPD_H__ */
diff --git a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h
index eb5b7eb292ef..a391b939d709 100644
--- a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h
+++ b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h
@@ -126,10 +126,22 @@ enum dmub_notification_type {
DMUB_NOTIFICATION_HPD,
DMUB_NOTIFICATION_HPD_IRQ,
DMUB_NOTIFICATION_SET_CONFIG_REPLY,
+ DMUB_NOTIFICATION_DPIA_NOTIFICATION,
DMUB_NOTIFICATION_MAX
};
/**
+ * DPIA NOTIFICATION Response Type
+ */
+enum dpia_notify_bw_alloc_status {
+
+ DPIA_BW_REQ_FAILED = 0,
+ DPIA_BW_REQ_SUCCESS,
+ DPIA_EST_BW_CHANGED,
+ DPIA_BW_ALLOC_CAPS_CHANGED
+};
+
+/**
* struct dmub_region - dmub hw memory region
* @base: base address for region, must be 256 byte aligned
* @top: top address for region
@@ -453,6 +465,7 @@ struct dmub_srv {
* @pending_notification: Indicates there are other pending notifications
* @aux_reply: aux reply
* @hpd_status: hpd status
+ * @bw_alloc_reply: BW Allocation reply from CM/DPIA
*/
struct dmub_notification {
enum dmub_notification_type type;
@@ -463,6 +476,10 @@ struct dmub_notification {
struct aux_reply_data aux_reply;
enum dp_hpd_status hpd_status;
enum set_config_status sc_status;
+ /**
+ * DPIA notification command.
+ */
+ struct dmub_rb_cmd_dpia_notification dpia_notification;
};
};
diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
index 33907feefebb..007d6bdc3e39 100644
--- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
+++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
@@ -162,6 +162,7 @@ extern "C" {
#define dmub_udelay(microseconds) udelay(microseconds)
#endif
+#pragma pack(push, 1)
/**
* union dmub_addr - DMUB physical/virtual 64-bit address.
*/
@@ -172,6 +173,7 @@ union dmub_addr {
} u; /*<< Low/high bit access */
uint64_t quad_part; /*<< 64 bit address */
};
+#pragma pack(pop)
/**
* Dirty rect definition.
@@ -457,6 +459,10 @@ enum dmub_cmd_vbios_type {
* Query DP alt status on a transmitter.
*/
DMUB_CMD__VBIOS_TRANSMITTER_QUERY_DP_ALT = 26,
+ /**
+ * Controls domain power gating
+ */
+ DMUB_CMD__VBIOS_DOMAIN_CONTROL = 28,
};
//==============================================================================
@@ -770,6 +776,10 @@ enum dmub_out_cmd_type {
* Command type used for SET_CONFIG Reply notification
*/
DMUB_OUT_CMD__SET_CONFIG_REPLY = 3,
+ /**
+ * Command type used for USB4 DPIA notification
+ */
+ DMUB_OUT_CMD__DPIA_NOTIFICATION = 5,
};
/* DMUB_CMD__DPIA command sub-types. */
@@ -779,6 +789,11 @@ enum dmub_cmd_dpia_type {
DMUB_CMD__DPIA_MST_ALLOC_SLOTS = 2,
};
+/* DMUB_OUT_CMD__DPIA_NOTIFICATION command types. */
+enum dmub_cmd_dpia_notification_type {
+ DPIA_NOTIFY__BW_ALLOCATION = 0,
+};
+
#pragma pack(push, 1)
/**
@@ -1205,6 +1220,23 @@ struct dmub_rb_cmd_dig1_transmitter_control {
};
/**
+ * struct dmub_rb_cmd_domain_control_data - Data for DOMAIN power control
+ */
+struct dmub_rb_cmd_domain_control_data {
+ uint8_t inst : 6; /**< DOMAIN instance to control */
+ uint8_t power_gate : 1; /**< 1=power gate, 0=power up */
+ uint8_t reserved[3]; /**< Reserved for future use */
+};
+
+/**
+ * struct dmub_rb_cmd_domain_control - Controls DOMAIN power gating
+ */
+struct dmub_rb_cmd_domain_control {
+ struct dmub_cmd_header header; /**< header */
+ struct dmub_rb_cmd_domain_control_data data; /**< payload */
+};
+
+/**
* DPIA tunnel command parameters.
*/
struct dmub_cmd_dig_dpia_control_data {
@@ -1558,6 +1590,79 @@ struct dmub_rb_cmd_dp_set_config_reply {
};
/**
+ * Definition of a DPIA notification header
+ */
+struct dpia_notification_header {
+ uint8_t instance; /**< DPIA Instance */
+ uint8_t reserved[3];
+ enum dmub_cmd_dpia_notification_type type; /**< DPIA notification type */
+};
+
+/**
+ * Definition of the common data struct of DPIA notification
+ */
+struct dpia_notification_common {
+ uint8_t cmd_buffer[DMUB_RB_CMD_SIZE - sizeof(struct dmub_cmd_header)
+ - sizeof(struct dpia_notification_header)];
+};
+
+/**
+ * Definition of a DPIA notification data
+ */
+struct dpia_bw_allocation_notify_data {
+ union {
+ struct {
+ uint16_t cm_bw_alloc_support: 1; /**< USB4 CM BW Allocation mode support */
+ uint16_t bw_request_failed: 1; /**< BW_Request_Failed */
+ uint16_t bw_request_succeeded: 1; /**< BW_Request_Succeeded */
+ uint16_t est_bw_changed: 1; /**< Estimated_BW changed */
+ uint16_t bw_alloc_cap_changed: 1; /**< BW_Allocation_Capabiity_Changed */
+ uint16_t reserved: 11; /**< Reserved */
+ } bits;
+
+ uint16_t flags;
+ };
+
+ uint8_t cm_id; /**< CM ID */
+ uint8_t group_id; /**< Group ID */
+ uint8_t granularity; /**< BW Allocation Granularity */
+ uint8_t estimated_bw; /**< Estimated_BW */
+ uint8_t allocated_bw; /**< Allocated_BW */
+ uint8_t reserved;
+};
+
+/**
+ * union dpia_notify_data_type - DPIA Notification in Outbox command
+ */
+union dpia_notification_data {
+ /**
+ * DPIA Notification for common data struct
+ */
+ struct dpia_notification_common common_data;
+
+ /**
+ * DPIA Notification for DP BW Allocation support
+ */
+ struct dpia_bw_allocation_notify_data dpia_bw_alloc;
+};
+
+/**
+ * Definition of a DPIA notification payload
+ */
+struct dpia_notification_payload {
+ struct dpia_notification_header header;
+ union dpia_notification_data data; /**< DPIA notification payload data */
+};
+
+/**
+ * Definition of a DMUB_OUT_CMD__DPIA_NOTIFICATION command.
+ */
+struct dmub_rb_cmd_dpia_notification {
+ struct dmub_cmd_header header; /**< DPIA notification header */
+ struct dpia_notification_payload payload; /**< DPIA notification payload */
+};
+
+/**
* Data passed from driver to FW in a DMUB_CMD__QUERY_HPD_STATE command.
*/
struct dmub_cmd_hpd_state_query_data {
@@ -1886,6 +1991,14 @@ struct dmub_cmd_psr_copy_settings_data {
* Explicit padding to 2 byte boundary.
*/
uint8_t pad3;
+ /**
+ * DSC Slice height.
+ */
+ uint16_t dsc_slice_height;
+ /**
+ * Explicit padding to 4 byte boundary.
+ */
+ uint16_t pad;
};
/**
@@ -3029,7 +3142,8 @@ struct dmub_rb_cmd_panel_cntl {
*/
struct dmub_cmd_lvtma_control_data {
uint8_t uc_pwr_action; /**< LVTMA_ACTION */
- uint8_t reserved_0[3]; /**< For future use */
+ uint8_t bypass_panel_control_wait;
+ uint8_t reserved_0[2]; /**< For future use */
uint8_t panel_inst; /**< LVTMA control instance */
uint8_t reserved_1[3]; /**< For future use */
};
@@ -3232,6 +3346,10 @@ union dmub_rb_cmd {
*/
struct dmub_rb_cmd_dig1_transmitter_control dig1_transmitter_control;
/**
+ * Definition of a DMUB_CMD__VBIOS_DOMAIN_CONTROL command.
+ */
+ struct dmub_rb_cmd_domain_control domain_control;
+ /**
* Definition of a DMUB_CMD__PSR_SET_VERSION command.
*/
struct dmub_rb_cmd_psr_set_version psr_set_version;
@@ -3422,6 +3540,10 @@ union dmub_rb_out_cmd {
* SET_CONFIG reply command.
*/
struct dmub_rb_cmd_dp_set_config_reply set_config_reply;
+ /**
+ * DPIA notification command.
+ */
+ struct dmub_rb_cmd_dpia_notification dpia_notification;
};
#pragma pack(pop)
diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv_stat.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv_stat.c
index 44502ec919a2..74189102eaec 100644
--- a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv_stat.c
+++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv_stat.c
@@ -92,6 +92,27 @@ enum dmub_status dmub_srv_stat_get_notification(struct dmub_srv *dmub,
notify->link_index = cmd.set_config_reply.set_config_reply_control.instance;
notify->sc_status = cmd.set_config_reply.set_config_reply_control.status;
break;
+ case DMUB_OUT_CMD__DPIA_NOTIFICATION:
+ notify->type = DMUB_NOTIFICATION_DPIA_NOTIFICATION;
+ notify->link_index = cmd.dpia_notification.payload.header.instance;
+
+ if (cmd.dpia_notification.payload.header.type == DPIA_NOTIFY__BW_ALLOCATION) {
+
+ notify->dpia_notification.payload.data.dpia_bw_alloc.estimated_bw =
+ cmd.dpia_notification.payload.data.dpia_bw_alloc.estimated_bw;
+ notify->dpia_notification.payload.data.dpia_bw_alloc.allocated_bw =
+ cmd.dpia_notification.payload.data.dpia_bw_alloc.allocated_bw;
+
+ if (cmd.dpia_notification.payload.data.dpia_bw_alloc.bits.bw_request_failed)
+ notify->result = DPIA_BW_REQ_FAILED;
+ else if (cmd.dpia_notification.payload.data.dpia_bw_alloc.bits.bw_request_succeeded)
+ notify->result = DPIA_BW_REQ_SUCCESS;
+ else if (cmd.dpia_notification.payload.data.dpia_bw_alloc.bits.est_bw_changed)
+ notify->result = DPIA_EST_BW_CHANGED;
+ else if (cmd.dpia_notification.payload.data.dpia_bw_alloc.bits.bw_alloc_cap_changed)
+ notify->result = DPIA_BW_ALLOC_CAPS_CHANGED;
+ }
+ break;
default:
notify->type = DMUB_NOTIFICATION_NO_DATA;
break;
diff --git a/drivers/gpu/drm/amd/display/include/ddc_service_types.h b/drivers/gpu/drm/amd/display/include/ddc_service_types.h
index a7ba5bd8dc16..31a12ce79a8e 100644
--- a/drivers/gpu/drm/amd/display/include/ddc_service_types.h
+++ b/drivers/gpu/drm/amd/display/include/ddc_service_types.h
@@ -35,6 +35,7 @@
#define DP_BRANCH_DEVICE_ID_00E04C 0x00E04C
#define DP_BRANCH_DEVICE_ID_006037 0x006037
#define DP_BRANCH_DEVICE_ID_001CF8 0x001CF8
+#define DP_BRANCH_DEVICE_ID_0060AD 0x0060AD
#define DP_BRANCH_HW_REV_10 0x10
#define DP_BRANCH_HW_REV_20 0x20
@@ -133,6 +134,11 @@ static const uint8_t DP_SINK_DEVICE_STR_ID_2[] = {7, 1, 8, 7, 5};
static const u8 DP_SINK_BRANCH_DEV_NAME_7580[] = "7580\x80u";
+/*Travis*/
+static const uint8_t DP_VGA_LVDS_CONVERTER_ID_2[] = "sivarT";
+/*Nutmeg*/
+static const uint8_t DP_VGA_LVDS_CONVERTER_ID_3[] = "dnomlA";
+
/*MST Dock*/
static const uint8_t SYNAPTICS_DEVICE_ID[] = "SYNA";
diff --git a/drivers/gpu/drm/amd/display/include/dpcd_defs.h b/drivers/gpu/drm/amd/display/include/dpcd_defs.h
index b2df07f9e91c..c062a44db078 100644
--- a/drivers/gpu/drm/amd/display/include/dpcd_defs.h
+++ b/drivers/gpu/drm/amd/display/include/dpcd_defs.h
@@ -88,7 +88,10 @@ enum dpcd_phy_test_patterns {
PHY_TEST_PATTERN_PRBS23 = 0x30,
PHY_TEST_PATTERN_PRBS31 = 0x38,
PHY_TEST_PATTERN_264BIT_CUSTOM = 0x40,
- PHY_TEST_PATTERN_SQUARE_PULSE = 0x48,
+ PHY_TEST_PATTERN_SQUARE = 0x48,
+ PHY_TEST_PATTERN_SQUARE_PRESHOOT_DISABLED = 0x49,
+ PHY_TEST_PATTERN_SQUARE_DEEMPHASIS_DISABLED = 0x4A,
+ PHY_TEST_PATTERN_SQUARE_PRESHOOT_DEEMPHASIS_DISABLED = 0x4B,
};
enum dpcd_test_dyn_range {
diff --git a/drivers/gpu/drm/amd/display/include/link_service_types.h b/drivers/gpu/drm/amd/display/include/link_service_types.h
index d1e91d31d151..18b9173d5a96 100644
--- a/drivers/gpu/drm/amd/display/include/link_service_types.h
+++ b/drivers/gpu/drm/amd/display/include/link_service_types.h
@@ -165,7 +165,12 @@ enum dp_test_pattern {
DP_TEST_PATTERN_PRBS23,
DP_TEST_PATTERN_PRBS31,
DP_TEST_PATTERN_264BIT_CUSTOM,
- DP_TEST_PATTERN_SQUARE_PULSE,
+ DP_TEST_PATTERN_SQUARE_BEGIN,
+ DP_TEST_PATTERN_SQUARE = DP_TEST_PATTERN_SQUARE_BEGIN,
+ DP_TEST_PATTERN_SQUARE_PRESHOOT_DISABLED,
+ DP_TEST_PATTERN_SQUARE_DEEMPHASIS_DISABLED,
+ DP_TEST_PATTERN_SQUARE_PRESHOOT_DEEMPHASIS_DISABLED,
+ DP_TEST_PATTERN_SQUARE_END = DP_TEST_PATTERN_SQUARE_PRESHOOT_DEEMPHASIS_DISABLED,
/* Link Training Patterns */
DP_TEST_PATTERN_TRAINING_PATTERN1,
diff --git a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c
index f6034213c700..67a062af3ab0 100644
--- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c
+++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c
@@ -1715,8 +1715,8 @@ static bool map_regamma_hw_to_x_user(
const struct pwl_float_data_ex *rgb_regamma,
uint32_t hw_points_num,
struct dc_transfer_func_distributed_points *tf_pts,
- bool mapUserRamp,
- bool doClamping)
+ bool map_user_ramp,
+ bool do_clamping)
{
/* setup to spare calculated ideal regamma values */
@@ -1724,7 +1724,7 @@ static bool map_regamma_hw_to_x_user(
struct hw_x_point *coords = coords_x;
const struct pwl_float_data_ex *regamma = rgb_regamma;
- if (ramp && mapUserRamp) {
+ if (ramp && map_user_ramp) {
copy_rgb_regamma_to_coordinates_x(coords,
hw_points_num,
rgb_regamma);
@@ -1744,7 +1744,7 @@ static bool map_regamma_hw_to_x_user(
}
}
- if (doClamping) {
+ if (do_clamping) {
/* this should be named differently, all it does is clamp to 0-1 */
build_new_custom_resulted_curve(hw_points_num, tf_pts);
}
@@ -1875,7 +1875,7 @@ rgb_user_alloc_fail:
bool mod_color_calculate_degamma_params(struct dc_color_caps *dc_caps,
struct dc_transfer_func *input_tf,
- const struct dc_gamma *ramp, bool mapUserRamp)
+ const struct dc_gamma *ramp, bool map_user_ramp)
{
struct dc_transfer_func_distributed_points *tf_pts = &input_tf->tf_pts;
struct dividers dividers;
@@ -1883,7 +1883,7 @@ bool mod_color_calculate_degamma_params(struct dc_color_caps *dc_caps,
struct pwl_float_data_ex *curve = NULL;
struct gamma_pixel *axis_x = NULL;
struct pixel_gamma_point *coeff = NULL;
- enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB;
+ enum dc_transfer_func_predefined tf;
uint32_t i;
bool ret = false;
@@ -1891,12 +1891,12 @@ bool mod_color_calculate_degamma_params(struct dc_color_caps *dc_caps,
return false;
/* we can use hardcoded curve for plain SRGB TF
- * If linear, it's bypass if on user ramp
+ * If linear, it's bypass if no user ramp
*/
if (input_tf->type == TF_TYPE_PREDEFINED) {
if ((input_tf->tf == TRANSFER_FUNCTION_SRGB ||
input_tf->tf == TRANSFER_FUNCTION_LINEAR) &&
- !mapUserRamp)
+ !map_user_ramp)
return true;
if (dc_caps != NULL &&
@@ -1919,7 +1919,7 @@ bool mod_color_calculate_degamma_params(struct dc_color_caps *dc_caps,
input_tf->type = TF_TYPE_DISTRIBUTED_POINTS;
- if (mapUserRamp && ramp && ramp->type == GAMMA_RGB_256) {
+ if (map_user_ramp && ramp && ramp->type == GAMMA_RGB_256) {
rgb_user = kvcalloc(ramp->num_entries + _EXTRA_POINTS,
sizeof(*rgb_user),
GFP_KERNEL);
@@ -2007,7 +2007,7 @@ bool mod_color_calculate_degamma_params(struct dc_color_caps *dc_caps,
map_regamma_hw_to_x_user(ramp, coeff, rgb_user,
coordinates_x, axis_x, curve,
MAX_HW_POINTS, tf_pts,
- mapUserRamp && ramp && ramp->type == GAMMA_RGB_256,
+ map_user_ramp && ramp && ramp->type == GAMMA_RGB_256,
true);
}
@@ -2112,9 +2112,11 @@ static bool calculate_curve(enum dc_transfer_func_predefined trans,
}
bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf,
- const struct dc_gamma *ramp, bool mapUserRamp, bool canRomBeUsed,
- const struct hdr_tm_params *fs_params,
- struct calculate_buffer *cal_buffer)
+ const struct dc_gamma *ramp,
+ bool map_user_ramp,
+ bool can_rom_be_used,
+ const struct hdr_tm_params *fs_params,
+ struct calculate_buffer *cal_buffer)
{
struct dc_transfer_func_distributed_points *tf_pts = &output_tf->tf_pts;
struct dividers dividers;
@@ -2123,27 +2125,27 @@ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf,
struct pwl_float_data_ex *rgb_regamma = NULL;
struct gamma_pixel *axis_x = NULL;
struct pixel_gamma_point *coeff = NULL;
- enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB;
- bool doClamping = true;
+ enum dc_transfer_func_predefined tf;
+ bool do_clamping = true;
bool ret = false;
if (output_tf->type == TF_TYPE_BYPASS)
return false;
/* we can use hardcoded curve for plain SRGB TF */
- if (output_tf->type == TF_TYPE_PREDEFINED && canRomBeUsed == true &&
+ if (output_tf->type == TF_TYPE_PREDEFINED && can_rom_be_used == true &&
output_tf->tf == TRANSFER_FUNCTION_SRGB) {
if (ramp == NULL)
return true;
if ((ramp->is_identity && ramp->type != GAMMA_CS_TFM_1D) ||
- (!mapUserRamp && ramp->type == GAMMA_RGB_256))
+ (!map_user_ramp && ramp->type == GAMMA_RGB_256))
return true;
}
output_tf->type = TF_TYPE_DISTRIBUTED_POINTS;
if (ramp && ramp->type != GAMMA_CS_TFM_1D &&
- (mapUserRamp || ramp->type != GAMMA_RGB_256)) {
+ (map_user_ramp || ramp->type != GAMMA_RGB_256)) {
rgb_user = kvcalloc(ramp->num_entries + _EXTRA_POINTS,
sizeof(*rgb_user),
GFP_KERNEL);
@@ -2164,7 +2166,7 @@ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf,
ramp->num_entries,
dividers);
- if (ramp->type == GAMMA_RGB_256 && mapUserRamp)
+ if (ramp->type == GAMMA_RGB_256 && map_user_ramp)
scale_gamma(rgb_user, ramp, dividers);
else if (ramp->type == GAMMA_RGB_FLOAT_1024)
scale_gamma_dx(rgb_user, ramp, dividers);
@@ -2191,15 +2193,15 @@ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf,
cal_buffer);
if (ret) {
- doClamping = !(output_tf->tf == TRANSFER_FUNCTION_GAMMA22 &&
- fs_params != NULL && fs_params->skip_tm == 0);
+ do_clamping = !(output_tf->tf == TRANSFER_FUNCTION_GAMMA22 &&
+ fs_params != NULL && fs_params->skip_tm == 0);
map_regamma_hw_to_x_user(ramp, coeff, rgb_user,
- coordinates_x, axis_x, rgb_regamma,
- MAX_HW_POINTS, tf_pts,
- (mapUserRamp || (ramp && ramp->type != GAMMA_RGB_256)) &&
- (ramp && ramp->type != GAMMA_CS_TFM_1D),
- doClamping);
+ coordinates_x, axis_x, rgb_regamma,
+ MAX_HW_POINTS, tf_pts,
+ (map_user_ramp || (ramp && ramp->type != GAMMA_RGB_256)) &&
+ (ramp && ramp->type != GAMMA_CS_TFM_1D),
+ do_clamping);
if (ramp && ramp->type == GAMMA_CS_TFM_1D)
apply_lut_1d(ramp, MAX_HW_POINTS, tf_pts);
@@ -2215,89 +2217,3 @@ axis_x_alloc_fail:
rgb_user_alloc_fail:
return ret;
}
-
-bool mod_color_calculate_degamma_curve(enum dc_transfer_func_predefined trans,
- struct dc_transfer_func_distributed_points *points)
-{
- uint32_t i;
- bool ret = false;
- struct pwl_float_data_ex *rgb_degamma = NULL;
-
- if (trans == TRANSFER_FUNCTION_UNITY ||
- trans == TRANSFER_FUNCTION_LINEAR) {
-
- for (i = 0; i <= MAX_HW_POINTS ; i++) {
- points->red[i] = coordinates_x[i].x;
- points->green[i] = coordinates_x[i].x;
- points->blue[i] = coordinates_x[i].x;
- }
- ret = true;
- } else if (trans == TRANSFER_FUNCTION_PQ) {
- rgb_degamma = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS,
- sizeof(*rgb_degamma),
- GFP_KERNEL);
- if (!rgb_degamma)
- goto rgb_degamma_alloc_fail;
-
-
- build_de_pq(rgb_degamma,
- MAX_HW_POINTS,
- coordinates_x);
- for (i = 0; i <= MAX_HW_POINTS ; i++) {
- points->red[i] = rgb_degamma[i].r;
- points->green[i] = rgb_degamma[i].g;
- points->blue[i] = rgb_degamma[i].b;
- }
- ret = true;
-
- kvfree(rgb_degamma);
- } else if (trans == TRANSFER_FUNCTION_SRGB ||
- trans == TRANSFER_FUNCTION_BT709 ||
- trans == TRANSFER_FUNCTION_GAMMA22 ||
- trans == TRANSFER_FUNCTION_GAMMA24 ||
- trans == TRANSFER_FUNCTION_GAMMA26) {
- rgb_degamma = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS,
- sizeof(*rgb_degamma),
- GFP_KERNEL);
- if (!rgb_degamma)
- goto rgb_degamma_alloc_fail;
-
- build_degamma(rgb_degamma,
- MAX_HW_POINTS,
- coordinates_x,
- trans);
- for (i = 0; i <= MAX_HW_POINTS ; i++) {
- points->red[i] = rgb_degamma[i].r;
- points->green[i] = rgb_degamma[i].g;
- points->blue[i] = rgb_degamma[i].b;
- }
- ret = true;
-
- kvfree(rgb_degamma);
- } else if (trans == TRANSFER_FUNCTION_HLG) {
- rgb_degamma = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS,
- sizeof(*rgb_degamma),
- GFP_KERNEL);
- if (!rgb_degamma)
- goto rgb_degamma_alloc_fail;
-
- build_hlg_degamma(rgb_degamma,
- MAX_HW_POINTS,
- coordinates_x,
- 80, 1000);
- for (i = 0; i <= MAX_HW_POINTS ; i++) {
- points->red[i] = rgb_degamma[i].r;
- points->green[i] = rgb_degamma[i].g;
- points->blue[i] = rgb_degamma[i].b;
- }
- ret = true;
- kvfree(rgb_degamma);
- }
- points->end_exponent = 0;
- points->x_point_at_y1_red = 1;
- points->x_point_at_y1_green = 1;
- points->x_point_at_y1_blue = 1;
-
-rgb_degamma_alloc_fail:
- return ret;
-}
diff --git a/drivers/gpu/drm/amd/display/modules/color/color_gamma.h b/drivers/gpu/drm/amd/display/modules/color/color_gamma.h
index 2893abf48208..ee5c466613de 100644
--- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.h
+++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.h
@@ -115,9 +115,6 @@ bool mod_color_calculate_degamma_params(struct dc_color_caps *dc_caps,
struct dc_transfer_func *output_tf,
const struct dc_gamma *ramp, bool mapUserRamp);
-bool mod_color_calculate_degamma_curve(enum dc_transfer_func_predefined trans,
- struct dc_transfer_func_distributed_points *points);
-
bool calculate_user_regamma_coeff(struct dc_transfer_func *output_tf,
const struct regamma_lut *regamma,
struct calculate_buffer *cal_buffer,
diff --git a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c
index c2e00f7b8381..2be45b314922 100644
--- a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c
+++ b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c
@@ -616,7 +616,8 @@ static void build_vrr_infopacket_data_v1(const struct mod_vrr_params *vrr,
}
static void build_vrr_infopacket_data_v3(const struct mod_vrr_params *vrr,
- struct dc_info_packet *infopacket)
+ struct dc_info_packet *infopacket,
+ bool freesync_on_desktop)
{
unsigned int min_refresh;
unsigned int max_refresh;
@@ -649,9 +650,15 @@ static void build_vrr_infopacket_data_v3(const struct mod_vrr_params *vrr,
infopacket->sb[6] |= 0x02;
/* PB6 = [Bit 2 = FreeSync Active] */
- if (vrr->state == VRR_STATE_ACTIVE_VARIABLE ||
+ if (freesync_on_desktop) {
+ if (vrr->state != VRR_STATE_DISABLED &&
+ vrr->state != VRR_STATE_UNSUPPORTED)
+ infopacket->sb[6] |= 0x04;
+ } else {
+ if (vrr->state == VRR_STATE_ACTIVE_VARIABLE ||
vrr->state == VRR_STATE_ACTIVE_FIXED)
- infopacket->sb[6] |= 0x04;
+ infopacket->sb[6] |= 0x04;
+ }
min_refresh = (vrr->min_refresh_in_uhz + 500000) / 1000000;
max_refresh = (vrr->max_refresh_in_uhz + 500000) / 1000000;
@@ -898,52 +905,20 @@ static void build_vrr_infopacket_v2(enum signal_type signal,
infopacket->valid = true;
}
-#ifndef TRIM_FSFT
-static void build_vrr_infopacket_fast_transport_data(
- bool ftActive,
- unsigned int ftOutputRate,
- struct dc_info_packet *infopacket)
-{
- /* PB9 : bit7 - fast transport Active*/
- unsigned char activeBit = (ftActive) ? 1 << 7 : 0;
-
- infopacket->sb[1] &= ~activeBit; //clear bit
- infopacket->sb[1] |= activeBit; //set bit
-
- /* PB13 : Target Output Pixel Rate [kHz] - bits 7:0 */
- infopacket->sb[13] = ftOutputRate & 0xFF;
-
- /* PB14 : Target Output Pixel Rate [kHz] - bits 15:8 */
- infopacket->sb[14] = (ftOutputRate >> 8) & 0xFF;
-
- /* PB15 : Target Output Pixel Rate [kHz] - bits 23:16 */
- infopacket->sb[15] = (ftOutputRate >> 16) & 0xFF;
-
-}
-#endif
static void build_vrr_infopacket_v3(enum signal_type signal,
const struct mod_vrr_params *vrr,
-#ifndef TRIM_FSFT
- bool ftActive, unsigned int ftOutputRate,
-#endif
enum color_transfer_func app_tf,
- struct dc_info_packet *infopacket)
+ struct dc_info_packet *infopacket,
+ bool freesync_on_desktop)
{
unsigned int payload_size = 0;
build_vrr_infopacket_header_v3(signal, infopacket, &payload_size);
- build_vrr_infopacket_data_v3(vrr, infopacket);
+ build_vrr_infopacket_data_v3(vrr, infopacket, freesync_on_desktop);
build_vrr_infopacket_fs2_data(app_tf, infopacket);
-#ifndef TRIM_FSFT
- build_vrr_infopacket_fast_transport_data(
- ftActive,
- ftOutputRate,
- infopacket);
-#endif
-
build_vrr_infopacket_checksum(&payload_size, infopacket);
infopacket->valid = true;
@@ -980,31 +955,26 @@ void mod_freesync_build_vrr_infopacket(struct mod_freesync *mod_freesync,
* Check if Freesync is supported. Return if false. If true,
* set the corresponding bit in the info packet
*/
+ bool freesync_on_desktop;
+ bool fams_enable;
+
+ fams_enable = stream->ctx->dc->current_state->bw_ctx.bw.dcn.clk.fw_based_mclk_switching;
+ freesync_on_desktop = stream->freesync_on_desktop && fams_enable;
+
if (!vrr->send_info_frame)
return;
switch (packet_type) {
case PACKET_TYPE_FS_V3:
-#ifndef TRIM_FSFT
- // always populate with pixel rate.
- build_vrr_infopacket_v3(
- stream->signal, vrr,
- stream->timing.flags.FAST_TRANSPORT,
- (stream->timing.flags.FAST_TRANSPORT) ?
- stream->timing.fast_transport_output_rate_100hz :
- stream->timing.pix_clk_100hz,
- app_tf, infopacket);
-#else
- build_vrr_infopacket_v3(stream->signal, vrr, app_tf, infopacket);
-#endif
+ build_vrr_infopacket_v3(stream->signal, vrr, app_tf, infopacket, freesync_on_desktop);
break;
case PACKET_TYPE_FS_V2:
- build_vrr_infopacket_v2(stream->signal, vrr, app_tf, infopacket, stream->freesync_on_desktop);
+ build_vrr_infopacket_v2(stream->signal, vrr, app_tf, infopacket, freesync_on_desktop);
break;
case PACKET_TYPE_VRR:
case PACKET_TYPE_FS_V1:
default:
- build_vrr_infopacket_v1(stream->signal, vrr, infopacket, stream->freesync_on_desktop);
+ build_vrr_infopacket_v1(stream->signal, vrr, infopacket, freesync_on_desktop);
}
if (true == pack_sdp_v1_3 &&
diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h b/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h
index edf5845f6a1f..66dc9a19aebe 100644
--- a/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h
+++ b/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h
@@ -41,4 +41,40 @@ void mod_build_vsc_infopacket(const struct dc_stream_state *stream,
void mod_build_hf_vsif_infopacket(const struct dc_stream_state *stream,
struct dc_info_packet *info_packet);
+enum adaptive_sync_type {
+ ADAPTIVE_SYNC_TYPE_NONE = 0,
+ ADAPTIVE_SYNC_TYPE_DP = 1,
+ FREESYNC_TYPE_PCON_IN_WHITELIST = 2,
+ FREESYNC_TYPE_PCON_NOT_IN_WHITELIST = 3,
+ ADAPTIVE_SYNC_TYPE_EDP = 4,
+};
+
+enum adaptive_sync_sdp_version {
+ AS_SDP_VER_0 = 0x0,
+ AS_SDP_VER_1 = 0x1,
+ AS_SDP_VER_2 = 0x2,
+};
+
+#define AS_DP_SDP_LENGTH (9)
+
+struct frame_duration_op {
+ bool support;
+ unsigned char frame_duration_hex;
+};
+
+struct AS_Df_params {
+ bool supportMode;
+ struct frame_duration_op increase;
+ struct frame_duration_op decrease;
+};
+
+void mod_build_adaptive_sync_infopacket(const struct dc_stream_state *stream,
+ enum adaptive_sync_type asType, const struct AS_Df_params *param,
+ struct dc_info_packet *info_packet);
+
+void mod_build_adaptive_sync_infopacket_v2(const struct dc_stream_state *stream,
+ const struct AS_Df_params *param, struct dc_info_packet *info_packet);
+
+void mod_build_adaptive_sync_infopacket_v1(struct dc_info_packet *info_packet);
+
#endif
diff --git a/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c b/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c
index 69691058ab89..ec64f19e1786 100644
--- a/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c
+++ b/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c
@@ -519,3 +519,58 @@ void mod_build_hf_vsif_infopacket(const struct dc_stream_state *stream,
info_packet->valid = true;
}
+void mod_build_adaptive_sync_infopacket(const struct dc_stream_state *stream,
+ enum adaptive_sync_type asType,
+ const struct AS_Df_params *param,
+ struct dc_info_packet *info_packet)
+{
+ info_packet->valid = false;
+
+ memset(info_packet, 0, sizeof(struct dc_info_packet));
+
+ switch (asType) {
+ case ADAPTIVE_SYNC_TYPE_DP:
+ if (stream != NULL)
+ mod_build_adaptive_sync_infopacket_v2(stream, param, info_packet);
+ break;
+ case FREESYNC_TYPE_PCON_IN_WHITELIST:
+ mod_build_adaptive_sync_infopacket_v1(info_packet);
+ break;
+ case ADAPTIVE_SYNC_TYPE_NONE:
+ case FREESYNC_TYPE_PCON_NOT_IN_WHITELIST:
+ default:
+ break;
+ }
+}
+
+void mod_build_adaptive_sync_infopacket_v1(struct dc_info_packet *info_packet)
+{
+ info_packet->valid = true;
+ // HEADER {HB0, HB1, HB2, HB3} = {00, Type, Version, Length}
+ info_packet->hb0 = 0x00;
+ info_packet->hb1 = 0x22;
+ info_packet->hb2 = AS_SDP_VER_1;
+ info_packet->hb3 = 0x00;
+}
+
+void mod_build_adaptive_sync_infopacket_v2(const struct dc_stream_state *stream,
+ const struct AS_Df_params *param,
+ struct dc_info_packet *info_packet)
+{
+ info_packet->valid = true;
+ // HEADER {HB0, HB1, HB2, HB3} = {00, Type, Version, Length}
+ info_packet->hb0 = 0x00;
+ info_packet->hb1 = 0x22;
+ info_packet->hb2 = AS_SDP_VER_2;
+ info_packet->hb3 = AS_DP_SDP_LENGTH;
+
+ //Payload
+ info_packet->sb[0] = param->supportMode; //1: AVT; 0: FAVT
+ info_packet->sb[1] = (stream->timing.v_total & 0x00FF);
+ info_packet->sb[2] = (stream->timing.v_total & 0xFF00) >> 8;
+ //info_packet->sb[3] = 0x00; Target RR, not use fot AVT
+ info_packet->sb[4] = (param->increase.support << 6 | param->decrease.support << 7);
+ info_packet->sb[5] = param->increase.frame_duration_hex;
+ info_packet->sb[6] = param->decrease.frame_duration_hex;
+}
+
diff --git a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c
index 9b5d9b2c9a6a..e39b133d05af 100644
--- a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c
+++ b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c
@@ -916,3 +916,34 @@ bool mod_power_only_edp(const struct dc_state *context, const struct dc_stream_s
{
return context && context->stream_count == 1 && dc_is_embedded_signal(stream->signal);
}
+
+bool psr_su_set_dsc_slice_height(struct dc *dc, struct dc_link *link,
+ struct dc_stream_state *stream,
+ struct psr_config *config)
+{
+ uint16_t pic_height;
+ uint16_t slice_height;
+
+ config->dsc_slice_height = 0;
+ if ((link->connector_signal & SIGNAL_TYPE_EDP) &&
+ (!dc->caps.edp_dsc_support ||
+ link->panel_config.dsc.disable_dsc_edp ||
+ !link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_SUPPORT ||
+ !stream->timing.dsc_cfg.num_slices_v))
+ return true;
+
+ pic_height = stream->timing.v_addressable +
+ stream->timing.v_border_top + stream->timing.v_border_bottom;
+ slice_height = pic_height / stream->timing.dsc_cfg.num_slices_v;
+ config->dsc_slice_height = slice_height;
+
+ if (slice_height) {
+ if (config->su_y_granularity &&
+ (slice_height % config->su_y_granularity)) {
+ ASSERT(0);
+ return false;
+ }
+ }
+
+ return true;
+}
diff --git a/drivers/gpu/drm/amd/display/modules/power/power_helpers.h b/drivers/gpu/drm/amd/display/modules/power/power_helpers.h
index 316452e9dbc9..1d3079e56799 100644
--- a/drivers/gpu/drm/amd/display/modules/power/power_helpers.h
+++ b/drivers/gpu/drm/amd/display/modules/power/power_helpers.h
@@ -59,4 +59,7 @@ void mod_power_calc_psr_configs(struct psr_config *psr_config,
const struct dc_stream_state *stream);
bool mod_power_only_edp(const struct dc_state *context,
const struct dc_stream_state *stream);
+bool psr_su_set_dsc_slice_height(struct dc *dc, struct dc_link *link,
+ struct dc_stream_state *stream,
+ struct psr_config *config);
#endif /* MODULES_POWER_POWER_HELPERS_H_ */
diff --git a/drivers/gpu/drm/amd/include/amd_shared.h b/drivers/gpu/drm/amd/include/amd_shared.h
index f175e65b853a..e4a22c68517d 100644
--- a/drivers/gpu/drm/amd/include/amd_shared.h
+++ b/drivers/gpu/drm/amd/include/amd_shared.h
@@ -240,6 +240,7 @@ enum DC_FEATURE_MASK {
DC_DISABLE_LTTPR_DP2_0 = (1 << 6), //0x40, disabled by default
DC_PSR_ALLOW_SMU_OPT = (1 << 7), //0x80, disabled by default
DC_PSR_ALLOW_MULTI_DISP_OPT = (1 << 8), //0x100, disabled by default
+ DC_ENABLE_SUBVP_DRR = (1 << 9), // 0x200, disabled by default
};
enum DC_DEBUG_MASK {
diff --git a/drivers/gpu/drm/amd/include/asic_reg/df/df_4_3_offset.h b/drivers/gpu/drm/amd/include/asic_reg/df/df_4_3_offset.h
new file mode 100644
index 000000000000..fbb18e44ec52
--- /dev/null
+++ b/drivers/gpu/drm/amd/include/asic_reg/df/df_4_3_offset.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) 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.
+ */
+
+#ifndef _df_4_3_OFFSET_HEADER
+#define _df_4_3_OFFSET_HEADER
+
+#define regDF_CS_UMC_AON0_HardwareAssertMaskLow 0x0e3e
+#define regDF_CS_UMC_AON0_HardwareAssertMaskLow_BASE_IDX 4
+#define regDF_NCS_PG0_HardwareAssertMaskHigh 0x0e3f
+#define regDF_NCS_PG0_HardwareAssertMaskHigh_BASE_IDX 4
+
+#endif
diff --git a/drivers/gpu/drm/amd/include/asic_reg/df/df_4_3_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/df/df_4_3_sh_mask.h
new file mode 100644
index 000000000000..9c8f19ded4eb
--- /dev/null
+++ b/drivers/gpu/drm/amd/include/asic_reg/df/df_4_3_sh_mask.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) 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.
+ */
+
+#ifndef _df_4_3_SH_MASK_HEADER
+#define _df_4_3_SH_MASK_HEADER
+
+//DF_CS_UMC_AON0_HardwareAssertMaskLow
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk0__SHIFT 0x0
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk1__SHIFT 0x1
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk2__SHIFT 0x2
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk3__SHIFT 0x3
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk4__SHIFT 0x4
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk5__SHIFT 0x5
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk6__SHIFT 0x6
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk7__SHIFT 0x7
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk8__SHIFT 0x8
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk9__SHIFT 0x9
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk10__SHIFT 0xa
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk11__SHIFT 0xb
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk12__SHIFT 0xc
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk13__SHIFT 0xd
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk14__SHIFT 0xe
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk15__SHIFT 0xf
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk16__SHIFT 0x10
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk17__SHIFT 0x11
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk18__SHIFT 0x12
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk19__SHIFT 0x13
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk20__SHIFT 0x14
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk21__SHIFT 0x15
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk22__SHIFT 0x16
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk23__SHIFT 0x17
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk24__SHIFT 0x18
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk25__SHIFT 0x19
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk26__SHIFT 0x1a
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk27__SHIFT 0x1b
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk28__SHIFT 0x1c
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk29__SHIFT 0x1d
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk30__SHIFT 0x1e
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk31__SHIFT 0x1f
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk0_MASK 0x00000001L
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk1_MASK 0x00000002L
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk2_MASK 0x00000004L
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk3_MASK 0x00000008L
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk4_MASK 0x00000010L
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk5_MASK 0x00000020L
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk6_MASK 0x00000040L
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk7_MASK 0x00000080L
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk8_MASK 0x00000100L
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk9_MASK 0x00000200L
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk10_MASK 0x00000400L
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk11_MASK 0x00000800L
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk12_MASK 0x00001000L
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk13_MASK 0x00002000L
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk14_MASK 0x00004000L
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk15_MASK 0x00008000L
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk16_MASK 0x00010000L
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk17_MASK 0x00020000L
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk18_MASK 0x00040000L
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk19_MASK 0x00080000L
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk20_MASK 0x00100000L
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk21_MASK 0x00200000L
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk22_MASK 0x00400000L
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk23_MASK 0x00800000L
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk24_MASK 0x01000000L
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk25_MASK 0x02000000L
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk26_MASK 0x04000000L
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk27_MASK 0x08000000L
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk28_MASK 0x10000000L
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk29_MASK 0x20000000L
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk30_MASK 0x40000000L
+#define DF_CS_UMC_AON0_HardwareAssertMaskLow__HWAssertMsk31_MASK 0x80000000L
+
+//DF_NCS_PG0_HardwareAssertMaskHigh
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk0__SHIFT 0x0
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk1__SHIFT 0x1
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk2__SHIFT 0x2
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk3__SHIFT 0x3
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk4__SHIFT 0x4
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk5__SHIFT 0x5
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk6__SHIFT 0x6
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk7__SHIFT 0x7
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk8__SHIFT 0x8
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk9__SHIFT 0x9
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk10__SHIFT 0xa
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk11__SHIFT 0xb
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk12__SHIFT 0xc
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk13__SHIFT 0xd
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk14__SHIFT 0xe
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk15__SHIFT 0xf
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk16__SHIFT 0x10
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk17__SHIFT 0x11
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk18__SHIFT 0x12
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk19__SHIFT 0x13
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk20__SHIFT 0x14
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk21__SHIFT 0x15
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk22__SHIFT 0x16
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk23__SHIFT 0x17
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk24__SHIFT 0x18
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk25__SHIFT 0x19
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk26__SHIFT 0x1a
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk27__SHIFT 0x1b
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk28__SHIFT 0x1c
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk29__SHIFT 0x1d
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk30__SHIFT 0x1e
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk31__SHIFT 0x1f
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk0_MASK 0x00000001L
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk1_MASK 0x00000002L
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk2_MASK 0x00000004L
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk3_MASK 0x00000008L
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk4_MASK 0x00000010L
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk5_MASK 0x00000020L
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk6_MASK 0x00000040L
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk7_MASK 0x00000080L
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk8_MASK 0x00000100L
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk9_MASK 0x00000200L
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk10_MASK 0x00000400L
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk11_MASK 0x00000800L
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk12_MASK 0x00001000L
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk13_MASK 0x00002000L
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk14_MASK 0x00004000L
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk15_MASK 0x00008000L
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk16_MASK 0x00010000L
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk17_MASK 0x00020000L
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk18_MASK 0x00040000L
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk19_MASK 0x00080000L
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk20_MASK 0x00100000L
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk21_MASK 0x00200000L
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk22_MASK 0x00400000L
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk23_MASK 0x00800000L
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk24_MASK 0x01000000L
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk25_MASK 0x02000000L
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk26_MASK 0x04000000L
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk27_MASK 0x08000000L
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk28_MASK 0x10000000L
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk29_MASK 0x20000000L
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk30_MASK 0x40000000L
+#define DF_NCS_PG0_HardwareAssertMaskHigh__HWAssertMsk31_MASK 0x80000000L
+
+#endif
diff --git a/drivers/gpu/drm/amd/include/asic_reg/gc/gc_11_0_3_offset.h b/drivers/gpu/drm/amd/include/asic_reg/gc/gc_11_0_3_offset.h
index 3b95a59b196c..56e00252bff8 100644
--- a/drivers/gpu/drm/amd/include/asic_reg/gc/gc_11_0_3_offset.h
+++ b/drivers/gpu/drm/amd/include/asic_reg/gc/gc_11_0_3_offset.h
@@ -3593,6 +3593,14 @@
#define regGCL2TLB_PERFCOUNTER_RSLT_CNTL_BASE_IDX 1
+// addressBlock: gc_rlcsdec
+// base address: 0x3b980
+#define regRLC_RLCS_FED_STATUS_0 0x4eff
+#define regRLC_RLCS_FED_STATUS_0_BASE_IDX 1
+#define regRLC_RLCS_FED_STATUS_1 0x4f00
+#define regRLC_RLCS_FED_STATUS_1_BASE_IDX 1
+
+
// addressBlock: gc_gcvml2pspdec
// base address: 0x3f900
#define regGCUTCL2_TRANSLATION_BYPASS_BY_VMID 0x5e41
diff --git a/drivers/gpu/drm/amd/include/asic_reg/gc/gc_11_0_3_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/gc/gc_11_0_3_sh_mask.h
index ae3ef8a9e702..658e88a8e2ac 100644
--- a/drivers/gpu/drm/amd/include/asic_reg/gc/gc_11_0_3_sh_mask.h
+++ b/drivers/gpu/drm/amd/include/asic_reg/gc/gc_11_0_3_sh_mask.h
@@ -37642,6 +37642,56 @@
#define RLC_RLCG_DOORBELL_RANGE__LOWER_ADDR_MASK 0x00000FFCL
#define RLC_RLCG_DOORBELL_RANGE__UPPER_ADDR_RESERVED_MASK 0x00030000L
#define RLC_RLCG_DOORBELL_RANGE__UPPER_ADDR_MASK 0x0FFC0000L
+//RLC_RLCS_FED_STATUS_0
+#define RLC_RLCS_FED_STATUS_0__RLC_FED_ERR__SHIFT 0x0
+#define RLC_RLCS_FED_STATUS_0__UTCL2_FED_ERR__SHIFT 0x1
+#define RLC_RLCS_FED_STATUS_0__GE_FED_ERR__SHIFT 0x2
+#define RLC_RLCS_FED_STATUS_0__CPC_FED_ERR__SHIFT 0x3
+#define RLC_RLCS_FED_STATUS_0__CPF_FED_ERR__SHIFT 0x4
+#define RLC_RLCS_FED_STATUS_0__CPG_FED_ERR__SHIFT 0x5
+#define RLC_RLCS_FED_STATUS_0__SDMA0_FED_ERR__SHIFT 0x6
+#define RLC_RLCS_FED_STATUS_0__SDMA1_FED_ERR__SHIFT 0x7
+#define RLC_RLCS_FED_STATUS_0__RLC_FED_ERR_MASK 0x00000001L
+#define RLC_RLCS_FED_STATUS_0__UTCL2_FED_ERR_MASK 0x00000002L
+#define RLC_RLCS_FED_STATUS_0__GE_FED_ERR_MASK 0x00000004L
+#define RLC_RLCS_FED_STATUS_0__CPC_FED_ERR_MASK 0x00000008L
+#define RLC_RLCS_FED_STATUS_0__CPF_FED_ERR_MASK 0x00000010L
+#define RLC_RLCS_FED_STATUS_0__CPG_FED_ERR_MASK 0x00000020L
+#define RLC_RLCS_FED_STATUS_0__SDMA0_FED_ERR_MASK 0x00000040L
+#define RLC_RLCS_FED_STATUS_0__SDMA1_FED_ERR_MASK 0x00000080L
+//RLC_RLCS_FED_STATUS_1
+#define RLC_RLCS_FED_STATUS_1__GL2C0_FED_ERR__SHIFT 0x0
+#define RLC_RLCS_FED_STATUS_1__GL2C1_FED_ERR__SHIFT 0x1
+#define RLC_RLCS_FED_STATUS_1__GL2C2_FED_ERR__SHIFT 0x2
+#define RLC_RLCS_FED_STATUS_1__GL2C3_FED_ERR__SHIFT 0x3
+#define RLC_RLCS_FED_STATUS_1__GL2C4_FED_ERR__SHIFT 0x4
+#define RLC_RLCS_FED_STATUS_1__GL2C5_FED_ERR__SHIFT 0x5
+#define RLC_RLCS_FED_STATUS_1__GL2C6_FED_ERR__SHIFT 0x6
+#define RLC_RLCS_FED_STATUS_1__GL2C7_FED_ERR__SHIFT 0x7
+#define RLC_RLCS_FED_STATUS_1__GL2C8_FED_ERR__SHIFT 0x8
+#define RLC_RLCS_FED_STATUS_1__GL2C9_FED_ERR__SHIFT 0x9
+#define RLC_RLCS_FED_STATUS_1__GL2C10_FED_ERR__SHIFT 0xa
+#define RLC_RLCS_FED_STATUS_1__GL2C11_FED_ERR__SHIFT 0xb
+#define RLC_RLCS_FED_STATUS_1__GL2C12_FED_ERR__SHIFT 0xc
+#define RLC_RLCS_FED_STATUS_1__GL2C13_FED_ERR__SHIFT 0xd
+#define RLC_RLCS_FED_STATUS_1__GL2C14_FED_ERR__SHIFT 0xe
+#define RLC_RLCS_FED_STATUS_1__GL2C15_FED_ERR__SHIFT 0xf
+#define RLC_RLCS_FED_STATUS_1__GL2C0_FED_ERR_MASK 0x00000001L
+#define RLC_RLCS_FED_STATUS_1__GL2C1_FED_ERR_MASK 0x00000002L
+#define RLC_RLCS_FED_STATUS_1__GL2C2_FED_ERR_MASK 0x00000004L
+#define RLC_RLCS_FED_STATUS_1__GL2C3_FED_ERR_MASK 0x00000008L
+#define RLC_RLCS_FED_STATUS_1__GL2C4_FED_ERR_MASK 0x00000010L
+#define RLC_RLCS_FED_STATUS_1__GL2C5_FED_ERR_MASK 0x00000020L
+#define RLC_RLCS_FED_STATUS_1__GL2C6_FED_ERR_MASK 0x00000040L
+#define RLC_RLCS_FED_STATUS_1__GL2C7_FED_ERR_MASK 0x00000080L
+#define RLC_RLCS_FED_STATUS_1__GL2C8_FED_ERR_MASK 0x00000100L
+#define RLC_RLCS_FED_STATUS_1__GL2C9_FED_ERR_MASK 0x00000200L
+#define RLC_RLCS_FED_STATUS_1__GL2C10_FED_ERR_MASK 0x00000400L
+#define RLC_RLCS_FED_STATUS_1__GL2C11_FED_ERR_MASK 0x00000800L
+#define RLC_RLCS_FED_STATUS_1__GL2C12_FED_ERR_MASK 0x00001000L
+#define RLC_RLCS_FED_STATUS_1__GL2C13_FED_ERR_MASK 0x00002000L
+#define RLC_RLCS_FED_STATUS_1__GL2C14_FED_ERR_MASK 0x00004000L
+#define RLC_RLCS_FED_STATUS_1__GL2C15_FED_ERR_MASK 0x00008000L
//RLC_CGTT_MGCG_OVERRIDE
#define RLC_CGTT_MGCG_OVERRIDE__RLC_REPEATER_FGCG_OVERRIDE__SHIFT 0x0
#define RLC_CGTT_MGCG_OVERRIDE__RLC_CGTT_SCLK_OVERRIDE__SHIFT 0x1
diff --git a/drivers/gpu/drm/amd/include/asic_reg/xgmi/xgmi_6_1_0_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/xgmi/xgmi_6_1_0_sh_mask.h
new file mode 100644
index 000000000000..c6c0cf1376a6
--- /dev/null
+++ b/drivers/gpu/drm/amd/include/asic_reg/xgmi/xgmi_6_1_0_sh_mask.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2023 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ */
+
+#ifndef _xgmi_6_1_0_SH_MASK_HEADER
+#define _xgmi_6_1_0_SH_MASK_HEADER
+
+//PCS_XGMI3X16_PCS_ERROR_STATUS
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__DataLossErr__SHIFT 0x0
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__TrainingErr__SHIFT 0x1
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__FlowCtrlAckErr__SHIFT 0x2
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__RxFifoUnderflowErr__SHIFT 0x3
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__RxFifoOverflowErr__SHIFT 0x4
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__CRCErr__SHIFT 0x5
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__BERExceededErr__SHIFT 0x6
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__TxVcidDataErr__SHIFT 0x7
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__ReplayBufParityErr__SHIFT 0x8
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__DataParityErr__SHIFT 0x9
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__ReplayFifoOverflowErr__SHIFT 0xa
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__ReplayFifoUnderflowErr__SHIFT 0xb
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__ElasticFifoOverflowErr__SHIFT 0xc
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__DeskewErr__SHIFT 0xd
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__FlowCtrlCRCErr__SHIFT 0xe
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__DataStartupLimitErr__SHIFT 0xf
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__FCInitTimeoutErr__SHIFT 0x10
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__RecoveryTimeoutErr__SHIFT 0x11
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__ReadySerialTimeoutErr__SHIFT 0x12
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__ReadySerialAttemptErr__SHIFT 0x13
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__RecoveryAttemptErr__SHIFT 0x14
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__RecoveryRelockAttemptErr__SHIFT 0x15
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__ReplayAttemptErr__SHIFT 0x16
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__SyncHdrErr__SHIFT 0x17
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__TxReplayTimeoutErr__SHIFT 0x18
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__RxReplayTimeoutErr__SHIFT 0x19
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__LinkSubTxTimeoutErr__SHIFT 0x1a
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__LinkSubRxTimeoutErr__SHIFT 0x1b
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__RxCMDPktErr__SHIFT 0x1c
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__DataLossErr_MASK 0x00000001L
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__TrainingErr_MASK 0x00000002L
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__FlowCtrlAckErr_MASK 0x00000004L
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__RxFifoUnderflowErr_MASK 0x00000008L
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__RxFifoOverflowErr_MASK 0x00000010L
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__CRCErr_MASK 0x00000020L
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__BERExceededErr_MASK 0x00000040L
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__TxVcidDataErr_MASK 0x00000080L
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__ReplayBufParityErr_MASK 0x00000100L
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__DataParityErr_MASK 0x00000200L
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__ReplayFifoOverflowErr_MASK 0x00000400L
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__ReplayFifoUnderflowErr_MASK 0x00000800L
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__ElasticFifoOverflowErr_MASK 0x00001000L
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__DeskewErr_MASK 0x00002000L
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__FlowCtrlCRCErr_MASK 0x00004000L
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__DataStartupLimitErr_MASK 0x00008000L
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__FCInitTimeoutErr_MASK 0x00010000L
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__RecoveryTimeoutErr_MASK 0x00020000L
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__ReadySerialTimeoutErr_MASK 0x00040000L
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__ReadySerialAttemptErr_MASK 0x00080000L
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__RecoveryAttemptErr_MASK 0x00100000L
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__RecoveryRelockAttemptErr_MASK 0x00200000L
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__ReplayAttemptErr_MASK 0x00400000L
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__SyncHdrErr_MASK 0x00800000L
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__TxReplayTimeoutErr_MASK 0x01000000L
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__RxReplayTimeoutErr_MASK 0x02000000L
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__LinkSubTxTimeoutErr_MASK 0x04000000L
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__LinkSubRxTimeoutErr_MASK 0x08000000L
+#define PCS_XGMI3X16_PCS_ERROR_STATUS__RxCMDPktErr_MASK 0x10000000L
+
+#endif
diff --git a/drivers/gpu/drm/amd/include/ivsrcid/gfx/irqsrcs_gfx_11_0_0.h b/drivers/gpu/drm/amd/include/ivsrcid/gfx/irqsrcs_gfx_11_0_0.h
index 9e8ed9f4bb15..3a4670bc4449 100644
--- a/drivers/gpu/drm/amd/include/ivsrcid/gfx/irqsrcs_gfx_11_0_0.h
+++ b/drivers/gpu/drm/amd/include/ivsrcid/gfx/irqsrcs_gfx_11_0_0.h
@@ -49,6 +49,8 @@
#define GFX_11_0_0__SRCID__SDMA_SEM_INCOMPLETE_TIMEOUT 65 // 0x41 GPF(Sem incomplete timeout)
#define GFX_11_0_0__SRCID__SDMA_SEM_WAIT_FAIL_TIMEOUT 66 // 0x42 Semaphore wait fail timeout
+#define GFX_11_0_0__SRCID__RLC_GC_FED_INTERRUPT 128 // 0x80 FED Interrupt (for data poisoning)
+
#define GFX_11_0_0__SRCID__CP_GENERIC_INT 177 // 0xB1 CP_GENERIC int
#define GFX_11_0_0__SRCID__CP_PM4_PKT_RSVD_BIT_ERROR 180 // 0xB4 PM4 Pkt Rsvd Bits Error
#define GFX_11_0_0__SRCID__CP_EOP_INTERRUPT 181 // 0xB5 End-of-Pipe Interrupt
diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h
index d18162e9ed1d..75f18791cdb9 100644
--- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h
+++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h
@@ -139,6 +139,8 @@ enum amd_pp_sensors {
AMDGPU_PP_SENSOR_MIN_FAN_RPM,
AMDGPU_PP_SENSOR_MAX_FAN_RPM,
AMDGPU_PP_SENSOR_VCN_POWER_STATE,
+ AMDGPU_PP_SENSOR_PEAK_PSTATE_SCLK,
+ AMDGPU_PP_SENSOR_PEAK_PSTATE_MCLK,
};
enum amd_pp_task {
@@ -395,6 +397,7 @@ struct amd_pm_funcs {
int (*get_ppfeature_status)(void *handle, char *buf);
int (*set_ppfeature_status)(void *handle, uint64_t ppfeature_masks);
int (*asic_reset_mode_2)(void *handle);
+ int (*asic_reset_enable_gfx_features)(void *handle);
int (*set_df_cstate)(void *handle, enum pp_df_cstate state);
int (*set_xgmi_pstate)(void *handle, uint32_t pstate);
ssize_t (*get_gpu_metrics)(void *handle, void **table);
diff --git a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
index 1b300c569faf..6e79d3352d0b 100644
--- a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
+++ b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
@@ -227,6 +227,24 @@ int amdgpu_dpm_mode2_reset(struct amdgpu_device *adev)
return ret;
}
+int amdgpu_dpm_enable_gfx_features(struct amdgpu_device *adev)
+{
+ const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
+ void *pp_handle = adev->powerplay.pp_handle;
+ int ret = 0;
+
+ if (!pp_funcs || !pp_funcs->asic_reset_enable_gfx_features)
+ return -ENOENT;
+
+ mutex_lock(&adev->pm.mutex);
+
+ ret = pp_funcs->asic_reset_enable_gfx_features(pp_handle);
+
+ mutex_unlock(&adev->pm.mutex);
+
+ return ret;
+}
+
int amdgpu_dpm_baco_reset(struct amdgpu_device *adev)
{
const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c
index 2f3e239e623d..bf6d63673b5a 100644
--- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c
+++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c
@@ -3063,7 +3063,7 @@ static ssize_t amdgpu_hwmon_show_mclk_label(struct device *dev,
*
* hwmon interfaces for GPU power:
*
- * - power1_average: average power used by the GPU in microWatts
+ * - power1_average: average power used by the SoC in microWatts. On APUs this includes the CPU.
*
* - power1_cap_min: minimum cap supported in microWatts
*
diff --git a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
index cb5b9df78b4d..16addceca68f 100644
--- a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
+++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
@@ -386,6 +386,7 @@ int amdgpu_dpm_switch_power_profile(struct amdgpu_device *adev,
int amdgpu_dpm_baco_reset(struct amdgpu_device *adev);
int amdgpu_dpm_mode2_reset(struct amdgpu_device *adev);
+int amdgpu_dpm_enable_gfx_features(struct amdgpu_device *adev);
bool amdgpu_dpm_is_baco_supported(struct amdgpu_device *adev);
diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c b/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c
index 49c398ec0aaf..d6d9e3b1b2c0 100644
--- a/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c
+++ b/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c
@@ -7714,20 +7714,13 @@ static int si_dpm_init_microcode(struct amdgpu_device *adev)
}
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_smc.bin", chip_name);
- err = request_firmware(&adev->pm.fw, fw_name, adev->dev);
- if (err)
- goto out;
- err = amdgpu_ucode_validate(adev->pm.fw);
-
-out:
+ err = amdgpu_ucode_request(adev, &adev->pm.fw, fw_name);
if (err) {
DRM_ERROR("si_smc: Failed to load firmware. err = %d\"%s\"\n",
err, fw_name);
- release_firmware(adev->pm.fw);
- adev->pm.fw = NULL;
+ amdgpu_ucode_release(&adev->pm.fw);
}
return err;
-
}
static int si_dpm_sw_init(void *handle)
diff --git a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c
index 304190d5c9d2..11b7b4cffaae 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c
@@ -111,8 +111,7 @@ static int pp_sw_fini(void *handle)
hwmgr_sw_fini(hwmgr);
- release_firmware(adev->pm.fw);
- adev->pm.fw = NULL;
+ amdgpu_ucode_release(&adev->pm.fw);
return 0;
}
@@ -769,10 +768,16 @@ static int pp_dpm_read_sensor(void *handle, int idx,
switch (idx) {
case AMDGPU_PP_SENSOR_STABLE_PSTATE_SCLK:
- *((uint32_t *)value) = hwmgr->pstate_sclk;
+ *((uint32_t *)value) = hwmgr->pstate_sclk * 100;
return 0;
case AMDGPU_PP_SENSOR_STABLE_PSTATE_MCLK:
- *((uint32_t *)value) = hwmgr->pstate_mclk;
+ *((uint32_t *)value) = hwmgr->pstate_mclk * 100;
+ return 0;
+ case AMDGPU_PP_SENSOR_PEAK_PSTATE_SCLK:
+ *((uint32_t *)value) = hwmgr->pstate_sclk_peak * 100;
+ return 0;
+ case AMDGPU_PP_SENSOR_PEAK_PSTATE_MCLK:
+ *((uint32_t *)value) = hwmgr->pstate_mclk_peak * 100;
return 0;
case AMDGPU_PP_SENSOR_MIN_FAN_RPM:
*((uint32_t *)value) = hwmgr->thermal_controller.fanInfo.ulMinRPM;
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c
index ede71de2343d..86d6e88c7386 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c
@@ -375,6 +375,17 @@ static int smu10_enable_gfx_off(struct pp_hwmgr *hwmgr)
return 0;
}
+static void smu10_populate_umdpstate_clocks(struct pp_hwmgr *hwmgr)
+{
+ hwmgr->pstate_sclk = SMU10_UMD_PSTATE_GFXCLK;
+ hwmgr->pstate_mclk = SMU10_UMD_PSTATE_FCLK;
+
+ smum_send_msg_to_smc(hwmgr,
+ PPSMC_MSG_GetMaxGfxclkFrequency,
+ &hwmgr->pstate_sclk_peak);
+ hwmgr->pstate_mclk_peak = SMU10_UMD_PSTATE_PEAK_FCLK;
+}
+
static int smu10_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
{
struct amdgpu_device *adev = hwmgr->adev;
@@ -398,6 +409,8 @@ static int smu10_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
return ret;
}
+ smu10_populate_umdpstate_clocks(hwmgr);
+
return 0;
}
@@ -574,9 +587,6 @@ static int smu10_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
hwmgr->platform_descriptor.minimumClocksReductionPercentage = 50;
- hwmgr->pstate_sclk = SMU10_UMD_PSTATE_GFXCLK * 100;
- hwmgr->pstate_mclk = SMU10_UMD_PSTATE_FCLK * 100;
-
/* enable the pp_od_clk_voltage sysfs file */
hwmgr->od_enabled = 1;
/* disabled fine grain tuning function by default */
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c
index 7ef7e81525a3..e10cc5e7928e 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c
@@ -22,7 +22,6 @@
*/
#include "pp_debug.h"
#include <linux/delay.h>
-#include <linux/fb.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/slab.h>
@@ -1501,6 +1500,67 @@ static int smu7_populate_edc_leakage_registers(struct pp_hwmgr *hwmgr)
return ret;
}
+static void smu7_populate_umdpstate_clocks(struct pp_hwmgr *hwmgr)
+{
+ struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+ struct smu7_dpm_table *golden_dpm_table = &data->golden_dpm_table;
+ int32_t tmp_sclk, count, percentage;
+
+ if (golden_dpm_table->mclk_table.count == 1) {
+ percentage = 70;
+ hwmgr->pstate_mclk = golden_dpm_table->mclk_table.dpm_levels[0].value;
+ } else {
+ percentage = 100 * golden_dpm_table->sclk_table.dpm_levels[golden_dpm_table->sclk_table.count - 1].value /
+ golden_dpm_table->mclk_table.dpm_levels[golden_dpm_table->mclk_table.count - 1].value;
+ hwmgr->pstate_mclk = golden_dpm_table->mclk_table.dpm_levels[golden_dpm_table->mclk_table.count - 2].value;
+ }
+
+ tmp_sclk = hwmgr->pstate_mclk * percentage / 100;
+
+ if (hwmgr->pp_table_version == PP_TABLE_V0) {
+ struct phm_clock_voltage_dependency_table *vddc_dependency_on_sclk =
+ hwmgr->dyn_state.vddc_dependency_on_sclk;
+
+ for (count = vddc_dependency_on_sclk->count - 1; count >= 0; count--) {
+ if (tmp_sclk >= vddc_dependency_on_sclk->entries[count].clk) {
+ hwmgr->pstate_sclk = vddc_dependency_on_sclk->entries[count].clk;
+ break;
+ }
+ }
+ if (count < 0)
+ hwmgr->pstate_sclk = vddc_dependency_on_sclk->entries[0].clk;
+
+ hwmgr->pstate_sclk_peak =
+ vddc_dependency_on_sclk->entries[vddc_dependency_on_sclk->count - 1].clk;
+ } else if (hwmgr->pp_table_version == PP_TABLE_V1) {
+ struct phm_ppt_v1_information *table_info =
+ (struct phm_ppt_v1_information *)(hwmgr->pptable);
+ struct phm_ppt_v1_clock_voltage_dependency_table *vdd_dep_on_sclk =
+ table_info->vdd_dep_on_sclk;
+
+ for (count = vdd_dep_on_sclk->count - 1; count >= 0; count--) {
+ if (tmp_sclk >= vdd_dep_on_sclk->entries[count].clk) {
+ hwmgr->pstate_sclk = vdd_dep_on_sclk->entries[count].clk;
+ break;
+ }
+ }
+ if (count < 0)
+ hwmgr->pstate_sclk = vdd_dep_on_sclk->entries[0].clk;
+
+ hwmgr->pstate_sclk_peak =
+ vdd_dep_on_sclk->entries[vdd_dep_on_sclk->count - 1].clk;
+ }
+
+ hwmgr->pstate_mclk_peak =
+ golden_dpm_table->mclk_table.dpm_levels[golden_dpm_table->mclk_table.count - 1].value;
+
+ /* make sure the output is in Mhz */
+ hwmgr->pstate_sclk /= 100;
+ hwmgr->pstate_mclk /= 100;
+ hwmgr->pstate_sclk_peak /= 100;
+ hwmgr->pstate_mclk_peak /= 100;
+}
+
static int smu7_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
{
int tmp_result = 0;
@@ -1625,6 +1685,8 @@ static int smu7_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
PP_ASSERT_WITH_CODE((0 == tmp_result),
"pcie performance request failed!", result = tmp_result);
+ smu7_populate_umdpstate_clocks(hwmgr);
+
return 0;
}
@@ -3143,15 +3205,12 @@ static int smu7_get_profiling_clk(struct pp_hwmgr *hwmgr, enum amd_dpm_forced_le
for (count = hwmgr->dyn_state.vddc_dependency_on_sclk->count-1;
count >= 0; count--) {
if (tmp_sclk >= hwmgr->dyn_state.vddc_dependency_on_sclk->entries[count].clk) {
- tmp_sclk = hwmgr->dyn_state.vddc_dependency_on_sclk->entries[count].clk;
*sclk_mask = count;
break;
}
}
- if (count < 0 || level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) {
+ if (count < 0 || level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK)
*sclk_mask = 0;
- tmp_sclk = hwmgr->dyn_state.vddc_dependency_on_sclk->entries[0].clk;
- }
if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK)
*sclk_mask = hwmgr->dyn_state.vddc_dependency_on_sclk->count-1;
@@ -3161,15 +3220,12 @@ static int smu7_get_profiling_clk(struct pp_hwmgr *hwmgr, enum amd_dpm_forced_le
for (count = table_info->vdd_dep_on_sclk->count-1; count >= 0; count--) {
if (tmp_sclk >= table_info->vdd_dep_on_sclk->entries[count].clk) {
- tmp_sclk = table_info->vdd_dep_on_sclk->entries[count].clk;
*sclk_mask = count;
break;
}
}
- if (count < 0 || level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) {
+ if (count < 0 || level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK)
*sclk_mask = 0;
- tmp_sclk = table_info->vdd_dep_on_sclk->entries[0].clk;
- }
if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK)
*sclk_mask = table_info->vdd_dep_on_sclk->count - 1;
@@ -3181,8 +3237,6 @@ static int smu7_get_profiling_clk(struct pp_hwmgr *hwmgr, enum amd_dpm_forced_le
*mclk_mask = golden_dpm_table->mclk_table.count - 1;
*pcie_mask = data->dpm_table.pcie_speed_table.count - 1;
- hwmgr->pstate_sclk = tmp_sclk;
- hwmgr->pstate_mclk = tmp_mclk;
return 0;
}
@@ -3195,9 +3249,6 @@ static int smu7_force_dpm_level(struct pp_hwmgr *hwmgr,
uint32_t mclk_mask = 0;
uint32_t pcie_mask = 0;
- if (hwmgr->pstate_sclk == 0)
- smu7_get_profiling_clk(hwmgr, level, &sclk_mask, &mclk_mask, &pcie_mask);
-
switch (level) {
case AMD_DPM_FORCED_LEVEL_HIGH:
ret = smu7_force_dpm_highest(hwmgr);
@@ -4153,7 +4204,7 @@ static int smu7_freeze_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
if ((0 == data->sclk_dpm_key_disabled) &&
(data->need_update_smu7_dpm_table &
- (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK))) {
+ (DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_UPDATE_SCLK))) {
PP_ASSERT_WITH_CODE(true == smum_is_dpm_running(hwmgr),
"Trying to freeze SCLK DPM when DPM is disabled",
);
@@ -4210,7 +4261,7 @@ static int smu7_populate_and_upload_sclk_mclk_dpm_levels(
}
if (data->need_update_smu7_dpm_table &
- (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK)) {
+ (DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_UPDATE_SCLK)) {
result = smum_populate_all_graphic_levels(hwmgr);
PP_ASSERT_WITH_CODE((0 == result),
"Failed to populate SCLK during PopulateNewDPMClocksStates Function!",
@@ -4218,7 +4269,7 @@ static int smu7_populate_and_upload_sclk_mclk_dpm_levels(
}
if (data->need_update_smu7_dpm_table &
- (DPMTABLE_OD_UPDATE_MCLK + DPMTABLE_UPDATE_MCLK)) {
+ (DPMTABLE_OD_UPDATE_MCLK | DPMTABLE_UPDATE_MCLK)) {
/*populate MCLK dpm table to SMU7 */
result = smum_populate_all_memory_levels(hwmgr);
PP_ASSERT_WITH_CODE((0 == result),
@@ -4309,7 +4360,7 @@ static int smu7_unfreeze_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
if ((0 == data->sclk_dpm_key_disabled) &&
(data->need_update_smu7_dpm_table &
- (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_UPDATE_SCLK))) {
+ (DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_UPDATE_SCLK))) {
PP_ASSERT_WITH_CODE(true == smum_is_dpm_running(hwmgr),
"Trying to Unfreeze SCLK DPM when DPM is disabled",
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.c
index b50fd4a4a3d1..b015a601b385 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.c
@@ -1016,6 +1016,18 @@ static void smu8_reset_acp_boot_level(struct pp_hwmgr *hwmgr)
data->acp_boot_level = 0xff;
}
+static void smu8_populate_umdpstate_clocks(struct pp_hwmgr *hwmgr)
+{
+ struct phm_clock_voltage_dependency_table *table =
+ hwmgr->dyn_state.vddc_dependency_on_sclk;
+
+ hwmgr->pstate_sclk = table->entries[0].clk / 100;
+ hwmgr->pstate_mclk = 0;
+
+ hwmgr->pstate_sclk_peak = table->entries[table->count - 1].clk / 100;
+ hwmgr->pstate_mclk_peak = 0;
+}
+
static int smu8_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
{
smu8_program_voting_clients(hwmgr);
@@ -1024,6 +1036,8 @@ static int smu8_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
smu8_program_bootup_state(hwmgr);
smu8_reset_acp_boot_level(hwmgr);
+ smu8_populate_umdpstate_clocks(hwmgr);
+
return 0;
}
@@ -1167,8 +1181,6 @@ static int smu8_phm_unforce_dpm_levels(struct pp_hwmgr *hwmgr)
data->sclk_dpm.soft_min_clk = table->entries[0].clk;
data->sclk_dpm.hard_min_clk = table->entries[0].clk;
- hwmgr->pstate_sclk = table->entries[0].clk;
- hwmgr->pstate_mclk = 0;
level = smu8_get_max_sclk_level(hwmgr) - 1;
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c
index c8c9fb827bda..99cd2e63afdd 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c
@@ -22,7 +22,6 @@
*/
#include <linux/delay.h>
-#include <linux/fb.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/slab.h>
@@ -3008,6 +3007,30 @@ static int vega10_enable_disable_PCC_limit_feature(struct pp_hwmgr *hwmgr, bool
return 0;
}
+static void vega10_populate_umdpstate_clocks(struct pp_hwmgr *hwmgr)
+{
+ struct phm_ppt_v2_information *table_info =
+ (struct phm_ppt_v2_information *)(hwmgr->pptable);
+
+ if (table_info->vdd_dep_on_sclk->count > VEGA10_UMD_PSTATE_GFXCLK_LEVEL &&
+ table_info->vdd_dep_on_mclk->count > VEGA10_UMD_PSTATE_MCLK_LEVEL) {
+ hwmgr->pstate_sclk = table_info->vdd_dep_on_sclk->entries[VEGA10_UMD_PSTATE_GFXCLK_LEVEL].clk;
+ hwmgr->pstate_mclk = table_info->vdd_dep_on_mclk->entries[VEGA10_UMD_PSTATE_MCLK_LEVEL].clk;
+ } else {
+ hwmgr->pstate_sclk = table_info->vdd_dep_on_sclk->entries[0].clk;
+ hwmgr->pstate_mclk = table_info->vdd_dep_on_mclk->entries[0].clk;
+ }
+
+ hwmgr->pstate_sclk_peak = table_info->vdd_dep_on_sclk->entries[table_info->vdd_dep_on_sclk->count - 1].clk;
+ hwmgr->pstate_mclk_peak = table_info->vdd_dep_on_mclk->entries[table_info->vdd_dep_on_mclk->count - 1].clk;
+
+ /* make sure the output is in Mhz */
+ hwmgr->pstate_sclk /= 100;
+ hwmgr->pstate_mclk /= 100;
+ hwmgr->pstate_sclk_peak /= 100;
+ hwmgr->pstate_mclk_peak /= 100;
+}
+
static int vega10_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
{
struct vega10_hwmgr *data = hwmgr->backend;
@@ -3082,6 +3105,8 @@ static int vega10_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
result = tmp_result);
}
+ vega10_populate_umdpstate_clocks(hwmgr);
+
return result;
}
@@ -4169,8 +4194,6 @@ static int vega10_get_profiling_clk_mask(struct pp_hwmgr *hwmgr, enum amd_dpm_fo
*sclk_mask = VEGA10_UMD_PSTATE_GFXCLK_LEVEL;
*soc_mask = VEGA10_UMD_PSTATE_SOCCLK_LEVEL;
*mclk_mask = VEGA10_UMD_PSTATE_MCLK_LEVEL;
- hwmgr->pstate_sclk = table_info->vdd_dep_on_sclk->entries[VEGA10_UMD_PSTATE_GFXCLK_LEVEL].clk;
- hwmgr->pstate_mclk = table_info->vdd_dep_on_mclk->entries[VEGA10_UMD_PSTATE_MCLK_LEVEL].clk;
}
if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) {
@@ -4281,9 +4304,6 @@ static int vega10_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
uint32_t mclk_mask = 0;
uint32_t soc_mask = 0;
- if (hwmgr->pstate_sclk == 0)
- vega10_get_profiling_clk_mask(hwmgr, level, &sclk_mask, &mclk_mask, &soc_mask);
-
switch (level) {
case AMD_DPM_FORCED_LEVEL_HIGH:
ret = vega10_force_dpm_highest(hwmgr);
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_processpptables.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_processpptables.c
index 95b988823f50..bb90d8abf79b 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_processpptables.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_processpptables.c
@@ -23,7 +23,6 @@
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/slab.h>
-#include <linux/fb.h>
#include "vega10_processpptables.h"
#include "ppatomfwctrl.h"
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c
index a2f4d6773d45..e9db137cd1c6 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_hwmgr.c
@@ -22,7 +22,6 @@
*/
#include <linux/delay.h>
-#include <linux/fb.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -1026,6 +1025,25 @@ static int vega12_get_all_clock_ranges(struct pp_hwmgr *hwmgr)
return 0;
}
+static void vega12_populate_umdpstate_clocks(struct pp_hwmgr *hwmgr)
+{
+ struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend);
+ struct vega12_single_dpm_table *gfx_dpm_table = &(data->dpm_table.gfx_table);
+ struct vega12_single_dpm_table *mem_dpm_table = &(data->dpm_table.mem_table);
+
+ if (gfx_dpm_table->count > VEGA12_UMD_PSTATE_GFXCLK_LEVEL &&
+ mem_dpm_table->count > VEGA12_UMD_PSTATE_MCLK_LEVEL) {
+ hwmgr->pstate_sclk = gfx_dpm_table->dpm_levels[VEGA12_UMD_PSTATE_GFXCLK_LEVEL].value;
+ hwmgr->pstate_mclk = mem_dpm_table->dpm_levels[VEGA12_UMD_PSTATE_MCLK_LEVEL].value;
+ } else {
+ hwmgr->pstate_sclk = gfx_dpm_table->dpm_levels[0].value;
+ hwmgr->pstate_mclk = mem_dpm_table->dpm_levels[0].value;
+ }
+
+ hwmgr->pstate_sclk_peak = gfx_dpm_table->dpm_levels[gfx_dpm_table->count].value;
+ hwmgr->pstate_mclk_peak = mem_dpm_table->dpm_levels[mem_dpm_table->count].value;
+}
+
static int vega12_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
{
int tmp_result, result = 0;
@@ -1077,6 +1095,9 @@ static int vega12_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
PP_ASSERT_WITH_CODE(!result,
"Failed to setup default DPM tables!",
return result);
+
+ vega12_populate_umdpstate_clocks(hwmgr);
+
return result;
}
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.c
index bd54fbd393b9..89148f73b514 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.c
@@ -22,7 +22,6 @@
*/
#include <linux/module.h>
#include <linux/slab.h>
-#include <linux/fb.h>
#include "vega12/smu9_driver_if.h"
#include "vega12_processpptables.h"
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c
index b30684c84e20..0d4d4811527c 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_hwmgr.c
@@ -22,7 +22,6 @@
*/
#include <linux/delay.h>
-#include <linux/fb.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -1555,26 +1554,23 @@ static int vega20_set_mclk_od(
return 0;
}
-static int vega20_populate_umdpstate_clocks(
- struct pp_hwmgr *hwmgr)
+static void vega20_populate_umdpstate_clocks(struct pp_hwmgr *hwmgr)
{
struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
struct vega20_single_dpm_table *gfx_table = &(data->dpm_table.gfx_table);
struct vega20_single_dpm_table *mem_table = &(data->dpm_table.mem_table);
- hwmgr->pstate_sclk = gfx_table->dpm_levels[0].value;
- hwmgr->pstate_mclk = mem_table->dpm_levels[0].value;
-
if (gfx_table->count > VEGA20_UMD_PSTATE_GFXCLK_LEVEL &&
mem_table->count > VEGA20_UMD_PSTATE_MCLK_LEVEL) {
hwmgr->pstate_sclk = gfx_table->dpm_levels[VEGA20_UMD_PSTATE_GFXCLK_LEVEL].value;
hwmgr->pstate_mclk = mem_table->dpm_levels[VEGA20_UMD_PSTATE_MCLK_LEVEL].value;
+ } else {
+ hwmgr->pstate_sclk = gfx_table->dpm_levels[0].value;
+ hwmgr->pstate_mclk = mem_table->dpm_levels[0].value;
}
- hwmgr->pstate_sclk = hwmgr->pstate_sclk * 100;
- hwmgr->pstate_mclk = hwmgr->pstate_mclk * 100;
-
- return 0;
+ hwmgr->pstate_sclk_peak = gfx_table->dpm_levels[gfx_table->count - 1].value;
+ hwmgr->pstate_mclk_peak = mem_table->dpm_levels[mem_table->count - 1].value;
}
static int vega20_get_max_sustainable_clock(struct pp_hwmgr *hwmgr,
@@ -1753,10 +1749,7 @@ static int vega20_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
"[EnableDPMTasks] Failed to initialize odn settings!",
return result);
- result = vega20_populate_umdpstate_clocks(hwmgr);
- PP_ASSERT_WITH_CODE(!result,
- "[EnableDPMTasks] Failed to populate umdpstate clocks!",
- return result);
+ vega20_populate_umdpstate_clocks(hwmgr);
result = smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_GetPptLimit,
POWER_SOURCE_AC << 16, &hwmgr->default_power_limit);
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.c
index 1f9082539457..79c817752a33 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.c
@@ -22,7 +22,6 @@
*/
#include <linux/module.h>
#include <linux/slab.h>
-#include <linux/fb.h>
#include "smu11_driver_if.h"
#include "vega20_processpptables.h"
diff --git a/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h
index 27f8d0e0e6a8..5ce433e2c16a 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h
+++ b/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h
@@ -809,6 +809,8 @@ struct pp_hwmgr {
uint32_t workload_prority[Workload_Policy_Max];
uint32_t workload_setting[Workload_Policy_Max];
bool gfxoff_state_changed_by_workload;
+ uint32_t pstate_sclk_peak;
+ uint32_t pstate_mclk_peak;
};
int hwmgr_early_init(struct pp_hwmgr *hwmgr);
diff --git a/drivers/gpu/drm/amd/pm/powerplay/inc/smu11_driver_if.h b/drivers/gpu/drm/amd/pm/powerplay/inc/smu11_driver_if.h
index fdc6b7a57bc9..c2efc70ef288 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/inc/smu11_driver_if.h
+++ b/drivers/gpu/drm/amd/pm/powerplay/inc/smu11_driver_if.h
@@ -358,6 +358,7 @@ typedef struct {
QuadraticInt_t SsCurve;
} DpmDescriptor_t;
+#pragma pack(push, 1)
typedef struct {
uint32_t Version;
@@ -609,6 +610,7 @@ typedef struct {
uint32_t MmHubPadding[8];
} PPTable_t;
+#pragma pack(pop)
typedef struct {
diff --git a/drivers/gpu/drm/amd/pm/powerplay/inc/smu9_driver_if.h b/drivers/gpu/drm/amd/pm/powerplay/inc/smu9_driver_if.h
index 2818c98ff5ca..faae4b918d90 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/inc/smu9_driver_if.h
+++ b/drivers/gpu/drm/amd/pm/powerplay/inc/smu9_driver_if.h
@@ -122,6 +122,7 @@ typedef struct {
uint16_t Vid; /* min voltage in SVI2 VID */
} DisplayClockTable_t;
+#pragma pack(push, 1)
typedef struct {
/* PowerTune */
uint16_t SocketPowerLimit; /* Watts */
@@ -323,6 +324,7 @@ typedef struct {
uint32_t MmHubPadding[3]; /* SMU internal use */
} PPTable_t;
+#pragma pack(pop)
typedef struct {
uint16_t MinClock; // This is either DCEFCLK or SOCCLK (in MHz)
diff --git a/drivers/gpu/drm/amd/pm/powerplay/inc/vega12/smu9_driver_if.h b/drivers/gpu/drm/amd/pm/powerplay/inc/vega12/smu9_driver_if.h
index b6ffd08784e7..6456bea5d2d5 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/inc/vega12/smu9_driver_if.h
+++ b/drivers/gpu/drm/amd/pm/powerplay/inc/vega12/smu9_driver_if.h
@@ -245,6 +245,7 @@ typedef struct {
QuadraticInt_t SsCurve;
} DpmDescriptor_t;
+#pragma pack(push, 1)
typedef struct {
uint32_t Version;
@@ -508,6 +509,7 @@ typedef struct {
uint32_t MmHubPadding[7];
} PPTable_t;
+#pragma pack(pop)
typedef struct {
diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c
index 5ca3c422f7d4..4bc8db1be738 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c
@@ -22,7 +22,6 @@
*/
#include <linux/module.h>
#include <linux/slab.h>
-#include <linux/fb.h>
#include "linux/delay.h"
#include <linux/types.h>
#include <linux/pci.h>
@@ -2203,7 +2202,7 @@ static int ci_program_mem_timing_parameters(struct pp_hwmgr *hwmgr)
struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
if (data->need_update_smu7_dpm_table &
- (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_OD_UPDATE_MCLK))
+ (DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_OD_UPDATE_MCLK))
return ci_program_memory_timing_parameters(hwmgr);
return 0;
diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/iceland_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/iceland_smumgr.c
index 03df35dee8ba..060fc140c574 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/iceland_smumgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/iceland_smumgr.c
@@ -2165,7 +2165,7 @@ static int iceland_program_mem_timing_parameters(struct pp_hwmgr *hwmgr)
struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
if (data->need_update_smu7_dpm_table &
- (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_OD_UPDATE_MCLK))
+ (DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_OD_UPDATE_MCLK))
return iceland_program_memory_timing_parameters(hwmgr);
return 0;
diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu10_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu10_smumgr.c
index 88a5641465dc..7eeab84d421a 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu10_smumgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/smu10_smumgr.c
@@ -250,9 +250,8 @@ static int smu10_smu_init(struct pp_hwmgr *hwmgr)
/* allocate space for watermarks table */
r = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev,
- sizeof(Watermarks_t),
- PAGE_SIZE,
- AMDGPU_GEM_DOMAIN_VRAM,
+ sizeof(Watermarks_t), PAGE_SIZE,
+ AMDGPU_GEM_DOMAIN_VRAM | AMDGPU_GEM_DOMAIN_GTT,
&priv->smu_tables.entry[SMU10_WMTABLE].handle,
&priv->smu_tables.entry[SMU10_WMTABLE].mc_addr,
&priv->smu_tables.entry[SMU10_WMTABLE].table);
@@ -266,9 +265,8 @@ static int smu10_smu_init(struct pp_hwmgr *hwmgr)
/* allocate space for watermarks table */
r = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev,
- sizeof(DpmClocks_t),
- PAGE_SIZE,
- AMDGPU_GEM_DOMAIN_VRAM,
+ sizeof(DpmClocks_t), PAGE_SIZE,
+ AMDGPU_GEM_DOMAIN_VRAM | AMDGPU_GEM_DOMAIN_GTT,
&priv->smu_tables.entry[SMU10_CLOCKTABLE].handle,
&priv->smu_tables.entry[SMU10_CLOCKTABLE].mc_addr,
&priv->smu_tables.entry[SMU10_CLOCKTABLE].table);
diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/tonga_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/tonga_smumgr.c
index 04b561f5d932..acbe41174d7e 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/tonga_smumgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/tonga_smumgr.c
@@ -2554,7 +2554,7 @@ static int tonga_program_mem_timing_parameters(struct pp_hwmgr *hwmgr)
struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
if (data->need_update_smu7_dpm_table &
- (DPMTABLE_OD_UPDATE_SCLK + DPMTABLE_OD_UPDATE_MCLK))
+ (DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_OD_UPDATE_MCLK))
return tonga_program_memory_timing_parameters(hwmgr);
return 0;
diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
index 6ab155023592..0652b001ad54 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
@@ -623,6 +623,7 @@ static int smu_early_init(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
struct smu_context *smu;
+ int r;
smu = kzalloc(sizeof(struct smu_context), GFP_KERNEL);
if (!smu)
@@ -640,7 +641,10 @@ static int smu_early_init(void *handle)
adev->powerplay.pp_handle = smu;
adev->powerplay.pp_funcs = &swsmu_pm_funcs;
- return smu_set_funcs(adev);
+ r = smu_set_funcs(adev);
+ if (r)
+ return r;
+ return smu_init_microcode(smu);
}
static int smu_set_default_dpm_table(struct smu_context *smu)
@@ -900,9 +904,8 @@ static int smu_alloc_dummy_read_table(struct smu_context *smu)
struct amdgpu_device *adev = smu->adev;
int ret = 0;
- dummy_read_1_table->size = 0x40000;
- dummy_read_1_table->align = PAGE_SIZE;
- dummy_read_1_table->domain = AMDGPU_GEM_DOMAIN_VRAM;
+ if (!dummy_read_1_table->size)
+ return 0;
ret = amdgpu_bo_create_kernel(adev,
dummy_read_1_table->size,
@@ -1067,12 +1070,6 @@ static int smu_sw_init(void *handle)
smu->smu_dpm.dpm_level = AMD_DPM_FORCED_LEVEL_AUTO;
smu->smu_dpm.requested_dpm_level = AMD_DPM_FORCED_LEVEL_AUTO;
- ret = smu_init_microcode(smu);
- if (ret) {
- dev_err(adev->dev, "Failed to load smu firmware!\n");
- return ret;
- }
-
ret = smu_smc_table_sw_init(smu);
if (ret) {
dev_err(adev->dev, "Failed to sw init smc table!\n");
@@ -1205,10 +1202,17 @@ static int smu_smc_hw_setup(struct smu_context *smu)
return ret;
}
- ret = smu_setup_pptable(smu);
- if (ret) {
- dev_err(adev->dev, "Failed to setup pptable!\n");
- return ret;
+ /*
+ * It is assumed the pptable used before runpm is same as
+ * the one used afterwards. Thus, we can reuse the stored
+ * copy and do not need to resetup the pptable again.
+ */
+ if (!adev->in_runpm) {
+ ret = smu_setup_pptable(smu);
+ if (ret) {
+ dev_err(adev->dev, "Failed to setup pptable!\n");
+ return ret;
+ }
}
/* smu_dump_pptable(smu); */
@@ -2487,6 +2491,14 @@ static int smu_read_sensor(void *handle,
*((uint32_t *)data) = pstate_table->uclk_pstate.standard * 100;
*size = 4;
break;
+ case AMDGPU_PP_SENSOR_PEAK_PSTATE_SCLK:
+ *((uint32_t *)data) = pstate_table->gfxclk_pstate.peak * 100;
+ *size = 4;
+ break;
+ case AMDGPU_PP_SENSOR_PEAK_PSTATE_MCLK:
+ *((uint32_t *)data) = pstate_table->uclk_pstate.peak * 100;
+ *size = 4;
+ break;
case AMDGPU_PP_SENSOR_ENABLED_SMC_FEATURES_MASK:
ret = smu_feature_get_enabled_mask(smu, (uint64_t *)data);
*size = 8;
@@ -2853,6 +2865,23 @@ static int smu_mode2_reset(void *handle)
return ret;
}
+static int smu_enable_gfx_features(void *handle)
+{
+ struct smu_context *smu = handle;
+ int ret = 0;
+
+ if (!smu->pm_enabled)
+ return -EOPNOTSUPP;
+
+ if (smu->ppt_funcs->enable_gfx_features)
+ ret = smu->ppt_funcs->enable_gfx_features(smu);
+
+ if (ret)
+ dev_err(smu->adev->dev, "enable gfx features failed!\n");
+
+ return ret;
+}
+
static int smu_get_max_sustainable_clocks_by_dc(void *handle,
struct pp_smu_nv_clock_table *max_clocks)
{
@@ -3037,6 +3066,7 @@ static const struct amd_pm_funcs swsmu_pm_funcs = {
.get_ppfeature_status = smu_sys_get_pp_feature_mask,
.set_ppfeature_status = smu_sys_set_pp_feature_mask,
.asic_reset_mode_2 = smu_mode2_reset,
+ .asic_reset_enable_gfx_features = smu_enable_gfx_features,
.set_df_cstate = smu_set_df_cstate,
.set_xgmi_pstate = smu_set_xgmi_pstate,
.get_gpu_metrics = smu_sys_get_gpu_metrics,
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
index 3bc4128a22ac..2a03d85bf4e2 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
@@ -1201,6 +1201,8 @@ struct pptable_funcs {
* IPs reset varies by asic.
*/
int (*mode2_reset)(struct smu_context *smu);
+ /* for gfx feature enablement after mode2 reset */
+ int (*enable_gfx_features)(struct smu_context *smu);
/**
* @get_dpm_ultimate_freq: Get the hard frequency range of a clock
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu11_driver_if_arcturus.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu11_driver_if_arcturus.h
index 43d43d6addc0..d518dee18e1b 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu11_driver_if_arcturus.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu11_driver_if_arcturus.h
@@ -464,6 +464,7 @@ typedef struct {
uint16_t Padding16;
} DpmDescriptor_t;
+#pragma pack(push, 1)
typedef struct {
uint32_t Version;
@@ -733,6 +734,7 @@ typedef struct {
uint32_t MmHubPadding[8]; // SMU internal use
} PPTable_t;
+#pragma pack(pop)
typedef struct {
// Time constant parameters for clock averages in ms
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu11_driver_if_navi10.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu11_driver_if_navi10.h
index 04752ade1016..c5c1943fb6a1 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu11_driver_if_navi10.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu11_driver_if_navi10.h
@@ -515,6 +515,7 @@ typedef struct {
uint32_t BoardLevelEnergyAccumulator;
} OutOfBandMonitor_t;
+#pragma pack(push, 1)
typedef struct {
uint32_t Version;
@@ -814,6 +815,7 @@ typedef struct {
uint32_t MmHubPadding[8]; // SMU internal use
} PPTable_t;
+#pragma pack(pop)
typedef struct {
// Time constant parameters for clock averages in ms
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu11_driver_if_sienna_cichlid.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu11_driver_if_sienna_cichlid.h
index 351a4af429b3..aa6d29de4002 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu11_driver_if_sienna_cichlid.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu11_driver_if_sienna_cichlid.h
@@ -599,6 +599,7 @@ typedef struct {
uint16_t Fmax;
} UclkDpmChangeRange_t;
+#pragma pack(push, 1)
typedef struct {
// MAJOR SECTION: SKU PARAMETERS
@@ -957,6 +958,7 @@ typedef struct {
uint32_t MmHubPadding[8]; // SMU internal use
} PPTable_t;
+#pragma pack(pop)
typedef struct {
// MAJOR SECTION: SKU PARAMETERS
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_aldebaran.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_aldebaran.h
index 7a6075daa7b2..90200f31ff52 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_aldebaran.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_aldebaran.h
@@ -267,6 +267,7 @@ typedef struct {
QuadraticInt_t SsCurve; // Slow-slow curve (GHz->V)
} DpmDescriptor_t;
+#pragma pack(push, 1)
typedef struct {
uint32_t Version;
@@ -448,6 +449,7 @@ typedef struct {
uint32_t reserved[14];
} PPTable_t;
+#pragma pack(pop)
typedef struct {
// Time constant parameters for clock averages in ms
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_0.h
index 4bc7aee4d44f..b686fb68a6e7 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_0.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_0.h
@@ -1347,10 +1347,12 @@ typedef struct {
uint32_t MmHubPadding[8];
} BoardTable_t;
+#pragma pack(push, 1)
typedef struct {
SkuTable_t SkuTable;
BoardTable_t BoardTable;
} PPTable_t;
+#pragma pack(pop)
typedef struct {
// Time constant parameters for clock averages in ms
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_7.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_7.h
index 48a3a3952ceb..4c46a0392451 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_7.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_7.h
@@ -1380,10 +1380,12 @@ typedef struct {
uint32_t MmHubPadding[8];
} BoardTable_t;
+#pragma pack(push, 1)
typedef struct {
SkuTable_t SkuTable;
BoardTable_t BoardTable;
} PPTable_t;
+#pragma pack(pop)
typedef struct {
// Time constant parameters for clock averages in ms
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_0_ppsmc.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_0_ppsmc.h
index 8b8266890a10..10cff75b44d5 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_0_ppsmc.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_0_ppsmc.h
@@ -94,6 +94,7 @@
//Resets
#define PPSMC_MSG_PrepareMp1ForUnload 0x2E
#define PPSMC_MSG_Mode1Reset 0x2F
+#define PPSMC_MSG_Mode2Reset 0x4F
//Set SystemVirtual DramAddrHigh
#define PPSMC_MSG_SetSystemVirtualDramAddrHigh 0x30
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h
index 4180c71d930f..96f6c2db955b 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h
@@ -242,7 +242,8 @@
__SMU_DUMMY_MAP(LogGfxOffResidency), \
__SMU_DUMMY_MAP(SetNumBadMemoryPagesRetired), \
__SMU_DUMMY_MAP(SetBadMemoryPagesRetiredFlagsPerChannel), \
- __SMU_DUMMY_MAP(AllowGpo),
+ __SMU_DUMMY_MAP(AllowGpo), \
+ __SMU_DUMMY_MAP(Mode2Reset),
#undef __SMU_DUMMY_MAP
#define __SMU_DUMMY_MAP(type) SMU_MSG_##type
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h
index 992163e66f7b..1c0ae2cb757b 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h
@@ -244,11 +244,6 @@ int smu_v13_0_set_single_dpm_table(struct smu_context *smu,
enum smu_clk_type clk_type,
struct smu_13_0_dpm_table *single_dpm_table);
-int smu_v13_0_get_dpm_level_range(struct smu_context *smu,
- enum smu_clk_type clk_type,
- uint32_t *min_value,
- uint32_t *max_value);
-
int smu_v13_0_get_current_pcie_link_width_level(struct smu_context *smu);
int smu_v13_0_get_current_pcie_link_width(struct smu_context *smu);
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
index 0bcd4fe0ef17..95da6dd1cc65 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
@@ -494,6 +494,8 @@ static int navi10_tables_init(struct smu_context *smu)
{
struct smu_table_context *smu_table = &smu->smu_table;
struct smu_table *tables = smu_table->tables;
+ struct smu_table *dummy_read_1_table =
+ &smu_table->dummy_read_1_table;
SMU_TABLE_INIT(tables, SMU_TABLE_PPTABLE, sizeof(PPTable_t),
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
@@ -513,6 +515,10 @@ static int navi10_tables_init(struct smu_context *smu)
SMU_TABLE_INIT(tables, SMU_TABLE_DRIVER_SMU_CONFIG, sizeof(DriverSmuConfig_t),
PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
+ dummy_read_1_table->size = 0x40000;
+ dummy_read_1_table->align = PAGE_SIZE;
+ dummy_read_1_table->domain = AMDGPU_GEM_DOMAIN_VRAM;
+
smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_NV1X_t),
GFP_KERNEL);
if (!smu_table->metrics_table)
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c
index ad66d57aa102..e1ef88ee1ed3 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c
@@ -93,7 +93,7 @@ static void smu_v11_0_poll_baco_exit(struct smu_context *smu)
int smu_v11_0_init_microcode(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
- const char *chip_name;
+ char ucode_prefix[30];
char fw_name[SMU_FW_NAME_LEN];
int err = 0;
const struct smc_firmware_header_v1_0 *hdr;
@@ -105,43 +105,11 @@ int smu_v11_0_init_microcode(struct smu_context *smu)
(adev->ip_versions[MP1_HWIP][0] == IP_VERSION(11, 0, 7))))
return 0;
- switch (adev->ip_versions[MP1_HWIP][0]) {
- case IP_VERSION(11, 0, 0):
- chip_name = "navi10";
- break;
- case IP_VERSION(11, 0, 5):
- chip_name = "navi14";
- break;
- case IP_VERSION(11, 0, 9):
- chip_name = "navi12";
- break;
- case IP_VERSION(11, 0, 7):
- chip_name = "sienna_cichlid";
- break;
- case IP_VERSION(11, 0, 11):
- chip_name = "navy_flounder";
- break;
- case IP_VERSION(11, 0, 12):
- chip_name = "dimgrey_cavefish";
- break;
- case IP_VERSION(11, 0, 13):
- chip_name = "beige_goby";
- break;
- case IP_VERSION(11, 0, 2):
- chip_name = "arcturus";
- break;
- default:
- dev_err(adev->dev, "Unsupported IP version 0x%x\n",
- adev->ip_versions[MP1_HWIP][0]);
- return -EINVAL;
- }
+ amdgpu_ucode_ip_version_decode(adev, MP1_HWIP, ucode_prefix, sizeof(ucode_prefix));
- snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_smc.bin", chip_name);
+ snprintf(fw_name, sizeof(fw_name), "amdgpu/%s.bin", ucode_prefix);
- err = request_firmware(&adev->pm.fw, fw_name, adev->dev);
- if (err)
- goto out;
- err = amdgpu_ucode_validate(adev->pm.fw);
+ err = amdgpu_ucode_request(adev, &adev->pm.fw, fw_name);
if (err)
goto out;
@@ -159,12 +127,8 @@ int smu_v11_0_init_microcode(struct smu_context *smu)
}
out:
- if (err) {
- DRM_ERROR("smu_v11_0: Failed to load firmware \"%s\"\n",
- fw_name);
- release_firmware(adev->pm.fw);
- adev->pm.fw = NULL;
- }
+ if (err)
+ amdgpu_ucode_release(&adev->pm.fw);
return err;
}
@@ -172,8 +136,7 @@ void smu_v11_0_fini_microcode(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
- release_firmware(adev->pm.fw);
- adev->pm.fw = NULL;
+ amdgpu_ucode_release(&adev->pm.fw);
adev->pm.fw_version = 0;
}
@@ -293,7 +256,7 @@ int smu_v11_0_check_fw_version(struct smu_context *smu)
* to be backward compatible.
* 2. New fw usually brings some optimizations. But that's visible
* only on the paired driver.
- * Considering above, we just leave user a warning message instead
+ * Considering above, we just leave user a verbal message instead
* of halt driver loading.
*/
if (if_version != smu->smc_driver_if_version) {
@@ -301,7 +264,7 @@ int smu_v11_0_check_fw_version(struct smu_context *smu)
"smu fw program = %d, version = 0x%08x (%d.%d.%d)\n",
smu->smc_driver_if_version, if_version,
smu_program, smu_version, smu_major, smu_minor, smu_debug);
- dev_warn(smu->adev->dev, "SMU driver if version not matched\n");
+ dev_info(smu->adev->dev, "SMU driver if version not matched\n");
}
return ret;
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c
index 56a02bc60cee..c788aa7a99a9 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c
@@ -93,7 +93,7 @@ int smu_v12_0_check_fw_version(struct smu_context *smu)
* to be backward compatible.
* 2. New fw usually brings some optimizations. But that's visible
* only on the paired driver.
- * Considering above, we just leave user a warning message instead
+ * Considering above, we just leave user a verbal message instead
* of halt driver loading.
*/
if (if_version != smu->smc_driver_if_version) {
@@ -101,7 +101,7 @@ int smu_v12_0_check_fw_version(struct smu_context *smu)
"smu fw program = %d, smu fw version = 0x%08x (%d.%d.%d)\n",
smu->smc_driver_if_version, if_version,
smu_program, smu_version, smu_major, smu_minor, smu_debug);
- dev_warn(smu->adev->dev, "SMU driver if version not matched\n");
+ dev_info(smu->adev->dev, "SMU driver if version not matched\n");
}
return ret;
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c
index b4373b6568ae..a52ed0580fd7 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c
@@ -88,7 +88,6 @@ static const int link_speed[] = {25, 50, 80, 160};
int smu_v13_0_init_microcode(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
- const char *chip_name;
char fw_name[30];
char ucode_prefix[30];
int err = 0;
@@ -100,21 +99,11 @@ int smu_v13_0_init_microcode(struct smu_context *smu)
if (amdgpu_sriov_vf(adev))
return 0;
- switch (adev->ip_versions[MP1_HWIP][0]) {
- case IP_VERSION(13, 0, 2):
- chip_name = "aldebaran_smc";
- break;
- default:
- amdgpu_ucode_ip_version_decode(adev, MP1_HWIP, ucode_prefix, sizeof(ucode_prefix));
- chip_name = ucode_prefix;
- }
+ amdgpu_ucode_ip_version_decode(adev, MP1_HWIP, ucode_prefix, sizeof(ucode_prefix));
- snprintf(fw_name, sizeof(fw_name), "amdgpu/%s.bin", chip_name);
+ snprintf(fw_name, sizeof(fw_name), "amdgpu/%s.bin", ucode_prefix);
- err = request_firmware(&adev->pm.fw, fw_name, adev->dev);
- if (err)
- goto out;
- err = amdgpu_ucode_validate(adev->pm.fw);
+ err = amdgpu_ucode_request(adev, &adev->pm.fw, fw_name);
if (err)
goto out;
@@ -132,12 +121,8 @@ int smu_v13_0_init_microcode(struct smu_context *smu)
}
out:
- if (err) {
- DRM_ERROR("smu_v13_0: Failed to load firmware \"%s\"\n",
- fw_name);
- release_firmware(adev->pm.fw);
- adev->pm.fw = NULL;
- }
+ if (err)
+ amdgpu_ucode_release(&adev->pm.fw);
return err;
}
@@ -145,8 +130,7 @@ void smu_v13_0_fini_microcode(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
- release_firmware(adev->pm.fw);
- adev->pm.fw = NULL;
+ amdgpu_ucode_release(&adev->pm.fw);
adev->pm.fw_version = 0;
}
@@ -327,7 +311,7 @@ int smu_v13_0_check_fw_version(struct smu_context *smu)
* to be backward compatible.
* 2. New fw usually brings some optimizations. But that's visible
* only on the paired driver.
- * Considering above, we just leave user a warning message instead
+ * Considering above, we just leave user a verbal message instead
* of halt driver loading.
*/
if (if_version != smu->smc_driver_if_version) {
@@ -335,7 +319,7 @@ int smu_v13_0_check_fw_version(struct smu_context *smu)
"smu fw program = %d, smu fw version = 0x%08x (%d.%d.%d)\n",
smu->smc_driver_if_version, if_version,
smu_program, smu_version, smu_major, smu_minor, smu_debug);
- dev_warn(adev->dev, "SMU driver if version not matched\n");
+ dev_info(adev->dev, "SMU driver if version not matched\n");
}
return ret;
@@ -2064,45 +2048,6 @@ int smu_v13_0_set_single_dpm_table(struct smu_context *smu,
return 0;
}
-int smu_v13_0_get_dpm_level_range(struct smu_context *smu,
- enum smu_clk_type clk_type,
- uint32_t *min_value,
- uint32_t *max_value)
-{
- uint32_t level_count = 0;
- int ret = 0;
-
- if (!min_value && !max_value)
- return -EINVAL;
-
- if (min_value) {
- /* by default, level 0 clock value as min value */
- ret = smu_v13_0_get_dpm_freq_by_index(smu,
- clk_type,
- 0,
- min_value);
- if (ret)
- return ret;
- }
-
- if (max_value) {
- ret = smu_v13_0_get_dpm_level_count(smu,
- clk_type,
- &level_count);
- if (ret)
- return ret;
-
- ret = smu_v13_0_get_dpm_freq_by_index(smu,
- clk_type,
- level_count - 1,
- max_value);
- if (ret)
- return ret;
- }
-
- return ret;
-}
-
int smu_v13_0_get_current_pcie_link_width_level(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
@@ -2284,10 +2229,23 @@ int smu_v13_0_gfx_ulv_control(struct smu_context *smu,
int smu_v13_0_baco_set_armd3_sequence(struct smu_context *smu,
enum smu_baco_seq baco_seq)
{
- return smu_cmn_send_smc_msg_with_param(smu,
- SMU_MSG_ArmD3,
- baco_seq,
- NULL);
+ struct smu_baco_context *smu_baco = &smu->smu_baco;
+ int ret;
+
+ ret = smu_cmn_send_smc_msg_with_param(smu,
+ SMU_MSG_ArmD3,
+ baco_seq,
+ NULL);
+ if (ret)
+ return ret;
+
+ if (baco_seq == BACO_SEQ_BAMACO ||
+ baco_seq == BACO_SEQ_BACO)
+ smu_baco->state = SMU_BACO_STATE_ENTER;
+ else
+ smu_baco->state = SMU_BACO_STATE_EXIT;
+
+ return 0;
}
bool smu_v13_0_baco_is_support(struct smu_context *smu)
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
index 508e392547d7..923a9fb3c887 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
@@ -138,6 +138,7 @@ static struct cmn2asic_msg_mapping smu_v13_0_0_message_map[SMU_MSG_MAX_COUNT] =
MSG_MAP(GetPptLimit, PPSMC_MSG_GetPptLimit, 0),
MSG_MAP(NotifyPowerSource, PPSMC_MSG_NotifyPowerSource, 0),
MSG_MAP(Mode1Reset, PPSMC_MSG_Mode1Reset, 0),
+ MSG_MAP(Mode2Reset, PPSMC_MSG_Mode2Reset, 0),
MSG_MAP(PrepareMp1ForUnload, PPSMC_MSG_PrepareMp1ForUnload, 0),
MSG_MAP(DFCstateControl, PPSMC_MSG_SetExternalClientDfCstateAllow, 0),
MSG_MAP(ArmD3, PPSMC_MSG_ArmD3, 0),
@@ -146,6 +147,7 @@ static struct cmn2asic_msg_mapping smu_v13_0_0_message_map[SMU_MSG_MAX_COUNT] =
PPSMC_MSG_SetBadMemoryPagesRetiredFlagsPerChannel, 0),
MSG_MAP(AllowGpo, PPSMC_MSG_SetGpoAllow, 0),
MSG_MAP(AllowIHHostInterrupt, PPSMC_MSG_AllowIHHostInterrupt, 0),
+ MSG_MAP(ReenableAcDcInterrupt, PPSMC_MSG_ReenableAcDcInterrupt, 0),
};
static struct cmn2asic_mapping smu_v13_0_0_clk_map[SMU_CLK_COUNT] = {
@@ -242,6 +244,7 @@ static struct cmn2asic_mapping smu_v13_0_0_workload_map[PP_SMC_POWER_PROFILE_COU
WORKLOAD_MAP(PP_SMC_POWER_PROFILE_VR, WORKLOAD_PPLIB_VR_BIT),
WORKLOAD_MAP(PP_SMC_POWER_PROFILE_COMPUTE, WORKLOAD_PPLIB_COMPUTE_BIT),
WORKLOAD_MAP(PP_SMC_POWER_PROFILE_CUSTOM, WORKLOAD_PPLIB_CUSTOM_BIT),
+ WORKLOAD_MAP(PP_SMC_POWER_PROFILE_WINDOW3D, WORKLOAD_PPLIB_WINDOW_3D_BIT),
};
static const uint8_t smu_v13_0_0_throttler_map[] = {
@@ -1563,7 +1566,7 @@ static int smu_v13_0_0_get_power_profile_mode(struct smu_context *smu,
title[0], title[1], title[2], title[3], title[4], title[5],
title[6], title[7], title[8], title[9]);
- for (i = 0; i <= PP_SMC_POWER_PROFILE_CUSTOM; i++) {
+ for (i = 0; i < PP_SMC_POWER_PROFILE_COUNT; i++) {
/* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
workload_type = smu_cmn_to_asic_specific_index(smu,
CMN2ASIC_MAPPING_WORKLOAD,
@@ -1625,7 +1628,7 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
smu->power_profile_mode = input[size];
- if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
+ if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) {
dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
return -EINVAL;
}
@@ -1910,15 +1913,51 @@ static int smu_v13_0_0_set_df_cstate(struct smu_context *smu,
NULL);
}
+static void smu_v13_0_0_set_mode1_reset_param(struct smu_context *smu,
+ uint32_t supported_version,
+ uint32_t *param)
+{
+ uint32_t smu_version;
+ struct amdgpu_device *adev = smu->adev;
+ struct amdgpu_ras *ras = amdgpu_ras_get_context(adev);
+
+ smu_cmn_get_smc_version(smu, NULL, &smu_version);
+
+ if ((smu_version >= supported_version) &&
+ ras && atomic_read(&ras->in_recovery))
+ /* Set RAS fatal error reset flag */
+ *param = 1 << 16;
+ else
+ *param = 0;
+}
+
static int smu_v13_0_0_mode1_reset(struct smu_context *smu)
{
int ret;
+ uint32_t param;
struct amdgpu_device *adev = smu->adev;
- if (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 10))
- ret = smu_cmn_send_debug_smc_msg(smu, DEBUGSMC_MSG_Mode1Reset);
- else
+ switch (adev->ip_versions[MP1_HWIP][0]) {
+ case IP_VERSION(13, 0, 0):
+ /* SMU 13_0_0 PMFW supports RAS fatal error reset from 78.77 */
+ smu_v13_0_0_set_mode1_reset_param(smu, 0x004e4d00, &param);
+
+ ret = smu_cmn_send_smc_msg_with_param(smu,
+ SMU_MSG_Mode1Reset, param, NULL);
+ break;
+
+ case IP_VERSION(13, 0, 10):
+ /* SMU 13_0_10 PMFW supports RAS fatal error reset from 80.28 */
+ smu_v13_0_0_set_mode1_reset_param(smu, 0x00501c00, &param);
+
+ ret = smu_cmn_send_debug_smc_msg_with_param(smu,
+ DEBUGSMC_MSG_Mode1Reset, param);
+ break;
+
+ default:
ret = smu_cmn_send_smc_msg(smu, SMU_MSG_Mode1Reset, NULL);
+ break;
+ }
if (!ret)
msleep(SMU13_MODE1_RESET_WAIT_TIME_IN_MS);
@@ -1926,6 +1965,30 @@ static int smu_v13_0_0_mode1_reset(struct smu_context *smu)
return ret;
}
+static int smu_v13_0_0_mode2_reset(struct smu_context *smu)
+{
+ int ret;
+ struct amdgpu_device *adev = smu->adev;
+
+ if (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 10))
+ ret = smu_cmn_send_smc_msg(smu, SMU_MSG_Mode2Reset, NULL);
+ else
+ return -EOPNOTSUPP;
+
+ return ret;
+}
+
+static int smu_v13_0_0_enable_gfx_features(struct smu_context *smu)
+{
+ struct amdgpu_device *adev = smu->adev;
+
+ if (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 10))
+ return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_EnableAllSmuFeatures,
+ FEATURE_PWR_GFX, NULL);
+ else
+ return -EOPNOTSUPP;
+}
+
static void smu_v13_0_0_set_smu_mailbox_registers(struct smu_context *smu)
{
struct amdgpu_device *adev = smu->adev;
@@ -2041,6 +2104,8 @@ static const struct pptable_funcs smu_v13_0_0_ppt_funcs = {
.baco_exit = smu_v13_0_0_baco_exit,
.mode1_reset_is_support = smu_v13_0_0_is_mode1_reset_supported,
.mode1_reset = smu_v13_0_0_mode1_reset,
+ .mode2_reset = smu_v13_0_0_mode2_reset,
+ .enable_gfx_features = smu_v13_0_0_enable_gfx_features,
.set_mp1_state = smu_v13_0_0_set_mp1_state,
.set_df_cstate = smu_v13_0_0_set_df_cstate,
.send_hbm_bad_pages_num = smu_v13_0_0_smu_send_bad_mem_page_num,
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
index 768b6e7dbd77..d5abafc5a682 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
@@ -404,6 +404,12 @@ int smu_cmn_send_debug_smc_msg(struct smu_context *smu,
return __smu_cmn_send_debug_msg(smu, msg, 0);
}
+int smu_cmn_send_debug_smc_msg_with_param(struct smu_context *smu,
+ uint32_t msg, uint32_t param)
+{
+ return __smu_cmn_send_debug_msg(smu, msg, param);
+}
+
int smu_cmn_to_asic_specific_index(struct smu_context *smu,
enum smu_cmn2asic_mapping_type type,
uint32_t index)
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
index f82cf76dd3a4..d7cd358a53bd 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
@@ -45,6 +45,9 @@ int smu_cmn_send_smc_msg(struct smu_context *smu,
int smu_cmn_send_debug_smc_msg(struct smu_context *smu,
uint32_t msg);
+int smu_cmn_send_debug_smc_msg_with_param(struct smu_context *smu,
+ uint32_t msg, uint32_t param);
+
int smu_cmn_wait_for_response(struct smu_context *smu);
int smu_cmn_to_asic_specific_index(struct smu_context *smu,
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
index 4cc07d6bb9d8..cea3fd5772b5 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
@@ -10,7 +10,6 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_print.h>
#include <drm/drm_vblank.h>
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
index 3f4e719eebd8..28f76e07dd95 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
@@ -6,6 +6,7 @@
*/
#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/component.h>
#include <linux/pm_runtime.h>
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.h b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
index 7339339ef6b8..3a872c292091 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
@@ -11,7 +11,6 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_blend.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_device.h>
#include <drm/drm_writeback.h>
#include <drm/drm_print.h>
diff --git a/drivers/gpu/drm/arm/hdlcd_drv.c b/drivers/gpu/drm/arm/hdlcd_drv.c
index 7043d1c9ed8f..e3507dd6f82a 100644
--- a/drivers/gpu/drm/arm/hdlcd_drv.c
+++ b/drivers/gpu/drm/arm/hdlcd_drv.c
@@ -195,8 +195,8 @@ static int hdlcd_setup_mode_config(struct drm_device *drm)
#ifdef CONFIG_DEBUG_FS
static int hdlcd_show_underrun_count(struct seq_file *m, void *arg)
{
- struct drm_info_node *node = (struct drm_info_node *)m->private;
- struct drm_device *drm = node->minor->dev;
+ struct drm_debugfs_entry *entry = m->private;
+ struct drm_device *drm = entry->dev;
struct hdlcd_drm_private *hdlcd = drm_to_hdlcd_priv(drm);
seq_printf(m, "underrun : %d\n", atomic_read(&hdlcd->buffer_underrun_count));
@@ -208,8 +208,8 @@ static int hdlcd_show_underrun_count(struct seq_file *m, void *arg)
static int hdlcd_show_pxlclock(struct seq_file *m, void *arg)
{
- struct drm_info_node *node = (struct drm_info_node *)m->private;
- struct drm_device *drm = node->minor->dev;
+ struct drm_debugfs_entry *entry = m->private;
+ struct drm_device *drm = entry->dev;
struct hdlcd_drm_private *hdlcd = drm_to_hdlcd_priv(drm);
unsigned long clkrate = clk_get_rate(hdlcd->clk);
unsigned long mode_clock = hdlcd->crtc.mode.crtc_clock * 1000;
@@ -219,17 +219,10 @@ static int hdlcd_show_pxlclock(struct seq_file *m, void *arg)
return 0;
}
-static struct drm_info_list hdlcd_debugfs_list[] = {
+static struct drm_debugfs_info hdlcd_debugfs_list[] = {
{ "interrupt_count", hdlcd_show_underrun_count, 0 },
{ "clocks", hdlcd_show_pxlclock, 0 },
};
-
-static void hdlcd_debugfs_init(struct drm_minor *minor)
-{
- drm_debugfs_create_files(hdlcd_debugfs_list,
- ARRAY_SIZE(hdlcd_debugfs_list),
- minor->debugfs_root, minor);
-}
#endif
DEFINE_DRM_GEM_DMA_FOPS(fops);
@@ -237,9 +230,6 @@ DEFINE_DRM_GEM_DMA_FOPS(fops);
static const struct drm_driver hdlcd_driver = {
.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
DRM_GEM_DMA_DRIVER_OPS,
-#ifdef CONFIG_DEBUG_FS
- .debugfs_init = hdlcd_debugfs_init,
-#endif
.fops = &fops,
.name = "hdlcd",
.desc = "ARM HDLCD Controller DRM",
@@ -303,6 +293,10 @@ static int hdlcd_drm_bind(struct device *dev)
drm_mode_config_reset(drm);
drm_kms_helper_poll_init(drm);
+#ifdef CONFIG_DEBUG_FS
+ drm_debugfs_add_files(drm, hdlcd_debugfs_list, ARRAY_SIZE(hdlcd_debugfs_list));
+#endif
+
ret = drm_dev_register(drm, 0);
if (ret)
goto err_register;
diff --git a/drivers/gpu/drm/armada/armada_fbdev.c b/drivers/gpu/drm/armada/armada_fbdev.c
index 584cee123bd8..0e44f53e9fa4 100644
--- a/drivers/gpu/drm/armada/armada_fbdev.c
+++ b/drivers/gpu/drm/armada/armada_fbdev.c
@@ -129,7 +129,7 @@ int armada_fbdev_init(struct drm_device *dev)
priv->fbdev = fbh;
- drm_fb_helper_prepare(dev, fbh, &armada_fb_helper_funcs);
+ drm_fb_helper_prepare(dev, fbh, 32, &armada_fb_helper_funcs);
ret = drm_fb_helper_init(dev, fbh);
if (ret) {
@@ -137,7 +137,7 @@ int armada_fbdev_init(struct drm_device *dev)
goto err_fb_helper;
}
- ret = drm_fb_helper_initial_config(fbh, 32);
+ ret = drm_fb_helper_initial_config(fbh);
if (ret) {
DRM_ERROR("failed to set initial config\n");
goto err_fb_setup;
@@ -147,6 +147,7 @@ int armada_fbdev_init(struct drm_device *dev)
err_fb_setup:
drm_fb_helper_fini(fbh);
err_fb_helper:
+ drm_fb_helper_unprepare(fbh);
priv->fbdev = NULL;
return ret;
}
@@ -164,6 +165,8 @@ void armada_fbdev_fini(struct drm_device *dev)
if (fbh->fb)
fbh->fb->funcs->destroy(fbh->fb);
+ drm_fb_helper_unprepare(fbh);
+
priv->fbdev = NULL;
}
}
diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c b/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c
index 55a3444a51d8..7877a57b8e26 100644
--- a/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c
+++ b/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c
@@ -5,7 +5,6 @@
#include <linux/reset.h>
#include <linux/regmap.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_device.h>
#include <drm/drm_fb_dma_helper.h>
#include <drm/drm_fourcc.h>
diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c
index 718119e168a6..ecfb060d2557 100644
--- a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c
+++ b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c
@@ -14,7 +14,6 @@
#include <linux/reset.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_device.h>
#include <drm/drm_fbdev_generic.h>
#include <drm/drm_gem_dma_helper.h>
diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx_out.c b/drivers/gpu/drm/aspeed/aspeed_gfx_out.c
index 4f2187025a21..78775e0c853f 100644
--- a/drivers/gpu/drm/aspeed/aspeed_gfx_out.c
+++ b/drivers/gpu/drm/aspeed/aspeed_gfx_out.c
@@ -3,7 +3,6 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_connector.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_probe_helper.h>
diff --git a/drivers/gpu/drm/ast/Kconfig b/drivers/gpu/drm/ast/Kconfig
index d367a90cd3de..563fa7a3b546 100644
--- a/drivers/gpu/drm/ast/Kconfig
+++ b/drivers/gpu/drm/ast/Kconfig
@@ -4,6 +4,8 @@ config DRM_AST
depends on DRM && PCI && MMU
select DRM_GEM_SHMEM_HELPER
select DRM_KMS_HELPER
+ select I2C
+ select I2C_ALGOBIT
help
Say yes for experimental AST GPU driver. Do not enable
this driver without having a working -modesetting,
diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c
index 420fc75c240e..d78852c7cf5b 100644
--- a/drivers/gpu/drm/ast/ast_drv.c
+++ b/drivers/gpu/drm/ast/ast_drv.c
@@ -31,7 +31,6 @@
#include <drm/drm_aperture.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_fbdev_generic.h>
#include <drm/drm_gem_shmem_helper.h>
diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c
index bffa310a0431..f83ce77127cb 100644
--- a/drivers/gpu/drm/ast/ast_main.c
+++ b/drivers/gpu/drm/ast/ast_main.c
@@ -29,7 +29,6 @@
#include <linux/pci.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_gem.h>
#include <drm/drm_managed.h>
diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
index 66a4a41c3fe9..984ec590a7e7 100644
--- a/drivers/gpu/drm/ast/ast_mode.c
+++ b/drivers/gpu/drm/ast/ast_mode.c
@@ -35,7 +35,6 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_atomic_state_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_damage_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_format_helper.h>
@@ -636,7 +635,7 @@ static void ast_handle_damage(struct ast_plane *ast_plane, struct iosys_map *src
struct drm_framebuffer *fb,
const struct drm_rect *clip)
{
- struct iosys_map dst = IOSYS_MAP_INIT_VADDR(ast_plane->vaddr);
+ struct iosys_map dst = IOSYS_MAP_INIT_VADDR_IOMEM(ast_plane->vaddr);
iosys_map_incr(&dst, drm_fb_clip_offset(fb->pitches[0], fb->format, clip));
drm_fb_memcpy(&dst, fb->pitches, src, fb, clip);
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
index a2bb5b916235..4e806b06d35d 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
@@ -784,7 +784,6 @@ static int atmel_hlcdc_dc_drm_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
static int atmel_hlcdc_dc_drm_suspend(struct device *dev)
{
struct drm_device *drm_dev = dev_get_drvdata(dev);
@@ -815,10 +814,10 @@ static int atmel_hlcdc_dc_drm_resume(struct device *dev)
return drm_atomic_helper_resume(drm_dev, dc->suspend.state);
}
-#endif
-static SIMPLE_DEV_PM_OPS(atmel_hlcdc_dc_drm_pm_ops,
- atmel_hlcdc_dc_drm_suspend, atmel_hlcdc_dc_drm_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(atmel_hlcdc_dc_drm_pm_ops,
+ atmel_hlcdc_dc_drm_suspend,
+ atmel_hlcdc_dc_drm_resume);
static const struct of_device_id atmel_hlcdc_dc_of_match[] = {
{ .compatible = "atmel,hlcdc-display-controller" },
@@ -830,7 +829,7 @@ static struct platform_driver atmel_hlcdc_dc_platform_driver = {
.remove = atmel_hlcdc_dc_drm_remove,
.driver = {
.name = "atmel-hlcdc-display-controller",
- .pm = &atmel_hlcdc_dc_drm_pm_ops,
+ .pm = pm_sleep_ptr(&atmel_hlcdc_dc_drm_pm_ops),
.of_match_table = atmel_hlcdc_dc_of_match,
},
};
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 57946d80b02d..8b2226f72b24 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -15,17 +15,6 @@ config DRM_PANEL_BRIDGE
menu "Display Interface Bridges"
depends on DRM && DRM_BRIDGE
-config DRM_CDNS_DSI
- tristate "Cadence DPI/DSI bridge"
- select DRM_KMS_HELPER
- select DRM_MIPI_DSI
- select DRM_PANEL_BRIDGE
- select GENERIC_PHY_MIPI_DPHY
- depends on OF
- help
- Support Cadence DPI to DSI bridge. This is an internal
- bridge and is meant to be directly embedded in a SoC.
-
config DRM_CHIPONE_ICN6211
tristate "Chipone ICN6211 MIPI-DSI/RGB Converter bridge"
depends on OF
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index 1884803c6860..52f6e8b4a821 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -1,5 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_DRM_CDNS_DSI) += cdns-dsi.o
obj-$(CONFIG_DRM_CHIPONE_ICN6211) += chipone-icn6211.o
obj-$(CONFIG_DRM_CHRONTEL_CH7033) += chrontel-ch7033.o
obj-$(CONFIG_DRM_CROS_EC_ANX7688) += cros-ec-anx7688.o
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
index e7a6e456ed0d..ddceafa7b637 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
@@ -1185,8 +1185,9 @@ static int adv7511_parse_dt(struct device_node *np,
return 0;
}
-static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
+static int adv7511_probe(struct i2c_client *i2c)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(i2c);
struct adv7511_link_config link_config;
struct adv7511 *adv7511;
struct device *dev = &i2c->dev;
@@ -1392,7 +1393,7 @@ static struct i2c_driver adv7511_driver = {
.of_match_table = adv7511_of_ids,
},
.id_table = adv7511_i2c_ids,
- .probe = adv7511_probe,
+ .probe_new = adv7511_probe,
.remove = adv7511_remove,
};
diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c
index 660a54857929..3577c532abb4 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c
@@ -22,7 +22,6 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
@@ -692,8 +691,7 @@ static bool anx6345_get_chip_id(struct anx6345 *anx6345)
return false;
}
-static int anx6345_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int anx6345_i2c_probe(struct i2c_client *client)
{
struct anx6345 *anx6345;
struct device *dev;
@@ -817,7 +815,7 @@ static struct i2c_driver anx6345_driver = {
.name = "anx6345",
.of_match_table = of_match_ptr(anx6345_match_table),
},
- .probe = anx6345_i2c_probe,
+ .probe_new = anx6345_i2c_probe,
.remove = anx6345_i2c_remove,
.id_table = anx6345_id,
};
diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c
index 5997049fde5b..a3a38bbe2786 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c
@@ -1214,8 +1214,7 @@ static const u16 anx78xx_chipid_list[] = {
0x7818,
};
-static int anx78xx_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int anx78xx_i2c_probe(struct i2c_client *client)
{
struct anx78xx *anx78xx;
struct anx78xx_platform_data *pdata;
@@ -1390,7 +1389,7 @@ static struct i2c_driver anx78xx_driver = {
.name = "anx7814",
.of_match_table = of_match_ptr(anx78xx_match_table),
},
- .probe = anx78xx_i2c_probe,
+ .probe_new = anx78xx_i2c_probe,
.remove = anx78xx_i2c_remove,
.id_table = anx78xx_id,
};
diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c
index b0ff1ecb80a5..6846199a2ee1 100644
--- a/drivers/gpu/drm/bridge/analogix/anx7625.c
+++ b/drivers/gpu/drm/bridge/analogix/anx7625.c
@@ -26,7 +26,6 @@
#include <drm/display/drm_hdcp_helper.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_of.h>
@@ -1403,7 +1402,6 @@ static void anx7625_stop_dp_work(struct anx7625_data *ctx)
{
ctx->hpd_status = 0;
ctx->hpd_high_cnt = 0;
- ctx->display_timing_valid = 0;
}
static void anx7625_start_dp_work(struct anx7625_data *ctx)
@@ -2562,8 +2560,7 @@ static void anx7625_runtime_disable(void *data)
pm_runtime_disable(data);
}
-static int anx7625_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int anx7625_i2c_probe(struct i2c_client *client)
{
struct anx7625_data *platform;
struct anx7625_platform_data *pdata;
@@ -2756,7 +2753,7 @@ static struct i2c_driver anx7625_driver = {
.of_match_table = anx_match_table,
.pm = &anx7625_pm_ops,
},
- .probe = anx7625_i2c_probe,
+ .probe_new = anx7625_i2c_probe,
.remove = anx7625_i2c_remove,
.id_table = anx7625_id,
diff --git a/drivers/gpu/drm/bridge/cadence/Kconfig b/drivers/gpu/drm/bridge/cadence/Kconfig
index 1d06182bea71..ec35215a2003 100644
--- a/drivers/gpu/drm/bridge/cadence/Kconfig
+++ b/drivers/gpu/drm/bridge/cadence/Kconfig
@@ -1,4 +1,25 @@
# SPDX-License-Identifier: GPL-2.0-only
+config DRM_CDNS_DSI
+ tristate "Cadence DPI/DSI bridge"
+ select DRM_KMS_HELPER
+ select DRM_MIPI_DSI
+ select DRM_PANEL_BRIDGE
+ select GENERIC_PHY_MIPI_DPHY
+ depends on OF
+ help
+ Support Cadence DPI to DSI bridge. This is an internal
+ bridge and is meant to be directly embedded in a SoC.
+
+if DRM_CDNS_DSI
+
+config DRM_CDNS_DSI_J721E
+ bool "J721E Cadence DSI wrapper support"
+ default y
+ help
+ Support J721E Cadence DSI wrapper. The wrapper manages
+ the routing of the DSS DPI signal to the Cadence DSI.
+endif
+
config DRM_CDNS_MHDP8546
tristate "Cadence DPI/DP bridge"
select DRM_DISPLAY_DP_HELPER
diff --git a/drivers/gpu/drm/bridge/cadence/Makefile b/drivers/gpu/drm/bridge/cadence/Makefile
index 4d2db8df1bc6..c95fd5b81d13 100644
--- a/drivers/gpu/drm/bridge/cadence/Makefile
+++ b/drivers/gpu/drm/bridge/cadence/Makefile
@@ -1,4 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_DRM_CDNS_DSI) += cdns-dsi.o
+cdns-dsi-y := cdns-dsi-core.o
+cdns-dsi-$(CONFIG_DRM_CDNS_DSI_J721E) += cdns-dsi-j721e.o
obj-$(CONFIG_DRM_CDNS_MHDP8546) += cdns-mhdp8546.o
cdns-mhdp8546-y := cdns-mhdp8546-core.o cdns-mhdp8546-hdcp.o
cdns-mhdp8546-$(CONFIG_DRM_CDNS_MHDP8546_J721E) += cdns-mhdp8546-j721e.o
diff --git a/drivers/gpu/drm/bridge/cdns-dsi.c b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
index 20bece84ff8c..5dbfc7226b31 100644
--- a/drivers/gpu/drm/bridge/cdns-dsi.c
+++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
@@ -6,10 +6,7 @@
*/
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_bridge.h>
#include <drm/drm_drv.h>
-#include <drm/drm_mipi_dsi.h>
-#include <drm/drm_panel.h>
#include <drm/drm_probe_helper.h>
#include <video/mipi_display.h>
@@ -18,14 +15,19 @@
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/of_address.h>
+#include <linux/of_device.h>
#include <linux/of_graph.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
-#include <linux/phy/phy.h>
#include <linux/phy/phy-mipi-dphy.h>
+#include "cdns-dsi-core.h"
+#ifdef CONFIG_DRM_CDNS_DSI_J721E
+#include "cdns-dsi-j721e.h"
+#endif
+
#define IP_CONF 0x0
#define SP_HS_FIFO_DEPTH(x) (((x) & GENMASK(30, 26)) >> 26)
#define SP_LP_FIFO_DEPTH(x) (((x) & GENMASK(25, 21)) >> 21)
@@ -424,48 +426,6 @@
#define DSI_NULL_FRAME_OVERHEAD 6
#define DSI_EOT_PKT_SIZE 4
-struct cdns_dsi_output {
- struct mipi_dsi_device *dev;
- struct drm_panel *panel;
- struct drm_bridge *bridge;
- union phy_configure_opts phy_opts;
-};
-
-enum cdns_dsi_input_id {
- CDNS_SDI_INPUT,
- CDNS_DPI_INPUT,
- CDNS_DSC_INPUT,
-};
-
-struct cdns_dsi_cfg {
- unsigned int hfp;
- unsigned int hsa;
- unsigned int hbp;
- unsigned int hact;
- unsigned int htotal;
-};
-
-struct cdns_dsi_input {
- enum cdns_dsi_input_id id;
- struct drm_bridge bridge;
-};
-
-struct cdns_dsi {
- struct mipi_dsi_host base;
- void __iomem *regs;
- struct cdns_dsi_input input;
- struct cdns_dsi_output output;
- unsigned int direct_cmd_fifo_depth;
- unsigned int rx_fifo_depth;
- struct completion direct_cmd_comp;
- struct clk *dsi_p_clk;
- struct reset_control *dsi_p_rst;
- struct clk *dsi_sys_clk;
- bool link_initialized;
- bool phy_initialized;
- struct phy *dphy;
-};
-
static inline struct cdns_dsi *input_to_dsi(struct cdns_dsi_input *input)
{
return container_of(input, struct cdns_dsi, input);
@@ -709,6 +669,10 @@ static void cdns_dsi_bridge_disable(struct drm_bridge *bridge)
val = readl(dsi->regs + MCTL_MAIN_EN) & ~IF_EN(input->id);
writel(val, dsi->regs + MCTL_MAIN_EN);
+
+ if (dsi->platform_ops && dsi->platform_ops->disable)
+ dsi->platform_ops->disable(dsi);
+
pm_runtime_put(dsi->base.dev);
}
@@ -804,6 +768,9 @@ static void cdns_dsi_bridge_enable(struct drm_bridge *bridge)
if (WARN_ON(pm_runtime_get_sync(dsi->base.dev) < 0))
return;
+ if (dsi->platform_ops && dsi->platform_ops->enable)
+ dsi->platform_ops->enable(dsi);
+
mode = &bridge->encoder->crtc->state->adjusted_mode;
nlanes = output->dev->lanes;
@@ -1244,6 +1211,8 @@ static int cdns_dsi_drm_probe(struct platform_device *pdev)
goto err_disable_pclk;
}
+ dsi->platform_ops = of_device_get_match_data(&pdev->dev);
+
val = readl(dsi->regs + IP_CONF);
dsi->direct_cmd_fifo_depth = 1 << (DIRCMD_FIFO_DEPTH(val) + 2);
dsi->rx_fifo_depth = RX_FIFO_DEPTH(val);
@@ -1279,14 +1248,27 @@ static int cdns_dsi_drm_probe(struct platform_device *pdev)
dsi->base.dev = &pdev->dev;
dsi->base.ops = &cdns_dsi_ops;
+ if (dsi->platform_ops && dsi->platform_ops->init) {
+ ret = dsi->platform_ops->init(dsi);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "platform initialization failed: %d\n",
+ ret);
+ goto err_disable_runtime_pm;
+ }
+ }
+
ret = mipi_dsi_host_register(&dsi->base);
if (ret)
- goto err_disable_runtime_pm;
+ goto err_deinit_platform;
clk_disable_unprepare(dsi->dsi_p_clk);
return 0;
+err_deinit_platform:
+ if (dsi->platform_ops && dsi->platform_ops->deinit)
+ dsi->platform_ops->deinit(dsi);
+
err_disable_runtime_pm:
pm_runtime_disable(&pdev->dev);
@@ -1301,6 +1283,10 @@ static int cdns_dsi_drm_remove(struct platform_device *pdev)
struct cdns_dsi *dsi = platform_get_drvdata(pdev);
mipi_dsi_host_unregister(&dsi->base);
+
+ if (dsi->platform_ops && dsi->platform_ops->deinit)
+ dsi->platform_ops->deinit(dsi);
+
pm_runtime_disable(&pdev->dev);
return 0;
@@ -1308,6 +1294,9 @@ static int cdns_dsi_drm_remove(struct platform_device *pdev)
static const struct of_device_id cdns_dsi_of_match[] = {
{ .compatible = "cdns,dsi" },
+#ifdef CONFIG_DRM_CDNS_DSI_J721E
+ { .compatible = "ti,j721e-dsi", .data = &dsi_ti_j721e_ops, },
+#endif
{ },
};
MODULE_DEVICE_TABLE(of, cdns_dsi_of_match);
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.h b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.h
new file mode 100644
index 000000000000..ca7ea2da635c
--- /dev/null
+++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.h
@@ -0,0 +1,84 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright: 2017 Cadence Design Systems, Inc.
+ *
+ * Author: Boris Brezillon <boris.brezillon@bootlin.com>
+ */
+
+#ifndef __CDNS_DSI_H__
+#define __CDNS_DSI_H__
+
+#include <drm/drm_bridge.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_panel.h>
+
+#include <linux/bits.h>
+#include <linux/completion.h>
+#include <linux/phy/phy.h>
+
+struct clk;
+struct reset_control;
+
+struct cdns_dsi_output {
+ struct mipi_dsi_device *dev;
+ struct drm_panel *panel;
+ struct drm_bridge *bridge;
+ union phy_configure_opts phy_opts;
+};
+
+enum cdns_dsi_input_id {
+ CDNS_SDI_INPUT,
+ CDNS_DPI_INPUT,
+ CDNS_DSC_INPUT,
+};
+
+struct cdns_dsi_cfg {
+ unsigned int hfp;
+ unsigned int hsa;
+ unsigned int hbp;
+ unsigned int hact;
+ unsigned int htotal;
+};
+
+struct cdns_dsi_input {
+ enum cdns_dsi_input_id id;
+ struct drm_bridge bridge;
+};
+
+struct cdns_dsi;
+
+/**
+ * struct cdns_dsi_platform_ops - CDNS DSI Platform operations
+ * @init: Called in the CDNS DSI probe
+ * @deinit: Called in the CDNS DSI remove
+ * @enable: Called at the beginning of CDNS DSI bridge enable
+ * @disable: Called at the end of CDNS DSI bridge disable
+ */
+struct cdns_dsi_platform_ops {
+ int (*init)(struct cdns_dsi *dsi);
+ void (*deinit)(struct cdns_dsi *dsi);
+ void (*enable)(struct cdns_dsi *dsi);
+ void (*disable)(struct cdns_dsi *dsi);
+};
+
+struct cdns_dsi {
+ struct mipi_dsi_host base;
+ void __iomem *regs;
+#ifdef CONFIG_DRM_CDNS_DSI_J721E
+ void __iomem *j721e_regs;
+#endif
+ const struct cdns_dsi_platform_ops *platform_ops;
+ struct cdns_dsi_input input;
+ struct cdns_dsi_output output;
+ unsigned int direct_cmd_fifo_depth;
+ unsigned int rx_fifo_depth;
+ struct completion direct_cmd_comp;
+ struct clk *dsi_p_clk;
+ struct reset_control *dsi_p_rst;
+ struct clk *dsi_sys_clk;
+ bool link_initialized;
+ bool phy_initialized;
+ struct phy *dphy;
+};
+
+#endif /* !__CDNS_DSI_H__ */
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-j721e.c b/drivers/gpu/drm/bridge/cadence/cdns-dsi-j721e.c
new file mode 100644
index 000000000000..b654d4b3cb5c
--- /dev/null
+++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-j721e.c
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * TI j721e Cadence DSI wrapper
+ *
+ * Copyright (C) 2022 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Rahul T R <r-ravikumar@ti.com>
+ */
+
+#include <linux/io.h>
+#include <linux/platform_device.h>
+
+#include "cdns-dsi-j721e.h"
+
+#define DSI_WRAP_REVISION 0x0
+#define DSI_WRAP_DPI_CONTROL 0x4
+#define DSI_WRAP_DSC_CONTROL 0x8
+#define DSI_WRAP_DPI_SECURE 0xc
+#define DSI_WRAP_DSI_0_ASF_STATUS 0x10
+
+#define DSI_WRAP_DPI_0_EN BIT(0)
+#define DSI_WRAP_DSI2_MUX_SEL BIT(4)
+
+static int cdns_dsi_j721e_init(struct cdns_dsi *dsi)
+{
+ struct platform_device *pdev = to_platform_device(dsi->base.dev);
+
+ dsi->j721e_regs = devm_platform_ioremap_resource(pdev, 1);
+ return PTR_ERR_OR_ZERO(dsi->j721e_regs);
+}
+
+static void cdns_dsi_j721e_enable(struct cdns_dsi *dsi)
+{
+ /*
+ * Enable DPI0 as its input. DSS0 DPI2 is connected
+ * to DSI DPI0. This is the only supported configuration on
+ * J721E.
+ */
+ writel(DSI_WRAP_DPI_0_EN, dsi->j721e_regs + DSI_WRAP_DPI_CONTROL);
+}
+
+static void cdns_dsi_j721e_disable(struct cdns_dsi *dsi)
+{
+ /* Put everything to defaults */
+ writel(0, dsi->j721e_regs + DSI_WRAP_DPI_CONTROL);
+}
+
+const struct cdns_dsi_platform_ops dsi_ti_j721e_ops = {
+ .init = cdns_dsi_j721e_init,
+ .enable = cdns_dsi_j721e_enable,
+ .disable = cdns_dsi_j721e_disable,
+};
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-j721e.h b/drivers/gpu/drm/bridge/cadence/cdns-dsi-j721e.h
new file mode 100644
index 000000000000..275e5e8e7583
--- /dev/null
+++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-j721e.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * TI j721e Cadence DSI wrapper
+ *
+ * Copyright (C) 2022 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Rahul T R <r-ravikumar@ti.com>
+ */
+
+#ifndef __CDNS_DSI_J721E_H__
+#define __CDNS_DSI_J721E_H__
+
+#include "cdns-dsi-core.h"
+
+extern const struct cdns_dsi_platform_ops dsi_ti_j721e_ops;
+
+#endif /* !__CDNS_DSI_J721E_H__ */
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c
index 31442a922502..f6822dfa3805 100644
--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c
+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c
@@ -43,7 +43,6 @@
#include <drm/drm_atomic_state_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_connector.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_print.h>
diff --git a/drivers/gpu/drm/bridge/chipone-icn6211.c b/drivers/gpu/drm/bridge/chipone-icn6211.c
index bf920c3503aa..0e37840cd7a8 100644
--- a/drivers/gpu/drm/bridge/chipone-icn6211.c
+++ b/drivers/gpu/drm/bridge/chipone-icn6211.c
@@ -740,8 +740,7 @@ static int chipone_dsi_probe(struct mipi_dsi_device *dsi)
return ret;
}
-static int chipone_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int chipone_i2c_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct chipone *icn;
@@ -796,7 +795,7 @@ static struct i2c_device_id chipone_i2c_id[] = {
MODULE_DEVICE_TABLE(i2c, chipone_i2c_id);
static struct i2c_driver chipone_i2c_driver = {
- .probe = chipone_i2c_probe,
+ .probe_new = chipone_i2c_probe,
.id_table = chipone_i2c_id,
.driver = {
.name = "chipone-icn6211-i2c",
diff --git a/drivers/gpu/drm/bridge/chrontel-ch7033.c b/drivers/gpu/drm/bridge/chrontel-ch7033.c
index b94f39a86846..339b759e4c81 100644
--- a/drivers/gpu/drm/bridge/chrontel-ch7033.c
+++ b/drivers/gpu/drm/bridge/chrontel-ch7033.c
@@ -528,8 +528,7 @@ static const struct regmap_config ch7033_regmap_config = {
.max_register = 0x7f,
};
-static int ch7033_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ch7033_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct ch7033_priv *priv;
@@ -604,7 +603,7 @@ static const struct i2c_device_id ch7033_ids[] = {
MODULE_DEVICE_TABLE(i2c, ch7033_ids);
static struct i2c_driver ch7033_driver = {
- .probe = ch7033_probe,
+ .probe_new = ch7033_probe,
.remove = ch7033_remove,
.driver = {
.name = "ch7033",
diff --git a/drivers/gpu/drm/bridge/fsl-ldb.c b/drivers/gpu/drm/bridge/fsl-ldb.c
index f9e0f8d99268..6bac160b395b 100644
--- a/drivers/gpu/drm/bridge/fsl-ldb.c
+++ b/drivers/gpu/drm/bridge/fsl-ldb.c
@@ -18,7 +18,6 @@
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
-#define LDB_CTRL 0x5c
#define LDB_CTRL_CH0_ENABLE BIT(0)
#define LDB_CTRL_CH0_DI_SELECT BIT(1)
#define LDB_CTRL_CH1_ENABLE BIT(2)
@@ -35,9 +34,13 @@
#define LDB_CTRL_ASYNC_FIFO_ENABLE BIT(24)
#define LDB_CTRL_ASYNC_FIFO_THRESHOLD_MASK GENMASK(27, 25)
-#define LVDS_CTRL 0x128
#define LVDS_CTRL_CH0_EN BIT(0)
#define LVDS_CTRL_CH1_EN BIT(1)
+/*
+ * LVDS_CTRL_LVDS_EN bit is poorly named in i.MX93 reference manual.
+ * Clear it to enable LVDS and set it to disable LVDS.
+ */
+#define LVDS_CTRL_LVDS_EN BIT(1)
#define LVDS_CTRL_VBG_EN BIT(2)
#define LVDS_CTRL_HS_EN BIT(3)
#define LVDS_CTRL_PRE_EMPH_EN BIT(4)
@@ -52,6 +55,29 @@
#define LVDS_CTRL_VBG_ADJ(n) (((n) & 0x7) << 17)
#define LVDS_CTRL_VBG_ADJ_MASK GENMASK(19, 17)
+enum fsl_ldb_devtype {
+ IMX8MP_LDB,
+ IMX93_LDB,
+};
+
+struct fsl_ldb_devdata {
+ u32 ldb_ctrl;
+ u32 lvds_ctrl;
+ bool lvds_en_bit;
+};
+
+static const struct fsl_ldb_devdata fsl_ldb_devdata[] = {
+ [IMX8MP_LDB] = {
+ .ldb_ctrl = 0x5c,
+ .lvds_ctrl = 0x128,
+ },
+ [IMX93_LDB] = {
+ .ldb_ctrl = 0x20,
+ .lvds_ctrl = 0x24,
+ .lvds_en_bit = true,
+ },
+};
+
struct fsl_ldb {
struct device *dev;
struct drm_bridge bridge;
@@ -59,6 +85,7 @@ struct fsl_ldb {
struct clk *clk;
struct regmap *regmap;
bool lvds_dual_link;
+ const struct fsl_ldb_devdata *devdata;
};
static inline struct fsl_ldb *to_fsl_ldb(struct drm_bridge *bridge)
@@ -66,6 +93,14 @@ static inline struct fsl_ldb *to_fsl_ldb(struct drm_bridge *bridge)
return container_of(bridge, struct fsl_ldb, bridge);
}
+static unsigned long fsl_ldb_link_frequency(struct fsl_ldb *fsl_ldb, int clock)
+{
+ if (fsl_ldb->lvds_dual_link)
+ return clock * 3500;
+ else
+ return clock * 7000;
+}
+
static int fsl_ldb_attach(struct drm_bridge *bridge,
enum drm_bridge_attach_flags flags)
{
@@ -85,6 +120,8 @@ static void fsl_ldb_atomic_enable(struct drm_bridge *bridge,
const struct drm_display_mode *mode;
struct drm_connector *connector;
struct drm_crtc *crtc;
+ unsigned long configured_link_freq;
+ unsigned long requested_link_freq;
bool lvds_format_24bpp;
bool lvds_format_jeida;
u32 reg;
@@ -128,10 +165,15 @@ static void fsl_ldb_atomic_enable(struct drm_bridge *bridge,
crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
mode = &crtc_state->adjusted_mode;
- if (fsl_ldb->lvds_dual_link)
- clk_set_rate(fsl_ldb->clk, mode->clock * 3500);
- else
- clk_set_rate(fsl_ldb->clk, mode->clock * 7000);
+ requested_link_freq = fsl_ldb_link_frequency(fsl_ldb, mode->clock);
+ clk_set_rate(fsl_ldb->clk, requested_link_freq);
+
+ configured_link_freq = clk_get_rate(fsl_ldb->clk);
+ if (configured_link_freq != requested_link_freq)
+ dev_warn(fsl_ldb->dev, "Configured LDB clock (%lu Hz) does not match requested LVDS clock: %lu Hz",
+ configured_link_freq,
+ requested_link_freq);
+
clk_prepare_enable(fsl_ldb->clk);
/* Program LDB_CTRL */
@@ -158,12 +200,12 @@ static void fsl_ldb_atomic_enable(struct drm_bridge *bridge,
reg |= LDB_CTRL_DI1_VSYNC_POLARITY;
}
- regmap_write(fsl_ldb->regmap, LDB_CTRL, reg);
+ regmap_write(fsl_ldb->regmap, fsl_ldb->devdata->ldb_ctrl, reg);
/* Program LVDS_CTRL */
reg = LVDS_CTRL_CC_ADJ(2) | LVDS_CTRL_PRE_EMPH_EN |
LVDS_CTRL_PRE_EMPH_ADJ(3) | LVDS_CTRL_VBG_EN;
- regmap_write(fsl_ldb->regmap, LVDS_CTRL, reg);
+ regmap_write(fsl_ldb->regmap, fsl_ldb->devdata->lvds_ctrl, reg);
/* Wait for VBG to stabilize. */
usleep_range(15, 20);
@@ -172,7 +214,7 @@ static void fsl_ldb_atomic_enable(struct drm_bridge *bridge,
if (fsl_ldb->lvds_dual_link)
reg |= LVDS_CTRL_CH1_EN;
- regmap_write(fsl_ldb->regmap, LVDS_CTRL, reg);
+ regmap_write(fsl_ldb->regmap, fsl_ldb->devdata->lvds_ctrl, reg);
}
static void fsl_ldb_atomic_disable(struct drm_bridge *bridge,
@@ -180,9 +222,14 @@ static void fsl_ldb_atomic_disable(struct drm_bridge *bridge,
{
struct fsl_ldb *fsl_ldb = to_fsl_ldb(bridge);
- /* Stop both channels. */
- regmap_write(fsl_ldb->regmap, LVDS_CTRL, 0);
- regmap_write(fsl_ldb->regmap, LDB_CTRL, 0);
+ /* Stop channel(s). */
+ if (fsl_ldb->devdata->lvds_en_bit)
+ /* Set LVDS_CTRL_LVDS_EN bit to disable. */
+ regmap_write(fsl_ldb->regmap, fsl_ldb->devdata->lvds_ctrl,
+ LVDS_CTRL_LVDS_EN);
+ else
+ regmap_write(fsl_ldb->regmap, fsl_ldb->devdata->lvds_ctrl, 0);
+ regmap_write(fsl_ldb->regmap, fsl_ldb->devdata->ldb_ctrl, 0);
clk_disable_unprepare(fsl_ldb->clk);
}
@@ -248,6 +295,10 @@ static int fsl_ldb_probe(struct platform_device *pdev)
if (!fsl_ldb)
return -ENOMEM;
+ fsl_ldb->devdata = of_device_get_match_data(dev);
+ if (!fsl_ldb->devdata)
+ return -EINVAL;
+
fsl_ldb->dev = &pdev->dev;
fsl_ldb->bridge.funcs = &funcs;
fsl_ldb->bridge.of_node = dev->of_node;
@@ -306,7 +357,10 @@ static int fsl_ldb_remove(struct platform_device *pdev)
}
static const struct of_device_id fsl_ldb_match[] = {
- { .compatible = "fsl,imx8mp-ldb", },
+ { .compatible = "fsl,imx8mp-ldb",
+ .data = &fsl_ldb_devdata[IMX8MP_LDB], },
+ { .compatible = "fsl,imx93-ldb",
+ .data = &fsl_ldb_devdata[IMX93_LDB], },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, fsl_ldb_match);
diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/ite-it6505.c
index 21a9b8422bda..bc451b2a77c2 100644
--- a/drivers/gpu/drm/bridge/ite-it6505.c
+++ b/drivers/gpu/drm/bridge/ite-it6505.c
@@ -26,7 +26,6 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
@@ -412,7 +411,6 @@ struct it6505 {
* Mutex protects extcon and interrupt functions from interfering
* each other.
*/
- struct mutex irq_lock;
struct mutex extcon_lock;
struct mutex mode_lock; /* used to bridge_detect */
struct mutex aux_lock; /* used to aux data transfers */
@@ -438,6 +436,8 @@ struct it6505 {
bool powered;
bool hpd_state;
u32 afe_setting;
+ u32 max_dpi_pixel_clock;
+ u32 max_lane_count;
enum hdcp_state hdcp_status;
struct delayed_work hdcp_work;
struct work_struct hdcp_wait_ksv_list;
@@ -457,6 +457,8 @@ struct it6505 {
/* it6505 driver hold option */
bool enable_drv_hold;
+
+ struct edid *cached_edid;
};
struct it6505_step_train_para {
@@ -1463,7 +1465,8 @@ static void it6505_parse_link_capabilities(struct it6505 *it6505)
it6505->lane_count = link->num_lanes;
DRM_DEV_DEBUG_DRIVER(dev, "Sink support %d lanes training",
it6505->lane_count);
- it6505->lane_count = min_t(int, it6505->lane_count, MAX_LANE_COUNT);
+ it6505->lane_count = min_t(int, it6505->lane_count,
+ it6505->max_lane_count);
it6505->branch_device = drm_dp_is_branch(it6505->dpcd);
DRM_DEV_DEBUG_DRIVER(dev, "Sink %sbranch device",
@@ -2244,6 +2247,12 @@ static void it6505_plugged_status_to_codec(struct it6505 *it6505)
status == connector_status_connected);
}
+static void it6505_remove_edid(struct it6505 *it6505)
+{
+ kfree(it6505->cached_edid);
+ it6505->cached_edid = NULL;
+}
+
static int it6505_process_hpd_irq(struct it6505 *it6505)
{
struct device *dev = &it6505->client->dev;
@@ -2270,6 +2279,7 @@ static int it6505_process_hpd_irq(struct it6505 *it6505)
it6505_reset_logic(it6505);
it6505_int_mask_enable(it6505);
it6505_init(it6505);
+ it6505_remove_edid(it6505);
return 0;
}
@@ -2353,6 +2363,7 @@ static void it6505_irq_hpd(struct it6505 *it6505)
it6505_video_reset(it6505);
} else {
memset(it6505->dpcd, 0, sizeof(it6505->dpcd));
+ it6505_remove_edid(it6505);
if (it6505->hdcp_desired)
it6505_stop_hdcp(it6505);
@@ -2494,10 +2505,8 @@ static irqreturn_t it6505_int_threaded_handler(int unused, void *data)
};
int int_status[3], i;
- mutex_lock(&it6505->irq_lock);
-
- if (it6505->enable_drv_hold || !it6505->powered)
- goto unlock;
+ if (it6505->enable_drv_hold || pm_runtime_get_if_in_use(dev) <= 0)
+ return IRQ_HANDLED;
int_status[0] = it6505_read(it6505, INT_STATUS_01);
int_status[1] = it6505_read(it6505, INT_STATUS_02);
@@ -2515,16 +2524,14 @@ static irqreturn_t it6505_int_threaded_handler(int unused, void *data)
if (it6505_test_bit(irq_vec[0].bit, (unsigned int *)int_status))
irq_vec[0].handler(it6505);
- if (!it6505->hpd_state)
- goto unlock;
-
- for (i = 1; i < ARRAY_SIZE(irq_vec); i++) {
- if (it6505_test_bit(irq_vec[i].bit, (unsigned int *)int_status))
- irq_vec[i].handler(it6505);
+ if (it6505->hpd_state) {
+ for (i = 1; i < ARRAY_SIZE(irq_vec); i++) {
+ if (it6505_test_bit(irq_vec[i].bit, (unsigned int *)int_status))
+ irq_vec[i].handler(it6505);
+ }
}
-unlock:
- mutex_unlock(&it6505->irq_lock);
+ pm_runtime_put_sync(dev);
return IRQ_HANDLED;
}
@@ -2902,7 +2909,7 @@ it6505_bridge_mode_valid(struct drm_bridge *bridge,
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
return MODE_NO_INTERLACE;
- if (mode->clock > DPI_PIXEL_CLK_MAX)
+ if (mode->clock > it6505->max_dpi_pixel_clock)
return MODE_CLOCK_HIGH;
it6505->video_info.clock = mode->clock;
@@ -3016,16 +3023,18 @@ static struct edid *it6505_bridge_get_edid(struct drm_bridge *bridge,
{
struct it6505 *it6505 = bridge_to_it6505(bridge);
struct device *dev = &it6505->client->dev;
- struct edid *edid;
- edid = drm_do_get_edid(connector, it6505_get_edid_block, it6505);
+ if (!it6505->cached_edid) {
+ it6505->cached_edid = drm_do_get_edid(connector, it6505_get_edid_block,
+ it6505);
- if (!edid) {
- DRM_DEV_DEBUG_DRIVER(dev, "failed to get edid!");
- return NULL;
+ if (!it6505->cached_edid) {
+ DRM_DEV_DEBUG_DRIVER(dev, "failed to get edid!");
+ return NULL;
+ }
}
- return edid;
+ return drm_edid_duplicate(it6505->cached_edid);
}
static const struct drm_bridge_funcs it6505_bridge_funcs = {
@@ -3089,10 +3098,32 @@ static int it6505_init_pdata(struct it6505 *it6505)
return 0;
}
+static int it6505_get_data_lanes_count(const struct device_node *endpoint,
+ const unsigned int min,
+ const unsigned int max)
+{
+ int ret;
+
+ ret = of_property_count_u32_elems(endpoint, "data-lanes");
+ if (ret < 0)
+ return ret;
+
+ if (ret < min || ret > max)
+ return -EINVAL;
+
+ return ret;
+}
+
static void it6505_parse_dt(struct it6505 *it6505)
{
struct device *dev = &it6505->client->dev;
+ struct device_node *np = dev->of_node, *ep = NULL;
+ int len;
+ u64 link_frequencies;
+ u32 data_lanes[4];
u32 *afe_setting = &it6505->afe_setting;
+ u32 *max_lane_count = &it6505->max_lane_count;
+ u32 *max_dpi_pixel_clock = &it6505->max_dpi_pixel_clock;
it6505->lane_swap_disabled =
device_property_read_bool(dev, "no-laneswap");
@@ -3108,7 +3139,56 @@ static void it6505_parse_dt(struct it6505 *it6505)
} else {
*afe_setting = 0;
}
- DRM_DEV_DEBUG_DRIVER(dev, "using afe_setting: %d", *afe_setting);
+
+ ep = of_graph_get_endpoint_by_regs(np, 1, 0);
+ of_node_put(ep);
+
+ if (ep) {
+ len = it6505_get_data_lanes_count(ep, 1, 4);
+
+ if (len > 0 && len != 3) {
+ of_property_read_u32_array(ep, "data-lanes",
+ data_lanes, len);
+ *max_lane_count = len;
+ } else {
+ *max_lane_count = MAX_LANE_COUNT;
+ dev_err(dev, "error data-lanes, use default");
+ }
+ } else {
+ *max_lane_count = MAX_LANE_COUNT;
+ dev_err(dev, "error endpoint, use default");
+ }
+
+ ep = of_graph_get_endpoint_by_regs(np, 0, 0);
+ of_node_put(ep);
+
+ if (ep) {
+ len = of_property_read_variable_u64_array(ep,
+ "link-frequencies",
+ &link_frequencies, 0,
+ 1);
+ if (len >= 0) {
+ do_div(link_frequencies, 1000);
+ if (link_frequencies > 297000) {
+ dev_err(dev,
+ "max pixel clock error, use default");
+ *max_dpi_pixel_clock = DPI_PIXEL_CLK_MAX;
+ } else {
+ *max_dpi_pixel_clock = link_frequencies;
+ }
+ } else {
+ dev_err(dev, "error link frequencies, use default");
+ *max_dpi_pixel_clock = DPI_PIXEL_CLK_MAX;
+ }
+ } else {
+ dev_err(dev, "error endpoint, use default");
+ *max_dpi_pixel_clock = DPI_PIXEL_CLK_MAX;
+ }
+
+ DRM_DEV_DEBUG_DRIVER(dev, "using afe_setting: %u, max_lane_count: %u",
+ it6505->afe_setting, it6505->max_lane_count);
+ DRM_DEV_DEBUG_DRIVER(dev, "using max_dpi_pixel_clock: %u kHz",
+ it6505->max_dpi_pixel_clock);
}
static ssize_t receive_timing_debugfs_show(struct file *file, char __user *buf,
@@ -3265,8 +3345,7 @@ static void it6505_shutdown(struct i2c_client *client)
it6505_lane_off(it6505);
}
-static int it6505_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int it6505_i2c_probe(struct i2c_client *client)
{
struct it6505 *it6505;
struct device *dev = &client->dev;
@@ -3277,7 +3356,6 @@ static int it6505_i2c_probe(struct i2c_client *client,
if (!it6505)
return -ENOMEM;
- mutex_init(&it6505->irq_lock);
mutex_init(&it6505->extcon_lock);
mutex_init(&it6505->mode_lock);
mutex_init(&it6505->aux_lock);
@@ -3367,6 +3445,7 @@ static void it6505_i2c_remove(struct i2c_client *client)
drm_dp_aux_unregister(&it6505->aux);
it6505_debugfs_remove(it6505);
it6505_poweroff(it6505);
+ it6505_remove_edid(it6505);
}
static const struct i2c_device_id it6505_id[] = {
@@ -3387,7 +3466,7 @@ static struct i2c_driver it6505_i2c_driver = {
.of_match_table = it6505_of_match,
.pm = &it6505_bridge_pm_ops,
},
- .probe = it6505_i2c_probe,
+ .probe_new = it6505_i2c_probe,
.remove = it6505_i2c_remove,
.shutdown = it6505_shutdown,
.id_table = it6505_id,
diff --git a/drivers/gpu/drm/bridge/ite-it66121.c b/drivers/gpu/drm/bridge/ite-it66121.c
index 4f6f1deba28c..a2d723d6a4be 100644
--- a/drivers/gpu/drm/bridge/ite-it66121.c
+++ b/drivers/gpu/drm/bridge/ite-it66121.c
@@ -22,7 +22,6 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_modes.h>
#include <drm/drm_print.h>
@@ -35,10 +34,6 @@
#define IT66121_DEVICE_ID0_REG 0x02
#define IT66121_DEVICE_ID1_REG 0x03
-#define IT66121_VENDOR_ID0 0x54
-#define IT66121_VENDOR_ID1 0x49
-#define IT66121_DEVICE_ID0 0x12
-#define IT66121_DEVICE_ID1 0x06
#define IT66121_REVISION_MASK GENMASK(7, 4)
#define IT66121_DEVICE_ID1_MASK GENMASK(3, 0)
@@ -72,6 +67,7 @@
#define IT66121_AFE_XP_ENO BIT(4)
#define IT66121_AFE_XP_RESETB BIT(3)
#define IT66121_AFE_XP_PWDI BIT(2)
+#define IT6610_AFE_XP_BYPASS BIT(0)
#define IT66121_AFE_IP_REG 0x64
#define IT66121_AFE_IP_GAINBIT BIT(7)
@@ -286,13 +282,18 @@
#define IT66121_AUD_SWL_16BIT 0x2
#define IT66121_AUD_SWL_NOT_INDICATED 0x0
-#define IT66121_VENDOR_ID0 0x54
-#define IT66121_VENDOR_ID1 0x49
-#define IT66121_DEVICE_ID0 0x12
-#define IT66121_DEVICE_ID1 0x06
-#define IT66121_DEVICE_MASK 0x0F
#define IT66121_AFE_CLK_HIGH 80000 /* Khz */
+enum chip_id {
+ ID_IT6610,
+ ID_IT66121,
+};
+
+struct it66121_chip_info {
+ enum chip_id id;
+ u16 vid, pid;
+};
+
struct it66121_ctx {
struct regmap *regmap;
struct drm_bridge bridge;
@@ -301,7 +302,6 @@ struct it66121_ctx {
struct device *dev;
struct gpio_desc *gpio_reset;
struct i2c_client *client;
- struct regulator_bulk_data supplies[3];
u32 bus_width;
struct mutex lock; /* Protects fields below and device registers */
struct hdmi_avi_infoframe hdmi_avi_infoframe;
@@ -312,6 +312,7 @@ struct it66121_ctx {
u8 swl;
bool auto_cts;
} audio;
+ const struct it66121_chip_info *info;
};
static const struct regmap_range_cfg it66121_regmap_banks[] = {
@@ -342,16 +343,6 @@ static void it66121_hw_reset(struct it66121_ctx *ctx)
gpiod_set_value(ctx->gpio_reset, 0);
}
-static inline int ite66121_power_on(struct it66121_ctx *ctx)
-{
- return regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
-}
-
-static inline int ite66121_power_off(struct it66121_ctx *ctx)
-{
- return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
-}
-
static inline int it66121_preamble_ddc(struct it66121_ctx *ctx)
{
return regmap_write(ctx->regmap, IT66121_MASTER_SEL_REG, IT66121_MASTER_SEL_HOST);
@@ -406,16 +397,22 @@ static int it66121_configure_afe(struct it66121_ctx *ctx,
ret = regmap_write_bits(ctx->regmap, IT66121_AFE_IP_REG,
IT66121_AFE_IP_GAINBIT |
- IT66121_AFE_IP_ER0 |
- IT66121_AFE_IP_EC1,
+ IT66121_AFE_IP_ER0,
IT66121_AFE_IP_GAINBIT);
if (ret)
return ret;
- ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_EC1_REG,
- IT66121_AFE_XP_EC1_LOWCLK, 0x80);
- if (ret)
- return ret;
+ if (ctx->info->id == ID_IT66121) {
+ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_IP_REG,
+ IT66121_AFE_IP_EC1, 0);
+ if (ret)
+ return ret;
+
+ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_EC1_REG,
+ IT66121_AFE_XP_EC1_LOWCLK, 0x80);
+ if (ret)
+ return ret;
+ }
} else {
ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_REG,
IT66121_AFE_XP_GAINBIT |
@@ -426,17 +423,24 @@ static int it66121_configure_afe(struct it66121_ctx *ctx,
ret = regmap_write_bits(ctx->regmap, IT66121_AFE_IP_REG,
IT66121_AFE_IP_GAINBIT |
- IT66121_AFE_IP_ER0 |
- IT66121_AFE_IP_EC1, IT66121_AFE_IP_ER0 |
- IT66121_AFE_IP_EC1);
+ IT66121_AFE_IP_ER0,
+ IT66121_AFE_IP_ER0);
if (ret)
return ret;
- ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_EC1_REG,
- IT66121_AFE_XP_EC1_LOWCLK,
- IT66121_AFE_XP_EC1_LOWCLK);
- if (ret)
- return ret;
+ if (ctx->info->id == ID_IT66121) {
+ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_IP_REG,
+ IT66121_AFE_IP_EC1,
+ IT66121_AFE_IP_EC1);
+ if (ret)
+ return ret;
+
+ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_EC1_REG,
+ IT66121_AFE_XP_EC1_LOWCLK,
+ IT66121_AFE_XP_EC1_LOWCLK);
+ if (ret)
+ return ret;
+ }
}
/* Clear reset flags */
@@ -445,38 +449,36 @@ static int it66121_configure_afe(struct it66121_ctx *ctx,
if (ret)
return ret;
+ if (ctx->info->id == ID_IT6610) {
+ ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_REG,
+ IT6610_AFE_XP_BYPASS,
+ IT6610_AFE_XP_BYPASS);
+ if (ret)
+ return ret;
+ }
+
return it66121_fire_afe(ctx);
}
static inline int it66121_wait_ddc_ready(struct it66121_ctx *ctx)
{
int ret, val;
- u32 busy = IT66121_DDC_STATUS_NOACK | IT66121_DDC_STATUS_WAIT_BUS |
- IT66121_DDC_STATUS_ARBI_LOSE;
+ u32 error = IT66121_DDC_STATUS_NOACK | IT66121_DDC_STATUS_WAIT_BUS |
+ IT66121_DDC_STATUS_ARBI_LOSE;
+ u32 done = IT66121_DDC_STATUS_TX_DONE;
- ret = regmap_read_poll_timeout(ctx->regmap, IT66121_DDC_STATUS_REG, val, true,
- IT66121_EDID_SLEEP_US, IT66121_EDID_TIMEOUT_US);
+ ret = regmap_read_poll_timeout(ctx->regmap, IT66121_DDC_STATUS_REG, val,
+ val & (error | done), IT66121_EDID_SLEEP_US,
+ IT66121_EDID_TIMEOUT_US);
if (ret)
return ret;
- if (val & busy)
+ if (val & error)
return -EAGAIN;
return 0;
}
-static int it66121_clear_ddc_fifo(struct it66121_ctx *ctx)
-{
- int ret;
-
- ret = it66121_preamble_ddc(ctx);
- if (ret)
- return ret;
-
- return regmap_write(ctx->regmap, IT66121_DDC_COMMAND_REG,
- IT66121_DDC_COMMAND_FIFO_CLR);
-}
-
static int it66121_abort_ddc_ops(struct it66121_ctx *ctx)
{
int ret;
@@ -516,7 +518,6 @@ static int it66121_get_edid_block(void *context, u8 *buf,
unsigned int block, size_t len)
{
struct it66121_ctx *ctx = context;
- unsigned int val;
int remain = len;
int offset = 0;
int ret, cnt;
@@ -524,26 +525,9 @@ static int it66121_get_edid_block(void *context, u8 *buf,
offset = (block % 2) * len;
block = block / 2;
- ret = regmap_read(ctx->regmap, IT66121_INT_STATUS1_REG, &val);
- if (ret)
- return ret;
-
- if (val & IT66121_INT_STATUS1_DDC_BUSHANG) {
- ret = it66121_abort_ddc_ops(ctx);
- if (ret)
- return ret;
- }
-
- ret = it66121_clear_ddc_fifo(ctx);
- if (ret)
- return ret;
-
while (remain > 0) {
cnt = (remain > IT66121_EDID_FIFO_SIZE) ?
IT66121_EDID_FIFO_SIZE : remain;
- ret = it66121_preamble_ddc(ctx);
- if (ret)
- return ret;
ret = regmap_write(ctx->regmap, IT66121_DDC_COMMAND_REG,
IT66121_DDC_COMMAND_FIFO_CLR);
@@ -554,25 +538,6 @@ static int it66121_get_edid_block(void *context, u8 *buf,
if (ret)
return ret;
- ret = regmap_read(ctx->regmap, IT66121_INT_STATUS1_REG, &val);
- if (ret)
- return ret;
-
- if (val & IT66121_INT_STATUS1_DDC_BUSHANG) {
- ret = it66121_abort_ddc_ops(ctx);
- if (ret)
- return ret;
- }
-
- ret = it66121_preamble_ddc(ctx);
- if (ret)
- return ret;
-
- ret = regmap_write(ctx->regmap, IT66121_DDC_HEADER_REG,
- IT66121_DDC_HEADER_EDID);
- if (ret)
- return ret;
-
ret = regmap_write(ctx->regmap, IT66121_DDC_OFFSET_REG, offset);
if (ret)
return ret;
@@ -593,20 +558,18 @@ static int it66121_get_edid_block(void *context, u8 *buf,
offset += cnt;
remain -= cnt;
- /* Per programming manual, sleep here before emptying the FIFO */
- msleep(20);
-
ret = it66121_wait_ddc_ready(ctx);
+ if (ret) {
+ it66121_abort_ddc_ops(ctx);
+ return ret;
+ }
+
+ ret = regmap_noinc_read(ctx->regmap, IT66121_DDC_RD_FIFO_REG,
+ buf, cnt);
if (ret)
return ret;
- do {
- ret = regmap_read(ctx->regmap, IT66121_DDC_RD_FIFO_REG, &val);
- if (ret)
- return ret;
- *(buf++) = val;
- cnt--;
- } while (cnt > 0);
+ buf += cnt;
}
return 0;
@@ -635,10 +598,12 @@ static int it66121_bridge_attach(struct drm_bridge *bridge,
if (ret)
return ret;
- ret = regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG,
- IT66121_CLK_BANK_PWROFF_RCLK, 0);
- if (ret)
- return ret;
+ if (ctx->info->id == ID_IT66121) {
+ ret = regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG,
+ IT66121_CLK_BANK_PWROFF_RCLK, 0);
+ if (ret)
+ return ret;
+ }
ret = regmap_write_bits(ctx->regmap, IT66121_INT_REG,
IT66121_INT_TX_CLK_OFF, 0);
@@ -684,11 +649,7 @@ static int it66121_bridge_attach(struct drm_bridge *bridge,
/* Per programming manual, sleep here for bridge to settle */
msleep(50);
- /* Start interrupts */
- return regmap_write_bits(ctx->regmap, IT66121_INT_MASK1_REG,
- IT66121_INT_MASK1_DDC_NOACK |
- IT66121_INT_MASK1_DDC_FIFOERR |
- IT66121_INT_MASK1_DDC_BUSHANG, 0);
+ return 0;
}
static int it66121_set_mute(struct it66121_ctx *ctx, bool mute)
@@ -780,29 +741,32 @@ static void it66121_bridge_disable(struct drm_bridge *bridge,
ctx->connector = NULL;
}
+static int it66121_bridge_check(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
+{
+ struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, bridge);
+
+ if (ctx->info->id == ID_IT6610) {
+ /* The IT6610 only supports these settings */
+ bridge_state->input_bus_cfg.flags |= DRM_BUS_FLAG_DE_HIGH |
+ DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE;
+ bridge_state->input_bus_cfg.flags &=
+ ~DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE;
+ }
+
+ return 0;
+}
+
static
void it66121_bridge_mode_set(struct drm_bridge *bridge,
const struct drm_display_mode *mode,
const struct drm_display_mode *adjusted_mode)
{
- int ret, i;
u8 buf[HDMI_INFOFRAME_SIZE(AVI)];
struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, bridge);
- const u16 aviinfo_reg[HDMI_AVI_INFOFRAME_SIZE] = {
- IT66121_AVIINFO_DB1_REG,
- IT66121_AVIINFO_DB2_REG,
- IT66121_AVIINFO_DB3_REG,
- IT66121_AVIINFO_DB4_REG,
- IT66121_AVIINFO_DB5_REG,
- IT66121_AVIINFO_DB6_REG,
- IT66121_AVIINFO_DB7_REG,
- IT66121_AVIINFO_DB8_REG,
- IT66121_AVIINFO_DB9_REG,
- IT66121_AVIINFO_DB10_REG,
- IT66121_AVIINFO_DB11_REG,
- IT66121_AVIINFO_DB12_REG,
- IT66121_AVIINFO_DB13_REG
- };
+ int ret;
mutex_lock(&ctx->lock);
@@ -822,10 +786,12 @@ void it66121_bridge_mode_set(struct drm_bridge *bridge,
}
/* Write new AVI infoframe packet */
- for (i = 0; i < HDMI_AVI_INFOFRAME_SIZE; i++) {
- if (regmap_write(ctx->regmap, aviinfo_reg[i], buf[i + HDMI_INFOFRAME_HEADER_SIZE]))
- goto unlock;
- }
+ ret = regmap_bulk_write(ctx->regmap, IT66121_AVIINFO_DB1_REG,
+ &buf[HDMI_INFOFRAME_HEADER_SIZE],
+ HDMI_AVI_INFOFRAME_SIZE);
+ if (ret)
+ goto unlock;
+
if (regmap_write(ctx->regmap, IT66121_AVIINFO_CSUM_REG, buf[3]))
goto unlock;
@@ -838,9 +804,12 @@ void it66121_bridge_mode_set(struct drm_bridge *bridge,
if (regmap_write(ctx->regmap, IT66121_HDMI_MODE_REG, IT66121_HDMI_MODE_HDMI))
goto unlock;
- if (regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG,
- IT66121_CLK_BANK_PWROFF_TXCLK, IT66121_CLK_BANK_PWROFF_TXCLK))
+ if (ctx->info->id == ID_IT66121 &&
+ regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG,
+ IT66121_CLK_BANK_PWROFF_TXCLK,
+ IT66121_CLK_BANK_PWROFF_TXCLK)) {
goto unlock;
+ }
if (it66121_configure_input(ctx))
goto unlock;
@@ -848,7 +817,11 @@ void it66121_bridge_mode_set(struct drm_bridge *bridge,
if (it66121_configure_afe(ctx, adjusted_mode))
goto unlock;
- regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG, IT66121_CLK_BANK_PWROFF_TXCLK, 0);
+ if (ctx->info->id == ID_IT66121 &&
+ regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG,
+ IT66121_CLK_BANK_PWROFF_TXCLK, 0)) {
+ goto unlock;
+ }
unlock:
mutex_unlock(&ctx->lock);
@@ -906,9 +879,25 @@ static struct edid *it66121_bridge_get_edid(struct drm_bridge *bridge,
{
struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, bridge);
struct edid *edid;
+ int ret;
mutex_lock(&ctx->lock);
+ ret = it66121_preamble_ddc(ctx);
+ if (ret) {
+ edid = ERR_PTR(ret);
+ goto out_unlock;
+ }
+
+ ret = regmap_write(ctx->regmap, IT66121_DDC_HEADER_REG,
+ IT66121_DDC_HEADER_EDID);
+ if (ret) {
+ edid = ERR_PTR(ret);
+ goto out_unlock;
+ }
+
edid = drm_do_get_edid(connector, it66121_get_edid_block, ctx);
+
+out_unlock:
mutex_unlock(&ctx->lock);
return edid;
@@ -923,6 +912,7 @@ static const struct drm_bridge_funcs it66121_bridge_funcs = {
.atomic_get_input_bus_fmts = it66121_bridge_atomic_get_input_bus_fmts,
.atomic_enable = it66121_bridge_enable,
.atomic_disable = it66121_bridge_disable,
+ .atomic_check = it66121_bridge_check,
.mode_set = it66121_bridge_mode_set,
.mode_valid = it66121_bridge_mode_valid,
.detect = it66121_bridge_detect,
@@ -952,21 +942,14 @@ static irqreturn_t it66121_irq_threaded_handler(int irq, void *dev_id)
ret = regmap_read(ctx->regmap, IT66121_INT_STATUS1_REG, &val);
if (ret) {
dev_err(dev, "Cannot read STATUS1_REG %d\n", ret);
- } else {
- if (val & IT66121_INT_STATUS1_DDC_FIFOERR)
- it66121_clear_ddc_fifo(ctx);
- if (val & (IT66121_INT_STATUS1_DDC_BUSHANG |
- IT66121_INT_STATUS1_DDC_NOACK))
- it66121_abort_ddc_ops(ctx);
- if (val & IT66121_INT_STATUS1_HPD_STATUS) {
- regmap_write_bits(ctx->regmap, IT66121_INT_CLR1_REG,
- IT66121_INT_CLR1_HPD, IT66121_INT_CLR1_HPD);
+ } else if (val & IT66121_INT_STATUS1_HPD_STATUS) {
+ regmap_write_bits(ctx->regmap, IT66121_INT_CLR1_REG,
+ IT66121_INT_CLR1_HPD, IT66121_INT_CLR1_HPD);
- status = it66121_is_hpd_detect(ctx) ? connector_status_connected
- : connector_status_disconnected;
+ status = it66121_is_hpd_detect(ctx) ? connector_status_connected
+ : connector_status_disconnected;
- event = true;
- }
+ event = true;
}
regmap_write_bits(ctx->regmap, IT66121_SYS_STATUS_REG,
@@ -1512,9 +1495,13 @@ static int it66121_audio_codec_init(struct it66121_ctx *ctx, struct device *dev)
return PTR_ERR_OR_ZERO(ctx->audio.pdev);
}
-static int it66121_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static const char * const it66121_supplies[] = {
+ "vcn33", "vcn18", "vrf12"
+};
+
+static int it66121_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
u32 revision_id, vendor_ids[2] = { 0 }, device_ids[2] = { 0 };
struct device_node *ep;
int ret;
@@ -1536,6 +1523,7 @@ static int it66121_probe(struct i2c_client *client,
ctx->dev = dev;
ctx->client = client;
+ ctx->info = (const struct it66121_chip_info *) id->driver_data;
of_property_read_u32(ep, "bus-width", &ctx->bus_width);
of_node_put(ep);
@@ -1565,26 +1553,18 @@ static int it66121_probe(struct i2c_client *client,
i2c_set_clientdata(client, ctx);
mutex_init(&ctx->lock);
- ctx->supplies[0].supply = "vcn33";
- ctx->supplies[1].supply = "vcn18";
- ctx->supplies[2].supply = "vrf12";
- ret = devm_regulator_bulk_get(ctx->dev, 3, ctx->supplies);
+ ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(it66121_supplies),
+ it66121_supplies);
if (ret) {
- dev_err(ctx->dev, "regulator_bulk failed\n");
+ dev_err(dev, "Failed to enable power supplies\n");
return ret;
}
- ret = ite66121_power_on(ctx);
- if (ret)
- return ret;
-
it66121_hw_reset(ctx);
ctx->regmap = devm_regmap_init_i2c(client, &it66121_regmap_config);
- if (IS_ERR(ctx->regmap)) {
- ite66121_power_off(ctx);
+ if (IS_ERR(ctx->regmap))
return PTR_ERR(ctx->regmap);
- }
regmap_read(ctx->regmap, IT66121_VENDOR_ID0_REG, &vendor_ids[0]);
regmap_read(ctx->regmap, IT66121_VENDOR_ID1_REG, &vendor_ids[1]);
@@ -1595,9 +1575,8 @@ static int it66121_probe(struct i2c_client *client,
revision_id = FIELD_GET(IT66121_REVISION_MASK, device_ids[1]);
device_ids[1] &= IT66121_DEVICE_ID1_MASK;
- if (vendor_ids[0] != IT66121_VENDOR_ID0 || vendor_ids[1] != IT66121_VENDOR_ID1 ||
- device_ids[0] != IT66121_DEVICE_ID0 || device_ids[1] != IT66121_DEVICE_ID1) {
- ite66121_power_off(ctx);
+ if ((vendor_ids[1] << 8 | vendor_ids[0]) != ctx->info->vid ||
+ (device_ids[1] << 8 | device_ids[0]) != ctx->info->pid) {
return -ENODEV;
}
@@ -1610,7 +1589,6 @@ static int it66121_probe(struct i2c_client *client,
IRQF_ONESHOT, dev_name(dev), ctx);
if (ret < 0) {
dev_err(dev, "Failed to request irq %d:%d\n", client->irq, ret);
- ite66121_power_off(ctx);
return ret;
}
@@ -1627,19 +1605,32 @@ static void it66121_remove(struct i2c_client *client)
{
struct it66121_ctx *ctx = i2c_get_clientdata(client);
- ite66121_power_off(ctx);
drm_bridge_remove(&ctx->bridge);
mutex_destroy(&ctx->lock);
}
static const struct of_device_id it66121_dt_match[] = {
{ .compatible = "ite,it66121" },
+ { .compatible = "ite,it6610" },
{ }
};
MODULE_DEVICE_TABLE(of, it66121_dt_match);
+static const struct it66121_chip_info it66121_chip_info = {
+ .id = ID_IT66121,
+ .vid = 0x4954,
+ .pid = 0x0612,
+};
+
+static const struct it66121_chip_info it6610_chip_info = {
+ .id = ID_IT6610,
+ .vid = 0xca00,
+ .pid = 0x0611,
+};
+
static const struct i2c_device_id it66121_id[] = {
- { "it66121", 0 },
+ { "it66121", (kernel_ulong_t) &it66121_chip_info },
+ { "it6610", (kernel_ulong_t) &it6610_chip_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, it66121_id);
@@ -1649,7 +1640,7 @@ static struct i2c_driver it66121_driver = {
.name = "it66121",
.of_match_table = it66121_dt_match,
},
- .probe = it66121_probe,
+ .probe_new = it66121_probe,
.remove = it66121_remove,
.id_table = it66121_id,
};
diff --git a/drivers/gpu/drm/bridge/lontium-lt8912b.c b/drivers/gpu/drm/bridge/lontium-lt8912b.c
index a98efef0ba0e..2019a8167d69 100644
--- a/drivers/gpu/drm/bridge/lontium-lt8912b.c
+++ b/drivers/gpu/drm/bridge/lontium-lt8912b.c
@@ -517,14 +517,27 @@ static int lt8912_attach_dsi(struct lt8912 *lt)
return 0;
}
+static void lt8912_bridge_hpd_cb(void *data, enum drm_connector_status status)
+{
+ struct lt8912 *lt = data;
+
+ if (lt->bridge.dev)
+ drm_helper_hpd_irq_event(lt->bridge.dev);
+}
+
static int lt8912_bridge_connector_init(struct drm_bridge *bridge)
{
int ret;
struct lt8912 *lt = bridge_to_lt8912(bridge);
struct drm_connector *connector = &lt->connector;
- connector->polled = DRM_CONNECTOR_POLL_CONNECT |
- DRM_CONNECTOR_POLL_DISCONNECT;
+ if (lt->hdmi_port->ops & DRM_BRIDGE_OP_HPD) {
+ drm_bridge_hpd_enable(lt->hdmi_port, lt8912_bridge_hpd_cb, lt);
+ connector->polled = DRM_CONNECTOR_POLL_HPD;
+ } else {
+ connector->polled = DRM_CONNECTOR_POLL_CONNECT |
+ DRM_CONNECTOR_POLL_DISCONNECT;
+ }
ret = drm_connector_init(bridge->dev, connector,
&lt8912_connector_funcs,
@@ -578,6 +591,10 @@ static void lt8912_bridge_detach(struct drm_bridge *bridge)
if (lt->is_attached) {
lt8912_hard_power_off(lt);
+
+ if (lt->hdmi_port->ops & DRM_BRIDGE_OP_HPD)
+ drm_bridge_hpd_disable(lt->hdmi_port);
+
drm_connector_unregister(&lt->connector);
drm_connector_cleanup(&lt->connector);
}
@@ -685,8 +702,7 @@ static int lt8912_put_dt(struct lt8912 *lt)
return 0;
}
-static int lt8912_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int lt8912_probe(struct i2c_client *client)
{
static struct lt8912 *lt;
int ret = 0;
@@ -758,7 +774,7 @@ static struct i2c_driver lt8912_i2c_driver = {
.name = "lt8912",
.of_match_table = lt8912_dt_match,
},
- .probe = lt8912_probe,
+ .probe_new = lt8912_probe,
.remove = lt8912_remove,
.id_table = lt8912_id,
};
diff --git a/drivers/gpu/drm/bridge/lontium-lt9211.c b/drivers/gpu/drm/bridge/lontium-lt9211.c
index 933ca028d612..3e19fff6547a 100644
--- a/drivers/gpu/drm/bridge/lontium-lt9211.c
+++ b/drivers/gpu/drm/bridge/lontium-lt9211.c
@@ -720,8 +720,7 @@ static int lt9211_host_attach(struct lt9211 *ctx)
return 0;
}
-static int lt9211_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int lt9211_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct lt9211 *ctx;
@@ -786,7 +785,7 @@ static const struct of_device_id lt9211_match_table[] = {
MODULE_DEVICE_TABLE(of, lt9211_match_table);
static struct i2c_driver lt9211_driver = {
- .probe = lt9211_probe,
+ .probe_new = lt9211_probe,
.remove = lt9211_remove,
.id_table = lt9211_id,
.driver = {
diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c
index 7c0a99173b39..a25d21a7d5c1 100644
--- a/drivers/gpu/drm/bridge/lontium-lt9611.c
+++ b/drivers/gpu/drm/bridge/lontium-lt9611.c
@@ -19,6 +19,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_of.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
@@ -33,7 +34,7 @@
struct lt9611 {
struct device *dev;
struct drm_bridge bridge;
- struct drm_connector connector;
+ struct drm_bridge *next_bridge;
struct regmap *regmap;
@@ -58,7 +59,6 @@ struct lt9611 {
enum drm_connector_status status;
u8 edid_buf[EDID_SEG_SIZE];
- u32 vic;
};
#define LT9611_PAGE_CONTROL 0xff
@@ -84,34 +84,11 @@ static const struct regmap_config lt9611_regmap_config = {
.num_ranges = ARRAY_SIZE(lt9611_ranges),
};
-struct lt9611_mode {
- u16 hdisplay;
- u16 vdisplay;
- u8 vrefresh;
- u8 lanes;
- u8 intfs;
-};
-
-static struct lt9611_mode lt9611_modes[] = {
- { 3840, 2160, 30, 4, 2 }, /* 3840x2160 24bit 30Hz 4Lane 2ports */
- { 1920, 1080, 60, 4, 1 }, /* 1080P 24bit 60Hz 4lane 1port */
- { 1920, 1080, 30, 3, 1 }, /* 1080P 24bit 30Hz 3lane 1port */
- { 1920, 1080, 24, 3, 1 },
- { 720, 480, 60, 4, 1 },
- { 720, 576, 50, 2, 1 },
- { 640, 480, 60, 2, 1 },
-};
-
static struct lt9611 *bridge_to_lt9611(struct drm_bridge *bridge)
{
return container_of(bridge, struct lt9611, bridge);
}
-static struct lt9611 *connector_to_lt9611(struct drm_connector *connector)
-{
- return container_of(connector, struct lt9611, connector);
-}
-
static int lt9611_mipi_input_analog(struct lt9611 *lt9611)
{
const struct reg_sequence reg_cfg[] = {
@@ -141,7 +118,7 @@ static int lt9611_mipi_input_digital(struct lt9611 *lt9611,
{ 0x8306, 0x0a },
};
- if (mode->hdisplay == 3840)
+ if (lt9611->dsi1_node)
reg_cfg[1].def = 0x03;
return regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg));
@@ -159,12 +136,12 @@ static void lt9611_mipi_video_setup(struct lt9611 *lt9611,
hactive = mode->hdisplay;
hsync_len = mode->hsync_end - mode->hsync_start;
hfront_porch = mode->hsync_start - mode->hdisplay;
- hsync_porch = hsync_len + mode->htotal - mode->hsync_end;
+ hsync_porch = mode->htotal - mode->hsync_start;
vactive = mode->vdisplay;
vsync_len = mode->vsync_end - mode->vsync_start;
vfront_porch = mode->vsync_start - mode->vdisplay;
- vsync_porch = vsync_len + mode->vtotal - mode->vsync_end;
+ vsync_porch = mode->vtotal - mode->vsync_start;
regmap_write(lt9611->regmap, 0x830d, (u8)(v_total / 256));
regmap_write(lt9611->regmap, 0x830e, (u8)(v_total % 256));
@@ -187,12 +164,14 @@ static void lt9611_mipi_video_setup(struct lt9611 *lt9611,
regmap_write(lt9611->regmap, 0x8319, (u8)(hfront_porch % 256));
- regmap_write(lt9611->regmap, 0x831a, (u8)(hsync_porch / 256));
+ regmap_write(lt9611->regmap, 0x831a, (u8)(hsync_porch / 256) |
+ ((hfront_porch / 256) << 4));
regmap_write(lt9611->regmap, 0x831b, (u8)(hsync_porch % 256));
}
-static void lt9611_pcr_setup(struct lt9611 *lt9611, const struct drm_display_mode *mode)
+static void lt9611_pcr_setup(struct lt9611 *lt9611, const struct drm_display_mode *mode, unsigned int postdiv)
{
+ unsigned int pcr_m = mode->clock * 5 * postdiv / 27000;
const struct reg_sequence reg_cfg[] = {
{ 0x830b, 0x01 },
{ 0x830c, 0x10 },
@@ -207,45 +186,40 @@ static void lt9611_pcr_setup(struct lt9611 *lt9611, const struct drm_display_mod
/* stage 2 */
{ 0x834a, 0x40 },
- { 0x831d, 0x10 },
/* MK limit */
{ 0x832d, 0x38 },
{ 0x8331, 0x08 },
};
- const struct reg_sequence reg_cfg2[] = {
- { 0x830b, 0x03 },
- { 0x830c, 0xd0 },
- { 0x8348, 0x03 },
- { 0x8349, 0xe0 },
- { 0x8324, 0x72 },
- { 0x8325, 0x00 },
- { 0x832a, 0x01 },
- { 0x834a, 0x10 },
- { 0x831d, 0x10 },
- { 0x8326, 0x37 },
- };
+ u8 pol = 0x10;
- regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg));
+ if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+ pol |= 0x2;
+ if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+ pol |= 0x1;
+ regmap_write(lt9611->regmap, 0x831d, pol);
- switch (mode->hdisplay) {
- case 640:
- regmap_write(lt9611->regmap, 0x8326, 0x14);
- break;
- case 1920:
- regmap_write(lt9611->regmap, 0x8326, 0x37);
- break;
- case 3840:
- regmap_multi_reg_write(lt9611->regmap, reg_cfg2, ARRAY_SIZE(reg_cfg2));
- break;
+ regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg));
+ if (lt9611->dsi1_node) {
+ unsigned int hact = mode->hdisplay;
+
+ hact >>= 2;
+ hact += 0x50;
+ hact = min(hact, 0x3e0U);
+ regmap_write(lt9611->regmap, 0x830b, hact / 256);
+ regmap_write(lt9611->regmap, 0x830c, hact % 256);
+ regmap_write(lt9611->regmap, 0x8348, hact / 256);
+ regmap_write(lt9611->regmap, 0x8349, hact % 256);
}
+ regmap_write(lt9611->regmap, 0x8326, pcr_m);
+
/* pcr rst */
regmap_write(lt9611->regmap, 0x8011, 0x5a);
regmap_write(lt9611->regmap, 0x8011, 0xfa);
}
-static int lt9611_pll_setup(struct lt9611 *lt9611, const struct drm_display_mode *mode)
+static int lt9611_pll_setup(struct lt9611 *lt9611, const struct drm_display_mode *mode, unsigned int *postdiv)
{
unsigned int pclk = mode->clock;
const struct reg_sequence reg_cfg[] = {
@@ -259,16 +233,21 @@ static int lt9611_pll_setup(struct lt9611 *lt9611, const struct drm_display_mode
{ 0x8126, 0x55 },
{ 0x8127, 0x66 },
{ 0x8128, 0x88 },
+ { 0x812a, 0x20 },
};
regmap_multi_reg_write(lt9611->regmap, reg_cfg, ARRAY_SIZE(reg_cfg));
- if (pclk > 150000)
+ if (pclk > 150000) {
regmap_write(lt9611->regmap, 0x812d, 0x88);
- else if (pclk > 70000)
+ *postdiv = 1;
+ } else if (pclk > 70000) {
regmap_write(lt9611->regmap, 0x812d, 0x99);
- else
+ *postdiv = 2;
+ } else {
regmap_write(lt9611->regmap, 0x812d, 0xaa);
+ *postdiv = 4;
+ }
/*
* first divide pclk by 2 first
@@ -353,13 +332,55 @@ end:
return temp;
}
-static void lt9611_hdmi_tx_digital(struct lt9611 *lt9611)
+static void lt9611_hdmi_set_infoframes(struct lt9611 *lt9611,
+ struct drm_connector *connector,
+ struct drm_display_mode *mode)
{
- regmap_write(lt9611->regmap, 0x8443, 0x46 - lt9611->vic);
- regmap_write(lt9611->regmap, 0x8447, lt9611->vic);
- regmap_write(lt9611->regmap, 0x843d, 0x0a); /* UD1 infoframe */
+ union hdmi_infoframe infoframe;
+ ssize_t len;
+ u8 iframes = 0x0a; /* UD1 infoframe */
+ u8 buf[32];
+ int ret;
+ int i;
- regmap_write(lt9611->regmap, 0x82d6, 0x8c);
+ ret = drm_hdmi_avi_infoframe_from_display_mode(&infoframe.avi,
+ connector,
+ mode);
+ if (ret < 0)
+ goto out;
+
+ len = hdmi_infoframe_pack(&infoframe, buf, sizeof(buf));
+ if (len < 0)
+ goto out;
+
+ for (i = 0; i < len; i++)
+ regmap_write(lt9611->regmap, 0x8440 + i, buf[i]);
+
+ ret = drm_hdmi_vendor_infoframe_from_display_mode(&infoframe.vendor.hdmi,
+ connector,
+ mode);
+ if (ret < 0)
+ goto out;
+
+ len = hdmi_infoframe_pack(&infoframe, buf, sizeof(buf));
+ if (len < 0)
+ goto out;
+
+ for (i = 0; i < len; i++)
+ regmap_write(lt9611->regmap, 0x8474 + i, buf[i]);
+
+ iframes |= 0x20;
+
+out:
+ regmap_write(lt9611->regmap, 0x843d, iframes); /* UD1 infoframe */
+}
+
+static void lt9611_hdmi_tx_digital(struct lt9611 *lt9611, bool is_hdmi)
+{
+ if (is_hdmi)
+ regmap_write(lt9611->regmap, 0x82d6, 0x8c);
+ else
+ regmap_write(lt9611->regmap, 0x82d6, 0x0c);
regmap_write(lt9611->regmap, 0x82d7, 0x04);
}
@@ -448,12 +469,11 @@ static void lt9611_sleep_setup(struct lt9611 *lt9611)
{ 0x8023, 0x01 },
{ 0x8157, 0x03 }, /* set addr pin as output */
{ 0x8149, 0x0b },
- { 0x8151, 0x30 }, /* disable IRQ */
+
{ 0x8102, 0x48 }, /* MIPI Rx power down */
{ 0x8123, 0x80 },
{ 0x8130, 0x00 },
- { 0x8100, 0x01 }, /* bandgap power down */
- { 0x8101, 0x00 }, /* system clk power down */
+ { 0x8011, 0x0a },
};
regmap_multi_reg_write(lt9611->regmap,
@@ -564,24 +584,9 @@ static int lt9611_regulator_enable(struct lt9611 *lt9611)
return 0;
}
-static struct lt9611_mode *lt9611_find_mode(const struct drm_display_mode *mode)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(lt9611_modes); i++) {
- if (lt9611_modes[i].hdisplay == mode->hdisplay &&
- lt9611_modes[i].vdisplay == mode->vdisplay &&
- lt9611_modes[i].vrefresh == drm_mode_vrefresh(mode)) {
- return &lt9611_modes[i];
- }
- }
-
- return NULL;
-}
-
-/* connector funcs */
-static enum drm_connector_status __lt9611_detect(struct lt9611 *lt9611)
+static enum drm_connector_status lt9611_bridge_detect(struct drm_bridge *bridge)
{
+ struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
unsigned int reg_val = 0;
int connected = 0;
@@ -594,12 +599,6 @@ static enum drm_connector_status __lt9611_detect(struct lt9611 *lt9611)
return lt9611->status;
}
-static enum drm_connector_status
-lt9611_connector_detect(struct drm_connector *connector, bool force)
-{
- return __lt9611_detect(connector_to_lt9611(connector));
-}
-
static int lt9611_read_edid(struct lt9611 *lt9611)
{
unsigned int temp;
@@ -681,36 +680,37 @@ lt9611_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len)
return 0;
}
-static int lt9611_connector_get_modes(struct drm_connector *connector)
-{
- struct lt9611 *lt9611 = connector_to_lt9611(connector);
- unsigned int count;
- struct edid *edid;
-
- lt9611_power_on(lt9611);
- edid = drm_do_get_edid(connector, lt9611_get_edid_block, lt9611);
- drm_connector_update_edid_property(connector, edid);
- count = drm_add_edid_modes(connector, edid);
- kfree(edid);
-
- return count;
-}
-
-static enum drm_mode_status
-lt9611_connector_mode_valid(struct drm_connector *connector,
- struct drm_display_mode *mode)
-{
- struct lt9611_mode *lt9611_mode = lt9611_find_mode(mode);
-
- return lt9611_mode ? MODE_OK : MODE_BAD;
-}
-
/* bridge funcs */
static void
lt9611_bridge_atomic_enable(struct drm_bridge *bridge,
struct drm_bridge_state *old_bridge_state)
{
struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
+ struct drm_atomic_state *state = old_bridge_state->base.state;
+ struct drm_connector *connector;
+ struct drm_connector_state *conn_state;
+ struct drm_crtc_state *crtc_state;
+ struct drm_display_mode *mode;
+ unsigned int postdiv;
+
+ connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);
+ if (WARN_ON(!connector))
+ return;
+
+ conn_state = drm_atomic_get_new_connector_state(state, connector);
+ if (WARN_ON(!conn_state))
+ return;
+
+ crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
+ if (WARN_ON(!crtc_state))
+ return;
+
+ mode = &crtc_state->adjusted_mode;
+
+ lt9611_mipi_input_digital(lt9611, mode);
+ lt9611_pll_setup(lt9611, mode, &postdiv);
+ lt9611_mipi_video_setup(lt9611, mode);
+ lt9611_pcr_setup(lt9611, mode, postdiv);
if (lt9611_power_on(lt9611)) {
dev_err(lt9611->dev, "power on failed\n");
@@ -718,7 +718,8 @@ lt9611_bridge_atomic_enable(struct drm_bridge *bridge,
}
lt9611_mipi_input_analog(lt9611);
- lt9611_hdmi_tx_digital(lt9611);
+ lt9611_hdmi_set_infoframes(lt9611, connector, mode);
+ lt9611_hdmi_tx_digital(lt9611, connector->display_info.is_hdmi);
lt9611_hdmi_tx_phy(lt9611);
msleep(500);
@@ -749,25 +750,10 @@ lt9611_bridge_atomic_disable(struct drm_bridge *bridge,
}
}
-static struct
-drm_connector_helper_funcs lt9611_bridge_connector_helper_funcs = {
- .get_modes = lt9611_connector_get_modes,
- .mode_valid = lt9611_connector_mode_valid,
-};
-
-static const struct drm_connector_funcs lt9611_bridge_connector_funcs = {
- .fill_modes = drm_helper_probe_single_connector_modes,
- .detect = lt9611_connector_detect,
- .destroy = drm_connector_cleanup,
- .reset = drm_atomic_helper_connector_reset,
- .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-};
-
static struct mipi_dsi_device *lt9611_attach_dsi(struct lt9611 *lt9611,
struct device_node *dsi_node)
{
- const struct mipi_dsi_device_info info = { "lt9611", 0, NULL };
+ const struct mipi_dsi_device_info info = { "lt9611", 0, lt9611->dev->of_node};
struct mipi_dsi_device *dsi;
struct mipi_dsi_host *host;
struct device *dev = lt9611->dev;
@@ -799,70 +785,54 @@ static struct mipi_dsi_device *lt9611_attach_dsi(struct lt9611 *lt9611,
return dsi;
}
-static int lt9611_connector_init(struct drm_bridge *bridge, struct lt9611 *lt9611)
-{
- int ret;
-
- ret = drm_connector_init(bridge->dev, &lt9611->connector,
- &lt9611_bridge_connector_funcs,
- DRM_MODE_CONNECTOR_HDMIA);
- if (ret) {
- DRM_ERROR("Failed to initialize connector with drm\n");
- return ret;
- }
-
- drm_connector_helper_add(&lt9611->connector,
- &lt9611_bridge_connector_helper_funcs);
-
- if (!bridge->encoder) {
- DRM_ERROR("Parent encoder object not found");
- return -ENODEV;
- }
-
- drm_connector_attach_encoder(&lt9611->connector, bridge->encoder);
-
- return 0;
-}
-
static int lt9611_bridge_attach(struct drm_bridge *bridge,
enum drm_bridge_attach_flags flags)
{
struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
- int ret;
- if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
- ret = lt9611_connector_init(bridge, lt9611);
- if (ret < 0)
- return ret;
- }
-
- return 0;
+ return drm_bridge_attach(bridge->encoder, lt9611->next_bridge,
+ bridge, flags);
}
static enum drm_mode_status lt9611_bridge_mode_valid(struct drm_bridge *bridge,
const struct drm_display_info *info,
const struct drm_display_mode *mode)
{
- struct lt9611_mode *lt9611_mode = lt9611_find_mode(mode);
struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
- if (!lt9611_mode)
- return MODE_BAD;
- else if (lt9611_mode->intfs > 1 && !lt9611->dsi1)
+ if (mode->hdisplay > 3840)
+ return MODE_BAD_HVALUE;
+
+ if (mode->vdisplay > 2160)
+ return MODE_BAD_VVALUE;
+
+ if (mode->hdisplay == 3840 &&
+ mode->vdisplay == 2160 &&
+ drm_mode_vrefresh(mode) > 30)
+ return MODE_CLOCK_HIGH;
+
+ if (mode->hdisplay > 2000 && !lt9611->dsi1_node)
return MODE_PANEL;
else
return MODE_OK;
}
-static void lt9611_bridge_pre_enable(struct drm_bridge *bridge)
+static void lt9611_bridge_atomic_pre_enable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_bridge_state)
{
struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
+ static const struct reg_sequence reg_cfg[] = {
+ { 0x8102, 0x12 },
+ { 0x8123, 0x40 },
+ { 0x8130, 0xea },
+ { 0x8011, 0xfa },
+ };
if (!lt9611->sleep)
return;
- lt9611_reset(lt9611);
- regmap_write(lt9611->regmap, 0x80ee, 0x01);
+ regmap_multi_reg_write(lt9611->regmap,
+ reg_cfg, ARRAY_SIZE(reg_cfg));
lt9611->sleep = false;
}
@@ -876,33 +846,6 @@ lt9611_bridge_atomic_post_disable(struct drm_bridge *bridge,
lt9611_sleep_setup(lt9611);
}
-static void lt9611_bridge_mode_set(struct drm_bridge *bridge,
- const struct drm_display_mode *mode,
- const struct drm_display_mode *adj_mode)
-{
- struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
- struct hdmi_avi_infoframe avi_frame;
- int ret;
-
- lt9611_bridge_pre_enable(bridge);
-
- lt9611_mipi_input_digital(lt9611, mode);
- lt9611_pll_setup(lt9611, mode);
- lt9611_mipi_video_setup(lt9611, mode);
- lt9611_pcr_setup(lt9611, mode);
-
- ret = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame,
- &lt9611->connector,
- mode);
- if (!ret)
- lt9611->vic = avi_frame.video_code;
-}
-
-static enum drm_connector_status lt9611_bridge_detect(struct drm_bridge *bridge)
-{
- return __lt9611_detect(bridge_to_lt9611(bridge));
-}
-
static struct edid *lt9611_bridge_get_edid(struct drm_bridge *bridge,
struct drm_connector *connector)
{
@@ -948,11 +891,11 @@ lt9611_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
static const struct drm_bridge_funcs lt9611_bridge_funcs = {
.attach = lt9611_bridge_attach,
.mode_valid = lt9611_bridge_mode_valid,
- .mode_set = lt9611_bridge_mode_set,
.detect = lt9611_bridge_detect,
.get_edid = lt9611_bridge_get_edid,
.hpd_enable = lt9611_bridge_hpd_enable,
+ .atomic_pre_enable = lt9611_bridge_atomic_pre_enable,
.atomic_enable = lt9611_bridge_atomic_enable,
.atomic_disable = lt9611_bridge_atomic_disable,
.atomic_post_disable = lt9611_bridge_atomic_post_disable,
@@ -975,7 +918,7 @@ static int lt9611_parse_dt(struct device *dev,
lt9611->ac_mode = of_property_read_bool(dev->of_node, "lt,ac-mode");
- return 0;
+ return drm_of_find_panel_or_bridge(dev->of_node, 2, -1, NULL, &lt9611->next_bridge);
}
static int lt9611_gpio_init(struct lt9611 *lt9611)
@@ -1108,8 +1051,7 @@ static void lt9611_audio_exit(struct lt9611 *lt9611)
}
}
-static int lt9611_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int lt9611_probe(struct i2c_client *client)
{
struct lt9611 *lt9611;
struct device *dev = &client->dev;
@@ -1248,7 +1190,7 @@ static struct i2c_driver lt9611_driver = {
.name = "lt9611",
.of_match_table = lt9611_match_table,
},
- .probe = lt9611_probe,
+ .probe_new = lt9611_probe,
.remove = lt9611_remove,
.id_table = lt9611_id,
};
diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c
index fa1ee6264d92..583daacf3705 100644
--- a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c
+++ b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c
@@ -844,8 +844,7 @@ static const struct attribute_group *lt9611uxc_attr_groups[] = {
NULL,
};
-static int lt9611uxc_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int lt9611uxc_probe(struct i2c_client *client)
{
struct lt9611uxc *lt9611uxc;
struct device *dev = &client->dev;
@@ -1012,7 +1011,7 @@ static struct i2c_driver lt9611uxc_driver = {
.of_match_table = lt9611uxc_match_table,
.dev_groups = lt9611uxc_attr_groups,
},
- .probe = lt9611uxc_probe,
+ .probe_new = lt9611uxc_probe,
.remove = lt9611uxc_remove,
.id_table = lt9611uxc_id,
};
diff --git a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c
index 97359f807bfc..4fc494d9084b 100644
--- a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c
+++ b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c
@@ -336,8 +336,7 @@ static int ge_b850v3_register(void)
"ge-b850v3-lvds-dp", ge_b850v3_lvds_ptr);
}
-static int stdp4028_ge_b850v3_fw_probe(struct i2c_client *stdp4028_i2c,
- const struct i2c_device_id *id)
+static int stdp4028_ge_b850v3_fw_probe(struct i2c_client *stdp4028_i2c)
{
struct device *dev = &stdp4028_i2c->dev;
int ret;
@@ -376,7 +375,7 @@ MODULE_DEVICE_TABLE(of, stdp4028_ge_b850v3_fw_match);
static struct i2c_driver stdp4028_ge_b850v3_fw_driver = {
.id_table = stdp4028_ge_b850v3_fw_i2c_table,
- .probe = stdp4028_ge_b850v3_fw_probe,
+ .probe_new = stdp4028_ge_b850v3_fw_probe,
.remove = stdp4028_ge_b850v3_fw_remove,
.driver = {
.name = "stdp4028-ge-b850v3-fw",
@@ -384,8 +383,7 @@ static struct i2c_driver stdp4028_ge_b850v3_fw_driver = {
},
};
-static int stdp2690_ge_b850v3_fw_probe(struct i2c_client *stdp2690_i2c,
- const struct i2c_device_id *id)
+static int stdp2690_ge_b850v3_fw_probe(struct i2c_client *stdp2690_i2c)
{
struct device *dev = &stdp2690_i2c->dev;
int ret;
@@ -424,7 +422,7 @@ MODULE_DEVICE_TABLE(of, stdp2690_ge_b850v3_fw_match);
static struct i2c_driver stdp2690_ge_b850v3_fw_driver = {
.id_table = stdp2690_ge_b850v3_fw_i2c_table,
- .probe = stdp2690_ge_b850v3_fw_probe,
+ .probe_new = stdp2690_ge_b850v3_fw_probe,
.remove = stdp2690_ge_b850v3_fw_remove,
.driver = {
.name = "stdp2690-ge-b850v3-fw",
@@ -440,7 +438,11 @@ static int __init stdpxxxx_ge_b850v3_init(void)
if (ret)
return ret;
- return i2c_add_driver(&stdp2690_ge_b850v3_fw_driver);
+ ret = i2c_add_driver(&stdp2690_ge_b850v3_fw_driver);
+ if (ret)
+ i2c_del_driver(&stdp4028_ge_b850v3_fw_driver);
+
+ return ret;
}
module_init(stdpxxxx_ge_b850v3_init);
diff --git a/drivers/gpu/drm/bridge/nxp-ptn3460.c b/drivers/gpu/drm/bridge/nxp-ptn3460.c
index 0851101a8c72..cd292a2f894c 100644
--- a/drivers/gpu/drm/bridge/nxp-ptn3460.c
+++ b/drivers/gpu/drm/bridge/nxp-ptn3460.c
@@ -257,8 +257,7 @@ static const struct drm_bridge_funcs ptn3460_bridge_funcs = {
.get_edid = ptn3460_get_edid,
};
-static int ptn3460_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ptn3460_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct ptn3460_bridge *ptn_bridge;
@@ -336,7 +335,7 @@ MODULE_DEVICE_TABLE(of, ptn3460_match);
static struct i2c_driver ptn3460_driver = {
.id_table = ptn3460_i2c_table,
- .probe = ptn3460_probe,
+ .probe_new = ptn3460_probe,
.remove = ptn3460_remove,
.driver = {
.name = "nxp,ptn3460",
diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c
index 216af76d0042..e8aae3cdc73d 100644
--- a/drivers/gpu/drm/bridge/panel.c
+++ b/drivers/gpu/drm/bridge/panel.c
@@ -357,13 +357,16 @@ struct drm_bridge *devm_drm_panel_bridge_add_typed(struct device *dev,
return ERR_PTR(-ENOMEM);
bridge = drm_panel_bridge_add_typed(panel, connector_type);
- if (!IS_ERR(bridge)) {
- *ptr = bridge;
- devres_add(dev, ptr);
- } else {
+ if (IS_ERR(bridge)) {
devres_free(ptr);
+ return bridge;
}
+ bridge->pre_enable_prev_first = panel->prepare_prev_first;
+
+ *ptr = bridge;
+ devres_add(dev, ptr);
+
return bridge;
}
EXPORT_SYMBOL(devm_drm_panel_bridge_add_typed);
@@ -402,6 +405,8 @@ struct drm_bridge *drmm_panel_bridge_add(struct drm_device *drm,
if (ret)
return ERR_PTR(ret);
+ bridge->pre_enable_prev_first = panel->prepare_prev_first;
+
return bridge;
}
EXPORT_SYMBOL(drmm_panel_bridge_add);
diff --git a/drivers/gpu/drm/bridge/parade-ps8622.c b/drivers/gpu/drm/bridge/parade-ps8622.c
index 309de802863d..530ee6a19e7e 100644
--- a/drivers/gpu/drm/bridge/parade-ps8622.c
+++ b/drivers/gpu/drm/bridge/parade-ps8622.c
@@ -442,9 +442,9 @@ static const struct of_device_id ps8622_devices[] = {
};
MODULE_DEVICE_TABLE(of, ps8622_devices);
-static int ps8622_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ps8622_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct device *dev = &client->dev;
struct ps8622_bridge *ps8622;
struct drm_bridge *panel_bridge;
@@ -538,7 +538,7 @@ MODULE_DEVICE_TABLE(i2c, ps8622_i2c_table);
static struct i2c_driver ps8622_driver = {
.id_table = ps8622_i2c_table,
- .probe = ps8622_probe,
+ .probe_new = ps8622_probe,
.remove = ps8622_remove,
.driver = {
.name = "ps8622",
diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c
index 6a614e54b383..4b361d7d5e44 100644
--- a/drivers/gpu/drm/bridge/parade-ps8640.c
+++ b/drivers/gpu/drm/bridge/parade-ps8640.c
@@ -15,6 +15,7 @@
#include <drm/display/drm_dp_aux_bus.h>
#include <drm/display/drm_dp_helper.h>
+#include <drm/drm_atomic_state_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_edid.h>
#include <drm/drm_mipi_dsi.h>
@@ -442,7 +443,8 @@ static const struct dev_pm_ops ps8640_pm_ops = {
pm_runtime_force_resume)
};
-static void ps8640_pre_enable(struct drm_bridge *bridge)
+static void ps8640_atomic_pre_enable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_bridge_state)
{
struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
struct regmap *map = ps_bridge->regmap[PAGE2_TOP_CNTL];
@@ -476,7 +478,8 @@ static void ps8640_pre_enable(struct drm_bridge *bridge)
ps_bridge->pre_enabled = true;
}
-static void ps8640_post_disable(struct drm_bridge *bridge)
+static void ps8640_atomic_post_disable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_bridge_state)
{
struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
@@ -554,7 +557,7 @@ static struct edid *ps8640_bridge_get_edid(struct drm_bridge *bridge,
* EDID, for this chip, we need to do a full poweron, otherwise it will
* fail.
*/
- drm_bridge_chain_pre_enable(bridge);
+ drm_atomic_bridge_chain_pre_enable(bridge, connector->state->state);
edid = drm_get_edid(connector,
ps_bridge->page[PAGE0_DP_CNTL]->adapter);
@@ -564,7 +567,7 @@ static struct edid *ps8640_bridge_get_edid(struct drm_bridge *bridge,
* before, return the chip to its original power state.
*/
if (poweroff)
- drm_bridge_chain_post_disable(bridge);
+ drm_atomic_bridge_chain_post_disable(bridge, connector->state->state);
return edid;
}
@@ -579,8 +582,11 @@ static const struct drm_bridge_funcs ps8640_bridge_funcs = {
.attach = ps8640_bridge_attach,
.detach = ps8640_bridge_detach,
.get_edid = ps8640_bridge_get_edid,
- .post_disable = ps8640_post_disable,
- .pre_enable = ps8640_pre_enable,
+ .atomic_post_disable = ps8640_atomic_post_disable,
+ .atomic_pre_enable = ps8640_atomic_pre_enable,
+ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
+ .atomic_reset = drm_atomic_helper_bridge_reset,
};
static int ps8640_bridge_get_dsi_resources(struct device *dev, struct ps8640 *ps_bridge)
@@ -734,13 +740,13 @@ static int ps8640_probe(struct i2c_client *client)
pm_runtime_enable(dev);
/*
* Powering on ps8640 takes ~300ms. To avoid wasting time on power
- * cycling ps8640 too often, set autosuspend_delay to 1000ms to ensure
+ * cycling ps8640 too often, set autosuspend_delay to 2000ms to ensure
* the bridge wouldn't suspend in between each _aux_transfer_msg() call
* during EDID read (~20ms in my experiment) and in between the last
* _aux_transfer_msg() call during EDID read and the _pre_enable() call
* (~100ms in my experiment).
*/
- pm_runtime_set_autosuspend_delay(dev, 1000);
+ pm_runtime_set_autosuspend_delay(dev, 2000);
pm_runtime_use_autosuspend(dev);
pm_suspend_ignore_children(dev, true);
ret = devm_add_action_or_reset(dev, ps8640_runtime_disable, dev);
diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c
index 878fb7d3732b..ef66461e7f7c 100644
--- a/drivers/gpu/drm/bridge/sii902x.c
+++ b/drivers/gpu/drm/bridge/sii902x.c
@@ -171,7 +171,6 @@ struct sii902x {
struct drm_connector connector;
struct gpio_desc *reset_gpio;
struct i2c_mux_core *i2cmux;
- struct regulator_bulk_data supplies[2];
bool sink_is_hdmi;
/*
* Mutex protects audio and video functions from interfering
@@ -240,12 +239,12 @@ static void sii902x_reset(struct sii902x *sii902x)
if (!sii902x->reset_gpio)
return;
- gpiod_set_value(sii902x->reset_gpio, 1);
+ gpiod_set_value_cansleep(sii902x->reset_gpio, 1);
/* The datasheet says treset-min = 100us. Make it 150us to be sure. */
usleep_range(150, 200);
- gpiod_set_value(sii902x->reset_gpio, 0);
+ gpiod_set_value_cansleep(sii902x->reset_gpio, 0);
}
static enum drm_connector_status sii902x_detect(struct sii902x *sii902x)
@@ -1066,12 +1065,12 @@ static int sii902x_init(struct sii902x *sii902x)
return i2c_mux_add_adapter(sii902x->i2cmux, 0, 0, 0);
}
-static int sii902x_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int sii902x_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct device_node *endpoint;
struct sii902x *sii902x;
+ static const char * const supplies[] = {"iovcc", "cvcc12"};
int ret;
ret = i2c_check_functionality(client->adapter,
@@ -1117,32 +1116,17 @@ static int sii902x_probe(struct i2c_client *client,
sii902x->next_bridge = of_drm_find_bridge(remote);
of_node_put(remote);
if (!sii902x->next_bridge)
- return -EPROBE_DEFER;
+ return dev_err_probe(dev, -EPROBE_DEFER,
+ "Failed to find remote bridge\n");
}
mutex_init(&sii902x->mutex);
- sii902x->supplies[0].supply = "iovcc";
- sii902x->supplies[1].supply = "cvcc12";
- ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(sii902x->supplies),
- sii902x->supplies);
+ ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(supplies), supplies);
if (ret < 0)
- return ret;
-
- ret = regulator_bulk_enable(ARRAY_SIZE(sii902x->supplies),
- sii902x->supplies);
- if (ret < 0) {
- dev_err_probe(dev, ret, "Failed to enable supplies");
- return ret;
- }
+ return dev_err_probe(dev, ret, "Failed to enable supplies");
- ret = sii902x_init(sii902x);
- if (ret < 0) {
- regulator_bulk_disable(ARRAY_SIZE(sii902x->supplies),
- sii902x->supplies);
- }
-
- return ret;
+ return sii902x_init(sii902x);
}
static void sii902x_remove(struct i2c_client *client)
@@ -1152,8 +1136,6 @@ static void sii902x_remove(struct i2c_client *client)
i2c_mux_del_adapters(sii902x->i2cmux);
drm_bridge_remove(&sii902x->bridge);
- regulator_bulk_disable(ARRAY_SIZE(sii902x->supplies),
- sii902x->supplies);
}
static const struct of_device_id sii902x_dt_ids[] = {
@@ -1169,7 +1151,7 @@ static const struct i2c_device_id sii902x_i2c_ids[] = {
MODULE_DEVICE_TABLE(i2c, sii902x_i2c_ids);
static struct i2c_driver sii902x_driver = {
- .probe = sii902x_probe,
+ .probe_new = sii902x_probe,
.remove = sii902x_remove,
.driver = {
.name = "sii902x",
diff --git a/drivers/gpu/drm/bridge/sii9234.c b/drivers/gpu/drm/bridge/sii9234.c
index 5b3061d4b5c3..099b510ff285 100644
--- a/drivers/gpu/drm/bridge/sii9234.c
+++ b/drivers/gpu/drm/bridge/sii9234.c
@@ -886,8 +886,7 @@ static const struct drm_bridge_funcs sii9234_bridge_funcs = {
.mode_valid = sii9234_mode_valid,
};
-static int sii9234_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int sii9234_probe(struct i2c_client *client)
{
struct i2c_adapter *adapter = client->adapter;
struct sii9234 *ctx;
@@ -961,7 +960,7 @@ static struct i2c_driver sii9234_driver = {
.name = "sii9234",
.of_match_table = sii9234_dt_match,
},
- .probe = sii9234_probe,
+ .probe_new = sii9234_probe,
.remove = sii9234_remove,
.id_table = sii9234_id,
};
diff --git a/drivers/gpu/drm/bridge/sil-sii8620.c b/drivers/gpu/drm/bridge/sil-sii8620.c
index 511982a1cedb..b96d03cd878d 100644
--- a/drivers/gpu/drm/bridge/sil-sii8620.c
+++ b/drivers/gpu/drm/bridge/sil-sii8620.c
@@ -2284,8 +2284,7 @@ static const struct drm_bridge_funcs sii8620_bridge_funcs = {
.mode_valid = sii8620_mode_valid,
};
-static int sii8620_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int sii8620_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct sii8620 *ctx;
@@ -2379,7 +2378,7 @@ static struct i2c_driver sii8620_driver = {
.name = "sii8620",
.of_match_table = of_match_ptr(sii8620_dt_match),
},
- .probe = sii8620_probe,
+ .probe_new = sii8620_probe,
.remove = sii8620_remove,
.id_table = sii8620_id,
};
diff --git a/drivers/gpu/drm/bridge/tc358764.c b/drivers/gpu/drm/bridge/tc358764.c
index 53259c12d777..f85654f1b104 100644
--- a/drivers/gpu/drm/bridge/tc358764.c
+++ b/drivers/gpu/drm/bridge/tc358764.c
@@ -369,6 +369,7 @@ static int tc358764_probe(struct mipi_dsi_device *dsi)
ctx->bridge.funcs = &tc358764_bridge_funcs;
ctx->bridge.of_node = dev->of_node;
+ ctx->bridge.pre_enable_prev_first = true;
drm_bridge_add(&ctx->bridge);
diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
index 2a58eb271f70..6d16ec45ea61 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -1264,10 +1264,10 @@ static int tc_dsi_rx_enable(struct tc_data *tc)
u32 value;
int ret;
- regmap_write(tc->regmap, PPI_D0S_CLRSIPOCOUNT, 5);
- regmap_write(tc->regmap, PPI_D1S_CLRSIPOCOUNT, 5);
- regmap_write(tc->regmap, PPI_D2S_CLRSIPOCOUNT, 5);
- regmap_write(tc->regmap, PPI_D3S_CLRSIPOCOUNT, 5);
+ regmap_write(tc->regmap, PPI_D0S_CLRSIPOCOUNT, 25);
+ regmap_write(tc->regmap, PPI_D1S_CLRSIPOCOUNT, 25);
+ regmap_write(tc->regmap, PPI_D2S_CLRSIPOCOUNT, 25);
+ regmap_write(tc->regmap, PPI_D3S_CLRSIPOCOUNT, 25);
regmap_write(tc->regmap, PPI_D0S_ATMR, 0);
regmap_write(tc->regmap, PPI_D1S_ATMR, 0);
regmap_write(tc->regmap, PPI_TX_RX_TA, TTA_GET | TTA_SURE);
@@ -2029,7 +2029,7 @@ static void tc_clk_disable(void *data)
clk_disable_unprepare(refclk);
}
-static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
+static int tc_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct tc_data *tc;
@@ -2209,7 +2209,7 @@ static struct i2c_driver tc358767_driver = {
.of_match_table = tc358767_of_ids,
},
.id_table = tc358767_i2c_ids,
- .probe = tc_probe,
+ .probe_new = tc_probe,
.remove = tc_remove,
};
module_i2c_driver(tc358767_driver);
diff --git a/drivers/gpu/drm/bridge/tc358768.c b/drivers/gpu/drm/bridge/tc358768.c
index 4c4b77ce8aba..7c0cbe84611b 100644
--- a/drivers/gpu/drm/bridge/tc358768.c
+++ b/drivers/gpu/drm/bridge/tc358768.c
@@ -15,7 +15,6 @@
#include <linux/slab.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_of.h>
@@ -1018,8 +1017,7 @@ static int tc358768_get_regulators(struct tc358768_priv *priv)
return ret;
}
-static int tc358768_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int tc358768_i2c_probe(struct i2c_client *client)
{
struct tc358768_priv *priv;
struct device *dev = &client->dev;
@@ -1085,7 +1083,7 @@ static struct i2c_driver tc358768_driver = {
.of_match_table = tc358768_of_ids,
},
.id_table = tc358768_i2c_ids,
- .probe = tc358768_i2c_probe,
+ .probe_new = tc358768_i2c_probe,
.remove = tc358768_i2c_remove,
};
module_i2c_driver(tc358768_driver);
diff --git a/drivers/gpu/drm/bridge/tc358775.c b/drivers/gpu/drm/bridge/tc358775.c
index 3ceb0e9f9bdc..19316994ddd1 100644
--- a/drivers/gpu/drm/bridge/tc358775.c
+++ b/drivers/gpu/drm/bridge/tc358775.c
@@ -23,7 +23,6 @@
#include <drm/display/drm_dp_helper.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
@@ -637,7 +636,7 @@ static int tc_attach_host(struct tc_data *tc)
return 0;
}
-static int tc_probe(struct i2c_client *client, const struct i2c_device_id *id)
+static int tc_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct tc_data *tc;
@@ -729,7 +728,7 @@ static struct i2c_driver tc358775_driver = {
.of_match_table = tc358775_of_ids,
},
.id_table = tc358775_i2c_ids,
- .probe = tc_probe,
+ .probe_new = tc_probe,
.remove = tc_remove,
};
module_i2c_driver(tc358775_driver);
diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi83.c b/drivers/gpu/drm/bridge/ti-sn65dsi83.c
index 7ba9467fff12..91ecfbe45bf9 100644
--- a/drivers/gpu/drm/bridge/ti-sn65dsi83.c
+++ b/drivers/gpu/drm/bridge/ti-sn65dsi83.c
@@ -346,7 +346,7 @@ static void sn65dsi83_atomic_enable(struct drm_bridge *bridge,
/* Deassert reset */
gpiod_set_value_cansleep(ctx->enable_gpio, 1);
- usleep_range(1000, 1100);
+ usleep_range(10000, 11000);
/* Get the LVDS format from the bridge state. */
bridge_state = drm_atomic_get_new_bridge_state(state, bridge);
@@ -653,9 +653,9 @@ static int sn65dsi83_host_attach(struct sn65dsi83 *ctx)
return 0;
}
-static int sn65dsi83_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int sn65dsi83_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct device *dev = &client->dev;
enum sn65dsi83_model model;
struct sn65dsi83 *ctx;
@@ -730,7 +730,7 @@ static const struct of_device_id sn65dsi83_match_table[] = {
MODULE_DEVICE_TABLE(of, sn65dsi83_match_table);
static struct i2c_driver sn65dsi83_driver = {
- .probe = sn65dsi83_probe,
+ .probe_new = sn65dsi83_probe,
.remove = sn65dsi83_remove,
.id_table = sn65dsi83_id,
.driver = {
diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
index 05f8756d1aaf..1e26fa63845a 100644
--- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c
+++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
@@ -1852,8 +1852,7 @@ static int ti_sn65dsi86_parse_regulators(struct ti_sn65dsi86 *pdata)
pdata->supplies);
}
-static int ti_sn65dsi86_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ti_sn65dsi86_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct ti_sn65dsi86 *pdata;
@@ -1952,7 +1951,7 @@ static struct i2c_driver ti_sn65dsi86_driver = {
.of_match_table = ti_sn65dsi86_match_table,
.pm = &ti_sn65dsi86_pm_ops,
},
- .probe = ti_sn65dsi86_probe,
+ .probe_new = ti_sn65dsi86_probe,
.id_table = ti_sn65dsi86_id,
};
diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c
index b9635abbad16..6db69df0e18b 100644
--- a/drivers/gpu/drm/bridge/ti-tfp410.c
+++ b/drivers/gpu/drm/bridge/ti-tfp410.c
@@ -379,8 +379,7 @@ static struct platform_driver tfp410_platform_driver = {
#if IS_ENABLED(CONFIG_I2C)
/* There is currently no i2c functionality. */
-static int tfp410_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int tfp410_i2c_probe(struct i2c_client *client)
{
int reg;
@@ -411,7 +410,7 @@ static struct i2c_driver tfp410_i2c_driver = {
.of_match_table = of_match_ptr(tfp410_match),
},
.id_table = tfp410_i2c_ids,
- .probe = tfp410_i2c_probe,
+ .probe_new = tfp410_i2c_probe,
.remove = tfp410_i2c_remove,
};
#endif /* IS_ENABLED(CONFIG_I2C) */
diff --git a/drivers/gpu/drm/display/drm_dp_aux_bus.c b/drivers/gpu/drm/display/drm_dp_aux_bus.c
index f5741b45ca07..8a165be1a821 100644
--- a/drivers/gpu/drm/display/drm_dp_aux_bus.c
+++ b/drivers/gpu/drm/display/drm_dp_aux_bus.c
@@ -161,9 +161,14 @@ static void dp_aux_ep_dev_release(struct device *dev)
kfree(aux_ep_with_data);
}
+static int dp_aux_ep_dev_modalias(const struct device *dev, struct kobj_uevent_env *env)
+{
+ return of_device_uevent_modalias(dev, env);
+}
+
static struct device_type dp_aux_device_type_type = {
.groups = dp_aux_ep_dev_groups,
- .uevent = of_device_uevent_modalias,
+ .uevent = dp_aux_ep_dev_modalias,
.release = dp_aux_ep_dev_release,
};
diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c
index 4ca37261584a..38dab76ae69e 100644
--- a/drivers/gpu/drm/display/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c
@@ -3309,8 +3309,13 @@ int drm_dp_add_payload_part1(struct drm_dp_mst_topology_mgr *mgr,
int ret;
port = drm_dp_mst_topology_get_port_validated(mgr, payload->port);
- if (!port)
+ if (!port) {
+ drm_dbg_kms(mgr->dev,
+ "VCPI %d for port %p not in topology, not creating a payload\n",
+ payload->vcpi, payload->port);
+ payload->vc_start_slot = -1;
return 0;
+ }
if (mgr->payload_count == 0)
mgr->next_start_slot = mst_state->start_slot;
@@ -3337,7 +3342,8 @@ EXPORT_SYMBOL(drm_dp_add_payload_part1);
* drm_dp_remove_payload() - Remove an MST payload
* @mgr: Manager to use.
* @mst_state: The MST atomic state
- * @payload: The payload to write
+ * @old_payload: The payload with its old state
+ * @new_payload: The payload to write
*
* Removes a payload from an MST topology if it was successfully assigned a start slot. Also updates
* the starting time slots of all other payloads which would have been shifted towards the start of
@@ -3345,36 +3351,37 @@ EXPORT_SYMBOL(drm_dp_add_payload_part1);
*/
void drm_dp_remove_payload(struct drm_dp_mst_topology_mgr *mgr,
struct drm_dp_mst_topology_state *mst_state,
- struct drm_dp_mst_atomic_payload *payload)
+ const struct drm_dp_mst_atomic_payload *old_payload,
+ struct drm_dp_mst_atomic_payload *new_payload)
{
struct drm_dp_mst_atomic_payload *pos;
bool send_remove = false;
/* We failed to make the payload, so nothing to do */
- if (payload->vc_start_slot == -1)
+ if (new_payload->vc_start_slot == -1)
return;
mutex_lock(&mgr->lock);
- send_remove = drm_dp_mst_port_downstream_of_branch(payload->port, mgr->mst_primary);
+ send_remove = drm_dp_mst_port_downstream_of_branch(new_payload->port, mgr->mst_primary);
mutex_unlock(&mgr->lock);
if (send_remove)
- drm_dp_destroy_payload_step1(mgr, mst_state, payload);
+ drm_dp_destroy_payload_step1(mgr, mst_state, new_payload);
else
drm_dbg_kms(mgr->dev, "Payload for VCPI %d not in topology, not sending remove\n",
- payload->vcpi);
+ new_payload->vcpi);
list_for_each_entry(pos, &mst_state->payloads, next) {
- if (pos != payload && pos->vc_start_slot > payload->vc_start_slot)
- pos->vc_start_slot -= payload->time_slots;
+ if (pos != new_payload && pos->vc_start_slot > new_payload->vc_start_slot)
+ pos->vc_start_slot -= old_payload->time_slots;
}
- payload->vc_start_slot = -1;
+ new_payload->vc_start_slot = -1;
mgr->payload_count--;
- mgr->next_start_slot -= payload->time_slots;
+ mgr->next_start_slot -= old_payload->time_slots;
- if (payload->delete)
- drm_dp_mst_put_port_malloc(payload->port);
+ if (new_payload->delete)
+ drm_dp_mst_put_port_malloc(new_payload->port);
}
EXPORT_SYMBOL(drm_dp_remove_payload);
@@ -3644,6 +3651,9 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms
drm_dp_dpcd_writeb(mgr->aux, DP_MSTM_CTRL, 0);
ret = 0;
mgr->payload_id_table_cleared = false;
+
+ memset(&mgr->down_rep_recv, 0, sizeof(mgr->down_rep_recv));
+ memset(&mgr->up_req_recv, 0, sizeof(mgr->up_req_recv));
}
out_unlock:
@@ -3856,7 +3866,7 @@ static int drm_dp_mst_handle_down_rep(struct drm_dp_mst_topology_mgr *mgr)
struct drm_dp_sideband_msg_rx *msg = &mgr->down_rep_recv;
if (!drm_dp_get_one_sb_msg(mgr, false, &mstb))
- goto out;
+ goto out_clear_reply;
/* Multi-packet message transmission, don't clear the reply */
if (!msg->have_eomt)
@@ -5355,27 +5365,52 @@ struct drm_dp_mst_topology_state *drm_atomic_get_mst_topology_state(struct drm_a
EXPORT_SYMBOL(drm_atomic_get_mst_topology_state);
/**
+ * drm_atomic_get_old_mst_topology_state: get old MST topology state in atomic state, if any
+ * @state: global atomic state
+ * @mgr: MST topology manager, also the private object in this case
+ *
+ * This function wraps drm_atomic_get_old_private_obj_state() passing in the MST atomic
+ * state vtable so that the private object state returned is that of a MST
+ * topology object.
+ *
+ * Returns:
+ *
+ * The old MST topology state, or NULL if there's no topology state for this MST mgr
+ * in the global atomic state
+ */
+struct drm_dp_mst_topology_state *
+drm_atomic_get_old_mst_topology_state(struct drm_atomic_state *state,
+ struct drm_dp_mst_topology_mgr *mgr)
+{
+ struct drm_private_state *old_priv_state =
+ drm_atomic_get_old_private_obj_state(state, &mgr->base);
+
+ return old_priv_state ? to_dp_mst_topology_state(old_priv_state) : NULL;
+}
+EXPORT_SYMBOL(drm_atomic_get_old_mst_topology_state);
+
+/**
* drm_atomic_get_new_mst_topology_state: get new MST topology state in atomic state, if any
* @state: global atomic state
* @mgr: MST topology manager, also the private object in this case
*
- * This function wraps drm_atomic_get_priv_obj_state() passing in the MST atomic
+ * This function wraps drm_atomic_get_new_private_obj_state() passing in the MST atomic
* state vtable so that the private object state returned is that of a MST
* topology object.
*
* Returns:
*
- * The MST topology state, or NULL if there's no topology state for this MST mgr
+ * The new MST topology state, or NULL if there's no topology state for this MST mgr
* in the global atomic state
*/
struct drm_dp_mst_topology_state *
drm_atomic_get_new_mst_topology_state(struct drm_atomic_state *state,
struct drm_dp_mst_topology_mgr *mgr)
{
- struct drm_private_state *priv_state =
+ struct drm_private_state *new_priv_state =
drm_atomic_get_new_private_obj_state(state, &mgr->base);
- return priv_state ? to_dp_mst_topology_state(priv_state) : NULL;
+ return new_priv_state ? to_dp_mst_topology_state(new_priv_state) : NULL;
}
EXPORT_SYMBOL(drm_atomic_get_new_mst_topology_state);
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index f197f59f6d99..5457c02ca1ab 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -880,7 +880,7 @@ EXPORT_SYMBOL(drm_atomic_get_private_obj_state);
* or NULL if the private_obj is not part of the global atomic state.
*/
struct drm_private_state *
-drm_atomic_get_old_private_obj_state(struct drm_atomic_state *state,
+drm_atomic_get_old_private_obj_state(const struct drm_atomic_state *state,
struct drm_private_obj *obj)
{
int i;
@@ -902,7 +902,7 @@ EXPORT_SYMBOL(drm_atomic_get_old_private_obj_state);
* or NULL if the private_obj is not part of the global atomic state.
*/
struct drm_private_state *
-drm_atomic_get_new_private_obj_state(struct drm_atomic_state *state,
+drm_atomic_get_new_private_obj_state(const struct drm_atomic_state *state,
struct drm_private_obj *obj)
{
int i;
@@ -934,7 +934,7 @@ EXPORT_SYMBOL(drm_atomic_get_new_private_obj_state);
* not connected.
*/
struct drm_connector *
-drm_atomic_get_old_connector_for_encoder(struct drm_atomic_state *state,
+drm_atomic_get_old_connector_for_encoder(const struct drm_atomic_state *state,
struct drm_encoder *encoder)
{
struct drm_connector_state *conn_state;
@@ -968,7 +968,7 @@ EXPORT_SYMBOL(drm_atomic_get_old_connector_for_encoder);
* not connected.
*/
struct drm_connector *
-drm_atomic_get_new_connector_for_encoder(struct drm_atomic_state *state,
+drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
struct drm_encoder *encoder)
{
struct drm_connector_state *conn_state;
@@ -1117,7 +1117,7 @@ EXPORT_SYMBOL(drm_atomic_get_bridge_state);
* the bridge is not part of the global atomic state.
*/
struct drm_bridge_state *
-drm_atomic_get_old_bridge_state(struct drm_atomic_state *state,
+drm_atomic_get_old_bridge_state(const struct drm_atomic_state *state,
struct drm_bridge *bridge)
{
struct drm_private_state *obj_state;
@@ -1139,7 +1139,7 @@ EXPORT_SYMBOL(drm_atomic_get_old_bridge_state);
* the bridge is not part of the global atomic state.
*/
struct drm_bridge_state *
-drm_atomic_get_new_bridge_state(struct drm_atomic_state *state,
+drm_atomic_get_new_bridge_state(const struct drm_atomic_state *state,
struct drm_bridge *bridge)
{
struct drm_private_state *obj_state;
@@ -1756,8 +1756,8 @@ EXPORT_SYMBOL(drm_state_dump);
#ifdef CONFIG_DEBUG_FS
static int drm_state_info(struct seq_file *m, void *data)
{
- struct drm_info_node *node = (struct drm_info_node *) m->private;
- struct drm_device *dev = node->minor->dev;
+ struct drm_debugfs_entry *entry = m->private;
+ struct drm_device *dev = entry->dev;
struct drm_printer p = drm_seq_file_printer(m);
__drm_state_dump(dev, &p, true);
@@ -1766,14 +1766,13 @@ static int drm_state_info(struct seq_file *m, void *data)
}
/* any use in debugfs files to dump individual planes/crtc/etc? */
-static const struct drm_info_list drm_atomic_debugfs_list[] = {
+static const struct drm_debugfs_info drm_atomic_debugfs_list[] = {
{"state", drm_state_info, 0},
};
void drm_atomic_debugfs_init(struct drm_minor *minor)
{
- drm_debugfs_create_files(drm_atomic_debugfs_list,
- ARRAY_SIZE(drm_atomic_debugfs_list),
- minor->debugfs_root, minor);
+ drm_debugfs_add_files(minor->dev, drm_atomic_debugfs_list,
+ ARRAY_SIZE(drm_atomic_debugfs_list));
}
#endif
diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c
index dfb57217253b..784e63d70a42 100644
--- a/drivers/gpu/drm/drm_atomic_state_helper.c
+++ b/drivers/gpu/drm/drm_atomic_state_helper.c
@@ -482,6 +482,130 @@ void drm_atomic_helper_connector_tv_margins_reset(struct drm_connector *connecto
EXPORT_SYMBOL(drm_atomic_helper_connector_tv_margins_reset);
/**
+ * drm_atomic_helper_connector_tv_reset - Resets Analog TV connector properties
+ * @connector: DRM connector
+ *
+ * Resets the analog TV properties attached to a connector
+ */
+void drm_atomic_helper_connector_tv_reset(struct drm_connector *connector)
+{
+ struct drm_device *dev = connector->dev;
+ struct drm_cmdline_mode *cmdline = &connector->cmdline_mode;
+ struct drm_connector_state *state = connector->state;
+ struct drm_property *prop;
+ uint64_t val;
+
+ prop = dev->mode_config.tv_mode_property;
+ if (prop)
+ if (!drm_object_property_get_default_value(&connector->base,
+ prop, &val))
+ state->tv.mode = val;
+
+ if (cmdline->tv_mode_specified)
+ state->tv.mode = cmdline->tv_mode;
+
+ prop = dev->mode_config.tv_select_subconnector_property;
+ if (prop)
+ if (!drm_object_property_get_default_value(&connector->base,
+ prop, &val))
+ state->tv.select_subconnector = val;
+
+ prop = dev->mode_config.tv_subconnector_property;
+ if (prop)
+ if (!drm_object_property_get_default_value(&connector->base,
+ prop, &val))
+ state->tv.subconnector = val;
+
+ prop = dev->mode_config.tv_brightness_property;
+ if (prop)
+ if (!drm_object_property_get_default_value(&connector->base,
+ prop, &val))
+ state->tv.brightness = val;
+
+ prop = dev->mode_config.tv_contrast_property;
+ if (prop)
+ if (!drm_object_property_get_default_value(&connector->base,
+ prop, &val))
+ state->tv.contrast = val;
+
+ prop = dev->mode_config.tv_flicker_reduction_property;
+ if (prop)
+ if (!drm_object_property_get_default_value(&connector->base,
+ prop, &val))
+ state->tv.flicker_reduction = val;
+
+ prop = dev->mode_config.tv_overscan_property;
+ if (prop)
+ if (!drm_object_property_get_default_value(&connector->base,
+ prop, &val))
+ state->tv.overscan = val;
+
+ prop = dev->mode_config.tv_saturation_property;
+ if (prop)
+ if (!drm_object_property_get_default_value(&connector->base,
+ prop, &val))
+ state->tv.saturation = val;
+
+ prop = dev->mode_config.tv_hue_property;
+ if (prop)
+ if (!drm_object_property_get_default_value(&connector->base,
+ prop, &val))
+ state->tv.hue = val;
+
+ drm_atomic_helper_connector_tv_margins_reset(connector);
+}
+EXPORT_SYMBOL(drm_atomic_helper_connector_tv_reset);
+
+/**
+ * drm_atomic_helper_connector_tv_check - Validate an analog TV connector state
+ * @connector: DRM Connector
+ * @state: the DRM State object
+ *
+ * Checks the state object to see if the requested state is valid for an
+ * analog TV connector.
+ *
+ * Return:
+ * %0 for success, a negative error code on error.
+ */
+int drm_atomic_helper_connector_tv_check(struct drm_connector *connector,
+ struct drm_atomic_state *state)
+{
+ struct drm_connector_state *old_conn_state =
+ drm_atomic_get_old_connector_state(state, connector);
+ struct drm_connector_state *new_conn_state =
+ drm_atomic_get_new_connector_state(state, connector);
+ struct drm_crtc_state *crtc_state;
+ struct drm_crtc *crtc;
+
+ crtc = new_conn_state->crtc;
+ if (!crtc)
+ return 0;
+
+ crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+ if (!crtc_state)
+ return -EINVAL;
+
+ if (old_conn_state->tv.mode != new_conn_state->tv.mode)
+ crtc_state->mode_changed = true;
+
+ if (old_conn_state->tv.margins.left != new_conn_state->tv.margins.left ||
+ old_conn_state->tv.margins.right != new_conn_state->tv.margins.right ||
+ old_conn_state->tv.margins.top != new_conn_state->tv.margins.top ||
+ old_conn_state->tv.margins.bottom != new_conn_state->tv.margins.bottom ||
+ old_conn_state->tv.mode != new_conn_state->tv.mode ||
+ old_conn_state->tv.brightness != new_conn_state->tv.brightness ||
+ old_conn_state->tv.contrast != new_conn_state->tv.contrast ||
+ old_conn_state->tv.flicker_reduction != new_conn_state->tv.flicker_reduction ||
+ old_conn_state->tv.overscan != new_conn_state->tv.overscan ||
+ old_conn_state->tv.saturation != new_conn_state->tv.saturation ||
+ old_conn_state->tv.hue != new_conn_state->tv.hue)
+ crtc_state->connectors_changed = true;
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_atomic_helper_connector_tv_check);
+
+/**
* __drm_atomic_helper_connector_duplicate_state - copy atomic connector state
* @connector: connector object
* @state: atomic connector state
diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
index c06d0639d552..d867e7f9f2cd 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -698,6 +698,8 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector,
state->tv.margins.top = val;
} else if (property == config->tv_bottom_margin_property) {
state->tv.margins.bottom = val;
+ } else if (property == config->legacy_tv_mode_property) {
+ state->tv.legacy_mode = val;
} else if (property == config->tv_mode_property) {
state->tv.mode = val;
} else if (property == config->tv_brightness_property) {
@@ -808,6 +810,8 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
*val = state->tv.margins.top;
} else if (property == config->tv_bottom_margin_property) {
*val = state->tv.margins.bottom;
+ } else if (property == config->legacy_tv_mode_property) {
+ *val = state->tv.legacy_mode;
} else if (property == config->tv_mode_property) {
*val = state->tv.mode;
} else if (property == config->tv_brightness_property) {
diff --git a/drivers/gpu/drm/drm_blend.c b/drivers/gpu/drm/drm_blend.c
index b4c8cab7158c..6e74de833466 100644
--- a/drivers/gpu/drm/drm_blend.c
+++ b/drivers/gpu/drm/drm_blend.c
@@ -450,8 +450,8 @@ static int drm_atomic_helper_crtc_normalize_zpos(struct drm_crtc *crtc,
int i, n = 0;
int ret = 0;
- DRM_DEBUG_ATOMIC("[CRTC:%d:%s] calculating normalized zpos values\n",
- crtc->base.id, crtc->name);
+ drm_dbg_atomic(dev, "[CRTC:%d:%s] calculating normalized zpos values\n",
+ crtc->base.id, crtc->name);
states = kmalloc_array(total_planes, sizeof(*states), GFP_KERNEL);
if (!states)
@@ -469,9 +469,8 @@ static int drm_atomic_helper_crtc_normalize_zpos(struct drm_crtc *crtc,
goto done;
}
states[n++] = plane_state;
- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] processing zpos value %d\n",
- plane->base.id, plane->name,
- plane_state->zpos);
+ drm_dbg_atomic(dev, "[PLANE:%d:%s] processing zpos value %d\n",
+ plane->base.id, plane->name, plane_state->zpos);
}
sort(states, n, sizeof(*states), drm_atomic_state_zpos_cmp, NULL);
@@ -480,8 +479,8 @@ static int drm_atomic_helper_crtc_normalize_zpos(struct drm_crtc *crtc,
plane = states[i]->plane;
states[i]->normalized_zpos = i;
- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] normalized zpos value %d\n",
- plane->base.id, plane->name, i);
+ drm_dbg_atomic(dev, "[PLANE:%d:%s] normalized zpos value %d\n",
+ plane->base.id, plane->name, i);
}
crtc_state->zpos_changed = true;
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 1545c50fd1c8..c3d69af02e79 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -153,6 +153,45 @@
* situation when probing.
*/
+/**
+ * DOC: dsi bridge operations
+ *
+ * DSI host interfaces are expected to be implemented as bridges rather than
+ * encoders, however there are a few aspects of their operation that need to
+ * be defined in order to provide a consistent interface.
+ *
+ * A DSI host should keep the PHY powered down until the pre_enable operation is
+ * called. All lanes are in an undefined idle state up to this point, and it
+ * must not be assumed that it is LP-11.
+ * pre_enable should initialise the PHY, set the data lanes to LP-11, and the
+ * clock lane to either LP-11 or HS depending on the mode_flag
+ * %MIPI_DSI_CLOCK_NON_CONTINUOUS.
+ *
+ * Ordinarily the downstream bridge DSI peripheral pre_enable will have been
+ * called before the DSI host. If the DSI peripheral requires LP-11 and/or
+ * the clock lane to be in HS mode prior to pre_enable, then it can set the
+ * &pre_enable_prev_first flag to request the pre_enable (and
+ * post_disable) order to be altered to enable the DSI host first.
+ *
+ * Either the CRTC being enabled, or the DSI host enable operation should switch
+ * the host to actively transmitting video on the data lanes.
+ *
+ * The reverse also applies. The DSI host disable operation or stopping the CRTC
+ * should stop transmitting video, and the data lanes should return to the LP-11
+ * state. The DSI host &post_disable operation should disable the PHY.
+ * If the &pre_enable_prev_first flag is set, then the DSI peripheral's
+ * bridge &post_disable will be called before the DSI host's post_disable.
+ *
+ * Whilst it is valid to call &host_transfer prior to pre_enable or after
+ * post_disable, the exact state of the lanes is undefined at this point. The
+ * DSI host should initialise the interface, transmit the data, and then disable
+ * the interface again.
+ *
+ * Ultra Low Power State (ULPS) is not explicitly supported by DRM. If
+ * implemented, it therefore needs to be handled entirely within the DSI Host
+ * driver.
+ */
+
static DEFINE_MUTEX(bridge_lock);
static LIST_HEAD(bridge_list);
@@ -510,61 +549,6 @@ drm_bridge_chain_mode_valid(struct drm_bridge *bridge,
EXPORT_SYMBOL(drm_bridge_chain_mode_valid);
/**
- * drm_bridge_chain_disable - disables all bridges in the encoder chain
- * @bridge: bridge control structure
- *
- * Calls &drm_bridge_funcs.disable op for all the bridges in the encoder
- * chain, starting from the last bridge to the first. These are called before
- * calling the encoder's prepare op.
- *
- * Note: the bridge passed should be the one closest to the encoder
- */
-void drm_bridge_chain_disable(struct drm_bridge *bridge)
-{
- struct drm_encoder *encoder;
- struct drm_bridge *iter;
-
- if (!bridge)
- return;
-
- encoder = bridge->encoder;
- list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
- if (iter->funcs->disable)
- iter->funcs->disable(iter);
-
- if (iter == bridge)
- break;
- }
-}
-EXPORT_SYMBOL(drm_bridge_chain_disable);
-
-/**
- * drm_bridge_chain_post_disable - cleans up after disabling all bridges in the
- * encoder chain
- * @bridge: bridge control structure
- *
- * Calls &drm_bridge_funcs.post_disable op for all the bridges in the
- * encoder chain, starting from the first bridge to the last. These are called
- * after completing the encoder's prepare op.
- *
- * Note: the bridge passed should be the one closest to the encoder
- */
-void drm_bridge_chain_post_disable(struct drm_bridge *bridge)
-{
- struct drm_encoder *encoder;
-
- if (!bridge)
- return;
-
- encoder = bridge->encoder;
- list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
- if (bridge->funcs->post_disable)
- bridge->funcs->post_disable(bridge);
- }
-}
-EXPORT_SYMBOL(drm_bridge_chain_post_disable);
-
-/**
* drm_bridge_chain_mode_set - set proposed mode for all bridges in the
* encoder chain
* @bridge: bridge control structure
@@ -594,61 +578,6 @@ void drm_bridge_chain_mode_set(struct drm_bridge *bridge,
EXPORT_SYMBOL(drm_bridge_chain_mode_set);
/**
- * drm_bridge_chain_pre_enable - prepares for enabling all bridges in the
- * encoder chain
- * @bridge: bridge control structure
- *
- * Calls &drm_bridge_funcs.pre_enable op for all the bridges in the encoder
- * chain, starting from the last bridge to the first. These are called
- * before calling the encoder's commit op.
- *
- * Note: the bridge passed should be the one closest to the encoder
- */
-void drm_bridge_chain_pre_enable(struct drm_bridge *bridge)
-{
- struct drm_encoder *encoder;
- struct drm_bridge *iter;
-
- if (!bridge)
- return;
-
- encoder = bridge->encoder;
- list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
- if (iter->funcs->pre_enable)
- iter->funcs->pre_enable(iter);
-
- if (iter == bridge)
- break;
- }
-}
-EXPORT_SYMBOL(drm_bridge_chain_pre_enable);
-
-/**
- * drm_bridge_chain_enable - enables all bridges in the encoder chain
- * @bridge: bridge control structure
- *
- * Calls &drm_bridge_funcs.enable op for all the bridges in the encoder
- * chain, starting from the first bridge to the last. These are called
- * after completing the encoder's commit op.
- *
- * Note that the bridge passed should be the one closest to the encoder
- */
-void drm_bridge_chain_enable(struct drm_bridge *bridge)
-{
- struct drm_encoder *encoder;
-
- if (!bridge)
- return;
-
- encoder = bridge->encoder;
- list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
- if (bridge->funcs->enable)
- bridge->funcs->enable(bridge);
- }
-}
-EXPORT_SYMBOL(drm_bridge_chain_enable);
-
-/**
* drm_atomic_bridge_chain_disable - disables all bridges in the encoder chain
* @bridge: bridge control structure
* @old_state: old atomic state
@@ -691,6 +620,25 @@ void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge,
}
EXPORT_SYMBOL(drm_atomic_bridge_chain_disable);
+static void drm_atomic_bridge_call_post_disable(struct drm_bridge *bridge,
+ struct drm_atomic_state *old_state)
+{
+ if (old_state && bridge->funcs->atomic_post_disable) {
+ struct drm_bridge_state *old_bridge_state;
+
+ old_bridge_state =
+ drm_atomic_get_old_bridge_state(old_state,
+ bridge);
+ if (WARN_ON(!old_bridge_state))
+ return;
+
+ bridge->funcs->atomic_post_disable(bridge,
+ old_bridge_state);
+ } else if (bridge->funcs->post_disable) {
+ bridge->funcs->post_disable(bridge);
+ }
+}
+
/**
* drm_atomic_bridge_chain_post_disable - cleans up after disabling all bridges
* in the encoder chain
@@ -702,36 +650,86 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_disable);
* starting from the first bridge to the last. These are called after completing
* &drm_encoder_helper_funcs.atomic_disable
*
+ * If a bridge sets @pre_enable_prev_first, then the @post_disable for that
+ * bridge will be called before the previous one to reverse the @pre_enable
+ * calling direction.
+ *
* Note: the bridge passed should be the one closest to the encoder
*/
void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge,
struct drm_atomic_state *old_state)
{
struct drm_encoder *encoder;
+ struct drm_bridge *next, *limit;
if (!bridge)
return;
encoder = bridge->encoder;
+
list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
- if (bridge->funcs->atomic_post_disable) {
- struct drm_bridge_state *old_bridge_state;
+ limit = NULL;
+
+ if (!list_is_last(&bridge->chain_node, &encoder->bridge_chain)) {
+ next = list_next_entry(bridge, chain_node);
+
+ if (next->pre_enable_prev_first) {
+ /* next bridge had requested that prev
+ * was enabled first, so disabled last
+ */
+ limit = next;
+
+ /* Find the next bridge that has NOT requested
+ * prev to be enabled first / disabled last
+ */
+ list_for_each_entry_from(next, &encoder->bridge_chain,
+ chain_node) {
+ if (next->pre_enable_prev_first) {
+ next = list_prev_entry(next, chain_node);
+ limit = next;
+ break;
+ }
+ }
+
+ /* Call these bridges in reverse order */
+ list_for_each_entry_from_reverse(next, &encoder->bridge_chain,
+ chain_node) {
+ if (next == bridge)
+ break;
+
+ drm_atomic_bridge_call_post_disable(next,
+ old_state);
+ }
+ }
+ }
- old_bridge_state =
- drm_atomic_get_old_bridge_state(old_state,
- bridge);
- if (WARN_ON(!old_bridge_state))
- return;
+ drm_atomic_bridge_call_post_disable(bridge, old_state);
- bridge->funcs->atomic_post_disable(bridge,
- old_bridge_state);
- } else if (bridge->funcs->post_disable) {
- bridge->funcs->post_disable(bridge);
- }
+ if (limit)
+ /* Jump all bridges that we have already post_disabled */
+ bridge = limit;
}
}
EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable);
+static void drm_atomic_bridge_call_pre_enable(struct drm_bridge *bridge,
+ struct drm_atomic_state *old_state)
+{
+ if (old_state && bridge->funcs->atomic_pre_enable) {
+ struct drm_bridge_state *old_bridge_state;
+
+ old_bridge_state =
+ drm_atomic_get_old_bridge_state(old_state,
+ bridge);
+ if (WARN_ON(!old_bridge_state))
+ return;
+
+ bridge->funcs->atomic_pre_enable(bridge, old_bridge_state);
+ } else if (bridge->funcs->pre_enable) {
+ bridge->funcs->pre_enable(bridge);
+ }
+}
+
/**
* drm_atomic_bridge_chain_pre_enable - prepares for enabling all bridges in
* the encoder chain
@@ -743,32 +741,60 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable);
* starting from the last bridge to the first. These are called before calling
* &drm_encoder_helper_funcs.atomic_enable
*
+ * If a bridge sets @pre_enable_prev_first, then the pre_enable for the
+ * prev bridge will be called before pre_enable of this bridge.
+ *
* Note: the bridge passed should be the one closest to the encoder
*/
void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge,
struct drm_atomic_state *old_state)
{
struct drm_encoder *encoder;
- struct drm_bridge *iter;
+ struct drm_bridge *iter, *next, *limit;
if (!bridge)
return;
encoder = bridge->encoder;
+
list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
- if (iter->funcs->atomic_pre_enable) {
- struct drm_bridge_state *old_bridge_state;
+ if (iter->pre_enable_prev_first) {
+ next = iter;
+ limit = bridge;
+ list_for_each_entry_from_reverse(next,
+ &encoder->bridge_chain,
+ chain_node) {
+ if (next == bridge)
+ break;
+
+ if (!next->pre_enable_prev_first) {
+ /* Found first bridge that does NOT
+ * request prev to be enabled first
+ */
+ limit = list_prev_entry(next, chain_node);
+ break;
+ }
+ }
+
+ list_for_each_entry_from(next, &encoder->bridge_chain, chain_node) {
+ /* Call requested prev bridge pre_enable
+ * in order.
+ */
+ if (next == iter)
+ /* At the first bridge to request prev
+ * bridges called first.
+ */
+ break;
+
+ drm_atomic_bridge_call_pre_enable(next, old_state);
+ }
+ }
- old_bridge_state =
- drm_atomic_get_old_bridge_state(old_state,
- iter);
- if (WARN_ON(!old_bridge_state))
- return;
+ drm_atomic_bridge_call_pre_enable(iter, old_state);
- iter->funcs->atomic_pre_enable(iter, old_bridge_state);
- } else if (iter->funcs->pre_enable) {
- iter->funcs->pre_enable(iter);
- }
+ if (iter->pre_enable_prev_first)
+ /* Jump all bridges that we have already pre_enabled */
+ iter = limit;
if (iter == bridge)
break;
diff --git a/drivers/gpu/drm/drm_bridge_connector.c b/drivers/gpu/drm/drm_bridge_connector.c
index 1c7d936523df..19ae4a177ac3 100644
--- a/drivers/gpu/drm/drm_bridge_connector.c
+++ b/drivers/gpu/drm/drm_bridge_connector.c
@@ -128,14 +128,7 @@ static void drm_bridge_connector_hpd_cb(void *cb_data,
drm_kms_helper_hotplug_event(dev);
}
-/**
- * drm_bridge_connector_enable_hpd - Enable hot-plug detection for the connector
- * @connector: The DRM bridge connector
- *
- * This function enables hot-plug detection for the given bridge connector.
- * This is typically used by display drivers in their resume handler.
- */
-void drm_bridge_connector_enable_hpd(struct drm_connector *connector)
+static void drm_bridge_connector_enable_hpd(struct drm_connector *connector)
{
struct drm_bridge_connector *bridge_connector =
to_drm_bridge_connector(connector);
@@ -145,17 +138,8 @@ void drm_bridge_connector_enable_hpd(struct drm_connector *connector)
drm_bridge_hpd_enable(hpd, drm_bridge_connector_hpd_cb,
bridge_connector);
}
-EXPORT_SYMBOL_GPL(drm_bridge_connector_enable_hpd);
-/**
- * drm_bridge_connector_disable_hpd - Disable hot-plug detection for the
- * connector
- * @connector: The DRM bridge connector
- *
- * This function disables hot-plug detection for the given bridge connector.
- * This is typically used by display drivers in their suspend handler.
- */
-void drm_bridge_connector_disable_hpd(struct drm_connector *connector)
+static void drm_bridge_connector_disable_hpd(struct drm_connector *connector)
{
struct drm_bridge_connector *bridge_connector =
to_drm_bridge_connector(connector);
@@ -164,7 +148,6 @@ void drm_bridge_connector_disable_hpd(struct drm_connector *connector)
if (hpd)
drm_bridge_hpd_disable(hpd);
}
-EXPORT_SYMBOL_GPL(drm_bridge_connector_disable_hpd);
/* -----------------------------------------------------------------------------
* Bridge Connector Functions
@@ -305,6 +288,8 @@ static int drm_bridge_connector_get_modes(struct drm_connector *connector)
static const struct drm_connector_helper_funcs drm_bridge_connector_helper_funcs = {
.get_modes = drm_bridge_connector_get_modes,
/* No need for .mode_valid(), the bridges are checked by the core. */
+ .enable_hpd = drm_bridge_connector_enable_hpd,
+ .disable_hpd = drm_bridge_connector_disable_hpd,
};
/* -----------------------------------------------------------------------------
@@ -387,10 +372,8 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
connector_type, ddc);
drm_connector_helper_add(connector, &drm_bridge_connector_helper_funcs);
- if (bridge_connector->bridge_hpd) {
+ if (bridge_connector->bridge_hpd)
connector->polled = DRM_CONNECTOR_POLL_HPD;
- drm_bridge_connector_enable_hpd(connector);
- }
else if (bridge_connector->bridge_detect)
connector->polled = DRM_CONNECTOR_POLL_CONNECT
| DRM_CONNECTOR_POLL_DISCONNECT;
diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c
index fcca21e8efac..86700560fea2 100644
--- a/drivers/gpu/drm/drm_bufs.c
+++ b/drivers/gpu/drm/drm_bufs.c
@@ -423,8 +423,7 @@ int drm_legacy_addmap_ioctl(struct drm_device *dev, void *data,
if (!(capable(CAP_SYS_ADMIN) || map->type == _DRM_AGP || map->type == _DRM_SHM))
return -EPERM;
- if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
- !drm_core_check_feature(dev, DRIVER_LEGACY))
+ if (!drm_core_check_feature(dev, DRIVER_LEGACY))
return -EOPNOTSUPP;
err = drm_addmap_core(dev, map->offset, map->size, map->type,
@@ -469,8 +468,7 @@ int drm_legacy_getmap_ioctl(struct drm_device *dev, void *data,
int idx;
int i;
- if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
- !drm_core_check_feature(dev, DRIVER_LEGACY))
+ if (!drm_core_check_feature(dev, DRIVER_LEGACY))
return -EOPNOTSUPP;
idx = map->offset;
@@ -570,8 +568,7 @@ EXPORT_SYMBOL(drm_legacy_rmmap_locked);
void drm_legacy_rmmap(struct drm_device *dev, struct drm_local_map *map)
{
- if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
- !drm_core_check_feature(dev, DRIVER_LEGACY))
+ if (!drm_core_check_feature(dev, DRIVER_LEGACY))
return;
mutex_lock(&dev->struct_mutex);
@@ -628,8 +625,7 @@ int drm_legacy_rmmap_ioctl(struct drm_device *dev, void *data,
struct drm_map_list *r_list;
int ret;
- if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
- !drm_core_check_feature(dev, DRIVER_LEGACY))
+ if (!drm_core_check_feature(dev, DRIVER_LEGACY))
return -EOPNOTSUPP;
mutex_lock(&dev->struct_mutex);
diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
index 056ab9d5f313..f6292ba0e6fc 100644
--- a/drivers/gpu/drm/drm_client.c
+++ b/drivers/gpu/drm/drm_client.c
@@ -198,13 +198,23 @@ void drm_client_dev_hotplug(struct drm_device *dev)
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return;
+ if (!dev->mode_config.num_connector) {
+ drm_dbg_kms(dev, "No connectors found, will not send hotplug events!\n");
+ return;
+ }
+
mutex_lock(&dev->clientlist_mutex);
list_for_each_entry(client, &dev->clientlist, list) {
if (!client->funcs || !client->funcs->hotplug)
continue;
+ if (client->hotplug_failed)
+ continue;
+
ret = client->funcs->hotplug(client);
drm_dbg_kms(dev, "%s: ret=%d\n", client->name, ret);
+ if (ret)
+ client->hotplug_failed = true;
}
mutex_unlock(&dev->clientlist_mutex);
}
@@ -487,8 +497,8 @@ EXPORT_SYMBOL(drm_client_framebuffer_flush);
#ifdef CONFIG_DEBUG_FS
static int drm_client_debugfs_internal_clients(struct seq_file *m, void *data)
{
- struct drm_info_node *node = m->private;
- struct drm_device *dev = node->minor->dev;
+ struct drm_debugfs_entry *entry = m->private;
+ struct drm_device *dev = entry->dev;
struct drm_printer p = drm_seq_file_printer(m);
struct drm_client_dev *client;
@@ -500,14 +510,13 @@ static int drm_client_debugfs_internal_clients(struct seq_file *m, void *data)
return 0;
}
-static const struct drm_info_list drm_client_debugfs_list[] = {
+static const struct drm_debugfs_info drm_client_debugfs_list[] = {
{ "internal_clients", drm_client_debugfs_internal_clients, 0 },
};
void drm_client_debugfs_init(struct drm_minor *minor)
{
- drm_debugfs_create_files(drm_client_debugfs_list,
- ARRAY_SIZE(drm_client_debugfs_list),
- minor->debugfs_root, minor);
+ drm_debugfs_add_files(minor->dev, drm_client_debugfs_list,
+ ARRAY_SIZE(drm_client_debugfs_list));
}
#endif
diff --git a/drivers/gpu/drm/drm_client_modeset.c b/drivers/gpu/drm/drm_client_modeset.c
index d553e793e673..1b12a3c201a3 100644
--- a/drivers/gpu/drm/drm_client_modeset.c
+++ b/drivers/gpu/drm/drm_client_modeset.c
@@ -188,10 +188,6 @@ static struct drm_display_mode *drm_connector_pick_cmdline_mode(struct drm_conne
prefer_non_interlace = !cmdline_mode->interlace;
again:
list_for_each_entry(mode, &connector->modes, head) {
- /* Check (optional) mode name first */
- if (!strcmp(mode->name, cmdline_mode->name))
- return mode;
-
/* check width/height */
if (mode->hdisplay != cmdline_mode->xres ||
mode->vdisplay != cmdline_mode->yres)
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 547356e00341..9d0250c28e9b 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -565,6 +565,7 @@ void drm_connector_cleanup(struct drm_connector *connector)
ida_free(&dev->mode_config.connector_ida, connector->index);
kfree(connector->display_info.bus_formats);
+ kfree(connector->display_info.vics);
drm_mode_object_unregister(dev, &connector->base);
kfree(connector->name);
connector->name = NULL;
@@ -984,6 +985,41 @@ static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = {
DRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name,
drm_dvi_i_subconnector_enum_list)
+static const struct drm_prop_enum_list drm_tv_mode_enum_list[] = {
+ { DRM_MODE_TV_MODE_NTSC, "NTSC" },
+ { DRM_MODE_TV_MODE_NTSC_443, "NTSC-443" },
+ { DRM_MODE_TV_MODE_NTSC_J, "NTSC-J" },
+ { DRM_MODE_TV_MODE_PAL, "PAL" },
+ { DRM_MODE_TV_MODE_PAL_M, "PAL-M" },
+ { DRM_MODE_TV_MODE_PAL_N, "PAL-N" },
+ { DRM_MODE_TV_MODE_SECAM, "SECAM" },
+};
+DRM_ENUM_NAME_FN(drm_get_tv_mode_name, drm_tv_mode_enum_list)
+
+/**
+ * drm_get_tv_mode_from_name - Translates a TV mode name into its enum value
+ * @name: TV Mode name we want to convert
+ * @len: Length of @name
+ *
+ * Translates @name into an enum drm_connector_tv_mode.
+ *
+ * Returns: the enum value on success, a negative errno otherwise.
+ */
+int drm_get_tv_mode_from_name(const char *name, size_t len)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(drm_tv_mode_enum_list); i++) {
+ const struct drm_prop_enum_list *item = &drm_tv_mode_enum_list[i];
+
+ if (strlen(item->name) == len && !strncmp(item->name, name, len))
+ return item->type;
+ }
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL(drm_get_tv_mode_from_name);
+
static const struct drm_prop_enum_list drm_tv_select_enum_list[] = {
{ DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */
{ DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
@@ -1552,6 +1588,71 @@ EXPORT_SYMBOL(drm_connector_attach_dp_subconnector_property);
* infoframe values is done through drm_hdmi_avi_infoframe_content_type().
*/
+/*
+ * TODO: Document the properties:
+ * - left margin
+ * - right margin
+ * - top margin
+ * - bottom margin
+ * - brightness
+ * - contrast
+ * - flicker reduction
+ * - hue
+ * - mode
+ * - overscan
+ * - saturation
+ * - select subconnector
+ * - subconnector
+ */
+/**
+ * DOC: Analog TV Connector Properties
+ *
+ * TV Mode:
+ * Indicates the TV Mode used on an analog TV connector. The value
+ * of this property can be one of the following:
+ *
+ * NTSC:
+ * TV Mode is CCIR System M (aka 525-lines) together with
+ * the NTSC Color Encoding.
+ *
+ * NTSC-443:
+ *
+ * TV Mode is CCIR System M (aka 525-lines) together with
+ * the NTSC Color Encoding, but with a color subcarrier
+ * frequency of 4.43MHz
+ *
+ * NTSC-J:
+ *
+ * TV Mode is CCIR System M (aka 525-lines) together with
+ * the NTSC Color Encoding, but with a black level equal to
+ * the blanking level.
+ *
+ * PAL:
+ *
+ * TV Mode is CCIR System B (aka 625-lines) together with
+ * the PAL Color Encoding.
+ *
+ * PAL-M:
+ *
+ * TV Mode is CCIR System M (aka 525-lines) together with
+ * the PAL Color Encoding.
+ *
+ * PAL-N:
+ *
+ * TV Mode is CCIR System N together with the PAL Color
+ * Encoding, a color subcarrier frequency of 3.58MHz, the
+ * SECAM color space, and narrower channels than other PAL
+ * variants.
+ *
+ * SECAM:
+ *
+ * TV Mode is CCIR System B (aka 625-lines) together with
+ * the SECAM Color Encoding.
+ *
+ * Drivers can set up this property by calling
+ * drm_mode_create_tv_properties().
+ */
+
/**
* drm_connector_attach_content_type_property - attach content-type property
* @connector: connector to attach content type property on.
@@ -1604,7 +1705,7 @@ EXPORT_SYMBOL(drm_connector_attach_tv_margin_properties);
* Called by a driver's HDMI connector initialization routine, this function
* creates the TV margin properties for a given device. No need to call this
* function for an SDTV connector, it's already called from
- * drm_mode_create_tv_properties().
+ * drm_mode_create_tv_properties_legacy().
*
* Returns:
* 0 on success or a negative error code on failure.
@@ -1639,7 +1740,7 @@ int drm_mode_create_tv_margin_properties(struct drm_device *dev)
EXPORT_SYMBOL(drm_mode_create_tv_margin_properties);
/**
- * drm_mode_create_tv_properties - create TV specific connector properties
+ * drm_mode_create_tv_properties_legacy - create TV specific connector properties
* @dev: DRM device
* @num_modes: number of different TV formats (modes) supported
* @modes: array of pointers to strings containing name of each format
@@ -1649,12 +1750,16 @@ EXPORT_SYMBOL(drm_mode_create_tv_margin_properties);
* responsible for allocating a list of format names and passing them to
* this routine.
*
+ * NOTE: This functions registers the deprecated "mode" connector
+ * property to select the analog TV mode (ie, NTSC, PAL, etc.). New
+ * drivers must use drm_mode_create_tv_properties() instead.
+ *
* Returns:
* 0 on success or a negative error code on failure.
*/
-int drm_mode_create_tv_properties(struct drm_device *dev,
- unsigned int num_modes,
- const char * const modes[])
+int drm_mode_create_tv_properties_legacy(struct drm_device *dev,
+ unsigned int num_modes,
+ const char * const modes[])
{
struct drm_property *tv_selector;
struct drm_property *tv_subconnector;
@@ -1690,15 +1795,17 @@ int drm_mode_create_tv_properties(struct drm_device *dev,
if (drm_mode_create_tv_margin_properties(dev))
goto nomem;
- dev->mode_config.tv_mode_property =
- drm_property_create(dev, DRM_MODE_PROP_ENUM,
- "mode", num_modes);
- if (!dev->mode_config.tv_mode_property)
- goto nomem;
+ if (num_modes) {
+ dev->mode_config.legacy_tv_mode_property =
+ drm_property_create(dev, DRM_MODE_PROP_ENUM,
+ "mode", num_modes);
+ if (!dev->mode_config.legacy_tv_mode_property)
+ goto nomem;
- for (i = 0; i < num_modes; i++)
- drm_property_add_enum(dev->mode_config.tv_mode_property,
- i, modes[i]);
+ for (i = 0; i < num_modes; i++)
+ drm_property_add_enum(dev->mode_config.legacy_tv_mode_property,
+ i, modes[i]);
+ }
dev->mode_config.tv_brightness_property =
drm_property_create_range(dev, 0, "brightness", 0, 100);
@@ -1734,6 +1841,47 @@ int drm_mode_create_tv_properties(struct drm_device *dev,
nomem:
return -ENOMEM;
}
+EXPORT_SYMBOL(drm_mode_create_tv_properties_legacy);
+
+/**
+ * drm_mode_create_tv_properties - create TV specific connector properties
+ * @dev: DRM device
+ * @supported_tv_modes: Bitmask of TV modes supported (See DRM_MODE_TV_MODE_*)
+ *
+ * Called by a driver's TV initialization routine, this function creates
+ * the TV specific connector properties for a given device.
+ *
+ * Returns:
+ * 0 on success or a negative error code on failure.
+ */
+int drm_mode_create_tv_properties(struct drm_device *dev,
+ unsigned int supported_tv_modes)
+{
+ struct drm_prop_enum_list tv_mode_list[DRM_MODE_TV_MODE_MAX];
+ struct drm_property *tv_mode;
+ unsigned int i, len = 0;
+
+ if (dev->mode_config.tv_mode_property)
+ return 0;
+
+ for (i = 0; i < DRM_MODE_TV_MODE_MAX; i++) {
+ if (!(supported_tv_modes & BIT(i)))
+ continue;
+
+ tv_mode_list[len].type = i;
+ tv_mode_list[len].name = drm_get_tv_mode_name(i);
+ len++;
+ }
+
+ tv_mode = drm_property_create_enum(dev, 0, "TV mode",
+ tv_mode_list, len);
+ if (!tv_mode)
+ return -ENOMEM;
+
+ dev->mode_config.tv_mode_property = tv_mode;
+
+ return drm_mode_create_tv_properties_legacy(dev, 0, NULL);
+}
EXPORT_SYMBOL(drm_mode_create_tv_properties);
/**
diff --git a/drivers/gpu/drm/drm_context.c b/drivers/gpu/drm/drm_context.c
index c6e6a3e7219a..a0fc779e5e1e 100644
--- a/drivers/gpu/drm/drm_context.c
+++ b/drivers/gpu/drm/drm_context.c
@@ -59,8 +59,7 @@ struct drm_ctx_list {
*/
void drm_legacy_ctxbitmap_free(struct drm_device * dev, int ctx_handle)
{
- if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
- !drm_core_check_feature(dev, DRIVER_LEGACY))
+ if (!drm_core_check_feature(dev, DRIVER_LEGACY))
return;
mutex_lock(&dev->struct_mutex);
@@ -97,8 +96,7 @@ static int drm_legacy_ctxbitmap_next(struct drm_device * dev)
*/
void drm_legacy_ctxbitmap_init(struct drm_device * dev)
{
- if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
- !drm_core_check_feature(dev, DRIVER_LEGACY))
+ if (!drm_core_check_feature(dev, DRIVER_LEGACY))
return;
idr_init(&dev->ctx_idr);
@@ -114,8 +112,7 @@ void drm_legacy_ctxbitmap_init(struct drm_device * dev)
*/
void drm_legacy_ctxbitmap_cleanup(struct drm_device * dev)
{
- if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
- !drm_core_check_feature(dev, DRIVER_LEGACY))
+ if (!drm_core_check_feature(dev, DRIVER_LEGACY))
return;
mutex_lock(&dev->struct_mutex);
@@ -136,8 +133,7 @@ void drm_legacy_ctxbitmap_flush(struct drm_device *dev, struct drm_file *file)
{
struct drm_ctx_list *pos, *tmp;
- if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
- !drm_core_check_feature(dev, DRIVER_LEGACY))
+ if (!drm_core_check_feature(dev, DRIVER_LEGACY))
return;
mutex_lock(&dev->ctxlist_mutex);
@@ -182,8 +178,7 @@ int drm_legacy_getsareactx(struct drm_device *dev, void *data,
struct drm_local_map *map;
struct drm_map_list *_entry;
- if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
- !drm_core_check_feature(dev, DRIVER_LEGACY))
+ if (!drm_core_check_feature(dev, DRIVER_LEGACY))
return -EOPNOTSUPP;
mutex_lock(&dev->struct_mutex);
@@ -230,8 +225,7 @@ int drm_legacy_setsareactx(struct drm_device *dev, void *data,
struct drm_local_map *map = NULL;
struct drm_map_list *r_list = NULL;
- if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
- !drm_core_check_feature(dev, DRIVER_LEGACY))
+ if (!drm_core_check_feature(dev, DRIVER_LEGACY))
return -EOPNOTSUPP;
mutex_lock(&dev->struct_mutex);
@@ -335,8 +329,7 @@ int drm_legacy_resctx(struct drm_device *dev, void *data,
struct drm_ctx ctx;
int i;
- if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
- !drm_core_check_feature(dev, DRIVER_LEGACY))
+ if (!drm_core_check_feature(dev, DRIVER_LEGACY))
return -EOPNOTSUPP;
if (res->count >= DRM_RESERVED_CONTEXTS) {
@@ -370,8 +363,7 @@ int drm_legacy_addctx(struct drm_device *dev, void *data,
struct drm_ctx *ctx = data;
int tmp_handle;
- if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
- !drm_core_check_feature(dev, DRIVER_LEGACY))
+ if (!drm_core_check_feature(dev, DRIVER_LEGACY))
return -EOPNOTSUPP;
tmp_handle = drm_legacy_ctxbitmap_next(dev);
@@ -419,8 +411,7 @@ int drm_legacy_getctx(struct drm_device *dev, void *data,
{
struct drm_ctx *ctx = data;
- if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
- !drm_core_check_feature(dev, DRIVER_LEGACY))
+ if (!drm_core_check_feature(dev, DRIVER_LEGACY))
return -EOPNOTSUPP;
/* This is 0, because we don't handle any context flags */
@@ -445,8 +436,7 @@ int drm_legacy_switchctx(struct drm_device *dev, void *data,
{
struct drm_ctx *ctx = data;
- if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
- !drm_core_check_feature(dev, DRIVER_LEGACY))
+ if (!drm_core_check_feature(dev, DRIVER_LEGACY))
return -EOPNOTSUPP;
DRM_DEBUG("%d\n", ctx->handle);
@@ -469,8 +459,7 @@ int drm_legacy_newctx(struct drm_device *dev, void *data,
{
struct drm_ctx *ctx = data;
- if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
- !drm_core_check_feature(dev, DRIVER_LEGACY))
+ if (!drm_core_check_feature(dev, DRIVER_LEGACY))
return -EOPNOTSUPP;
DRM_DEBUG("%d\n", ctx->handle);
@@ -495,8 +484,7 @@ int drm_legacy_rmctx(struct drm_device *dev, void *data,
{
struct drm_ctx *ctx = data;
- if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
- !drm_core_check_feature(dev, DRIVER_LEGACY))
+ if (!drm_core_check_feature(dev, DRIVER_LEGACY))
return -EOPNOTSUPP;
DRM_DEBUG("%d\n", ctx->handle);
diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c
index ee445f4605ba..4f643a490dc3 100644
--- a/drivers/gpu/drm/drm_debugfs.c
+++ b/drivers/gpu/drm/drm_debugfs.c
@@ -38,6 +38,7 @@
#include <drm/drm_edid.h>
#include <drm/drm_file.h>
#include <drm/drm_gem.h>
+#include <drm/drm_managed.h>
#include "drm_crtc_internal.h"
#include "drm_internal.h"
@@ -50,9 +51,8 @@
static int drm_name_info(struct seq_file *m, void *data)
{
- struct drm_info_node *node = (struct drm_info_node *) m->private;
- struct drm_minor *minor = node->minor;
- struct drm_device *dev = minor->dev;
+ struct drm_debugfs_entry *entry = m->private;
+ struct drm_device *dev = entry->dev;
struct drm_master *master;
mutex_lock(&dev->master_mutex);
@@ -72,8 +72,8 @@ static int drm_name_info(struct seq_file *m, void *data)
static int drm_clients_info(struct seq_file *m, void *data)
{
- struct drm_info_node *node = (struct drm_info_node *) m->private;
- struct drm_device *dev = node->minor->dev;
+ struct drm_debugfs_entry *entry = m->private;
+ struct drm_device *dev = entry->dev;
struct drm_file *priv;
kuid_t uid;
@@ -124,8 +124,8 @@ static int drm_gem_one_name_info(int id, void *ptr, void *data)
static int drm_gem_name_info(struct seq_file *m, void *data)
{
- struct drm_info_node *node = (struct drm_info_node *) m->private;
- struct drm_device *dev = node->minor->dev;
+ struct drm_debugfs_entry *entry = m->private;
+ struct drm_device *dev = entry->dev;
seq_printf(m, " name size handles refcount\n");
@@ -136,7 +136,7 @@ static int drm_gem_name_info(struct seq_file *m, void *data)
return 0;
}
-static const struct drm_info_list drm_debugfs_list[] = {
+static const struct drm_debugfs_info drm_debugfs_list[] = {
{"name", drm_name_info, 0},
{"clients", drm_clients_info, 0},
{"gem_names", drm_gem_name_info, DRIVER_GEM},
@@ -151,6 +151,21 @@ static int drm_debugfs_open(struct inode *inode, struct file *file)
return single_open(file, node->info_ent->show, node);
}
+static int drm_debugfs_entry_open(struct inode *inode, struct file *file)
+{
+ struct drm_debugfs_entry *entry = inode->i_private;
+ struct drm_debugfs_info *node = &entry->file;
+
+ return single_open(file, node->show, entry);
+}
+
+static const struct file_operations drm_debugfs_entry_fops = {
+ .owner = THIS_MODULE,
+ .open = drm_debugfs_entry_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
static const struct file_operations drm_debugfs_fops = {
.owner = THIS_MODULE,
@@ -192,7 +207,7 @@ void drm_debugfs_create_files(const struct drm_info_list *files, int count,
tmp->minor = minor;
tmp->dent = debugfs_create_file(files[i].name,
- S_IFREG | S_IRUGO, root, tmp,
+ 0444, root, tmp,
&drm_debugfs_fops);
tmp->info_ent = &files[i];
@@ -207,6 +222,7 @@ int drm_debugfs_init(struct drm_minor *minor, int minor_id,
struct dentry *root)
{
struct drm_device *dev = minor->dev;
+ struct drm_debugfs_entry *entry, *tmp;
char name[64];
INIT_LIST_HEAD(&minor->debugfs_list);
@@ -214,8 +230,7 @@ int drm_debugfs_init(struct drm_minor *minor, int minor_id,
sprintf(name, "%d", minor_id);
minor->debugfs_root = debugfs_create_dir(name, root);
- drm_debugfs_create_files(drm_debugfs_list, DRM_DEBUGFS_ENTRIES,
- minor->debugfs_root, minor);
+ drm_debugfs_add_files(minor->dev, drm_debugfs_list, DRM_DEBUGFS_ENTRIES);
if (drm_drv_uses_atomic_modeset(dev)) {
drm_atomic_debugfs_init(minor);
@@ -230,9 +245,29 @@ int drm_debugfs_init(struct drm_minor *minor, int minor_id,
if (dev->driver->debugfs_init)
dev->driver->debugfs_init(minor);
+ list_for_each_entry_safe(entry, tmp, &dev->debugfs_list, list) {
+ debugfs_create_file(entry->file.name, 0444,
+ minor->debugfs_root, entry, &drm_debugfs_entry_fops);
+ list_del(&entry->list);
+ }
+
return 0;
}
+void drm_debugfs_late_register(struct drm_device *dev)
+{
+ struct drm_minor *minor = dev->primary;
+ struct drm_debugfs_entry *entry, *tmp;
+
+ if (!minor)
+ return;
+
+ list_for_each_entry_safe(entry, tmp, &dev->debugfs_list, list) {
+ debugfs_create_file(entry->file.name, 0444,
+ minor->debugfs_root, entry, &drm_debugfs_entry_fops);
+ list_del(&entry->list);
+ }
+}
int drm_debugfs_remove_files(const struct drm_info_list *files, int count,
struct drm_minor *minor)
@@ -281,6 +316,53 @@ void drm_debugfs_cleanup(struct drm_minor *minor)
minor->debugfs_root = NULL;
}
+/**
+ * drm_debugfs_add_file - Add a given file to the DRM device debugfs file list
+ * @dev: drm device for the ioctl
+ * @name: debugfs file name
+ * @show: show callback
+ * @data: driver-private data, should not be device-specific
+ *
+ * Add a given file entry to the DRM device debugfs file list to be created on
+ * drm_debugfs_init.
+ */
+void drm_debugfs_add_file(struct drm_device *dev, const char *name,
+ int (*show)(struct seq_file*, void*), void *data)
+{
+ struct drm_debugfs_entry *entry = drmm_kzalloc(dev, sizeof(*entry), GFP_KERNEL);
+
+ if (!entry)
+ return;
+
+ entry->file.name = name;
+ entry->file.show = show;
+ entry->file.data = data;
+ entry->dev = dev;
+
+ mutex_lock(&dev->debugfs_mutex);
+ list_add(&entry->list, &dev->debugfs_list);
+ mutex_unlock(&dev->debugfs_mutex);
+}
+EXPORT_SYMBOL(drm_debugfs_add_file);
+
+/**
+ * drm_debugfs_add_files - Add an array of files to the DRM device debugfs file list
+ * @dev: drm device for the ioctl
+ * @files: The array of files to create
+ * @count: The number of files given
+ *
+ * Add a given set of debugfs files represented by an array of
+ * &struct drm_debugfs_info in the DRM device debugfs file list.
+ */
+void drm_debugfs_add_files(struct drm_device *dev, const struct drm_debugfs_info *files, int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++)
+ drm_debugfs_add_file(dev, files[i].name, files[i].show, files[i].data);
+}
+EXPORT_SYMBOL(drm_debugfs_add_files);
+
static int connector_show(struct seq_file *m, void *data)
{
struct drm_connector *connector = m->private;
@@ -426,15 +508,15 @@ void drm_debugfs_connector_add(struct drm_connector *connector)
connector->debugfs_entry = root;
/* force */
- debugfs_create_file("force", S_IRUGO | S_IWUSR, root, connector,
+ debugfs_create_file("force", 0644, root, connector,
&drm_connector_fops);
/* edid */
- debugfs_create_file("edid_override", S_IRUGO | S_IWUSR, root, connector,
+ debugfs_create_file("edid_override", 0644, root, connector,
&drm_edid_fops);
/* vrr range */
- debugfs_create_file("vrr_range", S_IRUGO, root, connector,
+ debugfs_create_file("vrr_range", 0444, root, connector,
&vrr_range_fops);
/* max bpc */
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 73b845a75d52..c6eb8972451a 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -598,6 +598,7 @@ static void drm_dev_init_release(struct drm_device *dev, void *res)
mutex_destroy(&dev->clientlist_mutex);
mutex_destroy(&dev->filelist_mutex);
mutex_destroy(&dev->struct_mutex);
+ mutex_destroy(&dev->debugfs_mutex);
drm_legacy_destroy_members(dev);
}
@@ -638,12 +639,14 @@ static int drm_dev_init(struct drm_device *dev,
INIT_LIST_HEAD(&dev->filelist_internal);
INIT_LIST_HEAD(&dev->clientlist);
INIT_LIST_HEAD(&dev->vblank_event_list);
+ INIT_LIST_HEAD(&dev->debugfs_list);
spin_lock_init(&dev->event_lock);
mutex_init(&dev->struct_mutex);
mutex_init(&dev->filelist_mutex);
mutex_init(&dev->clientlist_mutex);
mutex_init(&dev->master_mutex);
+ mutex_init(&dev->debugfs_mutex);
ret = drmm_add_action_or_reset(dev, drm_dev_init_release, NULL);
if (ret)
@@ -929,8 +932,8 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags)
dev->registered = true;
- if (dev->driver->load) {
- ret = dev->driver->load(dev, flags);
+ if (driver->load) {
+ ret = driver->load(dev, flags);
if (ret)
goto err_minors;
}
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 3841aba17abd..3d0a4da661bc 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -96,7 +96,6 @@ struct detailed_mode_closure {
struct drm_connector *connector;
const struct drm_edid *drm_edid;
bool preferred;
- u32 quirks;
int modes;
};
@@ -2887,9 +2886,9 @@ static u32 edid_get_quirks(const struct drm_edid *drm_edid)
* Walk the mode list for connector, clearing the preferred status on existing
* modes and setting it anew for the right mode ala quirks.
*/
-static void edid_fixup_preferred(struct drm_connector *connector,
- u32 quirks)
+static void edid_fixup_preferred(struct drm_connector *connector)
{
+ const struct drm_display_info *info = &connector->display_info;
struct drm_display_mode *t, *cur_mode, *preferred_mode;
int target_refresh = 0;
int cur_vrefresh, preferred_vrefresh;
@@ -2897,9 +2896,9 @@ static void edid_fixup_preferred(struct drm_connector *connector,
if (list_empty(&connector->probed_modes))
return;
- if (quirks & EDID_QUIRK_PREFER_LARGE_60)
+ if (info->quirks & EDID_QUIRK_PREFER_LARGE_60)
target_refresh = 60;
- if (quirks & EDID_QUIRK_PREFER_LARGE_75)
+ if (info->quirks & EDID_QUIRK_PREFER_LARGE_75)
target_refresh = 75;
preferred_mode = list_first_entry(&connector->probed_modes,
@@ -3401,9 +3400,9 @@ drm_mode_do_interlace_quirk(struct drm_display_mode *mode,
*/
static struct drm_display_mode *drm_mode_detailed(struct drm_connector *connector,
const struct drm_edid *drm_edid,
- const struct detailed_timing *timing,
- u32 quirks)
+ const struct detailed_timing *timing)
{
+ const struct drm_display_info *info = &connector->display_info;
struct drm_device *dev = connector->dev;
struct drm_display_mode *mode;
const struct detailed_pixel_timing *pt = &timing->data.pixel_data;
@@ -3437,7 +3436,7 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_connector *connecto
return NULL;
}
- if (quirks & EDID_QUIRK_FORCE_REDUCED_BLANKING) {
+ if (info->quirks & EDID_QUIRK_FORCE_REDUCED_BLANKING) {
mode = drm_cvt_mode(dev, hactive, vactive, 60, true, false, false);
if (!mode)
return NULL;
@@ -3449,7 +3448,7 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_connector *connecto
if (!mode)
return NULL;
- if (quirks & EDID_QUIRK_135_CLOCK_TOO_HIGH)
+ if (info->quirks & EDID_QUIRK_135_CLOCK_TOO_HIGH)
mode->clock = 1088 * 10;
else
mode->clock = le16_to_cpu(timing->pixel_clock) * 10;
@@ -3472,7 +3471,7 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_connector *connecto
drm_mode_do_interlace_quirk(mode, pt);
- if (quirks & EDID_QUIRK_DETAILED_SYNC_PP) {
+ if (info->quirks & EDID_QUIRK_DETAILED_SYNC_PP) {
mode->flags |= DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC;
} else {
mode->flags |= (pt->misc & DRM_EDID_PT_HSYNC_POSITIVE) ?
@@ -3485,12 +3484,12 @@ set_size:
mode->width_mm = pt->width_mm_lo | (pt->width_height_mm_hi & 0xf0) << 4;
mode->height_mm = pt->height_mm_lo | (pt->width_height_mm_hi & 0xf) << 8;
- if (quirks & EDID_QUIRK_DETAILED_IN_CM) {
+ if (info->quirks & EDID_QUIRK_DETAILED_IN_CM) {
mode->width_mm *= 10;
mode->height_mm *= 10;
}
- if (quirks & EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE) {
+ if (info->quirks & EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE) {
mode->width_mm = drm_edid->edid->width_cm * 10;
mode->height_mm = drm_edid->edid->height_cm * 10;
}
@@ -4003,8 +4002,7 @@ do_detailed_mode(const struct detailed_timing *timing, void *c)
return;
newmode = drm_mode_detailed(closure->connector,
- closure->drm_edid, timing,
- closure->quirks);
+ closure->drm_edid, timing);
if (!newmode)
return;
@@ -4027,15 +4025,13 @@ do_detailed_mode(const struct detailed_timing *timing, void *c)
* add_detailed_modes - Add modes from detailed timings
* @connector: attached connector
* @drm_edid: EDID block to scan
- * @quirks: quirks to apply
*/
static int add_detailed_modes(struct drm_connector *connector,
- const struct drm_edid *drm_edid, u32 quirks)
+ const struct drm_edid *drm_edid)
{
struct detailed_mode_closure closure = {
.connector = connector,
.drm_edid = drm_edid,
- .quirks = quirks,
};
if (drm_edid->edid->revision >= 4)
@@ -4468,28 +4464,20 @@ static u8 svd_to_vic(u8 svd)
return svd;
}
+/*
+ * Return a display mode for the 0-based vic_index'th VIC across all CTA VDBs in
+ * the EDID, or NULL on errors.
+ */
static struct drm_display_mode *
-drm_display_mode_from_vic_index(struct drm_connector *connector,
- const u8 *video_db, u8 video_len,
- u8 video_index)
+drm_display_mode_from_vic_index(struct drm_connector *connector, int vic_index)
{
+ const struct drm_display_info *info = &connector->display_info;
struct drm_device *dev = connector->dev;
- struct drm_display_mode *newmode;
- u8 vic;
-
- if (video_db == NULL || video_index >= video_len)
- return NULL;
- /* CEA modes are numbered 1..127 */
- vic = svd_to_vic(video_db[video_index]);
- if (!drm_valid_cea_vic(vic))
- return NULL;
-
- newmode = drm_mode_duplicate(dev, cea_mode_for_vic(vic));
- if (!newmode)
+ if (!info->vics || vic_index >= info->vics_len || !info->vics[vic_index])
return NULL;
- return newmode;
+ return drm_display_mode_from_cea_vic(dev, info->vics[vic_index]);
}
/*
@@ -4505,10 +4493,8 @@ drm_display_mode_from_vic_index(struct drm_connector *connector,
static int do_y420vdb_modes(struct drm_connector *connector,
const u8 *svds, u8 svds_len)
{
- int modes = 0, i;
struct drm_device *dev = connector->dev;
- struct drm_display_info *info = &connector->display_info;
- struct drm_hdmi_info *hdmi = &info->hdmi;
+ int modes = 0, i;
for (i = 0; i < svds_len; i++) {
u8 vic = svd_to_vic(svds[i]);
@@ -4520,35 +4506,13 @@ static int do_y420vdb_modes(struct drm_connector *connector,
newmode = drm_mode_duplicate(dev, cea_mode_for_vic(vic));
if (!newmode)
break;
- bitmap_set(hdmi->y420_vdb_modes, vic, 1);
drm_mode_probed_add(connector, newmode);
modes++;
}
- if (modes > 0)
- info->color_formats |= DRM_COLOR_FORMAT_YCBCR420;
return modes;
}
-/*
- * drm_add_cmdb_modes - Add a YCBCR 420 mode into bitmap
- * @connector: connector corresponding to the HDMI sink
- * @vic: CEA vic for the video mode to be added in the map
- *
- * Makes an entry for a videomode in the YCBCR 420 bitmap
- */
-static void
-drm_add_cmdb_modes(struct drm_connector *connector, u8 svd)
-{
- u8 vic = svd_to_vic(svd);
- struct drm_hdmi_info *hdmi = &connector->display_info.hdmi;
-
- if (!drm_valid_cea_vic(vic))
- return;
-
- bitmap_set(hdmi->y420_cmdb_modes, vic, 1);
-}
-
/**
* drm_display_mode_from_cea_vic() - return a mode for CEA VIC
* @dev: DRM device
@@ -4577,29 +4541,20 @@ drm_display_mode_from_cea_vic(struct drm_device *dev,
}
EXPORT_SYMBOL(drm_display_mode_from_cea_vic);
-static int
-do_cea_modes(struct drm_connector *connector, const u8 *db, u8 len)
+/* Add modes based on VICs parsed in parse_cta_vdb() */
+static int add_cta_vdb_modes(struct drm_connector *connector)
{
+ const struct drm_display_info *info = &connector->display_info;
int i, modes = 0;
- struct drm_hdmi_info *hdmi = &connector->display_info.hdmi;
- for (i = 0; i < len; i++) {
+ if (!info->vics)
+ return 0;
+
+ for (i = 0; i < info->vics_len; i++) {
struct drm_display_mode *mode;
- mode = drm_display_mode_from_vic_index(connector, db, len, i);
+ mode = drm_display_mode_from_vic_index(connector, i);
if (mode) {
- /*
- * YCBCR420 capability block contains a bitmap which
- * gives the index of CEA modes from CEA VDB, which
- * can support YCBCR 420 sampling output also (apart
- * from RGB/YCBCR444 etc).
- * For example, if the bit 0 in bitmap is set,
- * first mode in VDB can support YCBCR420 output too.
- * Add YCBCR420 modes only if sink is HDMI 2.0 capable.
- */
- if (i < 64 && hdmi->y420_cmdb_map & (1ULL << i))
- drm_add_cmdb_modes(connector, db[i]);
-
drm_mode_probed_add(connector, mode);
modes++;
}
@@ -4693,15 +4648,13 @@ static int add_hdmi_mode(struct drm_connector *connector, u8 vic)
}
static int add_3d_struct_modes(struct drm_connector *connector, u16 structure,
- const u8 *video_db, u8 video_len, u8 video_index)
+ int vic_index)
{
struct drm_display_mode *newmode;
int modes = 0;
if (structure & (1 << 0)) {
- newmode = drm_display_mode_from_vic_index(connector, video_db,
- video_len,
- video_index);
+ newmode = drm_display_mode_from_vic_index(connector, vic_index);
if (newmode) {
newmode->flags |= DRM_MODE_FLAG_3D_FRAME_PACKING;
drm_mode_probed_add(connector, newmode);
@@ -4709,9 +4662,7 @@ static int add_3d_struct_modes(struct drm_connector *connector, u16 structure,
}
}
if (structure & (1 << 6)) {
- newmode = drm_display_mode_from_vic_index(connector, video_db,
- video_len,
- video_index);
+ newmode = drm_display_mode_from_vic_index(connector, vic_index);
if (newmode) {
newmode->flags |= DRM_MODE_FLAG_3D_TOP_AND_BOTTOM;
drm_mode_probed_add(connector, newmode);
@@ -4719,9 +4670,7 @@ static int add_3d_struct_modes(struct drm_connector *connector, u16 structure,
}
}
if (structure & (1 << 8)) {
- newmode = drm_display_mode_from_vic_index(connector, video_db,
- video_len,
- video_index);
+ newmode = drm_display_mode_from_vic_index(connector, vic_index);
if (newmode) {
newmode->flags |= DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF;
drm_mode_probed_add(connector, newmode);
@@ -4732,6 +4681,26 @@ static int add_3d_struct_modes(struct drm_connector *connector, u16 structure,
return modes;
}
+static bool hdmi_vsdb_latency_present(const u8 *db)
+{
+ return db[8] & BIT(7);
+}
+
+static bool hdmi_vsdb_i_latency_present(const u8 *db)
+{
+ return hdmi_vsdb_latency_present(db) && db[8] & BIT(6);
+}
+
+static int hdmi_vsdb_latency_length(const u8 *db)
+{
+ if (hdmi_vsdb_i_latency_present(db))
+ return 4;
+ else if (hdmi_vsdb_latency_present(db))
+ return 2;
+ else
+ return 0;
+}
+
/*
* do_hdmi_vsdb_modes - Parse the HDMI Vendor Specific data block
* @connector: connector corresponding to the HDMI sink
@@ -4742,10 +4711,8 @@ static int add_3d_struct_modes(struct drm_connector *connector, u16 structure,
* also adds the stereo 3d modes when applicable.
*/
static int
-do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len,
- const u8 *video_db, u8 video_len)
+do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len)
{
- struct drm_display_info *info = &connector->display_info;
int modes = 0, offset = 0, i, multi_present = 0, multi_len;
u8 vic_len, hdmi_3d_len = 0;
u16 mask;
@@ -4758,13 +4725,7 @@ do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len,
if (!(db[8] & (1 << 5)))
goto out;
- /* Latency_Fields_Present */
- if (db[8] & (1 << 7))
- offset += 2;
-
- /* I_Latency_Fields_Present */
- if (db[8] & (1 << 6))
- offset += 2;
+ offset += hdmi_vsdb_latency_length(db);
/* the declared length is not long enough for the 2 first bytes
* of additional video format capabilities */
@@ -4818,9 +4779,7 @@ do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len,
for (i = 0; i < 16; i++) {
if (mask & (1 << i))
modes += add_3d_struct_modes(connector,
- structure_all,
- video_db,
- video_len, i);
+ structure_all, i);
}
}
@@ -4857,8 +4816,6 @@ do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len,
if (newflag != 0) {
newmode = drm_display_mode_from_vic_index(connector,
- video_db,
- video_len,
vic_index);
if (newmode) {
@@ -4873,8 +4830,6 @@ do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len,
}
out:
- if (modes > 0)
- info->has_hdmi_infoframe = true;
return modes;
}
@@ -5204,20 +5159,26 @@ static int edid_hfeeodb_extension_block_count(const struct edid *edid)
return cta[4 + 2];
}
-static void drm_parse_y420cmdb_bitmap(struct drm_connector *connector,
- const u8 *db)
+/*
+ * CTA-861 YCbCr 4:2:0 Capability Map Data Block (CTA Y420CMDB)
+ *
+ * Y420CMDB contains a bitmap which gives the index of CTA modes from CTA VDB,
+ * which can support YCBCR 420 sampling output also (apart from RGB/YCBCR444
+ * etc). For example, if the bit 0 in bitmap is set, first mode in VDB can
+ * support YCBCR420 output too.
+ */
+static void parse_cta_y420cmdb(struct drm_connector *connector,
+ const struct cea_db *db, u64 *y420cmdb_map)
{
struct drm_display_info *info = &connector->display_info;
- struct drm_hdmi_info *hdmi = &info->hdmi;
- u8 map_len = cea_db_payload_len(db) - 1;
- u8 count;
+ int i, map_len = cea_db_payload_len(db) - 1;
+ const u8 *data = cea_db_data(db) + 1;
u64 map = 0;
if (map_len == 0) {
/* All CEA modes support ycbcr420 sampling also.*/
- hdmi->y420_cmdb_map = U64_MAX;
- info->color_formats |= DRM_COLOR_FORMAT_YCBCR420;
- return;
+ map = U64_MAX;
+ goto out;
}
/*
@@ -5235,13 +5196,14 @@ static void drm_parse_y420cmdb_bitmap(struct drm_connector *connector,
if (WARN_ON_ONCE(map_len > 8))
map_len = 8;
- for (count = 0; count < map_len; count++)
- map |= (u64)db[2 + count] << (8 * count);
+ for (i = 0; i < map_len; i++)
+ map |= (u64)data[i] << (8 * i);
+out:
if (map)
info->color_formats |= DRM_COLOR_FORMAT_YCBCR420;
- hdmi->y420_cmdb_map = map;
+ *y420cmdb_map = map;
}
static int add_cea_modes(struct drm_connector *connector,
@@ -5249,21 +5211,16 @@ static int add_cea_modes(struct drm_connector *connector,
{
const struct cea_db *db;
struct cea_db_iter iter;
- int modes = 0;
+ int modes;
+
+ /* CTA VDB block VICs parsed earlier */
+ modes = add_cta_vdb_modes(connector);
cea_db_iter_edid_begin(drm_edid, &iter);
cea_db_iter_for_each(db, &iter) {
- const u8 *hdmi = NULL, *video = NULL;
- u8 hdmi_len = 0, video_len = 0;
-
- if (cea_db_tag(db) == CTA_DB_VIDEO) {
- video = cea_db_data(db);
- video_len = cea_db_payload_len(db);
- modes += do_cea_modes(connector, video, video_len);
- } else if (cea_db_is_hdmi_vsdb(db)) {
- /* FIXME: Switch to use cea_db_data() */
- hdmi = (const u8 *)db;
- hdmi_len = cea_db_payload_len(db);
+ if (cea_db_is_hdmi_vsdb(db)) {
+ modes += do_hdmi_vsdb_modes(connector, (const u8 *)db,
+ cea_db_payload_len(db));
} else if (cea_db_is_y420vdb(db)) {
const u8 *vdb420 = cea_db_data(db) + 1;
@@ -5271,15 +5228,6 @@ static int add_cea_modes(struct drm_connector *connector,
modes += do_y420vdb_modes(connector, vdb420,
cea_db_payload_len(db) - 1);
}
-
- /*
- * We parse the HDMI VSDB after having added the cea modes as we
- * will be patching their flags when the sink supports stereo
- * 3D.
- */
- if (hdmi)
- modes += do_hdmi_vsdb_modes(connector, hdmi, hdmi_len,
- video, video_len);
}
cea_db_iter_end(&iter);
@@ -5416,6 +5364,7 @@ drm_parse_hdr_metadata_block(struct drm_connector *connector, const u8 *db)
}
}
+/* HDMI Vendor-Specific Data Block (HDMI VSDB, H14b-VSDB) */
static void
drm_parse_hdmi_vsdb_audio(struct drm_connector *connector, const u8 *db)
{
@@ -5423,18 +5372,18 @@ drm_parse_hdmi_vsdb_audio(struct drm_connector *connector, const u8 *db)
if (len >= 6 && (db[6] & (1 << 7)))
connector->eld[DRM_ELD_SAD_COUNT_CONN_TYPE] |= DRM_ELD_SUPPORTS_AI;
- if (len >= 8) {
- connector->latency_present[0] = db[8] >> 7;
- connector->latency_present[1] = (db[8] >> 6) & 1;
- }
- if (len >= 9)
+
+ if (len >= 10 && hdmi_vsdb_latency_present(db)) {
+ connector->latency_present[0] = true;
connector->video_latency[0] = db[9];
- if (len >= 10)
connector->audio_latency[0] = db[10];
- if (len >= 11)
+ }
+
+ if (len >= 12 && hdmi_vsdb_i_latency_present(db)) {
+ connector->latency_present[1] = true;
connector->video_latency[1] = db[11];
- if (len >= 12)
connector->audio_latency[1] = db[12];
+ }
drm_dbg_kms(connector->dev,
"[CONNECTOR:%d:%s] HDMI: latency present %d %d, video latency %d %d, audio latency %d %d\n",
@@ -5533,8 +5482,6 @@ static void drm_edid_to_eld(struct drm_connector *connector,
int total_sad_count = 0;
int mnl;
- clear_eld(connector);
-
if (!drm_edid)
return;
@@ -5864,6 +5811,92 @@ drm_default_rgb_quant_range(const struct drm_display_mode *mode)
}
EXPORT_SYMBOL(drm_default_rgb_quant_range);
+/* CTA-861 Video Data Block (CTA VDB) */
+static void parse_cta_vdb(struct drm_connector *connector, const struct cea_db *db)
+{
+ struct drm_display_info *info = &connector->display_info;
+ int i, vic_index, len = cea_db_payload_len(db);
+ const u8 *svds = cea_db_data(db);
+ u8 *vics;
+
+ if (!len)
+ return;
+
+ /* Gracefully handle multiple VDBs, however unlikely that is */
+ vics = krealloc(info->vics, info->vics_len + len, GFP_KERNEL);
+ if (!vics)
+ return;
+
+ vic_index = info->vics_len;
+ info->vics_len += len;
+ info->vics = vics;
+
+ for (i = 0; i < len; i++) {
+ u8 vic = svd_to_vic(svds[i]);
+
+ if (!drm_valid_cea_vic(vic))
+ vic = 0;
+
+ info->vics[vic_index++] = vic;
+ }
+}
+
+/*
+ * Update y420_cmdb_modes based on previously parsed CTA VDB and Y420CMDB.
+ *
+ * Translate the y420cmdb_map based on VIC indexes to y420_cmdb_modes indexed
+ * using the VICs themselves.
+ */
+static void update_cta_y420cmdb(struct drm_connector *connector, u64 y420cmdb_map)
+{
+ struct drm_display_info *info = &connector->display_info;
+ struct drm_hdmi_info *hdmi = &info->hdmi;
+ int i, len = min_t(int, info->vics_len, BITS_PER_TYPE(y420cmdb_map));
+
+ for (i = 0; i < len; i++) {
+ u8 vic = info->vics[i];
+
+ if (vic && y420cmdb_map & BIT_ULL(i))
+ bitmap_set(hdmi->y420_cmdb_modes, vic, 1);
+ }
+}
+
+static bool cta_vdb_has_vic(const struct drm_connector *connector, u8 vic)
+{
+ const struct drm_display_info *info = &connector->display_info;
+ int i;
+
+ if (!vic || !info->vics)
+ return false;
+
+ for (i = 0; i < info->vics_len; i++) {
+ if (info->vics[i] == vic)
+ return true;
+ }
+
+ return false;
+}
+
+/* CTA-861-H YCbCr 4:2:0 Video Data Block (CTA Y420VDB) */
+static void parse_cta_y420vdb(struct drm_connector *connector,
+ const struct cea_db *db)
+{
+ struct drm_display_info *info = &connector->display_info;
+ struct drm_hdmi_info *hdmi = &info->hdmi;
+ const u8 *svds = cea_db_data(db) + 1;
+ int i;
+
+ for (i = 0; i < cea_db_payload_len(db) - 1; i++) {
+ u8 vic = svd_to_vic(svds[i]);
+
+ if (!drm_valid_cea_vic(vic))
+ continue;
+
+ bitmap_set(hdmi->y420_vdb_modes, vic, 1);
+ info->color_formats |= DRM_COLOR_FORMAT_YCBCR420;
+ }
+}
+
static void drm_parse_vcdb(struct drm_connector *connector, const u8 *db)
{
struct drm_display_info *info = &connector->display_info;
@@ -5995,14 +6028,14 @@ static void drm_parse_dsc_info(struct drm_hdmi_dsc_cap *hdmi_dsc,
static void drm_parse_hdmi_forum_scds(struct drm_connector *connector,
const u8 *hf_scds)
{
- struct drm_display_info *display = &connector->display_info;
- struct drm_hdmi_info *hdmi = &display->hdmi;
+ struct drm_display_info *info = &connector->display_info;
+ struct drm_hdmi_info *hdmi = &info->hdmi;
struct drm_hdmi_dsc_cap *hdmi_dsc = &hdmi->dsc_cap;
int max_tmds_clock = 0;
u8 max_frl_rate = 0;
bool dsc_support = false;
- display->has_hdmi_infoframe = true;
+ info->has_hdmi_infoframe = true;
if (hf_scds[6] & 0x80) {
hdmi->scdc.supported = true;
@@ -6026,7 +6059,7 @@ static void drm_parse_hdmi_forum_scds(struct drm_connector *connector,
max_tmds_clock = hf_scds[5] * 5000;
if (max_tmds_clock > 340000) {
- display->max_tmds_clock = max_tmds_clock;
+ info->max_tmds_clock = max_tmds_clock;
}
if (scdc->supported) {
@@ -6117,6 +6150,7 @@ static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector,
}
}
+/* HDMI Vendor-Specific Data Block (HDMI VSDB, H14b-VSDB) */
static void
drm_parse_hdmi_vsdb_video(struct drm_connector *connector, const u8 *db)
{
@@ -6130,6 +6164,15 @@ drm_parse_hdmi_vsdb_video(struct drm_connector *connector, const u8 *db)
if (len >= 7)
info->max_tmds_clock = db[7] * 5000;
+ /*
+ * Try to infer whether the sink supports HDMI infoframes.
+ *
+ * HDMI infoframe support was first added in HDMI 1.4. Assume the sink
+ * supports infoframes if HDMI_Video_present is set.
+ */
+ if (len >= 8 && db[8] & BIT(5))
+ info->has_hdmi_infoframe = true;
+
drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] HDMI: DVI dual %d, max TMDS clock %d kHz\n",
connector->base.id, connector->name,
info->dvi_dual, info->max_tmds_clock);
@@ -6165,6 +6208,7 @@ static void drm_parse_cea_ext(struct drm_connector *connector,
const struct cea_db *db;
struct cea_db_iter iter;
const u8 *edid_ext;
+ u64 y420cmdb_map = 0;
drm_edid_iter_begin(drm_edid, &edid_iter);
drm_edid_iter_for_each(edid_ext, &edid_iter) {
@@ -6202,13 +6246,20 @@ static void drm_parse_cea_ext(struct drm_connector *connector,
else if (cea_db_is_microsoft_vsdb(db))
drm_parse_microsoft_vsdb(connector, data);
else if (cea_db_is_y420cmdb(db))
- drm_parse_y420cmdb_bitmap(connector, data);
+ parse_cta_y420cmdb(connector, db, &y420cmdb_map);
+ else if (cea_db_is_y420vdb(db))
+ parse_cta_y420vdb(connector, db);
else if (cea_db_is_vcdb(db))
drm_parse_vcdb(connector, data);
else if (cea_db_is_hdmi_hdr_metadata_block(db))
drm_parse_hdr_metadata_block(connector, data);
+ else if (cea_db_tag(db) == CTA_DB_VIDEO)
+ parse_cta_vdb(connector, db);
}
cea_db_iter_end(&iter);
+
+ if (y420cmdb_map)
+ update_cta_y420cmdb(connector, y420cmdb_map);
}
static
@@ -6374,17 +6425,29 @@ static void drm_reset_display_info(struct drm_connector *connector)
info->mso_stream_count = 0;
info->mso_pixel_overlap = 0;
info->max_dsc_bpp = 0;
+
+ kfree(info->vics);
+ info->vics = NULL;
+ info->vics_len = 0;
+
+ info->quirks = 0;
}
-static u32 update_display_info(struct drm_connector *connector,
- const struct drm_edid *drm_edid)
+static void update_display_info(struct drm_connector *connector,
+ const struct drm_edid *drm_edid)
{
struct drm_display_info *info = &connector->display_info;
- const struct edid *edid = drm_edid->edid;
-
- u32 quirks = edid_get_quirks(drm_edid);
+ const struct edid *edid;
drm_reset_display_info(connector);
+ clear_eld(connector);
+
+ if (!drm_edid)
+ return;
+
+ edid = drm_edid->edid;
+
+ info->quirks = edid_get_quirks(drm_edid);
info->width_mm = edid->width_cm * 10;
info->height_mm = edid->height_cm * 10;
@@ -6456,17 +6519,30 @@ static u32 update_display_info(struct drm_connector *connector,
drm_update_mso(connector, drm_edid);
out:
- if (quirks & EDID_QUIRK_NON_DESKTOP) {
+ if (info->quirks & EDID_QUIRK_NON_DESKTOP) {
drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] Non-desktop display%s\n",
connector->base.id, connector->name,
info->non_desktop ? " (redundant quirk)" : "");
info->non_desktop = true;
}
- if (quirks & EDID_QUIRK_CAP_DSC_15BPP)
+ if (info->quirks & EDID_QUIRK_CAP_DSC_15BPP)
info->max_dsc_bpp = 15;
- return quirks;
+ if (info->quirks & EDID_QUIRK_FORCE_6BPC)
+ info->bpc = 6;
+
+ if (info->quirks & EDID_QUIRK_FORCE_8BPC)
+ info->bpc = 8;
+
+ if (info->quirks & EDID_QUIRK_FORCE_10BPC)
+ info->bpc = 10;
+
+ if (info->quirks & EDID_QUIRK_FORCE_12BPC)
+ info->bpc = 12;
+
+ /* Depends on info->cea_rev set by drm_parse_cea_ext() above */
+ drm_edid_to_eld(connector, drm_edid);
}
static struct drm_display_mode *drm_mode_displayid_detailed(struct drm_device *dev,
@@ -6561,27 +6637,14 @@ static int add_displayid_detailed_modes(struct drm_connector *connector,
return num_modes;
}
-static int _drm_edid_connector_update(struct drm_connector *connector,
- const struct drm_edid *drm_edid)
+static int _drm_edid_connector_add_modes(struct drm_connector *connector,
+ const struct drm_edid *drm_edid)
{
+ const struct drm_display_info *info = &connector->display_info;
int num_modes = 0;
- u32 quirks;
- if (!drm_edid) {
- drm_reset_display_info(connector);
- clear_eld(connector);
+ if (!drm_edid)
return 0;
- }
-
- /*
- * CEA-861-F adds ycbcr capability map block, for HDMI 2.0 sinks.
- * To avoid multiple parsing of same block, lets parse that map
- * from sink info, before parsing CEA modes.
- */
- quirks = update_display_info(connector, drm_edid);
-
- /* Depends on info->cea_rev set by update_display_info() above */
- drm_edid_to_eld(connector, drm_edid);
/*
* EDID spec says modes should be preferred in this order:
@@ -6597,7 +6660,7 @@ static int _drm_edid_connector_update(struct drm_connector *connector,
*
* XXX order for additional mode types in extension blocks?
*/
- num_modes += add_detailed_modes(connector, drm_edid, quirks);
+ num_modes += add_detailed_modes(connector, drm_edid);
num_modes += add_cvt_modes(connector, drm_edid);
num_modes += add_standard_modes(connector, drm_edid);
num_modes += add_established_modes(connector, drm_edid);
@@ -6607,20 +6670,8 @@ static int _drm_edid_connector_update(struct drm_connector *connector,
if (drm_edid->edid->features & DRM_EDID_FEATURE_CONTINUOUS_FREQ)
num_modes += add_inferred_modes(connector, drm_edid);
- if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
- edid_fixup_preferred(connector, quirks);
-
- if (quirks & EDID_QUIRK_FORCE_6BPC)
- connector->display_info.bpc = 6;
-
- if (quirks & EDID_QUIRK_FORCE_8BPC)
- connector->display_info.bpc = 8;
-
- if (quirks & EDID_QUIRK_FORCE_10BPC)
- connector->display_info.bpc = 10;
-
- if (quirks & EDID_QUIRK_FORCE_12BPC)
- connector->display_info.bpc = 12;
+ if (info->quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
+ edid_fixup_preferred(connector);
return num_modes;
}
@@ -6684,49 +6735,54 @@ out:
* @connector: Connector
* @drm_edid: EDID
*
- * Update the connector mode list, display info, ELD, HDR metadata, relevant
- * properties, etc. from the passed in EDID.
+ * Update the connector display info, ELD, HDR metadata, relevant properties,
+ * etc. from the passed in EDID.
*
* If EDID is NULL, reset the information.
*
- * Return: The number of modes added or 0 if we couldn't find any.
+ * Must be called before calling drm_edid_connector_add_modes().
+ *
+ * Return: 0 on success, negative error on errors.
*/
int drm_edid_connector_update(struct drm_connector *connector,
const struct drm_edid *drm_edid)
{
- int count;
-
- count = _drm_edid_connector_update(connector, drm_edid);
+ update_display_info(connector, drm_edid);
_drm_update_tile_info(connector, drm_edid);
- /* Note: Ignore errors for now. */
- _drm_edid_connector_property_update(connector, drm_edid);
-
- return count;
+ return _drm_edid_connector_property_update(connector, drm_edid);
}
EXPORT_SYMBOL(drm_edid_connector_update);
-static int _drm_connector_update_edid_property(struct drm_connector *connector,
- const struct drm_edid *drm_edid)
+/**
+ * drm_edid_connector_add_modes - Update probed modes from the EDID property
+ * @connector: Connector
+ *
+ * Add the modes from the previously updated EDID property to the connector
+ * probed modes list.
+ *
+ * drm_edid_connector_update() must have been called before this to update the
+ * EDID property.
+ *
+ * Return: The number of modes added, or 0 if we couldn't find any.
+ */
+int drm_edid_connector_add_modes(struct drm_connector *connector)
{
- /*
- * Set the display info, using edid if available, otherwise resetting
- * the values to defaults. This duplicates the work done in
- * drm_add_edid_modes, but that function is not consistently called
- * before this one in all drivers and the computation is cheap enough
- * that it seems better to duplicate it rather than attempt to ensure
- * some arbitrary ordering of calls.
- */
- if (drm_edid)
- update_display_info(connector, drm_edid);
- else
- drm_reset_display_info(connector);
+ const struct drm_edid *drm_edid = NULL;
+ int count;
- _drm_update_tile_info(connector, drm_edid);
+ if (connector->edid_blob_ptr)
+ drm_edid = drm_edid_alloc(connector->edid_blob_ptr->data,
+ connector->edid_blob_ptr->length);
- return _drm_edid_connector_property_update(connector, drm_edid);
+ count = _drm_edid_connector_add_modes(connector, drm_edid);
+
+ drm_edid_free(drm_edid);
+
+ return count;
}
+EXPORT_SYMBOL(drm_edid_connector_add_modes);
/**
* drm_connector_update_edid_property - update the edid property of a connector
@@ -6749,8 +6805,7 @@ int drm_connector_update_edid_property(struct drm_connector *connector,
{
struct drm_edid drm_edid;
- return _drm_connector_update_edid_property(connector,
- drm_edid_legacy_init(&drm_edid, edid));
+ return drm_edid_connector_update(connector, drm_edid_legacy_init(&drm_edid, edid));
}
EXPORT_SYMBOL(drm_connector_update_edid_property);
@@ -6763,13 +6818,14 @@ EXPORT_SYMBOL(drm_connector_update_edid_property);
* &drm_display_info structure and ELD in @connector with any information which
* can be derived from the edid.
*
- * This function is deprecated. Use drm_edid_connector_update() instead.
+ * This function is deprecated. Use drm_edid_connector_add_modes() instead.
*
* Return: The number of modes added or 0 if we couldn't find any.
*/
int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
{
- struct drm_edid drm_edid;
+ struct drm_edid _drm_edid;
+ const struct drm_edid *drm_edid;
if (edid && !drm_edid_is_valid(edid)) {
drm_warn(connector->dev, "[CONNECTOR:%d:%s] EDID invalid.\n",
@@ -6777,8 +6833,11 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
edid = NULL;
}
- return _drm_edid_connector_update(connector,
- drm_edid_legacy_init(&drm_edid, edid));
+ drm_edid = drm_edid_legacy_init(&_drm_edid, edid);
+
+ update_display_info(connector, drm_edid);
+
+ return _drm_edid_connector_add_modes(connector, drm_edid);
}
EXPORT_SYMBOL(drm_add_edid_modes);
@@ -6885,8 +6944,6 @@ static u8 drm_mode_hdmi_vic(const struct drm_connector *connector,
static u8 drm_mode_cea_vic(const struct drm_connector *connector,
const struct drm_display_mode *mode)
{
- u8 vic;
-
/*
* HDMI spec says if a mode is found in HDMI 1.4b 4K modes
* we should send its VIC in vendor infoframes, else send the
@@ -6896,14 +6953,23 @@ static u8 drm_mode_cea_vic(const struct drm_connector *connector,
if (drm_mode_hdmi_vic(connector, mode))
return 0;
- vic = drm_match_cea_mode(mode);
+ return drm_match_cea_mode(mode);
+}
- /*
- * HDMI 1.4 VIC range: 1 <= VIC <= 64 (CEA-861-D) but
- * HDMI 2.0 VIC range: 1 <= VIC <= 107 (CEA-861-F). So we
- * have to make sure we dont break HDMI 1.4 sinks.
- */
- if (!is_hdmi2_sink(connector) && vic > 64)
+/*
+ * Avoid sending VICs defined in HDMI 2.0 in AVI infoframes to sinks that
+ * conform to HDMI 1.4.
+ *
+ * HDMI 1.4 (CTA-861-D) VIC range: [1..64]
+ * HDMI 2.0 (CTA-861-F) VIC range: [1..107]
+ *
+ * If the sink lists the VIC in CTA VDB, assume it's fine, regardless of HDMI
+ * version.
+ */
+static u8 vic_for_avi_infoframe(const struct drm_connector *connector, u8 vic)
+{
+ if (!is_hdmi2_sink(connector) && vic > 64 &&
+ !cta_vdb_has_vic(connector, vic))
return 0;
return vic;
@@ -6978,7 +7044,7 @@ drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame,
picture_aspect = HDMI_PICTURE_ASPECT_NONE;
}
- frame->video_code = vic;
+ frame->video_code = vic_for_avi_infoframe(connector, vic);
frame->picture_aspect = picture_aspect;
frame->active_aspect = HDMI_ACTIVE_ASPECT_PICTURE;
frame->scan_mode = HDMI_SCAN_MODE_UNDERSCAN;
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 0d0c26ebab90..a39998047f8a 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -416,14 +416,30 @@ static void drm_fb_helper_damage_work(struct work_struct *work)
* drm_fb_helper_prepare - setup a drm_fb_helper structure
* @dev: DRM device
* @helper: driver-allocated fbdev helper structure to set up
+ * @preferred_bpp: Preferred bits per pixel for the device.
* @funcs: pointer to structure of functions associate with this helper
*
* Sets up the bare minimum to make the framebuffer helper usable. This is
* useful to implement race-free initialization of the polling helpers.
*/
void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper,
+ unsigned int preferred_bpp,
const struct drm_fb_helper_funcs *funcs)
{
+ /*
+ * Pick a preferred bpp of 32 if no value has been given. This
+ * will select XRGB8888 for the framebuffer formats. All drivers
+ * have to support XRGB8888 for backwards compatibility with legacy
+ * userspace, so it's the safe choice here.
+ *
+ * TODO: Replace struct drm_mode_config.preferred_depth and this
+ * bpp value with a preferred format that is given as struct
+ * drm_format_info. Then derive all other values from the
+ * format.
+ */
+ if (!preferred_bpp)
+ preferred_bpp = 32;
+
INIT_LIST_HEAD(&helper->kernel_fb_list);
spin_lock_init(&helper->damage_lock);
INIT_WORK(&helper->resume_work, drm_fb_helper_resume_worker);
@@ -432,10 +448,23 @@ void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper,
mutex_init(&helper->lock);
helper->funcs = funcs;
helper->dev = dev;
+ helper->preferred_bpp = preferred_bpp;
}
EXPORT_SYMBOL(drm_fb_helper_prepare);
/**
+ * drm_fb_helper_unprepare - clean up a drm_fb_helper structure
+ * @fb_helper: driver-allocated fbdev helper structure to set up
+ *
+ * Cleans up the framebuffer helper. Inverse of drm_fb_helper_prepare().
+ */
+void drm_fb_helper_unprepare(struct drm_fb_helper *fb_helper)
+{
+ mutex_destroy(&fb_helper->lock);
+}
+EXPORT_SYMBOL(drm_fb_helper_unprepare);
+
+/**
* drm_fb_helper_init - initialize a &struct drm_fb_helper
* @dev: drm device
* @fb_helper: driver-allocated fbdev helper structure to initialize
@@ -475,8 +504,8 @@ EXPORT_SYMBOL(drm_fb_helper_init);
* drm_fb_helper_alloc_info - allocate fb_info and some of its members
* @fb_helper: driver-allocated fbdev helper
*
- * A helper to alloc fb_info and the members cmap and apertures. Called
- * by the driver within the fb_probe fb_helper callback function. Drivers do not
+ * A helper to alloc fb_info and the member cmap. Called by the driver
+ * within the fb_probe fb_helper callback function. Drivers do not
* need to release the allocated fb_info structure themselves, this is
* automatically done when calling drm_fb_helper_fini().
*
@@ -498,27 +527,11 @@ struct fb_info *drm_fb_helper_alloc_info(struct drm_fb_helper *fb_helper)
if (ret)
goto err_release;
- /*
- * TODO: We really should be smarter here and alloc an aperture
- * for each IORESOURCE_MEM resource helper->dev->dev has and also
- * init the ranges of the appertures based on the resources.
- * Note some drivers currently count on there being only 1 empty
- * aperture and fill this themselves, these will need to be dealt
- * with somehow when fixing this.
- */
- info->apertures = alloc_apertures(1);
- if (!info->apertures) {
- ret = -ENOMEM;
- goto err_free_cmap;
- }
-
fb_helper->info = info;
info->skip_vt_switch = true;
return info;
-err_free_cmap:
- fb_dealloc_cmap(&info->cmap);
err_release:
framebuffer_release(info);
return ERR_PTR(ret);
@@ -577,8 +590,6 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
}
mutex_unlock(&kernel_fb_helper_lock);
- mutex_destroy(&fb_helper->lock);
-
if (!fb_helper->client.funcs)
drm_client_release(&fb_helper->client);
}
@@ -1728,117 +1739,132 @@ unlock:
}
EXPORT_SYMBOL(drm_fb_helper_pan_display);
-/*
- * Allocates the backing storage and sets up the fbdev info structure through
- * the ->fb_probe callback.
- */
-static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
- int preferred_bpp)
+static uint32_t drm_fb_helper_find_format(struct drm_fb_helper *fb_helper, const uint32_t *formats,
+ size_t format_count, uint32_t bpp, uint32_t depth)
{
- struct drm_client_dev *client = &fb_helper->client;
struct drm_device *dev = fb_helper->dev;
- struct drm_mode_config *config = &dev->mode_config;
- int ret = 0;
- int crtc_count = 0;
- struct drm_connector_list_iter conn_iter;
- struct drm_fb_helper_surface_size sizes;
- struct drm_connector *connector;
- struct drm_mode_set *mode_set;
- int best_depth = 0;
-
- memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size));
- sizes.surface_depth = 24;
- sizes.surface_bpp = 32;
- sizes.fb_width = (u32)-1;
- sizes.fb_height = (u32)-1;
+ uint32_t format;
+ size_t i;
/*
- * If driver picks 8 or 16 by default use that for both depth/bpp
- * to begin with
+ * Do not consider YUV or other complicated formats
+ * for framebuffers. This means only legacy formats
+ * are supported (fmt->depth is a legacy field), but
+ * the framebuffer emulation can only deal with such
+ * formats, specifically RGB/BGA formats.
*/
- if (preferred_bpp != sizes.surface_bpp)
- sizes.surface_depth = sizes.surface_bpp = preferred_bpp;
+ format = drm_mode_legacy_fb_format(bpp, depth);
+ if (!format)
+ goto err;
- drm_connector_list_iter_begin(fb_helper->dev, &conn_iter);
- drm_client_for_each_connector_iter(connector, &conn_iter) {
- struct drm_cmdline_mode *cmdline_mode;
+ for (i = 0; i < format_count; ++i) {
+ if (formats[i] == format)
+ return format;
+ }
- cmdline_mode = &connector->cmdline_mode;
+err:
+ /* We found nothing. */
+ drm_warn(dev, "bpp/depth value of %u/%u not supported\n", bpp, depth);
- if (cmdline_mode->bpp_specified) {
- switch (cmdline_mode->bpp) {
- case 8:
- sizes.surface_depth = sizes.surface_bpp = 8;
- break;
- case 15:
- sizes.surface_depth = 15;
- sizes.surface_bpp = 16;
- break;
- case 16:
- sizes.surface_depth = sizes.surface_bpp = 16;
- break;
- case 24:
- sizes.surface_depth = sizes.surface_bpp = 24;
- break;
- case 32:
- sizes.surface_depth = 24;
- sizes.surface_bpp = 32;
- break;
- }
- break;
- }
+ return DRM_FORMAT_INVALID;
+}
+
+static uint32_t drm_fb_helper_find_color_mode_format(struct drm_fb_helper *fb_helper,
+ const uint32_t *formats, size_t format_count,
+ unsigned int color_mode)
+{
+ struct drm_device *dev = fb_helper->dev;
+ uint32_t bpp, depth;
+
+ switch (color_mode) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 16:
+ case 24:
+ bpp = depth = color_mode;
+ break;
+ case 15:
+ bpp = 16;
+ depth = 15;
+ break;
+ case 32:
+ bpp = 32;
+ depth = 24;
+ break;
+ default:
+ drm_info(dev, "unsupported color mode of %d\n", color_mode);
+ return DRM_FORMAT_INVALID;
}
- drm_connector_list_iter_end(&conn_iter);
- /*
- * If we run into a situation where, for example, the primary plane
- * supports RGBA5551 (16 bpp, depth 15) but not RGB565 (16 bpp, depth
- * 16) we need to scale down the depth of the sizes we request.
- */
- mutex_lock(&client->modeset_mutex);
+ return drm_fb_helper_find_format(fb_helper, formats, format_count, bpp, depth);
+}
+
+static int __drm_fb_helper_find_sizes(struct drm_fb_helper *fb_helper,
+ struct drm_fb_helper_surface_size *sizes)
+{
+ struct drm_client_dev *client = &fb_helper->client;
+ struct drm_device *dev = fb_helper->dev;
+ int crtc_count = 0;
+ struct drm_connector_list_iter conn_iter;
+ struct drm_connector *connector;
+ struct drm_mode_set *mode_set;
+ uint32_t surface_format = DRM_FORMAT_INVALID;
+ const struct drm_format_info *info;
+
+ memset(sizes, 0, sizeof(*sizes));
+ sizes->fb_width = (u32)-1;
+ sizes->fb_height = (u32)-1;
+
drm_client_for_each_modeset(mode_set, client) {
struct drm_crtc *crtc = mode_set->crtc;
struct drm_plane *plane = crtc->primary;
- int j;
drm_dbg_kms(dev, "test CRTC %u primary plane\n", drm_crtc_index(crtc));
- for (j = 0; j < plane->format_count; j++) {
- const struct drm_format_info *fmt;
-
- fmt = drm_format_info(plane->format_types[j]);
-
- /*
- * Do not consider YUV or other complicated formats
- * for framebuffers. This means only legacy formats
- * are supported (fmt->depth is a legacy field) but
- * the framebuffer emulation can only deal with such
- * formats, specifically RGB/BGA formats.
- */
- if (fmt->depth == 0)
- continue;
-
- /* We found a perfect fit, great */
- if (fmt->depth == sizes.surface_depth) {
- best_depth = fmt->depth;
- break;
- }
+ drm_connector_list_iter_begin(fb_helper->dev, &conn_iter);
+ drm_client_for_each_connector_iter(connector, &conn_iter) {
+ struct drm_cmdline_mode *cmdline_mode = &connector->cmdline_mode;
- /* Skip depths above what we're looking for */
- if (fmt->depth > sizes.surface_depth)
+ if (!cmdline_mode->bpp_specified)
continue;
- /* Best depth found so far */
- if (fmt->depth > best_depth)
- best_depth = fmt->depth;
+ surface_format = drm_fb_helper_find_color_mode_format(fb_helper,
+ plane->format_types,
+ plane->format_count,
+ cmdline_mode->bpp);
+ if (surface_format != DRM_FORMAT_INVALID)
+ break; /* found supported format */
}
+ drm_connector_list_iter_end(&conn_iter);
+
+ if (surface_format != DRM_FORMAT_INVALID)
+ break; /* found supported format */
+
+ /* try preferred color mode */
+ surface_format = drm_fb_helper_find_color_mode_format(fb_helper,
+ plane->format_types,
+ plane->format_count,
+ fb_helper->preferred_bpp);
+ if (surface_format != DRM_FORMAT_INVALID)
+ break; /* found supported format */
}
- if (sizes.surface_depth != best_depth && best_depth) {
- drm_info(dev, "requested bpp %d, scaled depth down to %d",
- sizes.surface_bpp, best_depth);
- sizes.surface_depth = best_depth;
+
+ if (surface_format == DRM_FORMAT_INVALID) {
+ /*
+ * If none of the given color modes works, fall back
+ * to XRGB8888. Drivers are expected to provide this
+ * format for compatibility with legacy applications.
+ */
+ drm_warn(dev, "No compatible format found\n");
+ surface_format = drm_driver_legacy_fb_format(dev, 32, 24);
}
+ info = drm_format_info(surface_format);
+ sizes->surface_bpp = drm_format_info_bpp(info, 0);
+ sizes->surface_depth = info->depth;
+
/* first up get a count of crtcs now in use and new min/maxes width/heights */
crtc_count = 0;
drm_client_for_each_modeset(mode_set, client) {
@@ -1860,8 +1886,10 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
x = mode_set->x;
y = mode_set->y;
- sizes.surface_width = max_t(u32, desired_mode->hdisplay + x, sizes.surface_width);
- sizes.surface_height = max_t(u32, desired_mode->vdisplay + y, sizes.surface_height);
+ sizes->surface_width =
+ max_t(u32, desired_mode->hdisplay + x, sizes->surface_width);
+ sizes->surface_height =
+ max_t(u32, desired_mode->vdisplay + y, sizes->surface_height);
for (j = 0; j < mode_set->num_connectors; j++) {
struct drm_connector *connector = mode_set->connectors[j];
@@ -1877,28 +1905,63 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
}
if (lasth)
- sizes.fb_width = min_t(u32, desired_mode->hdisplay + x, sizes.fb_width);
+ sizes->fb_width = min_t(u32, desired_mode->hdisplay + x, sizes->fb_width);
if (lastv)
- sizes.fb_height = min_t(u32, desired_mode->vdisplay + y, sizes.fb_height);
+ sizes->fb_height = min_t(u32, desired_mode->vdisplay + y, sizes->fb_height);
}
- mutex_unlock(&client->modeset_mutex);
- if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) {
+ if (crtc_count == 0 || sizes->fb_width == -1 || sizes->fb_height == -1) {
drm_info(dev, "Cannot find any crtc or sizes\n");
-
- /* First time: disable all crtc's.. */
- if (!fb_helper->deferred_setup)
- drm_client_modeset_commit(client);
return -EAGAIN;
}
+ return 0;
+}
+
+static int drm_fb_helper_find_sizes(struct drm_fb_helper *fb_helper,
+ struct drm_fb_helper_surface_size *sizes)
+{
+ struct drm_client_dev *client = &fb_helper->client;
+ struct drm_device *dev = fb_helper->dev;
+ struct drm_mode_config *config = &dev->mode_config;
+ int ret;
+
+ mutex_lock(&client->modeset_mutex);
+ ret = __drm_fb_helper_find_sizes(fb_helper, sizes);
+ mutex_unlock(&client->modeset_mutex);
+
+ if (ret)
+ return ret;
+
/* Handle our overallocation */
- sizes.surface_height *= drm_fbdev_overalloc;
- sizes.surface_height /= 100;
- if (sizes.surface_height > config->max_height) {
+ sizes->surface_height *= drm_fbdev_overalloc;
+ sizes->surface_height /= 100;
+ if (sizes->surface_height > config->max_height) {
drm_dbg_kms(dev, "Fbdev over-allocation too large; clamping height to %d\n",
config->max_height);
- sizes.surface_height = config->max_height;
+ sizes->surface_height = config->max_height;
+ }
+
+ return 0;
+}
+
+/*
+ * Allocates the backing storage and sets up the fbdev info structure through
+ * the ->fb_probe callback.
+ */
+static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper)
+{
+ struct drm_client_dev *client = &fb_helper->client;
+ struct drm_device *dev = fb_helper->dev;
+ struct drm_fb_helper_surface_size sizes;
+ int ret;
+
+ ret = drm_fb_helper_find_sizes(fb_helper, &sizes);
+ if (ret) {
+ /* First time: disable all crtc's.. */
+ if (!fb_helper->deferred_setup)
+ drm_client_modeset_commit(client);
+ return ret;
}
#if IS_ENABLED(CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM)
@@ -2076,8 +2139,7 @@ static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
/* Note: Drops fb_helper->lock before returning. */
static int
-__drm_fb_helper_initial_config_and_unlock(struct drm_fb_helper *fb_helper,
- int bpp_sel)
+__drm_fb_helper_initial_config_and_unlock(struct drm_fb_helper *fb_helper)
{
struct drm_device *dev = fb_helper->dev;
struct fb_info *info;
@@ -2088,10 +2150,9 @@ __drm_fb_helper_initial_config_and_unlock(struct drm_fb_helper *fb_helper,
height = dev->mode_config.max_height;
drm_client_modeset_probe(&fb_helper->client, width, height);
- ret = drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
+ ret = drm_fb_helper_single_fb_probe(fb_helper);
if (ret < 0) {
if (ret == -EAGAIN) {
- fb_helper->preferred_bpp = bpp_sel;
fb_helper->deferred_setup = true;
ret = 0;
}
@@ -2137,7 +2198,6 @@ __drm_fb_helper_initial_config_and_unlock(struct drm_fb_helper *fb_helper,
/**
* drm_fb_helper_initial_config - setup a sane initial connector configuration
* @fb_helper: fb_helper device struct
- * @bpp_sel: bpp value to use for the framebuffer configuration
*
* Scans the CRTCs and connectors and tries to put together an initial setup.
* At the moment, this is a cloned configuration across all heads with
@@ -2175,7 +2235,7 @@ __drm_fb_helper_initial_config_and_unlock(struct drm_fb_helper *fb_helper,
* RETURNS:
* Zero if everything went ok, nonzero otherwise.
*/
-int drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
+int drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper)
{
int ret;
@@ -2183,7 +2243,7 @@ int drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
return 0;
mutex_lock(&fb_helper->lock);
- ret = __drm_fb_helper_initial_config_and_unlock(fb_helper, bpp_sel);
+ ret = __drm_fb_helper_initial_config_and_unlock(fb_helper);
return ret;
}
@@ -2219,8 +2279,7 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
mutex_lock(&fb_helper->lock);
if (fb_helper->deferred_setup) {
- err = __drm_fb_helper_initial_config_and_unlock(fb_helper,
- fb_helper->preferred_bpp);
+ err = __drm_fb_helper_initial_config_and_unlock(fb_helper);
return err;
}
diff --git a/drivers/gpu/drm/drm_fbdev_generic.c b/drivers/gpu/drm/drm_fbdev_generic.c
index 593aa3283792..4d6325e91565 100644
--- a/drivers/gpu/drm/drm_fbdev_generic.c
+++ b/drivers/gpu/drm/drm_fbdev_generic.c
@@ -43,20 +43,18 @@ static int drm_fbdev_fb_release(struct fb_info *info, int user)
return 0;
}
-static void drm_fbdev_cleanup(struct drm_fb_helper *fb_helper)
+static void drm_fbdev_fb_destroy(struct fb_info *info)
{
- struct fb_info *fbi = fb_helper->info;
+ struct drm_fb_helper *fb_helper = info->par;
void *shadow = NULL;
if (!fb_helper->dev)
return;
- if (fbi) {
- if (fbi->fbdefio)
- fb_deferred_io_cleanup(fbi);
- if (drm_fbdev_use_shadow_fb(fb_helper))
- shadow = fbi->screen_buffer;
- }
+ if (info->fbdefio)
+ fb_deferred_io_cleanup(info);
+ if (drm_fbdev_use_shadow_fb(fb_helper))
+ shadow = info->screen_buffer;
drm_fb_helper_fini(fb_helper);
@@ -66,22 +64,10 @@ static void drm_fbdev_cleanup(struct drm_fb_helper *fb_helper)
drm_client_buffer_vunmap(fb_helper->buffer);
drm_client_framebuffer_delete(fb_helper->buffer);
-}
-
-static void drm_fbdev_release(struct drm_fb_helper *fb_helper)
-{
- drm_fbdev_cleanup(fb_helper);
drm_client_release(&fb_helper->client);
- kfree(fb_helper);
-}
-/*
- * fb_ops.fb_destroy is called by the last put_fb_info() call at the end of
- * unregister_framebuffer() or fb_release().
- */
-static void drm_fbdev_fb_destroy(struct fb_info *info)
-{
- drm_fbdev_release(info->par);
+ drm_fb_helper_unprepare(fb_helper);
+ kfree(fb_helper);
}
static int drm_fbdev_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
@@ -181,7 +167,7 @@ static int drm_fbdev_fb_probe(struct drm_fb_helper *fb_helper,
struct drm_device *dev = fb_helper->dev;
struct drm_client_buffer *buffer;
struct drm_framebuffer *fb;
- struct fb_info *fbi;
+ struct fb_info *info;
u32 format;
struct iosys_map map;
int ret;
@@ -200,29 +186,29 @@ static int drm_fbdev_fb_probe(struct drm_fb_helper *fb_helper,
fb_helper->fb = buffer->fb;
fb = buffer->fb;
- fbi = drm_fb_helper_alloc_info(fb_helper);
- if (IS_ERR(fbi))
- return PTR_ERR(fbi);
+ info = drm_fb_helper_alloc_info(fb_helper);
+ if (IS_ERR(info))
+ return PTR_ERR(info);
- fbi->fbops = &drm_fbdev_fb_ops;
- fbi->screen_size = sizes->surface_height * fb->pitches[0];
- fbi->fix.smem_len = fbi->screen_size;
- fbi->flags = FBINFO_DEFAULT;
+ info->fbops = &drm_fbdev_fb_ops;
+ info->screen_size = sizes->surface_height * fb->pitches[0];
+ info->fix.smem_len = info->screen_size;
+ info->flags = FBINFO_DEFAULT;
- drm_fb_helper_fill_info(fbi, fb_helper, sizes);
+ drm_fb_helper_fill_info(info, fb_helper, sizes);
if (drm_fbdev_use_shadow_fb(fb_helper)) {
- fbi->screen_buffer = vzalloc(fbi->screen_size);
- if (!fbi->screen_buffer)
+ info->screen_buffer = vzalloc(info->screen_size);
+ if (!info->screen_buffer)
return -ENOMEM;
- fbi->flags |= FBINFO_VIRTFB | FBINFO_READS_FAST;
+ info->flags |= FBINFO_VIRTFB | FBINFO_READS_FAST;
/* Set a default deferred I/O handler */
fb_helper->fbdefio.delay = HZ / 20;
fb_helper->fbdefio.deferred_io = drm_fb_helper_deferred_io;
- fbi->fbdefio = &fb_helper->fbdefio;
- ret = fb_deferred_io_init(fbi);
+ info->fbdefio = &fb_helper->fbdefio;
+ ret = fb_deferred_io_init(info);
if (ret)
return ret;
} else {
@@ -231,10 +217,10 @@ static int drm_fbdev_fb_probe(struct drm_fb_helper *fb_helper,
if (ret)
return ret;
if (map.is_iomem) {
- fbi->screen_base = map.vaddr_iomem;
+ info->screen_base = map.vaddr_iomem;
} else {
- fbi->screen_buffer = map.vaddr;
- fbi->flags |= FBINFO_VIRTFB;
+ info->screen_buffer = map.vaddr;
+ info->flags |= FBINFO_VIRTFB;
}
/*
@@ -243,10 +229,10 @@ static int drm_fbdev_fb_probe(struct drm_fb_helper *fb_helper,
* case.
*/
#if IS_ENABLED(CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM)
- if (fb_helper->hint_leak_smem_start && fbi->fix.smem_start == 0 &&
+ if (fb_helper->hint_leak_smem_start && info->fix.smem_start == 0 &&
!drm_WARN_ON_ONCE(dev, map.is_iomem))
- fbi->fix.smem_start =
- page_to_phys(virt_to_page(fbi->screen_buffer));
+ info->fix.smem_start =
+ page_to_phys(virt_to_page(info->screen_buffer));
#endif
}
@@ -363,11 +349,13 @@ static void drm_fbdev_client_unregister(struct drm_client_dev *client)
{
struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
- if (fb_helper->info)
- /* drm_fbdev_fb_destroy() takes care of cleanup */
+ if (fb_helper->info) {
drm_fb_helper_unregister_info(fb_helper);
- else
- drm_fbdev_release(fb_helper);
+ } else {
+ drm_client_release(&fb_helper->client);
+ drm_fb_helper_unprepare(fb_helper);
+ kfree(fb_helper);
+ }
}
static int drm_fbdev_client_restore(struct drm_client_dev *client)
@@ -383,41 +371,26 @@ static int drm_fbdev_client_hotplug(struct drm_client_dev *client)
struct drm_device *dev = client->dev;
int ret;
- /* Setup is not retried if it has failed */
- if (!fb_helper->dev && fb_helper->funcs)
- return 0;
-
if (dev->fb_helper)
return drm_fb_helper_hotplug_event(dev->fb_helper);
- if (!dev->mode_config.num_connector) {
- drm_dbg_kms(dev, "No connectors found, will not create framebuffer!\n");
- return 0;
- }
-
- drm_fb_helper_prepare(dev, fb_helper, &drm_fb_helper_generic_funcs);
-
ret = drm_fb_helper_init(dev, fb_helper);
if (ret)
- goto err;
+ goto err_drm_err;
if (!drm_drv_uses_atomic_modeset(dev))
drm_helper_disable_unused_functions(dev);
- ret = drm_fb_helper_initial_config(fb_helper, fb_helper->preferred_bpp);
+ ret = drm_fb_helper_initial_config(fb_helper);
if (ret)
- goto err_cleanup;
+ goto err_drm_fb_helper_fini;
return 0;
-err_cleanup:
- drm_fbdev_cleanup(fb_helper);
-err:
- fb_helper->dev = NULL;
- fb_helper->info = NULL;
-
+err_drm_fb_helper_fini:
+ drm_fb_helper_fini(fb_helper);
+err_drm_err:
drm_err(dev, "fbdev: Failed to setup generic emulation (ret=%d)\n", ret);
-
return ret;
}
@@ -432,7 +405,6 @@ static const struct drm_client_funcs drm_fbdev_client_funcs = {
* drm_fbdev_generic_setup() - Setup generic fbdev emulation
* @dev: DRM device
* @preferred_bpp: Preferred bits per pixel for the device.
- * @dev->mode_config.preferred_depth is used if this is zero.
*
* This function sets up generic fbdev emulation for drivers that supports
* dumb buffers with a virtual address and that can be mmap'ed.
@@ -467,29 +439,25 @@ void drm_fbdev_generic_setup(struct drm_device *dev,
fb_helper = kzalloc(sizeof(*fb_helper), GFP_KERNEL);
if (!fb_helper)
return;
+ drm_fb_helper_prepare(dev, fb_helper, preferred_bpp, &drm_fb_helper_generic_funcs);
ret = drm_client_init(dev, &fb_helper->client, "fbdev", &drm_fbdev_client_funcs);
if (ret) {
- kfree(fb_helper);
drm_err(dev, "Failed to register client: %d\n", ret);
- return;
+ goto err_drm_client_init;
}
- /*
- * FIXME: This mixes up depth with bpp, which results in a glorious
- * mess, resulting in some drivers picking wrong fbdev defaults and
- * others wrong preferred_depth defaults.
- */
- if (!preferred_bpp)
- preferred_bpp = dev->mode_config.preferred_depth;
- if (!preferred_bpp)
- preferred_bpp = 32;
- fb_helper->preferred_bpp = preferred_bpp;
-
ret = drm_fbdev_client_hotplug(&fb_helper->client);
if (ret)
drm_dbg_kms(dev, "client hotplug ret=%d\n", ret);
drm_client_register(&fb_helper->client);
+
+ return;
+
+err_drm_client_init:
+ drm_fb_helper_unprepare(fb_helper);
+ kfree(fb_helper);
+ return;
}
EXPORT_SYMBOL(drm_fbdev_generic_setup);
diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c
index 64b4a3a87fbb..a51ff8cee049 100644
--- a/drivers/gpu/drm/drm_file.c
+++ b/drivers/gpu/drm/drm_file.c
@@ -245,10 +245,10 @@ void drm_file_free(struct drm_file *file)
dev = file->minor->dev;
- DRM_DEBUG("comm=\"%s\", pid=%d, dev=0x%lx, open_count=%d\n",
- current->comm, task_pid_nr(current),
- (long)old_encode_dev(file->minor->kdev->devt),
- atomic_read(&dev->open_count));
+ drm_dbg_core(dev, "comm=\"%s\", pid=%d, dev=0x%lx, open_count=%d\n",
+ current->comm, task_pid_nr(current),
+ (long)old_encode_dev(file->minor->kdev->devt),
+ atomic_read(&dev->open_count));
#ifdef CONFIG_DRM_LEGACY
if (drm_core_check_feature(dev, DRIVER_LEGACY) &&
@@ -340,8 +340,8 @@ int drm_open_helper(struct file *filp, struct drm_minor *minor)
dev->switch_power_state != DRM_SWITCH_POWER_DYNAMIC_OFF)
return -EINVAL;
- DRM_DEBUG("comm=\"%s\", pid=%d, minor=%d\n", current->comm,
- task_pid_nr(current), minor->index);
+ drm_dbg_core(dev, "comm=\"%s\", pid=%d, minor=%d\n",
+ current->comm, task_pid_nr(current), minor->index);
priv = drm_file_alloc(minor);
if (IS_ERR(priv))
@@ -450,11 +450,11 @@ EXPORT_SYMBOL(drm_open);
void drm_lastclose(struct drm_device * dev)
{
- DRM_DEBUG("\n");
+ drm_dbg_core(dev, "\n");
if (dev->driver->lastclose)
dev->driver->lastclose(dev);
- DRM_DEBUG("driver lastclose completed\n");
+ drm_dbg_core(dev, "driver lastclose completed\n");
if (drm_core_check_feature(dev, DRIVER_LEGACY))
drm_legacy_dev_reinit(dev);
@@ -485,7 +485,7 @@ int drm_release(struct inode *inode, struct file *filp)
if (drm_dev_needs_global_mutex(dev))
mutex_lock(&drm_global_mutex);
- DRM_DEBUG("open_count = %d\n", atomic_read(&dev->open_count));
+ drm_dbg_core(dev, "open_count = %d\n", atomic_read(&dev->open_count));
drm_close_helper(filp);
diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c
index 74ff33c2ddaa..f93a4efcee90 100644
--- a/drivers/gpu/drm/drm_format_helper.c
+++ b/drivers/gpu/drm/drm_format_helper.c
@@ -322,7 +322,7 @@ EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb332);
static void drm_fb_xrgb8888_to_rgb565_line(void *dbuf, const void *sbuf, unsigned int pixels)
{
- u16 *dbuf16 = dbuf;
+ __le16 *dbuf16 = dbuf;
const __le32 *sbuf32 = sbuf;
unsigned int x;
u16 val16;
@@ -333,14 +333,15 @@ static void drm_fb_xrgb8888_to_rgb565_line(void *dbuf, const void *sbuf, unsigne
val16 = ((pix & 0x00F80000) >> 8) |
((pix & 0x0000FC00) >> 5) |
((pix & 0x000000F8) >> 3);
- dbuf16[x] = val16;
+ dbuf16[x] = cpu_to_le16(val16);
}
}
+/* TODO: implement this helper as conversion to RGB565|BIG_ENDIAN */
static void drm_fb_xrgb8888_to_rgb565_swab_line(void *dbuf, const void *sbuf,
unsigned int pixels)
{
- u16 *dbuf16 = dbuf;
+ __le16 *dbuf16 = dbuf;
const __le32 *sbuf32 = sbuf;
unsigned int x;
u16 val16;
@@ -351,7 +352,7 @@ static void drm_fb_xrgb8888_to_rgb565_swab_line(void *dbuf, const void *sbuf,
val16 = ((pix & 0x00F80000) >> 8) |
((pix & 0x0000FC00) >> 5) |
((pix & 0x000000F8) >> 3);
- dbuf16[x] = swab16(val16);
+ dbuf16[x] = cpu_to_le16(swab16(val16));
}
}
@@ -395,6 +396,161 @@ void drm_fb_xrgb8888_to_rgb565(struct iosys_map *dst, const unsigned int *dst_pi
}
EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565);
+static void drm_fb_xrgb8888_to_xrgb1555_line(void *dbuf, const void *sbuf, unsigned int pixels)
+{
+ __le16 *dbuf16 = dbuf;
+ const __le32 *sbuf32 = sbuf;
+ unsigned int x;
+ u16 val16;
+ u32 pix;
+
+ for (x = 0; x < pixels; x++) {
+ pix = le32_to_cpu(sbuf32[x]);
+ val16 = ((pix & 0x00f80000) >> 9) |
+ ((pix & 0x0000f800) >> 6) |
+ ((pix & 0x000000f8) >> 3);
+ dbuf16[x] = cpu_to_le16(val16);
+ }
+}
+
+/**
+ * drm_fb_xrgb8888_to_xrgb1555 - Convert XRGB8888 to XRGB1555 clip buffer
+ * @dst: Array of XRGB1555 destination buffers
+ * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
+ * within @dst; can be NULL if scanlines are stored next to each other.
+ * @src: Array of XRGB8888 source buffer
+ * @fb: DRM framebuffer
+ * @clip: Clip rectangle area to copy
+ *
+ * This function copies parts of a framebuffer to display memory and converts
+ * the color format during the process. The parameters @dst, @dst_pitch and
+ * @src refer to arrays. Each array must have at least as many entries as
+ * there are planes in @fb's format. Each entry stores the value for the
+ * format's respective color plane at the same index.
+ *
+ * This function does not apply clipping on @dst (i.e. the destination is at the
+ * top-left corner).
+ *
+ * Drivers can use this function for XRGB1555 devices that don't support
+ * XRGB8888 natively.
+ */
+void drm_fb_xrgb8888_to_xrgb1555(struct iosys_map *dst, const unsigned int *dst_pitch,
+ const struct iosys_map *src, const struct drm_framebuffer *fb,
+ const struct drm_rect *clip)
+{
+ static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
+ 2,
+ };
+
+ drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
+ drm_fb_xrgb8888_to_xrgb1555_line);
+}
+EXPORT_SYMBOL(drm_fb_xrgb8888_to_xrgb1555);
+
+static void drm_fb_xrgb8888_to_argb1555_line(void *dbuf, const void *sbuf, unsigned int pixels)
+{
+ __le16 *dbuf16 = dbuf;
+ const __le32 *sbuf32 = sbuf;
+ unsigned int x;
+ u16 val16;
+ u32 pix;
+
+ for (x = 0; x < pixels; x++) {
+ pix = le32_to_cpu(sbuf32[x]);
+ val16 = BIT(15) | /* set alpha bit */
+ ((pix & 0x00f80000) >> 9) |
+ ((pix & 0x0000f800) >> 6) |
+ ((pix & 0x000000f8) >> 3);
+ dbuf16[x] = cpu_to_le16(val16);
+ }
+}
+
+/**
+ * drm_fb_xrgb8888_to_argb1555 - Convert XRGB8888 to ARGB1555 clip buffer
+ * @dst: Array of ARGB1555 destination buffers
+ * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
+ * within @dst; can be NULL if scanlines are stored next to each other.
+ * @src: Array of XRGB8888 source buffer
+ * @fb: DRM framebuffer
+ * @clip: Clip rectangle area to copy
+ *
+ * This function copies parts of a framebuffer to display memory and converts
+ * the color format during the process. The parameters @dst, @dst_pitch and
+ * @src refer to arrays. Each array must have at least as many entries as
+ * there are planes in @fb's format. Each entry stores the value for the
+ * format's respective color plane at the same index.
+ *
+ * This function does not apply clipping on @dst (i.e. the destination is at the
+ * top-left corner).
+ *
+ * Drivers can use this function for ARGB1555 devices that don't support
+ * XRGB8888 natively. It sets an opaque alpha channel as part of the conversion.
+ */
+void drm_fb_xrgb8888_to_argb1555(struct iosys_map *dst, const unsigned int *dst_pitch,
+ const struct iosys_map *src, const struct drm_framebuffer *fb,
+ const struct drm_rect *clip)
+{
+ static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
+ 2,
+ };
+
+ drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
+ drm_fb_xrgb8888_to_argb1555_line);
+}
+EXPORT_SYMBOL(drm_fb_xrgb8888_to_argb1555);
+
+static void drm_fb_xrgb8888_to_rgba5551_line(void *dbuf, const void *sbuf, unsigned int pixels)
+{
+ __le16 *dbuf16 = dbuf;
+ const __le32 *sbuf32 = sbuf;
+ unsigned int x;
+ u16 val16;
+ u32 pix;
+
+ for (x = 0; x < pixels; x++) {
+ pix = le32_to_cpu(sbuf32[x]);
+ val16 = ((pix & 0x00f80000) >> 8) |
+ ((pix & 0x0000f800) >> 5) |
+ ((pix & 0x000000f8) >> 2) |
+ BIT(0); /* set alpha bit */
+ dbuf16[x] = cpu_to_le16(val16);
+ }
+}
+
+/**
+ * drm_fb_xrgb8888_to_rgba5551 - Convert XRGB8888 to RGBA5551 clip buffer
+ * @dst: Array of RGBA5551 destination buffers
+ * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
+ * within @dst; can be NULL if scanlines are stored next to each other.
+ * @src: Array of XRGB8888 source buffer
+ * @fb: DRM framebuffer
+ * @clip: Clip rectangle area to copy
+ *
+ * This function copies parts of a framebuffer to display memory and converts
+ * the color format during the process. The parameters @dst, @dst_pitch and
+ * @src refer to arrays. Each array must have at least as many entries as
+ * there are planes in @fb's format. Each entry stores the value for the
+ * format's respective color plane at the same index.
+ *
+ * This function does not apply clipping on @dst (i.e. the destination is at the
+ * top-left corner).
+ *
+ * Drivers can use this function for RGBA5551 devices that don't support
+ * XRGB8888 natively. It sets an opaque alpha channel as part of the conversion.
+ */
+void drm_fb_xrgb8888_to_rgba5551(struct iosys_map *dst, const unsigned int *dst_pitch,
+ const struct iosys_map *src, const struct drm_framebuffer *fb,
+ const struct drm_rect *clip)
+{
+ static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
+ 2,
+ };
+
+ drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
+ drm_fb_xrgb8888_to_rgba5551_line);
+}
+EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgba5551);
+
static void drm_fb_xrgb8888_to_rgb888_line(void *dbuf, const void *sbuf, unsigned int pixels)
{
u8 *dbuf8 = dbuf;
@@ -404,6 +560,7 @@ static void drm_fb_xrgb8888_to_rgb888_line(void *dbuf, const void *sbuf, unsigne
for (x = 0; x < pixels; x++) {
pix = le32_to_cpu(sbuf32[x]);
+ /* write blue-green-red to output in little endianness */
*dbuf8++ = (pix & 0x000000FF) >> 0;
*dbuf8++ = (pix & 0x0000FF00) >> 8;
*dbuf8++ = (pix & 0x00FF0000) >> 16;
@@ -444,63 +601,112 @@ void drm_fb_xrgb8888_to_rgb888(struct iosys_map *dst, const unsigned int *dst_pi
}
EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888);
-static void drm_fb_rgb565_to_xrgb8888_line(void *dbuf, const void *sbuf, unsigned int pixels)
+static void drm_fb_xrgb8888_to_argb8888_line(void *dbuf, const void *sbuf, unsigned int pixels)
{
__le32 *dbuf32 = dbuf;
- const __le16 *sbuf16 = sbuf;
+ const __le32 *sbuf32 = sbuf;
unsigned int x;
+ u32 pix;
for (x = 0; x < pixels; x++) {
- u16 val16 = le16_to_cpu(sbuf16[x]);
- u32 val32 = ((val16 & 0xf800) << 8) |
- ((val16 & 0x07e0) << 5) |
- ((val16 & 0x001f) << 3);
- val32 = 0xff000000 | val32 |
- ((val32 >> 3) & 0x00070007) |
- ((val32 >> 2) & 0x00000300);
- dbuf32[x] = cpu_to_le32(val32);
+ pix = le32_to_cpu(sbuf32[x]);
+ pix |= GENMASK(31, 24); /* fill alpha bits */
+ dbuf32[x] = cpu_to_le32(pix);
}
}
-static void drm_fb_rgb565_to_xrgb8888(struct iosys_map *dst, const unsigned int *dst_pitch,
- const struct iosys_map *src,
- const struct drm_framebuffer *fb,
- const struct drm_rect *clip)
+/**
+ * drm_fb_xrgb8888_to_argb8888 - Convert XRGB8888 to ARGB8888 clip buffer
+ * @dst: Array of ARGB8888 destination buffers
+ * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
+ * within @dst; can be NULL if scanlines are stored next to each other.
+ * @src: Array of XRGB8888 source buffer
+ * @fb: DRM framebuffer
+ * @clip: Clip rectangle area to copy
+ *
+ * This function copies parts of a framebuffer to display memory and converts the
+ * color format during the process. The parameters @dst, @dst_pitch and @src refer
+ * to arrays. Each array must have at least as many entries as there are planes in
+ * @fb's format. Each entry stores the value for the format's respective color plane
+ * at the same index.
+ *
+ * This function does not apply clipping on @dst (i.e. the destination is at the
+ * top-left corner).
+ *
+ * Drivers can use this function for ARGB8888 devices that don't support XRGB8888
+ * natively. It sets an opaque alpha channel as part of the conversion.
+ */
+void drm_fb_xrgb8888_to_argb8888(struct iosys_map *dst, const unsigned int *dst_pitch,
+ const struct iosys_map *src, const struct drm_framebuffer *fb,
+ const struct drm_rect *clip)
{
static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
4,
};
drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
- drm_fb_rgb565_to_xrgb8888_line);
+ drm_fb_xrgb8888_to_argb8888_line);
}
+EXPORT_SYMBOL(drm_fb_xrgb8888_to_argb8888);
-static void drm_fb_rgb888_to_xrgb8888_line(void *dbuf, const void *sbuf, unsigned int pixels)
+static void drm_fb_xrgb8888_to_abgr8888_line(void *dbuf, const void *sbuf, unsigned int pixels)
{
__le32 *dbuf32 = dbuf;
- const u8 *sbuf8 = sbuf;
+ const __le32 *sbuf32 = sbuf;
unsigned int x;
+ u32 pix;
for (x = 0; x < pixels; x++) {
- u8 r = *sbuf8++;
- u8 g = *sbuf8++;
- u8 b = *sbuf8++;
- u32 pix = 0xff000000 | (r << 16) | (g << 8) | b;
- dbuf32[x] = cpu_to_le32(pix);
+ pix = le32_to_cpu(sbuf32[x]);
+ pix = ((pix & 0x00ff0000) >> 16) << 0 |
+ ((pix & 0x0000ff00) >> 8) << 8 |
+ ((pix & 0x000000ff) >> 0) << 16 |
+ GENMASK(31, 24); /* fill alpha bits */
+ *dbuf32++ = cpu_to_le32(pix);
}
}
-static void drm_fb_rgb888_to_xrgb8888(struct iosys_map *dst, const unsigned int *dst_pitch,
- const struct iosys_map *src,
- const struct drm_framebuffer *fb,
- const struct drm_rect *clip)
+static void drm_fb_xrgb8888_to_abgr8888(struct iosys_map *dst, const unsigned int *dst_pitch,
+ const struct iosys_map *src,
+ const struct drm_framebuffer *fb,
+ const struct drm_rect *clip)
{
static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
4,
};
drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
- drm_fb_rgb888_to_xrgb8888_line);
+ drm_fb_xrgb8888_to_abgr8888_line);
+}
+
+static void drm_fb_xrgb8888_to_xbgr8888_line(void *dbuf, const void *sbuf, unsigned int pixels)
+{
+ __le32 *dbuf32 = dbuf;
+ const __le32 *sbuf32 = sbuf;
+ unsigned int x;
+ u32 pix;
+
+ for (x = 0; x < pixels; x++) {
+ pix = le32_to_cpu(sbuf32[x]);
+ pix = ((pix & 0x00ff0000) >> 16) << 0 |
+ ((pix & 0x0000ff00) >> 8) << 8 |
+ ((pix & 0x000000ff) >> 0) << 16 |
+ ((pix & 0xff000000) >> 24) << 24;
+ *dbuf32++ = cpu_to_le32(pix);
+ }
+}
+
+static void drm_fb_xrgb8888_to_xbgr8888(struct iosys_map *dst, const unsigned int *dst_pitch,
+ const struct iosys_map *src,
+ const struct drm_framebuffer *fb,
+ const struct drm_rect *clip)
+{
+ static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
+ 4,
+ };
+
+ drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
+ drm_fb_xrgb8888_to_xbgr8888_line);
}
static void drm_fb_xrgb8888_to_xrgb2101010_line(void *dbuf, const void *sbuf, unsigned int pixels)
@@ -555,6 +761,59 @@ void drm_fb_xrgb8888_to_xrgb2101010(struct iosys_map *dst, const unsigned int *d
}
EXPORT_SYMBOL(drm_fb_xrgb8888_to_xrgb2101010);
+static void drm_fb_xrgb8888_to_argb2101010_line(void *dbuf, const void *sbuf, unsigned int pixels)
+{
+ __le32 *dbuf32 = dbuf;
+ const __le32 *sbuf32 = sbuf;
+ unsigned int x;
+ u32 val32;
+ u32 pix;
+
+ for (x = 0; x < pixels; x++) {
+ pix = le32_to_cpu(sbuf32[x]);
+ val32 = ((pix & 0x000000ff) << 2) |
+ ((pix & 0x0000ff00) << 4) |
+ ((pix & 0x00ff0000) << 6);
+ pix = GENMASK(31, 30) | /* set alpha bits */
+ val32 | ((val32 >> 8) & 0x00300c03);
+ *dbuf32++ = cpu_to_le32(pix);
+ }
+}
+
+/**
+ * drm_fb_xrgb8888_to_argb2101010 - Convert XRGB8888 to ARGB2101010 clip buffer
+ * @dst: Array of ARGB2101010 destination buffers
+ * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
+ * within @dst; can be NULL if scanlines are stored next to each other.
+ * @src: Array of XRGB8888 source buffers
+ * @fb: DRM framebuffer
+ * @clip: Clip rectangle area to copy
+ *
+ * This function copies parts of a framebuffer to display memory and converts
+ * the color format during the process. The parameters @dst, @dst_pitch and
+ * @src refer to arrays. Each array must have at least as many entries as
+ * there are planes in @fb's format. Each entry stores the value for the
+ * format's respective color plane at the same index.
+ *
+ * This function does not apply clipping on @dst (i.e. the destination is at the
+ * top-left corner).
+ *
+ * Drivers can use this function for ARGB2101010 devices that don't support XRGB8888
+ * natively.
+ */
+void drm_fb_xrgb8888_to_argb2101010(struct iosys_map *dst, const unsigned int *dst_pitch,
+ const struct iosys_map *src, const struct drm_framebuffer *fb,
+ const struct drm_rect *clip)
+{
+ static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
+ 4,
+ };
+
+ drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
+ drm_fb_xrgb8888_to_argb2101010_line);
+}
+EXPORT_SYMBOL(drm_fb_xrgb8888_to_argb2101010);
+
static void drm_fb_xrgb8888_to_gray8_line(void *dbuf, const void *sbuf, unsigned int pixels)
{
u8 *dbuf8 = dbuf;
@@ -641,50 +900,47 @@ int drm_fb_blit(struct iosys_map *dst, const unsigned int *dst_pitch, uint32_t d
{
uint32_t fb_format = fb->format->format;
- /* treat alpha channel like filler bits */
- if (fb_format == DRM_FORMAT_ARGB8888)
- fb_format = DRM_FORMAT_XRGB8888;
- if (dst_format == DRM_FORMAT_ARGB8888)
- dst_format = DRM_FORMAT_XRGB8888;
- if (fb_format == DRM_FORMAT_ARGB2101010)
- fb_format = DRM_FORMAT_XRGB2101010;
- if (dst_format == DRM_FORMAT_ARGB2101010)
- dst_format = DRM_FORMAT_XRGB2101010;
-
- if (dst_format == fb_format) {
+ if (fb_format == dst_format) {
drm_fb_memcpy(dst, dst_pitch, src, fb, clip);
return 0;
-
- } else if (dst_format == DRM_FORMAT_RGB565) {
- if (fb_format == DRM_FORMAT_XRGB8888) {
+ } else if (fb_format == (dst_format | DRM_FORMAT_BIG_ENDIAN)) {
+ drm_fb_swab(dst, dst_pitch, src, fb, clip, false);
+ return 0;
+ } else if (fb_format == (dst_format & ~DRM_FORMAT_BIG_ENDIAN)) {
+ drm_fb_swab(dst, dst_pitch, src, fb, clip, false);
+ return 0;
+ } else if (fb_format == DRM_FORMAT_XRGB8888) {
+ if (dst_format == DRM_FORMAT_RGB565) {
drm_fb_xrgb8888_to_rgb565(dst, dst_pitch, src, fb, clip, false);
return 0;
- }
- } else if (dst_format == (DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN)) {
- if (fb_format == DRM_FORMAT_RGB565) {
- drm_fb_swab(dst, dst_pitch, src, fb, clip, false);
+ } else if (dst_format == DRM_FORMAT_XRGB1555) {
+ drm_fb_xrgb8888_to_xrgb1555(dst, dst_pitch, src, fb, clip);
return 0;
- }
- } else if (dst_format == DRM_FORMAT_RGB888) {
- if (fb_format == DRM_FORMAT_XRGB8888) {
+ } else if (dst_format == DRM_FORMAT_ARGB1555) {
+ drm_fb_xrgb8888_to_argb1555(dst, dst_pitch, src, fb, clip);
+ return 0;
+ } else if (dst_format == DRM_FORMAT_RGBA5551) {
+ drm_fb_xrgb8888_to_rgba5551(dst, dst_pitch, src, fb, clip);
+ return 0;
+ } else if (dst_format == DRM_FORMAT_RGB888) {
drm_fb_xrgb8888_to_rgb888(dst, dst_pitch, src, fb, clip);
return 0;
- }
- } else if (dst_format == DRM_FORMAT_XRGB8888) {
- if (fb_format == DRM_FORMAT_RGB888) {
- drm_fb_rgb888_to_xrgb8888(dst, dst_pitch, src, fb, clip);
+ } else if (dst_format == DRM_FORMAT_ARGB8888) {
+ drm_fb_xrgb8888_to_argb8888(dst, dst_pitch, src, fb, clip);
return 0;
- } else if (fb_format == DRM_FORMAT_RGB565) {
- drm_fb_rgb565_to_xrgb8888(dst, dst_pitch, src, fb, clip);
+ } else if (dst_format == DRM_FORMAT_XBGR8888) {
+ drm_fb_xrgb8888_to_xbgr8888(dst, dst_pitch, src, fb, clip);
return 0;
- }
- } else if (dst_format == DRM_FORMAT_XRGB2101010) {
- if (fb_format == DRM_FORMAT_XRGB8888) {
+ } else if (dst_format == DRM_FORMAT_ABGR8888) {
+ drm_fb_xrgb8888_to_abgr8888(dst, dst_pitch, src, fb, clip);
+ return 0;
+ } else if (dst_format == DRM_FORMAT_XRGB2101010) {
drm_fb_xrgb8888_to_xrgb2101010(dst, dst_pitch, src, fb, clip);
return 0;
- }
- } else if (dst_format == DRM_FORMAT_BGRX8888) {
- if (fb_format == DRM_FORMAT_XRGB8888) {
+ } else if (dst_format == DRM_FORMAT_ARGB2101010) {
+ drm_fb_xrgb8888_to_argb2101010(dst, dst_pitch, src, fb, clip);
+ return 0;
+ } else if (dst_format == DRM_FORMAT_BGRX8888) {
drm_fb_swab(dst, dst_pitch, src, fb, clip, false);
return 0;
}
@@ -805,6 +1061,39 @@ void drm_fb_xrgb8888_to_mono(struct iosys_map *dst, const unsigned int *dst_pitc
}
EXPORT_SYMBOL(drm_fb_xrgb8888_to_mono);
+static uint32_t drm_fb_nonalpha_fourcc(uint32_t fourcc)
+{
+ /* only handle formats with depth != 0 and alpha channel */
+ switch (fourcc) {
+ case DRM_FORMAT_ARGB1555:
+ return DRM_FORMAT_XRGB1555;
+ case DRM_FORMAT_ABGR1555:
+ return DRM_FORMAT_XBGR1555;
+ case DRM_FORMAT_RGBA5551:
+ return DRM_FORMAT_RGBX5551;
+ case DRM_FORMAT_BGRA5551:
+ return DRM_FORMAT_BGRX5551;
+ case DRM_FORMAT_ARGB8888:
+ return DRM_FORMAT_XRGB8888;
+ case DRM_FORMAT_ABGR8888:
+ return DRM_FORMAT_XBGR8888;
+ case DRM_FORMAT_RGBA8888:
+ return DRM_FORMAT_RGBX8888;
+ case DRM_FORMAT_BGRA8888:
+ return DRM_FORMAT_BGRX8888;
+ case DRM_FORMAT_ARGB2101010:
+ return DRM_FORMAT_XRGB2101010;
+ case DRM_FORMAT_ABGR2101010:
+ return DRM_FORMAT_XBGR2101010;
+ case DRM_FORMAT_RGBA1010102:
+ return DRM_FORMAT_RGBX1010102;
+ case DRM_FORMAT_BGRA1010102:
+ return DRM_FORMAT_BGRX1010102;
+ }
+
+ return fourcc;
+}
+
static bool is_listed_fourcc(const uint32_t *fourccs, size_t nfourccs, uint32_t fourcc)
{
const uint32_t *fourccs_end = fourccs + nfourccs;
@@ -817,73 +1106,48 @@ static bool is_listed_fourcc(const uint32_t *fourccs, size_t nfourccs, uint32_t
return false;
}
-static const uint32_t conv_from_xrgb8888[] = {
- DRM_FORMAT_XRGB8888,
- DRM_FORMAT_ARGB8888,
- DRM_FORMAT_XRGB2101010,
- DRM_FORMAT_ARGB2101010,
- DRM_FORMAT_RGB565,
- DRM_FORMAT_RGB888,
-};
-
-static const uint32_t conv_from_rgb565_888[] = {
- DRM_FORMAT_XRGB8888,
- DRM_FORMAT_ARGB8888,
-};
-
-static bool is_conversion_supported(uint32_t from, uint32_t to)
-{
- switch (from) {
- case DRM_FORMAT_XRGB8888:
- case DRM_FORMAT_ARGB8888:
- return is_listed_fourcc(conv_from_xrgb8888, ARRAY_SIZE(conv_from_xrgb8888), to);
- case DRM_FORMAT_RGB565:
- case DRM_FORMAT_RGB888:
- return is_listed_fourcc(conv_from_rgb565_888, ARRAY_SIZE(conv_from_rgb565_888), to);
- case DRM_FORMAT_XRGB2101010:
- return to == DRM_FORMAT_ARGB2101010;
- case DRM_FORMAT_ARGB2101010:
- return to == DRM_FORMAT_XRGB2101010;
- default:
- return false;
- }
-}
-
/**
* drm_fb_build_fourcc_list - Filters a list of supported color formats against
* the device's native formats
* @dev: DRM device
* @native_fourccs: 4CC codes of natively supported color formats
* @native_nfourccs: The number of entries in @native_fourccs
- * @driver_fourccs: 4CC codes of all driver-supported color formats
- * @driver_nfourccs: The number of entries in @driver_fourccs
* @fourccs_out: Returns 4CC codes of supported color formats
* @nfourccs_out: The number of available entries in @fourccs_out
*
* This function create a list of supported color format from natively
- * supported formats and the emulated formats.
+ * supported formats and additional emulated formats.
* At a minimum, most userspace programs expect at least support for
* XRGB8888 on the primary plane. Devices that have to emulate the
* format, and possibly others, can use drm_fb_build_fourcc_list() to
* create a list of supported color formats. The returned list can
* be handed over to drm_universal_plane_init() et al. Native formats
- * will go before emulated formats. Other heuristics might be applied
+ * will go before emulated formats. Native formats with alpha channel
+ * will be replaced by such without, as primary planes usually don't
+ * support alpha. Other heuristics might be applied
* to optimize the order. Formats near the beginning of the list are
- * usually preferred over formats near the end of the list. Formats
- * without conversion helpers will be skipped. New drivers should only
- * pass in XRGB8888 and avoid exposing additional emulated formats.
+ * usually preferred over formats near the end of the list.
*
* Returns:
* The number of color-formats 4CC codes returned in @fourccs_out.
*/
size_t drm_fb_build_fourcc_list(struct drm_device *dev,
const u32 *native_fourccs, size_t native_nfourccs,
- const u32 *driver_fourccs, size_t driver_nfourccs,
u32 *fourccs_out, size_t nfourccs_out)
{
+ /*
+ * XRGB8888 is the default fallback format for most of userspace
+ * and it's currently the only format that should be emulated for
+ * the primary plane. Only if there's ever another default fallback,
+ * it should be added here.
+ */
+ static const uint32_t extra_fourccs[] = {
+ DRM_FORMAT_XRGB8888,
+ };
+ static const size_t extra_nfourccs = ARRAY_SIZE(extra_fourccs);
+
u32 *fourccs = fourccs_out;
const u32 *fourccs_end = fourccs_out + nfourccs_out;
- uint32_t native_format = 0;
size_t i;
/*
@@ -891,7 +1155,12 @@ size_t drm_fb_build_fourcc_list(struct drm_device *dev,
*/
for (i = 0; i < native_nfourccs; ++i) {
- u32 fourcc = native_fourccs[i];
+ /*
+ * Several DTs, boot loaders and firmware report native
+ * alpha formats that are non-alpha formats instead. So
+ * replace alpha formats by non-alpha formats.
+ */
+ u32 fourcc = drm_fb_nonalpha_fourcc(native_fourccs[i]);
if (is_listed_fourcc(fourccs_out, fourccs - fourccs_out, fourcc)) {
continue; /* skip duplicate entries */
@@ -902,14 +1171,6 @@ size_t drm_fb_build_fourcc_list(struct drm_device *dev,
drm_dbg_kms(dev, "adding native format %p4cc\n", &fourcc);
- /*
- * There should only be one native format with the current API.
- * This API needs to be refactored to correctly support arbitrary
- * sets of native formats, since it needs to report which native
- * format to use for each emulated format.
- */
- if (!native_format)
- native_format = fourcc;
*fourccs = fourcc;
++fourccs;
}
@@ -918,17 +1179,14 @@ size_t drm_fb_build_fourcc_list(struct drm_device *dev,
* The extra formats, emulated by the driver, go second.
*/
- for (i = 0; (i < driver_nfourccs) && (fourccs < fourccs_end); ++i) {
- u32 fourcc = driver_fourccs[i];
+ for (i = 0; (i < extra_nfourccs) && (fourccs < fourccs_end); ++i) {
+ u32 fourcc = extra_fourccs[i];
if (is_listed_fourcc(fourccs_out, fourccs - fourccs_out, fourcc)) {
continue; /* skip duplicate and native entries */
} else if (fourccs == fourccs_end) {
drm_warn(dev, "Ignoring emulated format %p4cc\n", &fourcc);
continue; /* end of available output buffer */
- } else if (!is_conversion_supported(fourcc, native_format)) {
- drm_dbg_kms(dev, "Unsupported emulated format %p4cc\n", &fourcc);
- continue; /* format is not supported for conversion */
}
drm_dbg_kms(dev, "adding emulated format %p4cc\n", &fourcc);
diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c
index 6242dfbe9240..0f17dfa8702b 100644
--- a/drivers/gpu/drm/drm_fourcc.c
+++ b/drivers/gpu/drm/drm_fourcc.c
@@ -190,6 +190,10 @@ const struct drm_format_info *__drm_format_info(u32 format)
{ .format = DRM_FORMAT_BGRA5551, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true },
{ .format = DRM_FORMAT_RGB565, .depth = 16, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
{ .format = DRM_FORMAT_BGR565, .depth = 16, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
+#ifdef __BIG_ENDIAN
+ { .format = DRM_FORMAT_XRGB1555 | DRM_FORMAT_BIG_ENDIAN, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
+ { .format = DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN, .depth = 16, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 },
+#endif
{ .format = DRM_FORMAT_RGB888, .depth = 24, .num_planes = 1, .cpp = { 3, 0, 0 }, .hsub = 1, .vsub = 1 },
{ .format = DRM_FORMAT_BGR888, .depth = 24, .num_planes = 1, .cpp = { 3, 0, 0 }, .hsub = 1, .vsub = 1 },
{ .format = DRM_FORMAT_XRGB8888, .depth = 24, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c
index 2dd97473ca10..aff3746dedfb 100644
--- a/drivers/gpu/drm/drm_framebuffer.c
+++ b/drivers/gpu/drm/drm_framebuffer.c
@@ -1203,8 +1203,8 @@ void drm_framebuffer_print_info(struct drm_printer *p, unsigned int indent,
#ifdef CONFIG_DEBUG_FS
static int drm_framebuffer_info(struct seq_file *m, void *data)
{
- struct drm_info_node *node = m->private;
- struct drm_device *dev = node->minor->dev;
+ struct drm_debugfs_entry *entry = m->private;
+ struct drm_device *dev = entry->dev;
struct drm_printer p = drm_seq_file_printer(m);
struct drm_framebuffer *fb;
@@ -1218,14 +1218,13 @@ static int drm_framebuffer_info(struct seq_file *m, void *data)
return 0;
}
-static const struct drm_info_list drm_framebuffer_debugfs_list[] = {
+static const struct drm_debugfs_info drm_framebuffer_debugfs_list[] = {
{ "framebuffer", drm_framebuffer_info, 0 },
};
void drm_framebuffer_debugfs_init(struct drm_minor *minor)
{
- drm_debugfs_create_files(drm_framebuffer_debugfs_list,
- ARRAY_SIZE(drm_framebuffer_debugfs_list),
- minor->debugfs_root, minor);
+ drm_debugfs_add_files(minor->dev, drm_framebuffer_debugfs_list,
+ ARRAY_SIZE(drm_framebuffer_debugfs_list));
}
#endif
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index b8db675e7fb5..7a3cb08dc942 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -170,6 +170,20 @@ void drm_gem_private_object_init(struct drm_device *dev,
EXPORT_SYMBOL(drm_gem_private_object_init);
/**
+ * drm_gem_private_object_fini - Finalize a failed drm_gem_object
+ * @obj: drm_gem_object
+ *
+ * Uninitialize an already allocated GEM object when it initialized failed
+ */
+void drm_gem_private_object_fini(struct drm_gem_object *obj)
+{
+ WARN_ON(obj->dma_buf);
+
+ dma_resv_fini(&obj->_resv);
+}
+EXPORT_SYMBOL(drm_gem_private_object_fini);
+
+/**
* drm_gem_object_handle_free - release resources bound to userspace handles
* @obj: GEM object to clean up.
*
@@ -930,12 +944,11 @@ drm_gem_release(struct drm_device *dev, struct drm_file *file_private)
void
drm_gem_object_release(struct drm_gem_object *obj)
{
- WARN_ON(obj->dma_buf);
-
if (obj->filp)
fput(obj->filp);
- dma_resv_fini(&obj->_resv);
+ drm_gem_private_object_fini(obj);
+
drm_gem_free_mmap_offset(obj);
drm_gem_lru_remove(obj);
}
@@ -1047,7 +1060,7 @@ int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size,
goto err_drm_gem_object_put;
}
- vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP;
+ vm_flags_set(vma, VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP);
vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
}
diff --git a/drivers/gpu/drm/drm_gem_atomic_helper.c b/drivers/gpu/drm/drm_gem_atomic_helper.c
index e42800718f51..5d4b9cd077f7 100644
--- a/drivers/gpu/drm/drm_gem_atomic_helper.c
+++ b/drivers/gpu/drm/drm_gem_atomic_helper.c
@@ -26,11 +26,8 @@
* call drm_gem_plane_helper_prepare_fb() from their implementation of
* struct &drm_plane_helper.prepare_fb . It sets the plane's fence from
* the framebuffer so that the DRM core can synchronize access automatically.
- *
* drm_gem_plane_helper_prepare_fb() can also be used directly as
- * implementation of prepare_fb. For drivers based on
- * struct drm_simple_display_pipe, drm_gem_simple_display_pipe_prepare_fb()
- * provides equivalent functionality.
+ * implementation of prepare_fb.
*
* .. code-block:: c
*
@@ -41,11 +38,6 @@
* . prepare_fb = drm_gem_plane_helper_prepare_fb,
* };
*
- * struct drm_simple_display_pipe_funcs driver_pipe_funcs = {
- * ...,
- * . prepare_fb = drm_gem_simple_display_pipe_prepare_fb,
- * };
- *
* A driver using a shadow buffer copies the content of the shadow buffers
* into the HW's framebuffer memory during an atomic update. This requires
* a mapping of the shadow buffer into kernel address space. The mappings
@@ -205,27 +197,6 @@ error:
}
EXPORT_SYMBOL_GPL(drm_gem_plane_helper_prepare_fb);
-/**
- * drm_gem_simple_display_pipe_prepare_fb - prepare_fb helper for &drm_simple_display_pipe
- * @pipe: Simple display pipe
- * @plane_state: Plane state
- *
- * This function uses drm_gem_plane_helper_prepare_fb() to extract the fences
- * from &drm_gem_object.resv and attaches them to the plane state for the atomic
- * helper to wait on. This is necessary to correctly implement implicit
- * synchronization for any buffers shared as a struct &dma_buf. Drivers can use
- * this as their &drm_simple_display_pipe_funcs.prepare_fb callback.
- *
- * See drm_gem_plane_helper_prepare_fb() for a discussion of implicit and
- * explicit fencing in atomic modeset updates.
- */
-int drm_gem_simple_display_pipe_prepare_fb(struct drm_simple_display_pipe *pipe,
- struct drm_plane_state *plane_state)
-{
- return drm_gem_plane_helper_prepare_fb(&pipe->plane, plane_state);
-}
-EXPORT_SYMBOL(drm_gem_simple_display_pipe_prepare_fb);
-
/*
* Shadow-buffered Planes
*/
diff --git a/drivers/gpu/drm/drm_gem_dma_helper.c b/drivers/gpu/drm/drm_gem_dma_helper.c
index 1e658c448366..870b90b78bc4 100644
--- a/drivers/gpu/drm/drm_gem_dma_helper.c
+++ b/drivers/gpu/drm/drm_gem_dma_helper.c
@@ -477,8 +477,8 @@ drm_gem_dma_prime_import_sg_table(struct drm_device *dev,
dma_obj->dma_addr = sg_dma_address(sgt->sgl);
dma_obj->sgt = sgt;
- DRM_DEBUG_PRIME("dma_addr = %pad, size = %zu\n", &dma_obj->dma_addr,
- attach->dmabuf->size);
+ drm_dbg_prime(dev, "dma_addr = %pad, size = %zu\n", &dma_obj->dma_addr,
+ attach->dmabuf->size);
return &dma_obj->base;
}
@@ -530,8 +530,7 @@ int drm_gem_dma_mmap(struct drm_gem_dma_object *dma_obj, struct vm_area_struct *
* the whole buffer.
*/
vma->vm_pgoff -= drm_vma_node_start(&obj->vma_node);
- vma->vm_flags &= ~VM_PFNMAP;
- vma->vm_flags |= VM_DONTEXPAND;
+ vm_flags_mod(vma, VM_DONTEXPAND, VM_PFNMAP);
if (dma_obj->map_noncoherent) {
vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
index b602cd72a120..75185a960fc4 100644
--- a/drivers/gpu/drm/drm_gem_shmem_helper.c
+++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
@@ -79,8 +79,10 @@ __drm_gem_shmem_create(struct drm_device *dev, size_t size, bool private)
} else {
ret = drm_gem_object_init(dev, obj, size);
}
- if (ret)
+ if (ret) {
+ drm_gem_private_object_fini(obj);
goto err_free;
+ }
ret = drm_gem_create_mmap_offset(obj);
if (ret)
@@ -413,7 +415,7 @@ void drm_gem_shmem_vunmap(struct drm_gem_shmem_object *shmem,
}
EXPORT_SYMBOL(drm_gem_shmem_vunmap);
-static struct drm_gem_shmem_object *
+static int
drm_gem_shmem_create_with_handle(struct drm_file *file_priv,
struct drm_device *dev, size_t size,
uint32_t *handle)
@@ -423,7 +425,7 @@ drm_gem_shmem_create_with_handle(struct drm_file *file_priv,
shmem = drm_gem_shmem_create(dev, size);
if (IS_ERR(shmem))
- return shmem;
+ return PTR_ERR(shmem);
/*
* Allocate an id of idr table where the obj is registered
@@ -432,10 +434,8 @@ drm_gem_shmem_create_with_handle(struct drm_file *file_priv,
ret = drm_gem_handle_create(file_priv, &shmem->base, handle);
/* drop reference from allocate - handle holds it now. */
drm_gem_object_put(&shmem->base);
- if (ret)
- return ERR_PTR(ret);
- return shmem;
+ return ret;
}
/* Update madvise status, returns true if not purged, else
@@ -518,7 +518,6 @@ int drm_gem_shmem_dumb_create(struct drm_file *file, struct drm_device *dev,
struct drm_mode_create_dumb *args)
{
u32 min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
- struct drm_gem_shmem_object *shmem;
if (!args->pitch || !args->size) {
args->pitch = min_pitch;
@@ -531,9 +530,7 @@ int drm_gem_shmem_dumb_create(struct drm_file *file, struct drm_device *dev,
args->size = PAGE_ALIGN(args->pitch * args->height);
}
- shmem = drm_gem_shmem_create_with_handle(file, dev, args->size, &args->handle);
-
- return PTR_ERR_OR_ZERO(shmem);
+ return drm_gem_shmem_create_with_handle(file, dev, args->size, &args->handle);
}
EXPORT_SYMBOL_GPL(drm_gem_shmem_dumb_create);
@@ -633,7 +630,7 @@ int drm_gem_shmem_mmap(struct drm_gem_shmem_object *shmem, struct vm_area_struct
if (ret)
return ret;
- vma->vm_flags |= VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP;
+ vm_flags_set(vma, VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP);
vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
if (shmem->map_wc)
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
@@ -681,23 +678,7 @@ struct sg_table *drm_gem_shmem_get_sg_table(struct drm_gem_shmem_object *shmem)
}
EXPORT_SYMBOL_GPL(drm_gem_shmem_get_sg_table);
-/**
- * drm_gem_shmem_get_pages_sgt - Pin pages, dma map them, and return a
- * scatter/gather table for a shmem GEM object.
- * @shmem: shmem GEM object
- *
- * This function returns a scatter/gather table suitable for driver usage. If
- * the sg table doesn't exist, the pages are pinned, dma-mapped, and a sg
- * table created.
- *
- * This is the main function for drivers to get at backing storage, and it hides
- * and difference between dma-buf imported and natively allocated objects.
- * drm_gem_shmem_get_sg_table() should not be directly called by drivers.
- *
- * Returns:
- * A pointer to the scatter/gather table of pinned pages or errno on failure.
- */
-struct sg_table *drm_gem_shmem_get_pages_sgt(struct drm_gem_shmem_object *shmem)
+static struct sg_table *drm_gem_shmem_get_pages_sgt_locked(struct drm_gem_shmem_object *shmem)
{
struct drm_gem_object *obj = &shmem->base;
int ret;
@@ -708,7 +689,7 @@ struct sg_table *drm_gem_shmem_get_pages_sgt(struct drm_gem_shmem_object *shmem)
WARN_ON(obj->import_attach);
- ret = drm_gem_shmem_get_pages(shmem);
+ ret = drm_gem_shmem_get_pages_locked(shmem);
if (ret)
return ERR_PTR(ret);
@@ -730,9 +711,39 @@ err_free_sgt:
sg_free_table(sgt);
kfree(sgt);
err_put_pages:
- drm_gem_shmem_put_pages(shmem);
+ drm_gem_shmem_put_pages_locked(shmem);
return ERR_PTR(ret);
}
+
+/**
+ * drm_gem_shmem_get_pages_sgt - Pin pages, dma map them, and return a
+ * scatter/gather table for a shmem GEM object.
+ * @shmem: shmem GEM object
+ *
+ * This function returns a scatter/gather table suitable for driver usage. If
+ * the sg table doesn't exist, the pages are pinned, dma-mapped, and a sg
+ * table created.
+ *
+ * This is the main function for drivers to get at backing storage, and it hides
+ * and difference between dma-buf imported and natively allocated objects.
+ * drm_gem_shmem_get_sg_table() should not be directly called by drivers.
+ *
+ * Returns:
+ * A pointer to the scatter/gather table of pinned pages or errno on failure.
+ */
+struct sg_table *drm_gem_shmem_get_pages_sgt(struct drm_gem_shmem_object *shmem)
+{
+ int ret;
+ struct sg_table *sgt;
+
+ ret = mutex_lock_interruptible(&shmem->pages_lock);
+ if (ret)
+ return ERR_PTR(ret);
+ sgt = drm_gem_shmem_get_pages_sgt_locked(shmem);
+ mutex_unlock(&shmem->pages_lock);
+
+ return sgt;
+}
EXPORT_SYMBOL_GPL(drm_gem_shmem_get_pages_sgt);
/**
@@ -764,7 +775,7 @@ drm_gem_shmem_prime_import_sg_table(struct drm_device *dev,
shmem->sgt = sgt;
- DRM_DEBUG_PRIME("size = %zu\n", size);
+ drm_dbg_prime(dev, "size = %zu\n", size);
return &shmem->base;
}
diff --git a/drivers/gpu/drm/drm_gem_ttm_helper.c b/drivers/gpu/drm/drm_gem_ttm_helper.c
index d5962a34c01d..3734aa2d1c5b 100644
--- a/drivers/gpu/drm/drm_gem_ttm_helper.c
+++ b/drivers/gpu/drm/drm_gem_ttm_helper.c
@@ -3,6 +3,8 @@
#include <linux/module.h>
#include <drm/drm_gem_ttm_helper.h>
+#include <drm/ttm/ttm_placement.h>
+#include <drm/ttm/ttm_tt.h>
/**
* DOC: overview
diff --git a/drivers/gpu/drm/drm_gem_vram_helper.c b/drivers/gpu/drm/drm_gem_vram_helper.c
index b6c7e3803bb3..d40b3edb52d0 100644
--- a/drivers/gpu/drm/drm_gem_vram_helper.c
+++ b/drivers/gpu/drm/drm_gem_vram_helper.c
@@ -19,6 +19,7 @@
#include <drm/drm_simple_kms_helper.h>
#include <drm/ttm/ttm_range_manager.h>
+#include <drm/ttm/ttm_tt.h>
static const struct drm_gem_object_funcs drm_gem_vram_object_funcs;
@@ -956,8 +957,8 @@ static struct ttm_device_funcs bo_driver = {
static int drm_vram_mm_debugfs(struct seq_file *m, void *data)
{
- struct drm_info_node *node = (struct drm_info_node *) m->private;
- struct drm_vram_mm *vmm = node->minor->dev->vram_mm;
+ struct drm_debugfs_entry *entry = m->private;
+ struct drm_vram_mm *vmm = entry->dev->vram_mm;
struct ttm_resource_manager *man = ttm_manager_type(&vmm->bdev, TTM_PL_VRAM);
struct drm_printer p = drm_seq_file_printer(m);
@@ -965,7 +966,7 @@ static int drm_vram_mm_debugfs(struct seq_file *m, void *data)
return 0;
}
-static const struct drm_info_list drm_vram_mm_debugfs_list[] = {
+static const struct drm_debugfs_info drm_vram_mm_debugfs_list[] = {
{ "vram-mm", drm_vram_mm_debugfs, 0, NULL },
};
@@ -977,9 +978,8 @@ static const struct drm_info_list drm_vram_mm_debugfs_list[] = {
*/
void drm_vram_mm_debugfs_init(struct drm_minor *minor)
{
- drm_debugfs_create_files(drm_vram_mm_debugfs_list,
- ARRAY_SIZE(drm_vram_mm_debugfs_list),
- minor->debugfs_root, minor);
+ drm_debugfs_add_files(minor->dev, drm_vram_mm_debugfs_list,
+ ARRAY_SIZE(drm_vram_mm_debugfs_list));
}
EXPORT_SYMBOL(drm_vram_mm_debugfs_init);
diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h
index 5ea5e260118c..ed2103ee272c 100644
--- a/drivers/gpu/drm/drm_internal.h
+++ b/drivers/gpu/drm/drm_internal.h
@@ -186,6 +186,7 @@ int drm_gem_dumb_destroy(struct drm_file *file, struct drm_device *dev,
int drm_debugfs_init(struct drm_minor *minor, int minor_id,
struct dentry *root);
void drm_debugfs_cleanup(struct drm_minor *minor);
+void drm_debugfs_late_register(struct drm_device *dev);
void drm_debugfs_connector_add(struct drm_connector *connector);
void drm_debugfs_connector_remove(struct drm_connector *connector);
void drm_debugfs_crtc_add(struct drm_crtc *crtc);
@@ -202,6 +203,10 @@ static inline void drm_debugfs_cleanup(struct drm_minor *minor)
{
}
+static inline void drm_debugfs_late_register(struct drm_device *dev)
+{
+}
+
static inline void drm_debugfs_connector_add(struct drm_connector *connector)
{
}
diff --git a/drivers/gpu/drm/drm_ioc32.c b/drivers/gpu/drm/drm_ioc32.c
index 5d82891c3222..49a743f62b4a 100644
--- a/drivers/gpu/drm/drm_ioc32.c
+++ b/drivers/gpu/drm/drm_ioc32.c
@@ -972,6 +972,7 @@ long drm_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
unsigned int nr = DRM_IOCTL_NR(cmd);
struct drm_file *file_priv = filp->private_data;
+ struct drm_device *dev = file_priv->minor->dev;
drm_ioctl_compat_t *fn;
int ret;
@@ -986,14 +987,14 @@ long drm_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (!fn)
return drm_ioctl(filp, cmd, arg);
- DRM_DEBUG("comm=\"%s\", pid=%d, dev=0x%lx, auth=%d, %s\n",
- current->comm, task_pid_nr(current),
- (long)old_encode_dev(file_priv->minor->kdev->devt),
- file_priv->authenticated,
- drm_compat_ioctls[nr].name);
+ drm_dbg_core(dev, "comm=\"%s\", pid=%d, dev=0x%lx, auth=%d, %s\n",
+ current->comm, task_pid_nr(current),
+ (long)old_encode_dev(file_priv->minor->kdev->devt),
+ file_priv->authenticated,
+ drm_compat_ioctls[nr].name);
ret = (*fn)(filp, cmd, arg);
if (ret)
- DRM_DEBUG("ret = %d\n", ret);
+ drm_dbg_core(dev, "ret = %d\n", ret);
return ret;
}
EXPORT_SYMBOL(drm_compat_ioctl);
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index ca2a6e6101dc..7c9d66ee917d 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -440,7 +440,7 @@ done:
int drm_noop(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
- DRM_DEBUG("\n");
+ drm_dbg_core(dev, "\n");
return 0;
}
EXPORT_SYMBOL(drm_noop);
@@ -856,16 +856,16 @@ long drm_ioctl(struct file *filp,
out_size = 0;
ksize = max(max(in_size, out_size), drv_size);
- DRM_DEBUG("comm=\"%s\" pid=%d, dev=0x%lx, auth=%d, %s\n",
- current->comm, task_pid_nr(current),
- (long)old_encode_dev(file_priv->minor->kdev->devt),
- file_priv->authenticated, ioctl->name);
+ drm_dbg_core(dev, "comm=\"%s\" pid=%d, dev=0x%lx, auth=%d, %s\n",
+ current->comm, task_pid_nr(current),
+ (long)old_encode_dev(file_priv->minor->kdev->devt),
+ file_priv->authenticated, ioctl->name);
/* Do not trust userspace, use our own definition */
func = ioctl->func;
if (unlikely(!func)) {
- DRM_DEBUG("no function\n");
+ drm_dbg_core(dev, "no function\n");
retcode = -EINVAL;
goto err_i1;
}
@@ -894,16 +894,17 @@ long drm_ioctl(struct file *filp,
err_i1:
if (!ioctl)
- DRM_DEBUG("invalid ioctl: comm=\"%s\", pid=%d, dev=0x%lx, auth=%d, cmd=0x%02x, nr=0x%02x\n",
- current->comm, task_pid_nr(current),
- (long)old_encode_dev(file_priv->minor->kdev->devt),
- file_priv->authenticated, cmd, nr);
+ drm_dbg_core(dev,
+ "invalid ioctl: comm=\"%s\", pid=%d, dev=0x%lx, auth=%d, cmd=0x%02x, nr=0x%02x\n",
+ current->comm, task_pid_nr(current),
+ (long)old_encode_dev(file_priv->minor->kdev->devt),
+ file_priv->authenticated, cmd, nr);
if (kdata != stack_kdata)
kfree(kdata);
if (retcode)
- DRM_DEBUG("comm=\"%s\", pid=%d, ret=%d\n", current->comm,
- task_pid_nr(current), retcode);
+ drm_dbg_core(dev, "comm=\"%s\", pid=%d, ret=%d\n",
+ current->comm, task_pid_nr(current), retcode);
return retcode;
}
EXPORT_SYMBOL(drm_ioctl);
diff --git a/drivers/gpu/drm/drm_lease.c b/drivers/gpu/drm/drm_lease.c
index d72c2fac0ff1..150fe1555068 100644
--- a/drivers/gpu/drm/drm_lease.c
+++ b/drivers/gpu/drm/drm_lease.c
@@ -6,7 +6,7 @@
#include <linux/uaccess.h>
#include <drm/drm_auth.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_crtc.h>
#include <drm/drm_drv.h>
#include <drm/drm_file.h>
#include <drm/drm_lease.h>
@@ -213,11 +213,11 @@ static struct drm_master *drm_lease_create(struct drm_master *lessor, struct idr
int id;
void *entry;
- DRM_DEBUG_LEASE("lessor %d\n", lessor->lessee_id);
+ drm_dbg_lease(dev, "lessor %d\n", lessor->lessee_id);
lessee = drm_master_create(lessor->dev);
if (!lessee) {
- DRM_DEBUG_LEASE("drm_master_create failed\n");
+ drm_dbg_lease(dev, "drm_master_create failed\n");
return ERR_PTR(-ENOMEM);
}
@@ -231,7 +231,7 @@ static struct drm_master *drm_lease_create(struct drm_master *lessor, struct idr
error = -EBUSY;
if (error != 0) {
- DRM_DEBUG_LEASE("object %d failed %d\n", object, error);
+ drm_dbg_lease(dev, "object %d failed %d\n", object, error);
goto out_lessee;
}
}
@@ -249,7 +249,8 @@ static struct drm_master *drm_lease_create(struct drm_master *lessor, struct idr
/* Move the leases over */
lessee->leases = *leases;
- DRM_DEBUG_LEASE("new lessee %d %p, lessor %d %p\n", lessee->lessee_id, lessee, lessor->lessee_id, lessor);
+ drm_dbg_lease(dev, "new lessee %d %p, lessor %d %p\n",
+ lessee->lessee_id, lessee, lessor->lessee_id, lessor);
mutex_unlock(&dev->mode_config.idr_mutex);
return lessee;
@@ -268,7 +269,7 @@ void drm_lease_destroy(struct drm_master *master)
mutex_lock(&dev->mode_config.idr_mutex);
- DRM_DEBUG_LEASE("drm_lease_destroy %d\n", master->lessee_id);
+ drm_dbg_lease(dev, "drm_lease_destroy %d\n", master->lessee_id);
/* This master is referenced by all lessees, hence it cannot be destroyed
* until all of them have been
@@ -277,7 +278,8 @@ void drm_lease_destroy(struct drm_master *master)
/* Remove this master from the lessee idr in the owner */
if (master->lessee_id != 0) {
- DRM_DEBUG_LEASE("remove master %d from device list of lessees\n", master->lessee_id);
+ drm_dbg_lease(dev, "remove master %d from device list of lessees\n",
+ master->lessee_id);
idr_remove(&(drm_lease_owner(master)->lessee_idr), master->lessee_id);
}
@@ -292,7 +294,7 @@ void drm_lease_destroy(struct drm_master *master)
drm_master_put(&master->lessor);
}
- DRM_DEBUG_LEASE("drm_lease_destroy done %d\n", master->lessee_id);
+ drm_dbg_lease(dev, "drm_lease_destroy done %d\n", master->lessee_id);
}
static void _drm_lease_revoke(struct drm_master *top)
@@ -308,7 +310,8 @@ static void _drm_lease_revoke(struct drm_master *top)
* the tree is fully connected, we can do this without recursing
*/
for (;;) {
- DRM_DEBUG_LEASE("revoke leases for %p %d\n", master, master->lessee_id);
+ drm_dbg_lease(master->dev, "revoke leases for %p %d\n",
+ master, master->lessee_id);
/* Evacuate the lease */
idr_for_each_entry(&master->leases, entry, object)
@@ -408,7 +411,7 @@ static int fill_object_idr(struct drm_device *dev,
ret = validate_lease(dev, object_count, objects, universal_planes);
if (ret) {
- DRM_DEBUG_LEASE("lease validation failed\n");
+ drm_dbg_lease(dev, "lease validation failed\n");
goto out_free_objects;
}
@@ -418,7 +421,7 @@ static int fill_object_idr(struct drm_device *dev,
struct drm_mode_object *obj = objects[o];
u32 object_id = objects[o]->id;
- DRM_DEBUG_LEASE("Adding object %d to lease\n", object_id);
+ drm_dbg_lease(dev, "Adding object %d to lease\n", object_id);
/*
* We're using an IDR to hold the set of leased
@@ -430,8 +433,8 @@ static int fill_object_idr(struct drm_device *dev,
*/
ret = idr_alloc(leases, &drm_lease_idr_object , object_id, object_id + 1, GFP_KERNEL);
if (ret < 0) {
- DRM_DEBUG_LEASE("Object %d cannot be inserted into leases (%d)\n",
- object_id, ret);
+ drm_dbg_lease(dev, "Object %d cannot be inserted into leases (%d)\n",
+ object_id, ret);
goto out_free_objects;
}
if (obj->type == DRM_MODE_OBJECT_CRTC && !universal_planes) {
@@ -439,15 +442,15 @@ static int fill_object_idr(struct drm_device *dev,
ret = idr_alloc(leases, &drm_lease_idr_object, crtc->primary->base.id, crtc->primary->base.id + 1, GFP_KERNEL);
if (ret < 0) {
- DRM_DEBUG_LEASE("Object primary plane %d cannot be inserted into leases (%d)\n",
- object_id, ret);
+ drm_dbg_lease(dev, "Object primary plane %d cannot be inserted into leases (%d)\n",
+ object_id, ret);
goto out_free_objects;
}
if (crtc->cursor) {
ret = idr_alloc(leases, &drm_lease_idr_object, crtc->cursor->base.id, crtc->cursor->base.id + 1, GFP_KERNEL);
if (ret < 0) {
- DRM_DEBUG_LEASE("Object cursor plane %d cannot be inserted into leases (%d)\n",
- object_id, ret);
+ drm_dbg_lease(dev, "Object cursor plane %d cannot be inserted into leases (%d)\n",
+ object_id, ret);
goto out_free_objects;
}
}
@@ -490,14 +493,14 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev,
return -EOPNOTSUPP;
if (cl->flags && (cl->flags & ~(O_CLOEXEC | O_NONBLOCK))) {
- DRM_DEBUG_LEASE("invalid flags\n");
+ drm_dbg_lease(dev, "invalid flags\n");
return -EINVAL;
}
lessor = drm_file_get_master(lessor_priv);
/* Do not allow sub-leases */
if (lessor->lessor) {
- DRM_DEBUG_LEASE("recursive leasing not allowed\n");
+ drm_dbg_lease(dev, "recursive leasing not allowed\n");
ret = -EINVAL;
goto out_lessor;
}
@@ -520,7 +523,7 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev,
object_count, object_ids);
kfree(object_ids);
if (ret) {
- DRM_DEBUG_LEASE("lease object lookup failed: %i\n", ret);
+ drm_dbg_lease(dev, "lease object lookup failed: %i\n", ret);
idr_destroy(&leases);
goto out_lessor;
}
@@ -534,7 +537,7 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev,
goto out_lessor;
}
- DRM_DEBUG_LEASE("Creating lease\n");
+ drm_dbg_lease(dev, "Creating lease\n");
/* lessee will take the ownership of leases */
lessee = drm_lease_create(lessor, &leases);
@@ -545,7 +548,7 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev,
}
/* Clone the lessor file to create a new file for us */
- DRM_DEBUG_LEASE("Allocating lease file\n");
+ drm_dbg_lease(dev, "Allocating lease file\n");
lessee_file = file_clone_open(lessor_file);
if (IS_ERR(lessee_file)) {
ret = PTR_ERR(lessee_file);
@@ -560,7 +563,7 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev,
lessee_priv->authenticated = 1;
/* Pass fd back to userspace */
- DRM_DEBUG_LEASE("Returning fd %d id %d\n", fd, lessee->lessee_id);
+ drm_dbg_lease(dev, "Returning fd %d id %d\n", fd, lessee->lessee_id);
cl->fd = fd;
cl->lessee_id = lessee->lessee_id;
@@ -568,7 +571,7 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev,
fd_install(fd, lessee_file);
drm_master_put(&lessor);
- DRM_DEBUG_LEASE("drm_mode_create_lease_ioctl succeeded\n");
+ drm_dbg_lease(dev, "drm_mode_create_lease_ioctl succeeded\n");
return 0;
out_lessee:
@@ -579,7 +582,7 @@ out_leases:
out_lessor:
drm_master_put(&lessor);
- DRM_DEBUG_LEASE("drm_mode_create_lease_ioctl failed: %d\n", ret);
+ drm_dbg_lease(dev, "drm_mode_create_lease_ioctl failed: %d\n", ret);
return ret;
}
@@ -601,7 +604,7 @@ int drm_mode_list_lessees_ioctl(struct drm_device *dev,
return -EOPNOTSUPP;
lessor = drm_file_get_master(lessor_priv);
- DRM_DEBUG_LEASE("List lessees for %d\n", lessor->lessee_id);
+ drm_dbg_lease(dev, "List lessees for %d\n", lessor->lessee_id);
mutex_lock(&dev->mode_config.idr_mutex);
@@ -610,7 +613,8 @@ int drm_mode_list_lessees_ioctl(struct drm_device *dev,
/* Only list un-revoked leases */
if (!idr_is_empty(&lessee->leases)) {
if (count_lessees > count) {
- DRM_DEBUG_LEASE("Add lessee %d\n", lessee->lessee_id);
+ drm_dbg_lease(dev, "Add lessee %d\n",
+ lessee->lessee_id);
ret = put_user(lessee->lessee_id, lessee_ids + count);
if (ret)
break;
@@ -619,7 +623,7 @@ int drm_mode_list_lessees_ioctl(struct drm_device *dev,
}
}
- DRM_DEBUG_LEASE("Lessor leases to %d\n", count);
+ drm_dbg_lease(dev, "Lessor leases to %d\n", count);
if (ret == 0)
arg->count_lessees = count;
@@ -651,7 +655,7 @@ int drm_mode_get_lease_ioctl(struct drm_device *dev,
return -EOPNOTSUPP;
lessee = drm_file_get_master(lessee_priv);
- DRM_DEBUG_LEASE("get lease for %d\n", lessee->lessee_id);
+ drm_dbg_lease(dev, "get lease for %d\n", lessee->lessee_id);
mutex_lock(&dev->mode_config.idr_mutex);
@@ -665,7 +669,7 @@ int drm_mode_get_lease_ioctl(struct drm_device *dev,
count = 0;
idr_for_each_entry(object_idr, entry, object) {
if (count_objects > count) {
- DRM_DEBUG_LEASE("adding object %d\n", object);
+ drm_dbg_lease(dev, "adding object %d\n", object);
ret = put_user(object, object_ids + count);
if (ret)
break;
@@ -696,7 +700,7 @@ int drm_mode_revoke_lease_ioctl(struct drm_device *dev,
struct drm_master *lessee;
int ret = 0;
- DRM_DEBUG_LEASE("revoke lease for %d\n", arg->lessee_id);
+ drm_dbg_lease(dev, "revoke lease for %d\n", arg->lessee_id);
/* Can't lease without MODESET */
if (!drm_core_check_feature(dev, DRIVER_MODESET))
diff --git a/drivers/gpu/drm/drm_mipi_dbi.c b/drivers/gpu/drm/drm_mipi_dbi.c
index a6ac56580876..c871d9f096b8 100644
--- a/drivers/gpu/drm/drm_mipi_dbi.c
+++ b/drivers/gpu/drm/drm_mipi_dbi.c
@@ -21,6 +21,7 @@
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem.h>
+#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_mipi_dbi.h>
#include <drm/drm_modes.h>
@@ -192,6 +193,7 @@ EXPORT_SYMBOL(mipi_dbi_command_stackbuf);
/**
* mipi_dbi_buf_copy - Copy a framebuffer, transforming it if necessary
* @dst: The destination buffer
+ * @src: The source buffer
* @fb: The source framebuffer
* @clip: Clipping rectangle of the area to be copied
* @swap: When true, swap MSB/LSB of 16-bit values
@@ -199,12 +201,10 @@ EXPORT_SYMBOL(mipi_dbi_command_stackbuf);
* Returns:
* Zero on success, negative error code on failure.
*/
-int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer *fb,
+int mipi_dbi_buf_copy(void *dst, struct iosys_map *src, struct drm_framebuffer *fb,
struct drm_rect *clip, bool swap)
{
struct drm_gem_object *gem = drm_gem_fb_get_obj(fb, 0);
- struct iosys_map map[DRM_FORMAT_MAX_PLANES];
- struct iosys_map data[DRM_FORMAT_MAX_PLANES];
struct iosys_map dst_map = IOSYS_MAP_INIT_VADDR(dst);
int ret;
@@ -212,19 +212,15 @@ int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer *fb,
if (ret)
return ret;
- ret = drm_gem_fb_vmap(fb, map, data);
- if (ret)
- goto out_drm_gem_fb_end_cpu_access;
-
switch (fb->format->format) {
case DRM_FORMAT_RGB565:
if (swap)
- drm_fb_swab(&dst_map, NULL, data, fb, clip, !gem->import_attach);
+ drm_fb_swab(&dst_map, NULL, src, fb, clip, !gem->import_attach);
else
- drm_fb_memcpy(&dst_map, NULL, data, fb, clip);
+ drm_fb_memcpy(&dst_map, NULL, src, fb, clip);
break;
case DRM_FORMAT_XRGB8888:
- drm_fb_xrgb8888_to_rgb565(&dst_map, NULL, data, fb, clip, swap);
+ drm_fb_xrgb8888_to_rgb565(&dst_map, NULL, src, fb, clip, swap);
break;
default:
drm_err_once(fb->dev, "Format is not supported: %p4cc\n",
@@ -232,8 +228,6 @@ int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer *fb,
ret = -EINVAL;
}
- drm_gem_fb_vunmap(fb, map);
-out_drm_gem_fb_end_cpu_access:
drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
return ret;
@@ -257,29 +251,18 @@ static void mipi_dbi_set_window_address(struct mipi_dbi_dev *dbidev,
ys & 0xff, (ye >> 8) & 0xff, ye & 0xff);
}
-static void mipi_dbi_fb_dirty(struct drm_framebuffer *fb, struct drm_rect *rect)
+static void mipi_dbi_fb_dirty(struct iosys_map *src, struct drm_framebuffer *fb,
+ struct drm_rect *rect)
{
- struct iosys_map map[DRM_FORMAT_MAX_PLANES];
- struct iosys_map data[DRM_FORMAT_MAX_PLANES];
struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(fb->dev);
unsigned int height = rect->y2 - rect->y1;
unsigned int width = rect->x2 - rect->x1;
struct mipi_dbi *dbi = &dbidev->dbi;
bool swap = dbi->swap_bytes;
- int idx, ret = 0;
+ int ret = 0;
bool full;
void *tr;
- if (WARN_ON(!fb))
- return;
-
- if (!drm_dev_enter(fb->dev, &idx))
- return;
-
- ret = drm_gem_fb_vmap(fb, map, data);
- if (ret)
- goto err_drm_dev_exit;
-
full = width == fb->width && height == fb->height;
DRM_DEBUG_KMS("Flushing [FB:%d] " DRM_RECT_FMT "\n", fb->base.id, DRM_RECT_ARG(rect));
@@ -287,11 +270,11 @@ static void mipi_dbi_fb_dirty(struct drm_framebuffer *fb, struct drm_rect *rect)
if (!dbi->dc || !full || swap ||
fb->format->format == DRM_FORMAT_XRGB8888) {
tr = dbidev->tx_buf;
- ret = mipi_dbi_buf_copy(dbidev->tx_buf, fb, rect, swap);
+ ret = mipi_dbi_buf_copy(tr, src, fb, rect, swap);
if (ret)
goto err_msg;
} else {
- tr = data[0].vaddr; /* TODO: Use mapping abstraction properly */
+ tr = src->vaddr; /* TODO: Use mapping abstraction properly */
}
mipi_dbi_set_window_address(dbidev, rect->x1, rect->x2 - 1, rect->y1,
@@ -302,11 +285,6 @@ static void mipi_dbi_fb_dirty(struct drm_framebuffer *fb, struct drm_rect *rect)
err_msg:
if (ret)
drm_err_once(fb->dev, "Failed to update display %d\n", ret);
-
- drm_gem_fb_vunmap(fb, map);
-
-err_drm_dev_exit:
- drm_dev_exit(idx);
}
/**
@@ -339,13 +317,24 @@ void mipi_dbi_pipe_update(struct drm_simple_display_pipe *pipe,
struct drm_plane_state *old_state)
{
struct drm_plane_state *state = pipe->plane.state;
+ struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(state);
+ struct drm_framebuffer *fb = state->fb;
struct drm_rect rect;
+ int idx;
if (!pipe->crtc.state->active)
return;
+ if (WARN_ON(!fb))
+ return;
+
+ if (!drm_dev_enter(fb->dev, &idx))
+ return;
+
if (drm_atomic_helper_damage_merged(old_state, state, &rect))
- mipi_dbi_fb_dirty(state->fb, &rect);
+ mipi_dbi_fb_dirty(&shadow_plane_state->data[0], fb, &rect);
+
+ drm_dev_exit(idx);
}
EXPORT_SYMBOL(mipi_dbi_pipe_update);
@@ -366,6 +355,7 @@ void mipi_dbi_enable_flush(struct mipi_dbi_dev *dbidev,
struct drm_crtc_state *crtc_state,
struct drm_plane_state *plane_state)
{
+ struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
struct drm_framebuffer *fb = plane_state->fb;
struct drm_rect rect = {
.x1 = 0,
@@ -378,7 +368,7 @@ void mipi_dbi_enable_flush(struct mipi_dbi_dev *dbidev,
if (!drm_dev_enter(&dbidev->drm, &idx))
return;
- mipi_dbi_fb_dirty(fb, &rect);
+ mipi_dbi_fb_dirty(&shadow_plane_state->data[0], fb, &rect);
backlight_enable(dbidev->backlight);
drm_dev_exit(idx);
@@ -427,9 +417,95 @@ void mipi_dbi_pipe_disable(struct drm_simple_display_pipe *pipe)
if (dbidev->regulator)
regulator_disable(dbidev->regulator);
+ if (dbidev->io_regulator)
+ regulator_disable(dbidev->io_regulator);
}
EXPORT_SYMBOL(mipi_dbi_pipe_disable);
+/**
+ * mipi_dbi_pipe_begin_fb_access - MIPI DBI pipe begin-access helper
+ * @pipe: Display pipe
+ * @plane_state: Plane state
+ *
+ * This function implements struct &drm_simple_display_funcs.begin_fb_access.
+ *
+ * See drm_gem_begin_shadow_fb_access() for details and mipi_dbi_pipe_cleanup_fb()
+ * for cleanup.
+ *
+ * Returns:
+ * 0 on success, or a negative errno code otherwise.
+ */
+int mipi_dbi_pipe_begin_fb_access(struct drm_simple_display_pipe *pipe,
+ struct drm_plane_state *plane_state)
+{
+ return drm_gem_begin_shadow_fb_access(&pipe->plane, plane_state);
+}
+EXPORT_SYMBOL(mipi_dbi_pipe_begin_fb_access);
+
+/**
+ * mipi_dbi_pipe_end_fb_access - MIPI DBI pipe end-access helper
+ * @pipe: Display pipe
+ * @plane_state: Plane state
+ *
+ * This function implements struct &drm_simple_display_funcs.end_fb_access.
+ *
+ * See mipi_dbi_pipe_begin_fb_access().
+ */
+void mipi_dbi_pipe_end_fb_access(struct drm_simple_display_pipe *pipe,
+ struct drm_plane_state *plane_state)
+{
+ drm_gem_end_shadow_fb_access(&pipe->plane, plane_state);
+}
+EXPORT_SYMBOL(mipi_dbi_pipe_end_fb_access);
+
+/**
+ * mipi_dbi_pipe_reset_plane - MIPI DBI plane-reset helper
+ * @pipe: Display pipe
+ *
+ * This function implements struct &drm_simple_display_funcs.reset_plane
+ * for MIPI DBI planes.
+ */
+void mipi_dbi_pipe_reset_plane(struct drm_simple_display_pipe *pipe)
+{
+ drm_gem_reset_shadow_plane(&pipe->plane);
+}
+EXPORT_SYMBOL(mipi_dbi_pipe_reset_plane);
+
+/**
+ * mipi_dbi_pipe_duplicate_plane_state - duplicates MIPI DBI plane state
+ * @pipe: Display pipe
+ *
+ * This function implements struct &drm_simple_display_funcs.duplicate_plane_state
+ * for MIPI DBI planes.
+ *
+ * See drm_gem_duplicate_shadow_plane_state() for additional details.
+ *
+ * Returns:
+ * A pointer to a new plane state on success, or NULL otherwise.
+ */
+struct drm_plane_state *mipi_dbi_pipe_duplicate_plane_state(struct drm_simple_display_pipe *pipe)
+{
+ return drm_gem_duplicate_shadow_plane_state(&pipe->plane);
+}
+EXPORT_SYMBOL(mipi_dbi_pipe_duplicate_plane_state);
+
+/**
+ * mipi_dbi_pipe_destroy_plane_state - cleans up MIPI DBI plane state
+ * @pipe: Display pipe
+ * @plane_state: Plane state
+ *
+ * This function implements struct drm_simple_display_funcs.destroy_plane_state
+ * for MIPI DBI planes.
+ *
+ * See drm_gem_destroy_shadow_plane_state() for additional details.
+ */
+void mipi_dbi_pipe_destroy_plane_state(struct drm_simple_display_pipe *pipe,
+ struct drm_plane_state *plane_state)
+{
+ drm_gem_destroy_shadow_plane_state(&pipe->plane, plane_state);
+}
+EXPORT_SYMBOL(mipi_dbi_pipe_destroy_plane_state);
+
static int mipi_dbi_connector_get_modes(struct drm_connector *connector)
{
struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(connector->dev);
@@ -652,6 +728,16 @@ static int mipi_dbi_poweron_reset_conditional(struct mipi_dbi_dev *dbidev, bool
}
}
+ if (dbidev->io_regulator) {
+ ret = regulator_enable(dbidev->io_regulator);
+ if (ret) {
+ DRM_DEV_ERROR(dev, "Failed to enable I/O regulator (%d)\n", ret);
+ if (dbidev->regulator)
+ regulator_disable(dbidev->regulator);
+ return ret;
+ }
+ }
+
if (cond && mipi_dbi_display_is_on(dbi))
return 1;
@@ -661,6 +747,8 @@ static int mipi_dbi_poweron_reset_conditional(struct mipi_dbi_dev *dbidev, bool
DRM_DEV_ERROR(dev, "Failed to send reset command (%d)\n", ret);
if (dbidev->regulator)
regulator_disable(dbidev->regulator);
+ if (dbidev->io_regulator)
+ regulator_disable(dbidev->io_regulator);
return ret;
}
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c
index 497ef4b6a90a..b41aaf2bb9f1 100644
--- a/drivers/gpu/drm/drm_mipi_dsi.c
+++ b/drivers/gpu/drm/drm_mipi_dsi.c
@@ -62,9 +62,9 @@ static int mipi_dsi_device_match(struct device *dev, struct device_driver *drv)
return 0;
}
-static int mipi_dsi_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int mipi_dsi_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev);
+ const struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev);
int err;
err = of_device_uevent_modalias(dev, env);
@@ -1224,6 +1224,58 @@ int mipi_dsi_dcs_get_display_brightness(struct mipi_dsi_device *dsi,
}
EXPORT_SYMBOL(mipi_dsi_dcs_get_display_brightness);
+/**
+ * mipi_dsi_dcs_set_display_brightness_large() - sets the 16-bit brightness value
+ * of the display
+ * @dsi: DSI peripheral device
+ * @brightness: brightness value
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_dcs_set_display_brightness_large(struct mipi_dsi_device *dsi,
+ u16 brightness)
+{
+ u8 payload[2] = { brightness >> 8, brightness & 0xff };
+ ssize_t err;
+
+ err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS,
+ payload, sizeof(payload));
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+EXPORT_SYMBOL(mipi_dsi_dcs_set_display_brightness_large);
+
+/**
+ * mipi_dsi_dcs_get_display_brightness_large() - gets the current 16-bit
+ * brightness value of the display
+ * @dsi: DSI peripheral device
+ * @brightness: brightness value
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_dcs_get_display_brightness_large(struct mipi_dsi_device *dsi,
+ u16 *brightness)
+{
+ u8 brightness_be[2];
+ ssize_t err;
+
+ err = mipi_dsi_dcs_read(dsi, MIPI_DCS_GET_DISPLAY_BRIGHTNESS,
+ brightness_be, sizeof(brightness_be));
+ if (err <= 0) {
+ if (err == 0)
+ err = -ENODATA;
+
+ return err;
+ }
+
+ *brightness = (brightness_be[0] << 8) | brightness_be[1];
+
+ return 0;
+}
+EXPORT_SYMBOL(mipi_dsi_dcs_get_display_brightness_large);
+
static int mipi_dsi_drv_probe(struct device *dev)
{
struct mipi_dsi_driver *drv = to_mipi_dsi_driver(dev->driver);
diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c
index 688c8afe0bf1..87eb591fe9b5 100644
--- a/drivers/gpu/drm/drm_mode_config.c
+++ b/drivers/gpu/drm/drm_mode_config.c
@@ -54,6 +54,8 @@ int drm_modeset_register_all(struct drm_device *dev)
if (ret)
goto err_connector;
+ drm_debugfs_late_register(dev);
+
return 0;
err_connector:
@@ -399,6 +401,8 @@ static void drm_mode_config_init_release(struct drm_device *dev, void *ptr)
*/
int drmm_mode_config_init(struct drm_device *dev)
{
+ int ret;
+
mutex_init(&dev->mode_config.mutex);
drm_modeset_lock_init(&dev->mode_config.connection_mutex);
mutex_init(&dev->mode_config.idr_mutex);
@@ -420,7 +424,11 @@ int drmm_mode_config_init(struct drm_device *dev)
init_llist_head(&dev->mode_config.connector_free_list);
INIT_WORK(&dev->mode_config.connector_free_work, drm_connector_free_work_fn);
- drm_mode_create_standard_properties(dev);
+ ret = drm_mode_create_standard_properties(dev);
+ if (ret) {
+ drm_mode_config_cleanup(dev);
+ return ret;
+ }
/* Just to be sure */
dev->mode_config.num_fb = 0;
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index 3c8034a8c27b..40d482a01178 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -31,10 +31,11 @@
*/
#include <linux/ctype.h>
+#include <linux/export.h>
+#include <linux/fb.h> /* for KHZ2PICOS() */
#include <linux/list.h>
#include <linux/list_sort.h>
-#include <linux/export.h>
-#include <linux/fb.h>
+#include <linux/of.h>
#include <video/of_display_timing.h>
#include <video/of_videomode.h>
@@ -116,6 +117,482 @@ void drm_mode_probed_add(struct drm_connector *connector,
}
EXPORT_SYMBOL(drm_mode_probed_add);
+enum drm_mode_analog {
+ DRM_MODE_ANALOG_NTSC, /* 525 lines, 60Hz */
+ DRM_MODE_ANALOG_PAL, /* 625 lines, 50Hz */
+};
+
+/*
+ * The timings come from:
+ * - https://web.archive.org/web/20220406232708/http://www.kolumbus.fi/pami1/video/pal_ntsc.html
+ * - https://web.archive.org/web/20220406124914/http://martin.hinner.info/vga/pal.html
+ * - https://web.archive.org/web/20220609202433/http://www.batsocks.co.uk/readme/video_timing.htm
+ */
+#define NTSC_LINE_DURATION_NS 63556U
+#define NTSC_LINES_NUMBER 525
+
+#define NTSC_HBLK_DURATION_TYP_NS 10900U
+#define NTSC_HBLK_DURATION_MIN_NS (NTSC_HBLK_DURATION_TYP_NS - 200)
+#define NTSC_HBLK_DURATION_MAX_NS (NTSC_HBLK_DURATION_TYP_NS + 200)
+
+#define NTSC_HACT_DURATION_TYP_NS (NTSC_LINE_DURATION_NS - NTSC_HBLK_DURATION_TYP_NS)
+#define NTSC_HACT_DURATION_MIN_NS (NTSC_LINE_DURATION_NS - NTSC_HBLK_DURATION_MAX_NS)
+#define NTSC_HACT_DURATION_MAX_NS (NTSC_LINE_DURATION_NS - NTSC_HBLK_DURATION_MIN_NS)
+
+#define NTSC_HFP_DURATION_TYP_NS 1500
+#define NTSC_HFP_DURATION_MIN_NS 1270
+#define NTSC_HFP_DURATION_MAX_NS 2220
+
+#define NTSC_HSLEN_DURATION_TYP_NS 4700
+#define NTSC_HSLEN_DURATION_MIN_NS (NTSC_HSLEN_DURATION_TYP_NS - 100)
+#define NTSC_HSLEN_DURATION_MAX_NS (NTSC_HSLEN_DURATION_TYP_NS + 100)
+
+#define NTSC_HBP_DURATION_TYP_NS 4700
+
+/*
+ * I couldn't find the actual tolerance for the back porch, so let's
+ * just reuse the sync length ones.
+ */
+#define NTSC_HBP_DURATION_MIN_NS (NTSC_HBP_DURATION_TYP_NS - 100)
+#define NTSC_HBP_DURATION_MAX_NS (NTSC_HBP_DURATION_TYP_NS + 100)
+
+#define PAL_LINE_DURATION_NS 64000U
+#define PAL_LINES_NUMBER 625
+
+#define PAL_HACT_DURATION_TYP_NS 51950U
+#define PAL_HACT_DURATION_MIN_NS (PAL_HACT_DURATION_TYP_NS - 100)
+#define PAL_HACT_DURATION_MAX_NS (PAL_HACT_DURATION_TYP_NS + 400)
+
+#define PAL_HBLK_DURATION_TYP_NS (PAL_LINE_DURATION_NS - PAL_HACT_DURATION_TYP_NS)
+#define PAL_HBLK_DURATION_MIN_NS (PAL_LINE_DURATION_NS - PAL_HACT_DURATION_MAX_NS)
+#define PAL_HBLK_DURATION_MAX_NS (PAL_LINE_DURATION_NS - PAL_HACT_DURATION_MIN_NS)
+
+#define PAL_HFP_DURATION_TYP_NS 1650
+#define PAL_HFP_DURATION_MIN_NS (PAL_HFP_DURATION_TYP_NS - 100)
+#define PAL_HFP_DURATION_MAX_NS (PAL_HFP_DURATION_TYP_NS + 400)
+
+#define PAL_HSLEN_DURATION_TYP_NS 4700
+#define PAL_HSLEN_DURATION_MIN_NS (PAL_HSLEN_DURATION_TYP_NS - 200)
+#define PAL_HSLEN_DURATION_MAX_NS (PAL_HSLEN_DURATION_TYP_NS + 200)
+
+#define PAL_HBP_DURATION_TYP_NS 5700
+#define PAL_HBP_DURATION_MIN_NS (PAL_HBP_DURATION_TYP_NS - 200)
+#define PAL_HBP_DURATION_MAX_NS (PAL_HBP_DURATION_TYP_NS + 200)
+
+struct analog_param_field {
+ unsigned int even, odd;
+};
+
+#define PARAM_FIELD(_odd, _even) \
+ { .even = _even, .odd = _odd }
+
+struct analog_param_range {
+ unsigned int min, typ, max;
+};
+
+#define PARAM_RANGE(_min, _typ, _max) \
+ { .min = _min, .typ = _typ, .max = _max }
+
+struct analog_parameters {
+ unsigned int num_lines;
+ unsigned int line_duration_ns;
+
+ struct analog_param_range hact_ns;
+ struct analog_param_range hfp_ns;
+ struct analog_param_range hslen_ns;
+ struct analog_param_range hbp_ns;
+ struct analog_param_range hblk_ns;
+
+ unsigned int bt601_hfp;
+
+ struct analog_param_field vfp_lines;
+ struct analog_param_field vslen_lines;
+ struct analog_param_field vbp_lines;
+};
+
+#define TV_MODE_PARAMETER(_mode, _lines, _line_dur, _hact, _hfp, \
+ _hslen, _hbp, _hblk, _bt601_hfp, _vfp, \
+ _vslen, _vbp) \
+ [_mode] = { \
+ .num_lines = _lines, \
+ .line_duration_ns = _line_dur, \
+ .hact_ns = _hact, \
+ .hfp_ns = _hfp, \
+ .hslen_ns = _hslen, \
+ .hbp_ns = _hbp, \
+ .hblk_ns = _hblk, \
+ .bt601_hfp = _bt601_hfp, \
+ .vfp_lines = _vfp, \
+ .vslen_lines = _vslen, \
+ .vbp_lines = _vbp, \
+ }
+
+static const struct analog_parameters tv_modes_parameters[] = {
+ TV_MODE_PARAMETER(DRM_MODE_ANALOG_NTSC,
+ NTSC_LINES_NUMBER,
+ NTSC_LINE_DURATION_NS,
+ PARAM_RANGE(NTSC_HACT_DURATION_MIN_NS,
+ NTSC_HACT_DURATION_TYP_NS,
+ NTSC_HACT_DURATION_MAX_NS),
+ PARAM_RANGE(NTSC_HFP_DURATION_MIN_NS,
+ NTSC_HFP_DURATION_TYP_NS,
+ NTSC_HFP_DURATION_MAX_NS),
+ PARAM_RANGE(NTSC_HSLEN_DURATION_MIN_NS,
+ NTSC_HSLEN_DURATION_TYP_NS,
+ NTSC_HSLEN_DURATION_MAX_NS),
+ PARAM_RANGE(NTSC_HBP_DURATION_MIN_NS,
+ NTSC_HBP_DURATION_TYP_NS,
+ NTSC_HBP_DURATION_MAX_NS),
+ PARAM_RANGE(NTSC_HBLK_DURATION_MIN_NS,
+ NTSC_HBLK_DURATION_TYP_NS,
+ NTSC_HBLK_DURATION_MAX_NS),
+ 16,
+ PARAM_FIELD(3, 3),
+ PARAM_FIELD(3, 3),
+ PARAM_FIELD(16, 17)),
+ TV_MODE_PARAMETER(DRM_MODE_ANALOG_PAL,
+ PAL_LINES_NUMBER,
+ PAL_LINE_DURATION_NS,
+ PARAM_RANGE(PAL_HACT_DURATION_MIN_NS,
+ PAL_HACT_DURATION_TYP_NS,
+ PAL_HACT_DURATION_MAX_NS),
+ PARAM_RANGE(PAL_HFP_DURATION_MIN_NS,
+ PAL_HFP_DURATION_TYP_NS,
+ PAL_HFP_DURATION_MAX_NS),
+ PARAM_RANGE(PAL_HSLEN_DURATION_MIN_NS,
+ PAL_HSLEN_DURATION_TYP_NS,
+ PAL_HSLEN_DURATION_MAX_NS),
+ PARAM_RANGE(PAL_HBP_DURATION_MIN_NS,
+ PAL_HBP_DURATION_TYP_NS,
+ PAL_HBP_DURATION_MAX_NS),
+ PARAM_RANGE(PAL_HBLK_DURATION_MIN_NS,
+ PAL_HBLK_DURATION_TYP_NS,
+ PAL_HBLK_DURATION_MAX_NS),
+ 12,
+
+ /*
+ * The front porch is actually 6 short sync
+ * pulses for the even field, and 5 for the
+ * odd field. Each sync takes half a life so
+ * the odd field front porch is shorter by
+ * half a line.
+ *
+ * In progressive, we're supposed to use 6
+ * pulses, so we're fine there
+ */
+ PARAM_FIELD(3, 2),
+
+ /*
+ * The vsync length is 5 long sync pulses,
+ * each field taking half a line. We're
+ * shorter for both fields by half a line.
+ *
+ * In progressive, we're supposed to use 5
+ * pulses, so we're off by half
+ * a line.
+ *
+ * In interlace, we're now off by half a line
+ * for the even field and one line for the odd
+ * field.
+ */
+ PARAM_FIELD(3, 3),
+
+ /*
+ * The back porch starts with post-equalizing
+ * pulses, consisting in 5 short sync pulses
+ * for the even field, 4 for the odd field. In
+ * progressive, it's 5 short syncs.
+ *
+ * In progressive, we thus have 2.5 lines,
+ * plus the 0.5 line we were missing
+ * previously, so we should use 3 lines.
+ *
+ * In interlace, the even field is in the
+ * exact same case than progressive. For the
+ * odd field, we should be using 2 lines but
+ * we're one line short, so we'll make up for
+ * it here by using 3.
+ *
+ * The entire blanking area is supposed to
+ * take 25 lines, so we also need to account
+ * for the rest of the blanking area that
+ * can't be in either the front porch or sync
+ * period.
+ */
+ PARAM_FIELD(19, 20)),
+};
+
+static int fill_analog_mode(struct drm_device *dev,
+ struct drm_display_mode *mode,
+ const struct analog_parameters *params,
+ unsigned long pixel_clock_hz,
+ unsigned int hactive,
+ unsigned int vactive,
+ bool interlace)
+{
+ unsigned long pixel_duration_ns = NSEC_PER_SEC / pixel_clock_hz;
+ unsigned int htotal, vtotal;
+ unsigned int max_hact, hact_duration_ns;
+ unsigned int hblk, hblk_duration_ns;
+ unsigned int hfp, hfp_duration_ns;
+ unsigned int hslen, hslen_duration_ns;
+ unsigned int hbp, hbp_duration_ns;
+ unsigned int porches, porches_duration_ns;
+ unsigned int vfp, vfp_min;
+ unsigned int vbp, vbp_min;
+ unsigned int vslen;
+ bool bt601 = false;
+ int porches_rem;
+ u64 result;
+
+ drm_dbg_kms(dev,
+ "Generating a %ux%u%c, %u-line mode with a %lu kHz clock\n",
+ hactive, vactive,
+ interlace ? 'i' : 'p',
+ params->num_lines,
+ pixel_clock_hz / 1000);
+
+ max_hact = params->hact_ns.max / pixel_duration_ns;
+ if (pixel_clock_hz == 13500000 && hactive > max_hact && hactive <= 720) {
+ drm_dbg_kms(dev, "Trying to generate a BT.601 mode. Disabling checks.\n");
+ bt601 = true;
+ }
+
+ /*
+ * Our pixel duration is going to be round down by the division,
+ * so rounding up is probably going to introduce even more
+ * deviation.
+ */
+ result = (u64)params->line_duration_ns * pixel_clock_hz;
+ do_div(result, NSEC_PER_SEC);
+ htotal = result;
+
+ drm_dbg_kms(dev, "Total Horizontal Number of Pixels: %u\n", htotal);
+
+ hact_duration_ns = hactive * pixel_duration_ns;
+ if (!bt601 &&
+ (hact_duration_ns < params->hact_ns.min ||
+ hact_duration_ns > params->hact_ns.max)) {
+ DRM_ERROR("Invalid horizontal active area duration: %uns (min: %u, max %u)\n",
+ hact_duration_ns, params->hact_ns.min, params->hact_ns.max);
+ return -EINVAL;
+ }
+
+ hblk = htotal - hactive;
+ drm_dbg_kms(dev, "Horizontal Blanking Period: %u\n", hblk);
+
+ hblk_duration_ns = hblk * pixel_duration_ns;
+ if (!bt601 &&
+ (hblk_duration_ns < params->hblk_ns.min ||
+ hblk_duration_ns > params->hblk_ns.max)) {
+ DRM_ERROR("Invalid horizontal blanking duration: %uns (min: %u, max %u)\n",
+ hblk_duration_ns, params->hblk_ns.min, params->hblk_ns.max);
+ return -EINVAL;
+ }
+
+ hslen = DIV_ROUND_UP(params->hslen_ns.typ, pixel_duration_ns);
+ drm_dbg_kms(dev, "Horizontal Sync Period: %u\n", hslen);
+
+ hslen_duration_ns = hslen * pixel_duration_ns;
+ if (!bt601 &&
+ (hslen_duration_ns < params->hslen_ns.min ||
+ hslen_duration_ns > params->hslen_ns.max)) {
+ DRM_ERROR("Invalid horizontal sync duration: %uns (min: %u, max %u)\n",
+ hslen_duration_ns, params->hslen_ns.min, params->hslen_ns.max);
+ return -EINVAL;
+ }
+
+ porches = hblk - hslen;
+ drm_dbg_kms(dev, "Remaining horizontal pixels for both porches: %u\n", porches);
+
+ porches_duration_ns = porches * pixel_duration_ns;
+ if (!bt601 &&
+ (porches_duration_ns > (params->hfp_ns.max + params->hbp_ns.max) ||
+ porches_duration_ns < (params->hfp_ns.min + params->hbp_ns.min))) {
+ DRM_ERROR("Invalid horizontal porches duration: %uns\n", porches_duration_ns);
+ return -EINVAL;
+ }
+
+ if (bt601) {
+ hfp = params->bt601_hfp;
+ } else {
+ unsigned int hfp_min = DIV_ROUND_UP(params->hfp_ns.min,
+ pixel_duration_ns);
+ unsigned int hbp_min = DIV_ROUND_UP(params->hbp_ns.min,
+ pixel_duration_ns);
+ int porches_rem = porches - hfp_min - hbp_min;
+
+ hfp = hfp_min + DIV_ROUND_UP(porches_rem, 2);
+ }
+
+ drm_dbg_kms(dev, "Horizontal Front Porch: %u\n", hfp);
+
+ hfp_duration_ns = hfp * pixel_duration_ns;
+ if (!bt601 &&
+ (hfp_duration_ns < params->hfp_ns.min ||
+ hfp_duration_ns > params->hfp_ns.max)) {
+ DRM_ERROR("Invalid horizontal front porch duration: %uns (min: %u, max %u)\n",
+ hfp_duration_ns, params->hfp_ns.min, params->hfp_ns.max);
+ return -EINVAL;
+ }
+
+ hbp = porches - hfp;
+ drm_dbg_kms(dev, "Horizontal Back Porch: %u\n", hbp);
+
+ hbp_duration_ns = hbp * pixel_duration_ns;
+ if (!bt601 &&
+ (hbp_duration_ns < params->hbp_ns.min ||
+ hbp_duration_ns > params->hbp_ns.max)) {
+ DRM_ERROR("Invalid horizontal back porch duration: %uns (min: %u, max %u)\n",
+ hbp_duration_ns, params->hbp_ns.min, params->hbp_ns.max);
+ return -EINVAL;
+ }
+
+ if (htotal != (hactive + hfp + hslen + hbp))
+ return -EINVAL;
+
+ mode->clock = pixel_clock_hz / 1000;
+ mode->hdisplay = hactive;
+ mode->hsync_start = mode->hdisplay + hfp;
+ mode->hsync_end = mode->hsync_start + hslen;
+ mode->htotal = mode->hsync_end + hbp;
+
+ if (interlace) {
+ vfp_min = params->vfp_lines.even + params->vfp_lines.odd;
+ vbp_min = params->vbp_lines.even + params->vbp_lines.odd;
+ vslen = params->vslen_lines.even + params->vslen_lines.odd;
+ } else {
+ /*
+ * By convention, NTSC (aka 525/60) systems start with
+ * the even field, but PAL (aka 625/50) systems start
+ * with the odd one.
+ *
+ * PAL systems also have asymmetric timings between the
+ * even and odd field, while NTSC is symmetric.
+ *
+ * Moreover, if we want to create a progressive mode for
+ * PAL, we need to use the odd field timings.
+ *
+ * Since odd == even for NTSC, we can just use the odd
+ * one all the time to simplify the code a bit.
+ */
+ vfp_min = params->vfp_lines.odd;
+ vbp_min = params->vbp_lines.odd;
+ vslen = params->vslen_lines.odd;
+ }
+
+ drm_dbg_kms(dev, "Vertical Sync Period: %u\n", vslen);
+
+ porches = params->num_lines - vactive - vslen;
+ drm_dbg_kms(dev, "Remaining vertical pixels for both porches: %u\n", porches);
+
+ porches_rem = porches - vfp_min - vbp_min;
+ vfp = vfp_min + (porches_rem / 2);
+ drm_dbg_kms(dev, "Vertical Front Porch: %u\n", vfp);
+
+ vbp = porches - vfp;
+ drm_dbg_kms(dev, "Vertical Back Porch: %u\n", vbp);
+
+ vtotal = vactive + vfp + vslen + vbp;
+ if (params->num_lines != vtotal) {
+ DRM_ERROR("Invalid vertical total: %upx (expected %upx)\n",
+ vtotal, params->num_lines);
+ return -EINVAL;
+ }
+
+ mode->vdisplay = vactive;
+ mode->vsync_start = mode->vdisplay + vfp;
+ mode->vsync_end = mode->vsync_start + vslen;
+ mode->vtotal = mode->vsync_end + vbp;
+
+ if (mode->vtotal != params->num_lines)
+ return -EINVAL;
+
+ mode->type = DRM_MODE_TYPE_DRIVER;
+ mode->flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC;
+ if (interlace)
+ mode->flags |= DRM_MODE_FLAG_INTERLACE;
+
+ drm_mode_set_name(mode);
+
+ drm_dbg_kms(dev, "Generated mode " DRM_MODE_FMT "\n", DRM_MODE_ARG(mode));
+
+ return 0;
+}
+
+/**
+ * drm_analog_tv_mode - create a display mode for an analog TV
+ * @dev: drm device
+ * @tv_mode: TV Mode standard to create a mode for. See DRM_MODE_TV_MODE_*.
+ * @pixel_clock_hz: Pixel Clock Frequency, in Hertz
+ * @hdisplay: hdisplay size
+ * @vdisplay: vdisplay size
+ * @interlace: whether to compute an interlaced mode
+ *
+ * This function creates a struct drm_display_mode instance suited for
+ * an analog TV output, for one of the usual analog TV mode.
+ *
+ * Note that @hdisplay is larger than the usual constraints for the PAL
+ * and NTSC timings, and we'll choose to ignore most timings constraints
+ * to reach those resolutions.
+ *
+ * Returns:
+ *
+ * A pointer to the mode, allocated with drm_mode_create(). Returns NULL
+ * on error.
+ */
+struct drm_display_mode *drm_analog_tv_mode(struct drm_device *dev,
+ enum drm_connector_tv_mode tv_mode,
+ unsigned long pixel_clock_hz,
+ unsigned int hdisplay,
+ unsigned int vdisplay,
+ bool interlace)
+{
+ struct drm_display_mode *mode;
+ enum drm_mode_analog analog;
+ int ret;
+
+ switch (tv_mode) {
+ case DRM_MODE_TV_MODE_NTSC:
+ fallthrough;
+ case DRM_MODE_TV_MODE_NTSC_443:
+ fallthrough;
+ case DRM_MODE_TV_MODE_NTSC_J:
+ fallthrough;
+ case DRM_MODE_TV_MODE_PAL_M:
+ analog = DRM_MODE_ANALOG_NTSC;
+ break;
+
+ case DRM_MODE_TV_MODE_PAL:
+ fallthrough;
+ case DRM_MODE_TV_MODE_PAL_N:
+ fallthrough;
+ case DRM_MODE_TV_MODE_SECAM:
+ analog = DRM_MODE_ANALOG_PAL;
+ break;
+
+ default:
+ return NULL;
+ }
+
+ mode = drm_mode_create(dev);
+ if (!mode)
+ return NULL;
+
+ ret = fill_analog_mode(dev, mode,
+ &tv_modes_parameters[analog],
+ pixel_clock_hz, hdisplay, vdisplay, interlace);
+ if (ret)
+ goto err_free_mode;
+
+ return mode;
+
+err_free_mode:
+ drm_mode_destroy(dev, mode);
+ return NULL;
+}
+EXPORT_SYMBOL(drm_analog_tv_mode);
+
/**
* drm_cvt_mode -create a modeline based on the CVT algorithm
* @dev: drm device
@@ -1659,6 +2136,30 @@ static int drm_mode_parse_panel_orientation(const char *delim,
return 0;
}
+static int drm_mode_parse_tv_mode(const char *delim,
+ struct drm_cmdline_mode *mode)
+{
+ const char *value;
+ int ret;
+
+ if (*delim != '=')
+ return -EINVAL;
+
+ value = delim + 1;
+ delim = strchr(value, ',');
+ if (!delim)
+ delim = value + strlen(value);
+
+ ret = drm_get_tv_mode_from_name(value, delim - value);
+ if (ret < 0)
+ return ret;
+
+ mode->tv_mode_specified = true;
+ mode->tv_mode = ret;
+
+ return 0;
+}
+
static int drm_mode_parse_cmdline_options(const char *str,
bool freestanding,
const struct drm_connector *connector,
@@ -1728,6 +2229,9 @@ static int drm_mode_parse_cmdline_options(const char *str,
} else if (!strncmp(option, "panel_orientation", delim - option)) {
if (drm_mode_parse_panel_orientation(delim, mode))
return -EINVAL;
+ } else if (!strncmp(option, "tv_mode", delim - option)) {
+ if (drm_mode_parse_tv_mode(delim, mode))
+ return -EINVAL;
} else {
return -EINVAL;
}
@@ -1756,20 +2260,24 @@ struct drm_named_mode {
unsigned int xres;
unsigned int yres;
unsigned int flags;
+ unsigned int tv_mode;
};
-#define NAMED_MODE(_name, _pclk, _x, _y, _flags) \
+#define NAMED_MODE(_name, _pclk, _x, _y, _flags, _mode) \
{ \
.name = _name, \
.pixel_clock_khz = _pclk, \
.xres = _x, \
.yres = _y, \
.flags = _flags, \
+ .tv_mode = _mode, \
}
static const struct drm_named_mode drm_named_modes[] = {
- NAMED_MODE("NTSC", 13500, 720, 480, DRM_MODE_FLAG_INTERLACE),
- NAMED_MODE("PAL", 13500, 720, 576, DRM_MODE_FLAG_INTERLACE),
+ NAMED_MODE("NTSC", 13500, 720, 480, DRM_MODE_FLAG_INTERLACE, DRM_MODE_TV_MODE_NTSC),
+ NAMED_MODE("NTSC-J", 13500, 720, 480, DRM_MODE_FLAG_INTERLACE, DRM_MODE_TV_MODE_NTSC_J),
+ NAMED_MODE("PAL", 13500, 720, 576, DRM_MODE_FLAG_INTERLACE, DRM_MODE_TV_MODE_PAL),
+ NAMED_MODE("PAL-M", 13500, 720, 480, DRM_MODE_FLAG_INTERLACE, DRM_MODE_TV_MODE_PAL_M),
};
static int drm_mode_parse_cmdline_named_mode(const char *name,
@@ -1809,11 +2317,13 @@ static int drm_mode_parse_cmdline_named_mode(const char *name,
if (ret != name_end)
continue;
- strcpy(cmdline_mode->name, mode->name);
+ strscpy(cmdline_mode->name, mode->name, sizeof(cmdline_mode->name));
cmdline_mode->pixel_clock = mode->pixel_clock_khz;
cmdline_mode->xres = mode->xres;
cmdline_mode->yres = mode->yres;
cmdline_mode->interlace = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
+ cmdline_mode->tv_mode = mode->tv_mode;
+ cmdline_mode->tv_mode_specified = true;
cmdline_mode->specified = true;
return 1;
@@ -1992,6 +2502,31 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
}
EXPORT_SYMBOL(drm_mode_parse_command_line_for_connector);
+static struct drm_display_mode *drm_named_mode(struct drm_device *dev,
+ struct drm_cmdline_mode *cmd)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(drm_named_modes); i++) {
+ const struct drm_named_mode *named_mode = &drm_named_modes[i];
+
+ if (strcmp(cmd->name, named_mode->name))
+ continue;
+
+ if (!cmd->tv_mode_specified)
+ continue;
+
+ return drm_analog_tv_mode(dev,
+ named_mode->tv_mode,
+ named_mode->pixel_clock_khz * 1000,
+ named_mode->xres,
+ named_mode->yres,
+ named_mode->flags & DRM_MODE_FLAG_INTERLACE);
+ }
+
+ return NULL;
+}
+
/**
* drm_mode_create_from_cmdline_mode - convert a command line modeline into a DRM display mode
* @dev: DRM device to create the new mode for
@@ -2009,7 +2544,9 @@ drm_mode_create_from_cmdline_mode(struct drm_device *dev,
if (cmd->xres == 0 || cmd->yres == 0)
return NULL;
- if (cmd->cvt)
+ if (strlen(cmd->name))
+ mode = drm_named_mode(dev, cmd);
+ else if (cmd->cvt)
mode = drm_cvt_mode(dev,
cmd->xres, cmd->yres,
cmd->refresh_specified ? cmd->refresh : 60,
diff --git a/drivers/gpu/drm/drm_panel_orientation_quirks.c b/drivers/gpu/drm/drm_panel_orientation_quirks.c
index 3659f0465a72..5522d610c5cf 100644
--- a/drivers/gpu/drm/drm_panel_orientation_quirks.c
+++ b/drivers/gpu/drm/drm_panel_orientation_quirks.c
@@ -30,12 +30,6 @@ struct drm_dmi_panel_orientation_data {
int orientation;
};
-static const struct drm_dmi_panel_orientation_data asus_t100ha = {
- .width = 800,
- .height = 1280,
- .orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP,
-};
-
static const struct drm_dmi_panel_orientation_data gpd_micropc = {
.width = 720,
.height = 1280,
@@ -97,6 +91,12 @@ static const struct drm_dmi_panel_orientation_data lcd720x1280_rightside_up = {
.orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
};
+static const struct drm_dmi_panel_orientation_data lcd800x1280_leftside_up = {
+ .width = 800,
+ .height = 1280,
+ .orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP,
+};
+
static const struct drm_dmi_panel_orientation_data lcd800x1280_rightside_up = {
.width = 800,
.height = 1280,
@@ -127,6 +127,12 @@ static const struct drm_dmi_panel_orientation_data lcd1600x2560_leftside_up = {
.orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP,
};
+static const struct drm_dmi_panel_orientation_data lcd1600x2560_rightside_up = {
+ .width = 1600,
+ .height = 2560,
+ .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
+};
+
static const struct dmi_system_id orientation_data[] = {
{ /* Acer One 10 (S1003) */
.matches = {
@@ -151,7 +157,7 @@ static const struct dmi_system_id orientation_data[] = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100HAN"),
},
- .driver_data = (void *)&asus_t100ha,
+ .driver_data = (void *)&lcd800x1280_leftside_up,
}, { /* Asus T101HA */
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
@@ -196,6 +202,12 @@ static const struct dmi_system_id orientation_data[] = {
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Hi10 pro tablet"),
},
.driver_data = (void *)&lcd1200x1920_rightside_up,
+ }, { /* Dynabook K50 */
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dynabook Inc."),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "dynabook K50/FR"),
+ },
+ .driver_data = (void *)&lcd800x1280_leftside_up,
}, { /* GPD MicroPC (generic strings, also match on bios date) */
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Default string"),
@@ -310,6 +322,12 @@ static const struct dmi_system_id orientation_data[] = {
DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad D330-10IGL"),
},
.driver_data = (void *)&lcd800x1280_rightside_up,
+ }, { /* Lenovo IdeaPad Duet 3 10IGL5 */
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "IdeaPad Duet 3 10IGL5"),
+ },
+ .driver_data = (void *)&lcd1200x1920_rightside_up,
}, { /* Lenovo Yoga Book X90F / X91F / X91L */
.matches = {
/* Non exact match to match all versions */
@@ -331,6 +349,13 @@ static const struct dmi_system_id orientation_data[] = {
DMI_MATCH(DMI_BIOS_VERSION, "BLADE_21"),
},
.driver_data = (void *)&lcd1200x1920_rightside_up,
+ }, { /* Lenovo Yoga Tab 3 X90F */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "Blade3-10A-001"),
+ },
+ .driver_data = (void *)&lcd1600x2560_rightside_up,
}, { /* Nanote UMPC-01 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "RWC CO.,LTD"),
diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c
index 33357629a7f5..24e7998d1731 100644
--- a/drivers/gpu/drm/drm_plane.c
+++ b/drivers/gpu/drm/drm_plane.c
@@ -46,6 +46,11 @@
* properties that specify how the pixels are positioned and blended, like
* rotation or Z-position. All these properties are stored in &drm_plane_state.
*
+ * Unless explicitly specified (via CRTC property or otherwise), the active area
+ * of a CRTC will be black by default. This means portions of the active area
+ * which are not covered by a plane will be black, and alpha blending of any
+ * planes with the CRTC background will blend with black at the lowest zpos.
+ *
* To create a plane, a KMS drivers allocates and zeroes an instances of
* &struct drm_plane (possibly as part of a larger structure) and registers it
* with a call to drm_universal_plane_init().
diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c
index ba6a9136a065..c91e454eba09 100644
--- a/drivers/gpu/drm/drm_plane_helper.c
+++ b/drivers/gpu/drm/drm_plane_helper.c
@@ -28,7 +28,6 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_atomic_uapi.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_device.h>
#include <drm/drm_drv.h>
#include <drm/drm_encoder.h>
diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
index bcd9611dabfd..8127be134c39 100644
--- a/drivers/gpu/drm/drm_probe_helper.c
+++ b/drivers/gpu/drm/drm_probe_helper.c
@@ -222,6 +222,45 @@ drm_connector_mode_valid(struct drm_connector *connector,
return ret;
}
+static void drm_kms_helper_disable_hpd(struct drm_device *dev)
+{
+ struct drm_connector *connector;
+ struct drm_connector_list_iter conn_iter;
+
+ drm_connector_list_iter_begin(dev, &conn_iter);
+ drm_for_each_connector_iter(connector, &conn_iter) {
+ const struct drm_connector_helper_funcs *funcs =
+ connector->helper_private;
+
+ if (funcs && funcs->disable_hpd)
+ funcs->disable_hpd(connector);
+ }
+ drm_connector_list_iter_end(&conn_iter);
+}
+
+static bool drm_kms_helper_enable_hpd(struct drm_device *dev)
+{
+ bool poll = false;
+ struct drm_connector *connector;
+ struct drm_connector_list_iter conn_iter;
+
+ drm_connector_list_iter_begin(dev, &conn_iter);
+ drm_for_each_connector_iter(connector, &conn_iter) {
+ const struct drm_connector_helper_funcs *funcs =
+ connector->helper_private;
+
+ if (funcs && funcs->enable_hpd)
+ funcs->enable_hpd(connector);
+
+ if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT |
+ DRM_CONNECTOR_POLL_DISCONNECT))
+ poll = true;
+ }
+ drm_connector_list_iter_end(&conn_iter);
+
+ return poll;
+}
+
#define DRM_OUTPUT_POLL_PERIOD (10*HZ)
/**
* drm_kms_helper_poll_enable - re-enable output polling.
@@ -241,20 +280,13 @@ drm_connector_mode_valid(struct drm_connector *connector,
void drm_kms_helper_poll_enable(struct drm_device *dev)
{
bool poll = false;
- struct drm_connector *connector;
- struct drm_connector_list_iter conn_iter;
unsigned long delay = DRM_OUTPUT_POLL_PERIOD;
- if (!dev->mode_config.poll_enabled || !drm_kms_helper_poll)
+ if (!dev->mode_config.poll_enabled || !drm_kms_helper_poll ||
+ dev->mode_config.poll_running)
return;
- drm_connector_list_iter_begin(dev, &conn_iter);
- drm_for_each_connector_iter(connector, &conn_iter) {
- if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT |
- DRM_CONNECTOR_POLL_DISCONNECT))
- poll = true;
- }
- drm_connector_list_iter_end(&conn_iter);
+ poll = drm_kms_helper_enable_hpd(dev);
if (dev->mode_config.delayed_event) {
/*
@@ -273,6 +305,8 @@ void drm_kms_helper_poll_enable(struct drm_device *dev)
if (poll)
schedule_delayed_work(&dev->mode_config.output_poll_work, delay);
+
+ dev->mode_config.poll_running = true;
}
EXPORT_SYMBOL(drm_kms_helper_poll_enable);
@@ -561,10 +595,7 @@ retry:
}
/* Re-enable polling in case the global poll config changed. */
- if (drm_kms_helper_poll != dev->mode_config.poll_running)
- drm_kms_helper_poll_enable(dev);
-
- dev->mode_config.poll_running = drm_kms_helper_poll;
+ drm_kms_helper_poll_enable(dev);
if (connector->status == connector_status_disconnected) {
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] disconnected\n",
@@ -704,8 +735,11 @@ static void output_poll_execute(struct work_struct *work)
changed = dev->mode_config.delayed_event;
dev->mode_config.delayed_event = false;
- if (!drm_kms_helper_poll)
+ if (!drm_kms_helper_poll && dev->mode_config.poll_running) {
+ drm_kms_helper_disable_hpd(dev);
+ dev->mode_config.poll_running = false;
goto out;
+ }
if (!mutex_trylock(&dev->mode_config.mutex)) {
repoll = true;
@@ -818,9 +852,12 @@ EXPORT_SYMBOL(drm_kms_helper_is_poll_worker);
*/
void drm_kms_helper_poll_disable(struct drm_device *dev)
{
- if (!dev->mode_config.poll_enabled)
- return;
+ if (dev->mode_config.poll_running)
+ drm_kms_helper_disable_hpd(dev);
+
cancel_delayed_work_sync(&dev->mode_config.output_poll_work);
+
+ dev->mode_config.poll_running = false;
}
EXPORT_SYMBOL(drm_kms_helper_poll_disable);
@@ -861,8 +898,9 @@ void drm_kms_helper_poll_fini(struct drm_device *dev)
if (!dev->mode_config.poll_enabled)
return;
+ drm_kms_helper_poll_disable(dev);
+
dev->mode_config.poll_enabled = false;
- cancel_delayed_work_sync(&dev->mode_config.output_poll_work);
}
EXPORT_SYMBOL(drm_kms_helper_poll_fini);
@@ -1139,10 +1177,94 @@ int drm_connector_helper_get_modes(struct drm_connector *connector)
* EDID. Otherwise, if the EDID is NULL, clear the connector
* information.
*/
- count = drm_edid_connector_update(connector, drm_edid);
+ drm_edid_connector_update(connector, drm_edid);
+
+ count = drm_edid_connector_add_modes(connector);
drm_edid_free(drm_edid);
return count;
}
EXPORT_SYMBOL(drm_connector_helper_get_modes);
+
+/**
+ * drm_connector_helper_tv_get_modes - Fills the modes availables to a TV connector
+ * @connector: The connector
+ *
+ * Fills the available modes for a TV connector based on the supported
+ * TV modes, and the default mode expressed by the kernel command line.
+ *
+ * This can be used as the default TV connector helper .get_modes() hook
+ * if the driver does not need any special processing.
+ *
+ * Returns:
+ * The number of modes added to the connector.
+ */
+int drm_connector_helper_tv_get_modes(struct drm_connector *connector)
+{
+ struct drm_device *dev = connector->dev;
+ struct drm_property *tv_mode_property =
+ dev->mode_config.tv_mode_property;
+ struct drm_cmdline_mode *cmdline = &connector->cmdline_mode;
+ unsigned int ntsc_modes = BIT(DRM_MODE_TV_MODE_NTSC) |
+ BIT(DRM_MODE_TV_MODE_NTSC_443) |
+ BIT(DRM_MODE_TV_MODE_NTSC_J) |
+ BIT(DRM_MODE_TV_MODE_PAL_M);
+ unsigned int pal_modes = BIT(DRM_MODE_TV_MODE_PAL) |
+ BIT(DRM_MODE_TV_MODE_PAL_N) |
+ BIT(DRM_MODE_TV_MODE_SECAM);
+ unsigned int tv_modes[2] = { UINT_MAX, UINT_MAX };
+ unsigned int i, supported_tv_modes = 0;
+
+ if (!tv_mode_property)
+ return 0;
+
+ for (i = 0; i < tv_mode_property->num_values; i++)
+ supported_tv_modes |= BIT(tv_mode_property->values[i]);
+
+ if ((supported_tv_modes & ntsc_modes) &&
+ (supported_tv_modes & pal_modes)) {
+ uint64_t default_mode;
+
+ if (drm_object_property_get_default_value(&connector->base,
+ tv_mode_property,
+ &default_mode))
+ return 0;
+
+ if (cmdline->tv_mode_specified)
+ default_mode = cmdline->tv_mode;
+
+ if (BIT(default_mode) & ntsc_modes) {
+ tv_modes[0] = DRM_MODE_TV_MODE_NTSC;
+ tv_modes[1] = DRM_MODE_TV_MODE_PAL;
+ } else {
+ tv_modes[0] = DRM_MODE_TV_MODE_PAL;
+ tv_modes[1] = DRM_MODE_TV_MODE_NTSC;
+ }
+ } else if (supported_tv_modes & ntsc_modes) {
+ tv_modes[0] = DRM_MODE_TV_MODE_NTSC;
+ } else if (supported_tv_modes & pal_modes) {
+ tv_modes[0] = DRM_MODE_TV_MODE_PAL;
+ } else {
+ return 0;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
+ struct drm_display_mode *mode;
+
+ if (tv_modes[i] == DRM_MODE_TV_MODE_NTSC)
+ mode = drm_mode_analog_ntsc_480i(dev);
+ else if (tv_modes[i] == DRM_MODE_TV_MODE_PAL)
+ mode = drm_mode_analog_pal_576i(dev);
+ else
+ break;
+ if (!mode)
+ return i;
+ if (!i)
+ mode->type |= DRM_MODE_TYPE_PREFERRED;
+ drm_mode_probed_add(connector, mode);
+ }
+
+ return i;
+}
+EXPORT_SYMBOL(drm_connector_helper_tv_get_modes);
diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c
index 3ef420ec4534..270523ae36d4 100644
--- a/drivers/gpu/drm/drm_simple_kms_helper.c
+++ b/drivers/gpu/drm/drm_simple_kms_helper.c
@@ -267,7 +267,7 @@ static int drm_simple_kms_plane_prepare_fb(struct drm_plane *plane,
WARN_ON_ONCE(pipe->funcs && pipe->funcs->cleanup_fb);
- return drm_gem_simple_display_pipe_prepare_fb(pipe, state);
+ return drm_gem_plane_helper_prepare_fb(plane, state);
}
return pipe->funcs->prepare_fb(pipe, state);
diff --git a/drivers/gpu/drm/drm_vm.c b/drivers/gpu/drm/drm_vm.c
index f024dc93939e..87c9fe55dec7 100644
--- a/drivers/gpu/drm/drm_vm.c
+++ b/drivers/gpu/drm/drm_vm.c
@@ -476,7 +476,7 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
if (!capable(CAP_SYS_ADMIN) &&
(dma->flags & _DRM_DMA_USE_PCI_RO)) {
- vma->vm_flags &= ~(VM_WRITE | VM_MAYWRITE);
+ vm_flags_clear(vma, VM_WRITE | VM_MAYWRITE);
#if defined(__i386__) || defined(__x86_64__)
pgprot_val(vma->vm_page_prot) &= ~_PAGE_RW;
#else
@@ -492,7 +492,7 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
vma->vm_ops = &drm_vm_dma_ops;
- vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
+ vm_flags_set(vma, VM_DONTEXPAND | VM_DONTDUMP);
drm_vm_open_locked(dev, vma);
return 0;
@@ -560,7 +560,7 @@ static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
return -EINVAL;
if (!capable(CAP_SYS_ADMIN) && (map->flags & _DRM_READ_ONLY)) {
- vma->vm_flags &= ~(VM_WRITE | VM_MAYWRITE);
+ vm_flags_clear(vma, VM_WRITE | VM_MAYWRITE);
#if defined(__i386__) || defined(__x86_64__)
pgprot_val(vma->vm_page_prot) &= ~_PAGE_RW;
#else
@@ -628,7 +628,7 @@ static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
default:
return -EINVAL; /* This should never happen. */
}
- vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
+ vm_flags_set(vma, VM_DONTEXPAND | VM_DONTDUMP);
drm_vm_open_locked(dev, vma);
return 0;
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
index 1d2b4fb4bcf8..44ca803237a5 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
@@ -22,6 +22,7 @@
#include "etnaviv_gem.h"
#include "etnaviv_mmu.h"
#include "etnaviv_perfmon.h"
+#include "common.xml.h"
/*
* DRM operations:
@@ -56,6 +57,11 @@ static int etnaviv_open(struct drm_device *dev, struct drm_file *file)
if (!ctx)
return -ENOMEM;
+ ret = xa_alloc_cyclic(&priv->active_contexts, &ctx->id, ctx,
+ xa_limit_32b, &priv->next_context_id, GFP_KERNEL);
+ if (ret < 0)
+ goto out_free;
+
ctx->mmu = etnaviv_iommu_context_init(priv->mmu_global,
priv->cmdbuf_suballoc);
if (!ctx->mmu) {
@@ -99,6 +105,8 @@ static void etnaviv_postclose(struct drm_device *dev, struct drm_file *file)
etnaviv_iommu_context_put(ctx->mmu);
+ xa_erase(&priv->active_contexts, ctx->id);
+
kfree(ctx);
}
@@ -468,7 +476,47 @@ static const struct drm_ioctl_desc etnaviv_ioctls[] = {
ETNA_IOCTL(PM_QUERY_SIG, pm_query_sig, DRM_RENDER_ALLOW),
};
-DEFINE_DRM_GEM_FOPS(fops);
+static void etnaviv_fop_show_fdinfo(struct seq_file *m, struct file *f)
+{
+ struct drm_file *file = f->private_data;
+ struct drm_device *dev = file->minor->dev;
+ struct etnaviv_drm_private *priv = dev->dev_private;
+ struct etnaviv_file_private *ctx = file->driver_priv;
+
+ /*
+ * For a description of the text output format used here, see
+ * Documentation/gpu/drm-usage-stats.rst.
+ */
+ seq_printf(m, "drm-driver:\t%s\n", dev->driver->name);
+ seq_printf(m, "drm-client-id:\t%u\n", ctx->id);
+
+ for (int i = 0; i < ETNA_MAX_PIPES; i++) {
+ struct etnaviv_gpu *gpu = priv->gpu[i];
+ char engine[10] = "UNK";
+ int cur = 0;
+
+ if (!gpu)
+ continue;
+
+ if (gpu->identity.features & chipFeatures_PIPE_2D)
+ cur = snprintf(engine, sizeof(engine), "2D");
+ if (gpu->identity.features & chipFeatures_PIPE_3D)
+ cur = snprintf(engine + cur, sizeof(engine) - cur,
+ "%s3D", cur ? "/" : "");
+ if (gpu->identity.nn_core_count > 0)
+ cur = snprintf(engine + cur, sizeof(engine) - cur,
+ "%sNN", cur ? "/" : "");
+
+ seq_printf(m, "drm-engine-%s:\t%llu ns\n", engine,
+ ctx->sched_entity[i].elapsed_ns);
+ }
+}
+
+static const struct file_operations fops = {
+ .owner = THIS_MODULE,
+ DRM_GEM_FOPS,
+ .show_fdinfo = etnaviv_fop_show_fdinfo,
+};
static const struct drm_driver etnaviv_drm_driver = {
.driver_features = DRIVER_GEM | DRIVER_RENDER,
@@ -514,6 +562,8 @@ static int etnaviv_bind(struct device *dev)
dma_set_max_seg_size(dev, SZ_2G);
+ xa_init_flags(&priv->active_contexts, XA_FLAGS_ALLOC);
+
mutex_init(&priv->gem_lock);
INIT_LIST_HEAD(&priv->gem_list);
priv->num_gpus = 0;
@@ -563,6 +613,8 @@ static void etnaviv_unbind(struct device *dev)
etnaviv_cmdbuf_suballoc_destroy(priv->cmdbuf_suballoc);
+ xa_destroy(&priv->active_contexts);
+
drm->dev_private = NULL;
kfree(priv);
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
index 2bb4c25565dc..b3eb1662e90c 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
@@ -12,6 +12,7 @@
#include <linux/sizes.h>
#include <linux/time64.h>
#include <linux/types.h>
+#include <linux/xarray.h>
#include <drm/drm_drv.h>
#include <drm/drm_gem.h>
@@ -28,6 +29,7 @@ struct etnaviv_iommu_global;
#define ETNAVIV_SOFTPIN_START_ADDRESS SZ_4M /* must be >= SUBALLOC_SIZE */
struct etnaviv_file_private {
+ int id;
struct etnaviv_iommu_context *mmu;
struct drm_sched_entity sched_entity[ETNA_MAX_PIPES];
};
@@ -40,6 +42,9 @@ struct etnaviv_drm_private {
struct etnaviv_cmdbuf_suballoc *cmdbuf_suballoc;
struct etnaviv_iommu_global *mmu_global;
+ struct xarray active_contexts;
+ u32 next_context_id;
+
/* list of GEM objects: */
struct mutex gem_lock;
struct list_head gem_list;
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
index c5ae5492e1af..b5f73502e3dd 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
@@ -130,7 +130,7 @@ static int etnaviv_gem_mmap_obj(struct etnaviv_gem_object *etnaviv_obj,
{
pgprot_t vm_page_prot;
- vma->vm_flags |= VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP;
+ vm_flags_set(vma, VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP);
vm_page_prot = vm_get_page_prot(vma->vm_flags);
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
index 1491159d0d20..45403ea38906 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
@@ -393,10 +393,11 @@ static void submit_cleanup(struct kref *kref)
wake_up_all(&submit->gpu->fence_event);
if (submit->out_fence) {
- /* first remove from IDR, so fence can not be found anymore */
- mutex_lock(&submit->gpu->fence_lock);
- idr_remove(&submit->gpu->fence_idr, submit->out_fence_id);
- mutex_unlock(&submit->gpu->fence_lock);
+ /*
+ * Remove from user fence array before dropping the reference,
+ * so fence can not be found in lookup anymore.
+ */
+ xa_erase(&submit->gpu->user_fences, submit->out_fence_id);
dma_fence_put(submit->out_fence);
}
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
index 51320eeebfcf..de8c9894967c 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -773,6 +773,10 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu)
goto fail;
}
+ if (gpu->identity.nn_core_count > 0)
+ dev_warn(gpu->dev, "etnaviv has been instantiated on a NPU, "
+ "for which the UAPI is still experimental\n");
+
/* Exclude VG cores with FE2.0 */
if (gpu->identity.features & chipFeatures_PIPE_VG &&
gpu->identity.features & chipFeatures_FE20) {
@@ -957,6 +961,8 @@ int etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m)
gpu->identity.vertex_cache_size);
seq_printf(m, "\t shader_core_count: %d\n",
gpu->identity.shader_core_count);
+ seq_printf(m, "\t nn_core_count: %d\n",
+ gpu->identity.nn_core_count);
seq_printf(m, "\t pixel_pipes: %d\n",
gpu->identity.pixel_pipes);
seq_printf(m, "\t vertex_output_buffer_size: %d\n",
@@ -1240,7 +1246,7 @@ int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu,
* pretends we didn't find a fence in that case.
*/
rcu_read_lock();
- fence = idr_find(&gpu->fence_idr, id);
+ fence = xa_load(&gpu->user_fences, id);
if (fence)
fence = dma_fence_get_rcu(fence);
rcu_read_unlock();
@@ -1450,6 +1456,15 @@ static void sync_point_worker(struct work_struct *work)
static void dump_mmu_fault(struct etnaviv_gpu *gpu)
{
+ static const char *fault_reasons[] = {
+ "slave not present",
+ "page not present",
+ "write violation",
+ "out of bounds",
+ "read security violation",
+ "write security violation",
+ };
+
u32 status_reg, status;
int i;
@@ -1462,18 +1477,25 @@ static void dump_mmu_fault(struct etnaviv_gpu *gpu)
dev_err_ratelimited(gpu->dev, "MMU fault status 0x%08x\n", status);
for (i = 0; i < 4; i++) {
+ const char *reason = "unknown";
u32 address_reg;
+ u32 mmu_status;
- if (!(status & (VIVS_MMUv2_STATUS_EXCEPTION0__MASK << (i * 4))))
+ mmu_status = (status >> (i * 4)) & VIVS_MMUv2_STATUS_EXCEPTION0__MASK;
+ if (!mmu_status)
continue;
+ if ((mmu_status - 1) < ARRAY_SIZE(fault_reasons))
+ reason = fault_reasons[mmu_status - 1];
+
if (gpu->sec_mode == ETNA_SEC_NONE)
address_reg = VIVS_MMUv2_EXCEPTION_ADDR(i);
else
address_reg = VIVS_MMUv2_SEC_EXCEPTION_ADDR;
- dev_err_ratelimited(gpu->dev, "MMU %d fault addr 0x%08x\n", i,
- gpu_read(gpu, address_reg));
+ dev_err_ratelimited(gpu->dev,
+ "MMU %d fault (%s) addr 0x%08x\n",
+ i, reason, gpu_read(gpu, address_reg));
}
}
@@ -1629,7 +1651,6 @@ static int etnaviv_gpu_hw_suspend(struct etnaviv_gpu *gpu)
return etnaviv_gpu_clk_disable(gpu);
}
-#ifdef CONFIG_PM
static int etnaviv_gpu_hw_resume(struct etnaviv_gpu *gpu)
{
int ret;
@@ -1645,7 +1666,6 @@ static int etnaviv_gpu_hw_resume(struct etnaviv_gpu *gpu)
return 0;
}
-#endif
static int
etnaviv_gpu_cooling_get_max_state(struct thermal_cooling_device *cdev,
@@ -1713,18 +1733,17 @@ static int etnaviv_gpu_bind(struct device *dev, struct device *master,
if (ret)
goto out_workqueue;
-#ifdef CONFIG_PM
- ret = pm_runtime_get_sync(gpu->dev);
-#else
- ret = etnaviv_gpu_clk_enable(gpu);
-#endif
+ if (IS_ENABLED(CONFIG_PM))
+ ret = pm_runtime_get_sync(gpu->dev);
+ else
+ ret = etnaviv_gpu_clk_enable(gpu);
if (ret < 0)
goto out_sched;
gpu->drm = drm;
gpu->fence_context = dma_fence_context_alloc(1);
- idr_init(&gpu->fence_idr);
+ xa_init_flags(&gpu->user_fences, XA_FLAGS_ALLOC);
spin_lock_init(&gpu->fence_spinlock);
INIT_WORK(&gpu->sync_point_work, sync_point_worker);
@@ -1761,12 +1780,12 @@ static void etnaviv_gpu_unbind(struct device *dev, struct device *master,
etnaviv_sched_fini(gpu);
-#ifdef CONFIG_PM
- pm_runtime_get_sync(gpu->dev);
- pm_runtime_put_sync_suspend(gpu->dev);
-#else
- etnaviv_gpu_hw_suspend(gpu);
-#endif
+ if (IS_ENABLED(CONFIG_PM)) {
+ pm_runtime_get_sync(gpu->dev);
+ pm_runtime_put_sync_suspend(gpu->dev);
+ } else {
+ etnaviv_gpu_hw_suspend(gpu);
+ }
if (gpu->mmu_context)
etnaviv_iommu_context_put(gpu->mmu_context);
@@ -1778,7 +1797,7 @@ static void etnaviv_gpu_unbind(struct device *dev, struct device *master,
}
gpu->drm = NULL;
- idr_destroy(&gpu->fence_idr);
+ xa_destroy(&gpu->user_fences);
if (IS_ENABLED(CONFIG_DRM_ETNAVIV_THERMAL))
thermal_cooling_device_unregister(gpu->cooling);
@@ -1810,7 +1829,7 @@ static int etnaviv_gpu_platform_probe(struct platform_device *pdev)
gpu->dev = &pdev->dev;
mutex_init(&gpu->lock);
- mutex_init(&gpu->fence_lock);
+ mutex_init(&gpu->sched_lock);
/* Map registers: */
gpu->mmio = devm_platform_ioremap_resource(pdev, 0);
@@ -1880,7 +1899,6 @@ static int etnaviv_gpu_platform_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
static int etnaviv_gpu_rpm_suspend(struct device *dev)
{
struct etnaviv_gpu *gpu = dev_get_drvdata(dev);
@@ -1923,18 +1941,16 @@ static int etnaviv_gpu_rpm_resume(struct device *dev)
return 0;
}
-#endif
static const struct dev_pm_ops etnaviv_gpu_pm_ops = {
- SET_RUNTIME_PM_OPS(etnaviv_gpu_rpm_suspend, etnaviv_gpu_rpm_resume,
- NULL)
+ RUNTIME_PM_OPS(etnaviv_gpu_rpm_suspend, etnaviv_gpu_rpm_resume, NULL)
};
struct platform_driver etnaviv_gpu_driver = {
.driver = {
.name = "etnaviv-gpu",
.owner = THIS_MODULE,
- .pm = &etnaviv_gpu_pm_ops,
+ .pm = pm_ptr(&etnaviv_gpu_pm_ops),
.of_match_table = etnaviv_gpu_match,
},
.probe = etnaviv_gpu_platform_probe,
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
index f1204b070fb8..98c6f9c320fc 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
@@ -51,6 +51,9 @@ struct etnaviv_chip_identity {
/* Number of shader cores. */
u32 shader_core_count;
+ /* Number of Neural Network cores. */
+ u32 nn_core_count;
+
/* Size of the vertex cache. */
u32 vertex_cache_size;
@@ -100,6 +103,7 @@ struct etnaviv_gpu {
struct etnaviv_chip_identity identity;
enum etnaviv_sec_mode sec_mode;
struct workqueue_struct *wq;
+ struct mutex sched_lock;
struct drm_gpu_scheduler sched;
bool initialized;
bool fe_running;
@@ -117,8 +121,8 @@ struct etnaviv_gpu {
u32 idle_mask;
/* Fencing support */
- struct mutex fence_lock;
- struct idr fence_idr;
+ struct xarray user_fences;
+ u32 next_user_fence;
u32 next_fence;
u32 completed_fence;
wait_queue_head_t fence_event;
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_hwdb.c b/drivers/gpu/drm/etnaviv/etnaviv_hwdb.c
index 57f334e24189..2e63afa6c798 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_hwdb.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_hwdb.c
@@ -16,6 +16,7 @@ static const struct etnaviv_chip_identity etnaviv_chip_identities[] = {
.register_max = 64,
.thread_count = 128,
.shader_core_count = 1,
+ .nn_core_count = 0,
.vertex_cache_size = 8,
.vertex_output_buffer_size = 1024,
.pixel_pipes = 1,
@@ -47,6 +48,7 @@ static const struct etnaviv_chip_identity etnaviv_chip_identities[] = {
.register_max = 64,
.thread_count = 512,
.shader_core_count = 2,
+ .nn_core_count = 0,
.vertex_cache_size = 16,
.vertex_output_buffer_size = 1024,
.pixel_pipes = 1,
@@ -78,6 +80,7 @@ static const struct etnaviv_chip_identity etnaviv_chip_identities[] = {
.register_max = 64,
.thread_count = 512,
.shader_core_count = 2,
+ .nn_core_count = 0,
.vertex_cache_size = 16,
.vertex_output_buffer_size = 1024,
.pixel_pipes = 1,
@@ -140,6 +143,7 @@ static const struct etnaviv_chip_identity etnaviv_chip_identities[] = {
.register_max = 64,
.thread_count = 1024,
.shader_core_count = 4,
+ .nn_core_count = 0,
.vertex_cache_size = 16,
.vertex_output_buffer_size = 1024,
.pixel_pipes = 2,
@@ -161,6 +165,38 @@ static const struct etnaviv_chip_identity etnaviv_chip_identities[] = {
.minor_features10 = 0x90044250,
.minor_features11 = 0x00000024,
},
+ {
+ .model = 0x8000,
+ .revision = 0x7120,
+ .product_id = 0x45080009,
+ .customer_id = 0x88,
+ .eco_id = 0,
+ .stream_count = 8,
+ .register_max = 64,
+ .thread_count = 256,
+ .shader_core_count = 1,
+ .nn_core_count = 8,
+ .vertex_cache_size = 16,
+ .vertex_output_buffer_size = 1024,
+ .pixel_pipes = 1,
+ .instruction_count = 512,
+ .num_constants = 320,
+ .buffer_size = 0,
+ .varyings_count = 16,
+ .features = 0xe0287cac,
+ .minor_features0 = 0xc1799eff,
+ .minor_features1 = 0xfefbfadb,
+ .minor_features2 = 0xeb9d6fbf,
+ .minor_features3 = 0xedfffced,
+ .minor_features4 = 0xd30dafc7,
+ .minor_features5 = 0x7b5ac333,
+ .minor_features6 = 0xfc8ee200,
+ .minor_features7 = 0x03fffa6f,
+ .minor_features8 = 0x00fe0ef0,
+ .minor_features9 = 0x0088003c,
+ .minor_features10 = 0x108048c0,
+ .minor_features11 = 0x00000010,
+ },
};
bool etnaviv_fill_identity_from_hwdb(struct etnaviv_gpu *gpu)
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_sched.c b/drivers/gpu/drm/etnaviv/etnaviv_sched.c
index d29f467eee13..1ae87dfd19c4 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_sched.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_sched.c
@@ -97,24 +97,24 @@ static const struct drm_sched_backend_ops etnaviv_sched_ops = {
int etnaviv_sched_push_job(struct etnaviv_gem_submit *submit)
{
- int ret = 0;
+ struct etnaviv_gpu *gpu = submit->gpu;
+ int ret;
/*
- * Hold the fence lock across the whole operation to avoid jobs being
+ * Hold the sched lock across the whole operation to avoid jobs being
* pushed out of order with regard to their sched fence seqnos as
* allocated in drm_sched_job_arm.
*/
- mutex_lock(&submit->gpu->fence_lock);
+ mutex_lock(&gpu->sched_lock);
drm_sched_job_arm(&submit->sched_job);
submit->out_fence = dma_fence_get(&submit->sched_job.s_fence->finished);
- submit->out_fence_id = idr_alloc_cyclic(&submit->gpu->fence_idr,
- submit->out_fence, 0,
- INT_MAX, GFP_KERNEL);
- if (submit->out_fence_id < 0) {
+ ret = xa_alloc_cyclic(&gpu->user_fences, &submit->out_fence_id,
+ submit->out_fence, xa_limit_32b,
+ &gpu->next_user_fence, GFP_KERNEL);
+ if (ret < 0) {
drm_sched_job_cleanup(&submit->sched_job);
- ret = -ENOMEM;
goto out_unlock;
}
@@ -124,7 +124,7 @@ int etnaviv_sched_push_job(struct etnaviv_gem_submit *submit)
drm_sched_entity_push_job(&submit->sched_job);
out_unlock:
- mutex_unlock(&submit->gpu->fence_lock);
+ mutex_unlock(&gpu->sched_lock);
return ret;
}
diff --git a/drivers/gpu/drm/etnaviv/state_hi.xml.h b/drivers/gpu/drm/etnaviv/state_hi.xml.h
index deaaa99fa654..94d5f33b1fd6 100644
--- a/drivers/gpu/drm/etnaviv/state_hi.xml.h
+++ b/drivers/gpu/drm/etnaviv/state_hi.xml.h
@@ -8,17 +8,17 @@ http://0x04.net/cgit/index.cgi/rules-ng-ng
git clone git://0x04.net/rules-ng-ng
The rules-ng-ng source files this header was generated from are:
-- state.xml ( 26666 bytes, from 2019-12-20 21:20:35)
-- common.xml ( 35468 bytes, from 2018-02-10 13:09:26)
-- common_3d.xml ( 15058 bytes, from 2019-12-28 20:02:03)
-- state_hi.xml ( 30552 bytes, from 2019-12-28 20:02:48)
-- copyright.xml ( 1597 bytes, from 2018-02-10 13:09:26)
-- state_2d.xml ( 51552 bytes, from 2018-02-10 13:09:26)
-- state_3d.xml ( 83098 bytes, from 2019-12-28 20:02:03)
-- state_blt.xml ( 14252 bytes, from 2019-10-20 19:59:15)
-- state_vg.xml ( 5975 bytes, from 2018-02-10 13:09:26)
-
-Copyright (C) 2012-2019 by the following authors:
+- state.xml ( 27198 bytes, from 2022-04-22 10:35:24)
+- common.xml ( 35468 bytes, from 2020-10-28 12:56:03)
+- common_3d.xml ( 15058 bytes, from 2020-10-28 12:56:03)
+- state_hi.xml ( 34804 bytes, from 2022-12-02 09:06:28)
+- copyright.xml ( 1597 bytes, from 2020-10-28 12:56:03)
+- state_2d.xml ( 51552 bytes, from 2020-10-28 12:56:03)
+- state_3d.xml ( 84445 bytes, from 2022-11-15 15:59:38)
+- state_blt.xml ( 14424 bytes, from 2022-11-07 11:18:41)
+- state_vg.xml ( 5975 bytes, from 2020-10-28 12:56:03)
+
+Copyright (C) 2012-2022 by the following authors:
- Wladimir J. van der Laan <laanwj@gmail.com>
- Christian Gmeiner <christian.gmeiner@gmail.com>
- Lucas Stach <l.stach@pengutronix.de>
@@ -321,16 +321,16 @@ DEALINGS IN THE SOFTWARE.
#define VIVS_MMUv2_CONFIGURATION_ADDRESS(x) (((x) << VIVS_MMUv2_CONFIGURATION_ADDRESS__SHIFT) & VIVS_MMUv2_CONFIGURATION_ADDRESS__MASK)
#define VIVS_MMUv2_STATUS 0x00000188
-#define VIVS_MMUv2_STATUS_EXCEPTION0__MASK 0x00000003
+#define VIVS_MMUv2_STATUS_EXCEPTION0__MASK 0x0000000f
#define VIVS_MMUv2_STATUS_EXCEPTION0__SHIFT 0
#define VIVS_MMUv2_STATUS_EXCEPTION0(x) (((x) << VIVS_MMUv2_STATUS_EXCEPTION0__SHIFT) & VIVS_MMUv2_STATUS_EXCEPTION0__MASK)
-#define VIVS_MMUv2_STATUS_EXCEPTION1__MASK 0x00000030
+#define VIVS_MMUv2_STATUS_EXCEPTION1__MASK 0x000000f0
#define VIVS_MMUv2_STATUS_EXCEPTION1__SHIFT 4
#define VIVS_MMUv2_STATUS_EXCEPTION1(x) (((x) << VIVS_MMUv2_STATUS_EXCEPTION1__SHIFT) & VIVS_MMUv2_STATUS_EXCEPTION1__MASK)
-#define VIVS_MMUv2_STATUS_EXCEPTION2__MASK 0x00000300
+#define VIVS_MMUv2_STATUS_EXCEPTION2__MASK 0x00000f00
#define VIVS_MMUv2_STATUS_EXCEPTION2__SHIFT 8
#define VIVS_MMUv2_STATUS_EXCEPTION2(x) (((x) << VIVS_MMUv2_STATUS_EXCEPTION2__SHIFT) & VIVS_MMUv2_STATUS_EXCEPTION2__MASK)
-#define VIVS_MMUv2_STATUS_EXCEPTION3__MASK 0x00003000
+#define VIVS_MMUv2_STATUS_EXCEPTION3__MASK 0x0000f000
#define VIVS_MMUv2_STATUS_EXCEPTION3__SHIFT 12
#define VIVS_MMUv2_STATUS_EXCEPTION3(x) (((x) << VIVS_MMUv2_STATUS_EXCEPTION3__SHIFT) & VIVS_MMUv2_STATUS_EXCEPTION3__MASK)
@@ -465,7 +465,13 @@ DEALINGS IN THE SOFTWARE.
#define VIVS_MC_PROFILE_CONFIG0 0x00000470
#define VIVS_MC_PROFILE_CONFIG0_FE__MASK 0x000000ff
#define VIVS_MC_PROFILE_CONFIG0_FE__SHIFT 0
+#define VIVS_MC_PROFILE_CONFIG0_FE_DRAW_COUNT 0x0000000a
+#define VIVS_MC_PROFILE_CONFIG0_FE_OUT_VERTEX_COUNT 0x0000000b
+#define VIVS_MC_PROFILE_CONFIG0_FE_CACHE_MISS_COUNT 0x0000000c
#define VIVS_MC_PROFILE_CONFIG0_FE_RESET 0x0000000f
+#define VIVS_MC_PROFILE_CONFIG0_FE_CACHE_LK_COUNT 0x00000010
+#define VIVS_MC_PROFILE_CONFIG0_FE_STALL_COUNT 0x00000011
+#define VIVS_MC_PROFILE_CONFIG0_FE_PROCESS_COUNT 0x00000012
#define VIVS_MC_PROFILE_CONFIG0_DE__MASK 0x0000ff00
#define VIVS_MC_PROFILE_CONFIG0_DE__SHIFT 8
#define VIVS_MC_PROFILE_CONFIG0_DE_RESET 0x00000f00
@@ -499,11 +505,14 @@ DEALINGS IN THE SOFTWARE.
#define VIVS_MC_PROFILE_CONFIG1_PA_DEPTH_CLIPPED_COUNTER 0x00000006
#define VIVS_MC_PROFILE_CONFIG1_PA_TRIVIAL_REJECTED_COUNTER 0x00000007
#define VIVS_MC_PROFILE_CONFIG1_PA_CULLED_COUNTER 0x00000008
+#define VIVS_MC_PROFILE_CONFIG1_PA_DROPED_PRIM_COUNTER 0x00000009
+#define VIVS_MC_PROFILE_CONFIG1_PA_FRUSTUM_CLIPPED_PRIM_COUNTER 0x0000000a
#define VIVS_MC_PROFILE_CONFIG1_PA_RESET 0x0000000f
#define VIVS_MC_PROFILE_CONFIG1_SE__MASK 0x0000ff00
#define VIVS_MC_PROFILE_CONFIG1_SE__SHIFT 8
#define VIVS_MC_PROFILE_CONFIG1_SE_CULLED_TRIANGLE_COUNT 0x00000000
#define VIVS_MC_PROFILE_CONFIG1_SE_CULLED_LINES_COUNT 0x00000100
+#define VIVS_MC_PROFILE_CONFIG1_SE_TRIVIAL_REJECTED_LINE_COUNT 0x00000400
#define VIVS_MC_PROFILE_CONFIG1_SE_RESET 0x00000f00
#define VIVS_MC_PROFILE_CONFIG1_RA__MASK 0x00ff0000
#define VIVS_MC_PROFILE_CONFIG1_RA__SHIFT 16
@@ -515,6 +524,8 @@ DEALINGS IN THE SOFTWARE.
#define VIVS_MC_PROFILE_CONFIG1_RA_PREFETCH_CACHE_MISS_COUNTER 0x000a0000
#define VIVS_MC_PROFILE_CONFIG1_RA_CULLED_QUAD_COUNT 0x000b0000
#define VIVS_MC_PROFILE_CONFIG1_RA_RESET 0x000f0000
+#define VIVS_MC_PROFILE_CONFIG1_RA_PIPE_HZ_CACHE_MISS_COUNTER 0x00110000
+#define VIVS_MC_PROFILE_CONFIG1_RA_PREFETCH_HZ_CACHE_MISS_COUNTER 0x00120000
#define VIVS_MC_PROFILE_CONFIG1_TX__MASK 0xff000000
#define VIVS_MC_PROFILE_CONFIG1_TX__SHIFT 24
#define VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_BILINEAR_REQUESTS 0x00000000
@@ -535,13 +546,48 @@ DEALINGS IN THE SOFTWARE.
#define VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_READ_REQ_8B_FROM_PIPELINE 0x00000001
#define VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_READ_REQ_8B_FROM_IP 0x00000002
#define VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_WRITE_REQ_8B_FROM_PIPELINE 0x00000003
-#define VIVS_MC_PROFILE_CONFIG2_MC_RESET 0x0000000f
+#define VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_READ_REQ_SENTOUT_FROM_COLORPIPE 0x00000004
+#define VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_WRITE_REQ_FROM_COLORPIPE 0x00000005
+#define VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_READ_REQ_8B_FROM_DEPTHPIPE 0x00000007
+#define VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_READ_REQ_8B_SENTOUT_FROM_DEPTHPIPE 0x00000008
+#define VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_WRITE_REQ_8B_FROM_DEPTHPIPE 0x00000009
+#define VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_READ_REQ_SENTOUT_FROM_DEPTHPIPE 0x0000000a
+#define VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_WRITE_REQ_FROM_DEPTHPIPE 0x0000000b
+#define VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_READ_REQ_8B_FROM_OTHERS 0x0000000c
+#define VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_WRITE_REQ_8B_FROM_OTHERS 0x0000000d
+#define VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_READ_REQ_FROM_OTHERS 0x0000000e
+#define VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_WRITE_REQ_FROM_OTHERS 0x0000000f
+#define VIVS_MC_PROFILE_CONFIG2_MC_FE_READ_BANDWIDTH 0x00000015
+#define VIVS_MC_PROFILE_CONFIG2_MC_MMU_READ_BANDWIDTH 0x00000016
+#define VIVS_MC_PROFILE_CONFIG2_MC_BLT_READ_BANDWIDTH 0x00000017
+#define VIVS_MC_PROFILE_CONFIG2_MC_SH0_READ_BANDWIDTH 0x00000018
+#define VIVS_MC_PROFILE_CONFIG2_MC_SH1_READ_BANDWIDTH 0x00000019
+#define VIVS_MC_PROFILE_CONFIG2_MC_PE_WRITE_BANDWIDTH 0x0000001a
+#define VIVS_MC_PROFILE_CONFIG2_MC_BLT_WRITE_BANDWIDTH 0x0000001b
+#define VIVS_MC_PROFILE_CONFIG2_MC_SH0_WRITE_BANDWIDTH 0x0000001c
+#define VIVS_MC_PROFILE_CONFIG2_MC_SH1_WRITE_BANDWIDTH 0x0000001d
#define VIVS_MC_PROFILE_CONFIG2_HI__MASK 0x0000ff00
#define VIVS_MC_PROFILE_CONFIG2_HI__SHIFT 8
#define VIVS_MC_PROFILE_CONFIG2_HI_AXI_CYCLES_READ_REQUEST_STALLED 0x00000000
#define VIVS_MC_PROFILE_CONFIG2_HI_AXI_CYCLES_WRITE_REQUEST_STALLED 0x00000100
#define VIVS_MC_PROFILE_CONFIG2_HI_AXI_CYCLES_WRITE_DATA_STALLED 0x00000200
#define VIVS_MC_PROFILE_CONFIG2_HI_RESET 0x00000f00
+#define VIVS_MC_PROFILE_CONFIG2_L2__MASK 0x00ff0000
+#define VIVS_MC_PROFILE_CONFIG2_L2__SHIFT 16
+#define VIVS_MC_PROFILE_CONFIG2_L2_TOTAL_AXI0_READ_REQUEST_COUNT 0x00000000
+#define VIVS_MC_PROFILE_CONFIG2_L2_TOTAL_AXI0_WRITE_REQUEST_COUNT 0x00040000
+#define VIVS_MC_PROFILE_CONFIG2_L2_TOTAL_AXI1_WRITE_REQUEST_COUNT 0x00050000
+#define VIVS_MC_PROFILE_CONFIG2_L2_TOTAL_READ_TRANSACTIONS_REQUEST_BY_AXI0 0x00080000
+#define VIVS_MC_PROFILE_CONFIG2_L2_TOTAL_READ_TRANSACTIONS_REQUEST_BY_AXI1 0x00090000
+#define VIVS_MC_PROFILE_CONFIG2_L2_TOTAL_WRITE_TRANSACTIONS_REQUEST_BY_AXI0 0x000c0000
+#define VIVS_MC_PROFILE_CONFIG2_L2_TOTAL_WRITE_TRANSACTIONS_REQUEST_BY_AXI1 0x000d0000
+#define VIVS_MC_PROFILE_CONFIG2_L2_RESET 0x000f0000
+#define VIVS_MC_PROFILE_CONFIG2_L2_AXI0_MINMAX_LATENCY 0x00100000
+#define VIVS_MC_PROFILE_CONFIG2_L2_AXI0_TOTAL_LATENCY 0x00110000
+#define VIVS_MC_PROFILE_CONFIG2_L2_AXI0_TOTAL_REQUEST_COUNT 0x00120000
+#define VIVS_MC_PROFILE_CONFIG2_L2_AXI1_MINMAX_LATENCY 0x00130000
+#define VIVS_MC_PROFILE_CONFIG2_L2_AXI1_TOTAL_LATENCY 0x00140000
+#define VIVS_MC_PROFILE_CONFIG2_L2_AXI1_TOTAL_REQUEST_COUNT 0x00150000
#define VIVS_MC_PROFILE_CONFIG2_BLT__MASK 0xff000000
#define VIVS_MC_PROFILE_CONFIG2_BLT__SHIFT 24
#define VIVS_MC_PROFILE_CONFIG2_BLT_UNK0 0x00000000
@@ -566,5 +612,13 @@ DEALINGS IN THE SOFTWARE.
#define VIVS_MC_PROFILE_L2_READ 0x00000564
+#define VIVS_MC_MC_LATENCY_RESET 0x00000568
+
+#define VIVS_MC_MC_AXI_MAX_MIN_LATENCY 0x0000056c
+
+#define VIVS_MC_MC_AXI_TOTAL_LATENCY 0x00000570
+
+#define VIVS_MC_MC_AXI_SAMPLE_COUNT 0x00000574
+
#endif /* STATE_HI_XML */
diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c
index 8155d7e650f1..2867b39fa35e 100644
--- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c
+++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c
@@ -710,7 +710,6 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
-#ifdef CONFIG_PM
static int exynos5433_decon_suspend(struct device *dev)
{
struct decon_context *ctx = dev_get_drvdata(dev);
@@ -741,14 +740,10 @@ err:
return ret;
}
-#endif
-static const struct dev_pm_ops exynos5433_decon_pm_ops = {
- SET_RUNTIME_PM_OPS(exynos5433_decon_suspend, exynos5433_decon_resume,
- NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
-};
+static DEFINE_RUNTIME_DEV_PM_OPS(exynos5433_decon_pm_ops,
+ exynos5433_decon_suspend,
+ exynos5433_decon_resume, NULL);
static const struct of_device_id exynos5433_decon_driver_dt_match[] = {
{
@@ -881,7 +876,7 @@ struct platform_driver exynos5433_decon_driver = {
.remove = exynos5433_decon_remove,
.driver = {
.name = "exynos5433-decon",
- .pm = &exynos5433_decon_pm_ops,
+ .pm = pm_ptr(&exynos5433_decon_pm_ops),
.of_match_table = exynos5433_decon_driver_dt_match,
},
};
diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c
index 7080cf7952ec..3126f735dedc 100644
--- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c
+++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c
@@ -779,7 +779,6 @@ static int decon_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
static int exynos7_decon_suspend(struct device *dev)
{
struct decon_context *ctx = dev_get_drvdata(dev);
@@ -836,21 +835,16 @@ err_aclk_enable:
err_pclk_enable:
return ret;
}
-#endif
-static const struct dev_pm_ops exynos7_decon_pm_ops = {
- SET_RUNTIME_PM_OPS(exynos7_decon_suspend, exynos7_decon_resume,
- NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
-};
+static DEFINE_RUNTIME_DEV_PM_OPS(exynos7_decon_pm_ops, exynos7_decon_suspend,
+ exynos7_decon_resume, NULL);
struct platform_driver decon_driver = {
.probe = decon_probe,
.remove = decon_remove,
.driver = {
.name = "exynos-decon",
- .pm = &exynos7_decon_pm_ops,
+ .pm = pm_ptr(&exynos7_decon_pm_ops),
.of_match_table = decon_driver_dt_match,
},
};
diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
index 4e3d3d5f6866..3404ec1367fb 100644
--- a/drivers/gpu/drm/exynos/exynos_dp.c
+++ b/drivers/gpu/drm/exynos/exynos_dp.c
@@ -260,7 +260,6 @@ static int exynos_dp_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
static int exynos_dp_suspend(struct device *dev)
{
struct exynos_dp_device *dp = dev_get_drvdata(dev);
@@ -274,13 +273,9 @@ static int exynos_dp_resume(struct device *dev)
return analogix_dp_resume(dp->adp);
}
-#endif
-static const struct dev_pm_ops exynos_dp_pm_ops = {
- SET_RUNTIME_PM_OPS(exynos_dp_suspend, exynos_dp_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
-};
+static DEFINE_RUNTIME_DEV_PM_OPS(exynos_dp_pm_ops, exynos_dp_suspend,
+ exynos_dp_resume, NULL);
static const struct of_device_id exynos_dp_match[] = {
{ .compatible = "samsung,exynos5-dp" },
@@ -294,7 +289,7 @@ struct platform_driver dp_driver = {
.driver = {
.name = "exynos-dp",
.owner = THIS_MODULE,
- .pm = &exynos_dp_pm_ops,
+ .pm = pm_ptr(&exynos_dp_pm_ops),
.of_match_table = exynos_dp_match,
},
};
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index ec673223d6b7..06d6513ddaae 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -75,10 +75,27 @@
#define DSIM_MAIN_PIX_FORMAT_RGB565 (0x4 << 12)
#define DSIM_SUB_VC (((x) & 0x3) << 16)
#define DSIM_MAIN_VC (((x) & 0x3) << 18)
-#define DSIM_HSA_MODE (1 << 20)
-#define DSIM_HBP_MODE (1 << 21)
-#define DSIM_HFP_MODE (1 << 22)
-#define DSIM_HSE_MODE (1 << 23)
+#define DSIM_HSA_DISABLE_MODE (1 << 20)
+#define DSIM_HBP_DISABLE_MODE (1 << 21)
+#define DSIM_HFP_DISABLE_MODE (1 << 22)
+/*
+ * The i.MX 8M Mini Applications Processor Reference Manual,
+ * Rev. 3, 11/2020 Page 4091
+ * The i.MX 8M Nano Applications Processor Reference Manual,
+ * Rev. 2, 07/2022 Page 3058
+ * The i.MX 8M Plus Applications Processor Reference Manual,
+ * Rev. 1, 06/2021 Page 5436
+ * named this bit as 'HseDisableMode' but the bit definition
+ * is quite opposite like
+ * 0 = Disables transfer
+ * 1 = Enables transfer
+ * which clearly states that HSE is not a disable bit.
+ *
+ * This bit is named as per the manual even though it is not
+ * a disable bit however the driver logic for handling HSE
+ * is based on the MIPI_DSI_MODE_VIDEO_HSE flag itself.
+ */
+#define DSIM_HSE_DISABLE_MODE (1 << 23)
#define DSIM_AUTO_MODE (1 << 24)
#define DSIM_VIDEO_MODE (1 << 25)
#define DSIM_BURST_MODE (1 << 26)
@@ -804,16 +821,16 @@ static int exynos_dsi_init_link(struct exynos_dsi *dsi)
if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_AUTO_VERT)
reg |= DSIM_AUTO_MODE;
if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HSE)
- reg |= DSIM_HSE_MODE;
- if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_NO_HFP))
- reg |= DSIM_HFP_MODE;
- if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_NO_HBP))
- reg |= DSIM_HBP_MODE;
- if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_NO_HSA))
- reg |= DSIM_HSA_MODE;
+ reg |= DSIM_HSE_DISABLE_MODE;
+ if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_NO_HFP)
+ reg |= DSIM_HFP_DISABLE_MODE;
+ if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_NO_HBP)
+ reg |= DSIM_HBP_DISABLE_MODE;
+ if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_NO_HSA)
+ reg |= DSIM_HSA_DISABLE_MODE;
}
- if (!(dsi->mode_flags & MIPI_DSI_MODE_NO_EOT_PACKET))
+ if (dsi->mode_flags & MIPI_DSI_MODE_NO_EOT_PACKET)
reg |= DSIM_EOT_DISABLE;
switch (dsi->format) {
@@ -1428,7 +1445,8 @@ static int exynos_dsi_attach(struct drm_bridge *bridge,
{
struct exynos_dsi *dsi = bridge_to_dsi(bridge);
- return drm_bridge_attach(bridge->encoder, dsi->out_bridge, NULL, flags);
+ return drm_bridge_attach(bridge->encoder, dsi->out_bridge, bridge,
+ flags);
}
static const struct drm_bridge_funcs exynos_dsi_bridge_funcs = {
@@ -1474,7 +1492,10 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
drm_bridge_add(&dsi->bridge);
- drm_bridge_attach(encoder, &dsi->bridge, NULL, 0);
+ drm_bridge_attach(encoder, &dsi->bridge,
+ list_first_entry_or_null(&encoder->bridge_chain,
+ struct drm_bridge,
+ chain_node), 0);
/*
* This is a temporary solution and should be made by more generic way.
@@ -1709,6 +1730,7 @@ static int exynos_dsi_probe(struct platform_device *pdev)
dsi->bridge.funcs = &exynos_dsi_bridge_funcs;
dsi->bridge.of_node = dev->of_node;
dsi->bridge.type = DRM_MODE_CONNECTOR_DSI;
+ dsi->bridge.pre_enable_prev_first = true;
ret = component_add(dev, &exynos_dsi_component_ops);
if (ret)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
index 55c92372fca0..4929ffe5a09a 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
@@ -163,7 +163,7 @@ int exynos_drm_fbdev_init(struct drm_device *dev)
private->fb_helper = helper = &fbdev->drm_fb_helper;
- drm_fb_helper_prepare(dev, helper, &exynos_drm_fb_helper_funcs);
+ drm_fb_helper_prepare(dev, helper, PREFERRED_BPP, &exynos_drm_fb_helper_funcs);
ret = drm_fb_helper_init(dev, helper);
if (ret < 0) {
@@ -172,7 +172,7 @@ int exynos_drm_fbdev_init(struct drm_device *dev)
goto err_init;
}
- ret = drm_fb_helper_initial_config(helper, PREFERRED_BPP);
+ ret = drm_fb_helper_initial_config(helper);
if (ret < 0) {
DRM_DEV_ERROR(dev->dev,
"failed to set up hw configuration.\n");
@@ -183,8 +183,8 @@ int exynos_drm_fbdev_init(struct drm_device *dev)
err_setup:
drm_fb_helper_fini(helper);
-
err_init:
+ drm_fb_helper_unprepare(helper);
private->fb_helper = NULL;
kfree(fbdev);
@@ -219,6 +219,7 @@ void exynos_drm_fbdev_fini(struct drm_device *dev)
fbdev = to_exynos_fbdev(private->fb_helper);
exynos_drm_fbdev_destroy(dev, private->fb_helper);
+ drm_fb_helper_unprepare(private->fb_helper);
kfree(fbdev);
private->fb_helper = NULL;
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimc.c b/drivers/gpu/drm/exynos/exynos_drm_fimc.c
index 0ee32e4b1e43..8de2714599fc 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimc.c
@@ -1381,7 +1381,6 @@ static int fimc_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
static int fimc_runtime_suspend(struct device *dev)
{
struct fimc_context *ctx = get_fimc_context(dev);
@@ -1398,13 +1397,9 @@ static int fimc_runtime_resume(struct device *dev)
DRM_DEV_DEBUG_KMS(dev, "id[%d]\n", ctx->id);
return clk_prepare_enable(ctx->clocks[FIMC_CLK_GATE]);
}
-#endif
-static const struct dev_pm_ops fimc_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
- SET_RUNTIME_PM_OPS(fimc_runtime_suspend, fimc_runtime_resume, NULL)
-};
+static DEFINE_RUNTIME_DEV_PM_OPS(fimc_pm_ops, fimc_runtime_suspend,
+ fimc_runtime_resume, NULL);
static const struct of_device_id fimc_of_match[] = {
{ .compatible = "samsung,exynos4210-fimc" },
@@ -1420,6 +1415,6 @@ struct platform_driver fimc_driver = {
.of_match_table = fimc_of_match,
.name = "exynos-drm-fimc",
.owner = THIS_MODULE,
- .pm = &fimc_pm_ops,
+ .pm = pm_ptr(&fimc_pm_ops),
},
};
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index ae6636e6658e..7f4a0be03dd1 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -1287,7 +1287,6 @@ static int fimd_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
static int exynos_fimd_suspend(struct device *dev)
{
struct fimd_context *ctx = dev_get_drvdata(dev);
@@ -1321,13 +1320,9 @@ static int exynos_fimd_resume(struct device *dev)
return 0;
}
-#endif
-static const struct dev_pm_ops exynos_fimd_pm_ops = {
- SET_RUNTIME_PM_OPS(exynos_fimd_suspend, exynos_fimd_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
-};
+static DEFINE_RUNTIME_DEV_PM_OPS(exynos_fimd_pm_ops, exynos_fimd_suspend,
+ exynos_fimd_resume, NULL);
struct platform_driver fimd_driver = {
.probe = fimd_probe,
@@ -1335,7 +1330,7 @@ struct platform_driver fimd_driver = {
.driver = {
.name = "exynos4-fb",
.owner = THIS_MODULE,
- .pm = &exynos_fimd_pm_ops,
+ .pm = pm_ptr(&exynos_fimd_pm_ops),
.of_match_table = fimd_driver_dt_match,
},
};
diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
index e19c2ceb3759..ec784e58da5c 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
@@ -1549,7 +1549,6 @@ static int g2d_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
static int g2d_suspend(struct device *dev)
{
struct g2d_data *g2d = dev_get_drvdata(dev);
@@ -1574,9 +1573,7 @@ static int g2d_resume(struct device *dev)
return 0;
}
-#endif
-#ifdef CONFIG_PM
static int g2d_runtime_suspend(struct device *dev)
{
struct g2d_data *g2d = dev_get_drvdata(dev);
@@ -1597,11 +1594,10 @@ static int g2d_runtime_resume(struct device *dev)
return ret;
}
-#endif
static const struct dev_pm_ops g2d_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(g2d_suspend, g2d_resume)
- SET_RUNTIME_PM_OPS(g2d_runtime_suspend, g2d_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(g2d_suspend, g2d_resume)
+ RUNTIME_PM_OPS(g2d_runtime_suspend, g2d_runtime_resume, NULL)
};
static const struct of_device_id exynos_g2d_match[] = {
@@ -1617,7 +1613,7 @@ struct platform_driver g2d_driver = {
.driver = {
.name = "exynos-drm-g2d",
.owner = THIS_MODULE,
- .pm = &g2d_pm_ops,
+ .pm = pm_ptr(&g2d_pm_ops),
.of_match_table = exynos_g2d_match,
},
};
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c
index 3e493f48e0d4..638ca96830e9 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c
@@ -274,7 +274,7 @@ static int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem *exynos_gem,
unsigned long vm_size;
int ret;
- vma->vm_flags &= ~VM_PFNMAP;
+ vm_flags_clear(vma, VM_PFNMAP);
vma->vm_pgoff = 0;
vm_size = vma->vm_end - vma->vm_start;
@@ -368,7 +368,7 @@ static int exynos_drm_gem_mmap(struct drm_gem_object *obj, struct vm_area_struct
if (obj->import_attach)
return dma_buf_mmap(obj->dma_buf, vma, 0);
- vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
+ vm_flags_set(vma, VM_IO | VM_DONTEXPAND | VM_DONTDUMP);
DRM_DEV_DEBUG_KMS(to_dma_dev(obj->dev), "flags = 0x%x\n",
exynos_gem->flags);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_mic.c b/drivers/gpu/drm/exynos/exynos_drm_mic.c
index 09ce28ee08d9..17bab5b1663f 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_mic.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_mic.c
@@ -340,7 +340,6 @@ static const struct component_ops exynos_mic_component_ops = {
.unbind = exynos_mic_unbind,
};
-#ifdef CONFIG_PM
static int exynos_mic_suspend(struct device *dev)
{
struct exynos_mic *mic = dev_get_drvdata(dev);
@@ -369,13 +368,9 @@ static int exynos_mic_resume(struct device *dev)
}
return 0;
}
-#endif
-static const struct dev_pm_ops exynos_mic_pm_ops = {
- SET_RUNTIME_PM_OPS(exynos_mic_suspend, exynos_mic_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
-};
+static DEFINE_RUNTIME_DEV_PM_OPS(exynos_mic_pm_ops, exynos_mic_suspend,
+ exynos_mic_resume, NULL);
static int exynos_mic_probe(struct platform_device *pdev)
{
@@ -470,7 +465,7 @@ struct platform_driver mic_driver = {
.remove = exynos_mic_remove,
.driver = {
.name = "exynos-mic",
- .pm = &exynos_mic_pm_ops,
+ .pm = pm_ptr(&exynos_mic_pm_ops),
.owner = THIS_MODULE,
.of_match_table = exynos_mic_of_match,
},
diff --git a/drivers/gpu/drm/exynos/exynos_drm_rotator.c b/drivers/gpu/drm/exynos/exynos_drm_rotator.c
index dec7df35baa9..8706f377c349 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_rotator.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_rotator.c
@@ -340,7 +340,6 @@ static int rotator_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
static int rotator_runtime_suspend(struct device *dev)
{
struct rot_context *rot = dev_get_drvdata(dev);
@@ -355,7 +354,6 @@ static int rotator_runtime_resume(struct device *dev)
return clk_prepare_enable(rot->clock);
}
-#endif
static const struct drm_exynos_ipp_limit rotator_s5pv210_rbg888_limits[] = {
{ IPP_SIZE_LIMIT(BUFFER, .h = { 8, SZ_16K }, .v = { 8, SZ_16K }) },
@@ -450,12 +448,8 @@ static const struct of_device_id exynos_rotator_match[] = {
};
MODULE_DEVICE_TABLE(of, exynos_rotator_match);
-static const struct dev_pm_ops rotator_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
- SET_RUNTIME_PM_OPS(rotator_runtime_suspend, rotator_runtime_resume,
- NULL)
-};
+static DEFINE_RUNTIME_DEV_PM_OPS(rotator_pm_ops, rotator_runtime_suspend,
+ rotator_runtime_resume, NULL);
struct platform_driver rotator_driver = {
.probe = rotator_probe,
@@ -463,7 +457,7 @@ struct platform_driver rotator_driver = {
.driver = {
.name = "exynos-rotator",
.owner = THIS_MODULE,
- .pm = &rotator_pm_ops,
+ .pm = pm_ptr(&rotator_pm_ops),
.of_match_table = exynos_rotator_match,
},
};
diff --git a/drivers/gpu/drm/exynos/exynos_drm_scaler.c b/drivers/gpu/drm/exynos/exynos_drm_scaler.c
index 3c049fb658a3..20608e9780ce 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_scaler.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_scaler.c
@@ -550,8 +550,6 @@ static int scaler_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
-
static int clk_disable_unprepare_wrapper(struct clk *clk)
{
clk_disable_unprepare(clk);
@@ -584,13 +582,9 @@ static int scaler_runtime_resume(struct device *dev)
return scaler_clk_ctrl(scaler, true);
}
-#endif
-static const struct dev_pm_ops scaler_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
- SET_RUNTIME_PM_OPS(scaler_runtime_suspend, scaler_runtime_resume, NULL)
-};
+static DEFINE_RUNTIME_DEV_PM_OPS(scaler_pm_ops, scaler_runtime_suspend,
+ scaler_runtime_resume, NULL);
static const struct drm_exynos_ipp_limit scaler_5420_two_pixel_hv_limits[] = {
{ IPP_SIZE_LIMIT(BUFFER, .h = { 16, SZ_8K }, .v = { 16, SZ_8K }) },
@@ -731,7 +725,7 @@ struct platform_driver scaler_driver = {
.driver = {
.name = "exynos-scaler",
.owner = THIS_MODULE,
- .pm = &scaler_pm_ops,
+ .pm = pm_ptr(&scaler_pm_ops),
.of_match_table = exynos_scaler_match,
},
};
diff --git a/drivers/gpu/drm/gma500/Kconfig b/drivers/gpu/drm/gma500/Kconfig
index 807b989e3c77..2efc0eb41c64 100644
--- a/drivers/gpu/drm/gma500/Kconfig
+++ b/drivers/gpu/drm/gma500/Kconfig
@@ -3,6 +3,8 @@ config DRM_GMA500
tristate "Intel GMA500/600/3600/3650 KMS Framebuffer"
depends on DRM && PCI && X86 && MMU
select DRM_KMS_HELPER
+ select I2C
+ select I2C_ALGOBIT
# GMA500 depends on ACPI_VIDEO when ACPI is enabled, just like i915
select ACPI_VIDEO if ACPI
select BACKLIGHT_CLASS_DEVICE if ACPI
diff --git a/drivers/gpu/drm/gma500/backlight.c b/drivers/gpu/drm/gma500/backlight.c
index 577a4987b193..8711a7a5b8da 100644
--- a/drivers/gpu/drm/gma500/backlight.c
+++ b/drivers/gpu/drm/gma500/backlight.c
@@ -7,6 +7,8 @@
* Authors: Eric Knopp
*/
+#include <linux/backlight.h>
+
#include <acpi/video.h>
#include "psb_drv.h"
diff --git a/drivers/gpu/drm/gma500/cdv_device.c b/drivers/gpu/drm/gma500/cdv_device.c
index 3065596257e9..3e83299113e3 100644
--- a/drivers/gpu/drm/gma500/cdv_device.c
+++ b/drivers/gpu/drm/gma500/cdv_device.c
@@ -8,6 +8,7 @@
#include <linux/delay.h>
#include <drm/drm.h>
+#include <drm/drm_crtc_helper.h>
#include "cdv_device.h"
#include "gma_device.h"
diff --git a/drivers/gpu/drm/gma500/cdv_intel_crt.c b/drivers/gpu/drm/gma500/cdv_intel_crt.c
index 7ff1e5141150..5a0acd914f76 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_crt.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_crt.c
@@ -28,6 +28,8 @@
#include <linux/i2c.h>
#include <linux/pm_runtime.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_simple_kms_helper.h>
#include "cdv_device.h"
diff --git a/drivers/gpu/drm/gma500/cdv_intel_display.c b/drivers/gpu/drm/gma500/cdv_intel_display.c
index 0c3ddcdc29dc..bbd0abdd8382 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_display.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_display.c
@@ -10,6 +10,7 @@
#include <linux/i2c.h>
#include <drm/drm_crtc.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include "cdv_device.h"
#include "framebuffer.h"
diff --git a/drivers/gpu/drm/gma500/cdv_intel_dp.c b/drivers/gpu/drm/gma500/cdv_intel_dp.c
index 53b967282d6a..8992a95076f2 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_dp.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_dp.c
@@ -33,6 +33,7 @@
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_simple_kms_helper.h>
#include "gma_display.h"
diff --git a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
index 29ef45f14169..2d95e0471291 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
@@ -28,7 +28,9 @@
#include <drm/drm.h>
#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_simple_kms_helper.h>
#include "cdv_device.h"
diff --git a/drivers/gpu/drm/gma500/cdv_intel_lvds.c b/drivers/gpu/drm/gma500/cdv_intel_lvds.c
index be6efcaaa3b3..f08a6803dc18 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_lvds.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_lvds.c
@@ -12,6 +12,8 @@
#include <linux/i2c.h>
#include <linux/pm_runtime.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_simple_kms_helper.h>
#include "cdv_device.h"
diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c
index 8d5a37b8f110..50611eb7f134 100644
--- a/drivers/gpu/drm/gma500/framebuffer.c
+++ b/drivers/gpu/drm/gma500/framebuffer.c
@@ -19,10 +19,12 @@
#include <drm/drm.h>
#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_modeset_helper.h>
#include "framebuffer.h"
#include "gem.h"
@@ -139,7 +141,7 @@ static int psbfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
*/
vma->vm_ops = &psbfb_vm_ops;
vma->vm_private_data = (void *)fb;
- vma->vm_flags |= VM_IO | VM_MIXEDMAP | VM_DONTEXPAND | VM_DONTDUMP;
+ vm_flags_set(vma, VM_IO | VM_MIXEDMAP | VM_DONTEXPAND | VM_DONTDUMP);
return 0;
}
@@ -297,11 +299,6 @@ static int psbfb_create(struct drm_fb_helper *fb_helper,
info->screen_base = dev_priv->vram_addr + backing->offset;
info->screen_size = size;
- if (dev_priv->gtt.stolen_size) {
- info->apertures->ranges[0].base = dev_priv->fb_base;
- info->apertures->ranges[0].size = dev_priv->gtt.stolen_size;
- }
-
drm_fb_helper_fill_info(info, fb_helper, sizes);
info->fix.mmio_start = pci_resource_start(pdev, 0);
@@ -412,7 +409,7 @@ int psb_fbdev_init(struct drm_device *dev)
dev_priv->fb_helper = fb_helper;
- drm_fb_helper_prepare(dev, fb_helper, &psb_fb_helper_funcs);
+ drm_fb_helper_prepare(dev, fb_helper, 32, &psb_fb_helper_funcs);
ret = drm_fb_helper_init(dev, fb_helper);
if (ret)
@@ -421,7 +418,7 @@ int psb_fbdev_init(struct drm_device *dev)
/* disable all the possible outputs/crtcs before entering KMS mode */
drm_helper_disable_unused_functions(dev);
- ret = drm_fb_helper_initial_config(fb_helper, 32);
+ ret = drm_fb_helper_initial_config(fb_helper);
if (ret)
goto fini;
@@ -430,6 +427,7 @@ int psb_fbdev_init(struct drm_device *dev)
fini:
drm_fb_helper_fini(fb_helper);
free:
+ drm_fb_helper_unprepare(fb_helper);
kfree(fb_helper);
return ret;
}
@@ -442,6 +440,7 @@ static void psb_fbdev_fini(struct drm_device *dev)
return;
psb_fbdev_destroy(dev, dev_priv->fb_helper);
+ drm_fb_helper_unprepare(dev_priv->fb_helper);
kfree(dev_priv->fb_helper);
dev_priv->fb_helper = NULL;
}
diff --git a/drivers/gpu/drm/gma500/gma_display.c b/drivers/gpu/drm/gma500/gma_display.c
index fe7b8436f87a..f65e90d890f4 100644
--- a/drivers/gpu/drm/gma500/gma_display.c
+++ b/drivers/gpu/drm/gma500/gma_display.c
@@ -11,8 +11,10 @@
#include <linux/highmem.h>
#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_vblank.h>
#include "framebuffer.h"
diff --git a/drivers/gpu/drm/gma500/oaktrail_crtc.c b/drivers/gpu/drm/gma500/oaktrail_crtc.c
index 64761f46b434..de8ccfe9890f 100644
--- a/drivers/gpu/drm/gma500/oaktrail_crtc.c
+++ b/drivers/gpu/drm/gma500/oaktrail_crtc.c
@@ -9,6 +9,7 @@
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include "framebuffer.h"
#include "gem.h"
diff --git a/drivers/gpu/drm/gma500/oaktrail_hdmi.c b/drivers/gpu/drm/gma500/oaktrail_hdmi.c
index 95b7cb099e63..ed8626c73541 100644
--- a/drivers/gpu/drm/gma500/oaktrail_hdmi.c
+++ b/drivers/gpu/drm/gma500/oaktrail_hdmi.c
@@ -27,7 +27,9 @@
#include <linux/delay.h>
#include <drm/drm.h>
+#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_simple_kms_helper.h>
#include "psb_drv.h"
diff --git a/drivers/gpu/drm/gma500/oaktrail_lvds.c b/drivers/gpu/drm/gma500/oaktrail_lvds.c
index 75b4eb1c8884..d974d0c60d2a 100644
--- a/drivers/gpu/drm/gma500/oaktrail_lvds.c
+++ b/drivers/gpu/drm/gma500/oaktrail_lvds.c
@@ -14,6 +14,7 @@
#include <asm/intel-mid.h>
#include <drm/drm_edid.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_simple_kms_helper.h>
#include "intel_bios.h"
diff --git a/drivers/gpu/drm/gma500/psb_device.c b/drivers/gpu/drm/gma500/psb_device.c
index 3c294c38bdb4..dcfcd7b89d4a 100644
--- a/drivers/gpu/drm/gma500/psb_device.c
+++ b/drivers/gpu/drm/gma500/psb_device.c
@@ -6,6 +6,7 @@
**************************************************************************/
#include <drm/drm.h>
+#include <drm/drm_crtc_helper.h>
#include "gma_device.h"
#include "intel_bios.h"
diff --git a/drivers/gpu/drm/gma500/psb_intel_display.c b/drivers/gpu/drm/gma500/psb_intel_display.c
index 531c1781a8fb..ff46e88c4768 100644
--- a/drivers/gpu/drm/gma500/psb_intel_display.c
+++ b/drivers/gpu/drm/gma500/psb_intel_display.c
@@ -9,6 +9,9 @@
#include <linux/delay.h>
#include <linux/i2c.h>
+#include <drm/drm_modeset_helper.h>
+#include <drm/drm_modeset_helper_vtables.h>
+
#include "framebuffer.h"
#include "gem.h"
#include "gma_display.h"
diff --git a/drivers/gpu/drm/gma500/psb_intel_drv.h b/drivers/gpu/drm/gma500/psb_intel_drv.h
index 8a1111fe714b..0bb85494e3da 100644
--- a/drivers/gpu/drm/gma500/psb_intel_drv.h
+++ b/drivers/gpu/drm/gma500/psb_intel_drv.h
@@ -9,7 +9,6 @@
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_encoder.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
diff --git a/drivers/gpu/drm/gma500/psb_intel_lvds.c b/drivers/gpu/drm/gma500/psb_intel_lvds.c
index 7ee6c8ce103b..8486de230ec9 100644
--- a/drivers/gpu/drm/gma500/psb_intel_lvds.c
+++ b/drivers/gpu/drm/gma500/psb_intel_lvds.c
@@ -11,6 +11,8 @@
#include <linux/i2c.h>
#include <linux/pm_runtime.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_simple_kms_helper.h>
#include "intel_bios.h"
diff --git a/drivers/gpu/drm/gma500/psb_intel_sdvo.c b/drivers/gpu/drm/gma500/psb_intel_sdvo.c
index bdced46dd333..d6fd5d726216 100644
--- a/drivers/gpu/drm/gma500/psb_intel_sdvo.c
+++ b/drivers/gpu/drm/gma500/psb_intel_sdvo.c
@@ -33,7 +33,9 @@
#include <linux/slab.h>
#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include "psb_drv.h"
#include "psb_intel_drv.h"
diff --git a/drivers/gpu/drm/gud/gud_connector.c b/drivers/gpu/drm/gud/gud_connector.c
index fa636206f232..034e78360d4f 100644
--- a/drivers/gpu/drm/gud/gud_connector.c
+++ b/drivers/gpu/drm/gud/gud_connector.c
@@ -303,7 +303,7 @@ static int gud_connector_atomic_check(struct drm_connector *connector,
old_state->tv.margins.right != new_state->tv.margins.right ||
old_state->tv.margins.top != new_state->tv.margins.top ||
old_state->tv.margins.bottom != new_state->tv.margins.bottom ||
- old_state->tv.mode != new_state->tv.mode ||
+ old_state->tv.legacy_mode != new_state->tv.legacy_mode ||
old_state->tv.brightness != new_state->tv.brightness ||
old_state->tv.contrast != new_state->tv.contrast ||
old_state->tv.flicker_reduction != new_state->tv.flicker_reduction ||
@@ -400,7 +400,7 @@ static int gud_connector_add_tv_mode(struct gud_device *gdrm, struct drm_connect
for (i = 0; i < num_modes; i++)
modes[i] = &buf[i * GUD_CONNECTOR_TV_MODE_NAME_LEN];
- ret = drm_mode_create_tv_properties(connector->dev, num_modes, modes);
+ ret = drm_mode_create_tv_properties_legacy(connector->dev, num_modes, modes);
free:
kfree(buf);
if (ret < 0)
@@ -424,7 +424,7 @@ gud_connector_property_lookup(struct drm_connector *connector, u16 prop)
case GUD_PROPERTY_TV_BOTTOM_MARGIN:
return config->tv_bottom_margin_property;
case GUD_PROPERTY_TV_MODE:
- return config->tv_mode_property;
+ return config->legacy_tv_mode_property;
case GUD_PROPERTY_TV_BRIGHTNESS:
return config->tv_brightness_property;
case GUD_PROPERTY_TV_CONTRAST:
@@ -454,7 +454,7 @@ static unsigned int *gud_connector_tv_state_val(u16 prop, struct drm_tv_connecto
case GUD_PROPERTY_TV_BOTTOM_MARGIN:
return &state->margins.bottom;
case GUD_PROPERTY_TV_MODE:
- return &state->mode;
+ return &state->legacy_mode;
case GUD_PROPERTY_TV_BRIGHTNESS:
return &state->brightness;
case GUD_PROPERTY_TV_CONTRAST:
@@ -539,7 +539,7 @@ static int gud_connector_add_properties(struct gud_device *gdrm, struct gud_conn
fallthrough;
case GUD_PROPERTY_TV_HUE:
/* This is a no-op if already added. */
- ret = drm_mode_create_tv_properties(drm, 0, NULL);
+ ret = drm_mode_create_tv_properties_legacy(drm, 0, NULL);
if (ret)
goto out;
break;
diff --git a/drivers/gpu/drm/gud/gud_drv.c b/drivers/gpu/drm/gud/gud_drv.c
index d57dab104358..9d7bf8ee45f1 100644
--- a/drivers/gpu/drm/gud/gud_drv.c
+++ b/drivers/gpu/drm/gud/gud_drv.c
@@ -325,8 +325,8 @@ static struct drm_gem_object *gud_gem_prime_import(struct drm_device *drm, struc
static int gud_stats_debugfs(struct seq_file *m, void *data)
{
- struct drm_info_node *node = m->private;
- struct gud_device *gdrm = to_gud_device(node->minor->dev);
+ struct drm_debugfs_entry *entry = m->private;
+ struct gud_device *gdrm = to_gud_device(entry->dev);
char buf[10];
string_get_size(gdrm->bulk_len, 1, STRING_UNITS_2, buf, sizeof(buf));
@@ -352,19 +352,10 @@ static int gud_stats_debugfs(struct seq_file *m, void *data)
return 0;
}
-static const struct drm_info_list gud_debugfs_list[] = {
- { "stats", gud_stats_debugfs, 0, NULL },
-};
-
-static void gud_debugfs_init(struct drm_minor *minor)
-{
- drm_debugfs_create_files(gud_debugfs_list, ARRAY_SIZE(gud_debugfs_list),
- minor->debugfs_root, minor);
-}
-
static const struct drm_simple_display_pipe_funcs gud_pipe_funcs = {
.check = gud_pipe_check,
.update = gud_pipe_update,
+ DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS
};
static const struct drm_mode_config_funcs gud_mode_config_funcs = {
@@ -385,7 +376,6 @@ static const struct drm_driver gud_drm_driver = {
.fops = &gud_fops,
DRM_GEM_SHMEM_DRIVER_OPS,
.gem_prime_import = gud_gem_prime_import,
- .debugfs_init = gud_debugfs_init,
.name = "gud",
.desc = "Generic USB Display",
@@ -622,6 +612,8 @@ static int gud_probe(struct usb_interface *intf, const struct usb_device_id *id)
if (!gdrm->dmadev)
dev_warn(dev, "buffer sharing not supported");
+ drm_debugfs_add_file(drm, "stats", gud_stats_debugfs, NULL);
+
ret = drm_dev_register(drm, 0);
if (ret) {
put_device(gdrm->dmadev);
diff --git a/drivers/gpu/drm/gud/gud_internal.h b/drivers/gpu/drm/gud/gud_internal.h
index e351a1f1420d..0d148a6f27aa 100644
--- a/drivers/gpu/drm/gud/gud_internal.h
+++ b/drivers/gpu/drm/gud/gud_internal.h
@@ -43,6 +43,7 @@ struct gud_device {
struct drm_framebuffer *fb;
struct drm_rect damage;
bool prev_flush_failed;
+ void *shadow_buf;
};
static inline struct gud_device *to_gud_device(struct drm_device *drm)
diff --git a/drivers/gpu/drm/gud/gud_pipe.c b/drivers/gpu/drm/gud/gud_pipe.c
index 7c6dc2bcd14a..dc16a92625d4 100644
--- a/drivers/gpu/drm/gud/gud_pipe.c
+++ b/drivers/gpu/drm/gud/gud_pipe.c
@@ -5,6 +5,7 @@
#include <linux/lz4.h>
#include <linux/usb.h>
+#include <linux/vmalloc.h>
#include <linux/workqueue.h>
#include <drm/drm_atomic.h>
@@ -15,6 +16,7 @@
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem.h>
+#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_print.h>
#include <drm/drm_rect.h>
@@ -24,17 +26,13 @@
#include "gud_internal.h"
/*
- * Some userspace rendering loops runs all displays in the same loop.
+ * Some userspace rendering loops run all displays in the same loop.
* This means that a fast display will have to wait for a slow one.
- * For this reason gud does flushing asynchronous by default.
- * The down side is that in e.g. a single display setup userspace thinks
- * the display is insanely fast since the driver reports back immediately
- * that the flush/pageflip is done. This wastes CPU and power.
- * Such users might want to set this module parameter to false.
+ * Such users might want to enable this module parameter.
*/
-static bool gud_async_flush = true;
+static bool gud_async_flush;
module_param_named(async_flush, gud_async_flush, bool, 0644);
-MODULE_PARM_DESC(async_flush, "Enable asynchronous flushing [default=true]");
+MODULE_PARM_DESC(async_flush, "Enable asynchronous flushing [default=0]");
/*
* FIXME: The driver is probably broken on Big Endian machines.
@@ -152,32 +150,21 @@ static size_t gud_xrgb8888_to_color(u8 *dst, const struct drm_format_info *forma
}
static int gud_prep_flush(struct gud_device *gdrm, struct drm_framebuffer *fb,
+ const struct iosys_map *src, bool cached_reads,
const struct drm_format_info *format, struct drm_rect *rect,
struct gud_set_buffer_req *req)
{
- struct dma_buf_attachment *import_attach = fb->obj[0]->import_attach;
u8 compression = gdrm->compression;
- struct iosys_map map[DRM_FORMAT_MAX_PLANES];
- struct iosys_map map_data[DRM_FORMAT_MAX_PLANES];
struct iosys_map dst;
void *vaddr, *buf;
size_t pitch, len;
- int ret = 0;
pitch = drm_format_info_min_pitch(format, 0, drm_rect_width(rect));
len = pitch * drm_rect_height(rect);
if (len > gdrm->bulk_len)
return -E2BIG;
- ret = drm_gem_fb_vmap(fb, map, map_data);
- if (ret)
- return ret;
-
- vaddr = map_data[0].vaddr;
-
- ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE);
- if (ret)
- goto vunmap;
+ vaddr = src[0].vaddr;
retry:
if (compression)
buf = gdrm->compress_buf;
@@ -192,29 +179,27 @@ retry:
if (format != fb->format) {
if (format->format == GUD_DRM_FORMAT_R1) {
len = gud_xrgb8888_to_r124(buf, format, vaddr, fb, rect);
- if (!len) {
- ret = -ENOMEM;
- goto end_cpu_access;
- }
+ if (!len)
+ return -ENOMEM;
} else if (format->format == DRM_FORMAT_R8) {
- drm_fb_xrgb8888_to_gray8(&dst, NULL, map_data, fb, rect);
+ drm_fb_xrgb8888_to_gray8(&dst, NULL, src, fb, rect);
} else if (format->format == DRM_FORMAT_RGB332) {
- drm_fb_xrgb8888_to_rgb332(&dst, NULL, map_data, fb, rect);
+ drm_fb_xrgb8888_to_rgb332(&dst, NULL, src, fb, rect);
} else if (format->format == DRM_FORMAT_RGB565) {
- drm_fb_xrgb8888_to_rgb565(&dst, NULL, map_data, fb, rect,
+ drm_fb_xrgb8888_to_rgb565(&dst, NULL, src, fb, rect,
gud_is_big_endian());
} else if (format->format == DRM_FORMAT_RGB888) {
- drm_fb_xrgb8888_to_rgb888(&dst, NULL, map_data, fb, rect);
+ drm_fb_xrgb8888_to_rgb888(&dst, NULL, src, fb, rect);
} else {
len = gud_xrgb8888_to_color(buf, format, vaddr, fb, rect);
}
} else if (gud_is_big_endian() && format->cpp[0] > 1) {
- drm_fb_swab(&dst, NULL, map_data, fb, rect, !import_attach);
- } else if (compression && !import_attach && pitch == fb->pitches[0]) {
+ drm_fb_swab(&dst, NULL, src, fb, rect, cached_reads);
+ } else if (compression && cached_reads && pitch == fb->pitches[0]) {
/* can compress directly from the framebuffer */
buf = vaddr + rect->y1 * pitch;
} else {
- drm_fb_memcpy(&dst, NULL, map_data, fb, rect);
+ drm_fb_memcpy(&dst, NULL, src, fb, rect);
}
memset(req, 0, sizeof(*req));
@@ -237,12 +222,7 @@ retry:
req->compressed_length = cpu_to_le32(complen);
}
-end_cpu_access:
- drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
-vunmap:
- drm_gem_fb_vunmap(fb, map);
-
- return ret;
+ return 0;
}
struct gud_usb_bulk_context {
@@ -285,6 +265,7 @@ static int gud_usb_bulk(struct gud_device *gdrm, size_t len)
}
static int gud_flush_rect(struct gud_device *gdrm, struct drm_framebuffer *fb,
+ const struct iosys_map *src, bool cached_reads,
const struct drm_format_info *format, struct drm_rect *rect)
{
struct gud_set_buffer_req req;
@@ -293,7 +274,7 @@ static int gud_flush_rect(struct gud_device *gdrm, struct drm_framebuffer *fb,
drm_dbg(&gdrm->drm, "Flushing [FB:%d] " DRM_RECT_FMT "\n", fb->base.id, DRM_RECT_ARG(rect));
- ret = gud_prep_flush(gdrm, fb, format, rect, &req);
+ ret = gud_prep_flush(gdrm, fb, src, cached_reads, format, rect, &req);
if (ret)
return ret;
@@ -333,46 +314,51 @@ void gud_clear_damage(struct gud_device *gdrm)
gdrm->damage.y2 = 0;
}
-static void gud_add_damage(struct gud_device *gdrm, struct drm_rect *damage)
+static void gud_flush_damage(struct gud_device *gdrm, struct drm_framebuffer *fb,
+ const struct iosys_map *src, bool cached_reads,
+ struct drm_rect *damage)
{
- gdrm->damage.x1 = min(gdrm->damage.x1, damage->x1);
- gdrm->damage.y1 = min(gdrm->damage.y1, damage->y1);
- gdrm->damage.x2 = max(gdrm->damage.x2, damage->x2);
- gdrm->damage.y2 = max(gdrm->damage.y2, damage->y2);
-}
+ const struct drm_format_info *format;
+ unsigned int i, lines;
+ size_t pitch;
+ int ret;
-static void gud_retry_failed_flush(struct gud_device *gdrm, struct drm_framebuffer *fb,
- struct drm_rect *damage)
-{
- /*
- * pipe_update waits for the worker when the display mode is going to change.
- * This ensures that the width and height is still the same making it safe to
- * add back the damage.
- */
+ format = fb->format;
+ if (format->format == DRM_FORMAT_XRGB8888 && gdrm->xrgb8888_emulation_format)
+ format = gdrm->xrgb8888_emulation_format;
- mutex_lock(&gdrm->damage_lock);
- if (!gdrm->fb) {
- drm_framebuffer_get(fb);
- gdrm->fb = fb;
- }
- gud_add_damage(gdrm, damage);
- mutex_unlock(&gdrm->damage_lock);
+ /* Split update if it's too big */
+ pitch = drm_format_info_min_pitch(format, 0, drm_rect_width(damage));
+ lines = drm_rect_height(damage);
+
+ if (gdrm->bulk_len < lines * pitch)
+ lines = gdrm->bulk_len / pitch;
+
+ for (i = 0; i < DIV_ROUND_UP(drm_rect_height(damage), lines); i++) {
+ struct drm_rect rect = *damage;
- /* Retry only once to avoid a possible storm in case of continues errors. */
- if (!gdrm->prev_flush_failed)
- queue_work(system_long_wq, &gdrm->work);
- gdrm->prev_flush_failed = true;
+ rect.y1 += i * lines;
+ rect.y2 = min_t(u32, rect.y1 + lines, damage->y2);
+
+ ret = gud_flush_rect(gdrm, fb, src, cached_reads, format, &rect);
+ if (ret) {
+ if (ret != -ENODEV && ret != -ECONNRESET &&
+ ret != -ESHUTDOWN && ret != -EPROTO)
+ dev_err_ratelimited(fb->dev->dev,
+ "Failed to flush framebuffer: error=%d\n", ret);
+ gdrm->prev_flush_failed = true;
+ break;
+ }
+ }
}
void gud_flush_work(struct work_struct *work)
{
struct gud_device *gdrm = container_of(work, struct gud_device, work);
- const struct drm_format_info *format;
+ struct iosys_map shadow_map;
struct drm_framebuffer *fb;
struct drm_rect damage;
- unsigned int i, lines;
- int idx, ret = 0;
- size_t pitch;
+ int idx;
if (!drm_dev_enter(&gdrm->drm, &idx))
return;
@@ -380,6 +366,7 @@ void gud_flush_work(struct work_struct *work)
mutex_lock(&gdrm->damage_lock);
fb = gdrm->fb;
gdrm->fb = NULL;
+ iosys_map_set_vaddr(&shadow_map, gdrm->shadow_buf);
damage = gdrm->damage;
gud_clear_damage(gdrm);
mutex_unlock(&gdrm->damage_lock);
@@ -387,59 +374,43 @@ void gud_flush_work(struct work_struct *work)
if (!fb)
goto out;
- format = fb->format;
- if (format->format == DRM_FORMAT_XRGB8888 && gdrm->xrgb8888_emulation_format)
- format = gdrm->xrgb8888_emulation_format;
-
- /* Split update if it's too big */
- pitch = drm_format_info_min_pitch(format, 0, drm_rect_width(&damage));
- lines = drm_rect_height(&damage);
-
- if (gdrm->bulk_len < lines * pitch)
- lines = gdrm->bulk_len / pitch;
-
- for (i = 0; i < DIV_ROUND_UP(drm_rect_height(&damage), lines); i++) {
- struct drm_rect rect = damage;
-
- rect.y1 += i * lines;
- rect.y2 = min_t(u32, rect.y1 + lines, damage.y2);
-
- ret = gud_flush_rect(gdrm, fb, format, &rect);
- if (ret) {
- if (ret != -ENODEV && ret != -ECONNRESET &&
- ret != -ESHUTDOWN && ret != -EPROTO) {
- bool prev_flush_failed = gdrm->prev_flush_failed;
-
- gud_retry_failed_flush(gdrm, fb, &damage);
- if (!prev_flush_failed)
- dev_err_ratelimited(fb->dev->dev,
- "Failed to flush framebuffer: error=%d\n", ret);
- }
- break;
- }
-
- gdrm->prev_flush_failed = false;
- }
+ gud_flush_damage(gdrm, fb, &shadow_map, true, &damage);
drm_framebuffer_put(fb);
out:
drm_dev_exit(idx);
}
-static void gud_fb_queue_damage(struct gud_device *gdrm, struct drm_framebuffer *fb,
- struct drm_rect *damage)
+static int gud_fb_queue_damage(struct gud_device *gdrm, struct drm_framebuffer *fb,
+ const struct iosys_map *src, struct drm_rect *damage)
{
struct drm_framebuffer *old_fb = NULL;
+ struct iosys_map shadow_map;
mutex_lock(&gdrm->damage_lock);
+ if (!gdrm->shadow_buf) {
+ gdrm->shadow_buf = vzalloc(fb->pitches[0] * fb->height);
+ if (!gdrm->shadow_buf) {
+ mutex_unlock(&gdrm->damage_lock);
+ return -ENOMEM;
+ }
+ }
+
+ iosys_map_set_vaddr(&shadow_map, gdrm->shadow_buf);
+ iosys_map_incr(&shadow_map, drm_fb_clip_offset(fb->pitches[0], fb->format, damage));
+ drm_fb_memcpy(&shadow_map, fb->pitches, src, fb, damage);
+
if (fb != gdrm->fb) {
old_fb = gdrm->fb;
drm_framebuffer_get(fb);
gdrm->fb = fb;
}
- gud_add_damage(gdrm, damage);
+ gdrm->damage.x1 = min(gdrm->damage.x1, damage->x1);
+ gdrm->damage.y1 = min(gdrm->damage.y1, damage->y1);
+ gdrm->damage.x2 = max(gdrm->damage.x2, damage->x2);
+ gdrm->damage.y2 = max(gdrm->damage.y2, damage->y2);
mutex_unlock(&gdrm->damage_lock);
@@ -447,6 +418,26 @@ static void gud_fb_queue_damage(struct gud_device *gdrm, struct drm_framebuffer
if (old_fb)
drm_framebuffer_put(old_fb);
+
+ return 0;
+}
+
+static void gud_fb_handle_damage(struct gud_device *gdrm, struct drm_framebuffer *fb,
+ const struct iosys_map *src, struct drm_rect *damage)
+{
+ int ret;
+
+ if (gdrm->flags & GUD_DISPLAY_FLAG_FULL_UPDATE)
+ drm_rect_init(damage, 0, 0, fb->width, fb->height);
+
+ if (gud_async_flush) {
+ ret = gud_fb_queue_damage(gdrm, fb, src, damage);
+ if (ret != -ENOMEM)
+ return;
+ }
+
+ /* Imported buffers are assumed to be WriteCombined with uncached reads */
+ gud_flush_damage(gdrm, fb, src, !fb->obj[0]->import_attach, damage);
}
int gud_pipe_check(struct drm_simple_display_pipe *pipe,
@@ -571,10 +562,11 @@ void gud_pipe_update(struct drm_simple_display_pipe *pipe,
struct drm_device *drm = pipe->crtc.dev;
struct gud_device *gdrm = to_gud_device(drm);
struct drm_plane_state *state = pipe->plane.state;
+ struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(state);
struct drm_framebuffer *fb = state->fb;
struct drm_crtc *crtc = &pipe->crtc;
struct drm_rect damage;
- int idx;
+ int ret, idx;
if (crtc->state->mode_changed || !crtc->state->enable) {
cancel_work_sync(&gdrm->work);
@@ -584,6 +576,8 @@ void gud_pipe_update(struct drm_simple_display_pipe *pipe,
gdrm->fb = NULL;
}
gud_clear_damage(gdrm);
+ vfree(gdrm->shadow_buf);
+ gdrm->shadow_buf = NULL;
mutex_unlock(&gdrm->damage_lock);
}
@@ -599,14 +593,19 @@ void gud_pipe_update(struct drm_simple_display_pipe *pipe,
if (crtc->state->active_changed)
gud_usb_set_u8(gdrm, GUD_REQ_SET_DISPLAY_ENABLE, crtc->state->active);
- if (drm_atomic_helper_damage_merged(old_state, state, &damage)) {
- if (gdrm->flags & GUD_DISPLAY_FLAG_FULL_UPDATE)
- drm_rect_init(&damage, 0, 0, fb->width, fb->height);
- gud_fb_queue_damage(gdrm, fb, &damage);
- if (!gud_async_flush)
- flush_work(&gdrm->work);
- }
+ if (!fb)
+ goto ctrl_disable;
+
+ ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE);
+ if (ret)
+ goto ctrl_disable;
+
+ if (drm_atomic_helper_damage_merged(old_state, state, &damage))
+ gud_fb_handle_damage(gdrm, fb, &shadow_plane_state->data[0], &damage);
+
+ drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
+ctrl_disable:
if (!crtc->state->enable)
gud_usb_set_u8(gdrm, GUD_REQ_SET_CONTROLLER_ENABLE, 0);
diff --git a/drivers/gpu/drm/hisilicon/hibmc/Kconfig b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
index 4e41c144a290..126504318a4f 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/Kconfig
+++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
@@ -7,6 +7,8 @@ config DRM_HISI_HIBMC
select DRM_VRAM_HELPER
select DRM_TTM
select DRM_TTM_HELPER
+ select I2C
+ select I2C_ALGOBIT
help
Choose this option if you have a Hisilicon Hibmc soc chipset.
If M is selected the module will be called hibmc-drm.
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
index 22053c613644..0c4aa4d9b0a7 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -106,7 +106,7 @@ static int hibmc_kms_init(struct hibmc_drm_private *priv)
dev->mode_config.max_width = 1920;
dev->mode_config.max_height = 1200;
- dev->mode_config.preferred_depth = 32;
+ dev->mode_config.preferred_depth = 24;
dev->mode_config.prefer_shadow = 1;
dev->mode_config.funcs = (void *)&hibmc_mode_funcs;
@@ -340,7 +340,7 @@ static int hibmc_pci_probe(struct pci_dev *pdev,
goto err_unload;
}
- drm_fbdev_generic_setup(dev, dev->mode_config.preferred_depth);
+ drm_fbdev_generic_setup(dev, 32);
return 0;
diff --git a/drivers/gpu/drm/i2c/ch7006_drv.c b/drivers/gpu/drm/i2c/ch7006_drv.c
index 578b738859b9..521bdf656cca 100644
--- a/drivers/gpu/drm/i2c/ch7006_drv.c
+++ b/drivers/gpu/drm/i2c/ch7006_drv.c
@@ -26,6 +26,8 @@
#include <linux/module.h>
+#include <drm/drm_crtc_helper.h>
+
#include "ch7006_priv.h"
/* DRM encoder functions */
@@ -250,7 +252,7 @@ static int ch7006_encoder_create_resources(struct drm_encoder *encoder,
struct drm_device *dev = encoder->dev;
struct drm_mode_config *conf = &dev->mode_config;
- drm_mode_create_tv_properties(dev, NUM_TV_NORMS, ch7006_tv_norm_names);
+ drm_mode_create_tv_properties_legacy(dev, NUM_TV_NORMS, ch7006_tv_norm_names);
priv->scale_property = drm_property_create_range(dev, 0, "scale", 0, 2);
if (!priv->scale_property)
@@ -264,8 +266,8 @@ static int ch7006_encoder_create_resources(struct drm_encoder *encoder,
priv->hmargin);
drm_object_attach_property(&connector->base, conf->tv_bottom_margin_property,
priv->vmargin);
- drm_object_attach_property(&connector->base, conf->tv_mode_property,
- priv->norm);
+ drm_object_attach_property(&connector->base, conf->legacy_tv_mode_property,
+ priv->norm);
drm_object_attach_property(&connector->base, conf->tv_brightness_property,
priv->brightness);
drm_object_attach_property(&connector->base, conf->tv_contrast_property,
@@ -315,7 +317,7 @@ static int ch7006_encoder_set_property(struct drm_encoder *encoder,
ch7006_load_reg(client, state, CH7006_POV);
ch7006_load_reg(client, state, CH7006_VPOS);
- } else if (property == conf->tv_mode_property) {
+ } else if (property == conf->legacy_tv_mode_property) {
if (connector->dpms != DRM_MODE_DPMS_OFF)
return -EINVAL;
@@ -386,7 +388,7 @@ static const struct drm_encoder_slave_funcs ch7006_encoder_funcs = {
/* I2C driver functions */
-static int ch7006_probe(struct i2c_client *client, const struct i2c_device_id *id)
+static int ch7006_probe(struct i2c_client *client)
{
uint8_t addr = CH7006_VERSION_ID;
uint8_t val;
@@ -495,7 +497,7 @@ static const struct dev_pm_ops ch7006_pm_ops = {
static struct drm_i2c_encoder_driver ch7006_driver = {
.i2c_driver = {
- .probe = ch7006_probe,
+ .probe_new = ch7006_probe,
.remove = ch7006_remove,
.driver = {
diff --git a/drivers/gpu/drm/i2c/ch7006_priv.h b/drivers/gpu/drm/i2c/ch7006_priv.h
index 986b04599906..052bdc48a339 100644
--- a/drivers/gpu/drm/i2c/ch7006_priv.h
+++ b/drivers/gpu/drm/i2c/ch7006_priv.h
@@ -27,7 +27,6 @@
#ifndef __DRM_I2C_CH7006_PRIV_H__
#define __DRM_I2C_CH7006_PRIV_H__
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_encoder_slave.h>
#include <drm/drm_probe_helper.h>
#include <drm/i2c/ch7006.h>
diff --git a/drivers/gpu/drm/i2c/sil164_drv.c b/drivers/gpu/drm/i2c/sil164_drv.c
index 1bc0b5de4499..f57f9a807542 100644
--- a/drivers/gpu/drm/i2c/sil164_drv.c
+++ b/drivers/gpu/drm/i2c/sil164_drv.c
@@ -350,7 +350,7 @@ static const struct drm_encoder_slave_funcs sil164_encoder_funcs = {
/* I2C driver functions */
static int
-sil164_probe(struct i2c_client *client, const struct i2c_device_id *id)
+sil164_probe(struct i2c_client *client)
{
int vendor = sil164_read(client, SIL164_VENDOR_HI) << 8 |
sil164_read(client, SIL164_VENDOR_LO);
@@ -420,7 +420,7 @@ MODULE_DEVICE_TABLE(i2c, sil164_ids);
static struct drm_i2c_encoder_driver sil164_driver = {
.i2c_driver = {
- .probe = sil164_probe,
+ .probe_new = sil164_probe,
.driver = {
.name = "sil164",
},
diff --git a/drivers/gpu/drm/i2c/tda9950.c b/drivers/gpu/drm/i2c/tda9950.c
index 9ed54e7ccff2..b8c143e573e0 100644
--- a/drivers/gpu/drm/i2c/tda9950.c
+++ b/drivers/gpu/drm/i2c/tda9950.c
@@ -375,8 +375,7 @@ static void tda9950_cec_del(void *data)
cec_delete_adapter(priv->adap);
}
-static int tda9950_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int tda9950_probe(struct i2c_client *client)
{
struct tda9950_glue *glue = client->dev.platform_data;
struct device *dev = &client->dev;
@@ -493,7 +492,7 @@ static struct i2c_device_id tda9950_ids[] = {
MODULE_DEVICE_TABLE(i2c, tda9950_ids);
static struct i2c_driver tda9950_driver = {
- .probe = tda9950_probe,
+ .probe_new = tda9950_probe,
.remove = tda9950_remove,
.driver = {
.name = "tda9950",
diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c
index a14d2896aebb..db5c9343a3d2 100644
--- a/drivers/gpu/drm/i2c/tda998x_drv.c
+++ b/drivers/gpu/drm/i2c/tda998x_drv.c
@@ -2059,7 +2059,7 @@ static const struct component_ops tda998x_ops = {
};
static int
-tda998x_probe(struct i2c_client *client, const struct i2c_device_id *id)
+tda998x_probe(struct i2c_client *client)
{
int ret;
@@ -2099,7 +2099,7 @@ static const struct i2c_device_id tda998x_ids[] = {
MODULE_DEVICE_TABLE(i2c, tda998x_ids);
static struct i2c_driver tda998x_driver = {
- .probe = tda998x_probe,
+ .probe_new = tda998x_probe,
.remove = tda998x_remove,
.driver = {
.name = "tda998x",
diff --git a/drivers/gpu/drm/i810/Makefile b/drivers/gpu/drm/i810/Makefile
deleted file mode 100644
index c181f8528c5c..000000000000
--- a/drivers/gpu/drm/i810/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Makefile for the drm device driver. This driver provides support for the
-# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
-
-i810-y := i810_drv.o i810_dma.o
-
-obj-$(CONFIG_DRM_I810) += i810.o
diff --git a/drivers/gpu/drm/i810/i810_dma.c b/drivers/gpu/drm/i810/i810_dma.c
deleted file mode 100644
index 9fb4dd63342f..000000000000
--- a/drivers/gpu/drm/i810/i810_dma.c
+++ /dev/null
@@ -1,1266 +0,0 @@
-/* i810_dma.c -- DMA support for the i810 -*- linux-c -*-
- * Created: Mon Dec 13 01:50:01 1999 by jhartmann@precisioninsight.com
- *
- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software 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 (including the next
- * paragraph) 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
- * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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.
- *
- * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
- * Jeff Hartmann <jhartmann@valinux.com>
- * Keith Whitwell <keith@tungstengraphics.com>
- *
- */
-
-#include <linux/delay.h>
-#include <linux/mman.h>
-#include <linux/pci.h>
-
-#include <drm/drm_device.h>
-#include <drm/drm_drv.h>
-#include <drm/drm_file.h>
-#include <drm/drm_ioctl.h>
-#include <drm/drm_print.h>
-#include <drm/i810_drm.h>
-
-#include "i810_drv.h"
-
-#define I810_BUF_FREE 2
-#define I810_BUF_CLIENT 1
-#define I810_BUF_HARDWARE 0
-
-#define I810_BUF_UNMAPPED 0
-#define I810_BUF_MAPPED 1
-
-static struct drm_buf *i810_freelist_get(struct drm_device * dev)
-{
- struct drm_device_dma *dma = dev->dma;
- int i;
- int used;
-
- /* Linear search might not be the best solution */
-
- for (i = 0; i < dma->buf_count; i++) {
- struct drm_buf *buf = dma->buflist[i];
- drm_i810_buf_priv_t *buf_priv = buf->dev_private;
- /* In use is already a pointer */
- used = cmpxchg(buf_priv->in_use, I810_BUF_FREE,
- I810_BUF_CLIENT);
- if (used == I810_BUF_FREE)
- return buf;
- }
- return NULL;
-}
-
-/* This should only be called if the buffer is not sent to the hardware
- * yet, the hardware updates in use for us once its on the ring buffer.
- */
-
-static int i810_freelist_put(struct drm_device *dev, struct drm_buf *buf)
-{
- drm_i810_buf_priv_t *buf_priv = buf->dev_private;
- int used;
-
- /* In use is already a pointer */
- used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, I810_BUF_FREE);
- if (used != I810_BUF_CLIENT) {
- DRM_ERROR("Freeing buffer thats not in use : %d\n", buf->idx);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
-{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev;
- drm_i810_private_t *dev_priv;
- struct drm_buf *buf;
- drm_i810_buf_priv_t *buf_priv;
-
- dev = priv->minor->dev;
- dev_priv = dev->dev_private;
- buf = dev_priv->mmap_buffer;
- buf_priv = buf->dev_private;
-
- vma->vm_flags |= VM_DONTCOPY;
-
- buf_priv->currently_mapped = I810_BUF_MAPPED;
-
- if (io_remap_pfn_range(vma, vma->vm_start,
- vma->vm_pgoff,
- vma->vm_end - vma->vm_start, vma->vm_page_prot))
- return -EAGAIN;
- return 0;
-}
-
-static const struct file_operations i810_buffer_fops = {
- .open = drm_open,
- .release = drm_release,
- .unlocked_ioctl = drm_ioctl,
- .mmap = i810_mmap_buffers,
- .compat_ioctl = drm_compat_ioctl,
- .llseek = noop_llseek,
-};
-
-static int i810_map_buffer(struct drm_buf *buf, struct drm_file *file_priv)
-{
- struct drm_device *dev = file_priv->minor->dev;
- drm_i810_buf_priv_t *buf_priv = buf->dev_private;
- drm_i810_private_t *dev_priv = dev->dev_private;
- const struct file_operations *old_fops;
- int retcode = 0;
-
- if (buf_priv->currently_mapped == I810_BUF_MAPPED)
- return -EINVAL;
-
- /* This is all entirely broken */
- old_fops = file_priv->filp->f_op;
- file_priv->filp->f_op = &i810_buffer_fops;
- dev_priv->mmap_buffer = buf;
- buf_priv->virtual = (void *)vm_mmap(file_priv->filp, 0, buf->total,
- PROT_READ | PROT_WRITE,
- MAP_SHARED, buf->bus_address);
- dev_priv->mmap_buffer = NULL;
- file_priv->filp->f_op = old_fops;
- if (IS_ERR(buf_priv->virtual)) {
- /* Real error */
- DRM_ERROR("mmap error\n");
- retcode = PTR_ERR(buf_priv->virtual);
- buf_priv->virtual = NULL;
- }
-
- return retcode;
-}
-
-static int i810_unmap_buffer(struct drm_buf *buf)
-{
- drm_i810_buf_priv_t *buf_priv = buf->dev_private;
- int retcode = 0;
-
- if (buf_priv->currently_mapped != I810_BUF_MAPPED)
- return -EINVAL;
-
- retcode = vm_munmap((unsigned long)buf_priv->virtual,
- (size_t) buf->total);
-
- buf_priv->currently_mapped = I810_BUF_UNMAPPED;
- buf_priv->virtual = NULL;
-
- return retcode;
-}
-
-static int i810_dma_get_buffer(struct drm_device *dev, drm_i810_dma_t *d,
- struct drm_file *file_priv)
-{
- struct drm_buf *buf;
- drm_i810_buf_priv_t *buf_priv;
- int retcode = 0;
-
- buf = i810_freelist_get(dev);
- if (!buf) {
- retcode = -ENOMEM;
- DRM_DEBUG("retcode=%d\n", retcode);
- return retcode;
- }
-
- retcode = i810_map_buffer(buf, file_priv);
- if (retcode) {
- i810_freelist_put(dev, buf);
- DRM_ERROR("mapbuf failed, retcode %d\n", retcode);
- return retcode;
- }
- buf->file_priv = file_priv;
- buf_priv = buf->dev_private;
- d->granted = 1;
- d->request_idx = buf->idx;
- d->request_size = buf->total;
- d->virtual = buf_priv->virtual;
-
- return retcode;
-}
-
-static int i810_dma_cleanup(struct drm_device *dev)
-{
- struct drm_device_dma *dma = dev->dma;
-
- /* Make sure interrupts are disabled here because the uninstall ioctl
- * may not have been called from userspace and after dev_private
- * is freed, it's too late.
- */
- if (drm_core_check_feature(dev, DRIVER_HAVE_IRQ) && dev->irq_enabled)
- drm_legacy_irq_uninstall(dev);
-
- if (dev->dev_private) {
- int i;
- drm_i810_private_t *dev_priv =
- (drm_i810_private_t *) dev->dev_private;
-
- if (dev_priv->ring.virtual_start)
- drm_legacy_ioremapfree(&dev_priv->ring.map, dev);
- if (dev_priv->hw_status_page) {
- dma_free_coherent(dev->dev, PAGE_SIZE,
- dev_priv->hw_status_page,
- dev_priv->dma_status_page);
- }
- kfree(dev->dev_private);
- dev->dev_private = NULL;
-
- for (i = 0; i < dma->buf_count; i++) {
- struct drm_buf *buf = dma->buflist[i];
- drm_i810_buf_priv_t *buf_priv = buf->dev_private;
-
- if (buf_priv->kernel_virtual && buf->total)
- drm_legacy_ioremapfree(&buf_priv->map, dev);
- }
- }
- return 0;
-}
-
-static int i810_wait_ring(struct drm_device *dev, int n)
-{
- drm_i810_private_t *dev_priv = dev->dev_private;
- drm_i810_ring_buffer_t *ring = &(dev_priv->ring);
- int iters = 0;
- unsigned long end;
- unsigned int last_head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
-
- end = jiffies + (HZ * 3);
- while (ring->space < n) {
- ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
- ring->space = ring->head - (ring->tail + 8);
- if (ring->space < 0)
- ring->space += ring->Size;
-
- if (ring->head != last_head) {
- end = jiffies + (HZ * 3);
- last_head = ring->head;
- }
-
- iters++;
- if (time_before(end, jiffies)) {
- DRM_ERROR("space: %d wanted %d\n", ring->space, n);
- DRM_ERROR("lockup\n");
- goto out_wait_ring;
- }
- udelay(1);
- }
-
-out_wait_ring:
- return iters;
-}
-
-static void i810_kernel_lost_context(struct drm_device *dev)
-{
- drm_i810_private_t *dev_priv = dev->dev_private;
- drm_i810_ring_buffer_t *ring = &(dev_priv->ring);
-
- ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
- ring->tail = I810_READ(LP_RING + RING_TAIL);
- ring->space = ring->head - (ring->tail + 8);
- if (ring->space < 0)
- ring->space += ring->Size;
-}
-
-static int i810_freelist_init(struct drm_device *dev, drm_i810_private_t *dev_priv)
-{
- struct drm_device_dma *dma = dev->dma;
- int my_idx = 24;
- u32 *hw_status = (u32 *) (dev_priv->hw_status_page + my_idx);
- int i;
-
- if (dma->buf_count > 1019) {
- /* Not enough space in the status page for the freelist */
- return -EINVAL;
- }
-
- for (i = 0; i < dma->buf_count; i++) {
- struct drm_buf *buf = dma->buflist[i];
- drm_i810_buf_priv_t *buf_priv = buf->dev_private;
-
- buf_priv->in_use = hw_status++;
- buf_priv->my_use_idx = my_idx;
- my_idx += 4;
-
- *buf_priv->in_use = I810_BUF_FREE;
-
- buf_priv->map.offset = buf->bus_address;
- buf_priv->map.size = buf->total;
- buf_priv->map.type = _DRM_AGP;
- buf_priv->map.flags = 0;
- buf_priv->map.mtrr = 0;
-
- drm_legacy_ioremap(&buf_priv->map, dev);
- buf_priv->kernel_virtual = buf_priv->map.handle;
-
- }
- return 0;
-}
-
-static int i810_dma_initialize(struct drm_device *dev,
- drm_i810_private_t *dev_priv,
- drm_i810_init_t *init)
-{
- struct drm_map_list *r_list;
- memset(dev_priv, 0, sizeof(drm_i810_private_t));
-
- list_for_each_entry(r_list, &dev->maplist, head) {
- if (r_list->map &&
- r_list->map->type == _DRM_SHM &&
- r_list->map->flags & _DRM_CONTAINS_LOCK) {
- dev_priv->sarea_map = r_list->map;
- break;
- }
- }
- if (!dev_priv->sarea_map) {
- dev->dev_private = (void *)dev_priv;
- i810_dma_cleanup(dev);
- DRM_ERROR("can not find sarea!\n");
- return -EINVAL;
- }
- dev_priv->mmio_map = drm_legacy_findmap(dev, init->mmio_offset);
- if (!dev_priv->mmio_map) {
- dev->dev_private = (void *)dev_priv;
- i810_dma_cleanup(dev);
- DRM_ERROR("can not find mmio map!\n");
- return -EINVAL;
- }
- dev->agp_buffer_token = init->buffers_offset;
- dev->agp_buffer_map = drm_legacy_findmap(dev, init->buffers_offset);
- if (!dev->agp_buffer_map) {
- dev->dev_private = (void *)dev_priv;
- i810_dma_cleanup(dev);
- DRM_ERROR("can not find dma buffer map!\n");
- return -EINVAL;
- }
-
- dev_priv->sarea_priv = (drm_i810_sarea_t *)
- ((u8 *) dev_priv->sarea_map->handle + init->sarea_priv_offset);
-
- dev_priv->ring.Start = init->ring_start;
- dev_priv->ring.End = init->ring_end;
- dev_priv->ring.Size = init->ring_size;
-
- dev_priv->ring.map.offset = dev->agp->base + init->ring_start;
- dev_priv->ring.map.size = init->ring_size;
- dev_priv->ring.map.type = _DRM_AGP;
- dev_priv->ring.map.flags = 0;
- dev_priv->ring.map.mtrr = 0;
-
- drm_legacy_ioremap(&dev_priv->ring.map, dev);
-
- if (dev_priv->ring.map.handle == NULL) {
- dev->dev_private = (void *)dev_priv;
- i810_dma_cleanup(dev);
- DRM_ERROR("can not ioremap virtual address for"
- " ring buffer\n");
- return -ENOMEM;
- }
-
- dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
-
- dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
-
- dev_priv->w = init->w;
- dev_priv->h = init->h;
- dev_priv->pitch = init->pitch;
- dev_priv->back_offset = init->back_offset;
- dev_priv->depth_offset = init->depth_offset;
- dev_priv->front_offset = init->front_offset;
-
- dev_priv->overlay_offset = init->overlay_offset;
- dev_priv->overlay_physical = init->overlay_physical;
-
- dev_priv->front_di1 = init->front_offset | init->pitch_bits;
- dev_priv->back_di1 = init->back_offset | init->pitch_bits;
- dev_priv->zi1 = init->depth_offset | init->pitch_bits;
-
- /* Program Hardware Status Page */
- dev_priv->hw_status_page =
- dma_alloc_coherent(dev->dev, PAGE_SIZE,
- &dev_priv->dma_status_page, GFP_KERNEL);
- if (!dev_priv->hw_status_page) {
- dev->dev_private = (void *)dev_priv;
- i810_dma_cleanup(dev);
- DRM_ERROR("Can not allocate hardware status page\n");
- return -ENOMEM;
- }
- DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
-
- I810_WRITE(0x02080, dev_priv->dma_status_page);
- DRM_DEBUG("Enabled hardware status page\n");
-
- /* Now we need to init our freelist */
- if (i810_freelist_init(dev, dev_priv) != 0) {
- dev->dev_private = (void *)dev_priv;
- i810_dma_cleanup(dev);
- DRM_ERROR("Not enough space in the status page for"
- " the freelist\n");
- return -ENOMEM;
- }
- dev->dev_private = (void *)dev_priv;
-
- return 0;
-}
-
-static int i810_dma_init(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- drm_i810_private_t *dev_priv;
- drm_i810_init_t *init = data;
- int retcode = 0;
-
- switch (init->func) {
- case I810_INIT_DMA_1_4:
- DRM_INFO("Using v1.4 init.\n");
- dev_priv = kmalloc(sizeof(drm_i810_private_t), GFP_KERNEL);
- if (dev_priv == NULL)
- return -ENOMEM;
- retcode = i810_dma_initialize(dev, dev_priv, init);
- break;
-
- case I810_CLEANUP_DMA:
- DRM_INFO("DMA Cleanup\n");
- retcode = i810_dma_cleanup(dev);
- break;
- default:
- return -EINVAL;
- }
-
- return retcode;
-}
-
-/* Most efficient way to verify state for the i810 is as it is
- * emitted. Non-conformant state is silently dropped.
- *
- * Use 'volatile' & local var tmp to force the emitted values to be
- * identical to the verified ones.
- */
-static void i810EmitContextVerified(struct drm_device *dev,
- volatile unsigned int *code)
-{
- drm_i810_private_t *dev_priv = dev->dev_private;
- int i, j = 0;
- unsigned int tmp;
- RING_LOCALS;
-
- BEGIN_LP_RING(I810_CTX_SETUP_SIZE);
-
- OUT_RING(GFX_OP_COLOR_FACTOR);
- OUT_RING(code[I810_CTXREG_CF1]);
-
- OUT_RING(GFX_OP_STIPPLE);
- OUT_RING(code[I810_CTXREG_ST1]);
-
- for (i = 4; i < I810_CTX_SETUP_SIZE; i++) {
- tmp = code[i];
-
- if ((tmp & (7 << 29)) == (3 << 29) &&
- (tmp & (0x1f << 24)) < (0x1d << 24)) {
- OUT_RING(tmp);
- j++;
- } else
- printk("constext state dropped!!!\n");
- }
-
- if (j & 1)
- OUT_RING(0);
-
- ADVANCE_LP_RING();
-}
-
-static void i810EmitTexVerified(struct drm_device *dev, volatile unsigned int *code)
-{
- drm_i810_private_t *dev_priv = dev->dev_private;
- int i, j = 0;
- unsigned int tmp;
- RING_LOCALS;
-
- BEGIN_LP_RING(I810_TEX_SETUP_SIZE);
-
- OUT_RING(GFX_OP_MAP_INFO);
- OUT_RING(code[I810_TEXREG_MI1]);
- OUT_RING(code[I810_TEXREG_MI2]);
- OUT_RING(code[I810_TEXREG_MI3]);
-
- for (i = 4; i < I810_TEX_SETUP_SIZE; i++) {
- tmp = code[i];
-
- if ((tmp & (7 << 29)) == (3 << 29) &&
- (tmp & (0x1f << 24)) < (0x1d << 24)) {
- OUT_RING(tmp);
- j++;
- } else
- printk("texture state dropped!!!\n");
- }
-
- if (j & 1)
- OUT_RING(0);
-
- ADVANCE_LP_RING();
-}
-
-/* Need to do some additional checking when setting the dest buffer.
- */
-static void i810EmitDestVerified(struct drm_device *dev,
- volatile unsigned int *code)
-{
- drm_i810_private_t *dev_priv = dev->dev_private;
- unsigned int tmp;
- RING_LOCALS;
-
- BEGIN_LP_RING(I810_DEST_SETUP_SIZE + 2);
-
- tmp = code[I810_DESTREG_DI1];
- if (tmp == dev_priv->front_di1 || tmp == dev_priv->back_di1) {
- OUT_RING(CMD_OP_DESTBUFFER_INFO);
- OUT_RING(tmp);
- } else
- DRM_DEBUG("bad di1 %x (allow %x or %x)\n",
- tmp, dev_priv->front_di1, dev_priv->back_di1);
-
- /* invarient:
- */
- OUT_RING(CMD_OP_Z_BUFFER_INFO);
- OUT_RING(dev_priv->zi1);
-
- OUT_RING(GFX_OP_DESTBUFFER_VARS);
- OUT_RING(code[I810_DESTREG_DV1]);
-
- OUT_RING(GFX_OP_DRAWRECT_INFO);
- OUT_RING(code[I810_DESTREG_DR1]);
- OUT_RING(code[I810_DESTREG_DR2]);
- OUT_RING(code[I810_DESTREG_DR3]);
- OUT_RING(code[I810_DESTREG_DR4]);
- OUT_RING(0);
-
- ADVANCE_LP_RING();
-}
-
-static void i810EmitState(struct drm_device *dev)
-{
- drm_i810_private_t *dev_priv = dev->dev_private;
- drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
- unsigned int dirty = sarea_priv->dirty;
-
- DRM_DEBUG("%x\n", dirty);
-
- if (dirty & I810_UPLOAD_BUFFERS) {
- i810EmitDestVerified(dev, sarea_priv->BufferState);
- sarea_priv->dirty &= ~I810_UPLOAD_BUFFERS;
- }
-
- if (dirty & I810_UPLOAD_CTX) {
- i810EmitContextVerified(dev, sarea_priv->ContextState);
- sarea_priv->dirty &= ~I810_UPLOAD_CTX;
- }
-
- if (dirty & I810_UPLOAD_TEX0) {
- i810EmitTexVerified(dev, sarea_priv->TexState[0]);
- sarea_priv->dirty &= ~I810_UPLOAD_TEX0;
- }
-
- if (dirty & I810_UPLOAD_TEX1) {
- i810EmitTexVerified(dev, sarea_priv->TexState[1]);
- sarea_priv->dirty &= ~I810_UPLOAD_TEX1;
- }
-}
-
-/* need to verify
- */
-static void i810_dma_dispatch_clear(struct drm_device *dev, int flags,
- unsigned int clear_color,
- unsigned int clear_zval)
-{
- drm_i810_private_t *dev_priv = dev->dev_private;
- drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
- int nbox = sarea_priv->nbox;
- struct drm_clip_rect *pbox = sarea_priv->boxes;
- int pitch = dev_priv->pitch;
- int cpp = 2;
- int i;
- RING_LOCALS;
-
- if (dev_priv->current_page == 1) {
- unsigned int tmp = flags;
-
- flags &= ~(I810_FRONT | I810_BACK);
- if (tmp & I810_FRONT)
- flags |= I810_BACK;
- if (tmp & I810_BACK)
- flags |= I810_FRONT;
- }
-
- i810_kernel_lost_context(dev);
-
- if (nbox > I810_NR_SAREA_CLIPRECTS)
- nbox = I810_NR_SAREA_CLIPRECTS;
-
- for (i = 0; i < nbox; i++, pbox++) {
- unsigned int x = pbox->x1;
- unsigned int y = pbox->y1;
- unsigned int width = (pbox->x2 - x) * cpp;
- unsigned int height = pbox->y2 - y;
- unsigned int start = y * pitch + x * cpp;
-
- if (pbox->x1 > pbox->x2 ||
- pbox->y1 > pbox->y2 ||
- pbox->x2 > dev_priv->w || pbox->y2 > dev_priv->h)
- continue;
-
- if (flags & I810_FRONT) {
- BEGIN_LP_RING(6);
- OUT_RING(BR00_BITBLT_CLIENT | BR00_OP_COLOR_BLT | 0x3);
- OUT_RING(BR13_SOLID_PATTERN | (0xF0 << 16) | pitch);
- OUT_RING((height << 16) | width);
- OUT_RING(start);
- OUT_RING(clear_color);
- OUT_RING(0);
- ADVANCE_LP_RING();
- }
-
- if (flags & I810_BACK) {
- BEGIN_LP_RING(6);
- OUT_RING(BR00_BITBLT_CLIENT | BR00_OP_COLOR_BLT | 0x3);
- OUT_RING(BR13_SOLID_PATTERN | (0xF0 << 16) | pitch);
- OUT_RING((height << 16) | width);
- OUT_RING(dev_priv->back_offset + start);
- OUT_RING(clear_color);
- OUT_RING(0);
- ADVANCE_LP_RING();
- }
-
- if (flags & I810_DEPTH) {
- BEGIN_LP_RING(6);
- OUT_RING(BR00_BITBLT_CLIENT | BR00_OP_COLOR_BLT | 0x3);
- OUT_RING(BR13_SOLID_PATTERN | (0xF0 << 16) | pitch);
- OUT_RING((height << 16) | width);
- OUT_RING(dev_priv->depth_offset + start);
- OUT_RING(clear_zval);
- OUT_RING(0);
- ADVANCE_LP_RING();
- }
- }
-}
-
-static void i810_dma_dispatch_swap(struct drm_device *dev)
-{
- drm_i810_private_t *dev_priv = dev->dev_private;
- drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
- int nbox = sarea_priv->nbox;
- struct drm_clip_rect *pbox = sarea_priv->boxes;
- int pitch = dev_priv->pitch;
- int cpp = 2;
- int i;
- RING_LOCALS;
-
- DRM_DEBUG("swapbuffers\n");
-
- i810_kernel_lost_context(dev);
-
- if (nbox > I810_NR_SAREA_CLIPRECTS)
- nbox = I810_NR_SAREA_CLIPRECTS;
-
- for (i = 0; i < nbox; i++, pbox++) {
- unsigned int w = pbox->x2 - pbox->x1;
- unsigned int h = pbox->y2 - pbox->y1;
- unsigned int dst = pbox->x1 * cpp + pbox->y1 * pitch;
- unsigned int start = dst;
-
- if (pbox->x1 > pbox->x2 ||
- pbox->y1 > pbox->y2 ||
- pbox->x2 > dev_priv->w || pbox->y2 > dev_priv->h)
- continue;
-
- BEGIN_LP_RING(6);
- OUT_RING(BR00_BITBLT_CLIENT | BR00_OP_SRC_COPY_BLT | 0x4);
- OUT_RING(pitch | (0xCC << 16));
- OUT_RING((h << 16) | (w * cpp));
- if (dev_priv->current_page == 0)
- OUT_RING(dev_priv->front_offset + start);
- else
- OUT_RING(dev_priv->back_offset + start);
- OUT_RING(pitch);
- if (dev_priv->current_page == 0)
- OUT_RING(dev_priv->back_offset + start);
- else
- OUT_RING(dev_priv->front_offset + start);
- ADVANCE_LP_RING();
- }
-}
-
-static void i810_dma_dispatch_vertex(struct drm_device *dev,
- struct drm_buf *buf, int discard, int used)
-{
- drm_i810_private_t *dev_priv = dev->dev_private;
- drm_i810_buf_priv_t *buf_priv = buf->dev_private;
- drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
- struct drm_clip_rect *box = sarea_priv->boxes;
- int nbox = sarea_priv->nbox;
- unsigned long address = (unsigned long)buf->bus_address;
- unsigned long start = address - dev->agp->base;
- int i = 0;
- RING_LOCALS;
-
- i810_kernel_lost_context(dev);
-
- if (nbox > I810_NR_SAREA_CLIPRECTS)
- nbox = I810_NR_SAREA_CLIPRECTS;
-
- if (used < 0 || used > 4 * 1024)
- used = 0;
-
- if (sarea_priv->dirty)
- i810EmitState(dev);
-
- if (buf_priv->currently_mapped == I810_BUF_MAPPED) {
- unsigned int prim = (sarea_priv->vertex_prim & PR_MASK);
-
- *(u32 *) buf_priv->kernel_virtual =
- ((GFX_OP_PRIMITIVE | prim | ((used / 4) - 2)));
-
- if (used & 4) {
- *(u32 *) ((char *) buf_priv->kernel_virtual + used) = 0;
- used += 4;
- }
-
- i810_unmap_buffer(buf);
- }
-
- if (used) {
- do {
- if (i < nbox) {
- BEGIN_LP_RING(4);
- OUT_RING(GFX_OP_SCISSOR | SC_UPDATE_SCISSOR |
- SC_ENABLE);
- OUT_RING(GFX_OP_SCISSOR_INFO);
- OUT_RING(box[i].x1 | (box[i].y1 << 16));
- OUT_RING((box[i].x2 -
- 1) | ((box[i].y2 - 1) << 16));
- ADVANCE_LP_RING();
- }
-
- BEGIN_LP_RING(4);
- OUT_RING(CMD_OP_BATCH_BUFFER);
- OUT_RING(start | BB1_PROTECTED);
- OUT_RING(start + used - 4);
- OUT_RING(0);
- ADVANCE_LP_RING();
-
- } while (++i < nbox);
- }
-
- if (discard) {
- dev_priv->counter++;
-
- (void)cmpxchg(buf_priv->in_use, I810_BUF_CLIENT,
- I810_BUF_HARDWARE);
-
- BEGIN_LP_RING(8);
- OUT_RING(CMD_STORE_DWORD_IDX);
- OUT_RING(20);
- OUT_RING(dev_priv->counter);
- OUT_RING(CMD_STORE_DWORD_IDX);
- OUT_RING(buf_priv->my_use_idx);
- OUT_RING(I810_BUF_FREE);
- OUT_RING(CMD_REPORT_HEAD);
- OUT_RING(0);
- ADVANCE_LP_RING();
- }
-}
-
-static void i810_dma_dispatch_flip(struct drm_device *dev)
-{
- drm_i810_private_t *dev_priv = dev->dev_private;
- int pitch = dev_priv->pitch;
- RING_LOCALS;
-
- DRM_DEBUG("page=%d pfCurrentPage=%d\n",
- dev_priv->current_page,
- dev_priv->sarea_priv->pf_current_page);
-
- i810_kernel_lost_context(dev);
-
- BEGIN_LP_RING(2);
- OUT_RING(INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE);
- OUT_RING(0);
- ADVANCE_LP_RING();
-
- BEGIN_LP_RING(I810_DEST_SETUP_SIZE + 2);
- /* On i815 at least ASYNC is buggy */
- /* pitch<<5 is from 11.2.8 p158,
- its the pitch / 8 then left shifted 8,
- so (pitch >> 3) << 8 */
- OUT_RING(CMD_OP_FRONTBUFFER_INFO | (pitch << 5) /*| ASYNC_FLIP */ );
- if (dev_priv->current_page == 0) {
- OUT_RING(dev_priv->back_offset);
- dev_priv->current_page = 1;
- } else {
- OUT_RING(dev_priv->front_offset);
- dev_priv->current_page = 0;
- }
- OUT_RING(0);
- ADVANCE_LP_RING();
-
- BEGIN_LP_RING(2);
- OUT_RING(CMD_OP_WAIT_FOR_EVENT | WAIT_FOR_PLANE_A_FLIP);
- OUT_RING(0);
- ADVANCE_LP_RING();
-
- /* Increment the frame counter. The client-side 3D driver must
- * throttle the framerate by waiting for this value before
- * performing the swapbuffer ioctl.
- */
- dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
-
-}
-
-static void i810_dma_quiescent(struct drm_device *dev)
-{
- drm_i810_private_t *dev_priv = dev->dev_private;
- RING_LOCALS;
-
- i810_kernel_lost_context(dev);
-
- BEGIN_LP_RING(4);
- OUT_RING(INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE);
- OUT_RING(CMD_REPORT_HEAD);
- OUT_RING(0);
- OUT_RING(0);
- ADVANCE_LP_RING();
-
- i810_wait_ring(dev, dev_priv->ring.Size - 8);
-}
-
-static void i810_flush_queue(struct drm_device *dev)
-{
- drm_i810_private_t *dev_priv = dev->dev_private;
- struct drm_device_dma *dma = dev->dma;
- int i;
- RING_LOCALS;
-
- i810_kernel_lost_context(dev);
-
- BEGIN_LP_RING(2);
- OUT_RING(CMD_REPORT_HEAD);
- OUT_RING(0);
- ADVANCE_LP_RING();
-
- i810_wait_ring(dev, dev_priv->ring.Size - 8);
-
- for (i = 0; i < dma->buf_count; i++) {
- struct drm_buf *buf = dma->buflist[i];
- drm_i810_buf_priv_t *buf_priv = buf->dev_private;
-
- int used = cmpxchg(buf_priv->in_use, I810_BUF_HARDWARE,
- I810_BUF_FREE);
-
- if (used == I810_BUF_HARDWARE)
- DRM_DEBUG("reclaimed from HARDWARE\n");
- if (used == I810_BUF_CLIENT)
- DRM_DEBUG("still on client\n");
- }
-
- return;
-}
-
-/* Must be called with the lock held */
-void i810_driver_reclaim_buffers(struct drm_device *dev,
- struct drm_file *file_priv)
-{
- struct drm_device_dma *dma = dev->dma;
- int i;
-
- if (!dma)
- return;
- if (!dev->dev_private)
- return;
- if (!dma->buflist)
- return;
-
- i810_flush_queue(dev);
-
- for (i = 0; i < dma->buf_count; i++) {
- struct drm_buf *buf = dma->buflist[i];
- drm_i810_buf_priv_t *buf_priv = buf->dev_private;
-
- if (buf->file_priv == file_priv && buf_priv) {
- int used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT,
- I810_BUF_FREE);
-
- if (used == I810_BUF_CLIENT)
- DRM_DEBUG("reclaimed from client\n");
- if (buf_priv->currently_mapped == I810_BUF_MAPPED)
- buf_priv->currently_mapped = I810_BUF_UNMAPPED;
- }
- }
-}
-
-static int i810_flush_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- i810_flush_queue(dev);
- return 0;
-}
-
-static int i810_dma_vertex(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- struct drm_device_dma *dma = dev->dma;
- drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
- u32 *hw_status = dev_priv->hw_status_page;
- drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
- dev_priv->sarea_priv;
- drm_i810_vertex_t *vertex = data;
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- DRM_DEBUG("idx %d used %d discard %d\n",
- vertex->idx, vertex->used, vertex->discard);
-
- if (vertex->idx < 0 || vertex->idx >= dma->buf_count)
- return -EINVAL;
-
- i810_dma_dispatch_vertex(dev,
- dma->buflist[vertex->idx],
- vertex->discard, vertex->used);
-
- sarea_priv->last_enqueue = dev_priv->counter - 1;
- sarea_priv->last_dispatch = (int)hw_status[5];
-
- return 0;
-}
-
-static int i810_clear_bufs(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- drm_i810_clear_t *clear = data;
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- /* GH: Someone's doing nasty things... */
- if (!dev->dev_private)
- return -EINVAL;
-
- i810_dma_dispatch_clear(dev, clear->flags,
- clear->clear_color, clear->clear_depth);
- return 0;
-}
-
-static int i810_swap_bufs(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- DRM_DEBUG("\n");
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- i810_dma_dispatch_swap(dev);
- return 0;
-}
-
-static int i810_getage(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
- u32 *hw_status = dev_priv->hw_status_page;
- drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
- dev_priv->sarea_priv;
-
- sarea_priv->last_dispatch = (int)hw_status[5];
- return 0;
-}
-
-static int i810_getbuf(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- int retcode = 0;
- drm_i810_dma_t *d = data;
- drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
- u32 *hw_status = dev_priv->hw_status_page;
- drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
- dev_priv->sarea_priv;
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- d->granted = 0;
-
- retcode = i810_dma_get_buffer(dev, d, file_priv);
-
- DRM_DEBUG("i810_dma: %d returning %d, granted = %d\n",
- task_pid_nr(current), retcode, d->granted);
-
- sarea_priv->last_dispatch = (int)hw_status[5];
-
- return retcode;
-}
-
-static int i810_copybuf(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- /* Never copy - 2.4.x doesn't need it */
- return 0;
-}
-
-static int i810_docopy(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- /* Never copy - 2.4.x doesn't need it */
- return 0;
-}
-
-static void i810_dma_dispatch_mc(struct drm_device *dev, struct drm_buf *buf, int used,
- unsigned int last_render)
-{
- drm_i810_private_t *dev_priv = dev->dev_private;
- drm_i810_buf_priv_t *buf_priv = buf->dev_private;
- drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
- unsigned long address = (unsigned long)buf->bus_address;
- unsigned long start = address - dev->agp->base;
- int u;
- RING_LOCALS;
-
- i810_kernel_lost_context(dev);
-
- u = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, I810_BUF_HARDWARE);
- if (u != I810_BUF_CLIENT)
- DRM_DEBUG("MC found buffer that isn't mine!\n");
-
- if (used < 0 || used > 4 * 1024)
- used = 0;
-
- sarea_priv->dirty = 0x7f;
-
- DRM_DEBUG("addr 0x%lx, used 0x%x\n", address, used);
-
- dev_priv->counter++;
- DRM_DEBUG("dispatch counter : %ld\n", dev_priv->counter);
- DRM_DEBUG("start : %lx\n", start);
- DRM_DEBUG("used : %d\n", used);
- DRM_DEBUG("start + used - 4 : %ld\n", start + used - 4);
-
- if (buf_priv->currently_mapped == I810_BUF_MAPPED) {
- if (used & 4) {
- *(u32 *) ((char *) buf_priv->virtual + used) = 0;
- used += 4;
- }
-
- i810_unmap_buffer(buf);
- }
- BEGIN_LP_RING(4);
- OUT_RING(CMD_OP_BATCH_BUFFER);
- OUT_RING(start | BB1_PROTECTED);
- OUT_RING(start + used - 4);
- OUT_RING(0);
- ADVANCE_LP_RING();
-
- BEGIN_LP_RING(8);
- OUT_RING(CMD_STORE_DWORD_IDX);
- OUT_RING(buf_priv->my_use_idx);
- OUT_RING(I810_BUF_FREE);
- OUT_RING(0);
-
- OUT_RING(CMD_STORE_DWORD_IDX);
- OUT_RING(16);
- OUT_RING(last_render);
- OUT_RING(0);
- ADVANCE_LP_RING();
-}
-
-static int i810_dma_mc(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- struct drm_device_dma *dma = dev->dma;
- drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
- u32 *hw_status = dev_priv->hw_status_page;
- drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
- dev_priv->sarea_priv;
- drm_i810_mc_t *mc = data;
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- if (mc->idx >= dma->buf_count || mc->idx < 0)
- return -EINVAL;
-
- i810_dma_dispatch_mc(dev, dma->buflist[mc->idx], mc->used,
- mc->last_render);
-
- sarea_priv->last_enqueue = dev_priv->counter - 1;
- sarea_priv->last_dispatch = (int)hw_status[5];
-
- return 0;
-}
-
-static int i810_rstatus(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
-
- return (int)(((u32 *) (dev_priv->hw_status_page))[4]);
-}
-
-static int i810_ov0_info(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
- drm_i810_overlay_t *ov = data;
-
- ov->offset = dev_priv->overlay_offset;
- ov->physical = dev_priv->overlay_physical;
-
- return 0;
-}
-
-static int i810_fstatus(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
- return I810_READ(0x30008);
-}
-
-static int i810_ov0_flip(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- /* Tell the overlay to update */
- I810_WRITE(0x30000, dev_priv->overlay_physical | 0x80000000);
-
- return 0;
-}
-
-/* Not sure why this isn't set all the time:
- */
-static void i810_do_init_pageflip(struct drm_device *dev)
-{
- drm_i810_private_t *dev_priv = dev->dev_private;
-
- DRM_DEBUG("\n");
- dev_priv->page_flipping = 1;
- dev_priv->current_page = 0;
- dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
-}
-
-static int i810_do_cleanup_pageflip(struct drm_device *dev)
-{
- drm_i810_private_t *dev_priv = dev->dev_private;
-
- DRM_DEBUG("\n");
- if (dev_priv->current_page != 0)
- i810_dma_dispatch_flip(dev);
-
- dev_priv->page_flipping = 0;
- return 0;
-}
-
-static int i810_flip_bufs(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- drm_i810_private_t *dev_priv = dev->dev_private;
-
- DRM_DEBUG("\n");
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- if (!dev_priv->page_flipping)
- i810_do_init_pageflip(dev);
-
- i810_dma_dispatch_flip(dev);
- return 0;
-}
-
-int i810_driver_load(struct drm_device *dev, unsigned long flags)
-{
- struct pci_dev *pdev = to_pci_dev(dev->dev);
-
- dev->agp = drm_legacy_agp_init(dev);
- if (dev->agp) {
- dev->agp->agp_mtrr = arch_phys_wc_add(
- dev->agp->agp_info.aper_base,
- dev->agp->agp_info.aper_size *
- 1024 * 1024);
- }
-
- /* Our userspace depends upon the agp mapping support. */
- if (!dev->agp)
- return -EINVAL;
-
- pci_set_master(pdev);
-
- return 0;
-}
-
-void i810_driver_lastclose(struct drm_device *dev)
-{
- i810_dma_cleanup(dev);
-}
-
-void i810_driver_preclose(struct drm_device *dev, struct drm_file *file_priv)
-{
- if (dev->dev_private) {
- drm_i810_private_t *dev_priv = dev->dev_private;
- if (dev_priv->page_flipping)
- i810_do_cleanup_pageflip(dev);
- }
-
- if (file_priv->master && file_priv->master->lock.hw_lock) {
- drm_legacy_idlelock_take(&file_priv->master->lock);
- i810_driver_reclaim_buffers(dev, file_priv);
- drm_legacy_idlelock_release(&file_priv->master->lock);
- } else {
- /* master disappeared, clean up stuff anyway and hope nothing
- * goes wrong */
- i810_driver_reclaim_buffers(dev, file_priv);
- }
-
-}
-
-int i810_driver_dma_quiescent(struct drm_device *dev)
-{
- i810_dma_quiescent(dev);
- return 0;
-}
-
-const struct drm_ioctl_desc i810_ioctls[] = {
- DRM_IOCTL_DEF_DRV(I810_INIT, i810_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED),
- DRM_IOCTL_DEF_DRV(I810_VERTEX, i810_dma_vertex, DRM_AUTH|DRM_UNLOCKED),
- DRM_IOCTL_DEF_DRV(I810_CLEAR, i810_clear_bufs, DRM_AUTH|DRM_UNLOCKED),
- DRM_IOCTL_DEF_DRV(I810_FLUSH, i810_flush_ioctl, DRM_AUTH|DRM_UNLOCKED),
- DRM_IOCTL_DEF_DRV(I810_GETAGE, i810_getage, DRM_AUTH|DRM_UNLOCKED),
- DRM_IOCTL_DEF_DRV(I810_GETBUF, i810_getbuf, DRM_AUTH|DRM_UNLOCKED),
- DRM_IOCTL_DEF_DRV(I810_SWAP, i810_swap_bufs, DRM_AUTH|DRM_UNLOCKED),
- DRM_IOCTL_DEF_DRV(I810_COPY, i810_copybuf, DRM_AUTH|DRM_UNLOCKED),
- DRM_IOCTL_DEF_DRV(I810_DOCOPY, i810_docopy, DRM_AUTH|DRM_UNLOCKED),
- DRM_IOCTL_DEF_DRV(I810_OV0INFO, i810_ov0_info, DRM_AUTH|DRM_UNLOCKED),
- DRM_IOCTL_DEF_DRV(I810_FSTATUS, i810_fstatus, DRM_AUTH|DRM_UNLOCKED),
- DRM_IOCTL_DEF_DRV(I810_OV0FLIP, i810_ov0_flip, DRM_AUTH|DRM_UNLOCKED),
- DRM_IOCTL_DEF_DRV(I810_MC, i810_dma_mc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED),
- DRM_IOCTL_DEF_DRV(I810_RSTATUS, i810_rstatus, DRM_AUTH|DRM_UNLOCKED),
- DRM_IOCTL_DEF_DRV(I810_FLIP, i810_flip_bufs, DRM_AUTH|DRM_UNLOCKED),
-};
-
-int i810_max_ioctl = ARRAY_SIZE(i810_ioctls);
diff --git a/drivers/gpu/drm/i810/i810_drv.c b/drivers/gpu/drm/i810/i810_drv.c
deleted file mode 100644
index 0e53a066d4db..000000000000
--- a/drivers/gpu/drm/i810/i810_drv.c
+++ /dev/null
@@ -1,101 +0,0 @@
-/* i810_drv.c -- I810 driver -*- linux-c -*-
- * Created: Mon Dec 13 01:56:22 1999 by jhartmann@precisioninsight.com
- *
- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software 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 (including the next
- * paragraph) 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
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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.
- *
- * Authors:
- * Rickard E. (Rik) Faith <faith@valinux.com>
- * Jeff Hartmann <jhartmann@valinux.com>
- * Gareth Hughes <gareth@valinux.com>
- */
-
-#include "i810_drv.h"
-
-#include <linux/module.h>
-#include <linux/pci.h>
-
-#include <drm/drm_drv.h>
-#include <drm/drm_file.h>
-#include <drm/drm_pciids.h>
-#include <drm/i810_drm.h>
-
-
-static struct pci_device_id pciidlist[] = {
- i810_PCI_IDS
-};
-
-static const struct file_operations i810_driver_fops = {
- .owner = THIS_MODULE,
- .open = drm_open,
- .release = drm_release,
- .unlocked_ioctl = drm_ioctl,
- .mmap = drm_legacy_mmap,
- .poll = drm_poll,
- .compat_ioctl = drm_compat_ioctl,
- .llseek = noop_llseek,
-};
-
-static struct drm_driver driver = {
- .driver_features = DRIVER_USE_AGP | DRIVER_HAVE_DMA | DRIVER_LEGACY,
- .dev_priv_size = sizeof(drm_i810_buf_priv_t),
- .load = i810_driver_load,
- .lastclose = i810_driver_lastclose,
- .preclose = i810_driver_preclose,
- .dma_quiescent = i810_driver_dma_quiescent,
- .ioctls = i810_ioctls,
- .fops = &i810_driver_fops,
- .name = DRIVER_NAME,
- .desc = DRIVER_DESC,
- .date = DRIVER_DATE,
- .major = DRIVER_MAJOR,
- .minor = DRIVER_MINOR,
- .patchlevel = DRIVER_PATCHLEVEL,
-};
-
-static struct pci_driver i810_pci_driver = {
- .name = DRIVER_NAME,
- .id_table = pciidlist,
-};
-
-static int __init i810_init(void)
-{
- if (num_possible_cpus() > 1) {
- pr_err("drm/i810 does not support SMP\n");
- return -EINVAL;
- }
- driver.num_ioctls = i810_max_ioctl;
- return drm_legacy_pci_init(&driver, &i810_pci_driver);
-}
-
-static void __exit i810_exit(void)
-{
- drm_legacy_pci_exit(&driver, &i810_pci_driver);
-}
-
-module_init(i810_init);
-module_exit(i810_exit);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/gpu/drm/i810/i810_drv.h b/drivers/gpu/drm/i810/i810_drv.h
deleted file mode 100644
index 9df3981ffc66..000000000000
--- a/drivers/gpu/drm/i810/i810_drv.h
+++ /dev/null
@@ -1,246 +0,0 @@
-/* i810_drv.h -- Private header for the Matrox g200/g400 driver -*- linux-c -*-
- * Created: Mon Dec 13 01:50:01 1999 by jhartmann@precisioninsight.com
- *
- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software 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 (including the next
- * paragraph) 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
- * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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.
- *
- * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
- * Jeff Hartmann <jhartmann@valinux.com>
- *
- */
-
-#ifndef _I810_DRV_H_
-#define _I810_DRV_H_
-
-#include <drm/drm_ioctl.h>
-#include <drm/drm_legacy.h>
-#include <drm/i810_drm.h>
-
-/* General customization:
- */
-
-#define DRIVER_AUTHOR "VA Linux Systems Inc."
-
-#define DRIVER_NAME "i810"
-#define DRIVER_DESC "Intel i810"
-#define DRIVER_DATE "20030605"
-
-/* Interface history
- *
- * 1.1 - XFree86 4.1
- * 1.2 - XvMC interfaces
- * - XFree86 4.2
- * 1.2.1 - Disable copying code (leave stub ioctls for backwards compatibility)
- * - Remove requirement for interrupt (leave stubs again)
- * 1.3 - Add page flipping.
- * 1.4 - fix DRM interface
- */
-#define DRIVER_MAJOR 1
-#define DRIVER_MINOR 4
-#define DRIVER_PATCHLEVEL 0
-
-typedef struct drm_i810_buf_priv {
- u32 *in_use;
- int my_use_idx;
- int currently_mapped;
- void *virtual;
- void *kernel_virtual;
- drm_local_map_t map;
-} drm_i810_buf_priv_t;
-
-typedef struct _drm_i810_ring_buffer {
- int tail_mask;
- unsigned long Start;
- unsigned long End;
- unsigned long Size;
- u8 *virtual_start;
- int head;
- int tail;
- int space;
- drm_local_map_t map;
-} drm_i810_ring_buffer_t;
-
-typedef struct drm_i810_private {
- struct drm_local_map *sarea_map;
- struct drm_local_map *mmio_map;
-
- drm_i810_sarea_t *sarea_priv;
- drm_i810_ring_buffer_t ring;
-
- void *hw_status_page;
- unsigned long counter;
-
- dma_addr_t dma_status_page;
-
- struct drm_buf *mmap_buffer;
-
- u32 front_di1, back_di1, zi1;
-
- int back_offset;
- int depth_offset;
- int overlay_offset;
- int overlay_physical;
- int w, h;
- int pitch;
- int back_pitch;
- int depth_pitch;
-
- int do_boxes;
- int dma_used;
-
- int current_page;
- int page_flipping;
-
- wait_queue_head_t irq_queue;
- atomic_t irq_received;
- atomic_t irq_emitted;
-
- int front_offset;
-} drm_i810_private_t;
-
- /* i810_dma.c */
-extern int i810_driver_dma_quiescent(struct drm_device *dev);
-void i810_driver_reclaim_buffers(struct drm_device *dev,
- struct drm_file *file_priv);
-extern int i810_driver_load(struct drm_device *, unsigned long flags);
-extern void i810_driver_lastclose(struct drm_device *dev);
-extern void i810_driver_preclose(struct drm_device *dev,
- struct drm_file *file_priv);
-
-extern long i810_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
-extern const struct drm_ioctl_desc i810_ioctls[];
-extern int i810_max_ioctl;
-
-#define I810_BASE(reg) ((unsigned long) \
- dev_priv->mmio_map->handle)
-#define I810_ADDR(reg) (I810_BASE(reg) + reg)
-#define I810_DEREF(reg) (*(__volatile__ int *)I810_ADDR(reg))
-#define I810_READ(reg) I810_DEREF(reg)
-#define I810_WRITE(reg, val) do { I810_DEREF(reg) = val; } while (0)
-#define I810_DEREF16(reg) (*(__volatile__ u16 *)I810_ADDR(reg))
-#define I810_READ16(reg) I810_DEREF16(reg)
-#define I810_WRITE16(reg, val) do { I810_DEREF16(reg) = val; } while (0)
-
-#define I810_VERBOSE 0
-#define RING_LOCALS unsigned int outring, ringmask; \
- volatile char *virt;
-
-#define BEGIN_LP_RING(n) do { \
- if (I810_VERBOSE) \
- DRM_DEBUG("BEGIN_LP_RING(%d)\n", n); \
- if (dev_priv->ring.space < n*4) \
- i810_wait_ring(dev, n*4); \
- dev_priv->ring.space -= n*4; \
- outring = dev_priv->ring.tail; \
- ringmask = dev_priv->ring.tail_mask; \
- virt = dev_priv->ring.virtual_start; \
-} while (0)
-
-#define ADVANCE_LP_RING() do { \
- if (I810_VERBOSE) \
- DRM_DEBUG("ADVANCE_LP_RING\n"); \
- dev_priv->ring.tail = outring; \
- I810_WRITE(LP_RING + RING_TAIL, outring); \
-} while (0)
-
-#define OUT_RING(n) do { \
- if (I810_VERBOSE) \
- DRM_DEBUG(" OUT_RING %x\n", (int)(n)); \
- *(volatile unsigned int *)(virt + outring) = n; \
- outring += 4; \
- outring &= ringmask; \
-} while (0)
-
-#define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23))
-#define GFX_OP_BREAKPOINT_INTERRUPT ((0<<29)|(1<<23))
-#define CMD_REPORT_HEAD (7<<23)
-#define CMD_STORE_DWORD_IDX ((0x21<<23) | 0x1)
-#define CMD_OP_BATCH_BUFFER ((0x0<<29)|(0x30<<23)|0x1)
-
-#define INST_PARSER_CLIENT 0x00000000
-#define INST_OP_FLUSH 0x02000000
-#define INST_FLUSH_MAP_CACHE 0x00000001
-
-#define BB1_START_ADDR_MASK (~0x7)
-#define BB1_PROTECTED (1<<0)
-#define BB1_UNPROTECTED (0<<0)
-#define BB2_END_ADDR_MASK (~0x7)
-
-#define I810REG_HWSTAM 0x02098
-#define I810REG_INT_IDENTITY_R 0x020a4
-#define I810REG_INT_MASK_R 0x020a8
-#define I810REG_INT_ENABLE_R 0x020a0
-
-#define LP_RING 0x2030
-#define HP_RING 0x2040
-#define RING_TAIL 0x00
-#define TAIL_ADDR 0x000FFFF8
-#define RING_HEAD 0x04
-#define HEAD_WRAP_COUNT 0xFFE00000
-#define HEAD_WRAP_ONE 0x00200000
-#define HEAD_ADDR 0x001FFFFC
-#define RING_START 0x08
-#define START_ADDR 0x00FFFFF8
-#define RING_LEN 0x0C
-#define RING_NR_PAGES 0x000FF000
-#define RING_REPORT_MASK 0x00000006
-#define RING_REPORT_64K 0x00000002
-#define RING_REPORT_128K 0x00000004
-#define RING_NO_REPORT 0x00000000
-#define RING_VALID_MASK 0x00000001
-#define RING_VALID 0x00000001
-#define RING_INVALID 0x00000000
-
-#define GFX_OP_SCISSOR ((0x3<<29)|(0x1c<<24)|(0x10<<19))
-#define SC_UPDATE_SCISSOR (0x1<<1)
-#define SC_ENABLE_MASK (0x1<<0)
-#define SC_ENABLE (0x1<<0)
-
-#define GFX_OP_SCISSOR_INFO ((0x3<<29)|(0x1d<<24)|(0x81<<16)|(0x1))
-#define SCI_YMIN_MASK (0xffff<<16)
-#define SCI_XMIN_MASK (0xffff<<0)
-#define SCI_YMAX_MASK (0xffff<<16)
-#define SCI_XMAX_MASK (0xffff<<0)
-
-#define GFX_OP_COLOR_FACTOR ((0x3<<29)|(0x1d<<24)|(0x1<<16)|0x0)
-#define GFX_OP_STIPPLE ((0x3<<29)|(0x1d<<24)|(0x83<<16))
-#define GFX_OP_MAP_INFO ((0x3<<29)|(0x1d<<24)|0x2)
-#define GFX_OP_DESTBUFFER_VARS ((0x3<<29)|(0x1d<<24)|(0x85<<16)|0x0)
-#define GFX_OP_DRAWRECT_INFO ((0x3<<29)|(0x1d<<24)|(0x80<<16)|(0x3))
-#define GFX_OP_PRIMITIVE ((0x3<<29)|(0x1f<<24))
-
-#define CMD_OP_Z_BUFFER_INFO ((0x0<<29)|(0x16<<23))
-#define CMD_OP_DESTBUFFER_INFO ((0x0<<29)|(0x15<<23))
-#define CMD_OP_FRONTBUFFER_INFO ((0x0<<29)|(0x14<<23))
-#define CMD_OP_WAIT_FOR_EVENT ((0x0<<29)|(0x03<<23))
-
-#define BR00_BITBLT_CLIENT 0x40000000
-#define BR00_OP_COLOR_BLT 0x10000000
-#define BR00_OP_SRC_COPY_BLT 0x10C00000
-#define BR13_SOLID_PATTERN 0x80000000
-
-#define WAIT_FOR_PLANE_A_SCANLINES (1<<1)
-#define WAIT_FOR_PLANE_A_FLIP (1<<2)
-#define WAIT_FOR_VBLANK (1<<3)
-
-#endif
diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig
index 3efce05d7b57..98f4e44976e0 100644
--- a/drivers/gpu/drm/i915/Kconfig
+++ b/drivers/gpu/drm/i915/Kconfig
@@ -18,6 +18,8 @@ config DRM_I915
select DRM_PANEL
select DRM_MIPI_DSI
select RELAY
+ select I2C
+ select I2C_ALGOBIT
select IRQ_WORK
# i915 depends on ACPI_VIDEO when ACPI is enabled
# but for select to work, need to select ACPI_VIDEO's dependencies, ick
@@ -54,24 +56,33 @@ config DRM_I915
If "M" is selected, the module will be called i915.
config DRM_I915_FORCE_PROBE
- string "Force probe driver for selected new Intel hardware"
+ string "Force probe i915 for selected Intel hardware IDs"
depends on DRM_I915
help
This is the default value for the i915.force_probe module
parameter. Using the module parameter overrides this option.
- Force probe the driver for new Intel graphics devices that are
+ Force probe the i915 for Intel graphics devices that are
recognized but not properly supported by this kernel version. It is
recommended to upgrade to a kernel version with proper support as soon
as it is available.
+ It can also be used to block the probe of recognized and fully
+ supported devices.
+
Use "" to disable force probe. If in doubt, use this.
- Use "<pci-id>[,<pci-id>,...]" to force probe the driver for listed
+ Use "<pci-id>[,<pci-id>,...]" to force probe the i915 for listed
devices. For example, "4500" or "4500,4571".
Use "*" to force probe the driver for all known devices.
+ Use "!" right before the ID to block the probe of the device. For
+ example, "4500,!4571" forces the probe of 4500 and blocks the probe of
+ 4571.
+
+ Use "!*" to block the probe of the driver for all known devices.
+
config DRM_I915_CAPTURE_ERROR
bool "Enable capturing GPU state following a hang"
depends on DRM_I915
@@ -107,18 +118,16 @@ config DRM_I915_USERPTR
If in doubt, say "Y".
-config DRM_I915_GVT
- bool
-
config DRM_I915_GVT_KVMGT
tristate "Enable KVM host support Intel GVT-g graphics virtualization"
depends on DRM_I915
depends on X86
depends on 64BIT
depends on KVM
- depends on VFIO_MDEV
+ depends on VFIO
select DRM_I915_GVT
select KVM_EXTERNAL_WRITE_TRACKING
+ select VFIO_MDEV
help
Choose this option if you want to enable Intel GVT-g graphics
@@ -160,3 +169,6 @@ menu "drm/i915 Unstable Evolution"
depends on DRM_I915
source "drivers/gpu/drm/i915/Kconfig.unstable"
endmenu
+
+config DRM_I915_GVT
+ bool
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 01974b82d205..918470a04591 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -48,9 +48,7 @@ i915-y += i915_driver.o \
i915_sysfs.o \
i915_utils.o \
intel_device_info.o \
- intel_dram.o \
intel_memory_region.o \
- intel_pch.o \
intel_pcode.o \
intel_pm.o \
intel_region_ttm.o \
@@ -62,6 +60,12 @@ i915-y += i915_driver.o \
vlv_sideband.o \
vlv_suspend.o
+# core peripheral code
+i915-y += \
+ soc/intel_dram.o \
+ soc/intel_gmch.o \
+ soc/intel_pch.o
+
# core library code
i915-y += \
i915_memcpy.o \
@@ -188,9 +192,9 @@ i915-y += \
i915_vma_resource.o
# general-purpose microcontroller (GuC) support
-i915-y += gt/uc/intel_uc.o \
- gt/uc/intel_uc_debugfs.o \
- gt/uc/intel_uc_fw.o \
+i915-y += \
+ gt/uc/intel_gsc_fw.o \
+ gt/uc/intel_gsc_uc.o \
gt/uc/intel_guc.o \
gt/uc/intel_guc_ads.o \
gt/uc/intel_guc_capture.o \
@@ -205,7 +209,10 @@ i915-y += gt/uc/intel_uc.o \
gt/uc/intel_guc_submission.o \
gt/uc/intel_huc.o \
gt/uc/intel_huc_debugfs.o \
- gt/uc/intel_huc_fw.o
+ gt/uc/intel_huc_fw.o \
+ gt/uc/intel_uc.o \
+ gt/uc/intel_uc_debugfs.o \
+ gt/uc/intel_uc_fw.o
# graphics system controller (GSC) support
i915-y += gt/intel_gsc.o
@@ -260,6 +267,7 @@ i915-y += \
display/intel_quirks.o \
display/intel_sprite.o \
display/intel_tc.o \
+ display/intel_vblank.o \
display/intel_vga.o \
display/i9xx_plane.o \
display/skl_scaler.o \
diff --git a/drivers/gpu/drm/i915/display/dvo_ch7xxx.c b/drivers/gpu/drm/i915/display/dvo_ch7xxx.c
index 54f58ba44b9f..6d948520e9a6 100644
--- a/drivers/gpu/drm/i915/display/dvo_ch7xxx.c
+++ b/drivers/gpu/drm/i915/display/dvo_ch7xxx.c
@@ -50,15 +50,26 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define CH7xxx_INPUT_CLOCK 0x1d
#define CH7xxx_GPIO 0x1e
#define CH7xxx_GPIO_HPIR (1<<3)
-#define CH7xxx_IDF 0x1f
+#define CH7xxx_IDF 0x1f
+#define CH7xxx_IDF_IBS (1<<7)
+#define CH7xxx_IDF_DES (1<<6)
#define CH7xxx_IDF_HSP (1<<3)
#define CH7xxx_IDF_VSP (1<<4)
#define CH7xxx_CONNECTION_DETECT 0x20
#define CH7xxx_CDET_DVI (1<<5)
-#define CH7301_DAC_CNTL 0x21
+#define CH7xxx_DAC_CNTL 0x21
+#define CH7xxx_SYNCO_MASK (3 << 3)
+#define CH7xxx_SYNCO_VGA_HSYNC (1 << 3)
+
+#define CH7xxx_CLOCK_OUTPUT 0x22
+#define CH7xxx_BCOEN (1 << 4)
+#define CH7xxx_BCOP (1 << 3)
+#define CH7xxx_BCO_MASK (7 << 0)
+#define CH7xxx_BCO_VGA_VSYNC (6 << 0)
+
#define CH7301_HOTPLUG 0x23
#define CH7xxx_TCTL 0x31
#define CH7xxx_TVCO 0x32
@@ -301,6 +312,8 @@ static void ch7xxx_mode_set(struct intel_dvo_device *dvo,
ch7xxx_readb(dvo, CH7xxx_IDF, &idf);
+ idf |= CH7xxx_IDF_IBS;
+
idf &= ~(CH7xxx_IDF_HSP | CH7xxx_IDF_VSP);
if (mode->flags & DRM_MODE_FLAG_PHSYNC)
idf |= CH7xxx_IDF_HSP;
@@ -309,6 +322,11 @@ static void ch7xxx_mode_set(struct intel_dvo_device *dvo,
idf |= CH7xxx_IDF_VSP;
ch7xxx_writeb(dvo, CH7xxx_IDF, idf);
+
+ ch7xxx_writeb(dvo, CH7xxx_DAC_CNTL,
+ CH7xxx_SYNCO_VGA_HSYNC);
+ ch7xxx_writeb(dvo, CH7xxx_CLOCK_OUTPUT,
+ CH7xxx_BCOEN | CH7xxx_BCO_VGA_VSYNC);
}
/* set the CH7xxx power state */
diff --git a/drivers/gpu/drm/i915/display/dvo_sil164.c b/drivers/gpu/drm/i915/display/dvo_sil164.c
index 0dfa0a0209ff..4acc8ce29c0b 100644
--- a/drivers/gpu/drm/i915/display/dvo_sil164.c
+++ b/drivers/gpu/drm/i915/display/dvo_sil164.c
@@ -58,6 +58,10 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define SIL164_9_MDI (1<<0)
#define SIL164_REGC 0x0c
+#define SIL164_C_SCNT (1<<7)
+#define SIL164_C_PLLF_MASK (0xf<<1)
+#define SIL164_C_PLLF_REC (4<<1)
+#define SIL164_C_PFEN (1<<0)
struct sil164_priv {
//I2CDevRec d;
@@ -205,7 +209,13 @@ static void sil164_mode_set(struct intel_dvo_device *dvo,
sil164_writeb(sil, 0x0c, 0x89);
sil164_writeb(sil, 0x08, 0x31);*/
/* don't do much */
- return;
+
+ sil164_writeb(dvo, SIL164_REG8,
+ SIL164_8_VEN | SIL164_8_HEN);
+ sil164_writeb(dvo, SIL164_REG9,
+ SIL164_9_TSEL);
+ sil164_writeb(dvo, SIL164_REGC,
+ SIL164_C_PLLF_REC | SIL164_C_PFEN);
}
/* set the SIL164 power state */
@@ -224,7 +234,6 @@ static void sil164_dpms(struct intel_dvo_device *dvo, bool enable)
ch &= ~SIL164_8_PD;
sil164_writeb(dvo, SIL164_REG8, ch);
- return;
}
static bool sil164_get_hw_state(struct intel_dvo_device *dvo)
diff --git a/drivers/gpu/drm/i915/display/g4x_dp.c b/drivers/gpu/drm/i915/display/g4x_dp.c
index 24ef36ec2d3d..fa754038d669 100644
--- a/drivers/gpu/drm/i915/display/g4x_dp.c
+++ b/drivers/gpu/drm/i915/display/g4x_dp.c
@@ -398,6 +398,8 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
if (intel_dp_is_edp(intel_dp))
intel_edp_fixup_vbt_bpp(encoder, pipe_config->pipe_bpp);
+
+ intel_audio_codec_get_config(encoder, pipe_config);
}
static void
diff --git a/drivers/gpu/drm/i915/display/g4x_hdmi.c b/drivers/gpu/drm/i915/display/g4x_hdmi.c
index c3580d96765c..64c3b3990702 100644
--- a/drivers/gpu/drm/i915/display/g4x_hdmi.c
+++ b/drivers/gpu/drm/i915/display/g4x_hdmi.c
@@ -155,6 +155,8 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder,
intel_read_infoframe(encoder, pipe_config,
HDMI_INFOFRAME_TYPE_VENDOR,
&pipe_config->infoframes.hdmi);
+
+ intel_audio_codec_get_config(encoder, pipe_config);
}
static void g4x_hdmi_enable_port(struct intel_encoder *encoder,
diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c
index d16b30a2dded..468a792e6a40 100644
--- a/drivers/gpu/drm/i915/display/icl_dsi.c
+++ b/drivers/gpu/drm/i915/display/icl_dsi.c
@@ -2043,7 +2043,8 @@ void icl_dsi_init(struct drm_i915_private *dev_priv)
/* attach connector to encoder */
intel_connector_attach_encoder(intel_connector, encoder);
- intel_bios_init_panel(dev_priv, &intel_connector->panel, NULL, NULL);
+ encoder->devdata = intel_bios_encoder_data_lookup(dev_priv, port);
+ intel_bios_init_panel_late(dev_priv, &intel_connector->panel, encoder->devdata, NULL);
mutex_lock(&dev_priv->drm.mode_config.mutex);
intel_panel_add_vbt_lfp_fixed_mode(intel_connector);
@@ -2054,7 +2055,7 @@ void icl_dsi_init(struct drm_i915_private *dev_priv)
goto err;
}
- intel_panel_init(intel_connector);
+ intel_panel_init(intel_connector, NULL);
intel_backlight_setup(intel_connector, INVALID_PIPE);
diff --git a/drivers/gpu/drm/i915/display/intel_atomic.c b/drivers/gpu/drm/i915/display/intel_atomic.c
index 6621aa245caf..a9a3f3715279 100644
--- a/drivers/gpu/drm/i915/display/intel_atomic.c
+++ b/drivers/gpu/drm/i915/display/intel_atomic.c
@@ -41,6 +41,7 @@
#include "intel_global_state.h"
#include "intel_hdcp.h"
#include "intel_psr.h"
+#include "intel_fb.h"
#include "skl_universal_plane.h"
/**
@@ -310,11 +311,11 @@ intel_crtc_destroy_state(struct drm_crtc *crtc,
kfree(crtc_state);
}
-static void intel_atomic_setup_scaler(struct intel_crtc_scaler_state *scaler_state,
- int num_scalers_need, struct intel_crtc *intel_crtc,
- const char *name, int idx,
- struct intel_plane_state *plane_state,
- int *scaler_id)
+static int intel_atomic_setup_scaler(struct intel_crtc_scaler_state *scaler_state,
+ int num_scalers_need, struct intel_crtc *intel_crtc,
+ const char *name, int idx,
+ struct intel_plane_state *plane_state,
+ int *scaler_id)
{
struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
int j;
@@ -334,7 +335,7 @@ static void intel_atomic_setup_scaler(struct intel_crtc_scaler_state *scaler_sta
if (drm_WARN(&dev_priv->drm, *scaler_id < 0,
"Cannot find scaler for %s:%d\n", name, idx))
- return;
+ return -EINVAL;
/* set scaler mode */
if (plane_state && plane_state->hw.fb &&
@@ -375,9 +376,71 @@ static void intel_atomic_setup_scaler(struct intel_crtc_scaler_state *scaler_sta
mode = SKL_PS_SCALER_MODE_DYN;
}
+ /*
+ * FIXME: we should also check the scaler factors for pfit, so
+ * this shouldn't be tied directly to planes.
+ */
+ if (plane_state && plane_state->hw.fb) {
+ const struct drm_framebuffer *fb = plane_state->hw.fb;
+ const struct drm_rect *src = &plane_state->uapi.src;
+ const struct drm_rect *dst = &plane_state->uapi.dst;
+ int hscale, vscale, max_vscale, max_hscale;
+
+ /*
+ * FIXME: When two scalers are needed, but only one of
+ * them needs to downscale, we should make sure that
+ * the one that needs downscaling support is assigned
+ * as the first scaler, so we don't reject downscaling
+ * unnecessarily.
+ */
+
+ if (DISPLAY_VER(dev_priv) >= 14) {
+ /*
+ * On versions 14 and up, only the first
+ * scaler supports a vertical scaling factor
+ * of more than 1.0, while a horizontal
+ * scaling factor of 3.0 is supported.
+ */
+ max_hscale = 0x30000 - 1;
+ if (*scaler_id == 0)
+ max_vscale = 0x30000 - 1;
+ else
+ max_vscale = 0x10000;
+
+ } else if (DISPLAY_VER(dev_priv) >= 10 ||
+ !intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier)) {
+ max_hscale = 0x30000 - 1;
+ max_vscale = 0x30000 - 1;
+ } else {
+ max_hscale = 0x20000 - 1;
+ max_vscale = 0x20000 - 1;
+ }
+
+ /*
+ * FIXME: We should change the if-else block above to
+ * support HQ vs dynamic scaler properly.
+ */
+
+ /* Check if required scaling is within limits */
+ hscale = drm_rect_calc_hscale(src, dst, 1, max_hscale);
+ vscale = drm_rect_calc_vscale(src, dst, 1, max_vscale);
+
+ if (hscale < 0 || vscale < 0) {
+ drm_dbg_kms(&dev_priv->drm,
+ "Scaler %d doesn't support required plane scaling\n",
+ *scaler_id);
+ drm_rect_debug_print("src: ", src, true);
+ drm_rect_debug_print("dst: ", dst, false);
+
+ return -EINVAL;
+ }
+ }
+
drm_dbg_kms(&dev_priv->drm, "Attached scaler id %u.%u to %s:%d\n",
intel_crtc->pipe, *scaler_id, name, idx);
scaler_state->scalers[*scaler_id].mode = mode;
+
+ return 0;
}
/**
@@ -437,7 +500,7 @@ int intel_atomic_setup_scalers(struct drm_i915_private *dev_priv,
for (i = 0; i < sizeof(scaler_state->scaler_users) * 8; i++) {
int *scaler_id;
const char *name;
- int idx;
+ int idx, ret;
/* skip if scaler not required */
if (!(scaler_state->scaler_users & (1 << i)))
@@ -494,9 +557,11 @@ int intel_atomic_setup_scalers(struct drm_i915_private *dev_priv,
scaler_id = &plane_state->scaler_id;
}
- intel_atomic_setup_scaler(scaler_state, num_scalers_need,
- intel_crtc, name, idx,
- plane_state, scaler_id);
+ ret = intel_atomic_setup_scaler(scaler_state, num_scalers_need,
+ intel_crtc, name, idx,
+ plane_state, scaler_id);
+ if (ret < 0)
+ return ret;
}
return 0;
diff --git a/drivers/gpu/drm/i915/display/intel_atomic_plane.c b/drivers/gpu/drm/i915/display/intel_atomic_plane.c
index 10e1fc9d0698..1409bcfb6fd3 100644
--- a/drivers/gpu/drm/i915/display/intel_atomic_plane.c
+++ b/drivers/gpu/drm/i915/display/intel_atomic_plane.c
@@ -36,6 +36,7 @@
#include "gt/intel_rps.h"
+#include "i915_config.h"
#include "intel_atomic_plane.h"
#include "intel_cdclk.h"
#include "intel_display_trace.h"
diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c
index 98c3322b4549..a9335c856644 100644
--- a/drivers/gpu/drm/i915/display/intel_audio.c
+++ b/drivers/gpu/drm/i915/display/intel_audio.c
@@ -71,6 +71,8 @@ struct intel_audio_funcs {
void (*audio_codec_disable)(struct intel_encoder *encoder,
const struct intel_crtc_state *old_crtc_state,
const struct drm_connector_state *old_conn_state);
+ void (*audio_codec_get_config)(struct intel_encoder *encoder,
+ struct intel_crtc_state *crtc_state);
};
/* DP N/M table */
@@ -314,6 +316,27 @@ static int g4x_eld_buffer_size(struct drm_i915_private *i915)
return REG_FIELD_GET(G4X_ELD_BUFFER_SIZE_MASK, tmp);
}
+static void g4x_audio_codec_get_config(struct intel_encoder *encoder,
+ struct intel_crtc_state *crtc_state)
+{
+ struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+ u32 *eld = (u32 *)crtc_state->eld;
+ int eld_buffer_size, len, i;
+ u32 tmp;
+
+ tmp = intel_de_read(i915, G4X_AUD_CNTL_ST);
+ if ((tmp & G4X_ELD_VALID) == 0)
+ return;
+
+ intel_de_rmw(i915, G4X_AUD_CNTL_ST, G4X_ELD_ADDRESS_MASK, 0);
+
+ eld_buffer_size = g4x_eld_buffer_size(i915);
+ len = min_t(int, sizeof(crtc_state->eld) / 4, eld_buffer_size);
+
+ for (i = 0; i < len; i++)
+ eld[i] = intel_de_read(i915, G4X_HDMIW_HDMIEDID);
+}
+
static void g4x_audio_codec_disable(struct intel_encoder *encoder,
const struct intel_crtc_state *old_crtc_state,
const struct drm_connector_state *old_conn_state)
@@ -335,8 +358,7 @@ static void g4x_audio_codec_enable(struct intel_encoder *encoder,
{
struct drm_i915_private *i915 = to_i915(encoder->base.dev);
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- struct drm_connector *connector = conn_state->connector;
- const u32 *eld = (const u32 *)connector->eld;
+ const u32 *eld = (const u32 *)crtc_state->eld;
int eld_buffer_size, len, i;
intel_crtc_wait_for_next_vblank(crtc);
@@ -345,7 +367,7 @@ static void g4x_audio_codec_enable(struct intel_encoder *encoder,
G4X_ELD_VALID | G4X_ELD_ADDRESS_MASK, 0);
eld_buffer_size = g4x_eld_buffer_size(i915);
- len = min(drm_eld_size(connector->eld) / 4, eld_buffer_size);
+ len = min(drm_eld_size(crtc_state->eld) / 4, eld_buffer_size);
for (i = 0; i < len; i++)
intel_de_write(i915, G4X_HDMIW_HDMIEDID, eld[i]);
@@ -459,17 +481,6 @@ hsw_audio_config_update(struct intel_encoder *encoder,
hsw_hdmi_audio_config_update(encoder, crtc_state);
}
-/* ELD buffer size in dwords */
-static int hsw_eld_buffer_size(struct drm_i915_private *i915,
- enum transcoder cpu_transcoder)
-{
- u32 tmp;
-
- tmp = intel_de_read(i915, HSW_AUD_DIP_ELD_CTRL(cpu_transcoder));
-
- return REG_FIELD_GET(IBX_ELD_BUFFER_SIZE_MASK, tmp);
-}
-
static void hsw_audio_codec_disable(struct intel_encoder *encoder,
const struct intel_crtc_state *old_crtc_state,
const struct drm_connector_state *old_conn_state)
@@ -618,10 +629,7 @@ static void hsw_audio_codec_enable(struct intel_encoder *encoder,
{
struct drm_i915_private *i915 = to_i915(encoder->base.dev);
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- struct drm_connector *connector = conn_state->connector;
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
- const u32 *eld = (const u32 *)connector->eld;
- int eld_buffer_size, len, i;
mutex_lock(&i915->display.audio.mutex);
@@ -639,25 +647,10 @@ static void hsw_audio_codec_enable(struct intel_encoder *encoder,
intel_de_rmw(i915, HSW_AUD_PIN_ELD_CP_VLD,
AUDIO_ELD_VALID(cpu_transcoder), 0);
- /* Reset ELD address */
- intel_de_rmw(i915, HSW_AUD_DIP_ELD_CTRL(cpu_transcoder),
- IBX_ELD_ADDRESS_MASK, 0);
-
- eld_buffer_size = hsw_eld_buffer_size(i915, cpu_transcoder);
- len = min(drm_eld_size(connector->eld) / 4, eld_buffer_size);
-
- for (i = 0; i < len; i++)
- intel_de_write(i915, HSW_AUD_EDID_DATA(cpu_transcoder), eld[i]);
- for (; i < eld_buffer_size; i++)
- intel_de_write(i915, HSW_AUD_EDID_DATA(cpu_transcoder), 0);
-
- drm_WARN_ON(&i915->drm,
- (intel_de_read(i915, HSW_AUD_DIP_ELD_CTRL(cpu_transcoder)) &
- IBX_ELD_ADDRESS_MASK) != 0);
-
- /* ELD valid */
- intel_de_rmw(i915, HSW_AUD_PIN_ELD_CP_VLD,
- 0, AUDIO_ELD_VALID(cpu_transcoder));
+ /*
+ * The audio componenent is used to convey the ELD
+ * instead using of the hardware ELD buffer.
+ */
/* Enable timestamps */
hsw_audio_config_update(encoder, crtc_state);
@@ -665,47 +658,33 @@ static void hsw_audio_codec_enable(struct intel_encoder *encoder,
mutex_unlock(&i915->display.audio.mutex);
}
-struct ilk_audio_regs {
+struct ibx_audio_regs {
i915_reg_t hdmiw_hdmiedid, aud_config, aud_cntl_st, aud_cntrl_st2;
};
-static void ilk_audio_regs_init(struct drm_i915_private *i915,
+static void ibx_audio_regs_init(struct drm_i915_private *i915,
enum pipe pipe,
- struct ilk_audio_regs *regs)
+ struct ibx_audio_regs *regs)
{
- if (HAS_PCH_IBX(i915)) {
- regs->hdmiw_hdmiedid = IBX_HDMIW_HDMIEDID(pipe);
- regs->aud_config = IBX_AUD_CFG(pipe);
- regs->aud_cntl_st = IBX_AUD_CNTL_ST(pipe);
- regs->aud_cntrl_st2 = IBX_AUD_CNTL_ST2;
- } else if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) {
+ if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) {
regs->hdmiw_hdmiedid = VLV_HDMIW_HDMIEDID(pipe);
regs->aud_config = VLV_AUD_CFG(pipe);
regs->aud_cntl_st = VLV_AUD_CNTL_ST(pipe);
regs->aud_cntrl_st2 = VLV_AUD_CNTL_ST2;
- } else {
+ } else if (HAS_PCH_CPT(i915)) {
regs->hdmiw_hdmiedid = CPT_HDMIW_HDMIEDID(pipe);
regs->aud_config = CPT_AUD_CFG(pipe);
regs->aud_cntl_st = CPT_AUD_CNTL_ST(pipe);
regs->aud_cntrl_st2 = CPT_AUD_CNTRL_ST2;
+ } else if (HAS_PCH_IBX(i915)) {
+ regs->hdmiw_hdmiedid = IBX_HDMIW_HDMIEDID(pipe);
+ regs->aud_config = IBX_AUD_CFG(pipe);
+ regs->aud_cntl_st = IBX_AUD_CNTL_ST(pipe);
+ regs->aud_cntrl_st2 = IBX_AUD_CNTL_ST2;
}
}
-/* ELD buffer size in dwords */
-static int ilk_eld_buffer_size(struct drm_i915_private *i915,
- enum pipe pipe)
-{
- struct ilk_audio_regs regs;
- u32 tmp;
-
- ilk_audio_regs_init(i915, pipe, &regs);
-
- tmp = intel_de_read(i915, regs.aud_cntl_st);
-
- return REG_FIELD_GET(IBX_ELD_BUFFER_SIZE_MASK, tmp);
-}
-
-static void ilk_audio_codec_disable(struct intel_encoder *encoder,
+static void ibx_audio_codec_disable(struct intel_encoder *encoder,
const struct intel_crtc_state *old_crtc_state,
const struct drm_connector_state *old_conn_state)
{
@@ -713,12 +692,12 @@ static void ilk_audio_codec_disable(struct intel_encoder *encoder,
struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc);
enum port port = encoder->port;
enum pipe pipe = crtc->pipe;
- struct ilk_audio_regs regs;
+ struct ibx_audio_regs regs;
if (drm_WARN_ON(&i915->drm, port == PORT_A))
return;
- ilk_audio_regs_init(i915, pipe, &regs);
+ ibx_audio_regs_init(i915, pipe, &regs);
mutex_lock(&i915->display.audio.mutex);
@@ -741,25 +720,22 @@ static void ilk_audio_codec_disable(struct intel_encoder *encoder,
intel_crtc_wait_for_next_vblank(crtc);
}
-static void ilk_audio_codec_enable(struct intel_encoder *encoder,
+static void ibx_audio_codec_enable(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state)
{
struct drm_i915_private *i915 = to_i915(encoder->base.dev);
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- struct drm_connector *connector = conn_state->connector;
- const u32 *eld = (const u32 *)connector->eld;
enum port port = encoder->port;
enum pipe pipe = crtc->pipe;
- int eld_buffer_size, len, i;
- struct ilk_audio_regs regs;
+ struct ibx_audio_regs regs;
if (drm_WARN_ON(&i915->drm, port == PORT_A))
return;
intel_crtc_wait_for_next_vblank(crtc);
- ilk_audio_regs_init(i915, pipe, &regs);
+ ibx_audio_regs_init(i915, pipe, &regs);
mutex_lock(&i915->display.audio.mutex);
@@ -767,24 +743,10 @@ static void ilk_audio_codec_enable(struct intel_encoder *encoder,
intel_de_rmw(i915, regs.aud_cntrl_st2,
IBX_ELD_VALID(port), 0);
- /* Reset ELD address */
- intel_de_rmw(i915, regs.aud_cntl_st,
- IBX_ELD_ADDRESS_MASK, 0);
-
- eld_buffer_size = ilk_eld_buffer_size(i915, pipe);
- len = min(drm_eld_size(connector->eld) / 4, eld_buffer_size);
-
- for (i = 0; i < len; i++)
- intel_de_write(i915, regs.hdmiw_hdmiedid, eld[i]);
- for (; i < eld_buffer_size; i++)
- intel_de_write(i915, regs.hdmiw_hdmiedid, 0);
-
- drm_WARN_ON(&i915->drm,
- (intel_de_read(i915, regs.aud_cntl_st) & IBX_ELD_ADDRESS_MASK) != 0);
-
- /* ELD valid */
- intel_de_rmw(i915, regs.aud_cntrl_st2,
- 0, IBX_ELD_VALID(port));
+ /*
+ * The audio componenent is used to convey the ELD
+ * instead using of the hardware ELD buffer.
+ */
/* Enable timestamps */
intel_de_rmw(i915, regs.aud_config,
@@ -798,6 +760,41 @@ static void ilk_audio_codec_enable(struct intel_encoder *encoder,
mutex_unlock(&i915->display.audio.mutex);
}
+void intel_audio_sdp_split_update(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state)
+{
+ struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+ enum transcoder trans = crtc_state->cpu_transcoder;
+
+ if (HAS_DP20(i915))
+ intel_de_rmw(i915, AUD_DP_2DOT0_CTRL(trans), AUD_ENABLE_SDP_SPLIT,
+ crtc_state->sdp_split_enable ? AUD_ENABLE_SDP_SPLIT : 0);
+}
+
+bool intel_audio_compute_config(struct intel_encoder *encoder,
+ struct intel_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
+{
+ struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+ struct drm_connector *connector = conn_state->connector;
+ const struct drm_display_mode *adjusted_mode =
+ &crtc_state->hw.adjusted_mode;
+
+ if (!connector->eld[0]) {
+ drm_dbg_kms(&i915->drm,
+ "Bogus ELD on [CONNECTOR:%d:%s]\n",
+ connector->base.id, connector->name);
+ return false;
+ }
+
+ BUILD_BUG_ON(sizeof(crtc_state->eld) != sizeof(connector->eld));
+ memcpy(crtc_state->eld, connector->eld, sizeof(crtc_state->eld));
+
+ crtc_state->eld[6] = drm_av_sync_delay(connector, adjusted_mode) / 2;
+
+ return true;
+}
+
/**
* intel_audio_codec_enable - Enable the audio codec for HD audio
* @encoder: encoder on which to enable audio
@@ -814,27 +811,19 @@ void intel_audio_codec_enable(struct intel_encoder *encoder,
struct drm_i915_private *i915 = to_i915(encoder->base.dev);
struct i915_audio_component *acomp = i915->display.audio.component;
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- struct drm_connector *connector = conn_state->connector;
- const struct drm_display_mode *adjusted_mode =
- &crtc_state->hw.adjusted_mode;
+ struct intel_connector *connector = to_intel_connector(conn_state->connector);
+ struct intel_audio_state *audio_state;
enum port port = encoder->port;
enum pipe pipe = crtc->pipe;
if (!crtc_state->has_audio)
return;
- drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s][ENCODER:%d:%s] Enable audio codec on pipe %c, %u bytes ELD\n",
- connector->base.id, connector->name,
+ drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s][ENCODER:%d:%s] Enable audio codec on [CRTC:%d:%s], %u bytes ELD\n",
+ connector->base.base.id, connector->base.name,
encoder->base.base.id, encoder->base.name,
- pipe_name(pipe), drm_eld_size(connector->eld));
-
- /* FIXME precompute the ELD in .compute_config() */
- if (!connector->eld[0])
- drm_dbg_kms(&i915->drm,
- "Bogus ELD on [CONNECTOR:%d:%s]\n",
- connector->base.id, connector->name);
-
- connector->eld[6] = drm_av_sync_delay(connector, adjusted_mode) / 2;
+ crtc->base.base.id, crtc->base.name,
+ drm_eld_size(crtc_state->eld));
if (i915->display.funcs.audio)
i915->display.funcs.audio->audio_codec_enable(encoder,
@@ -842,10 +831,13 @@ void intel_audio_codec_enable(struct intel_encoder *encoder,
conn_state);
mutex_lock(&i915->display.audio.mutex);
- encoder->audio_connector = connector;
- /* referred in audio callbacks */
- i915->display.audio.encoder_map[pipe] = encoder;
+ audio_state = &i915->display.audio.state[pipe];
+
+ audio_state->encoder = encoder;
+ BUILD_BUG_ON(sizeof(audio_state->eld) != sizeof(crtc_state->eld));
+ memcpy(audio_state->eld, crtc_state->eld, sizeof(audio_state->eld));
+
mutex_unlock(&i915->display.audio.mutex);
if (acomp && acomp->base.audio_ops &&
@@ -857,7 +849,7 @@ void intel_audio_codec_enable(struct intel_encoder *encoder,
(int)port, (int)pipe);
}
- intel_lpe_audio_notify(i915, pipe, port, connector->eld,
+ intel_lpe_audio_notify(i915, pipe, port, crtc_state->eld,
crtc_state->port_clock,
intel_crtc_has_dp_encoder(crtc_state));
}
@@ -878,16 +870,18 @@ void intel_audio_codec_disable(struct intel_encoder *encoder,
struct drm_i915_private *i915 = to_i915(encoder->base.dev);
struct i915_audio_component *acomp = i915->display.audio.component;
struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc);
- struct drm_connector *connector = old_conn_state->connector;
+ struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
+ struct intel_audio_state *audio_state;
enum port port = encoder->port;
enum pipe pipe = crtc->pipe;
if (!old_crtc_state->has_audio)
return;
- drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s][ENCODER:%d:%s] Disable audio codec on pipe %c\n",
- connector->base.id, connector->name,
- encoder->base.base.id, encoder->base.name, pipe_name(pipe));
+ drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s][ENCODER:%d:%s] Disable audio codec on [CRTC:%d:%s]\n",
+ connector->base.base.id, connector->base.name,
+ encoder->base.base.id, encoder->base.name,
+ crtc->base.base.id, crtc->base.name);
if (i915->display.funcs.audio)
i915->display.funcs.audio->audio_codec_disable(encoder,
@@ -895,8 +889,12 @@ void intel_audio_codec_disable(struct intel_encoder *encoder,
old_conn_state);
mutex_lock(&i915->display.audio.mutex);
- encoder->audio_connector = NULL;
- i915->display.audio.encoder_map[pipe] = NULL;
+
+ audio_state = &i915->display.audio.state[pipe];
+
+ audio_state->encoder = NULL;
+ memset(audio_state->eld, 0, sizeof(audio_state->eld));
+
mutex_unlock(&i915->display.audio.mutex);
if (acomp && acomp->base.audio_ops &&
@@ -911,19 +909,52 @@ void intel_audio_codec_disable(struct intel_encoder *encoder,
intel_lpe_audio_notify(i915, pipe, port, NULL, 0, false);
}
+static void intel_acomp_get_config(struct intel_encoder *encoder,
+ struct intel_crtc_state *crtc_state)
+{
+ struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+ struct intel_audio_state *audio_state;
+ enum pipe pipe = crtc->pipe;
+
+ mutex_lock(&i915->display.audio.mutex);
+
+ audio_state = &i915->display.audio.state[pipe];
+
+ if (audio_state->encoder)
+ memcpy(crtc_state->eld, audio_state->eld, sizeof(audio_state->eld));
+
+ mutex_unlock(&i915->display.audio.mutex);
+}
+
+void intel_audio_codec_get_config(struct intel_encoder *encoder,
+ struct intel_crtc_state *crtc_state)
+{
+ struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+
+ if (!crtc_state->has_audio)
+ return;
+
+ if (i915->display.funcs.audio)
+ i915->display.funcs.audio->audio_codec_get_config(encoder, crtc_state);
+}
+
static const struct intel_audio_funcs g4x_audio_funcs = {
.audio_codec_enable = g4x_audio_codec_enable,
.audio_codec_disable = g4x_audio_codec_disable,
+ .audio_codec_get_config = g4x_audio_codec_get_config,
};
-static const struct intel_audio_funcs ilk_audio_funcs = {
- .audio_codec_enable = ilk_audio_codec_enable,
- .audio_codec_disable = ilk_audio_codec_disable,
+static const struct intel_audio_funcs ibx_audio_funcs = {
+ .audio_codec_enable = ibx_audio_codec_enable,
+ .audio_codec_disable = ibx_audio_codec_disable,
+ .audio_codec_get_config = intel_acomp_get_config,
};
static const struct intel_audio_funcs hsw_audio_funcs = {
.audio_codec_enable = hsw_audio_codec_enable,
.audio_codec_disable = hsw_audio_codec_disable,
+ .audio_codec_get_config = intel_acomp_get_config,
};
/**
@@ -934,12 +965,11 @@ void intel_audio_hooks_init(struct drm_i915_private *i915)
{
if (IS_G4X(i915))
i915->display.funcs.audio = &g4x_audio_funcs;
- else if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915))
- i915->display.funcs.audio = &ilk_audio_funcs;
+ else if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915) ||
+ HAS_PCH_CPT(i915) || HAS_PCH_IBX(i915))
+ i915->display.funcs.audio = &ibx_audio_funcs;
else if (IS_HASWELL(i915) || DISPLAY_VER(i915) >= 8)
i915->display.funcs.audio = &hsw_audio_funcs;
- else if (HAS_PCH_SPLIT(i915))
- i915->display.funcs.audio = &ilk_audio_funcs;
}
struct aud_ts_cdclk_m_n {
@@ -1117,35 +1147,32 @@ static int i915_audio_component_get_cdclk_freq(struct device *kdev)
}
/*
- * get the intel_encoder according to the parameter port and pipe
- * intel_encoder is saved by the index of pipe
- * MST & (pipe >= 0): return the audio.encoder_map[pipe],
+ * get the intel audio state according to the parameter port and pipe
+ * MST & (pipe >= 0): return the audio.state[pipe].encoder],
* when port is matched
* MST & (pipe < 0): this is invalid
* Non-MST & (pipe >= 0): only pipe = 0 (the first device entry)
* will get the right intel_encoder with port matched
* Non-MST & (pipe < 0): get the right intel_encoder with port matched
*/
-static struct intel_encoder *get_saved_enc(struct drm_i915_private *i915,
- int port, int pipe)
+static struct intel_audio_state *find_audio_state(struct drm_i915_private *i915,
+ int port, int pipe)
{
/* MST */
if (pipe >= 0) {
+ struct intel_audio_state *audio_state;
struct intel_encoder *encoder;
if (drm_WARN_ON(&i915->drm,
- pipe >= ARRAY_SIZE(i915->display.audio.encoder_map)))
+ pipe >= ARRAY_SIZE(i915->display.audio.state)))
return NULL;
- encoder = i915->display.audio.encoder_map[pipe];
- /*
- * when bootup, audio driver may not know it is
- * MST or not. So it will poll all the port & pipe
- * combinations
- */
+ audio_state = &i915->display.audio.state[pipe];
+ encoder = audio_state->encoder;
+
if (encoder && encoder->port == port &&
encoder->type == INTEL_OUTPUT_DP_MST)
- return encoder;
+ return audio_state;
}
/* Non-MST */
@@ -1153,13 +1180,15 @@ static struct intel_encoder *get_saved_enc(struct drm_i915_private *i915,
return NULL;
for_each_pipe(i915, pipe) {
+ struct intel_audio_state *audio_state;
struct intel_encoder *encoder;
- encoder = i915->display.audio.encoder_map[pipe];
+ audio_state = &i915->display.audio.state[pipe];
+ encoder = audio_state->encoder;
if (encoder && encoder->port == port &&
encoder->type != INTEL_OUTPUT_DP_MST)
- return encoder;
+ return audio_state;
}
return NULL;
@@ -1170,6 +1199,7 @@ static int i915_audio_component_sync_audio_rate(struct device *kdev, int port,
{
struct drm_i915_private *i915 = kdev_to_i915(kdev);
struct i915_audio_component *acomp = i915->display.audio.component;
+ const struct intel_audio_state *audio_state;
struct intel_encoder *encoder;
struct intel_crtc *crtc;
unsigned long cookie;
@@ -1181,20 +1211,22 @@ static int i915_audio_component_sync_audio_rate(struct device *kdev, int port,
cookie = i915_audio_component_get_power(kdev);
mutex_lock(&i915->display.audio.mutex);
- /* 1. get the pipe */
- encoder = get_saved_enc(i915, port, pipe);
- if (!encoder || !encoder->base.crtc) {
- drm_dbg_kms(&i915->drm, "Not valid for port %c\n",
- port_name(port));
+ audio_state = find_audio_state(i915, port, pipe);
+ if (!audio_state) {
+ drm_dbg_kms(&i915->drm, "Not valid for port %c\n", port_name(port));
err = -ENODEV;
goto unlock;
}
+ encoder = audio_state->encoder;
+
+ /* FIXME stop using the legacy crtc pointer */
crtc = to_intel_crtc(encoder->base.crtc);
/* port must be valid now, otherwise the pipe will be invalid */
acomp->aud_sample_rate[port] = rate;
+ /* FIXME get rid of the crtc->config stuff */
hsw_audio_config_update(encoder, crtc->config);
unlock:
@@ -1208,24 +1240,22 @@ static int i915_audio_component_get_eld(struct device *kdev, int port,
unsigned char *buf, int max_bytes)
{
struct drm_i915_private *i915 = kdev_to_i915(kdev);
- struct intel_encoder *intel_encoder;
- const u8 *eld;
- int ret = -EINVAL;
+ const struct intel_audio_state *audio_state;
+ int ret = 0;
mutex_lock(&i915->display.audio.mutex);
- intel_encoder = get_saved_enc(i915, port, pipe);
- if (!intel_encoder) {
- drm_dbg_kms(&i915->drm, "Not valid for port %c\n",
- port_name(port));
+ audio_state = find_audio_state(i915, port, pipe);
+ if (!audio_state) {
+ drm_dbg_kms(&i915->drm, "Not valid for port %c\n", port_name(port));
mutex_unlock(&i915->display.audio.mutex);
- return ret;
+ return -EINVAL;
}
- ret = 0;
- *enabled = intel_encoder->audio_connector != NULL;
+ *enabled = audio_state->encoder != NULL;
if (*enabled) {
- eld = intel_encoder->audio_connector->eld;
+ const u8 *eld = audio_state->eld;
+
ret = drm_eld_size(eld);
memcpy(buf, eld, min(max_bytes, ret));
}
diff --git a/drivers/gpu/drm/i915/display/intel_audio.h b/drivers/gpu/drm/i915/display/intel_audio.h
index 63b22131dc45..07d034a981e9 100644
--- a/drivers/gpu/drm/i915/display/intel_audio.h
+++ b/drivers/gpu/drm/i915/display/intel_audio.h
@@ -6,21 +6,30 @@
#ifndef __INTEL_AUDIO_H__
#define __INTEL_AUDIO_H__
+#include <linux/types.h>
+
struct drm_connector_state;
struct drm_i915_private;
struct intel_crtc_state;
struct intel_encoder;
void intel_audio_hooks_init(struct drm_i915_private *dev_priv);
+bool intel_audio_compute_config(struct intel_encoder *encoder,
+ struct intel_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state);
void intel_audio_codec_enable(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state);
void intel_audio_codec_disable(struct intel_encoder *encoder,
const struct intel_crtc_state *old_crtc_state,
const struct drm_connector_state *old_conn_state);
+void intel_audio_codec_get_config(struct intel_encoder *encoder,
+ struct intel_crtc_state *crtc_state);
void intel_audio_cdclk_change_pre(struct drm_i915_private *dev_priv);
void intel_audio_cdclk_change_post(struct drm_i915_private *dev_priv);
void intel_audio_init(struct drm_i915_private *dev_priv);
void intel_audio_deinit(struct drm_i915_private *dev_priv);
+void intel_audio_sdp_split_update(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state);
#endif /* __INTEL_AUDIO_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_backlight.c b/drivers/gpu/drm/i915/display/intel_backlight.c
index 71af88a70461..a4e4b7f79e4d 100644
--- a/drivers/gpu/drm/i915/display/intel_backlight.c
+++ b/drivers/gpu/drm/i915/display/intel_backlight.c
@@ -83,16 +83,16 @@ static u32 scale_hw_to_user(struct intel_connector *connector,
u32 intel_backlight_invert_pwm_level(struct intel_connector *connector, u32 val)
{
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
- drm_WARN_ON(&dev_priv->drm, panel->backlight.pwm_level_max == 0);
+ drm_WARN_ON(&i915->drm, panel->backlight.pwm_level_max == 0);
- if (dev_priv->params.invert_brightness < 0)
+ if (i915->params.invert_brightness < 0)
return val;
- if (dev_priv->params.invert_brightness > 0 ||
- intel_has_quirk(dev_priv, QUIRK_INVERT_BRIGHTNESS)) {
+ if (i915->params.invert_brightness > 0 ||
+ intel_has_quirk(i915, QUIRK_INVERT_BRIGHTNESS)) {
return panel->backlight.pwm_level_max - val + panel->backlight.pwm_level_min;
}
@@ -111,10 +111,10 @@ void intel_backlight_set_pwm_level(const struct drm_connector_state *conn_state,
u32 intel_backlight_level_to_pwm(struct intel_connector *connector, u32 val)
{
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
- drm_WARN_ON_ONCE(&dev_priv->drm,
+ drm_WARN_ON_ONCE(&i915->drm,
panel->backlight.max == 0 || panel->backlight.pwm_level_max == 0);
val = scale(val, panel->backlight.min, panel->backlight.max,
@@ -125,14 +125,14 @@ u32 intel_backlight_level_to_pwm(struct intel_connector *connector, u32 val)
u32 intel_backlight_level_from_pwm(struct intel_connector *connector, u32 val)
{
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
- drm_WARN_ON_ONCE(&dev_priv->drm,
+ drm_WARN_ON_ONCE(&i915->drm,
panel->backlight.max == 0 || panel->backlight.pwm_level_max == 0);
- if (dev_priv->params.invert_brightness > 0 ||
- (dev_priv->params.invert_brightness == 0 && intel_has_quirk(dev_priv, QUIRK_INVERT_BRIGHTNESS)))
+ if (i915->params.invert_brightness > 0 ||
+ (i915->params.invert_brightness == 0 && intel_has_quirk(i915, QUIRK_INVERT_BRIGHTNESS)))
val = panel->backlight.pwm_level_max - (val - panel->backlight.pwm_level_min);
return scale(val, panel->backlight.pwm_level_min, panel->backlight.pwm_level_max,
@@ -141,32 +141,32 @@ u32 intel_backlight_level_from_pwm(struct intel_connector *connector, u32 val)
static u32 lpt_get_backlight(struct intel_connector *connector, enum pipe unused)
{
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
- return intel_de_read(dev_priv, BLC_PWM_PCH_CTL2) & BACKLIGHT_DUTY_CYCLE_MASK;
+ return intel_de_read(i915, BLC_PWM_PCH_CTL2) & BACKLIGHT_DUTY_CYCLE_MASK;
}
static u32 pch_get_backlight(struct intel_connector *connector, enum pipe unused)
{
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
- return intel_de_read(dev_priv, BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
+ return intel_de_read(i915, BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
}
static u32 i9xx_get_backlight(struct intel_connector *connector, enum pipe unused)
{
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
u32 val;
- val = intel_de_read(dev_priv, BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
- if (DISPLAY_VER(dev_priv) < 4)
+ val = intel_de_read(i915, BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
+ if (DISPLAY_VER(i915) < 4)
val >>= 1;
if (panel->backlight.combination_mode) {
u8 lbpc;
- pci_read_config_byte(to_pci_dev(dev_priv->drm.dev), LBPC, &lbpc);
+ pci_read_config_byte(to_pci_dev(i915->drm.dev), LBPC, &lbpc);
val *= lbpc;
}
@@ -175,21 +175,20 @@ static u32 i9xx_get_backlight(struct intel_connector *connector, enum pipe unuse
static u32 vlv_get_backlight(struct intel_connector *connector, enum pipe pipe)
{
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
- if (drm_WARN_ON(&dev_priv->drm, pipe != PIPE_A && pipe != PIPE_B))
+ if (drm_WARN_ON(&i915->drm, pipe != PIPE_A && pipe != PIPE_B))
return 0;
- return intel_de_read(dev_priv, VLV_BLC_PWM_CTL(pipe)) & BACKLIGHT_DUTY_CYCLE_MASK;
+ return intel_de_read(i915, VLV_BLC_PWM_CTL(pipe)) & BACKLIGHT_DUTY_CYCLE_MASK;
}
static u32 bxt_get_backlight(struct intel_connector *connector, enum pipe unused)
{
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
- return intel_de_read(dev_priv,
- BXT_BLC_PWM_DUTY(panel->backlight.controller));
+ return intel_de_read(i915, BXT_BLC_PWM_DUTY(panel->backlight.controller));
}
static u32 ext_pwm_get_backlight(struct intel_connector *connector, enum pipe unused)
@@ -204,69 +203,69 @@ static u32 ext_pwm_get_backlight(struct intel_connector *connector, enum pipe un
static void lpt_set_backlight(const struct drm_connector_state *conn_state, u32 level)
{
struct intel_connector *connector = to_intel_connector(conn_state->connector);
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
+ u32 val;
- u32 val = intel_de_read(dev_priv, BLC_PWM_PCH_CTL2) & ~BACKLIGHT_DUTY_CYCLE_MASK;
- intel_de_write(dev_priv, BLC_PWM_PCH_CTL2, val | level);
+ val = intel_de_read(i915, BLC_PWM_PCH_CTL2) & ~BACKLIGHT_DUTY_CYCLE_MASK;
+ intel_de_write(i915, BLC_PWM_PCH_CTL2, val | level);
}
static void pch_set_backlight(const struct drm_connector_state *conn_state, u32 level)
{
struct intel_connector *connector = to_intel_connector(conn_state->connector);
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
u32 tmp;
- tmp = intel_de_read(dev_priv, BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK;
- intel_de_write(dev_priv, BLC_PWM_CPU_CTL, tmp | level);
+ tmp = intel_de_read(i915, BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK;
+ intel_de_write(i915, BLC_PWM_CPU_CTL, tmp | level);
}
static void i9xx_set_backlight(const struct drm_connector_state *conn_state, u32 level)
{
struct intel_connector *connector = to_intel_connector(conn_state->connector);
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
u32 tmp, mask;
- drm_WARN_ON(&dev_priv->drm, panel->backlight.pwm_level_max == 0);
+ drm_WARN_ON(&i915->drm, panel->backlight.pwm_level_max == 0);
if (panel->backlight.combination_mode) {
u8 lbpc;
lbpc = level * 0xfe / panel->backlight.pwm_level_max + 1;
level /= lbpc;
- pci_write_config_byte(to_pci_dev(dev_priv->drm.dev), LBPC, lbpc);
+ pci_write_config_byte(to_pci_dev(i915->drm.dev), LBPC, lbpc);
}
- if (DISPLAY_VER(dev_priv) == 4) {
+ if (DISPLAY_VER(i915) == 4) {
mask = BACKLIGHT_DUTY_CYCLE_MASK;
} else {
level <<= 1;
mask = BACKLIGHT_DUTY_CYCLE_MASK_PNV;
}
- tmp = intel_de_read(dev_priv, BLC_PWM_CTL) & ~mask;
- intel_de_write(dev_priv, BLC_PWM_CTL, tmp | level);
+ tmp = intel_de_read(i915, BLC_PWM_CTL) & ~mask;
+ intel_de_write(i915, BLC_PWM_CTL, tmp | level);
}
static void vlv_set_backlight(const struct drm_connector_state *conn_state, u32 level)
{
struct intel_connector *connector = to_intel_connector(conn_state->connector);
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
enum pipe pipe = to_intel_crtc(conn_state->crtc)->pipe;
u32 tmp;
- tmp = intel_de_read(dev_priv, VLV_BLC_PWM_CTL(pipe)) & ~BACKLIGHT_DUTY_CYCLE_MASK;
- intel_de_write(dev_priv, VLV_BLC_PWM_CTL(pipe), tmp | level);
+ tmp = intel_de_read(i915, VLV_BLC_PWM_CTL(pipe)) & ~BACKLIGHT_DUTY_CYCLE_MASK;
+ intel_de_write(i915, VLV_BLC_PWM_CTL(pipe), tmp | level);
}
static void bxt_set_backlight(const struct drm_connector_state *conn_state, u32 level)
{
struct intel_connector *connector = to_intel_connector(conn_state->connector);
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
- intel_de_write(dev_priv,
- BXT_BLC_PWM_DUTY(panel->backlight.controller), level);
+ intel_de_write(i915, BXT_BLC_PWM_DUTY(panel->backlight.controller), level);
}
static void ext_pwm_set_backlight(const struct drm_connector_state *conn_state, u32 level)
@@ -296,7 +295,7 @@ void intel_backlight_set_acpi(const struct drm_connector_state *conn_state,
u32 user_level, u32 user_max)
{
struct intel_connector *connector = to_intel_connector(conn_state->connector);
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
u32 hw_level;
@@ -309,9 +308,9 @@ void intel_backlight_set_acpi(const struct drm_connector_state *conn_state,
if (!panel->backlight.present || !conn_state->crtc)
return;
- mutex_lock(&dev_priv->display.backlight.lock);
+ mutex_lock(&i915->display.backlight.lock);
- drm_WARN_ON(&dev_priv->drm, panel->backlight.max == 0);
+ drm_WARN_ON(&i915->drm, panel->backlight.max == 0);
hw_level = clamp_user_to_hw(connector, user_level, user_max);
panel->backlight.level = hw_level;
@@ -325,13 +324,13 @@ void intel_backlight_set_acpi(const struct drm_connector_state *conn_state,
if (panel->backlight.enabled)
intel_panel_actually_set_backlight(conn_state, hw_level);
- mutex_unlock(&dev_priv->display.backlight.lock);
+ mutex_unlock(&i915->display.backlight.lock);
}
static void lpt_disable_backlight(const struct drm_connector_state *old_conn_state, u32 level)
{
struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
u32 tmp;
intel_backlight_set_pwm_level(old_conn_state, level);
@@ -344,31 +343,29 @@ static void lpt_disable_backlight(const struct drm_connector_state *old_conn_sta
* This needs rework if we need to add support for CPU PWM on PCH split
* platforms.
*/
- tmp = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2);
+ tmp = intel_de_read(i915, BLC_PWM_CPU_CTL2);
if (tmp & BLM_PWM_ENABLE) {
- drm_dbg_kms(&dev_priv->drm,
- "cpu backlight was enabled, disabling\n");
- intel_de_write(dev_priv, BLC_PWM_CPU_CTL2,
- tmp & ~BLM_PWM_ENABLE);
+ drm_dbg_kms(&i915->drm, "cpu backlight was enabled, disabling\n");
+ intel_de_write(i915, BLC_PWM_CPU_CTL2, tmp & ~BLM_PWM_ENABLE);
}
- tmp = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1);
- intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, tmp & ~BLM_PCH_PWM_ENABLE);
+ tmp = intel_de_read(i915, BLC_PWM_PCH_CTL1);
+ intel_de_write(i915, BLC_PWM_PCH_CTL1, tmp & ~BLM_PCH_PWM_ENABLE);
}
static void pch_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val)
{
struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
u32 tmp;
intel_backlight_set_pwm_level(old_conn_state, val);
- tmp = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2);
- intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, tmp & ~BLM_PWM_ENABLE);
+ tmp = intel_de_read(i915, BLC_PWM_CPU_CTL2);
+ intel_de_write(i915, BLC_PWM_CPU_CTL2, tmp & ~BLM_PWM_ENABLE);
- tmp = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1);
- intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, tmp & ~BLM_PCH_PWM_ENABLE);
+ tmp = intel_de_read(i915, BLC_PWM_PCH_CTL1);
+ intel_de_write(i915, BLC_PWM_PCH_CTL1, tmp & ~BLM_PCH_PWM_ENABLE);
}
static void i9xx_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val)
@@ -378,62 +375,59 @@ static void i9xx_disable_backlight(const struct drm_connector_state *old_conn_st
static void i965_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val)
{
- struct drm_i915_private *dev_priv = to_i915(old_conn_state->connector->dev);
+ struct drm_i915_private *i915 = to_i915(old_conn_state->connector->dev);
u32 tmp;
intel_backlight_set_pwm_level(old_conn_state, val);
- tmp = intel_de_read(dev_priv, BLC_PWM_CTL2);
- intel_de_write(dev_priv, BLC_PWM_CTL2, tmp & ~BLM_PWM_ENABLE);
+ tmp = intel_de_read(i915, BLC_PWM_CTL2);
+ intel_de_write(i915, BLC_PWM_CTL2, tmp & ~BLM_PWM_ENABLE);
}
static void vlv_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val)
{
struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
enum pipe pipe = to_intel_crtc(old_conn_state->crtc)->pipe;
u32 tmp;
intel_backlight_set_pwm_level(old_conn_state, val);
- tmp = intel_de_read(dev_priv, VLV_BLC_PWM_CTL2(pipe));
- intel_de_write(dev_priv, VLV_BLC_PWM_CTL2(pipe),
- tmp & ~BLM_PWM_ENABLE);
+ tmp = intel_de_read(i915, VLV_BLC_PWM_CTL2(pipe));
+ intel_de_write(i915, VLV_BLC_PWM_CTL2(pipe), tmp & ~BLM_PWM_ENABLE);
}
static void bxt_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val)
{
struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
u32 tmp;
intel_backlight_set_pwm_level(old_conn_state, val);
- tmp = intel_de_read(dev_priv,
- BXT_BLC_PWM_CTL(panel->backlight.controller));
- intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller),
+ tmp = intel_de_read(i915, BXT_BLC_PWM_CTL(panel->backlight.controller));
+ intel_de_write(i915, BXT_BLC_PWM_CTL(panel->backlight.controller),
tmp & ~BXT_BLC_PWM_ENABLE);
if (panel->backlight.controller == 1) {
- val = intel_de_read(dev_priv, UTIL_PIN_CTL);
+ val = intel_de_read(i915, UTIL_PIN_CTL);
val &= ~UTIL_PIN_ENABLE;
- intel_de_write(dev_priv, UTIL_PIN_CTL, val);
+ intel_de_write(i915, UTIL_PIN_CTL, val);
}
}
static void cnp_disable_backlight(const struct drm_connector_state *old_conn_state, u32 val)
{
struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
u32 tmp;
intel_backlight_set_pwm_level(old_conn_state, val);
- tmp = intel_de_read(dev_priv,
- BXT_BLC_PWM_CTL(panel->backlight.controller));
- intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller),
+ tmp = intel_de_read(i915, BXT_BLC_PWM_CTL(panel->backlight.controller));
+ intel_de_write(i915, BXT_BLC_PWM_CTL(panel->backlight.controller),
tmp & ~BXT_BLC_PWM_ENABLE);
}
@@ -451,7 +445,7 @@ static void ext_pwm_disable_backlight(const struct drm_connector_state *old_conn
void intel_backlight_disable(const struct drm_connector_state *old_conn_state)
{
struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
if (!panel->backlight.present)
@@ -463,68 +457,66 @@ void intel_backlight_disable(const struct drm_connector_state *old_conn_state)
* backlight. This will leave the backlight on unnecessarily when
* another client is not activated.
*/
- if (dev_priv->drm.switch_power_state == DRM_SWITCH_POWER_CHANGING) {
- drm_dbg_kms(&dev_priv->drm,
- "Skipping backlight disable on vga switch\n");
+ if (i915->drm.switch_power_state == DRM_SWITCH_POWER_CHANGING) {
+ drm_dbg_kms(&i915->drm, "Skipping backlight disable on vga switch\n");
return;
}
- mutex_lock(&dev_priv->display.backlight.lock);
+ mutex_lock(&i915->display.backlight.lock);
if (panel->backlight.device)
panel->backlight.device->props.power = FB_BLANK_POWERDOWN;
panel->backlight.enabled = false;
panel->backlight.funcs->disable(old_conn_state, 0);
- mutex_unlock(&dev_priv->display.backlight.lock);
+ mutex_unlock(&i915->display.backlight.lock);
}
static void lpt_enable_backlight(const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state, u32 level)
{
struct intel_connector *connector = to_intel_connector(conn_state->connector);
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
u32 pch_ctl1, pch_ctl2, schicken;
- pch_ctl1 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1);
+ pch_ctl1 = intel_de_read(i915, BLC_PWM_PCH_CTL1);
if (pch_ctl1 & BLM_PCH_PWM_ENABLE) {
- drm_dbg_kms(&dev_priv->drm, "pch backlight already enabled\n");
+ drm_dbg_kms(&i915->drm, "pch backlight already enabled\n");
pch_ctl1 &= ~BLM_PCH_PWM_ENABLE;
- intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, pch_ctl1);
+ intel_de_write(i915, BLC_PWM_PCH_CTL1, pch_ctl1);
}
- if (HAS_PCH_LPT(dev_priv)) {
- schicken = intel_de_read(dev_priv, SOUTH_CHICKEN2);
+ if (HAS_PCH_LPT(i915)) {
+ schicken = intel_de_read(i915, SOUTH_CHICKEN2);
if (panel->backlight.alternate_pwm_increment)
schicken |= LPT_PWM_GRANULARITY;
else
schicken &= ~LPT_PWM_GRANULARITY;
- intel_de_write(dev_priv, SOUTH_CHICKEN2, schicken);
+ intel_de_write(i915, SOUTH_CHICKEN2, schicken);
} else {
- schicken = intel_de_read(dev_priv, SOUTH_CHICKEN1);
+ schicken = intel_de_read(i915, SOUTH_CHICKEN1);
if (panel->backlight.alternate_pwm_increment)
schicken |= SPT_PWM_GRANULARITY;
else
schicken &= ~SPT_PWM_GRANULARITY;
- intel_de_write(dev_priv, SOUTH_CHICKEN1, schicken);
+ intel_de_write(i915, SOUTH_CHICKEN1, schicken);
}
pch_ctl2 = panel->backlight.pwm_level_max << 16;
- intel_de_write(dev_priv, BLC_PWM_PCH_CTL2, pch_ctl2);
+ intel_de_write(i915, BLC_PWM_PCH_CTL2, pch_ctl2);
pch_ctl1 = 0;
if (panel->backlight.active_low_pwm)
pch_ctl1 |= BLM_PCH_POLARITY;
/* After LPT, override is the default. */
- if (HAS_PCH_LPT(dev_priv))
+ if (HAS_PCH_LPT(i915))
pch_ctl1 |= BLM_PCH_OVERRIDE_ENABLE;
- intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, pch_ctl1);
- intel_de_posting_read(dev_priv, BLC_PWM_PCH_CTL1);
- intel_de_write(dev_priv, BLC_PWM_PCH_CTL1,
- pch_ctl1 | BLM_PCH_PWM_ENABLE);
+ intel_de_write(i915, BLC_PWM_PCH_CTL1, pch_ctl1);
+ intel_de_posting_read(i915, BLC_PWM_PCH_CTL1);
+ intel_de_write(i915, BLC_PWM_PCH_CTL1, pch_ctl1 | BLM_PCH_PWM_ENABLE);
/* This won't stick until the above enable. */
intel_backlight_set_pwm_level(conn_state, level);
@@ -534,61 +526,60 @@ static void pch_enable_backlight(const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state, u32 level)
{
struct intel_connector *connector = to_intel_connector(conn_state->connector);
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
u32 cpu_ctl2, pch_ctl1, pch_ctl2;
- cpu_ctl2 = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2);
+ cpu_ctl2 = intel_de_read(i915, BLC_PWM_CPU_CTL2);
if (cpu_ctl2 & BLM_PWM_ENABLE) {
- drm_dbg_kms(&dev_priv->drm, "cpu backlight already enabled\n");
+ drm_dbg_kms(&i915->drm, "cpu backlight already enabled\n");
cpu_ctl2 &= ~BLM_PWM_ENABLE;
- intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, cpu_ctl2);
+ intel_de_write(i915, BLC_PWM_CPU_CTL2, cpu_ctl2);
}
- pch_ctl1 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1);
+ pch_ctl1 = intel_de_read(i915, BLC_PWM_PCH_CTL1);
if (pch_ctl1 & BLM_PCH_PWM_ENABLE) {
- drm_dbg_kms(&dev_priv->drm, "pch backlight already enabled\n");
+ drm_dbg_kms(&i915->drm, "pch backlight already enabled\n");
pch_ctl1 &= ~BLM_PCH_PWM_ENABLE;
- intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, pch_ctl1);
+ intel_de_write(i915, BLC_PWM_PCH_CTL1, pch_ctl1);
}
if (cpu_transcoder == TRANSCODER_EDP)
cpu_ctl2 = BLM_TRANSCODER_EDP;
else
cpu_ctl2 = BLM_PIPE(cpu_transcoder);
- intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, cpu_ctl2);
- intel_de_posting_read(dev_priv, BLC_PWM_CPU_CTL2);
- intel_de_write(dev_priv, BLC_PWM_CPU_CTL2, cpu_ctl2 | BLM_PWM_ENABLE);
+ intel_de_write(i915, BLC_PWM_CPU_CTL2, cpu_ctl2);
+ intel_de_posting_read(i915, BLC_PWM_CPU_CTL2);
+ intel_de_write(i915, BLC_PWM_CPU_CTL2, cpu_ctl2 | BLM_PWM_ENABLE);
/* This won't stick until the above enable. */
intel_backlight_set_pwm_level(conn_state, level);
pch_ctl2 = panel->backlight.pwm_level_max << 16;
- intel_de_write(dev_priv, BLC_PWM_PCH_CTL2, pch_ctl2);
+ intel_de_write(i915, BLC_PWM_PCH_CTL2, pch_ctl2);
pch_ctl1 = 0;
if (panel->backlight.active_low_pwm)
pch_ctl1 |= BLM_PCH_POLARITY;
- intel_de_write(dev_priv, BLC_PWM_PCH_CTL1, pch_ctl1);
- intel_de_posting_read(dev_priv, BLC_PWM_PCH_CTL1);
- intel_de_write(dev_priv, BLC_PWM_PCH_CTL1,
- pch_ctl1 | BLM_PCH_PWM_ENABLE);
+ intel_de_write(i915, BLC_PWM_PCH_CTL1, pch_ctl1);
+ intel_de_posting_read(i915, BLC_PWM_PCH_CTL1);
+ intel_de_write(i915, BLC_PWM_PCH_CTL1, pch_ctl1 | BLM_PCH_PWM_ENABLE);
}
static void i9xx_enable_backlight(const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state, u32 level)
{
struct intel_connector *connector = to_intel_connector(conn_state->connector);
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
u32 ctl, freq;
- ctl = intel_de_read(dev_priv, BLC_PWM_CTL);
+ ctl = intel_de_read(i915, BLC_PWM_CTL);
if (ctl & BACKLIGHT_DUTY_CYCLE_MASK_PNV) {
- drm_dbg_kms(&dev_priv->drm, "backlight already enabled\n");
- intel_de_write(dev_priv, BLC_PWM_CTL, 0);
+ drm_dbg_kms(&i915->drm, "backlight already enabled\n");
+ intel_de_write(i915, BLC_PWM_CTL, 0);
}
freq = panel->backlight.pwm_level_max;
@@ -598,11 +589,11 @@ static void i9xx_enable_backlight(const struct intel_crtc_state *crtc_state,
ctl = freq << 17;
if (panel->backlight.combination_mode)
ctl |= BLM_LEGACY_MODE;
- if (IS_PINEVIEW(dev_priv) && panel->backlight.active_low_pwm)
+ if (IS_PINEVIEW(i915) && panel->backlight.active_low_pwm)
ctl |= BLM_POLARITY_PNV;
- intel_de_write(dev_priv, BLC_PWM_CTL, ctl);
- intel_de_posting_read(dev_priv, BLC_PWM_CTL);
+ intel_de_write(i915, BLC_PWM_CTL, ctl);
+ intel_de_posting_read(i915, BLC_PWM_CTL);
/* XXX: combine this into above write? */
intel_backlight_set_pwm_level(conn_state, level);
@@ -612,24 +603,24 @@ static void i9xx_enable_backlight(const struct intel_crtc_state *crtc_state,
* 855gm only, but checking for gen2 is safe, as 855gm is the only gen2
* that has backlight.
*/
- if (DISPLAY_VER(dev_priv) == 2)
- intel_de_write(dev_priv, BLC_HIST_CTL, BLM_HISTOGRAM_ENABLE);
+ if (DISPLAY_VER(i915) == 2)
+ intel_de_write(i915, BLC_HIST_CTL, BLM_HISTOGRAM_ENABLE);
}
static void i965_enable_backlight(const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state, u32 level)
{
struct intel_connector *connector = to_intel_connector(conn_state->connector);
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
enum pipe pipe = to_intel_crtc(conn_state->crtc)->pipe;
u32 ctl, ctl2, freq;
- ctl2 = intel_de_read(dev_priv, BLC_PWM_CTL2);
+ ctl2 = intel_de_read(i915, BLC_PWM_CTL2);
if (ctl2 & BLM_PWM_ENABLE) {
- drm_dbg_kms(&dev_priv->drm, "backlight already enabled\n");
+ drm_dbg_kms(&i915->drm, "backlight already enabled\n");
ctl2 &= ~BLM_PWM_ENABLE;
- intel_de_write(dev_priv, BLC_PWM_CTL2, ctl2);
+ intel_de_write(i915, BLC_PWM_CTL2, ctl2);
}
freq = panel->backlight.pwm_level_max;
@@ -637,16 +628,16 @@ static void i965_enable_backlight(const struct intel_crtc_state *crtc_state,
freq /= 0xff;
ctl = freq << 16;
- intel_de_write(dev_priv, BLC_PWM_CTL, ctl);
+ intel_de_write(i915, BLC_PWM_CTL, ctl);
ctl2 = BLM_PIPE(pipe);
if (panel->backlight.combination_mode)
ctl2 |= BLM_COMBINATION_MODE;
if (panel->backlight.active_low_pwm)
ctl2 |= BLM_POLARITY_I965;
- intel_de_write(dev_priv, BLC_PWM_CTL2, ctl2);
- intel_de_posting_read(dev_priv, BLC_PWM_CTL2);
- intel_de_write(dev_priv, BLC_PWM_CTL2, ctl2 | BLM_PWM_ENABLE);
+ intel_de_write(i915, BLC_PWM_CTL2, ctl2);
+ intel_de_posting_read(i915, BLC_PWM_CTL2);
+ intel_de_write(i915, BLC_PWM_CTL2, ctl2 | BLM_PWM_ENABLE);
intel_backlight_set_pwm_level(conn_state, level);
}
@@ -655,20 +646,20 @@ static void vlv_enable_backlight(const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state, u32 level)
{
struct intel_connector *connector = to_intel_connector(conn_state->connector);
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
enum pipe pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe;
u32 ctl, ctl2;
- ctl2 = intel_de_read(dev_priv, VLV_BLC_PWM_CTL2(pipe));
+ ctl2 = intel_de_read(i915, VLV_BLC_PWM_CTL2(pipe));
if (ctl2 & BLM_PWM_ENABLE) {
- drm_dbg_kms(&dev_priv->drm, "backlight already enabled\n");
+ drm_dbg_kms(&i915->drm, "backlight already enabled\n");
ctl2 &= ~BLM_PWM_ENABLE;
- intel_de_write(dev_priv, VLV_BLC_PWM_CTL2(pipe), ctl2);
+ intel_de_write(i915, VLV_BLC_PWM_CTL2(pipe), ctl2);
}
ctl = panel->backlight.pwm_level_max << 16;
- intel_de_write(dev_priv, VLV_BLC_PWM_CTL(pipe), ctl);
+ intel_de_write(i915, VLV_BLC_PWM_CTL(pipe), ctl);
/* XXX: combine this into above write? */
intel_backlight_set_pwm_level(conn_state, level);
@@ -676,50 +667,45 @@ static void vlv_enable_backlight(const struct intel_crtc_state *crtc_state,
ctl2 = 0;
if (panel->backlight.active_low_pwm)
ctl2 |= BLM_POLARITY_I965;
- intel_de_write(dev_priv, VLV_BLC_PWM_CTL2(pipe), ctl2);
- intel_de_posting_read(dev_priv, VLV_BLC_PWM_CTL2(pipe));
- intel_de_write(dev_priv, VLV_BLC_PWM_CTL2(pipe),
- ctl2 | BLM_PWM_ENABLE);
+ intel_de_write(i915, VLV_BLC_PWM_CTL2(pipe), ctl2);
+ intel_de_posting_read(i915, VLV_BLC_PWM_CTL2(pipe));
+ intel_de_write(i915, VLV_BLC_PWM_CTL2(pipe), ctl2 | BLM_PWM_ENABLE);
}
static void bxt_enable_backlight(const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state, u32 level)
{
struct intel_connector *connector = to_intel_connector(conn_state->connector);
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
enum pipe pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe;
u32 pwm_ctl, val;
/* Controller 1 uses the utility pin. */
if (panel->backlight.controller == 1) {
- val = intel_de_read(dev_priv, UTIL_PIN_CTL);
+ val = intel_de_read(i915, UTIL_PIN_CTL);
if (val & UTIL_PIN_ENABLE) {
- drm_dbg_kms(&dev_priv->drm,
- "util pin already enabled\n");
+ drm_dbg_kms(&i915->drm, "util pin already enabled\n");
val &= ~UTIL_PIN_ENABLE;
- intel_de_write(dev_priv, UTIL_PIN_CTL, val);
+ intel_de_write(i915, UTIL_PIN_CTL, val);
}
val = 0;
if (panel->backlight.util_pin_active_low)
val |= UTIL_PIN_POLARITY;
- intel_de_write(dev_priv, UTIL_PIN_CTL,
+ intel_de_write(i915, UTIL_PIN_CTL,
val | UTIL_PIN_PIPE(pipe) | UTIL_PIN_MODE_PWM | UTIL_PIN_ENABLE);
}
- pwm_ctl = intel_de_read(dev_priv,
- BXT_BLC_PWM_CTL(panel->backlight.controller));
+ pwm_ctl = intel_de_read(i915, BXT_BLC_PWM_CTL(panel->backlight.controller));
if (pwm_ctl & BXT_BLC_PWM_ENABLE) {
- drm_dbg_kms(&dev_priv->drm, "backlight already enabled\n");
+ drm_dbg_kms(&i915->drm, "backlight already enabled\n");
pwm_ctl &= ~BXT_BLC_PWM_ENABLE;
- intel_de_write(dev_priv,
- BXT_BLC_PWM_CTL(panel->backlight.controller),
+ intel_de_write(i915, BXT_BLC_PWM_CTL(panel->backlight.controller),
pwm_ctl);
}
- intel_de_write(dev_priv,
- BXT_BLC_PWM_FREQ(panel->backlight.controller),
+ intel_de_write(i915, BXT_BLC_PWM_FREQ(panel->backlight.controller),
panel->backlight.pwm_level_max);
intel_backlight_set_pwm_level(conn_state, level);
@@ -728,11 +714,9 @@ static void bxt_enable_backlight(const struct intel_crtc_state *crtc_state,
if (panel->backlight.active_low_pwm)
pwm_ctl |= BXT_BLC_PWM_POLARITY;
- intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller),
- pwm_ctl);
- intel_de_posting_read(dev_priv,
- BXT_BLC_PWM_CTL(panel->backlight.controller));
- intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller),
+ intel_de_write(i915, BXT_BLC_PWM_CTL(panel->backlight.controller), pwm_ctl);
+ intel_de_posting_read(i915, BXT_BLC_PWM_CTL(panel->backlight.controller));
+ intel_de_write(i915, BXT_BLC_PWM_CTL(panel->backlight.controller),
pwm_ctl | BXT_BLC_PWM_ENABLE);
}
@@ -740,22 +724,19 @@ static void cnp_enable_backlight(const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state, u32 level)
{
struct intel_connector *connector = to_intel_connector(conn_state->connector);
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
u32 pwm_ctl;
- pwm_ctl = intel_de_read(dev_priv,
- BXT_BLC_PWM_CTL(panel->backlight.controller));
+ pwm_ctl = intel_de_read(i915, BXT_BLC_PWM_CTL(panel->backlight.controller));
if (pwm_ctl & BXT_BLC_PWM_ENABLE) {
- drm_dbg_kms(&dev_priv->drm, "backlight already enabled\n");
+ drm_dbg_kms(&i915->drm, "backlight already enabled\n");
pwm_ctl &= ~BXT_BLC_PWM_ENABLE;
- intel_de_write(dev_priv,
- BXT_BLC_PWM_CTL(panel->backlight.controller),
+ intel_de_write(i915, BXT_BLC_PWM_CTL(panel->backlight.controller),
pwm_ctl);
}
- intel_de_write(dev_priv,
- BXT_BLC_PWM_FREQ(panel->backlight.controller),
+ intel_de_write(i915, BXT_BLC_PWM_FREQ(panel->backlight.controller),
panel->backlight.pwm_level_max);
intel_backlight_set_pwm_level(conn_state, level);
@@ -764,11 +745,9 @@ static void cnp_enable_backlight(const struct intel_crtc_state *crtc_state,
if (panel->backlight.active_low_pwm)
pwm_ctl |= BXT_BLC_PWM_POLARITY;
- intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller),
- pwm_ctl);
- intel_de_posting_read(dev_priv,
- BXT_BLC_PWM_CTL(panel->backlight.controller));
- intel_de_write(dev_priv, BXT_BLC_PWM_CTL(panel->backlight.controller),
+ intel_de_write(i915, BXT_BLC_PWM_CTL(panel->backlight.controller), pwm_ctl);
+ intel_de_posting_read(i915, BXT_BLC_PWM_CTL(panel->backlight.controller));
+ intel_de_write(i915, BXT_BLC_PWM_CTL(panel->backlight.controller),
pwm_ctl | BXT_BLC_PWM_ENABLE);
}
@@ -810,37 +789,37 @@ void intel_backlight_enable(const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state)
{
struct intel_connector *connector = to_intel_connector(conn_state->connector);
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
enum pipe pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe;
if (!panel->backlight.present)
return;
- drm_dbg_kms(&dev_priv->drm, "pipe %c\n", pipe_name(pipe));
+ drm_dbg_kms(&i915->drm, "pipe %c\n", pipe_name(pipe));
- mutex_lock(&dev_priv->display.backlight.lock);
+ mutex_lock(&i915->display.backlight.lock);
__intel_backlight_enable(crtc_state, conn_state);
- mutex_unlock(&dev_priv->display.backlight.lock);
+ mutex_unlock(&i915->display.backlight.lock);
}
#if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE)
static u32 intel_panel_get_backlight(struct intel_connector *connector)
{
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
u32 val = 0;
- mutex_lock(&dev_priv->display.backlight.lock);
+ mutex_lock(&i915->display.backlight.lock);
if (panel->backlight.enabled)
val = panel->backlight.funcs->get(connector, intel_connector_get_pipe(connector));
- mutex_unlock(&dev_priv->display.backlight.lock);
+ mutex_unlock(&i915->display.backlight.lock);
- drm_dbg_kms(&dev_priv->drm, "get backlight PWM = %d\n", val);
+ drm_dbg_kms(&i915->drm, "get backlight PWM = %d\n", val);
return val;
}
@@ -859,16 +838,16 @@ static void intel_panel_set_backlight(const struct drm_connector_state *conn_sta
u32 user_level, u32 user_max)
{
struct intel_connector *connector = to_intel_connector(conn_state->connector);
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
u32 hw_level;
if (!panel->backlight.present)
return;
- mutex_lock(&dev_priv->display.backlight.lock);
+ mutex_lock(&i915->display.backlight.lock);
- drm_WARN_ON(&dev_priv->drm, panel->backlight.max == 0);
+ drm_WARN_ON(&i915->drm, panel->backlight.max == 0);
hw_level = scale_user_to_hw(connector, user_level, user_max);
panel->backlight.level = hw_level;
@@ -876,18 +855,19 @@ static void intel_panel_set_backlight(const struct drm_connector_state *conn_sta
if (panel->backlight.enabled)
intel_panel_actually_set_backlight(conn_state, hw_level);
- mutex_unlock(&dev_priv->display.backlight.lock);
+ mutex_unlock(&i915->display.backlight.lock);
}
static int intel_backlight_device_update_status(struct backlight_device *bd)
{
struct intel_connector *connector = bl_get_data(bd);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
- struct drm_device *dev = connector->base.dev;
- drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
- DRM_DEBUG_KMS("updating intel_backlight, brightness=%d/%d\n",
- bd->props.brightness, bd->props.max_brightness);
+ drm_modeset_lock(&i915->drm.mode_config.connection_mutex, NULL);
+
+ drm_dbg_kms(&i915->drm, "updating intel_backlight, brightness=%d/%d\n",
+ bd->props.brightness, bd->props.max_brightness);
intel_panel_set_backlight(connector->base.state, bd->props.brightness,
bd->props.max_brightness);
@@ -907,28 +887,28 @@ static int intel_backlight_device_update_status(struct backlight_device *bd)
bd->props.power = FB_BLANK_POWERDOWN;
}
- drm_modeset_unlock(&dev->mode_config.connection_mutex);
+ drm_modeset_unlock(&i915->drm.mode_config.connection_mutex);
+
return 0;
}
static int intel_backlight_device_get_brightness(struct backlight_device *bd)
{
struct intel_connector *connector = bl_get_data(bd);
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = to_i915(dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
intel_wakeref_t wakeref;
int ret = 0;
- with_intel_runtime_pm(&dev_priv->runtime_pm, wakeref) {
+ with_intel_runtime_pm(&i915->runtime_pm, wakeref) {
u32 hw_level;
- drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
+ drm_modeset_lock(&i915->drm.mode_config.connection_mutex, NULL);
hw_level = intel_panel_get_backlight(connector);
ret = scale_hw_to_user(connector,
hw_level, bd->props.max_brightness);
- drm_modeset_unlock(&dev->mode_config.connection_mutex);
+ drm_modeset_unlock(&i915->drm.mode_config.connection_mutex);
}
return ret;
@@ -1038,9 +1018,9 @@ void intel_backlight_device_unregister(struct intel_connector *connector)
*/
static u32 cnp_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
{
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
- return DIV_ROUND_CLOSEST(KHz(RUNTIME_INFO(dev_priv)->rawclk_freq),
+ return DIV_ROUND_CLOSEST(KHz(RUNTIME_INFO(i915)->rawclk_freq),
pwm_freq_hz);
}
@@ -1077,7 +1057,7 @@ static u32 spt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
*/
static u32 lpt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
{
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
u32 mul, clock;
@@ -1086,7 +1066,7 @@ static u32 lpt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
else
mul = 128;
- if (HAS_PCH_LPT_H(dev_priv))
+ if (HAS_PCH_LPT_H(i915))
clock = MHz(135); /* LPT:H */
else
clock = MHz(24); /* LPT:LP */
@@ -1100,9 +1080,9 @@ static u32 lpt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
*/
static u32 pch_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
{
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
- return DIV_ROUND_CLOSEST(KHz(RUNTIME_INFO(dev_priv)->rawclk_freq),
+ return DIV_ROUND_CLOSEST(KHz(RUNTIME_INFO(i915)->rawclk_freq),
pwm_freq_hz * 128);
}
@@ -1116,13 +1096,13 @@ static u32 pch_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
*/
static u32 i9xx_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
{
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
int clock;
- if (IS_PINEVIEW(dev_priv))
- clock = KHz(RUNTIME_INFO(dev_priv)->rawclk_freq);
+ if (IS_PINEVIEW(i915))
+ clock = KHz(RUNTIME_INFO(i915)->rawclk_freq);
else
- clock = KHz(dev_priv->display.cdclk.hw.cdclk);
+ clock = KHz(i915->display.cdclk.hw.cdclk);
return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * 32);
}
@@ -1134,13 +1114,13 @@ static u32 i9xx_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
*/
static u32 i965_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
{
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
int clock;
- if (IS_G4X(dev_priv))
- clock = KHz(RUNTIME_INFO(dev_priv)->rawclk_freq);
+ if (IS_G4X(i915))
+ clock = KHz(RUNTIME_INFO(i915)->rawclk_freq);
else
- clock = KHz(dev_priv->display.cdclk.hw.cdclk);
+ clock = KHz(i915->display.cdclk.hw.cdclk);
return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * 128);
}
@@ -1152,17 +1132,17 @@ static u32 i965_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
*/
static u32 vlv_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
{
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
int mul, clock;
- if ((intel_de_read(dev_priv, CBR1_VLV) & CBR_PWM_CLOCK_MUX_SELECT) == 0) {
- if (IS_CHERRYVIEW(dev_priv))
+ if ((intel_de_read(i915, CBR1_VLV) & CBR_PWM_CLOCK_MUX_SELECT) == 0) {
+ if (IS_CHERRYVIEW(i915))
clock = KHz(19200);
else
clock = MHz(25);
mul = 16;
} else {
- clock = KHz(RUNTIME_INFO(dev_priv)->rawclk_freq);
+ clock = KHz(RUNTIME_INFO(i915)->rawclk_freq);
mul = 128;
}
@@ -1171,16 +1151,16 @@ static u32 vlv_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
static u16 get_vbt_pwm_freq(struct intel_connector *connector)
{
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
u16 pwm_freq_hz = connector->panel.vbt.backlight.pwm_freq_hz;
if (pwm_freq_hz) {
- drm_dbg_kms(&dev_priv->drm,
+ drm_dbg_kms(&i915->drm,
"VBT defined backlight frequency %u Hz\n",
pwm_freq_hz);
} else {
pwm_freq_hz = 200;
- drm_dbg_kms(&dev_priv->drm,
+ drm_dbg_kms(&i915->drm,
"default backlight frequency %u Hz\n",
pwm_freq_hz);
}
@@ -1190,20 +1170,20 @@ static u16 get_vbt_pwm_freq(struct intel_connector *connector)
static u32 get_backlight_max_vbt(struct intel_connector *connector)
{
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
u16 pwm_freq_hz = get_vbt_pwm_freq(connector);
u32 pwm;
if (!panel->backlight.pwm_funcs->hz_to_pwm) {
- drm_dbg_kms(&dev_priv->drm,
+ drm_dbg_kms(&i915->drm,
"backlight frequency conversion not supported\n");
return 0;
}
pwm = panel->backlight.pwm_funcs->hz_to_pwm(connector, pwm_freq_hz);
if (!pwm) {
- drm_dbg_kms(&dev_priv->drm,
+ drm_dbg_kms(&i915->drm,
"backlight frequency conversion failed\n");
return 0;
}
@@ -1216,11 +1196,11 @@ static u32 get_backlight_max_vbt(struct intel_connector *connector)
*/
static u32 get_backlight_min_vbt(struct intel_connector *connector)
{
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
int min;
- drm_WARN_ON(&dev_priv->drm, panel->backlight.pwm_level_max == 0);
+ drm_WARN_ON(&i915->drm, panel->backlight.pwm_level_max == 0);
/*
* XXX: If the vbt value is 255, it makes min equal to max, which leads
@@ -1231,7 +1211,7 @@ static u32 get_backlight_min_vbt(struct intel_connector *connector)
*/
min = clamp_t(int, connector->panel.vbt.backlight.min_brightness, 0, 64);
if (min != connector->panel.vbt.backlight.min_brightness) {
- drm_dbg_kms(&dev_priv->drm,
+ drm_dbg_kms(&i915->drm,
"clamping VBT min backlight %d/255 to %d/255\n",
connector->panel.vbt.backlight.min_brightness, min);
}
@@ -1242,24 +1222,24 @@ static u32 get_backlight_min_vbt(struct intel_connector *connector)
static int lpt_setup_backlight(struct intel_connector *connector, enum pipe unused)
{
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
u32 cpu_ctl2, pch_ctl1, pch_ctl2, val;
bool alt, cpu_mode;
- if (HAS_PCH_LPT(dev_priv))
- alt = intel_de_read(dev_priv, SOUTH_CHICKEN2) & LPT_PWM_GRANULARITY;
+ if (HAS_PCH_LPT(i915))
+ alt = intel_de_read(i915, SOUTH_CHICKEN2) & LPT_PWM_GRANULARITY;
else
- alt = intel_de_read(dev_priv, SOUTH_CHICKEN1) & SPT_PWM_GRANULARITY;
+ alt = intel_de_read(i915, SOUTH_CHICKEN1) & SPT_PWM_GRANULARITY;
panel->backlight.alternate_pwm_increment = alt;
- pch_ctl1 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1);
+ pch_ctl1 = intel_de_read(i915, BLC_PWM_PCH_CTL1);
panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY;
- pch_ctl2 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL2);
+ pch_ctl2 = intel_de_read(i915, BLC_PWM_PCH_CTL2);
panel->backlight.pwm_level_max = pch_ctl2 >> 16;
- cpu_ctl2 = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2);
+ cpu_ctl2 = intel_de_read(i915, BLC_PWM_CPU_CTL2);
if (!panel->backlight.pwm_level_max)
panel->backlight.pwm_level_max = get_backlight_max_vbt(connector);
@@ -1271,22 +1251,22 @@ static int lpt_setup_backlight(struct intel_connector *connector, enum pipe unus
panel->backlight.pwm_enabled = pch_ctl1 & BLM_PCH_PWM_ENABLE;
- cpu_mode = panel->backlight.pwm_enabled && HAS_PCH_LPT(dev_priv) &&
+ cpu_mode = panel->backlight.pwm_enabled && HAS_PCH_LPT(i915) &&
!(pch_ctl1 & BLM_PCH_OVERRIDE_ENABLE) &&
(cpu_ctl2 & BLM_PWM_ENABLE);
if (cpu_mode) {
val = pch_get_backlight(connector, unused);
- drm_dbg_kms(&dev_priv->drm,
+ drm_dbg_kms(&i915->drm,
"CPU backlight register was enabled, switching to PCH override\n");
/* Write converted CPU PWM value to PCH override register */
lpt_set_backlight(connector->base.state, val);
- intel_de_write(dev_priv, BLC_PWM_PCH_CTL1,
+ intel_de_write(i915, BLC_PWM_PCH_CTL1,
pch_ctl1 | BLM_PCH_OVERRIDE_ENABLE);
- intel_de_write(dev_priv, BLC_PWM_CPU_CTL2,
+ intel_de_write(i915, BLC_PWM_CPU_CTL2,
cpu_ctl2 & ~BLM_PWM_ENABLE);
}
@@ -1295,14 +1275,14 @@ static int lpt_setup_backlight(struct intel_connector *connector, enum pipe unus
static int pch_setup_backlight(struct intel_connector *connector, enum pipe unused)
{
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
u32 cpu_ctl2, pch_ctl1, pch_ctl2;
- pch_ctl1 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL1);
+ pch_ctl1 = intel_de_read(i915, BLC_PWM_PCH_CTL1);
panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY;
- pch_ctl2 = intel_de_read(dev_priv, BLC_PWM_PCH_CTL2);
+ pch_ctl2 = intel_de_read(i915, BLC_PWM_PCH_CTL2);
panel->backlight.pwm_level_max = pch_ctl2 >> 16;
if (!panel->backlight.pwm_level_max)
@@ -1313,7 +1293,7 @@ static int pch_setup_backlight(struct intel_connector *connector, enum pipe unus
panel->backlight.pwm_level_min = get_backlight_min_vbt(connector);
- cpu_ctl2 = intel_de_read(dev_priv, BLC_PWM_CPU_CTL2);
+ cpu_ctl2 = intel_de_read(i915, BLC_PWM_CPU_CTL2);
panel->backlight.pwm_enabled = (cpu_ctl2 & BLM_PWM_ENABLE) &&
(pch_ctl1 & BLM_PCH_PWM_ENABLE);
@@ -1322,16 +1302,16 @@ static int pch_setup_backlight(struct intel_connector *connector, enum pipe unus
static int i9xx_setup_backlight(struct intel_connector *connector, enum pipe unused)
{
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
u32 ctl, val;
- ctl = intel_de_read(dev_priv, BLC_PWM_CTL);
+ ctl = intel_de_read(i915, BLC_PWM_CTL);
- if (DISPLAY_VER(dev_priv) == 2 || IS_I915GM(dev_priv) || IS_I945GM(dev_priv))
+ if (DISPLAY_VER(i915) == 2 || IS_I915GM(i915) || IS_I945GM(i915))
panel->backlight.combination_mode = ctl & BLM_LEGACY_MODE;
- if (IS_PINEVIEW(dev_priv))
+ if (IS_PINEVIEW(i915))
panel->backlight.active_low_pwm = ctl & BLM_POLARITY_PNV;
panel->backlight.pwm_level_max = ctl >> 17;
@@ -1360,15 +1340,15 @@ static int i9xx_setup_backlight(struct intel_connector *connector, enum pipe unu
static int i965_setup_backlight(struct intel_connector *connector, enum pipe unused)
{
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
u32 ctl, ctl2;
- ctl2 = intel_de_read(dev_priv, BLC_PWM_CTL2);
+ ctl2 = intel_de_read(i915, BLC_PWM_CTL2);
panel->backlight.combination_mode = ctl2 & BLM_COMBINATION_MODE;
panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965;
- ctl = intel_de_read(dev_priv, BLC_PWM_CTL);
+ ctl = intel_de_read(i915, BLC_PWM_CTL);
panel->backlight.pwm_level_max = ctl >> 16;
if (!panel->backlight.pwm_level_max)
@@ -1389,17 +1369,17 @@ static int i965_setup_backlight(struct intel_connector *connector, enum pipe unu
static int vlv_setup_backlight(struct intel_connector *connector, enum pipe pipe)
{
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
u32 ctl, ctl2;
- if (drm_WARN_ON(&dev_priv->drm, pipe != PIPE_A && pipe != PIPE_B))
+ if (drm_WARN_ON(&i915->drm, pipe != PIPE_A && pipe != PIPE_B))
return -ENODEV;
- ctl2 = intel_de_read(dev_priv, VLV_BLC_PWM_CTL2(pipe));
+ ctl2 = intel_de_read(i915, VLV_BLC_PWM_CTL2(pipe));
panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965;
- ctl = intel_de_read(dev_priv, VLV_BLC_PWM_CTL(pipe));
+ ctl = intel_de_read(i915, VLV_BLC_PWM_CTL(pipe));
panel->backlight.pwm_level_max = ctl >> 16;
if (!panel->backlight.pwm_level_max)
@@ -1418,25 +1398,25 @@ static int vlv_setup_backlight(struct intel_connector *connector, enum pipe pipe
static int
bxt_setup_backlight(struct intel_connector *connector, enum pipe unused)
{
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
u32 pwm_ctl, val;
panel->backlight.controller = connector->panel.vbt.backlight.controller;
- pwm_ctl = intel_de_read(dev_priv,
+ pwm_ctl = intel_de_read(i915,
BXT_BLC_PWM_CTL(panel->backlight.controller));
/* Controller 1 uses the utility pin. */
if (panel->backlight.controller == 1) {
- val = intel_de_read(dev_priv, UTIL_PIN_CTL);
+ val = intel_de_read(i915, UTIL_PIN_CTL);
panel->backlight.util_pin_active_low =
val & UTIL_PIN_POLARITY;
}
panel->backlight.active_low_pwm = pwm_ctl & BXT_BLC_PWM_POLARITY;
panel->backlight.pwm_level_max =
- intel_de_read(dev_priv, BXT_BLC_PWM_FREQ(panel->backlight.controller));
+ intel_de_read(i915, BXT_BLC_PWM_FREQ(panel->backlight.controller));
if (!panel->backlight.pwm_level_max)
panel->backlight.pwm_level_max = get_backlight_max_vbt(connector);
@@ -1451,26 +1431,54 @@ bxt_setup_backlight(struct intel_connector *connector, enum pipe unused)
return 0;
}
+static int cnp_num_backlight_controllers(struct drm_i915_private *i915)
+{
+ if (INTEL_PCH_TYPE(i915) >= PCH_DG1)
+ return 1;
+
+ if (INTEL_PCH_TYPE(i915) >= PCH_ICP)
+ return 2;
+
+ return 1;
+}
+
+static bool cnp_backlight_controller_is_valid(struct drm_i915_private *i915, int controller)
+{
+ if (controller < 0 || controller >= cnp_num_backlight_controllers(i915))
+ return false;
+
+ if (controller == 1 &&
+ INTEL_PCH_TYPE(i915) >= PCH_ICP &&
+ INTEL_PCH_TYPE(i915) < PCH_MTP)
+ return intel_de_read(i915, SOUTH_CHICKEN1) & ICP_SECOND_PPS_IO_SELECT;
+
+ return true;
+}
+
static int
cnp_setup_backlight(struct intel_connector *connector, enum pipe unused)
{
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
u32 pwm_ctl;
/*
* CNP has the BXT implementation of backlight, but with only one
- * controller. TODO: ICP has multiple controllers but we only use
- * controller 0 for now.
+ * controller. ICP+ can have two controllers, depending on pin muxing.
*/
- panel->backlight.controller = 0;
+ panel->backlight.controller = connector->panel.vbt.backlight.controller;
+ if (!cnp_backlight_controller_is_valid(i915, panel->backlight.controller)) {
+ drm_dbg_kms(&i915->drm, "Invalid backlight controller %d, assuming 0\n",
+ panel->backlight.controller);
+ panel->backlight.controller = 0;
+ }
- pwm_ctl = intel_de_read(dev_priv,
+ pwm_ctl = intel_de_read(i915,
BXT_BLC_PWM_CTL(panel->backlight.controller));
panel->backlight.active_low_pwm = pwm_ctl & BXT_BLC_PWM_POLARITY;
panel->backlight.pwm_level_max =
- intel_de_read(dev_priv, BXT_BLC_PWM_FREQ(panel->backlight.controller));
+ intel_de_read(i915, BXT_BLC_PWM_FREQ(panel->backlight.controller));
if (!panel->backlight.pwm_level_max)
panel->backlight.pwm_level_max = get_backlight_max_vbt(connector);
@@ -1488,23 +1496,22 @@ cnp_setup_backlight(struct intel_connector *connector, enum pipe unused)
static int ext_pwm_setup_backlight(struct intel_connector *connector,
enum pipe pipe)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = to_i915(dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
const char *desc;
u32 level;
/* Get the right PWM chip for DSI backlight according to VBT */
if (connector->panel.vbt.dsi.config->pwm_blc == PPS_BLC_PMIC) {
- panel->backlight.pwm = pwm_get(dev->dev, "pwm_pmic_backlight");
+ panel->backlight.pwm = pwm_get(i915->drm.dev, "pwm_pmic_backlight");
desc = "PMIC";
} else {
- panel->backlight.pwm = pwm_get(dev->dev, "pwm_soc_backlight");
+ panel->backlight.pwm = pwm_get(i915->drm.dev, "pwm_soc_backlight");
desc = "SoC";
}
if (IS_ERR(panel->backlight.pwm)) {
- drm_err(&dev_priv->drm, "Failed to get the %s PWM chip\n",
+ drm_err(&i915->drm, "Failed to get the %s PWM chip\n",
desc);
panel->backlight.pwm = NULL;
return -ENODEV;
@@ -1522,7 +1529,7 @@ static int ext_pwm_setup_backlight(struct intel_connector *connector,
level = intel_backlight_invert_pwm_level(connector, level);
panel->backlight.pwm_enabled = true;
- drm_dbg_kms(&dev_priv->drm, "PWM already enabled at freq %ld, VBT freq %d, level %d\n",
+ drm_dbg_kms(&i915->drm, "PWM already enabled at freq %ld, VBT freq %d, level %d\n",
NSEC_PER_SEC / (unsigned long)panel->backlight.pwm_state.period,
get_vbt_pwm_freq(connector), level);
} else {
@@ -1531,7 +1538,7 @@ static int ext_pwm_setup_backlight(struct intel_connector *connector,
NSEC_PER_SEC / get_vbt_pwm_freq(connector);
}
- drm_info(&dev_priv->drm, "Using %s PWM for LCD backlight control\n",
+ drm_info(&i915->drm, "Using %s PWM for LCD backlight control\n",
desc);
return 0;
}
@@ -1594,47 +1601,47 @@ void intel_backlight_update(struct intel_atomic_state *state,
const struct drm_connector_state *conn_state)
{
struct intel_connector *connector = to_intel_connector(conn_state->connector);
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
if (!panel->backlight.present)
return;
- mutex_lock(&dev_priv->display.backlight.lock);
+ mutex_lock(&i915->display.backlight.lock);
if (!panel->backlight.enabled)
__intel_backlight_enable(crtc_state, conn_state);
- mutex_unlock(&dev_priv->display.backlight.lock);
+ mutex_unlock(&i915->display.backlight.lock);
}
int intel_backlight_setup(struct intel_connector *connector, enum pipe pipe)
{
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_panel *panel = &connector->panel;
int ret;
if (!connector->panel.vbt.backlight.present) {
- if (intel_has_quirk(dev_priv, QUIRK_BACKLIGHT_PRESENT)) {
- drm_dbg_kms(&dev_priv->drm,
+ if (intel_has_quirk(i915, QUIRK_BACKLIGHT_PRESENT)) {
+ drm_dbg_kms(&i915->drm,
"no backlight present per VBT, but present per quirk\n");
} else {
- drm_dbg_kms(&dev_priv->drm,
+ drm_dbg_kms(&i915->drm,
"no backlight present per VBT\n");
return 0;
}
}
/* ensure intel_panel has been initialized first */
- if (drm_WARN_ON(&dev_priv->drm, !panel->backlight.funcs))
+ if (drm_WARN_ON(&i915->drm, !panel->backlight.funcs))
return -ENODEV;
/* set level and max in panel struct */
- mutex_lock(&dev_priv->display.backlight.lock);
+ mutex_lock(&i915->display.backlight.lock);
ret = panel->backlight.funcs->setup(connector, pipe);
- mutex_unlock(&dev_priv->display.backlight.lock);
+ mutex_unlock(&i915->display.backlight.lock);
if (ret) {
- drm_dbg_kms(&dev_priv->drm,
+ drm_dbg_kms(&i915->drm,
"failed to setup backlight for connector %s\n",
connector->base.name);
return ret;
@@ -1642,7 +1649,7 @@ int intel_backlight_setup(struct intel_connector *connector, enum pipe pipe)
panel->backlight.present = true;
- drm_dbg_kms(&dev_priv->drm,
+ drm_dbg_kms(&i915->drm,
"Connector %s backlight initialized, %s, brightness %u/%u\n",
connector->base.name,
str_enabled_disabled(panel->backlight.enabled),
@@ -1753,30 +1760,30 @@ void intel_backlight_init_funcs(struct intel_panel *panel)
{
struct intel_connector *connector =
container_of(panel, struct intel_connector, panel);
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
if (connector->base.connector_type == DRM_MODE_CONNECTOR_DSI &&
intel_dsi_dcs_init_backlight_funcs(connector) == 0)
return;
- if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) {
+ if (IS_GEMINILAKE(i915) || IS_BROXTON(i915)) {
panel->backlight.pwm_funcs = &bxt_pwm_funcs;
- } else if (INTEL_PCH_TYPE(dev_priv) >= PCH_CNP) {
+ } else if (INTEL_PCH_TYPE(i915) >= PCH_CNP) {
panel->backlight.pwm_funcs = &cnp_pwm_funcs;
- } else if (INTEL_PCH_TYPE(dev_priv) >= PCH_LPT) {
- if (HAS_PCH_LPT(dev_priv))
+ } else if (INTEL_PCH_TYPE(i915) >= PCH_LPT) {
+ if (HAS_PCH_LPT(i915))
panel->backlight.pwm_funcs = &lpt_pwm_funcs;
else
panel->backlight.pwm_funcs = &spt_pwm_funcs;
- } else if (HAS_PCH_SPLIT(dev_priv)) {
+ } else if (HAS_PCH_SPLIT(i915)) {
panel->backlight.pwm_funcs = &pch_pwm_funcs;
- } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
+ } else if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) {
if (connector->base.connector_type == DRM_MODE_CONNECTOR_DSI) {
panel->backlight.pwm_funcs = &ext_pwm_funcs;
} else {
panel->backlight.pwm_funcs = &vlv_pwm_funcs;
}
- } else if (DISPLAY_VER(dev_priv) == 4) {
+ } else if (DISPLAY_VER(i915) == 4) {
panel->backlight.pwm_funcs = &i965_pwm_funcs;
} else {
panel->backlight.pwm_funcs = &i9xx_pwm_funcs;
@@ -1786,7 +1793,7 @@ void intel_backlight_init_funcs(struct intel_panel *panel)
if (intel_dp_aux_init_backlight_funcs(connector) == 0)
return;
- if (!intel_has_quirk(dev_priv, QUIRK_NO_PPS_BACKLIGHT_POWER_HOOK))
+ if (!intel_has_quirk(i915, QUIRK_NO_PPS_BACKLIGHT_POWER_HOOK))
connector->panel.backlight.power = intel_pps_backlight_power;
}
diff --git a/drivers/gpu/drm/i915/display/intel_backlight_regs.h b/drivers/gpu/drm/i915/display/intel_backlight_regs.h
index 344eb8096bd2..d0cdfd631d75 100644
--- a/drivers/gpu/drm/i915/display/intel_backlight_regs.h
+++ b/drivers/gpu/drm/i915/display/intel_backlight_regs.h
@@ -8,23 +8,20 @@
#include "intel_display_reg_defs.h"
-#define _VLV_BLC_PWM_CTL2_A (DISPLAY_MMIO_BASE(dev_priv) + 0x61250)
-#define _VLV_BLC_PWM_CTL2_B (DISPLAY_MMIO_BASE(dev_priv) + 0x61350)
-#define VLV_BLC_PWM_CTL2(pipe) _MMIO_PIPE(pipe, _VLV_BLC_PWM_CTL2_A, \
- _VLV_BLC_PWM_CTL2_B)
+#define _VLV_BLC_PWM_CTL2_A (VLV_DISPLAY_BASE + 0x61250)
+#define _VLV_BLC_PWM_CTL2_B (VLV_DISPLAY_BASE + 0x61350)
+#define VLV_BLC_PWM_CTL2(pipe) _MMIO_PIPE(pipe, _VLV_BLC_PWM_CTL2_A, _VLV_BLC_PWM_CTL2_B)
-#define _VLV_BLC_PWM_CTL_A (DISPLAY_MMIO_BASE(dev_priv) + 0x61254)
-#define _VLV_BLC_PWM_CTL_B (DISPLAY_MMIO_BASE(dev_priv) + 0x61354)
-#define VLV_BLC_PWM_CTL(pipe) _MMIO_PIPE(pipe, _VLV_BLC_PWM_CTL_A, \
- _VLV_BLC_PWM_CTL_B)
+#define _VLV_BLC_PWM_CTL_A (VLV_DISPLAY_BASE + 0x61254)
+#define _VLV_BLC_PWM_CTL_B (VLV_DISPLAY_BASE + 0x61354)
+#define VLV_BLC_PWM_CTL(pipe) _MMIO_PIPE(pipe, _VLV_BLC_PWM_CTL_A, _VLV_BLC_PWM_CTL_B)
-#define _VLV_BLC_HIST_CTL_A (DISPLAY_MMIO_BASE(dev_priv) + 0x61260)
-#define _VLV_BLC_HIST_CTL_B (DISPLAY_MMIO_BASE(dev_priv) + 0x61360)
-#define VLV_BLC_HIST_CTL(pipe) _MMIO_PIPE(pipe, _VLV_BLC_HIST_CTL_A, \
- _VLV_BLC_HIST_CTL_B)
+#define _VLV_BLC_HIST_CTL_A (VLV_DISPLAY_BASE + 0x61260)
+#define _VLV_BLC_HIST_CTL_B (VLV_DISPLAY_BASE + 0x61360)
+#define VLV_BLC_HIST_CTL(pipe) _MMIO_PIPE(pipe, _VLV_BLC_HIST_CTL_A, _VLV_BLC_HIST_CTL_B)
/* Backlight control */
-#define BLC_PWM_CTL2 _MMIO(DISPLAY_MMIO_BASE(dev_priv) + 0x61250) /* 965+ only */
+#define BLC_PWM_CTL2 _MMIO(0x61250) /* 965+ only */
#define BLM_PWM_ENABLE (1 << 31)
#define BLM_COMBINATION_MODE (1 << 30) /* gen4 only */
#define BLM_PIPE_SELECT (1 << 29)
@@ -47,7 +44,7 @@
#define BLM_PHASE_IN_COUNT_MASK (0xff << 8)
#define BLM_PHASE_IN_INCR_SHIFT (0)
#define BLM_PHASE_IN_INCR_MASK (0xff << 0)
-#define BLC_PWM_CTL _MMIO(DISPLAY_MMIO_BASE(dev_priv) + 0x61254)
+#define BLC_PWM_CTL _MMIO(0x61254)
/*
* This is the most significant 15 bits of the number of backlight cycles in a
* complete cycle of the modulated backlight control.
@@ -69,7 +66,7 @@
#define BACKLIGHT_DUTY_CYCLE_MASK_PNV (0xfffe)
#define BLM_POLARITY_PNV (1 << 0) /* pnv only */
-#define BLC_HIST_CTL _MMIO(DISPLAY_MMIO_BASE(dev_priv) + 0x61260)
+#define BLC_HIST_CTL _MMIO(0x61260)
#define BLM_HISTOGRAM_ENABLE (1 << 31)
/* New registers for PCH-split platforms. Safe where new bits show up, the
diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c
index a491e6c38875..04b846440de6 100644
--- a/drivers/gpu/drm/i915/display/intel_bios.c
+++ b/drivers/gpu/drm/i915/display/intel_bios.c
@@ -25,16 +25,15 @@
*
*/
-#include <drm/drm_edid.h>
#include <drm/display/drm_dp_helper.h>
#include <drm/display/drm_dsc_helper.h>
-
-#include "display/intel_display.h"
-#include "display/intel_display_types.h"
-#include "display/intel_gmbus.h"
+#include <drm/drm_edid.h>
#include "i915_drv.h"
#include "i915_reg.h"
+#include "intel_display.h"
+#include "intel_display_types.h"
+#include "intel_gmbus.h"
#define _INTEL_BIOS_PRIVATE
#include "intel_vbt_defs.h"
@@ -620,14 +619,14 @@ static void dump_pnp_id(struct drm_i915_private *i915,
static int opregion_get_panel_type(struct drm_i915_private *i915,
const struct intel_bios_encoder_data *devdata,
- const struct edid *edid)
+ const struct drm_edid *drm_edid, bool use_fallback)
{
return intel_opregion_get_panel_type(i915);
}
static int vbt_get_panel_type(struct drm_i915_private *i915,
const struct intel_bios_encoder_data *devdata,
- const struct edid *edid)
+ const struct drm_edid *drm_edid, bool use_fallback)
{
const struct bdb_lvds_options *lvds_options;
@@ -652,12 +651,13 @@ static int vbt_get_panel_type(struct drm_i915_private *i915,
static int pnpid_get_panel_type(struct drm_i915_private *i915,
const struct intel_bios_encoder_data *devdata,
- const struct edid *edid)
+ const struct drm_edid *drm_edid, bool use_fallback)
{
const struct bdb_lvds_lfp_data *data;
const struct bdb_lvds_lfp_data_ptrs *ptrs;
const struct lvds_pnp_id *edid_id;
struct lvds_pnp_id edid_id_nodate;
+ const struct edid *edid = drm_edid_raw(drm_edid); /* FIXME */
int i, best = -1;
if (!edid)
@@ -701,9 +701,9 @@ static int pnpid_get_panel_type(struct drm_i915_private *i915,
static int fallback_get_panel_type(struct drm_i915_private *i915,
const struct intel_bios_encoder_data *devdata,
- const struct edid *edid)
+ const struct drm_edid *drm_edid, bool use_fallback)
{
- return 0;
+ return use_fallback ? 0 : -1;
}
enum panel_type {
@@ -715,13 +715,13 @@ enum panel_type {
static int get_panel_type(struct drm_i915_private *i915,
const struct intel_bios_encoder_data *devdata,
- const struct edid *edid)
+ const struct drm_edid *drm_edid, bool use_fallback)
{
struct {
const char *name;
int (*get_panel_type)(struct drm_i915_private *i915,
const struct intel_bios_encoder_data *devdata,
- const struct edid *edid);
+ const struct drm_edid *drm_edid, bool use_fallback);
int panel_type;
} panel_types[] = {
[PANEL_TYPE_OPREGION] = {
@@ -744,7 +744,8 @@ static int get_panel_type(struct drm_i915_private *i915,
int i;
for (i = 0; i < ARRAY_SIZE(panel_types); i++) {
- panel_types[i].panel_type = panel_types[i].get_panel_type(i915, devdata, edid);
+ panel_types[i].panel_type = panel_types[i].get_panel_type(i915, devdata,
+ drm_edid, use_fallback);
drm_WARN_ON(&i915->drm, panel_types[i].panel_type > 0xf &&
panel_types[i].panel_type != 0xff);
@@ -1032,6 +1033,7 @@ parse_lfp_backlight(struct drm_i915_private *i915,
}
panel->vbt.backlight.type = INTEL_BACKLIGHT_DISPLAY_DDI;
+ panel->vbt.backlight.controller = 0;
if (i915->display.vbt.version >= 191) {
size_t exp_size;
@@ -2592,6 +2594,12 @@ intel_bios_encoder_supports_edp(const struct intel_bios_encoder_data *devdata)
devdata->child.device_type & DEVICE_TYPE_INTERNAL_CONNECTOR;
}
+static bool
+intel_bios_encoder_supports_dsi(const struct intel_bios_encoder_data *devdata)
+{
+ return devdata->child.device_type & DEVICE_TYPE_MIPI_OUTPUT;
+}
+
static int _intel_bios_hdmi_level_shift(const struct intel_bios_encoder_data *devdata)
{
if (!devdata || devdata->i915->display.vbt.version < 158)
@@ -2642,7 +2650,7 @@ static void print_ddi_port(const struct intel_bios_encoder_data *devdata,
{
struct drm_i915_private *i915 = devdata->i915;
const struct child_device_config *child = &devdata->child;
- bool is_dvi, is_hdmi, is_dp, is_edp, is_crt, supports_typec_usb, supports_tbt;
+ bool is_dvi, is_hdmi, is_dp, is_edp, is_dsi, is_crt, supports_typec_usb, supports_tbt;
int dp_boost_level, dp_max_link_rate, hdmi_boost_level, hdmi_level_shift, max_tmds_clock;
is_dvi = intel_bios_encoder_supports_dvi(devdata);
@@ -2650,13 +2658,14 @@ static void print_ddi_port(const struct intel_bios_encoder_data *devdata,
is_crt = intel_bios_encoder_supports_crt(devdata);
is_hdmi = intel_bios_encoder_supports_hdmi(devdata);
is_edp = intel_bios_encoder_supports_edp(devdata);
+ is_dsi = intel_bios_encoder_supports_dsi(devdata);
supports_typec_usb = intel_bios_encoder_supports_typec_usb(devdata);
supports_tbt = intel_bios_encoder_supports_tbt(devdata);
drm_dbg_kms(&i915->drm,
- "Port %c VBT info: CRT:%d DVI:%d HDMI:%d DP:%d eDP:%d LSPCON:%d USB-Type-C:%d TBT:%d DSC:%d\n",
- port_name(port), is_crt, is_dvi, is_hdmi, is_dp, is_edp,
+ "Port %c VBT info: CRT:%d DVI:%d HDMI:%d DP:%d eDP:%d DSI:%d LSPCON:%d USB-Type-C:%d TBT:%d DSC:%d\n",
+ port_name(port), is_crt, is_dvi, is_hdmi, is_dp, is_edp, is_dsi,
HAS_LSPCON(i915) && child->lspcon,
supports_typec_usb, supports_tbt,
devdata->dsc != NULL);
@@ -2709,6 +2718,8 @@ static void parse_ddi_port(struct intel_bios_encoder_data *devdata)
enum port port;
port = dvo_port_to_port(i915, child->dvo_port);
+ if (port == PORT_NONE && DISPLAY_VER(i915) >= 11)
+ port = dsi_dvo_port_to_port(i915, child->dvo_port);
if (port == PORT_NONE)
return;
@@ -3199,14 +3210,26 @@ out:
kfree(oprom_vbt);
}
-void intel_bios_init_panel(struct drm_i915_private *i915,
- struct intel_panel *panel,
- const struct intel_bios_encoder_data *devdata,
- const struct edid *edid)
+static void intel_bios_init_panel(struct drm_i915_private *i915,
+ struct intel_panel *panel,
+ const struct intel_bios_encoder_data *devdata,
+ const struct drm_edid *drm_edid,
+ bool use_fallback)
{
- init_vbt_panel_defaults(panel);
+ /* already have it? */
+ if (panel->vbt.panel_type >= 0) {
+ drm_WARN_ON(&i915->drm, !use_fallback);
+ return;
+ }
- panel->vbt.panel_type = get_panel_type(i915, devdata, edid);
+ panel->vbt.panel_type = get_panel_type(i915, devdata,
+ drm_edid, use_fallback);
+ if (panel->vbt.panel_type < 0) {
+ drm_WARN_ON(&i915->drm, use_fallback);
+ return;
+ }
+
+ init_vbt_panel_defaults(panel);
parse_panel_options(i915, panel);
parse_generic_dtd(i915, panel);
@@ -3221,6 +3244,21 @@ void intel_bios_init_panel(struct drm_i915_private *i915,
parse_mipi_sequence(i915, panel);
}
+void intel_bios_init_panel_early(struct drm_i915_private *i915,
+ struct intel_panel *panel,
+ const struct intel_bios_encoder_data *devdata)
+{
+ intel_bios_init_panel(i915, panel, devdata, NULL, false);
+}
+
+void intel_bios_init_panel_late(struct drm_i915_private *i915,
+ struct intel_panel *panel,
+ const struct intel_bios_encoder_data *devdata,
+ const struct drm_edid *drm_edid)
+{
+ intel_bios_init_panel(i915, panel, devdata, drm_edid, true);
+}
+
/**
* intel_bios_driver_remove - Free any resources allocated by intel_bios_init()
* @i915: i915 device instance
diff --git a/drivers/gpu/drm/i915/display/intel_bios.h b/drivers/gpu/drm/i915/display/intel_bios.h
index e375405a7828..d221f784aa88 100644
--- a/drivers/gpu/drm/i915/display/intel_bios.h
+++ b/drivers/gpu/drm/i915/display/intel_bios.h
@@ -32,8 +32,8 @@
#include <linux/types.h>
+struct drm_edid;
struct drm_i915_private;
-struct edid;
struct intel_bios_encoder_data;
struct intel_crtc_state;
struct intel_encoder;
@@ -232,10 +232,13 @@ struct mipi_pps_data {
} __packed;
void intel_bios_init(struct drm_i915_private *dev_priv);
-void intel_bios_init_panel(struct drm_i915_private *dev_priv,
- struct intel_panel *panel,
- const struct intel_bios_encoder_data *devdata,
- const struct edid *edid);
+void intel_bios_init_panel_early(struct drm_i915_private *dev_priv,
+ struct intel_panel *panel,
+ const struct intel_bios_encoder_data *devdata);
+void intel_bios_init_panel_late(struct drm_i915_private *dev_priv,
+ struct intel_panel *panel,
+ const struct intel_bios_encoder_data *devdata,
+ const struct drm_edid *drm_edid);
void intel_bios_fini_panel(struct intel_panel *panel);
void intel_bios_driver_remove(struct drm_i915_private *dev_priv);
bool intel_bios_is_valid_vbt(const void *buf, size_t size);
diff --git a/drivers/gpu/drm/i915/display/intel_bw.h b/drivers/gpu/drm/i915/display/intel_bw.h
index cb7ee3a24a58..f20292143745 100644
--- a/drivers/gpu/drm/i915/display/intel_bw.h
+++ b/drivers/gpu/drm/i915/display/intel_bw.h
@@ -8,7 +8,7 @@
#include <drm/drm_atomic.h>
-#include "intel_display.h"
+#include "intel_display_limits.h"
#include "intel_display_power.h"
#include "intel_global_state.h"
diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c
index 407a477939e5..7e16b655c833 100644
--- a/drivers/gpu/drm/i915/display/intel_cdclk.c
+++ b/drivers/gpu/drm/i915/display/intel_cdclk.c
@@ -1346,6 +1346,16 @@ static const struct intel_cdclk_vals dg2_cdclk_table[] = {
{}
};
+static const struct intel_cdclk_vals mtl_cdclk_table[] = {
+ { .refclk = 38400, .cdclk = 172800, .divider = 2, .ratio = 16, .waveform = 0xad5a },
+ { .refclk = 38400, .cdclk = 192000, .divider = 2, .ratio = 16, .waveform = 0xb6b6 },
+ { .refclk = 38400, .cdclk = 307200, .divider = 2, .ratio = 16, .waveform = 0x0000 },
+ { .refclk = 38400, .cdclk = 480000, .divider = 2, .ratio = 25, .waveform = 0x0000 },
+ { .refclk = 38400, .cdclk = 556800, .divider = 2, .ratio = 29, .waveform = 0x0000 },
+ { .refclk = 38400, .cdclk = 652800, .divider = 2, .ratio = 34, .waveform = 0x0000 },
+ {}
+};
+
static int bxt_calc_cdclk(struct drm_i915_private *dev_priv, int min_cdclk)
{
const struct intel_cdclk_vals *table = dev_priv->display.cdclk.table;
@@ -1717,39 +1727,92 @@ static void dg2_cdclk_squash_program(struct drm_i915_private *i915,
intel_de_write(i915, CDCLK_SQUASH_CTL, squash_ctl);
}
-static void bxt_set_cdclk(struct drm_i915_private *dev_priv,
- const struct intel_cdclk_config *cdclk_config,
- enum pipe pipe)
+static bool cdclk_pll_is_unknown(unsigned int vco)
+{
+ /*
+ * Ensure driver does not take the crawl path for the
+ * case when the vco is set to ~0 in the
+ * sanitize path.
+ */
+ return vco == ~0;
+}
+
+static int cdclk_squash_divider(u16 waveform)
+{
+ return hweight16(waveform ?: 0xffff);
+}
+
+static bool cdclk_compute_crawl_and_squash_midpoint(struct drm_i915_private *i915,
+ const struct intel_cdclk_config *old_cdclk_config,
+ const struct intel_cdclk_config *new_cdclk_config,
+ struct intel_cdclk_config *mid_cdclk_config)
+{
+ u16 old_waveform, new_waveform, mid_waveform;
+ int size = 16;
+ int div = 2;
+
+ /* Return if PLL is in an unknown state, force a complete disable and re-enable. */
+ if (cdclk_pll_is_unknown(old_cdclk_config->vco))
+ return false;
+
+ /* Return if both Squash and Crawl are not present */
+ if (!HAS_CDCLK_CRAWL(i915) || !HAS_CDCLK_SQUASH(i915))
+ return false;
+
+ old_waveform = cdclk_squash_waveform(i915, old_cdclk_config->cdclk);
+ new_waveform = cdclk_squash_waveform(i915, new_cdclk_config->cdclk);
+
+ /* Return if Squash only or Crawl only is the desired action */
+ if (old_cdclk_config->vco == 0 || new_cdclk_config->vco == 0 ||
+ old_cdclk_config->vco == new_cdclk_config->vco ||
+ old_waveform == new_waveform)
+ return false;
+
+ *mid_cdclk_config = *new_cdclk_config;
+
+ /*
+ * Populate the mid_cdclk_config accordingly.
+ * - If moving to a higher cdclk, the desired action is squashing.
+ * The mid cdclk config should have the new (squash) waveform.
+ * - If moving to a lower cdclk, the desired action is crawling.
+ * The mid cdclk config should have the new vco.
+ */
+
+ if (cdclk_squash_divider(new_waveform) > cdclk_squash_divider(old_waveform)) {
+ mid_cdclk_config->vco = old_cdclk_config->vco;
+ mid_waveform = new_waveform;
+ } else {
+ mid_cdclk_config->vco = new_cdclk_config->vco;
+ mid_waveform = old_waveform;
+ }
+
+ mid_cdclk_config->cdclk = DIV_ROUND_CLOSEST(cdclk_squash_divider(mid_waveform) *
+ mid_cdclk_config->vco, size * div);
+
+ /* make sure the mid clock came out sane */
+
+ drm_WARN_ON(&i915->drm, mid_cdclk_config->cdclk <
+ min(old_cdclk_config->cdclk, new_cdclk_config->cdclk));
+ drm_WARN_ON(&i915->drm, mid_cdclk_config->cdclk >
+ i915->display.cdclk.max_cdclk_freq);
+ drm_WARN_ON(&i915->drm, cdclk_squash_waveform(i915, mid_cdclk_config->cdclk) !=
+ mid_waveform);
+
+ return true;
+}
+
+static void _bxt_set_cdclk(struct drm_i915_private *dev_priv,
+ const struct intel_cdclk_config *cdclk_config,
+ enum pipe pipe)
{
int cdclk = cdclk_config->cdclk;
int vco = cdclk_config->vco;
u32 val;
u16 waveform;
int clock;
- int ret;
-
- /* Inform power controller of upcoming frequency change. */
- if (DISPLAY_VER(dev_priv) >= 11)
- ret = skl_pcode_request(&dev_priv->uncore, SKL_PCODE_CDCLK_CONTROL,
- SKL_CDCLK_PREPARE_FOR_CHANGE,
- SKL_CDCLK_READY_FOR_CHANGE,
- SKL_CDCLK_READY_FOR_CHANGE, 3);
- else
- /*
- * BSpec requires us to wait up to 150usec, but that leads to
- * timeouts; the 2ms used here is based on experiment.
- */
- ret = snb_pcode_write_timeout(&dev_priv->uncore,
- HSW_PCODE_DE_WRITE_FREQ_REQ,
- 0x80000000, 150, 2);
- if (ret) {
- drm_err(&dev_priv->drm,
- "Failed to inform PCU about cdclk change (err %d, freq %d)\n",
- ret, cdclk);
- return;
- }
- if (HAS_CDCLK_CRAWL(dev_priv) && dev_priv->display.cdclk.hw.vco > 0 && vco > 0) {
+ if (HAS_CDCLK_CRAWL(dev_priv) && dev_priv->display.cdclk.hw.vco > 0 && vco > 0 &&
+ !cdclk_pll_is_unknown(dev_priv->display.cdclk.hw.vco)) {
if (dev_priv->display.cdclk.hw.vco != vco)
adlp_cdclk_pll_crawl(dev_priv, vco);
} else if (DISPLAY_VER(dev_priv) >= 11)
@@ -1782,11 +1845,62 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv,
if (pipe != INVALID_PIPE)
intel_crtc_wait_for_next_vblank(intel_crtc_for_pipe(dev_priv, pipe));
+}
- if (DISPLAY_VER(dev_priv) >= 11) {
+static void bxt_set_cdclk(struct drm_i915_private *dev_priv,
+ const struct intel_cdclk_config *cdclk_config,
+ enum pipe pipe)
+{
+ struct intel_cdclk_config mid_cdclk_config;
+ int cdclk = cdclk_config->cdclk;
+ int ret = 0;
+
+ /*
+ * Inform power controller of upcoming frequency change.
+ * Display versions 14 and beyond do not follow the PUnit
+ * mailbox communication, skip
+ * this step.
+ */
+ if (DISPLAY_VER(dev_priv) >= 14)
+ /* NOOP */;
+ else if (DISPLAY_VER(dev_priv) >= 11)
+ ret = skl_pcode_request(&dev_priv->uncore, SKL_PCODE_CDCLK_CONTROL,
+ SKL_CDCLK_PREPARE_FOR_CHANGE,
+ SKL_CDCLK_READY_FOR_CHANGE,
+ SKL_CDCLK_READY_FOR_CHANGE, 3);
+ else
+ /*
+ * BSpec requires us to wait up to 150usec, but that leads to
+ * timeouts; the 2ms used here is based on experiment.
+ */
+ ret = snb_pcode_write_timeout(&dev_priv->uncore,
+ HSW_PCODE_DE_WRITE_FREQ_REQ,
+ 0x80000000, 150, 2);
+
+ if (ret) {
+ drm_err(&dev_priv->drm,
+ "Failed to inform PCU about cdclk change (err %d, freq %d)\n",
+ ret, cdclk);
+ return;
+ }
+
+ if (cdclk_compute_crawl_and_squash_midpoint(dev_priv, &dev_priv->display.cdclk.hw,
+ cdclk_config, &mid_cdclk_config)) {
+ _bxt_set_cdclk(dev_priv, &mid_cdclk_config, pipe);
+ _bxt_set_cdclk(dev_priv, cdclk_config, pipe);
+ } else {
+ _bxt_set_cdclk(dev_priv, cdclk_config, pipe);
+ }
+
+ if (DISPLAY_VER(dev_priv) >= 14)
+ /*
+ * NOOP - No Pcode communication needed for
+ * Display versions 14 and beyond
+ */;
+ else if (DISPLAY_VER(dev_priv) >= 11)
ret = snb_pcode_write(&dev_priv->uncore, SKL_PCODE_CDCLK_CONTROL,
cdclk_config->voltage_level);
- } else {
+ else
/*
* The timeout isn't specified, the 2ms used here is based on
* experiment.
@@ -1797,7 +1911,6 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv,
HSW_PCODE_DE_WRITE_FREQ_REQ,
cdclk_config->voltage_level,
150, 2);
- }
if (ret) {
drm_err(&dev_priv->drm,
@@ -1954,6 +2067,28 @@ void intel_cdclk_uninit_hw(struct drm_i915_private *i915)
skl_cdclk_uninit_hw(i915);
}
+static bool intel_cdclk_can_crawl_and_squash(struct drm_i915_private *i915,
+ const struct intel_cdclk_config *a,
+ const struct intel_cdclk_config *b)
+{
+ u16 old_waveform;
+ u16 new_waveform;
+
+ drm_WARN_ON(&i915->drm, cdclk_pll_is_unknown(a->vco));
+
+ if (a->vco == 0 || b->vco == 0)
+ return false;
+
+ if (!HAS_CDCLK_CRAWL(i915) || !HAS_CDCLK_SQUASH(i915))
+ return false;
+
+ old_waveform = cdclk_squash_waveform(i915, a->cdclk);
+ new_waveform = cdclk_squash_waveform(i915, b->cdclk);
+
+ return a->vco != b->vco &&
+ old_waveform != new_waveform;
+}
+
static bool intel_cdclk_can_crawl(struct drm_i915_private *dev_priv,
const struct intel_cdclk_config *a,
const struct intel_cdclk_config *b)
@@ -2760,9 +2895,14 @@ int intel_modeset_calc_cdclk(struct intel_atomic_state *state)
pipe = INVALID_PIPE;
}
- if (intel_cdclk_can_squash(dev_priv,
- &old_cdclk_state->actual,
- &new_cdclk_state->actual)) {
+ if (intel_cdclk_can_crawl_and_squash(dev_priv,
+ &old_cdclk_state->actual,
+ &new_cdclk_state->actual)) {
+ drm_dbg_kms(&dev_priv->drm,
+ "Can change cdclk via crawling and squashing\n");
+ } else if (intel_cdclk_can_squash(dev_priv,
+ &old_cdclk_state->actual,
+ &new_cdclk_state->actual)) {
drm_dbg_kms(&dev_priv->drm,
"Can change cdclk via squashing\n");
} else if (intel_cdclk_can_crawl(dev_priv,
@@ -3060,6 +3200,13 @@ u32 intel_read_rawclk(struct drm_i915_private *dev_priv)
return freq;
}
+static const struct intel_cdclk_funcs mtl_cdclk_funcs = {
+ .get_cdclk = bxt_get_cdclk,
+ .set_cdclk = bxt_set_cdclk,
+ .modeset_calc_cdclk = bxt_modeset_calc_cdclk,
+ .calc_voltage_level = tgl_calc_voltage_level,
+};
+
static const struct intel_cdclk_funcs tgl_cdclk_funcs = {
.get_cdclk = bxt_get_cdclk,
.set_cdclk = bxt_set_cdclk,
@@ -3195,7 +3342,10 @@ static const struct intel_cdclk_funcs i830_cdclk_funcs = {
*/
void intel_init_cdclk_hooks(struct drm_i915_private *dev_priv)
{
- if (IS_DG2(dev_priv)) {
+ if (IS_METEORLAKE(dev_priv)) {
+ dev_priv->display.funcs.cdclk = &mtl_cdclk_funcs;
+ dev_priv->display.cdclk.table = mtl_cdclk_table;
+ } else if (IS_DG2(dev_priv)) {
dev_priv->display.funcs.cdclk = &tgl_cdclk_funcs;
dev_priv->display.cdclk.table = dg2_cdclk_table;
} else if (IS_ALDERLAKE_P(dev_priv)) {
diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.h b/drivers/gpu/drm/i915/display/intel_cdclk.h
index c674879a84a5..51e2f6a11ce4 100644
--- a/drivers/gpu/drm/i915/display/intel_cdclk.h
+++ b/drivers/gpu/drm/i915/display/intel_cdclk.h
@@ -8,7 +8,7 @@
#include <linux/types.h>
-#include "intel_display.h"
+#include "intel_display_limits.h"
#include "intel_global_state.h"
struct drm_i915_private;
diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c
index 250e83f1f5ac..8d97c299e657 100644
--- a/drivers/gpu/drm/i915/display/intel_color.c
+++ b/drivers/gpu/drm/i915/display/intel_color.c
@@ -53,7 +53,18 @@ struct intel_color_funcs {
* involved with the same commit.
*/
void (*load_luts)(const struct intel_crtc_state *crtc_state);
+ /*
+ * Read out the LUTs from the hardware into the software state.
+ * Used by eg. the hardware state checker.
+ */
void (*read_luts)(struct intel_crtc_state *crtc_state);
+ /*
+ * Compare the LUTs
+ */
+ bool (*lut_equal)(const struct intel_crtc_state *crtc_state,
+ const struct drm_property_blob *blob1,
+ const struct drm_property_blob *blob2,
+ bool is_pre_csc_lut);
};
#define CTM_COEFF_SIGN (1ULL << 63)
@@ -143,15 +154,7 @@ static const u16 ilk_csc_postoff_rgb_to_ycbcr[3] = {
static bool lut_is_legacy(const struct drm_property_blob *lut)
{
- return drm_color_lut_size(lut) == LEGACY_LUT_LENGTH;
-}
-
-static bool crtc_state_is_legacy_gamma(const struct intel_crtc_state *crtc_state)
-{
- return !crtc_state->hw.degamma_lut &&
- !crtc_state->hw.ctm &&
- crtc_state->hw.gamma_lut &&
- lut_is_legacy(crtc_state->hw.gamma_lut);
+ return lut && drm_color_lut_size(lut) == LEGACY_LUT_LENGTH;
}
/*
@@ -246,17 +249,44 @@ static void icl_update_output_csc(struct intel_crtc *crtc,
intel_de_write_fw(i915, PIPE_CSC_OUTPUT_POSTOFF_LO(pipe), postoff[2]);
}
-static bool ilk_csc_limited_range(const struct intel_crtc_state *crtc_state)
+static bool ilk_limited_range(const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
- /*
- * FIXME if there's a gamma LUT after the CSC, we should
- * do the range compression using the gamma LUT instead.
- */
- return crtc_state->limited_color_range &&
- (IS_HASWELL(i915) || IS_BROADWELL(i915) ||
- IS_DISPLAY_VER(i915, 9, 10));
+ /* icl+ have dedicated output CSC */
+ if (DISPLAY_VER(i915) >= 11)
+ return false;
+
+ /* pre-hsw have PIPECONF_COLOR_RANGE_SELECT */
+ if (DISPLAY_VER(i915) < 7 || IS_IVYBRIDGE(i915))
+ return false;
+
+ return crtc_state->limited_color_range;
+}
+
+static bool ilk_lut_limited_range(const struct intel_crtc_state *crtc_state)
+{
+ struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
+
+ if (!ilk_limited_range(crtc_state))
+ return false;
+
+ if (crtc_state->c8_planes)
+ return false;
+
+ if (DISPLAY_VER(i915) == 10)
+ return crtc_state->hw.gamma_lut;
+ else
+ return crtc_state->hw.gamma_lut &&
+ (crtc_state->hw.degamma_lut || crtc_state->hw.ctm);
+}
+
+static bool ilk_csc_limited_range(const struct intel_crtc_state *crtc_state)
+{
+ if (!ilk_limited_range(crtc_state))
+ return false;
+
+ return !ilk_lut_limited_range(crtc_state);
}
static void ilk_csc_convert_ctm(const struct intel_crtc_state *crtc_state,
@@ -437,6 +467,79 @@ static void i9xx_lut_8_pack(struct drm_color_lut *entry, u32 val)
entry->blue = intel_color_lut_pack(REG_FIELD_GET(PALETTE_BLUE_MASK, val), 8);
}
+/* i8xx/i9xx+ 10bit slope format "even DW" (low 8 bits) */
+static u32 _i9xx_lut_10_ldw(u16 a)
+{
+ return drm_color_lut_extract(a, 10) & 0xff;
+}
+
+static u32 i9xx_lut_10_ldw(const struct drm_color_lut *color)
+{
+ return REG_FIELD_PREP(PALETTE_RED_MASK, _i9xx_lut_10_ldw(color[0].red)) |
+ REG_FIELD_PREP(PALETTE_GREEN_MASK, _i9xx_lut_10_ldw(color[0].green)) |
+ REG_FIELD_PREP(PALETTE_BLUE_MASK, _i9xx_lut_10_ldw(color[0].blue));
+}
+
+/* i8xx/i9xx+ 10bit slope format "odd DW" (high 2 bits + slope) */
+static u32 _i9xx_lut_10_udw(u16 a, u16 b)
+{
+ unsigned int mantissa, exponent;
+
+ a = drm_color_lut_extract(a, 10);
+ b = drm_color_lut_extract(b, 10);
+
+ /* b = a + 8 * m * 2 ^ -e */
+ mantissa = clamp(b - a, 0, 0x7f);
+ exponent = 3;
+ while (mantissa > 0xf) {
+ mantissa >>= 1;
+ exponent--;
+ }
+
+ return (exponent << 6) |
+ (mantissa << 2) |
+ (a >> 8);
+}
+
+static u32 i9xx_lut_10_udw(const struct drm_color_lut *color)
+{
+ return REG_FIELD_PREP(PALETTE_RED_MASK, _i9xx_lut_10_udw(color[0].red, color[1].red)) |
+ REG_FIELD_PREP(PALETTE_GREEN_MASK, _i9xx_lut_10_udw(color[0].green, color[1].green)) |
+ REG_FIELD_PREP(PALETTE_BLUE_MASK, _i9xx_lut_10_udw(color[0].blue, color[1].blue));
+}
+
+static void i9xx_lut_10_pack(struct drm_color_lut *color,
+ u32 ldw, u32 udw)
+{
+ u16 red = REG_FIELD_GET(PALETTE_10BIT_RED_LDW_MASK, ldw) |
+ REG_FIELD_GET(PALETTE_10BIT_RED_UDW_MASK, udw) << 8;
+ u16 green = REG_FIELD_GET(PALETTE_10BIT_GREEN_LDW_MASK, ldw) |
+ REG_FIELD_GET(PALETTE_10BIT_GREEN_UDW_MASK, udw) << 8;
+ u16 blue = REG_FIELD_GET(PALETTE_10BIT_BLUE_LDW_MASK, ldw) |
+ REG_FIELD_GET(PALETTE_10BIT_BLUE_UDW_MASK, udw) << 8;
+
+ color->red = intel_color_lut_pack(red, 10);
+ color->green = intel_color_lut_pack(green, 10);
+ color->blue = intel_color_lut_pack(blue, 10);
+}
+
+static void i9xx_lut_10_pack_slope(struct drm_color_lut *color,
+ u32 ldw, u32 udw)
+{
+ int r_exp = REG_FIELD_GET(PALETTE_10BIT_RED_EXP_MASK, udw);
+ int r_mant = REG_FIELD_GET(PALETTE_10BIT_RED_MANT_MASK, udw);
+ int g_exp = REG_FIELD_GET(PALETTE_10BIT_GREEN_EXP_MASK, udw);
+ int g_mant = REG_FIELD_GET(PALETTE_10BIT_GREEN_MANT_MASK, udw);
+ int b_exp = REG_FIELD_GET(PALETTE_10BIT_BLUE_EXP_MASK, udw);
+ int b_mant = REG_FIELD_GET(PALETTE_10BIT_BLUE_MANT_MASK, udw);
+
+ i9xx_lut_10_pack(color, ldw, udw);
+
+ color->red += r_mant << (3 - r_exp);
+ color->green += g_mant << (3 - g_exp);
+ color->blue += b_mant << (3 - b_exp);
+}
+
/* i965+ "10.6" bit interpolated format "even DW" (low 8 bits) */
static u32 i965_lut_10p6_ldw(const struct drm_color_lut *color)
{
@@ -600,9 +703,18 @@ create_linear_lut(struct drm_i915_private *i915, int lut_size)
return blob;
}
+static u16 lut_limited_range(unsigned int value)
+{
+ unsigned int min = 16 << 8;
+ unsigned int max = 235 << 8;
+
+ return value * (max - min) / 0xffff + min;
+}
+
static struct drm_property_blob *
create_resized_lut(struct drm_i915_private *i915,
- const struct drm_property_blob *blob_in, int lut_out_size)
+ const struct drm_property_blob *blob_in, int lut_out_size,
+ bool limited_color_range)
{
int i, lut_in_size = drm_color_lut_size(blob_in);
struct drm_property_blob *blob_out;
@@ -618,8 +730,18 @@ create_resized_lut(struct drm_i915_private *i915,
lut_in = blob_in->data;
lut_out = blob_out->data;
- for (i = 0; i < lut_out_size; i++)
- lut_out[i] = lut_in[i * (lut_in_size - 1) / (lut_out_size - 1)];
+ for (i = 0; i < lut_out_size; i++) {
+ const struct drm_color_lut *entry =
+ &lut_in[i * (lut_in_size - 1) / (lut_out_size - 1)];
+
+ if (limited_color_range) {
+ lut_out[i].red = lut_limited_range(entry->red);
+ lut_out[i].green = lut_limited_range(entry->green);
+ lut_out[i].blue = lut_limited_range(entry->blue);
+ } else {
+ lut_out[i] = *entry;
+ }
+ }
return blob_out;
}
@@ -642,12 +764,38 @@ static void i9xx_load_lut_8(struct intel_crtc *crtc,
i9xx_lut_8(&lut[i]));
}
+static void i9xx_load_lut_10(struct intel_crtc *crtc,
+ const struct drm_property_blob *blob)
+{
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ const struct drm_color_lut *lut = blob->data;
+ int i, lut_size = drm_color_lut_size(blob);
+ enum pipe pipe = crtc->pipe;
+
+ for (i = 0; i < lut_size - 1; i++) {
+ intel_de_write_fw(dev_priv, PALETTE(pipe, 2 * i + 0),
+ i9xx_lut_10_ldw(&lut[i]));
+ intel_de_write_fw(dev_priv, PALETTE(pipe, 2 * i + 1),
+ i9xx_lut_10_udw(&lut[i]));
+ }
+}
+
static void i9xx_load_luts(const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
const struct drm_property_blob *post_csc_lut = crtc_state->post_csc_lut;
- i9xx_load_lut_8(crtc, post_csc_lut);
+ switch (crtc_state->gamma_mode) {
+ case GAMMA_MODE_MODE_8BIT:
+ i9xx_load_lut_8(crtc, post_csc_lut);
+ break;
+ case GAMMA_MODE_MODE_10BIT:
+ i9xx_load_lut_10(crtc, post_csc_lut);
+ break;
+ default:
+ MISSING_CASE(crtc_state->gamma_mode);
+ break;
+ }
}
static void i965_load_lut_10p6(struct intel_crtc *crtc,
@@ -675,16 +823,34 @@ static void i965_load_luts(const struct intel_crtc_state *crtc_state)
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
const struct drm_property_blob *post_csc_lut = crtc_state->post_csc_lut;
- if (crtc_state->gamma_mode == GAMMA_MODE_MODE_8BIT)
+ switch (crtc_state->gamma_mode) {
+ case GAMMA_MODE_MODE_8BIT:
i9xx_load_lut_8(crtc, post_csc_lut);
- else
+ break;
+ case GAMMA_MODE_MODE_10BIT:
i965_load_lut_10p6(crtc, post_csc_lut);
+ break;
+ default:
+ MISSING_CASE(crtc_state->gamma_mode);
+ break;
+ }
}
-static void ilk_load_lut_8(struct intel_crtc *crtc,
+static void ilk_lut_write(const struct intel_crtc_state *crtc_state,
+ i915_reg_t reg, u32 val)
+{
+ struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
+
+ if (crtc_state->dsb)
+ intel_dsb_reg_write(crtc_state->dsb, reg, val);
+ else
+ intel_de_write_fw(i915, reg, val);
+}
+
+static void ilk_load_lut_8(const struct intel_crtc_state *crtc_state,
const struct drm_property_blob *blob)
{
- struct drm_i915_private *i915 = to_i915(crtc->base.dev);
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
const struct drm_color_lut *lut;
enum pipe pipe = crtc->pipe;
int i;
@@ -695,36 +861,35 @@ static void ilk_load_lut_8(struct intel_crtc *crtc,
lut = blob->data;
for (i = 0; i < 256; i++)
- intel_de_write_fw(i915, LGC_PALETTE(pipe, i),
- i9xx_lut_8(&lut[i]));
+ ilk_lut_write(crtc_state, LGC_PALETTE(pipe, i),
+ i9xx_lut_8(&lut[i]));
}
-static void ilk_load_lut_10(struct intel_crtc *crtc,
+static void ilk_load_lut_10(const struct intel_crtc_state *crtc_state,
const struct drm_property_blob *blob)
{
- struct drm_i915_private *i915 = to_i915(crtc->base.dev);
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
const struct drm_color_lut *lut = blob->data;
int i, lut_size = drm_color_lut_size(blob);
enum pipe pipe = crtc->pipe;
for (i = 0; i < lut_size; i++)
- intel_de_write_fw(i915, PREC_PALETTE(pipe, i),
- ilk_lut_10(&lut[i]));
+ ilk_lut_write(crtc_state, PREC_PALETTE(pipe, i),
+ ilk_lut_10(&lut[i]));
}
static void ilk_load_luts(const struct intel_crtc_state *crtc_state)
{
- struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
const struct drm_property_blob *post_csc_lut = crtc_state->post_csc_lut;
const struct drm_property_blob *pre_csc_lut = crtc_state->pre_csc_lut;
const struct drm_property_blob *blob = post_csc_lut ?: pre_csc_lut;
switch (crtc_state->gamma_mode) {
case GAMMA_MODE_MODE_8BIT:
- ilk_load_lut_8(crtc, blob);
+ ilk_load_lut_8(crtc_state, blob);
break;
case GAMMA_MODE_MODE_10BIT:
- ilk_load_lut_10(crtc, blob);
+ ilk_load_lut_10(crtc_state, blob);
break;
default:
MISSING_CASE(crtc_state->gamma_mode);
@@ -745,50 +910,56 @@ static int ivb_lut_10_size(u32 prec_index)
* "Restriction : Index auto increment mode is not
* supported and must not be enabled."
*/
-static void ivb_load_lut_10(struct intel_crtc *crtc,
+static void ivb_load_lut_10(const struct intel_crtc_state *crtc_state,
const struct drm_property_blob *blob,
u32 prec_index)
{
- struct drm_i915_private *i915 = to_i915(crtc->base.dev);
+ const struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
const struct drm_color_lut *lut = blob->data;
int i, lut_size = drm_color_lut_size(blob);
enum pipe pipe = crtc->pipe;
for (i = 0; i < lut_size; i++) {
- intel_de_write_fw(i915, PREC_PAL_INDEX(pipe), prec_index++);
- intel_de_write_fw(i915, PREC_PAL_DATA(pipe),
- ilk_lut_10(&lut[i]));
+ ilk_lut_write(crtc_state, PREC_PAL_INDEX(pipe),
+ prec_index + i);
+ ilk_lut_write(crtc_state, PREC_PAL_DATA(pipe),
+ ilk_lut_10(&lut[i]));
}
/*
* Reset the index, otherwise it prevents the legacy palette to be
* written properly.
*/
- intel_de_write_fw(i915, PREC_PAL_INDEX(pipe), 0);
+ ilk_lut_write(crtc_state, PREC_PAL_INDEX(pipe),
+ PAL_PREC_INDEX_VALUE(0));
}
/* On BDW+ the index auto increment mode actually works */
-static void bdw_load_lut_10(struct intel_crtc *crtc,
+static void bdw_load_lut_10(const struct intel_crtc_state *crtc_state,
const struct drm_property_blob *blob,
u32 prec_index)
{
- struct drm_i915_private *i915 = to_i915(crtc->base.dev);
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
const struct drm_color_lut *lut = blob->data;
int i, lut_size = drm_color_lut_size(blob);
enum pipe pipe = crtc->pipe;
- intel_de_write_fw(i915, PREC_PAL_INDEX(pipe),
- prec_index | PAL_PREC_AUTO_INCREMENT);
+ ilk_lut_write(crtc_state, PREC_PAL_INDEX(pipe),
+ prec_index);
+ ilk_lut_write(crtc_state, PREC_PAL_INDEX(pipe),
+ PAL_PREC_AUTO_INCREMENT |
+ prec_index);
for (i = 0; i < lut_size; i++)
- intel_de_write_fw(i915, PREC_PAL_DATA(pipe),
- ilk_lut_10(&lut[i]));
+ ilk_lut_write(crtc_state, PREC_PAL_DATA(pipe),
+ ilk_lut_10(&lut[i]));
/*
* Reset the index, otherwise it prevents the legacy palette to be
* written properly.
*/
- intel_de_write_fw(i915, PREC_PAL_INDEX(pipe), 0);
+ ilk_lut_write(crtc_state, PREC_PAL_INDEX(pipe),
+ PAL_PREC_INDEX_VALUE(0));
}
static void ivb_load_lut_ext_max(const struct intel_crtc_state *crtc_state)
@@ -797,9 +968,9 @@ static void ivb_load_lut_ext_max(const struct intel_crtc_state *crtc_state)
enum pipe pipe = crtc->pipe;
/* Program the max register to clamp values > 1.0. */
- intel_dsb_reg_write(crtc_state, PREC_PAL_EXT_GC_MAX(pipe, 0), 1 << 16);
- intel_dsb_reg_write(crtc_state, PREC_PAL_EXT_GC_MAX(pipe, 1), 1 << 16);
- intel_dsb_reg_write(crtc_state, PREC_PAL_EXT_GC_MAX(pipe, 2), 1 << 16);
+ ilk_lut_write(crtc_state, PREC_PAL_EXT_GC_MAX(pipe, 0), 1 << 16);
+ ilk_lut_write(crtc_state, PREC_PAL_EXT_GC_MAX(pipe, 1), 1 << 16);
+ ilk_lut_write(crtc_state, PREC_PAL_EXT_GC_MAX(pipe, 2), 1 << 16);
}
static void glk_load_lut_ext2_max(const struct intel_crtc_state *crtc_state)
@@ -808,31 +979,30 @@ static void glk_load_lut_ext2_max(const struct intel_crtc_state *crtc_state)
enum pipe pipe = crtc->pipe;
/* Program the max register to clamp values > 1.0. */
- intel_dsb_reg_write(crtc_state, PREC_PAL_EXT2_GC_MAX(pipe, 0), 1 << 16);
- intel_dsb_reg_write(crtc_state, PREC_PAL_EXT2_GC_MAX(pipe, 1), 1 << 16);
- intel_dsb_reg_write(crtc_state, PREC_PAL_EXT2_GC_MAX(pipe, 2), 1 << 16);
+ ilk_lut_write(crtc_state, PREC_PAL_EXT2_GC_MAX(pipe, 0), 1 << 16);
+ ilk_lut_write(crtc_state, PREC_PAL_EXT2_GC_MAX(pipe, 1), 1 << 16);
+ ilk_lut_write(crtc_state, PREC_PAL_EXT2_GC_MAX(pipe, 2), 1 << 16);
}
static void ivb_load_luts(const struct intel_crtc_state *crtc_state)
{
- struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
const struct drm_property_blob *post_csc_lut = crtc_state->post_csc_lut;
const struct drm_property_blob *pre_csc_lut = crtc_state->pre_csc_lut;
const struct drm_property_blob *blob = post_csc_lut ?: pre_csc_lut;
switch (crtc_state->gamma_mode) {
case GAMMA_MODE_MODE_8BIT:
- ilk_load_lut_8(crtc, blob);
+ ilk_load_lut_8(crtc_state, blob);
break;
case GAMMA_MODE_MODE_SPLIT:
- ivb_load_lut_10(crtc, pre_csc_lut, PAL_PREC_SPLIT_MODE |
+ ivb_load_lut_10(crtc_state, pre_csc_lut, PAL_PREC_SPLIT_MODE |
PAL_PREC_INDEX_VALUE(0));
ivb_load_lut_ext_max(crtc_state);
- ivb_load_lut_10(crtc, post_csc_lut, PAL_PREC_SPLIT_MODE |
+ ivb_load_lut_10(crtc_state, post_csc_lut, PAL_PREC_SPLIT_MODE |
PAL_PREC_INDEX_VALUE(512));
break;
case GAMMA_MODE_MODE_10BIT:
- ivb_load_lut_10(crtc, blob,
+ ivb_load_lut_10(crtc_state, blob,
PAL_PREC_INDEX_VALUE(0));
ivb_load_lut_ext_max(crtc_state);
break;
@@ -844,25 +1014,23 @@ static void ivb_load_luts(const struct intel_crtc_state *crtc_state)
static void bdw_load_luts(const struct intel_crtc_state *crtc_state)
{
- struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
const struct drm_property_blob *post_csc_lut = crtc_state->post_csc_lut;
const struct drm_property_blob *pre_csc_lut = crtc_state->pre_csc_lut;
const struct drm_property_blob *blob = post_csc_lut ?: pre_csc_lut;
switch (crtc_state->gamma_mode) {
case GAMMA_MODE_MODE_8BIT:
- ilk_load_lut_8(crtc, blob);
+ ilk_load_lut_8(crtc_state, blob);
break;
case GAMMA_MODE_MODE_SPLIT:
- bdw_load_lut_10(crtc, pre_csc_lut, PAL_PREC_SPLIT_MODE |
+ bdw_load_lut_10(crtc_state, pre_csc_lut, PAL_PREC_SPLIT_MODE |
PAL_PREC_INDEX_VALUE(0));
ivb_load_lut_ext_max(crtc_state);
- bdw_load_lut_10(crtc, post_csc_lut, PAL_PREC_SPLIT_MODE |
+ bdw_load_lut_10(crtc_state, post_csc_lut, PAL_PREC_SPLIT_MODE |
PAL_PREC_INDEX_VALUE(512));
break;
case GAMMA_MODE_MODE_10BIT:
-
- bdw_load_lut_10(crtc, blob,
+ bdw_load_lut_10(crtc_state, blob,
PAL_PREC_INDEX_VALUE(0));
ivb_load_lut_ext_max(crtc_state);
break;
@@ -894,9 +1062,11 @@ static void glk_load_degamma_lut(const struct intel_crtc_state *crtc_state,
* ignore the index bits, so we need to reset it to index 0
* separately.
*/
- intel_de_write_fw(i915, PRE_CSC_GAMC_INDEX(pipe), 0);
- intel_de_write_fw(i915, PRE_CSC_GAMC_INDEX(pipe),
- PRE_CSC_GAMC_AUTO_INCREMENT);
+ ilk_lut_write(crtc_state, PRE_CSC_GAMC_INDEX(pipe),
+ PRE_CSC_GAMC_INDEX_VALUE(0));
+ ilk_lut_write(crtc_state, PRE_CSC_GAMC_INDEX(pipe),
+ PRE_CSC_GAMC_AUTO_INCREMENT |
+ PRE_CSC_GAMC_INDEX_VALUE(0));
for (i = 0; i < lut_size; i++) {
/*
@@ -912,32 +1082,31 @@ static void glk_load_degamma_lut(const struct intel_crtc_state *crtc_state,
* ToDo: Extend to max 7.0. Enable 32 bit input value
* as compared to just 16 to achieve this.
*/
- intel_de_write_fw(i915, PRE_CSC_GAMC_DATA(pipe),
- lut[i].green);
+ ilk_lut_write(crtc_state, PRE_CSC_GAMC_DATA(pipe),
+ lut[i].green);
}
/* Clamp values > 1.0. */
while (i++ < glk_degamma_lut_size(i915))
- intel_de_write_fw(i915, PRE_CSC_GAMC_DATA(pipe), 1 << 16);
+ ilk_lut_write(crtc_state, PRE_CSC_GAMC_DATA(pipe), 1 << 16);
- intel_de_write_fw(i915, PRE_CSC_GAMC_INDEX(pipe), 0);
+ ilk_lut_write(crtc_state, PRE_CSC_GAMC_INDEX(pipe), 0);
}
static void glk_load_luts(const struct intel_crtc_state *crtc_state)
{
const struct drm_property_blob *pre_csc_lut = crtc_state->pre_csc_lut;
const struct drm_property_blob *post_csc_lut = crtc_state->post_csc_lut;
- struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
if (pre_csc_lut)
glk_load_degamma_lut(crtc_state, pre_csc_lut);
switch (crtc_state->gamma_mode) {
case GAMMA_MODE_MODE_8BIT:
- ilk_load_lut_8(crtc, post_csc_lut);
+ ilk_load_lut_8(crtc_state, post_csc_lut);
break;
case GAMMA_MODE_MODE_10BIT:
- bdw_load_lut_10(crtc, post_csc_lut, PAL_PREC_INDEX_VALUE(0));
+ bdw_load_lut_10(crtc_state, post_csc_lut, PAL_PREC_INDEX_VALUE(0));
ivb_load_lut_ext_max(crtc_state);
glk_load_lut_ext2_max(crtc_state);
break;
@@ -955,9 +1124,9 @@ ivb_load_lut_max(const struct intel_crtc_state *crtc_state,
enum pipe pipe = crtc->pipe;
/* FIXME LUT entries are 16 bit only, so we can prog 0xFFFF max */
- intel_dsb_reg_write(crtc_state, PREC_PAL_GC_MAX(pipe, 0), color->red);
- intel_dsb_reg_write(crtc_state, PREC_PAL_GC_MAX(pipe, 1), color->green);
- intel_dsb_reg_write(crtc_state, PREC_PAL_GC_MAX(pipe, 2), color->blue);
+ ilk_lut_write(crtc_state, PREC_PAL_GC_MAX(pipe, 0), color->red);
+ ilk_lut_write(crtc_state, PREC_PAL_GC_MAX(pipe, 1), color->green);
+ ilk_lut_write(crtc_state, PREC_PAL_GC_MAX(pipe, 2), color->blue);
}
static void
@@ -976,17 +1145,23 @@ icl_program_gamma_superfine_segment(const struct intel_crtc_state *crtc_state)
* 9 entries, corresponding to values 0, 1/(8 * 128 * 256),
* 2/(8 * 128 * 256) ... 8/(8 * 128 * 256).
*/
- intel_dsb_reg_write(crtc_state, PREC_PAL_MULTI_SEG_INDEX(pipe),
- PAL_PREC_AUTO_INCREMENT);
+ ilk_lut_write(crtc_state, PREC_PAL_MULTI_SEG_INDEX(pipe),
+ PAL_PREC_MULTI_SEG_INDEX_VALUE(0));
+ ilk_lut_write(crtc_state, PREC_PAL_MULTI_SEG_INDEX(pipe),
+ PAL_PREC_AUTO_INCREMENT |
+ PAL_PREC_MULTI_SEG_INDEX_VALUE(0));
for (i = 0; i < 9; i++) {
const struct drm_color_lut *entry = &lut[i];
- intel_dsb_indexed_reg_write(crtc_state, PREC_PAL_MULTI_SEG_DATA(pipe),
- ilk_lut_12p4_ldw(entry));
- intel_dsb_indexed_reg_write(crtc_state, PREC_PAL_MULTI_SEG_DATA(pipe),
- ilk_lut_12p4_udw(entry));
+ ilk_lut_write(crtc_state, PREC_PAL_MULTI_SEG_DATA(pipe),
+ ilk_lut_12p4_ldw(entry));
+ ilk_lut_write(crtc_state, PREC_PAL_MULTI_SEG_DATA(pipe),
+ ilk_lut_12p4_udw(entry));
}
+
+ ilk_lut_write(crtc_state, PREC_PAL_MULTI_SEG_INDEX(pipe),
+ PAL_PREC_MULTI_SEG_INDEX_VALUE(0));
}
static void
@@ -1009,14 +1184,19 @@ icl_program_gamma_multi_segment(const struct intel_crtc_state *crtc_state)
* PAL_PREC_INDEX[0] and PAL_PREC_INDEX[1] map to seg2[1],
* seg2[0] being unused by the hardware.
*/
- intel_dsb_reg_write(crtc_state, PREC_PAL_INDEX(pipe),
- PAL_PREC_AUTO_INCREMENT);
+ ilk_lut_write(crtc_state, PREC_PAL_INDEX(pipe),
+ PAL_PREC_INDEX_VALUE(0));
+ ilk_lut_write(crtc_state, PREC_PAL_INDEX(pipe),
+ PAL_PREC_AUTO_INCREMENT |
+ PAL_PREC_INDEX_VALUE(0));
+
for (i = 1; i < 257; i++) {
entry = &lut[i * 8];
- intel_dsb_indexed_reg_write(crtc_state, PREC_PAL_DATA(pipe),
- ilk_lut_12p4_ldw(entry));
- intel_dsb_indexed_reg_write(crtc_state, PREC_PAL_DATA(pipe),
- ilk_lut_12p4_udw(entry));
+
+ ilk_lut_write(crtc_state, PREC_PAL_DATA(pipe),
+ ilk_lut_12p4_ldw(entry));
+ ilk_lut_write(crtc_state, PREC_PAL_DATA(pipe),
+ ilk_lut_12p4_udw(entry));
}
/*
@@ -1033,12 +1213,16 @@ icl_program_gamma_multi_segment(const struct intel_crtc_state *crtc_state)
*/
for (i = 0; i < 256; i++) {
entry = &lut[i * 8 * 128];
- intel_dsb_indexed_reg_write(crtc_state, PREC_PAL_DATA(pipe),
- ilk_lut_12p4_ldw(entry));
- intel_dsb_indexed_reg_write(crtc_state, PREC_PAL_DATA(pipe),
- ilk_lut_12p4_udw(entry));
+
+ ilk_lut_write(crtc_state, PREC_PAL_DATA(pipe),
+ ilk_lut_12p4_ldw(entry));
+ ilk_lut_write(crtc_state, PREC_PAL_DATA(pipe),
+ ilk_lut_12p4_udw(entry));
}
+ ilk_lut_write(crtc_state, PREC_PAL_INDEX(pipe),
+ PAL_PREC_INDEX_VALUE(0));
+
/* The last entry in the LUT is to be programmed in GCMAX */
entry = &lut[256 * 8 * 128];
ivb_load_lut_max(crtc_state, entry);
@@ -1048,23 +1232,22 @@ static void icl_load_luts(const struct intel_crtc_state *crtc_state)
{
const struct drm_property_blob *pre_csc_lut = crtc_state->pre_csc_lut;
const struct drm_property_blob *post_csc_lut = crtc_state->post_csc_lut;
- struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
if (pre_csc_lut)
glk_load_degamma_lut(crtc_state, pre_csc_lut);
switch (crtc_state->gamma_mode & GAMMA_MODE_MODE_MASK) {
case GAMMA_MODE_MODE_8BIT:
- ilk_load_lut_8(crtc, post_csc_lut);
+ ilk_load_lut_8(crtc_state, post_csc_lut);
break;
- case GAMMA_MODE_MODE_12BIT_MULTI_SEGMENTED:
+ case GAMMA_MODE_MODE_12BIT_MULTI_SEG:
icl_program_gamma_superfine_segment(crtc_state);
icl_program_gamma_multi_segment(crtc_state);
ivb_load_lut_ext_max(crtc_state);
glk_load_lut_ext2_max(crtc_state);
break;
case GAMMA_MODE_MODE_10BIT:
- bdw_load_lut_10(crtc, post_csc_lut, PAL_PREC_INDEX_VALUE(0));
+ bdw_load_lut_10(crtc_state, post_csc_lut, PAL_PREC_INDEX_VALUE(0));
ivb_load_lut_ext_max(crtc_state);
glk_load_lut_ext2_max(crtc_state);
break;
@@ -1073,7 +1256,8 @@ static void icl_load_luts(const struct intel_crtc_state *crtc_state)
break;
}
- intel_dsb_commit(crtc_state);
+ if (crtc_state->dsb)
+ intel_dsb_commit(crtc_state->dsb);
}
static u32 chv_cgm_degamma_ldw(const struct drm_color_lut *color)
@@ -1087,6 +1271,13 @@ static u32 chv_cgm_degamma_udw(const struct drm_color_lut *color)
return REG_FIELD_PREP(CGM_PIPE_DEGAMMA_RED_UDW_MASK, drm_color_lut_extract(color->red, 14));
}
+static void chv_cgm_degamma_pack(struct drm_color_lut *entry, u32 ldw, u32 udw)
+{
+ entry->green = intel_color_lut_pack(REG_FIELD_GET(CGM_PIPE_DEGAMMA_GREEN_LDW_MASK, ldw), 14);
+ entry->blue = intel_color_lut_pack(REG_FIELD_GET(CGM_PIPE_DEGAMMA_BLUE_LDW_MASK, ldw), 14);
+ entry->red = intel_color_lut_pack(REG_FIELD_GET(CGM_PIPE_DEGAMMA_RED_UDW_MASK, udw), 14);
+}
+
static void chv_load_cgm_degamma(struct intel_crtc *crtc,
const struct drm_property_blob *blob)
{
@@ -1182,6 +1373,25 @@ void intel_color_commit_arm(const struct intel_crtc_state *crtc_state)
i915->display.funcs.color->color_commit_arm(crtc_state);
}
+void intel_color_prepare_commit(struct intel_crtc_state *crtc_state)
+{
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+
+ /* FIXME DSB has issues loading LUTs, disable it for now */
+ return;
+
+ crtc_state->dsb = intel_dsb_prepare(crtc, 1024);
+}
+
+void intel_color_cleanup_commit(struct intel_crtc_state *crtc_state)
+{
+ if (!crtc_state->dsb)
+ return;
+
+ intel_dsb_cleanup(crtc_state->dsb);
+ crtc_state->dsb = NULL;
+}
+
static bool intel_can_preload_luts(const struct intel_crtc_state *new_crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc);
@@ -1224,8 +1434,25 @@ void intel_color_get_config(struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
- if (i915->display.funcs.color->read_luts)
- i915->display.funcs.color->read_luts(crtc_state);
+ i915->display.funcs.color->read_luts(crtc_state);
+}
+
+bool intel_color_lut_equal(const struct intel_crtc_state *crtc_state,
+ const struct drm_property_blob *blob1,
+ const struct drm_property_blob *blob2,
+ bool is_pre_csc_lut)
+{
+ struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
+
+ /*
+ * FIXME c8_planes readout missing thus
+ * .read_luts() doesn't read out post_csc_lut.
+ */
+ if (!is_pre_csc_lut && crtc_state->c8_planes)
+ return true;
+
+ return i915->display.funcs.color->lut_equal(crtc_state, blob1, blob2,
+ is_pre_csc_lut);
}
static bool need_plane_update(struct intel_plane *plane,
@@ -1282,6 +1509,42 @@ intel_color_add_affected_planes(struct intel_crtc_state *new_crtc_state)
return 0;
}
+static u32 intel_gamma_lut_tests(const struct intel_crtc_state *crtc_state)
+{
+ struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
+ const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut;
+
+ if (lut_is_legacy(gamma_lut))
+ return 0;
+
+ return INTEL_INFO(i915)->display.color.gamma_lut_tests;
+}
+
+static u32 intel_degamma_lut_tests(const struct intel_crtc_state *crtc_state)
+{
+ struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
+
+ return INTEL_INFO(i915)->display.color.degamma_lut_tests;
+}
+
+static int intel_gamma_lut_size(const struct intel_crtc_state *crtc_state)
+{
+ struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
+ const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut;
+
+ if (lut_is_legacy(gamma_lut))
+ return LEGACY_LUT_LENGTH;
+
+ return INTEL_INFO(i915)->display.color.gamma_lut_size;
+}
+
+static u32 intel_degamma_lut_size(const struct intel_crtc_state *crtc_state)
+{
+ struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
+
+ return INTEL_INFO(i915)->display.color.degamma_lut_size;
+}
+
static int check_lut_size(const struct drm_property_blob *lut, int expected)
{
int len;
@@ -1299,29 +1562,23 @@ static int check_lut_size(const struct drm_property_blob *lut, int expected)
return 0;
}
-static int check_luts(const struct intel_crtc_state *crtc_state)
+static int _check_luts(const struct intel_crtc_state *crtc_state,
+ u32 degamma_tests, u32 gamma_tests)
{
struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
const struct drm_property_blob *gamma_lut = crtc_state->hw.gamma_lut;
const struct drm_property_blob *degamma_lut = crtc_state->hw.degamma_lut;
int gamma_length, degamma_length;
- u32 gamma_tests, degamma_tests;
-
- /* Always allow legacy gamma LUT with no further checking. */
- if (crtc_state_is_legacy_gamma(crtc_state))
- return 0;
/* C8 relies on its palette being stored in the legacy LUT */
- if (crtc_state->c8_planes) {
+ if (crtc_state->c8_planes && !lut_is_legacy(crtc_state->hw.gamma_lut)) {
drm_dbg_kms(&i915->drm,
"C8 pixelformat requires the legacy LUT\n");
return -EINVAL;
}
- degamma_length = INTEL_INFO(i915)->display.color.degamma_lut_size;
- gamma_length = INTEL_INFO(i915)->display.color.gamma_lut_size;
- degamma_tests = INTEL_INFO(i915)->display.color.degamma_lut_tests;
- gamma_tests = INTEL_INFO(i915)->display.color.gamma_lut_tests;
+ degamma_length = intel_degamma_lut_size(crtc_state);
+ gamma_length = intel_gamma_lut_size(crtc_state);
if (check_lut_size(degamma_lut, degamma_length) ||
check_lut_size(gamma_lut, gamma_length))
@@ -1334,13 +1591,44 @@ static int check_luts(const struct intel_crtc_state *crtc_state)
return 0;
}
+static int check_luts(const struct intel_crtc_state *crtc_state)
+{
+ return _check_luts(crtc_state,
+ intel_degamma_lut_tests(crtc_state),
+ intel_gamma_lut_tests(crtc_state));
+}
+
static u32 i9xx_gamma_mode(struct intel_crtc_state *crtc_state)
{
if (!crtc_state->gamma_enable ||
- crtc_state_is_legacy_gamma(crtc_state))
+ lut_is_legacy(crtc_state->hw.gamma_lut))
return GAMMA_MODE_MODE_8BIT;
else
- return GAMMA_MODE_MODE_10BIT; /* i965+ only */
+ return GAMMA_MODE_MODE_10BIT;
+}
+
+static int i9xx_lut_10_diff(u16 a, u16 b)
+{
+ return drm_color_lut_extract(a, 10) -
+ drm_color_lut_extract(b, 10);
+}
+
+static int i9xx_check_lut_10(struct drm_i915_private *dev_priv,
+ const struct drm_property_blob *blob)
+{
+ const struct drm_color_lut *lut = blob->data;
+ int lut_size = drm_color_lut_size(blob);
+ const struct drm_color_lut *a = &lut[lut_size - 2];
+ const struct drm_color_lut *b = &lut[lut_size - 1];
+
+ if (i9xx_lut_10_diff(b->red, a->red) > 0x7f ||
+ i9xx_lut_10_diff(b->green, a->green) > 0x7f ||
+ i9xx_lut_10_diff(b->blue, a->blue) > 0x7f) {
+ drm_dbg_kms(&dev_priv->drm, "Last gamma LUT entry exceeds max slope\n");
+ return -EINVAL;
+ }
+
+ return 0;
}
void intel_color_assert_luts(const struct intel_crtc_state *crtc_state)
@@ -1355,15 +1643,19 @@ void intel_color_assert_luts(const struct intel_crtc_state *crtc_state)
crtc_state->post_csc_lut != crtc_state->hw.gamma_lut);
} else if (DISPLAY_VER(i915) == 10) {
drm_WARN_ON(&i915->drm,
+ crtc_state->post_csc_lut == crtc_state->hw.gamma_lut &&
crtc_state->pre_csc_lut != crtc_state->hw.degamma_lut &&
crtc_state->pre_csc_lut != i915->display.color.glk_linear_degamma_lut);
drm_WARN_ON(&i915->drm,
+ !ilk_lut_limited_range(crtc_state) &&
+ crtc_state->post_csc_lut != NULL &&
crtc_state->post_csc_lut != crtc_state->hw.gamma_lut);
} else if (crtc_state->gamma_mode != GAMMA_MODE_MODE_SPLIT) {
drm_WARN_ON(&i915->drm,
crtc_state->pre_csc_lut != crtc_state->hw.degamma_lut &&
crtc_state->pre_csc_lut != crtc_state->hw.gamma_lut);
drm_WARN_ON(&i915->drm,
+ !ilk_lut_limited_range(crtc_state) &&
crtc_state->post_csc_lut != crtc_state->hw.degamma_lut &&
crtc_state->post_csc_lut != crtc_state->hw.gamma_lut);
}
@@ -1379,6 +1671,7 @@ static void intel_assign_luts(struct intel_crtc_state *crtc_state)
static int i9xx_color_check(struct intel_crtc_state *crtc_state)
{
+ struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
int ret;
ret = check_luts(crtc_state);
@@ -1391,6 +1684,13 @@ static int i9xx_color_check(struct intel_crtc_state *crtc_state)
crtc_state->gamma_mode = i9xx_gamma_mode(crtc_state);
+ if (DISPLAY_VER(i915) < 4 &&
+ crtc_state->gamma_mode == GAMMA_MODE_MODE_10BIT) {
+ ret = i9xx_check_lut_10(i915, crtc_state->hw.gamma_lut);
+ if (ret)
+ return ret;
+ }
+
ret = intel_color_add_affected_planes(crtc_state);
if (ret)
return ret;
@@ -1406,14 +1706,12 @@ static u32 chv_cgm_mode(const struct intel_crtc_state *crtc_state)
{
u32 cgm_mode = 0;
- if (crtc_state_is_legacy_gamma(crtc_state))
- return 0;
-
if (crtc_state->hw.degamma_lut)
cgm_mode |= CGM_PIPE_MODE_DEGAMMA;
if (crtc_state->hw.ctm)
cgm_mode |= CGM_PIPE_MODE_CSC;
- if (crtc_state->hw.gamma_lut)
+ if (crtc_state->hw.gamma_lut &&
+ !lut_is_legacy(crtc_state->hw.gamma_lut))
cgm_mode |= CGM_PIPE_MODE_GAMMA;
return cgm_mode;
@@ -1440,7 +1738,7 @@ static int chv_color_check(struct intel_crtc_state *crtc_state)
* Otherwise we bypass it and use the CGM gamma instead.
*/
crtc_state->gamma_enable =
- crtc_state_is_legacy_gamma(crtc_state) &&
+ lut_is_legacy(crtc_state->hw.gamma_lut) &&
!crtc_state->c8_planes;
crtc_state->gamma_mode = GAMMA_MODE_MODE_8BIT;
@@ -1475,7 +1773,7 @@ static bool ilk_csc_enable(const struct intel_crtc_state *crtc_state)
static u32 ilk_gamma_mode(const struct intel_crtc_state *crtc_state)
{
if (!crtc_state->gamma_enable ||
- crtc_state_is_legacy_gamma(crtc_state))
+ lut_is_legacy(crtc_state->hw.gamma_lut))
return GAMMA_MODE_MODE_8BIT;
else
return GAMMA_MODE_MODE_10BIT;
@@ -1499,8 +1797,28 @@ static u32 ilk_csc_mode(const struct intel_crtc_state *crtc_state)
CSC_POSITION_BEFORE_GAMMA;
}
-static void ilk_assign_luts(struct intel_crtc_state *crtc_state)
+static int ilk_assign_luts(struct intel_crtc_state *crtc_state)
{
+ struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
+
+ if (ilk_lut_limited_range(crtc_state)) {
+ struct drm_property_blob *gamma_lut;
+
+ gamma_lut = create_resized_lut(i915, crtc_state->hw.gamma_lut,
+ drm_color_lut_size(crtc_state->hw.gamma_lut),
+ true);
+ if (IS_ERR(gamma_lut))
+ return PTR_ERR(gamma_lut);
+
+ drm_property_replace_blob(&crtc_state->post_csc_lut, gamma_lut);
+
+ drm_property_blob_put(gamma_lut);
+
+ drm_property_replace_blob(&crtc_state->pre_csc_lut, crtc_state->hw.degamma_lut);
+
+ return 0;
+ }
+
if (crtc_state->hw.degamma_lut ||
crtc_state->csc_mode & CSC_POSITION_BEFORE_GAMMA) {
drm_property_replace_blob(&crtc_state->pre_csc_lut,
@@ -1513,6 +1831,8 @@ static void ilk_assign_luts(struct intel_crtc_state *crtc_state)
drm_property_replace_blob(&crtc_state->post_csc_lut,
NULL);
}
+
+ return 0;
}
static int ilk_color_check(struct intel_crtc_state *crtc_state)
@@ -1549,7 +1869,9 @@ static int ilk_color_check(struct intel_crtc_state *crtc_state)
if (ret)
return ret;
- ilk_assign_luts(crtc_state);
+ ret = ilk_assign_luts(crtc_state);
+ if (ret)
+ return ret;
crtc_state->preload_luts = intel_can_preload_luts(crtc_state);
@@ -1585,19 +1907,19 @@ static int ivb_assign_luts(struct intel_crtc_state *crtc_state)
struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
struct drm_property_blob *degamma_lut, *gamma_lut;
- if (crtc_state->gamma_mode != GAMMA_MODE_MODE_SPLIT) {
- ilk_assign_luts(crtc_state);
- return 0;
- }
+ if (crtc_state->gamma_mode != GAMMA_MODE_MODE_SPLIT)
+ return ilk_assign_luts(crtc_state);
drm_WARN_ON(&i915->drm, drm_color_lut_size(crtc_state->hw.degamma_lut) != 1024);
drm_WARN_ON(&i915->drm, drm_color_lut_size(crtc_state->hw.gamma_lut) != 1024);
- degamma_lut = create_resized_lut(i915, crtc_state->hw.degamma_lut, 512);
+ degamma_lut = create_resized_lut(i915, crtc_state->hw.degamma_lut, 512,
+ false);
if (IS_ERR(degamma_lut))
return PTR_ERR(degamma_lut);
- gamma_lut = create_resized_lut(i915, crtc_state->hw.gamma_lut, 512);
+ gamma_lut = create_resized_lut(i915, crtc_state->hw.gamma_lut, 512,
+ ilk_lut_limited_range(crtc_state));
if (IS_ERR(gamma_lut)) {
drm_property_blob_put(degamma_lut);
return PTR_ERR(gamma_lut);
@@ -1621,6 +1943,12 @@ static int ivb_color_check(struct intel_crtc_state *crtc_state)
if (ret)
return ret;
+ if (crtc_state->c8_planes && crtc_state->hw.degamma_lut) {
+ drm_dbg_kms(&i915->drm,
+ "C8 pixelformat and degamma together are not possible\n");
+ return -EINVAL;
+ }
+
if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB &&
crtc_state->hw.ctm) {
drm_dbg_kms(&i915->drm,
@@ -1659,17 +1987,57 @@ static int ivb_color_check(struct intel_crtc_state *crtc_state)
static u32 glk_gamma_mode(const struct intel_crtc_state *crtc_state)
{
if (!crtc_state->gamma_enable ||
- crtc_state_is_legacy_gamma(crtc_state))
+ lut_is_legacy(crtc_state->hw.gamma_lut))
return GAMMA_MODE_MODE_8BIT;
else
return GAMMA_MODE_MODE_10BIT;
}
-static void glk_assign_luts(struct intel_crtc_state *crtc_state)
+static bool glk_use_pre_csc_lut_for_gamma(const struct intel_crtc_state *crtc_state)
+{
+ return crtc_state->hw.gamma_lut &&
+ !crtc_state->c8_planes &&
+ crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB;
+}
+
+static int glk_assign_luts(struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
- intel_assign_luts(crtc_state);
+ if (glk_use_pre_csc_lut_for_gamma(crtc_state)) {
+ struct drm_property_blob *gamma_lut;
+
+ gamma_lut = create_resized_lut(i915, crtc_state->hw.gamma_lut,
+ INTEL_INFO(i915)->display.color.degamma_lut_size,
+ false);
+ if (IS_ERR(gamma_lut))
+ return PTR_ERR(gamma_lut);
+
+ drm_property_replace_blob(&crtc_state->pre_csc_lut, gamma_lut);
+ drm_property_replace_blob(&crtc_state->post_csc_lut, NULL);
+
+ drm_property_blob_put(gamma_lut);
+
+ return 0;
+ }
+
+ if (ilk_lut_limited_range(crtc_state)) {
+ struct drm_property_blob *gamma_lut;
+
+ gamma_lut = create_resized_lut(i915, crtc_state->hw.gamma_lut,
+ drm_color_lut_size(crtc_state->hw.gamma_lut),
+ true);
+ if (IS_ERR(gamma_lut))
+ return PTR_ERR(gamma_lut);
+
+ drm_property_replace_blob(&crtc_state->post_csc_lut, gamma_lut);
+
+ drm_property_blob_put(gamma_lut);
+ } else {
+ drm_property_replace_blob(&crtc_state->post_csc_lut, crtc_state->hw.gamma_lut);
+ }
+
+ drm_property_replace_blob(&crtc_state->pre_csc_lut, crtc_state->hw.degamma_lut);
/*
* On GLK+ both pipe CSC and degamma LUT are controlled
@@ -1680,6 +2048,19 @@ static void glk_assign_luts(struct intel_crtc_state *crtc_state)
if (crtc_state->csc_enable && !crtc_state->pre_csc_lut)
drm_property_replace_blob(&crtc_state->pre_csc_lut,
i915->display.color.glk_linear_degamma_lut);
+
+ return 0;
+}
+
+static int glk_check_luts(const struct intel_crtc_state *crtc_state)
+{
+ u32 degamma_tests = intel_degamma_lut_tests(crtc_state);
+ u32 gamma_tests = intel_gamma_lut_tests(crtc_state);
+
+ if (glk_use_pre_csc_lut_for_gamma(crtc_state))
+ gamma_tests |= degamma_tests;
+
+ return _check_luts(crtc_state, degamma_tests, gamma_tests);
}
static int glk_color_check(struct intel_crtc_state *crtc_state)
@@ -1687,7 +2068,7 @@ static int glk_color_check(struct intel_crtc_state *crtc_state)
struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
int ret;
- ret = check_luts(crtc_state);
+ ret = glk_check_luts(crtc_state);
if (ret)
return ret;
@@ -1706,14 +2087,16 @@ static int glk_color_check(struct intel_crtc_state *crtc_state)
}
crtc_state->gamma_enable =
+ !glk_use_pre_csc_lut_for_gamma(crtc_state) &&
crtc_state->hw.gamma_lut &&
!crtc_state->c8_planes;
/* On GLK+ degamma LUT is controlled by csc_enable */
crtc_state->csc_enable =
+ glk_use_pre_csc_lut_for_gamma(crtc_state) ||
crtc_state->hw.degamma_lut ||
crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB ||
- crtc_state->hw.ctm || crtc_state->limited_color_range;
+ crtc_state->hw.ctm || ilk_csc_limited_range(crtc_state);
crtc_state->gamma_mode = glk_gamma_mode(crtc_state);
@@ -1723,7 +2106,9 @@ static int glk_color_check(struct intel_crtc_state *crtc_state)
if (ret)
return ret;
- glk_assign_luts(crtc_state);
+ ret = glk_assign_luts(crtc_state);
+ if (ret)
+ return ret;
crtc_state->preload_luts = intel_can_preload_luts(crtc_state);
@@ -1744,7 +2129,7 @@ static u32 icl_gamma_mode(const struct intel_crtc_state *crtc_state)
gamma_mode |= POST_CSC_GAMMA_ENABLE;
if (!crtc_state->hw.gamma_lut ||
- crtc_state_is_legacy_gamma(crtc_state))
+ lut_is_legacy(crtc_state->hw.gamma_lut))
gamma_mode |= GAMMA_MODE_MODE_8BIT;
/*
* Enable 10bit gamma for D13
@@ -1754,7 +2139,7 @@ static u32 icl_gamma_mode(const struct intel_crtc_state *crtc_state)
else if (DISPLAY_VER(i915) >= 13)
gamma_mode |= GAMMA_MODE_MODE_10BIT;
else
- gamma_mode |= GAMMA_MODE_MODE_12BIT_MULTI_SEGMENTED;
+ gamma_mode |= GAMMA_MODE_MODE_12BIT_MULTI_SEG;
return gamma_mode;
}
@@ -1792,68 +2177,153 @@ static int icl_color_check(struct intel_crtc_state *crtc_state)
return 0;
}
-static int i9xx_gamma_precision(const struct intel_crtc_state *crtc_state)
+static int i9xx_post_csc_lut_precision(const struct intel_crtc_state *crtc_state)
{
- if (!crtc_state->gamma_enable)
+ if (!crtc_state->gamma_enable && !crtc_state->c8_planes)
return 0;
switch (crtc_state->gamma_mode) {
case GAMMA_MODE_MODE_8BIT:
return 8;
case GAMMA_MODE_MODE_10BIT:
- return 16;
+ return 10;
default:
MISSING_CASE(crtc_state->gamma_mode);
return 0;
}
}
-static int ilk_gamma_precision(const struct intel_crtc_state *crtc_state)
+static int i9xx_pre_csc_lut_precision(const struct intel_crtc_state *crtc_state)
{
- if (!crtc_state->gamma_enable)
- return 0;
+ return 0;
+}
- if ((crtc_state->csc_mode & CSC_POSITION_BEFORE_GAMMA) == 0)
+static int i965_post_csc_lut_precision(const struct intel_crtc_state *crtc_state)
+{
+ if (!crtc_state->gamma_enable && !crtc_state->c8_planes)
return 0;
switch (crtc_state->gamma_mode) {
case GAMMA_MODE_MODE_8BIT:
return 8;
case GAMMA_MODE_MODE_10BIT:
- return 10;
+ return 16;
default:
MISSING_CASE(crtc_state->gamma_mode);
return 0;
}
}
-static int chv_gamma_precision(const struct intel_crtc_state *crtc_state)
+static int ilk_gamma_mode_precision(u32 gamma_mode)
{
- if (crtc_state->cgm_mode & CGM_PIPE_MODE_GAMMA)
+ switch (gamma_mode) {
+ case GAMMA_MODE_MODE_8BIT:
+ return 8;
+ case GAMMA_MODE_MODE_10BIT:
return 10;
- else
- return i9xx_gamma_precision(crtc_state);
+ default:
+ MISSING_CASE(gamma_mode);
+ return 0;
+ }
+}
+
+static bool ilk_has_post_csc_lut(const struct intel_crtc_state *crtc_state)
+{
+ if (crtc_state->c8_planes)
+ return true;
+
+ return crtc_state->gamma_enable &&
+ (crtc_state->csc_mode & CSC_POSITION_BEFORE_GAMMA) != 0;
+}
+
+static bool ilk_has_pre_csc_lut(const struct intel_crtc_state *crtc_state)
+{
+ return crtc_state->gamma_enable &&
+ (crtc_state->csc_mode & CSC_POSITION_BEFORE_GAMMA) == 0;
}
-static int glk_gamma_precision(const struct intel_crtc_state *crtc_state)
+static int ilk_post_csc_lut_precision(const struct intel_crtc_state *crtc_state)
{
- if (!crtc_state->gamma_enable)
+ if (!ilk_has_post_csc_lut(crtc_state))
return 0;
- switch (crtc_state->gamma_mode) {
- case GAMMA_MODE_MODE_8BIT:
- return 8;
- case GAMMA_MODE_MODE_10BIT:
+ return ilk_gamma_mode_precision(crtc_state->gamma_mode);
+}
+
+static int ilk_pre_csc_lut_precision(const struct intel_crtc_state *crtc_state)
+{
+ if (!ilk_has_pre_csc_lut(crtc_state))
+ return 0;
+
+ return ilk_gamma_mode_precision(crtc_state->gamma_mode);
+}
+
+static int ivb_post_csc_lut_precision(const struct intel_crtc_state *crtc_state)
+{
+ if (crtc_state->gamma_enable &&
+ crtc_state->gamma_mode == GAMMA_MODE_MODE_SPLIT)
return 10;
- default:
- MISSING_CASE(crtc_state->gamma_mode);
+
+ return ilk_post_csc_lut_precision(crtc_state);
+}
+
+static int ivb_pre_csc_lut_precision(const struct intel_crtc_state *crtc_state)
+{
+ if (crtc_state->gamma_enable &&
+ crtc_state->gamma_mode == GAMMA_MODE_MODE_SPLIT)
+ return 10;
+
+ return ilk_pre_csc_lut_precision(crtc_state);
+}
+
+static int chv_post_csc_lut_precision(const struct intel_crtc_state *crtc_state)
+{
+ if (crtc_state->cgm_mode & CGM_PIPE_MODE_GAMMA)
+ return 10;
+
+ return i965_post_csc_lut_precision(crtc_state);
+}
+
+static int chv_pre_csc_lut_precision(const struct intel_crtc_state *crtc_state)
+{
+ if (crtc_state->cgm_mode & CGM_PIPE_MODE_DEGAMMA)
+ return 14;
+
+ return 0;
+}
+
+static int glk_post_csc_lut_precision(const struct intel_crtc_state *crtc_state)
+{
+ if (!crtc_state->gamma_enable && !crtc_state->c8_planes)
return 0;
- }
+
+ return ilk_gamma_mode_precision(crtc_state->gamma_mode);
}
-static int icl_gamma_precision(const struct intel_crtc_state *crtc_state)
+static int glk_pre_csc_lut_precision(const struct intel_crtc_state *crtc_state)
{
- if ((crtc_state->gamma_mode & POST_CSC_GAMMA_ENABLE) == 0)
+ if (!crtc_state->csc_enable)
+ return 0;
+
+ return 16;
+}
+
+static bool icl_has_post_csc_lut(const struct intel_crtc_state *crtc_state)
+{
+ if (crtc_state->c8_planes)
+ return true;
+
+ return crtc_state->gamma_mode & POST_CSC_GAMMA_ENABLE;
+}
+
+static bool icl_has_pre_csc_lut(const struct intel_crtc_state *crtc_state)
+{
+ return crtc_state->gamma_mode & PRE_CSC_GAMMA_ENABLE;
+}
+
+static int icl_post_csc_lut_precision(const struct intel_crtc_state *crtc_state)
+{
+ if (!icl_has_post_csc_lut(crtc_state))
return 0;
switch (crtc_state->gamma_mode & GAMMA_MODE_MODE_MASK) {
@@ -1861,7 +2331,7 @@ static int icl_gamma_precision(const struct intel_crtc_state *crtc_state)
return 8;
case GAMMA_MODE_MODE_10BIT:
return 10;
- case GAMMA_MODE_MODE_12BIT_MULTI_SEGMENTED:
+ case GAMMA_MODE_MODE_12BIT_MULTI_SEG:
return 16;
default:
MISSING_CASE(crtc_state->gamma_mode);
@@ -1869,26 +2339,12 @@ static int icl_gamma_precision(const struct intel_crtc_state *crtc_state)
}
}
-int intel_color_get_gamma_bit_precision(const struct intel_crtc_state *crtc_state)
+static int icl_pre_csc_lut_precision(const struct intel_crtc_state *crtc_state)
{
- struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- struct drm_i915_private *i915 = to_i915(crtc->base.dev);
-
- if (HAS_GMCH(i915)) {
- if (IS_CHERRYVIEW(i915))
- return chv_gamma_precision(crtc_state);
- else
- return i9xx_gamma_precision(crtc_state);
- } else {
- if (DISPLAY_VER(i915) >= 11)
- return icl_gamma_precision(crtc_state);
- else if (DISPLAY_VER(i915) == 10)
- return glk_gamma_precision(crtc_state);
- else if (IS_IRONLAKE(i915))
- return ilk_gamma_precision(crtc_state);
- }
+ if (!icl_has_pre_csc_lut(crtc_state))
+ return 0;
- return 0;
+ return 16;
}
static bool err_check(struct drm_color_lut *lut1,
@@ -1899,9 +2355,9 @@ static bool err_check(struct drm_color_lut *lut1,
((abs((long)lut2->green - lut1->green)) <= err);
}
-static bool intel_color_lut_entries_equal(struct drm_color_lut *lut1,
- struct drm_color_lut *lut2,
- int lut_size, u32 err)
+static bool intel_lut_entries_equal(struct drm_color_lut *lut1,
+ struct drm_color_lut *lut2,
+ int lut_size, u32 err)
{
int i;
@@ -1913,9 +2369,9 @@ static bool intel_color_lut_entries_equal(struct drm_color_lut *lut1,
return true;
}
-bool intel_color_lut_equal(struct drm_property_blob *blob1,
- struct drm_property_blob *blob2,
- u32 gamma_mode, u32 bit_precision)
+static bool intel_lut_equal(const struct drm_property_blob *blob1,
+ const struct drm_property_blob *blob2,
+ int check_size, int precision)
{
struct drm_color_lut *lut1, *lut2;
int lut_size1, lut_size2;
@@ -1924,40 +2380,134 @@ bool intel_color_lut_equal(struct drm_property_blob *blob1,
if (!blob1 != !blob2)
return false;
+ if (!blob1 != !precision)
+ return false;
+
if (!blob1)
return true;
lut_size1 = drm_color_lut_size(blob1);
lut_size2 = drm_color_lut_size(blob2);
- /* check sw and hw lut size */
if (lut_size1 != lut_size2)
return false;
+ if (check_size > lut_size1)
+ return false;
+
lut1 = blob1->data;
lut2 = blob2->data;
- err = 0xffff >> bit_precision;
+ err = 0xffff >> precision;
- /* check sw and hw lut entry to be equal */
- switch (gamma_mode & GAMMA_MODE_MODE_MASK) {
- case GAMMA_MODE_MODE_8BIT:
- case GAMMA_MODE_MODE_10BIT:
- if (!intel_color_lut_entries_equal(lut1, lut2,
- lut_size2, err))
- return false;
- break;
- case GAMMA_MODE_MODE_12BIT_MULTI_SEGMENTED:
- if (!intel_color_lut_entries_equal(lut1, lut2,
- 9, err))
- return false;
- break;
- default:
- MISSING_CASE(gamma_mode);
- return false;
- }
+ if (!check_size)
+ check_size = lut_size1;
- return true;
+ return intel_lut_entries_equal(lut1, lut2, check_size, err);
+}
+
+static bool i9xx_lut_equal(const struct intel_crtc_state *crtc_state,
+ const struct drm_property_blob *blob1,
+ const struct drm_property_blob *blob2,
+ bool is_pre_csc_lut)
+{
+ int check_size = 0;
+
+ if (is_pre_csc_lut)
+ return intel_lut_equal(blob1, blob2, 0,
+ i9xx_pre_csc_lut_precision(crtc_state));
+
+ /* 10bit mode last entry is implicit, just skip it */
+ if (crtc_state->gamma_mode == GAMMA_MODE_MODE_10BIT)
+ check_size = 128;
+
+ return intel_lut_equal(blob1, blob2, check_size,
+ i9xx_post_csc_lut_precision(crtc_state));
+}
+
+static bool i965_lut_equal(const struct intel_crtc_state *crtc_state,
+ const struct drm_property_blob *blob1,
+ const struct drm_property_blob *blob2,
+ bool is_pre_csc_lut)
+{
+ if (is_pre_csc_lut)
+ return intel_lut_equal(blob1, blob2, 0,
+ i9xx_pre_csc_lut_precision(crtc_state));
+ else
+ return intel_lut_equal(blob1, blob2, 0,
+ i965_post_csc_lut_precision(crtc_state));
+}
+
+static bool chv_lut_equal(const struct intel_crtc_state *crtc_state,
+ const struct drm_property_blob *blob1,
+ const struct drm_property_blob *blob2,
+ bool is_pre_csc_lut)
+{
+ if (is_pre_csc_lut)
+ return intel_lut_equal(blob1, blob2, 0,
+ chv_pre_csc_lut_precision(crtc_state));
+ else
+ return intel_lut_equal(blob1, blob2, 0,
+ chv_post_csc_lut_precision(crtc_state));
+}
+
+static bool ilk_lut_equal(const struct intel_crtc_state *crtc_state,
+ const struct drm_property_blob *blob1,
+ const struct drm_property_blob *blob2,
+ bool is_pre_csc_lut)
+{
+ if (is_pre_csc_lut)
+ return intel_lut_equal(blob1, blob2, 0,
+ ilk_pre_csc_lut_precision(crtc_state));
+ else
+ return intel_lut_equal(blob1, blob2, 0,
+ ilk_post_csc_lut_precision(crtc_state));
+}
+
+static bool ivb_lut_equal(const struct intel_crtc_state *crtc_state,
+ const struct drm_property_blob *blob1,
+ const struct drm_property_blob *blob2,
+ bool is_pre_csc_lut)
+{
+ if (is_pre_csc_lut)
+ return intel_lut_equal(blob1, blob2, 0,
+ ivb_pre_csc_lut_precision(crtc_state));
+ else
+ return intel_lut_equal(blob1, blob2, 0,
+ ivb_post_csc_lut_precision(crtc_state));
+}
+
+static bool glk_lut_equal(const struct intel_crtc_state *crtc_state,
+ const struct drm_property_blob *blob1,
+ const struct drm_property_blob *blob2,
+ bool is_pre_csc_lut)
+{
+ if (is_pre_csc_lut)
+ return intel_lut_equal(blob1, blob2, 0,
+ glk_pre_csc_lut_precision(crtc_state));
+ else
+ return intel_lut_equal(blob1, blob2, 0,
+ glk_post_csc_lut_precision(crtc_state));
+}
+
+static bool icl_lut_equal(const struct intel_crtc_state *crtc_state,
+ const struct drm_property_blob *blob1,
+ const struct drm_property_blob *blob2,
+ bool is_pre_csc_lut)
+{
+ int check_size = 0;
+
+ if (is_pre_csc_lut)
+ return intel_lut_equal(blob1, blob2, 0,
+ icl_pre_csc_lut_precision(crtc_state));
+
+ /* hw readout broken except for the super fine segment :( */
+ if ((crtc_state->gamma_mode & GAMMA_MODE_MODE_MASK) ==
+ GAMMA_MODE_MODE_12BIT_MULTI_SEG)
+ check_size = 9;
+
+ return intel_lut_equal(blob1, blob2, check_size,
+ icl_post_csc_lut_precision(crtc_state));
}
static struct drm_property_blob *i9xx_read_lut_8(struct intel_crtc *crtc)
@@ -1985,14 +2535,53 @@ static struct drm_property_blob *i9xx_read_lut_8(struct intel_crtc *crtc)
return blob;
}
+static struct drm_property_blob *i9xx_read_lut_10(struct intel_crtc *crtc)
+{
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ u32 lut_size = INTEL_INFO(dev_priv)->display.color.gamma_lut_size;
+ enum pipe pipe = crtc->pipe;
+ struct drm_property_blob *blob;
+ struct drm_color_lut *lut;
+ u32 ldw, udw;
+ int i;
+
+ blob = drm_property_create_blob(&dev_priv->drm,
+ lut_size * sizeof(lut[0]), NULL);
+ if (IS_ERR(blob))
+ return NULL;
+
+ lut = blob->data;
+
+ for (i = 0; i < lut_size - 1; i++) {
+ ldw = intel_de_read_fw(dev_priv, PALETTE(pipe, 2 * i + 0));
+ udw = intel_de_read_fw(dev_priv, PALETTE(pipe, 2 * i + 1));
+
+ i9xx_lut_10_pack(&lut[i], ldw, udw);
+ }
+
+ i9xx_lut_10_pack_slope(&lut[i], ldw, udw);
+
+ return blob;
+}
+
static void i9xx_read_luts(struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- if (!crtc_state->gamma_enable)
+ if (!crtc_state->gamma_enable && !crtc_state->c8_planes)
return;
- crtc_state->post_csc_lut = i9xx_read_lut_8(crtc);
+ switch (crtc_state->gamma_mode) {
+ case GAMMA_MODE_MODE_8BIT:
+ crtc_state->post_csc_lut = i9xx_read_lut_8(crtc);
+ break;
+ case GAMMA_MODE_MODE_10BIT:
+ crtc_state->post_csc_lut = i9xx_read_lut_10(crtc);
+ break;
+ default:
+ MISSING_CASE(crtc_state->gamma_mode);
+ break;
+ }
}
static struct drm_property_blob *i965_read_lut_10p6(struct intel_crtc *crtc)
@@ -2029,13 +2618,46 @@ static void i965_read_luts(struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- if (!crtc_state->gamma_enable)
+ if (!crtc_state->gamma_enable && !crtc_state->c8_planes)
return;
- if (crtc_state->gamma_mode == GAMMA_MODE_MODE_8BIT)
+ switch (crtc_state->gamma_mode) {
+ case GAMMA_MODE_MODE_8BIT:
crtc_state->post_csc_lut = i9xx_read_lut_8(crtc);
- else
+ break;
+ case GAMMA_MODE_MODE_10BIT:
crtc_state->post_csc_lut = i965_read_lut_10p6(crtc);
+ break;
+ default:
+ MISSING_CASE(crtc_state->gamma_mode);
+ break;
+ }
+}
+
+static struct drm_property_blob *chv_read_cgm_degamma(struct intel_crtc *crtc)
+{
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ int i, lut_size = INTEL_INFO(dev_priv)->display.color.degamma_lut_size;
+ enum pipe pipe = crtc->pipe;
+ struct drm_property_blob *blob;
+ struct drm_color_lut *lut;
+
+ blob = drm_property_create_blob(&dev_priv->drm,
+ sizeof(lut[0]) * lut_size,
+ NULL);
+ if (IS_ERR(blob))
+ return NULL;
+
+ lut = blob->data;
+
+ for (i = 0; i < lut_size; i++) {
+ u32 ldw = intel_de_read_fw(dev_priv, CGM_PIPE_DEGAMMA(pipe, i, 0));
+ u32 udw = intel_de_read_fw(dev_priv, CGM_PIPE_DEGAMMA(pipe, i, 1));
+
+ chv_cgm_degamma_pack(&lut[i], ldw, udw);
+ }
+
+ return blob;
}
static struct drm_property_blob *chv_read_cgm_gamma(struct intel_crtc *crtc)
@@ -2068,6 +2690,9 @@ static void chv_read_luts(struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+ if (crtc_state->cgm_mode & CGM_PIPE_MODE_DEGAMMA)
+ crtc_state->pre_csc_lut = chv_read_cgm_degamma(crtc);
+
if (crtc_state->cgm_mode & CGM_PIPE_MODE_GAMMA)
crtc_state->post_csc_lut = chv_read_cgm_gamma(crtc);
else
@@ -2127,19 +2752,88 @@ static struct drm_property_blob *ilk_read_lut_10(struct intel_crtc *crtc)
static void ilk_read_luts(struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+ struct drm_property_blob **blob =
+ ilk_has_post_csc_lut(crtc_state) ?
+ &crtc_state->post_csc_lut : &crtc_state->pre_csc_lut;
- if (!crtc_state->gamma_enable)
+ if (!crtc_state->gamma_enable && !crtc_state->c8_planes)
return;
- if ((crtc_state->csc_mode & CSC_POSITION_BEFORE_GAMMA) == 0)
+ switch (crtc_state->gamma_mode) {
+ case GAMMA_MODE_MODE_8BIT:
+ *blob = ilk_read_lut_8(crtc);
+ break;
+ case GAMMA_MODE_MODE_10BIT:
+ *blob = ilk_read_lut_10(crtc);
+ break;
+ default:
+ MISSING_CASE(crtc_state->gamma_mode);
+ break;
+ }
+}
+
+/*
+ * IVB/HSW Bspec / PAL_PREC_INDEX:
+ * "Restriction : Index auto increment mode is not
+ * supported and must not be enabled."
+ */
+static struct drm_property_blob *ivb_read_lut_10(struct intel_crtc *crtc,
+ u32 prec_index)
+{
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ int i, lut_size = ivb_lut_10_size(prec_index);
+ enum pipe pipe = crtc->pipe;
+ struct drm_property_blob *blob;
+ struct drm_color_lut *lut;
+
+ blob = drm_property_create_blob(&dev_priv->drm,
+ sizeof(lut[0]) * lut_size,
+ NULL);
+ if (IS_ERR(blob))
+ return NULL;
+
+ lut = blob->data;
+
+ for (i = 0; i < lut_size; i++) {
+ u32 val;
+
+ intel_de_write_fw(dev_priv, PREC_PAL_INDEX(pipe),
+ prec_index + i);
+ val = intel_de_read_fw(dev_priv, PREC_PAL_DATA(pipe));
+
+ ilk_lut_10_pack(&lut[i], val);
+ }
+
+ intel_de_write_fw(dev_priv, PREC_PAL_INDEX(pipe),
+ PAL_PREC_INDEX_VALUE(0));
+
+ return blob;
+}
+
+static void ivb_read_luts(struct intel_crtc_state *crtc_state)
+{
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+ struct drm_property_blob **blob =
+ ilk_has_post_csc_lut(crtc_state) ?
+ &crtc_state->post_csc_lut : &crtc_state->pre_csc_lut;
+
+ if (!crtc_state->gamma_enable && !crtc_state->c8_planes)
return;
switch (crtc_state->gamma_mode) {
case GAMMA_MODE_MODE_8BIT:
- crtc_state->post_csc_lut = ilk_read_lut_8(crtc);
+ *blob = ilk_read_lut_8(crtc);
+ break;
+ case GAMMA_MODE_MODE_SPLIT:
+ crtc_state->pre_csc_lut =
+ ivb_read_lut_10(crtc, PAL_PREC_SPLIT_MODE |
+ PAL_PREC_INDEX_VALUE(0));
+ crtc_state->post_csc_lut =
+ ivb_read_lut_10(crtc, PAL_PREC_SPLIT_MODE |
+ PAL_PREC_INDEX_VALUE(512));
break;
case GAMMA_MODE_MODE_10BIT:
- crtc_state->post_csc_lut = ilk_read_lut_10(crtc);
+ *blob = ivb_read_lut_10(crtc, PAL_PREC_INDEX_VALUE(0));
break;
default:
MISSING_CASE(crtc_state->gamma_mode);
@@ -2152,14 +2846,11 @@ static struct drm_property_blob *bdw_read_lut_10(struct intel_crtc *crtc,
u32 prec_index)
{
struct drm_i915_private *i915 = to_i915(crtc->base.dev);
- int i, hw_lut_size = ivb_lut_10_size(prec_index);
- int lut_size = INTEL_INFO(i915)->display.color.gamma_lut_size;
+ int i, lut_size = ivb_lut_10_size(prec_index);
enum pipe pipe = crtc->pipe;
struct drm_property_blob *blob;
struct drm_color_lut *lut;
- drm_WARN_ON(&i915->drm, lut_size != hw_lut_size);
-
blob = drm_property_create_blob(&i915->drm,
sizeof(lut[0]) * lut_size,
NULL);
@@ -2169,7 +2860,10 @@ static struct drm_property_blob *bdw_read_lut_10(struct intel_crtc *crtc,
lut = blob->data;
intel_de_write_fw(i915, PREC_PAL_INDEX(pipe),
- prec_index | PAL_PREC_AUTO_INCREMENT);
+ prec_index);
+ intel_de_write_fw(i915, PREC_PAL_INDEX(pipe),
+ PAL_PREC_AUTO_INCREMENT |
+ prec_index);
for (i = 0; i < lut_size; i++) {
u32 val = intel_de_read_fw(i915, PREC_PAL_DATA(pipe));
@@ -2177,7 +2871,80 @@ static struct drm_property_blob *bdw_read_lut_10(struct intel_crtc *crtc,
ilk_lut_10_pack(&lut[i], val);
}
- intel_de_write_fw(i915, PREC_PAL_INDEX(pipe), 0);
+ intel_de_write_fw(i915, PREC_PAL_INDEX(pipe),
+ PAL_PREC_INDEX_VALUE(0));
+
+ return blob;
+}
+
+static void bdw_read_luts(struct intel_crtc_state *crtc_state)
+{
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+ struct drm_property_blob **blob =
+ ilk_has_post_csc_lut(crtc_state) ?
+ &crtc_state->post_csc_lut : &crtc_state->pre_csc_lut;
+
+ if (!crtc_state->gamma_enable && !crtc_state->c8_planes)
+ return;
+
+ switch (crtc_state->gamma_mode) {
+ case GAMMA_MODE_MODE_8BIT:
+ *blob = ilk_read_lut_8(crtc);
+ break;
+ case GAMMA_MODE_MODE_SPLIT:
+ crtc_state->pre_csc_lut =
+ bdw_read_lut_10(crtc, PAL_PREC_SPLIT_MODE |
+ PAL_PREC_INDEX_VALUE(0));
+ crtc_state->post_csc_lut =
+ bdw_read_lut_10(crtc, PAL_PREC_SPLIT_MODE |
+ PAL_PREC_INDEX_VALUE(512));
+ break;
+ case GAMMA_MODE_MODE_10BIT:
+ *blob = bdw_read_lut_10(crtc, PAL_PREC_INDEX_VALUE(0));
+ break;
+ default:
+ MISSING_CASE(crtc_state->gamma_mode);
+ break;
+ }
+}
+
+static struct drm_property_blob *glk_read_degamma_lut(struct intel_crtc *crtc)
+{
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ int i, lut_size = INTEL_INFO(dev_priv)->display.color.degamma_lut_size;
+ enum pipe pipe = crtc->pipe;
+ struct drm_property_blob *blob;
+ struct drm_color_lut *lut;
+
+ blob = drm_property_create_blob(&dev_priv->drm,
+ sizeof(lut[0]) * lut_size,
+ NULL);
+ if (IS_ERR(blob))
+ return NULL;
+
+ lut = blob->data;
+
+ /*
+ * When setting the auto-increment bit, the hardware seems to
+ * ignore the index bits, so we need to reset it to index 0
+ * separately.
+ */
+ intel_de_write_fw(dev_priv, PRE_CSC_GAMC_INDEX(pipe),
+ PRE_CSC_GAMC_INDEX_VALUE(0));
+ intel_de_write_fw(dev_priv, PRE_CSC_GAMC_INDEX(pipe),
+ PRE_CSC_GAMC_AUTO_INCREMENT |
+ PRE_CSC_GAMC_INDEX_VALUE(0));
+
+ for (i = 0; i < lut_size; i++) {
+ u32 val = intel_de_read_fw(dev_priv, PRE_CSC_GAMC_DATA(pipe));
+
+ lut[i].red = val;
+ lut[i].green = val;
+ lut[i].blue = val;
+ }
+
+ intel_de_write_fw(dev_priv, PRE_CSC_GAMC_INDEX(pipe),
+ PRE_CSC_GAMC_INDEX_VALUE(0));
return blob;
}
@@ -2186,7 +2953,10 @@ static void glk_read_luts(struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- if (!crtc_state->gamma_enable)
+ if (crtc_state->csc_enable)
+ crtc_state->pre_csc_lut = glk_read_degamma_lut(crtc);
+
+ if (!crtc_state->gamma_enable && !crtc_state->c8_planes)
return;
switch (crtc_state->gamma_mode) {
@@ -2220,7 +2990,10 @@ icl_read_lut_multi_segment(struct intel_crtc *crtc)
lut = blob->data;
intel_de_write_fw(i915, PREC_PAL_MULTI_SEG_INDEX(pipe),
- PAL_PREC_AUTO_INCREMENT);
+ PAL_PREC_MULTI_SEG_INDEX_VALUE(0));
+ intel_de_write_fw(i915, PREC_PAL_MULTI_SEG_INDEX(pipe),
+ PAL_PREC_MULTI_SEG_AUTO_INCREMENT |
+ PAL_PREC_MULTI_SEG_INDEX_VALUE(0));
for (i = 0; i < 9; i++) {
u32 ldw = intel_de_read_fw(i915, PREC_PAL_MULTI_SEG_DATA(pipe));
@@ -2229,7 +3002,8 @@ icl_read_lut_multi_segment(struct intel_crtc *crtc)
ilk_lut_12p4_pack(&lut[i], ldw, udw);
}
- intel_de_write_fw(i915, PREC_PAL_MULTI_SEG_INDEX(pipe), 0);
+ intel_de_write_fw(i915, PREC_PAL_MULTI_SEG_INDEX(pipe),
+ PAL_PREC_MULTI_SEG_INDEX_VALUE(0));
/*
* FIXME readouts from PAL_PREC_DATA register aren't giving
@@ -2244,7 +3018,10 @@ static void icl_read_luts(struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- if ((crtc_state->gamma_mode & POST_CSC_GAMMA_ENABLE) == 0)
+ if (icl_has_pre_csc_lut(crtc_state))
+ crtc_state->pre_csc_lut = glk_read_degamma_lut(crtc);
+
+ if (!icl_has_post_csc_lut(crtc_state))
return;
switch (crtc_state->gamma_mode & GAMMA_MODE_MODE_MASK) {
@@ -2254,7 +3031,7 @@ static void icl_read_luts(struct intel_crtc_state *crtc_state)
case GAMMA_MODE_MODE_10BIT:
crtc_state->post_csc_lut = bdw_read_lut_10(crtc, PAL_PREC_INDEX_VALUE(0));
break;
- case GAMMA_MODE_MODE_12BIT_MULTI_SEGMENTED:
+ case GAMMA_MODE_MODE_12BIT_MULTI_SEG:
crtc_state->post_csc_lut = icl_read_lut_multi_segment(crtc);
break;
default:
@@ -2268,6 +3045,7 @@ static const struct intel_color_funcs chv_color_funcs = {
.color_commit_arm = i9xx_color_commit_arm,
.load_luts = chv_load_luts,
.read_luts = chv_read_luts,
+ .lut_equal = chv_lut_equal,
};
static const struct intel_color_funcs i965_color_funcs = {
@@ -2275,6 +3053,7 @@ static const struct intel_color_funcs i965_color_funcs = {
.color_commit_arm = i9xx_color_commit_arm,
.load_luts = i965_load_luts,
.read_luts = i965_read_luts,
+ .lut_equal = i965_lut_equal,
};
static const struct intel_color_funcs i9xx_color_funcs = {
@@ -2282,6 +3061,7 @@ static const struct intel_color_funcs i9xx_color_funcs = {
.color_commit_arm = i9xx_color_commit_arm,
.load_luts = i9xx_load_luts,
.read_luts = i9xx_read_luts,
+ .lut_equal = i9xx_lut_equal,
};
static const struct intel_color_funcs icl_color_funcs = {
@@ -2290,6 +3070,7 @@ static const struct intel_color_funcs icl_color_funcs = {
.color_commit_arm = skl_color_commit_arm,
.load_luts = icl_load_luts,
.read_luts = icl_read_luts,
+ .lut_equal = icl_lut_equal,
};
static const struct intel_color_funcs glk_color_funcs = {
@@ -2298,6 +3079,7 @@ static const struct intel_color_funcs glk_color_funcs = {
.color_commit_arm = skl_color_commit_arm,
.load_luts = glk_load_luts,
.read_luts = glk_read_luts,
+ .lut_equal = glk_lut_equal,
};
static const struct intel_color_funcs skl_color_funcs = {
@@ -2305,7 +3087,8 @@ static const struct intel_color_funcs skl_color_funcs = {
.color_commit_noarm = ilk_color_commit_noarm,
.color_commit_arm = skl_color_commit_arm,
.load_luts = bdw_load_luts,
- .read_luts = NULL,
+ .read_luts = bdw_read_luts,
+ .lut_equal = ivb_lut_equal,
};
static const struct intel_color_funcs bdw_color_funcs = {
@@ -2313,7 +3096,8 @@ static const struct intel_color_funcs bdw_color_funcs = {
.color_commit_noarm = ilk_color_commit_noarm,
.color_commit_arm = hsw_color_commit_arm,
.load_luts = bdw_load_luts,
- .read_luts = NULL,
+ .read_luts = bdw_read_luts,
+ .lut_equal = ivb_lut_equal,
};
static const struct intel_color_funcs hsw_color_funcs = {
@@ -2321,7 +3105,8 @@ static const struct intel_color_funcs hsw_color_funcs = {
.color_commit_noarm = ilk_color_commit_noarm,
.color_commit_arm = hsw_color_commit_arm,
.load_luts = ivb_load_luts,
- .read_luts = NULL,
+ .read_luts = ivb_read_luts,
+ .lut_equal = ivb_lut_equal,
};
static const struct intel_color_funcs ivb_color_funcs = {
@@ -2329,7 +3114,8 @@ static const struct intel_color_funcs ivb_color_funcs = {
.color_commit_noarm = ilk_color_commit_noarm,
.color_commit_arm = ilk_color_commit_arm,
.load_luts = ivb_load_luts,
- .read_luts = NULL,
+ .read_luts = ivb_read_luts,
+ .lut_equal = ivb_lut_equal,
};
static const struct intel_color_funcs ilk_color_funcs = {
@@ -2338,19 +3124,34 @@ static const struct intel_color_funcs ilk_color_funcs = {
.color_commit_arm = ilk_color_commit_arm,
.load_luts = ilk_load_luts,
.read_luts = ilk_read_luts,
+ .lut_equal = ilk_lut_equal,
};
void intel_color_crtc_init(struct intel_crtc *crtc)
{
struct drm_i915_private *i915 = to_i915(crtc->base.dev);
- bool has_ctm = INTEL_INFO(i915)->display.color.degamma_lut_size != 0;
+ int degamma_lut_size, gamma_lut_size;
+ bool has_ctm;
drm_mode_crtc_set_gamma_size(&crtc->base, 256);
- drm_crtc_enable_color_mgmt(&crtc->base,
- INTEL_INFO(i915)->display.color.degamma_lut_size,
- has_ctm,
- INTEL_INFO(i915)->display.color.gamma_lut_size);
+ gamma_lut_size = INTEL_INFO(i915)->display.color.gamma_lut_size;
+ degamma_lut_size = INTEL_INFO(i915)->display.color.degamma_lut_size;
+ has_ctm = degamma_lut_size != 0;
+
+ /*
+ * "DPALETTE_A: NOTE: The 8-bit (non-10-bit) mode is the
+ * only mode supported by Alviso and Grantsdale."
+ *
+ * Actually looks like this affects all of gen3.
+ * Confirmed on alv,cst,pnv. Mobile gen2 parts (alm,mgm)
+ * are confirmed not to suffer from this restriction.
+ */
+ if (DISPLAY_VER(i915) == 3 && crtc->pipe == PIPE_A)
+ gamma_lut_size = 256;
+
+ drm_crtc_enable_color_mgmt(&crtc->base, degamma_lut_size,
+ has_ctm, gamma_lut_size);
}
int intel_color_init(struct drm_i915_private *i915)
diff --git a/drivers/gpu/drm/i915/display/intel_color.h b/drivers/gpu/drm/i915/display/intel_color.h
index 2a5ada67774d..d620b5b1e2a6 100644
--- a/drivers/gpu/drm/i915/display/intel_color.h
+++ b/drivers/gpu/drm/i915/display/intel_color.h
@@ -17,14 +17,16 @@ void intel_color_init_hooks(struct drm_i915_private *i915);
int intel_color_init(struct drm_i915_private *i915);
void intel_color_crtc_init(struct intel_crtc *crtc);
int intel_color_check(struct intel_crtc_state *crtc_state);
+void intel_color_prepare_commit(struct intel_crtc_state *crtc_state);
+void intel_color_cleanup_commit(struct intel_crtc_state *crtc_state);
void intel_color_commit_noarm(const struct intel_crtc_state *crtc_state);
void intel_color_commit_arm(const struct intel_crtc_state *crtc_state);
void intel_color_load_luts(const struct intel_crtc_state *crtc_state);
void intel_color_get_config(struct intel_crtc_state *crtc_state);
-int intel_color_get_gamma_bit_precision(const struct intel_crtc_state *crtc_state);
-bool intel_color_lut_equal(struct drm_property_blob *blob1,
- struct drm_property_blob *blob2,
- u32 gamma_mode, u32 bit_precision);
+bool intel_color_lut_equal(const struct intel_crtc_state *crtc_state,
+ const struct drm_property_blob *blob1,
+ const struct drm_property_blob *blob2,
+ bool is_pre_csc_lut);
void intel_color_assert_luts(const struct intel_crtc_state *crtc_state);
#endif /* __INTEL_COLOR_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_connector.c b/drivers/gpu/drm/i915/display/intel_connector.c
index 6205ddd3ded0..257afac34839 100644
--- a/drivers/gpu/drm/i915/display/intel_connector.c
+++ b/drivers/gpu/drm/i915/display/intel_connector.c
@@ -54,7 +54,7 @@ int intel_connector_init(struct intel_connector *connector)
__drm_atomic_helper_connector_reset(&connector->base,
&conn_state->base);
- INIT_LIST_HEAD(&connector->panel.fixed_modes);
+ intel_panel_init_alloc(connector);
return 0;
}
@@ -95,13 +95,10 @@ void intel_connector_destroy(struct drm_connector *connector)
{
struct intel_connector *intel_connector = to_intel_connector(connector);
- kfree(intel_connector->detect_edid);
+ drm_edid_free(intel_connector->detect_edid);
intel_hdcp_cleanup(intel_connector);
- if (!IS_ERR_OR_NULL(intel_connector->edid))
- kfree(intel_connector->edid);
-
intel_panel_fini(intel_connector);
drm_connector_cleanup(connector);
diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c
index 797ad9489f7e..7267ffc7f539 100644
--- a/drivers/gpu/drm/i915/display/intel_crt.c
+++ b/drivers/gpu/drm/i915/display/intel_crt.c
@@ -682,30 +682,20 @@ intel_crt_load_detect(struct intel_crt *crt, u32 pipe)
{
struct drm_device *dev = crt->base.base.dev;
struct drm_i915_private *dev_priv = to_i915(dev);
- struct intel_uncore *uncore = &dev_priv->uncore;
u32 save_bclrpat;
u32 save_vtotal;
u32 vtotal, vactive;
u32 vsample;
u32 vblank, vblank_start, vblank_end;
u32 dsl;
- i915_reg_t bclrpat_reg, vtotal_reg,
- vblank_reg, vsync_reg, pipeconf_reg, pipe_dsl_reg;
u8 st00;
enum drm_connector_status status;
drm_dbg_kms(&dev_priv->drm, "starting load-detect on CRT\n");
- bclrpat_reg = BCLRPAT(pipe);
- vtotal_reg = VTOTAL(pipe);
- vblank_reg = VBLANK(pipe);
- vsync_reg = VSYNC(pipe);
- pipeconf_reg = PIPECONF(pipe);
- pipe_dsl_reg = PIPEDSL(pipe);
-
- save_bclrpat = intel_uncore_read(uncore, bclrpat_reg);
- save_vtotal = intel_uncore_read(uncore, vtotal_reg);
- vblank = intel_uncore_read(uncore, vblank_reg);
+ save_bclrpat = intel_de_read(dev_priv, BCLRPAT(pipe));
+ save_vtotal = intel_de_read(dev_priv, VTOTAL(pipe));
+ vblank = intel_de_read(dev_priv, VBLANK(pipe));
vtotal = ((save_vtotal >> 16) & 0xfff) + 1;
vactive = (save_vtotal & 0x7ff) + 1;
@@ -714,23 +704,23 @@ intel_crt_load_detect(struct intel_crt *crt, u32 pipe)
vblank_end = ((vblank >> 16) & 0xfff) + 1;
/* Set the border color to purple. */
- intel_uncore_write(uncore, bclrpat_reg, 0x500050);
+ intel_de_write(dev_priv, BCLRPAT(pipe), 0x500050);
if (DISPLAY_VER(dev_priv) != 2) {
- u32 pipeconf = intel_uncore_read(uncore, pipeconf_reg);
- intel_uncore_write(uncore,
- pipeconf_reg,
- pipeconf | PIPECONF_FORCE_BORDER);
- intel_uncore_posting_read(uncore, pipeconf_reg);
+ u32 pipeconf = intel_de_read(dev_priv, PIPECONF(pipe));
+
+ intel_de_write(dev_priv, PIPECONF(pipe),
+ pipeconf | PIPECONF_FORCE_BORDER);
+ intel_de_posting_read(dev_priv, PIPECONF(pipe));
/* Wait for next Vblank to substitue
* border color for Color info */
intel_crtc_wait_for_next_vblank(intel_crtc_for_pipe(dev_priv, pipe));
- st00 = intel_uncore_read8(uncore, _VGA_MSR_WRITE);
+ st00 = intel_de_read8(dev_priv, _VGA_MSR_WRITE);
status = ((st00 & (1 << 4)) != 0) ?
connector_status_connected :
connector_status_disconnected;
- intel_uncore_write(uncore, pipeconf_reg, pipeconf);
+ intel_de_write(dev_priv, PIPECONF(pipe), pipeconf);
} else {
bool restore_vblank = false;
int count, detect;
@@ -740,14 +730,12 @@ intel_crt_load_detect(struct intel_crt *crt, u32 pipe)
* Yes, this will flicker
*/
if (vblank_start <= vactive && vblank_end >= vtotal) {
- u32 vsync = intel_de_read(dev_priv, vsync_reg);
+ u32 vsync = intel_de_read(dev_priv, VSYNC(pipe));
u32 vsync_start = (vsync & 0xffff) + 1;
vblank_start = vsync_start;
- intel_uncore_write(uncore,
- vblank_reg,
- (vblank_start - 1) |
- ((vblank_end - 1) << 16));
+ intel_de_write(dev_priv, VBLANK(pipe),
+ (vblank_start - 1) | ((vblank_end - 1) << 16));
restore_vblank = true;
}
/* sample in the vertical border, selecting the larger one */
@@ -759,10 +747,9 @@ intel_crt_load_detect(struct intel_crt *crt, u32 pipe)
/*
* Wait for the border to be displayed
*/
- while (intel_uncore_read(uncore, pipe_dsl_reg) >= vactive)
+ while (intel_de_read(dev_priv, PIPEDSL(pipe)) >= vactive)
;
- while ((dsl = intel_uncore_read(uncore, pipe_dsl_reg)) <=
- vsample)
+ while ((dsl = intel_de_read(dev_priv, PIPEDSL(pipe))) <= vsample)
;
/*
* Watch ST00 for an entire scanline
@@ -772,14 +759,14 @@ intel_crt_load_detect(struct intel_crt *crt, u32 pipe)
do {
count++;
/* Read the ST00 VGA status register */
- st00 = intel_uncore_read8(uncore, _VGA_MSR_WRITE);
+ st00 = intel_de_read8(dev_priv, _VGA_MSR_WRITE);
if (st00 & (1 << 4))
detect++;
- } while ((intel_uncore_read(uncore, pipe_dsl_reg) == dsl));
+ } while ((intel_de_read(dev_priv, PIPEDSL(pipe)) == dsl));
/* restore vblank if necessary */
if (restore_vblank)
- intel_uncore_write(uncore, vblank_reg, vblank);
+ intel_de_write(dev_priv, VBLANK(pipe), vblank);
/*
* If more than 3/4 of the scanline detected a monitor,
* then it is assumed to be present. This works even on i830,
@@ -792,7 +779,7 @@ intel_crt_load_detect(struct intel_crt *crt, u32 pipe)
}
/* Restore previous settings */
- intel_uncore_write(uncore, bclrpat_reg, save_bclrpat);
+ intel_de_write(dev_priv, BCLRPAT(pipe), save_bclrpat);
return status;
}
diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c
index 037fc140b585..82be0fbe9934 100644
--- a/drivers/gpu/drm/i915/display/intel_crtc.c
+++ b/drivers/gpu/drm/i915/display/intel_crtc.c
@@ -28,6 +28,7 @@
#include "intel_pipe_crc.h"
#include "intel_psr.h"
#include "intel_sprite.h"
+#include "intel_vblank.h"
#include "intel_vrr.h"
#include "skl_universal_plane.h"
diff --git a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c
index e3273fe8ddac..2422d6ef5777 100644
--- a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c
+++ b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c
@@ -3,6 +3,8 @@
* Copyright © 2022 Intel Corporation
*/
+#include <drm/drm_edid.h>
+
#include "i915_drv.h"
#include "intel_crtc_state_dump.h"
#include "intel_display_types.h"
@@ -56,6 +58,17 @@ intel_dump_dp_vsc_sdp(struct drm_i915_private *i915,
drm_dp_vsc_sdp_log(KERN_DEBUG, i915->drm.dev, vsc);
}
+static void
+intel_dump_buffer(struct drm_i915_private *i915,
+ const char *prefix, const u8 *buf, size_t len)
+{
+ if (!drm_debug_enabled(DRM_UT_KMS))
+ return;
+
+ print_hex_dump(KERN_DEBUG, prefix, DUMP_PREFIX_NONE,
+ 16, 0, buf, len, false);
+}
+
#define OUTPUT_TYPE(x) [INTEL_OUTPUT_ ## x] = #x
static const char * const output_type_str[] = {
@@ -236,6 +249,10 @@ void intel_crtc_state_dump(const struct intel_crtc_state *pipe_config,
intel_hdmi_infoframe_enable(DP_SDP_VSC))
intel_dump_dp_vsc_sdp(i915, &pipe_config->infoframes.vsc);
+ if (pipe_config->has_audio)
+ intel_dump_buffer(i915, "ELD: ", pipe_config->eld,
+ drm_eld_size(pipe_config->eld));
+
drm_dbg_kms(&i915->drm, "vrr: %s, vmin: %d, vmax: %d, pipeline full: %d, guardband: %d flipline: %d, vmin vblank: %d, vmax vblank: %d\n",
str_yes_no(pipe_config->vrr.enable),
pipe_config->vrr.vmin, pipe_config->vrr.vmax,
diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
index 0f1ec2a98cc8..254559abedfb 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -185,6 +185,8 @@ void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv,
static void intel_wait_ddi_buf_active(struct drm_i915_private *dev_priv,
enum port port)
{
+ enum phy phy = intel_port_to_phy(dev_priv, port);
+ int timeout_us;
int ret;
/* Wait > 518 usecs for DDI_BUF_CTL to be non idle */
@@ -193,8 +195,19 @@ static void intel_wait_ddi_buf_active(struct drm_i915_private *dev_priv,
return;
}
+ if (IS_DG2(dev_priv)) {
+ timeout_us = 1200;
+ } else if (DISPLAY_VER(dev_priv) >= 12) {
+ if (intel_phy_is_tc(dev_priv, phy))
+ timeout_us = 3000;
+ else
+ timeout_us = 1000;
+ } else {
+ timeout_us = 500;
+ }
+
ret = _wait_for(!(intel_de_read(dev_priv, DDI_BUF_CTL(port)) &
- DDI_BUF_IS_IDLE), IS_DG2(dev_priv) ? 1200 : 500, 10, 10);
+ DDI_BUF_IS_IDLE), timeout_us, 10, 10);
if (ret)
drm_err(&dev_priv->drm, "Timeout waiting for DDI BUF %c to get active\n",
@@ -2726,10 +2739,10 @@ static void intel_ddi_post_disable(struct intel_atomic_state *state,
if (!intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_DP_MST)) {
intel_crtc_vblank_off(old_crtc_state);
- intel_disable_transcoder(old_crtc_state);
-
intel_vrr_disable(old_crtc_state);
+ intel_disable_transcoder(old_crtc_state);
+
intel_ddi_disable_transcoder_func(old_crtc_state);
intel_dsc_disable(old_crtc_state);
@@ -2933,6 +2946,8 @@ static void intel_enable_ddi_hdmi(struct intel_atomic_state *state,
}
intel_de_write(dev_priv, DDI_BUF_CTL(port), buf_ctl);
+ intel_wait_ddi_buf_active(dev_priv, port);
+
intel_audio_codec_enable(encoder, crtc_state, conn_state);
}
@@ -2946,10 +2961,13 @@ static void intel_enable_ddi(struct intel_atomic_state *state,
if (!intel_crtc_is_bigjoiner_slave(crtc_state))
intel_ddi_enable_transcoder_func(encoder, crtc_state);
- intel_vrr_enable(encoder, crtc_state);
+ /* Enable/Disable DP2.0 SDP split config before transcoder */
+ intel_audio_sdp_split_update(encoder, crtc_state);
intel_enable_transcoder(crtc_state);
+ intel_vrr_enable(encoder, crtc_state);
+
intel_crtc_vblank_on(crtc_state);
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
@@ -3478,6 +3496,8 @@ static void intel_ddi_get_config(struct intel_encoder *encoder,
intel_read_dp_sdp(encoder, pipe_config, DP_SDP_VSC);
intel_psr_get_config(encoder, pipe_config);
+
+ intel_audio_codec_get_config(encoder, pipe_config);
}
void intel_ddi_get_clock(struct intel_encoder *encoder,
@@ -4305,7 +4325,7 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
}
if (intel_phy_is_snps(dev_priv, phy) &&
- dev_priv->snps_phy_failed_calibration & BIT(phy)) {
+ dev_priv->display.snps.phy_failed_calibration & BIT(phy)) {
drm_dbg_kms(&dev_priv->drm,
"SNPS PHY %c failed to calibrate, proceeding anyway\n",
phy_name(phy));
diff --git a/drivers/gpu/drm/i915/display/intel_de.h b/drivers/gpu/drm/i915/display/intel_de.h
index 9c104f65e4c8..42552d8c151e 100644
--- a/drivers/gpu/drm/i915/display/intel_de.h
+++ b/drivers/gpu/drm/i915/display/intel_de.h
@@ -16,6 +16,19 @@ intel_de_read(struct drm_i915_private *i915, i915_reg_t reg)
return intel_uncore_read(&i915->uncore, reg);
}
+static inline u8
+intel_de_read8(struct drm_i915_private *i915, i915_reg_t reg)
+{
+ return intel_uncore_read8(&i915->uncore, reg);
+}
+
+static inline u64
+intel_de_read64_2x32(struct drm_i915_private *i915,
+ i915_reg_t lower_reg, i915_reg_t upper_reg)
+{
+ return intel_uncore_read64_2x32(&i915->uncore, lower_reg, upper_reg);
+}
+
static inline void
intel_de_posting_read(struct drm_i915_private *i915, i915_reg_t reg)
{
@@ -28,10 +41,10 @@ intel_de_write(struct drm_i915_private *i915, i915_reg_t reg, u32 val)
intel_uncore_write(&i915->uncore, reg, val);
}
-static inline void
+static inline u32
intel_de_rmw(struct drm_i915_private *i915, i915_reg_t reg, u32 clear, u32 set)
{
- intel_uncore_rmw(&i915->uncore, reg, clear, set);
+ return intel_uncore_rmw(&i915->uncore, reg, clear, set);
}
static inline int
@@ -42,6 +55,23 @@ intel_de_wait_for_register(struct drm_i915_private *i915, i915_reg_t reg,
}
static inline int
+intel_de_wait_for_register_fw(struct drm_i915_private *i915, i915_reg_t reg,
+ u32 mask, u32 value, unsigned int timeout)
+{
+ return intel_wait_for_register_fw(&i915->uncore, reg, mask, value, timeout);
+}
+
+static inline int
+__intel_de_wait_for_register(struct drm_i915_private *i915, i915_reg_t reg,
+ u32 mask, u32 value,
+ unsigned int fast_timeout_us,
+ unsigned int slow_timeout_ms, u32 *out_value)
+{
+ return __intel_wait_for_register(&i915->uncore, reg, mask, value,
+ fast_timeout_us, slow_timeout_ms, out_value);
+}
+
+static inline int
intel_de_wait_for_set(struct drm_i915_private *i915, i915_reg_t reg,
u32 mask, unsigned int timeout)
{
@@ -81,4 +111,16 @@ intel_de_write_fw(struct drm_i915_private *i915, i915_reg_t reg, u32 val)
intel_uncore_write_fw(&i915->uncore, reg, val);
}
+static inline u32
+intel_de_read_notrace(struct drm_i915_private *i915, i915_reg_t reg)
+{
+ return intel_uncore_read_notrace(&i915->uncore, reg);
+}
+
+static inline void
+intel_de_write_notrace(struct drm_i915_private *i915, i915_reg_t reg, u32 val)
+{
+ intel_uncore_write_notrace(&i915->uncore, reg, val);
+}
+
#endif /* __INTEL_DE_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index 6c2686ecb62a..d3994e2a7d63 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -24,15 +24,15 @@
* Eric Anholt <eric@anholt.net>
*/
-#include <acpi/video.h>
+#include <linux/dma-resv.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/dma-resv.h>
#include <linux/slab.h>
#include <linux/string_helpers.h>
#include <linux/vga_switcheroo.h>
+#include <acpi/video.h>
#include <drm/display/drm_dp_helper.h>
#include <drm/drm_atomic.h>
@@ -45,65 +45,57 @@
#include <drm/drm_probe_helper.h>
#include <drm/drm_rect.h>
-#include "display/intel_audio.h"
-#include "display/intel_crt.h"
-#include "display/intel_ddi.h"
-#include "display/intel_display_debugfs.h"
-#include "display/intel_display_power.h"
-#include "display/intel_dp.h"
-#include "display/intel_dp_mst.h"
-#include "display/intel_dpll.h"
-#include "display/intel_dpll_mgr.h"
-#include "display/intel_drrs.h"
-#include "display/intel_dsi.h"
-#include "display/intel_dvo.h"
-#include "display/intel_fb.h"
-#include "display/intel_gmbus.h"
-#include "display/intel_hdmi.h"
-#include "display/intel_lvds.h"
-#include "display/intel_sdvo.h"
-#include "display/intel_snps_phy.h"
-#include "display/intel_tv.h"
-#include "display/intel_vdsc.h"
-#include "display/intel_vrr.h"
-
#include "gem/i915_gem_lmem.h"
#include "gem/i915_gem_object.h"
-#include "gt/gen8_ppgtt.h"
-
#include "g4x_dp.h"
#include "g4x_hdmi.h"
#include "hsw_ips.h"
#include "i915_drv.h"
#include "i915_reg.h"
#include "i915_utils.h"
+#include "i9xx_plane.h"
#include "icl_dsi.h"
#include "intel_acpi.h"
#include "intel_atomic.h"
#include "intel_atomic_plane.h"
+#include "intel_audio.h"
#include "intel_bw.h"
#include "intel_cdclk.h"
#include "intel_color.h"
+#include "intel_crt.h"
#include "intel_crtc.h"
#include "intel_crtc_state_dump.h"
+#include "intel_ddi.h"
#include "intel_de.h"
+#include "intel_display_debugfs.h"
+#include "intel_display_power.h"
#include "intel_display_types.h"
#include "intel_dmc.h"
+#include "intel_dp.h"
#include "intel_dp_link_training.h"
+#include "intel_dp_mst.h"
#include "intel_dpio_phy.h"
+#include "intel_dpll.h"
+#include "intel_dpll_mgr.h"
#include "intel_dpt.h"
-#include "intel_dsb.h"
+#include "intel_drrs.h"
+#include "intel_dsi.h"
+#include "intel_dvo.h"
+#include "intel_fb.h"
#include "intel_fbc.h"
#include "intel_fbdev.h"
#include "intel_fdi.h"
#include "intel_fifo_underrun.h"
#include "intel_frontbuffer.h"
+#include "intel_gmbus.h"
#include "intel_hdcp.h"
+#include "intel_hdmi.h"
#include "intel_hotplug.h"
#include "intel_hti.h"
-#include "intel_modeset_verify.h"
+#include "intel_lvds.h"
#include "intel_modeset_setup.h"
+#include "intel_modeset_verify.h"
#include "intel_overlay.h"
#include "intel_panel.h"
#include "intel_pch_display.h"
@@ -115,10 +107,15 @@
#include "intel_pps.h"
#include "intel_psr.h"
#include "intel_quirks.h"
+#include "intel_sdvo.h"
+#include "intel_snps_phy.h"
#include "intel_sprite.h"
#include "intel_tc.h"
+#include "intel_tv.h"
+#include "intel_vblank.h"
+#include "intel_vdsc.h"
#include "intel_vga.h"
-#include "i9xx_plane.h"
+#include "intel_vrr.h"
#include "skl_scaler.h"
#include "skl_universal_plane.h"
#include "skl_watermark.h"
@@ -388,41 +385,6 @@ struct intel_crtc *intel_master_crtc(const struct intel_crtc_state *crtc_state)
return to_intel_crtc(crtc_state->uapi.crtc);
}
-static bool pipe_scanline_is_moving(struct drm_i915_private *dev_priv,
- enum pipe pipe)
-{
- i915_reg_t reg = PIPEDSL(pipe);
- u32 line1, line2;
-
- line1 = intel_de_read(dev_priv, reg) & PIPEDSL_LINE_MASK;
- msleep(5);
- line2 = intel_de_read(dev_priv, reg) & PIPEDSL_LINE_MASK;
-
- return line1 != line2;
-}
-
-static void wait_for_pipe_scanline_moving(struct intel_crtc *crtc, bool state)
-{
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
- enum pipe pipe = crtc->pipe;
-
- /* Wait for the display line to settle/start moving */
- if (wait_for(pipe_scanline_is_moving(dev_priv, pipe) == state, 100))
- drm_err(&dev_priv->drm,
- "pipe %c scanline %s wait timed out\n",
- pipe_name(pipe), str_on_off(state));
-}
-
-static void intel_wait_for_pipe_scanline_stopped(struct intel_crtc *crtc)
-{
- wait_for_pipe_scanline_moving(crtc, false);
-}
-
-static void intel_wait_for_pipe_scanline_moving(struct intel_crtc *crtc)
-{
- wait_for_pipe_scanline_moving(crtc, true);
-}
-
static void
intel_wait_for_pipe_off(const struct intel_crtc_state *old_crtc_state)
{
@@ -1098,22 +1060,6 @@ intel_get_crtc_new_encoder(const struct intel_atomic_state *state,
return encoder;
}
-static void cpt_verify_modeset(struct drm_i915_private *dev_priv,
- enum pipe pipe)
-{
- i915_reg_t dslreg = PIPEDSL(pipe);
- u32 temp;
-
- temp = intel_de_read(dev_priv, dslreg);
- udelay(500);
- if (wait_for(intel_de_read(dev_priv, dslreg) != temp, 5)) {
- if (wait_for(intel_de_read(dev_priv, dslreg) != temp, 5))
- drm_err(&dev_priv->drm,
- "mode set failed: pipe %c stuck\n",
- pipe_name(pipe));
- }
-}
-
static void ilk_pfit_enable(const struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
@@ -1246,7 +1192,6 @@ static void intel_post_plane_update(struct intel_atomic_state *state,
if (new_crtc_state->update_wm_post && new_crtc_state->hw.active)
intel_update_watermarks(dev_priv);
- hsw_ips_post_update(state, crtc);
intel_fbc_post_update(state, crtc);
if (needs_async_flip_vtd_wa(old_crtc_state) &&
@@ -1809,7 +1754,7 @@ static void ilk_crtc_enable(struct intel_atomic_state *state,
intel_encoders_enable(state, crtc);
if (HAS_PCH_CPT(dev_priv))
- cpt_verify_modeset(dev_priv, pipe);
+ intel_wait_for_pipe_scanline_moving(crtc);
/*
* Must wait for vblank to avoid spurious PCH FIFO underruns.
@@ -1922,6 +1867,8 @@ static void hsw_crtc_enable(struct intel_atomic_state *state,
if (drm_WARN_ON(&dev_priv->drm, crtc->active))
return;
+ intel_dmc_enable_pipe(dev_priv, crtc->pipe);
+
if (!new_crtc_state->bigjoiner_pipes) {
intel_encoders_pre_pll_enable(state, crtc);
@@ -2057,6 +2004,7 @@ static void hsw_crtc_disable(struct intel_atomic_state *state,
{
const struct intel_crtc_state *old_crtc_state =
intel_atomic_get_old_crtc_state(state, crtc);
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
/*
* FIXME collapse everything to one hook.
@@ -2066,6 +2014,8 @@ static void hsw_crtc_disable(struct intel_atomic_state *state,
intel_encoders_disable(state, crtc);
intel_encoders_post_disable(state, crtc);
}
+
+ intel_dmc_disable_pipe(i915, crtc->pipe);
}
static void i9xx_pfit_enable(const struct intel_crtc_state *crtc_state)
@@ -3296,7 +3246,7 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
if (DISPLAY_VER(dev_priv) >= 4) {
/* No way to read it out on pipes B and C */
if (IS_CHERRYVIEW(dev_priv) && crtc->pipe != PIPE_A)
- tmp = dev_priv->chv_dpll_md[crtc->pipe];
+ tmp = dev_priv->display.state.chv_dpll_md[crtc->pipe];
else
tmp = intel_de_read(dev_priv, DPLL_MD(crtc->pipe));
pipe_config->pixel_multiplier =
@@ -5433,6 +5383,12 @@ intel_compare_dp_vsc_sdp(const struct drm_dp_vsc_sdp *a,
return memcmp(a, b, sizeof(*a)) == 0;
}
+static bool
+intel_compare_buffer(const u8 *a, const u8 *b, size_t len)
+{
+ return memcmp(a, b, len) == 0;
+}
+
static void
pipe_config_infoframe_mismatch(struct drm_i915_private *dev_priv,
bool fastset, const char *name,
@@ -5483,6 +5439,30 @@ pipe_config_dp_vsc_sdp_mismatch(struct drm_i915_private *dev_priv,
}
}
+static void
+pipe_config_buffer_mismatch(struct drm_i915_private *dev_priv,
+ bool fastset, const char *name,
+ const u8 *a, const u8 *b, size_t len)
+{
+ if (fastset) {
+ if (!drm_debug_enabled(DRM_UT_KMS))
+ return;
+
+ drm_dbg_kms(&dev_priv->drm,
+ "fastset mismatch in %s buffer\n", name);
+ print_hex_dump(KERN_DEBUG, "expected: ", DUMP_PREFIX_NONE,
+ 16, 0, a, len, false);
+ print_hex_dump(KERN_DEBUG, "found: ", DUMP_PREFIX_NONE,
+ 16, 0, b, len, false);
+ } else {
+ drm_err(&dev_priv->drm, "mismatch in %s buffer\n", name);
+ print_hex_dump(KERN_ERR, "expected: ", DUMP_PREFIX_NONE,
+ 16, 0, a, len, false);
+ print_hex_dump(KERN_ERR, "found: ", DUMP_PREFIX_NONE,
+ 16, 0, b, len, false);
+ }
+}
+
static void __printf(4, 5)
pipe_config_mismatch(bool fastset, const struct intel_crtc *crtc,
const char *name, const char *format, ...)
@@ -5531,7 +5511,6 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
struct drm_i915_private *dev_priv = to_i915(current_config->uapi.crtc->dev);
struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc);
bool ret = true;
- u32 bp_gamma = 0;
bool fixup_inherited = fastset &&
current_config->inherited && !pipe_config->inherited;
@@ -5682,21 +5661,26 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
} \
} while (0)
-#define PIPE_CONF_CHECK_COLOR_LUT(name1, name2, bit_precision) do { \
- if (current_config->name1 != pipe_config->name1) { \
- pipe_config_mismatch(fastset, crtc, __stringify(name1), \
- "(expected %i, found %i, won't compare lut values)", \
- current_config->name1, \
- pipe_config->name1); \
- ret = false;\
- } else { \
- if (!intel_color_lut_equal(current_config->name2, \
- pipe_config->name2, pipe_config->name1, \
- bit_precision)) { \
- pipe_config_mismatch(fastset, crtc, __stringify(name2), \
- "hw_state doesn't match sw_state"); \
- ret = false; \
- } \
+#define PIPE_CONF_CHECK_BUFFER(name, len) do { \
+ BUILD_BUG_ON(sizeof(current_config->name) != (len)); \
+ BUILD_BUG_ON(sizeof(pipe_config->name) != (len)); \
+ if (!intel_compare_buffer(current_config->name, pipe_config->name, (len))) { \
+ pipe_config_buffer_mismatch(dev_priv, fastset, __stringify(name), \
+ current_config->name, \
+ pipe_config->name, \
+ (len)); \
+ ret = false; \
+ } \
+} while (0)
+
+#define PIPE_CONF_CHECK_COLOR_LUT(lut, is_pre_csc_lut) do { \
+ if (current_config->gamma_mode == pipe_config->gamma_mode && \
+ !intel_color_lut_equal(current_config, \
+ current_config->lut, pipe_config->lut, \
+ is_pre_csc_lut)) { \
+ pipe_config_mismatch(fastset, crtc, __stringify(lut), \
+ "hw_state doesn't match sw_state"); \
+ ret = false; \
} \
} while (0)
@@ -5760,6 +5744,7 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
PIPE_CONF_CHECK_BOOL(fec_enable);
PIPE_CONF_CHECK_BOOL_INCOMPLETE(has_audio);
+ PIPE_CONF_CHECK_BUFFER(eld, MAX_ELD_BYTES);
PIPE_CONF_CHECK_X(gmch_pfit.control);
/* pfit ratios are autocomputed by the hw on gen4+ */
@@ -5793,9 +5778,8 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,
PIPE_CONF_CHECK_I(linetime);
PIPE_CONF_CHECK_I(ips_linetime);
- bp_gamma = intel_color_get_gamma_bit_precision(pipe_config);
- if (bp_gamma)
- PIPE_CONF_CHECK_COLOR_LUT(gamma_mode, post_csc_lut, bp_gamma);
+ PIPE_CONF_CHECK_COLOR_LUT(pre_csc_lut, true);
+ PIPE_CONF_CHECK_COLOR_LUT(post_csc_lut, false);
if (current_config->active_planes) {
PIPE_CONF_CHECK_BOOL(has_psr);
@@ -5950,6 +5934,10 @@ int intel_modeset_all_pipes(struct intel_atomic_state *state,
if (ret)
return ret;
+ ret = intel_dp_mst_add_topology_state_for_crtc(state, crtc);
+ if (ret)
+ return ret;
+
ret = intel_atomic_add_affected_planes(state, crtc);
if (ret)
return ret;
@@ -6941,7 +6929,7 @@ static int intel_atomic_prepare_commit(struct intel_atomic_state *state)
for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) {
if (intel_crtc_needs_color_update(crtc_state))
- intel_dsb_prepare(crtc_state);
+ intel_color_prepare_commit(crtc_state);
}
return 0;
@@ -7392,24 +7380,18 @@ static void intel_atomic_commit_fence_wait(struct intel_atomic_state *intel_stat
&wait_reset);
}
-static void intel_cleanup_dsbs(struct intel_atomic_state *state)
-{
- struct intel_crtc_state *old_crtc_state, *new_crtc_state;
- struct intel_crtc *crtc;
- int i;
-
- for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
- new_crtc_state, i)
- intel_dsb_cleanup(old_crtc_state);
-}
-
static void intel_atomic_cleanup_work(struct work_struct *work)
{
struct intel_atomic_state *state =
container_of(work, struct intel_atomic_state, base.commit_work);
struct drm_i915_private *i915 = to_i915(state->base.dev);
+ struct intel_crtc_state *old_crtc_state;
+ struct intel_crtc *crtc;
+ int i;
+
+ for_each_old_intel_crtc_in_state(state, crtc, old_crtc_state, i)
+ intel_color_cleanup_commit(old_crtc_state);
- intel_cleanup_dsbs(state);
drm_atomic_helper_cleanup_planes(&i915->drm, &state->base);
drm_atomic_helper_commit_cleanup_done(&state->base);
drm_atomic_state_put(&state->base);
@@ -7587,6 +7569,9 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
intel_modeset_verify_crtc(crtc, state, old_crtc_state, new_crtc_state);
+ /* Must be done after gamma readout due to HSW split gamma vs. IPS w/a */
+ hsw_ips_post_update(state, crtc);
+
/*
* Activate DRRS after state readout to avoid
* dp_m_n vs. dp_m2_n2 confusion on BDW+.
@@ -7597,6 +7582,8 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
* DSB cleanup is done in cleanup_work aligning with framebuffer
* cleanup. So copy and reset the dsb structure to sync with
* commit_done and later do dsb cleanup in cleanup_work.
+ *
+ * FIXME get rid of this funny new->old swapping
*/
old_crtc_state->dsb = fetch_and_zero(&new_crtc_state->dsb);
}
@@ -7747,7 +7734,7 @@ static int intel_atomic_commit(struct drm_device *dev,
i915_sw_fence_commit(&state->commit_ready);
for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i)
- intel_dsb_cleanup(new_crtc_state);
+ intel_color_cleanup_commit(new_crtc_state);
drm_atomic_helper_cleanup_planes(dev, &state->base);
intel_runtime_pm_put(&dev_priv->runtime_pm, state->wakeref);
diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h
index 714030136b7f..cb6f520cc575 100644
--- a/drivers/gpu/drm/i915/display/intel_display.h
+++ b/drivers/gpu/drm/i915/display/intel_display.h
@@ -28,6 +28,7 @@
#include <drm/drm_util.h>
#include "i915_reg_defs.h"
+#include "intel_display_limits.h"
enum drm_scaling_filter;
struct dpll;
@@ -62,51 +63,9 @@ struct intel_remapped_info;
struct intel_rotation_info;
struct pci_dev;
-/*
- * Keep the pipe enum values fixed: the code assumes that PIPE_A=0, the
- * rest have consecutive values and match the enum values of transcoders
- * with a 1:1 transcoder -> pipe mapping.
- */
-enum pipe {
- INVALID_PIPE = -1,
-
- PIPE_A = 0,
- PIPE_B,
- PIPE_C,
- PIPE_D,
- _PIPE_EDP,
-
- I915_MAX_PIPES = _PIPE_EDP
-};
#define pipe_name(p) ((p) + 'A')
-enum transcoder {
- INVALID_TRANSCODER = -1,
- /*
- * The following transcoders have a 1:1 transcoder -> pipe mapping,
- * keep their values fixed: the code assumes that TRANSCODER_A=0, the
- * rest have consecutive values and match the enum values of the pipes
- * they map to.
- */
- TRANSCODER_A = PIPE_A,
- TRANSCODER_B = PIPE_B,
- TRANSCODER_C = PIPE_C,
- TRANSCODER_D = PIPE_D,
-
- /*
- * The following transcoders can map to any pipe, their enum value
- * doesn't need to stay fixed.
- */
- TRANSCODER_EDP,
- TRANSCODER_DSI_0,
- TRANSCODER_DSI_1,
- TRANSCODER_DSI_A = TRANSCODER_DSI_0, /* legacy DSI */
- TRANSCODER_DSI_C = TRANSCODER_DSI_1, /* legacy DSI */
-
- I915_MAX_TRANSCODERS
-};
-
static inline const char *transcoder_name(enum transcoder transcoder)
{
switch (transcoder) {
@@ -147,29 +106,6 @@ enum i9xx_plane_id {
#define plane_name(p) ((p) + 'A')
#define sprite_name(p, s) ((p) * RUNTIME_INFO(dev_priv)->num_sprites[(p)] + (s) + 'A')
-/*
- * Per-pipe plane identifier.
- * I915_MAX_PLANES in the enum below is the maximum (across all platforms)
- * number of planes per CRTC. Not all platforms really have this many planes,
- * which means some arrays of size I915_MAX_PLANES may have unused entries
- * between the topmost sprite plane and the cursor plane.
- *
- * This is expected to be passed to various register macros
- * (eg. PLANE_CTL(), PS_PLANE_SEL(), etc.) so adjust with care.
- */
-enum plane_id {
- PLANE_PRIMARY,
- PLANE_SPRITE0,
- PLANE_SPRITE1,
- PLANE_SPRITE2,
- PLANE_SPRITE3,
- PLANE_SPRITE4,
- PLANE_SPRITE5,
- PLANE_CURSOR,
-
- I915_MAX_PLANES,
-};
-
#define for_each_plane_id_on_crtc(__crtc, __p) \
for ((__p) = PLANE_PRIMARY; (__p) < I915_MAX_PLANES; (__p)++) \
for_each_if((__crtc)->plane_ids_mask & BIT(__p))
@@ -182,34 +118,6 @@ enum plane_id {
for_each_dbuf_slice((__dev_priv), (__slice)) \
for_each_if((__mask) & BIT(__slice))
-enum port {
- PORT_NONE = -1,
-
- PORT_A = 0,
- PORT_B,
- PORT_C,
- PORT_D,
- PORT_E,
- PORT_F,
- PORT_G,
- PORT_H,
- PORT_I,
-
- /* tgl+ */
- PORT_TC1 = PORT_D,
- PORT_TC2,
- PORT_TC3,
- PORT_TC4,
- PORT_TC5,
- PORT_TC6,
-
- /* XE_LPD repositions D/E offsets and bitfields */
- PORT_D_XELPD = PORT_TC5,
- PORT_E_XELPD,
-
- I915_MAX_PORTS
-};
-
#define port_name(p) ((p) + 'A')
/*
@@ -312,27 +220,6 @@ enum phy_fia {
FIA3,
};
-enum hpd_pin {
- HPD_NONE = 0,
- HPD_TV = HPD_NONE, /* TV is known to be unreliable */
- HPD_CRT,
- HPD_SDVO_B,
- HPD_SDVO_C,
- HPD_PORT_A,
- HPD_PORT_B,
- HPD_PORT_C,
- HPD_PORT_D,
- HPD_PORT_E,
- HPD_PORT_TC1,
- HPD_PORT_TC2,
- HPD_PORT_TC3,
- HPD_PORT_TC4,
- HPD_PORT_TC5,
- HPD_PORT_TC6,
-
- HPD_NUM_PINS
-};
-
#define for_each_hpd_pin(__pin) \
for ((__pin) = (HPD_NONE + 1); (__pin) < HPD_NUM_PINS; (__pin)++)
@@ -440,6 +327,14 @@ enum hpd_pin {
(__i)++) \
for_each_if(plane)
+#define for_each_old_intel_crtc_in_state(__state, crtc, old_crtc_state, __i) \
+ for ((__i) = 0; \
+ (__i) < (__state)->base.dev->mode_config.num_crtc && \
+ ((crtc) = to_intel_crtc((__state)->base.crtcs[__i].ptr), \
+ (old_crtc_state) = to_intel_crtc_state((__state)->base.crtcs[__i].old_state), 1); \
+ (__i)++) \
+ for_each_if(crtc)
+
#define for_each_new_intel_plane_in_state(__state, plane, new_plane_state, __i) \
for ((__i) = 0; \
(__i) < (__state)->base.dev->mode_config.num_total_plane && \
diff --git a/drivers/gpu/drm/i915/display/intel_display_core.h b/drivers/gpu/drm/i915/display/intel_display_core.h
index 57ddce3ba02b..fb8670aa2932 100644
--- a/drivers/gpu/drm/i915/display/intel_display_core.h
+++ b/drivers/gpu/drm/i915/display/intel_display_core.h
@@ -17,7 +17,7 @@
#include <drm/drm_modeset_lock.h>
#include "intel_cdclk.h"
-#include "intel_display.h"
+#include "intel_display_limits.h"
#include "intel_display_power.h"
#include "intel_dmc.h"
#include "intel_dpll_mgr.h"
@@ -87,6 +87,11 @@ struct intel_wm_funcs {
int (*compute_global_watermarks)(struct intel_atomic_state *state);
};
+struct intel_audio_state {
+ struct intel_encoder *encoder;
+ u8 eld[MAX_ELD_BYTES];
+};
+
struct intel_audio {
/* hda/i915 audio component */
struct i915_audio_component *component;
@@ -96,8 +101,8 @@ struct intel_audio {
int power_refcount;
u32 freq_cntrl;
- /* Used to save the pipe-to-encoder mapping for audio */
- struct intel_encoder *encoder_map[I915_MAX_PIPES];
+ /* current audio state for the audio component hooks */
+ struct intel_audio_state state[I915_MAX_PIPES];
/* necessary resource sharing with HDMI LPE audio driver. */
struct {
@@ -122,6 +127,11 @@ struct intel_dpll {
int nssc;
int ssc;
} ref_clks;
+
+ /*
+ * Bitmask of PLLs using the PCH SSC, indexed using enum intel_dpll_id.
+ */
+ u8 pch_ssc_use;
};
struct intel_frontbuffer_tracking {
@@ -429,6 +439,24 @@ struct intel_display {
} sagv;
struct {
+ /*
+ * DG2: Mask of PHYs that were not calibrated by the firmware
+ * and should not be used.
+ */
+ u8 phy_failed_calibration;
+ } snps;
+
+ struct {
+ /*
+ * Shadows for CHV DPLL_MD regs to keep the state
+ * checker somewhat working in the presence hardware
+ * crappiness (can't read out DPLL_MD for pipes B & C).
+ */
+ u32 chv_dpll_md[I915_MAX_PIPES];
+ u32 bxt_phy_grc;
+ } state;
+
+ struct {
/* ordered wq for modesets */
struct workqueue_struct *modeset;
diff --git a/drivers/gpu/drm/i915/display/intel_display_limits.h b/drivers/gpu/drm/i915/display/intel_display_limits.h
new file mode 100644
index 000000000000..5126d0b5ae5d
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/intel_display_limits.h
@@ -0,0 +1,124 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2022 Intel Corporation
+ */
+
+#ifndef __INTEL_DISPLAY_LIMITS_H__
+#define __INTEL_DISPLAY_LIMITS_H__
+
+/*
+ * Keep the pipe enum values fixed: the code assumes that PIPE_A=0, the
+ * rest have consecutive values and match the enum values of transcoders
+ * with a 1:1 transcoder -> pipe mapping.
+ */
+enum pipe {
+ INVALID_PIPE = -1,
+
+ PIPE_A = 0,
+ PIPE_B,
+ PIPE_C,
+ PIPE_D,
+ _PIPE_EDP,
+
+ I915_MAX_PIPES = _PIPE_EDP
+};
+
+enum transcoder {
+ INVALID_TRANSCODER = -1,
+ /*
+ * The following transcoders have a 1:1 transcoder -> pipe mapping,
+ * keep their values fixed: the code assumes that TRANSCODER_A=0, the
+ * rest have consecutive values and match the enum values of the pipes
+ * they map to.
+ */
+ TRANSCODER_A = PIPE_A,
+ TRANSCODER_B = PIPE_B,
+ TRANSCODER_C = PIPE_C,
+ TRANSCODER_D = PIPE_D,
+
+ /*
+ * The following transcoders can map to any pipe, their enum value
+ * doesn't need to stay fixed.
+ */
+ TRANSCODER_EDP,
+ TRANSCODER_DSI_0,
+ TRANSCODER_DSI_1,
+ TRANSCODER_DSI_A = TRANSCODER_DSI_0, /* legacy DSI */
+ TRANSCODER_DSI_C = TRANSCODER_DSI_1, /* legacy DSI */
+
+ I915_MAX_TRANSCODERS
+};
+
+/*
+ * Per-pipe plane identifier.
+ * I915_MAX_PLANES in the enum below is the maximum (across all platforms)
+ * number of planes per CRTC. Not all platforms really have this many planes,
+ * which means some arrays of size I915_MAX_PLANES may have unused entries
+ * between the topmost sprite plane and the cursor plane.
+ *
+ * This is expected to be passed to various register macros
+ * (eg. PLANE_CTL(), PS_PLANE_SEL(), etc.) so adjust with care.
+ */
+enum plane_id {
+ PLANE_PRIMARY,
+ PLANE_SPRITE0,
+ PLANE_SPRITE1,
+ PLANE_SPRITE2,
+ PLANE_SPRITE3,
+ PLANE_SPRITE4,
+ PLANE_SPRITE5,
+ PLANE_CURSOR,
+
+ I915_MAX_PLANES,
+};
+
+enum port {
+ PORT_NONE = -1,
+
+ PORT_A = 0,
+ PORT_B,
+ PORT_C,
+ PORT_D,
+ PORT_E,
+ PORT_F,
+ PORT_G,
+ PORT_H,
+ PORT_I,
+
+ /* tgl+ */
+ PORT_TC1 = PORT_D,
+ PORT_TC2,
+ PORT_TC3,
+ PORT_TC4,
+ PORT_TC5,
+ PORT_TC6,
+
+ /* XE_LPD repositions D/E offsets and bitfields */
+ PORT_D_XELPD = PORT_TC5,
+ PORT_E_XELPD,
+
+ I915_MAX_PORTS
+};
+
+enum hpd_pin {
+ HPD_NONE = 0,
+ HPD_TV = HPD_NONE, /* TV is known to be unreliable */
+ HPD_CRT,
+ HPD_SDVO_B,
+ HPD_SDVO_C,
+ HPD_PORT_A,
+ HPD_PORT_B,
+ HPD_PORT_C,
+ HPD_PORT_D,
+ HPD_PORT_E,
+ HPD_PORT_TC1,
+ HPD_PORT_TC2,
+ HPD_PORT_TC3,
+ HPD_PORT_TC4,
+ HPD_PORT_TC5,
+ HPD_PORT_TC6,
+
+ HPD_NUM_PINS
+};
+
+#endif /* __INTEL_DISPLAY_LIMITS_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c
index 3adba64937de..1a23ecd4623a 100644
--- a/drivers/gpu/drm/i915/display/intel_display_power.c
+++ b/drivers/gpu/drm/i915/display/intel_display_power.c
@@ -1673,7 +1673,7 @@ static void icl_display_core_init(struct drm_i915_private *dev_priv,
if (DISPLAY_VER(dev_priv) >= 12) {
val = DCPR_CLEAR_MEMSTAT_DIS | DCPR_SEND_RESP_IMM |
DCPR_MASK_LPMODE | DCPR_MASK_MAXLATENCY_MEMUP_CLR;
- intel_uncore_rmw(&dev_priv->uncore, GEN11_CHICKEN_DCPR_2, 0, val);
+ intel_de_rmw(dev_priv, GEN11_CHICKEN_DCPR_2, 0, val);
}
/* Wa_14011503030:xelpd */
diff --git a/drivers/gpu/drm/i915/display/intel_display_power_map.c b/drivers/gpu/drm/i915/display/intel_display_power_map.c
index f5d66ca85b19..6645eb1911d8 100644
--- a/drivers/gpu/drm/i915/display/intel_display_power_map.c
+++ b/drivers/gpu/drm/i915/display/intel_display_power_map.c
@@ -10,6 +10,7 @@
#include "intel_display_power_map.h"
#include "intel_display_power_well.h"
+#include "intel_display_types.h"
#define __LIST_INLINE_ELEMS(__elem_type, ...) \
((__elem_type[]) { __VA_ARGS__ })
diff --git a/drivers/gpu/drm/i915/display/intel_display_trace.h b/drivers/gpu/drm/i915/display/intel_display_trace.h
index 725aba3fa531..651ea8564e1b 100644
--- a/drivers/gpu/drm/i915/display/intel_display_trace.h
+++ b/drivers/gpu/drm/i915/display/intel_display_trace.h
@@ -17,6 +17,7 @@
#include "i915_irq.h"
#include "intel_crtc.h"
#include "intel_display_types.h"
+#include "intel_vblank.h"
#define __dev_name_i915(i915) dev_name((i915)->drm.dev)
#define __dev_name_kms(obj) dev_name((obj)->base.dev->dev)
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index f07395065a69..54c517ca9632 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -50,6 +50,7 @@
#include "i915_vma_types.h"
#include "intel_bios.h"
#include "intel_display.h"
+#include "intel_display_limits.h"
#include "intel_display_power.h"
#include "intel_dpll_mgr.h"
#include "intel_pm_types.h"
@@ -262,8 +263,6 @@ struct intel_encoder {
enum hpd_pin hpd_pin;
enum intel_display_power_domain power_domain;
- /* for communication with audio component; protected by av_mutex */
- const struct drm_connector *audio_connector;
/* VBT information for this encoder (may be NULL for older platforms) */
const struct intel_bios_encoder_data *devdata;
@@ -291,7 +290,7 @@ struct intel_vbt_panel_data {
struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */
/* Feature bits */
- unsigned int panel_type:4;
+ int panel_type;
unsigned int lvds_dither:1;
unsigned int bios_lvds_val; /* initial [PCH_]LVDS reg val in VBIOS */
@@ -330,7 +329,7 @@ struct intel_vbt_panel_data {
bool present;
bool active_low_pwm;
u8 min_brightness; /* min_brightness/255 of max */
- u8 controller; /* brightness controller number */
+ s8 controller; /* brightness controller number */
enum intel_backlight_type type;
} backlight;
@@ -351,6 +350,9 @@ struct intel_vbt_panel_data {
};
struct intel_panel {
+ /* Fixed EDID for eDP and LVDS. May hold ERR_PTR for invalid EDID. */
+ const struct drm_edid *fixed_edid;
+
struct list_head fixed_modes;
/* backlight */
@@ -591,9 +593,8 @@ struct intel_connector {
/* Panel info for eDP and LVDS */
struct intel_panel panel;
- /* Cached EDID for eDP and LVDS. May hold ERR_PTR for invalid EDID. */
- struct edid *edid;
- struct edid *detect_edid;
+ /* Cached EDID for detect. */
+ const struct drm_edid *detect_edid;
/* Number of times hotplug detection was tried after an HPD interrupt */
int hotplug_retries;
@@ -1261,6 +1262,8 @@ struct intel_crtc_state {
struct drm_dp_vsc_sdp vsc;
} infoframes;
+ u8 eld[MAX_ELD_BYTES];
+
/* HDMI scrambling status */
bool hdmi_scrambling;
@@ -1295,6 +1298,8 @@ struct intel_crtc_state {
/* Forward Error correction State */
bool fec_enable;
+ bool sdp_split_enable;
+
/* Pointer to master transcoder in case of tiled displays */
enum transcoder master_transcoder;
@@ -1568,11 +1573,19 @@ struct intel_pps {
ktime_t panel_power_off_time;
intel_wakeref_t vdd_wakeref;
- /*
- * Pipe whose power sequencer is currently locked into
- * this port. Only relevant on VLV/CHV.
- */
- enum pipe pps_pipe;
+ union {
+ /*
+ * Pipe whose power sequencer is currently locked into
+ * this port. Only relevant on VLV/CHV.
+ */
+ enum pipe pps_pipe;
+
+ /*
+ * Power sequencer index. Only relevant on BXT+.
+ */
+ int pps_idx;
+ };
+
/*
* Pipe currently driving the port. Used for preventing
* the use of the PPS for any pipe currentrly driving
@@ -1581,7 +1594,7 @@ struct intel_pps {
enum pipe active_pipe;
/*
* Set if the sequencer may be reset due to a power transition,
- * requiring a reinitialization. Only relevant on BXT.
+ * requiring a reinitialization. Only relevant on BXT+.
*/
bool pps_reset;
struct edp_power_seq pps_delays;
diff --git a/drivers/gpu/drm/i915/display/intel_dmc.c b/drivers/gpu/drm/i915/display/intel_dmc.c
index eff3add70611..257aa2b7cf20 100644
--- a/drivers/gpu/drm/i915/display/intel_dmc.c
+++ b/drivers/gpu/drm/i915/display/intel_dmc.c
@@ -42,62 +42,61 @@
#define DMC_VERSION_MAJOR(version) ((version) >> 16)
#define DMC_VERSION_MINOR(version) ((version) & 0xffff)
-#define DMC_PATH(platform, major, minor) \
- "i915/" \
- __stringify(platform) "_dmc_ver" \
- __stringify(major) "_" \
+#define DMC_PATH(platform) \
+ "i915/" __stringify(platform) "_dmc.bin"
+
+/*
+ * New DMC additions should not use this. This is used solely to remain
+ * compatible with systems that have not yet updated DMC blobs to use
+ * unversioned file names.
+ */
+#define DMC_LEGACY_PATH(platform, major, minor) \
+ "i915/" \
+ __stringify(platform) "_dmc_ver" \
+ __stringify(major) "_" \
__stringify(minor) ".bin"
#define DISPLAY_VER13_DMC_MAX_FW_SIZE 0x20000
#define DISPLAY_VER12_DMC_MAX_FW_SIZE ICL_DMC_MAX_FW_SIZE
-#define DG2_DMC_PATH DMC_PATH(dg2, 2, 08)
-#define DG2_DMC_VERSION_REQUIRED DMC_VERSION(2, 8)
+#define DG2_DMC_PATH DMC_LEGACY_PATH(dg2, 2, 08)
MODULE_FIRMWARE(DG2_DMC_PATH);
-#define ADLP_DMC_PATH DMC_PATH(adlp, 2, 16)
-#define ADLP_DMC_VERSION_REQUIRED DMC_VERSION(2, 16)
+#define ADLP_DMC_PATH DMC_PATH(adlp)
+#define ADLP_DMC_FALLBACK_PATH DMC_LEGACY_PATH(adlp, 2, 16)
MODULE_FIRMWARE(ADLP_DMC_PATH);
+MODULE_FIRMWARE(ADLP_DMC_FALLBACK_PATH);
-#define ADLS_DMC_PATH DMC_PATH(adls, 2, 01)
-#define ADLS_DMC_VERSION_REQUIRED DMC_VERSION(2, 1)
+#define ADLS_DMC_PATH DMC_LEGACY_PATH(adls, 2, 01)
MODULE_FIRMWARE(ADLS_DMC_PATH);
-#define DG1_DMC_PATH DMC_PATH(dg1, 2, 02)
-#define DG1_DMC_VERSION_REQUIRED DMC_VERSION(2, 2)
+#define DG1_DMC_PATH DMC_LEGACY_PATH(dg1, 2, 02)
MODULE_FIRMWARE(DG1_DMC_PATH);
-#define RKL_DMC_PATH DMC_PATH(rkl, 2, 03)
-#define RKL_DMC_VERSION_REQUIRED DMC_VERSION(2, 3)
+#define RKL_DMC_PATH DMC_LEGACY_PATH(rkl, 2, 03)
MODULE_FIRMWARE(RKL_DMC_PATH);
-#define TGL_DMC_PATH DMC_PATH(tgl, 2, 12)
-#define TGL_DMC_VERSION_REQUIRED DMC_VERSION(2, 12)
+#define TGL_DMC_PATH DMC_LEGACY_PATH(tgl, 2, 12)
MODULE_FIRMWARE(TGL_DMC_PATH);
-#define ICL_DMC_PATH DMC_PATH(icl, 1, 09)
-#define ICL_DMC_VERSION_REQUIRED DMC_VERSION(1, 9)
+#define ICL_DMC_PATH DMC_LEGACY_PATH(icl, 1, 09)
#define ICL_DMC_MAX_FW_SIZE 0x6000
MODULE_FIRMWARE(ICL_DMC_PATH);
-#define GLK_DMC_PATH DMC_PATH(glk, 1, 04)
-#define GLK_DMC_VERSION_REQUIRED DMC_VERSION(1, 4)
+#define GLK_DMC_PATH DMC_LEGACY_PATH(glk, 1, 04)
#define GLK_DMC_MAX_FW_SIZE 0x4000
MODULE_FIRMWARE(GLK_DMC_PATH);
-#define KBL_DMC_PATH DMC_PATH(kbl, 1, 04)
-#define KBL_DMC_VERSION_REQUIRED DMC_VERSION(1, 4)
+#define KBL_DMC_PATH DMC_LEGACY_PATH(kbl, 1, 04)
#define KBL_DMC_MAX_FW_SIZE BXT_DMC_MAX_FW_SIZE
MODULE_FIRMWARE(KBL_DMC_PATH);
-#define SKL_DMC_PATH DMC_PATH(skl, 1, 27)
-#define SKL_DMC_VERSION_REQUIRED DMC_VERSION(1, 27)
+#define SKL_DMC_PATH DMC_LEGACY_PATH(skl, 1, 27)
#define SKL_DMC_MAX_FW_SIZE BXT_DMC_MAX_FW_SIZE
MODULE_FIRMWARE(SKL_DMC_PATH);
-#define BXT_DMC_PATH DMC_PATH(bxt, 1, 07)
-#define BXT_DMC_VERSION_REQUIRED DMC_VERSION(1, 7)
+#define BXT_DMC_PATH DMC_LEGACY_PATH(bxt, 1, 07)
#define BXT_DMC_MAX_FW_SIZE 0x3000
MODULE_FIRMWARE(BXT_DMC_PATH);
@@ -108,6 +107,8 @@ MODULE_FIRMWARE(BXT_DMC_PATH);
#define DMC_V3_MAX_MMIO_COUNT 20
#define DMC_V1_MMIO_START_RANGE 0x80000
+#define PIPE_TO_DMC_ID(pipe) (DMC_FW_PIPEA + ((pipe) - PIPE_A))
+
struct intel_css_header {
/* 0x09 for DMC */
u32 module_type;
@@ -387,11 +388,11 @@ static void pipedmc_clock_gating_wa(struct drm_i915_private *i915, bool enable)
{
enum pipe pipe;
- if (DISPLAY_VER(i915) != 13)
+ if (DISPLAY_VER(i915) < 13)
return;
/*
- * Wa_16015201720:adl-p,dg2
+ * Wa_16015201720:adl-p,dg2, mtl
* The WA requires clock gating to be disabled all the time
* for pipe A and B.
* For pipe C and D clock gating needs to be disabled only
@@ -407,6 +408,28 @@ static void pipedmc_clock_gating_wa(struct drm_i915_private *i915, bool enable)
PIPEDMC_GATING_DIS, 0);
}
+void intel_dmc_enable_pipe(struct drm_i915_private *i915, enum pipe pipe)
+{
+ if (!has_dmc_id_fw(i915, PIPE_TO_DMC_ID(pipe)))
+ return;
+
+ if (DISPLAY_VER(i915) >= 14)
+ intel_de_rmw(i915, MTL_PIPEDMC_CONTROL, 0, PIPEDMC_ENABLE_MTL(pipe));
+ else
+ intel_de_rmw(i915, PIPEDMC_CONTROL(pipe), 0, PIPEDMC_ENABLE);
+}
+
+void intel_dmc_disable_pipe(struct drm_i915_private *i915, enum pipe pipe)
+{
+ if (!has_dmc_id_fw(i915, PIPE_TO_DMC_ID(pipe)))
+ return;
+
+ if (DISPLAY_VER(i915) >= 14)
+ intel_de_rmw(i915, MTL_PIPEDMC_CONTROL, PIPEDMC_ENABLE_MTL(pipe), 0);
+ else
+ intel_de_rmw(i915, PIPEDMC_CONTROL(pipe), PIPEDMC_ENABLE, 0);
+}
+
/**
* intel_dmc_load_program() - write the firmware from memory to register.
* @dev_priv: i915 drm device.
@@ -433,9 +456,9 @@ void intel_dmc_load_program(struct drm_i915_private *dev_priv)
for (id = 0; id < DMC_FW_MAX; id++) {
for (i = 0; i < dmc->dmc_info[id].dmc_fw_size; i++) {
- intel_uncore_write_fw(&dev_priv->uncore,
- DMC_PROGRAM(dmc->dmc_info[id].start_mmioaddr, i),
- dmc->dmc_info[id].payload[i]);
+ intel_de_write_fw(dev_priv,
+ DMC_PROGRAM(dmc->dmc_info[id].start_mmioaddr, i),
+ dmc->dmc_info[id].payload[i]);
}
}
@@ -765,17 +788,6 @@ static u32 parse_dmc_fw_css(struct intel_dmc *dmc,
return 0;
}
- if (dmc->required_version &&
- css_header->version != dmc->required_version) {
- drm_info(&i915->drm, "Refusing to load DMC firmware v%u.%u,"
- " please use v%u.%u\n",
- DMC_VERSION_MAJOR(css_header->version),
- DMC_VERSION_MINOR(css_header->version),
- DMC_VERSION_MAJOR(dmc->required_version),
- DMC_VERSION_MINOR(dmc->required_version));
- return 0;
- }
-
dmc->version = css_header->version;
return sizeof(struct intel_css_header);
@@ -843,16 +855,40 @@ static void intel_dmc_runtime_pm_put(struct drm_i915_private *dev_priv)
intel_display_power_put(dev_priv, POWER_DOMAIN_INIT, wakeref);
}
+static const char *dmc_fallback_path(struct drm_i915_private *i915)
+{
+ if (IS_ALDERLAKE_P(i915))
+ return ADLP_DMC_FALLBACK_PATH;
+
+ return NULL;
+}
+
static void dmc_load_work_fn(struct work_struct *work)
{
struct drm_i915_private *dev_priv;
struct intel_dmc *dmc;
const struct firmware *fw = NULL;
+ const char *fallback_path;
+ int err;
dev_priv = container_of(work, typeof(*dev_priv), display.dmc.work);
dmc = &dev_priv->display.dmc;
- request_firmware(&fw, dev_priv->display.dmc.fw_path, dev_priv->drm.dev);
+ err = request_firmware(&fw, dev_priv->display.dmc.fw_path, dev_priv->drm.dev);
+
+ if (err == -ENOENT && !dev_priv->params.dmc_firmware_path) {
+ fallback_path = dmc_fallback_path(dev_priv);
+ if (fallback_path) {
+ drm_dbg_kms(&dev_priv->drm,
+ "%s not found, falling back to %s\n",
+ dmc->fw_path,
+ fallback_path);
+ err = request_firmware(&fw, fallback_path, dev_priv->drm.dev);
+ if (err == 0)
+ dev_priv->display.dmc.fw_path = fallback_path;
+ }
+ }
+
parse_dmc_fw(dev_priv, fw);
if (intel_dmc_has_payload(dev_priv)) {
@@ -903,49 +939,38 @@ void intel_dmc_ucode_init(struct drm_i915_private *dev_priv)
if (IS_DG2(dev_priv)) {
dmc->fw_path = DG2_DMC_PATH;
- dmc->required_version = DG2_DMC_VERSION_REQUIRED;
dmc->max_fw_size = DISPLAY_VER13_DMC_MAX_FW_SIZE;
} else if (IS_ALDERLAKE_P(dev_priv)) {
dmc->fw_path = ADLP_DMC_PATH;
- dmc->required_version = ADLP_DMC_VERSION_REQUIRED;
dmc->max_fw_size = DISPLAY_VER13_DMC_MAX_FW_SIZE;
} else if (IS_ALDERLAKE_S(dev_priv)) {
dmc->fw_path = ADLS_DMC_PATH;
- dmc->required_version = ADLS_DMC_VERSION_REQUIRED;
dmc->max_fw_size = DISPLAY_VER12_DMC_MAX_FW_SIZE;
} else if (IS_DG1(dev_priv)) {
dmc->fw_path = DG1_DMC_PATH;
- dmc->required_version = DG1_DMC_VERSION_REQUIRED;
dmc->max_fw_size = DISPLAY_VER12_DMC_MAX_FW_SIZE;
} else if (IS_ROCKETLAKE(dev_priv)) {
dmc->fw_path = RKL_DMC_PATH;
- dmc->required_version = RKL_DMC_VERSION_REQUIRED;
dmc->max_fw_size = DISPLAY_VER12_DMC_MAX_FW_SIZE;
} else if (IS_TIGERLAKE(dev_priv)) {
dmc->fw_path = TGL_DMC_PATH;
- dmc->required_version = TGL_DMC_VERSION_REQUIRED;
dmc->max_fw_size = DISPLAY_VER12_DMC_MAX_FW_SIZE;
} else if (DISPLAY_VER(dev_priv) == 11) {
dmc->fw_path = ICL_DMC_PATH;
- dmc->required_version = ICL_DMC_VERSION_REQUIRED;
dmc->max_fw_size = ICL_DMC_MAX_FW_SIZE;
} else if (IS_GEMINILAKE(dev_priv)) {
dmc->fw_path = GLK_DMC_PATH;
- dmc->required_version = GLK_DMC_VERSION_REQUIRED;
dmc->max_fw_size = GLK_DMC_MAX_FW_SIZE;
} else if (IS_KABYLAKE(dev_priv) ||
IS_COFFEELAKE(dev_priv) ||
IS_COMETLAKE(dev_priv)) {
dmc->fw_path = KBL_DMC_PATH;
- dmc->required_version = KBL_DMC_VERSION_REQUIRED;
dmc->max_fw_size = KBL_DMC_MAX_FW_SIZE;
} else if (IS_SKYLAKE(dev_priv)) {
dmc->fw_path = SKL_DMC_PATH;
- dmc->required_version = SKL_DMC_VERSION_REQUIRED;
dmc->max_fw_size = SKL_DMC_MAX_FW_SIZE;
} else if (IS_BROXTON(dev_priv)) {
dmc->fw_path = BXT_DMC_PATH;
- dmc->required_version = BXT_DMC_VERSION_REQUIRED;
dmc->max_fw_size = BXT_DMC_MAX_FW_SIZE;
}
@@ -958,8 +983,6 @@ void intel_dmc_ucode_init(struct drm_i915_private *dev_priv)
}
dmc->fw_path = dev_priv->params.dmc_firmware_path;
- /* Bypass version check for firmware override. */
- dmc->required_version = 0;
}
if (!dmc->fw_path) {
diff --git a/drivers/gpu/drm/i915/display/intel_dmc.h b/drivers/gpu/drm/i915/display/intel_dmc.h
index 67e03315ef99..fd1725de4289 100644
--- a/drivers/gpu/drm/i915/display/intel_dmc.h
+++ b/drivers/gpu/drm/i915/display/intel_dmc.h
@@ -13,6 +13,8 @@
struct drm_i915_error_state_buf;
struct drm_i915_private;
+enum pipe;
+
enum {
DMC_FW_MAIN = 0,
DMC_FW_PIPEA,
@@ -25,7 +27,6 @@ enum {
struct intel_dmc {
struct work_struct work;
const char *fw_path;
- u32 required_version;
u32 max_fw_size; /* bytes */
u32 version;
struct dmc_fw_info {
@@ -48,6 +49,8 @@ struct intel_dmc {
void intel_dmc_ucode_init(struct drm_i915_private *i915);
void intel_dmc_load_program(struct drm_i915_private *i915);
void intel_dmc_disable_program(struct drm_i915_private *i915);
+void intel_dmc_enable_pipe(struct drm_i915_private *i915, enum pipe pipe);
+void intel_dmc_disable_pipe(struct drm_i915_private *i915, enum pipe pipe);
void intel_dmc_ucode_fini(struct drm_i915_private *i915);
void intel_dmc_ucode_suspend(struct drm_i915_private *i915);
void intel_dmc_ucode_resume(struct drm_i915_private *i915);
diff --git a/drivers/gpu/drm/i915/display/intel_dmc_regs.h b/drivers/gpu/drm/i915/display/intel_dmc_regs.h
index 5e5e41644ddf..cf10094acae3 100644
--- a/drivers/gpu/drm/i915/display/intel_dmc_regs.h
+++ b/drivers/gpu/drm/i915/display/intel_dmc_regs.h
@@ -11,6 +11,16 @@
#define DMC_PROGRAM(addr, i) _MMIO((addr) + (i) * 4)
#define DMC_SSP_BASE_ADDR_GEN9 0x00002FC0
+#define _PIPEDMC_CONTROL_A 0x45250
+#define _PIPEDMC_CONTROL_B 0x45254
+#define PIPEDMC_CONTROL(pipe) _MMIO_PIPE(pipe, \
+ _PIPEDMC_CONTROL_A, \
+ _PIPEDMC_CONTROL_B)
+#define PIPEDMC_ENABLE REG_BIT(0)
+
+#define MTL_PIPEDMC_CONTROL _MMIO(0x45250)
+#define PIPEDMC_ENABLE_MTL(pipe) REG_BIT(((pipe) - PIPE_A) * 4)
+
#define _ADLP_PIPEDMC_REG_MMIO_BASE_A 0x5f000
#define _TGL_PIPEDMC_REG_MMIO_BASE_A 0x92000
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 75070eb07d4b..62cbab7402e9 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -117,7 +117,6 @@ bool intel_dp_is_edp(struct intel_dp *intel_dp)
}
static void intel_dp_unset_edid(struct intel_dp *intel_dp);
-static int intel_dp_dsc_compute_bpp(struct intel_dp *intel_dp, u8 dsc_max_bpc);
/* Is link rate UHBR and thus 128b/132b? */
bool intel_dp_is_uhbr(const struct intel_crtc_state *crtc_state)
@@ -673,23 +672,59 @@ small_joiner_ram_size_bits(struct drm_i915_private *i915)
return 6144 * 8;
}
-static u16 intel_dp_dsc_get_output_bpp(struct drm_i915_private *i915,
- u32 link_clock, u32 lane_count,
- u32 mode_clock, u32 mode_hdisplay,
- bool bigjoiner,
- u32 pipe_bpp)
+u32 intel_dp_dsc_nearest_valid_bpp(struct drm_i915_private *i915, u32 bpp, u32 pipe_bpp)
{
- u32 bits_per_pixel, max_bpp_small_joiner_ram;
+ u32 bits_per_pixel = bpp;
int i;
+ /* Error out if the max bpp is less than smallest allowed valid bpp */
+ if (bits_per_pixel < valid_dsc_bpp[0]) {
+ drm_dbg_kms(&i915->drm, "Unsupported BPP %u, min %u\n",
+ bits_per_pixel, valid_dsc_bpp[0]);
+ return 0;
+ }
+
+ /* From XE_LPD onwards we support from bpc upto uncompressed bpp-1 BPPs */
+ if (DISPLAY_VER(i915) >= 13) {
+ bits_per_pixel = min(bits_per_pixel, pipe_bpp - 1);
+ } else {
+ /* Find the nearest match in the array of known BPPs from VESA */
+ for (i = 0; i < ARRAY_SIZE(valid_dsc_bpp) - 1; i++) {
+ if (bits_per_pixel < valid_dsc_bpp[i + 1])
+ break;
+ }
+ drm_dbg_kms(&i915->drm, "Set dsc bpp from %d to VESA %d\n",
+ bits_per_pixel, valid_dsc_bpp[i]);
+
+ bits_per_pixel = valid_dsc_bpp[i];
+ }
+
+ return bits_per_pixel;
+}
+
+u16 intel_dp_dsc_get_output_bpp(struct drm_i915_private *i915,
+ u32 link_clock, u32 lane_count,
+ u32 mode_clock, u32 mode_hdisplay,
+ bool bigjoiner,
+ u32 pipe_bpp,
+ u32 timeslots)
+{
+ u32 bits_per_pixel, max_bpp_small_joiner_ram;
+
/*
* Available Link Bandwidth(Kbits/sec) = (NumberOfLanes)*
- * (LinkSymbolClock)* 8 * (TimeSlotsPerMTP)
- * for SST -> TimeSlotsPerMTP is 1,
- * for MST -> TimeSlotsPerMTP has to be calculated
+ * (LinkSymbolClock)* 8 * (TimeSlots / 64)
+ * for SST -> TimeSlots is 64(i.e all TimeSlots that are available)
+ * for MST -> TimeSlots has to be calculated, based on mode requirements
*/
- bits_per_pixel = (link_clock * lane_count * 8) /
- intel_dp_mode_to_fec_clock(mode_clock);
+ bits_per_pixel = DIV_ROUND_UP((link_clock * lane_count) * timeslots,
+ intel_dp_mode_to_fec_clock(mode_clock) * 8);
+
+ drm_dbg_kms(&i915->drm, "Max link bpp is %u for %u timeslots "
+ "total bw %u pixel clock %u\n",
+ bits_per_pixel, timeslots,
+ (link_clock * lane_count * 8),
+ intel_dp_mode_to_fec_clock(mode_clock));
/* Small Joiner Check: output bpp <= joiner RAM (bits) / Horiz. width */
max_bpp_small_joiner_ram = small_joiner_ram_size_bits(i915) /
@@ -712,24 +747,7 @@ static u16 intel_dp_dsc_get_output_bpp(struct drm_i915_private *i915,
bits_per_pixel = min(bits_per_pixel, max_bpp_bigjoiner);
}
- /* Error out if the max bpp is less than smallest allowed valid bpp */
- if (bits_per_pixel < valid_dsc_bpp[0]) {
- drm_dbg_kms(&i915->drm, "Unsupported BPP %u, min %u\n",
- bits_per_pixel, valid_dsc_bpp[0]);
- return 0;
- }
-
- /* From XE_LPD onwards we support from bpc upto uncompressed bpp-1 BPPs */
- if (DISPLAY_VER(i915) >= 13) {
- bits_per_pixel = min(bits_per_pixel, pipe_bpp - 1);
- } else {
- /* Find the nearest match in the array of known BPPs from VESA */
- for (i = 0; i < ARRAY_SIZE(valid_dsc_bpp) - 1; i++) {
- if (bits_per_pixel < valid_dsc_bpp[i + 1])
- break;
- }
- bits_per_pixel = valid_dsc_bpp[i];
- }
+ bits_per_pixel = intel_dp_dsc_nearest_valid_bpp(i915, bits_per_pixel, pipe_bpp);
/*
* Compressed BPP in U6.4 format so multiply by 16, for Gen 11,
@@ -738,9 +756,9 @@ static u16 intel_dp_dsc_get_output_bpp(struct drm_i915_private *i915,
return bits_per_pixel << 4;
}
-static u8 intel_dp_dsc_get_slice_count(struct intel_dp *intel_dp,
- int mode_clock, int mode_hdisplay,
- bool bigjoiner)
+u8 intel_dp_dsc_get_slice_count(struct intel_dp *intel_dp,
+ int mode_clock, int mode_hdisplay,
+ bool bigjoiner)
{
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
u8 min_slice_count, i;
@@ -947,8 +965,8 @@ intel_dp_mode_valid_downstream(struct intel_connector *connector,
return MODE_OK;
}
-static bool intel_dp_need_bigjoiner(struct intel_dp *intel_dp,
- int hdisplay, int clock)
+bool intel_dp_need_bigjoiner(struct intel_dp *intel_dp,
+ int hdisplay, int clock)
{
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
@@ -974,9 +992,6 @@ intel_dp_mode_valid(struct drm_connector *_connector,
enum drm_mode_status status;
bool dsc = false, bigjoiner = false;
- if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
- return MODE_NO_DBLESCAN;
-
if (mode->flags & DRM_MODE_FLAG_DBLCLK)
return MODE_H_ILLEGAL;
@@ -1013,7 +1028,7 @@ intel_dp_mode_valid(struct drm_connector *_connector,
* Output bpp is stored in 6.4 format so right shift by 4 to get the
* integer value since we support only integer values of bpp.
*/
- if (DISPLAY_VER(dev_priv) >= 10 &&
+ if (HAS_DSC(dev_priv) &&
drm_dp_sink_supports_dsc(intel_dp->dsc_dpcd)) {
/*
* TBD pass the connector BPC,
@@ -1035,7 +1050,7 @@ intel_dp_mode_valid(struct drm_connector *_connector,
target_clock,
mode->hdisplay,
bigjoiner,
- pipe_bpp) >> 4;
+ pipe_bpp, 64) >> 4;
dsc_slice_count =
intel_dp_dsc_get_slice_count(intel_dp,
target_clock,
@@ -1364,7 +1379,7 @@ intel_dp_compute_link_config_wide(struct intel_dp *intel_dp,
return -EINVAL;
}
-static int intel_dp_dsc_compute_bpp(struct intel_dp *intel_dp, u8 max_req_bpc)
+int intel_dp_dsc_compute_bpp(struct intel_dp *intel_dp, u8 max_req_bpc)
{
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
int i, num_bpc;
@@ -1465,10 +1480,12 @@ static int intel_dp_dsc_compute_params(struct intel_encoder *encoder,
return drm_dsc_compute_rc_parameters(vdsc_cfg);
}
-static int intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
- struct intel_crtc_state *pipe_config,
- struct drm_connector_state *conn_state,
- struct link_config_limits *limits)
+int intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
+ struct intel_crtc_state *pipe_config,
+ struct drm_connector_state *conn_state,
+ struct link_config_limits *limits,
+ int timeslots,
+ bool compute_pipe_bpp)
{
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
@@ -1483,7 +1500,10 @@ static int intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
if (!intel_dp_supports_dsc(intel_dp, pipe_config))
return -EINVAL;
- pipe_bpp = intel_dp_dsc_compute_bpp(intel_dp, conn_state->max_requested_bpc);
+ if (compute_pipe_bpp)
+ pipe_bpp = intel_dp_dsc_compute_bpp(intel_dp, conn_state->max_requested_bpc);
+ else
+ pipe_bpp = pipe_config->pipe_bpp;
if (intel_dp->force_dsc_bpc) {
pipe_bpp = intel_dp->force_dsc_bpc * 3;
@@ -1514,33 +1534,52 @@ static int intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
drm_dp_dsc_sink_max_slice_count(intel_dp->dsc_dpcd,
true);
} else {
- u16 dsc_max_output_bpp;
+ u16 dsc_max_output_bpp = 0;
u8 dsc_dp_slice_count;
- dsc_max_output_bpp =
- intel_dp_dsc_get_output_bpp(dev_priv,
- pipe_config->port_clock,
- pipe_config->lane_count,
- adjusted_mode->crtc_clock,
- adjusted_mode->crtc_hdisplay,
- pipe_config->bigjoiner_pipes,
- pipe_bpp);
+ if (compute_pipe_bpp) {
+ dsc_max_output_bpp =
+ intel_dp_dsc_get_output_bpp(dev_priv,
+ pipe_config->port_clock,
+ pipe_config->lane_count,
+ adjusted_mode->crtc_clock,
+ adjusted_mode->crtc_hdisplay,
+ pipe_config->bigjoiner_pipes,
+ pipe_bpp,
+ timeslots);
+ if (!dsc_max_output_bpp) {
+ drm_dbg_kms(&dev_priv->drm,
+ "Compressed BPP not supported\n");
+ return -EINVAL;
+ }
+ }
dsc_dp_slice_count =
intel_dp_dsc_get_slice_count(intel_dp,
adjusted_mode->crtc_clock,
adjusted_mode->crtc_hdisplay,
pipe_config->bigjoiner_pipes);
- if (!dsc_max_output_bpp || !dsc_dp_slice_count) {
+ if (!dsc_dp_slice_count) {
drm_dbg_kms(&dev_priv->drm,
- "Compressed BPP/Slice Count not supported\n");
+ "Compressed Slice Count not supported\n");
return -EINVAL;
}
- pipe_config->dsc.compressed_bpp = min_t(u16,
- dsc_max_output_bpp >> 4,
- pipe_config->pipe_bpp);
+
+ /*
+ * compute pipe bpp is set to false for DP MST DSC case
+ * and compressed_bpp is calculated same time once
+ * vpci timeslots are allocated, because overall bpp
+ * calculation procedure is bit different for MST case.
+ */
+ if (compute_pipe_bpp) {
+ pipe_config->dsc.compressed_bpp = min_t(u16,
+ dsc_max_output_bpp >> 4,
+ pipe_config->pipe_bpp);
+ }
pipe_config->dsc.slice_count = dsc_dp_slice_count;
+ drm_dbg_kms(&dev_priv->drm, "DSC: compressed bpp %d slice count %d\n",
+ pipe_config->dsc.compressed_bpp,
+ pipe_config->dsc.slice_count);
}
-
/*
* VDSC engine operates at 1 Pixel per clock, so if peak pixel rate
* is greater than the maximum Cdclock and if slice count is even
@@ -1548,13 +1587,13 @@ static int intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
*/
if (adjusted_mode->crtc_clock > dev_priv->display.cdclk.max_cdclk_freq ||
pipe_config->bigjoiner_pipes) {
- if (pipe_config->dsc.slice_count < 2) {
+ if (pipe_config->dsc.slice_count > 1) {
+ pipe_config->dsc.dsc_split = true;
+ } else {
drm_dbg_kms(&dev_priv->drm,
"Cannot split stream to use 2 VDSC instances\n");
return -EINVAL;
}
-
- pipe_config->dsc.dsc_split = true;
}
ret = intel_dp_dsc_compute_params(&dig_port->base, pipe_config);
@@ -1643,7 +1682,7 @@ intel_dp_compute_link_config(struct intel_encoder *encoder,
str_yes_no(ret), str_yes_no(joiner_needs_dsc),
str_yes_no(intel_dp->force_dsc_en));
ret = intel_dp_dsc_compute_config(intel_dp, pipe_config,
- conn_state, &limits);
+ conn_state, &limits, 64, true);
if (ret < 0)
return ret;
}
@@ -2009,6 +2048,23 @@ intel_dp_compute_output_format(struct intel_encoder *encoder,
return ret;
}
+static void
+intel_dp_audio_compute_config(struct intel_encoder *encoder,
+ struct intel_crtc_state *pipe_config,
+ struct drm_connector_state *conn_state)
+{
+ struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+ struct drm_connector *connector = conn_state->connector;
+
+ pipe_config->sdp_split_enable =
+ intel_dp_has_audio(encoder, pipe_config, conn_state) &&
+ intel_dp_is_uhbr(pipe_config);
+
+ drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] SDP split enable: %s\n",
+ connector->base.id, connector->name,
+ str_yes_no(pipe_config->sdp_split_enable));
+}
+
int
intel_dp_compute_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config,
@@ -2024,7 +2080,9 @@ intel_dp_compute_config(struct intel_encoder *encoder,
if (HAS_PCH_SPLIT(dev_priv) && !HAS_DDI(dev_priv) && encoder->port != PORT_A)
pipe_config->has_pch_encoder = true;
- pipe_config->has_audio = intel_dp_has_audio(encoder, pipe_config, conn_state);
+ pipe_config->has_audio =
+ intel_dp_has_audio(encoder, pipe_config, conn_state) &&
+ intel_audio_compute_config(encoder, pipe_config, conn_state);
fixed_mode = intel_panel_fixed_mode(connector, adjusted_mode);
if (intel_dp_is_edp(intel_dp) && fixed_mode) {
@@ -2036,7 +2094,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
return -EINVAL;
- if (HAS_GMCH(dev_priv) &&
+ if (!connector->base.interlace_allowed &&
adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
return -EINVAL;
@@ -2092,6 +2150,8 @@ intel_dp_compute_config(struct intel_encoder *encoder,
adjusted_mode->crtc_clock /= n;
}
+ intel_dp_audio_compute_config(encoder, pipe_config, conn_state);
+
intel_link_compute_m_n(output_bpp,
pipe_config->lane_count,
adjusted_mode->crtc_clock,
@@ -2907,7 +2967,7 @@ intel_edp_init_dpcd(struct intel_dp *intel_dp)
intel_dp_set_max_sink_lane_count(intel_dp);
/* Read the eDP DSC DPCD registers */
- if (DISPLAY_VER(dev_priv) >= 10)
+ if (HAS_DSC(dev_priv))
intel_dp_get_dsc_sink_cap(intel_dp);
/*
@@ -3590,12 +3650,11 @@ static u8 intel_dp_autotest_edid(struct intel_dp *intel_dp)
intel_dp->aux.i2c_defer_count);
intel_dp->compliance.test_data.edid = INTEL_DP_RESOLUTION_FAILSAFE;
} else {
- struct edid *block = intel_connector->detect_edid;
+ /* FIXME: Get rid of drm_edid_raw() */
+ const struct edid *block = drm_edid_raw(intel_connector->detect_edid);
- /* We have to write the checksum
- * of the last block read
- */
- block += intel_connector->detect_edid->extensions;
+ /* We have to write the checksum of the last block read */
+ block += block->extensions;
if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_EDID_CHECKSUM,
block->checksum) <= 0)
@@ -4417,29 +4476,34 @@ bool intel_digital_port_connected(struct intel_encoder *encoder)
return is_connected;
}
-static struct edid *
+static const struct drm_edid *
intel_dp_get_edid(struct intel_dp *intel_dp)
{
- struct intel_connector *intel_connector = intel_dp->attached_connector;
+ struct intel_connector *connector = intel_dp->attached_connector;
+ const struct drm_edid *fixed_edid = connector->panel.fixed_edid;
- /* use cached edid if we have one */
- if (intel_connector->edid) {
+ /* Use panel fixed edid if we have one */
+ if (fixed_edid) {
/* invalid edid */
- if (IS_ERR(intel_connector->edid))
+ if (IS_ERR(fixed_edid))
return NULL;
- return drm_edid_duplicate(intel_connector->edid);
- } else
- return drm_get_edid(&intel_connector->base,
- &intel_dp->aux.ddc);
+ return drm_edid_dup(fixed_edid);
+ }
+
+ return drm_edid_read_ddc(&connector->base, &intel_dp->aux.ddc);
}
static void
intel_dp_update_dfp(struct intel_dp *intel_dp,
- const struct edid *edid)
+ const struct drm_edid *drm_edid)
{
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
struct intel_connector *connector = intel_dp->attached_connector;
+ const struct edid *edid;
+
+ /* FIXME: Get rid of drm_edid_raw() */
+ edid = drm_edid_raw(drm_edid);
intel_dp->dfp.max_bpc =
drm_dp_downstream_max_bpc(intel_dp->dpcd,
@@ -4539,21 +4603,27 @@ intel_dp_set_edid(struct intel_dp *intel_dp)
{
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
struct intel_connector *connector = intel_dp->attached_connector;
- struct edid *edid;
+ const struct drm_edid *drm_edid;
+ const struct edid *edid;
bool vrr_capable;
intel_dp_unset_edid(intel_dp);
- edid = intel_dp_get_edid(intel_dp);
- connector->detect_edid = edid;
+ drm_edid = intel_dp_get_edid(intel_dp);
+ connector->detect_edid = drm_edid;
+
+ /* Below we depend on display info having been updated */
+ drm_edid_connector_update(&connector->base, drm_edid);
vrr_capable = intel_vrr_is_capable(connector);
drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] VRR capable: %s\n",
connector->base.base.id, connector->base.name, str_yes_no(vrr_capable));
drm_connector_set_vrr_capable_property(&connector->base, vrr_capable);
- intel_dp_update_dfp(intel_dp, edid);
+ intel_dp_update_dfp(intel_dp, drm_edid);
intel_dp_update_420(intel_dp);
+ /* FIXME: Get rid of drm_edid_raw() */
+ edid = drm_edid_raw(drm_edid);
if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
intel_dp->has_hdmi_sink = drm_detect_hdmi_monitor(edid);
intel_dp->has_audio = drm_detect_monitor_audio(edid);
@@ -4568,7 +4638,7 @@ intel_dp_unset_edid(struct intel_dp *intel_dp)
struct intel_connector *connector = intel_dp->attached_connector;
drm_dp_cec_unset_edid(&intel_dp->aux);
- kfree(connector->detect_edid);
+ drm_edid_free(connector->detect_edid);
connector->detect_edid = NULL;
intel_dp->has_hdmi_sink = false;
@@ -4633,7 +4703,7 @@ intel_dp_detect(struct drm_connector *connector,
}
/* Read DP Sink DSC Cap DPCD regs for DP v1.4 */
- if (DISPLAY_VER(dev_priv) >= 11)
+ if (HAS_DSC(dev_priv))
intel_dp_get_dsc_sink_cap(intel_dp);
intel_dp_configure_mst(intel_dp);
@@ -4732,12 +4802,10 @@ intel_dp_force(struct drm_connector *connector)
static int intel_dp_get_modes(struct drm_connector *connector)
{
struct intel_connector *intel_connector = to_intel_connector(connector);
- struct edid *edid;
- int num_modes = 0;
+ int num_modes;
- edid = intel_connector->detect_edid;
- if (edid)
- num_modes = intel_connector_update_modes(connector, edid);
+ /* drm_edid_connector_update() done in ->detect() or ->force() */
+ num_modes = drm_edid_connector_add_modes(connector);
/* Also add fixed mode, which may or may not be present in EDID */
if (intel_dp_is_edp(intel_attached_dp(intel_connector)))
@@ -4746,7 +4814,7 @@ static int intel_dp_get_modes(struct drm_connector *connector)
if (num_modes)
return num_modes;
- if (!edid) {
+ if (!intel_connector->detect_edid) {
struct intel_dp *intel_dp = intel_attached_dp(intel_connector);
struct drm_display_mode *mode;
@@ -5182,7 +5250,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
struct drm_display_mode *fixed_mode;
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
bool has_dpcd;
- struct edid *edid;
+ const struct drm_edid *drm_edid;
if (!intel_dp_is_edp(intel_dp))
return true;
@@ -5202,7 +5270,20 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
return false;
}
- intel_pps_init(intel_dp);
+ intel_bios_init_panel_early(dev_priv, &intel_connector->panel,
+ encoder->devdata);
+
+ if (!intel_pps_init(intel_dp)) {
+ drm_info(&dev_priv->drm,
+ "[ENCODER:%d:%s] unusable PPS, disabling eDP\n",
+ encoder->base.base.id, encoder->base.name);
+ /*
+ * The BIOS may have still enabled VDD on the PPS even
+ * though it's unusable. Make sure we turn it back off
+ * and to release the power domain references/etc.
+ */
+ goto out_vdd_off;
+ }
/* Cache DPCD and EDID for edp. */
has_dpcd = intel_edp_init_dpcd(intel_dp);
@@ -5216,29 +5297,28 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
}
mutex_lock(&dev_priv->drm.mode_config.mutex);
- edid = drm_get_edid(connector, &intel_dp->aux.ddc);
- if (!edid) {
+ drm_edid = drm_edid_read_ddc(connector, &intel_dp->aux.ddc);
+ if (!drm_edid) {
/* Fallback to EDID from ACPI OpRegion, if any */
- edid = intel_opregion_get_edid(intel_connector);
- if (edid)
+ drm_edid = intel_opregion_get_edid(intel_connector);
+ if (drm_edid)
drm_dbg_kms(&dev_priv->drm,
"[CONNECTOR:%d:%s] Using OpRegion EDID\n",
connector->base.id, connector->name);
}
- if (edid) {
- if (drm_add_edid_modes(connector, edid)) {
- drm_connector_update_edid_property(connector, edid);
- } else {
- kfree(edid);
- edid = ERR_PTR(-EINVAL);
+ if (drm_edid) {
+ if (drm_edid_connector_update(connector, drm_edid) ||
+ !drm_edid_connector_add_modes(connector)) {
+ drm_edid_connector_update(connector, NULL);
+ drm_edid_free(drm_edid);
+ drm_edid = ERR_PTR(-EINVAL);
}
} else {
- edid = ERR_PTR(-ENOENT);
+ drm_edid = ERR_PTR(-ENOENT);
}
- intel_connector->edid = edid;
- intel_bios_init_panel(dev_priv, &intel_connector->panel,
- encoder->devdata, IS_ERR(edid) ? NULL : edid);
+ intel_bios_init_panel_late(dev_priv, &intel_connector->panel, encoder->devdata,
+ IS_ERR(drm_edid) ? NULL : drm_edid);
intel_panel_add_edid_fixed_modes(intel_connector, true);
@@ -5262,7 +5342,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
goto out_vdd_off;
}
- intel_panel_init(intel_connector);
+ intel_panel_init(intel_connector, drm_edid);
intel_edp_backlight_setup(intel_dp, intel_connector);
@@ -5364,7 +5444,7 @@ intel_dp_init_connector(struct intel_digital_port *dig_port,
drm_connector_init(dev, connector, &intel_dp_connector_funcs, type);
drm_connector_helper_add(connector, &intel_dp_connector_helper_funcs);
- if (!HAS_GMCH(dev_priv))
+ if (!HAS_GMCH(dev_priv) && DISPLAY_VER(dev_priv) < 12)
connector->interlace_allowed = true;
intel_connector->polled = DRM_CONNECTOR_POLL_HPD;
diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h
index a54902c713a3..ef39e4f7a329 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.h
+++ b/drivers/gpu/drm/i915/display/intel_dp.h
@@ -56,6 +56,12 @@ void intel_dp_encoder_flush_work(struct drm_encoder *encoder);
int intel_dp_compute_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config,
struct drm_connector_state *conn_state);
+int intel_dp_dsc_compute_config(struct intel_dp *intel_dp,
+ struct intel_crtc_state *pipe_config,
+ struct drm_connector_state *conn_state,
+ struct link_config_limits *limits,
+ int timeslots,
+ bool recompute_pipe_bpp);
bool intel_dp_is_edp(struct intel_dp *intel_dp);
bool intel_dp_is_uhbr(const struct intel_crtc_state *crtc_state);
bool intel_dp_is_port_edp(struct drm_i915_private *dev_priv, enum port port);
@@ -96,6 +102,18 @@ void intel_read_dp_sdp(struct intel_encoder *encoder,
struct intel_crtc_state *crtc_state,
unsigned int type);
bool intel_digital_port_connected(struct intel_encoder *encoder);
+int intel_dp_dsc_compute_bpp(struct intel_dp *intel_dp, u8 dsc_max_bpc);
+u16 intel_dp_dsc_get_output_bpp(struct drm_i915_private *i915,
+ u32 link_clock, u32 lane_count,
+ u32 mode_clock, u32 mode_hdisplay,
+ bool bigjoiner,
+ u32 pipe_bpp,
+ u32 timeslots);
+u8 intel_dp_dsc_get_slice_count(struct intel_dp *intel_dp,
+ int mode_clock, int mode_hdisplay,
+ bool bigjoiner);
+bool intel_dp_need_bigjoiner(struct intel_dp *intel_dp,
+ int hdisplay, int clock);
static inline unsigned int intel_dp_unused_lane_mask(int lane_count)
{
@@ -103,6 +121,7 @@ static inline unsigned int intel_dp_unused_lane_mask(int lane_count)
}
u32 intel_dp_mode_to_fec_clock(u32 mode_clock);
+u32 intel_dp_dsc_nearest_valid_bpp(struct drm_i915_private *i915, u32 bpp, u32 pipe_bpp);
void intel_ddi_update_pipe(struct intel_atomic_state *state,
struct intel_encoder *encoder,
diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux.c b/drivers/gpu/drm/i915/display/intel_dp_aux.c
index 664bebdecea7..5a176bfb10a2 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_aux.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_aux.c
@@ -6,6 +6,7 @@
#include "i915_drv.h"
#include "i915_reg.h"
#include "i915_trace.h"
+#include "intel_de.h"
#include "intel_display_types.h"
#include "intel_dp_aux.h"
#include "intel_pps.h"
@@ -40,20 +41,16 @@ intel_dp_aux_wait_done(struct intel_dp *intel_dp)
i915_reg_t ch_ctl = intel_dp->aux_ch_ctl_reg(intel_dp);
const unsigned int timeout_ms = 10;
u32 status;
- bool done;
-
-#define C (((status = intel_uncore_read_notrace(&i915->uncore, ch_ctl)) & DP_AUX_CH_CTL_SEND_BUSY) == 0)
- done = wait_event_timeout(i915->display.gmbus.wait_queue, C,
- msecs_to_jiffies_timeout(timeout_ms));
+ int ret;
- /* just trace the final value */
- trace_i915_reg_rw(false, ch_ctl, status, sizeof(status), true);
+ ret = __intel_de_wait_for_register(i915, ch_ctl,
+ DP_AUX_CH_CTL_SEND_BUSY, 0,
+ 2, timeout_ms, &status);
- if (!done)
+ if (ret == -ETIMEDOUT)
drm_err(&i915->drm,
"%s: did not complete or timeout within %ums (status 0x%08x)\n",
intel_dp->aux.name, timeout_ms, status);
-#undef C
return status;
}
@@ -191,7 +188,6 @@ intel_dp_aux_xfer(struct intel_dp *intel_dp,
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
struct drm_i915_private *i915 =
to_i915(dig_port->base.base.dev);
- struct intel_uncore *uncore = &i915->uncore;
enum phy phy = intel_port_to_phy(i915, dig_port->base.port);
bool is_tc_port = intel_phy_is_tc(i915, phy);
i915_reg_t ch_ctl, ch_data[5];
@@ -235,7 +231,7 @@ intel_dp_aux_xfer(struct intel_dp *intel_dp,
/* Try to wait for any previous AUX channel activity */
for (try = 0; try < 3; try++) {
- status = intel_uncore_read_notrace(uncore, ch_ctl);
+ status = intel_de_read_notrace(i915, ch_ctl);
if ((status & DP_AUX_CH_CTL_SEND_BUSY) == 0)
break;
msleep(1);
@@ -244,7 +240,7 @@ intel_dp_aux_xfer(struct intel_dp *intel_dp,
trace_i915_reg_rw(false, ch_ctl, status, sizeof(status), true);
if (try == 3) {
- const u32 status = intel_uncore_read(uncore, ch_ctl);
+ const u32 status = intel_de_read(i915, ch_ctl);
if (status != intel_dp->aux_busy_last_status) {
drm_WARN(&i915->drm, 1,
@@ -274,23 +270,20 @@ intel_dp_aux_xfer(struct intel_dp *intel_dp,
for (try = 0; try < 5; try++) {
/* Load the send data into the aux channel data registers */
for (i = 0; i < send_bytes; i += 4)
- intel_uncore_write(uncore,
- ch_data[i >> 2],
- intel_dp_aux_pack(send + i,
- send_bytes - i));
+ intel_de_write(i915, ch_data[i >> 2],
+ intel_dp_aux_pack(send + i,
+ send_bytes - i));
/* Send the command and wait for it to complete */
- intel_uncore_write(uncore, ch_ctl, send_ctl);
+ intel_de_write(i915, ch_ctl, send_ctl);
status = intel_dp_aux_wait_done(intel_dp);
/* Clear done status and any errors */
- intel_uncore_write(uncore,
- ch_ctl,
- status |
- DP_AUX_CH_CTL_DONE |
- DP_AUX_CH_CTL_TIME_OUT_ERROR |
- DP_AUX_CH_CTL_RECEIVE_ERROR);
+ intel_de_write(i915, ch_ctl,
+ status | DP_AUX_CH_CTL_DONE |
+ DP_AUX_CH_CTL_TIME_OUT_ERROR |
+ DP_AUX_CH_CTL_RECEIVE_ERROR);
/*
* DP CTS 1.2 Core Rev 1.1, 4.2.1.1 & 4.2.1.2
@@ -361,7 +354,7 @@ done:
recv_bytes = recv_size;
for (i = 0; i < recv_bytes; i += 4)
- intel_dp_aux_unpack(intel_uncore_read(uncore, ch_data[i >> 2]),
+ intel_dp_aux_unpack(intel_de_read(i915, ch_data[i >> 2]),
recv + i, recv_bytes - i);
ret = recv_bytes;
diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c
index 4077a979a924..054a009e800d 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c
@@ -45,10 +45,14 @@
#include "intel_hotplug.h"
#include "skl_scaler.h"
-static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder,
- struct intel_crtc_state *crtc_state,
- struct drm_connector_state *conn_state,
- struct link_config_limits *limits)
+static int intel_dp_mst_find_vcpi_slots_for_bpp(struct intel_encoder *encoder,
+ struct intel_crtc_state *crtc_state,
+ int max_bpp,
+ int min_bpp,
+ struct link_config_limits *limits,
+ struct drm_connector_state *conn_state,
+ int step,
+ bool dsc)
{
struct drm_atomic_state *state = crtc_state->uapi.state;
struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder);
@@ -60,6 +64,7 @@ static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder,
const struct drm_display_mode *adjusted_mode =
&crtc_state->hw.adjusted_mode;
int bpp, slots = -EINVAL;
+ int ret = 0;
mst_state = drm_atomic_get_mst_topology_state(state, &intel_dp->mst_mgr);
if (IS_ERR(mst_state))
@@ -71,30 +76,68 @@ static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder,
// TODO: Handle pbn_div changes by adding a new MST helper
if (!mst_state->pbn_div) {
mst_state->pbn_div = drm_dp_get_vc_payload_bw(&intel_dp->mst_mgr,
- limits->max_rate,
- limits->max_lane_count);
+ crtc_state->port_clock,
+ crtc_state->lane_count);
}
- for (bpp = limits->max_bpp; bpp >= limits->min_bpp; bpp -= 2 * 3) {
- crtc_state->pipe_bpp = bpp;
-
+ for (bpp = max_bpp; bpp >= min_bpp; bpp -= step) {
crtc_state->pbn = drm_dp_calc_pbn_mode(adjusted_mode->crtc_clock,
- crtc_state->pipe_bpp,
- false);
+ dsc ? bpp << 4 : bpp,
+ dsc);
+
+ drm_dbg_kms(&i915->drm, "Trying bpp %d\n", bpp);
+
slots = drm_dp_atomic_find_time_slots(state, &intel_dp->mst_mgr,
- connector->port, crtc_state->pbn);
+ connector->port,
+ crtc_state->pbn);
if (slots == -EDEADLK)
return slots;
- if (slots >= 0)
- break;
+
+ if (slots >= 0) {
+ ret = drm_dp_mst_atomic_check(state);
+ /*
+ * If we got slots >= 0 and we can fit those based on check
+ * then we can exit the loop. Otherwise keep trying.
+ */
+ if (!ret)
+ break;
+ }
}
+ /* Despite slots are non-zero, we still failed the atomic check */
+ if (ret && slots >= 0)
+ slots = ret;
+
if (slots < 0) {
drm_dbg_kms(&i915->drm, "failed finding vcpi slots:%d\n",
slots);
- return slots;
+ } else {
+ if (!dsc)
+ crtc_state->pipe_bpp = bpp;
+ else
+ crtc_state->dsc.compressed_bpp = bpp;
+ drm_dbg_kms(&i915->drm, "Got %d slots for pipe bpp %d dsc %d\n", slots, bpp, dsc);
}
+ return slots;
+}
+
+static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder,
+ struct intel_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state,
+ struct link_config_limits *limits)
+{
+ const struct drm_display_mode *adjusted_mode =
+ &crtc_state->hw.adjusted_mode;
+ int slots = -EINVAL;
+
+ slots = intel_dp_mst_find_vcpi_slots_for_bpp(encoder, crtc_state, limits->max_bpp,
+ limits->min_bpp, limits,
+ conn_state, 2 * 3, false);
+
+ if (slots < 0)
+ return slots;
+
intel_link_compute_m_n(crtc_state->pipe_bpp,
crtc_state->lane_count,
adjusted_mode->crtc_clock,
@@ -106,6 +149,99 @@ static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder,
return 0;
}
+static int intel_dp_dsc_mst_compute_link_config(struct intel_encoder *encoder,
+ struct intel_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state,
+ struct link_config_limits *limits)
+{
+ struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder);
+ struct intel_dp *intel_dp = &intel_mst->primary->dp;
+ struct intel_connector *connector =
+ to_intel_connector(conn_state->connector);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
+ const struct drm_display_mode *adjusted_mode =
+ &crtc_state->hw.adjusted_mode;
+ int slots = -EINVAL;
+ int i, num_bpc;
+ u8 dsc_bpc[3] = {0};
+ int min_bpp, max_bpp, sink_min_bpp, sink_max_bpp;
+ u8 dsc_max_bpc;
+ bool need_timeslot_recalc = false;
+ u32 last_compressed_bpp;
+
+ /* Max DSC Input BPC for ICL is 10 and for TGL+ is 12 */
+ if (DISPLAY_VER(i915) >= 12)
+ dsc_max_bpc = min_t(u8, 12, conn_state->max_requested_bpc);
+ else
+ dsc_max_bpc = min_t(u8, 10, conn_state->max_requested_bpc);
+
+ max_bpp = min_t(u8, dsc_max_bpc * 3, limits->max_bpp);
+ min_bpp = limits->min_bpp;
+
+ num_bpc = drm_dp_dsc_sink_supported_input_bpcs(intel_dp->dsc_dpcd,
+ dsc_bpc);
+
+ drm_dbg_kms(&i915->drm, "DSC Source supported min bpp %d max bpp %d\n",
+ min_bpp, max_bpp);
+
+ sink_max_bpp = dsc_bpc[0] * 3;
+ sink_min_bpp = sink_max_bpp;
+
+ for (i = 1; i < num_bpc; i++) {
+ if (sink_min_bpp > dsc_bpc[i] * 3)
+ sink_min_bpp = dsc_bpc[i] * 3;
+ if (sink_max_bpp < dsc_bpc[i] * 3)
+ sink_max_bpp = dsc_bpc[i] * 3;
+ }
+
+ drm_dbg_kms(&i915->drm, "DSC Sink supported min bpp %d max bpp %d\n",
+ sink_min_bpp, sink_max_bpp);
+
+ if (min_bpp < sink_min_bpp)
+ min_bpp = sink_min_bpp;
+
+ if (max_bpp > sink_max_bpp)
+ max_bpp = sink_max_bpp;
+
+ slots = intel_dp_mst_find_vcpi_slots_for_bpp(encoder, crtc_state, max_bpp,
+ min_bpp, limits,
+ conn_state, 2 * 3, true);
+
+ if (slots < 0)
+ return slots;
+
+ last_compressed_bpp = crtc_state->dsc.compressed_bpp;
+
+ crtc_state->dsc.compressed_bpp = intel_dp_dsc_nearest_valid_bpp(i915,
+ last_compressed_bpp,
+ crtc_state->pipe_bpp);
+
+ if (crtc_state->dsc.compressed_bpp != last_compressed_bpp)
+ need_timeslot_recalc = true;
+
+ /*
+ * Apparently some MST hubs dislike if vcpi slots are not matching precisely
+ * the actual compressed bpp we use.
+ */
+ if (need_timeslot_recalc) {
+ slots = intel_dp_mst_find_vcpi_slots_for_bpp(encoder, crtc_state,
+ crtc_state->dsc.compressed_bpp,
+ crtc_state->dsc.compressed_bpp,
+ limits, conn_state, 2 * 3, true);
+ if (slots < 0)
+ return slots;
+ }
+
+ intel_link_compute_m_n(crtc_state->pipe_bpp,
+ crtc_state->lane_count,
+ adjusted_mode->crtc_clock,
+ crtc_state->port_clock,
+ &crtc_state->dp_m_n,
+ crtc_state->fec_enable);
+ crtc_state->dp_m_n.tu = slots;
+
+ return 0;
+}
static int intel_dp_mst_update_slots(struct intel_encoder *encoder,
struct intel_crtc_state *crtc_state,
struct drm_connector_state *conn_state)
@@ -182,6 +318,29 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder,
ret = intel_dp_mst_compute_link_config(encoder, pipe_config,
conn_state, &limits);
+
+ if (ret == -EDEADLK)
+ return ret;
+
+ /* enable compression if the mode doesn't fit available BW */
+ drm_dbg_kms(&dev_priv->drm, "Force DSC en = %d\n", intel_dp->force_dsc_en);
+ if (ret || intel_dp->force_dsc_en) {
+ /*
+ * Try to get at least some timeslots and then see, if
+ * we can fit there with DSC.
+ */
+ drm_dbg_kms(&dev_priv->drm, "Trying to find VCPI slots in DSC mode\n");
+
+ ret = intel_dp_dsc_mst_compute_link_config(encoder, pipe_config,
+ conn_state, &limits);
+ if (ret < 0)
+ return ret;
+
+ ret = intel_dp_dsc_compute_config(intel_dp, pipe_config,
+ conn_state, &limits,
+ pipe_config->dp_m_n.tu, false);
+ }
+
if (ret)
return ret;
@@ -365,8 +524,14 @@ static void intel_mst_disable_dp(struct intel_atomic_state *state,
struct intel_dp *intel_dp = &dig_port->dp;
struct intel_connector *connector =
to_intel_connector(old_conn_state->connector);
- struct drm_dp_mst_topology_state *mst_state =
- drm_atomic_get_mst_topology_state(&state->base, &intel_dp->mst_mgr);
+ struct drm_dp_mst_topology_state *old_mst_state =
+ drm_atomic_get_old_mst_topology_state(&state->base, &intel_dp->mst_mgr);
+ struct drm_dp_mst_topology_state *new_mst_state =
+ drm_atomic_get_new_mst_topology_state(&state->base, &intel_dp->mst_mgr);
+ const struct drm_dp_mst_atomic_payload *old_payload =
+ drm_atomic_get_mst_payload_state(old_mst_state, connector->port);
+ struct drm_dp_mst_atomic_payload *new_payload =
+ drm_atomic_get_mst_payload_state(new_mst_state, connector->port);
struct drm_i915_private *i915 = to_i915(connector->base.dev);
drm_dbg_kms(&i915->drm, "active links %d\n",
@@ -374,8 +539,8 @@ static void intel_mst_disable_dp(struct intel_atomic_state *state,
intel_hdcp_disable(intel_mst->connector);
- drm_dp_remove_payload(&intel_dp->mst_mgr, mst_state,
- drm_atomic_get_mst_payload_state(mst_state, connector->port));
+ drm_dp_remove_payload(&intel_dp->mst_mgr, new_mst_state,
+ old_payload, new_payload);
intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state);
}
@@ -692,6 +857,10 @@ intel_dp_mst_mode_valid_ctx(struct drm_connector *connector,
int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
int max_rate, mode_rate, max_lanes, max_link_clock;
int ret;
+ bool dsc = false, bigjoiner = false;
+ u16 dsc_max_output_bpp = 0;
+ u8 dsc_slice_count = 0;
+ int target_clock = mode->clock;
if (drm_connector_is_unregistered(connector)) {
*status = MODE_ERROR;
@@ -729,6 +898,48 @@ intel_dp_mst_mode_valid_ctx(struct drm_connector *connector,
return 0;
}
+ if (intel_dp_need_bigjoiner(intel_dp, mode->hdisplay, target_clock)) {
+ bigjoiner = true;
+ max_dotclk *= 2;
+ }
+
+ if (DISPLAY_VER(dev_priv) >= 10 &&
+ drm_dp_sink_supports_dsc(intel_dp->dsc_dpcd)) {
+ /*
+ * TBD pass the connector BPC,
+ * for now U8_MAX so that max BPC on that platform would be picked
+ */
+ int pipe_bpp = intel_dp_dsc_compute_bpp(intel_dp, U8_MAX);
+
+ if (drm_dp_sink_supports_fec(intel_dp->fec_capable)) {
+ dsc_max_output_bpp =
+ intel_dp_dsc_get_output_bpp(dev_priv,
+ max_link_clock,
+ max_lanes,
+ target_clock,
+ mode->hdisplay,
+ bigjoiner,
+ pipe_bpp, 64) >> 4;
+ dsc_slice_count =
+ intel_dp_dsc_get_slice_count(intel_dp,
+ target_clock,
+ mode->hdisplay,
+ bigjoiner);
+ }
+
+ dsc = dsc_max_output_bpp && dsc_slice_count;
+ }
+
+ /*
+ * Big joiner configuration needs DSC for TGL which is not true for
+ * XE_LPD where uncompressed joiner is supported.
+ */
+ if (DISPLAY_VER(dev_priv) < 13 && bigjoiner && !dsc)
+ return MODE_CLOCK_HIGH;
+
+ if (mode_rate > max_rate && !dsc)
+ return MODE_CLOCK_HIGH;
+
*status = intel_mode_valid_max_plane_size(dev_priv, mode, false);
return 0;
}
@@ -1018,3 +1229,64 @@ bool intel_dp_mst_is_slave_trans(const struct intel_crtc_state *crtc_state)
return crtc_state->mst_master_transcoder != INVALID_TRANSCODER &&
crtc_state->mst_master_transcoder != crtc_state->cpu_transcoder;
}
+
+/**
+ * intel_dp_mst_add_topology_state_for_connector - add MST topology state for a connector
+ * @state: atomic state
+ * @connector: connector to add the state for
+ * @crtc: the CRTC @connector is attached to
+ *
+ * Add the MST topology state for @connector to @state.
+ *
+ * Returns 0 on success, negative error code on failure.
+ */
+static int
+intel_dp_mst_add_topology_state_for_connector(struct intel_atomic_state *state,
+ struct intel_connector *connector,
+ struct intel_crtc *crtc)
+{
+ struct drm_dp_mst_topology_state *mst_state;
+
+ if (!connector->mst_port)
+ return 0;
+
+ mst_state = drm_atomic_get_mst_topology_state(&state->base,
+ &connector->mst_port->mst_mgr);
+ if (IS_ERR(mst_state))
+ return PTR_ERR(mst_state);
+
+ mst_state->pending_crtc_mask |= drm_crtc_mask(&crtc->base);
+
+ return 0;
+}
+
+/**
+ * intel_dp_mst_add_topology_state_for_crtc - add MST topology state for a CRTC
+ * @state: atomic state
+ * @crtc: CRTC to add the state for
+ *
+ * Add the MST topology state for @crtc to @state.
+ *
+ * Returns 0 on success, negative error code on failure.
+ */
+int intel_dp_mst_add_topology_state_for_crtc(struct intel_atomic_state *state,
+ struct intel_crtc *crtc)
+{
+ struct drm_connector *_connector;
+ struct drm_connector_state *conn_state;
+ int i;
+
+ for_each_new_connector_in_state(&state->base, _connector, conn_state, i) {
+ struct intel_connector *connector = to_intel_connector(_connector);
+ int ret;
+
+ if (conn_state->crtc != &crtc->base)
+ continue;
+
+ ret = intel_dp_mst_add_topology_state_for_connector(state, connector, crtc);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.h b/drivers/gpu/drm/i915/display/intel_dp_mst.h
index f7301de6cdfb..f1815bb72267 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_mst.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_mst.h
@@ -8,6 +8,8 @@
#include <linux/types.h>
+struct intel_atomic_state;
+struct intel_crtc;
struct intel_crtc_state;
struct intel_digital_port;
struct intel_dp;
@@ -18,5 +20,7 @@ int intel_dp_mst_encoder_active_links(struct intel_digital_port *dig_port);
bool intel_dp_mst_is_master_trans(const struct intel_crtc_state *crtc_state);
bool intel_dp_mst_is_slave_trans(const struct intel_crtc_state *crtc_state);
bool intel_dp_mst_source_support(struct intel_dp *intel_dp);
+int intel_dp_mst_add_topology_state_for_crtc(struct intel_atomic_state *state,
+ struct intel_crtc *crtc);
#endif /* __INTEL_DP_MST_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_dpio_phy.c b/drivers/gpu/drm/i915/display/intel_dpio_phy.c
index 7eb7440b3180..565c06de2432 100644
--- a/drivers/gpu/drm/i915/display/intel_dpio_phy.c
+++ b/drivers/gpu/drm/i915/display/intel_dpio_phy.c
@@ -376,7 +376,7 @@ static void _bxt_ddi_phy_init(struct drm_i915_private *dev_priv,
if (bxt_ddi_phy_is_enabled(dev_priv, phy)) {
/* Still read out the GRC value for state verification */
if (phy_info->rcomp_phy != -1)
- dev_priv->bxt_phy_grc = bxt_get_grc(dev_priv, phy);
+ dev_priv->display.state.bxt_phy_grc = bxt_get_grc(dev_priv, phy);
if (bxt_ddi_phy_verify_state(dev_priv, phy)) {
drm_dbg(&dev_priv->drm, "DDI PHY %d already enabled, "
@@ -442,8 +442,9 @@ static void _bxt_ddi_phy_init(struct drm_i915_private *dev_priv,
* the corresponding calibrated value from PHY1, and disable
* the automatic calibration on PHY0.
*/
- val = dev_priv->bxt_phy_grc = bxt_get_grc(dev_priv,
- phy_info->rcomp_phy);
+ val = bxt_get_grc(dev_priv, phy_info->rcomp_phy);
+ dev_priv->display.state.bxt_phy_grc = val;
+
grc_code = val << GRC_CODE_FAST_SHIFT |
val << GRC_CODE_SLOW_SHIFT |
val;
@@ -568,7 +569,7 @@ bool bxt_ddi_phy_verify_state(struct drm_i915_private *dev_priv,
"BXT_PORT_CL2CM_DW6(%d)", phy);
if (phy_info->rcomp_phy != -1) {
- u32 grc_code = dev_priv->bxt_phy_grc;
+ u32 grc_code = dev_priv->display.state.bxt_phy_grc;
grc_code = grc_code << GRC_CODE_FAST_SHIFT |
grc_code << GRC_CODE_SLOW_SHIFT |
diff --git a/drivers/gpu/drm/i915/display/intel_dpll.c b/drivers/gpu/drm/i915/display/intel_dpll.c
index c236aafe9be0..4e9c18be7e1f 100644
--- a/drivers/gpu/drm/i915/display/intel_dpll.c
+++ b/drivers/gpu/drm/i915/display/intel_dpll.c
@@ -1910,7 +1910,7 @@ void chv_enable_pll(const struct intel_crtc_state *crtc_state)
intel_de_write(dev_priv, DPLL_MD(PIPE_B),
crtc_state->dpll_hw_state.dpll_md);
intel_de_write(dev_priv, CBR4_VLV, 0);
- dev_priv->chv_dpll_md[pipe] = crtc_state->dpll_hw_state.dpll_md;
+ dev_priv->display.state.chv_dpll_md[pipe] = crtc_state->dpll_hw_state.dpll_md;
/*
* DPLLB VGA mode also seems to cause problems.
diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
index 1974eb580ed1..380368eff31a 100644
--- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
+++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c
@@ -618,7 +618,7 @@ static void hsw_ddi_wrpll_disable(struct drm_i915_private *dev_priv,
* Try to set up the PCH reference clock once all DPLLs
* that depend on it have been shut down.
*/
- if (dev_priv->pch_ssc_use & BIT(id))
+ if (dev_priv->display.dpll.pch_ssc_use & BIT(id))
intel_init_pch_refclk(dev_priv);
}
@@ -636,7 +636,7 @@ static void hsw_ddi_spll_disable(struct drm_i915_private *dev_priv,
* Try to set up the PCH reference clock once all DPLLs
* that depend on it have been shut down.
*/
- if (dev_priv->pch_ssc_use & BIT(id))
+ if (dev_priv->display.dpll.pch_ssc_use & BIT(id))
intel_init_pch_refclk(dev_priv);
}
diff --git a/drivers/gpu/drm/i915/display/intel_drrs.c b/drivers/gpu/drm/i915/display/intel_drrs.c
index 5b9e44443814..29c6421cd666 100644
--- a/drivers/gpu/drm/i915/display/intel_drrs.c
+++ b/drivers/gpu/drm/i915/display/intel_drrs.c
@@ -374,16 +374,16 @@ out:
return ret;
}
-DEFINE_SIMPLE_ATTRIBUTE(intel_drrs_debugfs_ctl_fops,
- NULL, intel_drrs_debugfs_ctl_set, "%llu\n");
+DEFINE_DEBUGFS_ATTRIBUTE(intel_drrs_debugfs_ctl_fops,
+ NULL, intel_drrs_debugfs_ctl_set, "%llu\n");
void intel_drrs_crtc_debugfs_add(struct intel_crtc *crtc)
{
debugfs_create_file("i915_drrs_status", 0444, crtc->base.debugfs_entry,
crtc, &intel_drrs_debugfs_status_fops);
- debugfs_create_file("i915_drrs_ctl", 0644, crtc->base.debugfs_entry,
- crtc, &intel_drrs_debugfs_ctl_fops);
+ debugfs_create_file_unsafe("i915_drrs_ctl", 0644, crtc->base.debugfs_entry,
+ crtc, &intel_drrs_debugfs_ctl_fops);
}
static int intel_drrs_debugfs_type_show(struct seq_file *m, void *unused)
diff --git a/drivers/gpu/drm/i915/display/intel_dsb.c b/drivers/gpu/drm/i915/display/intel_dsb.c
index 1e1c6107d51b..96bc117fd6a0 100644
--- a/drivers/gpu/drm/i915/display/intel_dsb.c
+++ b/drivers/gpu/drm/i915/display/intel_dsb.c
@@ -24,25 +24,30 @@ enum dsb_id {
struct intel_dsb {
enum dsb_id id;
+
u32 *cmd_buf;
struct i915_vma *vma;
+ struct intel_crtc *crtc;
+
+ /*
+ * maximum number of dwords the buffer will hold.
+ */
+ unsigned int size;
/*
- * free_pos will point the first free entry position
- * and help in calculating tail of command buffer.
+ * free_pos will point the first free dword and
+ * help in calculating tail of command buffer.
*/
- int free_pos;
+ unsigned int free_pos;
/*
- * ins_start_offset will help to store start address of the dsb
+ * ins_start_offset will help to store start dword of the dsb
* instuction and help in identifying the batch of auto-increment
* register.
*/
- u32 ins_start_offset;
+ unsigned int ins_start_offset;
};
-#define DSB_BUF_SIZE (2 * PAGE_SIZE)
-
/**
* DOC: DSB
*
@@ -62,86 +67,86 @@ struct intel_dsb {
/* DSB opcodes. */
#define DSB_OPCODE_SHIFT 24
+#define DSB_OPCODE_NOOP 0x0
#define DSB_OPCODE_MMIO_WRITE 0x1
+#define DSB_OPCODE_WAIT_USEC 0x2
+#define DSB_OPCODE_WAIT_LINES 0x3
+#define DSB_OPCODE_WAIT_VBLANKS 0x4
+#define DSB_OPCODE_WAIT_DSL_IN 0x5
+#define DSB_OPCODE_WAIT_DSL_OUT 0x6
+#define DSB_OPCODE_INTERRUPT 0x7
#define DSB_OPCODE_INDEXED_WRITE 0x9
+#define DSB_OPCODE_POLL 0xA
#define DSB_BYTE_EN 0xF
#define DSB_BYTE_EN_SHIFT 20
#define DSB_REG_VALUE_MASK 0xfffff
+static bool assert_dsb_has_room(struct intel_dsb *dsb)
+{
+ struct intel_crtc *crtc = dsb->crtc;
+ struct drm_i915_private *i915 = to_i915(crtc->base.dev);
+
+ /* each instruction is 2 dwords */
+ return !drm_WARN(&i915->drm, dsb->free_pos > dsb->size - 2,
+ "DSB buffer overflow\n");
+}
+
static bool is_dsb_busy(struct drm_i915_private *i915, enum pipe pipe,
enum dsb_id id)
{
- return DSB_STATUS & intel_de_read(i915, DSB_CTRL(pipe, id));
+ return intel_de_read(i915, DSB_CTRL(pipe, id)) & DSB_STATUS_BUSY;
}
-static bool intel_dsb_enable_engine(struct drm_i915_private *i915,
- enum pipe pipe, enum dsb_id id)
+static void intel_dsb_emit(struct intel_dsb *dsb, u32 ldw, u32 udw)
{
- u32 dsb_ctrl;
+ u32 *buf = dsb->cmd_buf;
- dsb_ctrl = intel_de_read(i915, DSB_CTRL(pipe, id));
- if (DSB_STATUS & dsb_ctrl) {
- drm_dbg_kms(&i915->drm, "DSB engine is busy.\n");
- return false;
- }
+ if (!assert_dsb_has_room(dsb))
+ return;
- dsb_ctrl |= DSB_ENABLE;
- intel_de_write(i915, DSB_CTRL(pipe, id), dsb_ctrl);
+ /* Every instruction should be 8 byte aligned. */
+ dsb->free_pos = ALIGN(dsb->free_pos, 2);
- intel_de_posting_read(i915, DSB_CTRL(pipe, id));
- return true;
+ dsb->ins_start_offset = dsb->free_pos;
+
+ buf[dsb->free_pos++] = ldw;
+ buf[dsb->free_pos++] = udw;
}
-static bool intel_dsb_disable_engine(struct drm_i915_private *i915,
- enum pipe pipe, enum dsb_id id)
+static bool intel_dsb_prev_ins_is_write(struct intel_dsb *dsb,
+ u32 opcode, i915_reg_t reg)
{
- u32 dsb_ctrl;
+ const u32 *buf = dsb->cmd_buf;
+ u32 prev_opcode, prev_reg;
- dsb_ctrl = intel_de_read(i915, DSB_CTRL(pipe, id));
- if (DSB_STATUS & dsb_ctrl) {
- drm_dbg_kms(&i915->drm, "DSB engine is busy.\n");
- return false;
- }
+ prev_opcode = buf[dsb->ins_start_offset + 1] >> DSB_OPCODE_SHIFT;
+ prev_reg = buf[dsb->ins_start_offset + 1] & DSB_REG_VALUE_MASK;
- dsb_ctrl &= ~DSB_ENABLE;
- intel_de_write(i915, DSB_CTRL(pipe, id), dsb_ctrl);
+ return prev_opcode == opcode && prev_reg == i915_mmio_reg_offset(reg);
+}
+
+static bool intel_dsb_prev_ins_is_mmio_write(struct intel_dsb *dsb, i915_reg_t reg)
+{
+ return intel_dsb_prev_ins_is_write(dsb, DSB_OPCODE_MMIO_WRITE, reg);
+}
- intel_de_posting_read(i915, DSB_CTRL(pipe, id));
- return true;
+static bool intel_dsb_prev_ins_is_indexed_write(struct intel_dsb *dsb, i915_reg_t reg)
+{
+ return intel_dsb_prev_ins_is_write(dsb, DSB_OPCODE_INDEXED_WRITE, reg);
}
/**
- * intel_dsb_indexed_reg_write() -Write to the DSB context for auto
- * increment register.
- * @crtc_state: intel_crtc_state structure
+ * intel_dsb_reg_write() - Emit register wriite to the DSB context
+ * @dsb: DSB context
* @reg: register address.
* @val: value.
*
* This function is used for writing register-value pair in command
- * buffer of DSB for auto-increment register. During command buffer overflow,
- * a warning is thrown and rest all erroneous condition register programming
- * is done through mmio write.
+ * buffer of DSB.
*/
-
-void intel_dsb_indexed_reg_write(const struct intel_crtc_state *crtc_state,
- i915_reg_t reg, u32 val)
+void intel_dsb_reg_write(struct intel_dsb *dsb,
+ i915_reg_t reg, u32 val)
{
- struct intel_dsb *dsb = crtc_state->dsb;
- struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
- u32 *buf;
- u32 reg_val;
-
- if (!dsb) {
- intel_de_write_fw(dev_priv, reg, val);
- return;
- }
- buf = dsb->cmd_buf;
- if (drm_WARN_ON(&dev_priv->drm, dsb->free_pos >= DSB_BUF_SIZE)) {
- drm_dbg_kms(&dev_priv->drm, "DSB buffer overflow\n");
- return;
- }
-
/*
* For example the buffer will look like below for 3 dwords for auto
* increment register:
@@ -158,207 +163,182 @@ void intel_dsb_indexed_reg_write(const struct intel_crtc_state *crtc_state,
* we are writing odd no of dwords, Zeros will be added in the end for
* padding.
*/
- reg_val = buf[dsb->ins_start_offset + 1] & DSB_REG_VALUE_MASK;
- if (reg_val != i915_mmio_reg_offset(reg)) {
- /* Every instruction should be 8 byte aligned. */
- dsb->free_pos = ALIGN(dsb->free_pos, 2);
+ if (!intel_dsb_prev_ins_is_mmio_write(dsb, reg) &&
+ !intel_dsb_prev_ins_is_indexed_write(dsb, reg)) {
+ intel_dsb_emit(dsb, val,
+ (DSB_OPCODE_MMIO_WRITE << DSB_OPCODE_SHIFT) |
+ (DSB_BYTE_EN << DSB_BYTE_EN_SHIFT) |
+ i915_mmio_reg_offset(reg));
+ } else {
+ u32 *buf = dsb->cmd_buf;
- dsb->ins_start_offset = dsb->free_pos;
+ if (!assert_dsb_has_room(dsb))
+ return;
- /* Update the size. */
- buf[dsb->free_pos++] = 1;
+ /* convert to indexed write? */
+ if (intel_dsb_prev_ins_is_mmio_write(dsb, reg)) {
+ u32 prev_val = buf[dsb->ins_start_offset + 0];
- /* Update the opcode and reg. */
- buf[dsb->free_pos++] = (DSB_OPCODE_INDEXED_WRITE <<
- DSB_OPCODE_SHIFT) |
- i915_mmio_reg_offset(reg);
+ buf[dsb->ins_start_offset + 0] = 1; /* count */
+ buf[dsb->ins_start_offset + 1] =
+ (DSB_OPCODE_INDEXED_WRITE << DSB_OPCODE_SHIFT) |
+ i915_mmio_reg_offset(reg);
+ buf[dsb->ins_start_offset + 2] = prev_val;
- /* Update the value. */
- buf[dsb->free_pos++] = val;
- } else {
- /* Update the new value. */
- buf[dsb->free_pos++] = val;
+ dsb->free_pos++;
+ }
- /* Update the size. */
+ buf[dsb->free_pos++] = val;
+ /* Update the count */
buf[dsb->ins_start_offset]++;
- }
- /* if number of data words is odd, then the last dword should be 0.*/
- if (dsb->free_pos & 0x1)
- buf[dsb->free_pos] = 0;
+ /* if number of data words is odd, then the last dword should be 0.*/
+ if (dsb->free_pos & 0x1)
+ buf[dsb->free_pos] = 0;
+ }
}
-/**
- * intel_dsb_reg_write() -Write to the DSB context for normal
- * register.
- * @crtc_state: intel_crtc_state structure
- * @reg: register address.
- * @val: value.
- *
- * This function is used for writing register-value pair in command
- * buffer of DSB. During command buffer overflow, a warning is thrown
- * and rest all erroneous condition register programming is done
- * through mmio write.
- */
-void intel_dsb_reg_write(const struct intel_crtc_state *crtc_state,
- i915_reg_t reg, u32 val)
+static u32 intel_dsb_align_tail(struct intel_dsb *dsb)
{
- struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
- struct intel_dsb *dsb;
- u32 *buf;
+ u32 aligned_tail, tail;
- dsb = crtc_state->dsb;
- if (!dsb) {
- intel_de_write_fw(dev_priv, reg, val);
- return;
- }
+ tail = dsb->free_pos * 4;
+ aligned_tail = ALIGN(tail, CACHELINE_BYTES);
- buf = dsb->cmd_buf;
- if (drm_WARN_ON(&dev_priv->drm, dsb->free_pos >= DSB_BUF_SIZE)) {
- drm_dbg_kms(&dev_priv->drm, "DSB buffer overflow\n");
- return;
- }
+ if (aligned_tail > tail)
+ memset(&dsb->cmd_buf[dsb->free_pos], 0,
+ aligned_tail - tail);
- dsb->ins_start_offset = dsb->free_pos;
- buf[dsb->free_pos++] = val;
- buf[dsb->free_pos++] = (DSB_OPCODE_MMIO_WRITE << DSB_OPCODE_SHIFT) |
- (DSB_BYTE_EN << DSB_BYTE_EN_SHIFT) |
- i915_mmio_reg_offset(reg);
+ dsb->free_pos = aligned_tail / 4;
+
+ return aligned_tail;
}
/**
* intel_dsb_commit() - Trigger workload execution of DSB.
- * @crtc_state: intel_crtc_state structure
+ * @dsb: DSB context
*
* This function is used to do actual write to hardware using DSB.
- * On errors, fall back to MMIO. Also this function help to reset the context.
*/
-void intel_dsb_commit(const struct intel_crtc_state *crtc_state)
+void intel_dsb_commit(struct intel_dsb *dsb)
{
- struct intel_dsb *dsb = crtc_state->dsb;
- struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
- struct drm_device *dev = crtc->base.dev;
- struct drm_i915_private *dev_priv = to_i915(dev);
+ struct intel_crtc *crtc = dsb->crtc;
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
enum pipe pipe = crtc->pipe;
u32 tail;
- if (!(dsb && dsb->free_pos))
+ tail = intel_dsb_align_tail(dsb);
+ if (tail == 0)
return;
- if (!intel_dsb_enable_engine(dev_priv, pipe, dsb->id))
- goto reset;
-
if (is_dsb_busy(dev_priv, pipe, dsb->id)) {
- drm_err(&dev_priv->drm,
- "HEAD_PTR write failed - dsb engine is busy.\n");
+ drm_err(&dev_priv->drm, "DSB engine is busy.\n");
goto reset;
}
+
+ intel_de_write(dev_priv, DSB_CTRL(pipe, dsb->id),
+ DSB_ENABLE);
intel_de_write(dev_priv, DSB_HEAD(pipe, dsb->id),
i915_ggtt_offset(dsb->vma));
+ intel_de_write(dev_priv, DSB_TAIL(pipe, dsb->id),
+ i915_ggtt_offset(dsb->vma) + tail);
- tail = ALIGN(dsb->free_pos * 4, CACHELINE_BYTES);
- if (tail > dsb->free_pos * 4)
- memset(&dsb->cmd_buf[dsb->free_pos], 0,
- (tail - dsb->free_pos * 4));
-
- if (is_dsb_busy(dev_priv, pipe, dsb->id)) {
- drm_err(&dev_priv->drm,
- "TAIL_PTR write failed - dsb engine is busy.\n");
- goto reset;
- }
drm_dbg_kms(&dev_priv->drm,
"DSB execution started - head 0x%x, tail 0x%x\n",
- i915_ggtt_offset(dsb->vma), tail);
- intel_de_write(dev_priv, DSB_TAIL(pipe, dsb->id),
- i915_ggtt_offset(dsb->vma) + tail);
- if (wait_for(!is_dsb_busy(dev_priv, pipe, dsb->id), 1)) {
+ i915_ggtt_offset(dsb->vma),
+ i915_ggtt_offset(dsb->vma) + tail);
+
+ if (wait_for(!is_dsb_busy(dev_priv, pipe, dsb->id), 1))
drm_err(&dev_priv->drm,
"Timed out waiting for DSB workload completion.\n");
- goto reset;
- }
reset:
dsb->free_pos = 0;
dsb->ins_start_offset = 0;
- intel_dsb_disable_engine(dev_priv, pipe, dsb->id);
+ intel_de_write(dev_priv, DSB_CTRL(pipe, dsb->id), 0);
}
/**
* intel_dsb_prepare() - Allocate, pin and map the DSB command buffer.
- * @crtc_state: intel_crtc_state structure to prepare associated dsb instance.
+ * @crtc: the CRTC
+ * @max_cmds: number of commands we need to fit into command buffer
*
* This function prepare the command buffer which is used to store dsb
* instructions with data.
+ *
+ * Returns:
+ * DSB context, NULL on failure
*/
-void intel_dsb_prepare(struct intel_crtc_state *crtc_state)
+struct intel_dsb *intel_dsb_prepare(struct intel_crtc *crtc,
+ unsigned int max_cmds)
{
- struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_i915_private *i915 = to_i915(crtc->base.dev);
- struct intel_dsb *dsb;
struct drm_i915_gem_object *obj;
+ intel_wakeref_t wakeref;
+ struct intel_dsb *dsb;
struct i915_vma *vma;
+ unsigned int size;
u32 *buf;
- intel_wakeref_t wakeref;
if (!HAS_DSB(i915))
- return;
+ return NULL;
- dsb = kmalloc(sizeof(*dsb), GFP_KERNEL);
- if (!dsb) {
- drm_err(&i915->drm, "DSB object creation failed\n");
- return;
- }
+ dsb = kzalloc(sizeof(*dsb), GFP_KERNEL);
+ if (!dsb)
+ goto out;
wakeref = intel_runtime_pm_get(&i915->runtime_pm);
- obj = i915_gem_object_create_internal(i915, DSB_BUF_SIZE);
- if (IS_ERR(obj)) {
- kfree(dsb);
- goto out;
- }
+ /* ~1 qword per instruction, full cachelines */
+ size = ALIGN(max_cmds * 8, CACHELINE_BYTES);
+
+ obj = i915_gem_object_create_internal(i915, PAGE_ALIGN(size));
+ if (IS_ERR(obj))
+ goto out_put_rpm;
vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, 0);
if (IS_ERR(vma)) {
i915_gem_object_put(obj);
- kfree(dsb);
- goto out;
+ goto out_put_rpm;
}
buf = i915_gem_object_pin_map_unlocked(vma->obj, I915_MAP_WC);
if (IS_ERR(buf)) {
i915_vma_unpin_and_release(&vma, I915_VMA_RELEASE_MAP);
- kfree(dsb);
- goto out;
+ goto out_put_rpm;
}
+ intel_runtime_pm_put(&i915->runtime_pm, wakeref);
+
dsb->id = DSB1;
dsb->vma = vma;
+ dsb->crtc = crtc;
dsb->cmd_buf = buf;
+ dsb->size = size / 4; /* in dwords */
dsb->free_pos = 0;
dsb->ins_start_offset = 0;
- crtc_state->dsb = dsb;
-out:
- if (!crtc_state->dsb)
- drm_info(&i915->drm,
- "DSB queue setup failed, will fallback to MMIO for display HW programming\n");
+ return dsb;
+
+out_put_rpm:
intel_runtime_pm_put(&i915->runtime_pm, wakeref);
+ kfree(dsb);
+out:
+ drm_info_once(&i915->drm,
+ "DSB queue setup failed, will fallback to MMIO for display HW programming\n");
+
+ return NULL;
}
/**
* intel_dsb_cleanup() - To cleanup DSB context.
- * @crtc_state: intel_crtc_state structure to cleanup associated dsb instance.
+ * @dsb: DSB context
*
* This function cleanup the DSB context by unpinning and releasing
* the VMA object associated with it.
*/
-void intel_dsb_cleanup(struct intel_crtc_state *crtc_state)
+void intel_dsb_cleanup(struct intel_dsb *dsb)
{
- if (!crtc_state->dsb)
- return;
-
- i915_vma_unpin_and_release(&crtc_state->dsb->vma, I915_VMA_RELEASE_MAP);
- kfree(crtc_state->dsb);
- crtc_state->dsb = NULL;
+ i915_vma_unpin_and_release(&dsb->vma, I915_VMA_RELEASE_MAP);
+ kfree(dsb);
}
diff --git a/drivers/gpu/drm/i915/display/intel_dsb.h b/drivers/gpu/drm/i915/display/intel_dsb.h
index 74dd2b3343bb..05c221b6d0a4 100644
--- a/drivers/gpu/drm/i915/display/intel_dsb.h
+++ b/drivers/gpu/drm/i915/display/intel_dsb.h
@@ -10,14 +10,14 @@
#include "i915_reg_defs.h"
-struct intel_crtc_state;
+struct intel_crtc;
+struct intel_dsb;
-void intel_dsb_prepare(struct intel_crtc_state *crtc_state);
-void intel_dsb_cleanup(struct intel_crtc_state *crtc_state);
-void intel_dsb_reg_write(const struct intel_crtc_state *crtc_state,
+struct intel_dsb *intel_dsb_prepare(struct intel_crtc *crtc,
+ unsigned int max_cmds);
+void intel_dsb_cleanup(struct intel_dsb *dsb);
+void intel_dsb_reg_write(struct intel_dsb *dsb,
i915_reg_t reg, u32 val);
-void intel_dsb_indexed_reg_write(const struct intel_crtc_state *crtc_state,
- i915_reg_t reg, u32 val);
-void intel_dsb_commit(const struct intel_crtc_state *crtc_state);
+void intel_dsb_commit(struct intel_dsb *dsb);
#endif
diff --git a/drivers/gpu/drm/i915/display/intel_dvo.c b/drivers/gpu/drm/i915/display/intel_dvo.c
index c86f9890754d..0be8105cb18a 100644
--- a/drivers/gpu/drm/i915/display/intel_dvo.c
+++ b/drivers/gpu/drm/i915/display/intel_dvo.c
@@ -38,6 +38,7 @@
#include "intel_display_types.h"
#include "intel_dvo.h"
#include "intel_dvo_dev.h"
+#include "intel_dvo_regs.h"
#include "intel_gmbus.h"
#include "intel_panel.h"
@@ -56,48 +57,42 @@ static const struct intel_dvo_device intel_dvo_devices[] = {
{
.type = INTEL_DVO_CHIP_TMDS,
.name = "sil164",
- .dvo_reg = DVOC,
- .dvo_srcdim_reg = DVOC_SRCDIM,
+ .port = PORT_C,
.slave_addr = SIL164_ADDR,
.dev_ops = &sil164_ops,
},
{
.type = INTEL_DVO_CHIP_TMDS,
.name = "ch7xxx",
- .dvo_reg = DVOC,
- .dvo_srcdim_reg = DVOC_SRCDIM,
+ .port = PORT_C,
.slave_addr = CH7xxx_ADDR,
.dev_ops = &ch7xxx_ops,
},
{
.type = INTEL_DVO_CHIP_TMDS,
.name = "ch7xxx",
- .dvo_reg = DVOC,
- .dvo_srcdim_reg = DVOC_SRCDIM,
+ .port = PORT_C,
.slave_addr = 0x75, /* For some ch7010 */
.dev_ops = &ch7xxx_ops,
},
{
.type = INTEL_DVO_CHIP_LVDS,
.name = "ivch",
- .dvo_reg = DVOA,
- .dvo_srcdim_reg = DVOA_SRCDIM,
+ .port = PORT_A,
.slave_addr = 0x02, /* Might also be 0x44, 0x84, 0xc4 */
.dev_ops = &ivch_ops,
},
{
.type = INTEL_DVO_CHIP_TMDS,
.name = "tfp410",
- .dvo_reg = DVOC,
- .dvo_srcdim_reg = DVOC_SRCDIM,
+ .port = PORT_C,
.slave_addr = TFP410_ADDR,
.dev_ops = &tfp410_ops,
},
{
.type = INTEL_DVO_CHIP_LVDS,
.name = "ch7017",
- .dvo_reg = DVOC,
- .dvo_srcdim_reg = DVOC_SRCDIM,
+ .port = PORT_C,
.slave_addr = 0x75,
.gpio = GMBUS_PIN_DPB,
.dev_ops = &ch7017_ops,
@@ -105,8 +100,7 @@ static const struct intel_dvo_device intel_dvo_devices[] = {
{
.type = INTEL_DVO_CHIP_LVDS_NO_FIXED,
.name = "ns2501",
- .dvo_reg = DVOB,
- .dvo_srcdim_reg = DVOB_SRCDIM,
+ .port = PORT_B,
.slave_addr = NS2501_ADDR,
.dev_ops = &ns2501_ops,
},
@@ -118,8 +112,6 @@ struct intel_dvo {
struct intel_dvo_device dev;
struct intel_connector *attached_connector;
-
- bool panel_wants_dither;
};
static struct intel_dvo *enc_to_dvo(struct intel_encoder *encoder)
@@ -134,12 +126,13 @@ static struct intel_dvo *intel_attached_dvo(struct intel_connector *connector)
static bool intel_dvo_connector_get_hw_state(struct intel_connector *connector)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = to_i915(dev);
- struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
+ struct intel_encoder *encoder = intel_attached_encoder(connector);
+ struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
+ enum port port = encoder->port;
u32 tmp;
- tmp = intel_de_read(dev_priv, intel_dvo->dev.dvo_reg);
+ tmp = intel_de_read(i915, DVO(port));
if (!(tmp & DVO_ENABLE))
return false;
@@ -150,13 +143,13 @@ static bool intel_dvo_connector_get_hw_state(struct intel_connector *connector)
static bool intel_dvo_get_hw_state(struct intel_encoder *encoder,
enum pipe *pipe)
{
- struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
- struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
+ struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+ enum port port = encoder->port;
u32 tmp;
- tmp = intel_de_read(dev_priv, intel_dvo->dev.dvo_reg);
+ tmp = intel_de_read(i915, DVO(port));
- *pipe = (tmp & DVO_PIPE_SEL_MASK) >> DVO_PIPE_SEL_SHIFT;
+ *pipe = REG_FIELD_GET(DVO_PIPE_SEL_MASK, tmp);
return tmp & DVO_ENABLE;
}
@@ -164,13 +157,13 @@ static bool intel_dvo_get_hw_state(struct intel_encoder *encoder,
static void intel_dvo_get_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config)
{
- struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
- struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
+ struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+ enum port port = encoder->port;
u32 tmp, flags = 0;
pipe_config->output_types |= BIT(INTEL_OUTPUT_DVO);
- tmp = intel_de_read(dev_priv, intel_dvo->dev.dvo_reg);
+ tmp = intel_de_read(i915, DVO(port));
if (tmp & DVO_HSYNC_ACTIVE_HIGH)
flags |= DRM_MODE_FLAG_PHSYNC;
else
@@ -190,14 +183,14 @@ static void intel_disable_dvo(struct intel_atomic_state *state,
const struct intel_crtc_state *old_crtc_state,
const struct drm_connector_state *old_conn_state)
{
- struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ struct drm_i915_private *i915 = to_i915(encoder->base.dev);
struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
- i915_reg_t dvo_reg = intel_dvo->dev.dvo_reg;
- u32 temp = intel_de_read(dev_priv, dvo_reg);
+ enum port port = encoder->port;
intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, false);
- intel_de_write(dev_priv, dvo_reg, temp & ~DVO_ENABLE);
- intel_de_read(dev_priv, dvo_reg);
+
+ intel_de_rmw(i915, DVO(port), DVO_ENABLE, 0);
+ intel_de_posting_read(i915, DVO(port));
}
static void intel_enable_dvo(struct intel_atomic_state *state,
@@ -205,30 +198,29 @@ static void intel_enable_dvo(struct intel_atomic_state *state,
const struct intel_crtc_state *pipe_config,
const struct drm_connector_state *conn_state)
{
- struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ struct drm_i915_private *i915 = to_i915(encoder->base.dev);
struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
- i915_reg_t dvo_reg = intel_dvo->dev.dvo_reg;
- u32 temp = intel_de_read(dev_priv, dvo_reg);
+ enum port port = encoder->port;
intel_dvo->dev.dev_ops->mode_set(&intel_dvo->dev,
&pipe_config->hw.mode,
&pipe_config->hw.adjusted_mode);
- intel_de_write(dev_priv, dvo_reg, temp | DVO_ENABLE);
- intel_de_read(dev_priv, dvo_reg);
+ intel_de_rmw(i915, DVO(port), 0, DVO_ENABLE);
+ intel_de_posting_read(i915, DVO(port));
intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, true);
}
static enum drm_mode_status
-intel_dvo_mode_valid(struct drm_connector *connector,
+intel_dvo_mode_valid(struct drm_connector *_connector,
struct drm_display_mode *mode)
{
- struct intel_connector *intel_connector = to_intel_connector(connector);
- struct intel_dvo *intel_dvo = intel_attached_dvo(intel_connector);
+ struct intel_connector *connector = to_intel_connector(_connector);
+ struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
const struct drm_display_mode *fixed_mode =
- intel_panel_fixed_mode(intel_connector, mode);
- int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
+ intel_panel_fixed_mode(connector, mode);
+ int max_dotclk = to_i915(connector->base.dev)->max_dotclk_freq;
int target_clock = mode->clock;
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
@@ -239,7 +231,7 @@ intel_dvo_mode_valid(struct drm_connector *connector,
if (fixed_mode) {
enum drm_mode_status status;
- status = intel_panel_mode_valid(intel_connector, mode);
+ status = intel_panel_mode_valid(connector, mode);
if (status != MODE_OK)
return status;
@@ -289,18 +281,17 @@ static void intel_dvo_pre_enable(struct intel_atomic_state *state,
const struct intel_crtc_state *pipe_config,
const struct drm_connector_state *conn_state)
{
- struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ struct drm_i915_private *i915 = to_i915(encoder->base.dev);
struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc);
const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
- struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
+ enum port port = encoder->port;
enum pipe pipe = crtc->pipe;
u32 dvo_val;
- i915_reg_t dvo_reg = intel_dvo->dev.dvo_reg;
- i915_reg_t dvo_srcdim_reg = intel_dvo->dev.dvo_srcdim_reg;
- /* Save the data order, since I don't know what it should be set to. */
- dvo_val = intel_de_read(dev_priv, dvo_reg) &
- (DVO_PRESERVE_MASK | DVO_DATA_ORDER_GBRG);
+ /* Save the active data order, since I don't know what it should be set to. */
+ dvo_val = intel_de_read(i915, DVO(port)) &
+ (DVO_DEDICATED_INT_ENABLE |
+ DVO_PRESERVE_MASK | DVO_ACT_DATA_ORDER_MASK);
dvo_val |= DVO_DATA_ORDER_FP | DVO_BORDER_ENABLE |
DVO_BLANK_ACTIVE_HIGH;
@@ -311,19 +302,21 @@ static void intel_dvo_pre_enable(struct intel_atomic_state *state,
if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
dvo_val |= DVO_VSYNC_ACTIVE_HIGH;
- intel_de_write(dev_priv, dvo_srcdim_reg,
- (adjusted_mode->crtc_hdisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) | (adjusted_mode->crtc_vdisplay << DVO_SRCDIM_VERTICAL_SHIFT));
- intel_de_write(dev_priv, dvo_reg, dvo_val);
+ intel_de_write(i915, DVO_SRCDIM(port),
+ DVO_SRCDIM_HORIZONTAL(adjusted_mode->crtc_hdisplay) |
+ DVO_SRCDIM_VERTICAL(adjusted_mode->crtc_vdisplay));
+ intel_de_write(i915, DVO(port), dvo_val);
}
static enum drm_connector_status
-intel_dvo_detect(struct drm_connector *connector, bool force)
+intel_dvo_detect(struct drm_connector *_connector, bool force)
{
- struct drm_i915_private *i915 = to_i915(connector->dev);
- struct intel_dvo *intel_dvo = intel_attached_dvo(to_intel_connector(connector));
+ struct intel_connector *connector = to_intel_connector(_connector);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
+ struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
- DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
- connector->base.id, connector->name);
+ drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s]\n",
+ connector->base.base.id, connector->base.name);
if (!INTEL_DISPLAY_ENABLED(i915))
return connector_status_disconnected;
@@ -331,9 +324,10 @@ intel_dvo_detect(struct drm_connector *connector, bool force)
return intel_dvo->dev.dev_ops->detect(&intel_dvo->dev);
}
-static int intel_dvo_get_modes(struct drm_connector *connector)
+static int intel_dvo_get_modes(struct drm_connector *_connector)
{
- struct drm_i915_private *dev_priv = to_i915(connector->dev);
+ struct intel_connector *connector = to_intel_connector(_connector);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
int num_modes;
/*
@@ -342,12 +336,12 @@ static int intel_dvo_get_modes(struct drm_connector *connector)
* (TV-out, for example), but for now with just TMDS and LVDS,
* that's not the case.
*/
- num_modes = intel_ddc_get_modes(connector,
- intel_gmbus_get_adapter(dev_priv, GMBUS_PIN_DPC));
+ num_modes = intel_ddc_get_modes(&connector->base,
+ intel_gmbus_get_adapter(i915, GMBUS_PIN_DPC));
if (num_modes)
return num_modes;
- return intel_panel_get_modes(to_intel_connector(connector));
+ return intel_panel_get_modes(connector);
}
static const struct drm_connector_funcs intel_dvo_connector_funcs = {
@@ -379,165 +373,187 @@ static const struct drm_encoder_funcs intel_dvo_enc_funcs = {
.destroy = intel_dvo_enc_destroy,
};
-static enum port intel_dvo_port(i915_reg_t dvo_reg)
+static int intel_dvo_encoder_type(const struct intel_dvo_device *dvo)
+{
+ switch (dvo->type) {
+ case INTEL_DVO_CHIP_TMDS:
+ return DRM_MODE_ENCODER_TMDS;
+ case INTEL_DVO_CHIP_LVDS_NO_FIXED:
+ case INTEL_DVO_CHIP_LVDS:
+ return DRM_MODE_ENCODER_LVDS;
+ default:
+ MISSING_CASE(dvo->type);
+ return DRM_MODE_ENCODER_NONE;
+ }
+}
+
+static int intel_dvo_connector_type(const struct intel_dvo_device *dvo)
+{
+ switch (dvo->type) {
+ case INTEL_DVO_CHIP_TMDS:
+ return DRM_MODE_CONNECTOR_DVII;
+ case INTEL_DVO_CHIP_LVDS_NO_FIXED:
+ case INTEL_DVO_CHIP_LVDS:
+ return DRM_MODE_CONNECTOR_LVDS;
+ default:
+ MISSING_CASE(dvo->type);
+ return DRM_MODE_CONNECTOR_Unknown;
+ }
+}
+
+static bool intel_dvo_init_dev(struct drm_i915_private *dev_priv,
+ struct intel_dvo *intel_dvo,
+ const struct intel_dvo_device *dvo)
{
- if (i915_mmio_reg_equal(dvo_reg, DVOA))
- return PORT_A;
- else if (i915_mmio_reg_equal(dvo_reg, DVOB))
- return PORT_B;
+ struct i2c_adapter *i2c;
+ u32 dpll[I915_MAX_PIPES];
+ enum pipe pipe;
+ int gpio;
+ bool ret;
+
+ /*
+ * Allow the I2C driver info to specify the GPIO to be used in
+ * special cases, but otherwise default to what's defined
+ * in the spec.
+ */
+ if (intel_gmbus_is_valid_pin(dev_priv, dvo->gpio))
+ gpio = dvo->gpio;
+ else if (dvo->type == INTEL_DVO_CHIP_LVDS)
+ gpio = GMBUS_PIN_SSC;
else
- return PORT_C;
+ gpio = GMBUS_PIN_DPB;
+
+ /*
+ * Set up the I2C bus necessary for the chip we're probing.
+ * It appears that everything is on GPIOE except for panels
+ * on i830 laptops, which are on GPIOB (DVOA).
+ */
+ i2c = intel_gmbus_get_adapter(dev_priv, gpio);
+
+ intel_dvo->dev = *dvo;
+
+ /*
+ * GMBUS NAK handling seems to be unstable, hence let the
+ * transmitter detection run in bit banging mode for now.
+ */
+ intel_gmbus_force_bit(i2c, true);
+
+ /*
+ * ns2501 requires the DVO 2x clock before it will
+ * respond to i2c accesses, so make sure we have
+ * the clock enabled before we attempt to initialize
+ * the device.
+ */
+ for_each_pipe(dev_priv, pipe) {
+ dpll[pipe] = intel_de_read(dev_priv, DPLL(pipe));
+ intel_de_write(dev_priv, DPLL(pipe),
+ dpll[pipe] | DPLL_DVO_2X_MODE);
+ }
+
+ ret = dvo->dev_ops->init(&intel_dvo->dev, i2c);
+
+ /* restore the DVO 2x clock state to original */
+ for_each_pipe(dev_priv, pipe) {
+ intel_de_write(dev_priv, DPLL(pipe), dpll[pipe]);
+ }
+
+ intel_gmbus_force_bit(i2c, false);
+
+ return ret;
}
-void intel_dvo_init(struct drm_i915_private *dev_priv)
+static bool intel_dvo_probe(struct drm_i915_private *i915,
+ struct intel_dvo *intel_dvo)
{
- struct intel_encoder *intel_encoder;
- struct intel_dvo *intel_dvo;
- struct intel_connector *intel_connector;
int i;
- int encoder_type = DRM_MODE_ENCODER_NONE;
+
+ /* Now, try to find a controller */
+ for (i = 0; i < ARRAY_SIZE(intel_dvo_devices); i++) {
+ if (intel_dvo_init_dev(i915, intel_dvo,
+ &intel_dvo_devices[i]))
+ return true;
+ }
+
+ return false;
+}
+
+void intel_dvo_init(struct drm_i915_private *i915)
+{
+ struct intel_connector *connector;
+ struct intel_encoder *encoder;
+ struct intel_dvo *intel_dvo;
intel_dvo = kzalloc(sizeof(*intel_dvo), GFP_KERNEL);
if (!intel_dvo)
return;
- intel_connector = intel_connector_alloc();
- if (!intel_connector) {
+ connector = intel_connector_alloc();
+ if (!connector) {
kfree(intel_dvo);
return;
}
- intel_dvo->attached_connector = intel_connector;
+ intel_dvo->attached_connector = connector;
- intel_encoder = &intel_dvo->base;
+ encoder = &intel_dvo->base;
- intel_encoder->disable = intel_disable_dvo;
- intel_encoder->enable = intel_enable_dvo;
- intel_encoder->get_hw_state = intel_dvo_get_hw_state;
- intel_encoder->get_config = intel_dvo_get_config;
- intel_encoder->compute_config = intel_dvo_compute_config;
- intel_encoder->pre_enable = intel_dvo_pre_enable;
- intel_connector->get_hw_state = intel_dvo_connector_get_hw_state;
+ encoder->disable = intel_disable_dvo;
+ encoder->enable = intel_enable_dvo;
+ encoder->get_hw_state = intel_dvo_get_hw_state;
+ encoder->get_config = intel_dvo_get_config;
+ encoder->compute_config = intel_dvo_compute_config;
+ encoder->pre_enable = intel_dvo_pre_enable;
+ connector->get_hw_state = intel_dvo_connector_get_hw_state;
- /* Now, try to find a controller */
- for (i = 0; i < ARRAY_SIZE(intel_dvo_devices); i++) {
- struct drm_connector *connector = &intel_connector->base;
- const struct intel_dvo_device *dvo = &intel_dvo_devices[i];
- struct i2c_adapter *i2c;
- int gpio;
- bool dvoinit;
- enum pipe pipe;
- u32 dpll[I915_MAX_PIPES];
- enum port port;
+ if (!intel_dvo_probe(i915, intel_dvo)) {
+ kfree(intel_dvo);
+ intel_connector_free(connector);
+ return;
+ }
- /*
- * Allow the I2C driver info to specify the GPIO to be used in
- * special cases, but otherwise default to what's defined
- * in the spec.
- */
- if (intel_gmbus_is_valid_pin(dev_priv, dvo->gpio))
- gpio = dvo->gpio;
- else if (dvo->type == INTEL_DVO_CHIP_LVDS)
- gpio = GMBUS_PIN_SSC;
- else
- gpio = GMBUS_PIN_DPB;
+ encoder->type = INTEL_OUTPUT_DVO;
+ encoder->power_domain = POWER_DOMAIN_PORT_OTHER;
+ encoder->port = intel_dvo->dev.port;
+ encoder->pipe_mask = ~0;
- /*
- * Set up the I2C bus necessary for the chip we're probing.
- * It appears that everything is on GPIOE except for panels
- * on i830 laptops, which are on GPIOB (DVOA).
- */
- i2c = intel_gmbus_get_adapter(dev_priv, gpio);
+ if (intel_dvo->dev.type != INTEL_DVO_CHIP_LVDS)
+ encoder->cloneable = BIT(INTEL_OUTPUT_ANALOG) |
+ BIT(INTEL_OUTPUT_DVO);
- intel_dvo->dev = *dvo;
+ drm_encoder_init(&i915->drm, &encoder->base,
+ &intel_dvo_enc_funcs,
+ intel_dvo_encoder_type(&intel_dvo->dev),
+ "DVO %c", port_name(encoder->port));
- /*
- * GMBUS NAK handling seems to be unstable, hence let the
- * transmitter detection run in bit banging mode for now.
- */
- intel_gmbus_force_bit(i2c, true);
+ drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s] detected %s\n",
+ encoder->base.base.id, encoder->base.name,
+ intel_dvo->dev.name);
+
+ if (intel_dvo->dev.type == INTEL_DVO_CHIP_TMDS)
+ connector->polled = DRM_CONNECTOR_POLL_CONNECT |
+ DRM_CONNECTOR_POLL_DISCONNECT;
+
+ drm_connector_init(&i915->drm, &connector->base,
+ &intel_dvo_connector_funcs,
+ intel_dvo_connector_type(&intel_dvo->dev));
+
+ drm_connector_helper_add(&connector->base,
+ &intel_dvo_connector_helper_funcs);
+ connector->base.display_info.subpixel_order = SubPixelHorizontalRGB;
+ intel_connector_attach_encoder(connector, encoder);
+
+ if (intel_dvo->dev.type == INTEL_DVO_CHIP_LVDS) {
/*
- * ns2501 requires the DVO 2x clock before it will
- * respond to i2c accesses, so make sure we have
- * have the clock enabled before we attempt to
- * initialize the device.
+ * For our LVDS chipsets, we should hopefully be able
+ * to dig the fixed panel mode out of the BIOS data.
+ * However, it's in a different format from the BIOS
+ * data on chipsets with integrated LVDS (stored in AIM
+ * headers, likely), so for now, just get the current
+ * mode being output through DVO.
*/
- for_each_pipe(dev_priv, pipe) {
- dpll[pipe] = intel_de_read(dev_priv, DPLL(pipe));
- intel_de_write(dev_priv, DPLL(pipe),
- dpll[pipe] | DPLL_DVO_2X_MODE);
- }
-
- dvoinit = dvo->dev_ops->init(&intel_dvo->dev, i2c);
-
- /* restore the DVO 2x clock state to original */
- for_each_pipe(dev_priv, pipe) {
- intel_de_write(dev_priv, DPLL(pipe), dpll[pipe]);
- }
-
- intel_gmbus_force_bit(i2c, false);
-
- if (!dvoinit)
- continue;
-
- port = intel_dvo_port(dvo->dvo_reg);
- drm_encoder_init(&dev_priv->drm, &intel_encoder->base,
- &intel_dvo_enc_funcs, encoder_type,
- "DVO %c", port_name(port));
-
- intel_encoder->type = INTEL_OUTPUT_DVO;
- intel_encoder->power_domain = POWER_DOMAIN_PORT_OTHER;
- intel_encoder->port = port;
- intel_encoder->pipe_mask = ~0;
-
- if (dvo->type != INTEL_DVO_CHIP_LVDS)
- intel_encoder->cloneable = BIT(INTEL_OUTPUT_ANALOG) |
- BIT(INTEL_OUTPUT_DVO);
-
- switch (dvo->type) {
- case INTEL_DVO_CHIP_TMDS:
- intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT |
- DRM_CONNECTOR_POLL_DISCONNECT;
- drm_connector_init(&dev_priv->drm, connector,
- &intel_dvo_connector_funcs,
- DRM_MODE_CONNECTOR_DVII);
- encoder_type = DRM_MODE_ENCODER_TMDS;
- break;
- case INTEL_DVO_CHIP_LVDS_NO_FIXED:
- case INTEL_DVO_CHIP_LVDS:
- drm_connector_init(&dev_priv->drm, connector,
- &intel_dvo_connector_funcs,
- DRM_MODE_CONNECTOR_LVDS);
- encoder_type = DRM_MODE_ENCODER_LVDS;
- break;
- }
-
- drm_connector_helper_add(connector,
- &intel_dvo_connector_helper_funcs);
- connector->display_info.subpixel_order = SubPixelHorizontalRGB;
-
- intel_connector_attach_encoder(intel_connector, intel_encoder);
- if (dvo->type == INTEL_DVO_CHIP_LVDS) {
- /*
- * For our LVDS chipsets, we should hopefully be able
- * to dig the fixed panel mode out of the BIOS data.
- * However, it's in a different format from the BIOS
- * data on chipsets with integrated LVDS (stored in AIM
- * headers, likely), so for now, just get the current
- * mode being output through DVO.
- */
- intel_panel_add_encoder_fixed_mode(intel_connector,
- intel_encoder);
-
- intel_panel_init(intel_connector);
-
- intel_dvo->panel_wants_dither = true;
- }
+ intel_panel_add_encoder_fixed_mode(connector, encoder);
- return;
+ intel_panel_init(connector, NULL);
}
-
- kfree(intel_dvo);
- kfree(intel_connector);
}
diff --git a/drivers/gpu/drm/i915/display/intel_dvo_dev.h b/drivers/gpu/drm/i915/display/intel_dvo_dev.h
index ecff7b190856..f7e98e1c6470 100644
--- a/drivers/gpu/drm/i915/display/intel_dvo_dev.h
+++ b/drivers/gpu/drm/i915/display/intel_dvo_dev.h
@@ -25,6 +25,8 @@
#include "i915_reg_defs.h"
+#include "intel_display_limits.h"
+
enum drm_connector_status;
struct drm_display_mode;
struct i2c_adapter;
@@ -32,9 +34,8 @@ struct i2c_adapter;
struct intel_dvo_device {
const char *name;
int type;
- /* DVOA/B/C output register */
- i915_reg_t dvo_reg;
- i915_reg_t dvo_srcdim_reg;
+ /* DVOA/B/C */
+ enum port port;
/* GPIO register used for i2c bus to control this device */
u32 gpio;
int slave_addr;
diff --git a/drivers/gpu/drm/i915/display/intel_dvo_regs.h b/drivers/gpu/drm/i915/display/intel_dvo_regs.h
new file mode 100644
index 000000000000..6f9058462850
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/intel_dvo_regs.h
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2022 Intel Corporation
+ */
+
+#ifndef __INTEL_DVO_REGS_H__
+#define __INTEL_DVO_REGS_H__
+
+#include "intel_display_reg_defs.h"
+
+#define _DVOA 0x61120
+#define _DVOB 0x61140
+#define _DVOC 0x61160
+#define DVO(port) _MMIO_PORT((port), _DVOA, _DVOB)
+#define DVO_ENABLE REG_BIT(31)
+#define DVO_PIPE_SEL_MASK REG_BIT(30)
+#define DVO_PIPE_SEL(pipe) REG_FIELD_PREP(DVO_PIPE_SEL_MASK, (pipe))
+#define DVO_PIPE_STALL_MASK REG_GENMASK(29, 28)
+#define DVO_PIPE_STALL_UNUSED REG_FIELD_PREP(DVO_PIPE_STALL_MASK, 0)
+#define DVO_PIPE_STALL REG_FIELD_PREP(DVO_PIPE_STALL_MASK, 1)
+#define DVO_PIPE_STALL_TV REG_FIELD_PREP(DVO_PIPE_STALL_MASK, 2)
+#define DVO_INTERRUPT_SELECT REG_BIT(27)
+#define DVO_DEDICATED_INT_ENABLE REG_BIT(26)
+#define DVO_PRESERVE_MASK REG_GENMASK(25, 24)
+#define DVO_USE_VGA_SYNC REG_BIT(15)
+#define DVO_DATA_ORDER_MASK REG_BIT(14)
+#define DVO_DATA_ORDER_I740 REG_FIELD_PREP(DVO_DATA_ORDER_MASK, 0)
+#define DVO_DATA_ORDER_FP REG_FIELD_PREP(DVO_DATA_ORDER_MASK, 1)
+#define DVO_VSYNC_DISABLE REG_BIT(11)
+#define DVO_HSYNC_DISABLE REG_BIT(10)
+#define DVO_VSYNC_TRISTATE REG_BIT(9)
+#define DVO_HSYNC_TRISTATE REG_BIT(8)
+#define DVO_BORDER_ENABLE REG_BIT(7)
+#define DVO_ACT_DATA_ORDER_MASK REG_BIT(6)
+#define DVO_ACT_DATA_ORDER_RGGB REG_FIELD_PREP(DVO_ACT_DATA_ORDER_MASK, 0)
+#define DVO_ACT_DATA_ORDER_GBRG REG_FIELD_PREP(DVO_ACT_DATA_ORDER_MASK, 1)
+#define DVO_ACT_DATA_ORDER_GBRG_ERRATA REG_FIELD_PREP(DVO_ACT_DATA_ORDER_MASK, 0)
+#define DVO_ACT_DATA_ORDER_RGGB_ERRATA REG_FIELD_PREP(DVO_ACT_DATA_ORDER_MASK, 1)
+#define DVO_VSYNC_ACTIVE_HIGH REG_BIT(4)
+#define DVO_HSYNC_ACTIVE_HIGH REG_BIT(3)
+#define DVO_BLANK_ACTIVE_HIGH REG_BIT(2)
+#define DVO_OUTPUT_CSTATE_PIXELS REG_BIT(1) /* SDG only */
+#define DVO_OUTPUT_SOURCE_SIZE_PIXELS REG_BIT(0) /* SDG only */
+
+#define _DVOA_SRCDIM 0x61124
+#define _DVOB_SRCDIM 0x61144
+#define _DVOC_SRCDIM 0x61164
+#define DVO_SRCDIM(port) _MMIO_PORT((port), _DVOA_SRCDIM, _DVOB_SRCDIM)
+#define DVO_SRCDIM_HORIZONTAL_MASK REG_GENMASK(22, 12)
+#define DVO_SRCDIM_HORIZONTAL(x) REG_FIELD_PREP(DVO_SRCDIM_HORIZONTAL_MASK, (x))
+#define DVO_SRCDIM_VERTICAL_MASK REG_GENMASK(10, 0)
+#define DVO_SRCDIM_VERTICAL(x) REG_FIELD_PREP(DVO_SRCDIM_VERTICAL_MASK, (x))
+
+#endif /* __INTEL_DVO_REGS_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_fb.c b/drivers/gpu/drm/i915/display/intel_fb.c
index 63137ae5ab21..93d0e46e5481 100644
--- a/drivers/gpu/drm/i915/display/intel_fb.c
+++ b/drivers/gpu/drm/i915/display/intel_fb.c
@@ -174,7 +174,7 @@ static const struct intel_modifier_desc intel_modifiers[] = {
.plane_caps = INTEL_PLANE_CAP_TILING_4 | INTEL_PLANE_CAP_CCS_RC,
}, {
.modifier = I915_FORMAT_MOD_4_TILED,
- .display_ver = { 13, 13 },
+ .display_ver = { 13, -1 },
.plane_caps = INTEL_PLANE_CAP_TILING_4,
}, {
.modifier = I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS,
diff --git a/drivers/gpu/drm/i915/display/intel_fb_pin.c b/drivers/gpu/drm/i915/display/intel_fb_pin.c
index 6900acbb1381..1aca7552a85d 100644
--- a/drivers/gpu/drm/i915/display/intel_fb_pin.c
+++ b/drivers/gpu/drm/i915/display/intel_fb_pin.c
@@ -91,7 +91,7 @@ intel_pin_fb_obj_dpt(struct drm_framebuffer *fb,
goto err;
}
- vma->display_alignment = max_t(u64, vma->display_alignment, alignment);
+ vma->display_alignment = max(vma->display_alignment, alignment);
i915_gem_object_flush_if_display(obj);
diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c
index b5ee5ea0d010..b507ff944864 100644
--- a/drivers/gpu/drm/i915/display/intel_fbc.c
+++ b/drivers/gpu/drm/i915/display/intel_fbc.c
@@ -323,25 +323,23 @@ static void i8xx_fbc_nuke(struct intel_fbc *fbc)
enum i9xx_plane_id i9xx_plane = fbc_state->plane->i9xx_plane;
struct drm_i915_private *dev_priv = fbc->i915;
- spin_lock_irq(&dev_priv->uncore.lock);
intel_de_write_fw(dev_priv, DSPADDR(i9xx_plane),
intel_de_read_fw(dev_priv, DSPADDR(i9xx_plane)));
- spin_unlock_irq(&dev_priv->uncore.lock);
}
static void i8xx_fbc_program_cfb(struct intel_fbc *fbc)
{
struct drm_i915_private *i915 = fbc->i915;
- GEM_BUG_ON(range_overflows_end_t(u64, i915->dsm.start,
+ GEM_BUG_ON(range_overflows_end_t(u64, i915->dsm.stolen.start,
fbc->compressed_fb.start, U32_MAX));
- GEM_BUG_ON(range_overflows_end_t(u64, i915->dsm.start,
+ GEM_BUG_ON(range_overflows_end_t(u64, i915->dsm.stolen.start,
fbc->compressed_llb.start, U32_MAX));
intel_de_write(i915, FBC_CFB_BASE,
- i915->dsm.start + fbc->compressed_fb.start);
+ i915->dsm.stolen.start + fbc->compressed_fb.start);
intel_de_write(i915, FBC_LL_BASE,
- i915->dsm.start + fbc->compressed_llb.start);
+ i915->dsm.stolen.start + fbc->compressed_llb.start);
}
static const struct intel_fbc_funcs i8xx_fbc_funcs = {
@@ -359,10 +357,8 @@ static void i965_fbc_nuke(struct intel_fbc *fbc)
enum i9xx_plane_id i9xx_plane = fbc_state->plane->i9xx_plane;
struct drm_i915_private *dev_priv = fbc->i915;
- spin_lock_irq(&dev_priv->uncore.lock);
intel_de_write_fw(dev_priv, DSPSURF(i9xx_plane),
intel_de_read_fw(dev_priv, DSPSURF(i9xx_plane)));
- spin_unlock_irq(&dev_priv->uncore.lock);
}
static const struct intel_fbc_funcs i965_fbc_funcs = {
@@ -716,7 +712,7 @@ static u64 intel_fbc_stolen_end(struct drm_i915_private *i915)
* underruns, even if that range is not reserved by the BIOS. */
if (IS_BROADWELL(i915) ||
(DISPLAY_VER(i915) == 9 && !IS_BROXTON(i915)))
- end = resource_size(&i915->dsm) - 8 * 1024 * 1024;
+ end = resource_size(&i915->dsm.stolen) - 8 * 1024 * 1024;
else
end = U64_MAX;
@@ -815,7 +811,7 @@ static void intel_fbc_program_cfb(struct intel_fbc *fbc)
static void intel_fbc_program_workarounds(struct intel_fbc *fbc)
{
- /* Wa_22014263786:icl,jsl,tgl,dg1,rkl,adls,adlp */
+ /* Wa_22014263786:icl,jsl,tgl,dg1,rkl,adls,adlp,mtl */
if (DISPLAY_VER(fbc->i915) >= 11 && !IS_DG2(fbc->i915))
intel_de_rmw(fbc->i915, ILK_DPFC_CHICKEN(fbc->id), 0,
DPFC_CHICKEN_FORCE_SLB_INVALIDATION);
@@ -1095,7 +1091,9 @@ static int intel_fbc_check_plane(struct intel_atomic_state *state,
}
/* Wa_14016291713 */
- if (IS_DISPLAY_VER(i915, 12, 13) && crtc_state->has_psr) {
+ if ((IS_DISPLAY_VER(i915, 12, 13) ||
+ IS_MTL_DISPLAY_STEP(i915, STEP_A0, STEP_C0)) &&
+ crtc_state->has_psr) {
plane_state->no_fbc_reason = "PSR1 enabled (Wa_14016291713)";
return 0;
}
@@ -1809,10 +1807,10 @@ static int intel_fbc_debugfs_false_color_set(void *data, u64 val)
return 0;
}
-DEFINE_SIMPLE_ATTRIBUTE(intel_fbc_debugfs_false_color_fops,
- intel_fbc_debugfs_false_color_get,
- intel_fbc_debugfs_false_color_set,
- "%llu\n");
+DEFINE_DEBUGFS_ATTRIBUTE(intel_fbc_debugfs_false_color_fops,
+ intel_fbc_debugfs_false_color_get,
+ intel_fbc_debugfs_false_color_set,
+ "%llu\n");
static void intel_fbc_debugfs_add(struct intel_fbc *fbc,
struct dentry *parent)
@@ -1821,8 +1819,8 @@ static void intel_fbc_debugfs_add(struct intel_fbc *fbc,
fbc, &intel_fbc_debugfs_status_fops);
if (fbc->funcs->set_false_color)
- debugfs_create_file("i915_fbc_false_color", 0644, parent,
- fbc, &intel_fbc_debugfs_false_color_fops);
+ debugfs_create_file_unsafe("i915_fbc_false_color", 0644, parent,
+ fbc, &intel_fbc_debugfs_false_color_fops);
}
void intel_fbc_crtc_debugfs_add(struct intel_crtc *crtc)
diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c
index f76c06b7f1d4..f76b06293eb9 100644
--- a/drivers/gpu/drm/i915/display/intel_fbdev.c
+++ b/drivers/gpu/drm/i915/display/intel_fbdev.c
@@ -170,7 +170,7 @@ static int intelfb_alloc(struct drm_fb_helper *helper,
* important and we should probably use that space with FBC or other
* features.
*/
- if (size * 2 < dev_priv->stolen_usable_size)
+ if (size * 2 < dev_priv->dsm.usable_size)
obj = i915_gem_object_create_stolen(dev_priv, size);
if (IS_ERR(obj))
obj = i915_gem_object_create_shmem(dev_priv, size);
@@ -267,26 +267,19 @@ static int intelfb_create(struct drm_fb_helper *helper,
info->fbops = &intelfb_ops;
- /* setup aperture base/size for vesafb takeover */
obj = intel_fb_obj(&intel_fb->base);
if (i915_gem_object_is_lmem(obj)) {
struct intel_memory_region *mem = obj->mm.region;
- info->apertures->ranges[0].base = mem->io_start;
- info->apertures->ranges[0].size = mem->io_size;
-
/* Use fbdev's framebuffer from lmem for discrete */
info->fix.smem_start =
(unsigned long)(mem->io_start +
i915_gem_object_get_dma_address(obj, 0));
info->fix.smem_len = obj->base.size;
} else {
- info->apertures->ranges[0].base = ggtt->gmadr.start;
- info->apertures->ranges[0].size = ggtt->mappable_end;
-
/* Our framebuffer is the entirety of fbdev's system memory */
info->fix.smem_start =
- (unsigned long)(ggtt->gmadr.start + vma->node.start);
+ (unsigned long)(ggtt->gmadr.start + i915_ggtt_offset(vma));
info->fix.smem_len = vma->size;
}
@@ -359,6 +352,7 @@ static void intel_fbdev_destroy(struct intel_fbdev *ifbdev)
if (ifbdev->fb)
drm_framebuffer_remove(&ifbdev->fb->base);
+ drm_fb_helper_unprepare(&ifbdev->helper);
kfree(ifbdev);
}
@@ -539,10 +533,12 @@ int intel_fbdev_init(struct drm_device *dev)
return -ENOMEM;
mutex_init(&ifbdev->hpd_lock);
- drm_fb_helper_prepare(dev, &ifbdev->helper, &intel_fb_helper_funcs);
+ drm_fb_helper_prepare(dev, &ifbdev->helper, 32, &intel_fb_helper_funcs);
- if (!intel_fbdev_init_bios(dev, ifbdev))
- ifbdev->preferred_bpp = 32;
+ if (intel_fbdev_init_bios(dev, ifbdev))
+ ifbdev->helper.preferred_bpp = ifbdev->preferred_bpp;
+ else
+ ifbdev->preferred_bpp = ifbdev->helper.preferred_bpp;
ret = drm_fb_helper_init(dev, &ifbdev->helper);
if (ret) {
@@ -561,8 +557,7 @@ static void intel_fbdev_initial_config(void *data, async_cookie_t cookie)
struct intel_fbdev *ifbdev = data;
/* Due to peculiar init order wrt to hpd handling this is separate. */
- if (drm_fb_helper_initial_config(&ifbdev->helper,
- ifbdev->preferred_bpp))
+ if (drm_fb_helper_initial_config(&ifbdev->helper))
intel_fbdev_unregister(to_i915(ifbdev->helper.dev));
}
@@ -638,7 +633,13 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous
struct intel_fbdev *ifbdev = dev_priv->display.fbdev.fbdev;
struct fb_info *info;
- if (!ifbdev || !ifbdev->vma)
+ if (!ifbdev)
+ return;
+
+ if (drm_WARN_ON(&dev_priv->drm, !HAS_DISPLAY(dev_priv)))
+ return;
+
+ if (!ifbdev->vma)
goto set_suspend;
info = ifbdev->helper.info;
diff --git a/drivers/gpu/drm/i915/display/intel_gmbus.c b/drivers/gpu/drm/i915/display/intel_gmbus.c
index a5840a28a69d..0bc4f6b48e80 100644
--- a/drivers/gpu/drm/i915/display/intel_gmbus.c
+++ b/drivers/gpu/drm/i915/display/intel_gmbus.c
@@ -255,14 +255,12 @@ static void bxt_gmbus_clock_gating(struct drm_i915_private *i915,
static u32 get_reserved(struct intel_gmbus *bus)
{
struct drm_i915_private *i915 = bus->i915;
- struct intel_uncore *uncore = &i915->uncore;
u32 reserved = 0;
/* On most chips, these bits must be preserved in software. */
if (!IS_I830(i915) && !IS_I845G(i915))
- reserved = intel_uncore_read_notrace(uncore, bus->gpio_reg) &
- (GPIO_DATA_PULLUP_DISABLE |
- GPIO_CLOCK_PULLUP_DISABLE);
+ reserved = intel_de_read_notrace(i915, bus->gpio_reg) &
+ (GPIO_DATA_PULLUP_DISABLE | GPIO_CLOCK_PULLUP_DISABLE);
return reserved;
}
@@ -270,37 +268,31 @@ static u32 get_reserved(struct intel_gmbus *bus)
static int get_clock(void *data)
{
struct intel_gmbus *bus = data;
- struct intel_uncore *uncore = &bus->i915->uncore;
+ struct drm_i915_private *i915 = bus->i915;
u32 reserved = get_reserved(bus);
- intel_uncore_write_notrace(uncore,
- bus->gpio_reg,
- reserved | GPIO_CLOCK_DIR_MASK);
- intel_uncore_write_notrace(uncore, bus->gpio_reg, reserved);
+ intel_de_write_notrace(i915, bus->gpio_reg, reserved | GPIO_CLOCK_DIR_MASK);
+ intel_de_write_notrace(i915, bus->gpio_reg, reserved);
- return (intel_uncore_read_notrace(uncore, bus->gpio_reg) &
- GPIO_CLOCK_VAL_IN) != 0;
+ return (intel_de_read_notrace(i915, bus->gpio_reg) & GPIO_CLOCK_VAL_IN) != 0;
}
static int get_data(void *data)
{
struct intel_gmbus *bus = data;
- struct intel_uncore *uncore = &bus->i915->uncore;
+ struct drm_i915_private *i915 = bus->i915;
u32 reserved = get_reserved(bus);
- intel_uncore_write_notrace(uncore,
- bus->gpio_reg,
- reserved | GPIO_DATA_DIR_MASK);
- intel_uncore_write_notrace(uncore, bus->gpio_reg, reserved);
+ intel_de_write_notrace(i915, bus->gpio_reg, reserved | GPIO_DATA_DIR_MASK);
+ intel_de_write_notrace(i915, bus->gpio_reg, reserved);
- return (intel_uncore_read_notrace(uncore, bus->gpio_reg) &
- GPIO_DATA_VAL_IN) != 0;
+ return (intel_de_read_notrace(i915, bus->gpio_reg) & GPIO_DATA_VAL_IN) != 0;
}
static void set_clock(void *data, int state_high)
{
struct intel_gmbus *bus = data;
- struct intel_uncore *uncore = &bus->i915->uncore;
+ struct drm_i915_private *i915 = bus->i915;
u32 reserved = get_reserved(bus);
u32 clock_bits;
@@ -310,16 +302,14 @@ static void set_clock(void *data, int state_high)
clock_bits = GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK |
GPIO_CLOCK_VAL_MASK;
- intel_uncore_write_notrace(uncore,
- bus->gpio_reg,
- reserved | clock_bits);
- intel_uncore_posting_read(uncore, bus->gpio_reg);
+ intel_de_write_notrace(i915, bus->gpio_reg, reserved | clock_bits);
+ intel_de_posting_read(i915, bus->gpio_reg);
}
static void set_data(void *data, int state_high)
{
struct intel_gmbus *bus = data;
- struct intel_uncore *uncore = &bus->i915->uncore;
+ struct drm_i915_private *i915 = bus->i915;
u32 reserved = get_reserved(bus);
u32 data_bits;
@@ -329,8 +319,8 @@ static void set_data(void *data, int state_high)
data_bits = GPIO_DATA_DIR_OUT | GPIO_DATA_DIR_MASK |
GPIO_DATA_VAL_MASK;
- intel_uncore_write_notrace(uncore, bus->gpio_reg, reserved | data_bits);
- intel_uncore_posting_read(uncore, bus->gpio_reg);
+ intel_de_write_notrace(i915, bus->gpio_reg, reserved | data_bits);
+ intel_de_posting_read(i915, bus->gpio_reg);
}
static int
@@ -439,9 +429,7 @@ gmbus_wait_idle(struct drm_i915_private *i915)
add_wait_queue(&i915->display.gmbus.wait_queue, &wait);
intel_de_write_fw(i915, GMBUS4(i915), irq_enable);
- ret = intel_wait_for_register_fw(&i915->uncore,
- GMBUS2(i915), GMBUS_ACTIVE, 0,
- 10);
+ ret = intel_de_wait_for_register_fw(i915, GMBUS2(i915), GMBUS_ACTIVE, 0, 10);
intel_de_write_fw(i915, GMBUS4(i915), 0);
remove_wait_queue(&i915->display.gmbus.wait_queue, &wait);
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
index bac85d88054f..c0ce6d3dc505 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -44,6 +44,7 @@
#include "i915_drv.h"
#include "i915_reg.h"
#include "intel_atomic.h"
+#include "intel_audio.h"
#include "intel_connector.h"
#include "intel_ddi.h"
#include "intel_de.h"
@@ -537,8 +538,7 @@ void hsw_write_infoframe(struct intel_encoder *encoder,
0);
/* Wa_14013475917 */
- if (DISPLAY_VER(dev_priv) == 13 && crtc_state->has_psr &&
- type == DP_SDP_VSC)
+ if (IS_DISPLAY_VER(dev_priv, 13, 14) && crtc_state->has_psr && type == DP_SDP_VSC)
return;
val |= hsw_infoframe_enable(type);
@@ -767,6 +767,7 @@ intel_hdmi_compute_spd_infoframe(struct intel_encoder *encoder,
struct intel_crtc_state *crtc_state,
struct drm_connector_state *conn_state)
{
+ struct drm_i915_private *i915 = to_i915(encoder->base.dev);
struct hdmi_spd_infoframe *frame = &crtc_state->infoframes.spd.spd;
int ret;
@@ -776,7 +777,11 @@ intel_hdmi_compute_spd_infoframe(struct intel_encoder *encoder,
crtc_state->infoframes.enable |=
intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_SPD);
- ret = hdmi_spd_infoframe_init(frame, "Intel", "Integrated gfx");
+ if (IS_DGFX(i915))
+ ret = hdmi_spd_infoframe_init(frame, "Intel", "Discrete gfx");
+ else
+ ret = hdmi_spd_infoframe_init(frame, "Intel", "Integrated gfx");
+
if (drm_WARN_ON(encoder->base.dev, ret))
return false;
@@ -1988,9 +1993,6 @@ intel_hdmi_mode_valid(struct drm_connector *connector,
bool has_hdmi_sink = intel_has_hdmi_sink(hdmi, connector->state);
bool ycbcr_420_only;
- if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
- return MODE_NO_DBLESCAN;
-
if ((mode->flags & DRM_MODE_FLAG_3D_MASK) == DRM_MODE_FLAG_3D_FRAME_PACKING)
clock *= 2;
@@ -2252,6 +2254,10 @@ int intel_hdmi_compute_config(struct intel_encoder *encoder,
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
return -EINVAL;
+ if (!connector->interlace_allowed &&
+ adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
+ return -EINVAL;
+
pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
pipe_config->has_hdmi_sink =
intel_has_hdmi_sink(intel_hdmi, conn_state) &&
@@ -2264,7 +2270,8 @@ int intel_hdmi_compute_config(struct intel_encoder *encoder,
pipe_config->pixel_multiplier = 2;
pipe_config->has_audio =
- intel_hdmi_has_audio(encoder, pipe_config, conn_state);
+ intel_hdmi_has_audio(encoder, pipe_config, conn_state) &&
+ intel_audio_compute_config(encoder, pipe_config, conn_state);
/*
* Try to respect downstream TMDS clock limits first, if
@@ -2353,7 +2360,7 @@ intel_hdmi_unset_edid(struct drm_connector *connector)
intel_hdmi->dp_dual_mode.type = DRM_DP_DUAL_MODE_NONE;
intel_hdmi->dp_dual_mode.max_tmds_clock = 0;
- kfree(to_intel_connector(connector)->detect_edid);
+ drm_edid_free(to_intel_connector(connector)->detect_edid);
to_intel_connector(connector)->detect_edid = NULL;
}
@@ -2414,7 +2421,8 @@ intel_hdmi_set_edid(struct drm_connector *connector)
struct drm_i915_private *dev_priv = to_i915(connector->dev);
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(to_intel_connector(connector));
intel_wakeref_t wakeref;
- struct edid *edid;
+ const struct drm_edid *drm_edid;
+ const struct edid *edid;
bool connected = false;
struct i2c_adapter *i2c;
@@ -2422,17 +2430,23 @@ intel_hdmi_set_edid(struct drm_connector *connector)
i2c = intel_gmbus_get_adapter(dev_priv, intel_hdmi->ddc_bus);
- edid = drm_get_edid(connector, i2c);
+ drm_edid = drm_edid_read_ddc(connector, i2c);
- if (!edid && !intel_gmbus_is_forced_bit(i2c)) {
+ if (!drm_edid && !intel_gmbus_is_forced_bit(i2c)) {
drm_dbg_kms(&dev_priv->drm,
"HDMI GMBUS EDID read failed, retry using GPIO bit-banging\n");
intel_gmbus_force_bit(i2c, true);
- edid = drm_get_edid(connector, i2c);
+ drm_edid = drm_edid_read_ddc(connector, i2c);
intel_gmbus_force_bit(i2c, false);
}
- to_intel_connector(connector)->detect_edid = edid;
+ /* Below we depend on display info having been updated */
+ drm_edid_connector_update(connector, drm_edid);
+
+ to_intel_connector(connector)->detect_edid = drm_edid;
+
+ /* FIXME: Get rid of drm_edid_raw() */
+ edid = drm_edid_raw(drm_edid);
if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
intel_hdmi->has_audio = drm_detect_monitor_audio(edid);
intel_hdmi->has_hdmi_sink = drm_detect_hdmi_monitor(edid);
@@ -2508,13 +2522,8 @@ intel_hdmi_force(struct drm_connector *connector)
static int intel_hdmi_get_modes(struct drm_connector *connector)
{
- struct edid *edid;
-
- edid = to_intel_connector(connector)->detect_edid;
- if (edid == NULL)
- return 0;
-
- return intel_connector_update_modes(connector, edid);
+ /* drm_edid_connector_update() done in ->detect() or ->force() */
+ return drm_edid_connector_add_modes(connector);
}
static struct i2c_adapter *
@@ -2953,7 +2962,9 @@ void intel_hdmi_init_connector(struct intel_digital_port *dig_port,
ddc);
drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs);
- connector->interlace_allowed = true;
+ if (DISPLAY_VER(dev_priv) < 12)
+ connector->interlace_allowed = true;
+
connector->stereo_allowed = true;
if (DISPLAY_VER(dev_priv) >= 10)
diff --git a/drivers/gpu/drm/i915/display/intel_hti.c b/drivers/gpu/drm/i915/display/intel_hti.c
index 12a1f4ce1a77..c518efebdf77 100644
--- a/drivers/gpu/drm/i915/display/intel_hti.c
+++ b/drivers/gpu/drm/i915/display/intel_hti.c
@@ -21,6 +21,9 @@ void intel_hti_init(struct drm_i915_private *i915)
bool intel_hti_uses_phy(struct drm_i915_private *i915, enum phy phy)
{
+ if (drm_WARN_ON(&i915->drm, phy == PHY_NONE))
+ return false;
+
return i915->display.hti.state & HDPORT_ENABLED &&
i915->display.hti.state & HDPORT_DDI_USED(phy);
}
diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c
index 7bf1bdfd03ec..a1557d84ce0a 100644
--- a/drivers/gpu/drm/i915/display/intel_lvds.c
+++ b/drivers/gpu/drm/i915/display/intel_lvds.c
@@ -477,10 +477,14 @@ static int intel_lvds_compute_config(struct intel_encoder *intel_encoder,
static int intel_lvds_get_modes(struct drm_connector *connector)
{
struct intel_connector *intel_connector = to_intel_connector(connector);
+ const struct drm_edid *fixed_edid = intel_connector->panel.fixed_edid;
- /* use cached edid if we have one */
- if (!IS_ERR_OR_NULL(intel_connector->edid))
- return drm_add_edid_modes(connector, intel_connector->edid);
+ /* Use panel fixed edid if we have one */
+ if (!IS_ERR_OR_NULL(fixed_edid)) {
+ drm_edid_connector_update(connector, fixed_edid);
+
+ return drm_edid_connector_add_modes(connector);
+ }
return intel_panel_get_modes(intel_connector);
}
@@ -834,7 +838,7 @@ void intel_lvds_init(struct drm_i915_private *dev_priv)
struct intel_connector *intel_connector;
struct drm_connector *connector;
struct drm_encoder *encoder;
- struct edid *edid;
+ const struct drm_edid *drm_edid;
i915_reg_t lvds_reg;
u32 lvds;
u8 pin;
@@ -945,27 +949,34 @@ void intel_lvds_init(struct drm_i915_private *dev_priv)
* preferred mode is the right one.
*/
mutex_lock(&dev_priv->drm.mode_config.mutex);
- if (vga_switcheroo_handler_flags() & VGA_SWITCHEROO_CAN_SWITCH_DDC)
+ if (vga_switcheroo_handler_flags() & VGA_SWITCHEROO_CAN_SWITCH_DDC) {
+ const struct edid *edid;
+
+ /* FIXME: Make drm_get_edid_switcheroo() return drm_edid */
edid = drm_get_edid_switcheroo(connector,
- intel_gmbus_get_adapter(dev_priv, pin));
- else
- edid = drm_get_edid(connector,
- intel_gmbus_get_adapter(dev_priv, pin));
- if (edid) {
- if (drm_add_edid_modes(connector, edid)) {
- drm_connector_update_edid_property(connector,
- edid);
- } else {
+ intel_gmbus_get_adapter(dev_priv, pin));
+ if (edid) {
+ drm_edid = drm_edid_alloc(edid, (edid->extensions + 1) * EDID_LENGTH);
kfree(edid);
- edid = ERR_PTR(-EINVAL);
+ } else {
+ drm_edid = NULL;
}
} else {
- edid = ERR_PTR(-ENOENT);
+ drm_edid = drm_edid_read_ddc(connector,
+ intel_gmbus_get_adapter(dev_priv, pin));
}
- intel_connector->edid = edid;
-
- intel_bios_init_panel(dev_priv, &intel_connector->panel, NULL,
- IS_ERR(edid) ? NULL : edid);
+ if (drm_edid) {
+ if (drm_edid_connector_update(connector, drm_edid) ||
+ !drm_edid_connector_add_modes(connector)) {
+ drm_edid_connector_update(connector, NULL);
+ drm_edid_free(drm_edid);
+ drm_edid = ERR_PTR(-EINVAL);
+ }
+ } else {
+ drm_edid = ERR_PTR(-ENOENT);
+ }
+ intel_bios_init_panel_late(dev_priv, &intel_connector->panel, NULL,
+ IS_ERR(drm_edid) ? NULL : drm_edid);
/* Try EDID first */
intel_panel_add_edid_fixed_modes(intel_connector, true);
@@ -988,7 +999,7 @@ void intel_lvds_init(struct drm_i915_private *dev_priv)
if (!intel_panel_preferred_fixed_mode(intel_connector))
goto failed;
- intel_panel_init(intel_connector);
+ intel_panel_init(intel_connector, drm_edid);
intel_backlight_setup(intel_connector, INVALID_PIPE);
diff --git a/drivers/gpu/drm/i915/display/intel_modeset_setup.c b/drivers/gpu/drm/i915/display/intel_modeset_setup.c
index 96395bfbd41d..52cdbd4fc2fa 100644
--- a/drivers/gpu/drm/i915/display/intel_modeset_setup.c
+++ b/drivers/gpu/drm/i915/display/intel_modeset_setup.c
@@ -698,8 +698,10 @@ void intel_modeset_setup_hw_state(struct drm_i915_private *i915,
drm_crtc_vblank_reset(&crtc->base);
- if (crtc_state->hw.active)
+ if (crtc_state->hw.active) {
+ intel_dmc_enable_pipe(i915, crtc->pipe);
intel_crtc_vblank_on(crtc_state);
+ }
}
intel_fbc_sanitize(i915);
diff --git a/drivers/gpu/drm/i915/display/intel_opregion.c b/drivers/gpu/drm/i915/display/intel_opregion.c
index e0184745632c..b8dce0576512 100644
--- a/drivers/gpu/drm/i915/display/intel_opregion.c
+++ b/drivers/gpu/drm/i915/display/intel_opregion.c
@@ -1101,41 +1101,34 @@ intel_opregion_get_panel_type(struct drm_i915_private *dev_priv)
* The EDID in the OpRegion, or NULL if there is none or it's invalid.
*
*/
-struct edid *intel_opregion_get_edid(struct intel_connector *intel_connector)
+const struct drm_edid *intel_opregion_get_edid(struct intel_connector *intel_connector)
{
struct drm_connector *connector = &intel_connector->base;
struct drm_i915_private *i915 = to_i915(connector->dev);
struct intel_opregion *opregion = &i915->display.opregion;
- const void *in_edid;
- const struct edid *edid;
- struct edid *new_edid;
+ const struct drm_edid *drm_edid;
+ const void *edid;
int len;
if (!opregion->asle_ext)
return NULL;
- in_edid = opregion->asle_ext->bddc;
+ edid = opregion->asle_ext->bddc;
/* Validity corresponds to number of 128-byte blocks */
len = (opregion->asle_ext->phed & ASLE_PHED_EDID_VALID_MASK) * 128;
- if (!len || !memchr_inv(in_edid, 0, len))
+ if (!len || !memchr_inv(edid, 0, len))
return NULL;
- edid = in_edid;
+ drm_edid = drm_edid_alloc(edid, len);
- if (len < EDID_LENGTH * (1 + edid->extensions)) {
- drm_dbg_kms(&i915->drm, "Invalid EDID in ACPI OpRegion (Mailbox #5): too short\n");
- return NULL;
- }
- new_edid = drm_edid_duplicate(edid);
- if (!new_edid)
- return NULL;
- if (!drm_edid_is_valid(new_edid)) {
- kfree(new_edid);
+ if (!drm_edid_valid(drm_edid)) {
drm_dbg_kms(&i915->drm, "Invalid EDID in ACPI OpRegion (Mailbox #5)\n");
- return NULL;
+ drm_edid_free(drm_edid);
+ drm_edid = NULL;
}
- return new_edid;
+
+ return drm_edid;
}
bool intel_opregion_headless_sku(struct drm_i915_private *i915)
diff --git a/drivers/gpu/drm/i915/display/intel_opregion.h b/drivers/gpu/drm/i915/display/intel_opregion.h
index 2f261f985400..d02e6696a050 100644
--- a/drivers/gpu/drm/i915/display/intel_opregion.h
+++ b/drivers/gpu/drm/i915/display/intel_opregion.h
@@ -74,7 +74,7 @@ int intel_opregion_notify_encoder(struct intel_encoder *intel_encoder,
int intel_opregion_notify_adapter(struct drm_i915_private *dev_priv,
pci_power_t state);
int intel_opregion_get_panel_type(struct drm_i915_private *dev_priv);
-struct edid *intel_opregion_get_edid(struct intel_connector *connector);
+const struct drm_edid *intel_opregion_get_edid(struct intel_connector *connector);
bool intel_opregion_headless_sku(struct drm_i915_private *i915);
@@ -123,7 +123,7 @@ static inline int intel_opregion_get_panel_type(struct drm_i915_private *dev)
return -ENODEV;
}
-static inline struct edid *
+static inline const struct drm_edid *
intel_opregion_get_edid(struct intel_connector *connector)
{
return NULL;
diff --git a/drivers/gpu/drm/i915/display/intel_panel.c b/drivers/gpu/drm/i915/display/intel_panel.c
index 1640726bfbf6..42aa04bac261 100644
--- a/drivers/gpu/drm/i915/display/intel_panel.c
+++ b/drivers/gpu/drm/i915/display/intel_panel.c
@@ -31,6 +31,8 @@
#include <linux/kernel.h>
#include <linux/pwm.h>
+#include <drm/drm_edid.h>
+
#include "i915_reg.h"
#include "intel_backlight.h"
#include "intel_connector.h"
@@ -661,10 +663,22 @@ intel_panel_mode_valid(struct intel_connector *connector,
return MODE_OK;
}
-int intel_panel_init(struct intel_connector *connector)
+void intel_panel_init_alloc(struct intel_connector *connector)
+{
+ struct intel_panel *panel = &connector->panel;
+
+ connector->panel.vbt.panel_type = -1;
+ connector->panel.vbt.backlight.controller = -1;
+ INIT_LIST_HEAD(&panel->fixed_modes);
+}
+
+int intel_panel_init(struct intel_connector *connector,
+ const struct drm_edid *fixed_edid)
{
struct intel_panel *panel = &connector->panel;
+ panel->fixed_edid = fixed_edid;
+
intel_backlight_init_funcs(panel);
if (!has_drrs_modes(connector))
@@ -683,6 +697,9 @@ void intel_panel_fini(struct intel_connector *connector)
struct intel_panel *panel = &connector->panel;
struct drm_display_mode *fixed_mode, *next;
+ if (!IS_ERR_OR_NULL(panel->fixed_edid))
+ drm_edid_free(panel->fixed_edid);
+
intel_backlight_destroy(panel);
intel_bios_fini_panel(panel);
diff --git a/drivers/gpu/drm/i915/display/intel_panel.h b/drivers/gpu/drm/i915/display/intel_panel.h
index 5c5b5b7f95b6..15a8c897b33f 100644
--- a/drivers/gpu/drm/i915/display/intel_panel.h
+++ b/drivers/gpu/drm/i915/display/intel_panel.h
@@ -13,12 +13,15 @@ enum drrs_type;
struct drm_connector;
struct drm_connector_state;
struct drm_display_mode;
+struct drm_edid;
struct drm_i915_private;
struct intel_connector;
struct intel_crtc_state;
struct intel_encoder;
-int intel_panel_init(struct intel_connector *connector);
+void intel_panel_init_alloc(struct intel_connector *connector);
+int intel_panel_init(struct intel_connector *connector,
+ const struct drm_edid *fixed_edid);
void intel_panel_fini(struct intel_connector *connector);
enum drm_connector_status
intel_panel_detect(struct drm_connector *connector, bool force);
diff --git a/drivers/gpu/drm/i915/display/intel_pch_refclk.c b/drivers/gpu/drm/i915/display/intel_pch_refclk.c
index 08a94365b7d1..3657b2940702 100644
--- a/drivers/gpu/drm/i915/display/intel_pch_refclk.c
+++ b/drivers/gpu/drm/i915/display/intel_pch_refclk.c
@@ -467,24 +467,24 @@ static void lpt_init_pch_refclk(struct drm_i915_private *dev_priv)
* clock hierarchy. That would also allow us to do
* clock bending finally.
*/
- dev_priv->pch_ssc_use = 0;
+ dev_priv->display.dpll.pch_ssc_use = 0;
if (spll_uses_pch_ssc(dev_priv)) {
drm_dbg_kms(&dev_priv->drm, "SPLL using PCH SSC\n");
- dev_priv->pch_ssc_use |= BIT(DPLL_ID_SPLL);
+ dev_priv->display.dpll.pch_ssc_use |= BIT(DPLL_ID_SPLL);
}
if (wrpll_uses_pch_ssc(dev_priv, DPLL_ID_WRPLL1)) {
drm_dbg_kms(&dev_priv->drm, "WRPLL1 using PCH SSC\n");
- dev_priv->pch_ssc_use |= BIT(DPLL_ID_WRPLL1);
+ dev_priv->display.dpll.pch_ssc_use |= BIT(DPLL_ID_WRPLL1);
}
if (wrpll_uses_pch_ssc(dev_priv, DPLL_ID_WRPLL2)) {
drm_dbg_kms(&dev_priv->drm, "WRPLL2 using PCH SSC\n");
- dev_priv->pch_ssc_use |= BIT(DPLL_ID_WRPLL2);
+ dev_priv->display.dpll.pch_ssc_use |= BIT(DPLL_ID_WRPLL2);
}
- if (dev_priv->pch_ssc_use)
+ if (dev_priv->display.dpll.pch_ssc_use)
return;
if (has_fdi) {
diff --git a/drivers/gpu/drm/i915/display/intel_pipe_crc.c b/drivers/gpu/drm/i915/display/intel_pipe_crc.c
index e9774670e3f6..8d3ea8d7b737 100644
--- a/drivers/gpu/drm/i915/display/intel_pipe_crc.c
+++ b/drivers/gpu/drm/i915/display/intel_pipe_crc.c
@@ -72,14 +72,13 @@ static int i8xx_pipe_crc_ctl_reg(enum intel_pipe_crc_source *source,
return 0;
}
-static int i9xx_pipe_crc_auto_source(struct drm_i915_private *dev_priv,
- enum pipe pipe,
- enum intel_pipe_crc_source *source)
+static void i9xx_pipe_crc_auto_source(struct drm_i915_private *dev_priv,
+ enum pipe pipe,
+ enum intel_pipe_crc_source *source)
{
struct intel_encoder *encoder;
struct intel_crtc *crtc;
struct intel_digital_port *dig_port;
- int ret = 0;
*source = INTEL_PIPE_CRC_SOURCE_PIPE;
@@ -121,8 +120,6 @@ static int i9xx_pipe_crc_auto_source(struct drm_i915_private *dev_priv,
}
}
drm_modeset_unlock_all(&dev_priv->drm);
-
- return ret;
}
static int vlv_pipe_crc_ctl_reg(struct drm_i915_private *dev_priv,
@@ -132,11 +129,8 @@ static int vlv_pipe_crc_ctl_reg(struct drm_i915_private *dev_priv,
{
bool need_stable_symbols = false;
- if (*source == INTEL_PIPE_CRC_SOURCE_AUTO) {
- int ret = i9xx_pipe_crc_auto_source(dev_priv, pipe, source);
- if (ret)
- return ret;
- }
+ if (*source == INTEL_PIPE_CRC_SOURCE_AUTO)
+ i9xx_pipe_crc_auto_source(dev_priv, pipe, source);
switch (*source) {
case INTEL_PIPE_CRC_SOURCE_PIPE:
@@ -200,11 +194,8 @@ static int i9xx_pipe_crc_ctl_reg(struct drm_i915_private *dev_priv,
enum intel_pipe_crc_source *source,
u32 *val)
{
- if (*source == INTEL_PIPE_CRC_SOURCE_AUTO) {
- int ret = i9xx_pipe_crc_auto_source(dev_priv, pipe, source);
- if (ret)
- return ret;
- }
+ if (*source == INTEL_PIPE_CRC_SOURCE_AUTO)
+ i9xx_pipe_crc_auto_source(dev_priv, pipe, source);
switch (*source) {
case INTEL_PIPE_CRC_SOURCE_PIPE:
diff --git a/drivers/gpu/drm/i915/display/intel_plane_initial.c b/drivers/gpu/drm/i915/display/intel_plane_initial.c
index 76be796df255..bb6ea7de5c61 100644
--- a/drivers/gpu/drm/i915/display/intel_plane_initial.c
+++ b/drivers/gpu/drm/i915/display/intel_plane_initial.c
@@ -107,7 +107,7 @@ initial_plane_vma(struct drm_i915_private *i915,
*/
if (IS_ENABLED(CONFIG_FRAMEBUFFER_CONSOLE) &&
mem == i915->mm.stolen_region &&
- size * 2 > i915->stolen_usable_size)
+ size * 2 > i915->dsm.usable_size)
return NULL;
obj = i915_gem_object_create_region_at(mem, phys_base, size, 0);
diff --git a/drivers/gpu/drm/i915/display/intel_pps.c b/drivers/gpu/drm/i915/display/intel_pps.c
index 9bbf41a076f7..7b21438edd9b 100644
--- a/drivers/gpu/drm/i915/display/intel_pps.c
+++ b/drivers/gpu/drm/i915/display/intel_pps.c
@@ -22,6 +22,40 @@ static void vlv_steal_power_sequencer(struct drm_i915_private *dev_priv,
static void pps_init_delays(struct intel_dp *intel_dp);
static void pps_init_registers(struct intel_dp *intel_dp, bool force_disable_vdd);
+static const char *pps_name(struct drm_i915_private *i915,
+ struct intel_pps *pps)
+{
+ if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) {
+ switch (pps->pps_pipe) {
+ case INVALID_PIPE:
+ /*
+ * FIXME would be nice if we can guarantee
+ * to always have a valid PPS when calling this.
+ */
+ return "PPS <none>";
+ case PIPE_A:
+ return "PPS A";
+ case PIPE_B:
+ return "PPS B";
+ default:
+ MISSING_CASE(pps->pps_pipe);
+ break;
+ }
+ } else {
+ switch (pps->pps_idx) {
+ case 0:
+ return "PPS 0";
+ case 1:
+ return "PPS 1";
+ default:
+ MISSING_CASE(pps->pps_idx);
+ break;
+ }
+ }
+
+ return "PPS <invalid>";
+}
+
intel_wakeref_t intel_pps_lock(struct intel_dp *intel_dp)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
@@ -60,15 +94,15 @@ vlv_power_sequencer_kick(struct intel_dp *intel_dp)
if (drm_WARN(&dev_priv->drm,
intel_de_read(dev_priv, intel_dp->output_reg) & DP_PORT_EN,
- "skipping pipe %c power sequencer kick due to [ENCODER:%d:%s] being active\n",
- pipe_name(pipe), dig_port->base.base.base.id,
- dig_port->base.base.name))
+ "skipping %s kick due to [ENCODER:%d:%s] being active\n",
+ pps_name(dev_priv, &intel_dp->pps),
+ dig_port->base.base.base.id, dig_port->base.base.name))
return;
drm_dbg_kms(&dev_priv->drm,
- "kicking pipe %c power sequencer for [ENCODER:%d:%s]\n",
- pipe_name(pipe), dig_port->base.base.base.id,
- dig_port->base.base.name);
+ "kicking %s for [ENCODER:%d:%s]\n",
+ pps_name(dev_priv, &intel_dp->pps),
+ dig_port->base.base.base.id, dig_port->base.base.name);
/* Preserve the BIOS-computed detected bit. This is
* supposed to be read-only.
@@ -95,7 +129,7 @@ vlv_power_sequencer_kick(struct intel_dp *intel_dp)
if (vlv_force_pll_on(dev_priv, pipe, vlv_get_dpll(dev_priv))) {
drm_err(&dev_priv->drm,
- "Failed to force on pll for pipe %c!\n",
+ "Failed to force on PLL for pipe %c!\n",
pipe_name(pipe));
return;
}
@@ -190,10 +224,9 @@ vlv_power_sequencer_pipe(struct intel_dp *intel_dp)
intel_dp->pps.pps_pipe = pipe;
drm_dbg_kms(&dev_priv->drm,
- "picked pipe %c power sequencer for [ENCODER:%d:%s]\n",
- pipe_name(intel_dp->pps.pps_pipe),
- dig_port->base.base.base.id,
- dig_port->base.base.name);
+ "picked %s for [ENCODER:%d:%s]\n",
+ pps_name(dev_priv, &intel_dp->pps),
+ dig_port->base.base.base.id, dig_port->base.base.name);
/* init power sequencer on this pipe and port */
pps_init_delays(intel_dp);
@@ -212,8 +245,7 @@ static int
bxt_power_sequencer_idx(struct intel_dp *intel_dp)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
- struct intel_connector *connector = intel_dp->attached_connector;
- int backlight_controller = connector->panel.vbt.backlight.controller;
+ int pps_idx = intel_dp->pps.pps_idx;
lockdep_assert_held(&dev_priv->display.pps.mutex);
@@ -221,7 +253,7 @@ bxt_power_sequencer_idx(struct intel_dp *intel_dp)
drm_WARN_ON(&dev_priv->drm, !intel_dp_is_edp(intel_dp));
if (!intel_dp->pps.pps_reset)
- return backlight_controller;
+ return pps_idx;
intel_dp->pps.pps_reset = false;
@@ -231,34 +263,29 @@ bxt_power_sequencer_idx(struct intel_dp *intel_dp)
*/
pps_init_registers(intel_dp, false);
- return backlight_controller;
+ return pps_idx;
}
-typedef bool (*vlv_pipe_check)(struct drm_i915_private *dev_priv,
- enum pipe pipe);
+typedef bool (*pps_check)(struct drm_i915_private *dev_priv, int pps_idx);
-static bool vlv_pipe_has_pp_on(struct drm_i915_private *dev_priv,
- enum pipe pipe)
+static bool pps_has_pp_on(struct drm_i915_private *dev_priv, int pps_idx)
{
- return intel_de_read(dev_priv, PP_STATUS(pipe)) & PP_ON;
+ return intel_de_read(dev_priv, PP_STATUS(pps_idx)) & PP_ON;
}
-static bool vlv_pipe_has_vdd_on(struct drm_i915_private *dev_priv,
- enum pipe pipe)
+static bool pps_has_vdd_on(struct drm_i915_private *dev_priv, int pps_idx)
{
- return intel_de_read(dev_priv, PP_CONTROL(pipe)) & EDP_FORCE_VDD;
+ return intel_de_read(dev_priv, PP_CONTROL(pps_idx)) & EDP_FORCE_VDD;
}
-static bool vlv_pipe_any(struct drm_i915_private *dev_priv,
- enum pipe pipe)
+static bool pps_any(struct drm_i915_private *dev_priv, int pps_idx)
{
return true;
}
static enum pipe
vlv_initial_pps_pipe(struct drm_i915_private *dev_priv,
- enum port port,
- vlv_pipe_check pipe_check)
+ enum port port, pps_check check)
{
enum pipe pipe;
@@ -269,7 +296,7 @@ vlv_initial_pps_pipe(struct drm_i915_private *dev_priv,
if (port_sel != PANEL_PORT_SELECT_VLV(port))
continue;
- if (!pipe_check(dev_priv, pipe))
+ if (!check(dev_priv, pipe))
continue;
return pipe;
@@ -290,30 +317,117 @@ vlv_initial_power_sequencer_setup(struct intel_dp *intel_dp)
/* try to find a pipe with this port selected */
/* first pick one where the panel is on */
intel_dp->pps.pps_pipe = vlv_initial_pps_pipe(dev_priv, port,
- vlv_pipe_has_pp_on);
+ pps_has_pp_on);
/* didn't find one? pick one where vdd is on */
if (intel_dp->pps.pps_pipe == INVALID_PIPE)
intel_dp->pps.pps_pipe = vlv_initial_pps_pipe(dev_priv, port,
- vlv_pipe_has_vdd_on);
+ pps_has_vdd_on);
/* didn't find one? pick one with just the correct port */
if (intel_dp->pps.pps_pipe == INVALID_PIPE)
intel_dp->pps.pps_pipe = vlv_initial_pps_pipe(dev_priv, port,
- vlv_pipe_any);
+ pps_any);
/* didn't find one? just let vlv_power_sequencer_pipe() pick one when needed */
if (intel_dp->pps.pps_pipe == INVALID_PIPE) {
drm_dbg_kms(&dev_priv->drm,
- "no initial power sequencer for [ENCODER:%d:%s]\n",
- dig_port->base.base.base.id,
- dig_port->base.base.name);
+ "[ENCODER:%d:%s] no initial power sequencer\n",
+ dig_port->base.base.base.id, dig_port->base.base.name);
return;
}
drm_dbg_kms(&dev_priv->drm,
- "initial power sequencer for [ENCODER:%d:%s]: pipe %c\n",
- dig_port->base.base.base.id,
- dig_port->base.base.name,
- pipe_name(intel_dp->pps.pps_pipe));
+ "[ENCODER:%d:%s] initial power sequencer: %s\n",
+ dig_port->base.base.base.id, dig_port->base.base.name,
+ pps_name(dev_priv, &intel_dp->pps));
+}
+
+static int intel_num_pps(struct drm_i915_private *i915)
+{
+ if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915))
+ return 2;
+
+ if (IS_GEMINILAKE(i915) || IS_BROXTON(i915))
+ return 2;
+
+ if (INTEL_PCH_TYPE(i915) >= PCH_DG1)
+ return 1;
+
+ if (INTEL_PCH_TYPE(i915) >= PCH_ICP)
+ return 2;
+
+ return 1;
+}
+
+static bool intel_pps_is_valid(struct intel_dp *intel_dp)
+{
+ struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+
+ if (intel_dp->pps.pps_idx == 1 &&
+ INTEL_PCH_TYPE(i915) >= PCH_ICP &&
+ INTEL_PCH_TYPE(i915) < PCH_MTP)
+ return intel_de_read(i915, SOUTH_CHICKEN1) & ICP_SECOND_PPS_IO_SELECT;
+
+ return true;
+}
+
+static int
+bxt_initial_pps_idx(struct drm_i915_private *i915, pps_check check)
+{
+ int pps_idx, pps_num = intel_num_pps(i915);
+
+ for (pps_idx = 0; pps_idx < pps_num; pps_idx++) {
+ if (check(i915, pps_idx))
+ return pps_idx;
+ }
+
+ return -1;
+}
+
+static bool
+pps_initial_setup(struct intel_dp *intel_dp)
+{
+ struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
+ struct intel_connector *connector = intel_dp->attached_connector;
+ struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+
+ lockdep_assert_held(&i915->display.pps.mutex);
+
+ if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) {
+ vlv_initial_power_sequencer_setup(intel_dp);
+ return true;
+ }
+
+ /* first ask the VBT */
+ if (intel_num_pps(i915) > 1)
+ intel_dp->pps.pps_idx = connector->panel.vbt.backlight.controller;
+ else
+ intel_dp->pps.pps_idx = 0;
+
+ if (drm_WARN_ON(&i915->drm, intel_dp->pps.pps_idx >= intel_num_pps(i915)))
+ intel_dp->pps.pps_idx = -1;
+
+ /* VBT wasn't parsed yet? pick one where the panel is on */
+ if (intel_dp->pps.pps_idx < 0)
+ intel_dp->pps.pps_idx = bxt_initial_pps_idx(i915, pps_has_pp_on);
+ /* didn't find one? pick one where vdd is on */
+ if (intel_dp->pps.pps_idx < 0)
+ intel_dp->pps.pps_idx = bxt_initial_pps_idx(i915, pps_has_vdd_on);
+ /* didn't find one? pick any */
+ if (intel_dp->pps.pps_idx < 0) {
+ intel_dp->pps.pps_idx = bxt_initial_pps_idx(i915, pps_any);
+
+ drm_dbg_kms(&i915->drm,
+ "[ENCODER:%d:%s] no initial power sequencer, assuming %s\n",
+ encoder->base.base.id, encoder->base.name,
+ pps_name(i915, &intel_dp->pps));
+ } else {
+ drm_dbg_kms(&i915->drm,
+ "[ENCODER:%d:%s] initial power sequencer: %s\n",
+ encoder->base.base.id, encoder->base.name,
+ pps_name(i915, &intel_dp->pps));
+ }
+
+ return intel_pps_is_valid(intel_dp);
}
void intel_pps_reset_all(struct drm_i915_private *dev_priv)
@@ -364,14 +478,16 @@ static void intel_pps_get_registers(struct intel_dp *intel_dp,
struct pps_registers *regs)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
- int pps_idx = 0;
+ int pps_idx;
memset(regs, 0, sizeof(*regs));
- if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv))
- pps_idx = bxt_power_sequencer_idx(intel_dp);
- else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
+ if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
pps_idx = vlv_power_sequencer_pipe(intel_dp);
+ else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv))
+ pps_idx = bxt_power_sequencer_idx(intel_dp);
+ else
+ pps_idx = intel_dp->pps.pps_idx;
regs->pp_ctrl = PP_CONTROL(pps_idx);
regs->pp_stat = PP_STATUS(pps_idx);
@@ -435,21 +551,27 @@ static bool edp_have_panel_vdd(struct intel_dp *intel_dp)
void intel_pps_check_power_unlocked(struct intel_dp *intel_dp)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+ struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
if (!intel_dp_is_edp(intel_dp))
return;
if (!edp_have_panel_power(intel_dp) && !edp_have_panel_vdd(intel_dp)) {
drm_WARN(&dev_priv->drm, 1,
- "eDP powered off while attempting aux channel communication.\n");
- drm_dbg_kms(&dev_priv->drm, "Status 0x%08x Control 0x%08x\n",
+ "[ENCODER:%d:%s] %s powered off while attempting AUX CH communication.\n",
+ dig_port->base.base.base.id, dig_port->base.base.name,
+ pps_name(dev_priv, &intel_dp->pps));
+ drm_dbg_kms(&dev_priv->drm,
+ "[ENCODER:%d:%s] %s PP_STATUS: 0x%08x PP_CONTROL: 0x%08x\n",
+ dig_port->base.base.base.id, dig_port->base.base.name,
+ pps_name(dev_priv, &intel_dp->pps),
intel_de_read(dev_priv, _pp_stat_reg(intel_dp)),
intel_de_read(dev_priv, _pp_ctrl_reg(intel_dp)));
}
}
#define IDLE_ON_MASK (PP_ON | PP_SEQUENCE_MASK | 0 | PP_SEQUENCE_STATE_MASK)
-#define IDLE_ON_VALUE (PP_ON | PP_SEQUENCE_NONE | 0 | PP_SEQUENCE_STATE_ON_IDLE)
+#define IDLE_ON_VALUE (PP_ON | PP_SEQUENCE_NONE | 0 | PP_SEQUENCE_STATE_ON_IDLE)
#define IDLE_OFF_MASK (PP_ON | PP_SEQUENCE_MASK | 0 | 0)
#define IDLE_OFF_VALUE (0 | PP_SEQUENCE_NONE | 0 | 0)
@@ -460,10 +582,10 @@ void intel_pps_check_power_unlocked(struct intel_dp *intel_dp)
static void intel_pps_verify_state(struct intel_dp *intel_dp);
static void wait_panel_status(struct intel_dp *intel_dp,
- u32 mask,
- u32 value)
+ u32 mask, u32 value)
{
struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+ struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
i915_reg_t pp_stat_reg, pp_ctrl_reg;
lockdep_assert_held(&dev_priv->display.pps.mutex);
@@ -474,7 +596,9 @@ static void wait_panel_status(struct intel_dp *intel_dp,
pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
drm_dbg_kms(&dev_priv->drm,
- "mask %08x value %08x status %08x control %08x\n",
+ "[ENCODER:%d:%s] %s mask: 0x%08x value: 0x%08x PP_STATUS: 0x%08x PP_CONTROL: 0x%08x\n",
+ dig_port->base.base.base.id, dig_port->base.base.name,
+ pps_name(dev_priv, &intel_dp->pps),
mask, value,
intel_de_read(dev_priv, pp_stat_reg),
intel_de_read(dev_priv, pp_ctrl_reg));
@@ -482,7 +606,9 @@ static void wait_panel_status(struct intel_dp *intel_dp,
if (intel_de_wait_for_register(dev_priv, pp_stat_reg,
mask, value, 5000))
drm_err(&dev_priv->drm,
- "Panel status timeout: status %08x control %08x\n",
+ "[ENCODER:%d:%s] %s panel status timeout: PP_STATUS: 0x%08x PP_CONTROL: 0x%08x\n",
+ dig_port->base.base.base.id, dig_port->base.base.name,
+ pps_name(dev_priv, &intel_dp->pps),
intel_de_read(dev_priv, pp_stat_reg),
intel_de_read(dev_priv, pp_ctrl_reg));
@@ -492,26 +618,35 @@ static void wait_panel_status(struct intel_dp *intel_dp,
static void wait_panel_on(struct intel_dp *intel_dp)
{
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+ struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
- drm_dbg_kms(&i915->drm, "Wait for panel power on\n");
+ drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s] %s wait for panel power on\n",
+ dig_port->base.base.base.id, dig_port->base.base.name,
+ pps_name(i915, &intel_dp->pps));
wait_panel_status(intel_dp, IDLE_ON_MASK, IDLE_ON_VALUE);
}
static void wait_panel_off(struct intel_dp *intel_dp)
{
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+ struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
- drm_dbg_kms(&i915->drm, "Wait for panel power off time\n");
+ drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s] %s wait for panel power off time\n",
+ dig_port->base.base.base.id, dig_port->base.base.name,
+ pps_name(i915, &intel_dp->pps));
wait_panel_status(intel_dp, IDLE_OFF_MASK, IDLE_OFF_VALUE);
}
static void wait_panel_power_cycle(struct intel_dp *intel_dp)
{
struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+ struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
ktime_t panel_power_on_time;
s64 panel_power_off_duration;
- drm_dbg_kms(&i915->drm, "Wait for panel power cycle\n");
+ drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s] %s wait for panel power cycle\n",
+ dig_port->base.base.base.id, dig_port->base.base.name,
+ pps_name(i915, &intel_dp->pps));
/* take the difference of current time and panel power off time
* and then make panel wait for t11_t12 if needed. */
@@ -598,9 +733,12 @@ bool intel_pps_vdd_on_unlocked(struct intel_dp *intel_dp)
intel_dp->pps.vdd_wakeref = intel_display_power_get(dev_priv,
intel_aux_power_domain(dig_port));
- drm_dbg_kms(&dev_priv->drm, "Turning [ENCODER:%d:%s] VDD on\n",
- dig_port->base.base.base.id,
- dig_port->base.base.name);
+ pp_stat_reg = _pp_stat_reg(intel_dp);
+ pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
+
+ drm_dbg_kms(&dev_priv->drm, "[ENCODER:%d:%s] %s turning VDD on\n",
+ dig_port->base.base.base.id, dig_port->base.base.name,
+ pps_name(dev_priv, &intel_dp->pps));
if (!edp_have_panel_power(intel_dp))
wait_panel_power_cycle(intel_dp);
@@ -608,12 +746,11 @@ bool intel_pps_vdd_on_unlocked(struct intel_dp *intel_dp)
pp = ilk_get_pp_control(intel_dp);
pp |= EDP_FORCE_VDD;
- pp_stat_reg = _pp_stat_reg(intel_dp);
- pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
-
intel_de_write(dev_priv, pp_ctrl_reg, pp);
intel_de_posting_read(dev_priv, pp_ctrl_reg);
- drm_dbg_kms(&dev_priv->drm, "PP_STATUS: 0x%08x PP_CONTROL: 0x%08x\n",
+ drm_dbg_kms(&dev_priv->drm, "[ENCODER:%d:%s] %s PP_STATUS: 0x%08x PP_CONTROL: 0x%08x\n",
+ dig_port->base.base.base.id, dig_port->base.base.name,
+ pps_name(dev_priv, &intel_dp->pps),
intel_de_read(dev_priv, pp_stat_reg),
intel_de_read(dev_priv, pp_ctrl_reg));
/*
@@ -621,9 +758,9 @@ bool intel_pps_vdd_on_unlocked(struct intel_dp *intel_dp)
*/
if (!edp_have_panel_power(intel_dp)) {
drm_dbg_kms(&dev_priv->drm,
- "[ENCODER:%d:%s] panel power wasn't enabled\n",
- dig_port->base.base.base.id,
- dig_port->base.base.name);
+ "[ENCODER:%d:%s] %s panel power wasn't enabled\n",
+ dig_port->base.base.base.id, dig_port->base.base.name,
+ pps_name(dev_priv, &intel_dp->pps));
msleep(intel_dp->pps.panel_power_up_delay);
}
@@ -638,6 +775,7 @@ bool intel_pps_vdd_on_unlocked(struct intel_dp *intel_dp)
*/
void intel_pps_vdd_on(struct intel_dp *intel_dp)
{
+ struct drm_i915_private *i915 = dp_to_i915(intel_dp);
intel_wakeref_t wakeref;
bool vdd;
@@ -647,9 +785,10 @@ void intel_pps_vdd_on(struct intel_dp *intel_dp)
vdd = false;
with_intel_pps_lock(intel_dp, wakeref)
vdd = intel_pps_vdd_on_unlocked(intel_dp);
- I915_STATE_WARN(!vdd, "[ENCODER:%d:%s] VDD already requested on\n",
+ I915_STATE_WARN(!vdd, "[ENCODER:%d:%s] %s VDD already requested on\n",
dp_to_dig_port(intel_dp)->base.base.base.id,
- dp_to_dig_port(intel_dp)->base.base.name);
+ dp_to_dig_port(intel_dp)->base.base.name,
+ pps_name(i915, &intel_dp->pps));
}
static void intel_pps_vdd_off_sync_unlocked(struct intel_dp *intel_dp)
@@ -667,9 +806,9 @@ static void intel_pps_vdd_off_sync_unlocked(struct intel_dp *intel_dp)
if (!edp_have_panel_vdd(intel_dp))
return;
- drm_dbg_kms(&dev_priv->drm, "Turning [ENCODER:%d:%s] VDD off\n",
- dig_port->base.base.base.id,
- dig_port->base.base.name);
+ drm_dbg_kms(&dev_priv->drm, "[ENCODER:%d:%s] %s turning VDD off\n",
+ dig_port->base.base.base.id, dig_port->base.base.name,
+ pps_name(dev_priv, &intel_dp->pps));
pp = ilk_get_pp_control(intel_dp);
pp &= ~EDP_FORCE_VDD;
@@ -681,7 +820,9 @@ static void intel_pps_vdd_off_sync_unlocked(struct intel_dp *intel_dp)
intel_de_posting_read(dev_priv, pp_ctrl_reg);
/* Make sure sequencer is idle before allowing subsequent activity */
- drm_dbg_kms(&dev_priv->drm, "PP_STATUS: 0x%08x PP_CONTROL: 0x%08x\n",
+ drm_dbg_kms(&dev_priv->drm, "[ENCODER:%d:%s] %s PP_STATUS: 0x%08x PP_CONTROL: 0x%08x\n",
+ dig_port->base.base.base.id, dig_port->base.base.name,
+ pps_name(dev_priv, &intel_dp->pps),
intel_de_read(dev_priv, pp_stat_reg),
intel_de_read(dev_priv, pp_ctrl_reg));
@@ -756,9 +897,10 @@ void intel_pps_vdd_off_unlocked(struct intel_dp *intel_dp, bool sync)
if (!intel_dp_is_edp(intel_dp))
return;
- I915_STATE_WARN(!intel_dp->pps.want_panel_vdd, "[ENCODER:%d:%s] VDD not forced on",
+ I915_STATE_WARN(!intel_dp->pps.want_panel_vdd, "[ENCODER:%d:%s] %s VDD not forced on",
dp_to_dig_port(intel_dp)->base.base.base.id,
- dp_to_dig_port(intel_dp)->base.base.name);
+ dp_to_dig_port(intel_dp)->base.base.name,
+ pps_name(dev_priv, &intel_dp->pps));
intel_dp->pps.want_panel_vdd = false;
@@ -779,14 +921,16 @@ void intel_pps_on_unlocked(struct intel_dp *intel_dp)
if (!intel_dp_is_edp(intel_dp))
return;
- drm_dbg_kms(&dev_priv->drm, "Turn [ENCODER:%d:%s] panel power on\n",
+ drm_dbg_kms(&dev_priv->drm, "[ENCODER:%d:%s] %s turn panel power on\n",
dp_to_dig_port(intel_dp)->base.base.base.id,
- dp_to_dig_port(intel_dp)->base.base.name);
+ dp_to_dig_port(intel_dp)->base.base.name,
+ pps_name(dev_priv, &intel_dp->pps));
if (drm_WARN(&dev_priv->drm, edp_have_panel_power(intel_dp),
- "[ENCODER:%d:%s] panel power already on\n",
+ "[ENCODER:%d:%s] %s panel power already on\n",
dp_to_dig_port(intel_dp)->base.base.base.id,
- dp_to_dig_port(intel_dp)->base.base.name))
+ dp_to_dig_port(intel_dp)->base.base.name,
+ pps_name(dev_priv, &intel_dp->pps)))
return;
wait_panel_power_cycle(intel_dp);
@@ -840,12 +984,14 @@ void intel_pps_off_unlocked(struct intel_dp *intel_dp)
if (!intel_dp_is_edp(intel_dp))
return;
- drm_dbg_kms(&dev_priv->drm, "Turn [ENCODER:%d:%s] panel power off\n",
- dig_port->base.base.base.id, dig_port->base.base.name);
+ drm_dbg_kms(&dev_priv->drm, "[ENCODER:%d:%s] %s turn panel power off\n",
+ dig_port->base.base.base.id, dig_port->base.base.name,
+ pps_name(dev_priv, &intel_dp->pps));
drm_WARN(&dev_priv->drm, !intel_dp->pps.want_panel_vdd,
- "Need [ENCODER:%d:%s] VDD to turn off panel\n",
- dig_port->base.base.base.id, dig_port->base.base.name);
+ "[ENCODER:%d:%s] %s need VDD to turn off panel\n",
+ dig_port->base.base.base.id, dig_port->base.base.name,
+ pps_name(dev_priv, &intel_dp->pps));
pp = ilk_get_pp_control(intel_dp);
/* We need to switch off panel power _and_ force vdd, for otherwise some
@@ -980,9 +1126,9 @@ static void vlv_detach_power_sequencer(struct intel_dp *intel_dp)
* from a port.
*/
drm_dbg_kms(&dev_priv->drm,
- "detaching pipe %c power sequencer from [ENCODER:%d:%s]\n",
- pipe_name(pipe), dig_port->base.base.base.id,
- dig_port->base.base.name);
+ "detaching %s from [ENCODER:%d:%s]\n",
+ pps_name(dev_priv, &intel_dp->pps),
+ dig_port->base.base.base.id, dig_port->base.base.name);
intel_de_write(dev_priv, pp_on_reg, 0);
intel_de_posting_read(dev_priv, pp_on_reg);
@@ -1000,7 +1146,7 @@ static void vlv_steal_power_sequencer(struct drm_i915_private *dev_priv,
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
drm_WARN(&dev_priv->drm, intel_dp->pps.active_pipe == pipe,
- "stealing pipe %c power sequencer from active [ENCODER:%d:%s]\n",
+ "stealing PPS %c from active [ENCODER:%d:%s]\n",
pipe_name(pipe), encoder->base.base.id,
encoder->base.name);
@@ -1008,7 +1154,7 @@ static void vlv_steal_power_sequencer(struct drm_i915_private *dev_priv,
continue;
drm_dbg_kms(&dev_priv->drm,
- "stealing pipe %c power sequencer from [ENCODER:%d:%s]\n",
+ "stealing PPS %c from [ENCODER:%d:%s]\n",
pipe_name(pipe), encoder->base.base.id,
encoder->base.name);
@@ -1053,9 +1199,9 @@ void vlv_pps_init(struct intel_encoder *encoder,
intel_dp->pps.pps_pipe = crtc->pipe;
drm_dbg_kms(&dev_priv->drm,
- "initializing pipe %c power sequencer for [ENCODER:%d:%s]\n",
- pipe_name(intel_dp->pps.pps_pipe), encoder->base.base.id,
- encoder->base.name);
+ "initializing %s for [ENCODER:%d:%s]\n",
+ pps_name(dev_priv, &intel_dp->pps),
+ encoder->base.base.id, encoder->base.name);
/* init power sequencer on this pipe and port */
pps_init_delays(intel_dp);
@@ -1079,7 +1225,9 @@ static void pps_vdd_init(struct intel_dp *intel_dp)
* indefinitely.
*/
drm_dbg_kms(&dev_priv->drm,
- "VDD left on by BIOS, adjusting state tracking\n");
+ "[ENCODER:%d:%s] %s VDD left on by BIOS, adjusting state tracking\n",
+ dig_port->base.base.base.id, dig_port->base.base.name,
+ pps_name(dev_priv, &intel_dp->pps));
drm_WARN_ON(&dev_priv->drm, intel_dp->pps.vdd_wakeref);
intel_dp->pps.vdd_wakeref = intel_display_power_get(dev_priv,
intel_aux_power_domain(dig_port));
@@ -1432,10 +1580,10 @@ void intel_pps_encoder_reset(struct intel_dp *intel_dp)
}
}
-void intel_pps_init(struct intel_dp *intel_dp)
+bool intel_pps_init(struct intel_dp *intel_dp)
{
- struct drm_i915_private *i915 = dp_to_i915(intel_dp);
intel_wakeref_t wakeref;
+ bool ret;
intel_dp->pps.initializing = true;
INIT_DELAYED_WORK(&intel_dp->pps.panel_vdd_work, edp_panel_vdd_work);
@@ -1443,13 +1591,36 @@ void intel_pps_init(struct intel_dp *intel_dp)
pps_init_timestamps(intel_dp);
with_intel_pps_lock(intel_dp, wakeref) {
- if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915))
- vlv_initial_power_sequencer_setup(intel_dp);
+ ret = pps_initial_setup(intel_dp);
pps_init_delays(intel_dp);
pps_init_registers(intel_dp, false);
pps_vdd_init(intel_dp);
}
+
+ return ret;
+}
+
+static void pps_init_late(struct intel_dp *intel_dp)
+{
+ struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+ struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
+ struct intel_connector *connector = intel_dp->attached_connector;
+
+ if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915))
+ return;
+
+ if (intel_num_pps(i915) < 2)
+ return;
+
+ drm_WARN(&i915->drm, connector->panel.vbt.backlight.controller >= 0 &&
+ intel_dp->pps.pps_idx != connector->panel.vbt.backlight.controller,
+ "[ENCODER:%d:%s] power sequencer mismatch: %d (initial) vs. %d (VBT)\n",
+ encoder->base.base.id, encoder->base.name,
+ intel_dp->pps.pps_idx, connector->panel.vbt.backlight.controller);
+
+ if (connector->panel.vbt.backlight.controller >= 0)
+ intel_dp->pps.pps_idx = connector->panel.vbt.backlight.controller;
}
void intel_pps_init_late(struct intel_dp *intel_dp)
@@ -1458,6 +1629,8 @@ void intel_pps_init_late(struct intel_dp *intel_dp)
with_intel_pps_lock(intel_dp, wakeref) {
/* Reinit delays after per-panel info has been parsed from VBT */
+ pps_init_late(intel_dp);
+
memset(&intel_dp->pps.pps_delays, 0, sizeof(intel_dp->pps.pps_delays));
pps_init_delays(intel_dp);
pps_init_registers(intel_dp, false);
@@ -1480,10 +1653,7 @@ void intel_pps_unlock_regs_wa(struct drm_i915_private *dev_priv)
* This w/a is needed at least on CPT/PPT, but to be sure apply it
* everywhere where registers can be write protected.
*/
- if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
- pps_num = 2;
- else
- pps_num = 1;
+ pps_num = intel_num_pps(dev_priv);
for (pps_idx = 0; pps_idx < pps_num; pps_idx++) {
u32 val = intel_de_read(dev_priv, PP_CONTROL(pps_idx));
diff --git a/drivers/gpu/drm/i915/display/intel_pps.h b/drivers/gpu/drm/i915/display/intel_pps.h
index a3a56f903f26..a2c2467e3c22 100644
--- a/drivers/gpu/drm/i915/display/intel_pps.h
+++ b/drivers/gpu/drm/i915/display/intel_pps.h
@@ -40,7 +40,7 @@ void intel_pps_vdd_off_sync(struct intel_dp *intel_dp);
bool intel_pps_have_panel_power_or_vdd(struct intel_dp *intel_dp);
void intel_pps_wait_power_cycle(struct intel_dp *intel_dp);
-void intel_pps_init(struct intel_dp *intel_dp);
+bool intel_pps_init(struct intel_dp *intel_dp);
void intel_pps_init_late(struct intel_dp *intel_dp);
void intel_pps_encoder_reset(struct intel_dp *intel_dp);
void intel_pps_reset_all(struct drm_i915_private *i915);
diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c
index 5b678916e6db..7a72e15e6836 100644
--- a/drivers/gpu/drm/i915/display/intel_psr.c
+++ b/drivers/gpu/drm/i915/display/intel_psr.c
@@ -24,14 +24,13 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_damage_helper.h>
-#include "display/intel_dp.h"
-
#include "i915_drv.h"
#include "i915_reg.h"
#include "intel_atomic.h"
#include "intel_crtc.h"
#include "intel_de.h"
#include "intel_display_types.h"
+#include "intel_dp.h"
#include "intel_dp_aux.h"
#include "intel_hdmi.h"
#include "intel_psr.h"
@@ -797,7 +796,7 @@ static bool psr2_granularity_check(struct intel_dp *intel_dp,
return intel_dp->psr.su_y_granularity == 4;
/*
- * adl_p and display 14+ platforms has 1 line granularity.
+ * adl_p and mtl platforms have 1 line granularity.
* For other platforms with SW tracking we can adjust the y coordinates
* to match sink requirement if multiple of 4.
*/
@@ -1112,6 +1111,8 @@ static u32 wa_16013835468_bit_get(struct intel_dp *intel_dp)
return LATENCY_REPORTING_REMOVED_PIPE_B;
case PIPE_C:
return LATENCY_REPORTING_REMOVED_PIPE_C;
+ case PIPE_D:
+ return LATENCY_REPORTING_REMOVED_PIPE_D;
default:
MISSING_CASE(intel_dp->psr.pipe);
return 0;
@@ -1163,6 +1164,23 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp,
intel_dp->psr.psr2_sel_fetch_enabled ?
IGNORE_PSR2_HW_TRACKING : 0);
+ /*
+ * Wa_16013835468
+ * Wa_14015648006
+ */
+ if (IS_MTL_DISPLAY_STEP(dev_priv, STEP_A0, STEP_B0) ||
+ IS_DISPLAY_VER(dev_priv, 12, 13)) {
+ u16 vtotal, vblank;
+
+ vtotal = crtc_state->uapi.adjusted_mode.crtc_vtotal -
+ crtc_state->uapi.adjusted_mode.crtc_vdisplay;
+ vblank = crtc_state->uapi.adjusted_mode.crtc_vblank_end -
+ crtc_state->uapi.adjusted_mode.crtc_vblank_start;
+ if (vblank > vtotal)
+ intel_de_rmw(dev_priv, GEN8_CHICKEN_DCPR_1, 0,
+ wa_16013835468_bit_get(intel_dp));
+ }
+
if (intel_dp->psr.psr2_enabled) {
if (DISPLAY_VER(dev_priv) == 9)
intel_de_rmw(dev_priv, CHICKEN_TRANS(cpu_transcoder), 0,
@@ -1170,11 +1188,14 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp,
PSR2_ADD_VERTICAL_LINE_COUNT);
/*
- * Wa_16014451276:adlp
+ * Wa_16014451276:adlp,mtl[a0,b0]
* All supported adlp panels have 1-based X granularity, this may
* cause issues if non-supported panels are used.
*/
- if (IS_ALDERLAKE_P(dev_priv))
+ if (IS_MTL_DISPLAY_STEP(dev_priv, STEP_A0, STEP_B0))
+ intel_de_rmw(dev_priv, MTL_CHICKEN_TRANS(cpu_transcoder), 0,
+ ADLP_1_BASED_X_GRANULARITY);
+ else if (IS_ALDERLAKE_P(dev_priv))
intel_de_rmw(dev_priv, CHICKEN_TRANS(cpu_transcoder), 0,
ADLP_1_BASED_X_GRANULARITY);
@@ -1185,24 +1206,14 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp,
TRANS_SET_CONTEXT_LATENCY_MASK,
TRANS_SET_CONTEXT_LATENCY_VALUE(1));
- /* Wa_16012604467:adlp */
- if (IS_ALDERLAKE_P(dev_priv))
+ /* Wa_16012604467:adlp,mtl[a0,b0] */
+ if (IS_MTL_DISPLAY_STEP(dev_priv, STEP_A0, STEP_B0))
+ intel_de_rmw(dev_priv,
+ MTL_CLKGATE_DIS_TRANS(cpu_transcoder), 0,
+ MTL_CLKGATE_DIS_TRANS_DMASC_GATING_DIS);
+ else if (IS_ALDERLAKE_P(dev_priv))
intel_de_rmw(dev_priv, CLKGATE_DIS_MISC, 0,
CLKGATE_DIS_MISC_DMASC_GATING_DIS);
-
- /* Wa_16013835468:tgl[b0+], dg1 */
- if (IS_TGL_DISPLAY_STEP(dev_priv, STEP_B0, STEP_FOREVER) ||
- IS_DG1(dev_priv)) {
- u16 vtotal, vblank;
-
- vtotal = crtc_state->uapi.adjusted_mode.crtc_vtotal -
- crtc_state->uapi.adjusted_mode.crtc_vdisplay;
- vblank = crtc_state->uapi.adjusted_mode.crtc_vblank_end -
- crtc_state->uapi.adjusted_mode.crtc_vblank_start;
- if (vblank > vtotal)
- intel_de_rmw(dev_priv, GEN8_CHICKEN_DCPR_1, 0,
- wa_16013835468_bit_get(intel_dp));
- }
}
}
@@ -1355,6 +1366,15 @@ static void intel_psr_disable_locked(struct intel_dp *intel_dp)
intel_de_rmw(dev_priv, CHICKEN_PAR1_1,
DIS_RAM_BYPASS_PSR2_MAN_TRACK, 0);
+ /*
+ * Wa_16013835468
+ * Wa_14015648006
+ */
+ if (IS_MTL_DISPLAY_STEP(dev_priv, STEP_A0, STEP_B0) ||
+ IS_DISPLAY_VER(dev_priv, 12, 13))
+ intel_de_rmw(dev_priv, GEN8_CHICKEN_DCPR_1,
+ wa_16013835468_bit_get(intel_dp), 0);
+
if (intel_dp->psr.psr2_enabled) {
/* Wa_16011168373:adl-p */
if (IS_ADLP_DISPLAY_STEP(dev_priv, STEP_A0, STEP_B0))
@@ -1362,16 +1382,14 @@ static void intel_psr_disable_locked(struct intel_dp *intel_dp)
TRANS_SET_CONTEXT_LATENCY(intel_dp->psr.transcoder),
TRANS_SET_CONTEXT_LATENCY_MASK, 0);
- /* Wa_16012604467:adlp */
- if (IS_ALDERLAKE_P(dev_priv))
+ /* Wa_16012604467:adlp,mtl[a0,b0] */
+ if (IS_MTL_DISPLAY_STEP(dev_priv, STEP_A0, STEP_B0))
+ intel_de_rmw(dev_priv,
+ MTL_CLKGATE_DIS_TRANS(intel_dp->psr.transcoder),
+ MTL_CLKGATE_DIS_TRANS_DMASC_GATING_DIS, 0);
+ else if (IS_ALDERLAKE_P(dev_priv))
intel_de_rmw(dev_priv, CLKGATE_DIS_MISC,
CLKGATE_DIS_MISC_DMASC_GATING_DIS, 0);
-
- /* Wa_16013835468:tgl[b0+], dg1 */
- if (IS_TGL_DISPLAY_STEP(dev_priv, STEP_B0, STEP_FOREVER) ||
- IS_DG1(dev_priv))
- intel_de_rmw(dev_priv, GEN8_CHICKEN_DCPR_1,
- wa_16013835468_bit_get(intel_dp), 0);
}
intel_snps_phy_update_psr_power_state(dev_priv, phy, false);
@@ -1510,7 +1528,8 @@ static void psr_force_hw_tracking_exit(struct intel_dp *intel_dp)
PSR2_MAN_TRK_CTL(intel_dp->psr.transcoder),
man_trk_ctl_enable_bit_get(dev_priv) |
man_trk_ctl_partial_frame_bit_get(dev_priv) |
- man_trk_ctl_single_full_frame_bit_get(dev_priv));
+ man_trk_ctl_single_full_frame_bit_get(dev_priv) |
+ man_trk_ctl_continuos_full_frame(dev_priv));
/*
* Display WA #0884: skl+
@@ -1624,11 +1643,8 @@ static void psr2_man_trk_ctl_calc(struct intel_crtc_state *crtc_state,
val |= man_trk_ctl_partial_frame_bit_get(dev_priv);
if (full_update) {
- /*
- * Not applying Wa_14014971508:adlp as we do not support the
- * feature that requires this workaround.
- */
val |= man_trk_ctl_single_full_frame_bit_get(dev_priv);
+ val |= man_trk_ctl_continuos_full_frame(dev_priv);
goto exit;
}
@@ -1826,6 +1842,12 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
if (full_update)
goto skip_sel_fetch_set_loop;
+ /* Wa_14014971492 */
+ if ((IS_MTL_DISPLAY_STEP(dev_priv, STEP_A0, STEP_B0) ||
+ IS_ALDERLAKE_P(dev_priv) || IS_TIGERLAKE(dev_priv)) &&
+ crtc_state->splitter.enable)
+ pipe_clip.y1 = 0;
+
ret = drm_atomic_add_affected_planes(&state->base, &crtc->base);
if (ret)
return ret;
@@ -2307,12 +2329,15 @@ static void _psr_flush_handle(struct intel_dp *intel_dp)
/* can we turn CFF off? */
if (intel_dp->psr.busy_frontbuffer_bits == 0) {
u32 val = man_trk_ctl_enable_bit_get(dev_priv) |
- man_trk_ctl_partial_frame_bit_get(dev_priv) |
- man_trk_ctl_single_full_frame_bit_get(dev_priv);
+ man_trk_ctl_partial_frame_bit_get(dev_priv) |
+ man_trk_ctl_single_full_frame_bit_get(dev_priv) |
+ man_trk_ctl_continuos_full_frame(dev_priv);
/*
- * turn continuous full frame off and do a single
- * full frame
+ * Set psr2_sel_fetch_cff_enabled as false to allow selective
+ * updates. Still keep cff bit enabled as we don't have proper
+ * SU configuration in case update is sent for any reason after
+ * sff bit gets cleared by the HW on next vblank.
*/
intel_de_write(dev_priv, PSR2_MAN_TRK_CTL(intel_dp->psr.transcoder),
val);
diff --git a/drivers/gpu/drm/i915/display/intel_quirks.c b/drivers/gpu/drm/i915/display/intel_quirks.c
index 6e48d3bcdfec..a280448df771 100644
--- a/drivers/gpu/drm/i915/display/intel_quirks.c
+++ b/drivers/gpu/drm/i915/display/intel_quirks.c
@@ -199,6 +199,8 @@ static struct intel_quirk intel_quirks[] = {
/* ECS Liva Q2 */
{ 0x3185, 0x1019, 0xa94d, quirk_increase_ddi_disabled_time },
{ 0x3184, 0x1019, 0xa94d, quirk_increase_ddi_disabled_time },
+ /* HP Notebook - 14-r206nv */
+ { 0x0f31, 0x103c, 0x220f, quirk_invert_brightness },
};
void intel_init_quirks(struct drm_i915_private *i915)
diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c
index 329b9d9af667..e12ba458636c 100644
--- a/drivers/gpu/drm/i915/display/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/display/intel_sdvo.c
@@ -39,6 +39,7 @@
#include "i915_drv.h"
#include "i915_reg.h"
#include "intel_atomic.h"
+#include "intel_audio.h"
#include "intel_connector.h"
#include "intel_crtc.h"
#include "intel_de.h"
@@ -1068,7 +1069,8 @@ static ssize_t intel_sdvo_read_infoframe(struct intel_sdvo *intel_sdvo,
&tx_rate, 1))
return -ENXIO;
- if (tx_rate == SDVO_HBUF_TX_DISABLED)
+ /* TX_DISABLED doesn't mean disabled for ELD */
+ if (if_index != SDVO_HBUF_INDEX_ELD && tx_rate == SDVO_HBUF_TX_DISABLED)
return 0;
if (!intel_sdvo_get_hbuf_size(intel_sdvo, &hbuf_size))
@@ -1185,6 +1187,28 @@ static void intel_sdvo_get_avi_infoframe(struct intel_sdvo *intel_sdvo,
frame->any.type, HDMI_INFOFRAME_TYPE_AVI);
}
+static void intel_sdvo_get_eld(struct intel_sdvo *intel_sdvo,
+ struct intel_crtc_state *crtc_state)
+{
+ struct drm_i915_private *i915 = to_i915(intel_sdvo->base.base.dev);
+ ssize_t len;
+ u8 val;
+
+ if (!crtc_state->has_audio)
+ return;
+
+ if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_AUDIO_STAT, &val, 1))
+ return;
+
+ if ((val & SDVO_AUDIO_ELD_VALID) == 0)
+ return;
+
+ len = intel_sdvo_read_infoframe(intel_sdvo, SDVO_HBUF_INDEX_ELD,
+ crtc_state->eld, sizeof(crtc_state->eld));
+ if (len < 0)
+ drm_dbg_kms(&i915->drm, "failed to read ELD\n");
+}
+
static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo,
const struct drm_connector_state *conn_state)
{
@@ -1378,7 +1402,9 @@ static int intel_sdvo_compute_config(struct intel_encoder *encoder,
pipe_config->has_hdmi_sink = intel_has_hdmi_sink(intel_sdvo, conn_state);
- pipe_config->has_audio = intel_sdvo_has_audio(encoder, pipe_config, conn_state);
+ pipe_config->has_audio =
+ intel_sdvo_has_audio(encoder, pipe_config, conn_state) &&
+ intel_audio_compute_config(encoder, pipe_config, conn_state);
pipe_config->limited_color_range =
intel_sdvo_limited_color_range(encoder, pipe_config,
@@ -1729,9 +1755,7 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder,
if (intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_AUDIO_STAT,
&val, 1)) {
- u8 mask = SDVO_AUDIO_ELD_VALID | SDVO_AUDIO_PRESENCE_DETECT;
-
- if ((val & mask) == mask)
+ if (val & SDVO_AUDIO_PRESENCE_DETECT)
pipe_config->has_audio = true;
}
@@ -1742,6 +1766,8 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder,
}
intel_sdvo_get_avi_infoframe(intel_sdvo, pipe_config);
+
+ intel_sdvo_get_eld(intel_sdvo, pipe_config);
}
static void intel_sdvo_disable_audio(struct intel_sdvo *intel_sdvo)
@@ -1753,12 +1779,7 @@ static void intel_sdvo_enable_audio(struct intel_sdvo *intel_sdvo,
const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state)
{
- const struct drm_display_mode *adjusted_mode =
- &crtc_state->hw.adjusted_mode;
- struct drm_connector *connector = conn_state->connector;
- u8 *eld = connector->eld;
-
- eld[6] = drm_av_sync_delay(connector, adjusted_mode) / 2;
+ const u8 *eld = crtc_state->eld;
intel_sdvo_set_audio_state(intel_sdvo, 0);
@@ -2886,7 +2907,7 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, u16 type)
if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
goto err;
- intel_bios_init_panel(i915, &intel_connector->panel, NULL, NULL);
+ intel_bios_init_panel_late(i915, &intel_connector->panel, NULL, NULL);
/*
* Fetch modes from VBT. For SDVO prefer the VBT mode since some
@@ -2903,7 +2924,7 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, u16 type)
mutex_unlock(&i915->drm.mode_config.mutex);
}
- intel_panel_init(intel_connector);
+ intel_panel_init(intel_connector, NULL);
if (!intel_panel_preferred_fixed_mode(intel_connector))
goto err;
diff --git a/drivers/gpu/drm/i915/display/intel_snps_phy.c b/drivers/gpu/drm/i915/display/intel_snps_phy.c
index c799e891f8b5..c65c771f5c46 100644
--- a/drivers/gpu/drm/i915/display/intel_snps_phy.c
+++ b/drivers/gpu/drm/i915/display/intel_snps_phy.c
@@ -40,22 +40,22 @@ void intel_snps_phy_wait_for_calibration(struct drm_i915_private *i915)
*/
if (intel_de_wait_for_clear(i915, DG2_PHY_MISC(phy),
DG2_PHY_DP_TX_ACK_MASK, 25))
- i915->snps_phy_failed_calibration |= BIT(phy);
+ i915->display.snps.phy_failed_calibration |= BIT(phy);
}
}
-void intel_snps_phy_update_psr_power_state(struct drm_i915_private *dev_priv,
+void intel_snps_phy_update_psr_power_state(struct drm_i915_private *i915,
enum phy phy, bool enable)
{
u32 val;
- if (!intel_phy_is_snps(dev_priv, phy))
+ if (!intel_phy_is_snps(i915, phy))
return;
val = REG_FIELD_PREP(SNPS_PHY_TX_REQ_LN_DIS_PWR_STATE_PSR,
enable ? 2 : 3);
- intel_uncore_rmw(&dev_priv->uncore, SNPS_PHY_TX_REQ(phy),
- SNPS_PHY_TX_REQ_LN_DIS_PWR_STATE_PSR, val);
+ intel_de_rmw(i915, SNPS_PHY_TX_REQ(phy),
+ SNPS_PHY_TX_REQ_LN_DIS_PWR_STATE_PSR, val);
}
void intel_snps_phy_set_signal_levels(struct intel_encoder *encoder,
@@ -1785,7 +1785,7 @@ void intel_mpllb_enable(struct intel_encoder *encoder,
*/
/* 5. Software sets DPLL_ENABLE [PLL Enable] to "1". */
- intel_uncore_rmw(&dev_priv->uncore, enable_reg, 0, PLL_ENABLE);
+ intel_de_rmw(dev_priv, enable_reg, 0, PLL_ENABLE);
/*
* 9. Software sets SNPS_PHY_MPLLB_DIV dp_mpllb_force_en to "1". This
@@ -1830,14 +1830,13 @@ void intel_mpllb_disable(struct intel_encoder *encoder)
*/
/* 2. Software programs DPLL_ENABLE [PLL Enable] to "0" */
- intel_uncore_rmw(&i915->uncore, enable_reg, PLL_ENABLE, 0);
+ intel_de_rmw(i915, enable_reg, PLL_ENABLE, 0);
/*
* 4. Software programs SNPS_PHY_MPLLB_DIV dp_mpllb_force_en to "0".
* This will allow the PLL to stop running.
*/
- intel_uncore_rmw(&i915->uncore, SNPS_PHY_MPLLB_DIV(phy),
- SNPS_PHY_MPLLB_FORCE_EN, 0);
+ intel_de_rmw(i915, SNPS_PHY_MPLLB_DIV(phy), SNPS_PHY_MPLLB_FORCE_EN, 0);
/*
* 5. Software polls DPLL_ENABLE [PLL Lock] for PHY acknowledgment
diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c
index 70624b4b2d38..f45328712bff 100644
--- a/drivers/gpu/drm/i915/display/intel_tc.c
+++ b/drivers/gpu/drm/i915/display/intel_tc.c
@@ -5,6 +5,7 @@
#include "i915_drv.h"
#include "i915_reg.h"
+#include "intel_de.h"
#include "intel_display.h"
#include "intel_display_power_map.h"
#include "intel_display_types.h"
@@ -120,11 +121,9 @@ assert_tc_cold_blocked(struct intel_digital_port *dig_port)
u32 intel_tc_port_get_lane_mask(struct intel_digital_port *dig_port)
{
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
- struct intel_uncore *uncore = &i915->uncore;
u32 lane_mask;
- lane_mask = intel_uncore_read(uncore,
- PORT_TX_DFLEXDPSP(dig_port->tc_phy_fia));
+ lane_mask = intel_de_read(i915, PORT_TX_DFLEXDPSP(dig_port->tc_phy_fia));
drm_WARN_ON(&i915->drm, lane_mask == 0xffffffff);
assert_tc_cold_blocked(dig_port);
@@ -136,11 +135,9 @@ u32 intel_tc_port_get_lane_mask(struct intel_digital_port *dig_port)
u32 intel_tc_port_get_pin_assignment_mask(struct intel_digital_port *dig_port)
{
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
- struct intel_uncore *uncore = &i915->uncore;
u32 pin_mask;
- pin_mask = intel_uncore_read(uncore,
- PORT_TX_DFLEXPA1(dig_port->tc_phy_fia));
+ pin_mask = intel_de_read(i915, PORT_TX_DFLEXPA1(dig_port->tc_phy_fia));
drm_WARN_ON(&i915->drm, pin_mask == 0xffffffff);
assert_tc_cold_blocked(dig_port);
@@ -186,7 +183,6 @@ void intel_tc_port_set_fia_lane_count(struct intel_digital_port *dig_port,
{
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
bool lane_reversal = dig_port->saved_port_bits & DDI_BUF_PORT_REVERSAL;
- struct intel_uncore *uncore = &i915->uncore;
u32 val;
drm_WARN_ON(&i915->drm,
@@ -194,8 +190,7 @@ void intel_tc_port_set_fia_lane_count(struct intel_digital_port *dig_port,
assert_tc_cold_blocked(dig_port);
- val = intel_uncore_read(uncore,
- PORT_TX_DFLEXDPMLE1(dig_port->tc_phy_fia));
+ val = intel_de_read(i915, PORT_TX_DFLEXDPMLE1(dig_port->tc_phy_fia));
val &= ~DFLEXDPMLE1_DPMLETC_MASK(dig_port->tc_phy_fia_idx);
switch (required_lanes) {
@@ -216,8 +211,7 @@ void intel_tc_port_set_fia_lane_count(struct intel_digital_port *dig_port,
MISSING_CASE(required_lanes);
}
- intel_uncore_write(uncore,
- PORT_TX_DFLEXDPMLE1(dig_port->tc_phy_fia), val);
+ intel_de_write(i915, PORT_TX_DFLEXDPMLE1(dig_port->tc_phy_fia), val);
}
static void tc_port_fixup_legacy_flag(struct intel_digital_port *dig_port,
@@ -246,13 +240,11 @@ static void tc_port_fixup_legacy_flag(struct intel_digital_port *dig_port,
static u32 icl_tc_port_live_status_mask(struct intel_digital_port *dig_port)
{
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
- struct intel_uncore *uncore = &i915->uncore;
u32 isr_bit = i915->display.hotplug.pch_hpd[dig_port->base.hpd_pin];
u32 mask = 0;
u32 val;
- val = intel_uncore_read(uncore,
- PORT_TX_DFLEXDPSP(dig_port->tc_phy_fia));
+ val = intel_de_read(i915, PORT_TX_DFLEXDPSP(dig_port->tc_phy_fia));
if (val == 0xffffffff) {
drm_dbg_kms(&i915->drm,
@@ -266,7 +258,7 @@ static u32 icl_tc_port_live_status_mask(struct intel_digital_port *dig_port)
if (val & TC_LIVE_STATE_TC(dig_port->tc_phy_fia_idx))
mask |= BIT(TC_PORT_DP_ALT);
- if (intel_uncore_read(uncore, SDEISR) & isr_bit)
+ if (intel_de_read(i915, SDEISR) & isr_bit)
mask |= BIT(TC_PORT_LEGACY);
/* The sink can be connected only in a single mode. */
@@ -281,7 +273,6 @@ static u32 adl_tc_port_live_status_mask(struct intel_digital_port *dig_port)
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
enum tc_port tc_port = intel_port_to_tc(i915, dig_port->base.port);
u32 isr_bit = i915->display.hotplug.pch_hpd[dig_port->base.hpd_pin];
- struct intel_uncore *uncore = &i915->uncore;
u32 val, mask = 0;
/*
@@ -289,13 +280,13 @@ static u32 adl_tc_port_live_status_mask(struct intel_digital_port *dig_port)
* registers in IOM. Note that this doesn't apply to PHY and FIA
* registers.
*/
- val = intel_uncore_read(uncore, TCSS_DDI_STATUS(tc_port));
+ val = intel_de_read(i915, TCSS_DDI_STATUS(tc_port));
if (val & TCSS_DDI_STATUS_HPD_LIVE_STATUS_ALT)
mask |= BIT(TC_PORT_DP_ALT);
if (val & TCSS_DDI_STATUS_HPD_LIVE_STATUS_TBT)
mask |= BIT(TC_PORT_TBT_ALT);
- if (intel_uncore_read(uncore, SDEISR) & isr_bit)
+ if (intel_de_read(i915, SDEISR) & isr_bit)
mask |= BIT(TC_PORT_LEGACY);
/* The sink can be connected only in a single mode. */
@@ -326,11 +317,9 @@ static u32 tc_port_live_status_mask(struct intel_digital_port *dig_port)
static bool icl_tc_phy_status_complete(struct intel_digital_port *dig_port)
{
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
- struct intel_uncore *uncore = &i915->uncore;
u32 val;
- val = intel_uncore_read(uncore,
- PORT_TX_DFLEXDPPMS(dig_port->tc_phy_fia));
+ val = intel_de_read(i915, PORT_TX_DFLEXDPPMS(dig_port->tc_phy_fia));
if (val == 0xffffffff) {
drm_dbg_kms(&i915->drm,
"Port %s: PHY in TCCOLD, assuming not complete\n",
@@ -352,10 +341,9 @@ static bool adl_tc_phy_status_complete(struct intel_digital_port *dig_port)
{
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
enum tc_port tc_port = intel_port_to_tc(i915, dig_port->base.port);
- struct intel_uncore *uncore = &i915->uncore;
u32 val;
- val = intel_uncore_read(uncore, TCSS_DDI_STATUS(tc_port));
+ val = intel_de_read(i915, TCSS_DDI_STATUS(tc_port));
if (val == 0xffffffff) {
drm_dbg_kms(&i915->drm,
"Port %s: PHY in TCCOLD, assuming not complete\n",
@@ -380,11 +368,9 @@ static bool icl_tc_phy_take_ownership(struct intel_digital_port *dig_port,
bool take)
{
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
- struct intel_uncore *uncore = &i915->uncore;
u32 val;
- val = intel_uncore_read(uncore,
- PORT_TX_DFLEXDPCSSS(dig_port->tc_phy_fia));
+ val = intel_de_read(i915, PORT_TX_DFLEXDPCSSS(dig_port->tc_phy_fia));
if (val == 0xffffffff) {
drm_dbg_kms(&i915->drm,
"Port %s: PHY in TCCOLD, can't %s ownership\n",
@@ -397,8 +383,7 @@ static bool icl_tc_phy_take_ownership(struct intel_digital_port *dig_port,
if (take)
val |= DP_PHY_MODE_STATUS_NOT_SAFE(dig_port->tc_phy_fia_idx);
- intel_uncore_write(uncore,
- PORT_TX_DFLEXDPCSSS(dig_port->tc_phy_fia), val);
+ intel_de_write(i915, PORT_TX_DFLEXDPCSSS(dig_port->tc_phy_fia), val);
return true;
}
@@ -407,11 +392,10 @@ static bool adl_tc_phy_take_ownership(struct intel_digital_port *dig_port,
bool take)
{
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
- struct intel_uncore *uncore = &i915->uncore;
enum port port = dig_port->base.port;
- intel_uncore_rmw(uncore, DDI_BUF_CTL(port), DDI_BUF_CTL_TC_PHY_OWNERSHIP,
- take ? DDI_BUF_CTL_TC_PHY_OWNERSHIP : 0);
+ intel_de_rmw(i915, DDI_BUF_CTL(port), DDI_BUF_CTL_TC_PHY_OWNERSHIP,
+ take ? DDI_BUF_CTL_TC_PHY_OWNERSHIP : 0);
return true;
}
@@ -429,11 +413,9 @@ static bool tc_phy_take_ownership(struct intel_digital_port *dig_port, bool take
static bool icl_tc_phy_is_owned(struct intel_digital_port *dig_port)
{
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
- struct intel_uncore *uncore = &i915->uncore;
u32 val;
- val = intel_uncore_read(uncore,
- PORT_TX_DFLEXDPCSSS(dig_port->tc_phy_fia));
+ val = intel_de_read(i915, PORT_TX_DFLEXDPCSSS(dig_port->tc_phy_fia));
if (val == 0xffffffff) {
drm_dbg_kms(&i915->drm,
"Port %s: PHY in TCCOLD, assume safe mode\n",
@@ -447,11 +429,10 @@ static bool icl_tc_phy_is_owned(struct intel_digital_port *dig_port)
static bool adl_tc_phy_is_owned(struct intel_digital_port *dig_port)
{
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
- struct intel_uncore *uncore = &i915->uncore;
enum port port = dig_port->base.port;
u32 val;
- val = intel_uncore_read(uncore, DDI_BUF_CTL(port));
+ val = intel_de_read(i915, DDI_BUF_CTL(port));
return val & DDI_BUF_CTL_TC_PHY_OWNERSHIP;
}
@@ -907,7 +888,7 @@ tc_has_modular_fia(struct drm_i915_private *i915, struct intel_digital_port *dig
mutex_lock(&dig_port->tc_lock);
wakeref = tc_cold_block(dig_port, &domain);
- val = intel_uncore_read(&i915->uncore, PORT_TX_DFLEXDPSP(FIA1));
+ val = intel_de_read(i915, PORT_TX_DFLEXDPSP(FIA1));
tc_cold_unblock(dig_port, domain, wakeref);
mutex_unlock(&dig_port->tc_lock);
diff --git a/drivers/gpu/drm/i915/display/intel_tv.c b/drivers/gpu/drm/i915/display/intel_tv.c
index 4d2101ca1692..b986bf075889 100644
--- a/drivers/gpu/drm/i915/display/intel_tv.c
+++ b/drivers/gpu/drm/i915/display/intel_tv.c
@@ -1905,10 +1905,10 @@ static void intel_tv_add_properties(struct drm_connector *connector)
tv_format_names[i] = tv_modes[i].name;
}
- drm_mode_create_tv_properties(&i915->drm, i, tv_format_names);
+ drm_mode_create_tv_properties_legacy(&i915->drm, i, tv_format_names);
drm_object_attach_property(&connector->base,
- i915->drm.mode_config.tv_mode_property,
+ i915->drm.mode_config.legacy_tv_mode_property,
conn_state->tv.mode);
drm_object_attach_property(&connector->base,
i915->drm.mode_config.tv_left_margin_property,
diff --git a/drivers/gpu/drm/i915/display/intel_vblank.c b/drivers/gpu/drm/i915/display/intel_vblank.c
new file mode 100644
index 000000000000..4c83e2320bca
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/intel_vblank.c
@@ -0,0 +1,441 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2022-2023 Intel Corporation
+ */
+
+#include "i915_drv.h"
+#include "i915_reg.h"
+#include "intel_de.h"
+#include "intel_display_types.h"
+#include "intel_vblank.h"
+
+/*
+ * This timing diagram depicts the video signal in and
+ * around the vertical blanking period.
+ *
+ * Assumptions about the fictitious mode used in this example:
+ * vblank_start >= 3
+ * vsync_start = vblank_start + 1
+ * vsync_end = vblank_start + 2
+ * vtotal = vblank_start + 3
+ *
+ * start of vblank:
+ * latch double buffered registers
+ * increment frame counter (ctg+)
+ * generate start of vblank interrupt (gen4+)
+ * |
+ * | frame start:
+ * | generate frame start interrupt (aka. vblank interrupt) (gmch)
+ * | may be shifted forward 1-3 extra lines via PIPECONF
+ * | |
+ * | | start of vsync:
+ * | | generate vsync interrupt
+ * | | |
+ * ___xxxx___ ___xxxx___ ___xxxx___ ___xxxx___ ___xxxx___ ___xxxx
+ * . \hs/ . \hs/ \hs/ \hs/ . \hs/
+ * ----va---> <-----------------vb--------------------> <--------va-------------
+ * | | <----vs-----> |
+ * -vbs-----> <---vbs+1---> <---vbs+2---> <-----0-----> <-----1-----> <-----2--- (scanline counter gen2)
+ * -vbs-2---> <---vbs-1---> <---vbs-----> <---vbs+1---> <---vbs+2---> <-----0--- (scanline counter gen3+)
+ * -vbs-2---> <---vbs-2---> <---vbs-1---> <---vbs-----> <---vbs+1---> <---vbs+2- (scanline counter hsw+ hdmi)
+ * | | |
+ * last visible pixel first visible pixel
+ * | increment frame counter (gen3/4)
+ * pixel counter = vblank_start * htotal pixel counter = 0 (gen3/4)
+ *
+ * x = horizontal active
+ * _ = horizontal blanking
+ * hs = horizontal sync
+ * va = vertical active
+ * vb = vertical blanking
+ * vs = vertical sync
+ * vbs = vblank_start (number)
+ *
+ * Summary:
+ * - most events happen at the start of horizontal sync
+ * - frame start happens at the start of horizontal blank, 1-4 lines
+ * (depending on PIPECONF settings) after the start of vblank
+ * - gen3/4 pixel and frame counter are synchronized with the start
+ * of horizontal active on the first line of vertical active
+ */
+
+/*
+ * Called from drm generic code, passed a 'crtc', which we use as a pipe index.
+ */
+u32 i915_get_vblank_counter(struct drm_crtc *crtc)
+{
+ struct drm_i915_private *dev_priv = to_i915(crtc->dev);
+ struct drm_vblank_crtc *vblank = &dev_priv->drm.vblank[drm_crtc_index(crtc)];
+ const struct drm_display_mode *mode = &vblank->hwmode;
+ enum pipe pipe = to_intel_crtc(crtc)->pipe;
+ u32 pixel, vbl_start, hsync_start, htotal;
+ u64 frame;
+
+ /*
+ * On i965gm TV output the frame counter only works up to
+ * the point when we enable the TV encoder. After that the
+ * frame counter ceases to work and reads zero. We need a
+ * vblank wait before enabling the TV encoder and so we
+ * have to enable vblank interrupts while the frame counter
+ * is still in a working state. However the core vblank code
+ * does not like us returning non-zero frame counter values
+ * when we've told it that we don't have a working frame
+ * counter. Thus we must stop non-zero values leaking out.
+ */
+ if (!vblank->max_vblank_count)
+ return 0;
+
+ htotal = mode->crtc_htotal;
+ hsync_start = mode->crtc_hsync_start;
+ vbl_start = mode->crtc_vblank_start;
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+ vbl_start = DIV_ROUND_UP(vbl_start, 2);
+
+ /* Convert to pixel count */
+ vbl_start *= htotal;
+
+ /* Start of vblank event occurs at start of hsync */
+ vbl_start -= htotal - hsync_start;
+
+ /*
+ * High & low register fields aren't synchronized, so make sure
+ * we get a low value that's stable across two reads of the high
+ * register.
+ */
+ frame = intel_de_read64_2x32(dev_priv, PIPEFRAMEPIXEL(pipe), PIPEFRAME(pipe));
+
+ pixel = frame & PIPE_PIXEL_MASK;
+ frame = (frame >> PIPE_FRAME_LOW_SHIFT) & 0xffffff;
+
+ /*
+ * The frame counter increments at beginning of active.
+ * Cook up a vblank counter by also checking the pixel
+ * counter against vblank start.
+ */
+ return (frame + (pixel >= vbl_start)) & 0xffffff;
+}
+
+u32 g4x_get_vblank_counter(struct drm_crtc *crtc)
+{
+ struct drm_i915_private *dev_priv = to_i915(crtc->dev);
+ struct drm_vblank_crtc *vblank = &dev_priv->drm.vblank[drm_crtc_index(crtc)];
+ enum pipe pipe = to_intel_crtc(crtc)->pipe;
+
+ if (!vblank->max_vblank_count)
+ return 0;
+
+ return intel_de_read(dev_priv, PIPE_FRMCOUNT_G4X(pipe));
+}
+
+static u32 intel_crtc_scanlines_since_frame_timestamp(struct intel_crtc *crtc)
+{
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ struct drm_vblank_crtc *vblank =
+ &crtc->base.dev->vblank[drm_crtc_index(&crtc->base)];
+ const struct drm_display_mode *mode = &vblank->hwmode;
+ u32 htotal = mode->crtc_htotal;
+ u32 clock = mode->crtc_clock;
+ u32 scan_prev_time, scan_curr_time, scan_post_time;
+
+ /*
+ * To avoid the race condition where we might cross into the
+ * next vblank just between the PIPE_FRMTMSTMP and TIMESTAMP_CTR
+ * reads. We make sure we read PIPE_FRMTMSTMP and TIMESTAMP_CTR
+ * during the same frame.
+ */
+ do {
+ /*
+ * This field provides read back of the display
+ * pipe frame time stamp. The time stamp value
+ * is sampled at every start of vertical blank.
+ */
+ scan_prev_time = intel_de_read_fw(dev_priv,
+ PIPE_FRMTMSTMP(crtc->pipe));
+
+ /*
+ * The TIMESTAMP_CTR register has the current
+ * time stamp value.
+ */
+ scan_curr_time = intel_de_read_fw(dev_priv, IVB_TIMESTAMP_CTR);
+
+ scan_post_time = intel_de_read_fw(dev_priv,
+ PIPE_FRMTMSTMP(crtc->pipe));
+ } while (scan_post_time != scan_prev_time);
+
+ return div_u64(mul_u32_u32(scan_curr_time - scan_prev_time,
+ clock), 1000 * htotal);
+}
+
+/*
+ * On certain encoders on certain platforms, pipe
+ * scanline register will not work to get the scanline,
+ * since the timings are driven from the PORT or issues
+ * with scanline register updates.
+ * This function will use Framestamp and current
+ * timestamp registers to calculate the scanline.
+ */
+static u32 __intel_get_crtc_scanline_from_timestamp(struct intel_crtc *crtc)
+{
+ struct drm_vblank_crtc *vblank =
+ &crtc->base.dev->vblank[drm_crtc_index(&crtc->base)];
+ const struct drm_display_mode *mode = &vblank->hwmode;
+ u32 vblank_start = mode->crtc_vblank_start;
+ u32 vtotal = mode->crtc_vtotal;
+ u32 scanline;
+
+ scanline = intel_crtc_scanlines_since_frame_timestamp(crtc);
+ scanline = min(scanline, vtotal - 1);
+ scanline = (scanline + vblank_start) % vtotal;
+
+ return scanline;
+}
+
+/*
+ * intel_de_read_fw(), only for fast reads of display block, no need for
+ * forcewake etc.
+ */
+static int __intel_get_crtc_scanline(struct intel_crtc *crtc)
+{
+ struct drm_device *dev = crtc->base.dev;
+ struct drm_i915_private *dev_priv = to_i915(dev);
+ const struct drm_display_mode *mode;
+ struct drm_vblank_crtc *vblank;
+ enum pipe pipe = crtc->pipe;
+ int position, vtotal;
+
+ if (!crtc->active)
+ return 0;
+
+ vblank = &crtc->base.dev->vblank[drm_crtc_index(&crtc->base)];
+ mode = &vblank->hwmode;
+
+ if (crtc->mode_flags & I915_MODE_FLAG_GET_SCANLINE_FROM_TIMESTAMP)
+ return __intel_get_crtc_scanline_from_timestamp(crtc);
+
+ vtotal = mode->crtc_vtotal;
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+ vtotal /= 2;
+
+ position = intel_de_read_fw(dev_priv, PIPEDSL(pipe)) & PIPEDSL_LINE_MASK;
+
+ /*
+ * On HSW, the DSL reg (0x70000) appears to return 0 if we
+ * read it just before the start of vblank. So try it again
+ * so we don't accidentally end up spanning a vblank frame
+ * increment, causing the pipe_update_end() code to squak at us.
+ *
+ * The nature of this problem means we can't simply check the ISR
+ * bit and return the vblank start value; nor can we use the scanline
+ * debug register in the transcoder as it appears to have the same
+ * problem. We may need to extend this to include other platforms,
+ * but so far testing only shows the problem on HSW.
+ */
+ if (HAS_DDI(dev_priv) && !position) {
+ int i, temp;
+
+ for (i = 0; i < 100; i++) {
+ udelay(1);
+ temp = intel_de_read_fw(dev_priv, PIPEDSL(pipe)) & PIPEDSL_LINE_MASK;
+ if (temp != position) {
+ position = temp;
+ break;
+ }
+ }
+ }
+
+ /*
+ * See update_scanline_offset() for the details on the
+ * scanline_offset adjustment.
+ */
+ return (position + crtc->scanline_offset) % vtotal;
+}
+
+static bool i915_get_crtc_scanoutpos(struct drm_crtc *_crtc,
+ bool in_vblank_irq,
+ int *vpos, int *hpos,
+ ktime_t *stime, ktime_t *etime,
+ const struct drm_display_mode *mode)
+{
+ struct drm_device *dev = _crtc->dev;
+ struct drm_i915_private *dev_priv = to_i915(dev);
+ struct intel_crtc *crtc = to_intel_crtc(_crtc);
+ enum pipe pipe = crtc->pipe;
+ int position;
+ int vbl_start, vbl_end, hsync_start, htotal, vtotal;
+ unsigned long irqflags;
+ bool use_scanline_counter = DISPLAY_VER(dev_priv) >= 5 ||
+ IS_G4X(dev_priv) || DISPLAY_VER(dev_priv) == 2 ||
+ crtc->mode_flags & I915_MODE_FLAG_USE_SCANLINE_COUNTER;
+
+ if (drm_WARN_ON(&dev_priv->drm, !mode->crtc_clock)) {
+ drm_dbg(&dev_priv->drm,
+ "trying to get scanoutpos for disabled pipe %c\n",
+ pipe_name(pipe));
+ return false;
+ }
+
+ htotal = mode->crtc_htotal;
+ hsync_start = mode->crtc_hsync_start;
+ vtotal = mode->crtc_vtotal;
+ vbl_start = mode->crtc_vblank_start;
+ vbl_end = mode->crtc_vblank_end;
+
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
+ vbl_start = DIV_ROUND_UP(vbl_start, 2);
+ vbl_end /= 2;
+ vtotal /= 2;
+ }
+
+ /*
+ * Lock uncore.lock, as we will do multiple timing critical raw
+ * register reads, potentially with preemption disabled, so the
+ * following code must not block on uncore.lock.
+ */
+ spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+
+ /* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */
+
+ /* Get optional system timestamp before query. */
+ if (stime)
+ *stime = ktime_get();
+
+ if (crtc->mode_flags & I915_MODE_FLAG_VRR) {
+ int scanlines = intel_crtc_scanlines_since_frame_timestamp(crtc);
+
+ position = __intel_get_crtc_scanline(crtc);
+
+ /*
+ * Already exiting vblank? If so, shift our position
+ * so it looks like we're already apporaching the full
+ * vblank end. This should make the generated timestamp
+ * more or less match when the active portion will start.
+ */
+ if (position >= vbl_start && scanlines < position)
+ position = min(crtc->vmax_vblank_start + scanlines, vtotal - 1);
+ } else if (use_scanline_counter) {
+ /* No obvious pixelcount register. Only query vertical
+ * scanout position from Display scan line register.
+ */
+ position = __intel_get_crtc_scanline(crtc);
+ } else {
+ /*
+ * Have access to pixelcount since start of frame.
+ * We can split this into vertical and horizontal
+ * scanout position.
+ */
+ position = (intel_de_read_fw(dev_priv, PIPEFRAMEPIXEL(pipe)) & PIPE_PIXEL_MASK) >> PIPE_PIXEL_SHIFT;
+
+ /* convert to pixel counts */
+ vbl_start *= htotal;
+ vbl_end *= htotal;
+ vtotal *= htotal;
+
+ /*
+ * In interlaced modes, the pixel counter counts all pixels,
+ * so one field will have htotal more pixels. In order to avoid
+ * the reported position from jumping backwards when the pixel
+ * counter is beyond the length of the shorter field, just
+ * clamp the position the length of the shorter field. This
+ * matches how the scanline counter based position works since
+ * the scanline counter doesn't count the two half lines.
+ */
+ if (position >= vtotal)
+ position = vtotal - 1;
+
+ /*
+ * Start of vblank interrupt is triggered at start of hsync,
+ * just prior to the first active line of vblank. However we
+ * consider lines to start at the leading edge of horizontal
+ * active. So, should we get here before we've crossed into
+ * the horizontal active of the first line in vblank, we would
+ * not set the DRM_SCANOUTPOS_INVBL flag. In order to fix that,
+ * always add htotal-hsync_start to the current pixel position.
+ */
+ position = (position + htotal - hsync_start) % vtotal;
+ }
+
+ /* Get optional system timestamp after query. */
+ if (etime)
+ *etime = ktime_get();
+
+ /* preempt_enable_rt() should go right here in PREEMPT_RT patchset. */
+
+ spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
+
+ /*
+ * While in vblank, position will be negative
+ * counting up towards 0 at vbl_end. And outside
+ * vblank, position will be positive counting
+ * up since vbl_end.
+ */
+ if (position >= vbl_start)
+ position -= vbl_end;
+ else
+ position += vtotal - vbl_end;
+
+ if (use_scanline_counter) {
+ *vpos = position;
+ *hpos = 0;
+ } else {
+ *vpos = position / htotal;
+ *hpos = position - (*vpos * htotal);
+ }
+
+ return true;
+}
+
+bool intel_crtc_get_vblank_timestamp(struct drm_crtc *crtc, int *max_error,
+ ktime_t *vblank_time, bool in_vblank_irq)
+{
+ return drm_crtc_vblank_helper_get_vblank_timestamp_internal(
+ crtc, max_error, vblank_time, in_vblank_irq,
+ i915_get_crtc_scanoutpos);
+}
+
+int intel_get_crtc_scanline(struct intel_crtc *crtc)
+{
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ unsigned long irqflags;
+ int position;
+
+ spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+ position = __intel_get_crtc_scanline(crtc);
+ spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
+
+ return position;
+}
+
+static bool pipe_scanline_is_moving(struct drm_i915_private *dev_priv,
+ enum pipe pipe)
+{
+ i915_reg_t reg = PIPEDSL(pipe);
+ u32 line1, line2;
+
+ line1 = intel_de_read(dev_priv, reg) & PIPEDSL_LINE_MASK;
+ msleep(5);
+ line2 = intel_de_read(dev_priv, reg) & PIPEDSL_LINE_MASK;
+
+ return line1 != line2;
+}
+
+static void wait_for_pipe_scanline_moving(struct intel_crtc *crtc, bool state)
+{
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ enum pipe pipe = crtc->pipe;
+
+ /* Wait for the display line to settle/start moving */
+ if (wait_for(pipe_scanline_is_moving(dev_priv, pipe) == state, 100))
+ drm_err(&dev_priv->drm,
+ "pipe %c scanline %s wait timed out\n",
+ pipe_name(pipe), str_on_off(state));
+}
+
+void intel_wait_for_pipe_scanline_stopped(struct intel_crtc *crtc)
+{
+ wait_for_pipe_scanline_moving(crtc, false);
+}
+
+void intel_wait_for_pipe_scanline_moving(struct intel_crtc *crtc)
+{
+ wait_for_pipe_scanline_moving(crtc, true);
+}
diff --git a/drivers/gpu/drm/i915/display/intel_vblank.h b/drivers/gpu/drm/i915/display/intel_vblank.h
new file mode 100644
index 000000000000..c9fea2c2a990
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/intel_vblank.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2022-2023 Intel Corporation
+ */
+
+#ifndef __INTEL_VBLANK_H__
+#define __INTEL_VBLANK_H__
+
+#include <linux/ktime.h>
+#include <linux/types.h>
+
+struct drm_crtc;
+struct intel_crtc;
+
+u32 i915_get_vblank_counter(struct drm_crtc *crtc);
+u32 g4x_get_vblank_counter(struct drm_crtc *crtc);
+bool intel_crtc_get_vblank_timestamp(struct drm_crtc *crtc, int *max_error,
+ ktime_t *vblank_time, bool in_vblank_irq);
+int intel_get_crtc_scanline(struct intel_crtc *crtc);
+void intel_wait_for_pipe_scanline_stopped(struct intel_crtc *crtc);
+void intel_wait_for_pipe_scanline_moving(struct intel_crtc *crtc);
+
+#endif /* __INTEL_VBLANK_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_vdsc.c b/drivers/gpu/drm/i915/display/intel_vdsc.c
index 9d3b77b41b5c..207b2a648d32 100644
--- a/drivers/gpu/drm/i915/display/intel_vdsc.c
+++ b/drivers/gpu/drm/i915/display/intel_vdsc.c
@@ -345,16 +345,13 @@ bool intel_dsc_source_support(const struct intel_crtc_state *crtc_state)
struct drm_i915_private *i915 = to_i915(crtc->base.dev);
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
- if (!RUNTIME_INFO(i915)->has_dsc)
+ if (!HAS_DSC(i915))
return false;
- if (DISPLAY_VER(i915) >= 12)
- return true;
-
- if (DISPLAY_VER(i915) >= 11 && cpu_transcoder != TRANSCODER_A)
- return true;
+ if (DISPLAY_VER(i915) == 11 && cpu_transcoder == TRANSCODER_A)
+ return false;
- return false;
+ return true;
}
static bool is_pipe_dsc(struct intel_crtc *crtc, enum transcoder cpu_transcoder)
diff --git a/drivers/gpu/drm/i915/display/intel_vga.c b/drivers/gpu/drm/i915/display/intel_vga.c
index a69bfcac9a94..286a0bdd28c6 100644
--- a/drivers/gpu/drm/i915/display/intel_vga.c
+++ b/drivers/gpu/drm/i915/display/intel_vga.c
@@ -6,9 +6,10 @@
#include <linux/pci.h>
#include <linux/vgaarb.h>
-#include <drm/i915_drm.h>
#include <video/vga.h>
+#include "soc/intel_gmch.h"
+
#include "i915_drv.h"
#include "i915_reg.h"
#include "intel_de.h"
@@ -98,39 +99,12 @@ void intel_vga_reset_io_mem(struct drm_i915_private *i915)
vga_put(pdev, VGA_RSRC_LEGACY_IO);
}
-static int
-intel_vga_set_state(struct drm_i915_private *i915, bool enable_decode)
-{
- unsigned int reg = DISPLAY_VER(i915) >= 6 ? SNB_GMCH_CTRL : INTEL_GMCH_CTRL;
- u16 gmch_ctrl;
-
- if (pci_read_config_word(i915->bridge_dev, reg, &gmch_ctrl)) {
- drm_err(&i915->drm, "failed to read control word\n");
- return -EIO;
- }
-
- if (!!(gmch_ctrl & INTEL_GMCH_VGA_DISABLE) == !enable_decode)
- return 0;
-
- if (enable_decode)
- gmch_ctrl &= ~INTEL_GMCH_VGA_DISABLE;
- else
- gmch_ctrl |= INTEL_GMCH_VGA_DISABLE;
-
- if (pci_write_config_word(i915->bridge_dev, reg, gmch_ctrl)) {
- drm_err(&i915->drm, "failed to write control word\n");
- return -EIO;
- }
-
- return 0;
-}
-
static unsigned int
intel_vga_set_decode(struct pci_dev *pdev, bool enable_decode)
{
struct drm_i915_private *i915 = pdev_to_i915(pdev);
- intel_vga_set_state(i915, enable_decode);
+ intel_gmch_vga_set_state(i915, enable_decode);
if (enable_decode)
return VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM |
diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c b/drivers/gpu/drm/i915/display/intel_vrr.c
index 7b1357e82b69..5ff6aed9575e 100644
--- a/drivers/gpu/drm/i915/display/intel_vrr.c
+++ b/drivers/gpu/drm/i915/display/intel_vrr.c
@@ -78,10 +78,10 @@ static int intel_vrr_vblank_exit_length(const struct intel_crtc_state *crtc_stat
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
struct drm_i915_private *i915 = to_i915(crtc->base.dev);
- /* The hw imposes the extra scanline before frame start */
if (DISPLAY_VER(i915) >= 13)
- return crtc_state->vrr.guardband + crtc_state->framestart_delay + 1;
+ return crtc_state->vrr.guardband;
else
+ /* The hw imposes the extra scanline before frame start */
return crtc_state->vrr.pipeline_full + crtc_state->framestart_delay + 1;
}
@@ -151,50 +151,46 @@ intel_vrr_compute_config(struct intel_crtc_state *crtc_state,
* number of scan lines. Assuming 0 for no DSB.
*/
crtc_state->vrr.guardband =
- crtc_state->vrr.vmin - adjusted_mode->crtc_vdisplay;
+ crtc_state->vrr.vmin + 1 - adjusted_mode->crtc_vdisplay;
} else {
- /*
- * FIXME: s/4/framestart_delay/ to get consistent
- * earliest/latest points for register latching regardless
- * of the framestart_delay used?
- *
- * FIXME: this really needs the extra scanline to provide consistent
- * behaviour for all framestart_delay values. Otherwise with
- * framestart_delay==4 we will end up extending the min vblank by
- * one extra line.
- */
crtc_state->vrr.pipeline_full =
- min(255, crtc_state->vrr.vmin - adjusted_mode->crtc_vdisplay - 4 - 1);
+ min(255, crtc_state->vrr.vmin - adjusted_mode->crtc_vdisplay -
+ crtc_state->framestart_delay - 1);
}
crtc_state->mode_flags |= I915_MODE_FLAG_VRR;
}
+static u32 trans_vrr_ctl(const struct intel_crtc_state *crtc_state)
+{
+ struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
+
+ if (DISPLAY_VER(i915) >= 13)
+ return VRR_CTL_IGN_MAX_SHIFT | VRR_CTL_FLIP_LINE_EN |
+ XELPD_VRR_CTL_VRR_GUARDBAND(crtc_state->vrr.guardband);
+ else
+ return VRR_CTL_IGN_MAX_SHIFT | VRR_CTL_FLIP_LINE_EN |
+ VRR_CTL_PIPELINE_FULL(crtc_state->vrr.pipeline_full) |
+ VRR_CTL_PIPELINE_FULL_OVERRIDE;
+}
+
void intel_vrr_enable(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
- u32 trans_vrr_ctl;
if (!crtc_state->vrr.enable)
return;
- if (DISPLAY_VER(dev_priv) >= 13)
- trans_vrr_ctl = VRR_CTL_VRR_ENABLE |
- VRR_CTL_IGN_MAX_SHIFT | VRR_CTL_FLIP_LINE_EN |
- XELPD_VRR_CTL_VRR_GUARDBAND(crtc_state->vrr.guardband);
- else
- trans_vrr_ctl = VRR_CTL_VRR_ENABLE |
- VRR_CTL_IGN_MAX_SHIFT | VRR_CTL_FLIP_LINE_EN |
- VRR_CTL_PIPELINE_FULL(crtc_state->vrr.pipeline_full) |
- VRR_CTL_PIPELINE_FULL_OVERRIDE;
-
intel_de_write(dev_priv, TRANS_VRR_VMIN(cpu_transcoder), crtc_state->vrr.vmin - 1);
intel_de_write(dev_priv, TRANS_VRR_VMAX(cpu_transcoder), crtc_state->vrr.vmax - 1);
- intel_de_write(dev_priv, TRANS_VRR_CTL(cpu_transcoder), trans_vrr_ctl);
+ intel_de_write(dev_priv, TRANS_VRR_CTL(cpu_transcoder), trans_vrr_ctl(crtc_state));
intel_de_write(dev_priv, TRANS_VRR_FLIPLINE(cpu_transcoder), crtc_state->vrr.flipline - 1);
intel_de_write(dev_priv, TRANS_PUSH(cpu_transcoder), TRANS_PUSH_EN);
+
+ intel_de_write(dev_priv, TRANS_VRR_CTL(cpu_transcoder),
+ VRR_CTL_VRR_ENABLE | trans_vrr_ctl(crtc_state));
}
void intel_vrr_send_push(const struct intel_crtc_state *crtc_state)
@@ -231,8 +227,13 @@ void intel_vrr_disable(const struct intel_crtc_state *old_crtc_state)
if (!old_crtc_state->vrr.enable)
return;
- intel_de_write(dev_priv, TRANS_VRR_CTL(cpu_transcoder), 0);
+ intel_de_write(dev_priv, TRANS_VRR_CTL(cpu_transcoder),
+ trans_vrr_ctl(old_crtc_state));
+ intel_de_wait_for_clear(dev_priv, TRANS_VRR_STATUS(cpu_transcoder),
+ VRR_STATUS_VRR_EN_LIVE, 1000);
+
intel_de_write(dev_priv, TRANS_PUSH(cpu_transcoder), 0);
+ intel_de_write(dev_priv, TRANS_VRR_CTL(cpu_transcoder), 0);
}
void intel_vrr_get_config(struct intel_crtc *crtc,
diff --git a/drivers/gpu/drm/i915/display/skl_scaler.c b/drivers/gpu/drm/i915/display/skl_scaler.c
index d7390067b7d4..473d53610b92 100644
--- a/drivers/gpu/drm/i915/display/skl_scaler.c
+++ b/drivers/gpu/drm/i915/display/skl_scaler.c
@@ -87,6 +87,14 @@ static u16 skl_scaler_calc_phase(int sub, int scale, bool chroma_cosited)
#define ICL_MAX_SRC_H 4096
#define ICL_MAX_DST_W 5120
#define ICL_MAX_DST_H 4096
+#define TGL_MAX_SRC_W 5120
+#define TGL_MAX_SRC_H 8192
+#define TGL_MAX_DST_W 8192
+#define TGL_MAX_DST_H 8192
+#define MTL_MAX_SRC_W 4096
+#define MTL_MAX_SRC_H 8192
+#define MTL_MAX_DST_W 8192
+#define MTL_MAX_DST_H 8192
#define SKL_MIN_YUV_420_SRC_W 16
#define SKL_MIN_YUV_420_SRC_H 16
@@ -103,6 +111,8 @@ skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach,
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
const struct drm_display_mode *adjusted_mode =
&crtc_state->hw.adjusted_mode;
+ int min_src_w, min_src_h, min_dst_w, min_dst_h;
+ int max_src_w, max_src_h, max_dst_w, max_dst_h;
/*
* Src coordinates are already rotated by 270 degrees for
@@ -157,15 +167,38 @@ skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach,
return -EINVAL;
}
+ min_src_w = SKL_MIN_SRC_W;
+ min_src_h = SKL_MIN_SRC_H;
+ min_dst_w = SKL_MIN_DST_W;
+ min_dst_h = SKL_MIN_DST_H;
+
+ if (DISPLAY_VER(dev_priv) < 11) {
+ max_src_w = SKL_MAX_SRC_W;
+ max_src_h = SKL_MAX_SRC_H;
+ max_dst_w = SKL_MAX_DST_W;
+ max_dst_h = SKL_MAX_DST_H;
+ } else if (DISPLAY_VER(dev_priv) < 12) {
+ max_src_w = ICL_MAX_SRC_W;
+ max_src_h = ICL_MAX_SRC_H;
+ max_dst_w = ICL_MAX_DST_W;
+ max_dst_h = ICL_MAX_DST_H;
+ } else if (DISPLAY_VER(dev_priv) < 14) {
+ max_src_w = TGL_MAX_SRC_W;
+ max_src_h = TGL_MAX_SRC_H;
+ max_dst_w = TGL_MAX_DST_W;
+ max_dst_h = TGL_MAX_DST_H;
+ } else {
+ max_src_w = MTL_MAX_SRC_W;
+ max_src_h = MTL_MAX_SRC_H;
+ max_dst_w = MTL_MAX_DST_W;
+ max_dst_h = MTL_MAX_DST_H;
+ }
+
/* range checks */
- if (src_w < SKL_MIN_SRC_W || src_h < SKL_MIN_SRC_H ||
- dst_w < SKL_MIN_DST_W || dst_h < SKL_MIN_DST_H ||
- (DISPLAY_VER(dev_priv) >= 11 &&
- (src_w > ICL_MAX_SRC_W || src_h > ICL_MAX_SRC_H ||
- dst_w > ICL_MAX_DST_W || dst_h > ICL_MAX_DST_H)) ||
- (DISPLAY_VER(dev_priv) < 11 &&
- (src_w > SKL_MAX_SRC_W || src_h > SKL_MAX_SRC_H ||
- dst_w > SKL_MAX_DST_W || dst_h > SKL_MAX_DST_H))) {
+ if (src_w < min_src_w || src_h < min_src_h ||
+ dst_w < min_dst_w || dst_h < min_dst_h ||
+ src_w > max_src_w || src_h > max_src_h ||
+ dst_w > max_dst_w || dst_h > max_dst_h) {
drm_dbg_kms(&dev_priv->drm,
"scaler_user index %u.%u: src %ux%u dst %ux%u "
"size is out of scaler range\n",
diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c
index 7d07fa3123ec..9b172a1e90de 100644
--- a/drivers/gpu/drm/i915/display/skl_universal_plane.c
+++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c
@@ -1848,7 +1848,7 @@ static bool bo_has_valid_encryption(struct drm_i915_gem_object *obj)
{
struct drm_i915_private *i915 = to_i915(obj->base.dev);
- return intel_pxp_key_check(&to_gt(i915)->pxp, obj, false) == 0;
+ return intel_pxp_key_check(i915->pxp, obj, false) == 0;
}
static bool pxp_is_borked(struct drm_i915_gem_object *obj)
diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c
index 11554645e6ee..d1670cc3eff2 100644
--- a/drivers/gpu/drm/i915/display/skl_watermark.c
+++ b/drivers/gpu/drm/i915/display/skl_watermark.c
@@ -45,8 +45,7 @@ u8 intel_enabled_dbuf_slices_mask(struct drm_i915_private *i915)
enum dbuf_slice slice;
for_each_dbuf_slice(i915, slice) {
- if (intel_uncore_read(&i915->uncore,
- DBUF_CTL_S(slice)) & DBUF_POWER_STATE)
+ if (intel_de_read(i915, DBUF_CTL_S(slice)) & DBUF_POWER_STATE)
enabled_slices |= BIT(slice);
}
@@ -75,7 +74,7 @@ intel_sagv_block_time(struct drm_i915_private *i915)
if (DISPLAY_VER(i915) >= 14) {
u32 val;
- val = intel_uncore_read(&i915->uncore, MTL_LATENCY_SAGV);
+ val = intel_de_read(i915, MTL_LATENCY_SAGV);
return REG_FIELD_GET(MTL_LATENCY_QCLK_SAGV, val);
} else if (DISPLAY_VER(i915) >= 12) {
@@ -756,18 +755,18 @@ skl_ddb_get_hw_plane_state(struct drm_i915_private *i915,
/* Cursor doesn't support NV12/planar, so no extra calculation needed */
if (plane_id == PLANE_CURSOR) {
- val = intel_uncore_read(&i915->uncore, CUR_BUF_CFG(pipe));
+ val = intel_de_read(i915, CUR_BUF_CFG(pipe));
skl_ddb_entry_init_from_hw(ddb, val);
return;
}
- val = intel_uncore_read(&i915->uncore, PLANE_BUF_CFG(pipe, plane_id));
+ val = intel_de_read(i915, PLANE_BUF_CFG(pipe, plane_id));
skl_ddb_entry_init_from_hw(ddb, val);
if (DISPLAY_VER(i915) >= 11)
return;
- val = intel_uncore_read(&i915->uncore, PLANE_NV12_BUF_CFG(pipe, plane_id));
+ val = intel_de_read(i915, PLANE_NV12_BUF_CFG(pipe, plane_id));
skl_ddb_entry_init_from_hw(ddb_y, val);
}
@@ -2822,36 +2821,32 @@ static void skl_pipe_wm_get_hw_state(struct intel_crtc *crtc,
for (level = 0; level <= max_level; level++) {
if (plane_id != PLANE_CURSOR)
- val = intel_uncore_read(&i915->uncore, PLANE_WM(pipe, plane_id, level));
+ val = intel_de_read(i915, PLANE_WM(pipe, plane_id, level));
else
- val = intel_uncore_read(&i915->uncore, CUR_WM(pipe, level));
+ val = intel_de_read(i915, CUR_WM(pipe, level));
skl_wm_level_from_reg_val(val, &wm->wm[level]);
}
if (plane_id != PLANE_CURSOR)
- val = intel_uncore_read(&i915->uncore, PLANE_WM_TRANS(pipe, plane_id));
+ val = intel_de_read(i915, PLANE_WM_TRANS(pipe, plane_id));
else
- val = intel_uncore_read(&i915->uncore, CUR_WM_TRANS(pipe));
+ val = intel_de_read(i915, CUR_WM_TRANS(pipe));
skl_wm_level_from_reg_val(val, &wm->trans_wm);
if (HAS_HW_SAGV_WM(i915)) {
if (plane_id != PLANE_CURSOR)
- val = intel_uncore_read(&i915->uncore,
- PLANE_WM_SAGV(pipe, plane_id));
+ val = intel_de_read(i915, PLANE_WM_SAGV(pipe, plane_id));
else
- val = intel_uncore_read(&i915->uncore,
- CUR_WM_SAGV(pipe));
+ val = intel_de_read(i915, CUR_WM_SAGV(pipe));
skl_wm_level_from_reg_val(val, &wm->sagv.wm0);
if (plane_id != PLANE_CURSOR)
- val = intel_uncore_read(&i915->uncore,
- PLANE_WM_SAGV_TRANS(pipe, plane_id));
+ val = intel_de_read(i915, PLANE_WM_SAGV_TRANS(pipe, plane_id));
else
- val = intel_uncore_read(&i915->uncore,
- CUR_WM_SAGV_TRANS(pipe));
+ val = intel_de_read(i915, CUR_WM_SAGV_TRANS(pipe));
skl_wm_level_from_reg_val(val, &wm->sagv.trans_wm);
} else if (DISPLAY_VER(i915) >= 12) {
@@ -3127,8 +3122,8 @@ void skl_watermark_ipc_update(struct drm_i915_private *i915)
if (!HAS_IPC(i915))
return;
- intel_uncore_rmw(&i915->uncore, DISP_ARB_CTL2, DISP_IPC_ENABLE,
- skl_watermark_ipc_enabled(i915) ? DISP_IPC_ENABLE : 0);
+ intel_de_rmw(i915, DISP_ARB_CTL2, DISP_IPC_ENABLE,
+ skl_watermark_ipc_enabled(i915) ? DISP_IPC_ENABLE : 0);
}
static bool skl_watermark_ipc_can_enable(struct drm_i915_private *i915)
@@ -3202,19 +3197,18 @@ adjust_wm_latency(struct drm_i915_private *i915,
static void mtl_read_wm_latency(struct drm_i915_private *i915, u16 wm[])
{
- struct intel_uncore *uncore = &i915->uncore;
int max_level = ilk_wm_max_level(i915);
u32 val;
- val = intel_uncore_read(uncore, MTL_LATENCY_LP0_LP1);
+ val = intel_de_read(i915, MTL_LATENCY_LP0_LP1);
wm[0] = REG_FIELD_GET(MTL_LATENCY_LEVEL_EVEN_MASK, val);
wm[1] = REG_FIELD_GET(MTL_LATENCY_LEVEL_ODD_MASK, val);
- val = intel_uncore_read(uncore, MTL_LATENCY_LP2_LP3);
+ val = intel_de_read(i915, MTL_LATENCY_LP2_LP3);
wm[2] = REG_FIELD_GET(MTL_LATENCY_LEVEL_EVEN_MASK, val);
wm[3] = REG_FIELD_GET(MTL_LATENCY_LEVEL_ODD_MASK, val);
- val = intel_uncore_read(uncore, MTL_LATENCY_LP4_LP5);
+ val = intel_de_read(i915, MTL_LATENCY_LP4_LP5);
wm[4] = REG_FIELD_GET(MTL_LATENCY_LEVEL_EVEN_MASK, val);
wm[5] = REG_FIELD_GET(MTL_LATENCY_LEVEL_ODD_MASK, val);
diff --git a/drivers/gpu/drm/i915/display/skl_watermark.h b/drivers/gpu/drm/i915/display/skl_watermark.h
index 7a5a4e67cd73..37954c472070 100644
--- a/drivers/gpu/drm/i915/display/skl_watermark.h
+++ b/drivers/gpu/drm/i915/display/skl_watermark.h
@@ -8,7 +8,7 @@
#include <linux/types.h>
-#include "intel_display.h"
+#include "intel_display_limits.h"
#include "intel_global_state.h"
#include "intel_pm_types.h"
diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c
index 84481030883a..2289f6b1b4eb 100644
--- a/drivers/gpu/drm/i915/display/vlv_dsi.c
+++ b/drivers/gpu/drm/i915/display/vlv_dsi.c
@@ -1916,7 +1916,7 @@ void vlv_dsi_init(struct drm_i915_private *dev_priv)
intel_dsi->panel_power_off_time = ktime_get_boottime();
- intel_bios_init_panel(dev_priv, &intel_connector->panel, NULL, NULL);
+ intel_bios_init_panel_late(dev_priv, &intel_connector->panel, NULL, NULL);
if (intel_connector->panel.vbt.dsi.config->dual_link)
intel_dsi->ports = BIT(PORT_A) | BIT(PORT_C);
@@ -1983,7 +1983,7 @@ void vlv_dsi_init(struct drm_i915_private *dev_priv)
goto err_cleanup_connector;
}
- intel_panel_init(intel_connector);
+ intel_panel_init(intel_connector, NULL);
intel_backlight_setup(intel_connector, INVALID_PIPE);
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_clflush.c b/drivers/gpu/drm/i915/gem/i915_gem_clflush.c
index b3b398fe689c..385ffc575b48 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_clflush.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_clflush.c
@@ -8,6 +8,7 @@
#include "display/intel_frontbuffer.h"
+#include "i915_config.h"
#include "i915_drv.h"
#include "i915_gem_clflush.h"
#include "i915_sw_fence_work.h"
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index e4b78ab4773b..6d639ca24dfb 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -257,7 +257,7 @@ static int proto_context_set_protected(struct drm_i915_private *i915,
if (!protected) {
pc->uses_protected_content = false;
- } else if (!intel_pxp_is_enabled(&to_gt(i915)->pxp)) {
+ } else if (!intel_pxp_is_enabled(i915->pxp)) {
ret = -ENODEV;
} else if ((pc->user_flags & BIT(UCONTEXT_RECOVERABLE)) ||
!(pc->user_flags & BIT(UCONTEXT_BANNABLE))) {
@@ -271,8 +271,8 @@ static int proto_context_set_protected(struct drm_i915_private *i915,
*/
pc->pxp_wakeref = intel_runtime_pm_get(&i915->runtime_pm);
- if (!intel_pxp_is_active(&to_gt(i915)->pxp))
- ret = intel_pxp_start(&to_gt(i915)->pxp);
+ if (!intel_pxp_is_active(i915->pxp))
+ ret = intel_pxp_start(i915->pxp);
}
return ret;
@@ -1096,16 +1096,15 @@ static struct i915_gem_engines *alloc_engines(unsigned int count)
static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx,
struct intel_sseu rcs_sseu)
{
- const struct intel_gt *gt = to_gt(ctx->i915);
+ const unsigned int max = I915_NUM_ENGINES;
struct intel_engine_cs *engine;
struct i915_gem_engines *e, *err;
- enum intel_engine_id id;
- e = alloc_engines(I915_NUM_ENGINES);
+ e = alloc_engines(max);
if (!e)
return ERR_PTR(-ENOMEM);
- for_each_engine(engine, gt, id) {
+ for_each_uabi_engine(engine, ctx->i915) {
struct intel_context *ce;
struct intel_sseu sseu = {};
int ret;
@@ -1113,7 +1112,7 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx,
if (engine->legacy_idx == INVALID_ENGINE)
continue;
- GEM_BUG_ON(engine->legacy_idx >= I915_NUM_ENGINES);
+ GEM_BUG_ON(engine->legacy_idx >= max);
GEM_BUG_ON(e->engines[engine->legacy_idx]);
ce = intel_context_create(engine);
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_create.c b/drivers/gpu/drm/i915/gem/i915_gem_create.c
index 33673fe7ee0a..e76c9703680e 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_create.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_create.c
@@ -5,6 +5,7 @@
#include <drm/drm_fourcc.h>
+#include "display/intel_display.h"
#include "gem/i915_gem_ioctls.h"
#include "gem/i915_gem_lmem.h"
#include "gem/i915_gem_region.h"
@@ -384,7 +385,7 @@ static int ext_set_protected(struct i915_user_extension __user *base, void *data
if (ext.flags)
return -EINVAL;
- if (!intel_pxp_is_enabled(&to_gt(ext_data->i915)->pxp))
+ if (!intel_pxp_is_enabled(ext_data->i915->pxp))
return -ENODEV;
ext_data->flags |= I915_BO_PROTECTED;
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_domain.c b/drivers/gpu/drm/i915/gem/i915_gem_domain.c
index d44a152ce680..497de40b8e68 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_domain.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_domain.c
@@ -4,6 +4,7 @@
* Copyright © 2014-2016 Intel Corporation
*/
+#include "display/intel_display.h"
#include "display/intel_frontbuffer.h"
#include "gt/intel_gt.h"
@@ -17,6 +18,8 @@
#include "i915_gem_object.h"
#include "i915_vma.h"
+#define VTD_GUARD (168u * I915_GTT_PAGE_SIZE) /* 168 or tile-row PTE padding */
+
static bool gpu_write_needs_clflush(struct drm_i915_gem_object *obj)
{
struct drm_i915_private *i915 = to_i915(obj->base.dev);
@@ -424,6 +427,17 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
if (ret)
return ERR_PTR(ret);
+ /* VT-d may overfetch before/after the vma, so pad with scratch */
+ if (intel_scanout_needs_vtd_wa(i915)) {
+ unsigned int guard = VTD_GUARD;
+
+ if (i915_gem_object_is_tiled(obj))
+ guard = max(guard,
+ i915_gem_object_get_tile_row_size(obj));
+
+ flags |= PIN_OFFSET_GUARD | guard;
+ }
+
/*
* As the user may map the buffer once pinned in the display plane
* (e.g. libkms for the bootup splash), we have to ensure that we
@@ -444,7 +458,7 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
if (IS_ERR(vma))
return vma;
- vma->display_alignment = max_t(u64, vma->display_alignment, alignment);
+ vma->display_alignment = max(vma->display_alignment, alignment);
i915_vma_mark_scanout(vma);
i915_gem_object_flush_if_display_locked(obj);
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
index 0f2e056c02dd..9dce2957b4e5 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
@@ -379,22 +379,25 @@ eb_vma_misplaced(const struct drm_i915_gem_exec_object2 *entry,
const struct i915_vma *vma,
unsigned int flags)
{
- if (vma->node.size < entry->pad_to_size)
+ const u64 start = i915_vma_offset(vma);
+ const u64 size = i915_vma_size(vma);
+
+ if (size < entry->pad_to_size)
return true;
- if (entry->alignment && !IS_ALIGNED(vma->node.start, entry->alignment))
+ if (entry->alignment && !IS_ALIGNED(start, entry->alignment))
return true;
if (flags & EXEC_OBJECT_PINNED &&
- vma->node.start != entry->offset)
+ start != entry->offset)
return true;
if (flags & __EXEC_OBJECT_NEEDS_BIAS &&
- vma->node.start < BATCH_OFFSET_BIAS)
+ start < BATCH_OFFSET_BIAS)
return true;
if (!(flags & EXEC_OBJECT_SUPPORTS_48B_ADDRESS) &&
- (vma->node.start + vma->node.size + 4095) >> 32)
+ (start + size + 4095) >> 32)
return true;
if (flags & __EXEC_OBJECT_NEEDS_MAP &&
@@ -440,7 +443,7 @@ eb_pin_vma(struct i915_execbuffer *eb,
int err;
if (vma->node.size)
- pin_flags = vma->node.start;
+ pin_flags = __i915_vma_offset(vma);
else
pin_flags = entry->offset & PIN_OFFSET_MASK;
@@ -663,8 +666,8 @@ static int eb_reserve_vma(struct i915_execbuffer *eb,
if (err)
return err;
- if (entry->offset != vma->node.start) {
- entry->offset = vma->node.start | UPDATE;
+ if (entry->offset != i915_vma_offset(vma)) {
+ entry->offset = i915_vma_offset(vma) | UPDATE;
eb->args->flags |= __EXEC_HAS_RELOC;
}
@@ -906,7 +909,7 @@ static struct i915_vma *eb_lookup_vma(struct i915_execbuffer *eb, u32 handle)
*/
if (i915_gem_context_uses_protected_content(eb->gem_context) &&
i915_gem_object_is_protected(obj)) {
- err = intel_pxp_key_check(&vm->gt->pxp, obj, true);
+ err = intel_pxp_key_check(eb->i915->pxp, obj, true);
if (err) {
i915_gem_object_put(obj);
return ERR_PTR(err);
@@ -1021,8 +1024,8 @@ static int eb_validate_vmas(struct i915_execbuffer *eb)
return err;
if (!err) {
- if (entry->offset != vma->node.start) {
- entry->offset = vma->node.start | UPDATE;
+ if (entry->offset != i915_vma_offset(vma)) {
+ entry->offset = i915_vma_offset(vma) | UPDATE;
eb->args->flags |= __EXEC_HAS_RELOC;
}
} else {
@@ -1103,7 +1106,7 @@ static inline u64
relocation_target(const struct drm_i915_gem_relocation_entry *reloc,
const struct i915_vma *target)
{
- return gen8_canonical_addr((int)reloc->delta + target->node.start);
+ return gen8_canonical_addr((int)reloc->delta + i915_vma_offset(target));
}
static void reloc_cache_init(struct reloc_cache *cache,
@@ -1312,7 +1315,7 @@ static void *reloc_iomap(struct i915_vma *batch,
if (err) /* no inactive aperture space, use cpu reloc */
return NULL;
} else {
- cache->node.start = vma->node.start;
+ cache->node.start = i915_ggtt_offset(vma);
cache->node.mm = (void *)vma;
}
}
@@ -1475,7 +1478,7 @@ eb_relocate_entry(struct i915_execbuffer *eb,
* more work needs to be done.
*/
if (!DBG_FORCE_RELOC &&
- gen8_canonical_addr(target->vma->node.start) == reloc->presumed_offset)
+ gen8_canonical_addr(i915_vma_offset(target->vma)) == reloc->presumed_offset)
return 0;
/* Check that the relocation address is valid... */
@@ -2405,7 +2408,7 @@ static int eb_request_submit(struct i915_execbuffer *eb,
}
err = rq->context->engine->emit_bb_start(rq,
- batch->node.start +
+ i915_vma_offset(batch) +
eb->batch_start_offset,
batch_len,
eb->batch_flags);
@@ -2416,7 +2419,7 @@ static int eb_request_submit(struct i915_execbuffer *eb,
GEM_BUG_ON(intel_context_is_parallel(rq->context));
GEM_BUG_ON(eb->batch_start_offset);
err = rq->context->engine->emit_bb_start(rq,
- eb->trampoline->node.start +
+ i915_vma_offset(eb->trampoline) +
batch_len, 0, 0);
if (err)
return err;
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_internal.c b/drivers/gpu/drm/i915/gem/i915_gem_internal.c
index f66bcefc09ec..6bc26b4b06b8 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_internal.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_internal.c
@@ -35,11 +35,15 @@ static int i915_gem_object_get_pages_internal(struct drm_i915_gem_object *obj)
struct drm_i915_private *i915 = to_i915(obj->base.dev);
struct sg_table *st;
struct scatterlist *sg;
- unsigned int npages;
+ unsigned int npages; /* restricted by sg_alloc_table */
int max_order = MAX_ORDER;
unsigned int max_segment;
gfp_t gfp;
+ if (overflows_type(obj->base.size >> PAGE_SHIFT, npages))
+ return -E2BIG;
+
+ npages = obj->base.size >> PAGE_SHIFT;
max_segment = i915_sg_segment_size(i915->drm.dev) >> PAGE_SHIFT;
max_order = min(max_order, get_order(max_segment));
@@ -55,7 +59,6 @@ create_st:
if (!st)
return -ENOMEM;
- npages = obj->base.size / PAGE_SIZE;
if (sg_alloc_table(st, npages, GFP_KERNEL)) {
kfree(st);
return -ENOMEM;
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_mman.c b/drivers/gpu/drm/i915/gem/i915_gem_mman.c
index c7c252d4d366..d3c1dee16af2 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_mman.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_mman.c
@@ -395,7 +395,7 @@ retry:
/* Finally, remap it using the new GTT offset */
ret = remap_io_mapping(area,
area->vm_start + (vma->gtt_view.partial.offset << PAGE_SHIFT),
- (ggtt->gmadr.start + vma->node.start) >> PAGE_SHIFT,
+ (ggtt->gmadr.start + i915_ggtt_offset(vma)) >> PAGE_SHIFT,
min_t(u64, vma->size, area->vm_end - area->vm_start),
&ggtt->iomap);
if (ret)
@@ -979,7 +979,7 @@ int i915_gem_mmap(struct file *filp, struct vm_area_struct *vma)
i915_gem_object_put(obj);
return -EINVAL;
}
- vma->vm_flags &= ~VM_MAYWRITE;
+ vm_flags_clear(vma, VM_MAYWRITE);
}
anon = mmap_singleton(to_i915(dev));
@@ -988,7 +988,7 @@ int i915_gem_mmap(struct file *filp, struct vm_area_struct *vma)
return PTR_ERR(anon);
}
- vma->vm_flags |= VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP | VM_IO;
+ vm_flags_set(vma, VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP | VM_IO);
/*
* We keep the ref on mmo->obj, not vm_file, but we require
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c
index 1a0886b8aaa1..e6d4efde4fc5 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c
@@ -427,10 +427,11 @@ void __i915_gem_object_invalidate_frontbuffer(struct drm_i915_gem_object *obj,
static void
i915_gem_object_read_from_page_kmap(struct drm_i915_gem_object *obj, u64 offset, void *dst, int size)
{
+ pgoff_t idx = offset >> PAGE_SHIFT;
void *src_map;
void *src_ptr;
- src_map = kmap_atomic(i915_gem_object_get_page(obj, offset >> PAGE_SHIFT));
+ src_map = kmap_atomic(i915_gem_object_get_page(obj, idx));
src_ptr = src_map + offset_in_page(offset);
if (!(obj->cache_coherent & I915_BO_CACHE_COHERENT_FOR_READ))
@@ -443,9 +444,10 @@ i915_gem_object_read_from_page_kmap(struct drm_i915_gem_object *obj, u64 offset,
static void
i915_gem_object_read_from_page_iomap(struct drm_i915_gem_object *obj, u64 offset, void *dst, int size)
{
+ pgoff_t idx = offset >> PAGE_SHIFT;
+ dma_addr_t dma = i915_gem_object_get_dma_address(obj, idx);
void __iomem *src_map;
void __iomem *src_ptr;
- dma_addr_t dma = i915_gem_object_get_dma_address(obj, offset >> PAGE_SHIFT);
src_map = io_mapping_map_wc(&obj->mm.region->iomap,
dma - obj->mm.region->region.start,
@@ -484,6 +486,7 @@ static bool object_has_mappable_iomem(struct drm_i915_gem_object *obj)
*/
int i915_gem_object_read_from_page(struct drm_i915_gem_object *obj, u64 offset, void *dst, int size)
{
+ GEM_BUG_ON(overflows_type(offset >> PAGE_SHIFT, pgoff_t));
GEM_BUG_ON(offset >= obj->base.size);
GEM_BUG_ON(offset_in_page(offset) > PAGE_SIZE - size);
GEM_BUG_ON(!i915_gem_object_has_pinned_pages(obj));
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.h b/drivers/gpu/drm/i915/gem/i915_gem_object.h
index 3db53769864c..f9a8acbba715 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object.h
@@ -20,26 +20,10 @@
enum intel_region_id;
-/*
- * XXX: There is a prevalence of the assumption that we fit the
- * object's page count inside a 32bit _signed_ variable. Let's document
- * this and catch if we ever need to fix it. In the meantime, if you do
- * spot such a local variable, please consider fixing!
- *
- * Aside from our own locals (for which we have no excuse!):
- * - sg_table embeds unsigned int for num_pages
- * - get_user_pages*() mixed ints with longs
- */
-#define GEM_CHECK_SIZE_OVERFLOW(sz) \
- GEM_WARN_ON((sz) >> PAGE_SHIFT > INT_MAX)
-
static inline bool i915_gem_object_size_2big(u64 size)
{
struct drm_i915_gem_object *obj;
- if (GEM_CHECK_SIZE_OVERFLOW(size))
- return true;
-
if (overflows_type(size, obj->base.size))
return true;
@@ -363,44 +347,289 @@ i915_gem_object_get_tile_row_size(const struct drm_i915_gem_object *obj)
int i915_gem_object_set_tiling(struct drm_i915_gem_object *obj,
unsigned int tiling, unsigned int stride);
+/**
+ * __i915_gem_object_page_iter_get_sg - helper to find the target scatterlist
+ * pointer and the target page position using pgoff_t n input argument and
+ * i915_gem_object_page_iter
+ * @obj: i915 GEM buffer object
+ * @iter: i915 GEM buffer object page iterator
+ * @n: page offset
+ * @offset: searched physical offset,
+ * it will be used for returning physical page offset value
+ *
+ * Context: Takes and releases the mutex lock of the i915_gem_object_page_iter.
+ * Takes and releases the RCU lock to search the radix_tree of
+ * i915_gem_object_page_iter.
+ *
+ * Returns:
+ * The target scatterlist pointer and the target page position.
+ *
+ * Recommended to use wrapper macro: i915_gem_object_page_iter_get_sg()
+ */
struct scatterlist *
-__i915_gem_object_get_sg(struct drm_i915_gem_object *obj,
- struct i915_gem_object_page_iter *iter,
- unsigned int n,
- unsigned int *offset, bool dma);
+__i915_gem_object_page_iter_get_sg(struct drm_i915_gem_object *obj,
+ struct i915_gem_object_page_iter *iter,
+ pgoff_t n,
+ unsigned int *offset);
+/**
+ * i915_gem_object_page_iter_get_sg - wrapper macro for
+ * __i915_gem_object_page_iter_get_sg()
+ * @obj: i915 GEM buffer object
+ * @it: i915 GEM buffer object page iterator
+ * @n: page offset
+ * @offset: searched physical offset,
+ * it will be used for returning physical page offset value
+ *
+ * Context: Takes and releases the mutex lock of the i915_gem_object_page_iter.
+ * Takes and releases the RCU lock to search the radix_tree of
+ * i915_gem_object_page_iter.
+ *
+ * Returns:
+ * The target scatterlist pointer and the target page position.
+ *
+ * In order to avoid the truncation of the input parameter, it checks the page
+ * offset n's type from the input parameter before calling
+ * __i915_gem_object_page_iter_get_sg().
+ */
+#define i915_gem_object_page_iter_get_sg(obj, it, n, offset) ({ \
+ static_assert(castable_to_type(n, pgoff_t)); \
+ __i915_gem_object_page_iter_get_sg(obj, it, n, offset); \
+})
+
+/**
+ * __i915_gem_object_get_sg - helper to find the target scatterlist
+ * pointer and the target page position using pgoff_t n input argument and
+ * drm_i915_gem_object. It uses an internal shmem scatterlist lookup function.
+ * @obj: i915 GEM buffer object
+ * @n: page offset
+ * @offset: searched physical offset,
+ * it will be used for returning physical page offset value
+ *
+ * It uses drm_i915_gem_object's internal shmem scatterlist lookup function as
+ * i915_gem_object_page_iter and calls __i915_gem_object_page_iter_get_sg().
+ *
+ * Returns:
+ * The target scatterlist pointer and the target page position.
+ *
+ * Recommended to use wrapper macro: i915_gem_object_get_sg()
+ * See also __i915_gem_object_page_iter_get_sg()
+ */
static inline struct scatterlist *
-i915_gem_object_get_sg(struct drm_i915_gem_object *obj,
- unsigned int n,
- unsigned int *offset)
+__i915_gem_object_get_sg(struct drm_i915_gem_object *obj, pgoff_t n,
+ unsigned int *offset)
{
- return __i915_gem_object_get_sg(obj, &obj->mm.get_page, n, offset, false);
+ return __i915_gem_object_page_iter_get_sg(obj, &obj->mm.get_page, n, offset);
}
+/**
+ * i915_gem_object_get_sg - wrapper macro for __i915_gem_object_get_sg()
+ * @obj: i915 GEM buffer object
+ * @n: page offset
+ * @offset: searched physical offset,
+ * it will be used for returning physical page offset value
+ *
+ * Returns:
+ * The target scatterlist pointer and the target page position.
+ *
+ * In order to avoid the truncation of the input parameter, it checks the page
+ * offset n's type from the input parameter before calling
+ * __i915_gem_object_get_sg().
+ * See also __i915_gem_object_page_iter_get_sg()
+ */
+#define i915_gem_object_get_sg(obj, n, offset) ({ \
+ static_assert(castable_to_type(n, pgoff_t)); \
+ __i915_gem_object_get_sg(obj, n, offset); \
+})
+
+/**
+ * __i915_gem_object_get_sg_dma - helper to find the target scatterlist
+ * pointer and the target page position using pgoff_t n input argument and
+ * drm_i915_gem_object. It uses an internal DMA mapped scatterlist lookup function
+ * @obj: i915 GEM buffer object
+ * @n: page offset
+ * @offset: searched physical offset,
+ * it will be used for returning physical page offset value
+ *
+ * It uses drm_i915_gem_object's internal DMA mapped scatterlist lookup function
+ * as i915_gem_object_page_iter and calls __i915_gem_object_page_iter_get_sg().
+ *
+ * Returns:
+ * The target scatterlist pointer and the target page position.
+ *
+ * Recommended to use wrapper macro: i915_gem_object_get_sg_dma()
+ * See also __i915_gem_object_page_iter_get_sg()
+ */
static inline struct scatterlist *
-i915_gem_object_get_sg_dma(struct drm_i915_gem_object *obj,
- unsigned int n,
- unsigned int *offset)
+__i915_gem_object_get_sg_dma(struct drm_i915_gem_object *obj, pgoff_t n,
+ unsigned int *offset)
{
- return __i915_gem_object_get_sg(obj, &obj->mm.get_dma_page, n, offset, true);
+ return __i915_gem_object_page_iter_get_sg(obj, &obj->mm.get_dma_page, n, offset);
}
+/**
+ * i915_gem_object_get_sg_dma - wrapper macro for __i915_gem_object_get_sg_dma()
+ * @obj: i915 GEM buffer object
+ * @n: page offset
+ * @offset: searched physical offset,
+ * it will be used for returning physical page offset value
+ *
+ * Returns:
+ * The target scatterlist pointer and the target page position.
+ *
+ * In order to avoid the truncation of the input parameter, it checks the page
+ * offset n's type from the input parameter before calling
+ * __i915_gem_object_get_sg_dma().
+ * See also __i915_gem_object_page_iter_get_sg()
+ */
+#define i915_gem_object_get_sg_dma(obj, n, offset) ({ \
+ static_assert(castable_to_type(n, pgoff_t)); \
+ __i915_gem_object_get_sg_dma(obj, n, offset); \
+})
+
+/**
+ * __i915_gem_object_get_page - helper to find the target page with a page offset
+ * @obj: i915 GEM buffer object
+ * @n: page offset
+ *
+ * It uses drm_i915_gem_object's internal shmem scatterlist lookup function as
+ * i915_gem_object_page_iter and calls __i915_gem_object_page_iter_get_sg()
+ * internally.
+ *
+ * Returns:
+ * The target page pointer.
+ *
+ * Recommended to use wrapper macro: i915_gem_object_get_page()
+ * See also __i915_gem_object_page_iter_get_sg()
+ */
struct page *
-i915_gem_object_get_page(struct drm_i915_gem_object *obj,
- unsigned int n);
+__i915_gem_object_get_page(struct drm_i915_gem_object *obj, pgoff_t n);
+/**
+ * i915_gem_object_get_page - wrapper macro for __i915_gem_object_get_page
+ * @obj: i915 GEM buffer object
+ * @n: page offset
+ *
+ * Returns:
+ * The target page pointer.
+ *
+ * In order to avoid the truncation of the input parameter, it checks the page
+ * offset n's type from the input parameter before calling
+ * __i915_gem_object_get_page().
+ * See also __i915_gem_object_page_iter_get_sg()
+ */
+#define i915_gem_object_get_page(obj, n) ({ \
+ static_assert(castable_to_type(n, pgoff_t)); \
+ __i915_gem_object_get_page(obj, n); \
+})
+
+/**
+ * __i915_gem_object_get_dirty_page - helper to find the target page with a page
+ * offset
+ * @obj: i915 GEM buffer object
+ * @n: page offset
+ *
+ * It works like i915_gem_object_get_page(), but it marks the returned page dirty.
+ *
+ * Returns:
+ * The target page pointer.
+ *
+ * Recommended to use wrapper macro: i915_gem_object_get_dirty_page()
+ * See also __i915_gem_object_page_iter_get_sg() and __i915_gem_object_get_page()
+ */
struct page *
-i915_gem_object_get_dirty_page(struct drm_i915_gem_object *obj,
- unsigned int n);
+__i915_gem_object_get_dirty_page(struct drm_i915_gem_object *obj, pgoff_t n);
+
+/**
+ * i915_gem_object_get_dirty_page - wrapper macro for __i915_gem_object_get_dirty_page
+ * @obj: i915 GEM buffer object
+ * @n: page offset
+ *
+ * Returns:
+ * The target page pointer.
+ *
+ * In order to avoid the truncation of the input parameter, it checks the page
+ * offset n's type from the input parameter before calling
+ * __i915_gem_object_get_dirty_page().
+ * See also __i915_gem_object_page_iter_get_sg() and __i915_gem_object_get_page()
+ */
+#define i915_gem_object_get_dirty_page(obj, n) ({ \
+ static_assert(castable_to_type(n, pgoff_t)); \
+ __i915_gem_object_get_dirty_page(obj, n); \
+})
+/**
+ * __i915_gem_object_get_dma_address_len - helper to get bus addresses of
+ * targeted DMA mapped scatterlist from i915 GEM buffer object and it's length
+ * @obj: i915 GEM buffer object
+ * @n: page offset
+ * @len: DMA mapped scatterlist's DMA bus addresses length to return
+ *
+ * Returns:
+ * Bus addresses of targeted DMA mapped scatterlist
+ *
+ * Recommended to use wrapper macro: i915_gem_object_get_dma_address_len()
+ * See also __i915_gem_object_page_iter_get_sg() and __i915_gem_object_get_sg_dma()
+ */
dma_addr_t
-i915_gem_object_get_dma_address_len(struct drm_i915_gem_object *obj,
- unsigned long n,
- unsigned int *len);
+__i915_gem_object_get_dma_address_len(struct drm_i915_gem_object *obj, pgoff_t n,
+ unsigned int *len);
+
+/**
+ * i915_gem_object_get_dma_address_len - wrapper macro for
+ * __i915_gem_object_get_dma_address_len
+ * @obj: i915 GEM buffer object
+ * @n: page offset
+ * @len: DMA mapped scatterlist's DMA bus addresses length to return
+ *
+ * Returns:
+ * Bus addresses of targeted DMA mapped scatterlist
+ *
+ * In order to avoid the truncation of the input parameter, it checks the page
+ * offset n's type from the input parameter before calling
+ * __i915_gem_object_get_dma_address_len().
+ * See also __i915_gem_object_page_iter_get_sg() and
+ * __i915_gem_object_get_dma_address_len()
+ */
+#define i915_gem_object_get_dma_address_len(obj, n, len) ({ \
+ static_assert(castable_to_type(n, pgoff_t)); \
+ __i915_gem_object_get_dma_address_len(obj, n, len); \
+})
+/**
+ * __i915_gem_object_get_dma_address - helper to get bus addresses of
+ * targeted DMA mapped scatterlist from i915 GEM buffer object
+ * @obj: i915 GEM buffer object
+ * @n: page offset
+ *
+ * Returns:
+ * Bus addresses of targeted DMA mapped scatterlis
+ *
+ * Recommended to use wrapper macro: i915_gem_object_get_dma_address()
+ * See also __i915_gem_object_page_iter_get_sg() and __i915_gem_object_get_sg_dma()
+ */
dma_addr_t
-i915_gem_object_get_dma_address(struct drm_i915_gem_object *obj,
- unsigned long n);
+__i915_gem_object_get_dma_address(struct drm_i915_gem_object *obj, pgoff_t n);
+
+/**
+ * i915_gem_object_get_dma_address - wrapper macro for
+ * __i915_gem_object_get_dma_address
+ * @obj: i915 GEM buffer object
+ * @n: page offset
+ *
+ * Returns:
+ * Bus addresses of targeted DMA mapped scatterlist
+ *
+ * In order to avoid the truncation of the input parameter, it checks the page
+ * offset n's type from the input parameter before calling
+ * __i915_gem_object_get_dma_address().
+ * See also __i915_gem_object_page_iter_get_sg() and
+ * __i915_gem_object_get_dma_address()
+ */
+#define i915_gem_object_get_dma_address(obj, n) ({ \
+ static_assert(castable_to_type(n, pgoff_t)); \
+ __i915_gem_object_get_dma_address(obj, n); \
+})
void __i915_gem_object_set_pages(struct drm_i915_gem_object *obj,
struct sg_table *pages);
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
index ab4c2f90a564..19c9bdd8f905 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
@@ -10,7 +10,7 @@
#include <linux/mmu_notifier.h>
#include <drm/drm_gem.h>
-#include <drm/ttm/ttm_bo_api.h>
+#include <drm/ttm/ttm_bo.h>
#include <uapi/drm/i915_drm.h>
#include "i915_active.h"
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_pages.c b/drivers/gpu/drm/i915/gem/i915_gem_pages.c
index 05a27723ebb8..ecd86130b74f 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_pages.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_pages.c
@@ -521,14 +521,16 @@ void __i915_gem_object_release_map(struct drm_i915_gem_object *obj)
}
struct scatterlist *
-__i915_gem_object_get_sg(struct drm_i915_gem_object *obj,
- struct i915_gem_object_page_iter *iter,
- unsigned int n,
- unsigned int *offset,
- bool dma)
+__i915_gem_object_page_iter_get_sg(struct drm_i915_gem_object *obj,
+ struct i915_gem_object_page_iter *iter,
+ pgoff_t n,
+ unsigned int *offset)
+
{
- struct scatterlist *sg;
+ const bool dma = iter == &obj->mm.get_dma_page ||
+ iter == &obj->ttm.get_io_page;
unsigned int idx, count;
+ struct scatterlist *sg;
might_sleep();
GEM_BUG_ON(n >= obj->base.size >> PAGE_SHIFT);
@@ -636,7 +638,7 @@ lookup:
}
struct page *
-i915_gem_object_get_page(struct drm_i915_gem_object *obj, unsigned int n)
+__i915_gem_object_get_page(struct drm_i915_gem_object *obj, pgoff_t n)
{
struct scatterlist *sg;
unsigned int offset;
@@ -649,8 +651,7 @@ i915_gem_object_get_page(struct drm_i915_gem_object *obj, unsigned int n)
/* Like i915_gem_object_get_page(), but mark the returned page dirty */
struct page *
-i915_gem_object_get_dirty_page(struct drm_i915_gem_object *obj,
- unsigned int n)
+__i915_gem_object_get_dirty_page(struct drm_i915_gem_object *obj, pgoff_t n)
{
struct page *page;
@@ -662,9 +663,8 @@ i915_gem_object_get_dirty_page(struct drm_i915_gem_object *obj,
}
dma_addr_t
-i915_gem_object_get_dma_address_len(struct drm_i915_gem_object *obj,
- unsigned long n,
- unsigned int *len)
+__i915_gem_object_get_dma_address_len(struct drm_i915_gem_object *obj,
+ pgoff_t n, unsigned int *len)
{
struct scatterlist *sg;
unsigned int offset;
@@ -678,8 +678,7 @@ i915_gem_object_get_dma_address_len(struct drm_i915_gem_object *obj,
}
dma_addr_t
-i915_gem_object_get_dma_address(struct drm_i915_gem_object *obj,
- unsigned long n)
+__i915_gem_object_get_dma_address(struct drm_i915_gem_object *obj, pgoff_t n)
{
return i915_gem_object_get_dma_address_len(obj, n, NULL);
}
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_phys.c b/drivers/gpu/drm/i915/gem/i915_gem_phys.c
index 68453572275b..76efe98eaa14 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_phys.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_phys.c
@@ -28,6 +28,10 @@ static int i915_gem_object_get_pages_phys(struct drm_i915_gem_object *obj)
void *dst;
int i;
+ /* Contiguous chunk, with a single scatterlist element */
+ if (overflows_type(obj->base.size, sg->length))
+ return -E2BIG;
+
if (GEM_WARN_ON(i915_gem_object_needs_bit17_swizzle(obj)))
return -EINVAL;
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
index 937728840428..37d1efcd3ca6 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
@@ -60,7 +60,7 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st,
struct address_space *mapping,
unsigned int max_segment)
{
- const unsigned long page_count = size / PAGE_SIZE;
+ unsigned int page_count; /* restricted by sg_alloc_table */
unsigned long i;
struct scatterlist *sg;
struct page *page;
@@ -68,6 +68,10 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st,
gfp_t noreclaim;
int ret;
+ if (overflows_type(size / PAGE_SIZE, page_count))
+ return -E2BIG;
+
+ page_count = size / PAGE_SIZE;
/*
* If there's no chance of allocating enough pages for the whole
* object, bail early.
@@ -193,7 +197,6 @@ static int shmem_get_pages(struct drm_i915_gem_object *obj)
struct drm_i915_private *i915 = to_i915(obj->base.dev);
struct intel_memory_region *mem = obj->mm.region;
struct address_space *mapping = obj->base.filp->f_mapping;
- const unsigned long page_count = obj->base.size / PAGE_SIZE;
unsigned int max_segment = i915_sg_segment_size(i915->drm.dev);
struct sg_table *st;
struct sgt_iter sgt_iter;
@@ -235,8 +238,8 @@ rebuild_st:
goto rebuild_st;
} else {
dev_warn(i915->drm.dev,
- "Failed to DMA remap %lu pages\n",
- page_count);
+ "Failed to DMA remap %zu pages\n",
+ obj->base.size >> PAGE_SHIFT);
goto err_pages;
}
}
@@ -538,6 +541,20 @@ static int __create_shmem(struct drm_i915_private *i915,
drm_gem_private_object_init(&i915->drm, obj, size);
+ /* XXX: The __shmem_file_setup() function returns -EINVAL if size is
+ * greater than MAX_LFS_FILESIZE.
+ * To handle the same error as other code that returns -E2BIG when
+ * the size is too large, we add a code that returns -E2BIG when the
+ * size is larger than the size that can be handled.
+ * If BITS_PER_LONG is 32, size > MAX_LFS_FILESIZE is always false,
+ * so we only needs to check when BITS_PER_LONG is 64.
+ * If BITS_PER_LONG is 32, E2BIG checks are processed when
+ * i915_gem_object_size_2big() is called before init_object() callback
+ * is called.
+ */
+ if (BITS_PER_LONG == 64 && size > MAX_LFS_FILESIZE)
+ return -E2BIG;
+
if (i915->mm.gemfs)
filp = shmem_file_setup_with_mnt(i915->mm.gemfs, "i915", size,
flags);
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c b/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c
index 8dc5c8874d8a..b1672e054b21 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c
@@ -400,7 +400,7 @@ i915_gem_shrinker_vmap(struct notifier_block *nb, unsigned long event, void *ptr
mutex_lock(&to_gt(i915)->ggtt->vm.mutex);
list_for_each_entry_safe(vma, next,
&to_gt(i915)->ggtt->vm.bound_list, vm_link) {
- unsigned long count = vma->node.size >> PAGE_SHIFT;
+ unsigned long count = i915_vma_size(vma) >> PAGE_SHIFT;
struct drm_i915_gem_object *obj = vma->obj;
if (!vma->iomap || i915_vma_is_active(vma))
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c
index bc9521078807..90a967374b1a 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c
@@ -110,9 +110,7 @@ static int adjust_stolen(struct drm_i915_private *i915,
else
ggtt_start &= PGTBL_ADDRESS_LO_MASK;
- ggtt_res =
- (struct resource) DEFINE_RES_MEM(ggtt_start,
- ggtt_total_entries(ggtt) * 4);
+ ggtt_res = DEFINE_RES_MEM(ggtt_start, ggtt_total_entries(ggtt) * 4);
if (ggtt_res.start >= stolen[0].start && ggtt_res.start < stolen[0].end)
stolen[0].end = ggtt_res.start;
@@ -211,7 +209,7 @@ static void g4x_get_stolen_reserved(struct drm_i915_private *i915,
IS_GM45(i915) ?
CTG_STOLEN_RESERVED :
ELK_STOLEN_RESERVED);
- resource_size_t stolen_top = i915->dsm.end + 1;
+ resource_size_t stolen_top = i915->dsm.stolen.end + 1;
drm_dbg(&i915->drm, "%s_STOLEN_RESERVED = %08x\n",
IS_GM45(i915) ? "CTG" : "ELK", reg_val);
@@ -276,7 +274,7 @@ static void vlv_get_stolen_reserved(struct drm_i915_private *i915,
resource_size_t *size)
{
u32 reg_val = intel_uncore_read(uncore, GEN6_STOLEN_RESERVED);
- resource_size_t stolen_top = i915->dsm.end + 1;
+ resource_size_t stolen_top = i915->dsm.stolen.end + 1;
drm_dbg(&i915->drm, "GEN6_STOLEN_RESERVED = %08x\n", reg_val);
@@ -365,7 +363,7 @@ static void bdw_get_stolen_reserved(struct drm_i915_private *i915,
resource_size_t *size)
{
u32 reg_val = intel_uncore_read(uncore, GEN6_STOLEN_RESERVED);
- resource_size_t stolen_top = i915->dsm.end + 1;
+ resource_size_t stolen_top = i915->dsm.stolen.end + 1;
drm_dbg(&i915->drm, "GEN6_STOLEN_RESERVED = %08x\n", reg_val);
@@ -414,7 +412,7 @@ static void icl_get_stolen_reserved(struct drm_i915_private *i915,
}
/*
- * Initialize i915->dsm_reserved to contain the reserved space within the Data
+ * Initialize i915->dsm.reserved to contain the reserved space within the Data
* Stolen Memory. This is a range on the top of DSM that is reserved, not to
* be used by driver, so must be excluded from the region passed to the
* allocator later. In the spec this is also called as WOPCM.
@@ -430,7 +428,7 @@ static int init_reserved_stolen(struct drm_i915_private *i915)
resource_size_t reserved_size;
int ret = 0;
- stolen_top = i915->dsm.end + 1;
+ stolen_top = i915->dsm.stolen.end + 1;
reserved_base = stolen_top;
reserved_size = 0;
@@ -471,13 +469,12 @@ static int init_reserved_stolen(struct drm_i915_private *i915)
goto bail_out;
}
- i915->dsm_reserved =
- (struct resource)DEFINE_RES_MEM(reserved_base, reserved_size);
+ i915->dsm.reserved = DEFINE_RES_MEM(reserved_base, reserved_size);
- if (!resource_contains(&i915->dsm, &i915->dsm_reserved)) {
+ if (!resource_contains(&i915->dsm.stolen, &i915->dsm.reserved)) {
drm_err(&i915->drm,
"Stolen reserved area %pR outside stolen memory %pR\n",
- &i915->dsm_reserved, &i915->dsm);
+ &i915->dsm.reserved, &i915->dsm.stolen);
ret = -EINVAL;
goto bail_out;
}
@@ -485,8 +482,7 @@ static int init_reserved_stolen(struct drm_i915_private *i915)
return 0;
bail_out:
- i915->dsm_reserved =
- (struct resource)DEFINE_RES_MEM(reserved_base, 0);
+ i915->dsm.reserved = DEFINE_RES_MEM(reserved_base, 0);
return ret;
}
@@ -517,27 +513,27 @@ static int i915_gem_init_stolen(struct intel_memory_region *mem)
if (request_smem_stolen(i915, &mem->region))
return -ENOSPC;
- i915->dsm = mem->region;
+ i915->dsm.stolen = mem->region;
if (init_reserved_stolen(i915))
return -ENOSPC;
/* Exclude the reserved region from driver use */
- mem->region.end = i915->dsm_reserved.start - 1;
+ mem->region.end = i915->dsm.reserved.start - 1;
mem->io_size = min(mem->io_size, resource_size(&mem->region));
- i915->stolen_usable_size = resource_size(&mem->region);
+ i915->dsm.usable_size = resource_size(&mem->region);
drm_dbg(&i915->drm,
"Memory reserved for graphics device: %lluK, usable: %lluK\n",
- (u64)resource_size(&i915->dsm) >> 10,
- (u64)i915->stolen_usable_size >> 10);
+ (u64)resource_size(&i915->dsm.stolen) >> 10,
+ (u64)i915->dsm.usable_size >> 10);
- if (i915->stolen_usable_size == 0)
+ if (i915->dsm.usable_size == 0)
return -ENOSPC;
/* Basic memrange allocator for stolen space. */
- drm_mm_init(&i915->mm.stolen, 0, i915->stolen_usable_size);
+ drm_mm_init(&i915->mm.stolen, 0, i915->dsm.usable_size);
return 0;
}
@@ -587,7 +583,7 @@ i915_pages_create_for_stolen(struct drm_device *dev,
struct sg_table *st;
struct scatterlist *sg;
- GEM_BUG_ON(range_overflows(offset, size, resource_size(&i915->dsm)));
+ GEM_BUG_ON(range_overflows(offset, size, resource_size(&i915->dsm.stolen)));
/* We hide that we have no struct page backing our stolen object
* by wrapping the contiguous physical allocation with a fake
@@ -607,7 +603,7 @@ i915_pages_create_for_stolen(struct drm_device *dev,
sg->offset = 0;
sg->length = size;
- sg_dma_address(sg) = (dma_addr_t)i915->dsm.start + offset;
+ sg_dma_address(sg) = (dma_addr_t)i915->dsm.stolen.start + offset;
sg_dma_len(sg) = size;
return st;
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_tiling.c b/drivers/gpu/drm/i915/gem/i915_gem_tiling.c
index bc21b1c2350a..a049ca0b7980 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_tiling.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_tiling.c
@@ -168,11 +168,11 @@ static bool i915_vma_fence_prepare(struct i915_vma *vma,
return true;
size = i915_gem_fence_size(i915, vma->size, tiling_mode, stride);
- if (vma->node.size < size)
+ if (i915_vma_size(vma) < size)
return false;
alignment = i915_gem_fence_alignment(i915, vma->size, tiling_mode, stride);
- if (!IS_ALIGNED(vma->node.start, alignment))
+ if (!IS_ALIGNED(i915_ggtt_offset(vma), alignment))
return false;
return true;
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
index 1e50fb0d6bfc..7420276827a5 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
@@ -5,8 +5,8 @@
#include <linux/shmem_fs.h>
-#include <drm/ttm/ttm_bo_driver.h>
#include <drm/ttm/ttm_placement.h>
+#include <drm/ttm/ttm_tt.h>
#include <drm/drm_buddy.h>
#include "i915_drv.h"
@@ -140,13 +140,16 @@ i915_ttm_place_from_region(const struct intel_memory_region *mr,
if (flags & I915_BO_ALLOC_CONTIGUOUS)
place->flags |= TTM_PL_FLAG_CONTIGUOUS;
if (offset != I915_BO_INVALID_OFFSET) {
+ WARN_ON(overflows_type(offset >> PAGE_SHIFT, place->fpfn));
place->fpfn = offset >> PAGE_SHIFT;
+ WARN_ON(overflows_type(place->fpfn + (size >> PAGE_SHIFT), place->lpfn));
place->lpfn = place->fpfn + (size >> PAGE_SHIFT);
} else if (mr->io_size && mr->io_size < mr->total) {
if (flags & I915_BO_ALLOC_GPU_ONLY) {
place->flags |= TTM_PL_FLAG_TOPDOWN;
} else {
place->fpfn = 0;
+ WARN_ON(overflows_type(mr->io_size >> PAGE_SHIFT, place->lpfn));
place->lpfn = mr->io_size >> PAGE_SHIFT;
}
}
@@ -271,8 +274,6 @@ static struct ttm_tt *i915_ttm_tt_create(struct ttm_buffer_object *bo,
{
struct drm_i915_private *i915 = container_of(bo->bdev, typeof(*i915),
bdev);
- struct ttm_resource_manager *man =
- ttm_manager_type(bo->bdev, bo->resource->mem_type);
struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo);
unsigned long ccs_pages = 0;
enum ttm_caching caching;
@@ -286,8 +287,8 @@ static struct ttm_tt *i915_ttm_tt_create(struct ttm_buffer_object *bo,
if (!i915_tt)
return NULL;
- if (obj->flags & I915_BO_ALLOC_CPU_CLEAR &&
- man->use_tt)
+ if (obj->flags & I915_BO_ALLOC_CPU_CLEAR && (!bo->resource ||
+ ttm_manager_type(bo->bdev, bo->resource->mem_type)->use_tt))
page_flags |= TTM_TT_FLAG_ZERO_ALLOC;
caching = i915_ttm_select_tt_caching(obj);
@@ -599,13 +600,16 @@ i915_ttm_resource_get_st(struct drm_i915_gem_object *obj,
static int i915_ttm_truncate(struct drm_i915_gem_object *obj)
{
struct ttm_buffer_object *bo = i915_gem_to_ttm(obj);
- int err;
+ long err;
WARN_ON_ONCE(obj->mm.madv == I915_MADV_WILLNEED);
- err = ttm_bo_wait(bo, true, false);
- if (err)
+ err = dma_resv_wait_timeout(bo->base.resv, DMA_RESV_USAGE_BOOKKEEP,
+ true, 15 * HZ);
+ if (err < 0)
return err;
+ if (err == 0)
+ return -EBUSY;
err = i915_ttm_move_notify(bo);
if (err)
@@ -689,7 +693,7 @@ static unsigned long i915_ttm_io_mem_pfn(struct ttm_buffer_object *bo,
GEM_WARN_ON(bo->ttm);
base = obj->mm.region->iomap.base - obj->mm.region->region.start;
- sg = __i915_gem_object_get_sg(obj, &obj->ttm.get_io_page, page_offset, &ofs, true);
+ sg = i915_gem_object_page_iter_get_sg(obj, &obj->ttm.get_io_page, page_offset, &ofs);
return ((base + sg_dma_address(sg)) >> PAGE_SHIFT) + ofs;
}
@@ -832,6 +836,10 @@ static int i915_ttm_get_pages(struct drm_i915_gem_object *obj)
struct ttm_place requested, busy[I915_TTM_MAX_PLACEMENTS];
struct ttm_placement placement;
+ /* restricted by sg_alloc_table */
+ if (overflows_type(obj->base.size >> PAGE_SHIFT, unsigned int))
+ return -E2BIG;
+
GEM_BUG_ON(obj->mm.n_placements > I915_TTM_MAX_PLACEMENTS);
/* Move to the requested placement. */
@@ -1048,7 +1056,26 @@ static vm_fault_t vm_fault_ttm(struct vm_fault *vmf)
return VM_FAULT_SIGBUS;
}
- if (!i915_ttm_resource_mappable(bo->resource)) {
+ /*
+ * This must be swapped out with shmem ttm_tt (pipeline-gutting).
+ * Calling ttm_bo_validate() here with TTM_PL_SYSTEM should only go as
+ * far as far doing a ttm_bo_move_null(), which should skip all the
+ * other junk.
+ */
+ if (!bo->resource) {
+ struct ttm_operation_ctx ctx = {
+ .interruptible = true,
+ .no_wait_gpu = true, /* should be idle already */
+ };
+
+ GEM_BUG_ON(!bo->ttm || !(bo->ttm->page_flags & TTM_TT_FLAG_SWAPPED));
+
+ ret = ttm_bo_validate(bo, i915_ttm_sys_placement(), &ctx);
+ if (ret) {
+ dma_resv_unlock(bo->base.resv);
+ return VM_FAULT_SIGBUS;
+ }
+ } else if (!i915_ttm_resource_mappable(bo->resource)) {
int err = -ENODEV;
int i;
@@ -1302,6 +1329,17 @@ int __i915_gem_ttm_object_init(struct intel_memory_region *mem,
ret = ttm_bo_init_reserved(&i915->bdev, i915_gem_to_ttm(obj), bo_type,
&i915_sys_placement, page_size >> PAGE_SHIFT,
&ctx, NULL, NULL, i915_ttm_bo_destroy);
+
+ /*
+ * XXX: The ttm_bo_init_reserved() functions returns -ENOSPC if the size
+ * is too big to add vma. The direct function that returns -ENOSPC is
+ * drm_mm_insert_node_in_range(). To handle the same error as other code
+ * that returns -E2BIG when the size is too large, it converts -ENOSPC to
+ * -E2BIG.
+ */
+ if (size >> PAGE_SHIFT > INT_MAX && ret == -ENOSPC)
+ ret = -E2BIG;
+
if (ret)
return i915_ttm_err_to_gem(ret);
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c
index f59f812dc6d2..76dd9e5e1a8b 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c
@@ -3,7 +3,7 @@
* Copyright © 2021 Intel Corporation
*/
-#include <drm/ttm/ttm_bo_driver.h>
+#include <drm/ttm/ttm_tt.h>
#include "i915_deps.h"
#include "i915_drv.h"
@@ -103,7 +103,27 @@ void i915_ttm_adjust_gem_after_move(struct drm_i915_gem_object *obj)
{
struct ttm_buffer_object *bo = i915_gem_to_ttm(obj);
unsigned int cache_level;
+ unsigned int mem_flags;
unsigned int i;
+ int mem_type;
+
+ /*
+ * We might have been purged (or swapped out) if the resource is NULL,
+ * in which case the SYSTEM placement is the closest match to describe
+ * the current domain. If the object is ever used in this state then we
+ * will require moving it again.
+ */
+ if (!bo->resource) {
+ mem_flags = I915_BO_FLAG_STRUCT_PAGE;
+ mem_type = I915_PL_SYSTEM;
+ cache_level = I915_CACHE_NONE;
+ } else {
+ mem_flags = i915_ttm_cpu_maps_iomem(bo->resource) ? I915_BO_FLAG_IOMEM :
+ I915_BO_FLAG_STRUCT_PAGE;
+ mem_type = bo->resource->mem_type;
+ cache_level = i915_ttm_cache_level(to_i915(bo->base.dev), bo->resource,
+ bo->ttm);
+ }
/*
* If object was moved to an allowable region, update the object
@@ -111,11 +131,11 @@ void i915_ttm_adjust_gem_after_move(struct drm_i915_gem_object *obj)
* in an allowable region, it's evicted and we don't update the
* object region.
*/
- if (intel_region_to_ttm_type(obj->mm.region) != bo->resource->mem_type) {
+ if (intel_region_to_ttm_type(obj->mm.region) != mem_type) {
for (i = 0; i < obj->mm.n_placements; ++i) {
struct intel_memory_region *mr = obj->mm.placements[i];
- if (intel_region_to_ttm_type(mr) == bo->resource->mem_type &&
+ if (intel_region_to_ttm_type(mr) == mem_type &&
mr != obj->mm.region) {
i915_gem_object_release_memory_region(obj);
i915_gem_object_init_memory_region(obj, mr);
@@ -125,12 +145,8 @@ void i915_ttm_adjust_gem_after_move(struct drm_i915_gem_object *obj)
}
obj->mem_flags &= ~(I915_BO_FLAG_STRUCT_PAGE | I915_BO_FLAG_IOMEM);
+ obj->mem_flags |= mem_flags;
- obj->mem_flags |= i915_ttm_cpu_maps_iomem(bo->resource) ? I915_BO_FLAG_IOMEM :
- I915_BO_FLAG_STRUCT_PAGE;
-
- cache_level = i915_ttm_cache_level(to_i915(bo->base.dev), bo->resource,
- bo->ttm);
i915_gem_object_set_cache_coherency(obj, cache_level);
}
@@ -565,6 +581,32 @@ int i915_ttm_move(struct ttm_buffer_object *bo, bool evict,
return 0;
}
+ if (!bo->resource) {
+ if (dst_mem->mem_type != TTM_PL_SYSTEM) {
+ hop->mem_type = TTM_PL_SYSTEM;
+ hop->flags = TTM_PL_FLAG_TEMPORARY;
+ return -EMULTIHOP;
+ }
+
+ /*
+ * This is only reached when first creating the object, or if
+ * the object was purged or swapped out (pipeline-gutting). For
+ * the former we can safely skip all of the below since we are
+ * only using a dummy SYSTEM placement here. And with the latter
+ * we will always re-enter here with bo->resource set correctly
+ * (as per the above), since this is part of a multi-hop
+ * sequence, where at the end we can do the move for real.
+ *
+ * The special case here is when the dst_mem is TTM_PL_SYSTEM,
+ * which doens't require any kind of move, so it should be safe
+ * to skip all the below and call ttm_bo_move_null() here, where
+ * the caller in __i915_ttm_get_pages() will take care of the
+ * rest, since we should have a valid ttm_tt.
+ */
+ ttm_bo_move_null(bo, dst_mem);
+ return 0;
+ }
+
ret = i915_ttm_move_notify(bo);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_userptr.c b/drivers/gpu/drm/i915/gem/i915_gem_userptr.c
index 9348b1804d53..1d3ebdf4069b 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_userptr.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_userptr.c
@@ -128,12 +128,16 @@ static void i915_gem_object_userptr_drop_ref(struct drm_i915_gem_object *obj)
static int i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj)
{
- const unsigned long num_pages = obj->base.size >> PAGE_SHIFT;
unsigned int max_segment = i915_sg_segment_size(obj->base.dev->dev);
struct sg_table *st;
struct page **pvec;
+ unsigned int num_pages; /* limited by sg_alloc_table_from_pages_segment */
int ret;
+ if (overflows_type(obj->base.size >> PAGE_SHIFT, num_pages))
+ return -E2BIG;
+
+ num_pages = obj->base.size >> PAGE_SHIFT;
st = kmalloc(sizeof(*st), GFP_KERNEL);
if (!st)
return -ENOMEM;
diff --git a/drivers/gpu/drm/i915/gem/selftests/huge_gem_object.c b/drivers/gpu/drm/i915/gem/selftests/huge_gem_object.c
index cbd9b624a788..bac957755068 100644
--- a/drivers/gpu/drm/i915/gem/selftests/huge_gem_object.c
+++ b/drivers/gpu/drm/i915/gem/selftests/huge_gem_object.c
@@ -29,11 +29,15 @@ static int huge_get_pages(struct drm_i915_gem_object *obj)
{
#define GFP (GFP_KERNEL | __GFP_NOWARN | __GFP_RETRY_MAYFAIL)
const unsigned long nreal = obj->scratch / PAGE_SIZE;
- const unsigned long npages = obj->base.size / PAGE_SIZE;
+ unsigned int npages; /* restricted by sg_alloc_table */
struct scatterlist *sg, *src, *end;
struct sg_table *pages;
unsigned long n;
+ if (overflows_type(obj->base.size / PAGE_SIZE, npages))
+ return -E2BIG;
+
+ npages = obj->base.size / PAGE_SIZE;
pages = kmalloc(sizeof(*pages), GFP);
if (!pages)
return -ENOMEM;
diff --git a/drivers/gpu/drm/i915/gem/selftests/huge_pages.c b/drivers/gpu/drm/i915/gem/selftests/huge_pages.c
index 977dead10ab5..defece0bcb81 100644
--- a/drivers/gpu/drm/i915/gem/selftests/huge_pages.c
+++ b/drivers/gpu/drm/i915/gem/selftests/huge_pages.c
@@ -84,6 +84,10 @@ static int get_huge_pages(struct drm_i915_gem_object *obj)
unsigned int sg_page_sizes;
u64 rem;
+ /* restricted by sg_alloc_table */
+ if (overflows_type(obj->base.size >> PAGE_SHIFT, unsigned int))
+ return -E2BIG;
+
st = kmalloc(sizeof(*st), GFP);
if (!st)
return -ENOMEM;
@@ -212,6 +216,10 @@ static int fake_get_huge_pages(struct drm_i915_gem_object *obj)
struct scatterlist *sg;
u64 rem;
+ /* restricted by sg_alloc_table */
+ if (overflows_type(obj->base.size >> PAGE_SHIFT, unsigned int))
+ return -E2BIG;
+
st = kmalloc(sizeof(*st), GFP);
if (!st)
return -ENOMEM;
@@ -400,7 +408,7 @@ static int igt_check_page_sizes(struct i915_vma *vma)
* Maintaining alignment is required to utilise huge pages in the ppGGT.
*/
if (i915_gem_object_is_lmem(obj) &&
- IS_ALIGNED(vma->node.start, SZ_2M) &&
+ IS_ALIGNED(i915_vma_offset(vma), SZ_2M) &&
vma->page_sizes.sg & SZ_2M &&
vma->resource->page_sizes_gtt < SZ_2M) {
pr_err("gtt pages mismatch for LMEM, expected 2M GTT pages, sg(%u), gtt(%u)\n",
diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_client_blt.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_client_blt.c
index 692a16914ca0..3bb1f7f0110e 100644
--- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_client_blt.c
+++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_client_blt.c
@@ -194,12 +194,12 @@ static int prepare_blit(const struct tiled_blits *t,
*cs++ = src_4t | dst_4t | BLT_DEPTH_32 | dst_pitch;
*cs++ = 0;
*cs++ = t->height << 16 | t->width;
- *cs++ = lower_32_bits(dst->vma->node.start);
- *cs++ = upper_32_bits(dst->vma->node.start);
+ *cs++ = lower_32_bits(i915_vma_offset(dst->vma));
+ *cs++ = upper_32_bits(i915_vma_offset(dst->vma));
*cs++ = 0;
*cs++ = src_pitch;
- *cs++ = lower_32_bits(src->vma->node.start);
- *cs++ = upper_32_bits(src->vma->node.start);
+ *cs++ = lower_32_bits(i915_vma_offset(src->vma));
+ *cs++ = upper_32_bits(i915_vma_offset(src->vma));
} else {
if (ver >= 6) {
*cs++ = MI_LOAD_REGISTER_IMM(1);
@@ -240,14 +240,14 @@ static int prepare_blit(const struct tiled_blits *t,
*cs++ = BLT_DEPTH_32 | BLT_ROP_SRC_COPY | dst_pitch;
*cs++ = 0;
*cs++ = t->height << 16 | t->width;
- *cs++ = lower_32_bits(dst->vma->node.start);
+ *cs++ = lower_32_bits(i915_vma_offset(dst->vma));
if (use_64b_reloc)
- *cs++ = upper_32_bits(dst->vma->node.start);
+ *cs++ = upper_32_bits(i915_vma_offset(dst->vma));
*cs++ = 0;
*cs++ = src_pitch;
- *cs++ = lower_32_bits(src->vma->node.start);
+ *cs++ = lower_32_bits(i915_vma_offset(src->vma));
if (use_64b_reloc)
- *cs++ = upper_32_bits(src->vma->node.start);
+ *cs++ = upper_32_bits(i915_vma_offset(src->vma));
}
*cs++ = MI_BATCH_BUFFER_END;
@@ -462,7 +462,7 @@ static int pin_buffer(struct i915_vma *vma, u64 addr)
{
int err;
- if (drm_mm_node_allocated(&vma->node) && vma->node.start != addr) {
+ if (drm_mm_node_allocated(&vma->node) && i915_vma_offset(vma) != addr) {
err = i915_vma_unbind_unlocked(vma);
if (err)
return err;
@@ -472,6 +472,7 @@ static int pin_buffer(struct i915_vma *vma, u64 addr)
if (err)
return err;
+ GEM_BUG_ON(i915_vma_offset(vma) != addr);
return 0;
}
@@ -518,8 +519,8 @@ tiled_blit(struct tiled_blits *t,
err = igt_vma_move_to_active_unlocked(dst->vma, rq, 0);
if (!err)
err = rq->engine->emit_bb_start(rq,
- t->batch->node.start,
- t->batch->node.size,
+ i915_vma_offset(t->batch),
+ i915_vma_size(t->batch),
0);
i915_request_get(rq);
i915_request_add(rq);
diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_coherency.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_coherency.c
index c228fe4aba50..3bef1beec7cb 100644
--- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_coherency.c
+++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_coherency.c
@@ -222,7 +222,7 @@ static int gpu_set(struct context *ctx, unsigned long offset, u32 v)
}
if (GRAPHICS_VER(ctx->engine->i915) >= 8) {
- *cs++ = MI_STORE_DWORD_IMM_GEN4 | 1 << 22;
+ *cs++ = MI_STORE_DWORD_IMM_GEN4 | MI_USE_GGTT;
*cs++ = lower_32_bits(i915_ggtt_offset(vma) + offset);
*cs++ = upper_32_bits(i915_ggtt_offset(vma) + offset);
*cs++ = v;
diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
index a0ff51d71d07..a81fa6a20f5a 100644
--- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
@@ -469,7 +469,8 @@ static int gpu_fill(struct intel_context *ce,
static int cpu_fill(struct drm_i915_gem_object *obj, u32 value)
{
const bool has_llc = HAS_LLC(to_i915(obj->base.dev));
- unsigned int n, m, need_flush;
+ unsigned int need_flush;
+ unsigned long n, m;
int err;
i915_gem_object_lock(obj, NULL);
@@ -499,7 +500,8 @@ out:
static noinline int cpu_check(struct drm_i915_gem_object *obj,
unsigned int idx, unsigned int max)
{
- unsigned int n, m, needs_flush;
+ unsigned int needs_flush;
+ unsigned long n;
int err;
i915_gem_object_lock(obj, NULL);
@@ -508,7 +510,7 @@ static noinline int cpu_check(struct drm_i915_gem_object *obj,
goto out_unlock;
for (n = 0; n < real_page_count(obj); n++) {
- u32 *map;
+ u32 *map, m;
map = kmap_atomic(i915_gem_object_get_page(obj, n));
if (needs_flush & CLFLUSH_BEFORE)
@@ -516,7 +518,7 @@ static noinline int cpu_check(struct drm_i915_gem_object *obj,
for (m = 0; m < max; m++) {
if (map[m] != m) {
- pr_err("%pS: Invalid value at object %d page %d/%ld, offset %d/%d: found %x expected %x\n",
+ pr_err("%pS: Invalid value at object %d page %ld/%ld, offset %d/%d: found %x expected %x\n",
__builtin_return_address(0), idx,
n, real_page_count(obj), m, max,
map[m], m);
@@ -527,7 +529,7 @@ static noinline int cpu_check(struct drm_i915_gem_object *obj,
for (; m < DW_PER_PAGE; m++) {
if (map[m] != STACK_MAGIC) {
- pr_err("%pS: Invalid value at object %d page %d, offset %d: found %x expected %x (uninitialised)\n",
+ pr_err("%pS: Invalid value at object %d page %ld, offset %d: found %x expected %x (uninitialised)\n",
__builtin_return_address(0), idx, n, m,
map[m], STACK_MAGIC);
err = -EINVAL;
@@ -914,8 +916,8 @@ static int rpcs_query_batch(struct drm_i915_gem_object *rpcs,
*cmd++ = MI_STORE_REGISTER_MEM_GEN8;
*cmd++ = i915_mmio_reg_offset(GEN8_R_PWR_CLK_STATE(engine->mmio_base));
- *cmd++ = lower_32_bits(vma->node.start);
- *cmd++ = upper_32_bits(vma->node.start);
+ *cmd++ = lower_32_bits(i915_vma_offset(vma));
+ *cmd++ = upper_32_bits(i915_vma_offset(vma));
*cmd = MI_BATCH_BUFFER_END;
__i915_gem_object_flush_map(rpcs, 0, 64);
@@ -999,7 +1001,8 @@ retry:
}
err = rq->engine->emit_bb_start(rq,
- batch->node.start, batch->node.size,
+ i915_vma_offset(batch),
+ i915_vma_size(batch),
0);
if (err)
goto skip_request;
@@ -1548,9 +1551,7 @@ static int write_to_scratch(struct i915_gem_context *ctx,
goto err_unpin;
}
- i915_vma_lock(vma);
- err = i915_vma_move_to_active(vma, rq, 0);
- i915_vma_unlock(vma);
+ err = igt_vma_move_to_active_unlocked(vma, rq, 0);
if (err)
goto skip_request;
@@ -1560,7 +1561,8 @@ static int write_to_scratch(struct i915_gem_context *ctx,
goto skip_request;
}
- err = engine->emit_bb_start(rq, vma->node.start, vma->node.size, 0);
+ err = engine->emit_bb_start(rq, i915_vma_offset(vma),
+ i915_vma_size(vma), 0);
if (err)
goto skip_request;
@@ -1665,7 +1667,7 @@ static int read_from_scratch(struct i915_gem_context *ctx,
*cmd++ = offset;
*cmd++ = MI_STORE_REGISTER_MEM | MI_USE_GGTT;
*cmd++ = reg;
- *cmd++ = vma->node.start + result;
+ *cmd++ = i915_vma_offset(vma) + result;
*cmd = MI_BATCH_BUFFER_END;
i915_gem_object_flush_map(obj);
@@ -1682,9 +1684,7 @@ static int read_from_scratch(struct i915_gem_context *ctx,
goto err_unpin;
}
- i915_vma_lock(vma);
- err = i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE);
- i915_vma_unlock(vma);
+ err = igt_vma_move_to_active_unlocked(vma, rq, EXEC_OBJECT_WRITE);
if (err)
goto skip_request;
@@ -1694,7 +1694,8 @@ static int read_from_scratch(struct i915_gem_context *ctx,
goto skip_request;
}
- err = engine->emit_bb_start(rq, vma->node.start, vma->node.size, flags);
+ err = engine->emit_bb_start(rq, i915_vma_offset(vma),
+ i915_vma_size(vma), flags);
if (err)
goto skip_request;
diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c
index 3f658d5717d8..56279908ed30 100644
--- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c
+++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c
@@ -97,11 +97,11 @@ static int check_partial_mapping(struct drm_i915_gem_object *obj,
struct drm_i915_private *i915 = to_i915(obj->base.dev);
struct i915_gtt_view view;
struct i915_vma *vma;
+ unsigned long offset;
unsigned long page;
u32 __iomem *io;
struct page *p;
unsigned int n;
- u64 offset;
u32 *cpu;
int err;
@@ -158,7 +158,7 @@ static int check_partial_mapping(struct drm_i915_gem_object *obj,
cpu = kmap(p) + offset_in_page(offset);
drm_clflush_virt_range(cpu, sizeof(*cpu));
if (*cpu != (u32)page) {
- pr_err("Partial view for %lu [%u] (offset=%llu, size=%u [%llu, row size %u], fence=%d, tiling=%d, stride=%d) misalignment, expected write to page (%llu + %u [0x%llx]) of 0x%x, found 0x%x\n",
+ pr_err("Partial view for %lu [%u] (offset=%llu, size=%u [%llu, row size %u], fence=%d, tiling=%d, stride=%d) misalignment, expected write to page (%lu + %u [0x%lx]) of 0x%x, found 0x%x\n",
page, n,
view.partial.offset,
view.partial.size,
@@ -214,10 +214,10 @@ static int check_partial_mappings(struct drm_i915_gem_object *obj,
for_each_prime_number_from(page, 1, npages) {
struct i915_gtt_view view =
compute_partial_view(obj, page, MIN_CHUNK_PAGES);
+ unsigned long offset;
u32 __iomem *io;
struct page *p;
unsigned int n;
- u64 offset;
u32 *cpu;
GEM_BUG_ON(view.partial.size > nreal);
@@ -254,7 +254,7 @@ static int check_partial_mappings(struct drm_i915_gem_object *obj,
cpu = kmap(p) + offset_in_page(offset);
drm_clflush_virt_range(cpu, sizeof(*cpu));
if (*cpu != (u32)page) {
- pr_err("Partial view for %lu [%u] (offset=%llu, size=%u [%llu, row size %u], fence=%d, tiling=%d, stride=%d) misalignment, expected write to page (%llu + %u [0x%llx]) of 0x%x, found 0x%x\n",
+ pr_err("Partial view for %lu [%u] (offset=%llu, size=%u [%llu, row size %u], fence=%d, tiling=%d, stride=%d) misalignment, expected write to page (%lu + %u [0x%lx]) of 0x%x, found 0x%x\n",
page, n,
view.partial.offset,
view.partial.size,
@@ -1609,7 +1609,7 @@ retry:
err = i915_vma_move_to_active(vma, rq, 0);
- err = engine->emit_bb_start(rq, vma->node.start, 0, 0);
+ err = engine->emit_bb_start(rq, i915_vma_offset(vma), 0, 0);
i915_request_get(rq);
i915_request_add(rq);
diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_object.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_object.c
index bdf5bb40ccf1..19e374f68ff7 100644
--- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_object.c
+++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_object.c
@@ -33,10 +33,10 @@ out:
static int igt_gem_huge(void *arg)
{
- const unsigned int nreal = 509; /* just to be awkward */
+ const unsigned long nreal = 509; /* just to be awkward */
struct drm_i915_private *i915 = arg;
struct drm_i915_gem_object *obj;
- unsigned int n;
+ unsigned long n;
int err;
/* Basic sanitycheck of our huge fake object allocation */
@@ -49,7 +49,7 @@ static int igt_gem_huge(void *arg)
err = i915_gem_object_pin_pages_unlocked(obj);
if (err) {
- pr_err("Failed to allocate %u pages (%lu total), err=%d\n",
+ pr_err("Failed to allocate %lu pages (%lu total), err=%d\n",
nreal, obj->base.size / PAGE_SIZE, err);
goto out;
}
@@ -57,7 +57,7 @@ static int igt_gem_huge(void *arg)
for (n = 0; n < obj->base.size / PAGE_SIZE; n++) {
if (i915_gem_object_get_page(obj, n) !=
i915_gem_object_get_page(obj, n % nreal)) {
- pr_err("Page lookup mismatch at index %u [%u]\n",
+ pr_err("Page lookup mismatch at index %lu [%lu]\n",
n, n % nreal);
err = -EINVAL;
goto out_unpin;
diff --git a/drivers/gpu/drm/i915/gem/selftests/igt_gem_utils.c b/drivers/gpu/drm/i915/gem/selftests/igt_gem_utils.c
index 374b10ac430e..20a232a140b0 100644
--- a/drivers/gpu/drm/i915/gem/selftests/igt_gem_utils.c
+++ b/drivers/gpu/drm/i915/gem/selftests/igt_gem_utils.c
@@ -62,8 +62,8 @@ igt_emit_store_dw(struct i915_vma *vma,
goto err;
}
- GEM_BUG_ON(offset + (count - 1) * PAGE_SIZE > vma->node.size);
- offset += vma->node.start;
+ GEM_BUG_ON(offset + (count - 1) * PAGE_SIZE > i915_vma_size(vma));
+ offset += i915_vma_offset(vma);
for (n = 0; n < count; n++) {
if (ver >= 8) {
@@ -130,15 +130,11 @@ int igt_gpu_fill_dw(struct intel_context *ce,
goto err_batch;
}
- i915_vma_lock(batch);
- err = i915_vma_move_to_active(batch, rq, 0);
- i915_vma_unlock(batch);
+ err = igt_vma_move_to_active_unlocked(batch, rq, 0);
if (err)
goto skip_request;
- i915_vma_lock(vma);
- err = i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE);
- i915_vma_unlock(vma);
+ err = igt_vma_move_to_active_unlocked(vma, rq, EXEC_OBJECT_WRITE);
if (err)
goto skip_request;
@@ -147,7 +143,8 @@ int igt_gpu_fill_dw(struct intel_context *ce,
flags |= I915_DISPATCH_SECURE;
err = rq->engine->emit_bb_start(rq,
- batch->node.start, batch->node.size,
+ i915_vma_offset(batch),
+ i915_vma_size(batch),
flags);
skip_request:
diff --git a/drivers/gpu/drm/i915/gem/selftests/igt_gem_utils.h b/drivers/gpu/drm/i915/gem/selftests/igt_gem_utils.h
index 1379fbc14431..71a3ca8a8865 100644
--- a/drivers/gpu/drm/i915/gem/selftests/igt_gem_utils.h
+++ b/drivers/gpu/drm/i915/gem/selftests/igt_gem_utils.h
@@ -38,7 +38,7 @@ igt_vma_move_to_active_unlocked(struct i915_vma *vma, struct i915_request *rq,
int err;
i915_vma_lock(vma);
- err = _i915_vma_move_to_active(vma, rq, &rq->fence, flags);
+ err = i915_vma_move_to_active(vma, rq, flags);
i915_vma_unlock(vma);
return err;
}
diff --git a/drivers/gpu/drm/i915/gt/gen7_renderclear.c b/drivers/gpu/drm/i915/gt/gen7_renderclear.c
index 317efb145787..d38b914d1206 100644
--- a/drivers/gpu/drm/i915/gt/gen7_renderclear.c
+++ b/drivers/gpu/drm/i915/gt/gen7_renderclear.c
@@ -106,7 +106,7 @@ static u32 batch_offset(const struct batch_chunk *bc, u32 *cs)
static u32 batch_addr(const struct batch_chunk *bc)
{
- return bc->vma->node.start;
+ return i915_vma_offset(bc->vma);
}
static void batch_add(struct batch_chunk *bc, const u32 d)
diff --git a/drivers/gpu/drm/i915/gt/intel_engine.h b/drivers/gpu/drm/i915/gt/intel_engine.h
index 7a4504ea35c3..b58c30ac8ef0 100644
--- a/drivers/gpu/drm/i915/gt/intel_engine.h
+++ b/drivers/gpu/drm/i915/gt/intel_engine.h
@@ -172,6 +172,8 @@ intel_write_status_page(struct intel_engine_cs *engine, int reg, u32 value)
#define I915_GEM_HWS_MIGRATE (0x42 * sizeof(u32))
#define I915_GEM_HWS_PXP 0x60
#define I915_GEM_HWS_PXP_ADDR (I915_GEM_HWS_PXP * sizeof(u32))
+#define I915_GEM_HWS_GSC 0x62
+#define I915_GEM_HWS_GSC_ADDR (I915_GEM_HWS_GSC * sizeof(u32))
#define I915_GEM_HWS_SCRATCH 0x80
#define I915_HWS_CSB_BUF0_INDEX 0x10
diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c
index d37931e16fd9..d4e29da74612 100644
--- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c
+++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c
@@ -894,6 +894,24 @@ static intel_engine_mask_t init_engine_mask(struct intel_gt *gt)
engine_mask_apply_compute_fuses(gt);
engine_mask_apply_copy_fuses(gt);
+ /*
+ * The only use of the GSC CS is to load and communicate with the GSC
+ * FW, so we have no use for it if we don't have the FW.
+ *
+ * IMPORTANT: in cases where we don't have the GSC FW, we have a
+ * catch-22 situation that breaks media C6 due to 2 requirements:
+ * 1) once turned on, the GSC power well will not go to sleep unless the
+ * GSC FW is loaded.
+ * 2) to enable idling (which is required for media C6) we need to
+ * initialize the IDLE_MSG register for the GSC CS and do at least 1
+ * submission, which will wake up the GSC power well.
+ */
+ if (__HAS_ENGINE(info->engine_mask, GSC0) && !intel_uc_wants_gsc_uc(&gt->uc)) {
+ drm_notice(&gt->i915->drm,
+ "No GSC FW selected, disabling GSC CS and media C6\n");
+ info->engine_mask &= ~BIT(GSC0);
+ }
+
return info->engine_mask;
}
@@ -1476,10 +1494,12 @@ static int __intel_engine_stop_cs(struct intel_engine_cs *engine,
intel_uncore_write_fw(uncore, mode, _MASKED_BIT_ENABLE(STOP_RING));
/*
- * Wa_22011802037 : gen11, gen12, Prior to doing a reset, ensure CS is
+ * Wa_22011802037: Prior to doing a reset, ensure CS is
* stopped, set ring stop bit and prefetch disable bit to halt CS
*/
- if (IS_GRAPHICS_VER(engine->i915, 11, 12))
+ if (IS_MTL_GRAPHICS_STEP(engine->i915, M, STEP_A0, STEP_B0) ||
+ (GRAPHICS_VER(engine->i915) >= 11 &&
+ GRAPHICS_VER_FULL(engine->i915) < IP_VER(12, 70)))
intel_uncore_write_fw(uncore, RING_MODE_GEN7(engine->mmio_base),
_MASKED_BIT_ENABLE(GEN12_GFX_PREFETCH_DISABLE));
@@ -1564,11 +1584,8 @@ static u32 __cs_pending_mi_force_wakes(struct intel_engine_cs *engine)
};
u32 val;
- if (!_reg[engine->id].reg) {
- drm_err(&engine->i915->drm,
- "MSG IDLE undefined for engine id %u\n", engine->id);
+ if (!_reg[engine->id].reg)
return 0;
- }
val = intel_uncore_read(engine->uncore, _reg[engine->id]);
diff --git a/drivers/gpu/drm/i915/gt/intel_engine_pm.c b/drivers/gpu/drm/i915/gt/intel_engine_pm.c
index b0a4a2dbe3ee..e971b153fda9 100644
--- a/drivers/gpu/drm/i915/gt/intel_engine_pm.c
+++ b/drivers/gpu/drm/i915/gt/intel_engine_pm.c
@@ -15,6 +15,22 @@
#include "intel_rc6.h"
#include "intel_ring.h"
#include "shmem_utils.h"
+#include "intel_gt_regs.h"
+
+static void intel_gsc_idle_msg_enable(struct intel_engine_cs *engine)
+{
+ struct drm_i915_private *i915 = engine->i915;
+
+ if (IS_METEORLAKE(i915) && engine->id == GSC0) {
+ intel_uncore_write(engine->gt->uncore,
+ RC_PSMI_CTRL_GSCCS,
+ _MASKED_BIT_DISABLE(IDLE_MSG_DISABLE));
+ /* hysteresis 0xA=5us as recommended in spec*/
+ intel_uncore_write(engine->gt->uncore,
+ PWRCTX_MAXCNT_GSCCS,
+ 0xA);
+ }
+}
static void dbg_poison_ce(struct intel_context *ce)
{
@@ -275,6 +291,8 @@ void intel_engine_init__pm(struct intel_engine_cs *engine)
intel_wakeref_init(&engine->wakeref, rpm, &wf_ops);
intel_engine_init_heartbeat(engine);
+
+ intel_gsc_idle_msg_enable(engine);
}
/**
diff --git a/drivers/gpu/drm/i915/gt/intel_engine_regs.h b/drivers/gpu/drm/i915/gt/intel_engine_regs.h
index ee3efd06ee54..6b9d9f837669 100644
--- a/drivers/gpu/drm/i915/gt/intel_engine_regs.h
+++ b/drivers/gpu/drm/i915/gt/intel_engine_regs.h
@@ -81,6 +81,7 @@
#define RING_EIR(base) _MMIO((base) + 0xb0)
#define RING_EMR(base) _MMIO((base) + 0xb4)
#define RING_ESR(base) _MMIO((base) + 0xb8)
+#define GEN12_STATE_ACK_DEBUG(base) _MMIO((base) + 0xbc)
#define RING_INSTPM(base) _MMIO((base) + 0xc0)
#define RING_CMD_CCTL(base) _MMIO((base) + 0xc4)
#define ACTHD(base) _MMIO((base) + 0xc8)
diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
index 21cb5b69d82e..1bbe6708d0a7 100644
--- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
+++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
@@ -2989,10 +2989,12 @@ static void execlists_reset_prepare(struct intel_engine_cs *engine)
intel_engine_stop_cs(engine);
/*
- * Wa_22011802037:gen11/gen12: In addition to stopping the cs, we need
+ * Wa_22011802037: In addition to stopping the cs, we need
* to wait for any pending mi force wakeups
*/
- if (IS_GRAPHICS_VER(engine->i915, 11, 12))
+ if (IS_MTL_GRAPHICS_STEP(engine->i915, M, STEP_A0, STEP_B0) ||
+ (GRAPHICS_VER(engine->i915) >= 11 &&
+ GRAPHICS_VER_FULL(engine->i915) < IP_VER(12, 70)))
intel_engine_wait_for_pending_mi_fw(engine);
engine->execlists.reset_ccid = active_ccid(engine);
@@ -4148,17 +4150,6 @@ void intel_execlists_show_requests(struct intel_engine_cs *engine,
spin_unlock_irqrestore(&sched_engine->lock, flags);
}
-static unsigned long list_count(struct list_head *list)
-{
- struct list_head *pos;
- unsigned long count = 0;
-
- list_for_each(pos, list)
- count++;
-
- return count;
-}
-
void intel_execlists_dump_active_requests(struct intel_engine_cs *engine,
struct i915_request *hung_rq,
struct drm_printer *m)
@@ -4169,8 +4160,8 @@ void intel_execlists_dump_active_requests(struct intel_engine_cs *engine,
intel_engine_dump_active_requests(&engine->sched_engine->requests, hung_rq, m);
- drm_printf(m, "\tOn hold?: %lu\n",
- list_count(&engine->sched_engine->hold));
+ drm_printf(m, "\tOn hold?: %zu\n",
+ list_count_nodes(&engine->sched_engine->hold));
spin_unlock_irqrestore(&engine->sched_engine->lock, flags);
}
diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt.c b/drivers/gpu/drm/i915/gt/intel_ggtt.c
index 8145851ad23d..842e69c7b21e 100644
--- a/drivers/gpu/drm/i915/gt/intel_ggtt.c
+++ b/drivers/gpu/drm/i915/gt/intel_ggtt.c
@@ -8,9 +8,11 @@
#include <linux/types.h>
#include <linux/stop_machine.h>
+#include <drm/drm_managed.h>
#include <drm/i915_drm.h>
#include <drm/intel-gtt.h>
+#include "display/intel_display.h"
#include "gem/i915_gem_lmem.h"
#include "intel_ggtt_gmch.h"
@@ -26,13 +28,6 @@
#include "intel_gtt.h"
#include "gen8_ppgtt.h"
-static inline bool suspend_retains_ptes(struct i915_address_space *vm)
-{
- return GRAPHICS_VER(vm->i915) >= 8 &&
- !HAS_LMEM(vm->i915) &&
- vm->is_ggtt;
-}
-
static void i915_ggtt_color_adjust(const struct drm_mm_node *node,
unsigned long color,
u64 *start,
@@ -104,23 +99,6 @@ int i915_ggtt_init_hw(struct drm_i915_private *i915)
return 0;
}
-/*
- * Return the value of the last GGTT pte cast to an u64, if
- * the system is supposed to retain ptes across resume. 0 otherwise.
- */
-static u64 read_last_pte(struct i915_address_space *vm)
-{
- struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
- gen8_pte_t __iomem *ptep;
-
- if (!suspend_retains_ptes(vm))
- return 0;
-
- GEM_BUG_ON(GRAPHICS_VER(vm->i915) < 8);
- ptep = (typeof(ptep))ggtt->gsm + (ggtt_total_entries(ggtt) - 1);
- return readq(ptep);
-}
-
/**
* i915_ggtt_suspend_vm - Suspend the memory mappings for a GGTT or DPT VM
* @vm: The VM to suspend the mappings for
@@ -184,10 +162,7 @@ retry:
i915_gem_object_unlock(obj);
}
- if (!suspend_retains_ptes(vm))
- vm->clear_range(vm, 0, vm->total);
- else
- i915_vm_to_ggtt(vm)->probed_pte = read_last_pte(vm);
+ vm->clear_range(vm, 0, vm->total);
vm->skip_pte_rewrite = save_skip_rewrite;
@@ -196,10 +171,13 @@ retry:
void i915_ggtt_suspend(struct i915_ggtt *ggtt)
{
+ struct intel_gt *gt;
+
i915_ggtt_suspend_vm(&ggtt->vm);
ggtt->invalidate(ggtt);
- intel_gt_check_and_clear_faults(ggtt->vm.gt);
+ list_for_each_entry(gt, &ggtt->gt_list, ggtt_link)
+ intel_gt_check_and_clear_faults(gt);
}
void gen6_ggtt_invalidate(struct i915_ggtt *ggtt)
@@ -225,16 +203,21 @@ static void gen8_ggtt_invalidate(struct i915_ggtt *ggtt)
static void guc_ggtt_invalidate(struct i915_ggtt *ggtt)
{
- struct intel_uncore *uncore = ggtt->vm.gt->uncore;
struct drm_i915_private *i915 = ggtt->vm.i915;
gen8_ggtt_invalidate(ggtt);
- if (GRAPHICS_VER(i915) >= 12)
- intel_uncore_write_fw(uncore, GEN12_GUC_TLB_INV_CR,
- GEN12_GUC_TLB_INV_CR_INVALIDATE);
- else
- intel_uncore_write_fw(uncore, GEN8_GTCR, GEN8_GTCR_INVALIDATE);
+ if (GRAPHICS_VER(i915) >= 12) {
+ struct intel_gt *gt;
+
+ list_for_each_entry(gt, &ggtt->gt_list, ggtt_link)
+ intel_uncore_write_fw(gt->uncore,
+ GEN12_GUC_TLB_INV_CR,
+ GEN12_GUC_TLB_INV_CR_INVALIDATE);
+ } else {
+ intel_uncore_write_fw(ggtt->vm.gt->uncore,
+ GEN8_GTCR, GEN8_GTCR_INVALIDATE);
+ }
}
u64 gen8_ggtt_pte_encode(dma_addr_t addr,
@@ -287,8 +270,11 @@ static void gen8_ggtt_insert_entries(struct i915_address_space *vm,
*/
gte = (gen8_pte_t __iomem *)ggtt->gsm;
- gte += vma_res->start / I915_GTT_PAGE_SIZE;
- end = gte + vma_res->node_size / I915_GTT_PAGE_SIZE;
+ gte += (vma_res->start - vma_res->guard) / I915_GTT_PAGE_SIZE;
+ end = gte + vma_res->guard / I915_GTT_PAGE_SIZE;
+ while (gte < end)
+ gen8_set_pte(gte++, vm->scratch[0]->encode);
+ end += (vma_res->node_size + vma_res->guard) / I915_GTT_PAGE_SIZE;
for_each_sgt_daddr(addr, iter, vma_res->bi.pages)
gen8_set_pte(gte++, pte_encode | addr);
@@ -338,9 +324,12 @@ static void gen6_ggtt_insert_entries(struct i915_address_space *vm,
dma_addr_t addr;
gte = (gen6_pte_t __iomem *)ggtt->gsm;
- gte += vma_res->start / I915_GTT_PAGE_SIZE;
- end = gte + vma_res->node_size / I915_GTT_PAGE_SIZE;
+ gte += (vma_res->start - vma_res->guard) / I915_GTT_PAGE_SIZE;
+ end = gte + vma_res->guard / I915_GTT_PAGE_SIZE;
+ while (gte < end)
+ iowrite32(vm->scratch[0]->encode, gte++);
+ end += (vma_res->node_size + vma_res->guard) / I915_GTT_PAGE_SIZE;
for_each_sgt_daddr(addr, iter, vma_res->bi.pages)
iowrite32(vm->pte_encode(addr, level, flags), gte++);
GEM_BUG_ON(gte > end);
@@ -361,27 +350,6 @@ static void nop_clear_range(struct i915_address_space *vm,
{
}
-static void gen8_ggtt_clear_range(struct i915_address_space *vm,
- u64 start, u64 length)
-{
- struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
- unsigned int first_entry = start / I915_GTT_PAGE_SIZE;
- unsigned int num_entries = length / I915_GTT_PAGE_SIZE;
- const gen8_pte_t scratch_pte = vm->scratch[0]->encode;
- gen8_pte_t __iomem *gtt_base =
- (gen8_pte_t __iomem *)ggtt->gsm + first_entry;
- const int max_entries = ggtt_total_entries(ggtt) - first_entry;
- int i;
-
- if (WARN(num_entries > max_entries,
- "First entry = %d; Num entries = %d (max=%d)\n",
- first_entry, num_entries, max_entries))
- num_entries = max_entries;
-
- for (i = 0; i < num_entries; i++)
- gen8_set_pte(&gtt_base[i], scratch_pte);
-}
-
static void bxt_vtd_ggtt_wa(struct i915_address_space *vm)
{
/*
@@ -551,8 +519,6 @@ static int init_ggtt(struct i915_ggtt *ggtt)
struct drm_mm_node *entry;
int ret;
- ggtt->pte_lost = true;
-
/*
* GuC requires all resources that we're sharing with it to be placed in
* non-WOPCM memory. If GuC is not present or not in use we still need a
@@ -920,8 +886,8 @@ static void gen6_gmch_remove(struct i915_address_space *vm)
static struct resource pci_resource(struct pci_dev *pdev, int bar)
{
- return (struct resource)DEFINE_RES_MEM(pci_resource_start(pdev, bar),
- pci_resource_len(pdev, bar));
+ return DEFINE_RES_MEM(pci_resource_start(pdev, bar),
+ pci_resource_len(pdev, bar));
}
static int gen8_gmch_probe(struct i915_ggtt *ggtt)
@@ -953,8 +919,6 @@ static int gen8_gmch_probe(struct i915_ggtt *ggtt)
ggtt->vm.cleanup = gen6_gmch_remove;
ggtt->vm.insert_page = gen8_ggtt_insert_page;
ggtt->vm.clear_range = nop_clear_range;
- if (intel_scanout_needs_vtd_wa(i915))
- ggtt->vm.clear_range = gen8_ggtt_clear_range;
ggtt->vm.insert_entries = gen8_ggtt_insert_entries;
@@ -979,15 +943,16 @@ static int gen8_gmch_probe(struct i915_ggtt *ggtt)
I915_VMA_GLOBAL_BIND | I915_VMA_LOCAL_BIND;
}
- ggtt->invalidate = gen8_ggtt_invalidate;
+ if (intel_uc_wants_guc(&ggtt->vm.gt->uc))
+ ggtt->invalidate = guc_ggtt_invalidate;
+ else
+ ggtt->invalidate = gen8_ggtt_invalidate;
ggtt->vm.vma_ops.bind_vma = intel_ggtt_bind_vma;
ggtt->vm.vma_ops.unbind_vma = intel_ggtt_unbind_vma;
ggtt->vm.pte_encode = gen8_ggtt_pte_encode;
- setup_private_pat(ggtt->vm.gt);
-
return ggtt_probe_common(ggtt, size);
}
@@ -1115,7 +1080,7 @@ static int gen6_gmch_probe(struct i915_ggtt *ggtt)
ggtt->vm.alloc_scratch_dma = alloc_pt_dma;
ggtt->vm.clear_range = nop_clear_range;
- if (!HAS_FULL_PPGTT(i915) || intel_scanout_needs_vtd_wa(i915))
+ if (!HAS_FULL_PPGTT(i915))
ggtt->vm.clear_range = gen6_ggtt_clear_range;
ggtt->vm.insert_page = gen6_ggtt_insert_page;
ggtt->vm.insert_entries = gen6_ggtt_insert_entries;
@@ -1196,7 +1161,14 @@ static int ggtt_probe_hw(struct i915_ggtt *ggtt, struct intel_gt *gt)
*/
int i915_ggtt_probe_hw(struct drm_i915_private *i915)
{
- int ret;
+ struct intel_gt *gt;
+ int ret, i;
+
+ for_each_gt(gt, i915, i) {
+ ret = intel_gt_assign_ggtt(gt);
+ if (ret)
+ return ret;
+ }
ret = ggtt_probe_hw(to_gt(i915)->ggtt, to_gt(i915));
if (ret)
@@ -1208,35 +1180,25 @@ int i915_ggtt_probe_hw(struct drm_i915_private *i915)
return 0;
}
-int i915_ggtt_enable_hw(struct drm_i915_private *i915)
+struct i915_ggtt *i915_ggtt_create(struct drm_i915_private *i915)
{
- if (GRAPHICS_VER(i915) < 6)
- return intel_ggtt_gmch_enable_hw(i915);
+ struct i915_ggtt *ggtt;
- return 0;
-}
+ ggtt = drmm_kzalloc(&i915->drm, sizeof(*ggtt), GFP_KERNEL);
+ if (!ggtt)
+ return ERR_PTR(-ENOMEM);
-void i915_ggtt_enable_guc(struct i915_ggtt *ggtt)
-{
- GEM_BUG_ON(ggtt->invalidate != gen8_ggtt_invalidate);
+ INIT_LIST_HEAD(&ggtt->gt_list);
- ggtt->invalidate = guc_ggtt_invalidate;
-
- ggtt->invalidate(ggtt);
+ return ggtt;
}
-void i915_ggtt_disable_guc(struct i915_ggtt *ggtt)
+int i915_ggtt_enable_hw(struct drm_i915_private *i915)
{
- /* XXX Temporary pardon for error unload */
- if (ggtt->invalidate == gen8_ggtt_invalidate)
- return;
-
- /* We should only be called after i915_ggtt_enable_guc() */
- GEM_BUG_ON(ggtt->invalidate != guc_ggtt_invalidate);
-
- ggtt->invalidate = gen8_ggtt_invalidate;
+ if (GRAPHICS_VER(i915) < 6)
+ return intel_ggtt_gmch_enable_hw(i915);
- ggtt->invalidate(ggtt);
+ return 0;
}
/**
@@ -1253,20 +1215,11 @@ bool i915_ggtt_resume_vm(struct i915_address_space *vm)
{
struct i915_vma *vma;
bool write_domain_objs = false;
- bool retained_ptes;
drm_WARN_ON(&vm->i915->drm, !vm->is_ggtt && !vm->is_dpt);
- /*
- * First fill our portion of the GTT with scratch pages if
- * they were not retained across suspend.
- */
- retained_ptes = suspend_retains_ptes(vm) &&
- !i915_vm_to_ggtt(vm)->pte_lost &&
- !GEM_WARN_ON(i915_vm_to_ggtt(vm)->probed_pte != read_last_pte(vm));
-
- if (!retained_ptes)
- vm->clear_range(vm, 0, vm->total);
+ /* First fill our portion of the GTT with scratch pages */
+ vm->clear_range(vm, 0, vm->total);
/* clflush objects bound into the GGTT and rebind them. */
list_for_each_entry(vma, &vm->bound_list, vm_link) {
@@ -1275,16 +1228,16 @@ bool i915_ggtt_resume_vm(struct i915_address_space *vm)
atomic_read(&vma->flags) & I915_VMA_BIND_MASK;
GEM_BUG_ON(!was_bound);
- if (!retained_ptes) {
- /*
- * Clear the bound flags of the vma resource to allow
- * ptes to be repopulated.
- */
- vma->resource->bound_flags = 0;
- vma->ops->bind_vma(vm, NULL, vma->resource,
- obj ? obj->cache_level : 0,
- was_bound);
- }
+
+ /*
+ * Clear the bound flags of the vma resource to allow
+ * ptes to be repopulated.
+ */
+ vma->resource->bound_flags = 0;
+ vma->ops->bind_vma(vm, NULL, vma->resource,
+ obj ? obj->cache_level : 0,
+ was_bound);
+
if (obj) { /* only used during resume => exclusive access */
write_domain_objs |= fetch_and_zero(&obj->write_domain);
obj->read_domains |= I915_GEM_DOMAIN_GTT;
@@ -1296,9 +1249,11 @@ bool i915_ggtt_resume_vm(struct i915_address_space *vm)
void i915_ggtt_resume(struct i915_ggtt *ggtt)
{
+ struct intel_gt *gt;
bool flush;
- intel_gt_check_and_clear_faults(ggtt->vm.gt);
+ list_for_each_entry(gt, &ggtt->gt_list, ggtt_link)
+ intel_gt_check_and_clear_faults(gt);
flush = i915_ggtt_resume_vm(&ggtt->vm);
@@ -1307,13 +1262,5 @@ void i915_ggtt_resume(struct i915_ggtt *ggtt)
if (flush)
wbinvd_on_all_cpus();
- if (GRAPHICS_VER(ggtt->vm.i915) >= 8)
- setup_private_pat(ggtt->vm.gt);
-
intel_ggtt_restore_fences(ggtt);
}
-
-void i915_ggtt_mark_pte_lost(struct drm_i915_private *i915, bool val)
-{
- to_gt(i915)->ggtt->pte_lost = val;
-}
diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c b/drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c
index 995082d45cb2..37d0b0fe791d 100644
--- a/drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c
+++ b/drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c
@@ -5,6 +5,7 @@
#include <linux/highmem.h>
+#include "display/intel_display.h"
#include "i915_drv.h"
#include "i915_reg.h"
#include "i915_scatterlist.h"
@@ -220,7 +221,8 @@ static int fence_update(struct i915_fence_reg *fence,
return ret;
}
- fence->start = vma->node.start;
+ GEM_BUG_ON(vma->fence_size > i915_vma_size(vma));
+ fence->start = i915_ggtt_offset(vma);
fence->size = vma->fence_size;
fence->stride = i915_gem_object_get_stride(vma->obj);
fence->tiling = i915_gem_object_get_tiling(vma->obj);
diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt_gmch.c b/drivers/gpu/drm/i915/gt/intel_ggtt_gmch.c
index 4e2163a1aa46..77c793812eb4 100644
--- a/drivers/gpu/drm/i915/gt/intel_ggtt_gmch.c
+++ b/drivers/gpu/drm/i915/gt/intel_ggtt_gmch.c
@@ -6,7 +6,6 @@
#include "intel_ggtt_gmch.h"
#include <drm/intel-gtt.h>
-#include <drm/i915_drm.h>
#include <linux/agp_backend.h>
@@ -81,7 +80,7 @@ int intel_ggtt_gmch_probe(struct i915_ggtt *ggtt)
phys_addr_t gmadr_base;
int ret;
- ret = intel_gmch_probe(i915->bridge_dev, to_pci_dev(i915->drm.dev), NULL);
+ ret = intel_gmch_probe(i915->gmch.pdev, to_pci_dev(i915->drm.dev), NULL);
if (!ret) {
drm_err(&i915->drm, "failed to set up gmch\n");
return -EIO;
@@ -89,8 +88,7 @@ int intel_ggtt_gmch_probe(struct i915_ggtt *ggtt)
intel_gmch_gtt_get(&ggtt->vm.total, &gmadr_base, &ggtt->mappable_end);
- ggtt->gmadr =
- (struct resource)DEFINE_RES_MEM(gmadr_base, ggtt->mappable_end);
+ ggtt->gmadr = DEFINE_RES_MEM(gmadr_base, ggtt->mappable_end);
ggtt->vm.alloc_pt_dma = alloc_pt_dma;
ggtt->vm.alloc_scratch_dma = alloc_pt_dma;
diff --git a/drivers/gpu/drm/i915/gt/intel_gpu_commands.h b/drivers/gpu/drm/i915/gt/intel_gpu_commands.h
index f50ea92910d9..2af1ae3831df 100644
--- a/drivers/gpu/drm/i915/gt/intel_gpu_commands.h
+++ b/drivers/gpu/drm/i915/gt/intel_gpu_commands.h
@@ -21,6 +21,7 @@
#define INSTR_CLIENT_SHIFT 29
#define INSTR_MI_CLIENT 0x0
#define INSTR_BC_CLIENT 0x2
+#define INSTR_GSC_CLIENT 0x2 /* MTL+ */
#define INSTR_RC_CLIENT 0x3
#define INSTR_SUBCLIENT_SHIFT 27
#define INSTR_SUBCLIENT_MASK 0x18000000
@@ -432,6 +433,12 @@
#define COLOR_BLT ((0x2<<29)|(0x40<<22))
#define SRC_COPY_BLT ((0x2<<29)|(0x43<<22))
+#define GSC_INSTR(opcode, data, flags) \
+ (__INSTR(INSTR_GSC_CLIENT) | (opcode) << 22 | (data) << 9 | (flags))
+
+#define GSC_FW_LOAD GSC_INSTR(1, 0, 2)
+#define HECI1_FW_LIMIT_VALID (1 << 31)
+
/*
* Used to convert any address to canonical form.
* Starting from gen8, some commands (e.g. STATE_BASE_ADDRESS,
diff --git a/drivers/gpu/drm/i915/gt/intel_gsc.c b/drivers/gpu/drm/i915/gt/intel_gsc.c
index 976fdf27e790..bcc3605158db 100644
--- a/drivers/gpu/drm/i915/gt/intel_gsc.c
+++ b/drivers/gpu/drm/i915/gt/intel_gsc.c
@@ -174,6 +174,14 @@ static void gsc_init_one(struct drm_i915_private *i915, struct intel_gsc *gsc,
intf->irq = -1;
intf->id = intf_id;
+ /*
+ * On the multi-tile setups the GSC is functional on the first tile only
+ */
+ if (gsc_to_gt(gsc)->info.id != 0) {
+ drm_dbg(&i915->drm, "Not initializing gsc for remote tiles\n");
+ return;
+ }
+
if (intf_id == 0 && !HAS_HECI_PXP(i915))
return;
diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c b/drivers/gpu/drm/i915/gt/intel_gt.c
index 9c18b5f2e789..f0dbfc434e07 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt.c
+++ b/drivers/gpu/drm/i915/gt/intel_gt.c
@@ -8,7 +8,6 @@
#include "gem/i915_gem_internal.h"
#include "gem/i915_gem_lmem.h"
-#include "pxp/intel_pxp.h"
#include "i915_drv.h"
#include "i915_perf_oa_regs.h"
@@ -23,6 +22,7 @@
#include "intel_gt_debugfs.h"
#include "intel_gt_mcr.h"
#include "intel_gt_pm.h"
+#include "intel_gt_print.h"
#include "intel_gt_regs.h"
#include "intel_gt_requests.h"
#include "intel_migrate.h"
@@ -90,9 +90,8 @@ static int intel_gt_probe_lmem(struct intel_gt *gt)
if (err == -ENODEV)
return 0;
- drm_err(&i915->drm,
- "Failed to setup region(%d) type=%d\n",
- err, INTEL_MEMORY_LOCAL);
+ gt_err(gt, "Failed to setup region(%d) type=%d\n",
+ err, INTEL_MEMORY_LOCAL);
return err;
}
@@ -110,9 +109,18 @@ static int intel_gt_probe_lmem(struct intel_gt *gt)
int intel_gt_assign_ggtt(struct intel_gt *gt)
{
- gt->ggtt = drmm_kzalloc(&gt->i915->drm, sizeof(*gt->ggtt), GFP_KERNEL);
+ /* Media GT shares primary GT's GGTT */
+ if (gt->type == GT_MEDIA) {
+ gt->ggtt = to_gt(gt->i915)->ggtt;
+ } else {
+ gt->ggtt = i915_ggtt_create(gt->i915);
+ if (IS_ERR(gt->ggtt))
+ return PTR_ERR(gt->ggtt);
+ }
+
+ list_add_tail(&gt->ggtt_link, &gt->ggtt->gt_list);
- return gt->ggtt ? 0 : -ENOMEM;
+ return 0;
}
int intel_gt_init_mmio(struct intel_gt *gt)
@@ -192,14 +200,14 @@ int intel_gt_init_hw(struct intel_gt *gt)
ret = i915_ppgtt_init_hw(gt);
if (ret) {
- drm_err(&i915->drm, "Enabling PPGTT failed (%d)\n", ret);
+ gt_err(gt, "Enabling PPGTT failed (%d)\n", ret);
goto out;
}
/* We can't enable contexts until all firmware is loaded */
ret = intel_uc_init_hw(&gt->uc);
if (ret) {
- i915_probe_error(i915, "Enabling uc failed (%d)\n", ret);
+ gt_probe_error(gt, "Enabling uc failed (%d)\n", ret);
goto out;
}
@@ -210,21 +218,6 @@ out:
return ret;
}
-static void rmw_set(struct intel_uncore *uncore, i915_reg_t reg, u32 set)
-{
- intel_uncore_rmw(uncore, reg, 0, set);
-}
-
-static void rmw_clear(struct intel_uncore *uncore, i915_reg_t reg, u32 clr)
-{
- intel_uncore_rmw(uncore, reg, clr, 0);
-}
-
-static void clear_register(struct intel_uncore *uncore, i915_reg_t reg)
-{
- intel_uncore_rmw(uncore, reg, 0, 0);
-}
-
static void gen6_clear_engine_error_register(struct intel_engine_cs *engine)
{
GEN6_RING_FAULT_REG_RMW(engine, RING_FAULT_VALID, 0);
@@ -250,22 +243,22 @@ intel_gt_clear_error_registers(struct intel_gt *gt,
u32 eir;
if (GRAPHICS_VER(i915) != 2)
- clear_register(uncore, PGTBL_ER);
+ intel_uncore_write(uncore, PGTBL_ER, 0);
if (GRAPHICS_VER(i915) < 4)
- clear_register(uncore, IPEIR(RENDER_RING_BASE));
+ intel_uncore_write(uncore, IPEIR(RENDER_RING_BASE), 0);
else
- clear_register(uncore, IPEIR_I965);
+ intel_uncore_write(uncore, IPEIR_I965, 0);
- clear_register(uncore, EIR);
+ intel_uncore_write(uncore, EIR, 0);
eir = intel_uncore_read(uncore, EIR);
if (eir) {
/*
* some errors might have become stuck,
* mask them.
*/
- drm_dbg(&gt->i915->drm, "EIR stuck: 0x%08x, masking\n", eir);
- rmw_set(uncore, EMR, eir);
+ gt_dbg(gt, "EIR stuck: 0x%08x, masking\n", eir);
+ intel_uncore_rmw(uncore, EMR, 0, eir);
intel_uncore_write(uncore, GEN2_IIR,
I915_MASTER_ERROR_INTERRUPT);
}
@@ -275,10 +268,10 @@ intel_gt_clear_error_registers(struct intel_gt *gt,
RING_FAULT_VALID, 0);
intel_gt_mcr_read_any(gt, XEHP_RING_FAULT_REG);
} else if (GRAPHICS_VER(i915) >= 12) {
- rmw_clear(uncore, GEN12_RING_FAULT_REG, RING_FAULT_VALID);
+ intel_uncore_rmw(uncore, GEN12_RING_FAULT_REG, RING_FAULT_VALID, 0);
intel_uncore_posting_read(uncore, GEN12_RING_FAULT_REG);
} else if (GRAPHICS_VER(i915) >= 8) {
- rmw_clear(uncore, GEN8_RING_FAULT_REG, RING_FAULT_VALID);
+ intel_uncore_rmw(uncore, GEN8_RING_FAULT_REG, RING_FAULT_VALID, 0);
intel_uncore_posting_read(uncore, GEN8_RING_FAULT_REG);
} else if (GRAPHICS_VER(i915) >= 6) {
struct intel_engine_cs *engine;
@@ -298,16 +291,16 @@ static void gen6_check_faults(struct intel_gt *gt)
for_each_engine(engine, gt, id) {
fault = GEN6_RING_FAULT_REG_READ(engine);
if (fault & RING_FAULT_VALID) {
- drm_dbg(&engine->i915->drm, "Unexpected fault\n"
- "\tAddr: 0x%08lx\n"
- "\tAddress space: %s\n"
- "\tSource ID: %d\n"
- "\tType: %d\n",
- fault & PAGE_MASK,
- fault & RING_FAULT_GTTSEL_MASK ?
- "GGTT" : "PPGTT",
- RING_FAULT_SRCID(fault),
- RING_FAULT_FAULT_TYPE(fault));
+ gt_dbg(gt, "Unexpected fault\n"
+ "\tAddr: 0x%08lx\n"
+ "\tAddress space: %s\n"
+ "\tSource ID: %d\n"
+ "\tType: %d\n",
+ fault & PAGE_MASK,
+ fault & RING_FAULT_GTTSEL_MASK ?
+ "GGTT" : "PPGTT",
+ RING_FAULT_SRCID(fault),
+ RING_FAULT_FAULT_TYPE(fault));
}
}
}
@@ -334,17 +327,17 @@ static void xehp_check_faults(struct intel_gt *gt)
fault_addr = ((u64)(fault_data1 & FAULT_VA_HIGH_BITS) << 44) |
((u64)fault_data0 << 12);
- drm_dbg(&gt->i915->drm, "Unexpected fault\n"
- "\tAddr: 0x%08x_%08x\n"
- "\tAddress space: %s\n"
- "\tEngine ID: %d\n"
- "\tSource ID: %d\n"
- "\tType: %d\n",
- upper_32_bits(fault_addr), lower_32_bits(fault_addr),
- fault_data1 & FAULT_GTT_SEL ? "GGTT" : "PPGTT",
- GEN8_RING_FAULT_ENGINE_ID(fault),
- RING_FAULT_SRCID(fault),
- RING_FAULT_FAULT_TYPE(fault));
+ gt_dbg(gt, "Unexpected fault\n"
+ "\tAddr: 0x%08x_%08x\n"
+ "\tAddress space: %s\n"
+ "\tEngine ID: %d\n"
+ "\tSource ID: %d\n"
+ "\tType: %d\n",
+ upper_32_bits(fault_addr), lower_32_bits(fault_addr),
+ fault_data1 & FAULT_GTT_SEL ? "GGTT" : "PPGTT",
+ GEN8_RING_FAULT_ENGINE_ID(fault),
+ RING_FAULT_SRCID(fault),
+ RING_FAULT_FAULT_TYPE(fault));
}
}
@@ -375,17 +368,17 @@ static void gen8_check_faults(struct intel_gt *gt)
fault_addr = ((u64)(fault_data1 & FAULT_VA_HIGH_BITS) << 44) |
((u64)fault_data0 << 12);
- drm_dbg(&uncore->i915->drm, "Unexpected fault\n"
- "\tAddr: 0x%08x_%08x\n"
- "\tAddress space: %s\n"
- "\tEngine ID: %d\n"
- "\tSource ID: %d\n"
- "\tType: %d\n",
- upper_32_bits(fault_addr), lower_32_bits(fault_addr),
- fault_data1 & FAULT_GTT_SEL ? "GGTT" : "PPGTT",
- GEN8_RING_FAULT_ENGINE_ID(fault),
- RING_FAULT_SRCID(fault),
- RING_FAULT_FAULT_TYPE(fault));
+ gt_dbg(gt, "Unexpected fault\n"
+ "\tAddr: 0x%08x_%08x\n"
+ "\tAddress space: %s\n"
+ "\tEngine ID: %d\n"
+ "\tSource ID: %d\n"
+ "\tType: %d\n",
+ upper_32_bits(fault_addr), lower_32_bits(fault_addr),
+ fault_data1 & FAULT_GTT_SEL ? "GGTT" : "PPGTT",
+ GEN8_RING_FAULT_ENGINE_ID(fault),
+ RING_FAULT_SRCID(fault),
+ RING_FAULT_FAULT_TYPE(fault));
}
}
@@ -479,7 +472,7 @@ static int intel_gt_init_scratch(struct intel_gt *gt, unsigned int size)
if (IS_ERR(obj))
obj = i915_gem_object_create_internal(i915, size);
if (IS_ERR(obj)) {
- drm_err(&i915->drm, "Failed to allocate scratch page\n");
+ gt_err(gt, "Failed to allocate scratch page\n");
return PTR_ERR(obj);
}
@@ -734,8 +727,7 @@ int intel_gt_init(struct intel_gt *gt)
err = intel_gt_init_hwconfig(gt);
if (err)
- drm_err(&gt->i915->drm, "Failed to retrieve hwconfig table: %pe\n",
- ERR_PTR(err));
+ gt_err(gt, "Failed to retrieve hwconfig table: %pe\n", ERR_PTR(err));
err = __engines_record_defaults(gt);
if (err)
@@ -753,8 +745,6 @@ int intel_gt_init(struct intel_gt *gt)
intel_migrate_init(&gt->migrate, gt);
- intel_pxp_init(&gt->pxp);
-
goto out_fw;
err_gt:
__intel_gt_disable(gt);
@@ -794,8 +784,6 @@ void intel_gt_driver_unregister(struct intel_gt *gt)
intel_rps_driver_unregister(&gt->rps);
intel_gsc_fini(&gt->gsc);
- intel_pxp_fini(&gt->pxp);
-
/*
* Upon unregistering the device to prevent any new users, cancel
* all in-flight requests so that we can quickly unbind the active
@@ -896,7 +884,7 @@ int intel_gt_probe_all(struct drm_i915_private *i915)
gt->name = "Primary GT";
gt->info.engine_mask = RUNTIME_INFO(i915)->platform_engine_mask;
- drm_dbg(&i915->drm, "Setting up %s\n", gt->name);
+ gt_dbg(gt, "Setting up %s\n", gt->name);
ret = intel_gt_tile_setup(gt, phys_addr);
if (ret)
return ret;
@@ -921,7 +909,7 @@ int intel_gt_probe_all(struct drm_i915_private *i915)
gt->info.engine_mask = gtdef->engine_mask;
gt->info.id = i;
- drm_dbg(&i915->drm, "Setting up %s\n", gt->name);
+ gt_dbg(gt, "Setting up %s\n", gt->name);
if (GEM_WARN_ON(range_overflows_t(resource_size_t,
gtdef->mapping_base,
SZ_16M,
@@ -1009,8 +997,7 @@ get_reg_and_bit(const struct intel_engine_cs *engine, const bool gen8,
const unsigned int class = engine->class;
struct reg_and_bit rb = { };
- if (drm_WARN_ON_ONCE(&engine->i915->drm,
- class >= num || !regs[class].reg))
+ if (gt_WARN_ON_ONCE(engine->gt, class >= num || !regs[class].reg))
return rb;
rb.reg = regs[class];
@@ -1079,11 +1066,25 @@ static void mmio_invalidate_full(struct intel_gt *gt)
enum intel_engine_id id;
const i915_reg_t *regs;
unsigned int num = 0;
+ unsigned long flags;
- if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 50)) {
+ /*
+ * New platforms should not be added with catch-all-newer (>=)
+ * condition so that any later platform added triggers the below warning
+ * and in turn mandates a human cross-check of whether the invalidation
+ * flows have compatible semantics.
+ *
+ * For instance with the 11.00 -> 12.00 transition three out of five
+ * respective engine registers were moved to masked type. Then after the
+ * 12.00 -> 12.50 transition multi cast handling is required too.
+ */
+
+ if (GRAPHICS_VER_FULL(i915) == IP_VER(12, 50) ||
+ GRAPHICS_VER_FULL(i915) == IP_VER(12, 55)) {
regs = NULL;
num = ARRAY_SIZE(xehp_regs);
- } else if (GRAPHICS_VER(i915) == 12) {
+ } else if (GRAPHICS_VER_FULL(i915) == IP_VER(12, 0) ||
+ GRAPHICS_VER_FULL(i915) == IP_VER(12, 10)) {
regs = gen12_regs;
num = ARRAY_SIZE(gen12_regs);
} else if (GRAPHICS_VER(i915) >= 8 && GRAPHICS_VER(i915) <= 11) {
@@ -1093,13 +1094,13 @@ static void mmio_invalidate_full(struct intel_gt *gt)
return;
}
- if (drm_WARN_ONCE(&i915->drm, !num,
- "Platform does not implement TLB invalidation!"))
+ if (gt_WARN_ONCE(gt, !num, "Platform does not implement TLB invalidation!"))
return;
intel_uncore_forcewake_get(uncore, FORCEWAKE_ALL);
- spin_lock_irq(&uncore->lock); /* serialise invalidate with GT reset */
+ intel_gt_mcr_lock(gt, &flags);
+ spin_lock(&uncore->lock); /* serialise invalidate with GT reset */
awake = 0;
for_each_engine(engine, gt, id) {
@@ -1144,7 +1145,8 @@ static void mmio_invalidate_full(struct intel_gt *gt)
IS_ALDERLAKE_P(i915)))
intel_uncore_write_fw(uncore, GEN12_OA_TLB_INV_CR, 1);
- spin_unlock_irq(&uncore->lock);
+ spin_unlock(&uncore->lock);
+ intel_gt_mcr_unlock(gt, flags);
for_each_engine_masked(engine, gt, awake, tmp) {
struct reg_and_bit rb;
@@ -1157,9 +1159,8 @@ static void mmio_invalidate_full(struct intel_gt *gt)
}
if (wait_for_invalidate(gt, rb))
- drm_err_ratelimited(&gt->i915->drm,
- "%s TLB invalidation did not complete in %ums!\n",
- engine->name, TLB_INVAL_TIMEOUT_MS);
+ gt_err_ratelimited(gt, "%s TLB invalidation did not complete in %ums!\n",
+ engine->name, TLB_INVAL_TIMEOUT_MS);
}
/*
diff --git a/drivers/gpu/drm/i915/gt/intel_gt.h b/drivers/gpu/drm/i915/gt/intel_gt.h
index e0365d556248..d2f4fbde5f9f 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt.h
+++ b/drivers/gpu/drm/i915/gt/intel_gt.h
@@ -39,6 +39,11 @@ static inline struct intel_gt *huc_to_gt(struct intel_huc *huc)
return container_of(huc, struct intel_gt, uc.huc);
}
+static inline struct intel_gt *gsc_uc_to_gt(struct intel_gsc_uc *gsc_uc)
+{
+ return container_of(gsc_uc, struct intel_gt, uc.gsc);
+}
+
static inline struct intel_gt *gsc_to_gt(struct intel_gsc *gsc)
{
return container_of(gsc, struct intel_gt, gsc);
diff --git a/drivers/gpu/drm/i915/gt/intel_gt_clock_utils.c b/drivers/gpu/drm/i915/gt/intel_gt_clock_utils.c
index 2a6a4ca7fdad..7c9be4fd1c8c 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt_clock_utils.c
+++ b/drivers/gpu/drm/i915/gt/intel_gt_clock_utils.c
@@ -7,6 +7,7 @@
#include "i915_reg.h"
#include "intel_gt.h"
#include "intel_gt_clock_utils.h"
+#include "intel_gt_print.h"
#include "intel_gt_regs.h"
static u32 read_reference_ts_freq(struct intel_uncore *uncore)
@@ -193,10 +194,9 @@ void intel_gt_init_clock_frequency(struct intel_gt *gt)
void intel_gt_check_clock_frequency(const struct intel_gt *gt)
{
if (gt->clock_frequency != read_clock_frequency(gt->uncore)) {
- dev_err(gt->i915->drm.dev,
- "GT clock frequency changed, was %uHz, now %uHz!\n",
- gt->clock_frequency,
- read_clock_frequency(gt->uncore));
+ gt_err(gt, "GT clock frequency changed, was %uHz, now %uHz!\n",
+ gt->clock_frequency,
+ read_clock_frequency(gt->uncore));
}
}
#endif
diff --git a/drivers/gpu/drm/i915/gt/intel_gt_debugfs.c b/drivers/gpu/drm/i915/gt/intel_gt_debugfs.c
index dd53641f3637..5fc2df01aa0d 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt_debugfs.c
+++ b/drivers/gpu/drm/i915/gt/intel_gt_debugfs.c
@@ -12,7 +12,6 @@
#include "intel_gt_mcr.h"
#include "intel_gt_pm_debugfs.h"
#include "intel_sseu_debugfs.h"
-#include "pxp/intel_pxp_debugfs.h"
#include "uc/intel_uc_debugfs.h"
int intel_gt_debugfs_reset_show(struct intel_gt *gt, u64 *val)
@@ -99,7 +98,6 @@ void intel_gt_debugfs_register(struct intel_gt *gt)
intel_sseu_debugfs_register(gt, root);
intel_uc_debugfs_register(&gt->uc, root);
- intel_pxp_debugfs_register(&gt->pxp, root);
}
void intel_gt_debugfs_register_files(struct dentry *root,
diff --git a/drivers/gpu/drm/i915/gt/intel_gt_irq.c b/drivers/gpu/drm/i915/gt/intel_gt_irq.c
index 6f6b9e04d916..1b25a6039152 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt_irq.c
+++ b/drivers/gpu/drm/i915/gt/intel_gt_irq.c
@@ -10,6 +10,7 @@
#include "intel_breadcrumbs.h"
#include "intel_gt.h"
#include "intel_gt_irq.h"
+#include "intel_gt_print.h"
#include "intel_gt_regs.h"
#include "intel_uncore.h"
#include "intel_rps.h"
@@ -47,9 +48,8 @@ gen11_gt_engine_identity(struct intel_gt *gt,
!time_after32(local_clock() >> 10, timeout_ts));
if (unlikely(!(ident & GEN11_INTR_DATA_VALID))) {
- drm_err(&gt->i915->drm,
- "INTR_IDENTITY_REG%u:%u 0x%08x not valid!\n",
- bank, bit, ident);
+ gt_err(gt, "INTR_IDENTITY_REG%u:%u 0x%08x not valid!\n",
+ bank, bit, ident);
return 0;
}
@@ -76,7 +76,7 @@ gen11_other_irq_handler(struct intel_gt *gt, const u8 instance,
return gen11_rps_irq_handler(&media_gt->rps, iir);
if (instance == OTHER_KCR_INSTANCE)
- return intel_pxp_irq_handler(&gt->pxp, iir);
+ return intel_pxp_irq_handler(gt->i915->pxp, iir);
if (instance == OTHER_GSC_INSTANCE)
return intel_gsc_irq_handler(gt, iir);
@@ -378,8 +378,7 @@ void gen6_gt_irq_handler(struct intel_gt *gt, u32 gt_iir)
if (gt_iir & (GT_BLT_CS_ERROR_INTERRUPT |
GT_BSD_CS_ERROR_INTERRUPT |
GT_CS_MASTER_ERROR_INTERRUPT))
- drm_dbg(&gt->i915->drm, "Command parser error, gt_iir 0x%08x\n",
- gt_iir);
+ gt_dbg(gt, "Command parser error, gt_iir 0x%08x\n", gt_iir);
if (gt_iir & GT_PARITY_ERROR(gt->i915))
gen7_parity_error_irq_handler(gt, gt_iir);
diff --git a/drivers/gpu/drm/i915/gt/intel_gt_mcr.c b/drivers/gpu/drm/i915/gt/intel_gt_mcr.c
index ea86c1ab5dc5..3bb1c701d5ff 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt_mcr.c
+++ b/drivers/gpu/drm/i915/gt/intel_gt_mcr.c
@@ -6,6 +6,7 @@
#include "i915_drv.h"
#include "intel_gt_mcr.h"
+#include "intel_gt_print.h"
#include "intel_gt_regs.h"
/**
@@ -143,6 +144,8 @@ void intel_gt_mcr_init(struct intel_gt *gt)
unsigned long fuse;
int i;
+ spin_lock_init(&gt->mcr_lock);
+
/*
* An mslice is unavailable only if both the meml3 for the slice is
* disabled *and* all of the DSS in the slice (quadrant) are disabled.
@@ -156,14 +159,21 @@ void intel_gt_mcr_init(struct intel_gt *gt)
GEN12_MEML3_EN_MASK);
if (!gt->info.mslice_mask) /* should be impossible! */
- drm_warn(&i915->drm, "mslice mask all zero!\n");
+ gt_warn(gt, "mslice mask all zero!\n");
}
if (MEDIA_VER(i915) >= 13 && gt->type == GT_MEDIA) {
gt->steering_table[OADDRM] = xelpmp_oaddrm_steering_table;
} else if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 70)) {
- fuse = REG_FIELD_GET(GT_L3_EXC_MASK,
- intel_uncore_read(gt->uncore, XEHP_FUSE4));
+ /* Wa_14016747170 */
+ if (IS_MTL_GRAPHICS_STEP(i915, M, STEP_A0, STEP_B0) ||
+ IS_MTL_GRAPHICS_STEP(i915, P, STEP_A0, STEP_B0))
+ fuse = REG_FIELD_GET(MTL_GT_L3_EXC_MASK,
+ intel_uncore_read(gt->uncore,
+ MTL_GT_ACTIVITY_FACTOR));
+ else
+ fuse = REG_FIELD_GET(GT_L3_EXC_MASK,
+ intel_uncore_read(gt->uncore, XEHP_FUSE4));
/*
* Despite the register field being named "exclude mask" the
@@ -196,7 +206,7 @@ void intel_gt_mcr_init(struct intel_gt *gt)
~intel_uncore_read(gt->uncore, GEN10_MIRROR_FUSE3) &
GEN10_L3BANK_MASK;
if (!gt->info.l3bank_mask) /* should be impossible! */
- drm_warn(&i915->drm, "L3 bank mask is all zero!\n");
+ gt_warn(gt, "L3 bank mask is all zero!\n");
} else if (GRAPHICS_VER(i915) >= 11) {
/*
* We expect all modern platforms to have at least some
@@ -221,24 +231,26 @@ static i915_reg_t mcr_reg_cast(const i915_mcr_reg_t mcr)
/*
* rw_with_mcr_steering_fw - Access a register with specific MCR steering
- * @uncore: pointer to struct intel_uncore
+ * @gt: GT to read register from
* @reg: register being accessed
* @rw_flag: FW_REG_READ for read access or FW_REG_WRITE for write access
* @group: group number (documented as "sliceid" on older platforms)
* @instance: instance number (documented as "subsliceid" on older platforms)
* @value: register value to be written (ignored for read)
*
+ * Context: The caller must hold the MCR lock
* Return: 0 for write access. register value for read access.
*
* Caller needs to make sure the relevant forcewake wells are up.
*/
-static u32 rw_with_mcr_steering_fw(struct intel_uncore *uncore,
+static u32 rw_with_mcr_steering_fw(struct intel_gt *gt,
i915_mcr_reg_t reg, u8 rw_flag,
int group, int instance, u32 value)
{
+ struct intel_uncore *uncore = gt->uncore;
u32 mcr_mask, mcr_ss, mcr, old_mcr, val = 0;
- lockdep_assert_held(&uncore->lock);
+ lockdep_assert_held(&gt->mcr_lock);
if (GRAPHICS_VER_FULL(uncore->i915) >= IP_VER(12, 70)) {
/*
@@ -308,12 +320,14 @@ static u32 rw_with_mcr_steering_fw(struct intel_uncore *uncore,
return val;
}
-static u32 rw_with_mcr_steering(struct intel_uncore *uncore,
+static u32 rw_with_mcr_steering(struct intel_gt *gt,
i915_mcr_reg_t reg, u8 rw_flag,
int group, int instance,
u32 value)
{
+ struct intel_uncore *uncore = gt->uncore;
enum forcewake_domains fw_domains;
+ unsigned long flags;
u32 val;
fw_domains = intel_uncore_forcewake_for_reg(uncore, mcr_reg_cast(reg),
@@ -322,24 +336,96 @@ static u32 rw_with_mcr_steering(struct intel_uncore *uncore,
GEN8_MCR_SELECTOR,
FW_REG_READ | FW_REG_WRITE);
- spin_lock_irq(&uncore->lock);
+ intel_gt_mcr_lock(gt, &flags);
+ spin_lock(&uncore->lock);
intel_uncore_forcewake_get__locked(uncore, fw_domains);
- val = rw_with_mcr_steering_fw(uncore, reg, rw_flag, group, instance, value);
+ val = rw_with_mcr_steering_fw(gt, reg, rw_flag, group, instance, value);
intel_uncore_forcewake_put__locked(uncore, fw_domains);
- spin_unlock_irq(&uncore->lock);
+ spin_unlock(&uncore->lock);
+ intel_gt_mcr_unlock(gt, flags);
return val;
}
/**
+ * intel_gt_mcr_lock - Acquire MCR steering lock
+ * @gt: GT structure
+ * @flags: storage to save IRQ flags to
+ *
+ * Performs locking to protect the steering for the duration of an MCR
+ * operation. On MTL and beyond, a hardware lock will also be taken to
+ * serialize access not only for the driver, but also for external hardware and
+ * firmware agents.
+ *
+ * Context: Takes gt->mcr_lock. uncore->lock should *not* be held when this
+ * function is called, although it may be acquired after this
+ * function call.
+ */
+void intel_gt_mcr_lock(struct intel_gt *gt, unsigned long *flags)
+{
+ unsigned long __flags;
+ int err = 0;
+
+ lockdep_assert_not_held(&gt->uncore->lock);
+
+ /*
+ * Starting with MTL, we need to coordinate not only with other
+ * driver threads, but also with hardware/firmware agents. A dedicated
+ * locking register is used.
+ */
+ if (GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 70))
+ err = wait_for(intel_uncore_read_fw(gt->uncore,
+ MTL_STEER_SEMAPHORE) == 0x1, 100);
+
+ /*
+ * Even on platforms with a hardware lock, we'll continue to grab
+ * a software spinlock too for lockdep purposes. If the hardware lock
+ * was already acquired, there should never be contention on the
+ * software lock.
+ */
+ spin_lock_irqsave(&gt->mcr_lock, __flags);
+
+ *flags = __flags;
+
+ /*
+ * In theory we should never fail to acquire the HW semaphore; this
+ * would indicate some hardware/firmware is misbehaving and not
+ * releasing it properly.
+ */
+ if (err == -ETIMEDOUT) {
+ gt_err_ratelimited(gt, "hardware MCR steering semaphore timed out");
+ add_taint_for_CI(gt->i915, TAINT_WARN); /* CI is now unreliable */
+ }
+}
+
+/**
+ * intel_gt_mcr_unlock - Release MCR steering lock
+ * @gt: GT structure
+ * @flags: IRQ flags to restore
+ *
+ * Releases the lock acquired by intel_gt_mcr_lock().
+ *
+ * Context: Releases gt->mcr_lock
+ */
+void intel_gt_mcr_unlock(struct intel_gt *gt, unsigned long flags)
+{
+ spin_unlock_irqrestore(&gt->mcr_lock, flags);
+
+ if (GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 70))
+ intel_uncore_write_fw(gt->uncore, MTL_STEER_SEMAPHORE, 0x1);
+}
+
+/**
* intel_gt_mcr_read - read a specific instance of an MCR register
* @gt: GT structure
* @reg: the MCR register to read
* @group: the MCR group
* @instance: the MCR instance
*
+ * Context: Takes and releases gt->mcr_lock
+ *
* Returns the value read from an MCR register after steering toward a specific
* group/instance.
*/
@@ -347,7 +433,7 @@ u32 intel_gt_mcr_read(struct intel_gt *gt,
i915_mcr_reg_t reg,
int group, int instance)
{
- return rw_with_mcr_steering(gt->uncore, reg, FW_REG_READ, group, instance, 0);
+ return rw_with_mcr_steering(gt, reg, FW_REG_READ, group, instance, 0);
}
/**
@@ -360,11 +446,13 @@ u32 intel_gt_mcr_read(struct intel_gt *gt,
*
* Write an MCR register in unicast mode after steering toward a specific
* group/instance.
+ *
+ * Context: Calls a function that takes and releases gt->mcr_lock
*/
void intel_gt_mcr_unicast_write(struct intel_gt *gt, i915_mcr_reg_t reg, u32 value,
int group, int instance)
{
- rw_with_mcr_steering(gt->uncore, reg, FW_REG_WRITE, group, instance, value);
+ rw_with_mcr_steering(gt, reg, FW_REG_WRITE, group, instance, value);
}
/**
@@ -374,10 +462,16 @@ void intel_gt_mcr_unicast_write(struct intel_gt *gt, i915_mcr_reg_t reg, u32 val
* @value: value to write
*
* Write an MCR register in multicast mode to update all instances.
+ *
+ * Context: Takes and releases gt->mcr_lock
*/
void intel_gt_mcr_multicast_write(struct intel_gt *gt,
i915_mcr_reg_t reg, u32 value)
{
+ unsigned long flags;
+
+ intel_gt_mcr_lock(gt, &flags);
+
/*
* Ensure we have multicast behavior, just in case some non-i915 agent
* left the hardware in unicast mode.
@@ -386,6 +480,8 @@ void intel_gt_mcr_multicast_write(struct intel_gt *gt,
intel_uncore_write_fw(gt->uncore, MTL_MCR_SELECTOR, GEN11_MCR_MULTICAST);
intel_uncore_write(gt->uncore, mcr_reg_cast(reg), value);
+
+ intel_gt_mcr_unlock(gt, flags);
}
/**
@@ -398,9 +494,13 @@ void intel_gt_mcr_multicast_write(struct intel_gt *gt,
* function assumes the caller is already holding any necessary forcewake
* domains; use intel_gt_mcr_multicast_write() in cases where forcewake should
* be obtained automatically.
+ *
+ * Context: The caller must hold gt->mcr_lock.
*/
void intel_gt_mcr_multicast_write_fw(struct intel_gt *gt, i915_mcr_reg_t reg, u32 value)
{
+ lockdep_assert_held(&gt->mcr_lock);
+
/*
* Ensure we have multicast behavior, just in case some non-i915 agent
* left the hardware in unicast mode.
@@ -427,6 +527,8 @@ void intel_gt_mcr_multicast_write_fw(struct intel_gt *gt, i915_mcr_reg_t reg, u3
* domains; use intel_gt_mcr_multicast_rmw() in cases where forcewake should
* be obtained automatically.
*
+ * Context: Calls functions that take and release gt->mcr_lock
+ *
* Returns the old (unmodified) value read.
*/
u32 intel_gt_mcr_multicast_rmw(struct intel_gt *gt, i915_mcr_reg_t reg,
@@ -457,12 +559,15 @@ static bool reg_needs_read_steering(struct intel_gt *gt,
i915_mcr_reg_t reg,
enum intel_steering_type type)
{
- const u32 offset = i915_mmio_reg_offset(reg);
+ u32 offset = i915_mmio_reg_offset(reg);
const struct intel_mmio_range *entry;
if (likely(!gt->steering_table[type]))
return false;
+ if (IS_GSI_REG(offset))
+ offset += gt->uncore->gsi_offset;
+
for (entry = gt->steering_table[type]; entry->end; entry++) {
if (offset >= entry->start && offset <= entry->end)
return true;
@@ -578,6 +683,8 @@ void intel_gt_mcr_get_nonterminated_steering(struct intel_gt *gt,
* domains; use intel_gt_mcr_read_any() in cases where forcewake should be
* obtained automatically.
*
+ * Context: The caller must hold gt->mcr_lock.
+ *
* Returns the value from a non-terminated instance of @reg.
*/
u32 intel_gt_mcr_read_any_fw(struct intel_gt *gt, i915_mcr_reg_t reg)
@@ -585,10 +692,12 @@ u32 intel_gt_mcr_read_any_fw(struct intel_gt *gt, i915_mcr_reg_t reg)
int type;
u8 group, instance;
+ lockdep_assert_held(&gt->mcr_lock);
+
for (type = 0; type < NUM_STEERING_TYPES; type++) {
if (reg_needs_read_steering(gt, reg, type)) {
get_nonterminated_steering(gt, type, &group, &instance);
- return rw_with_mcr_steering_fw(gt->uncore, reg,
+ return rw_with_mcr_steering_fw(gt, reg,
FW_REG_READ,
group, instance, 0);
}
@@ -605,6 +714,8 @@ u32 intel_gt_mcr_read_any_fw(struct intel_gt *gt, i915_mcr_reg_t reg)
* Reads a GT MCR register. The read will be steered to a non-terminated
* instance (i.e., one that isn't fused off or powered down by power gating).
*
+ * Context: Calls a function that takes and releases gt->mcr_lock.
+ *
* Returns the value from a non-terminated instance of @reg.
*/
u32 intel_gt_mcr_read_any(struct intel_gt *gt, i915_mcr_reg_t reg)
@@ -615,7 +726,7 @@ u32 intel_gt_mcr_read_any(struct intel_gt *gt, i915_mcr_reg_t reg)
for (type = 0; type < NUM_STEERING_TYPES; type++) {
if (reg_needs_read_steering(gt, reg, type)) {
get_nonterminated_steering(gt, type, &group, &instance);
- return rw_with_mcr_steering(gt->uncore, reg,
+ return rw_with_mcr_steering(gt, reg,
FW_REG_READ,
group, instance, 0);
}
@@ -728,6 +839,7 @@ void intel_gt_mcr_get_ss_steering(struct intel_gt *gt, unsigned int dss,
* Note that this routine assumes the caller holds forcewake asserted, it is
* not suitable for very long waits.
*
+ * Context: Calls a function that takes and releases gt->mcr_lock
* Return: 0 if the register matches the desired condition, or -ETIMEDOUT.
*/
int intel_gt_mcr_wait_for_reg(struct intel_gt *gt,
@@ -739,7 +851,7 @@ int intel_gt_mcr_wait_for_reg(struct intel_gt *gt,
{
int ret;
- lockdep_assert_not_held(&gt->uncore->lock);
+ lockdep_assert_not_held(&gt->mcr_lock);
#define done ((intel_gt_mcr_read_any(gt, reg) & mask) == value)
diff --git a/drivers/gpu/drm/i915/gt/intel_gt_mcr.h b/drivers/gpu/drm/i915/gt/intel_gt_mcr.h
index ae93b20e1c17..41684495b7da 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt_mcr.h
+++ b/drivers/gpu/drm/i915/gt/intel_gt_mcr.h
@@ -9,6 +9,8 @@
#include "intel_gt_types.h"
void intel_gt_mcr_init(struct intel_gt *gt);
+void intel_gt_mcr_lock(struct intel_gt *gt, unsigned long *flags);
+void intel_gt_mcr_unlock(struct intel_gt *gt, unsigned long flags);
u32 intel_gt_mcr_read(struct intel_gt *gt,
i915_mcr_reg_t reg,
diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm.c b/drivers/gpu/drm/i915/gt/intel_gt_pm.c
index 16db85fab0b1..cef3d6f5c34e 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt_pm.c
+++ b/drivers/gpu/drm/i915/gt/intel_gt_pm.c
@@ -14,6 +14,7 @@
#include "intel_gt.h"
#include "intel_gt_clock_utils.h"
#include "intel_gt_pm.h"
+#include "intel_gt_print.h"
#include "intel_gt_requests.h"
#include "intel_llc.h"
#include "intel_pm.h"
@@ -275,8 +276,7 @@ int intel_gt_resume(struct intel_gt *gt)
/* Only when the HW is re-initialised, can we replay the requests */
err = intel_gt_init_hw(gt);
if (err) {
- i915_probe_error(gt->i915,
- "Failed to initialize GPU, declaring it wedged!\n");
+ gt_probe_error(gt, "Failed to initialize GPU, declaring it wedged!\n");
goto err_wedged;
}
@@ -293,9 +293,8 @@ int intel_gt_resume(struct intel_gt *gt)
intel_engine_pm_put(engine);
if (err) {
- drm_err(&gt->i915->drm,
- "Failed to restart %s (%d)\n",
- engine->name, err);
+ gt_err(gt, "Failed to restart %s (%d)\n",
+ engine->name, err);
goto err_wedged;
}
}
@@ -304,8 +303,6 @@ int intel_gt_resume(struct intel_gt *gt)
intel_uc_resume(&gt->uc);
- intel_pxp_resume(&gt->pxp);
-
user_forcewake(gt, false);
out_fw:
@@ -339,8 +336,6 @@ void intel_gt_suspend_prepare(struct intel_gt *gt)
{
user_forcewake(gt, true);
wait_for_suspend(gt);
-
- intel_pxp_suspend_prepare(&gt->pxp);
}
static suspend_state_t pm_suspend_target(void)
@@ -365,7 +360,6 @@ void intel_gt_suspend_late(struct intel_gt *gt)
GEM_BUG_ON(gt->awake);
intel_uc_suspend(&gt->uc);
- intel_pxp_suspend(&gt->pxp);
/*
* On disabling the device, we want to turn off HW access to memory
@@ -393,7 +387,6 @@ void intel_gt_suspend_late(struct intel_gt *gt)
void intel_gt_runtime_suspend(struct intel_gt *gt)
{
- intel_pxp_runtime_suspend(&gt->pxp);
intel_uc_runtime_suspend(&gt->uc);
GT_TRACE(gt, "\n");
@@ -411,8 +404,6 @@ int intel_gt_runtime_resume(struct intel_gt *gt)
if (ret)
return ret;
- intel_pxp_runtime_resume(&gt->pxp);
-
return 0;
}
diff --git a/drivers/gpu/drm/i915/gt/intel_gt_print.h b/drivers/gpu/drm/i915/gt/intel_gt_print.h
new file mode 100644
index 000000000000..5d9da355ce24
--- /dev/null
+++ b/drivers/gpu/drm/i915/gt/intel_gt_print.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+#ifndef __INTEL_GT_PRINT__
+#define __INTEL_GT_PRINT__
+
+#include <drm/drm_print.h>
+#include "intel_gt_types.h"
+#include "i915_utils.h"
+
+#define gt_err(_gt, _fmt, ...) \
+ drm_err(&(_gt)->i915->drm, "GT%u: " _fmt, (_gt)->info.id, ##__VA_ARGS__)
+
+#define gt_warn(_gt, _fmt, ...) \
+ drm_warn(&(_gt)->i915->drm, "GT%u: " _fmt, (_gt)->info.id, ##__VA_ARGS__)
+
+#define gt_notice(_gt, _fmt, ...) \
+ drm_notice(&(_gt)->i915->drm, "GT%u: " _fmt, (_gt)->info.id, ##__VA_ARGS__)
+
+#define gt_info(_gt, _fmt, ...) \
+ drm_info(&(_gt)->i915->drm, "GT%u: " _fmt, (_gt)->info.id, ##__VA_ARGS__)
+
+#define gt_dbg(_gt, _fmt, ...) \
+ drm_dbg(&(_gt)->i915->drm, "GT%u: " _fmt, (_gt)->info.id, ##__VA_ARGS__)
+
+#define gt_err_ratelimited(_gt, _fmt, ...) \
+ drm_err_ratelimited(&(_gt)->i915->drm, "GT%u: " _fmt, (_gt)->info.id, ##__VA_ARGS__)
+
+#define gt_probe_error(_gt, _fmt, ...) \
+ do { \
+ if (i915_error_injected()) \
+ gt_dbg(_gt, _fmt, ##__VA_ARGS__); \
+ else \
+ gt_err(_gt, _fmt, ##__VA_ARGS__); \
+ } while (0)
+
+#define gt_WARN(_gt, _condition, _fmt, ...) \
+ drm_WARN(&(_gt)->i915->drm, _condition, "GT%u: " _fmt, (_gt)->info.id, ##__VA_ARGS__)
+
+#define gt_WARN_ONCE(_gt, _condition, _fmt, ...) \
+ drm_WARN_ONCE(&(_gt)->i915->drm, _condition, "GT%u: " _fmt, (_gt)->info.id, ##__VA_ARGS__)
+
+#define gt_WARN_ON(_gt, _condition) \
+ gt_WARN(_gt, _condition, "%s", "gt_WARN_ON(" __stringify(_condition) ")")
+
+#define gt_WARN_ON_ONCE(_gt, _condition) \
+ gt_WARN_ONCE(_gt, _condition, "%s", "gt_WARN_ONCE(" __stringify(_condition) ")")
+
+#endif /* __INTEL_GT_PRINT_H__ */
diff --git a/drivers/gpu/drm/i915/gt/intel_gt_regs.h b/drivers/gpu/drm/i915/gt/intel_gt_regs.h
index a5454af2a9cf..be0f6e305c88 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt_regs.h
+++ b/drivers/gpu/drm/i915/gt/intel_gt_regs.h
@@ -67,6 +67,7 @@
#define GMD_ID_MEDIA _MMIO(MTL_MEDIA_GSI_BASE + 0xd8c)
#define MCFG_MCR_SELECTOR _MMIO(0xfd0)
+#define MTL_STEER_SEMAPHORE _MMIO(0xfd0)
#define MTL_MCR_SELECTOR _MMIO(0xfd4)
#define SF_MCR_SELECTOR _MMIO(0xfd8)
#define GEN8_MCR_SELECTOR _MMIO(0xfdc)
@@ -406,6 +407,8 @@
#define GEN9_WM_CHICKEN3 _MMIO(0x5588)
#define GEN9_FACTOR_IN_CLR_VAL_HIZ (1 << 9)
+#define XEHP_CULLBIT1 MCR_REG(0x6100)
+
#define CHICKEN_RASTER_1 MCR_REG(0x6204)
#define DIS_SF_ROUND_NEAREST_EVEN REG_BIT(8)
@@ -413,6 +416,7 @@
#define TBIMR_FAST_CLIP REG_BIT(5)
#define VFLSKPD MCR_REG(0x62a8)
+#define VF_PREFETCH_TLB_DIS REG_BIT(5)
#define DIS_OVER_FETCH_CACHE REG_BIT(1)
#define DIS_MULT_MISS_RD_SQUASH REG_BIT(0)
@@ -455,10 +459,12 @@
#define HZ_DEPTH_TEST_LE_GE_OPT_DISABLE REG_BIT(13)
#define BDW_HIZ_POWER_COMPILER_CLOCK_GATING_DISABLE REG_BIT(3)
+#define XEHP_CULLBIT2 MCR_REG(0x7030)
+
#define GEN8_L3CNTLREG _MMIO(0x7034)
#define GEN8_ERRDETBCTRL (1 << 9)
-#define PSS_MODE2 _MMIO(0x703c)
+#define XEHP_PSS_MODE2 MCR_REG(0x703c)
#define SCOREBOARD_STALL_FLUSH_CONTROL REG_BIT(5)
#define GEN7_SC_INSTDONE _MMIO(0x7100)
@@ -680,10 +686,7 @@
#define GEN6_RSTCTL _MMIO(0x9420)
#define GEN7_MISCCPCTL _MMIO(0x9424)
-#define GEN7_DOP_CLOCK_GATE_ENABLE (1 << 0)
-
-#define GEN8_MISCCPCTL MCR_REG(0x9424)
-#define GEN8_DOP_CLOCK_GATE_ENABLE REG_BIT(0)
+#define GEN7_DOP_CLOCK_GATE_ENABLE REG_BIT(0)
#define GEN12_DOP_CLOCK_GATE_RENDER_ENABLE REG_BIT(1)
#define GEN8_DOP_CLOCK_GATE_CFCLK_ENABLE (1 << 2)
#define GEN8_DOP_CLOCK_GATE_GUC_ENABLE (1 << 4)
@@ -921,6 +924,10 @@
#define MSG_IDLE_FW_MASK REG_GENMASK(13, 9)
#define MSG_IDLE_FW_SHIFT 9
+#define RC_PSMI_CTRL_GSCCS _MMIO(0x11a050)
+#define IDLE_MSG_DISABLE REG_BIT(0)
+#define PWRCTX_MAXCNT_GSCCS _MMIO(0x11a054)
+
#define FORCEWAKE_MEDIA_GEN9 _MMIO(0xa270)
#define FORCEWAKE_RENDER_GEN9 _MMIO(0xa278)
@@ -953,10 +960,11 @@
#define GEN7_DISABLE_SAMPLER_PREFETCH (1 << 30)
#define GEN8_GARBCNTL _MMIO(0xb004)
-#define GEN9_GAPS_TSV_CREDIT_DISABLE (1 << 7)
-#define GEN11_ARBITRATION_PRIO_ORDER_MASK (0x3f << 22)
-#define GEN11_HASH_CTRL_EXCL_MASK (0x7f << 0)
-#define GEN11_HASH_CTRL_EXCL_BIT0 (1 << 0)
+#define GEN11_ARBITRATION_PRIO_ORDER_MASK REG_GENMASK(27, 22)
+#define GEN12_BUS_HASH_CTL_BIT_EXC REG_BIT(7)
+#define GEN9_GAPS_TSV_CREDIT_DISABLE REG_BIT(7)
+#define GEN11_HASH_CTRL_EXCL_MASK REG_GENMASK(6, 0)
+#define GEN11_HASH_CTRL_EXCL_BIT0 REG_FIELD_PREP(GEN11_HASH_CTRL_EXCL_MASK, 0x1)
#define GEN9_SCRATCH_LNCF1 _MMIO(0xb008)
#define GEN9_LNCF_NONIA_COHERENT_ATOMICS_ENABLE REG_BIT(0)
@@ -968,7 +976,8 @@
#define GEN7_WA_FOR_GEN7_L3_CONTROL 0x3C47FF8C
#define GEN7_L3AGDIS (1 << 19)
-#define XEHPC_LNCFMISCCFGREG0 _MMIO(0xb01c)
+#define XEHPC_LNCFMISCCFGREG0 MCR_REG(0xb01c)
+#define XEHPC_HOSTCACHEEN REG_BIT(1)
#define XEHPC_OVRLSCCC REG_BIT(0)
#define GEN7_L3CNTLREG2 _MMIO(0xb020)
@@ -1030,7 +1039,7 @@
#define XEHP_L3SCQREG7 MCR_REG(0xb188)
#define BLEND_FILL_CACHING_OPT_DIS REG_BIT(3)
-#define XEHPC_L3SCRUB _MMIO(0xb18c)
+#define XEHPC_L3SCRUB MCR_REG(0xb18c)
#define SCRUB_CL_DWNGRADE_SHARED REG_BIT(12)
#define SCRUB_RATE_PER_BANK_MASK REG_GENMASK(2, 0)
#define SCRUB_RATE_4B_PER_CLK REG_FIELD_PREP(SCRUB_RATE_PER_BANK_MASK, 0x6)
@@ -1088,16 +1097,19 @@
#define XEHP_MERT_MOD_CTRL MCR_REG(0xcf28)
#define RENDER_MOD_CTRL MCR_REG(0xcf2c)
#define COMP_MOD_CTRL MCR_REG(0xcf30)
-#define VDBX_MOD_CTRL MCR_REG(0xcf34)
-#define VEBX_MOD_CTRL MCR_REG(0xcf38)
+#define XELPMP_GSC_MOD_CTRL _MMIO(0xcf30) /* media GT only */
+#define XEHP_VDBX_MOD_CTRL MCR_REG(0xcf34)
+#define XELPMP_VDBX_MOD_CTRL _MMIO(0xcf34)
+#define XEHP_VEBX_MOD_CTRL MCR_REG(0xcf38)
+#define XELPMP_VEBX_MOD_CTRL _MMIO(0xcf38)
#define FORCE_MISS_FTLB REG_BIT(3)
-#define GEN12_GAMSTLB_CTRL _MMIO(0xcf4c)
+#define XEHP_GAMSTLB_CTRL MCR_REG(0xcf4c)
#define CONTROL_BLOCK_CLKGATE_DIS REG_BIT(12)
#define EGRESS_BLOCK_CLKGATE_DIS REG_BIT(11)
#define TAG_BLOCK_CLKGATE_DIS REG_BIT(7)
-#define GEN12_GAMCNTRL_CTRL _MMIO(0xcf54)
+#define XEHP_GAMCNTRL_CTRL MCR_REG(0xcf54)
#define INVALIDATION_BROADCAST_MODE_DIS REG_BIT(12)
#define GLOBAL_INVALIDATION_MODE REG_BIT(2)
@@ -1528,6 +1540,9 @@
#define MTL_MEDIA_MC6 _MMIO(0x138048)
+#define MTL_GT_ACTIVITY_FACTOR _MMIO(0x138010)
+#define MTL_GT_L3_EXC_MASK REG_GENMASK(5, 3)
+
#define GEN6_GT_THREAD_STATUS_REG _MMIO(0x13805c)
#define GEN6_GT_THREAD_STATUS_CORE_MASK 0x7
diff --git a/drivers/gpu/drm/i915/gt/intel_gt_sysfs.c b/drivers/gpu/drm/i915/gt/intel_gt_sysfs.c
index 9486dd3bed99..6629e4c72b6b 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt_sysfs.c
+++ b/drivers/gpu/drm/i915/gt/intel_gt_sysfs.c
@@ -12,6 +12,7 @@
#include "i915_drv.h"
#include "i915_sysfs.h"
#include "intel_gt.h"
+#include "intel_gt_print.h"
#include "intel_gt_sysfs.h"
#include "intel_gt_sysfs_pm.h"
#include "intel_gt_types.h"
@@ -105,8 +106,7 @@ void intel_gt_sysfs_register(struct intel_gt *gt)
exit_fail:
kobject_put(&gt->sysfs_gt);
- drm_warn(&gt->i915->drm,
- "failed to initialize gt%d sysfs root\n", gt->info.id);
+ gt_warn(gt, "failed to initialize sysfs root\n");
}
void intel_gt_sysfs_unregister(struct intel_gt *gt)
diff --git a/drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c b/drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c
index cf71305ad586..28f27091cd3b 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c
+++ b/drivers/gpu/drm/i915/gt/intel_gt_sysfs_pm.c
@@ -11,6 +11,7 @@
#include "i915_reg.h"
#include "i915_sysfs.h"
#include "intel_gt.h"
+#include "intel_gt_print.h"
#include "intel_gt_regs.h"
#include "intel_gt_sysfs.h"
#include "intel_gt_sysfs_pm.h"
@@ -164,7 +165,6 @@ sysfs_gt_attribute_r_func(struct kobject *kobj, struct attribute *attr,
NULL); \
INTEL_GT_ATTR_RO(_name)
-#ifdef CONFIG_PM
static u32 get_residency(struct intel_gt *gt, enum intel_rc6_res_type id)
{
intel_wakeref_t wakeref;
@@ -300,14 +300,12 @@ static void intel_sysfs_rc6_init(struct intel_gt *gt, struct kobject *kobj)
{
int ret;
- if (!HAS_RC6(gt->i915))
+ if (!IS_ENABLED(CONFIG_PM) || !HAS_RC6(gt->i915))
return;
ret = __intel_gt_sysfs_create_group(kobj, rc6_attr_group);
if (ret)
- drm_warn(&gt->i915->drm,
- "failed to create gt%u RC6 sysfs files (%pe)\n",
- gt->info.id, ERR_PTR(ret));
+ gt_warn(gt, "failed to create RC6 sysfs files (%pe)\n", ERR_PTR(ret));
/*
* cannot use the is_visible() attribute because
@@ -316,24 +314,15 @@ static void intel_sysfs_rc6_init(struct intel_gt *gt, struct kobject *kobj)
if (HAS_RC6p(gt->i915)) {
ret = __intel_gt_sysfs_create_group(kobj, rc6p_attr_group);
if (ret)
- drm_warn(&gt->i915->drm,
- "failed to create gt%u RC6p sysfs files (%pe)\n",
- gt->info.id, ERR_PTR(ret));
+ gt_warn(gt, "failed to create RC6p sysfs files (%pe)\n", ERR_PTR(ret));
}
if (IS_VALLEYVIEW(gt->i915) || IS_CHERRYVIEW(gt->i915)) {
ret = __intel_gt_sysfs_create_group(kobj, media_rc6_attr_group);
if (ret)
- drm_warn(&gt->i915->drm,
- "failed to create media %u RC6 sysfs files (%pe)\n",
- gt->info.id, ERR_PTR(ret));
+ gt_warn(gt, "failed to create media RC6 sysfs files (%pe)\n", ERR_PTR(ret));
}
}
-#else
-static void intel_sysfs_rc6_init(struct intel_gt *gt, struct kobject *kobj)
-{
-}
-#endif /* CONFIG_PM */
static u32 __act_freq_mhz_show(struct intel_gt *gt)
{
@@ -745,9 +734,7 @@ void intel_gt_sysfs_pm_init(struct intel_gt *gt, struct kobject *kobj)
ret = intel_sysfs_rps_init(gt, kobj);
if (ret)
- drm_warn(&gt->i915->drm,
- "failed to create gt%u RPS sysfs files (%pe)",
- gt->info.id, ERR_PTR(ret));
+ gt_warn(gt, "failed to create RPS sysfs files (%pe)", ERR_PTR(ret));
/* end of the legacy interfaces */
if (!is_object_gt(kobj))
@@ -755,29 +742,22 @@ void intel_gt_sysfs_pm_init(struct intel_gt *gt, struct kobject *kobj)
ret = sysfs_create_file(kobj, &attr_punit_req_freq_mhz.attr);
if (ret)
- drm_warn(&gt->i915->drm,
- "failed to create gt%u punit_req_freq_mhz sysfs (%pe)",
- gt->info.id, ERR_PTR(ret));
+ gt_warn(gt, "failed to create punit_req_freq_mhz sysfs (%pe)", ERR_PTR(ret));
if (i915_mmio_reg_valid(intel_gt_perf_limit_reasons_reg(gt))) {
ret = sysfs_create_files(kobj, throttle_reason_attrs);
if (ret)
- drm_warn(&gt->i915->drm,
- "failed to create gt%u throttle sysfs files (%pe)",
- gt->info.id, ERR_PTR(ret));
+ gt_warn(gt, "failed to create throttle sysfs files (%pe)", ERR_PTR(ret));
}
if (HAS_MEDIA_RATIO_MODE(gt->i915) && intel_uc_uses_guc_slpc(&gt->uc)) {
ret = sysfs_create_files(kobj, media_perf_power_attrs);
if (ret)
- drm_warn(&gt->i915->drm,
- "failed to create gt%u media_perf_power_attrs sysfs (%pe)\n",
- gt->info.id, ERR_PTR(ret));
+ gt_warn(gt, "failed to create media_perf_power_attrs sysfs (%pe)\n",
+ ERR_PTR(ret));
}
ret = sysfs_create_files(gt->sysfs_defaults, rps_defaults_attrs);
if (ret)
- drm_warn(&gt->i915->drm,
- "failed to add gt%u rps defaults (%pe)\n",
- gt->info.id, ERR_PTR(ret));
+ gt_warn(gt, "failed to add rps defaults (%pe)\n", ERR_PTR(ret));
}
diff --git a/drivers/gpu/drm/i915/gt/intel_gt_types.h b/drivers/gpu/drm/i915/gt/intel_gt_types.h
index c1d9cd255e06..f08c2556aa25 100644
--- a/drivers/gpu/drm/i915/gt/intel_gt_types.h
+++ b/drivers/gpu/drm/i915/gt/intel_gt_types.h
@@ -30,7 +30,6 @@
#include "intel_rps_types.h"
#include "intel_migrate_types.h"
#include "intel_wakeref.h"
-#include "pxp/intel_pxp_types.h"
#include "intel_wopcm.h"
struct drm_i915_private;
@@ -233,6 +232,14 @@ struct intel_gt {
u8 instanceid;
} default_steering;
+ /**
+ * @mcr_lock: Protects the MCR steering register
+ *
+ * Protects the MCR steering register (e.g., GEN8_MCR_SELECTOR).
+ * Should be taken before uncore->lock in cases where both are desired.
+ */
+ spinlock_t mcr_lock;
+
/*
* Base of per-tile GTTMMADR where we can derive the MMIO and the GGTT.
*/
@@ -267,8 +274,6 @@ struct intel_gt {
u8 wb_index; /* Only used on HAS_L3_CCS_READ() platforms */
} mocs;
- struct intel_pxp pxp;
-
/* gt/gtN sysfs */
struct kobject sysfs_gt;
@@ -277,6 +282,9 @@ struct intel_gt {
struct kobject *sysfs_defaults;
struct i915_perf_gt perf;
+
+ /** link: &ggtt.gt_list */
+ struct list_head ggtt_link;
};
struct intel_gt_definition {
@@ -296,12 +304,6 @@ enum intel_gt_scratch_field {
/* 8 bytes */
INTEL_GT_SCRATCH_FIELD_COHERENTL3_WA = 256,
-
- /* 6 * 8 bytes */
- INTEL_GT_SCRATCH_FIELD_PERF_CS_GPR = 2048,
-
- /* 4 bytes */
- INTEL_GT_SCRATCH_FIELD_PERF_PREDICATE_RESULT_1 = 2096,
};
#endif /* __INTEL_GT_TYPES_H__ */
diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.c b/drivers/gpu/drm/i915/gt/intel_gtt.c
index 2ba3983984b9..4f436ba7a3c8 100644
--- a/drivers/gpu/drm/i915/gt/intel_gtt.c
+++ b/drivers/gpu/drm/i915/gt/intel_gtt.c
@@ -17,6 +17,7 @@
#include "i915_utils.h"
#include "intel_gt.h"
#include "intel_gt_mcr.h"
+#include "intel_gt_print.h"
#include "intel_gt_regs.h"
#include "intel_gtt.h"
@@ -461,9 +462,9 @@ void gtt_write_workarounds(struct intel_gt *gt)
intel_uncore_write(uncore,
HSW_GTT_CACHE_EN,
can_use_gtt_cache ? GTT_CACHE_EN_ALL : 0);
- drm_WARN_ON_ONCE(&i915->drm, can_use_gtt_cache &&
- intel_uncore_read(uncore,
- HSW_GTT_CACHE_EN) == 0);
+ gt_WARN_ON_ONCE(gt, can_use_gtt_cache &&
+ intel_uncore_read(uncore,
+ HSW_GTT_CACHE_EN) == 0);
}
}
@@ -482,14 +483,25 @@ static void tgl_setup_private_ppat(struct intel_uncore *uncore)
static void xehp_setup_private_ppat(struct intel_gt *gt)
{
- intel_gt_mcr_multicast_write(gt, XEHP_PAT_INDEX(0), GEN8_PPAT_WB);
- intel_gt_mcr_multicast_write(gt, XEHP_PAT_INDEX(1), GEN8_PPAT_WC);
- intel_gt_mcr_multicast_write(gt, XEHP_PAT_INDEX(2), GEN8_PPAT_WT);
- intel_gt_mcr_multicast_write(gt, XEHP_PAT_INDEX(3), GEN8_PPAT_UC);
- intel_gt_mcr_multicast_write(gt, XEHP_PAT_INDEX(4), GEN8_PPAT_WB);
- intel_gt_mcr_multicast_write(gt, XEHP_PAT_INDEX(5), GEN8_PPAT_WB);
- intel_gt_mcr_multicast_write(gt, XEHP_PAT_INDEX(6), GEN8_PPAT_WB);
- intel_gt_mcr_multicast_write(gt, XEHP_PAT_INDEX(7), GEN8_PPAT_WB);
+ enum forcewake_domains fw;
+ unsigned long flags;
+
+ fw = intel_uncore_forcewake_for_reg(gt->uncore, _MMIO(XEHP_PAT_INDEX(0).reg),
+ FW_REG_WRITE);
+ intel_uncore_forcewake_get(gt->uncore, fw);
+
+ intel_gt_mcr_lock(gt, &flags);
+ intel_gt_mcr_multicast_write_fw(gt, XEHP_PAT_INDEX(0), GEN8_PPAT_WB);
+ intel_gt_mcr_multicast_write_fw(gt, XEHP_PAT_INDEX(1), GEN8_PPAT_WC);
+ intel_gt_mcr_multicast_write_fw(gt, XEHP_PAT_INDEX(2), GEN8_PPAT_WT);
+ intel_gt_mcr_multicast_write_fw(gt, XEHP_PAT_INDEX(3), GEN8_PPAT_UC);
+ intel_gt_mcr_multicast_write_fw(gt, XEHP_PAT_INDEX(4), GEN8_PPAT_WB);
+ intel_gt_mcr_multicast_write_fw(gt, XEHP_PAT_INDEX(5), GEN8_PPAT_WB);
+ intel_gt_mcr_multicast_write_fw(gt, XEHP_PAT_INDEX(6), GEN8_PPAT_WB);
+ intel_gt_mcr_multicast_write_fw(gt, XEHP_PAT_INDEX(7), GEN8_PPAT_WB);
+ intel_gt_mcr_unlock(gt, flags);
+
+ intel_uncore_forcewake_put(gt->uncore, fw);
}
static void icl_setup_private_ppat(struct intel_uncore *uncore)
diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.h b/drivers/gpu/drm/i915/gt/intel_gtt.h
index 4d75ba4bb41d..5a775310d3fc 100644
--- a/drivers/gpu/drm/i915/gt/intel_gtt.h
+++ b/drivers/gpu/drm/i915/gt/intel_gtt.h
@@ -355,19 +355,6 @@ struct i915_ggtt {
bool do_idle_maps;
- /**
- * @pte_lost: Are ptes lost on resume?
- *
- * Whether the system was recently restored from hibernate and
- * thus may have lost pte content.
- */
- bool pte_lost;
-
- /**
- * @probed_pte: Probed pte value on suspend. Re-checked on resume.
- */
- u64 probed_pte;
-
int mtrr;
/** Bit 6 swizzling required for X tiling */
@@ -390,6 +377,9 @@ struct i915_ggtt {
struct mutex error_mutex;
struct drm_mm_node error_capture;
struct drm_mm_node uc_fw;
+
+ /** List of GTs mapping this GGTT */
+ struct list_head gt_list;
};
struct i915_ppgtt {
@@ -579,11 +569,10 @@ void intel_ggtt_unbind_vma(struct i915_address_space *vm,
int i915_ggtt_probe_hw(struct drm_i915_private *i915);
int i915_ggtt_init_hw(struct drm_i915_private *i915);
int i915_ggtt_enable_hw(struct drm_i915_private *i915);
-void i915_ggtt_enable_guc(struct i915_ggtt *ggtt);
-void i915_ggtt_disable_guc(struct i915_ggtt *ggtt);
int i915_init_ggtt(struct drm_i915_private *i915);
void i915_ggtt_driver_release(struct drm_i915_private *i915);
void i915_ggtt_driver_late_release(struct drm_i915_private *i915);
+struct i915_ggtt *i915_ggtt_create(struct drm_i915_private *i915);
static inline bool i915_ggtt_has_aperture(const struct i915_ggtt *ggtt)
{
@@ -600,17 +589,6 @@ bool i915_ggtt_resume_vm(struct i915_address_space *vm);
void i915_ggtt_suspend(struct i915_ggtt *gtt);
void i915_ggtt_resume(struct i915_ggtt *ggtt);
-/**
- * i915_ggtt_mark_pte_lost - Mark ggtt ptes as lost or clear such a marking
- * @i915 The device private.
- * @val whether the ptes should be marked as lost.
- *
- * In some cases pte content is retained across suspend, but typically lost
- * across hibernate. Typically they should be marked as lost on
- * hibernation restore and such marking cleared on suspend.
- */
-void i915_ggtt_mark_pte_lost(struct drm_i915_private *i915, bool val);
-
void
fill_page_dma(struct drm_i915_gem_object *p, const u64 val, unsigned int count);
diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.c b/drivers/gpu/drm/i915/gt/intel_lrc.c
index bbeeb6dde7ae..81a96c52a92b 100644
--- a/drivers/gpu/drm/i915/gt/intel_lrc.c
+++ b/drivers/gpu/drm/i915/gt/intel_lrc.c
@@ -1316,16 +1316,16 @@ static u32 *
dg2_emit_rcs_hang_wabb(const struct intel_context *ce, u32 *cs)
{
*cs++ = MI_LOAD_REGISTER_IMM(1);
- *cs++ = i915_mmio_reg_offset(GEN12_STATE_ACK_DEBUG);
+ *cs++ = i915_mmio_reg_offset(GEN12_STATE_ACK_DEBUG(ce->engine->mmio_base));
*cs++ = 0x21;
*cs++ = MI_LOAD_REGISTER_REG;
*cs++ = i915_mmio_reg_offset(RING_NOPID(ce->engine->mmio_base));
- *cs++ = i915_mmio_reg_offset(GEN12_CULLBIT1);
+ *cs++ = i915_mmio_reg_offset(XEHP_CULLBIT1);
*cs++ = MI_LOAD_REGISTER_REG;
*cs++ = i915_mmio_reg_offset(RING_NOPID(ce->engine->mmio_base));
- *cs++ = i915_mmio_reg_offset(GEN12_CULLBIT2);
+ *cs++ = i915_mmio_reg_offset(XEHP_CULLBIT2);
return cs;
}
diff --git a/drivers/gpu/drm/i915/gt/intel_migrate.c b/drivers/gpu/drm/i915/gt/intel_migrate.c
index 5fb74e71f27b..3f638f198796 100644
--- a/drivers/gpu/drm/i915/gt/intel_migrate.c
+++ b/drivers/gpu/drm/i915/gt/intel_migrate.c
@@ -352,6 +352,8 @@ static int max_pte_pkt_size(struct i915_request *rq, int pkt)
return pkt;
}
+#define I915_EMIT_PTE_NUM_DWORDS 6
+
static int emit_pte(struct i915_request *rq,
struct sgt_dma *it,
enum i915_cache_level cache_level,
@@ -393,7 +395,7 @@ static int emit_pte(struct i915_request *rq,
offset += (u64)rq->engine->instance << 32;
- cs = intel_ring_begin(rq, 6);
+ cs = intel_ring_begin(rq, I915_EMIT_PTE_NUM_DWORDS);
if (IS_ERR(cs))
return PTR_ERR(cs);
@@ -416,7 +418,7 @@ static int emit_pte(struct i915_request *rq,
intel_ring_advance(rq, cs);
intel_ring_update_space(ring);
- cs = intel_ring_begin(rq, 6);
+ cs = intel_ring_begin(rq, I915_EMIT_PTE_NUM_DWORDS);
if (IS_ERR(cs))
return PTR_ERR(cs);
diff --git a/drivers/gpu/drm/i915/gt/intel_mocs.c b/drivers/gpu/drm/i915/gt/intel_mocs.c
index 49fdd509527a..69b489e8dfed 100644
--- a/drivers/gpu/drm/i915/gt/intel_mocs.c
+++ b/drivers/gpu/drm/i915/gt/intel_mocs.c
@@ -613,14 +613,17 @@ static u32 l3cc_combine(u16 low, u16 high)
static void init_l3cc_table(struct intel_gt *gt,
const struct drm_i915_mocs_table *table)
{
+ unsigned long flags;
unsigned int i;
u32 l3cc;
+ intel_gt_mcr_lock(gt, &flags);
for_each_l3cc(l3cc, table, i)
if (GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 50))
intel_gt_mcr_multicast_write_fw(gt, XEHP_LNCFCMOCS(i), l3cc);
else
intel_uncore_write_fw(gt->uncore, GEN9_LNCFCMOCS(i), l3cc);
+ intel_gt_mcr_unlock(gt, flags);
}
void intel_mocs_init_engine(struct intel_engine_cs *engine)
diff --git a/drivers/gpu/drm/i915/gt/intel_rc6.c b/drivers/gpu/drm/i915/gt/intel_rc6.c
index 2ee4051e4d96..5c91622dfca4 100644
--- a/drivers/gpu/drm/i915/gt/intel_rc6.c
+++ b/drivers/gpu/drm/i915/gt/intel_rc6.c
@@ -301,7 +301,7 @@ static int chv_rc6_init(struct intel_rc6 *rc6)
pcbr = intel_uncore_read(uncore, VLV_PCBR);
if ((pcbr >> VLV_PCBR_ADDR_SHIFT) == 0) {
drm_dbg(&i915->drm, "BIOS didn't set up PCBR, fixing up\n");
- paddr = i915->dsm.end + 1 - pctx_size;
+ paddr = i915->dsm.stolen.end + 1 - pctx_size;
GEM_BUG_ON(paddr > U32_MAX);
pctx_paddr = (paddr & ~4095);
@@ -325,7 +325,7 @@ static int vlv_rc6_init(struct intel_rc6 *rc6)
/* BIOS set it up already, grab the pre-alloc'd space */
resource_size_t pcbr_offset;
- pcbr_offset = (pcbr & ~4095) - i915->dsm.start;
+ pcbr_offset = (pcbr & ~4095) - i915->dsm.stolen.start;
pctx = i915_gem_object_create_region_at(i915->mm.stolen_region,
pcbr_offset,
pctx_size,
@@ -354,10 +354,10 @@ static int vlv_rc6_init(struct intel_rc6 *rc6)
}
GEM_BUG_ON(range_overflows_end_t(u64,
- i915->dsm.start,
+ i915->dsm.stolen.start,
pctx->stolen->start,
U32_MAX));
- pctx_paddr = i915->dsm.start + pctx->stolen->start;
+ pctx_paddr = i915->dsm.stolen.start + pctx->stolen->start;
intel_uncore_write(uncore, VLV_PCBR, pctx_paddr);
out:
@@ -448,8 +448,8 @@ static bool bxt_check_bios_rc6_setup(struct intel_rc6 *rc6)
*/
rc6_ctx_base =
intel_uncore_read(uncore, RC6_CTX_BASE) & RC6_CTX_BASE_MASK;
- if (!(rc6_ctx_base >= i915->dsm_reserved.start &&
- rc6_ctx_base + PAGE_SIZE < i915->dsm_reserved.end)) {
+ if (!(rc6_ctx_base >= i915->dsm.reserved.start &&
+ rc6_ctx_base + PAGE_SIZE < i915->dsm.reserved.end)) {
drm_dbg(&i915->drm, "RC6 Base address not as expected.\n");
enable_rc6 = false;
}
diff --git a/drivers/gpu/drm/i915/gt/intel_renderstate.c b/drivers/gpu/drm/i915/gt/intel_renderstate.c
index 9c1ae070ee7b..4b56ec3743cf 100644
--- a/drivers/gpu/drm/i915/gt/intel_renderstate.c
+++ b/drivers/gpu/drm/i915/gt/intel_renderstate.c
@@ -63,7 +63,7 @@ static int render_state_setup(struct intel_renderstate *so,
u32 s = rodata->batch[i];
if (i * 4 == rodata->reloc[reloc_index]) {
- u64 r = s + so->vma->node.start;
+ u64 r = s + i915_vma_offset(so->vma);
s = lower_32_bits(r);
if (HAS_64BIT_RELOC(i915)) {
diff --git a/drivers/gpu/drm/i915/gt/intel_reset.c b/drivers/gpu/drm/i915/gt/intel_reset.c
index 78dc5e493c62..0bb9094fdacd 100644
--- a/drivers/gpu/drm/i915/gt/intel_reset.c
+++ b/drivers/gpu/drm/i915/gt/intel_reset.c
@@ -35,16 +35,6 @@
/* XXX How to handle concurrent GGTT updates using tiling registers? */
#define RESET_UNDER_STOP_MACHINE 0
-static void rmw_set_fw(struct intel_uncore *uncore, i915_reg_t reg, u32 set)
-{
- intel_uncore_rmw_fw(uncore, reg, 0, set);
-}
-
-static void rmw_clear_fw(struct intel_uncore *uncore, i915_reg_t reg, u32 clr)
-{
- intel_uncore_rmw_fw(uncore, reg, clr, 0);
-}
-
static void client_mark_guilty(struct i915_gem_context *ctx, bool banned)
{
struct drm_i915_file_private *file_priv = ctx->file_priv;
@@ -212,7 +202,7 @@ static int g4x_do_reset(struct intel_gt *gt,
int ret;
/* WaVcpClkGateDisableForMediaReset:ctg,elk */
- rmw_set_fw(uncore, VDECCLK_GATE_D, VCP_UNIT_CLOCK_GATE_DISABLE);
+ intel_uncore_rmw_fw(uncore, VDECCLK_GATE_D, 0, VCP_UNIT_CLOCK_GATE_DISABLE);
intel_uncore_posting_read_fw(uncore, VDECCLK_GATE_D);
pci_write_config_byte(pdev, I915_GDRST,
@@ -234,7 +224,7 @@ static int g4x_do_reset(struct intel_gt *gt,
out:
pci_write_config_byte(pdev, I915_GDRST, 0);
- rmw_clear_fw(uncore, VDECCLK_GATE_D, VCP_UNIT_CLOCK_GATE_DISABLE);
+ intel_uncore_rmw_fw(uncore, VDECCLK_GATE_D, VCP_UNIT_CLOCK_GATE_DISABLE, 0);
intel_uncore_posting_read_fw(uncore, VDECCLK_GATE_D);
return ret;
@@ -470,7 +460,7 @@ static int gen11_lock_sfc(struct intel_engine_cs *engine,
* to reset it as well (we will unlock it once the reset sequence is
* completed).
*/
- rmw_set_fw(uncore, sfc_lock.lock_reg, sfc_lock.lock_bit);
+ intel_uncore_rmw_fw(uncore, sfc_lock.lock_reg, 0, sfc_lock.lock_bit);
ret = __intel_wait_for_register_fw(uncore,
sfc_lock.ack_reg,
@@ -520,7 +510,7 @@ static void gen11_unlock_sfc(struct intel_engine_cs *engine)
get_sfc_forced_lock_data(engine, &sfc_lock);
- rmw_clear_fw(uncore, sfc_lock.lock_reg, sfc_lock.lock_bit);
+ intel_uncore_rmw_fw(uncore, sfc_lock.lock_reg, sfc_lock.lock_bit, 0);
}
static int __gen11_reset_engines(struct intel_gt *gt,
diff --git a/drivers/gpu/drm/i915/gt/intel_ring.c b/drivers/gpu/drm/i915/gt/intel_ring.c
index 15ec64d881c4..fb99143be98e 100644
--- a/drivers/gpu/drm/i915/gt/intel_ring.c
+++ b/drivers/gpu/drm/i915/gt/intel_ring.c
@@ -53,7 +53,7 @@ int intel_ring_pin(struct intel_ring *ring, struct i915_gem_ww_ctx *ww)
if (unlikely(ret))
goto err_unpin;
- if (i915_vma_is_map_and_fenceable(vma)) {
+ if (i915_vma_is_map_and_fenceable(vma) && !HAS_LLC(vma->vm->i915)) {
addr = (void __force *)i915_vma_pin_iomap(vma);
} else {
int type = i915_coherent_map_type(vma->vm->i915, vma->obj, false);
@@ -98,7 +98,7 @@ void intel_ring_unpin(struct intel_ring *ring)
return;
i915_vma_unset_ggtt_write(vma);
- if (i915_vma_is_map_and_fenceable(vma))
+ if (i915_vma_is_map_and_fenceable(vma) && !HAS_LLC(vma->vm->i915))
i915_vma_unpin_iomap(vma);
else
i915_gem_object_unpin_map(vma->obj);
@@ -116,7 +116,7 @@ static struct i915_vma *create_ring_vma(struct i915_ggtt *ggtt, int size)
obj = i915_gem_object_create_lmem(i915, size, I915_BO_ALLOC_VOLATILE |
I915_BO_ALLOC_PM_VOLATILE);
- if (IS_ERR(obj) && i915_ggtt_has_aperture(ggtt))
+ if (IS_ERR(obj) && i915_ggtt_has_aperture(ggtt) && !HAS_LLC(i915))
obj = i915_gem_object_create_stolen(i915, size);
if (IS_ERR(obj))
obj = i915_gem_object_create_internal(i915, size);
diff --git a/drivers/gpu/drm/i915/gt/intel_ring_submission.c b/drivers/gpu/drm/i915/gt/intel_ring_submission.c
index 356c787e11d3..827adb0cfaea 100644
--- a/drivers/gpu/drm/i915/gt/intel_ring_submission.c
+++ b/drivers/gpu/drm/i915/gt/intel_ring_submission.c
@@ -897,7 +897,7 @@ static int clear_residuals(struct i915_request *rq)
}
ret = engine->emit_bb_start(rq,
- engine->wa_ctx.vma->node.start, 0,
+ i915_vma_offset(engine->wa_ctx.vma), 0,
0);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/i915/gt/intel_rps.c b/drivers/gpu/drm/i915/gt/intel_rps.c
index 9ad3bc7201cb..f5d7b5126433 100644
--- a/drivers/gpu/drm/i915/gt/intel_rps.c
+++ b/drivers/gpu/drm/i915/gt/intel_rps.c
@@ -7,6 +7,7 @@
#include <drm/i915_drm.h>
+#include "display/intel_display.h"
#include "i915_drv.h"
#include "i915_irq.h"
#include "intel_breadcrumbs.h"
diff --git a/drivers/gpu/drm/i915/gt/intel_rps.h b/drivers/gpu/drm/i915/gt/intel_rps.h
index 9e1cad9ba0e9..c622962c6bef 100644
--- a/drivers/gpu/drm/i915/gt/intel_rps.h
+++ b/drivers/gpu/drm/i915/gt/intel_rps.h
@@ -12,6 +12,9 @@
struct i915_request;
struct drm_printer;
+#define GT_FREQUENCY_MULTIPLIER 50
+#define GEN9_FREQ_SCALER 3
+
void intel_rps_init_early(struct intel_rps *rps);
void intel_rps_init(struct intel_rps *rps);
void intel_rps_sanitize(struct intel_rps *rps);
diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c
index a0740308555d..485c5cc5d0f9 100644
--- a/drivers/gpu/drm/i915/gt/intel_workarounds.c
+++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c
@@ -30,6 +30,9 @@
* creation to have a "primed golden context", i.e. a context image that
* already contains the changes needed to all the registers.
*
+ * Context workarounds should be implemented in the \*_ctx_workarounds_init()
+ * variants respective to the targeted platforms.
+ *
* - Engine workarounds: the list of these WAs is applied whenever the specific
* engine is reset. It's also possible that a set of engine classes share a
* common power domain and they are reset together. This happens on some
@@ -42,15 +45,28 @@
* saves/restores their values before/after the reset takes place. See
* ``drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c`` for reference.
*
+ * Workarounds for registers specific to RCS and CCS should be implemented in
+ * rcs_engine_wa_init() and ccs_engine_wa_init(), respectively; those for
+ * registers belonging to BCS, VCS or VECS should be implemented in
+ * xcs_engine_wa_init(). Workarounds for registers not belonging to a specific
+ * engine's MMIO range but that are part of of the common RCS/CCS reset domain
+ * should be implemented in general_render_compute_wa_init().
+ *
* - GT workarounds: the list of these WAs is applied whenever these registers
* revert to their default values: on GPU reset, suspend/resume [1]_, etc.
*
+ * GT workarounds should be implemented in the \*_gt_workarounds_init()
+ * variants respective to the targeted platforms.
+ *
* - Register whitelist: some workarounds need to be implemented in userspace,
* but need to touch privileged registers. The whitelist in the kernel
* instructs the hardware to allow the access to happen. From the kernel side,
* this is just a special case of a MMIO workaround (as we write the list of
* these to/be-whitelisted registers to some special HW registers).
*
+ * Register whitelisting should be done in the \*_whitelist_build() variants
+ * respective to the targeted platforms.
+ *
* - Workaround batchbuffers: buffers that get executed automatically by the
* hardware on every HW context restore. These buffers are created and
* programmed in the default context so the hardware always go through those
@@ -225,6 +241,12 @@ wa_write(struct i915_wa_list *wal, i915_reg_t reg, u32 set)
}
static void
+wa_mcr_write(struct i915_wa_list *wal, i915_mcr_reg_t reg, u32 set)
+{
+ wa_mcr_write_clr_set(wal, reg, ~0, set);
+}
+
+static void
wa_write_or(struct i915_wa_list *wal, i915_reg_t reg, u32 set)
{
wa_write_clr_set(wal, reg, set, set);
@@ -777,7 +799,7 @@ static void dg2_ctx_workarounds_init(struct intel_engine_cs *engine,
/* Wa_18018764978:dg2 */
if (IS_DG2_GRAPHICS_STEP(engine->i915, G10, STEP_C0, STEP_FOREVER) ||
IS_DG2_G11(engine->i915) || IS_DG2_G12(engine->i915))
- wa_masked_en(wal, PSS_MODE2, SCOREBOARD_STALL_FLUSH_CONTROL);
+ wa_mcr_masked_en(wal, XEHP_PSS_MODE2, SCOREBOARD_STALL_FLUSH_CONTROL);
/* Wa_15010599737:dg2 */
wa_mcr_masked_en(wal, CHICKEN_RASTER_1, DIS_SF_ROUND_NEAREST_EVEN);
@@ -786,6 +808,32 @@ static void dg2_ctx_workarounds_init(struct intel_engine_cs *engine,
wa_masked_en(wal, CACHE_MODE_1, MSAA_OPTIMIZATION_REDUC_DISABLE);
}
+static void mtl_ctx_workarounds_init(struct intel_engine_cs *engine,
+ struct i915_wa_list *wal)
+{
+ struct drm_i915_private *i915 = engine->i915;
+
+ if (IS_MTL_GRAPHICS_STEP(i915, M, STEP_A0, STEP_B0) ||
+ IS_MTL_GRAPHICS_STEP(i915, P, STEP_A0, STEP_B0)) {
+ /* Wa_14014947963 */
+ wa_masked_field_set(wal, VF_PREEMPTION,
+ PREEMPTION_VERTEX_COUNT, 0x4000);
+
+ /* Wa_16013271637 */
+ wa_mcr_masked_en(wal, XEHP_SLICE_COMMON_ECO_CHICKEN1,
+ MSC_MSAA_REODER_BUF_BYPASS_DISABLE);
+
+ /* Wa_18019627453 */
+ wa_mcr_masked_en(wal, VFLSKPD, VF_PREFETCH_TLB_DIS);
+
+ /* Wa_18018764978 */
+ wa_mcr_masked_en(wal, XEHP_PSS_MODE2, SCOREBOARD_STALL_FLUSH_CONTROL);
+ }
+
+ /* Wa_18019271663 */
+ wa_masked_en(wal, CACHE_MODE_1, MSAA_OPTIMIZATION_REDUC_DISABLE);
+}
+
static void fakewa_disable_nestedbb_mode(struct intel_engine_cs *engine,
struct i915_wa_list *wal)
{
@@ -872,7 +920,9 @@ __intel_engine_init_ctx_wa(struct intel_engine_cs *engine,
if (engine->class != RENDER_CLASS)
goto done;
- if (IS_PONTEVECCHIO(i915))
+ if (IS_METEORLAKE(i915))
+ mtl_ctx_workarounds_init(engine, wal);
+ else if (IS_PONTEVECCHIO(i915))
; /* noop; none at this time */
else if (IS_DG2(i915))
dg2_ctx_workarounds_init(engine, wal);
@@ -1522,6 +1572,13 @@ xehpsdv_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal)
/* Wa_14011060649:xehpsdv */
wa_14011060649(gt, wal);
+
+ /* Wa_14012362059:xehpsdv */
+ wa_mcr_write_or(wal, XEHP_MERT_MOD_CTRL, FORCE_MISS_FTLB);
+
+ /* Wa_14014368820:xehpsdv */
+ wa_mcr_write_or(wal, XEHP_GAMCNTRL_CTRL,
+ INVALIDATION_BROADCAST_MODE_DIS | GLOBAL_INVALIDATION_MODE);
}
static void
@@ -1562,6 +1619,12 @@ dg2_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal)
DSS_ROUTER_CLKGATE_DIS);
}
+ if (IS_DG2_GRAPHICS_STEP(gt->i915, G10, STEP_A0, STEP_B0) ||
+ IS_DG2_GRAPHICS_STEP(gt->i915, G11, STEP_A0, STEP_B0)) {
+ /* Wa_14012362059:dg2 */
+ wa_mcr_write_or(wal, XEHP_MERT_MOD_CTRL, FORCE_MISS_FTLB);
+ }
+
if (IS_DG2_GRAPHICS_STEP(gt->i915, G10, STEP_A0, STEP_B0)) {
/* Wa_14010948348:dg2_g10 */
wa_write_or(wal, UNSLCGCTL9430, MSQDUNIT_CLKGATE_DIS);
@@ -1607,6 +1670,12 @@ dg2_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal)
/* Wa_14011028019:dg2_g10 */
wa_mcr_write_or(wal, SSMCGCTL9530, RTFUNIT_CLKGATE_DIS);
+
+ /* Wa_14010680813:dg2_g10 */
+ wa_mcr_write_or(wal, XEHP_GAMSTLB_CTRL,
+ CONTROL_BLOCK_CLKGATE_DIS |
+ EGRESS_BLOCK_CLKGATE_DIS |
+ TAG_BLOCK_CLKGATE_DIS);
}
/* Wa_14014830051:dg2 */
@@ -1620,7 +1689,17 @@ dg2_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal)
wa_mcr_write_or(wal, XEHP_SQCM, EN_32B_ACCESS);
/* Wa_14015795083 */
- wa_mcr_write_clr(wal, GEN8_MISCCPCTL, GEN12_DOP_CLOCK_GATE_RENDER_ENABLE);
+ wa_write_clr(wal, GEN7_MISCCPCTL, GEN12_DOP_CLOCK_GATE_RENDER_ENABLE);
+
+ /* Wa_18018781329 */
+ wa_mcr_write_or(wal, RENDER_MOD_CTRL, FORCE_MISS_FTLB);
+ wa_mcr_write_or(wal, COMP_MOD_CTRL, FORCE_MISS_FTLB);
+ wa_mcr_write_or(wal, XEHP_VDBX_MOD_CTRL, FORCE_MISS_FTLB);
+ wa_mcr_write_or(wal, XEHP_VEBX_MOD_CTRL, FORCE_MISS_FTLB);
+
+ /* Wa_1509235366:dg2 */
+ wa_mcr_write_or(wal, XEHP_GAMCNTRL_CTRL,
+ INVALIDATION_BROADCAST_MODE_DIS | GLOBAL_INVALIDATION_MODE);
}
static void
@@ -1629,13 +1708,27 @@ pvc_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal)
pvc_init_mcr(gt, wal);
/* Wa_14015795083 */
- wa_mcr_write_clr(wal, GEN8_MISCCPCTL, GEN12_DOP_CLOCK_GATE_RENDER_ENABLE);
+ wa_write_clr(wal, GEN7_MISCCPCTL, GEN12_DOP_CLOCK_GATE_RENDER_ENABLE);
+
+ /* Wa_18018781329 */
+ wa_mcr_write_or(wal, RENDER_MOD_CTRL, FORCE_MISS_FTLB);
+ wa_mcr_write_or(wal, COMP_MOD_CTRL, FORCE_MISS_FTLB);
+ wa_mcr_write_or(wal, XEHP_VDBX_MOD_CTRL, FORCE_MISS_FTLB);
+ wa_mcr_write_or(wal, XEHP_VEBX_MOD_CTRL, FORCE_MISS_FTLB);
}
static void
xelpg_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal)
{
- /* FIXME: Actual workarounds will be added in future patch(es) */
+ if (IS_MTL_GRAPHICS_STEP(gt->i915, M, STEP_A0, STEP_B0) ||
+ IS_MTL_GRAPHICS_STEP(gt->i915, P, STEP_A0, STEP_B0)) {
+ /* Wa_14014830051 */
+ wa_mcr_write_clr(wal, SARB_CHICKEN1, COMP_CKN_IN);
+
+ /* Wa_18018781329 */
+ wa_mcr_write_or(wal, RENDER_MOD_CTRL, FORCE_MISS_FTLB);
+ wa_mcr_write_or(wal, COMP_MOD_CTRL, FORCE_MISS_FTLB);
+ }
/*
* Unlike older platforms, we no longer setup implicit steering here;
@@ -1647,7 +1740,17 @@ xelpg_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal)
static void
xelpmp_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal)
{
- /* FIXME: Actual workarounds will be added in future patch(es) */
+ if (IS_MTL_MEDIA_STEP(gt->i915, STEP_A0, STEP_B0)) {
+ /*
+ * Wa_18018781329
+ *
+ * Note that although these registers are MCR on the primary
+ * GT, the media GT's versions are regular singleton registers.
+ */
+ wa_write_or(wal, XELPMP_GSC_MOD_CTRL, FORCE_MISS_FTLB);
+ wa_write_or(wal, XELPMP_VDBX_MOD_CTRL, FORCE_MISS_FTLB);
+ wa_write_or(wal, XELPMP_VEBX_MOD_CTRL, FORCE_MISS_FTLB);
+ }
debug_dump_steering(gt);
}
@@ -1767,7 +1870,8 @@ static void wa_list_apply(const struct i915_wa_list *wal)
fw = wal_get_fw_for_rmw(uncore, wal);
- spin_lock_irqsave(&uncore->lock, flags);
+ intel_gt_mcr_lock(gt, &flags);
+ spin_lock(&uncore->lock);
intel_uncore_forcewake_get__locked(uncore, fw);
for (i = 0, wa = wal->list; i < wal->count; i++, wa++) {
@@ -1796,7 +1900,8 @@ static void wa_list_apply(const struct i915_wa_list *wal)
}
intel_uncore_forcewake_put__locked(uncore, fw);
- spin_unlock_irqrestore(&uncore->lock, flags);
+ spin_unlock(&uncore->lock);
+ intel_gt_mcr_unlock(gt, flags);
}
void intel_gt_apply_workarounds(struct intel_gt *gt)
@@ -1817,7 +1922,8 @@ static bool wa_list_verify(struct intel_gt *gt,
fw = wal_get_fw_for_rmw(uncore, wal);
- spin_lock_irqsave(&uncore->lock, flags);
+ intel_gt_mcr_lock(gt, &flags);
+ spin_lock(&uncore->lock);
intel_uncore_forcewake_get__locked(uncore, fw);
for (i = 0, wa = wal->list; i < wal->count; i++, wa++)
@@ -1827,7 +1933,8 @@ static bool wa_list_verify(struct intel_gt *gt,
wal->name, from);
intel_uncore_forcewake_put__locked(uncore, fw);
- spin_unlock_irqrestore(&uncore->lock, flags);
+ spin_unlock(&uncore->lock);
+ intel_gt_mcr_unlock(gt, flags);
return ok;
}
@@ -2171,7 +2278,9 @@ void intel_engine_init_whitelist(struct intel_engine_cs *engine)
wa_init_start(w, engine->gt, "whitelist", engine->name);
- if (IS_PONTEVECCHIO(i915))
+ if (IS_METEORLAKE(i915))
+ ; /* noop; none at this time */
+ else if (IS_PONTEVECCHIO(i915))
pvc_whitelist_build(engine);
else if (IS_DG2(i915))
dg2_whitelist_build(engine);
@@ -2281,24 +2390,35 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal)
{
struct drm_i915_private *i915 = engine->i915;
- if (IS_DG2(i915)) {
- /* Wa_1509235366:dg2 */
- wa_write_or(wal, GEN12_GAMCNTRL_CTRL, INVALIDATION_BROADCAST_MODE_DIS |
- GLOBAL_INVALIDATION_MODE);
+ if (IS_MTL_GRAPHICS_STEP(i915, M, STEP_A0, STEP_B0) ||
+ IS_MTL_GRAPHICS_STEP(i915, P, STEP_A0, STEP_B0)) {
+ /* Wa_22014600077 */
+ wa_mcr_masked_en(wal, GEN10_CACHE_MODE_SS,
+ ENABLE_EU_COUNT_FOR_TDL_FLUSH);
}
- if (IS_DG2_GRAPHICS_STEP(i915, G11, STEP_A0, STEP_B0)) {
- /* Wa_14013392000:dg2_g11 */
- wa_mcr_masked_en(wal, GEN8_ROW_CHICKEN2, GEN12_ENABLE_LARGE_GRF_MODE);
- }
-
- if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_B0, STEP_FOREVER) ||
+ if (IS_MTL_GRAPHICS_STEP(i915, M, STEP_A0, STEP_B0) ||
+ IS_MTL_GRAPHICS_STEP(i915, P, STEP_A0, STEP_B0) ||
+ IS_DG2_GRAPHICS_STEP(i915, G10, STEP_B0, STEP_FOREVER) ||
IS_DG2_G11(i915) || IS_DG2_G12(i915)) {
- /* Wa_1509727124:dg2 */
+ /* Wa_1509727124 */
wa_mcr_masked_en(wal, GEN10_SAMPLER_MODE,
SC_DISABLE_POWER_OPTIMIZATION_EBB);
}
+ if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_B0, STEP_FOREVER) ||
+ IS_DG2_G11(i915) || IS_DG2_G12(i915) ||
+ IS_MTL_GRAPHICS_STEP(i915, M, STEP_A0, STEP_B0)) {
+ /* Wa_22012856258 */
+ wa_mcr_masked_en(wal, GEN8_ROW_CHICKEN2,
+ GEN12_DISABLE_READ_SUPPRESSION);
+ }
+
+ if (IS_DG2_GRAPHICS_STEP(i915, G11, STEP_A0, STEP_B0)) {
+ /* Wa_14013392000:dg2_g11 */
+ wa_mcr_masked_en(wal, GEN8_ROW_CHICKEN2, GEN12_ENABLE_LARGE_GRF_MODE);
+ }
+
if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_A0, STEP_B0) ||
IS_DG2_GRAPHICS_STEP(i915, G11, STEP_A0, STEP_B0)) {
/* Wa_14012419201:dg2 */
@@ -2306,21 +2426,6 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal)
GEN12_DISABLE_HDR_PAST_PAYLOAD_HOLD_FIX);
}
- if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_B0, STEP_C0) ||
- IS_DG2_G11(i915)) {
- /*
- * Wa_22012826095:dg2
- * Wa_22013059131:dg2
- */
- wa_mcr_write_clr_set(wal, LSC_CHICKEN_BIT_0_UDW,
- MAXREQS_PER_BANK,
- REG_FIELD_PREP(MAXREQS_PER_BANK, 2));
-
- /* Wa_22013059131:dg2 */
- wa_mcr_write_or(wal, LSC_CHICKEN_BIT_0,
- FORCE_1_SUB_MESSAGE_PER_FRAGMENT);
- }
-
/* Wa_1308578152:dg2_g10 when first gslice is fused off */
if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_B0, STEP_C0) &&
needs_wa_1308578152(engine)) {
@@ -2330,14 +2435,6 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal)
if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_B0, STEP_FOREVER) ||
IS_DG2_G11(i915) || IS_DG2_G12(i915)) {
- /* Wa_22013037850:dg2 */
- wa_mcr_write_or(wal, LSC_CHICKEN_BIT_0_UDW,
- DISABLE_128B_EVICTION_COMMAND_UDW);
-
- /* Wa_22012856258:dg2 */
- wa_mcr_masked_en(wal, GEN8_ROW_CHICKEN2,
- GEN12_DISABLE_READ_SUPPRESSION);
-
/*
* Wa_22010960976:dg2
* Wa_14013347512:dg2
@@ -2353,16 +2450,6 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal)
*/
wa_mcr_masked_en(wal, GEN8_ROW_CHICKEN,
MDQ_ARBITRATION_MODE | UGM_BACKUP_MODE);
-
- /*
- * Wa_14010918519:dg2_g10
- *
- * LSC_CHICKEN_BIT_0 always reads back as 0 is this stepping,
- * so ignoring verification.
- */
- wa_mcr_add(wal, LSC_CHICKEN_BIT_0_UDW, 0,
- FORCE_SLM_FENCE_SCOPE_TO_TILE | FORCE_UGM_FENCE_SCOPE_TO_TILE,
- 0, false);
}
if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_A0, STEP_B0)) {
@@ -2386,18 +2473,6 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal)
wa_mcr_masked_en(wal, GEN9_HALF_SLICE_CHICKEN7,
DG2_DISABLE_ROUND_ENABLE_ALLOW_FOR_SSLA);
- if (IS_DG2_GRAPHICS_STEP(engine->i915, G10, STEP_A0, STEP_B0)) {
- /* Wa_14010680813:dg2_g10 */
- wa_write_or(wal, GEN12_GAMSTLB_CTRL, CONTROL_BLOCK_CLKGATE_DIS |
- EGRESS_BLOCK_CLKGATE_DIS | TAG_BLOCK_CLKGATE_DIS);
- }
-
- if (IS_DG2_GRAPHICS_STEP(engine->i915, G10, STEP_A0, STEP_B0) ||
- IS_DG2_GRAPHICS_STEP(engine->i915, G11, STEP_A0, STEP_B0)) {
- /* Wa_14012362059:dg2 */
- wa_mcr_write_or(wal, XEHP_MERT_MOD_CTRL, FORCE_MISS_FTLB);
- }
-
if (IS_DG2_GRAPHICS_STEP(i915, G11, STEP_B0, STEP_FOREVER) ||
IS_DG2_G10(i915)) {
/* Wa_22014600077:dg2 */
@@ -2901,27 +2976,14 @@ add_render_compute_tuning_settings(struct drm_i915_private *i915,
struct i915_wa_list *wal)
{
if (IS_PONTEVECCHIO(i915)) {
- wa_write(wal, XEHPC_L3SCRUB,
- SCRUB_CL_DWNGRADE_SHARED | SCRUB_RATE_4B_PER_CLK);
+ wa_mcr_write(wal, XEHPC_L3SCRUB,
+ SCRUB_CL_DWNGRADE_SHARED | SCRUB_RATE_4B_PER_CLK);
+ wa_mcr_masked_en(wal, XEHPC_LNCFMISCCFGREG0, XEHPC_HOSTCACHEEN);
}
if (IS_DG2(i915)) {
wa_mcr_write_or(wal, XEHP_L3SCQREG7, BLEND_FILL_CACHING_OPT_DIS);
wa_mcr_write_clr_set(wal, RT_CTRL, STACKID_CTRL, STACKID_CTRL_512);
-
- /*
- * This is also listed as Wa_22012654132 for certain DG2
- * steppings, but the tuning setting programming is a superset
- * since it applies to all DG2 variants and steppings.
- *
- * Note that register 0xE420 is write-only and cannot be read
- * back for verification on DG2 (due to Wa_14012342262), so
- * we need to explicitly skip the readback.
- */
- wa_mcr_add(wal, GEN10_CACHE_MODE_SS, 0,
- _MASKED_BIT_ENABLE(ENABLE_PREFETCH_INTO_IC),
- 0 /* write-only, so skip validation */,
- true);
}
/*
@@ -2932,6 +2994,9 @@ add_render_compute_tuning_settings(struct drm_i915_private *i915,
if (INTEL_INFO(i915)->tuning_thread_rr_after_dep)
wa_mcr_masked_field_set(wal, GEN9_ROW_CHICKEN4, THREAD_EX_ARB_MODE,
THREAD_EX_ARB_MODE_RR_AFTER_DEP);
+
+ if (GRAPHICS_VER(i915) == 12 && GRAPHICS_VER_FULL(i915) < IP_VER(12, 50))
+ wa_write_clr(wal, GEN8_GARBCNTL, GEN12_BUS_HASH_CTL_BIT_EXC);
}
/*
@@ -2950,9 +3015,60 @@ general_render_compute_wa_init(struct intel_engine_cs *engine, struct i915_wa_li
add_render_compute_tuning_settings(i915, wal);
+ if (IS_MTL_GRAPHICS_STEP(i915, M, STEP_A0, STEP_B0) ||
+ IS_MTL_GRAPHICS_STEP(i915, P, STEP_A0, STEP_B0) ||
+ IS_DG2_GRAPHICS_STEP(i915, G10, STEP_B0, STEP_FOREVER) ||
+ IS_DG2_G11(i915) || IS_DG2_G12(i915)) {
+ /* Wa_22013037850 */
+ wa_mcr_write_or(wal, LSC_CHICKEN_BIT_0_UDW,
+ DISABLE_128B_EVICTION_COMMAND_UDW);
+ }
+
+ if (IS_MTL_GRAPHICS_STEP(i915, M, STEP_A0, STEP_B0) ||
+ IS_MTL_GRAPHICS_STEP(i915, P, STEP_A0, STEP_B0) ||
+ IS_PONTEVECCHIO(i915) ||
+ IS_DG2(i915)) {
+ /* Wa_22014226127 */
+ wa_mcr_write_or(wal, LSC_CHICKEN_BIT_0, DISABLE_D8_D16_COASLESCE);
+ }
+
+ if (IS_MTL_GRAPHICS_STEP(i915, M, STEP_A0, STEP_B0) ||
+ IS_MTL_GRAPHICS_STEP(i915, P, STEP_A0, STEP_B0) ||
+ IS_DG2(i915)) {
+ /* Wa_18017747507 */
+ wa_masked_en(wal, VFG_PREEMPTION_CHICKEN, POLYGON_TRIFAN_LINELOOP_DISABLE);
+ }
+
+ if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_B0, STEP_C0) ||
+ IS_DG2_G11(i915)) {
+ /*
+ * Wa_22012826095:dg2
+ * Wa_22013059131:dg2
+ */
+ wa_mcr_write_clr_set(wal, LSC_CHICKEN_BIT_0_UDW,
+ MAXREQS_PER_BANK,
+ REG_FIELD_PREP(MAXREQS_PER_BANK, 2));
+
+ /* Wa_22013059131:dg2 */
+ wa_mcr_write_or(wal, LSC_CHICKEN_BIT_0,
+ FORCE_1_SUB_MESSAGE_PER_FRAGMENT);
+ }
+
+ if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_A0, STEP_B0)) {
+ /*
+ * Wa_14010918519:dg2_g10
+ *
+ * LSC_CHICKEN_BIT_0 always reads back as 0 is this stepping,
+ * so ignoring verification.
+ */
+ wa_mcr_add(wal, LSC_CHICKEN_BIT_0_UDW, 0,
+ FORCE_SLM_FENCE_SCOPE_TO_TILE | FORCE_UGM_FENCE_SCOPE_TO_TILE,
+ 0, false);
+ }
+
if (IS_PONTEVECCHIO(i915)) {
/* Wa_16016694945 */
- wa_masked_en(wal, XEHPC_LNCFMISCCFGREG0, XEHPC_OVRLSCCC);
+ wa_mcr_masked_en(wal, XEHPC_LNCFMISCCFGREG0, XEHPC_OVRLSCCC);
}
if (IS_XEHPSDV(i915)) {
@@ -2978,30 +3094,14 @@ general_render_compute_wa_init(struct intel_engine_cs *engine, struct i915_wa_li
wa_mcr_masked_dis(wal, MLTICTXCTL, TDONRENDER);
wa_mcr_write_or(wal, L3SQCREG1_CCS0, FLUSHALLNONCOH);
}
-
- /* Wa_14012362059:xehpsdv */
- wa_mcr_write_or(wal, XEHP_MERT_MOD_CTRL, FORCE_MISS_FTLB);
-
- /* Wa_14014368820:xehpsdv */
- wa_write_or(wal, GEN12_GAMCNTRL_CTRL, INVALIDATION_BROADCAST_MODE_DIS |
- GLOBAL_INVALIDATION_MODE);
}
if (IS_DG2(i915) || IS_PONTEVECCHIO(i915)) {
/* Wa_14015227452:dg2,pvc */
wa_mcr_masked_en(wal, GEN9_ROW_CHICKEN4, XEHP_DIS_BBL_SYSPIPE);
- /* Wa_22014226127:dg2,pvc */
- wa_mcr_write_or(wal, LSC_CHICKEN_BIT_0, DISABLE_D8_D16_COASLESCE);
-
/* Wa_16015675438:dg2,pvc */
wa_masked_en(wal, FF_SLICE_CS_CHICKEN2, GEN12_PERF_FIX_BALANCING_CFE_DISABLE);
-
- /* Wa_18018781329:dg2,pvc */
- wa_mcr_write_or(wal, RENDER_MOD_CTRL, FORCE_MISS_FTLB);
- wa_mcr_write_or(wal, COMP_MOD_CTRL, FORCE_MISS_FTLB);
- wa_mcr_write_or(wal, VDBX_MOD_CTRL, FORCE_MISS_FTLB);
- wa_mcr_write_or(wal, VEBX_MOD_CTRL, FORCE_MISS_FTLB);
}
if (IS_DG2(i915)) {
@@ -3010,10 +3110,20 @@ general_render_compute_wa_init(struct intel_engine_cs *engine, struct i915_wa_li
* Wa_22015475538:dg2
*/
wa_mcr_write_or(wal, LSC_CHICKEN_BIT_0_UDW, DIS_CHAIN_2XSIMD8);
-
- /* Wa_18017747507:dg2 */
- wa_masked_en(wal, VFG_PREEMPTION_CHICKEN, POLYGON_TRIFAN_LINELOOP_DISABLE);
}
+
+ if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_A0, STEP_C0) || IS_DG2_G11(i915))
+ /*
+ * Wa_22012654132
+ *
+ * Note that register 0xE420 is write-only and cannot be read
+ * back for verification on DG2 (due to Wa_14012342262), so
+ * we need to explicitly skip the readback.
+ */
+ wa_mcr_add(wal, GEN10_CACHE_MODE_SS, 0,
+ _MASKED_BIT_ENABLE(ENABLE_PREFETCH_INTO_IC),
+ 0 /* write-only, so skip validation */,
+ true);
}
static void
diff --git a/drivers/gpu/drm/i915/gt/selftest_engine_cs.c b/drivers/gpu/drm/i915/gt/selftest_engine_cs.c
index 881b64f3e7b9..542ce6d2de19 100644
--- a/drivers/gpu/drm/i915/gt/selftest_engine_cs.c
+++ b/drivers/gpu/drm/i915/gt/selftest_engine_cs.c
@@ -178,7 +178,7 @@ static int perf_mi_bb_start(void *arg)
goto out;
err = rq->engine->emit_bb_start(rq,
- batch->node.start, 8,
+ i915_vma_offset(batch), 8,
0);
if (err)
goto out;
@@ -321,7 +321,7 @@ static int perf_mi_noop(void *arg)
goto out;
err = rq->engine->emit_bb_start(rq,
- base->node.start, 8,
+ i915_vma_offset(base), 8,
0);
if (err)
goto out;
@@ -331,8 +331,8 @@ static int perf_mi_noop(void *arg)
goto out;
err = rq->engine->emit_bb_start(rq,
- nop->node.start,
- nop->node.size,
+ i915_vma_offset(nop),
+ i915_vma_size(nop),
0);
if (err)
goto out;
diff --git a/drivers/gpu/drm/i915/gt/selftest_execlists.c b/drivers/gpu/drm/i915/gt/selftest_execlists.c
index ab2e9a6a2452..736b89a8ecf5 100644
--- a/drivers/gpu/drm/i915/gt/selftest_execlists.c
+++ b/drivers/gpu/drm/i915/gt/selftest_execlists.c
@@ -2737,11 +2737,11 @@ static int create_gang(struct intel_engine_cs *engine,
MI_SEMAPHORE_POLL |
MI_SEMAPHORE_SAD_EQ_SDD;
*cs++ = 0;
- *cs++ = lower_32_bits(vma->node.start);
- *cs++ = upper_32_bits(vma->node.start);
+ *cs++ = lower_32_bits(i915_vma_offset(vma));
+ *cs++ = upper_32_bits(i915_vma_offset(vma));
if (*prev) {
- u64 offset = (*prev)->batch->node.start;
+ u64 offset = i915_vma_offset((*prev)->batch);
/* Terminate the spinner in the next lower priority batch. */
*cs++ = MI_STORE_DWORD_IMM_GEN4;
@@ -2763,13 +2763,11 @@ static int create_gang(struct intel_engine_cs *engine,
rq->batch = i915_vma_get(vma);
i915_request_get(rq);
- i915_vma_lock(vma);
- err = i915_vma_move_to_active(vma, rq, 0);
+ err = igt_vma_move_to_active_unlocked(vma, rq, 0);
if (!err)
err = rq->engine->emit_bb_start(rq,
- vma->node.start,
+ i915_vma_offset(vma),
PAGE_SIZE, 0);
- i915_vma_unlock(vma);
i915_request_add(rq);
if (err)
goto err_rq;
@@ -3095,7 +3093,7 @@ create_gpr_user(struct intel_engine_cs *engine,
*cs++ = MI_MATH_ADD;
*cs++ = MI_MATH_STORE(MI_MATH_REG(i), MI_MATH_REG_ACCU);
- addr = result->node.start + offset + i * sizeof(*cs);
+ addr = i915_vma_offset(result) + offset + i * sizeof(*cs);
*cs++ = MI_STORE_REGISTER_MEM_GEN8;
*cs++ = CS_GPR(engine, 2 * i);
*cs++ = lower_32_bits(addr);
@@ -3105,8 +3103,8 @@ create_gpr_user(struct intel_engine_cs *engine,
MI_SEMAPHORE_POLL |
MI_SEMAPHORE_SAD_GTE_SDD;
*cs++ = i;
- *cs++ = lower_32_bits(result->node.start);
- *cs++ = upper_32_bits(result->node.start);
+ *cs++ = lower_32_bits(i915_vma_offset(result));
+ *cs++ = upper_32_bits(i915_vma_offset(result));
}
*cs++ = MI_BATCH_BUFFER_END;
@@ -3177,16 +3175,14 @@ create_gpr_client(struct intel_engine_cs *engine,
goto out_batch;
}
- i915_vma_lock(vma);
- err = i915_vma_move_to_active(vma, rq, 0);
- i915_vma_unlock(vma);
+ err = igt_vma_move_to_active_unlocked(vma, rq, 0);
i915_vma_lock(batch);
if (!err)
err = i915_vma_move_to_active(batch, rq, 0);
if (!err)
err = rq->engine->emit_bb_start(rq,
- batch->node.start,
+ i915_vma_offset(batch),
PAGE_SIZE, 0);
i915_vma_unlock(batch);
i915_vma_unpin(batch);
@@ -3514,13 +3510,11 @@ static int smoke_submit(struct preempt_smoke *smoke,
}
if (vma) {
- i915_vma_lock(vma);
- err = i915_vma_move_to_active(vma, rq, 0);
+ err = igt_vma_move_to_active_unlocked(vma, rq, 0);
if (!err)
err = rq->engine->emit_bb_start(rq,
- vma->node.start,
+ i915_vma_offset(vma),
PAGE_SIZE, 0);
- i915_vma_unlock(vma);
}
i915_request_add(rq);
diff --git a/drivers/gpu/drm/i915/gt/selftest_hangcheck.c b/drivers/gpu/drm/i915/gt/selftest_hangcheck.c
index bc05ef48c194..8b0d84f2aad2 100644
--- a/drivers/gpu/drm/i915/gt/selftest_hangcheck.c
+++ b/drivers/gpu/drm/i915/gt/selftest_hangcheck.c
@@ -96,7 +96,8 @@ err_ctx:
static u64 hws_address(const struct i915_vma *hws,
const struct i915_request *rq)
{
- return hws->node.start + offset_in_page(sizeof(u32)*rq->fence.context);
+ return i915_vma_offset(hws) +
+ offset_in_page(sizeof(u32) * rq->fence.context);
}
static struct i915_request *
@@ -180,8 +181,8 @@ hang_create_request(struct hang *h, struct intel_engine_cs *engine)
*batch++ = MI_NOOP;
*batch++ = MI_BATCH_BUFFER_START | 1 << 8 | 1;
- *batch++ = lower_32_bits(vma->node.start);
- *batch++ = upper_32_bits(vma->node.start);
+ *batch++ = lower_32_bits(i915_vma_offset(vma));
+ *batch++ = upper_32_bits(i915_vma_offset(vma));
} else if (GRAPHICS_VER(gt->i915) >= 6) {
*batch++ = MI_STORE_DWORD_IMM_GEN4;
*batch++ = 0;
@@ -194,7 +195,7 @@ hang_create_request(struct hang *h, struct intel_engine_cs *engine)
*batch++ = MI_NOOP;
*batch++ = MI_BATCH_BUFFER_START | 1 << 8;
- *batch++ = lower_32_bits(vma->node.start);
+ *batch++ = lower_32_bits(i915_vma_offset(vma));
} else if (GRAPHICS_VER(gt->i915) >= 4) {
*batch++ = MI_STORE_DWORD_IMM_GEN4 | MI_USE_GGTT;
*batch++ = 0;
@@ -207,7 +208,7 @@ hang_create_request(struct hang *h, struct intel_engine_cs *engine)
*batch++ = MI_NOOP;
*batch++ = MI_BATCH_BUFFER_START | 2 << 6;
- *batch++ = lower_32_bits(vma->node.start);
+ *batch++ = lower_32_bits(i915_vma_offset(vma));
} else {
*batch++ = MI_STORE_DWORD_IMM | MI_MEM_VIRTUAL;
*batch++ = lower_32_bits(hws_address(hws, rq));
@@ -219,7 +220,7 @@ hang_create_request(struct hang *h, struct intel_engine_cs *engine)
*batch++ = MI_NOOP;
*batch++ = MI_BATCH_BUFFER_START | 2 << 6;
- *batch++ = lower_32_bits(vma->node.start);
+ *batch++ = lower_32_bits(i915_vma_offset(vma));
}
*batch++ = MI_BATCH_BUFFER_END; /* not reached */
intel_gt_chipset_flush(engine->gt);
@@ -234,7 +235,7 @@ hang_create_request(struct hang *h, struct intel_engine_cs *engine)
if (GRAPHICS_VER(gt->i915) <= 5)
flags |= I915_DISPATCH_SECURE;
- err = rq->engine->emit_bb_start(rq, vma->node.start, PAGE_SIZE, flags);
+ err = rq->engine->emit_bb_start(rq, i915_vma_offset(vma), PAGE_SIZE, flags);
cancel_rq:
if (err) {
diff --git a/drivers/gpu/drm/i915/gt/selftest_lrc.c b/drivers/gpu/drm/i915/gt/selftest_lrc.c
index 7c56ffd2c659..a78a3d2c2e16 100644
--- a/drivers/gpu/drm/i915/gt/selftest_lrc.c
+++ b/drivers/gpu/drm/i915/gt/selftest_lrc.c
@@ -599,9 +599,7 @@ __gpr_read(struct intel_context *ce, struct i915_vma *scratch, u32 *slot)
*cs++ = 0;
}
- i915_vma_lock(scratch);
- err = i915_vma_move_to_active(scratch, rq, EXEC_OBJECT_WRITE);
- i915_vma_unlock(scratch);
+ err = igt_vma_move_to_active_unlocked(scratch, rq, EXEC_OBJECT_WRITE);
i915_request_get(rq);
i915_request_add(rq);
@@ -1030,8 +1028,8 @@ store_context(struct intel_context *ce, struct i915_vma *scratch)
while (len--) {
*cs++ = MI_STORE_REGISTER_MEM_GEN8;
*cs++ = hw[dw];
- *cs++ = lower_32_bits(scratch->node.start + x);
- *cs++ = upper_32_bits(scratch->node.start + x);
+ *cs++ = lower_32_bits(i915_vma_offset(scratch) + x);
+ *cs++ = upper_32_bits(i915_vma_offset(scratch) + x);
dw += 2;
x += 4;
@@ -1098,8 +1096,8 @@ record_registers(struct intel_context *ce,
*cs++ = MI_ARB_ON_OFF | MI_ARB_DISABLE;
*cs++ = MI_BATCH_BUFFER_START_GEN8 | BIT(8);
- *cs++ = lower_32_bits(b_before->node.start);
- *cs++ = upper_32_bits(b_before->node.start);
+ *cs++ = lower_32_bits(i915_vma_offset(b_before));
+ *cs++ = upper_32_bits(i915_vma_offset(b_before));
*cs++ = MI_ARB_ON_OFF | MI_ARB_ENABLE;
*cs++ = MI_SEMAPHORE_WAIT |
@@ -1114,8 +1112,8 @@ record_registers(struct intel_context *ce,
*cs++ = MI_ARB_ON_OFF | MI_ARB_DISABLE;
*cs++ = MI_BATCH_BUFFER_START_GEN8 | BIT(8);
- *cs++ = lower_32_bits(b_after->node.start);
- *cs++ = upper_32_bits(b_after->node.start);
+ *cs++ = lower_32_bits(i915_vma_offset(b_after));
+ *cs++ = upper_32_bits(i915_vma_offset(b_after));
intel_ring_advance(rq, cs);
@@ -1236,8 +1234,8 @@ static int poison_registers(struct intel_context *ce, u32 poison, u32 *sema)
*cs++ = MI_ARB_ON_OFF | MI_ARB_DISABLE;
*cs++ = MI_BATCH_BUFFER_START_GEN8 | BIT(8);
- *cs++ = lower_32_bits(batch->node.start);
- *cs++ = upper_32_bits(batch->node.start);
+ *cs++ = lower_32_bits(i915_vma_offset(batch));
+ *cs++ = upper_32_bits(i915_vma_offset(batch));
*cs++ = MI_STORE_DWORD_IMM_GEN4 | MI_USE_GGTT;
*cs++ = i915_ggtt_offset(ce->engine->status_page.vma) +
diff --git a/drivers/gpu/drm/i915/gt/selftest_migrate.c b/drivers/gpu/drm/i915/gt/selftest_migrate.c
index 0dc5309c90a4..e677f2da093d 100644
--- a/drivers/gpu/drm/i915/gt/selftest_migrate.c
+++ b/drivers/gpu/drm/i915/gt/selftest_migrate.c
@@ -8,6 +8,7 @@
#include "gem/i915_gem_internal.h"
#include "gem/i915_gem_lmem.h"
+#include "selftests/igt_spinner.h"
#include "selftests/i915_random.h"
static const unsigned int sizes[] = {
@@ -486,7 +487,8 @@ global_clear(struct intel_migrate *migrate, u32 sz, struct rnd_state *prng)
static int live_migrate_copy(void *arg)
{
- struct intel_migrate *migrate = arg;
+ struct intel_gt *gt = arg;
+ struct intel_migrate *migrate = &gt->migrate;
struct drm_i915_private *i915 = migrate->context->engine->i915;
I915_RND_STATE(prng);
int i;
@@ -507,7 +509,8 @@ static int live_migrate_copy(void *arg)
static int live_migrate_clear(void *arg)
{
- struct intel_migrate *migrate = arg;
+ struct intel_gt *gt = arg;
+ struct intel_migrate *migrate = &gt->migrate;
struct drm_i915_private *i915 = migrate->context->engine->i915;
I915_RND_STATE(prng);
int i;
@@ -527,6 +530,149 @@ static int live_migrate_clear(void *arg)
return 0;
}
+struct spinner_timer {
+ struct timer_list timer;
+ struct igt_spinner spin;
+};
+
+static void spinner_kill(struct timer_list *timer)
+{
+ struct spinner_timer *st = from_timer(st, timer, timer);
+
+ igt_spinner_end(&st->spin);
+ pr_info("%s\n", __func__);
+}
+
+static int live_emit_pte_full_ring(void *arg)
+{
+ struct intel_gt *gt = arg;
+ struct intel_migrate *migrate = &gt->migrate;
+ struct drm_i915_private *i915 = migrate->context->engine->i915;
+ struct drm_i915_gem_object *obj;
+ struct intel_context *ce;
+ struct i915_request *rq, *prev;
+ struct spinner_timer st;
+ struct sgt_dma it;
+ int len, sz, err;
+ u32 *cs;
+
+ /*
+ * Simple regression test to check that we don't trample the
+ * rq->reserved_space when returning from emit_pte(), if the ring is
+ * nearly full.
+ */
+
+ if (igt_spinner_init(&st.spin, to_gt(i915)))
+ return -ENOMEM;
+
+ obj = i915_gem_object_create_internal(i915, 2 * PAGE_SIZE);
+ if (IS_ERR(obj)) {
+ err = PTR_ERR(obj);
+ goto out_spinner;
+ }
+
+ err = i915_gem_object_pin_pages_unlocked(obj);
+ if (err)
+ goto out_obj;
+
+ ce = intel_migrate_create_context(migrate);
+ if (IS_ERR(ce)) {
+ err = PTR_ERR(ce);
+ goto out_obj;
+ }
+
+ ce->ring_size = SZ_4K; /* Not too big */
+
+ err = intel_context_pin(ce);
+ if (err)
+ goto out_put;
+
+ rq = igt_spinner_create_request(&st.spin, ce, MI_ARB_CHECK);
+ if (IS_ERR(rq)) {
+ err = PTR_ERR(rq);
+ goto out_unpin;
+ }
+
+ i915_request_add(rq);
+ if (!igt_wait_for_spinner(&st.spin, rq)) {
+ err = -EIO;
+ goto out_unpin;
+ }
+
+ /*
+ * Fill the rest of the ring leaving I915_EMIT_PTE_NUM_DWORDS +
+ * ring->reserved_space at the end. To actually emit the PTEs we require
+ * slightly more than I915_EMIT_PTE_NUM_DWORDS, since our object size is
+ * greater than PAGE_SIZE. The correct behaviour is to wait for more
+ * ring space in emit_pte(), otherwise we trample on the reserved_space
+ * resulting in crashes when later submitting the rq.
+ */
+
+ prev = NULL;
+ do {
+ if (prev)
+ i915_request_add(rq);
+
+ rq = i915_request_create(ce);
+ if (IS_ERR(rq)) {
+ err = PTR_ERR(rq);
+ goto out_unpin;
+ }
+
+ sz = (rq->ring->space - rq->reserved_space) / sizeof(u32) -
+ I915_EMIT_PTE_NUM_DWORDS;
+ sz = min_t(u32, sz, (SZ_1K - rq->reserved_space) / sizeof(u32) -
+ I915_EMIT_PTE_NUM_DWORDS);
+ cs = intel_ring_begin(rq, sz);
+ if (IS_ERR(cs)) {
+ err = PTR_ERR(cs);
+ goto out_rq;
+ }
+
+ memset32(cs, MI_NOOP, sz);
+ cs += sz;
+ intel_ring_advance(rq, cs);
+
+ pr_info("%s emit=%u sz=%d\n", __func__, rq->ring->emit, sz);
+
+ prev = rq;
+ } while (rq->ring->space > (rq->reserved_space +
+ I915_EMIT_PTE_NUM_DWORDS * sizeof(u32)));
+
+ timer_setup_on_stack(&st.timer, spinner_kill, 0);
+ mod_timer(&st.timer, jiffies + 2 * HZ);
+
+ /*
+ * This should wait for the spinner to be killed, otherwise we should go
+ * down in flames when doing i915_request_add().
+ */
+ pr_info("%s emite_pte ring space=%u\n", __func__, rq->ring->space);
+ it = sg_sgt(obj->mm.pages->sgl);
+ len = emit_pte(rq, &it, obj->cache_level, false, 0, CHUNK_SZ);
+ if (!len) {
+ err = -EINVAL;
+ goto out_rq;
+ }
+ if (len < 0) {
+ err = len;
+ goto out_rq;
+ }
+
+out_rq:
+ i915_request_add(rq); /* GEM_BUG_ON(rq->reserved_space > ring->space)? */
+ del_timer_sync(&st.timer);
+ destroy_timer_on_stack(&st.timer);
+out_unpin:
+ intel_context_unpin(ce);
+out_put:
+ intel_context_put(ce);
+out_obj:
+ i915_gem_object_put(obj);
+out_spinner:
+ igt_spinner_fini(&st.spin);
+ return err;
+}
+
struct threaded_migrate {
struct intel_migrate *migrate;
struct task_struct *tsk;
@@ -593,7 +739,10 @@ static int __thread_migrate_copy(void *arg)
static int thread_migrate_copy(void *arg)
{
- return threaded_migrate(arg, __thread_migrate_copy, 0);
+ struct intel_gt *gt = arg;
+ struct intel_migrate *migrate = &gt->migrate;
+
+ return threaded_migrate(migrate, __thread_migrate_copy, 0);
}
static int __thread_global_copy(void *arg)
@@ -605,7 +754,10 @@ static int __thread_global_copy(void *arg)
static int thread_global_copy(void *arg)
{
- return threaded_migrate(arg, __thread_global_copy, 0);
+ struct intel_gt *gt = arg;
+ struct intel_migrate *migrate = &gt->migrate;
+
+ return threaded_migrate(migrate, __thread_global_copy, 0);
}
static int __thread_migrate_clear(void *arg)
@@ -624,12 +776,18 @@ static int __thread_global_clear(void *arg)
static int thread_migrate_clear(void *arg)
{
- return threaded_migrate(arg, __thread_migrate_clear, 0);
+ struct intel_gt *gt = arg;
+ struct intel_migrate *migrate = &gt->migrate;
+
+ return threaded_migrate(migrate, __thread_migrate_clear, 0);
}
static int thread_global_clear(void *arg)
{
- return threaded_migrate(arg, __thread_global_clear, 0);
+ struct intel_gt *gt = arg;
+ struct intel_migrate *migrate = &gt->migrate;
+
+ return threaded_migrate(migrate, __thread_global_clear, 0);
}
int intel_migrate_live_selftests(struct drm_i915_private *i915)
@@ -637,6 +795,7 @@ int intel_migrate_live_selftests(struct drm_i915_private *i915)
static const struct i915_subtest tests[] = {
SUBTEST(live_migrate_copy),
SUBTEST(live_migrate_clear),
+ SUBTEST(live_emit_pte_full_ring),
SUBTEST(thread_migrate_copy),
SUBTEST(thread_migrate_clear),
SUBTEST(thread_global_copy),
@@ -647,7 +806,7 @@ int intel_migrate_live_selftests(struct drm_i915_private *i915)
if (!gt->migrate.context)
return 0;
- return i915_subtests(tests, &gt->migrate);
+ return intel_gt_live_subtests(tests, gt);
}
static struct drm_i915_gem_object *
diff --git a/drivers/gpu/drm/i915/gt/selftest_mocs.c b/drivers/gpu/drm/i915/gt/selftest_mocs.c
index f27cc28608d4..ca009a6a13bd 100644
--- a/drivers/gpu/drm/i915/gt/selftest_mocs.c
+++ b/drivers/gpu/drm/i915/gt/selftest_mocs.c
@@ -228,9 +228,7 @@ static int check_mocs_engine(struct live_mocs *arg,
if (IS_ERR(rq))
return PTR_ERR(rq);
- i915_vma_lock(vma);
- err = i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE);
- i915_vma_unlock(vma);
+ err = igt_vma_move_to_active_unlocked(vma, rq, EXEC_OBJECT_WRITE);
/* Read the mocs tables back using SRM */
offset = i915_ggtt_offset(vma);
diff --git a/drivers/gpu/drm/i915/gt/selftest_reset.c b/drivers/gpu/drm/i915/gt/selftest_reset.c
index 37c38bdd5f47..a9e0a91bc0e0 100644
--- a/drivers/gpu/drm/i915/gt/selftest_reset.c
+++ b/drivers/gpu/drm/i915/gt/selftest_reset.c
@@ -20,7 +20,7 @@ __igt_reset_stolen(struct intel_gt *gt,
const char *msg)
{
struct i915_ggtt *ggtt = gt->ggtt;
- const struct resource *dsm = &gt->i915->dsm;
+ const struct resource *dsm = &gt->i915->dsm.stolen;
resource_size_t num_pages, page;
struct intel_engine_cs *engine;
intel_wakeref_t wakeref;
diff --git a/drivers/gpu/drm/i915/gt/selftest_ring_submission.c b/drivers/gpu/drm/i915/gt/selftest_ring_submission.c
index 70f9ac1ec2c7..87ceb0f374b6 100644
--- a/drivers/gpu/drm/i915/gt/selftest_ring_submission.c
+++ b/drivers/gpu/drm/i915/gt/selftest_ring_submission.c
@@ -50,7 +50,7 @@ static struct i915_vma *create_wally(struct intel_engine_cs *engine)
} else {
*cs++ = MI_STORE_DWORD_IMM | MI_MEM_VIRTUAL;
}
- *cs++ = vma->node.start + 4000;
+ *cs++ = i915_vma_offset(vma) + 4000;
*cs++ = STACK_MAGIC;
*cs++ = MI_BATCH_BUFFER_END;
diff --git a/drivers/gpu/drm/i915/gt/selftest_rps.c b/drivers/gpu/drm/i915/gt/selftest_rps.c
index 39f1b7564170..6755bbc4ebda 100644
--- a/drivers/gpu/drm/i915/gt/selftest_rps.c
+++ b/drivers/gpu/drm/i915/gt/selftest_rps.c
@@ -122,14 +122,14 @@ create_spin_counter(struct intel_engine_cs *engine,
if (srm) {
*cs++ = MI_STORE_REGISTER_MEM_GEN8;
*cs++ = i915_mmio_reg_offset(CS_GPR(COUNT));
- *cs++ = lower_32_bits(vma->node.start + end * sizeof(*cs));
- *cs++ = upper_32_bits(vma->node.start + end * sizeof(*cs));
+ *cs++ = lower_32_bits(i915_vma_offset(vma) + end * sizeof(*cs));
+ *cs++ = upper_32_bits(i915_vma_offset(vma) + end * sizeof(*cs));
}
}
*cs++ = MI_BATCH_BUFFER_START_GEN8;
- *cs++ = lower_32_bits(vma->node.start + loop * sizeof(*cs));
- *cs++ = upper_32_bits(vma->node.start + loop * sizeof(*cs));
+ *cs++ = lower_32_bits(i915_vma_offset(vma) + loop * sizeof(*cs));
+ *cs++ = upper_32_bits(i915_vma_offset(vma) + loop * sizeof(*cs));
GEM_BUG_ON(cs - base > end);
i915_gem_object_flush_map(obj);
@@ -655,7 +655,7 @@ int live_rps_frequency_cs(void *arg)
err = i915_vma_move_to_active(vma, rq, 0);
if (!err)
err = rq->engine->emit_bb_start(rq,
- vma->node.start,
+ i915_vma_offset(vma),
PAGE_SIZE, 0);
i915_request_add(rq);
if (err)
@@ -794,7 +794,7 @@ int live_rps_frequency_srm(void *arg)
err = i915_vma_move_to_active(vma, rq, 0);
if (!err)
err = rq->engine->emit_bb_start(rq,
- vma->node.start,
+ i915_vma_offset(vma),
PAGE_SIZE, 0);
i915_request_add(rq);
if (err)
diff --git a/drivers/gpu/drm/i915/gt/selftest_workarounds.c b/drivers/gpu/drm/i915/gt/selftest_workarounds.c
index 96e3861706d6..14a8b25b6204 100644
--- a/drivers/gpu/drm/i915/gt/selftest_workarounds.c
+++ b/drivers/gpu/drm/i915/gt/selftest_workarounds.c
@@ -138,9 +138,7 @@ read_nonprivs(struct intel_context *ce)
goto err_pin;
}
- i915_vma_lock(vma);
- err = i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE);
- i915_vma_unlock(vma);
+ err = igt_vma_move_to_active_unlocked(vma, rq, EXEC_OBJECT_WRITE);
if (err)
goto err_req;
@@ -521,7 +519,7 @@ static int check_dirty_whitelist(struct intel_context *ce)
for (i = 0; i < engine->whitelist.count; i++) {
u32 reg = i915_mmio_reg_offset(engine->whitelist.list[i].reg);
struct i915_gem_ww_ctx ww;
- u64 addr = scratch->node.start;
+ u64 addr = i915_vma_offset(scratch);
struct i915_request *rq;
u32 srm, lrm, rsvd;
u32 expect;
@@ -640,7 +638,7 @@ retry:
goto err_request;
err = engine->emit_bb_start(rq,
- batch->node.start, PAGE_SIZE,
+ i915_vma_offset(batch), PAGE_SIZE,
0);
if (err)
goto err_request;
@@ -853,9 +851,7 @@ static int read_whitelisted_registers(struct intel_context *ce,
if (IS_ERR(rq))
return PTR_ERR(rq);
- i915_vma_lock(results);
- err = i915_vma_move_to_active(results, rq, EXEC_OBJECT_WRITE);
- i915_vma_unlock(results);
+ err = igt_vma_move_to_active_unlocked(results, rq, EXEC_OBJECT_WRITE);
if (err)
goto err_req;
@@ -870,7 +866,7 @@ static int read_whitelisted_registers(struct intel_context *ce,
}
for (i = 0; i < engine->whitelist.count; i++) {
- u64 offset = results->node.start + sizeof(u32) * i;
+ u64 offset = i915_vma_offset(results) + sizeof(u32) * i;
u32 reg = i915_mmio_reg_offset(engine->whitelist.list[i].reg);
/* Clear non priv flags */
@@ -935,14 +931,12 @@ static int scrub_whitelisted_registers(struct intel_context *ce)
goto err_request;
}
- i915_vma_lock(batch);
- err = i915_vma_move_to_active(batch, rq, 0);
- i915_vma_unlock(batch);
+ err = igt_vma_move_to_active_unlocked(batch, rq, 0);
if (err)
goto err_request;
/* Perform the writes from an unprivileged "user" batch */
- err = engine->emit_bb_start(rq, batch->node.start, 0, 0);
+ err = engine->emit_bb_start(rq, i915_vma_offset(batch), 0, 0);
err_request:
err = request_add_sync(rq, err);
diff --git a/drivers/gpu/drm/i915/gt/shmem_utils.c b/drivers/gpu/drm/i915/gt/shmem_utils.c
index 402f085f3a02..449c9ed44382 100644
--- a/drivers/gpu/drm/i915/gt/shmem_utils.c
+++ b/drivers/gpu/drm/i915/gt/shmem_utils.c
@@ -8,6 +8,7 @@
#include <linux/pagemap.h>
#include <linux/shmem_fs.h>
+#include "i915_drv.h"
#include "gem/i915_gem_object.h"
#include "gem/i915_gem_lmem.h"
#include "shmem_utils.h"
@@ -32,6 +33,8 @@ struct file *shmem_create_from_data(const char *name, void *data, size_t len)
struct file *shmem_create_from_object(struct drm_i915_gem_object *obj)
{
+ struct drm_i915_private *i915 = to_i915(obj->base.dev);
+ enum i915_map_type map_type;
struct file *file;
void *ptr;
@@ -41,8 +44,8 @@ struct file *shmem_create_from_object(struct drm_i915_gem_object *obj)
return file;
}
- ptr = i915_gem_object_pin_map_unlocked(obj, i915_gem_object_is_lmem(obj) ?
- I915_MAP_WC : I915_MAP_WB);
+ map_type = i915_coherent_map_type(i915, obj, true);
+ ptr = i915_gem_object_pin_map_unlocked(obj, map_type);
if (IS_ERR(ptr))
return ERR_CAST(ptr);
diff --git a/drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h b/drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h
index 3624abfd22d1..9d589c28f40f 100644
--- a/drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h
+++ b/drivers/gpu/drm/i915/gt/uc/guc_capture_fwif.h
@@ -73,7 +73,7 @@ struct guc_debug_capture_list_header {
struct guc_debug_capture_list {
struct guc_debug_capture_list_header header;
- struct guc_mmio_reg regs[0];
+ struct guc_mmio_reg regs[];
} __packed;
/**
@@ -125,7 +125,7 @@ struct guc_state_capture_header_t {
struct guc_state_capture_t {
struct guc_state_capture_header_t header;
- struct guc_mmio_reg mmio_entries[0];
+ struct guc_mmio_reg mmio_entries[];
} __packed;
enum guc_capture_group_types {
@@ -145,7 +145,7 @@ struct guc_state_capture_group_header_t {
/* this is the top level structure where an error-capture dump starts */
struct guc_state_capture_group_t {
struct guc_state_capture_group_header_t grp_header;
- struct guc_state_capture_t capture_entries[0];
+ struct guc_state_capture_t capture_entries[];
} __packed;
/**
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_gsc_fw.c b/drivers/gpu/drm/i915/gt/uc/intel_gsc_fw.c
new file mode 100644
index 000000000000..e73d4440c5e8
--- /dev/null
+++ b/drivers/gpu/drm/i915/gt/uc/intel_gsc_fw.c
@@ -0,0 +1,210 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2022 Intel Corporation
+ */
+
+#include "gt/intel_engine_pm.h"
+#include "gt/intel_gpu_commands.h"
+#include "gt/intel_gt.h"
+#include "gt/intel_ring.h"
+#include "intel_gsc_fw.h"
+
+#define GSC_FW_STATUS_REG _MMIO(0x116C40)
+#define GSC_FW_CURRENT_STATE REG_GENMASK(3, 0)
+#define GSC_FW_CURRENT_STATE_RESET 0
+#define GSC_FW_INIT_COMPLETE_BIT REG_BIT(9)
+
+static bool gsc_is_in_reset(struct intel_uncore *uncore)
+{
+ u32 fw_status = intel_uncore_read(uncore, GSC_FW_STATUS_REG);
+
+ return REG_FIELD_GET(GSC_FW_CURRENT_STATE, fw_status) ==
+ GSC_FW_CURRENT_STATE_RESET;
+}
+
+bool intel_gsc_uc_fw_init_done(struct intel_gsc_uc *gsc)
+{
+ struct intel_uncore *uncore = gsc_uc_to_gt(gsc)->uncore;
+ u32 fw_status = intel_uncore_read(uncore, GSC_FW_STATUS_REG);
+
+ return fw_status & GSC_FW_INIT_COMPLETE_BIT;
+}
+
+static int emit_gsc_fw_load(struct i915_request *rq, struct intel_gsc_uc *gsc)
+{
+ u32 offset = i915_ggtt_offset(gsc->local);
+ u32 *cs;
+
+ cs = intel_ring_begin(rq, 4);
+ if (IS_ERR(cs))
+ return PTR_ERR(cs);
+
+ *cs++ = GSC_FW_LOAD;
+ *cs++ = lower_32_bits(offset);
+ *cs++ = upper_32_bits(offset);
+ *cs++ = (gsc->local->size / SZ_4K) | HECI1_FW_LIMIT_VALID;
+
+ intel_ring_advance(rq, cs);
+
+ return 0;
+}
+
+static int gsc_fw_load(struct intel_gsc_uc *gsc)
+{
+ struct intel_context *ce = gsc->ce;
+ struct i915_request *rq;
+ int err;
+
+ if (!ce)
+ return -ENODEV;
+
+ rq = i915_request_create(ce);
+ if (IS_ERR(rq))
+ return PTR_ERR(rq);
+
+ if (ce->engine->emit_init_breadcrumb) {
+ err = ce->engine->emit_init_breadcrumb(rq);
+ if (err)
+ goto out_rq;
+ }
+
+ err = emit_gsc_fw_load(rq, gsc);
+ if (err)
+ goto out_rq;
+
+ err = ce->engine->emit_flush(rq, 0);
+
+out_rq:
+ i915_request_get(rq);
+
+ if (unlikely(err))
+ i915_request_set_error_once(rq, err);
+
+ i915_request_add(rq);
+
+ if (!err && i915_request_wait(rq, 0, msecs_to_jiffies(500)) < 0)
+ err = -ETIME;
+
+ i915_request_put(rq);
+
+ if (err)
+ drm_err(&gsc_uc_to_gt(gsc)->i915->drm,
+ "Request submission for GSC load failed (%d)\n",
+ err);
+
+ return err;
+}
+
+static int gsc_fw_load_prepare(struct intel_gsc_uc *gsc)
+{
+ struct intel_gt *gt = gsc_uc_to_gt(gsc);
+ struct drm_i915_private *i915 = gt->i915;
+ struct drm_i915_gem_object *obj;
+ void *src, *dst;
+
+ if (!gsc->local)
+ return -ENODEV;
+
+ obj = gsc->local->obj;
+
+ if (obj->base.size < gsc->fw.size)
+ return -ENOSPC;
+
+ dst = i915_gem_object_pin_map_unlocked(obj,
+ i915_coherent_map_type(i915, obj, true));
+ if (IS_ERR(dst))
+ return PTR_ERR(dst);
+
+ src = i915_gem_object_pin_map_unlocked(gsc->fw.obj,
+ i915_coherent_map_type(i915, gsc->fw.obj, true));
+ if (IS_ERR(src)) {
+ i915_gem_object_unpin_map(obj);
+ return PTR_ERR(src);
+ }
+
+ memset(dst, 0, obj->base.size);
+ memcpy(dst, src, gsc->fw.size);
+
+ i915_gem_object_unpin_map(gsc->fw.obj);
+ i915_gem_object_unpin_map(obj);
+
+ return 0;
+}
+
+static int gsc_fw_wait(struct intel_gt *gt)
+{
+ return intel_wait_for_register(gt->uncore,
+ GSC_FW_STATUS_REG,
+ GSC_FW_INIT_COMPLETE_BIT,
+ GSC_FW_INIT_COMPLETE_BIT,
+ 500);
+}
+
+int intel_gsc_uc_fw_upload(struct intel_gsc_uc *gsc)
+{
+ struct intel_gt *gt = gsc_uc_to_gt(gsc);
+ struct intel_uc_fw *gsc_fw = &gsc->fw;
+ int err;
+
+ /* check current fw status */
+ if (intel_gsc_uc_fw_init_done(gsc)) {
+ if (GEM_WARN_ON(!intel_uc_fw_is_loaded(gsc_fw)))
+ intel_uc_fw_change_status(gsc_fw, INTEL_UC_FIRMWARE_TRANSFERRED);
+ return -EEXIST;
+ }
+
+ if (!intel_uc_fw_is_loadable(gsc_fw))
+ return -ENOEXEC;
+
+ /* FW blob is ok, so clean the status */
+ intel_uc_fw_sanitize(&gsc->fw);
+
+ if (!gsc_is_in_reset(gt->uncore))
+ return -EIO;
+
+ err = gsc_fw_load_prepare(gsc);
+ if (err)
+ goto fail;
+
+ /*
+ * GSC is only killed by an FLR, so we need to trigger one on unload to
+ * make sure we stop it. This is because we assign a chunk of memory to
+ * the GSC as part of the FW load , so we need to make sure it stops
+ * using it when we release it to the system on driver unload. Note that
+ * this is not a problem of the unload per-se, because the GSC will not
+ * touch that memory unless there are requests for it coming from the
+ * driver; therefore, no accesses will happen while i915 is not loaded,
+ * but if we re-load the driver then the GSC might wake up and try to
+ * access that old memory location again.
+ * Given that an FLR is a very disruptive action (see the FLR function
+ * for details), we want to do it as the last action before releasing
+ * the access to the MMIO bar, which means we need to do it as part of
+ * the primary uncore cleanup.
+ * An alternative approach to the FLR would be to use a memory location
+ * that survives driver unload, like e.g. stolen memory, and keep the
+ * GSC loaded across reloads. However, this requires us to make sure we
+ * preserve that memory location on unload and then determine and
+ * reserve its offset on each subsequent load, which is not trivial, so
+ * it is easier to just kill everything and start fresh.
+ */
+ intel_uncore_set_flr_on_fini(&gt->i915->uncore);
+
+ err = gsc_fw_load(gsc);
+ if (err)
+ goto fail;
+
+ err = gsc_fw_wait(gt);
+ if (err)
+ goto fail;
+
+ /* FW is not fully operational until we enable SW proxy */
+ intel_uc_fw_change_status(gsc_fw, INTEL_UC_FIRMWARE_TRANSFERRED);
+
+ drm_info(&gt->i915->drm, "Loaded GSC firmware %s\n",
+ gsc_fw->file_selected.path);
+
+ return 0;
+
+fail:
+ return intel_uc_fw_mark_load_failed(gsc_fw, err);
+}
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_gsc_fw.h b/drivers/gpu/drm/i915/gt/uc/intel_gsc_fw.h
new file mode 100644
index 000000000000..4b5dbb44afb4
--- /dev/null
+++ b/drivers/gpu/drm/i915/gt/uc/intel_gsc_fw.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2022 Intel Corporation
+ */
+
+#ifndef _INTEL_GSC_FW_H_
+#define _INTEL_GSC_FW_H_
+
+#include <linux/types.h>
+
+struct intel_gsc_uc;
+
+int intel_gsc_uc_fw_upload(struct intel_gsc_uc *gsc);
+bool intel_gsc_uc_fw_init_done(struct intel_gsc_uc *gsc);
+#endif
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_gsc_uc.c b/drivers/gpu/drm/i915/gt/uc/intel_gsc_uc.c
new file mode 100644
index 000000000000..fd21dbd2663b
--- /dev/null
+++ b/drivers/gpu/drm/i915/gt/uc/intel_gsc_uc.c
@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2022 Intel Corporation
+ */
+
+#include <linux/types.h>
+
+#include "gt/intel_gt.h"
+#include "intel_gsc_uc.h"
+#include "intel_gsc_fw.h"
+#include "i915_drv.h"
+
+static void gsc_work(struct work_struct *work)
+{
+ struct intel_gsc_uc *gsc = container_of(work, typeof(*gsc), work);
+ struct intel_gt *gt = gsc_uc_to_gt(gsc);
+ intel_wakeref_t wakeref;
+
+ with_intel_runtime_pm(gt->uncore->rpm, wakeref)
+ intel_gsc_uc_fw_upload(gsc);
+}
+
+static bool gsc_engine_supported(struct intel_gt *gt)
+{
+ intel_engine_mask_t mask;
+
+ /*
+ * We reach here from i915_driver_early_probe for the primary GT before
+ * its engine mask is set, so we use the device info engine mask for it.
+ * For other GTs we expect the GT-specific mask to be set before we
+ * call this function.
+ */
+ GEM_BUG_ON(!gt_is_root(gt) && !gt->info.engine_mask);
+
+ if (gt_is_root(gt))
+ mask = RUNTIME_INFO(gt->i915)->platform_engine_mask;
+ else
+ mask = gt->info.engine_mask;
+
+ return __HAS_ENGINE(mask, GSC0);
+}
+
+void intel_gsc_uc_init_early(struct intel_gsc_uc *gsc)
+{
+ intel_uc_fw_init_early(&gsc->fw, INTEL_UC_FW_TYPE_GSC);
+ INIT_WORK(&gsc->work, gsc_work);
+
+ /* we can arrive here from i915_driver_early_probe for primary
+ * GT with it being not fully setup hence check device info's
+ * engine mask
+ */
+ if (!gsc_engine_supported(gsc_uc_to_gt(gsc))) {
+ intel_uc_fw_change_status(&gsc->fw, INTEL_UC_FIRMWARE_NOT_SUPPORTED);
+ return;
+ }
+}
+
+int intel_gsc_uc_init(struct intel_gsc_uc *gsc)
+{
+ static struct lock_class_key gsc_lock;
+ struct intel_gt *gt = gsc_uc_to_gt(gsc);
+ struct drm_i915_private *i915 = gt->i915;
+ struct intel_engine_cs *engine = gt->engine[GSC0];
+ struct intel_context *ce;
+ struct i915_vma *vma;
+ int err;
+
+ err = intel_uc_fw_init(&gsc->fw);
+ if (err)
+ goto out;
+
+ vma = intel_guc_allocate_vma(&gt->uc.guc, SZ_8M);
+ if (IS_ERR(vma)) {
+ err = PTR_ERR(vma);
+ goto out_fw;
+ }
+
+ gsc->local = vma;
+
+ ce = intel_engine_create_pinned_context(engine, engine->gt->vm, SZ_4K,
+ I915_GEM_HWS_GSC_ADDR,
+ &gsc_lock, "gsc_context");
+ if (IS_ERR(ce)) {
+ drm_err(&gt->i915->drm,
+ "failed to create GSC CS ctx for FW communication\n");
+ err = PTR_ERR(ce);
+ goto out_vma;
+ }
+
+ gsc->ce = ce;
+
+ intel_uc_fw_change_status(&gsc->fw, INTEL_UC_FIRMWARE_LOADABLE);
+
+ return 0;
+
+out_vma:
+ i915_vma_unpin_and_release(&gsc->local, 0);
+out_fw:
+ intel_uc_fw_fini(&gsc->fw);
+out:
+ i915_probe_error(i915, "failed with %d\n", err);
+ return err;
+}
+
+void intel_gsc_uc_fini(struct intel_gsc_uc *gsc)
+{
+ if (!intel_uc_fw_is_loadable(&gsc->fw))
+ return;
+
+ flush_work(&gsc->work);
+
+ if (gsc->ce)
+ intel_engine_destroy_pinned_context(fetch_and_zero(&gsc->ce));
+
+ i915_vma_unpin_and_release(&gsc->local, 0);
+
+ intel_uc_fw_fini(&gsc->fw);
+}
+
+void intel_gsc_uc_suspend(struct intel_gsc_uc *gsc)
+{
+ if (!intel_uc_fw_is_loadable(&gsc->fw))
+ return;
+
+ flush_work(&gsc->work);
+}
+
+void intel_gsc_uc_load_start(struct intel_gsc_uc *gsc)
+{
+ if (!intel_uc_fw_is_loadable(&gsc->fw))
+ return;
+
+ if (intel_gsc_uc_fw_init_done(gsc))
+ return;
+
+ queue_work(system_unbound_wq, &gsc->work);
+}
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_gsc_uc.h b/drivers/gpu/drm/i915/gt/uc/intel_gsc_uc.h
new file mode 100644
index 000000000000..03fd0a8e8db1
--- /dev/null
+++ b/drivers/gpu/drm/i915/gt/uc/intel_gsc_uc.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2022 Intel Corporation
+ */
+
+#ifndef _INTEL_GSC_UC_H_
+#define _INTEL_GSC_UC_H_
+
+#include "intel_uc_fw.h"
+
+struct i915_vma;
+struct intel_context;
+
+struct intel_gsc_uc {
+ /* Generic uC firmware management */
+ struct intel_uc_fw fw;
+
+ /* GSC-specific additions */
+ struct i915_vma *local; /* private memory for GSC usage */
+ struct intel_context *ce; /* for submission to GSC FW via GSC engine */
+
+ struct work_struct work; /* for delayed load */
+};
+
+void intel_gsc_uc_init_early(struct intel_gsc_uc *gsc);
+int intel_gsc_uc_init(struct intel_gsc_uc *gsc);
+void intel_gsc_uc_fini(struct intel_gsc_uc *gsc);
+void intel_gsc_uc_suspend(struct intel_gsc_uc *gsc);
+void intel_gsc_uc_load_start(struct intel_gsc_uc *gsc);
+
+static inline bool intel_gsc_uc_is_supported(struct intel_gsc_uc *gsc)
+{
+ return intel_uc_fw_is_supported(&gsc->fw);
+}
+
+static inline bool intel_gsc_uc_is_wanted(struct intel_gsc_uc *gsc)
+{
+ return intel_uc_fw_is_enabled(&gsc->fw);
+}
+
+static inline bool intel_gsc_uc_is_used(struct intel_gsc_uc *gsc)
+{
+ GEM_BUG_ON(__intel_uc_fw_status(&gsc->fw) == INTEL_UC_FIRMWARE_SELECTED);
+ return intel_uc_fw_is_available(&gsc->fw);
+}
+
+#endif
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.c b/drivers/gpu/drm/i915/gt/uc/intel_guc.c
index 52aede324788..d76508fa3af7 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.c
@@ -11,6 +11,7 @@
#include "intel_guc.h"
#include "intel_guc_ads.h"
#include "intel_guc_capture.h"
+#include "intel_guc_print.h"
#include "intel_guc_slpc.h"
#include "intel_guc_submission.h"
#include "i915_drv.h"
@@ -94,8 +95,8 @@ static void gen9_enable_guc_interrupts(struct intel_guc *guc)
assert_rpm_wakelock_held(&gt->i915->runtime_pm);
spin_lock_irq(gt->irq_lock);
- WARN_ON_ONCE(intel_uncore_read(gt->uncore, GEN8_GT_IIR(2)) &
- gt->pm_guc_events);
+ guc_WARN_ON_ONCE(guc, intel_uncore_read(gt->uncore, GEN8_GT_IIR(2)) &
+ gt->pm_guc_events);
gen6_gt_pm_enable_irq(gt, gt->pm_guc_events);
spin_unlock_irq(gt->irq_lock);
@@ -274,8 +275,9 @@ static u32 guc_ctl_wa_flags(struct intel_guc *guc)
if (IS_DG2_GRAPHICS_STEP(gt->i915, G10, STEP_A0, STEP_B0))
flags |= GUC_WA_GAM_CREDITS;
- /* Wa_14014475959:dg2 */
- if (IS_DG2(gt->i915))
+ /* Wa_14014475959 */
+ if (IS_MTL_GRAPHICS_STEP(gt->i915, M, STEP_A0, STEP_B0) ||
+ IS_DG2(gt->i915))
flags |= GUC_WA_HOLD_CCS_SWITCHOUT;
/*
@@ -289,7 +291,9 @@ static u32 guc_ctl_wa_flags(struct intel_guc *guc)
flags |= GUC_WA_DUAL_QUEUE;
/* Wa_22011802037: graphics version 11/12 */
- if (IS_GRAPHICS_VER(gt->i915, 11, 12))
+ if (IS_MTL_GRAPHICS_STEP(gt->i915, M, STEP_A0, STEP_B0) ||
+ (GRAPHICS_VER(gt->i915) >= 11 &&
+ GRAPHICS_VER_FULL(gt->i915) < IP_VER(12, 70)))
flags |= GUC_WA_PRE_PARSER;
/* Wa_16011777198:dg2 */
@@ -339,7 +343,7 @@ static void guc_init_params(struct intel_guc *guc)
params[GUC_CTL_DEVID] = guc_ctl_devid(guc);
for (i = 0; i < GUC_CTL_MAX_DWORDS; i++)
- DRM_DEBUG_DRIVER("param[%2d] = %#x\n", i, params[i]);
+ guc_dbg(guc, "param[%2d] = %#x\n", i, params[i]);
}
/*
@@ -386,7 +390,6 @@ void intel_guc_dump_time_info(struct intel_guc *guc, struct drm_printer *p)
int intel_guc_init(struct intel_guc *guc)
{
- struct intel_gt *gt = guc_to_gt(guc);
int ret;
ret = intel_uc_fw_init(&guc->fw);
@@ -430,9 +433,6 @@ int intel_guc_init(struct intel_guc *guc)
/* now that everything is perma-pinned, initialize the parameters */
guc_init_params(guc);
- /* We need to notify the guc whenever we change the GGTT */
- i915_ggtt_enable_guc(gt->ggtt);
-
intel_uc_fw_change_status(&guc->fw, INTEL_UC_FIRMWARE_LOADABLE);
return 0;
@@ -451,19 +451,15 @@ err_fw:
intel_uc_fw_fini(&guc->fw);
out:
intel_uc_fw_change_status(&guc->fw, INTEL_UC_FIRMWARE_INIT_FAIL);
- i915_probe_error(gt->i915, "failed with %d\n", ret);
+ guc_probe_error(guc, "failed with %pe\n", ERR_PTR(ret));
return ret;
}
void intel_guc_fini(struct intel_guc *guc)
{
- struct intel_gt *gt = guc_to_gt(guc);
-
if (!intel_uc_fw_is_loadable(&guc->fw))
return;
- i915_ggtt_disable_guc(gt->ggtt);
-
if (intel_guc_slpc_is_used(guc))
intel_guc_slpc_fini(&guc->slpc);
@@ -484,7 +480,6 @@ void intel_guc_fini(struct intel_guc *guc)
int intel_guc_send_mmio(struct intel_guc *guc, const u32 *request, u32 len,
u32 *response_buf, u32 response_buf_size)
{
- struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
struct intel_uncore *uncore = guc_to_gt(guc)->uncore;
u32 header;
int i;
@@ -519,7 +514,7 @@ retry:
10, 10, &header);
if (unlikely(ret)) {
timeout:
- drm_err(&i915->drm, "mmio request %#x: no reply %x\n",
+ guc_err(guc, "mmio request %#x: no reply %x\n",
request[0], header);
goto out;
}
@@ -541,7 +536,7 @@ timeout:
if (FIELD_GET(GUC_HXG_MSG_0_TYPE, header) == GUC_HXG_TYPE_NO_RESPONSE_RETRY) {
u32 reason = FIELD_GET(GUC_HXG_RETRY_MSG_0_REASON, header);
- drm_dbg(&i915->drm, "mmio request %#x: retrying, reason %u\n",
+ guc_dbg(guc, "mmio request %#x: retrying, reason %u\n",
request[0], reason);
goto retry;
}
@@ -550,7 +545,7 @@ timeout:
u32 hint = FIELD_GET(GUC_HXG_FAILURE_MSG_0_HINT, header);
u32 error = FIELD_GET(GUC_HXG_FAILURE_MSG_0_ERROR, header);
- drm_err(&i915->drm, "mmio request %#x: failure %x/%u\n",
+ guc_err(guc, "mmio request %#x: failure %x/%u\n",
request[0], error, hint);
ret = -ENXIO;
goto out;
@@ -558,7 +553,7 @@ timeout:
if (FIELD_GET(GUC_HXG_MSG_0_TYPE, header) != GUC_HXG_TYPE_RESPONSE_SUCCESS) {
proto:
- drm_err(&i915->drm, "mmio request %#x: unexpected reply %#x\n",
+ guc_err(guc, "mmio request %#x: unexpected reply %#x\n",
request[0], header);
ret = -EPROTO;
goto out;
@@ -601,9 +596,9 @@ int intel_guc_to_host_process_recv_msg(struct intel_guc *guc,
msg = payload[0] & guc->msg_enabled_mask;
if (msg & INTEL_GUC_RECV_MSG_CRASH_DUMP_POSTED)
- drm_err(&guc_to_gt(guc)->i915->drm, "Received early GuC crash dump notification!\n");
+ guc_err(guc, "Received early crash dump notification!\n");
if (msg & INTEL_GUC_RECV_MSG_EXCEPTION)
- drm_err(&guc_to_gt(guc)->i915->drm, "Received early GuC exception notification!\n");
+ guc_err(guc, "Received early exception notification!\n");
return 0;
}
@@ -657,7 +652,8 @@ int intel_guc_suspend(struct intel_guc *guc)
*/
ret = intel_guc_send_mmio(guc, action, ARRAY_SIZE(action), NULL, 0);
if (ret)
- DRM_ERROR("GuC suspend: RESET_CLIENT action failed with error %d!\n", ret);
+ guc_err(guc, "suspend: RESET_CLIENT action failed with %pe\n",
+ ERR_PTR(ret));
}
/* Signal that the GuC isn't running. */
@@ -832,12 +828,11 @@ static int __guc_action_self_cfg(struct intel_guc *guc, u16 key, u16 len, u64 va
static int __guc_self_cfg(struct intel_guc *guc, u16 key, u16 len, u64 value)
{
- struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
int err = __guc_action_self_cfg(guc, key, len, value);
if (unlikely(err))
- i915_probe_error(i915, "Unsuccessful self-config (%pe) key %#hx value %#llx\n",
- ERR_PTR(err), key, value);
+ guc_probe_error(guc, "Unsuccessful self-config (%pe) key %#hx value %#llx\n",
+ ERR_PTR(err), key, value);
return err;
}
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.h b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
index 1bb3f9829286..bb4dfe707a7d 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
@@ -158,6 +158,9 @@ struct intel_guc {
bool submission_selected;
/** @submission_initialized: tracks whether GuC submission has been initialised */
bool submission_initialized;
+ /** @submission_version: Submission API version of the currently loaded firmware */
+ struct intel_uc_fw_ver submission_version;
+
/**
* @rc_supported: tracks whether we support GuC rc on the current platform
*/
@@ -268,6 +271,14 @@ struct intel_guc {
#endif
};
+/*
+ * GuC version number components are only 8-bit, so converting to a 32bit 8.8.8
+ * integer works.
+ */
+#define MAKE_GUC_VER(maj, min, pat) (((maj) << 16) | ((min) << 8) | (pat))
+#define MAKE_GUC_VER_STRUCT(ver) MAKE_GUC_VER((ver).major, (ver).minor, (ver).patch)
+#define GUC_SUBMIT_VER(guc) MAKE_GUC_VER_STRUCT((guc)->submission_version)
+
static inline struct intel_guc *log_to_guc(struct intel_guc_log *log)
{
return container_of(log, struct intel_guc, log);
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
index a7f737c4792e..69ce06faf8cd 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ads.c
@@ -15,6 +15,7 @@
#include "intel_guc_ads.h"
#include "intel_guc_capture.h"
#include "intel_guc_fwif.h"
+#include "intel_guc_print.h"
#include "intel_uc.h"
#include "i915_drv.h"
@@ -427,7 +428,7 @@ static long guc_mmio_reg_state_create(struct intel_guc *guc)
guc->ads_regset = temp_set.storage;
- drm_dbg(&guc_to_gt(guc)->i915->drm, "Used %zu KB for temporary ADS regset\n",
+ guc_dbg(guc, "Used %zu KB for temporary ADS regset\n",
(temp_set.storage_max * sizeof(struct guc_mmio_reg)) >> 10);
return total * sizeof(struct guc_mmio_reg);
@@ -621,7 +622,7 @@ static void guc_init_golden_context(struct intel_guc *guc)
engine = find_engine_state(gt, engine_class);
if (!engine) {
- drm_err(&gt->i915->drm, "No engine state recorded for class %d!\n",
+ guc_err(guc, "No engine state recorded for class %d!\n",
engine_class);
ads_blob_write(guc, ads.eng_state_size[guc_class], 0);
ads_blob_write(guc, ads.golden_context_lrca[guc_class], 0);
@@ -646,7 +647,6 @@ static int
guc_capture_prep_lists(struct intel_guc *guc)
{
struct intel_gt *gt = guc_to_gt(guc);
- struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
u32 ads_ggtt, capture_offset, null_ggtt, total_size = 0;
struct guc_gt_system_info local_info;
struct iosys_map info_map;
@@ -751,7 +751,7 @@ engine_instance_list:
}
if (guc->ads_capture_size && guc->ads_capture_size != PAGE_ALIGN(total_size))
- drm_warn(&i915->drm, "GuC->ADS->Capture alloc size changed from %d to %d\n",
+ guc_warn(guc, "ADS capture alloc size changed from %d to %d\n",
guc->ads_capture_size, PAGE_ALIGN(total_size));
return PAGE_ALIGN(total_size);
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
index 1c1b85073b4b..fc3b994626a4 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c
@@ -1506,7 +1506,7 @@ int intel_guc_capture_print_engine_node(struct drm_i915_error_state_buf *ebuf,
if (!ebuf || !ee)
return -EINVAL;
- cap = ee->capture;
+ cap = ee->guc_capture;
if (!cap || !ee->engine)
return -ENODEV;
@@ -1576,8 +1576,8 @@ void intel_guc_capture_free_node(struct intel_engine_coredump *ee)
if (!ee || !ee->guc_capture_node)
return;
- guc_capture_add_node_to_cachelist(ee->capture, ee->guc_capture_node);
- ee->capture = NULL;
+ guc_capture_add_node_to_cachelist(ee->guc_capture, ee->guc_capture_node);
+ ee->guc_capture = NULL;
ee->guc_capture_node = NULL;
}
@@ -1611,7 +1611,7 @@ void intel_guc_capture_get_matching_node(struct intel_gt *gt,
(ce->lrc.lrca & CTX_GTT_ADDRESS_MASK)) {
list_del(&n->link);
ee->guc_capture_node = n;
- ee->capture = guc->capture;
+ ee->guc_capture = guc->capture;
return;
}
}
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c
index 2b22065e87bf..1803a633ed64 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c
@@ -11,38 +11,23 @@
#include "i915_drv.h"
#include "intel_guc_ct.h"
-#include "gt/intel_gt.h"
+#include "intel_guc_print.h"
static inline struct intel_guc *ct_to_guc(struct intel_guc_ct *ct)
{
return container_of(ct, struct intel_guc, ct);
}
-static inline struct intel_gt *ct_to_gt(struct intel_guc_ct *ct)
-{
- return guc_to_gt(ct_to_guc(ct));
-}
-
-static inline struct drm_i915_private *ct_to_i915(struct intel_guc_ct *ct)
-{
- return ct_to_gt(ct)->i915;
-}
-
-static inline struct drm_device *ct_to_drm(struct intel_guc_ct *ct)
-{
- return &ct_to_i915(ct)->drm;
-}
-
#define CT_ERROR(_ct, _fmt, ...) \
- drm_err(ct_to_drm(_ct), "CT: " _fmt, ##__VA_ARGS__)
+ guc_err(ct_to_guc(_ct), "CT: " _fmt, ##__VA_ARGS__)
#ifdef CONFIG_DRM_I915_DEBUG_GUC
#define CT_DEBUG(_ct, _fmt, ...) \
- drm_dbg(ct_to_drm(_ct), "CT: " _fmt, ##__VA_ARGS__)
+ guc_dbg(ct_to_guc(_ct), "CT: " _fmt, ##__VA_ARGS__)
#else
#define CT_DEBUG(...) do { } while (0)
#endif
#define CT_PROBE_ERROR(_ct, _fmt, ...) \
- i915_probe_error(ct_to_i915(ct), "CT: " _fmt, ##__VA_ARGS__)
+ guc_probe_error(ct_to_guc(ct), "CT: " _fmt, ##__VA_ARGS__)
/**
* DOC: CTB Blob
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c
index 5b86b2e286e0..69133420c78b 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_fw.c
@@ -13,6 +13,7 @@
#include "gt/intel_gt_mcr.h"
#include "gt/intel_gt_regs.h"
#include "intel_guc_fw.h"
+#include "intel_guc_print.h"
#include "i915_drv.h"
static void guc_prepare_xfer(struct intel_gt *gt)
@@ -38,9 +39,8 @@ static void guc_prepare_xfer(struct intel_gt *gt)
if (GRAPHICS_VER(uncore->i915) == 9) {
/* DOP Clock Gating Enable for GuC clocks */
- intel_gt_mcr_multicast_write(gt, GEN8_MISCCPCTL,
- GEN8_DOP_CLOCK_GATE_GUC_ENABLE |
- intel_gt_mcr_read_any(gt, GEN8_MISCCPCTL));
+ intel_uncore_rmw(uncore, GEN7_MISCCPCTL, 0,
+ GEN8_DOP_CLOCK_GATE_GUC_ENABLE);
/* allows for 5us (in 10ns units) before GT can go to RC6 */
intel_uncore_write(uncore, GUC_ARAT_C6DIS, 0x1FF);
@@ -103,8 +103,10 @@ static inline bool guc_ready(struct intel_uncore *uncore, u32 *status)
return uk_val == INTEL_GUC_LOAD_STATUS_READY;
}
-static int guc_wait_ucode(struct intel_uncore *uncore)
+static int guc_wait_ucode(struct intel_guc *guc)
{
+ struct intel_gt *gt = guc_to_gt(guc);
+ struct intel_uncore *uncore = gt->uncore;
u32 status;
int ret;
@@ -127,10 +129,8 @@ static int guc_wait_ucode(struct intel_uncore *uncore)
*/
ret = wait_for(guc_ready(uncore, &status), 200);
if (ret) {
- struct drm_device *drm = &uncore->i915->drm;
-
- drm_info(drm, "GuC load failed: status = 0x%08X\n", status);
- drm_info(drm, "GuC load failed: status: Reset = %d, "
+ guc_info(guc, "load failed: status = 0x%08X\n", status);
+ guc_info(guc, "load failed: status: Reset = %d, "
"BootROM = 0x%02X, UKernel = 0x%02X, "
"MIA = 0x%02X, Auth = 0x%02X\n",
REG_FIELD_GET(GS_MIA_IN_RESET, status),
@@ -140,12 +140,12 @@ static int guc_wait_ucode(struct intel_uncore *uncore)
REG_FIELD_GET(GS_AUTH_STATUS_MASK, status));
if ((status & GS_BOOTROM_MASK) == GS_BOOTROM_RSA_FAILED) {
- drm_info(drm, "GuC firmware signature verification failed\n");
+ guc_info(guc, "firmware signature verification failed\n");
ret = -ENOEXEC;
}
if (REG_FIELD_GET(GS_UKERNEL_MASK, status) == INTEL_GUC_LOAD_STATUS_EXCEPTION) {
- drm_info(drm, "GuC firmware exception. EIP: %#x\n",
+ guc_info(guc, "firmware exception. EIP: %#x\n",
intel_uncore_read(uncore, SOFT_SCRATCH(13)));
ret = -ENXIO;
}
@@ -194,7 +194,7 @@ int intel_guc_fw_upload(struct intel_guc *guc)
if (ret)
goto out;
- ret = guc_wait_ucode(uncore);
+ ret = guc_wait_ucode(guc);
if (ret)
goto out;
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c
index 68331c538b0a..c3792ddeec80 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c
@@ -12,6 +12,7 @@
#include "i915_memcpy.h"
#include "intel_guc_capture.h"
#include "intel_guc_log.h"
+#include "intel_guc_print.h"
#if defined(CONFIG_DRM_I915_DEBUG_GUC)
#define GUC_LOG_DEFAULT_CRASH_BUFFER_SIZE SZ_2M
@@ -39,7 +40,6 @@ struct guc_log_section {
static void _guc_log_init_sizes(struct intel_guc_log *log)
{
struct intel_guc *guc = log_to_guc(log);
- struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
static const struct guc_log_section sections[GUC_LOG_SECTIONS_LIMIT] = {
{
GUC_LOG_CRASH_MASK >> GUC_LOG_CRASH_SHIFT,
@@ -82,12 +82,12 @@ static void _guc_log_init_sizes(struct intel_guc_log *log)
}
if (!IS_ALIGNED(log->sizes[i].bytes, log->sizes[i].units))
- drm_err(&i915->drm, "Mis-aligned GuC log %s size: 0x%X vs 0x%X!",
+ guc_err(guc, "Mis-aligned log %s size: 0x%X vs 0x%X!\n",
sections[i].name, log->sizes[i].bytes, log->sizes[i].units);
log->sizes[i].count = log->sizes[i].bytes / log->sizes[i].units;
if (!log->sizes[i].count) {
- drm_err(&i915->drm, "Zero GuC log %s size!", sections[i].name);
+ guc_err(guc, "Zero log %s size!\n", sections[i].name);
} else {
/* Size is +1 unit */
log->sizes[i].count--;
@@ -95,14 +95,14 @@ static void _guc_log_init_sizes(struct intel_guc_log *log)
/* Clip to field size */
if (log->sizes[i].count > sections[i].max) {
- drm_err(&i915->drm, "GuC log %s size too large: %d vs %d!",
+ guc_err(guc, "log %s size too large: %d vs %d!\n",
sections[i].name, log->sizes[i].count + 1, sections[i].max + 1);
log->sizes[i].count = sections[i].max;
}
}
if (log->sizes[GUC_LOG_SECTIONS_CRASH].units != log->sizes[GUC_LOG_SECTIONS_DEBUG].units) {
- drm_err(&i915->drm, "Unit mis-match for GuC log crash and debug sections: %d vs %d!",
+ guc_err(guc, "Unit mismatch for crash and debug sections: %d vs %d!\n",
log->sizes[GUC_LOG_SECTIONS_CRASH].units,
log->sizes[GUC_LOG_SECTIONS_DEBUG].units);
log->sizes[GUC_LOG_SECTIONS_CRASH].units = log->sizes[GUC_LOG_SECTIONS_DEBUG].units;
@@ -374,6 +374,7 @@ size_t intel_guc_get_log_buffer_offset(struct intel_guc_log *log,
static void _guc_log_copy_debuglogs_for_relay(struct intel_guc_log *log)
{
+ struct intel_guc *guc = log_to_guc(log);
unsigned int buffer_size, read_offset, write_offset, bytes_to_copy, full_cnt;
struct guc_log_buffer_state *log_buf_state, *log_buf_snapshot_state;
struct guc_log_buffer_state log_buf_state_local;
@@ -383,7 +384,7 @@ static void _guc_log_copy_debuglogs_for_relay(struct intel_guc_log *log)
mutex_lock(&log->relay.lock);
- if (WARN_ON(!intel_guc_log_relay_created(log)))
+ if (guc_WARN_ON(guc, !intel_guc_log_relay_created(log)))
goto out_unlock;
/* Get the pointer to shared GuC log buffer */
@@ -398,7 +399,7 @@ static void _guc_log_copy_debuglogs_for_relay(struct intel_guc_log *log)
* Used rate limited to avoid deluge of messages, logs might be
* getting consumed by User at a slow rate.
*/
- DRM_ERROR_RATELIMITED("no sub-buffer to copy general logs\n");
+ guc_err_ratelimited(guc, "no sub-buffer to copy general logs\n");
log->relay.full_count++;
goto out_unlock;
@@ -451,7 +452,7 @@ static void _guc_log_copy_debuglogs_for_relay(struct intel_guc_log *log)
write_offset = buffer_size;
} else if (unlikely((read_offset > buffer_size) ||
(write_offset > buffer_size))) {
- DRM_ERROR("invalid log buffer state\n");
+ guc_err(guc, "invalid log buffer state\n");
/* copy whole buffer as offsets are unreliable */
read_offset = 0;
write_offset = buffer_size;
@@ -547,7 +548,7 @@ static int guc_log_relay_create(struct intel_guc_log *log)
subbuf_size, n_subbufs,
&relay_callbacks, dev_priv);
if (!guc_log_relay_chan) {
- DRM_ERROR("Couldn't create relay chan for GuC logging\n");
+ guc_err(guc, "Couldn't create relay channel for logging\n");
ret = -ENOMEM;
return ret;
@@ -596,9 +597,8 @@ static u32 __get_default_log_level(struct intel_guc_log *log)
}
if (i915->params.guc_log_level > GUC_LOG_LEVEL_MAX) {
- DRM_WARN("Incompatible option detected: %s=%d, %s!\n",
- "guc_log_level", i915->params.guc_log_level,
- "verbosity too high");
+ guc_warn(guc, "Log verbosity param out of range: %d > %d!\n",
+ i915->params.guc_log_level, GUC_LOG_LEVEL_MAX);
return (IS_ENABLED(CONFIG_DRM_I915_DEBUG) ||
IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)) ?
GUC_LOG_LEVEL_MAX : GUC_LOG_LEVEL_DISABLED;
@@ -641,15 +641,15 @@ int intel_guc_log_create(struct intel_guc_log *log)
log->buf_addr = vaddr;
log->level = __get_default_log_level(log);
- DRM_DEBUG_DRIVER("guc_log_level=%d (%s, verbose:%s, verbosity:%d)\n",
- log->level, str_enabled_disabled(log->level),
- str_yes_no(GUC_LOG_LEVEL_IS_VERBOSE(log->level)),
- GUC_LOG_LEVEL_TO_VERBOSITY(log->level));
+ guc_dbg(guc, "guc_log_level=%d (%s, verbose:%s, verbosity:%d)\n",
+ log->level, str_enabled_disabled(log->level),
+ str_yes_no(GUC_LOG_LEVEL_IS_VERBOSE(log->level)),
+ GUC_LOG_LEVEL_TO_VERBOSITY(log->level));
return 0;
err:
- DRM_ERROR("Failed to allocate or map GuC log buffer. %d\n", ret);
+ guc_err(guc, "Failed to allocate or map log buffer %pe\n", ERR_PTR(ret));
return ret;
}
@@ -687,7 +687,7 @@ int intel_guc_log_set_level(struct intel_guc_log *log, u32 level)
GUC_LOG_LEVEL_IS_ENABLED(level),
GUC_LOG_LEVEL_TO_VERBOSITY(level));
if (ret) {
- DRM_DEBUG_DRIVER("guc_log_control action failed %d\n", ret);
+ guc_dbg(guc, "guc_log_control action failed %pe\n", ERR_PTR(ret));
goto out_unlock;
}
@@ -905,7 +905,7 @@ int intel_guc_log_dump(struct intel_guc_log *log, struct drm_printer *p,
map = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WC);
if (IS_ERR(map)) {
- DRM_DEBUG("Failed to pin object\n");
+ guc_dbg(guc, "Failed to pin log object: %pe\n", map);
drm_puts(p, "(log data unaccessible)\n");
free_page((unsigned long)page);
return PTR_ERR(map);
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_print.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_print.h
new file mode 100644
index 000000000000..e75989d4ba06
--- /dev/null
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_print.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+#ifndef __INTEL_GUC_PRINT__
+#define __INTEL_GUC_PRINT__
+
+#include "gt/intel_gt.h"
+#include "gt/intel_gt_print.h"
+
+#define guc_printk(_guc, _level, _fmt, ...) \
+ gt_##_level(guc_to_gt(_guc), "GUC: " _fmt, ##__VA_ARGS__)
+
+#define guc_err(_guc, _fmt, ...) \
+ guc_printk((_guc), err, _fmt, ##__VA_ARGS__)
+
+#define guc_warn(_guc, _fmt, ...) \
+ guc_printk((_guc), warn, _fmt, ##__VA_ARGS__)
+
+#define guc_notice(_guc, _fmt, ...) \
+ guc_printk((_guc), notice, _fmt, ##__VA_ARGS__)
+
+#define guc_info(_guc, _fmt, ...) \
+ guc_printk((_guc), info, _fmt, ##__VA_ARGS__)
+
+#define guc_dbg(_guc, _fmt, ...) \
+ guc_printk((_guc), dbg, _fmt, ##__VA_ARGS__)
+
+#define guc_err_ratelimited(_guc, _fmt, ...) \
+ guc_printk((_guc), err_ratelimited, _fmt, ##__VA_ARGS__)
+
+#define guc_probe_error(_guc, _fmt, ...) \
+ guc_printk((_guc), probe_error, _fmt, ##__VA_ARGS__)
+
+#define guc_WARN(_guc, _cond, _fmt, ...) \
+ gt_WARN(guc_to_gt(_guc), _cond, "GUC: " _fmt, ##__VA_ARGS__)
+
+#define guc_WARN_ONCE(_guc, _cond, _fmt, ...) \
+ gt_WARN_ONCE(guc_to_gt(_guc), _cond, "GUC: " _fmt, ##__VA_ARGS__)
+
+#define guc_WARN_ON(_guc, _cond) \
+ gt_WARN(guc_to_gt(_guc), _cond, "%s(%s)", "guc_WARN_ON", __stringify(_cond))
+
+#define guc_WARN_ON_ONCE(_guc, _cond) \
+ gt_WARN_ONCE(guc_to_gt(_guc), _cond, "%s(%s)", "guc_WARN_ON_ONCE", __stringify(_cond))
+
+#endif /* __INTEL_GUC_PRINT__ */
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
index c10977cb06b9..53f3ed3244d5 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
@@ -27,6 +27,7 @@
#include "intel_guc_ads.h"
#include "intel_guc_capture.h"
+#include "intel_guc_print.h"
#include "intel_guc_submission.h"
#include "i915_drv.h"
@@ -1443,8 +1444,7 @@ static void guc_init_engine_stats(struct intel_guc *guc)
int ret = guc_action_enable_usage_stats(guc);
if (ret)
- drm_err(&gt->i915->drm,
- "Failed to enable usage stats: %d!\n", ret);
+ guc_err(guc, "Failed to enable usage stats: %pe\n", ERR_PTR(ret));
}
}
@@ -1621,7 +1621,7 @@ static void guc_engine_reset_prepare(struct intel_engine_cs *engine)
intel_engine_stop_cs(engine);
/*
- * Wa_22011802037:gen11/gen12: In addition to stopping the cs, we need
+ * Wa_22011802037: In addition to stopping the cs, we need
* to wait for any pending mi force wakeups
*/
intel_engine_wait_for_pending_mi_fw(engine);
@@ -1891,7 +1891,7 @@ int intel_guc_submission_init(struct intel_guc *guc)
if (guc->submission_initialized)
return 0;
- if (GET_UC_VER(guc) < MAKE_UC_VER(70, 0, 0)) {
+ if (GUC_SUBMIT_VER(guc) < MAKE_GUC_VER(1, 0, 0)) {
ret = guc_lrc_desc_pool_create_v69(guc);
if (ret)
return ret;
@@ -2331,7 +2331,7 @@ static int register_context(struct intel_context *ce, bool loop)
GEM_BUG_ON(intel_context_is_child(ce));
trace_intel_context_register(ce);
- if (GET_UC_VER(guc) >= MAKE_UC_VER(70, 0, 0))
+ if (GUC_SUBMIT_VER(guc) >= MAKE_GUC_VER(1, 0, 0))
ret = register_context_v70(guc, ce, loop);
else
ret = register_context_v69(guc, ce, loop);
@@ -2343,7 +2343,7 @@ static int register_context(struct intel_context *ce, bool loop)
set_context_registered(ce);
spin_unlock_irqrestore(&ce->guc_state.lock, flags);
- if (GET_UC_VER(guc) >= MAKE_UC_VER(70, 0, 0))
+ if (GUC_SUBMIT_VER(guc) >= MAKE_GUC_VER(1, 0, 0))
guc_context_policy_init_v70(ce, loop);
}
@@ -2535,6 +2535,7 @@ static void prepare_context_registration_info_v69(struct intel_context *ce)
i915_gem_object_is_lmem(ce->ring->vma->obj));
desc = __get_lrc_desc_v69(guc, ctx_id);
+ GEM_BUG_ON(!desc);
desc->engine_class = engine_class_to_guc_class(engine->class);
desc->engine_submit_mask = engine->logical_mask;
desc->hw_context_desc = ce->lrc.lrca;
@@ -2957,7 +2958,7 @@ static void __guc_context_set_preemption_timeout(struct intel_guc *guc,
u16 guc_id,
u32 preemption_timeout)
{
- if (GET_UC_VER(guc) >= MAKE_UC_VER(70, 0, 0)) {
+ if (GUC_SUBMIT_VER(guc) >= MAKE_GUC_VER(1, 0, 0)) {
struct context_policy policy;
__guc_context_policy_start_klv(&policy, guc_id);
@@ -3284,7 +3285,7 @@ static int guc_context_alloc(struct intel_context *ce)
static void __guc_context_set_prio(struct intel_guc *guc,
struct intel_context *ce)
{
- if (GET_UC_VER(guc) >= MAKE_UC_VER(70, 0, 0)) {
+ if (GUC_SUBMIT_VER(guc) >= MAKE_GUC_VER(1, 0, 0)) {
struct context_policy policy;
__guc_context_policy_start_klv(&policy, ce->guc_id.id);
@@ -3585,8 +3586,7 @@ static int guc_request_alloc(struct i915_request *rq)
intel_context_sched_disable_unpin(ce);
else if (intel_context_is_closed(ce))
if (wait_for(context_close_done(ce), 1500))
- drm_warn(&guc_to_gt(guc)->i915->drm,
- "timed out waiting on context sched close before realloc\n");
+ guc_warn(guc, "timed out waiting on context sched close before realloc\n");
/*
* Call pin_guc_id here rather than in the pinning step as with
* dma_resv, contexts can be repeatedly pinned / unpinned trashing the
@@ -4203,8 +4203,10 @@ static void guc_default_vfuncs(struct intel_engine_cs *engine)
engine->flags |= I915_ENGINE_HAS_TIMESLICES;
/* Wa_14014475959:dg2 */
- if (IS_DG2(engine->i915) && engine->class == COMPUTE_CLASS)
- engine->flags |= I915_ENGINE_USES_WA_HOLD_CCS_SWITCHOUT;
+ if (engine->class == COMPUTE_CLASS)
+ if (IS_MTL_GRAPHICS_STEP(engine->i915, M, STEP_A0, STEP_B0) ||
+ IS_DG2(engine->i915))
+ engine->flags |= I915_ENGINE_USES_WA_HOLD_CCS_SWITCHOUT;
/*
* TODO: GuC supports timeslicing and semaphores as well, but they're
@@ -4347,11 +4349,14 @@ static int __guc_action_set_scheduling_policies(struct intel_guc *guc,
ret = intel_guc_send(guc, (u32 *)&policy->h2g,
__guc_scheduling_policy_action_size(policy));
- if (ret < 0)
+ if (ret < 0) {
+ guc_probe_error(guc, "Failed to configure global scheduling policies: %pe!\n",
+ ERR_PTR(ret));
return ret;
+ }
if (ret != policy->count) {
- drm_warn(&guc_to_gt(guc)->i915->drm, "GuC global scheduler policy processed %d of %d KLVs!",
+ guc_warn(guc, "global scheduler policy processed %d of %d KLVs!",
ret, policy->count);
if (ret > policy->count)
return -EPROTO;
@@ -4365,9 +4370,9 @@ static int guc_init_global_schedule_policy(struct intel_guc *guc)
struct scheduling_policy policy;
struct intel_gt *gt = guc_to_gt(guc);
intel_wakeref_t wakeref;
- int ret = 0;
+ int ret;
- if (GET_UC_VER(guc) < MAKE_UC_VER(70, 3, 0))
+ if (GUC_SUBMIT_VER(guc) < MAKE_GUC_VER(1, 1, 0))
return 0;
__guc_scheduling_policy_start_klv(&policy);
@@ -4383,10 +4388,6 @@ static int guc_init_global_schedule_policy(struct intel_guc *guc)
yield, ARRAY_SIZE(yield));
ret = __guc_action_set_scheduling_policies(guc, &policy);
- if (ret)
- i915_probe_error(gt->i915,
- "Failed to configure global scheduling policies: %pe!\n",
- ERR_PTR(ret));
}
return ret;
@@ -4485,21 +4486,18 @@ g2h_context_lookup(struct intel_guc *guc, u32 ctx_id)
struct intel_context *ce;
if (unlikely(ctx_id >= GUC_MAX_CONTEXT_ID)) {
- drm_err(&guc_to_gt(guc)->i915->drm,
- "Invalid ctx_id %u\n", ctx_id);
+ guc_err(guc, "Invalid ctx_id %u\n", ctx_id);
return NULL;
}
ce = __get_context(guc, ctx_id);
if (unlikely(!ce)) {
- drm_err(&guc_to_gt(guc)->i915->drm,
- "Context is NULL, ctx_id %u\n", ctx_id);
+ guc_err(guc, "Context is NULL, ctx_id %u\n", ctx_id);
return NULL;
}
if (unlikely(intel_context_is_child(ce))) {
- drm_err(&guc_to_gt(guc)->i915->drm,
- "Context is child, ctx_id %u\n", ctx_id);
+ guc_err(guc, "Context is child, ctx_id %u\n", ctx_id);
return NULL;
}
@@ -4514,7 +4512,7 @@ int intel_guc_deregister_done_process_msg(struct intel_guc *guc,
u32 ctx_id;
if (unlikely(len < 1)) {
- drm_err(&guc_to_gt(guc)->i915->drm, "Invalid length %u\n", len);
+ guc_err(guc, "Invalid length %u\n", len);
return -EPROTO;
}
ctx_id = msg[0];
@@ -4566,7 +4564,7 @@ int intel_guc_sched_done_process_msg(struct intel_guc *guc,
u32 ctx_id;
if (unlikely(len < 2)) {
- drm_err(&guc_to_gt(guc)->i915->drm, "Invalid length %u\n", len);
+ guc_err(guc, "Invalid length %u\n", len);
return -EPROTO;
}
ctx_id = msg[0];
@@ -4578,8 +4576,7 @@ int intel_guc_sched_done_process_msg(struct intel_guc *guc,
if (unlikely(context_destroyed(ce) ||
(!context_pending_enable(ce) &&
!context_pending_disable(ce)))) {
- drm_err(&guc_to_gt(guc)->i915->drm,
- "Bad context sched_state 0x%x, ctx_id %u\n",
+ guc_err(guc, "Bad context sched_state 0x%x, ctx_id %u\n",
ce->guc_state.sched_state, ctx_id);
return -EPROTO;
}
@@ -4663,12 +4660,15 @@ static void guc_handle_context_reset(struct intel_guc *guc,
{
trace_intel_context_reset(ce);
+ drm_dbg(&guc_to_gt(guc)->i915->drm, "Got GuC reset of 0x%04X, exiting = %d, banned = %d\n",
+ ce->guc_id.id, test_bit(CONTEXT_EXITING, &ce->flags),
+ test_bit(CONTEXT_BANNED, &ce->flags));
+
if (likely(intel_context_is_schedulable(ce))) {
capture_error_state(guc, ce);
guc_context_replay(ce);
} else {
- drm_info(&guc_to_gt(guc)->i915->drm,
- "Ignoring context reset notification of exiting context 0x%04X on %s",
+ guc_info(guc, "Ignoring context reset notification of exiting context 0x%04X on %s",
ce->guc_id.id, ce->engine->name);
}
}
@@ -4681,7 +4681,7 @@ int intel_guc_context_reset_process_msg(struct intel_guc *guc,
int ctx_id;
if (unlikely(len != 1)) {
- drm_err(&guc_to_gt(guc)->i915->drm, "Invalid length %u", len);
+ guc_err(guc, "Invalid length %u", len);
return -EPROTO;
}
@@ -4714,13 +4714,13 @@ int intel_guc_error_capture_process_msg(struct intel_guc *guc,
u32 status;
if (unlikely(len != 1)) {
- drm_dbg(&guc_to_gt(guc)->i915->drm, "Invalid length %u", len);
+ guc_dbg(guc, "Invalid length %u", len);
return -EPROTO;
}
status = msg[0] & INTEL_GUC_STATE_CAPTURE_EVENT_STATUS_MASK;
if (status == INTEL_GUC_STATE_CAPTURE_EVENT_STATUS_NOSPACE)
- drm_warn(&guc_to_gt(guc)->i915->drm, "G2H-Error capture no space");
+ guc_warn(guc, "No space for error capture");
intel_guc_capture_process(guc);
@@ -4752,24 +4752,36 @@ static void reset_fail_worker_func(struct work_struct *w)
guc->submission_state.reset_fail_mask = 0;
spin_unlock_irqrestore(&guc->submission_state.lock, flags);
- if (likely(reset_fail_mask))
+ if (likely(reset_fail_mask)) {
+ struct intel_engine_cs *engine;
+ enum intel_engine_id id;
+
+ /*
+ * GuC is toast at this point - it dead loops after sending the failed
+ * reset notification. So need to manually determine the guilty context.
+ * Note that it should be reliable to do this here because the GuC is
+ * toast and will not be scheduling behind the KMD's back.
+ */
+ for_each_engine_masked(engine, gt, reset_fail_mask, id)
+ intel_guc_find_hung_context(engine);
+
intel_gt_handle_error(gt, reset_fail_mask,
I915_ERROR_CAPTURE,
- "GuC failed to reset engine mask=0x%x\n",
+ "GuC failed to reset engine mask=0x%x",
reset_fail_mask);
+ }
}
int intel_guc_engine_failure_process_msg(struct intel_guc *guc,
const u32 *msg, u32 len)
{
struct intel_engine_cs *engine;
- struct intel_gt *gt = guc_to_gt(guc);
u8 guc_class, instance;
u32 reason;
unsigned long flags;
if (unlikely(len != 3)) {
- drm_err(&gt->i915->drm, "Invalid length %u", len);
+ guc_err(guc, "Invalid length %u", len);
return -EPROTO;
}
@@ -4779,8 +4791,7 @@ int intel_guc_engine_failure_process_msg(struct intel_guc *guc,
engine = intel_guc_lookup_engine(guc, guc_class, instance);
if (unlikely(!engine)) {
- drm_err(&gt->i915->drm,
- "Invalid engine %d:%d", guc_class, instance);
+ guc_err(guc, "Invalid engine %d:%d", guc_class, instance);
return -EPROTO;
}
@@ -4788,7 +4799,7 @@ int intel_guc_engine_failure_process_msg(struct intel_guc *guc,
* This is an unexpected failure of a hardware feature. So, log a real
* error message not just the informational that comes with the reset.
*/
- drm_err(&gt->i915->drm, "GuC engine reset request failed on %d:%d (%s) because 0x%08X",
+ guc_err(guc, "Engine reset failed on %d:%d (%s) because 0x%08X",
guc_class, instance, engine->name, reason);
spin_lock_irqsave(&guc->submission_state.lock, flags);
@@ -4917,6 +4928,9 @@ void intel_guc_submission_print_info(struct intel_guc *guc,
if (!sched_engine)
return;
+ drm_printf(p, "GuC Submission API Version: %d.%d.%d\n",
+ guc->submission_version.major, guc->submission_version.minor,
+ guc->submission_version.patch);
drm_printf(p, "GuC Number Outstanding Submission G2H: %u\n",
atomic_read(&guc->outstanding_submission_g2h));
drm_printf(p, "GuC tasklet count: %u\n",
@@ -5348,8 +5362,8 @@ guc_create_virtual(struct intel_engine_cs **siblings, unsigned int count,
GEM_BUG_ON(!is_power_of_2(sibling->mask));
if (sibling->mask & ve->base.mask) {
- DRM_DEBUG("duplicate %s entry in load balancer\n",
- sibling->name);
+ guc_dbg(guc, "duplicate %s entry in load balancer\n",
+ sibling->name);
err = -EINVAL;
goto err_put;
}
@@ -5358,8 +5372,8 @@ guc_create_virtual(struct intel_engine_cs **siblings, unsigned int count,
ve->base.logical_mask |= sibling->logical_mask;
if (n != 0 && ve->base.class != sibling->class) {
- DRM_DEBUG("invalid mixing of engine class, sibling %d, already %d\n",
- sibling->class, ve->base.class);
+ guc_dbg(guc, "invalid mixing of engine class, sibling %d, already %d\n",
+ sibling->class, ve->base.class);
err = -EINVAL;
goto err_put;
} else if (n == 0) {
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_huc_fw.c b/drivers/gpu/drm/i915/gt/uc/intel_huc_fw.c
index 4f246416db17..534b0aa43316 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_huc_fw.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_huc_fw.c
@@ -32,7 +32,7 @@ int intel_huc_fw_load_and_auth_via_gsc(struct intel_huc *huc)
GEM_WARN_ON(intel_uc_fw_is_loaded(&huc->fw));
- ret = intel_pxp_huc_load_and_auth(&huc_to_gt(huc)->pxp);
+ ret = intel_pxp_huc_load_and_auth(huc_to_gt(huc)->i915->pxp);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc.c b/drivers/gpu/drm/i915/gt/uc/intel_uc.c
index 2a508b137e90..de7f987cf611 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_uc.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_uc.c
@@ -6,9 +6,13 @@
#include <linux/string_helpers.h>
#include "gt/intel_gt.h"
+#include "gt/intel_gt_print.h"
#include "gt/intel_reset.h"
+#include "intel_gsc_fw.h"
+#include "intel_gsc_uc.h"
#include "intel_guc.h"
#include "intel_guc_ads.h"
+#include "intel_guc_print.h"
#include "intel_guc_submission.h"
#include "gt/intel_rps.h"
#include "intel_uc.h"
@@ -65,14 +69,14 @@ static int __intel_uc_reset_hw(struct intel_uc *uc)
ret = intel_reset_guc(gt);
if (ret) {
- DRM_ERROR("Failed to reset GuC, ret = %d\n", ret);
+ gt_err(gt, "Failed to reset GuC, ret = %d\n", ret);
return ret;
}
guc_status = intel_uncore_read(gt->uncore, GUC_STATUS);
- WARN(!(guc_status & GS_MIA_IN_RESET),
- "GuC status: 0x%x, MIA core expected to be in reset\n",
- guc_status);
+ gt_WARN(gt, !(guc_status & GS_MIA_IN_RESET),
+ "GuC status: 0x%x, MIA core expected to be in reset\n",
+ guc_status);
return ret;
}
@@ -126,6 +130,7 @@ void intel_uc_init_early(struct intel_uc *uc)
intel_guc_init_early(&uc->guc);
intel_huc_init_early(&uc->huc);
+ intel_gsc_uc_init_early(&uc->gsc);
__confirm_options(uc);
@@ -249,15 +254,13 @@ static int guc_enable_communication(struct intel_guc *guc)
intel_guc_ct_event_handler(&guc->ct);
spin_unlock_irq(gt->irq_lock);
- drm_dbg(&i915->drm, "GuC communication enabled\n");
+ guc_dbg(guc, "communication enabled\n");
return 0;
}
static void guc_disable_communication(struct intel_guc *guc)
{
- struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
-
/*
* Events generated during or after CT disable are logged by guc in
* via mmio. Make sure the register is clear before disabling CT since
@@ -277,11 +280,12 @@ static void guc_disable_communication(struct intel_guc *guc)
*/
guc_get_mmio_msg(guc);
- drm_dbg(&i915->drm, "GuC communication disabled\n");
+ guc_dbg(guc, "communication disabled\n");
}
static void __uc_fetch_firmwares(struct intel_uc *uc)
{
+ struct intel_gt *gt = uc_to_gt(uc);
int err;
GEM_BUG_ON(!intel_uc_wants_guc(uc));
@@ -290,21 +294,30 @@ static void __uc_fetch_firmwares(struct intel_uc *uc)
if (err) {
/* Make sure we transition out of transient "SELECTED" state */
if (intel_uc_wants_huc(uc)) {
- drm_dbg(&uc_to_gt(uc)->i915->drm,
- "Failed to fetch GuC: %d disabling HuC\n", err);
+ gt_dbg(gt, "Failed to fetch GuC fw (%pe) disabling HuC\n", ERR_PTR(err));
intel_uc_fw_change_status(&uc->huc.fw,
INTEL_UC_FIRMWARE_ERROR);
}
+ if (intel_uc_wants_gsc_uc(uc)) {
+ gt_dbg(gt, "Failed to fetch GuC fw (%pe) disabling GSC\n", ERR_PTR(err));
+ intel_uc_fw_change_status(&uc->gsc.fw,
+ INTEL_UC_FIRMWARE_ERROR);
+ }
+
return;
}
if (intel_uc_wants_huc(uc))
intel_uc_fw_fetch(&uc->huc.fw);
+
+ if (intel_uc_wants_gsc_uc(uc))
+ intel_uc_fw_fetch(&uc->gsc.fw);
}
static void __uc_cleanup_firmwares(struct intel_uc *uc)
{
+ intel_uc_fw_cleanup_fetch(&uc->gsc.fw);
intel_uc_fw_cleanup_fetch(&uc->huc.fw);
intel_uc_fw_cleanup_fetch(&uc->guc.fw);
}
@@ -330,11 +343,15 @@ static int __uc_init(struct intel_uc *uc)
if (intel_uc_uses_huc(uc))
intel_huc_init(huc);
+ if (intel_uc_uses_gsc_uc(uc))
+ intel_gsc_uc_init(&uc->gsc);
+
return 0;
}
static void __uc_fini(struct intel_uc *uc)
{
+ intel_gsc_uc_fini(&uc->gsc);
intel_huc_fini(&uc->huc);
intel_guc_fini(&uc->guc);
}
@@ -364,7 +381,7 @@ static int uc_init_wopcm(struct intel_uc *uc)
int err;
if (unlikely(!base || !size)) {
- i915_probe_error(gt->i915, "Unsuccessful WOPCM partitioning\n");
+ gt_probe_error(gt, "Unsuccessful WOPCM partitioning\n");
return -E2BIG;
}
@@ -395,13 +412,13 @@ static int uc_init_wopcm(struct intel_uc *uc)
return 0;
err_out:
- i915_probe_error(gt->i915, "Failed to init uC WOPCM registers!\n");
- i915_probe_error(gt->i915, "%s(%#x)=%#x\n", "DMA_GUC_WOPCM_OFFSET",
- i915_mmio_reg_offset(DMA_GUC_WOPCM_OFFSET),
- intel_uncore_read(uncore, DMA_GUC_WOPCM_OFFSET));
- i915_probe_error(gt->i915, "%s(%#x)=%#x\n", "GUC_WOPCM_SIZE",
- i915_mmio_reg_offset(GUC_WOPCM_SIZE),
- intel_uncore_read(uncore, GUC_WOPCM_SIZE));
+ gt_probe_error(gt, "Failed to init uC WOPCM registers!\n");
+ gt_probe_error(gt, "%s(%#x)=%#x\n", "DMA_GUC_WOPCM_OFFSET",
+ i915_mmio_reg_offset(DMA_GUC_WOPCM_OFFSET),
+ intel_uncore_read(uncore, DMA_GUC_WOPCM_OFFSET));
+ gt_probe_error(gt, "%s(%#x)=%#x\n", "GUC_WOPCM_SIZE",
+ i915_mmio_reg_offset(GUC_WOPCM_SIZE),
+ intel_uncore_read(uncore, GUC_WOPCM_SIZE));
return err;
}
@@ -431,20 +448,19 @@ static int __uc_check_hw(struct intel_uc *uc)
return 0;
}
-static void print_fw_ver(struct intel_uc *uc, struct intel_uc_fw *fw)
+static void print_fw_ver(struct intel_gt *gt, struct intel_uc_fw *fw)
{
- struct drm_i915_private *i915 = uc_to_gt(uc)->i915;
-
- drm_info(&i915->drm, "%s firmware %s version %u.%u.%u\n",
- intel_uc_fw_type_repr(fw->type), fw->file_selected.path,
- fw->file_selected.major_ver,
- fw->file_selected.minor_ver,
- fw->file_selected.patch_ver);
+ gt_info(gt, "%s firmware %s version %u.%u.%u\n",
+ intel_uc_fw_type_repr(fw->type), fw->file_selected.path,
+ fw->file_selected.ver.major,
+ fw->file_selected.ver.minor,
+ fw->file_selected.ver.patch);
}
static int __uc_init_hw(struct intel_uc *uc)
{
- struct drm_i915_private *i915 = uc_to_gt(uc)->i915;
+ struct intel_gt *gt = uc_to_gt(uc);
+ struct drm_i915_private *i915 = gt->i915;
struct intel_guc *guc = &uc->guc;
struct intel_huc *huc = &uc->huc;
int ret, attempts;
@@ -452,10 +468,10 @@ static int __uc_init_hw(struct intel_uc *uc)
GEM_BUG_ON(!intel_uc_supports_guc(uc));
GEM_BUG_ON(!intel_uc_wants_guc(uc));
- print_fw_ver(uc, &guc->fw);
+ print_fw_ver(gt, &guc->fw);
if (intel_uc_uses_huc(uc))
- print_fw_ver(uc, &huc->fw);
+ print_fw_ver(gt, &huc->fw);
if (!intel_uc_fw_is_loadable(&guc->fw)) {
ret = __uc_check_hw(uc) ||
@@ -496,8 +512,8 @@ static int __uc_init_hw(struct intel_uc *uc)
if (ret == 0)
break;
- DRM_DEBUG_DRIVER("GuC fw load failed: %d; will reset and "
- "retry %d more time(s)\n", ret, attempts);
+ gt_dbg(gt, "GuC fw load failed (%pe) will reset and retry %d more time(s)\n",
+ ERR_PTR(ret), attempts);
}
/* Did we succeded or run out of retries? */
@@ -531,10 +547,12 @@ static int __uc_init_hw(struct intel_uc *uc)
intel_rps_lower_unslice(&uc_to_gt(uc)->rps);
}
- drm_info(&i915->drm, "GuC submission %s\n",
- str_enabled_disabled(intel_uc_uses_guc_submission(uc)));
- drm_info(&i915->drm, "GuC SLPC %s\n",
- str_enabled_disabled(intel_uc_uses_guc_slpc(uc)));
+ intel_gsc_uc_load_start(&uc->gsc);
+
+ gt_info(gt, "GuC submission %s\n",
+ str_enabled_disabled(intel_uc_uses_guc_submission(uc)));
+ gt_info(gt, "GuC SLPC %s\n",
+ str_enabled_disabled(intel_uc_uses_guc_slpc(uc)));
return 0;
@@ -552,12 +570,12 @@ err_out:
__uc_sanitize(uc);
if (!ret) {
- drm_notice(&i915->drm, "GuC is uninitialized\n");
+ gt_notice(gt, "GuC is uninitialized\n");
/* We want to run without GuC submission */
return 0;
}
- i915_probe_error(i915, "GuC initialization failed %d\n", ret);
+ gt_probe_error(gt, "GuC initialization failed %pe\n", ERR_PTR(ret));
/* We want to keep KMS alive */
return -EIO;
@@ -659,6 +677,9 @@ void intel_uc_suspend(struct intel_uc *uc)
intel_wakeref_t wakeref;
int err;
+ /* flush the GSC worker */
+ intel_gsc_uc_suspend(&uc->gsc);
+
if (!intel_guc_is_ready(guc)) {
guc->interrupts.enabled = false;
return;
@@ -667,7 +688,7 @@ void intel_uc_suspend(struct intel_uc *uc)
with_intel_runtime_pm(&uc_to_gt(uc)->i915->runtime_pm, wakeref) {
err = intel_guc_suspend(guc);
if (err)
- DRM_DEBUG_DRIVER("Failed to suspend GuC, err=%d", err);
+ guc_dbg(guc, "Failed to suspend, %pe", ERR_PTR(err));
}
}
@@ -695,7 +716,7 @@ static int __uc_resume(struct intel_uc *uc, bool enable_communication)
err = intel_guc_resume(guc);
if (err) {
- DRM_DEBUG_DRIVER("Failed to resume GuC, err=%d", err);
+ guc_dbg(guc, "Failed to resume, %pe", ERR_PTR(err));
return err;
}
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc.h b/drivers/gpu/drm/i915/gt/uc/intel_uc.h
index a8f38c2c60e2..5d0f1bcc381e 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_uc.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_uc.h
@@ -6,6 +6,7 @@
#ifndef _INTEL_UC_H_
#define _INTEL_UC_H_
+#include "intel_gsc_uc.h"
#include "intel_guc.h"
#include "intel_guc_rc.h"
#include "intel_guc_submission.h"
@@ -27,6 +28,7 @@ struct intel_uc_ops {
struct intel_uc {
struct intel_uc_ops const *ops;
+ struct intel_gsc_uc gsc;
struct intel_guc guc;
struct intel_huc huc;
@@ -87,6 +89,7 @@ uc_state_checkers(huc, huc);
uc_state_checkers(guc, guc_submission);
uc_state_checkers(guc, guc_slpc);
uc_state_checkers(guc, guc_rc);
+uc_state_checkers(gsc, gsc_uc);
#undef uc_state_checkers
#undef __uc_state_checker
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c
index 2bcdd192f814..65672ff82605 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c
@@ -19,11 +19,18 @@
static inline struct intel_gt *
____uc_fw_to_gt(struct intel_uc_fw *uc_fw, enum intel_uc_fw_type type)
{
- if (type == INTEL_UC_FW_TYPE_GUC)
+ GEM_BUG_ON(type >= INTEL_UC_FW_NUM_TYPES);
+
+ switch (type) {
+ case INTEL_UC_FW_TYPE_GUC:
return container_of(uc_fw, struct intel_gt, uc.guc.fw);
+ case INTEL_UC_FW_TYPE_HUC:
+ return container_of(uc_fw, struct intel_gt, uc.huc.fw);
+ case INTEL_UC_FW_TYPE_GSC:
+ return container_of(uc_fw, struct intel_gt, uc.gsc.fw);
+ }
- GEM_BUG_ON(type != INTEL_UC_FW_TYPE_HUC);
- return container_of(uc_fw, struct intel_gt, uc.huc.fw);
+ return NULL;
}
static inline struct intel_gt *__uc_fw_to_gt(struct intel_uc_fw *uc_fw)
@@ -118,35 +125,35 @@ void intel_uc_fw_change_status(struct intel_uc_fw *uc_fw,
*/
#define __MAKE_UC_FW_PATH_BLANK(prefix_, name_) \
"i915/" \
- __stringify(prefix_) name_ ".bin"
+ __stringify(prefix_) "_" name_ ".bin"
#define __MAKE_UC_FW_PATH_MAJOR(prefix_, name_, major_) \
"i915/" \
- __stringify(prefix_) name_ \
+ __stringify(prefix_) "_" name_ "_" \
__stringify(major_) ".bin"
#define __MAKE_UC_FW_PATH_MMP(prefix_, name_, major_, minor_, patch_) \
"i915/" \
- __stringify(prefix_) name_ \
+ __stringify(prefix_) "_" name_ "_" \
__stringify(major_) "." \
__stringify(minor_) "." \
__stringify(patch_) ".bin"
/* Minor for internal driver use, not part of file name */
#define MAKE_GUC_FW_PATH_MAJOR(prefix_, major_, minor_) \
- __MAKE_UC_FW_PATH_MAJOR(prefix_, "_guc_", major_)
+ __MAKE_UC_FW_PATH_MAJOR(prefix_, "guc", major_)
#define MAKE_GUC_FW_PATH_MMP(prefix_, major_, minor_, patch_) \
- __MAKE_UC_FW_PATH_MMP(prefix_, "_guc_", major_, minor_, patch_)
+ __MAKE_UC_FW_PATH_MMP(prefix_, "guc", major_, minor_, patch_)
#define MAKE_HUC_FW_PATH_BLANK(prefix_) \
- __MAKE_UC_FW_PATH_BLANK(prefix_, "_huc")
+ __MAKE_UC_FW_PATH_BLANK(prefix_, "huc")
#define MAKE_HUC_FW_PATH_GSC(prefix_) \
- __MAKE_UC_FW_PATH_BLANK(prefix_, "_huc_gsc")
+ __MAKE_UC_FW_PATH_BLANK(prefix_, "huc_gsc")
#define MAKE_HUC_FW_PATH_MMP(prefix_, major_, minor_, patch_) \
- __MAKE_UC_FW_PATH_MMP(prefix_, "_huc_", major_, minor_, patch_)
+ __MAKE_UC_FW_PATH_MMP(prefix_, "huc", major_, minor_, patch_)
/*
* All blobs need to be declared via MODULE_FIRMWARE().
@@ -238,7 +245,7 @@ __uc_fw_auto_select(struct drm_i915_private *i915, struct intel_uc_fw *uc_fw)
[INTEL_UC_FW_TYPE_GUC] = { blobs_guc, ARRAY_SIZE(blobs_guc) },
[INTEL_UC_FW_TYPE_HUC] = { blobs_huc, ARRAY_SIZE(blobs_huc) },
};
- static bool verified;
+ static bool verified[INTEL_UC_FW_NUM_TYPES];
const struct uc_fw_platform_requirement *fw_blobs;
enum intel_platform p = INTEL_INFO(i915)->platform;
u32 fw_count;
@@ -247,6 +254,14 @@ __uc_fw_auto_select(struct drm_i915_private *i915, struct intel_uc_fw *uc_fw)
bool found;
/*
+ * GSC FW support is still not fully in place, so we're not defining
+ * the FW blob yet because we don't want the driver to attempt to load
+ * it until we're ready for it.
+ */
+ if (uc_fw->type == INTEL_UC_FW_TYPE_GSC)
+ return;
+
+ /*
* The only difference between the ADL GuC FWs is the HWConfig support.
* ADL-N does not support HWConfig, so we should use the same binary as
* ADL-S, otherwise the GuC might attempt to fetch a config table that
@@ -278,8 +293,8 @@ __uc_fw_auto_select(struct drm_i915_private *i915, struct intel_uc_fw *uc_fw)
uc_fw->file_selected.path = blob->path;
uc_fw->file_wanted.path = blob->path;
- uc_fw->file_wanted.major_ver = blob->major;
- uc_fw->file_wanted.minor_ver = blob->minor;
+ uc_fw->file_wanted.ver.major = blob->major;
+ uc_fw->file_wanted.ver.minor = blob->minor;
uc_fw->loaded_via_gsc = blob->loaded_via_gsc;
found = true;
break;
@@ -291,8 +306,8 @@ __uc_fw_auto_select(struct drm_i915_private *i915, struct intel_uc_fw *uc_fw)
}
/* make sure the list is ordered as expected */
- if (IS_ENABLED(CONFIG_DRM_I915_SELFTEST) && !verified) {
- verified = true;
+ if (IS_ENABLED(CONFIG_DRM_I915_SELFTEST) && !verified[uc_fw->type]) {
+ verified[uc_fw->type] = true;
for (i = 1; i < fw_count; i++) {
/* Next platform is good: */
@@ -343,7 +358,8 @@ __uc_fw_auto_select(struct drm_i915_private *i915, struct intel_uc_fw *uc_fw)
continue;
bad:
- drm_err(&i915->drm, "Invalid FW blob order: %s r%u %s%d.%d.%d comes before %s r%u %s%d.%d.%d\n",
+ drm_err(&i915->drm, "Invalid %s blob order: %s r%u %s%d.%d.%d comes before %s r%u %s%d.%d.%d\n",
+ intel_uc_fw_type_repr(uc_fw->type),
intel_platform_name(fw_blobs[i - 1].p), fw_blobs[i - 1].rev,
fw_blobs[i - 1].blob.legacy ? "L" : "v",
fw_blobs[i - 1].blob.major,
@@ -374,6 +390,11 @@ static const char *__override_huc_firmware_path(struct drm_i915_private *i915)
return "";
}
+static const char *__override_gsc_firmware_path(struct drm_i915_private *i915)
+{
+ return i915->params.gsc_firmware_path;
+}
+
static void __uc_fw_user_override(struct drm_i915_private *i915, struct intel_uc_fw *uc_fw)
{
const char *path = NULL;
@@ -385,6 +406,9 @@ static void __uc_fw_user_override(struct drm_i915_private *i915, struct intel_uc
case INTEL_UC_FW_TYPE_HUC:
path = __override_huc_firmware_path(i915);
break;
+ case INTEL_UC_FW_TYPE_GSC:
+ path = __override_gsc_firmware_path(i915);
+ break;
}
if (unlikely(path)) {
@@ -438,28 +462,28 @@ static void __force_fw_fetch_failures(struct intel_uc_fw *uc_fw, int e)
uc_fw->user_overridden = user;
} else if (i915_inject_probe_error(i915, e)) {
/* require next major version */
- uc_fw->file_wanted.major_ver += 1;
- uc_fw->file_wanted.minor_ver = 0;
+ uc_fw->file_wanted.ver.major += 1;
+ uc_fw->file_wanted.ver.minor = 0;
uc_fw->user_overridden = user;
} else if (i915_inject_probe_error(i915, e)) {
/* require next minor version */
- uc_fw->file_wanted.minor_ver += 1;
+ uc_fw->file_wanted.ver.minor += 1;
uc_fw->user_overridden = user;
- } else if (uc_fw->file_wanted.major_ver &&
+ } else if (uc_fw->file_wanted.ver.major &&
i915_inject_probe_error(i915, e)) {
/* require prev major version */
- uc_fw->file_wanted.major_ver -= 1;
- uc_fw->file_wanted.minor_ver = 0;
+ uc_fw->file_wanted.ver.major -= 1;
+ uc_fw->file_wanted.ver.minor = 0;
uc_fw->user_overridden = user;
- } else if (uc_fw->file_wanted.minor_ver &&
+ } else if (uc_fw->file_wanted.ver.minor &&
i915_inject_probe_error(i915, e)) {
/* require prev minor version - hey, this should work! */
- uc_fw->file_wanted.minor_ver -= 1;
+ uc_fw->file_wanted.ver.minor -= 1;
uc_fw->user_overridden = user;
} else if (user && i915_inject_probe_error(i915, e)) {
/* officially unsupported platform */
- uc_fw->file_wanted.major_ver = 0;
- uc_fw->file_wanted.minor_ver = 0;
+ uc_fw->file_wanted.ver.major = 0;
+ uc_fw->file_wanted.ver.minor = 0;
uc_fw->user_overridden = true;
}
}
@@ -471,13 +495,69 @@ static int check_gsc_manifest(const struct firmware *fw,
u32 version_hi = dw[HUC_GSC_VERSION_HI_DW];
u32 version_lo = dw[HUC_GSC_VERSION_LO_DW];
- uc_fw->file_selected.major_ver = FIELD_GET(HUC_GSC_MAJOR_VER_HI_MASK, version_hi);
- uc_fw->file_selected.minor_ver = FIELD_GET(HUC_GSC_MINOR_VER_HI_MASK, version_hi);
- uc_fw->file_selected.patch_ver = FIELD_GET(HUC_GSC_PATCH_VER_LO_MASK, version_lo);
+ uc_fw->file_selected.ver.major = FIELD_GET(HUC_GSC_MAJOR_VER_HI_MASK, version_hi);
+ uc_fw->file_selected.ver.minor = FIELD_GET(HUC_GSC_MINOR_VER_HI_MASK, version_hi);
+ uc_fw->file_selected.ver.patch = FIELD_GET(HUC_GSC_PATCH_VER_LO_MASK, version_lo);
return 0;
}
+static void uc_unpack_css_version(struct intel_uc_fw_ver *ver, u32 css_value)
+{
+ /* Get version numbers from the CSS header */
+ ver->major = FIELD_GET(CSS_SW_VERSION_UC_MAJOR, css_value);
+ ver->minor = FIELD_GET(CSS_SW_VERSION_UC_MINOR, css_value);
+ ver->patch = FIELD_GET(CSS_SW_VERSION_UC_PATCH, css_value);
+}
+
+static void guc_read_css_info(struct intel_uc_fw *uc_fw, struct uc_css_header *css)
+{
+ struct intel_guc *guc = container_of(uc_fw, struct intel_guc, fw);
+
+ /*
+ * The GuC firmware includes an extra version number to specify the
+ * submission API level. This allows submission code to work with
+ * multiple GuC versions without having to know the absolute firmware
+ * version number (there are likely to be multiple firmware releases
+ * which all support the same submission API level).
+ *
+ * Note that the spec for the CSS header defines this version number
+ * as 'vf_version' as it was originally intended for virtualisation.
+ * However, it is applicable to native submission as well.
+ *
+ * Unfortunately, due to an oversight, this version number was only
+ * exposed in the CSS header from v70.6.0.
+ */
+ if (uc_fw->file_selected.ver.major >= 70) {
+ if (uc_fw->file_selected.ver.minor >= 6) {
+ /* v70.6.0 adds CSS header support */
+ uc_unpack_css_version(&guc->submission_version, css->vf_version);
+ } else if (uc_fw->file_selected.ver.minor >= 3) {
+ /* v70.3.0 introduced v1.1.0 */
+ guc->submission_version.major = 1;
+ guc->submission_version.minor = 1;
+ guc->submission_version.patch = 0;
+ } else {
+ /* v70.0.0 introduced v1.0.0 */
+ guc->submission_version.major = 1;
+ guc->submission_version.minor = 0;
+ guc->submission_version.patch = 0;
+ }
+ } else if (uc_fw->file_selected.ver.major >= 69) {
+ /* v69.0.0 introduced v0.10.0 */
+ guc->submission_version.major = 0;
+ guc->submission_version.minor = 10;
+ guc->submission_version.patch = 0;
+ } else {
+ /* Prior versions were v0.1.0 */
+ guc->submission_version.major = 0;
+ guc->submission_version.minor = 1;
+ guc->submission_version.patch = 0;
+ }
+
+ uc_fw->private_data_size = css->private_data_size;
+}
+
static int check_ccs_header(struct intel_gt *gt,
const struct firmware *fw,
struct intel_uc_fw *uc_fw)
@@ -531,16 +611,66 @@ static int check_ccs_header(struct intel_gt *gt,
return -E2BIG;
}
- /* Get version numbers from the CSS header */
- uc_fw->file_selected.major_ver = FIELD_GET(CSS_SW_VERSION_UC_MAJOR,
- css->sw_version);
- uc_fw->file_selected.minor_ver = FIELD_GET(CSS_SW_VERSION_UC_MINOR,
- css->sw_version);
- uc_fw->file_selected.patch_ver = FIELD_GET(CSS_SW_VERSION_UC_PATCH,
- css->sw_version);
+ uc_unpack_css_version(&uc_fw->file_selected.ver, css->sw_version);
if (uc_fw->type == INTEL_UC_FW_TYPE_GUC)
- uc_fw->private_data_size = css->private_data_size;
+ guc_read_css_info(uc_fw, css);
+
+ return 0;
+}
+
+static bool is_ver_8bit(struct intel_uc_fw_ver *ver)
+{
+ return ver->major < 0xFF && ver->minor < 0xFF && ver->patch < 0xFF;
+}
+
+static bool guc_check_version_range(struct intel_uc_fw *uc_fw)
+{
+ struct intel_guc *guc = container_of(uc_fw, struct intel_guc, fw);
+
+ /*
+ * GuC version number components are defined as being 8-bits.
+ * The submission code relies on this to optimise version comparison
+ * tests. So enforce the restriction here.
+ */
+
+ if (!is_ver_8bit(&uc_fw->file_selected.ver)) {
+ drm_warn(&__uc_fw_to_gt(uc_fw)->i915->drm, "%s firmware: invalid file version: 0x%02X:%02X:%02X\n",
+ intel_uc_fw_type_repr(uc_fw->type),
+ uc_fw->file_selected.ver.major,
+ uc_fw->file_selected.ver.minor,
+ uc_fw->file_selected.ver.patch);
+ return false;
+ }
+
+ if (!is_ver_8bit(&guc->submission_version)) {
+ drm_warn(&__uc_fw_to_gt(uc_fw)->i915->drm, "%s firmware: invalid submit version: 0x%02X:%02X:%02X\n",
+ intel_uc_fw_type_repr(uc_fw->type),
+ guc->submission_version.major,
+ guc->submission_version.minor,
+ guc->submission_version.patch);
+ return false;
+ }
+
+ return true;
+}
+
+static int check_fw_header(struct intel_gt *gt,
+ const struct firmware *fw,
+ struct intel_uc_fw *uc_fw)
+{
+ int err = 0;
+
+ /* GSC FW version is queried after the FW is loaded */
+ if (uc_fw->type == INTEL_UC_FW_TYPE_GSC)
+ return 0;
+
+ if (uc_fw->loaded_via_gsc)
+ err = check_gsc_manifest(fw, uc_fw);
+ else
+ err = check_ccs_header(gt, fw, uc_fw);
+ if (err)
+ return err;
return 0;
}
@@ -628,31 +758,31 @@ int intel_uc_fw_fetch(struct intel_uc_fw *uc_fw)
if (err)
goto fail;
- if (uc_fw->loaded_via_gsc)
- err = check_gsc_manifest(fw, uc_fw);
- else
- err = check_ccs_header(gt, fw, uc_fw);
+ err = check_fw_header(gt, fw, uc_fw);
if (err)
goto fail;
- if (uc_fw->file_wanted.major_ver) {
+ if (uc_fw->type == INTEL_UC_FW_TYPE_GUC && !guc_check_version_range(uc_fw))
+ goto fail;
+
+ if (uc_fw->file_wanted.ver.major && uc_fw->file_selected.ver.major) {
/* Check the file's major version was as it claimed */
- if (uc_fw->file_selected.major_ver != uc_fw->file_wanted.major_ver) {
+ if (uc_fw->file_selected.ver.major != uc_fw->file_wanted.ver.major) {
drm_notice(&i915->drm, "%s firmware %s: unexpected version: %u.%u != %u.%u\n",
intel_uc_fw_type_repr(uc_fw->type), uc_fw->file_selected.path,
- uc_fw->file_selected.major_ver, uc_fw->file_selected.minor_ver,
- uc_fw->file_wanted.major_ver, uc_fw->file_wanted.minor_ver);
+ uc_fw->file_selected.ver.major, uc_fw->file_selected.ver.minor,
+ uc_fw->file_wanted.ver.major, uc_fw->file_wanted.ver.minor);
if (!intel_uc_fw_is_overridden(uc_fw)) {
err = -ENOEXEC;
goto fail;
}
} else {
- if (uc_fw->file_selected.minor_ver < uc_fw->file_wanted.minor_ver)
+ if (uc_fw->file_selected.ver.minor < uc_fw->file_wanted.ver.minor)
old_ver = true;
}
}
- if (old_ver) {
+ if (old_ver && uc_fw->file_selected.ver.major) {
/* Preserve the version that was really wanted */
memcpy(&uc_fw->file_wanted, &file_ideal, sizeof(uc_fw->file_wanted));
@@ -660,9 +790,9 @@ int intel_uc_fw_fetch(struct intel_uc_fw *uc_fw)
"%s firmware %s (%d.%d) is recommended, but only %s (%d.%d) was found\n",
intel_uc_fw_type_repr(uc_fw->type),
uc_fw->file_wanted.path,
- uc_fw->file_wanted.major_ver, uc_fw->file_wanted.minor_ver,
+ uc_fw->file_wanted.ver.major, uc_fw->file_wanted.ver.minor,
uc_fw->file_selected.path,
- uc_fw->file_selected.major_ver, uc_fw->file_selected.minor_ver);
+ uc_fw->file_selected.ver.major, uc_fw->file_selected.ver.minor);
drm_info(&i915->drm,
"Consider updating your linux-firmware pkg or downloading from %s\n",
INTEL_UC_FIRMWARE_URL);
@@ -814,6 +944,20 @@ static int uc_fw_xfer(struct intel_uc_fw *uc_fw, u32 dst_offset, u32 dma_flags)
return ret;
}
+int intel_uc_fw_mark_load_failed(struct intel_uc_fw *uc_fw, int err)
+{
+ struct intel_gt *gt = __uc_fw_to_gt(uc_fw);
+
+ GEM_BUG_ON(!intel_uc_fw_is_loadable(uc_fw));
+
+ i915_probe_error(gt->i915, "Failed to load %s firmware %s (%d)\n",
+ intel_uc_fw_type_repr(uc_fw->type), uc_fw->file_selected.path,
+ err);
+ intel_uc_fw_change_status(uc_fw, INTEL_UC_FIRMWARE_LOAD_FAIL);
+
+ return err;
+}
+
/**
* intel_uc_fw_upload - load uC firmware using custom loader
* @uc_fw: uC firmware
@@ -850,11 +994,7 @@ int intel_uc_fw_upload(struct intel_uc_fw *uc_fw, u32 dst_offset, u32 dma_flags)
return 0;
fail:
- i915_probe_error(gt->i915, "Failed to load %s firmware %s (%d)\n",
- intel_uc_fw_type_repr(uc_fw->type), uc_fw->file_selected.path,
- err);
- intel_uc_fw_change_status(uc_fw, INTEL_UC_FIRMWARE_LOAD_FAIL);
- return err;
+ return intel_uc_fw_mark_load_failed(uc_fw, err);
}
static inline bool uc_fw_need_rsa_in_memory(struct intel_uc_fw *uc_fw)
@@ -1068,7 +1208,7 @@ size_t intel_uc_fw_copy_rsa(struct intel_uc_fw *uc_fw, void *dst, u32 max_len)
*/
void intel_uc_fw_dump(const struct intel_uc_fw *uc_fw, struct drm_printer *p)
{
- u32 ver_sel, ver_want;
+ bool got_wanted;
drm_printf(p, "%s firmware: %s\n",
intel_uc_fw_type_repr(uc_fw->type), uc_fw->file_selected.path);
@@ -1077,25 +1217,32 @@ void intel_uc_fw_dump(const struct intel_uc_fw *uc_fw, struct drm_printer *p)
intel_uc_fw_type_repr(uc_fw->type), uc_fw->file_wanted.path);
drm_printf(p, "\tstatus: %s\n",
intel_uc_fw_status_repr(uc_fw->status));
- ver_sel = MAKE_UC_VER(uc_fw->file_selected.major_ver,
- uc_fw->file_selected.minor_ver,
- uc_fw->file_selected.patch_ver);
- ver_want = MAKE_UC_VER(uc_fw->file_wanted.major_ver,
- uc_fw->file_wanted.minor_ver,
- uc_fw->file_wanted.patch_ver);
- if (ver_sel < ver_want)
+
+ if (uc_fw->file_selected.ver.major < uc_fw->file_wanted.ver.major)
+ got_wanted = false;
+ else if ((uc_fw->file_selected.ver.major == uc_fw->file_wanted.ver.major) &&
+ (uc_fw->file_selected.ver.minor < uc_fw->file_wanted.ver.minor))
+ got_wanted = false;
+ else if ((uc_fw->file_selected.ver.major == uc_fw->file_wanted.ver.major) &&
+ (uc_fw->file_selected.ver.minor == uc_fw->file_wanted.ver.minor) &&
+ (uc_fw->file_selected.ver.patch < uc_fw->file_wanted.ver.patch))
+ got_wanted = false;
+ else
+ got_wanted = true;
+
+ if (!got_wanted)
drm_printf(p, "\tversion: wanted %u.%u.%u, found %u.%u.%u\n",
- uc_fw->file_wanted.major_ver,
- uc_fw->file_wanted.minor_ver,
- uc_fw->file_wanted.patch_ver,
- uc_fw->file_selected.major_ver,
- uc_fw->file_selected.minor_ver,
- uc_fw->file_selected.patch_ver);
+ uc_fw->file_wanted.ver.major,
+ uc_fw->file_wanted.ver.minor,
+ uc_fw->file_wanted.ver.patch,
+ uc_fw->file_selected.ver.major,
+ uc_fw->file_selected.ver.minor,
+ uc_fw->file_selected.ver.patch);
else
drm_printf(p, "\tversion: found %u.%u.%u\n",
- uc_fw->file_selected.major_ver,
- uc_fw->file_selected.minor_ver,
- uc_fw->file_selected.patch_ver);
+ uc_fw->file_selected.ver.major,
+ uc_fw->file_selected.ver.minor,
+ uc_fw->file_selected.ver.patch);
drm_printf(p, "\tuCode: %u bytes\n", uc_fw->ucode_size);
drm_printf(p, "\tRSA: %u bytes\n", uc_fw->rsa_size);
}
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h
index bc898ba5355d..6ba00e6b3975 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h
@@ -61,9 +61,16 @@ enum intel_uc_fw_status {
enum intel_uc_fw_type {
INTEL_UC_FW_TYPE_GUC = 0,
- INTEL_UC_FW_TYPE_HUC
+ INTEL_UC_FW_TYPE_HUC,
+ INTEL_UC_FW_TYPE_GSC,
+};
+#define INTEL_UC_FW_NUM_TYPES 3
+
+struct intel_uc_fw_ver {
+ u32 major;
+ u32 minor;
+ u32 patch;
};
-#define INTEL_UC_FW_NUM_TYPES 2
/*
* The firmware build process will generate a version header file with major and
@@ -72,9 +79,7 @@ enum intel_uc_fw_type {
*/
struct intel_uc_fw_file {
const char *path;
- u16 major_ver;
- u16 minor_ver;
- u16 patch_ver;
+ struct intel_uc_fw_ver ver;
};
/*
@@ -110,11 +115,6 @@ struct intel_uc_fw {
bool loaded_via_gsc;
};
-#define MAKE_UC_VER(maj, min, pat) ((pat) | ((min) << 8) | ((maj) << 16))
-#define GET_UC_VER(uc) (MAKE_UC_VER((uc)->fw.file_selected.major_ver, \
- (uc)->fw.file_selected.minor_ver, \
- (uc)->fw.file_selected.patch_ver))
-
/*
* When we load the uC binaries, we pin them in a reserved section at the top of
* the GGTT, which is ~18 MBs. On multi-GT systems where the GTs share the GGTT,
@@ -205,6 +205,8 @@ static inline const char *intel_uc_fw_type_repr(enum intel_uc_fw_type type)
return "GuC";
case INTEL_UC_FW_TYPE_HUC:
return "HuC";
+ case INTEL_UC_FW_TYPE_GSC:
+ return "GSC";
}
return "uC";
}
@@ -287,6 +289,7 @@ int intel_uc_fw_upload(struct intel_uc_fw *uc_fw, u32 offset, u32 dma_flags);
int intel_uc_fw_init(struct intel_uc_fw *uc_fw);
void intel_uc_fw_fini(struct intel_uc_fw *uc_fw);
size_t intel_uc_fw_copy_rsa(struct intel_uc_fw *uc_fw, void *dst, u32 max_len);
+int intel_uc_fw_mark_load_failed(struct intel_uc_fw *uc_fw, int err);
void intel_uc_fw_dump(const struct intel_uc_fw *uc_fw, struct drm_printer *p);
#endif
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw_abi.h b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw_abi.h
index 7a411178bdbf..646fa8aa6cf1 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw_abi.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw_abi.h
@@ -74,7 +74,8 @@ struct uc_css_header {
#define CSS_SW_VERSION_UC_MAJOR (0xFF << 16)
#define CSS_SW_VERSION_UC_MINOR (0xFF << 8)
#define CSS_SW_VERSION_UC_PATCH (0xFF << 0)
- u32 reserved0[13];
+ u32 vf_version;
+ u32 reserved0[12];
union {
u32 private_data_size; /* only applies to GuC */
u32 reserved1;
diff --git a/drivers/gpu/drm/i915/gvt/cmd_parser.c b/drivers/gpu/drm/i915/gvt/cmd_parser.c
index 0ebf5fbf0e39..3c4ae1da0d41 100644
--- a/drivers/gpu/drm/i915/gvt/cmd_parser.c
+++ b/drivers/gpu/drm/i915/gvt/cmd_parser.c
@@ -49,6 +49,7 @@
#include "i915_pvinfo.h"
#include "trace.h"
+#include "display/intel_display.h"
#include "gem/i915_gem_context.h"
#include "gem/i915_gem_pm.h"
#include "gt/intel_context.h"
diff --git a/drivers/gpu/drm/i915/gvt/debugfs.c b/drivers/gpu/drm/i915/gvt/debugfs.c
index 0616b73175f3..baccbf1761b7 100644
--- a/drivers/gpu/drm/i915/gvt/debugfs.c
+++ b/drivers/gpu/drm/i915/gvt/debugfs.c
@@ -147,9 +147,9 @@ vgpu_scan_nonprivbb_set(void *data, u64 val)
return 0;
}
-DEFINE_SIMPLE_ATTRIBUTE(vgpu_scan_nonprivbb_fops,
- vgpu_scan_nonprivbb_get, vgpu_scan_nonprivbb_set,
- "0x%llx\n");
+DEFINE_DEBUGFS_ATTRIBUTE(vgpu_scan_nonprivbb_fops,
+ vgpu_scan_nonprivbb_get, vgpu_scan_nonprivbb_set,
+ "0x%llx\n");
static int vgpu_status_get(void *data, u64 *val)
{
@@ -165,7 +165,7 @@ static int vgpu_status_get(void *data, u64 *val)
return 0;
}
-DEFINE_SIMPLE_ATTRIBUTE(vgpu_status_fops, vgpu_status_get, NULL, "0x%llx\n");
+DEFINE_DEBUGFS_ATTRIBUTE(vgpu_status_fops, vgpu_status_get, NULL, "0x%llx\n");
/**
* intel_gvt_debugfs_add_vgpu - register debugfs entries for a vGPU
@@ -180,10 +180,10 @@ void intel_gvt_debugfs_add_vgpu(struct intel_vgpu *vgpu)
debugfs_create_file("mmio_diff", 0444, vgpu->debugfs, vgpu,
&vgpu_mmio_diff_fops);
- debugfs_create_file("scan_nonprivbb", 0644, vgpu->debugfs, vgpu,
- &vgpu_scan_nonprivbb_fops);
- debugfs_create_file("status", 0644, vgpu->debugfs, vgpu,
- &vgpu_status_fops);
+ debugfs_create_file_unsafe("scan_nonprivbb", 0644, vgpu->debugfs, vgpu,
+ &vgpu_scan_nonprivbb_fops);
+ debugfs_create_file_unsafe("status", 0644, vgpu->debugfs, vgpu,
+ &vgpu_status_fops);
}
/**
diff --git a/drivers/gpu/drm/i915/gvt/display.c b/drivers/gpu/drm/i915/gvt/display.c
index c033249e73f4..4d898b14de93 100644
--- a/drivers/gpu/drm/i915/gvt/display.c
+++ b/drivers/gpu/drm/i915/gvt/display.c
@@ -36,6 +36,7 @@
#include "i915_reg.h"
#include "gvt.h"
+#include "display/intel_display.h"
#include "display/intel_dpio_phy.h"
static int get_edp_pipe(struct intel_vgpu *vgpu)
diff --git a/drivers/gpu/drm/i915/gvt/dmabuf.c b/drivers/gpu/drm/i915/gvt/dmabuf.c
index ffe41e9be04f..6834f9fe40cf 100644
--- a/drivers/gpu/drm/i915/gvt/dmabuf.c
+++ b/drivers/gpu/drm/i915/gvt/dmabuf.c
@@ -42,8 +42,7 @@
#define GEN8_DECODE_PTE(pte) (pte & GENMASK_ULL(63, 12))
-static int vgpu_gem_get_pages(
- struct drm_i915_gem_object *obj)
+static int vgpu_gem_get_pages(struct drm_i915_gem_object *obj)
{
struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
struct intel_vgpu *vgpu;
@@ -52,8 +51,12 @@ static int vgpu_gem_get_pages(
int i, j, ret;
gen8_pte_t __iomem *gtt_entries;
struct intel_vgpu_fb_info *fb_info;
- u32 page_num;
+ unsigned int page_num; /* limited by sg_alloc_table */
+ if (overflows_type(obj->base.size >> PAGE_SHIFT, page_num))
+ return -E2BIG;
+
+ page_num = obj->base.size >> PAGE_SHIFT;
fb_info = (struct intel_vgpu_fb_info *)obj->gvt_info;
if (drm_WARN_ON(&dev_priv->drm, !fb_info))
return -ENODEV;
@@ -66,7 +69,6 @@ static int vgpu_gem_get_pages(
if (unlikely(!st))
return -ENOMEM;
- page_num = obj->base.size >> PAGE_SHIFT;
ret = sg_alloc_table(st, page_num, GFP_KERNEL);
if (ret) {
kfree(st);
diff --git a/drivers/gpu/drm/i915/gvt/fb_decoder.h b/drivers/gpu/drm/i915/gvt/fb_decoder.h
index 0daa3931aef7..4eff44194439 100644
--- a/drivers/gpu/drm/i915/gvt/fb_decoder.h
+++ b/drivers/gpu/drm/i915/gvt/fb_decoder.h
@@ -38,7 +38,7 @@
#include <linux/types.h>
-#include "display/intel_display.h"
+#include "display/intel_display_limits.h"
struct intel_vgpu;
diff --git a/drivers/gpu/drm/i915/gvt/firmware.c b/drivers/gpu/drm/i915/gvt/firmware.c
index dce93738e98a..4dd52ac2043e 100644
--- a/drivers/gpu/drm/i915/gvt/firmware.c
+++ b/drivers/gpu/drm/i915/gvt/firmware.c
@@ -171,7 +171,7 @@ static int verify_firmware(struct intel_gvt *gvt,
mem = (fw->data + h->cfg_space_offset);
id = *(u16 *)(mem + PCI_VENDOR_ID);
- VERIFY("vender id", id, pdev->vendor);
+ VERIFY("vendor id", id, pdev->vendor);
id = *(u16 *)(mem + PCI_DEVICE_ID);
VERIFY("device id", id, pdev->device);
diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c
index 8ae7039b3683..de675d799c7d 100644
--- a/drivers/gpu/drm/i915/gvt/kvmgt.c
+++ b/drivers/gpu/drm/i915/gvt/kvmgt.c
@@ -699,7 +699,7 @@ static void intel_vgpu_close_device(struct vfio_device *vfio_dev)
clear_bit(INTEL_VGPU_STATUS_ATTACHED, vgpu->status);
- debugfs_remove(debugfs_lookup(KVMGT_DEBUGFS_FILENAME, vgpu->debugfs));
+ debugfs_lookup_and_remove(KVMGT_DEBUGFS_FILENAME, vgpu->debugfs);
kvm_page_track_unregister_notifier(vgpu->vfio_device.kvm,
&vgpu->track_node);
diff --git a/drivers/gpu/drm/i915/gvt/vgpu.c b/drivers/gpu/drm/i915/gvt/vgpu.c
index a5497440484f..08ad1bd651f1 100644
--- a/drivers/gpu/drm/i915/gvt/vgpu.c
+++ b/drivers/gpu/drm/i915/gvt/vgpu.c
@@ -323,7 +323,7 @@ int intel_gvt_create_vgpu(struct intel_vgpu *vgpu,
ret = idr_alloc(&gvt->vgpu_idr, vgpu, IDLE_VGPU_IDR + 1, GVT_MAX_VGPU,
GFP_KERNEL);
if (ret < 0)
- goto out_unlock;;
+ goto out_unlock;
vgpu->id = ret;
vgpu->sched_ctl.weight = conf->weight;
diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c
index f93e6122f247..ddf49c2dbb91 100644
--- a/drivers/gpu/drm/i915/i915_cmd_parser.c
+++ b/drivers/gpu/drm/i915/i915_cmd_parser.c
@@ -1471,8 +1471,8 @@ int intel_engine_cmd_parser(struct intel_engine_cs *engine,
/* Defer failure until attempted use */
jump_whitelist = alloc_whitelist(batch_length);
- shadow_addr = gen8_canonical_addr(shadow->node.start);
- batch_addr = gen8_canonical_addr(batch->node.start + batch_offset);
+ shadow_addr = gen8_canonical_addr(i915_vma_offset(shadow));
+ batch_addr = gen8_canonical_addr(i915_vma_offset(batch) + batch_offset);
/*
* We use the batch length as size because the shadow object is as
diff --git a/drivers/gpu/drm/i915/i915_config.c b/drivers/gpu/drm/i915/i915_config.c
index afb828dab53b..24e5bb8a670e 100644
--- a/drivers/gpu/drm/i915/i915_config.c
+++ b/drivers/gpu/drm/i915/i915_config.c
@@ -3,7 +3,10 @@
* Copyright © 2020 Intel Corporation
*/
-#include "i915_drv.h"
+#include <linux/kernel.h>
+
+#include "i915_config.h"
+#include "i915_utils.h"
unsigned long
i915_fence_context_timeout(const struct drm_i915_private *i915, u64 context)
diff --git a/drivers/gpu/drm/i915/i915_config.h b/drivers/gpu/drm/i915/i915_config.h
new file mode 100644
index 000000000000..10e18b036489
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_config.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+#ifndef __I915_CONFIG_H__
+#define __I915_CONFIG_H__
+
+#include <linux/types.h>
+#include <linux/limits.h>
+
+struct drm_i915_private;
+
+unsigned long i915_fence_context_timeout(const struct drm_i915_private *i915,
+ u64 context);
+
+static inline unsigned long
+i915_fence_timeout(const struct drm_i915_private *i915)
+{
+ return i915_fence_context_timeout(i915, U64_MAX);
+}
+
+#endif /* __I915_CONFIG_H__ */
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 6c7ac73b69a5..45773ce1deac 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -183,7 +183,7 @@ i915_debugfs_describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
seq_printf(m, " (%s offset: %08llx, size: %08llx, pages: %s",
stringify_vma_type(vma),
- vma->node.start, vma->node.size,
+ i915_vma_offset(vma), i915_vma_size(vma),
stringify_page_sizes(vma->resource->page_sizes_gtt,
NULL, 0));
if (i915_vma_is_ggtt(vma) || i915_vma_is_dpt(vma)) {
@@ -648,13 +648,14 @@ i915_drop_caches_get(void *data, u64 *val)
return 0;
}
+
static int
gt_drop_caches(struct intel_gt *gt, u64 val)
{
int ret;
if (val & DROP_RESET_ACTIVE &&
- wait_for(intel_engines_are_idle(gt), I915_IDLE_ENGINES_TIMEOUT))
+ wait_for(intel_engines_are_idle(gt), 200))
intel_gt_set_wedged(gt);
if (val & DROP_RETIRE)
@@ -762,7 +763,6 @@ static const struct drm_info_list i915_debugfs_list[] = {
{"i915_sseu_status", i915_sseu_status, 0},
{"i915_rps_boost_info", i915_rps_boost_info, 0},
};
-#define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)
static const struct i915_debugfs_files {
const char *name;
@@ -795,6 +795,6 @@ void i915_debugfs_register(struct drm_i915_private *dev_priv)
}
drm_debugfs_create_files(i915_debugfs_list,
- I915_DEBUGFS_ENTRIES,
+ ARRAY_SIZE(i915_debugfs_list),
minor->debugfs_root, minor);
}
diff --git a/drivers/gpu/drm/i915/i915_debugfs_params.c b/drivers/gpu/drm/i915/i915_debugfs_params.c
index 783c8676eee2..614bde321589 100644
--- a/drivers/gpu/drm/i915/i915_debugfs_params.c
+++ b/drivers/gpu/drm/i915/i915_debugfs_params.c
@@ -230,27 +230,16 @@ i915_debugfs_create_charp(const char *name, umode_t mode,
&i915_param_charp_fops);
}
-static __always_inline void
-_i915_param_create_file(struct dentry *parent, const char *name,
- const char *type, int mode, void *value)
-{
- if (!mode)
- return;
-
- if (!__builtin_strcmp(type, "bool"))
- debugfs_create_bool(name, mode, parent, value);
- else if (!__builtin_strcmp(type, "int"))
- i915_debugfs_create_int(name, mode, parent, value);
- else if (!__builtin_strcmp(type, "unsigned int"))
- i915_debugfs_create_uint(name, mode, parent, value);
- else if (!__builtin_strcmp(type, "unsigned long"))
- debugfs_create_ulong(name, mode, parent, value);
- else if (!__builtin_strcmp(type, "char *"))
- i915_debugfs_create_charp(name, mode, parent, value);
- else
- WARN(1, "no debugfs fops defined for param type %s (i915.%s)\n",
- type, name);
-}
+#define _i915_param_create_file(parent, name, mode, valp) \
+ do { \
+ if (mode) \
+ _Generic(valp, \
+ bool *: debugfs_create_bool, \
+ int *: i915_debugfs_create_int, \
+ unsigned int *: i915_debugfs_create_uint, \
+ unsigned long *: debugfs_create_ulong, \
+ char **: i915_debugfs_create_charp)(name, mode, parent, valp); \
+ } while(0)
/* add a subdirectory with files for each i915 param */
struct dentry *i915_debugfs_params(struct drm_i915_private *i915)
@@ -269,7 +258,7 @@ struct dentry *i915_debugfs_params(struct drm_i915_private *i915)
* just let the generic create file fail silently with -EEXIST.
*/
-#define REGISTER(T, x, unused, mode, ...) _i915_param_create_file(dir, #x, #T, mode, &params->x);
+#define REGISTER(T, x, unused, mode, ...) _i915_param_create_file(dir, #x, mode, &params->x);
I915_PARAMS_FOR_EACH(REGISTER);
#undef REGISTER
diff --git a/drivers/gpu/drm/i915/i915_deps.c b/drivers/gpu/drm/i915/i915_deps.c
index 297b8e4e42ee..91c61864285a 100644
--- a/drivers/gpu/drm/i915/i915_deps.c
+++ b/drivers/gpu/drm/i915/i915_deps.c
@@ -6,7 +6,7 @@
#include <linux/dma-fence.h>
#include <linux/slab.h>
-#include <drm/ttm/ttm_bo_api.h>
+#include <drm/ttm/ttm_bo.h>
#include "i915_deps.h"
diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c
index 61c38fc734cf..cf1c0970ecb4 100644
--- a/drivers/gpu/drm/i915/i915_driver.c
+++ b/drivers/gpu/drm/i915/i915_driver.c
@@ -34,7 +34,6 @@
#include <linux/pci.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
-#include <linux/pnp.h>
#include <linux/slab.h>
#include <linux/string_helpers.h>
#include <linux/vga_switcheroo.h>
@@ -73,8 +72,13 @@
#include "gt/intel_gt_pm.h"
#include "gt/intel_rc6.h"
+#include "pxp/intel_pxp.h"
+#include "pxp/intel_pxp_debugfs.h"
#include "pxp/intel_pxp_pm.h"
+#include "soc/intel_dram.h"
+#include "soc/intel_gmch.h"
+
#include "i915_file_private.h"
#include "i915_debugfs.h"
#include "i915_driver.h"
@@ -93,7 +97,6 @@
#include "i915_sysfs.h"
#include "i915_utils.h"
#include "i915_vgpu.h"
-#include "intel_dram.h"
#include "intel_gvt.h"
#include "intel_memory_region.h"
#include "intel_pci_config.h"
@@ -102,146 +105,8 @@
#include "intel_region_ttm.h"
#include "vlv_suspend.h"
-/* Intel Rapid Start Technology ACPI device name */
-static const char irst_name[] = "INT3392";
-
static const struct drm_driver i915_drm_driver;
-static void i915_release_bridge_dev(struct drm_device *dev,
- void *bridge)
-{
- pci_dev_put(bridge);
-}
-
-static int i915_get_bridge_dev(struct drm_i915_private *dev_priv)
-{
- int domain = pci_domain_nr(to_pci_dev(dev_priv->drm.dev)->bus);
-
- dev_priv->bridge_dev =
- pci_get_domain_bus_and_slot(domain, 0, PCI_DEVFN(0, 0));
- if (!dev_priv->bridge_dev) {
- drm_err(&dev_priv->drm, "bridge device not found\n");
- return -EIO;
- }
-
- return drmm_add_action_or_reset(&dev_priv->drm, i915_release_bridge_dev,
- dev_priv->bridge_dev);
-}
-
-/* Allocate space for the MCH regs if needed, return nonzero on error */
-static int
-intel_alloc_mchbar_resource(struct drm_i915_private *dev_priv)
-{
- int reg = GRAPHICS_VER(dev_priv) >= 4 ? MCHBAR_I965 : MCHBAR_I915;
- u32 temp_lo, temp_hi = 0;
- u64 mchbar_addr;
- int ret;
-
- if (GRAPHICS_VER(dev_priv) >= 4)
- pci_read_config_dword(dev_priv->bridge_dev, reg + 4, &temp_hi);
- pci_read_config_dword(dev_priv->bridge_dev, reg, &temp_lo);
- mchbar_addr = ((u64)temp_hi << 32) | temp_lo;
-
- /* If ACPI doesn't have it, assume we need to allocate it ourselves */
-#ifdef CONFIG_PNP
- if (mchbar_addr &&
- pnp_range_reserved(mchbar_addr, mchbar_addr + MCHBAR_SIZE))
- return 0;
-#endif
-
- /* Get some space for it */
- dev_priv->mch_res.name = "i915 MCHBAR";
- dev_priv->mch_res.flags = IORESOURCE_MEM;
- ret = pci_bus_alloc_resource(dev_priv->bridge_dev->bus,
- &dev_priv->mch_res,
- MCHBAR_SIZE, MCHBAR_SIZE,
- PCIBIOS_MIN_MEM,
- 0, pcibios_align_resource,
- dev_priv->bridge_dev);
- if (ret) {
- drm_dbg(&dev_priv->drm, "failed bus alloc: %d\n", ret);
- dev_priv->mch_res.start = 0;
- return ret;
- }
-
- if (GRAPHICS_VER(dev_priv) >= 4)
- pci_write_config_dword(dev_priv->bridge_dev, reg + 4,
- upper_32_bits(dev_priv->mch_res.start));
-
- pci_write_config_dword(dev_priv->bridge_dev, reg,
- lower_32_bits(dev_priv->mch_res.start));
- return 0;
-}
-
-/* Setup MCHBAR if possible, return true if we should disable it again */
-static void
-intel_setup_mchbar(struct drm_i915_private *dev_priv)
-{
- int mchbar_reg = GRAPHICS_VER(dev_priv) >= 4 ? MCHBAR_I965 : MCHBAR_I915;
- u32 temp;
- bool enabled;
-
- if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
- return;
-
- dev_priv->mchbar_need_disable = false;
-
- if (IS_I915G(dev_priv) || IS_I915GM(dev_priv)) {
- pci_read_config_dword(dev_priv->bridge_dev, DEVEN, &temp);
- enabled = !!(temp & DEVEN_MCHBAR_EN);
- } else {
- pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp);
- enabled = temp & 1;
- }
-
- /* If it's already enabled, don't have to do anything */
- if (enabled)
- return;
-
- if (intel_alloc_mchbar_resource(dev_priv))
- return;
-
- dev_priv->mchbar_need_disable = true;
-
- /* Space is allocated or reserved, so enable it. */
- if (IS_I915G(dev_priv) || IS_I915GM(dev_priv)) {
- pci_write_config_dword(dev_priv->bridge_dev, DEVEN,
- temp | DEVEN_MCHBAR_EN);
- } else {
- pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp);
- pci_write_config_dword(dev_priv->bridge_dev, mchbar_reg, temp | 1);
- }
-}
-
-static void
-intel_teardown_mchbar(struct drm_i915_private *dev_priv)
-{
- int mchbar_reg = GRAPHICS_VER(dev_priv) >= 4 ? MCHBAR_I965 : MCHBAR_I915;
-
- if (dev_priv->mchbar_need_disable) {
- if (IS_I915G(dev_priv) || IS_I915GM(dev_priv)) {
- u32 deven_val;
-
- pci_read_config_dword(dev_priv->bridge_dev, DEVEN,
- &deven_val);
- deven_val &= ~DEVEN_MCHBAR_EN;
- pci_write_config_dword(dev_priv->bridge_dev, DEVEN,
- deven_val);
- } else {
- u32 mchbar_val;
-
- pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg,
- &mchbar_val);
- mchbar_val &= ~1;
- pci_write_config_dword(dev_priv->bridge_dev, mchbar_reg,
- mchbar_val);
- }
- }
-
- if (dev_priv->mch_res.start)
- release_resource(&dev_priv->mch_res);
-}
-
static int i915_workqueues_init(struct drm_i915_private *dev_priv)
{
/*
@@ -447,7 +312,7 @@ static int i915_driver_mmio_probe(struct drm_i915_private *dev_priv)
if (i915_inject_probe_failure(dev_priv))
return -ENODEV;
- ret = i915_get_bridge_dev(dev_priv);
+ ret = intel_gmch_bridge_setup(dev_priv);
if (ret < 0)
return ret;
@@ -464,7 +329,7 @@ static int i915_driver_mmio_probe(struct drm_i915_private *dev_priv)
}
/* Try to make sure MCHBAR is enabled before poking at it */
- intel_setup_mchbar(dev_priv);
+ intel_gmch_bar_setup(dev_priv);
intel_device_info_runtime_init(dev_priv);
for_each_gt(gt, dev_priv, i) {
@@ -479,7 +344,7 @@ static int i915_driver_mmio_probe(struct drm_i915_private *dev_priv)
return 0;
err_uncore:
- intel_teardown_mchbar(dev_priv);
+ intel_gmch_bar_teardown(dev_priv);
return ret;
}
@@ -490,7 +355,7 @@ err_uncore:
*/
static void i915_driver_mmio_release(struct drm_i915_private *dev_priv)
{
- intel_teardown_mchbar(dev_priv);
+ intel_gmch_bar_teardown(dev_priv);
}
/**
@@ -612,10 +477,6 @@ static int i915_driver_hw_probe(struct drm_i915_private *dev_priv)
i915_perf_init(dev_priv);
- ret = intel_gt_assign_ggtt(to_gt(dev_priv));
- if (ret)
- goto err_perf;
-
ret = i915_ggtt_probe_hw(dev_priv);
if (ret)
goto err_perf;
@@ -763,6 +624,8 @@ static void i915_driver_register(struct drm_i915_private *dev_priv)
for_each_gt(gt, dev_priv, i)
intel_gt_driver_register(gt);
+ intel_pxp_debugfs_register(dev_priv->pxp);
+
i915_hwmon_register(dev_priv);
intel_display_driver_register(dev_priv);
@@ -794,6 +657,8 @@ static void i915_driver_unregister(struct drm_i915_private *dev_priv)
intel_display_driver_unregister(dev_priv);
+ intel_pxp_fini(dev_priv);
+
for_each_gt(gt, dev_priv, i)
intel_gt_driver_unregister(gt);
@@ -937,6 +802,8 @@ int i915_driver_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (ret)
goto out_cleanup_modeset2;
+ intel_pxp_init(i915);
+
ret = intel_modeset_init(i915);
if (ret)
goto out_cleanup_gem;
@@ -1169,6 +1036,8 @@ static int i915_drm_prepare(struct drm_device *dev)
{
struct drm_i915_private *i915 = to_i915(dev);
+ intel_pxp_suspend_prepare(i915->pxp);
+
/*
* NB intel_display_suspend() may issue new requests after we've
* ostensibly marked the GPU as ready-to-sleep here. We need to
@@ -1249,6 +1118,8 @@ static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation)
disable_rpm_wakeref_asserts(rpm);
+ intel_pxp_suspend(dev_priv->pxp);
+
i915_gem_suspend_late(dev_priv);
for_each_gt(gt, dev_priv, i)
@@ -1313,7 +1184,8 @@ int i915_driver_suspend_switcheroo(struct drm_i915_private *i915,
static int i915_drm_resume(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = to_i915(dev);
- int ret;
+ struct intel_gt *gt;
+ int ret, i;
disable_rpm_wakeref_asserts(&dev_priv->runtime_pm);
@@ -1328,6 +1200,11 @@ static int i915_drm_resume(struct drm_device *dev)
drm_err(&dev_priv->drm, "failed to re-enable GGTT\n");
i915_ggtt_resume(to_gt(dev_priv)->ggtt);
+
+ for_each_gt(gt, dev_priv, i)
+ if (GRAPHICS_VER(gt->i915) >= 8)
+ setup_private_pat(gt);
+
/* Must be called after GGTT is resumed. */
intel_dpt_resume(dev_priv);
@@ -1355,6 +1232,8 @@ static int i915_drm_resume(struct drm_device *dev)
i915_gem_resume(dev_priv);
+ intel_pxp_resume(dev_priv->pxp);
+
intel_modeset_init_hw(dev_priv);
intel_init_clock_gating(dev_priv);
intel_hpd_init(dev_priv);
@@ -1491,8 +1370,6 @@ static int i915_pm_suspend(struct device *kdev)
return -ENODEV;
}
- i915_ggtt_mark_pte_lost(i915, false);
-
if (i915->drm.switch_power_state == DRM_SWITCH_POWER_OFF)
return 0;
@@ -1545,14 +1422,6 @@ static int i915_pm_resume(struct device *kdev)
if (i915->drm.switch_power_state == DRM_SWITCH_POWER_OFF)
return 0;
- /*
- * If IRST is enabled, or if we can't detect whether it's enabled,
- * then we must assume we lost the GGTT page table entries, since
- * they are not retained if IRST decided to enter S4.
- */
- if (!IS_ENABLED(CONFIG_ACPI) || acpi_dev_present(irst_name, NULL, -1))
- i915_ggtt_mark_pte_lost(i915, true);
-
return i915_drm_resume(&i915->drm);
}
@@ -1612,9 +1481,6 @@ static int i915_pm_restore_early(struct device *kdev)
static int i915_pm_restore(struct device *kdev)
{
- struct drm_i915_private *i915 = kdev_to_i915(kdev);
-
- i915_ggtt_mark_pte_lost(i915, true);
return i915_pm_resume(kdev);
}
@@ -1638,6 +1504,8 @@ static int intel_runtime_suspend(struct device *kdev)
*/
i915_gem_runtime_suspend(dev_priv);
+ intel_pxp_runtime_suspend(dev_priv->pxp);
+
for_each_gt(gt, dev_priv, i)
intel_gt_runtime_suspend(gt);
@@ -1742,6 +1610,8 @@ static int intel_runtime_resume(struct device *kdev)
for_each_gt(gt, dev_priv, i)
intel_gt_runtime_resume(gt);
+ intel_pxp_runtime_resume(dev_priv->pxp);
+
/*
* On VLV/CHV display interrupts are part of the display
* power well, so hpd is reinitialized from there. For
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index a380db36d52c..4295306487c7 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -36,7 +36,7 @@
#include <drm/ttm/ttm_device.h>
-#include "display/intel_display.h"
+#include "display/intel_display_limits.h"
#include "display/intel_display_core.h"
#include "gem/i915_gem_context_types.h"
@@ -49,6 +49,8 @@
#include "gt/intel_workarounds.h"
#include "gt/uc/intel_uc.h"
+#include "soc/intel_pch.h"
+
#include "i915_drm_client.h"
#include "i915_gem.h"
#include "i915_gpu_error.h"
@@ -58,31 +60,46 @@
#include "i915_utils.h"
#include "intel_device_info.h"
#include "intel_memory_region.h"
-#include "intel_pch.h"
#include "intel_runtime_pm.h"
#include "intel_step.h"
#include "intel_uncore.h"
struct drm_i915_clock_gating_funcs;
-struct drm_i915_gem_object;
-struct drm_i915_private;
-struct intel_connector;
-struct intel_dp;
-struct intel_encoder;
-struct intel_limit;
-struct intel_overlay_error_state;
struct vlv_s0ix_state;
+struct intel_pxp;
-#define I915_GEM_GPU_DOMAINS \
- (I915_GEM_DOMAIN_RENDER | \
- I915_GEM_DOMAIN_SAMPLER | \
- I915_GEM_DOMAIN_COMMAND | \
- I915_GEM_DOMAIN_INSTRUCTION | \
- I915_GEM_DOMAIN_VERTEX)
+#define GEM_QUIRK_PIN_SWIZZLED_PAGES BIT(0)
-#define I915_COLOR_UNEVICTABLE (-1) /* a non-vma sharing the address space */
+/* Data Stolen Memory (DSM) aka "i915 stolen memory" */
+struct i915_dsm {
+ /*
+ * The start and end of DSM which we can optionally use to create GEM
+ * objects backed by stolen memory.
+ *
+ * Note that usable_size tells us exactly how much of this we are
+ * actually allowed to use, given that some portion of it is in fact
+ * reserved for use by hardware functions.
+ */
+ struct resource stolen;
-#define GEM_QUIRK_PIN_SWIZZLED_PAGES BIT(0)
+ /*
+ * Reserved portion of DSM.
+ */
+ struct resource reserved;
+
+ /*
+ * Total size minus reserved ranges.
+ *
+ * DSM is segmented in hardware with different portions offlimits to
+ * certain functions.
+ *
+ * The drm_mm is initialised to the total accessible range, as found
+ * from the PCI config. On Broadwell+, this is further restricted to
+ * avoid the first page! The upper end of DSM is reserved for hardware
+ * functions and similarly removed from the accessible range.
+ */
+ resource_size_t usable_size;
+};
struct i915_suspend_saved_registers {
u32 saveDSPARB;
@@ -161,19 +178,6 @@ struct i915_gem_mm {
u32 shrink_count;
};
-#define I915_IDLE_ENGINES_TIMEOUT (200) /* in ms */
-
-unsigned long i915_fence_context_timeout(const struct drm_i915_private *i915,
- u64 context);
-
-static inline unsigned long
-i915_fence_timeout(const struct drm_i915_private *i915)
-{
- return i915_fence_context_timeout(i915, U64_MAX);
-}
-
-#define HAS_HW_SAGV_WM(i915) (DISPLAY_VER(i915) >= 13 && !IS_DGFX(i915))
-
struct i915_virtual_gpu {
struct mutex lock; /* serialises sending of g2v_notify command pkts */
bool active;
@@ -203,29 +207,7 @@ struct drm_i915_private {
struct intel_runtime_info __runtime; /* Use RUNTIME_INFO() to access. */
struct intel_driver_caps caps;
- /**
- * Data Stolen Memory - aka "i915 stolen memory" gives us the start and
- * end of stolen which we can optionally use to create GEM objects
- * backed by stolen memory. Note that stolen_usable_size tells us
- * exactly how much of this we are actually allowed to use, given that
- * some portion of it is in fact reserved for use by hardware functions.
- */
- struct resource dsm;
- /**
- * Reseved portion of Data Stolen Memory
- */
- struct resource dsm_reserved;
-
- /*
- * Stolen memory is segmented in hardware with different portions
- * offlimits to certain functions.
- *
- * The drm_mm is initialised to the total accessible range, as found
- * from the PCI config. On Broadwell+, this is further restricted to
- * avoid the first page! The upper end of stolen memory is reserved for
- * hardware functions and similarly removed from the accessible range.
- */
- resource_size_t stolen_usable_size; /* Total size minus reserved ranges */
+ struct i915_dsm dsm;
struct intel_uncore uncore;
struct intel_uncore_mmio_debug mmio_debug;
@@ -234,13 +216,15 @@ struct drm_i915_private {
struct intel_gvt *gvt;
- struct pci_dev *bridge_dev;
+ struct {
+ struct pci_dev *pdev;
+ struct resource mch_res;
+ bool mchbar_need_disable;
+ } gmch;
struct rb_root uabi_engines;
unsigned int engine_uabi_class_count[I915_LAST_UABI_ENGINE_CLASS + 1];
- struct resource mch_res;
-
/* protects the irq masks */
spinlock_t irq_lock;
@@ -286,8 +270,6 @@ struct drm_i915_private {
struct i915_gem_mm mm;
- bool mchbar_need_disable;
-
struct intel_l3_parity l3_parity;
/*
@@ -298,14 +280,6 @@ struct drm_i915_private {
struct i915_gpu_error gpu_error;
- /*
- * Shadows for CHV DPLL_MD regs to keep the state
- * checker somewhat working in the presence hardware
- * crappiness (can't read out DPLL_MD for pipes B & C).
- */
- u32 chv_dpll_md[I915_MAX_PIPES];
- u32 bxt_phy_grc;
-
u32 suspend_count;
struct i915_suspend_saved_registers regfile;
struct vlv_s0ix_state *vlv_s0ix_state;
@@ -364,19 +338,13 @@ struct drm_i915_private {
struct file *mmap_singleton;
} gem;
- u8 pch_ssc_use;
+ struct intel_pxp *pxp;
/* For i915gm/i945gm vblank irq workaround */
u8 vblank_enabled;
bool irq_enabled;
- /*
- * DG2: Mask of PHYs that were not calibrated by the firmware
- * and should not be used.
- */
- u8 snps_phy_failed_calibration;
-
struct i915_pmu pmu;
struct i915_drm_clients clients;
@@ -465,8 +433,6 @@ static inline struct intel_gt *to_gt(struct drm_i915_private *i915)
#define INTEL_REVID(dev_priv) (to_pci_dev((dev_priv)->drm.dev)->revision)
-#define HAS_DSB(dev_priv) (INTEL_INFO(dev_priv)->display.has_dsb)
-
#define INTEL_DISPLAY_STEP(__i915) (RUNTIME_INFO(__i915)->step.display_step)
#define INTEL_GRAPHICS_STEP(__i915) (RUNTIME_INFO(__i915)->step.graphics_step)
#define INTEL_MEDIA_STEP(__i915) (RUNTIME_INFO(__i915)->step.media_step)
@@ -726,6 +692,14 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915,
(IS_SUBPLATFORM(__i915, INTEL_METEORLAKE, INTEL_SUBPLATFORM_##variant) && \
IS_GRAPHICS_STEP(__i915, since, until))
+#define IS_MTL_DISPLAY_STEP(__i915, since, until) \
+ (IS_METEORLAKE(__i915) && \
+ IS_DISPLAY_STEP(__i915, since, until))
+
+#define IS_MTL_MEDIA_STEP(__i915, since, until) \
+ (IS_METEORLAKE(__i915) && \
+ IS_MEDIA_STEP(__i915, since, until))
+
/*
* DG2 hardware steppings are a bit unusual. The hardware design was forked to
* create three variants (G10, G11, and G12) which each have distinct
@@ -874,6 +848,9 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915,
#define HAS_RPS(dev_priv) (INTEL_INFO(dev_priv)->has_rps)
#define HAS_DMC(dev_priv) (RUNTIME_INFO(dev_priv)->has_dmc)
+#define HAS_DSB(dev_priv) (INTEL_INFO(dev_priv)->display.has_dsb)
+#define HAS_DSC(__i915) (RUNTIME_INFO(__i915)->has_dsc)
+#define HAS_HW_SAGV_WM(i915) (DISPLAY_VER(i915) >= 13 && !IS_DGFX(i915))
#define HAS_HECI_PXP(dev_priv) \
(INTEL_INFO(dev_priv)->has_heci_pxp)
@@ -918,10 +895,6 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915,
#define HAS_GLOBAL_MOCS_REGISTERS(dev_priv) (INTEL_INFO(dev_priv)->has_global_mocs)
-#define HAS_PXP(dev_priv) ((IS_ENABLED(CONFIG_DRM_I915_PXP) && \
- INTEL_INFO(dev_priv)->has_pxp) && \
- VDBOX_MASK(to_gt(dev_priv)))
-
#define HAS_GMCH(dev_priv) (INTEL_INFO(dev_priv)->display.has_gmch)
#define HAS_GMD_ID(i915) (INTEL_INFO(i915)->has_gmd_id)
@@ -935,9 +908,6 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915,
#define NUM_L3_SLICES(dev_priv) (IS_HSW_GT3(dev_priv) ? \
2 : HAS_L3_DPF(dev_priv))
-#define GT_FREQUENCY_MULTIPLIER 50
-#define GEN9_FREQ_SCALER 3
-
#define INTEL_NUM_PIPES(dev_priv) (hweight8(RUNTIME_INFO(dev_priv)->pipe_mask))
#define HAS_DISPLAY(dev_priv) (RUNTIME_INFO(dev_priv)->pipe_mask != 0)
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 8468ca9885fd..35950fa91406 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -229,8 +229,9 @@ i915_gem_shmem_pread(struct drm_i915_gem_object *obj,
struct drm_i915_gem_pread *args)
{
unsigned int needs_clflush;
- unsigned int idx, offset;
char __user *user_data;
+ unsigned long offset;
+ pgoff_t idx;
u64 remain;
int ret;
@@ -383,13 +384,17 @@ i915_gem_gtt_pread(struct drm_i915_gem_object *obj,
{
struct drm_i915_private *i915 = to_i915(obj->base.dev);
struct i915_ggtt *ggtt = to_gt(i915)->ggtt;
+ unsigned long remain, offset;
intel_wakeref_t wakeref;
struct drm_mm_node node;
void __user *user_data;
struct i915_vma *vma;
- u64 remain, offset;
int ret = 0;
+ if (overflows_type(args->size, remain) ||
+ overflows_type(args->offset, offset))
+ return -EINVAL;
+
wakeref = intel_runtime_pm_get(&i915->runtime_pm);
vma = i915_gem_gtt_prepare(obj, &node, false);
@@ -540,13 +545,17 @@ i915_gem_gtt_pwrite_fast(struct drm_i915_gem_object *obj,
struct drm_i915_private *i915 = to_i915(obj->base.dev);
struct i915_ggtt *ggtt = to_gt(i915)->ggtt;
struct intel_runtime_pm *rpm = &i915->runtime_pm;
+ unsigned long remain, offset;
intel_wakeref_t wakeref;
struct drm_mm_node node;
struct i915_vma *vma;
- u64 remain, offset;
void __user *user_data;
int ret = 0;
+ if (overflows_type(args->size, remain) ||
+ overflows_type(args->offset, offset))
+ return -EINVAL;
+
if (i915_gem_object_has_struct_page(obj)) {
/*
* Avoid waking the device up if we can fallback, as
@@ -654,8 +663,9 @@ i915_gem_shmem_pwrite(struct drm_i915_gem_object *obj,
{
unsigned int partial_cacheline_write;
unsigned int needs_clflush;
- unsigned int offset, idx;
void __user *user_data;
+ unsigned long offset;
+ pgoff_t idx;
u64 remain;
int ret;
@@ -1099,7 +1109,7 @@ void i915_gem_drain_freed_objects(struct drm_i915_private *i915)
{
while (atomic_read(&i915->mm.free_count)) {
flush_work(&i915->mm.free_work);
- flush_delayed_work(&i915->bdev.wq);
+ drain_workqueue(i915->bdev.wq);
rcu_barrier();
}
}
@@ -1143,6 +1153,8 @@ int i915_gem_init(struct drm_i915_private *dev_priv)
for_each_gt(gt, dev_priv, i) {
intel_uc_fetch_firmwares(&gt->uc);
intel_wopcm_init(&gt->wopcm);
+ if (GRAPHICS_VER(dev_priv) >= 8)
+ setup_private_pat(gt);
}
ret = i915_init_ggtt(dev_priv);
diff --git a/drivers/gpu/drm/i915/i915_gem.h b/drivers/gpu/drm/i915/i915_gem.h
index a5cdf6662d01..82e9d289398c 100644
--- a/drivers/gpu/drm/i915/i915_gem.h
+++ b/drivers/gpu/drm/i915/i915_gem.h
@@ -39,6 +39,13 @@ struct i915_gem_ww_ctx;
struct i915_gtt_view;
struct i915_vma;
+#define I915_GEM_GPU_DOMAINS \
+ (I915_GEM_DOMAIN_RENDER | \
+ I915_GEM_DOMAIN_SAMPLER | \
+ I915_GEM_DOMAIN_COMMAND | \
+ I915_GEM_DOMAIN_INSTRUCTION | \
+ I915_GEM_DOMAIN_VERTEX)
+
void i915_gem_init_early(struct drm_i915_private *i915);
void i915_gem_cleanup_early(struct drm_i915_private *i915);
diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c
index a4b4d9b7d26c..c02ebd6900ae 100644
--- a/drivers/gpu/drm/i915/i915_gem_evict.c
+++ b/drivers/gpu/drm/i915/i915_gem_evict.c
@@ -43,16 +43,25 @@ static bool dying_vma(struct i915_vma *vma)
return !kref_read(&vma->obj->base.refcount);
}
-static int ggtt_flush(struct intel_gt *gt)
+static int ggtt_flush(struct i915_address_space *vm)
{
- /*
- * Not everything in the GGTT is tracked via vma (otherwise we
- * could evict as required with minimal stalling) so we are forced
- * to idle the GPU and explicitly retire outstanding requests in
- * the hopes that we can then remove contexts and the like only
- * bound by their active reference.
- */
- return intel_gt_wait_for_idle(gt, MAX_SCHEDULE_TIMEOUT);
+ struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
+ struct intel_gt *gt;
+ int ret = 0;
+
+ list_for_each_entry(gt, &ggtt->gt_list, ggtt_link) {
+ /*
+ * Not everything in the GGTT is tracked via vma (otherwise we
+ * could evict as required with minimal stalling) so we are forced
+ * to idle the GPU and explicitly retire outstanding requests in
+ * the hopes that we can then remove contexts and the like only
+ * bound by their active reference.
+ */
+ ret = intel_gt_wait_for_idle(gt, MAX_SCHEDULE_TIMEOUT);
+ if (ret)
+ return ret;
+ }
+ return ret;
}
static bool grab_vma(struct i915_vma *vma, struct i915_gem_ww_ctx *ww)
@@ -149,6 +158,7 @@ i915_gem_evict_something(struct i915_address_space *vm,
struct drm_mm_node *node;
enum drm_mm_insert_mode mode;
struct i915_vma *active;
+ struct intel_gt *gt;
int ret;
lockdep_assert_held(&vm->mutex);
@@ -174,7 +184,14 @@ i915_gem_evict_something(struct i915_address_space *vm,
min_size, alignment, color,
start, end, mode);
- intel_gt_retire_requests(vm->gt);
+ if (i915_is_ggtt(vm)) {
+ struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
+
+ list_for_each_entry(gt, &ggtt->gt_list, ggtt_link)
+ intel_gt_retire_requests(gt);
+ } else {
+ intel_gt_retire_requests(vm->gt);
+ }
search_again:
active = NULL;
@@ -246,7 +263,7 @@ search_again:
if (I915_SELFTEST_ONLY(igt_evict_ctl.fail_if_busy))
return -EBUSY;
- ret = ggtt_flush(vm->gt);
+ ret = ggtt_flush(vm);
if (ret)
return ret;
@@ -332,7 +349,15 @@ int i915_gem_evict_for_node(struct i915_address_space *vm,
* a stray pin (preventing eviction) that can only be resolved by
* retiring.
*/
- intel_gt_retire_requests(vm->gt);
+ if (i915_is_ggtt(vm)) {
+ struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
+ struct intel_gt *gt;
+
+ list_for_each_entry(gt, &ggtt->gt_list, ggtt_link)
+ intel_gt_retire_requests(gt);
+ } else {
+ intel_gt_retire_requests(vm->gt);
+ }
if (i915_vm_has_cache_coloring(vm)) {
/* Expand search to cover neighbouring guard pages (or lack!) */
@@ -444,7 +469,7 @@ int i915_gem_evict_vm(struct i915_address_space *vm, struct i915_gem_ww_ctx *ww,
* switch otherwise is ineffective.
*/
if (i915_is_ggtt(vm)) {
- ret = ggtt_flush(vm->gt);
+ ret = ggtt_flush(vm);
if (ret)
return ret;
}
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h
index 8c2f57eb5dda..3d77679bf211 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.h
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.h
@@ -18,6 +18,8 @@ struct drm_i915_gem_object;
struct i915_address_space;
struct i915_gem_ww_ctx;
+#define I915_COLOR_UNEVICTABLE (-1) /* a non-vma sharing the address space */
+
int __must_check i915_gem_gtt_prepare_pages(struct drm_i915_gem_object *obj,
struct sg_table *pages);
void i915_gem_gtt_finish_pages(struct drm_i915_gem_object *obj,
@@ -44,7 +46,8 @@ int i915_gem_gtt_insert(struct i915_address_space *vm,
#define PIN_HIGH BIT_ULL(5)
#define PIN_OFFSET_BIAS BIT_ULL(6)
#define PIN_OFFSET_FIXED BIT_ULL(7)
-#define PIN_VALIDATE BIT_ULL(8) /* validate placement only, no need to call unpin() */
+#define PIN_OFFSET_GUARD BIT_ULL(8)
+#define PIN_VALIDATE BIT_ULL(9) /* validate placement only, no need to call unpin() */
#define PIN_GLOBAL BIT_ULL(10) /* I915_VMA_GLOBAL_BIND */
#define PIN_USER BIT_ULL(11) /* I915_VMA_LOCAL_BIND */
diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c
index b20bd6365615..904f21e1380c 100644
--- a/drivers/gpu/drm/i915/i915_gpu_error.c
+++ b/drivers/gpu/drm/i915/i915_gpu_error.c
@@ -1370,14 +1370,14 @@ static void engine_record_execlists(struct intel_engine_coredump *ee)
}
static bool record_context(struct i915_gem_context_coredump *e,
- const struct i915_request *rq)
+ struct intel_context *ce)
{
struct i915_gem_context *ctx;
struct task_struct *task;
bool simulated;
rcu_read_lock();
- ctx = rcu_dereference(rq->context->gem_context);
+ ctx = rcu_dereference(ce->gem_context);
if (ctx && !kref_get_unless_zero(&ctx->ref))
ctx = NULL;
rcu_read_unlock();
@@ -1396,8 +1396,8 @@ static bool record_context(struct i915_gem_context_coredump *e,
e->guilty = atomic_read(&ctx->guilty_count);
e->active = atomic_read(&ctx->active_count);
- e->total_runtime = intel_context_get_total_runtime_ns(rq->context);
- e->avg_runtime = intel_context_get_avg_runtime_ns(rq->context);
+ e->total_runtime = intel_context_get_total_runtime_ns(ce);
+ e->avg_runtime = intel_context_get_avg_runtime_ns(ce);
simulated = i915_gem_context_no_error_capture(ctx);
@@ -1532,15 +1532,37 @@ intel_engine_coredump_alloc(struct intel_engine_cs *engine, gfp_t gfp, u32 dump_
return ee;
}
+static struct intel_engine_capture_vma *
+engine_coredump_add_context(struct intel_engine_coredump *ee,
+ struct intel_context *ce,
+ gfp_t gfp)
+{
+ struct intel_engine_capture_vma *vma = NULL;
+
+ ee->simulated |= record_context(&ee->context, ce);
+ if (ee->simulated)
+ return NULL;
+
+ /*
+ * We need to copy these to an anonymous buffer
+ * as the simplest method to avoid being overwritten
+ * by userspace.
+ */
+ vma = capture_vma(vma, ce->ring->vma, "ring", gfp);
+ vma = capture_vma(vma, ce->state, "HW context", gfp);
+
+ return vma;
+}
+
struct intel_engine_capture_vma *
intel_engine_coredump_add_request(struct intel_engine_coredump *ee,
struct i915_request *rq,
gfp_t gfp)
{
- struct intel_engine_capture_vma *vma = NULL;
+ struct intel_engine_capture_vma *vma;
- ee->simulated |= record_context(&ee->context, rq);
- if (ee->simulated)
+ vma = engine_coredump_add_context(ee, rq->context, gfp);
+ if (!vma)
return NULL;
/*
@@ -1550,8 +1572,6 @@ intel_engine_coredump_add_request(struct intel_engine_coredump *ee,
*/
vma = capture_vma_snapshot(vma, rq->batch_res, gfp, "batch");
vma = capture_user(vma, rq, gfp);
- vma = capture_vma(vma, rq->ring->vma, "ring", gfp);
- vma = capture_vma(vma, rq->context->state, "HW context", gfp);
ee->rq_head = rq->head;
ee->rq_post = rq->postfix;
@@ -1604,25 +1624,28 @@ capture_engine(struct intel_engine_cs *engine,
return NULL;
intel_engine_get_hung_entity(engine, &ce, &rq);
- if (!rq || !i915_request_started(rq))
- goto no_request_capture;
+ if (rq && !i915_request_started(rq))
+ drm_info(&engine->gt->i915->drm, "Got hung context on %s with active request %lld:%lld [0x%04X] not yet started\n",
+ engine->name, rq->fence.context, rq->fence.seqno, ce->guc_id.id);
+
+ if (rq) {
+ capture = intel_engine_coredump_add_request(ee, rq, ATOMIC_MAYFAIL);
+ i915_request_put(rq);
+ } else if (ce) {
+ capture = engine_coredump_add_context(ee, ce, ATOMIC_MAYFAIL);
+ }
- capture = intel_engine_coredump_add_request(ee, rq, ATOMIC_MAYFAIL);
- if (!capture)
- goto no_request_capture;
- if (dump_flags & CORE_DUMP_FLAG_IS_GUC_CAPTURE)
- intel_guc_capture_get_matching_node(engine->gt, ee, ce);
+ if (capture) {
+ intel_engine_coredump_add_vma(ee, capture, compress);
- intel_engine_coredump_add_vma(ee, capture, compress);
- i915_request_put(rq);
+ if (dump_flags & CORE_DUMP_FLAG_IS_GUC_CAPTURE)
+ intel_guc_capture_get_matching_node(engine->gt, ee, ce);
+ } else {
+ kfree(ee);
+ ee = NULL;
+ }
return ee;
-
-no_request_capture:
- if (rq)
- i915_request_put(rq);
- kfree(ee);
- return NULL;
}
static void
diff --git a/drivers/gpu/drm/i915/i915_gpu_error.h b/drivers/gpu/drm/i915/i915_gpu_error.h
index efc75cc2ffdb..56027ffbce51 100644
--- a/drivers/gpu/drm/i915/i915_gpu_error.h
+++ b/drivers/gpu/drm/i915/i915_gpu_error.h
@@ -94,7 +94,7 @@ struct intel_engine_coredump {
struct intel_instdone instdone;
/* GuC matched capture-lists info */
- struct intel_guc_state_capture *capture;
+ struct intel_guc_state_capture *guc_capture;
struct __guc_capture_parsed_output *guc_capture_node;
struct i915_gem_context_coredump {
diff --git a/drivers/gpu/drm/i915/i915_hwmon.c b/drivers/gpu/drm/i915/i915_hwmon.c
index c588a17f97e9..1225bc432f0d 100644
--- a/drivers/gpu/drm/i915/i915_hwmon.c
+++ b/drivers/gpu/drm/i915/i915_hwmon.c
@@ -293,6 +293,10 @@ static const struct hwmon_channel_info *hwm_gt_info[] = {
/* I1 is exposed as power_crit or as curr_crit depending on bit 31 */
static int hwm_pcode_read_i1(struct drm_i915_private *i915, u32 *uval)
{
+ /* Avoid ILLEGAL_SUBCOMMAND "mailbox access failed" warning in snb_pcode_read */
+ if (IS_DG1(i915) || IS_DG2(i915))
+ return -ENXIO;
+
return snb_pcode_read_p(&i915->uncore, PCODE_POWER_SETUP,
POWER_SETUP_SUBCOMMAND_READ_I1, 0, uval);
}
@@ -355,6 +359,38 @@ hwm_power_is_visible(const struct hwm_drvdata *ddat, u32 attr, int chan)
}
}
+/*
+ * HW allows arbitrary PL1 limits to be set but silently clamps these values to
+ * "typical but not guaranteed" min/max values in rg.pkg_power_sku. Follow the
+ * same pattern for sysfs, allow arbitrary PL1 limits to be set but display
+ * clamped values when read. Write/read I1 also follows the same pattern.
+ */
+static int
+hwm_power_max_read(struct hwm_drvdata *ddat, long *val)
+{
+ struct i915_hwmon *hwmon = ddat->hwmon;
+ intel_wakeref_t wakeref;
+ u64 r, min, max;
+
+ *val = hwm_field_read_and_scale(ddat,
+ hwmon->rg.pkg_rapl_limit,
+ PKG_PWR_LIM_1,
+ hwmon->scl_shift_power,
+ SF_POWER);
+
+ with_intel_runtime_pm(ddat->uncore->rpm, wakeref)
+ r = intel_uncore_read64(ddat->uncore, hwmon->rg.pkg_power_sku);
+ min = REG_FIELD_GET(PKG_MIN_PWR, r);
+ min = mul_u64_u32_shr(min, SF_POWER, hwmon->scl_shift_power);
+ max = REG_FIELD_GET(PKG_MAX_PWR, r);
+ max = mul_u64_u32_shr(max, SF_POWER, hwmon->scl_shift_power);
+
+ if (min && max)
+ *val = clamp_t(u64, *val, min, max);
+
+ return 0;
+}
+
static int
hwm_power_read(struct hwm_drvdata *ddat, u32 attr, int chan, long *val)
{
@@ -364,12 +400,7 @@ hwm_power_read(struct hwm_drvdata *ddat, u32 attr, int chan, long *val)
switch (attr) {
case hwmon_power_max:
- *val = hwm_field_read_and_scale(ddat,
- hwmon->rg.pkg_rapl_limit,
- PKG_PWR_LIM_1,
- hwmon->scl_shift_power,
- SF_POWER);
- return 0;
+ return hwm_power_max_read(ddat, val);
case hwmon_power_rated_max:
*val = hwm_field_read_and_scale(ddat,
hwmon->rg.pkg_power_sku,
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 91c533986041..240d5e198904 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -614,414 +614,6 @@ static void i915_enable_asle_pipestat(struct drm_i915_private *dev_priv)
spin_unlock_irq(&dev_priv->irq_lock);
}
-/*
- * This timing diagram depicts the video signal in and
- * around the vertical blanking period.
- *
- * Assumptions about the fictitious mode used in this example:
- * vblank_start >= 3
- * vsync_start = vblank_start + 1
- * vsync_end = vblank_start + 2
- * vtotal = vblank_start + 3
- *
- * start of vblank:
- * latch double buffered registers
- * increment frame counter (ctg+)
- * generate start of vblank interrupt (gen4+)
- * |
- * | frame start:
- * | generate frame start interrupt (aka. vblank interrupt) (gmch)
- * | may be shifted forward 1-3 extra lines via PIPECONF
- * | |
- * | | start of vsync:
- * | | generate vsync interrupt
- * | | |
- * ___xxxx___ ___xxxx___ ___xxxx___ ___xxxx___ ___xxxx___ ___xxxx
- * . \hs/ . \hs/ \hs/ \hs/ . \hs/
- * ----va---> <-----------------vb--------------------> <--------va-------------
- * | | <----vs-----> |
- * -vbs-----> <---vbs+1---> <---vbs+2---> <-----0-----> <-----1-----> <-----2--- (scanline counter gen2)
- * -vbs-2---> <---vbs-1---> <---vbs-----> <---vbs+1---> <---vbs+2---> <-----0--- (scanline counter gen3+)
- * -vbs-2---> <---vbs-2---> <---vbs-1---> <---vbs-----> <---vbs+1---> <---vbs+2- (scanline counter hsw+ hdmi)
- * | | |
- * last visible pixel first visible pixel
- * | increment frame counter (gen3/4)
- * pixel counter = vblank_start * htotal pixel counter = 0 (gen3/4)
- *
- * x = horizontal active
- * _ = horizontal blanking
- * hs = horizontal sync
- * va = vertical active
- * vb = vertical blanking
- * vs = vertical sync
- * vbs = vblank_start (number)
- *
- * Summary:
- * - most events happen at the start of horizontal sync
- * - frame start happens at the start of horizontal blank, 1-4 lines
- * (depending on PIPECONF settings) after the start of vblank
- * - gen3/4 pixel and frame counter are synchronized with the start
- * of horizontal active on the first line of vertical active
- */
-
-/* Called from drm generic code, passed a 'crtc', which
- * we use as a pipe index
- */
-u32 i915_get_vblank_counter(struct drm_crtc *crtc)
-{
- struct drm_i915_private *dev_priv = to_i915(crtc->dev);
- struct drm_vblank_crtc *vblank = &dev_priv->drm.vblank[drm_crtc_index(crtc)];
- const struct drm_display_mode *mode = &vblank->hwmode;
- enum pipe pipe = to_intel_crtc(crtc)->pipe;
- i915_reg_t high_frame, low_frame;
- u32 high1, high2, low, pixel, vbl_start, hsync_start, htotal;
- unsigned long irqflags;
-
- /*
- * On i965gm TV output the frame counter only works up to
- * the point when we enable the TV encoder. After that the
- * frame counter ceases to work and reads zero. We need a
- * vblank wait before enabling the TV encoder and so we
- * have to enable vblank interrupts while the frame counter
- * is still in a working state. However the core vblank code
- * does not like us returning non-zero frame counter values
- * when we've told it that we don't have a working frame
- * counter. Thus we must stop non-zero values leaking out.
- */
- if (!vblank->max_vblank_count)
- return 0;
-
- htotal = mode->crtc_htotal;
- hsync_start = mode->crtc_hsync_start;
- vbl_start = mode->crtc_vblank_start;
- if (mode->flags & DRM_MODE_FLAG_INTERLACE)
- vbl_start = DIV_ROUND_UP(vbl_start, 2);
-
- /* Convert to pixel count */
- vbl_start *= htotal;
-
- /* Start of vblank event occurs at start of hsync */
- vbl_start -= htotal - hsync_start;
-
- high_frame = PIPEFRAME(pipe);
- low_frame = PIPEFRAMEPIXEL(pipe);
-
- spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
-
- /*
- * High & low register fields aren't synchronized, so make sure
- * we get a low value that's stable across two reads of the high
- * register.
- */
- do {
- high1 = intel_de_read_fw(dev_priv, high_frame) & PIPE_FRAME_HIGH_MASK;
- low = intel_de_read_fw(dev_priv, low_frame);
- high2 = intel_de_read_fw(dev_priv, high_frame) & PIPE_FRAME_HIGH_MASK;
- } while (high1 != high2);
-
- spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
-
- high1 >>= PIPE_FRAME_HIGH_SHIFT;
- pixel = low & PIPE_PIXEL_MASK;
- low >>= PIPE_FRAME_LOW_SHIFT;
-
- /*
- * The frame counter increments at beginning of active.
- * Cook up a vblank counter by also checking the pixel
- * counter against vblank start.
- */
- return (((high1 << 8) | low) + (pixel >= vbl_start)) & 0xffffff;
-}
-
-u32 g4x_get_vblank_counter(struct drm_crtc *crtc)
-{
- struct drm_i915_private *dev_priv = to_i915(crtc->dev);
- struct drm_vblank_crtc *vblank = &dev_priv->drm.vblank[drm_crtc_index(crtc)];
- enum pipe pipe = to_intel_crtc(crtc)->pipe;
-
- if (!vblank->max_vblank_count)
- return 0;
-
- return intel_uncore_read(&dev_priv->uncore, PIPE_FRMCOUNT_G4X(pipe));
-}
-
-static u32 intel_crtc_scanlines_since_frame_timestamp(struct intel_crtc *crtc)
-{
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
- struct drm_vblank_crtc *vblank =
- &crtc->base.dev->vblank[drm_crtc_index(&crtc->base)];
- const struct drm_display_mode *mode = &vblank->hwmode;
- u32 htotal = mode->crtc_htotal;
- u32 clock = mode->crtc_clock;
- u32 scan_prev_time, scan_curr_time, scan_post_time;
-
- /*
- * To avoid the race condition where we might cross into the
- * next vblank just between the PIPE_FRMTMSTMP and TIMESTAMP_CTR
- * reads. We make sure we read PIPE_FRMTMSTMP and TIMESTAMP_CTR
- * during the same frame.
- */
- do {
- /*
- * This field provides read back of the display
- * pipe frame time stamp. The time stamp value
- * is sampled at every start of vertical blank.
- */
- scan_prev_time = intel_de_read_fw(dev_priv,
- PIPE_FRMTMSTMP(crtc->pipe));
-
- /*
- * The TIMESTAMP_CTR register has the current
- * time stamp value.
- */
- scan_curr_time = intel_de_read_fw(dev_priv, IVB_TIMESTAMP_CTR);
-
- scan_post_time = intel_de_read_fw(dev_priv,
- PIPE_FRMTMSTMP(crtc->pipe));
- } while (scan_post_time != scan_prev_time);
-
- return div_u64(mul_u32_u32(scan_curr_time - scan_prev_time,
- clock), 1000 * htotal);
-}
-
-/*
- * On certain encoders on certain platforms, pipe
- * scanline register will not work to get the scanline,
- * since the timings are driven from the PORT or issues
- * with scanline register updates.
- * This function will use Framestamp and current
- * timestamp registers to calculate the scanline.
- */
-static u32 __intel_get_crtc_scanline_from_timestamp(struct intel_crtc *crtc)
-{
- struct drm_vblank_crtc *vblank =
- &crtc->base.dev->vblank[drm_crtc_index(&crtc->base)];
- const struct drm_display_mode *mode = &vblank->hwmode;
- u32 vblank_start = mode->crtc_vblank_start;
- u32 vtotal = mode->crtc_vtotal;
- u32 scanline;
-
- scanline = intel_crtc_scanlines_since_frame_timestamp(crtc);
- scanline = min(scanline, vtotal - 1);
- scanline = (scanline + vblank_start) % vtotal;
-
- return scanline;
-}
-
-/*
- * intel_de_read_fw(), only for fast reads of display block, no need for
- * forcewake etc.
- */
-static int __intel_get_crtc_scanline(struct intel_crtc *crtc)
-{
- struct drm_device *dev = crtc->base.dev;
- struct drm_i915_private *dev_priv = to_i915(dev);
- const struct drm_display_mode *mode;
- struct drm_vblank_crtc *vblank;
- enum pipe pipe = crtc->pipe;
- int position, vtotal;
-
- if (!crtc->active)
- return 0;
-
- vblank = &crtc->base.dev->vblank[drm_crtc_index(&crtc->base)];
- mode = &vblank->hwmode;
-
- if (crtc->mode_flags & I915_MODE_FLAG_GET_SCANLINE_FROM_TIMESTAMP)
- return __intel_get_crtc_scanline_from_timestamp(crtc);
-
- vtotal = mode->crtc_vtotal;
- if (mode->flags & DRM_MODE_FLAG_INTERLACE)
- vtotal /= 2;
-
- position = intel_de_read_fw(dev_priv, PIPEDSL(pipe)) & PIPEDSL_LINE_MASK;
-
- /*
- * On HSW, the DSL reg (0x70000) appears to return 0 if we
- * read it just before the start of vblank. So try it again
- * so we don't accidentally end up spanning a vblank frame
- * increment, causing the pipe_update_end() code to squak at us.
- *
- * The nature of this problem means we can't simply check the ISR
- * bit and return the vblank start value; nor can we use the scanline
- * debug register in the transcoder as it appears to have the same
- * problem. We may need to extend this to include other platforms,
- * but so far testing only shows the problem on HSW.
- */
- if (HAS_DDI(dev_priv) && !position) {
- int i, temp;
-
- for (i = 0; i < 100; i++) {
- udelay(1);
- temp = intel_de_read_fw(dev_priv, PIPEDSL(pipe)) & PIPEDSL_LINE_MASK;
- if (temp != position) {
- position = temp;
- break;
- }
- }
- }
-
- /*
- * See update_scanline_offset() for the details on the
- * scanline_offset adjustment.
- */
- return (position + crtc->scanline_offset) % vtotal;
-}
-
-static bool i915_get_crtc_scanoutpos(struct drm_crtc *_crtc,
- bool in_vblank_irq,
- int *vpos, int *hpos,
- ktime_t *stime, ktime_t *etime,
- const struct drm_display_mode *mode)
-{
- struct drm_device *dev = _crtc->dev;
- struct drm_i915_private *dev_priv = to_i915(dev);
- struct intel_crtc *crtc = to_intel_crtc(_crtc);
- enum pipe pipe = crtc->pipe;
- int position;
- int vbl_start, vbl_end, hsync_start, htotal, vtotal;
- unsigned long irqflags;
- bool use_scanline_counter = DISPLAY_VER(dev_priv) >= 5 ||
- IS_G4X(dev_priv) || DISPLAY_VER(dev_priv) == 2 ||
- crtc->mode_flags & I915_MODE_FLAG_USE_SCANLINE_COUNTER;
-
- if (drm_WARN_ON(&dev_priv->drm, !mode->crtc_clock)) {
- drm_dbg(&dev_priv->drm,
- "trying to get scanoutpos for disabled "
- "pipe %c\n", pipe_name(pipe));
- return false;
- }
-
- htotal = mode->crtc_htotal;
- hsync_start = mode->crtc_hsync_start;
- vtotal = mode->crtc_vtotal;
- vbl_start = mode->crtc_vblank_start;
- vbl_end = mode->crtc_vblank_end;
-
- if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
- vbl_start = DIV_ROUND_UP(vbl_start, 2);
- vbl_end /= 2;
- vtotal /= 2;
- }
-
- /*
- * Lock uncore.lock, as we will do multiple timing critical raw
- * register reads, potentially with preemption disabled, so the
- * following code must not block on uncore.lock.
- */
- spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
-
- /* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */
-
- /* Get optional system timestamp before query. */
- if (stime)
- *stime = ktime_get();
-
- if (crtc->mode_flags & I915_MODE_FLAG_VRR) {
- int scanlines = intel_crtc_scanlines_since_frame_timestamp(crtc);
-
- position = __intel_get_crtc_scanline(crtc);
-
- /*
- * Already exiting vblank? If so, shift our position
- * so it looks like we're already apporaching the full
- * vblank end. This should make the generated timestamp
- * more or less match when the active portion will start.
- */
- if (position >= vbl_start && scanlines < position)
- position = min(crtc->vmax_vblank_start + scanlines, vtotal - 1);
- } else if (use_scanline_counter) {
- /* No obvious pixelcount register. Only query vertical
- * scanout position from Display scan line register.
- */
- position = __intel_get_crtc_scanline(crtc);
- } else {
- /* Have access to pixelcount since start of frame.
- * We can split this into vertical and horizontal
- * scanout position.
- */
- position = (intel_de_read_fw(dev_priv, PIPEFRAMEPIXEL(pipe)) & PIPE_PIXEL_MASK) >> PIPE_PIXEL_SHIFT;
-
- /* convert to pixel counts */
- vbl_start *= htotal;
- vbl_end *= htotal;
- vtotal *= htotal;
-
- /*
- * In interlaced modes, the pixel counter counts all pixels,
- * so one field will have htotal more pixels. In order to avoid
- * the reported position from jumping backwards when the pixel
- * counter is beyond the length of the shorter field, just
- * clamp the position the length of the shorter field. This
- * matches how the scanline counter based position works since
- * the scanline counter doesn't count the two half lines.
- */
- if (position >= vtotal)
- position = vtotal - 1;
-
- /*
- * Start of vblank interrupt is triggered at start of hsync,
- * just prior to the first active line of vblank. However we
- * consider lines to start at the leading edge of horizontal
- * active. So, should we get here before we've crossed into
- * the horizontal active of the first line in vblank, we would
- * not set the DRM_SCANOUTPOS_INVBL flag. In order to fix that,
- * always add htotal-hsync_start to the current pixel position.
- */
- position = (position + htotal - hsync_start) % vtotal;
- }
-
- /* Get optional system timestamp after query. */
- if (etime)
- *etime = ktime_get();
-
- /* preempt_enable_rt() should go right here in PREEMPT_RT patchset. */
-
- spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
-
- /*
- * While in vblank, position will be negative
- * counting up towards 0 at vbl_end. And outside
- * vblank, position will be positive counting
- * up since vbl_end.
- */
- if (position >= vbl_start)
- position -= vbl_end;
- else
- position += vtotal - vbl_end;
-
- if (use_scanline_counter) {
- *vpos = position;
- *hpos = 0;
- } else {
- *vpos = position / htotal;
- *hpos = position - (*vpos * htotal);
- }
-
- return true;
-}
-
-bool intel_crtc_get_vblank_timestamp(struct drm_crtc *crtc, int *max_error,
- ktime_t *vblank_time, bool in_vblank_irq)
-{
- return drm_crtc_vblank_helper_get_vblank_timestamp_internal(
- crtc, max_error, vblank_time, in_vblank_irq,
- i915_get_crtc_scanoutpos);
-}
-
-int intel_get_crtc_scanline(struct intel_crtc *crtc)
-{
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
- unsigned long irqflags;
- int position;
-
- spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
- position = __intel_get_crtc_scanline(crtc);
- spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
-
- return position;
-}
-
/**
* ivb_parity_work - Workqueue called when a parity error interrupt
* occurred.
@@ -2451,8 +2043,8 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
ret = IRQ_HANDLED;
gen8_de_misc_irq_handler(dev_priv, iir);
} else {
- drm_err(&dev_priv->drm,
- "The master control interrupt lied (DE MISC)!\n");
+ drm_err_ratelimited(&dev_priv->drm,
+ "The master control interrupt lied (DE MISC)!\n");
}
}
@@ -2463,8 +2055,8 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
ret = IRQ_HANDLED;
gen11_hpd_irq_handler(dev_priv, iir);
} else {
- drm_err(&dev_priv->drm,
- "The master control interrupt lied, (DE HPD)!\n");
+ drm_err_ratelimited(&dev_priv->drm,
+ "The master control interrupt lied, (DE HPD)!\n");
}
}
@@ -2513,12 +2105,12 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
}
if (!found)
- drm_err(&dev_priv->drm,
- "Unexpected DE Port interrupt\n");
+ drm_err_ratelimited(&dev_priv->drm,
+ "Unexpected DE Port interrupt\n");
}
else
- drm_err(&dev_priv->drm,
- "The master control interrupt lied (DE PORT)!\n");
+ drm_err_ratelimited(&dev_priv->drm,
+ "The master control interrupt lied (DE PORT)!\n");
}
for_each_pipe(dev_priv, pipe) {
@@ -2529,8 +2121,8 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
iir = intel_uncore_read(&dev_priv->uncore, GEN8_DE_PIPE_IIR(pipe));
if (!iir) {
- drm_err(&dev_priv->drm,
- "The master control interrupt lied (DE PIPE)!\n");
+ drm_err_ratelimited(&dev_priv->drm,
+ "The master control interrupt lied (DE PIPE)!\n");
continue;
}
@@ -2551,10 +2143,10 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
fault_errors = iir & gen8_de_pipe_fault_mask(dev_priv);
if (fault_errors)
- drm_err(&dev_priv->drm,
- "Fault errors on pipe %c: 0x%08x\n",
- pipe_name(pipe),
- fault_errors);
+ drm_err_ratelimited(&dev_priv->drm,
+ "Fault errors on pipe %c: 0x%08x\n",
+ pipe_name(pipe),
+ fault_errors);
}
if (HAS_PCH_SPLIT(dev_priv) && !HAS_PCH_NOP(dev_priv) &&
diff --git a/drivers/gpu/drm/i915/i915_irq.h b/drivers/gpu/drm/i915/i915_irq.h
index 9b004fc3444e..03ee4c8b1ed3 100644
--- a/drivers/gpu/drm/i915/i915_irq.h
+++ b/drivers/gpu/drm/i915/i915_irq.h
@@ -66,18 +66,12 @@ bool intel_irqs_enabled(struct drm_i915_private *dev_priv);
void intel_synchronize_irq(struct drm_i915_private *i915);
void intel_synchronize_hardirq(struct drm_i915_private *i915);
-int intel_get_crtc_scanline(struct intel_crtc *crtc);
void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv,
u8 pipe_mask);
void gen8_irq_power_well_pre_disable(struct drm_i915_private *dev_priv,
u8 pipe_mask);
u32 gen8_de_pipe_underrun_mask(struct drm_i915_private *dev_priv);
-bool intel_crtc_get_vblank_timestamp(struct drm_crtc *crtc, int *max_error,
- ktime_t *vblank_time, bool in_vblank_irq);
-
-u32 i915_get_vblank_counter(struct drm_crtc *crtc);
-u32 g4x_get_vblank_counter(struct drm_crtc *crtc);
int i8xx_enable_vblank(struct drm_crtc *crtc);
int i915gm_enable_vblank(struct drm_crtc *crtc);
diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c
index d1e4d528cb17..ade744cccfea 100644
--- a/drivers/gpu/drm/i915/i915_params.c
+++ b/drivers/gpu/drm/i915/i915_params.c
@@ -122,7 +122,7 @@ i915_param_named_unsafe(enable_psr2_sel_fetch, bool, 0400,
"Default: 0");
i915_param_named_unsafe(force_probe, charp, 0400,
- "Force probe the driver for specified devices. "
+ "Force probe options for specified supported devices. "
"See CONFIG_DRM_I915_FORCE_PROBE for details.");
i915_param_named_unsafe(disable_power_well, int, 0400,
@@ -192,6 +192,9 @@ i915_param_named_unsafe(huc_firmware_path, charp, 0400,
i915_param_named_unsafe(dmc_firmware_path, charp, 0400,
"DMC firmware path to use instead of the default one");
+i915_param_named_unsafe(gsc_firmware_path, charp, 0400,
+ "GSC firmware path to use instead of the default one");
+
i915_param_named_unsafe(enable_dp_mst, bool, 0400,
"Enable multi-stream transport (MST) for new DisplayPort sinks. (default: true)");
@@ -219,27 +222,44 @@ i915_param_named_unsafe(lmem_size, uint, 0400,
i915_param_named_unsafe(lmem_bar_size, uint, 0400,
"Set the lmem bar size(in MiB).");
-static __always_inline void _print_param(struct drm_printer *p,
- const char *name,
- const char *type,
- const void *x)
+static void _param_print_bool(struct drm_printer *p, const char *name,
+ bool val)
+{
+ drm_printf(p, "i915.%s=%s\n", name, str_yes_no(val));
+}
+
+static void _param_print_int(struct drm_printer *p, const char *name,
+ int val)
+{
+ drm_printf(p, "i915.%s=%d\n", name, val);
+}
+
+static void _param_print_uint(struct drm_printer *p, const char *name,
+ unsigned int val)
+{
+ drm_printf(p, "i915.%s=%u\n", name, val);
+}
+
+static void _param_print_ulong(struct drm_printer *p, const char *name,
+ unsigned long val)
{
- if (!__builtin_strcmp(type, "bool"))
- drm_printf(p, "i915.%s=%s\n", name,
- str_yes_no(*(const bool *)x));
- else if (!__builtin_strcmp(type, "int"))
- drm_printf(p, "i915.%s=%d\n", name, *(const int *)x);
- else if (!__builtin_strcmp(type, "unsigned int"))
- drm_printf(p, "i915.%s=%u\n", name, *(const unsigned int *)x);
- else if (!__builtin_strcmp(type, "unsigned long"))
- drm_printf(p, "i915.%s=%lu\n", name, *(const unsigned long *)x);
- else if (!__builtin_strcmp(type, "char *"))
- drm_printf(p, "i915.%s=%s\n", name, *(const char **)x);
- else
- WARN_ONCE(1, "no printer defined for param type %s (i915.%s)\n",
- type, name);
+ drm_printf(p, "i915.%s=%lu\n", name, val);
}
+static void _param_print_charp(struct drm_printer *p, const char *name,
+ const char *val)
+{
+ drm_printf(p, "i915.%s=%s\n", name, val);
+}
+
+#define _param_print(p, name, val) \
+ _Generic(val, \
+ bool: _param_print_bool, \
+ int: _param_print_int, \
+ unsigned int: _param_print_uint, \
+ unsigned long: _param_print_ulong, \
+ char *: _param_print_charp)(p, name, val)
+
/**
* i915_params_dump - dump i915 modparams
* @params: i915 modparams
@@ -249,37 +269,48 @@ static __always_inline void _print_param(struct drm_printer *p,
*/
void i915_params_dump(const struct i915_params *params, struct drm_printer *p)
{
-#define PRINT(T, x, ...) _print_param(p, #x, #T, &params->x);
+#define PRINT(T, x, ...) _param_print(p, #x, params->x);
I915_PARAMS_FOR_EACH(PRINT);
#undef PRINT
}
-static __always_inline void dup_param(const char *type, void *x)
+static void _param_dup_charp(char **valp)
{
- if (!__builtin_strcmp(type, "char *"))
- *(void **)x = kstrdup(*(void **)x, GFP_ATOMIC);
+ *valp = kstrdup(*valp, GFP_ATOMIC);
}
+static void _param_nop(void *valp)
+{
+}
+
+#define _param_dup(valp) \
+ _Generic(valp, \
+ char **: _param_dup_charp, \
+ default: _param_nop)(valp)
+
void i915_params_copy(struct i915_params *dest, const struct i915_params *src)
{
*dest = *src;
-#define DUP(T, x, ...) dup_param(#T, &dest->x);
+#define DUP(T, x, ...) _param_dup(&dest->x);
I915_PARAMS_FOR_EACH(DUP);
#undef DUP
}
-static __always_inline void free_param(const char *type, void *x)
+static void _param_free_charp(char **valp)
{
- if (!__builtin_strcmp(type, "char *")) {
- kfree(*(void **)x);
- *(void **)x = NULL;
- }
+ kfree(*valp);
+ *valp = NULL;
}
+#define _param_free(valp) \
+ _Generic(valp, \
+ char **: _param_free_charp, \
+ default: _param_nop)(valp)
+
/* free the allocated members, *not* the passed in params itself */
void i915_params_free(struct i915_params *params)
{
-#define FREE(T, x, ...) free_param(#T, &params->x);
+#define FREE(T, x, ...) _param_free(&params->x);
I915_PARAMS_FOR_EACH(FREE);
#undef FREE
}
diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h
index 2733cb6cfe09..3f51f90145b6 100644
--- a/drivers/gpu/drm/i915/i915_params.h
+++ b/drivers/gpu/drm/i915/i915_params.h
@@ -64,6 +64,7 @@ struct drm_printer;
param(char *, guc_firmware_path, NULL, 0400) \
param(char *, huc_firmware_path, NULL, 0400) \
param(char *, dmc_firmware_path, NULL, 0400) \
+ param(char *, gsc_firmware_path, NULL, 0400) \
param(bool, memtest, false, 0400) \
param(int, mmio_debug, -IS_ENABLED(CONFIG_DRM_I915_DEBUG_MMIO), 0600) \
param(int, edp_vswing, 0, 0400) \
diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c
index 4fada7ebe8d8..a8d942b16223 100644
--- a/drivers/gpu/drm/i915/i915_pci.c
+++ b/drivers/gpu/drm/i915/i915_pci.c
@@ -26,6 +26,7 @@
#include <drm/drm_drv.h>
#include <drm/i915_pciids.h>
+#include "display/intel_display.h"
#include "gt/intel_gt_regs.h"
#include "gt/intel_sa_media.h"
@@ -132,9 +133,9 @@
[PIPE_D] = TGL_CURSOR_D_OFFSET, \
}
-#define I9XX_COLORS \
+#define I845_COLORS \
.display.color = { .gamma_lut_size = 256 }
-#define I965_COLORS \
+#define I9XX_COLORS \
.display.color = { .gamma_lut_size = 129, \
.gamma_lut_tests = DRM_COLOR_LUT_NON_DECREASING, \
}
@@ -210,7 +211,7 @@
.dma_mask_size = 32, \
I845_PIPE_OFFSETS, \
I845_CURSOR_OFFSETS, \
- I9XX_COLORS, \
+ I845_COLORS, \
GEN_DEFAULT_PAGE_SIZES, \
GEN_DEFAULT_REGIONS
@@ -341,7 +342,7 @@ static const struct intel_device_info pnv_m_info = {
.dma_mask_size = 36, \
I9XX_PIPE_OFFSETS, \
I9XX_CURSOR_OFFSETS, \
- I965_COLORS, \
+ I9XX_COLORS, \
GEN_DEFAULT_PAGE_SIZES, \
GEN_DEFAULT_REGIONS
@@ -548,7 +549,7 @@ static const struct intel_device_info vlv_info = {
.display.mmio_offset = VLV_DISPLAY_BASE,
I9XX_PIPE_OFFSETS,
I9XX_CURSOR_OFFSETS,
- I965_COLORS,
+ I9XX_COLORS,
GEN_DEFAULT_PAGE_SIZES,
GEN_DEFAULT_REGIONS,
};
@@ -890,7 +891,7 @@ static const struct intel_device_info jsl_info = {
TGL_CURSOR_OFFSETS, \
.has_global_mocs = 1, \
.has_pxp = 1, \
- .display.has_dsb = 0 /* FIXME: LUT load is broken with DSB */
+ .display.has_dsb = 1
static const struct intel_device_info tgl_info = {
GEN12_FEATURES,
@@ -949,7 +950,7 @@ static const struct intel_device_info adl_s_info = {
#define XE_LPD_FEATURES \
.display.abox_mask = GENMASK(1, 0), \
.display.color = { \
- .degamma_lut_size = 128, .gamma_lut_size = 1024, \
+ .degamma_lut_size = 129, .gamma_lut_size = 1024, \
.degamma_lut_tests = DRM_COLOR_LUT_NON_DECREASING | \
DRM_COLOR_LUT_EQUAL_CHANNELS, \
}, \
@@ -1018,6 +1019,7 @@ static const struct intel_device_info adl_p_info = {
.has_3d_pipeline = 1, \
.has_64bit_reloc = 1, \
.has_flat_ccs = 1, \
+ .has_4tile = 1, \
.has_global_mocs = 1, \
.has_gt_uc = 1, \
.has_llc = 1, \
@@ -1062,7 +1064,6 @@ static const struct intel_device_info xehpsdv_info = {
.__runtime.graphics.ip.rel = 55, \
.__runtime.media.ip.rel = 55, \
PLATFORM(INTEL_DG2), \
- .has_4tile = 1, \
.has_64k_pages = 1, \
.has_guc_deprivilege = 1, \
.has_heci_pxp = 1, \
@@ -1118,6 +1119,7 @@ static const struct intel_device_info pvc_info = {
XE_LPD_FEATURES, \
.__runtime.display.ip.ver = 14, \
.display.has_cdclk_crawl = 1, \
+ .display.has_cdclk_squash = 1, \
.__runtime.fbc_mask = BIT(INTEL_FBC_A) | BIT(INTEL_FBC_B)
static const struct intel_gt_definition xelpmp_extra_gt[] = {
@@ -1125,7 +1127,7 @@ static const struct intel_gt_definition xelpmp_extra_gt[] = {
.type = GT_MEDIA,
.name = "Standalone Media GT",
.gsi_offset = MTL_MEDIA_GSI_BASE,
- .engine_mask = BIT(VECS0) | BIT(VCS0) | BIT(VCS2),
+ .engine_mask = BIT(VECS0) | BIT(VCS0) | BIT(VCS2) | BIT(GSC0),
},
{}
};
@@ -1253,7 +1255,7 @@ static void i915_pci_remove(struct pci_dev *pdev)
}
/* is device_id present in comma separated list of ids */
-static bool force_probe(u16 device_id, const char *devices)
+static bool device_id_in_list(u16 device_id, const char *devices, bool negative)
{
char *s, *p, *tok;
bool ret;
@@ -1262,7 +1264,9 @@ static bool force_probe(u16 device_id, const char *devices)
return false;
/* match everything */
- if (strcmp(devices, "*") == 0)
+ if (negative && strcmp(devices, "!*") == 0)
+ return true;
+ if (!negative && strcmp(devices, "*") == 0)
return true;
s = kstrdup(devices, GFP_KERNEL);
@@ -1272,6 +1276,12 @@ static bool force_probe(u16 device_id, const char *devices)
for (p = s, ret = false; (tok = strsep(&p, ",")) != NULL; ) {
u16 val;
+ if (negative && tok[0] == '!')
+ tok++;
+ else if ((negative && tok[0] != '!') ||
+ (!negative && tok[0] == '!'))
+ continue;
+
if (kstrtou16(tok, 16, &val) == 0 && val == device_id) {
ret = true;
break;
@@ -1283,6 +1293,16 @@ static bool force_probe(u16 device_id, const char *devices)
return ret;
}
+static bool id_forced(u16 device_id)
+{
+ return device_id_in_list(device_id, i915_modparams.force_probe, false);
+}
+
+static bool id_blocked(u16 device_id)
+{
+ return device_id_in_list(device_id, i915_modparams.force_probe, true);
+}
+
bool i915_pci_resource_valid(struct pci_dev *pdev, int bar)
{
if (!pci_resource_flags(pdev, bar))
@@ -1308,10 +1328,9 @@ static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
(struct intel_device_info *) ent->driver_data;
int err;
- if (intel_info->require_force_probe &&
- !force_probe(pdev->device, i915_modparams.force_probe)) {
+ if (intel_info->require_force_probe && !id_forced(pdev->device)) {
dev_info(&pdev->dev,
- "Your graphics device %04x is not properly supported by the driver in this\n"
+ "Your graphics device %04x is not properly supported by i915 in this\n"
"kernel version. To force driver probe anyway, use i915.force_probe=%04x\n"
"module parameter or CONFIG_DRM_I915_FORCE_PROBE=%04x configuration option,\n"
"or (recommended) check for kernel updates.\n",
@@ -1319,6 +1338,12 @@ static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
return -ENODEV;
}
+ if (id_blocked(pdev->device)) {
+ dev_info(&pdev->dev, "I915 probe blocked for Device ID %04x.\n",
+ pdev->device);
+ return -ENODEV;
+ }
+
/* Only bind to function 0 of the device. Early generations
* used function 1 as a placeholder for multi-head. This causes
* us confusion instead, especially on the systems where both
diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c
index 125b6ca25a75..824a34ec0b83 100644
--- a/drivers/gpu/drm/i915/i915_perf.c
+++ b/drivers/gpu/drm/i915/i915_perf.c
@@ -1846,8 +1846,7 @@ static u32 *save_restore_register(struct i915_perf_stream *stream, u32 *cs,
for (d = 0; d < dword_count; d++) {
*cs++ = cmd;
*cs++ = i915_mmio_reg_offset(reg) + 4 * d;
- *cs++ = intel_gt_scratch_offset(stream->engine->gt,
- offset) + 4 * d;
+ *cs++ = i915_ggtt_offset(stream->noa_wait) + offset + 4 * d;
*cs++ = 0;
}
@@ -1880,7 +1879,13 @@ static int alloc_noa_wait(struct i915_perf_stream *stream)
MI_PREDICATE_RESULT_2_ENGINE(base) :
MI_PREDICATE_RESULT_1(RENDER_RING_BASE);
- bo = i915_gem_object_create_internal(i915, 4096);
+ /*
+ * gt->scratch was being used to save/restore the GPR registers, but on
+ * MTL the scratch uses stolen lmem. An MI_SRM to this memory region
+ * causes an engine hang. Instead allocate an additional page here to
+ * save/restore GPR registers
+ */
+ bo = i915_gem_object_create_internal(i915, 8192);
if (IS_ERR(bo)) {
drm_err(&i915->drm,
"Failed to allocate NOA wait batchbuffer\n");
@@ -1914,14 +1919,19 @@ retry:
goto err_unpin;
}
+ stream->noa_wait = vma;
+
+#define GPR_SAVE_OFFSET 4096
+#define PREDICATE_SAVE_OFFSET 4160
+
/* Save registers. */
for (i = 0; i < N_CS_GPR; i++)
cs = save_restore_register(
stream, cs, true /* save */, CS_GPR(i),
- INTEL_GT_SCRATCH_FIELD_PERF_CS_GPR + 8 * i, 2);
+ GPR_SAVE_OFFSET + 8 * i, 2);
cs = save_restore_register(
stream, cs, true /* save */, mi_predicate_result,
- INTEL_GT_SCRATCH_FIELD_PERF_PREDICATE_RESULT_1, 1);
+ PREDICATE_SAVE_OFFSET, 1);
/* First timestamp snapshot location. */
ts0 = cs;
@@ -2037,10 +2047,10 @@ retry:
for (i = 0; i < N_CS_GPR; i++)
cs = save_restore_register(
stream, cs, false /* restore */, CS_GPR(i),
- INTEL_GT_SCRATCH_FIELD_PERF_CS_GPR + 8 * i, 2);
+ GPR_SAVE_OFFSET + 8 * i, 2);
cs = save_restore_register(
stream, cs, false /* restore */, mi_predicate_result,
- INTEL_GT_SCRATCH_FIELD_PERF_PREDICATE_RESULT_1, 1);
+ PREDICATE_SAVE_OFFSET, 1);
/* And return to the ring. */
*cs++ = MI_BATCH_BUFFER_END;
@@ -2050,7 +2060,6 @@ retry:
i915_gem_object_flush_map(bo);
__i915_gem_object_release_map(bo);
- stream->noa_wait = vma;
goto out_ww;
err_unpin:
@@ -2263,7 +2272,7 @@ retry:
goto err_add_request;
err = rq->engine->emit_bb_start(rq,
- vma->node.start, 0,
+ i915_vma_offset(vma), 0,
I915_DISPATCH_SECURE);
if (err)
goto err_add_request;
@@ -3131,8 +3140,11 @@ get_sseu_config(struct intel_sseu *out_sseu,
*/
u32 i915_perf_oa_timestamp_frequency(struct drm_i915_private *i915)
{
- /* Wa_18013179988:dg2 */
- if (IS_DG2(i915)) {
+ /*
+ * Wa_18013179988:dg2
+ * Wa_14015846243:mtl
+ */
+ if (IS_DG2(i915) || IS_METEORLAKE(i915)) {
intel_wakeref_t wakeref;
u32 reg, shift;
@@ -4310,6 +4322,17 @@ static const struct i915_range gen12_oa_mux_regs[] = {
{}
};
+/*
+ * Ref: 14010536224:
+ * 0x20cc is repurposed on MTL, so use a separate array for MTL.
+ */
+static const struct i915_range mtl_oa_mux_regs[] = {
+ { .start = 0x0d00, .end = 0x0d04 }, /* RPM_CONFIG[0-1] */
+ { .start = 0x0d0c, .end = 0x0d2c }, /* NOA_CONFIG[0-8] */
+ { .start = 0x9840, .end = 0x9840 }, /* GDT_CHICKEN_BITS */
+ { .start = 0x9884, .end = 0x9888 }, /* NOA_WRITE */
+};
+
static bool gen7_is_valid_b_counter_addr(struct i915_perf *perf, u32 addr)
{
return reg_in_range_table(addr, gen7_oa_b_counters);
@@ -4353,7 +4376,10 @@ static bool xehp_is_valid_b_counter_addr(struct i915_perf *perf, u32 addr)
static bool gen12_is_valid_mux_addr(struct i915_perf *perf, u32 addr)
{
- return reg_in_range_table(addr, gen12_oa_mux_regs);
+ if (IS_METEORLAKE(perf->i915))
+ return reg_in_range_table(addr, mtl_oa_mux_regs);
+ else
+ return reg_in_range_table(addr, gen12_oa_mux_regs);
}
static u32 mask_reg_value(u32 reg, u32 val)
@@ -4750,6 +4776,7 @@ static void oa_init_supported_formats(struct i915_perf *perf)
break;
case INTEL_DG2:
+ case INTEL_METEORLAKE:
oa_format_add(perf, I915_OAR_FORMAT_A32u40_A4u32_B8_C8);
oa_format_add(perf, I915_OA_FORMAT_A24u40_A14u32_B8_C8);
break;
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 916176872544..3b2642397b82 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -118,6 +118,9 @@
#define GU_CNTL _MMIO(0x101010)
#define LMEM_INIT REG_BIT(7)
+#define DRIVERFLR REG_BIT(31)
+#define GU_DEBUG _MMIO(0x101018)
+#define DRIVERFLR_STATUS REG_BIT(31)
#define GEN6_STOLEN_RESERVED _MMIO(0x1082C0)
#define GEN6_STOLEN_RESERVED_ADDR_MASK (0xFFF << 20)
@@ -1713,6 +1716,20 @@
#define PALETTE_RED_MASK REG_GENMASK(23, 16)
#define PALETTE_GREEN_MASK REG_GENMASK(15, 8)
#define PALETTE_BLUE_MASK REG_GENMASK(7, 0)
+/* pre-i965 10bit interpolated mode ldw */
+#define PALETTE_10BIT_RED_LDW_MASK REG_GENMASK(23, 16)
+#define PALETTE_10BIT_GREEN_LDW_MASK REG_GENMASK(15, 8)
+#define PALETTE_10BIT_BLUE_LDW_MASK REG_GENMASK(7, 0)
+/* pre-i965 10bit interpolated mode udw */
+#define PALETTE_10BIT_RED_EXP_MASK REG_GENMASK(23, 22)
+#define PALETTE_10BIT_RED_MANT_MASK REG_GENMASK(21, 18)
+#define PALETTE_10BIT_RED_UDW_MASK REG_GENMASK(17, 16)
+#define PALETTE_10BIT_GREEN_EXP_MASK REG_GENMASK(15, 14)
+#define PALETTE_10BIT_GREEN_MANT_MASK REG_GENMASK(13, 10)
+#define PALETTE_10BIT_GREEN_UDW_MASK REG_GENMASK(9, 8)
+#define PALETTE_10BIT_BLUE_EXP_MASK REG_GENMASK(7, 6)
+#define PALETTE_10BIT_BLUE_MANT_MASK REG_GENMASK(5, 2)
+#define PALETTE_10BIT_BLUE_UDW_MASK REG_GENMASK(1, 0)
#define PALETTE(pipe, i) _MMIO(DISPLAY_MMIO_BASE(dev_priv) + \
_PICK((pipe), _PALETTE_A, \
_PALETTE_B, _CHV_PALETTE_C) + \
@@ -2575,46 +2592,6 @@
#define SDVO_PIPE_SEL_MASK_CHV (3 << 24)
#define SDVO_PIPE_SEL_CHV(pipe) ((pipe) << 24)
-
-/* DVO port control */
-#define _DVOA 0x61120
-#define DVOA _MMIO(_DVOA)
-#define _DVOB 0x61140
-#define DVOB _MMIO(_DVOB)
-#define _DVOC 0x61160
-#define DVOC _MMIO(_DVOC)
-#define DVO_ENABLE (1 << 31)
-#define DVO_PIPE_SEL_SHIFT 30
-#define DVO_PIPE_SEL_MASK (1 << 30)
-#define DVO_PIPE_SEL(pipe) ((pipe) << 30)
-#define DVO_PIPE_STALL_UNUSED (0 << 28)
-#define DVO_PIPE_STALL (1 << 28)
-#define DVO_PIPE_STALL_TV (2 << 28)
-#define DVO_PIPE_STALL_MASK (3 << 28)
-#define DVO_USE_VGA_SYNC (1 << 15)
-#define DVO_DATA_ORDER_I740 (0 << 14)
-#define DVO_DATA_ORDER_FP (1 << 14)
-#define DVO_VSYNC_DISABLE (1 << 11)
-#define DVO_HSYNC_DISABLE (1 << 10)
-#define DVO_VSYNC_TRISTATE (1 << 9)
-#define DVO_HSYNC_TRISTATE (1 << 8)
-#define DVO_BORDER_ENABLE (1 << 7)
-#define DVO_DATA_ORDER_GBRG (1 << 6)
-#define DVO_DATA_ORDER_RGGB (0 << 6)
-#define DVO_DATA_ORDER_GBRG_ERRATA (0 << 6)
-#define DVO_DATA_ORDER_RGGB_ERRATA (1 << 6)
-#define DVO_VSYNC_ACTIVE_HIGH (1 << 4)
-#define DVO_HSYNC_ACTIVE_HIGH (1 << 3)
-#define DVO_BLANK_ACTIVE_HIGH (1 << 2)
-#define DVO_OUTPUT_CSTATE_PIXELS (1 << 1) /* SDG only */
-#define DVO_OUTPUT_SOURCE_SIZE_PIXELS (1 << 0) /* SDG only */
-#define DVO_PRESERVE_MASK (0x7 << 24)
-#define DVOA_SRCDIM _MMIO(0x61124)
-#define DVOB_SRCDIM _MMIO(0x61144)
-#define DVOC_SRCDIM _MMIO(0x61164)
-#define DVO_SRCDIM_HORIZONTAL_SHIFT 12
-#define DVO_SRCDIM_VERTICAL_SHIFT 0
-
/* LVDS port control */
#define LVDS _MMIO(0x61180)
/*
@@ -3646,7 +3623,7 @@
#define _PIPEAGCMAX 0x70010
#define _PIPEBGCMAX 0x71010
-#define PIPEGCMAX(pipe, i) _MMIO_PIPE2(pipe, _PIPEAGCMAX + (i) * 4)
+#define PIPEGCMAX(pipe, i) _MMIO_PIPE2(pipe, _PIPEAGCMAX + (i) * 4) /* u1.16 */
#define _PIPE_ARB_CTL_A 0x70028 /* icl+ */
#define PIPE_ARB_CTL(pipe) _MMIO_PIPE2(pipe, _PIPE_ARB_CTL_A)
@@ -5330,19 +5307,20 @@
#define _PREC_PIPEAGCMAX 0x4d000
#define _PREC_PIPEBGCMAX 0x4d010
-#define PREC_PIPEGCMAX(pipe, i) _MMIO(_PIPE(pipe, _PIPEAGCMAX, _PIPEBGCMAX) + (i) * 4)
+#define PREC_PIPEGCMAX(pipe, i) _MMIO(_PIPE(pipe, _PIPEAGCMAX, _PIPEBGCMAX) + (i) * 4) /* u1.16 */
#define _GAMMA_MODE_A 0x4a480
#define _GAMMA_MODE_B 0x4ac80
#define GAMMA_MODE(pipe) _MMIO_PIPE(pipe, _GAMMA_MODE_A, _GAMMA_MODE_B)
-#define PRE_CSC_GAMMA_ENABLE (1 << 31)
-#define POST_CSC_GAMMA_ENABLE (1 << 30)
-#define GAMMA_MODE_MODE_MASK (3 << 0)
-#define GAMMA_MODE_MODE_8BIT (0 << 0)
-#define GAMMA_MODE_MODE_10BIT (1 << 0)
-#define GAMMA_MODE_MODE_12BIT (2 << 0)
-#define GAMMA_MODE_MODE_SPLIT (3 << 0) /* ivb-bdw */
-#define GAMMA_MODE_MODE_12BIT_MULTI_SEGMENTED (3 << 0) /* icl + */
+#define PRE_CSC_GAMMA_ENABLE REG_BIT(31) /* icl+ */
+#define POST_CSC_GAMMA_ENABLE REG_BIT(30) /* icl+ */
+#define PALETTE_ANTICOL_DISABLE REG_BIT(15) /* skl+ */
+#define GAMMA_MODE_MODE_MASK REG_GENMASK(1, 0)
+#define GAMMA_MODE_MODE_8BIT REG_FIELD_PREP(GAMMA_MODE_MODE_MASK, 0)
+#define GAMMA_MODE_MODE_10BIT REG_FIELD_PREP(GAMMA_MODE_MODE_MASK, 1)
+#define GAMMA_MODE_MODE_12BIT REG_FIELD_PREP(GAMMA_MODE_MODE_MASK, 2)
+#define GAMMA_MODE_MODE_SPLIT REG_FIELD_PREP(GAMMA_MODE_MODE_MASK, 3) /* ivb-bdw */
+#define GAMMA_MODE_MODE_12BIT_MULTI_SEG REG_FIELD_PREP(GAMMA_MODE_MODE_MASK, 3) /* icl-tgl */
/* Display Internal Timeout Register */
#define RM_TIMEOUT _MMIO(0x42060)
@@ -5759,6 +5737,7 @@
#define RESET_PCH_HANDSHAKE_ENABLE REG_BIT(4)
#define GEN8_CHICKEN_DCPR_1 _MMIO(0x46430)
+#define LATENCY_REPORTING_REMOVED_PIPE_D REG_BIT(31)
#define SKL_SELECT_ALTERNATE_DC_EXIT REG_BIT(30)
#define LATENCY_REPORTING_REMOVED_PIPE_C REG_BIT(25)
#define LATENCY_REPORTING_REMOVED_PIPE_B REG_BIT(24)
@@ -6269,6 +6248,7 @@
#define CHASSIS_CLK_REQ_DURATION_MASK (0xf << 8)
#define CHASSIS_CLK_REQ_DURATION(x) ((x) << 8)
#define SBCLK_RUN_REFCLK_DIS (1 << 7)
+#define ICP_SECOND_PPS_IO_SELECT REG_BIT(2)
#define SPT_PWM_GRANULARITY (1 << 0)
#define SOUTH_CHICKEN2 _MMIO(0xc2004)
#define FDI_MPHY_IOSFSB_RESET_STATUS (1 << 13)
@@ -7557,11 +7537,10 @@ enum skl_power_gate {
#define _PAL_PREC_INDEX_A 0x4A400
#define _PAL_PREC_INDEX_B 0x4AC00
#define _PAL_PREC_INDEX_C 0x4B400
-#define PAL_PREC_10_12_BIT (0 << 31)
-#define PAL_PREC_SPLIT_MODE (1 << 31)
-#define PAL_PREC_AUTO_INCREMENT (1 << 15)
-#define PAL_PREC_INDEX_VALUE_MASK (0x3ff << 0)
-#define PAL_PREC_INDEX_VALUE(x) ((x) << 0)
+#define PAL_PREC_SPLIT_MODE REG_BIT(31)
+#define PAL_PREC_AUTO_INCREMENT REG_BIT(15)
+#define PAL_PREC_INDEX_VALUE_MASK REG_GENMASK(9, 0)
+#define PAL_PREC_INDEX_VALUE(x) REG_FIELD_PREP(PAL_PREC_INDEX_VALUE_MASK, (x))
#define _PAL_PREC_DATA_A 0x4A404
#define _PAL_PREC_DATA_B 0x4AC04
#define _PAL_PREC_DATA_C 0x4B404
@@ -7578,14 +7557,16 @@ enum skl_power_gate {
#define PREC_PAL_INDEX(pipe) _MMIO_PIPE(pipe, _PAL_PREC_INDEX_A, _PAL_PREC_INDEX_B)
#define PREC_PAL_DATA(pipe) _MMIO_PIPE(pipe, _PAL_PREC_DATA_A, _PAL_PREC_DATA_B)
-#define PREC_PAL_GC_MAX(pipe, i) _MMIO(_PIPE(pipe, _PAL_PREC_GC_MAX_A, _PAL_PREC_GC_MAX_B) + (i) * 4)
-#define PREC_PAL_EXT_GC_MAX(pipe, i) _MMIO(_PIPE(pipe, _PAL_PREC_EXT_GC_MAX_A, _PAL_PREC_EXT_GC_MAX_B) + (i) * 4)
-#define PREC_PAL_EXT2_GC_MAX(pipe, i) _MMIO(_PIPE(pipe, _PAL_PREC_EXT2_GC_MAX_A, _PAL_PREC_EXT2_GC_MAX_B) + (i) * 4)
+#define PREC_PAL_GC_MAX(pipe, i) _MMIO(_PIPE(pipe, _PAL_PREC_GC_MAX_A, _PAL_PREC_GC_MAX_B) + (i) * 4) /* u1.16 */
+#define PREC_PAL_EXT_GC_MAX(pipe, i) _MMIO(_PIPE(pipe, _PAL_PREC_EXT_GC_MAX_A, _PAL_PREC_EXT_GC_MAX_B) + (i) * 4) /* u3.16 */
+#define PREC_PAL_EXT2_GC_MAX(pipe, i) _MMIO(_PIPE(pipe, _PAL_PREC_EXT2_GC_MAX_A, _PAL_PREC_EXT2_GC_MAX_B) + (i) * 4) /* glk+, u3.16 */
#define _PRE_CSC_GAMC_INDEX_A 0x4A484
#define _PRE_CSC_GAMC_INDEX_B 0x4AC84
#define _PRE_CSC_GAMC_INDEX_C 0x4B484
-#define PRE_CSC_GAMC_AUTO_INCREMENT (1 << 10)
+#define PRE_CSC_GAMC_AUTO_INCREMENT REG_BIT(10)
+#define PRE_CSC_GAMC_INDEX_VALUE_MASK REG_GENMASK(7, 0)
+#define PRE_CSC_GAMC_INDEX_VALUE(x) REG_FIELD_PREP(PRE_CSC_GAMC_INDEX_VALUE_MASK, (x))
#define _PRE_CSC_GAMC_DATA_A 0x4A488
#define _PRE_CSC_GAMC_DATA_B 0x4AC88
#define _PRE_CSC_GAMC_DATA_C 0x4B488
@@ -7596,8 +7577,9 @@ enum skl_power_gate {
/* ICL Multi segmented gamma */
#define _PAL_PREC_MULTI_SEG_INDEX_A 0x4A408
#define _PAL_PREC_MULTI_SEG_INDEX_B 0x4AC08
-#define PAL_PREC_MULTI_SEGMENT_AUTO_INCREMENT REG_BIT(15)
-#define PAL_PREC_MULTI_SEGMENT_INDEX_VALUE_MASK REG_GENMASK(4, 0)
+#define PAL_PREC_MULTI_SEG_AUTO_INCREMENT REG_BIT(15)
+#define PAL_PREC_MULTI_SEG_INDEX_VALUE_MASK REG_GENMASK(4, 0)
+#define PAL_PREC_MULTI_SEG_INDEX_VALUE(x) REG_FIELD_PREP(PAL_PREC_MULTI_SEG_INDEX_VALUE_MASK, (x))
#define _PAL_PREC_MULTI_SEG_DATA_A 0x4A40C
#define _PAL_PREC_MULTI_SEG_DATA_B 0x4AC0C
@@ -8124,7 +8106,7 @@ enum skl_power_gate {
#define DSB_TAIL(pipe, id) _MMIO(DSBSL_INSTANCE(pipe, id) + 0x4)
#define DSB_CTRL(pipe, id) _MMIO(DSBSL_INSTANCE(pipe, id) + 0x8)
#define DSB_ENABLE (1 << 31)
-#define DSB_STATUS (1 << 0)
+#define DSB_STATUS_BUSY (1 << 0)
#define CLKREQ_POLICY _MMIO(0x101038)
#define CLKREQ_POLICY_MEM_UP_OVRD REG_BIT(1)
@@ -8132,10 +8114,6 @@ enum skl_power_gate {
#define CLKGATE_DIS_MISC _MMIO(0x46534)
#define CLKGATE_DIS_MISC_DMASC_GATING_DIS REG_BIT(21)
-#define GEN12_CULLBIT1 _MMIO(0x6100)
-#define GEN12_CULLBIT2 _MMIO(0x7030)
-#define GEN12_STATE_ACK_DEBUG _MMIO(0x20BC)
-
#define _MTL_CLKGATE_DIS_TRANS_A 0x604E8
#define _MTL_CLKGATE_DIS_TRANS_B 0x614E8
#define MTL_CLKGATE_DIS_TRANS(trans) _MMIO_TRANS2(trans, _MTL_CLKGATE_DIS_TRANS_A)
diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c
index f949a9495758..7503dcb9043b 100644
--- a/drivers/gpu/drm/i915/i915_request.c
+++ b/drivers/gpu/drm/i915/i915_request.c
@@ -43,6 +43,7 @@
#include "gt/intel_rps.h"
#include "i915_active.h"
+#include "i915_config.h"
#include "i915_deps.h"
#include "i915_driver.h"
#include "i915_drv.h"
diff --git a/drivers/gpu/drm/i915/i915_scatterlist.c b/drivers/gpu/drm/i915/i915_scatterlist.c
index 114e5e39aa72..7c7a86921b1c 100644
--- a/drivers/gpu/drm/i915/i915_scatterlist.c
+++ b/drivers/gpu/drm/i915/i915_scatterlist.c
@@ -96,6 +96,13 @@ struct i915_refct_sgt *i915_rsgt_from_mm_node(const struct drm_mm_node *node,
i915_refct_sgt_init(rsgt, node->size << PAGE_SHIFT);
st = &rsgt->table;
+ /* restricted by sg_alloc_table */
+ if (WARN_ON(overflows_type(DIV_ROUND_UP_ULL(node->size, segment_pages),
+ unsigned int))) {
+ i915_refct_sgt_put(rsgt);
+ return ERR_PTR(-E2BIG);
+ }
+
if (sg_alloc_table(st, DIV_ROUND_UP_ULL(node->size, segment_pages),
GFP_KERNEL)) {
i915_refct_sgt_put(rsgt);
@@ -177,6 +184,12 @@ struct i915_refct_sgt *i915_rsgt_from_buddy_resource(struct ttm_resource *res,
i915_refct_sgt_init(rsgt, size);
st = &rsgt->table;
+ /* restricted by sg_alloc_table */
+ if (WARN_ON(overflows_type(PFN_UP(res->size), unsigned int))) {
+ i915_refct_sgt_put(rsgt);
+ return ERR_PTR(-E2BIG);
+ }
+
if (sg_alloc_table(st, PFN_UP(res->size), GFP_KERNEL)) {
i915_refct_sgt_put(rsgt);
return ERR_PTR(-ENOMEM);
diff --git a/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c b/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c
index 7e611476c7a4..a72698a2dbc8 100644
--- a/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c
+++ b/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c
@@ -5,8 +5,8 @@
#include <linux/slab.h>
-#include <drm/ttm/ttm_bo_driver.h>
#include <drm/ttm/ttm_placement.h>
+#include <drm/ttm/ttm_bo.h>
#include <drm/drm_buddy.h>
diff --git a/drivers/gpu/drm/i915/i915_utils.h b/drivers/gpu/drm/i915/i915_utils.h
index 67a66d4d5c70..2c430c0c3bad 100644
--- a/drivers/gpu/drm/i915/i915_utils.h
+++ b/drivers/gpu/drm/i915/i915_utils.h
@@ -145,8 +145,6 @@ bool i915_error_injected(void);
#define page_pack_bits(ptr, bits) ptr_pack_bits(ptr, bits, PAGE_SHIFT)
#define page_unpack_bits(ptr, bits) ptr_unpack_bits(ptr, bits, PAGE_SHIFT)
-#define struct_member(T, member) (((T *)0)->member)
-
#define fetch_and_zero(ptr) ({ \
typeof(*ptr) __T = *(ptr); \
*(ptr) = (typeof(*ptr))0; \
@@ -166,7 +164,7 @@ static __always_inline ptrdiff_t ptrdiff(const void *a, const void *b)
*/
#define container_of_user(ptr, type, member) ({ \
void __user *__mptr = (void __user *)(ptr); \
- BUILD_BUG_ON_MSG(!__same_type(*(ptr), struct_member(type, member)) && \
+ BUILD_BUG_ON_MSG(!__same_type(*(ptr), typeof_member(type, member)) && \
!__same_type(*(ptr), void), \
"pointer type mismatch in container_of()"); \
((type __user *)(__mptr - offsetof(type, member))); })
diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c
index 135390d975b6..f51fd9fd4c89 100644
--- a/drivers/gpu/drm/i915/i915_vma.c
+++ b/drivers/gpu/drm/i915/i915_vma.c
@@ -26,6 +26,7 @@
#include <linux/dma-fence-array.h>
#include <drm/drm_gem.h>
+#include "display/intel_display.h"
#include "display/intel_frontbuffer.h"
#include "gem/i915_gem_lmem.h"
#include "gem/i915_gem_tiling.h"
@@ -418,8 +419,8 @@ i915_vma_resource_init_from_vma(struct i915_vma_resource *vma_res,
i915_vma_resource_init(vma_res, vma->vm, vma->pages, &vma->page_sizes,
obj->mm.rsgt, i915_gem_object_is_readonly(obj),
i915_gem_object_is_lmem(obj), obj->mm.region,
- vma->ops, vma->private, vma->node.start,
- vma->node.size, vma->size);
+ vma->ops, vma->private, __i915_vma_offset(vma),
+ __i915_vma_size(vma), vma->size, vma->guard);
}
/**
@@ -447,7 +448,7 @@ int i915_vma_bind(struct i915_vma *vma,
lockdep_assert_held(&vma->vm->mutex);
GEM_BUG_ON(!drm_mm_node_allocated(&vma->node));
- GEM_BUG_ON(vma->size > vma->node.size);
+ GEM_BUG_ON(vma->size > i915_vma_size(vma));
if (GEM_DEBUG_WARN_ON(range_overflows(vma->node.start,
vma->node.size,
@@ -569,8 +570,8 @@ void __iomem *i915_vma_pin_iomap(struct i915_vma *vma)
vma->obj->base.size);
} else if (i915_vma_is_map_and_fenceable(vma)) {
ptr = io_mapping_map_wc(&i915_vm_to_ggtt(vma->vm)->iomap,
- vma->node.start,
- vma->node.size);
+ i915_vma_offset(vma),
+ i915_vma_size(vma));
} else {
ptr = (void __iomem *)
i915_gem_object_pin_map(vma->obj, I915_MAP_WC);
@@ -659,22 +660,26 @@ bool i915_vma_misplaced(const struct i915_vma *vma,
if (test_bit(I915_VMA_ERROR_BIT, __i915_vma_flags(vma)))
return true;
- if (vma->node.size < size)
+ if (i915_vma_size(vma) < size)
return true;
GEM_BUG_ON(alignment && !is_power_of_2(alignment));
- if (alignment && !IS_ALIGNED(vma->node.start, alignment))
+ if (alignment && !IS_ALIGNED(i915_vma_offset(vma), alignment))
return true;
if (flags & PIN_MAPPABLE && !i915_vma_is_map_and_fenceable(vma))
return true;
if (flags & PIN_OFFSET_BIAS &&
- vma->node.start < (flags & PIN_OFFSET_MASK))
+ i915_vma_offset(vma) < (flags & PIN_OFFSET_MASK))
return true;
if (flags & PIN_OFFSET_FIXED &&
- vma->node.start != (flags & PIN_OFFSET_MASK))
+ i915_vma_offset(vma) != (flags & PIN_OFFSET_MASK))
+ return true;
+
+ if (flags & PIN_OFFSET_GUARD &&
+ vma->guard < (flags & PIN_OFFSET_MASK))
return true;
return false;
@@ -687,10 +692,11 @@ void __i915_vma_set_map_and_fenceable(struct i915_vma *vma)
GEM_BUG_ON(!i915_vma_is_ggtt(vma));
GEM_BUG_ON(!vma->fence_size);
- fenceable = (vma->node.size >= vma->fence_size &&
- IS_ALIGNED(vma->node.start, vma->fence_alignment));
+ fenceable = (i915_vma_size(vma) >= vma->fence_size &&
+ IS_ALIGNED(i915_vma_offset(vma), vma->fence_alignment));
- mappable = vma->node.start + vma->fence_size <= i915_vm_to_ggtt(vma->vm)->mappable_end;
+ mappable = i915_ggtt_offset(vma) + vma->fence_size <=
+ i915_vm_to_ggtt(vma->vm)->mappable_end;
if (mappable && fenceable)
set_bit(I915_VMA_CAN_FENCE_BIT, __i915_vma_flags(vma));
@@ -748,15 +754,16 @@ static int
i915_vma_insert(struct i915_vma *vma, struct i915_gem_ww_ctx *ww,
u64 size, u64 alignment, u64 flags)
{
- unsigned long color;
+ unsigned long color, guard;
u64 start, end;
int ret;
GEM_BUG_ON(i915_vma_is_bound(vma, I915_VMA_GLOBAL_BIND | I915_VMA_LOCAL_BIND));
GEM_BUG_ON(drm_mm_node_allocated(&vma->node));
+ GEM_BUG_ON(hweight64(flags & (PIN_OFFSET_GUARD | PIN_OFFSET_FIXED | PIN_OFFSET_BIAS)) > 1);
size = max(size, vma->size);
- alignment = max(alignment, vma->display_alignment);
+ alignment = max_t(typeof(alignment), alignment, vma->display_alignment);
if (flags & PIN_MAPPABLE) {
size = max_t(typeof(size), size, vma->fence_size);
alignment = max_t(typeof(alignment),
@@ -767,6 +774,18 @@ i915_vma_insert(struct i915_vma *vma, struct i915_gem_ww_ctx *ww,
GEM_BUG_ON(!IS_ALIGNED(alignment, I915_GTT_MIN_ALIGNMENT));
GEM_BUG_ON(!is_power_of_2(alignment));
+ guard = vma->guard; /* retain guard across rebinds */
+ if (flags & PIN_OFFSET_GUARD) {
+ GEM_BUG_ON(overflows_type(flags & PIN_OFFSET_MASK, u32));
+ guard = max_t(u32, guard, flags & PIN_OFFSET_MASK);
+ }
+ /*
+ * As we align the node upon insertion, but the hardware gets
+ * node.start + guard, the easiest way to make that work is
+ * to make the guard a multiple of the alignment size.
+ */
+ guard = ALIGN(guard, alignment);
+
start = flags & PIN_OFFSET_BIAS ? flags & PIN_OFFSET_MASK : 0;
GEM_BUG_ON(!IS_ALIGNED(start, I915_GTT_PAGE_SIZE));
@@ -779,11 +798,12 @@ i915_vma_insert(struct i915_vma *vma, struct i915_gem_ww_ctx *ww,
alignment = max(alignment, i915_vm_obj_min_alignment(vma->vm, vma->obj));
- /* If binding the object/GGTT view requires more space than the entire
+ /*
+ * If binding the object/GGTT view requires more space than the entire
* aperture has, reject it early before evicting everything in a vain
* attempt to find space.
*/
- if (size > end) {
+ if (size > end - 2 * guard) {
drm_dbg(&to_i915(vma->obj->base.dev)->drm,
"Attempting to bind an object larger than the aperture: request=%llu > %s aperture=%llu\n",
size, flags & PIN_MAPPABLE ? "mappable" : "total", end);
@@ -800,13 +820,23 @@ i915_vma_insert(struct i915_vma *vma, struct i915_gem_ww_ctx *ww,
if (!IS_ALIGNED(offset, alignment) ||
range_overflows(offset, size, end))
return -EINVAL;
+ /*
+ * The caller knows not of the guard added by others and
+ * requests for the offset of the start of its buffer
+ * to be fixed, which may not be the same as the position
+ * of the vma->node due to the guard pages.
+ */
+ if (offset < guard || offset + size > end - guard)
+ return -ENOSPC;
ret = i915_gem_gtt_reserve(vma->vm, ww, &vma->node,
- size, offset, color,
- flags);
+ size + 2 * guard,
+ offset - guard,
+ color, flags);
if (ret)
return ret;
} else {
+ size += 2 * guard;
/*
* We only support huge gtt pages through the 48b PPGTT,
* however we also don't want to force any alignment for
@@ -854,6 +884,7 @@ i915_vma_insert(struct i915_vma *vma, struct i915_gem_ww_ctx *ww,
GEM_BUG_ON(!i915_gem_valid_gtt_space(vma, color));
list_move_tail(&vma->vm_link, &vma->vm->bound_list);
+ vma->guard = guard;
return 0;
}
@@ -906,7 +937,7 @@ rotate_pages(struct drm_i915_gem_object *obj, unsigned int offset,
struct sg_table *st, struct scatterlist *sg)
{
unsigned int column, row;
- unsigned int src_idx;
+ pgoff_t src_idx;
for (column = 0; column < width; column++) {
unsigned int left;
@@ -1012,7 +1043,7 @@ add_padding_pages(unsigned int count,
static struct scatterlist *
remap_tiled_color_plane_pages(struct drm_i915_gem_object *obj,
- unsigned int offset, unsigned int alignment_pad,
+ unsigned long offset, unsigned int alignment_pad,
unsigned int width, unsigned int height,
unsigned int src_stride, unsigned int dst_stride,
struct sg_table *st, struct scatterlist *sg,
@@ -1071,7 +1102,7 @@ remap_tiled_color_plane_pages(struct drm_i915_gem_object *obj,
static struct scatterlist *
remap_contiguous_pages(struct drm_i915_gem_object *obj,
- unsigned int obj_offset,
+ pgoff_t obj_offset,
unsigned int count,
struct sg_table *st, struct scatterlist *sg)
{
@@ -1104,7 +1135,7 @@ remap_contiguous_pages(struct drm_i915_gem_object *obj,
static struct scatterlist *
remap_linear_color_plane_pages(struct drm_i915_gem_object *obj,
- unsigned int obj_offset, unsigned int alignment_pad,
+ pgoff_t obj_offset, unsigned int alignment_pad,
unsigned int size,
struct sg_table *st, struct scatterlist *sg,
unsigned int *gtt_offset)
@@ -1544,6 +1575,8 @@ static int __i915_ggtt_pin(struct i915_vma *vma, struct i915_gem_ww_ctx *ww,
u32 align, unsigned int flags)
{
struct i915_address_space *vm = vma->vm;
+ struct intel_gt *gt;
+ struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
int err;
do {
@@ -1559,7 +1592,8 @@ static int __i915_ggtt_pin(struct i915_vma *vma, struct i915_gem_ww_ctx *ww,
}
/* Unlike i915_vma_pin, we don't take no for an answer! */
- flush_idle_contexts(vm->gt);
+ list_for_each_entry(gt, &ggtt->gt_list, ggtt_link)
+ flush_idle_contexts(gt);
if (mutex_lock_interruptible(&vm->mutex) == 0) {
/*
* We pass NULL ww here, as we don't want to unbind
diff --git a/drivers/gpu/drm/i915/i915_vma.h b/drivers/gpu/drm/i915/i915_vma.h
index 0757977a489b..ed5c9d682a1b 100644
--- a/drivers/gpu/drm/i915/i915_vma.h
+++ b/drivers/gpu/drm/i915/i915_vma.h
@@ -125,13 +125,59 @@ static inline bool i915_vma_is_closed(const struct i915_vma *vma)
return !list_empty(&vma->closed_link);
}
+/* Internal use only. */
+static inline u64 __i915_vma_size(const struct i915_vma *vma)
+{
+ return vma->node.size - 2 * vma->guard;
+}
+
+/**
+ * i915_vma_offset - Obtain the va range size of the vma
+ * @vma: The vma
+ *
+ * GPU virtual address space may be allocated with padding. This
+ * function returns the effective virtual address range size
+ * with padding subtracted.
+ *
+ * Return: The effective virtual address range size.
+ */
+static inline u64 i915_vma_size(const struct i915_vma *vma)
+{
+ GEM_BUG_ON(!drm_mm_node_allocated(&vma->node));
+ return __i915_vma_size(vma);
+}
+
+/* Internal use only. */
+static inline u64 __i915_vma_offset(const struct i915_vma *vma)
+{
+ /* The actual start of the vma->pages is after the guard pages. */
+ return vma->node.start + vma->guard;
+}
+
+/**
+ * i915_vma_offset - Obtain the va offset of the vma
+ * @vma: The vma
+ *
+ * GPU virtual address space may be allocated with padding. This
+ * function returns the effective virtual address offset the gpu
+ * should use to access the bound data.
+ *
+ * Return: The effective virtual address offset.
+ */
+static inline u64 i915_vma_offset(const struct i915_vma *vma)
+{
+ GEM_BUG_ON(!drm_mm_node_allocated(&vma->node));
+ return __i915_vma_offset(vma);
+}
+
static inline u32 i915_ggtt_offset(const struct i915_vma *vma)
{
GEM_BUG_ON(!i915_vma_is_ggtt(vma));
GEM_BUG_ON(!drm_mm_node_allocated(&vma->node));
- GEM_BUG_ON(upper_32_bits(vma->node.start));
- GEM_BUG_ON(upper_32_bits(vma->node.start + vma->node.size - 1));
- return lower_32_bits(vma->node.start);
+ GEM_BUG_ON(upper_32_bits(i915_vma_offset(vma)));
+ GEM_BUG_ON(upper_32_bits(i915_vma_offset(vma) +
+ i915_vma_size(vma) - 1));
+ return lower_32_bits(i915_vma_offset(vma));
}
static inline u32 i915_ggtt_pin_bias(struct i915_vma *vma)
diff --git a/drivers/gpu/drm/i915/i915_vma_resource.c b/drivers/gpu/drm/i915/i915_vma_resource.c
index de1342dbfa12..6ba7a7feceba 100644
--- a/drivers/gpu/drm/i915/i915_vma_resource.c
+++ b/drivers/gpu/drm/i915/i915_vma_resource.c
@@ -34,8 +34,8 @@ static struct kmem_cache *slab_vma_resources;
* and removal of fences increases as O(ln(pending_unbinds)) instead of
* O(1) for a single fence without interval tree.
*/
-#define VMA_RES_START(_node) ((_node)->start)
-#define VMA_RES_LAST(_node) ((_node)->start + (_node)->node_size - 1)
+#define VMA_RES_START(_node) ((_node)->start - (_node)->guard)
+#define VMA_RES_LAST(_node) ((_node)->start + (_node)->node_size + (_node)->guard - 1)
INTERVAL_TREE_DEFINE(struct i915_vma_resource, rb,
u64, __subtree_last,
VMA_RES_START, VMA_RES_LAST, static, vma_res_itree);
diff --git a/drivers/gpu/drm/i915/i915_vma_resource.h b/drivers/gpu/drm/i915/i915_vma_resource.h
index 06923d1816e7..c1864e3d0b43 100644
--- a/drivers/gpu/drm/i915/i915_vma_resource.h
+++ b/drivers/gpu/drm/i915/i915_vma_resource.h
@@ -52,9 +52,12 @@ struct i915_page_sizes {
* @mr: The memory region of the object pointed to by the vma.
* @ops: Pointer to the backend i915_vma_ops.
* @private: Bind backend private info.
- * @start: Offset into the address space of bind range start.
- * @node_size: Size of the allocated range manager node.
+ * @start: Offset into the address space of bind range start. Note that
+ * this is after any padding that might have been allocated.
+ * @node_size: Size of the allocated range manager node with padding
+ * subtracted.
* @vma_size: Bind size.
+ * @guard: The size of guard area preceding and trailing the bind.
* @page_sizes_gtt: Resulting page sizes from the bind operation.
* @bound_flags: Flags indicating binding status.
* @allocated: Backend private data. TODO: Should move into @private.
@@ -113,6 +116,7 @@ struct i915_vma_resource {
u64 start;
u64 node_size;
u64 vma_size;
+ u32 guard;
u32 page_sizes_gtt;
u32 bound_flags;
@@ -174,9 +178,10 @@ static inline void i915_vma_resource_put(struct i915_vma_resource *vma_res)
* @mr: The memory region of the object the vma points to.
* @ops: The backend ops.
* @private: Bind backend private info.
- * @start: Offset into the address space of bind range start.
- * @node_size: Size of the allocated range manager node.
+ * @start: Offset into the address space of bind range start after padding.
+ * @node_size: Size of the allocated range manager node minus padding.
* @size: Bind size.
+ * @guard: The size of the guard area preceding and trailing the bind.
*
* Initializes a vma resource allocated using i915_vma_resource_alloc().
* The reason for having separate allocate and initialize function is that
@@ -195,7 +200,8 @@ static inline void i915_vma_resource_init(struct i915_vma_resource *vma_res,
void *private,
u64 start,
u64 node_size,
- u64 size)
+ u64 size,
+ u32 guard)
{
__i915_vma_resource_init(vma_res);
vma_res->vm = vm;
@@ -213,6 +219,7 @@ static inline void i915_vma_resource_init(struct i915_vma_resource *vma_res,
vma_res->start = start;
vma_res->node_size = node_size;
vma_res->vma_size = size;
+ vma_res->guard = guard;
}
static inline void i915_vma_resource_fini(struct i915_vma_resource *vma_res)
diff --git a/drivers/gpu/drm/i915/i915_vma_types.h b/drivers/gpu/drm/i915/i915_vma_types.h
index ec0f6c9f57d0..77fda2244d16 100644
--- a/drivers/gpu/drm/i915/i915_vma_types.h
+++ b/drivers/gpu/drm/i915/i915_vma_types.h
@@ -197,14 +197,15 @@ struct i915_vma {
struct i915_fence_reg *fence;
u64 size;
- u64 display_alignment;
struct i915_page_sizes page_sizes;
/* mmap-offset associated with fencing for this vma */
struct i915_mmap_offset *mmo;
+ u32 guard; /* padding allocated around vma->pages within the node */
u32 fence_size;
u32 fence_alignment;
+ u32 display_alignment;
/**
* Count of the number of times this vma has been opened by different
diff --git a/drivers/gpu/drm/i915/intel_device_info.c b/drivers/gpu/drm/i915/intel_device_info.c
index 849baf6c3b3c..98769e5f2c3d 100644
--- a/drivers/gpu/drm/i915/intel_device_info.c
+++ b/drivers/gpu/drm/i915/intel_device_info.c
@@ -29,6 +29,7 @@
#include "display/intel_cdclk.h"
#include "display/intel_de.h"
+#include "display/intel_display.h"
#include "gt/intel_gt_regs.h"
#include "i915_drv.h"
#include "i915_reg.h"
@@ -343,6 +344,12 @@ static void intel_ipver_early_init(struct drm_i915_private *i915)
ip_ver_read(i915, i915_mmio_reg_offset(GMD_ID_GRAPHICS),
&runtime->graphics.ip);
+ /* Wa_22012778468 */
+ if (runtime->graphics.ip.ver == 0x0 &&
+ INTEL_INFO(i915)->platform == INTEL_METEORLAKE) {
+ RUNTIME_INFO(i915)->graphics.ip.ver = 12;
+ RUNTIME_INFO(i915)->graphics.ip.rel = 70;
+ }
ip_ver_read(i915, i915_mmio_reg_offset(GMD_ID_DISPLAY),
&runtime->display.ip);
ip_ver_read(i915, i915_mmio_reg_offset(GMD_ID_MEDIA),
diff --git a/drivers/gpu/drm/i915/intel_device_info.h b/drivers/gpu/drm/i915/intel_device_info.h
index d588e5fd2eea..80bda653d61b 100644
--- a/drivers/gpu/drm/i915/intel_device_info.h
+++ b/drivers/gpu/drm/i915/intel_device_info.h
@@ -29,7 +29,7 @@
#include "intel_step.h"
-#include "display/intel_display.h"
+#include "display/intel_display_limits.h"
#include "gt/intel_engine_types.h"
#include "gt/intel_context_types.h"
diff --git a/drivers/gpu/drm/i915/intel_gvt_mmio_table.c b/drivers/gpu/drm/i915/intel_gvt_mmio_table.c
index ce6b3c3b636a..1f4805aa2b08 100644
--- a/drivers/gpu/drm/i915/intel_gvt_mmio_table.c
+++ b/drivers/gpu/drm/i915/intel_gvt_mmio_table.c
@@ -5,6 +5,7 @@
#include "display/intel_audio_regs.h"
#include "display/intel_backlight_regs.h"
+#include "display/intel_display_types.h"
#include "display/intel_dmc_regs.h"
#include "display/intel_dpio_phy.h"
#include "display/vlv_dsi_pll_regs.h"
diff --git a/drivers/gpu/drm/i915/intel_mchbar_regs.h b/drivers/gpu/drm/i915/intel_mchbar_regs.h
index f93e9af43ac3..73900c098d59 100644
--- a/drivers/gpu/drm/i915/intel_mchbar_regs.h
+++ b/drivers/gpu/drm/i915/intel_mchbar_regs.h
@@ -194,6 +194,8 @@
*/
#define PCU_PACKAGE_POWER_SKU _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5930)
#define PKG_PKG_TDP GENMASK_ULL(14, 0)
+#define PKG_MIN_PWR GENMASK_ULL(30, 16)
+#define PKG_MAX_PWR GENMASK_ULL(46, 32)
#define PKG_MAX_WIN GENMASK_ULL(54, 48)
#define PKG_MAX_WIN_X GENMASK_ULL(54, 53)
#define PKG_MAX_WIN_Y GENMASK_ULL(52, 48)
diff --git a/drivers/gpu/drm/i915/intel_memory_region.c b/drivers/gpu/drm/i915/intel_memory_region.c
index b9a164efd6ae..3d1fdea9811d 100644
--- a/drivers/gpu/drm/i915/intel_memory_region.c
+++ b/drivers/gpu/drm/i915/intel_memory_region.c
@@ -235,7 +235,7 @@ intel_memory_region_create(struct drm_i915_private *i915,
return ERR_PTR(-ENOMEM);
mem->i915 = i915;
- mem->region = (struct resource)DEFINE_RES_MEM(start, size);
+ mem->region = DEFINE_RES_MEM(start, size);
mem->io_start = io_start;
mem->io_size = io_size;
mem->min_page_size = min_page_size;
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 73c88b1c9545..59714b1080d4 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -26,6 +26,7 @@
*/
#include "display/intel_de.h"
+#include "display/intel_display.h"
#include "display/intel_display_trace.h"
#include "display/skl_watermark.h"
@@ -4299,8 +4300,8 @@ static void gen8_set_l3sqc_credits(struct drm_i915_private *dev_priv,
u32 val;
/* WaTempDisableDOPClkGating:bdw */
- misccpctl = intel_gt_mcr_multicast_rmw(to_gt(dev_priv), GEN8_MISCCPCTL,
- GEN8_DOP_CLOCK_GATE_ENABLE, 0);
+ misccpctl = intel_uncore_rmw(&dev_priv->uncore, GEN7_MISCCPCTL,
+ GEN7_DOP_CLOCK_GATE_ENABLE, 0);
val = intel_gt_mcr_read_any(to_gt(dev_priv), GEN8_L3SQCREG1);
val &= ~L3_PRIO_CREDITS_MASK;
@@ -4314,7 +4315,7 @@ static void gen8_set_l3sqc_credits(struct drm_i915_private *dev_priv,
*/
intel_gt_mcr_read_any(to_gt(dev_priv), GEN8_L3SQCREG1);
udelay(1);
- intel_gt_mcr_multicast_write(to_gt(dev_priv), GEN8_MISCCPCTL, misccpctl);
+ intel_uncore_write(&dev_priv->uncore, GEN7_MISCCPCTL, misccpctl);
}
static void icl_init_clock_gating(struct drm_i915_private *dev_priv)
@@ -4465,8 +4466,8 @@ static void skl_init_clock_gating(struct drm_i915_private *dev_priv)
gen9_init_clock_gating(dev_priv);
/* WaDisableDopClockGating:skl */
- intel_gt_mcr_multicast_rmw(to_gt(dev_priv), GEN8_MISCCPCTL,
- GEN8_DOP_CLOCK_GATE_ENABLE, 0);
+ intel_uncore_rmw(&dev_priv->uncore, GEN7_MISCCPCTL,
+ GEN7_DOP_CLOCK_GATE_ENABLE, 0);
/* WAC6entrylatency:skl */
intel_uncore_rmw(&dev_priv->uncore, FBC_LLC_READ_CTRL, 0, FBC_LLC_FULLY_OPEN);
diff --git a/drivers/gpu/drm/i915/intel_pm_types.h b/drivers/gpu/drm/i915/intel_pm_types.h
index 211632f58751..93152537b420 100644
--- a/drivers/gpu/drm/i915/intel_pm_types.h
+++ b/drivers/gpu/drm/i915/intel_pm_types.h
@@ -8,7 +8,7 @@
#include <linux/types.h>
-#include "display/intel_display.h"
+#include "display/intel_display_limits.h"
enum intel_ddb_partitioning {
INTEL_DDB_PART_1_2,
diff --git a/drivers/gpu/drm/i915/intel_region_ttm.c b/drivers/gpu/drm/i915/intel_region_ttm.c
index cf89d0c2a2d9..b7fbd5abb42a 100644
--- a/drivers/gpu/drm/i915/intel_region_ttm.c
+++ b/drivers/gpu/drm/i915/intel_region_ttm.c
@@ -2,7 +2,6 @@
/*
* Copyright © 2021 Intel Corporation
*/
-#include <drm/ttm/ttm_bo_driver.h>
#include <drm/ttm/ttm_device.h>
#include <drm/ttm/ttm_range_manager.h>
@@ -132,7 +131,7 @@ int intel_region_ttm_fini(struct intel_memory_region *mem)
break;
msleep(20);
- flush_delayed_work(&mem->i915->bdev.wq);
+ drain_workqueue(mem->i915->bdev.wq);
}
/* If we leaked objects, Don't free the region causing use after free */
@@ -209,13 +208,25 @@ intel_region_ttm_resource_alloc(struct intel_memory_region *mem,
if (flags & I915_BO_ALLOC_CONTIGUOUS)
place.flags |= TTM_PL_FLAG_CONTIGUOUS;
if (offset != I915_BO_INVALID_OFFSET) {
+ if (WARN_ON(overflows_type(offset >> PAGE_SHIFT, place.fpfn))) {
+ ret = -E2BIG;
+ goto out;
+ }
place.fpfn = offset >> PAGE_SHIFT;
+ if (WARN_ON(overflows_type(place.fpfn + (size >> PAGE_SHIFT), place.lpfn))) {
+ ret = -E2BIG;
+ goto out;
+ }
place.lpfn = place.fpfn + (size >> PAGE_SHIFT);
} else if (mem->io_size && mem->io_size < mem->total) {
if (flags & I915_BO_ALLOC_GPU_ONLY) {
place.flags |= TTM_PL_FLAG_TOPDOWN;
} else {
place.fpfn = 0;
+ if (WARN_ON(overflows_type(mem->io_size >> PAGE_SHIFT, place.lpfn))) {
+ ret = -E2BIG;
+ goto out;
+ }
place.lpfn = mem->io_size >> PAGE_SHIFT;
}
}
@@ -224,6 +235,8 @@ intel_region_ttm_resource_alloc(struct intel_memory_region *mem,
mock_bo.bdev = &mem->i915->bdev;
ret = man->func->alloc(man, &mock_bo, &place, &res);
+
+out:
if (ret == -ENOSPC)
ret = -ENXIO;
if (!ret)
diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.h b/drivers/gpu/drm/i915/intel_runtime_pm.h
index 98b8b28baaa1..e592e8d6499a 100644
--- a/drivers/gpu/drm/i915/intel_runtime_pm.h
+++ b/drivers/gpu/drm/i915/intel_runtime_pm.h
@@ -96,7 +96,7 @@ struct intel_runtime_pm {
};
#define BITS_PER_WAKEREF \
- BITS_PER_TYPE(struct_member(struct intel_runtime_pm, wakeref_count))
+ BITS_PER_TYPE(typeof_member(struct intel_runtime_pm, wakeref_count))
#define INTEL_RPM_WAKELOCK_SHIFT (BITS_PER_WAKEREF / 2)
#define INTEL_RPM_WAKELOCK_BIAS (1 << INTEL_RPM_WAKELOCK_SHIFT)
#define INTEL_RPM_RAW_WAKEREF_MASK (INTEL_RPM_WAKELOCK_BIAS - 1)
diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c
index 614013745fca..8dee9e62a73e 100644
--- a/drivers/gpu/drm/i915/intel_uncore.c
+++ b/drivers/gpu/drm/i915/intel_uncore.c
@@ -2701,6 +2701,62 @@ void intel_uncore_prune_engine_fw_domains(struct intel_uncore *uncore,
if (fw_domains & BIT(domain_id))
fw_domain_fini(uncore, domain_id);
}
+
+ if ((fw_domains & BIT(FW_DOMAIN_ID_GSC)) && !HAS_ENGINE(gt, GSC0))
+ fw_domain_fini(uncore, FW_DOMAIN_ID_GSC);
+}
+
+/*
+ * The driver-initiated FLR is the highest level of reset that we can trigger
+ * from within the driver. It is different from the PCI FLR in that it doesn't
+ * fully reset the SGUnit and doesn't modify the PCI config space and therefore
+ * it doesn't require a re-enumeration of the PCI BARs. However, the
+ * driver-initiated FLR does still cause a reset of both GT and display and a
+ * memory wipe of local and stolen memory, so recovery would require a full HW
+ * re-init and saving/restoring (or re-populating) the wiped memory. Since we
+ * perform the FLR as the very last action before releasing access to the HW
+ * during the driver release flow, we don't attempt recovery at all, because
+ * if/when a new instance of i915 is bound to the device it will do a full
+ * re-init anyway.
+ */
+static void driver_initiated_flr(struct intel_uncore *uncore)
+{
+ struct drm_i915_private *i915 = uncore->i915;
+ const unsigned int flr_timeout_ms = 3000; /* specs recommend a 3s wait */
+ int ret;
+
+ drm_dbg(&i915->drm, "Triggering Driver-FLR\n");
+
+ /*
+ * Make sure any pending FLR requests have cleared by waiting for the
+ * FLR trigger bit to go to zero. Also clear GU_DEBUG's DRIVERFLR_STATUS
+ * to make sure it's not still set from a prior attempt (it's a write to
+ * clear bit).
+ * Note that we should never be in a situation where a previous attempt
+ * is still pending (unless the HW is totally dead), but better to be
+ * safe in case something unexpected happens
+ */
+ ret = intel_wait_for_register_fw(uncore, GU_CNTL, DRIVERFLR, 0, flr_timeout_ms);
+ if (ret) {
+ drm_err(&i915->drm,
+ "Failed to wait for Driver-FLR bit to clear! %d\n",
+ ret);
+ return;
+ }
+ intel_uncore_write_fw(uncore, GU_DEBUG, DRIVERFLR_STATUS);
+
+ /* Trigger the actual Driver-FLR */
+ intel_uncore_rmw_fw(uncore, GU_CNTL, 0, DRIVERFLR);
+
+ ret = intel_wait_for_register_fw(uncore, GU_DEBUG,
+ DRIVERFLR_STATUS, DRIVERFLR_STATUS,
+ flr_timeout_ms);
+ if (ret) {
+ drm_err(&i915->drm, "wait for Driver-FLR completion failed! %d\n", ret);
+ return;
+ }
+
+ intel_uncore_write_fw(uncore, GU_DEBUG, DRIVERFLR_STATUS);
}
/* Called via drm-managed action */
@@ -2716,6 +2772,9 @@ void intel_uncore_fini_mmio(struct drm_device *dev, void *data)
intel_uncore_fw_domains_fini(uncore);
iosf_mbi_punit_release();
}
+
+ if (intel_uncore_needs_flr_on_fini(uncore))
+ driver_initiated_flr(uncore);
}
/**
diff --git a/drivers/gpu/drm/i915/intel_uncore.h b/drivers/gpu/drm/i915/intel_uncore.h
index e9e38490815d..9ea1f4864a3a 100644
--- a/drivers/gpu/drm/i915/intel_uncore.h
+++ b/drivers/gpu/drm/i915/intel_uncore.h
@@ -153,6 +153,7 @@ struct intel_uncore {
#define UNCORE_HAS_FPGA_DBG_UNCLAIMED BIT(1)
#define UNCORE_HAS_DBG_UNCLAIMED BIT(2)
#define UNCORE_HAS_FIFO BIT(3)
+#define UNCORE_NEEDS_FLR_ON_FINI BIT(4)
const struct intel_forcewake_range *fw_domains_table;
unsigned int fw_domains_table_entries;
@@ -223,6 +224,18 @@ intel_uncore_has_fifo(const struct intel_uncore *uncore)
return uncore->flags & UNCORE_HAS_FIFO;
}
+static inline bool
+intel_uncore_needs_flr_on_fini(const struct intel_uncore *uncore)
+{
+ return uncore->flags & UNCORE_NEEDS_FLR_ON_FINI;
+}
+
+static inline bool
+intel_uncore_set_flr_on_fini(struct intel_uncore *uncore)
+{
+ return uncore->flags |= UNCORE_NEEDS_FLR_ON_FINI;
+}
+
void intel_uncore_mmio_debug_init_early(struct drm_i915_private *i915);
void intel_uncore_init_early(struct intel_uncore *uncore,
struct intel_gt *gt);
diff --git a/drivers/gpu/drm/i915/intel_wakeref.h b/drivers/gpu/drm/i915/intel_wakeref.h
index 4f4c2e15e736..71b8a63f6f10 100644
--- a/drivers/gpu/drm/i915/intel_wakeref.h
+++ b/drivers/gpu/drm/i915/intel_wakeref.h
@@ -68,11 +68,12 @@ void __intel_wakeref_put_last(struct intel_wakeref *wf, unsigned long flags);
* @wf: the wakeref
*
* Acquire a hold on the wakeref. The first user to do so, will acquire
- * the runtime pm wakeref and then call the @fn underneath the wakeref
- * mutex.
+ * the runtime pm wakeref and then call the intel_wakeref_ops->get()
+ * underneath the wakeref mutex.
*
- * Note that @fn is allowed to fail, in which case the runtime-pm wakeref
- * will be released and the acquisition unwound, and an error reported.
+ * Note that intel_wakeref_ops->get() is allowed to fail, in which case
+ * the runtime-pm wakeref will be released and the acquisition unwound,
+ * and an error reported.
*
* Returns: 0 if the wakeref was acquired successfully, or a negative error
* code otherwise.
@@ -130,19 +131,17 @@ intel_wakeref_might_get(struct intel_wakeref *wf)
}
/**
- * intel_wakeref_put_flags: Release the wakeref
+ * __intel_wakeref_put: Release the wakeref
* @wf: the wakeref
* @flags: control flags
*
* Release our hold on the wakeref. When there are no more users,
- * the runtime pm wakeref will be released after the @fn callback is called
- * underneath the wakeref mutex.
+ * the runtime pm wakeref will be released after the intel_wakeref_ops->put()
+ * callback is called underneath the wakeref mutex.
*
- * Note that @fn is allowed to fail, in which case the runtime-pm wakeref
- * is retained and an error reported.
+ * Note that intel_wakeref_ops->put() is allowed to fail, in which case the
+ * runtime-pm wakeref is retained.
*
- * Returns: 0 if the wakeref was released successfully, or a negative error
- * code otherwise.
*/
static inline void
__intel_wakeref_put(struct intel_wakeref *wf, unsigned long flags)
diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp.c b/drivers/gpu/drm/i915/pxp/intel_pxp.c
index 5efe61f67546..cfc9af8b3d21 100644
--- a/drivers/gpu/drm/i915/pxp/intel_pxp.c
+++ b/drivers/gpu/drm/i915/pxp/intel_pxp.c
@@ -3,13 +3,19 @@
* Copyright(c) 2020 Intel Corporation.
*/
#include <linux/workqueue.h>
+
+#include "gem/i915_gem_context.h"
+
+#include "gt/intel_context.h"
+#include "gt/intel_gt.h"
+
+#include "i915_drv.h"
+
#include "intel_pxp.h"
#include "intel_pxp_irq.h"
#include "intel_pxp_session.h"
#include "intel_pxp_tee.h"
-#include "gem/i915_gem_context.h"
-#include "gt/intel_context.h"
-#include "i915_drv.h"
+#include "intel_pxp_types.h"
/**
* DOC: PXP
@@ -39,19 +45,19 @@
* performed via the mei_pxp component module.
*/
-struct intel_gt *pxp_to_gt(const struct intel_pxp *pxp)
+bool intel_pxp_is_supported(const struct intel_pxp *pxp)
{
- return container_of(pxp, struct intel_gt, pxp);
+ return IS_ENABLED(CONFIG_DRM_I915_PXP) && pxp;
}
bool intel_pxp_is_enabled(const struct intel_pxp *pxp)
{
- return pxp->ce;
+ return IS_ENABLED(CONFIG_DRM_I915_PXP) && pxp && pxp->ce;
}
bool intel_pxp_is_active(const struct intel_pxp *pxp)
{
- return pxp->arb_is_valid;
+ return IS_ENABLED(CONFIG_DRM_I915_PXP) && pxp && pxp->arb_is_valid;
}
/* KCR register definitions */
@@ -74,7 +80,7 @@ static void kcr_pxp_disable(struct intel_gt *gt)
static int create_vcs_context(struct intel_pxp *pxp)
{
static struct lock_class_key pxp_lock;
- struct intel_gt *gt = pxp_to_gt(pxp);
+ struct intel_gt *gt = pxp->ctrl_gt;
struct intel_engine_cs *engine;
struct intel_context *ce;
int i;
@@ -109,7 +115,7 @@ static void destroy_vcs_context(struct intel_pxp *pxp)
static void pxp_init_full(struct intel_pxp *pxp)
{
- struct intel_gt *gt = pxp_to_gt(pxp);
+ struct intel_gt *gt = pxp->ctrl_gt;
int ret;
/*
@@ -138,31 +144,97 @@ out_context:
destroy_vcs_context(pxp);
}
-void intel_pxp_init(struct intel_pxp *pxp)
+static struct intel_gt *find_gt_for_required_teelink(struct drm_i915_private *i915)
{
- struct intel_gt *gt = pxp_to_gt(pxp);
+ /*
+ * NOTE: Only certain platforms require PXP-tee-backend dependencies
+ * for HuC authentication. For now, its limited to DG2.
+ */
+ if (IS_ENABLED(CONFIG_INTEL_MEI_PXP) && IS_ENABLED(CONFIG_INTEL_MEI_GSC) &&
+ intel_huc_is_loaded_by_gsc(&i915->gt0.uc.huc) && intel_uc_uses_huc(&i915->gt0.uc))
+ return &i915->gt0;
- /* we rely on the mei PXP module */
- if (!IS_ENABLED(CONFIG_INTEL_MEI_PXP))
- return;
+ return NULL;
+}
+
+static struct intel_gt *find_gt_for_required_protected_content(struct drm_i915_private *i915)
+{
+ if (!IS_ENABLED(CONFIG_DRM_I915_PXP) || !INTEL_INFO(i915)->has_pxp)
+ return NULL;
/*
- * If HuC is loaded by GSC but PXP is disabled, we can skip the init of
- * the full PXP session/object management and just init the tee channel.
+ * For MTL onwards, PXP-controller-GT needs to have a valid GSC engine
+ * on the media GT. NOTE: if we have a media-tile with a GSC-engine,
+ * the VDBOX is already present so skip that check
*/
- if (HAS_PXP(gt->i915))
- pxp_init_full(pxp);
- else if (intel_huc_is_loaded_by_gsc(&gt->uc.huc) && intel_uc_uses_huc(&gt->uc))
- intel_pxp_tee_component_init(pxp);
+ if (i915->media_gt && HAS_ENGINE(i915->media_gt, GSC0))
+ return i915->media_gt;
+
+ /*
+ * Else we rely on mei-pxp module but only on legacy platforms
+ * prior to having separate media GTs and has a valid VDBOX.
+ */
+ if (IS_ENABLED(CONFIG_INTEL_MEI_PXP) && !i915->media_gt && VDBOX_MASK(&i915->gt0))
+ return &i915->gt0;
+
+ return NULL;
}
-void intel_pxp_fini(struct intel_pxp *pxp)
+int intel_pxp_init(struct drm_i915_private *i915)
{
- pxp->arb_is_valid = false;
+ struct intel_gt *gt;
+ bool is_full_feature = false;
- intel_pxp_tee_component_fini(pxp);
+ /*
+ * NOTE: Get the ctrl_gt before checking intel_pxp_is_supported since
+ * we still need it if PXP's backend tee transport is needed.
+ */
+ gt = find_gt_for_required_protected_content(i915);
+ if (gt)
+ is_full_feature = true;
+ else
+ gt = find_gt_for_required_teelink(i915);
- destroy_vcs_context(pxp);
+ if (!gt)
+ return -ENODEV;
+
+ /*
+ * At this point, we will either enable full featured PXP capabilities
+ * including session and object management, or we will init the backend tee
+ * channel for internal users such as HuC loading by GSC
+ */
+ i915->pxp = kzalloc(sizeof(*i915->pxp), GFP_KERNEL);
+ if (!i915->pxp)
+ return -ENOMEM;
+
+ i915->pxp->ctrl_gt = gt;
+
+ /*
+ * If full PXP feature is not available but HuC is loaded by GSC on pre-MTL
+ * such as DG2, we can skip the init of the full PXP session/object management
+ * and just init the tee channel.
+ */
+ if (is_full_feature)
+ pxp_init_full(i915->pxp);
+ else
+ intel_pxp_tee_component_init(i915->pxp);
+
+ return 0;
+}
+
+void intel_pxp_fini(struct drm_i915_private *i915)
+{
+ if (!i915->pxp)
+ return;
+
+ i915->pxp->arb_is_valid = false;
+
+ intel_pxp_tee_component_fini(i915->pxp);
+
+ destroy_vcs_context(i915->pxp);
+
+ kfree(i915->pxp);
+ i915->pxp = NULL;
}
void intel_pxp_mark_termination_in_progress(struct intel_pxp *pxp)
@@ -173,7 +245,7 @@ void intel_pxp_mark_termination_in_progress(struct intel_pxp *pxp)
static void pxp_queue_termination(struct intel_pxp *pxp)
{
- struct intel_gt *gt = pxp_to_gt(pxp);
+ struct intel_gt *gt = pxp->ctrl_gt;
/*
* We want to get the same effect as if we received a termination
@@ -238,13 +310,13 @@ unlock:
void intel_pxp_init_hw(struct intel_pxp *pxp)
{
- kcr_pxp_enable(pxp_to_gt(pxp));
+ kcr_pxp_enable(pxp->ctrl_gt);
intel_pxp_irq_enable(pxp);
}
void intel_pxp_fini_hw(struct intel_pxp *pxp)
{
- kcr_pxp_disable(pxp_to_gt(pxp));
+ kcr_pxp_disable(pxp->ctrl_gt);
intel_pxp_irq_disable(pxp);
}
@@ -278,7 +350,7 @@ int intel_pxp_key_check(struct intel_pxp *pxp,
void intel_pxp_invalidate(struct intel_pxp *pxp)
{
- struct drm_i915_private *i915 = pxp_to_gt(pxp)->i915;
+ struct drm_i915_private *i915 = pxp->ctrl_gt->i915;
struct i915_gem_context *ctx, *cn;
/* ban all contexts marked as protected */
diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp.h b/drivers/gpu/drm/i915/pxp/intel_pxp.h
index 2da309088c6d..04440fada711 100644
--- a/drivers/gpu/drm/i915/pxp/intel_pxp.h
+++ b/drivers/gpu/drm/i915/pxp/intel_pxp.h
@@ -9,15 +9,16 @@
#include <linux/errno.h>
#include <linux/types.h>
-struct intel_pxp;
struct drm_i915_gem_object;
+struct drm_i915_private;
+struct intel_pxp;
-struct intel_gt *pxp_to_gt(const struct intel_pxp *pxp);
+bool intel_pxp_is_supported(const struct intel_pxp *pxp);
bool intel_pxp_is_enabled(const struct intel_pxp *pxp);
bool intel_pxp_is_active(const struct intel_pxp *pxp);
-void intel_pxp_init(struct intel_pxp *pxp);
-void intel_pxp_fini(struct intel_pxp *pxp);
+int intel_pxp_init(struct drm_i915_private *i915);
+void intel_pxp_fini(struct drm_i915_private *i915);
void intel_pxp_init_hw(struct intel_pxp *pxp);
void intel_pxp_fini_hw(struct intel_pxp *pxp);
diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_cmd.c b/drivers/gpu/drm/i915/pxp/intel_pxp_cmd.c
index f41e45763d0d..0eee51c4a772 100644
--- a/drivers/gpu/drm/i915/pxp/intel_pxp_cmd.c
+++ b/drivers/gpu/drm/i915/pxp/intel_pxp_cmd.c
@@ -3,9 +3,6 @@
* Copyright(c) 2020, Intel Corporation. All rights reserved.
*/
-#include "intel_pxp.h"
-#include "intel_pxp_cmd.h"
-#include "intel_pxp_session.h"
#include "gt/intel_context.h"
#include "gt/intel_engine_pm.h"
#include "gt/intel_gpu_commands.h"
@@ -13,6 +10,11 @@
#include "i915_trace.h"
+#include "intel_pxp.h"
+#include "intel_pxp_cmd.h"
+#include "intel_pxp_session.h"
+#include "intel_pxp_types.h"
+
/* stall until prior PXP and MFX/HCP/HUC objects are cmopleted */
#define MFX_WAIT_PXP (MFX_WAIT | \
MFX_WAIT_DW0_PXP_SYNC_CONTROL_FLAG | \
diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_cmd_interface_cmn.h b/drivers/gpu/drm/i915/pxp/intel_pxp_cmd_interface_cmn.h
index c2f23394f9b8..aaa8187a0afb 100644
--- a/drivers/gpu/drm/i915/pxp/intel_pxp_cmd_interface_cmn.h
+++ b/drivers/gpu/drm/i915/pxp/intel_pxp_cmd_interface_cmn.h
@@ -17,6 +17,7 @@
*/
enum pxp_status {
PXP_STATUS_SUCCESS = 0x0,
+ PXP_STATUS_ERROR_API_VERSION = 0x1002,
PXP_STATUS_OP_NOT_PERMITTED = 0x4013
};
diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_debugfs.c b/drivers/gpu/drm/i915/pxp/intel_pxp_debugfs.c
index 4359e8be4101..4b8e70caa3ad 100644
--- a/drivers/gpu/drm/i915/pxp/intel_pxp_debugfs.c
+++ b/drivers/gpu/drm/i915/pxp/intel_pxp_debugfs.c
@@ -9,18 +9,20 @@
#include <drm/drm_print.h>
#include "gt/intel_gt_debugfs.h"
+
#include "i915_drv.h"
+
#include "intel_pxp.h"
#include "intel_pxp_debugfs.h"
#include "intel_pxp_irq.h"
+#include "intel_pxp_types.h"
static int pxp_info_show(struct seq_file *m, void *data)
{
struct intel_pxp *pxp = m->private;
struct drm_printer p = drm_seq_file_printer(m);
- bool enabled = intel_pxp_is_enabled(pxp);
- if (!enabled) {
+ if (!intel_pxp_is_enabled(pxp)) {
drm_printf(&p, "pxp disabled\n");
return 0;
}
@@ -30,7 +32,8 @@ static int pxp_info_show(struct seq_file *m, void *data)
return 0;
}
-DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(pxp_info);
+
+DEFINE_SHOW_ATTRIBUTE(pxp_info);
static int pxp_terminate_get(void *data, u64 *val)
{
@@ -41,7 +44,7 @@ static int pxp_terminate_get(void *data, u64 *val)
static int pxp_terminate_set(void *data, u64 val)
{
struct intel_pxp *pxp = data;
- struct intel_gt *gt = pxp_to_gt(pxp);
+ struct intel_gt *gt = pxp->ctrl_gt;
if (!intel_pxp_is_active(pxp))
return -ENODEV;
@@ -59,23 +62,26 @@ static int pxp_terminate_set(void *data, u64 val)
}
DEFINE_SIMPLE_ATTRIBUTE(pxp_terminate_fops, pxp_terminate_get, pxp_terminate_set, "%llx\n");
-void intel_pxp_debugfs_register(struct intel_pxp *pxp, struct dentry *gt_root)
+
+void intel_pxp_debugfs_register(struct intel_pxp *pxp)
{
- static const struct intel_gt_debugfs_file files[] = {
- { "info", &pxp_info_fops, NULL },
- { "terminate_state", &pxp_terminate_fops, NULL },
- };
- struct dentry *root;
+ struct drm_minor *minor;
+ struct dentry *pxproot;
- if (!gt_root)
+ if (!intel_pxp_is_supported(pxp))
return;
- if (!HAS_PXP((pxp_to_gt(pxp)->i915)))
+ minor = pxp->ctrl_gt->i915->drm.primary;
+ if (!minor->debugfs_root)
return;
- root = debugfs_create_dir("pxp", gt_root);
- if (IS_ERR(root))
+ pxproot = debugfs_create_dir("pxp", minor->debugfs_root);
+ if (IS_ERR(pxproot))
return;
- intel_gt_debugfs_register_files(root, files, ARRAY_SIZE(files), pxp);
+ debugfs_create_file("info", 0444, pxproot,
+ pxp, &pxp_info_fops);
+
+ debugfs_create_file("terminate_state", 0644, pxproot,
+ pxp, &pxp_terminate_fops);
}
diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_debugfs.h b/drivers/gpu/drm/i915/pxp/intel_pxp_debugfs.h
index 7e0c3d2f5d7e..299382b59e66 100644
--- a/drivers/gpu/drm/i915/pxp/intel_pxp_debugfs.h
+++ b/drivers/gpu/drm/i915/pxp/intel_pxp_debugfs.h
@@ -10,10 +10,10 @@ struct intel_pxp;
struct dentry;
#ifdef CONFIG_DRM_I915_PXP
-void intel_pxp_debugfs_register(struct intel_pxp *pxp, struct dentry *root);
+void intel_pxp_debugfs_register(struct intel_pxp *pxp);
#else
static inline void
-intel_pxp_debugfs_register(struct intel_pxp *pxp, struct dentry *root)
+intel_pxp_debugfs_register(struct intel_pxp *pxp)
{
}
#endif
diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_huc.c b/drivers/gpu/drm/i915/pxp/intel_pxp_huc.c
index 2e1165522950..64609d1b1c0f 100644
--- a/drivers/gpu/drm/i915/pxp/intel_pxp_huc.c
+++ b/drivers/gpu/drm/i915/pxp/intel_pxp_huc.c
@@ -3,8 +3,6 @@
* Copyright(c) 2021-2022, Intel Corporation. All rights reserved.
*/
-#include <drm/i915_drm.h>
-
#include "i915_drv.h"
#include "gem/i915_gem_region.h"
@@ -18,8 +16,8 @@
int intel_pxp_huc_load_and_auth(struct intel_pxp *pxp)
{
- struct intel_gt *gt = pxp_to_gt(pxp);
- struct intel_huc *huc = &gt->uc.huc;
+ struct intel_gt *gt;
+ struct intel_huc *huc;
struct pxp43_start_huc_auth_in huc_in = {0};
struct pxp43_start_huc_auth_out huc_out = {0};
dma_addr_t huc_phys_addr;
@@ -27,9 +25,12 @@ int intel_pxp_huc_load_and_auth(struct intel_pxp *pxp)
u8 fence_id = 0;
int err;
- if (!pxp->pxp_component)
+ if (!pxp || !pxp->pxp_component)
return -ENODEV;
+ gt = pxp->ctrl_gt;
+ huc = &gt->uc.huc;
+
huc_phys_addr = i915_gem_object_get_dma_address(huc->fw.obj, 0);
/* write the PXP message into the lmem (the sg list) */
diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_irq.c b/drivers/gpu/drm/i915/pxp/intel_pxp_irq.c
index c28be430718a..91e9622c07d0 100644
--- a/drivers/gpu/drm/i915/pxp/intel_pxp_irq.c
+++ b/drivers/gpu/drm/i915/pxp/intel_pxp_irq.c
@@ -3,14 +3,18 @@
* Copyright(c) 2020 Intel Corporation.
*/
#include <linux/workqueue.h>
-#include "intel_pxp.h"
-#include "intel_pxp_irq.h"
-#include "intel_pxp_session.h"
+
#include "gt/intel_gt_irq.h"
#include "gt/intel_gt_regs.h"
#include "gt/intel_gt_types.h"
+
#include "i915_irq.h"
#include "i915_reg.h"
+
+#include "intel_pxp.h"
+#include "intel_pxp_irq.h"
+#include "intel_pxp_session.h"
+#include "intel_pxp_types.h"
#include "intel_runtime_pm.h"
/**
@@ -20,11 +24,13 @@
*/
void intel_pxp_irq_handler(struct intel_pxp *pxp, u16 iir)
{
- struct intel_gt *gt = pxp_to_gt(pxp);
+ struct intel_gt *gt;
if (GEM_WARN_ON(!intel_pxp_is_enabled(pxp)))
return;
+ gt = pxp->ctrl_gt;
+
lockdep_assert_held(gt->irq_lock);
if (unlikely(!iir))
@@ -62,7 +68,7 @@ static inline void pxp_irq_reset(struct intel_gt *gt)
void intel_pxp_irq_enable(struct intel_pxp *pxp)
{
- struct intel_gt *gt = pxp_to_gt(pxp);
+ struct intel_gt *gt = pxp->ctrl_gt;
spin_lock_irq(gt->irq_lock);
@@ -77,7 +83,7 @@ void intel_pxp_irq_enable(struct intel_pxp *pxp)
void intel_pxp_irq_disable(struct intel_pxp *pxp)
{
- struct intel_gt *gt = pxp_to_gt(pxp);
+ struct intel_gt *gt = pxp->ctrl_gt;
/*
* We always need to submit a global termination when we re-enable the
diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_pm.c b/drivers/gpu/drm/i915/pxp/intel_pxp_pm.c
index 6a7d4e2ee138..892d39cc61c1 100644
--- a/drivers/gpu/drm/i915/pxp/intel_pxp_pm.c
+++ b/drivers/gpu/drm/i915/pxp/intel_pxp_pm.c
@@ -3,11 +3,13 @@
* Copyright(c) 2020 Intel Corporation.
*/
+#include "i915_drv.h"
+
#include "intel_pxp.h"
#include "intel_pxp_irq.h"
#include "intel_pxp_pm.h"
#include "intel_pxp_session.h"
-#include "i915_drv.h"
+#include "intel_pxp_types.h"
void intel_pxp_suspend_prepare(struct intel_pxp *pxp)
{
@@ -26,7 +28,7 @@ void intel_pxp_suspend(struct intel_pxp *pxp)
if (!intel_pxp_is_enabled(pxp))
return;
- with_intel_runtime_pm(&pxp_to_gt(pxp)->i915->runtime_pm, wakeref) {
+ with_intel_runtime_pm(&pxp->ctrl_gt->i915->runtime_pm, wakeref) {
intel_pxp_fini_hw(pxp);
pxp->hw_state_invalidated = false;
}
diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_session.c b/drivers/gpu/drm/i915/pxp/intel_pxp_session.c
index 85572360c71a..ae413580b81a 100644
--- a/drivers/gpu/drm/i915/pxp/intel_pxp_session.c
+++ b/drivers/gpu/drm/i915/pxp/intel_pxp_session.c
@@ -20,7 +20,7 @@
static bool intel_pxp_session_is_in_play(struct intel_pxp *pxp, u32 id)
{
- struct intel_uncore *uncore = pxp_to_gt(pxp)->uncore;
+ struct intel_uncore *uncore = pxp->ctrl_gt->uncore;
intel_wakeref_t wakeref;
u32 sip = 0;
@@ -33,7 +33,7 @@ static bool intel_pxp_session_is_in_play(struct intel_pxp *pxp, u32 id)
static int pxp_wait_for_session_state(struct intel_pxp *pxp, u32 id, bool in_play)
{
- struct intel_uncore *uncore = pxp_to_gt(pxp)->uncore;
+ struct intel_uncore *uncore = pxp->ctrl_gt->uncore;
intel_wakeref_t wakeref;
u32 mask = BIT(id);
int ret;
@@ -56,7 +56,7 @@ static int pxp_wait_for_session_state(struct intel_pxp *pxp, u32 id, bool in_pla
static int pxp_create_arb_session(struct intel_pxp *pxp)
{
- struct intel_gt *gt = pxp_to_gt(pxp);
+ struct intel_gt *gt = pxp->ctrl_gt;
int ret;
pxp->arb_is_valid = false;
@@ -90,7 +90,7 @@ static int pxp_create_arb_session(struct intel_pxp *pxp)
static int pxp_terminate_arb_session_and_global(struct intel_pxp *pxp)
{
int ret;
- struct intel_gt *gt = pxp_to_gt(pxp);
+ struct intel_gt *gt = pxp->ctrl_gt;
/* must mark termination in progress calling this function */
GEM_WARN_ON(pxp->arb_is_valid);
@@ -141,7 +141,7 @@ static void pxp_terminate_complete(struct intel_pxp *pxp)
static void pxp_session_work(struct work_struct *work)
{
struct intel_pxp *pxp = container_of(work, typeof(*pxp), session_work);
- struct intel_gt *gt = pxp_to_gt(pxp);
+ struct intel_gt *gt = pxp->ctrl_gt;
intel_wakeref_t wakeref;
u32 events = 0;
diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c b/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c
index b0c9170b1395..73aa8015f828 100644
--- a/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c
+++ b/drivers/gpu/drm/i915/pxp/intel_pxp_tee.c
@@ -11,25 +11,20 @@
#include "gem/i915_gem_lmem.h"
#include "i915_drv.h"
+
#include "intel_pxp.h"
-#include "intel_pxp_session.h"
-#include "intel_pxp_tee.h"
#include "intel_pxp_cmd_interface_42.h"
#include "intel_pxp_huc.h"
-
-static inline struct intel_pxp *i915_dev_to_pxp(struct device *i915_kdev)
-{
- struct drm_i915_private *i915 = kdev_to_i915(i915_kdev);
-
- return &to_gt(i915)->pxp;
-}
+#include "intel_pxp_session.h"
+#include "intel_pxp_tee.h"
+#include "intel_pxp_types.h"
static int intel_pxp_tee_io_message(struct intel_pxp *pxp,
void *msg_in, u32 msg_in_size,
void *msg_out, u32 msg_out_max_size,
u32 *msg_out_rcv_size)
{
- struct drm_i915_private *i915 = pxp_to_gt(pxp)->i915;
+ struct drm_i915_private *i915 = pxp->ctrl_gt->i915;
struct i915_pxp_component *pxp_component = pxp->pxp_component;
int ret = 0;
@@ -79,7 +74,7 @@ int intel_pxp_tee_stream_message(struct intel_pxp *pxp,
{
/* TODO: for bigger objects we need to use a sg of 4k pages */
const size_t max_msg_size = PAGE_SIZE;
- struct drm_i915_private *i915 = pxp_to_gt(pxp)->i915;
+ struct drm_i915_private *i915 = pxp->ctrl_gt->i915;
struct i915_pxp_component *pxp_component = pxp->pxp_component;
unsigned int offset = 0;
struct scatterlist *sg;
@@ -127,8 +122,8 @@ static int i915_pxp_tee_component_bind(struct device *i915_kdev,
struct device *tee_kdev, void *data)
{
struct drm_i915_private *i915 = kdev_to_i915(i915_kdev);
- struct intel_pxp *pxp = i915_dev_to_pxp(i915_kdev);
- struct intel_uc *uc = &pxp_to_gt(pxp)->uc;
+ struct intel_pxp *pxp = i915->pxp;
+ struct intel_uc *uc = &pxp->ctrl_gt->uc;
intel_wakeref_t wakeref;
int ret = 0;
@@ -164,7 +159,7 @@ static void i915_pxp_tee_component_unbind(struct device *i915_kdev,
struct device *tee_kdev, void *data)
{
struct drm_i915_private *i915 = kdev_to_i915(i915_kdev);
- struct intel_pxp *pxp = i915_dev_to_pxp(i915_kdev);
+ struct intel_pxp *pxp = i915->pxp;
intel_wakeref_t wakeref;
if (intel_pxp_is_enabled(pxp))
@@ -183,7 +178,7 @@ static const struct component_ops i915_pxp_tee_component_ops = {
static int alloc_streaming_command(struct intel_pxp *pxp)
{
- struct drm_i915_private *i915 = pxp_to_gt(pxp)->i915;
+ struct drm_i915_private *i915 = pxp->ctrl_gt->i915;
struct drm_i915_gem_object *obj = NULL;
void *cmd;
int err;
@@ -244,7 +239,7 @@ static void free_streaming_command(struct intel_pxp *pxp)
int intel_pxp_tee_component_init(struct intel_pxp *pxp)
{
int ret;
- struct intel_gt *gt = pxp_to_gt(pxp);
+ struct intel_gt *gt = pxp->ctrl_gt;
struct drm_i915_private *i915 = gt->i915;
mutex_init(&pxp->tee_mutex);
@@ -271,7 +266,7 @@ out_free:
void intel_pxp_tee_component_fini(struct intel_pxp *pxp)
{
- struct drm_i915_private *i915 = pxp_to_gt(pxp)->i915;
+ struct drm_i915_private *i915 = pxp->ctrl_gt->i915;
if (!pxp->pxp_component_added)
return;
@@ -285,7 +280,7 @@ void intel_pxp_tee_component_fini(struct intel_pxp *pxp)
int intel_pxp_tee_cmd_create_arb_session(struct intel_pxp *pxp,
int arb_session_id)
{
- struct drm_i915_private *i915 = pxp_to_gt(pxp)->i915;
+ struct drm_i915_private *i915 = pxp->ctrl_gt->i915;
struct pxp42_create_arb_in msg_in = {0};
struct pxp42_create_arb_out msg_out = {0};
int ret;
@@ -303,6 +298,10 @@ int intel_pxp_tee_cmd_create_arb_session(struct intel_pxp *pxp,
if (ret)
drm_err(&i915->drm, "Failed to send tee msg ret=[%d]\n", ret);
+ else if (msg_out.header.status == PXP_STATUS_ERROR_API_VERSION)
+ drm_dbg(&i915->drm, "PXP firmware version unsupported, requested: "
+ "CMD-ID-[0x%08x] on API-Ver-[0x%08x]\n",
+ msg_in.header.command_id, msg_in.header.api_version);
else if (msg_out.header.status != 0x0)
drm_warn(&i915->drm, "PXP firmware failed arb session init request ret=[0x%08x]\n",
msg_out.header.status);
diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_types.h b/drivers/gpu/drm/i915/pxp/intel_pxp_types.h
index f74b1e11a505..7dc5f08d1583 100644
--- a/drivers/gpu/drm/i915/pxp/intel_pxp_types.h
+++ b/drivers/gpu/drm/i915/pxp/intel_pxp_types.h
@@ -12,13 +12,21 @@
#include <linux/workqueue.h>
struct intel_context;
+struct intel_gt;
struct i915_pxp_component;
+struct drm_i915_private;
/**
* struct intel_pxp - pxp state
*/
struct intel_pxp {
/**
+ * @ctrl_gt: poiner to the tile that owns the controls for PXP subsystem assets that
+ * the VDBOX, the KCR engine (and GSC CS depending on the platform)
+ */
+ struct intel_gt *ctrl_gt;
+
+ /**
* @pxp_component: i915_pxp_component struct of the bound mei_pxp
* module. Only set and cleared inside component bind/unbind functions,
* which are protected by &tee_mutex.
diff --git a/drivers/gpu/drm/i915/selftests/i915_gem.c b/drivers/gpu/drm/i915/selftests/i915_gem.c
index e5dd82e7e480..d91d0ade8abd 100644
--- a/drivers/gpu/drm/i915/selftests/i915_gem.c
+++ b/drivers/gpu/drm/i915/selftests/i915_gem.c
@@ -44,7 +44,7 @@ static void trash_stolen(struct drm_i915_private *i915)
{
struct i915_ggtt *ggtt = to_gt(i915)->ggtt;
const u64 slot = ggtt->error_capture.start;
- const resource_size_t size = resource_size(&i915->dsm);
+ const resource_size_t size = resource_size(&i915->dsm.stolen);
unsigned long page;
u32 prng = 0x12345678;
@@ -53,7 +53,7 @@ static void trash_stolen(struct drm_i915_private *i915)
return;
for (page = 0; page < size; page += PAGE_SIZE) {
- const dma_addr_t dma = i915->dsm.start + page;
+ const dma_addr_t dma = i915->dsm.stolen.start + page;
u32 __iomem *s;
int x;
@@ -127,6 +127,8 @@ static void igt_pm_resume(struct drm_i915_private *i915)
*/
with_intel_runtime_pm(&i915->runtime_pm, wakeref) {
i915_ggtt_resume(to_gt(i915)->ggtt);
+ if (GRAPHICS_VER(i915) >= 8)
+ setup_private_pat(to_gt(i915));
i915_gem_resume(i915);
}
}
diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
index eae7d947d7de..01e75160a84a 100644
--- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
@@ -68,6 +68,10 @@ static int fake_get_pages(struct drm_i915_gem_object *obj)
return -ENOMEM;
rem = round_up(obj->base.size, BIT(31)) >> 31;
+ /* restricted by sg_alloc_table */
+ if (overflows_type(rem, unsigned int))
+ return -E2BIG;
+
if (sg_alloc_table(pages, rem, GFP)) {
kfree(pages);
return -ENOMEM;
diff --git a/drivers/gpu/drm/i915/selftests/i915_request.c b/drivers/gpu/drm/i915/selftests/i915_request.c
index 0daa8669181d..6fe22b096bdd 100644
--- a/drivers/gpu/drm/i915/selftests/i915_request.c
+++ b/drivers/gpu/drm/i915/selftests/i915_request.c
@@ -1017,8 +1017,8 @@ empty_request(struct intel_engine_cs *engine,
return request;
err = engine->emit_bb_start(request,
- batch->node.start,
- batch->node.size,
+ i915_vma_offset(batch),
+ i915_vma_size(batch),
I915_DISPATCH_SECURE);
if (err)
goto out_request;
@@ -1138,14 +1138,14 @@ static struct i915_vma *recursive_batch(struct drm_i915_private *i915)
if (ver >= 8) {
*cmd++ = MI_BATCH_BUFFER_START | 1 << 8 | 1;
- *cmd++ = lower_32_bits(vma->node.start);
- *cmd++ = upper_32_bits(vma->node.start);
+ *cmd++ = lower_32_bits(i915_vma_offset(vma));
+ *cmd++ = upper_32_bits(i915_vma_offset(vma));
} else if (ver >= 6) {
*cmd++ = MI_BATCH_BUFFER_START | 1 << 8;
- *cmd++ = lower_32_bits(vma->node.start);
+ *cmd++ = lower_32_bits(i915_vma_offset(vma));
} else {
*cmd++ = MI_BATCH_BUFFER_START | MI_BATCH_GTT;
- *cmd++ = lower_32_bits(vma->node.start);
+ *cmd++ = lower_32_bits(i915_vma_offset(vma));
}
*cmd++ = MI_BATCH_BUFFER_END; /* terminate early in case of error */
@@ -1227,8 +1227,8 @@ static int live_all_engines(void *arg)
GEM_BUG_ON(err);
err = engine->emit_bb_start(request[idx],
- batch->node.start,
- batch->node.size,
+ i915_vma_offset(batch),
+ i915_vma_size(batch),
0);
GEM_BUG_ON(err);
request[idx]->batch = batch;
@@ -1354,8 +1354,8 @@ static int live_sequential_engines(void *arg)
GEM_BUG_ON(err);
err = engine->emit_bb_start(request[idx],
- batch->node.start,
- batch->node.size,
+ i915_vma_offset(batch),
+ i915_vma_size(batch),
0);
GEM_BUG_ON(err);
request[idx]->batch = batch;
diff --git a/drivers/gpu/drm/i915/selftests/igt_flush_test.c b/drivers/gpu/drm/i915/selftests/igt_flush_test.c
index b484e12df417..29110abb4fe0 100644
--- a/drivers/gpu/drm/i915/selftests/igt_flush_test.c
+++ b/drivers/gpu/drm/i915/selftests/igt_flush_test.c
@@ -14,21 +14,27 @@
int igt_flush_test(struct drm_i915_private *i915)
{
- struct intel_gt *gt = to_gt(i915);
- int ret = intel_gt_is_wedged(gt) ? -EIO : 0;
+ struct intel_gt *gt;
+ unsigned int i;
+ int ret = 0;
- cond_resched();
+ for_each_gt(gt, i915, i) {
+ if (intel_gt_is_wedged(gt))
+ ret = -EIO;
- if (intel_gt_wait_for_idle(gt, HZ * 3) == -ETIME) {
- pr_err("%pS timed out, cancelling all further testing.\n",
- __builtin_return_address(0));
+ cond_resched();
- GEM_TRACE("%pS timed out.\n",
- __builtin_return_address(0));
- GEM_TRACE_DUMP();
+ if (intel_gt_wait_for_idle(gt, HZ * 3) == -ETIME) {
+ pr_err("%pS timed out, cancelling all further testing.\n",
+ __builtin_return_address(0));
- intel_gt_set_wedged(gt);
- ret = -EIO;
+ GEM_TRACE("%pS timed out.\n",
+ __builtin_return_address(0));
+ GEM_TRACE_DUMP();
+
+ intel_gt_set_wedged(gt);
+ ret = -EIO;
+ }
}
return ret;
diff --git a/drivers/gpu/drm/i915/selftests/igt_spinner.c b/drivers/gpu/drm/i915/selftests/igt_spinner.c
index 16978ac59797..618d9386d554 100644
--- a/drivers/gpu/drm/i915/selftests/igt_spinner.c
+++ b/drivers/gpu/drm/i915/selftests/igt_spinner.c
@@ -116,7 +116,7 @@ static unsigned int seqno_offset(u64 fence)
static u64 hws_address(const struct i915_vma *hws,
const struct i915_request *rq)
{
- return hws->node.start + seqno_offset(rq->fence.context);
+ return i915_vma_offset(hws) + seqno_offset(rq->fence.context);
}
struct i915_request *
@@ -187,8 +187,8 @@ igt_spinner_create_request(struct igt_spinner *spin,
*batch++ = MI_BATCH_BUFFER_START;
else
*batch++ = MI_BATCH_BUFFER_START | MI_BATCH_GTT;
- *batch++ = lower_32_bits(vma->node.start);
- *batch++ = upper_32_bits(vma->node.start);
+ *batch++ = lower_32_bits(i915_vma_offset(vma));
+ *batch++ = upper_32_bits(i915_vma_offset(vma));
*batch++ = MI_BATCH_BUFFER_END; /* not reached */
@@ -203,7 +203,7 @@ igt_spinner_create_request(struct igt_spinner *spin,
flags = 0;
if (GRAPHICS_VER(rq->engine->i915) <= 5)
flags |= I915_DISPATCH_SECURE;
- err = engine->emit_bb_start(rq, vma->node.start, PAGE_SIZE, flags);
+ err = engine->emit_bb_start(rq, i915_vma_offset(vma), PAGE_SIZE, flags);
cancel_rq:
if (err) {
diff --git a/drivers/gpu/drm/i915/selftests/mock_gtt.c b/drivers/gpu/drm/i915/selftests/mock_gtt.c
index 568840e7ca66..ece97e4faacb 100644
--- a/drivers/gpu/drm/i915/selftests/mock_gtt.c
+++ b/drivers/gpu/drm/i915/selftests/mock_gtt.c
@@ -112,7 +112,7 @@ void mock_init_ggtt(struct intel_gt *gt)
ggtt->vm.i915 = gt->i915;
ggtt->vm.is_ggtt = true;
- ggtt->gmadr = (struct resource) DEFINE_RES_MEM(0, 2048 * PAGE_SIZE);
+ ggtt->gmadr = DEFINE_RES_MEM(0, 2048 * PAGE_SIZE);
ggtt->mappable_end = resource_size(&ggtt->gmadr);
ggtt->vm.total = 4096 * PAGE_SIZE;
diff --git a/drivers/gpu/drm/i915/selftests/scatterlist.c b/drivers/gpu/drm/i915/selftests/scatterlist.c
index d599186d5b71..805c4bfb85fe 100644
--- a/drivers/gpu/drm/i915/selftests/scatterlist.c
+++ b/drivers/gpu/drm/i915/selftests/scatterlist.c
@@ -220,6 +220,10 @@ static int alloc_table(struct pfn_table *pt,
struct scatterlist *sg;
unsigned long n, pfn;
+ /* restricted by sg_alloc_table */
+ if (overflows_type(max, unsigned int))
+ return -E2BIG;
+
if (sg_alloc_table(&pt->st, max,
GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN))
return alloc_error;
diff --git a/drivers/gpu/drm/i915/intel_dram.c b/drivers/gpu/drm/i915/soc/intel_dram.c
index bba8cb6e8ae4..bba8cb6e8ae4 100644
--- a/drivers/gpu/drm/i915/intel_dram.c
+++ b/drivers/gpu/drm/i915/soc/intel_dram.c
diff --git a/drivers/gpu/drm/i915/intel_dram.h b/drivers/gpu/drm/i915/soc/intel_dram.h
index 4ba13c13162c..4ba13c13162c 100644
--- a/drivers/gpu/drm/i915/intel_dram.h
+++ b/drivers/gpu/drm/i915/soc/intel_dram.h
diff --git a/drivers/gpu/drm/i915/soc/intel_gmch.c b/drivers/gpu/drm/i915/soc/intel_gmch.c
new file mode 100644
index 000000000000..6d0204942f7a
--- /dev/null
+++ b/drivers/gpu/drm/i915/soc/intel_gmch.c
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+#include <linux/pci.h>
+#include <linux/pnp.h>
+
+#include <drm/drm_managed.h>
+#include <drm/i915_drm.h>
+
+#include "i915_drv.h"
+#include "intel_gmch.h"
+#include "intel_pci_config.h"
+
+static void intel_gmch_bridge_release(struct drm_device *dev, void *bridge)
+{
+ pci_dev_put(bridge);
+}
+
+int intel_gmch_bridge_setup(struct drm_i915_private *i915)
+{
+ int domain = pci_domain_nr(to_pci_dev(i915->drm.dev)->bus);
+
+ i915->gmch.pdev = pci_get_domain_bus_and_slot(domain, 0, PCI_DEVFN(0, 0));
+ if (!i915->gmch.pdev) {
+ drm_err(&i915->drm, "bridge device not found\n");
+ return -EIO;
+ }
+
+ return drmm_add_action_or_reset(&i915->drm, intel_gmch_bridge_release,
+ i915->gmch.pdev);
+}
+
+/* Allocate space for the MCH regs if needed, return nonzero on error */
+static int
+intel_alloc_mchbar_resource(struct drm_i915_private *i915)
+{
+ int reg = GRAPHICS_VER(i915) >= 4 ? MCHBAR_I965 : MCHBAR_I915;
+ u32 temp_lo, temp_hi = 0;
+ u64 mchbar_addr;
+ int ret;
+
+ if (GRAPHICS_VER(i915) >= 4)
+ pci_read_config_dword(i915->gmch.pdev, reg + 4, &temp_hi);
+ pci_read_config_dword(i915->gmch.pdev, reg, &temp_lo);
+ mchbar_addr = ((u64)temp_hi << 32) | temp_lo;
+
+ /* If ACPI doesn't have it, assume we need to allocate it ourselves */
+#ifdef CONFIG_PNP
+ if (mchbar_addr &&
+ pnp_range_reserved(mchbar_addr, mchbar_addr + MCHBAR_SIZE))
+ return 0;
+#endif
+
+ /* Get some space for it */
+ i915->gmch.mch_res.name = "i915 MCHBAR";
+ i915->gmch.mch_res.flags = IORESOURCE_MEM;
+ ret = pci_bus_alloc_resource(i915->gmch.pdev->bus,
+ &i915->gmch.mch_res,
+ MCHBAR_SIZE, MCHBAR_SIZE,
+ PCIBIOS_MIN_MEM,
+ 0, pcibios_align_resource,
+ i915->gmch.pdev);
+ if (ret) {
+ drm_dbg(&i915->drm, "failed bus alloc: %d\n", ret);
+ i915->gmch.mch_res.start = 0;
+ return ret;
+ }
+
+ if (GRAPHICS_VER(i915) >= 4)
+ pci_write_config_dword(i915->gmch.pdev, reg + 4,
+ upper_32_bits(i915->gmch.mch_res.start));
+
+ pci_write_config_dword(i915->gmch.pdev, reg,
+ lower_32_bits(i915->gmch.mch_res.start));
+ return 0;
+}
+
+/* Setup MCHBAR if possible, return true if we should disable it again */
+void intel_gmch_bar_setup(struct drm_i915_private *i915)
+{
+ int mchbar_reg = GRAPHICS_VER(i915) >= 4 ? MCHBAR_I965 : MCHBAR_I915;
+ u32 temp;
+ bool enabled;
+
+ if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915))
+ return;
+
+ i915->gmch.mchbar_need_disable = false;
+
+ if (IS_I915G(i915) || IS_I915GM(i915)) {
+ pci_read_config_dword(i915->gmch.pdev, DEVEN, &temp);
+ enabled = !!(temp & DEVEN_MCHBAR_EN);
+ } else {
+ pci_read_config_dword(i915->gmch.pdev, mchbar_reg, &temp);
+ enabled = temp & 1;
+ }
+
+ /* If it's already enabled, don't have to do anything */
+ if (enabled)
+ return;
+
+ if (intel_alloc_mchbar_resource(i915))
+ return;
+
+ i915->gmch.mchbar_need_disable = true;
+
+ /* Space is allocated or reserved, so enable it. */
+ if (IS_I915G(i915) || IS_I915GM(i915)) {
+ pci_write_config_dword(i915->gmch.pdev, DEVEN,
+ temp | DEVEN_MCHBAR_EN);
+ } else {
+ pci_read_config_dword(i915->gmch.pdev, mchbar_reg, &temp);
+ pci_write_config_dword(i915->gmch.pdev, mchbar_reg, temp | 1);
+ }
+}
+
+void intel_gmch_bar_teardown(struct drm_i915_private *i915)
+{
+ int mchbar_reg = GRAPHICS_VER(i915) >= 4 ? MCHBAR_I965 : MCHBAR_I915;
+
+ if (i915->gmch.mchbar_need_disable) {
+ if (IS_I915G(i915) || IS_I915GM(i915)) {
+ u32 deven_val;
+
+ pci_read_config_dword(i915->gmch.pdev, DEVEN,
+ &deven_val);
+ deven_val &= ~DEVEN_MCHBAR_EN;
+ pci_write_config_dword(i915->gmch.pdev, DEVEN,
+ deven_val);
+ } else {
+ u32 mchbar_val;
+
+ pci_read_config_dword(i915->gmch.pdev, mchbar_reg,
+ &mchbar_val);
+ mchbar_val &= ~1;
+ pci_write_config_dword(i915->gmch.pdev, mchbar_reg,
+ mchbar_val);
+ }
+ }
+
+ if (i915->gmch.mch_res.start)
+ release_resource(&i915->gmch.mch_res);
+}
+
+int intel_gmch_vga_set_state(struct drm_i915_private *i915, bool enable_decode)
+{
+ unsigned int reg = DISPLAY_VER(i915) >= 6 ? SNB_GMCH_CTRL : INTEL_GMCH_CTRL;
+ u16 gmch_ctrl;
+
+ if (pci_read_config_word(i915->gmch.pdev, reg, &gmch_ctrl)) {
+ drm_err(&i915->drm, "failed to read control word\n");
+ return -EIO;
+ }
+
+ if (!!(gmch_ctrl & INTEL_GMCH_VGA_DISABLE) == !enable_decode)
+ return 0;
+
+ if (enable_decode)
+ gmch_ctrl &= ~INTEL_GMCH_VGA_DISABLE;
+ else
+ gmch_ctrl |= INTEL_GMCH_VGA_DISABLE;
+
+ if (pci_write_config_word(i915->gmch.pdev, reg, gmch_ctrl)) {
+ drm_err(&i915->drm, "failed to write control word\n");
+ return -EIO;
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/i915/soc/intel_gmch.h b/drivers/gpu/drm/i915/soc/intel_gmch.h
new file mode 100644
index 000000000000..d0133eedc720
--- /dev/null
+++ b/drivers/gpu/drm/i915/soc/intel_gmch.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2023 Intel Corporation
+ */
+
+#ifndef __INTEL_GMCH_H__
+#define __INTEL_GMCH_H__
+
+#include <linux/types.h>
+
+struct drm_i915_private;
+
+int intel_gmch_bridge_setup(struct drm_i915_private *i915);
+void intel_gmch_bar_setup(struct drm_i915_private *i915);
+void intel_gmch_bar_teardown(struct drm_i915_private *i915);
+int intel_gmch_vga_set_state(struct drm_i915_private *i915, bool enable_decode);
+
+#endif /* __INTEL_GMCH_H__ */
diff --git a/drivers/gpu/drm/i915/intel_pch.c b/drivers/gpu/drm/i915/soc/intel_pch.c
index ba9843cb1b13..ba9843cb1b13 100644
--- a/drivers/gpu/drm/i915/intel_pch.c
+++ b/drivers/gpu/drm/i915/soc/intel_pch.c
diff --git a/drivers/gpu/drm/i915/intel_pch.h b/drivers/gpu/drm/i915/soc/intel_pch.h
index 32aff5a70d04..32aff5a70d04 100644
--- a/drivers/gpu/drm/i915/intel_pch.h
+++ b/drivers/gpu/drm/i915/soc/intel_pch.h
diff --git a/drivers/gpu/drm/i915/vlv_sideband.c b/drivers/gpu/drm/i915/vlv_sideband.c
index 6eea6e1a99c0..b98dec3ad817 100644
--- a/drivers/gpu/drm/i915/vlv_sideband.c
+++ b/drivers/gpu/drm/i915/vlv_sideband.c
@@ -9,6 +9,7 @@
#include "vlv_sideband.h"
#include "display/intel_dpio_phy.h"
+#include "display/intel_display_types.h"
/*
* IOSF sideband, see VLV2_SidebandMsg_HAS.docx and
diff --git a/drivers/gpu/drm/imx/Kconfig b/drivers/gpu/drm/imx/Kconfig
index fd5b2471fdf0..e5749927fd6c 100644
--- a/drivers/gpu/drm/imx/Kconfig
+++ b/drivers/gpu/drm/imx/Kconfig
@@ -1,43 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
-config DRM_IMX
- tristate "DRM Support for Freescale i.MX"
- select DRM_KMS_HELPER
- select VIDEOMODE_HELPERS
- select DRM_GEM_DMA_HELPER
- depends on DRM && (ARCH_MXC || ARCH_MULTIPLATFORM || COMPILE_TEST)
- depends on IMX_IPUV3_CORE
- help
- enable i.MX graphics support
-
-config DRM_IMX_PARALLEL_DISPLAY
- tristate "Support for parallel displays"
- select DRM_PANEL
- depends on DRM_IMX
- select VIDEOMODE_HELPERS
-
-config DRM_IMX_TVE
- tristate "Support for TV and VGA displays"
- depends on DRM_IMX
- depends on COMMON_CLK
- select REGMAP_MMIO
- help
- Choose this to enable the internal Television Encoder (TVe)
- found on i.MX53 processors.
-
-config DRM_IMX_LDB
- tristate "Support for LVDS displays"
- depends on DRM_IMX && MFD_SYSCON
- depends on COMMON_CLK
- select DRM_PANEL
- help
- Choose this to enable the internal LVDS Display Bridge (LDB)
- found on i.MX53 and i.MX6 processors.
-
-config DRM_IMX_HDMI
- tristate "Freescale i.MX DRM HDMI"
- select DRM_DW_HDMI
- depends on DRM_IMX && OF
- help
- Choose this if you want to use HDMI on i.MX6.
source "drivers/gpu/drm/imx/dcss/Kconfig"
+source "drivers/gpu/drm/imx/ipuv3/Kconfig"
diff --git a/drivers/gpu/drm/imx/Makefile b/drivers/gpu/drm/imx/Makefile
index b644deffe948..909622864716 100644
--- a/drivers/gpu/drm/imx/Makefile
+++ b/drivers/gpu/drm/imx/Makefile
@@ -1,12 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
-imxdrm-objs := imx-drm-core.o ipuv3-crtc.o ipuv3-plane.o
-
-obj-$(CONFIG_DRM_IMX) += imxdrm.o
-
-obj-$(CONFIG_DRM_IMX_PARALLEL_DISPLAY) += parallel-display.o
-obj-$(CONFIG_DRM_IMX_TVE) += imx-tve.o
-obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o
-
-obj-$(CONFIG_DRM_IMX_HDMI) += dw_hdmi-imx.o
obj-$(CONFIG_DRM_IMX_DCSS) += dcss/
+obj-$(CONFIG_DRM_IMX) += ipuv3/
diff --git a/drivers/gpu/drm/imx/dcss/dcss-dev.c b/drivers/gpu/drm/imx/dcss/dcss-dev.c
index 3f5750cc2673..5d1779ab65c0 100644
--- a/drivers/gpu/drm/imx/dcss/dcss-dev.c
+++ b/drivers/gpu/drm/imx/dcss/dcss-dev.c
@@ -249,16 +249,12 @@ void dcss_dev_destroy(struct dcss_dev *dcss)
kfree(dcss);
}
-#ifdef CONFIG_PM_SLEEP
-int dcss_dev_suspend(struct device *dev)
+static int dcss_dev_suspend(struct device *dev)
{
struct dcss_dev *dcss = dcss_drv_dev_to_dcss(dev);
struct drm_device *ddev = dcss_drv_dev_to_drm(dev);
- struct dcss_kms_dev *kms = container_of(ddev, struct dcss_kms_dev, base);
int ret;
- drm_bridge_connector_disable_hpd(kms->connector);
-
drm_mode_config_helper_suspend(ddev);
if (pm_runtime_suspended(dev))
@@ -273,11 +269,10 @@ int dcss_dev_suspend(struct device *dev)
return 0;
}
-int dcss_dev_resume(struct device *dev)
+static int dcss_dev_resume(struct device *dev)
{
struct dcss_dev *dcss = dcss_drv_dev_to_dcss(dev);
struct drm_device *ddev = dcss_drv_dev_to_drm(dev);
- struct dcss_kms_dev *kms = container_of(ddev, struct dcss_kms_dev, base);
if (pm_runtime_suspended(dev)) {
drm_mode_config_helper_resume(ddev);
@@ -292,14 +287,10 @@ int dcss_dev_resume(struct device *dev)
drm_mode_config_helper_resume(ddev);
- drm_bridge_connector_enable_hpd(kms->connector);
-
return 0;
}
-#endif /* CONFIG_PM_SLEEP */
-#ifdef CONFIG_PM
-int dcss_dev_runtime_suspend(struct device *dev)
+static int dcss_dev_runtime_suspend(struct device *dev)
{
struct dcss_dev *dcss = dcss_drv_dev_to_dcss(dev);
int ret;
@@ -313,7 +304,7 @@ int dcss_dev_runtime_suspend(struct device *dev)
return 0;
}
-int dcss_dev_runtime_resume(struct device *dev)
+static int dcss_dev_runtime_resume(struct device *dev)
{
struct dcss_dev *dcss = dcss_drv_dev_to_dcss(dev);
@@ -325,4 +316,8 @@ int dcss_dev_runtime_resume(struct device *dev)
return 0;
}
-#endif /* CONFIG_PM */
+
+EXPORT_GPL_DEV_PM_OPS(dcss_dev_pm_ops) = {
+ RUNTIME_PM_OPS(dcss_dev_runtime_suspend, dcss_dev_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(dcss_dev_suspend, dcss_dev_resume)
+};
diff --git a/drivers/gpu/drm/imx/dcss/dcss-dev.h b/drivers/gpu/drm/imx/dcss/dcss-dev.h
index 1e582270c6ea..f27b87c09599 100644
--- a/drivers/gpu/drm/imx/dcss/dcss-dev.h
+++ b/drivers/gpu/drm/imx/dcss/dcss-dev.h
@@ -9,6 +9,7 @@
#include <drm/drm_fourcc.h>
#include <drm/drm_plane.h>
#include <linux/io.h>
+#include <linux/pm.h>
#include <video/videomode.h>
#define SET 0x04
@@ -95,13 +96,11 @@ struct dcss_dev *dcss_drv_dev_to_dcss(struct device *dev);
struct drm_device *dcss_drv_dev_to_drm(struct device *dev);
struct dcss_dev *dcss_dev_create(struct device *dev, bool hdmi_output);
void dcss_dev_destroy(struct dcss_dev *dcss);
-int dcss_dev_runtime_suspend(struct device *dev);
-int dcss_dev_runtime_resume(struct device *dev);
-int dcss_dev_suspend(struct device *dev);
-int dcss_dev_resume(struct device *dev);
void dcss_enable_dtg_and_ss(struct dcss_dev *dcss);
void dcss_disable_dtg_and_ss(struct dcss_dev *dcss);
+extern const struct dev_pm_ops dcss_dev_pm_ops;
+
/* BLKCTL */
int dcss_blkctl_init(struct dcss_dev *dcss, unsigned long blkctl_base);
void dcss_blkctl_cfg(struct dcss_blkctl *blkctl);
diff --git a/drivers/gpu/drm/imx/dcss/dcss-drv.c b/drivers/gpu/drm/imx/dcss/dcss-drv.c
index 1c70f70247f6..4f2291610139 100644
--- a/drivers/gpu/drm/imx/dcss/dcss-drv.c
+++ b/drivers/gpu/drm/imx/dcss/dcss-drv.c
@@ -74,8 +74,6 @@ static int dcss_drv_platform_probe(struct platform_device *pdev)
dcss_shutoff:
dcss_dev_destroy(mdrv->dcss);
- dev_set_drvdata(dev, NULL);
-
err:
kfree(mdrv);
return err;
@@ -85,14 +83,9 @@ static int dcss_drv_platform_remove(struct platform_device *pdev)
{
struct dcss_drv *mdrv = dev_get_drvdata(&pdev->dev);
- if (!mdrv)
- return 0;
-
dcss_kms_detach(mdrv->kms);
dcss_dev_destroy(mdrv->dcss);
- dev_set_drvdata(&pdev->dev, NULL);
-
kfree(mdrv);
return 0;
@@ -117,19 +110,13 @@ static const struct of_device_id dcss_of_match[] = {
MODULE_DEVICE_TABLE(of, dcss_of_match);
-static const struct dev_pm_ops dcss_dev_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(dcss_dev_suspend, dcss_dev_resume)
- SET_RUNTIME_PM_OPS(dcss_dev_runtime_suspend,
- dcss_dev_runtime_resume, NULL)
-};
-
static struct platform_driver dcss_platform_driver = {
.probe = dcss_drv_platform_probe,
.remove = dcss_drv_platform_remove,
.driver = {
.name = "imx-dcss",
.of_match_table = dcss_of_match,
- .pm = &dcss_dev_pm,
+ .pm = pm_ptr(&dcss_dev_pm_ops),
},
};
diff --git a/drivers/gpu/drm/imx/dcss/dcss-kms.c b/drivers/gpu/drm/imx/dcss/dcss-kms.c
index 18df3888b7f9..dab5e664920d 100644
--- a/drivers/gpu/drm/imx/dcss/dcss-kms.c
+++ b/drivers/gpu/drm/imx/dcss/dcss-kms.c
@@ -150,7 +150,6 @@ struct dcss_kms_dev *dcss_kms_attach(struct dcss_dev *dcss)
return kms;
cleanup_crtc:
- drm_bridge_connector_disable_hpd(kms->connector);
drm_kms_helper_poll_fini(drm);
dcss_crtc_deinit(crtc, drm);
@@ -166,7 +165,6 @@ void dcss_kms_detach(struct dcss_kms_dev *kms)
struct drm_device *drm = &kms->base;
drm_dev_unregister(drm);
- drm_bridge_connector_disable_hpd(kms->connector);
drm_kms_helper_poll_fini(drm);
drm_atomic_helper_shutdown(drm);
drm_crtc_vblank_off(&kms->crtc.base);
diff --git a/drivers/gpu/drm/imx/ipuv3/Kconfig b/drivers/gpu/drm/imx/ipuv3/Kconfig
new file mode 100644
index 000000000000..bb278a369575
--- /dev/null
+++ b/drivers/gpu/drm/imx/ipuv3/Kconfig
@@ -0,0 +1,41 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config DRM_IMX
+ tristate "DRM Support for Freescale i.MX"
+ select DRM_KMS_HELPER
+ select VIDEOMODE_HELPERS
+ select DRM_GEM_DMA_HELPER
+ depends on DRM && (ARCH_MXC || ARCH_MULTIPLATFORM || COMPILE_TEST)
+ depends on IMX_IPUV3_CORE
+ help
+ enable i.MX graphics support
+
+config DRM_IMX_PARALLEL_DISPLAY
+ tristate "Support for parallel displays"
+ select DRM_PANEL
+ depends on DRM_IMX
+ select VIDEOMODE_HELPERS
+
+config DRM_IMX_TVE
+ tristate "Support for TV and VGA displays"
+ depends on DRM_IMX
+ depends on COMMON_CLK
+ select REGMAP_MMIO
+ help
+ Choose this to enable the internal Television Encoder (TVe)
+ found on i.MX53 processors.
+
+config DRM_IMX_LDB
+ tristate "Support for LVDS displays"
+ depends on DRM_IMX && MFD_SYSCON
+ depends on COMMON_CLK
+ select DRM_PANEL
+ help
+ Choose this to enable the internal LVDS Display Bridge (LDB)
+ found on i.MX53 and i.MX6 processors.
+
+config DRM_IMX_HDMI
+ tristate "Freescale i.MX DRM HDMI"
+ select DRM_DW_HDMI
+ depends on DRM_IMX && OF
+ help
+ Choose this if you want to use HDMI on i.MX6.
diff --git a/drivers/gpu/drm/imx/ipuv3/Makefile b/drivers/gpu/drm/imx/ipuv3/Makefile
new file mode 100644
index 000000000000..21cdcc2faabc
--- /dev/null
+++ b/drivers/gpu/drm/imx/ipuv3/Makefile
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0
+
+imxdrm-objs := imx-drm-core.o ipuv3-crtc.o ipuv3-plane.o
+
+obj-$(CONFIG_DRM_IMX) += imxdrm.o
+
+obj-$(CONFIG_DRM_IMX_PARALLEL_DISPLAY) += parallel-display.o
+obj-$(CONFIG_DRM_IMX_TVE) += imx-tve.o
+obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o
+
+obj-$(CONFIG_DRM_IMX_HDMI) += dw_hdmi-imx.o
diff --git a/drivers/gpu/drm/imx/dw_hdmi-imx.c b/drivers/gpu/drm/imx/ipuv3/dw_hdmi-imx.c
index a2277a0d6d06..a2277a0d6d06 100644
--- a/drivers/gpu/drm/imx/dw_hdmi-imx.c
+++ b/drivers/gpu/drm/imx/ipuv3/dw_hdmi-imx.c
diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/ipuv3/imx-drm-core.c
index e060fa6cbcb9..e060fa6cbcb9 100644
--- a/drivers/gpu/drm/imx/imx-drm-core.c
+++ b/drivers/gpu/drm/imx/ipuv3/imx-drm-core.c
diff --git a/drivers/gpu/drm/imx/imx-drm.h b/drivers/gpu/drm/imx/ipuv3/imx-drm.h
index e721bebda2bd..e721bebda2bd 100644
--- a/drivers/gpu/drm/imx/imx-drm.h
+++ b/drivers/gpu/drm/imx/ipuv3/imx-drm.h
diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/ipuv3/imx-ldb.c
index c45fc8f4744d..c45fc8f4744d 100644
--- a/drivers/gpu/drm/imx/imx-ldb.c
+++ b/drivers/gpu/drm/imx/ipuv3/imx-ldb.c
diff --git a/drivers/gpu/drm/imx/imx-tve.c b/drivers/gpu/drm/imx/ipuv3/imx-tve.c
index d6832f506322..d6832f506322 100644
--- a/drivers/gpu/drm/imx/imx-tve.c
+++ b/drivers/gpu/drm/imx/ipuv3/imx-tve.c
diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3/ipuv3-crtc.c
index 5f26090b0c98..5f26090b0c98 100644
--- a/drivers/gpu/drm/imx/ipuv3-crtc.c
+++ b/drivers/gpu/drm/imx/ipuv3/ipuv3-crtc.c
diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c
index 80142d9a4a55..80142d9a4a55 100644
--- a/drivers/gpu/drm/imx/ipuv3-plane.c
+++ b/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c
diff --git a/drivers/gpu/drm/imx/ipuv3-plane.h b/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.h
index 6d544e6ce63f..6d544e6ce63f 100644
--- a/drivers/gpu/drm/imx/ipuv3-plane.h
+++ b/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.h
diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/ipuv3/parallel-display.c
index 0fa0b590830b..0fa0b590830b 100644
--- a/drivers/gpu/drm/imx/parallel-display.c
+++ b/drivers/gpu/drm/imx/ipuv3/parallel-display.c
diff --git a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
index 3d5af44bf92d..5ec75e9ba499 100644
--- a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
+++ b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
@@ -26,7 +26,6 @@
#include <drm/drm_bridge_connector.h>
#include <drm/drm_color_mgmt.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_damage_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_encoder.h>
diff --git a/drivers/gpu/drm/kmb/kmb_crtc.c b/drivers/gpu/drm/kmb/kmb_crtc.c
index 06613ffeaaf8..647872f65bff 100644
--- a/drivers/gpu/drm/kmb/kmb_crtc.c
+++ b/drivers/gpu/drm/kmb/kmb_crtc.c
@@ -8,7 +8,6 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_print.h>
#include <drm/drm_vblank.h>
#include <drm/drm_modeset_helper_vtables.h>
diff --git a/drivers/gpu/drm/kmb/kmb_plane.c b/drivers/gpu/drm/kmb/kmb_plane.c
index d172a302f902..9e0562aa2bcb 100644
--- a/drivers/gpu/drm/kmb/kmb_plane.c
+++ b/drivers/gpu/drm/kmb/kmb_plane.c
@@ -7,7 +7,6 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_blend.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_dma_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
diff --git a/drivers/gpu/drm/logicvc/logicvc_drm.c b/drivers/gpu/drm/logicvc/logicvc_drm.c
index 9de24d9f0c96..2fb23697740a 100644
--- a/drivers/gpu/drm/logicvc/logicvc_drm.c
+++ b/drivers/gpu/drm/logicvc/logicvc_drm.c
@@ -301,6 +301,7 @@ static int logicvc_drm_probe(struct platform_device *pdev)
struct regmap *regmap = NULL;
struct resource res;
void __iomem *base;
+ unsigned int preferred_bpp;
int irq;
int ret;
@@ -438,7 +439,17 @@ static int logicvc_drm_probe(struct platform_device *pdev)
goto error_mode;
}
- drm_fbdev_generic_setup(drm_dev, drm_dev->mode_config.preferred_depth);
+ switch (drm_dev->mode_config.preferred_depth) {
+ case 16:
+ preferred_bpp = 16;
+ break;
+ case 24:
+ case 32:
+ default:
+ preferred_bpp = 32;
+ break;
+ }
+ drm_fbdev_generic_setup(drm_dev, preferred_bpp);
return 0;
diff --git a/drivers/gpu/drm/logicvc/logicvc_interface.c b/drivers/gpu/drm/logicvc/logicvc_interface.c
index 815cebb4c4ca..689049d395c0 100644
--- a/drivers/gpu/drm/logicvc/logicvc_interface.c
+++ b/drivers/gpu/drm/logicvc/logicvc_interface.c
@@ -9,7 +9,6 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_connector.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_encoder.h>
#include <drm/drm_gem_dma_helper.h>
diff --git a/drivers/gpu/drm/logicvc/logicvc_mode.c b/drivers/gpu/drm/logicvc/logicvc_mode.c
index 9971950ebd4e..3cf04b70bd27 100644
--- a/drivers/gpu/drm/logicvc/logicvc_mode.c
+++ b/drivers/gpu/drm/logicvc/logicvc_mode.c
@@ -8,7 +8,6 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
diff --git a/drivers/gpu/drm/mediatek/Kconfig b/drivers/gpu/drm/mediatek/Kconfig
index 369e495d0c3e..b451dee64d34 100644
--- a/drivers/gpu/drm/mediatek/Kconfig
+++ b/drivers/gpu/drm/mediatek/Kconfig
@@ -7,7 +7,6 @@ config DRM_MEDIATEK
depends on HAVE_ARM_SMCCC
depends on OF
depends on MTK_MMSYS
- select DRM_GEM_DMA_HELPER
select DRM_KMS_HELPER
select DRM_MIPI_DSI
select DRM_PANEL
diff --git a/drivers/gpu/drm/mediatek/mtk_cec.c b/drivers/gpu/drm/mediatek/mtk_cec.c
index cdfa648910b2..b640bc0559e7 100644
--- a/drivers/gpu/drm/mediatek/mtk_cec.c
+++ b/drivers/gpu/drm/mediatek/mtk_cec.c
@@ -12,6 +12,8 @@
#include <linux/platform_device.h>
#include "mtk_cec.h"
+#include "mtk_hdmi.h"
+#include "mtk_drm_drv.h"
#define TR_CONFIG 0x00
#define CLEAR_CEC_IRQ BIT(15)
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_aal.c b/drivers/gpu/drm/mediatek/mtk_disp_aal.c
index 0f9d7efb61d7..434e8a9ce8ab 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_aal.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_aal.c
@@ -14,6 +14,7 @@
#include "mtk_disp_drv.h"
#include "mtk_drm_crtc.h"
#include "mtk_drm_ddp_comp.h"
+#include "mtk_drm_drv.h"
#define DISP_AAL_EN 0x0000
#define AAL_EN BIT(0)
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c b/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c
index 3a53ebc4e172..1773379b2439 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c
@@ -14,6 +14,7 @@
#include "mtk_disp_drv.h"
#include "mtk_drm_crtc.h"
#include "mtk_drm_ddp_comp.h"
+#include "mtk_drm_drv.h"
#define DISP_CCORR_EN 0x0000
#define CCORR_EN BIT(0)
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_color.c b/drivers/gpu/drm/mediatek/mtk_disp_color.c
index 473f5bb5cbad..cac9206079e7 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_color.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_color.c
@@ -14,6 +14,7 @@
#include "mtk_disp_drv.h"
#include "mtk_drm_crtc.h"
#include "mtk_drm_ddp_comp.h"
+#include "mtk_drm_drv.h"
#define DISP_COLOR_CFG_MAIN 0x0400
#define DISP_COLOR_START_MT2701 0x0f00
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
index bbd558a036ec..c844942603f7 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
@@ -14,6 +14,7 @@
#include "mtk_disp_drv.h"
#include "mtk_drm_crtc.h"
#include "mtk_drm_ddp_comp.h"
+#include "mtk_drm_drv.h"
#define DISP_GAMMA_EN 0x0000
#define GAMMA_EN BIT(0)
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
index 84daeaffab6a..9d8c986700ee 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
@@ -19,6 +19,7 @@
#include "mtk_disp_drv.h"
#include "mtk_drm_crtc.h"
#include "mtk_drm_ddp_comp.h"
+#include "mtk_drm_drv.h"
#define DISP_REG_OVL_INTEN 0x0004
#define OVL_FME_CPL_INT BIT(1)
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
index 0ec2e4049e07..a5a0c3bac35d 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
@@ -17,6 +17,7 @@
#include "mtk_disp_drv.h"
#include "mtk_drm_crtc.h"
#include "mtk_drm_ddp_comp.h"
+#include "mtk_drm_drv.h"
#define DISP_REG_RDMA_INT_ENABLE 0x0000
#define DISP_REG_RDMA_INT_STATUS 0x0004
diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
index 9d085c05c49c..1f94fcc144d3 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -1693,7 +1693,7 @@ static int mtk_dp_training(struct mtk_dp *mtk_dp)
break;
default:
return -EINVAL;
- };
+ }
continue;
}
@@ -1981,7 +1981,7 @@ static struct edid *mtk_dp_get_edid(struct drm_bridge *bridge,
struct cea_sad *sads;
if (!enabled) {
- drm_bridge_chain_pre_enable(bridge);
+ drm_atomic_bridge_chain_pre_enable(bridge, connector->state->state);
/* power on aux */
mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
@@ -2019,7 +2019,7 @@ static struct edid *mtk_dp_get_edid(struct drm_bridge *bridge,
DP_PWR_STATE_BANDGAP_TPLL,
DP_PWR_STATE_MASK);
- drm_bridge_chain_post_disable(bridge);
+ drm_atomic_bridge_chain_post_disable(bridge, connector->state->state);
}
return new_edid;
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
index 4317595a15d1..948a53f1f4b3 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
@@ -14,6 +14,7 @@
#include <linux/of_graph.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
+#include <linux/soc/mediatek/mtk-mmsys.h>
#include <linux/types.h>
#include <video/videomode.h>
@@ -29,6 +30,7 @@
#include "mtk_disp_drv.h"
#include "mtk_dpi_regs.h"
#include "mtk_drm_ddp_comp.h"
+#include "mtk_drm_drv.h"
enum mtk_dpi_out_bit_num {
MTK_DPI_OUT_BIT_NUM_8BITS,
@@ -66,6 +68,7 @@ struct mtk_dpi {
struct drm_connector *connector;
void __iomem *regs;
struct device *dev;
+ struct device *mmsys_dev;
struct clk *engine_clk;
struct clk *pixel_clk;
struct clk *tvd_clk;
@@ -134,6 +137,7 @@ struct mtk_dpi_yc_limit {
* @yuv422_en_bit: Enable bit of yuv422.
* @csc_enable_bit: Enable bit of CSC.
* @pixels_per_iter: Quantity of transferred pixels per iteration.
+ * @edge_cfg_in_mmsys: If the edge configuration for DPI's output needs to be set in MMSYS.
*/
struct mtk_dpi_conf {
unsigned int (*cal_factor)(int clock);
@@ -152,6 +156,7 @@ struct mtk_dpi_conf {
u32 yuv422_en_bit;
u32 csc_enable_bit;
u32 pixels_per_iter;
+ bool edge_cfg_in_mmsys;
};
static void mtk_dpi_mask(struct mtk_dpi *dpi, u32 offset, u32 val, u32 mask)
@@ -448,8 +453,12 @@ static void mtk_dpi_dual_edge(struct mtk_dpi *dpi)
mtk_dpi_mask(dpi, DPI_OUTPUT_SETTING,
dpi->output_fmt == MEDIA_BUS_FMT_RGB888_2X12_LE ?
EDGE_SEL : 0, EDGE_SEL);
+ if (dpi->conf->edge_cfg_in_mmsys)
+ mtk_mmsys_ddp_dpi_fmt_config(dpi->mmsys_dev, MTK_DPI_RGB888_DDR_CON);
} else {
mtk_dpi_mask(dpi, DPI_DDR_SETTING, DDR_EN | DDR_4PHASE, 0);
+ if (dpi->conf->edge_cfg_in_mmsys)
+ mtk_mmsys_ddp_dpi_fmt_config(dpi->mmsys_dev, MTK_DPI_RGB888_SDR_CON);
}
}
@@ -777,8 +786,10 @@ static int mtk_dpi_bind(struct device *dev, struct device *master, void *data)
{
struct mtk_dpi *dpi = dev_get_drvdata(dev);
struct drm_device *drm_dev = data;
+ struct mtk_drm_private *priv = drm_dev->dev_private;
int ret;
+ dpi->mmsys_dev = priv->mmsys_dev;
ret = drm_simple_encoder_init(drm_dev, &dpi->encoder,
DRM_MODE_ENCODER_TMDS);
if (ret) {
@@ -929,6 +940,24 @@ static const struct mtk_dpi_conf mt8183_conf = {
.csc_enable_bit = CSC_ENABLE,
};
+static const struct mtk_dpi_conf mt8186_conf = {
+ .cal_factor = mt8183_calculate_factor,
+ .reg_h_fre_con = 0xe0,
+ .max_clock_khz = 150000,
+ .output_fmts = mt8183_output_fmts,
+ .num_output_fmts = ARRAY_SIZE(mt8183_output_fmts),
+ .edge_cfg_in_mmsys = true,
+ .pixels_per_iter = 1,
+ .is_ck_de_pol = true,
+ .swap_input_support = true,
+ .support_direct_pin = true,
+ .dimension_mask = HPW_MASK,
+ .hvsize_mask = HSIZE_MASK,
+ .channel_swap_shift = CH_SWAP,
+ .yuv422_en_bit = YUV422_EN,
+ .csc_enable_bit = CSC_ENABLE,
+};
+
static const struct mtk_dpi_conf mt8188_dpintf_conf = {
.cal_factor = mt8195_dpintf_calculate_factor,
.max_clock_khz = 600000,
@@ -1093,6 +1122,9 @@ static const struct of_device_id mtk_dpi_of_ids[] = {
{ .compatible = "mediatek,mt8183-dpi",
.data = &mt8183_conf,
},
+ { .compatible = "mediatek,mt8186-dpi",
+ .data = &mt8186_conf,
+ },
{ .compatible = "mediatek,mt8188-dp-intf",
.data = &mt8188_dpintf_conf,
},
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
index 112615817dcb..5071f1263216 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
@@ -945,6 +945,8 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
mtk_crtc->planes = devm_kcalloc(dev, num_comp_planes,
sizeof(struct drm_plane), GFP_KERNEL);
+ if (!mtk_crtc->planes)
+ return -ENOMEM;
for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
ret = mtk_drm_crtc_init_comp_planes(drm_dev, mtk_crtc, i,
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index cd5b18ef7951..a13b36ac03a1 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -20,8 +20,8 @@
#include <drm/drm_fbdev_generic.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_gem.h>
-#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_ioctl.h>
#include <drm/drm_of.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
@@ -520,6 +520,7 @@ static int mtk_drm_bind(struct device *dev)
err_deinit:
mtk_drm_kms_deinit(drm);
err_free:
+ private->drm = NULL;
drm_dev_put(drm);
return ret;
}
@@ -637,6 +638,8 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
.data = (void *)MTK_DPI },
{ .compatible = "mediatek,mt8183-dpi",
.data = (void *)MTK_DPI },
+ { .compatible = "mediatek,mt8186-dpi",
+ .data = (void *)MTK_DPI },
{ .compatible = "mediatek,mt8188-dp-intf",
.data = (void *)MTK_DP_INTF },
{ .compatible = "mediatek,mt8192-dpi",
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_gem.c b/drivers/gpu/drm/mediatek/mtk_drm_gem.c
index 47e96b0289f9..a25b28d3ee90 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_gem.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_gem.c
@@ -16,13 +16,18 @@
static int mtk_drm_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma);
+static const struct vm_operations_struct vm_ops = {
+ .open = drm_gem_vm_open,
+ .close = drm_gem_vm_close,
+};
+
static const struct drm_gem_object_funcs mtk_drm_gem_object_funcs = {
.free = mtk_drm_gem_free_object,
.get_sg_table = mtk_gem_prime_get_sg_table,
.vmap = mtk_drm_gem_prime_vmap,
.vunmap = mtk_drm_gem_prime_vunmap,
.mmap = mtk_drm_gem_object_mmap,
- .vm_ops = &drm_gem_dma_vm_ops,
+ .vm_ops = &vm_ops,
};
static struct mtk_drm_gem_obj *mtk_drm_gem_init(struct drm_device *dev,
@@ -158,14 +163,12 @@ static int mtk_drm_gem_object_mmap(struct drm_gem_object *obj,
* dma_alloc_attrs() allocated a struct page table for mtk_gem, so clear
* VM_PFNMAP flag that was set by drm_gem_mmap_obj()/drm_gem_mmap().
*/
- vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
+ vm_flags_set(vma, VM_IO | VM_DONTEXPAND | VM_DONTDUMP);
vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
ret = dma_mmap_attrs(priv->dma_dev, vma, mtk_gem->cookie,
mtk_gem->dma_addr, obj->size, mtk_gem->dma_attrs);
- if (ret)
- drm_gem_vm_close(vma);
return ret;
}
@@ -262,6 +265,6 @@ void mtk_drm_gem_prime_vunmap(struct drm_gem_object *obj,
return;
vunmap(vaddr);
- mtk_gem->kvaddr = 0;
+ mtk_gem->kvaddr = NULL;
kfree(mtk_gem->pages);
}
diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
index 3b7d13028fb6..7d5250351193 100644
--- a/drivers/gpu/drm/mediatek/mtk_dsi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
@@ -28,6 +28,7 @@
#include "mtk_disp_drv.h"
#include "mtk_drm_ddp_comp.h"
+#include "mtk_drm_drv.h"
#define DSI_START 0x00
@@ -721,7 +722,7 @@ static void mtk_dsi_lane_ready(struct mtk_dsi *dsi)
mtk_dsi_clk_ulp_mode_leave(dsi);
mtk_dsi_lane0_ulp_mode_leave(dsi);
mtk_dsi_clk_hs_mode(dsi, 0);
- msleep(20);
+ usleep_range(1000, 3000);
/* The reaction time after pulling up the mipi signal for dsi_rx */
}
}
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c b/drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c
index 6207eac88550..2fc9214ffa82 100644
--- a/drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c
@@ -19,6 +19,9 @@
#include <linux/of_irq.h>
#include <linux/of_platform.h>
+#include "mtk_drm_drv.h"
+#include "mtk_hdmi.h"
+
#define SIF1_CLOK (288)
#define DDC_DDCMCTL0 (0x0)
#define DDCM_ODRAIN BIT(31)
diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c
index 5cd2b2ebbbd3..534621a13a34 100644
--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c
+++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c
@@ -140,7 +140,6 @@ struct meson_dw_hdmi {
struct reset_control *hdmitx_apb;
struct reset_control *hdmitx_ctrl;
struct reset_control *hdmitx_phy;
- struct regulator *hdmi_supply;
u32 irq_stat;
struct dw_hdmi *hdmi;
struct drm_bridge *bridge;
@@ -665,11 +664,6 @@ static void meson_dw_hdmi_init(struct meson_dw_hdmi *meson_dw_hdmi)
}
-static void meson_disable_regulator(void *data)
-{
- regulator_disable(data);
-}
-
static void meson_disable_clk(void *data)
{
clk_disable_unprepare(data);
@@ -723,20 +717,9 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
meson_dw_hdmi->data = match;
dw_plat_data = &meson_dw_hdmi->dw_plat_data;
- meson_dw_hdmi->hdmi_supply = devm_regulator_get_optional(dev, "hdmi");
- if (IS_ERR(meson_dw_hdmi->hdmi_supply)) {
- if (PTR_ERR(meson_dw_hdmi->hdmi_supply) == -EPROBE_DEFER)
- return -EPROBE_DEFER;
- meson_dw_hdmi->hdmi_supply = NULL;
- } else {
- ret = regulator_enable(meson_dw_hdmi->hdmi_supply);
- if (ret)
- return ret;
- ret = devm_add_action_or_reset(dev, meson_disable_regulator,
- meson_dw_hdmi->hdmi_supply);
- if (ret)
- return ret;
- }
+ ret = devm_regulator_get_enable_optional(dev, "hdmi");
+ if (ret < 0)
+ return ret;
meson_dw_hdmi->hdmitx_apb = devm_reset_control_get_exclusive(dev,
"hdmitx_apb");
diff --git a/drivers/gpu/drm/mga/Makefile b/drivers/gpu/drm/mga/Makefile
deleted file mode 100644
index db07c7fcc996..000000000000
--- a/drivers/gpu/drm/mga/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Makefile for the drm device driver. This driver provides support for the
-# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
-
-mga-y := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o
-
-mga-$(CONFIG_COMPAT) += mga_ioc32.o
-
-obj-$(CONFIG_DRM_MGA) += mga.o
-
diff --git a/drivers/gpu/drm/mga/mga_dma.c b/drivers/gpu/drm/mga/mga_dma.c
deleted file mode 100644
index 331c2f0da57a..000000000000
--- a/drivers/gpu/drm/mga/mga_dma.c
+++ /dev/null
@@ -1,1168 +0,0 @@
-/* mga_dma.c -- DMA support for mga g200/g400 -*- linux-c -*-
- * Created: Mon Dec 13 01:50:01 1999 by jhartmann@precisioninsight.com
- *
- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software 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 (including the next
- * paragraph) 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
- * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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 mga_dma.c
- * DMA support for MGA G200 / G400.
- *
- * \author Rickard E. (Rik) Faith <faith@valinux.com>
- * \author Jeff Hartmann <jhartmann@valinux.com>
- * \author Keith Whitwell <keith@tungstengraphics.com>
- * \author Gareth Hughes <gareth@valinux.com>
- */
-
-#include <linux/delay.h>
-
-#include "mga_drv.h"
-
-#define MGA_DEFAULT_USEC_TIMEOUT 10000
-#define MGA_FREELIST_DEBUG 0
-
-#define MINIMAL_CLEANUP 0
-#define FULL_CLEANUP 1
-static int mga_do_cleanup_dma(struct drm_device *dev, int full_cleanup);
-
-/* ================================================================
- * Engine control
- */
-
-int mga_do_wait_for_idle(drm_mga_private_t *dev_priv)
-{
- u32 status = 0;
- int i;
- DRM_DEBUG("\n");
-
- for (i = 0; i < dev_priv->usec_timeout; i++) {
- status = MGA_READ(MGA_STATUS) & MGA_ENGINE_IDLE_MASK;
- if (status == MGA_ENDPRDMASTS) {
- MGA_WRITE8(MGA_CRTC_INDEX, 0);
- return 0;
- }
- udelay(1);
- }
-
-#if MGA_DMA_DEBUG
- DRM_ERROR("failed!\n");
- DRM_INFO(" status=0x%08x\n", status);
-#endif
- return -EBUSY;
-}
-
-static int mga_do_dma_reset(drm_mga_private_t *dev_priv)
-{
- drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_mga_primary_buffer_t *primary = &dev_priv->prim;
-
- DRM_DEBUG("\n");
-
- /* The primary DMA stream should look like new right about now.
- */
- primary->tail = 0;
- primary->space = primary->size;
- primary->last_flush = 0;
-
- sarea_priv->last_wrap = 0;
-
- /* FIXME: Reset counters, buffer ages etc...
- */
-
- /* FIXME: What else do we need to reinitialize? WARP stuff?
- */
-
- return 0;
-}
-
-/* ================================================================
- * Primary DMA stream
- */
-
-void mga_do_dma_flush(drm_mga_private_t *dev_priv)
-{
- drm_mga_primary_buffer_t *primary = &dev_priv->prim;
- u32 head, tail;
- u32 status = 0;
- int i;
- DMA_LOCALS;
- DRM_DEBUG("\n");
-
- /* We need to wait so that we can do an safe flush */
- for (i = 0; i < dev_priv->usec_timeout; i++) {
- status = MGA_READ(MGA_STATUS) & MGA_ENGINE_IDLE_MASK;
- if (status == MGA_ENDPRDMASTS)
- break;
- udelay(1);
- }
-
- if (primary->tail == primary->last_flush) {
- DRM_DEBUG(" bailing out...\n");
- return;
- }
-
- tail = primary->tail + dev_priv->primary->offset;
-
- /* We need to pad the stream between flushes, as the card
- * actually (partially?) reads the first of these commands.
- * See page 4-16 in the G400 manual, middle of the page or so.
- */
- BEGIN_DMA(1);
-
- DMA_BLOCK(MGA_DMAPAD, 0x00000000,
- MGA_DMAPAD, 0x00000000,
- MGA_DMAPAD, 0x00000000, MGA_DMAPAD, 0x00000000);
-
- ADVANCE_DMA();
-
- primary->last_flush = primary->tail;
-
- head = MGA_READ(MGA_PRIMADDRESS);
-
- if (head <= tail)
- primary->space = primary->size - primary->tail;
- else
- primary->space = head - tail;
-
- DRM_DEBUG(" head = 0x%06lx\n", (unsigned long)(head - dev_priv->primary->offset));
- DRM_DEBUG(" tail = 0x%06lx\n", (unsigned long)(tail - dev_priv->primary->offset));
- DRM_DEBUG(" space = 0x%06x\n", primary->space);
-
- mga_flush_write_combine();
- MGA_WRITE(MGA_PRIMEND, tail | dev_priv->dma_access);
-
- DRM_DEBUG("done.\n");
-}
-
-void mga_do_dma_wrap_start(drm_mga_private_t *dev_priv)
-{
- drm_mga_primary_buffer_t *primary = &dev_priv->prim;
- u32 head, tail;
- DMA_LOCALS;
- DRM_DEBUG("\n");
-
- BEGIN_DMA_WRAP();
-
- DMA_BLOCK(MGA_DMAPAD, 0x00000000,
- MGA_DMAPAD, 0x00000000,
- MGA_DMAPAD, 0x00000000, MGA_DMAPAD, 0x00000000);
-
- ADVANCE_DMA();
-
- tail = primary->tail + dev_priv->primary->offset;
-
- primary->tail = 0;
- primary->last_flush = 0;
- primary->last_wrap++;
-
- head = MGA_READ(MGA_PRIMADDRESS);
-
- if (head == dev_priv->primary->offset)
- primary->space = primary->size;
- else
- primary->space = head - dev_priv->primary->offset;
-
- DRM_DEBUG(" head = 0x%06lx\n", (unsigned long)(head - dev_priv->primary->offset));
- DRM_DEBUG(" tail = 0x%06x\n", primary->tail);
- DRM_DEBUG(" wrap = %d\n", primary->last_wrap);
- DRM_DEBUG(" space = 0x%06x\n", primary->space);
-
- mga_flush_write_combine();
- MGA_WRITE(MGA_PRIMEND, tail | dev_priv->dma_access);
-
- set_bit(0, &primary->wrapped);
- DRM_DEBUG("done.\n");
-}
-
-void mga_do_dma_wrap_end(drm_mga_private_t *dev_priv)
-{
- drm_mga_primary_buffer_t *primary = &dev_priv->prim;
- drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
- u32 head = dev_priv->primary->offset;
- DRM_DEBUG("\n");
-
- sarea_priv->last_wrap++;
- DRM_DEBUG(" wrap = %d\n", sarea_priv->last_wrap);
-
- mga_flush_write_combine();
- MGA_WRITE(MGA_PRIMADDRESS, head | MGA_DMA_GENERAL);
-
- clear_bit(0, &primary->wrapped);
- DRM_DEBUG("done.\n");
-}
-
-/* ================================================================
- * Freelist management
- */
-
-#define MGA_BUFFER_USED (~0)
-#define MGA_BUFFER_FREE 0
-
-#if MGA_FREELIST_DEBUG
-static void mga_freelist_print(struct drm_device *dev)
-{
- drm_mga_private_t *dev_priv = dev->dev_private;
- drm_mga_freelist_t *entry;
-
- DRM_INFO("\n");
- DRM_INFO("current dispatch: last=0x%x done=0x%x\n",
- dev_priv->sarea_priv->last_dispatch,
- (unsigned int)(MGA_READ(MGA_PRIMADDRESS) -
- dev_priv->primary->offset));
- DRM_INFO("current freelist:\n");
-
- for (entry = dev_priv->head->next; entry; entry = entry->next) {
- DRM_INFO(" %p idx=%2d age=0x%x 0x%06lx\n",
- entry, entry->buf->idx, entry->age.head,
- (unsigned long)(entry->age.head - dev_priv->primary->offset));
- }
- DRM_INFO("\n");
-}
-#endif
-
-static int mga_freelist_init(struct drm_device *dev, drm_mga_private_t *dev_priv)
-{
- struct drm_device_dma *dma = dev->dma;
- struct drm_buf *buf;
- drm_mga_buf_priv_t *buf_priv;
- drm_mga_freelist_t *entry;
- int i;
- DRM_DEBUG("count=%d\n", dma->buf_count);
-
- dev_priv->head = kzalloc(sizeof(drm_mga_freelist_t), GFP_KERNEL);
- if (dev_priv->head == NULL)
- return -ENOMEM;
-
- SET_AGE(&dev_priv->head->age, MGA_BUFFER_USED, 0);
-
- for (i = 0; i < dma->buf_count; i++) {
- buf = dma->buflist[i];
- buf_priv = buf->dev_private;
-
- entry = kzalloc(sizeof(drm_mga_freelist_t), GFP_KERNEL);
- if (entry == NULL)
- return -ENOMEM;
-
- entry->next = dev_priv->head->next;
- entry->prev = dev_priv->head;
- SET_AGE(&entry->age, MGA_BUFFER_FREE, 0);
- entry->buf = buf;
-
- if (dev_priv->head->next != NULL)
- dev_priv->head->next->prev = entry;
- if (entry->next == NULL)
- dev_priv->tail = entry;
-
- buf_priv->list_entry = entry;
- buf_priv->discard = 0;
- buf_priv->dispatched = 0;
-
- dev_priv->head->next = entry;
- }
-
- return 0;
-}
-
-static void mga_freelist_cleanup(struct drm_device *dev)
-{
- drm_mga_private_t *dev_priv = dev->dev_private;
- drm_mga_freelist_t *entry;
- drm_mga_freelist_t *next;
- DRM_DEBUG("\n");
-
- entry = dev_priv->head;
- while (entry) {
- next = entry->next;
- kfree(entry);
- entry = next;
- }
-
- dev_priv->head = dev_priv->tail = NULL;
-}
-
-#if 0
-/* FIXME: Still needed?
- */
-static void mga_freelist_reset(struct drm_device *dev)
-{
- struct drm_device_dma *dma = dev->dma;
- struct drm_buf *buf;
- drm_mga_buf_priv_t *buf_priv;
- int i;
-
- for (i = 0; i < dma->buf_count; i++) {
- buf = dma->buflist[i];
- buf_priv = buf->dev_private;
- SET_AGE(&buf_priv->list_entry->age, MGA_BUFFER_FREE, 0);
- }
-}
-#endif
-
-static struct drm_buf *mga_freelist_get(struct drm_device * dev)
-{
- drm_mga_private_t *dev_priv = dev->dev_private;
- drm_mga_freelist_t *next;
- drm_mga_freelist_t *prev;
- drm_mga_freelist_t *tail = dev_priv->tail;
- u32 head, wrap;
- DRM_DEBUG("\n");
-
- head = MGA_READ(MGA_PRIMADDRESS);
- wrap = dev_priv->sarea_priv->last_wrap;
-
- DRM_DEBUG(" tail=0x%06lx %d\n",
- tail->age.head ?
- (unsigned long)(tail->age.head - dev_priv->primary->offset) : 0,
- tail->age.wrap);
- DRM_DEBUG(" head=0x%06lx %d\n",
- (unsigned long)(head - dev_priv->primary->offset), wrap);
-
- if (TEST_AGE(&tail->age, head, wrap)) {
- prev = dev_priv->tail->prev;
- next = dev_priv->tail;
- prev->next = NULL;
- next->prev = next->next = NULL;
- dev_priv->tail = prev;
- SET_AGE(&next->age, MGA_BUFFER_USED, 0);
- return next->buf;
- }
-
- DRM_DEBUG("returning NULL!\n");
- return NULL;
-}
-
-int mga_freelist_put(struct drm_device *dev, struct drm_buf *buf)
-{
- drm_mga_private_t *dev_priv = dev->dev_private;
- drm_mga_buf_priv_t *buf_priv = buf->dev_private;
- drm_mga_freelist_t *head, *entry, *prev;
-
- DRM_DEBUG("age=0x%06lx wrap=%d\n",
- (unsigned long)(buf_priv->list_entry->age.head -
- dev_priv->primary->offset),
- buf_priv->list_entry->age.wrap);
-
- entry = buf_priv->list_entry;
- head = dev_priv->head;
-
- if (buf_priv->list_entry->age.head == MGA_BUFFER_USED) {
- SET_AGE(&entry->age, MGA_BUFFER_FREE, 0);
- prev = dev_priv->tail;
- prev->next = entry;
- entry->prev = prev;
- entry->next = NULL;
- } else {
- prev = head->next;
- head->next = entry;
- prev->prev = entry;
- entry->prev = head;
- entry->next = prev;
- }
-
- return 0;
-}
-
-/* ================================================================
- * DMA initialization, cleanup
- */
-
-int mga_driver_load(struct drm_device *dev, unsigned long flags)
-{
- struct pci_dev *pdev = to_pci_dev(dev->dev);
- drm_mga_private_t *dev_priv;
- int ret;
-
- /* There are PCI versions of the G450. These cards have the
- * same PCI ID as the AGP G450, but have an additional PCI-to-PCI
- * bridge chip. We detect these cards, which are not currently
- * supported by this driver, by looking at the device ID of the
- * bus the "card" is on. If vendor is 0x3388 (Hint Corp) and the
- * device is 0x0021 (HB6 Universal PCI-PCI bridge), we reject the
- * device.
- */
- if ((pdev->device == 0x0525) && pdev->bus->self
- && (pdev->bus->self->vendor == 0x3388)
- && (pdev->bus->self->device == 0x0021)
- && dev->agp) {
- /* FIXME: This should be quirked in the pci core, but oh well
- * the hw probably stopped existing. */
- arch_phys_wc_del(dev->agp->agp_mtrr);
- kfree(dev->agp);
- dev->agp = NULL;
- }
- dev_priv = kzalloc(sizeof(drm_mga_private_t), GFP_KERNEL);
- if (!dev_priv)
- return -ENOMEM;
-
- dev->dev_private = (void *)dev_priv;
-
- dev_priv->usec_timeout = MGA_DEFAULT_USEC_TIMEOUT;
- dev_priv->chipset = flags;
-
- pci_set_master(pdev);
-
- dev_priv->mmio_base = pci_resource_start(pdev, 1);
- dev_priv->mmio_size = pci_resource_len(pdev, 1);
-
- ret = drm_vblank_init(dev, 1);
-
- if (ret) {
- (void) mga_driver_unload(dev);
- return ret;
- }
-
- return 0;
-}
-
-#if IS_ENABLED(CONFIG_AGP)
-/*
- * Bootstrap the driver for AGP DMA.
- *
- * \todo
- * Investigate whether there is any benefit to storing the WARP microcode in
- * AGP memory. If not, the microcode may as well always be put in PCI
- * memory.
- *
- * \todo
- * This routine needs to set dma_bs->agp_mode to the mode actually configured
- * in the hardware. Looking just at the Linux AGP driver code, I don't see
- * an easy way to determine this.
- *
- * \sa mga_do_dma_bootstrap, mga_do_pci_dma_bootstrap
- */
-static int mga_do_agp_dma_bootstrap(struct drm_device *dev,
- drm_mga_dma_bootstrap_t *dma_bs)
-{
- drm_mga_private_t *const dev_priv =
- (drm_mga_private_t *) dev->dev_private;
- unsigned int warp_size = MGA_WARP_UCODE_SIZE;
- int err;
- unsigned offset;
- const unsigned secondary_size = dma_bs->secondary_bin_count
- * dma_bs->secondary_bin_size;
- const unsigned agp_size = (dma_bs->agp_size << 20);
- struct drm_buf_desc req;
- struct drm_agp_mode mode;
- struct drm_agp_info info;
- struct drm_agp_buffer agp_req;
- struct drm_agp_binding bind_req;
-
- /* Acquire AGP. */
- err = drm_legacy_agp_acquire(dev);
- if (err) {
- DRM_ERROR("Unable to acquire AGP: %d\n", err);
- return err;
- }
-
- err = drm_legacy_agp_info(dev, &info);
- if (err) {
- DRM_ERROR("Unable to get AGP info: %d\n", err);
- return err;
- }
-
- mode.mode = (info.mode & ~0x07) | dma_bs->agp_mode;
- err = drm_legacy_agp_enable(dev, mode);
- if (err) {
- DRM_ERROR("Unable to enable AGP (mode = 0x%lx)\n", mode.mode);
- return err;
- }
-
- /* In addition to the usual AGP mode configuration, the G200 AGP cards
- * need to have the AGP mode "manually" set.
- */
-
- if (dev_priv->chipset == MGA_CARD_TYPE_G200) {
- if (mode.mode & 0x02)
- MGA_WRITE(MGA_AGP_PLL, MGA_AGP2XPLL_ENABLE);
- else
- MGA_WRITE(MGA_AGP_PLL, MGA_AGP2XPLL_DISABLE);
- }
-
- /* Allocate and bind AGP memory. */
- agp_req.size = agp_size;
- agp_req.type = 0;
- err = drm_legacy_agp_alloc(dev, &agp_req);
- if (err) {
- dev_priv->agp_size = 0;
- DRM_ERROR("Unable to allocate %uMB AGP memory\n",
- dma_bs->agp_size);
- return err;
- }
-
- dev_priv->agp_size = agp_size;
- dev_priv->agp_handle = agp_req.handle;
-
- bind_req.handle = agp_req.handle;
- bind_req.offset = 0;
- err = drm_legacy_agp_bind(dev, &bind_req);
- if (err) {
- DRM_ERROR("Unable to bind AGP memory: %d\n", err);
- return err;
- }
-
- /* Make drm_legacy_addbufs happy by not trying to create a mapping for
- * less than a page.
- */
- if (warp_size < PAGE_SIZE)
- warp_size = PAGE_SIZE;
-
- offset = 0;
- err = drm_legacy_addmap(dev, offset, warp_size,
- _DRM_AGP, _DRM_READ_ONLY, &dev_priv->warp);
- if (err) {
- DRM_ERROR("Unable to map WARP microcode: %d\n", err);
- return err;
- }
-
- offset += warp_size;
- err = drm_legacy_addmap(dev, offset, dma_bs->primary_size,
- _DRM_AGP, _DRM_READ_ONLY, &dev_priv->primary);
- if (err) {
- DRM_ERROR("Unable to map primary DMA region: %d\n", err);
- return err;
- }
-
- offset += dma_bs->primary_size;
- err = drm_legacy_addmap(dev, offset, secondary_size,
- _DRM_AGP, 0, &dev->agp_buffer_map);
- if (err) {
- DRM_ERROR("Unable to map secondary DMA region: %d\n", err);
- return err;
- }
-
- (void)memset(&req, 0, sizeof(req));
- req.count = dma_bs->secondary_bin_count;
- req.size = dma_bs->secondary_bin_size;
- req.flags = _DRM_AGP_BUFFER;
- req.agp_start = offset;
-
- err = drm_legacy_addbufs_agp(dev, &req);
- if (err) {
- DRM_ERROR("Unable to add secondary DMA buffers: %d\n", err);
- return err;
- }
-
- {
- struct drm_map_list *_entry;
- unsigned long agp_token = 0;
-
- list_for_each_entry(_entry, &dev->maplist, head) {
- if (_entry->map == dev->agp_buffer_map)
- agp_token = _entry->user_token;
- }
- if (!agp_token)
- return -EFAULT;
-
- dev->agp_buffer_token = agp_token;
- }
-
- offset += secondary_size;
- err = drm_legacy_addmap(dev, offset, agp_size - offset,
- _DRM_AGP, 0, &dev_priv->agp_textures);
- if (err) {
- DRM_ERROR("Unable to map AGP texture region %d\n", err);
- return err;
- }
-
- drm_legacy_ioremap(dev_priv->warp, dev);
- drm_legacy_ioremap(dev_priv->primary, dev);
- drm_legacy_ioremap(dev->agp_buffer_map, dev);
-
- if (!dev_priv->warp->handle ||
- !dev_priv->primary->handle || !dev->agp_buffer_map->handle) {
- DRM_ERROR("failed to ioremap agp regions! (%p, %p, %p)\n",
- dev_priv->warp->handle, dev_priv->primary->handle,
- dev->agp_buffer_map->handle);
- return -ENOMEM;
- }
-
- dev_priv->dma_access = MGA_PAGPXFER;
- dev_priv->wagp_enable = MGA_WAGP_ENABLE;
-
- DRM_INFO("Initialized card for AGP DMA.\n");
- return 0;
-}
-#else
-static int mga_do_agp_dma_bootstrap(struct drm_device *dev,
- drm_mga_dma_bootstrap_t *dma_bs)
-{
- return -EINVAL;
-}
-#endif
-
-/*
- * Bootstrap the driver for PCI DMA.
- *
- * \todo
- * The algorithm for decreasing the size of the primary DMA buffer could be
- * better. The size should be rounded up to the nearest page size, then
- * decrease the request size by a single page each pass through the loop.
- *
- * \todo
- * Determine whether the maximum address passed to drm_pci_alloc is correct.
- * The same goes for drm_legacy_addbufs_pci.
- *
- * \sa mga_do_dma_bootstrap, mga_do_agp_dma_bootstrap
- */
-static int mga_do_pci_dma_bootstrap(struct drm_device *dev,
- drm_mga_dma_bootstrap_t *dma_bs)
-{
- drm_mga_private_t *const dev_priv =
- (drm_mga_private_t *) dev->dev_private;
- unsigned int warp_size = MGA_WARP_UCODE_SIZE;
- unsigned int primary_size;
- unsigned int bin_count;
- int err;
- struct drm_buf_desc req;
-
- if (dev->dma == NULL) {
- DRM_ERROR("dev->dma is NULL\n");
- return -EFAULT;
- }
-
- /* Make drm_legacy_addbufs happy by not trying to create a mapping for
- * less than a page.
- */
- if (warp_size < PAGE_SIZE)
- warp_size = PAGE_SIZE;
-
- /* The proper alignment is 0x100 for this mapping */
- err = drm_legacy_addmap(dev, 0, warp_size, _DRM_CONSISTENT,
- _DRM_READ_ONLY, &dev_priv->warp);
- if (err != 0) {
- DRM_ERROR("Unable to create mapping for WARP microcode: %d\n",
- err);
- return err;
- }
-
- /* Other than the bottom two bits being used to encode other
- * information, there don't appear to be any restrictions on the
- * alignment of the primary or secondary DMA buffers.
- */
-
- for (primary_size = dma_bs->primary_size; primary_size != 0;
- primary_size >>= 1) {
- /* The proper alignment for this mapping is 0x04 */
- err = drm_legacy_addmap(dev, 0, primary_size, _DRM_CONSISTENT,
- _DRM_READ_ONLY, &dev_priv->primary);
- if (!err)
- break;
- }
-
- if (err != 0) {
- DRM_ERROR("Unable to allocate primary DMA region: %d\n", err);
- return -ENOMEM;
- }
-
- if (dev_priv->primary->size != dma_bs->primary_size) {
- DRM_INFO("Primary DMA buffer size reduced from %u to %u.\n",
- dma_bs->primary_size,
- (unsigned)dev_priv->primary->size);
- dma_bs->primary_size = dev_priv->primary->size;
- }
-
- for (bin_count = dma_bs->secondary_bin_count; bin_count > 0;
- bin_count--) {
- (void)memset(&req, 0, sizeof(req));
- req.count = bin_count;
- req.size = dma_bs->secondary_bin_size;
-
- err = drm_legacy_addbufs_pci(dev, &req);
- if (!err)
- break;
- }
-
- if (bin_count == 0) {
- DRM_ERROR("Unable to add secondary DMA buffers: %d\n", err);
- return err;
- }
-
- if (bin_count != dma_bs->secondary_bin_count) {
- DRM_INFO("Secondary PCI DMA buffer bin count reduced from %u "
- "to %u.\n", dma_bs->secondary_bin_count, bin_count);
-
- dma_bs->secondary_bin_count = bin_count;
- }
-
- dev_priv->dma_access = 0;
- dev_priv->wagp_enable = 0;
-
- dma_bs->agp_mode = 0;
-
- DRM_INFO("Initialized card for PCI DMA.\n");
- return 0;
-}
-
-static int mga_do_dma_bootstrap(struct drm_device *dev,
- drm_mga_dma_bootstrap_t *dma_bs)
-{
- const int is_agp = (dma_bs->agp_mode != 0) && dev->agp;
- int err;
- drm_mga_private_t *const dev_priv =
- (drm_mga_private_t *) dev->dev_private;
-
- dev_priv->used_new_dma_init = 1;
-
- /* The first steps are the same for both PCI and AGP based DMA. Map
- * the cards MMIO registers and map a status page.
- */
- err = drm_legacy_addmap(dev, dev_priv->mmio_base, dev_priv->mmio_size,
- _DRM_REGISTERS, _DRM_READ_ONLY,
- &dev_priv->mmio);
- if (err) {
- DRM_ERROR("Unable to map MMIO region: %d\n", err);
- return err;
- }
-
- err = drm_legacy_addmap(dev, 0, SAREA_MAX, _DRM_SHM,
- _DRM_READ_ONLY | _DRM_LOCKED | _DRM_KERNEL,
- &dev_priv->status);
- if (err) {
- DRM_ERROR("Unable to map status region: %d\n", err);
- return err;
- }
-
- /* The DMA initialization procedure is slightly different for PCI and
- * AGP cards. AGP cards just allocate a large block of AGP memory and
- * carve off portions of it for internal uses. The remaining memory
- * is returned to user-mode to be used for AGP textures.
- */
- if (is_agp)
- err = mga_do_agp_dma_bootstrap(dev, dma_bs);
-
- /* If we attempted to initialize the card for AGP DMA but failed,
- * clean-up any mess that may have been created.
- */
-
- if (err)
- mga_do_cleanup_dma(dev, MINIMAL_CLEANUP);
-
- /* Not only do we want to try and initialized PCI cards for PCI DMA,
- * but we also try to initialized AGP cards that could not be
- * initialized for AGP DMA. This covers the case where we have an AGP
- * card in a system with an unsupported AGP chipset. In that case the
- * card will be detected as AGP, but we won't be able to allocate any
- * AGP memory, etc.
- */
-
- if (!is_agp || err)
- err = mga_do_pci_dma_bootstrap(dev, dma_bs);
-
- return err;
-}
-
-int mga_dma_bootstrap(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- drm_mga_dma_bootstrap_t *bootstrap = data;
- int err;
- static const int modes[] = { 0, 1, 2, 2, 4, 4, 4, 4 };
- const drm_mga_private_t *const dev_priv =
- (drm_mga_private_t *) dev->dev_private;
-
- err = mga_do_dma_bootstrap(dev, bootstrap);
- if (err) {
- mga_do_cleanup_dma(dev, FULL_CLEANUP);
- return err;
- }
-
- if (dev_priv->agp_textures != NULL) {
- bootstrap->texture_handle = dev_priv->agp_textures->offset;
- bootstrap->texture_size = dev_priv->agp_textures->size;
- } else {
- bootstrap->texture_handle = 0;
- bootstrap->texture_size = 0;
- }
-
- bootstrap->agp_mode = modes[bootstrap->agp_mode & 0x07];
-
- return err;
-}
-
-static int mga_do_init_dma(struct drm_device *dev, drm_mga_init_t *init)
-{
- drm_mga_private_t *dev_priv;
- int ret;
- DRM_DEBUG("\n");
-
- dev_priv = dev->dev_private;
-
- if (init->sgram)
- dev_priv->clear_cmd = MGA_DWGCTL_CLEAR | MGA_ATYPE_BLK;
- else
- dev_priv->clear_cmd = MGA_DWGCTL_CLEAR | MGA_ATYPE_RSTR;
- dev_priv->maccess = init->maccess;
-
- dev_priv->fb_cpp = init->fb_cpp;
- dev_priv->front_offset = init->front_offset;
- dev_priv->front_pitch = init->front_pitch;
- dev_priv->back_offset = init->back_offset;
- dev_priv->back_pitch = init->back_pitch;
-
- dev_priv->depth_cpp = init->depth_cpp;
- dev_priv->depth_offset = init->depth_offset;
- dev_priv->depth_pitch = init->depth_pitch;
-
- /* FIXME: Need to support AGP textures...
- */
- dev_priv->texture_offset = init->texture_offset[0];
- dev_priv->texture_size = init->texture_size[0];
-
- dev_priv->sarea = drm_legacy_getsarea(dev);
- if (!dev_priv->sarea) {
- DRM_ERROR("failed to find sarea!\n");
- return -EINVAL;
- }
-
- if (!dev_priv->used_new_dma_init) {
-
- dev_priv->dma_access = MGA_PAGPXFER;
- dev_priv->wagp_enable = MGA_WAGP_ENABLE;
-
- dev_priv->status = drm_legacy_findmap(dev, init->status_offset);
- if (!dev_priv->status) {
- DRM_ERROR("failed to find status page!\n");
- return -EINVAL;
- }
- dev_priv->mmio = drm_legacy_findmap(dev, init->mmio_offset);
- if (!dev_priv->mmio) {
- DRM_ERROR("failed to find mmio region!\n");
- return -EINVAL;
- }
- dev_priv->warp = drm_legacy_findmap(dev, init->warp_offset);
- if (!dev_priv->warp) {
- DRM_ERROR("failed to find warp microcode region!\n");
- return -EINVAL;
- }
- dev_priv->primary = drm_legacy_findmap(dev, init->primary_offset);
- if (!dev_priv->primary) {
- DRM_ERROR("failed to find primary dma region!\n");
- return -EINVAL;
- }
- dev->agp_buffer_token = init->buffers_offset;
- dev->agp_buffer_map =
- drm_legacy_findmap(dev, init->buffers_offset);
- if (!dev->agp_buffer_map) {
- DRM_ERROR("failed to find dma buffer region!\n");
- return -EINVAL;
- }
-
- drm_legacy_ioremap(dev_priv->warp, dev);
- drm_legacy_ioremap(dev_priv->primary, dev);
- drm_legacy_ioremap(dev->agp_buffer_map, dev);
- }
-
- dev_priv->sarea_priv =
- (drm_mga_sarea_t *) ((u8 *) dev_priv->sarea->handle +
- init->sarea_priv_offset);
-
- if (!dev_priv->warp->handle ||
- !dev_priv->primary->handle ||
- ((dev_priv->dma_access != 0) &&
- ((dev->agp_buffer_map == NULL) ||
- (dev->agp_buffer_map->handle == NULL)))) {
- DRM_ERROR("failed to ioremap agp regions!\n");
- return -ENOMEM;
- }
-
- ret = mga_warp_install_microcode(dev_priv);
- if (ret < 0) {
- DRM_ERROR("failed to install WARP ucode!: %d\n", ret);
- return ret;
- }
-
- ret = mga_warp_init(dev_priv);
- if (ret < 0) {
- DRM_ERROR("failed to init WARP engine!: %d\n", ret);
- return ret;
- }
-
- dev_priv->prim.status = (u32 *) dev_priv->status->handle;
-
- mga_do_wait_for_idle(dev_priv);
-
- /* Init the primary DMA registers.
- */
- MGA_WRITE(MGA_PRIMADDRESS, dev_priv->primary->offset | MGA_DMA_GENERAL);
-#if 0
- MGA_WRITE(MGA_PRIMPTR, virt_to_bus((void *)dev_priv->prim.status) | MGA_PRIMPTREN0 | /* Soft trap, SECEND, SETUPEND */
- MGA_PRIMPTREN1); /* DWGSYNC */
-#endif
-
- dev_priv->prim.start = (u8 *) dev_priv->primary->handle;
- dev_priv->prim.end = ((u8 *) dev_priv->primary->handle
- + dev_priv->primary->size);
- dev_priv->prim.size = dev_priv->primary->size;
-
- dev_priv->prim.tail = 0;
- dev_priv->prim.space = dev_priv->prim.size;
- dev_priv->prim.wrapped = 0;
-
- dev_priv->prim.last_flush = 0;
- dev_priv->prim.last_wrap = 0;
-
- dev_priv->prim.high_mark = 256 * DMA_BLOCK_SIZE;
-
- dev_priv->prim.status[0] = dev_priv->primary->offset;
- dev_priv->prim.status[1] = 0;
-
- dev_priv->sarea_priv->last_wrap = 0;
- dev_priv->sarea_priv->last_frame.head = 0;
- dev_priv->sarea_priv->last_frame.wrap = 0;
-
- if (mga_freelist_init(dev, dev_priv) < 0) {
- DRM_ERROR("could not initialize freelist\n");
- return -ENOMEM;
- }
-
- return 0;
-}
-
-static int mga_do_cleanup_dma(struct drm_device *dev, int full_cleanup)
-{
- int err = 0;
- DRM_DEBUG("\n");
-
- /* Make sure interrupts are disabled here because the uninstall ioctl
- * may not have been called from userspace and after dev_private
- * is freed, it's too late.
- */
- if (dev->irq_enabled)
- drm_legacy_irq_uninstall(dev);
-
- if (dev->dev_private) {
- drm_mga_private_t *dev_priv = dev->dev_private;
-
- if ((dev_priv->warp != NULL)
- && (dev_priv->warp->type != _DRM_CONSISTENT))
- drm_legacy_ioremapfree(dev_priv->warp, dev);
-
- if ((dev_priv->primary != NULL)
- && (dev_priv->primary->type != _DRM_CONSISTENT))
- drm_legacy_ioremapfree(dev_priv->primary, dev);
-
- if (dev->agp_buffer_map != NULL)
- drm_legacy_ioremapfree(dev->agp_buffer_map, dev);
-
- if (dev_priv->used_new_dma_init) {
-#if IS_ENABLED(CONFIG_AGP)
- if (dev_priv->agp_handle != 0) {
- struct drm_agp_binding unbind_req;
- struct drm_agp_buffer free_req;
-
- unbind_req.handle = dev_priv->agp_handle;
- drm_legacy_agp_unbind(dev, &unbind_req);
-
- free_req.handle = dev_priv->agp_handle;
- drm_legacy_agp_free(dev, &free_req);
-
- dev_priv->agp_textures = NULL;
- dev_priv->agp_size = 0;
- dev_priv->agp_handle = 0;
- }
-
- if ((dev->agp != NULL) && dev->agp->acquired)
- err = drm_legacy_agp_release(dev);
-#endif
- }
-
- dev_priv->warp = NULL;
- dev_priv->primary = NULL;
- dev_priv->sarea = NULL;
- dev_priv->sarea_priv = NULL;
- dev->agp_buffer_map = NULL;
-
- if (full_cleanup) {
- dev_priv->mmio = NULL;
- dev_priv->status = NULL;
- dev_priv->used_new_dma_init = 0;
- }
-
- memset(&dev_priv->prim, 0, sizeof(dev_priv->prim));
- dev_priv->warp_pipe = 0;
- memset(dev_priv->warp_pipe_phys, 0,
- sizeof(dev_priv->warp_pipe_phys));
-
- if (dev_priv->head != NULL)
- mga_freelist_cleanup(dev);
- }
-
- return err;
-}
-
-int mga_dma_init(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- drm_mga_init_t *init = data;
- int err;
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- switch (init->func) {
- case MGA_INIT_DMA:
- err = mga_do_init_dma(dev, init);
- if (err)
- (void)mga_do_cleanup_dma(dev, FULL_CLEANUP);
- return err;
- case MGA_CLEANUP_DMA:
- return mga_do_cleanup_dma(dev, FULL_CLEANUP);
- }
-
- return -EINVAL;
-}
-
-/* ================================================================
- * Primary DMA stream management
- */
-
-int mga_dma_flush(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
- struct drm_lock *lock = data;
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- DRM_DEBUG("%s%s%s\n",
- (lock->flags & _DRM_LOCK_FLUSH) ? "flush, " : "",
- (lock->flags & _DRM_LOCK_FLUSH_ALL) ? "flush all, " : "",
- (lock->flags & _DRM_LOCK_QUIESCENT) ? "idle, " : "");
-
- WRAP_WAIT_WITH_RETURN(dev_priv);
-
- if (lock->flags & (_DRM_LOCK_FLUSH | _DRM_LOCK_FLUSH_ALL))
- mga_do_dma_flush(dev_priv);
-
- if (lock->flags & _DRM_LOCK_QUIESCENT) {
-#if MGA_DMA_DEBUG
- int ret = mga_do_wait_for_idle(dev_priv);
- if (ret < 0)
- DRM_INFO("-EBUSY\n");
- return ret;
-#else
- return mga_do_wait_for_idle(dev_priv);
-#endif
- } else {
- return 0;
- }
-}
-
-int mga_dma_reset(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- return mga_do_dma_reset(dev_priv);
-}
-
-/* ================================================================
- * DMA buffer management
- */
-
-static int mga_dma_get_buffers(struct drm_device *dev,
- struct drm_file *file_priv, struct drm_dma *d)
-{
- struct drm_buf *buf;
- int i;
-
- for (i = d->granted_count; i < d->request_count; i++) {
- buf = mga_freelist_get(dev);
- if (!buf)
- return -EAGAIN;
-
- buf->file_priv = file_priv;
-
- if (copy_to_user(&d->request_indices[i],
- &buf->idx, sizeof(buf->idx)))
- return -EFAULT;
- if (copy_to_user(&d->request_sizes[i],
- &buf->total, sizeof(buf->total)))
- return -EFAULT;
-
- d->granted_count++;
- }
- return 0;
-}
-
-int mga_dma_buffers(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- struct drm_device_dma *dma = dev->dma;
- drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
- struct drm_dma *d = data;
- int ret = 0;
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- /* Please don't send us buffers.
- */
- if (d->send_count != 0) {
- DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n",
- task_pid_nr(current), d->send_count);
- return -EINVAL;
- }
-
- /* We'll send you buffers.
- */
- if (d->request_count < 0 || d->request_count > dma->buf_count) {
- DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",
- task_pid_nr(current), d->request_count,
- dma->buf_count);
- return -EINVAL;
- }
-
- WRAP_TEST_WITH_RETURN(dev_priv);
-
- d->granted_count = 0;
-
- if (d->request_count)
- ret = mga_dma_get_buffers(dev, file_priv, d);
-
- return ret;
-}
-
-/*
- * Called just before the module is unloaded.
- */
-void mga_driver_unload(struct drm_device *dev)
-{
- kfree(dev->dev_private);
- dev->dev_private = NULL;
-}
-
-/*
- * Called when the last opener of the device is closed.
- */
-void mga_driver_lastclose(struct drm_device *dev)
-{
- mga_do_cleanup_dma(dev, FULL_CLEANUP);
-}
-
-int mga_driver_dma_quiescent(struct drm_device *dev)
-{
- drm_mga_private_t *dev_priv = dev->dev_private;
- return mga_do_wait_for_idle(dev_priv);
-}
diff --git a/drivers/gpu/drm/mga/mga_drv.c b/drivers/gpu/drm/mga/mga_drv.c
deleted file mode 100644
index 71128e6f6ae9..000000000000
--- a/drivers/gpu/drm/mga/mga_drv.c
+++ /dev/null
@@ -1,104 +0,0 @@
-/* mga_drv.c -- Matrox G200/G400 driver -*- linux-c -*-
- * Created: Mon Dec 13 01:56:22 1999 by jhartmann@precisioninsight.com
- *
- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software 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 (including the next
- * paragraph) 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
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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.
- *
- * Authors:
- * Rickard E. (Rik) Faith <faith@valinux.com>
- * Gareth Hughes <gareth@valinux.com>
- */
-
-#include <linux/module.h>
-
-#include <drm/drm_drv.h>
-#include <drm/drm_pciids.h>
-
-#include "mga_drv.h"
-
-static struct pci_device_id pciidlist[] = {
- mga_PCI_IDS
-};
-
-static const struct file_operations mga_driver_fops = {
- .owner = THIS_MODULE,
- .open = drm_open,
- .release = drm_release,
- .unlocked_ioctl = drm_ioctl,
- .mmap = drm_legacy_mmap,
- .poll = drm_poll,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = mga_compat_ioctl,
-#endif
- .llseek = noop_llseek,
-};
-
-static struct drm_driver driver = {
- .driver_features =
- DRIVER_USE_AGP | DRIVER_PCI_DMA | DRIVER_LEGACY |
- DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ,
- .dev_priv_size = sizeof(drm_mga_buf_priv_t),
- .load = mga_driver_load,
- .unload = mga_driver_unload,
- .lastclose = mga_driver_lastclose,
- .dma_quiescent = mga_driver_dma_quiescent,
- .get_vblank_counter = mga_get_vblank_counter,
- .enable_vblank = mga_enable_vblank,
- .disable_vblank = mga_disable_vblank,
- .irq_preinstall = mga_driver_irq_preinstall,
- .irq_postinstall = mga_driver_irq_postinstall,
- .irq_uninstall = mga_driver_irq_uninstall,
- .irq_handler = mga_driver_irq_handler,
- .ioctls = mga_ioctls,
- .dma_ioctl = mga_dma_buffers,
- .fops = &mga_driver_fops,
- .name = DRIVER_NAME,
- .desc = DRIVER_DESC,
- .date = DRIVER_DATE,
- .major = DRIVER_MAJOR,
- .minor = DRIVER_MINOR,
- .patchlevel = DRIVER_PATCHLEVEL,
-};
-
-static struct pci_driver mga_pci_driver = {
- .name = DRIVER_NAME,
- .id_table = pciidlist,
-};
-
-static int __init mga_init(void)
-{
- driver.num_ioctls = mga_max_ioctl;
- return drm_legacy_pci_init(&driver, &mga_pci_driver);
-}
-
-static void __exit mga_exit(void)
-{
- drm_legacy_pci_exit(&driver, &mga_pci_driver);
-}
-
-module_init(mga_init);
-module_exit(mga_exit);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/gpu/drm/mga/mga_drv.h b/drivers/gpu/drm/mga/mga_drv.h
deleted file mode 100644
index f61401c70b90..000000000000
--- a/drivers/gpu/drm/mga/mga_drv.h
+++ /dev/null
@@ -1,685 +0,0 @@
-/* mga_drv.h -- Private header for the Matrox G200/G400 driver -*- linux-c -*-
- * Created: Mon Dec 13 01:50:01 1999 by jhartmann@precisioninsight.com
- *
- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software 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 (including the next
- * paragraph) 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
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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.
- *
- * Authors:
- * Gareth Hughes <gareth@valinux.com>
- */
-
-#ifndef __MGA_DRV_H__
-#define __MGA_DRV_H__
-
-#include <linux/irqreturn.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-
-#include <drm/drm_device.h>
-#include <drm/drm_file.h>
-#include <drm/drm_ioctl.h>
-#include <drm/drm_legacy.h>
-#include <drm/drm_print.h>
-#include <drm/drm_sarea.h>
-#include <drm/drm_vblank.h>
-#include <drm/mga_drm.h>
-
-/* General customization:
- */
-
-#define DRIVER_AUTHOR "Gareth Hughes, VA Linux Systems Inc."
-
-#define DRIVER_NAME "mga"
-#define DRIVER_DESC "Matrox G200/G400"
-#define DRIVER_DATE "20051102"
-
-#define DRIVER_MAJOR 3
-#define DRIVER_MINOR 2
-#define DRIVER_PATCHLEVEL 1
-
-typedef struct drm_mga_primary_buffer {
- u8 *start;
- u8 *end;
- int size;
-
- u32 tail;
- int space;
- volatile long wrapped;
-
- volatile u32 *status;
-
- u32 last_flush;
- u32 last_wrap;
-
- u32 high_mark;
-} drm_mga_primary_buffer_t;
-
-typedef struct drm_mga_freelist {
- struct drm_mga_freelist *next;
- struct drm_mga_freelist *prev;
- drm_mga_age_t age;
- struct drm_buf *buf;
-} drm_mga_freelist_t;
-
-typedef struct {
- drm_mga_freelist_t *list_entry;
- int discard;
- int dispatched;
-} drm_mga_buf_priv_t;
-
-typedef struct drm_mga_private {
- drm_mga_primary_buffer_t prim;
- drm_mga_sarea_t *sarea_priv;
-
- drm_mga_freelist_t *head;
- drm_mga_freelist_t *tail;
-
- unsigned int warp_pipe;
- unsigned long warp_pipe_phys[MGA_MAX_WARP_PIPES];
-
- int chipset;
- int usec_timeout;
-
- /**
- * If set, the new DMA initialization sequence was used. This is
- * primarilly used to select how the driver should uninitialized its
- * internal DMA structures.
- */
- int used_new_dma_init;
-
- /**
- * If AGP memory is used for DMA buffers, this will be the value
- * \c MGA_PAGPXFER. Otherwise, it will be zero (for a PCI transfer).
- */
- u32 dma_access;
-
- /**
- * If AGP memory is used for DMA buffers, this will be the value
- * \c MGA_WAGP_ENABLE. Otherwise, it will be zero (for a PCI
- * transfer).
- */
- u32 wagp_enable;
-
- /**
- * \name MMIO region parameters.
- *
- * \sa drm_mga_private_t::mmio
- */
- /*@{ */
- resource_size_t mmio_base; /**< Bus address of base of MMIO. */
- resource_size_t mmio_size; /**< Size of the MMIO region. */
- /*@} */
-
- u32 clear_cmd;
- u32 maccess;
-
- atomic_t vbl_received; /**< Number of vblanks received. */
- wait_queue_head_t fence_queue;
- atomic_t last_fence_retired;
- u32 next_fence_to_post;
-
- unsigned int fb_cpp;
- unsigned int front_offset;
- unsigned int front_pitch;
- unsigned int back_offset;
- unsigned int back_pitch;
-
- unsigned int depth_cpp;
- unsigned int depth_offset;
- unsigned int depth_pitch;
-
- unsigned int texture_offset;
- unsigned int texture_size;
-
- drm_local_map_t *sarea;
- drm_local_map_t *mmio;
- drm_local_map_t *status;
- drm_local_map_t *warp;
- drm_local_map_t *primary;
- drm_local_map_t *agp_textures;
-
- unsigned long agp_handle;
- unsigned int agp_size;
-} drm_mga_private_t;
-
-extern const struct drm_ioctl_desc mga_ioctls[];
-extern int mga_max_ioctl;
-
- /* mga_dma.c */
-extern int mga_dma_bootstrap(struct drm_device *dev, void *data,
- struct drm_file *file_priv);
-extern int mga_dma_init(struct drm_device *dev, void *data,
- struct drm_file *file_priv);
-extern int mga_getparam(struct drm_device *dev, void *data,
- struct drm_file *file_priv);
-extern int mga_dma_flush(struct drm_device *dev, void *data,
- struct drm_file *file_priv);
-extern int mga_dma_reset(struct drm_device *dev, void *data,
- struct drm_file *file_priv);
-extern int mga_dma_buffers(struct drm_device *dev, void *data,
- struct drm_file *file_priv);
-extern int mga_driver_load(struct drm_device *dev, unsigned long flags);
-extern void mga_driver_unload(struct drm_device *dev);
-extern void mga_driver_lastclose(struct drm_device *dev);
-extern int mga_driver_dma_quiescent(struct drm_device *dev);
-
-extern int mga_do_wait_for_idle(drm_mga_private_t *dev_priv);
-
-extern void mga_do_dma_flush(drm_mga_private_t *dev_priv);
-extern void mga_do_dma_wrap_start(drm_mga_private_t *dev_priv);
-extern void mga_do_dma_wrap_end(drm_mga_private_t *dev_priv);
-
-extern int mga_freelist_put(struct drm_device *dev, struct drm_buf *buf);
-
- /* mga_warp.c */
-extern int mga_warp_install_microcode(drm_mga_private_t *dev_priv);
-extern int mga_warp_init(drm_mga_private_t *dev_priv);
-
- /* mga_irq.c */
-extern int mga_enable_vblank(struct drm_device *dev, unsigned int pipe);
-extern void mga_disable_vblank(struct drm_device *dev, unsigned int pipe);
-extern u32 mga_get_vblank_counter(struct drm_device *dev, unsigned int pipe);
-extern void mga_driver_fence_wait(struct drm_device *dev, unsigned int *sequence);
-extern int mga_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence);
-extern irqreturn_t mga_driver_irq_handler(int irq, void *arg);
-extern void mga_driver_irq_preinstall(struct drm_device *dev);
-extern int mga_driver_irq_postinstall(struct drm_device *dev);
-extern void mga_driver_irq_uninstall(struct drm_device *dev);
-extern long mga_compat_ioctl(struct file *filp, unsigned int cmd,
- unsigned long arg);
-
-#define mga_flush_write_combine() wmb()
-
-#define MGA_READ8(reg) \
- readb(((void __iomem *)dev_priv->mmio->handle) + (reg))
-#define MGA_READ(reg) \
- readl(((void __iomem *)dev_priv->mmio->handle) + (reg))
-#define MGA_WRITE8(reg, val) \
- writeb(val, ((void __iomem *)dev_priv->mmio->handle) + (reg))
-#define MGA_WRITE(reg, val) \
- writel(val, ((void __iomem *)dev_priv->mmio->handle) + (reg))
-
-#define DWGREG0 0x1c00
-#define DWGREG0_END 0x1dff
-#define DWGREG1 0x2c00
-#define DWGREG1_END 0x2dff
-
-#define ISREG0(r) (r >= DWGREG0 && r <= DWGREG0_END)
-#define DMAREG0(r) (u8)((r - DWGREG0) >> 2)
-#define DMAREG1(r) (u8)(((r - DWGREG1) >> 2) | 0x80)
-#define DMAREG(r) (ISREG0(r) ? DMAREG0(r) : DMAREG1(r))
-
-/* ================================================================
- * Helper macross...
- */
-
-#define MGA_EMIT_STATE(dev_priv, dirty) \
-do { \
- if ((dirty) & ~MGA_UPLOAD_CLIPRECTS) { \
- if (dev_priv->chipset >= MGA_CARD_TYPE_G400) \
- mga_g400_emit_state(dev_priv); \
- else \
- mga_g200_emit_state(dev_priv); \
- } \
-} while (0)
-
-#define WRAP_TEST_WITH_RETURN(dev_priv) \
-do { \
- if (test_bit(0, &dev_priv->prim.wrapped)) { \
- if (mga_is_idle(dev_priv)) { \
- mga_do_dma_wrap_end(dev_priv); \
- } else if (dev_priv->prim.space < \
- dev_priv->prim.high_mark) { \
- if (MGA_DMA_DEBUG) \
- DRM_INFO("wrap...\n"); \
- return -EBUSY; \
- } \
- } \
-} while (0)
-
-#define WRAP_WAIT_WITH_RETURN(dev_priv) \
-do { \
- if (test_bit(0, &dev_priv->prim.wrapped)) { \
- if (mga_do_wait_for_idle(dev_priv) < 0) { \
- if (MGA_DMA_DEBUG) \
- DRM_INFO("wrap...\n"); \
- return -EBUSY; \
- } \
- mga_do_dma_wrap_end(dev_priv); \
- } \
-} while (0)
-
-/* ================================================================
- * Primary DMA command stream
- */
-
-#define MGA_VERBOSE 0
-
-#define DMA_LOCALS unsigned int write; volatile u8 *prim;
-
-#define DMA_BLOCK_SIZE (5 * sizeof(u32))
-
-#define BEGIN_DMA(n) \
-do { \
- if (MGA_VERBOSE) { \
- DRM_INFO("BEGIN_DMA(%d)\n", (n)); \
- DRM_INFO(" space=0x%x req=0x%zx\n", \
- dev_priv->prim.space, (n) * DMA_BLOCK_SIZE); \
- } \
- prim = dev_priv->prim.start; \
- write = dev_priv->prim.tail; \
-} while (0)
-
-#define BEGIN_DMA_WRAP() \
-do { \
- if (MGA_VERBOSE) { \
- DRM_INFO("BEGIN_DMA()\n"); \
- DRM_INFO(" space=0x%x\n", dev_priv->prim.space); \
- } \
- prim = dev_priv->prim.start; \
- write = dev_priv->prim.tail; \
-} while (0)
-
-#define ADVANCE_DMA() \
-do { \
- dev_priv->prim.tail = write; \
- if (MGA_VERBOSE) \
- DRM_INFO("ADVANCE_DMA() tail=0x%05x sp=0x%x\n", \
- write, dev_priv->prim.space); \
-} while (0)
-
-#define FLUSH_DMA() \
-do { \
- if (0) { \
- DRM_INFO("\n"); \
- DRM_INFO(" tail=0x%06x head=0x%06lx\n", \
- dev_priv->prim.tail, \
- (unsigned long)(MGA_READ(MGA_PRIMADDRESS) - \
- dev_priv->primary->offset)); \
- } \
- if (!test_bit(0, &dev_priv->prim.wrapped)) { \
- if (dev_priv->prim.space < dev_priv->prim.high_mark) \
- mga_do_dma_wrap_start(dev_priv); \
- else \
- mga_do_dma_flush(dev_priv); \
- } \
-} while (0)
-
-/* Never use this, always use DMA_BLOCK(...) for primary DMA output.
- */
-#define DMA_WRITE(offset, val) \
-do { \
- if (MGA_VERBOSE) \
- DRM_INFO(" DMA_WRITE( 0x%08x ) at 0x%04zx\n", \
- (u32)(val), write + (offset) * sizeof(u32)); \
- *(volatile u32 *)(prim + write + (offset) * sizeof(u32)) = val; \
-} while (0)
-
-#define DMA_BLOCK(reg0, val0, reg1, val1, reg2, val2, reg3, val3) \
-do { \
- DMA_WRITE(0, ((DMAREG(reg0) << 0) | \
- (DMAREG(reg1) << 8) | \
- (DMAREG(reg2) << 16) | \
- (DMAREG(reg3) << 24))); \
- DMA_WRITE(1, val0); \
- DMA_WRITE(2, val1); \
- DMA_WRITE(3, val2); \
- DMA_WRITE(4, val3); \
- write += DMA_BLOCK_SIZE; \
-} while (0)
-
-/* Buffer aging via primary DMA stream head pointer.
- */
-
-#define SET_AGE(age, h, w) \
-do { \
- (age)->head = h; \
- (age)->wrap = w; \
-} while (0)
-
-#define TEST_AGE(age, h, w) ((age)->wrap < w || \
- ((age)->wrap == w && \
- (age)->head < h))
-
-#define AGE_BUFFER(buf_priv) \
-do { \
- drm_mga_freelist_t *entry = (buf_priv)->list_entry; \
- if ((buf_priv)->dispatched) { \
- entry->age.head = (dev_priv->prim.tail + \
- dev_priv->primary->offset); \
- entry->age.wrap = dev_priv->sarea_priv->last_wrap; \
- } else { \
- entry->age.head = 0; \
- entry->age.wrap = 0; \
- } \
-} while (0)
-
-#define MGA_ENGINE_IDLE_MASK (MGA_SOFTRAPEN | \
- MGA_DWGENGSTS | \
- MGA_ENDPRDMASTS)
-#define MGA_DMA_IDLE_MASK (MGA_SOFTRAPEN | \
- MGA_ENDPRDMASTS)
-
-#define MGA_DMA_DEBUG 0
-
-/* A reduced set of the mga registers.
- */
-#define MGA_CRTC_INDEX 0x1fd4
-#define MGA_CRTC_DATA 0x1fd5
-
-/* CRTC11 */
-#define MGA_VINTCLR (1 << 4)
-#define MGA_VINTEN (1 << 5)
-
-#define MGA_ALPHACTRL 0x2c7c
-#define MGA_AR0 0x1c60
-#define MGA_AR1 0x1c64
-#define MGA_AR2 0x1c68
-#define MGA_AR3 0x1c6c
-#define MGA_AR4 0x1c70
-#define MGA_AR5 0x1c74
-#define MGA_AR6 0x1c78
-
-#define MGA_CXBNDRY 0x1c80
-#define MGA_CXLEFT 0x1ca0
-#define MGA_CXRIGHT 0x1ca4
-
-#define MGA_DMAPAD 0x1c54
-#define MGA_DSTORG 0x2cb8
-#define MGA_DWGCTL 0x1c00
-# define MGA_OPCOD_MASK (15 << 0)
-# define MGA_OPCOD_TRAP (4 << 0)
-# define MGA_OPCOD_TEXTURE_TRAP (6 << 0)
-# define MGA_OPCOD_BITBLT (8 << 0)
-# define MGA_OPCOD_ILOAD (9 << 0)
-# define MGA_ATYPE_MASK (7 << 4)
-# define MGA_ATYPE_RPL (0 << 4)
-# define MGA_ATYPE_RSTR (1 << 4)
-# define MGA_ATYPE_ZI (3 << 4)
-# define MGA_ATYPE_BLK (4 << 4)
-# define MGA_ATYPE_I (7 << 4)
-# define MGA_LINEAR (1 << 7)
-# define MGA_ZMODE_MASK (7 << 8)
-# define MGA_ZMODE_NOZCMP (0 << 8)
-# define MGA_ZMODE_ZE (2 << 8)
-# define MGA_ZMODE_ZNE (3 << 8)
-# define MGA_ZMODE_ZLT (4 << 8)
-# define MGA_ZMODE_ZLTE (5 << 8)
-# define MGA_ZMODE_ZGT (6 << 8)
-# define MGA_ZMODE_ZGTE (7 << 8)
-# define MGA_SOLID (1 << 11)
-# define MGA_ARZERO (1 << 12)
-# define MGA_SGNZERO (1 << 13)
-# define MGA_SHIFTZERO (1 << 14)
-# define MGA_BOP_MASK (15 << 16)
-# define MGA_BOP_ZERO (0 << 16)
-# define MGA_BOP_DST (10 << 16)
-# define MGA_BOP_SRC (12 << 16)
-# define MGA_BOP_ONE (15 << 16)
-# define MGA_TRANS_SHIFT 20
-# define MGA_TRANS_MASK (15 << 20)
-# define MGA_BLTMOD_MASK (15 << 25)
-# define MGA_BLTMOD_BMONOLEF (0 << 25)
-# define MGA_BLTMOD_BMONOWF (4 << 25)
-# define MGA_BLTMOD_PLAN (1 << 25)
-# define MGA_BLTMOD_BFCOL (2 << 25)
-# define MGA_BLTMOD_BU32BGR (3 << 25)
-# define MGA_BLTMOD_BU32RGB (7 << 25)
-# define MGA_BLTMOD_BU24BGR (11 << 25)
-# define MGA_BLTMOD_BU24RGB (15 << 25)
-# define MGA_PATTERN (1 << 29)
-# define MGA_TRANSC (1 << 30)
-# define MGA_CLIPDIS (1 << 31)
-#define MGA_DWGSYNC 0x2c4c
-
-#define MGA_FCOL 0x1c24
-#define MGA_FIFOSTATUS 0x1e10
-#define MGA_FOGCOL 0x1cf4
-#define MGA_FXBNDRY 0x1c84
-#define MGA_FXLEFT 0x1ca8
-#define MGA_FXRIGHT 0x1cac
-
-#define MGA_ICLEAR 0x1e18
-# define MGA_SOFTRAPICLR (1 << 0)
-# define MGA_VLINEICLR (1 << 5)
-#define MGA_IEN 0x1e1c
-# define MGA_SOFTRAPIEN (1 << 0)
-# define MGA_VLINEIEN (1 << 5)
-
-#define MGA_LEN 0x1c5c
-
-#define MGA_MACCESS 0x1c04
-
-#define MGA_PITCH 0x1c8c
-#define MGA_PLNWT 0x1c1c
-#define MGA_PRIMADDRESS 0x1e58
-# define MGA_DMA_GENERAL (0 << 0)
-# define MGA_DMA_BLIT (1 << 0)
-# define MGA_DMA_VECTOR (2 << 0)
-# define MGA_DMA_VERTEX (3 << 0)
-#define MGA_PRIMEND 0x1e5c
-# define MGA_PRIMNOSTART (1 << 0)
-# define MGA_PAGPXFER (1 << 1)
-#define MGA_PRIMPTR 0x1e50
-# define MGA_PRIMPTREN0 (1 << 0)
-# define MGA_PRIMPTREN1 (1 << 1)
-
-#define MGA_RST 0x1e40
-# define MGA_SOFTRESET (1 << 0)
-# define MGA_SOFTEXTRST (1 << 1)
-
-#define MGA_SECADDRESS 0x2c40
-#define MGA_SECEND 0x2c44
-#define MGA_SETUPADDRESS 0x2cd0
-#define MGA_SETUPEND 0x2cd4
-#define MGA_SGN 0x1c58
-#define MGA_SOFTRAP 0x2c48
-#define MGA_SRCORG 0x2cb4
-# define MGA_SRMMAP_MASK (1 << 0)
-# define MGA_SRCMAP_FB (0 << 0)
-# define MGA_SRCMAP_SYSMEM (1 << 0)
-# define MGA_SRCACC_MASK (1 << 1)
-# define MGA_SRCACC_PCI (0 << 1)
-# define MGA_SRCACC_AGP (1 << 1)
-#define MGA_STATUS 0x1e14
-# define MGA_SOFTRAPEN (1 << 0)
-# define MGA_VSYNCPEN (1 << 4)
-# define MGA_VLINEPEN (1 << 5)
-# define MGA_DWGENGSTS (1 << 16)
-# define MGA_ENDPRDMASTS (1 << 17)
-#define MGA_STENCIL 0x2cc8
-#define MGA_STENCILCTL 0x2ccc
-
-#define MGA_TDUALSTAGE0 0x2cf8
-#define MGA_TDUALSTAGE1 0x2cfc
-#define MGA_TEXBORDERCOL 0x2c5c
-#define MGA_TEXCTL 0x2c30
-#define MGA_TEXCTL2 0x2c3c
-# define MGA_DUALTEX (1 << 7)
-# define MGA_G400_TC2_MAGIC (1 << 15)
-# define MGA_MAP1_ENABLE (1 << 31)
-#define MGA_TEXFILTER 0x2c58
-#define MGA_TEXHEIGHT 0x2c2c
-#define MGA_TEXORG 0x2c24
-# define MGA_TEXORGMAP_MASK (1 << 0)
-# define MGA_TEXORGMAP_FB (0 << 0)
-# define MGA_TEXORGMAP_SYSMEM (1 << 0)
-# define MGA_TEXORGACC_MASK (1 << 1)
-# define MGA_TEXORGACC_PCI (0 << 1)
-# define MGA_TEXORGACC_AGP (1 << 1)
-#define MGA_TEXORG1 0x2ca4
-#define MGA_TEXORG2 0x2ca8
-#define MGA_TEXORG3 0x2cac
-#define MGA_TEXORG4 0x2cb0
-#define MGA_TEXTRANS 0x2c34
-#define MGA_TEXTRANSHIGH 0x2c38
-#define MGA_TEXWIDTH 0x2c28
-
-#define MGA_WACCEPTSEQ 0x1dd4
-#define MGA_WCODEADDR 0x1e6c
-#define MGA_WFLAG 0x1dc4
-#define MGA_WFLAG1 0x1de0
-#define MGA_WFLAGNB 0x1e64
-#define MGA_WFLAGNB1 0x1e08
-#define MGA_WGETMSB 0x1dc8
-#define MGA_WIADDR 0x1dc0
-#define MGA_WIADDR2 0x1dd8
-# define MGA_WMODE_SUSPEND (0 << 0)
-# define MGA_WMODE_RESUME (1 << 0)
-# define MGA_WMODE_JUMP (2 << 0)
-# define MGA_WMODE_START (3 << 0)
-# define MGA_WAGP_ENABLE (1 << 2)
-#define MGA_WMISC 0x1e70
-# define MGA_WUCODECACHE_ENABLE (1 << 0)
-# define MGA_WMASTER_ENABLE (1 << 1)
-# define MGA_WCACHEFLUSH_ENABLE (1 << 3)
-#define MGA_WVRTXSZ 0x1dcc
-
-#define MGA_YBOT 0x1c9c
-#define MGA_YDST 0x1c90
-#define MGA_YDSTLEN 0x1c88
-#define MGA_YDSTORG 0x1c94
-#define MGA_YTOP 0x1c98
-
-#define MGA_ZORG 0x1c0c
-
-/* This finishes the current batch of commands
- */
-#define MGA_EXEC 0x0100
-
-/* AGP PLL encoding (for G200 only).
- */
-#define MGA_AGP_PLL 0x1e4c
-# define MGA_AGP2XPLL_DISABLE (0 << 0)
-# define MGA_AGP2XPLL_ENABLE (1 << 0)
-
-/* Warp registers
- */
-#define MGA_WR0 0x2d00
-#define MGA_WR1 0x2d04
-#define MGA_WR2 0x2d08
-#define MGA_WR3 0x2d0c
-#define MGA_WR4 0x2d10
-#define MGA_WR5 0x2d14
-#define MGA_WR6 0x2d18
-#define MGA_WR7 0x2d1c
-#define MGA_WR8 0x2d20
-#define MGA_WR9 0x2d24
-#define MGA_WR10 0x2d28
-#define MGA_WR11 0x2d2c
-#define MGA_WR12 0x2d30
-#define MGA_WR13 0x2d34
-#define MGA_WR14 0x2d38
-#define MGA_WR15 0x2d3c
-#define MGA_WR16 0x2d40
-#define MGA_WR17 0x2d44
-#define MGA_WR18 0x2d48
-#define MGA_WR19 0x2d4c
-#define MGA_WR20 0x2d50
-#define MGA_WR21 0x2d54
-#define MGA_WR22 0x2d58
-#define MGA_WR23 0x2d5c
-#define MGA_WR24 0x2d60
-#define MGA_WR25 0x2d64
-#define MGA_WR26 0x2d68
-#define MGA_WR27 0x2d6c
-#define MGA_WR28 0x2d70
-#define MGA_WR29 0x2d74
-#define MGA_WR30 0x2d78
-#define MGA_WR31 0x2d7c
-#define MGA_WR32 0x2d80
-#define MGA_WR33 0x2d84
-#define MGA_WR34 0x2d88
-#define MGA_WR35 0x2d8c
-#define MGA_WR36 0x2d90
-#define MGA_WR37 0x2d94
-#define MGA_WR38 0x2d98
-#define MGA_WR39 0x2d9c
-#define MGA_WR40 0x2da0
-#define MGA_WR41 0x2da4
-#define MGA_WR42 0x2da8
-#define MGA_WR43 0x2dac
-#define MGA_WR44 0x2db0
-#define MGA_WR45 0x2db4
-#define MGA_WR46 0x2db8
-#define MGA_WR47 0x2dbc
-#define MGA_WR48 0x2dc0
-#define MGA_WR49 0x2dc4
-#define MGA_WR50 0x2dc8
-#define MGA_WR51 0x2dcc
-#define MGA_WR52 0x2dd0
-#define MGA_WR53 0x2dd4
-#define MGA_WR54 0x2dd8
-#define MGA_WR55 0x2ddc
-#define MGA_WR56 0x2de0
-#define MGA_WR57 0x2de4
-#define MGA_WR58 0x2de8
-#define MGA_WR59 0x2dec
-#define MGA_WR60 0x2df0
-#define MGA_WR61 0x2df4
-#define MGA_WR62 0x2df8
-#define MGA_WR63 0x2dfc
-# define MGA_G400_WR_MAGIC (1 << 6)
-# define MGA_G400_WR56_MAGIC 0x46480000 /* 12800.0f */
-
-#define MGA_ILOAD_ALIGN 64
-#define MGA_ILOAD_MASK (MGA_ILOAD_ALIGN - 1)
-
-#define MGA_DWGCTL_FLUSH (MGA_OPCOD_TEXTURE_TRAP | \
- MGA_ATYPE_I | \
- MGA_ZMODE_NOZCMP | \
- MGA_ARZERO | \
- MGA_SGNZERO | \
- MGA_BOP_SRC | \
- (15 << MGA_TRANS_SHIFT))
-
-#define MGA_DWGCTL_CLEAR (MGA_OPCOD_TRAP | \
- MGA_ZMODE_NOZCMP | \
- MGA_SOLID | \
- MGA_ARZERO | \
- MGA_SGNZERO | \
- MGA_SHIFTZERO | \
- MGA_BOP_SRC | \
- (0 << MGA_TRANS_SHIFT) | \
- MGA_BLTMOD_BMONOLEF | \
- MGA_TRANSC | \
- MGA_CLIPDIS)
-
-#define MGA_DWGCTL_COPY (MGA_OPCOD_BITBLT | \
- MGA_ATYPE_RPL | \
- MGA_SGNZERO | \
- MGA_SHIFTZERO | \
- MGA_BOP_SRC | \
- (0 << MGA_TRANS_SHIFT) | \
- MGA_BLTMOD_BFCOL | \
- MGA_CLIPDIS)
-
-/* Simple idle test.
- */
-static __inline__ int mga_is_idle(drm_mga_private_t *dev_priv)
-{
- u32 status = MGA_READ(MGA_STATUS) & MGA_ENGINE_IDLE_MASK;
- return (status == MGA_ENDPRDMASTS);
-}
-
-#endif
diff --git a/drivers/gpu/drm/mga/mga_ioc32.c b/drivers/gpu/drm/mga/mga_ioc32.c
deleted file mode 100644
index 894472921c30..000000000000
--- a/drivers/gpu/drm/mga/mga_ioc32.c
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * \file mga_ioc32.c
- *
- * 32-bit ioctl compatibility routines for the MGA DRM.
- *
- * \author Dave Airlie <airlied@linux.ie> with code from patches by Egbert Eich
- *
- *
- * Copyright (C) Paul Mackerras 2005
- * Copyright (C) Egbert Eich 2003,2004
- * Copyright (C) Dave Airlie 2005
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software 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 (including the next
- * paragraph) 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 AUTHOR 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.
- */
-
-#include <linux/compat.h>
-
-#include "mga_drv.h"
-
-typedef struct drm32_mga_init {
- int func;
- u32 sarea_priv_offset;
- struct_group(always32bit,
- int chipset;
- int sgram;
- unsigned int maccess;
- unsigned int fb_cpp;
- unsigned int front_offset, front_pitch;
- unsigned int back_offset, back_pitch;
- unsigned int depth_cpp;
- unsigned int depth_offset, depth_pitch;
- unsigned int texture_offset[MGA_NR_TEX_HEAPS];
- unsigned int texture_size[MGA_NR_TEX_HEAPS];
- );
- u32 fb_offset;
- u32 mmio_offset;
- u32 status_offset;
- u32 warp_offset;
- u32 primary_offset;
- u32 buffers_offset;
-} drm_mga_init32_t;
-
-static int compat_mga_init(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- drm_mga_init32_t init32;
- drm_mga_init_t init;
-
- if (copy_from_user(&init32, (void __user *)arg, sizeof(init32)))
- return -EFAULT;
-
- init.func = init32.func;
- init.sarea_priv_offset = init32.sarea_priv_offset;
- memcpy(&init.always32bit, &init32.always32bit,
- sizeof(init32.always32bit));
- init.fb_offset = init32.fb_offset;
- init.mmio_offset = init32.mmio_offset;
- init.status_offset = init32.status_offset;
- init.warp_offset = init32.warp_offset;
- init.primary_offset = init32.primary_offset;
- init.buffers_offset = init32.buffers_offset;
-
- return drm_ioctl_kernel(file, mga_dma_init, &init,
- DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY);
-}
-
-typedef struct drm_mga_getparam32 {
- int param;
- u32 value;
-} drm_mga_getparam32_t;
-
-static int compat_mga_getparam(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- drm_mga_getparam32_t getparam32;
- drm_mga_getparam_t getparam;
-
- if (copy_from_user(&getparam32, (void __user *)arg, sizeof(getparam32)))
- return -EFAULT;
-
- getparam.param = getparam32.param;
- getparam.value = compat_ptr(getparam32.value);
- return drm_ioctl_kernel(file, mga_getparam, &getparam, DRM_AUTH);
-}
-
-typedef struct drm_mga_drm_bootstrap32 {
- u32 texture_handle;
- u32 texture_size;
- u32 primary_size;
- u32 secondary_bin_count;
- u32 secondary_bin_size;
- u32 agp_mode;
- u8 agp_size;
-} drm_mga_dma_bootstrap32_t;
-
-static int compat_mga_dma_bootstrap(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- drm_mga_dma_bootstrap32_t dma_bootstrap32;
- drm_mga_dma_bootstrap_t dma_bootstrap;
- int err;
-
- if (copy_from_user(&dma_bootstrap32, (void __user *)arg,
- sizeof(dma_bootstrap32)))
- return -EFAULT;
-
- dma_bootstrap.texture_handle = dma_bootstrap32.texture_handle;
- dma_bootstrap.texture_size = dma_bootstrap32.texture_size;
- dma_bootstrap.primary_size = dma_bootstrap32.primary_size;
- dma_bootstrap.secondary_bin_count = dma_bootstrap32.secondary_bin_count;
- dma_bootstrap.secondary_bin_size = dma_bootstrap32.secondary_bin_size;
- dma_bootstrap.agp_mode = dma_bootstrap32.agp_mode;
- dma_bootstrap.agp_size = dma_bootstrap32.agp_size;
-
- err = drm_ioctl_kernel(file, mga_dma_bootstrap, &dma_bootstrap,
- DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY);
- if (err)
- return err;
-
- dma_bootstrap32.texture_handle = dma_bootstrap.texture_handle;
- dma_bootstrap32.texture_size = dma_bootstrap.texture_size;
- dma_bootstrap32.primary_size = dma_bootstrap.primary_size;
- dma_bootstrap32.secondary_bin_count = dma_bootstrap.secondary_bin_count;
- dma_bootstrap32.secondary_bin_size = dma_bootstrap.secondary_bin_size;
- dma_bootstrap32.agp_mode = dma_bootstrap.agp_mode;
- dma_bootstrap32.agp_size = dma_bootstrap.agp_size;
- if (copy_to_user((void __user *)arg, &dma_bootstrap32,
- sizeof(dma_bootstrap32)))
- return -EFAULT;
-
- return 0;
-}
-
-static struct {
- drm_ioctl_compat_t *fn;
- char *name;
-} mga_compat_ioctls[] = {
-#define DRM_IOCTL32_DEF(n, f)[DRM_##n] = {.fn = f, .name = #n}
- DRM_IOCTL32_DEF(MGA_INIT, compat_mga_init),
- DRM_IOCTL32_DEF(MGA_GETPARAM, compat_mga_getparam),
- DRM_IOCTL32_DEF(MGA_DMA_BOOTSTRAP, compat_mga_dma_bootstrap),
-};
-
-/**
- * mga_compat_ioctl - Called whenever a 32-bit process running under
- * a 64-bit kernel performs an ioctl on /dev/dri/card<n>.
- *
- * @filp: file pointer.
- * @cmd: command.
- * @arg: user argument.
- * return: zero on success or negative number on failure.
- */
-long mga_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
-{
- unsigned int nr = DRM_IOCTL_NR(cmd);
- struct drm_file *file_priv = filp->private_data;
- drm_ioctl_compat_t *fn = NULL;
- int ret;
-
- if (nr < DRM_COMMAND_BASE)
- return drm_compat_ioctl(filp, cmd, arg);
-
- if (nr >= DRM_COMMAND_BASE + ARRAY_SIZE(mga_compat_ioctls))
- return drm_ioctl(filp, cmd, arg);
-
- fn = mga_compat_ioctls[nr - DRM_COMMAND_BASE].fn;
- if (!fn)
- return drm_ioctl(filp, cmd, arg);
-
- DRM_DEBUG("pid=%d, dev=0x%lx, auth=%d, %s\n",
- task_pid_nr(current),
- (long)old_encode_dev(file_priv->minor->kdev->devt),
- file_priv->authenticated,
- mga_compat_ioctls[nr - DRM_COMMAND_BASE].name);
- ret = (*fn) (filp, cmd, arg);
- if (ret)
- DRM_DEBUG("ret = %d\n", ret);
- return ret;
-}
diff --git a/drivers/gpu/drm/mga/mga_irq.c b/drivers/gpu/drm/mga/mga_irq.c
deleted file mode 100644
index a7e6ffc80a78..000000000000
--- a/drivers/gpu/drm/mga/mga_irq.c
+++ /dev/null
@@ -1,169 +0,0 @@
-/* mga_irq.c -- IRQ handling for radeon -*- linux-c -*-
- */
-/*
- * Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved.
- *
- * The Weather Channel (TM) funded Tungsten Graphics to develop the
- * initial release of the Radeon 8500 driver under the XFree86 license.
- * This notice must be preserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software 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 (including the next
- * paragraph) 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
- * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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.
- *
- * Authors:
- * Keith Whitwell <keith@tungstengraphics.com>
- * Eric Anholt <anholt@FreeBSD.org>
- */
-
-#include "mga_drv.h"
-
-u32 mga_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
-{
- const drm_mga_private_t *const dev_priv =
- (drm_mga_private_t *) dev->dev_private;
-
- if (pipe != 0)
- return 0;
-
- return atomic_read(&dev_priv->vbl_received);
-}
-
-
-irqreturn_t mga_driver_irq_handler(int irq, void *arg)
-{
- struct drm_device *dev = (struct drm_device *) arg;
- drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
- int status;
- int handled = 0;
-
- status = MGA_READ(MGA_STATUS);
-
- /* VBLANK interrupt */
- if (status & MGA_VLINEPEN) {
- MGA_WRITE(MGA_ICLEAR, MGA_VLINEICLR);
- atomic_inc(&dev_priv->vbl_received);
- drm_handle_vblank(dev, 0);
- handled = 1;
- }
-
- /* SOFTRAP interrupt */
- if (status & MGA_SOFTRAPEN) {
- const u32 prim_start = MGA_READ(MGA_PRIMADDRESS);
- const u32 prim_end = MGA_READ(MGA_PRIMEND);
-
-
- MGA_WRITE(MGA_ICLEAR, MGA_SOFTRAPICLR);
-
- /* In addition to clearing the interrupt-pending bit, we
- * have to write to MGA_PRIMEND to re-start the DMA operation.
- */
- if ((prim_start & ~0x03) != (prim_end & ~0x03))
- MGA_WRITE(MGA_PRIMEND, prim_end);
-
- atomic_inc(&dev_priv->last_fence_retired);
- wake_up(&dev_priv->fence_queue);
- handled = 1;
- }
-
- if (handled)
- return IRQ_HANDLED;
- return IRQ_NONE;
-}
-
-int mga_enable_vblank(struct drm_device *dev, unsigned int pipe)
-{
- drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
-
- if (pipe != 0) {
- DRM_ERROR("tried to enable vblank on non-existent crtc %u\n",
- pipe);
- return 0;
- }
-
- MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN);
- return 0;
-}
-
-
-void mga_disable_vblank(struct drm_device *dev, unsigned int pipe)
-{
- if (pipe != 0) {
- DRM_ERROR("tried to disable vblank on non-existent crtc %u\n",
- pipe);
- }
-
- /* Do *NOT* disable the vertical refresh interrupt. MGA doesn't have
- * a nice hardware counter that tracks the number of refreshes when
- * the interrupt is disabled, and the kernel doesn't know the refresh
- * rate to calculate an estimate.
- */
- /* MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); */
-}
-
-void mga_driver_fence_wait(struct drm_device *dev, unsigned int *sequence)
-{
- drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
- unsigned int cur_fence;
-
- /* Assume that the user has missed the current sequence number
- * by about a day rather than she wants to wait for years
- * using fences.
- */
- wait_event_timeout(dev_priv->fence_queue,
- (((cur_fence = atomic_read(&dev_priv->last_fence_retired))
- - *sequence) <= (1 << 23)),
- msecs_to_jiffies(3000));
-
- *sequence = cur_fence;
-}
-
-void mga_driver_irq_preinstall(struct drm_device *dev)
-{
- drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
-
- /* Disable *all* interrupts */
- MGA_WRITE(MGA_IEN, 0);
- /* Clear bits if they're already high */
- MGA_WRITE(MGA_ICLEAR, ~0);
-}
-
-int mga_driver_irq_postinstall(struct drm_device *dev)
-{
- drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
-
- init_waitqueue_head(&dev_priv->fence_queue);
-
- /* Turn on soft trap interrupt. Vertical blank interrupts are enabled
- * in mga_enable_vblank.
- */
- MGA_WRITE(MGA_IEN, MGA_SOFTRAPEN);
- return 0;
-}
-
-void mga_driver_irq_uninstall(struct drm_device *dev)
-{
- drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
- if (!dev_priv)
- return;
-
- /* Disable *all* interrupts */
- MGA_WRITE(MGA_IEN, 0);
-
- dev->irq_enabled = false;
-}
diff --git a/drivers/gpu/drm/mga/mga_state.c b/drivers/gpu/drm/mga/mga_state.c
deleted file mode 100644
index 5b7247b58451..000000000000
--- a/drivers/gpu/drm/mga/mga_state.c
+++ /dev/null
@@ -1,1099 +0,0 @@
-/* mga_state.c -- State support for MGA G200/G400 -*- linux-c -*-
- * Created: Thu Jan 27 02:53:43 2000 by jhartmann@precisioninsight.com
- *
- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software 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 (including the next
- * paragraph) 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
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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.
- *
- * Authors:
- * Jeff Hartmann <jhartmann@valinux.com>
- * Keith Whitwell <keith@tungstengraphics.com>
- *
- * Rewritten by:
- * Gareth Hughes <gareth@valinux.com>
- */
-
-#include "mga_drv.h"
-
-/* ================================================================
- * DMA hardware state programming functions
- */
-
-static void mga_emit_clip_rect(drm_mga_private_t *dev_priv,
- struct drm_clip_rect *box)
-{
- drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
- unsigned int pitch = dev_priv->front_pitch;
- DMA_LOCALS;
-
- BEGIN_DMA(2);
-
- /* Force reset of DWGCTL on G400 (eliminates clip disable bit).
- */
- if (dev_priv->chipset >= MGA_CARD_TYPE_G400) {
- DMA_BLOCK(MGA_DWGCTL, ctx->dwgctl,
- MGA_LEN + MGA_EXEC, 0x80000000,
- MGA_DWGCTL, ctx->dwgctl,
- MGA_LEN + MGA_EXEC, 0x80000000);
- }
- DMA_BLOCK(MGA_DMAPAD, 0x00000000,
- MGA_CXBNDRY, ((box->x2 - 1) << 16) | box->x1,
- MGA_YTOP, box->y1 * pitch, MGA_YBOT, (box->y2 - 1) * pitch);
-
- ADVANCE_DMA();
-}
-
-static __inline__ void mga_g200_emit_context(drm_mga_private_t *dev_priv)
-{
- drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
- DMA_LOCALS;
-
- BEGIN_DMA(3);
-
- DMA_BLOCK(MGA_DSTORG, ctx->dstorg,
- MGA_MACCESS, ctx->maccess,
- MGA_PLNWT, ctx->plnwt, MGA_DWGCTL, ctx->dwgctl);
-
- DMA_BLOCK(MGA_ALPHACTRL, ctx->alphactrl,
- MGA_FOGCOL, ctx->fogcolor,
- MGA_WFLAG, ctx->wflag, MGA_ZORG, dev_priv->depth_offset);
-
- DMA_BLOCK(MGA_FCOL, ctx->fcol,
- MGA_DMAPAD, 0x00000000,
- MGA_DMAPAD, 0x00000000, MGA_DMAPAD, 0x00000000);
-
- ADVANCE_DMA();
-}
-
-static __inline__ void mga_g400_emit_context(drm_mga_private_t *dev_priv)
-{
- drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
- DMA_LOCALS;
-
- BEGIN_DMA(4);
-
- DMA_BLOCK(MGA_DSTORG, ctx->dstorg,
- MGA_MACCESS, ctx->maccess,
- MGA_PLNWT, ctx->plnwt, MGA_DWGCTL, ctx->dwgctl);
-
- DMA_BLOCK(MGA_ALPHACTRL, ctx->alphactrl,
- MGA_FOGCOL, ctx->fogcolor,
- MGA_WFLAG, ctx->wflag, MGA_ZORG, dev_priv->depth_offset);
-
- DMA_BLOCK(MGA_WFLAG1, ctx->wflag,
- MGA_TDUALSTAGE0, ctx->tdualstage0,
- MGA_TDUALSTAGE1, ctx->tdualstage1, MGA_FCOL, ctx->fcol);
-
- DMA_BLOCK(MGA_STENCIL, ctx->stencil,
- MGA_STENCILCTL, ctx->stencilctl,
- MGA_DMAPAD, 0x00000000, MGA_DMAPAD, 0x00000000);
-
- ADVANCE_DMA();
-}
-
-static __inline__ void mga_g200_emit_tex0(drm_mga_private_t *dev_priv)
-{
- drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[0];
- DMA_LOCALS;
-
- BEGIN_DMA(4);
-
- DMA_BLOCK(MGA_TEXCTL2, tex->texctl2,
- MGA_TEXCTL, tex->texctl,
- MGA_TEXFILTER, tex->texfilter,
- MGA_TEXBORDERCOL, tex->texbordercol);
-
- DMA_BLOCK(MGA_TEXORG, tex->texorg,
- MGA_TEXORG1, tex->texorg1,
- MGA_TEXORG2, tex->texorg2, MGA_TEXORG3, tex->texorg3);
-
- DMA_BLOCK(MGA_TEXORG4, tex->texorg4,
- MGA_TEXWIDTH, tex->texwidth,
- MGA_TEXHEIGHT, tex->texheight, MGA_WR24, tex->texwidth);
-
- DMA_BLOCK(MGA_WR34, tex->texheight,
- MGA_TEXTRANS, 0x0000ffff,
- MGA_TEXTRANSHIGH, 0x0000ffff, MGA_DMAPAD, 0x00000000);
-
- ADVANCE_DMA();
-}
-
-static __inline__ void mga_g400_emit_tex0(drm_mga_private_t *dev_priv)
-{
- drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[0];
- DMA_LOCALS;
-
-/* printk("mga_g400_emit_tex0 %x %x %x\n", tex->texorg, */
-/* tex->texctl, tex->texctl2); */
-
- BEGIN_DMA(6);
-
- DMA_BLOCK(MGA_TEXCTL2, tex->texctl2 | MGA_G400_TC2_MAGIC,
- MGA_TEXCTL, tex->texctl,
- MGA_TEXFILTER, tex->texfilter,
- MGA_TEXBORDERCOL, tex->texbordercol);
-
- DMA_BLOCK(MGA_TEXORG, tex->texorg,
- MGA_TEXORG1, tex->texorg1,
- MGA_TEXORG2, tex->texorg2, MGA_TEXORG3, tex->texorg3);
-
- DMA_BLOCK(MGA_TEXORG4, tex->texorg4,
- MGA_TEXWIDTH, tex->texwidth,
- MGA_TEXHEIGHT, tex->texheight, MGA_WR49, 0x00000000);
-
- DMA_BLOCK(MGA_WR57, 0x00000000,
- MGA_WR53, 0x00000000,
- MGA_WR61, 0x00000000, MGA_WR52, MGA_G400_WR_MAGIC);
-
- DMA_BLOCK(MGA_WR60, MGA_G400_WR_MAGIC,
- MGA_WR54, tex->texwidth | MGA_G400_WR_MAGIC,
- MGA_WR62, tex->texheight | MGA_G400_WR_MAGIC,
- MGA_DMAPAD, 0x00000000);
-
- DMA_BLOCK(MGA_DMAPAD, 0x00000000,
- MGA_DMAPAD, 0x00000000,
- MGA_TEXTRANS, 0x0000ffff, MGA_TEXTRANSHIGH, 0x0000ffff);
-
- ADVANCE_DMA();
-}
-
-static __inline__ void mga_g400_emit_tex1(drm_mga_private_t *dev_priv)
-{
- drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[1];
- DMA_LOCALS;
-
-/* printk("mga_g400_emit_tex1 %x %x %x\n", tex->texorg, */
-/* tex->texctl, tex->texctl2); */
-
- BEGIN_DMA(5);
-
- DMA_BLOCK(MGA_TEXCTL2, (tex->texctl2 |
- MGA_MAP1_ENABLE |
- MGA_G400_TC2_MAGIC),
- MGA_TEXCTL, tex->texctl,
- MGA_TEXFILTER, tex->texfilter,
- MGA_TEXBORDERCOL, tex->texbordercol);
-
- DMA_BLOCK(MGA_TEXORG, tex->texorg,
- MGA_TEXORG1, tex->texorg1,
- MGA_TEXORG2, tex->texorg2, MGA_TEXORG3, tex->texorg3);
-
- DMA_BLOCK(MGA_TEXORG4, tex->texorg4,
- MGA_TEXWIDTH, tex->texwidth,
- MGA_TEXHEIGHT, tex->texheight, MGA_WR49, 0x00000000);
-
- DMA_BLOCK(MGA_WR57, 0x00000000,
- MGA_WR53, 0x00000000,
- MGA_WR61, 0x00000000,
- MGA_WR52, tex->texwidth | MGA_G400_WR_MAGIC);
-
- DMA_BLOCK(MGA_WR60, tex->texheight | MGA_G400_WR_MAGIC,
- MGA_TEXTRANS, 0x0000ffff,
- MGA_TEXTRANSHIGH, 0x0000ffff,
- MGA_TEXCTL2, tex->texctl2 | MGA_G400_TC2_MAGIC);
-
- ADVANCE_DMA();
-}
-
-static __inline__ void mga_g200_emit_pipe(drm_mga_private_t *dev_priv)
-{
- drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
- unsigned int pipe = sarea_priv->warp_pipe;
- DMA_LOCALS;
-
- BEGIN_DMA(3);
-
- DMA_BLOCK(MGA_WIADDR, MGA_WMODE_SUSPEND,
- MGA_WVRTXSZ, 0x00000007,
- MGA_WFLAG, 0x00000000, MGA_WR24, 0x00000000);
-
- DMA_BLOCK(MGA_WR25, 0x00000100,
- MGA_WR34, 0x00000000,
- MGA_WR42, 0x0000ffff, MGA_WR60, 0x0000ffff);
-
- /* Padding required due to hardware bug.
- */
- DMA_BLOCK(MGA_DMAPAD, 0xffffffff,
- MGA_DMAPAD, 0xffffffff,
- MGA_DMAPAD, 0xffffffff,
- MGA_WIADDR, (dev_priv->warp_pipe_phys[pipe] |
- MGA_WMODE_START | dev_priv->wagp_enable));
-
- ADVANCE_DMA();
-}
-
-static __inline__ void mga_g400_emit_pipe(drm_mga_private_t *dev_priv)
-{
- drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
- unsigned int pipe = sarea_priv->warp_pipe;
- DMA_LOCALS;
-
-/* printk("mga_g400_emit_pipe %x\n", pipe); */
-
- BEGIN_DMA(10);
-
- DMA_BLOCK(MGA_WIADDR2, MGA_WMODE_SUSPEND,
- MGA_DMAPAD, 0x00000000,
- MGA_DMAPAD, 0x00000000, MGA_DMAPAD, 0x00000000);
-
- if (pipe & MGA_T2) {
- DMA_BLOCK(MGA_WVRTXSZ, 0x00001e09,
- MGA_DMAPAD, 0x00000000,
- MGA_DMAPAD, 0x00000000, MGA_DMAPAD, 0x00000000);
-
- DMA_BLOCK(MGA_WACCEPTSEQ, 0x00000000,
- MGA_WACCEPTSEQ, 0x00000000,
- MGA_WACCEPTSEQ, 0x00000000,
- MGA_WACCEPTSEQ, 0x1e000000);
- } else {
- if (dev_priv->warp_pipe & MGA_T2) {
- /* Flush the WARP pipe */
- DMA_BLOCK(MGA_YDST, 0x00000000,
- MGA_FXLEFT, 0x00000000,
- MGA_FXRIGHT, 0x00000001,
- MGA_DWGCTL, MGA_DWGCTL_FLUSH);
-
- DMA_BLOCK(MGA_LEN + MGA_EXEC, 0x00000001,
- MGA_DWGSYNC, 0x00007000,
- MGA_TEXCTL2, MGA_G400_TC2_MAGIC,
- MGA_LEN + MGA_EXEC, 0x00000000);
-
- DMA_BLOCK(MGA_TEXCTL2, (MGA_DUALTEX |
- MGA_G400_TC2_MAGIC),
- MGA_LEN + MGA_EXEC, 0x00000000,
- MGA_TEXCTL2, MGA_G400_TC2_MAGIC,
- MGA_DMAPAD, 0x00000000);
- }
-
- DMA_BLOCK(MGA_WVRTXSZ, 0x00001807,
- MGA_DMAPAD, 0x00000000,
- MGA_DMAPAD, 0x00000000, MGA_DMAPAD, 0x00000000);
-
- DMA_BLOCK(MGA_WACCEPTSEQ, 0x00000000,
- MGA_WACCEPTSEQ, 0x00000000,
- MGA_WACCEPTSEQ, 0x00000000,
- MGA_WACCEPTSEQ, 0x18000000);
- }
-
- DMA_BLOCK(MGA_WFLAG, 0x00000000,
- MGA_WFLAG1, 0x00000000,
- MGA_WR56, MGA_G400_WR56_MAGIC, MGA_DMAPAD, 0x00000000);
-
- DMA_BLOCK(MGA_WR49, 0x00000000, /* tex0 */
- MGA_WR57, 0x00000000, /* tex0 */
- MGA_WR53, 0x00000000, /* tex1 */
- MGA_WR61, 0x00000000); /* tex1 */
-
- DMA_BLOCK(MGA_WR54, MGA_G400_WR_MAGIC, /* tex0 width */
- MGA_WR62, MGA_G400_WR_MAGIC, /* tex0 height */
- MGA_WR52, MGA_G400_WR_MAGIC, /* tex1 width */
- MGA_WR60, MGA_G400_WR_MAGIC); /* tex1 height */
-
- /* Padding required due to hardware bug */
- DMA_BLOCK(MGA_DMAPAD, 0xffffffff,
- MGA_DMAPAD, 0xffffffff,
- MGA_DMAPAD, 0xffffffff,
- MGA_WIADDR2, (dev_priv->warp_pipe_phys[pipe] |
- MGA_WMODE_START | dev_priv->wagp_enable));
-
- ADVANCE_DMA();
-}
-
-static void mga_g200_emit_state(drm_mga_private_t *dev_priv)
-{
- drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
- unsigned int dirty = sarea_priv->dirty;
-
- if (sarea_priv->warp_pipe != dev_priv->warp_pipe) {
- mga_g200_emit_pipe(dev_priv);
- dev_priv->warp_pipe = sarea_priv->warp_pipe;
- }
-
- if (dirty & MGA_UPLOAD_CONTEXT) {
- mga_g200_emit_context(dev_priv);
- sarea_priv->dirty &= ~MGA_UPLOAD_CONTEXT;
- }
-
- if (dirty & MGA_UPLOAD_TEX0) {
- mga_g200_emit_tex0(dev_priv);
- sarea_priv->dirty &= ~MGA_UPLOAD_TEX0;
- }
-}
-
-static void mga_g400_emit_state(drm_mga_private_t *dev_priv)
-{
- drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
- unsigned int dirty = sarea_priv->dirty;
- int multitex = sarea_priv->warp_pipe & MGA_T2;
-
- if (sarea_priv->warp_pipe != dev_priv->warp_pipe) {
- mga_g400_emit_pipe(dev_priv);
- dev_priv->warp_pipe = sarea_priv->warp_pipe;
- }
-
- if (dirty & MGA_UPLOAD_CONTEXT) {
- mga_g400_emit_context(dev_priv);
- sarea_priv->dirty &= ~MGA_UPLOAD_CONTEXT;
- }
-
- if (dirty & MGA_UPLOAD_TEX0) {
- mga_g400_emit_tex0(dev_priv);
- sarea_priv->dirty &= ~MGA_UPLOAD_TEX0;
- }
-
- if ((dirty & MGA_UPLOAD_TEX1) && multitex) {
- mga_g400_emit_tex1(dev_priv);
- sarea_priv->dirty &= ~MGA_UPLOAD_TEX1;
- }
-}
-
-/* ================================================================
- * SAREA state verification
- */
-
-/* Disallow all write destinations except the front and backbuffer.
- */
-static int mga_verify_context(drm_mga_private_t *dev_priv)
-{
- drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
-
- if (ctx->dstorg != dev_priv->front_offset &&
- ctx->dstorg != dev_priv->back_offset) {
- DRM_ERROR("*** bad DSTORG: %x (front %x, back %x)\n\n",
- ctx->dstorg, dev_priv->front_offset,
- dev_priv->back_offset);
- ctx->dstorg = 0;
- return -EINVAL;
- }
-
- return 0;
-}
-
-/* Disallow texture reads from PCI space.
- */
-static int mga_verify_tex(drm_mga_private_t *dev_priv, int unit)
-{
- drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[unit];
- unsigned int org;
-
- org = tex->texorg & (MGA_TEXORGMAP_MASK | MGA_TEXORGACC_MASK);
-
- if (org == (MGA_TEXORGMAP_SYSMEM | MGA_TEXORGACC_PCI)) {
- DRM_ERROR("*** bad TEXORG: 0x%x, unit %d\n", tex->texorg, unit);
- tex->texorg = 0;
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int mga_verify_state(drm_mga_private_t *dev_priv)
-{
- drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
- unsigned int dirty = sarea_priv->dirty;
- int ret = 0;
-
- if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS)
- sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS;
-
- if (dirty & MGA_UPLOAD_CONTEXT)
- ret |= mga_verify_context(dev_priv);
-
- if (dirty & MGA_UPLOAD_TEX0)
- ret |= mga_verify_tex(dev_priv, 0);
-
- if (dev_priv->chipset >= MGA_CARD_TYPE_G400) {
- if (dirty & MGA_UPLOAD_TEX1)
- ret |= mga_verify_tex(dev_priv, 1);
-
- if (dirty & MGA_UPLOAD_PIPE)
- ret |= (sarea_priv->warp_pipe > MGA_MAX_G400_PIPES);
- } else {
- if (dirty & MGA_UPLOAD_PIPE)
- ret |= (sarea_priv->warp_pipe > MGA_MAX_G200_PIPES);
- }
-
- return (ret == 0);
-}
-
-static int mga_verify_iload(drm_mga_private_t *dev_priv,
- unsigned int dstorg, unsigned int length)
-{
- if (dstorg < dev_priv->texture_offset ||
- dstorg + length > (dev_priv->texture_offset +
- dev_priv->texture_size)) {
- DRM_ERROR("*** bad iload DSTORG: 0x%x\n", dstorg);
- return -EINVAL;
- }
-
- if (length & MGA_ILOAD_MASK) {
- DRM_ERROR("*** bad iload length: 0x%x\n",
- length & MGA_ILOAD_MASK);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int mga_verify_blit(drm_mga_private_t *dev_priv,
- unsigned int srcorg, unsigned int dstorg)
-{
- if ((srcorg & 0x3) == (MGA_SRCACC_PCI | MGA_SRCMAP_SYSMEM) ||
- (dstorg & 0x3) == (MGA_SRCACC_PCI | MGA_SRCMAP_SYSMEM)) {
- DRM_ERROR("*** bad blit: src=0x%x dst=0x%x\n", srcorg, dstorg);
- return -EINVAL;
- }
- return 0;
-}
-
-/* ================================================================
- *
- */
-
-static void mga_dma_dispatch_clear(struct drm_device *dev, drm_mga_clear_t *clear)
-{
- drm_mga_private_t *dev_priv = dev->dev_private;
- drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
- struct drm_clip_rect *pbox = sarea_priv->boxes;
- int nbox = sarea_priv->nbox;
- int i;
- DMA_LOCALS;
- DRM_DEBUG("\n");
-
- BEGIN_DMA(1);
-
- DMA_BLOCK(MGA_DMAPAD, 0x00000000,
- MGA_DMAPAD, 0x00000000,
- MGA_DWGSYNC, 0x00007100, MGA_DWGSYNC, 0x00007000);
-
- ADVANCE_DMA();
-
- for (i = 0; i < nbox; i++) {
- struct drm_clip_rect *box = &pbox[i];
- u32 height = box->y2 - box->y1;
-
- DRM_DEBUG(" from=%d,%d to=%d,%d\n",
- box->x1, box->y1, box->x2, box->y2);
-
- if (clear->flags & MGA_FRONT) {
- BEGIN_DMA(2);
-
- DMA_BLOCK(MGA_DMAPAD, 0x00000000,
- MGA_PLNWT, clear->color_mask,
- MGA_YDSTLEN, (box->y1 << 16) | height,
- MGA_FXBNDRY, (box->x2 << 16) | box->x1);
-
- DMA_BLOCK(MGA_DMAPAD, 0x00000000,
- MGA_FCOL, clear->clear_color,
- MGA_DSTORG, dev_priv->front_offset,
- MGA_DWGCTL + MGA_EXEC, dev_priv->clear_cmd);
-
- ADVANCE_DMA();
- }
-
- if (clear->flags & MGA_BACK) {
- BEGIN_DMA(2);
-
- DMA_BLOCK(MGA_DMAPAD, 0x00000000,
- MGA_PLNWT, clear->color_mask,
- MGA_YDSTLEN, (box->y1 << 16) | height,
- MGA_FXBNDRY, (box->x2 << 16) | box->x1);
-
- DMA_BLOCK(MGA_DMAPAD, 0x00000000,
- MGA_FCOL, clear->clear_color,
- MGA_DSTORG, dev_priv->back_offset,
- MGA_DWGCTL + MGA_EXEC, dev_priv->clear_cmd);
-
- ADVANCE_DMA();
- }
-
- if (clear->flags & MGA_DEPTH) {
- BEGIN_DMA(2);
-
- DMA_BLOCK(MGA_DMAPAD, 0x00000000,
- MGA_PLNWT, clear->depth_mask,
- MGA_YDSTLEN, (box->y1 << 16) | height,
- MGA_FXBNDRY, (box->x2 << 16) | box->x1);
-
- DMA_BLOCK(MGA_DMAPAD, 0x00000000,
- MGA_FCOL, clear->clear_depth,
- MGA_DSTORG, dev_priv->depth_offset,
- MGA_DWGCTL + MGA_EXEC, dev_priv->clear_cmd);
-
- ADVANCE_DMA();
- }
-
- }
-
- BEGIN_DMA(1);
-
- /* Force reset of DWGCTL */
- DMA_BLOCK(MGA_DMAPAD, 0x00000000,
- MGA_DMAPAD, 0x00000000,
- MGA_PLNWT, ctx->plnwt, MGA_DWGCTL, ctx->dwgctl);
-
- ADVANCE_DMA();
-
- FLUSH_DMA();
-}
-
-static void mga_dma_dispatch_swap(struct drm_device *dev)
-{
- drm_mga_private_t *dev_priv = dev->dev_private;
- drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
- struct drm_clip_rect *pbox = sarea_priv->boxes;
- int nbox = sarea_priv->nbox;
- int i;
- DMA_LOCALS;
- DRM_DEBUG("\n");
-
- sarea_priv->last_frame.head = dev_priv->prim.tail;
- sarea_priv->last_frame.wrap = dev_priv->prim.last_wrap;
-
- BEGIN_DMA(4 + nbox);
-
- DMA_BLOCK(MGA_DMAPAD, 0x00000000,
- MGA_DMAPAD, 0x00000000,
- MGA_DWGSYNC, 0x00007100, MGA_DWGSYNC, 0x00007000);
-
- DMA_BLOCK(MGA_DSTORG, dev_priv->front_offset,
- MGA_MACCESS, dev_priv->maccess,
- MGA_SRCORG, dev_priv->back_offset,
- MGA_AR5, dev_priv->front_pitch);
-
- DMA_BLOCK(MGA_DMAPAD, 0x00000000,
- MGA_DMAPAD, 0x00000000,
- MGA_PLNWT, 0xffffffff, MGA_DWGCTL, MGA_DWGCTL_COPY);
-
- for (i = 0; i < nbox; i++) {
- struct drm_clip_rect *box = &pbox[i];
- u32 height = box->y2 - box->y1;
- u32 start = box->y1 * dev_priv->front_pitch;
-
- DRM_DEBUG(" from=%d,%d to=%d,%d\n",
- box->x1, box->y1, box->x2, box->y2);
-
- DMA_BLOCK(MGA_AR0, start + box->x2 - 1,
- MGA_AR3, start + box->x1,
- MGA_FXBNDRY, ((box->x2 - 1) << 16) | box->x1,
- MGA_YDSTLEN + MGA_EXEC, (box->y1 << 16) | height);
- }
-
- DMA_BLOCK(MGA_DMAPAD, 0x00000000,
- MGA_PLNWT, ctx->plnwt,
- MGA_SRCORG, dev_priv->front_offset, MGA_DWGCTL, ctx->dwgctl);
-
- ADVANCE_DMA();
-
- FLUSH_DMA();
-
- DRM_DEBUG("... done.\n");
-}
-
-static void mga_dma_dispatch_vertex(struct drm_device *dev, struct drm_buf *buf)
-{
- drm_mga_private_t *dev_priv = dev->dev_private;
- drm_mga_buf_priv_t *buf_priv = buf->dev_private;
- drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
- u32 address = (u32) buf->bus_address;
- u32 length = (u32) buf->used;
- int i = 0;
- DMA_LOCALS;
- DRM_DEBUG("buf=%d used=%d\n", buf->idx, buf->used);
-
- if (buf->used) {
- buf_priv->dispatched = 1;
-
- MGA_EMIT_STATE(dev_priv, sarea_priv->dirty);
-
- do {
- if (i < sarea_priv->nbox) {
- mga_emit_clip_rect(dev_priv,
- &sarea_priv->boxes[i]);
- }
-
- BEGIN_DMA(1);
-
- DMA_BLOCK(MGA_DMAPAD, 0x00000000,
- MGA_DMAPAD, 0x00000000,
- MGA_SECADDRESS, (address |
- MGA_DMA_VERTEX),
- MGA_SECEND, ((address + length) |
- dev_priv->dma_access));
-
- ADVANCE_DMA();
- } while (++i < sarea_priv->nbox);
- }
-
- if (buf_priv->discard) {
- AGE_BUFFER(buf_priv);
- buf->pending = 0;
- buf->used = 0;
- buf_priv->dispatched = 0;
-
- mga_freelist_put(dev, buf);
- }
-
- FLUSH_DMA();
-}
-
-static void mga_dma_dispatch_indices(struct drm_device *dev, struct drm_buf *buf,
- unsigned int start, unsigned int end)
-{
- drm_mga_private_t *dev_priv = dev->dev_private;
- drm_mga_buf_priv_t *buf_priv = buf->dev_private;
- drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
- u32 address = (u32) buf->bus_address;
- int i = 0;
- DMA_LOCALS;
- DRM_DEBUG("buf=%d start=%d end=%d\n", buf->idx, start, end);
-
- if (start != end) {
- buf_priv->dispatched = 1;
-
- MGA_EMIT_STATE(dev_priv, sarea_priv->dirty);
-
- do {
- if (i < sarea_priv->nbox) {
- mga_emit_clip_rect(dev_priv,
- &sarea_priv->boxes[i]);
- }
-
- BEGIN_DMA(1);
-
- DMA_BLOCK(MGA_DMAPAD, 0x00000000,
- MGA_DMAPAD, 0x00000000,
- MGA_SETUPADDRESS, address + start,
- MGA_SETUPEND, ((address + end) |
- dev_priv->dma_access));
-
- ADVANCE_DMA();
- } while (++i < sarea_priv->nbox);
- }
-
- if (buf_priv->discard) {
- AGE_BUFFER(buf_priv);
- buf->pending = 0;
- buf->used = 0;
- buf_priv->dispatched = 0;
-
- mga_freelist_put(dev, buf);
- }
-
- FLUSH_DMA();
-}
-
-/* This copies a 64 byte aligned agp region to the frambuffer with a
- * standard blit, the ioctl needs to do checking.
- */
-static void mga_dma_dispatch_iload(struct drm_device *dev, struct drm_buf *buf,
- unsigned int dstorg, unsigned int length)
-{
- drm_mga_private_t *dev_priv = dev->dev_private;
- drm_mga_buf_priv_t *buf_priv = buf->dev_private;
- drm_mga_context_regs_t *ctx = &dev_priv->sarea_priv->context_state;
- u32 srcorg =
- buf->bus_address | dev_priv->dma_access | MGA_SRCMAP_SYSMEM;
- u32 y2;
- DMA_LOCALS;
- DRM_DEBUG("buf=%d used=%d\n", buf->idx, buf->used);
-
- y2 = length / 64;
-
- BEGIN_DMA(5);
-
- DMA_BLOCK(MGA_DMAPAD, 0x00000000,
- MGA_DMAPAD, 0x00000000,
- MGA_DWGSYNC, 0x00007100, MGA_DWGSYNC, 0x00007000);
-
- DMA_BLOCK(MGA_DSTORG, dstorg,
- MGA_MACCESS, 0x00000000, MGA_SRCORG, srcorg, MGA_AR5, 64);
-
- DMA_BLOCK(MGA_PITCH, 64,
- MGA_PLNWT, 0xffffffff,
- MGA_DMAPAD, 0x00000000, MGA_DWGCTL, MGA_DWGCTL_COPY);
-
- DMA_BLOCK(MGA_AR0, 63,
- MGA_AR3, 0,
- MGA_FXBNDRY, (63 << 16) | 0, MGA_YDSTLEN + MGA_EXEC, y2);
-
- DMA_BLOCK(MGA_PLNWT, ctx->plnwt,
- MGA_SRCORG, dev_priv->front_offset,
- MGA_PITCH, dev_priv->front_pitch, MGA_DWGSYNC, 0x00007000);
-
- ADVANCE_DMA();
-
- AGE_BUFFER(buf_priv);
-
- buf->pending = 0;
- buf->used = 0;
- buf_priv->dispatched = 0;
-
- mga_freelist_put(dev, buf);
-
- FLUSH_DMA();
-}
-
-static void mga_dma_dispatch_blit(struct drm_device *dev, drm_mga_blit_t *blit)
-{
- drm_mga_private_t *dev_priv = dev->dev_private;
- drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
- struct drm_clip_rect *pbox = sarea_priv->boxes;
- int nbox = sarea_priv->nbox;
- u32 scandir = 0, i;
- DMA_LOCALS;
- DRM_DEBUG("\n");
-
- BEGIN_DMA(4 + nbox);
-
- DMA_BLOCK(MGA_DMAPAD, 0x00000000,
- MGA_DMAPAD, 0x00000000,
- MGA_DWGSYNC, 0x00007100, MGA_DWGSYNC, 0x00007000);
-
- DMA_BLOCK(MGA_DWGCTL, MGA_DWGCTL_COPY,
- MGA_PLNWT, blit->planemask,
- MGA_SRCORG, blit->srcorg, MGA_DSTORG, blit->dstorg);
-
- DMA_BLOCK(MGA_SGN, scandir,
- MGA_MACCESS, dev_priv->maccess,
- MGA_AR5, blit->ydir * blit->src_pitch,
- MGA_PITCH, blit->dst_pitch);
-
- for (i = 0; i < nbox; i++) {
- int srcx = pbox[i].x1 + blit->delta_sx;
- int srcy = pbox[i].y1 + blit->delta_sy;
- int dstx = pbox[i].x1 + blit->delta_dx;
- int dsty = pbox[i].y1 + blit->delta_dy;
- int h = pbox[i].y2 - pbox[i].y1;
- int w = pbox[i].x2 - pbox[i].x1 - 1;
- int start;
-
- if (blit->ydir == -1)
- srcy = blit->height - srcy - 1;
-
- start = srcy * blit->src_pitch + srcx;
-
- DMA_BLOCK(MGA_AR0, start + w,
- MGA_AR3, start,
- MGA_FXBNDRY, ((dstx + w) << 16) | (dstx & 0xffff),
- MGA_YDSTLEN + MGA_EXEC, (dsty << 16) | h);
- }
-
- /* Do something to flush AGP?
- */
-
- /* Force reset of DWGCTL */
- DMA_BLOCK(MGA_DMAPAD, 0x00000000,
- MGA_PLNWT, ctx->plnwt,
- MGA_PITCH, dev_priv->front_pitch, MGA_DWGCTL, ctx->dwgctl);
-
- ADVANCE_DMA();
-}
-
-/* ================================================================
- *
- */
-
-static int mga_dma_clear(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_mga_private_t *dev_priv = dev->dev_private;
- drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_mga_clear_t *clear = data;
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS)
- sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS;
-
- WRAP_TEST_WITH_RETURN(dev_priv);
-
- mga_dma_dispatch_clear(dev, clear);
-
- /* Make sure we restore the 3D state next time.
- */
- dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CONTEXT;
-
- return 0;
-}
-
-static int mga_dma_swap(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_mga_private_t *dev_priv = dev->dev_private;
- drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS)
- sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS;
-
- WRAP_TEST_WITH_RETURN(dev_priv);
-
- mga_dma_dispatch_swap(dev);
-
- /* Make sure we restore the 3D state next time.
- */
- dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CONTEXT;
-
- return 0;
-}
-
-static int mga_dma_vertex(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_mga_private_t *dev_priv = dev->dev_private;
- struct drm_device_dma *dma = dev->dma;
- struct drm_buf *buf;
- drm_mga_buf_priv_t *buf_priv;
- drm_mga_vertex_t *vertex = data;
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- if (vertex->idx < 0 || vertex->idx > dma->buf_count)
- return -EINVAL;
- buf = dma->buflist[vertex->idx];
- buf_priv = buf->dev_private;
-
- buf->used = vertex->used;
- buf_priv->discard = vertex->discard;
-
- if (!mga_verify_state(dev_priv)) {
- if (vertex->discard) {
- if (buf_priv->dispatched == 1)
- AGE_BUFFER(buf_priv);
- buf_priv->dispatched = 0;
- mga_freelist_put(dev, buf);
- }
- return -EINVAL;
- }
-
- WRAP_TEST_WITH_RETURN(dev_priv);
-
- mga_dma_dispatch_vertex(dev, buf);
-
- return 0;
-}
-
-static int mga_dma_indices(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_mga_private_t *dev_priv = dev->dev_private;
- struct drm_device_dma *dma = dev->dma;
- struct drm_buf *buf;
- drm_mga_buf_priv_t *buf_priv;
- drm_mga_indices_t *indices = data;
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- if (indices->idx < 0 || indices->idx > dma->buf_count)
- return -EINVAL;
-
- buf = dma->buflist[indices->idx];
- buf_priv = buf->dev_private;
-
- buf_priv->discard = indices->discard;
-
- if (!mga_verify_state(dev_priv)) {
- if (indices->discard) {
- if (buf_priv->dispatched == 1)
- AGE_BUFFER(buf_priv);
- buf_priv->dispatched = 0;
- mga_freelist_put(dev, buf);
- }
- return -EINVAL;
- }
-
- WRAP_TEST_WITH_RETURN(dev_priv);
-
- mga_dma_dispatch_indices(dev, buf, indices->start, indices->end);
-
- return 0;
-}
-
-static int mga_dma_iload(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- struct drm_device_dma *dma = dev->dma;
- drm_mga_private_t *dev_priv = dev->dev_private;
- struct drm_buf *buf;
- drm_mga_iload_t *iload = data;
- DRM_DEBUG("\n");
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
-#if 0
- if (mga_do_wait_for_idle(dev_priv) < 0) {
- if (MGA_DMA_DEBUG)
- DRM_INFO("-EBUSY\n");
- return -EBUSY;
- }
-#endif
- if (iload->idx < 0 || iload->idx > dma->buf_count)
- return -EINVAL;
-
- buf = dma->buflist[iload->idx];
-
- if (mga_verify_iload(dev_priv, iload->dstorg, iload->length)) {
- mga_freelist_put(dev, buf);
- return -EINVAL;
- }
-
- WRAP_TEST_WITH_RETURN(dev_priv);
-
- mga_dma_dispatch_iload(dev, buf, iload->dstorg, iload->length);
-
- /* Make sure we restore the 3D state next time.
- */
- dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CONTEXT;
-
- return 0;
-}
-
-static int mga_dma_blit(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_mga_private_t *dev_priv = dev->dev_private;
- drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_mga_blit_t *blit = data;
- DRM_DEBUG("\n");
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS)
- sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS;
-
- if (mga_verify_blit(dev_priv, blit->srcorg, blit->dstorg))
- return -EINVAL;
-
- WRAP_TEST_WITH_RETURN(dev_priv);
-
- mga_dma_dispatch_blit(dev, blit);
-
- /* Make sure we restore the 3D state next time.
- */
- dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CONTEXT;
-
- return 0;
-}
-
-int mga_getparam(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_mga_private_t *dev_priv = dev->dev_private;
- drm_mga_getparam_t *param = data;
- struct pci_dev *pdev = to_pci_dev(dev->dev);
- int value;
-
- if (!dev_priv) {
- DRM_ERROR("called with no initialization\n");
- return -EINVAL;
- }
-
- DRM_DEBUG("pid=%d\n", task_pid_nr(current));
-
- switch (param->param) {
- case MGA_PARAM_IRQ_NR:
- value = pdev->irq;
- break;
- case MGA_PARAM_CARD_TYPE:
- value = dev_priv->chipset;
- break;
- default:
- return -EINVAL;
- }
-
- if (copy_to_user(param->value, &value, sizeof(int))) {
- DRM_ERROR("copy_to_user\n");
- return -EFAULT;
- }
-
- return 0;
-}
-
-static int mga_set_fence(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_mga_private_t *dev_priv = dev->dev_private;
- u32 *fence = data;
- DMA_LOCALS;
-
- if (!dev_priv) {
- DRM_ERROR("called with no initialization\n");
- return -EINVAL;
- }
-
- DRM_DEBUG("pid=%d\n", task_pid_nr(current));
-
- /* I would normal do this assignment in the declaration of fence,
- * but dev_priv may be NULL.
- */
-
- *fence = dev_priv->next_fence_to_post;
- dev_priv->next_fence_to_post++;
-
- BEGIN_DMA(1);
- DMA_BLOCK(MGA_DMAPAD, 0x00000000,
- MGA_DMAPAD, 0x00000000,
- MGA_DMAPAD, 0x00000000, MGA_SOFTRAP, 0x00000000);
- ADVANCE_DMA();
-
- return 0;
-}
-
-static int mga_wait_fence(struct drm_device *dev, void *data, struct drm_file *
-file_priv)
-{
- drm_mga_private_t *dev_priv = dev->dev_private;
- u32 *fence = data;
-
- if (!dev_priv) {
- DRM_ERROR("called with no initialization\n");
- return -EINVAL;
- }
-
- DRM_DEBUG("pid=%d\n", task_pid_nr(current));
-
- mga_driver_fence_wait(dev, fence);
- return 0;
-}
-
-const struct drm_ioctl_desc mga_ioctls[] = {
- DRM_IOCTL_DEF_DRV(MGA_INIT, mga_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
- DRM_IOCTL_DEF_DRV(MGA_FLUSH, mga_dma_flush, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(MGA_RESET, mga_dma_reset, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(MGA_SWAP, mga_dma_swap, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(MGA_CLEAR, mga_dma_clear, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(MGA_VERTEX, mga_dma_vertex, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(MGA_INDICES, mga_dma_indices, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(MGA_ILOAD, mga_dma_iload, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(MGA_BLIT, mga_dma_blit, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(MGA_GETPARAM, mga_getparam, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(MGA_SET_FENCE, mga_set_fence, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(MGA_WAIT_FENCE, mga_wait_fence, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(MGA_DMA_BOOTSTRAP, mga_dma_bootstrap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
-};
-
-int mga_max_ioctl = ARRAY_SIZE(mga_ioctls);
diff --git a/drivers/gpu/drm/mga/mga_warp.c b/drivers/gpu/drm/mga/mga_warp.c
deleted file mode 100644
index b5ef1d2c8b1c..000000000000
--- a/drivers/gpu/drm/mga/mga_warp.c
+++ /dev/null
@@ -1,167 +0,0 @@
-/* mga_warp.c -- Matrox G200/G400 WARP engine management -*- linux-c -*-
- * Created: Thu Jan 11 21:29:32 2001 by gareth@valinux.com
- *
- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software 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 (including the next
- * paragraph) 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
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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.
- *
- * Authors:
- * Gareth Hughes <gareth@valinux.com>
- */
-
-#include <linux/firmware.h>
-#include <linux/ihex.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-
-#include "mga_drv.h"
-
-#define FIRMWARE_G200 "matrox/g200_warp.fw"
-#define FIRMWARE_G400 "matrox/g400_warp.fw"
-
-MODULE_FIRMWARE(FIRMWARE_G200);
-MODULE_FIRMWARE(FIRMWARE_G400);
-
-#define MGA_WARP_CODE_ALIGN 256 /* in bytes */
-
-#define WARP_UCODE_SIZE(size) ALIGN(size, MGA_WARP_CODE_ALIGN)
-
-int mga_warp_install_microcode(drm_mga_private_t *dev_priv)
-{
- unsigned char *vcbase = dev_priv->warp->handle;
- unsigned long pcbase = dev_priv->warp->offset;
- const char *firmware_name;
- struct platform_device *pdev;
- const struct firmware *fw = NULL;
- const struct ihex_binrec *rec;
- unsigned int size;
- int n_pipes, where;
- int rc = 0;
-
- switch (dev_priv->chipset) {
- case MGA_CARD_TYPE_G400:
- case MGA_CARD_TYPE_G550:
- firmware_name = FIRMWARE_G400;
- n_pipes = MGA_MAX_G400_PIPES;
- break;
- case MGA_CARD_TYPE_G200:
- firmware_name = FIRMWARE_G200;
- n_pipes = MGA_MAX_G200_PIPES;
- break;
- default:
- return -EINVAL;
- }
-
- pdev = platform_device_register_simple("mga_warp", 0, NULL, 0);
- if (IS_ERR(pdev)) {
- DRM_ERROR("mga: Failed to register microcode\n");
- return PTR_ERR(pdev);
- }
- rc = request_ihex_firmware(&fw, firmware_name, &pdev->dev);
- platform_device_unregister(pdev);
- if (rc) {
- DRM_ERROR("mga: Failed to load microcode \"%s\"\n",
- firmware_name);
- return rc;
- }
-
- size = 0;
- where = 0;
- for (rec = (const struct ihex_binrec *)fw->data;
- rec;
- rec = ihex_next_binrec(rec)) {
- size += WARP_UCODE_SIZE(be16_to_cpu(rec->len));
- where++;
- }
-
- if (where != n_pipes) {
- DRM_ERROR("mga: Invalid microcode \"%s\"\n", firmware_name);
- rc = -EINVAL;
- goto out;
- }
- size = PAGE_ALIGN(size);
- DRM_DEBUG("MGA ucode size = %d bytes\n", size);
- if (size > dev_priv->warp->size) {
- DRM_ERROR("microcode too large! (%u > %lu)\n",
- size, dev_priv->warp->size);
- rc = -ENOMEM;
- goto out;
- }
-
- memset(dev_priv->warp_pipe_phys, 0, sizeof(dev_priv->warp_pipe_phys));
-
- where = 0;
- for (rec = (const struct ihex_binrec *)fw->data;
- rec;
- rec = ihex_next_binrec(rec)) {
- unsigned int src_size, dst_size;
-
- DRM_DEBUG(" pcbase = 0x%08lx vcbase = %p\n", pcbase, vcbase);
- dev_priv->warp_pipe_phys[where] = pcbase;
- src_size = be16_to_cpu(rec->len);
- dst_size = WARP_UCODE_SIZE(src_size);
- memcpy(vcbase, rec->data, src_size);
- pcbase += dst_size;
- vcbase += dst_size;
- where++;
- }
-
-out:
- release_firmware(fw);
- return rc;
-}
-
-#define WMISC_EXPECTED (MGA_WUCODECACHE_ENABLE | MGA_WMASTER_ENABLE)
-
-int mga_warp_init(drm_mga_private_t *dev_priv)
-{
- u32 wmisc;
-
- /* FIXME: Get rid of these damned magic numbers...
- */
- switch (dev_priv->chipset) {
- case MGA_CARD_TYPE_G400:
- case MGA_CARD_TYPE_G550:
- MGA_WRITE(MGA_WIADDR2, MGA_WMODE_SUSPEND);
- MGA_WRITE(MGA_WGETMSB, 0x00000E00);
- MGA_WRITE(MGA_WVRTXSZ, 0x00001807);
- MGA_WRITE(MGA_WACCEPTSEQ, 0x18000000);
- break;
- case MGA_CARD_TYPE_G200:
- MGA_WRITE(MGA_WIADDR, MGA_WMODE_SUSPEND);
- MGA_WRITE(MGA_WGETMSB, 0x1606);
- MGA_WRITE(MGA_WVRTXSZ, 7);
- break;
- default:
- return -EINVAL;
- }
-
- MGA_WRITE(MGA_WMISC, (MGA_WUCODECACHE_ENABLE |
- MGA_WMASTER_ENABLE | MGA_WCACHEFLUSH_ENABLE));
- wmisc = MGA_READ(MGA_WMISC);
- if (wmisc != WMISC_EXPECTED) {
- DRM_ERROR("WARP engine config failed! 0x%x != 0x%x\n",
- wmisc, WMISC_EXPECTED);
- return -EINVAL;
- }
-
- return 0;
-}
diff --git a/drivers/gpu/drm/mgag200/Kconfig b/drivers/gpu/drm/mgag200/Kconfig
index eec59658a938..b28c5e4828f4 100644
--- a/drivers/gpu/drm/mgag200/Kconfig
+++ b/drivers/gpu/drm/mgag200/Kconfig
@@ -4,6 +4,8 @@ config DRM_MGAG200
depends on DRM && PCI && MMU
select DRM_GEM_SHMEM_HELPER
select DRM_KMS_HELPER
+ select I2C
+ select I2C_ALGOBIT
help
This is a KMS driver for Matrox G200 chips. It supports the original
MGA G200 desktop chips and the server variants. It requires 0.3.0
diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig
index 3c9dfdb0b328..871870ddf7ec 100644
--- a/drivers/gpu/drm/msm/Kconfig
+++ b/drivers/gpu/drm/msm/Kconfig
@@ -23,6 +23,7 @@ config DRM_MSM
select SHMEM
select TMPFS
select QCOM_SCM
+ select DEVFREQ_GOV_SIMPLE_ONDEMAND
select WANT_DEV_COREDUMP
select SND_SOC_HDMI_CODEC if SND_SOC
select SYNC_FILE
@@ -140,12 +141,12 @@ config DRM_MSM_DSI_10NM_PHY
Choose this option if DSI PHY on SDM845 is used on the platform.
config DRM_MSM_DSI_7NM_PHY
- bool "Enable DSI 7nm PHY driver in MSM DRM"
+ bool "Enable DSI 7nm/5nm/4nm PHY driver in MSM DRM"
depends on DRM_MSM_DSI
default y
help
- Choose this option if DSI PHY on SM8150/SM8250/SC7280 is used on
- the platform.
+ Choose this option if DSI PHY on SM8150/SM8250/SM8350/SM8450/SM8550/SC7280
+ is used on the platform.
config DRM_MSM_HDMI
bool "Enable HDMI support in MSM DRM driver"
diff --git a/drivers/gpu/drm/msm/adreno/a2xx_gpu.c b/drivers/gpu/drm/msm/adreno/a2xx_gpu.c
index 6c9a747eb4ad..c67089a7ebc1 100644
--- a/drivers/gpu/drm/msm/adreno/a2xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a2xx_gpu.c
@@ -53,6 +53,8 @@ static void a2xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
static bool a2xx_me_init(struct msm_gpu *gpu)
{
+ struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+ struct a2xx_gpu *a2xx_gpu = to_a2xx_gpu(adreno_gpu);
struct msm_ringbuffer *ring = gpu->rb[0];
OUT_PKT3(ring, CP_ME_INIT, 18);
@@ -84,15 +86,20 @@ static bool a2xx_me_init(struct msm_gpu *gpu)
/* NQ and External Memory Swap */
OUT_RING(ring, 0x00000000);
/* protected mode error checking (0x1f2 is REG_AXXX_CP_INT_CNTL) */
- OUT_RING(ring, 0x200001f2);
+ if (a2xx_gpu->protection_disabled)
+ OUT_RING(ring, 0x00000000);
+ else
+ OUT_RING(ring, 0x200001f2);
/* Disable header dumping and Header dump address */
OUT_RING(ring, 0x00000000);
/* Header dump size */
OUT_RING(ring, 0x00000000);
- /* enable protected mode */
- OUT_PKT3(ring, CP_SET_PROTECTED_MODE, 1);
- OUT_RING(ring, 1);
+ if (!a2xx_gpu->protection_disabled) {
+ /* enable protected mode */
+ OUT_PKT3(ring, CP_SET_PROTECTED_MODE, 1);
+ OUT_RING(ring, 1);
+ }
adreno_flush(gpu, ring, REG_AXXX_CP_RB_WPTR);
return a2xx_idle(gpu);
@@ -101,6 +108,7 @@ static bool a2xx_me_init(struct msm_gpu *gpu)
static int a2xx_hw_init(struct msm_gpu *gpu)
{
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+ struct a2xx_gpu *a2xx_gpu = to_a2xx_gpu(adreno_gpu);
dma_addr_t pt_base, tran_error;
uint32_t *ptr, len;
int i, ret;
@@ -221,6 +229,17 @@ static int a2xx_hw_init(struct msm_gpu *gpu)
len = adreno_gpu->fw[ADRENO_FW_PM4]->size / 4;
DBG("loading PM4 ucode version: %x", ptr[1]);
+ /*
+ * New firmware files seem to have GPU and firmware version in this
+ * word (0x20xxxx for A200, 0x220xxx for A220, 0x225xxx for A225).
+ * Older firmware files, which lack protection support, have 0 instead.
+ */
+ if (ptr[1] == 0) {
+ dev_warn(gpu->dev->dev,
+ "Legacy firmware detected, disabling protection support\n");
+ a2xx_gpu->protection_disabled = true;
+ }
+
gpu_write(gpu, REG_AXXX_CP_DEBUG,
AXXX_CP_DEBUG_MIU_128BIT_WRITE_ENABLE);
gpu_write(gpu, REG_AXXX_CP_ME_RAM_WADDR, 0);
diff --git a/drivers/gpu/drm/msm/adreno/a2xx_gpu.h b/drivers/gpu/drm/msm/adreno/a2xx_gpu.h
index 02fba2cb8932..161a075f94af 100644
--- a/drivers/gpu/drm/msm/adreno/a2xx_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/a2xx_gpu.h
@@ -15,6 +15,7 @@
struct a2xx_gpu {
struct adreno_gpu base;
bool pm_enabled;
+ bool protection_disabled;
};
#define to_a2xx_gpu(x) container_of(x, struct a2xx_gpu, base)
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
index 660ba0db8900..d09221f97f71 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
@@ -5,7 +5,7 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/cpumask.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/pm_opp.h>
#include <linux/nvmem-consumer.h>
#include <linux/slab.h>
diff --git a/drivers/gpu/drm/msm/adreno/a6xx.xml.h b/drivers/gpu/drm/msm/adreno/a6xx.xml.h
index beea4a7fc1df..a92788019376 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx.xml.h
+++ b/drivers/gpu/drm/msm/adreno/a6xx.xml.h
@@ -241,6 +241,9 @@ enum a6xx_shader_id {
A6XX_HLSQ_FRONTEND_META = 97,
A6XX_HLSQ_INDIRECT_META = 98,
A6XX_HLSQ_BACKEND_META = 99,
+ A6XX_SP_LB_6_DATA = 112,
+ A6XX_SP_LB_7_DATA = 113,
+ A6XX_HLSQ_INST_RAM_1 = 115,
};
enum a6xx_debugbus_id {
@@ -274,19 +277,32 @@ enum a6xx_debugbus_id {
A6XX_DBGBUS_HLSQ_SPTP = 31,
A6XX_DBGBUS_RB_0 = 32,
A6XX_DBGBUS_RB_1 = 33,
+ A6XX_DBGBUS_RB_2 = 34,
A6XX_DBGBUS_UCHE_WRAPPER = 36,
A6XX_DBGBUS_CCU_0 = 40,
A6XX_DBGBUS_CCU_1 = 41,
+ A6XX_DBGBUS_CCU_2 = 42,
A6XX_DBGBUS_VFD_0 = 56,
A6XX_DBGBUS_VFD_1 = 57,
A6XX_DBGBUS_VFD_2 = 58,
A6XX_DBGBUS_VFD_3 = 59,
+ A6XX_DBGBUS_VFD_4 = 60,
+ A6XX_DBGBUS_VFD_5 = 61,
A6XX_DBGBUS_SP_0 = 64,
A6XX_DBGBUS_SP_1 = 65,
+ A6XX_DBGBUS_SP_2 = 66,
A6XX_DBGBUS_TPL1_0 = 72,
A6XX_DBGBUS_TPL1_1 = 73,
A6XX_DBGBUS_TPL1_2 = 74,
A6XX_DBGBUS_TPL1_3 = 75,
+ A6XX_DBGBUS_TPL1_4 = 76,
+ A6XX_DBGBUS_TPL1_5 = 77,
+ A6XX_DBGBUS_SPTP_0 = 88,
+ A6XX_DBGBUS_SPTP_1 = 89,
+ A6XX_DBGBUS_SPTP_2 = 90,
+ A6XX_DBGBUS_SPTP_3 = 91,
+ A6XX_DBGBUS_SPTP_4 = 92,
+ A6XX_DBGBUS_SPTP_5 = 93,
};
enum a6xx_cp_perfcounter_select {
@@ -1071,6 +1087,8 @@ enum a6xx_tex_type {
#define REG_A6XX_CP_MISC_CNTL 0x00000840
+#define REG_A6XX_CP_CHICKEN_DBG 0x00000841
+
#define REG_A6XX_CP_APRIV_CNTL 0x00000844
#define REG_A6XX_CP_ROQ_THRESHOLDS_1 0x000008c1
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
index 3be0f2928b57..aae60cbd9164 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
@@ -2028,7 +2028,7 @@ struct msm_gpu *a6xx_gpu_init(struct drm_device *dev)
* to cause power supply issues:
*/
if (adreno_is_a618(adreno_gpu) || adreno_is_7c3(adreno_gpu))
- gpu->clamp_to_idle = true;
+ priv->gpu_clamp_to_idle = true;
/* Check if there is a GMU phandle and set it up */
node = of_parse_phandle(pdev->dev.of_node, "qcom,gmu", 0);
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c
index a023d5f962dc..b7e217d00a22 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c
@@ -385,6 +385,9 @@ static void a6xx_get_debugbus(struct msm_gpu *gpu,
nr_debugbus_blocks = ARRAY_SIZE(a6xx_debugbus_blocks) +
(a6xx_has_gbif(to_adreno_gpu(gpu)) ? 1 : 0);
+ if (adreno_is_a650_family(to_adreno_gpu(gpu)))
+ nr_debugbus_blocks += ARRAY_SIZE(a650_debugbus_blocks);
+
a6xx_state->debugbus = state_kcalloc(a6xx_state, nr_debugbus_blocks,
sizeof(*a6xx_state->debugbus));
@@ -411,6 +414,15 @@ static void a6xx_get_debugbus(struct msm_gpu *gpu,
a6xx_state->nr_debugbus += 1;
}
+
+
+ if (adreno_is_a650_family(to_adreno_gpu(gpu))) {
+ for (i = 0; i < ARRAY_SIZE(a650_debugbus_blocks); i++)
+ a6xx_get_debugbus_block(gpu,
+ a6xx_state,
+ &a650_debugbus_blocks[i],
+ &a6xx_state->debugbus[i]);
+ }
}
/* Dump the VBIF debugbus on applicable targets */
@@ -524,10 +536,21 @@ static void a6xx_get_cluster(struct msm_gpu *gpu,
struct a6xx_gpu_state_obj *obj,
struct a6xx_crashdumper *dumper)
{
+ struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
u64 *in = dumper->ptr;
u64 out = dumper->iova + A6XX_CD_DATA_OFFSET;
size_t datasize;
int i, regcount = 0;
+ u32 id = cluster->id;
+
+ /* Skip registers that are not present on older generation */
+ if (!adreno_is_a660_family(adreno_gpu) &&
+ cluster->registers == a660_fe_cluster)
+ return;
+
+ if (adreno_is_a650_family(adreno_gpu) &&
+ cluster->registers == a6xx_ps_cluster)
+ id = CLUSTER_VPC_PS;
/* Some clusters need a selector register to be programmed too */
if (cluster->sel_reg)
@@ -537,7 +560,7 @@ static void a6xx_get_cluster(struct msm_gpu *gpu,
int j;
in += CRASHDUMP_WRITE(in, REG_A6XX_CP_APERTURE_CNTL_CD,
- (cluster->id << 8) | (i << 4) | i);
+ (id << 8) | (i << 4) | i);
for (j = 0; j < cluster->count; j += 2) {
int count = RANGE(cluster->registers, j);
@@ -687,6 +710,11 @@ static void a6xx_get_crashdumper_registers(struct msm_gpu *gpu,
u64 out = dumper->iova + A6XX_CD_DATA_OFFSET;
int i, regcount = 0;
+ /* Skip unsupported registers on older generations */
+ if (!adreno_is_a660_family(to_adreno_gpu(gpu)) &&
+ (regs->registers == a660_registers))
+ return;
+
/* Some blocks might need to program a selector register first */
if (regs->val0)
in += CRASHDUMP_WRITE(in, regs->val0, regs->val1);
@@ -721,6 +749,11 @@ static void a6xx_get_ahb_gpu_registers(struct msm_gpu *gpu,
{
int i, regcount = 0, index = 0;
+ /* Skip unsupported registers on older generations */
+ if (!adreno_is_a660_family(to_adreno_gpu(gpu)) &&
+ (regs->registers == a660_registers))
+ return;
+
for (i = 0; i < regs->count; i += 2)
regcount += RANGE(regs->registers, i);
@@ -909,15 +942,24 @@ static void a6xx_get_registers(struct msm_gpu *gpu,
dumper);
}
+static u32 a6xx_get_cp_roq_size(struct msm_gpu *gpu)
+{
+ /* The value at [16:31] is in 4dword units. Convert it to dwords */
+ return gpu_read(gpu, REG_A6XX_CP_ROQ_THRESHOLDS_2) >> 14;
+}
+
/* Read a block of data from an indexed register pair */
static void a6xx_get_indexed_regs(struct msm_gpu *gpu,
struct a6xx_gpu_state *a6xx_state,
- const struct a6xx_indexed_registers *indexed,
+ struct a6xx_indexed_registers *indexed,
struct a6xx_gpu_state_obj *obj)
{
int i;
obj->handle = (const void *) indexed;
+ if (indexed->count_fn)
+ indexed->count = indexed->count_fn(gpu);
+
obj->data = state_kcalloc(a6xx_state, indexed->count, sizeof(u32));
if (!obj->data)
return;
@@ -946,6 +988,21 @@ static void a6xx_get_indexed_registers(struct msm_gpu *gpu,
a6xx_get_indexed_regs(gpu, a6xx_state, &a6xx_indexed_reglist[i],
&a6xx_state->indexed_regs[i]);
+ if (adreno_is_a650_family(to_adreno_gpu(gpu))) {
+ u32 val;
+
+ val = gpu_read(gpu, REG_A6XX_CP_CHICKEN_DBG);
+ gpu_write(gpu, REG_A6XX_CP_CHICKEN_DBG, val | 4);
+
+ /* Get the contents of the CP mempool */
+ a6xx_get_indexed_regs(gpu, a6xx_state, &a6xx_cp_mempool_indexed,
+ &a6xx_state->indexed_regs[i]);
+
+ gpu_write(gpu, REG_A6XX_CP_CHICKEN_DBG, val);
+ a6xx_state->nr_indexed_regs = count;
+ return;
+ }
+
/* Set the CP mempool size to 0 to stabilize it while dumping */
mempool_size = gpu_read(gpu, REG_A6XX_CP_MEM_POOL_SIZE);
gpu_write(gpu, REG_A6XX_CP_MEM_POOL_SIZE, 0);
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.h b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.h
index 2fb58b7098e4..790f55e24533 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.h
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.h
@@ -36,16 +36,21 @@ static const u32 a6xx_fe_cluster[] = {
0xa00e, 0xa0ef, 0xa0f8, 0xa0f8,
};
+static const u32 a660_fe_cluster[] = {
+ 0x9807, 0x9807,
+};
+
static const u32 a6xx_pc_vs_cluster[] = {
0x9100, 0x9108, 0x9300, 0x9306, 0x9980, 0x9981, 0x9b00, 0x9b07,
};
-#define CLUSTER_FE 0
-#define CLUSTER_SP_VS 1
-#define CLUSTER_PC_VS 2
-#define CLUSTER_GRAS 3
-#define CLUSTER_SP_PS 4
-#define CLUSTER_PS 5
+#define CLUSTER_FE 0
+#define CLUSTER_SP_VS 1
+#define CLUSTER_PC_VS 2
+#define CLUSTER_GRAS 3
+#define CLUSTER_SP_PS 4
+#define CLUSTER_PS 5
+#define CLUSTER_VPC_PS 6
#define CLUSTER(_id, _reg, _sel_reg, _sel_val) \
{ .id = _id, .name = #_id,\
@@ -67,6 +72,7 @@ static const struct a6xx_cluster {
CLUSTER(CLUSTER_PS, a6xx_ps_cluster, 0, 0),
CLUSTER(CLUSTER_FE, a6xx_fe_cluster, 0, 0),
CLUSTER(CLUSTER_PC_VS, a6xx_pc_vs_cluster, 0, 0),
+ CLUSTER(CLUSTER_FE, a660_fe_cluster, 0, 0),
};
static const u32 a6xx_sp_vs_hlsq_cluster[] = {
@@ -105,7 +111,7 @@ static const u32 a6xx_sp_ps_hlsq_2d_cluster[] = {
static const u32 a6xx_sp_ps_sp_cluster[] = {
0xa980, 0xa9a8, 0xa9b0, 0xa9bc, 0xa9d0, 0xa9d3, 0xa9e0, 0xa9f3,
- 0xaa00, 0xaa00, 0xaa30, 0xaa31,
+ 0xaa00, 0xaa00, 0xaa30, 0xaa31, 0xaaf2, 0xaaf2,
};
static const u32 a6xx_sp_ps_sp_2d_cluster[] = {
@@ -229,6 +235,9 @@ static const struct a6xx_shader_block {
SHADER(A6XX_HLSQ_DATAPATH_META, 0x40),
SHADER(A6XX_HLSQ_FRONTEND_META, 0x40),
SHADER(A6XX_HLSQ_INDIRECT_META, 0x40),
+ SHADER(A6XX_SP_LB_6_DATA, 0x200),
+ SHADER(A6XX_SP_LB_7_DATA, 0x200),
+ SHADER(A6XX_HLSQ_INST_RAM_1, 0x200),
};
static const u32 a6xx_rb_rac_registers[] = {
@@ -251,7 +260,7 @@ static const u32 a6xx_registers[] = {
0x0540, 0x0555,
/* CP */
0x0800, 0x0808, 0x0810, 0x0813, 0x0820, 0x0821, 0x0823, 0x0824,
- 0x0826, 0x0827, 0x0830, 0x0833, 0x0840, 0x0843, 0x084f, 0x086f,
+ 0x0826, 0x0827, 0x0830, 0x0833, 0x0840, 0x0845, 0x084f, 0x086f,
0x0880, 0x088a, 0x08a0, 0x08ab, 0x08c0, 0x08c4, 0x08d0, 0x08dd,
0x08f0, 0x08f3, 0x0900, 0x0903, 0x0908, 0x0911, 0x0928, 0x093e,
0x0942, 0x094d, 0x0980, 0x0984, 0x098d, 0x0996, 0x0998, 0x099e,
@@ -274,6 +283,13 @@ static const u32 a6xx_registers[] = {
/* VFD */
0xa600, 0xa601, 0xa603, 0xa603, 0xa60a, 0xa60a, 0xa610, 0xa617,
0xa630, 0xa630,
+ /* HLSQ */
+ 0xd002, 0xd003,
+};
+
+static const u32 a660_registers[] = {
+ /* UCHE */
+ 0x0e3c, 0x0e3c,
};
#define REGS(_array, _sel_reg, _sel_val) \
@@ -282,6 +298,7 @@ static const u32 a6xx_registers[] = {
static const struct a6xx_registers a6xx_reglist[] = {
REGS(a6xx_registers, 0, 0),
+ REGS(a660_registers, 0, 0),
REGS(a6xx_rb_rac_registers, REG_A6XX_RB_RB_SUB_BLOCK_SEL_CNTL_CD, 0),
REGS(a6xx_rb_rbp_registers, REG_A6XX_RB_RB_SUB_BLOCK_SEL_CNTL_CD, 9),
};
@@ -366,25 +383,28 @@ static const struct a6xx_registers a6xx_gmu_reglist[] = {
REGS(a6xx_gmu_gx_registers, 0, 0),
};
-static const struct a6xx_indexed_registers {
+static u32 a6xx_get_cp_roq_size(struct msm_gpu *gpu);
+
+static struct a6xx_indexed_registers {
const char *name;
u32 addr;
u32 data;
u32 count;
+ u32 (*count_fn)(struct msm_gpu *gpu);
} a6xx_indexed_reglist[] = {
{ "CP_SQE_STAT", REG_A6XX_CP_SQE_STAT_ADDR,
- REG_A6XX_CP_SQE_STAT_DATA, 0x33 },
+ REG_A6XX_CP_SQE_STAT_DATA, 0x33, NULL },
{ "CP_DRAW_STATE", REG_A6XX_CP_DRAW_STATE_ADDR,
- REG_A6XX_CP_DRAW_STATE_DATA, 0x100 },
+ REG_A6XX_CP_DRAW_STATE_DATA, 0x100, NULL },
{ "CP_UCODE_DBG_DATA", REG_A6XX_CP_SQE_UCODE_DBG_ADDR,
- REG_A6XX_CP_SQE_UCODE_DBG_DATA, 0x6000 },
+ REG_A6XX_CP_SQE_UCODE_DBG_DATA, 0x8000, NULL },
{ "CP_ROQ", REG_A6XX_CP_ROQ_DBG_ADDR,
- REG_A6XX_CP_ROQ_DBG_DATA, 0x400 },
+ REG_A6XX_CP_ROQ_DBG_DATA, 0, a6xx_get_cp_roq_size},
};
-static const struct a6xx_indexed_registers a6xx_cp_mempool_indexed = {
+static struct a6xx_indexed_registers a6xx_cp_mempool_indexed = {
"CP_MEMPOOL", REG_A6XX_CP_MEM_POOL_DBG_ADDR,
- REG_A6XX_CP_MEM_POOL_DBG_DATA, 0x2060,
+ REG_A6XX_CP_MEM_POOL_DBG_DATA, 0x2060, NULL,
};
#define DEBUGBUS(_id, _count) { .id = _id, .name = #_id, .count = _count }
@@ -443,4 +463,20 @@ static const struct a6xx_debugbus_block a6xx_cx_debugbus_blocks[] = {
DEBUGBUS(A6XX_DBGBUS_CX, 0x100),
};
+static const struct a6xx_debugbus_block a650_debugbus_blocks[] = {
+ DEBUGBUS(A6XX_DBGBUS_RB_2, 0x100),
+ DEBUGBUS(A6XX_DBGBUS_CCU_2, 0x100),
+ DEBUGBUS(A6XX_DBGBUS_VFD_4, 0x100),
+ DEBUGBUS(A6XX_DBGBUS_VFD_5, 0x100),
+ DEBUGBUS(A6XX_DBGBUS_SP_2, 0x100),
+ DEBUGBUS(A6XX_DBGBUS_TPL1_4, 0x100),
+ DEBUGBUS(A6XX_DBGBUS_TPL1_5, 0x100),
+ DEBUGBUS(A6XX_DBGBUS_SPTP_0, 0x100),
+ DEBUGBUS(A6XX_DBGBUS_SPTP_1, 0x100),
+ DEBUGBUS(A6XX_DBGBUS_SPTP_2, 0x100),
+ DEBUGBUS(A6XX_DBGBUS_SPTP_3, 0x100),
+ DEBUGBUS(A6XX_DBGBUS_SPTP_4, 0x100),
+ DEBUGBUS(A6XX_DBGBUS_SPTP_5, 0x100),
+};
+
#endif
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
index 3605f095b2de..ce6b76c45b6f 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
@@ -8,7 +8,7 @@
#include <linux/ascii85.h>
#include <linux/interconnect.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/kernel.h>
#include <linux/of_address.h>
#include <linux/pm_opp.h>
@@ -1083,13 +1083,13 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
void adreno_gpu_cleanup(struct adreno_gpu *adreno_gpu)
{
struct msm_gpu *gpu = &adreno_gpu->base;
- struct msm_drm_private *priv = gpu->dev->dev_private;
+ struct msm_drm_private *priv = gpu->dev ? gpu->dev->dev_private : NULL;
unsigned int i;
for (i = 0; i < ARRAY_SIZE(adreno_gpu->info->fw); i++)
release_firmware(adreno_gpu->fw[i]);
- if (pm_runtime_enabled(&priv->gpu_pdev->dev))
+ if (priv && pm_runtime_enabled(&priv->gpu_pdev->dev))
pm_runtime_disable(&priv->gpu_pdev->dev);
msm_gpu_cleanup(&adreno_gpu->base);
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
index 13ce321283ff..f29a339a3705 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -748,7 +748,7 @@ static void _dpu_crtc_setup_cp_blocks(struct drm_crtc *crtc)
int i;
- if (!state->color_mgmt_changed)
+ if (!state->color_mgmt_changed && !drm_atomic_crtc_needs_modeset(state))
return;
for (i = 0; i < cstate->num_mixers; i++) {
@@ -968,7 +968,10 @@ static void dpu_crtc_reset(struct drm_crtc *crtc)
if (crtc->state)
dpu_crtc_destroy_state(crtc, crtc->state);
- __drm_atomic_helper_crtc_reset(crtc, &cstate->base);
+ if (cstate)
+ __drm_atomic_helper_crtc_reset(crtc, &cstate->base);
+ else
+ __drm_atomic_helper_crtc_reset(crtc, NULL);
}
/**
@@ -1150,6 +1153,8 @@ static int dpu_crtc_atomic_check(struct drm_crtc *crtc,
bool needs_dirtyfb = dpu_crtc_needs_dirtyfb(crtc_state);
pstates = kzalloc(sizeof(*pstates) * DPU_STAGE_MAX * 4, GFP_KERNEL);
+ if (!pstates)
+ return -ENOMEM;
if (!crtc_state->enable || !crtc_state->active) {
DRM_DEBUG_ATOMIC("crtc%d -> enable %d, active %d, skip atomic_check\n",
@@ -1517,16 +1522,12 @@ DEFINE_SHOW_ATTRIBUTE(dpu_crtc_debugfs_state);
static int _dpu_crtc_init_debugfs(struct drm_crtc *crtc)
{
struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
- struct dentry *debugfs_root;
-
- debugfs_root = debugfs_create_dir(dpu_crtc->name,
- crtc->dev->primary->debugfs_root);
debugfs_create_file("status", 0400,
- debugfs_root,
+ crtc->debugfs_entry,
dpu_crtc, &_dpu_debugfs_status_fops);
debugfs_create_file("state", 0600,
- debugfs_root,
+ crtc->debugfs_entry,
&dpu_crtc->base,
&dpu_crtc_debugfs_state_fops);
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 9c6817b5a194..758261e8ac73 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -162,6 +162,7 @@ enum dpu_enc_rc_states {
* @vsync_event_work: worker to handle vsync event for autorefresh
* @topology: topology of the display
* @idle_timeout: idle timeout duration in milliseconds
+ * @wide_bus_en: wide bus is enabled on this interface
* @dsc: drm_dsc_config pointer, for DSC-enabled encoders
*/
struct dpu_encoder_virt {
@@ -340,9 +341,7 @@ void dpu_encoder_helper_report_irq_timeout(struct dpu_encoder_phys *phys_enc,
phys_enc->intf_idx - INTF_0, phys_enc->wb_idx - WB_0,
phys_enc->hw_pp->idx - PINGPONG_0, intr_idx);
- if (phys_enc->parent_ops->handle_frame_done)
- phys_enc->parent_ops->handle_frame_done(
- phys_enc->parent, phys_enc,
+ dpu_encoder_frame_done_callback(phys_enc->parent, phys_enc,
DPU_ENCODER_FRAME_EVENT_ERROR);
}
@@ -579,19 +578,18 @@ static struct msm_display_topology dpu_encoder_get_topology(
topology.num_dspp = topology.num_lm;
}
- topology.num_enc = 0;
topology.num_intf = intf_count;
if (dpu_enc->dsc) {
- /* In case of Display Stream Compression (DSC), we would use
- * 2 encoders, 2 layer mixers and 1 interface
+ /*
+ * In case of Display Stream Compression (DSC), we would use
+ * 2 DSC encoders, 2 layer mixers and 1 interface
* this is power optimal and can drive up to (including) 4k
* screens
*/
- topology.num_enc = 2;
topology.num_dsc = 2;
- topology.num_intf = 1;
topology.num_lm = 2;
+ topology.num_intf = 1;
}
return topology;
@@ -1284,7 +1282,7 @@ static enum dpu_wb dpu_encoder_get_wb(const struct dpu_mdss_cfg *catalog,
return WB_MAX;
}
-static void dpu_encoder_vblank_callback(struct drm_encoder *drm_enc,
+void dpu_encoder_vblank_callback(struct drm_encoder *drm_enc,
struct dpu_encoder_phys *phy_enc)
{
struct dpu_encoder_virt *dpu_enc = NULL;
@@ -1306,7 +1304,7 @@ static void dpu_encoder_vblank_callback(struct drm_encoder *drm_enc,
DPU_ATRACE_END("encoder_vblank_callback");
}
-static void dpu_encoder_underrun_callback(struct drm_encoder *drm_enc,
+void dpu_encoder_underrun_callback(struct drm_encoder *drm_enc,
struct dpu_encoder_phys *phy_enc)
{
if (!phy_enc)
@@ -1382,7 +1380,7 @@ void dpu_encoder_register_frame_event_callback(struct drm_encoder *drm_enc,
spin_unlock_irqrestore(&dpu_enc->enc_spinlock, lock_flags);
}
-static void dpu_encoder_frame_done_callback(
+void dpu_encoder_frame_done_callback(
struct drm_encoder *drm_enc,
struct dpu_encoder_phys *ready_phys, u32 event)
{
@@ -1830,6 +1828,9 @@ static void dpu_encoder_dsc_pipe_cfg(struct dpu_hw_dsc *hw_dsc,
if (hw_pp->ops.setup_dsc)
hw_pp->ops.setup_dsc(hw_pp);
+ if (hw_dsc->ops.dsc_bind_pingpong_blk)
+ hw_dsc->ops.dsc_bind_pingpong_blk(hw_dsc, true, hw_pp->idx);
+
if (hw_pp->ops.enable_dsc)
hw_pp->ops.enable_dsc(hw_pp);
}
@@ -2233,12 +2234,6 @@ static int dpu_encoder_virt_add_phys_encs(
return 0;
}
-static const struct dpu_encoder_virt_ops dpu_encoder_parent_ops = {
- .handle_vblank_virt = dpu_encoder_vblank_callback,
- .handle_underrun_virt = dpu_encoder_underrun_callback,
- .handle_frame_done = dpu_encoder_frame_done_callback,
-};
-
static int dpu_encoder_setup_display(struct dpu_encoder_virt *dpu_enc,
struct dpu_kms *dpu_kms,
struct msm_display_info *disp_info)
@@ -2258,7 +2253,6 @@ static int dpu_encoder_setup_display(struct dpu_encoder_virt *dpu_enc,
memset(&phys_params, 0, sizeof(phys_params));
phys_params.dpu_kms = dpu_kms;
phys_params.parent = &dpu_enc->base;
- phys_params.parent_ops = &dpu_encoder_parent_ops;
phys_params.enc_spinlock = &dpu_enc->enc_spinlock;
switch (disp_info->intf_type) {
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
index f2af07d87f56..1d434b22180d 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
@@ -61,25 +61,6 @@ enum dpu_enc_enable_state {
struct dpu_encoder_phys;
/**
- * struct dpu_encoder_virt_ops - Interface the containing virtual encoder
- * provides for the physical encoders to use to callback.
- * @handle_vblank_virt: Notify virtual encoder of vblank IRQ reception
- * Note: This is called from IRQ handler context.
- * @handle_underrun_virt: Notify virtual encoder of underrun IRQ reception
- * Note: This is called from IRQ handler context.
- * @handle_frame_done: Notify virtual encoder that this phys encoder
- * completes last request frame.
- */
-struct dpu_encoder_virt_ops {
- void (*handle_vblank_virt)(struct drm_encoder *,
- struct dpu_encoder_phys *phys);
- void (*handle_underrun_virt)(struct drm_encoder *,
- struct dpu_encoder_phys *phys);
- void (*handle_frame_done)(struct drm_encoder *,
- struct dpu_encoder_phys *phys, u32 event);
-};
-
-/**
* struct dpu_encoder_phys_ops - Interface the physical encoders provide to
* the containing virtual encoder.
* @late_register: DRM Call. Add Userspace interfaces, debugfs.
@@ -199,7 +180,6 @@ enum dpu_intr_idx {
struct dpu_encoder_phys {
struct drm_encoder *parent;
struct dpu_encoder_phys_ops ops;
- const struct dpu_encoder_virt_ops *parent_ops;
struct dpu_hw_mdp *hw_mdptop;
struct dpu_hw_ctl *hw_ctl;
struct dpu_hw_pingpong *hw_pp;
@@ -283,7 +263,6 @@ struct dpu_encoder_phys_cmd {
struct dpu_enc_phys_init_params {
struct dpu_kms *dpu_kms;
struct drm_encoder *parent;
- const struct dpu_encoder_virt_ops *parent_ops;
enum dpu_enc_split_role split_role;
enum dpu_intf intf_idx;
enum dpu_wb wb_idx;
@@ -400,4 +379,30 @@ int dpu_encoder_helper_wait_for_irq(struct dpu_encoder_phys *phys_enc,
*/
void dpu_encoder_helper_phys_cleanup(struct dpu_encoder_phys *phys_enc);
+/**
+ * dpu_encoder_vblank_callback - Notify virtual encoder of vblank IRQ reception
+ * @drm_enc: Pointer to drm encoder structure
+ * @phys_enc: Pointer to physical encoder
+ * Note: This is called from IRQ handler context.
+ */
+void dpu_encoder_vblank_callback(struct drm_encoder *drm_enc,
+ struct dpu_encoder_phys *phy_enc);
+
+/** dpu_encoder_underrun_callback - Notify virtual encoder of underrun IRQ reception
+ * @drm_enc: Pointer to drm encoder structure
+ * @phys_enc: Pointer to physical encoder
+ * Note: This is called from IRQ handler context.
+ */
+void dpu_encoder_underrun_callback(struct drm_encoder *drm_enc,
+ struct dpu_encoder_phys *phy_enc);
+
+/** dpu_encoder_frame_done_callback -- Notify virtual encoder that this phys encoder completes last request frame
+ * @drm_enc: Pointer to drm encoder structure
+ * @phys_enc: Pointer to physical encoder
+ * @event: Event to process
+ */
+void dpu_encoder_frame_done_callback(
+ struct drm_encoder *drm_enc,
+ struct dpu_encoder_phys *ready_phys, u32 event);
+
#endif /* __dpu_encoder_phys_H__ */
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c
index ae28b2b93e69..c8f4a62a9536 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c
@@ -61,6 +61,7 @@ static void _dpu_encoder_phys_cmd_update_intf_cfg(
intf_cfg.intf_mode_sel = DPU_CTL_MODE_SEL_CMD;
intf_cfg.stream_sel = cmd_enc->stream_sel;
intf_cfg.mode_3d = dpu_encoder_helper_get_3d_blend_mode(phys_enc);
+ intf_cfg.dsc = dpu_encoder_helper_get_dsc(phys_enc);
ctl->ops.setup_intf_cfg(ctl, &intf_cfg);
/* setup which pp blk will connect to this intf */
@@ -83,9 +84,7 @@ static void dpu_encoder_phys_cmd_pp_tx_done_irq(void *arg, int irq_idx)
DPU_ATRACE_BEGIN("pp_done_irq");
/* notify all synchronous clients first, then asynchronous clients */
- if (phys_enc->parent_ops->handle_frame_done)
- phys_enc->parent_ops->handle_frame_done(phys_enc->parent,
- phys_enc, event);
+ dpu_encoder_frame_done_callback(phys_enc->parent, phys_enc, event);
spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
new_cnt = atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0);
@@ -111,9 +110,7 @@ static void dpu_encoder_phys_cmd_pp_rd_ptr_irq(void *arg, int irq_idx)
DPU_ATRACE_BEGIN("rd_ptr_irq");
cmd_enc = to_dpu_encoder_phys_cmd(phys_enc);
- if (phys_enc->parent_ops->handle_vblank_virt)
- phys_enc->parent_ops->handle_vblank_virt(phys_enc->parent,
- phys_enc);
+ dpu_encoder_vblank_callback(phys_enc->parent, phys_enc);
atomic_add_unless(&cmd_enc->pending_vblank_cnt, -1, 0);
wake_up_all(&cmd_enc->pending_vblank_wq);
@@ -137,9 +134,7 @@ static void dpu_encoder_phys_cmd_underrun_irq(void *arg, int irq_idx)
{
struct dpu_encoder_phys *phys_enc = arg;
- if (phys_enc->parent_ops->handle_underrun_virt)
- phys_enc->parent_ops->handle_underrun_virt(phys_enc->parent,
- phys_enc);
+ dpu_encoder_underrun_callback(phys_enc->parent, phys_enc);
}
static void dpu_encoder_phys_cmd_atomic_mode_set(
@@ -202,9 +197,7 @@ static int _dpu_encoder_phys_cmd_handle_ppdone_timeout(
/* request a ctl reset before the next kickoff */
phys_enc->enable_state = DPU_ENC_ERR_NEEDS_HW_RESET;
- if (phys_enc->parent_ops->handle_frame_done)
- phys_enc->parent_ops->handle_frame_done(
- drm_enc, phys_enc, frame_event);
+ dpu_encoder_frame_done_callback(phys_enc->parent, phys_enc, frame_event);
return -ETIMEDOUT;
}
@@ -780,7 +773,6 @@ struct dpu_encoder_phys *dpu_encoder_phys_cmd_init(
dpu_encoder_phys_cmd_init_ops(&phys_enc->ops);
phys_enc->parent = p->parent;
- phys_enc->parent_ops = p->parent_ops;
phys_enc->dpu_kms = p->dpu_kms;
phys_enc->split_role = p->split_role;
phys_enc->intf_mode = INTF_MODE_CMD;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
index 0f71e8fe7be7..48c48106b16a 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
@@ -274,6 +274,7 @@ static void dpu_encoder_phys_vid_setup_timing_engine(
intf_cfg.intf_mode_sel = DPU_CTL_MODE_SEL_VID;
intf_cfg.stream_sel = 0; /* Don't care value for video mode */
intf_cfg.mode_3d = dpu_encoder_helper_get_3d_blend_mode(phys_enc);
+ intf_cfg.dsc = dpu_encoder_helper_get_dsc(phys_enc);
if (phys_enc->hw_pp->merge_3d)
intf_cfg.merge_3d = phys_enc->hw_pp->merge_3d->idx;
@@ -308,9 +309,7 @@ static void dpu_encoder_phys_vid_vblank_irq(void *arg, int irq_idx)
DPU_ATRACE_BEGIN("vblank_irq");
- if (phys_enc->parent_ops->handle_vblank_virt)
- phys_enc->parent_ops->handle_vblank_virt(phys_enc->parent,
- phys_enc);
+ dpu_encoder_vblank_callback(phys_enc->parent, phys_enc);
atomic_read(&phys_enc->pending_kickoff_cnt);
@@ -330,7 +329,7 @@ static void dpu_encoder_phys_vid_vblank_irq(void *arg, int irq_idx)
/* Signal any waiting atomic commit thread */
wake_up_all(&phys_enc->pending_kickoff_wq);
- phys_enc->parent_ops->handle_frame_done(phys_enc->parent, phys_enc,
+ dpu_encoder_frame_done_callback(phys_enc->parent, phys_enc,
DPU_ENCODER_FRAME_EVENT_DONE);
DPU_ATRACE_END("vblank_irq");
@@ -340,9 +339,7 @@ static void dpu_encoder_phys_vid_underrun_irq(void *arg, int irq_idx)
{
struct dpu_encoder_phys *phys_enc = arg;
- if (phys_enc->parent_ops->handle_underrun_virt)
- phys_enc->parent_ops->handle_underrun_virt(phys_enc->parent,
- phys_enc);
+ dpu_encoder_underrun_callback(phys_enc->parent, phys_enc);
}
static bool dpu_encoder_phys_vid_needs_single_flush(
@@ -700,7 +697,6 @@ struct dpu_encoder_phys *dpu_encoder_phys_vid_init(
dpu_encoder_phys_vid_init_ops(&phys_enc->ops);
phys_enc->parent = p->parent;
- phys_enc->parent_ops = p->parent_ops;
phys_enc->dpu_kms = p->dpu_kms;
phys_enc->split_role = p->split_role;
phys_enc->intf_mode = INTF_MODE_VIDEO;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
index 62f6ff6abf41..bac4aa807b4b 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
@@ -26,6 +26,7 @@
/**
* dpu_encoder_phys_wb_is_master - report wb always as master encoder
+ * @phys_enc: Pointer to physical encoder
*/
static bool dpu_encoder_phys_wb_is_master(struct dpu_encoder_phys *phys_enc)
{
@@ -364,13 +365,9 @@ static void _dpu_encoder_phys_wb_frame_done_helper(void *arg)
DPU_DEBUG("[wb:%d]\n", hw_wb->idx - WB_0);
- if (phys_enc->parent_ops->handle_frame_done)
- phys_enc->parent_ops->handle_frame_done(phys_enc->parent,
- phys_enc, event);
+ dpu_encoder_frame_done_callback(phys_enc->parent, phys_enc, event);
- if (phys_enc->parent_ops->handle_vblank_virt)
- phys_enc->parent_ops->handle_vblank_virt(phys_enc->parent,
- phys_enc);
+ dpu_encoder_vblank_callback(phys_enc->parent, phys_enc);
spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0);
@@ -440,9 +437,7 @@ static void _dpu_encoder_phys_wb_handle_wbdone_timeout(
if (wb_enc->wb_conn)
drm_writeback_signal_completion(wb_enc->wb_conn, 0);
- if (phys_enc->parent_ops->handle_frame_done)
- phys_enc->parent_ops->handle_frame_done(
- phys_enc->parent, phys_enc, frame_event);
+ dpu_encoder_frame_done_callback(phys_enc->parent, phys_enc, frame_event);
}
/**
@@ -722,7 +717,6 @@ struct dpu_encoder_phys *dpu_encoder_phys_wb_init(
dpu_encoder_phys_wb_init_ops(&phys_enc->ops);
phys_enc->parent = p->parent;
- phys_enc->parent_ops = p->parent_ops;
phys_enc->dpu_kms = p->dpu_kms;
phys_enc->split_role = p->split_role;
phys_enc->intf_mode = INTF_MODE_WB_LINE;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
index 2196e205efa5..cf053e8f081e 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
@@ -56,7 +56,7 @@
#define MIXER_SDM845_MASK \
(BIT(DPU_MIXER_SOURCESPLIT) | BIT(DPU_DIM_LAYER) | BIT(DPU_MIXER_COMBINED_ALPHA))
-#define MIXER_SC7180_MASK \
+#define MIXER_QCM2290_MASK \
(BIT(DPU_DIM_LAYER) | BIT(DPU_MIXER_COMBINED_ALPHA))
#define PINGPONG_SDM845_MASK BIT(DPU_PINGPONG_DITHER)
@@ -67,6 +67,9 @@
#define CTL_SC7280_MASK \
(BIT(DPU_CTL_ACTIVE_CFG) | BIT(DPU_CTL_FETCH_ACTIVE) | BIT(DPU_CTL_VM_CFG))
+#define CTL_SM8550_MASK \
+ (CTL_SC7280_MASK | BIT(DPU_CTL_HAS_LAYER_EXT4))
+
#define MERGE_3D_SM8150_MASK (0)
#define DSPP_MSM8998_MASK BIT(DPU_DSPP_PCC) | BIT(DPU_DSPP_GC)
@@ -86,7 +89,6 @@
BIT(MDP_INTF1_INTR) | \
BIT(MDP_INTF2_INTR) | \
BIT(MDP_INTF3_INTR) | \
- BIT(MDP_INTF4_INTR) | \
BIT(MDP_AD4_0_INTR) | \
BIT(MDP_AD4_1_INTR))
@@ -112,6 +114,14 @@
BIT(MDP_INTF3_INTR) | \
BIT(MDP_INTF4_INTR))
+#define IRQ_SM8350_MASK (BIT(MDP_SSPP_TOP0_INTR) | \
+ BIT(MDP_SSPP_TOP0_INTR2) | \
+ BIT(MDP_SSPP_TOP0_HIST_INTR) | \
+ BIT(MDP_INTF0_7xxx_INTR) | \
+ BIT(MDP_INTF1_7xxx_INTR) | \
+ BIT(MDP_INTF2_7xxx_INTR) | \
+ BIT(MDP_INTF3_7xxx_INTR))
+
#define IRQ_SC8180X_MASK (BIT(MDP_SSPP_TOP0_INTR) | \
BIT(MDP_SSPP_TOP0_INTR2) | \
BIT(MDP_SSPP_TOP0_HIST_INTR) | \
@@ -124,6 +134,27 @@
BIT(MDP_AD4_0_INTR) | \
BIT(MDP_AD4_1_INTR))
+#define IRQ_SC8280XP_MASK (BIT(MDP_SSPP_TOP0_INTR) | \
+ BIT(MDP_SSPP_TOP0_INTR2) | \
+ BIT(MDP_SSPP_TOP0_HIST_INTR) | \
+ BIT(MDP_INTF0_7xxx_INTR) | \
+ BIT(MDP_INTF1_7xxx_INTR) | \
+ BIT(MDP_INTF2_7xxx_INTR) | \
+ BIT(MDP_INTF3_7xxx_INTR) | \
+ BIT(MDP_INTF4_7xxx_INTR) | \
+ BIT(MDP_INTF5_7xxx_INTR) | \
+ BIT(MDP_INTF6_7xxx_INTR) | \
+ BIT(MDP_INTF7_7xxx_INTR) | \
+ BIT(MDP_INTF8_7xxx_INTR))
+
+#define IRQ_SM8450_MASK (BIT(MDP_SSPP_TOP0_INTR) | \
+ BIT(MDP_SSPP_TOP0_INTR2) | \
+ BIT(MDP_SSPP_TOP0_HIST_INTR) | \
+ BIT(MDP_INTF0_7xxx_INTR) | \
+ BIT(MDP_INTF1_7xxx_INTR) | \
+ BIT(MDP_INTF2_7xxx_INTR) | \
+ BIT(MDP_INTF3_7xxx_INTR))
+
#define WB_SM8250_MASK (BIT(DPU_WB_LINE_MODE) | \
BIT(DPU_WB_UBWC) | \
BIT(DPU_WB_YUV_CONFIG) | \
@@ -326,7 +357,7 @@ static const struct dpu_caps sm6115_dpu_caps = {
.max_mixer_blendstages = 0x4,
.qseed_type = DPU_SSPP_SCALER_QSEED3LITE,
.smart_dma_rev = DPU_SSPP_SMART_DMA_V2, /* TODO: v2.5 */
- .ubwc_version = DPU_HW_UBWC_VER_20,
+ .ubwc_version = DPU_HW_UBWC_VER_10,
.has_dim_layer = true,
.has_idle_pc = true,
.max_linewidth = 2160,
@@ -365,6 +396,20 @@ static const struct dpu_caps sc8180x_dpu_caps = {
.max_vdeci_exp = MAX_VERT_DECIMATION,
};
+static const struct dpu_caps sc8280xp_dpu_caps = {
+ .max_mixer_width = 2560,
+ .max_mixer_blendstages = 11,
+ .qseed_type = DPU_SSPP_SCALER_QSEED3LITE,
+ .smart_dma_rev = DPU_SSPP_SMART_DMA_V2, /* TODO: v2.5 */
+ .ubwc_version = DPU_HW_UBWC_VER_40,
+ .has_src_split = true,
+ .has_dim_layer = true,
+ .has_idle_pc = true,
+ .has_3d_merge = true,
+ .max_linewidth = 5120,
+ .pixel_ram_size = DEFAULT_PIXEL_RAM_SIZE,
+};
+
static const struct dpu_caps sm8250_dpu_caps = {
.max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH,
.max_mixer_blendstages = 0xb,
@@ -379,6 +424,48 @@ static const struct dpu_caps sm8250_dpu_caps = {
.pixel_ram_size = DEFAULT_PIXEL_RAM_SIZE,
};
+static const struct dpu_caps sm8350_dpu_caps = {
+ .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH,
+ .max_mixer_blendstages = 0xb,
+ .qseed_type = DPU_SSPP_SCALER_QSEED3LITE,
+ .smart_dma_rev = DPU_SSPP_SMART_DMA_V2, /* TODO: v2.5 */
+ .ubwc_version = DPU_HW_UBWC_VER_40,
+ .has_src_split = true,
+ .has_dim_layer = true,
+ .has_idle_pc = true,
+ .has_3d_merge = true,
+ .max_linewidth = 4096,
+ .pixel_ram_size = DEFAULT_PIXEL_RAM_SIZE,
+};
+
+static const struct dpu_caps sm8450_dpu_caps = {
+ .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH,
+ .max_mixer_blendstages = 0xb,
+ .qseed_type = DPU_SSPP_SCALER_QSEED4,
+ .smart_dma_rev = DPU_SSPP_SMART_DMA_V2, /* TODO: v2.5 */
+ .ubwc_version = DPU_HW_UBWC_VER_40,
+ .has_src_split = true,
+ .has_dim_layer = true,
+ .has_idle_pc = true,
+ .has_3d_merge = true,
+ .max_linewidth = 5120,
+ .pixel_ram_size = DEFAULT_PIXEL_RAM_SIZE,
+};
+
+static const struct dpu_caps sm8550_dpu_caps = {
+ .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH,
+ .max_mixer_blendstages = 0xb,
+ .qseed_type = DPU_SSPP_SCALER_QSEED3LITE,
+ .smart_dma_rev = DPU_SSPP_SMART_DMA_V2, /* TODO: v2.5 */
+ .ubwc_version = DPU_HW_UBWC_VER_40,
+ .has_src_split = true,
+ .has_dim_layer = true,
+ .has_idle_pc = true,
+ .has_3d_merge = true,
+ .max_linewidth = 5120,
+ .pixel_ram_size = DEFAULT_PIXEL_RAM_SIZE,
+};
+
static const struct dpu_caps sc7280_dpu_caps = {
.max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH,
.max_mixer_blendstages = 0x7,
@@ -459,6 +546,8 @@ static const struct dpu_mdp_cfg sc7180_mdp[] = {
.reg_off = 0x2B4, .bit_off = 8},
.clk_ctrls[DPU_CLK_CTRL_CURSOR1] = {
.reg_off = 0x2C4, .bit_off = 8},
+ .clk_ctrls[DPU_CLK_CTRL_WB2] = {
+ .reg_off = 0x3B8, .bit_off = 24},
},
};
@@ -466,7 +555,7 @@ static const struct dpu_mdp_cfg sc8180x_mdp[] = {
{
.name = "top_0", .id = MDP_TOP,
.base = 0x0, .len = 0x45C,
- .features = 0,
+ .features = BIT(DPU_MDP_AUDIO_SELECT),
.highest_bank_bit = 0x3,
.clk_ctrls[DPU_CLK_CTRL_VIG0] = {
.reg_off = 0x2AC, .bit_off = 0},
@@ -493,6 +582,7 @@ static const struct dpu_mdp_cfg sm6115_mdp[] = {
.base = 0x0, .len = 0x494,
.features = 0,
.highest_bank_bit = 0x1,
+ .ubwc_swizzle = 0x7,
.clk_ctrls[DPU_CLK_CTRL_VIG0] = {
.reg_off = 0x2ac, .bit_off = 0},
.clk_ctrls[DPU_CLK_CTRL_DMA0] = {
@@ -506,6 +596,7 @@ static const struct dpu_mdp_cfg sm8250_mdp[] = {
.base = 0x0, .len = 0x494,
.features = 0,
.highest_bank_bit = 0x3, /* TODO: 2 for LP_DDR4 */
+ .ubwc_swizzle = 0x6,
.clk_ctrls[DPU_CLK_CTRL_VIG0] = {
.reg_off = 0x2AC, .bit_off = 0},
.clk_ctrls[DPU_CLK_CTRL_VIG1] = {
@@ -529,11 +620,67 @@ static const struct dpu_mdp_cfg sm8250_mdp[] = {
},
};
+static const struct dpu_mdp_cfg sm8350_mdp[] = {
+ {
+ .name = "top_0", .id = MDP_TOP,
+ .base = 0x0, .len = 0x494,
+ .features = 0,
+ .highest_bank_bit = 0x3, /* TODO: 2 for LP_DDR4 */
+ .clk_ctrls[DPU_CLK_CTRL_VIG0] = {
+ .reg_off = 0x2ac, .bit_off = 0},
+ .clk_ctrls[DPU_CLK_CTRL_VIG1] = {
+ .reg_off = 0x2b4, .bit_off = 0},
+ .clk_ctrls[DPU_CLK_CTRL_VIG2] = {
+ .reg_off = 0x2bc, .bit_off = 0},
+ .clk_ctrls[DPU_CLK_CTRL_VIG3] = {
+ .reg_off = 0x2c4, .bit_off = 0},
+ .clk_ctrls[DPU_CLK_CTRL_DMA0] = {
+ .reg_off = 0x2ac, .bit_off = 8},
+ .clk_ctrls[DPU_CLK_CTRL_DMA1] = {
+ .reg_off = 0x2b4, .bit_off = 8},
+ .clk_ctrls[DPU_CLK_CTRL_CURSOR0] = {
+ .reg_off = 0x2bc, .bit_off = 8},
+ .clk_ctrls[DPU_CLK_CTRL_CURSOR1] = {
+ .reg_off = 0x2c4, .bit_off = 8},
+ .clk_ctrls[DPU_CLK_CTRL_REG_DMA] = {
+ .reg_off = 0x2bc, .bit_off = 20},
+ },
+};
+
+static const struct dpu_mdp_cfg sm8450_mdp[] = {
+ {
+ .name = "top_0", .id = MDP_TOP,
+ .base = 0x0, .len = 0x494,
+ .features = BIT(DPU_MDP_PERIPH_0_REMOVED),
+ .highest_bank_bit = 0x3, /* TODO: 2 for LP_DDR4 */
+ .ubwc_swizzle = 0x6,
+ .clk_ctrls[DPU_CLK_CTRL_VIG0] = {
+ .reg_off = 0x2AC, .bit_off = 0},
+ .clk_ctrls[DPU_CLK_CTRL_VIG1] = {
+ .reg_off = 0x2B4, .bit_off = 0},
+ .clk_ctrls[DPU_CLK_CTRL_VIG2] = {
+ .reg_off = 0x2BC, .bit_off = 0},
+ .clk_ctrls[DPU_CLK_CTRL_VIG3] = {
+ .reg_off = 0x2C4, .bit_off = 0},
+ .clk_ctrls[DPU_CLK_CTRL_DMA0] = {
+ .reg_off = 0x2AC, .bit_off = 8},
+ .clk_ctrls[DPU_CLK_CTRL_DMA1] = {
+ .reg_off = 0x2B4, .bit_off = 8},
+ .clk_ctrls[DPU_CLK_CTRL_CURSOR0] = {
+ .reg_off = 0x2BC, .bit_off = 8},
+ .clk_ctrls[DPU_CLK_CTRL_CURSOR1] = {
+ .reg_off = 0x2C4, .bit_off = 8},
+ .clk_ctrls[DPU_CLK_CTRL_REG_DMA] = {
+ .reg_off = 0x2BC, .bit_off = 20},
+ },
+};
+
static const struct dpu_mdp_cfg sc7280_mdp[] = {
{
.name = "top_0", .id = MDP_TOP,
.base = 0x0, .len = 0x2014,
.highest_bank_bit = 0x1,
+ .ubwc_swizzle = 0x6,
.clk_ctrls[DPU_CLK_CTRL_VIG0] = {
.reg_off = 0x2AC, .bit_off = 0},
.clk_ctrls[DPU_CLK_CTRL_DMA0] = {
@@ -545,6 +692,57 @@ static const struct dpu_mdp_cfg sc7280_mdp[] = {
},
};
+static const struct dpu_mdp_cfg sc8280xp_mdp[] = {
+ {
+ .name = "top_0", .id = MDP_TOP,
+ .base = 0x0, .len = 0x494,
+ .features = 0,
+ .highest_bank_bit = 2,
+ .ubwc_swizzle = 6,
+ .clk_ctrls[DPU_CLK_CTRL_VIG0] = { .reg_off = 0x2ac, .bit_off = 0},
+ .clk_ctrls[DPU_CLK_CTRL_VIG1] = { .reg_off = 0x2b4, .bit_off = 0},
+ .clk_ctrls[DPU_CLK_CTRL_VIG2] = { .reg_off = 0x2bc, .bit_off = 0},
+ .clk_ctrls[DPU_CLK_CTRL_VIG3] = { .reg_off = 0x2c4, .bit_off = 0},
+ .clk_ctrls[DPU_CLK_CTRL_DMA0] = { .reg_off = 0x2ac, .bit_off = 8},
+ .clk_ctrls[DPU_CLK_CTRL_DMA1] = { .reg_off = 0x2b4, .bit_off = 8},
+ .clk_ctrls[DPU_CLK_CTRL_CURSOR0] = { .reg_off = 0x2bc, .bit_off = 8},
+ .clk_ctrls[DPU_CLK_CTRL_CURSOR1] = { .reg_off = 0x2c4, .bit_off = 8},
+ .clk_ctrls[DPU_CLK_CTRL_REG_DMA] = { .reg_off = 0x2bc, .bit_off = 20},
+ },
+};
+
+static const struct dpu_mdp_cfg sm8550_mdp[] = {
+ {
+ .name = "top_0", .id = MDP_TOP,
+ .base = 0, .len = 0x494,
+ .features = BIT(DPU_MDP_PERIPH_0_REMOVED),
+ .highest_bank_bit = 0x3, /* TODO: 2 for LP_DDR4 */
+ .ubwc_swizzle = 0x6,
+ .clk_ctrls[DPU_CLK_CTRL_VIG0] = {
+ .reg_off = 0x4330, .bit_off = 0},
+ .clk_ctrls[DPU_CLK_CTRL_VIG1] = {
+ .reg_off = 0x6330, .bit_off = 0},
+ .clk_ctrls[DPU_CLK_CTRL_VIG2] = {
+ .reg_off = 0x8330, .bit_off = 0},
+ .clk_ctrls[DPU_CLK_CTRL_VIG3] = {
+ .reg_off = 0xa330, .bit_off = 0},
+ .clk_ctrls[DPU_CLK_CTRL_DMA0] = {
+ .reg_off = 0x24330, .bit_off = 0},
+ .clk_ctrls[DPU_CLK_CTRL_DMA1] = {
+ .reg_off = 0x26330, .bit_off = 0},
+ .clk_ctrls[DPU_CLK_CTRL_DMA2] = {
+ .reg_off = 0x28330, .bit_off = 0},
+ .clk_ctrls[DPU_CLK_CTRL_DMA3] = {
+ .reg_off = 0x2a330, .bit_off = 0},
+ .clk_ctrls[DPU_CLK_CTRL_CURSOR0] = {
+ .reg_off = 0x2c330, .bit_off = 0},
+ .clk_ctrls[DPU_CLK_CTRL_CURSOR1] = {
+ .reg_off = 0x2e330, .bit_off = 0},
+ .clk_ctrls[DPU_CLK_CTRL_REG_DMA] = {
+ .reg_off = 0x2bc, .bit_off = 20},
+ },
+};
+
static const struct dpu_mdp_cfg qcm2290_mdp[] = {
{
.name = "top_0", .id = MDP_TOP,
@@ -648,6 +846,45 @@ static const struct dpu_ctl_cfg sc7180_ctl[] = {
},
};
+static const struct dpu_ctl_cfg sc8280xp_ctl[] = {
+ {
+ .name = "ctl_0", .id = CTL_0,
+ .base = 0x15000, .len = 0x204,
+ .features = CTL_SC7280_MASK,
+ .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 9),
+ },
+ {
+ .name = "ctl_1", .id = CTL_1,
+ .base = 0x16000, .len = 0x204,
+ .features = CTL_SC7280_MASK,
+ .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 10),
+ },
+ {
+ .name = "ctl_2", .id = CTL_2,
+ .base = 0x17000, .len = 0x204,
+ .features = CTL_SC7280_MASK,
+ .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 11),
+ },
+ {
+ .name = "ctl_3", .id = CTL_3,
+ .base = 0x18000, .len = 0x204,
+ .features = CTL_SC7280_MASK,
+ .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 12),
+ },
+ {
+ .name = "ctl_4", .id = CTL_4,
+ .base = 0x19000, .len = 0x204,
+ .features = CTL_SC7280_MASK,
+ .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 13),
+ },
+ {
+ .name = "ctl_5", .id = CTL_5,
+ .base = 0x1a000, .len = 0x204,
+ .features = CTL_SC7280_MASK,
+ .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 23),
+ },
+};
+
static const struct dpu_ctl_cfg sm8150_ctl[] = {
{
.name = "ctl_0", .id = CTL_0,
@@ -687,6 +924,123 @@ static const struct dpu_ctl_cfg sm8150_ctl[] = {
},
};
+static const struct dpu_ctl_cfg sm8350_ctl[] = {
+ {
+ .name = "ctl_0", .id = CTL_0,
+ .base = 0x15000, .len = 0x1e8,
+ .features = BIT(DPU_CTL_SPLIT_DISPLAY) | CTL_SC7280_MASK,
+ .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 9),
+ },
+ {
+ .name = "ctl_1", .id = CTL_1,
+ .base = 0x16000, .len = 0x1e8,
+ .features = BIT(DPU_CTL_SPLIT_DISPLAY) | CTL_SC7280_MASK,
+ .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 10),
+ },
+ {
+ .name = "ctl_2", .id = CTL_2,
+ .base = 0x17000, .len = 0x1e8,
+ .features = CTL_SC7280_MASK,
+ .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 11),
+ },
+ {
+ .name = "ctl_3", .id = CTL_3,
+ .base = 0x18000, .len = 0x1e8,
+ .features = CTL_SC7280_MASK,
+ .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 12),
+ },
+ {
+ .name = "ctl_4", .id = CTL_4,
+ .base = 0x19000, .len = 0x1e8,
+ .features = CTL_SC7280_MASK,
+ .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 13),
+ },
+ {
+ .name = "ctl_5", .id = CTL_5,
+ .base = 0x1a000, .len = 0x1e8,
+ .features = CTL_SC7280_MASK,
+ .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 23),
+ },
+};
+
+static const struct dpu_ctl_cfg sm8450_ctl[] = {
+ {
+ .name = "ctl_0", .id = CTL_0,
+ .base = 0x15000, .len = 0x204,
+ .features = BIT(DPU_CTL_ACTIVE_CFG) | BIT(DPU_CTL_SPLIT_DISPLAY) | BIT(DPU_CTL_FETCH_ACTIVE),
+ .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 9),
+ },
+ {
+ .name = "ctl_1", .id = CTL_1,
+ .base = 0x16000, .len = 0x204,
+ .features = BIT(DPU_CTL_SPLIT_DISPLAY) | CTL_SC7280_MASK,
+ .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 10),
+ },
+ {
+ .name = "ctl_2", .id = CTL_2,
+ .base = 0x17000, .len = 0x204,
+ .features = CTL_SC7280_MASK,
+ .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 11),
+ },
+ {
+ .name = "ctl_3", .id = CTL_3,
+ .base = 0x18000, .len = 0x204,
+ .features = CTL_SC7280_MASK,
+ .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 12),
+ },
+ {
+ .name = "ctl_4", .id = CTL_4,
+ .base = 0x19000, .len = 0x204,
+ .features = CTL_SC7280_MASK,
+ .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 13),
+ },
+ {
+ .name = "ctl_5", .id = CTL_5,
+ .base = 0x1a000, .len = 0x204,
+ .features = CTL_SC7280_MASK,
+ .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 23),
+ },
+};
+
+static const struct dpu_ctl_cfg sm8550_ctl[] = {
+ {
+ .name = "ctl_0", .id = CTL_0,
+ .base = 0x15000, .len = 0x290,
+ .features = CTL_SM8550_MASK | BIT(DPU_CTL_SPLIT_DISPLAY),
+ .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 9),
+ },
+ {
+ .name = "ctl_1", .id = CTL_1,
+ .base = 0x16000, .len = 0x290,
+ .features = CTL_SM8550_MASK | BIT(DPU_CTL_SPLIT_DISPLAY),
+ .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 10),
+ },
+ {
+ .name = "ctl_2", .id = CTL_2,
+ .base = 0x17000, .len = 0x290,
+ .features = CTL_SM8550_MASK,
+ .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 11),
+ },
+ {
+ .name = "ctl_3", .id = CTL_3,
+ .base = 0x18000, .len = 0x290,
+ .features = CTL_SM8550_MASK,
+ .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 12),
+ },
+ {
+ .name = "ctl_4", .id = CTL_4,
+ .base = 0x19000, .len = 0x290,
+ .features = CTL_SM8550_MASK,
+ .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 13),
+ },
+ {
+ .name = "ctl_5", .id = CTL_5,
+ .base = 0x1a000, .len = 0x290,
+ .features = CTL_SM8550_MASK,
+ .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 23),
+ },
+};
+
static const struct dpu_ctl_cfg sc7280_ctl[] = {
{
.name = "ctl_0", .id = CTL_0,
@@ -915,6 +1269,68 @@ static const struct dpu_sspp_cfg sm8250_sspp[] = {
sdm845_dma_sblk_3, 13, SSPP_TYPE_DMA, DPU_CLK_CTRL_CURSOR1),
};
+static const struct dpu_sspp_sub_blks sm8450_vig_sblk_0 =
+ _VIG_SBLK("0", 5, DPU_SSPP_SCALER_QSEED3LITE);
+static const struct dpu_sspp_sub_blks sm8450_vig_sblk_1 =
+ _VIG_SBLK("1", 6, DPU_SSPP_SCALER_QSEED3LITE);
+static const struct dpu_sspp_sub_blks sm8450_vig_sblk_2 =
+ _VIG_SBLK("2", 7, DPU_SSPP_SCALER_QSEED3LITE);
+static const struct dpu_sspp_sub_blks sm8450_vig_sblk_3 =
+ _VIG_SBLK("3", 8, DPU_SSPP_SCALER_QSEED3LITE);
+
+static const struct dpu_sspp_cfg sm8450_sspp[] = {
+ SSPP_BLK("sspp_0", SSPP_VIG0, 0x4000, VIG_SC7180_MASK,
+ sm8450_vig_sblk_0, 0, SSPP_TYPE_VIG, DPU_CLK_CTRL_VIG0),
+ SSPP_BLK("sspp_1", SSPP_VIG1, 0x6000, VIG_SC7180_MASK,
+ sm8450_vig_sblk_1, 4, SSPP_TYPE_VIG, DPU_CLK_CTRL_VIG1),
+ SSPP_BLK("sspp_2", SSPP_VIG2, 0x8000, VIG_SC7180_MASK,
+ sm8450_vig_sblk_2, 8, SSPP_TYPE_VIG, DPU_CLK_CTRL_VIG2),
+ SSPP_BLK("sspp_3", SSPP_VIG3, 0xa000, VIG_SC7180_MASK,
+ sm8450_vig_sblk_3, 12, SSPP_TYPE_VIG, DPU_CLK_CTRL_VIG3),
+ SSPP_BLK("sspp_8", SSPP_DMA0, 0x24000, DMA_SDM845_MASK,
+ sdm845_dma_sblk_0, 1, SSPP_TYPE_DMA, DPU_CLK_CTRL_DMA0),
+ SSPP_BLK("sspp_9", SSPP_DMA1, 0x26000, DMA_SDM845_MASK,
+ sdm845_dma_sblk_1, 5, SSPP_TYPE_DMA, DPU_CLK_CTRL_DMA1),
+ SSPP_BLK("sspp_10", SSPP_DMA2, 0x28000, DMA_CURSOR_SDM845_MASK,
+ sdm845_dma_sblk_2, 9, SSPP_TYPE_DMA, DPU_CLK_CTRL_CURSOR0),
+ SSPP_BLK("sspp_11", SSPP_DMA3, 0x2a000, DMA_CURSOR_SDM845_MASK,
+ sdm845_dma_sblk_3, 13, SSPP_TYPE_DMA, DPU_CLK_CTRL_CURSOR1),
+};
+
+static const struct dpu_sspp_sub_blks sm8550_vig_sblk_0 =
+ _VIG_SBLK("0", 7, DPU_SSPP_SCALER_QSEED3LITE);
+static const struct dpu_sspp_sub_blks sm8550_vig_sblk_1 =
+ _VIG_SBLK("1", 8, DPU_SSPP_SCALER_QSEED3LITE);
+static const struct dpu_sspp_sub_blks sm8550_vig_sblk_2 =
+ _VIG_SBLK("2", 9, DPU_SSPP_SCALER_QSEED3LITE);
+static const struct dpu_sspp_sub_blks sm8550_vig_sblk_3 =
+ _VIG_SBLK("3", 10, DPU_SSPP_SCALER_QSEED3LITE);
+static const struct dpu_sspp_sub_blks sm8550_dma_sblk_4 = _DMA_SBLK("12", 5);
+static const struct dpu_sspp_sub_blks sd8550_dma_sblk_5 = _DMA_SBLK("13", 6);
+
+static const struct dpu_sspp_cfg sm8550_sspp[] = {
+ SSPP_BLK("sspp_0", SSPP_VIG0, 0x4000, VIG_SC7180_MASK,
+ sm8550_vig_sblk_0, 0, SSPP_TYPE_VIG, DPU_CLK_CTRL_VIG0),
+ SSPP_BLK("sspp_1", SSPP_VIG1, 0x6000, VIG_SC7180_MASK,
+ sm8550_vig_sblk_1, 4, SSPP_TYPE_VIG, DPU_CLK_CTRL_VIG1),
+ SSPP_BLK("sspp_2", SSPP_VIG2, 0x8000, VIG_SC7180_MASK,
+ sm8550_vig_sblk_2, 8, SSPP_TYPE_VIG, DPU_CLK_CTRL_VIG2),
+ SSPP_BLK("sspp_3", SSPP_VIG3, 0xa000, VIG_SC7180_MASK,
+ sm8550_vig_sblk_3, 12, SSPP_TYPE_VIG, DPU_CLK_CTRL_VIG3),
+ SSPP_BLK("sspp_8", SSPP_DMA0, 0x24000, DMA_SDM845_MASK,
+ sdm845_dma_sblk_0, 1, SSPP_TYPE_DMA, DPU_CLK_CTRL_DMA0),
+ SSPP_BLK("sspp_9", SSPP_DMA1, 0x26000, DMA_SDM845_MASK,
+ sdm845_dma_sblk_1, 5, SSPP_TYPE_DMA, DPU_CLK_CTRL_DMA1),
+ SSPP_BLK("sspp_10", SSPP_DMA2, 0x28000, DMA_SDM845_MASK,
+ sdm845_dma_sblk_2, 9, SSPP_TYPE_DMA, DPU_CLK_CTRL_DMA2),
+ SSPP_BLK("sspp_11", SSPP_DMA3, 0x2a000, DMA_SDM845_MASK,
+ sdm845_dma_sblk_3, 13, SSPP_TYPE_DMA, DPU_CLK_CTRL_DMA3),
+ SSPP_BLK("sspp_12", SSPP_DMA4, 0x2c000, DMA_CURSOR_SDM845_MASK,
+ sm8550_dma_sblk_4, 14, SSPP_TYPE_DMA, DPU_CLK_CTRL_CURSOR0),
+ SSPP_BLK("sspp_13", SSPP_DMA5, 0x2e000, DMA_CURSOR_SDM845_MASK,
+ sd8550_dma_sblk_5, 15, SSPP_TYPE_DMA, DPU_CLK_CTRL_CURSOR1),
+};
+
static const struct dpu_sspp_cfg sc7280_sspp[] = {
SSPP_BLK("sspp_0", SSPP_VIG0, 0x4000, VIG_SC7280_MASK,
sc7280_vig_sblk_0, 0, SSPP_TYPE_VIG, DPU_CLK_CTRL_VIG0),
@@ -926,6 +1342,33 @@ static const struct dpu_sspp_cfg sc7280_sspp[] = {
sdm845_dma_sblk_2, 9, SSPP_TYPE_DMA, DPU_CLK_CTRL_CURSOR1),
};
+static const struct dpu_sspp_sub_blks sc8280xp_vig_sblk_0 =
+ _VIG_SBLK("0", 5, DPU_SSPP_SCALER_QSEED3LITE);
+static const struct dpu_sspp_sub_blks sc8280xp_vig_sblk_1 =
+ _VIG_SBLK("1", 6, DPU_SSPP_SCALER_QSEED3LITE);
+static const struct dpu_sspp_sub_blks sc8280xp_vig_sblk_2 =
+ _VIG_SBLK("2", 7, DPU_SSPP_SCALER_QSEED3LITE);
+static const struct dpu_sspp_sub_blks sc8280xp_vig_sblk_3 =
+ _VIG_SBLK("3", 8, DPU_SSPP_SCALER_QSEED3LITE);
+
+static const struct dpu_sspp_cfg sc8280xp_sspp[] = {
+ SSPP_BLK("sspp_0", SSPP_VIG0, 0x4000, VIG_SM8250_MASK,
+ sc8280xp_vig_sblk_0, 0, SSPP_TYPE_VIG, DPU_CLK_CTRL_VIG0),
+ SSPP_BLK("sspp_1", SSPP_VIG1, 0x6000, VIG_SM8250_MASK,
+ sc8280xp_vig_sblk_1, 4, SSPP_TYPE_VIG, DPU_CLK_CTRL_VIG1),
+ SSPP_BLK("sspp_2", SSPP_VIG2, 0x8000, VIG_SM8250_MASK,
+ sc8280xp_vig_sblk_2, 8, SSPP_TYPE_VIG, DPU_CLK_CTRL_VIG2),
+ SSPP_BLK("sspp_3", SSPP_VIG3, 0xa000, VIG_SM8250_MASK,
+ sc8280xp_vig_sblk_3, 12, SSPP_TYPE_VIG, DPU_CLK_CTRL_VIG3),
+ SSPP_BLK("sspp_8", SSPP_DMA0, 0x24000, DMA_SDM845_MASK,
+ sdm845_dma_sblk_0, 1, SSPP_TYPE_DMA, DPU_CLK_CTRL_DMA0),
+ SSPP_BLK("sspp_9", SSPP_DMA1, 0x26000, DMA_SDM845_MASK,
+ sdm845_dma_sblk_1, 5, SSPP_TYPE_DMA, DPU_CLK_CTRL_DMA1),
+ SSPP_BLK("sspp_10", SSPP_DMA2, 0x28000, DMA_CURSOR_SDM845_MASK,
+ sdm845_dma_sblk_2, 9, SSPP_TYPE_DMA, DPU_CLK_CTRL_CURSOR0),
+ SSPP_BLK("sspp_11", SSPP_DMA3, 0x2a000, DMA_CURSOR_SDM845_MASK,
+ sdm845_dma_sblk_3, 13, SSPP_TYPE_DMA, DPU_CLK_CTRL_CURSOR1),
+};
#define _VIG_SBLK_NOSCALE(num, sdma_pri) \
{ \
@@ -1028,12 +1471,23 @@ static const struct dpu_lm_sub_blks sc7180_lm_sblk = {
};
static const struct dpu_lm_cfg sc7180_lm[] = {
- LM_BLK("lm_0", LM_0, 0x44000, MIXER_SC7180_MASK,
+ LM_BLK("lm_0", LM_0, 0x44000, MIXER_SDM845_MASK,
&sc7180_lm_sblk, PINGPONG_0, LM_1, DSPP_0),
- LM_BLK("lm_1", LM_1, 0x45000, MIXER_SC7180_MASK,
+ LM_BLK("lm_1", LM_1, 0x45000, MIXER_SDM845_MASK,
&sc7180_lm_sblk, PINGPONG_1, LM_0, 0),
};
+/* SC8280XP */
+
+static const struct dpu_lm_cfg sc8280xp_lm[] = {
+ LM_BLK("lm_0", LM_0, 0x44000, MIXER_SDM845_MASK, &sdm845_lm_sblk, PINGPONG_0, LM_1, DSPP_0),
+ LM_BLK("lm_1", LM_1, 0x45000, MIXER_SDM845_MASK, &sdm845_lm_sblk, PINGPONG_1, LM_0, DSPP_1),
+ LM_BLK("lm_2", LM_2, 0x46000, MIXER_SDM845_MASK, &sdm845_lm_sblk, PINGPONG_2, LM_3, DSPP_2),
+ LM_BLK("lm_3", LM_3, 0x47000, MIXER_SDM845_MASK, &sdm845_lm_sblk, PINGPONG_3, LM_2, DSPP_3),
+ LM_BLK("lm_4", LM_4, 0x48000, MIXER_SDM845_MASK, &sdm845_lm_sblk, PINGPONG_4, LM_5, 0),
+ LM_BLK("lm_5", LM_5, 0x49000, MIXER_SDM845_MASK, &sdm845_lm_sblk, PINGPONG_5, LM_4, 0),
+};
+
/* SM8150 */
static const struct dpu_lm_cfg sm8150_lm[] = {
@@ -1052,11 +1506,11 @@ static const struct dpu_lm_cfg sm8150_lm[] = {
};
static const struct dpu_lm_cfg sc7280_lm[] = {
- LM_BLK("lm_0", LM_0, 0x44000, MIXER_SC7180_MASK,
+ LM_BLK("lm_0", LM_0, 0x44000, MIXER_SDM845_MASK,
&sc7180_lm_sblk, PINGPONG_0, 0, DSPP_0),
- LM_BLK("lm_2", LM_2, 0x46000, MIXER_SC7180_MASK,
+ LM_BLK("lm_2", LM_2, 0x46000, MIXER_SDM845_MASK,
&sc7180_lm_sblk, PINGPONG_2, LM_3, 0),
- LM_BLK("lm_3", LM_3, 0x47000, MIXER_SC7180_MASK,
+ LM_BLK("lm_3", LM_3, 0x47000, MIXER_SDM845_MASK,
&sc7180_lm_sblk, PINGPONG_3, LM_2, 0),
};
@@ -1071,7 +1525,7 @@ static const struct dpu_lm_sub_blks qcm2290_lm_sblk = {
};
static const struct dpu_lm_cfg qcm2290_lm[] = {
- LM_BLK("lm_0", LM_0, 0x44000, MIXER_SC7180_MASK,
+ LM_BLK("lm_0", LM_0, 0x44000, MIXER_QCM2290_MASK,
&qcm2290_lm_sblk, PINGPONG_0, 0, DSPP_0),
};
@@ -1151,6 +1605,16 @@ static const struct dpu_pingpong_sub_blks sc7280_pp_sblk = {
.len = 0x20, .version = 0x20000},
};
+#define PP_BLK_DIPHER(_name, _id, _base, _merge_3d, _sblk, _done, _rdptr) \
+ {\
+ .name = _name, .id = _id, \
+ .base = _base, .len = 0, \
+ .features = BIT(DPU_PINGPONG_DITHER), \
+ .merge_3d = _merge_3d, \
+ .sblk = &_sblk, \
+ .intr_done = _done, \
+ .intr_rdptr = _rdptr, \
+ }
#define PP_BLK_TE(_name, _id, _base, _merge_3d, _sblk, _done, _rdptr) \
{\
.name = _name, .id = _id, \
@@ -1192,6 +1656,21 @@ static struct dpu_pingpong_cfg sc7180_pp[] = {
PP_BLK_TE("pingpong_1", PINGPONG_1, 0x70800, 0, sdm845_pp_sblk_te, -1, -1),
};
+static struct dpu_pingpong_cfg sc8280xp_pp[] = {
+ PP_BLK_TE("pingpong_0", PINGPONG_0, 0x69000, MERGE_3D_0, sdm845_pp_sblk_te,
+ DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 8), -1),
+ PP_BLK_TE("pingpong_1", PINGPONG_1, 0x6a000, MERGE_3D_0, sdm845_pp_sblk_te,
+ DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 9), -1),
+ PP_BLK_TE("pingpong_2", PINGPONG_2, 0x6b000, MERGE_3D_1, sdm845_pp_sblk_te,
+ DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 10), -1),
+ PP_BLK_TE("pingpong_3", PINGPONG_3, 0x6c000, MERGE_3D_1, sdm845_pp_sblk_te,
+ DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 11), -1),
+ PP_BLK_TE("pingpong_4", PINGPONG_4, 0x6d000, MERGE_3D_2, sdm845_pp_sblk_te,
+ DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 30), -1),
+ PP_BLK_TE("pingpong_5", PINGPONG_5, 0x6e000, MERGE_3D_2, sdm845_pp_sblk_te,
+ DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 31), -1),
+};
+
static const struct dpu_pingpong_cfg sm8150_pp[] = {
PP_BLK_TE("pingpong_0", PINGPONG_0, 0x70000, MERGE_3D_0, sdm845_pp_sblk_te,
DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 8),
@@ -1213,6 +1692,27 @@ static const struct dpu_pingpong_cfg sm8150_pp[] = {
-1),
};
+static const struct dpu_pingpong_cfg sm8350_pp[] = {
+ PP_BLK_TE("pingpong_0", PINGPONG_0, 0x69000, MERGE_3D_0, sdm845_pp_sblk_te,
+ DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 8),
+ DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 12)),
+ PP_BLK_TE("pingpong_1", PINGPONG_1, 0x6a000, MERGE_3D_0, sdm845_pp_sblk_te,
+ DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 9),
+ DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 13)),
+ PP_BLK("pingpong_2", PINGPONG_2, 0x6b000, MERGE_3D_1, sdm845_pp_sblk,
+ DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 10),
+ DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 14)),
+ PP_BLK("pingpong_3", PINGPONG_3, 0x6c000, MERGE_3D_1, sdm845_pp_sblk,
+ DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 11),
+ DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 15)),
+ PP_BLK("pingpong_4", PINGPONG_4, 0x6d000, MERGE_3D_2, sdm845_pp_sblk,
+ DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 30),
+ -1),
+ PP_BLK("pingpong_5", PINGPONG_5, 0x6e000, MERGE_3D_2, sdm845_pp_sblk,
+ DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 31),
+ -1),
+};
+
static const struct dpu_pingpong_cfg sc7280_pp[] = {
PP_BLK("pingpong_0", PINGPONG_0, 0x59000, 0, sc7280_pp_sblk, -1, -1),
PP_BLK("pingpong_1", PINGPONG_1, 0x6a000, 0, sc7280_pp_sblk, -1, -1),
@@ -1226,6 +1726,61 @@ static struct dpu_pingpong_cfg qcm2290_pp[] = {
DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 12)),
};
+/* FIXME: interrupts */
+static const struct dpu_pingpong_cfg sm8450_pp[] = {
+ PP_BLK_TE("pingpong_0", PINGPONG_0, 0x69000, MERGE_3D_0, sdm845_pp_sblk_te,
+ DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 8),
+ DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 12)),
+ PP_BLK_TE("pingpong_1", PINGPONG_1, 0x6a000, MERGE_3D_0, sdm845_pp_sblk_te,
+ DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 9),
+ DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 13)),
+ PP_BLK("pingpong_2", PINGPONG_2, 0x6b000, MERGE_3D_1, sdm845_pp_sblk,
+ DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 10),
+ DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 14)),
+ PP_BLK("pingpong_3", PINGPONG_3, 0x6c000, MERGE_3D_1, sdm845_pp_sblk,
+ DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 11),
+ DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 15)),
+ PP_BLK("pingpong_4", PINGPONG_4, 0x6d000, MERGE_3D_2, sdm845_pp_sblk,
+ DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 30),
+ -1),
+ PP_BLK("pingpong_5", PINGPONG_5, 0x6e000, MERGE_3D_2, sdm845_pp_sblk,
+ DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 31),
+ -1),
+ PP_BLK("pingpong_6", PINGPONG_6, 0x65800, MERGE_3D_3, sdm845_pp_sblk,
+ -1,
+ -1),
+ PP_BLK("pingpong_7", PINGPONG_7, 0x65c00, MERGE_3D_3, sdm845_pp_sblk,
+ -1,
+ -1),
+};
+
+static const struct dpu_pingpong_cfg sm8550_pp[] = {
+ PP_BLK_DIPHER("pingpong_0", PINGPONG_0, 0x69000, MERGE_3D_0, sc7280_pp_sblk,
+ DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 8),
+ -1),
+ PP_BLK_DIPHER("pingpong_1", PINGPONG_1, 0x6a000, MERGE_3D_0, sc7280_pp_sblk,
+ DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 9),
+ -1),
+ PP_BLK_DIPHER("pingpong_2", PINGPONG_2, 0x6b000, MERGE_3D_1, sc7280_pp_sblk,
+ DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 10),
+ -1),
+ PP_BLK_DIPHER("pingpong_3", PINGPONG_3, 0x6c000, MERGE_3D_1, sc7280_pp_sblk,
+ DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 11),
+ -1),
+ PP_BLK_DIPHER("pingpong_4", PINGPONG_4, 0x6d000, MERGE_3D_2, sc7280_pp_sblk,
+ DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 30),
+ -1),
+ PP_BLK_DIPHER("pingpong_5", PINGPONG_5, 0x6e000, MERGE_3D_2, sc7280_pp_sblk,
+ DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 31),
+ -1),
+ PP_BLK_DIPHER("pingpong_6", PINGPONG_6, 0x66000, MERGE_3D_3, sc7280_pp_sblk,
+ -1,
+ -1),
+ PP_BLK_DIPHER("pingpong_7", PINGPONG_7, 0x66400, MERGE_3D_3, sc7280_pp_sblk,
+ -1,
+ -1),
+};
+
/*************************************************************
* MERGE_3D sub blocks config
*************************************************************/
@@ -1243,21 +1798,48 @@ static const struct dpu_merge_3d_cfg sm8150_merge_3d[] = {
MERGE_3D_BLK("merge_3d_2", MERGE_3D_2, 0x83200),
};
+static const struct dpu_merge_3d_cfg sm8350_merge_3d[] = {
+ MERGE_3D_BLK("merge_3d_0", MERGE_3D_0, 0x4e000),
+ MERGE_3D_BLK("merge_3d_1", MERGE_3D_1, 0x4f000),
+ MERGE_3D_BLK("merge_3d_2", MERGE_3D_2, 0x50000),
+};
+
+static const struct dpu_merge_3d_cfg sm8450_merge_3d[] = {
+ MERGE_3D_BLK("merge_3d_0", MERGE_3D_0, 0x4e000),
+ MERGE_3D_BLK("merge_3d_1", MERGE_3D_1, 0x4f000),
+ MERGE_3D_BLK("merge_3d_2", MERGE_3D_2, 0x50000),
+ MERGE_3D_BLK("merge_3d_3", MERGE_3D_3, 0x65f00),
+};
+
+static const struct dpu_merge_3d_cfg sm8550_merge_3d[] = {
+ MERGE_3D_BLK("merge_3d_0", MERGE_3D_0, 0x4e000),
+ MERGE_3D_BLK("merge_3d_1", MERGE_3D_1, 0x4f000),
+ MERGE_3D_BLK("merge_3d_2", MERGE_3D_2, 0x50000),
+ MERGE_3D_BLK("merge_3d_3", MERGE_3D_3, 0x66700),
+};
+
/*************************************************************
* DSC sub blocks config
*************************************************************/
-#define DSC_BLK(_name, _id, _base) \
+#define DSC_BLK(_name, _id, _base, _features) \
{\
.name = _name, .id = _id, \
.base = _base, .len = 0x140, \
- .features = 0, \
+ .features = _features, \
}
static struct dpu_dsc_cfg sdm845_dsc[] = {
- DSC_BLK("dsc_0", DSC_0, 0x80000),
- DSC_BLK("dsc_1", DSC_1, 0x80400),
- DSC_BLK("dsc_2", DSC_2, 0x80800),
- DSC_BLK("dsc_3", DSC_3, 0x80c00),
+ DSC_BLK("dsc_0", DSC_0, 0x80000, 0),
+ DSC_BLK("dsc_1", DSC_1, 0x80400, 0),
+ DSC_BLK("dsc_2", DSC_2, 0x80800, 0),
+ DSC_BLK("dsc_3", DSC_3, 0x80c00, 0),
+};
+
+static struct dpu_dsc_cfg sm8150_dsc[] = {
+ DSC_BLK("dsc_0", DSC_0, 0x80000, BIT(DPU_DSC_OUTPUT_CTRL)),
+ DSC_BLK("dsc_1", DSC_1, 0x80400, BIT(DPU_DSC_OUTPUT_CTRL)),
+ DSC_BLK("dsc_2", DSC_2, 0x80800, BIT(DPU_DSC_OUTPUT_CTRL)),
+ DSC_BLK("dsc_3", DSC_3, 0x80c00, BIT(DPU_DSC_OUTPUT_CTRL)),
};
/*************************************************************
@@ -1307,6 +1889,13 @@ static const struct dpu_intf_cfg sc7280_intf[] = {
INTF_BLK("intf_5", INTF_5, 0x39000, INTF_DP, MSM_DP_CONTROLLER_1, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 22, 23),
};
+static const struct dpu_intf_cfg sm8350_intf[] = {
+ INTF_BLK("intf_0", INTF_0, 0x34000, INTF_DP, MSM_DP_CONTROLLER_0, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 24, 25),
+ INTF_BLK("intf_1", INTF_1, 0x35000, INTF_DSI, 0, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 26, 27),
+ INTF_BLK("intf_2", INTF_2, 0x36000, INTF_DSI, 1, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 28, 29),
+ INTF_BLK("intf_3", INTF_3, 0x37000, INTF_DP, MSM_DP_CONTROLLER_1, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 30, 31),
+};
+
static const struct dpu_intf_cfg sc8180x_intf[] = {
INTF_BLK("intf_0", INTF_0, 0x6A000, INTF_DP, MSM_DP_CONTROLLER_0, 24, INTF_SC7180_MASK, MDP_SSPP_TOP0_INTR, 24, 25),
INTF_BLK("intf_1", INTF_1, 0x6A800, INTF_DSI, 0, 24, INTF_SC7180_MASK, MDP_SSPP_TOP0_INTR, 26, 27),
@@ -1317,11 +1906,39 @@ static const struct dpu_intf_cfg sc8180x_intf[] = {
INTF_BLK("intf_5", INTF_5, 0x6C800, INTF_DP, MSM_DP_CONTROLLER_2, 24, INTF_SC7180_MASK, MDP_SSPP_TOP0_INTR, 22, 23),
};
+/* TODO: INTF 3, 8 and 7 are used for MST, marked as INTF_NONE for now */
+static const struct dpu_intf_cfg sc8280xp_intf[] = {
+ INTF_BLK("intf_0", INTF_0, 0x34000, INTF_DP, MSM_DP_CONTROLLER_0, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 24, 25),
+ INTF_BLK("intf_1", INTF_1, 0x35000, INTF_DSI, 0, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 26, 27),
+ INTF_BLK("intf_2", INTF_2, 0x36000, INTF_DSI, 1, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 28, 29),
+ INTF_BLK("intf_3", INTF_3, 0x37000, INTF_NONE, MSM_DP_CONTROLLER_0, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 30, 31),
+ INTF_BLK("intf_4", INTF_4, 0x38000, INTF_DP, MSM_DP_CONTROLLER_1, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 20, 21),
+ INTF_BLK("intf_5", INTF_5, 0x39000, INTF_DP, MSM_DP_CONTROLLER_3, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 22, 23),
+ INTF_BLK("intf_6", INTF_6, 0x3a000, INTF_DP, MSM_DP_CONTROLLER_2, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 16, 17),
+ INTF_BLK("intf_7", INTF_7, 0x3b000, INTF_NONE, MSM_DP_CONTROLLER_2, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 18, 19),
+ INTF_BLK("intf_8", INTF_8, 0x3c000, INTF_NONE, MSM_DP_CONTROLLER_1, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 12, 13),
+};
+
static const struct dpu_intf_cfg qcm2290_intf[] = {
INTF_BLK("intf_0", INTF_0, 0x00000, INTF_NONE, 0, 0, 0, 0, 0, 0),
INTF_BLK("intf_1", INTF_1, 0x6A800, INTF_DSI, 0, 24, INTF_SC7180_MASK, MDP_SSPP_TOP0_INTR, 26, 27),
};
+static const struct dpu_intf_cfg sm8450_intf[] = {
+ INTF_BLK("intf_0", INTF_0, 0x34000, INTF_DP, MSM_DP_CONTROLLER_0, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 24, 25),
+ INTF_BLK("intf_1", INTF_1, 0x35000, INTF_DSI, 0, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 26, 27),
+ INTF_BLK("intf_2", INTF_2, 0x36000, INTF_DSI, 1, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 28, 29),
+ INTF_BLK("intf_3", INTF_3, 0x37000, INTF_DP, MSM_DP_CONTROLLER_1, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 30, 31),
+};
+
+static const struct dpu_intf_cfg sm8550_intf[] = {
+ INTF_BLK("intf_0", INTF_0, 0x34000, INTF_DP, MSM_DP_CONTROLLER_0, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 24, 25),
+ /* TODO TE sub-blocks for intf1 & intf2 */
+ INTF_BLK("intf_1", INTF_1, 0x35000, INTF_DSI, 0, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 26, 27),
+ INTF_BLK("intf_2", INTF_2, 0x36000, INTF_DSI, 1, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 28, 29),
+ INTF_BLK("intf_3", INTF_3, 0x37000, INTF_DP, MSM_DP_CONTROLLER_1, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 30, 31),
+};
+
/*************************************************************
* Writeback blocks config
*************************************************************/
@@ -1419,6 +2036,14 @@ static const struct dpu_vbif_cfg sdm845_vbif[] = {
},
};
+static const struct dpu_reg_dma_cfg sc8280xp_regdma = {
+ .base = 0x0,
+ .version = 0x00020000,
+ .trigger_sel_off = 0x119c,
+ .xin_id = 7,
+ .clk_ctrl = DPU_CLK_CTRL_REG_DMA,
+};
+
static const struct dpu_reg_dma_cfg sdm845_regdma = {
.base = 0x0, .version = 0x1, .trigger_sel_off = 0x119c
};
@@ -1435,6 +2060,22 @@ static const struct dpu_reg_dma_cfg sm8250_regdma = {
.clk_ctrl = DPU_CLK_CTRL_REG_DMA,
};
+static const struct dpu_reg_dma_cfg sm8350_regdma = {
+ .base = 0x400,
+ .version = 0x00020000,
+ .trigger_sel_off = 0x119c,
+ .xin_id = 7,
+ .clk_ctrl = DPU_CLK_CTRL_REG_DMA,
+};
+
+static const struct dpu_reg_dma_cfg sm8450_regdma = {
+ .base = 0x0,
+ .version = 0x00020000,
+ .trigger_sel_off = 0x119c,
+ .xin_id = 7,
+ .clk_ctrl = DPU_CLK_CTRL_REG_DMA,
+};
+
/*************************************************************
* PERF data config
*************************************************************/
@@ -1691,6 +2332,33 @@ static const struct dpu_perf_cfg sc8180x_perf_data = {
.min_dram_ib = 800000,
.danger_lut_tbl = {0xf, 0xffff, 0x0},
.qos_lut_tbl = {
+ {.nentry = ARRAY_SIZE(sc7180_qos_linear),
+ .entries = sc7180_qos_linear
+ },
+ {.nentry = ARRAY_SIZE(sc7180_qos_macrotile),
+ .entries = sc7180_qos_macrotile
+ },
+ {.nentry = ARRAY_SIZE(sc7180_qos_nrt),
+ .entries = sc7180_qos_nrt
+ },
+ /* TODO: macrotile-qseed is different from macrotile */
+ },
+ .cdp_cfg = {
+ {.rd_enable = 1, .wr_enable = 1},
+ {.rd_enable = 1, .wr_enable = 0}
+ },
+ .clk_inefficiency_factor = 105,
+ .bw_inefficiency_factor = 120,
+};
+
+static const struct dpu_perf_cfg sc8280xp_perf_data = {
+ .max_bw_low = 13600000,
+ .max_bw_high = 18200000,
+ .min_core_ib = 2500000,
+ .min_llcc_ib = 0,
+ .min_dram_ib = 800000,
+ .danger_lut_tbl = {0xf, 0xffff, 0x0},
+ .qos_lut_tbl = {
{.nentry = ARRAY_SIZE(sc8180x_qos_linear),
.entries = sc8180x_qos_linear
},
@@ -1739,6 +2407,36 @@ static const struct dpu_perf_cfg sm8250_perf_data = {
.bw_inefficiency_factor = 120,
};
+static const struct dpu_perf_cfg sm8450_perf_data = {
+ .max_bw_low = 13600000,
+ .max_bw_high = 18200000,
+ .min_core_ib = 2500000,
+ .min_llcc_ib = 0,
+ .min_dram_ib = 800000,
+ .min_prefill_lines = 35,
+ /* FIXME: lut tables */
+ .danger_lut_tbl = {0x3ffff, 0x3ffff, 0x0},
+ .safe_lut_tbl = {0xfe00, 0xfe00, 0xffff},
+ .qos_lut_tbl = {
+ {.nentry = ARRAY_SIZE(sc7180_qos_linear),
+ .entries = sc7180_qos_linear
+ },
+ {.nentry = ARRAY_SIZE(sc7180_qos_macrotile),
+ .entries = sc7180_qos_macrotile
+ },
+ {.nentry = ARRAY_SIZE(sc7180_qos_nrt),
+ .entries = sc7180_qos_nrt
+ },
+ /* TODO: macrotile-qseed is different from macrotile */
+ },
+ .cdp_cfg = {
+ {.rd_enable = 1, .wr_enable = 1},
+ {.rd_enable = 1, .wr_enable = 0}
+ },
+ .clk_inefficiency_factor = 105,
+ .bw_inefficiency_factor = 120,
+};
+
static const struct dpu_perf_cfg sc7280_perf_data = {
.max_bw_low = 4700000,
.max_bw_high = 8800000,
@@ -1767,6 +2465,36 @@ static const struct dpu_perf_cfg sc7280_perf_data = {
.bw_inefficiency_factor = 120,
};
+static const struct dpu_perf_cfg sm8350_perf_data = {
+ .max_bw_low = 11800000,
+ .max_bw_high = 15500000,
+ .min_core_ib = 2500000,
+ .min_llcc_ib = 0,
+ .min_dram_ib = 800000,
+ .min_prefill_lines = 40,
+ /* FIXME: lut tables */
+ .danger_lut_tbl = {0x3ffff, 0x3ffff, 0x0},
+ .safe_lut_tbl = {0xfe00, 0xfe00, 0xffff},
+ .qos_lut_tbl = {
+ {.nentry = ARRAY_SIZE(sc7180_qos_linear),
+ .entries = sc7180_qos_linear
+ },
+ {.nentry = ARRAY_SIZE(sc7180_qos_macrotile),
+ .entries = sc7180_qos_macrotile
+ },
+ {.nentry = ARRAY_SIZE(sc7180_qos_nrt),
+ .entries = sc7180_qos_nrt
+ },
+ /* TODO: macrotile-qseed is different from macrotile */
+ },
+ .cdp_cfg = {
+ {.rd_enable = 1, .wr_enable = 1},
+ {.rd_enable = 1, .wr_enable = 0}
+ },
+ .clk_inefficiency_factor = 105,
+ .bw_inefficiency_factor = 120,
+};
+
static const struct dpu_perf_cfg qcm2290_perf_data = {
.max_bw_low = 2700000,
.max_bw_high = 2700000,
@@ -1899,6 +2627,8 @@ static const struct dpu_mdss_cfg sm8150_dpu_cfg = {
.mixer = sm8150_lm,
.dspp_count = ARRAY_SIZE(sm8150_dspp),
.dspp = sm8150_dspp,
+ .dsc_count = ARRAY_SIZE(sm8150_dsc),
+ .dsc = sm8150_dsc,
.pingpong_count = ARRAY_SIZE(sm8150_pp),
.pingpong = sm8150_pp,
.merge_3d_count = ARRAY_SIZE(sm8150_merge_3d),
@@ -1937,6 +2667,32 @@ static const struct dpu_mdss_cfg sc8180x_dpu_cfg = {
.mdss_irqs = IRQ_SC8180X_MASK,
};
+static const struct dpu_mdss_cfg sc8280xp_dpu_cfg = {
+ .caps = &sc8280xp_dpu_caps,
+ .mdp_count = ARRAY_SIZE(sc8280xp_mdp),
+ .mdp = sc8280xp_mdp,
+ .ctl_count = ARRAY_SIZE(sc8280xp_ctl),
+ .ctl = sc8280xp_ctl,
+ .sspp_count = ARRAY_SIZE(sc8280xp_sspp),
+ .sspp = sc8280xp_sspp,
+ .mixer_count = ARRAY_SIZE(sc8280xp_lm),
+ .mixer = sc8280xp_lm,
+ .dspp_count = ARRAY_SIZE(sm8150_dspp),
+ .dspp = sm8150_dspp,
+ .pingpong_count = ARRAY_SIZE(sc8280xp_pp),
+ .pingpong = sc8280xp_pp,
+ .merge_3d_count = ARRAY_SIZE(sm8350_merge_3d),
+ .merge_3d = sm8350_merge_3d,
+ .intf_count = ARRAY_SIZE(sc8280xp_intf),
+ .intf = sc8280xp_intf,
+ .vbif_count = ARRAY_SIZE(sdm845_vbif),
+ .vbif = sdm845_vbif,
+ .reg_dma_count = 1,
+ .dma_cfg = &sc8280xp_regdma,
+ .perf = &sc8280xp_perf_data,
+ .mdss_irqs = IRQ_SC8280XP_MASK,
+};
+
static const struct dpu_mdss_cfg sm8250_dpu_cfg = {
.caps = &sm8250_dpu_caps,
.mdp_count = ARRAY_SIZE(sm8250_mdp),
@@ -1949,6 +2705,8 @@ static const struct dpu_mdss_cfg sm8250_dpu_cfg = {
.mixer = sm8150_lm,
.dspp_count = ARRAY_SIZE(sm8150_dspp),
.dspp = sm8150_dspp,
+ .dsc_count = ARRAY_SIZE(sm8150_dsc),
+ .dsc = sm8150_dsc,
.pingpong_count = ARRAY_SIZE(sm8150_pp),
.pingpong = sm8150_pp,
.merge_3d_count = ARRAY_SIZE(sm8150_merge_3d),
@@ -1965,6 +2723,84 @@ static const struct dpu_mdss_cfg sm8250_dpu_cfg = {
.mdss_irqs = IRQ_SM8250_MASK,
};
+static const struct dpu_mdss_cfg sm8350_dpu_cfg = {
+ .caps = &sm8350_dpu_caps,
+ .mdp_count = ARRAY_SIZE(sm8350_mdp),
+ .mdp = sm8350_mdp,
+ .ctl_count = ARRAY_SIZE(sm8350_ctl),
+ .ctl = sm8350_ctl,
+ .sspp_count = ARRAY_SIZE(sm8250_sspp),
+ .sspp = sm8250_sspp,
+ .mixer_count = ARRAY_SIZE(sm8150_lm),
+ .mixer = sm8150_lm,
+ .dspp_count = ARRAY_SIZE(sm8150_dspp),
+ .dspp = sm8150_dspp,
+ .pingpong_count = ARRAY_SIZE(sm8350_pp),
+ .pingpong = sm8350_pp,
+ .merge_3d_count = ARRAY_SIZE(sm8350_merge_3d),
+ .merge_3d = sm8350_merge_3d,
+ .intf_count = ARRAY_SIZE(sm8350_intf),
+ .intf = sm8350_intf,
+ .vbif_count = ARRAY_SIZE(sdm845_vbif),
+ .vbif = sdm845_vbif,
+ .reg_dma_count = 1,
+ .dma_cfg = &sm8350_regdma,
+ .perf = &sm8350_perf_data,
+ .mdss_irqs = IRQ_SM8350_MASK,
+};
+
+static const struct dpu_mdss_cfg sm8450_dpu_cfg = {
+ .caps = &sm8450_dpu_caps,
+ .mdp_count = ARRAY_SIZE(sm8450_mdp),
+ .mdp = sm8450_mdp,
+ .ctl_count = ARRAY_SIZE(sm8450_ctl),
+ .ctl = sm8450_ctl,
+ .sspp_count = ARRAY_SIZE(sm8450_sspp),
+ .sspp = sm8450_sspp,
+ .mixer_count = ARRAY_SIZE(sm8150_lm),
+ .mixer = sm8150_lm,
+ .dspp_count = ARRAY_SIZE(sm8150_dspp),
+ .dspp = sm8150_dspp,
+ .pingpong_count = ARRAY_SIZE(sm8450_pp),
+ .pingpong = sm8450_pp,
+ .merge_3d_count = ARRAY_SIZE(sm8450_merge_3d),
+ .merge_3d = sm8450_merge_3d,
+ .intf_count = ARRAY_SIZE(sm8450_intf),
+ .intf = sm8450_intf,
+ .vbif_count = ARRAY_SIZE(sdm845_vbif),
+ .vbif = sdm845_vbif,
+ .reg_dma_count = 1,
+ .dma_cfg = &sm8450_regdma,
+ .perf = &sm8450_perf_data,
+ .mdss_irqs = IRQ_SM8450_MASK,
+};
+
+static const struct dpu_mdss_cfg sm8550_dpu_cfg = {
+ .caps = &sm8550_dpu_caps,
+ .mdp_count = ARRAY_SIZE(sm8550_mdp),
+ .mdp = sm8550_mdp,
+ .ctl_count = ARRAY_SIZE(sm8550_ctl),
+ .ctl = sm8550_ctl,
+ .sspp_count = ARRAY_SIZE(sm8550_sspp),
+ .sspp = sm8550_sspp,
+ .mixer_count = ARRAY_SIZE(sm8150_lm),
+ .mixer = sm8150_lm,
+ .dspp_count = ARRAY_SIZE(sm8150_dspp),
+ .dspp = sm8150_dspp,
+ .pingpong_count = ARRAY_SIZE(sm8550_pp),
+ .pingpong = sm8550_pp,
+ .merge_3d_count = ARRAY_SIZE(sm8550_merge_3d),
+ .merge_3d = sm8550_merge_3d,
+ .intf_count = ARRAY_SIZE(sm8550_intf),
+ .intf = sm8550_intf,
+ .vbif_count = ARRAY_SIZE(sdm845_vbif),
+ .vbif = sdm845_vbif,
+ .reg_dma_count = 1,
+ .dma_cfg = &sm8450_regdma,
+ .perf = &sm8450_perf_data,
+ .mdss_irqs = IRQ_SM8450_MASK,
+};
+
static const struct dpu_mdss_cfg sc7280_dpu_cfg = {
.caps = &sc7280_dpu_caps,
.mdp_count = ARRAY_SIZE(sc7280_mdp),
@@ -2023,7 +2859,11 @@ static const struct dpu_mdss_hw_cfg_handler cfg_handler[] = {
{ .hw_rev = DPU_HW_VER_620, .dpu_cfg = &sc7180_dpu_cfg},
{ .hw_rev = DPU_HW_VER_630, .dpu_cfg = &sm6115_dpu_cfg},
{ .hw_rev = DPU_HW_VER_650, .dpu_cfg = &qcm2290_dpu_cfg},
+ { .hw_rev = DPU_HW_VER_700, .dpu_cfg = &sm8350_dpu_cfg},
{ .hw_rev = DPU_HW_VER_720, .dpu_cfg = &sc7280_dpu_cfg},
+ { .hw_rev = DPU_HW_VER_800, .dpu_cfg = &sc8280xp_dpu_cfg},
+ { .hw_rev = DPU_HW_VER_810, .dpu_cfg = &sm8450_dpu_cfg},
+ { .hw_rev = DPU_HW_VER_900, .dpu_cfg = &sm8550_dpu_cfg},
};
const struct dpu_mdss_cfg *dpu_hw_catalog_init(u32 hw_rev)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
index 3b645d5aa9aa..ddab9caebb18 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
@@ -46,7 +46,11 @@
#define DPU_HW_VER_620 DPU_HW_VER(6, 2, 0) /* sc7180 v1.0 */
#define DPU_HW_VER_630 DPU_HW_VER(6, 3, 0) /* sm6115|sm4250 */
#define DPU_HW_VER_650 DPU_HW_VER(6, 5, 0) /* qcm2290|sm4125 */
+#define DPU_HW_VER_700 DPU_HW_VER(7, 0, 0) /* sm8350 */
#define DPU_HW_VER_720 DPU_HW_VER(7, 2, 0) /* sc7280 */
+#define DPU_HW_VER_800 DPU_HW_VER(8, 0, 0) /* sc8280xp */
+#define DPU_HW_VER_810 DPU_HW_VER(8, 1, 0) /* sm8450 */
+#define DPU_HW_VER_900 DPU_HW_VER(9, 0, 0) /* sm8550 */
#define IS_MSM8996_TARGET(rev) IS_DPU_MAJOR_MINOR_SAME((rev), DPU_HW_VER_170)
#define IS_MSM8998_TARGET(rev) IS_DPU_MAJOR_MINOR_SAME((rev), DPU_HW_VER_300)
@@ -83,6 +87,8 @@ enum {
* @DPU_MDP_UBWC_1_0, This chipsets supports Universal Bandwidth
* compression initial revision
* @DPU_MDP_UBWC_1_5, Universal Bandwidth compression version 1.5
+ * @DPU_MDP_PERIPH_0_REMOVED Indicates that access to periph top0 block results
+ * in a failure
* @DPU_MDP_MAX Maximum value
*/
@@ -93,6 +99,7 @@ enum {
DPU_MDP_UBWC_1_0,
DPU_MDP_UBWC_1_5,
DPU_MDP_AUDIO_SELECT,
+ DPU_MDP_PERIPH_0_REMOVED,
DPU_MDP_MAX
};
@@ -192,6 +199,7 @@ enum {
* @DPU_CTL_SPLIT_DISPLAY: CTL supports video mode split display
* @DPU_CTL_FETCH_ACTIVE: Active CTL for fetch HW (SSPPs)
* @DPU_CTL_VM_CFG: CTL config to support multiple VMs
+ * @DPU_CTL_HAS_LAYER_EXT4: CTL has the CTL_LAYER_EXT4 register
* @DPU_CTL_MAX
*/
enum {
@@ -199,6 +207,7 @@ enum {
DPU_CTL_ACTIVE_CFG,
DPU_CTL_FETCH_ACTIVE,
DPU_CTL_VM_CFG,
+ DPU_CTL_HAS_LAYER_EXT4,
DPU_CTL_MAX
};
@@ -267,6 +276,15 @@ enum {
};
/**
+ * DSC features
+ * @DPU_DSC_OUTPUT_CTRL Configure which PINGPONG block gets
+ * the pixel output from this DSC.
+ */
+enum {
+ DPU_DSC_OUTPUT_CTRL = 0x1,
+};
+
+/**
* MACRO DPU_HW_BLK_INFO - information of HW blocks inside DPU
* @name: string name for debug purposes
* @id: enum identifying this block
@@ -519,7 +537,6 @@ struct dpu_clk_ctrl_reg {
* @base: register base offset to mdss
* @features bit mask identifying sub-blocks/features
* @highest_bank_bit: UBWC parameter
- * @ubwc_static: ubwc static configuration
* @ubwc_swizzle: ubwc default swizzle setting
* @clk_ctrls clock control register definition
*/
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
index a35ecb6676c8..b88a2f3724e6 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
@@ -17,6 +17,8 @@
(0x70 + (((lm) - LM_0) * 0x004))
#define CTL_LAYER_EXT3(lm) \
(0xA0 + (((lm) - LM_0) * 0x004))
+#define CTL_LAYER_EXT4(lm) \
+ (0xB8 + (((lm) - LM_0) * 0x004))
#define CTL_TOP 0x014
#define CTL_FLUSH 0x018
#define CTL_START 0x01C
@@ -377,12 +379,37 @@ static void dpu_hw_ctl_clear_all_blendstages(struct dpu_hw_ctl *ctx)
DPU_REG_WRITE(c, CTL_FETCH_PIPE_ACTIVE, 0);
}
+struct ctl_blend_config {
+ int idx, shift, ext_shift;
+};
+
+static const struct ctl_blend_config ctl_blend_config[][2] = {
+ [SSPP_NONE] = { { -1 }, { -1 } },
+ [SSPP_MAX] = { { -1 }, { -1 } },
+ [SSPP_VIG0] = { { 0, 0, 0 }, { 3, 0 } },
+ [SSPP_VIG1] = { { 0, 3, 2 }, { 3, 4 } },
+ [SSPP_VIG2] = { { 0, 6, 4 }, { 3, 8 } },
+ [SSPP_VIG3] = { { 0, 26, 6 }, { 3, 12 } },
+ [SSPP_RGB0] = { { 0, 9, 8 }, { -1 } },
+ [SSPP_RGB1] = { { 0, 12, 10 }, { -1 } },
+ [SSPP_RGB2] = { { 0, 15, 12 }, { -1 } },
+ [SSPP_RGB3] = { { 0, 29, 14 }, { -1 } },
+ [SSPP_DMA0] = { { 0, 18, 16 }, { 2, 8 } },
+ [SSPP_DMA1] = { { 0, 21, 18 }, { 2, 12 } },
+ [SSPP_DMA2] = { { 2, 0 }, { 2, 16 } },
+ [SSPP_DMA3] = { { 2, 4 }, { 2, 20 } },
+ [SSPP_DMA4] = { { 4, 0 }, { 4, 8 } },
+ [SSPP_DMA5] = { { 4, 4 }, { 4, 12 } },
+ [SSPP_CURSOR0] = { { 1, 20 }, { -1 } },
+ [SSPP_CURSOR1] = { { 1, 26 }, { -1 } },
+};
+
static void dpu_hw_ctl_setup_blendstage(struct dpu_hw_ctl *ctx,
enum dpu_lm lm, struct dpu_hw_stage_cfg *stage_cfg)
{
struct dpu_hw_blk_reg_map *c = &ctx->hw;
- u32 mixercfg = 0, mixercfg_ext = 0, mix, ext;
- u32 mixercfg_ext2 = 0, mixercfg_ext3 = 0;
+ u32 mix, ext, mix_ext;
+ u32 mixercfg[5] = { 0 };
int i, j;
int stages;
int pipes_per_stage;
@@ -397,7 +424,7 @@ static void dpu_hw_ctl_setup_blendstage(struct dpu_hw_ctl *ctx,
else
pipes_per_stage = 1;
- mixercfg = CTL_MIXER_BORDER_OUT; /* always set BORDER_OUT */
+ mixercfg[0] = CTL_MIXER_BORDER_OUT; /* always set BORDER_OUT */
if (!stage_cfg)
goto exit;
@@ -406,109 +433,35 @@ static void dpu_hw_ctl_setup_blendstage(struct dpu_hw_ctl *ctx,
/* overflow to ext register if 'i + 1 > 7' */
mix = (i + 1) & 0x7;
ext = i >= 7;
+ mix_ext = (i + 1) & 0xf;
for (j = 0 ; j < pipes_per_stage; j++) {
enum dpu_sspp_multirect_index rect_index =
stage_cfg->multirect_index[i][j];
-
- switch (stage_cfg->stage[i][j]) {
- case SSPP_VIG0:
- if (rect_index == DPU_SSPP_RECT_1) {
- mixercfg_ext3 |= ((i + 1) & 0xF) << 0;
- } else {
- mixercfg |= mix << 0;
- mixercfg_ext |= ext << 0;
- }
- break;
- case SSPP_VIG1:
- if (rect_index == DPU_SSPP_RECT_1) {
- mixercfg_ext3 |= ((i + 1) & 0xF) << 4;
- } else {
- mixercfg |= mix << 3;
- mixercfg_ext |= ext << 2;
- }
- break;
- case SSPP_VIG2:
- if (rect_index == DPU_SSPP_RECT_1) {
- mixercfg_ext3 |= ((i + 1) & 0xF) << 8;
- } else {
- mixercfg |= mix << 6;
- mixercfg_ext |= ext << 4;
- }
- break;
- case SSPP_VIG3:
- if (rect_index == DPU_SSPP_RECT_1) {
- mixercfg_ext3 |= ((i + 1) & 0xF) << 12;
- } else {
- mixercfg |= mix << 26;
- mixercfg_ext |= ext << 6;
- }
- break;
- case SSPP_RGB0:
- mixercfg |= mix << 9;
- mixercfg_ext |= ext << 8;
- break;
- case SSPP_RGB1:
- mixercfg |= mix << 12;
- mixercfg_ext |= ext << 10;
- break;
- case SSPP_RGB2:
- mixercfg |= mix << 15;
- mixercfg_ext |= ext << 12;
- break;
- case SSPP_RGB3:
- mixercfg |= mix << 29;
- mixercfg_ext |= ext << 14;
- break;
- case SSPP_DMA0:
- if (rect_index == DPU_SSPP_RECT_1) {
- mixercfg_ext2 |= ((i + 1) & 0xF) << 8;
- } else {
- mixercfg |= mix << 18;
- mixercfg_ext |= ext << 16;
- }
- break;
- case SSPP_DMA1:
- if (rect_index == DPU_SSPP_RECT_1) {
- mixercfg_ext2 |= ((i + 1) & 0xF) << 12;
- } else {
- mixercfg |= mix << 21;
- mixercfg_ext |= ext << 18;
- }
- break;
- case SSPP_DMA2:
- if (rect_index == DPU_SSPP_RECT_1) {
- mixercfg_ext2 |= ((i + 1) & 0xF) << 16;
- } else {
- mix |= (i + 1) & 0xF;
- mixercfg_ext2 |= mix << 0;
- }
- break;
- case SSPP_DMA3:
- if (rect_index == DPU_SSPP_RECT_1) {
- mixercfg_ext2 |= ((i + 1) & 0xF) << 20;
- } else {
- mix |= (i + 1) & 0xF;
- mixercfg_ext2 |= mix << 4;
- }
- break;
- case SSPP_CURSOR0:
- mixercfg_ext |= ((i + 1) & 0xF) << 20;
- break;
- case SSPP_CURSOR1:
- mixercfg_ext |= ((i + 1) & 0xF) << 26;
- break;
- default:
- break;
+ enum dpu_sspp pipe = stage_cfg->stage[i][j];
+ const struct ctl_blend_config *cfg =
+ &ctl_blend_config[pipe][rect_index == DPU_SSPP_RECT_1];
+
+ /*
+ * CTL_LAYER has 3-bit field (and extra bits in EXT register),
+ * all EXT registers has 4-bit fields.
+ */
+ if (cfg->idx == 0) {
+ mixercfg[0] |= mix << cfg->shift;
+ mixercfg[1] |= ext << cfg->ext_shift;
+ } else {
+ mixercfg[cfg->idx] |= mix_ext << cfg->shift;
}
}
}
exit:
- DPU_REG_WRITE(c, CTL_LAYER(lm), mixercfg);
- DPU_REG_WRITE(c, CTL_LAYER_EXT(lm), mixercfg_ext);
- DPU_REG_WRITE(c, CTL_LAYER_EXT2(lm), mixercfg_ext2);
- DPU_REG_WRITE(c, CTL_LAYER_EXT3(lm), mixercfg_ext3);
+ DPU_REG_WRITE(c, CTL_LAYER(lm), mixercfg[0]);
+ DPU_REG_WRITE(c, CTL_LAYER_EXT(lm), mixercfg[1]);
+ DPU_REG_WRITE(c, CTL_LAYER_EXT2(lm), mixercfg[2]);
+ DPU_REG_WRITE(c, CTL_LAYER_EXT3(lm), mixercfg[3]);
+ if ((test_bit(DPU_CTL_HAS_LAYER_EXT4, &ctx->caps->features)))
+ DPU_REG_WRITE(c, CTL_LAYER_EXT4(lm), mixercfg[4]);
}
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c
index 3662df698dae..619926da1441 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c
@@ -29,6 +29,8 @@
#define DSC_RANGE_MAX_QP 0x0B0
#define DSC_RANGE_BPG_OFFSET 0x0EC
+#define DSC_CTL(m) (0x1800 - 0x3FC * (m - DSC_0))
+
static void dpu_hw_dsc_disable(struct dpu_hw_dsc *dsc)
{
struct dpu_hw_blk_reg_map *c = &dsc->hw;
@@ -150,6 +152,29 @@ static void dpu_hw_dsc_config_thresh(struct dpu_hw_dsc *hw_dsc,
}
}
+static void dpu_hw_dsc_bind_pingpong_blk(
+ struct dpu_hw_dsc *hw_dsc,
+ bool enable,
+ const enum dpu_pingpong pp)
+{
+ struct dpu_hw_blk_reg_map *c = &hw_dsc->hw;
+ int mux_cfg = 0xF;
+ u32 dsc_ctl_offset;
+
+ dsc_ctl_offset = DSC_CTL(hw_dsc->idx);
+
+ if (enable)
+ mux_cfg = (pp - PINGPONG_0) & 0x7;
+
+ DRM_DEBUG_KMS("%s dsc:%d %s pp:%d\n",
+ enable ? "Binding" : "Unbinding",
+ hw_dsc->idx - DSC_0,
+ enable ? "to" : "from",
+ pp - PINGPONG_0);
+
+ DPU_REG_WRITE(c, dsc_ctl_offset, mux_cfg);
+}
+
static struct dpu_dsc_cfg *_dsc_offset(enum dpu_dsc dsc,
const struct dpu_mdss_cfg *m,
void __iomem *addr,
@@ -174,6 +199,8 @@ static void _setup_dsc_ops(struct dpu_hw_dsc_ops *ops,
ops->dsc_disable = dpu_hw_dsc_disable;
ops->dsc_config = dpu_hw_dsc_config;
ops->dsc_config_thresh = dpu_hw_dsc_config_thresh;
+ if (cap & BIT(DPU_DSC_OUTPUT_CTRL))
+ ops->dsc_bind_pingpong_blk = dpu_hw_dsc_bind_pingpong_blk;
};
struct dpu_hw_dsc *dpu_hw_dsc_init(enum dpu_dsc idx, void __iomem *addr,
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h
index c0b77fe1a696..ae9b5db53d7f 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h
@@ -42,6 +42,10 @@ struct dpu_hw_dsc_ops {
*/
void (*dsc_config_thresh)(struct dpu_hw_dsc *hw_dsc,
struct drm_dsc_config *dsc);
+
+ void (*dsc_bind_pingpong_blk)(struct dpu_hw_dsc *hw_dsc,
+ bool enable,
+ enum dpu_pingpong pp);
};
struct dpu_hw_dsc {
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c
index cf1b6d84c18a..53326f25e40e 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c
@@ -35,6 +35,9 @@
#define MDP_INTF_3_OFF_REV_7xxx 0x37000
#define MDP_INTF_4_OFF_REV_7xxx 0x38000
#define MDP_INTF_5_OFF_REV_7xxx 0x39000
+#define MDP_INTF_6_OFF_REV_7xxx 0x3a000
+#define MDP_INTF_7_OFF_REV_7xxx 0x3b000
+#define MDP_INTF_8_OFF_REV_7xxx 0x3c000
/**
* struct dpu_intr_reg - array of DPU register sets
@@ -139,6 +142,21 @@ static const struct dpu_intr_reg dpu_intr_set[] = {
MDP_INTF_5_OFF_REV_7xxx+INTF_INTR_EN,
MDP_INTF_5_OFF_REV_7xxx+INTF_INTR_STATUS
},
+ [MDP_INTF6_7xxx_INTR] = {
+ MDP_INTF_6_OFF_REV_7xxx+INTF_INTR_CLEAR,
+ MDP_INTF_6_OFF_REV_7xxx+INTF_INTR_EN,
+ MDP_INTF_6_OFF_REV_7xxx+INTF_INTR_STATUS
+ },
+ [MDP_INTF7_7xxx_INTR] = {
+ MDP_INTF_7_OFF_REV_7xxx+INTF_INTR_CLEAR,
+ MDP_INTF_7_OFF_REV_7xxx+INTF_INTR_EN,
+ MDP_INTF_7_OFF_REV_7xxx+INTF_INTR_STATUS
+ },
+ [MDP_INTF8_7xxx_INTR] = {
+ MDP_INTF_8_OFF_REV_7xxx+INTF_INTR_CLEAR,
+ MDP_INTF_8_OFF_REV_7xxx+INTF_INTR_EN,
+ MDP_INTF_8_OFF_REV_7xxx+INTF_INTR_STATUS
+ },
};
#define DPU_IRQ_REG(irq_idx) (irq_idx / 32)
@@ -252,9 +270,9 @@ static int dpu_hw_intr_enable_irq_locked(struct dpu_hw_intr *intr, int irq_idx)
cache_irq_mask = intr->cache_irq_mask[reg_idx];
if (cache_irq_mask & DPU_IRQ_MASK(irq_idx)) {
- dbgstr = "DPU IRQ already set:";
+ dbgstr = "already ";
} else {
- dbgstr = "DPU IRQ enabled:";
+ dbgstr = "";
cache_irq_mask |= DPU_IRQ_MASK(irq_idx);
/* Cleaning any pending interrupt */
@@ -268,7 +286,7 @@ static int dpu_hw_intr_enable_irq_locked(struct dpu_hw_intr *intr, int irq_idx)
intr->cache_irq_mask[reg_idx] = cache_irq_mask;
}
- pr_debug("%s MASK:0x%.8lx, CACHE-MASK:0x%.8x\n", dbgstr,
+ pr_debug("DPU IRQ %d %senabled: MASK:0x%.8lx, CACHE-MASK:0x%.8x\n", irq_idx, dbgstr,
DPU_IRQ_MASK(irq_idx), cache_irq_mask);
return 0;
@@ -301,9 +319,9 @@ static int dpu_hw_intr_disable_irq_locked(struct dpu_hw_intr *intr, int irq_idx)
cache_irq_mask = intr->cache_irq_mask[reg_idx];
if ((cache_irq_mask & DPU_IRQ_MASK(irq_idx)) == 0) {
- dbgstr = "DPU IRQ is already cleared:";
+ dbgstr = "already ";
} else {
- dbgstr = "DPU IRQ mask disable:";
+ dbgstr = "";
cache_irq_mask &= ~DPU_IRQ_MASK(irq_idx);
/* Disable interrupts based on the new mask */
@@ -317,7 +335,7 @@ static int dpu_hw_intr_disable_irq_locked(struct dpu_hw_intr *intr, int irq_idx)
intr->cache_irq_mask[reg_idx] = cache_irq_mask;
}
- pr_debug("%s MASK:0x%.8lx, CACHE-MASK:0x%.8x\n", dbgstr,
+ pr_debug("DPU IRQ %d %sdisabled: MASK:0x%.8lx, CACHE-MASK:0x%.8x\n", irq_idx, dbgstr,
DPU_IRQ_MASK(irq_idx), cache_irq_mask);
return 0;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h
index 46443955443c..425465011c80 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h
@@ -31,6 +31,9 @@ enum dpu_hw_intr_reg {
MDP_INTF3_7xxx_INTR,
MDP_INTF4_7xxx_INTR,
MDP_INTF5_7xxx_INTR,
+ MDP_INTF6_7xxx_INTR,
+ MDP_INTF7_7xxx_INTR,
+ MDP_INTF8_7xxx_INTR,
MDP_INTR_MAX,
};
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h
index d3b0ed0a9c6c..2d9192a6ce00 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h
@@ -120,6 +120,8 @@ enum dpu_sspp {
SSPP_DMA1,
SSPP_DMA2,
SSPP_DMA3,
+ SSPP_DMA4,
+ SSPP_DMA5,
SSPP_CURSOR0,
SSPP_CURSOR1,
SSPP_MAX
@@ -195,6 +197,8 @@ enum dpu_pingpong {
PINGPONG_3,
PINGPONG_4,
PINGPONG_5,
+ PINGPONG_6,
+ PINGPONG_7,
PINGPONG_S0,
PINGPONG_MAX
};
@@ -203,6 +207,7 @@ enum dpu_merge_3d {
MERGE_3D_0 = 1,
MERGE_3D_1,
MERGE_3D_2,
+ MERGE_3D_3,
MERGE_3D_MAX
};
@@ -214,6 +219,8 @@ enum dpu_intf {
INTF_4,
INTF_5,
INTF_6,
+ INTF_7,
+ INTF_8,
INTF_MAX
};
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c
index 691c471b08c2..4246ab0b3bee 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c
@@ -310,7 +310,11 @@ static void dpu_hw_sspp_setup_format(struct dpu_hw_pipe *ctx,
ctx->mdp->highest_bank_bit << 18);
switch (ctx->catalog->caps->ubwc_version) {
case DPU_HW_UBWC_VER_10:
- /* TODO: UBWC v1 case */
+ fast_clear = fmt->alpha_enable ? BIT(31) : 0;
+ DPU_REG_WRITE(c, SSPP_UBWC_STATIC_CTRL,
+ fast_clear | (ctx->mdp->ubwc_swizzle & 0x1) |
+ BIT(8) |
+ (ctx->mdp->highest_bank_bit << 4));
break;
case DPU_HW_UBWC_VER_20:
fast_clear = fmt->alpha_enable ? BIT(31) : 0;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c
index c3110a25a30d..2bb02e17ee52 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c
@@ -7,40 +7,17 @@
#include "dpu_hw_top.h"
#include "dpu_kms.h"
-#define SSPP_SPARE 0x28
-
#define FLD_SPLIT_DISPLAY_CMD BIT(1)
#define FLD_SMART_PANEL_FREE_RUN BIT(2)
#define FLD_INTF_1_SW_TRG_MUX BIT(4)
#define FLD_INTF_2_SW_TRG_MUX BIT(8)
#define FLD_TE_LINE_INTER_WATERLEVEL_MASK 0xFFFF
-#define DANGER_STATUS 0x360
-#define SAFE_STATUS 0x364
-
-#define TE_LINE_INTERVAL 0x3F4
-
#define TRAFFIC_SHAPER_EN BIT(31)
#define TRAFFIC_SHAPER_RD_CLIENT(num) (0x030 + (num * 4))
#define TRAFFIC_SHAPER_WR_CLIENT(num) (0x060 + (num * 4))
#define TRAFFIC_SHAPER_FIXPOINT_FACTOR 4
-#define MDP_WD_TIMER_0_CTL 0x380
-#define MDP_WD_TIMER_0_CTL2 0x384
-#define MDP_WD_TIMER_0_LOAD_VALUE 0x388
-#define MDP_WD_TIMER_1_CTL 0x390
-#define MDP_WD_TIMER_1_CTL2 0x394
-#define MDP_WD_TIMER_1_LOAD_VALUE 0x398
-#define MDP_WD_TIMER_2_CTL 0x420
-#define MDP_WD_TIMER_2_CTL2 0x424
-#define MDP_WD_TIMER_2_LOAD_VALUE 0x428
-#define MDP_WD_TIMER_3_CTL 0x430
-#define MDP_WD_TIMER_3_CTL2 0x434
-#define MDP_WD_TIMER_3_LOAD_VALUE 0x438
-#define MDP_WD_TIMER_4_CTL 0x440
-#define MDP_WD_TIMER_4_CTL2 0x444
-#define MDP_WD_TIMER_4_LOAD_VALUE 0x448
-
#define MDP_TICK_COUNT 16
#define XO_CLK_RATE 19200
#define MS_TICKS_IN_SEC 1000
@@ -48,8 +25,6 @@
#define CALCULATE_WD_LOAD_VALUE(fps) \
((uint32_t)((MS_TICKS_IN_SEC * XO_CLK_RATE)/(MDP_TICK_COUNT * fps)))
-#define DCE_SEL 0x450
-
static void dpu_hw_setup_split_pipe(struct dpu_hw_mdp *mdp,
struct split_pipe_cfg *cfg)
{
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hwio.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hwio.h
index c8156ed4b7fb..feb9a729844a 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hwio.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hwio.h
@@ -16,6 +16,7 @@
#define INTR_CLEAR 0x018
#define INTR2_EN 0x008
#define INTR2_STATUS 0x00c
+#define SSPP_SPARE 0x028
#define INTR2_CLEAR 0x02c
#define HIST_INTR_EN 0x01c
#define HIST_INTR_STATUS 0x020
@@ -28,7 +29,15 @@
#define DSPP_IGC_COLOR0_RAM_LUTN 0x300
#define DSPP_IGC_COLOR1_RAM_LUTN 0x304
#define DSPP_IGC_COLOR2_RAM_LUTN 0x308
+#define DANGER_STATUS 0x360
+#define SAFE_STATUS 0x364
#define HW_EVENTS_CTL 0x37C
+#define MDP_WD_TIMER_0_CTL 0x380
+#define MDP_WD_TIMER_0_CTL2 0x384
+#define MDP_WD_TIMER_0_LOAD_VALUE 0x388
+#define MDP_WD_TIMER_1_CTL 0x390
+#define MDP_WD_TIMER_1_CTL2 0x394
+#define MDP_WD_TIMER_1_LOAD_VALUE 0x398
#define CLK_CTRL3 0x3A8
#define CLK_STATUS3 0x3AC
#define CLK_CTRL4 0x3B0
@@ -43,6 +52,18 @@
#define HDMI_DP_CORE_SELECT 0x408
#define MDP_OUT_CTL_0 0x410
#define MDP_VSYNC_SEL 0x414
+#define MDP_WD_TIMER_2_CTL 0x420
+#define MDP_WD_TIMER_2_CTL2 0x424
+#define MDP_WD_TIMER_2_LOAD_VALUE 0x428
+#define MDP_WD_TIMER_3_CTL 0x430
+#define MDP_WD_TIMER_3_CTL2 0x434
+#define MDP_WD_TIMER_3_LOAD_VALUE 0x438
+#define MDP_WD_TIMER_4_CTL 0x440
+#define MDP_WD_TIMER_4_CTL2 0x444
+#define MDP_WD_TIMER_4_LOAD_VALUE 0x448
#define DCE_SEL 0x450
+#define MDP_PERIPH_TOP0 MDP_WD_TIMER_0_CTL
+#define MDP_PERIPH_TOP0_END CLK_CTRL3
+
#endif /*_DPU_HWIO_H */
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index b71199511a52..a683bd9b5a04 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -927,8 +927,20 @@ static void dpu_kms_mdp_snapshot(struct msm_disp_state *disp_state, struct msm_k
msm_disp_snapshot_add_block(disp_state, cat->wb[i].len,
dpu_kms->mmio + cat->wb[i].base, "wb_%d", i);
- msm_disp_snapshot_add_block(disp_state, cat->mdp[0].len,
- dpu_kms->mmio + cat->mdp[0].base, "top");
+ if (cat->mdp[0].features & BIT(DPU_MDP_PERIPH_0_REMOVED)) {
+ msm_disp_snapshot_add_block(disp_state, MDP_PERIPH_TOP0,
+ dpu_kms->mmio + cat->mdp[0].base, "top");
+ msm_disp_snapshot_add_block(disp_state, cat->mdp[0].len - MDP_PERIPH_TOP0_END,
+ dpu_kms->mmio + cat->mdp[0].base + MDP_PERIPH_TOP0_END, "top_2");
+ } else {
+ msm_disp_snapshot_add_block(disp_state, cat->mdp[0].len,
+ dpu_kms->mmio + cat->mdp[0].base, "top");
+ }
+
+ /* dump DSC sub-blocks HW regs info */
+ for (i = 0; i < cat->dsc_count; i++)
+ msm_disp_snapshot_add_block(disp_state, cat->dsc[i].len,
+ dpu_kms->mmio + cat->dsc[i].base, "dsc_%d", i);
pm_runtime_put_sync(&dpu_kms->pdev->dev);
}
@@ -1292,9 +1304,13 @@ static const struct of_device_id dpu_dt_match[] = {
{ .compatible = "qcom,sc7180-dpu", },
{ .compatible = "qcom,sc7280-dpu", },
{ .compatible = "qcom,sc8180x-dpu", },
+ { .compatible = "qcom,sc8280xp-dpu", },
{ .compatible = "qcom,sm6115-dpu", },
{ .compatible = "qcom,sm8150-dpu", },
{ .compatible = "qcom,sm8250-dpu", },
+ { .compatible = "qcom,sm8350-dpu", },
+ { .compatible = "qcom,sm8450-dpu", },
+ { .compatible = "qcom,sm8550-dpu", },
{}
};
MODULE_DEVICE_TABLE(of, dpu_dt_match);
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
index 86719020afe2..bfd5be89e8b8 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
@@ -1126,7 +1126,7 @@ static void dpu_plane_sspp_atomic_update(struct drm_plane *plane)
struct dpu_plane_state *pstate = to_dpu_plane_state(state);
struct drm_crtc *crtc = state->crtc;
struct drm_framebuffer *fb = state->fb;
- bool is_rt_pipe, update_qos_remap;
+ bool is_rt_pipe;
const struct dpu_format *fmt =
to_dpu_format(msm_framebuffer_format(fb));
struct dpu_hw_pipe_cfg pipe_cfg;
@@ -1138,6 +1138,9 @@ static void dpu_plane_sspp_atomic_update(struct drm_plane *plane)
pstate->pending = true;
is_rt_pipe = (dpu_crtc_get_client_type(crtc) != NRT_CLIENT);
+ pstate->needs_qos_remap |= (is_rt_pipe != pdpu->is_rt_pipe);
+ pdpu->is_rt_pipe = is_rt_pipe;
+
_dpu_plane_set_qos_ctrl(plane, false, DPU_PLANE_QOS_PANIC_CTRL);
DPU_DEBUG_PLANE(pdpu, "FB[%u] " DRM_RECT_FP_FMT "->crtc%u " DRM_RECT_FMT
@@ -1219,14 +1222,8 @@ static void dpu_plane_sspp_atomic_update(struct drm_plane *plane)
_dpu_plane_set_ot_limit(plane, crtc, &pipe_cfg);
}
- update_qos_remap = (is_rt_pipe != pdpu->is_rt_pipe) ||
- pstate->needs_qos_remap;
-
- if (update_qos_remap) {
- if (is_rt_pipe != pdpu->is_rt_pipe)
- pdpu->is_rt_pipe = is_rt_pipe;
- else if (pstate->needs_qos_remap)
- pstate->needs_qos_remap = false;
+ if (pstate->needs_qos_remap) {
+ pstate->needs_qos_remap = false;
_dpu_plane_set_qos_remap(plane);
}
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
index 73b3442e7467..396429e63756 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
@@ -496,6 +496,11 @@ static int _dpu_rm_reserve_dsc(struct dpu_rm *rm,
/* check if DSC required are allocated or not */
for (i = 0; i < num_dsc; i++) {
+ if (!rm->dsc_blks[i]) {
+ DPU_ERROR("DSC %d does not exist\n", i);
+ return -EIO;
+ }
+
if (global_state->dsc_to_enc_id[i]) {
DPU_ERROR("DSC %d is already allocated\n", i);
return -EIO;
@@ -543,8 +548,8 @@ static int _dpu_rm_populate_requirements(
{
reqs->topology = req_topology;
- DRM_DEBUG_KMS("num_lm: %d num_enc: %d num_intf: %d\n",
- reqs->topology.num_lm, reqs->topology.num_enc,
+ DRM_DEBUG_KMS("num_lm: %d num_dsc: %d num_intf: %d\n",
+ reqs->topology.num_lm, reqs->topology.num_dsc,
reqs->topology.num_intf);
return 0;
@@ -660,6 +665,11 @@ int dpu_rm_get_assigned_resources(struct dpu_rm *rm,
blks_size, enc_id);
break;
}
+ if (!hw_blks[i]) {
+ DPU_ERROR("Allocated resource %d unavailable to assign to enc %d\n",
+ type, enc_id);
+ break;
+ }
blks[num_blks++] = hw_blks[i];
}
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c
index 088ec990a2f2..2a5a68366582 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c
@@ -70,6 +70,8 @@ int dpu_writeback_init(struct drm_device *dev, struct drm_encoder *enc,
int rc = 0;
dpu_wb_conn = devm_kzalloc(dev->dev, sizeof(*dpu_wb_conn), GFP_KERNEL);
+ if (!dpu_wb_conn)
+ return -ENOMEM;
drm_connector_helper_add(&dpu_wb_conn->base.base, &dpu_wb_conn_helper_funcs);
diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_irq.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_irq.c
index 4d49f3ba6a96..ddcdd5e87853 100644
--- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_irq.c
+++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_irq.c
@@ -69,8 +69,7 @@ irqreturn_t mdp4_irq(struct msm_kms *kms)
struct mdp_kms *mdp_kms = to_mdp_kms(kms);
struct mdp4_kms *mdp4_kms = to_mdp4_kms(mdp_kms);
struct drm_device *dev = mdp4_kms->dev;
- struct msm_drm_private *priv = dev->dev_private;
- unsigned int id;
+ struct drm_crtc *crtc;
uint32_t status, enable;
enable = mdp4_read(mdp4_kms, REG_MDP4_INTR_ENABLE);
@@ -81,9 +80,9 @@ irqreturn_t mdp4_irq(struct msm_kms *kms)
mdp_dispatch_irqs(mdp_kms, status);
- for (id = 0; id < priv->num_crtcs; id++)
- if (status & mdp4_crtc_vblank(priv->crtcs[id]))
- drm_handle_vblank(dev, id);
+ drm_for_each_crtc(crtc, dev)
+ if (status & mdp4_crtc_vblank(crtc))
+ drm_crtc_handle_vblank(crtc);
return IRQ_HANDLED;
}
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c
index e86421c69bd1..86036dd4e1e8 100644
--- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c
@@ -1139,7 +1139,10 @@ static void mdp5_crtc_reset(struct drm_crtc *crtc)
if (crtc->state)
mdp5_crtc_destroy_state(crtc, crtc->state);
- __drm_atomic_helper_crtc_reset(crtc, &mdp5_cstate->base);
+ if (mdp5_cstate)
+ __drm_atomic_helper_crtc_reset(crtc, &mdp5_cstate->base);
+ else
+ __drm_atomic_helper_crtc_reset(crtc, NULL);
}
static const struct drm_crtc_funcs mdp5_crtc_no_lm_cursor_funcs = {
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_irq.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_irq.c
index 9b4c8d92ff32..43443a435d59 100644
--- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_irq.c
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_irq.c
@@ -82,8 +82,7 @@ irqreturn_t mdp5_irq(struct msm_kms *kms)
struct mdp_kms *mdp_kms = to_mdp_kms(kms);
struct mdp5_kms *mdp5_kms = to_mdp5_kms(mdp_kms);
struct drm_device *dev = mdp5_kms->dev;
- struct msm_drm_private *priv = dev->dev_private;
- unsigned int id;
+ struct drm_crtc *crtc;
uint32_t status, enable;
enable = mdp5_read(mdp5_kms, REG_MDP5_INTR_EN);
@@ -94,9 +93,9 @@ irqreturn_t mdp5_irq(struct msm_kms *kms)
mdp_dispatch_irqs(mdp_kms, status);
- for (id = 0; id < priv->num_crtcs; id++)
- if (status & mdp5_crtc_vblank(priv->crtcs[id]))
- drm_handle_vblank(dev, id);
+ drm_for_each_crtc(crtc, dev)
+ if (status & mdp5_crtc_vblank(crtc))
+ drm_crtc_handle_vblank(crtc);
return IRQ_HANDLED;
}
diff --git a/drivers/gpu/drm/msm/disp/msm_disp_snapshot.c b/drivers/gpu/drm/msm/disp/msm_disp_snapshot.c
index e75b97127c0d..b73031cd48e4 100644
--- a/drivers/gpu/drm/msm/disp/msm_disp_snapshot.c
+++ b/drivers/gpu/drm/msm/disp/msm_disp_snapshot.c
@@ -129,6 +129,9 @@ void msm_disp_snapshot_destroy(struct drm_device *drm_dev)
}
priv = drm_dev->dev_private;
+ if (!priv->kms)
+ return;
+
kms = priv->kms;
if (kms->dump_worker)
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index 7ff60e5ff325..bde1a7ce442f 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -122,61 +122,64 @@ struct dp_display_private {
struct msm_dp_desc {
phys_addr_t io_start;
+ unsigned int id;
unsigned int connector_type;
bool wide_bus_en;
};
-struct msm_dp_config {
- const struct msm_dp_desc *descs;
- size_t num_descs;
-};
-
static const struct msm_dp_desc sc7180_dp_descs[] = {
- [MSM_DP_CONTROLLER_0] = { .io_start = 0x0ae90000, .connector_type = DRM_MODE_CONNECTOR_DisplayPort },
-};
-
-static const struct msm_dp_config sc7180_dp_cfg = {
- .descs = sc7180_dp_descs,
- .num_descs = ARRAY_SIZE(sc7180_dp_descs),
+ { .io_start = 0x0ae90000, .id = MSM_DP_CONTROLLER_0, .connector_type = DRM_MODE_CONNECTOR_DisplayPort },
+ {}
};
static const struct msm_dp_desc sc7280_dp_descs[] = {
- [MSM_DP_CONTROLLER_0] = { .io_start = 0x0ae90000, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
- [MSM_DP_CONTROLLER_1] = { .io_start = 0x0aea0000, .connector_type = DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
-};
-
-static const struct msm_dp_config sc7280_dp_cfg = {
- .descs = sc7280_dp_descs,
- .num_descs = ARRAY_SIZE(sc7280_dp_descs),
+ { .io_start = 0x0ae90000, .id = MSM_DP_CONTROLLER_0, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
+ { .io_start = 0x0aea0000, .id = MSM_DP_CONTROLLER_1, .connector_type = DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
+ {}
};
static const struct msm_dp_desc sc8180x_dp_descs[] = {
- [MSM_DP_CONTROLLER_0] = { .io_start = 0x0ae90000, .connector_type = DRM_MODE_CONNECTOR_DisplayPort },
- [MSM_DP_CONTROLLER_1] = { .io_start = 0x0ae98000, .connector_type = DRM_MODE_CONNECTOR_DisplayPort },
- [MSM_DP_CONTROLLER_2] = { .io_start = 0x0ae9a000, .connector_type = DRM_MODE_CONNECTOR_eDP },
+ { .io_start = 0x0ae90000, .id = MSM_DP_CONTROLLER_0, .connector_type = DRM_MODE_CONNECTOR_DisplayPort },
+ { .io_start = 0x0ae98000, .id = MSM_DP_CONTROLLER_1, .connector_type = DRM_MODE_CONNECTOR_DisplayPort },
+ { .io_start = 0x0ae9a000, .id = MSM_DP_CONTROLLER_2, .connector_type = DRM_MODE_CONNECTOR_eDP },
+ {}
};
-static const struct msm_dp_config sc8180x_dp_cfg = {
- .descs = sc8180x_dp_descs,
- .num_descs = ARRAY_SIZE(sc8180x_dp_descs),
+static const struct msm_dp_desc sc8280xp_dp_descs[] = {
+ { .io_start = 0x0ae90000, .id = MSM_DP_CONTROLLER_0, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
+ { .io_start = 0x0ae98000, .id = MSM_DP_CONTROLLER_1, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
+ { .io_start = 0x0ae9a000, .id = MSM_DP_CONTROLLER_2, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
+ { .io_start = 0x0aea0000, .id = MSM_DP_CONTROLLER_3, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
+ { .io_start = 0x22090000, .id = MSM_DP_CONTROLLER_0, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
+ { .io_start = 0x22098000, .id = MSM_DP_CONTROLLER_1, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
+ { .io_start = 0x2209a000, .id = MSM_DP_CONTROLLER_2, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
+ { .io_start = 0x220a0000, .id = MSM_DP_CONTROLLER_3, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
+ {}
};
-static const struct msm_dp_desc sm8350_dp_descs[] = {
- [MSM_DP_CONTROLLER_0] = { .io_start = 0x0ae90000, .connector_type = DRM_MODE_CONNECTOR_DisplayPort },
+static const struct msm_dp_desc sc8280xp_edp_descs[] = {
+ { .io_start = 0x0ae9a000, .id = MSM_DP_CONTROLLER_2, .connector_type = DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
+ { .io_start = 0x0aea0000, .id = MSM_DP_CONTROLLER_3, .connector_type = DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
+ { .io_start = 0x2209a000, .id = MSM_DP_CONTROLLER_2, .connector_type = DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
+ { .io_start = 0x220a0000, .id = MSM_DP_CONTROLLER_3, .connector_type = DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
+ {}
};
-static const struct msm_dp_config sm8350_dp_cfg = {
- .descs = sm8350_dp_descs,
- .num_descs = ARRAY_SIZE(sm8350_dp_descs),
+static const struct msm_dp_desc sm8350_dp_descs[] = {
+ { .io_start = 0x0ae90000, .id = MSM_DP_CONTROLLER_0, .connector_type = DRM_MODE_CONNECTOR_DisplayPort },
+ {}
};
static const struct of_device_id dp_dt_match[] = {
- { .compatible = "qcom,sc7180-dp", .data = &sc7180_dp_cfg },
- { .compatible = "qcom,sc7280-dp", .data = &sc7280_dp_cfg },
- { .compatible = "qcom,sc7280-edp", .data = &sc7280_dp_cfg },
- { .compatible = "qcom,sc8180x-dp", .data = &sc8180x_dp_cfg },
- { .compatible = "qcom,sc8180x-edp", .data = &sc8180x_dp_cfg },
- { .compatible = "qcom,sm8350-dp", .data = &sm8350_dp_cfg },
+ { .compatible = "qcom,sc7180-dp", .data = &sc7180_dp_descs },
+ { .compatible = "qcom,sc7280-dp", .data = &sc7280_dp_descs },
+ { .compatible = "qcom,sc7280-edp", .data = &sc7280_dp_descs },
+ { .compatible = "qcom,sc8180x-dp", .data = &sc8180x_dp_descs },
+ { .compatible = "qcom,sc8180x-edp", .data = &sc8180x_dp_descs },
+ { .compatible = "qcom,sc8280xp-dp", .data = &sc8280xp_dp_descs },
+ { .compatible = "qcom,sc8280xp-edp", .data = &sc8280xp_edp_descs },
+ { .compatible = "qcom,sdm845-dp", .data = &sc7180_dp_descs },
+ { .compatible = "qcom,sm8350-dp", .data = &sm8350_dp_descs },
{}
};
@@ -390,6 +393,10 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp)
struct edid *edid;
dp->panel->max_dp_lanes = dp->parser->max_dp_lanes;
+ dp->panel->max_dp_link_rate = dp->parser->max_dp_link_rate;
+
+ drm_dbg_dp(dp->drm_dev, "max_lanes=%d max_link_rate=%d\n",
+ dp->panel->max_dp_lanes, dp->panel->max_dp_link_rate);
rc = dp_panel_read_sink_caps(dp->panel, dp->dp_display.connector);
if (rc)
@@ -607,8 +614,10 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data)
}
/* enable HDP irq_hpd/replug interrupt */
- dp_catalog_hpd_config_intr(dp->catalog,
- DP_DP_IRQ_HPD_INT_MASK | DP_DP_HPD_REPLUG_INT_MASK, true);
+ if (dp->dp_display.internal_hpd)
+ dp_catalog_hpd_config_intr(dp->catalog,
+ DP_DP_IRQ_HPD_INT_MASK | DP_DP_HPD_REPLUG_INT_MASK,
+ true);
drm_dbg_dp(dp->drm_dev, "After, type=%d hpd_state=%d\n",
dp->dp_display.connector_type, state);
@@ -648,8 +657,10 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data)
dp->dp_display.connector_type, state);
/* disable irq_hpd/replug interrupts */
- dp_catalog_hpd_config_intr(dp->catalog,
- DP_DP_IRQ_HPD_INT_MASK | DP_DP_HPD_REPLUG_INT_MASK, false);
+ if (dp->dp_display.internal_hpd)
+ dp_catalog_hpd_config_intr(dp->catalog,
+ DP_DP_IRQ_HPD_INT_MASK | DP_DP_HPD_REPLUG_INT_MASK,
+ false);
/* unplugged, no more irq_hpd handle */
dp_del_event(dp, EV_IRQ_HPD_INT);
@@ -675,7 +686,8 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data)
}
/* disable HPD plug interrupts */
- dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK, false);
+ if (dp->dp_display.internal_hpd)
+ dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK, false);
/*
* We don't need separate work for disconnect as
@@ -693,7 +705,7 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data)
dp_display_handle_plugged_change(&dp->dp_display, false);
/* enable HDP plug interrupt to prepare for next plugin */
- if (!dp->dp_display.is_edp)
+ if (dp->dp_display.internal_hpd)
dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK, true);
drm_dbg_dp(dp->drm_dev, "After, type=%d hpd_state=%d\n",
@@ -1078,8 +1090,8 @@ static void dp_display_config_hpd(struct dp_display_private *dp)
dp_display_host_init(dp);
dp_catalog_ctrl_hpd_config(dp->catalog);
- /* Enable plug and unplug interrupts only for external DisplayPort */
- if (!dp->dp_display.is_edp)
+ /* Enable plug and unplug interrupts only if requested */
+ if (dp->dp_display.internal_hpd)
dp_catalog_hpd_config_intr(dp->catalog,
DP_DP_HPD_PLUG_INT_MASK |
DP_DP_HPD_UNPLUG_INT_MASK,
@@ -1262,10 +1274,9 @@ int dp_display_request_irq(struct msm_dp *dp_display)
return 0;
}
-static const struct msm_dp_desc *dp_display_get_desc(struct platform_device *pdev,
- unsigned int *id)
+static const struct msm_dp_desc *dp_display_get_desc(struct platform_device *pdev)
{
- const struct msm_dp_config *cfg = of_device_get_match_data(&pdev->dev);
+ const struct msm_dp_desc *descs = of_device_get_match_data(&pdev->dev);
struct resource *res;
int i;
@@ -1273,11 +1284,9 @@ static const struct msm_dp_desc *dp_display_get_desc(struct platform_device *pde
if (!res)
return NULL;
- for (i = 0; i < cfg->num_descs; i++) {
- if (cfg->descs[i].io_start == res->start) {
- *id = i;
- return &cfg->descs[i];
- }
+ for (i = 0; i < descs[i].io_start; i++) {
+ if (descs[i].io_start == res->start)
+ return &descs[i];
}
dev_err(&pdev->dev, "unknown displayport instance\n");
@@ -1299,12 +1308,13 @@ static int dp_display_probe(struct platform_device *pdev)
if (!dp)
return -ENOMEM;
- desc = dp_display_get_desc(pdev, &dp->id);
+ desc = dp_display_get_desc(pdev);
if (!desc)
return -EINVAL;
dp->pdev = pdev;
dp->name = "drm_dp";
+ dp->id = desc->id;
dp->dp_display.connector_type = desc->connector_type;
dp->wide_bus_en = desc->wide_bus_en;
dp->dp_display.is_edp =
@@ -1373,8 +1383,7 @@ static int dp_pm_resume(struct device *dev)
dp_catalog_ctrl_hpd_config(dp->catalog);
-
- if (!dp->dp_display.is_edp)
+ if (dp->dp_display.internal_hpd)
dp_catalog_hpd_config_intr(dp->catalog,
DP_DP_HPD_PLUG_INT_MASK |
DP_DP_HPD_UNPLUG_INT_MASK,
@@ -1497,7 +1506,7 @@ void msm_dp_irq_postinstall(struct msm_dp *dp_display)
dp = container_of(dp_display, struct dp_display_private, dp_display);
if (!dp_display->is_edp)
- dp_add_event(dp, EV_HPD_INIT_SETUP, 0, 100);
+ dp_add_event(dp, EV_HPD_INIT_SETUP, 0, 0);
}
bool msm_dp_wide_bus_available(const struct msm_dp *dp_display)
@@ -1771,3 +1780,41 @@ void dp_bridge_mode_set(struct drm_bridge *drm_bridge,
dp_display->dp_mode.h_active_low =
!!(dp_display->dp_mode.drm_mode.flags & DRM_MODE_FLAG_NHSYNC);
}
+
+void dp_bridge_hpd_enable(struct drm_bridge *bridge)
+{
+ struct msm_dp_bridge *dp_bridge = to_dp_bridge(bridge);
+ struct msm_dp *dp_display = dp_bridge->dp_display;
+
+ dp_display->internal_hpd = true;
+}
+
+void dp_bridge_hpd_disable(struct drm_bridge *bridge)
+{
+ struct msm_dp_bridge *dp_bridge = to_dp_bridge(bridge);
+ struct msm_dp *dp_display = dp_bridge->dp_display;
+
+ dp_display->internal_hpd = false;
+}
+
+void dp_bridge_hpd_notify(struct drm_bridge *bridge,
+ enum drm_connector_status status)
+{
+ struct msm_dp_bridge *dp_bridge = to_dp_bridge(bridge);
+ struct msm_dp *dp_display = dp_bridge->dp_display;
+ struct dp_display_private *dp = container_of(dp_display, struct dp_display_private, dp_display);
+
+ /* Without next_bridge interrupts are handled by the DP core directly */
+ if (dp_display->internal_hpd)
+ return;
+
+ if (!dp->core_initialized) {
+ drm_dbg_dp(dp->drm_dev, "not initialized\n");
+ return;
+ }
+
+ if (!dp_display->is_connected && status == connector_status_connected)
+ dp_add_event(dp, EV_HPD_PLUG_INT, 0, 0);
+ else if (dp_display->is_connected && status == connector_status_disconnected)
+ dp_add_event(dp, EV_HPD_UNPLUG_INT, 0, 0);
+}
diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h
index dcedf021f7fe..371337d0fae2 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.h
+++ b/drivers/gpu/drm/msm/dp/dp_display.h
@@ -21,6 +21,7 @@ struct msm_dp {
bool power_on;
unsigned int connector_type;
bool is_edp;
+ bool internal_hpd;
hdmi_codec_plugged_cb plugged_cb;
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
index 6db82f9b03af..275370f21115 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c
@@ -102,6 +102,9 @@ static const struct drm_bridge_funcs dp_bridge_ops = {
.get_modes = dp_bridge_get_modes,
.detect = dp_bridge_detect,
.atomic_check = dp_bridge_atomic_check,
+ .hpd_enable = dp_bridge_hpd_enable,
+ .hpd_disable = dp_bridge_hpd_disable,
+ .hpd_notify = dp_bridge_hpd_notify,
};
struct drm_bridge *dp_bridge_init(struct msm_dp *dp_display, struct drm_device *dev,
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.h b/drivers/gpu/drm/msm/dp/dp_drm.h
index 82035dbb0578..250f7c66201f 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.h
+++ b/drivers/gpu/drm/msm/dp/dp_drm.h
@@ -32,5 +32,9 @@ enum drm_mode_status dp_bridge_mode_valid(struct drm_bridge *bridge,
void dp_bridge_mode_set(struct drm_bridge *drm_bridge,
const struct drm_display_mode *mode,
const struct drm_display_mode *adjusted_mode);
+void dp_bridge_hpd_enable(struct drm_bridge *bridge);
+void dp_bridge_hpd_disable(struct drm_bridge *bridge);
+void dp_bridge_hpd_notify(struct drm_bridge *bridge,
+ enum drm_connector_status status);
#endif /* _DP_DRM_H_ */
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c
index 5149cebc93f6..1800d8963f8a 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.c
+++ b/drivers/gpu/drm/msm/dp/dp_panel.c
@@ -75,12 +75,13 @@ static int dp_panel_read_dpcd(struct dp_panel *dp_panel)
link_info->rate = drm_dp_bw_code_to_link_rate(dpcd[DP_MAX_LINK_RATE]);
link_info->num_lanes = dpcd[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK;
+ /* Limit data lanes from data-lanes of endpoint property of dtsi */
if (link_info->num_lanes > dp_panel->max_dp_lanes)
link_info->num_lanes = dp_panel->max_dp_lanes;
- /* Limit support upto HBR2 until HBR3 support is added */
- if (link_info->rate >= (drm_dp_bw_code_to_link_rate(DP_LINK_BW_5_4)))
- link_info->rate = drm_dp_bw_code_to_link_rate(DP_LINK_BW_5_4);
+ /* Limit link rate from link-frequencies of endpoint property of dtsi */
+ if (link_info->rate > dp_panel->max_dp_link_rate)
+ link_info->rate = dp_panel->max_dp_link_rate;
drm_dbg_dp(panel->drm_dev, "version: %d.%d\n", major, minor);
drm_dbg_dp(panel->drm_dev, "link_rate=%d\n", link_info->rate);
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h
index d861197ac1c8..f04d0210b5cd 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.h
+++ b/drivers/gpu/drm/msm/dp/dp_panel.h
@@ -50,6 +50,7 @@ struct dp_panel {
u32 vic;
u32 max_dp_lanes;
+ u32 max_dp_link_rate;
u32 max_bw_code;
};
diff --git a/drivers/gpu/drm/msm/dp/dp_parser.c b/drivers/gpu/drm/msm/dp/dp_parser.c
index dcbe893d66d7..7032dcc8842b 100644
--- a/drivers/gpu/drm/msm/dp/dp_parser.c
+++ b/drivers/gpu/drm/msm/dp/dp_parser.c
@@ -91,19 +91,53 @@ static int dp_parser_ctrl_res(struct dp_parser *parser)
return 0;
}
+static u32 dp_parser_link_frequencies(struct device_node *of_node)
+{
+ struct device_node *endpoint;
+ u64 frequency = 0;
+ int cnt;
+
+ endpoint = of_graph_get_endpoint_by_regs(of_node, 1, 0); /* port@1 */
+ if (!endpoint)
+ return 0;
+
+ cnt = of_property_count_u64_elems(endpoint, "link-frequencies");
+
+ if (cnt > 0)
+ of_property_read_u64_index(endpoint, "link-frequencies",
+ cnt - 1, &frequency);
+ of_node_put(endpoint);
+
+ do_div(frequency,
+ 10 * /* from symbol rate to link rate */
+ 1000); /* kbytes */
+
+ return frequency;
+}
+
static int dp_parser_misc(struct dp_parser *parser)
{
struct device_node *of_node = parser->pdev->dev.of_node;
- int len;
-
- len = drm_of_get_data_lanes_count(of_node, 1, DP_MAX_NUM_DP_LANES);
- if (len < 0) {
- DRM_WARN("Invalid property \"data-lanes\", default max DP lanes = %d\n",
- DP_MAX_NUM_DP_LANES);
- len = DP_MAX_NUM_DP_LANES;
+ int cnt;
+
+ /*
+ * data-lanes is the property of dp_out endpoint
+ */
+ cnt = drm_of_get_data_lanes_count_ep(of_node, 1, 0, 1, DP_MAX_NUM_DP_LANES);
+ if (cnt < 0) {
+ /* legacy code, data-lanes is the property of mdss_dp node */
+ cnt = drm_of_get_data_lanes_count(of_node, 1, DP_MAX_NUM_DP_LANES);
}
- parser->max_dp_lanes = len;
+ if (cnt > 0)
+ parser->max_dp_lanes = cnt;
+ else
+ parser->max_dp_lanes = DP_MAX_NUM_DP_LANES; /* 4 lanes */
+
+ parser->max_dp_link_rate = dp_parser_link_frequencies(of_node);
+ if (!parser->max_dp_link_rate)
+ parser->max_dp_link_rate = DP_LINK_RATE_HBR2;
+
return 0;
}
diff --git a/drivers/gpu/drm/msm/dp/dp_parser.h b/drivers/gpu/drm/msm/dp/dp_parser.h
index d30ab773db46..1f068626d445 100644
--- a/drivers/gpu/drm/msm/dp/dp_parser.h
+++ b/drivers/gpu/drm/msm/dp/dp_parser.h
@@ -15,6 +15,7 @@
#define DP_LABEL "MDSS DP DISPLAY"
#define DP_MAX_PIXEL_CLK_KHZ 675000
#define DP_MAX_NUM_DP_LANES 4
+#define DP_LINK_RATE_HBR2 540000 /* kbytes */
enum dp_pm_type {
DP_CORE_PM,
@@ -119,6 +120,7 @@ struct dp_parser {
struct dp_io io;
struct dp_display_data disp_data;
u32 max_dp_lanes;
+ u32 max_dp_link_rate;
struct drm_bridge *next_bridge;
int (*parse)(struct dp_parser *parser);
diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h
index 2a96b4fe7839..bd3763a5d723 100644
--- a/drivers/gpu/drm/msm/dsi/dsi.h
+++ b/drivers/gpu/drm/msm/dsi/dsi.h
@@ -118,6 +118,8 @@ int dsi_link_clk_enable_6g(struct msm_dsi_host *msm_host);
int dsi_link_clk_enable_v2(struct msm_dsi_host *msm_host);
void dsi_link_clk_disable_6g(struct msm_dsi_host *msm_host);
void dsi_link_clk_disable_v2(struct msm_dsi_host *msm_host);
+unsigned long dsi_byte_clk_get_rate(struct mipi_dsi_host *host, bool is_bonded_dsi,
+ const struct drm_display_mode *mode);
int dsi_tx_buf_alloc_6g(struct msm_dsi_host *msm_host, int size);
int dsi_tx_buf_alloc_v2(struct msm_dsi_host *msm_host, int size);
void *dsi_tx_buf_get_6g(struct msm_dsi_host *msm_host);
@@ -139,6 +141,7 @@ struct msm_dsi_phy_shared_timings {
u32 clk_post;
u32 clk_pre;
bool clk_pre_inc_by_2;
+ bool byte_intf_clk_div_2;
};
struct msm_dsi_phy_clk_request {
diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.c b/drivers/gpu/drm/msm/dsi/dsi_cfg.c
index 7e97c239ed48..6d21f0b33411 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_cfg.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.c
@@ -181,6 +181,20 @@ static const struct msm_dsi_config sdm845_dsi_cfg = {
.num_dsi = 2,
};
+static const struct regulator_bulk_data sm8550_dsi_regulators[] = {
+ { .supply = "vdda", .init_load_uA = 16800 }, /* 1.2 V */
+};
+
+static const struct msm_dsi_config sm8550_dsi_cfg = {
+ .io_offset = DSI_6G_REG_SHIFT,
+ .regulator_data = sm8550_dsi_regulators,
+ .num_regulators = ARRAY_SIZE(sm8550_dsi_regulators),
+ .bus_clk_names = dsi_sdm845_bus_clk_names,
+ .num_bus_clks = ARRAY_SIZE(dsi_sdm845_bus_clk_names),
+ .io_start = { 0xae94000, 0xae96000 },
+ .num_dsi = 2,
+};
+
static const struct regulator_bulk_data sc7180_dsi_regulators[] = {
{ .supply = "vdda", .init_load_uA = 21800 }, /* 1.2 V */
};
@@ -209,8 +223,8 @@ static const struct msm_dsi_config sc7280_dsi_cfg = {
.num_regulators = ARRAY_SIZE(sc7280_dsi_regulators),
.bus_clk_names = dsi_sc7280_bus_clk_names,
.num_bus_clks = ARRAY_SIZE(dsi_sc7280_bus_clk_names),
- .io_start = { 0xae94000 },
- .num_dsi = 1,
+ .io_start = { 0xae94000, 0xae96000 },
+ .num_dsi = 2,
};
static const char * const dsi_qcm2290_bus_clk_names[] = {
@@ -300,6 +314,10 @@ static const struct msm_dsi_cfg_handler dsi_cfg_handlers[] = {
&sc7180_dsi_cfg, &msm_dsi_6g_v2_host_ops},
{MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_5_0,
&sc7280_dsi_cfg, &msm_dsi_6g_v2_host_ops},
+ {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_6_0,
+ &sdm845_dsi_cfg, &msm_dsi_6g_v2_host_ops},
+ {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_7_0,
+ &sm8550_dsi_cfg, &msm_dsi_6g_v2_host_ops},
};
const struct msm_dsi_cfg_handler *msm_dsi_cfg_get(u32 major, u32 minor)
diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.h b/drivers/gpu/drm/msm/dsi/dsi_cfg.h
index 8f04e685a74e..44be4a88aa83 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_cfg.h
+++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.h
@@ -25,6 +25,8 @@
#define MSM_DSI_6G_VER_MINOR_V2_4_0 0x20040000
#define MSM_DSI_6G_VER_MINOR_V2_4_1 0x20040001
#define MSM_DSI_6G_VER_MINOR_V2_5_0 0x20050000
+#define MSM_DSI_6G_VER_MINOR_V2_6_0 0x20060000
+#define MSM_DSI_6G_VER_MINOR_V2_7_0 0x20070000
#define MSM_DSI_V2_VER_MINOR_8064 0x0
diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c
index 89aadd3b3202..18fa30e1e858 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_host.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
@@ -122,6 +122,7 @@ struct msm_dsi_host {
struct clk *byte_intf_clk;
unsigned long byte_clk_rate;
+ unsigned long byte_intf_clk_rate;
unsigned long pixel_clk_rate;
unsigned long esc_clk_rate;
@@ -398,7 +399,6 @@ int msm_dsi_runtime_resume(struct device *dev)
int dsi_link_clk_set_rate_6g(struct msm_dsi_host *msm_host)
{
- unsigned long byte_intf_rate;
int ret;
DBG("Set clk rates: pclk=%d, byteclk=%lu",
@@ -418,13 +418,7 @@ int dsi_link_clk_set_rate_6g(struct msm_dsi_host *msm_host)
}
if (msm_host->byte_intf_clk) {
- /* For CPHY, byte_intf_clk is same as byte_clk */
- if (msm_host->cphy_mode)
- byte_intf_rate = msm_host->byte_clk_rate;
- else
- byte_intf_rate = msm_host->byte_clk_rate / 2;
-
- ret = clk_set_rate(msm_host->byte_intf_clk, byte_intf_rate);
+ ret = clk_set_rate(msm_host->byte_intf_clk, msm_host->byte_intf_clk_rate);
if (ret) {
pr_err("%s: Failed to set rate byte intf clk, %d\n",
__func__, ret);
@@ -570,9 +564,8 @@ void dsi_link_clk_disable_v2(struct msm_dsi_host *msm_host)
clk_disable_unprepare(msm_host->byte_clk);
}
-static unsigned long dsi_get_pclk_rate(struct msm_dsi_host *msm_host, bool is_bonded_dsi)
+static unsigned long dsi_get_pclk_rate(const struct drm_display_mode *mode, bool is_bonded_dsi)
{
- struct drm_display_mode *mode = msm_host->mode;
unsigned long pclk_rate;
pclk_rate = mode->clock * 1000;
@@ -589,11 +582,13 @@ static unsigned long dsi_get_pclk_rate(struct msm_dsi_host *msm_host, bool is_bo
return pclk_rate;
}
-static void dsi_calc_pclk(struct msm_dsi_host *msm_host, bool is_bonded_dsi)
+unsigned long dsi_byte_clk_get_rate(struct mipi_dsi_host *host, bool is_bonded_dsi,
+ const struct drm_display_mode *mode)
{
+ struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
u8 lanes = msm_host->lanes;
u32 bpp = dsi_get_bpp(msm_host->format);
- unsigned long pclk_rate = dsi_get_pclk_rate(msm_host, is_bonded_dsi);
+ unsigned long pclk_rate = dsi_get_pclk_rate(mode, is_bonded_dsi);
u64 pclk_bpp = (u64)pclk_rate * bpp;
if (lanes == 0) {
@@ -607,8 +602,14 @@ static void dsi_calc_pclk(struct msm_dsi_host *msm_host, bool is_bonded_dsi)
else
do_div(pclk_bpp, (8 * lanes));
- msm_host->pixel_clk_rate = pclk_rate;
- msm_host->byte_clk_rate = pclk_bpp;
+ return pclk_bpp;
+}
+
+static void dsi_calc_pclk(struct msm_dsi_host *msm_host, bool is_bonded_dsi)
+{
+ msm_host->pixel_clk_rate = dsi_get_pclk_rate(msm_host->mode, is_bonded_dsi);
+ msm_host->byte_clk_rate = dsi_byte_clk_get_rate(&msm_host->base, is_bonded_dsi,
+ msm_host->mode);
DBG("pclk=%lu, bclk=%lu", msm_host->pixel_clk_rate,
msm_host->byte_clk_rate);
@@ -636,7 +637,7 @@ int dsi_calc_clk_rate_v2(struct msm_dsi_host *msm_host, bool is_bonded_dsi)
dsi_calc_pclk(msm_host, is_bonded_dsi);
- pclk_bpp = (u64)dsi_get_pclk_rate(msm_host, is_bonded_dsi) * bpp;
+ pclk_bpp = (u64)dsi_get_pclk_rate(msm_host->mode, is_bonded_dsi) * bpp;
do_div(pclk_bpp, 8);
msm_host->src_clk_rate = pclk_bpp;
@@ -853,11 +854,12 @@ static void dsi_update_dsc_timing(struct msm_dsi_host *msm_host, bool is_cmd_mod
*/
slice_per_intf = DIV_ROUND_UP(hdisplay, dsc->slice_width);
- /* If slice_per_pkt is greater than slice_per_intf
+ /*
+ * If slice_count is greater than slice_per_intf
* then default to 1. This can happen during partial
* update.
*/
- if (slice_per_intf > dsc->slice_count)
+ if (dsc->slice_count > slice_per_intf)
dsc->slice_count = 1;
total_bytes_per_intf = dsc->slice_chunk_size * slice_per_intf;
@@ -987,7 +989,7 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_bonded_dsi)
if (!msm_host->dsc)
wc = hdisplay * dsi_get_bpp(msm_host->format) / 8 + 1;
else
- wc = mode->hdisplay / 2 + 1;
+ wc = msm_host->dsc->slice_chunk_size * msm_host->dsc->slice_count + 1;
dsi_write(msm_host, REG_DSI_CMD_MDP_STREAM0_CTRL,
DSI_CMD_MDP_STREAM0_CTRL_WORD_COUNT(wc) |
@@ -1883,8 +1885,7 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi)
msm_host = devm_kzalloc(&pdev->dev, sizeof(*msm_host), GFP_KERNEL);
if (!msm_host) {
- ret = -ENOMEM;
- goto fail;
+ return -ENOMEM;
}
msm_host->pdev = pdev;
@@ -1893,31 +1894,28 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi)
ret = dsi_host_parse_dt(msm_host);
if (ret) {
pr_err("%s: failed to parse dt\n", __func__);
- goto fail;
+ return ret;
}
msm_host->ctrl_base = msm_ioremap_size(pdev, "dsi_ctrl", &msm_host->ctrl_size);
if (IS_ERR(msm_host->ctrl_base)) {
pr_err("%s: unable to map Dsi ctrl base\n", __func__);
- ret = PTR_ERR(msm_host->ctrl_base);
- goto fail;
+ return PTR_ERR(msm_host->ctrl_base);
}
pm_runtime_enable(&pdev->dev);
msm_host->cfg_hnd = dsi_get_config(msm_host);
if (!msm_host->cfg_hnd) {
- ret = -EINVAL;
pr_err("%s: get config failed\n", __func__);
- goto fail;
+ return -EINVAL;
}
cfg = msm_host->cfg_hnd->cfg;
msm_host->id = dsi_host_get_id(msm_host);
if (msm_host->id < 0) {
- ret = msm_host->id;
pr_err("%s: unable to identify DSI host index\n", __func__);
- goto fail;
+ return msm_host->id;
}
/* fixup base address by io offset */
@@ -1927,19 +1925,18 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi)
cfg->regulator_data,
&msm_host->supplies);
if (ret)
- goto fail;
+ return ret;
ret = dsi_clk_init(msm_host);
if (ret) {
pr_err("%s: unable to initialize dsi clks\n", __func__);
- goto fail;
+ return ret;
}
msm_host->rx_buf = devm_kzalloc(&pdev->dev, SZ_4K, GFP_KERNEL);
if (!msm_host->rx_buf) {
- ret = -ENOMEM;
pr_err("%s: alloc rx temp buf failed\n", __func__);
- goto fail;
+ return -ENOMEM;
}
ret = devm_pm_opp_set_clkname(&pdev->dev, "byte");
@@ -1977,15 +1974,15 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi)
/* setup workqueue */
msm_host->workqueue = alloc_ordered_workqueue("dsi_drm_work", 0);
+ if (!msm_host->workqueue)
+ return -ENOMEM;
+
INIT_WORK(&msm_host->err_work, dsi_err_worker);
msm_dsi->id = msm_host->id;
DBG("Dsi Host %d initialized", msm_host->id);
return 0;
-
-fail:
- return ret;
}
void msm_dsi_host_destroy(struct mipi_dsi_host *host)
@@ -2391,6 +2388,10 @@ int msm_dsi_host_power_on(struct mipi_dsi_host *host,
goto unlock_ret;
}
+ msm_host->byte_intf_clk_rate = msm_host->byte_clk_rate;
+ if (phy_shared_timings->byte_intf_clk_div_2)
+ msm_host->byte_intf_clk_rate /= 2;
+
msm_dsi_sfpb_config(msm_host, true);
ret = regulator_bulk_enable(msm_host->cfg_hnd->cfg->num_regulators,
diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c
index 3a1417397283..1bbac72dad35 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
@@ -450,6 +450,26 @@ static enum drm_mode_status dsi_mgr_bridge_mode_valid(struct drm_bridge *bridge,
int id = dsi_mgr_bridge_get_id(bridge);
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
struct mipi_dsi_host *host = msm_dsi->host;
+ struct platform_device *pdev = msm_dsi->pdev;
+ struct dev_pm_opp *opp;
+ unsigned long byte_clk_rate;
+
+ byte_clk_rate = dsi_byte_clk_get_rate(host, IS_BONDED_DSI(), mode);
+
+ opp = dev_pm_opp_find_freq_ceil(&pdev->dev, &byte_clk_rate);
+ if (!IS_ERR(opp)) {
+ dev_pm_opp_put(opp);
+ } else if (PTR_ERR(opp) == -ERANGE) {
+ /*
+ * An empty table is created by devm_pm_opp_set_clkname() even
+ * if there is none. Thus find_freq_ceil will still return
+ * -ERANGE in such case.
+ */
+ if (dev_pm_opp_get_opp_count(&pdev->dev) != 0)
+ return MODE_CLOCK_RANGE;
+ } else {
+ return MODE_ERROR;
+ }
return msm_dsi_host_check_dsc(host, mode);
}
diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
index ee6051367679..bb09cbe8ff86 100644
--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
+++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
@@ -350,6 +350,8 @@ int msm_dsi_dphy_timing_calc_v3(struct msm_dsi_dphy_timing *timing,
timing->shared_timings.clk_pre_inc_by_2 = 0;
}
+ timing->shared_timings.byte_intf_clk_div_2 = true;
+
timing->ta_go = 3;
timing->ta_sure = 0;
timing->ta_get = 4;
@@ -454,6 +456,8 @@ int msm_dsi_dphy_timing_calc_v4(struct msm_dsi_dphy_timing *timing,
tmax = 255;
timing->shared_timings.clk_pre = DIV_ROUND_UP((tmax - tmin) * 125, 10000) + tmin;
+ timing->shared_timings.byte_intf_clk_div_2 = true;
+
DBG("%d, %d, %d, %d, %d, %d, %d, %d, %d, %d",
timing->shared_timings.clk_pre, timing->shared_timings.clk_post,
timing->clk_zero, timing->clk_trail, timing->clk_prepare, timing->hs_exit,
@@ -569,6 +573,14 @@ static const struct of_device_id dsi_phy_dt_match[] = {
.data = &dsi_phy_7nm_8150_cfgs },
{ .compatible = "qcom,sc7280-dsi-phy-7nm",
.data = &dsi_phy_7nm_7280_cfgs },
+ { .compatible = "qcom,sm6375-dsi-phy-7nm",
+ .data = &dsi_phy_7nm_6375_cfgs },
+ { .compatible = "qcom,sm8350-dsi-phy-5nm",
+ .data = &dsi_phy_5nm_8350_cfgs },
+ { .compatible = "qcom,sm8450-dsi-phy-5nm",
+ .data = &dsi_phy_5nm_8450_cfgs },
+ { .compatible = "qcom,sm8550-dsi-phy-4nm",
+ .data = &dsi_phy_4nm_8550_cfgs },
#endif
{}
};
diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h
index 1096afedd616..7137a17ae523 100644
--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h
+++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h
@@ -55,8 +55,12 @@ extern const struct msm_dsi_phy_cfg dsi_phy_14nm_8953_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_10nm_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_10nm_8998_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_7nm_cfgs;
+extern const struct msm_dsi_phy_cfg dsi_phy_7nm_6375_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_7nm_8150_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_7nm_7280_cfgs;
+extern const struct msm_dsi_phy_cfg dsi_phy_5nm_8350_cfgs;
+extern const struct msm_dsi_phy_cfg dsi_phy_5nm_8450_cfgs;
+extern const struct msm_dsi_phy_cfg dsi_phy_4nm_8550_cfgs;
struct msm_dsi_dphy_timing {
u32 clk_zero;
diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c
index 9e7fa7d88ead..3b1ed02f644d 100644
--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c
+++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c
@@ -39,8 +39,16 @@
#define VCO_REF_CLK_RATE 19200000
#define FRAC_BITS 18
+/* Hardware is pre V4.1 */
+#define DSI_PHY_7NM_QUIRK_PRE_V4_1 BIT(0)
/* Hardware is V4.1 */
-#define DSI_PHY_7NM_QUIRK_V4_1 BIT(0)
+#define DSI_PHY_7NM_QUIRK_V4_1 BIT(1)
+/* Hardware is V4.2 */
+#define DSI_PHY_7NM_QUIRK_V4_2 BIT(2)
+/* Hardware is V4.3 */
+#define DSI_PHY_7NM_QUIRK_V4_3 BIT(3)
+/* Hardware is V5.2 */
+#define DSI_PHY_7NM_QUIRK_V5_2 BIT(4)
struct dsi_pll_config {
bool enable_ssc;
@@ -116,16 +124,27 @@ static void dsi_pll_calc_dec_frac(struct dsi_pll_7nm *pll, struct dsi_pll_config
dec_multiple = div_u64(pll_freq * multiplier, divider);
dec = div_u64_rem(dec_multiple, multiplier, &frac);
- if (!(pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_1))
+ if (pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_PRE_V4_1)
config->pll_clock_inverters = 0x28;
- else if (pll_freq <= 1000000000ULL)
- config->pll_clock_inverters = 0xa0;
- else if (pll_freq <= 2500000000ULL)
- config->pll_clock_inverters = 0x20;
- else if (pll_freq <= 3020000000ULL)
- config->pll_clock_inverters = 0x00;
- else
- config->pll_clock_inverters = 0x40;
+ else if ((pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V5_2)) {
+ if (pll_freq <= 1300000000ULL)
+ config->pll_clock_inverters = 0xa0;
+ else if (pll_freq <= 2500000000ULL)
+ config->pll_clock_inverters = 0x20;
+ else if (pll_freq <= 4000000000ULL)
+ config->pll_clock_inverters = 0x00;
+ else
+ config->pll_clock_inverters = 0x40;
+ } else {
+ if (pll_freq <= 1000000000ULL)
+ config->pll_clock_inverters = 0xa0;
+ else if (pll_freq <= 2500000000ULL)
+ config->pll_clock_inverters = 0x20;
+ else if (pll_freq <= 3020000000ULL)
+ config->pll_clock_inverters = 0x00;
+ else
+ config->pll_clock_inverters = 0x40;
+ }
config->decimal_div_start = dec;
config->frac_div_start = frac;
@@ -197,16 +216,32 @@ static void dsi_pll_config_hzindep_reg(struct dsi_pll_7nm *pll)
void __iomem *base = pll->phy->pll_base;
u8 analog_controls_five_1 = 0x01, vco_config_1 = 0x00;
- if (pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_1) {
+ if (!(pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_PRE_V4_1))
if (pll->vco_current_rate >= 3100000000ULL)
analog_controls_five_1 = 0x03;
+ if (pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_1) {
if (pll->vco_current_rate < 1520000000ULL)
vco_config_1 = 0x08;
else if (pll->vco_current_rate < 2990000000ULL)
vco_config_1 = 0x01;
}
+ if ((pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_2) ||
+ (pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_3)) {
+ if (pll->vco_current_rate < 1520000000ULL)
+ vco_config_1 = 0x08;
+ else if (pll->vco_current_rate >= 2990000000ULL)
+ vco_config_1 = 0x01;
+ }
+
+ if ((pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V5_2)) {
+ if (pll->vco_current_rate < 1557000000ULL)
+ vco_config_1 = 0x08;
+ else
+ vco_config_1 = 0x01;
+ }
+
dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_ANALOG_CONTROLS_FIVE_1,
analog_controls_five_1);
dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_VCO_CONFIG_1, vco_config_1);
@@ -231,9 +266,9 @@ static void dsi_pll_config_hzindep_reg(struct dsi_pll_7nm *pll)
dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_PFILT, 0x2f);
dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_IFILT, 0x2a);
dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_IFILT,
- pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_1 ? 0x3f : 0x22);
+ !(pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_PRE_V4_1) ? 0x3f : 0x22);
- if (pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_1) {
+ if (!(pll->phy->cfg->quirks & DSI_PHY_7NM_QUIRK_PRE_V4_1)) {
dsi_phy_write(base + REG_DSI_7nm_PHY_PLL_PERF_OPTIMIZE, 0x22);
if (pll->slave)
dsi_phy_write(pll->slave->phy->pll_base + REG_DSI_7nm_PHY_PLL_PERF_OPTIMIZE, 0x22);
@@ -788,7 +823,7 @@ static void dsi_phy_hw_v4_0_lane_settings(struct msm_dsi_phy *phy)
const u8 *tx_dctrl = tx_dctrl_0;
void __iomem *lane_base = phy->lane_base;
- if (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_1)
+ if (!(phy->cfg->quirks & DSI_PHY_7NM_QUIRK_PRE_V4_1))
tx_dctrl = tx_dctrl_1;
/* Strength ctrl settings */
@@ -844,6 +879,13 @@ static int dsi_7nm_phy_enable(struct msm_dsi_phy *phy,
if (dsi_phy_hw_v4_0_is_pll_on(phy))
pr_warn("PLL turned on before configuring PHY\n");
+ /* Request for REFGEN READY */
+ if ((phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_3) ||
+ (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V5_2)) {
+ dsi_phy_write(phy->base + REG_DSI_7nm_PHY_CMN_GLBL_DIGTOP_SPARE10, 0x1);
+ udelay(500);
+ }
+
/* wait for REFGEN READY */
ret = readl_poll_timeout_atomic(base + REG_DSI_7nm_PHY_CMN_PHY_STATUS,
status, (status & BIT(0)),
@@ -858,23 +900,64 @@ static int dsi_7nm_phy_enable(struct msm_dsi_phy *phy,
/* Alter PHY configurations if data rate less than 1.5GHZ*/
less_than_1500_mhz = (clk_req->bitclk_rate <= 1500000000);
- if (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_1) {
+ glbl_str_swi_cal_sel_ctrl = 0x00;
+ if (phy->cphy_mode) {
+ vreg_ctrl_0 = 0x51;
+ vreg_ctrl_1 = 0x55;
+ glbl_hstx_str_ctrl_0 = 0x00;
+ glbl_pemph_ctrl_0 = 0x11;
+ lane_ctrl0 = 0x17;
+ } else {
vreg_ctrl_0 = less_than_1500_mhz ? 0x53 : 0x52;
+ vreg_ctrl_1 = 0x5c;
+ glbl_hstx_str_ctrl_0 = 0x88;
+ glbl_pemph_ctrl_0 = 0x00;
+ lane_ctrl0 = 0x1f;
+ }
+
+ if ((phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V5_2)) {
if (phy->cphy_mode) {
+ vreg_ctrl_0 = 0x45;
+ vreg_ctrl_1 = 0x45;
+ glbl_rescode_top_ctrl = 0x00;
+ glbl_rescode_bot_ctrl = 0x00;
+ } else {
+ vreg_ctrl_0 = 0x44;
+ vreg_ctrl_1 = 0x19;
+ glbl_rescode_top_ctrl = less_than_1500_mhz ? 0x3c : 0x03;
+ glbl_rescode_bot_ctrl = less_than_1500_mhz ? 0x38 : 0x3c;
+ }
+ } else if ((phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_3)) {
+ if (phy->cphy_mode) {
+ glbl_rescode_top_ctrl = less_than_1500_mhz ? 0x3d : 0x01;
+ glbl_rescode_bot_ctrl = less_than_1500_mhz ? 0x38 : 0x3b;
+ } else {
+ glbl_rescode_top_ctrl = less_than_1500_mhz ? 0x3d : 0x01;
+ glbl_rescode_bot_ctrl = less_than_1500_mhz ? 0x38 : 0x39;
+ }
+ } else if (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_2) {
+ if (phy->cphy_mode) {
+ glbl_rescode_top_ctrl = less_than_1500_mhz ? 0x3d : 0x01;
+ glbl_rescode_bot_ctrl = less_than_1500_mhz ? 0x38 : 0x3b;
+ } else {
+ glbl_rescode_top_ctrl = less_than_1500_mhz ? 0x3c : 0x00;
+ glbl_rescode_bot_ctrl = less_than_1500_mhz ? 0x38 : 0x39;
+ }
+ } else if (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_1) {
+ if (phy->cphy_mode) {
+ glbl_hstx_str_ctrl_0 = 0x88;
glbl_rescode_top_ctrl = 0x00;
glbl_rescode_bot_ctrl = 0x3c;
} else {
glbl_rescode_top_ctrl = less_than_1500_mhz ? 0x3d : 0x00;
glbl_rescode_bot_ctrl = less_than_1500_mhz ? 0x39 : 0x3c;
}
- glbl_str_swi_cal_sel_ctrl = 0x00;
- glbl_hstx_str_ctrl_0 = 0x88;
} else {
- vreg_ctrl_0 = less_than_1500_mhz ? 0x5B : 0x59;
if (phy->cphy_mode) {
glbl_str_swi_cal_sel_ctrl = 0x03;
glbl_hstx_str_ctrl_0 = 0x66;
} else {
+ vreg_ctrl_0 = less_than_1500_mhz ? 0x5B : 0x59;
glbl_str_swi_cal_sel_ctrl = less_than_1500_mhz ? 0x03 : 0x00;
glbl_hstx_str_ctrl_0 = less_than_1500_mhz ? 0x66 : 0x88;
}
@@ -882,17 +965,6 @@ static int dsi_7nm_phy_enable(struct msm_dsi_phy *phy,
glbl_rescode_bot_ctrl = 0x3c;
}
- if (phy->cphy_mode) {
- vreg_ctrl_0 = 0x51;
- vreg_ctrl_1 = 0x55;
- glbl_pemph_ctrl_0 = 0x11;
- lane_ctrl0 = 0x17;
- } else {
- vreg_ctrl_1 = 0x5c;
- glbl_pemph_ctrl_0 = 0x00;
- lane_ctrl0 = 0x1f;
- }
-
/* de-assert digital and pll power down */
data = BIT(6) | BIT(5);
dsi_phy_write(base + REG_DSI_7nm_PHY_CMN_CTRL_0, data);
@@ -904,9 +976,8 @@ static int dsi_7nm_phy_enable(struct msm_dsi_phy *phy,
dsi_phy_write(base + REG_DSI_7nm_PHY_CMN_RBUF_CTRL, 0x00);
/* program CMN_CTRL_4 for minor_ver 2 chipsets*/
- data = dsi_phy_read(base + REG_DSI_7nm_PHY_CMN_REVISION_ID0);
- data = data & (0xf0);
- if (data == 0x20)
+ if ((phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V5_2) ||
+ (dsi_phy_read(base + REG_DSI_7nm_PHY_CMN_REVISION_ID0) & (0xf0)) == 0x20)
dsi_phy_write(base + REG_DSI_7nm_PHY_CMN_CTRL_4, 0x04);
/* Configure PHY lane swap (TODO: we need to calculate this) */
@@ -1017,6 +1088,16 @@ static void dsi_7nm_phy_disable(struct msm_dsi_phy *phy)
pr_warn("Turning OFF PHY while PLL is on\n");
dsi_phy_hw_v4_0_config_lpcdrx(phy, false);
+
+ /* Turn off REFGEN Vote */
+ if ((phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V4_3) ||
+ (phy->cfg->quirks & DSI_PHY_7NM_QUIRK_V5_2)) {
+ dsi_phy_write(base + REG_DSI_7nm_PHY_CMN_GLBL_DIGTOP_SPARE10, 0x0);
+ wmb();
+ /* Delay to ensure HW removes vote before PHY shut down */
+ udelay(2);
+ }
+
data = dsi_phy_read(base + REG_DSI_7nm_PHY_CMN_CTRL_0);
/* disable all lanes */
@@ -1040,6 +1121,14 @@ static const struct regulator_bulk_data dsi_phy_7nm_37750uA_regulators[] = {
{ .supply = "vdds", .init_load_uA = 37550 },
};
+static const struct regulator_bulk_data dsi_phy_7nm_97800uA_regulators[] = {
+ { .supply = "vdds", .init_load_uA = 97800 },
+};
+
+static const struct regulator_bulk_data dsi_phy_7nm_98400uA_regulators[] = {
+ { .supply = "vdds", .init_load_uA = 98400 },
+};
+
const struct msm_dsi_phy_cfg dsi_phy_7nm_cfgs = {
.has_phy_lane = true,
.regulator_data = dsi_phy_7nm_36mA_regulators,
@@ -1063,6 +1152,26 @@ const struct msm_dsi_phy_cfg dsi_phy_7nm_cfgs = {
.quirks = DSI_PHY_7NM_QUIRK_V4_1,
};
+const struct msm_dsi_phy_cfg dsi_phy_7nm_6375_cfgs = {
+ .has_phy_lane = true,
+ .ops = {
+ .enable = dsi_7nm_phy_enable,
+ .disable = dsi_7nm_phy_disable,
+ .pll_init = dsi_pll_7nm_init,
+ .save_pll_state = dsi_7nm_pll_save_state,
+ .restore_pll_state = dsi_7nm_pll_restore_state,
+ },
+ .min_pll_rate = 600000000UL,
+#ifdef CONFIG_64BIT
+ .max_pll_rate = 5000000000ULL,
+#else
+ .max_pll_rate = ULONG_MAX,
+#endif
+ .io_start = { 0x5e94400 },
+ .num_dsi_phy = 1,
+ .quirks = DSI_PHY_7NM_QUIRK_V4_1,
+};
+
const struct msm_dsi_phy_cfg dsi_phy_7nm_8150_cfgs = {
.has_phy_lane = true,
.regulator_data = dsi_phy_7nm_36mA_regulators,
@@ -1079,6 +1188,7 @@ const struct msm_dsi_phy_cfg dsi_phy_7nm_8150_cfgs = {
.max_pll_rate = 3500000000UL,
.io_start = { 0xae94400, 0xae96400 },
.num_dsi_phy = 2,
+ .quirks = DSI_PHY_7NM_QUIRK_PRE_V4_1,
};
const struct msm_dsi_phy_cfg dsi_phy_7nm_7280_cfgs = {
@@ -1102,3 +1212,72 @@ const struct msm_dsi_phy_cfg dsi_phy_7nm_7280_cfgs = {
.num_dsi_phy = 1,
.quirks = DSI_PHY_7NM_QUIRK_V4_1,
};
+
+const struct msm_dsi_phy_cfg dsi_phy_5nm_8350_cfgs = {
+ .has_phy_lane = true,
+ .regulator_data = dsi_phy_7nm_37750uA_regulators,
+ .num_regulators = ARRAY_SIZE(dsi_phy_7nm_37750uA_regulators),
+ .ops = {
+ .enable = dsi_7nm_phy_enable,
+ .disable = dsi_7nm_phy_disable,
+ .pll_init = dsi_pll_7nm_init,
+ .save_pll_state = dsi_7nm_pll_save_state,
+ .restore_pll_state = dsi_7nm_pll_restore_state,
+ .set_continuous_clock = dsi_7nm_set_continuous_clock,
+ },
+ .min_pll_rate = 600000000UL,
+#ifdef CONFIG_64BIT
+ .max_pll_rate = 5000000000UL,
+#else
+ .max_pll_rate = ULONG_MAX,
+#endif
+ .io_start = { 0xae94400, 0xae96400 },
+ .num_dsi_phy = 2,
+ .quirks = DSI_PHY_7NM_QUIRK_V4_2,
+};
+
+const struct msm_dsi_phy_cfg dsi_phy_5nm_8450_cfgs = {
+ .has_phy_lane = true,
+ .regulator_data = dsi_phy_7nm_97800uA_regulators,
+ .num_regulators = ARRAY_SIZE(dsi_phy_7nm_97800uA_regulators),
+ .ops = {
+ .enable = dsi_7nm_phy_enable,
+ .disable = dsi_7nm_phy_disable,
+ .pll_init = dsi_pll_7nm_init,
+ .save_pll_state = dsi_7nm_pll_save_state,
+ .restore_pll_state = dsi_7nm_pll_restore_state,
+ .set_continuous_clock = dsi_7nm_set_continuous_clock,
+ },
+ .min_pll_rate = 600000000UL,
+#ifdef CONFIG_64BIT
+ .max_pll_rate = 5000000000UL,
+#else
+ .max_pll_rate = ULONG_MAX,
+#endif
+ .io_start = { 0xae94400, 0xae96400 },
+ .num_dsi_phy = 2,
+ .quirks = DSI_PHY_7NM_QUIRK_V4_3,
+};
+
+const struct msm_dsi_phy_cfg dsi_phy_4nm_8550_cfgs = {
+ .has_phy_lane = true,
+ .regulator_data = dsi_phy_7nm_98400uA_regulators,
+ .num_regulators = ARRAY_SIZE(dsi_phy_7nm_98400uA_regulators),
+ .ops = {
+ .enable = dsi_7nm_phy_enable,
+ .disable = dsi_7nm_phy_disable,
+ .pll_init = dsi_pll_7nm_init,
+ .save_pll_state = dsi_7nm_pll_save_state,
+ .restore_pll_state = dsi_7nm_pll_restore_state,
+ .set_continuous_clock = dsi_7nm_set_continuous_clock,
+ },
+ .min_pll_rate = 600000000UL,
+#ifdef CONFIG_64BIT
+ .max_pll_rate = 5000000000UL,
+#else
+ .max_pll_rate = ULONG_MAX,
+#endif
+ .io_start = { 0xae95000, 0xae97000 },
+ .num_dsi_phy = 2,
+ .quirks = DSI_PHY_7NM_QUIRK_V5_2,
+};
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
index 97372bb241d8..3132105a2a43 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
@@ -120,6 +120,10 @@ static int msm_hdmi_init(struct hdmi *hdmi)
int ret;
hdmi->workq = alloc_ordered_workqueue("msm_hdmi", 0);
+ if (!hdmi->workq) {
+ ret = -ENOMEM;
+ goto fail;
+ }
hdmi->i2c = msm_hdmi_i2c_init(hdmi);
if (IS_ERR(hdmi->i2c)) {
@@ -203,8 +207,6 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi,
goto fail;
}
- drm_bridge_connector_enable_hpd(hdmi->connector);
-
ret = msm_hdmi_hpd_enable(hdmi->bridge);
if (ret < 0) {
DRM_DEV_ERROR(&hdmi->pdev->dev, "failed to enable HPD: %d\n", ret);
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_hdcp.c b/drivers/gpu/drm/msm/hdmi/hdmi_hdcp.c
index e7748461cffc..0752fe373351 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_hdcp.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_hdcp.c
@@ -3,7 +3,7 @@
*/
#include "hdmi.h"
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#define HDCP_REG_ENABLE 0x01
#define HDCP_REG_DISABLE 0x00
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_pll_8960.c b/drivers/gpu/drm/msm/hdmi/hdmi_pll_8960.c
index be4b0b67e797..cb35a297afbd 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_pll_8960.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_pll_8960.c
@@ -406,14 +406,14 @@ static const struct clk_ops hdmi_pll_ops = {
.set_rate = hdmi_pll_set_rate,
};
-static const char * const hdmi_pll_parents[] = {
- "pxo",
+static const struct clk_parent_data hdmi_pll_parents[] = {
+ { .fw_name = "pxo", .name = "pxo_board" },
};
static struct clk_init_data pll_init = {
.name = "hdmi_pll",
.ops = &hdmi_pll_ops,
- .parent_names = hdmi_pll_parents,
+ .parent_data = hdmi_pll_parents,
.num_parents = ARRAY_SIZE(hdmi_pll_parents),
.flags = CLK_IGNORE_UNUSED,
};
@@ -422,8 +422,7 @@ int msm_hdmi_pll_8960_init(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct hdmi_pll_8960 *pll;
- struct clk *clk;
- int i;
+ int i, ret;
/* sanity check: */
for (i = 0; i < (ARRAY_SIZE(freqtbl) - 1); i++)
@@ -443,10 +442,16 @@ int msm_hdmi_pll_8960_init(struct platform_device *pdev)
pll->pdev = pdev;
pll->clk_hw.init = &pll_init;
- clk = devm_clk_register(dev, &pll->clk_hw);
- if (IS_ERR(clk)) {
+ ret = devm_clk_hw_register(dev, &pll->clk_hw);
+ if (ret < 0) {
DRM_DEV_ERROR(dev, "failed to register pll clock\n");
- return -EINVAL;
+ return ret;
+ }
+
+ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, &pll->clk_hw);
+ if (ret) {
+ DRM_DEV_ERROR(dev, "%s: failed to register clk provider: %d\n", __func__, ret);
+ return ret;
}
return 0;
diff --git a/drivers/gpu/drm/msm/msm_debugfs.c b/drivers/gpu/drm/msm/msm_debugfs.c
index 95f4374ae21c..d6ecff0ab618 100644
--- a/drivers/gpu/drm/msm/msm_debugfs.c
+++ b/drivers/gpu/drm/msm/msm_debugfs.c
@@ -305,6 +305,7 @@ void msm_debugfs_init(struct drm_minor *minor)
{
struct drm_device *dev = minor->dev;
struct msm_drm_private *priv = dev->dev_private;
+ struct dentry *gpu_devfreq;
drm_debugfs_create_files(msm_debugfs_list,
ARRAY_SIZE(msm_debugfs_list),
@@ -325,6 +326,17 @@ void msm_debugfs_init(struct drm_minor *minor)
debugfs_create_file("shrink", S_IRWXU, minor->debugfs_root,
dev, &shrink_fops);
+ gpu_devfreq = debugfs_create_dir("devfreq", minor->debugfs_root);
+
+ debugfs_create_bool("idle_clamp",0600, gpu_devfreq,
+ &priv->gpu_clamp_to_idle);
+
+ debugfs_create_u32("upthreshold",0600, gpu_devfreq,
+ &priv->gpu_devfreq_config.upthreshold);
+
+ debugfs_create_u32("downdifferential",0600, gpu_devfreq,
+ &priv->gpu_devfreq_config.downdifferential);
+
if (priv->kms && priv->kms->funcs->debugfs_init)
priv->kms->funcs->debugfs_init(priv->kms, minor);
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index 45e81eb148a8..aca48c868c14 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -45,9 +45,10 @@
* - 1.7.0 - Add MSM_PARAM_SUSPENDS to access suspend count
* - 1.8.0 - Add MSM_BO_CACHED_COHERENT for supported GPUs (a6xx)
* - 1.9.0 - Add MSM_SUBMIT_FENCE_SN_IN
+ * - 1.10.0 - Add MSM_SUBMIT_BO_NO_IMPLICIT
*/
#define MSM_VERSION_MAJOR 1
-#define MSM_VERSION_MINOR 9
+#define MSM_VERSION_MINOR 10
#define MSM_VERSION_PATCHLEVEL 0
static const struct drm_mode_config_funcs mode_config_funcs = {
@@ -149,6 +150,9 @@ static void msm_irq_uninstall(struct drm_device *dev)
struct msm_drm_private *priv = dev->dev_private;
struct msm_kms *kms = priv->kms;
+ if (!priv->kms)
+ return;
+
kms->funcs->irq_uninstall(kms);
if (kms->irq_requested)
free_irq(kms->irq, dev);
@@ -266,8 +270,6 @@ static int msm_drm_uninit(struct device *dev)
component_unbind_all(dev, ddev);
ddev->dev_private = NULL;
- drm_dev_put(ddev);
-
destroy_workqueue(priv->wq);
return 0;
@@ -418,6 +420,8 @@ static int msm_drm_init(struct device *dev, const struct drm_driver *drv)
priv->dev = ddev;
priv->wq = alloc_ordered_workqueue("msm", 0);
+ if (!priv->wq)
+ return -ENOMEM;
INIT_LIST_HEAD(&priv->objects);
mutex_init(&priv->obj_lock);
@@ -440,12 +444,12 @@ static int msm_drm_init(struct device *dev, const struct drm_driver *drv)
ret = msm_init_vram(ddev);
if (ret)
- return ret;
+ goto err_drm_dev_put;
/* Bind all our sub-components: */
ret = component_bind_all(dev, ddev);
if (ret)
- return ret;
+ goto err_drm_dev_put;
dma_set_max_seg_size(dev, UINT_MAX);
@@ -491,7 +495,7 @@ static int msm_drm_init(struct device *dev, const struct drm_driver *drv)
if (IS_ERR(priv->event_thread[i].worker)) {
ret = PTR_ERR(priv->event_thread[i].worker);
DRM_DEV_ERROR(dev, "failed to create crtc_event kthread\n");
- ret = PTR_ERR(priv->event_thread[i].worker);
+ priv->event_thread[i].worker = NULL;
goto err_msm_uninit;
}
@@ -540,6 +544,8 @@ static int msm_drm_init(struct device *dev, const struct drm_driver *drv)
err_msm_uninit:
msm_drm_uninit(dev);
+err_drm_dev_put:
+ drm_dev_put(ddev);
return ret;
}
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index d4e0ef608950..9f0c184b02a0 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -11,6 +11,7 @@
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/cpufreq.h>
+#include <linux/devfreq.h>
#include <linux/module.h>
#include <linux/component.h>
#include <linux/platform_device.h>
@@ -61,6 +62,7 @@ enum msm_dp_controller {
MSM_DP_CONTROLLER_0,
MSM_DP_CONTROLLER_1,
MSM_DP_CONTROLLER_2,
+ MSM_DP_CONTROLLER_3,
MSM_DP_CONTROLLER_COUNT,
};
@@ -82,14 +84,12 @@ enum msm_event_wait {
/**
* struct msm_display_topology - defines a display topology pipeline
* @num_lm: number of layer mixers used
- * @num_enc: number of compression encoder blocks used
* @num_intf: number of interfaces the panel is mounted on
* @num_dspp: number of dspp blocks used
* @num_dsc: number of Display Stream Compression (DSC) blocks used
*/
struct msm_display_topology {
u32 num_lm;
- u32 num_enc;
u32 num_intf;
u32 num_dspp;
u32 num_dsc;
@@ -233,6 +233,14 @@ struct msm_drm_private {
*/
unsigned int hangcheck_period;
+ /** gpu_devfreq_config: Devfreq tuning config for the GPU. */
+ struct devfreq_simple_ondemand_data gpu_devfreq_config;
+
+ /**
+ * gpu_clamp_to_idle: Enable clamping to idle freq when inactive
+ */
+ bool gpu_clamp_to_idle;
+
/**
* disable_err_irq:
*
diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c
index 31e1e30cb52a..d26aa52217ce 100644
--- a/drivers/gpu/drm/msm/msm_fbdev.c
+++ b/drivers/gpu/drm/msm/msm_fbdev.c
@@ -136,17 +136,17 @@ static const struct drm_fb_helper_funcs msm_fb_helper_funcs = {
struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev)
{
struct msm_drm_private *priv = dev->dev_private;
- struct msm_fbdev *fbdev = NULL;
+ struct msm_fbdev *fbdev;
struct drm_fb_helper *helper;
int ret;
fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL);
if (!fbdev)
- goto fail;
+ return NULL;
helper = &fbdev->base;
- drm_fb_helper_prepare(dev, helper, &msm_fb_helper_funcs);
+ drm_fb_helper_prepare(dev, helper, 32, &msm_fb_helper_funcs);
ret = drm_fb_helper_init(dev, helper);
if (ret) {
@@ -159,7 +159,7 @@ struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev)
if (ret)
goto fini;
- ret = drm_fb_helper_initial_config(helper, 32);
+ ret = drm_fb_helper_initial_config(helper);
if (ret)
goto fini;
@@ -170,6 +170,7 @@ struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev)
fini:
drm_fb_helper_fini(helper);
fail:
+ drm_fb_helper_unprepare(helper);
kfree(fbdev);
return NULL;
}
@@ -196,6 +197,7 @@ void msm_fbdev_free(struct drm_device *dev)
drm_framebuffer_remove(fbdev->fb);
}
+ drm_fb_helper_unprepare(helper);
kfree(fbdev);
priv->fbdev = NULL;
diff --git a/drivers/gpu/drm/msm/msm_fence.c b/drivers/gpu/drm/msm/msm_fence.c
index a47e5837c528..56641408ea74 100644
--- a/drivers/gpu/drm/msm/msm_fence.c
+++ b/drivers/gpu/drm/msm/msm_fence.c
@@ -22,7 +22,7 @@ msm_fence_context_alloc(struct drm_device *dev, volatile uint32_t *fenceptr,
return ERR_PTR(-ENOMEM);
fctx->dev = dev;
- strncpy(fctx->name, name, sizeof(fctx->name));
+ strscpy(fctx->name, name, sizeof(fctx->name));
fctx->context = dma_fence_context_alloc(1);
fctx->index = index++;
fctx->fenceptr = fenceptr;
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index 1dee0d18abbb..c2fb98a94bc3 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -1012,7 +1012,7 @@ static int msm_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struct
{
struct msm_gem_object *msm_obj = to_msm_bo(obj);
- vma->vm_flags |= VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP;
+ vm_flags_set(vma, VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP);
vma->vm_page_prot = msm_gem_pgprot(msm_obj, vm_get_page_prot(vma->vm_flags));
return 0;
diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c
index 73a2ca122c57..be4bf77103cd 100644
--- a/drivers/gpu/drm/msm/msm_gem_submit.c
+++ b/drivers/gpu/drm/msm/msm_gem_submit.c
@@ -209,6 +209,10 @@ static int submit_lookup_cmds(struct msm_gem_submit *submit,
goto out;
}
submit->cmd[i].relocs = kmalloc(sz, GFP_KERNEL);
+ if (!submit->cmd[i].relocs) {
+ ret = -ENOMEM;
+ goto out;
+ }
ret = copy_from_user(submit->cmd[i].relocs, userptr, sz);
if (ret) {
ret = -EFAULT;
@@ -334,9 +338,20 @@ static int submit_fence_sync(struct msm_gem_submit *submit, bool no_implicit)
if (ret)
return ret;
+ /* If userspace has determined that explicit fencing is
+ * used, it can disable implicit sync on the entire
+ * submit:
+ */
if (no_implicit)
continue;
+ /* Otherwise userspace can ask for implicit sync to be
+ * disabled on specific buffers. This is useful for internal
+ * usermode driver managed buffers, suballocation, etc.
+ */
+ if (submit->bos[i].flags & MSM_SUBMIT_BO_NO_IMPLICIT)
+ continue;
+
ret = drm_sched_job_add_implicit_dependencies(&submit->base,
obj,
write);
diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h
index 732295e25683..fc1c0d8611a8 100644
--- a/drivers/gpu/drm/msm/msm_gpu.h
+++ b/drivers/gpu/drm/msm/msm_gpu.h
@@ -109,11 +109,15 @@ struct msm_gpu_devfreq {
struct mutex lock;
/**
- * idle_constraint:
+ * idle_freq:
*
- * A PM QoS constraint to limit max freq while the GPU is idle.
+ * Shadow frequency used while the GPU is idle. From the PoV of
+ * the devfreq governor, we are continuing to sample busyness and
+ * adjust frequency while the GPU is idle, but we use this shadow
+ * value as the GPU is actually clamped to minimum frequency while
+ * it is inactive.
*/
- struct dev_pm_qos_request idle_freq;
+ unsigned long idle_freq;
/**
* boost_constraint:
@@ -135,8 +139,6 @@ struct msm_gpu_devfreq {
/** idle_time: Time of last transition to idle: */
ktime_t idle_time;
- struct devfreq_dev_status average_status;
-
/**
* idle_work:
*
@@ -275,9 +277,6 @@ struct msm_gpu {
struct msm_gpu_state *crashstate;
- /* Enable clamping to idle freq when inactive: */
- bool clamp_to_idle;
-
/* True if the hardware supports expanded apriv (a650 and newer) */
bool hw_apriv;
diff --git a/drivers/gpu/drm/msm/msm_gpu_devfreq.c b/drivers/gpu/drm/msm/msm_gpu_devfreq.c
index 85c443a37e4e..e27dbf12b5e8 100644
--- a/drivers/gpu/drm/msm/msm_gpu_devfreq.c
+++ b/drivers/gpu/drm/msm/msm_gpu_devfreq.c
@@ -33,6 +33,16 @@ static int msm_devfreq_target(struct device *dev, unsigned long *freq,
trace_msm_gpu_freq_change(dev_pm_opp_get_freq(opp));
+ /*
+ * If the GPU is idle, devfreq is not aware, so just stash
+ * the new target freq (to use when we return to active)
+ */
+ if (df->idle_freq) {
+ df->idle_freq = *freq;
+ dev_pm_opp_put(opp);
+ return 0;
+ }
+
if (gpu->funcs->gpu_set_freq) {
mutex_lock(&df->lock);
gpu->funcs->gpu_set_freq(gpu, opp, df->suspended);
@@ -48,15 +58,26 @@ static int msm_devfreq_target(struct device *dev, unsigned long *freq,
static unsigned long get_freq(struct msm_gpu *gpu)
{
+ struct msm_gpu_devfreq *df = &gpu->devfreq;
+
+ /*
+ * If the GPU is idle, use the shadow/saved freq to avoid
+ * confusing devfreq (which is unaware that we are switching
+ * to lowest freq until the device is active again)
+ */
+ if (df->idle_freq)
+ return df->idle_freq;
+
if (gpu->funcs->gpu_get_freq)
return gpu->funcs->gpu_get_freq(gpu);
return clk_get_rate(gpu->core_clk);
}
-static void get_raw_dev_status(struct msm_gpu *gpu,
+static int msm_devfreq_get_dev_status(struct device *dev,
struct devfreq_dev_status *status)
{
+ struct msm_gpu *gpu = dev_to_gpu(dev);
struct msm_gpu_devfreq *df = &gpu->devfreq;
u64 busy_cycles, busy_time;
unsigned long sample_rate;
@@ -72,7 +93,7 @@ static void get_raw_dev_status(struct msm_gpu *gpu,
if (df->suspended) {
mutex_unlock(&df->lock);
status->busy_time = 0;
- return;
+ return 0;
}
busy_cycles = gpu->funcs->gpu_busy(gpu, &sample_rate);
@@ -87,71 +108,6 @@ static void get_raw_dev_status(struct msm_gpu *gpu,
busy_time = ~0LU;
status->busy_time = busy_time;
-}
-
-static void update_average_dev_status(struct msm_gpu *gpu,
- const struct devfreq_dev_status *raw)
-{
- struct msm_gpu_devfreq *df = &gpu->devfreq;
- const u32 polling_ms = df->devfreq->profile->polling_ms;
- const u32 max_history_ms = polling_ms * 11 / 10;
- struct devfreq_dev_status *avg = &df->average_status;
- u64 avg_freq;
-
- /* simple_ondemand governor interacts poorly with gpu->clamp_to_idle.
- * When we enforce the constraint on idle, it calls get_dev_status
- * which would normally reset the stats. When we remove the
- * constraint on active, it calls get_dev_status again where busy_time
- * would be 0.
- *
- * To remedy this, we always return the average load over the past
- * polling_ms.
- */
-
- /* raw is longer than polling_ms or avg has no history */
- if (div_u64(raw->total_time, USEC_PER_MSEC) >= polling_ms ||
- !avg->total_time) {
- *avg = *raw;
- return;
- }
-
- /* Truncate the oldest history first.
- *
- * Because we keep the history with a single devfreq_dev_status,
- * rather than a list of devfreq_dev_status, we have to assume freq
- * and load are the same over avg->total_time. We can scale down
- * avg->busy_time and avg->total_time by the same factor to drop
- * history.
- */
- if (div_u64(avg->total_time + raw->total_time, USEC_PER_MSEC) >=
- max_history_ms) {
- const u32 new_total_time = polling_ms * USEC_PER_MSEC -
- raw->total_time;
- avg->busy_time = div_u64(
- mul_u32_u32(avg->busy_time, new_total_time),
- avg->total_time);
- avg->total_time = new_total_time;
- }
-
- /* compute the average freq over avg->total_time + raw->total_time */
- avg_freq = mul_u32_u32(avg->current_frequency, avg->total_time);
- avg_freq += mul_u32_u32(raw->current_frequency, raw->total_time);
- do_div(avg_freq, avg->total_time + raw->total_time);
-
- avg->current_frequency = avg_freq;
- avg->busy_time += raw->busy_time;
- avg->total_time += raw->total_time;
-}
-
-static int msm_devfreq_get_dev_status(struct device *dev,
- struct devfreq_dev_status *status)
-{
- struct msm_gpu *gpu = dev_to_gpu(dev);
- struct devfreq_dev_status raw;
-
- get_raw_dev_status(gpu, &raw);
- update_average_dev_status(gpu, &raw);
- *status = gpu->devfreq.average_status;
return 0;
}
@@ -183,16 +139,23 @@ static bool has_devfreq(struct msm_gpu *gpu)
void msm_devfreq_init(struct msm_gpu *gpu)
{
struct msm_gpu_devfreq *df = &gpu->devfreq;
+ struct msm_drm_private *priv = gpu->dev->dev_private;
/* We need target support to do devfreq */
if (!gpu->funcs->gpu_busy)
return;
+ /*
+ * Setup default values for simple_ondemand governor tuning. We
+ * want to throttle up at 50% load for the double-buffer case,
+ * where due to stalling waiting for vblank we could get stuck
+ * at (for ex) 30fps at 50% utilization.
+ */
+ priv->gpu_devfreq_config.upthreshold = 50;
+ priv->gpu_devfreq_config.downdifferential = 10;
+
mutex_init(&df->lock);
- dev_pm_qos_add_request(&gpu->pdev->dev, &df->idle_freq,
- DEV_PM_QOS_MAX_FREQUENCY,
- PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE);
dev_pm_qos_add_request(&gpu->pdev->dev, &df->boost_freq,
DEV_PM_QOS_MIN_FREQUENCY, 0);
@@ -209,11 +172,10 @@ void msm_devfreq_init(struct msm_gpu *gpu)
df->devfreq = devm_devfreq_add_device(&gpu->pdev->dev,
&msm_devfreq_profile, DEVFREQ_GOV_SIMPLE_ONDEMAND,
- NULL);
+ &priv->gpu_devfreq_config);
if (IS_ERR(df->devfreq)) {
DRM_DEV_ERROR(&gpu->pdev->dev, "Couldn't initialize GPU devfreq\n");
- dev_pm_qos_remove_request(&df->idle_freq);
dev_pm_qos_remove_request(&df->boost_freq);
df->devfreq = NULL;
return;
@@ -255,7 +217,6 @@ void msm_devfreq_cleanup(struct msm_gpu *gpu)
devfreq_cooling_unregister(gpu->cooling);
dev_pm_qos_remove_request(&df->boost_freq);
- dev_pm_qos_remove_request(&df->idle_freq);
}
void msm_devfreq_resume(struct msm_gpu *gpu)
@@ -328,6 +289,7 @@ void msm_devfreq_active(struct msm_gpu *gpu)
{
struct msm_gpu_devfreq *df = &gpu->devfreq;
unsigned int idle_time;
+ unsigned long target_freq;
if (!has_devfreq(gpu))
return;
@@ -337,8 +299,28 @@ void msm_devfreq_active(struct msm_gpu *gpu)
*/
cancel_idle_work(df);
+ /*
+ * Hold devfreq lock to synchronize with get_dev_status()/
+ * target() callbacks
+ */
+ mutex_lock(&df->devfreq->lock);
+
+ target_freq = df->idle_freq;
+
idle_time = ktime_to_ms(ktime_sub(ktime_get(), df->idle_time));
+ df->idle_freq = 0;
+
+ /*
+ * We could have become active again before the idle work had a
+ * chance to run, in which case the df->idle_freq would have
+ * still been zero. In this case, no need to change freq.
+ */
+ if (target_freq)
+ msm_devfreq_target(&gpu->pdev->dev, &target_freq, 0);
+
+ mutex_unlock(&df->devfreq->lock);
+
/*
* If we've been idle for a significant fraction of a polling
* interval, then we won't meet the threshold of busyness for
@@ -347,9 +329,6 @@ void msm_devfreq_active(struct msm_gpu *gpu)
if (idle_time > msm_devfreq_profile.polling_ms) {
msm_devfreq_boost(gpu, 2);
}
-
- dev_pm_qos_update_request(&df->idle_freq,
- PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE);
}
@@ -358,11 +337,24 @@ static void msm_devfreq_idle_work(struct kthread_work *work)
struct msm_gpu_devfreq *df = container_of(work,
struct msm_gpu_devfreq, idle_work.work);
struct msm_gpu *gpu = container_of(df, struct msm_gpu, devfreq);
+ struct msm_drm_private *priv = gpu->dev->dev_private;
+ unsigned long idle_freq, target_freq = 0;
+
+ /*
+ * Hold devfreq lock to synchronize with get_dev_status()/
+ * target() callbacks
+ */
+ mutex_lock(&df->devfreq->lock);
+
+ idle_freq = get_freq(gpu);
+
+ if (priv->gpu_clamp_to_idle)
+ msm_devfreq_target(&gpu->pdev->dev, &target_freq, 0);
df->idle_time = ktime_get();
+ df->idle_freq = idle_freq;
- if (gpu->clamp_to_idle)
- dev_pm_qos_update_request(&df->idle_freq, 0);
+ mutex_unlock(&df->devfreq->lock);
}
void msm_devfreq_idle(struct msm_gpu *gpu)
diff --git a/drivers/gpu/drm/msm/msm_mdss.c b/drivers/gpu/drm/msm/msm_mdss.c
index 2527afef9c19..02646e4bb4cd 100644
--- a/drivers/gpu/drm/msm/msm_mdss.c
+++ b/drivers/gpu/drm/msm/msm_mdss.c
@@ -286,9 +286,21 @@ static int msm_mdss_enable(struct msm_mdss *msm_mdss)
/* UBWC_2_0 */
msm_mdss_setup_ubwc_dec_20(msm_mdss, 0x11f);
break;
+ case DPU_HW_VER_700:
+ /* TODO: highest_bank_bit = 2 for LP_DDR4 */
+ msm_mdss_setup_ubwc_dec_40(msm_mdss, UBWC_4_0, 6, 1, 3, 1);
+ break;
case DPU_HW_VER_720:
msm_mdss_setup_ubwc_dec_40(msm_mdss, UBWC_3_0, 6, 1, 1, 1);
break;
+ case DPU_HW_VER_800:
+ msm_mdss_setup_ubwc_dec_40(msm_mdss, UBWC_4_0, 6, 1, 2, 1);
+ break;
+ case DPU_HW_VER_810:
+ case DPU_HW_VER_900:
+ /* TODO: highest_bank_bit = 2 for LP_DDR4 */
+ msm_mdss_setup_ubwc_dec_40(msm_mdss, UBWC_4_0, 6, 1, 3, 1);
+ break;
}
return ret;
@@ -515,9 +527,13 @@ static const struct of_device_id mdss_dt_match[] = {
{ .compatible = "qcom,sc7180-mdss" },
{ .compatible = "qcom,sc7280-mdss" },
{ .compatible = "qcom,sc8180x-mdss" },
+ { .compatible = "qcom,sc8280xp-mdss" },
{ .compatible = "qcom,sm6115-mdss" },
{ .compatible = "qcom,sm8150-mdss" },
{ .compatible = "qcom,sm8250-mdss" },
+ { .compatible = "qcom,sm8350-mdss" },
+ { .compatible = "qcom,sm8450-mdss" },
+ { .compatible = "qcom,sm8550-mdss" },
{}
};
MODULE_DEVICE_TABLE(of, mdss_dt_match);
diff --git a/drivers/gpu/drm/mxsfb/Kconfig b/drivers/gpu/drm/mxsfb/Kconfig
index 116f8168bda4..518b53345354 100644
--- a/drivers/gpu/drm/mxsfb/Kconfig
+++ b/drivers/gpu/drm/mxsfb/Kconfig
@@ -8,6 +8,7 @@ config DRM_MXSFB
tristate "i.MX (e)LCDIF LCD controller"
depends on DRM && OF
depends on COMMON_CLK
+ depends on ARCH_MXS || ARCH_MXC || COMPILE_TEST
select DRM_MXS
select DRM_KMS_HELPER
select DRM_GEM_DMA_HELPER
@@ -24,6 +25,7 @@ config DRM_IMX_LCDIF
tristate "i.MX LCDIFv3 LCD controller"
depends on DRM && OF
depends on COMMON_CLK
+ depends on ARCH_MXC || COMPILE_TEST
select DRM_MXS
select DRM_KMS_HELPER
select DRM_GEM_DMA_HELPER
diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.c b/drivers/gpu/drm/mxsfb/mxsfb_drv.c
index 810edea0a31e..b3ab86ad1b36 100644
--- a/drivers/gpu/drm/mxsfb/mxsfb_drv.c
+++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.c
@@ -78,14 +78,12 @@ static const struct mxsfb_devdata mxsfb_devdata[] = {
void mxsfb_enable_axi_clk(struct mxsfb_drm_private *mxsfb)
{
- if (mxsfb->clk_axi)
- clk_prepare_enable(mxsfb->clk_axi);
+ clk_prepare_enable(mxsfb->clk_axi);
}
void mxsfb_disable_axi_clk(struct mxsfb_drm_private *mxsfb)
{
- if (mxsfb->clk_axi)
- clk_disable_unprepare(mxsfb->clk_axi);
+ clk_disable_unprepare(mxsfb->clk_axi);
}
static struct drm_framebuffer *
@@ -235,9 +233,9 @@ static int mxsfb_load(struct drm_device *drm,
if (IS_ERR(mxsfb->clk))
return PTR_ERR(mxsfb->clk);
- mxsfb->clk_axi = devm_clk_get(drm->dev, "axi");
+ mxsfb->clk_axi = devm_clk_get_optional(drm->dev, "axi");
if (IS_ERR(mxsfb->clk_axi))
- mxsfb->clk_axi = NULL;
+ return PTR_ERR(mxsfb->clk_axi);
mxsfb->clk_disp_axi = devm_clk_get(drm->dev, "disp_axi");
if (IS_ERR(mxsfb->clk_disp_axi))
diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig
index 03d12caf9e26..a70bd65e1400 100644
--- a/drivers/gpu/drm/nouveau/Kconfig
+++ b/drivers/gpu/drm/nouveau/Kconfig
@@ -10,6 +10,8 @@ config DRM_NOUVEAU
select DRM_KMS_HELPER
select DRM_TTM
select DRM_TTM_HELPER
+ select I2C
+ select I2C_ALGOBIT
select BACKLIGHT_CLASS_DEVICE if DRM_NOUVEAU_BACKLIGHT
select X86_PLATFORM_DEVICES if ACPI && X86
select ACPI_WMI if ACPI && X86
@@ -24,18 +26,6 @@ config DRM_NOUVEAU
help
Choose this option for open-source NVIDIA support.
-config NOUVEAU_LEGACY_CTX_SUPPORT
- bool "Nouveau legacy context support"
- depends on DRM_NOUVEAU
- select DRM_LEGACY
- default y
- help
- There was a version of the nouveau DDX that relied on legacy
- ctx ioctls not erroring out. But that was back in time a long
- ways, so offer a way to disable it now. For uapi compat with
- old nouveau ddx this should be on by default, but modern distros
- should consider turning it off.
-
config NOUVEAU_PLATFORM_DRIVER
bool "Nouveau (NVIDIA) SoC GPUs"
depends on DRM_NOUVEAU && ARCH_TEGRA
diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
index 0e0f117bc70b..a6f2e681bde9 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
@@ -23,8 +23,8 @@
* DEALINGS IN THE SOFTWARE.
*/
#include <drm/drm_crtc_helper.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_fourcc.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_plane_helper.h>
#include <drm/drm_vblank.h>
diff --git a/drivers/gpu/drm/nouveau/dispnv04/dac.c b/drivers/gpu/drm/nouveau/dispnv04/dac.c
index 22d10f328559..d6b8e0cce2ac 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/dac.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/dac.c
@@ -24,7 +24,7 @@
* DEALINGS IN THE SOFTWARE.
*/
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include "nouveau_drv.h"
#include "nouveau_encoder.h"
diff --git a/drivers/gpu/drm/nouveau/dispnv04/dfp.c b/drivers/gpu/drm/nouveau/dispnv04/dfp.c
index ce3d8c6ef000..d5b129dc623b 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/dfp.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/dfp.c
@@ -24,8 +24,8 @@
* DEALINGS IN THE SOFTWARE.
*/
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_fourcc.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include "nouveau_drv.h"
#include "nouveau_reg.h"
diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvmodesnv17.c b/drivers/gpu/drm/nouveau/dispnv04/tvmodesnv17.c
index 2f6d2b6711ab..a3fedd226854 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/tvmodesnv17.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/tvmodesnv17.c
@@ -24,7 +24,6 @@
*
*/
-#include <drm/drm_crtc_helper.h>
#include "nouveau_drv.h"
#include "nouveau_encoder.h"
#include "nouveau_crtc.h"
diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c b/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c
index 3ba7b59580d5..de3ea731d6e6 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c
@@ -30,7 +30,7 @@
#include "nouveau_connector.h"
#include "nouveau_crtc.h"
#include "hw.h"
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include <drm/i2c/ch7006.h>
diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c
index be28e7bd7490..670c9739e5e1 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c
@@ -25,6 +25,7 @@
*/
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_probe_helper.h>
#include "nouveau_drv.h"
#include "nouveau_reg.h"
@@ -653,7 +654,7 @@ static int nv17_tv_create_resources(struct drm_encoder *encoder,
tv_enc->tv_norm = i;
}
- drm_mode_create_tv_properties(dev, num_tv_norms, nv17_tv_norm_names);
+ drm_mode_create_tv_properties_legacy(dev, num_tv_norms, nv17_tv_norm_names);
drm_object_attach_property(&connector->base,
conf->tv_select_subconnector_property,
@@ -662,7 +663,7 @@ static int nv17_tv_create_resources(struct drm_encoder *encoder,
conf->tv_subconnector_property,
tv_enc->subconnector);
drm_object_attach_property(&connector->base,
- conf->tv_mode_property,
+ conf->legacy_tv_mode_property,
tv_enc->tv_norm);
drm_object_attach_property(&connector->base,
conf->tv_flicker_reduction_property,
@@ -722,7 +723,7 @@ static int nv17_tv_set_property(struct drm_encoder *encoder,
if (encoder->crtc)
nv17_tv_update_rescaler(encoder);
- } else if (property == conf->tv_mode_property) {
+ } else if (property == conf->legacy_tv_mode_property) {
if (connector->dpms != DRM_MODE_DPMS_OFF)
return -EINVAL;
diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c
index edcb2529b402..ed9d374147b8 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/disp.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c
@@ -885,7 +885,7 @@ nv50_msto_prepare(struct drm_atomic_state *state,
// TODO: Figure out if we want to do a better job of handling VCPI allocation failures here?
if (msto->disabled) {
- drm_dp_remove_payload(mgr, mst_state, payload);
+ drm_dp_remove_payload(mgr, mst_state, payload, payload);
nvif_outp_dp_mst_vcpi(&mstm->outp->outp, msto->head->base.index, 0, 0, 0, 0);
} else {
diff --git a/drivers/gpu/drm/nouveau/dispnv50/head.c b/drivers/gpu/drm/nouveau/dispnv50/head.c
index f006e56e1e08..5f490fbf1877 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/head.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/head.c
@@ -32,7 +32,6 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_vblank.h>
#include "nouveau_connector.h"
diff --git a/drivers/gpu/drm/nouveau/include/nvfw/hs.h b/drivers/gpu/drm/nouveau/include/nvfw/hs.h
index 8c4cd08a7b5f..8b58b668fc0c 100644
--- a/drivers/gpu/drm/nouveau/include/nvfw/hs.h
+++ b/drivers/gpu/drm/nouveau/include/nvfw/hs.h
@@ -52,7 +52,7 @@ struct nvfw_hs_load_header_v2 {
struct {
u32 offset;
u32 size;
- } app[0];
+ } app[];
};
const struct nvfw_hs_load_header_v2 *nvfw_hs_load_header_v2(struct nvkm_subdev *, const void *);
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
index a11871e3119c..288eebc70a67 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -28,6 +28,7 @@
*/
#include <linux/dma-mapping.h>
+#include <drm/ttm/ttm_tt.h>
#include "nouveau_drv.h"
#include "nouveau_chan.h"
@@ -921,6 +922,7 @@ static void nouveau_bo_move_ntfy(struct ttm_buffer_object *bo,
struct nouveau_mem *mem = new_reg ? nouveau_mem(new_reg) : NULL;
struct nouveau_bo *nvbo = nouveau_bo(bo);
struct nouveau_vma *vma;
+ long ret;
/* ttm can now (stupidly) pass the driver bos it didn't create... */
if (bo->destroy != nouveau_bo_del_ttm)
@@ -935,7 +937,10 @@ static void nouveau_bo_move_ntfy(struct ttm_buffer_object *bo,
}
} else {
list_for_each_entry(vma, &nvbo->vma_list, head) {
- WARN_ON(ttm_bo_wait(bo, false, false));
+ ret = dma_resv_wait_timeout(bo->base.resv,
+ DMA_RESV_USAGE_BOOKKEEP,
+ false, 15 * HZ);
+ WARN_ON(ret <= 0);
nouveau_vma_unmap(vma);
}
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.h b/drivers/gpu/drm/nouveau/nouveau_bo.h
index c2d3f9c48eba..774dd93ca76b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.h
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.h
@@ -1,8 +1,9 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NOUVEAU_BO_H__
#define __NOUVEAU_BO_H__
-#include <drm/ttm/ttm_bo_driver.h>
#include <drm/drm_gem.h>
+#include <drm/ttm/ttm_bo.h>
+#include <drm/ttm/ttm_placement.h>
struct nouveau_channel;
struct nouveau_cli;
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index 80f154b6adab..cc7c5b4a05fd 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -31,9 +31,7 @@
#include <linux/dynamic_debug.h>
#include <drm/drm_aperture.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_fbdev_generic.h>
#include <drm/drm_gem_ttm_helper.h>
#include <drm/drm_ioctl.h>
@@ -1221,13 +1219,9 @@ nouveau_driver_fops = {
static struct drm_driver
driver_stub = {
- .driver_features =
- DRIVER_GEM | DRIVER_MODESET | DRIVER_RENDER
-#if defined(CONFIG_NOUVEAU_LEGACY_CTX_SUPPORT)
- | DRIVER_KMS_LEGACY_CONTEXT
-#endif
- ,
-
+ .driver_features = DRIVER_GEM |
+ DRIVER_MODESET |
+ DRIVER_RENDER,
.open = nouveau_drm_open,
.postclose = nouveau_drm_postclose,
.lastclose = nouveau_vga_lastclose,
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index d6dd07bfa64a..b5de312a523f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -51,8 +51,7 @@
#include <drm/drm_drv.h>
#include <drm/drm_file.h>
-#include <drm/ttm/ttm_bo_api.h>
-#include <drm/ttm/ttm_bo_driver.h>
+#include <drm/ttm/ttm_bo.h>
#include <drm/ttm/ttm_placement.h>
#include <drm/drm_audio_component.h>
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
index ac5793c96957..f77e44958037 100644
--- a/drivers/gpu/drm/nouveau/nouveau_gem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
@@ -645,7 +645,7 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli,
struct drm_nouveau_gem_pushbuf_reloc *reloc,
struct drm_nouveau_gem_pushbuf_bo *bo)
{
- int ret = 0;
+ long ret = 0;
unsigned i;
for (i = 0; i < req->nr_relocs; i++) {
@@ -703,9 +703,14 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli,
data |= r->vor;
}
- ret = ttm_bo_wait(&nvbo->bo, false, false);
+ ret = dma_resv_wait_timeout(nvbo->bo.base.resv,
+ DMA_RESV_USAGE_BOOKKEEP,
+ false, 15 * HZ);
+ if (ret == 0)
+ ret = -EBUSY;
if (ret) {
- NV_PRINTK(err, cli, "reloc wait_idle failed: %d\n", ret);
+ NV_PRINTK(err, cli, "reloc wait_idle failed: %ld\n",
+ ret);
break;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c
index 1fde3a5d7c32..25f31d5169e5 100644
--- a/drivers/gpu/drm/nouveau/nouveau_mem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_mem.c
@@ -19,11 +19,12 @@
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
+#include <drm/ttm/ttm_tt.h>
+
#include "nouveau_mem.h"
#include "nouveau_drv.h"
#include "nouveau_bo.h"
-#include <drm/ttm/ttm_bo_driver.h>
#include <nvif/class.h>
#include <nvif/if000a.h>
diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.h b/drivers/gpu/drm/nouveau/nouveau_mem.h
index 1ee6cdb9ad9b..76c86d8bb01e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_mem.h
+++ b/drivers/gpu/drm/nouveau/nouveau_mem.h
@@ -1,6 +1,6 @@
#ifndef __NOUVEAU_MEM_H__
#define __NOUVEAU_MEM_H__
-#include <drm/ttm/ttm_bo_api.h>
+#include <drm/ttm/ttm_bo.h>
struct ttm_tt;
#include <nvif/mem.h>
diff --git a/drivers/gpu/drm/nouveau/nouveau_prime.c b/drivers/gpu/drm/nouveau/nouveau_prime.c
index 9608121e49b7..f42c2b1b0363 100644
--- a/drivers/gpu/drm/nouveau/nouveau_prime.c
+++ b/drivers/gpu/drm/nouveau/nouveau_prime.c
@@ -23,6 +23,7 @@
*/
#include <linux/dma-buf.h>
+#include <drm/ttm/ttm_tt.h>
#include "nouveau_drv.h"
#include "nouveau_gem.h"
diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
index 85c03c83259b..b14895f75b3c 100644
--- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c
+++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: MIT
#include <linux/pagemap.h>
#include <linux/slab.h>
+#include <drm/ttm/ttm_tt.h>
#include "nouveau_drv.h"
#include "nouveau_mem.h"
diff --git a/drivers/gpu/drm/nouveau/nouveau_vga.c b/drivers/gpu/drm/nouveau/nouveau_vga.c
index 789393b94291..f8bf0ec26844 100644
--- a/drivers/gpu/drm/nouveau/nouveau_vga.c
+++ b/drivers/gpu/drm/nouveau/nouveau_vga.c
@@ -2,7 +2,6 @@
#include <linux/vgaarb.h>
#include <linux/vga_switcheroo.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h>
#include "nouveau_drv.h"
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c
index dd4981708fe4..3d9319c319c6 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c
@@ -51,7 +51,8 @@ u64
nvkm_devinit_disable(struct nvkm_devinit *init)
{
if (init && init->func->disable)
- return init->func->disable(init);
+ init->func->disable(init);
+
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g84.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g84.c
index c224702b7bed..00df7811dd10 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g84.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g84.c
@@ -26,13 +26,12 @@
#include <subdev/bios.h>
#include <subdev/bios/init.h>
-static u64
+static void
g84_devinit_disable(struct nvkm_devinit *init)
{
struct nvkm_device *device = init->subdev.device;
u32 r001540 = nvkm_rd32(device, 0x001540);
u32 r00154c = nvkm_rd32(device, 0x00154c);
- u64 disable = 0ULL;
if (!(r001540 & 0x40000000)) {
nvkm_subdev_disable(device, NVKM_ENGINE_MPEG, 0);
@@ -47,8 +46,6 @@ g84_devinit_disable(struct nvkm_devinit *init)
nvkm_subdev_disable(device, NVKM_ENGINE_BSP, 0);
if (!(r00154c & 0x00000040))
nvkm_subdev_disable(device, NVKM_ENGINE_CIPHER, 0);
-
- return disable;
}
static const struct nvkm_devinit_func
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g98.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g98.c
index 8977483a9f42..54bee499b982 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g98.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g98.c
@@ -26,7 +26,7 @@
#include <subdev/bios.h>
#include <subdev/bios/init.h>
-static u64
+static void
g98_devinit_disable(struct nvkm_devinit *init)
{
struct nvkm_device *device = init->subdev.device;
@@ -45,8 +45,6 @@ g98_devinit_disable(struct nvkm_devinit *init)
nvkm_subdev_disable(device, NVKM_ENGINE_MSVLD, 0);
if (!(r00154c & 0x00000040))
nvkm_subdev_disable(device, NVKM_ENGINE_SEC, 0);
-
- return 0ULL;
}
static const struct nvkm_devinit_func
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c
index 5b7cb1fe7897..5368e705e7fd 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c
@@ -63,7 +63,7 @@ gf100_devinit_pll_set(struct nvkm_devinit *init, u32 type, u32 freq)
return ret;
}
-static u64
+static void
gf100_devinit_disable(struct nvkm_devinit *init)
{
struct nvkm_device *device = init->subdev.device;
@@ -85,8 +85,6 @@ gf100_devinit_disable(struct nvkm_devinit *init)
nvkm_subdev_disable(device, NVKM_ENGINE_CE, 0);
if (r022500 & 0x00000200)
nvkm_subdev_disable(device, NVKM_ENGINE_CE, 1);
-
- return 0ULL;
}
void
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm107.c
index 8955af2704c7..7bcbc4895ec2 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm107.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm107.c
@@ -26,7 +26,7 @@
#include <subdev/bios.h>
#include <subdev/bios/init.h>
-u64
+void
gm107_devinit_disable(struct nvkm_devinit *init)
{
struct nvkm_device *device = init->subdev.device;
@@ -39,8 +39,6 @@ gm107_devinit_disable(struct nvkm_devinit *init)
nvkm_subdev_disable(device, NVKM_ENGINE_CE, 2);
if (r021c04 & 0x00000001)
nvkm_subdev_disable(device, NVKM_ENGINE_DISP, 0);
-
- return 0ULL;
}
static const struct nvkm_devinit_func
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gt215.c
index 3d0ab86c3115..dbca92318baf 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gt215.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gt215.c
@@ -62,7 +62,7 @@ gt215_devinit_pll_set(struct nvkm_devinit *init, u32 type, u32 freq)
return ret;
}
-static u64
+static void
gt215_devinit_disable(struct nvkm_devinit *init)
{
struct nvkm_device *device = init->subdev.device;
@@ -80,8 +80,6 @@ gt215_devinit_disable(struct nvkm_devinit *init)
nvkm_subdev_disable(device, NVKM_ENGINE_MSVLD, 0);
if (!(r00154c & 0x00000200))
nvkm_subdev_disable(device, NVKM_ENGINE_CE, 0);
-
- return 0ULL;
}
static u32
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/mcp89.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/mcp89.c
index a9cdf2411187..a24bd2e7d7ce 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/mcp89.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/mcp89.c
@@ -26,7 +26,7 @@
#include <subdev/bios.h>
#include <subdev/bios/init.h>
-static u64
+static void
mcp89_devinit_disable(struct nvkm_devinit *init)
{
struct nvkm_device *device = init->subdev.device;
@@ -46,8 +46,6 @@ mcp89_devinit_disable(struct nvkm_devinit *init)
nvkm_subdev_disable(device, NVKM_ENGINE_VIC, 0);
if (!(r00154c & 0x00000200))
nvkm_subdev_disable(device, NVKM_ENGINE_CE, 0);
-
- return 0;
}
static const struct nvkm_devinit_func
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c
index 380995d398b1..07ed8fd778b2 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c
@@ -77,17 +77,14 @@ nv50_devinit_pll_set(struct nvkm_devinit *init, u32 type, u32 freq)
return 0;
}
-static u64
+static void
nv50_devinit_disable(struct nvkm_devinit *init)
{
struct nvkm_device *device = init->subdev.device;
u32 r001540 = nvkm_rd32(device, 0x001540);
- u64 disable = 0ULL;
if (!(r001540 & 0x40000000))
nvkm_subdev_disable(device, NVKM_ENGINE_MPEG, 0);
-
- return disable;
}
void
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.h b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.h
index 987a7f478b84..8de409c084c1 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.h
@@ -23,7 +23,7 @@ int gf100_devinit_ctor(struct nvkm_object *, struct nvkm_object *,
int gf100_devinit_pll_set(struct nvkm_devinit *, u32, u32);
void gf100_devinit_preinit(struct nvkm_devinit *);
-u64 gm107_devinit_disable(struct nvkm_devinit *);
+void gm107_devinit_disable(struct nvkm_devinit *);
int gm200_devinit_post(struct nvkm_devinit *, bool);
void gm200_devinit_preos(struct nv50_devinit *, bool);
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/priv.h
index dd8b038a8cee..a648482d06e9 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/priv.h
@@ -12,7 +12,7 @@ struct nvkm_devinit_func {
u32 (*mmio)(struct nvkm_devinit *, u32);
void (*meminit)(struct nvkm_devinit *);
int (*pll_set)(struct nvkm_devinit *, u32 type, u32 freq);
- u64 (*disable)(struct nvkm_devinit *);
+ void (*disable)(struct nvkm_devinit *);
};
void nvkm_devinit_ctor(const struct nvkm_devinit_func *, struct nvkm_device *,
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c
index 648ecf5a8fbc..a4ac94a2ab57 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c
@@ -475,7 +475,8 @@ gk20a_instobj_ctor_iommu(struct gk20a_instmem *imem, u32 npages, u32 align,
u32 offset = (r->offset + i) << imem->iommu_pgshift;
ret = iommu_map(imem->domain, offset, node->dma_addrs[i],
- PAGE_SIZE, IOMMU_READ | IOMMU_WRITE);
+ PAGE_SIZE, IOMMU_READ | IOMMU_WRITE,
+ GFP_KERNEL);
if (ret < 0) {
nvkm_error(subdev, "IOMMU mapping failure: %d\n", ret);
diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c
index 0ee344ebcd1c..aacad5045e95 100644
--- a/drivers/gpu/drm/omapdrm/dss/dispc.c
+++ b/drivers/gpu/drm/omapdrm/dss/dispc.c
@@ -855,11 +855,6 @@ struct csc_coef_yuv2rgb {
bool full_range;
};
-struct csc_coef_rgb2yuv {
- int yr, yg, yb, cbr, cbg, cbb, crr, crg, crb;
- bool full_range;
-};
-
static void dispc_ovl_write_color_conv_coef(struct dispc_device *dispc,
enum omap_plane_id plane,
const struct csc_coef_yuv2rgb *ct)
diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c
index a6845856cbce..4c1084eb0175 100644
--- a/drivers/gpu/drm/omapdrm/dss/dsi.c
+++ b/drivers/gpu/drm/omapdrm/dss/dsi.c
@@ -1039,22 +1039,26 @@ static int dsi_dump_dsi_irqs(struct seq_file *s, void *p)
{
struct dsi_data *dsi = s->private;
unsigned long flags;
- struct dsi_irq_stats stats;
+ struct dsi_irq_stats *stats;
+
+ stats = kmalloc(sizeof(*stats), GFP_KERNEL);
+ if (!stats)
+ return -ENOMEM;
spin_lock_irqsave(&dsi->irq_stats_lock, flags);
- stats = dsi->irq_stats;
+ *stats = dsi->irq_stats;
memset(&dsi->irq_stats, 0, sizeof(dsi->irq_stats));
dsi->irq_stats.last_reset = jiffies;
spin_unlock_irqrestore(&dsi->irq_stats_lock, flags);
seq_printf(s, "period %u ms\n",
- jiffies_to_msecs(jiffies - stats.last_reset));
+ jiffies_to_msecs(jiffies - stats->last_reset));
- seq_printf(s, "irqs %d\n", stats.irq_count);
+ seq_printf(s, "irqs %d\n", stats->irq_count);
#define PIS(x) \
- seq_printf(s, "%-20s %10d\n", #x, stats.dsi_irqs[ffs(DSI_IRQ_##x)-1]);
+ seq_printf(s, "%-20s %10d\n", #x, stats->dsi_irqs[ffs(DSI_IRQ_##x)-1]);
seq_printf(s, "-- DSI%d interrupts --\n", dsi->module_id + 1);
PIS(VC0);
@@ -1078,10 +1082,10 @@ static int dsi_dump_dsi_irqs(struct seq_file *s, void *p)
#define PIS(x) \
seq_printf(s, "%-20s %10d %10d %10d %10d\n", #x, \
- stats.vc_irqs[0][ffs(DSI_VC_IRQ_##x)-1], \
- stats.vc_irqs[1][ffs(DSI_VC_IRQ_##x)-1], \
- stats.vc_irqs[2][ffs(DSI_VC_IRQ_##x)-1], \
- stats.vc_irqs[3][ffs(DSI_VC_IRQ_##x)-1]);
+ stats->vc_irqs[0][ffs(DSI_VC_IRQ_##x)-1], \
+ stats->vc_irqs[1][ffs(DSI_VC_IRQ_##x)-1], \
+ stats->vc_irqs[2][ffs(DSI_VC_IRQ_##x)-1], \
+ stats->vc_irqs[3][ffs(DSI_VC_IRQ_##x)-1]);
seq_printf(s, "-- VC interrupts --\n");
PIS(CS);
@@ -1097,7 +1101,7 @@ static int dsi_dump_dsi_irqs(struct seq_file *s, void *p)
#define PIS(x) \
seq_printf(s, "%-20s %10d\n", #x, \
- stats.cio_irqs[ffs(DSI_CIO_IRQ_##x)-1]);
+ stats->cio_irqs[ffs(DSI_CIO_IRQ_##x)-1]);
seq_printf(s, "-- CIO interrupts --\n");
PIS(ERRSYNCESC1);
@@ -1122,6 +1126,8 @@ static int dsi_dump_dsi_irqs(struct seq_file *s, void *p)
PIS(ULPSACTIVENOT_ALL1);
#undef PIS
+ kfree(stats);
+
return 0;
}
#endif
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
index eaf67b9e5f12..699ed814e021 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -546,44 +546,6 @@ static void omap_modeset_fini(struct drm_device *ddev)
}
/*
- * Enable the HPD in external components if supported
- */
-static void omap_modeset_enable_external_hpd(struct drm_device *ddev)
-{
- struct omap_drm_private *priv = ddev->dev_private;
- unsigned int i;
-
- for (i = 0; i < priv->num_pipes; i++) {
- struct drm_connector *connector = priv->pipes[i].connector;
-
- if (!connector)
- continue;
-
- if (priv->pipes[i].output->bridge)
- drm_bridge_connector_enable_hpd(connector);
- }
-}
-
-/*
- * Disable the HPD in external components if supported
- */
-static void omap_modeset_disable_external_hpd(struct drm_device *ddev)
-{
- struct omap_drm_private *priv = ddev->dev_private;
- unsigned int i;
-
- for (i = 0; i < priv->num_pipes; i++) {
- struct drm_connector *connector = priv->pipes[i].connector;
-
- if (!connector)
- continue;
-
- if (priv->pipes[i].output->bridge)
- drm_bridge_connector_disable_hpd(connector);
- }
-}
-
-/*
* drm ioctl funcs
*/
@@ -782,7 +744,6 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev)
omap_fbdev_init(ddev);
drm_kms_helper_poll_init(ddev);
- omap_modeset_enable_external_hpd(ddev);
/*
* Register the DRM device with the core and the connectors with
@@ -795,7 +756,6 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev)
return 0;
err_cleanup_helpers:
- omap_modeset_disable_external_hpd(ddev);
drm_kms_helper_poll_fini(ddev);
omap_fbdev_fini(ddev);
@@ -822,7 +782,6 @@ static void omapdrm_cleanup(struct omap_drm_private *priv)
drm_dev_unregister(ddev);
- omap_modeset_disable_external_hpd(ddev);
drm_kms_helper_poll_fini(ddev);
omap_fbdev_fini(ddev);
diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c
index 98d8758048fc..a6c8542087ec 100644
--- a/drivers/gpu/drm/omapdrm/omap_fbdev.c
+++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c
@@ -233,19 +233,19 @@ void omap_fbdev_init(struct drm_device *dev)
fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL);
if (!fbdev)
- goto fail;
+ return;
INIT_WORK(&fbdev->work, pan_worker);
helper = &fbdev->base;
- drm_fb_helper_prepare(dev, helper, &omap_fb_helper_funcs);
+ drm_fb_helper_prepare(dev, helper, 32, &omap_fb_helper_funcs);
ret = drm_fb_helper_init(dev, helper);
if (ret)
goto fail;
- ret = drm_fb_helper_initial_config(helper, 32);
+ ret = drm_fb_helper_initial_config(helper);
if (ret)
goto fini;
@@ -256,6 +256,7 @@ void omap_fbdev_init(struct drm_device *dev)
fini:
drm_fb_helper_fini(helper);
fail:
+ drm_fb_helper_unprepare(helper);
kfree(fbdev);
dev_warn(dev->dev, "omap_fbdev_init failed\n");
@@ -286,6 +287,7 @@ void omap_fbdev_fini(struct drm_device *dev)
if (fbdev->fb)
drm_framebuffer_remove(fbdev->fb);
+ drm_fb_helper_unprepare(helper);
kfree(fbdev);
priv->fbdev = NULL;
diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c
index cf571796fd26..6b58a5bb7b44 100644
--- a/drivers/gpu/drm/omapdrm/omap_gem.c
+++ b/drivers/gpu/drm/omapdrm/omap_gem.c
@@ -543,8 +543,7 @@ int omap_gem_mmap_obj(struct drm_gem_object *obj,
{
struct omap_gem_object *omap_obj = to_omap_bo(obj);
- vma->vm_flags &= ~VM_PFNMAP;
- vma->vm_flags |= VM_MIXEDMAP;
+ vm_flags_mod(vma, VM_MIXEDMAP, VM_PFNMAP);
if (omap_obj->flags & OMAP_BO_WC) {
vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
@@ -605,7 +604,7 @@ int omap_gem_dumb_create(struct drm_file *file, struct drm_device *dev,
}
/**
- * omap_gem_dumb_map - buffer mapping for dumb interface
+ * omap_gem_dumb_map_offset - create an offset for a dumb buffer
* @file: our drm client file
* @dev: drm device
* @handle: GEM handle to the object (from dumb_create)
diff --git a/drivers/gpu/drm/omapdrm/omap_irq.c b/drivers/gpu/drm/omapdrm/omap_irq.c
index 4aca14dab927..a6f0bbc879d2 100644
--- a/drivers/gpu/drm/omapdrm/omap_irq.c
+++ b/drivers/gpu/drm/omapdrm/omap_irq.c
@@ -99,7 +99,7 @@ int omap_irq_enable_framedone(struct drm_crtc *crtc, bool enable)
}
/**
- * enable_vblank - enable vblank interrupt events
+ * omap_irq_enable_vblank - enable vblank interrupt events
* @crtc: DRM CRTC
*
* Enable vblank interrupts for @crtc. If the device doesn't have
@@ -129,7 +129,7 @@ int omap_irq_enable_vblank(struct drm_crtc *crtc)
}
/**
- * disable_vblank - disable vblank interrupt events
+ * omap_irq_disable_vblank - disable vblank interrupt events
* @crtc: DRM CRTC
*
* Disable vblank interrupts for @crtc. If the device doesn't have
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index 737edcdf9eef..8eeee71c0000 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -37,6 +37,14 @@ config DRM_PANEL_ASUS_Z00T_TM5P5_NT35596
NT35596 1080x1920 video mode panel as found in some Asus
Zenfone 2 Laser Z00T devices.
+config DRM_PANEL_AUO_A030JTN01
+ tristate "AUO A030JTN01"
+ depends on SPI
+ select REGMAP_SPI
+ help
+ Say Y here to enable support for the AUO A030JTN01 320x480 3.0" panel
+ as found in the YLM RS-97 handheld gaming console.
+
config DRM_PANEL_BOE_BF060Y8M_AJ0
tristate "Boe BF060Y8M-AJ0 panel"
depends on OF
@@ -154,6 +162,18 @@ config DRM_PANEL_FEIYANG_FY07024DI26A30D
Say Y if you want to enable support for panels based on the
Feiyang FY07024DI26A30-D MIPI-DSI interface.
+config DRM_PANEL_HIMAX_HX8394
+ tristate "HIMAX HX8394 MIPI-DSI LCD panels"
+ depends on OF
+ depends on DRM_MIPI_DSI
+ depends on BACKLIGHT_CLASS_DEVICE
+ help
+ Say Y if you want to enable support for panels based on the
+ Himax HX8394 controller, such as the HannStar HSD060BHW4
+ 720x1440 TFT LCD panel that uses a MIPI-DSI interface.
+
+ If M is selected the module will be called panel-himax-hx8394.
+
config DRM_PANEL_ILITEK_IL9322
tristate "Ilitek ILI9322 320x240 QVGA panels"
depends on OF && SPI
@@ -400,6 +420,15 @@ config DRM_PANEL_OLIMEX_LCD_OLINUXINO
Say Y here if you want to enable support for Olimex Ltd.
LCD-OLinuXino panel.
+config DRM_PANEL_ORISETECH_OTA5601A
+ tristate "Orise Technology ota5601a RGB/SPI panel"
+ depends on SPI
+ depends on BACKLIGHT_CLASS_DEVICE
+ select REGMAP_SPI
+ help
+ Say Y here if you want to enable support for the panels built
+ around the Orise Technology OTA9601A display controller.
+
config DRM_PANEL_ORISETECH_OTM8009A
tristate "Orise Technology otm8009a 480x800 dsi 2dl panel"
depends on OF
@@ -717,6 +746,15 @@ config DRM_PANEL_VISIONOX_RM69299
Say Y here if you want to enable support for Visionox
RM69299 DSI Video Mode panel.
+config DRM_PANEL_VISIONOX_VTDR6130
+ tristate "Visionox VTDR6130"
+ depends on OF
+ depends on DRM_MIPI_DSI
+ depends on BACKLIGHT_CLASS_DEVICE
+ help
+ Say Y here if you want to enable support for Visionox
+ VTDR6130 1080x2400 AMOLED DSI panel.
+
config DRM_PANEL_WIDECHIPS_WS2401
tristate "Widechips WS2401 DPI panel driver"
depends on SPI && GPIOLIB
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index f8f9d9f6a307..c05aa9e23907 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -2,6 +2,7 @@
obj-$(CONFIG_DRM_PANEL_ABT_Y030XX067A) += panel-abt-y030xx067a.o
obj-$(CONFIG_DRM_PANEL_ARM_VERSATILE) += panel-arm-versatile.o
obj-$(CONFIG_DRM_PANEL_ASUS_Z00T_TM5P5_NT35596) += panel-asus-z00t-tm5p5-n35596.o
+obj-$(CONFIG_DRM_PANEL_AUO_A030JTN01) += panel-auo-a030jtn01.o
obj-$(CONFIG_DRM_PANEL_BOE_BF060Y8M_AJ0) += panel-boe-bf060y8m-aj0.o
obj-$(CONFIG_DRM_PANEL_BOE_HIMAX8279D) += panel-boe-himax8279d.o
obj-$(CONFIG_DRM_PANEL_BOE_TV101WUM_NL6) += panel-boe-tv101wum-nl6.o
@@ -13,6 +14,7 @@ obj-$(CONFIG_DRM_PANEL_EBBG_FT8719) += panel-ebbg-ft8719.o
obj-$(CONFIG_DRM_PANEL_ELIDA_KD35T133) += panel-elida-kd35t133.o
obj-$(CONFIG_DRM_PANEL_FEIXIN_K101_IM2BA02) += panel-feixin-k101-im2ba02.o
obj-$(CONFIG_DRM_PANEL_FEIYANG_FY07024DI26A30D) += panel-feiyang-fy07024di26a30d.o
+obj-$(CONFIG_DRM_PANEL_HIMAX_HX8394) += panel-himax-hx8394.o
obj-$(CONFIG_DRM_PANEL_ILITEK_IL9322) += panel-ilitek-ili9322.o
obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9341) += panel-ilitek-ili9341.o
obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9881C) += panel-ilitek-ili9881c.o
@@ -37,6 +39,7 @@ obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36672A) += panel-novatek-nt36672a.o
obj-$(CONFIG_DRM_PANEL_NOVATEK_NT39016) += panel-novatek-nt39016.o
obj-$(CONFIG_DRM_PANEL_MANTIX_MLAF057WE51) += panel-mantix-mlaf057we51.o
obj-$(CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO) += panel-olimex-lcd-olinuxino.o
+obj-$(CONFIG_DRM_PANEL_ORISETECH_OTA5601A) += panel-orisetech-ota5601a.o
obj-$(CONFIG_DRM_PANEL_ORISETECH_OTM8009A) += panel-orisetech-otm8009a.o
obj-$(CONFIG_DRM_PANEL_OSD_OSD101T2587_53TS) += panel-osd-osd101t2587-53ts.o
obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) += panel-panasonic-vvx10f034n00.o
@@ -73,5 +76,6 @@ obj-$(CONFIG_DRM_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o
obj-$(CONFIG_DRM_PANEL_TPO_TPG110) += panel-tpo-tpg110.o
obj-$(CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA) += panel-truly-nt35597.o
obj-$(CONFIG_DRM_PANEL_VISIONOX_RM69299) += panel-visionox-rm69299.o
+obj-$(CONFIG_DRM_PANEL_VISIONOX_VTDR6130) += panel-visionox-vtdr6130.o
obj-$(CONFIG_DRM_PANEL_WIDECHIPS_WS2401) += panel-widechips-ws2401.o
obj-$(CONFIG_DRM_PANEL_XINPENG_XPP055C272) += panel-xinpeng-xpp055c272.o
diff --git a/drivers/gpu/drm/panel/panel-asus-z00t-tm5p5-n35596.c b/drivers/gpu/drm/panel/panel-asus-z00t-tm5p5-n35596.c
index b3235781e6ba..075a7af81eff 100644
--- a/drivers/gpu/drm/panel/panel-asus-z00t-tm5p5-n35596.c
+++ b/drivers/gpu/drm/panel/panel-asus-z00t-tm5p5-n35596.c
@@ -24,22 +24,6 @@ static inline struct tm5p5_nt35596 *to_tm5p5_nt35596(struct drm_panel *panel)
return container_of(panel, struct tm5p5_nt35596, panel);
}
-#define dsi_generic_write_seq(dsi, seq...) do { \
- static const u8 d[] = { seq }; \
- int ret; \
- ret = mipi_dsi_generic_write(dsi, d, ARRAY_SIZE(d)); \
- if (ret < 0) \
- return ret; \
- } while (0)
-
-#define dsi_dcs_write_seq(dsi, seq...) do { \
- static const u8 d[] = { seq }; \
- int ret; \
- ret = mipi_dsi_dcs_write_buffer(dsi, d, ARRAY_SIZE(d)); \
- if (ret < 0) \
- return ret; \
- } while (0)
-
static void tm5p5_nt35596_reset(struct tm5p5_nt35596 *ctx)
{
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
@@ -54,46 +38,46 @@ static int tm5p5_nt35596_on(struct tm5p5_nt35596 *ctx)
{
struct mipi_dsi_device *dsi = ctx->dsi;
- dsi_generic_write_seq(dsi, 0xff, 0x05);
- dsi_generic_write_seq(dsi, 0xfb, 0x01);
- dsi_generic_write_seq(dsi, 0xc5, 0x31);
- dsi_generic_write_seq(dsi, 0xff, 0x04);
- dsi_generic_write_seq(dsi, 0x01, 0x84);
- dsi_generic_write_seq(dsi, 0x05, 0x25);
- dsi_generic_write_seq(dsi, 0x06, 0x01);
- dsi_generic_write_seq(dsi, 0x07, 0x20);
- dsi_generic_write_seq(dsi, 0x08, 0x06);
- dsi_generic_write_seq(dsi, 0x09, 0x08);
- dsi_generic_write_seq(dsi, 0x0a, 0x10);
- dsi_generic_write_seq(dsi, 0x0b, 0x10);
- dsi_generic_write_seq(dsi, 0x0c, 0x10);
- dsi_generic_write_seq(dsi, 0x0d, 0x14);
- dsi_generic_write_seq(dsi, 0x0e, 0x14);
- dsi_generic_write_seq(dsi, 0x0f, 0x14);
- dsi_generic_write_seq(dsi, 0x10, 0x14);
- dsi_generic_write_seq(dsi, 0x11, 0x14);
- dsi_generic_write_seq(dsi, 0x12, 0x14);
- dsi_generic_write_seq(dsi, 0x17, 0xf3);
- dsi_generic_write_seq(dsi, 0x18, 0xc0);
- dsi_generic_write_seq(dsi, 0x19, 0xc0);
- dsi_generic_write_seq(dsi, 0x1a, 0xc0);
- dsi_generic_write_seq(dsi, 0x1b, 0xb3);
- dsi_generic_write_seq(dsi, 0x1c, 0xb3);
- dsi_generic_write_seq(dsi, 0x1d, 0xb3);
- dsi_generic_write_seq(dsi, 0x1e, 0xb3);
- dsi_generic_write_seq(dsi, 0x1f, 0xb3);
- dsi_generic_write_seq(dsi, 0x20, 0xb3);
- dsi_generic_write_seq(dsi, 0xfb, 0x01);
- dsi_generic_write_seq(dsi, 0xff, 0x00);
- dsi_generic_write_seq(dsi, 0xfb, 0x01);
- dsi_generic_write_seq(dsi, 0x35, 0x01);
- dsi_generic_write_seq(dsi, 0xd3, 0x06);
- dsi_generic_write_seq(dsi, 0xd4, 0x04);
- dsi_generic_write_seq(dsi, 0x5e, 0x0d);
- dsi_generic_write_seq(dsi, 0x11, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xff, 0x05);
+ mipi_dsi_generic_write_seq(dsi, 0xfb, 0x01);
+ mipi_dsi_generic_write_seq(dsi, 0xc5, 0x31);
+ mipi_dsi_generic_write_seq(dsi, 0xff, 0x04);
+ mipi_dsi_generic_write_seq(dsi, 0x01, 0x84);
+ mipi_dsi_generic_write_seq(dsi, 0x05, 0x25);
+ mipi_dsi_generic_write_seq(dsi, 0x06, 0x01);
+ mipi_dsi_generic_write_seq(dsi, 0x07, 0x20);
+ mipi_dsi_generic_write_seq(dsi, 0x08, 0x06);
+ mipi_dsi_generic_write_seq(dsi, 0x09, 0x08);
+ mipi_dsi_generic_write_seq(dsi, 0x0a, 0x10);
+ mipi_dsi_generic_write_seq(dsi, 0x0b, 0x10);
+ mipi_dsi_generic_write_seq(dsi, 0x0c, 0x10);
+ mipi_dsi_generic_write_seq(dsi, 0x0d, 0x14);
+ mipi_dsi_generic_write_seq(dsi, 0x0e, 0x14);
+ mipi_dsi_generic_write_seq(dsi, 0x0f, 0x14);
+ mipi_dsi_generic_write_seq(dsi, 0x10, 0x14);
+ mipi_dsi_generic_write_seq(dsi, 0x11, 0x14);
+ mipi_dsi_generic_write_seq(dsi, 0x12, 0x14);
+ mipi_dsi_generic_write_seq(dsi, 0x17, 0xf3);
+ mipi_dsi_generic_write_seq(dsi, 0x18, 0xc0);
+ mipi_dsi_generic_write_seq(dsi, 0x19, 0xc0);
+ mipi_dsi_generic_write_seq(dsi, 0x1a, 0xc0);
+ mipi_dsi_generic_write_seq(dsi, 0x1b, 0xb3);
+ mipi_dsi_generic_write_seq(dsi, 0x1c, 0xb3);
+ mipi_dsi_generic_write_seq(dsi, 0x1d, 0xb3);
+ mipi_dsi_generic_write_seq(dsi, 0x1e, 0xb3);
+ mipi_dsi_generic_write_seq(dsi, 0x1f, 0xb3);
+ mipi_dsi_generic_write_seq(dsi, 0x20, 0xb3);
+ mipi_dsi_generic_write_seq(dsi, 0xfb, 0x01);
+ mipi_dsi_generic_write_seq(dsi, 0xff, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xfb, 0x01);
+ mipi_dsi_generic_write_seq(dsi, 0x35, 0x01);
+ mipi_dsi_generic_write_seq(dsi, 0xd3, 0x06);
+ mipi_dsi_generic_write_seq(dsi, 0xd4, 0x04);
+ mipi_dsi_generic_write_seq(dsi, 0x5e, 0x0d);
+ mipi_dsi_generic_write_seq(dsi, 0x11, 0x00);
msleep(100);
- dsi_generic_write_seq(dsi, 0x29, 0x00);
- dsi_generic_write_seq(dsi, 0x53, 0x24);
+ mipi_dsi_generic_write_seq(dsi, 0x29, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0x53, 0x24);
return 0;
}
@@ -117,7 +101,7 @@ static int tm5p5_nt35596_off(struct tm5p5_nt35596 *ctx)
return ret;
}
- dsi_dcs_write_seq(dsi, 0x4f, 0x01);
+ mipi_dsi_dcs_write_seq(dsi, 0x4f, 0x01);
return 0;
}
diff --git a/drivers/gpu/drm/panel/panel-auo-a030jtn01.c b/drivers/gpu/drm/panel/panel-auo-a030jtn01.c
new file mode 100644
index 000000000000..3c976a98de6a
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-auo-a030jtn01.c
@@ -0,0 +1,308 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * AU Optronics A030JTN01.0 TFT LCD panel driver
+ *
+ * Copyright (C) 2023, Paul Cercueil <paul@crapouillou.net>
+ * Copyright (C) 2023, Christophe Branchereau <cbranchereau@gmail.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/media-bus-format.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+
+#include <drm/drm_modes.h>
+#include <drm/drm_panel.h>
+
+#define REG05 0x05
+#define REG06 0x06
+#define REG07 0x07
+
+#define REG05_STDBY BIT(0)
+#define REG06_VBLK GENMASK(4, 0)
+#define REG07_HBLK GENMASK(7, 0)
+
+
+struct a030jtn01_info {
+ const struct drm_display_mode *display_modes;
+ unsigned int num_modes;
+ u16 width_mm, height_mm;
+ u32 bus_format, bus_flags;
+};
+
+struct a030jtn01 {
+ struct drm_panel panel;
+ struct spi_device *spi;
+ struct regmap *map;
+
+ const struct a030jtn01_info *panel_info;
+
+ struct regulator *supply;
+ struct gpio_desc *reset_gpio;
+};
+
+static inline struct a030jtn01 *to_a030jtn01(struct drm_panel *panel)
+{
+ return container_of(panel, struct a030jtn01, panel);
+}
+
+static int a030jtn01_prepare(struct drm_panel *panel)
+{
+ struct a030jtn01 *priv = to_a030jtn01(panel);
+ struct device *dev = &priv->spi->dev;
+ unsigned int dummy;
+ int err;
+
+ err = regulator_enable(priv->supply);
+ if (err) {
+ dev_err(dev, "Failed to enable power supply: %d\n", err);
+ return err;
+ }
+
+ usleep_range(1000, 8000);
+
+ /* Reset the chip */
+ gpiod_set_value_cansleep(priv->reset_gpio, 1);
+ usleep_range(100, 8000);
+ gpiod_set_value_cansleep(priv->reset_gpio, 0);
+ usleep_range(2000, 8000);
+
+ /*
+ * No idea why, but a register read (doesn't matter which) is needed to
+ * properly initialize the chip after a reset; otherwise, the colors
+ * will be wrong. It doesn't seem to be timing-related as a msleep(200)
+ * doesn't fix it.
+ */
+ err = regmap_read(priv->map, REG05, &dummy);
+ if (err)
+ goto err_disable_regulator;
+
+ /* Use (24 + 6) == 0x1e as the vertical back porch */
+ err = regmap_write(priv->map, REG06, FIELD_PREP(REG06_VBLK, 0x1e));
+ if (err)
+ goto err_disable_regulator;
+
+ /* Use (42 + 30) * 3 == 0xd8 as the horizontal back porch */
+ err = regmap_write(priv->map, REG07, FIELD_PREP(REG07_HBLK, 0xd8));
+ if (err)
+ goto err_disable_regulator;
+
+ return 0;
+
+err_disable_regulator:
+ gpiod_set_value_cansleep(priv->reset_gpio, 1);
+ regulator_disable(priv->supply);
+ return err;
+}
+
+static int a030jtn01_unprepare(struct drm_panel *panel)
+{
+ struct a030jtn01 *priv = to_a030jtn01(panel);
+
+ gpiod_set_value_cansleep(priv->reset_gpio, 1);
+ regulator_disable(priv->supply);
+
+ return 0;
+}
+
+static int a030jtn01_enable(struct drm_panel *panel)
+{
+ struct a030jtn01 *priv = to_a030jtn01(panel);
+ int ret;
+
+ ret = regmap_set_bits(priv->map, REG05, REG05_STDBY);
+ if (ret)
+ return ret;
+
+ /* Wait for the picture to be stable */
+ if (panel->backlight)
+ msleep(100);
+
+ return 0;
+}
+
+static int a030jtn01_disable(struct drm_panel *panel)
+{
+ struct a030jtn01 *priv = to_a030jtn01(panel);
+
+ return regmap_clear_bits(priv->map, REG05, REG05_STDBY);
+}
+
+static int a030jtn01_get_modes(struct drm_panel *panel,
+ struct drm_connector *connector)
+{
+ struct a030jtn01 *priv = to_a030jtn01(panel);
+ const struct a030jtn01_info *panel_info = priv->panel_info;
+ struct drm_display_mode *mode;
+ unsigned int i;
+
+ for (i = 0; i < panel_info->num_modes; i++) {
+ mode = drm_mode_duplicate(connector->dev,
+ &panel_info->display_modes[i]);
+ if (!mode)
+ return -ENOMEM;
+
+ drm_mode_set_name(mode);
+
+ mode->type = DRM_MODE_TYPE_DRIVER;
+ if (panel_info->num_modes == 1)
+ mode->type |= DRM_MODE_TYPE_PREFERRED;
+
+ drm_mode_probed_add(connector, mode);
+ }
+
+ connector->display_info.bpc = 8;
+ connector->display_info.width_mm = panel_info->width_mm;
+ connector->display_info.height_mm = panel_info->height_mm;
+
+ drm_display_info_set_bus_formats(&connector->display_info,
+ &panel_info->bus_format, 1);
+ connector->display_info.bus_flags = panel_info->bus_flags;
+
+ return panel_info->num_modes;
+}
+
+static const struct drm_panel_funcs a030jtn01_funcs = {
+ .prepare = a030jtn01_prepare,
+ .unprepare = a030jtn01_unprepare,
+ .enable = a030jtn01_enable,
+ .disable = a030jtn01_disable,
+ .get_modes = a030jtn01_get_modes,
+};
+
+static bool a030jtn01_has_reg(struct device *dev, unsigned int reg)
+{
+ static const u32 a030jtn01_regs_mask = 0x001823f1fb;
+
+ return a030jtn01_regs_mask & BIT(reg);
+};
+
+static const struct regmap_config a030jtn01_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .read_flag_mask = 0x40,
+ .max_register = 0x1c,
+ .readable_reg = a030jtn01_has_reg,
+ .writeable_reg = a030jtn01_has_reg,
+};
+
+static int a030jtn01_probe(struct spi_device *spi)
+{
+ struct device *dev = &spi->dev;
+ struct a030jtn01 *priv;
+ int err;
+
+ spi->mode |= SPI_MODE_3 | SPI_3WIRE;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->spi = spi;
+ spi_set_drvdata(spi, priv);
+
+ priv->map = devm_regmap_init_spi(spi, &a030jtn01_regmap_config);
+ if (IS_ERR(priv->map))
+ return dev_err_probe(dev, PTR_ERR(priv->map), "Unable to init regmap");
+
+ priv->panel_info = spi_get_device_match_data(spi);
+ if (!priv->panel_info)
+ return -EINVAL;
+
+ priv->supply = devm_regulator_get(dev, "power");
+ if (IS_ERR(priv->supply))
+ return dev_err_probe(dev, PTR_ERR(priv->supply), "Failed to get power supply");
+
+ priv->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(priv->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(priv->reset_gpio), "Failed to get reset GPIO");
+
+ drm_panel_init(&priv->panel, dev, &a030jtn01_funcs,
+ DRM_MODE_CONNECTOR_DPI);
+
+ err = drm_panel_of_backlight(&priv->panel);
+ if (err)
+ return err;
+
+ drm_panel_add(&priv->panel);
+
+ return 0;
+}
+
+static void a030jtn01_remove(struct spi_device *spi)
+{
+ struct a030jtn01 *priv = spi_get_drvdata(spi);
+
+ drm_panel_remove(&priv->panel);
+ drm_panel_disable(&priv->panel);
+ drm_panel_unprepare(&priv->panel);
+}
+
+static const struct drm_display_mode a030jtn01_modes[] = {
+ { /* 60 Hz */
+ .clock = 14400,
+ .hdisplay = 320,
+ .hsync_start = 320 + 8,
+ .hsync_end = 320 + 8 + 42,
+ .htotal = 320 + 8 + 42 + 30,
+ .vdisplay = 480,
+ .vsync_start = 480 + 90,
+ .vsync_end = 480 + 90 + 24,
+ .vtotal = 480 + 90 + 24 + 6,
+ .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+ },
+ { /* 50 Hz */
+ .clock = 12000,
+ .hdisplay = 320,
+ .hsync_start = 320 + 8,
+ .hsync_end = 320 + 8 + 42,
+ .htotal = 320 + 8 + 42 + 30,
+ .vdisplay = 480,
+ .vsync_start = 480 + 90,
+ .vsync_end = 480 + 90 + 24,
+ .vtotal = 480 + 90 + 24 + 6,
+ .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+ },
+};
+
+static const struct a030jtn01_info a030jtn01_info = {
+ .display_modes = a030jtn01_modes,
+ .num_modes = ARRAY_SIZE(a030jtn01_modes),
+ .width_mm = 70,
+ .height_mm = 51,
+ .bus_format = MEDIA_BUS_FMT_RGB888_3X8_DELTA,
+ .bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE,
+};
+
+static const struct spi_device_id a030jtn01_id[] = {
+ { "a030jtn01", (kernel_ulong_t) &a030jtn01_info },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(spi, a030jtn01_id);
+
+static const struct of_device_id a030jtn01_of_match[] = {
+ { .compatible = "auo,a030jtn01" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, a030jtn01_of_match);
+
+static struct spi_driver a030jtn01_driver = {
+ .driver = {
+ .name = "auo-a030jtn01",
+ .of_match_table = a030jtn01_of_match,
+ },
+ .id_table = a030jtn01_id,
+ .probe = a030jtn01_probe,
+ .remove = a030jtn01_remove,
+};
+module_spi_driver(a030jtn01_driver);
+
+MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>");
+MODULE_AUTHOR("Christophe Branchereau <cbranchereau@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/panel/panel-boe-bf060y8m-aj0.c b/drivers/gpu/drm/panel/panel-boe-bf060y8m-aj0.c
index ad58840eda41..90098b753e3b 100644
--- a/drivers/gpu/drm/panel/panel-boe-bf060y8m-aj0.c
+++ b/drivers/gpu/drm/panel/panel-boe-bf060y8m-aj0.c
@@ -43,14 +43,6 @@ struct boe_bf060y8m_aj0 *to_boe_bf060y8m_aj0(struct drm_panel *panel)
return container_of(panel, struct boe_bf060y8m_aj0, panel);
}
-#define dsi_dcs_write_seq(dsi, seq...) do { \
- static const u8 d[] = { seq }; \
- int ret; \
- ret = mipi_dsi_dcs_write_buffer(dsi, d, ARRAY_SIZE(d)); \
- if (ret < 0) \
- return ret; \
- } while (0)
-
static void boe_bf060y8m_aj0_reset(struct boe_bf060y8m_aj0 *boe)
{
gpiod_set_value_cansleep(boe->reset_gpio, 0);
@@ -67,12 +59,12 @@ static int boe_bf060y8m_aj0_on(struct boe_bf060y8m_aj0 *boe)
struct device *dev = &dsi->dev;
int ret;
- dsi_dcs_write_seq(dsi, 0xb0, 0xa5, 0x00);
- dsi_dcs_write_seq(dsi, 0xb2, 0x00, 0x4c);
- dsi_dcs_write_seq(dsi, MIPI_DCS_SET_3D_CONTROL, 0x10);
- dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_POWER_SAVE, DCS_ALLOW_HBM_RANGE);
- dsi_dcs_write_seq(dsi, 0xf8,
- 0x00, 0x08, 0x10, 0x00, 0x22, 0x00, 0x00, 0x2d);
+ mipi_dsi_dcs_write_seq(dsi, 0xb0, 0xa5, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, 0xb2, 0x00, 0x4c);
+ mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_3D_CONTROL, 0x10);
+ mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_POWER_SAVE, DCS_ALLOW_HBM_RANGE);
+ mipi_dsi_dcs_write_seq(dsi, 0xf8,
+ 0x00, 0x08, 0x10, 0x00, 0x22, 0x00, 0x00, 0x2d);
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
if (ret < 0) {
@@ -81,17 +73,17 @@ static int boe_bf060y8m_aj0_on(struct boe_bf060y8m_aj0 *boe)
}
msleep(30);
- dsi_dcs_write_seq(dsi, 0xb0, 0xa5, 0x00);
- dsi_dcs_write_seq(dsi, 0xc0,
- 0x08, 0x48, 0x65, 0x33, 0x33, 0x33,
- 0x2a, 0x31, 0x39, 0x20, 0x09);
- dsi_dcs_write_seq(dsi, 0xc1, 0x00, 0x00, 0x00, 0x1f, 0x1f,
- 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
- 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
- dsi_dcs_write_seq(dsi, 0xe2, 0x20, 0x04, 0x10, 0x12, 0x92,
- 0x4f, 0x8f, 0x44, 0x84, 0x83, 0x83, 0x83,
- 0x5c, 0x5c, 0x5c);
- dsi_dcs_write_seq(dsi, 0xde, 0x01, 0x2c, 0x00, 0x77, 0x3e);
+ mipi_dsi_dcs_write_seq(dsi, 0xb0, 0xa5, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, 0xc0,
+ 0x08, 0x48, 0x65, 0x33, 0x33, 0x33,
+ 0x2a, 0x31, 0x39, 0x20, 0x09);
+ mipi_dsi_dcs_write_seq(dsi, 0xc1, 0x00, 0x00, 0x00, 0x1f, 0x1f,
+ 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
+ 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
+ mipi_dsi_dcs_write_seq(dsi, 0xe2, 0x20, 0x04, 0x10, 0x12, 0x92,
+ 0x4f, 0x8f, 0x44, 0x84, 0x83, 0x83, 0x83,
+ 0x5c, 0x5c, 0x5c);
+ mipi_dsi_dcs_write_seq(dsi, 0xde, 0x01, 0x2c, 0x00, 0x77, 0x3e);
msleep(30);
diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c
index 5cb8dc2ebe18..01bfe0783304 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -351,7 +351,7 @@ static void panel_edp_wait(ktime_t start_ktime, unsigned int min_ms)
return;
min_ktime = ktime_add(start_ktime, ms_to_ktime(min_ms));
- now_ktime = ktime_get();
+ now_ktime = ktime_get_boottime();
if (ktime_before(now_ktime, min_ktime))
msleep(ktime_to_ms(ktime_sub(min_ktime, now_ktime)) + 1);
@@ -378,7 +378,7 @@ static int panel_edp_suspend(struct device *dev)
gpiod_set_value_cansleep(p->enable_gpio, 0);
regulator_disable(p->supply);
- p->unprepared_time = ktime_get();
+ p->unprepared_time = ktime_get_boottime();
return 0;
}
@@ -464,14 +464,14 @@ static int panel_edp_prepare_once(struct panel_edp *p)
}
}
- p->prepared_time = ktime_get();
+ p->prepared_time = ktime_get_boottime();
return 0;
error:
gpiod_set_value_cansleep(p->enable_gpio, 0);
regulator_disable(p->supply);
- p->unprepared_time = ktime_get();
+ p->unprepared_time = ktime_get_boottime();
return err;
}
@@ -1891,7 +1891,8 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1247, &delay_200_500_e80_d50, "N120ACA-EA1"),
EDP_PANEL_ENTRY('I', 'V', 'O', 0x057d, &delay_200_500_e200, "R140NWF5 RH"),
- EDP_PANEL_ENTRY('I', 'V', 'O', 0x854b, &delay_200_500_p2e100, "M133NW4J-R3"),
+ EDP_PANEL_ENTRY('I', 'V', 'O', 0x854a, &delay_200_500_p2e100, "M133NW4J"),
+ EDP_PANEL_ENTRY('I', 'V', 'O', 0x854b, &delay_200_500_p2e100, "R133NW4K-R0"),
EDP_PANEL_ENTRY('K', 'D', 'B', 0x0624, &kingdisplay_kd116n21_30nv_a010.delay, "116N21-30NV-A010"),
EDP_PANEL_ENTRY('K', 'D', 'B', 0x1120, &delay_200_500_e80_d50, "116N29-30NK-C007"),
diff --git a/drivers/gpu/drm/panel/panel-elida-kd35t133.c b/drivers/gpu/drm/panel/panel-elida-kd35t133.c
index eee714cf3f49..e7be15b68102 100644
--- a/drivers/gpu/drm/panel/panel-elida-kd35t133.c
+++ b/drivers/gpu/drm/panel/panel-elida-kd35t133.c
@@ -51,14 +51,6 @@ static inline struct kd35t133 *panel_to_kd35t133(struct drm_panel *panel)
return container_of(panel, struct kd35t133, panel);
}
-#define dsi_dcs_write_seq(dsi, cmd, seq...) do { \
- static const u8 b[] = { cmd, seq }; \
- int ret; \
- ret = mipi_dsi_dcs_write_buffer(dsi, b, ARRAY_SIZE(b)); \
- if (ret < 0) \
- return ret; \
- } while (0)
-
static int kd35t133_init_sequence(struct kd35t133 *ctx)
{
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
@@ -68,25 +60,25 @@ static int kd35t133_init_sequence(struct kd35t133 *ctx)
* Init sequence was supplied by the panel vendor with minimal
* documentation.
*/
- dsi_dcs_write_seq(dsi, KD35T133_CMD_POSITIVEGAMMA,
- 0x00, 0x13, 0x18, 0x04, 0x0f, 0x06, 0x3a, 0x56,
- 0x4d, 0x03, 0x0a, 0x06, 0x30, 0x3e, 0x0f);
- dsi_dcs_write_seq(dsi, KD35T133_CMD_NEGATIVEGAMMA,
- 0x00, 0x13, 0x18, 0x01, 0x11, 0x06, 0x38, 0x34,
- 0x4d, 0x06, 0x0d, 0x0b, 0x31, 0x37, 0x0f);
- dsi_dcs_write_seq(dsi, KD35T133_CMD_POWERCONTROL1, 0x18, 0x17);
- dsi_dcs_write_seq(dsi, KD35T133_CMD_POWERCONTROL2, 0x41);
- dsi_dcs_write_seq(dsi, KD35T133_CMD_VCOMCONTROL, 0x00, 0x1a, 0x80);
- dsi_dcs_write_seq(dsi, MIPI_DCS_SET_ADDRESS_MODE, 0x48);
- dsi_dcs_write_seq(dsi, MIPI_DCS_SET_PIXEL_FORMAT, 0x55);
- dsi_dcs_write_seq(dsi, KD35T133_CMD_INTERFACEMODECTRL, 0x00);
- dsi_dcs_write_seq(dsi, KD35T133_CMD_FRAMERATECTRL, 0xa0);
- dsi_dcs_write_seq(dsi, KD35T133_CMD_DISPLAYINVERSIONCTRL, 0x02);
- dsi_dcs_write_seq(dsi, KD35T133_CMD_DISPLAYFUNCTIONCTRL,
- 0x20, 0x02);
- dsi_dcs_write_seq(dsi, KD35T133_CMD_SETIMAGEFUNCTION, 0x00);
- dsi_dcs_write_seq(dsi, KD35T133_CMD_ADJUSTCONTROL3,
- 0xa9, 0x51, 0x2c, 0x82);
+ mipi_dsi_dcs_write_seq(dsi, KD35T133_CMD_POSITIVEGAMMA,
+ 0x00, 0x13, 0x18, 0x04, 0x0f, 0x06, 0x3a, 0x56,
+ 0x4d, 0x03, 0x0a, 0x06, 0x30, 0x3e, 0x0f);
+ mipi_dsi_dcs_write_seq(dsi, KD35T133_CMD_NEGATIVEGAMMA,
+ 0x00, 0x13, 0x18, 0x01, 0x11, 0x06, 0x38, 0x34,
+ 0x4d, 0x06, 0x0d, 0x0b, 0x31, 0x37, 0x0f);
+ mipi_dsi_dcs_write_seq(dsi, KD35T133_CMD_POWERCONTROL1, 0x18, 0x17);
+ mipi_dsi_dcs_write_seq(dsi, KD35T133_CMD_POWERCONTROL2, 0x41);
+ mipi_dsi_dcs_write_seq(dsi, KD35T133_CMD_VCOMCONTROL, 0x00, 0x1a, 0x80);
+ mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_ADDRESS_MODE, 0x48);
+ mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_PIXEL_FORMAT, 0x55);
+ mipi_dsi_dcs_write_seq(dsi, KD35T133_CMD_INTERFACEMODECTRL, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, KD35T133_CMD_FRAMERATECTRL, 0xa0);
+ mipi_dsi_dcs_write_seq(dsi, KD35T133_CMD_DISPLAYINVERSIONCTRL, 0x02);
+ mipi_dsi_dcs_write_seq(dsi, KD35T133_CMD_DISPLAYFUNCTIONCTRL,
+ 0x20, 0x02);
+ mipi_dsi_dcs_write_seq(dsi, KD35T133_CMD_SETIMAGEFUNCTION, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, KD35T133_CMD_ADJUSTCONTROL3,
+ 0xa9, 0x51, 0x2c, 0x82);
mipi_dsi_dcs_write(dsi, MIPI_DCS_ENTER_INVERT_MODE, NULL, 0);
dev_dbg(dev, "Panel init sequence done\n");
diff --git a/drivers/gpu/drm/panel/panel-himax-hx8394.c b/drivers/gpu/drm/panel/panel-himax-hx8394.c
new file mode 100644
index 000000000000..d4fb5d1b295b
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-himax-hx8394.c
@@ -0,0 +1,451 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for panels based on Himax HX8394 controller, such as:
+ *
+ * - HannStar HSD060BHW4 5.99" MIPI-DSI panel
+ *
+ * Copyright (C) 2021 Kamil Trzciński
+ *
+ * Based on drivers/gpu/drm/panel/panel-sitronix-st7703.c
+ * Copyright (C) Purism SPC 2019
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/media-bus-format.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regulator/consumer.h>
+
+#include <video/mipi_display.h>
+
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_panel.h>
+
+#define DRV_NAME "panel-himax-hx8394"
+
+/* Manufacturer specific commands sent via DSI, listed in HX8394-F datasheet */
+#define HX8394_CMD_SETSEQUENCE 0xb0
+#define HX8394_CMD_SETPOWER 0xb1
+#define HX8394_CMD_SETDISP 0xb2
+#define HX8394_CMD_SETCYC 0xb4
+#define HX8394_CMD_SETVCOM 0xb6
+#define HX8394_CMD_SETTE 0xb7
+#define HX8394_CMD_SETSENSOR 0xb8
+#define HX8394_CMD_SETEXTC 0xb9
+#define HX8394_CMD_SETMIPI 0xba
+#define HX8394_CMD_SETOTP 0xbb
+#define HX8394_CMD_SETREGBANK 0xbd
+#define HX8394_CMD_UNKNOWN1 0xc0
+#define HX8394_CMD_SETDGCLUT 0xc1
+#define HX8394_CMD_SETID 0xc3
+#define HX8394_CMD_SETDDB 0xc4
+#define HX8394_CMD_UNKNOWN2 0xc6
+#define HX8394_CMD_SETCABC 0xc9
+#define HX8394_CMD_SETCABCGAIN 0xca
+#define HX8394_CMD_SETPANEL 0xcc
+#define HX8394_CMD_SETOFFSET 0xd2
+#define HX8394_CMD_SETGIP0 0xd3
+#define HX8394_CMD_UNKNOWN3 0xd4
+#define HX8394_CMD_SETGIP1 0xd5
+#define HX8394_CMD_SETGIP2 0xd6
+#define HX8394_CMD_SETGPO 0xd6
+#define HX8394_CMD_SETSCALING 0xdd
+#define HX8394_CMD_SETIDLE 0xdf
+#define HX8394_CMD_SETGAMMA 0xe0
+#define HX8394_CMD_SETCHEMODE_DYN 0xe4
+#define HX8394_CMD_SETCHE 0xe5
+#define HX8394_CMD_SETCESEL 0xe6
+#define HX8394_CMD_SET_SP_CMD 0xe9
+#define HX8394_CMD_SETREADINDEX 0xfe
+#define HX8394_CMD_GETSPIREAD 0xff
+
+struct hx8394 {
+ struct device *dev;
+ struct drm_panel panel;
+ struct gpio_desc *reset_gpio;
+ struct regulator *vcc;
+ struct regulator *iovcc;
+ bool prepared;
+
+ const struct hx8394_panel_desc *desc;
+};
+
+struct hx8394_panel_desc {
+ const struct drm_display_mode *mode;
+ unsigned int lanes;
+ unsigned long mode_flags;
+ enum mipi_dsi_pixel_format format;
+ int (*init_sequence)(struct hx8394 *ctx);
+};
+
+static inline struct hx8394 *panel_to_hx8394(struct drm_panel *panel)
+{
+ return container_of(panel, struct hx8394, panel);
+}
+
+static int hsd060bhw4_init_sequence(struct hx8394 *ctx)
+{
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+
+ /* 5.19.8 SETEXTC: Set extension command (B9h) */
+ mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETEXTC,
+ 0xff, 0x83, 0x94);
+
+ /* 5.19.2 SETPOWER: Set power (B1h) */
+ mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETPOWER,
+ 0x48, 0x11, 0x71, 0x09, 0x32, 0x24, 0x71, 0x31, 0x55, 0x30);
+
+ /* 5.19.9 SETMIPI: Set MIPI control (BAh) */
+ mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETMIPI,
+ 0x63, 0x03, 0x68, 0x6b, 0xb2, 0xc0);
+
+ /* 5.19.3 SETDISP: Set display related register (B2h) */
+ mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETDISP,
+ 0x00, 0x80, 0x78, 0x0c, 0x07);
+
+ /* 5.19.4 SETCYC: Set display waveform cycles (B4h) */
+ mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETCYC,
+ 0x12, 0x63, 0x12, 0x63, 0x12, 0x63, 0x01, 0x0c, 0x7c, 0x55,
+ 0x00, 0x3f, 0x12, 0x6b, 0x12, 0x6b, 0x12, 0x6b, 0x01, 0x0c,
+ 0x7c);
+
+ /* 5.19.19 SETGIP0: Set GIP Option0 (D3h) */
+ mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGIP0,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x1c, 0x00, 0x00, 0x32, 0x10,
+ 0x09, 0x00, 0x09, 0x32, 0x15, 0xad, 0x05, 0xad, 0x32, 0x00,
+ 0x00, 0x00, 0x00, 0x37, 0x03, 0x0b, 0x0b, 0x37, 0x00, 0x00,
+ 0x00, 0x0c, 0x40);
+
+ /* 5.19.20 Set GIP Option1 (D5h) */
+ mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGIP1,
+ 0x19, 0x19, 0x18, 0x18, 0x1b, 0x1b, 0x1a, 0x1a, 0x00, 0x01,
+ 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x20, 0x21, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x24, 0x25, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18);
+
+ /* 5.19.21 Set GIP Option2 (D6h) */
+ mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGIP2,
+ 0x18, 0x18, 0x19, 0x19, 0x1b, 0x1b, 0x1a, 0x1a, 0x07, 0x06,
+ 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x25, 0x24, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x21, 0x20, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18);
+
+ /* 5.19.25 SETGAMMA: Set gamma curve related setting (E0h) */
+ mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGAMMA,
+ 0x00, 0x04, 0x0c, 0x12, 0x14, 0x18, 0x1a, 0x18, 0x31, 0x3f,
+ 0x4d, 0x4c, 0x54, 0x65, 0x6b, 0x70, 0x7f, 0x82, 0x7e, 0x8a,
+ 0x99, 0x4a, 0x48, 0x49, 0x4b, 0x4a, 0x4c, 0x4b, 0x7f, 0x00,
+ 0x04, 0x0c, 0x11, 0x13, 0x17, 0x1a, 0x18, 0x31,
+ 0x3f, 0x4d, 0x4c, 0x54, 0x65, 0x6b, 0x70, 0x7f,
+ 0x82, 0x7e, 0x8a, 0x99, 0x4a, 0x48, 0x49, 0x4b,
+ 0x4a, 0x4c, 0x4b, 0x7f);
+
+ /* 5.19.17 SETPANEL (CCh) */
+ mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETPANEL,
+ 0x0b);
+
+ /* Unknown command, not listed in the HX8394-F datasheet */
+ mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN1,
+ 0x1f, 0x31);
+
+ /* 5.19.5 SETVCOM: Set VCOM voltage (B6h) */
+ mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETVCOM,
+ 0x7d, 0x7d);
+
+ /* Unknown command, not listed in the HX8394-F datasheet */
+ mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN3,
+ 0x02);
+
+ /* 5.19.11 Set register bank (BDh) */
+ mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETREGBANK,
+ 0x01);
+
+ /* 5.19.2 SETPOWER: Set power (B1h) */
+ mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETPOWER,
+ 0x00);
+
+ /* 5.19.11 Set register bank (BDh) */
+ mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETREGBANK,
+ 0x00);
+
+ /* Unknown command, not listed in the HX8394-F datasheet */
+ mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN3,
+ 0xed);
+
+ return 0;
+}
+
+static const struct drm_display_mode hsd060bhw4_mode = {
+ .hdisplay = 720,
+ .hsync_start = 720 + 40,
+ .hsync_end = 720 + 40 + 46,
+ .htotal = 720 + 40 + 46 + 40,
+ .vdisplay = 1440,
+ .vsync_start = 1440 + 9,
+ .vsync_end = 1440 + 9 + 7,
+ .vtotal = 1440 + 9 + 7 + 7,
+ .clock = 74250,
+ .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+ .width_mm = 68,
+ .height_mm = 136,
+};
+
+static const struct hx8394_panel_desc hsd060bhw4_desc = {
+ .mode = &hsd060bhw4_mode,
+ .lanes = 4,
+ .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST,
+ .format = MIPI_DSI_FMT_RGB888,
+ .init_sequence = hsd060bhw4_init_sequence,
+};
+
+static int hx8394_enable(struct drm_panel *panel)
+{
+ struct hx8394 *ctx = panel_to_hx8394(panel);
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+ int ret;
+
+ ret = ctx->desc->init_sequence(ctx);
+ if (ret) {
+ dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
+ if (ret) {
+ dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
+ return ret;
+ }
+
+ /* Panel is operational 120 msec after reset */
+ msleep(120);
+
+ ret = mipi_dsi_dcs_set_display_on(dsi);
+ if (ret) {
+ dev_err(ctx->dev, "Failed to turn on the display: %d\n", ret);
+ goto sleep_in;
+ }
+
+ return 0;
+
+sleep_in:
+ /* This will probably fail, but let's try orderly power off anyway. */
+ ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
+ if (!ret)
+ msleep(50);
+
+ return ret;
+}
+
+static int hx8394_disable(struct drm_panel *panel)
+{
+ struct hx8394 *ctx = panel_to_hx8394(panel);
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+ int ret;
+
+ ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
+ if (ret) {
+ dev_err(ctx->dev, "Failed to enter sleep mode: %d\n", ret);
+ return ret;
+ }
+
+ msleep(50); /* about 3 frames */
+
+ return 0;
+}
+
+static int hx8394_unprepare(struct drm_panel *panel)
+{
+ struct hx8394 *ctx = panel_to_hx8394(panel);
+
+ if (!ctx->prepared)
+ return 0;
+
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+
+ regulator_disable(ctx->iovcc);
+ regulator_disable(ctx->vcc);
+
+ ctx->prepared = false;
+
+ return 0;
+}
+
+static int hx8394_prepare(struct drm_panel *panel)
+{
+ struct hx8394 *ctx = panel_to_hx8394(panel);
+ int ret;
+
+ if (ctx->prepared)
+ return 0;
+
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+
+ ret = regulator_enable(ctx->vcc);
+ if (ret) {
+ dev_err(ctx->dev, "Failed to enable vcc supply: %d\n", ret);
+ return ret;
+ }
+
+ ret = regulator_enable(ctx->iovcc);
+ if (ret) {
+ dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
+ goto disable_vcc;
+ }
+
+ gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+
+ msleep(180);
+
+ ctx->prepared = true;
+
+ return 0;
+
+disable_vcc:
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+ regulator_disable(ctx->vcc);
+ return ret;
+}
+
+static int hx8394_get_modes(struct drm_panel *panel,
+ struct drm_connector *connector)
+{
+ struct hx8394 *ctx = panel_to_hx8394(panel);
+ struct drm_display_mode *mode;
+
+ mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);
+ if (!mode) {
+ dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n",
+ ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
+ drm_mode_vrefresh(ctx->desc->mode));
+ return -ENOMEM;
+ }
+
+ drm_mode_set_name(mode);
+
+ mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+ connector->display_info.width_mm = mode->width_mm;
+ connector->display_info.height_mm = mode->height_mm;
+ drm_mode_probed_add(connector, mode);
+
+ return 1;
+}
+
+static const struct drm_panel_funcs hx8394_drm_funcs = {
+ .disable = hx8394_disable,
+ .unprepare = hx8394_unprepare,
+ .prepare = hx8394_prepare,
+ .enable = hx8394_enable,
+ .get_modes = hx8394_get_modes,
+};
+
+static int hx8394_probe(struct mipi_dsi_device *dsi)
+{
+ struct device *dev = &dsi->dev;
+ struct hx8394 *ctx;
+ int ret;
+
+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(ctx->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
+ "Failed to get reset gpio\n");
+
+ mipi_dsi_set_drvdata(dsi, ctx);
+
+ ctx->dev = dev;
+ ctx->desc = of_device_get_match_data(dev);
+
+ dsi->mode_flags = ctx->desc->mode_flags;
+ dsi->format = ctx->desc->format;
+ dsi->lanes = ctx->desc->lanes;
+
+ ctx->vcc = devm_regulator_get(dev, "vcc");
+ if (IS_ERR(ctx->vcc))
+ return dev_err_probe(dev, PTR_ERR(ctx->vcc),
+ "Failed to request vcc regulator\n");
+
+ ctx->iovcc = devm_regulator_get(dev, "iovcc");
+ if (IS_ERR(ctx->iovcc))
+ return dev_err_probe(dev, PTR_ERR(ctx->iovcc),
+ "Failed to request iovcc regulator\n");
+
+ drm_panel_init(&ctx->panel, dev, &hx8394_drm_funcs,
+ DRM_MODE_CONNECTOR_DSI);
+
+ ret = drm_panel_of_backlight(&ctx->panel);
+ if (ret)
+ return ret;
+
+ drm_panel_add(&ctx->panel);
+
+ ret = mipi_dsi_attach(dsi);
+ if (ret < 0) {
+ dev_err_probe(dev, ret, "mipi_dsi_attach failed\n");
+ drm_panel_remove(&ctx->panel);
+ return ret;
+ }
+
+ dev_dbg(dev, "%ux%u@%u %ubpp dsi %udl - ready\n",
+ ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
+ drm_mode_vrefresh(ctx->desc->mode),
+ mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes);
+
+ return 0;
+}
+
+static void hx8394_shutdown(struct mipi_dsi_device *dsi)
+{
+ struct hx8394 *ctx = mipi_dsi_get_drvdata(dsi);
+ int ret;
+
+ ret = drm_panel_disable(&ctx->panel);
+ if (ret < 0)
+ dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret);
+
+ ret = drm_panel_unprepare(&ctx->panel);
+ if (ret < 0)
+ dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret);
+}
+
+static void hx8394_remove(struct mipi_dsi_device *dsi)
+{
+ struct hx8394 *ctx = mipi_dsi_get_drvdata(dsi);
+ int ret;
+
+ hx8394_shutdown(dsi);
+
+ ret = mipi_dsi_detach(dsi);
+ if (ret < 0)
+ dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
+
+ drm_panel_remove(&ctx->panel);
+}
+
+static const struct of_device_id hx8394_of_match[] = {
+ { .compatible = "hannstar,hsd060bhw4", .data = &hsd060bhw4_desc },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, hx8394_of_match);
+
+static struct mipi_dsi_driver hx8394_driver = {
+ .probe = hx8394_probe,
+ .remove = hx8394_remove,
+ .shutdown = hx8394_shutdown,
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = hx8394_of_match,
+ },
+};
+module_mipi_dsi_driver(hx8394_driver);
+
+MODULE_AUTHOR("Kamil Trzciński <ayufan@ayufan.eu>");
+MODULE_DESCRIPTION("DRM driver for Himax HX8394 based MIPI DSI panels");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9341.c b/drivers/gpu/drm/panel/panel-ilitek-ili9341.c
index 384a724f2822..3fdf884b3257 100644
--- a/drivers/gpu/drm/panel/panel-ilitek-ili9341.c
+++ b/drivers/gpu/drm/panel/panel-ilitek-ili9341.c
@@ -577,11 +577,7 @@ out_exit:
}
static const struct drm_simple_display_pipe_funcs ili9341_dbi_funcs = {
- .mode_valid = mipi_dbi_pipe_mode_valid,
- .enable = ili9341_dbi_enable,
- .disable = mipi_dbi_pipe_disable,
- .update = mipi_dbi_pipe_update,
- .prepare_fb = drm_gem_simple_display_pipe_prepare_fb,
+ DRM_MIPI_DBI_SIMPLE_DISPLAY_PIPE_FUNCS(ili9341_dbi_enable),
};
static const struct drm_display_mode ili9341_dbi_mode = {
diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c
index cbb68caa36f2..1ec696adf9de 100644
--- a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c
+++ b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c
@@ -7,7 +7,6 @@
#include <linux/device.h>
#include <linux/err.h>
#include <linux/errno.h>
-#include <linux/fb.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_device.h>
diff --git a/drivers/gpu/drm/panel/panel-jdi-fhd-r63452.c b/drivers/gpu/drm/panel/panel-jdi-fhd-r63452.c
index d8765b2294fb..8912757a6f42 100644
--- a/drivers/gpu/drm/panel/panel-jdi-fhd-r63452.c
+++ b/drivers/gpu/drm/panel/panel-jdi-fhd-r63452.c
@@ -29,22 +29,6 @@ static inline struct jdi_fhd_r63452 *to_jdi_fhd_r63452(struct drm_panel *panel)
return container_of(panel, struct jdi_fhd_r63452, panel);
}
-#define dsi_generic_write_seq(dsi, seq...) do { \
- static const u8 d[] = { seq }; \
- int ret; \
- ret = mipi_dsi_generic_write(dsi, d, ARRAY_SIZE(d)); \
- if (ret < 0) \
- return ret; \
- } while (0)
-
-#define dsi_dcs_write_seq(dsi, seq...) do { \
- static const u8 d[] = { seq }; \
- int ret; \
- ret = mipi_dsi_dcs_write_buffer(dsi, d, ARRAY_SIZE(d)); \
- if (ret < 0) \
- return ret; \
- } while (0)
-
static void jdi_fhd_r63452_reset(struct jdi_fhd_r63452 *ctx)
{
gpiod_set_value_cansleep(ctx->reset_gpio, 0);
@@ -63,12 +47,12 @@ static int jdi_fhd_r63452_on(struct jdi_fhd_r63452 *ctx)
dsi->mode_flags |= MIPI_DSI_MODE_LPM;
- dsi_generic_write_seq(dsi, 0xb0, 0x00);
- dsi_generic_write_seq(dsi, 0xd6, 0x01);
- dsi_generic_write_seq(dsi, 0xec,
- 0x64, 0xdc, 0xec, 0x3b, 0x52, 0x00, 0x0b, 0x0b,
- 0x13, 0x15, 0x68, 0x0b, 0xb5);
- dsi_generic_write_seq(dsi, 0xb0, 0x03);
+ mipi_dsi_generic_write_seq(dsi, 0xb0, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xd6, 0x01);
+ mipi_dsi_generic_write_seq(dsi, 0xec,
+ 0x64, 0xdc, 0xec, 0x3b, 0x52, 0x00, 0x0b, 0x0b,
+ 0x13, 0x15, 0x68, 0x0b, 0xb5);
+ mipi_dsi_generic_write_seq(dsi, 0xb0, 0x03);
ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
if (ret < 0) {
@@ -76,7 +60,7 @@ static int jdi_fhd_r63452_on(struct jdi_fhd_r63452 *ctx)
return ret;
}
- dsi_dcs_write_seq(dsi, MIPI_DCS_SET_ADDRESS_MODE, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_ADDRESS_MODE, 0x00);
ret = mipi_dsi_dcs_set_pixel_format(dsi, 0x77);
if (ret < 0) {
@@ -108,10 +92,10 @@ static int jdi_fhd_r63452_on(struct jdi_fhd_r63452 *ctx)
return ret;
}
- dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24);
- dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_POWER_SAVE, 0x00);
- dsi_dcs_write_seq(dsi, MIPI_DCS_SET_CABC_MIN_BRIGHTNESS, 0x00);
- dsi_dcs_write_seq(dsi, 0x84, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24);
+ mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_POWER_SAVE, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_CABC_MIN_BRIGHTNESS, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, 0x84, 0x00);
ret = mipi_dsi_dcs_set_display_on(dsi);
if (ret < 0) {
@@ -127,10 +111,10 @@ static int jdi_fhd_r63452_on(struct jdi_fhd_r63452 *ctx)
}
msleep(80);
- dsi_generic_write_seq(dsi, 0xb0, 0x04);
- dsi_dcs_write_seq(dsi, 0x84, 0x00);
- dsi_generic_write_seq(dsi, 0xc8, 0x11);
- dsi_generic_write_seq(dsi, 0xb0, 0x03);
+ mipi_dsi_generic_write_seq(dsi, 0xb0, 0x04);
+ mipi_dsi_dcs_write_seq(dsi, 0x84, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xc8, 0x11);
+ mipi_dsi_generic_write_seq(dsi, 0xb0, 0x03);
return 0;
}
@@ -143,12 +127,12 @@ static int jdi_fhd_r63452_off(struct jdi_fhd_r63452 *ctx)
dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
- dsi_generic_write_seq(dsi, 0xb0, 0x00);
- dsi_generic_write_seq(dsi, 0xd6, 0x01);
- dsi_generic_write_seq(dsi, 0xec,
- 0x64, 0xdc, 0xec, 0x3b, 0x52, 0x00, 0x0b, 0x0b,
- 0x13, 0x15, 0x68, 0x0b, 0x95);
- dsi_generic_write_seq(dsi, 0xb0, 0x03);
+ mipi_dsi_generic_write_seq(dsi, 0xb0, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xd6, 0x01);
+ mipi_dsi_generic_write_seq(dsi, 0xec,
+ 0x64, 0xdc, 0xec, 0x3b, 0x52, 0x00, 0x0b, 0x0b,
+ 0x13, 0x15, 0x68, 0x0b, 0x95);
+ mipi_dsi_generic_write_seq(dsi, 0xb0, 0x03);
ret = mipi_dsi_dcs_set_display_off(dsi);
if (ret < 0) {
diff --git a/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c b/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c
index 5619f186d28c..d2efd887484b 100644
--- a/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c
+++ b/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c
@@ -244,14 +244,6 @@ struct ltk050h3146w *panel_to_ltk050h3146w(struct drm_panel *panel)
return container_of(panel, struct ltk050h3146w, panel);
}
-#define dsi_dcs_write_seq(dsi, cmd, seq...) do { \
- static const u8 b[] = { cmd, seq }; \
- int ret; \
- ret = mipi_dsi_dcs_write_buffer(dsi, b, ARRAY_SIZE(b)); \
- if (ret < 0) \
- return ret; \
- } while (0)
-
static int ltk050h3146w_init_sequence(struct ltk050h3146w *ctx)
{
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
@@ -261,55 +253,55 @@ static int ltk050h3146w_init_sequence(struct ltk050h3146w *ctx)
* Init sequence was supplied by the panel vendor without much
* documentation.
*/
- dsi_dcs_write_seq(dsi, 0xdf, 0x93, 0x65, 0xf8);
- dsi_dcs_write_seq(dsi, 0xb0, 0x01, 0x03, 0x02, 0x00, 0x64, 0x06,
- 0x01);
- dsi_dcs_write_seq(dsi, 0xb2, 0x00, 0xb5);
- dsi_dcs_write_seq(dsi, 0xb3, 0x00, 0xb5);
- dsi_dcs_write_seq(dsi, 0xb7, 0x00, 0xbf, 0x00, 0x00, 0xbf, 0x00);
-
- dsi_dcs_write_seq(dsi, 0xb9, 0x00, 0xc4, 0x23, 0x07);
- dsi_dcs_write_seq(dsi, 0xbb, 0x02, 0x01, 0x24, 0x00, 0x28, 0x0f,
- 0x28, 0x04, 0xcc, 0xcc, 0xcc);
- dsi_dcs_write_seq(dsi, 0xbc, 0x0f, 0x04);
- dsi_dcs_write_seq(dsi, 0xbe, 0x1e, 0xf2);
- dsi_dcs_write_seq(dsi, 0xc0, 0x26, 0x03);
- dsi_dcs_write_seq(dsi, 0xc1, 0x00, 0x12);
- dsi_dcs_write_seq(dsi, 0xc3, 0x04, 0x02, 0x02, 0x76, 0x01, 0x80,
- 0x80);
- dsi_dcs_write_seq(dsi, 0xc4, 0x24, 0x80, 0xb4, 0x81, 0x12, 0x0f,
- 0x16, 0x00, 0x00);
- dsi_dcs_write_seq(dsi, 0xc8, 0x7f, 0x72, 0x67, 0x5d, 0x5d, 0x50,
- 0x56, 0x41, 0x59, 0x57, 0x55, 0x70, 0x5b, 0x5f,
- 0x4f, 0x47, 0x38, 0x23, 0x08, 0x7f, 0x72, 0x67,
- 0x5d, 0x5d, 0x50, 0x56, 0x41, 0x59, 0x57, 0x55,
- 0x70, 0x5b, 0x5f, 0x4f, 0x47, 0x38, 0x23, 0x08);
- dsi_dcs_write_seq(dsi, 0xd0, 0x1e, 0x1f, 0x57, 0x58, 0x48, 0x4a,
- 0x44, 0x46, 0x40, 0x1f, 0x42, 0x1f, 0x1f, 0x1f,
- 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
- dsi_dcs_write_seq(dsi, 0xd1, 0x1e, 0x1f, 0x57, 0x58, 0x49, 0x4b,
- 0x45, 0x47, 0x41, 0x1f, 0x43, 0x1f, 0x1f, 0x1f,
- 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
- dsi_dcs_write_seq(dsi, 0xd2, 0x1f, 0x1e, 0x17, 0x18, 0x07, 0x05,
- 0x0b, 0x09, 0x03, 0x1f, 0x01, 0x1f, 0x1f, 0x1f,
- 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
- dsi_dcs_write_seq(dsi, 0xd3, 0x1f, 0x1e, 0x17, 0x18, 0x06, 0x04,
- 0x0a, 0x08, 0x02, 0x1f, 0x00, 0x1f, 0x1f, 0x1f,
- 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
- dsi_dcs_write_seq(dsi, 0xd4, 0x00, 0x00, 0x00, 0x0c, 0x06, 0x20,
- 0x01, 0x02, 0x00, 0x60, 0x15, 0xb0, 0x30, 0x03,
- 0x04, 0x00, 0x60, 0x72, 0x0a, 0x00, 0x60, 0x08);
- dsi_dcs_write_seq(dsi, 0xd5, 0x00, 0x06, 0x06, 0x00, 0x30, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xbc, 0x50, 0x00, 0x05,
- 0x21, 0x00, 0x60);
- dsi_dcs_write_seq(dsi, 0xdd, 0x2c, 0xa3, 0x00);
- dsi_dcs_write_seq(dsi, 0xde, 0x02);
- dsi_dcs_write_seq(dsi, 0xb2, 0x32, 0x1c);
- dsi_dcs_write_seq(dsi, 0xb7, 0x3b, 0x70, 0x00, 0x04);
- dsi_dcs_write_seq(dsi, 0xc1, 0x11);
- dsi_dcs_write_seq(dsi, 0xbb, 0x21, 0x22, 0x23, 0x24, 0x36, 0x37);
- dsi_dcs_write_seq(dsi, 0xc2, 0x20, 0x38, 0x1e, 0x84);
- dsi_dcs_write_seq(dsi, 0xde, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, 0xdf, 0x93, 0x65, 0xf8);
+ mipi_dsi_dcs_write_seq(dsi, 0xb0, 0x01, 0x03, 0x02, 0x00, 0x64, 0x06,
+ 0x01);
+ mipi_dsi_dcs_write_seq(dsi, 0xb2, 0x00, 0xb5);
+ mipi_dsi_dcs_write_seq(dsi, 0xb3, 0x00, 0xb5);
+ mipi_dsi_dcs_write_seq(dsi, 0xb7, 0x00, 0xbf, 0x00, 0x00, 0xbf, 0x00);
+
+ mipi_dsi_dcs_write_seq(dsi, 0xb9, 0x00, 0xc4, 0x23, 0x07);
+ mipi_dsi_dcs_write_seq(dsi, 0xbb, 0x02, 0x01, 0x24, 0x00, 0x28, 0x0f,
+ 0x28, 0x04, 0xcc, 0xcc, 0xcc);
+ mipi_dsi_dcs_write_seq(dsi, 0xbc, 0x0f, 0x04);
+ mipi_dsi_dcs_write_seq(dsi, 0xbe, 0x1e, 0xf2);
+ mipi_dsi_dcs_write_seq(dsi, 0xc0, 0x26, 0x03);
+ mipi_dsi_dcs_write_seq(dsi, 0xc1, 0x00, 0x12);
+ mipi_dsi_dcs_write_seq(dsi, 0xc3, 0x04, 0x02, 0x02, 0x76, 0x01, 0x80,
+ 0x80);
+ mipi_dsi_dcs_write_seq(dsi, 0xc4, 0x24, 0x80, 0xb4, 0x81, 0x12, 0x0f,
+ 0x16, 0x00, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, 0xc8, 0x7f, 0x72, 0x67, 0x5d, 0x5d, 0x50,
+ 0x56, 0x41, 0x59, 0x57, 0x55, 0x70, 0x5b, 0x5f,
+ 0x4f, 0x47, 0x38, 0x23, 0x08, 0x7f, 0x72, 0x67,
+ 0x5d, 0x5d, 0x50, 0x56, 0x41, 0x59, 0x57, 0x55,
+ 0x70, 0x5b, 0x5f, 0x4f, 0x47, 0x38, 0x23, 0x08);
+ mipi_dsi_dcs_write_seq(dsi, 0xd0, 0x1e, 0x1f, 0x57, 0x58, 0x48, 0x4a,
+ 0x44, 0x46, 0x40, 0x1f, 0x42, 0x1f, 0x1f, 0x1f,
+ 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
+ mipi_dsi_dcs_write_seq(dsi, 0xd1, 0x1e, 0x1f, 0x57, 0x58, 0x49, 0x4b,
+ 0x45, 0x47, 0x41, 0x1f, 0x43, 0x1f, 0x1f, 0x1f,
+ 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
+ mipi_dsi_dcs_write_seq(dsi, 0xd2, 0x1f, 0x1e, 0x17, 0x18, 0x07, 0x05,
+ 0x0b, 0x09, 0x03, 0x1f, 0x01, 0x1f, 0x1f, 0x1f,
+ 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
+ mipi_dsi_dcs_write_seq(dsi, 0xd3, 0x1f, 0x1e, 0x17, 0x18, 0x06, 0x04,
+ 0x0a, 0x08, 0x02, 0x1f, 0x00, 0x1f, 0x1f, 0x1f,
+ 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
+ mipi_dsi_dcs_write_seq(dsi, 0xd4, 0x00, 0x00, 0x00, 0x0c, 0x06, 0x20,
+ 0x01, 0x02, 0x00, 0x60, 0x15, 0xb0, 0x30, 0x03,
+ 0x04, 0x00, 0x60, 0x72, 0x0a, 0x00, 0x60, 0x08);
+ mipi_dsi_dcs_write_seq(dsi, 0xd5, 0x00, 0x06, 0x06, 0x00, 0x30, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xbc, 0x50, 0x00, 0x05,
+ 0x21, 0x00, 0x60);
+ mipi_dsi_dcs_write_seq(dsi, 0xdd, 0x2c, 0xa3, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, 0xde, 0x02);
+ mipi_dsi_dcs_write_seq(dsi, 0xb2, 0x32, 0x1c);
+ mipi_dsi_dcs_write_seq(dsi, 0xb7, 0x3b, 0x70, 0x00, 0x04);
+ mipi_dsi_dcs_write_seq(dsi, 0xc1, 0x11);
+ mipi_dsi_dcs_write_seq(dsi, 0xbb, 0x21, 0x22, 0x23, 0x24, 0x36, 0x37);
+ mipi_dsi_dcs_write_seq(dsi, 0xc2, 0x20, 0x38, 0x1e, 0x84);
+ mipi_dsi_dcs_write_seq(dsi, 0xde, 0x00);
ret = mipi_dsi_dcs_set_tear_on(dsi, 1);
if (ret < 0) {
diff --git a/drivers/gpu/drm/panel/panel-mantix-mlaf057we51.c b/drivers/gpu/drm/panel/panel-mantix-mlaf057we51.c
index 772e3b6acece..9243b2ad828d 100644
--- a/drivers/gpu/drm/panel/panel-mantix-mlaf057we51.c
+++ b/drivers/gpu/drm/panel/panel-mantix-mlaf057we51.c
@@ -45,14 +45,6 @@ static inline struct mantix *panel_to_mantix(struct drm_panel *panel)
return container_of(panel, struct mantix, panel);
}
-#define dsi_generic_write_seq(dsi, seq...) do { \
- static const u8 d[] = { seq }; \
- int ret; \
- ret = mipi_dsi_generic_write(dsi, d, ARRAY_SIZE(d)); \
- if (ret < 0) \
- return ret; \
- } while (0)
-
static int mantix_init_sequence(struct mantix *ctx)
{
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
@@ -61,18 +53,18 @@ static int mantix_init_sequence(struct mantix *ctx)
/*
* Init sequence was supplied by the panel vendor.
*/
- dsi_generic_write_seq(dsi, MANTIX_CMD_OTP_STOP_RELOAD_MIPI, 0x5A);
+ mipi_dsi_generic_write_seq(dsi, MANTIX_CMD_OTP_STOP_RELOAD_MIPI, 0x5A);
- dsi_generic_write_seq(dsi, MANTIX_CMD_INT_CANCEL, 0x03);
- dsi_generic_write_seq(dsi, MANTIX_CMD_OTP_STOP_RELOAD_MIPI, 0x5A, 0x03);
- dsi_generic_write_seq(dsi, 0x80, 0xA9, 0x00);
+ mipi_dsi_generic_write_seq(dsi, MANTIX_CMD_INT_CANCEL, 0x03);
+ mipi_dsi_generic_write_seq(dsi, MANTIX_CMD_OTP_STOP_RELOAD_MIPI, 0x5A, 0x03);
+ mipi_dsi_generic_write_seq(dsi, 0x80, 0xA9, 0x00);
- dsi_generic_write_seq(dsi, MANTIX_CMD_OTP_STOP_RELOAD_MIPI, 0x5A, 0x09);
- dsi_generic_write_seq(dsi, 0x80, 0x64, 0x00, 0x64, 0x00, 0x00);
+ mipi_dsi_generic_write_seq(dsi, MANTIX_CMD_OTP_STOP_RELOAD_MIPI, 0x5A, 0x09);
+ mipi_dsi_generic_write_seq(dsi, 0x80, 0x64, 0x00, 0x64, 0x00, 0x00);
msleep(20);
- dsi_generic_write_seq(dsi, MANTIX_CMD_SPI_FINISH, 0xA5);
- dsi_generic_write_seq(dsi, MANTIX_CMD_OTP_STOP_RELOAD_MIPI, 0x00, 0x2F);
+ mipi_dsi_generic_write_seq(dsi, MANTIX_CMD_SPI_FINISH, 0xA5);
+ mipi_dsi_generic_write_seq(dsi, MANTIX_CMD_OTP_STOP_RELOAD_MIPI, 0x00, 0x2F);
msleep(20);
dev_dbg(dev, "Panel init sequence done\n");
diff --git a/drivers/gpu/drm/panel/panel-novatek-nt35950.c b/drivers/gpu/drm/panel/panel-novatek-nt35950.c
index 3a844917da07..abf752b36a52 100644
--- a/drivers/gpu/drm/panel/panel-novatek-nt35950.c
+++ b/drivers/gpu/drm/panel/panel-novatek-nt35950.c
@@ -89,14 +89,6 @@ static inline struct nt35950 *to_nt35950(struct drm_panel *panel)
return container_of(panel, struct nt35950, panel);
}
-#define dsi_dcs_write_seq(dsi, seq...) do { \
- static const u8 d[] = { seq }; \
- int ret; \
- ret = mipi_dsi_dcs_write_buffer(dsi, d, ARRAY_SIZE(d)); \
- if (ret < 0) \
- return ret; \
- } while (0)
-
static void nt35950_reset(struct nt35950 *nt)
{
gpiod_set_value_cansleep(nt->reset_gpio, 1);
@@ -338,7 +330,7 @@ static int nt35950_on(struct nt35950 *nt)
return ret;
/* Unknown command */
- dsi_dcs_write_seq(dsi, 0xd4, 0x88, 0x88);
+ mipi_dsi_dcs_write_seq(dsi, 0xd4, 0x88, 0x88);
/* CMD2 Page 7 */
ret = nt35950_set_cmd2_page(nt, 7);
@@ -346,10 +338,10 @@ static int nt35950_on(struct nt35950 *nt)
return ret;
/* Enable SubPixel Rendering */
- dsi_dcs_write_seq(dsi, MCS_PARAM_SPR_EN, 0x01);
+ mipi_dsi_dcs_write_seq(dsi, MCS_PARAM_SPR_EN, 0x01);
/* SPR Mode: YYG Rainbow-RGB */
- dsi_dcs_write_seq(dsi, MCS_PARAM_SPR_MODE, MCS_SPR_MODE_YYG_RAINBOW_RGB);
+ mipi_dsi_dcs_write_seq(dsi, MCS_PARAM_SPR_MODE, MCS_SPR_MODE_YYG_RAINBOW_RGB);
/* CMD3 */
ret = nt35950_inject_black_image(nt);
diff --git a/drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c b/drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c
index 36a46cb7fe1c..aba556c98300 100644
--- a/drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c
+++ b/drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c
@@ -202,8 +202,7 @@ static const struct drm_panel_funcs lcd_olinuxino_funcs = {
.get_modes = lcd_olinuxino_get_modes,
};
-static int lcd_olinuxino_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int lcd_olinuxino_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct lcd_olinuxino *lcd;
@@ -309,7 +308,7 @@ static struct i2c_driver lcd_olinuxino_driver = {
.name = "lcd_olinuxino",
.of_match_table = lcd_olinuxino_of_ids,
},
- .probe = lcd_olinuxino_probe,
+ .probe_new = lcd_olinuxino_probe,
.remove = lcd_olinuxino_remove,
};
diff --git a/drivers/gpu/drm/panel/panel-orisetech-ota5601a.c b/drivers/gpu/drm/panel/panel-orisetech-ota5601a.c
new file mode 100644
index 000000000000..e46be5014d42
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-orisetech-ota5601a.c
@@ -0,0 +1,364 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Orisetech OTA5601A TFT LCD panel driver
+ *
+ * Copyright (C) 2021, Christophe Branchereau <cbranchereau@gmail.com>
+ */
+
+#include <linux/bits.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/media-bus-format.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+
+#include <drm/drm_modes.h>
+#include <drm/drm_panel.h>
+
+#define OTA5601A_CTL 0x01
+#define OTA5601A_CTL_OFF 0x00
+#define OTA5601A_CTL_ON BIT(0)
+
+struct ota5601a_panel_info {
+ const struct drm_display_mode *display_modes;
+ unsigned int num_modes;
+ u16 width_mm, height_mm;
+ u32 bus_format, bus_flags;
+};
+
+struct ota5601a {
+ struct drm_panel drm_panel;
+ struct regmap *map;
+ struct regulator *supply;
+ const struct ota5601a_panel_info *panel_info;
+
+ struct gpio_desc *reset_gpio;
+};
+
+static inline struct ota5601a *to_ota5601a(struct drm_panel *panel)
+{
+ return container_of(panel, struct ota5601a, drm_panel);
+}
+
+static const struct reg_sequence ota5601a_panel_regs[] = {
+ { 0xfd, 0x00 }, /* Page Shift */
+ { 0x02, 0x00 }, /* Reset */
+
+ { 0x18, 0x00 }, /* Interface Sel: RGB 24 Bits */
+ { 0x34, 0x20 }, /* Undocumented */
+
+ { 0x0c, 0x01 }, /* Contrast set by CMD1 == within page 0x00 */
+ { 0x0d, 0x48 }, /* R Brightness */
+ { 0x0e, 0x48 }, /* G Brightness */
+ { 0x0f, 0x48 }, /* B Brightness */
+ { 0x07, 0x40 }, /* R Contrast */
+ { 0x08, 0x33 }, /* G Contrast */
+ { 0x09, 0x3a }, /* B Contrast */
+
+ { 0x16, 0x01 }, /* NTSC Sel */
+ { 0x19, 0x8d }, /* VBLK */
+ { 0x1a, 0x28 }, /* HBLK */
+ { 0x1c, 0x00 }, /* Scan Shift Dir. */
+
+ { 0xfd, 0xc5 }, /* Page Shift */
+ { 0x82, 0x0c }, /* PWR_CTRL Pump */
+ { 0xa2, 0xb4 }, /* PWR_CTRL VGH/VGL */
+
+ { 0xfd, 0xc4 }, /* Page Shift - What follows is listed as "RGB 24bit Timing Set" */
+ { 0x82, 0x45 },
+
+ { 0xfd, 0xc1 },
+ { 0x91, 0x02 },
+
+ { 0xfd, 0xc0 },
+ { 0xa1, 0x01 },
+ { 0xa2, 0x1f },
+ { 0xa3, 0x0b },
+ { 0xa4, 0x38 },
+ { 0xa5, 0x00 },
+ { 0xa6, 0x0a },
+ { 0xa7, 0x38 },
+ { 0xa8, 0x00 },
+ { 0xa9, 0x0a },
+ { 0xaa, 0x37 },
+
+ { 0xfd, 0xce },
+ { 0x81, 0x18 },
+ { 0x82, 0x43 },
+ { 0x83, 0x43 },
+ { 0x91, 0x06 },
+ { 0x93, 0x38 },
+ { 0x94, 0x02 },
+ { 0x95, 0x06 },
+ { 0x97, 0x38 },
+ { 0x98, 0x02 },
+ { 0x99, 0x06 },
+ { 0x9b, 0x38 },
+ { 0x9c, 0x02 },
+
+ { 0xfd, 0x00 }, /* Page Shift */
+};
+
+static const struct regmap_config ota5601a_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+};
+
+static int ota5601a_prepare(struct drm_panel *drm_panel)
+{
+ struct ota5601a *panel = to_ota5601a(drm_panel);
+ int err;
+
+ err = regulator_enable(panel->supply);
+ if (err) {
+ dev_err(drm_panel->dev, "Failed to enable power supply: %d\n", err);
+ return err;
+ }
+
+ /* Reset to be held low for 10us min according to the doc, 10ms before sending commands */
+ gpiod_set_value_cansleep(panel->reset_gpio, 1);
+ usleep_range(10, 30);
+ gpiod_set_value_cansleep(panel->reset_gpio, 0);
+ usleep_range(10000, 20000);
+
+ /* Init all registers. */
+ err = regmap_multi_reg_write(panel->map, ota5601a_panel_regs,
+ ARRAY_SIZE(ota5601a_panel_regs));
+ if (err) {
+ dev_err(drm_panel->dev, "Failed to init registers: %d\n", err);
+ goto err_disable_regulator;
+ }
+
+ msleep(120);
+
+ return 0;
+
+err_disable_regulator:
+ regulator_disable(panel->supply);
+ return err;
+}
+
+static int ota5601a_unprepare(struct drm_panel *drm_panel)
+{
+ struct ota5601a *panel = to_ota5601a(drm_panel);
+
+ gpiod_set_value_cansleep(panel->reset_gpio, 1);
+
+ regulator_disable(panel->supply);
+
+ return 0;
+}
+
+static int ota5601a_enable(struct drm_panel *drm_panel)
+{
+ struct ota5601a *panel = to_ota5601a(drm_panel);
+ int err;
+
+ err = regmap_write(panel->map, OTA5601A_CTL, OTA5601A_CTL_ON);
+
+ if (err) {
+ dev_err(drm_panel->dev, "Unable to enable panel: %d\n", err);
+ return err;
+ }
+
+ if (drm_panel->backlight) {
+ /* Wait for the picture to be ready before enabling backlight */
+ msleep(120);
+ }
+
+ return 0;
+}
+
+static int ota5601a_disable(struct drm_panel *drm_panel)
+{
+ struct ota5601a *panel = to_ota5601a(drm_panel);
+ int err;
+
+ err = regmap_write(panel->map, OTA5601A_CTL, OTA5601A_CTL_OFF);
+
+ if (err) {
+ dev_err(drm_panel->dev, "Unable to disable panel: %d\n", err);
+ return err;
+ }
+
+ return 0;
+}
+
+static int ota5601a_get_modes(struct drm_panel *drm_panel,
+ struct drm_connector *connector)
+{
+ struct ota5601a *panel = to_ota5601a(drm_panel);
+ const struct ota5601a_panel_info *panel_info = panel->panel_info;
+ struct drm_display_mode *mode;
+ unsigned int i;
+
+ for (i = 0; i < panel_info->num_modes; i++) {
+ mode = drm_mode_duplicate(connector->dev,
+ &panel_info->display_modes[i]);
+ if (!mode)
+ return -ENOMEM;
+
+ drm_mode_set_name(mode);
+
+ mode->type = DRM_MODE_TYPE_DRIVER;
+ if (panel_info->num_modes == 1)
+ mode->type |= DRM_MODE_TYPE_PREFERRED;
+
+ drm_mode_probed_add(connector, mode);
+ }
+
+ connector->display_info.bpc = 8;
+ connector->display_info.width_mm = panel_info->width_mm;
+ connector->display_info.height_mm = panel_info->height_mm;
+
+ drm_display_info_set_bus_formats(&connector->display_info,
+ &panel_info->bus_format, 1);
+ connector->display_info.bus_flags = panel_info->bus_flags;
+
+ return panel_info->num_modes;
+}
+
+static const struct drm_panel_funcs ota5601a_funcs = {
+ .prepare = ota5601a_prepare,
+ .unprepare = ota5601a_unprepare,
+ .enable = ota5601a_enable,
+ .disable = ota5601a_disable,
+ .get_modes = ota5601a_get_modes,
+};
+
+static int ota5601a_probe(struct spi_device *spi)
+{
+ const struct spi_device_id *id = spi_get_device_id(spi);
+ struct device *dev = &spi->dev;
+ struct ota5601a *panel;
+ int err;
+
+ panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL);
+ if (!panel)
+ return -ENOMEM;
+
+ spi_set_drvdata(spi, panel);
+
+ panel->panel_info = (const struct ota5601a_panel_info *)id->driver_data;
+ if (!panel->panel_info)
+ return -EINVAL;
+
+ panel->supply = devm_regulator_get(dev, "power");
+ if (IS_ERR(panel->supply)) {
+ dev_err(dev, "Failed to get power supply\n");
+ return PTR_ERR(panel->supply);
+ }
+
+ panel->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(panel->reset_gpio)) {
+ dev_err(dev, "Failed to get reset GPIO\n");
+ return PTR_ERR(panel->reset_gpio);
+ }
+
+ spi->bits_per_word = 8;
+ spi->mode = SPI_MODE_3 | SPI_3WIRE;
+ err = spi_setup(spi);
+ if (err) {
+ dev_err(dev, "Failed to setup SPI\n");
+ return err;
+ }
+
+ panel->map = devm_regmap_init_spi(spi, &ota5601a_regmap_config);
+ if (IS_ERR(panel->map)) {
+ dev_err(dev, "Failed to init regmap\n");
+ return PTR_ERR(panel->map);
+ }
+
+ drm_panel_init(&panel->drm_panel, dev, &ota5601a_funcs,
+ DRM_MODE_CONNECTOR_DPI);
+
+ err = drm_panel_of_backlight(&panel->drm_panel);
+ if (err) {
+ if (err != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get backlight handle\n");
+ return err;
+ }
+
+ drm_panel_add(&panel->drm_panel);
+
+ return 0;
+}
+
+static void ota5601a_remove(struct spi_device *spi)
+{
+ struct ota5601a *panel = spi_get_drvdata(spi);
+
+ drm_panel_remove(&panel->drm_panel);
+
+ ota5601a_disable(&panel->drm_panel);
+ ota5601a_unprepare(&panel->drm_panel);
+}
+
+static const struct drm_display_mode gpt3_display_modes[] = {
+ { /* 60 Hz */
+ .clock = 27000,
+ .hdisplay = 640,
+ .hsync_start = 640 + 220,
+ .hsync_end = 640 + 220 + 20,
+ .htotal = 640 + 220 + 20 + 20,
+ .vdisplay = 480,
+ .vsync_start = 480 + 7,
+ .vsync_end = 480 + 7 + 6,
+ .vtotal = 480 + 7 + 6 + 7,
+ .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+ },
+
+ { /* 50 Hz */
+ .clock = 24000,
+ .hdisplay = 640,
+ .hsync_start = 640 + 280,
+ .hsync_end = 640 + 280 + 20,
+ .htotal = 640 + 280 + 20 + 20,
+ .vdisplay = 480,
+ .vsync_start = 480 + 7,
+ .vsync_end = 480 + 7 + 6,
+ .vtotal = 480 + 7 + 6 + 7,
+ .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+ },
+};
+
+static const struct ota5601a_panel_info gpt3_info = {
+ .display_modes = gpt3_display_modes,
+ .num_modes = ARRAY_SIZE(gpt3_display_modes),
+ .width_mm = 71,
+ .height_mm = 51,
+ .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
+ .bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE,
+};
+
+static const struct spi_device_id gpt3_id[] = {
+ { "gpt3", (kernel_ulong_t)&gpt3_info },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(spi, gpt3_id);
+
+static const struct of_device_id ota5601a_of_match[] = {
+ { .compatible = "focaltech,gpt3" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ota5601a_of_match);
+
+static struct spi_driver ota5601a_driver = {
+ .driver = {
+ .name = "ota5601a",
+ .of_match_table = ota5601a_of_match,
+ },
+ .id_table = gpt3_id,
+ .probe = ota5601a_probe,
+ .remove = ota5601a_remove,
+};
+
+module_spi_driver(ota5601a_driver);
+
+MODULE_AUTHOR("Christophe Branchereau <cbranchereau@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
index 79f852465a84..11d6ca276c1e 100644
--- a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
+++ b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
@@ -43,7 +43,6 @@
#include <linux/delay.h>
#include <linux/err.h>
-#include <linux/fb.h>
#include <linux/i2c.h>
#include <linux/media-bus-format.h>
#include <linux/module.h>
@@ -362,8 +361,7 @@ static const struct drm_panel_funcs rpi_touchscreen_funcs = {
.get_modes = rpi_touchscreen_get_modes,
};
-static int rpi_touchscreen_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static int rpi_touchscreen_probe(struct i2c_client *i2c)
{
struct device *dev = &i2c->dev;
struct rpi_touchscreen *ts;
@@ -491,7 +489,7 @@ static struct i2c_driver rpi_touchscreen_driver = {
.name = "rpi_touchscreen",
.of_match_table = rpi_touchscreen_of_ids,
},
- .probe = rpi_touchscreen_probe,
+ .probe_new = rpi_touchscreen_probe,
.remove = rpi_touchscreen_remove,
};
diff --git a/drivers/gpu/drm/panel/panel-ronbo-rb070d30.c b/drivers/gpu/drm/panel/panel-ronbo-rb070d30.c
index a8a98c91b13c..2ef5ea5eaeeb 100644
--- a/drivers/gpu/drm/panel/panel-ronbo-rb070d30.c
+++ b/drivers/gpu/drm/panel/panel-ronbo-rb070d30.c
@@ -11,10 +11,10 @@
#include <linux/device.h>
#include <linux/err.h>
#include <linux/errno.h>
-#include <linux/fb.h>
#include <linux/kernel.h>
#include <linux/media-bus-format.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
diff --git a/drivers/gpu/drm/panel/panel-samsung-atna33xc20.c b/drivers/gpu/drm/panel/panel-samsung-atna33xc20.c
index 5a8b978c6415..5703f4712d96 100644
--- a/drivers/gpu/drm/panel/panel-samsung-atna33xc20.c
+++ b/drivers/gpu/drm/panel/panel-samsung-atna33xc20.c
@@ -53,7 +53,7 @@ static void atana33xc20_wait(ktime_t start_ktime, unsigned int min_ms)
ktime_t now_ktime, min_ktime;
min_ktime = ktime_add(start_ktime, ms_to_ktime(min_ms));
- now_ktime = ktime_get();
+ now_ktime = ktime_get_boottime();
if (ktime_before(now_ktime, min_ktime))
msleep(ktime_to_ms(ktime_sub(min_ktime, now_ktime)) + 1);
@@ -75,7 +75,7 @@ static int atana33xc20_suspend(struct device *dev)
ret = regulator_disable(p->supply);
if (ret)
return ret;
- p->powered_off_time = ktime_get();
+ p->powered_off_time = ktime_get_boottime();
p->el3_was_on = false;
return 0;
@@ -93,7 +93,7 @@ static int atana33xc20_resume(struct device *dev)
ret = regulator_enable(p->supply);
if (ret)
return ret;
- p->powered_on_time = ktime_get();
+ p->powered_on_time = ktime_get_boottime();
if (p->no_hpd) {
msleep(HPD_MAX_MS);
@@ -142,7 +142,7 @@ static int atana33xc20_disable(struct drm_panel *panel)
return 0;
gpiod_set_value_cansleep(p->el_on3_gpio, 0);
- p->el_on3_off_time = ktime_get();
+ p->el_on3_off_time = ktime_get_boottime();
p->enabled = false;
/*
@@ -310,7 +310,7 @@ static int atana33xc20_probe(struct dp_aux_ep_device *aux_ep)
ret = devm_add_action_or_reset(dev, atana33xc20_runtime_disable, dev);
if (ret)
return ret;
- pm_runtime_set_autosuspend_delay(dev, 1000);
+ pm_runtime_set_autosuspend_delay(dev, 2000);
pm_runtime_use_autosuspend(dev);
ret = devm_add_action_or_reset(dev, atana33xc20_dont_use_autosuspend, dev);
if (ret)
diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c b/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c
index 5c621b15e84c..39eef3dce7c9 100644
--- a/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c
+++ b/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c
@@ -692,7 +692,9 @@ static int s6e3ha2_probe(struct mipi_dsi_device *dsi)
dsi->lanes = 4;
dsi->format = MIPI_DSI_FMT_RGB888;
- dsi->mode_flags = MIPI_DSI_CLOCK_NON_CONTINUOUS;
+ dsi->mode_flags = MIPI_DSI_CLOCK_NON_CONTINUOUS |
+ MIPI_DSI_MODE_VIDEO_NO_HFP | MIPI_DSI_MODE_VIDEO_NO_HBP |
+ MIPI_DSI_MODE_VIDEO_NO_HSA | MIPI_DSI_MODE_NO_EOT_PACKET;
ctx->supplies[0].supply = "vdd3";
ctx->supplies[1].supply = "vci";
@@ -731,6 +733,7 @@ static int s6e3ha2_probe(struct mipi_dsi_device *dsi)
drm_panel_init(&ctx->panel, dev, &s6e3ha2_drm_funcs,
DRM_MODE_CONNECTOR_DSI);
+ ctx->panel.prepare_prev_first = true;
drm_panel_add(&ctx->panel);
diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c b/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c
index e06fd35de814..46d6f4a87bf7 100644
--- a/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c
+++ b/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c
@@ -446,7 +446,8 @@ static int s6e63j0x03_probe(struct mipi_dsi_device *dsi)
dsi->lanes = 1;
dsi->format = MIPI_DSI_FMT_RGB888;
- dsi->mode_flags = MIPI_DSI_MODE_NO_EOT_PACKET;
+ dsi->mode_flags = MIPI_DSI_MODE_VIDEO_NO_HFP |
+ MIPI_DSI_MODE_VIDEO_NO_HBP | MIPI_DSI_MODE_VIDEO_NO_HSA;
ctx->supplies[0].supply = "vdd3";
ctx->supplies[1].supply = "vci";
@@ -462,6 +463,7 @@ static int s6e63j0x03_probe(struct mipi_dsi_device *dsi)
drm_panel_init(&ctx->panel, dev, &s6e63j0x03_funcs,
DRM_MODE_CONNECTOR_DSI);
+ ctx->panel.prepare_prev_first = true;
ctx->bl_dev = backlight_device_register("s6e63j0x03", dev, ctx,
&s6e63j0x03_bl_ops, NULL);
diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams452ef01.c b/drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams452ef01.c
index 97ff7a18545c..7431cae7427e 100644
--- a/drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams452ef01.c
+++ b/drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams452ef01.c
@@ -28,14 +28,6 @@ s6e88a0_ams452ef01 *to_s6e88a0_ams452ef01(struct drm_panel *panel)
return container_of(panel, struct s6e88a0_ams452ef01, panel);
}
-#define dsi_dcs_write_seq(dsi, seq...) do { \
- static const u8 d[] = { seq }; \
- int ret; \
- ret = mipi_dsi_dcs_write_buffer(dsi, d, ARRAY_SIZE(d)); \
- if (ret < 0) \
- return ret; \
- } while (0)
-
static void s6e88a0_ams452ef01_reset(struct s6e88a0_ams452ef01 *ctx)
{
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
@@ -54,8 +46,8 @@ static int s6e88a0_ams452ef01_on(struct s6e88a0_ams452ef01 *ctx)
dsi->mode_flags |= MIPI_DSI_MODE_LPM;
- dsi_dcs_write_seq(dsi, 0xf0, 0x5a, 0x5a); // enable LEVEL2 commands
- dsi_dcs_write_seq(dsi, 0xcc, 0x4c); // set Pixel Clock Divider polarity
+ mipi_dsi_dcs_write_seq(dsi, 0xf0, 0x5a, 0x5a); // enable LEVEL2 commands
+ mipi_dsi_dcs_write_seq(dsi, 0xcc, 0x4c); // set Pixel Clock Divider polarity
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
if (ret < 0) {
@@ -65,23 +57,23 @@ static int s6e88a0_ams452ef01_on(struct s6e88a0_ams452ef01 *ctx)
msleep(120);
// set default brightness/gama
- dsi_dcs_write_seq(dsi, 0xca,
- 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, // V255 RR,GG,BB
- 0x80, 0x80, 0x80, // V203 R,G,B
- 0x80, 0x80, 0x80, // V151 R,G,B
- 0x80, 0x80, 0x80, // V87 R,G,B
- 0x80, 0x80, 0x80, // V51 R,G,B
- 0x80, 0x80, 0x80, // V35 R,G,B
- 0x80, 0x80, 0x80, // V23 R,G,B
- 0x80, 0x80, 0x80, // V11 R,G,B
- 0x6b, 0x68, 0x71, // V3 R,G,B
- 0x00, 0x00, 0x00); // V1 R,G,B
+ mipi_dsi_dcs_write_seq(dsi, 0xca,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, // V255 RR,GG,BB
+ 0x80, 0x80, 0x80, // V203 R,G,B
+ 0x80, 0x80, 0x80, // V151 R,G,B
+ 0x80, 0x80, 0x80, // V87 R,G,B
+ 0x80, 0x80, 0x80, // V51 R,G,B
+ 0x80, 0x80, 0x80, // V35 R,G,B
+ 0x80, 0x80, 0x80, // V23 R,G,B
+ 0x80, 0x80, 0x80, // V11 R,G,B
+ 0x6b, 0x68, 0x71, // V3 R,G,B
+ 0x00, 0x00, 0x00); // V1 R,G,B
// set default Amoled Off Ratio
- dsi_dcs_write_seq(dsi, 0xb2, 0x40, 0x0a, 0x17, 0x00, 0x0a);
- dsi_dcs_write_seq(dsi, 0xb6, 0x2c, 0x0b); // set default elvss voltage
- dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_POWER_SAVE, 0x00);
- dsi_dcs_write_seq(dsi, 0xf7, 0x03); // gamma/aor update
- dsi_dcs_write_seq(dsi, 0xf0, 0xa5, 0xa5); // disable LEVEL2 commands
+ mipi_dsi_dcs_write_seq(dsi, 0xb2, 0x40, 0x0a, 0x17, 0x00, 0x0a);
+ mipi_dsi_dcs_write_seq(dsi, 0xb6, 0x2c, 0x0b); // set default elvss voltage
+ mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_POWER_SAVE, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, 0xf7, 0x03); // gamma/aor update
+ mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xa5, 0xa5); // disable LEVEL2 commands
ret = mipi_dsi_dcs_set_display_on(dsi);
if (ret < 0) {
diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c b/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c
index 54213beafaf5..c51d07ec1529 100644
--- a/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c
+++ b/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c
@@ -990,8 +990,6 @@ static int s6e8aa0_probe(struct mipi_dsi_device *dsi)
dsi->lanes = 4;
dsi->format = MIPI_DSI_FMT_RGB888;
dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST
- | MIPI_DSI_MODE_VIDEO_NO_HFP | MIPI_DSI_MODE_VIDEO_NO_HBP
- | MIPI_DSI_MODE_VIDEO_NO_HSA | MIPI_DSI_MODE_NO_EOT_PACKET
| MIPI_DSI_MODE_VSYNC_FLUSH | MIPI_DSI_MODE_VIDEO_AUTO_VERT;
ret = s6e8aa0_parse_dt(ctx);
@@ -1018,6 +1016,7 @@ static int s6e8aa0_probe(struct mipi_dsi_device *dsi)
drm_panel_init(&ctx->panel, dev, &s6e8aa0_drm_funcs,
DRM_MODE_CONNECTOR_DSI);
+ ctx->panel.prepare_prev_first = true;
drm_panel_add(&ctx->panel);
diff --git a/drivers/gpu/drm/panel/panel-samsung-sofef00.c b/drivers/gpu/drm/panel/panel-samsung-sofef00.c
index 1a0d24595faa..1ebb79e3103c 100644
--- a/drivers/gpu/drm/panel/panel-samsung-sofef00.c
+++ b/drivers/gpu/drm/panel/panel-samsung-sofef00.c
@@ -10,7 +10,6 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/regulator/consumer.h>
-#include <linux/swab.h>
#include <linux/backlight.h>
#include <video/mipi_display.h>
@@ -34,14 +33,6 @@ struct sofef00_panel *to_sofef00_panel(struct drm_panel *panel)
return container_of(panel, struct sofef00_panel, panel);
}
-#define dsi_dcs_write_seq(dsi, seq...) do { \
- static const u8 d[] = { seq }; \
- int ret; \
- ret = mipi_dsi_dcs_write_buffer(dsi, d, ARRAY_SIZE(d)); \
- if (ret < 0) \
- return ret; \
- } while (0)
-
static void sofef00_panel_reset(struct sofef00_panel *ctx)
{
gpiod_set_value_cansleep(ctx->reset_gpio, 0);
@@ -67,7 +58,7 @@ static int sofef00_panel_on(struct sofef00_panel *ctx)
}
usleep_range(10000, 11000);
- dsi_dcs_write_seq(dsi, 0xf0, 0x5a, 0x5a);
+ mipi_dsi_dcs_write_seq(dsi, 0xf0, 0x5a, 0x5a);
ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
if (ret < 0) {
@@ -75,13 +66,13 @@ static int sofef00_panel_on(struct sofef00_panel *ctx)
return ret;
}
- dsi_dcs_write_seq(dsi, 0xf0, 0xa5, 0xa5);
- dsi_dcs_write_seq(dsi, 0xf0, 0x5a, 0x5a);
- dsi_dcs_write_seq(dsi, 0xb0, 0x07);
- dsi_dcs_write_seq(dsi, 0xb6, 0x12);
- dsi_dcs_write_seq(dsi, 0xf0, 0xa5, 0xa5);
- dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x20);
- dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_POWER_SAVE, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xa5, 0xa5);
+ mipi_dsi_dcs_write_seq(dsi, 0xf0, 0x5a, 0x5a);
+ mipi_dsi_dcs_write_seq(dsi, 0xb0, 0x07);
+ mipi_dsi_dcs_write_seq(dsi, 0xb6, 0x12);
+ mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xa5, 0xa5);
+ mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x20);
+ mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_POWER_SAVE, 0x00);
ret = mipi_dsi_dcs_set_display_on(dsi);
if (ret < 0) {
@@ -221,13 +212,9 @@ static int sofef00_panel_bl_update_status(struct backlight_device *bl)
{
struct mipi_dsi_device *dsi = bl_get_data(bl);
int err;
- u16 brightness;
-
- brightness = (u16)backlight_get_brightness(bl);
- // This panel needs the high and low bytes swapped for the brightness value
- brightness = __swab16(brightness);
+ u16 brightness = (u16)backlight_get_brightness(bl);
- err = mipi_dsi_dcs_set_display_brightness(dsi, brightness);
+ err = mipi_dsi_dcs_set_display_brightness_large(dsi, brightness);
if (err < 0)
return err;
diff --git a/drivers/gpu/drm/panel/panel-sharp-ls060t1sx01.c b/drivers/gpu/drm/panel/panel-sharp-ls060t1sx01.c
index 8a4e0c1fe73f..68f52eaaf4fa 100644
--- a/drivers/gpu/drm/panel/panel-sharp-ls060t1sx01.c
+++ b/drivers/gpu/drm/panel/panel-sharp-ls060t1sx01.c
@@ -32,12 +32,6 @@ static inline struct sharp_ls060 *to_sharp_ls060(struct drm_panel *panel)
return container_of(panel, struct sharp_ls060, panel);
}
-#define dsi_dcs_write_seq(dsi, seq...) ({ \
- static const u8 d[] = { seq }; \
- \
- mipi_dsi_dcs_write_buffer(dsi, d, ARRAY_SIZE(d)); \
- })
-
static void sharp_ls060_reset(struct sharp_ls060 *ctx)
{
gpiod_set_value_cansleep(ctx->reset_gpio, 0);
@@ -56,17 +50,8 @@ static int sharp_ls060_on(struct sharp_ls060 *ctx)
dsi->mode_flags |= MIPI_DSI_MODE_LPM;
- ret = dsi_dcs_write_seq(dsi, 0xbb, 0x13);
- if (ret < 0) {
- dev_err(dev, "Failed to send command: %d\n", ret);
- return ret;
- }
-
- ret = dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_MEMORY_START);
- if (ret < 0) {
- dev_err(dev, "Failed to send command: %d\n", ret);
- return ret;
- }
+ mipi_dsi_dcs_write_seq(dsi, 0xbb, 0x13);
+ mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_MEMORY_START);
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
if (ret < 0) {
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
index 8a3b685c2fcc..065f378bba9d 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -280,7 +280,7 @@ static void panel_simple_wait(ktime_t start_ktime, unsigned int min_ms)
return;
min_ktime = ktime_add(start_ktime, ms_to_ktime(min_ms));
- now_ktime = ktime_get();
+ now_ktime = ktime_get_boottime();
if (ktime_before(now_ktime, min_ktime))
msleep(ktime_to_ms(ktime_sub(min_ktime, now_ktime)) + 1);
@@ -307,7 +307,7 @@ static int panel_simple_suspend(struct device *dev)
gpiod_set_value_cansleep(p->enable_gpio, 0);
regulator_disable(p->supply);
- p->unprepared_time = ktime_get();
+ p->unprepared_time = ktime_get_boottime();
kfree(p->edid);
p->edid = NULL;
@@ -351,7 +351,7 @@ static int panel_simple_resume(struct device *dev)
if (p->desc->delay.prepare)
msleep(p->desc->delay.prepare);
- p->prepared_time = ktime_get();
+ p->prepared_time = ktime_get_boottime();
return 0;
}
diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7703.c b/drivers/gpu/drm/panel/panel-sitronix-st7703.c
index 86a472b01360..6747ca237ced 100644
--- a/drivers/gpu/drm/panel/panel-sitronix-st7703.c
+++ b/drivers/gpu/drm/panel/panel-sitronix-st7703.c
@@ -73,14 +73,6 @@ static inline struct st7703 *panel_to_st7703(struct drm_panel *panel)
return container_of(panel, struct st7703, panel);
}
-#define dsi_generic_write_seq(dsi, seq...) do { \
- static const u8 d[] = { seq }; \
- int ret; \
- ret = mipi_dsi_generic_write(dsi, d, ARRAY_SIZE(d)); \
- if (ret < 0) \
- return ret; \
- } while (0)
-
static int jh057n_init_sequence(struct st7703 *ctx)
{
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
@@ -90,50 +82,50 @@ static int jh057n_init_sequence(struct st7703 *ctx)
* resemble the ST7703 but the number of parameters often don't match
* so it's likely a clone.
*/
- dsi_generic_write_seq(dsi, ST7703_CMD_SETEXTC,
- 0xF1, 0x12, 0x83);
- dsi_generic_write_seq(dsi, ST7703_CMD_SETRGBIF,
- 0x10, 0x10, 0x05, 0x05, 0x03, 0xFF, 0x00, 0x00,
- 0x00, 0x00);
- dsi_generic_write_seq(dsi, ST7703_CMD_SETSCR,
- 0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 0x08, 0x70,
- 0x00);
- dsi_generic_write_seq(dsi, ST7703_CMD_SETVDC, 0x4E);
- dsi_generic_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B);
- dsi_generic_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
- dsi_generic_write_seq(dsi, ST7703_CMD_SETDISP, 0xF0, 0x12, 0x30);
- dsi_generic_write_seq(dsi, ST7703_CMD_SETEQ,
- 0x07, 0x07, 0x0B, 0x0B, 0x03, 0x0B, 0x00, 0x00,
- 0x00, 0x00, 0xFF, 0x00, 0xC0, 0x10);
- dsi_generic_write_seq(dsi, ST7703_CMD_SETBGP, 0x08, 0x08);
+ mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETEXTC,
+ 0xF1, 0x12, 0x83);
+ mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETRGBIF,
+ 0x10, 0x10, 0x05, 0x05, 0x03, 0xFF, 0x00, 0x00,
+ 0x00, 0x00);
+ mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETSCR,
+ 0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 0x08, 0x70,
+ 0x00);
+ mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETVDC, 0x4E);
+ mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B);
+ mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
+ mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETDISP, 0xF0, 0x12, 0x30);
+ mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETEQ,
+ 0x07, 0x07, 0x0B, 0x0B, 0x03, 0x0B, 0x00, 0x00,
+ 0x00, 0x00, 0xFF, 0x00, 0xC0, 0x10);
+ mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETBGP, 0x08, 0x08);
msleep(20);
- dsi_generic_write_seq(dsi, ST7703_CMD_SETVCOM, 0x3F, 0x3F);
- dsi_generic_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
- dsi_generic_write_seq(dsi, ST7703_CMD_SETGIP1,
- 0x82, 0x10, 0x06, 0x05, 0x9E, 0x0A, 0xA5, 0x12,
- 0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
- 0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
- 0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
- 0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
- 0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
- 0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
- dsi_generic_write_seq(dsi, ST7703_CMD_SETGIP2,
- 0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
- 0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
- 0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
- 0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0A,
- 0xA5, 0x00, 0x00, 0x00, 0x00);
- dsi_generic_write_seq(dsi, ST7703_CMD_SETGAMMA,
- 0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41, 0x37,
- 0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10, 0x11,
- 0x18, 0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41,
- 0x37, 0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10,
- 0x11, 0x18);
+ mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETVCOM, 0x3F, 0x3F);
+ mipi_dsi_generic_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
+ mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETGIP1,
+ 0x82, 0x10, 0x06, 0x05, 0x9E, 0x0A, 0xA5, 0x12,
+ 0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
+ 0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
+ 0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
+ 0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+ 0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+ mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETGIP2,
+ 0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
+ 0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
+ 0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+ 0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0A,
+ 0xA5, 0x00, 0x00, 0x00, 0x00);
+ mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETGAMMA,
+ 0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41, 0x37,
+ 0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10, 0x11,
+ 0x18, 0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41,
+ 0x37, 0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10,
+ 0x11, 0x18);
return 0;
}
@@ -162,15 +154,6 @@ static const struct st7703_panel_desc jh057n00900_panel_desc = {
.init_sequence = jh057n_init_sequence,
};
-#define dsi_dcs_write_seq(dsi, cmd, seq...) do { \
- static const u8 d[] = { seq }; \
- int ret; \
- ret = mipi_dsi_dcs_write(dsi, cmd, d, ARRAY_SIZE(d)); \
- if (ret < 0) \
- return ret; \
- } while (0)
-
-
static int xbd599_init_sequence(struct st7703 *ctx)
{
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
@@ -180,154 +163,154 @@ static int xbd599_init_sequence(struct st7703 *ctx)
*/
/* Magic sequence to unlock user commands below. */
- dsi_dcs_write_seq(dsi, ST7703_CMD_SETEXTC, 0xF1, 0x12, 0x83);
-
- dsi_dcs_write_seq(dsi, ST7703_CMD_SETMIPI,
- 0x33, /* VC_main = 0, Lane_Number = 3 (4 lanes) */
- 0x81, /* DSI_LDO_SEL = 1.7V, RTERM = 90 Ohm */
- 0x05, /* IHSRX = x6 (Low High Speed driving ability) */
- 0xF9, /* TX_CLK_SEL = fDSICLK/16 */
- 0x0E, /* HFP_OSC (min. HFP number in DSI mode) */
- 0x0E, /* HBP_OSC (min. HBP number in DSI mode) */
- /* The rest is undocumented in ST7703 datasheet */
- 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x44, 0x25, 0x00, 0x91, 0x0a, 0x00, 0x00, 0x02,
- 0x4F, 0x11, 0x00, 0x00, 0x37);
-
- dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER_EXT,
- 0x25, /* PCCS = 2, ECP_DC_DIV = 1/4 HSYNC */
- 0x22, /* DT = 15ms XDK_ECP = x2 */
- 0x20, /* PFM_DC_DIV = /1 */
- 0x03 /* ECP_SYNC_EN = 1, VGX_SYNC_EN = 1 */);
+ mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEXTC, 0xF1, 0x12, 0x83);
+
+ mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETMIPI,
+ 0x33, /* VC_main = 0, Lane_Number = 3 (4 lanes) */
+ 0x81, /* DSI_LDO_SEL = 1.7V, RTERM = 90 Ohm */
+ 0x05, /* IHSRX = x6 (Low High Speed driving ability) */
+ 0xF9, /* TX_CLK_SEL = fDSICLK/16 */
+ 0x0E, /* HFP_OSC (min. HFP number in DSI mode) */
+ 0x0E, /* HBP_OSC (min. HBP number in DSI mode) */
+ /* The rest is undocumented in ST7703 datasheet */
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x44, 0x25, 0x00, 0x91, 0x0a, 0x00, 0x00, 0x02,
+ 0x4F, 0x11, 0x00, 0x00, 0x37);
+
+ mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER_EXT,
+ 0x25, /* PCCS = 2, ECP_DC_DIV = 1/4 HSYNC */
+ 0x22, /* DT = 15ms XDK_ECP = x2 */
+ 0x20, /* PFM_DC_DIV = /1 */
+ 0x03 /* ECP_SYNC_EN = 1, VGX_SYNC_EN = 1 */);
/* RGB I/F porch timing */
- dsi_dcs_write_seq(dsi, ST7703_CMD_SETRGBIF,
- 0x10, /* VBP_RGB_GEN */
- 0x10, /* VFP_RGB_GEN */
- 0x05, /* DE_BP_RGB_GEN */
- 0x05, /* DE_FP_RGB_GEN */
- /* The rest is undocumented in ST7703 datasheet */
- 0x03, 0xFF,
- 0x00, 0x00,
- 0x00, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETRGBIF,
+ 0x10, /* VBP_RGB_GEN */
+ 0x10, /* VFP_RGB_GEN */
+ 0x05, /* DE_BP_RGB_GEN */
+ 0x05, /* DE_FP_RGB_GEN */
+ /* The rest is undocumented in ST7703 datasheet */
+ 0x03, 0xFF,
+ 0x00, 0x00,
+ 0x00, 0x00);
/* Source driving settings. */
- dsi_dcs_write_seq(dsi, ST7703_CMD_SETSCR,
- 0x73, /* N_POPON */
- 0x73, /* N_NOPON */
- 0x50, /* I_POPON */
- 0x50, /* I_NOPON */
- 0x00, /* SCR[31,24] */
- 0xC0, /* SCR[23,16] */
- 0x08, /* SCR[15,8] */
- 0x70, /* SCR[7,0] */
- 0x00 /* Undocumented */);
+ mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETSCR,
+ 0x73, /* N_POPON */
+ 0x73, /* N_NOPON */
+ 0x50, /* I_POPON */
+ 0x50, /* I_NOPON */
+ 0x00, /* SCR[31,24] */
+ 0xC0, /* SCR[23,16] */
+ 0x08, /* SCR[15,8] */
+ 0x70, /* SCR[7,0] */
+ 0x00 /* Undocumented */);
/* NVDDD_SEL = -1.8V, VDDD_SEL = out of range (possibly 1.9V?) */
- dsi_dcs_write_seq(dsi, ST7703_CMD_SETVDC, 0x4E);
+ mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVDC, 0x4E);
/*
* SS_PANEL = 1 (reverse scan), GS_PANEL = 0 (normal scan)
* REV_PANEL = 1 (normally black panel), BGR_PANEL = 1 (BGR)
*/
- dsi_dcs_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B);
+ mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B);
/* Zig-Zag Type C column inversion. */
- dsi_dcs_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
+ mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
/* Set display resolution. */
- dsi_dcs_write_seq(dsi, ST7703_CMD_SETDISP,
- 0xF0, /* NL = 240 */
- 0x12, /* RES_V_LSB = 0, BLK_CON = VSSD,
- * RESO_SEL = 720RGB
- */
- 0xF0 /* WHITE_GND_EN = 1 (GND),
- * WHITE_FRAME_SEL = 7 frames,
- * ISC = 0 frames
- */);
-
- dsi_dcs_write_seq(dsi, ST7703_CMD_SETEQ,
- 0x00, /* PNOEQ */
- 0x00, /* NNOEQ */
- 0x0B, /* PEQGND */
- 0x0B, /* NEQGND */
- 0x10, /* PEQVCI */
- 0x10, /* NEQVCI */
- 0x00, /* PEQVCI1 */
- 0x00, /* NEQVCI1 */
- 0x00, /* reserved */
- 0x00, /* reserved */
- 0xFF, /* reserved */
- 0x00, /* reserved */
- 0xC0, /* ESD_DET_DATA_WHITE = 1, ESD_WHITE_EN = 1 */
- 0x10 /* SLPIN_OPTION = 1 (no need vsync after sleep-in)
- * VEDIO_NO_CHECK_EN = 0
- * ESD_WHITE_GND_EN = 0
- * ESD_DET_TIME_SEL = 0 frames
- */);
+ mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETDISP,
+ 0xF0, /* NL = 240 */
+ 0x12, /* RES_V_LSB = 0, BLK_CON = VSSD,
+ * RESO_SEL = 720RGB
+ */
+ 0xF0 /* WHITE_GND_EN = 1 (GND),
+ * WHITE_FRAME_SEL = 7 frames,
+ * ISC = 0 frames
+ */);
+
+ mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEQ,
+ 0x00, /* PNOEQ */
+ 0x00, /* NNOEQ */
+ 0x0B, /* PEQGND */
+ 0x0B, /* NEQGND */
+ 0x10, /* PEQVCI */
+ 0x10, /* NEQVCI */
+ 0x00, /* PEQVCI1 */
+ 0x00, /* NEQVCI1 */
+ 0x00, /* reserved */
+ 0x00, /* reserved */
+ 0xFF, /* reserved */
+ 0x00, /* reserved */
+ 0xC0, /* ESD_DET_DATA_WHITE = 1, ESD_WHITE_EN = 1 */
+ 0x10 /* SLPIN_OPTION = 1 (no need vsync after sleep-in)
+ * VEDIO_NO_CHECK_EN = 0
+ * ESD_WHITE_GND_EN = 0
+ * ESD_DET_TIME_SEL = 0 frames
+ */);
/* Undocumented command. */
- dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_C6, 0x01, 0x00, 0xFF, 0xFF, 0x00);
-
- dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER,
- 0x74, /* VBTHS, VBTLS: VGH = 17V, VBL = -11V */
- 0x00, /* FBOFF_VGH = 0, FBOFF_VGL = 0 */
- 0x32, /* VRP */
- 0x32, /* VRN */
- 0x77, /* reserved */
- 0xF1, /* APS = 1 (small),
- * VGL_DET_EN = 1, VGH_DET_EN = 1,
- * VGL_TURBO = 1, VGH_TURBO = 1
- */
- 0xFF, /* VGH1_L_DIV, VGL1_L_DIV (1.5MHz) */
- 0xFF, /* VGH1_R_DIV, VGL1_R_DIV (1.5MHz) */
- 0xCC, /* VGH2_L_DIV, VGL2_L_DIV (2.6MHz) */
- 0xCC, /* VGH2_R_DIV, VGL2_R_DIV (2.6MHz) */
- 0x77, /* VGH3_L_DIV, VGL3_L_DIV (4.5MHz) */
- 0x77 /* VGH3_R_DIV, VGL3_R_DIV (4.5MHz) */);
+ mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_C6, 0x01, 0x00, 0xFF, 0xFF, 0x00);
+
+ mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER,
+ 0x74, /* VBTHS, VBTLS: VGH = 17V, VBL = -11V */
+ 0x00, /* FBOFF_VGH = 0, FBOFF_VGL = 0 */
+ 0x32, /* VRP */
+ 0x32, /* VRN */
+ 0x77, /* reserved */
+ 0xF1, /* APS = 1 (small),
+ * VGL_DET_EN = 1, VGH_DET_EN = 1,
+ * VGL_TURBO = 1, VGH_TURBO = 1
+ */
+ 0xFF, /* VGH1_L_DIV, VGL1_L_DIV (1.5MHz) */
+ 0xFF, /* VGH1_R_DIV, VGL1_R_DIV (1.5MHz) */
+ 0xCC, /* VGH2_L_DIV, VGL2_L_DIV (2.6MHz) */
+ 0xCC, /* VGH2_R_DIV, VGL2_R_DIV (2.6MHz) */
+ 0x77, /* VGH3_L_DIV, VGL3_L_DIV (4.5MHz) */
+ 0x77 /* VGH3_R_DIV, VGL3_R_DIV (4.5MHz) */);
/* Reference voltage. */
- dsi_dcs_write_seq(dsi, ST7703_CMD_SETBGP,
- 0x07, /* VREF_SEL = 4.2V */
- 0x07 /* NVREF_SEL = 4.2V */);
+ mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETBGP,
+ 0x07, /* VREF_SEL = 4.2V */
+ 0x07 /* NVREF_SEL = 4.2V */);
msleep(20);
- dsi_dcs_write_seq(dsi, ST7703_CMD_SETVCOM,
- 0x2C, /* VCOMDC_F = -0.67V */
- 0x2C /* VCOMDC_B = -0.67V */);
+ mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVCOM,
+ 0x2C, /* VCOMDC_F = -0.67V */
+ 0x2C /* VCOMDC_B = -0.67V */);
/* Undocumented command. */
- dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
/* This command is to set forward GIP timing. */
- dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP1,
- 0x82, 0x10, 0x06, 0x05, 0xA2, 0x0A, 0xA5, 0x12,
- 0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
- 0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
- 0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
- 0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
- 0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
- 0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP1,
+ 0x82, 0x10, 0x06, 0x05, 0xA2, 0x0A, 0xA5, 0x12,
+ 0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
+ 0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
+ 0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
+ 0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+ 0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
/* This command is to set backward GIP timing. */
- dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP2,
- 0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
- 0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
- 0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
- 0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0A,
- 0xA5, 0x00, 0x00, 0x00, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP2,
+ 0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
+ 0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
+ 0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+ 0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0A,
+ 0xA5, 0x00, 0x00, 0x00, 0x00);
/* Adjust the gamma characteristics of the panel. */
- dsi_dcs_write_seq(dsi, ST7703_CMD_SETGAMMA,
- 0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41, 0x35,
- 0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12, 0x12,
- 0x18, 0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41,
- 0x35, 0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12,
- 0x12, 0x18);
+ mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGAMMA,
+ 0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41, 0x35,
+ 0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12, 0x12,
+ 0x18, 0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41,
+ 0x35, 0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12,
+ 0x12, 0x18);
return 0;
}
@@ -499,7 +482,7 @@ static int allpixelson_set(void *data, u64 val)
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
dev_dbg(ctx->dev, "Setting all pixels on\n");
- dsi_generic_write_seq(dsi, ST7703_CMD_ALL_PIXEL_ON);
+ mipi_dsi_generic_write_seq(dsi, ST7703_CMD_ALL_PIXEL_ON);
msleep(val * 1000);
/* Reset the panel to get video back */
drm_panel_disable(&ctx->panel);
diff --git a/drivers/gpu/drm/panel/panel-sony-tulip-truly-nt35521.c b/drivers/gpu/drm/panel/panel-sony-tulip-truly-nt35521.c
index fa9be3c299c0..ee5d20ecc577 100644
--- a/drivers/gpu/drm/panel/panel-sony-tulip-truly-nt35521.c
+++ b/drivers/gpu/drm/panel/panel-sony-tulip-truly-nt35521.c
@@ -33,14 +33,6 @@ struct truly_nt35521 *to_truly_nt35521(struct drm_panel *panel)
return container_of(panel, struct truly_nt35521, panel);
}
-#define dsi_generic_write_seq(dsi, seq...) do { \
- static const u8 d[] = { seq }; \
- int ret; \
- ret = mipi_dsi_generic_write(dsi, d, ARRAY_SIZE(d)); \
- if (ret < 0) \
- return ret; \
- } while (0)
-
static void truly_nt35521_reset(struct truly_nt35521 *ctx)
{
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
@@ -59,200 +51,200 @@ static int truly_nt35521_on(struct truly_nt35521 *ctx)
dsi->mode_flags |= MIPI_DSI_MODE_LPM;
- dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x00);
- dsi_generic_write_seq(dsi, 0xff, 0xaa, 0x55, 0xa5, 0x80);
- dsi_generic_write_seq(dsi, 0x6f, 0x11, 0x00);
- dsi_generic_write_seq(dsi, 0xf7, 0x20, 0x00);
- dsi_generic_write_seq(dsi, 0x6f, 0x01);
- dsi_generic_write_seq(dsi, 0xb1, 0x21);
- dsi_generic_write_seq(dsi, 0xbd, 0x01, 0xa0, 0x10, 0x08, 0x01);
- dsi_generic_write_seq(dsi, 0xb8, 0x01, 0x02, 0x0c, 0x02);
- dsi_generic_write_seq(dsi, 0xbb, 0x11, 0x11);
- dsi_generic_write_seq(dsi, 0xbc, 0x00, 0x00);
- dsi_generic_write_seq(dsi, 0xb6, 0x02);
- dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x01);
- dsi_generic_write_seq(dsi, 0xb0, 0x09, 0x09);
- dsi_generic_write_seq(dsi, 0xb1, 0x09, 0x09);
- dsi_generic_write_seq(dsi, 0xbc, 0x8c, 0x00);
- dsi_generic_write_seq(dsi, 0xbd, 0x8c, 0x00);
- dsi_generic_write_seq(dsi, 0xca, 0x00);
- dsi_generic_write_seq(dsi, 0xc0, 0x04);
- dsi_generic_write_seq(dsi, 0xbe, 0xb5);
- dsi_generic_write_seq(dsi, 0xb3, 0x35, 0x35);
- dsi_generic_write_seq(dsi, 0xb4, 0x25, 0x25);
- dsi_generic_write_seq(dsi, 0xb9, 0x43, 0x43);
- dsi_generic_write_seq(dsi, 0xba, 0x24, 0x24);
- dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x02);
- dsi_generic_write_seq(dsi, 0xee, 0x03);
- dsi_generic_write_seq(dsi, 0xb0,
- 0x00, 0xb2, 0x00, 0xb3, 0x00, 0xb6, 0x00, 0xc3,
- 0x00, 0xce, 0x00, 0xe1, 0x00, 0xf3, 0x01, 0x11);
- dsi_generic_write_seq(dsi, 0xb1,
- 0x01, 0x2e, 0x01, 0x5c, 0x01, 0x82, 0x01, 0xc3,
- 0x01, 0xfe, 0x02, 0x00, 0x02, 0x37, 0x02, 0x77);
- dsi_generic_write_seq(dsi, 0xb2,
- 0x02, 0xa1, 0x02, 0xd7, 0x02, 0xfe, 0x03, 0x2c,
- 0x03, 0x4b, 0x03, 0x63, 0x03, 0x8f, 0x03, 0x90);
- dsi_generic_write_seq(dsi, 0xb3, 0x03, 0x96, 0x03, 0x98);
- dsi_generic_write_seq(dsi, 0xb4,
- 0x00, 0x81, 0x00, 0x8b, 0x00, 0x9c, 0x00, 0xa9,
- 0x00, 0xb5, 0x00, 0xcb, 0x00, 0xdf, 0x01, 0x02);
- dsi_generic_write_seq(dsi, 0xb5,
- 0x01, 0x1f, 0x01, 0x51, 0x01, 0x7a, 0x01, 0xbf,
- 0x01, 0xfa, 0x01, 0xfc, 0x02, 0x34, 0x02, 0x76);
- dsi_generic_write_seq(dsi, 0xb6,
- 0x02, 0x9f, 0x02, 0xd7, 0x02, 0xfc, 0x03, 0x2c,
- 0x03, 0x4a, 0x03, 0x63, 0x03, 0x8f, 0x03, 0xa2);
- dsi_generic_write_seq(dsi, 0xb7, 0x03, 0xb8, 0x03, 0xba);
- dsi_generic_write_seq(dsi, 0xb8,
- 0x00, 0x01, 0x00, 0x02, 0x00, 0x0e, 0x00, 0x2a,
- 0x00, 0x41, 0x00, 0x67, 0x00, 0x87, 0x00, 0xb9);
- dsi_generic_write_seq(dsi, 0xb9,
- 0x00, 0xe2, 0x01, 0x22, 0x01, 0x54, 0x01, 0xa3,
- 0x01, 0xe6, 0x01, 0xe7, 0x02, 0x24, 0x02, 0x67);
- dsi_generic_write_seq(dsi, 0xba,
- 0x02, 0x93, 0x02, 0xcd, 0x02, 0xf6, 0x03, 0x31,
- 0x03, 0x6c, 0x03, 0xe9, 0x03, 0xef, 0x03, 0xf4);
- dsi_generic_write_seq(dsi, 0xbb, 0x03, 0xf6, 0x03, 0xf7);
- dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x03);
- dsi_generic_write_seq(dsi, 0xb0, 0x22, 0x00);
- dsi_generic_write_seq(dsi, 0xb1, 0x22, 0x00);
- dsi_generic_write_seq(dsi, 0xb2, 0x05, 0x00, 0x60, 0x00, 0x00);
- dsi_generic_write_seq(dsi, 0xb3, 0x05, 0x00, 0x60, 0x00, 0x00);
- dsi_generic_write_seq(dsi, 0xb4, 0x05, 0x00, 0x60, 0x00, 0x00);
- dsi_generic_write_seq(dsi, 0xb5, 0x05, 0x00, 0x60, 0x00, 0x00);
- dsi_generic_write_seq(dsi, 0xba, 0x53, 0x00, 0x60, 0x00, 0x00);
- dsi_generic_write_seq(dsi, 0xbb, 0x53, 0x00, 0x60, 0x00, 0x00);
- dsi_generic_write_seq(dsi, 0xbc, 0x53, 0x00, 0x60, 0x00, 0x00);
- dsi_generic_write_seq(dsi, 0xbd, 0x53, 0x00, 0x60, 0x00, 0x00);
- dsi_generic_write_seq(dsi, 0xc0, 0x00, 0x34, 0x00, 0x00);
- dsi_generic_write_seq(dsi, 0xc1, 0x00, 0x00, 0x34, 0x00);
- dsi_generic_write_seq(dsi, 0xc2, 0x00, 0x00, 0x34, 0x00);
- dsi_generic_write_seq(dsi, 0xc3, 0x00, 0x00, 0x34, 0x00);
- dsi_generic_write_seq(dsi, 0xc4, 0x60);
- dsi_generic_write_seq(dsi, 0xc5, 0xc0);
- dsi_generic_write_seq(dsi, 0xc6, 0x00);
- dsi_generic_write_seq(dsi, 0xc7, 0x00);
- dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x05);
- dsi_generic_write_seq(dsi, 0xb0, 0x17, 0x06);
- dsi_generic_write_seq(dsi, 0xb1, 0x17, 0x06);
- dsi_generic_write_seq(dsi, 0xb2, 0x17, 0x06);
- dsi_generic_write_seq(dsi, 0xb3, 0x17, 0x06);
- dsi_generic_write_seq(dsi, 0xb4, 0x17, 0x06);
- dsi_generic_write_seq(dsi, 0xb5, 0x17, 0x06);
- dsi_generic_write_seq(dsi, 0xb6, 0x17, 0x06);
- dsi_generic_write_seq(dsi, 0xb7, 0x17, 0x06);
- dsi_generic_write_seq(dsi, 0xb8, 0x00);
- dsi_generic_write_seq(dsi, 0xb9, 0x00, 0x03);
- dsi_generic_write_seq(dsi, 0xba, 0x00, 0x00);
- dsi_generic_write_seq(dsi, 0xbb, 0x02, 0x03);
- dsi_generic_write_seq(dsi, 0xbc, 0x02, 0x03);
- dsi_generic_write_seq(dsi, 0xbd, 0x03, 0x03, 0x00, 0x03, 0x03);
- dsi_generic_write_seq(dsi, 0xc0, 0x0b);
- dsi_generic_write_seq(dsi, 0xc1, 0x09);
- dsi_generic_write_seq(dsi, 0xc2, 0xa6);
- dsi_generic_write_seq(dsi, 0xc3, 0x05);
- dsi_generic_write_seq(dsi, 0xc4, 0x00);
- dsi_generic_write_seq(dsi, 0xc5, 0x02);
- dsi_generic_write_seq(dsi, 0xc6, 0x22);
- dsi_generic_write_seq(dsi, 0xc7, 0x03);
- dsi_generic_write_seq(dsi, 0xc8, 0x07, 0x20);
- dsi_generic_write_seq(dsi, 0xc9, 0x03, 0x20);
- dsi_generic_write_seq(dsi, 0xca, 0x01, 0x60);
- dsi_generic_write_seq(dsi, 0xcb, 0x01, 0x60);
- dsi_generic_write_seq(dsi, 0xcc, 0x00, 0x00, 0x02);
- dsi_generic_write_seq(dsi, 0xcd, 0x00, 0x00, 0x02);
- dsi_generic_write_seq(dsi, 0xce, 0x00, 0x00, 0x02);
- dsi_generic_write_seq(dsi, 0xcf, 0x00, 0x00, 0x02);
- dsi_generic_write_seq(dsi, 0xd1, 0x00, 0x05, 0x01, 0x07, 0x10);
- dsi_generic_write_seq(dsi, 0xd2, 0x10, 0x05, 0x05, 0x03, 0x10);
- dsi_generic_write_seq(dsi, 0xd3, 0x20, 0x00, 0x43, 0x07, 0x10);
- dsi_generic_write_seq(dsi, 0xd4, 0x30, 0x00, 0x43, 0x07, 0x10);
- dsi_generic_write_seq(dsi, 0xd0,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
- dsi_generic_write_seq(dsi, 0xd5,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00);
- dsi_generic_write_seq(dsi, 0xd6,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00);
- dsi_generic_write_seq(dsi, 0xd7,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00);
- dsi_generic_write_seq(dsi, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00);
- dsi_generic_write_seq(dsi, 0xe5, 0x06);
- dsi_generic_write_seq(dsi, 0xe6, 0x06);
- dsi_generic_write_seq(dsi, 0xe7, 0x00);
- dsi_generic_write_seq(dsi, 0xe8, 0x06);
- dsi_generic_write_seq(dsi, 0xe9, 0x06);
- dsi_generic_write_seq(dsi, 0xea, 0x06);
- dsi_generic_write_seq(dsi, 0xeb, 0x00);
- dsi_generic_write_seq(dsi, 0xec, 0x00);
- dsi_generic_write_seq(dsi, 0xed, 0x30);
- dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x06);
- dsi_generic_write_seq(dsi, 0xb0, 0x31, 0x31);
- dsi_generic_write_seq(dsi, 0xb1, 0x31, 0x31);
- dsi_generic_write_seq(dsi, 0xb2, 0x2d, 0x2e);
- dsi_generic_write_seq(dsi, 0xb3, 0x31, 0x34);
- dsi_generic_write_seq(dsi, 0xb4, 0x29, 0x2a);
- dsi_generic_write_seq(dsi, 0xb5, 0x12, 0x10);
- dsi_generic_write_seq(dsi, 0xb6, 0x18, 0x16);
- dsi_generic_write_seq(dsi, 0xb7, 0x00, 0x02);
- dsi_generic_write_seq(dsi, 0xb8, 0x08, 0x31);
- dsi_generic_write_seq(dsi, 0xb9, 0x31, 0x31);
- dsi_generic_write_seq(dsi, 0xba, 0x31, 0x31);
- dsi_generic_write_seq(dsi, 0xbb, 0x31, 0x08);
- dsi_generic_write_seq(dsi, 0xbc, 0x03, 0x01);
- dsi_generic_write_seq(dsi, 0xbd, 0x17, 0x19);
- dsi_generic_write_seq(dsi, 0xbe, 0x11, 0x13);
- dsi_generic_write_seq(dsi, 0xbf, 0x2a, 0x29);
- dsi_generic_write_seq(dsi, 0xc0, 0x34, 0x31);
- dsi_generic_write_seq(dsi, 0xc1, 0x2e, 0x2d);
- dsi_generic_write_seq(dsi, 0xc2, 0x31, 0x31);
- dsi_generic_write_seq(dsi, 0xc3, 0x31, 0x31);
- dsi_generic_write_seq(dsi, 0xc4, 0x31, 0x31);
- dsi_generic_write_seq(dsi, 0xc5, 0x31, 0x31);
- dsi_generic_write_seq(dsi, 0xc6, 0x2e, 0x2d);
- dsi_generic_write_seq(dsi, 0xc7, 0x31, 0x34);
- dsi_generic_write_seq(dsi, 0xc8, 0x29, 0x2a);
- dsi_generic_write_seq(dsi, 0xc9, 0x17, 0x19);
- dsi_generic_write_seq(dsi, 0xca, 0x11, 0x13);
- dsi_generic_write_seq(dsi, 0xcb, 0x03, 0x01);
- dsi_generic_write_seq(dsi, 0xcc, 0x08, 0x31);
- dsi_generic_write_seq(dsi, 0xcd, 0x31, 0x31);
- dsi_generic_write_seq(dsi, 0xce, 0x31, 0x31);
- dsi_generic_write_seq(dsi, 0xcf, 0x31, 0x08);
- dsi_generic_write_seq(dsi, 0xd0, 0x00, 0x02);
- dsi_generic_write_seq(dsi, 0xd1, 0x12, 0x10);
- dsi_generic_write_seq(dsi, 0xd2, 0x18, 0x16);
- dsi_generic_write_seq(dsi, 0xd3, 0x2a, 0x29);
- dsi_generic_write_seq(dsi, 0xd4, 0x34, 0x31);
- dsi_generic_write_seq(dsi, 0xd5, 0x2d, 0x2e);
- dsi_generic_write_seq(dsi, 0xd6, 0x31, 0x31);
- dsi_generic_write_seq(dsi, 0xd7, 0x31, 0x31);
- dsi_generic_write_seq(dsi, 0xe5, 0x31, 0x31);
- dsi_generic_write_seq(dsi, 0xe6, 0x31, 0x31);
- dsi_generic_write_seq(dsi, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00);
- dsi_generic_write_seq(dsi, 0xd9, 0x00, 0x00, 0x00, 0x00, 0x00);
- dsi_generic_write_seq(dsi, 0xe7, 0x00);
- dsi_generic_write_seq(dsi, 0x6f, 0x02);
- dsi_generic_write_seq(dsi, 0xf7, 0x47);
- dsi_generic_write_seq(dsi, 0x6f, 0x0a);
- dsi_generic_write_seq(dsi, 0xf7, 0x02);
- dsi_generic_write_seq(dsi, 0x6f, 0x17);
- dsi_generic_write_seq(dsi, 0xf4, 0x60);
- dsi_generic_write_seq(dsi, 0x6f, 0x01);
- dsi_generic_write_seq(dsi, 0xf9, 0x46);
- dsi_generic_write_seq(dsi, 0x6f, 0x11);
- dsi_generic_write_seq(dsi, 0xf3, 0x01);
- dsi_generic_write_seq(dsi, 0x35, 0x00);
- dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x00);
- dsi_generic_write_seq(dsi, 0xd9, 0x02, 0x03, 0x00);
- dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x00, 0x00);
- dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x00);
- dsi_generic_write_seq(dsi, 0xb1, 0x6c, 0x21);
- dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x00, 0x00);
- dsi_generic_write_seq(dsi, 0x35, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xff, 0xaa, 0x55, 0xa5, 0x80);
+ mipi_dsi_generic_write_seq(dsi, 0x6f, 0x11, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xf7, 0x20, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0x6f, 0x01);
+ mipi_dsi_generic_write_seq(dsi, 0xb1, 0x21);
+ mipi_dsi_generic_write_seq(dsi, 0xbd, 0x01, 0xa0, 0x10, 0x08, 0x01);
+ mipi_dsi_generic_write_seq(dsi, 0xb8, 0x01, 0x02, 0x0c, 0x02);
+ mipi_dsi_generic_write_seq(dsi, 0xbb, 0x11, 0x11);
+ mipi_dsi_generic_write_seq(dsi, 0xbc, 0x00, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xb6, 0x02);
+ mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x01);
+ mipi_dsi_generic_write_seq(dsi, 0xb0, 0x09, 0x09);
+ mipi_dsi_generic_write_seq(dsi, 0xb1, 0x09, 0x09);
+ mipi_dsi_generic_write_seq(dsi, 0xbc, 0x8c, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xbd, 0x8c, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xca, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xc0, 0x04);
+ mipi_dsi_generic_write_seq(dsi, 0xbe, 0xb5);
+ mipi_dsi_generic_write_seq(dsi, 0xb3, 0x35, 0x35);
+ mipi_dsi_generic_write_seq(dsi, 0xb4, 0x25, 0x25);
+ mipi_dsi_generic_write_seq(dsi, 0xb9, 0x43, 0x43);
+ mipi_dsi_generic_write_seq(dsi, 0xba, 0x24, 0x24);
+ mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x02);
+ mipi_dsi_generic_write_seq(dsi, 0xee, 0x03);
+ mipi_dsi_generic_write_seq(dsi, 0xb0,
+ 0x00, 0xb2, 0x00, 0xb3, 0x00, 0xb6, 0x00, 0xc3,
+ 0x00, 0xce, 0x00, 0xe1, 0x00, 0xf3, 0x01, 0x11);
+ mipi_dsi_generic_write_seq(dsi, 0xb1,
+ 0x01, 0x2e, 0x01, 0x5c, 0x01, 0x82, 0x01, 0xc3,
+ 0x01, 0xfe, 0x02, 0x00, 0x02, 0x37, 0x02, 0x77);
+ mipi_dsi_generic_write_seq(dsi, 0xb2,
+ 0x02, 0xa1, 0x02, 0xd7, 0x02, 0xfe, 0x03, 0x2c,
+ 0x03, 0x4b, 0x03, 0x63, 0x03, 0x8f, 0x03, 0x90);
+ mipi_dsi_generic_write_seq(dsi, 0xb3, 0x03, 0x96, 0x03, 0x98);
+ mipi_dsi_generic_write_seq(dsi, 0xb4,
+ 0x00, 0x81, 0x00, 0x8b, 0x00, 0x9c, 0x00, 0xa9,
+ 0x00, 0xb5, 0x00, 0xcb, 0x00, 0xdf, 0x01, 0x02);
+ mipi_dsi_generic_write_seq(dsi, 0xb5,
+ 0x01, 0x1f, 0x01, 0x51, 0x01, 0x7a, 0x01, 0xbf,
+ 0x01, 0xfa, 0x01, 0xfc, 0x02, 0x34, 0x02, 0x76);
+ mipi_dsi_generic_write_seq(dsi, 0xb6,
+ 0x02, 0x9f, 0x02, 0xd7, 0x02, 0xfc, 0x03, 0x2c,
+ 0x03, 0x4a, 0x03, 0x63, 0x03, 0x8f, 0x03, 0xa2);
+ mipi_dsi_generic_write_seq(dsi, 0xb7, 0x03, 0xb8, 0x03, 0xba);
+ mipi_dsi_generic_write_seq(dsi, 0xb8,
+ 0x00, 0x01, 0x00, 0x02, 0x00, 0x0e, 0x00, 0x2a,
+ 0x00, 0x41, 0x00, 0x67, 0x00, 0x87, 0x00, 0xb9);
+ mipi_dsi_generic_write_seq(dsi, 0xb9,
+ 0x00, 0xe2, 0x01, 0x22, 0x01, 0x54, 0x01, 0xa3,
+ 0x01, 0xe6, 0x01, 0xe7, 0x02, 0x24, 0x02, 0x67);
+ mipi_dsi_generic_write_seq(dsi, 0xba,
+ 0x02, 0x93, 0x02, 0xcd, 0x02, 0xf6, 0x03, 0x31,
+ 0x03, 0x6c, 0x03, 0xe9, 0x03, 0xef, 0x03, 0xf4);
+ mipi_dsi_generic_write_seq(dsi, 0xbb, 0x03, 0xf6, 0x03, 0xf7);
+ mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x03);
+ mipi_dsi_generic_write_seq(dsi, 0xb0, 0x22, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xb1, 0x22, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xb2, 0x05, 0x00, 0x60, 0x00, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xb3, 0x05, 0x00, 0x60, 0x00, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xb4, 0x05, 0x00, 0x60, 0x00, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xb5, 0x05, 0x00, 0x60, 0x00, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xba, 0x53, 0x00, 0x60, 0x00, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xbb, 0x53, 0x00, 0x60, 0x00, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xbc, 0x53, 0x00, 0x60, 0x00, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xbd, 0x53, 0x00, 0x60, 0x00, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xc0, 0x00, 0x34, 0x00, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xc1, 0x00, 0x00, 0x34, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xc2, 0x00, 0x00, 0x34, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xc3, 0x00, 0x00, 0x34, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xc4, 0x60);
+ mipi_dsi_generic_write_seq(dsi, 0xc5, 0xc0);
+ mipi_dsi_generic_write_seq(dsi, 0xc6, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xc7, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x05);
+ mipi_dsi_generic_write_seq(dsi, 0xb0, 0x17, 0x06);
+ mipi_dsi_generic_write_seq(dsi, 0xb1, 0x17, 0x06);
+ mipi_dsi_generic_write_seq(dsi, 0xb2, 0x17, 0x06);
+ mipi_dsi_generic_write_seq(dsi, 0xb3, 0x17, 0x06);
+ mipi_dsi_generic_write_seq(dsi, 0xb4, 0x17, 0x06);
+ mipi_dsi_generic_write_seq(dsi, 0xb5, 0x17, 0x06);
+ mipi_dsi_generic_write_seq(dsi, 0xb6, 0x17, 0x06);
+ mipi_dsi_generic_write_seq(dsi, 0xb7, 0x17, 0x06);
+ mipi_dsi_generic_write_seq(dsi, 0xb8, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xb9, 0x00, 0x03);
+ mipi_dsi_generic_write_seq(dsi, 0xba, 0x00, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xbb, 0x02, 0x03);
+ mipi_dsi_generic_write_seq(dsi, 0xbc, 0x02, 0x03);
+ mipi_dsi_generic_write_seq(dsi, 0xbd, 0x03, 0x03, 0x00, 0x03, 0x03);
+ mipi_dsi_generic_write_seq(dsi, 0xc0, 0x0b);
+ mipi_dsi_generic_write_seq(dsi, 0xc1, 0x09);
+ mipi_dsi_generic_write_seq(dsi, 0xc2, 0xa6);
+ mipi_dsi_generic_write_seq(dsi, 0xc3, 0x05);
+ mipi_dsi_generic_write_seq(dsi, 0xc4, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xc5, 0x02);
+ mipi_dsi_generic_write_seq(dsi, 0xc6, 0x22);
+ mipi_dsi_generic_write_seq(dsi, 0xc7, 0x03);
+ mipi_dsi_generic_write_seq(dsi, 0xc8, 0x07, 0x20);
+ mipi_dsi_generic_write_seq(dsi, 0xc9, 0x03, 0x20);
+ mipi_dsi_generic_write_seq(dsi, 0xca, 0x01, 0x60);
+ mipi_dsi_generic_write_seq(dsi, 0xcb, 0x01, 0x60);
+ mipi_dsi_generic_write_seq(dsi, 0xcc, 0x00, 0x00, 0x02);
+ mipi_dsi_generic_write_seq(dsi, 0xcd, 0x00, 0x00, 0x02);
+ mipi_dsi_generic_write_seq(dsi, 0xce, 0x00, 0x00, 0x02);
+ mipi_dsi_generic_write_seq(dsi, 0xcf, 0x00, 0x00, 0x02);
+ mipi_dsi_generic_write_seq(dsi, 0xd1, 0x00, 0x05, 0x01, 0x07, 0x10);
+ mipi_dsi_generic_write_seq(dsi, 0xd2, 0x10, 0x05, 0x05, 0x03, 0x10);
+ mipi_dsi_generic_write_seq(dsi, 0xd3, 0x20, 0x00, 0x43, 0x07, 0x10);
+ mipi_dsi_generic_write_seq(dsi, 0xd4, 0x30, 0x00, 0x43, 0x07, 0x10);
+ mipi_dsi_generic_write_seq(dsi, 0xd0,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xd5,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xd6,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xd7,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xe5, 0x06);
+ mipi_dsi_generic_write_seq(dsi, 0xe6, 0x06);
+ mipi_dsi_generic_write_seq(dsi, 0xe7, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xe8, 0x06);
+ mipi_dsi_generic_write_seq(dsi, 0xe9, 0x06);
+ mipi_dsi_generic_write_seq(dsi, 0xea, 0x06);
+ mipi_dsi_generic_write_seq(dsi, 0xeb, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xec, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xed, 0x30);
+ mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x06);
+ mipi_dsi_generic_write_seq(dsi, 0xb0, 0x31, 0x31);
+ mipi_dsi_generic_write_seq(dsi, 0xb1, 0x31, 0x31);
+ mipi_dsi_generic_write_seq(dsi, 0xb2, 0x2d, 0x2e);
+ mipi_dsi_generic_write_seq(dsi, 0xb3, 0x31, 0x34);
+ mipi_dsi_generic_write_seq(dsi, 0xb4, 0x29, 0x2a);
+ mipi_dsi_generic_write_seq(dsi, 0xb5, 0x12, 0x10);
+ mipi_dsi_generic_write_seq(dsi, 0xb6, 0x18, 0x16);
+ mipi_dsi_generic_write_seq(dsi, 0xb7, 0x00, 0x02);
+ mipi_dsi_generic_write_seq(dsi, 0xb8, 0x08, 0x31);
+ mipi_dsi_generic_write_seq(dsi, 0xb9, 0x31, 0x31);
+ mipi_dsi_generic_write_seq(dsi, 0xba, 0x31, 0x31);
+ mipi_dsi_generic_write_seq(dsi, 0xbb, 0x31, 0x08);
+ mipi_dsi_generic_write_seq(dsi, 0xbc, 0x03, 0x01);
+ mipi_dsi_generic_write_seq(dsi, 0xbd, 0x17, 0x19);
+ mipi_dsi_generic_write_seq(dsi, 0xbe, 0x11, 0x13);
+ mipi_dsi_generic_write_seq(dsi, 0xbf, 0x2a, 0x29);
+ mipi_dsi_generic_write_seq(dsi, 0xc0, 0x34, 0x31);
+ mipi_dsi_generic_write_seq(dsi, 0xc1, 0x2e, 0x2d);
+ mipi_dsi_generic_write_seq(dsi, 0xc2, 0x31, 0x31);
+ mipi_dsi_generic_write_seq(dsi, 0xc3, 0x31, 0x31);
+ mipi_dsi_generic_write_seq(dsi, 0xc4, 0x31, 0x31);
+ mipi_dsi_generic_write_seq(dsi, 0xc5, 0x31, 0x31);
+ mipi_dsi_generic_write_seq(dsi, 0xc6, 0x2e, 0x2d);
+ mipi_dsi_generic_write_seq(dsi, 0xc7, 0x31, 0x34);
+ mipi_dsi_generic_write_seq(dsi, 0xc8, 0x29, 0x2a);
+ mipi_dsi_generic_write_seq(dsi, 0xc9, 0x17, 0x19);
+ mipi_dsi_generic_write_seq(dsi, 0xca, 0x11, 0x13);
+ mipi_dsi_generic_write_seq(dsi, 0xcb, 0x03, 0x01);
+ mipi_dsi_generic_write_seq(dsi, 0xcc, 0x08, 0x31);
+ mipi_dsi_generic_write_seq(dsi, 0xcd, 0x31, 0x31);
+ mipi_dsi_generic_write_seq(dsi, 0xce, 0x31, 0x31);
+ mipi_dsi_generic_write_seq(dsi, 0xcf, 0x31, 0x08);
+ mipi_dsi_generic_write_seq(dsi, 0xd0, 0x00, 0x02);
+ mipi_dsi_generic_write_seq(dsi, 0xd1, 0x12, 0x10);
+ mipi_dsi_generic_write_seq(dsi, 0xd2, 0x18, 0x16);
+ mipi_dsi_generic_write_seq(dsi, 0xd3, 0x2a, 0x29);
+ mipi_dsi_generic_write_seq(dsi, 0xd4, 0x34, 0x31);
+ mipi_dsi_generic_write_seq(dsi, 0xd5, 0x2d, 0x2e);
+ mipi_dsi_generic_write_seq(dsi, 0xd6, 0x31, 0x31);
+ mipi_dsi_generic_write_seq(dsi, 0xd7, 0x31, 0x31);
+ mipi_dsi_generic_write_seq(dsi, 0xe5, 0x31, 0x31);
+ mipi_dsi_generic_write_seq(dsi, 0xe6, 0x31, 0x31);
+ mipi_dsi_generic_write_seq(dsi, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xd9, 0x00, 0x00, 0x00, 0x00, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xe7, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0x6f, 0x02);
+ mipi_dsi_generic_write_seq(dsi, 0xf7, 0x47);
+ mipi_dsi_generic_write_seq(dsi, 0x6f, 0x0a);
+ mipi_dsi_generic_write_seq(dsi, 0xf7, 0x02);
+ mipi_dsi_generic_write_seq(dsi, 0x6f, 0x17);
+ mipi_dsi_generic_write_seq(dsi, 0xf4, 0x60);
+ mipi_dsi_generic_write_seq(dsi, 0x6f, 0x01);
+ mipi_dsi_generic_write_seq(dsi, 0xf9, 0x46);
+ mipi_dsi_generic_write_seq(dsi, 0x6f, 0x11);
+ mipi_dsi_generic_write_seq(dsi, 0xf3, 0x01);
+ mipi_dsi_generic_write_seq(dsi, 0x35, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xd9, 0x02, 0x03, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x00, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0xb1, 0x6c, 0x21);
+ mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x00, 0x00);
+ mipi_dsi_generic_write_seq(dsi, 0x35, 0x00);
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
if (ret < 0) {
@@ -268,7 +260,7 @@ static int truly_nt35521_on(struct truly_nt35521 *ctx)
}
usleep_range(1000, 2000);
- dsi_generic_write_seq(dsi, 0x53, 0x24);
+ mipi_dsi_generic_write_seq(dsi, 0x53, 0x24);
return 0;
}
diff --git a/drivers/gpu/drm/panel/panel-visionox-vtdr6130.c b/drivers/gpu/drm/panel/panel-visionox-vtdr6130.c
new file mode 100644
index 000000000000..bb0dfd86ea67
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-visionox-vtdr6130.c
@@ -0,0 +1,350 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2023, Linaro Limited
+
+#include <linux/backlight.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/regulator/consumer.h>
+#include <linux/module.h>
+#include <linux/of.h>
+
+#include <drm/display/drm_dsc.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_panel.h>
+
+#include <video/mipi_display.h>
+
+struct visionox_vtdr6130 {
+ struct drm_panel panel;
+ struct mipi_dsi_device *dsi;
+ struct gpio_desc *reset_gpio;
+ struct regulator_bulk_data supplies[3];
+ bool prepared;
+};
+
+static inline struct visionox_vtdr6130 *to_visionox_vtdr6130(struct drm_panel *panel)
+{
+ return container_of(panel, struct visionox_vtdr6130, panel);
+}
+
+static void visionox_vtdr6130_reset(struct visionox_vtdr6130 *ctx)
+{
+ gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+ usleep_range(10000, 11000);
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+ usleep_range(10000, 11000);
+ gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+ usleep_range(10000, 11000);
+}
+
+static int visionox_vtdr6130_on(struct visionox_vtdr6130 *ctx)
+{
+ struct mipi_dsi_device *dsi = ctx->dsi;
+ struct device *dev = &dsi->dev;
+ int ret;
+
+ dsi->mode_flags |= MIPI_DSI_MODE_LPM;
+
+ ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
+ if (ret)
+ return ret;
+
+ mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x20);
+ mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, 0x00, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, 0x59, 0x09);
+ mipi_dsi_dcs_write_seq(dsi, 0x6c, 0x01);
+ mipi_dsi_dcs_write_seq(dsi, 0x6d, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, 0x6f, 0x01);
+ mipi_dsi_dcs_write_seq(dsi, 0x70,
+ 0x12, 0x00, 0x00, 0xab, 0x30, 0x80, 0x09, 0x60, 0x04,
+ 0x38, 0x00, 0x28, 0x02, 0x1c, 0x02, 0x1c, 0x02, 0x00,
+ 0x02, 0x0e, 0x00, 0x20, 0x03, 0xdd, 0x00, 0x07, 0x00,
+ 0x0c, 0x02, 0x77, 0x02, 0x8b, 0x18, 0x00, 0x10, 0xf0,
+ 0x07, 0x10, 0x20, 0x00, 0x06, 0x0f, 0x0f, 0x33, 0x0e,
+ 0x1c, 0x2a, 0x38, 0x46, 0x54, 0x62, 0x69, 0x70, 0x77,
+ 0x79, 0x7b, 0x7d, 0x7e, 0x02, 0x02, 0x22, 0x00, 0x2a,
+ 0x40, 0x2a, 0xbe, 0x3a, 0xfc, 0x3a, 0xfa, 0x3a, 0xf8,
+ 0x3b, 0x38, 0x3b, 0x78, 0x3b, 0xb6, 0x4b, 0xb6, 0x4b,
+ 0xf4, 0x4b, 0xf4, 0x6c, 0x34, 0x84, 0x74, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xaa, 0x10);
+ mipi_dsi_dcs_write_seq(dsi, 0xb1,
+ 0x01, 0x38, 0x00, 0x14, 0x00, 0x1c, 0x00, 0x01, 0x66,
+ 0x00, 0x14, 0x00, 0x14, 0x00, 0x01, 0x66, 0x00, 0x14,
+ 0x05, 0xcc, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xaa, 0x13);
+ mipi_dsi_dcs_write_seq(dsi, 0xce,
+ 0x09, 0x11, 0x09, 0x11, 0x08, 0xc1, 0x07, 0xfa, 0x05,
+ 0xa4, 0x00, 0x3c, 0x00, 0x34, 0x00, 0x24, 0x00, 0x0c,
+ 0x00, 0x0c, 0x04, 0x00, 0x35);
+ mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xaa, 0x14);
+ mipi_dsi_dcs_write_seq(dsi, 0xb2, 0x03, 0x33);
+ mipi_dsi_dcs_write_seq(dsi, 0xb4,
+ 0x00, 0x33, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00,
+ 0x3e, 0x00, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, 0xb5,
+ 0x00, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x06, 0x01);
+ mipi_dsi_dcs_write_seq(dsi, 0xb9, 0x00, 0x00, 0x08, 0x09, 0x09, 0x09);
+ mipi_dsi_dcs_write_seq(dsi, 0xbc,
+ 0x10, 0x00, 0x00, 0x06, 0x11, 0x09, 0x3b, 0x09, 0x47,
+ 0x09, 0x47, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, 0xbe,
+ 0x10, 0x10, 0x00, 0x08, 0x22, 0x09, 0x19, 0x09, 0x25,
+ 0x09, 0x25, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, 0xff, 0x5a, 0x80);
+ mipi_dsi_dcs_write_seq(dsi, 0x65, 0x14);
+ mipi_dsi_dcs_write_seq(dsi, 0xfa, 0x08, 0x08, 0x08);
+ mipi_dsi_dcs_write_seq(dsi, 0xff, 0x5a, 0x81);
+ mipi_dsi_dcs_write_seq(dsi, 0x65, 0x05);
+ mipi_dsi_dcs_write_seq(dsi, 0xf3, 0x0f);
+ mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xaa, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, 0xff, 0x5a, 0x82);
+ mipi_dsi_dcs_write_seq(dsi, 0xf9, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, 0xff, 0x51, 0x83);
+ mipi_dsi_dcs_write_seq(dsi, 0x65, 0x04);
+ mipi_dsi_dcs_write_seq(dsi, 0xf8, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, 0xff, 0x5a, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, 0x65, 0x01);
+ mipi_dsi_dcs_write_seq(dsi, 0xf4, 0x9a);
+ mipi_dsi_dcs_write_seq(dsi, 0xff, 0x5a, 0x00);
+
+ ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
+ if (ret < 0) {
+ dev_err(dev, "Failed to exit sleep mode: %d\n", ret);
+ return ret;
+ }
+ msleep(120);
+
+ ret = mipi_dsi_dcs_set_display_on(dsi);
+ if (ret < 0) {
+ dev_err(dev, "Failed to set display on: %d\n", ret);
+ return ret;
+ }
+ msleep(20);
+
+ return 0;
+}
+
+static int visionox_vtdr6130_off(struct visionox_vtdr6130 *ctx)
+{
+ struct mipi_dsi_device *dsi = ctx->dsi;
+ struct device *dev = &dsi->dev;
+ int ret;
+
+ dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
+
+ ret = mipi_dsi_dcs_set_display_off(dsi);
+ if (ret < 0) {
+ dev_err(dev, "Failed to set display off: %d\n", ret);
+ return ret;
+ }
+ msleep(20);
+
+ ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
+ if (ret < 0) {
+ dev_err(dev, "Failed to enter sleep mode: %d\n", ret);
+ return ret;
+ }
+ msleep(120);
+
+ return 0;
+}
+
+static int visionox_vtdr6130_prepare(struct drm_panel *panel)
+{
+ struct visionox_vtdr6130 *ctx = to_visionox_vtdr6130(panel);
+ struct device *dev = &ctx->dsi->dev;
+ int ret;
+
+ if (ctx->prepared)
+ return 0;
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies),
+ ctx->supplies);
+ if (ret < 0)
+ return ret;
+
+ visionox_vtdr6130_reset(ctx);
+
+ ret = visionox_vtdr6130_on(ctx);
+ if (ret < 0) {
+ dev_err(dev, "Failed to initialize panel: %d\n", ret);
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+ regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
+ return ret;
+ }
+
+ ctx->prepared = true;
+ return 0;
+}
+
+static int visionox_vtdr6130_unprepare(struct drm_panel *panel)
+{
+ struct visionox_vtdr6130 *ctx = to_visionox_vtdr6130(panel);
+ struct device *dev = &ctx->dsi->dev;
+ int ret;
+
+ if (!ctx->prepared)
+ return 0;
+
+ ret = visionox_vtdr6130_off(ctx);
+ if (ret < 0)
+ dev_err(dev, "Failed to un-initialize panel: %d\n", ret);
+
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+
+ regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
+
+ ctx->prepared = false;
+ return 0;
+}
+
+static const struct drm_display_mode visionox_vtdr6130_mode = {
+ .clock = (1080 + 20 + 2 + 20) * (2400 + 20 + 2 + 18) * 144 / 1000,
+ .hdisplay = 1080,
+ .hsync_start = 1080 + 20,
+ .hsync_end = 1080 + 20 + 2,
+ .htotal = 1080 + 20 + 2 + 20,
+ .vdisplay = 2400,
+ .vsync_start = 2400 + 20,
+ .vsync_end = 2400 + 20 + 2,
+ .vtotal = 2400 + 20 + 2 + 18,
+ .width_mm = 71,
+ .height_mm = 157,
+};
+
+static int visionox_vtdr6130_get_modes(struct drm_panel *panel,
+ struct drm_connector *connector)
+{
+ struct drm_display_mode *mode;
+
+ mode = drm_mode_duplicate(connector->dev, &visionox_vtdr6130_mode);
+ if (!mode)
+ return -ENOMEM;
+
+ drm_mode_set_name(mode);
+
+ mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+ connector->display_info.width_mm = mode->width_mm;
+ connector->display_info.height_mm = mode->height_mm;
+ drm_mode_probed_add(connector, mode);
+
+ return 1;
+}
+
+static const struct drm_panel_funcs visionox_vtdr6130_panel_funcs = {
+ .prepare = visionox_vtdr6130_prepare,
+ .unprepare = visionox_vtdr6130_unprepare,
+ .get_modes = visionox_vtdr6130_get_modes,
+};
+
+static int visionox_vtdr6130_bl_update_status(struct backlight_device *bl)
+{
+ struct mipi_dsi_device *dsi = bl_get_data(bl);
+ u16 brightness = backlight_get_brightness(bl);
+
+ return mipi_dsi_dcs_set_display_brightness_large(dsi, brightness);
+}
+
+static const struct backlight_ops visionox_vtdr6130_bl_ops = {
+ .update_status = visionox_vtdr6130_bl_update_status,
+};
+
+static struct backlight_device *
+visionox_vtdr6130_create_backlight(struct mipi_dsi_device *dsi)
+{
+ struct device *dev = &dsi->dev;
+ const struct backlight_properties props = {
+ .type = BACKLIGHT_RAW,
+ .brightness = 4095,
+ .max_brightness = 4095,
+ };
+
+ return devm_backlight_device_register(dev, dev_name(dev), dev, dsi,
+ &visionox_vtdr6130_bl_ops, &props);
+}
+
+static int visionox_vtdr6130_probe(struct mipi_dsi_device *dsi)
+{
+ struct device *dev = &dsi->dev;
+ struct visionox_vtdr6130 *ctx;
+ int ret;
+
+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ ctx->supplies[0].supply = "vddio";
+ ctx->supplies[1].supply = "vci";
+ ctx->supplies[2].supply = "vdd";
+
+ ret = devm_regulator_bulk_get(&dsi->dev, ARRAY_SIZE(ctx->supplies),
+ ctx->supplies);
+ if (ret < 0)
+ return ret;
+
+ ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(ctx->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
+ "Failed to get reset-gpios\n");
+
+ ctx->dsi = dsi;
+ mipi_dsi_set_drvdata(dsi, ctx);
+
+ dsi->lanes = 4;
+ dsi->format = MIPI_DSI_FMT_RGB888;
+ dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_NO_EOT_PACKET |
+ MIPI_DSI_CLOCK_NON_CONTINUOUS;
+
+ drm_panel_init(&ctx->panel, dev, &visionox_vtdr6130_panel_funcs,
+ DRM_MODE_CONNECTOR_DSI);
+
+ ctx->panel.backlight = visionox_vtdr6130_create_backlight(dsi);
+ if (IS_ERR(ctx->panel.backlight))
+ return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight),
+ "Failed to create backlight\n");
+
+ drm_panel_add(&ctx->panel);
+
+ ret = mipi_dsi_attach(dsi);
+ if (ret < 0) {
+ dev_err(dev, "Failed to attach to DSI host: %d\n", ret);
+ drm_panel_remove(&ctx->panel);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void visionox_vtdr6130_remove(struct mipi_dsi_device *dsi)
+{
+ struct visionox_vtdr6130 *ctx = mipi_dsi_get_drvdata(dsi);
+ int ret;
+
+ ret = mipi_dsi_detach(dsi);
+ if (ret < 0)
+ dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
+
+ drm_panel_remove(&ctx->panel);
+}
+
+static const struct of_device_id visionox_vtdr6130_of_match[] = {
+ { .compatible = "visionox,vtdr6130" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, visionox_vtdr6130_of_match);
+
+static struct mipi_dsi_driver visionox_vtdr6130_driver = {
+ .probe = visionox_vtdr6130_probe,
+ .remove = visionox_vtdr6130_remove,
+ .driver = {
+ .name = "panel-visionox-vtdr6130",
+ .of_match_table = visionox_vtdr6130_of_match,
+ },
+};
+module_mipi_dsi_driver(visionox_vtdr6130_driver);
+
+MODULE_AUTHOR("Neil Armstrong <neil.armstrong@linaro.org>");
+MODULE_DESCRIPTION("Panel driver for the Visionox VTDR6130 AMOLED DSI panel");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/panel/panel-xinpeng-xpp055c272.c b/drivers/gpu/drm/panel/panel-xinpeng-xpp055c272.c
index 2c54733ee241..8670386498a4 100644
--- a/drivers/gpu/drm/panel/panel-xinpeng-xpp055c272.c
+++ b/drivers/gpu/drm/panel/panel-xinpeng-xpp055c272.c
@@ -60,14 +60,6 @@ static inline struct xpp055c272 *panel_to_xpp055c272(struct drm_panel *panel)
return container_of(panel, struct xpp055c272, panel);
}
-#define dsi_generic_write_seq(dsi, cmd, seq...) do { \
- static const u8 b[] = { cmd, seq }; \
- int ret; \
- ret = mipi_dsi_dcs_write_buffer(dsi, b, ARRAY_SIZE(b)); \
- if (ret < 0) \
- return ret; \
- } while (0)
-
static int xpp055c272_init_sequence(struct xpp055c272 *ctx)
{
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
@@ -77,60 +69,60 @@ static int xpp055c272_init_sequence(struct xpp055c272 *ctx)
* Init sequence was supplied by the panel vendor without much
* documentation.
*/
- dsi_generic_write_seq(dsi, XPP055C272_CMD_SETEXTC, 0xf1, 0x12, 0x83);
- dsi_generic_write_seq(dsi, XPP055C272_CMD_SETMIPI,
- 0x33, 0x81, 0x05, 0xf9, 0x0e, 0x0e, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x25,
- 0x00, 0x91, 0x0a, 0x00, 0x00, 0x02, 0x4f, 0x01,
- 0x00, 0x00, 0x37);
- dsi_generic_write_seq(dsi, XPP055C272_CMD_SETPOWER_EXT, 0x25);
- dsi_generic_write_seq(dsi, XPP055C272_CMD_SETPCR, 0x02, 0x11, 0x00);
- dsi_generic_write_seq(dsi, XPP055C272_CMD_SETRGBIF,
- 0x0c, 0x10, 0x0a, 0x50, 0x03, 0xff, 0x00, 0x00,
- 0x00, 0x00);
- dsi_generic_write_seq(dsi, XPP055C272_CMD_SETSCR,
- 0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 0x08, 0x70,
- 0x00);
- dsi_generic_write_seq(dsi, XPP055C272_CMD_SETVDC, 0x46);
- dsi_generic_write_seq(dsi, XPP055C272_CMD_SETPANEL, 0x0b);
- dsi_generic_write_seq(dsi, XPP055C272_CMD_SETCYC, 0x80);
- dsi_generic_write_seq(dsi, XPP055C272_CMD_SETDISP, 0xc8, 0x12, 0x30);
- dsi_generic_write_seq(dsi, XPP055C272_CMD_SETEQ,
- 0x07, 0x07, 0x0B, 0x0B, 0x03, 0x0B, 0x00, 0x00,
- 0x00, 0x00, 0xFF, 0x00, 0xC0, 0x10);
- dsi_generic_write_seq(dsi, XPP055C272_CMD_SETPOWER,
- 0x53, 0x00, 0x1e, 0x1e, 0x77, 0xe1, 0xcc, 0xdd,
- 0x67, 0x77, 0x33, 0x33);
- dsi_generic_write_seq(dsi, XPP055C272_CMD_SETECO, 0x00, 0x00, 0xff,
- 0xff, 0x01, 0xff);
- dsi_generic_write_seq(dsi, XPP055C272_CMD_SETBGP, 0x09, 0x09);
+ mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETEXTC, 0xf1, 0x12, 0x83);
+ mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETMIPI,
+ 0x33, 0x81, 0x05, 0xf9, 0x0e, 0x0e, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x25,
+ 0x00, 0x91, 0x0a, 0x00, 0x00, 0x02, 0x4f, 0x01,
+ 0x00, 0x00, 0x37);
+ mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETPOWER_EXT, 0x25);
+ mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETPCR, 0x02, 0x11, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETRGBIF,
+ 0x0c, 0x10, 0x0a, 0x50, 0x03, 0xff, 0x00, 0x00,
+ 0x00, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETSCR,
+ 0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 0x08, 0x70,
+ 0x00);
+ mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETVDC, 0x46);
+ mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETPANEL, 0x0b);
+ mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETCYC, 0x80);
+ mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETDISP, 0xc8, 0x12, 0x30);
+ mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETEQ,
+ 0x07, 0x07, 0x0B, 0x0B, 0x03, 0x0B, 0x00, 0x00,
+ 0x00, 0x00, 0xFF, 0x00, 0xC0, 0x10);
+ mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETPOWER,
+ 0x53, 0x00, 0x1e, 0x1e, 0x77, 0xe1, 0xcc, 0xdd,
+ 0x67, 0x77, 0x33, 0x33);
+ mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETECO, 0x00, 0x00, 0xff,
+ 0xff, 0x01, 0xff);
+ mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETBGP, 0x09, 0x09);
msleep(20);
- dsi_generic_write_seq(dsi, XPP055C272_CMD_SETVCOM, 0x87, 0x95);
- dsi_generic_write_seq(dsi, XPP055C272_CMD_SETGIP1,
- 0xc2, 0x10, 0x05, 0x05, 0x10, 0x05, 0xa0, 0x12,
- 0x31, 0x23, 0x3f, 0x81, 0x0a, 0xa0, 0x37, 0x18,
- 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80,
- 0x01, 0x00, 0x00, 0x00, 0x48, 0xf8, 0x86, 0x42,
- 0x08, 0x88, 0x88, 0x80, 0x88, 0x88, 0x88, 0x58,
- 0xf8, 0x87, 0x53, 0x18, 0x88, 0x88, 0x81, 0x88,
- 0x88, 0x88, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
- dsi_generic_write_seq(dsi, XPP055C272_CMD_SETGIP2,
- 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x1f, 0x88, 0x81, 0x35,
- 0x78, 0x88, 0x88, 0x85, 0x88, 0x88, 0x88, 0x0f,
- 0x88, 0x80, 0x24, 0x68, 0x88, 0x88, 0x84, 0x88,
- 0x88, 0x88, 0x23, 0x10, 0x00, 0x00, 0x1c, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x05,
- 0xa0, 0x00, 0x00, 0x00, 0x00);
- dsi_generic_write_seq(dsi, XPP055C272_CMD_SETGAMMA,
- 0x00, 0x06, 0x08, 0x2a, 0x31, 0x3f, 0x38, 0x36,
- 0x07, 0x0c, 0x0d, 0x11, 0x13, 0x12, 0x13, 0x11,
- 0x18, 0x00, 0x06, 0x08, 0x2a, 0x31, 0x3f, 0x38,
- 0x36, 0x07, 0x0c, 0x0d, 0x11, 0x13, 0x12, 0x13,
- 0x11, 0x18);
+ mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETVCOM, 0x87, 0x95);
+ mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETGIP1,
+ 0xc2, 0x10, 0x05, 0x05, 0x10, 0x05, 0xa0, 0x12,
+ 0x31, 0x23, 0x3f, 0x81, 0x0a, 0xa0, 0x37, 0x18,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80,
+ 0x01, 0x00, 0x00, 0x00, 0x48, 0xf8, 0x86, 0x42,
+ 0x08, 0x88, 0x88, 0x80, 0x88, 0x88, 0x88, 0x58,
+ 0xf8, 0x87, 0x53, 0x18, 0x88, 0x88, 0x81, 0x88,
+ 0x88, 0x88, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETGIP2,
+ 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1f, 0x88, 0x81, 0x35,
+ 0x78, 0x88, 0x88, 0x85, 0x88, 0x88, 0x88, 0x0f,
+ 0x88, 0x80, 0x24, 0x68, 0x88, 0x88, 0x84, 0x88,
+ 0x88, 0x88, 0x23, 0x10, 0x00, 0x00, 0x1c, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x05,
+ 0xa0, 0x00, 0x00, 0x00, 0x00);
+ mipi_dsi_dcs_write_seq(dsi, XPP055C272_CMD_SETGAMMA,
+ 0x00, 0x06, 0x08, 0x2a, 0x31, 0x3f, 0x38, 0x36,
+ 0x07, 0x0c, 0x0d, 0x11, 0x13, 0x12, 0x13, 0x11,
+ 0x18, 0x00, 0x06, 0x08, 0x2a, 0x31, 0x3f, 0x38,
+ 0x36, 0x07, 0x0c, 0x0d, 0x11, 0x13, 0x12, 0x13,
+ 0x11, 0x18);
msleep(60);
diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c
index ee612303f076..fa1a086a862b 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.c
+++ b/drivers/gpu/drm/panfrost/panfrost_device.c
@@ -6,6 +6,7 @@
#include <linux/reset.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include "panfrost_device.h"
@@ -400,8 +401,7 @@ void panfrost_device_reset(struct panfrost_device *pfdev)
panfrost_job_enable_interrupts(pfdev);
}
-#ifdef CONFIG_PM
-int panfrost_device_resume(struct device *dev)
+static int panfrost_device_resume(struct device *dev)
{
struct panfrost_device *pfdev = dev_get_drvdata(dev);
@@ -411,7 +411,7 @@ int panfrost_device_resume(struct device *dev)
return 0;
}
-int panfrost_device_suspend(struct device *dev)
+static int panfrost_device_suspend(struct device *dev)
{
struct panfrost_device *pfdev = dev_get_drvdata(dev);
@@ -423,4 +423,6 @@ int panfrost_device_suspend(struct device *dev)
return 0;
}
-#endif
+
+EXPORT_GPL_RUNTIME_DEV_PM_OPS(panfrost_pm_ops, panfrost_device_suspend,
+ panfrost_device_resume, NULL);
diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h b/drivers/gpu/drm/panfrost/panfrost_device.h
index 8b25278f34c8..d9ba68cffb77 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.h
+++ b/drivers/gpu/drm/panfrost/panfrost_device.h
@@ -7,6 +7,7 @@
#include <linux/atomic.h>
#include <linux/io-pgtable.h>
+#include <linux/pm.h>
#include <linux/regulator/consumer.h>
#include <linux/spinlock.h>
#include <drm/drm_device.h>
@@ -172,8 +173,7 @@ int panfrost_device_init(struct panfrost_device *pfdev);
void panfrost_device_fini(struct panfrost_device *pfdev);
void panfrost_device_reset(struct panfrost_device *pfdev);
-int panfrost_device_resume(struct device *dev);
-int panfrost_device_suspend(struct device *dev);
+extern const struct dev_pm_ops panfrost_pm_ops;
enum drm_panfrost_exception_type {
DRM_PANFROST_EXCEPTION_OK = 0x00,
diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c
index 919e6cc04982..abb0dadd8f63 100644
--- a/drivers/gpu/drm/panfrost/panfrost_drv.c
+++ b/drivers/gpu/drm/panfrost/panfrost_drv.c
@@ -685,17 +685,12 @@ static const struct of_device_id dt_match[] = {
};
MODULE_DEVICE_TABLE(of, dt_match);
-static const struct dev_pm_ops panfrost_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
- SET_RUNTIME_PM_OPS(panfrost_device_suspend, panfrost_device_resume, NULL)
-};
-
static struct platform_driver panfrost_driver = {
.probe = panfrost_probe,
.remove = panfrost_remove,
.driver = {
.name = "panfrost",
- .pm = &panfrost_pm_ops,
+ .pm = pm_ptr(&panfrost_pm_ops),
.of_match_table = dt_match,
},
};
diff --git a/drivers/gpu/drm/qxl/qxl_cmd.c b/drivers/gpu/drm/qxl/qxl_cmd.c
index 63aa96a69752..281edab518cd 100644
--- a/drivers/gpu/drm/qxl/qxl_cmd.c
+++ b/drivers/gpu/drm/qxl/qxl_cmd.c
@@ -579,7 +579,7 @@ void qxl_surface_evict(struct qxl_device *qdev, struct qxl_bo *surf, bool do_upd
static int qxl_reap_surf(struct qxl_device *qdev, struct qxl_bo *surf, bool stall)
{
- int ret;
+ long ret;
ret = qxl_bo_reserve(surf);
if (ret)
@@ -588,7 +588,19 @@ static int qxl_reap_surf(struct qxl_device *qdev, struct qxl_bo *surf, bool stal
if (stall)
mutex_unlock(&qdev->surf_evict_mutex);
- ret = ttm_bo_wait(&surf->tbo, true, !stall);
+ if (stall) {
+ ret = dma_resv_wait_timeout(surf->tbo.base.resv,
+ DMA_RESV_USAGE_BOOKKEEP, true,
+ 15 * HZ);
+ if (ret > 0)
+ ret = 0;
+ else if (ret == 0)
+ ret = -EBUSY;
+ } else {
+ ret = dma_resv_test_signaled(surf->tbo.base.resv,
+ DMA_RESV_USAGE_BOOKKEEP);
+ ret = ret ? -EBUSY : 0;
+ }
if (stall)
mutex_lock(&qdev->surf_evict_mutex);
diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h
index 76f060810f63..ea993d7162e8 100644
--- a/drivers/gpu/drm/qxl/qxl_drv.h
+++ b/drivers/gpu/drm/qxl/qxl_drv.h
@@ -42,8 +42,7 @@
#include <drm/drm_ioctl.h>
#include <drm/drm_gem.h>
#include <drm/qxl_drm.h>
-#include <drm/ttm/ttm_bo_api.h>
-#include <drm/ttm/ttm_bo_driver.h>
+#include <drm/ttm/ttm_bo.h>
#include <drm/ttm/ttm_execbuf_util.h>
#include <drm/ttm/ttm_placement.h>
diff --git a/drivers/gpu/drm/qxl/qxl_ttm.c b/drivers/gpu/drm/qxl/qxl_ttm.c
index ee95001e6b5e..a92a5b0d4c25 100644
--- a/drivers/gpu/drm/qxl/qxl_ttm.c
+++ b/drivers/gpu/drm/qxl/qxl_ttm.c
@@ -29,10 +29,10 @@
#include <drm/drm_file.h>
#include <drm/drm_debugfs.h>
#include <drm/qxl_drm.h>
-#include <drm/ttm/ttm_bo_api.h>
-#include <drm/ttm/ttm_bo_driver.h>
+#include <drm/ttm/ttm_bo.h>
#include <drm/ttm/ttm_placement.h>
#include <drm/ttm/ttm_range_manager.h>
+#include <drm/ttm/ttm_tt.h>
#include "qxl_drv.h"
#include "qxl_object.h"
diff --git a/drivers/gpu/drm/r128/Makefile b/drivers/gpu/drm/r128/Makefile
deleted file mode 100644
index c07a069533ef..000000000000
--- a/drivers/gpu/drm/r128/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Makefile for the drm device driver. This driver provides support for the
-# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
-
-r128-y := r128_drv.o r128_cce.o r128_state.o r128_irq.o ati_pcigart.o
-
-r128-$(CONFIG_COMPAT) += r128_ioc32.o
-
-obj-$(CONFIG_DRM_R128) += r128.o
diff --git a/drivers/gpu/drm/r128/ati_pcigart.c b/drivers/gpu/drm/r128/ati_pcigart.c
deleted file mode 100644
index dde0501aea68..000000000000
--- a/drivers/gpu/drm/r128/ati_pcigart.c
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * \file ati_pcigart.c
- * ATI PCI GART support
- *
- * \author Gareth Hughes <gareth@valinux.com>
- */
-
-/*
- * Created: Wed Dec 13 21:52:19 2000 by gareth@valinux.com
- *
- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software 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 (including the next
- * paragraph) 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
- * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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.
- */
-
-#include <linux/export.h>
-#include <linux/pci.h>
-
-#include <drm/drm_device.h>
-#include <drm/drm_legacy.h>
-#include <drm/drm_print.h>
-
-#include "ati_pcigart.h"
-
-# define ATI_PCIGART_PAGE_SIZE 4096 /**< PCI GART page size */
-
-static int drm_ati_alloc_pcigart_table(struct drm_device *dev,
- struct drm_ati_pcigart_info *gart_info)
-{
- drm_dma_handle_t *dmah = kmalloc(sizeof(drm_dma_handle_t), GFP_KERNEL);
-
- if (!dmah)
- return -ENOMEM;
-
- dmah->size = gart_info->table_size;
- dmah->vaddr = dma_alloc_coherent(dev->dev,
- dmah->size,
- &dmah->busaddr,
- GFP_KERNEL);
-
- if (!dmah->vaddr) {
- kfree(dmah);
- return -ENOMEM;
- }
-
- gart_info->table_handle = dmah;
- return 0;
-}
-
-static void drm_ati_free_pcigart_table(struct drm_device *dev,
- struct drm_ati_pcigart_info *gart_info)
-{
- drm_dma_handle_t *dmah = gart_info->table_handle;
-
- dma_free_coherent(dev->dev, dmah->size, dmah->vaddr, dmah->busaddr);
- kfree(dmah);
-
- gart_info->table_handle = NULL;
-}
-
-int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info)
-{
- struct drm_sg_mem *entry = dev->sg;
- struct pci_dev *pdev = to_pci_dev(dev->dev);
- unsigned long pages;
- int i;
- int max_pages;
-
- /* we need to support large memory configurations */
- if (!entry) {
- DRM_ERROR("no scatter/gather memory!\n");
- return 0;
- }
-
- if (gart_info->bus_addr) {
-
- max_pages = (gart_info->table_size / sizeof(u32));
- pages = (entry->pages <= max_pages)
- ? entry->pages : max_pages;
-
- for (i = 0; i < pages; i++) {
- if (!entry->busaddr[i])
- break;
- dma_unmap_page(&pdev->dev, entry->busaddr[i],
- PAGE_SIZE, DMA_BIDIRECTIONAL);
- }
-
- if (gart_info->gart_table_location == DRM_ATI_GART_MAIN)
- gart_info->bus_addr = 0;
- }
-
- if (gart_info->gart_table_location == DRM_ATI_GART_MAIN &&
- gart_info->table_handle) {
- drm_ati_free_pcigart_table(dev, gart_info);
- }
-
- return 1;
-}
-
-int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info)
-{
- struct drm_local_map *map = &gart_info->mapping;
- struct drm_sg_mem *entry = dev->sg;
- struct pci_dev *pdev = to_pci_dev(dev->dev);
- void *address = NULL;
- unsigned long pages;
- u32 *pci_gart = NULL, page_base, gart_idx;
- dma_addr_t bus_address = 0;
- int i, j, ret = -ENOMEM;
- int max_ati_pages, max_real_pages;
-
- if (!entry) {
- DRM_ERROR("no scatter/gather memory!\n");
- goto done;
- }
-
- if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) {
- DRM_DEBUG("PCI: no table in VRAM: using normal RAM\n");
-
- if (dma_set_mask(&pdev->dev, gart_info->table_mask)) {
- DRM_ERROR("fail to set dma mask to 0x%Lx\n",
- (unsigned long long)gart_info->table_mask);
- ret = -EFAULT;
- goto done;
- }
-
- ret = drm_ati_alloc_pcigart_table(dev, gart_info);
- if (ret) {
- DRM_ERROR("cannot allocate PCI GART page!\n");
- goto done;
- }
-
- pci_gart = gart_info->table_handle->vaddr;
- address = gart_info->table_handle->vaddr;
- bus_address = gart_info->table_handle->busaddr;
- } else {
- address = gart_info->addr;
- bus_address = gart_info->bus_addr;
- DRM_DEBUG("PCI: Gart Table: VRAM %08LX mapped at %08lX\n",
- (unsigned long long)bus_address,
- (unsigned long)address);
- }
-
-
- max_ati_pages = (gart_info->table_size / sizeof(u32));
- max_real_pages = max_ati_pages / (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE);
- pages = (entry->pages <= max_real_pages)
- ? entry->pages : max_real_pages;
-
- if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) {
- memset(pci_gart, 0, max_ati_pages * sizeof(u32));
- } else {
- memset_io((void __iomem *)map->handle, 0, max_ati_pages * sizeof(u32));
- }
-
- gart_idx = 0;
- for (i = 0; i < pages; i++) {
- /* we need to support large memory configurations */
- entry->busaddr[i] = dma_map_page(&pdev->dev, entry->pagelist[i],
- 0, PAGE_SIZE, DMA_BIDIRECTIONAL);
- if (dma_mapping_error(&pdev->dev, entry->busaddr[i])) {
- DRM_ERROR("unable to map PCIGART pages!\n");
- drm_ati_pcigart_cleanup(dev, gart_info);
- address = NULL;
- bus_address = 0;
- ret = -ENOMEM;
- goto done;
- }
- page_base = (u32) entry->busaddr[i];
-
- for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) {
- u32 offset;
- u32 val;
-
- switch(gart_info->gart_reg_if) {
- case DRM_ATI_GART_IGP:
- val = page_base | 0xc;
- break;
- case DRM_ATI_GART_PCIE:
- val = (page_base >> 8) | 0xc;
- break;
- default:
- case DRM_ATI_GART_PCI:
- val = page_base;
- break;
- }
- if (gart_info->gart_table_location ==
- DRM_ATI_GART_MAIN) {
- pci_gart[gart_idx] = cpu_to_le32(val);
- } else {
- offset = gart_idx * sizeof(u32);
- writel(val, (void __iomem *)map->handle + offset);
- }
- gart_idx++;
- page_base += ATI_PCIGART_PAGE_SIZE;
- }
- }
- ret = 0;
-
-#ifdef CONFIG_X86
- wbinvd();
-#else
- mb();
-#endif
-
- done:
- gart_info->addr = address;
- gart_info->bus_addr = bus_address;
- return ret;
-}
diff --git a/drivers/gpu/drm/r128/ati_pcigart.h b/drivers/gpu/drm/r128/ati_pcigart.h
deleted file mode 100644
index a728a1364e66..000000000000
--- a/drivers/gpu/drm/r128/ati_pcigart.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef DRM_ATI_PCIGART_H
-#define DRM_ATI_PCIGART_H
-
-#include <drm/drm_legacy.h>
-
-/* location of GART table */
-#define DRM_ATI_GART_MAIN 1
-#define DRM_ATI_GART_FB 2
-
-#define DRM_ATI_GART_PCI 1
-#define DRM_ATI_GART_PCIE 2
-#define DRM_ATI_GART_IGP 3
-
-struct drm_ati_pcigart_info {
- int gart_table_location;
- int gart_reg_if;
- void *addr;
- dma_addr_t bus_addr;
- dma_addr_t table_mask;
- struct drm_dma_handle *table_handle;
- struct drm_local_map mapping;
- int table_size;
-};
-
-extern int drm_ati_pcigart_init(struct drm_device *dev,
- struct drm_ati_pcigart_info * gart_info);
-extern int drm_ati_pcigart_cleanup(struct drm_device *dev,
- struct drm_ati_pcigart_info * gart_info);
-
-#endif
diff --git a/drivers/gpu/drm/r128/r128_cce.c b/drivers/gpu/drm/r128/r128_cce.c
deleted file mode 100644
index c04d84a69dd2..000000000000
--- a/drivers/gpu/drm/r128/r128_cce.c
+++ /dev/null
@@ -1,944 +0,0 @@
-/* r128_cce.c -- ATI Rage 128 driver -*- linux-c -*-
- * Created: Wed Apr 5 19:24:19 2000 by kevin@precisioninsight.com
- */
-/*
- * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas.
- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software 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 (including the next
- * paragraph) 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
- * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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.
- *
- * Authors:
- * Gareth Hughes <gareth@valinux.com>
- */
-
-#include <linux/delay.h>
-#include <linux/dma-mapping.h>
-#include <linux/firmware.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/uaccess.h>
-
-#include <drm/drm_device.h>
-#include <drm/drm_file.h>
-#include <drm/drm_legacy.h>
-#include <drm/drm_print.h>
-#include <drm/r128_drm.h>
-
-#include "r128_drv.h"
-
-#define R128_FIFO_DEBUG 0
-
-#define FIRMWARE_NAME "r128/r128_cce.bin"
-
-MODULE_FIRMWARE(FIRMWARE_NAME);
-
-static int R128_READ_PLL(struct drm_device *dev, int addr)
-{
- drm_r128_private_t *dev_priv = dev->dev_private;
-
- R128_WRITE8(R128_CLOCK_CNTL_INDEX, addr & 0x1f);
- return R128_READ(R128_CLOCK_CNTL_DATA);
-}
-
-#if R128_FIFO_DEBUG
-static void r128_status(drm_r128_private_t *dev_priv)
-{
- printk("GUI_STAT = 0x%08x\n",
- (unsigned int)R128_READ(R128_GUI_STAT));
- printk("PM4_STAT = 0x%08x\n",
- (unsigned int)R128_READ(R128_PM4_STAT));
- printk("PM4_BUFFER_DL_WPTR = 0x%08x\n",
- (unsigned int)R128_READ(R128_PM4_BUFFER_DL_WPTR));
- printk("PM4_BUFFER_DL_RPTR = 0x%08x\n",
- (unsigned int)R128_READ(R128_PM4_BUFFER_DL_RPTR));
- printk("PM4_MICRO_CNTL = 0x%08x\n",
- (unsigned int)R128_READ(R128_PM4_MICRO_CNTL));
- printk("PM4_BUFFER_CNTL = 0x%08x\n",
- (unsigned int)R128_READ(R128_PM4_BUFFER_CNTL));
-}
-#endif
-
-/* ================================================================
- * Engine, FIFO control
- */
-
-static int r128_do_pixcache_flush(drm_r128_private_t *dev_priv)
-{
- u32 tmp;
- int i;
-
- tmp = R128_READ(R128_PC_NGUI_CTLSTAT) | R128_PC_FLUSH_ALL;
- R128_WRITE(R128_PC_NGUI_CTLSTAT, tmp);
-
- for (i = 0; i < dev_priv->usec_timeout; i++) {
- if (!(R128_READ(R128_PC_NGUI_CTLSTAT) & R128_PC_BUSY))
- return 0;
- udelay(1);
- }
-
-#if R128_FIFO_DEBUG
- DRM_ERROR("failed!\n");
-#endif
- return -EBUSY;
-}
-
-static int r128_do_wait_for_fifo(drm_r128_private_t *dev_priv, int entries)
-{
- int i;
-
- for (i = 0; i < dev_priv->usec_timeout; i++) {
- int slots = R128_READ(R128_GUI_STAT) & R128_GUI_FIFOCNT_MASK;
- if (slots >= entries)
- return 0;
- udelay(1);
- }
-
-#if R128_FIFO_DEBUG
- DRM_ERROR("failed!\n");
-#endif
- return -EBUSY;
-}
-
-static int r128_do_wait_for_idle(drm_r128_private_t *dev_priv)
-{
- int i, ret;
-
- ret = r128_do_wait_for_fifo(dev_priv, 64);
- if (ret)
- return ret;
-
- for (i = 0; i < dev_priv->usec_timeout; i++) {
- if (!(R128_READ(R128_GUI_STAT) & R128_GUI_ACTIVE)) {
- r128_do_pixcache_flush(dev_priv);
- return 0;
- }
- udelay(1);
- }
-
-#if R128_FIFO_DEBUG
- DRM_ERROR("failed!\n");
-#endif
- return -EBUSY;
-}
-
-/* ================================================================
- * CCE control, initialization
- */
-
-/* Load the microcode for the CCE */
-static int r128_cce_load_microcode(drm_r128_private_t *dev_priv)
-{
- struct platform_device *pdev;
- const struct firmware *fw;
- const __be32 *fw_data;
- int rc, i;
-
- DRM_DEBUG("\n");
-
- pdev = platform_device_register_simple("r128_cce", 0, NULL, 0);
- if (IS_ERR(pdev)) {
- pr_err("r128_cce: Failed to register firmware\n");
- return PTR_ERR(pdev);
- }
- rc = request_firmware(&fw, FIRMWARE_NAME, &pdev->dev);
- platform_device_unregister(pdev);
- if (rc) {
- pr_err("r128_cce: Failed to load firmware \"%s\"\n",
- FIRMWARE_NAME);
- return rc;
- }
-
- if (fw->size != 256 * 8) {
- pr_err("r128_cce: Bogus length %zu in firmware \"%s\"\n",
- fw->size, FIRMWARE_NAME);
- rc = -EINVAL;
- goto out_release;
- }
-
- r128_do_wait_for_idle(dev_priv);
-
- fw_data = (const __be32 *)fw->data;
- R128_WRITE(R128_PM4_MICROCODE_ADDR, 0);
- for (i = 0; i < 256; i++) {
- R128_WRITE(R128_PM4_MICROCODE_DATAH,
- be32_to_cpup(&fw_data[i * 2]));
- R128_WRITE(R128_PM4_MICROCODE_DATAL,
- be32_to_cpup(&fw_data[i * 2 + 1]));
- }
-
-out_release:
- release_firmware(fw);
- return rc;
-}
-
-/* Flush any pending commands to the CCE. This should only be used just
- * prior to a wait for idle, as it informs the engine that the command
- * stream is ending.
- */
-static void r128_do_cce_flush(drm_r128_private_t *dev_priv)
-{
- u32 tmp;
-
- tmp = R128_READ(R128_PM4_BUFFER_DL_WPTR) | R128_PM4_BUFFER_DL_DONE;
- R128_WRITE(R128_PM4_BUFFER_DL_WPTR, tmp);
-}
-
-/* Wait for the CCE to go idle.
- */
-int r128_do_cce_idle(drm_r128_private_t *dev_priv)
-{
- int i;
-
- for (i = 0; i < dev_priv->usec_timeout; i++) {
- if (GET_RING_HEAD(dev_priv) == dev_priv->ring.tail) {
- int pm4stat = R128_READ(R128_PM4_STAT);
- if (((pm4stat & R128_PM4_FIFOCNT_MASK) >=
- dev_priv->cce_fifo_size) &&
- !(pm4stat & (R128_PM4_BUSY |
- R128_PM4_GUI_ACTIVE))) {
- return r128_do_pixcache_flush(dev_priv);
- }
- }
- udelay(1);
- }
-
-#if R128_FIFO_DEBUG
- DRM_ERROR("failed!\n");
- r128_status(dev_priv);
-#endif
- return -EBUSY;
-}
-
-/* Start the Concurrent Command Engine.
- */
-static void r128_do_cce_start(drm_r128_private_t *dev_priv)
-{
- r128_do_wait_for_idle(dev_priv);
-
- R128_WRITE(R128_PM4_BUFFER_CNTL,
- dev_priv->cce_mode | dev_priv->ring.size_l2qw
- | R128_PM4_BUFFER_CNTL_NOUPDATE);
- R128_READ(R128_PM4_BUFFER_ADDR); /* as per the sample code */
- R128_WRITE(R128_PM4_MICRO_CNTL, R128_PM4_MICRO_FREERUN);
-
- dev_priv->cce_running = 1;
-}
-
-/* Reset the Concurrent Command Engine. This will not flush any pending
- * commands, so you must wait for the CCE command stream to complete
- * before calling this routine.
- */
-static void r128_do_cce_reset(drm_r128_private_t *dev_priv)
-{
- R128_WRITE(R128_PM4_BUFFER_DL_WPTR, 0);
- R128_WRITE(R128_PM4_BUFFER_DL_RPTR, 0);
- dev_priv->ring.tail = 0;
-}
-
-/* Stop the Concurrent Command Engine. This will not flush any pending
- * commands, so you must flush the command stream and wait for the CCE
- * to go idle before calling this routine.
- */
-static void r128_do_cce_stop(drm_r128_private_t *dev_priv)
-{
- R128_WRITE(R128_PM4_MICRO_CNTL, 0);
- R128_WRITE(R128_PM4_BUFFER_CNTL,
- R128_PM4_NONPM4 | R128_PM4_BUFFER_CNTL_NOUPDATE);
-
- dev_priv->cce_running = 0;
-}
-
-/* Reset the engine. This will stop the CCE if it is running.
- */
-static int r128_do_engine_reset(struct drm_device *dev)
-{
- drm_r128_private_t *dev_priv = dev->dev_private;
- u32 clock_cntl_index, mclk_cntl, gen_reset_cntl;
-
- r128_do_pixcache_flush(dev_priv);
-
- clock_cntl_index = R128_READ(R128_CLOCK_CNTL_INDEX);
- mclk_cntl = R128_READ_PLL(dev, R128_MCLK_CNTL);
-
- R128_WRITE_PLL(R128_MCLK_CNTL,
- mclk_cntl | R128_FORCE_GCP | R128_FORCE_PIPE3D_CP);
-
- gen_reset_cntl = R128_READ(R128_GEN_RESET_CNTL);
-
- /* Taken from the sample code - do not change */
- R128_WRITE(R128_GEN_RESET_CNTL, gen_reset_cntl | R128_SOFT_RESET_GUI);
- R128_READ(R128_GEN_RESET_CNTL);
- R128_WRITE(R128_GEN_RESET_CNTL, gen_reset_cntl & ~R128_SOFT_RESET_GUI);
- R128_READ(R128_GEN_RESET_CNTL);
-
- R128_WRITE_PLL(R128_MCLK_CNTL, mclk_cntl);
- R128_WRITE(R128_CLOCK_CNTL_INDEX, clock_cntl_index);
- R128_WRITE(R128_GEN_RESET_CNTL, gen_reset_cntl);
-
- /* Reset the CCE ring */
- r128_do_cce_reset(dev_priv);
-
- /* The CCE is no longer running after an engine reset */
- dev_priv->cce_running = 0;
-
- /* Reset any pending vertex, indirect buffers */
- r128_freelist_reset(dev);
-
- return 0;
-}
-
-static void r128_cce_init_ring_buffer(struct drm_device *dev,
- drm_r128_private_t *dev_priv)
-{
- u32 ring_start;
- u32 tmp;
-
- DRM_DEBUG("\n");
-
- /* The manual (p. 2) says this address is in "VM space". This
- * means it's an offset from the start of AGP space.
- */
-#if IS_ENABLED(CONFIG_AGP)
- if (!dev_priv->is_pci)
- ring_start = dev_priv->cce_ring->offset - dev->agp->base;
- else
-#endif
- ring_start = dev_priv->cce_ring->offset -
- (unsigned long)dev->sg->virtual;
-
- R128_WRITE(R128_PM4_BUFFER_OFFSET, ring_start | R128_AGP_OFFSET);
-
- R128_WRITE(R128_PM4_BUFFER_DL_WPTR, 0);
- R128_WRITE(R128_PM4_BUFFER_DL_RPTR, 0);
-
- /* Set watermark control */
- R128_WRITE(R128_PM4_BUFFER_WM_CNTL,
- ((R128_WATERMARK_L / 4) << R128_WMA_SHIFT)
- | ((R128_WATERMARK_M / 4) << R128_WMB_SHIFT)
- | ((R128_WATERMARK_N / 4) << R128_WMC_SHIFT)
- | ((R128_WATERMARK_K / 64) << R128_WB_WM_SHIFT));
-
- /* Force read. Why? Because it's in the examples... */
- R128_READ(R128_PM4_BUFFER_ADDR);
-
- /* Turn on bus mastering */
- tmp = R128_READ(R128_BUS_CNTL) & ~R128_BUS_MASTER_DIS;
- R128_WRITE(R128_BUS_CNTL, tmp);
-}
-
-static int r128_do_init_cce(struct drm_device *dev, drm_r128_init_t *init)
-{
- drm_r128_private_t *dev_priv;
- int rc;
-
- DRM_DEBUG("\n");
-
- if (dev->dev_private) {
- DRM_DEBUG("called when already initialized\n");
- return -EINVAL;
- }
-
- dev_priv = kzalloc(sizeof(drm_r128_private_t), GFP_KERNEL);
- if (dev_priv == NULL)
- return -ENOMEM;
-
- dev_priv->is_pci = init->is_pci;
-
- if (dev_priv->is_pci && !dev->sg) {
- DRM_ERROR("PCI GART memory not allocated!\n");
- dev->dev_private = (void *)dev_priv;
- r128_do_cleanup_cce(dev);
- return -EINVAL;
- }
-
- dev_priv->usec_timeout = init->usec_timeout;
- if (dev_priv->usec_timeout < 1 ||
- dev_priv->usec_timeout > R128_MAX_USEC_TIMEOUT) {
- DRM_DEBUG("TIMEOUT problem!\n");
- dev->dev_private = (void *)dev_priv;
- r128_do_cleanup_cce(dev);
- return -EINVAL;
- }
-
- dev_priv->cce_mode = init->cce_mode;
-
- /* GH: Simple idle check.
- */
- atomic_set(&dev_priv->idle_count, 0);
-
- /* We don't support anything other than bus-mastering ring mode,
- * but the ring can be in either AGP or PCI space for the ring
- * read pointer.
- */
- if ((init->cce_mode != R128_PM4_192BM) &&
- (init->cce_mode != R128_PM4_128BM_64INDBM) &&
- (init->cce_mode != R128_PM4_64BM_128INDBM) &&
- (init->cce_mode != R128_PM4_64BM_64VCBM_64INDBM)) {
- DRM_DEBUG("Bad cce_mode!\n");
- dev->dev_private = (void *)dev_priv;
- r128_do_cleanup_cce(dev);
- return -EINVAL;
- }
-
- switch (init->cce_mode) {
- case R128_PM4_NONPM4:
- dev_priv->cce_fifo_size = 0;
- break;
- case R128_PM4_192PIO:
- case R128_PM4_192BM:
- dev_priv->cce_fifo_size = 192;
- break;
- case R128_PM4_128PIO_64INDBM:
- case R128_PM4_128BM_64INDBM:
- dev_priv->cce_fifo_size = 128;
- break;
- case R128_PM4_64PIO_128INDBM:
- case R128_PM4_64BM_128INDBM:
- case R128_PM4_64PIO_64VCBM_64INDBM:
- case R128_PM4_64BM_64VCBM_64INDBM:
- case R128_PM4_64PIO_64VCPIO_64INDPIO:
- dev_priv->cce_fifo_size = 64;
- break;
- }
-
- switch (init->fb_bpp) {
- case 16:
- dev_priv->color_fmt = R128_DATATYPE_RGB565;
- break;
- case 32:
- default:
- dev_priv->color_fmt = R128_DATATYPE_ARGB8888;
- break;
- }
- dev_priv->front_offset = init->front_offset;
- dev_priv->front_pitch = init->front_pitch;
- dev_priv->back_offset = init->back_offset;
- dev_priv->back_pitch = init->back_pitch;
-
- switch (init->depth_bpp) {
- case 16:
- dev_priv->depth_fmt = R128_DATATYPE_RGB565;
- break;
- case 24:
- case 32:
- default:
- dev_priv->depth_fmt = R128_DATATYPE_ARGB8888;
- break;
- }
- dev_priv->depth_offset = init->depth_offset;
- dev_priv->depth_pitch = init->depth_pitch;
- dev_priv->span_offset = init->span_offset;
-
- dev_priv->front_pitch_offset_c = (((dev_priv->front_pitch / 8) << 21) |
- (dev_priv->front_offset >> 5));
- dev_priv->back_pitch_offset_c = (((dev_priv->back_pitch / 8) << 21) |
- (dev_priv->back_offset >> 5));
- dev_priv->depth_pitch_offset_c = (((dev_priv->depth_pitch / 8) << 21) |
- (dev_priv->depth_offset >> 5) |
- R128_DST_TILE);
- dev_priv->span_pitch_offset_c = (((dev_priv->depth_pitch / 8) << 21) |
- (dev_priv->span_offset >> 5));
-
- dev_priv->sarea = drm_legacy_getsarea(dev);
- if (!dev_priv->sarea) {
- DRM_ERROR("could not find sarea!\n");
- dev->dev_private = (void *)dev_priv;
- r128_do_cleanup_cce(dev);
- return -EINVAL;
- }
-
- dev_priv->mmio = drm_legacy_findmap(dev, init->mmio_offset);
- if (!dev_priv->mmio) {
- DRM_ERROR("could not find mmio region!\n");
- dev->dev_private = (void *)dev_priv;
- r128_do_cleanup_cce(dev);
- return -EINVAL;
- }
- dev_priv->cce_ring = drm_legacy_findmap(dev, init->ring_offset);
- if (!dev_priv->cce_ring) {
- DRM_ERROR("could not find cce ring region!\n");
- dev->dev_private = (void *)dev_priv;
- r128_do_cleanup_cce(dev);
- return -EINVAL;
- }
- dev_priv->ring_rptr = drm_legacy_findmap(dev, init->ring_rptr_offset);
- if (!dev_priv->ring_rptr) {
- DRM_ERROR("could not find ring read pointer!\n");
- dev->dev_private = (void *)dev_priv;
- r128_do_cleanup_cce(dev);
- return -EINVAL;
- }
- dev->agp_buffer_token = init->buffers_offset;
- dev->agp_buffer_map = drm_legacy_findmap(dev, init->buffers_offset);
- if (!dev->agp_buffer_map) {
- DRM_ERROR("could not find dma buffer region!\n");
- dev->dev_private = (void *)dev_priv;
- r128_do_cleanup_cce(dev);
- return -EINVAL;
- }
-
- if (!dev_priv->is_pci) {
- dev_priv->agp_textures =
- drm_legacy_findmap(dev, init->agp_textures_offset);
- if (!dev_priv->agp_textures) {
- DRM_ERROR("could not find agp texture region!\n");
- dev->dev_private = (void *)dev_priv;
- r128_do_cleanup_cce(dev);
- return -EINVAL;
- }
- }
-
- dev_priv->sarea_priv =
- (drm_r128_sarea_t *) ((u8 *) dev_priv->sarea->handle +
- init->sarea_priv_offset);
-
-#if IS_ENABLED(CONFIG_AGP)
- if (!dev_priv->is_pci) {
- drm_legacy_ioremap_wc(dev_priv->cce_ring, dev);
- drm_legacy_ioremap_wc(dev_priv->ring_rptr, dev);
- drm_legacy_ioremap_wc(dev->agp_buffer_map, dev);
- if (!dev_priv->cce_ring->handle ||
- !dev_priv->ring_rptr->handle ||
- !dev->agp_buffer_map->handle) {
- DRM_ERROR("Could not ioremap agp regions!\n");
- dev->dev_private = (void *)dev_priv;
- r128_do_cleanup_cce(dev);
- return -ENOMEM;
- }
- } else
-#endif
- {
- dev_priv->cce_ring->handle =
- (void *)(unsigned long)dev_priv->cce_ring->offset;
- dev_priv->ring_rptr->handle =
- (void *)(unsigned long)dev_priv->ring_rptr->offset;
- dev->agp_buffer_map->handle =
- (void *)(unsigned long)dev->agp_buffer_map->offset;
- }
-
-#if IS_ENABLED(CONFIG_AGP)
- if (!dev_priv->is_pci)
- dev_priv->cce_buffers_offset = dev->agp->base;
- else
-#endif
- dev_priv->cce_buffers_offset = (unsigned long)dev->sg->virtual;
-
- dev_priv->ring.start = (u32 *) dev_priv->cce_ring->handle;
- dev_priv->ring.end = ((u32 *) dev_priv->cce_ring->handle
- + init->ring_size / sizeof(u32));
- dev_priv->ring.size = init->ring_size;
- dev_priv->ring.size_l2qw = order_base_2(init->ring_size / 8);
-
- dev_priv->ring.tail_mask = (dev_priv->ring.size / sizeof(u32)) - 1;
-
- dev_priv->ring.high_mark = 128;
-
- dev_priv->sarea_priv->last_frame = 0;
- R128_WRITE(R128_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame);
-
- dev_priv->sarea_priv->last_dispatch = 0;
- R128_WRITE(R128_LAST_DISPATCH_REG, dev_priv->sarea_priv->last_dispatch);
-
-#if IS_ENABLED(CONFIG_AGP)
- if (dev_priv->is_pci) {
-#endif
- dev_priv->gart_info.table_mask = DMA_BIT_MASK(32);
- dev_priv->gart_info.gart_table_location = DRM_ATI_GART_MAIN;
- dev_priv->gart_info.table_size = R128_PCIGART_TABLE_SIZE;
- dev_priv->gart_info.addr = NULL;
- dev_priv->gart_info.bus_addr = 0;
- dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI;
- rc = drm_ati_pcigart_init(dev, &dev_priv->gart_info);
- if (rc) {
- DRM_ERROR("failed to init PCI GART!\n");
- dev->dev_private = (void *)dev_priv;
- r128_do_cleanup_cce(dev);
- return rc;
- }
- R128_WRITE(R128_PCI_GART_PAGE, dev_priv->gart_info.bus_addr);
-#if IS_ENABLED(CONFIG_AGP)
- }
-#endif
-
- r128_cce_init_ring_buffer(dev, dev_priv);
- rc = r128_cce_load_microcode(dev_priv);
-
- dev->dev_private = (void *)dev_priv;
-
- r128_do_engine_reset(dev);
-
- if (rc) {
- DRM_ERROR("Failed to load firmware!\n");
- r128_do_cleanup_cce(dev);
- }
-
- return rc;
-}
-
-int r128_do_cleanup_cce(struct drm_device *dev)
-{
-
- /* Make sure interrupts are disabled here because the uninstall ioctl
- * may not have been called from userspace and after dev_private
- * is freed, it's too late.
- */
- if (dev->irq_enabled)
- drm_legacy_irq_uninstall(dev);
-
- if (dev->dev_private) {
- drm_r128_private_t *dev_priv = dev->dev_private;
-
-#if IS_ENABLED(CONFIG_AGP)
- if (!dev_priv->is_pci) {
- if (dev_priv->cce_ring != NULL)
- drm_legacy_ioremapfree(dev_priv->cce_ring, dev);
- if (dev_priv->ring_rptr != NULL)
- drm_legacy_ioremapfree(dev_priv->ring_rptr, dev);
- if (dev->agp_buffer_map != NULL) {
- drm_legacy_ioremapfree(dev->agp_buffer_map, dev);
- dev->agp_buffer_map = NULL;
- }
- } else
-#endif
- {
- if (dev_priv->gart_info.bus_addr)
- if (!drm_ati_pcigart_cleanup(dev,
- &dev_priv->gart_info))
- DRM_ERROR
- ("failed to cleanup PCI GART!\n");
- }
-
- kfree(dev->dev_private);
- dev->dev_private = NULL;
- }
-
- return 0;
-}
-
-int r128_cce_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_r128_init_t *init = data;
-
- DRM_DEBUG("\n");
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- switch (init->func) {
- case R128_INIT_CCE:
- return r128_do_init_cce(dev, init);
- case R128_CLEANUP_CCE:
- return r128_do_cleanup_cce(dev);
- }
-
- return -EINVAL;
-}
-
-int r128_cce_start(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_r128_private_t *dev_priv = dev->dev_private;
- DRM_DEBUG("\n");
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- DEV_INIT_TEST_WITH_RETURN(dev_priv);
-
- if (dev_priv->cce_running || dev_priv->cce_mode == R128_PM4_NONPM4) {
- DRM_DEBUG("while CCE running\n");
- return 0;
- }
-
- r128_do_cce_start(dev_priv);
-
- return 0;
-}
-
-/* Stop the CCE. The engine must have been idled before calling this
- * routine.
- */
-int r128_cce_stop(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_r128_private_t *dev_priv = dev->dev_private;
- drm_r128_cce_stop_t *stop = data;
- int ret;
- DRM_DEBUG("\n");
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- DEV_INIT_TEST_WITH_RETURN(dev_priv);
-
- /* Flush any pending CCE commands. This ensures any outstanding
- * commands are exectuted by the engine before we turn it off.
- */
- if (stop->flush)
- r128_do_cce_flush(dev_priv);
-
- /* If we fail to make the engine go idle, we return an error
- * code so that the DRM ioctl wrapper can try again.
- */
- if (stop->idle) {
- ret = r128_do_cce_idle(dev_priv);
- if (ret)
- return ret;
- }
-
- /* Finally, we can turn off the CCE. If the engine isn't idle,
- * we will get some dropped triangles as they won't be fully
- * rendered before the CCE is shut down.
- */
- r128_do_cce_stop(dev_priv);
-
- /* Reset the engine */
- r128_do_engine_reset(dev);
-
- return 0;
-}
-
-/* Just reset the CCE ring. Called as part of an X Server engine reset.
- */
-int r128_cce_reset(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_r128_private_t *dev_priv = dev->dev_private;
- DRM_DEBUG("\n");
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- DEV_INIT_TEST_WITH_RETURN(dev_priv);
-
- r128_do_cce_reset(dev_priv);
-
- /* The CCE is no longer running after an engine reset */
- dev_priv->cce_running = 0;
-
- return 0;
-}
-
-int r128_cce_idle(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_r128_private_t *dev_priv = dev->dev_private;
- DRM_DEBUG("\n");
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- DEV_INIT_TEST_WITH_RETURN(dev_priv);
-
- if (dev_priv->cce_running)
- r128_do_cce_flush(dev_priv);
-
- return r128_do_cce_idle(dev_priv);
-}
-
-int r128_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- DRM_DEBUG("\n");
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- DEV_INIT_TEST_WITH_RETURN(dev->dev_private);
-
- return r128_do_engine_reset(dev);
-}
-
-int r128_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- return -EINVAL;
-}
-
-/* ================================================================
- * Freelist management
- */
-#define R128_BUFFER_USED 0xffffffff
-#define R128_BUFFER_FREE 0
-
-#if 0
-static int r128_freelist_init(struct drm_device *dev)
-{
- struct drm_device_dma *dma = dev->dma;
- drm_r128_private_t *dev_priv = dev->dev_private;
- struct drm_buf *buf;
- drm_r128_buf_priv_t *buf_priv;
- drm_r128_freelist_t *entry;
- int i;
-
- dev_priv->head = kzalloc(sizeof(drm_r128_freelist_t), GFP_KERNEL);
- if (dev_priv->head == NULL)
- return -ENOMEM;
-
- dev_priv->head->age = R128_BUFFER_USED;
-
- for (i = 0; i < dma->buf_count; i++) {
- buf = dma->buflist[i];
- buf_priv = buf->dev_private;
-
- entry = kmalloc(sizeof(drm_r128_freelist_t), GFP_KERNEL);
- if (!entry)
- return -ENOMEM;
-
- entry->age = R128_BUFFER_FREE;
- entry->buf = buf;
- entry->prev = dev_priv->head;
- entry->next = dev_priv->head->next;
- if (!entry->next)
- dev_priv->tail = entry;
-
- buf_priv->discard = 0;
- buf_priv->dispatched = 0;
- buf_priv->list_entry = entry;
-
- dev_priv->head->next = entry;
-
- if (dev_priv->head->next)
- dev_priv->head->next->prev = entry;
- }
-
- return 0;
-
-}
-#endif
-
-static struct drm_buf *r128_freelist_get(struct drm_device * dev)
-{
- struct drm_device_dma *dma = dev->dma;
- drm_r128_private_t *dev_priv = dev->dev_private;
- drm_r128_buf_priv_t *buf_priv;
- struct drm_buf *buf;
- int i, t;
-
- /* FIXME: Optimize -- use freelist code */
-
- for (i = 0; i < dma->buf_count; i++) {
- buf = dma->buflist[i];
- buf_priv = buf->dev_private;
- if (!buf->file_priv)
- return buf;
- }
-
- for (t = 0; t < dev_priv->usec_timeout; t++) {
- u32 done_age = R128_READ(R128_LAST_DISPATCH_REG);
-
- for (i = 0; i < dma->buf_count; i++) {
- buf = dma->buflist[i];
- buf_priv = buf->dev_private;
- if (buf->pending && buf_priv->age <= done_age) {
- /* The buffer has been processed, so it
- * can now be used.
- */
- buf->pending = 0;
- return buf;
- }
- }
- udelay(1);
- }
-
- DRM_DEBUG("returning NULL!\n");
- return NULL;
-}
-
-void r128_freelist_reset(struct drm_device *dev)
-{
- struct drm_device_dma *dma = dev->dma;
- int i;
-
- for (i = 0; i < dma->buf_count; i++) {
- struct drm_buf *buf = dma->buflist[i];
- drm_r128_buf_priv_t *buf_priv = buf->dev_private;
- buf_priv->age = 0;
- }
-}
-
-/* ================================================================
- * CCE command submission
- */
-
-int r128_wait_ring(drm_r128_private_t *dev_priv, int n)
-{
- drm_r128_ring_buffer_t *ring = &dev_priv->ring;
- int i;
-
- for (i = 0; i < dev_priv->usec_timeout; i++) {
- r128_update_ring_snapshot(dev_priv);
- if (ring->space >= n)
- return 0;
- udelay(1);
- }
-
- /* FIXME: This is being ignored... */
- DRM_ERROR("failed!\n");
- return -EBUSY;
-}
-
-static int r128_cce_get_buffers(struct drm_device *dev,
- struct drm_file *file_priv,
- struct drm_dma *d)
-{
- int i;
- struct drm_buf *buf;
-
- for (i = d->granted_count; i < d->request_count; i++) {
- buf = r128_freelist_get(dev);
- if (!buf)
- return -EAGAIN;
-
- buf->file_priv = file_priv;
-
- if (copy_to_user(&d->request_indices[i], &buf->idx,
- sizeof(buf->idx)))
- return -EFAULT;
- if (copy_to_user(&d->request_sizes[i], &buf->total,
- sizeof(buf->total)))
- return -EFAULT;
-
- d->granted_count++;
- }
- return 0;
-}
-
-int r128_cce_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- struct drm_device_dma *dma = dev->dma;
- int ret = 0;
- struct drm_dma *d = data;
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- /* Please don't send us buffers.
- */
- if (d->send_count != 0) {
- DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n",
- task_pid_nr(current), d->send_count);
- return -EINVAL;
- }
-
- /* We'll send you buffers.
- */
- if (d->request_count < 0 || d->request_count > dma->buf_count) {
- DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",
- task_pid_nr(current), d->request_count, dma->buf_count);
- return -EINVAL;
- }
-
- d->granted_count = 0;
-
- if (d->request_count)
- ret = r128_cce_get_buffers(dev, file_priv, d);
-
- return ret;
-}
diff --git a/drivers/gpu/drm/r128/r128_drv.c b/drivers/gpu/drm/r128/r128_drv.c
deleted file mode 100644
index e35a3a1449bd..000000000000
--- a/drivers/gpu/drm/r128/r128_drv.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/* r128_drv.c -- ATI Rage 128 driver -*- linux-c -*-
- * Created: Mon Dec 13 09:47:27 1999 by faith@precisioninsight.com
- *
- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software 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 (including the next
- * paragraph) 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
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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.
- *
- * Authors:
- * Rickard E. (Rik) Faith <faith@valinux.com>
- * Gareth Hughes <gareth@valinux.com>
- */
-
-#include <linux/module.h>
-#include <linux/pci.h>
-
-#include <drm/drm_drv.h>
-#include <drm/drm_file.h>
-#include <drm/drm_pciids.h>
-#include <drm/drm_vblank.h>
-#include <drm/r128_drm.h>
-
-#include "r128_drv.h"
-
-static struct pci_device_id pciidlist[] = {
- r128_PCI_IDS
-};
-
-static const struct file_operations r128_driver_fops = {
- .owner = THIS_MODULE,
- .open = drm_open,
- .release = drm_release,
- .unlocked_ioctl = drm_ioctl,
- .mmap = drm_legacy_mmap,
- .poll = drm_poll,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = r128_compat_ioctl,
-#endif
- .llseek = noop_llseek,
-};
-
-static struct drm_driver driver = {
- .driver_features =
- DRIVER_USE_AGP | DRIVER_PCI_DMA | DRIVER_SG | DRIVER_LEGACY |
- DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ,
- .dev_priv_size = sizeof(drm_r128_buf_priv_t),
- .load = r128_driver_load,
- .preclose = r128_driver_preclose,
- .lastclose = r128_driver_lastclose,
- .get_vblank_counter = r128_get_vblank_counter,
- .enable_vblank = r128_enable_vblank,
- .disable_vblank = r128_disable_vblank,
- .irq_preinstall = r128_driver_irq_preinstall,
- .irq_postinstall = r128_driver_irq_postinstall,
- .irq_uninstall = r128_driver_irq_uninstall,
- .irq_handler = r128_driver_irq_handler,
- .ioctls = r128_ioctls,
- .dma_ioctl = r128_cce_buffers,
- .fops = &r128_driver_fops,
- .name = DRIVER_NAME,
- .desc = DRIVER_DESC,
- .date = DRIVER_DATE,
- .major = DRIVER_MAJOR,
- .minor = DRIVER_MINOR,
- .patchlevel = DRIVER_PATCHLEVEL,
-};
-
-int r128_driver_load(struct drm_device *dev, unsigned long flags)
-{
- struct pci_dev *pdev = to_pci_dev(dev->dev);
-
- pci_set_master(pdev);
- return drm_vblank_init(dev, 1);
-}
-
-static struct pci_driver r128_pci_driver = {
- .name = DRIVER_NAME,
- .id_table = pciidlist,
-};
-
-static int __init r128_init(void)
-{
- driver.num_ioctls = r128_max_ioctl;
-
- return drm_legacy_pci_init(&driver, &r128_pci_driver);
-}
-
-static void __exit r128_exit(void)
-{
- drm_legacy_pci_exit(&driver, &r128_pci_driver);
-}
-
-module_init(r128_init);
-module_exit(r128_exit);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/gpu/drm/r128/r128_drv.h b/drivers/gpu/drm/r128/r128_drv.h
deleted file mode 100644
index 970e192b0d51..000000000000
--- a/drivers/gpu/drm/r128/r128_drv.h
+++ /dev/null
@@ -1,544 +0,0 @@
-/* r128_drv.h -- Private header for r128 driver -*- linux-c -*-
- * Created: Mon Dec 13 09:51:11 1999 by faith@precisioninsight.com
- */
-/*
- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software 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 (including the next
- * paragraph) 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
- * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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.
- *
- * Authors:
- * Rickard E. (Rik) Faith <faith@valinux.com>
- * Kevin E. Martin <martin@valinux.com>
- * Gareth Hughes <gareth@valinux.com>
- * Michel Dänzer <daenzerm@student.ethz.ch>
- */
-
-#ifndef __R128_DRV_H__
-#define __R128_DRV_H__
-
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/irqreturn.h>
-
-#include <drm/drm_ioctl.h>
-#include <drm/drm_legacy.h>
-#include <drm/r128_drm.h>
-
-#include "ati_pcigart.h"
-
-/* General customization:
- */
-#define DRIVER_AUTHOR "Gareth Hughes, VA Linux Systems Inc."
-
-#define DRIVER_NAME "r128"
-#define DRIVER_DESC "ATI Rage 128"
-#define DRIVER_DATE "20030725"
-
-/* Interface history:
- *
- * ?? - ??
- * 2.4 - Add support for ycbcr textures (no new ioctls)
- * 2.5 - Add FLIP ioctl, disable FULLSCREEN.
- */
-#define DRIVER_MAJOR 2
-#define DRIVER_MINOR 5
-#define DRIVER_PATCHLEVEL 0
-
-#define GET_RING_HEAD(dev_priv) R128_READ(R128_PM4_BUFFER_DL_RPTR)
-
-typedef struct drm_r128_freelist {
- unsigned int age;
- struct drm_buf *buf;
- struct drm_r128_freelist *next;
- struct drm_r128_freelist *prev;
-} drm_r128_freelist_t;
-
-typedef struct drm_r128_ring_buffer {
- u32 *start;
- u32 *end;
- int size;
- int size_l2qw;
-
- u32 tail;
- u32 tail_mask;
- int space;
-
- int high_mark;
-} drm_r128_ring_buffer_t;
-
-typedef struct drm_r128_private {
- drm_r128_ring_buffer_t ring;
- drm_r128_sarea_t *sarea_priv;
-
- int cce_mode;
- int cce_fifo_size;
- int cce_running;
-
- drm_r128_freelist_t *head;
- drm_r128_freelist_t *tail;
-
- int usec_timeout;
- int is_pci;
- unsigned long cce_buffers_offset;
-
- atomic_t idle_count;
-
- int page_flipping;
- int current_page;
- u32 crtc_offset;
- u32 crtc_offset_cntl;
-
- atomic_t vbl_received;
-
- u32 color_fmt;
- unsigned int front_offset;
- unsigned int front_pitch;
- unsigned int back_offset;
- unsigned int back_pitch;
-
- u32 depth_fmt;
- unsigned int depth_offset;
- unsigned int depth_pitch;
- unsigned int span_offset;
-
- u32 front_pitch_offset_c;
- u32 back_pitch_offset_c;
- u32 depth_pitch_offset_c;
- u32 span_pitch_offset_c;
-
- drm_local_map_t *sarea;
- drm_local_map_t *mmio;
- drm_local_map_t *cce_ring;
- drm_local_map_t *ring_rptr;
- drm_local_map_t *agp_textures;
- struct drm_ati_pcigart_info gart_info;
-} drm_r128_private_t;
-
-typedef struct drm_r128_buf_priv {
- u32 age;
- int prim;
- int discard;
- int dispatched;
- drm_r128_freelist_t *list_entry;
-} drm_r128_buf_priv_t;
-
-extern const struct drm_ioctl_desc r128_ioctls[];
-extern int r128_max_ioctl;
-
- /* r128_cce.c */
-extern int r128_cce_init(struct drm_device *dev, void *data, struct drm_file *file_priv);
-extern int r128_cce_start(struct drm_device *dev, void *data, struct drm_file *file_priv);
-extern int r128_cce_stop(struct drm_device *dev, void *data, struct drm_file *file_priv);
-extern int r128_cce_reset(struct drm_device *dev, void *data, struct drm_file *file_priv);
-extern int r128_cce_idle(struct drm_device *dev, void *data, struct drm_file *file_priv);
-extern int r128_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv);
-extern int r128_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv);
-extern int r128_cce_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv);
-
-extern int r128_cce_stipple(struct drm_device *dev, void *data, struct drm_file *file_priv);
-extern int r128_cce_depth(struct drm_device *dev, void *data, struct drm_file *file_priv);
-extern int r128_getparam(struct drm_device *dev, void *data, struct drm_file *file_priv);
-
-extern void r128_freelist_reset(struct drm_device *dev);
-
-extern int r128_wait_ring(drm_r128_private_t *dev_priv, int n);
-
-extern int r128_do_cce_idle(drm_r128_private_t *dev_priv);
-extern int r128_do_cleanup_cce(struct drm_device *dev);
-
-extern int r128_enable_vblank(struct drm_device *dev, unsigned int pipe);
-extern void r128_disable_vblank(struct drm_device *dev, unsigned int pipe);
-extern u32 r128_get_vblank_counter(struct drm_device *dev, unsigned int pipe);
-extern irqreturn_t r128_driver_irq_handler(int irq, void *arg);
-extern void r128_driver_irq_preinstall(struct drm_device *dev);
-extern int r128_driver_irq_postinstall(struct drm_device *dev);
-extern void r128_driver_irq_uninstall(struct drm_device *dev);
-extern void r128_driver_lastclose(struct drm_device *dev);
-extern int r128_driver_load(struct drm_device *dev, unsigned long flags);
-extern void r128_driver_preclose(struct drm_device *dev,
- struct drm_file *file_priv);
-
-extern long r128_compat_ioctl(struct file *filp, unsigned int cmd,
- unsigned long arg);
-
-/* Register definitions, register access macros and drmAddMap constants
- * for Rage 128 kernel driver.
- */
-
-#define R128_AUX_SC_CNTL 0x1660
-# define R128_AUX1_SC_EN (1 << 0)
-# define R128_AUX1_SC_MODE_OR (0 << 1)
-# define R128_AUX1_SC_MODE_NAND (1 << 1)
-# define R128_AUX2_SC_EN (1 << 2)
-# define R128_AUX2_SC_MODE_OR (0 << 3)
-# define R128_AUX2_SC_MODE_NAND (1 << 3)
-# define R128_AUX3_SC_EN (1 << 4)
-# define R128_AUX3_SC_MODE_OR (0 << 5)
-# define R128_AUX3_SC_MODE_NAND (1 << 5)
-#define R128_AUX1_SC_LEFT 0x1664
-#define R128_AUX1_SC_RIGHT 0x1668
-#define R128_AUX1_SC_TOP 0x166c
-#define R128_AUX1_SC_BOTTOM 0x1670
-#define R128_AUX2_SC_LEFT 0x1674
-#define R128_AUX2_SC_RIGHT 0x1678
-#define R128_AUX2_SC_TOP 0x167c
-#define R128_AUX2_SC_BOTTOM 0x1680
-#define R128_AUX3_SC_LEFT 0x1684
-#define R128_AUX3_SC_RIGHT 0x1688
-#define R128_AUX3_SC_TOP 0x168c
-#define R128_AUX3_SC_BOTTOM 0x1690
-
-#define R128_BRUSH_DATA0 0x1480
-#define R128_BUS_CNTL 0x0030
-# define R128_BUS_MASTER_DIS (1 << 6)
-
-#define R128_CLOCK_CNTL_INDEX 0x0008
-#define R128_CLOCK_CNTL_DATA 0x000c
-# define R128_PLL_WR_EN (1 << 7)
-#define R128_CONSTANT_COLOR_C 0x1d34
-#define R128_CRTC_OFFSET 0x0224
-#define R128_CRTC_OFFSET_CNTL 0x0228
-# define R128_CRTC_OFFSET_FLIP_CNTL (1 << 16)
-
-#define R128_DP_GUI_MASTER_CNTL 0x146c
-# define R128_GMC_SRC_PITCH_OFFSET_CNTL (1 << 0)
-# define R128_GMC_DST_PITCH_OFFSET_CNTL (1 << 1)
-# define R128_GMC_BRUSH_SOLID_COLOR (13 << 4)
-# define R128_GMC_BRUSH_NONE (15 << 4)
-# define R128_GMC_DST_16BPP (4 << 8)
-# define R128_GMC_DST_24BPP (5 << 8)
-# define R128_GMC_DST_32BPP (6 << 8)
-# define R128_GMC_DST_DATATYPE_SHIFT 8
-# define R128_GMC_SRC_DATATYPE_COLOR (3 << 12)
-# define R128_DP_SRC_SOURCE_MEMORY (2 << 24)
-# define R128_DP_SRC_SOURCE_HOST_DATA (3 << 24)
-# define R128_GMC_CLR_CMP_CNTL_DIS (1 << 28)
-# define R128_GMC_AUX_CLIP_DIS (1 << 29)
-# define R128_GMC_WR_MSK_DIS (1 << 30)
-# define R128_ROP3_S 0x00cc0000
-# define R128_ROP3_P 0x00f00000
-#define R128_DP_WRITE_MASK 0x16cc
-#define R128_DST_PITCH_OFFSET_C 0x1c80
-# define R128_DST_TILE (1 << 31)
-
-#define R128_GEN_INT_CNTL 0x0040
-# define R128_CRTC_VBLANK_INT_EN (1 << 0)
-#define R128_GEN_INT_STATUS 0x0044
-# define R128_CRTC_VBLANK_INT (1 << 0)
-# define R128_CRTC_VBLANK_INT_AK (1 << 0)
-#define R128_GEN_RESET_CNTL 0x00f0
-# define R128_SOFT_RESET_GUI (1 << 0)
-
-#define R128_GUI_SCRATCH_REG0 0x15e0
-#define R128_GUI_SCRATCH_REG1 0x15e4
-#define R128_GUI_SCRATCH_REG2 0x15e8
-#define R128_GUI_SCRATCH_REG3 0x15ec
-#define R128_GUI_SCRATCH_REG4 0x15f0
-#define R128_GUI_SCRATCH_REG5 0x15f4
-
-#define R128_GUI_STAT 0x1740
-# define R128_GUI_FIFOCNT_MASK 0x0fff
-# define R128_GUI_ACTIVE (1 << 31)
-
-#define R128_MCLK_CNTL 0x000f
-# define R128_FORCE_GCP (1 << 16)
-# define R128_FORCE_PIPE3D_CP (1 << 17)
-# define R128_FORCE_RCP (1 << 18)
-
-#define R128_PC_GUI_CTLSTAT 0x1748
-#define R128_PC_NGUI_CTLSTAT 0x0184
-# define R128_PC_FLUSH_GUI (3 << 0)
-# define R128_PC_RI_GUI (1 << 2)
-# define R128_PC_FLUSH_ALL 0x00ff
-# define R128_PC_BUSY (1 << 31)
-
-#define R128_PCI_GART_PAGE 0x017c
-#define R128_PRIM_TEX_CNTL_C 0x1cb0
-
-#define R128_SCALE_3D_CNTL 0x1a00
-#define R128_SEC_TEX_CNTL_C 0x1d00
-#define R128_SEC_TEXTURE_BORDER_COLOR_C 0x1d3c
-#define R128_SETUP_CNTL 0x1bc4
-#define R128_STEN_REF_MASK_C 0x1d40
-
-#define R128_TEX_CNTL_C 0x1c9c
-# define R128_TEX_CACHE_FLUSH (1 << 23)
-
-#define R128_WAIT_UNTIL 0x1720
-# define R128_EVENT_CRTC_OFFSET (1 << 0)
-#define R128_WINDOW_XY_OFFSET 0x1bcc
-
-/* CCE registers
- */
-#define R128_PM4_BUFFER_OFFSET 0x0700
-#define R128_PM4_BUFFER_CNTL 0x0704
-# define R128_PM4_MASK (15 << 28)
-# define R128_PM4_NONPM4 (0 << 28)
-# define R128_PM4_192PIO (1 << 28)
-# define R128_PM4_192BM (2 << 28)
-# define R128_PM4_128PIO_64INDBM (3 << 28)
-# define R128_PM4_128BM_64INDBM (4 << 28)
-# define R128_PM4_64PIO_128INDBM (5 << 28)
-# define R128_PM4_64BM_128INDBM (6 << 28)
-# define R128_PM4_64PIO_64VCBM_64INDBM (7 << 28)
-# define R128_PM4_64BM_64VCBM_64INDBM (8U << 28)
-# define R128_PM4_64PIO_64VCPIO_64INDPIO (15U << 28)
-# define R128_PM4_BUFFER_CNTL_NOUPDATE (1 << 27)
-
-#define R128_PM4_BUFFER_WM_CNTL 0x0708
-# define R128_WMA_SHIFT 0
-# define R128_WMB_SHIFT 8
-# define R128_WMC_SHIFT 16
-# define R128_WB_WM_SHIFT 24
-
-#define R128_PM4_BUFFER_DL_RPTR_ADDR 0x070c
-#define R128_PM4_BUFFER_DL_RPTR 0x0710
-#define R128_PM4_BUFFER_DL_WPTR 0x0714
-# define R128_PM4_BUFFER_DL_DONE (1 << 31)
-
-#define R128_PM4_VC_FPU_SETUP 0x071c
-
-#define R128_PM4_IW_INDOFF 0x0738
-#define R128_PM4_IW_INDSIZE 0x073c
-
-#define R128_PM4_STAT 0x07b8
-# define R128_PM4_FIFOCNT_MASK 0x0fff
-# define R128_PM4_BUSY (1 << 16)
-# define R128_PM4_GUI_ACTIVE (1 << 31)
-
-#define R128_PM4_MICROCODE_ADDR 0x07d4
-#define R128_PM4_MICROCODE_RADDR 0x07d8
-#define R128_PM4_MICROCODE_DATAH 0x07dc
-#define R128_PM4_MICROCODE_DATAL 0x07e0
-
-#define R128_PM4_BUFFER_ADDR 0x07f0
-#define R128_PM4_MICRO_CNTL 0x07fc
-# define R128_PM4_MICRO_FREERUN (1 << 30)
-
-#define R128_PM4_FIFO_DATA_EVEN 0x1000
-#define R128_PM4_FIFO_DATA_ODD 0x1004
-
-/* CCE command packets
- */
-#define R128_CCE_PACKET0 0x00000000
-#define R128_CCE_PACKET1 0x40000000
-#define R128_CCE_PACKET2 0x80000000
-#define R128_CCE_PACKET3 0xC0000000
-# define R128_CNTL_HOSTDATA_BLT 0x00009400
-# define R128_CNTL_PAINT_MULTI 0x00009A00
-# define R128_CNTL_BITBLT_MULTI 0x00009B00
-# define R128_3D_RNDR_GEN_INDX_PRIM 0x00002300
-
-#define R128_CCE_PACKET_MASK 0xC0000000
-#define R128_CCE_PACKET_COUNT_MASK 0x3fff0000
-#define R128_CCE_PACKET0_REG_MASK 0x000007ff
-#define R128_CCE_PACKET1_REG0_MASK 0x000007ff
-#define R128_CCE_PACKET1_REG1_MASK 0x003ff800
-
-#define R128_CCE_VC_CNTL_PRIM_TYPE_NONE 0x00000000
-#define R128_CCE_VC_CNTL_PRIM_TYPE_POINT 0x00000001
-#define R128_CCE_VC_CNTL_PRIM_TYPE_LINE 0x00000002
-#define R128_CCE_VC_CNTL_PRIM_TYPE_POLY_LINE 0x00000003
-#define R128_CCE_VC_CNTL_PRIM_TYPE_TRI_LIST 0x00000004
-#define R128_CCE_VC_CNTL_PRIM_TYPE_TRI_FAN 0x00000005
-#define R128_CCE_VC_CNTL_PRIM_TYPE_TRI_STRIP 0x00000006
-#define R128_CCE_VC_CNTL_PRIM_TYPE_TRI_TYPE2 0x00000007
-#define R128_CCE_VC_CNTL_PRIM_WALK_IND 0x00000010
-#define R128_CCE_VC_CNTL_PRIM_WALK_LIST 0x00000020
-#define R128_CCE_VC_CNTL_PRIM_WALK_RING 0x00000030
-#define R128_CCE_VC_CNTL_NUM_SHIFT 16
-
-#define R128_DATATYPE_VQ 0
-#define R128_DATATYPE_CI4 1
-#define R128_DATATYPE_CI8 2
-#define R128_DATATYPE_ARGB1555 3
-#define R128_DATATYPE_RGB565 4
-#define R128_DATATYPE_RGB888 5
-#define R128_DATATYPE_ARGB8888 6
-#define R128_DATATYPE_RGB332 7
-#define R128_DATATYPE_Y8 8
-#define R128_DATATYPE_RGB8 9
-#define R128_DATATYPE_CI16 10
-#define R128_DATATYPE_YVYU422 11
-#define R128_DATATYPE_VYUY422 12
-#define R128_DATATYPE_AYUV444 14
-#define R128_DATATYPE_ARGB4444 15
-
-/* Constants */
-#define R128_AGP_OFFSET 0x02000000
-
-#define R128_WATERMARK_L 16
-#define R128_WATERMARK_M 8
-#define R128_WATERMARK_N 8
-#define R128_WATERMARK_K 128
-
-#define R128_MAX_USEC_TIMEOUT 100000 /* 100 ms */
-
-#define R128_LAST_FRAME_REG R128_GUI_SCRATCH_REG0
-#define R128_LAST_DISPATCH_REG R128_GUI_SCRATCH_REG1
-#define R128_MAX_VB_AGE 0x7fffffff
-#define R128_MAX_VB_VERTS (0xffff)
-
-#define R128_RING_HIGH_MARK 128
-
-#define R128_PERFORMANCE_BOXES 0
-
-#define R128_PCIGART_TABLE_SIZE 32768
-
-#define R128_READ(reg) readl(((void __iomem *)dev_priv->mmio->handle) + (reg))
-#define R128_WRITE(reg, val) writel(val, ((void __iomem *)dev_priv->mmio->handle) + (reg))
-#define R128_READ8(reg) readb(((void __iomem *)dev_priv->mmio->handle) + (reg))
-#define R128_WRITE8(reg, val) writeb(val, ((void __iomem *)dev_priv->mmio->handle) + (reg))
-
-#define R128_WRITE_PLL(addr, val) \
-do { \
- R128_WRITE8(R128_CLOCK_CNTL_INDEX, \
- ((addr) & 0x1f) | R128_PLL_WR_EN); \
- R128_WRITE(R128_CLOCK_CNTL_DATA, (val)); \
-} while (0)
-
-#define CCE_PACKET0(reg, n) (R128_CCE_PACKET0 | \
- ((n) << 16) | ((reg) >> 2))
-#define CCE_PACKET1(reg0, reg1) (R128_CCE_PACKET1 | \
- (((reg1) >> 2) << 11) | ((reg0) >> 2))
-#define CCE_PACKET2() (R128_CCE_PACKET2)
-#define CCE_PACKET3(pkt, n) (R128_CCE_PACKET3 | \
- (pkt) | ((n) << 16))
-
-static __inline__ void r128_update_ring_snapshot(drm_r128_private_t *dev_priv)
-{
- drm_r128_ring_buffer_t *ring = &dev_priv->ring;
- ring->space = (GET_RING_HEAD(dev_priv) - ring->tail) * sizeof(u32);
- if (ring->space <= 0)
- ring->space += ring->size;
-}
-
-/* ================================================================
- * Misc helper macros
- */
-
-#define DEV_INIT_TEST_WITH_RETURN(_dev_priv) \
-do { \
- if (!_dev_priv) { \
- DRM_ERROR("called with no initialization\n"); \
- return -EINVAL; \
- } \
-} while (0)
-
-#define RING_SPACE_TEST_WITH_RETURN(dev_priv) \
-do { \
- drm_r128_ring_buffer_t *ring = &dev_priv->ring; int i; \
- if (ring->space < ring->high_mark) { \
- for (i = 0 ; i < dev_priv->usec_timeout ; i++) { \
- r128_update_ring_snapshot(dev_priv); \
- if (ring->space >= ring->high_mark) \
- goto __ring_space_done; \
- udelay(1); \
- } \
- DRM_ERROR("ring space check failed!\n"); \
- return -EBUSY; \
- } \
- __ring_space_done: \
- ; \
-} while (0)
-
-#define VB_AGE_TEST_WITH_RETURN(dev_priv) \
-do { \
- drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; \
- if (sarea_priv->last_dispatch >= R128_MAX_VB_AGE) { \
- int __ret = r128_do_cce_idle(dev_priv); \
- if (__ret) \
- return __ret; \
- sarea_priv->last_dispatch = 0; \
- r128_freelist_reset(dev); \
- } \
-} while (0)
-
-#define R128_WAIT_UNTIL_PAGE_FLIPPED() do { \
- OUT_RING(CCE_PACKET0(R128_WAIT_UNTIL, 0)); \
- OUT_RING(R128_EVENT_CRTC_OFFSET); \
-} while (0)
-
-/* ================================================================
- * Ring control
- */
-
-#define R128_VERBOSE 0
-
-#define RING_LOCALS \
- int write, _nr; unsigned int tail_mask; volatile u32 *ring;
-
-#define BEGIN_RING(n) do { \
- if (R128_VERBOSE) \
- DRM_INFO("BEGIN_RING(%d)\n", (n)); \
- if (dev_priv->ring.space <= (n) * sizeof(u32)) { \
- COMMIT_RING(); \
- r128_wait_ring(dev_priv, (n) * sizeof(u32)); \
- } \
- _nr = n; dev_priv->ring.space -= (n) * sizeof(u32); \
- ring = dev_priv->ring.start; \
- write = dev_priv->ring.tail; \
- tail_mask = dev_priv->ring.tail_mask; \
-} while (0)
-
-/* You can set this to zero if you want. If the card locks up, you'll
- * need to keep this set. It works around a bug in early revs of the
- * Rage 128 chipset, where the CCE would read 32 dwords past the end of
- * the ring buffer before wrapping around.
- */
-#define R128_BROKEN_CCE 1
-
-#define ADVANCE_RING() do { \
- if (R128_VERBOSE) \
- DRM_INFO("ADVANCE_RING() wr=0x%06x tail=0x%06x\n", \
- write, dev_priv->ring.tail); \
- if (R128_BROKEN_CCE && write < 32) \
- memcpy(dev_priv->ring.end, \
- dev_priv->ring.start, \
- write * sizeof(u32)); \
- if (((dev_priv->ring.tail + _nr) & tail_mask) != write) \
- DRM_ERROR( \
- "ADVANCE_RING(): mismatch: nr: %x write: %x line: %d\n", \
- ((dev_priv->ring.tail + _nr) & tail_mask), \
- write, __LINE__); \
- else \
- dev_priv->ring.tail = write; \
-} while (0)
-
-#define COMMIT_RING() do { \
- if (R128_VERBOSE) \
- DRM_INFO("COMMIT_RING() tail=0x%06x\n", \
- dev_priv->ring.tail); \
- mb(); \
- R128_WRITE(R128_PM4_BUFFER_DL_WPTR, dev_priv->ring.tail); \
- R128_READ(R128_PM4_BUFFER_DL_WPTR); \
-} while (0)
-
-#define OUT_RING(x) do { \
- if (R128_VERBOSE) \
- DRM_INFO(" OUT_RING( 0x%08x ) at 0x%x\n", \
- (unsigned int)(x), write); \
- ring[write++] = cpu_to_le32(x); \
- write &= tail_mask; \
-} while (0)
-
-#endif /* __R128_DRV_H__ */
diff --git a/drivers/gpu/drm/r128/r128_ioc32.c b/drivers/gpu/drm/r128/r128_ioc32.c
deleted file mode 100644
index cdeb1db87222..000000000000
--- a/drivers/gpu/drm/r128/r128_ioc32.c
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * \file r128_ioc32.c
- *
- * 32-bit ioctl compatibility routines for the R128 DRM.
- *
- * \author Dave Airlie <airlied@linux.ie> with code from patches by Egbert Eich
- *
- * Copyright (C) Paul Mackerras 2005
- * Copyright (C) Egbert Eich 2003,2004
- * Copyright (C) Dave Airlie 2005
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software 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 (including the next
- * paragraph) 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 AUTHOR 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.
- */
-
-#include <linux/compat.h>
-
-#include <drm/r128_drm.h>
-
-#include "r128_drv.h"
-
-typedef struct drm_r128_init32 {
- int func;
- unsigned int sarea_priv_offset;
- int is_pci;
- int cce_mode;
- int cce_secure;
- int ring_size;
- int usec_timeout;
-
- unsigned int fb_bpp;
- unsigned int front_offset, front_pitch;
- unsigned int back_offset, back_pitch;
- unsigned int depth_bpp;
- unsigned int depth_offset, depth_pitch;
- unsigned int span_offset;
-
- unsigned int fb_offset;
- unsigned int mmio_offset;
- unsigned int ring_offset;
- unsigned int ring_rptr_offset;
- unsigned int buffers_offset;
- unsigned int agp_textures_offset;
-} drm_r128_init32_t;
-
-static int compat_r128_init(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- drm_r128_init32_t init32;
- drm_r128_init_t init;
-
- if (copy_from_user(&init32, (void __user *)arg, sizeof(init32)))
- return -EFAULT;
-
- init.func = init32.func;
- init.sarea_priv_offset = init32.sarea_priv_offset;
- init.is_pci = init32.is_pci;
- init.cce_mode = init32.cce_mode;
- init.cce_secure = init32.cce_secure;
- init.ring_size = init32.ring_size;
- init.usec_timeout = init32.usec_timeout;
- init.fb_bpp = init32.fb_bpp;
- init.front_offset = init32.front_offset;
- init.front_pitch = init32.front_pitch;
- init.back_offset = init32.back_offset;
- init.back_pitch = init32.back_pitch;
- init.depth_bpp = init32.depth_bpp;
- init.depth_offset = init32.depth_offset;
- init.depth_pitch = init32.depth_pitch;
- init.span_offset = init32.span_offset;
- init.fb_offset = init32.fb_offset;
- init.mmio_offset = init32.mmio_offset;
- init.ring_offset = init32.ring_offset;
- init.ring_rptr_offset = init32.ring_rptr_offset;
- init.buffers_offset = init32.buffers_offset;
- init.agp_textures_offset = init32.agp_textures_offset;
-
- return drm_ioctl_kernel(file, r128_cce_init, &init,
- DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY);
-}
-
-typedef struct drm_r128_depth32 {
- int func;
- int n;
- u32 x;
- u32 y;
- u32 buffer;
- u32 mask;
-} drm_r128_depth32_t;
-
-static int compat_r128_depth(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- drm_r128_depth32_t depth32;
- drm_r128_depth_t depth;
-
- if (copy_from_user(&depth32, (void __user *)arg, sizeof(depth32)))
- return -EFAULT;
-
- depth.func = depth32.func;
- depth.n = depth32.n;
- depth.x = compat_ptr(depth32.x);
- depth.y = compat_ptr(depth32.y);
- depth.buffer = compat_ptr(depth32.buffer);
- depth.mask = compat_ptr(depth32.mask);
-
- return drm_ioctl_kernel(file, r128_cce_depth, &depth, DRM_AUTH);
-}
-
-typedef struct drm_r128_stipple32 {
- u32 mask;
-} drm_r128_stipple32_t;
-
-static int compat_r128_stipple(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- drm_r128_stipple32_t stipple32;
- drm_r128_stipple_t stipple;
-
- if (copy_from_user(&stipple32, (void __user *)arg, sizeof(stipple32)))
- return -EFAULT;
-
- stipple.mask = compat_ptr(stipple32.mask);
-
- return drm_ioctl_kernel(file, r128_cce_stipple, &stipple, DRM_AUTH);
-}
-
-typedef struct drm_r128_getparam32 {
- int param;
- u32 value;
-} drm_r128_getparam32_t;
-
-static int compat_r128_getparam(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- drm_r128_getparam32_t getparam32;
- drm_r128_getparam_t getparam;
-
- if (copy_from_user(&getparam32, (void __user *)arg, sizeof(getparam32)))
- return -EFAULT;
-
- getparam.param = getparam32.param;
- getparam.value = compat_ptr(getparam32.value);
-
- return drm_ioctl_kernel(file, r128_getparam, &getparam, DRM_AUTH);
-}
-
-drm_ioctl_compat_t *r128_compat_ioctls[] = {
- [DRM_R128_INIT] = compat_r128_init,
- [DRM_R128_DEPTH] = compat_r128_depth,
- [DRM_R128_STIPPLE] = compat_r128_stipple,
- [DRM_R128_GETPARAM] = compat_r128_getparam,
-};
-
-/**
- * r128_compat_ioctl - Called whenever a 32-bit process running under
- * a 64-bit kernel performs an ioctl on /dev/dri/card<n>.
- *
- * @filp: file pointer.
- * @cmd: command.
- * @arg: user argument.
- * return: zero on success or negative number on failure.
- */
-long r128_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
-{
- unsigned int nr = DRM_IOCTL_NR(cmd);
- drm_ioctl_compat_t *fn = NULL;
- int ret;
-
- if (nr < DRM_COMMAND_BASE)
- return drm_compat_ioctl(filp, cmd, arg);
-
- if (nr < DRM_COMMAND_BASE + ARRAY_SIZE(r128_compat_ioctls))
- fn = r128_compat_ioctls[nr - DRM_COMMAND_BASE];
-
- if (fn != NULL)
- ret = (*fn) (filp, cmd, arg);
- else
- ret = drm_ioctl(filp, cmd, arg);
-
- return ret;
-}
diff --git a/drivers/gpu/drm/r128/r128_irq.c b/drivers/gpu/drm/r128/r128_irq.c
deleted file mode 100644
index d84e9c96e20a..000000000000
--- a/drivers/gpu/drm/r128/r128_irq.c
+++ /dev/null
@@ -1,118 +0,0 @@
-/* r128_irq.c -- IRQ handling for radeon -*- linux-c -*- */
-/*
- * Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved.
- *
- * The Weather Channel (TM) funded Tungsten Graphics to develop the
- * initial release of the Radeon 8500 driver under the XFree86 license.
- * This notice must be preserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software 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 (including the next
- * paragraph) 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
- * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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.
- *
- * Authors:
- * Keith Whitwell <keith@tungstengraphics.com>
- * Eric Anholt <anholt@FreeBSD.org>
- */
-
-#include <drm/drm_device.h>
-#include <drm/drm_print.h>
-#include <drm/drm_vblank.h>
-#include <drm/r128_drm.h>
-
-#include "r128_drv.h"
-
-u32 r128_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
-{
- const drm_r128_private_t *dev_priv = dev->dev_private;
-
- if (pipe != 0)
- return 0;
-
- return atomic_read(&dev_priv->vbl_received);
-}
-
-irqreturn_t r128_driver_irq_handler(int irq, void *arg)
-{
- struct drm_device *dev = (struct drm_device *) arg;
- drm_r128_private_t *dev_priv = (drm_r128_private_t *) dev->dev_private;
- int status;
-
- status = R128_READ(R128_GEN_INT_STATUS);
-
- /* VBLANK interrupt */
- if (status & R128_CRTC_VBLANK_INT) {
- R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK);
- atomic_inc(&dev_priv->vbl_received);
- drm_handle_vblank(dev, 0);
- return IRQ_HANDLED;
- }
- return IRQ_NONE;
-}
-
-int r128_enable_vblank(struct drm_device *dev, unsigned int pipe)
-{
- drm_r128_private_t *dev_priv = dev->dev_private;
-
- if (pipe != 0) {
- DRM_ERROR("%s: bad crtc %u\n", __func__, pipe);
- return -EINVAL;
- }
-
- R128_WRITE(R128_GEN_INT_CNTL, R128_CRTC_VBLANK_INT_EN);
- return 0;
-}
-
-void r128_disable_vblank(struct drm_device *dev, unsigned int pipe)
-{
- if (pipe != 0)
- DRM_ERROR("%s: bad crtc %u\n", __func__, pipe);
-
- /*
- * FIXME: implement proper interrupt disable by using the vblank
- * counter register (if available)
- *
- * R128_WRITE(R128_GEN_INT_CNTL,
- * R128_READ(R128_GEN_INT_CNTL) & ~R128_CRTC_VBLANK_INT_EN);
- */
-}
-
-void r128_driver_irq_preinstall(struct drm_device *dev)
-{
- drm_r128_private_t *dev_priv = (drm_r128_private_t *) dev->dev_private;
-
- /* Disable *all* interrupts */
- R128_WRITE(R128_GEN_INT_CNTL, 0);
- /* Clear vblank bit if it's already high */
- R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK);
-}
-
-int r128_driver_irq_postinstall(struct drm_device *dev)
-{
- return 0;
-}
-
-void r128_driver_irq_uninstall(struct drm_device *dev)
-{
- drm_r128_private_t *dev_priv = (drm_r128_private_t *) dev->dev_private;
- if (!dev_priv)
- return;
-
- /* Disable *all* interrupts */
- R128_WRITE(R128_GEN_INT_CNTL, 0);
-}
diff --git a/drivers/gpu/drm/r128/r128_state.c b/drivers/gpu/drm/r128/r128_state.c
deleted file mode 100644
index ac13fc2a0214..000000000000
--- a/drivers/gpu/drm/r128/r128_state.c
+++ /dev/null
@@ -1,1641 +0,0 @@
-/* r128_state.c -- State support for r128 -*- linux-c -*-
- * Created: Thu Jan 27 02:53:43 2000 by gareth@valinux.com
- */
-/*
- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software 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 (including the next
- * paragraph) 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
- * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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.
- *
- * Authors:
- * Gareth Hughes <gareth@valinux.com>
- */
-
-#include <linux/pci.h>
-#include <linux/slab.h>
-#include <linux/uaccess.h>
-
-#include <drm/drm_device.h>
-#include <drm/drm_file.h>
-#include <drm/drm_print.h>
-#include <drm/r128_drm.h>
-
-#include "r128_drv.h"
-
-/* ================================================================
- * CCE hardware state programming functions
- */
-
-static void r128_emit_clip_rects(drm_r128_private_t *dev_priv,
- struct drm_clip_rect *boxes, int count)
-{
- u32 aux_sc_cntl = 0x00000000;
- RING_LOCALS;
- DRM_DEBUG("\n");
-
- BEGIN_RING((count < 3 ? count : 3) * 5 + 2);
-
- if (count >= 1) {
- OUT_RING(CCE_PACKET0(R128_AUX1_SC_LEFT, 3));
- OUT_RING(boxes[0].x1);
- OUT_RING(boxes[0].x2 - 1);
- OUT_RING(boxes[0].y1);
- OUT_RING(boxes[0].y2 - 1);
-
- aux_sc_cntl |= (R128_AUX1_SC_EN | R128_AUX1_SC_MODE_OR);
- }
- if (count >= 2) {
- OUT_RING(CCE_PACKET0(R128_AUX2_SC_LEFT, 3));
- OUT_RING(boxes[1].x1);
- OUT_RING(boxes[1].x2 - 1);
- OUT_RING(boxes[1].y1);
- OUT_RING(boxes[1].y2 - 1);
-
- aux_sc_cntl |= (R128_AUX2_SC_EN | R128_AUX2_SC_MODE_OR);
- }
- if (count >= 3) {
- OUT_RING(CCE_PACKET0(R128_AUX3_SC_LEFT, 3));
- OUT_RING(boxes[2].x1);
- OUT_RING(boxes[2].x2 - 1);
- OUT_RING(boxes[2].y1);
- OUT_RING(boxes[2].y2 - 1);
-
- aux_sc_cntl |= (R128_AUX3_SC_EN | R128_AUX3_SC_MODE_OR);
- }
-
- OUT_RING(CCE_PACKET0(R128_AUX_SC_CNTL, 0));
- OUT_RING(aux_sc_cntl);
-
- ADVANCE_RING();
-}
-
-static __inline__ void r128_emit_core(drm_r128_private_t *dev_priv)
-{
- drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_r128_context_regs_t *ctx = &sarea_priv->context_state;
- RING_LOCALS;
- DRM_DEBUG("\n");
-
- BEGIN_RING(2);
-
- OUT_RING(CCE_PACKET0(R128_SCALE_3D_CNTL, 0));
- OUT_RING(ctx->scale_3d_cntl);
-
- ADVANCE_RING();
-}
-
-static __inline__ void r128_emit_context(drm_r128_private_t *dev_priv)
-{
- drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_r128_context_regs_t *ctx = &sarea_priv->context_state;
- RING_LOCALS;
- DRM_DEBUG("\n");
-
- BEGIN_RING(13);
-
- OUT_RING(CCE_PACKET0(R128_DST_PITCH_OFFSET_C, 11));
- OUT_RING(ctx->dst_pitch_offset_c);
- OUT_RING(ctx->dp_gui_master_cntl_c);
- OUT_RING(ctx->sc_top_left_c);
- OUT_RING(ctx->sc_bottom_right_c);
- OUT_RING(ctx->z_offset_c);
- OUT_RING(ctx->z_pitch_c);
- OUT_RING(ctx->z_sten_cntl_c);
- OUT_RING(ctx->tex_cntl_c);
- OUT_RING(ctx->misc_3d_state_cntl_reg);
- OUT_RING(ctx->texture_clr_cmp_clr_c);
- OUT_RING(ctx->texture_clr_cmp_msk_c);
- OUT_RING(ctx->fog_color_c);
-
- ADVANCE_RING();
-}
-
-static __inline__ void r128_emit_setup(drm_r128_private_t *dev_priv)
-{
- drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_r128_context_regs_t *ctx = &sarea_priv->context_state;
- RING_LOCALS;
- DRM_DEBUG("\n");
-
- BEGIN_RING(3);
-
- OUT_RING(CCE_PACKET1(R128_SETUP_CNTL, R128_PM4_VC_FPU_SETUP));
- OUT_RING(ctx->setup_cntl);
- OUT_RING(ctx->pm4_vc_fpu_setup);
-
- ADVANCE_RING();
-}
-
-static __inline__ void r128_emit_masks(drm_r128_private_t *dev_priv)
-{
- drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_r128_context_regs_t *ctx = &sarea_priv->context_state;
- RING_LOCALS;
- DRM_DEBUG("\n");
-
- BEGIN_RING(5);
-
- OUT_RING(CCE_PACKET0(R128_DP_WRITE_MASK, 0));
- OUT_RING(ctx->dp_write_mask);
-
- OUT_RING(CCE_PACKET0(R128_STEN_REF_MASK_C, 1));
- OUT_RING(ctx->sten_ref_mask_c);
- OUT_RING(ctx->plane_3d_mask_c);
-
- ADVANCE_RING();
-}
-
-static __inline__ void r128_emit_window(drm_r128_private_t *dev_priv)
-{
- drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_r128_context_regs_t *ctx = &sarea_priv->context_state;
- RING_LOCALS;
- DRM_DEBUG("\n");
-
- BEGIN_RING(2);
-
- OUT_RING(CCE_PACKET0(R128_WINDOW_XY_OFFSET, 0));
- OUT_RING(ctx->window_xy_offset);
-
- ADVANCE_RING();
-}
-
-static __inline__ void r128_emit_tex0(drm_r128_private_t *dev_priv)
-{
- drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_r128_context_regs_t *ctx = &sarea_priv->context_state;
- drm_r128_texture_regs_t *tex = &sarea_priv->tex_state[0];
- int i;
- RING_LOCALS;
- DRM_DEBUG("\n");
-
- BEGIN_RING(7 + R128_MAX_TEXTURE_LEVELS);
-
- OUT_RING(CCE_PACKET0(R128_PRIM_TEX_CNTL_C,
- 2 + R128_MAX_TEXTURE_LEVELS));
- OUT_RING(tex->tex_cntl);
- OUT_RING(tex->tex_combine_cntl);
- OUT_RING(ctx->tex_size_pitch_c);
- for (i = 0; i < R128_MAX_TEXTURE_LEVELS; i++)
- OUT_RING(tex->tex_offset[i]);
-
- OUT_RING(CCE_PACKET0(R128_CONSTANT_COLOR_C, 1));
- OUT_RING(ctx->constant_color_c);
- OUT_RING(tex->tex_border_color);
-
- ADVANCE_RING();
-}
-
-static __inline__ void r128_emit_tex1(drm_r128_private_t *dev_priv)
-{
- drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_r128_texture_regs_t *tex = &sarea_priv->tex_state[1];
- int i;
- RING_LOCALS;
- DRM_DEBUG("\n");
-
- BEGIN_RING(5 + R128_MAX_TEXTURE_LEVELS);
-
- OUT_RING(CCE_PACKET0(R128_SEC_TEX_CNTL_C, 1 + R128_MAX_TEXTURE_LEVELS));
- OUT_RING(tex->tex_cntl);
- OUT_RING(tex->tex_combine_cntl);
- for (i = 0; i < R128_MAX_TEXTURE_LEVELS; i++)
- OUT_RING(tex->tex_offset[i]);
-
- OUT_RING(CCE_PACKET0(R128_SEC_TEXTURE_BORDER_COLOR_C, 0));
- OUT_RING(tex->tex_border_color);
-
- ADVANCE_RING();
-}
-
-static void r128_emit_state(drm_r128_private_t *dev_priv)
-{
- drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
- unsigned int dirty = sarea_priv->dirty;
-
- DRM_DEBUG("dirty=0x%08x\n", dirty);
-
- if (dirty & R128_UPLOAD_CORE) {
- r128_emit_core(dev_priv);
- sarea_priv->dirty &= ~R128_UPLOAD_CORE;
- }
-
- if (dirty & R128_UPLOAD_CONTEXT) {
- r128_emit_context(dev_priv);
- sarea_priv->dirty &= ~R128_UPLOAD_CONTEXT;
- }
-
- if (dirty & R128_UPLOAD_SETUP) {
- r128_emit_setup(dev_priv);
- sarea_priv->dirty &= ~R128_UPLOAD_SETUP;
- }
-
- if (dirty & R128_UPLOAD_MASKS) {
- r128_emit_masks(dev_priv);
- sarea_priv->dirty &= ~R128_UPLOAD_MASKS;
- }
-
- if (dirty & R128_UPLOAD_WINDOW) {
- r128_emit_window(dev_priv);
- sarea_priv->dirty &= ~R128_UPLOAD_WINDOW;
- }
-
- if (dirty & R128_UPLOAD_TEX0) {
- r128_emit_tex0(dev_priv);
- sarea_priv->dirty &= ~R128_UPLOAD_TEX0;
- }
-
- if (dirty & R128_UPLOAD_TEX1) {
- r128_emit_tex1(dev_priv);
- sarea_priv->dirty &= ~R128_UPLOAD_TEX1;
- }
-
- /* Turn off the texture cache flushing */
- sarea_priv->context_state.tex_cntl_c &= ~R128_TEX_CACHE_FLUSH;
-
- sarea_priv->dirty &= ~R128_REQUIRE_QUIESCENCE;
-}
-
-#if R128_PERFORMANCE_BOXES
-/* ================================================================
- * Performance monitoring functions
- */
-
-static void r128_clear_box(drm_r128_private_t *dev_priv,
- int x, int y, int w, int h, int r, int g, int b)
-{
- u32 pitch, offset;
- u32 fb_bpp, color;
- RING_LOCALS;
-
- switch (dev_priv->fb_bpp) {
- case 16:
- fb_bpp = R128_GMC_DST_16BPP;
- color = (((r & 0xf8) << 8) |
- ((g & 0xfc) << 3) | ((b & 0xf8) >> 3));
- break;
- case 24:
- fb_bpp = R128_GMC_DST_24BPP;
- color = ((r << 16) | (g << 8) | b);
- break;
- case 32:
- fb_bpp = R128_GMC_DST_32BPP;
- color = (((0xff) << 24) | (r << 16) | (g << 8) | b);
- break;
- default:
- return;
- }
-
- offset = dev_priv->back_offset;
- pitch = dev_priv->back_pitch >> 3;
-
- BEGIN_RING(6);
-
- OUT_RING(CCE_PACKET3(R128_CNTL_PAINT_MULTI, 4));
- OUT_RING(R128_GMC_DST_PITCH_OFFSET_CNTL |
- R128_GMC_BRUSH_SOLID_COLOR |
- fb_bpp |
- R128_GMC_SRC_DATATYPE_COLOR |
- R128_ROP3_P |
- R128_GMC_CLR_CMP_CNTL_DIS | R128_GMC_AUX_CLIP_DIS);
-
- OUT_RING((pitch << 21) | (offset >> 5));
- OUT_RING(color);
-
- OUT_RING((x << 16) | y);
- OUT_RING((w << 16) | h);
-
- ADVANCE_RING();
-}
-
-static void r128_cce_performance_boxes(drm_r128_private_t *dev_priv)
-{
- if (atomic_read(&dev_priv->idle_count) == 0)
- r128_clear_box(dev_priv, 64, 4, 8, 8, 0, 255, 0);
- else
- atomic_set(&dev_priv->idle_count, 0);
-}
-
-#endif
-
-/* ================================================================
- * CCE command dispatch functions
- */
-
-static void r128_print_dirty(const char *msg, unsigned int flags)
-{
- DRM_INFO("%s: (0x%x) %s%s%s%s%s%s%s%s%s\n",
- msg,
- flags,
- (flags & R128_UPLOAD_CORE) ? "core, " : "",
- (flags & R128_UPLOAD_CONTEXT) ? "context, " : "",
- (flags & R128_UPLOAD_SETUP) ? "setup, " : "",
- (flags & R128_UPLOAD_TEX0) ? "tex0, " : "",
- (flags & R128_UPLOAD_TEX1) ? "tex1, " : "",
- (flags & R128_UPLOAD_MASKS) ? "masks, " : "",
- (flags & R128_UPLOAD_WINDOW) ? "window, " : "",
- (flags & R128_UPLOAD_CLIPRECTS) ? "cliprects, " : "",
- (flags & R128_REQUIRE_QUIESCENCE) ? "quiescence, " : "");
-}
-
-static void r128_cce_dispatch_clear(struct drm_device *dev,
- drm_r128_clear_t *clear)
-{
- drm_r128_private_t *dev_priv = dev->dev_private;
- drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
- int nbox = sarea_priv->nbox;
- struct drm_clip_rect *pbox = sarea_priv->boxes;
- unsigned int flags = clear->flags;
- int i;
- RING_LOCALS;
- DRM_DEBUG("\n");
-
- if (dev_priv->page_flipping && dev_priv->current_page == 1) {
- unsigned int tmp = flags;
-
- flags &= ~(R128_FRONT | R128_BACK);
- if (tmp & R128_FRONT)
- flags |= R128_BACK;
- if (tmp & R128_BACK)
- flags |= R128_FRONT;
- }
-
- for (i = 0; i < nbox; i++) {
- int x = pbox[i].x1;
- int y = pbox[i].y1;
- int w = pbox[i].x2 - x;
- int h = pbox[i].y2 - y;
-
- DRM_DEBUG("dispatch clear %d,%d-%d,%d flags 0x%x\n",
- pbox[i].x1, pbox[i].y1, pbox[i].x2,
- pbox[i].y2, flags);
-
- if (flags & (R128_FRONT | R128_BACK)) {
- BEGIN_RING(2);
-
- OUT_RING(CCE_PACKET0(R128_DP_WRITE_MASK, 0));
- OUT_RING(clear->color_mask);
-
- ADVANCE_RING();
- }
-
- if (flags & R128_FRONT) {
- BEGIN_RING(6);
-
- OUT_RING(CCE_PACKET3(R128_CNTL_PAINT_MULTI, 4));
- OUT_RING(R128_GMC_DST_PITCH_OFFSET_CNTL |
- R128_GMC_BRUSH_SOLID_COLOR |
- (dev_priv->color_fmt << 8) |
- R128_GMC_SRC_DATATYPE_COLOR |
- R128_ROP3_P |
- R128_GMC_CLR_CMP_CNTL_DIS |
- R128_GMC_AUX_CLIP_DIS);
-
- OUT_RING(dev_priv->front_pitch_offset_c);
- OUT_RING(clear->clear_color);
-
- OUT_RING((x << 16) | y);
- OUT_RING((w << 16) | h);
-
- ADVANCE_RING();
- }
-
- if (flags & R128_BACK) {
- BEGIN_RING(6);
-
- OUT_RING(CCE_PACKET3(R128_CNTL_PAINT_MULTI, 4));
- OUT_RING(R128_GMC_DST_PITCH_OFFSET_CNTL |
- R128_GMC_BRUSH_SOLID_COLOR |
- (dev_priv->color_fmt << 8) |
- R128_GMC_SRC_DATATYPE_COLOR |
- R128_ROP3_P |
- R128_GMC_CLR_CMP_CNTL_DIS |
- R128_GMC_AUX_CLIP_DIS);
-
- OUT_RING(dev_priv->back_pitch_offset_c);
- OUT_RING(clear->clear_color);
-
- OUT_RING((x << 16) | y);
- OUT_RING((w << 16) | h);
-
- ADVANCE_RING();
- }
-
- if (flags & R128_DEPTH) {
- BEGIN_RING(6);
-
- OUT_RING(CCE_PACKET3(R128_CNTL_PAINT_MULTI, 4));
- OUT_RING(R128_GMC_DST_PITCH_OFFSET_CNTL |
- R128_GMC_BRUSH_SOLID_COLOR |
- (dev_priv->depth_fmt << 8) |
- R128_GMC_SRC_DATATYPE_COLOR |
- R128_ROP3_P |
- R128_GMC_CLR_CMP_CNTL_DIS |
- R128_GMC_AUX_CLIP_DIS | R128_GMC_WR_MSK_DIS);
-
- OUT_RING(dev_priv->depth_pitch_offset_c);
- OUT_RING(clear->clear_depth);
-
- OUT_RING((x << 16) | y);
- OUT_RING((w << 16) | h);
-
- ADVANCE_RING();
- }
- }
-}
-
-static void r128_cce_dispatch_swap(struct drm_device *dev)
-{
- drm_r128_private_t *dev_priv = dev->dev_private;
- drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
- int nbox = sarea_priv->nbox;
- struct drm_clip_rect *pbox = sarea_priv->boxes;
- int i;
- RING_LOCALS;
- DRM_DEBUG("\n");
-
-#if R128_PERFORMANCE_BOXES
- /* Do some trivial performance monitoring...
- */
- r128_cce_performance_boxes(dev_priv);
-#endif
-
- for (i = 0; i < nbox; i++) {
- int x = pbox[i].x1;
- int y = pbox[i].y1;
- int w = pbox[i].x2 - x;
- int h = pbox[i].y2 - y;
-
- BEGIN_RING(7);
-
- OUT_RING(CCE_PACKET3(R128_CNTL_BITBLT_MULTI, 5));
- OUT_RING(R128_GMC_SRC_PITCH_OFFSET_CNTL |
- R128_GMC_DST_PITCH_OFFSET_CNTL |
- R128_GMC_BRUSH_NONE |
- (dev_priv->color_fmt << 8) |
- R128_GMC_SRC_DATATYPE_COLOR |
- R128_ROP3_S |
- R128_DP_SRC_SOURCE_MEMORY |
- R128_GMC_CLR_CMP_CNTL_DIS |
- R128_GMC_AUX_CLIP_DIS | R128_GMC_WR_MSK_DIS);
-
- /* Make this work even if front & back are flipped:
- */
- if (dev_priv->current_page == 0) {
- OUT_RING(dev_priv->back_pitch_offset_c);
- OUT_RING(dev_priv->front_pitch_offset_c);
- } else {
- OUT_RING(dev_priv->front_pitch_offset_c);
- OUT_RING(dev_priv->back_pitch_offset_c);
- }
-
- OUT_RING((x << 16) | y);
- OUT_RING((x << 16) | y);
- OUT_RING((w << 16) | h);
-
- ADVANCE_RING();
- }
-
- /* Increment the frame counter. The client-side 3D driver must
- * throttle the framerate by waiting for this value before
- * performing the swapbuffer ioctl.
- */
- dev_priv->sarea_priv->last_frame++;
-
- BEGIN_RING(2);
-
- OUT_RING(CCE_PACKET0(R128_LAST_FRAME_REG, 0));
- OUT_RING(dev_priv->sarea_priv->last_frame);
-
- ADVANCE_RING();
-}
-
-static void r128_cce_dispatch_flip(struct drm_device *dev)
-{
- drm_r128_private_t *dev_priv = dev->dev_private;
- RING_LOCALS;
- DRM_DEBUG("page=%d pfCurrentPage=%d\n",
- dev_priv->current_page, dev_priv->sarea_priv->pfCurrentPage);
-
-#if R128_PERFORMANCE_BOXES
- /* Do some trivial performance monitoring...
- */
- r128_cce_performance_boxes(dev_priv);
-#endif
-
- BEGIN_RING(4);
-
- R128_WAIT_UNTIL_PAGE_FLIPPED();
- OUT_RING(CCE_PACKET0(R128_CRTC_OFFSET, 0));
-
- if (dev_priv->current_page == 0)
- OUT_RING(dev_priv->back_offset);
- else
- OUT_RING(dev_priv->front_offset);
-
- ADVANCE_RING();
-
- /* Increment the frame counter. The client-side 3D driver must
- * throttle the framerate by waiting for this value before
- * performing the swapbuffer ioctl.
- */
- dev_priv->sarea_priv->last_frame++;
- dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page =
- 1 - dev_priv->current_page;
-
- BEGIN_RING(2);
-
- OUT_RING(CCE_PACKET0(R128_LAST_FRAME_REG, 0));
- OUT_RING(dev_priv->sarea_priv->last_frame);
-
- ADVANCE_RING();
-}
-
-static void r128_cce_dispatch_vertex(struct drm_device *dev, struct drm_buf *buf)
-{
- drm_r128_private_t *dev_priv = dev->dev_private;
- drm_r128_buf_priv_t *buf_priv = buf->dev_private;
- drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
- int format = sarea_priv->vc_format;
- int offset = buf->bus_address;
- int size = buf->used;
- int prim = buf_priv->prim;
- int i = 0;
- RING_LOCALS;
- DRM_DEBUG("buf=%d nbox=%d\n", buf->idx, sarea_priv->nbox);
-
- if (0)
- r128_print_dirty("dispatch_vertex", sarea_priv->dirty);
-
- if (buf->used) {
- buf_priv->dispatched = 1;
-
- if (sarea_priv->dirty & ~R128_UPLOAD_CLIPRECTS)
- r128_emit_state(dev_priv);
-
- do {
- /* Emit the next set of up to three cliprects */
- if (i < sarea_priv->nbox) {
- r128_emit_clip_rects(dev_priv,
- &sarea_priv->boxes[i],
- sarea_priv->nbox - i);
- }
-
- /* Emit the vertex buffer rendering commands */
- BEGIN_RING(5);
-
- OUT_RING(CCE_PACKET3(R128_3D_RNDR_GEN_INDX_PRIM, 3));
- OUT_RING(offset);
- OUT_RING(size);
- OUT_RING(format);
- OUT_RING(prim | R128_CCE_VC_CNTL_PRIM_WALK_LIST |
- (size << R128_CCE_VC_CNTL_NUM_SHIFT));
-
- ADVANCE_RING();
-
- i += 3;
- } while (i < sarea_priv->nbox);
- }
-
- if (buf_priv->discard) {
- buf_priv->age = dev_priv->sarea_priv->last_dispatch;
-
- /* Emit the vertex buffer age */
- BEGIN_RING(2);
-
- OUT_RING(CCE_PACKET0(R128_LAST_DISPATCH_REG, 0));
- OUT_RING(buf_priv->age);
-
- ADVANCE_RING();
-
- buf->pending = 1;
- buf->used = 0;
- /* FIXME: Check dispatched field */
- buf_priv->dispatched = 0;
- }
-
- dev_priv->sarea_priv->last_dispatch++;
-
- sarea_priv->dirty &= ~R128_UPLOAD_CLIPRECTS;
- sarea_priv->nbox = 0;
-}
-
-static void r128_cce_dispatch_indirect(struct drm_device *dev,
- struct drm_buf *buf, int start, int end)
-{
- drm_r128_private_t *dev_priv = dev->dev_private;
- drm_r128_buf_priv_t *buf_priv = buf->dev_private;
- RING_LOCALS;
- DRM_DEBUG("indirect: buf=%d s=0x%x e=0x%x\n", buf->idx, start, end);
-
- if (start != end) {
- int offset = buf->bus_address + start;
- int dwords = (end - start + 3) / sizeof(u32);
-
- /* Indirect buffer data must be an even number of
- * dwords, so if we've been given an odd number we must
- * pad the data with a Type-2 CCE packet.
- */
- if (dwords & 1) {
- u32 *data = (u32 *)
- ((char *)dev->agp_buffer_map->handle
- + buf->offset + start);
- data[dwords++] = cpu_to_le32(R128_CCE_PACKET2);
- }
-
- buf_priv->dispatched = 1;
-
- /* Fire off the indirect buffer */
- BEGIN_RING(3);
-
- OUT_RING(CCE_PACKET0(R128_PM4_IW_INDOFF, 1));
- OUT_RING(offset);
- OUT_RING(dwords);
-
- ADVANCE_RING();
- }
-
- if (buf_priv->discard) {
- buf_priv->age = dev_priv->sarea_priv->last_dispatch;
-
- /* Emit the indirect buffer age */
- BEGIN_RING(2);
-
- OUT_RING(CCE_PACKET0(R128_LAST_DISPATCH_REG, 0));
- OUT_RING(buf_priv->age);
-
- ADVANCE_RING();
-
- buf->pending = 1;
- buf->used = 0;
- /* FIXME: Check dispatched field */
- buf_priv->dispatched = 0;
- }
-
- dev_priv->sarea_priv->last_dispatch++;
-}
-
-static void r128_cce_dispatch_indices(struct drm_device *dev,
- struct drm_buf *buf,
- int start, int end, int count)
-{
- drm_r128_private_t *dev_priv = dev->dev_private;
- drm_r128_buf_priv_t *buf_priv = buf->dev_private;
- drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
- int format = sarea_priv->vc_format;
- int offset = dev->agp_buffer_map->offset - dev_priv->cce_buffers_offset;
- int prim = buf_priv->prim;
- u32 *data;
- int dwords;
- int i = 0;
- RING_LOCALS;
- DRM_DEBUG("indices: s=%d e=%d c=%d\n", start, end, count);
-
- if (0)
- r128_print_dirty("dispatch_indices", sarea_priv->dirty);
-
- if (start != end) {
- buf_priv->dispatched = 1;
-
- if (sarea_priv->dirty & ~R128_UPLOAD_CLIPRECTS)
- r128_emit_state(dev_priv);
-
- dwords = (end - start + 3) / sizeof(u32);
-
- data = (u32 *) ((char *)dev->agp_buffer_map->handle
- + buf->offset + start);
-
- data[0] = cpu_to_le32(CCE_PACKET3(R128_3D_RNDR_GEN_INDX_PRIM,
- dwords - 2));
-
- data[1] = cpu_to_le32(offset);
- data[2] = cpu_to_le32(R128_MAX_VB_VERTS);
- data[3] = cpu_to_le32(format);
- data[4] = cpu_to_le32((prim | R128_CCE_VC_CNTL_PRIM_WALK_IND |
- (count << 16)));
-
- if (count & 0x1) {
-#ifdef __LITTLE_ENDIAN
- data[dwords - 1] &= 0x0000ffff;
-#else
- data[dwords - 1] &= 0xffff0000;
-#endif
- }
-
- do {
- /* Emit the next set of up to three cliprects */
- if (i < sarea_priv->nbox) {
- r128_emit_clip_rects(dev_priv,
- &sarea_priv->boxes[i],
- sarea_priv->nbox - i);
- }
-
- r128_cce_dispatch_indirect(dev, buf, start, end);
-
- i += 3;
- } while (i < sarea_priv->nbox);
- }
-
- if (buf_priv->discard) {
- buf_priv->age = dev_priv->sarea_priv->last_dispatch;
-
- /* Emit the vertex buffer age */
- BEGIN_RING(2);
-
- OUT_RING(CCE_PACKET0(R128_LAST_DISPATCH_REG, 0));
- OUT_RING(buf_priv->age);
-
- ADVANCE_RING();
-
- buf->pending = 1;
- /* FIXME: Check dispatched field */
- buf_priv->dispatched = 0;
- }
-
- dev_priv->sarea_priv->last_dispatch++;
-
- sarea_priv->dirty &= ~R128_UPLOAD_CLIPRECTS;
- sarea_priv->nbox = 0;
-}
-
-static int r128_cce_dispatch_blit(struct drm_device *dev,
- struct drm_file *file_priv,
- drm_r128_blit_t *blit)
-{
- drm_r128_private_t *dev_priv = dev->dev_private;
- struct drm_device_dma *dma = dev->dma;
- struct drm_buf *buf;
- drm_r128_buf_priv_t *buf_priv;
- u32 *data;
- int dword_shift, dwords;
- RING_LOCALS;
- DRM_DEBUG("\n");
-
- /* The compiler won't optimize away a division by a variable,
- * even if the only legal values are powers of two. Thus, we'll
- * use a shift instead.
- */
- switch (blit->format) {
- case R128_DATATYPE_ARGB8888:
- dword_shift = 0;
- break;
- case R128_DATATYPE_ARGB1555:
- case R128_DATATYPE_RGB565:
- case R128_DATATYPE_ARGB4444:
- case R128_DATATYPE_YVYU422:
- case R128_DATATYPE_VYUY422:
- dword_shift = 1;
- break;
- case R128_DATATYPE_CI8:
- case R128_DATATYPE_RGB8:
- dword_shift = 2;
- break;
- default:
- DRM_ERROR("invalid blit format %d\n", blit->format);
- return -EINVAL;
- }
-
- /* Flush the pixel cache, and mark the contents as Read Invalid.
- * This ensures no pixel data gets mixed up with the texture
- * data from the host data blit, otherwise part of the texture
- * image may be corrupted.
- */
- BEGIN_RING(2);
-
- OUT_RING(CCE_PACKET0(R128_PC_GUI_CTLSTAT, 0));
- OUT_RING(R128_PC_RI_GUI | R128_PC_FLUSH_GUI);
-
- ADVANCE_RING();
-
- /* Dispatch the indirect buffer.
- */
- buf = dma->buflist[blit->idx];
- buf_priv = buf->dev_private;
-
- if (buf->file_priv != file_priv) {
- DRM_ERROR("process %d using buffer owned by %p\n",
- task_pid_nr(current), buf->file_priv);
- return -EINVAL;
- }
- if (buf->pending) {
- DRM_ERROR("sending pending buffer %d\n", blit->idx);
- return -EINVAL;
- }
-
- buf_priv->discard = 1;
-
- dwords = (blit->width * blit->height) >> dword_shift;
-
- data = (u32 *) ((char *)dev->agp_buffer_map->handle + buf->offset);
-
- data[0] = cpu_to_le32(CCE_PACKET3(R128_CNTL_HOSTDATA_BLT, dwords + 6));
- data[1] = cpu_to_le32((R128_GMC_DST_PITCH_OFFSET_CNTL |
- R128_GMC_BRUSH_NONE |
- (blit->format << 8) |
- R128_GMC_SRC_DATATYPE_COLOR |
- R128_ROP3_S |
- R128_DP_SRC_SOURCE_HOST_DATA |
- R128_GMC_CLR_CMP_CNTL_DIS |
- R128_GMC_AUX_CLIP_DIS | R128_GMC_WR_MSK_DIS));
-
- data[2] = cpu_to_le32((blit->pitch << 21) | (blit->offset >> 5));
- data[3] = cpu_to_le32(0xffffffff);
- data[4] = cpu_to_le32(0xffffffff);
- data[5] = cpu_to_le32((blit->y << 16) | blit->x);
- data[6] = cpu_to_le32((blit->height << 16) | blit->width);
- data[7] = cpu_to_le32(dwords);
-
- buf->used = (dwords + 8) * sizeof(u32);
-
- r128_cce_dispatch_indirect(dev, buf, 0, buf->used);
-
- /* Flush the pixel cache after the blit completes. This ensures
- * the texture data is written out to memory before rendering
- * continues.
- */
- BEGIN_RING(2);
-
- OUT_RING(CCE_PACKET0(R128_PC_GUI_CTLSTAT, 0));
- OUT_RING(R128_PC_FLUSH_GUI);
-
- ADVANCE_RING();
-
- return 0;
-}
-
-/* ================================================================
- * Tiled depth buffer management
- *
- * FIXME: These should all set the destination write mask for when we
- * have hardware stencil support.
- */
-
-static int r128_cce_dispatch_write_span(struct drm_device *dev,
- drm_r128_depth_t *depth)
-{
- drm_r128_private_t *dev_priv = dev->dev_private;
- int count, x, y;
- u32 *buffer;
- u8 *mask;
- int i, buffer_size, mask_size;
- RING_LOCALS;
- DRM_DEBUG("\n");
-
- count = depth->n;
- if (count > 4096 || count <= 0)
- return -EMSGSIZE;
-
- if (copy_from_user(&x, depth->x, sizeof(x)))
- return -EFAULT;
- if (copy_from_user(&y, depth->y, sizeof(y)))
- return -EFAULT;
-
- buffer_size = depth->n * sizeof(u32);
- buffer = memdup_user(depth->buffer, buffer_size);
- if (IS_ERR(buffer))
- return PTR_ERR(buffer);
-
- mask_size = depth->n;
- if (depth->mask) {
- mask = memdup_user(depth->mask, mask_size);
- if (IS_ERR(mask)) {
- kfree(buffer);
- return PTR_ERR(mask);
- }
-
- for (i = 0; i < count; i++, x++) {
- if (mask[i]) {
- BEGIN_RING(6);
-
- OUT_RING(CCE_PACKET3(R128_CNTL_PAINT_MULTI, 4));
- OUT_RING(R128_GMC_DST_PITCH_OFFSET_CNTL |
- R128_GMC_BRUSH_SOLID_COLOR |
- (dev_priv->depth_fmt << 8) |
- R128_GMC_SRC_DATATYPE_COLOR |
- R128_ROP3_P |
- R128_GMC_CLR_CMP_CNTL_DIS |
- R128_GMC_WR_MSK_DIS);
-
- OUT_RING(dev_priv->depth_pitch_offset_c);
- OUT_RING(buffer[i]);
-
- OUT_RING((x << 16) | y);
- OUT_RING((1 << 16) | 1);
-
- ADVANCE_RING();
- }
- }
-
- kfree(mask);
- } else {
- for (i = 0; i < count; i++, x++) {
- BEGIN_RING(6);
-
- OUT_RING(CCE_PACKET3(R128_CNTL_PAINT_MULTI, 4));
- OUT_RING(R128_GMC_DST_PITCH_OFFSET_CNTL |
- R128_GMC_BRUSH_SOLID_COLOR |
- (dev_priv->depth_fmt << 8) |
- R128_GMC_SRC_DATATYPE_COLOR |
- R128_ROP3_P |
- R128_GMC_CLR_CMP_CNTL_DIS |
- R128_GMC_WR_MSK_DIS);
-
- OUT_RING(dev_priv->depth_pitch_offset_c);
- OUT_RING(buffer[i]);
-
- OUT_RING((x << 16) | y);
- OUT_RING((1 << 16) | 1);
-
- ADVANCE_RING();
- }
- }
-
- kfree(buffer);
-
- return 0;
-}
-
-static int r128_cce_dispatch_write_pixels(struct drm_device *dev,
- drm_r128_depth_t *depth)
-{
- drm_r128_private_t *dev_priv = dev->dev_private;
- int count, *x, *y;
- u32 *buffer;
- u8 *mask;
- int i, xbuf_size, ybuf_size, buffer_size, mask_size;
- RING_LOCALS;
- DRM_DEBUG("\n");
-
- count = depth->n;
- if (count > 4096 || count <= 0)
- return -EMSGSIZE;
-
- xbuf_size = count * sizeof(*x);
- ybuf_size = count * sizeof(*y);
- x = memdup_user(depth->x, xbuf_size);
- if (IS_ERR(x))
- return PTR_ERR(x);
- y = memdup_user(depth->y, ybuf_size);
- if (IS_ERR(y)) {
- kfree(x);
- return PTR_ERR(y);
- }
- buffer_size = depth->n * sizeof(u32);
- buffer = memdup_user(depth->buffer, buffer_size);
- if (IS_ERR(buffer)) {
- kfree(x);
- kfree(y);
- return PTR_ERR(buffer);
- }
-
- if (depth->mask) {
- mask_size = depth->n;
- mask = memdup_user(depth->mask, mask_size);
- if (IS_ERR(mask)) {
- kfree(x);
- kfree(y);
- kfree(buffer);
- return PTR_ERR(mask);
- }
-
- for (i = 0; i < count; i++) {
- if (mask[i]) {
- BEGIN_RING(6);
-
- OUT_RING(CCE_PACKET3(R128_CNTL_PAINT_MULTI, 4));
- OUT_RING(R128_GMC_DST_PITCH_OFFSET_CNTL |
- R128_GMC_BRUSH_SOLID_COLOR |
- (dev_priv->depth_fmt << 8) |
- R128_GMC_SRC_DATATYPE_COLOR |
- R128_ROP3_P |
- R128_GMC_CLR_CMP_CNTL_DIS |
- R128_GMC_WR_MSK_DIS);
-
- OUT_RING(dev_priv->depth_pitch_offset_c);
- OUT_RING(buffer[i]);
-
- OUT_RING((x[i] << 16) | y[i]);
- OUT_RING((1 << 16) | 1);
-
- ADVANCE_RING();
- }
- }
-
- kfree(mask);
- } else {
- for (i = 0; i < count; i++) {
- BEGIN_RING(6);
-
- OUT_RING(CCE_PACKET3(R128_CNTL_PAINT_MULTI, 4));
- OUT_RING(R128_GMC_DST_PITCH_OFFSET_CNTL |
- R128_GMC_BRUSH_SOLID_COLOR |
- (dev_priv->depth_fmt << 8) |
- R128_GMC_SRC_DATATYPE_COLOR |
- R128_ROP3_P |
- R128_GMC_CLR_CMP_CNTL_DIS |
- R128_GMC_WR_MSK_DIS);
-
- OUT_RING(dev_priv->depth_pitch_offset_c);
- OUT_RING(buffer[i]);
-
- OUT_RING((x[i] << 16) | y[i]);
- OUT_RING((1 << 16) | 1);
-
- ADVANCE_RING();
- }
- }
-
- kfree(x);
- kfree(y);
- kfree(buffer);
-
- return 0;
-}
-
-static int r128_cce_dispatch_read_span(struct drm_device *dev,
- drm_r128_depth_t *depth)
-{
- drm_r128_private_t *dev_priv = dev->dev_private;
- int count, x, y;
- RING_LOCALS;
- DRM_DEBUG("\n");
-
- count = depth->n;
- if (count > 4096 || count <= 0)
- return -EMSGSIZE;
-
- if (copy_from_user(&x, depth->x, sizeof(x)))
- return -EFAULT;
- if (copy_from_user(&y, depth->y, sizeof(y)))
- return -EFAULT;
-
- BEGIN_RING(7);
-
- OUT_RING(CCE_PACKET3(R128_CNTL_BITBLT_MULTI, 5));
- OUT_RING(R128_GMC_SRC_PITCH_OFFSET_CNTL |
- R128_GMC_DST_PITCH_OFFSET_CNTL |
- R128_GMC_BRUSH_NONE |
- (dev_priv->depth_fmt << 8) |
- R128_GMC_SRC_DATATYPE_COLOR |
- R128_ROP3_S |
- R128_DP_SRC_SOURCE_MEMORY |
- R128_GMC_CLR_CMP_CNTL_DIS | R128_GMC_WR_MSK_DIS);
-
- OUT_RING(dev_priv->depth_pitch_offset_c);
- OUT_RING(dev_priv->span_pitch_offset_c);
-
- OUT_RING((x << 16) | y);
- OUT_RING((0 << 16) | 0);
- OUT_RING((count << 16) | 1);
-
- ADVANCE_RING();
-
- return 0;
-}
-
-static int r128_cce_dispatch_read_pixels(struct drm_device *dev,
- drm_r128_depth_t *depth)
-{
- drm_r128_private_t *dev_priv = dev->dev_private;
- int count, *x, *y;
- int i, xbuf_size, ybuf_size;
- RING_LOCALS;
- DRM_DEBUG("\n");
-
- count = depth->n;
- if (count > 4096 || count <= 0)
- return -EMSGSIZE;
-
- if (count > dev_priv->depth_pitch)
- count = dev_priv->depth_pitch;
-
- xbuf_size = count * sizeof(*x);
- ybuf_size = count * sizeof(*y);
- x = kmalloc(xbuf_size, GFP_KERNEL);
- if (x == NULL)
- return -ENOMEM;
- y = kmalloc(ybuf_size, GFP_KERNEL);
- if (y == NULL) {
- kfree(x);
- return -ENOMEM;
- }
- if (copy_from_user(x, depth->x, xbuf_size)) {
- kfree(x);
- kfree(y);
- return -EFAULT;
- }
- if (copy_from_user(y, depth->y, ybuf_size)) {
- kfree(x);
- kfree(y);
- return -EFAULT;
- }
-
- for (i = 0; i < count; i++) {
- BEGIN_RING(7);
-
- OUT_RING(CCE_PACKET3(R128_CNTL_BITBLT_MULTI, 5));
- OUT_RING(R128_GMC_SRC_PITCH_OFFSET_CNTL |
- R128_GMC_DST_PITCH_OFFSET_CNTL |
- R128_GMC_BRUSH_NONE |
- (dev_priv->depth_fmt << 8) |
- R128_GMC_SRC_DATATYPE_COLOR |
- R128_ROP3_S |
- R128_DP_SRC_SOURCE_MEMORY |
- R128_GMC_CLR_CMP_CNTL_DIS | R128_GMC_WR_MSK_DIS);
-
- OUT_RING(dev_priv->depth_pitch_offset_c);
- OUT_RING(dev_priv->span_pitch_offset_c);
-
- OUT_RING((x[i] << 16) | y[i]);
- OUT_RING((i << 16) | 0);
- OUT_RING((1 << 16) | 1);
-
- ADVANCE_RING();
- }
-
- kfree(x);
- kfree(y);
-
- return 0;
-}
-
-/* ================================================================
- * Polygon stipple
- */
-
-static void r128_cce_dispatch_stipple(struct drm_device *dev, u32 *stipple)
-{
- drm_r128_private_t *dev_priv = dev->dev_private;
- int i;
- RING_LOCALS;
- DRM_DEBUG("\n");
-
- BEGIN_RING(33);
-
- OUT_RING(CCE_PACKET0(R128_BRUSH_DATA0, 31));
- for (i = 0; i < 32; i++)
- OUT_RING(stipple[i]);
-
- ADVANCE_RING();
-}
-
-/* ================================================================
- * IOCTL functions
- */
-
-static int r128_cce_clear(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_r128_private_t *dev_priv = dev->dev_private;
- drm_r128_sarea_t *sarea_priv;
- drm_r128_clear_t *clear = data;
- DRM_DEBUG("\n");
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- DEV_INIT_TEST_WITH_RETURN(dev_priv);
-
- RING_SPACE_TEST_WITH_RETURN(dev_priv);
-
- sarea_priv = dev_priv->sarea_priv;
-
- if (sarea_priv->nbox > R128_NR_SAREA_CLIPRECTS)
- sarea_priv->nbox = R128_NR_SAREA_CLIPRECTS;
-
- r128_cce_dispatch_clear(dev, clear);
- COMMIT_RING();
-
- /* Make sure we restore the 3D state next time.
- */
- dev_priv->sarea_priv->dirty |= R128_UPLOAD_CONTEXT | R128_UPLOAD_MASKS;
-
- return 0;
-}
-
-static int r128_do_init_pageflip(struct drm_device *dev)
-{
- drm_r128_private_t *dev_priv = dev->dev_private;
- DRM_DEBUG("\n");
-
- dev_priv->crtc_offset = R128_READ(R128_CRTC_OFFSET);
- dev_priv->crtc_offset_cntl = R128_READ(R128_CRTC_OFFSET_CNTL);
-
- R128_WRITE(R128_CRTC_OFFSET, dev_priv->front_offset);
- R128_WRITE(R128_CRTC_OFFSET_CNTL,
- dev_priv->crtc_offset_cntl | R128_CRTC_OFFSET_FLIP_CNTL);
-
- dev_priv->page_flipping = 1;
- dev_priv->current_page = 0;
- dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page;
-
- return 0;
-}
-
-static int r128_do_cleanup_pageflip(struct drm_device *dev)
-{
- drm_r128_private_t *dev_priv = dev->dev_private;
- DRM_DEBUG("\n");
-
- R128_WRITE(R128_CRTC_OFFSET, dev_priv->crtc_offset);
- R128_WRITE(R128_CRTC_OFFSET_CNTL, dev_priv->crtc_offset_cntl);
-
- if (dev_priv->current_page != 0) {
- r128_cce_dispatch_flip(dev);
- COMMIT_RING();
- }
-
- dev_priv->page_flipping = 0;
- return 0;
-}
-
-/* Swapping and flipping are different operations, need different ioctls.
- * They can & should be intermixed to support multiple 3d windows.
- */
-
-static int r128_cce_flip(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_r128_private_t *dev_priv = dev->dev_private;
- DRM_DEBUG("\n");
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- DEV_INIT_TEST_WITH_RETURN(dev_priv);
-
- RING_SPACE_TEST_WITH_RETURN(dev_priv);
-
- if (!dev_priv->page_flipping)
- r128_do_init_pageflip(dev);
-
- r128_cce_dispatch_flip(dev);
-
- COMMIT_RING();
- return 0;
-}
-
-static int r128_cce_swap(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_r128_private_t *dev_priv = dev->dev_private;
- drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
- DRM_DEBUG("\n");
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- DEV_INIT_TEST_WITH_RETURN(dev_priv);
-
- RING_SPACE_TEST_WITH_RETURN(dev_priv);
-
- if (sarea_priv->nbox > R128_NR_SAREA_CLIPRECTS)
- sarea_priv->nbox = R128_NR_SAREA_CLIPRECTS;
-
- r128_cce_dispatch_swap(dev);
- dev_priv->sarea_priv->dirty |= (R128_UPLOAD_CONTEXT |
- R128_UPLOAD_MASKS);
-
- COMMIT_RING();
- return 0;
-}
-
-static int r128_cce_vertex(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_r128_private_t *dev_priv = dev->dev_private;
- struct drm_device_dma *dma = dev->dma;
- struct drm_buf *buf;
- drm_r128_buf_priv_t *buf_priv;
- drm_r128_vertex_t *vertex = data;
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- DEV_INIT_TEST_WITH_RETURN(dev_priv);
-
- DRM_DEBUG("pid=%d index=%d count=%d discard=%d\n",
- task_pid_nr(current), vertex->idx, vertex->count, vertex->discard);
-
- if (vertex->idx < 0 || vertex->idx >= dma->buf_count) {
- DRM_ERROR("buffer index %d (of %d max)\n",
- vertex->idx, dma->buf_count - 1);
- return -EINVAL;
- }
- if (vertex->prim < 0 ||
- vertex->prim > R128_CCE_VC_CNTL_PRIM_TYPE_TRI_TYPE2) {
- DRM_ERROR("buffer prim %d\n", vertex->prim);
- return -EINVAL;
- }
-
- RING_SPACE_TEST_WITH_RETURN(dev_priv);
- VB_AGE_TEST_WITH_RETURN(dev_priv);
-
- buf = dma->buflist[vertex->idx];
- buf_priv = buf->dev_private;
-
- if (buf->file_priv != file_priv) {
- DRM_ERROR("process %d using buffer owned by %p\n",
- task_pid_nr(current), buf->file_priv);
- return -EINVAL;
- }
- if (buf->pending) {
- DRM_ERROR("sending pending buffer %d\n", vertex->idx);
- return -EINVAL;
- }
-
- buf->used = vertex->count;
- buf_priv->prim = vertex->prim;
- buf_priv->discard = vertex->discard;
-
- r128_cce_dispatch_vertex(dev, buf);
-
- COMMIT_RING();
- return 0;
-}
-
-static int r128_cce_indices(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_r128_private_t *dev_priv = dev->dev_private;
- struct drm_device_dma *dma = dev->dma;
- struct drm_buf *buf;
- drm_r128_buf_priv_t *buf_priv;
- drm_r128_indices_t *elts = data;
- int count;
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- DEV_INIT_TEST_WITH_RETURN(dev_priv);
-
- DRM_DEBUG("pid=%d buf=%d s=%d e=%d d=%d\n", task_pid_nr(current),
- elts->idx, elts->start, elts->end, elts->discard);
-
- if (elts->idx < 0 || elts->idx >= dma->buf_count) {
- DRM_ERROR("buffer index %d (of %d max)\n",
- elts->idx, dma->buf_count - 1);
- return -EINVAL;
- }
- if (elts->prim < 0 ||
- elts->prim > R128_CCE_VC_CNTL_PRIM_TYPE_TRI_TYPE2) {
- DRM_ERROR("buffer prim %d\n", elts->prim);
- return -EINVAL;
- }
-
- RING_SPACE_TEST_WITH_RETURN(dev_priv);
- VB_AGE_TEST_WITH_RETURN(dev_priv);
-
- buf = dma->buflist[elts->idx];
- buf_priv = buf->dev_private;
-
- if (buf->file_priv != file_priv) {
- DRM_ERROR("process %d using buffer owned by %p\n",
- task_pid_nr(current), buf->file_priv);
- return -EINVAL;
- }
- if (buf->pending) {
- DRM_ERROR("sending pending buffer %d\n", elts->idx);
- return -EINVAL;
- }
-
- count = (elts->end - elts->start) / sizeof(u16);
- elts->start -= R128_INDEX_PRIM_OFFSET;
-
- if (elts->start & 0x7) {
- DRM_ERROR("misaligned buffer 0x%x\n", elts->start);
- return -EINVAL;
- }
- if (elts->start < buf->used) {
- DRM_ERROR("no header 0x%x - 0x%x\n", elts->start, buf->used);
- return -EINVAL;
- }
-
- buf->used = elts->end;
- buf_priv->prim = elts->prim;
- buf_priv->discard = elts->discard;
-
- r128_cce_dispatch_indices(dev, buf, elts->start, elts->end, count);
-
- COMMIT_RING();
- return 0;
-}
-
-static int r128_cce_blit(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- struct drm_device_dma *dma = dev->dma;
- drm_r128_private_t *dev_priv = dev->dev_private;
- drm_r128_blit_t *blit = data;
- int ret;
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- DEV_INIT_TEST_WITH_RETURN(dev_priv);
-
- DRM_DEBUG("pid=%d index=%d\n", task_pid_nr(current), blit->idx);
-
- if (blit->idx < 0 || blit->idx >= dma->buf_count) {
- DRM_ERROR("buffer index %d (of %d max)\n",
- blit->idx, dma->buf_count - 1);
- return -EINVAL;
- }
-
- RING_SPACE_TEST_WITH_RETURN(dev_priv);
- VB_AGE_TEST_WITH_RETURN(dev_priv);
-
- ret = r128_cce_dispatch_blit(dev, file_priv, blit);
-
- COMMIT_RING();
- return ret;
-}
-
-int r128_cce_depth(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_r128_private_t *dev_priv = dev->dev_private;
- drm_r128_depth_t *depth = data;
- int ret;
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- DEV_INIT_TEST_WITH_RETURN(dev_priv);
-
- RING_SPACE_TEST_WITH_RETURN(dev_priv);
-
- ret = -EINVAL;
- switch (depth->func) {
- case R128_WRITE_SPAN:
- ret = r128_cce_dispatch_write_span(dev, depth);
- break;
- case R128_WRITE_PIXELS:
- ret = r128_cce_dispatch_write_pixels(dev, depth);
- break;
- case R128_READ_SPAN:
- ret = r128_cce_dispatch_read_span(dev, depth);
- break;
- case R128_READ_PIXELS:
- ret = r128_cce_dispatch_read_pixels(dev, depth);
- break;
- }
-
- COMMIT_RING();
- return ret;
-}
-
-int r128_cce_stipple(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_r128_private_t *dev_priv = dev->dev_private;
- drm_r128_stipple_t *stipple = data;
- u32 mask[32];
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- DEV_INIT_TEST_WITH_RETURN(dev_priv);
-
- if (copy_from_user(&mask, stipple->mask, 32 * sizeof(u32)))
- return -EFAULT;
-
- RING_SPACE_TEST_WITH_RETURN(dev_priv);
-
- r128_cce_dispatch_stipple(dev, mask);
-
- COMMIT_RING();
- return 0;
-}
-
-static int r128_cce_indirect(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_r128_private_t *dev_priv = dev->dev_private;
- struct drm_device_dma *dma = dev->dma;
- struct drm_buf *buf;
- drm_r128_buf_priv_t *buf_priv;
- drm_r128_indirect_t *indirect = data;
-#if 0
- RING_LOCALS;
-#endif
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- DEV_INIT_TEST_WITH_RETURN(dev_priv);
-
- DRM_DEBUG("idx=%d s=%d e=%d d=%d\n",
- indirect->idx, indirect->start, indirect->end,
- indirect->discard);
-
- if (indirect->idx < 0 || indirect->idx >= dma->buf_count) {
- DRM_ERROR("buffer index %d (of %d max)\n",
- indirect->idx, dma->buf_count - 1);
- return -EINVAL;
- }
-
- buf = dma->buflist[indirect->idx];
- buf_priv = buf->dev_private;
-
- if (buf->file_priv != file_priv) {
- DRM_ERROR("process %d using buffer owned by %p\n",
- task_pid_nr(current), buf->file_priv);
- return -EINVAL;
- }
- if (buf->pending) {
- DRM_ERROR("sending pending buffer %d\n", indirect->idx);
- return -EINVAL;
- }
-
- if (indirect->start < buf->used) {
- DRM_ERROR("reusing indirect: start=0x%x actual=0x%x\n",
- indirect->start, buf->used);
- return -EINVAL;
- }
-
- RING_SPACE_TEST_WITH_RETURN(dev_priv);
- VB_AGE_TEST_WITH_RETURN(dev_priv);
-
- buf->used = indirect->end;
- buf_priv->discard = indirect->discard;
-
-#if 0
- /* Wait for the 3D stream to idle before the indirect buffer
- * containing 2D acceleration commands is processed.
- */
- BEGIN_RING(2);
- RADEON_WAIT_UNTIL_3D_IDLE();
- ADVANCE_RING();
-#endif
-
- /* Dispatch the indirect buffer full of commands from the
- * X server. This is insecure and is thus only available to
- * privileged clients.
- */
- r128_cce_dispatch_indirect(dev, buf, indirect->start, indirect->end);
-
- COMMIT_RING();
- return 0;
-}
-
-int r128_getparam(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_r128_private_t *dev_priv = dev->dev_private;
- drm_r128_getparam_t *param = data;
- struct pci_dev *pdev = to_pci_dev(dev->dev);
- int value;
-
- DEV_INIT_TEST_WITH_RETURN(dev_priv);
-
- DRM_DEBUG("pid=%d\n", task_pid_nr(current));
-
- switch (param->param) {
- case R128_PARAM_IRQ_NR:
- value = pdev->irq;
- break;
- default:
- return -EINVAL;
- }
-
- if (copy_to_user(param->value, &value, sizeof(int))) {
- DRM_ERROR("copy_to_user\n");
- return -EFAULT;
- }
-
- return 0;
-}
-
-void r128_driver_preclose(struct drm_device *dev, struct drm_file *file_priv)
-{
- if (dev->dev_private) {
- drm_r128_private_t *dev_priv = dev->dev_private;
- if (dev_priv->page_flipping)
- r128_do_cleanup_pageflip(dev);
- }
-}
-void r128_driver_lastclose(struct drm_device *dev)
-{
- r128_do_cleanup_cce(dev);
-}
-
-const struct drm_ioctl_desc r128_ioctls[] = {
- DRM_IOCTL_DEF_DRV(R128_INIT, r128_cce_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
- DRM_IOCTL_DEF_DRV(R128_CCE_START, r128_cce_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
- DRM_IOCTL_DEF_DRV(R128_CCE_STOP, r128_cce_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
- DRM_IOCTL_DEF_DRV(R128_CCE_RESET, r128_cce_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
- DRM_IOCTL_DEF_DRV(R128_CCE_IDLE, r128_cce_idle, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(R128_RESET, r128_engine_reset, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(R128_FULLSCREEN, r128_fullscreen, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(R128_SWAP, r128_cce_swap, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(R128_FLIP, r128_cce_flip, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(R128_CLEAR, r128_cce_clear, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(R128_VERTEX, r128_cce_vertex, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(R128_INDICES, r128_cce_indices, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(R128_BLIT, r128_cce_blit, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(R128_DEPTH, r128_cce_depth, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(R128_STIPPLE, r128_cce_stipple, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(R128_INDIRECT, r128_cce_indirect, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
- DRM_IOCTL_DEF_DRV(R128_GETPARAM, r128_getparam, DRM_AUTH),
-};
-
-int r128_max_ioctl = ARRAY_SIZE(r128_ioctls);
diff --git a/drivers/gpu/drm/radeon/Kconfig b/drivers/gpu/drm/radeon/Kconfig
index 97a277f9a25e..62a596d3a891 100644
--- a/drivers/gpu/drm/radeon/Kconfig
+++ b/drivers/gpu/drm/radeon/Kconfig
@@ -15,6 +15,8 @@ config DRM_RADEON
select HWMON
select BACKLIGHT_CLASS_DEVICE
select INTERVAL_TREE
+ select I2C
+ select I2C_ALGOBIT
# radeon depends on ACPI_VIDEO when ACPI is enabled, for select to work
# ACPI_VIDEO's dependencies must also be selected.
select INPUT if ACPI
diff --git a/drivers/gpu/drm/radeon/atombios.h b/drivers/gpu/drm/radeon/atombios.h
index 235e59b547a1..8a6621f1e82c 100644
--- a/drivers/gpu/drm/radeon/atombios.h
+++ b/drivers/gpu/drm/radeon/atombios.h
@@ -4020,7 +4020,7 @@ typedef struct _ATOM_DISPLAY_OBJECT_PATH
USHORT usSize; //the size of ATOM_DISPLAY_OBJECT_PATH
USHORT usConnObjectId; //Connector Object ID
USHORT usGPUObjectId; //GPU ID
- USHORT usGraphicObjIds[1]; //1st Encoder Obj source from GPU to last Graphic Obj destinate to connector.
+ USHORT usGraphicObjIds[]; //1st Encoder Obj source from GPU to last Graphic Obj destinate to connector.
}ATOM_DISPLAY_OBJECT_PATH;
typedef struct _ATOM_DISPLAY_EXTERNAL_OBJECT_PATH
@@ -4037,7 +4037,7 @@ typedef struct _ATOM_DISPLAY_OBJECT_PATH_TABLE
UCHAR ucNumOfDispPath;
UCHAR ucVersion;
UCHAR ucPadding[2];
- ATOM_DISPLAY_OBJECT_PATH asDispPath[1];
+ ATOM_DISPLAY_OBJECT_PATH asDispPath[];
}ATOM_DISPLAY_OBJECT_PATH_TABLE;
@@ -4053,7 +4053,7 @@ typedef struct _ATOM_OBJECT_TABLE //Above 4 object table
{
UCHAR ucNumberOfObjects;
UCHAR ucPadding[3];
- ATOM_OBJECT asObjects[1];
+ ATOM_OBJECT asObjects[];
}ATOM_OBJECT_TABLE;
typedef struct _ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT //usSrcDstTableOffset pointing to this structure
@@ -4615,7 +4615,7 @@ typedef struct _ATOM_GPIO_VOLTAGE_OBJECT_V3
UCHAR ucPhaseDelay; // phase delay in unit of micro second
UCHAR ucReserved;
ULONG ulGpioMaskVal; // GPIO Mask value
- VOLTAGE_LUT_ENTRY_V2 asVolGpioLut[1];
+ VOLTAGE_LUT_ENTRY_V2 asVolGpioLut[];
}ATOM_GPIO_VOLTAGE_OBJECT_V3;
typedef struct _ATOM_LEAKAGE_VOLTAGE_OBJECT_V3
@@ -7964,7 +7964,7 @@ typedef struct {
typedef struct {
VFCT_IMAGE_HEADER VbiosHeader;
- UCHAR VbiosContent[1];
+ UCHAR VbiosContent[];
}GOP_VBIOS_CONTENT;
typedef struct {
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index d28d3acb3ba1..ade13173921b 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -24,11 +24,10 @@
* Alex Deucher
*/
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_fixed.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_vblank.h>
#include <drm/radeon_drm.h>
diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c
index c841c273222e..4aca09cab4b8 100644
--- a/drivers/gpu/drm/radeon/atombios_encoders.c
+++ b/drivers/gpu/drm/radeon/atombios_encoders.c
@@ -30,6 +30,7 @@
#include <drm/drm_crtc_helper.h>
#include <drm/drm_file.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include <drm/radeon_drm.h>
#include <acpi/video.h>
@@ -2122,11 +2123,12 @@ int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder, int fe_idx)
/*
* On DCE32 any encoder can drive any block so usually just use crtc id,
- * but Apple thinks different at least on iMac10,1, so there use linkb,
+ * but Apple thinks different at least on iMac10,1 and iMac11,2, so there use linkb,
* otherwise the internal eDP panel will stay dark.
*/
if (ASIC_IS_DCE32(rdev)) {
- if (dmi_match(DMI_PRODUCT_NAME, "iMac10,1"))
+ if (dmi_match(DMI_PRODUCT_NAME, "iMac10,1") ||
+ dmi_match(DMI_PRODUCT_NAME, "iMac11,2"))
enc_idx = (dig->linkb) ? 1 : 0;
else
enc_idx = radeon_crtc->crtc_id;
diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c
index 621ff174dff3..7b0cfeaddcec 100644
--- a/drivers/gpu/drm/radeon/r300.c
+++ b/drivers/gpu/drm/radeon/r300.c
@@ -31,7 +31,6 @@
#include <linux/slab.h>
#include <drm/drm.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_device.h>
#include <drm/drm_file.h>
#include <drm/radeon_drm.h>
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 2e7161acd443..57e20780a458 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -73,8 +73,7 @@
#include <linux/mmu_notifier.h>
#endif
-#include <drm/ttm/ttm_bo_api.h>
-#include <drm/ttm/ttm_bo_driver.h>
+#include <drm/ttm/ttm_bo.h>
#include <drm/ttm/ttm_placement.h>
#include <drm/ttm/ttm_execbuf_util.h>
diff --git a/drivers/gpu/drm/radeon/radeon_acpi.c b/drivers/gpu/drm/radeon/radeon_acpi.c
index b603c0b77075..5771d1fcb073 100644
--- a/drivers/gpu/drm/radeon/radeon_acpi.c
+++ b/drivers/gpu/drm/radeon/radeon_acpi.c
@@ -22,6 +22,7 @@
*/
#include <linux/acpi.h>
+#include <linux/backlight.h>
#include <linux/pci.h>
#include <linux/pm_runtime.h>
#include <linux/power_supply.h>
@@ -30,7 +31,6 @@
#include <acpi/acpi_bus.h>
#include <acpi/video.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_probe_helper.h>
#include "atom.h"
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
index bfacf8fe5cc1..802b5af19261 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -30,7 +30,6 @@
#include <linux/pci.h>
#include <linux/vgaarb.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/radeon_drm.h>
#include "atom.h"
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index f7431d224604..07193cd0c417 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -27,7 +27,7 @@
#include <drm/display/drm_dp_mst_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_crtc_helper.h>
-#include <drm/drm_fb_helper.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_probe_helper.h>
#include <drm/radeon_drm.h>
#include "radeon.h"
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index 6344454a7721..afbb3a80c0c6 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -1023,6 +1023,7 @@ void radeon_atombios_fini(struct radeon_device *rdev)
{
if (rdev->mode_info.atom_context) {
kfree(rdev->mode_info.atom_context->scratch);
+ kfree(rdev->mode_info.atom_context->iio);
}
kfree(rdev->mode_info.atom_context);
rdev->mode_info.atom_context = NULL;
@@ -1772,7 +1773,6 @@ int radeon_gpu_reset(struct radeon_device *rdev)
bool saved = false;
int i, r;
- int resched;
down_write(&rdev->exclusive_lock);
@@ -1784,8 +1784,6 @@ int radeon_gpu_reset(struct radeon_device *rdev)
atomic_inc(&rdev->gpu_reset_counter);
radeon_save_bios_scratch_regs(rdev);
- /* block TTM */
- resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev);
radeon_suspend(rdev);
radeon_hpd_fini(rdev);
@@ -1844,8 +1842,6 @@ int radeon_gpu_reset(struct radeon_device *rdev)
/* reset hpd state */
radeon_hpd_init(rdev);
- ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched);
-
rdev->in_reset = true;
rdev->needs_reset = false;
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index 9bed1a6cb163..f34a7f63261d 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -38,6 +38,7 @@
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_modeset_helper.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
#include <drm/radeon_drm.h>
diff --git a/drivers/gpu/drm/radeon/radeon_dp_auxch.c b/drivers/gpu/drm/radeon/radeon_dp_auxch.c
index 69379b95146e..1e5b6baf76a1 100644
--- a/drivers/gpu/drm/radeon/radeon_dp_auxch.c
+++ b/drivers/gpu/drm/radeon/radeon_dp_auxch.c
@@ -158,7 +158,7 @@ radeon_dp_aux_transfer_native(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg
} while (retry_count++ < 1000);
if (retry_count >= 1000) {
- DRM_ERROR("auxch hw never signalled completion, error %08x\n", tmp);
+ dev_err(rdev->dev, "auxch hw never signalled completion, error %08x\n", tmp);
ret = -EIO;
goto done;
}
@@ -168,8 +168,7 @@ radeon_dp_aux_transfer_native(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg
goto done;
}
if (tmp & AUX_RX_ERROR_FLAGS) {
- DRM_DEBUG_KMS_RATELIMITED("dp_aux_ch flags not zero: %08x\n",
- tmp);
+ drm_dbg_kms_ratelimited(dev, "dp_aux_ch flags not zero: %08x\n", tmp);
ret = -EIO;
goto done;
}
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index 6cbe1ab81aba..716ab85a376b 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -38,9 +38,7 @@
#include <linux/pci.h>
#include <drm/drm_aperture.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_drv.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_file.h>
#include <drm/drm_gem.h>
#include <drm/drm_ioctl.h>
diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c
index fbc0a2182318..b3518a8f95a0 100644
--- a/drivers/gpu/drm/radeon/radeon_encoders.c
+++ b/drivers/gpu/drm/radeon/radeon_encoders.c
@@ -26,7 +26,6 @@
#include <linux/pci.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_device.h>
#include <drm/radeon_drm.h>
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c
index c1710ed1cab8..c4807f0c43bc 100644
--- a/drivers/gpu/drm/radeon/radeon_fb.c
+++ b/drivers/gpu/drm/radeon/radeon_fb.c
@@ -277,10 +277,6 @@ static int radeonfb_create(struct drm_fb_helper *helper,
drm_fb_helper_fill_info(info, &rfbdev->helper, sizes);
- /* setup aperture base/size for vesafb takeover */
- info->apertures->ranges[0].base = rdev->mc.aper_base;
- info->apertures->ranges[0].size = rdev->mc.aper_size;
-
/* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
if (info->screen_base == NULL) {
@@ -352,7 +348,7 @@ int radeon_fbdev_init(struct radeon_device *rdev)
rfbdev->rdev = rdev;
rdev->mode_info.rfbdev = rfbdev;
- drm_fb_helper_prepare(rdev->ddev, &rfbdev->helper,
+ drm_fb_helper_prepare(rdev->ddev, &rfbdev->helper, bpp_sel,
&radeon_fb_helper_funcs);
ret = drm_fb_helper_init(rdev->ddev, &rfbdev->helper);
@@ -362,7 +358,7 @@ int radeon_fbdev_init(struct radeon_device *rdev)
/* disable all the possible outputs/crtcs before entering KMS mode */
drm_helper_disable_unused_functions(rdev->ddev);
- ret = drm_fb_helper_initial_config(&rfbdev->helper, bpp_sel);
+ ret = drm_fb_helper_initial_config(&rfbdev->helper);
if (ret)
goto fini;
@@ -371,6 +367,7 @@ int radeon_fbdev_init(struct radeon_device *rdev)
fini:
drm_fb_helper_fini(&rfbdev->helper);
free:
+ drm_fb_helper_unprepare(&rfbdev->helper);
kfree(rfbdev);
return ret;
}
@@ -381,6 +378,7 @@ void radeon_fbdev_fini(struct radeon_device *rdev)
return;
radeon_fbdev_destroy(rdev->ddev, rdev->mode_info.rfbdev);
+ drm_fb_helper_unprepare(&rdev->mode_info.rfbdev->helper);
kfree(rdev->mode_info.rfbdev);
rdev->mode_info.rfbdev = NULL;
}
diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c
index da2173435edd..3377fbc71f65 100644
--- a/drivers/gpu/drm/radeon/radeon_irq_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c
@@ -29,7 +29,6 @@
#include <linux/pci.h>
#include <linux/pm_runtime.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_device.h>
#include <drm/drm_drv.h>
#include <drm/drm_probe_helper.h>
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
index 6072ed5f2dd3..825b351ff53c 100644
--- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
+++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
@@ -24,11 +24,10 @@
* Alex Deucher
*/
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_fb_helper.h>
#include <drm/drm_fixed.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_vblank.h>
#include <drm/radeon_drm.h>
@@ -322,7 +321,7 @@ static void radeon_crtc_dpms(struct drm_crtc *crtc, int mode)
*/
if (rdev->flags & RADEON_SINGLE_CRTC)
crtc_ext_cntl = RADEON_CRTC_CRT_ON;
-
+
switch (mode) {
case DRM_MODE_DPMS_ON:
radeon_crtc->enabled = true;
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
index 0cd32c65456c..601d35d34eab 100644
--- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
+++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
@@ -27,9 +27,9 @@
#include <linux/backlight.h>
#include <linux/pci.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_device.h>
#include <drm/drm_file.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_util.h>
#include <drm/radeon_drm.h>
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_tv.c b/drivers/gpu/drm/radeon/radeon_legacy_tv.c
index d9df7f311e76..12e180b119ac 100644
--- a/drivers/gpu/drm/radeon/radeon_legacy_tv.c
+++ b/drivers/gpu/drm/radeon/radeon_legacy_tv.c
@@ -1,6 +1,5 @@
// SPDX-License-Identifier: MIT
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_device.h>
#include "radeon.h"
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index 9f5be416454f..3a59d016e8cd 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -35,7 +35,7 @@
#include <drm/drm_edid.h>
#include <drm/drm_encoder.h>
#include <drm/drm_fixed.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index 04c693ca419a..cbc554928bcc 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -1853,11 +1853,10 @@ static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish
static void radeon_dynpm_idle_work_handler(struct work_struct *work)
{
struct radeon_device *rdev;
- int resched;
+
rdev = container_of(work, struct radeon_device,
pm.dynpm_idle_work.work);
- resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev);
mutex_lock(&rdev->pm.mutex);
if (rdev->pm.dynpm_state == DYNPM_STATE_ACTIVE) {
int not_processed = 0;
@@ -1908,7 +1907,6 @@ static void radeon_dynpm_idle_work_handler(struct work_struct *work)
msecs_to_jiffies(RADEON_IDLE_LOOP_MS));
}
mutex_unlock(&rdev->pm.mutex);
- ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched);
}
/*
diff --git a/drivers/gpu/drm/radeon/radeon_prime.c b/drivers/gpu/drm/radeon/radeon_prime.c
index 42a87948e28c..b3cfc99f4d7e 100644
--- a/drivers/gpu/drm/radeon/radeon_prime.c
+++ b/drivers/gpu/drm/radeon/radeon_prime.c
@@ -29,6 +29,8 @@
#include <drm/drm_prime.h>
#include <drm/radeon_drm.h>
+#include <drm/ttm/ttm_tt.h>
+
#include "radeon.h"
#include "radeon_prime.h"
diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
index 30402b5ce4c5..1e8e287e113c 100644
--- a/drivers/gpu/drm/radeon/radeon_ttm.c
+++ b/drivers/gpu/drm/radeon/radeon_ttm.c
@@ -42,10 +42,10 @@
#include <drm/drm_file.h>
#include <drm/drm_prime.h>
#include <drm/radeon_drm.h>
-#include <drm/ttm/ttm_bo_api.h>
-#include <drm/ttm/ttm_bo_driver.h>
+#include <drm/ttm/ttm_bo.h>
#include <drm/ttm/ttm_placement.h>
#include <drm/ttm/ttm_range_manager.h>
+#include <drm/ttm/ttm_tt.h>
#include "radeon_reg.h"
#include "radeon.h"
diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig
index b2bddbeca878..53c356aed5d5 100644
--- a/drivers/gpu/drm/rcar-du/Kconfig
+++ b/drivers/gpu/drm/rcar-du/Kconfig
@@ -25,6 +25,7 @@ config DRM_RCAR_CMM
config DRM_RCAR_DW_HDMI
tristate "R-Car Gen3 and RZ/G2 DU HDMI Encoder Support"
depends on DRM && OF
+ depends on DRM_RCAR_DU || COMPILE_TEST
select DRM_DW_HDMI
help
Enable support for R-Car Gen3 or RZ/G2 internal HDMI encoder.
@@ -32,6 +33,7 @@ config DRM_RCAR_DW_HDMI
config DRM_RCAR_USE_LVDS
bool "R-Car DU LVDS Encoder Support"
depends on DRM_BRIDGE && OF
+ depends on DRM_RCAR_DU || COMPILE_TEST
default DRM_RCAR_DU
help
Enable support for the R-Car Display Unit embedded LVDS encoders.
@@ -39,12 +41,15 @@ config DRM_RCAR_USE_LVDS
config DRM_RCAR_LVDS
def_tristate DRM_RCAR_DU
depends on DRM_RCAR_USE_LVDS
+ depends on PM
select DRM_KMS_HELPER
select DRM_PANEL
+ select RESET_CONTROLLER
config DRM_RCAR_USE_MIPI_DSI
bool "R-Car DU MIPI DSI Encoder Support"
depends on DRM_BRIDGE && OF
+ depends on DRM_RCAR_DU || COMPILE_TEST
default DRM_RCAR_DU
help
Enable support for the R-Car Display Unit embedded MIPI DSI encoders.
@@ -53,6 +58,7 @@ config DRM_RCAR_MIPI_DSI
def_tristate DRM_RCAR_DU
depends on DRM_RCAR_USE_MIPI_DSI
select DRM_MIPI_DSI
+ select RESET_CONTROLLER
config DRM_RZG2L_MIPI_DSI
tristate "RZ/G2L MIPI DSI Encoder Support"
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index 3619e1ddeb62..008e172ed43b 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -10,7 +10,6 @@
#include <linux/clk.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
-#include <linux/sys_soc.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
@@ -204,11 +203,6 @@ static void rcar_du_escr_divider(struct clk *clk, unsigned long target,
}
}
-static const struct soc_device_attribute rcar_du_r8a7795_es1[] = {
- { .soc_id = "r8a7795", .revision = "ES1.*" },
- { /* sentinel */ }
-};
-
static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
{
const struct drm_display_mode *mode = &rcrtc->crtc.state->adjusted_mode;
@@ -238,7 +232,7 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
* no post-divider when a display PLL is present (as shown by
* the workaround breaking HDMI output on M3-W during testing).
*/
- if (soc_device_match(rcar_du_r8a7795_es1)) {
+ if (rcdu->info->quirks & RCAR_DU_QUIRK_H3_ES1_PCLK_STABILITY) {
target *= 2;
div = 1;
}
@@ -251,13 +245,30 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
| DPLLCR_N(dpll.n) | DPLLCR_M(dpll.m)
| DPLLCR_STBY;
- if (rcrtc->index == 1)
+ if (rcrtc->index == 1) {
dpllcr |= DPLLCR_PLCS1
| DPLLCR_INCS_DOTCLKIN1;
- else
- dpllcr |= DPLLCR_PLCS0
+ } else {
+ dpllcr |= DPLLCR_PLCS0_PLL
| DPLLCR_INCS_DOTCLKIN0;
+ /*
+ * On ES2.x we have a single mux controlled via bit 21,
+ * which selects between DCLKIN source (bit 21 = 0) and
+ * a PLL source (bit 21 = 1), where the PLL is always
+ * PLL1.
+ *
+ * On ES1.x we have an additional mux, controlled
+ * via bit 20, for choosing between PLL0 (bit 20 = 0)
+ * and PLL1 (bit 20 = 1). We always want to use PLL1,
+ * so on ES1.x, in addition to setting bit 21, we need
+ * to set the bit 20.
+ */
+
+ if (rcdu->info->quirks & RCAR_DU_QUIRK_H3_ES1_PLL)
+ dpllcr |= DPLLCR_PLCS0_H3ES1X_PLL1;
+ }
+
rcar_du_group_write(rcrtc->group, DPLLCR, dpllcr);
escr = ESCR_DCLKSEL_DCLKIN | div;
@@ -287,10 +298,12 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
escr = params.escr;
}
- dev_dbg(rcrtc->dev->dev, "%s: ESCR 0x%08x\n", __func__, escr);
+ if (rcdu->info->gen < 4) {
+ dev_dbg(rcrtc->dev->dev, "%s: ESCR 0x%08x\n", __func__, escr);
- rcar_du_crtc_write(rcrtc, rcrtc->index % 2 ? ESCR13 : ESCR02, escr);
- rcar_du_crtc_write(rcrtc, rcrtc->index % 2 ? OTAR13 : OTAR02, 0);
+ rcar_du_crtc_write(rcrtc, rcrtc->index % 2 ? ESCR13 : ESCR02, escr);
+ rcar_du_crtc_write(rcrtc, rcrtc->index % 2 ? OTAR13 : OTAR02, 0);
+ }
/* Signal polarities */
dsmr = ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? DSMR_VSL : 0)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
index d003e8d9e7a2..b9a94c5260e9 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
@@ -16,6 +16,7 @@
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/slab.h>
+#include <linux/sys_soc.h>
#include <linux/wait.h>
#include <drm/drm_atomic_helper.h>
@@ -386,6 +387,43 @@ static const struct rcar_du_device_info rcar_du_r8a7795_info = {
.dpll_mask = BIT(2) | BIT(1),
};
+static const struct rcar_du_device_info rcar_du_r8a7795_es1_info = {
+ .gen = 3,
+ .features = RCAR_DU_FEATURE_CRTC_IRQ
+ | RCAR_DU_FEATURE_CRTC_CLOCK
+ | RCAR_DU_FEATURE_VSP1_SOURCE
+ | RCAR_DU_FEATURE_INTERLACED
+ | RCAR_DU_FEATURE_TVM_SYNC,
+ .quirks = RCAR_DU_QUIRK_H3_ES1_PCLK_STABILITY
+ | RCAR_DU_QUIRK_H3_ES1_PLL,
+ .channels_mask = BIT(3) | BIT(2) | BIT(1) | BIT(0),
+ .routes = {
+ /*
+ * R8A7795 has one RGB output, two HDMI outputs and one
+ * LVDS output.
+ */
+ [RCAR_DU_OUTPUT_DPAD0] = {
+ .possible_crtcs = BIT(3),
+ .port = 0,
+ },
+ [RCAR_DU_OUTPUT_HDMI0] = {
+ .possible_crtcs = BIT(1),
+ .port = 1,
+ },
+ [RCAR_DU_OUTPUT_HDMI1] = {
+ .possible_crtcs = BIT(2),
+ .port = 2,
+ },
+ [RCAR_DU_OUTPUT_LVDS0] = {
+ .possible_crtcs = BIT(0),
+ .port = 3,
+ },
+ },
+ .num_lvds = 1,
+ .num_rpf = 5,
+ .dpll_mask = BIT(2) | BIT(1),
+};
+
static const struct rcar_du_device_info rcar_du_r8a7796_info = {
.gen = 3,
.features = RCAR_DU_FEATURE_CRTC_IRQ
@@ -504,7 +542,7 @@ static const struct rcar_du_device_info rcar_du_r8a7799x_info = {
};
static const struct rcar_du_device_info rcar_du_r8a779a0_info = {
- .gen = 3,
+ .gen = 4,
.features = RCAR_DU_FEATURE_CRTC_IRQ
| RCAR_DU_FEATURE_VSP1_SOURCE
| RCAR_DU_FEATURE_NO_BLENDING,
@@ -524,6 +562,27 @@ static const struct rcar_du_device_info rcar_du_r8a779a0_info = {
.dsi_clk_mask = BIT(1) | BIT(0),
};
+static const struct rcar_du_device_info rcar_du_r8a779g0_info = {
+ .gen = 4,
+ .features = RCAR_DU_FEATURE_CRTC_IRQ
+ | RCAR_DU_FEATURE_VSP1_SOURCE
+ | RCAR_DU_FEATURE_NO_BLENDING,
+ .channels_mask = BIT(1) | BIT(0),
+ .routes = {
+ /* R8A779G0 has two MIPI DSI outputs. */
+ [RCAR_DU_OUTPUT_DSI0] = {
+ .possible_crtcs = BIT(0),
+ .port = 0,
+ },
+ [RCAR_DU_OUTPUT_DSI1] = {
+ .possible_crtcs = BIT(1),
+ .port = 1,
+ },
+ },
+ .num_rpf = 5,
+ .dsi_clk_mask = BIT(1) | BIT(0),
+};
+
static const struct of_device_id rcar_du_of_table[] = {
{ .compatible = "renesas,du-r8a7742", .data = &rcar_du_r8a7790_info },
{ .compatible = "renesas,du-r8a7743", .data = &rzg1_du_r8a7743_info },
@@ -549,11 +608,17 @@ static const struct of_device_id rcar_du_of_table[] = {
{ .compatible = "renesas,du-r8a77990", .data = &rcar_du_r8a7799x_info },
{ .compatible = "renesas,du-r8a77995", .data = &rcar_du_r8a7799x_info },
{ .compatible = "renesas,du-r8a779a0", .data = &rcar_du_r8a779a0_info },
+ { .compatible = "renesas,du-r8a779g0", .data = &rcar_du_r8a779g0_info },
{ }
};
MODULE_DEVICE_TABLE(of, rcar_du_of_table);
+static const struct soc_device_attribute rcar_du_soc_table[] = {
+ { .soc_id = "r8a7795", .revision = "ES1.*", .data = &rcar_du_r8a7795_es1_info },
+ { /* sentinel */ }
+};
+
const char *rcar_du_output_name(enum rcar_du_output output)
{
static const char * const names[] = {
@@ -599,7 +664,6 @@ static const struct drm_driver rcar_du_driver = {
* Power management
*/
-#ifdef CONFIG_PM_SLEEP
static int rcar_du_pm_suspend(struct device *dev)
{
struct rcar_du_device *rcdu = dev_get_drvdata(dev);
@@ -613,11 +677,9 @@ static int rcar_du_pm_resume(struct device *dev)
return drm_mode_config_helper_resume(&rcdu->ddev);
}
-#endif
-static const struct dev_pm_ops rcar_du_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(rcar_du_pm_suspend, rcar_du_pm_resume)
-};
+static DEFINE_SIMPLE_DEV_PM_OPS(rcar_du_pm_ops,
+ rcar_du_pm_suspend, rcar_du_pm_resume);
/* -----------------------------------------------------------------------------
* Platform driver
@@ -645,6 +707,7 @@ static void rcar_du_shutdown(struct platform_device *pdev)
static int rcar_du_probe(struct platform_device *pdev)
{
+ const struct soc_device_attribute *soc_attr;
struct rcar_du_device *rcdu;
unsigned int mask;
int ret;
@@ -659,8 +722,13 @@ static int rcar_du_probe(struct platform_device *pdev)
return PTR_ERR(rcdu);
rcdu->dev = &pdev->dev;
+
rcdu->info = of_device_get_match_data(rcdu->dev);
+ soc_attr = soc_device_match(rcar_du_soc_table);
+ if (soc_attr)
+ rcdu->info = soc_attr->data;
+
platform_set_drvdata(pdev, rcdu);
/* I/O resources */
@@ -712,7 +780,7 @@ static struct platform_driver rcar_du_platform_driver = {
.shutdown = rcar_du_shutdown,
.driver = {
.name = "rcar-du",
- .pm = &rcar_du_pm_ops,
+ .pm = pm_sleep_ptr(&rcar_du_pm_ops),
.of_match_table = rcar_du_of_table,
},
};
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
index 5cfa2bb7ad93..acc3673fefe1 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
@@ -34,6 +34,8 @@ struct rcar_du_device;
#define RCAR_DU_FEATURE_NO_BLENDING BIT(5) /* PnMR.SPIM does not have ALP nor EOR bits */
#define RCAR_DU_QUIRK_ALIGN_128B BIT(0) /* Align pitches to 128 bytes */
+#define RCAR_DU_QUIRK_H3_ES1_PCLK_STABILITY BIT(1) /* H3 ES1 has pclk stability issue */
+#define RCAR_DU_QUIRK_H3_ES1_PLL BIT(2) /* H3 ES1 PLL setup differs from non-ES1 */
enum rcar_du_output {
RCAR_DU_OUTPUT_DPAD0,
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.c b/drivers/gpu/drm/rcar-du/rcar_du_group.c
index 1fe8581577ed..152602236377 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_group.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_group.c
@@ -107,7 +107,7 @@ static void rcar_du_group_setup_didsr(struct rcar_du_group *rgrp)
*/
rcrtc = rcdu->crtcs;
num_crtcs = rcdu->num_crtcs;
- } else if (rcdu->info->gen == 3 && rgrp->num_crtcs > 1) {
+ } else if (rcdu->info->gen >= 3 && rgrp->num_crtcs > 1) {
/*
* On Gen3 dot clocks are setup through per-group registers,
* only available when the group has two channels.
@@ -148,19 +148,23 @@ static void rcar_du_group_setup(struct rcar_du_group *rgrp)
}
rcar_du_group_write(rgrp, DEFR5, DEFR5_CODE | DEFR5_DEFE5);
- rcar_du_group_setup_pins(rgrp);
+ if (rcdu->info->gen < 4)
+ rcar_du_group_setup_pins(rgrp);
- /*
- * TODO: Handle routing of the DU output to CMM dynamically, as we
- * should bypass CMM completely when no color management feature is
- * used.
- */
- defr7 |= (rgrp->cmms_mask & BIT(1) ? DEFR7_CMME1 : 0) |
- (rgrp->cmms_mask & BIT(0) ? DEFR7_CMME0 : 0);
- rcar_du_group_write(rgrp, DEFR7, defr7);
+ if (rcdu->info->gen < 4) {
+ /*
+ * TODO: Handle routing of the DU output to CMM dynamically, as
+ * we should bypass CMM completely when no color management
+ * feature is used.
+ */
+ defr7 |= (rgrp->cmms_mask & BIT(1) ? DEFR7_CMME1 : 0) |
+ (rgrp->cmms_mask & BIT(0) ? DEFR7_CMME0 : 0);
+ rcar_du_group_write(rgrp, DEFR7, defr7);
+ }
if (rcdu->info->gen >= 2) {
- rcar_du_group_setup_defr8(rgrp);
+ if (rcdu->info->gen < 4)
+ rcar_du_group_setup_defr8(rgrp);
rcar_du_group_setup_didsr(rgrp);
}
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
index 8c2719efda2a..adfb36b0e815 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
@@ -260,6 +260,24 @@ static const struct rcar_du_format_info rcar_du_format_infos[] = {
.planes = 1,
.hsub = 1,
}, {
+ .fourcc = DRM_FORMAT_RGBX1010102,
+ .v4l2 = V4L2_PIX_FMT_RGBX1010102,
+ .bpp = 32,
+ .planes = 1,
+ .hsub = 1,
+ }, {
+ .fourcc = DRM_FORMAT_RGBA1010102,
+ .v4l2 = V4L2_PIX_FMT_RGBA1010102,
+ .bpp = 32,
+ .planes = 1,
+ .hsub = 1,
+ }, {
+ .fourcc = DRM_FORMAT_ARGB2101010,
+ .v4l2 = V4L2_PIX_FMT_ARGB2101010,
+ .bpp = 32,
+ .planes = 1,
+ .hsub = 1,
+ }, {
.fourcc = DRM_FORMAT_YVYU,
.v4l2 = V4L2_PIX_FMT_YVYU,
.bpp = 16,
@@ -307,6 +325,18 @@ static const struct rcar_du_format_info rcar_du_format_infos[] = {
.bpp = 24,
.planes = 3,
.hsub = 1,
+ }, {
+ .fourcc = DRM_FORMAT_Y210,
+ .v4l2 = V4L2_PIX_FMT_Y210,
+ .bpp = 32,
+ .planes = 1,
+ .hsub = 2,
+ }, {
+ .fourcc = DRM_FORMAT_Y212,
+ .v4l2 = V4L2_PIX_FMT_Y212,
+ .bpp = 32,
+ .planes = 1,
+ .hsub = 2,
},
};
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_regs.h b/drivers/gpu/drm/rcar-du/rcar_du_regs.h
index c1bcb0e8b5b4..789ae9285108 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_regs.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_regs.h
@@ -283,12 +283,8 @@
#define DPLLCR 0x20044
#define DPLLCR_CODE (0x95 << 24)
#define DPLLCR_PLCS1 (1 << 23)
-/*
- * PLCS0 is bit 21, but H3 ES1.x requires bit 20 to be set as well. As bit 20
- * isn't implemented by other SoC in the Gen3 family it can safely be set
- * unconditionally.
- */
-#define DPLLCR_PLCS0 (3 << 20)
+#define DPLLCR_PLCS0_PLL (1 << 21)
+#define DPLLCR_PLCS0_H3ES1X_PLL1 (1 << 20)
#define DPLLCR_CLKE (1 << 18)
#define DPLLCR_FDPLL(n) ((n) << 12)
#define DPLLCR_N(n) ((n) << 5)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
index e465aef41585..fe90be51d64e 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
@@ -139,6 +139,43 @@ static const u32 rcar_du_vsp_formats[] = {
DRM_FORMAT_YVU444,
};
+/*
+ * Gen4 supports the same formats as above, and additionally 2-10-10-10 RGB
+ * formats and Y210 & Y212 formats.
+ */
+static const u32 rcar_du_vsp_formats_gen4[] = {
+ DRM_FORMAT_RGB332,
+ DRM_FORMAT_ARGB4444,
+ DRM_FORMAT_XRGB4444,
+ DRM_FORMAT_ARGB1555,
+ DRM_FORMAT_XRGB1555,
+ DRM_FORMAT_RGB565,
+ DRM_FORMAT_BGR888,
+ DRM_FORMAT_RGB888,
+ DRM_FORMAT_BGRA8888,
+ DRM_FORMAT_BGRX8888,
+ DRM_FORMAT_ARGB8888,
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_RGBX1010102,
+ DRM_FORMAT_RGBA1010102,
+ DRM_FORMAT_ARGB2101010,
+ DRM_FORMAT_UYVY,
+ DRM_FORMAT_YUYV,
+ DRM_FORMAT_YVYU,
+ DRM_FORMAT_NV12,
+ DRM_FORMAT_NV21,
+ DRM_FORMAT_NV16,
+ DRM_FORMAT_NV61,
+ DRM_FORMAT_YUV420,
+ DRM_FORMAT_YVU420,
+ DRM_FORMAT_YUV422,
+ DRM_FORMAT_YVU422,
+ DRM_FORMAT_YUV444,
+ DRM_FORMAT_YVU444,
+ DRM_FORMAT_Y210,
+ DRM_FORMAT_Y212,
+};
+
static void rcar_du_vsp_plane_setup(struct rcar_du_vsp_plane *plane)
{
struct rcar_du_vsp_plane_state *state =
@@ -436,14 +473,23 @@ int rcar_du_vsp_init(struct rcar_du_vsp *vsp, struct device_node *np,
? DRM_PLANE_TYPE_PRIMARY
: DRM_PLANE_TYPE_OVERLAY;
struct rcar_du_vsp_plane *plane = &vsp->planes[i];
+ unsigned int num_formats;
+ const u32 *formats;
+
+ if (rcdu->info->gen < 4) {
+ num_formats = ARRAY_SIZE(rcar_du_vsp_formats);
+ formats = rcar_du_vsp_formats;
+ } else {
+ num_formats = ARRAY_SIZE(rcar_du_vsp_formats_gen4);
+ formats = rcar_du_vsp_formats_gen4;
+ }
plane->vsp = vsp;
plane->index = i;
ret = drm_universal_plane_init(&rcdu->ddev, &plane->plane,
crtcs, &rcar_du_vsp_plane_funcs,
- rcar_du_vsp_formats,
- ARRAY_SIZE(rcar_du_vsp_formats),
+ formats, num_formats,
NULL, type, NULL);
if (ret < 0)
return ret;
diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c
index 81a060c2fe3f..260ea5d8624e 100644
--- a/drivers/gpu/drm/rcar-du/rcar_lvds.c
+++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c
@@ -16,6 +16,8 @@
#include <linux/of_device.h>
#include <linux/of_graph.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
#include <linux/slab.h>
#include <linux/sys_soc.h>
@@ -60,6 +62,7 @@ struct rcar_lvds_device_info {
struct rcar_lvds {
struct device *dev;
const struct rcar_lvds_device_info *info;
+ struct reset_control *rstc;
struct drm_bridge bridge;
@@ -80,6 +83,11 @@ struct rcar_lvds {
#define bridge_to_rcar_lvds(b) \
container_of(b, struct rcar_lvds, bridge)
+static u32 rcar_lvds_read(struct rcar_lvds *lvds, u32 reg)
+{
+ return ioread32(lvds->mmio + reg);
+}
+
static void rcar_lvds_write(struct rcar_lvds *lvds, u32 reg, u32 data)
{
iowrite32(data, lvds->mmio + reg);
@@ -316,8 +324,8 @@ int rcar_lvds_pclk_enable(struct drm_bridge *bridge, unsigned long freq)
dev_dbg(lvds->dev, "enabling LVDS PLL, freq=%luHz\n", freq);
- ret = clk_prepare_enable(lvds->clocks.mod);
- if (ret < 0)
+ ret = pm_runtime_resume_and_get(lvds->dev);
+ if (ret)
return ret;
__rcar_lvds_pll_setup_d3_e3(lvds, freq, true);
@@ -337,7 +345,7 @@ void rcar_lvds_pclk_disable(struct drm_bridge *bridge)
rcar_lvds_write(lvds, LVDPLLCR, 0);
- clk_disable_unprepare(lvds->clocks.mod);
+ pm_runtime_put_sync(lvds->dev);
}
EXPORT_SYMBOL_GPL(rcar_lvds_pclk_disable);
@@ -396,8 +404,8 @@ static void __rcar_lvds_atomic_enable(struct drm_bridge *bridge,
u32 lvdcr0;
int ret;
- ret = clk_prepare_enable(lvds->clocks.mod);
- if (ret < 0)
+ ret = pm_runtime_resume_and_get(lvds->dev);
+ if (ret)
return;
/* Enable the companion LVDS encoder in dual-link mode. */
@@ -541,6 +549,32 @@ static void rcar_lvds_atomic_disable(struct drm_bridge *bridge,
struct drm_bridge_state *old_bridge_state)
{
struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
+ u32 lvdcr0;
+
+ /*
+ * Clear the LVDCR0 bits in the order specified by the hardware
+ * documentation, ending with a write of 0 to the full register to
+ * clear all remaining bits.
+ */
+ lvdcr0 = rcar_lvds_read(lvds, LVDCR0);
+
+ lvdcr0 &= ~LVDCR0_LVRES;
+ rcar_lvds_write(lvds, LVDCR0, lvdcr0);
+
+ if (lvds->info->quirks & RCAR_LVDS_QUIRK_GEN3_LVEN) {
+ lvdcr0 &= ~LVDCR0_LVEN;
+ rcar_lvds_write(lvds, LVDCR0, lvdcr0);
+ }
+
+ if (lvds->info->quirks & RCAR_LVDS_QUIRK_PWD) {
+ lvdcr0 &= ~LVDCR0_PWD;
+ rcar_lvds_write(lvds, LVDCR0, lvdcr0);
+ }
+
+ if (!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL)) {
+ lvdcr0 &= ~LVDCR0_PLLON;
+ rcar_lvds_write(lvds, LVDCR0, lvdcr0);
+ }
rcar_lvds_write(lvds, LVDCR0, 0);
rcar_lvds_write(lvds, LVDCR1, 0);
@@ -551,7 +585,7 @@ static void rcar_lvds_atomic_disable(struct drm_bridge *bridge,
lvds->companion->funcs->atomic_disable(lvds->companion,
old_bridge_state);
- clk_disable_unprepare(lvds->clocks.mod);
+ pm_runtime_put_sync(lvds->dev);
}
static bool rcar_lvds_mode_fixup(struct drm_bridge *bridge,
@@ -844,6 +878,13 @@ static int rcar_lvds_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
+ lvds->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
+ if (IS_ERR(lvds->rstc))
+ return dev_err_probe(&pdev->dev, PTR_ERR(lvds->rstc),
+ "failed to get cpg reset\n");
+
+ pm_runtime_enable(&pdev->dev);
+
drm_bridge_add(&lvds->bridge);
return 0;
@@ -855,6 +896,8 @@ static int rcar_lvds_remove(struct platform_device *pdev)
drm_bridge_remove(&lvds->bridge);
+ pm_runtime_disable(&pdev->dev);
+
return 0;
}
@@ -913,11 +956,48 @@ static const struct of_device_id rcar_lvds_of_table[] = {
MODULE_DEVICE_TABLE(of, rcar_lvds_of_table);
+static int rcar_lvds_runtime_suspend(struct device *dev)
+{
+ struct rcar_lvds *lvds = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(lvds->clocks.mod);
+
+ reset_control_assert(lvds->rstc);
+
+ return 0;
+}
+
+static int rcar_lvds_runtime_resume(struct device *dev)
+{
+ struct rcar_lvds *lvds = dev_get_drvdata(dev);
+ int ret;
+
+ ret = reset_control_deassert(lvds->rstc);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(lvds->clocks.mod);
+ if (ret < 0)
+ goto err_reset_assert;
+
+ return 0;
+
+err_reset_assert:
+ reset_control_assert(lvds->rstc);
+
+ return ret;
+}
+
+static const struct dev_pm_ops rcar_lvds_pm_ops = {
+ SET_RUNTIME_PM_OPS(rcar_lvds_runtime_suspend, rcar_lvds_runtime_resume, NULL)
+};
+
static struct platform_driver rcar_lvds_platform_driver = {
.probe = rcar_lvds_probe,
.remove = rcar_lvds_remove,
.driver = {
.name = "rcar-lvds",
+ .pm = &rcar_lvds_pm_ops,
.of_match_table = rcar_lvds_of_table,
},
};
diff --git a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c
index a7f2b7f66a17..e10e4d4b89a2 100644
--- a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c
+++ b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c
@@ -9,6 +9,7 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/iopoll.h>
+#include <linux/math64.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -28,6 +29,31 @@
#include "rcar_mipi_dsi.h"
#include "rcar_mipi_dsi_regs.h"
+#define MHZ(v) ((u32)((v) * 1000000U))
+
+enum rcar_mipi_dsi_hw_model {
+ RCAR_DSI_V3U,
+ RCAR_DSI_V4H,
+};
+
+struct rcar_mipi_dsi_device_info {
+ enum rcar_mipi_dsi_hw_model model;
+
+ const struct dsi_clk_config *clk_cfg;
+
+ u8 clockset2_m_offset;
+
+ u8 n_min;
+ u8 n_max;
+ u8 n_mul;
+ unsigned long fpfd_min;
+ unsigned long fpfd_max;
+ u16 m_min;
+ u16 m_max;
+ unsigned long fout_min;
+ unsigned long fout_max;
+};
+
struct rcar_mipi_dsi {
struct device *dev;
const struct rcar_mipi_dsi_device_info *info;
@@ -50,6 +76,17 @@ struct rcar_mipi_dsi {
unsigned int lanes;
};
+struct dsi_setup_info {
+ unsigned long hsfreq;
+ u16 hsfreqrange;
+
+ unsigned long fout;
+ u16 m;
+ u16 n;
+ u16 vclk_divider;
+ const struct dsi_clk_config *clkset;
+};
+
static inline struct rcar_mipi_dsi *
bridge_to_rcar_mipi_dsi(struct drm_bridge *bridge)
{
@@ -62,65 +99,78 @@ host_to_rcar_mipi_dsi(struct mipi_dsi_host *host)
return container_of(host, struct rcar_mipi_dsi, host);
}
-static const u32 phtw[] = {
- 0x01020114, 0x01600115, /* General testing */
- 0x01030116, 0x0102011d, /* General testing */
- 0x011101a4, 0x018601a4, /* 1Gbps testing */
- 0x014201a0, 0x010001a3, /* 1Gbps testing */
- 0x0101011f, /* 1Gbps testing */
-};
-
-static const u32 phtw2[] = {
- 0x010c0130, 0x010c0140, /* General testing */
- 0x010c0150, 0x010c0180, /* General testing */
- 0x010c0190,
- 0x010a0160, 0x010a0170,
- 0x01800164, 0x01800174, /* 1Gbps testing */
-};
-
static const u32 hsfreqrange_table[][2] = {
- { 80000000U, 0x00 }, { 90000000U, 0x10 }, { 100000000U, 0x20 },
- { 110000000U, 0x30 }, { 120000000U, 0x01 }, { 130000000U, 0x11 },
- { 140000000U, 0x21 }, { 150000000U, 0x31 }, { 160000000U, 0x02 },
- { 170000000U, 0x12 }, { 180000000U, 0x22 }, { 190000000U, 0x32 },
- { 205000000U, 0x03 }, { 220000000U, 0x13 }, { 235000000U, 0x23 },
- { 250000000U, 0x33 }, { 275000000U, 0x04 }, { 300000000U, 0x14 },
- { 325000000U, 0x25 }, { 350000000U, 0x35 }, { 400000000U, 0x05 },
- { 450000000U, 0x16 }, { 500000000U, 0x26 }, { 550000000U, 0x37 },
- { 600000000U, 0x07 }, { 650000000U, 0x18 }, { 700000000U, 0x28 },
- { 750000000U, 0x39 }, { 800000000U, 0x09 }, { 850000000U, 0x19 },
- { 900000000U, 0x29 }, { 950000000U, 0x3a }, { 1000000000U, 0x0a },
- { 1050000000U, 0x1a }, { 1100000000U, 0x2a }, { 1150000000U, 0x3b },
- { 1200000000U, 0x0b }, { 1250000000U, 0x1b }, { 1300000000U, 0x2b },
- { 1350000000U, 0x3c }, { 1400000000U, 0x0c }, { 1450000000U, 0x1c },
- { 1500000000U, 0x2c }, { 1550000000U, 0x3d }, { 1600000000U, 0x0d },
- { 1650000000U, 0x1d }, { 1700000000U, 0x2e }, { 1750000000U, 0x3e },
- { 1800000000U, 0x0e }, { 1850000000U, 0x1e }, { 1900000000U, 0x2f },
- { 1950000000U, 0x3f }, { 2000000000U, 0x0f }, { 2050000000U, 0x40 },
- { 2100000000U, 0x41 }, { 2150000000U, 0x42 }, { 2200000000U, 0x43 },
- { 2250000000U, 0x44 }, { 2300000000U, 0x45 }, { 2350000000U, 0x46 },
- { 2400000000U, 0x47 }, { 2450000000U, 0x48 }, { 2500000000U, 0x49 },
+ { MHZ(80), 0x00 }, { MHZ(90), 0x10 }, { MHZ(100), 0x20 },
+ { MHZ(110), 0x30 }, { MHZ(120), 0x01 }, { MHZ(130), 0x11 },
+ { MHZ(140), 0x21 }, { MHZ(150), 0x31 }, { MHZ(160), 0x02 },
+ { MHZ(170), 0x12 }, { MHZ(180), 0x22 }, { MHZ(190), 0x32 },
+ { MHZ(205), 0x03 }, { MHZ(220), 0x13 }, { MHZ(235), 0x23 },
+ { MHZ(250), 0x33 }, { MHZ(275), 0x04 }, { MHZ(300), 0x14 },
+ { MHZ(325), 0x25 }, { MHZ(350), 0x35 }, { MHZ(400), 0x05 },
+ { MHZ(450), 0x16 }, { MHZ(500), 0x26 }, { MHZ(550), 0x37 },
+ { MHZ(600), 0x07 }, { MHZ(650), 0x18 }, { MHZ(700), 0x28 },
+ { MHZ(750), 0x39 }, { MHZ(800), 0x09 }, { MHZ(850), 0x19 },
+ { MHZ(900), 0x29 }, { MHZ(950), 0x3a }, { MHZ(1000), 0x0a },
+ { MHZ(1050), 0x1a }, { MHZ(1100), 0x2a }, { MHZ(1150), 0x3b },
+ { MHZ(1200), 0x0b }, { MHZ(1250), 0x1b }, { MHZ(1300), 0x2b },
+ { MHZ(1350), 0x3c }, { MHZ(1400), 0x0c }, { MHZ(1450), 0x1c },
+ { MHZ(1500), 0x2c }, { MHZ(1550), 0x3d }, { MHZ(1600), 0x0d },
+ { MHZ(1650), 0x1d }, { MHZ(1700), 0x2e }, { MHZ(1750), 0x3e },
+ { MHZ(1800), 0x0e }, { MHZ(1850), 0x1e }, { MHZ(1900), 0x2f },
+ { MHZ(1950), 0x3f }, { MHZ(2000), 0x0f }, { MHZ(2050), 0x40 },
+ { MHZ(2100), 0x41 }, { MHZ(2150), 0x42 }, { MHZ(2200), 0x43 },
+ { MHZ(2250), 0x44 }, { MHZ(2300), 0x45 }, { MHZ(2350), 0x46 },
+ { MHZ(2400), 0x47 }, { MHZ(2450), 0x48 }, { MHZ(2500), 0x49 },
{ /* sentinel */ },
};
-struct vco_cntrl_value {
+struct dsi_clk_config {
u32 min_freq;
u32 max_freq;
- u16 value;
+ u8 vco_cntrl;
+ u8 cpbias_cntrl;
+ u8 gmp_cntrl;
+ u8 int_cntrl;
+ u8 prop_cntrl;
};
-static const struct vco_cntrl_value vco_cntrl_table[] = {
- { .min_freq = 40000000U, .max_freq = 55000000U, .value = 0x3f },
- { .min_freq = 52500000U, .max_freq = 80000000U, .value = 0x39 },
- { .min_freq = 80000000U, .max_freq = 110000000U, .value = 0x2f },
- { .min_freq = 105000000U, .max_freq = 160000000U, .value = 0x29 },
- { .min_freq = 160000000U, .max_freq = 220000000U, .value = 0x1f },
- { .min_freq = 210000000U, .max_freq = 320000000U, .value = 0x19 },
- { .min_freq = 320000000U, .max_freq = 440000000U, .value = 0x0f },
- { .min_freq = 420000000U, .max_freq = 660000000U, .value = 0x09 },
- { .min_freq = 630000000U, .max_freq = 1149000000U, .value = 0x03 },
- { .min_freq = 1100000000U, .max_freq = 1152000000U, .value = 0x01 },
- { .min_freq = 1150000000U, .max_freq = 1250000000U, .value = 0x01 },
+static const struct dsi_clk_config dsi_clk_cfg_v3u[] = {
+ { MHZ(40), MHZ(55), 0x3f, 0x10, 0x01, 0x00, 0x0b },
+ { MHZ(52.5), MHZ(80), 0x39, 0x10, 0x01, 0x00, 0x0b },
+ { MHZ(80), MHZ(110), 0x2f, 0x10, 0x01, 0x00, 0x0b },
+ { MHZ(105), MHZ(160), 0x29, 0x10, 0x01, 0x00, 0x0b },
+ { MHZ(160), MHZ(220), 0x1f, 0x10, 0x01, 0x00, 0x0b },
+ { MHZ(210), MHZ(320), 0x19, 0x10, 0x01, 0x00, 0x0b },
+ { MHZ(320), MHZ(440), 0x0f, 0x10, 0x01, 0x00, 0x0b },
+ { MHZ(420), MHZ(660), 0x09, 0x10, 0x01, 0x00, 0x0b },
+ { MHZ(630), MHZ(1149), 0x03, 0x10, 0x01, 0x00, 0x0b },
+ { MHZ(1100), MHZ(1152), 0x01, 0x10, 0x01, 0x00, 0x0b },
+ { MHZ(1150), MHZ(1250), 0x01, 0x10, 0x01, 0x00, 0x0c },
+ { /* sentinel */ },
+};
+
+static const struct dsi_clk_config dsi_clk_cfg_v4h[] = {
+ { MHZ(40), MHZ(45.31), 0x2b, 0x00, 0x00, 0x08, 0x0a },
+ { MHZ(45.31), MHZ(54.66), 0x28, 0x00, 0x00, 0x08, 0x0a },
+ { MHZ(54.66), MHZ(62.5), 0x28, 0x00, 0x00, 0x08, 0x0a },
+ { MHZ(62.5), MHZ(75), 0x27, 0x00, 0x00, 0x08, 0x0a },
+ { MHZ(75), MHZ(90.63), 0x23, 0x00, 0x00, 0x08, 0x0a },
+ { MHZ(90.63), MHZ(109.37), 0x20, 0x00, 0x00, 0x08, 0x0a },
+ { MHZ(109.37), MHZ(125), 0x20, 0x00, 0x00, 0x08, 0x0a },
+ { MHZ(125), MHZ(150), 0x1f, 0x00, 0x00, 0x08, 0x0a },
+ { MHZ(150), MHZ(181.25), 0x1b, 0x00, 0x00, 0x08, 0x0a },
+ { MHZ(181.25), MHZ(218.75), 0x18, 0x00, 0x00, 0x08, 0x0a },
+ { MHZ(218.75), MHZ(250), 0x18, 0x00, 0x00, 0x08, 0x0a },
+ { MHZ(250), MHZ(300), 0x17, 0x00, 0x00, 0x08, 0x0a },
+ { MHZ(300), MHZ(362.5), 0x13, 0x00, 0x00, 0x08, 0x0a },
+ { MHZ(362.5), MHZ(455.48), 0x10, 0x00, 0x00, 0x08, 0x0a },
+ { MHZ(455.48), MHZ(500), 0x10, 0x00, 0x00, 0x08, 0x0a },
+ { MHZ(500), MHZ(600), 0x0f, 0x00, 0x00, 0x08, 0x0a },
+ { MHZ(600), MHZ(725), 0x0b, 0x00, 0x00, 0x08, 0x0a },
+ { MHZ(725), MHZ(875), 0x08, 0x00, 0x00, 0x08, 0x0a },
+ { MHZ(875), MHZ(1000), 0x08, 0x00, 0x00, 0x08, 0x0a },
+ { MHZ(1000), MHZ(1200), 0x07, 0x00, 0x00, 0x08, 0x0a },
+ { MHZ(1200), MHZ(1250), 0x03, 0x00, 0x00, 0x08, 0x0a },
{ /* sentinel */ },
};
@@ -144,7 +194,7 @@ static void rcar_mipi_dsi_set(struct rcar_mipi_dsi *dsi, u32 reg, u32 set)
rcar_mipi_dsi_write(dsi, reg, rcar_mipi_dsi_read(dsi, reg) | set);
}
-static int rcar_mipi_dsi_phtw_test(struct rcar_mipi_dsi *dsi, u32 phtw)
+static int rcar_mipi_dsi_write_phtw(struct rcar_mipi_dsi *dsi, u32 phtw)
{
u32 status;
int ret;
@@ -163,32 +213,181 @@ static int rcar_mipi_dsi_phtw_test(struct rcar_mipi_dsi *dsi, u32 phtw)
return ret;
}
+static int rcar_mipi_dsi_write_phtw_arr(struct rcar_mipi_dsi *dsi,
+ const u32 *phtw, unsigned int size)
+{
+ for (unsigned int i = 0; i < size; i++) {
+ int ret = rcar_mipi_dsi_write_phtw(dsi, phtw[i]);
+
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+#define WRITE_PHTW(...) \
+ ({ \
+ static const u32 phtw[] = { __VA_ARGS__ }; \
+ int ret; \
+ ret = rcar_mipi_dsi_write_phtw_arr(dsi, phtw, \
+ ARRAY_SIZE(phtw)); \
+ ret; \
+ })
+
+static int rcar_mipi_dsi_init_phtw_v3u(struct rcar_mipi_dsi *dsi)
+{
+ return WRITE_PHTW(0x01020114, 0x01600115, 0x01030116, 0x0102011d,
+ 0x011101a4, 0x018601a4, 0x014201a0, 0x010001a3,
+ 0x0101011f);
+}
+
+static int rcar_mipi_dsi_post_init_phtw_v3u(struct rcar_mipi_dsi *dsi)
+{
+ return WRITE_PHTW(0x010c0130, 0x010c0140, 0x010c0150, 0x010c0180,
+ 0x010c0190, 0x010a0160, 0x010a0170, 0x01800164,
+ 0x01800174);
+}
+
+static int rcar_mipi_dsi_init_phtw_v4h(struct rcar_mipi_dsi *dsi,
+ const struct dsi_setup_info *setup_info)
+{
+ int ret;
+
+ if (setup_info->hsfreq < MHZ(450)) {
+ ret = WRITE_PHTW(0x01010100, 0x011b01ac);
+ if (ret)
+ return ret;
+ }
+
+ ret = WRITE_PHTW(0x01010100, 0x01030173, 0x01000174, 0x01500175,
+ 0x01030176, 0x01040166, 0x010201ad);
+ if (ret)
+ return ret;
+
+ if (setup_info->hsfreq <= MHZ(1000))
+ ret = WRITE_PHTW(0x01020100, 0x01910170, 0x01020171,
+ 0x01110172);
+ else if (setup_info->hsfreq <= MHZ(1500))
+ ret = WRITE_PHTW(0x01020100, 0x01980170, 0x01030171,
+ 0x01100172);
+ else if (setup_info->hsfreq <= MHZ(2500))
+ ret = WRITE_PHTW(0x01020100, 0x0144016b, 0x01000172);
+ else
+ return -EINVAL;
+
+ if (ret)
+ return ret;
+
+ if (dsi->lanes <= 1) {
+ ret = WRITE_PHTW(0x01070100, 0x010e010b);
+ if (ret)
+ return ret;
+ }
+
+ if (dsi->lanes <= 2) {
+ ret = WRITE_PHTW(0x01090100, 0x010e010b);
+ if (ret)
+ return ret;
+ }
+
+ if (dsi->lanes <= 3) {
+ ret = WRITE_PHTW(0x010b0100, 0x010e010b);
+ if (ret)
+ return ret;
+ }
+
+ if (setup_info->hsfreq <= MHZ(1500)) {
+ ret = WRITE_PHTW(0x01010100, 0x01c0016e);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+rcar_mipi_dsi_post_init_phtw_v4h(struct rcar_mipi_dsi *dsi,
+ const struct dsi_setup_info *setup_info)
+{
+ u32 status;
+ int ret;
+
+ if (setup_info->hsfreq <= MHZ(1500)) {
+ WRITE_PHTW(0x01020100, 0x00000180);
+
+ ret = read_poll_timeout(rcar_mipi_dsi_read, status,
+ status & PHTR_TEST, 2000, 10000, false,
+ dsi, PHTR);
+ if (ret < 0) {
+ dev_err(dsi->dev, "failed to test PHTR\n");
+ return ret;
+ }
+
+ WRITE_PHTW(0x01010100, 0x0100016e);
+ }
+
+ return 0;
+}
+
/* -----------------------------------------------------------------------------
* Hardware Setup
*/
-struct dsi_setup_info {
- unsigned long fout;
- u16 vco_cntrl;
- u16 prop_cntrl;
- u16 hsfreqrange;
- u16 div;
- unsigned int m;
- unsigned int n;
-};
+static void rcar_mipi_dsi_pll_calc(struct rcar_mipi_dsi *dsi,
+ unsigned long fin_rate,
+ unsigned long fout_target,
+ struct dsi_setup_info *setup_info)
+{
+ unsigned int best_err = -1;
+ const struct rcar_mipi_dsi_device_info *info = dsi->info;
+
+ for (unsigned int n = info->n_min; n <= info->n_max; n++) {
+ unsigned long fpfd;
+
+ fpfd = fin_rate / n;
+
+ if (fpfd < info->fpfd_min || fpfd > info->fpfd_max)
+ continue;
+
+ for (unsigned int m = info->m_min; m <= info->m_max; m++) {
+ unsigned int err;
+ u64 fout;
+
+ fout = div64_u64((u64)fpfd * m, dsi->info->n_mul);
+
+ if (fout < info->fout_min || fout > info->fout_max)
+ continue;
+
+ fout = div64_u64(fout, setup_info->vclk_divider);
+
+ if (fout < setup_info->clkset->min_freq ||
+ fout > setup_info->clkset->max_freq)
+ continue;
+
+ err = abs((long)(fout - fout_target) * 10000 /
+ (long)fout_target);
+ if (err < best_err) {
+ setup_info->m = m;
+ setup_info->n = n;
+ setup_info->fout = (unsigned long)fout;
+ best_err = err;
+
+ if (err == 0)
+ return;
+ }
+ }
+ }
+}
static void rcar_mipi_dsi_parameters_calc(struct rcar_mipi_dsi *dsi,
struct clk *clk, unsigned long target,
struct dsi_setup_info *setup_info)
{
- const struct vco_cntrl_value *vco_cntrl;
+ const struct dsi_clk_config *clk_cfg;
unsigned long fout_target;
- unsigned long fin, fout;
- unsigned long hsfreq;
- unsigned int best_err = -1;
- unsigned int divider;
- unsigned int n;
+ unsigned long fin_rate;
unsigned int i;
unsigned int err;
@@ -198,70 +397,53 @@ static void rcar_mipi_dsi_parameters_calc(struct rcar_mipi_dsi *dsi,
*/
fout_target = target * mipi_dsi_pixel_format_to_bpp(dsi->format)
/ (2 * dsi->lanes);
- if (fout_target < 40000000 || fout_target > 1250000000)
+ if (fout_target < MHZ(40) || fout_target > MHZ(1250))
return;
- /* Find vco_cntrl */
- for (vco_cntrl = vco_cntrl_table; vco_cntrl->min_freq != 0; vco_cntrl++) {
- if (fout_target > vco_cntrl->min_freq &&
- fout_target <= vco_cntrl->max_freq) {
- setup_info->vco_cntrl = vco_cntrl->value;
- if (fout_target >= 1150000000)
- setup_info->prop_cntrl = 0x0c;
- else
- setup_info->prop_cntrl = 0x0b;
+ /* Find PLL settings */
+ for (clk_cfg = dsi->info->clk_cfg; clk_cfg->min_freq != 0; clk_cfg++) {
+ if (fout_target > clk_cfg->min_freq &&
+ fout_target <= clk_cfg->max_freq) {
+ setup_info->clkset = clk_cfg;
break;
}
}
- /* Add divider */
- setup_info->div = (setup_info->vco_cntrl & 0x30) >> 4;
+ fin_rate = clk_get_rate(clk);
+
+ switch (dsi->info->model) {
+ case RCAR_DSI_V3U:
+ default:
+ setup_info->vclk_divider = 1 << ((clk_cfg->vco_cntrl >> 4) & 0x3);
+ break;
+
+ case RCAR_DSI_V4H:
+ setup_info->vclk_divider = 1 << (((clk_cfg->vco_cntrl >> 3) & 0x7) + 1);
+ break;
+ }
+
+ rcar_mipi_dsi_pll_calc(dsi, fin_rate, fout_target, setup_info);
/* Find hsfreqrange */
- hsfreq = fout_target * 2;
+ setup_info->hsfreq = setup_info->fout * 2;
for (i = 0; i < ARRAY_SIZE(hsfreqrange_table); i++) {
- if (hsfreqrange_table[i][0] >= hsfreq) {
+ if (hsfreqrange_table[i][0] >= setup_info->hsfreq) {
setup_info->hsfreqrange = hsfreqrange_table[i][1];
break;
}
}
- /*
- * Calculate n and m for PLL clock
- * Following the HW manual the ranges of n and m are
- * n = [3-8] and m = [64-625]
- */
- fin = clk_get_rate(clk);
- divider = 1 << setup_info->div;
- for (n = 3; n < 9; n++) {
- unsigned long fpfd;
- unsigned int m;
-
- fpfd = fin / n;
-
- for (m = 64; m < 626; m++) {
- fout = fpfd * m / divider;
- err = abs((long)(fout - fout_target) * 10000 /
- (long)fout_target);
- if (err < best_err) {
- setup_info->m = m - 2;
- setup_info->n = n - 1;
- setup_info->fout = fout;
- best_err = err;
- if (err == 0)
- goto done;
- }
- }
- }
+ err = abs((long)(setup_info->fout - fout_target) * 10000 / (long)fout_target);
-done:
dev_dbg(dsi->dev,
- "%pC %lu Hz -> Fout %lu Hz (target %lu Hz, error %d.%02u%%), PLL M/N/DIV %u/%u/%u\n",
- clk, fin, setup_info->fout, fout_target, best_err / 100,
- best_err % 100, setup_info->m, setup_info->n, setup_info->div);
+ "Fout = %u * %lu / (%u * %u * %u) = %lu (target %lu Hz, error %d.%02u%%)\n",
+ setup_info->m, fin_rate, dsi->info->n_mul, setup_info->n,
+ setup_info->vclk_divider, setup_info->fout, fout_target,
+ err / 100, err % 100);
+
dev_dbg(dsi->dev,
"vco_cntrl = 0x%x\tprop_cntrl = 0x%x\thsfreqrange = 0x%x\n",
- setup_info->vco_cntrl, setup_info->prop_cntrl,
+ clk_cfg->vco_cntrl, clk_cfg->prop_cntrl,
setup_info->hsfreqrange);
}
@@ -324,7 +506,7 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
{
struct dsi_setup_info setup_info = {};
unsigned int timeout;
- int ret, i;
+ int ret;
int dsi_format;
u32 phy_setup;
u32 clockset2, clockset3;
@@ -360,10 +542,19 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
phy_setup |= PHYSETUP_HSFREQRANGE(setup_info.hsfreqrange);
rcar_mipi_dsi_write(dsi, PHYSETUP, phy_setup);
- for (i = 0; i < ARRAY_SIZE(phtw); i++) {
- ret = rcar_mipi_dsi_phtw_test(dsi, phtw[i]);
+ switch (dsi->info->model) {
+ case RCAR_DSI_V3U:
+ default:
+ ret = rcar_mipi_dsi_init_phtw_v3u(dsi);
if (ret < 0)
return ret;
+ break;
+
+ case RCAR_DSI_V4H:
+ ret = rcar_mipi_dsi_init_phtw_v4h(dsi, &setup_info);
+ if (ret < 0)
+ return ret;
+ break;
}
/* PLL Clock Setting */
@@ -371,12 +562,13 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
rcar_mipi_dsi_set(dsi, CLOCKSET1, CLOCKSET1_SHADOW_CLEAR);
rcar_mipi_dsi_clr(dsi, CLOCKSET1, CLOCKSET1_SHADOW_CLEAR);
- clockset2 = CLOCKSET2_M(setup_info.m) | CLOCKSET2_N(setup_info.n)
- | CLOCKSET2_VCO_CNTRL(setup_info.vco_cntrl);
- clockset3 = CLOCKSET3_PROP_CNTRL(setup_info.prop_cntrl)
- | CLOCKSET3_INT_CNTRL(0)
- | CLOCKSET3_CPBIAS_CNTRL(0x10)
- | CLOCKSET3_GMP_CNTRL(1);
+ clockset2 = CLOCKSET2_M(setup_info.m - dsi->info->clockset2_m_offset)
+ | CLOCKSET2_N(setup_info.n - 1)
+ | CLOCKSET2_VCO_CNTRL(setup_info.clkset->vco_cntrl);
+ clockset3 = CLOCKSET3_PROP_CNTRL(setup_info.clkset->prop_cntrl)
+ | CLOCKSET3_INT_CNTRL(setup_info.clkset->int_cntrl)
+ | CLOCKSET3_CPBIAS_CNTRL(setup_info.clkset->cpbias_cntrl)
+ | CLOCKSET3_GMP_CNTRL(setup_info.clkset->gmp_cntrl);
rcar_mipi_dsi_write(dsi, CLOCKSET2, clockset2);
rcar_mipi_dsi_write(dsi, CLOCKSET3, clockset3);
@@ -407,10 +599,19 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
return -ETIMEDOUT;
}
- for (i = 0; i < ARRAY_SIZE(phtw2); i++) {
- ret = rcar_mipi_dsi_phtw_test(dsi, phtw2[i]);
+ switch (dsi->info->model) {
+ case RCAR_DSI_V3U:
+ default:
+ ret = rcar_mipi_dsi_post_init_phtw_v3u(dsi);
+ if (ret < 0)
+ return ret;
+ break;
+
+ case RCAR_DSI_V4H:
+ ret = rcar_mipi_dsi_post_init_phtw_v4h(dsi, &setup_info);
if (ret < 0)
return ret;
+ break;
}
/* Enable DOT clock */
@@ -427,8 +628,19 @@ static int rcar_mipi_dsi_startup(struct rcar_mipi_dsi *dsi,
dev_warn(dsi->dev, "unsupported format");
return -EINVAL;
}
- vclkset |= VCLKSET_COLOR_RGB | VCLKSET_DIV(setup_info.div)
- | VCLKSET_LANE(dsi->lanes - 1);
+
+ vclkset |= VCLKSET_COLOR_RGB | VCLKSET_LANE(dsi->lanes - 1);
+
+ switch (dsi->info->model) {
+ case RCAR_DSI_V3U:
+ default:
+ vclkset |= VCLKSET_DIV_V3U(__ffs(setup_info.vclk_divider));
+ break;
+
+ case RCAR_DSI_V4H:
+ vclkset |= VCLKSET_DIV_V4H(__ffs(setup_info.vclk_divider) - 1);
+ break;
+ }
rcar_mipi_dsi_write(dsi, VCLKSET, vclkset);
@@ -841,8 +1053,39 @@ static int rcar_mipi_dsi_remove(struct platform_device *pdev)
return 0;
}
+static const struct rcar_mipi_dsi_device_info v3u_data = {
+ .model = RCAR_DSI_V3U,
+ .clk_cfg = dsi_clk_cfg_v3u,
+ .clockset2_m_offset = 2,
+ .n_min = 3,
+ .n_max = 8,
+ .n_mul = 1,
+ .fpfd_min = MHZ(2),
+ .fpfd_max = MHZ(8),
+ .m_min = 64,
+ .m_max = 625,
+ .fout_min = MHZ(320),
+ .fout_max = MHZ(1250),
+};
+
+static const struct rcar_mipi_dsi_device_info v4h_data = {
+ .model = RCAR_DSI_V4H,
+ .clk_cfg = dsi_clk_cfg_v4h,
+ .clockset2_m_offset = 0,
+ .n_min = 1,
+ .n_max = 8,
+ .n_mul = 2,
+ .fpfd_min = MHZ(8),
+ .fpfd_max = MHZ(24),
+ .m_min = 167,
+ .m_max = 1000,
+ .fout_min = MHZ(2000),
+ .fout_max = MHZ(4000),
+};
+
static const struct of_device_id rcar_mipi_dsi_of_table[] = {
- { .compatible = "renesas,r8a779a0-dsi-csi2-tx" },
+ { .compatible = "renesas,r8a779a0-dsi-csi2-tx", .data = &v3u_data },
+ { .compatible = "renesas,r8a779g0-dsi-csi2-tx", .data = &v4h_data },
{ }
};
diff --git a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h
index 2eaca54636f3..f8114d11f2d1 100644
--- a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h
+++ b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h
@@ -122,7 +122,8 @@
#define VCLKSET_CKEN (1 << 16)
#define VCLKSET_COLOR_RGB (0 << 8)
#define VCLKSET_COLOR_YCC (1 << 8)
-#define VCLKSET_DIV(x) (((x) & 0x3) << 4)
+#define VCLKSET_DIV_V3U(x) (((x) & 0x3) << 4)
+#define VCLKSET_DIV_V4H(x) (((x) & 0x7) << 4)
#define VCLKSET_BPP_16 (0 << 2)
#define VCLKSET_BPP_18 (1 << 2)
#define VCLKSET_BPP_18L (2 << 2)
@@ -166,6 +167,9 @@
#define PHTW_CWEN (1 << 8)
#define PHTW_TESTDIN_CODE(x) (((x) & 0xff) << 0)
+#define PHTR 0x1038
+#define PHTR_TEST (1 << 16)
+
#define PHTC 0x103c
#define PHTC_TESTCLR (1 << 0)
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
index 6edb7c52cb3d..8ea09d915c3c 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
@@ -251,8 +251,7 @@ static int rockchip_drm_gem_object_mmap(struct drm_gem_object *obj,
* We allocated a struct page table for rk_obj, so clear
* VM_PFNMAP flag that was set by drm_gem_mmap_obj()/drm_gem_mmap().
*/
- vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
- vma->vm_flags &= ~VM_PFNMAP;
+ vm_flags_mod(vma, VM_IO | VM_DONTEXPAND | VM_DONTDUMP, VM_PFNMAP);
vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index 8cecf81a5ae0..ba3b81789509 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -25,7 +25,6 @@
#include <drm/drm_atomic_uapi.h>
#include <drm/drm_blend.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_debugfs.h>
#include <drm/drm_flip_work.h>
#include <drm/drm_framebuffer.h>
diff --git a/drivers/gpu/drm/savage/Makefile b/drivers/gpu/drm/savage/Makefile
deleted file mode 100644
index 3e520763d259..000000000000
--- a/drivers/gpu/drm/savage/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Makefile for the drm device driver. This driver provides support for the
-# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
-
-savage-y := savage_drv.o savage_bci.o savage_state.o
-
-obj-$(CONFIG_DRM_SAVAGE)+= savage.o
-
diff --git a/drivers/gpu/drm/savage/savage_bci.c b/drivers/gpu/drm/savage/savage_bci.c
deleted file mode 100644
index e33385dfe3ed..000000000000
--- a/drivers/gpu/drm/savage/savage_bci.c
+++ /dev/null
@@ -1,1082 +0,0 @@
-/* savage_bci.c -- BCI support for Savage
- *
- * Copyright 2004 Felix Kuehling
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software 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, sub license,
- * 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 (including the
- * next paragraph) 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
- * NON-INFRINGEMENT. IN NO EVENT SHALL FELIX KUEHLING 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.
- */
-
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-#include <linux/uaccess.h>
-
-#include <drm/drm_device.h>
-#include <drm/drm_file.h>
-#include <drm/drm_print.h>
-#include <drm/savage_drm.h>
-
-#include "savage_drv.h"
-
-/* Need a long timeout for shadow status updates can take a while
- * and so can waiting for events when the queue is full. */
-#define SAVAGE_DEFAULT_USEC_TIMEOUT 1000000 /* 1s */
-#define SAVAGE_EVENT_USEC_TIMEOUT 5000000 /* 5s */
-#define SAVAGE_FREELIST_DEBUG 0
-
-static int savage_do_cleanup_bci(struct drm_device *dev);
-
-static int
-savage_bci_wait_fifo_shadow(drm_savage_private_t * dev_priv, unsigned int n)
-{
- uint32_t mask = dev_priv->status_used_mask;
- uint32_t threshold = dev_priv->bci_threshold_hi;
- uint32_t status;
- int i;
-
-#if SAVAGE_BCI_DEBUG
- if (n > dev_priv->cob_size + SAVAGE_BCI_FIFO_SIZE - threshold)
- DRM_ERROR("Trying to emit %d words "
- "(more than guaranteed space in COB)\n", n);
-#endif
-
- for (i = 0; i < SAVAGE_DEFAULT_USEC_TIMEOUT; i++) {
- mb();
- status = dev_priv->status_ptr[0];
- if ((status & mask) < threshold)
- return 0;
- udelay(1);
- }
-
-#if SAVAGE_BCI_DEBUG
- DRM_ERROR("failed!\n");
- DRM_INFO(" status=0x%08x, threshold=0x%08x\n", status, threshold);
-#endif
- return -EBUSY;
-}
-
-static int
-savage_bci_wait_fifo_s3d(drm_savage_private_t * dev_priv, unsigned int n)
-{
- uint32_t maxUsed = dev_priv->cob_size + SAVAGE_BCI_FIFO_SIZE - n;
- uint32_t status;
- int i;
-
- for (i = 0; i < SAVAGE_DEFAULT_USEC_TIMEOUT; i++) {
- status = SAVAGE_READ(SAVAGE_STATUS_WORD0);
- if ((status & SAVAGE_FIFO_USED_MASK_S3D) <= maxUsed)
- return 0;
- udelay(1);
- }
-
-#if SAVAGE_BCI_DEBUG
- DRM_ERROR("failed!\n");
- DRM_INFO(" status=0x%08x\n", status);
-#endif
- return -EBUSY;
-}
-
-static int
-savage_bci_wait_fifo_s4(drm_savage_private_t * dev_priv, unsigned int n)
-{
- uint32_t maxUsed = dev_priv->cob_size + SAVAGE_BCI_FIFO_SIZE - n;
- uint32_t status;
- int i;
-
- for (i = 0; i < SAVAGE_DEFAULT_USEC_TIMEOUT; i++) {
- status = SAVAGE_READ(SAVAGE_ALT_STATUS_WORD0);
- if ((status & SAVAGE_FIFO_USED_MASK_S4) <= maxUsed)
- return 0;
- udelay(1);
- }
-
-#if SAVAGE_BCI_DEBUG
- DRM_ERROR("failed!\n");
- DRM_INFO(" status=0x%08x\n", status);
-#endif
- return -EBUSY;
-}
-
-/*
- * Waiting for events.
- *
- * The BIOSresets the event tag to 0 on mode changes. Therefore we
- * never emit 0 to the event tag. If we find a 0 event tag we know the
- * BIOS stomped on it and return success assuming that the BIOS waited
- * for engine idle.
- *
- * Note: if the Xserver uses the event tag it has to follow the same
- * rule. Otherwise there may be glitches every 2^16 events.
- */
-static int
-savage_bci_wait_event_shadow(drm_savage_private_t * dev_priv, uint16_t e)
-{
- uint32_t status;
- int i;
-
- for (i = 0; i < SAVAGE_EVENT_USEC_TIMEOUT; i++) {
- mb();
- status = dev_priv->status_ptr[1];
- if ((((status & 0xffff) - e) & 0xffff) <= 0x7fff ||
- (status & 0xffff) == 0)
- return 0;
- udelay(1);
- }
-
-#if SAVAGE_BCI_DEBUG
- DRM_ERROR("failed!\n");
- DRM_INFO(" status=0x%08x, e=0x%04x\n", status, e);
-#endif
-
- return -EBUSY;
-}
-
-static int
-savage_bci_wait_event_reg(drm_savage_private_t * dev_priv, uint16_t e)
-{
- uint32_t status;
- int i;
-
- for (i = 0; i < SAVAGE_EVENT_USEC_TIMEOUT; i++) {
- status = SAVAGE_READ(SAVAGE_STATUS_WORD1);
- if ((((status & 0xffff) - e) & 0xffff) <= 0x7fff ||
- (status & 0xffff) == 0)
- return 0;
- udelay(1);
- }
-
-#if SAVAGE_BCI_DEBUG
- DRM_ERROR("failed!\n");
- DRM_INFO(" status=0x%08x, e=0x%04x\n", status, e);
-#endif
-
- return -EBUSY;
-}
-
-uint16_t savage_bci_emit_event(drm_savage_private_t * dev_priv,
- unsigned int flags)
-{
- uint16_t count;
- BCI_LOCALS;
-
- if (dev_priv->status_ptr) {
- /* coordinate with Xserver */
- count = dev_priv->status_ptr[1023];
- if (count < dev_priv->event_counter)
- dev_priv->event_wrap++;
- } else {
- count = dev_priv->event_counter;
- }
- count = (count + 1) & 0xffff;
- if (count == 0) {
- count++; /* See the comment above savage_wait_event_*. */
- dev_priv->event_wrap++;
- }
- dev_priv->event_counter = count;
- if (dev_priv->status_ptr)
- dev_priv->status_ptr[1023] = (uint32_t) count;
-
- if ((flags & (SAVAGE_WAIT_2D | SAVAGE_WAIT_3D))) {
- unsigned int wait_cmd = BCI_CMD_WAIT;
- if ((flags & SAVAGE_WAIT_2D))
- wait_cmd |= BCI_CMD_WAIT_2D;
- if ((flags & SAVAGE_WAIT_3D))
- wait_cmd |= BCI_CMD_WAIT_3D;
- BEGIN_BCI(2);
- BCI_WRITE(wait_cmd);
- } else {
- BEGIN_BCI(1);
- }
- BCI_WRITE(BCI_CMD_UPDATE_EVENT_TAG | (uint32_t) count);
-
- return count;
-}
-
-/*
- * Freelist management
- */
-static int savage_freelist_init(struct drm_device * dev)
-{
- drm_savage_private_t *dev_priv = dev->dev_private;
- struct drm_device_dma *dma = dev->dma;
- struct drm_buf *buf;
- drm_savage_buf_priv_t *entry;
- int i;
- DRM_DEBUG("count=%d\n", dma->buf_count);
-
- dev_priv->head.next = &dev_priv->tail;
- dev_priv->head.prev = NULL;
- dev_priv->head.buf = NULL;
-
- dev_priv->tail.next = NULL;
- dev_priv->tail.prev = &dev_priv->head;
- dev_priv->tail.buf = NULL;
-
- for (i = 0; i < dma->buf_count; i++) {
- buf = dma->buflist[i];
- entry = buf->dev_private;
-
- SET_AGE(&entry->age, 0, 0);
- entry->buf = buf;
-
- entry->next = dev_priv->head.next;
- entry->prev = &dev_priv->head;
- dev_priv->head.next->prev = entry;
- dev_priv->head.next = entry;
- }
-
- return 0;
-}
-
-static struct drm_buf *savage_freelist_get(struct drm_device * dev)
-{
- drm_savage_private_t *dev_priv = dev->dev_private;
- drm_savage_buf_priv_t *tail = dev_priv->tail.prev;
- uint16_t event;
- unsigned int wrap;
- DRM_DEBUG("\n");
-
- UPDATE_EVENT_COUNTER();
- if (dev_priv->status_ptr)
- event = dev_priv->status_ptr[1] & 0xffff;
- else
- event = SAVAGE_READ(SAVAGE_STATUS_WORD1) & 0xffff;
- wrap = dev_priv->event_wrap;
- if (event > dev_priv->event_counter)
- wrap--; /* hardware hasn't passed the last wrap yet */
-
- DRM_DEBUG(" tail=0x%04x %d\n", tail->age.event, tail->age.wrap);
- DRM_DEBUG(" head=0x%04x %d\n", event, wrap);
-
- if (tail->buf && (TEST_AGE(&tail->age, event, wrap) || event == 0)) {
- drm_savage_buf_priv_t *next = tail->next;
- drm_savage_buf_priv_t *prev = tail->prev;
- prev->next = next;
- next->prev = prev;
- tail->next = tail->prev = NULL;
- return tail->buf;
- }
-
- DRM_DEBUG("returning NULL, tail->buf=%p!\n", tail->buf);
- return NULL;
-}
-
-void savage_freelist_put(struct drm_device * dev, struct drm_buf * buf)
-{
- drm_savage_private_t *dev_priv = dev->dev_private;
- drm_savage_buf_priv_t *entry = buf->dev_private, *prev, *next;
-
- DRM_DEBUG("age=0x%04x wrap=%d\n", entry->age.event, entry->age.wrap);
-
- if (entry->next != NULL || entry->prev != NULL) {
- DRM_ERROR("entry already on freelist.\n");
- return;
- }
-
- prev = &dev_priv->head;
- next = prev->next;
- prev->next = entry;
- next->prev = entry;
- entry->prev = prev;
- entry->next = next;
-}
-
-/*
- * Command DMA
- */
-static int savage_dma_init(drm_savage_private_t * dev_priv)
-{
- unsigned int i;
-
- dev_priv->nr_dma_pages = dev_priv->cmd_dma->size /
- (SAVAGE_DMA_PAGE_SIZE * 4);
- dev_priv->dma_pages = kmalloc_array(dev_priv->nr_dma_pages,
- sizeof(drm_savage_dma_page_t),
- GFP_KERNEL);
- if (dev_priv->dma_pages == NULL)
- return -ENOMEM;
-
- for (i = 0; i < dev_priv->nr_dma_pages; ++i) {
- SET_AGE(&dev_priv->dma_pages[i].age, 0, 0);
- dev_priv->dma_pages[i].used = 0;
- dev_priv->dma_pages[i].flushed = 0;
- }
- SET_AGE(&dev_priv->last_dma_age, 0, 0);
-
- dev_priv->first_dma_page = 0;
- dev_priv->current_dma_page = 0;
-
- return 0;
-}
-
-void savage_dma_reset(drm_savage_private_t * dev_priv)
-{
- uint16_t event;
- unsigned int wrap, i;
- event = savage_bci_emit_event(dev_priv, 0);
- wrap = dev_priv->event_wrap;
- for (i = 0; i < dev_priv->nr_dma_pages; ++i) {
- SET_AGE(&dev_priv->dma_pages[i].age, event, wrap);
- dev_priv->dma_pages[i].used = 0;
- dev_priv->dma_pages[i].flushed = 0;
- }
- SET_AGE(&dev_priv->last_dma_age, event, wrap);
- dev_priv->first_dma_page = dev_priv->current_dma_page = 0;
-}
-
-void savage_dma_wait(drm_savage_private_t * dev_priv, unsigned int page)
-{
- uint16_t event;
- unsigned int wrap;
-
- /* Faked DMA buffer pages don't age. */
- if (dev_priv->cmd_dma == &dev_priv->fake_dma)
- return;
-
- UPDATE_EVENT_COUNTER();
- if (dev_priv->status_ptr)
- event = dev_priv->status_ptr[1] & 0xffff;
- else
- event = SAVAGE_READ(SAVAGE_STATUS_WORD1) & 0xffff;
- wrap = dev_priv->event_wrap;
- if (event > dev_priv->event_counter)
- wrap--; /* hardware hasn't passed the last wrap yet */
-
- if (dev_priv->dma_pages[page].age.wrap > wrap ||
- (dev_priv->dma_pages[page].age.wrap == wrap &&
- dev_priv->dma_pages[page].age.event > event)) {
- if (dev_priv->wait_evnt(dev_priv,
- dev_priv->dma_pages[page].age.event)
- < 0)
- DRM_ERROR("wait_evnt failed!\n");
- }
-}
-
-uint32_t *savage_dma_alloc(drm_savage_private_t * dev_priv, unsigned int n)
-{
- unsigned int cur = dev_priv->current_dma_page;
- unsigned int rest = SAVAGE_DMA_PAGE_SIZE -
- dev_priv->dma_pages[cur].used;
- unsigned int nr_pages = (n - rest + SAVAGE_DMA_PAGE_SIZE - 1) /
- SAVAGE_DMA_PAGE_SIZE;
- uint32_t *dma_ptr;
- unsigned int i;
-
- DRM_DEBUG("cur=%u, cur->used=%u, n=%u, rest=%u, nr_pages=%u\n",
- cur, dev_priv->dma_pages[cur].used, n, rest, nr_pages);
-
- if (cur + nr_pages < dev_priv->nr_dma_pages) {
- dma_ptr = (uint32_t *) dev_priv->cmd_dma->handle +
- cur * SAVAGE_DMA_PAGE_SIZE + dev_priv->dma_pages[cur].used;
- if (n < rest)
- rest = n;
- dev_priv->dma_pages[cur].used += rest;
- n -= rest;
- cur++;
- } else {
- dev_priv->dma_flush(dev_priv);
- nr_pages =
- (n + SAVAGE_DMA_PAGE_SIZE - 1) / SAVAGE_DMA_PAGE_SIZE;
- for (i = cur; i < dev_priv->nr_dma_pages; ++i) {
- dev_priv->dma_pages[i].age = dev_priv->last_dma_age;
- dev_priv->dma_pages[i].used = 0;
- dev_priv->dma_pages[i].flushed = 0;
- }
- dma_ptr = (uint32_t *) dev_priv->cmd_dma->handle;
- dev_priv->first_dma_page = cur = 0;
- }
- for (i = cur; nr_pages > 0; ++i, --nr_pages) {
-#if SAVAGE_DMA_DEBUG
- if (dev_priv->dma_pages[i].used) {
- DRM_ERROR("unflushed page %u: used=%u\n",
- i, dev_priv->dma_pages[i].used);
- }
-#endif
- if (n > SAVAGE_DMA_PAGE_SIZE)
- dev_priv->dma_pages[i].used = SAVAGE_DMA_PAGE_SIZE;
- else
- dev_priv->dma_pages[i].used = n;
- n -= SAVAGE_DMA_PAGE_SIZE;
- }
- dev_priv->current_dma_page = --i;
-
- DRM_DEBUG("cur=%u, cur->used=%u, n=%u\n",
- i, dev_priv->dma_pages[i].used, n);
-
- savage_dma_wait(dev_priv, dev_priv->current_dma_page);
-
- return dma_ptr;
-}
-
-static void savage_dma_flush(drm_savage_private_t * dev_priv)
-{
- unsigned int first = dev_priv->first_dma_page;
- unsigned int cur = dev_priv->current_dma_page;
- uint16_t event;
- unsigned int wrap, pad, align, len, i;
- unsigned long phys_addr;
- BCI_LOCALS;
-
- if (first == cur &&
- dev_priv->dma_pages[cur].used == dev_priv->dma_pages[cur].flushed)
- return;
-
- /* pad length to multiples of 2 entries
- * align start of next DMA block to multiles of 8 entries */
- pad = -dev_priv->dma_pages[cur].used & 1;
- align = -(dev_priv->dma_pages[cur].used + pad) & 7;
-
- DRM_DEBUG("first=%u, cur=%u, first->flushed=%u, cur->used=%u, "
- "pad=%u, align=%u\n",
- first, cur, dev_priv->dma_pages[first].flushed,
- dev_priv->dma_pages[cur].used, pad, align);
-
- /* pad with noops */
- if (pad) {
- uint32_t *dma_ptr = (uint32_t *) dev_priv->cmd_dma->handle +
- cur * SAVAGE_DMA_PAGE_SIZE + dev_priv->dma_pages[cur].used;
- dev_priv->dma_pages[cur].used += pad;
- while (pad != 0) {
- *dma_ptr++ = BCI_CMD_WAIT;
- pad--;
- }
- }
-
- mb();
-
- /* do flush ... */
- phys_addr = dev_priv->cmd_dma->offset +
- (first * SAVAGE_DMA_PAGE_SIZE +
- dev_priv->dma_pages[first].flushed) * 4;
- len = (cur - first) * SAVAGE_DMA_PAGE_SIZE +
- dev_priv->dma_pages[cur].used - dev_priv->dma_pages[first].flushed;
-
- DRM_DEBUG("phys_addr=%lx, len=%u\n",
- phys_addr | dev_priv->dma_type, len);
-
- BEGIN_BCI(3);
- BCI_SET_REGISTERS(SAVAGE_DMABUFADDR, 1);
- BCI_WRITE(phys_addr | dev_priv->dma_type);
- BCI_DMA(len);
-
- /* fix alignment of the start of the next block */
- dev_priv->dma_pages[cur].used += align;
-
- /* age DMA pages */
- event = savage_bci_emit_event(dev_priv, 0);
- wrap = dev_priv->event_wrap;
- for (i = first; i < cur; ++i) {
- SET_AGE(&dev_priv->dma_pages[i].age, event, wrap);
- dev_priv->dma_pages[i].used = 0;
- dev_priv->dma_pages[i].flushed = 0;
- }
- /* age the current page only when it's full */
- if (dev_priv->dma_pages[cur].used == SAVAGE_DMA_PAGE_SIZE) {
- SET_AGE(&dev_priv->dma_pages[cur].age, event, wrap);
- dev_priv->dma_pages[cur].used = 0;
- dev_priv->dma_pages[cur].flushed = 0;
- /* advance to next page */
- cur++;
- if (cur == dev_priv->nr_dma_pages)
- cur = 0;
- dev_priv->first_dma_page = dev_priv->current_dma_page = cur;
- } else {
- dev_priv->first_dma_page = cur;
- dev_priv->dma_pages[cur].flushed = dev_priv->dma_pages[i].used;
- }
- SET_AGE(&dev_priv->last_dma_age, event, wrap);
-
- DRM_DEBUG("first=cur=%u, cur->used=%u, cur->flushed=%u\n", cur,
- dev_priv->dma_pages[cur].used,
- dev_priv->dma_pages[cur].flushed);
-}
-
-static void savage_fake_dma_flush(drm_savage_private_t * dev_priv)
-{
- unsigned int i, j;
- BCI_LOCALS;
-
- if (dev_priv->first_dma_page == dev_priv->current_dma_page &&
- dev_priv->dma_pages[dev_priv->current_dma_page].used == 0)
- return;
-
- DRM_DEBUG("first=%u, cur=%u, cur->used=%u\n",
- dev_priv->first_dma_page, dev_priv->current_dma_page,
- dev_priv->dma_pages[dev_priv->current_dma_page].used);
-
- for (i = dev_priv->first_dma_page;
- i <= dev_priv->current_dma_page && dev_priv->dma_pages[i].used;
- ++i) {
- uint32_t *dma_ptr = (uint32_t *) dev_priv->cmd_dma->handle +
- i * SAVAGE_DMA_PAGE_SIZE;
-#if SAVAGE_DMA_DEBUG
- /* Sanity check: all pages except the last one must be full. */
- if (i < dev_priv->current_dma_page &&
- dev_priv->dma_pages[i].used != SAVAGE_DMA_PAGE_SIZE) {
- DRM_ERROR("partial DMA page %u: used=%u",
- i, dev_priv->dma_pages[i].used);
- }
-#endif
- BEGIN_BCI(dev_priv->dma_pages[i].used);
- for (j = 0; j < dev_priv->dma_pages[i].used; ++j) {
- BCI_WRITE(dma_ptr[j]);
- }
- dev_priv->dma_pages[i].used = 0;
- }
-
- /* reset to first page */
- dev_priv->first_dma_page = dev_priv->current_dma_page = 0;
-}
-
-int savage_driver_load(struct drm_device *dev, unsigned long chipset)
-{
- struct pci_dev *pdev = to_pci_dev(dev->dev);
- drm_savage_private_t *dev_priv;
-
- dev_priv = kzalloc(sizeof(drm_savage_private_t), GFP_KERNEL);
- if (dev_priv == NULL)
- return -ENOMEM;
-
- dev->dev_private = (void *)dev_priv;
-
- dev_priv->chipset = (enum savage_family)chipset;
-
- pci_set_master(pdev);
-
- return 0;
-}
-
-
-/*
- * Initialize mappings. On Savage4 and SavageIX the alignment
- * and size of the aperture is not suitable for automatic MTRR setup
- * in drm_legacy_addmap. Therefore we add them manually before the maps are
- * initialized, and tear them down on last close.
- */
-int savage_driver_firstopen(struct drm_device *dev)
-{
- drm_savage_private_t *dev_priv = dev->dev_private;
- struct pci_dev *pdev = to_pci_dev(dev->dev);
- unsigned long mmio_base, fb_base, fb_size, aperture_base;
- int ret = 0;
-
- if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
- fb_base = pci_resource_start(pdev, 0);
- fb_size = SAVAGE_FB_SIZE_S3;
- mmio_base = fb_base + SAVAGE_FB_SIZE_S3;
- aperture_base = fb_base + SAVAGE_APERTURE_OFFSET;
- /* this should always be true */
- if (pci_resource_len(pdev, 0) == 0x08000000) {
- /* Don't make MMIO write-cobining! We need 3
- * MTRRs. */
- dev_priv->mtrr_handles[0] =
- arch_phys_wc_add(fb_base, 0x01000000);
- dev_priv->mtrr_handles[1] =
- arch_phys_wc_add(fb_base + 0x02000000,
- 0x02000000);
- dev_priv->mtrr_handles[2] =
- arch_phys_wc_add(fb_base + 0x04000000,
- 0x04000000);
- } else {
- DRM_ERROR("strange pci_resource_len %08llx\n",
- (unsigned long long)
- pci_resource_len(pdev, 0));
- }
- } else if (dev_priv->chipset != S3_SUPERSAVAGE &&
- dev_priv->chipset != S3_SAVAGE2000) {
- mmio_base = pci_resource_start(pdev, 0);
- fb_base = pci_resource_start(pdev, 1);
- fb_size = SAVAGE_FB_SIZE_S4;
- aperture_base = fb_base + SAVAGE_APERTURE_OFFSET;
- /* this should always be true */
- if (pci_resource_len(pdev, 1) == 0x08000000) {
- /* Can use one MTRR to cover both fb and
- * aperture. */
- dev_priv->mtrr_handles[0] =
- arch_phys_wc_add(fb_base,
- 0x08000000);
- } else {
- DRM_ERROR("strange pci_resource_len %08llx\n",
- (unsigned long long)
- pci_resource_len(pdev, 1));
- }
- } else {
- mmio_base = pci_resource_start(pdev, 0);
- fb_base = pci_resource_start(pdev, 1);
- fb_size = pci_resource_len(pdev, 1);
- aperture_base = pci_resource_start(pdev, 2);
- /* Automatic MTRR setup will do the right thing. */
- }
-
- ret = drm_legacy_addmap(dev, mmio_base, SAVAGE_MMIO_SIZE,
- _DRM_REGISTERS, _DRM_READ_ONLY,
- &dev_priv->mmio);
- if (ret)
- return ret;
-
- ret = drm_legacy_addmap(dev, fb_base, fb_size, _DRM_FRAME_BUFFER,
- _DRM_WRITE_COMBINING, &dev_priv->fb);
- if (ret)
- return ret;
-
- ret = drm_legacy_addmap(dev, aperture_base, SAVAGE_APERTURE_SIZE,
- _DRM_FRAME_BUFFER, _DRM_WRITE_COMBINING,
- &dev_priv->aperture);
- return ret;
-}
-
-/*
- * Delete MTRRs and free device-private data.
- */
-void savage_driver_lastclose(struct drm_device *dev)
-{
- drm_savage_private_t *dev_priv = dev->dev_private;
- int i;
-
- for (i = 0; i < 3; ++i) {
- arch_phys_wc_del(dev_priv->mtrr_handles[i]);
- dev_priv->mtrr_handles[i] = 0;
- }
-}
-
-void savage_driver_unload(struct drm_device *dev)
-{
- drm_savage_private_t *dev_priv = dev->dev_private;
-
- kfree(dev_priv);
-}
-
-static int savage_do_init_bci(struct drm_device * dev, drm_savage_init_t * init)
-{
- drm_savage_private_t *dev_priv = dev->dev_private;
-
- if (init->fb_bpp != 16 && init->fb_bpp != 32) {
- DRM_ERROR("invalid frame buffer bpp %d!\n", init->fb_bpp);
- return -EINVAL;
- }
- if (init->depth_bpp != 16 && init->depth_bpp != 32) {
- DRM_ERROR("invalid depth buffer bpp %d!\n", init->fb_bpp);
- return -EINVAL;
- }
- if (init->dma_type != SAVAGE_DMA_AGP &&
- init->dma_type != SAVAGE_DMA_PCI) {
- DRM_ERROR("invalid dma memory type %d!\n", init->dma_type);
- return -EINVAL;
- }
-
- dev_priv->cob_size = init->cob_size;
- dev_priv->bci_threshold_lo = init->bci_threshold_lo;
- dev_priv->bci_threshold_hi = init->bci_threshold_hi;
- dev_priv->dma_type = init->dma_type;
-
- dev_priv->fb_bpp = init->fb_bpp;
- dev_priv->front_offset = init->front_offset;
- dev_priv->front_pitch = init->front_pitch;
- dev_priv->back_offset = init->back_offset;
- dev_priv->back_pitch = init->back_pitch;
- dev_priv->depth_bpp = init->depth_bpp;
- dev_priv->depth_offset = init->depth_offset;
- dev_priv->depth_pitch = init->depth_pitch;
-
- dev_priv->texture_offset = init->texture_offset;
- dev_priv->texture_size = init->texture_size;
-
- dev_priv->sarea = drm_legacy_getsarea(dev);
- if (!dev_priv->sarea) {
- DRM_ERROR("could not find sarea!\n");
- savage_do_cleanup_bci(dev);
- return -EINVAL;
- }
- if (init->status_offset != 0) {
- dev_priv->status = drm_legacy_findmap(dev, init->status_offset);
- if (!dev_priv->status) {
- DRM_ERROR("could not find shadow status region!\n");
- savage_do_cleanup_bci(dev);
- return -EINVAL;
- }
- } else {
- dev_priv->status = NULL;
- }
- if (dev_priv->dma_type == SAVAGE_DMA_AGP && init->buffers_offset) {
- dev->agp_buffer_token = init->buffers_offset;
- dev->agp_buffer_map = drm_legacy_findmap(dev,
- init->buffers_offset);
- if (!dev->agp_buffer_map) {
- DRM_ERROR("could not find DMA buffer region!\n");
- savage_do_cleanup_bci(dev);
- return -EINVAL;
- }
- drm_legacy_ioremap(dev->agp_buffer_map, dev);
- if (!dev->agp_buffer_map->handle) {
- DRM_ERROR("failed to ioremap DMA buffer region!\n");
- savage_do_cleanup_bci(dev);
- return -ENOMEM;
- }
- }
- if (init->agp_textures_offset) {
- dev_priv->agp_textures =
- drm_legacy_findmap(dev, init->agp_textures_offset);
- if (!dev_priv->agp_textures) {
- DRM_ERROR("could not find agp texture region!\n");
- savage_do_cleanup_bci(dev);
- return -EINVAL;
- }
- } else {
- dev_priv->agp_textures = NULL;
- }
-
- if (init->cmd_dma_offset) {
- if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
- DRM_ERROR("command DMA not supported on "
- "Savage3D/MX/IX.\n");
- savage_do_cleanup_bci(dev);
- return -EINVAL;
- }
- if (dev->dma && dev->dma->buflist) {
- DRM_ERROR("command and vertex DMA not supported "
- "at the same time.\n");
- savage_do_cleanup_bci(dev);
- return -EINVAL;
- }
- dev_priv->cmd_dma = drm_legacy_findmap(dev, init->cmd_dma_offset);
- if (!dev_priv->cmd_dma) {
- DRM_ERROR("could not find command DMA region!\n");
- savage_do_cleanup_bci(dev);
- return -EINVAL;
- }
- if (dev_priv->dma_type == SAVAGE_DMA_AGP) {
- if (dev_priv->cmd_dma->type != _DRM_AGP) {
- DRM_ERROR("AGP command DMA region is not a "
- "_DRM_AGP map!\n");
- savage_do_cleanup_bci(dev);
- return -EINVAL;
- }
- drm_legacy_ioremap(dev_priv->cmd_dma, dev);
- if (!dev_priv->cmd_dma->handle) {
- DRM_ERROR("failed to ioremap command "
- "DMA region!\n");
- savage_do_cleanup_bci(dev);
- return -ENOMEM;
- }
- } else if (dev_priv->cmd_dma->type != _DRM_CONSISTENT) {
- DRM_ERROR("PCI command DMA region is not a "
- "_DRM_CONSISTENT map!\n");
- savage_do_cleanup_bci(dev);
- return -EINVAL;
- }
- } else {
- dev_priv->cmd_dma = NULL;
- }
-
- dev_priv->dma_flush = savage_dma_flush;
- if (!dev_priv->cmd_dma) {
- DRM_DEBUG("falling back to faked command DMA.\n");
- dev_priv->fake_dma.offset = 0;
- dev_priv->fake_dma.size = SAVAGE_FAKE_DMA_SIZE;
- dev_priv->fake_dma.type = _DRM_SHM;
- dev_priv->fake_dma.handle = kmalloc(SAVAGE_FAKE_DMA_SIZE,
- GFP_KERNEL);
- if (!dev_priv->fake_dma.handle) {
- DRM_ERROR("could not allocate faked DMA buffer!\n");
- savage_do_cleanup_bci(dev);
- return -ENOMEM;
- }
- dev_priv->cmd_dma = &dev_priv->fake_dma;
- dev_priv->dma_flush = savage_fake_dma_flush;
- }
-
- dev_priv->sarea_priv =
- (drm_savage_sarea_t *) ((uint8_t *) dev_priv->sarea->handle +
- init->sarea_priv_offset);
-
- /* setup bitmap descriptors */
- {
- unsigned int color_tile_format;
- unsigned int depth_tile_format;
- unsigned int front_stride, back_stride, depth_stride;
- if (dev_priv->chipset <= S3_SAVAGE4) {
- color_tile_format = dev_priv->fb_bpp == 16 ?
- SAVAGE_BD_TILE_16BPP : SAVAGE_BD_TILE_32BPP;
- depth_tile_format = dev_priv->depth_bpp == 16 ?
- SAVAGE_BD_TILE_16BPP : SAVAGE_BD_TILE_32BPP;
- } else {
- color_tile_format = SAVAGE_BD_TILE_DEST;
- depth_tile_format = SAVAGE_BD_TILE_DEST;
- }
- front_stride = dev_priv->front_pitch / (dev_priv->fb_bpp / 8);
- back_stride = dev_priv->back_pitch / (dev_priv->fb_bpp / 8);
- depth_stride =
- dev_priv->depth_pitch / (dev_priv->depth_bpp / 8);
-
- dev_priv->front_bd = front_stride | SAVAGE_BD_BW_DISABLE |
- (dev_priv->fb_bpp << SAVAGE_BD_BPP_SHIFT) |
- (color_tile_format << SAVAGE_BD_TILE_SHIFT);
-
- dev_priv->back_bd = back_stride | SAVAGE_BD_BW_DISABLE |
- (dev_priv->fb_bpp << SAVAGE_BD_BPP_SHIFT) |
- (color_tile_format << SAVAGE_BD_TILE_SHIFT);
-
- dev_priv->depth_bd = depth_stride | SAVAGE_BD_BW_DISABLE |
- (dev_priv->depth_bpp << SAVAGE_BD_BPP_SHIFT) |
- (depth_tile_format << SAVAGE_BD_TILE_SHIFT);
- }
-
- /* setup status and bci ptr */
- dev_priv->event_counter = 0;
- dev_priv->event_wrap = 0;
- dev_priv->bci_ptr = (volatile uint32_t *)
- ((uint8_t *) dev_priv->mmio->handle + SAVAGE_BCI_OFFSET);
- if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
- dev_priv->status_used_mask = SAVAGE_FIFO_USED_MASK_S3D;
- } else {
- dev_priv->status_used_mask = SAVAGE_FIFO_USED_MASK_S4;
- }
- if (dev_priv->status != NULL) {
- dev_priv->status_ptr =
- (volatile uint32_t *)dev_priv->status->handle;
- dev_priv->wait_fifo = savage_bci_wait_fifo_shadow;
- dev_priv->wait_evnt = savage_bci_wait_event_shadow;
- dev_priv->status_ptr[1023] = dev_priv->event_counter;
- } else {
- dev_priv->status_ptr = NULL;
- if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
- dev_priv->wait_fifo = savage_bci_wait_fifo_s3d;
- } else {
- dev_priv->wait_fifo = savage_bci_wait_fifo_s4;
- }
- dev_priv->wait_evnt = savage_bci_wait_event_reg;
- }
-
- /* cliprect functions */
- if (S3_SAVAGE3D_SERIES(dev_priv->chipset))
- dev_priv->emit_clip_rect = savage_emit_clip_rect_s3d;
- else
- dev_priv->emit_clip_rect = savage_emit_clip_rect_s4;
-
- if (savage_freelist_init(dev) < 0) {
- DRM_ERROR("could not initialize freelist\n");
- savage_do_cleanup_bci(dev);
- return -ENOMEM;
- }
-
- if (savage_dma_init(dev_priv) < 0) {
- DRM_ERROR("could not initialize command DMA\n");
- savage_do_cleanup_bci(dev);
- return -ENOMEM;
- }
-
- return 0;
-}
-
-static int savage_do_cleanup_bci(struct drm_device * dev)
-{
- drm_savage_private_t *dev_priv = dev->dev_private;
-
- if (dev_priv->cmd_dma == &dev_priv->fake_dma) {
- kfree(dev_priv->fake_dma.handle);
- } else if (dev_priv->cmd_dma && dev_priv->cmd_dma->handle &&
- dev_priv->cmd_dma->type == _DRM_AGP &&
- dev_priv->dma_type == SAVAGE_DMA_AGP)
- drm_legacy_ioremapfree(dev_priv->cmd_dma, dev);
-
- if (dev_priv->dma_type == SAVAGE_DMA_AGP &&
- dev->agp_buffer_map && dev->agp_buffer_map->handle) {
- drm_legacy_ioremapfree(dev->agp_buffer_map, dev);
- /* make sure the next instance (which may be running
- * in PCI mode) doesn't try to use an old
- * agp_buffer_map. */
- dev->agp_buffer_map = NULL;
- }
-
- kfree(dev_priv->dma_pages);
-
- return 0;
-}
-
-static int savage_bci_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_savage_init_t *init = data;
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- switch (init->func) {
- case SAVAGE_INIT_BCI:
- return savage_do_init_bci(dev, init);
- case SAVAGE_CLEANUP_BCI:
- return savage_do_cleanup_bci(dev);
- }
-
- return -EINVAL;
-}
-
-static int savage_bci_event_emit(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_savage_private_t *dev_priv = dev->dev_private;
- drm_savage_event_emit_t *event = data;
-
- DRM_DEBUG("\n");
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- event->count = savage_bci_emit_event(dev_priv, event->flags);
- event->count |= dev_priv->event_wrap << 16;
-
- return 0;
-}
-
-static int savage_bci_event_wait(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_savage_private_t *dev_priv = dev->dev_private;
- drm_savage_event_wait_t *event = data;
- unsigned int event_e, hw_e;
- unsigned int event_w, hw_w;
-
- DRM_DEBUG("\n");
-
- UPDATE_EVENT_COUNTER();
- if (dev_priv->status_ptr)
- hw_e = dev_priv->status_ptr[1] & 0xffff;
- else
- hw_e = SAVAGE_READ(SAVAGE_STATUS_WORD1) & 0xffff;
- hw_w = dev_priv->event_wrap;
- if (hw_e > dev_priv->event_counter)
- hw_w--; /* hardware hasn't passed the last wrap yet */
-
- event_e = event->count & 0xffff;
- event_w = event->count >> 16;
-
- /* Don't need to wait if
- * - event counter wrapped since the event was emitted or
- * - the hardware has advanced up to or over the event to wait for.
- */
- if (event_w < hw_w || (event_w == hw_w && event_e <= hw_e))
- return 0;
- else
- return dev_priv->wait_evnt(dev_priv, event_e);
-}
-
-/*
- * DMA buffer management
- */
-
-static int savage_bci_get_buffers(struct drm_device *dev,
- struct drm_file *file_priv,
- struct drm_dma *d)
-{
- struct drm_buf *buf;
- int i;
-
- for (i = d->granted_count; i < d->request_count; i++) {
- buf = savage_freelist_get(dev);
- if (!buf)
- return -EAGAIN;
-
- buf->file_priv = file_priv;
-
- if (copy_to_user(&d->request_indices[i],
- &buf->idx, sizeof(buf->idx)))
- return -EFAULT;
- if (copy_to_user(&d->request_sizes[i],
- &buf->total, sizeof(buf->total)))
- return -EFAULT;
-
- d->granted_count++;
- }
- return 0;
-}
-
-int savage_bci_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- struct drm_device_dma *dma = dev->dma;
- struct drm_dma *d = data;
- int ret = 0;
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- /* Please don't send us buffers.
- */
- if (d->send_count != 0) {
- DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n",
- task_pid_nr(current), d->send_count);
- return -EINVAL;
- }
-
- /* We'll send you buffers.
- */
- if (d->request_count < 0 || d->request_count > dma->buf_count) {
- DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",
- task_pid_nr(current), d->request_count, dma->buf_count);
- return -EINVAL;
- }
-
- d->granted_count = 0;
-
- if (d->request_count) {
- ret = savage_bci_get_buffers(dev, file_priv, d);
- }
-
- return ret;
-}
-
-void savage_reclaim_buffers(struct drm_device *dev, struct drm_file *file_priv)
-{
- struct drm_device_dma *dma = dev->dma;
- drm_savage_private_t *dev_priv = dev->dev_private;
- int release_idlelock = 0;
- int i;
-
- if (!dma)
- return;
- if (!dev_priv)
- return;
- if (!dma->buflist)
- return;
-
- if (file_priv->master && file_priv->master->lock.hw_lock) {
- drm_legacy_idlelock_take(&file_priv->master->lock);
- release_idlelock = 1;
- }
-
- for (i = 0; i < dma->buf_count; i++) {
- struct drm_buf *buf = dma->buflist[i];
- drm_savage_buf_priv_t *buf_priv = buf->dev_private;
-
- if (buf->file_priv == file_priv && buf_priv &&
- buf_priv->next == NULL && buf_priv->prev == NULL) {
- uint16_t event;
- DRM_DEBUG("reclaimed from client\n");
- event = savage_bci_emit_event(dev_priv, SAVAGE_WAIT_3D);
- SET_AGE(&buf_priv->age, event, dev_priv->event_wrap);
- savage_freelist_put(dev, buf);
- }
- }
-
- if (release_idlelock)
- drm_legacy_idlelock_release(&file_priv->master->lock);
-}
-
-const struct drm_ioctl_desc savage_ioctls[] = {
- DRM_IOCTL_DEF_DRV(SAVAGE_BCI_INIT, savage_bci_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
- DRM_IOCTL_DEF_DRV(SAVAGE_BCI_CMDBUF, savage_bci_cmdbuf, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(SAVAGE_BCI_EVENT_EMIT, savage_bci_event_emit, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(SAVAGE_BCI_EVENT_WAIT, savage_bci_event_wait, DRM_AUTH),
-};
-
-int savage_max_ioctl = ARRAY_SIZE(savage_ioctls);
diff --git a/drivers/gpu/drm/savage/savage_drv.c b/drivers/gpu/drm/savage/savage_drv.c
deleted file mode 100644
index 799bd11adb9c..000000000000
--- a/drivers/gpu/drm/savage/savage_drv.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/* savage_drv.c -- Savage driver for Linux
- *
- * Copyright 2004 Felix Kuehling
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software 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, sub license,
- * 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 (including the
- * next paragraph) 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
- * NON-INFRINGEMENT. IN NO EVENT SHALL FELIX KUEHLING 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.
- */
-
-#include <linux/module.h>
-#include <linux/pci.h>
-
-#include <drm/drm_drv.h>
-#include <drm/drm_file.h>
-#include <drm/drm_pciids.h>
-
-#include "savage_drv.h"
-
-static struct pci_device_id pciidlist[] = {
- savage_PCI_IDS
-};
-
-static const struct file_operations savage_driver_fops = {
- .owner = THIS_MODULE,
- .open = drm_open,
- .release = drm_release,
- .unlocked_ioctl = drm_ioctl,
- .mmap = drm_legacy_mmap,
- .poll = drm_poll,
- .compat_ioctl = drm_compat_ioctl,
- .llseek = noop_llseek,
-};
-
-static struct drm_driver driver = {
- .driver_features =
- DRIVER_USE_AGP | DRIVER_HAVE_DMA | DRIVER_PCI_DMA | DRIVER_LEGACY,
- .dev_priv_size = sizeof(drm_savage_buf_priv_t),
- .load = savage_driver_load,
- .firstopen = savage_driver_firstopen,
- .preclose = savage_reclaim_buffers,
- .lastclose = savage_driver_lastclose,
- .unload = savage_driver_unload,
- .ioctls = savage_ioctls,
- .dma_ioctl = savage_bci_buffers,
- .fops = &savage_driver_fops,
- .name = DRIVER_NAME,
- .desc = DRIVER_DESC,
- .date = DRIVER_DATE,
- .major = DRIVER_MAJOR,
- .minor = DRIVER_MINOR,
- .patchlevel = DRIVER_PATCHLEVEL,
-};
-
-static struct pci_driver savage_pci_driver = {
- .name = DRIVER_NAME,
- .id_table = pciidlist,
-};
-
-static int __init savage_init(void)
-{
- driver.num_ioctls = savage_max_ioctl;
- return drm_legacy_pci_init(&driver, &savage_pci_driver);
-}
-
-static void __exit savage_exit(void)
-{
- drm_legacy_pci_exit(&driver, &savage_pci_driver);
-}
-
-module_init(savage_init);
-module_exit(savage_exit);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/gpu/drm/savage/savage_drv.h b/drivers/gpu/drm/savage/savage_drv.h
deleted file mode 100644
index b0081bb64776..000000000000
--- a/drivers/gpu/drm/savage/savage_drv.h
+++ /dev/null
@@ -1,580 +0,0 @@
-/* savage_drv.h -- Private header for the savage driver */
-/*
- * Copyright 2004 Felix Kuehling
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software 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, sub license,
- * 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 (including the
- * next paragraph) 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
- * NON-INFRINGEMENT. IN NO EVENT SHALL FELIX KUEHLING 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.
- */
-
-#ifndef __SAVAGE_DRV_H__
-#define __SAVAGE_DRV_H__
-
-#include <linux/io.h>
-
-#include <drm/drm_ioctl.h>
-#include <drm/drm_legacy.h>
-#include <drm/savage_drm.h>
-
-#define DRIVER_AUTHOR "Felix Kuehling"
-
-#define DRIVER_NAME "savage"
-#define DRIVER_DESC "Savage3D/MX/IX, Savage4, SuperSavage, Twister, ProSavage[DDR]"
-#define DRIVER_DATE "20050313"
-
-#define DRIVER_MAJOR 2
-#define DRIVER_MINOR 4
-#define DRIVER_PATCHLEVEL 1
-/* Interface history:
- *
- * 1.x The DRM driver from the VIA/S3 code drop, basically a dummy
- * 2.0 The first real DRM
- * 2.1 Scissors registers managed by the DRM, 3D operations clipped by
- * cliprects of the cmdbuf ioctl
- * 2.2 Implemented SAVAGE_CMD_DMA_IDX and SAVAGE_CMD_VB_IDX
- * 2.3 Event counters used by BCI_EVENT_EMIT/WAIT ioctls are now 32 bits
- * wide and thus very long lived (unlikely to ever wrap). The size
- * in the struct was 32 bits before, but only 16 bits were used
- * 2.4 Implemented command DMA. Now drm_savage_init_t.cmd_dma_offset is
- * actually used
- */
-
-typedef struct drm_savage_age {
- uint16_t event;
- unsigned int wrap;
-} drm_savage_age_t;
-
-typedef struct drm_savage_buf_priv {
- struct drm_savage_buf_priv *next;
- struct drm_savage_buf_priv *prev;
- drm_savage_age_t age;
- struct drm_buf *buf;
-} drm_savage_buf_priv_t;
-
-typedef struct drm_savage_dma_page {
- drm_savage_age_t age;
- unsigned int used, flushed;
-} drm_savage_dma_page_t;
-#define SAVAGE_DMA_PAGE_SIZE 1024 /* in dwords */
-/* Fake DMA buffer size in bytes. 4 pages. Allows a maximum command
- * size of 16kbytes or 4k entries. Minimum requirement would be
- * 10kbytes for 255 40-byte vertices in one drawing command. */
-#define SAVAGE_FAKE_DMA_SIZE (SAVAGE_DMA_PAGE_SIZE*4*4)
-
-/* interesting bits of hardware state that are saved in dev_priv */
-typedef union {
- struct drm_savage_common_state {
- uint32_t vbaddr;
- } common;
- struct {
- unsigned char pad[sizeof(struct drm_savage_common_state)];
- uint32_t texctrl, texaddr;
- uint32_t scstart, new_scstart;
- uint32_t scend, new_scend;
- } s3d;
- struct {
- unsigned char pad[sizeof(struct drm_savage_common_state)];
- uint32_t texdescr, texaddr0, texaddr1;
- uint32_t drawctrl0, new_drawctrl0;
- uint32_t drawctrl1, new_drawctrl1;
- } s4;
-} drm_savage_state_t;
-
-/* these chip tags should match the ones in the 2D driver in savage_regs.h. */
-enum savage_family {
- S3_UNKNOWN = 0,
- S3_SAVAGE3D,
- S3_SAVAGE_MX,
- S3_SAVAGE4,
- S3_PROSAVAGE,
- S3_TWISTER,
- S3_PROSAVAGEDDR,
- S3_SUPERSAVAGE,
- S3_SAVAGE2000,
- S3_LAST
-};
-
-extern const struct drm_ioctl_desc savage_ioctls[];
-extern int savage_max_ioctl;
-
-#define S3_SAVAGE3D_SERIES(chip) ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE_MX))
-
-#define S3_SAVAGE4_SERIES(chip) ((chip==S3_SAVAGE4) \
- || (chip==S3_PROSAVAGE) \
- || (chip==S3_TWISTER) \
- || (chip==S3_PROSAVAGEDDR))
-
-#define S3_SAVAGE_MOBILE_SERIES(chip) ((chip==S3_SAVAGE_MX) || (chip==S3_SUPERSAVAGE))
-
-#define S3_SAVAGE_SERIES(chip) ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE2000))
-
-#define S3_MOBILE_TWISTER_SERIES(chip) ((chip==S3_TWISTER) \
- ||(chip==S3_PROSAVAGEDDR))
-
-/* flags */
-#define SAVAGE_IS_AGP 1
-
-typedef struct drm_savage_private {
- drm_savage_sarea_t *sarea_priv;
-
- drm_savage_buf_priv_t head, tail;
-
- /* who am I? */
- enum savage_family chipset;
-
- unsigned int cob_size;
- unsigned int bci_threshold_lo, bci_threshold_hi;
- unsigned int dma_type;
-
- /* frame buffer layout */
- unsigned int fb_bpp;
- unsigned int front_offset, front_pitch;
- unsigned int back_offset, back_pitch;
- unsigned int depth_bpp;
- unsigned int depth_offset, depth_pitch;
-
- /* bitmap descriptors for swap and clear */
- unsigned int front_bd, back_bd, depth_bd;
-
- /* local textures */
- unsigned int texture_offset;
- unsigned int texture_size;
-
- /* memory regions in physical memory */
- drm_local_map_t *sarea;
- drm_local_map_t *mmio;
- drm_local_map_t *fb;
- drm_local_map_t *aperture;
- drm_local_map_t *status;
- drm_local_map_t *agp_textures;
- drm_local_map_t *cmd_dma;
- drm_local_map_t fake_dma;
-
- int mtrr_handles[3];
-
- /* BCI and status-related stuff */
- volatile uint32_t *status_ptr, *bci_ptr;
- uint32_t status_used_mask;
- uint16_t event_counter;
- unsigned int event_wrap;
-
- /* Savage4 command DMA */
- drm_savage_dma_page_t *dma_pages;
- unsigned int nr_dma_pages, first_dma_page, current_dma_page;
- drm_savage_age_t last_dma_age;
-
- /* saved hw state for global/local check on S3D */
- uint32_t hw_draw_ctrl, hw_zbuf_ctrl;
- /* and for scissors (global, so don't emit if not changed) */
- uint32_t hw_scissors_start, hw_scissors_end;
-
- drm_savage_state_t state;
-
- /* after emitting a wait cmd Savage3D needs 63 nops before next DMA */
- unsigned int waiting;
-
- /* config/hardware-dependent function pointers */
- int (*wait_fifo) (struct drm_savage_private * dev_priv, unsigned int n);
- int (*wait_evnt) (struct drm_savage_private * dev_priv, uint16_t e);
- /* Err, there is a macro wait_event in include/linux/wait.h.
- * Avoid unwanted macro expansion. */
- void (*emit_clip_rect) (struct drm_savage_private * dev_priv,
- const struct drm_clip_rect * pbox);
- void (*dma_flush) (struct drm_savage_private * dev_priv);
-} drm_savage_private_t;
-
-/* ioctls */
-extern int savage_bci_cmdbuf(struct drm_device *dev, void *data, struct drm_file *file_priv);
-extern int savage_bci_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv);
-
-/* BCI functions */
-extern uint16_t savage_bci_emit_event(drm_savage_private_t * dev_priv,
- unsigned int flags);
-extern void savage_freelist_put(struct drm_device * dev, struct drm_buf * buf);
-extern void savage_dma_reset(drm_savage_private_t * dev_priv);
-extern void savage_dma_wait(drm_savage_private_t * dev_priv, unsigned int page);
-extern uint32_t *savage_dma_alloc(drm_savage_private_t * dev_priv,
- unsigned int n);
-extern int savage_driver_load(struct drm_device *dev, unsigned long chipset);
-extern int savage_driver_firstopen(struct drm_device *dev);
-extern void savage_driver_lastclose(struct drm_device *dev);
-extern void savage_driver_unload(struct drm_device *dev);
-extern void savage_reclaim_buffers(struct drm_device *dev,
- struct drm_file *file_priv);
-
-/* state functions */
-extern void savage_emit_clip_rect_s3d(drm_savage_private_t * dev_priv,
- const struct drm_clip_rect * pbox);
-extern void savage_emit_clip_rect_s4(drm_savage_private_t * dev_priv,
- const struct drm_clip_rect * pbox);
-
-#define SAVAGE_FB_SIZE_S3 0x01000000 /* 16MB */
-#define SAVAGE_FB_SIZE_S4 0x02000000 /* 32MB */
-#define SAVAGE_MMIO_SIZE 0x00080000 /* 512kB */
-#define SAVAGE_APERTURE_OFFSET 0x02000000 /* 32MB */
-#define SAVAGE_APERTURE_SIZE 0x05000000 /* 5 tiled surfaces, 16MB each */
-
-#define SAVAGE_BCI_OFFSET 0x00010000 /* offset of the BCI region
- * inside the MMIO region */
-#define SAVAGE_BCI_FIFO_SIZE 32 /* number of entries in on-chip
- * BCI FIFO */
-
-/*
- * MMIO registers
- */
-#define SAVAGE_STATUS_WORD0 0x48C00
-#define SAVAGE_STATUS_WORD1 0x48C04
-#define SAVAGE_ALT_STATUS_WORD0 0x48C60
-
-#define SAVAGE_FIFO_USED_MASK_S3D 0x0001ffff
-#define SAVAGE_FIFO_USED_MASK_S4 0x001fffff
-
-/* Copied from savage_bci.h in the 2D driver with some renaming. */
-
-/* Bitmap descriptors */
-#define SAVAGE_BD_STRIDE_SHIFT 0
-#define SAVAGE_BD_BPP_SHIFT 16
-#define SAVAGE_BD_TILE_SHIFT 24
-#define SAVAGE_BD_BW_DISABLE (1<<28)
-/* common: */
-#define SAVAGE_BD_TILE_LINEAR 0
-/* savage4, MX, IX, 3D */
-#define SAVAGE_BD_TILE_16BPP 2
-#define SAVAGE_BD_TILE_32BPP 3
-/* twister, prosavage, DDR, supersavage, 2000 */
-#define SAVAGE_BD_TILE_DEST 1
-#define SAVAGE_BD_TILE_TEXTURE 2
-/* GBD - BCI enable */
-/* savage4, MX, IX, 3D */
-#define SAVAGE_GBD_BCI_ENABLE 8
-/* twister, prosavage, DDR, supersavage, 2000 */
-#define SAVAGE_GBD_BCI_ENABLE_TWISTER 0
-
-#define SAVAGE_GBD_BIG_ENDIAN 4
-#define SAVAGE_GBD_LITTLE_ENDIAN 0
-#define SAVAGE_GBD_64 1
-
-/* Global Bitmap Descriptor */
-#define SAVAGE_BCI_GLB_BD_LOW 0x8168
-#define SAVAGE_BCI_GLB_BD_HIGH 0x816C
-
-/*
- * BCI registers
- */
-/* Savage4/Twister/ProSavage 3D registers */
-#define SAVAGE_DRAWLOCALCTRL_S4 0x1e
-#define SAVAGE_TEXPALADDR_S4 0x1f
-#define SAVAGE_TEXCTRL0_S4 0x20
-#define SAVAGE_TEXCTRL1_S4 0x21
-#define SAVAGE_TEXADDR0_S4 0x22
-#define SAVAGE_TEXADDR1_S4 0x23
-#define SAVAGE_TEXBLEND0_S4 0x24
-#define SAVAGE_TEXBLEND1_S4 0x25
-#define SAVAGE_TEXXPRCLR_S4 0x26 /* never used */
-#define SAVAGE_TEXDESCR_S4 0x27
-#define SAVAGE_FOGTABLE_S4 0x28
-#define SAVAGE_FOGCTRL_S4 0x30
-#define SAVAGE_STENCILCTRL_S4 0x31
-#define SAVAGE_ZBUFCTRL_S4 0x32
-#define SAVAGE_ZBUFOFF_S4 0x33
-#define SAVAGE_DESTCTRL_S4 0x34
-#define SAVAGE_DRAWCTRL0_S4 0x35
-#define SAVAGE_DRAWCTRL1_S4 0x36
-#define SAVAGE_ZWATERMARK_S4 0x37
-#define SAVAGE_DESTTEXRWWATERMARK_S4 0x38
-#define SAVAGE_TEXBLENDCOLOR_S4 0x39
-/* Savage3D/MX/IX 3D registers */
-#define SAVAGE_TEXPALADDR_S3D 0x18
-#define SAVAGE_TEXXPRCLR_S3D 0x19 /* never used */
-#define SAVAGE_TEXADDR_S3D 0x1A
-#define SAVAGE_TEXDESCR_S3D 0x1B
-#define SAVAGE_TEXCTRL_S3D 0x1C
-#define SAVAGE_FOGTABLE_S3D 0x20
-#define SAVAGE_FOGCTRL_S3D 0x30
-#define SAVAGE_DRAWCTRL_S3D 0x31
-#define SAVAGE_ZBUFCTRL_S3D 0x32
-#define SAVAGE_ZBUFOFF_S3D 0x33
-#define SAVAGE_DESTCTRL_S3D 0x34
-#define SAVAGE_SCSTART_S3D 0x35
-#define SAVAGE_SCEND_S3D 0x36
-#define SAVAGE_ZWATERMARK_S3D 0x37
-#define SAVAGE_DESTTEXRWWATERMARK_S3D 0x38
-/* common stuff */
-#define SAVAGE_VERTBUFADDR 0x3e
-#define SAVAGE_BITPLANEWTMASK 0xd7
-#define SAVAGE_DMABUFADDR 0x51
-
-/* texture enable bits (needed for tex addr checking) */
-#define SAVAGE_TEXCTRL_TEXEN_MASK 0x00010000 /* S3D */
-#define SAVAGE_TEXDESCR_TEX0EN_MASK 0x02000000 /* S4 */
-#define SAVAGE_TEXDESCR_TEX1EN_MASK 0x04000000 /* S4 */
-
-/* Global fields in Savage4/Twister/ProSavage 3D registers:
- *
- * All texture registers and DrawLocalCtrl are local. All other
- * registers are global. */
-
-/* Global fields in Savage3D/MX/IX 3D registers:
- *
- * All texture registers are local. DrawCtrl and ZBufCtrl are
- * partially local. All other registers are global.
- *
- * DrawCtrl global fields: cullMode, alphaTestCmpFunc, alphaTestEn, alphaRefVal
- * ZBufCtrl global fields: zCmpFunc, zBufEn
- */
-#define SAVAGE_DRAWCTRL_S3D_GLOBAL 0x03f3c00c
-#define SAVAGE_ZBUFCTRL_S3D_GLOBAL 0x00000027
-
-/* Masks for scissor bits (drawCtrl[01] on s4, scissorStart/End on s3d)
- */
-#define SAVAGE_SCISSOR_MASK_S4 0x00fff7ff
-#define SAVAGE_SCISSOR_MASK_S3D 0x07ff07ff
-
-/*
- * BCI commands
- */
-#define BCI_CMD_NOP 0x40000000
-#define BCI_CMD_RECT 0x48000000
-#define BCI_CMD_RECT_XP 0x01000000
-#define BCI_CMD_RECT_YP 0x02000000
-#define BCI_CMD_SCANLINE 0x50000000
-#define BCI_CMD_LINE 0x5C000000
-#define BCI_CMD_LINE_LAST_PIXEL 0x58000000
-#define BCI_CMD_BYTE_TEXT 0x63000000
-#define BCI_CMD_NT_BYTE_TEXT 0x67000000
-#define BCI_CMD_BIT_TEXT 0x6C000000
-#define BCI_CMD_GET_ROP(cmd) (((cmd) >> 16) & 0xFF)
-#define BCI_CMD_SET_ROP(cmd, rop) ((cmd) |= ((rop & 0xFF) << 16))
-#define BCI_CMD_SEND_COLOR 0x00008000
-
-#define BCI_CMD_CLIP_NONE 0x00000000
-#define BCI_CMD_CLIP_CURRENT 0x00002000
-#define BCI_CMD_CLIP_LR 0x00004000
-#define BCI_CMD_CLIP_NEW 0x00006000
-
-#define BCI_CMD_DEST_GBD 0x00000000
-#define BCI_CMD_DEST_PBD 0x00000800
-#define BCI_CMD_DEST_PBD_NEW 0x00000C00
-#define BCI_CMD_DEST_SBD 0x00001000
-#define BCI_CMD_DEST_SBD_NEW 0x00001400
-
-#define BCI_CMD_SRC_TRANSPARENT 0x00000200
-#define BCI_CMD_SRC_SOLID 0x00000000
-#define BCI_CMD_SRC_GBD 0x00000020
-#define BCI_CMD_SRC_COLOR 0x00000040
-#define BCI_CMD_SRC_MONO 0x00000060
-#define BCI_CMD_SRC_PBD_COLOR 0x00000080
-#define BCI_CMD_SRC_PBD_MONO 0x000000A0
-#define BCI_CMD_SRC_PBD_COLOR_NEW 0x000000C0
-#define BCI_CMD_SRC_PBD_MONO_NEW 0x000000E0
-#define BCI_CMD_SRC_SBD_COLOR 0x00000100
-#define BCI_CMD_SRC_SBD_MONO 0x00000120
-#define BCI_CMD_SRC_SBD_COLOR_NEW 0x00000140
-#define BCI_CMD_SRC_SBD_MONO_NEW 0x00000160
-
-#define BCI_CMD_PAT_TRANSPARENT 0x00000010
-#define BCI_CMD_PAT_NONE 0x00000000
-#define BCI_CMD_PAT_COLOR 0x00000002
-#define BCI_CMD_PAT_MONO 0x00000003
-#define BCI_CMD_PAT_PBD_COLOR 0x00000004
-#define BCI_CMD_PAT_PBD_MONO 0x00000005
-#define BCI_CMD_PAT_PBD_COLOR_NEW 0x00000006
-#define BCI_CMD_PAT_PBD_MONO_NEW 0x00000007
-#define BCI_CMD_PAT_SBD_COLOR 0x00000008
-#define BCI_CMD_PAT_SBD_MONO 0x00000009
-#define BCI_CMD_PAT_SBD_COLOR_NEW 0x0000000A
-#define BCI_CMD_PAT_SBD_MONO_NEW 0x0000000B
-
-#define BCI_BD_BW_DISABLE 0x10000000
-#define BCI_BD_TILE_MASK 0x03000000
-#define BCI_BD_TILE_NONE 0x00000000
-#define BCI_BD_TILE_16 0x02000000
-#define BCI_BD_TILE_32 0x03000000
-#define BCI_BD_GET_BPP(bd) (((bd) >> 16) & 0xFF)
-#define BCI_BD_SET_BPP(bd, bpp) ((bd) |= (((bpp) & 0xFF) << 16))
-#define BCI_BD_GET_STRIDE(bd) ((bd) & 0xFFFF)
-#define BCI_BD_SET_STRIDE(bd, st) ((bd) |= ((st) & 0xFFFF))
-
-#define BCI_CMD_SET_REGISTER 0x96000000
-
-#define BCI_CMD_WAIT 0xC0000000
-#define BCI_CMD_WAIT_3D 0x00010000
-#define BCI_CMD_WAIT_2D 0x00020000
-
-#define BCI_CMD_UPDATE_EVENT_TAG 0x98000000
-
-#define BCI_CMD_DRAW_PRIM 0x80000000
-#define BCI_CMD_DRAW_INDEXED_PRIM 0x88000000
-#define BCI_CMD_DRAW_CONT 0x01000000
-#define BCI_CMD_DRAW_TRILIST 0x00000000
-#define BCI_CMD_DRAW_TRISTRIP 0x02000000
-#define BCI_CMD_DRAW_TRIFAN 0x04000000
-#define BCI_CMD_DRAW_SKIPFLAGS 0x000000ff
-#define BCI_CMD_DRAW_NO_Z 0x00000001
-#define BCI_CMD_DRAW_NO_W 0x00000002
-#define BCI_CMD_DRAW_NO_CD 0x00000004
-#define BCI_CMD_DRAW_NO_CS 0x00000008
-#define BCI_CMD_DRAW_NO_U0 0x00000010
-#define BCI_CMD_DRAW_NO_V0 0x00000020
-#define BCI_CMD_DRAW_NO_UV0 0x00000030
-#define BCI_CMD_DRAW_NO_U1 0x00000040
-#define BCI_CMD_DRAW_NO_V1 0x00000080
-#define BCI_CMD_DRAW_NO_UV1 0x000000c0
-
-#define BCI_CMD_DMA 0xa8000000
-
-#define BCI_W_H(w, h) ((((h) << 16) | (w)) & 0x0FFF0FFF)
-#define BCI_X_Y(x, y) ((((y) << 16) | (x)) & 0x0FFF0FFF)
-#define BCI_X_W(x, y) ((((w) << 16) | (x)) & 0x0FFF0FFF)
-#define BCI_CLIP_LR(l, r) ((((r) << 16) | (l)) & 0x0FFF0FFF)
-#define BCI_CLIP_TL(t, l) ((((t) << 16) | (l)) & 0x0FFF0FFF)
-#define BCI_CLIP_BR(b, r) ((((b) << 16) | (r)) & 0x0FFF0FFF)
-
-#define BCI_LINE_X_Y(x, y) (((y) << 16) | ((x) & 0xFFFF))
-#define BCI_LINE_STEPS(diag, axi) (((axi) << 16) | ((diag) & 0xFFFF))
-#define BCI_LINE_MISC(maj, ym, xp, yp, err) \
- (((maj) & 0x1FFF) | \
- ((ym) ? 1<<13 : 0) | \
- ((xp) ? 1<<14 : 0) | \
- ((yp) ? 1<<15 : 0) | \
- ((err) << 16))
-
-/*
- * common commands
- */
-#define BCI_SET_REGISTERS( first, n ) \
- BCI_WRITE(BCI_CMD_SET_REGISTER | \
- ((uint32_t)(n) & 0xff) << 16 | \
- ((uint32_t)(first) & 0xffff))
-#define DMA_SET_REGISTERS( first, n ) \
- DMA_WRITE(BCI_CMD_SET_REGISTER | \
- ((uint32_t)(n) & 0xff) << 16 | \
- ((uint32_t)(first) & 0xffff))
-
-#define BCI_DRAW_PRIMITIVE(n, type, skip) \
- BCI_WRITE(BCI_CMD_DRAW_PRIM | (type) | (skip) | \
- ((n) << 16))
-#define DMA_DRAW_PRIMITIVE(n, type, skip) \
- DMA_WRITE(BCI_CMD_DRAW_PRIM | (type) | (skip) | \
- ((n) << 16))
-
-#define BCI_DRAW_INDICES_S3D(n, type, i0) \
- BCI_WRITE(BCI_CMD_DRAW_INDEXED_PRIM | (type) | \
- ((n) << 16) | (i0))
-
-#define BCI_DRAW_INDICES_S4(n, type, skip) \
- BCI_WRITE(BCI_CMD_DRAW_INDEXED_PRIM | (type) | \
- (skip) | ((n) << 16))
-
-#define BCI_DMA(n) \
- BCI_WRITE(BCI_CMD_DMA | (((n) >> 1) - 1))
-
-/*
- * access to MMIO
- */
-#define SAVAGE_READ(reg) \
- readl(((void __iomem *)dev_priv->mmio->handle) + (reg))
-#define SAVAGE_WRITE(reg) \
- writel(val, ((void __iomem *)dev_priv->mmio->handle) + (reg))
-
-/*
- * access to the burst command interface (BCI)
- */
-#define SAVAGE_BCI_DEBUG 1
-
-#define BCI_LOCALS volatile uint32_t *bci_ptr;
-
-#define BEGIN_BCI( n ) do { \
- dev_priv->wait_fifo(dev_priv, (n)); \
- bci_ptr = dev_priv->bci_ptr; \
-} while(0)
-
-#define BCI_WRITE( val ) *bci_ptr++ = (uint32_t)(val)
-
-/*
- * command DMA support
- */
-#define SAVAGE_DMA_DEBUG 1
-
-#define DMA_LOCALS uint32_t *dma_ptr;
-
-#define BEGIN_DMA( n ) do { \
- unsigned int cur = dev_priv->current_dma_page; \
- unsigned int rest = SAVAGE_DMA_PAGE_SIZE - \
- dev_priv->dma_pages[cur].used; \
- if ((n) > rest) { \
- dma_ptr = savage_dma_alloc(dev_priv, (n)); \
- } else { /* fast path for small allocations */ \
- dma_ptr = (uint32_t *)dev_priv->cmd_dma->handle + \
- cur * SAVAGE_DMA_PAGE_SIZE + \
- dev_priv->dma_pages[cur].used; \
- if (dev_priv->dma_pages[cur].used == 0) \
- savage_dma_wait(dev_priv, cur); \
- dev_priv->dma_pages[cur].used += (n); \
- } \
-} while(0)
-
-#define DMA_WRITE( val ) *dma_ptr++ = (uint32_t)(val)
-
-#define DMA_COPY(src, n) do { \
- memcpy(dma_ptr, (src), (n)*4); \
- dma_ptr += n; \
-} while(0)
-
-#if SAVAGE_DMA_DEBUG
-#define DMA_COMMIT() do { \
- unsigned int cur = dev_priv->current_dma_page; \
- uint32_t *expected = (uint32_t *)dev_priv->cmd_dma->handle + \
- cur * SAVAGE_DMA_PAGE_SIZE + \
- dev_priv->dma_pages[cur].used; \
- if (dma_ptr != expected) { \
- DRM_ERROR("DMA allocation and use don't match: " \
- "%p != %p\n", expected, dma_ptr); \
- savage_dma_reset(dev_priv); \
- } \
-} while(0)
-#else
-#define DMA_COMMIT() do {/* nothing */} while(0)
-#endif
-
-#define DMA_FLUSH() dev_priv->dma_flush(dev_priv)
-
-/* Buffer aging via event tag
- */
-
-#define UPDATE_EVENT_COUNTER( ) do { \
- if (dev_priv->status_ptr) { \
- uint16_t count; \
- /* coordinate with Xserver */ \
- count = dev_priv->status_ptr[1023]; \
- if (count < dev_priv->event_counter) \
- dev_priv->event_wrap++; \
- dev_priv->event_counter = count; \
- } \
-} while(0)
-
-#define SET_AGE( age, e, w ) do { \
- (age)->event = e; \
- (age)->wrap = w; \
-} while(0)
-
-#define TEST_AGE( age, e, w ) \
- ( (age)->wrap < (w) || ( (age)->wrap == (w) && (age)->event <= (e) ) )
-
-#endif /* __SAVAGE_DRV_H__ */
diff --git a/drivers/gpu/drm/savage/savage_state.c b/drivers/gpu/drm/savage/savage_state.c
deleted file mode 100644
index e0d40ae67d54..000000000000
--- a/drivers/gpu/drm/savage/savage_state.c
+++ /dev/null
@@ -1,1169 +0,0 @@
-/* savage_state.c -- State and drawing support for Savage
- *
- * Copyright 2004 Felix Kuehling
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software 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, sub license,
- * 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 (including the
- * next paragraph) 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
- * NON-INFRINGEMENT. IN NO EVENT SHALL FELIX KUEHLING 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.
- */
-
-#include <linux/slab.h>
-#include <linux/uaccess.h>
-
-#include <drm/drm_device.h>
-#include <drm/drm_file.h>
-#include <drm/drm_print.h>
-#include <drm/savage_drm.h>
-
-#include "savage_drv.h"
-
-void savage_emit_clip_rect_s3d(drm_savage_private_t * dev_priv,
- const struct drm_clip_rect * pbox)
-{
- uint32_t scstart = dev_priv->state.s3d.new_scstart;
- uint32_t scend = dev_priv->state.s3d.new_scend;
- scstart = (scstart & ~SAVAGE_SCISSOR_MASK_S3D) |
- ((uint32_t) pbox->x1 & 0x000007ff) |
- (((uint32_t) pbox->y1 << 16) & 0x07ff0000);
- scend = (scend & ~SAVAGE_SCISSOR_MASK_S3D) |
- (((uint32_t) pbox->x2 - 1) & 0x000007ff) |
- ((((uint32_t) pbox->y2 - 1) << 16) & 0x07ff0000);
- if (scstart != dev_priv->state.s3d.scstart ||
- scend != dev_priv->state.s3d.scend) {
- DMA_LOCALS;
- BEGIN_DMA(4);
- DMA_WRITE(BCI_CMD_WAIT | BCI_CMD_WAIT_3D);
- DMA_SET_REGISTERS(SAVAGE_SCSTART_S3D, 2);
- DMA_WRITE(scstart);
- DMA_WRITE(scend);
- dev_priv->state.s3d.scstart = scstart;
- dev_priv->state.s3d.scend = scend;
- dev_priv->waiting = 1;
- DMA_COMMIT();
- }
-}
-
-void savage_emit_clip_rect_s4(drm_savage_private_t * dev_priv,
- const struct drm_clip_rect * pbox)
-{
- uint32_t drawctrl0 = dev_priv->state.s4.new_drawctrl0;
- uint32_t drawctrl1 = dev_priv->state.s4.new_drawctrl1;
- drawctrl0 = (drawctrl0 & ~SAVAGE_SCISSOR_MASK_S4) |
- ((uint32_t) pbox->x1 & 0x000007ff) |
- (((uint32_t) pbox->y1 << 12) & 0x00fff000);
- drawctrl1 = (drawctrl1 & ~SAVAGE_SCISSOR_MASK_S4) |
- (((uint32_t) pbox->x2 - 1) & 0x000007ff) |
- ((((uint32_t) pbox->y2 - 1) << 12) & 0x00fff000);
- if (drawctrl0 != dev_priv->state.s4.drawctrl0 ||
- drawctrl1 != dev_priv->state.s4.drawctrl1) {
- DMA_LOCALS;
- BEGIN_DMA(4);
- DMA_WRITE(BCI_CMD_WAIT | BCI_CMD_WAIT_3D);
- DMA_SET_REGISTERS(SAVAGE_DRAWCTRL0_S4, 2);
- DMA_WRITE(drawctrl0);
- DMA_WRITE(drawctrl1);
- dev_priv->state.s4.drawctrl0 = drawctrl0;
- dev_priv->state.s4.drawctrl1 = drawctrl1;
- dev_priv->waiting = 1;
- DMA_COMMIT();
- }
-}
-
-static int savage_verify_texaddr(drm_savage_private_t * dev_priv, int unit,
- uint32_t addr)
-{
- if ((addr & 6) != 2) { /* reserved bits */
- DRM_ERROR("bad texAddr%d %08x (reserved bits)\n", unit, addr);
- return -EINVAL;
- }
- if (!(addr & 1)) { /* local */
- addr &= ~7;
- if (addr < dev_priv->texture_offset ||
- addr >= dev_priv->texture_offset + dev_priv->texture_size) {
- DRM_ERROR
- ("bad texAddr%d %08x (local addr out of range)\n",
- unit, addr);
- return -EINVAL;
- }
- } else { /* AGP */
- if (!dev_priv->agp_textures) {
- DRM_ERROR("bad texAddr%d %08x (AGP not available)\n",
- unit, addr);
- return -EINVAL;
- }
- addr &= ~7;
- if (addr < dev_priv->agp_textures->offset ||
- addr >= (dev_priv->agp_textures->offset +
- dev_priv->agp_textures->size)) {
- DRM_ERROR
- ("bad texAddr%d %08x (AGP addr out of range)\n",
- unit, addr);
- return -EINVAL;
- }
- }
- return 0;
-}
-
-#define SAVE_STATE(reg,where) \
- if(start <= reg && start+count > reg) \
- dev_priv->state.where = regs[reg - start]
-#define SAVE_STATE_MASK(reg,where,mask) do { \
- if(start <= reg && start+count > reg) { \
- uint32_t tmp; \
- tmp = regs[reg - start]; \
- dev_priv->state.where = (tmp & (mask)) | \
- (dev_priv->state.where & ~(mask)); \
- } \
-} while (0)
-
-static int savage_verify_state_s3d(drm_savage_private_t * dev_priv,
- unsigned int start, unsigned int count,
- const uint32_t *regs)
-{
- if (start < SAVAGE_TEXPALADDR_S3D ||
- start + count - 1 > SAVAGE_DESTTEXRWWATERMARK_S3D) {
- DRM_ERROR("invalid register range (0x%04x-0x%04x)\n",
- start, start + count - 1);
- return -EINVAL;
- }
-
- SAVE_STATE_MASK(SAVAGE_SCSTART_S3D, s3d.new_scstart,
- ~SAVAGE_SCISSOR_MASK_S3D);
- SAVE_STATE_MASK(SAVAGE_SCEND_S3D, s3d.new_scend,
- ~SAVAGE_SCISSOR_MASK_S3D);
-
- /* if any texture regs were changed ... */
- if (start <= SAVAGE_TEXCTRL_S3D &&
- start + count > SAVAGE_TEXPALADDR_S3D) {
- /* ... check texture state */
- SAVE_STATE(SAVAGE_TEXCTRL_S3D, s3d.texctrl);
- SAVE_STATE(SAVAGE_TEXADDR_S3D, s3d.texaddr);
- if (dev_priv->state.s3d.texctrl & SAVAGE_TEXCTRL_TEXEN_MASK)
- return savage_verify_texaddr(dev_priv, 0,
- dev_priv->state.s3d.texaddr);
- }
-
- return 0;
-}
-
-static int savage_verify_state_s4(drm_savage_private_t * dev_priv,
- unsigned int start, unsigned int count,
- const uint32_t *regs)
-{
- int ret = 0;
-
- if (start < SAVAGE_DRAWLOCALCTRL_S4 ||
- start + count - 1 > SAVAGE_TEXBLENDCOLOR_S4) {
- DRM_ERROR("invalid register range (0x%04x-0x%04x)\n",
- start, start + count - 1);
- return -EINVAL;
- }
-
- SAVE_STATE_MASK(SAVAGE_DRAWCTRL0_S4, s4.new_drawctrl0,
- ~SAVAGE_SCISSOR_MASK_S4);
- SAVE_STATE_MASK(SAVAGE_DRAWCTRL1_S4, s4.new_drawctrl1,
- ~SAVAGE_SCISSOR_MASK_S4);
-
- /* if any texture regs were changed ... */
- if (start <= SAVAGE_TEXDESCR_S4 &&
- start + count > SAVAGE_TEXPALADDR_S4) {
- /* ... check texture state */
- SAVE_STATE(SAVAGE_TEXDESCR_S4, s4.texdescr);
- SAVE_STATE(SAVAGE_TEXADDR0_S4, s4.texaddr0);
- SAVE_STATE(SAVAGE_TEXADDR1_S4, s4.texaddr1);
- if (dev_priv->state.s4.texdescr & SAVAGE_TEXDESCR_TEX0EN_MASK)
- ret |= savage_verify_texaddr(dev_priv, 0,
- dev_priv->state.s4.texaddr0);
- if (dev_priv->state.s4.texdescr & SAVAGE_TEXDESCR_TEX1EN_MASK)
- ret |= savage_verify_texaddr(dev_priv, 1,
- dev_priv->state.s4.texaddr1);
- }
-
- return ret;
-}
-
-#undef SAVE_STATE
-#undef SAVE_STATE_MASK
-
-static int savage_dispatch_state(drm_savage_private_t * dev_priv,
- const drm_savage_cmd_header_t * cmd_header,
- const uint32_t *regs)
-{
- unsigned int count = cmd_header->state.count;
- unsigned int start = cmd_header->state.start;
- unsigned int count2 = 0;
- unsigned int bci_size;
- int ret;
- DMA_LOCALS;
-
- if (!count)
- return 0;
-
- if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
- ret = savage_verify_state_s3d(dev_priv, start, count, regs);
- if (ret != 0)
- return ret;
- /* scissor regs are emitted in savage_dispatch_draw */
- if (start < SAVAGE_SCSTART_S3D) {
- if (start + count > SAVAGE_SCEND_S3D + 1)
- count2 = count - (SAVAGE_SCEND_S3D + 1 - start);
- if (start + count > SAVAGE_SCSTART_S3D)
- count = SAVAGE_SCSTART_S3D - start;
- } else if (start <= SAVAGE_SCEND_S3D) {
- if (start + count > SAVAGE_SCEND_S3D + 1) {
- count -= SAVAGE_SCEND_S3D + 1 - start;
- start = SAVAGE_SCEND_S3D + 1;
- } else
- return 0;
- }
- } else {
- ret = savage_verify_state_s4(dev_priv, start, count, regs);
- if (ret != 0)
- return ret;
- /* scissor regs are emitted in savage_dispatch_draw */
- if (start < SAVAGE_DRAWCTRL0_S4) {
- if (start + count > SAVAGE_DRAWCTRL1_S4 + 1)
- count2 = count -
- (SAVAGE_DRAWCTRL1_S4 + 1 - start);
- if (start + count > SAVAGE_DRAWCTRL0_S4)
- count = SAVAGE_DRAWCTRL0_S4 - start;
- } else if (start <= SAVAGE_DRAWCTRL1_S4) {
- if (start + count > SAVAGE_DRAWCTRL1_S4 + 1) {
- count -= SAVAGE_DRAWCTRL1_S4 + 1 - start;
- start = SAVAGE_DRAWCTRL1_S4 + 1;
- } else
- return 0;
- }
- }
-
- bci_size = count + (count + 254) / 255 + count2 + (count2 + 254) / 255;
-
- if (cmd_header->state.global) {
- BEGIN_DMA(bci_size + 1);
- DMA_WRITE(BCI_CMD_WAIT | BCI_CMD_WAIT_3D);
- dev_priv->waiting = 1;
- } else {
- BEGIN_DMA(bci_size);
- }
-
- do {
- while (count > 0) {
- unsigned int n = count < 255 ? count : 255;
- DMA_SET_REGISTERS(start, n);
- DMA_COPY(regs, n);
- count -= n;
- start += n;
- regs += n;
- }
- start += 2;
- regs += 2;
- count = count2;
- count2 = 0;
- } while (count);
-
- DMA_COMMIT();
-
- return 0;
-}
-
-static int savage_dispatch_dma_prim(drm_savage_private_t * dev_priv,
- const drm_savage_cmd_header_t * cmd_header,
- const struct drm_buf * dmabuf)
-{
- unsigned char reorder = 0;
- unsigned int prim = cmd_header->prim.prim;
- unsigned int skip = cmd_header->prim.skip;
- unsigned int n = cmd_header->prim.count;
- unsigned int start = cmd_header->prim.start;
- unsigned int i;
- BCI_LOCALS;
-
- if (!dmabuf) {
- DRM_ERROR("called without dma buffers!\n");
- return -EINVAL;
- }
-
- if (!n)
- return 0;
-
- switch (prim) {
- case SAVAGE_PRIM_TRILIST_201:
- reorder = 1;
- prim = SAVAGE_PRIM_TRILIST;
- fallthrough;
- case SAVAGE_PRIM_TRILIST:
- if (n % 3 != 0) {
- DRM_ERROR("wrong number of vertices %u in TRILIST\n",
- n);
- return -EINVAL;
- }
- break;
- case SAVAGE_PRIM_TRISTRIP:
- case SAVAGE_PRIM_TRIFAN:
- if (n < 3) {
- DRM_ERROR
- ("wrong number of vertices %u in TRIFAN/STRIP\n",
- n);
- return -EINVAL;
- }
- break;
- default:
- DRM_ERROR("invalid primitive type %u\n", prim);
- return -EINVAL;
- }
-
- if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
- if (skip != 0) {
- DRM_ERROR("invalid skip flags 0x%04x for DMA\n", skip);
- return -EINVAL;
- }
- } else {
- unsigned int size = 10 - (skip & 1) - (skip >> 1 & 1) -
- (skip >> 2 & 1) - (skip >> 3 & 1) - (skip >> 4 & 1) -
- (skip >> 5 & 1) - (skip >> 6 & 1) - (skip >> 7 & 1);
- if (skip > SAVAGE_SKIP_ALL_S4 || size != 8) {
- DRM_ERROR("invalid skip flags 0x%04x for DMA\n", skip);
- return -EINVAL;
- }
- if (reorder) {
- DRM_ERROR("TRILIST_201 used on Savage4 hardware\n");
- return -EINVAL;
- }
- }
-
- if (start + n > dmabuf->total / 32) {
- DRM_ERROR("vertex indices (%u-%u) out of range (0-%u)\n",
- start, start + n - 1, dmabuf->total / 32);
- return -EINVAL;
- }
-
- /* Vertex DMA doesn't work with command DMA at the same time,
- * so we use BCI_... to submit commands here. Flush buffered
- * faked DMA first. */
- DMA_FLUSH();
-
- if (dmabuf->bus_address != dev_priv->state.common.vbaddr) {
- BEGIN_BCI(2);
- BCI_SET_REGISTERS(SAVAGE_VERTBUFADDR, 1);
- BCI_WRITE(dmabuf->bus_address | dev_priv->dma_type);
- dev_priv->state.common.vbaddr = dmabuf->bus_address;
- }
- if (S3_SAVAGE3D_SERIES(dev_priv->chipset) && dev_priv->waiting) {
- /* Workaround for what looks like a hardware bug. If a
- * WAIT_3D_IDLE was emitted some time before the
- * indexed drawing command then the engine will lock
- * up. There are two known workarounds:
- * WAIT_IDLE_EMPTY or emit at least 63 NOPs. */
- BEGIN_BCI(63);
- for (i = 0; i < 63; ++i)
- BCI_WRITE(BCI_CMD_WAIT);
- dev_priv->waiting = 0;
- }
-
- prim <<= 25;
- while (n != 0) {
- /* Can emit up to 255 indices (85 triangles) at once. */
- unsigned int count = n > 255 ? 255 : n;
- if (reorder) {
- /* Need to reorder indices for correct flat
- * shading while preserving the clock sense
- * for correct culling. Only on Savage3D. */
- int reorder[3] = { -1, -1, -1 };
- reorder[start % 3] = 2;
-
- BEGIN_BCI((count + 1 + 1) / 2);
- BCI_DRAW_INDICES_S3D(count, prim, start + 2);
-
- for (i = start + 1; i + 1 < start + count; i += 2)
- BCI_WRITE((i + reorder[i % 3]) |
- ((i + 1 +
- reorder[(i + 1) % 3]) << 16));
- if (i < start + count)
- BCI_WRITE(i + reorder[i % 3]);
- } else if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
- BEGIN_BCI((count + 1 + 1) / 2);
- BCI_DRAW_INDICES_S3D(count, prim, start);
-
- for (i = start + 1; i + 1 < start + count; i += 2)
- BCI_WRITE(i | ((i + 1) << 16));
- if (i < start + count)
- BCI_WRITE(i);
- } else {
- BEGIN_BCI((count + 2 + 1) / 2);
- BCI_DRAW_INDICES_S4(count, prim, skip);
-
- for (i = start; i + 1 < start + count; i += 2)
- BCI_WRITE(i | ((i + 1) << 16));
- if (i < start + count)
- BCI_WRITE(i);
- }
-
- start += count;
- n -= count;
-
- prim |= BCI_CMD_DRAW_CONT;
- }
-
- return 0;
-}
-
-static int savage_dispatch_vb_prim(drm_savage_private_t * dev_priv,
- const drm_savage_cmd_header_t * cmd_header,
- const uint32_t *vtxbuf, unsigned int vb_size,
- unsigned int vb_stride)
-{
- unsigned char reorder = 0;
- unsigned int prim = cmd_header->prim.prim;
- unsigned int skip = cmd_header->prim.skip;
- unsigned int n = cmd_header->prim.count;
- unsigned int start = cmd_header->prim.start;
- unsigned int vtx_size;
- unsigned int i;
- DMA_LOCALS;
-
- if (!n)
- return 0;
-
- switch (prim) {
- case SAVAGE_PRIM_TRILIST_201:
- reorder = 1;
- prim = SAVAGE_PRIM_TRILIST;
- fallthrough;
- case SAVAGE_PRIM_TRILIST:
- if (n % 3 != 0) {
- DRM_ERROR("wrong number of vertices %u in TRILIST\n",
- n);
- return -EINVAL;
- }
- break;
- case SAVAGE_PRIM_TRISTRIP:
- case SAVAGE_PRIM_TRIFAN:
- if (n < 3) {
- DRM_ERROR
- ("wrong number of vertices %u in TRIFAN/STRIP\n",
- n);
- return -EINVAL;
- }
- break;
- default:
- DRM_ERROR("invalid primitive type %u\n", prim);
- return -EINVAL;
- }
-
- if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
- if (skip > SAVAGE_SKIP_ALL_S3D) {
- DRM_ERROR("invalid skip flags 0x%04x\n", skip);
- return -EINVAL;
- }
- vtx_size = 8; /* full vertex */
- } else {
- if (skip > SAVAGE_SKIP_ALL_S4) {
- DRM_ERROR("invalid skip flags 0x%04x\n", skip);
- return -EINVAL;
- }
- vtx_size = 10; /* full vertex */
- }
-
- vtx_size -= (skip & 1) + (skip >> 1 & 1) +
- (skip >> 2 & 1) + (skip >> 3 & 1) + (skip >> 4 & 1) +
- (skip >> 5 & 1) + (skip >> 6 & 1) + (skip >> 7 & 1);
-
- if (vtx_size > vb_stride) {
- DRM_ERROR("vertex size greater than vb stride (%u > %u)\n",
- vtx_size, vb_stride);
- return -EINVAL;
- }
-
- if (start + n > vb_size / (vb_stride * 4)) {
- DRM_ERROR("vertex indices (%u-%u) out of range (0-%u)\n",
- start, start + n - 1, vb_size / (vb_stride * 4));
- return -EINVAL;
- }
-
- prim <<= 25;
- while (n != 0) {
- /* Can emit up to 255 vertices (85 triangles) at once. */
- unsigned int count = n > 255 ? 255 : n;
- if (reorder) {
- /* Need to reorder vertices for correct flat
- * shading while preserving the clock sense
- * for correct culling. Only on Savage3D. */
- int reorder[3] = { -1, -1, -1 };
- reorder[start % 3] = 2;
-
- BEGIN_DMA(count * vtx_size + 1);
- DMA_DRAW_PRIMITIVE(count, prim, skip);
-
- for (i = start; i < start + count; ++i) {
- unsigned int j = i + reorder[i % 3];
- DMA_COPY(&vtxbuf[vb_stride * j], vtx_size);
- }
-
- DMA_COMMIT();
- } else {
- BEGIN_DMA(count * vtx_size + 1);
- DMA_DRAW_PRIMITIVE(count, prim, skip);
-
- if (vb_stride == vtx_size) {
- DMA_COPY(&vtxbuf[vb_stride * start],
- vtx_size * count);
- } else {
- for (i = start; i < start + count; ++i) {
- DMA_COPY(&vtxbuf [vb_stride * i],
- vtx_size);
- }
- }
-
- DMA_COMMIT();
- }
-
- start += count;
- n -= count;
-
- prim |= BCI_CMD_DRAW_CONT;
- }
-
- return 0;
-}
-
-static int savage_dispatch_dma_idx(drm_savage_private_t * dev_priv,
- const drm_savage_cmd_header_t * cmd_header,
- const uint16_t *idx,
- const struct drm_buf * dmabuf)
-{
- unsigned char reorder = 0;
- unsigned int prim = cmd_header->idx.prim;
- unsigned int skip = cmd_header->idx.skip;
- unsigned int n = cmd_header->idx.count;
- unsigned int i;
- BCI_LOCALS;
-
- if (!dmabuf) {
- DRM_ERROR("called without dma buffers!\n");
- return -EINVAL;
- }
-
- if (!n)
- return 0;
-
- switch (prim) {
- case SAVAGE_PRIM_TRILIST_201:
- reorder = 1;
- prim = SAVAGE_PRIM_TRILIST;
- fallthrough;
- case SAVAGE_PRIM_TRILIST:
- if (n % 3 != 0) {
- DRM_ERROR("wrong number of indices %u in TRILIST\n", n);
- return -EINVAL;
- }
- break;
- case SAVAGE_PRIM_TRISTRIP:
- case SAVAGE_PRIM_TRIFAN:
- if (n < 3) {
- DRM_ERROR
- ("wrong number of indices %u in TRIFAN/STRIP\n", n);
- return -EINVAL;
- }
- break;
- default:
- DRM_ERROR("invalid primitive type %u\n", prim);
- return -EINVAL;
- }
-
- if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
- if (skip != 0) {
- DRM_ERROR("invalid skip flags 0x%04x for DMA\n", skip);
- return -EINVAL;
- }
- } else {
- unsigned int size = 10 - (skip & 1) - (skip >> 1 & 1) -
- (skip >> 2 & 1) - (skip >> 3 & 1) - (skip >> 4 & 1) -
- (skip >> 5 & 1) - (skip >> 6 & 1) - (skip >> 7 & 1);
- if (skip > SAVAGE_SKIP_ALL_S4 || size != 8) {
- DRM_ERROR("invalid skip flags 0x%04x for DMA\n", skip);
- return -EINVAL;
- }
- if (reorder) {
- DRM_ERROR("TRILIST_201 used on Savage4 hardware\n");
- return -EINVAL;
- }
- }
-
- /* Vertex DMA doesn't work with command DMA at the same time,
- * so we use BCI_... to submit commands here. Flush buffered
- * faked DMA first. */
- DMA_FLUSH();
-
- if (dmabuf->bus_address != dev_priv->state.common.vbaddr) {
- BEGIN_BCI(2);
- BCI_SET_REGISTERS(SAVAGE_VERTBUFADDR, 1);
- BCI_WRITE(dmabuf->bus_address | dev_priv->dma_type);
- dev_priv->state.common.vbaddr = dmabuf->bus_address;
- }
- if (S3_SAVAGE3D_SERIES(dev_priv->chipset) && dev_priv->waiting) {
- /* Workaround for what looks like a hardware bug. If a
- * WAIT_3D_IDLE was emitted some time before the
- * indexed drawing command then the engine will lock
- * up. There are two known workarounds:
- * WAIT_IDLE_EMPTY or emit at least 63 NOPs. */
- BEGIN_BCI(63);
- for (i = 0; i < 63; ++i)
- BCI_WRITE(BCI_CMD_WAIT);
- dev_priv->waiting = 0;
- }
-
- prim <<= 25;
- while (n != 0) {
- /* Can emit up to 255 indices (85 triangles) at once. */
- unsigned int count = n > 255 ? 255 : n;
-
- /* check indices */
- for (i = 0; i < count; ++i) {
- if (idx[i] > dmabuf->total / 32) {
- DRM_ERROR("idx[%u]=%u out of range (0-%u)\n",
- i, idx[i], dmabuf->total / 32);
- return -EINVAL;
- }
- }
-
- if (reorder) {
- /* Need to reorder indices for correct flat
- * shading while preserving the clock sense
- * for correct culling. Only on Savage3D. */
- int reorder[3] = { 2, -1, -1 };
-
- BEGIN_BCI((count + 1 + 1) / 2);
- BCI_DRAW_INDICES_S3D(count, prim, idx[2]);
-
- for (i = 1; i + 1 < count; i += 2)
- BCI_WRITE(idx[i + reorder[i % 3]] |
- (idx[i + 1 +
- reorder[(i + 1) % 3]] << 16));
- if (i < count)
- BCI_WRITE(idx[i + reorder[i % 3]]);
- } else if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
- BEGIN_BCI((count + 1 + 1) / 2);
- BCI_DRAW_INDICES_S3D(count, prim, idx[0]);
-
- for (i = 1; i + 1 < count; i += 2)
- BCI_WRITE(idx[i] | (idx[i + 1] << 16));
- if (i < count)
- BCI_WRITE(idx[i]);
- } else {
- BEGIN_BCI((count + 2 + 1) / 2);
- BCI_DRAW_INDICES_S4(count, prim, skip);
-
- for (i = 0; i + 1 < count; i += 2)
- BCI_WRITE(idx[i] | (idx[i + 1] << 16));
- if (i < count)
- BCI_WRITE(idx[i]);
- }
-
- idx += count;
- n -= count;
-
- prim |= BCI_CMD_DRAW_CONT;
- }
-
- return 0;
-}
-
-static int savage_dispatch_vb_idx(drm_savage_private_t * dev_priv,
- const drm_savage_cmd_header_t * cmd_header,
- const uint16_t *idx,
- const uint32_t *vtxbuf,
- unsigned int vb_size, unsigned int vb_stride)
-{
- unsigned char reorder = 0;
- unsigned int prim = cmd_header->idx.prim;
- unsigned int skip = cmd_header->idx.skip;
- unsigned int n = cmd_header->idx.count;
- unsigned int vtx_size;
- unsigned int i;
- DMA_LOCALS;
-
- if (!n)
- return 0;
-
- switch (prim) {
- case SAVAGE_PRIM_TRILIST_201:
- reorder = 1;
- prim = SAVAGE_PRIM_TRILIST;
- fallthrough;
- case SAVAGE_PRIM_TRILIST:
- if (n % 3 != 0) {
- DRM_ERROR("wrong number of indices %u in TRILIST\n", n);
- return -EINVAL;
- }
- break;
- case SAVAGE_PRIM_TRISTRIP:
- case SAVAGE_PRIM_TRIFAN:
- if (n < 3) {
- DRM_ERROR
- ("wrong number of indices %u in TRIFAN/STRIP\n", n);
- return -EINVAL;
- }
- break;
- default:
- DRM_ERROR("invalid primitive type %u\n", prim);
- return -EINVAL;
- }
-
- if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
- if (skip > SAVAGE_SKIP_ALL_S3D) {
- DRM_ERROR("invalid skip flags 0x%04x\n", skip);
- return -EINVAL;
- }
- vtx_size = 8; /* full vertex */
- } else {
- if (skip > SAVAGE_SKIP_ALL_S4) {
- DRM_ERROR("invalid skip flags 0x%04x\n", skip);
- return -EINVAL;
- }
- vtx_size = 10; /* full vertex */
- }
-
- vtx_size -= (skip & 1) + (skip >> 1 & 1) +
- (skip >> 2 & 1) + (skip >> 3 & 1) + (skip >> 4 & 1) +
- (skip >> 5 & 1) + (skip >> 6 & 1) + (skip >> 7 & 1);
-
- if (vtx_size > vb_stride) {
- DRM_ERROR("vertex size greater than vb stride (%u > %u)\n",
- vtx_size, vb_stride);
- return -EINVAL;
- }
-
- prim <<= 25;
- while (n != 0) {
- /* Can emit up to 255 vertices (85 triangles) at once. */
- unsigned int count = n > 255 ? 255 : n;
-
- /* Check indices */
- for (i = 0; i < count; ++i) {
- if (idx[i] > vb_size / (vb_stride * 4)) {
- DRM_ERROR("idx[%u]=%u out of range (0-%u)\n",
- i, idx[i], vb_size / (vb_stride * 4));
- return -EINVAL;
- }
- }
-
- if (reorder) {
- /* Need to reorder vertices for correct flat
- * shading while preserving the clock sense
- * for correct culling. Only on Savage3D. */
- int reorder[3] = { 2, -1, -1 };
-
- BEGIN_DMA(count * vtx_size + 1);
- DMA_DRAW_PRIMITIVE(count, prim, skip);
-
- for (i = 0; i < count; ++i) {
- unsigned int j = idx[i + reorder[i % 3]];
- DMA_COPY(&vtxbuf[vb_stride * j], vtx_size);
- }
-
- DMA_COMMIT();
- } else {
- BEGIN_DMA(count * vtx_size + 1);
- DMA_DRAW_PRIMITIVE(count, prim, skip);
-
- for (i = 0; i < count; ++i) {
- unsigned int j = idx[i];
- DMA_COPY(&vtxbuf[vb_stride * j], vtx_size);
- }
-
- DMA_COMMIT();
- }
-
- idx += count;
- n -= count;
-
- prim |= BCI_CMD_DRAW_CONT;
- }
-
- return 0;
-}
-
-static int savage_dispatch_clear(drm_savage_private_t * dev_priv,
- const drm_savage_cmd_header_t * cmd_header,
- const drm_savage_cmd_header_t *data,
- unsigned int nbox,
- const struct drm_clip_rect *boxes)
-{
- unsigned int flags = cmd_header->clear0.flags;
- unsigned int clear_cmd;
- unsigned int i, nbufs;
- DMA_LOCALS;
-
- if (nbox == 0)
- return 0;
-
- clear_cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP |
- BCI_CMD_SEND_COLOR | BCI_CMD_DEST_PBD_NEW;
- BCI_CMD_SET_ROP(clear_cmd, 0xCC);
-
- nbufs = ((flags & SAVAGE_FRONT) ? 1 : 0) +
- ((flags & SAVAGE_BACK) ? 1 : 0) + ((flags & SAVAGE_DEPTH) ? 1 : 0);
- if (nbufs == 0)
- return 0;
-
- if (data->clear1.mask != 0xffffffff) {
- /* set mask */
- BEGIN_DMA(2);
- DMA_SET_REGISTERS(SAVAGE_BITPLANEWTMASK, 1);
- DMA_WRITE(data->clear1.mask);
- DMA_COMMIT();
- }
- for (i = 0; i < nbox; ++i) {
- unsigned int x, y, w, h;
- unsigned int buf;
- x = boxes[i].x1, y = boxes[i].y1;
- w = boxes[i].x2 - boxes[i].x1;
- h = boxes[i].y2 - boxes[i].y1;
- BEGIN_DMA(nbufs * 6);
- for (buf = SAVAGE_FRONT; buf <= SAVAGE_DEPTH; buf <<= 1) {
- if (!(flags & buf))
- continue;
- DMA_WRITE(clear_cmd);
- switch (buf) {
- case SAVAGE_FRONT:
- DMA_WRITE(dev_priv->front_offset);
- DMA_WRITE(dev_priv->front_bd);
- break;
- case SAVAGE_BACK:
- DMA_WRITE(dev_priv->back_offset);
- DMA_WRITE(dev_priv->back_bd);
- break;
- case SAVAGE_DEPTH:
- DMA_WRITE(dev_priv->depth_offset);
- DMA_WRITE(dev_priv->depth_bd);
- break;
- }
- DMA_WRITE(data->clear1.value);
- DMA_WRITE(BCI_X_Y(x, y));
- DMA_WRITE(BCI_W_H(w, h));
- }
- DMA_COMMIT();
- }
- if (data->clear1.mask != 0xffffffff) {
- /* reset mask */
- BEGIN_DMA(2);
- DMA_SET_REGISTERS(SAVAGE_BITPLANEWTMASK, 1);
- DMA_WRITE(0xffffffff);
- DMA_COMMIT();
- }
-
- return 0;
-}
-
-static int savage_dispatch_swap(drm_savage_private_t * dev_priv,
- unsigned int nbox, const struct drm_clip_rect *boxes)
-{
- unsigned int swap_cmd;
- unsigned int i;
- DMA_LOCALS;
-
- if (nbox == 0)
- return 0;
-
- swap_cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP |
- BCI_CMD_SRC_PBD_COLOR_NEW | BCI_CMD_DEST_GBD;
- BCI_CMD_SET_ROP(swap_cmd, 0xCC);
-
- for (i = 0; i < nbox; ++i) {
- BEGIN_DMA(6);
- DMA_WRITE(swap_cmd);
- DMA_WRITE(dev_priv->back_offset);
- DMA_WRITE(dev_priv->back_bd);
- DMA_WRITE(BCI_X_Y(boxes[i].x1, boxes[i].y1));
- DMA_WRITE(BCI_X_Y(boxes[i].x1, boxes[i].y1));
- DMA_WRITE(BCI_W_H(boxes[i].x2 - boxes[i].x1,
- boxes[i].y2 - boxes[i].y1));
- DMA_COMMIT();
- }
-
- return 0;
-}
-
-static int savage_dispatch_draw(drm_savage_private_t * dev_priv,
- const drm_savage_cmd_header_t *start,
- const drm_savage_cmd_header_t *end,
- const struct drm_buf * dmabuf,
- const unsigned int *vtxbuf,
- unsigned int vb_size, unsigned int vb_stride,
- unsigned int nbox,
- const struct drm_clip_rect *boxes)
-{
- unsigned int i, j;
- int ret;
-
- for (i = 0; i < nbox; ++i) {
- const drm_savage_cmd_header_t *cmdbuf;
- dev_priv->emit_clip_rect(dev_priv, &boxes[i]);
-
- cmdbuf = start;
- while (cmdbuf < end) {
- drm_savage_cmd_header_t cmd_header;
- cmd_header = *cmdbuf;
- cmdbuf++;
- switch (cmd_header.cmd.cmd) {
- case SAVAGE_CMD_DMA_PRIM:
- ret = savage_dispatch_dma_prim(
- dev_priv, &cmd_header, dmabuf);
- break;
- case SAVAGE_CMD_VB_PRIM:
- ret = savage_dispatch_vb_prim(
- dev_priv, &cmd_header,
- vtxbuf, vb_size, vb_stride);
- break;
- case SAVAGE_CMD_DMA_IDX:
- j = (cmd_header.idx.count + 3) / 4;
- /* j was check in savage_bci_cmdbuf */
- ret = savage_dispatch_dma_idx(dev_priv,
- &cmd_header, (const uint16_t *)cmdbuf,
- dmabuf);
- cmdbuf += j;
- break;
- case SAVAGE_CMD_VB_IDX:
- j = (cmd_header.idx.count + 3) / 4;
- /* j was check in savage_bci_cmdbuf */
- ret = savage_dispatch_vb_idx(dev_priv,
- &cmd_header, (const uint16_t *)cmdbuf,
- (const uint32_t *)vtxbuf, vb_size,
- vb_stride);
- cmdbuf += j;
- break;
- default:
- /* What's the best return code? EFAULT? */
- DRM_ERROR("IMPLEMENTATION ERROR: "
- "non-drawing-command %d\n",
- cmd_header.cmd.cmd);
- return -EINVAL;
- }
-
- if (ret != 0)
- return ret;
- }
- }
-
- return 0;
-}
-
-int savage_bci_cmdbuf(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_savage_private_t *dev_priv = dev->dev_private;
- struct drm_device_dma *dma = dev->dma;
- struct drm_buf *dmabuf;
- drm_savage_cmdbuf_t *cmdbuf = data;
- drm_savage_cmd_header_t *kcmd_addr = NULL;
- drm_savage_cmd_header_t *first_draw_cmd;
- unsigned int *kvb_addr = NULL;
- struct drm_clip_rect *kbox_addr = NULL;
- unsigned int i, j;
- int ret = 0;
-
- DRM_DEBUG("\n");
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- if (dma && dma->buflist) {
- if (cmdbuf->dma_idx >= dma->buf_count) {
- DRM_ERROR
- ("vertex buffer index %u out of range (0-%u)\n",
- cmdbuf->dma_idx, dma->buf_count - 1);
- return -EINVAL;
- }
- dmabuf = dma->buflist[cmdbuf->dma_idx];
- } else {
- dmabuf = NULL;
- }
-
- /* Copy the user buffers into kernel temporary areas. This hasn't been
- * a performance loss compared to VERIFYAREA_READ/
- * COPY_FROM_USER_UNCHECKED when done in other drivers, and is correct
- * for locking on FreeBSD.
- */
- if (cmdbuf->size) {
- kcmd_addr = kmalloc_array(cmdbuf->size, 8, GFP_KERNEL);
- if (kcmd_addr == NULL)
- return -ENOMEM;
-
- if (copy_from_user(kcmd_addr, cmdbuf->cmd_addr,
- cmdbuf->size * 8))
- {
- kfree(kcmd_addr);
- return -EFAULT;
- }
- cmdbuf->cmd_addr = kcmd_addr;
- }
- if (cmdbuf->vb_size) {
- kvb_addr = memdup_user(cmdbuf->vb_addr, cmdbuf->vb_size);
- if (IS_ERR(kvb_addr)) {
- ret = PTR_ERR(kvb_addr);
- kvb_addr = NULL;
- goto done;
- }
- cmdbuf->vb_addr = kvb_addr;
- }
- if (cmdbuf->nbox) {
- kbox_addr = kmalloc_array(cmdbuf->nbox, sizeof(struct drm_clip_rect),
- GFP_KERNEL);
- if (kbox_addr == NULL) {
- ret = -ENOMEM;
- goto done;
- }
-
- if (copy_from_user(kbox_addr, cmdbuf->box_addr,
- cmdbuf->nbox * sizeof(struct drm_clip_rect))) {
- ret = -EFAULT;
- goto done;
- }
- cmdbuf->box_addr = kbox_addr;
- }
-
- /* Make sure writes to DMA buffers are finished before sending
- * DMA commands to the graphics hardware. */
- mb();
-
- /* Coming from user space. Don't know if the Xserver has
- * emitted wait commands. Assuming the worst. */
- dev_priv->waiting = 1;
-
- i = 0;
- first_draw_cmd = NULL;
- while (i < cmdbuf->size) {
- drm_savage_cmd_header_t cmd_header;
- cmd_header = *(drm_savage_cmd_header_t *)cmdbuf->cmd_addr;
- cmdbuf->cmd_addr++;
- i++;
-
- /* Group drawing commands with same state to minimize
- * iterations over clip rects. */
- j = 0;
- switch (cmd_header.cmd.cmd) {
- case SAVAGE_CMD_DMA_IDX:
- case SAVAGE_CMD_VB_IDX:
- j = (cmd_header.idx.count + 3) / 4;
- if (i + j > cmdbuf->size) {
- DRM_ERROR("indexed drawing command extends "
- "beyond end of command buffer\n");
- DMA_FLUSH();
- ret = -EINVAL;
- goto done;
- }
- fallthrough;
- case SAVAGE_CMD_DMA_PRIM:
- case SAVAGE_CMD_VB_PRIM:
- if (!first_draw_cmd)
- first_draw_cmd = cmdbuf->cmd_addr - 1;
- cmdbuf->cmd_addr += j;
- i += j;
- break;
- default:
- if (first_draw_cmd) {
- ret = savage_dispatch_draw(
- dev_priv, first_draw_cmd,
- cmdbuf->cmd_addr - 1,
- dmabuf, cmdbuf->vb_addr, cmdbuf->vb_size,
- cmdbuf->vb_stride,
- cmdbuf->nbox, cmdbuf->box_addr);
- if (ret != 0)
- goto done;
- first_draw_cmd = NULL;
- }
- }
- if (first_draw_cmd)
- continue;
-
- switch (cmd_header.cmd.cmd) {
- case SAVAGE_CMD_STATE:
- j = (cmd_header.state.count + 1) / 2;
- if (i + j > cmdbuf->size) {
- DRM_ERROR("command SAVAGE_CMD_STATE extends "
- "beyond end of command buffer\n");
- DMA_FLUSH();
- ret = -EINVAL;
- goto done;
- }
- ret = savage_dispatch_state(dev_priv, &cmd_header,
- (const uint32_t *)cmdbuf->cmd_addr);
- cmdbuf->cmd_addr += j;
- i += j;
- break;
- case SAVAGE_CMD_CLEAR:
- if (i + 1 > cmdbuf->size) {
- DRM_ERROR("command SAVAGE_CMD_CLEAR extends "
- "beyond end of command buffer\n");
- DMA_FLUSH();
- ret = -EINVAL;
- goto done;
- }
- ret = savage_dispatch_clear(dev_priv, &cmd_header,
- cmdbuf->cmd_addr,
- cmdbuf->nbox,
- cmdbuf->box_addr);
- cmdbuf->cmd_addr++;
- i++;
- break;
- case SAVAGE_CMD_SWAP:
- ret = savage_dispatch_swap(dev_priv, cmdbuf->nbox,
- cmdbuf->box_addr);
- break;
- default:
- DRM_ERROR("invalid command 0x%x\n",
- cmd_header.cmd.cmd);
- DMA_FLUSH();
- ret = -EINVAL;
- goto done;
- }
-
- if (ret != 0) {
- DMA_FLUSH();
- goto done;
- }
- }
-
- if (first_draw_cmd) {
- ret = savage_dispatch_draw (
- dev_priv, first_draw_cmd, cmdbuf->cmd_addr, dmabuf,
- cmdbuf->vb_addr, cmdbuf->vb_size, cmdbuf->vb_stride,
- cmdbuf->nbox, cmdbuf->box_addr);
- if (ret != 0) {
- DMA_FLUSH();
- goto done;
- }
- }
-
- DMA_FLUSH();
-
- if (dmabuf && cmdbuf->discard) {
- drm_savage_buf_priv_t *buf_priv = dmabuf->dev_private;
- uint16_t event;
- event = savage_bci_emit_event(dev_priv, SAVAGE_WAIT_3D);
- SET_AGE(&buf_priv->age, event, dev_priv->event_wrap);
- savage_freelist_put(dev, dmabuf);
- }
-
-done:
- /* If we didn't need to allocate them, these'll be NULL */
- kfree(kcmd_addr);
- kfree(kvb_addr);
- kfree(kbox_addr);
-
- return ret;
-}
diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c
index fd22d753b4ed..4e6ad6e122bc 100644
--- a/drivers/gpu/drm/scheduler/sched_main.c
+++ b/drivers/gpu/drm/scheduler/sched_main.c
@@ -551,10 +551,21 @@ void drm_sched_start(struct drm_gpu_scheduler *sched, bool full_recovery)
EXPORT_SYMBOL(drm_sched_start);
/**
- * drm_sched_resubmit_jobs - helper to relaunch jobs from the pending list
+ * drm_sched_resubmit_jobs - Deprecated, don't use in new code!
*
* @sched: scheduler instance
*
+ * Re-submitting jobs was a concept AMD came up as cheap way to implement
+ * recovery after a job timeout.
+ *
+ * This turned out to be not working very well. First of all there are many
+ * problem with the dma_fence implementation and requirements. Either the
+ * implementation is risking deadlocks with core memory management or violating
+ * documented implementation details of the dma_fence object.
+ *
+ * Drivers can still save and restore their state for recovery operations, but
+ * we shouldn't make this a general scheduler feature around the dma_fence
+ * interface.
*/
void drm_sched_resubmit_jobs(struct drm_gpu_scheduler *sched)
{
@@ -895,6 +906,12 @@ drm_sched_get_cleanup_job(struct drm_gpu_scheduler *sched)
spin_unlock(&sched->job_list_lock);
+ if (job) {
+ job->entity->elapsed_ns += ktime_to_ns(
+ ktime_sub(job->s_fence->finished.timestamp,
+ job->s_fence->scheduled.timestamp));
+ }
+
return job;
}
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
index 4624c0aff51f..d354ab3077ce 100644
--- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
+++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
@@ -16,6 +16,8 @@
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_dma_helper.h>
+#include <drm/drm_modeset_helper.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h>
#include <drm/drm_vblank.h>
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/shmobile/shmob_drm_drv.c
index 3d511fa38913..faacfee24763 100644
--- a/drivers/gpu/drm/shmobile/shmob_drm_drv.c
+++ b/drivers/gpu/drm/shmobile/shmob_drm_drv.c
@@ -15,7 +15,6 @@
#include <linux/pm.h>
#include <linux/slab.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_module.h>
@@ -143,7 +142,6 @@ static const struct drm_driver shmob_drm_driver = {
* Power management
*/
-#ifdef CONFIG_PM_SLEEP
static int shmob_drm_pm_suspend(struct device *dev)
{
struct shmob_drm_device *sdev = dev_get_drvdata(dev);
@@ -165,11 +163,9 @@ static int shmob_drm_pm_resume(struct device *dev)
drm_kms_helper_poll_enable(sdev->ddev);
return 0;
}
-#endif
-static const struct dev_pm_ops shmob_drm_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(shmob_drm_pm_suspend, shmob_drm_pm_resume)
-};
+static DEFINE_SIMPLE_DEV_PM_OPS(shmob_drm_pm_ops,
+ shmob_drm_pm_suspend, shmob_drm_pm_resume);
/* -----------------------------------------------------------------------------
* Platform driver
@@ -292,7 +288,7 @@ static struct platform_driver shmob_drm_platform_driver = {
.remove = shmob_drm_remove,
.driver = {
.name = "shmob-drm",
- .pm = &shmob_drm_pm_ops,
+ .pm = pm_sleep_ptr(&shmob_drm_pm_ops),
},
};
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_plane.c b/drivers/gpu/drm/shmobile/shmob_drm_plane.c
index 6c5f0cbe7d95..604ae23825da 100644
--- a/drivers/gpu/drm/shmobile/shmob_drm_plane.c
+++ b/drivers/gpu/drm/shmobile/shmob_drm_plane.c
@@ -8,7 +8,6 @@
*/
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_dma_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
diff --git a/drivers/gpu/drm/sis/Makefile b/drivers/gpu/drm/sis/Makefile
deleted file mode 100644
index 02b0253fda93..000000000000
--- a/drivers/gpu/drm/sis/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Makefile for the drm device driver. This driver provides support for the
-# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
-
-sis-y := sis_drv.o sis_mm.o
-
-obj-$(CONFIG_DRM_SIS) += sis.o
-
-
diff --git a/drivers/gpu/drm/sis/sis_drv.c b/drivers/gpu/drm/sis/sis_drv.c
deleted file mode 100644
index 6173020a9bf5..000000000000
--- a/drivers/gpu/drm/sis/sis_drv.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/* sis.c -- sis driver -*- linux-c -*-
- *
- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software 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 (including the next
- * paragraph) 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
- * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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.
- *
- */
-
-#include <linux/module.h>
-#include <linux/pci.h>
-
-#include <drm/drm_drv.h>
-#include <drm/drm_file.h>
-#include <drm/drm_pciids.h>
-#include <drm/sis_drm.h>
-
-#include "sis_drv.h"
-
-static struct pci_device_id pciidlist[] = {
- sisdrv_PCI_IDS
-};
-
-static int sis_driver_load(struct drm_device *dev, unsigned long chipset)
-{
- struct pci_dev *pdev = to_pci_dev(dev->dev);
- drm_sis_private_t *dev_priv;
-
- pci_set_master(pdev);
-
- dev_priv = kzalloc(sizeof(drm_sis_private_t), GFP_KERNEL);
- if (dev_priv == NULL)
- return -ENOMEM;
-
- idr_init_base(&dev_priv->object_idr, 1);
- dev->dev_private = (void *)dev_priv;
- dev_priv->chipset = chipset;
-
- return 0;
-}
-
-static void sis_driver_unload(struct drm_device *dev)
-{
- drm_sis_private_t *dev_priv = dev->dev_private;
-
- idr_destroy(&dev_priv->object_idr);
-
- kfree(dev_priv);
-}
-
-static const struct file_operations sis_driver_fops = {
- .owner = THIS_MODULE,
- .open = drm_open,
- .release = drm_release,
- .unlocked_ioctl = drm_ioctl,
- .mmap = drm_legacy_mmap,
- .poll = drm_poll,
- .compat_ioctl = drm_compat_ioctl,
- .llseek = noop_llseek,
-};
-
-static int sis_driver_open(struct drm_device *dev, struct drm_file *file)
-{
- struct sis_file_private *file_priv;
-
- DRM_DEBUG_DRIVER("\n");
- file_priv = kmalloc(sizeof(*file_priv), GFP_KERNEL);
- if (!file_priv)
- return -ENOMEM;
-
- file->driver_priv = file_priv;
-
- INIT_LIST_HEAD(&file_priv->obj_list);
-
- return 0;
-}
-
-static void sis_driver_postclose(struct drm_device *dev, struct drm_file *file)
-{
- struct sis_file_private *file_priv = file->driver_priv;
-
- kfree(file_priv);
-}
-
-static struct drm_driver driver = {
- .driver_features = DRIVER_USE_AGP | DRIVER_LEGACY,
- .load = sis_driver_load,
- .unload = sis_driver_unload,
- .open = sis_driver_open,
- .preclose = sis_reclaim_buffers_locked,
- .postclose = sis_driver_postclose,
- .dma_quiescent = sis_idle,
- .lastclose = sis_lastclose,
- .ioctls = sis_ioctls,
- .fops = &sis_driver_fops,
- .name = DRIVER_NAME,
- .desc = DRIVER_DESC,
- .date = DRIVER_DATE,
- .major = DRIVER_MAJOR,
- .minor = DRIVER_MINOR,
- .patchlevel = DRIVER_PATCHLEVEL,
-};
-
-static struct pci_driver sis_pci_driver = {
- .name = DRIVER_NAME,
- .id_table = pciidlist,
-};
-
-static int __init sis_init(void)
-{
- driver.num_ioctls = sis_max_ioctl;
- return drm_legacy_pci_init(&driver, &sis_pci_driver);
-}
-
-static void __exit sis_exit(void)
-{
- drm_legacy_pci_exit(&driver, &sis_pci_driver);
-}
-
-module_init(sis_init);
-module_exit(sis_exit);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/gpu/drm/sis/sis_drv.h b/drivers/gpu/drm/sis/sis_drv.h
deleted file mode 100644
index 81339443b3b1..000000000000
--- a/drivers/gpu/drm/sis/sis_drv.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/* sis_drv.h -- Private header for sis driver -*- linux-c -*- */
-/*
- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software 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 (including the next
- * paragraph) 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
- * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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.
- *
- */
-
-#ifndef _SIS_DRV_H_
-#define _SIS_DRV_H_
-
-#include <drm/drm_ioctl.h>
-#include <drm/drm_legacy.h>
-#include <drm/drm_mm.h>
-
-/* General customization:
- */
-
-#define DRIVER_AUTHOR "SIS, Tungsten Graphics"
-#define DRIVER_NAME "sis"
-#define DRIVER_DESC "SIS 300/630/540 and XGI V3XE/V5/V8"
-#define DRIVER_DATE "20070626"
-#define DRIVER_MAJOR 1
-#define DRIVER_MINOR 3
-#define DRIVER_PATCHLEVEL 0
-
-enum sis_family {
- SIS_OTHER = 0,
- SIS_CHIP_315 = 1,
-};
-
-#define SIS_READ(reg) readl(((void __iomem *)dev_priv->mmio->handle) + (reg))
-#define SIS_WRITE(reg, val) writel(val, ((void __iomem *)dev_priv->mmio->handle) + (reg))
-
-typedef struct drm_sis_private {
- drm_local_map_t *mmio;
- unsigned int idle_fault;
- unsigned int chipset;
- int vram_initialized;
- int agp_initialized;
- unsigned long vram_offset;
- unsigned long agp_offset;
- struct drm_mm vram_mm;
- struct drm_mm agp_mm;
- /** Mapping of userspace keys to mm objects */
- struct idr object_idr;
-} drm_sis_private_t;
-
-struct sis_file_private {
- struct list_head obj_list;
-};
-
-extern int sis_idle(struct drm_device *dev);
-extern void sis_reclaim_buffers_locked(struct drm_device *dev,
- struct drm_file *file_priv);
-extern void sis_lastclose(struct drm_device *dev);
-
-extern const struct drm_ioctl_desc sis_ioctls[];
-extern int sis_max_ioctl;
-
-#endif
diff --git a/drivers/gpu/drm/sis/sis_mm.c b/drivers/gpu/drm/sis/sis_mm.c
deleted file mode 100644
index e51d4289a3d0..000000000000
--- a/drivers/gpu/drm/sis/sis_mm.c
+++ /dev/null
@@ -1,363 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software 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, sub license, 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 (including the
- * next paragraph) 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 NON-INFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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.
- *
- *
- **************************************************************************/
-
-/*
- * Authors:
- * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
- */
-
-#include <video/sisfb.h>
-
-#include <drm/drm_device.h>
-#include <drm/drm_file.h>
-#include <drm/sis_drm.h>
-
-#include "sis_drv.h"
-
-
-#define VIDEO_TYPE 0
-#define AGP_TYPE 1
-
-
-struct sis_memblock {
- struct drm_mm_node mm_node;
- struct sis_memreq req;
- struct list_head owner_list;
-};
-
-#if defined(CONFIG_FB_SIS) || defined(CONFIG_FB_SIS_MODULE)
-/* fb management via fb device */
-
-#define SIS_MM_ALIGN_SHIFT 0
-#define SIS_MM_ALIGN_MASK 0
-
-#else /* CONFIG_FB_SIS[_MODULE] */
-
-#define SIS_MM_ALIGN_SHIFT 4
-#define SIS_MM_ALIGN_MASK ((1 << SIS_MM_ALIGN_SHIFT) - 1)
-
-#endif /* CONFIG_FB_SIS[_MODULE] */
-
-static int sis_fb_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_sis_private_t *dev_priv = dev->dev_private;
- drm_sis_fb_t *fb = data;
-
- mutex_lock(&dev->struct_mutex);
- /* Unconditionally init the drm_mm, even though we don't use it when the
- * fb sis driver is available - make cleanup easier. */
- drm_mm_init(&dev_priv->vram_mm, 0, fb->size >> SIS_MM_ALIGN_SHIFT);
-
- dev_priv->vram_initialized = 1;
- dev_priv->vram_offset = fb->offset;
-
- mutex_unlock(&dev->struct_mutex);
- DRM_DEBUG("offset = %lu, size = %lu\n", fb->offset, fb->size);
-
- return 0;
-}
-
-static int sis_drm_alloc(struct drm_device *dev, struct drm_file *file,
- void *data, int pool)
-{
- drm_sis_private_t *dev_priv = dev->dev_private;
- drm_sis_mem_t *mem = data;
- int retval = 0, user_key;
- struct sis_memblock *item;
- struct sis_file_private *file_priv = file->driver_priv;
- unsigned long offset;
-
- mutex_lock(&dev->struct_mutex);
-
- if (0 == ((pool == 0) ? dev_priv->vram_initialized :
- dev_priv->agp_initialized)) {
- DRM_ERROR
- ("Attempt to allocate from uninitialized memory manager.\n");
- mutex_unlock(&dev->struct_mutex);
- return -EINVAL;
- }
-
- item = kzalloc(sizeof(*item), GFP_KERNEL);
- if (!item) {
- retval = -ENOMEM;
- goto fail_alloc;
- }
-
- mem->size = (mem->size + SIS_MM_ALIGN_MASK) >> SIS_MM_ALIGN_SHIFT;
- if (pool == AGP_TYPE) {
- retval = drm_mm_insert_node(&dev_priv->agp_mm,
- &item->mm_node,
- mem->size);
- offset = item->mm_node.start;
- } else {
-#if defined(CONFIG_FB_SIS) || defined(CONFIG_FB_SIS_MODULE)
- item->req.size = mem->size;
- sis_malloc(&item->req);
- if (item->req.size == 0)
- retval = -ENOMEM;
- offset = item->req.offset;
-#else
- retval = drm_mm_insert_node(&dev_priv->vram_mm,
- &item->mm_node,
- mem->size);
- offset = item->mm_node.start;
-#endif
- }
- if (retval)
- goto fail_alloc;
-
- retval = idr_alloc(&dev_priv->object_idr, item, 1, 0, GFP_KERNEL);
- if (retval < 0)
- goto fail_idr;
- user_key = retval;
-
- list_add(&item->owner_list, &file_priv->obj_list);
- mutex_unlock(&dev->struct_mutex);
-
- mem->offset = ((pool == 0) ?
- dev_priv->vram_offset : dev_priv->agp_offset) +
- (offset << SIS_MM_ALIGN_SHIFT);
- mem->free = user_key;
- mem->size = mem->size << SIS_MM_ALIGN_SHIFT;
-
- return 0;
-
-fail_idr:
- drm_mm_remove_node(&item->mm_node);
-fail_alloc:
- kfree(item);
- mutex_unlock(&dev->struct_mutex);
-
- mem->offset = 0;
- mem->size = 0;
- mem->free = 0;
-
- DRM_DEBUG("alloc %d, size = %ld, offset = %ld\n", pool, mem->size,
- mem->offset);
-
- return retval;
-}
-
-static int sis_drm_free(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_sis_private_t *dev_priv = dev->dev_private;
- drm_sis_mem_t *mem = data;
- struct sis_memblock *obj;
-
- mutex_lock(&dev->struct_mutex);
- obj = idr_find(&dev_priv->object_idr, mem->free);
- if (obj == NULL) {
- mutex_unlock(&dev->struct_mutex);
- return -EINVAL;
- }
-
- idr_remove(&dev_priv->object_idr, mem->free);
- list_del(&obj->owner_list);
- if (drm_mm_node_allocated(&obj->mm_node))
- drm_mm_remove_node(&obj->mm_node);
-#if defined(CONFIG_FB_SIS) || defined(CONFIG_FB_SIS_MODULE)
- else
- sis_free(obj->req.offset);
-#endif
- kfree(obj);
- mutex_unlock(&dev->struct_mutex);
- DRM_DEBUG("free = 0x%lx\n", mem->free);
-
- return 0;
-}
-
-static int sis_fb_alloc(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- return sis_drm_alloc(dev, file_priv, data, VIDEO_TYPE);
-}
-
-static int sis_ioctl_agp_init(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- drm_sis_private_t *dev_priv = dev->dev_private;
- drm_sis_agp_t *agp = data;
- dev_priv = dev->dev_private;
-
- mutex_lock(&dev->struct_mutex);
- drm_mm_init(&dev_priv->agp_mm, 0, agp->size >> SIS_MM_ALIGN_SHIFT);
-
- dev_priv->agp_initialized = 1;
- dev_priv->agp_offset = agp->offset;
- mutex_unlock(&dev->struct_mutex);
-
- DRM_DEBUG("offset = %lu, size = %lu\n", agp->offset, agp->size);
- return 0;
-}
-
-static int sis_ioctl_agp_alloc(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
-
- return sis_drm_alloc(dev, file_priv, data, AGP_TYPE);
-}
-
-static drm_local_map_t *sis_reg_init(struct drm_device *dev)
-{
- struct drm_map_list *entry;
- drm_local_map_t *map;
-
- list_for_each_entry(entry, &dev->maplist, head) {
- map = entry->map;
- if (!map)
- continue;
- if (map->type == _DRM_REGISTERS)
- return map;
- }
- return NULL;
-}
-
-int sis_idle(struct drm_device *dev)
-{
- drm_sis_private_t *dev_priv = dev->dev_private;
- uint32_t idle_reg;
- unsigned long end;
- int i;
-
- if (dev_priv->idle_fault)
- return 0;
-
- if (dev_priv->mmio == NULL) {
- dev_priv->mmio = sis_reg_init(dev);
- if (dev_priv->mmio == NULL) {
- DRM_ERROR("Could not find register map.\n");
- return 0;
- }
- }
-
- /*
- * Implement a device switch here if needed
- */
-
- if (dev_priv->chipset != SIS_CHIP_315)
- return 0;
-
- /*
- * Timeout after 3 seconds. We cannot use DRM_WAIT_ON here
- * because its polling frequency is too low.
- */
-
- end = jiffies + (HZ * 3);
-
- for (i = 0; i < 4; ++i) {
- do {
- idle_reg = SIS_READ(0x85cc);
- } while (!time_after_eq(jiffies, end) &&
- ((idle_reg & 0x80000000) != 0x80000000));
- }
-
- if (time_after_eq(jiffies, end)) {
- DRM_ERROR("Graphics engine idle timeout. "
- "Disabling idle check\n");
- dev_priv->idle_fault = 1;
- }
-
- /*
- * The caller never sees an error code. It gets trapped
- * in libdrm.
- */
-
- return 0;
-}
-
-
-void sis_lastclose(struct drm_device *dev)
-{
- drm_sis_private_t *dev_priv = dev->dev_private;
-
- if (!dev_priv)
- return;
-
- mutex_lock(&dev->struct_mutex);
- if (dev_priv->vram_initialized) {
- drm_mm_takedown(&dev_priv->vram_mm);
- dev_priv->vram_initialized = 0;
- }
- if (dev_priv->agp_initialized) {
- drm_mm_takedown(&dev_priv->agp_mm);
- dev_priv->agp_initialized = 0;
- }
- dev_priv->mmio = NULL;
- mutex_unlock(&dev->struct_mutex);
-}
-
-void sis_reclaim_buffers_locked(struct drm_device *dev,
- struct drm_file *file)
-{
- struct sis_file_private *file_priv = file->driver_priv;
- struct sis_memblock *entry, *next;
-
- if (!(dev->master && file->master->lock.hw_lock))
- return;
-
- drm_legacy_idlelock_take(&file->master->lock);
-
- mutex_lock(&dev->struct_mutex);
- if (list_empty(&file_priv->obj_list)) {
- mutex_unlock(&dev->struct_mutex);
- drm_legacy_idlelock_release(&file->master->lock);
-
- return;
- }
-
- sis_idle(dev);
-
-
- list_for_each_entry_safe(entry, next, &file_priv->obj_list,
- owner_list) {
- list_del(&entry->owner_list);
- if (drm_mm_node_allocated(&entry->mm_node))
- drm_mm_remove_node(&entry->mm_node);
-#if defined(CONFIG_FB_SIS) || defined(CONFIG_FB_SIS_MODULE)
- else
- sis_free(entry->req.offset);
-#endif
- kfree(entry);
- }
- mutex_unlock(&dev->struct_mutex);
-
- drm_legacy_idlelock_release(&file->master->lock);
-
- return;
-}
-
-const struct drm_ioctl_desc sis_ioctls[] = {
- DRM_IOCTL_DEF_DRV(SIS_FB_ALLOC, sis_fb_alloc, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(SIS_FB_FREE, sis_drm_free, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(SIS_AGP_INIT, sis_ioctl_agp_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY),
- DRM_IOCTL_DEF_DRV(SIS_AGP_ALLOC, sis_ioctl_agp_alloc, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(SIS_AGP_FREE, sis_drm_free, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(SIS_FB_INIT, sis_fb_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY),
-};
-
-int sis_max_ioctl = ARRAY_SIZE(sis_ioctls);
diff --git a/drivers/gpu/drm/solomon/ssd130x.c b/drivers/gpu/drm/solomon/ssd130x.c
index 91f69e62430b..8cbf5aa66e19 100644
--- a/drivers/gpu/drm/solomon/ssd130x.c
+++ b/drivers/gpu/drm/solomon/ssd130x.c
@@ -81,7 +81,7 @@
#define SSD130X_SET_PRECHARGE_PERIOD2_MASK GENMASK(7, 4)
#define SSD130X_SET_PRECHARGE_PERIOD2_SET(val) FIELD_PREP(SSD130X_SET_PRECHARGE_PERIOD2_MASK, (val))
#define SSD130X_SET_COM_PINS_CONFIG1_MASK GENMASK(4, 4)
-#define SSD130X_SET_COM_PINS_CONFIG1_SET(val) FIELD_PREP(SSD130X_SET_COM_PINS_CONFIG1_MASK, !(val))
+#define SSD130X_SET_COM_PINS_CONFIG1_SET(val) FIELD_PREP(SSD130X_SET_COM_PINS_CONFIG1_MASK, (val))
#define SSD130X_SET_COM_PINS_CONFIG2_MASK GENMASK(5, 5)
#define SSD130X_SET_COM_PINS_CONFIG2_SET(val) FIELD_PREP(SSD130X_SET_COM_PINS_CONFIG2_MASK, (val))
@@ -298,6 +298,7 @@ static void ssd130x_power_off(struct ssd130x_device *ssd130x)
static int ssd130x_init(struct ssd130x_device *ssd130x)
{
u32 precharge, dclk, com_invdir, compins, chargepump, seg_remap;
+ bool scan_mode;
int ret;
/* Set initial contrast */
@@ -360,7 +361,13 @@ static int ssd130x_init(struct ssd130x_device *ssd130x)
/* Set COM pins configuration */
compins = BIT(1);
- compins |= (SSD130X_SET_COM_PINS_CONFIG1_SET(ssd130x->com_seq) |
+ /*
+ * The COM scan mode field values are the inverse of the boolean DT
+ * property "solomon,com-seq". The value 0b means scan from COM0 to
+ * COM[N - 1] while 1b means scan from COM[N - 1] to COM0.
+ */
+ scan_mode = !ssd130x->com_seq;
+ compins |= (SSD130X_SET_COM_PINS_CONFIG1_SET(scan_mode) |
SSD130X_SET_COM_PINS_CONFIG2_SET(ssd130x->com_lrremap));
ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_COM_PINS_CONFIG, compins);
if (ret < 0)
@@ -872,7 +879,7 @@ static int ssd130x_init_modeset(struct ssd130x_device *ssd130x)
drm->mode_config.max_width = max_width;
drm->mode_config.min_height = mode->vdisplay;
drm->mode_config.max_height = max_height;
- drm->mode_config.preferred_depth = 32;
+ drm->mode_config.preferred_depth = 24;
drm->mode_config.funcs = &ssd130x_mode_config_funcs;
/* Primary plane */
@@ -1002,7 +1009,7 @@ struct ssd130x_device *ssd130x_probe(struct device *dev, struct regmap *regmap)
if (ret)
return ERR_PTR(dev_err_probe(dev, ret, "DRM device register failed\n"));
- drm_fbdev_generic_setup(drm, 0);
+ drm_fbdev_generic_setup(drm, 32);
return ssd130x;
}
diff --git a/drivers/gpu/drm/sprd/sprd_dpu.c b/drivers/gpu/drm/sprd/sprd_dpu.c
index 88f4259680f1..b96fc6837b0d 100644
--- a/drivers/gpu/drm/sprd/sprd_dpu.c
+++ b/drivers/gpu/drm/sprd/sprd_dpu.c
@@ -18,7 +18,6 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_blend.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_dma_helper.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_dma_helper.h>
@@ -803,10 +802,8 @@ static int sprd_dpu_context_init(struct sprd_dpu *dpu,
}
ctx->irq = platform_get_irq(pdev, 0);
- if (ctx->irq < 0) {
- dev_err(dev, "failed to get dpu irq\n");
+ if (ctx->irq < 0)
return ctx->irq;
- }
/* disable and clear interrupts before register dpu IRQ. */
writel(0x00, ctx->base + REG_DPU_INT_EN);
diff --git a/drivers/gpu/drm/sprd/sprd_drm.c b/drivers/gpu/drm/sprd/sprd_drm.c
index 9d42f17a5734..be60c0d546a3 100644
--- a/drivers/gpu/drm/sprd/sprd_drm.c
+++ b/drivers/gpu/drm/sprd/sprd_drm.c
@@ -11,7 +11,6 @@
#include <linux/of_platform.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
diff --git a/drivers/gpu/drm/sprd/sprd_dsi.c b/drivers/gpu/drm/sprd/sprd_dsi.c
index 12b67a5d5923..ab0e5cce7adb 100644
--- a/drivers/gpu/drm/sprd/sprd_dsi.c
+++ b/drivers/gpu/drm/sprd/sprd_dsi.c
@@ -13,7 +13,6 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_of.h>
#include <drm/drm_probe_helper.h>
diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c b/drivers/gpu/drm/sun4i/sun4i_tv.c
index c65f0a89b6b0..9625a00a48ba 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tv.c
@@ -141,23 +141,14 @@ struct resync_parameters {
struct tv_mode {
char *name;
+ unsigned int tv_mode;
+
u32 mode;
u32 chroma_freq;
u16 back_porch;
u16 front_porch;
- u16 line_number;
u16 vblank_level;
- u32 hdisplay;
- u16 hfront_porch;
- u16 hsync_len;
- u16 hback_porch;
-
- u32 vdisplay;
- u16 vfront_porch;
- u16 vsync_len;
- u16 vback_porch;
-
bool yc_en;
bool dac3_en;
bool dac_bit25_en;
@@ -213,7 +204,7 @@ static const struct resync_parameters pal_resync_parameters = {
static const struct tv_mode tv_modes[] = {
{
- .name = "NTSC",
+ .tv_mode = DRM_MODE_TV_MODE_NTSC,
.mode = SUN4I_TVE_CFG0_RES_480i,
.chroma_freq = 0x21f07c1f,
.yc_en = true,
@@ -222,17 +213,6 @@ static const struct tv_mode tv_modes[] = {
.back_porch = 118,
.front_porch = 32,
- .line_number = 525,
-
- .hdisplay = 720,
- .hfront_porch = 18,
- .hsync_len = 2,
- .hback_porch = 118,
-
- .vdisplay = 480,
- .vfront_porch = 26,
- .vsync_len = 2,
- .vback_porch = 17,
.vblank_level = 240,
@@ -242,23 +222,12 @@ static const struct tv_mode tv_modes[] = {
.resync_params = &ntsc_resync_parameters,
},
{
- .name = "PAL",
+ .tv_mode = DRM_MODE_TV_MODE_PAL,
.mode = SUN4I_TVE_CFG0_RES_576i,
.chroma_freq = 0x2a098acb,
.back_porch = 138,
.front_porch = 24,
- .line_number = 625,
-
- .hdisplay = 720,
- .hfront_porch = 3,
- .hsync_len = 2,
- .hback_porch = 139,
-
- .vdisplay = 576,
- .vfront_porch = 28,
- .vsync_len = 2,
- .vback_porch = 19,
.vblank_level = 252,
@@ -276,63 +245,21 @@ drm_encoder_to_sun4i_tv(struct drm_encoder *encoder)
encoder);
}
-/*
- * FIXME: If only the drm_display_mode private field was usable, this
- * could go away...
- *
- * So far, it doesn't seem to be preserved when the mode is passed by
- * to mode_set for some reason.
- */
-static const struct tv_mode *sun4i_tv_find_tv_by_mode(const struct drm_display_mode *mode)
+static const struct tv_mode *
+sun4i_tv_find_tv_by_mode(unsigned int mode)
{
int i;
- /* First try to identify the mode by name */
for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
const struct tv_mode *tv_mode = &tv_modes[i];
- DRM_DEBUG_DRIVER("Comparing mode %s vs %s",
- mode->name, tv_mode->name);
-
- if (!strcmp(mode->name, tv_mode->name))
- return tv_mode;
- }
-
- /* Then by number of lines */
- for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
- const struct tv_mode *tv_mode = &tv_modes[i];
-
- DRM_DEBUG_DRIVER("Comparing mode %s vs %s (X: %d vs %d)",
- mode->name, tv_mode->name,
- mode->vdisplay, tv_mode->vdisplay);
-
- if (mode->vdisplay == tv_mode->vdisplay)
+ if (tv_mode->tv_mode == mode)
return tv_mode;
}
return NULL;
}
-static void sun4i_tv_mode_to_drm_mode(const struct tv_mode *tv_mode,
- struct drm_display_mode *mode)
-{
- DRM_DEBUG_DRIVER("Creating mode %s\n", mode->name);
-
- mode->type = DRM_MODE_TYPE_DRIVER;
- mode->clock = 13500;
- mode->flags = DRM_MODE_FLAG_INTERLACE;
-
- mode->hdisplay = tv_mode->hdisplay;
- mode->hsync_start = mode->hdisplay + tv_mode->hfront_porch;
- mode->hsync_end = mode->hsync_start + tv_mode->hsync_len;
- mode->htotal = mode->hsync_end + tv_mode->hback_porch;
-
- mode->vdisplay = tv_mode->vdisplay;
- mode->vsync_start = mode->vdisplay + tv_mode->vfront_porch;
- mode->vsync_end = mode->vsync_start + tv_mode->vsync_len;
- mode->vtotal = mode->vsync_end + tv_mode->vback_porch;
-}
-
static void sun4i_tv_disable(struct drm_encoder *encoder,
struct drm_atomic_state *state)
{
@@ -356,7 +283,11 @@ static void sun4i_tv_enable(struct drm_encoder *encoder,
struct drm_crtc_state *crtc_state =
drm_atomic_get_new_crtc_state(state, encoder->crtc);
struct drm_display_mode *mode = &crtc_state->mode;
- const struct tv_mode *tv_mode = sun4i_tv_find_tv_by_mode(mode);
+ struct drm_connector *connector = &tv->connector;
+ struct drm_connector_state *conn_state =
+ drm_atomic_get_new_connector_state(state, connector);
+ const struct tv_mode *tv_mode =
+ sun4i_tv_find_tv_by_mode(conn_state->tv.mode);
DRM_DEBUG_DRIVER("Enabling the TV Output\n");
@@ -404,7 +335,7 @@ static void sun4i_tv_enable(struct drm_encoder *encoder,
/* Set the lines setup */
regmap_write(tv->regs, SUN4I_TVE_LINE_REG,
SUN4I_TVE_LINE_FIRST(22) |
- SUN4I_TVE_LINE_NUMBER(tv_mode->line_number));
+ SUN4I_TVE_LINE_NUMBER(mode->vtotal));
regmap_write(tv->regs, SUN4I_TVE_LEVEL_REG,
SUN4I_TVE_LEVEL_BLANK(tv_mode->video_levels->blank) |
@@ -465,37 +396,21 @@ static const struct drm_encoder_helper_funcs sun4i_tv_helper_funcs = {
.atomic_enable = sun4i_tv_enable,
};
-static int sun4i_tv_comp_get_modes(struct drm_connector *connector)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
- struct drm_display_mode *mode;
- const struct tv_mode *tv_mode = &tv_modes[i];
-
- mode = drm_mode_create(connector->dev);
- if (!mode) {
- DRM_ERROR("Failed to create a new display mode\n");
- return 0;
- }
-
- strcpy(mode->name, tv_mode->name);
-
- sun4i_tv_mode_to_drm_mode(tv_mode, mode);
- drm_mode_probed_add(connector, mode);
- }
-
- return i;
-}
-
static const struct drm_connector_helper_funcs sun4i_tv_comp_connector_helper_funcs = {
- .get_modes = sun4i_tv_comp_get_modes,
+ .atomic_check = drm_atomic_helper_connector_tv_check,
+ .get_modes = drm_connector_helper_tv_get_modes,
};
+static void sun4i_tv_connector_reset(struct drm_connector *connector)
+{
+ drm_atomic_helper_connector_reset(connector);
+ drm_atomic_helper_connector_tv_reset(connector);
+}
+
static const struct drm_connector_funcs sun4i_tv_comp_connector_funcs = {
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = drm_connector_cleanup,
- .reset = drm_atomic_helper_connector_reset,
+ .reset = sun4i_tv_connector_reset,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
@@ -587,8 +502,20 @@ static int sun4i_tv_bind(struct device *dev, struct device *master,
drm_connector_attach_encoder(&tv->connector, &tv->encoder);
+ ret = drm_mode_create_tv_properties(drm,
+ BIT(DRM_MODE_TV_MODE_NTSC) |
+ BIT(DRM_MODE_TV_MODE_PAL));
+ if (ret)
+ goto err_cleanup_connector;
+
+ drm_object_attach_property(&tv->connector.base,
+ drm->mode_config.tv_mode_property,
+ DRM_MODE_TV_MODE_NTSC);
+
return 0;
+err_cleanup_connector:
+ drm_connector_cleanup(&tv->connector);
err_cleanup_encoder:
drm_encoder_cleanup(&tv->encoder);
err_disable_clk:
diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
index 477cb6985b4d..7cab4213a680 100644
--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
+++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
@@ -8,7 +8,7 @@
#include <linux/of_device.h>
#include <linux/platform_device.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_of.h>
#include <drm/drm_simple_kms_helper.h>
diff --git a/drivers/gpu/drm/tdfx/Makefile b/drivers/gpu/drm/tdfx/Makefile
deleted file mode 100644
index 03b7d0f087b0..000000000000
--- a/drivers/gpu/drm/tdfx/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Makefile for the drm device driver. This driver provides support for the
-# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
-
-tdfx-y := tdfx_drv.o
-
-obj-$(CONFIG_DRM_TDFX) += tdfx.o
diff --git a/drivers/gpu/drm/tdfx/tdfx_drv.c b/drivers/gpu/drm/tdfx/tdfx_drv.c
deleted file mode 100644
index 58c185c299f4..000000000000
--- a/drivers/gpu/drm/tdfx/tdfx_drv.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/* tdfx_drv.c -- tdfx driver -*- linux-c -*-
- * Created: Thu Oct 7 10:38:32 1999 by faith@precisioninsight.com
- *
- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software 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 (including the next
- * paragraph) 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
- * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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.
- *
- * Authors:
- * Rickard E. (Rik) Faith <faith@valinux.com>
- * Daryll Strauss <daryll@valinux.com>
- * Gareth Hughes <gareth@valinux.com>
- */
-
-#include <linux/module.h>
-#include <linux/pci.h>
-
-#include <drm/drm_drv.h>
-#include <drm/drm_file.h>
-#include <drm/drm_ioctl.h>
-#include <drm/drm_legacy.h>
-#include <drm/drm_pciids.h>
-
-#include "tdfx_drv.h"
-
-static struct pci_device_id pciidlist[] = {
- tdfx_PCI_IDS
-};
-
-static const struct file_operations tdfx_driver_fops = {
- .owner = THIS_MODULE,
- .open = drm_open,
- .release = drm_release,
- .unlocked_ioctl = drm_ioctl,
- .mmap = drm_legacy_mmap,
- .poll = drm_poll,
- .compat_ioctl = drm_compat_ioctl,
- .llseek = noop_llseek,
-};
-
-static const struct drm_driver driver = {
- .driver_features = DRIVER_LEGACY,
- .fops = &tdfx_driver_fops,
- .name = DRIVER_NAME,
- .desc = DRIVER_DESC,
- .date = DRIVER_DATE,
- .major = DRIVER_MAJOR,
- .minor = DRIVER_MINOR,
- .patchlevel = DRIVER_PATCHLEVEL,
-};
-
-static struct pci_driver tdfx_pci_driver = {
- .name = DRIVER_NAME,
- .id_table = pciidlist,
-};
-
-static int __init tdfx_init(void)
-{
- return drm_legacy_pci_init(&driver, &tdfx_pci_driver);
-}
-
-static void __exit tdfx_exit(void)
-{
- drm_legacy_pci_exit(&driver, &tdfx_pci_driver);
-}
-
-module_init(tdfx_init);
-module_exit(tdfx_exit);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c
index 7dc681e2ee90..3c84e73d5051 100644
--- a/drivers/gpu/drm/tegra/dpaux.c
+++ b/drivers/gpu/drm/tegra/dpaux.c
@@ -598,7 +598,6 @@ static int tegra_dpaux_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
static int tegra_dpaux_suspend(struct device *dev)
{
struct tegra_dpaux *dpaux = dev_get_drvdata(dev);
@@ -657,10 +656,9 @@ disable_clk:
clk_disable_unprepare(dpaux->clk);
return err;
}
-#endif
static const struct dev_pm_ops tegra_dpaux_pm_ops = {
- SET_RUNTIME_PM_OPS(tegra_dpaux_suspend, tegra_dpaux_resume, NULL)
+ RUNTIME_PM_OPS(tegra_dpaux_suspend, tegra_dpaux_resume, NULL)
};
static const struct tegra_dpaux_soc tegra124_dpaux_soc = {
@@ -694,7 +692,7 @@ struct platform_driver tegra_dpaux_driver = {
.driver = {
.name = "tegra-dpaux",
.of_match_table = tegra_dpaux_of_match,
- .pm = &tegra_dpaux_pm_ops,
+ .pm = pm_ptr(&tegra_dpaux_pm_ops),
},
.probe = tegra_dpaux_probe,
.remove = tegra_dpaux_remove,
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
index 7bd2e65c2a16..6ca9f396e55b 100644
--- a/drivers/gpu/drm/tegra/drm.c
+++ b/drivers/gpu/drm/tegra/drm.c
@@ -1057,7 +1057,7 @@ void *tegra_drm_alloc(struct tegra_drm *tegra, size_t size, dma_addr_t *dma)
*dma = iova_dma_addr(&tegra->carveout.domain, alloc);
err = iommu_map(tegra->domain, *dma, virt_to_phys(virt),
- size, IOMMU_READ | IOMMU_WRITE);
+ size, IOMMU_READ | IOMMU_WRITE, GFP_KERNEL);
if (err < 0)
goto free_iova;
diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c
index a900300ae5bd..bfebe2786d61 100644
--- a/drivers/gpu/drm/tegra/fb.c
+++ b/drivers/gpu/drm/tegra/fb.c
@@ -308,18 +308,18 @@ static struct tegra_fbdev *tegra_fbdev_create(struct drm_device *drm)
return ERR_PTR(-ENOMEM);
}
- drm_fb_helper_prepare(drm, &fbdev->base, &tegra_fb_helper_funcs);
+ drm_fb_helper_prepare(drm, &fbdev->base, 32, &tegra_fb_helper_funcs);
return fbdev;
}
static void tegra_fbdev_free(struct tegra_fbdev *fbdev)
{
+ drm_fb_helper_unprepare(&fbdev->base);
kfree(fbdev);
}
static int tegra_fbdev_init(struct tegra_fbdev *fbdev,
- unsigned int preferred_bpp,
unsigned int num_crtc,
unsigned int max_connectors)
{
@@ -333,7 +333,7 @@ static int tegra_fbdev_init(struct tegra_fbdev *fbdev,
return err;
}
- err = drm_fb_helper_initial_config(&fbdev->base, preferred_bpp);
+ err = drm_fb_helper_initial_config(&fbdev->base);
if (err < 0) {
dev_err(drm->dev, "failed to set initial configuration: %d\n",
err);
@@ -396,7 +396,7 @@ int tegra_drm_fb_init(struct drm_device *drm)
struct tegra_drm *tegra = drm->dev_private;
int err;
- err = tegra_fbdev_init(tegra->fbdev, 32, drm->mode_config.num_crtc,
+ err = tegra_fbdev_init(tegra->fbdev, drm->mode_config.num_crtc,
drm->mode_config.num_connector);
if (err < 0)
return err;
diff --git a/drivers/gpu/drm/tegra/firewall.c b/drivers/gpu/drm/tegra/firewall.c
index 1824d2db0e2c..d53f890fa689 100644
--- a/drivers/gpu/drm/tegra/firewall.c
+++ b/drivers/gpu/drm/tegra/firewall.c
@@ -97,6 +97,9 @@ static int fw_check_regs_imm(struct tegra_drm_firewall *fw, u32 offset)
{
bool is_addr;
+ if (!fw->client->ops->is_addr_reg)
+ return 0;
+
is_addr = fw->client->ops->is_addr_reg(fw->client->base.dev, fw->class,
offset);
if (is_addr)
diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c
index 979e7bc902f6..bce991a2ccc0 100644
--- a/drivers/gpu/drm/tegra/gem.c
+++ b/drivers/gpu/drm/tegra/gem.c
@@ -574,7 +574,7 @@ int __tegra_gem_mmap(struct drm_gem_object *gem, struct vm_area_struct *vma)
* and set the vm_pgoff (used as a fake buffer offset by DRM)
* to 0 as we want to map the whole buffer.
*/
- vma->vm_flags &= ~VM_PFNMAP;
+ vm_flags_clear(vma, VM_PFNMAP);
vma->vm_pgoff = 0;
err = dma_mmap_wc(gem->dev->dev, vma, bo->vaddr, bo->iova,
@@ -588,8 +588,7 @@ int __tegra_gem_mmap(struct drm_gem_object *gem, struct vm_area_struct *vma)
} else {
pgprot_t prot = vm_get_page_prot(vma->vm_flags);
- vma->vm_flags |= VM_MIXEDMAP;
- vma->vm_flags &= ~VM_PFNMAP;
+ vm_flags_mod(vma, VM_MIXEDMAP, VM_PFNMAP);
vma->vm_page_prot = pgprot_writecombine(prot);
}
diff --git a/drivers/gpu/drm/tegra/nvdec.c b/drivers/gpu/drm/tegra/nvdec.c
index 10fd21517281..86c5818ac27b 100644
--- a/drivers/gpu/drm/tegra/nvdec.c
+++ b/drivers/gpu/drm/tegra/nvdec.c
@@ -67,26 +67,18 @@ static inline void nvdec_writel(struct nvdec *nvdec, u32 value,
static int nvdec_boot_falcon(struct nvdec *nvdec)
{
-#ifdef CONFIG_IOMMU_API
- struct iommu_fwspec *spec = dev_iommu_fwspec_get(nvdec->dev);
-#endif
+ u32 stream_id;
int err;
-#ifdef CONFIG_IOMMU_API
- if (nvdec->config->supports_sid && spec) {
+ if (nvdec->config->supports_sid && tegra_dev_iommu_get_stream_id(nvdec->dev, &stream_id)) {
u32 value;
value = TRANSCFG_ATT(1, TRANSCFG_SID_FALCON) | TRANSCFG_ATT(0, TRANSCFG_SID_HW);
nvdec_writel(nvdec, value, NVDEC_TFBIF_TRANSCFG);
- if (spec->num_ids > 0) {
- value = spec->ids[0] & 0xffff;
-
- nvdec_writel(nvdec, value, VIC_THI_STREAMID0);
- nvdec_writel(nvdec, value, VIC_THI_STREAMID1);
- }
+ nvdec_writel(nvdec, stream_id, VIC_THI_STREAMID0);
+ nvdec_writel(nvdec, stream_id, VIC_THI_STREAMID1);
}
-#endif
err = falcon_boot(&nvdec->falcon);
if (err < 0)
diff --git a/drivers/gpu/drm/tegra/submit.c b/drivers/gpu/drm/tegra/submit.c
index 066f88564169..2430fcc97448 100644
--- a/drivers/gpu/drm/tegra/submit.c
+++ b/drivers/gpu/drm/tegra/submit.c
@@ -609,21 +609,13 @@ int tegra_drm_ioctl_channel_submit(struct drm_device *drm, void *data,
host1x_memory_context_get(job->memory_context);
}
} else if (context->client->ops->get_streamid_offset) {
-#ifdef CONFIG_IOMMU_API
- struct iommu_fwspec *spec;
-
/*
* Job submission will need to temporarily change stream ID,
* so need to tell it what to change it back to.
*/
- spec = dev_iommu_fwspec_get(context->client->base.dev);
- if (spec && spec->num_ids > 0)
- job->engine_fallback_streamid = spec->ids[0] & 0xffff;
- else
- job->engine_fallback_streamid = 0x7f;
-#else
- job->engine_fallback_streamid = 0x7f;
-#endif
+ if (!tegra_dev_iommu_get_stream_id(context->client->base.dev,
+ &job->engine_fallback_streamid))
+ job->engine_fallback_streamid = TEGRA_STREAM_ID_BYPASS;
}
/* Boot engine. */
@@ -654,7 +646,7 @@ int tegra_drm_ioctl_channel_submit(struct drm_device *drm, void *data,
args->syncpt.value = job->syncpt_end;
if (syncobj) {
- struct dma_fence *fence = host1x_fence_create(job->syncpt, job->syncpt_end);
+ struct dma_fence *fence = host1x_fence_create(job->syncpt, job->syncpt_end, true);
if (IS_ERR(fence)) {
err = PTR_ERR(fence);
SUBMIT_ERR(context, "failed to create postfence: %d", err);
@@ -680,8 +672,7 @@ free_job_data:
kfree(job_data->used_mappings);
}
- if (job_data)
- kfree(job_data);
+ kfree(job_data);
put_bo:
gather_bo_put(&bo->base);
unlock:
diff --git a/drivers/gpu/drm/tegra/vic.c b/drivers/gpu/drm/tegra/vic.c
index 7382ee132eb7..531a71c72061 100644
--- a/drivers/gpu/drm/tegra/vic.c
+++ b/drivers/gpu/drm/tegra/vic.c
@@ -56,41 +56,30 @@ static void vic_writel(struct vic *vic, u32 value, unsigned int offset)
static int vic_boot(struct vic *vic)
{
-#ifdef CONFIG_IOMMU_API
- struct iommu_fwspec *spec = dev_iommu_fwspec_get(vic->dev);
-#endif
- u32 fce_ucode_size, fce_bin_data_offset;
+ u32 fce_ucode_size, fce_bin_data_offset, stream_id;
void *hdr;
int err = 0;
-#ifdef CONFIG_IOMMU_API
- if (vic->config->supports_sid && spec) {
+ if (vic->config->supports_sid && tegra_dev_iommu_get_stream_id(vic->dev, &stream_id)) {
u32 value;
value = TRANSCFG_ATT(1, TRANSCFG_SID_FALCON) |
TRANSCFG_ATT(0, TRANSCFG_SID_HW);
vic_writel(vic, value, VIC_TFBIF_TRANSCFG);
- if (spec->num_ids > 0) {
- value = spec->ids[0] & 0xffff;
-
- /*
- * STREAMID0 is used for input/output buffers.
- * Initialize it to SID_VIC in case context isolation
- * is not enabled, and SID_VIC is used for both firmware
- * and data buffers.
- *
- * If context isolation is enabled, it will be
- * overridden by the SETSTREAMID opcode as part of
- * each job.
- */
- vic_writel(vic, value, VIC_THI_STREAMID0);
-
- /* STREAMID1 is used for firmware loading. */
- vic_writel(vic, value, VIC_THI_STREAMID1);
- }
+ /*
+ * STREAMID0 is used for input/output buffers. Initialize it to SID_VIC in case
+ * context isolation is not enabled, and SID_VIC is used for both firmware and
+ * data buffers.
+ *
+ * If context isolation is enabled, it will be overridden by the SETSTREAMID
+ * opcode as part of each job.
+ */
+ vic_writel(vic, stream_id, VIC_THI_STREAMID0);
+
+ /* STREAMID1 is used for firmware loading. */
+ vic_writel(vic, stream_id, VIC_THI_STREAMID1);
}
-#endif
/* setup clockgating registers */
vic_writel(vic, CG_IDLE_CG_DLY_CNT(4) |
diff --git a/drivers/gpu/drm/tests/Makefile b/drivers/gpu/drm/tests/Makefile
index f896ef85c2f2..bca726a8f483 100644
--- a/drivers/gpu/drm/tests/Makefile
+++ b/drivers/gpu/drm/tests/Makefile
@@ -1,16 +1,22 @@
# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_DRM_KUNIT_TEST_HELPERS) += \
+ drm_kunit_helpers.o
+
obj-$(CONFIG_DRM_KUNIT_TEST) += \
drm_buddy_test.o \
drm_cmdline_parser_test.o \
+ drm_connector_test.o \
drm_damage_helper_test.o \
drm_dp_mst_helper_test.o \
drm_format_helper_test.o \
drm_format_test.o \
drm_framebuffer_test.o \
- drm_kunit_helpers.o \
+ drm_managed_test.o \
drm_mm_test.o \
+ drm_modes_test.o \
drm_plane_helper_test.o \
+ drm_probe_helper_test.o \
drm_rect_test.o
CFLAGS_drm_mm_test.o := $(DISABLE_STRUCTLEAK_PLUGIN)
diff --git a/drivers/gpu/drm/tests/drm_client_modeset_test.c b/drivers/gpu/drm/tests/drm_client_modeset_test.c
index 362a5fbd82f5..416a279b6dae 100644
--- a/drivers/gpu/drm/tests/drm_client_modeset_test.c
+++ b/drivers/gpu/drm/tests/drm_client_modeset_test.c
@@ -8,20 +8,39 @@
#include <drm/drm_connector.h>
#include <drm/drm_edid.h>
#include <drm/drm_drv.h>
+#include <drm/drm_kunit_helpers.h>
#include <drm/drm_modes.h>
#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_probe_helper.h>
-#include "drm_kunit_helpers.h"
-
struct drm_client_modeset_test_priv {
struct drm_device *drm;
+ struct device *dev;
struct drm_connector connector;
};
static int drm_client_modeset_connector_get_modes(struct drm_connector *connector)
{
- return drm_add_modes_noedid(connector, 1920, 1200);
+ struct drm_display_mode *mode;
+ int count;
+
+ count = drm_add_modes_noedid(connector, 1920, 1200);
+
+ mode = drm_mode_analog_ntsc_480i(connector->dev);
+ if (!mode)
+ return count;
+
+ drm_mode_probed_add(connector, mode);
+ count += 1;
+
+ mode = drm_mode_analog_pal_576i(connector->dev);
+ if (!mode)
+ return count;
+
+ drm_mode_probed_add(connector, mode);
+ count += 1;
+
+ return count;
}
static const struct drm_connector_helper_funcs drm_client_modeset_connector_helper_funcs = {
@@ -41,7 +60,12 @@ static int drm_client_modeset_test_init(struct kunit *test)
test->priv = priv;
- priv->drm = drm_kunit_device_init(test, DRIVER_MODESET, "drm-client-modeset-test");
+ priv->dev = drm_kunit_helper_alloc_device(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->dev);
+
+ priv->drm = __drm_kunit_helper_alloc_drm_device(test, priv->dev,
+ sizeof(*priv->drm), 0,
+ DRIVER_MODESET);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->drm);
ret = drmm_connector_init(priv->drm, &priv->connector,
@@ -52,9 +76,19 @@ static int drm_client_modeset_test_init(struct kunit *test)
drm_connector_helper_add(&priv->connector, &drm_client_modeset_connector_helper_funcs);
+ priv->connector.interlace_allowed = true;
+ priv->connector.doublescan_allowed = true;
+
return 0;
}
+static void drm_client_modeset_test_exit(struct kunit *test)
+{
+ struct drm_client_modeset_test_priv *priv = test->priv;
+
+ drm_kunit_helper_free_device(test, priv->dev);
+}
+
static void drm_test_pick_cmdline_res_1920_1080_60(struct kunit *test)
{
struct drm_client_modeset_test_priv *priv = test->priv;
@@ -84,15 +118,83 @@ static void drm_test_pick_cmdline_res_1920_1080_60(struct kunit *test)
KUNIT_EXPECT_TRUE(test, drm_mode_equal(expected_mode, mode));
}
+struct drm_connector_pick_cmdline_mode_test {
+ const char *cmdline;
+ struct drm_display_mode *(*func)(struct drm_device *drm);
+};
+
+#define TEST_CMDLINE(_cmdline, _fn) \
+ { \
+ .cmdline = _cmdline, \
+ .func = _fn, \
+ }
+
+static void drm_test_pick_cmdline_named(struct kunit *test)
+{
+ const struct drm_connector_pick_cmdline_mode_test *params = test->param_value;
+ struct drm_client_modeset_test_priv *priv = test->priv;
+ struct drm_device *drm = priv->drm;
+ struct drm_connector *connector = &priv->connector;
+ struct drm_cmdline_mode *cmdline_mode = &connector->cmdline_mode;
+ const struct drm_display_mode *expected_mode, *mode;
+ const char *cmdline = params->cmdline;
+ int ret;
+
+ KUNIT_ASSERT_TRUE(test,
+ drm_mode_parse_command_line_for_connector(cmdline,
+ connector,
+ cmdline_mode));
+
+ mutex_lock(&drm->mode_config.mutex);
+ ret = drm_helper_probe_single_connector_modes(connector, 1920, 1080);
+ mutex_unlock(&drm->mode_config.mutex);
+ KUNIT_ASSERT_GT(test, ret, 0);
+
+ mode = drm_connector_pick_cmdline_mode(connector);
+ KUNIT_ASSERT_NOT_NULL(test, mode);
+
+ expected_mode = params->func(drm);
+ KUNIT_ASSERT_NOT_NULL(test, expected_mode);
+
+ KUNIT_EXPECT_TRUE(test, drm_mode_equal(expected_mode, mode));
+}
+
+static const
+struct drm_connector_pick_cmdline_mode_test drm_connector_pick_cmdline_mode_tests[] = {
+ TEST_CMDLINE("NTSC", drm_mode_analog_ntsc_480i),
+ TEST_CMDLINE("NTSC-J", drm_mode_analog_ntsc_480i),
+ TEST_CMDLINE("PAL", drm_mode_analog_pal_576i),
+ TEST_CMDLINE("PAL-M", drm_mode_analog_ntsc_480i),
+};
+
+static void
+drm_connector_pick_cmdline_mode_desc(const struct drm_connector_pick_cmdline_mode_test *t,
+ char *desc)
+{
+ sprintf(desc, "%s", t->cmdline);
+}
+
+KUNIT_ARRAY_PARAM(drm_connector_pick_cmdline_mode,
+ drm_connector_pick_cmdline_mode_tests,
+ drm_connector_pick_cmdline_mode_desc);
+
static struct kunit_case drm_test_pick_cmdline_tests[] = {
KUNIT_CASE(drm_test_pick_cmdline_res_1920_1080_60),
+ KUNIT_CASE_PARAM(drm_test_pick_cmdline_named,
+ drm_connector_pick_cmdline_mode_gen_params),
{}
};
static struct kunit_suite drm_test_pick_cmdline_test_suite = {
.name = "drm_test_pick_cmdline",
.init = drm_client_modeset_test_init,
+ .exit = drm_client_modeset_test_exit,
.test_cases = drm_test_pick_cmdline_tests
};
kunit_test_suite(drm_test_pick_cmdline_test_suite);
+
+/*
+ * This file is included directly by drm_client_modeset.c so we can't
+ * use any MODULE_* macro here.
+ */
diff --git a/drivers/gpu/drm/tests/drm_cmdline_parser_test.c b/drivers/gpu/drm/tests/drm_cmdline_parser_test.c
index 34790e7a3760..88f7f518ffb3 100644
--- a/drivers/gpu/drm/tests/drm_cmdline_parser_test.c
+++ b/drivers/gpu/drm/tests/drm_cmdline_parser_test.c
@@ -927,6 +927,14 @@ static const struct drm_cmdline_invalid_test drm_cmdline_invalid_tests[] = {
.name = "invalid_option",
.cmdline = "720x480,test=42",
},
+ {
+ .name = "invalid_tv_option",
+ .cmdline = "720x480i,tv_mode=invalid",
+ },
+ {
+ .name = "truncated_tv_option",
+ .cmdline = "720x480i,tv_mode=NTS",
+ },
};
static void drm_cmdline_invalid_desc(const struct drm_cmdline_invalid_test *t,
@@ -937,6 +945,65 @@ static void drm_cmdline_invalid_desc(const struct drm_cmdline_invalid_test *t,
KUNIT_ARRAY_PARAM(drm_cmdline_invalid, drm_cmdline_invalid_tests, drm_cmdline_invalid_desc);
+struct drm_cmdline_tv_option_test {
+ const char *name;
+ const char *cmdline;
+ struct drm_display_mode *(*mode_fn)(struct drm_device *dev);
+ enum drm_connector_tv_mode tv_mode;
+};
+
+static void drm_test_cmdline_tv_options(struct kunit *test)
+{
+ const struct drm_cmdline_tv_option_test *params = test->param_value;
+ const struct drm_display_mode *expected_mode = params->mode_fn(NULL);
+ struct drm_cmdline_mode mode = { };
+
+ KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(params->cmdline,
+ &no_connector, &mode));
+ KUNIT_EXPECT_TRUE(test, mode.specified);
+ KUNIT_EXPECT_EQ(test, mode.xres, expected_mode->hdisplay);
+ KUNIT_EXPECT_EQ(test, mode.yres, expected_mode->vdisplay);
+ KUNIT_EXPECT_EQ(test, mode.tv_mode, params->tv_mode);
+
+ KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
+
+ KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
+
+ KUNIT_EXPECT_FALSE(test, mode.rb);
+ KUNIT_EXPECT_FALSE(test, mode.cvt);
+ KUNIT_EXPECT_EQ(test, mode.interlace, !!(expected_mode->flags & DRM_MODE_FLAG_INTERLACE));
+ KUNIT_EXPECT_FALSE(test, mode.margins);
+ KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
+}
+
+#define TV_OPT_TEST(_opt, _cmdline, _mode_fn) \
+ { \
+ .name = #_opt, \
+ .cmdline = _cmdline, \
+ .mode_fn = _mode_fn, \
+ .tv_mode = DRM_MODE_TV_MODE_ ## _opt, \
+ }
+
+static const struct drm_cmdline_tv_option_test drm_cmdline_tv_option_tests[] = {
+ TV_OPT_TEST(NTSC, "720x480i,tv_mode=NTSC", drm_mode_analog_ntsc_480i),
+ TV_OPT_TEST(NTSC_443, "720x480i,tv_mode=NTSC-443", drm_mode_analog_ntsc_480i),
+ TV_OPT_TEST(NTSC_J, "720x480i,tv_mode=NTSC-J", drm_mode_analog_ntsc_480i),
+ TV_OPT_TEST(PAL, "720x576i,tv_mode=PAL", drm_mode_analog_pal_576i),
+ TV_OPT_TEST(PAL_M, "720x480i,tv_mode=PAL-M", drm_mode_analog_ntsc_480i),
+ TV_OPT_TEST(PAL_N, "720x576i,tv_mode=PAL-N", drm_mode_analog_pal_576i),
+ TV_OPT_TEST(SECAM, "720x576i,tv_mode=SECAM", drm_mode_analog_pal_576i),
+};
+
+static void drm_cmdline_tv_option_desc(const struct drm_cmdline_tv_option_test *t,
+ char *desc)
+{
+ sprintf(desc, "%s", t->name);
+}
+
+KUNIT_ARRAY_PARAM(drm_cmdline_tv_option,
+ drm_cmdline_tv_option_tests,
+ drm_cmdline_tv_option_desc);
+
static struct kunit_case drm_cmdline_parser_tests[] = {
KUNIT_CASE(drm_test_cmdline_force_d_only),
KUNIT_CASE(drm_test_cmdline_force_D_only_dvi),
@@ -977,6 +1044,7 @@ static struct kunit_case drm_cmdline_parser_tests[] = {
KUNIT_CASE(drm_test_cmdline_freestanding_force_e_and_options),
KUNIT_CASE(drm_test_cmdline_panel_orientation),
KUNIT_CASE_PARAM(drm_test_cmdline_invalid, drm_cmdline_invalid_gen_params),
+ KUNIT_CASE_PARAM(drm_test_cmdline_tv_options, drm_cmdline_tv_option_gen_params),
{}
};
diff --git a/drivers/gpu/drm/tests/drm_connector_test.c b/drivers/gpu/drm/tests/drm_connector_test.c
new file mode 100644
index 000000000000..c66aa2dc8d9d
--- /dev/null
+++ b/drivers/gpu/drm/tests/drm_connector_test.c
@@ -0,0 +1,76 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Kunit test for drm_modes functions
+ */
+
+#include <drm/drm_connector.h>
+
+#include <kunit/test.h>
+
+struct drm_get_tv_mode_from_name_test {
+ const char *name;
+ enum drm_connector_tv_mode expected_mode;
+};
+
+#define TV_MODE_NAME(_name, _mode) \
+ { \
+ .name = _name, \
+ .expected_mode = _mode, \
+ }
+
+static void drm_test_get_tv_mode_from_name_valid(struct kunit *test)
+{
+ const struct drm_get_tv_mode_from_name_test *params = test->param_value;
+
+ KUNIT_EXPECT_EQ(test,
+ drm_get_tv_mode_from_name(params->name, strlen(params->name)),
+ params->expected_mode);
+}
+
+static const
+struct drm_get_tv_mode_from_name_test drm_get_tv_mode_from_name_valid_tests[] = {
+ TV_MODE_NAME("NTSC", DRM_MODE_TV_MODE_NTSC),
+ TV_MODE_NAME("NTSC-443", DRM_MODE_TV_MODE_NTSC_443),
+ TV_MODE_NAME("NTSC-J", DRM_MODE_TV_MODE_NTSC_J),
+ TV_MODE_NAME("PAL", DRM_MODE_TV_MODE_PAL),
+ TV_MODE_NAME("PAL-M", DRM_MODE_TV_MODE_PAL_M),
+ TV_MODE_NAME("PAL-N", DRM_MODE_TV_MODE_PAL_N),
+ TV_MODE_NAME("SECAM", DRM_MODE_TV_MODE_SECAM),
+};
+
+static void
+drm_get_tv_mode_from_name_valid_desc(const struct drm_get_tv_mode_from_name_test *t,
+ char *desc)
+{
+ sprintf(desc, "%s", t->name);
+}
+
+KUNIT_ARRAY_PARAM(drm_get_tv_mode_from_name_valid,
+ drm_get_tv_mode_from_name_valid_tests,
+ drm_get_tv_mode_from_name_valid_desc);
+
+static void drm_test_get_tv_mode_from_name_truncated(struct kunit *test)
+{
+ const char *name = "NTS";
+ int ret;
+
+ ret = drm_get_tv_mode_from_name(name, strlen(name));
+ KUNIT_EXPECT_LT(test, ret, 0);
+};
+
+static struct kunit_case drm_get_tv_mode_from_name_tests[] = {
+ KUNIT_CASE_PARAM(drm_test_get_tv_mode_from_name_valid,
+ drm_get_tv_mode_from_name_valid_gen_params),
+ KUNIT_CASE(drm_test_get_tv_mode_from_name_truncated),
+ { }
+};
+
+static struct kunit_suite drm_get_tv_mode_from_name_test_suite = {
+ .name = "drm_get_tv_mode_from_name",
+ .test_cases = drm_get_tv_mode_from_name_tests,
+};
+
+kunit_test_suite(drm_get_tv_mode_from_name_test_suite);
+
+MODULE_AUTHOR("Maxime Ripard <maxime@cerno.tech>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/tests/drm_format_helper_test.c b/drivers/gpu/drm/tests/drm_format_helper_test.c
index 567c71f95edc..34e80eb6d96e 100644
--- a/drivers/gpu/drm/tests/drm_format_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_format_helper_test.c
@@ -32,16 +32,41 @@ struct convert_to_rgb565_result {
const u16 expected_swab[TEST_BUF_SIZE];
};
+struct convert_to_xrgb1555_result {
+ unsigned int dst_pitch;
+ const u16 expected[TEST_BUF_SIZE];
+};
+
+struct convert_to_argb1555_result {
+ unsigned int dst_pitch;
+ const u16 expected[TEST_BUF_SIZE];
+};
+
+struct convert_to_rgba5551_result {
+ unsigned int dst_pitch;
+ const u16 expected[TEST_BUF_SIZE];
+};
+
struct convert_to_rgb888_result {
unsigned int dst_pitch;
const u8 expected[TEST_BUF_SIZE];
};
+struct convert_to_argb8888_result {
+ unsigned int dst_pitch;
+ const u32 expected[TEST_BUF_SIZE];
+};
+
struct convert_to_xrgb2101010_result {
unsigned int dst_pitch;
const u32 expected[TEST_BUF_SIZE];
};
+struct convert_to_argb2101010_result {
+ unsigned int dst_pitch;
+ const u32 expected[TEST_BUF_SIZE];
+};
+
struct convert_xrgb8888_case {
const char *name;
unsigned int pitch;
@@ -50,8 +75,13 @@ struct convert_xrgb8888_case {
struct convert_to_gray8_result gray8_result;
struct convert_to_rgb332_result rgb332_result;
struct convert_to_rgb565_result rgb565_result;
+ struct convert_to_xrgb1555_result xrgb1555_result;
+ struct convert_to_argb1555_result argb1555_result;
+ struct convert_to_rgba5551_result rgba5551_result;
struct convert_to_rgb888_result rgb888_result;
+ struct convert_to_argb8888_result argb8888_result;
struct convert_to_xrgb2101010_result xrgb2101010_result;
+ struct convert_to_argb2101010_result argb2101010_result;
};
static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
@@ -73,14 +103,34 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
.expected = { 0xF800 },
.expected_swab = { 0x00F8 },
},
+ .xrgb1555_result = {
+ .dst_pitch = 0,
+ .expected = { 0x7C00 },
+ },
+ .argb1555_result = {
+ .dst_pitch = 0,
+ .expected = { 0xFC00 },
+ },
+ .rgba5551_result = {
+ .dst_pitch = 0,
+ .expected = { 0xF801 },
+ },
.rgb888_result = {
.dst_pitch = 0,
.expected = { 0x00, 0x00, 0xFF },
},
+ .argb8888_result = {
+ .dst_pitch = 0,
+ .expected = { 0xFFFF0000 },
+ },
.xrgb2101010_result = {
.dst_pitch = 0,
.expected = { 0x3FF00000 },
},
+ .argb2101010_result = {
+ .dst_pitch = 0,
+ .expected = { 0xFFF00000 },
+ },
},
{
.name = "single_pixel_clip_rectangle",
@@ -103,14 +153,34 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
.expected = { 0xF800 },
.expected_swab = { 0x00F8 },
},
+ .xrgb1555_result = {
+ .dst_pitch = 0,
+ .expected = { 0x7C00 },
+ },
+ .argb1555_result = {
+ .dst_pitch = 0,
+ .expected = { 0xFC00 },
+ },
+ .rgba5551_result = {
+ .dst_pitch = 0,
+ .expected = { 0xF801 },
+ },
.rgb888_result = {
.dst_pitch = 0,
.expected = { 0x00, 0x00, 0xFF },
},
+ .argb8888_result = {
+ .dst_pitch = 0,
+ .expected = { 0xFFFF0000 },
+ },
.xrgb2101010_result = {
.dst_pitch = 0,
.expected = { 0x3FF00000 },
},
+ .argb2101010_result = {
+ .dst_pitch = 0,
+ .expected = { 0xFFF00000 },
+ },
},
{
/* Well known colors: White, black, red, green, blue, magenta,
@@ -160,6 +230,33 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
0xE0FF, 0xFF07,
},
},
+ .xrgb1555_result = {
+ .dst_pitch = 0,
+ .expected = {
+ 0x7FFF, 0x0000,
+ 0x7C00, 0x03E0,
+ 0x001F, 0x7C1F,
+ 0x7FE0, 0x03FF,
+ },
+ },
+ .argb1555_result = {
+ .dst_pitch = 0,
+ .expected = {
+ 0xFFFF, 0x8000,
+ 0xFC00, 0x83E0,
+ 0x801F, 0xFC1F,
+ 0xFFE0, 0x83FF,
+ },
+ },
+ .rgba5551_result = {
+ .dst_pitch = 0,
+ .expected = {
+ 0xFFFF, 0x0001,
+ 0xF801, 0x07C1,
+ 0x003F, 0xF83F,
+ 0xFFC1, 0x07FF,
+ },
+ },
.rgb888_result = {
.dst_pitch = 0,
.expected = {
@@ -169,6 +266,15 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
},
},
+ .argb8888_result = {
+ .dst_pitch = 0,
+ .expected = {
+ 0xFFFFFFFF, 0xFF000000,
+ 0xFFFF0000, 0xFF00FF00,
+ 0xFF0000FF, 0xFFFF00FF,
+ 0xFFFFFF00, 0xFF00FFFF,
+ },
+ },
.xrgb2101010_result = {
.dst_pitch = 0,
.expected = {
@@ -178,6 +284,15 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
0x3FFFFC00, 0x000FFFFF,
},
},
+ .argb2101010_result = {
+ .dst_pitch = 0,
+ .expected = {
+ 0xFFFFFFFF, 0xC0000000,
+ 0xFFF00000, 0xC00FFC00,
+ 0xC00003FF, 0xFFF003FF,
+ 0xFFFFFC00, 0xC00FFFFF,
+ },
+ },
},
{
/* Randomly picked colors. Full buffer within the clip area. */
@@ -218,6 +333,30 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
0x00A8, 0x8E6B, 0x330A, 0x0000, 0x0000,
},
},
+ .xrgb1555_result = {
+ .dst_pitch = 10,
+ .expected = {
+ 0x0513, 0x0920, 0x5400, 0x0000, 0x0000,
+ 0x35CE, 0x0513, 0x0920, 0x0000, 0x0000,
+ 0x5400, 0x35CE, 0x0513, 0x0000, 0x0000,
+ },
+ },
+ .argb1555_result = {
+ .dst_pitch = 10,
+ .expected = {
+ 0x8513, 0x8920, 0xD400, 0x0000, 0x0000,
+ 0xB5CE, 0x8513, 0x8920, 0x0000, 0x0000,
+ 0xD400, 0xB5CE, 0x8513, 0x0000, 0x0000,
+ },
+ },
+ .rgba5551_result = {
+ .dst_pitch = 10,
+ .expected = {
+ 0x0A27, 0x1241, 0xA801, 0x0000, 0x0000,
+ 0x6B9D, 0x0A27, 0x1241, 0x0000, 0x0000,
+ 0xA801, 0x6B9D, 0x0A27, 0x0000, 0x0000,
+ },
+ },
.rgb888_result = {
.dst_pitch = 15,
.expected = {
@@ -229,6 +368,14 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
},
},
+ .argb8888_result = {
+ .dst_pitch = 20,
+ .expected = {
+ 0xFF0E449C, 0xFF114D05, 0xFFA80303, 0x00000000, 0x00000000,
+ 0xFF6C7073, 0xFF0E449C, 0xFF114D05, 0x00000000, 0x00000000,
+ 0xFFA80303, 0xFF6C7073, 0xFF0E449C, 0x00000000, 0x00000000,
+ },
+ },
.xrgb2101010_result = {
.dst_pitch = 20,
.expected = {
@@ -237,6 +384,14 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
0x2A20300C, 0x1B1705CD, 0x03844672, 0x00000000, 0x00000000,
},
},
+ .argb2101010_result = {
+ .dst_pitch = 20,
+ .expected = {
+ 0xC3844672, 0xC444D414, 0xEA20300C, 0x00000000, 0x00000000,
+ 0xDB1705CD, 0xC3844672, 0xC444D414, 0x00000000, 0x00000000,
+ 0xEA20300C, 0xDB1705CD, 0xC3844672, 0x00000000, 0x00000000,
+ },
+ },
},
};
@@ -264,7 +419,22 @@ static size_t conversion_buf_size(u32 dst_format, unsigned int dst_pitch,
return dst_pitch * drm_rect_height(clip);
}
-static u32 *le32buf_to_cpu(struct kunit *test, const u32 *buf, size_t buf_size)
+static u16 *le16buf_to_cpu(struct kunit *test, const __le16 *buf, size_t buf_size)
+{
+ u16 *dst = NULL;
+ int n;
+
+ dst = kunit_kzalloc(test, sizeof(*dst) * buf_size, GFP_KERNEL);
+ if (!dst)
+ return NULL;
+
+ for (n = 0; n < buf_size; n++)
+ dst[n] = le16_to_cpu(buf[n]);
+
+ return dst;
+}
+
+static u32 *le32buf_to_cpu(struct kunit *test, const __le32 *buf, size_t buf_size)
{
u32 *dst = NULL;
int n;
@@ -279,6 +449,21 @@ static u32 *le32buf_to_cpu(struct kunit *test, const u32 *buf, size_t buf_size)
return dst;
}
+static __le32 *cpubuf_to_le32(struct kunit *test, const u32 *buf, size_t buf_size)
+{
+ __le32 *dst = NULL;
+ int n;
+
+ dst = kunit_kzalloc(test, sizeof(*dst) * buf_size, GFP_KERNEL);
+ if (!dst)
+ return NULL;
+
+ for (n = 0; n < buf_size; n++)
+ dst[n] = cpu_to_le32(buf[n]);
+
+ return dst;
+}
+
static void convert_xrgb8888_case_desc(struct convert_xrgb8888_case *t,
char *desc)
{
@@ -293,8 +478,8 @@ static void drm_test_fb_xrgb8888_to_gray8(struct kunit *test)
const struct convert_xrgb8888_case *params = test->param_value;
const struct convert_to_gray8_result *result = &params->gray8_result;
size_t dst_size;
- __u8 *buf = NULL;
- __u32 *xrgb8888 = NULL;
+ u8 *buf = NULL;
+ __le32 *xrgb8888 = NULL;
struct iosys_map dst, src;
struct drm_framebuffer fb = {
@@ -310,7 +495,7 @@ static void drm_test_fb_xrgb8888_to_gray8(struct kunit *test)
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);
iosys_map_set_vaddr(&dst, buf);
- xrgb8888 = le32buf_to_cpu(test, params->xrgb8888, TEST_BUF_SIZE);
+ xrgb8888 = cpubuf_to_le32(test, params->xrgb8888, TEST_BUF_SIZE);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888);
iosys_map_set_vaddr(&src, xrgb8888);
@@ -323,8 +508,8 @@ static void drm_test_fb_xrgb8888_to_rgb332(struct kunit *test)
const struct convert_xrgb8888_case *params = test->param_value;
const struct convert_to_rgb332_result *result = &params->rgb332_result;
size_t dst_size;
- __u8 *buf = NULL;
- __u32 *xrgb8888 = NULL;
+ u8 *buf = NULL;
+ __le32 *xrgb8888 = NULL;
struct iosys_map dst, src;
struct drm_framebuffer fb = {
@@ -340,7 +525,7 @@ static void drm_test_fb_xrgb8888_to_rgb332(struct kunit *test)
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);
iosys_map_set_vaddr(&dst, buf);
- xrgb8888 = le32buf_to_cpu(test, params->xrgb8888, TEST_BUF_SIZE);
+ xrgb8888 = cpubuf_to_le32(test, params->xrgb8888, TEST_BUF_SIZE);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888);
iosys_map_set_vaddr(&src, xrgb8888);
@@ -353,8 +538,8 @@ static void drm_test_fb_xrgb8888_to_rgb565(struct kunit *test)
const struct convert_xrgb8888_case *params = test->param_value;
const struct convert_to_rgb565_result *result = &params->rgb565_result;
size_t dst_size;
- __u16 *buf = NULL;
- __u32 *xrgb8888 = NULL;
+ u16 *buf = NULL;
+ __le32 *xrgb8888 = NULL;
struct iosys_map dst, src;
struct drm_framebuffer fb = {
@@ -370,24 +555,120 @@ static void drm_test_fb_xrgb8888_to_rgb565(struct kunit *test)
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);
iosys_map_set_vaddr(&dst, buf);
- xrgb8888 = le32buf_to_cpu(test, params->xrgb8888, TEST_BUF_SIZE);
+ xrgb8888 = cpubuf_to_le32(test, params->xrgb8888, TEST_BUF_SIZE);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888);
iosys_map_set_vaddr(&src, xrgb8888);
drm_fb_xrgb8888_to_rgb565(&dst, &result->dst_pitch, &src, &fb, &params->clip, false);
+ buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16));
KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size);
+ buf = dst.vaddr; /* restore original value of buf */
drm_fb_xrgb8888_to_rgb565(&dst, &result->dst_pitch, &src, &fb, &params->clip, true);
+ buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16));
KUNIT_EXPECT_MEMEQ(test, buf, result->expected_swab, dst_size);
}
+static void drm_test_fb_xrgb8888_to_xrgb1555(struct kunit *test)
+{
+ const struct convert_xrgb8888_case *params = test->param_value;
+ const struct convert_to_xrgb1555_result *result = &params->xrgb1555_result;
+ size_t dst_size;
+ u16 *buf = NULL;
+ __le32 *xrgb8888 = NULL;
+ struct iosys_map dst, src;
+
+ struct drm_framebuffer fb = {
+ .format = drm_format_info(DRM_FORMAT_XRGB8888),
+ .pitches = { params->pitch, 0, 0 },
+ };
+
+ dst_size = conversion_buf_size(DRM_FORMAT_XRGB1555, result->dst_pitch,
+ &params->clip);
+ KUNIT_ASSERT_GT(test, dst_size, 0);
+
+ buf = kunit_kzalloc(test, dst_size, GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);
+ iosys_map_set_vaddr(&dst, buf);
+
+ xrgb8888 = cpubuf_to_le32(test, params->xrgb8888, TEST_BUF_SIZE);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888);
+ iosys_map_set_vaddr(&src, xrgb8888);
+
+ drm_fb_xrgb8888_to_xrgb1555(&dst, &result->dst_pitch, &src, &fb, &params->clip);
+ buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16));
+ KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0);
+}
+
+static void drm_test_fb_xrgb8888_to_argb1555(struct kunit *test)
+{
+ const struct convert_xrgb8888_case *params = test->param_value;
+ const struct convert_to_argb1555_result *result = &params->argb1555_result;
+ size_t dst_size;
+ u16 *buf = NULL;
+ __le32 *xrgb8888 = NULL;
+ struct iosys_map dst, src;
+
+ struct drm_framebuffer fb = {
+ .format = drm_format_info(DRM_FORMAT_XRGB8888),
+ .pitches = { params->pitch, 0, 0 },
+ };
+
+ dst_size = conversion_buf_size(DRM_FORMAT_ARGB1555, result->dst_pitch,
+ &params->clip);
+ KUNIT_ASSERT_GT(test, dst_size, 0);
+
+ buf = kunit_kzalloc(test, dst_size, GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);
+ iosys_map_set_vaddr(&dst, buf);
+
+ xrgb8888 = cpubuf_to_le32(test, params->xrgb8888, TEST_BUF_SIZE);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888);
+ iosys_map_set_vaddr(&src, xrgb8888);
+
+ drm_fb_xrgb8888_to_argb1555(&dst, &result->dst_pitch, &src, &fb, &params->clip);
+ buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16));
+ KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0);
+}
+
+static void drm_test_fb_xrgb8888_to_rgba5551(struct kunit *test)
+{
+ const struct convert_xrgb8888_case *params = test->param_value;
+ const struct convert_to_rgba5551_result *result = &params->rgba5551_result;
+ size_t dst_size;
+ u16 *buf = NULL;
+ __le32 *xrgb8888 = NULL;
+ struct iosys_map dst, src;
+
+ struct drm_framebuffer fb = {
+ .format = drm_format_info(DRM_FORMAT_XRGB8888),
+ .pitches = { params->pitch, 0, 0 },
+ };
+
+ dst_size = conversion_buf_size(DRM_FORMAT_RGBA5551, result->dst_pitch,
+ &params->clip);
+ KUNIT_ASSERT_GT(test, dst_size, 0);
+
+ buf = kunit_kzalloc(test, dst_size, GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);
+ iosys_map_set_vaddr(&dst, buf);
+
+ xrgb8888 = cpubuf_to_le32(test, params->xrgb8888, TEST_BUF_SIZE);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888);
+ iosys_map_set_vaddr(&src, xrgb8888);
+
+ drm_fb_xrgb8888_to_rgba5551(&dst, &result->dst_pitch, &src, &fb, &params->clip);
+ buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16));
+ KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0);
+}
+
static void drm_test_fb_xrgb8888_to_rgb888(struct kunit *test)
{
const struct convert_xrgb8888_case *params = test->param_value;
const struct convert_to_rgb888_result *result = &params->rgb888_result;
size_t dst_size;
- __u8 *buf = NULL;
- __u32 *xrgb8888 = NULL;
+ u8 *buf = NULL;
+ __le32 *xrgb8888 = NULL;
struct iosys_map dst, src;
struct drm_framebuffer fb = {
@@ -403,21 +684,56 @@ static void drm_test_fb_xrgb8888_to_rgb888(struct kunit *test)
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);
iosys_map_set_vaddr(&dst, buf);
- xrgb8888 = le32buf_to_cpu(test, params->xrgb8888, TEST_BUF_SIZE);
+ xrgb8888 = cpubuf_to_le32(test, params->xrgb8888, TEST_BUF_SIZE);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888);
iosys_map_set_vaddr(&src, xrgb8888);
+ /*
+ * RGB888 expected results are already in little-endian
+ * order, so there's no need to convert the test output.
+ */
drm_fb_xrgb8888_to_rgb888(&dst, &result->dst_pitch, &src, &fb, &params->clip);
KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size);
}
+static void drm_test_fb_xrgb8888_to_argb8888(struct kunit *test)
+{
+ const struct convert_xrgb8888_case *params = test->param_value;
+ const struct convert_to_argb8888_result *result = &params->argb8888_result;
+ size_t dst_size;
+ u32 *buf = NULL;
+ __le32 *xrgb8888 = NULL;
+ struct iosys_map dst, src;
+
+ struct drm_framebuffer fb = {
+ .format = drm_format_info(DRM_FORMAT_XRGB8888),
+ .pitches = { params->pitch, 0, 0 },
+ };
+
+ dst_size = conversion_buf_size(DRM_FORMAT_ARGB8888,
+ result->dst_pitch, &params->clip);
+ KUNIT_ASSERT_GT(test, dst_size, 0);
+
+ buf = kunit_kzalloc(test, dst_size, GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);
+ iosys_map_set_vaddr(&dst, buf);
+
+ xrgb8888 = cpubuf_to_le32(test, params->xrgb8888, TEST_BUF_SIZE);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888);
+ iosys_map_set_vaddr(&src, xrgb8888);
+
+ drm_fb_xrgb8888_to_argb8888(&dst, &result->dst_pitch, &src, &fb, &params->clip);
+ buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32));
+ KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0);
+}
+
static void drm_test_fb_xrgb8888_to_xrgb2101010(struct kunit *test)
{
const struct convert_xrgb8888_case *params = test->param_value;
const struct convert_to_xrgb2101010_result *result = &params->xrgb2101010_result;
size_t dst_size;
- __u32 *buf = NULL;
- __u32 *xrgb8888 = NULL;
+ u32 *buf = NULL;
+ __le32 *xrgb8888 = NULL;
struct iosys_map dst, src;
struct drm_framebuffer fb = {
@@ -433,7 +749,7 @@ static void drm_test_fb_xrgb8888_to_xrgb2101010(struct kunit *test)
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);
iosys_map_set_vaddr(&dst, buf);
- xrgb8888 = le32buf_to_cpu(test, params->xrgb8888, TEST_BUF_SIZE);
+ xrgb8888 = cpubuf_to_le32(test, params->xrgb8888, TEST_BUF_SIZE);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888);
iosys_map_set_vaddr(&src, xrgb8888);
@@ -442,12 +758,48 @@ static void drm_test_fb_xrgb8888_to_xrgb2101010(struct kunit *test)
KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size);
}
+static void drm_test_fb_xrgb8888_to_argb2101010(struct kunit *test)
+{
+ const struct convert_xrgb8888_case *params = test->param_value;
+ const struct convert_to_argb2101010_result *result = &params->argb2101010_result;
+ size_t dst_size;
+ u32 *buf = NULL;
+ __le32 *xrgb8888 = NULL;
+ struct iosys_map dst, src;
+
+ struct drm_framebuffer fb = {
+ .format = drm_format_info(DRM_FORMAT_XRGB8888),
+ .pitches = { params->pitch, 0, 0 },
+ };
+
+ dst_size = conversion_buf_size(DRM_FORMAT_ARGB2101010,
+ result->dst_pitch, &params->clip);
+ KUNIT_ASSERT_GT(test, dst_size, 0);
+
+ buf = kunit_kzalloc(test, dst_size, GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);
+ iosys_map_set_vaddr(&dst, buf);
+
+ xrgb8888 = cpubuf_to_le32(test, params->xrgb8888, TEST_BUF_SIZE);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888);
+ iosys_map_set_vaddr(&src, xrgb8888);
+
+ drm_fb_xrgb8888_to_argb2101010(&dst, &result->dst_pitch, &src, &fb, &params->clip);
+ buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32));
+ KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0);
+}
+
static struct kunit_case drm_format_helper_test_cases[] = {
KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_gray8, convert_xrgb8888_gen_params),
KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_rgb332, convert_xrgb8888_gen_params),
KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_rgb565, convert_xrgb8888_gen_params),
+ KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_xrgb1555, convert_xrgb8888_gen_params),
+ KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_argb1555, convert_xrgb8888_gen_params),
+ KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_rgba5551, convert_xrgb8888_gen_params),
KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_rgb888, convert_xrgb8888_gen_params),
+ KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_argb8888, convert_xrgb8888_gen_params),
KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_xrgb2101010, convert_xrgb8888_gen_params),
+ KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_argb2101010, convert_xrgb8888_gen_params),
{}
};
diff --git a/drivers/gpu/drm/tests/drm_kunit_helpers.c b/drivers/gpu/drm/tests/drm_kunit_helpers.c
index f1662091f250..e98b4150f556 100644
--- a/drivers/gpu/drm/tests/drm_kunit_helpers.c
+++ b/drivers/gpu/drm/tests/drm_kunit_helpers.c
@@ -1,63 +1,101 @@
// SPDX-License-Identifier: GPL-2.0
#include <drm/drm_drv.h>
+#include <drm/drm_kunit_helpers.h>
#include <drm/drm_managed.h>
#include <kunit/resource.h>
#include <linux/device.h>
+#include <linux/platform_device.h>
-#include "drm_kunit_helpers.h"
-
-struct kunit_dev {
- struct drm_device base;
-};
+#define KUNIT_DEVICE_NAME "drm-kunit-mock-device"
static const struct drm_mode_config_funcs drm_mode_config_funcs = {
};
-static int dev_init(struct kunit_resource *res, void *ptr)
+static int fake_probe(struct platform_device *pdev)
{
- char *name = ptr;
- struct device *dev;
-
- dev = root_device_register(name);
- if (IS_ERR(dev))
- return PTR_ERR(dev);
+ return 0;
+}
- res->data = dev;
+static int fake_remove(struct platform_device *pdev)
+{
return 0;
}
-static void dev_free(struct kunit_resource *res)
+static struct platform_driver fake_platform_driver = {
+ .probe = fake_probe,
+ .remove = fake_remove,
+ .driver = {
+ .name = KUNIT_DEVICE_NAME,
+ },
+};
+
+/**
+ * drm_kunit_helper_alloc_device - Allocate a mock device for a KUnit test
+ * @test: The test context object
+ *
+ * This allocates a fake struct &device to create a mock for a KUnit
+ * test. The device will also be bound to a fake driver. It will thus be
+ * able to leverage the usual infrastructure and most notably the
+ * device-managed resources just like a "real" device.
+ *
+ * Callers need to make sure drm_kunit_helper_free_device() on the
+ * device when done.
+ *
+ * Returns:
+ * A pointer to the new device, or an ERR_PTR() otherwise.
+ */
+struct device *drm_kunit_helper_alloc_device(struct kunit *test)
{
- struct device *dev = res->data;
+ struct platform_device *pdev;
+ int ret;
- root_device_unregister(dev);
+ ret = platform_driver_register(&fake_platform_driver);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ pdev = platform_device_alloc(KUNIT_DEVICE_NAME, PLATFORM_DEVID_NONE);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
+
+ ret = platform_device_add(pdev);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ return &pdev->dev;
+}
+EXPORT_SYMBOL_GPL(drm_kunit_helper_alloc_device);
+
+/**
+ * drm_kunit_helper_free_device - Frees a mock device
+ * @test: The test context object
+ * @dev: The device to free
+ *
+ * Frees a device allocated with drm_kunit_helper_alloc_device().
+ */
+void drm_kunit_helper_free_device(struct kunit *test, struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+
+ platform_device_unregister(pdev);
+ platform_driver_unregister(&fake_platform_driver);
}
+EXPORT_SYMBOL_GPL(drm_kunit_helper_free_device);
-struct drm_device *drm_kunit_device_init(struct kunit *test, u32 features, char *name)
+struct drm_device *
+__drm_kunit_helper_alloc_drm_device_with_driver(struct kunit *test,
+ struct device *dev,
+ size_t size, size_t offset,
+ const struct drm_driver *driver)
{
- struct kunit_dev *kdev;
struct drm_device *drm;
- struct drm_driver *driver;
- struct device *dev;
+ void *container;
int ret;
- dev = kunit_alloc_resource(test, dev_init, dev_free, GFP_KERNEL, name);
- if (!dev)
- return ERR_PTR(-ENOMEM);
-
- driver = kunit_kzalloc(test, sizeof(*driver), GFP_KERNEL);
- if (!driver)
- return ERR_PTR(-ENOMEM);
-
- driver->driver_features = features;
- kdev = devm_drm_dev_alloc(dev, driver, struct kunit_dev, base);
- if (IS_ERR(kdev))
- return ERR_CAST(kdev);
+ container = __devm_drm_dev_alloc(dev, driver, size, offset);
+ if (IS_ERR(container))
+ return ERR_CAST(container);
- drm = &kdev->base;
+ drm = container + offset;
drm->mode_config.funcs = &drm_mode_config_funcs;
ret = drmm_mode_config_init(drm);
@@ -66,6 +104,7 @@ struct drm_device *drm_kunit_device_init(struct kunit *test, u32 features, char
return drm;
}
+EXPORT_SYMBOL_GPL(__drm_kunit_helper_alloc_drm_device_with_driver);
MODULE_AUTHOR("Maxime Ripard <maxime@cerno.tech>");
MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/tests/drm_kunit_helpers.h b/drivers/gpu/drm/tests/drm_kunit_helpers.h
deleted file mode 100644
index 20ab6eec4c89..000000000000
--- a/drivers/gpu/drm/tests/drm_kunit_helpers.h
+++ /dev/null
@@ -1,11 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-#ifndef DRM_KUNIT_HELPERS_H_
-#define DRM_KUNIT_HELPERS_H_
-
-struct drm_device;
-struct kunit;
-
-struct drm_device *drm_kunit_device_init(struct kunit *test, u32 features, char *name);
-
-#endif // DRM_KUNIT_HELPERS_H_
diff --git a/drivers/gpu/drm/tests/drm_managed_test.c b/drivers/gpu/drm/tests/drm_managed_test.c
new file mode 100644
index 000000000000..1652dca11d30
--- /dev/null
+++ b/drivers/gpu/drm/tests/drm_managed_test.c
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <drm/drm_drv.h>
+#include <drm/drm_kunit_helpers.h>
+#include <drm/drm_managed.h>
+
+#include <kunit/resource.h>
+
+#include <linux/device.h>
+
+/* Ought to be enough for anybody */
+#define TEST_TIMEOUT_MS 100
+
+struct managed_test_priv {
+ bool action_done;
+ wait_queue_head_t action_wq;
+};
+
+static void drm_action(struct drm_device *drm, void *ptr)
+{
+ struct managed_test_priv *priv = ptr;
+
+ priv->action_done = true;
+ wake_up_interruptible(&priv->action_wq);
+}
+
+static void drm_test_managed_run_action(struct kunit *test)
+{
+ struct managed_test_priv *priv;
+ struct drm_device *drm;
+ struct device *dev;
+ int ret;
+
+ priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
+ init_waitqueue_head(&priv->action_wq);
+
+ dev = drm_kunit_helper_alloc_device(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
+
+ drm = __drm_kunit_helper_alloc_drm_device(test, dev, sizeof(*drm), 0, DRIVER_MODESET);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, drm);
+
+ ret = drmm_add_action_or_reset(drm, drm_action, priv);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+
+ ret = drm_dev_register(drm, 0);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ drm_dev_unregister(drm);
+ drm_kunit_helper_free_device(test, dev);
+
+ ret = wait_event_interruptible_timeout(priv->action_wq, priv->action_done,
+ msecs_to_jiffies(TEST_TIMEOUT_MS));
+ KUNIT_EXPECT_GT(test, ret, 0);
+}
+
+static struct kunit_case drm_managed_tests[] = {
+ KUNIT_CASE(drm_test_managed_run_action),
+ {}
+};
+
+static struct kunit_suite drm_managed_test_suite = {
+ .name = "drm-test-managed",
+ .test_cases = drm_managed_tests
+};
+
+kunit_test_suite(drm_managed_test_suite);
+
+MODULE_AUTHOR("Maxime Ripard <maxime@cerno.tech>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/tests/drm_modes_test.c b/drivers/gpu/drm/tests/drm_modes_test.c
new file mode 100644
index 000000000000..bc4aa2ce78be
--- /dev/null
+++ b/drivers/gpu/drm/tests/drm_modes_test.c
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Kunit test for drm_modes functions
+ */
+
+#include <drm/drm_drv.h>
+#include <drm/drm_kunit_helpers.h>
+#include <drm/drm_modes.h>
+
+#include <kunit/test.h>
+
+#include <linux/units.h>
+
+struct drm_test_modes_priv {
+ struct drm_device *drm;
+ struct device *dev;
+};
+
+static int drm_test_modes_init(struct kunit *test)
+{
+ struct drm_test_modes_priv *priv;
+
+ priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, priv);
+
+ priv->dev = drm_kunit_helper_alloc_device(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->dev);
+
+ priv->drm = __drm_kunit_helper_alloc_drm_device(test, priv->dev,
+ sizeof(*priv->drm), 0,
+ DRIVER_MODESET);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->drm);
+
+ test->priv = priv;
+
+ return 0;
+}
+
+static void drm_test_modes_exit(struct kunit *test)
+{
+ struct drm_test_modes_priv *priv = test->priv;
+
+ drm_kunit_helper_free_device(test, priv->dev);
+}
+
+static void drm_test_modes_analog_tv_ntsc_480i(struct kunit *test)
+{
+ struct drm_test_modes_priv *priv = test->priv;
+ struct drm_display_mode *mode;
+
+ mode = drm_analog_tv_mode(priv->drm,
+ DRM_MODE_TV_MODE_NTSC,
+ 13500 * HZ_PER_KHZ, 720, 480,
+ true);
+ KUNIT_ASSERT_NOT_NULL(test, mode);
+
+ KUNIT_EXPECT_EQ(test, drm_mode_vrefresh(mode), 60);
+ KUNIT_EXPECT_EQ(test, mode->hdisplay, 720);
+
+ /* BT.601 defines hsync_start at 736 for 480i */
+ KUNIT_EXPECT_EQ(test, mode->hsync_start, 736);
+
+ /*
+ * The NTSC standard expects a line to take 63.556us. With a
+ * pixel clock of 13.5 MHz, a pixel takes around 74ns, so we
+ * need to have 63556ns / 74ns = 858.
+ *
+ * This is also mandated by BT.601.
+ */
+ KUNIT_EXPECT_EQ(test, mode->htotal, 858);
+
+ KUNIT_EXPECT_EQ(test, mode->vdisplay, 480);
+ KUNIT_EXPECT_EQ(test, mode->vtotal, 525);
+}
+
+static void drm_test_modes_analog_tv_ntsc_480i_inlined(struct kunit *test)
+{
+ struct drm_test_modes_priv *priv = test->priv;
+ struct drm_display_mode *expected, *mode;
+
+ expected = drm_analog_tv_mode(priv->drm,
+ DRM_MODE_TV_MODE_NTSC,
+ 13500 * HZ_PER_KHZ, 720, 480,
+ true);
+ KUNIT_ASSERT_NOT_NULL(test, expected);
+
+ mode = drm_mode_analog_ntsc_480i(priv->drm);
+ KUNIT_ASSERT_NOT_NULL(test, mode);
+
+ KUNIT_EXPECT_TRUE(test, drm_mode_equal(expected, mode));
+}
+
+static void drm_test_modes_analog_tv_pal_576i(struct kunit *test)
+{
+ struct drm_test_modes_priv *priv = test->priv;
+ struct drm_display_mode *mode;
+
+ mode = drm_analog_tv_mode(priv->drm,
+ DRM_MODE_TV_MODE_PAL,
+ 13500 * HZ_PER_KHZ, 720, 576,
+ true);
+ KUNIT_ASSERT_NOT_NULL(test, mode);
+
+ KUNIT_EXPECT_EQ(test, drm_mode_vrefresh(mode), 50);
+ KUNIT_EXPECT_EQ(test, mode->hdisplay, 720);
+
+ /* BT.601 defines hsync_start at 732 for 576i */
+ KUNIT_EXPECT_EQ(test, mode->hsync_start, 732);
+
+ /*
+ * The PAL standard expects a line to take 64us. With a pixel
+ * clock of 13.5 MHz, a pixel takes around 74ns, so we need to
+ * have 64000ns / 74ns = 864.
+ *
+ * This is also mandated by BT.601.
+ */
+ KUNIT_EXPECT_EQ(test, mode->htotal, 864);
+
+ KUNIT_EXPECT_EQ(test, mode->vdisplay, 576);
+ KUNIT_EXPECT_EQ(test, mode->vtotal, 625);
+}
+
+static void drm_test_modes_analog_tv_pal_576i_inlined(struct kunit *test)
+{
+ struct drm_test_modes_priv *priv = test->priv;
+ struct drm_display_mode *expected, *mode;
+
+ expected = drm_analog_tv_mode(priv->drm,
+ DRM_MODE_TV_MODE_PAL,
+ 13500 * HZ_PER_KHZ, 720, 576,
+ true);
+ KUNIT_ASSERT_NOT_NULL(test, expected);
+
+ mode = drm_mode_analog_pal_576i(priv->drm);
+ KUNIT_ASSERT_NOT_NULL(test, mode);
+
+ KUNIT_EXPECT_TRUE(test, drm_mode_equal(expected, mode));
+}
+
+static struct kunit_case drm_modes_analog_tv_tests[] = {
+ KUNIT_CASE(drm_test_modes_analog_tv_ntsc_480i),
+ KUNIT_CASE(drm_test_modes_analog_tv_ntsc_480i_inlined),
+ KUNIT_CASE(drm_test_modes_analog_tv_pal_576i),
+ KUNIT_CASE(drm_test_modes_analog_tv_pal_576i_inlined),
+ { }
+};
+
+static struct kunit_suite drm_modes_analog_tv_test_suite = {
+ .name = "drm_modes_analog_tv",
+ .init = drm_test_modes_init,
+ .exit = drm_test_modes_exit,
+ .test_cases = drm_modes_analog_tv_tests,
+};
+
+kunit_test_suite(drm_modes_analog_tv_test_suite);
+
+MODULE_AUTHOR("Maxime Ripard <maxime@cerno.tech>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/tests/drm_probe_helper_test.c b/drivers/gpu/drm/tests/drm_probe_helper_test.c
new file mode 100644
index 000000000000..0ee65828623e
--- /dev/null
+++ b/drivers/gpu/drm/tests/drm_probe_helper_test.c
@@ -0,0 +1,218 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Kunit test for drm_probe_helper functions
+ */
+
+#include <drm/drm_atomic_state_helper.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_device.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_kunit_helpers.h>
+#include <drm/drm_mode.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_modeset_helper_vtables.h>
+#include <drm/drm_probe_helper.h>
+
+#include <kunit/test.h>
+
+struct drm_probe_helper_test_priv {
+ struct drm_device *drm;
+ struct device *dev;
+ struct drm_connector connector;
+};
+
+static const struct drm_connector_helper_funcs drm_probe_helper_connector_helper_funcs = {
+};
+
+static const struct drm_connector_funcs drm_probe_helper_connector_funcs = {
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .reset = drm_atomic_helper_connector_reset,
+};
+
+static int drm_probe_helper_test_init(struct kunit *test)
+{
+ struct drm_probe_helper_test_priv *priv;
+ struct drm_connector *connector;
+ int ret;
+
+ priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, priv);
+ test->priv = priv;
+
+ priv->dev = drm_kunit_helper_alloc_device(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->dev);
+
+ priv->drm = __drm_kunit_helper_alloc_drm_device(test, priv->dev,
+ sizeof(*priv->drm), 0,
+ DRIVER_MODESET | DRIVER_ATOMIC);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->drm);
+
+ connector = &priv->connector;
+ ret = drmm_connector_init(priv->drm, connector,
+ &drm_probe_helper_connector_funcs,
+ DRM_MODE_CONNECTOR_Unknown,
+ NULL);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ drm_connector_helper_add(connector, &drm_probe_helper_connector_helper_funcs);
+
+ return 0;
+}
+
+static void drm_probe_helper_test_exit(struct kunit *test)
+{
+ struct drm_probe_helper_test_priv *priv = test->priv;
+
+ drm_kunit_helper_free_device(test, priv->dev);
+}
+
+typedef struct drm_display_mode *(*expected_mode_func_t)(struct drm_device *);
+
+struct drm_connector_helper_tv_get_modes_test {
+ const char *name;
+ unsigned int supported_tv_modes;
+ enum drm_connector_tv_mode default_mode;
+ bool cmdline;
+ enum drm_connector_tv_mode cmdline_mode;
+ expected_mode_func_t *expected_modes;
+ unsigned int num_expected_modes;
+};
+
+#define _TV_MODE_TEST(_name, _supported, _default, _cmdline, _cmdline_mode, ...) \
+ { \
+ .name = _name, \
+ .supported_tv_modes = _supported, \
+ .default_mode = _default, \
+ .cmdline = _cmdline, \
+ .cmdline_mode = _cmdline_mode, \
+ .expected_modes = (expected_mode_func_t[]) { __VA_ARGS__ }, \
+ .num_expected_modes = sizeof((expected_mode_func_t[]) { __VA_ARGS__ }) / \
+ (sizeof(expected_mode_func_t)), \
+ }
+
+#define TV_MODE_TEST(_name, _supported, _default, ...) \
+ _TV_MODE_TEST(_name, _supported, _default, false, 0, __VA_ARGS__)
+
+#define TV_MODE_TEST_CMDLINE(_name, _supported, _default, _cmdline, ...) \
+ _TV_MODE_TEST(_name, _supported, _default, true, _cmdline, __VA_ARGS__)
+
+static void
+drm_test_connector_helper_tv_get_modes_check(struct kunit *test)
+{
+ const struct drm_connector_helper_tv_get_modes_test *params = test->param_value;
+ struct drm_probe_helper_test_priv *priv = test->priv;
+ struct drm_connector *connector = &priv->connector;
+ struct drm_cmdline_mode *cmdline = &connector->cmdline_mode;
+ struct drm_display_mode *mode;
+ const struct drm_display_mode *expected;
+ size_t len;
+ int ret;
+
+ if (params->cmdline) {
+ cmdline->tv_mode_specified = true;
+ cmdline->tv_mode = params->cmdline_mode;
+ }
+
+ ret = drm_mode_create_tv_properties(priv->drm, params->supported_tv_modes);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ drm_object_attach_property(&connector->base,
+ priv->drm->mode_config.tv_mode_property,
+ params->default_mode);
+
+ mutex_lock(&priv->drm->mode_config.mutex);
+
+ ret = drm_connector_helper_tv_get_modes(connector);
+ KUNIT_EXPECT_EQ(test, ret, params->num_expected_modes);
+
+ len = 0;
+ list_for_each_entry(mode, &connector->probed_modes, head)
+ len++;
+ KUNIT_EXPECT_EQ(test, len, params->num_expected_modes);
+
+ if (params->num_expected_modes >= 1) {
+ mode = list_first_entry_or_null(&connector->probed_modes,
+ struct drm_display_mode, head);
+ KUNIT_ASSERT_NOT_NULL(test, mode);
+
+ expected = params->expected_modes[0](priv->drm);
+ KUNIT_ASSERT_NOT_NULL(test, expected);
+
+ KUNIT_EXPECT_TRUE(test, drm_mode_equal(mode, expected));
+ KUNIT_EXPECT_TRUE(test, mode->type & DRM_MODE_TYPE_PREFERRED);
+ }
+
+ if (params->num_expected_modes >= 2) {
+ mode = list_next_entry(mode, head);
+ KUNIT_ASSERT_NOT_NULL(test, mode);
+
+ expected = params->expected_modes[1](priv->drm);
+ KUNIT_ASSERT_NOT_NULL(test, expected);
+
+ KUNIT_EXPECT_TRUE(test, drm_mode_equal(mode, expected));
+ KUNIT_EXPECT_FALSE(test, mode->type & DRM_MODE_TYPE_PREFERRED);
+ }
+
+ mutex_unlock(&priv->drm->mode_config.mutex);
+}
+
+static const
+struct drm_connector_helper_tv_get_modes_test drm_connector_helper_tv_get_modes_tests[] = {
+ { .name = "None" },
+ TV_MODE_TEST("PAL",
+ BIT(DRM_MODE_TV_MODE_PAL),
+ DRM_MODE_TV_MODE_PAL,
+ drm_mode_analog_pal_576i),
+ TV_MODE_TEST("NTSC",
+ BIT(DRM_MODE_TV_MODE_NTSC),
+ DRM_MODE_TV_MODE_NTSC,
+ drm_mode_analog_ntsc_480i),
+ TV_MODE_TEST("Both, NTSC Default",
+ BIT(DRM_MODE_TV_MODE_NTSC) | BIT(DRM_MODE_TV_MODE_PAL),
+ DRM_MODE_TV_MODE_NTSC,
+ drm_mode_analog_ntsc_480i, drm_mode_analog_pal_576i),
+ TV_MODE_TEST("Both, PAL Default",
+ BIT(DRM_MODE_TV_MODE_NTSC) | BIT(DRM_MODE_TV_MODE_PAL),
+ DRM_MODE_TV_MODE_PAL,
+ drm_mode_analog_pal_576i, drm_mode_analog_ntsc_480i),
+ TV_MODE_TEST_CMDLINE("Both, NTSC Default, with PAL on command-line",
+ BIT(DRM_MODE_TV_MODE_NTSC) | BIT(DRM_MODE_TV_MODE_PAL),
+ DRM_MODE_TV_MODE_NTSC,
+ DRM_MODE_TV_MODE_PAL,
+ drm_mode_analog_pal_576i, drm_mode_analog_ntsc_480i),
+ TV_MODE_TEST_CMDLINE("Both, PAL Default, with NTSC on command-line",
+ BIT(DRM_MODE_TV_MODE_NTSC) | BIT(DRM_MODE_TV_MODE_PAL),
+ DRM_MODE_TV_MODE_PAL,
+ DRM_MODE_TV_MODE_NTSC,
+ drm_mode_analog_ntsc_480i, drm_mode_analog_pal_576i),
+};
+
+static void
+drm_connector_helper_tv_get_modes_desc(const struct drm_connector_helper_tv_get_modes_test *t,
+ char *desc)
+{
+ sprintf(desc, "%s", t->name);
+}
+
+KUNIT_ARRAY_PARAM(drm_connector_helper_tv_get_modes,
+ drm_connector_helper_tv_get_modes_tests,
+ drm_connector_helper_tv_get_modes_desc);
+
+static struct kunit_case drm_test_connector_helper_tv_get_modes_tests[] = {
+ KUNIT_CASE_PARAM(drm_test_connector_helper_tv_get_modes_check,
+ drm_connector_helper_tv_get_modes_gen_params),
+ { }
+};
+
+static struct kunit_suite drm_test_connector_helper_tv_get_modes_suite = {
+ .name = "drm_connector_helper_tv_get_modes",
+ .init = drm_probe_helper_test_init,
+ .exit = drm_probe_helper_test_exit,
+ .test_cases = drm_test_connector_helper_tv_get_modes_tests,
+};
+
+kunit_test_suite(drm_test_connector_helper_tv_get_modes_suite);
+
+MODULE_AUTHOR("Maxime Ripard <maxime@cerno.tech>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/tidss/tidss_crtc.c b/drivers/gpu/drm/tidss/tidss_crtc.c
index cd3c43a6c806..5e5e466f35d1 100644
--- a/drivers/gpu/drm/tidss/tidss_crtc.c
+++ b/drivers/gpu/drm/tidss/tidss_crtc.c
@@ -7,7 +7,6 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_vblank.h>
diff --git a/drivers/gpu/drm/tidss/tidss_dispc.c b/drivers/gpu/drm/tidss/tidss_dispc.c
index ad93acc9abd2..165365b515e1 100644
--- a/drivers/gpu/drm/tidss/tidss_dispc.c
+++ b/drivers/gpu/drm/tidss/tidss_dispc.c
@@ -1858,8 +1858,8 @@ static const struct {
{ DRM_FORMAT_XBGR4444, 0x21, },
{ DRM_FORMAT_RGBX4444, 0x22, },
- { DRM_FORMAT_ARGB1555, 0x25, },
- { DRM_FORMAT_ABGR1555, 0x26, },
+ { DRM_FORMAT_XRGB1555, 0x25, },
+ { DRM_FORMAT_XBGR1555, 0x26, },
{ DRM_FORMAT_XRGB8888, 0x27, },
{ DRM_FORMAT_XBGR8888, 0x28, },
@@ -2686,6 +2686,8 @@ int dispc_init(struct tidss_device *tidss)
dev_warn(dev, "cannot set DMA masks to 48-bit\n");
}
+ dma_set_max_seg_size(dev, UINT_MAX);
+
dispc = devm_kzalloc(dev, sizeof(*dispc), GFP_KERNEL);
if (!dispc)
return -ENOMEM;
diff --git a/drivers/gpu/drm/tidss/tidss_drv.c b/drivers/gpu/drm/tidss/tidss_drv.c
index 07d94b1e8089..2dac8727d2f4 100644
--- a/drivers/gpu/drm/tidss/tidss_drv.c
+++ b/drivers/gpu/drm/tidss/tidss_drv.c
@@ -12,7 +12,6 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_fbdev_generic.h>
#include <drm/drm_gem_dma_helper.h>
diff --git a/drivers/gpu/drm/tidss/tidss_encoder.c b/drivers/gpu/drm/tidss/tidss_encoder.c
index e278a9c89476..0d4865e9c03d 100644
--- a/drivers/gpu/drm/tidss/tidss_encoder.c
+++ b/drivers/gpu/drm/tidss/tidss_encoder.c
@@ -7,7 +7,7 @@
#include <linux/export.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_panel.h>
#include <drm/drm_of.h>
diff --git a/drivers/gpu/drm/tidss/tidss_kms.c b/drivers/gpu/drm/tidss/tidss_kms.c
index 345bcc3011e4..ad2fa3c3d4a7 100644
--- a/drivers/gpu/drm/tidss/tidss_kms.c
+++ b/drivers/gpu/drm/tidss/tidss_kms.c
@@ -9,7 +9,6 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
diff --git a/drivers/gpu/drm/tidss/tidss_plane.c b/drivers/gpu/drm/tidss/tidss_plane.c
index 42d50ec5526d..fe2c41f0cd4f 100644
--- a/drivers/gpu/drm/tidss/tidss_plane.c
+++ b/drivers/gpu/drm/tidss/tidss_plane.c
@@ -8,7 +8,6 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_blend.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_atomic_helper.h>
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
index 80615ecdae0b..4ca426007dc8 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
@@ -496,7 +496,6 @@ static const struct drm_driver tilcdc_driver = {
* Power management:
*/
-#ifdef CONFIG_PM_SLEEP
static int tilcdc_pm_suspend(struct device *dev)
{
struct drm_device *ddev = dev_get_drvdata(dev);
@@ -518,11 +517,9 @@ static int tilcdc_pm_resume(struct device *dev)
pinctrl_pm_select_default_state(dev);
return drm_mode_config_helper_resume(ddev);
}
-#endif
-static const struct dev_pm_ops tilcdc_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(tilcdc_pm_suspend, tilcdc_pm_resume)
-};
+static DEFINE_SIMPLE_DEV_PM_OPS(tilcdc_pm_ops,
+ tilcdc_pm_suspend, tilcdc_pm_resume);
/*
* Platform driver:
@@ -597,7 +594,7 @@ static struct platform_driver tilcdc_platform_driver = {
.remove = tilcdc_pdev_remove,
.driver = {
.name = "tilcdc",
- .pm = &tilcdc_pm_ops,
+ .pm = pm_sleep_ptr(&tilcdc_pm_ops),
.of_match_table = tilcdc_of_match,
},
};
diff --git a/drivers/gpu/drm/tiny/cirrus.c b/drivers/gpu/drm/tiny/cirrus.c
index 678c2ef1cae7..cf35b6090503 100644
--- a/drivers/gpu/drm/tiny/cirrus.c
+++ b/drivers/gpu/drm/tiny/cirrus.c
@@ -604,7 +604,7 @@ static int cirrus_pci_probe(struct pci_dev *pdev,
if (ret)
return ret;
- drm_fbdev_generic_setup(dev, dev->mode_config.preferred_depth);
+ drm_fbdev_generic_setup(dev, 16);
return 0;
}
diff --git a/drivers/gpu/drm/tiny/gm12u320.c b/drivers/gpu/drm/tiny/gm12u320.c
index 130fd07a967d..c5bb683e440c 100644
--- a/drivers/gpu/drm/tiny/gm12u320.c
+++ b/drivers/gpu/drm/tiny/gm12u320.c
@@ -4,6 +4,7 @@
*/
#include <linux/module.h>
+#include <linux/pm.h>
#include <linux/usb.h>
#include <drm/drm_atomic_helper.h>
@@ -718,15 +719,15 @@ static void gm12u320_usb_disconnect(struct usb_interface *interface)
drm_atomic_helper_shutdown(dev);
}
-static __maybe_unused int gm12u320_suspend(struct usb_interface *interface,
- pm_message_t message)
+static int gm12u320_suspend(struct usb_interface *interface,
+ pm_message_t message)
{
struct drm_device *dev = usb_get_intfdata(interface);
return drm_mode_config_helper_suspend(dev);
}
-static __maybe_unused int gm12u320_resume(struct usb_interface *interface)
+static int gm12u320_resume(struct usb_interface *interface)
{
struct drm_device *dev = usb_get_intfdata(interface);
struct gm12u320_device *gm12u320 = to_gm12u320(dev);
@@ -747,11 +748,9 @@ static struct usb_driver gm12u320_usb_driver = {
.probe = gm12u320_usb_probe,
.disconnect = gm12u320_usb_disconnect,
.id_table = id_table,
-#ifdef CONFIG_PM
- .suspend = gm12u320_suspend,
- .resume = gm12u320_resume,
- .reset_resume = gm12u320_resume,
-#endif
+ .suspend = pm_ptr(gm12u320_suspend),
+ .resume = pm_ptr(gm12u320_resume),
+ .reset_resume = pm_ptr(gm12u320_resume),
};
module_usb_driver(gm12u320_usb_driver);
diff --git a/drivers/gpu/drm/tiny/hx8357d.c b/drivers/gpu/drm/tiny/hx8357d.c
index 9f634f720817..cdc4486e059b 100644
--- a/drivers/gpu/drm/tiny/hx8357d.c
+++ b/drivers/gpu/drm/tiny/hx8357d.c
@@ -181,10 +181,7 @@ out_exit:
}
static const struct drm_simple_display_pipe_funcs hx8357d_pipe_funcs = {
- .mode_valid = mipi_dbi_pipe_mode_valid,
- .enable = yx240qv29_enable,
- .disable = mipi_dbi_pipe_disable,
- .update = mipi_dbi_pipe_update,
+ DRM_MIPI_DBI_SIMPLE_DISPLAY_PIPE_FUNCS(yx240qv29_enable),
};
static const struct drm_display_mode yx350hv15_mode = {
diff --git a/drivers/gpu/drm/tiny/ili9163.c b/drivers/gpu/drm/tiny/ili9163.c
index ca0451f79962..bc4384d410fc 100644
--- a/drivers/gpu/drm/tiny/ili9163.c
+++ b/drivers/gpu/drm/tiny/ili9163.c
@@ -100,11 +100,7 @@ out_exit:
}
static const struct drm_simple_display_pipe_funcs ili9163_pipe_funcs = {
- .mode_valid = mipi_dbi_pipe_mode_valid,
- .enable = yx240qv29_enable,
- .disable = mipi_dbi_pipe_disable,
- .update = mipi_dbi_pipe_update,
- .prepare_fb = drm_gem_simple_display_pipe_prepare_fb,
+ DRM_MIPI_DBI_SIMPLE_DISPLAY_PIPE_FUNCS(yx240qv29_enable),
};
static const struct drm_display_mode yx240qv29_mode = {
diff --git a/drivers/gpu/drm/tiny/ili9225.c b/drivers/gpu/drm/tiny/ili9225.c
index 815bab285823..077c6ff5a2e1 100644
--- a/drivers/gpu/drm/tiny/ili9225.c
+++ b/drivers/gpu/drm/tiny/ili9225.c
@@ -25,6 +25,7 @@
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_gem_dma_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_managed.h>
#include <drm/drm_mipi_dbi.h>
#include <drm/drm_rect.h>
@@ -76,9 +77,9 @@ static inline int ili9225_command(struct mipi_dbi *dbi, u8 cmd, u16 data)
return mipi_dbi_command_buf(dbi, cmd, par, 2);
}
-static void ili9225_fb_dirty(struct drm_framebuffer *fb, struct drm_rect *rect)
+static void ili9225_fb_dirty(struct iosys_map *src, struct drm_framebuffer *fb,
+ struct drm_rect *rect)
{
- struct drm_gem_dma_object *dma_obj = drm_fb_dma_get_gem_obj(fb, 0);
struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(fb->dev);
unsigned int height = rect->y2 - rect->y1;
unsigned int width = rect->x2 - rect->x1;
@@ -86,13 +87,10 @@ static void ili9225_fb_dirty(struct drm_framebuffer *fb, struct drm_rect *rect)
bool swap = dbi->swap_bytes;
u16 x_start, y_start;
u16 x1, x2, y1, y2;
- int idx, ret = 0;
+ int ret = 0;
bool full;
void *tr;
- if (!drm_dev_enter(fb->dev, &idx))
- return;
-
full = width == fb->width && height == fb->height;
DRM_DEBUG_KMS("Flushing [FB:%d] " DRM_RECT_FMT "\n", fb->base.id, DRM_RECT_ARG(rect));
@@ -100,11 +98,11 @@ static void ili9225_fb_dirty(struct drm_framebuffer *fb, struct drm_rect *rect)
if (!dbi->dc || !full || swap ||
fb->format->format == DRM_FORMAT_XRGB8888) {
tr = dbidev->tx_buf;
- ret = mipi_dbi_buf_copy(dbidev->tx_buf, fb, rect, swap);
+ ret = mipi_dbi_buf_copy(tr, src, fb, rect, swap);
if (ret)
goto err_msg;
} else {
- tr = dma_obj->vaddr;
+ tr = src->vaddr; /* TODO: Use mapping abstraction properly */
}
switch (dbidev->rotation) {
@@ -155,21 +153,27 @@ static void ili9225_fb_dirty(struct drm_framebuffer *fb, struct drm_rect *rect)
err_msg:
if (ret)
dev_err_once(fb->dev->dev, "Failed to update display %d\n", ret);
-
- drm_dev_exit(idx);
}
static void ili9225_pipe_update(struct drm_simple_display_pipe *pipe,
struct drm_plane_state *old_state)
{
struct drm_plane_state *state = pipe->plane.state;
+ struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(state);
+ struct drm_framebuffer *fb = state->fb;
struct drm_rect rect;
+ int idx;
if (!pipe->crtc.state->active)
return;
+ if (!drm_dev_enter(fb->dev, &idx))
+ return;
+
if (drm_atomic_helper_damage_merged(old_state, state, &rect))
- ili9225_fb_dirty(state->fb, &rect);
+ ili9225_fb_dirty(&shadow_plane_state->data[0], fb, &rect);
+
+ drm_dev_exit(idx);
}
static void ili9225_pipe_enable(struct drm_simple_display_pipe *pipe,
@@ -177,6 +181,7 @@ static void ili9225_pipe_enable(struct drm_simple_display_pipe *pipe,
struct drm_plane_state *plane_state)
{
struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev);
+ struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
struct drm_framebuffer *fb = plane_state->fb;
struct device *dev = pipe->crtc.dev->dev;
struct mipi_dbi *dbi = &dbidev->dbi;
@@ -276,7 +281,8 @@ static void ili9225_pipe_enable(struct drm_simple_display_pipe *pipe,
ili9225_command(dbi, ILI9225_DISPLAY_CONTROL_1, 0x1017);
- ili9225_fb_dirty(fb, &rect);
+ ili9225_fb_dirty(&shadow_plane_state->data[0], fb, &rect);
+
out_exit:
drm_dev_exit(idx);
}
@@ -326,9 +332,15 @@ static int ili9225_dbi_command(struct mipi_dbi *dbi, u8 *cmd, u8 *par,
}
static const struct drm_simple_display_pipe_funcs ili9225_pipe_funcs = {
+ .mode_valid = mipi_dbi_pipe_mode_valid,
.enable = ili9225_pipe_enable,
.disable = ili9225_pipe_disable,
.update = ili9225_pipe_update,
+ .begin_fb_access = mipi_dbi_pipe_begin_fb_access,
+ .end_fb_access = mipi_dbi_pipe_end_fb_access,
+ .reset_plane = mipi_dbi_pipe_reset_plane,
+ .duplicate_plane_state = mipi_dbi_pipe_duplicate_plane_state,
+ .destroy_plane_state = mipi_dbi_pipe_destroy_plane_state,
};
static const struct drm_display_mode ili9225_mode = {
diff --git a/drivers/gpu/drm/tiny/ili9341.c b/drivers/gpu/drm/tiny/ili9341.c
index 420f6005a956..47b61c3bf145 100644
--- a/drivers/gpu/drm/tiny/ili9341.c
+++ b/drivers/gpu/drm/tiny/ili9341.c
@@ -137,10 +137,7 @@ out_exit:
}
static const struct drm_simple_display_pipe_funcs ili9341_pipe_funcs = {
- .mode_valid = mipi_dbi_pipe_mode_valid,
- .enable = yx240qv29_enable,
- .disable = mipi_dbi_pipe_disable,
- .update = mipi_dbi_pipe_update,
+ DRM_MIPI_DBI_SIMPLE_DISPLAY_PIPE_FUNCS(yx240qv29_enable),
};
static const struct drm_display_mode yx240qv29_mode = {
diff --git a/drivers/gpu/drm/tiny/ili9486.c b/drivers/gpu/drm/tiny/ili9486.c
index 1bb847466b10..02265c898816 100644
--- a/drivers/gpu/drm/tiny/ili9486.c
+++ b/drivers/gpu/drm/tiny/ili9486.c
@@ -43,6 +43,7 @@ static int waveshare_command(struct mipi_dbi *mipi, u8 *cmd, u8 *par,
size_t num)
{
struct spi_device *spi = mipi->spi;
+ unsigned int bpw = 8;
void *data = par;
u32 speed_hz;
int i, ret;
@@ -56,8 +57,6 @@ static int waveshare_command(struct mipi_dbi *mipi, u8 *cmd, u8 *par,
* The displays are Raspberry Pi HATs and connected to the 8-bit only
* SPI controller, so 16-bit command and parameters need byte swapping
* before being transferred as 8-bit on the big endian SPI bus.
- * Pixel data bytes have already been swapped before this function is
- * called.
*/
buf[0] = cpu_to_be16(*cmd);
gpiod_set_value_cansleep(mipi->dc, 0);
@@ -71,12 +70,18 @@ static int waveshare_command(struct mipi_dbi *mipi, u8 *cmd, u8 *par,
for (i = 0; i < num; i++)
buf[i] = cpu_to_be16(par[i]);
num *= 2;
- speed_hz = mipi_dbi_spi_cmd_max_speed(spi, num);
data = buf;
}
+ /*
+ * Check whether pixel data bytes needs to be swapped or not
+ */
+ if (*cmd == MIPI_DCS_WRITE_MEMORY_START && !mipi->swap_bytes)
+ bpw = 16;
+
gpiod_set_value_cansleep(mipi->dc, 1);
- ret = mipi_dbi_spi_transfer(spi, speed_hz, 8, data, num);
+ speed_hz = mipi_dbi_spi_cmd_max_speed(spi, num);
+ ret = mipi_dbi_spi_transfer(spi, speed_hz, bpw, data, num);
free:
kfree(buf);
@@ -150,10 +155,7 @@ static void waveshare_enable(struct drm_simple_display_pipe *pipe,
}
static const struct drm_simple_display_pipe_funcs waveshare_pipe_funcs = {
- .mode_valid = mipi_dbi_pipe_mode_valid,
- .enable = waveshare_enable,
- .disable = mipi_dbi_pipe_disable,
- .update = mipi_dbi_pipe_update,
+ DRM_MIPI_DBI_SIMPLE_DISPLAY_PIPE_FUNCS(waveshare_enable),
};
static const struct drm_display_mode waveshare_mode = {
@@ -183,6 +185,8 @@ MODULE_DEVICE_TABLE(of, ili9486_of_match);
static const struct spi_device_id ili9486_id[] = {
{ "ili9486", 0 },
+ { "rpi-lcd-35", 0 },
+ { "piscreen", 0 },
{ }
};
MODULE_DEVICE_TABLE(spi, ili9486_id);
diff --git a/drivers/gpu/drm/tiny/mi0283qt.c b/drivers/gpu/drm/tiny/mi0283qt.c
index 47df2b5a3048..01ff43c8ac3f 100644
--- a/drivers/gpu/drm/tiny/mi0283qt.c
+++ b/drivers/gpu/drm/tiny/mi0283qt.c
@@ -141,10 +141,7 @@ out_exit:
}
static const struct drm_simple_display_pipe_funcs mi0283qt_pipe_funcs = {
- .mode_valid = mipi_dbi_pipe_mode_valid,
- .enable = mi0283qt_enable,
- .disable = mipi_dbi_pipe_disable,
- .update = mipi_dbi_pipe_update,
+ DRM_MIPI_DBI_SIMPLE_DISPLAY_PIPE_FUNCS(mi0283qt_enable),
};
static const struct drm_display_mode mi0283qt_mode = {
diff --git a/drivers/gpu/drm/tiny/ofdrm.c b/drivers/gpu/drm/tiny/ofdrm.c
index dc9e4d71b12a..6e349ca42485 100644
--- a/drivers/gpu/drm/tiny/ofdrm.c
+++ b/drivers/gpu/drm/tiny/ofdrm.c
@@ -754,24 +754,6 @@ static void ofdrm_crtc_state_destroy(struct ofdrm_crtc_state *ofdrm_crtc_state)
kfree(ofdrm_crtc_state);
}
-/*
- * Support all formats of OF display and maybe more; in order
- * of preference. The display's update function will do any
- * conversion necessary.
- *
- * TODO: Add blit helpers for remaining formats and uncomment
- * constants.
- */
-static const uint32_t ofdrm_primary_plane_formats[] = {
- DRM_FORMAT_XRGB8888,
- DRM_FORMAT_RGB565,
- //DRM_FORMAT_XRGB1555,
- //DRM_FORMAT_C8,
- /* Big-endian formats below */
- DRM_FORMAT_BGRX8888,
- DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN,
-};
-
static const uint64_t ofdrm_primary_plane_format_modifiers[] = {
DRM_FORMAT_MOD_LINEAR,
DRM_FORMAT_MOD_INVALID
@@ -1284,21 +1266,12 @@ static struct ofdrm_device *ofdrm_device_create(struct drm_driver *drv,
dev->mode_config.min_height = height;
dev->mode_config.max_height = max_height;
dev->mode_config.funcs = &ofdrm_mode_config_funcs;
- switch (depth) {
- case 32:
- dev->mode_config.preferred_depth = 24;
- break;
- default:
- dev->mode_config.preferred_depth = depth;
- break;
- }
+ dev->mode_config.preferred_depth = format->depth;
dev->mode_config.quirk_addfb_prefer_host_byte_order = true;
/* Primary plane */
nformats = drm_fb_build_fourcc_list(dev, &format->format, 1,
- ofdrm_primary_plane_formats,
- ARRAY_SIZE(ofdrm_primary_plane_formats),
odev->formats, ARRAY_SIZE(odev->formats));
primary_plane = &odev->primary_plane;
@@ -1379,6 +1352,7 @@ static int ofdrm_probe(struct platform_device *pdev)
{
struct ofdrm_device *odev;
struct drm_device *dev;
+ unsigned int color_mode;
int ret;
odev = ofdrm_device_create(&ofdrm_driver, pdev);
@@ -1390,11 +1364,11 @@ static int ofdrm_probe(struct platform_device *pdev)
if (ret)
return ret;
- /*
- * FIXME: 24-bit color depth does not work reliably with a 32-bpp
- * value. Force the bpp value of the scanout buffer's format.
- */
- drm_fbdev_generic_setup(dev, drm_format_info_bpp(odev->format, 0));
+ color_mode = drm_format_info_bpp(odev->format, 0);
+ if (color_mode == 16)
+ color_mode = odev->format->depth; // can be 15 or 16
+
+ drm_fbdev_generic_setup(dev, color_mode);
return 0;
}
diff --git a/drivers/gpu/drm/tiny/panel-mipi-dbi.c b/drivers/gpu/drm/tiny/panel-mipi-dbi.c
index 03a7d569cd56..eb9f13f18a02 100644
--- a/drivers/gpu/drm/tiny/panel-mipi-dbi.c
+++ b/drivers/gpu/drm/tiny/panel-mipi-dbi.c
@@ -212,10 +212,7 @@ out_exit:
}
static const struct drm_simple_display_pipe_funcs panel_mipi_dbi_pipe_funcs = {
- .mode_valid = mipi_dbi_pipe_mode_valid,
- .enable = panel_mipi_dbi_enable,
- .disable = mipi_dbi_pipe_disable,
- .update = mipi_dbi_pipe_update,
+ DRM_MIPI_DBI_SIMPLE_DISPLAY_PIPE_FUNCS(panel_mipi_dbi_enable),
};
DEFINE_DRM_GEM_DMA_FOPS(panel_mipi_dbi_fops);
@@ -297,6 +294,11 @@ static int panel_mipi_dbi_spi_probe(struct spi_device *spi)
return dev_err_probe(dev, PTR_ERR(dbidev->regulator),
"Failed to get regulator 'power'\n");
+ dbidev->io_regulator = devm_regulator_get(dev, "io");
+ if (IS_ERR(dbidev->io_regulator))
+ return dev_err_probe(dev, PTR_ERR(dbidev->io_regulator),
+ "Failed to get regulator 'io'\n");
+
dbidev->backlight = devm_of_find_backlight(dev);
if (IS_ERR(dbidev->backlight))
return dev_err_probe(dev, PTR_ERR(dbidev->backlight), "Failed to get backlight\n");
diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c
index 162eb44dcba8..63881a3754f8 100644
--- a/drivers/gpu/drm/tiny/simpledrm.c
+++ b/drivers/gpu/drm/tiny/simpledrm.c
@@ -3,6 +3,7 @@
#include <linux/clk.h>
#include <linux/of_clk.h>
#include <linux/minmax.h>
+#include <linux/of_address.h>
#include <linux/platform_data/simplefb.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
@@ -184,6 +185,31 @@ simplefb_get_format_of(struct drm_device *dev, struct device_node *of_node)
return simplefb_get_validated_format(dev, format);
}
+static struct resource *
+simplefb_get_memory_of(struct drm_device *dev, struct device_node *of_node)
+{
+ struct device_node *np;
+ struct resource *res;
+ int err;
+
+ np = of_parse_phandle(of_node, "memory-region", 0);
+ if (!np)
+ return NULL;
+
+ res = devm_kzalloc(dev->dev, sizeof(*res), GFP_KERNEL);
+ if (!res)
+ return ERR_PTR(-ENOMEM);
+
+ err = of_address_to_resource(np, 0, res);
+ if (err)
+ return ERR_PTR(err);
+
+ if (of_get_property(of_node, "reg", NULL))
+ drm_warn(dev, "preferring \"memory-region\" over \"reg\" property\n");
+
+ return res;
+}
+
/*
* Simple Framebuffer device
*/
@@ -208,7 +234,7 @@ struct simpledrm_device {
unsigned int pitch;
/* memory management */
- void __iomem *screen_base;
+ struct iosys_map screen_base;
/* modesetting */
uint32_t formats[8];
@@ -446,25 +472,6 @@ static int simpledrm_device_init_regulators(struct simpledrm_device *sdev)
* Modesetting
*/
-/*
- * Support all formats of simplefb and maybe more; in order
- * of preference. The display's update function will do any
- * conversion necessary.
- *
- * TODO: Add blit helpers for remaining formats and uncomment
- * constants.
- */
-static const uint32_t simpledrm_primary_plane_formats[] = {
- DRM_FORMAT_XRGB8888,
- DRM_FORMAT_ARGB8888,
- DRM_FORMAT_RGB565,
- //DRM_FORMAT_XRGB1555,
- //DRM_FORMAT_ARGB1555,
- DRM_FORMAT_RGB888,
- DRM_FORMAT_XRGB2101010,
- DRM_FORMAT_ARGB2101010,
-};
-
static const uint64_t simpledrm_primary_plane_format_modifiers[] = {
DRM_FORMAT_MOD_LINEAR,
DRM_FORMAT_MOD_INVALID
@@ -492,15 +499,15 @@ static void simpledrm_primary_plane_helper_atomic_update(struct drm_plane *plane
drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);
drm_atomic_for_each_plane_damage(&iter, &damage) {
- struct iosys_map dst = IOSYS_MAP_INIT_VADDR(sdev->screen_base);
struct drm_rect dst_clip = plane_state->dst;
+ struct iosys_map dst = sdev->screen_base;
if (!drm_rect_intersect(&dst_clip, &damage))
continue;
iosys_map_incr(&dst, drm_fb_clip_offset(sdev->pitch, sdev->format, &dst_clip));
- drm_fb_blit(&dst, &sdev->pitch, sdev->format->format, shadow_plane_state->data, fb,
- &damage);
+ drm_fb_blit(&dst, &sdev->pitch, sdev->format->format, shadow_plane_state->data,
+ fb, &damage);
}
drm_dev_exit(idx);
@@ -519,7 +526,7 @@ static void simpledrm_primary_plane_helper_atomic_disable(struct drm_plane *plan
return;
/* Clear screen to black if disabled */
- memset_io(sdev->screen_base, 0, sdev->pitch * sdev->mode.vdisplay);
+ iosys_map_memset(&sdev->screen_base, 0, 0, sdev->pitch * sdev->mode.vdisplay);
drm_dev_exit(idx);
}
@@ -623,8 +630,7 @@ static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv,
struct drm_device *dev;
int width, height, stride;
const struct drm_format_info *format;
- struct resource *res, *mem;
- void __iomem *screen_base;
+ struct resource *res, *mem = NULL;
struct drm_plane *primary_plane;
struct drm_crtc *crtc;
struct drm_encoder *encoder;
@@ -676,6 +682,9 @@ static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv,
format = simplefb_get_format_of(dev, of_node);
if (IS_ERR(format))
return ERR_CAST(format);
+ mem = simplefb_get_memory_of(dev, of_node);
+ if (IS_ERR(mem))
+ return ERR_CAST(mem);
} else {
drm_err(dev, "no simplefb configuration found\n");
return ERR_PTR(-ENODEV);
@@ -698,31 +707,55 @@ static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv,
* Memory management
*/
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return ERR_PTR(-EINVAL);
+ if (mem) {
+ void *screen_base;
- ret = devm_aperture_acquire_from_firmware(dev, res->start, resource_size(res));
- if (ret) {
- drm_err(dev, "could not acquire memory range %pr: error %d\n", res, ret);
- return ERR_PTR(ret);
- }
+ ret = devm_aperture_acquire_from_firmware(dev, mem->start, resource_size(mem));
+ if (ret) {
+ drm_err(dev, "could not acquire memory range %pr: %d\n", mem, ret);
+ return ERR_PTR(ret);
+ }
- mem = devm_request_mem_region(&pdev->dev, res->start, resource_size(res), drv->name);
- if (!mem) {
- /*
- * We cannot make this fatal. Sometimes this comes from magic
- * spaces our resource handlers simply don't know about. Use
- * the I/O-memory resource as-is and try to map that instead.
- */
- drm_warn(dev, "could not acquire memory region %pr\n", res);
- mem = res;
- }
+ drm_dbg(dev, "using system memory framebuffer at %pr\n", mem);
- screen_base = devm_ioremap_wc(&pdev->dev, mem->start, resource_size(mem));
- if (!screen_base)
- return ERR_PTR(-ENOMEM);
- sdev->screen_base = screen_base;
+ screen_base = devm_memremap(dev->dev, mem->start, resource_size(mem), MEMREMAP_WC);
+ if (IS_ERR(screen_base))
+ return screen_base;
+
+ iosys_map_set_vaddr(&sdev->screen_base, screen_base);
+ } else {
+ void __iomem *screen_base;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return ERR_PTR(-EINVAL);
+
+ ret = devm_aperture_acquire_from_firmware(dev, res->start, resource_size(res));
+ if (ret) {
+ drm_err(dev, "could not acquire memory range %pr: %d\n", &res, ret);
+ return ERR_PTR(ret);
+ }
+
+ drm_dbg(dev, "using I/O memory framebuffer at %pr\n", res);
+
+ mem = devm_request_mem_region(&pdev->dev, res->start, resource_size(res),
+ drv->name);
+ if (!mem) {
+ /*
+ * We cannot make this fatal. Sometimes this comes from magic
+ * spaces our resource handlers simply don't know about. Use
+ * the I/O-memory resource as-is and try to map that instead.
+ */
+ drm_warn(dev, "could not acquire memory region %pr\n", res);
+ mem = res;
+ }
+
+ screen_base = devm_ioremap_wc(&pdev->dev, mem->start, resource_size(mem));
+ if (!screen_base)
+ return ERR_PTR(-ENOMEM);
+
+ iosys_map_set_vaddr_iomem(&sdev->screen_base, screen_base);
+ }
/*
* Modesetting
@@ -739,14 +772,12 @@ static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv,
dev->mode_config.max_width = max_width;
dev->mode_config.min_height = height;
dev->mode_config.max_height = max_height;
- dev->mode_config.preferred_depth = format->cpp[0] * 8;
+ dev->mode_config.preferred_depth = format->depth;
dev->mode_config.funcs = &simpledrm_mode_config_funcs;
/* Primary plane */
nformats = drm_fb_build_fourcc_list(dev, &format->format, 1,
- simpledrm_primary_plane_formats,
- ARRAY_SIZE(simpledrm_primary_plane_formats),
sdev->formats, ARRAY_SIZE(sdev->formats));
primary_plane = &sdev->primary_plane;
@@ -823,6 +854,7 @@ static int simpledrm_probe(struct platform_device *pdev)
{
struct simpledrm_device *sdev;
struct drm_device *dev;
+ unsigned int color_mode;
int ret;
sdev = simpledrm_device_create(&simpledrm_driver, pdev);
@@ -834,7 +866,11 @@ static int simpledrm_probe(struct platform_device *pdev)
if (ret)
return ret;
- drm_fbdev_generic_setup(dev, 0);
+ color_mode = drm_format_info_bpp(sdev->format, 0);
+ if (color_mode == 16)
+ color_mode = sdev->format->depth; // can be 15 or 16
+
+ drm_fbdev_generic_setup(dev, color_mode);
return 0;
}
diff --git a/drivers/gpu/drm/tiny/st7586.c b/drivers/gpu/drm/tiny/st7586.c
index ce57fa9917e5..3cf4eec16a81 100644
--- a/drivers/gpu/drm/tiny/st7586.c
+++ b/drivers/gpu/drm/tiny/st7586.c
@@ -92,32 +92,28 @@ static void st7586_xrgb8888_to_gray332(u8 *dst, void *vaddr,
kfree(buf);
}
-static int st7586_buf_copy(void *dst, struct drm_framebuffer *fb,
+static int st7586_buf_copy(void *dst, struct iosys_map *src, struct drm_framebuffer *fb,
struct drm_rect *clip)
{
- struct drm_gem_dma_object *dma_obj = drm_fb_dma_get_gem_obj(fb, 0);
- void *src = dma_obj->vaddr;
- int ret = 0;
+ int ret;
ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE);
if (ret)
return ret;
- st7586_xrgb8888_to_gray332(dst, src, fb, clip);
+ st7586_xrgb8888_to_gray332(dst, src->vaddr, fb, clip);
drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
return 0;
}
-static void st7586_fb_dirty(struct drm_framebuffer *fb, struct drm_rect *rect)
+static void st7586_fb_dirty(struct iosys_map *src, struct drm_framebuffer *fb,
+ struct drm_rect *rect)
{
struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(fb->dev);
struct mipi_dbi *dbi = &dbidev->dbi;
- int start, end, idx, ret = 0;
-
- if (!drm_dev_enter(fb->dev, &idx))
- return;
+ int start, end, ret = 0;
/* 3 pixels per byte, so grow clip to nearest multiple of 3 */
rect->x1 = rounddown(rect->x1, 3);
@@ -125,7 +121,7 @@ static void st7586_fb_dirty(struct drm_framebuffer *fb, struct drm_rect *rect)
DRM_DEBUG_KMS("Flushing [FB:%d] " DRM_RECT_FMT "\n", fb->base.id, DRM_RECT_ARG(rect));
- ret = st7586_buf_copy(dbidev->tx_buf, fb, rect);
+ ret = st7586_buf_copy(dbidev->tx_buf, src, fb, rect);
if (ret)
goto err_msg;
@@ -146,21 +142,27 @@ static void st7586_fb_dirty(struct drm_framebuffer *fb, struct drm_rect *rect)
err_msg:
if (ret)
dev_err_once(fb->dev->dev, "Failed to update display %d\n", ret);
-
- drm_dev_exit(idx);
}
static void st7586_pipe_update(struct drm_simple_display_pipe *pipe,
struct drm_plane_state *old_state)
{
struct drm_plane_state *state = pipe->plane.state;
+ struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(state);
+ struct drm_framebuffer *fb = state->fb;
struct drm_rect rect;
+ int idx;
if (!pipe->crtc.state->active)
return;
+ if (!drm_dev_enter(fb->dev, &idx))
+ return;
+
if (drm_atomic_helper_damage_merged(old_state, state, &rect))
- st7586_fb_dirty(state->fb, &rect);
+ st7586_fb_dirty(&shadow_plane_state->data[0], fb, &rect);
+
+ drm_dev_exit(idx);
}
static void st7586_pipe_enable(struct drm_simple_display_pipe *pipe,
@@ -168,6 +170,7 @@ static void st7586_pipe_enable(struct drm_simple_display_pipe *pipe,
struct drm_plane_state *plane_state)
{
struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev);
+ struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
struct drm_framebuffer *fb = plane_state->fb;
struct mipi_dbi *dbi = &dbidev->dbi;
struct drm_rect rect = {
@@ -235,7 +238,7 @@ static void st7586_pipe_enable(struct drm_simple_display_pipe *pipe,
msleep(100);
- st7586_fb_dirty(fb, &rect);
+ st7586_fb_dirty(&shadow_plane_state->data[0], fb, &rect);
mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON);
out_exit:
@@ -263,9 +266,15 @@ static const u32 st7586_formats[] = {
};
static const struct drm_simple_display_pipe_funcs st7586_pipe_funcs = {
+ .mode_valid = mipi_dbi_pipe_mode_valid,
.enable = st7586_pipe_enable,
.disable = st7586_pipe_disable,
.update = st7586_pipe_update,
+ .begin_fb_access = mipi_dbi_pipe_begin_fb_access,
+ .end_fb_access = mipi_dbi_pipe_end_fb_access,
+ .reset_plane = mipi_dbi_pipe_reset_plane,
+ .duplicate_plane_state = mipi_dbi_pipe_duplicate_plane_state,
+ .destroy_plane_state = mipi_dbi_pipe_destroy_plane_state,
};
static const struct drm_display_mode st7586_mode = {
diff --git a/drivers/gpu/drm/tiny/st7735r.c b/drivers/gpu/drm/tiny/st7735r.c
index 15d9cf283c66..477eb36fbb70 100644
--- a/drivers/gpu/drm/tiny/st7735r.c
+++ b/drivers/gpu/drm/tiny/st7735r.c
@@ -133,10 +133,7 @@ out_exit:
}
static const struct drm_simple_display_pipe_funcs st7735r_pipe_funcs = {
- .mode_valid = mipi_dbi_pipe_mode_valid,
- .enable = st7735r_pipe_enable,
- .disable = mipi_dbi_pipe_disable,
- .update = mipi_dbi_pipe_update,
+ DRM_MIPI_DBI_SIMPLE_DISPLAY_PIPE_FUNCS(st7735r_pipe_enable),
};
static const struct st7735r_cfg jd_t18003_t01_cfg = {
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index c3f4b33136e5..326a3d13a829 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -31,8 +31,10 @@
#define pr_fmt(fmt) "[TTM] " fmt
-#include <drm/ttm/ttm_bo_driver.h>
+#include <drm/ttm/ttm_bo.h>
#include <drm/ttm/ttm_placement.h>
+#include <drm/ttm/ttm_tt.h>
+
#include <linux/jiffies.h>
#include <linux/slab.h>
#include <linux/sched.h>
@@ -280,14 +282,13 @@ static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo,
ret = 0;
}
- if (ret || unlikely(list_empty(&bo->ddestroy))) {
+ if (ret) {
if (unlock_resv)
dma_resv_unlock(bo->base.resv);
spin_unlock(&bo->bdev->lru_lock);
return ret;
}
- list_del_init(&bo->ddestroy);
spin_unlock(&bo->bdev->lru_lock);
ttm_bo_cleanup_memtype_use(bo);
@@ -300,47 +301,21 @@ static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo,
}
/*
- * Traverse the delayed list, and call ttm_bo_cleanup_refs on all
- * encountered buffers.
+ * Block for the dma_resv object to become idle, lock the buffer and clean up
+ * the resource and tt object.
*/
-bool ttm_bo_delayed_delete(struct ttm_device *bdev, bool remove_all)
+static void ttm_bo_delayed_delete(struct work_struct *work)
{
- struct list_head removed;
- bool empty;
-
- INIT_LIST_HEAD(&removed);
-
- spin_lock(&bdev->lru_lock);
- while (!list_empty(&bdev->ddestroy)) {
- struct ttm_buffer_object *bo;
-
- bo = list_first_entry(&bdev->ddestroy, struct ttm_buffer_object,
- ddestroy);
- list_move_tail(&bo->ddestroy, &removed);
- if (!ttm_bo_get_unless_zero(bo))
- continue;
-
- if (remove_all || bo->base.resv != &bo->base._resv) {
- spin_unlock(&bdev->lru_lock);
- dma_resv_lock(bo->base.resv, NULL);
-
- spin_lock(&bdev->lru_lock);
- ttm_bo_cleanup_refs(bo, false, !remove_all, true);
+ struct ttm_buffer_object *bo;
- } else if (dma_resv_trylock(bo->base.resv)) {
- ttm_bo_cleanup_refs(bo, false, !remove_all, true);
- } else {
- spin_unlock(&bdev->lru_lock);
- }
-
- ttm_bo_put(bo);
- spin_lock(&bdev->lru_lock);
- }
- list_splice_tail(&removed, &bdev->ddestroy);
- empty = list_empty(&bdev->ddestroy);
- spin_unlock(&bdev->lru_lock);
+ bo = container_of(work, typeof(*bo), delayed_delete);
- return empty;
+ dma_resv_wait_timeout(bo->base.resv, DMA_RESV_USAGE_BOOKKEEP, false,
+ MAX_SCHEDULE_TIMEOUT);
+ dma_resv_lock(bo->base.resv, NULL);
+ ttm_bo_cleanup_memtype_use(bo);
+ dma_resv_unlock(bo->base.resv);
+ ttm_bo_put(bo);
}
static void ttm_bo_release(struct kref *kref)
@@ -369,69 +344,58 @@ static void ttm_bo_release(struct kref *kref)
drm_vma_offset_remove(bdev->vma_manager, &bo->base.vma_node);
ttm_mem_io_free(bdev, bo->resource);
- }
- if (!dma_resv_test_signaled(bo->base.resv, DMA_RESV_USAGE_BOOKKEEP) ||
- !dma_resv_trylock(bo->base.resv)) {
- /* The BO is not idle, resurrect it for delayed destroy */
- ttm_bo_flush_all_fences(bo);
- bo->deleted = true;
+ if (!dma_resv_test_signaled(bo->base.resv,
+ DMA_RESV_USAGE_BOOKKEEP) ||
+ !dma_resv_trylock(bo->base.resv)) {
+ /* The BO is not idle, resurrect it for delayed destroy */
+ ttm_bo_flush_all_fences(bo);
+ bo->deleted = true;
- spin_lock(&bo->bdev->lru_lock);
-
- /*
- * Make pinned bos immediately available to
- * shrinkers, now that they are queued for
- * destruction.
- *
- * FIXME: QXL is triggering this. Can be removed when the
- * driver is fixed.
- */
- if (bo->pin_count) {
- bo->pin_count = 0;
- ttm_resource_move_to_lru_tail(bo->resource);
- }
+ spin_lock(&bo->bdev->lru_lock);
- kref_init(&bo->kref);
- list_add_tail(&bo->ddestroy, &bdev->ddestroy);
- spin_unlock(&bo->bdev->lru_lock);
+ /*
+ * Make pinned bos immediately available to
+ * shrinkers, now that they are queued for
+ * destruction.
+ *
+ * FIXME: QXL is triggering this. Can be removed when the
+ * driver is fixed.
+ */
+ if (bo->pin_count) {
+ bo->pin_count = 0;
+ ttm_resource_move_to_lru_tail(bo->resource);
+ }
- schedule_delayed_work(&bdev->wq,
- ((HZ / 100) < 1) ? 1 : HZ / 100);
- return;
- }
+ kref_init(&bo->kref);
+ spin_unlock(&bo->bdev->lru_lock);
- spin_lock(&bo->bdev->lru_lock);
- list_del(&bo->ddestroy);
- spin_unlock(&bo->bdev->lru_lock);
+ INIT_WORK(&bo->delayed_delete, ttm_bo_delayed_delete);
+ queue_work(bdev->wq, &bo->delayed_delete);
+ return;
+ }
- ttm_bo_cleanup_memtype_use(bo);
- dma_resv_unlock(bo->base.resv);
+ ttm_bo_cleanup_memtype_use(bo);
+ dma_resv_unlock(bo->base.resv);
+ }
atomic_dec(&ttm_glob.bo_count);
bo->destroy(bo);
}
+/**
+ * ttm_bo_put
+ *
+ * @bo: The buffer object.
+ *
+ * Unreference a buffer object.
+ */
void ttm_bo_put(struct ttm_buffer_object *bo)
{
kref_put(&bo->kref, ttm_bo_release);
}
EXPORT_SYMBOL(ttm_bo_put);
-int ttm_bo_lock_delayed_workqueue(struct ttm_device *bdev)
-{
- return cancel_delayed_work_sync(&bdev->wq);
-}
-EXPORT_SYMBOL(ttm_bo_lock_delayed_workqueue);
-
-void ttm_bo_unlock_delayed_workqueue(struct ttm_device *bdev, int resched)
-{
- if (resched)
- schedule_delayed_work(&bdev->wq,
- ((HZ / 100) < 1) ? 1 : HZ / 100);
-}
-EXPORT_SYMBOL(ttm_bo_unlock_delayed_workqueue);
-
static int ttm_bo_bounce_temp_buffer(struct ttm_buffer_object *bo,
struct ttm_resource **mem,
struct ttm_operation_ctx *ctx,
@@ -475,7 +439,7 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo,
bdev->funcs->evict_flags(bo, &placement);
if (!placement.num_placement && !placement.num_busy_placement) {
- ret = ttm_bo_wait(bo, true, false);
+ ret = ttm_bo_wait_ctx(bo, ctx);
if (ret)
return ret;
@@ -512,6 +476,14 @@ out:
return ret;
}
+/**
+ * ttm_bo_eviction_valuable
+ *
+ * @bo: The buffer object to evict
+ * @place: the placement we need to make room for
+ *
+ * Check if it is valuable to evict the BO to make room for the given placement.
+ */
bool ttm_bo_eviction_valuable(struct ttm_buffer_object *bo,
const struct ttm_place *place)
{
@@ -771,13 +743,23 @@ static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo,
return ttm_bo_add_move_fence(bo, man, *mem, ctx->no_wait_gpu);
}
-/*
- * Creates space for memory region @mem according to its type.
+/**
+ * ttm_bo_mem_space
*
- * This function first searches for free space in compatible memory types in
- * the priority order defined by the driver. If free space isn't found, then
- * ttm_bo_mem_force_space is attempted in priority order to evict and find
- * space.
+ * @bo: Pointer to a struct ttm_buffer_object. the data of which
+ * we want to allocate space for.
+ * @proposed_placement: Proposed new placement for the buffer object.
+ * @mem: A struct ttm_resource.
+ * @ctx: if and how to sleep, lock buffers and alloc memory
+ *
+ * Allocate memory space for the buffer object pointed to by @bo, using
+ * the placement flags in @placement, potentially evicting other idle buffer objects.
+ * This function may sleep while waiting for space to become available.
+ * Returns:
+ * -EBUSY: No space available (only if no_wait == 1).
+ * -ENOMEM: Could not allocate memory for the buffer object, either due to
+ * fragmentation or concurrent allocators.
+ * -ERESTARTSYS: An interruptible sleep was interrupted by a signal.
*/
int ttm_bo_mem_space(struct ttm_buffer_object *bo,
struct ttm_placement *placement,
@@ -883,6 +865,21 @@ out:
return ret;
}
+/**
+ * ttm_bo_validate
+ *
+ * @bo: The buffer object.
+ * @placement: Proposed placement for the buffer object.
+ * @ctx: validation parameters.
+ *
+ * Changes placement and caching policy of the buffer object
+ * according proposed placement.
+ * Returns
+ * -EINVAL on invalid proposed placement.
+ * -ENOMEM on out-of-memory condition.
+ * -EBUSY if no_wait is true and buffer busy.
+ * -ERESTARTSYS if interrupted by a signal.
+ */
int ttm_bo_validate(struct ttm_buffer_object *bo,
struct ttm_placement *placement,
struct ttm_operation_ctx *ctx)
@@ -960,7 +957,6 @@ int ttm_bo_init_reserved(struct ttm_device *bdev, struct ttm_buffer_object *bo,
int ret;
kref_init(&bo->kref);
- INIT_LIST_HEAD(&bo->ddestroy);
bo->bdev = bdev;
bo->type = type;
bo->page_alignment = alignment;
@@ -1076,6 +1072,11 @@ EXPORT_SYMBOL(ttm_bo_init_validate);
* buffer object vm functions.
*/
+/**
+ * ttm_bo_unmap_virtual
+ *
+ * @bo: tear down the virtual mappings for this BO
+ */
void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo)
{
struct ttm_device *bdev = bo->bdev;
@@ -1085,36 +1086,44 @@ void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo)
}
EXPORT_SYMBOL(ttm_bo_unmap_virtual);
-int ttm_bo_wait(struct ttm_buffer_object *bo,
- bool interruptible, bool no_wait)
+/**
+ * ttm_bo_wait_ctx - wait for buffer idle.
+ *
+ * @bo: The buffer object.
+ * @ctx: defines how to wait
+ *
+ * Waits for the buffer to be idle. Used timeout depends on the context.
+ * Returns -EBUSY if wait timed outt, -ERESTARTSYS if interrupted by a signal or
+ * zero on success.
+ */
+int ttm_bo_wait_ctx(struct ttm_buffer_object *bo, struct ttm_operation_ctx *ctx)
{
- long timeout = 15 * HZ;
+ long ret;
- if (no_wait) {
- if (dma_resv_test_signaled(bo->base.resv, DMA_RESV_USAGE_BOOKKEEP))
+ if (ctx->no_wait_gpu) {
+ if (dma_resv_test_signaled(bo->base.resv,
+ DMA_RESV_USAGE_BOOKKEEP))
return 0;
else
return -EBUSY;
}
- timeout = dma_resv_wait_timeout(bo->base.resv, DMA_RESV_USAGE_BOOKKEEP,
- interruptible, timeout);
- if (timeout < 0)
- return timeout;
-
- if (timeout == 0)
+ ret = dma_resv_wait_timeout(bo->base.resv, DMA_RESV_USAGE_BOOKKEEP,
+ ctx->interruptible, 15 * HZ);
+ if (unlikely(ret < 0))
+ return ret;
+ if (unlikely(ret == 0))
return -EBUSY;
-
return 0;
}
-EXPORT_SYMBOL(ttm_bo_wait);
+EXPORT_SYMBOL(ttm_bo_wait_ctx);
int ttm_bo_swapout(struct ttm_buffer_object *bo, struct ttm_operation_ctx *ctx,
gfp_t gfp_flags)
{
struct ttm_place place;
bool locked;
- int ret;
+ long ret;
/*
* While the bo may already reside in SYSTEM placement, set
@@ -1169,7 +1178,7 @@ int ttm_bo_swapout(struct ttm_buffer_object *bo, struct ttm_operation_ctx *ctx,
/*
* Make sure BO is idle.
*/
- ret = ttm_bo_wait(bo, false, false);
+ ret = ttm_bo_wait_ctx(bo, ctx);
if (unlikely(ret != 0))
goto out;
diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c
index da5493f789df..7635d7d6b13b 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_util.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_util.c
@@ -29,18 +29,13 @@
* Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
*/
-#include <drm/ttm/ttm_bo_driver.h>
+#include <linux/vmalloc.h>
+
+#include <drm/ttm/ttm_bo.h>
#include <drm/ttm/ttm_placement.h>
+#include <drm/ttm/ttm_tt.h>
+
#include <drm/drm_cache.h>
-#include <drm/drm_vma_manager.h>
-#include <linux/iosys-map.h>
-#include <linux/io.h>
-#include <linux/highmem.h>
-#include <linux/wait.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/module.h>
-#include <linux/dma-resv.h>
struct ttm_transfer_obj {
struct ttm_buffer_object base;
@@ -128,6 +123,22 @@ void ttm_move_memcpy(bool clear,
}
EXPORT_SYMBOL(ttm_move_memcpy);
+/**
+ * ttm_bo_move_memcpy
+ *
+ * @bo: A pointer to a struct ttm_buffer_object.
+ * @ctx: operation context
+ * @dst_mem: struct ttm_resource indicating where to move.
+ *
+ * Fallback move function for a mappable buffer object in mappable memory.
+ * The function will, if successful,
+ * free any old aperture space, and set (@new_mem)->mm_node to NULL,
+ * and update the (@bo)->mem placement flags. If unsuccessful, the old
+ * data remains untouched, and it's up to the caller to free the
+ * memory space indicated by @new_mem.
+ * Returns:
+ * !0: Failure.
+ */
int ttm_bo_move_memcpy(struct ttm_buffer_object *bo,
struct ttm_operation_ctx *ctx,
struct ttm_resource *dst_mem)
@@ -230,7 +241,6 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo,
*/
atomic_inc(&ttm_glob.bo_count);
- INIT_LIST_HEAD(&fbo->base.ddestroy);
drm_vma_node_reset(&fbo->base.base.vma_node);
kref_init(&fbo->base.kref);
@@ -267,6 +277,16 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo,
return 0;
}
+/**
+ * ttm_io_prot
+ *
+ * @bo: ttm buffer object
+ * @res: ttm resource object
+ * @tmp: Page protection flag for a normal, cached mapping.
+ *
+ * Utility function that returns the pgprot_t that should be used for
+ * setting up a PTE with the caching model indicated by @c_state.
+ */
pgprot_t ttm_io_prot(struct ttm_buffer_object *bo, struct ttm_resource *res,
pgprot_t tmp)
{
@@ -348,6 +368,22 @@ static int ttm_bo_kmap_ttm(struct ttm_buffer_object *bo,
return (!map->virtual) ? -ENOMEM : 0;
}
+/**
+ * ttm_bo_kmap
+ *
+ * @bo: The buffer object.
+ * @start_page: The first page to map.
+ * @num_pages: Number of pages to map.
+ * @map: pointer to a struct ttm_bo_kmap_obj representing the map.
+ *
+ * Sets up a kernel virtual mapping, using ioremap, vmap or kmap to the
+ * data in the buffer object. The ttm_kmap_obj_virtual function can then be
+ * used to obtain a virtual address to the data.
+ *
+ * Returns
+ * -ENOMEM: Out of memory.
+ * -EINVAL: Invalid range.
+ */
int ttm_bo_kmap(struct ttm_buffer_object *bo,
unsigned long start_page, unsigned long num_pages,
struct ttm_bo_kmap_obj *map)
@@ -375,6 +411,13 @@ int ttm_bo_kmap(struct ttm_buffer_object *bo,
}
EXPORT_SYMBOL(ttm_bo_kmap);
+/**
+ * ttm_bo_kunmap
+ *
+ * @map: Object describing the map to unmap.
+ *
+ * Unmaps a kernel map set up by ttm_bo_kmap.
+ */
void ttm_bo_kunmap(struct ttm_bo_kmap_obj *map)
{
if (!map->virtual)
@@ -400,6 +443,20 @@ void ttm_bo_kunmap(struct ttm_bo_kmap_obj *map)
}
EXPORT_SYMBOL(ttm_bo_kunmap);
+/**
+ * ttm_bo_vmap
+ *
+ * @bo: The buffer object.
+ * @map: pointer to a struct iosys_map representing the map.
+ *
+ * Sets up a kernel virtual mapping, using ioremap or vmap to the
+ * data in the buffer object. The parameter @map returns the virtual
+ * address as struct iosys_map. Unmap the buffer with ttm_bo_vunmap().
+ *
+ * Returns
+ * -ENOMEM: Out of memory.
+ * -EINVAL: Invalid range.
+ */
int ttm_bo_vmap(struct ttm_buffer_object *bo, struct iosys_map *map)
{
struct ttm_resource *mem = bo->resource;
@@ -461,6 +518,14 @@ int ttm_bo_vmap(struct ttm_buffer_object *bo, struct iosys_map *map)
}
EXPORT_SYMBOL(ttm_bo_vmap);
+/**
+ * ttm_bo_vunmap
+ *
+ * @bo: The buffer object.
+ * @map: Object describing the map to unmap.
+ *
+ * Unmaps a kernel map set up by ttm_bo_vmap().
+ */
void ttm_bo_vunmap(struct ttm_buffer_object *bo, struct iosys_map *map)
{
struct ttm_resource *mem = bo->resource;
@@ -483,9 +548,13 @@ EXPORT_SYMBOL(ttm_bo_vunmap);
static int ttm_bo_wait_free_node(struct ttm_buffer_object *bo,
bool dst_use_tt)
{
- int ret;
- ret = ttm_bo_wait(bo, false, false);
- if (ret)
+ long ret;
+
+ ret = dma_resv_wait_timeout(bo->base.resv, DMA_RESV_USAGE_BOOKKEEP,
+ false, 15 * HZ);
+ if (ret == 0)
+ return -EBUSY;
+ if (ret < 0)
return ret;
if (!dst_use_tt)
@@ -554,6 +623,22 @@ static void ttm_bo_move_pipeline_evict(struct ttm_buffer_object *bo,
ttm_resource_free(bo, &bo->resource);
}
+/**
+ * ttm_bo_move_accel_cleanup - cleanup helper for hw copies
+ *
+ * @bo: A pointer to a struct ttm_buffer_object.
+ * @fence: A fence object that signals when moving is complete.
+ * @evict: This is an evict move. Don't return until the buffer is idle.
+ * @pipeline: evictions are to be pipelined.
+ * @new_mem: struct ttm_resource indicating where to move.
+ *
+ * Accelerated move function to be called when an accelerated move
+ * has been scheduled. The function will create a new temporary buffer object
+ * representing the old placement, and put the sync object on both buffer
+ * objects. After that the newly created buffer object is unref'd to be
+ * destroyed when the move is complete. This will help pipeline
+ * buffer moves.
+ */
int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo,
struct dma_fence *fence,
bool evict,
@@ -582,6 +667,15 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo,
}
EXPORT_SYMBOL(ttm_bo_move_accel_cleanup);
+/**
+ * ttm_bo_move_sync_cleanup - cleanup by waiting for the move to finish
+ *
+ * @bo: A pointer to a struct ttm_buffer_object.
+ * @new_mem: struct ttm_resource indicating where to move.
+ *
+ * Special case of ttm_bo_move_accel_cleanup where the bo is guaranteed
+ * by the caller to be idle. Typically used after memcpy buffer moves.
+ */
void ttm_bo_move_sync_cleanup(struct ttm_buffer_object *bo,
struct ttm_resource *new_mem)
{
@@ -621,8 +715,7 @@ int ttm_bo_pipeline_gutting(struct ttm_buffer_object *bo)
return ret;
/* If already idle, no need for ghost object dance. */
- ret = ttm_bo_wait(bo, false, true);
- if (ret != -EBUSY) {
+ if (dma_resv_test_signaled(bo->base.resv, DMA_RESV_USAGE_BOOKKEEP)) {
if (!bo->ttm) {
/* See comment below about clearing. */
ret = ttm_tt_create(bo, true);
@@ -659,8 +752,10 @@ int ttm_bo_pipeline_gutting(struct ttm_buffer_object *bo)
ret = dma_resv_copy_fences(&ghost->base._resv, bo->base.resv);
/* Last resort, wait for the BO to be idle when we are OOM */
- if (ret)
- ttm_bo_wait(bo, false, false);
+ if (ret) {
+ dma_resv_wait_timeout(bo->base.resv, DMA_RESV_USAGE_BOOKKEEP,
+ false, MAX_SCHEDULE_TIMEOUT);
+ }
dma_resv_unlock(&ghost->base._resv);
ttm_bo_put(ghost);
diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c
index 5a3e4b891377..ca7744b852f5 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_vm.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c
@@ -31,17 +31,12 @@
#define pr_fmt(fmt) "[TTM] " fmt
-#include <drm/ttm/ttm_bo_driver.h>
+#include <drm/ttm/ttm_bo.h>
#include <drm/ttm/ttm_placement.h>
-#include <drm/drm_vma_manager.h>
+#include <drm/ttm/ttm_tt.h>
+
#include <drm/drm_drv.h>
#include <drm/drm_managed.h>
-#include <linux/mm.h>
-#include <linux/pfn_t.h>
-#include <linux/rbtree.h>
-#include <linux/module.h>
-#include <linux/uaccess.h>
-#include <linux/mem_encrypt.h>
static vm_fault_t ttm_bo_vm_fault_idle(struct ttm_buffer_object *bo,
struct vm_fault *vmf)
@@ -446,6 +441,14 @@ static const struct vm_operations_struct ttm_bo_vm_ops = {
.access = ttm_bo_vm_access,
};
+/**
+ * ttm_bo_mmap_obj - mmap memory backed by a ttm buffer object.
+ *
+ * @vma: vma as input from the fbdev mmap method.
+ * @bo: The bo backing the address space.
+ *
+ * Maps a buffer object.
+ */
int ttm_bo_mmap_obj(struct vm_area_struct *vma, struct ttm_buffer_object *bo)
{
/* Enforce no COW since would have really strange behavior with it. */
@@ -468,8 +471,7 @@ int ttm_bo_mmap_obj(struct vm_area_struct *vma, struct ttm_buffer_object *bo)
vma->vm_private_data = bo;
- vma->vm_flags |= VM_PFNMAP;
- vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
+ vm_flags_set(vma, VM_PFNMAP | VM_IO | VM_DONTEXPAND | VM_DONTDUMP);
return 0;
}
EXPORT_SYMBOL(ttm_bo_mmap_obj);
diff --git a/drivers/gpu/drm/ttm/ttm_device.c b/drivers/gpu/drm/ttm/ttm_device.c
index e7147e304637..c7a1862f322a 100644
--- a/drivers/gpu/drm/ttm/ttm_device.c
+++ b/drivers/gpu/drm/ttm/ttm_device.c
@@ -29,10 +29,10 @@
#include <linux/mm.h>
+#include <drm/ttm/ttm_bo.h>
#include <drm/ttm/ttm_device.h>
#include <drm/ttm/ttm_tt.h>
#include <drm/ttm/ttm_placement.h>
-#include <drm/ttm/ttm_bo_api.h>
#include "ttm_module.h"
@@ -175,16 +175,6 @@ int ttm_device_swapout(struct ttm_device *bdev, struct ttm_operation_ctx *ctx,
}
EXPORT_SYMBOL(ttm_device_swapout);
-static void ttm_device_delayed_workqueue(struct work_struct *work)
-{
- struct ttm_device *bdev =
- container_of(work, struct ttm_device, wq.work);
-
- if (!ttm_bo_delayed_delete(bdev, false))
- schedule_delayed_work(&bdev->wq,
- ((HZ / 100) < 1) ? 1 : HZ / 100);
-}
-
/**
* ttm_device_init
*
@@ -215,15 +205,19 @@ int ttm_device_init(struct ttm_device *bdev, struct ttm_device_funcs *funcs,
if (ret)
return ret;
+ bdev->wq = alloc_workqueue("ttm", WQ_MEM_RECLAIM | WQ_HIGHPRI, 16);
+ if (!bdev->wq) {
+ ttm_global_release();
+ return -ENOMEM;
+ }
+
bdev->funcs = funcs;
ttm_sys_man_init(bdev);
ttm_pool_init(&bdev->pool, dev, use_dma_alloc, use_dma32);
bdev->vma_manager = vma_manager;
- INIT_DELAYED_WORK(&bdev->wq, ttm_device_delayed_workqueue);
spin_lock_init(&bdev->lru_lock);
- INIT_LIST_HEAD(&bdev->ddestroy);
INIT_LIST_HEAD(&bdev->pinned);
bdev->dev_mapping = mapping;
mutex_lock(&ttm_global_mutex);
@@ -247,10 +241,8 @@ void ttm_device_fini(struct ttm_device *bdev)
list_del(&bdev->device_list);
mutex_unlock(&ttm_global_mutex);
- cancel_delayed_work_sync(&bdev->wq);
-
- if (ttm_bo_delayed_delete(bdev, true))
- pr_debug("Delayed destroy list was clean\n");
+ drain_workqueue(bdev->wq);
+ destroy_workqueue(bdev->wq);
spin_lock(&bdev->lru_lock);
for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i)
diff --git a/drivers/gpu/drm/ttm/ttm_execbuf_util.c b/drivers/gpu/drm/ttm/ttm_execbuf_util.c
index dbee34a058df..f1c60fa80c2d 100644
--- a/drivers/gpu/drm/ttm/ttm_execbuf_util.c
+++ b/drivers/gpu/drm/ttm/ttm_execbuf_util.c
@@ -27,11 +27,7 @@
**************************************************************************/
#include <drm/ttm/ttm_execbuf_util.h>
-#include <drm/ttm/ttm_bo_driver.h>
-#include <drm/ttm/ttm_placement.h>
-#include <linux/wait.h>
-#include <linux/sched.h>
-#include <linux/module.h>
+#include <drm/ttm/ttm_bo.h>
static void ttm_eu_backoff_reservation_reverse(struct list_head *list,
struct ttm_validate_buffer *entry)
diff --git a/drivers/gpu/drm/ttm/ttm_pool.c b/drivers/gpu/drm/ttm/ttm_pool.c
index 9f6764bf3b15..aa116a7bbae3 100644
--- a/drivers/gpu/drm/ttm/ttm_pool.c
+++ b/drivers/gpu/drm/ttm/ttm_pool.c
@@ -33,6 +33,7 @@
#include <linux/module.h>
#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
#include <linux/highmem.h>
#include <linux/sched/mm.h>
@@ -41,8 +42,8 @@
#endif
#include <drm/ttm/ttm_pool.h>
-#include <drm/ttm/ttm_bo_driver.h>
#include <drm/ttm/ttm_tt.h>
+#include <drm/ttm/ttm_bo.h>
#include "ttm_module.h"
diff --git a/drivers/gpu/drm/ttm/ttm_range_manager.c b/drivers/gpu/drm/ttm/ttm_range_manager.c
index 0a8bc0b7f380..ae11d07eb63a 100644
--- a/drivers/gpu/drm/ttm/ttm_range_manager.c
+++ b/drivers/gpu/drm/ttm/ttm_range_manager.c
@@ -32,7 +32,7 @@
#include <drm/ttm/ttm_device.h>
#include <drm/ttm/ttm_placement.h>
#include <drm/ttm/ttm_range_manager.h>
-#include <drm/ttm/ttm_bo_api.h>
+#include <drm/ttm/ttm_bo.h>
#include <drm/drm_mm.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
diff --git a/drivers/gpu/drm/ttm/ttm_resource.c b/drivers/gpu/drm/ttm/ttm_resource.c
index 328391bb1d87..b8a826a24fb2 100644
--- a/drivers/gpu/drm/ttm/ttm_resource.c
+++ b/drivers/gpu/drm/ttm/ttm_resource.c
@@ -26,8 +26,9 @@
#include <linux/io-mapping.h>
#include <linux/scatterlist.h>
+#include <drm/ttm/ttm_bo.h>
+#include <drm/ttm/ttm_placement.h>
#include <drm/ttm/ttm_resource.h>
-#include <drm/ttm/ttm_bo_driver.h>
/**
* ttm_lru_bulk_move_init - initialize a bulk move structure
diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c
index d505603930a7..ab725d9d14a6 100644
--- a/drivers/gpu/drm/ttm/ttm_tt.c
+++ b/drivers/gpu/drm/ttm/ttm_tt.c
@@ -36,7 +36,8 @@
#include <linux/file.h>
#include <linux/module.h>
#include <drm/drm_cache.h>
-#include <drm/ttm/ttm_bo_driver.h>
+#include <drm/ttm/ttm_bo.h>
+#include <drm/ttm/ttm_tt.h>
#include "ttm_module.h"
diff --git a/drivers/gpu/drm/udl/udl_drv.c b/drivers/gpu/drm/udl/udl_drv.c
index e81352126a0f..1506094a8009 100644
--- a/drivers/gpu/drm/udl/udl_drv.c
+++ b/drivers/gpu/drm/udl/udl_drv.c
@@ -5,12 +5,12 @@
#include <linux/module.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_fbdev_generic.h>
#include <drm/drm_file.h>
#include <drm/drm_gem_shmem_helper.h>
#include <drm/drm_managed.h>
+#include <drm/drm_modeset_helper.h>
#include <drm/drm_ioctl.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_print.h>
diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c
index 4b79d44752c9..aa02fd2789c3 100644
--- a/drivers/gpu/drm/udl/udl_modeset.c
+++ b/drivers/gpu/drm/udl/udl_modeset.c
@@ -12,7 +12,6 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_damage_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_edid.h>
diff --git a/drivers/gpu/drm/v3d/v3d_debugfs.c b/drivers/gpu/drm/v3d/v3d_debugfs.c
index efbde124c296..330669f51fa7 100644
--- a/drivers/gpu/drm/v3d/v3d_debugfs.c
+++ b/drivers/gpu/drm/v3d/v3d_debugfs.c
@@ -79,8 +79,8 @@ static const struct v3d_reg_def v3d_csd_reg_defs[] = {
static int v3d_v3d_debugfs_regs(struct seq_file *m, void *unused)
{
- struct drm_info_node *node = (struct drm_info_node *)m->private;
- struct drm_device *dev = node->minor->dev;
+ struct drm_debugfs_entry *entry = m->private;
+ struct drm_device *dev = entry->dev;
struct v3d_dev *v3d = to_v3d_dev(dev);
int i, core;
@@ -126,8 +126,8 @@ static int v3d_v3d_debugfs_regs(struct seq_file *m, void *unused)
static int v3d_v3d_debugfs_ident(struct seq_file *m, void *unused)
{
- struct drm_info_node *node = (struct drm_info_node *)m->private;
- struct drm_device *dev = node->minor->dev;
+ struct drm_debugfs_entry *entry = m->private;
+ struct drm_device *dev = entry->dev;
struct v3d_dev *v3d = to_v3d_dev(dev);
u32 ident0, ident1, ident2, ident3, cores;
int core;
@@ -188,8 +188,8 @@ static int v3d_v3d_debugfs_ident(struct seq_file *m, void *unused)
static int v3d_debugfs_bo_stats(struct seq_file *m, void *unused)
{
- struct drm_info_node *node = (struct drm_info_node *)m->private;
- struct drm_device *dev = node->minor->dev;
+ struct drm_debugfs_entry *entry = m->private;
+ struct drm_device *dev = entry->dev;
struct v3d_dev *v3d = to_v3d_dev(dev);
mutex_lock(&v3d->bo_lock);
@@ -204,8 +204,8 @@ static int v3d_debugfs_bo_stats(struct seq_file *m, void *unused)
static int v3d_measure_clock(struct seq_file *m, void *unused)
{
- struct drm_info_node *node = (struct drm_info_node *)m->private;
- struct drm_device *dev = node->minor->dev;
+ struct drm_debugfs_entry *entry = m->private;
+ struct drm_device *dev = entry->dev;
struct v3d_dev *v3d = to_v3d_dev(dev);
uint32_t cycles;
int core = 0;
@@ -236,7 +236,7 @@ static int v3d_measure_clock(struct seq_file *m, void *unused)
return 0;
}
-static const struct drm_info_list v3d_debugfs_list[] = {
+static const struct drm_debugfs_info v3d_debugfs_list[] = {
{"v3d_ident", v3d_v3d_debugfs_ident, 0},
{"v3d_regs", v3d_v3d_debugfs_regs, 0},
{"measure_clock", v3d_measure_clock, 0},
@@ -246,7 +246,5 @@ static const struct drm_info_list v3d_debugfs_list[] = {
void
v3d_debugfs_init(struct drm_minor *minor)
{
- drm_debugfs_create_files(v3d_debugfs_list,
- ARRAY_SIZE(v3d_debugfs_list),
- minor->debugfs_root, minor);
+ drm_debugfs_add_files(minor->dev, v3d_debugfs_list, ARRAY_SIZE(v3d_debugfs_list));
}
diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c
index 96af1cb5202a..5da1806f3969 100644
--- a/drivers/gpu/drm/v3d/v3d_gem.c
+++ b/drivers/gpu/drm/v3d/v3d_gem.c
@@ -299,10 +299,6 @@ v3d_lookup_bos(struct drm_device *dev,
u64 bo_handles,
u32 bo_count)
{
- u32 *handles;
- int ret = 0;
- int i;
-
job->bo_count = bo_count;
if (!job->bo_count) {
@@ -313,48 +309,9 @@ v3d_lookup_bos(struct drm_device *dev,
return -EINVAL;
}
- job->bo = kvmalloc_array(job->bo_count,
- sizeof(struct drm_gem_dma_object *),
- GFP_KERNEL | __GFP_ZERO);
- if (!job->bo) {
- DRM_DEBUG("Failed to allocate validated BO pointers\n");
- return -ENOMEM;
- }
-
- handles = kvmalloc_array(job->bo_count, sizeof(u32), GFP_KERNEL);
- if (!handles) {
- ret = -ENOMEM;
- DRM_DEBUG("Failed to allocate incoming GEM handles\n");
- goto fail;
- }
-
- if (copy_from_user(handles,
- (void __user *)(uintptr_t)bo_handles,
- job->bo_count * sizeof(u32))) {
- ret = -EFAULT;
- DRM_DEBUG("Failed to copy in GEM handles\n");
- goto fail;
- }
-
- spin_lock(&file_priv->table_lock);
- for (i = 0; i < job->bo_count; i++) {
- struct drm_gem_object *bo = idr_find(&file_priv->object_idr,
- handles[i]);
- if (!bo) {
- DRM_DEBUG("Failed to look up GEM BO %d: %d\n",
- i, handles[i]);
- ret = -ENOENT;
- spin_unlock(&file_priv->table_lock);
- goto fail;
- }
- drm_gem_object_get(bo);
- job->bo[i] = bo;
- }
- spin_unlock(&file_priv->table_lock);
-
-fail:
- kvfree(handles);
- return ret;
+ return drm_gem_objects_lookup(file_priv,
+ (void __user *)(uintptr_t)bo_handles,
+ job->bo_count, &job->bo);
}
static void
@@ -363,11 +320,11 @@ v3d_job_free(struct kref *ref)
struct v3d_job *job = container_of(ref, struct v3d_job, refcount);
int i;
- for (i = 0; i < job->bo_count; i++) {
- if (job->bo[i])
+ if (job->bo) {
+ for (i = 0; i < job->bo_count; i++)
drm_gem_object_put(job->bo[i]);
+ kvfree(job->bo);
}
- kvfree(job->bo);
dma_fence_put(job->irq_fence);
dma_fence_put(job->done_fence);
@@ -904,7 +861,6 @@ v3d_submit_tfu_ioctl(struct drm_device *dev, void *data,
job->args = *args;
- spin_lock(&file_priv->table_lock);
for (job->base.bo_count = 0;
job->base.bo_count < ARRAY_SIZE(args->bo_handles);
job->base.bo_count++) {
@@ -913,20 +869,16 @@ v3d_submit_tfu_ioctl(struct drm_device *dev, void *data,
if (!args->bo_handles[job->base.bo_count])
break;
- bo = idr_find(&file_priv->object_idr,
- args->bo_handles[job->base.bo_count]);
+ bo = drm_gem_object_lookup(file_priv, args->bo_handles[job->base.bo_count]);
if (!bo) {
DRM_DEBUG("Failed to look up GEM BO %d: %d\n",
job->base.bo_count,
args->bo_handles[job->base.bo_count]);
ret = -ENOENT;
- spin_unlock(&file_priv->table_lock);
goto fail;
}
- drm_gem_object_get(bo);
job->base.bo[job->base.bo_count] = bo;
}
- spin_unlock(&file_priv->table_lock);
ret = v3d_lock_bo_reservations(&job->base, &acquire_ctx);
if (ret)
diff --git a/drivers/gpu/drm/vboxvideo/vbox_drv.c b/drivers/gpu/drm/vboxvideo/vbox_drv.c
index b450f449a3ab..4fee15c97c34 100644
--- a/drivers/gpu/drm/vboxvideo/vbox_drv.c
+++ b/drivers/gpu/drm/vboxvideo/vbox_drv.c
@@ -12,12 +12,12 @@
#include <linux/vt_kern.h>
#include <drm/drm_aperture.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_fbdev_generic.h>
#include <drm/drm_file.h>
#include <drm/drm_ioctl.h>
#include <drm/drm_managed.h>
+#include <drm/drm_modeset_helper.h>
#include <drm/drm_module.h>
#include "vbox_drv.h"
@@ -102,7 +102,6 @@ static void vbox_pci_remove(struct pci_dev *pdev)
vbox_hw_fini(vbox);
}
-#ifdef CONFIG_PM_SLEEP
static int vbox_pm_suspend(struct device *dev)
{
struct vbox_private *vbox = dev_get_drvdata(dev);
@@ -160,16 +159,13 @@ static const struct dev_pm_ops vbox_pm_ops = {
.poweroff = vbox_pm_poweroff,
.restore = vbox_pm_resume,
};
-#endif
static struct pci_driver vbox_pci_driver = {
.name = DRIVER_NAME,
.id_table = pciidlist,
.probe = vbox_pci_probe,
.remove = vbox_pci_remove,
-#ifdef CONFIG_PM_SLEEP
- .driver.pm = &vbox_pm_ops,
-#endif
+ .driver.pm = pm_sleep_ptr(&vbox_pm_ops),
};
DEFINE_DRM_GEM_FOPS(vbox_fops);
diff --git a/drivers/gpu/drm/vboxvideo/vbox_main.c b/drivers/gpu/drm/vboxvideo/vbox_main.c
index 3b83e550f4df..42c2d8a99509 100644
--- a/drivers/gpu/drm/vboxvideo/vbox_main.c
+++ b/drivers/gpu/drm/vboxvideo/vbox_main.c
@@ -11,7 +11,6 @@
#include <linux/pci.h>
#include <linux/vbox_err.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_damage_helper.h>
#include "vbox_drv.h"
diff --git a/drivers/gpu/drm/vc4/Kconfig b/drivers/gpu/drm/vc4/Kconfig
index 246305d17a52..91dcf8d174d6 100644
--- a/drivers/gpu/drm/vc4/Kconfig
+++ b/drivers/gpu/drm/vc4/Kconfig
@@ -34,3 +34,19 @@ config DRM_VC4_HDMI_CEC
help
Choose this option if you have a Broadcom VC4 GPU
and want to use CEC.
+
+config DRM_VC4_KUNIT_TEST
+ tristate "KUnit tests for VC4" if !KUNIT_ALL_TESTS
+ depends on DRM_VC4 && KUNIT
+ select DRM_KUNIT_TEST_HELPERS
+ default KUNIT_ALL_TESTS
+ help
+ This builds unit tests for the VC4 DRM/KMS driver. This option is
+ not useful for distributions or general kernels, but only for kernel
+ developers working on the VC4 driver.
+
+ For more information on KUnit and unit tests in general,
+ please refer to the KUnit documentation in
+ Documentation/dev-tools/kunit/.
+
+ If in doubt, say "N".
diff --git a/drivers/gpu/drm/vc4/Makefile b/drivers/gpu/drm/vc4/Makefile
index d0163e18e9ca..c41f89a15a55 100644
--- a/drivers/gpu/drm/vc4/Makefile
+++ b/drivers/gpu/drm/vc4/Makefile
@@ -25,6 +25,13 @@ vc4-y := \
vc4_validate.o \
vc4_validate_shaders.o
+vc4-$(CONFIG_DRM_VC4_KUNIT_TEST) += \
+ tests/vc4_mock.o \
+ tests/vc4_mock_crtc.o \
+ tests/vc4_mock_output.o \
+ tests/vc4_mock_plane.o \
+ tests/vc4_test_pv_muxing.o
+
vc4-$(CONFIG_DEBUG_FS) += vc4_debugfs.o
obj-$(CONFIG_DRM_VC4) += vc4.o
diff --git a/drivers/gpu/drm/vc4/tests/.kunitconfig b/drivers/gpu/drm/vc4/tests/.kunitconfig
new file mode 100644
index 000000000000..b503e9036c7f
--- /dev/null
+++ b/drivers/gpu/drm/vc4/tests/.kunitconfig
@@ -0,0 +1,13 @@
+CONFIG_ARCH_BCM=y
+CONFIG_ARCH_BCM2835=y
+CONFIG_BCM2835_MBOX=y
+CONFIG_KUNIT=y
+CONFIG_DRM=y
+CONFIG_DRM_VC4=y
+CONFIG_DRM_VC4_KUNIT_TEST=y
+CONFIG_MAILBOX=y
+CONFIG_RASPBERRYPI_FIRMWARE=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_SOUND=y
+CONFIG_COMMON_CLK=y
diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock.c b/drivers/gpu/drm/vc4/tests/vc4_mock.c
new file mode 100644
index 000000000000..a4bed26af32f
--- /dev/null
+++ b/drivers/gpu/drm/vc4/tests/vc4_mock.c
@@ -0,0 +1,200 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <drm/drm_drv.h>
+#include <drm/drm_kunit_helpers.h>
+
+#include <kunit/test.h>
+
+#include "vc4_mock.h"
+
+struct vc4_mock_output_desc {
+ enum vc4_encoder_type vc4_encoder_type;
+ unsigned int encoder_type;
+ unsigned int connector_type;
+};
+
+#define VC4_MOCK_OUTPUT_DESC(_vc4_type, _etype, _ctype) \
+ { \
+ .vc4_encoder_type = _vc4_type, \
+ .encoder_type = _etype, \
+ .connector_type = _ctype, \
+ }
+
+struct vc4_mock_pipe_desc {
+ const struct vc4_crtc_data *data;
+ const struct vc4_mock_output_desc *outputs;
+ unsigned int noutputs;
+};
+
+#define VC4_MOCK_CRTC_DESC(_data, ...) \
+ { \
+ .data = _data, \
+ .outputs = (struct vc4_mock_output_desc[]) { __VA_ARGS__ }, \
+ .noutputs = sizeof((struct vc4_mock_output_desc[]) { __VA_ARGS__ }) / \
+ sizeof(struct vc4_mock_output_desc), \
+ }
+
+#define VC4_MOCK_PIXELVALVE_DESC(_data, ...) \
+ VC4_MOCK_CRTC_DESC(&(_data)->base, __VA_ARGS__)
+
+struct vc4_mock_desc {
+ const struct vc4_mock_pipe_desc *pipes;
+ unsigned int npipes;
+};
+
+#define VC4_MOCK_DESC(...) \
+ { \
+ .pipes = (struct vc4_mock_pipe_desc[]) { __VA_ARGS__ }, \
+ .npipes = sizeof((struct vc4_mock_pipe_desc[]) { __VA_ARGS__ }) / \
+ sizeof(struct vc4_mock_pipe_desc), \
+ }
+
+static const struct vc4_mock_desc vc4_mock =
+ VC4_MOCK_DESC(
+ VC4_MOCK_CRTC_DESC(&vc4_txp_crtc_data,
+ VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_TXP,
+ DRM_MODE_ENCODER_VIRTUAL,
+ DRM_MODE_CONNECTOR_WRITEBACK)),
+ VC4_MOCK_PIXELVALVE_DESC(&bcm2835_pv0_data,
+ VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_DSI0,
+ DRM_MODE_ENCODER_DSI,
+ DRM_MODE_CONNECTOR_DSI),
+ VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_DPI,
+ DRM_MODE_ENCODER_DPI,
+ DRM_MODE_CONNECTOR_DPI)),
+ VC4_MOCK_PIXELVALVE_DESC(&bcm2835_pv1_data,
+ VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_DSI1,
+ DRM_MODE_ENCODER_DSI,
+ DRM_MODE_CONNECTOR_DSI)),
+ VC4_MOCK_PIXELVALVE_DESC(&bcm2835_pv2_data,
+ VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_HDMI0,
+ DRM_MODE_ENCODER_TMDS,
+ DRM_MODE_CONNECTOR_HDMIA),
+ VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_VEC,
+ DRM_MODE_ENCODER_TVDAC,
+ DRM_MODE_CONNECTOR_Composite)),
+);
+
+static const struct vc4_mock_desc vc5_mock =
+ VC4_MOCK_DESC(
+ VC4_MOCK_CRTC_DESC(&vc4_txp_crtc_data,
+ VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_TXP,
+ DRM_MODE_ENCODER_VIRTUAL,
+ DRM_MODE_CONNECTOR_WRITEBACK)),
+ VC4_MOCK_PIXELVALVE_DESC(&bcm2711_pv0_data,
+ VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_DSI0,
+ DRM_MODE_ENCODER_DSI,
+ DRM_MODE_CONNECTOR_DSI),
+ VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_DPI,
+ DRM_MODE_ENCODER_DPI,
+ DRM_MODE_CONNECTOR_DPI)),
+ VC4_MOCK_PIXELVALVE_DESC(&bcm2711_pv1_data,
+ VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_DSI1,
+ DRM_MODE_ENCODER_DSI,
+ DRM_MODE_CONNECTOR_DSI)),
+ VC4_MOCK_PIXELVALVE_DESC(&bcm2711_pv2_data,
+ VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_HDMI0,
+ DRM_MODE_ENCODER_TMDS,
+ DRM_MODE_CONNECTOR_HDMIA)),
+ VC4_MOCK_PIXELVALVE_DESC(&bcm2711_pv3_data,
+ VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_VEC,
+ DRM_MODE_ENCODER_TVDAC,
+ DRM_MODE_CONNECTOR_Composite)),
+ VC4_MOCK_PIXELVALVE_DESC(&bcm2711_pv4_data,
+ VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_HDMI1,
+ DRM_MODE_ENCODER_TMDS,
+ DRM_MODE_CONNECTOR_HDMIA)),
+);
+
+static int __build_one_pipe(struct kunit *test, struct drm_device *drm,
+ const struct vc4_mock_pipe_desc *pipe)
+{
+ struct vc4_dummy_plane *dummy_plane;
+ struct drm_plane *plane;
+ struct vc4_dummy_crtc *dummy_crtc;
+ struct drm_crtc *crtc;
+ unsigned int i;
+
+ dummy_plane = vc4_dummy_plane(test, drm, DRM_PLANE_TYPE_PRIMARY);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_plane);
+
+ plane = &dummy_plane->plane.base;
+ dummy_crtc = vc4_mock_pv(test, drm, plane, pipe->data);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_crtc);
+
+ crtc = &dummy_crtc->crtc.base;
+ for (i = 0; i < pipe->noutputs; i++) {
+ const struct vc4_mock_output_desc *mock_output = &pipe->outputs[i];
+ struct vc4_dummy_output *dummy_output;
+
+ dummy_output = vc4_dummy_output(test, drm, crtc,
+ mock_output->vc4_encoder_type,
+ mock_output->encoder_type,
+ mock_output->connector_type);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_output);
+ }
+
+ return 0;
+}
+
+static int __build_mock(struct kunit *test, struct drm_device *drm,
+ const struct vc4_mock_desc *mock)
+{
+ unsigned int i;
+
+ for (i = 0; i < mock->npipes; i++) {
+ const struct vc4_mock_pipe_desc *pipe = &mock->pipes[i];
+ int ret;
+
+ ret = __build_one_pipe(test, drm, pipe);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+ }
+
+ return 0;
+}
+
+static struct vc4_dev *__mock_device(struct kunit *test, bool is_vc5)
+{
+ struct drm_device *drm;
+ const struct drm_driver *drv = is_vc5 ? &vc5_drm_driver : &vc4_drm_driver;
+ const struct vc4_mock_desc *desc = is_vc5 ? &vc5_mock : &vc4_mock;
+ struct vc4_dev *vc4;
+ struct device *dev;
+ int ret;
+
+ dev = drm_kunit_helper_alloc_device(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
+
+ vc4 = drm_kunit_helper_alloc_drm_device_with_driver(test, dev,
+ struct vc4_dev, base,
+ drv);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4);
+
+ vc4->dev = dev;
+ vc4->is_vc5 = is_vc5;
+
+ vc4->hvs = __vc4_hvs_alloc(vc4, NULL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4->hvs);
+
+ drm = &vc4->base;
+ ret = __build_mock(test, drm, desc);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ ret = vc4_kms_load(drm);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ ret = drm_dev_register(drm, 0);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ return vc4;
+}
+
+struct vc4_dev *vc4_mock_device(struct kunit *test)
+{
+ return __mock_device(test, false);
+}
+
+struct vc4_dev *vc5_mock_device(struct kunit *test)
+{
+ return __mock_device(test, true);
+}
diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock.h b/drivers/gpu/drm/vc4/tests/vc4_mock.h
new file mode 100644
index 000000000000..db8e9a141ef8
--- /dev/null
+++ b/drivers/gpu/drm/vc4/tests/vc4_mock.h
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef VC4_MOCK_H_
+#define VC4_MOCK_H_
+
+#include "../vc4_drv.h"
+
+static inline
+struct drm_crtc *vc4_find_crtc_for_encoder(struct kunit *test,
+ struct drm_device *drm,
+ struct drm_encoder *encoder)
+{
+ struct drm_crtc *crtc;
+
+ KUNIT_ASSERT_EQ(test, hweight32(encoder->possible_crtcs), 1);
+
+ drm_for_each_crtc(crtc, drm)
+ if (encoder->possible_crtcs & drm_crtc_mask(crtc))
+ return crtc;
+
+ return NULL;
+}
+
+struct vc4_dummy_plane {
+ struct vc4_plane plane;
+};
+
+struct vc4_dummy_plane *vc4_dummy_plane(struct kunit *test,
+ struct drm_device *drm,
+ enum drm_plane_type type);
+
+struct vc4_dummy_crtc {
+ struct vc4_crtc crtc;
+};
+
+struct vc4_dummy_crtc *vc4_mock_pv(struct kunit *test,
+ struct drm_device *drm,
+ struct drm_plane *plane,
+ const struct vc4_crtc_data *data);
+
+struct vc4_dummy_output {
+ struct vc4_encoder encoder;
+ struct drm_connector connector;
+};
+
+struct vc4_dummy_output *vc4_dummy_output(struct kunit *test,
+ struct drm_device *drm,
+ struct drm_crtc *crtc,
+ enum vc4_encoder_type vc4_encoder_type,
+ unsigned int kms_encoder_type,
+ unsigned int connector_type);
+
+struct vc4_dev *vc4_mock_device(struct kunit *test);
+struct vc4_dev *vc5_mock_device(struct kunit *test);
+
+int vc4_mock_atomic_add_output(struct kunit *test,
+ struct drm_atomic_state *state,
+ enum vc4_encoder_type type);
+int vc4_mock_atomic_del_output(struct kunit *test,
+ struct drm_atomic_state *state,
+ enum vc4_encoder_type type);
+
+#endif // VC4_MOCK_H_
diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock_crtc.c b/drivers/gpu/drm/vc4/tests/vc4_mock_crtc.c
new file mode 100644
index 000000000000..5d12d7beef0e
--- /dev/null
+++ b/drivers/gpu/drm/vc4/tests/vc4_mock_crtc.c
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <drm/drm_atomic_state_helper.h>
+#include <drm/drm_modeset_helper_vtables.h>
+
+#include <kunit/test.h>
+
+#include "vc4_mock.h"
+
+static const struct drm_crtc_helper_funcs vc4_dummy_crtc_helper_funcs = {
+ .atomic_check = vc4_crtc_atomic_check,
+};
+
+static const struct drm_crtc_funcs vc4_dummy_crtc_funcs = {
+ .atomic_destroy_state = vc4_crtc_destroy_state,
+ .atomic_duplicate_state = vc4_crtc_duplicate_state,
+ .reset = vc4_crtc_reset,
+};
+
+struct vc4_dummy_crtc *vc4_mock_pv(struct kunit *test,
+ struct drm_device *drm,
+ struct drm_plane *plane,
+ const struct vc4_crtc_data *data)
+{
+ struct vc4_dummy_crtc *dummy_crtc;
+ struct vc4_crtc *vc4_crtc;
+ int ret;
+
+ dummy_crtc = kunit_kzalloc(test, sizeof(*dummy_crtc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, dummy_crtc);
+
+ vc4_crtc = &dummy_crtc->crtc;
+ ret = __vc4_crtc_init(drm, NULL,
+ vc4_crtc, data, plane,
+ &vc4_dummy_crtc_funcs,
+ &vc4_dummy_crtc_helper_funcs,
+ false);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ return dummy_crtc;
+}
diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock_output.c b/drivers/gpu/drm/vc4/tests/vc4_mock_output.c
new file mode 100644
index 000000000000..8d33be828d9a
--- /dev/null
+++ b/drivers/gpu/drm/vc4/tests/vc4_mock_output.c
@@ -0,0 +1,138 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <drm/drm_atomic_state_helper.h>
+#include <drm/drm_atomic_uapi.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_encoder.h>
+#include <drm/drm_modeset_helper_vtables.h>
+
+#include <kunit/test.h>
+
+#include "vc4_mock.h"
+
+static const struct drm_connector_helper_funcs vc4_dummy_connector_helper_funcs = {
+};
+
+static const struct drm_connector_funcs vc4_dummy_connector_funcs = {
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .reset = drm_atomic_helper_connector_reset,
+};
+
+struct vc4_dummy_output *vc4_dummy_output(struct kunit *test,
+ struct drm_device *drm,
+ struct drm_crtc *crtc,
+ enum vc4_encoder_type vc4_encoder_type,
+ unsigned int kms_encoder_type,
+ unsigned int connector_type)
+{
+ struct vc4_dummy_output *dummy_output;
+ struct drm_connector *conn;
+ struct drm_encoder *enc;
+ int ret;
+
+ dummy_output = kunit_kzalloc(test, sizeof(*dummy_output), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_output);
+ dummy_output->encoder.type = vc4_encoder_type;
+
+ enc = &dummy_output->encoder.base;
+ ret = drmm_encoder_init(drm, enc,
+ NULL,
+ kms_encoder_type,
+ NULL);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+ enc->possible_crtcs = drm_crtc_mask(crtc);
+
+ conn = &dummy_output->connector;
+ ret = drmm_connector_init(drm, conn,
+ &vc4_dummy_connector_funcs,
+ connector_type,
+ NULL);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ drm_connector_helper_add(conn, &vc4_dummy_connector_helper_funcs);
+ drm_connector_attach_encoder(conn, enc);
+
+ return dummy_output;
+}
+
+static const struct drm_display_mode default_mode = {
+ DRM_SIMPLE_MODE(640, 480, 64, 48)
+};
+
+int vc4_mock_atomic_add_output(struct kunit *test,
+ struct drm_atomic_state *state,
+ enum vc4_encoder_type type)
+{
+ struct drm_device *drm = state->dev;
+ struct drm_connector_state *conn_state;
+ struct drm_crtc_state *crtc_state;
+ struct vc4_dummy_output *output;
+ struct drm_connector *conn;
+ struct drm_encoder *encoder;
+ struct drm_crtc *crtc;
+ int ret;
+
+ encoder = vc4_find_encoder_by_type(drm, type);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder);
+
+ crtc = vc4_find_crtc_for_encoder(test, drm, encoder);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc);
+
+ output = container_of(encoder, struct vc4_dummy_output, encoder.base);
+ conn = &output->connector;
+ conn_state = drm_atomic_get_connector_state(state, conn);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
+
+ ret = drm_atomic_set_crtc_for_connector(conn_state, crtc);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+
+ crtc_state = drm_atomic_get_crtc_state(state, crtc);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
+
+ ret = drm_atomic_set_mode_for_crtc(crtc_state, &default_mode);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+
+ crtc_state->active = true;
+
+ return 0;
+}
+
+int vc4_mock_atomic_del_output(struct kunit *test,
+ struct drm_atomic_state *state,
+ enum vc4_encoder_type type)
+{
+ struct drm_device *drm = state->dev;
+ struct drm_connector_state *conn_state;
+ struct drm_crtc_state *crtc_state;
+ struct vc4_dummy_output *output;
+ struct drm_connector *conn;
+ struct drm_encoder *encoder;
+ struct drm_crtc *crtc;
+ int ret;
+
+ encoder = vc4_find_encoder_by_type(drm, type);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder);
+
+ crtc = vc4_find_crtc_for_encoder(test, drm, encoder);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc);
+
+ crtc_state = drm_atomic_get_crtc_state(state, crtc);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
+
+ crtc_state->active = false;
+
+ ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ output = container_of(encoder, struct vc4_dummy_output, encoder.base);
+ conn = &output->connector;
+ conn_state = drm_atomic_get_connector_state(state, conn);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
+
+ ret = drm_atomic_set_crtc_for_connector(conn_state, NULL);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c b/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c
new file mode 100644
index 000000000000..62b18f5f41db
--- /dev/null
+++ b/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <drm/drm_atomic_state_helper.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_modeset_helper_vtables.h>
+#include <drm/drm_plane.h>
+
+#include <kunit/test.h>
+
+#include "vc4_mock.h"
+
+static const struct drm_plane_helper_funcs vc4_dummy_plane_helper_funcs = {
+};
+
+static const struct drm_plane_funcs vc4_dummy_plane_funcs = {
+ .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+ .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+ .reset = drm_atomic_helper_plane_reset,
+};
+
+static const uint32_t vc4_dummy_plane_formats[] = {
+ DRM_FORMAT_XRGB8888,
+};
+
+struct vc4_dummy_plane *vc4_dummy_plane(struct kunit *test,
+ struct drm_device *drm,
+ enum drm_plane_type type)
+{
+ struct vc4_dummy_plane *dummy_plane;
+ struct drm_plane *plane;
+
+ dummy_plane = drmm_universal_plane_alloc(drm,
+ struct vc4_dummy_plane, plane.base,
+ 0,
+ &vc4_dummy_plane_funcs,
+ vc4_dummy_plane_formats,
+ ARRAY_SIZE(vc4_dummy_plane_formats),
+ NULL,
+ DRM_PLANE_TYPE_PRIMARY,
+ NULL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_plane);
+
+ plane = &dummy_plane->plane.base;
+ drm_plane_helper_add(plane, &vc4_dummy_plane_helper_funcs);
+
+ return dummy_plane;
+}
diff --git a/drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c b/drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c
new file mode 100644
index 000000000000..ae0bd0f81698
--- /dev/null
+++ b/drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c
@@ -0,0 +1,1039 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_atomic_state_helper.h>
+#include <drm/drm_atomic_uapi.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_kunit_helpers.h>
+#include <drm/drm_mode.h>
+#include <drm/drm_modeset_helper_vtables.h>
+#include <drm/drm_plane.h>
+
+#include <kunit/test.h>
+
+#include "../vc4_drv.h"
+
+#include "vc4_mock.h"
+
+struct pv_muxing_priv {
+ struct vc4_dev *vc4;
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_atomic_state *state;
+};
+
+static bool check_fifo_conflict(struct kunit *test,
+ const struct drm_atomic_state *state)
+{
+ struct vc4_hvs_state *hvs_state;
+ unsigned int used_fifos = 0;
+ unsigned int i;
+
+ hvs_state = vc4_hvs_get_new_global_state(state);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hvs_state);
+
+ for (i = 0; i < HVS_NUM_CHANNELS; i++) {
+ if (!hvs_state->fifo_state[i].in_use)
+ continue;
+
+ KUNIT_EXPECT_FALSE(test, used_fifos & BIT(i));
+ used_fifos |= BIT(i);
+ }
+
+ return true;
+}
+
+struct encoder_constraint {
+ enum vc4_encoder_type type;
+ unsigned int *channels;
+ size_t nchannels;
+};
+
+#define ENCODER_CONSTRAINT(_type, ...) \
+ { \
+ .type = _type, \
+ .channels = (unsigned int[]) { __VA_ARGS__ }, \
+ .nchannels = sizeof((unsigned int[]) { __VA_ARGS__ }) / \
+ sizeof(unsigned int), \
+ }
+
+static bool __check_encoder_constraints(const struct encoder_constraint *constraints,
+ size_t nconstraints,
+ enum vc4_encoder_type type,
+ unsigned int channel)
+{
+ unsigned int i;
+
+ for (i = 0; i < nconstraints; i++) {
+ const struct encoder_constraint *constraint = &constraints[i];
+ unsigned int j;
+
+ if (constraint->type != type)
+ continue;
+
+ for (j = 0; j < constraint->nchannels; j++) {
+ unsigned int _channel = constraint->channels[j];
+
+ if (channel != _channel)
+ continue;
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static const struct encoder_constraint vc4_encoder_constraints[] = {
+ ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DPI, 0),
+ ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DSI0, 0),
+ ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_HDMI0, 1),
+ ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_VEC, 1),
+ ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_TXP, 2),
+ ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DSI1, 2),
+};
+
+static const struct encoder_constraint vc5_encoder_constraints[] = {
+ ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DPI, 0),
+ ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DSI0, 0),
+ ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_VEC, 1),
+ ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_TXP, 0, 2),
+ ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DSI1, 0, 1, 2),
+ ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_HDMI0, 0, 1, 2),
+ ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_HDMI1, 0, 1, 2),
+};
+
+static bool check_vc4_encoder_constraints(enum vc4_encoder_type type, unsigned int channel)
+{
+ return __check_encoder_constraints(vc4_encoder_constraints,
+ ARRAY_SIZE(vc4_encoder_constraints),
+ type, channel);
+}
+
+static bool check_vc5_encoder_constraints(enum vc4_encoder_type type, unsigned int channel)
+{
+ return __check_encoder_constraints(vc5_encoder_constraints,
+ ARRAY_SIZE(vc5_encoder_constraints),
+ type, channel);
+}
+
+static struct vc4_crtc_state *
+get_vc4_crtc_state_for_encoder(struct kunit *test,
+ const struct drm_atomic_state *state,
+ enum vc4_encoder_type type)
+{
+ struct drm_device *drm = state->dev;
+ struct drm_crtc_state *new_crtc_state;
+ struct drm_encoder *encoder;
+ struct drm_crtc *crtc;
+
+ encoder = vc4_find_encoder_by_type(drm, type);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder);
+
+ crtc = vc4_find_crtc_for_encoder(test, drm, encoder);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc);
+
+ new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+ if (!new_crtc_state)
+ return NULL;
+
+ return to_vc4_crtc_state(new_crtc_state);
+}
+
+static bool check_channel_for_encoder(struct kunit *test,
+ const struct drm_atomic_state *state,
+ enum vc4_encoder_type type,
+ bool (*check_fn)(enum vc4_encoder_type type, unsigned int channel))
+{
+ struct vc4_crtc_state *new_vc4_crtc_state;
+ struct vc4_hvs_state *new_hvs_state;
+ unsigned int channel;
+
+ new_hvs_state = vc4_hvs_get_new_global_state(state);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_hvs_state);
+
+ new_vc4_crtc_state = get_vc4_crtc_state_for_encoder(test, state, type);
+ KUNIT_ASSERT_NOT_NULL(test, new_vc4_crtc_state);
+
+ channel = new_vc4_crtc_state->assigned_channel;
+ KUNIT_EXPECT_NE(test, channel, VC4_HVS_CHANNEL_DISABLED);
+
+ KUNIT_EXPECT_TRUE(test, new_hvs_state->fifo_state[channel].in_use);
+
+ KUNIT_EXPECT_TRUE(test, check_fn(type, channel));
+
+ return true;
+}
+
+struct pv_muxing_param {
+ const char *name;
+ struct vc4_dev *(*mock_fn)(struct kunit *test);
+ bool (*check_fn)(enum vc4_encoder_type type, unsigned int channel);
+ enum vc4_encoder_type *encoders;
+ size_t nencoders;
+};
+
+static void vc4_test_pv_muxing_desc(const struct pv_muxing_param *t, char *desc)
+{
+ strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE);
+}
+
+#define PV_MUXING_TEST(_name, _mock_fn, _check_fn, ...) \
+ { \
+ .name = _name, \
+ .mock_fn = &_mock_fn, \
+ .check_fn = &_check_fn, \
+ .encoders = (enum vc4_encoder_type[]) { __VA_ARGS__ }, \
+ .nencoders = sizeof((enum vc4_encoder_type[]) { __VA_ARGS__ }) / \
+ sizeof(enum vc4_encoder_type), \
+ }
+
+#define VC4_PV_MUXING_TEST(_name, ...) \
+ PV_MUXING_TEST(_name, vc4_mock_device, check_vc4_encoder_constraints, __VA_ARGS__)
+
+#define VC5_PV_MUXING_TEST(_name, ...) \
+ PV_MUXING_TEST(_name, vc5_mock_device, check_vc5_encoder_constraints, __VA_ARGS__)
+
+static const struct pv_muxing_param vc4_test_pv_muxing_params[] = {
+ VC4_PV_MUXING_TEST("1 output: DSI0",
+ VC4_ENCODER_TYPE_DSI0),
+ VC4_PV_MUXING_TEST("1 output: DPI",
+ VC4_ENCODER_TYPE_DPI),
+ VC4_PV_MUXING_TEST("1 output: HDMI0",
+ VC4_ENCODER_TYPE_HDMI0),
+ VC4_PV_MUXING_TEST("1 output: VEC",
+ VC4_ENCODER_TYPE_VEC),
+ VC4_PV_MUXING_TEST("1 output: DSI1",
+ VC4_ENCODER_TYPE_DSI1),
+ VC4_PV_MUXING_TEST("1 output: TXP",
+ VC4_ENCODER_TYPE_TXP),
+ VC4_PV_MUXING_TEST("2 outputs: DSI0, HDMI0",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_HDMI0),
+ VC4_PV_MUXING_TEST("2 outputs: DSI0, VEC",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC),
+ VC4_PV_MUXING_TEST("2 outputs: DSI0, DSI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_DSI1),
+ VC4_PV_MUXING_TEST("2 outputs: DSI0, TXP",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_TXP),
+ VC4_PV_MUXING_TEST("2 outputs: DPI, HDMI0",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_HDMI0),
+ VC4_PV_MUXING_TEST("2 outputs: DPI, VEC",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC),
+ VC4_PV_MUXING_TEST("2 outputs: DPI, DSI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_DSI1),
+ VC4_PV_MUXING_TEST("2 outputs: DPI, TXP",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_TXP),
+ VC4_PV_MUXING_TEST("2 outputs: HDMI0, DSI1",
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_DSI1),
+ VC4_PV_MUXING_TEST("2 outputs: HDMI0, TXP",
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_TXP),
+ VC4_PV_MUXING_TEST("2 outputs: VEC, DSI1",
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_DSI1),
+ VC4_PV_MUXING_TEST("2 outputs: VEC, TXP",
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP),
+ VC4_PV_MUXING_TEST("3 outputs: DSI0, HDMI0, DSI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_DSI1),
+ VC4_PV_MUXING_TEST("3 outputs: DSI0, HDMI0, TXP",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_TXP),
+ VC4_PV_MUXING_TEST("3 outputs: DSI0, VEC, DSI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_DSI1),
+ VC4_PV_MUXING_TEST("3 outputs: DSI0, VEC, TXP",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP),
+ VC4_PV_MUXING_TEST("3 outputs: DPI, HDMI0, DSI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_DSI1),
+ VC4_PV_MUXING_TEST("3 outputs: DPI, HDMI0, TXP",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_TXP),
+ VC4_PV_MUXING_TEST("3 outputs: DPI, VEC, DSI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_DSI1),
+ VC4_PV_MUXING_TEST("3 outputs: DPI, VEC, TXP",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP),
+};
+
+KUNIT_ARRAY_PARAM(vc4_test_pv_muxing,
+ vc4_test_pv_muxing_params,
+ vc4_test_pv_muxing_desc);
+
+static const struct pv_muxing_param vc4_test_pv_muxing_invalid_params[] = {
+ VC4_PV_MUXING_TEST("DPI/DSI0 Conflict",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_DSI0),
+ VC4_PV_MUXING_TEST("TXP/DSI1 Conflict",
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_DSI1),
+ VC4_PV_MUXING_TEST("HDMI0/VEC Conflict",
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_VEC),
+ VC4_PV_MUXING_TEST("More than 3 outputs: DSI0, HDMI0, DSI1, TXP",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_TXP),
+ VC4_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, DSI1, TXP",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_TXP),
+ VC4_PV_MUXING_TEST("More than 3 outputs: DPI, HDMI0, DSI1, TXP",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_TXP),
+ VC4_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, DSI1, TXP",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_TXP),
+};
+
+KUNIT_ARRAY_PARAM(vc4_test_pv_muxing_invalid,
+ vc4_test_pv_muxing_invalid_params,
+ vc4_test_pv_muxing_desc);
+
+static const struct pv_muxing_param vc5_test_pv_muxing_params[] = {
+ VC5_PV_MUXING_TEST("1 output: DPI",
+ VC4_ENCODER_TYPE_DPI),
+ VC5_PV_MUXING_TEST("1 output: DSI0",
+ VC4_ENCODER_TYPE_DSI0),
+ VC5_PV_MUXING_TEST("1 output: DSI1",
+ VC4_ENCODER_TYPE_DSI1),
+ VC5_PV_MUXING_TEST("1 output: HDMI0",
+ VC4_ENCODER_TYPE_HDMI0),
+ VC5_PV_MUXING_TEST("1 output: HDMI1",
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("1 output: VEC",
+ VC4_ENCODER_TYPE_VEC),
+ VC5_PV_MUXING_TEST("2 outputs: DPI, DSI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_DSI1),
+ VC5_PV_MUXING_TEST("2 outputs: DPI, HDMI0",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_HDMI0),
+ VC5_PV_MUXING_TEST("2 outputs: DPI, HDMI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("2 outputs: DPI, TXP",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_TXP),
+ VC5_PV_MUXING_TEST("2 outputs: DPI, VEC",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC),
+ VC5_PV_MUXING_TEST("2 outputs: DPI, DSI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_DSI1),
+ VC5_PV_MUXING_TEST("2 outputs: DSI0, DSI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_DSI1),
+ VC5_PV_MUXING_TEST("2 outputs: DSI0, HDMI0",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_HDMI0),
+ VC5_PV_MUXING_TEST("2 outputs: DSI0, HDMI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("2 outputs: DSI0, TXP",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_TXP),
+ VC5_PV_MUXING_TEST("2 outputs: DSI0, VEC",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC),
+ VC5_PV_MUXING_TEST("2 outputs: DSI0, DSI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_DSI1),
+ VC5_PV_MUXING_TEST("2 outputs: DSI1, VEC",
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_VEC),
+ VC5_PV_MUXING_TEST("2 outputs: DSI1, TXP",
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_TXP),
+ VC5_PV_MUXING_TEST("2 outputs: DSI1, HDMI0",
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI0),
+ VC5_PV_MUXING_TEST("2 outputs: DSI1, HDMI1",
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("2 outputs: HDMI0, VEC",
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_VEC),
+ VC5_PV_MUXING_TEST("2 outputs: HDMI0, TXP",
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_TXP),
+ VC5_PV_MUXING_TEST("2 outputs: HDMI0, HDMI1",
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("2 outputs: HDMI1, VEC",
+ VC4_ENCODER_TYPE_HDMI1,
+ VC4_ENCODER_TYPE_VEC),
+ VC5_PV_MUXING_TEST("2 outputs: HDMI1, TXP",
+ VC4_ENCODER_TYPE_HDMI1,
+ VC4_ENCODER_TYPE_TXP),
+ VC5_PV_MUXING_TEST("2 outputs: TXP, VEC",
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_VEC),
+ VC5_PV_MUXING_TEST("3 outputs: DPI, VEC, TXP",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP),
+ VC5_PV_MUXING_TEST("3 outputs: DPI, VEC, DSI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_DSI1),
+ VC5_PV_MUXING_TEST("3 outputs: DPI, VEC, HDMI0",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_HDMI0),
+ VC5_PV_MUXING_TEST("3 outputs: DPI, VEC, HDMI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("3 outputs: DPI, TXP, DSI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_DSI1),
+ VC5_PV_MUXING_TEST("3 outputs: DPI, TXP, HDMI0",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_HDMI0),
+ VC5_PV_MUXING_TEST("3 outputs: DPI, TXP, HDMI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("3 outputs: DPI, DSI1, HDMI0",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI0),
+ VC5_PV_MUXING_TEST("3 outputs: DPI, DSI1, HDMI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("3 outputs: DPI, HDMI0, HDMI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("3 outputs: DSI0, VEC, TXP",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP),
+ VC5_PV_MUXING_TEST("3 outputs: DSI0, VEC, DSI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_DSI1),
+ VC5_PV_MUXING_TEST("3 outputs: DSI0, VEC, HDMI0",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_HDMI0),
+ VC5_PV_MUXING_TEST("3 outputs: DSI0, VEC, HDMI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("3 outputs: DSI0, TXP, DSI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_DSI1),
+ VC5_PV_MUXING_TEST("3 outputs: DSI0, TXP, HDMI0",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_HDMI0),
+ VC5_PV_MUXING_TEST("3 outputs: DSI0, TXP, HDMI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("3 outputs: DSI0, DSI1, HDMI0",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI0),
+ VC5_PV_MUXING_TEST("3 outputs: DSI0, DSI1, HDMI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("3 outputs: DSI0, HDMI0, HDMI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_HDMI1),
+};
+
+KUNIT_ARRAY_PARAM(vc5_test_pv_muxing,
+ vc5_test_pv_muxing_params,
+ vc4_test_pv_muxing_desc);
+
+static const struct pv_muxing_param vc5_test_pv_muxing_invalid_params[] = {
+ VC5_PV_MUXING_TEST("DPI/DSI0 Conflict",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_DSI0),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, DSI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_DSI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, HDMI0",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_HDMI0),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, HDMI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, DSI1, HDMI0",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI0),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, DSI1, HDMI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, HDMI0, HDMI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DPI, TXP, DSI1, HDMI0",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI0),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DPI, TXP, DSI1, HDMI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DPI, TXP, HDMI0, HDMI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DPI, DSI1, HDMI0, HDMI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, DSI1, HDMI0",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI0),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, DSI1, HDMI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, HDMI0, HDMI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, DSI1, HDMI0, HDMI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DPI, TXP, DSI1, HDMI0, HDMI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, DSI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_DSI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, HDMI0",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_HDMI0),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, HDMI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, DSI1, HDMI0",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI0),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, DSI1, HDMI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, HDMI0, HDMI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, TXP, DSI1, HDMI0",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI0),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, TXP, DSI1, HDMI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, TXP, HDMI0, HDMI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, DSI1, HDMI0, HDMI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, DSI1, HDMI0",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI0),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, DSI1, HDMI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, HDMI0, HDMI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, DSI1, HDMI0, HDMI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, TXP, DSI1, HDMI0, HDMI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: VEC, TXP, DSI1, HDMI0, HDMI1",
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, DSI1, HDMI0, HDMI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, DSI1, HDMI0, HDMI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_HDMI1),
+};
+
+KUNIT_ARRAY_PARAM(vc5_test_pv_muxing_invalid,
+ vc5_test_pv_muxing_invalid_params,
+ vc4_test_pv_muxing_desc);
+
+static void drm_vc4_test_pv_muxing(struct kunit *test)
+{
+ const struct pv_muxing_param *params = test->param_value;
+ const struct pv_muxing_priv *priv = test->priv;
+ struct drm_atomic_state *state = priv->state;
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < params->nencoders; i++) {
+ enum vc4_encoder_type enc_type = params->encoders[i];
+
+ ret = vc4_mock_atomic_add_output(test, state, enc_type);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+ }
+
+ ret = drm_atomic_check_only(state);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+
+ KUNIT_EXPECT_TRUE(test,
+ check_fifo_conflict(test, state));
+
+ for (i = 0; i < params->nencoders; i++) {
+ enum vc4_encoder_type enc_type = params->encoders[i];
+
+ KUNIT_EXPECT_TRUE(test, check_channel_for_encoder(test, state, enc_type,
+ params->check_fn));
+ }
+}
+
+static void drm_vc4_test_pv_muxing_invalid(struct kunit *test)
+{
+ const struct pv_muxing_param *params = test->param_value;
+ const struct pv_muxing_priv *priv = test->priv;
+ struct drm_atomic_state *state = priv->state;
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < params->nencoders; i++) {
+ enum vc4_encoder_type enc_type = params->encoders[i];
+
+ ret = vc4_mock_atomic_add_output(test, state, enc_type);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+ }
+
+ ret = drm_atomic_check_only(state);
+ KUNIT_EXPECT_LT(test, ret, 0);
+}
+
+static int vc4_pv_muxing_test_init(struct kunit *test)
+{
+ const struct pv_muxing_param *params = test->param_value;
+ struct drm_atomic_state *state;
+ struct pv_muxing_priv *priv;
+ struct drm_device *drm;
+ struct vc4_dev *vc4;
+
+ priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, priv);
+ test->priv = priv;
+
+ vc4 = params->mock_fn(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4);
+ priv->vc4 = vc4;
+
+ drm_modeset_acquire_init(&priv->ctx, 0);
+
+ drm = &vc4->base;
+ state = drm_atomic_state_alloc(drm);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+ state->acquire_ctx = &priv->ctx;
+
+ priv->state = state;
+
+ return 0;
+}
+
+static void vc4_pv_muxing_test_exit(struct kunit *test)
+{
+ struct pv_muxing_priv *priv = test->priv;
+ struct vc4_dev *vc4 = priv->vc4;
+ struct drm_device *drm = &vc4->base;
+ struct drm_atomic_state *state = priv->state;
+
+ drm_atomic_state_put(state);
+ drm_modeset_drop_locks(&priv->ctx);
+ drm_modeset_acquire_fini(&priv->ctx);
+ drm_dev_unregister(drm);
+ drm_kunit_helper_free_device(test, vc4->dev);
+}
+
+static struct kunit_case vc4_pv_muxing_tests[] = {
+ KUNIT_CASE_PARAM(drm_vc4_test_pv_muxing,
+ vc4_test_pv_muxing_gen_params),
+ KUNIT_CASE_PARAM(drm_vc4_test_pv_muxing_invalid,
+ vc4_test_pv_muxing_invalid_gen_params),
+ {}
+};
+
+static struct kunit_suite vc4_pv_muxing_test_suite = {
+ .name = "vc4-pv-muxing-combinations",
+ .init = vc4_pv_muxing_test_init,
+ .exit = vc4_pv_muxing_test_exit,
+ .test_cases = vc4_pv_muxing_tests,
+};
+
+static struct kunit_case vc5_pv_muxing_tests[] = {
+ KUNIT_CASE_PARAM(drm_vc4_test_pv_muxing,
+ vc5_test_pv_muxing_gen_params),
+ KUNIT_CASE_PARAM(drm_vc4_test_pv_muxing_invalid,
+ vc5_test_pv_muxing_invalid_gen_params),
+ {}
+};
+
+static struct kunit_suite vc5_pv_muxing_test_suite = {
+ .name = "vc5-pv-muxing-combinations",
+ .init = vc4_pv_muxing_test_init,
+ .exit = vc4_pv_muxing_test_exit,
+ .test_cases = vc5_pv_muxing_tests,
+};
+
+/* See
+ * https://lore.kernel.org/all/3e113525-aa89-b1e2-56b7-ca55bd41d057@samsung.com/
+ * and
+ * https://lore.kernel.org/dri-devel/20200917121623.42023-1-maxime@cerno.tech/
+ */
+static void drm_test_vc5_pv_muxing_bugs_subsequent_crtc_enable(struct kunit *test)
+{
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_atomic_state *state;
+ struct vc4_crtc_state *new_vc4_crtc_state;
+ struct vc4_hvs_state *new_hvs_state;
+ unsigned int hdmi0_channel;
+ unsigned int hdmi1_channel;
+ struct drm_device *drm;
+ struct vc4_dev *vc4;
+ int ret;
+
+ vc4 = vc5_mock_device(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4);
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+ drm = &vc4->base;
+ state = drm_atomic_state_alloc(drm);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+ state->acquire_ctx = &ctx;
+
+ ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI0);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ ret = drm_atomic_check_only(state);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ new_hvs_state = vc4_hvs_get_new_global_state(state);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_hvs_state);
+
+ new_vc4_crtc_state = get_vc4_crtc_state_for_encoder(test, state,
+ VC4_ENCODER_TYPE_HDMI0);
+ KUNIT_ASSERT_NOT_NULL(test, new_vc4_crtc_state);
+
+ hdmi0_channel = new_vc4_crtc_state->assigned_channel;
+ KUNIT_ASSERT_NE(test, hdmi0_channel, VC4_HVS_CHANNEL_DISABLED);
+ KUNIT_ASSERT_TRUE(test, new_hvs_state->fifo_state[hdmi0_channel].in_use);
+
+ ret = drm_atomic_helper_swap_state(state, false);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ drm_atomic_state_put(state);
+
+ state = drm_atomic_state_alloc(drm);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+ state->acquire_ctx = &ctx;
+
+ ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI1);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ ret = drm_atomic_check_only(state);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ new_hvs_state = vc4_hvs_get_new_global_state(state);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_hvs_state);
+
+ new_vc4_crtc_state = get_vc4_crtc_state_for_encoder(test, state,
+ VC4_ENCODER_TYPE_HDMI1);
+ KUNIT_ASSERT_NOT_NULL(test, new_vc4_crtc_state);
+
+ hdmi1_channel = new_vc4_crtc_state->assigned_channel;
+ KUNIT_ASSERT_NE(test, hdmi1_channel, VC4_HVS_CHANNEL_DISABLED);
+ KUNIT_ASSERT_TRUE(test, new_hvs_state->fifo_state[hdmi1_channel].in_use);
+
+ KUNIT_EXPECT_NE(test, hdmi0_channel, hdmi1_channel);
+
+ drm_atomic_state_put(state);
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+ drm_dev_unregister(drm);
+ drm_kunit_helper_free_device(test, vc4->dev);
+}
+
+static void drm_test_vc5_pv_muxing_bugs_stable_fifo(struct kunit *test)
+{
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_atomic_state *state;
+ struct vc4_crtc_state *new_vc4_crtc_state;
+ struct vc4_hvs_state *new_hvs_state;
+ unsigned int old_hdmi0_channel;
+ unsigned int old_hdmi1_channel;
+ struct drm_device *drm;
+ struct vc4_dev *vc4;
+ int ret;
+
+ vc4 = vc5_mock_device(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4);
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+ drm = &vc4->base;
+ state = drm_atomic_state_alloc(drm);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+ state->acquire_ctx = &ctx;
+
+ ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI0);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI1);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ ret = drm_atomic_check_only(state);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ new_hvs_state = vc4_hvs_get_new_global_state(state);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_hvs_state);
+
+ new_vc4_crtc_state = get_vc4_crtc_state_for_encoder(test, state,
+ VC4_ENCODER_TYPE_HDMI0);
+ KUNIT_ASSERT_NOT_NULL(test, new_vc4_crtc_state);
+
+ old_hdmi0_channel = new_vc4_crtc_state->assigned_channel;
+ KUNIT_ASSERT_NE(test, old_hdmi0_channel, VC4_HVS_CHANNEL_DISABLED);
+ KUNIT_ASSERT_TRUE(test, new_hvs_state->fifo_state[old_hdmi0_channel].in_use);
+
+ new_vc4_crtc_state = get_vc4_crtc_state_for_encoder(test, state,
+ VC4_ENCODER_TYPE_HDMI1);
+ KUNIT_ASSERT_NOT_NULL(test, new_vc4_crtc_state);
+
+ old_hdmi1_channel = new_vc4_crtc_state->assigned_channel;
+ KUNIT_ASSERT_NE(test, old_hdmi1_channel, VC4_HVS_CHANNEL_DISABLED);
+ KUNIT_ASSERT_TRUE(test, new_hvs_state->fifo_state[old_hdmi1_channel].in_use);
+
+ ret = drm_atomic_helper_swap_state(state, false);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ drm_atomic_state_put(state);
+
+ state = drm_atomic_state_alloc(drm);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+ state->acquire_ctx = &ctx;
+
+ ret = vc4_mock_atomic_del_output(test, state, VC4_ENCODER_TYPE_HDMI0);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ ret = drm_atomic_check_only(state);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ new_hvs_state = vc4_hvs_get_new_global_state(state);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_hvs_state);
+
+ new_vc4_crtc_state = get_vc4_crtc_state_for_encoder(test, state,
+ VC4_ENCODER_TYPE_HDMI1);
+
+ if (new_vc4_crtc_state) {
+ unsigned int hdmi1_channel;
+
+ hdmi1_channel = new_vc4_crtc_state->assigned_channel;
+ KUNIT_ASSERT_NE(test, hdmi1_channel, VC4_HVS_CHANNEL_DISABLED);
+ KUNIT_ASSERT_TRUE(test, new_hvs_state->fifo_state[hdmi1_channel].in_use);
+
+ KUNIT_EXPECT_EQ(test, old_hdmi1_channel, hdmi1_channel);
+ }
+
+ drm_atomic_state_put(state);
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+ drm_dev_unregister(drm);
+ drm_kunit_helper_free_device(test, vc4->dev);
+}
+
+static void
+drm_test_vc5_pv_muxing_bugs_subsequent_crtc_enable_too_many_crtc_state(struct kunit *test)
+{
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_atomic_state *state;
+ struct vc4_crtc_state *new_vc4_crtc_state;
+ struct drm_device *drm;
+ struct vc4_dev *vc4;
+ int ret;
+
+ vc4 = vc5_mock_device(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4);
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+ drm = &vc4->base;
+ state = drm_atomic_state_alloc(drm);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+ state->acquire_ctx = &ctx;
+
+ ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI0);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ ret = drm_atomic_check_only(state);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ ret = drm_atomic_helper_swap_state(state, false);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ drm_atomic_state_put(state);
+
+ state = drm_atomic_state_alloc(drm);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+ state->acquire_ctx = &ctx;
+
+ ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI1);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ ret = drm_atomic_check_only(state);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ new_vc4_crtc_state = get_vc4_crtc_state_for_encoder(test, state,
+ VC4_ENCODER_TYPE_HDMI0);
+ KUNIT_EXPECT_NULL(test, new_vc4_crtc_state);
+
+ drm_atomic_state_put(state);
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+ drm_dev_unregister(drm);
+ drm_kunit_helper_free_device(test, vc4->dev);
+}
+
+static struct kunit_case vc5_pv_muxing_bugs_tests[] = {
+ KUNIT_CASE(drm_test_vc5_pv_muxing_bugs_subsequent_crtc_enable),
+ KUNIT_CASE(drm_test_vc5_pv_muxing_bugs_subsequent_crtc_enable_too_many_crtc_state),
+ KUNIT_CASE(drm_test_vc5_pv_muxing_bugs_stable_fifo),
+ {}
+};
+
+static struct kunit_suite vc5_pv_muxing_bugs_test_suite = {
+ .name = "vc5-pv-muxing-bugs",
+ .test_cases = vc5_pv_muxing_bugs_tests,
+};
+
+kunit_test_suites(
+ &vc4_pv_muxing_test_suite,
+ &vc5_pv_muxing_test_suite,
+ &vc5_pv_muxing_bugs_test_suite
+);
diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c
index c5947ed8cc81..86d629e45307 100644
--- a/drivers/gpu/drm/vc4/vc4_bo.c
+++ b/drivers/gpu/drm/vc4/vc4_bo.c
@@ -69,8 +69,8 @@ static void vc4_bo_stats_print(struct drm_printer *p, struct vc4_dev *vc4)
static int vc4_bo_stats_debugfs(struct seq_file *m, void *unused)
{
- struct drm_info_node *node = (struct drm_info_node *)m->private;
- struct drm_device *dev = node->minor->dev;
+ struct drm_debugfs_entry *entry = m->private;
+ struct drm_device *dev = entry->dev;
struct vc4_dev *vc4 = to_vc4_dev(dev);
struct drm_printer p = drm_seq_file_printer(m);
@@ -991,15 +991,11 @@ int vc4_bo_debugfs_init(struct drm_minor *minor)
{
struct drm_device *drm = minor->dev;
struct vc4_dev *vc4 = to_vc4_dev(drm);
- int ret;
if (!vc4->v3d)
return -ENODEV;
- ret = vc4_debugfs_add_file(minor, "bo_stats",
- vc4_bo_stats_debugfs, NULL);
- if (ret)
- return ret;
+ drm_debugfs_add_file(drm, "bo_stats", vc4_bo_stats_debugfs, NULL);
return 0;
}
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
index 7258975331ca..bef9d45ef1df 100644
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
@@ -50,8 +50,17 @@
#define HVS_FIFO_LATENCY_PIX 6
-#define CRTC_WRITE(offset, val) writel(val, vc4_crtc->regs + (offset))
-#define CRTC_READ(offset) readl(vc4_crtc->regs + (offset))
+#define CRTC_WRITE(offset, val) \
+ do { \
+ kunit_fail_current_test("Accessing a register in a unit test!\n"); \
+ writel(val, vc4_crtc->regs + (offset)); \
+ } while (0)
+
+#define CRTC_READ(offset) \
+ ({ \
+ kunit_fail_current_test("Accessing a register in a unit test!\n"); \
+ readl(vc4_crtc->regs + (offset)); \
+ })
static const struct debugfs_reg32 crtc_regs[] = {
VC4_REG32(PV_CONTROL),
@@ -326,8 +335,14 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encode
bool is_dsi = (vc4_encoder->type == VC4_ENCODER_TYPE_DSI0 ||
vc4_encoder->type == VC4_ENCODER_TYPE_DSI1);
bool is_dsi1 = vc4_encoder->type == VC4_ENCODER_TYPE_DSI1;
+ bool is_vec = vc4_encoder->type == VC4_ENCODER_TYPE_VEC;
u32 format = is_dsi1 ? PV_CONTROL_FORMAT_DSIV_24 : PV_CONTROL_FORMAT_24;
u8 ppc = pv_data->pixels_per_clock;
+
+ u16 vert_bp = mode->crtc_vtotal - mode->crtc_vsync_end;
+ u16 vert_sync = mode->crtc_vsync_end - mode->crtc_vsync_start;
+ u16 vert_fp = mode->crtc_vsync_start - mode->crtc_vdisplay;
+
bool debug_dump_regs = false;
int idx;
@@ -355,49 +370,60 @@ static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encode
VC4_SET_FIELD(mode->hdisplay * pixel_rep / ppc,
PV_HORZB_HACTIVE));
- CRTC_WRITE(PV_VERTA,
- VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end +
- interlace,
- PV_VERTA_VBP) |
- VC4_SET_FIELD(mode->crtc_vsync_end - mode->crtc_vsync_start,
- PV_VERTA_VSYNC));
- CRTC_WRITE(PV_VERTB,
- VC4_SET_FIELD(mode->crtc_vsync_start - mode->crtc_vdisplay,
- PV_VERTB_VFP) |
- VC4_SET_FIELD(mode->crtc_vdisplay, PV_VERTB_VACTIVE));
-
if (interlace) {
+ bool odd_field_first = false;
+ u32 field_delay = mode->htotal * pixel_rep / (2 * ppc);
+ u16 vert_bp_even = vert_bp;
+ u16 vert_fp_even = vert_fp;
+
+ if (is_vec) {
+ /* VEC (composite output) */
+ ++field_delay;
+ if (mode->htotal == 858) {
+ /* 525-line mode (NTSC or PAL-M) */
+ odd_field_first = true;
+ }
+ }
+
+ if (odd_field_first)
+ ++vert_fp_even;
+ else
+ ++vert_bp;
+
CRTC_WRITE(PV_VERTA_EVEN,
- VC4_SET_FIELD(mode->crtc_vtotal -
- mode->crtc_vsync_end,
- PV_VERTA_VBP) |
- VC4_SET_FIELD(mode->crtc_vsync_end -
- mode->crtc_vsync_start,
- PV_VERTA_VSYNC));
+ VC4_SET_FIELD(vert_bp_even, PV_VERTA_VBP) |
+ VC4_SET_FIELD(vert_sync, PV_VERTA_VSYNC));
CRTC_WRITE(PV_VERTB_EVEN,
- VC4_SET_FIELD(mode->crtc_vsync_start -
- mode->crtc_vdisplay,
- PV_VERTB_VFP) |
+ VC4_SET_FIELD(vert_fp_even, PV_VERTB_VFP) |
VC4_SET_FIELD(mode->crtc_vdisplay, PV_VERTB_VACTIVE));
- /* We set up first field even mode for HDMI. VEC's
- * NTSC mode would want first field odd instead, once
- * we support it (to do so, set ODD_FIRST and put the
- * delay in VSYNCD_EVEN instead).
+ /* We set up first field even mode for HDMI and VEC's PAL.
+ * For NTSC, we need first field odd.
*/
CRTC_WRITE(PV_V_CONTROL,
PV_VCONTROL_CONTINUOUS |
(is_dsi ? PV_VCONTROL_DSI : 0) |
PV_VCONTROL_INTERLACE |
- VC4_SET_FIELD(mode->htotal * pixel_rep / (2 * ppc),
- PV_VCONTROL_ODD_DELAY));
- CRTC_WRITE(PV_VSYNCD_EVEN, 0);
+ (odd_field_first
+ ? PV_VCONTROL_ODD_FIRST
+ : VC4_SET_FIELD(field_delay,
+ PV_VCONTROL_ODD_DELAY)));
+ CRTC_WRITE(PV_VSYNCD_EVEN,
+ (odd_field_first ? field_delay : 0));
} else {
CRTC_WRITE(PV_V_CONTROL,
PV_VCONTROL_CONTINUOUS |
(is_dsi ? PV_VCONTROL_DSI : 0));
+ CRTC_WRITE(PV_VSYNCD_EVEN, 0);
}
+ CRTC_WRITE(PV_VERTA,
+ VC4_SET_FIELD(vert_bp, PV_VERTA_VBP) |
+ VC4_SET_FIELD(vert_sync, PV_VERTA_VSYNC));
+ CRTC_WRITE(PV_VERTB,
+ VC4_SET_FIELD(vert_fp, PV_VERTB_VFP) |
+ VC4_SET_FIELD(mode->crtc_vdisplay, PV_VERTB_VACTIVE));
+
if (is_dsi)
CRTC_WRITE(PV_HACT_ACT, mode->hdisplay * pixel_rep);
@@ -486,21 +512,6 @@ static int vc4_crtc_disable(struct drm_crtc *crtc,
return 0;
}
-static struct drm_encoder *vc4_crtc_get_encoder_by_type(struct drm_crtc *crtc,
- enum vc4_encoder_type type)
-{
- struct drm_encoder *encoder;
-
- drm_for_each_encoder(encoder, crtc->dev) {
- struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
-
- if (vc4_encoder->type == type)
- return encoder;
- }
-
- return NULL;
-}
-
int vc4_crtc_disable_at_boot(struct drm_crtc *crtc)
{
struct drm_device *drm = crtc->dev;
@@ -536,7 +547,7 @@ int vc4_crtc_disable_at_boot(struct drm_crtc *crtc)
pv_data = vc4_crtc_to_vc4_pv_data(vc4_crtc);
encoder_type = pv_data->encoder_types[encoder_sel];
- encoder = vc4_crtc_get_encoder_by_type(crtc, encoder_type);
+ encoder = vc4_find_encoder_by_type(drm, encoder_type);
if (WARN_ON(!encoder))
return 0;
@@ -690,8 +701,8 @@ void vc4_crtc_get_margins(struct drm_crtc_state *state,
}
}
-static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
- struct drm_atomic_state *state)
+int vc4_crtc_atomic_check(struct drm_crtc *crtc,
+ struct drm_atomic_state *state)
{
struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
crtc);
@@ -1096,12 +1107,9 @@ int vc4_crtc_late_register(struct drm_crtc *crtc)
struct drm_device *drm = crtc->dev;
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
const struct vc4_crtc_data *crtc_data = vc4_crtc_to_vc4_crtc_data(vc4_crtc);
- int ret;
- ret = vc4_debugfs_add_regset32(drm->primary, crtc_data->debugfs_name,
- &vc4_crtc->regset);
- if (ret)
- return ret;
+ vc4_debugfs_add_regset32(drm, crtc_data->debugfs_name,
+ &vc4_crtc->regset);
return 0;
}
@@ -1131,8 +1139,9 @@ static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
.get_scanout_position = vc4_crtc_get_scanout_position,
};
-static const struct vc4_pv_data bcm2835_pv0_data = {
+const struct vc4_pv_data bcm2835_pv0_data = {
.base = {
+ .name = "pixelvalve-0",
.debugfs_name = "crtc0_regs",
.hvs_available_channels = BIT(0),
.hvs_output = 0,
@@ -1145,8 +1154,9 @@ static const struct vc4_pv_data bcm2835_pv0_data = {
},
};
-static const struct vc4_pv_data bcm2835_pv1_data = {
+const struct vc4_pv_data bcm2835_pv1_data = {
.base = {
+ .name = "pixelvalve-1",
.debugfs_name = "crtc1_regs",
.hvs_available_channels = BIT(2),
.hvs_output = 2,
@@ -1159,8 +1169,9 @@ static const struct vc4_pv_data bcm2835_pv1_data = {
},
};
-static const struct vc4_pv_data bcm2835_pv2_data = {
+const struct vc4_pv_data bcm2835_pv2_data = {
.base = {
+ .name = "pixelvalve-2",
.debugfs_name = "crtc2_regs",
.hvs_available_channels = BIT(1),
.hvs_output = 1,
@@ -1173,8 +1184,9 @@ static const struct vc4_pv_data bcm2835_pv2_data = {
},
};
-static const struct vc4_pv_data bcm2711_pv0_data = {
+const struct vc4_pv_data bcm2711_pv0_data = {
.base = {
+ .name = "pixelvalve-0",
.debugfs_name = "crtc0_regs",
.hvs_available_channels = BIT(0),
.hvs_output = 0,
@@ -1187,8 +1199,9 @@ static const struct vc4_pv_data bcm2711_pv0_data = {
},
};
-static const struct vc4_pv_data bcm2711_pv1_data = {
+const struct vc4_pv_data bcm2711_pv1_data = {
.base = {
+ .name = "pixelvalve-1",
.debugfs_name = "crtc1_regs",
.hvs_available_channels = BIT(0) | BIT(1) | BIT(2),
.hvs_output = 3,
@@ -1201,8 +1214,9 @@ static const struct vc4_pv_data bcm2711_pv1_data = {
},
};
-static const struct vc4_pv_data bcm2711_pv2_data = {
+const struct vc4_pv_data bcm2711_pv2_data = {
.base = {
+ .name = "pixelvalve-2",
.debugfs_name = "crtc2_regs",
.hvs_available_channels = BIT(0) | BIT(1) | BIT(2),
.hvs_output = 4,
@@ -1214,8 +1228,9 @@ static const struct vc4_pv_data bcm2711_pv2_data = {
},
};
-static const struct vc4_pv_data bcm2711_pv3_data = {
+const struct vc4_pv_data bcm2711_pv3_data = {
.base = {
+ .name = "pixelvalve-3",
.debugfs_name = "crtc3_regs",
.hvs_available_channels = BIT(1),
.hvs_output = 1,
@@ -1227,8 +1242,9 @@ static const struct vc4_pv_data bcm2711_pv3_data = {
},
};
-static const struct vc4_pv_data bcm2711_pv4_data = {
+const struct vc4_pv_data bcm2711_pv4_data = {
.base = {
+ .name = "pixelvalve-4",
.debugfs_name = "crtc4_regs",
.hvs_available_channels = BIT(0) | BIT(1) | BIT(2),
.hvs_output = 5,
@@ -1278,31 +1294,44 @@ static void vc4_set_crtc_possible_masks(struct drm_device *drm,
}
}
-int vc4_crtc_init(struct drm_device *drm, struct vc4_crtc *vc4_crtc,
- const struct drm_crtc_funcs *crtc_funcs,
- const struct drm_crtc_helper_funcs *crtc_helper_funcs)
+/**
+ * __vc4_crtc_init - Initializes a CRTC
+ * @drm: DRM Device
+ * @pdev: CRTC Platform Device
+ * @vc4_crtc: CRTC Object to Initialize
+ * @data: Configuration data associated with this CRTC
+ * @primary_plane: Primary plane for CRTC
+ * @crtc_funcs: Callbacks for the new CRTC
+ * @crtc_helper_funcs: Helper Callbacks for the new CRTC
+ * @feeds_txp: Is this CRTC connected to the TXP?
+ *
+ * Initializes our private CRTC structure. This function is mostly
+ * relevant for KUnit testing, all other users should use
+ * vc4_crtc_init() instead.
+ *
+ * Returns:
+ * 0 on success, a negative error code on failure.
+ */
+int __vc4_crtc_init(struct drm_device *drm,
+ struct platform_device *pdev,
+ struct vc4_crtc *vc4_crtc,
+ const struct vc4_crtc_data *data,
+ struct drm_plane *primary_plane,
+ const struct drm_crtc_funcs *crtc_funcs,
+ const struct drm_crtc_helper_funcs *crtc_helper_funcs,
+ bool feeds_txp)
{
struct vc4_dev *vc4 = to_vc4_dev(drm);
struct drm_crtc *crtc = &vc4_crtc->base;
- struct drm_plane *primary_plane;
unsigned int i;
int ret;
- /* For now, we create just the primary and the legacy cursor
- * planes. We should be able to stack more planes on easily,
- * but to do that we would need to compute the bandwidth
- * requirement of the plane configuration, and reject ones
- * that will take too much.
- */
- primary_plane = vc4_plane_init(drm, DRM_PLANE_TYPE_PRIMARY, 0);
- if (IS_ERR(primary_plane)) {
- dev_err(drm->dev, "failed to construct primary plane\n");
- return PTR_ERR(primary_plane);
- }
-
+ vc4_crtc->data = data;
+ vc4_crtc->pdev = pdev;
+ vc4_crtc->feeds_txp = feeds_txp;
spin_lock_init(&vc4_crtc->irq_lock);
ret = drmm_crtc_init_with_planes(drm, crtc, primary_plane, NULL,
- crtc_funcs, NULL);
+ crtc_funcs, data->name);
if (ret)
return ret;
@@ -1328,6 +1357,31 @@ int vc4_crtc_init(struct drm_device *drm, struct vc4_crtc *vc4_crtc,
return 0;
}
+int vc4_crtc_init(struct drm_device *drm, struct platform_device *pdev,
+ struct vc4_crtc *vc4_crtc,
+ const struct vc4_crtc_data *data,
+ const struct drm_crtc_funcs *crtc_funcs,
+ const struct drm_crtc_helper_funcs *crtc_helper_funcs,
+ bool feeds_txp)
+{
+ struct drm_plane *primary_plane;
+
+ /* For now, we create just the primary and the legacy cursor
+ * planes. We should be able to stack more planes on easily,
+ * but to do that we would need to compute the bandwidth
+ * requirement of the plane configuration, and reject ones
+ * that will take too much.
+ */
+ primary_plane = vc4_plane_init(drm, DRM_PLANE_TYPE_PRIMARY, 0);
+ if (IS_ERR(primary_plane)) {
+ dev_err(drm->dev, "failed to construct primary plane\n");
+ return PTR_ERR(primary_plane);
+ }
+
+ return __vc4_crtc_init(drm, pdev, vc4_crtc, data, primary_plane,
+ crtc_funcs, crtc_helper_funcs, feeds_txp);
+}
+
static int vc4_crtc_bind(struct device *dev, struct device *master, void *data)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -1345,8 +1399,6 @@ static int vc4_crtc_bind(struct device *dev, struct device *master, void *data)
pv_data = of_device_get_match_data(dev);
if (!pv_data)
return -ENODEV;
- vc4_crtc->data = &pv_data->base;
- vc4_crtc->pdev = pdev;
vc4_crtc->regs = vc4_ioremap_regs(pdev, 0);
if (IS_ERR(vc4_crtc->regs))
@@ -1356,8 +1408,9 @@ static int vc4_crtc_bind(struct device *dev, struct device *master, void *data)
vc4_crtc->regset.regs = crtc_regs;
vc4_crtc->regset.nregs = ARRAY_SIZE(crtc_regs);
- ret = vc4_crtc_init(drm, vc4_crtc,
- &vc4_crtc_funcs, &vc4_crtc_helper_funcs);
+ ret = vc4_crtc_init(drm, pdev, vc4_crtc, &pv_data->base,
+ &vc4_crtc_funcs, &vc4_crtc_helper_funcs,
+ false);
if (ret)
return ret;
vc4_set_crtc_possible_masks(drm, crtc);
diff --git a/drivers/gpu/drm/vc4/vc4_debugfs.c b/drivers/gpu/drm/vc4/vc4_debugfs.c
index 19cda4f91a82..fac624a663ea 100644
--- a/drivers/gpu/drm/vc4/vc4_debugfs.c
+++ b/drivers/gpu/drm/vc4/vc4_debugfs.c
@@ -34,9 +34,9 @@ vc4_debugfs_init(struct drm_minor *minor)
static int vc4_debugfs_regset32(struct seq_file *m, void *unused)
{
- struct drm_info_node *node = (struct drm_info_node *)m->private;
- struct drm_device *drm = node->minor->dev;
- struct debugfs_regset32 *regset = node->info_ent->data;
+ struct drm_debugfs_entry *entry = m->private;
+ struct drm_device *drm = entry->dev;
+ struct debugfs_regset32 *regset = entry->file.data;
struct drm_printer p = drm_seq_file_printer(m);
int idx;
@@ -50,31 +50,9 @@ static int vc4_debugfs_regset32(struct seq_file *m, void *unused)
return 0;
}
-int vc4_debugfs_add_file(struct drm_minor *minor,
- const char *name,
- int (*show)(struct seq_file*, void*),
- void *data)
+void vc4_debugfs_add_regset32(struct drm_device *drm,
+ const char *name,
+ struct debugfs_regset32 *regset)
{
- struct drm_device *dev = minor->dev;
- struct dentry *root = minor->debugfs_root;
- struct drm_info_list *file;
-
- file = drmm_kzalloc(dev, sizeof(*file), GFP_KERNEL);
- if (!file)
- return -ENOMEM;
-
- file->name = name;
- file->show = show;
- file->data = data;
-
- drm_debugfs_create_files(file, 1, root, minor);
-
- return 0;
-}
-
-int vc4_debugfs_add_regset32(struct drm_minor *minor,
- const char *name,
- struct debugfs_regset32 *regset)
-{
- return vc4_debugfs_add_file(minor, name, vc4_debugfs_regset32, regset);
+ drm_debugfs_add_file(drm, name, vc4_debugfs_regset32, regset);
}
diff --git a/drivers/gpu/drm/vc4/vc4_dpi.c b/drivers/gpu/drm/vc4/vc4_dpi.c
index 1f8f44b7b5a5..f518d6e59ed6 100644
--- a/drivers/gpu/drm/vc4/vc4_dpi.c
+++ b/drivers/gpu/drm/vc4/vc4_dpi.c
@@ -103,8 +103,17 @@ to_vc4_dpi(struct drm_encoder *encoder)
return container_of(encoder, struct vc4_dpi, encoder.base);
}
-#define DPI_READ(offset) readl(dpi->regs + (offset))
-#define DPI_WRITE(offset, val) writel(val, dpi->regs + (offset))
+#define DPI_READ(offset) \
+ ({ \
+ kunit_fail_current_test("Accessing a register in a unit test!\n"); \
+ readl(dpi->regs + (offset)); \
+ })
+
+#define DPI_WRITE(offset, val) \
+ do { \
+ kunit_fail_current_test("Accessing a register in a unit test!\n"); \
+ writel(val, dpi->regs + (offset)); \
+ } while (0)
static const struct debugfs_reg32 dpi_regs[] = {
VC4_REG32(DPI_C),
@@ -150,8 +159,8 @@ static void vc4_dpi_encoder_enable(struct drm_encoder *encoder)
}
drm_connector_list_iter_end(&conn_iter);
- /* Default to 24bit if no connector or format found. */
- dpi_c |= VC4_SET_FIELD(DPI_FORMAT_24BIT_888_RGB, DPI_FORMAT);
+ /* Default to 18bit if no connector or format found. */
+ dpi_c |= VC4_SET_FIELD(DPI_FORMAT_18BIT_666_RGB_1, DPI_FORMAT);
if (connector) {
if (connector->display_info.num_bus_formats) {
@@ -170,16 +179,26 @@ static void vc4_dpi_encoder_enable(struct drm_encoder *encoder)
dpi_c |= VC4_SET_FIELD(DPI_ORDER_BGR,
DPI_ORDER);
break;
+ case MEDIA_BUS_FMT_BGR666_1X24_CPADHI:
+ dpi_c |= VC4_SET_FIELD(DPI_ORDER_BGR, DPI_ORDER);
+ fallthrough;
case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
dpi_c |= VC4_SET_FIELD(DPI_FORMAT_18BIT_666_RGB_2,
DPI_FORMAT);
break;
+ case MEDIA_BUS_FMT_BGR666_1X18:
+ dpi_c |= VC4_SET_FIELD(DPI_ORDER_BGR, DPI_ORDER);
+ fallthrough;
case MEDIA_BUS_FMT_RGB666_1X18:
dpi_c |= VC4_SET_FIELD(DPI_FORMAT_18BIT_666_RGB_1,
DPI_FORMAT);
break;
case MEDIA_BUS_FMT_RGB565_1X16:
- dpi_c |= VC4_SET_FIELD(DPI_FORMAT_16BIT_565_RGB_3,
+ dpi_c |= VC4_SET_FIELD(DPI_FORMAT_16BIT_565_RGB_1,
+ DPI_FORMAT);
+ break;
+ case MEDIA_BUS_FMT_RGB565_1X24_CPADHI:
+ dpi_c |= VC4_SET_FIELD(DPI_FORMAT_16BIT_565_RGB_2,
DPI_FORMAT);
break;
default:
@@ -248,11 +267,8 @@ static int vc4_dpi_late_register(struct drm_encoder *encoder)
{
struct drm_device *drm = encoder->dev;
struct vc4_dpi *dpi = to_vc4_dpi(encoder);
- int ret;
- ret = vc4_debugfs_add_regset32(drm->primary, "dpi_regs", &dpi->regset);
- if (ret)
- return ret;
+ vc4_debugfs_add_regset32(drm, "dpi_regs", &dpi->regset);
return 0;
}
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
index 5990d8f8c363..0ccaee57fe9a 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.c
+++ b/drivers/gpu/drm/vc4/vc4_drv.c
@@ -196,7 +196,7 @@ static const struct drm_ioctl_desc vc4_drm_ioctls[] = {
DRM_IOCTL_DEF_DRV(VC4_PERFMON_GET_VALUES, vc4_perfmon_get_values_ioctl, DRM_RENDER_ALLOW),
};
-static const struct drm_driver vc4_drm_driver = {
+const struct drm_driver vc4_drm_driver = {
.driver_features = (DRIVER_MODESET |
DRIVER_ATOMIC |
DRIVER_GEM |
@@ -225,7 +225,7 @@ static const struct drm_driver vc4_drm_driver = {
.patchlevel = DRIVER_PATCHLEVEL,
};
-static const struct drm_driver vc5_drm_driver = {
+const struct drm_driver vc5_drm_driver = {
.driver_features = (DRIVER_MODESET |
DRIVER_ATOMIC |
DRIVER_GEM),
@@ -320,7 +320,6 @@ static int vc4_drm_bind(struct device *dev)
drm = &vc4->base;
platform_set_drvdata(pdev, drm);
- INIT_LIST_HEAD(&vc4->debugfs_list);
if (!is_vc5) {
ret = drmm_mutex_init(drm, &vc4->bin_bo_lock);
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
index 515228682e8e..95069bb16821 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
@@ -19,11 +19,16 @@
#include <drm/drm_mm.h>
#include <drm/drm_modeset_lock.h>
+#include <kunit/test-bug.h>
+
#include "uapi/drm/vc4_drm.h"
struct drm_device;
struct drm_gem_object;
+extern const struct drm_driver vc4_drm_driver;
+extern const struct drm_driver vc5_drm_driver;
+
/* Don't forget to update vc4_bo.c: bo_type_names[] when adding to
* this.
*/
@@ -221,11 +226,6 @@ struct vc4_dev {
struct drm_private_obj hvs_channels;
struct drm_private_obj load_tracker;
- /* List of vc4_debugfs_info_entry for adding to debugfs once
- * the minor is available (after drm_dev_register()).
- */
- struct list_head debugfs_list;
-
/* Mutex for binner bo allocation. */
struct mutex bin_bo_lock;
/* Reference count for our binner bo. */
@@ -233,7 +233,7 @@ struct vc4_dev {
};
static inline struct vc4_dev *
-to_vc4_dev(struct drm_device *dev)
+to_vc4_dev(const struct drm_device *dev)
{
return container_of(dev, struct vc4_dev, base);
}
@@ -286,7 +286,7 @@ struct vc4_bo {
};
static inline struct vc4_bo *
-to_vc4_bo(struct drm_gem_object *bo)
+to_vc4_bo(const struct drm_gem_object *bo)
{
return container_of(to_drm_gem_dma_obj(bo), struct vc4_bo, base);
}
@@ -299,7 +299,7 @@ struct vc4_fence {
};
static inline struct vc4_fence *
-to_vc4_fence(struct dma_fence *fence)
+to_vc4_fence(const struct dma_fence *fence)
{
return container_of(fence, struct vc4_fence, base);
}
@@ -355,12 +355,35 @@ struct vc4_hvs {
bool vc5_hdmi_enable_4096by2160;
};
+#define HVS_NUM_CHANNELS 3
+
+struct vc4_hvs_state {
+ struct drm_private_state base;
+ unsigned long core_clock_rate;
+
+ struct {
+ unsigned in_use: 1;
+ unsigned long fifo_load;
+ struct drm_crtc_commit *pending_commit;
+ } fifo_state[HVS_NUM_CHANNELS];
+};
+
+static inline struct vc4_hvs_state *
+to_vc4_hvs_state(const struct drm_private_state *priv)
+{
+ return container_of(priv, struct vc4_hvs_state, base);
+}
+
+struct vc4_hvs_state *vc4_hvs_get_global_state(struct drm_atomic_state *state);
+struct vc4_hvs_state *vc4_hvs_get_old_global_state(const struct drm_atomic_state *state);
+struct vc4_hvs_state *vc4_hvs_get_new_global_state(const struct drm_atomic_state *state);
+
struct vc4_plane {
struct drm_plane base;
};
static inline struct vc4_plane *
-to_vc4_plane(struct drm_plane *plane)
+to_vc4_plane(const struct drm_plane *plane)
{
return container_of(plane, struct vc4_plane, base);
}
@@ -436,7 +459,7 @@ struct vc4_plane_state {
};
static inline struct vc4_plane_state *
-to_vc4_plane_state(struct drm_plane_state *state)
+to_vc4_plane_state(const struct drm_plane_state *state)
{
return container_of(state, struct vc4_plane_state, base);
}
@@ -450,6 +473,7 @@ enum vc4_encoder_type {
VC4_ENCODER_TYPE_DSI1,
VC4_ENCODER_TYPE_SMI,
VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_TXP,
};
struct vc4_encoder {
@@ -466,12 +490,30 @@ struct vc4_encoder {
};
static inline struct vc4_encoder *
-to_vc4_encoder(struct drm_encoder *encoder)
+to_vc4_encoder(const struct drm_encoder *encoder)
{
return container_of(encoder, struct vc4_encoder, base);
}
+static inline
+struct drm_encoder *vc4_find_encoder_by_type(struct drm_device *drm,
+ enum vc4_encoder_type type)
+{
+ struct drm_encoder *encoder;
+
+ drm_for_each_encoder(encoder, drm) {
+ struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
+
+ if (vc4_encoder->type == type)
+ return encoder;
+ }
+
+ return NULL;
+}
+
struct vc4_crtc_data {
+ const char *name;
+
const char *debugfs_name;
/* Bitmask of channels (FIFOs) of the HVS that the output can source from */
@@ -481,6 +523,8 @@ struct vc4_crtc_data {
int hvs_output;
};
+extern const struct vc4_crtc_data vc4_txp_crtc_data;
+
struct vc4_pv_data {
struct vc4_crtc_data base;
@@ -493,6 +537,15 @@ struct vc4_pv_data {
enum vc4_encoder_type encoder_types[4];
};
+extern const struct vc4_pv_data bcm2835_pv0_data;
+extern const struct vc4_pv_data bcm2835_pv1_data;
+extern const struct vc4_pv_data bcm2835_pv2_data;
+extern const struct vc4_pv_data bcm2711_pv0_data;
+extern const struct vc4_pv_data bcm2711_pv1_data;
+extern const struct vc4_pv_data bcm2711_pv2_data;
+extern const struct vc4_pv_data bcm2711_pv3_data;
+extern const struct vc4_pv_data bcm2711_pv4_data;
+
struct vc4_crtc {
struct drm_crtc base;
struct platform_device *pdev;
@@ -539,7 +592,7 @@ struct vc4_crtc {
};
static inline struct vc4_crtc *
-to_vc4_crtc(struct drm_crtc *crtc)
+to_vc4_crtc(const struct drm_crtc *crtc)
{
return container_of(crtc, struct vc4_crtc, base);
}
@@ -584,15 +637,34 @@ struct vc4_crtc_state {
#define VC4_HVS_CHANNEL_DISABLED ((unsigned int)-1)
static inline struct vc4_crtc_state *
-to_vc4_crtc_state(struct drm_crtc_state *crtc_state)
+to_vc4_crtc_state(const struct drm_crtc_state *crtc_state)
{
return container_of(crtc_state, struct vc4_crtc_state, base);
}
-#define V3D_READ(offset) readl(vc4->v3d->regs + offset)
-#define V3D_WRITE(offset, val) writel(val, vc4->v3d->regs + offset)
-#define HVS_READ(offset) readl(hvs->regs + offset)
-#define HVS_WRITE(offset, val) writel(val, hvs->regs + offset)
+#define V3D_READ(offset) \
+ ({ \
+ kunit_fail_current_test("Accessing a register in a unit test!\n"); \
+ readl(vc4->v3d->regs + (offset)); \
+ })
+
+#define V3D_WRITE(offset, val) \
+ do { \
+ kunit_fail_current_test("Accessing a register in a unit test!\n"); \
+ writel(val, vc4->v3d->regs + (offset)); \
+ } while (0)
+
+#define HVS_READ(offset) \
+ ({ \
+ kunit_fail_current_test("Accessing a register in a unit test!\n"); \
+ readl(hvs->regs + (offset)); \
+ })
+
+#define HVS_WRITE(offset, val) \
+ do { \
+ kunit_fail_current_test("Accessing a register in a unit test!\n"); \
+ writel(val, hvs->regs + (offset)); \
+ } while (0)
#define VC4_REG32(reg) { .name = #reg, .offset = reg }
@@ -862,14 +934,24 @@ int vc4_bo_debugfs_init(struct drm_minor *minor);
/* vc4_crtc.c */
extern struct platform_driver vc4_crtc_driver;
int vc4_crtc_disable_at_boot(struct drm_crtc *crtc);
-int vc4_crtc_init(struct drm_device *drm, struct vc4_crtc *vc4_crtc,
+int __vc4_crtc_init(struct drm_device *drm, struct platform_device *pdev,
+ struct vc4_crtc *vc4_crtc, const struct vc4_crtc_data *data,
+ struct drm_plane *primary_plane,
+ const struct drm_crtc_funcs *crtc_funcs,
+ const struct drm_crtc_helper_funcs *crtc_helper_funcs,
+ bool feeds_txp);
+int vc4_crtc_init(struct drm_device *drm, struct platform_device *pdev,
+ struct vc4_crtc *vc4_crtc, const struct vc4_crtc_data *data,
const struct drm_crtc_funcs *crtc_funcs,
- const struct drm_crtc_helper_funcs *crtc_helper_funcs);
+ const struct drm_crtc_helper_funcs *crtc_helper_funcs,
+ bool feeds_txp);
int vc4_page_flip(struct drm_crtc *crtc,
struct drm_framebuffer *fb,
struct drm_pending_vblank_event *event,
uint32_t flags,
struct drm_modeset_acquire_ctx *ctx);
+int vc4_crtc_atomic_check(struct drm_crtc *crtc,
+ struct drm_atomic_state *state);
struct drm_crtc_state *vc4_crtc_duplicate_state(struct drm_crtc *crtc);
void vc4_crtc_destroy_state(struct drm_crtc *crtc,
struct drm_crtc_state *state);
@@ -884,28 +966,15 @@ void vc4_crtc_get_margins(struct drm_crtc_state *state,
/* vc4_debugfs.c */
void vc4_debugfs_init(struct drm_minor *minor);
#ifdef CONFIG_DEBUG_FS
-int vc4_debugfs_add_file(struct drm_minor *minor,
- const char *filename,
- int (*show)(struct seq_file*, void*),
- void *data);
-int vc4_debugfs_add_regset32(struct drm_minor *minor,
- const char *filename,
- struct debugfs_regset32 *regset);
+void vc4_debugfs_add_regset32(struct drm_device *drm,
+ const char *filename,
+ struct debugfs_regset32 *regset);
#else
-static inline int vc4_debugfs_add_file(struct drm_minor *minor,
- const char *filename,
- int (*show)(struct seq_file*, void*),
- void *data)
-{
- return 0;
-}
-static inline int vc4_debugfs_add_regset32(struct drm_minor *minor,
- const char *filename,
- struct debugfs_regset32 *regset)
-{
- return 0;
-}
+static inline void vc4_debugfs_add_regset32(struct drm_device *drm,
+ const char *filename,
+ struct debugfs_regset32 *regset)
+{}
#endif
/* vc4_drv.c */
@@ -959,6 +1028,7 @@ void vc4_irq_reset(struct drm_device *dev);
/* vc4_hvs.c */
extern struct platform_driver vc4_hvs_driver;
+struct vc4_hvs *__vc4_hvs_alloc(struct vc4_dev *vc4, struct platform_device *pdev);
void vc4_hvs_stop_channel(struct vc4_hvs *hvs, unsigned int output);
int vc4_hvs_get_fifo_from_output(struct vc4_hvs *hvs, unsigned int output);
u8 vc4_hvs_get_fifo_frame_count(struct vc4_hvs *hvs, unsigned int fifo);
diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c
index 878e05d79e81..a5c075f802e4 100644
--- a/drivers/gpu/drm/vc4/vc4_dsi.c
+++ b/drivers/gpu/drm/vc4/vc4_dsi.c
@@ -24,7 +24,6 @@
#include <linux/component.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
-#include <linux/i2c.h>
#include <linux/io.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
@@ -556,8 +555,8 @@ struct vc4_dsi {
struct platform_device *pdev;
- struct drm_bridge *bridge;
- struct list_head bridge_chain;
+ struct drm_bridge *out_bridge;
+ struct drm_bridge bridge;
void __iomem *regs;
@@ -609,6 +608,12 @@ to_vc4_dsi(struct drm_encoder *encoder)
return container_of(encoder, struct vc4_dsi, encoder.base);
}
+static inline struct vc4_dsi *
+bridge_to_vc4_dsi(struct drm_bridge *bridge)
+{
+ return container_of(bridge, struct vc4_dsi, bridge);
+}
+
static inline void
dsi_dma_workaround_write(struct vc4_dsi *dsi, u32 offset, u32 val)
{
@@ -617,6 +622,8 @@ dsi_dma_workaround_write(struct vc4_dsi *dsi, u32 offset, u32 val)
dma_cookie_t cookie;
int ret;
+ kunit_fail_current_test("Accessing a register in a unit test!\n");
+
/* DSI0 should be able to write normally. */
if (!chan) {
writel(val, dsi->regs + offset);
@@ -645,7 +652,12 @@ dsi_dma_workaround_write(struct vc4_dsi *dsi, u32 offset, u32 val)
DRM_ERROR("Failed to wait for DMA: %d\n", ret);
}
-#define DSI_READ(offset) readl(dsi->regs + (offset))
+#define DSI_READ(offset) \
+ ({ \
+ kunit_fail_current_test("Accessing a register in a unit test!\n"); \
+ readl(dsi->regs + (offset)); \
+ })
+
#define DSI_WRITE(offset, val) dsi_dma_workaround_write(dsi, offset, val)
#define DSI_PORT_READ(offset) \
DSI_READ(dsi->variant->port ? DSI1_##offset : DSI0_##offset)
@@ -790,26 +802,22 @@ dsi_esc_timing(u32 ns)
return DIV_ROUND_UP(ns, ESC_TIME_NS);
}
-static void vc4_dsi_encoder_disable(struct drm_encoder *encoder)
+static void vc4_dsi_bridge_disable(struct drm_bridge *bridge,
+ struct drm_bridge_state *state)
{
- struct vc4_dsi *dsi = to_vc4_dsi(encoder);
- struct device *dev = &dsi->pdev->dev;
- struct drm_bridge *iter;
-
- list_for_each_entry_reverse(iter, &dsi->bridge_chain, chain_node) {
- if (iter->funcs->disable)
- iter->funcs->disable(iter);
+ struct vc4_dsi *dsi = bridge_to_vc4_dsi(bridge);
+ u32 disp0_ctrl;
- if (iter == dsi->bridge)
- break;
- }
-
- vc4_dsi_ulps(dsi, true);
+ disp0_ctrl = DSI_PORT_READ(DISP0_CTRL);
+ disp0_ctrl &= ~DSI_DISP0_ENABLE;
+ DSI_PORT_WRITE(DISP0_CTRL, disp0_ctrl);
+}
- list_for_each_entry_from(iter, &dsi->bridge_chain, chain_node) {
- if (iter->funcs->post_disable)
- iter->funcs->post_disable(iter);
- }
+static void vc4_dsi_bridge_post_disable(struct drm_bridge *bridge,
+ struct drm_bridge_state *state)
+{
+ struct vc4_dsi *dsi = bridge_to_vc4_dsi(bridge);
+ struct device *dev = &dsi->pdev->dev;
clk_disable_unprepare(dsi->pll_phy_clock);
clk_disable_unprepare(dsi->escape_clock);
@@ -831,11 +839,11 @@ static void vc4_dsi_encoder_disable(struct drm_encoder *encoder)
* higher-than-expected clock rate to the panel, but that's what the
* firmware does too.
*/
-static bool vc4_dsi_encoder_mode_fixup(struct drm_encoder *encoder,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
+static bool vc4_dsi_bridge_mode_fixup(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
{
- struct vc4_dsi *dsi = to_vc4_dsi(encoder);
+ struct vc4_dsi *dsi = bridge_to_vc4_dsi(bridge);
struct clk *phy_parent = clk_get_parent(dsi->pll_phy_clock);
unsigned long parent_rate = clk_get_rate(phy_parent);
unsigned long pixel_clock_hz = mode->clock * 1000;
@@ -867,18 +875,22 @@ static bool vc4_dsi_encoder_mode_fixup(struct drm_encoder *encoder,
return true;
}
-static void vc4_dsi_encoder_enable(struct drm_encoder *encoder)
+static void vc4_dsi_bridge_pre_enable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_state)
{
- struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
- struct vc4_dsi *dsi = to_vc4_dsi(encoder);
+ struct drm_atomic_state *state = old_state->base.state;
+ struct vc4_dsi *dsi = bridge_to_vc4_dsi(bridge);
+ const struct drm_crtc_state *crtc_state;
struct device *dev = &dsi->pdev->dev;
+ const struct drm_display_mode *mode;
+ struct drm_connector *connector;
bool debug_dump_regs = false;
- struct drm_bridge *iter;
unsigned long hs_clock;
+ struct drm_crtc *crtc;
u32 ui_ns;
/* Minimum LP state duration in escape clock cycles. */
u32 lpx = dsi_esc_timing(60);
- unsigned long pixel_clock_hz = mode->clock * 1000;
+ unsigned long pixel_clock_hz;
unsigned long dsip_clock;
unsigned long phy_clock;
int ret;
@@ -895,6 +907,18 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder)
drm_print_regset32(&p, &dsi->regset);
}
+ /*
+ * Retrieve the CRTC adjusted mode. This requires a little dance to go
+ * from the bridge to the encoder, to the connector and to the CRTC.
+ */
+ connector = drm_atomic_get_new_connector_for_encoder(state,
+ bridge->encoder);
+ crtc = drm_atomic_get_new_connector_state(state, connector)->crtc;
+ crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+ mode = &crtc_state->adjusted_mode;
+
+ pixel_clock_hz = mode->clock * 1000;
+
/* Round up the clk_set_rate() request slightly, since
* PLLD_DSI1 is an integer divider and its rate selection will
* never round up.
@@ -1106,11 +1130,6 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder)
vc4_dsi_ulps(dsi, false);
- list_for_each_entry_reverse(iter, &dsi->bridge_chain, chain_node) {
- if (iter->funcs->pre_enable)
- iter->funcs->pre_enable(iter);
- }
-
if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
DSI_PORT_WRITE(DISP0_CTRL,
VC4_SET_FIELD(dsi->divider,
@@ -1118,18 +1137,23 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder)
VC4_SET_FIELD(dsi->format, DSI_DISP0_PFORMAT) |
VC4_SET_FIELD(DSI_DISP0_LP_STOP_PERFRAME,
DSI_DISP0_LP_STOP_CTRL) |
- DSI_DISP0_ST_END |
- DSI_DISP0_ENABLE);
+ DSI_DISP0_ST_END);
} else {
DSI_PORT_WRITE(DISP0_CTRL,
- DSI_DISP0_COMMAND_MODE |
- DSI_DISP0_ENABLE);
+ DSI_DISP0_COMMAND_MODE);
}
+}
- list_for_each_entry(iter, &dsi->bridge_chain, chain_node) {
- if (iter->funcs->enable)
- iter->funcs->enable(iter);
- }
+static void vc4_dsi_bridge_enable(struct drm_bridge *bridge,
+ struct drm_bridge_state *old_state)
+{
+ struct vc4_dsi *dsi = bridge_to_vc4_dsi(bridge);
+ bool debug_dump_regs = false;
+ u32 disp0_ctrl;
+
+ disp0_ctrl = DSI_PORT_READ(DISP0_CTRL);
+ disp0_ctrl |= DSI_DISP0_ENABLE;
+ DSI_PORT_WRITE(DISP0_CTRL, disp0_ctrl);
if (debug_dump_regs) {
struct drm_printer p = drm_info_printer(&dsi->pdev->dev);
@@ -1138,6 +1162,16 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder)
}
}
+static int vc4_dsi_bridge_attach(struct drm_bridge *bridge,
+ enum drm_bridge_attach_flags flags)
+{
+ struct vc4_dsi *dsi = bridge_to_vc4_dsi(bridge);
+
+ /* Attach the panel or bridge to the dsi bridge */
+ return drm_bridge_attach(bridge->encoder, dsi->out_bridge,
+ &dsi->bridge, flags);
+}
+
static ssize_t vc4_dsi_host_transfer(struct mipi_dsi_host *host,
const struct mipi_dsi_msg *msg)
{
@@ -1314,6 +1348,7 @@ static int vc4_dsi_host_attach(struct mipi_dsi_host *host,
struct mipi_dsi_device *device)
{
struct vc4_dsi *dsi = host_to_dsi(host);
+ int ret;
dsi->lanes = device->lanes;
dsi->channel = device->channel;
@@ -1348,7 +1383,15 @@ static int vc4_dsi_host_attach(struct mipi_dsi_host *host,
return 0;
}
- return component_add(&dsi->pdev->dev, &vc4_dsi_ops);
+ drm_bridge_add(&dsi->bridge);
+
+ ret = component_add(&dsi->pdev->dev, &vc4_dsi_ops);
+ if (ret) {
+ drm_bridge_remove(&dsi->bridge);
+ return ret;
+ }
+
+ return 0;
}
static int vc4_dsi_host_detach(struct mipi_dsi_host *host,
@@ -1357,6 +1400,7 @@ static int vc4_dsi_host_detach(struct mipi_dsi_host *host,
struct vc4_dsi *dsi = host_to_dsi(host);
component_del(&dsi->pdev->dev, &vc4_dsi_ops);
+ drm_bridge_remove(&dsi->bridge);
return 0;
}
@@ -1366,22 +1410,24 @@ static const struct mipi_dsi_host_ops vc4_dsi_host_ops = {
.transfer = vc4_dsi_host_transfer,
};
-static const struct drm_encoder_helper_funcs vc4_dsi_encoder_helper_funcs = {
- .disable = vc4_dsi_encoder_disable,
- .enable = vc4_dsi_encoder_enable,
- .mode_fixup = vc4_dsi_encoder_mode_fixup,
+static const struct drm_bridge_funcs vc4_dsi_bridge_funcs = {
+ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
+ .atomic_reset = drm_atomic_helper_bridge_reset,
+ .atomic_pre_enable = vc4_dsi_bridge_pre_enable,
+ .atomic_enable = vc4_dsi_bridge_enable,
+ .atomic_disable = vc4_dsi_bridge_disable,
+ .atomic_post_disable = vc4_dsi_bridge_post_disable,
+ .attach = vc4_dsi_bridge_attach,
+ .mode_fixup = vc4_dsi_bridge_mode_fixup,
};
static int vc4_dsi_late_register(struct drm_encoder *encoder)
{
struct drm_device *drm = encoder->dev;
struct vc4_dsi *dsi = to_vc4_dsi(encoder);
- int ret;
- ret = vc4_debugfs_add_regset32(drm->primary, dsi->variant->debugfs_name,
- &dsi->regset);
- if (ret)
- return ret;
+ vc4_debugfs_add_regset32(drm, dsi->variant->debugfs_name, &dsi->regset);
return 0;
}
@@ -1617,7 +1663,6 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
dsi->variant = of_device_get_match_data(dev);
- INIT_LIST_HEAD(&dsi->bridge_chain);
dsi->encoder.type = dsi->variant->port ?
VC4_ENCODER_TYPE_DSI1 : VC4_ENCODER_TYPE_DSI0;
@@ -1723,9 +1768,9 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
return ret;
}
- dsi->bridge = drmm_of_get_bridge(drm, dev->of_node, 0, 0);
- if (IS_ERR(dsi->bridge))
- return PTR_ERR(dsi->bridge);
+ dsi->out_bridge = drmm_of_get_bridge(drm, dev->of_node, 0, 0);
+ if (IS_ERR(dsi->out_bridge))
+ return PTR_ERR(dsi->out_bridge);
/* The esc clock rate is supposed to always be 100Mhz. */
ret = clk_set_rate(dsi->escape_clock, 100 * 1000000);
@@ -1745,41 +1790,19 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
if (ret)
return ret;
- drm_encoder_helper_add(encoder, &vc4_dsi_encoder_helper_funcs);
-
ret = devm_pm_runtime_enable(dev);
if (ret)
return ret;
- ret = drm_bridge_attach(encoder, dsi->bridge, NULL, 0);
+ ret = drm_bridge_attach(encoder, &dsi->bridge, NULL, 0);
if (ret)
return ret;
- /* Disable the atomic helper calls into the bridge. We
- * manually call the bridge pre_enable / enable / etc. calls
- * from our driver, since we need to sequence them within the
- * encoder's enable/disable paths.
- */
- list_splice_init(&encoder->bridge_chain, &dsi->bridge_chain);
return 0;
}
-static void vc4_dsi_unbind(struct device *dev, struct device *master,
- void *data)
-{
- struct vc4_dsi *dsi = dev_get_drvdata(dev);
- struct drm_encoder *encoder = &dsi->encoder.base;
-
- /*
- * Restore the bridge_chain so the bridge detach procedure can happen
- * normally.
- */
- list_splice_init(&dsi->bridge_chain, &encoder->bridge_chain);
-}
-
static const struct component_ops vc4_dsi_ops = {
.bind = vc4_dsi_bind,
- .unbind = vc4_dsi_unbind,
};
static int vc4_dsi_dev_probe(struct platform_device *pdev)
@@ -1793,7 +1816,13 @@ static int vc4_dsi_dev_probe(struct platform_device *pdev)
dev_set_drvdata(dev, dsi);
kref_init(&dsi->kref);
+
dsi->pdev = pdev;
+ dsi->bridge.funcs = &vc4_dsi_bridge_funcs;
+#ifdef CONFIG_OF
+ dsi->bridge.of_node = dev->of_node;
+#endif
+ dsi->bridge.type = DRM_MODE_CONNECTOR_DSI;
dsi->dsi_host.ops = &vc4_dsi_host_ops;
dsi->dsi_host.dev = dev;
mipi_dsi_host_register(&dsi->dsi_host);
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 7546103f1499..ea22c9bf223a 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -164,8 +164,8 @@ static bool vc4_hdmi_is_full_range_rgb(struct vc4_hdmi *vc4_hdmi,
static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused)
{
- struct drm_info_node *node = (struct drm_info_node *)m->private;
- struct vc4_hdmi *vc4_hdmi = node->info_ent->data;
+ struct drm_debugfs_entry *entry = m->private;
+ struct vc4_hdmi *vc4_hdmi = entry->file.data;
struct drm_device *drm = vc4_hdmi->connector.dev;
struct drm_printer p = drm_seq_file_printer(m);
int idx;
@@ -406,6 +406,7 @@ static void vc4_hdmi_handle_hotplug(struct vc4_hdmi *vc4_hdmi,
{
struct drm_connector *connector = &vc4_hdmi->connector;
struct edid *edid;
+ int ret;
/*
* NOTE: This function should really be called with
@@ -434,7 +435,15 @@ static void vc4_hdmi_handle_hotplug(struct vc4_hdmi *vc4_hdmi,
cec_s_phys_addr_from_edid(vc4_hdmi->cec_adap, edid);
kfree(edid);
- vc4_hdmi_reset_link(connector, ctx);
+ for (;;) {
+ ret = vc4_hdmi_reset_link(connector, ctx);
+ if (ret == -EDEADLK) {
+ drm_modeset_backoff(ctx);
+ continue;
+ }
+
+ break;
+ }
}
static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector,
@@ -1302,11 +1311,12 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
VC4_SET_FIELD(mode->crtc_vdisplay, VC5_HDMI_VERTA_VAL));
u32 vertb = (VC4_SET_FIELD(mode->htotal >> (2 - pixel_rep),
VC5_HDMI_VERTB_VSPO) |
- VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end,
+ VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end +
+ interlaced,
VC4_HDMI_VERTB_VBP));
u32 vertb_even = (VC4_SET_FIELD(0, VC5_HDMI_VERTB_VSPO) |
VC4_SET_FIELD(mode->crtc_vtotal -
- mode->crtc_vsync_end - interlaced,
+ mode->crtc_vsync_end,
VC4_HDMI_VERTB_VBP));
unsigned long flags;
unsigned char gcp;
@@ -1995,13 +2005,9 @@ static int vc4_hdmi_late_register(struct drm_encoder *encoder)
struct drm_device *drm = encoder->dev;
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
const struct vc4_hdmi_variant *variant = vc4_hdmi->variant;
- int ret;
- ret = vc4_debugfs_add_file(drm->primary, variant->debugfs_name,
- vc4_hdmi_debugfs_regs,
- vc4_hdmi);
- if (ret)
- return ret;
+ drm_debugfs_add_file(drm, variant->debugfs_name,
+ vc4_hdmi_debugfs_regs, vc4_hdmi);
return 0;
}
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
index 48db438550b1..b04b2fc8d831 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
+++ b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
@@ -456,6 +456,8 @@ static inline u32 vc4_hdmi_read(struct vc4_hdmi *hdmi,
WARN_ON(pm_runtime_status_suspended(&hdmi->pdev->dev));
+ kunit_fail_current_test("Accessing an HDMI register in a unit test!\n");
+
if (reg >= variant->num_registers) {
dev_warn(&hdmi->pdev->dev,
"Invalid register ID %u\n", reg);
@@ -486,6 +488,8 @@ static inline void vc4_hdmi_write(struct vc4_hdmi *hdmi,
WARN_ON(pm_runtime_status_suspended(&hdmi->pdev->dev));
+ kunit_fail_current_test("Accessing an HDMI register in a unit test!\n");
+
if (reg >= variant->num_registers) {
dev_warn(&hdmi->pdev->dev,
"Invalid register ID %u\n", reg);
diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c
index c4453a5ae163..4da66ef96783 100644
--- a/drivers/gpu/drm/vc4/vc4_hvs.c
+++ b/drivers/gpu/drm/vc4/vc4_hvs.c
@@ -93,8 +93,8 @@ void vc4_hvs_dump_state(struct vc4_hvs *hvs)
static int vc4_hvs_debugfs_underrun(struct seq_file *m, void *data)
{
- struct drm_info_node *node = m->private;
- struct drm_device *dev = node->minor->dev;
+ struct drm_debugfs_entry *entry = m->private;
+ struct drm_device *dev = entry->dev;
struct vc4_dev *vc4 = to_vc4_dev(dev);
struct drm_printer p = drm_seq_file_printer(m);
@@ -105,8 +105,8 @@ static int vc4_hvs_debugfs_underrun(struct seq_file *m, void *data)
static int vc4_hvs_debugfs_dlist(struct seq_file *m, void *data)
{
- struct drm_info_node *node = m->private;
- struct drm_device *dev = node->minor->dev;
+ struct drm_debugfs_entry *entry = m->private;
+ struct drm_device *dev = entry->dev;
struct vc4_dev *vc4 = to_vc4_dev(dev);
struct vc4_hvs *hvs = vc4->hvs;
struct drm_printer p = drm_seq_file_printer(m);
@@ -370,28 +370,30 @@ static int vc4_hvs_init_channel(struct vc4_hvs *hvs, struct drm_crtc *crtc,
* mode.
*/
dispctrl = SCALER_DISPCTRLX_ENABLE;
+ dispbkgndx = HVS_READ(SCALER_DISPBKGNDX(chan));
- if (!vc4->is_vc5)
+ if (!vc4->is_vc5) {
dispctrl |= VC4_SET_FIELD(mode->hdisplay,
SCALER_DISPCTRLX_WIDTH) |
VC4_SET_FIELD(mode->vdisplay,
SCALER_DISPCTRLX_HEIGHT) |
(oneshot ? SCALER_DISPCTRLX_ONESHOT : 0);
- else
+ dispbkgndx |= SCALER_DISPBKGND_AUTOHS;
+ } else {
dispctrl |= VC4_SET_FIELD(mode->hdisplay,
SCALER5_DISPCTRLX_WIDTH) |
VC4_SET_FIELD(mode->vdisplay,
SCALER5_DISPCTRLX_HEIGHT) |
(oneshot ? SCALER5_DISPCTRLX_ONESHOT : 0);
+ dispbkgndx &= ~SCALER5_DISPBKGND_BCK2BCK;
+ }
HVS_WRITE(SCALER_DISPCTRLX(chan), dispctrl);
- dispbkgndx = HVS_READ(SCALER_DISPBKGNDX(chan));
dispbkgndx &= ~SCALER_DISPBKGND_GAMMA;
dispbkgndx &= ~SCALER_DISPBKGND_INTERLACE;
HVS_WRITE(SCALER_DISPBKGNDX(chan), dispbkgndx |
- SCALER_DISPBKGND_AUTOHS |
((!vc4->is_vc5) ? SCALER_DISPBKGND_GAMMA : 0) |
(interlace ? SCALER_DISPBKGND_INTERLACE : 0));
@@ -568,6 +570,8 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc,
bool enable_bg_fill = false;
u32 __iomem *dlist_start = vc4->hvs->dlist + vc4_state->mm.start;
u32 __iomem *dlist_next = dlist_start;
+ unsigned int zpos = 0;
+ bool found = false;
int idx;
if (!drm_dev_enter(dev, &idx)) {
@@ -575,29 +579,43 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc,
return;
}
+ if (vc4_state->assigned_channel == VC4_HVS_CHANNEL_DISABLED)
+ return;
+
if (debug_dump_regs) {
DRM_INFO("CRTC %d HVS before:\n", drm_crtc_index(crtc));
vc4_hvs_dump_state(hvs);
}
/* Copy all the active planes' dlist contents to the hardware dlist. */
- drm_atomic_crtc_for_each_plane(plane, crtc) {
- /* Is this the first active plane? */
- if (dlist_next == dlist_start) {
- /* We need to enable background fill when a plane
- * could be alpha blending from the background, i.e.
- * where no other plane is underneath. It suffices to
- * consider the first active plane here since we set
- * needs_bg_fill such that either the first plane
- * already needs it or all planes on top blend from
- * the first or a lower plane.
- */
- vc4_plane_state = to_vc4_plane_state(plane->state);
- enable_bg_fill = vc4_plane_state->needs_bg_fill;
+ do {
+ found = false;
+
+ drm_atomic_crtc_for_each_plane(plane, crtc) {
+ if (plane->state->normalized_zpos != zpos)
+ continue;
+
+ /* Is this the first active plane? */
+ if (dlist_next == dlist_start) {
+ /* We need to enable background fill when a plane
+ * could be alpha blending from the background, i.e.
+ * where no other plane is underneath. It suffices to
+ * consider the first active plane here since we set
+ * needs_bg_fill such that either the first plane
+ * already needs it or all planes on top blend from
+ * the first or a lower plane.
+ */
+ vc4_plane_state = to_vc4_plane_state(plane->state);
+ enable_bg_fill = vc4_plane_state->needs_bg_fill;
+ }
+
+ dlist_next += vc4_plane_write_dlist(plane, dlist_next);
+
+ found = true;
}
- dlist_next += vc4_plane_write_dlist(plane, dlist_next);
- }
+ zpos++;
+ } while (found);
writel(SCALER_CTL0_END, dlist_next);
dlist_next++;
@@ -658,7 +676,8 @@ void vc4_hvs_mask_underrun(struct vc4_hvs *hvs, int channel)
return;
dispctrl = HVS_READ(SCALER_DISPCTRL);
- dispctrl &= ~SCALER_DISPCTRL_DSPEISLUR(channel);
+ dispctrl &= ~(hvs->vc4->is_vc5 ? SCALER5_DISPCTRL_DSPEISLUR(channel) :
+ SCALER_DISPCTRL_DSPEISLUR(channel));
HVS_WRITE(SCALER_DISPCTRL, dispctrl);
@@ -675,7 +694,8 @@ void vc4_hvs_unmask_underrun(struct vc4_hvs *hvs, int channel)
return;
dispctrl = HVS_READ(SCALER_DISPCTRL);
- dispctrl |= SCALER_DISPCTRL_DSPEISLUR(channel);
+ dispctrl |= (hvs->vc4->is_vc5 ? SCALER5_DISPCTRL_DSPEISLUR(channel) :
+ SCALER_DISPCTRL_DSPEISLUR(channel));
HVS_WRITE(SCALER_DISPSTAT,
SCALER_DISPSTAT_EUFLOW(channel));
@@ -701,6 +721,7 @@ static irqreturn_t vc4_hvs_irq_handler(int irq, void *data)
int channel;
u32 control;
u32 status;
+ u32 dspeislur;
/*
* NOTE: We don't need to protect the register access using
@@ -717,9 +738,11 @@ static irqreturn_t vc4_hvs_irq_handler(int irq, void *data)
control = HVS_READ(SCALER_DISPCTRL);
for (channel = 0; channel < SCALER_CHANNELS_COUNT; channel++) {
+ dspeislur = vc4->is_vc5 ? SCALER5_DISPCTRL_DSPEISLUR(channel) :
+ SCALER_DISPCTRL_DSPEISLUR(channel);
/* Interrupt masking is not always honored, so check it here. */
if (status & SCALER_DISPSTAT_EUFLOW(channel) &&
- control & SCALER_DISPCTRL_DSPEISLUR(channel)) {
+ control & dspeislur) {
vc4_hvs_mask_underrun(hvs, channel);
vc4_hvs_report_underrun(dev);
@@ -740,7 +763,6 @@ int vc4_hvs_debugfs_init(struct drm_minor *minor)
struct drm_device *drm = minor->dev;
struct vc4_dev *vc4 = to_vc4_dev(drm);
struct vc4_hvs *hvs = vc4->hvs;
- int ret;
if (!vc4->hvs)
return -ENODEV;
@@ -750,24 +772,55 @@ int vc4_hvs_debugfs_init(struct drm_minor *minor)
minor->debugfs_root,
&vc4->load_tracker_enabled);
- ret = vc4_debugfs_add_file(minor, "hvs_dlists",
- vc4_hvs_debugfs_dlist, NULL);
- if (ret)
- return ret;
+ drm_debugfs_add_file(drm, "hvs_dlists", vc4_hvs_debugfs_dlist, NULL);
- ret = vc4_debugfs_add_file(minor, "hvs_underrun",
- vc4_hvs_debugfs_underrun, NULL);
- if (ret)
- return ret;
+ drm_debugfs_add_file(drm, "hvs_underrun", vc4_hvs_debugfs_underrun, NULL);
- ret = vc4_debugfs_add_regset32(minor, "hvs_regs",
- &hvs->regset);
- if (ret)
- return ret;
+ vc4_debugfs_add_regset32(drm, "hvs_regs", &hvs->regset);
return 0;
}
+struct vc4_hvs *__vc4_hvs_alloc(struct vc4_dev *vc4, struct platform_device *pdev)
+{
+ struct drm_device *drm = &vc4->base;
+ struct vc4_hvs *hvs;
+
+ hvs = drmm_kzalloc(drm, sizeof(*hvs), GFP_KERNEL);
+ if (!hvs)
+ return ERR_PTR(-ENOMEM);
+
+ hvs->vc4 = vc4;
+ hvs->pdev = pdev;
+
+ spin_lock_init(&hvs->mm_lock);
+
+ /* Set up the HVS display list memory manager. We never
+ * overwrite the setup from the bootloader (just 128b out of
+ * our 16K), since we don't want to scramble the screen when
+ * transitioning from the firmware's boot setup to runtime.
+ */
+ drm_mm_init(&hvs->dlist_mm,
+ HVS_BOOTLOADER_DLIST_END,
+ (SCALER_DLIST_SIZE >> 2) - HVS_BOOTLOADER_DLIST_END);
+
+ /* Set up the HVS LBM memory manager. We could have some more
+ * complicated data structure that allowed reuse of LBM areas
+ * between planes when they don't overlap on the screen, but
+ * for now we just allocate globally.
+ */
+ if (!vc4->is_vc5)
+ /* 48k words of 2x12-bit pixels */
+ drm_mm_init(&hvs->lbm_mm, 0, 48 * 1024);
+ else
+ /* 60k words of 4x12-bit pixels */
+ drm_mm_init(&hvs->lbm_mm, 0, 60 * 1024);
+
+ vc4->hvs = hvs;
+
+ return hvs;
+}
+
static int vc4_hvs_bind(struct device *dev, struct device *master, void *data)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -776,13 +829,11 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data)
struct vc4_hvs *hvs = NULL;
int ret;
u32 dispctrl;
- u32 reg;
+ u32 reg, top;
- hvs = drmm_kzalloc(drm, sizeof(*hvs), GFP_KERNEL);
- if (!hvs)
- return -ENOMEM;
- hvs->vc4 = vc4;
- hvs->pdev = pdev;
+ hvs = __vc4_hvs_alloc(vc4, NULL);
+ if (IS_ERR(hvs))
+ return PTR_ERR(hvs);
hvs->regs = vc4_ioremap_regs(pdev, 0);
if (IS_ERR(hvs->regs))
@@ -835,29 +886,6 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data)
else
hvs->dlist = hvs->regs + SCALER5_DLIST_START;
- spin_lock_init(&hvs->mm_lock);
-
- /* Set up the HVS display list memory manager. We never
- * overwrite the setup from the bootloader (just 128b out of
- * our 16K), since we don't want to scramble the screen when
- * transitioning from the firmware's boot setup to runtime.
- */
- drm_mm_init(&hvs->dlist_mm,
- HVS_BOOTLOADER_DLIST_END,
- (SCALER_DLIST_SIZE >> 2) - HVS_BOOTLOADER_DLIST_END);
-
- /* Set up the HVS LBM memory manager. We could have some more
- * complicated data structure that allowed reuse of LBM areas
- * between planes when they don't overlap on the screen, but
- * for now we just allocate globally.
- */
- if (!vc4->is_vc5)
- /* 48k words of 2x12-bit pixels */
- drm_mm_init(&hvs->lbm_mm, 0, 48 * 1024);
- else
- /* 60k words of 4x12-bit pixels */
- drm_mm_init(&hvs->lbm_mm, 0, 60 * 1024);
-
/* Upload filter kernels. We only have the one for now, so we
* keep it around for the lifetime of the driver.
*/
@@ -867,8 +895,6 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data)
if (ret)
return ret;
- vc4->hvs = hvs;
-
reg = HVS_READ(SCALER_DISPECTRL);
reg &= ~SCALER_DISPECTRL_DSP2_MUX_MASK;
HVS_WRITE(SCALER_DISPECTRL,
@@ -896,22 +922,102 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data)
SCALER_DISPCTRL_DISPEIRQ(1) |
SCALER_DISPCTRL_DISPEIRQ(2);
- dispctrl &= ~(SCALER_DISPCTRL_DMAEIRQ |
- SCALER_DISPCTRL_SLVWREIRQ |
- SCALER_DISPCTRL_SLVRDEIRQ |
- SCALER_DISPCTRL_DSPEIEOF(0) |
- SCALER_DISPCTRL_DSPEIEOF(1) |
- SCALER_DISPCTRL_DSPEIEOF(2) |
- SCALER_DISPCTRL_DSPEIEOLN(0) |
- SCALER_DISPCTRL_DSPEIEOLN(1) |
- SCALER_DISPCTRL_DSPEIEOLN(2) |
- SCALER_DISPCTRL_DSPEISLUR(0) |
- SCALER_DISPCTRL_DSPEISLUR(1) |
- SCALER_DISPCTRL_DSPEISLUR(2) |
- SCALER_DISPCTRL_SCLEIRQ);
+ if (!vc4->is_vc5)
+ dispctrl &= ~(SCALER_DISPCTRL_DMAEIRQ |
+ SCALER_DISPCTRL_SLVWREIRQ |
+ SCALER_DISPCTRL_SLVRDEIRQ |
+ SCALER_DISPCTRL_DSPEIEOF(0) |
+ SCALER_DISPCTRL_DSPEIEOF(1) |
+ SCALER_DISPCTRL_DSPEIEOF(2) |
+ SCALER_DISPCTRL_DSPEIEOLN(0) |
+ SCALER_DISPCTRL_DSPEIEOLN(1) |
+ SCALER_DISPCTRL_DSPEIEOLN(2) |
+ SCALER_DISPCTRL_DSPEISLUR(0) |
+ SCALER_DISPCTRL_DSPEISLUR(1) |
+ SCALER_DISPCTRL_DSPEISLUR(2) |
+ SCALER_DISPCTRL_SCLEIRQ);
+ else
+ dispctrl &= ~(SCALER_DISPCTRL_DMAEIRQ |
+ SCALER5_DISPCTRL_SLVEIRQ |
+ SCALER5_DISPCTRL_DSPEIEOF(0) |
+ SCALER5_DISPCTRL_DSPEIEOF(1) |
+ SCALER5_DISPCTRL_DSPEIEOF(2) |
+ SCALER5_DISPCTRL_DSPEIEOLN(0) |
+ SCALER5_DISPCTRL_DSPEIEOLN(1) |
+ SCALER5_DISPCTRL_DSPEIEOLN(2) |
+ SCALER5_DISPCTRL_DSPEISLUR(0) |
+ SCALER5_DISPCTRL_DSPEISLUR(1) |
+ SCALER5_DISPCTRL_DSPEISLUR(2) |
+ SCALER_DISPCTRL_SCLEIRQ);
+
+
+ /* Set AXI panic mode.
+ * VC4 panics when < 2 lines in FIFO.
+ * VC5 panics when less than 1 line in the FIFO.
+ */
+ dispctrl &= ~(SCALER_DISPCTRL_PANIC0_MASK |
+ SCALER_DISPCTRL_PANIC1_MASK |
+ SCALER_DISPCTRL_PANIC2_MASK);
+ dispctrl |= VC4_SET_FIELD(2, SCALER_DISPCTRL_PANIC0);
+ dispctrl |= VC4_SET_FIELD(2, SCALER_DISPCTRL_PANIC1);
+ dispctrl |= VC4_SET_FIELD(2, SCALER_DISPCTRL_PANIC2);
HVS_WRITE(SCALER_DISPCTRL, dispctrl);
+ /* Recompute Composite Output Buffer (COB) allocations for the displays
+ */
+ if (!vc4->is_vc5) {
+ /* The COB is 20736 pixels, or just over 10 lines at 2048 wide.
+ * The bottom 2048 pixels are full 32bpp RGBA (intended for the
+ * TXP composing RGBA to memory), whilst the remainder are only
+ * 24bpp RGB.
+ *
+ * Assign 3 lines to channels 1 & 2, and just over 4 lines to
+ * channel 0.
+ */
+ #define VC4_COB_SIZE 20736
+ #define VC4_COB_LINE_WIDTH 2048
+ #define VC4_COB_NUM_LINES 3
+ reg = 0;
+ top = VC4_COB_LINE_WIDTH * VC4_COB_NUM_LINES;
+ reg |= (top - 1) << 16;
+ HVS_WRITE(SCALER_DISPBASE2, reg);
+ reg = top;
+ top += VC4_COB_LINE_WIDTH * VC4_COB_NUM_LINES;
+ reg |= (top - 1) << 16;
+ HVS_WRITE(SCALER_DISPBASE1, reg);
+ reg = top;
+ top = VC4_COB_SIZE;
+ reg |= (top - 1) << 16;
+ HVS_WRITE(SCALER_DISPBASE0, reg);
+ } else {
+ /* The COB is 44416 pixels, or 10.8 lines at 4096 wide.
+ * The bottom 4096 pixels are full RGBA (intended for the TXP
+ * composing RGBA to memory), whilst the remainder are only
+ * RGB. Addressing is always pixel wide.
+ *
+ * Assign 3 lines of 4096 to channels 1 & 2, and just over 4
+ * lines. to channel 0.
+ */
+ #define VC5_COB_SIZE 44416
+ #define VC5_COB_LINE_WIDTH 4096
+ #define VC5_COB_NUM_LINES 3
+ reg = 0;
+ top = VC5_COB_LINE_WIDTH * VC5_COB_NUM_LINES;
+ reg |= top << 16;
+ HVS_WRITE(SCALER_DISPBASE2, reg);
+ top += 16;
+ reg = top;
+ top += VC5_COB_LINE_WIDTH * VC5_COB_NUM_LINES;
+ reg |= top << 16;
+ HVS_WRITE(SCALER_DISPBASE1, reg);
+ top += 16;
+ reg = top;
+ top = VC5_COB_SIZE;
+ reg |= top << 16;
+ HVS_WRITE(SCALER_DISPBASE0, reg);
+ }
+
ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
vc4_hvs_irq_handler, 0, "vc4 hvs", drm);
if (ret)
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
index 8fbeecdf2ec4..a7e3d47c50f4 100644
--- a/drivers/gpu/drm/vc4/vc4_kms.c
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
@@ -12,6 +12,7 @@
*/
#include <linux/clk.h>
+#include <linux/sort.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
@@ -24,8 +25,6 @@
#include "vc4_drv.h"
#include "vc4_regs.h"
-#define HVS_NUM_CHANNELS 3
-
struct vc4_ctm_state {
struct drm_private_state base;
struct drm_color_ctm *ctm;
@@ -38,23 +37,6 @@ to_vc4_ctm_state(const struct drm_private_state *priv)
return container_of(priv, struct vc4_ctm_state, base);
}
-struct vc4_hvs_state {
- struct drm_private_state base;
- unsigned long core_clock_rate;
-
- struct {
- unsigned in_use: 1;
- unsigned long fifo_load;
- struct drm_crtc_commit *pending_commit;
- } fifo_state[HVS_NUM_CHANNELS];
-};
-
-static struct vc4_hvs_state *
-to_vc4_hvs_state(const struct drm_private_state *priv)
-{
- return container_of(priv, struct vc4_hvs_state, base);
-}
-
struct vc4_load_tracker_state {
struct drm_private_state base;
u64 hvs_load;
@@ -190,8 +172,8 @@ vc4_ctm_commit(struct vc4_dev *vc4, struct drm_atomic_state *state)
VC4_SET_FIELD(ctm_state->fifo, SCALER_OLEDOFFS_DISPFIFO));
}
-static struct vc4_hvs_state *
-vc4_hvs_get_new_global_state(struct drm_atomic_state *state)
+struct vc4_hvs_state *
+vc4_hvs_get_new_global_state(const struct drm_atomic_state *state)
{
struct vc4_dev *vc4 = to_vc4_dev(state->dev);
struct drm_private_state *priv_state;
@@ -203,8 +185,8 @@ vc4_hvs_get_new_global_state(struct drm_atomic_state *state)
return to_vc4_hvs_state(priv_state);
}
-static struct vc4_hvs_state *
-vc4_hvs_get_old_global_state(struct drm_atomic_state *state)
+struct vc4_hvs_state *
+vc4_hvs_get_old_global_state(const struct drm_atomic_state *state)
{
struct vc4_dev *vc4 = to_vc4_dev(state->dev);
struct drm_private_state *priv_state;
@@ -216,7 +198,7 @@ vc4_hvs_get_old_global_state(struct drm_atomic_state *state)
return to_vc4_hvs_state(priv_state);
}
-static struct vc4_hvs_state *
+struct vc4_hvs_state *
vc4_hvs_get_global_state(struct drm_atomic_state *state)
{
struct vc4_dev *vc4 = to_vc4_dev(state->dev);
@@ -776,6 +758,20 @@ static int vc4_hvs_channels_obj_init(struct vc4_dev *vc4)
return drmm_add_action_or_reset(&vc4->base, vc4_hvs_channels_obj_fini, NULL);
}
+static int cmp_vc4_crtc_hvs_output(const void *a, const void *b)
+{
+ const struct vc4_crtc *crtc_a =
+ to_vc4_crtc(*(const struct drm_crtc **)a);
+ const struct vc4_crtc_data *data_a =
+ vc4_crtc_to_vc4_crtc_data(crtc_a);
+ const struct vc4_crtc *crtc_b =
+ to_vc4_crtc(*(const struct drm_crtc **)b);
+ const struct vc4_crtc_data *data_b =
+ vc4_crtc_to_vc4_crtc_data(crtc_b);
+
+ return data_a->hvs_output - data_b->hvs_output;
+}
+
/*
* The BCM2711 HVS has up to 7 outputs connected to the pixelvalves and
* the TXP (and therefore all the CRTCs found on that platform).
@@ -810,10 +806,11 @@ static int vc4_pv_muxing_atomic_check(struct drm_device *dev,
struct drm_atomic_state *state)
{
struct vc4_hvs_state *hvs_new_state;
- struct drm_crtc_state *old_crtc_state, *new_crtc_state;
+ struct drm_crtc **sorted_crtcs;
struct drm_crtc *crtc;
unsigned int unassigned_channels = 0;
unsigned int i;
+ int ret;
hvs_new_state = vc4_hvs_get_global_state(state);
if (IS_ERR(hvs_new_state))
@@ -823,15 +820,59 @@ static int vc4_pv_muxing_atomic_check(struct drm_device *dev,
if (!hvs_new_state->fifo_state[i].in_use)
unassigned_channels |= BIT(i);
- for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
- struct vc4_crtc_state *old_vc4_crtc_state =
- to_vc4_crtc_state(old_crtc_state);
- struct vc4_crtc_state *new_vc4_crtc_state =
- to_vc4_crtc_state(new_crtc_state);
- struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+ /*
+ * The problem we have to solve here is that we have up to 7
+ * encoders, connected to up to 6 CRTCs.
+ *
+ * Those CRTCs, depending on the instance, can be routed to 1, 2
+ * or 3 HVS FIFOs, and we need to set the muxing between FIFOs and
+ * outputs in the HVS accordingly.
+ *
+ * It would be pretty hard to come up with an algorithm that
+ * would generically solve this. However, the current routing
+ * trees we support allow us to simplify a bit the problem.
+ *
+ * Indeed, with the current supported layouts, if we try to
+ * assign in the ascending crtc index order the FIFOs, we can't
+ * fall into the situation where an earlier CRTC that had
+ * multiple routes is assigned one that was the only option for
+ * a later CRTC.
+ *
+ * If the layout changes and doesn't give us that in the future,
+ * we will need to have something smarter, but it works so far.
+ */
+ sorted_crtcs = kmalloc_array(dev->num_crtcs, sizeof(*sorted_crtcs), GFP_KERNEL);
+ if (!sorted_crtcs)
+ return -ENOMEM;
+
+ i = 0;
+ drm_for_each_crtc(crtc, dev)
+ sorted_crtcs[i++] = crtc;
+
+ sort(sorted_crtcs, i, sizeof(*sorted_crtcs), cmp_vc4_crtc_hvs_output, NULL);
+
+ for (i = 0; i < dev->num_crtcs; i++) {
+ struct vc4_crtc_state *old_vc4_crtc_state, *new_vc4_crtc_state;
+ struct drm_crtc_state *old_crtc_state, *new_crtc_state;
+ struct vc4_crtc *vc4_crtc;
unsigned int matching_channels;
unsigned int channel;
+ crtc = sorted_crtcs[i];
+ if (!crtc)
+ continue;
+ vc4_crtc = to_vc4_crtc(crtc);
+
+ old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc);
+ if (!old_crtc_state)
+ continue;
+ old_vc4_crtc_state = to_vc4_crtc_state(old_crtc_state);
+
+ new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+ if (!new_crtc_state)
+ continue;
+ new_vc4_crtc_state = to_vc4_crtc_state(new_crtc_state);
+
drm_dbg(dev, "%s: Trying to find a channel.\n", crtc->name);
/* Nothing to do here, let's skip it */
@@ -860,33 +901,11 @@ static int vc4_pv_muxing_atomic_check(struct drm_device *dev,
continue;
}
- /*
- * The problem we have to solve here is that we have
- * up to 7 encoders, connected to up to 6 CRTCs.
- *
- * Those CRTCs, depending on the instance, can be
- * routed to 1, 2 or 3 HVS FIFOs, and we need to set
- * the change the muxing between FIFOs and outputs in
- * the HVS accordingly.
- *
- * It would be pretty hard to come up with an
- * algorithm that would generically solve
- * this. However, the current routing trees we support
- * allow us to simplify a bit the problem.
- *
- * Indeed, with the current supported layouts, if we
- * try to assign in the ascending crtc index order the
- * FIFOs, we can't fall into the situation where an
- * earlier CRTC that had multiple routes is assigned
- * one that was the only option for a later CRTC.
- *
- * If the layout changes and doesn't give us that in
- * the future, we will need to have something smarter,
- * but it works so far.
- */
matching_channels = unassigned_channels & vc4_crtc->data->hvs_available_channels;
- if (!matching_channels)
- return -EINVAL;
+ if (!matching_channels) {
+ ret = -EINVAL;
+ goto err_free_crtc_array;
+ }
channel = ffs(matching_channels) - 1;
@@ -896,7 +915,12 @@ static int vc4_pv_muxing_atomic_check(struct drm_device *dev,
hvs_new_state->fifo_state[channel].in_use = true;
}
+ kfree(sorted_crtcs);
return 0;
+
+err_free_crtc_array:
+ kfree(sorted_crtcs);
+ return ret;
}
static int
@@ -1050,6 +1074,7 @@ int vc4_kms_load(struct drm_device *dev)
dev->mode_config.helper_private = &vc4_mode_config_helpers;
dev->mode_config.preferred_depth = 24;
dev->mode_config.async_page_flip = true;
+ dev->mode_config.normalize_zpos = true;
ret = vc4_ctm_obj_init(vc4);
if (ret)
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
index bd5acc4a8687..97c84a3f5a46 100644
--- a/drivers/gpu/drm/vc4/vc4_plane.c
+++ b/drivers/gpu/drm/vc4/vc4_plane.c
@@ -65,78 +65,176 @@ static const struct hvs_format {
.drm = DRM_FORMAT_RGB565,
.hvs = HVS_PIXEL_FORMAT_RGB565,
.pixel_order = HVS_PIXEL_ORDER_XRGB,
+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_XRGB,
},
{
.drm = DRM_FORMAT_BGR565,
.hvs = HVS_PIXEL_FORMAT_RGB565,
.pixel_order = HVS_PIXEL_ORDER_XBGR,
+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_XBGR,
},
{
.drm = DRM_FORMAT_ARGB1555,
.hvs = HVS_PIXEL_FORMAT_RGBA5551,
.pixel_order = HVS_PIXEL_ORDER_ABGR,
+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,
},
{
.drm = DRM_FORMAT_XRGB1555,
.hvs = HVS_PIXEL_FORMAT_RGBA5551,
.pixel_order = HVS_PIXEL_ORDER_ABGR,
+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,
},
{
.drm = DRM_FORMAT_RGB888,
.hvs = HVS_PIXEL_FORMAT_RGB888,
.pixel_order = HVS_PIXEL_ORDER_XRGB,
+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_XRGB,
},
{
.drm = DRM_FORMAT_BGR888,
.hvs = HVS_PIXEL_FORMAT_RGB888,
.pixel_order = HVS_PIXEL_ORDER_XBGR,
+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_XBGR,
},
{
.drm = DRM_FORMAT_YUV422,
.hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE,
.pixel_order = HVS_PIXEL_ORDER_XYCBCR,
+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCBCR,
},
{
.drm = DRM_FORMAT_YVU422,
.hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE,
.pixel_order = HVS_PIXEL_ORDER_XYCRCB,
+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCRCB,
},
{
.drm = DRM_FORMAT_YUV420,
.hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE,
.pixel_order = HVS_PIXEL_ORDER_XYCBCR,
+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCBCR,
},
{
.drm = DRM_FORMAT_YVU420,
.hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE,
.pixel_order = HVS_PIXEL_ORDER_XYCRCB,
+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCRCB,
},
{
.drm = DRM_FORMAT_NV12,
.hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE,
.pixel_order = HVS_PIXEL_ORDER_XYCBCR,
+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCBCR,
},
{
.drm = DRM_FORMAT_NV21,
.hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE,
.pixel_order = HVS_PIXEL_ORDER_XYCRCB,
+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCRCB,
},
{
.drm = DRM_FORMAT_NV16,
.hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE,
.pixel_order = HVS_PIXEL_ORDER_XYCBCR,
+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCBCR,
},
{
.drm = DRM_FORMAT_NV61,
.hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE,
.pixel_order = HVS_PIXEL_ORDER_XYCRCB,
+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCRCB,
},
{
.drm = DRM_FORMAT_P030,
.hvs = HVS_PIXEL_FORMAT_YCBCR_10BIT,
- .pixel_order = HVS_PIXEL_ORDER_XYCBCR,
+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_XYCBCR,
+ .hvs5_only = true,
+ },
+ {
+ .drm = DRM_FORMAT_XRGB2101010,
+ .hvs = HVS_PIXEL_FORMAT_RGBA1010102,
+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,
+ .hvs5_only = true,
+ },
+ {
+ .drm = DRM_FORMAT_ARGB2101010,
+ .hvs = HVS_PIXEL_FORMAT_RGBA1010102,
+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,
+ .hvs5_only = true,
+ },
+ {
+ .drm = DRM_FORMAT_ABGR2101010,
+ .hvs = HVS_PIXEL_FORMAT_RGBA1010102,
+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_ABGR,
.hvs5_only = true,
},
+ {
+ .drm = DRM_FORMAT_XBGR2101010,
+ .hvs = HVS_PIXEL_FORMAT_RGBA1010102,
+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_ABGR,
+ .hvs5_only = true,
+ },
+ {
+ .drm = DRM_FORMAT_RGB332,
+ .hvs = HVS_PIXEL_FORMAT_RGB332,
+ .pixel_order = HVS_PIXEL_ORDER_ARGB,
+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,
+ },
+ {
+ .drm = DRM_FORMAT_BGR233,
+ .hvs = HVS_PIXEL_FORMAT_RGB332,
+ .pixel_order = HVS_PIXEL_ORDER_ABGR,
+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_ABGR,
+ },
+ {
+ .drm = DRM_FORMAT_XRGB4444,
+ .hvs = HVS_PIXEL_FORMAT_RGBA4444,
+ .pixel_order = HVS_PIXEL_ORDER_ABGR,
+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,
+ },
+ {
+ .drm = DRM_FORMAT_ARGB4444,
+ .hvs = HVS_PIXEL_FORMAT_RGBA4444,
+ .pixel_order = HVS_PIXEL_ORDER_ABGR,
+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,
+ },
+ {
+ .drm = DRM_FORMAT_XBGR4444,
+ .hvs = HVS_PIXEL_FORMAT_RGBA4444,
+ .pixel_order = HVS_PIXEL_ORDER_ARGB,
+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_ABGR,
+ },
+ {
+ .drm = DRM_FORMAT_ABGR4444,
+ .hvs = HVS_PIXEL_FORMAT_RGBA4444,
+ .pixel_order = HVS_PIXEL_ORDER_ARGB,
+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_ABGR,
+ },
+ {
+ .drm = DRM_FORMAT_BGRX4444,
+ .hvs = HVS_PIXEL_FORMAT_RGBA4444,
+ .pixel_order = HVS_PIXEL_ORDER_RGBA,
+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_BGRA,
+ },
+ {
+ .drm = DRM_FORMAT_BGRA4444,
+ .hvs = HVS_PIXEL_FORMAT_RGBA4444,
+ .pixel_order = HVS_PIXEL_ORDER_RGBA,
+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_BGRA,
+ },
+ {
+ .drm = DRM_FORMAT_RGBX4444,
+ .hvs = HVS_PIXEL_FORMAT_RGBA4444,
+ .pixel_order = HVS_PIXEL_ORDER_BGRA,
+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_RGBA,
+ },
+ {
+ .drm = DRM_FORMAT_RGBA4444,
+ .hvs = HVS_PIXEL_FORMAT_RGBA4444,
+ .pixel_order = HVS_PIXEL_ORDER_BGRA,
+ .pixel_order_hvs5 = HVS_PIXEL_ORDER_RGBA,
+ },
};
static const struct hvs_format *vc4_get_hvs_format(u32 drm_format)
@@ -1003,15 +1101,10 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
vc4_dlist_write(vc4_state, 0xc0c0c0c0);
} else {
- u32 hvs_pixel_order = format->pixel_order;
-
- if (format->pixel_order_hvs5)
- hvs_pixel_order = format->pixel_order_hvs5;
-
/* Control word */
vc4_dlist_write(vc4_state,
SCALER_CTL0_VALID |
- (hvs_pixel_order << SCALER_CTL0_ORDER_SHIFT) |
+ (format->pixel_order_hvs5 << SCALER_CTL0_ORDER_SHIFT) |
(hvs_format << SCALER_CTL0_PIXEL_FORMAT_SHIFT) |
VC4_SET_FIELD(tiling, SCALER_CTL0_TILING) |
(vc4_state->is_unity ?
@@ -1490,6 +1583,16 @@ static bool vc4_format_mod_supported(struct drm_plane *plane,
case DRM_FORMAT_BGRX1010102:
case DRM_FORMAT_RGBA1010102:
case DRM_FORMAT_BGRA1010102:
+ case DRM_FORMAT_XRGB4444:
+ case DRM_FORMAT_ARGB4444:
+ case DRM_FORMAT_XBGR4444:
+ case DRM_FORMAT_ABGR4444:
+ case DRM_FORMAT_RGBX4444:
+ case DRM_FORMAT_RGBA4444:
+ case DRM_FORMAT_BGRX4444:
+ case DRM_FORMAT_BGRA4444:
+ case DRM_FORMAT_RGB332:
+ case DRM_FORMAT_BGR233:
case DRM_FORMAT_YUV422:
case DRM_FORMAT_YVU422:
case DRM_FORMAT_YUV420:
@@ -1570,9 +1673,14 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev,
DRM_COLOR_YCBCR_BT709,
DRM_COLOR_YCBCR_LIMITED_RANGE);
+ if (type == DRM_PLANE_TYPE_PRIMARY)
+ drm_plane_create_zpos_immutable_property(plane, 0);
+
return plane;
}
+#define VC4_NUM_OVERLAY_PLANES 16
+
int vc4_plane_create_additional_planes(struct drm_device *drm)
{
struct drm_plane *cursor_plane;
@@ -1588,24 +1696,35 @@ int vc4_plane_create_additional_planes(struct drm_device *drm)
* modest number of planes to expose, that should hopefully
* still cover any sane usecase.
*/
- for (i = 0; i < 16; i++) {
+ for (i = 0; i < VC4_NUM_OVERLAY_PLANES; i++) {
struct drm_plane *plane =
vc4_plane_init(drm, DRM_PLANE_TYPE_OVERLAY,
GENMASK(drm->mode_config.num_crtc - 1, 0));
if (IS_ERR(plane))
continue;
+
+ /* Create zpos property. Max of all the overlays + 1 primary +
+ * 1 cursor plane on a crtc.
+ */
+ drm_plane_create_zpos_property(plane, i + 1, 1,
+ VC4_NUM_OVERLAY_PLANES + 1);
}
drm_for_each_crtc(crtc, drm) {
/* Set up the legacy cursor after overlay initialization,
- * since we overlay planes on the CRTC in the order they were
- * initialized.
+ * since the zpos fallback is that planes are rendered by plane
+ * ID order, and that then puts the cursor on top.
*/
cursor_plane = vc4_plane_init(drm, DRM_PLANE_TYPE_CURSOR,
drm_crtc_mask(crtc));
if (!IS_ERR(cursor_plane)) {
crtc->cursor = cursor_plane;
+
+ drm_plane_create_zpos_property(cursor_plane,
+ VC4_NUM_OVERLAY_PLANES + 1,
+ 1,
+ VC4_NUM_OVERLAY_PLANES + 1);
}
}
diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h
index f0290fad991d..f3763bd600f6 100644
--- a/drivers/gpu/drm/vc4/vc4_regs.h
+++ b/drivers/gpu/drm/vc4/vc4_regs.h
@@ -220,6 +220,12 @@
#define SCALER_DISPCTRL 0x00000000
/* Global register for clock gating the HVS */
# define SCALER_DISPCTRL_ENABLE BIT(31)
+# define SCALER_DISPCTRL_PANIC0_MASK VC4_MASK(25, 24)
+# define SCALER_DISPCTRL_PANIC0_SHIFT 24
+# define SCALER_DISPCTRL_PANIC1_MASK VC4_MASK(27, 26)
+# define SCALER_DISPCTRL_PANIC1_SHIFT 26
+# define SCALER_DISPCTRL_PANIC2_MASK VC4_MASK(29, 28)
+# define SCALER_DISPCTRL_PANIC2_SHIFT 28
# define SCALER_DISPCTRL_DSP3_MUX_MASK VC4_MASK(19, 18)
# define SCALER_DISPCTRL_DSP3_MUX_SHIFT 18
@@ -228,15 +234,21 @@
* always enabled.
*/
# define SCALER_DISPCTRL_DSPEISLUR(x) BIT(13 + (x))
+# define SCALER5_DISPCTRL_DSPEISLUR(x) BIT(9 + ((x) * 4))
/* Enables Display 0 end-of-line-N contribution to
* SCALER_DISPSTAT_IRQDISP0
*/
# define SCALER_DISPCTRL_DSPEIEOLN(x) BIT(8 + ((x) * 2))
+# define SCALER5_DISPCTRL_DSPEIEOLN(x) BIT(8 + ((x) * 4))
/* Enables Display 0 EOF contribution to SCALER_DISPSTAT_IRQDISP0 */
# define SCALER_DISPCTRL_DSPEIEOF(x) BIT(7 + ((x) * 2))
+# define SCALER5_DISPCTRL_DSPEIEOF(x) BIT(7 + ((x) * 4))
-# define SCALER_DISPCTRL_SLVRDEIRQ BIT(6)
-# define SCALER_DISPCTRL_SLVWREIRQ BIT(5)
+# define SCALER5_DISPCTRL_DSPEIVST(x) BIT(6 + ((x) * 4))
+
+# define SCALER_DISPCTRL_SLVRDEIRQ BIT(6) /* HVS4 only */
+# define SCALER_DISPCTRL_SLVWREIRQ BIT(5) /* HVS4 only */
+# define SCALER5_DISPCTRL_SLVEIRQ BIT(5)
# define SCALER_DISPCTRL_DMAEIRQ BIT(4)
/* Enables interrupt generation on the enabled EOF/EOLN/EISLUR
* bits and short frames..
@@ -360,6 +372,7 @@
#define SCALER_DISPBKGND0 0x00000044
# define SCALER_DISPBKGND_AUTOHS BIT(31)
+# define SCALER5_DISPBKGND_BCK2BCK BIT(31)
# define SCALER_DISPBKGND_INTERLACE BIT(30)
# define SCALER_DISPBKGND_GAMMA BIT(29)
# define SCALER_DISPBKGND_TESTMODE_MASK VC4_MASK(28, 25)
@@ -835,16 +848,19 @@ enum hvs_pixel_format {
/* Note: the LSB is the rightmost character shown. Only valid for
* HVS_PIXEL_FORMAT_RGB8888, not RGB888.
*/
+/* For modes 332, 4444, 555, 5551, 6666, 8888, 10:10:10:2 */
#define HVS_PIXEL_ORDER_RGBA 0
#define HVS_PIXEL_ORDER_BGRA 1
#define HVS_PIXEL_ORDER_ARGB 2
#define HVS_PIXEL_ORDER_ABGR 3
+/* For modes 666 and 888 (4 & 5) */
#define HVS_PIXEL_ORDER_XBRG 0
#define HVS_PIXEL_ORDER_XRBG 1
#define HVS_PIXEL_ORDER_XRGB 2
#define HVS_PIXEL_ORDER_XBGR 3
+/* For YCbCr modes (8-12, and 17) */
#define HVS_PIXEL_ORDER_XYCBCR 0
#define HVS_PIXEL_ORDER_XYCRCB 1
#define HVS_PIXEL_ORDER_YXCBCR 2
diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c
index bd181b5a7b52..ef5cab2a3aa9 100644
--- a/drivers/gpu/drm/vc4/vc4_txp.c
+++ b/drivers/gpu/drm/vc4/vc4_txp.c
@@ -145,14 +145,24 @@
/* Number of lines received and committed to memory. */
#define TXP_PROGRESS 0x10
-#define TXP_READ(offset) readl(txp->regs + (offset))
-#define TXP_WRITE(offset, val) writel(val, txp->regs + (offset))
+#define TXP_READ(offset) \
+ ({ \
+ kunit_fail_current_test("Accessing a register in a unit test!\n"); \
+ readl(txp->regs + (offset)); \
+ })
+
+#define TXP_WRITE(offset, val) \
+ do { \
+ kunit_fail_current_test("Accessing a register in a unit test!\n"); \
+ writel(val, txp->regs + (offset)); \
+ } while (0)
struct vc4_txp {
struct vc4_crtc base;
struct platform_device *pdev;
+ struct vc4_encoder encoder;
struct drm_writeback_connector connector;
void __iomem *regs;
@@ -160,7 +170,7 @@ struct vc4_txp {
static inline struct vc4_txp *encoder_to_vc4_txp(struct drm_encoder *encoder)
{
- return container_of(encoder, struct vc4_txp, connector.encoder);
+ return container_of(encoder, struct vc4_txp, encoder.base);
}
static inline struct vc4_txp *connector_to_vc4_txp(struct drm_connector *conn)
@@ -478,7 +488,8 @@ static irqreturn_t vc4_txp_interrupt(int irq, void *data)
return IRQ_HANDLED;
}
-static const struct vc4_crtc_data vc4_txp_crtc_data = {
+const struct vc4_crtc_data vc4_txp_crtc_data = {
+ .name = "txp",
.debugfs_name = "txp_regs",
.hvs_available_channels = BIT(2),
.hvs_output = 2,
@@ -488,10 +499,10 @@ static int vc4_txp_bind(struct device *dev, struct device *master, void *data)
{
struct platform_device *pdev = to_platform_device(dev);
struct drm_device *drm = dev_get_drvdata(master);
+ struct vc4_encoder *vc4_encoder;
+ struct drm_encoder *encoder;
struct vc4_crtc *vc4_crtc;
struct vc4_txp *txp;
- struct drm_crtc *crtc;
- struct drm_encoder *encoder;
int ret, irq;
irq = platform_get_irq(pdev, 0);
@@ -501,39 +512,42 @@ static int vc4_txp_bind(struct device *dev, struct device *master, void *data)
txp = drmm_kzalloc(drm, sizeof(*txp), GFP_KERNEL);
if (!txp)
return -ENOMEM;
- vc4_crtc = &txp->base;
- crtc = &vc4_crtc->base;
-
- vc4_crtc->pdev = pdev;
- vc4_crtc->data = &vc4_txp_crtc_data;
- vc4_crtc->feeds_txp = true;
txp->pdev = pdev;
-
txp->regs = vc4_ioremap_regs(pdev, 0);
if (IS_ERR(txp->regs))
return PTR_ERR(txp->regs);
+
+ vc4_crtc = &txp->base;
vc4_crtc->regset.base = txp->regs;
vc4_crtc->regset.regs = txp_regs;
vc4_crtc->regset.nregs = ARRAY_SIZE(txp_regs);
- drm_connector_helper_add(&txp->connector.base,
- &vc4_txp_connector_helper_funcs);
- ret = drm_writeback_connector_init(drm, &txp->connector,
- &vc4_txp_connector_funcs,
- &vc4_txp_encoder_helper_funcs,
- drm_fmts, ARRAY_SIZE(drm_fmts),
- 0);
+ ret = vc4_crtc_init(drm, pdev, vc4_crtc, &vc4_txp_crtc_data,
+ &vc4_txp_crtc_funcs, &vc4_txp_crtc_helper_funcs, true);
if (ret)
return ret;
- ret = vc4_crtc_init(drm, vc4_crtc,
- &vc4_txp_crtc_funcs, &vc4_txp_crtc_helper_funcs);
+ vc4_encoder = &txp->encoder;
+ txp->encoder.type = VC4_ENCODER_TYPE_TXP;
+
+ encoder = &vc4_encoder->base;
+ encoder->possible_crtcs = drm_crtc_mask(&vc4_crtc->base);
+
+ drm_encoder_helper_add(encoder, &vc4_txp_encoder_helper_funcs);
+
+ ret = drmm_encoder_init(drm, encoder, NULL, DRM_MODE_ENCODER_VIRTUAL, NULL);
if (ret)
return ret;
- encoder = &txp->connector.encoder;
- encoder->possible_crtcs = drm_crtc_mask(crtc);
+ drm_connector_helper_add(&txp->connector.base,
+ &vc4_txp_connector_helper_funcs);
+ ret = drm_writeback_connector_init_with_encoder(drm, &txp->connector,
+ encoder,
+ &vc4_txp_connector_funcs,
+ drm_fmts, ARRAY_SIZE(drm_fmts));
+ if (ret)
+ return ret;
ret = devm_request_irq(dev, irq, vc4_txp_interrupt, 0,
dev_name(dev), txp);
diff --git a/drivers/gpu/drm/vc4/vc4_v3d.c b/drivers/gpu/drm/vc4/vc4_v3d.c
index 56abb0d6bc39..29a664c8bf44 100644
--- a/drivers/gpu/drm/vc4/vc4_v3d.c
+++ b/drivers/gpu/drm/vc4/vc4_v3d.c
@@ -96,8 +96,8 @@ static const struct debugfs_reg32 v3d_regs[] = {
static int vc4_v3d_debugfs_ident(struct seq_file *m, void *unused)
{
- struct drm_info_node *node = (struct drm_info_node *)m->private;
- struct drm_device *dev = node->minor->dev;
+ struct drm_debugfs_entry *entry = m->private;
+ struct drm_device *dev = entry->dev;
struct vc4_dev *vc4 = to_vc4_dev(dev);
int ret = vc4_v3d_pm_get(vc4);
@@ -404,19 +404,13 @@ int vc4_v3d_debugfs_init(struct drm_minor *minor)
struct drm_device *drm = minor->dev;
struct vc4_dev *vc4 = to_vc4_dev(drm);
struct vc4_v3d *v3d = vc4->v3d;
- int ret;
if (!vc4->v3d)
return -ENODEV;
- ret = vc4_debugfs_add_file(minor, "v3d_ident",
- vc4_v3d_debugfs_ident, NULL);
- if (ret)
- return ret;
+ drm_debugfs_add_file(drm, "v3d_ident", vc4_v3d_debugfs_ident, NULL);
- ret = vc4_debugfs_add_regset32(minor, "v3d_regs", &v3d->regset);
- if (ret)
- return ret;
+ vc4_debugfs_add_regset32(drm, "v3d_regs", &v3d->regset);
return 0;
}
diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
index 92c07e31d632..a3782d05cd66 100644
--- a/drivers/gpu/drm/vc4/vc4_vec.c
+++ b/drivers/gpu/drm/vc4/vc4_vec.c
@@ -46,6 +46,7 @@
#define VEC_CONFIG0_YDEL(x) ((x) << 26)
#define VEC_CONFIG0_CDEL_MASK GENMASK(25, 24)
#define VEC_CONFIG0_CDEL(x) ((x) << 24)
+#define VEC_CONFIG0_SECAM_STD BIT(21)
#define VEC_CONFIG0_PBPR_FIL BIT(18)
#define VEC_CONFIG0_CHROMA_GAIN_MASK GENMASK(17, 16)
#define VEC_CONFIG0_CHROMA_GAIN_UNITY (0 << 16)
@@ -76,6 +77,27 @@
#define VEC_SOFT_RESET 0x10c
#define VEC_CLMP0_START 0x144
#define VEC_CLMP0_END 0x148
+
+/*
+ * These set the color subcarrier frequency
+ * if VEC_CONFIG1_CUSTOM_FREQ is enabled.
+ *
+ * VEC_FREQ1_0 contains the most significant 16-bit half-word,
+ * VEC_FREQ3_2 contains the least significant 16-bit half-word.
+ * 0x80000000 seems to be equivalent to the pixel clock
+ * (which itself is the VEC clock divided by 8).
+ *
+ * Reference values (with the default pixel clock of 13.5 MHz):
+ *
+ * NTSC (3579545.[45] Hz) - 0x21F07C1F
+ * PAL (4433618.75 Hz) - 0x2A098ACB
+ * PAL-M (3575611.[888111] Hz) - 0x21E6EFE3
+ * PAL-N (3582056.25 Hz) - 0x21F69446
+ *
+ * NOTE: For SECAM, it is used as the Dr center frequency,
+ * regardless of whether VEC_CONFIG1_CUSTOM_FREQ is enabled or not;
+ * that is specified as 4406250 Hz, which corresponds to 0x29C71C72.
+ */
#define VEC_FREQ3_2 0x180
#define VEC_FREQ1_0 0x184
@@ -118,6 +140,14 @@
#define VEC_INTERRUPT_CONTROL 0x190
#define VEC_INTERRUPT_STATUS 0x194
+
+/*
+ * Db center frequency for SECAM; the clock for this is the same as for
+ * VEC_FREQ3_2/VEC_FREQ1_0, which is used for Dr center frequency.
+ *
+ * This is specified as 4250000 Hz, which corresponds to 0x284BDA13.
+ * That is also the default value, so no need to set it explicitly.
+ */
#define VEC_FCW_SECAM_B 0x198
#define VEC_SECAM_GAIN_VAL 0x19c
@@ -172,11 +202,22 @@ struct vc4_vec {
struct clk *clock;
+ struct drm_property *legacy_tv_mode_property;
+
struct debugfs_regset32 regset;
};
-#define VEC_READ(offset) readl(vec->regs + (offset))
-#define VEC_WRITE(offset, val) writel(val, vec->regs + (offset))
+#define VEC_READ(offset) \
+ ({ \
+ kunit_fail_current_test("Accessing a register in a unit test!\n"); \
+ readl(vec->regs + (offset)); \
+ })
+
+#define VEC_WRITE(offset, val) \
+ do { \
+ kunit_fail_current_test("Accessing a register in a unit test!\n"); \
+ writel(val, vec->regs + (offset)); \
+ } while (0)
static inline struct vc4_vec *
encoder_to_vc4_vec(struct drm_encoder *encoder)
@@ -184,15 +225,26 @@ encoder_to_vc4_vec(struct drm_encoder *encoder)
return container_of(encoder, struct vc4_vec, encoder.base);
}
+static inline struct vc4_vec *
+connector_to_vc4_vec(struct drm_connector *connector)
+{
+ return container_of(connector, struct vc4_vec, connector);
+}
+
enum vc4_vec_tv_mode_id {
VC4_VEC_TV_MODE_NTSC,
VC4_VEC_TV_MODE_NTSC_J,
VC4_VEC_TV_MODE_PAL,
VC4_VEC_TV_MODE_PAL_M,
+ VC4_VEC_TV_MODE_NTSC_443,
+ VC4_VEC_TV_MODE_PAL_60,
+ VC4_VEC_TV_MODE_PAL_N,
+ VC4_VEC_TV_MODE_SECAM,
};
struct vc4_vec_tv_mode {
- const struct drm_display_mode *mode;
+ unsigned int mode;
+ u16 expected_htotal;
u32 config0;
u32 config1;
u32 custom_freq;
@@ -225,41 +277,86 @@ static const struct debugfs_reg32 vec_regs[] = {
VC4_REG32(VEC_DAC_MISC),
};
-static const struct drm_display_mode ntsc_mode = {
- DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 13500,
- 720, 720 + 14, 720 + 14 + 64, 720 + 14 + 64 + 60, 0,
- 480, 480 + 7, 480 + 7 + 6, 525, 0,
- DRM_MODE_FLAG_INTERLACE)
-};
-
-static const struct drm_display_mode pal_mode = {
- DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 13500,
- 720, 720 + 20, 720 + 20 + 64, 720 + 20 + 64 + 60, 0,
- 576, 576 + 4, 576 + 4 + 6, 625, 0,
- DRM_MODE_FLAG_INTERLACE)
-};
-
static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = {
- [VC4_VEC_TV_MODE_NTSC] = {
- .mode = &ntsc_mode,
+ {
+ .mode = DRM_MODE_TV_MODE_NTSC,
+ .expected_htotal = 858,
.config0 = VEC_CONFIG0_NTSC_STD | VEC_CONFIG0_PDEN,
.config1 = VEC_CONFIG1_C_CVBS_CVBS,
},
- [VC4_VEC_TV_MODE_NTSC_J] = {
- .mode = &ntsc_mode,
+ {
+ .mode = DRM_MODE_TV_MODE_NTSC_443,
+ .expected_htotal = 858,
+ .config0 = VEC_CONFIG0_NTSC_STD,
+ .config1 = VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ,
+ .custom_freq = 0x2a098acb,
+ },
+ {
+ .mode = DRM_MODE_TV_MODE_NTSC_J,
+ .expected_htotal = 858,
.config0 = VEC_CONFIG0_NTSC_STD,
.config1 = VEC_CONFIG1_C_CVBS_CVBS,
},
- [VC4_VEC_TV_MODE_PAL] = {
- .mode = &pal_mode,
+ {
+ .mode = DRM_MODE_TV_MODE_PAL,
+ .expected_htotal = 864,
.config0 = VEC_CONFIG0_PAL_BDGHI_STD,
.config1 = VEC_CONFIG1_C_CVBS_CVBS,
},
- [VC4_VEC_TV_MODE_PAL_M] = {
- .mode = &ntsc_mode,
+ {
+ /* PAL-60 */
+ .mode = DRM_MODE_TV_MODE_PAL,
+ .expected_htotal = 858,
+ .config0 = VEC_CONFIG0_PAL_M_STD,
+ .config1 = VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ,
+ .custom_freq = 0x2a098acb,
+ },
+ {
+ .mode = DRM_MODE_TV_MODE_PAL_M,
+ .expected_htotal = 858,
.config0 = VEC_CONFIG0_PAL_M_STD,
.config1 = VEC_CONFIG1_C_CVBS_CVBS,
},
+ {
+ .mode = DRM_MODE_TV_MODE_PAL_N,
+ .expected_htotal = 864,
+ .config0 = VEC_CONFIG0_PAL_N_STD,
+ .config1 = VEC_CONFIG1_C_CVBS_CVBS,
+ },
+ {
+ .mode = DRM_MODE_TV_MODE_SECAM,
+ .expected_htotal = 864,
+ .config0 = VEC_CONFIG0_SECAM_STD,
+ .config1 = VEC_CONFIG1_C_CVBS_CVBS,
+ .custom_freq = 0x29c71c72,
+ },
+};
+
+static inline const struct vc4_vec_tv_mode *
+vc4_vec_tv_mode_lookup(unsigned int mode, u16 htotal)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(vc4_vec_tv_modes); i++) {
+ const struct vc4_vec_tv_mode *tv_mode = &vc4_vec_tv_modes[i];
+
+ if (tv_mode->mode == mode &&
+ tv_mode->expected_htotal == htotal)
+ return tv_mode;
+ }
+
+ return NULL;
+}
+
+static const struct drm_prop_enum_list legacy_tv_mode_names[] = {
+ { VC4_VEC_TV_MODE_NTSC, "NTSC", },
+ { VC4_VEC_TV_MODE_NTSC_443, "NTSC-443", },
+ { VC4_VEC_TV_MODE_NTSC_J, "NTSC-J", },
+ { VC4_VEC_TV_MODE_PAL, "PAL", },
+ { VC4_VEC_TV_MODE_PAL_60, "PAL-60", },
+ { VC4_VEC_TV_MODE_PAL_M, "PAL-M", },
+ { VC4_VEC_TV_MODE_PAL_N, "PAL-N", },
+ { VC4_VEC_TV_MODE_SECAM, "SECAM", },
};
static enum drm_connector_status
@@ -268,38 +365,126 @@ vc4_vec_connector_detect(struct drm_connector *connector, bool force)
return connector_status_unknown;
}
-static int vc4_vec_connector_get_modes(struct drm_connector *connector)
+static void vc4_vec_connector_reset(struct drm_connector *connector)
{
- struct drm_connector_state *state = connector->state;
- struct drm_display_mode *mode;
+ drm_atomic_helper_connector_reset(connector);
+ drm_atomic_helper_connector_tv_reset(connector);
+}
- mode = drm_mode_duplicate(connector->dev,
- vc4_vec_tv_modes[state->tv.mode].mode);
- if (!mode) {
- DRM_ERROR("Failed to create a new display mode\n");
- return -ENOMEM;
+static int
+vc4_vec_connector_set_property(struct drm_connector *connector,
+ struct drm_connector_state *state,
+ struct drm_property *property,
+ uint64_t val)
+{
+ struct vc4_vec *vec = connector_to_vc4_vec(connector);
+
+ if (property != vec->legacy_tv_mode_property)
+ return -EINVAL;
+
+ switch (val) {
+ case VC4_VEC_TV_MODE_NTSC:
+ state->tv.mode = DRM_MODE_TV_MODE_NTSC;
+ break;
+
+ case VC4_VEC_TV_MODE_NTSC_443:
+ state->tv.mode = DRM_MODE_TV_MODE_NTSC_443;
+ break;
+
+ case VC4_VEC_TV_MODE_NTSC_J:
+ state->tv.mode = DRM_MODE_TV_MODE_NTSC_J;
+ break;
+
+ case VC4_VEC_TV_MODE_PAL:
+ case VC4_VEC_TV_MODE_PAL_60:
+ state->tv.mode = DRM_MODE_TV_MODE_PAL;
+ break;
+
+ case VC4_VEC_TV_MODE_PAL_M:
+ state->tv.mode = DRM_MODE_TV_MODE_PAL_M;
+ break;
+
+ case VC4_VEC_TV_MODE_PAL_N:
+ state->tv.mode = DRM_MODE_TV_MODE_PAL_N;
+ break;
+
+ case VC4_VEC_TV_MODE_SECAM:
+ state->tv.mode = DRM_MODE_TV_MODE_SECAM;
+ break;
+
+ default:
+ return -EINVAL;
}
- drm_mode_probed_add(connector, mode);
+ return 0;
+}
+
+static int
+vc4_vec_connector_get_property(struct drm_connector *connector,
+ const struct drm_connector_state *state,
+ struct drm_property *property,
+ uint64_t *val)
+{
+ struct vc4_vec *vec = connector_to_vc4_vec(connector);
+
+ if (property != vec->legacy_tv_mode_property)
+ return -EINVAL;
+
+ switch (state->tv.mode) {
+ case DRM_MODE_TV_MODE_NTSC:
+ *val = VC4_VEC_TV_MODE_NTSC;
+ break;
+
+ case DRM_MODE_TV_MODE_NTSC_443:
+ *val = VC4_VEC_TV_MODE_NTSC_443;
+ break;
+
+ case DRM_MODE_TV_MODE_NTSC_J:
+ *val = VC4_VEC_TV_MODE_NTSC_J;
+ break;
- return 1;
+ case DRM_MODE_TV_MODE_PAL:
+ *val = VC4_VEC_TV_MODE_PAL;
+ break;
+
+ case DRM_MODE_TV_MODE_PAL_M:
+ *val = VC4_VEC_TV_MODE_PAL_M;
+ break;
+
+ case DRM_MODE_TV_MODE_PAL_N:
+ *val = VC4_VEC_TV_MODE_PAL_N;
+ break;
+
+ case DRM_MODE_TV_MODE_SECAM:
+ *val = VC4_VEC_TV_MODE_SECAM;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
}
static const struct drm_connector_funcs vc4_vec_connector_funcs = {
.detect = vc4_vec_connector_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
- .reset = drm_atomic_helper_connector_reset,
+ .reset = vc4_vec_connector_reset,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+ .atomic_get_property = vc4_vec_connector_get_property,
+ .atomic_set_property = vc4_vec_connector_set_property,
};
static const struct drm_connector_helper_funcs vc4_vec_connector_helper_funcs = {
- .get_modes = vc4_vec_connector_get_modes,
+ .atomic_check = drm_atomic_helper_connector_tv_check,
+ .get_modes = drm_connector_helper_tv_get_modes,
};
static int vc4_vec_connector_init(struct drm_device *dev, struct vc4_vec *vec)
{
struct drm_connector *connector = &vec->connector;
+ struct drm_property *prop;
int ret;
connector->interlace_allowed = true;
@@ -313,7 +498,16 @@ static int vc4_vec_connector_init(struct drm_device *dev, struct vc4_vec *vec)
drm_object_attach_property(&connector->base,
dev->mode_config.tv_mode_property,
- VC4_VEC_TV_MODE_NTSC);
+ DRM_MODE_TV_MODE_NTSC);
+
+ prop = drm_property_create_enum(dev, 0, "mode",
+ legacy_tv_mode_names,
+ ARRAY_SIZE(legacy_tv_mode_names));
+ if (!prop)
+ return -ENOMEM;
+ vec->legacy_tv_mode_property = prop;
+
+ drm_object_attach_property(&connector->base, prop, VC4_VEC_TV_MODE_NTSC);
drm_connector_attach_encoder(connector, &vec->encoder.base);
@@ -360,14 +554,20 @@ static void vc4_vec_encoder_enable(struct drm_encoder *encoder,
struct drm_connector *connector = &vec->connector;
struct drm_connector_state *conn_state =
drm_atomic_get_new_connector_state(state, connector);
- const struct vc4_vec_tv_mode *tv_mode =
- &vc4_vec_tv_modes[conn_state->tv.mode];
+ struct drm_display_mode *adjusted_mode =
+ &encoder->crtc->state->adjusted_mode;
+ const struct vc4_vec_tv_mode *tv_mode;
int idx, ret;
if (!drm_dev_enter(drm, &idx))
return;
- ret = pm_runtime_get_sync(&vec->pdev->dev);
+ tv_mode = vc4_vec_tv_mode_lookup(conn_state->tv.mode,
+ adjusted_mode->htotal);
+ if (!tv_mode)
+ goto err_dev_exit;
+
+ ret = pm_runtime_resume_and_get(&vec->pdev->dev);
if (ret < 0) {
DRM_ERROR("Failed to retain power domain: %d\n", ret);
goto err_dev_exit;
@@ -413,7 +613,9 @@ static void vc4_vec_encoder_enable(struct drm_encoder *encoder,
VEC_WRITE(VEC_CLMP0_START, 0xac);
VEC_WRITE(VEC_CLMP0_END, 0xec);
VEC_WRITE(VEC_CONFIG2,
- VEC_CONFIG2_UV_DIG_DIS | VEC_CONFIG2_RGB_DIG_DIS);
+ VEC_CONFIG2_UV_DIG_DIS |
+ VEC_CONFIG2_RGB_DIG_DIS |
+ ((adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) ? 0 : VEC_CONFIG2_PROG_SCAN));
VEC_WRITE(VEC_CONFIG3, VEC_CONFIG3_HORIZ_LEN_STD);
VEC_WRITE(VEC_DAC_CONFIG, vec->variant->dac_config);
@@ -447,13 +649,61 @@ static int vc4_vec_encoder_atomic_check(struct drm_encoder *encoder,
struct drm_crtc_state *crtc_state,
struct drm_connector_state *conn_state)
{
- const struct vc4_vec_tv_mode *vec_mode;
+ const struct drm_display_mode *mode = &crtc_state->adjusted_mode;
+ const struct vc4_vec_tv_mode *tv_mode;
+
+ tv_mode = vc4_vec_tv_mode_lookup(conn_state->tv.mode, mode->htotal);
+ if (!tv_mode)
+ return -EINVAL;
+
+ if (mode->crtc_hdisplay % 4)
+ return -EINVAL;
+
+ if (!(mode->crtc_hsync_end - mode->crtc_hsync_start))
+ return -EINVAL;
+
+ switch (mode->htotal) {
+ /* NTSC */
+ case 858:
+ if (mode->crtc_vtotal > 262)
+ return -EINVAL;
+
+ if (mode->crtc_vdisplay < 1 || mode->crtc_vdisplay > 253)
+ return -EINVAL;
+
+ if (!(mode->crtc_vsync_start - mode->crtc_vdisplay))
+ return -EINVAL;
+
+ if ((mode->crtc_vsync_end - mode->crtc_vsync_start) != 3)
+ return -EINVAL;
+
+ if ((mode->crtc_vtotal - mode->crtc_vsync_end) < 4)
+ return -EINVAL;
- vec_mode = &vc4_vec_tv_modes[conn_state->tv.mode];
+ break;
- if (conn_state->crtc &&
- !drm_mode_equal(vec_mode->mode, &crtc_state->adjusted_mode))
+ /* PAL/SECAM */
+ case 864:
+ if (mode->crtc_vtotal > 312)
+ return -EINVAL;
+
+ if (mode->crtc_vdisplay < 1 || mode->crtc_vdisplay > 305)
+ return -EINVAL;
+
+ if (!(mode->crtc_vsync_start - mode->crtc_vdisplay))
+ return -EINVAL;
+
+ if ((mode->crtc_vsync_end - mode->crtc_vsync_start) != 3)
+ return -EINVAL;
+
+ if ((mode->crtc_vtotal - mode->crtc_vsync_end) < 2)
+ return -EINVAL;
+
+ break;
+
+ default:
return -EINVAL;
+ }
return 0;
}
@@ -468,12 +718,8 @@ static int vc4_vec_late_register(struct drm_encoder *encoder)
{
struct drm_device *drm = encoder->dev;
struct vc4_vec *vec = encoder_to_vc4_vec(encoder);
- int ret;
- ret = vc4_debugfs_add_regset32(drm->primary, "vec_regs",
- &vec->regset);
- if (ret)
- return ret;
+ vc4_debugfs_add_regset32(drm, "vec_regs", &vec->regset);
return 0;
}
@@ -500,13 +746,6 @@ static const struct of_device_id vc4_vec_dt_match[] = {
{ /* sentinel */ },
};
-static const char * const tv_mode_names[] = {
- [VC4_VEC_TV_MODE_NTSC] = "NTSC",
- [VC4_VEC_TV_MODE_NTSC_J] = "NTSC-J",
- [VC4_VEC_TV_MODE_PAL] = "PAL",
- [VC4_VEC_TV_MODE_PAL_M] = "PAL-M",
-};
-
static int vc4_vec_bind(struct device *dev, struct device *master, void *data)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -514,8 +753,14 @@ static int vc4_vec_bind(struct device *dev, struct device *master, void *data)
struct vc4_vec *vec;
int ret;
- ret = drm_mode_create_tv_properties(drm, ARRAY_SIZE(tv_mode_names),
- tv_mode_names);
+ ret = drm_mode_create_tv_properties(drm,
+ BIT(DRM_MODE_TV_MODE_NTSC) |
+ BIT(DRM_MODE_TV_MODE_NTSC_443) |
+ BIT(DRM_MODE_TV_MODE_NTSC_J) |
+ BIT(DRM_MODE_TV_MODE_PAL) |
+ BIT(DRM_MODE_TV_MODE_PAL_M) |
+ BIT(DRM_MODE_TV_MODE_PAL_N) |
+ BIT(DRM_MODE_TV_MODE_SECAM));
if (ret)
return ret;
diff --git a/drivers/gpu/drm/via/Makefile b/drivers/gpu/drm/via/Makefile
deleted file mode 100644
index 8b978dd51a25..000000000000
--- a/drivers/gpu/drm/via/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Makefile for the drm device driver. This driver provides support for the
-# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
-
-via-y := via_dri1.o
-
-obj-$(CONFIG_DRM_VIA) +=via.o
diff --git a/drivers/gpu/drm/via/via_3d_reg.h b/drivers/gpu/drm/via/via_3d_reg.h
deleted file mode 100644
index eb848508b12b..000000000000
--- a/drivers/gpu/drm/via/via_3d_reg.h
+++ /dev/null
@@ -1,1771 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright 1998-2011 VIA Technologies, Inc. All Rights Reserved.
- * Copyright 2001-2011 S3 Graphics, Inc. All Rights Reserved.
- */
-
-#ifndef VIA_3D_REG_H
-#define VIA_3D_REG_H
-#define HC_REG_BASE 0x0400
-
-#define HC_REG_TRANS_SPACE 0x0040
-
-#define HC_ParaN_MASK 0xffffffff
-#define HC_Para_MASK 0x00ffffff
-#define HC_SubA_MASK 0xff000000
-#define HC_SubA_SHIFT 24
-/* Transmission Setting
- */
-#define HC_REG_TRANS_SET 0x003c
-#define HC_ParaSubType_MASK 0xff000000
-#define HC_ParaType_MASK 0x00ff0000
-#define HC_ParaOS_MASK 0x0000ff00
-#define HC_ParaAdr_MASK 0x000000ff
-#define HC_ParaSubType_SHIFT 24
-#define HC_ParaType_SHIFT 16
-#define HC_ParaOS_SHIFT 8
-#define HC_ParaAdr_SHIFT 0
-
-#define HC_ParaType_CmdVdata 0x0000
-#define HC_ParaType_NotTex 0x0001
-#define HC_ParaType_Tex 0x0002
-#define HC_ParaType_Palette 0x0003
-#define HC_ParaType_PreCR 0x0010
-#define HC_ParaType_Auto 0x00fe
-#define INV_ParaType_Dummy 0x00300000
-
-/* Transmission Space
- */
-#define HC_REG_Hpara0 0x0040
-#define HC_REG_HpataAF 0x02fc
-
-/* Read
- */
-#define HC_REG_HREngSt 0x0000
-#define HC_REG_HRFIFOempty 0x0004
-#define HC_REG_HRFIFOfull 0x0008
-#define HC_REG_HRErr 0x000c
-#define HC_REG_FIFOstatus 0x0010
-/* HC_REG_HREngSt 0x0000
- */
-#define HC_HDASZC_MASK 0x00010000
-#define HC_HSGEMI_MASK 0x0000f000
-#define HC_HLGEMISt_MASK 0x00000f00
-#define HC_HCRSt_MASK 0x00000080
-#define HC_HSE0St_MASK 0x00000040
-#define HC_HSE1St_MASK 0x00000020
-#define HC_HPESt_MASK 0x00000010
-#define HC_HXESt_MASK 0x00000008
-#define HC_HBESt_MASK 0x00000004
-#define HC_HE2St_MASK 0x00000002
-#define HC_HE3St_MASK 0x00000001
-/* HC_REG_HRFIFOempty 0x0004
- */
-#define HC_HRZDempty_MASK 0x00000010
-#define HC_HRTXAempty_MASK 0x00000008
-#define HC_HRTXDempty_MASK 0x00000004
-#define HC_HWZDempty_MASK 0x00000002
-#define HC_HWCDempty_MASK 0x00000001
-/* HC_REG_HRFIFOfull 0x0008
- */
-#define HC_HRZDfull_MASK 0x00000010
-#define HC_HRTXAfull_MASK 0x00000008
-#define HC_HRTXDfull_MASK 0x00000004
-#define HC_HWZDfull_MASK 0x00000002
-#define HC_HWCDfull_MASK 0x00000001
-/* HC_REG_HRErr 0x000c
- */
-#define HC_HAGPCMErr_MASK 0x80000000
-#define HC_HAGPCMErrC_MASK 0x70000000
-/* HC_REG_FIFOstatus 0x0010
- */
-#define HC_HRFIFOATall_MASK 0x80000000
-#define HC_HRFIFOATbusy_MASK 0x40000000
-#define HC_HRATFGMDo_MASK 0x00000100
-#define HC_HRATFGMDi_MASK 0x00000080
-#define HC_HRATFRZD_MASK 0x00000040
-#define HC_HRATFRTXA_MASK 0x00000020
-#define HC_HRATFRTXD_MASK 0x00000010
-#define HC_HRATFWZD_MASK 0x00000008
-#define HC_HRATFWCD_MASK 0x00000004
-#define HC_HRATTXTAG_MASK 0x00000002
-#define HC_HRATTXCH_MASK 0x00000001
-
-/* AGP Command Setting
- */
-#define HC_SubA_HAGPBstL 0x0060
-#define HC_SubA_HAGPBendL 0x0061
-#define HC_SubA_HAGPCMNT 0x0062
-#define HC_SubA_HAGPBpL 0x0063
-#define HC_SubA_HAGPBpH 0x0064
-/* HC_SubA_HAGPCMNT 0x0062
- */
-#define HC_HAGPCMNT_MASK 0x00800000
-#define HC_HCmdErrClr_MASK 0x00400000
-#define HC_HAGPBendH_MASK 0x0000ff00
-#define HC_HAGPBstH_MASK 0x000000ff
-#define HC_HAGPBendH_SHIFT 8
-#define HC_HAGPBstH_SHIFT 0
-/* HC_SubA_HAGPBpL 0x0063
- */
-#define HC_HAGPBpL_MASK 0x00fffffc
-#define HC_HAGPBpID_MASK 0x00000003
-#define HC_HAGPBpID_PAUSE 0x00000000
-#define HC_HAGPBpID_JUMP 0x00000001
-#define HC_HAGPBpID_STOP 0x00000002
-/* HC_SubA_HAGPBpH 0x0064
- */
-#define HC_HAGPBpH_MASK 0x00ffffff
-
-/* Miscellaneous Settings
- */
-#define HC_SubA_HClipTB 0x0070
-#define HC_SubA_HClipLR 0x0071
-#define HC_SubA_HFPClipTL 0x0072
-#define HC_SubA_HFPClipBL 0x0073
-#define HC_SubA_HFPClipLL 0x0074
-#define HC_SubA_HFPClipRL 0x0075
-#define HC_SubA_HFPClipTBH 0x0076
-#define HC_SubA_HFPClipLRH 0x0077
-#define HC_SubA_HLP 0x0078
-#define HC_SubA_HLPRF 0x0079
-#define HC_SubA_HSolidCL 0x007a
-#define HC_SubA_HPixGC 0x007b
-#define HC_SubA_HSPXYOS 0x007c
-#define HC_SubA_HVertexCNT 0x007d
-
-#define HC_HClipT_MASK 0x00fff000
-#define HC_HClipT_SHIFT 12
-#define HC_HClipB_MASK 0x00000fff
-#define HC_HClipB_SHIFT 0
-#define HC_HClipL_MASK 0x00fff000
-#define HC_HClipL_SHIFT 12
-#define HC_HClipR_MASK 0x00000fff
-#define HC_HClipR_SHIFT 0
-#define HC_HFPClipBH_MASK 0x0000ff00
-#define HC_HFPClipBH_SHIFT 8
-#define HC_HFPClipTH_MASK 0x000000ff
-#define HC_HFPClipTH_SHIFT 0
-#define HC_HFPClipRH_MASK 0x0000ff00
-#define HC_HFPClipRH_SHIFT 8
-#define HC_HFPClipLH_MASK 0x000000ff
-#define HC_HFPClipLH_SHIFT 0
-#define HC_HSolidCH_MASK 0x000000ff
-#define HC_HPixGC_MASK 0x00800000
-#define HC_HSPXOS_MASK 0x00fff000
-#define HC_HSPXOS_SHIFT 12
-#define HC_HSPYOS_MASK 0x00000fff
-
-/*
- * Command A
- */
-#define HC_HCmdHeader_MASK 0xfe000000 /*0xffe00000 */
-#define HC_HE3Fire_MASK 0x00100000
-#define HC_HPMType_MASK 0x000f0000
-#define HC_HEFlag_MASK 0x0000e000
-#define HC_HShading_MASK 0x00001c00
-#define HC_HPMValidN_MASK 0x00000200
-#define HC_HPLEND_MASK 0x00000100
-#define HC_HVCycle_MASK 0x000000ff
-#define HC_HVCycle_Style_MASK 0x000000c0
-#define HC_HVCycle_ChgA_MASK 0x00000030
-#define HC_HVCycle_ChgB_MASK 0x0000000c
-#define HC_HVCycle_ChgC_MASK 0x00000003
-#define HC_HPMType_Point 0x00000000
-#define HC_HPMType_Line 0x00010000
-#define HC_HPMType_Tri 0x00020000
-#define HC_HPMType_TriWF 0x00040000
-#define HC_HEFlag_NoAA 0x00000000
-#define HC_HEFlag_ab 0x00008000
-#define HC_HEFlag_bc 0x00004000
-#define HC_HEFlag_ca 0x00002000
-#define HC_HShading_Solid 0x00000000
-#define HC_HShading_FlatA 0x00000400
-#define HC_HShading_FlatB 0x00000800
-#define HC_HShading_FlatC 0x00000c00
-#define HC_HShading_Gouraud 0x00001000
-#define HC_HVCycle_Full 0x00000000
-#define HC_HVCycle_AFP 0x00000040
-#define HC_HVCycle_One 0x000000c0
-#define HC_HVCycle_NewA 0x00000000
-#define HC_HVCycle_AA 0x00000010
-#define HC_HVCycle_AB 0x00000020
-#define HC_HVCycle_AC 0x00000030
-#define HC_HVCycle_NewB 0x00000000
-#define HC_HVCycle_BA 0x00000004
-#define HC_HVCycle_BB 0x00000008
-#define HC_HVCycle_BC 0x0000000c
-#define HC_HVCycle_NewC 0x00000000
-#define HC_HVCycle_CA 0x00000001
-#define HC_HVCycle_CB 0x00000002
-#define HC_HVCycle_CC 0x00000003
-
-/* Command B
- */
-#define HC_HLPrst_MASK 0x00010000
-#define HC_HLLastP_MASK 0x00008000
-#define HC_HVPMSK_MASK 0x00007f80
-#define HC_HBFace_MASK 0x00000040
-#define HC_H2nd1VT_MASK 0x0000003f
-#define HC_HVPMSK_X 0x00004000
-#define HC_HVPMSK_Y 0x00002000
-#define HC_HVPMSK_Z 0x00001000
-#define HC_HVPMSK_W 0x00000800
-#define HC_HVPMSK_Cd 0x00000400
-#define HC_HVPMSK_Cs 0x00000200
-#define HC_HVPMSK_S 0x00000100
-#define HC_HVPMSK_T 0x00000080
-
-/* Enable Setting
- */
-#define HC_SubA_HEnable 0x0000
-#define HC_HenForce1P_MASK 0x00800000 /* [Force 1 Pipe] */
-#define HC_HenZDCheck_MASK 0x00400000 /* [Z dirty bit settings] */
-#define HC_HenTXEnvMap_MASK 0x00200000
-#define HC_HenVertexCNT_MASK 0x00100000
-#define HC_HenCPUDAZ_MASK 0x00080000
-#define HC_HenDASZWC_MASK 0x00040000
-#define HC_HenFBCull_MASK 0x00020000
-#define HC_HenCW_MASK 0x00010000
-#define HC_HenAA_MASK 0x00008000
-#define HC_HenST_MASK 0x00004000
-#define HC_HenZT_MASK 0x00002000
-#define HC_HenZW_MASK 0x00001000
-#define HC_HenAT_MASK 0x00000800
-#define HC_HenAW_MASK 0x00000400
-#define HC_HenSP_MASK 0x00000200
-#define HC_HenLP_MASK 0x00000100
-#define HC_HenTXCH_MASK 0x00000080
-#define HC_HenTXMP_MASK 0x00000040
-#define HC_HenTXPP_MASK 0x00000020
-#define HC_HenTXTR_MASK 0x00000010
-#define HC_HenCS_MASK 0x00000008
-#define HC_HenFOG_MASK 0x00000004
-#define HC_HenABL_MASK 0x00000002
-#define HC_HenDT_MASK 0x00000001
-
-/* Z Setting
- */
-#define HC_SubA_HZWBBasL 0x0010
-#define HC_SubA_HZWBBasH 0x0011
-#define HC_SubA_HZWBType 0x0012
-#define HC_SubA_HZBiasL 0x0013
-#define HC_SubA_HZWBend 0x0014
-#define HC_SubA_HZWTMD 0x0015
-#define HC_SubA_HZWCDL 0x0016
-#define HC_SubA_HZWCTAGnum 0x0017
-#define HC_SubA_HZCYNum 0x0018
-#define HC_SubA_HZWCFire 0x0019
-/* HC_SubA_HZWBType
- */
-#define HC_HZWBType_MASK 0x00800000
-#define HC_HZBiasedWB_MASK 0x00400000
-#define HC_HZONEasFF_MASK 0x00200000
-#define HC_HZOONEasFF_MASK 0x00100000
-#define HC_HZWBFM_MASK 0x00030000
-#define HC_HZWBLoc_MASK 0x0000c000
-#define HC_HZWBPit_MASK 0x00003fff
-#define HC_HZWBFM_16 0x00000000
-#define HC_HZWBFM_32 0x00020000
-#define HC_HZWBFM_24 0x00030000
-#define HC_HZWBLoc_Local 0x00000000
-#define HC_HZWBLoc_SyS 0x00004000
-/* HC_SubA_HZWBend
- */
-#define HC_HZWBend_MASK 0x00ffe000
-#define HC_HZBiasH_MASK 0x000000ff
-#define HC_HZWBend_SHIFT 10
-/* HC_SubA_HZWTMD
- */
-#define HC_HZWTMD_MASK 0x00070000
-#define HC_HEBEBias_MASK 0x00007f00
-#define HC_HZNF_MASK 0x000000ff
-#define HC_HZWTMD_NeverPass 0x00000000
-#define HC_HZWTMD_LT 0x00010000
-#define HC_HZWTMD_EQ 0x00020000
-#define HC_HZWTMD_LE 0x00030000
-#define HC_HZWTMD_GT 0x00040000
-#define HC_HZWTMD_NE 0x00050000
-#define HC_HZWTMD_GE 0x00060000
-#define HC_HZWTMD_AllPass 0x00070000
-#define HC_HEBEBias_SHIFT 8
-/* HC_SubA_HZWCDL 0x0016
- */
-#define HC_HZWCDL_MASK 0x00ffffff
-/* HC_SubA_HZWCTAGnum 0x0017
- */
-#define HC_HZWCTAGnum_MASK 0x00ff0000
-#define HC_HZWCTAGnum_SHIFT 16
-#define HC_HZWCDH_MASK 0x000000ff
-#define HC_HZWCDH_SHIFT 0
-/* HC_SubA_HZCYNum 0x0018
- */
-#define HC_HZCYNum_MASK 0x00030000
-#define HC_HZCYNum_SHIFT 16
-#define HC_HZWCQWnum_MASK 0x00003fff
-#define HC_HZWCQWnum_SHIFT 0
-/* HC_SubA_HZWCFire 0x0019
- */
-#define HC_ZWCFire_MASK 0x00010000
-#define HC_HZWCQWnumLast_MASK 0x00003fff
-#define HC_HZWCQWnumLast_SHIFT 0
-
-/* Stencil Setting
- */
-#define HC_SubA_HSTREF 0x0023
-#define HC_SubA_HSTMD 0x0024
-/* HC_SubA_HSBFM
- */
-#define HC_HSBFM_MASK 0x00030000
-#define HC_HSBLoc_MASK 0x0000c000
-#define HC_HSBPit_MASK 0x00003fff
-/* HC_SubA_HSTREF
- */
-#define HC_HSTREF_MASK 0x00ff0000
-#define HC_HSTOPMSK_MASK 0x0000ff00
-#define HC_HSTBMSK_MASK 0x000000ff
-#define HC_HSTREF_SHIFT 16
-#define HC_HSTOPMSK_SHIFT 8
-/* HC_SubA_HSTMD
- */
-#define HC_HSTMD_MASK 0x00070000
-#define HC_HSTOPSF_MASK 0x000001c0
-#define HC_HSTOPSPZF_MASK 0x00000038
-#define HC_HSTOPSPZP_MASK 0x00000007
-#define HC_HSTMD_NeverPass 0x00000000
-#define HC_HSTMD_LT 0x00010000
-#define HC_HSTMD_EQ 0x00020000
-#define HC_HSTMD_LE 0x00030000
-#define HC_HSTMD_GT 0x00040000
-#define HC_HSTMD_NE 0x00050000
-#define HC_HSTMD_GE 0x00060000
-#define HC_HSTMD_AllPass 0x00070000
-#define HC_HSTOPSF_KEEP 0x00000000
-#define HC_HSTOPSF_ZERO 0x00000040
-#define HC_HSTOPSF_REPLACE 0x00000080
-#define HC_HSTOPSF_INCRSAT 0x000000c0
-#define HC_HSTOPSF_DECRSAT 0x00000100
-#define HC_HSTOPSF_INVERT 0x00000140
-#define HC_HSTOPSF_INCR 0x00000180
-#define HC_HSTOPSF_DECR 0x000001c0
-#define HC_HSTOPSPZF_KEEP 0x00000000
-#define HC_HSTOPSPZF_ZERO 0x00000008
-#define HC_HSTOPSPZF_REPLACE 0x00000010
-#define HC_HSTOPSPZF_INCRSAT 0x00000018
-#define HC_HSTOPSPZF_DECRSAT 0x00000020
-#define HC_HSTOPSPZF_INVERT 0x00000028
-#define HC_HSTOPSPZF_INCR 0x00000030
-#define HC_HSTOPSPZF_DECR 0x00000038
-#define HC_HSTOPSPZP_KEEP 0x00000000
-#define HC_HSTOPSPZP_ZERO 0x00000001
-#define HC_HSTOPSPZP_REPLACE 0x00000002
-#define HC_HSTOPSPZP_INCRSAT 0x00000003
-#define HC_HSTOPSPZP_DECRSAT 0x00000004
-#define HC_HSTOPSPZP_INVERT 0x00000005
-#define HC_HSTOPSPZP_INCR 0x00000006
-#define HC_HSTOPSPZP_DECR 0x00000007
-
-/* Alpha Setting
- */
-#define HC_SubA_HABBasL 0x0030
-#define HC_SubA_HABBasH 0x0031
-#define HC_SubA_HABFM 0x0032
-#define HC_SubA_HATMD 0x0033
-#define HC_SubA_HABLCsat 0x0034
-#define HC_SubA_HABLCop 0x0035
-#define HC_SubA_HABLAsat 0x0036
-#define HC_SubA_HABLAop 0x0037
-#define HC_SubA_HABLRCa 0x0038
-#define HC_SubA_HABLRFCa 0x0039
-#define HC_SubA_HABLRCbias 0x003a
-#define HC_SubA_HABLRCb 0x003b
-#define HC_SubA_HABLRFCb 0x003c
-#define HC_SubA_HABLRAa 0x003d
-#define HC_SubA_HABLRAb 0x003e
-/* HC_SubA_HABFM
- */
-#define HC_HABFM_MASK 0x00030000
-#define HC_HABLoc_MASK 0x0000c000
-#define HC_HABPit_MASK 0x000007ff
-/* HC_SubA_HATMD
- */
-#define HC_HATMD_MASK 0x00000700
-#define HC_HATREF_MASK 0x000000ff
-#define HC_HATMD_NeverPass 0x00000000
-#define HC_HATMD_LT 0x00000100
-#define HC_HATMD_EQ 0x00000200
-#define HC_HATMD_LE 0x00000300
-#define HC_HATMD_GT 0x00000400
-#define HC_HATMD_NE 0x00000500
-#define HC_HATMD_GE 0x00000600
-#define HC_HATMD_AllPass 0x00000700
-/* HC_SubA_HABLCsat
- */
-#define HC_HABLCsat_MASK 0x00010000
-#define HC_HABLCa_MASK 0x0000fc00
-#define HC_HABLCa_C_MASK 0x0000c000
-#define HC_HABLCa_OPC_MASK 0x00003c00
-#define HC_HABLFCa_MASK 0x000003f0
-#define HC_HABLFCa_C_MASK 0x00000300
-#define HC_HABLFCa_OPC_MASK 0x000000f0
-#define HC_HABLCbias_MASK 0x0000000f
-#define HC_HABLCbias_C_MASK 0x00000008
-#define HC_HABLCbias_OPC_MASK 0x00000007
-/*-- Define the input color.
- */
-#define HC_XC_Csrc 0x00000000
-#define HC_XC_Cdst 0x00000001
-#define HC_XC_Asrc 0x00000002
-#define HC_XC_Adst 0x00000003
-#define HC_XC_Fog 0x00000004
-#define HC_XC_HABLRC 0x00000005
-#define HC_XC_minSrcDst 0x00000006
-#define HC_XC_maxSrcDst 0x00000007
-#define HC_XC_mimAsrcInvAdst 0x00000008
-#define HC_XC_OPC 0x00000000
-#define HC_XC_InvOPC 0x00000010
-#define HC_XC_OPCp5 0x00000020
-/*-- Define the input Alpha
- */
-#define HC_XA_OPA 0x00000000
-#define HC_XA_InvOPA 0x00000010
-#define HC_XA_OPAp5 0x00000020
-#define HC_XA_0 0x00000000
-#define HC_XA_Asrc 0x00000001
-#define HC_XA_Adst 0x00000002
-#define HC_XA_Fog 0x00000003
-#define HC_XA_minAsrcFog 0x00000004
-#define HC_XA_minAsrcAdst 0x00000005
-#define HC_XA_maxAsrcFog 0x00000006
-#define HC_XA_maxAsrcAdst 0x00000007
-#define HC_XA_HABLRA 0x00000008
-#define HC_XA_minAsrcInvAdst 0x00000008
-#define HC_XA_HABLFRA 0x00000009
-/*--
- */
-#define HC_HABLCa_OPC (HC_XC_OPC << 10)
-#define HC_HABLCa_InvOPC (HC_XC_InvOPC << 10)
-#define HC_HABLCa_OPCp5 (HC_XC_OPCp5 << 10)
-#define HC_HABLCa_Csrc (HC_XC_Csrc << 10)
-#define HC_HABLCa_Cdst (HC_XC_Cdst << 10)
-#define HC_HABLCa_Asrc (HC_XC_Asrc << 10)
-#define HC_HABLCa_Adst (HC_XC_Adst << 10)
-#define HC_HABLCa_Fog (HC_XC_Fog << 10)
-#define HC_HABLCa_HABLRCa (HC_XC_HABLRC << 10)
-#define HC_HABLCa_minSrcDst (HC_XC_minSrcDst << 10)
-#define HC_HABLCa_maxSrcDst (HC_XC_maxSrcDst << 10)
-#define HC_HABLFCa_OPC (HC_XC_OPC << 4)
-#define HC_HABLFCa_InvOPC (HC_XC_InvOPC << 4)
-#define HC_HABLFCa_OPCp5 (HC_XC_OPCp5 << 4)
-#define HC_HABLFCa_Csrc (HC_XC_Csrc << 4)
-#define HC_HABLFCa_Cdst (HC_XC_Cdst << 4)
-#define HC_HABLFCa_Asrc (HC_XC_Asrc << 4)
-#define HC_HABLFCa_Adst (HC_XC_Adst << 4)
-#define HC_HABLFCa_Fog (HC_XC_Fog << 4)
-#define HC_HABLFCa_HABLRCa (HC_XC_HABLRC << 4)
-#define HC_HABLFCa_minSrcDst (HC_XC_minSrcDst << 4)
-#define HC_HABLFCa_maxSrcDst (HC_XC_maxSrcDst << 4)
-#define HC_HABLFCa_mimAsrcInvAdst (HC_XC_mimAsrcInvAdst << 4)
-#define HC_HABLCbias_HABLRCbias 0x00000000
-#define HC_HABLCbias_Asrc 0x00000001
-#define HC_HABLCbias_Adst 0x00000002
-#define HC_HABLCbias_Fog 0x00000003
-#define HC_HABLCbias_Cin 0x00000004
-/* HC_SubA_HABLCop 0x0035
- */
-#define HC_HABLdot_MASK 0x00010000
-#define HC_HABLCop_MASK 0x00004000
-#define HC_HABLCb_MASK 0x00003f00
-#define HC_HABLCb_C_MASK 0x00003000
-#define HC_HABLCb_OPC_MASK 0x00000f00
-#define HC_HABLFCb_MASK 0x000000fc
-#define HC_HABLFCb_C_MASK 0x000000c0
-#define HC_HABLFCb_OPC_MASK 0x0000003c
-#define HC_HABLCshift_MASK 0x00000003
-#define HC_HABLCb_OPC (HC_XC_OPC << 8)
-#define HC_HABLCb_InvOPC (HC_XC_InvOPC << 8)
-#define HC_HABLCb_OPCp5 (HC_XC_OPCp5 << 8)
-#define HC_HABLCb_Csrc (HC_XC_Csrc << 8)
-#define HC_HABLCb_Cdst (HC_XC_Cdst << 8)
-#define HC_HABLCb_Asrc (HC_XC_Asrc << 8)
-#define HC_HABLCb_Adst (HC_XC_Adst << 8)
-#define HC_HABLCb_Fog (HC_XC_Fog << 8)
-#define HC_HABLCb_HABLRCa (HC_XC_HABLRC << 8)
-#define HC_HABLCb_minSrcDst (HC_XC_minSrcDst << 8)
-#define HC_HABLCb_maxSrcDst (HC_XC_maxSrcDst << 8)
-#define HC_HABLFCb_OPC (HC_XC_OPC << 2)
-#define HC_HABLFCb_InvOPC (HC_XC_InvOPC << 2)
-#define HC_HABLFCb_OPCp5 (HC_XC_OPCp5 << 2)
-#define HC_HABLFCb_Csrc (HC_XC_Csrc << 2)
-#define HC_HABLFCb_Cdst (HC_XC_Cdst << 2)
-#define HC_HABLFCb_Asrc (HC_XC_Asrc << 2)
-#define HC_HABLFCb_Adst (HC_XC_Adst << 2)
-#define HC_HABLFCb_Fog (HC_XC_Fog << 2)
-#define HC_HABLFCb_HABLRCb (HC_XC_HABLRC << 2)
-#define HC_HABLFCb_minSrcDst (HC_XC_minSrcDst << 2)
-#define HC_HABLFCb_maxSrcDst (HC_XC_maxSrcDst << 2)
-#define HC_HABLFCb_mimAsrcInvAdst (HC_XC_mimAsrcInvAdst << 2)
-/* HC_SubA_HABLAsat 0x0036
- */
-#define HC_HABLAsat_MASK 0x00010000
-#define HC_HABLAa_MASK 0x0000fc00
-#define HC_HABLAa_A_MASK 0x0000c000
-#define HC_HABLAa_OPA_MASK 0x00003c00
-#define HC_HABLFAa_MASK 0x000003f0
-#define HC_HABLFAa_A_MASK 0x00000300
-#define HC_HABLFAa_OPA_MASK 0x000000f0
-#define HC_HABLAbias_MASK 0x0000000f
-#define HC_HABLAbias_A_MASK 0x00000008
-#define HC_HABLAbias_OPA_MASK 0x00000007
-#define HC_HABLAa_OPA (HC_XA_OPA << 10)
-#define HC_HABLAa_InvOPA (HC_XA_InvOPA << 10)
-#define HC_HABLAa_OPAp5 (HC_XA_OPAp5 << 10)
-#define HC_HABLAa_0 (HC_XA_0 << 10)
-#define HC_HABLAa_Asrc (HC_XA_Asrc << 10)
-#define HC_HABLAa_Adst (HC_XA_Adst << 10)
-#define HC_HABLAa_Fog (HC_XA_Fog << 10)
-#define HC_HABLAa_minAsrcFog (HC_XA_minAsrcFog << 10)
-#define HC_HABLAa_minAsrcAdst (HC_XA_minAsrcAdst << 10)
-#define HC_HABLAa_maxAsrcFog (HC_XA_maxAsrcFog << 10)
-#define HC_HABLAa_maxAsrcAdst (HC_XA_maxAsrcAdst << 10)
-#define HC_HABLAa_HABLRA (HC_XA_HABLRA << 10)
-#define HC_HABLFAa_OPA (HC_XA_OPA << 4)
-#define HC_HABLFAa_InvOPA (HC_XA_InvOPA << 4)
-#define HC_HABLFAa_OPAp5 (HC_XA_OPAp5 << 4)
-#define HC_HABLFAa_0 (HC_XA_0 << 4)
-#define HC_HABLFAa_Asrc (HC_XA_Asrc << 4)
-#define HC_HABLFAa_Adst (HC_XA_Adst << 4)
-#define HC_HABLFAa_Fog (HC_XA_Fog << 4)
-#define HC_HABLFAa_minAsrcFog (HC_XA_minAsrcFog << 4)
-#define HC_HABLFAa_minAsrcAdst (HC_XA_minAsrcAdst << 4)
-#define HC_HABLFAa_maxAsrcFog (HC_XA_maxAsrcFog << 4)
-#define HC_HABLFAa_maxAsrcAdst (HC_XA_maxAsrcAdst << 4)
-#define HC_HABLFAa_minAsrcInvAdst (HC_XA_minAsrcInvAdst << 4)
-#define HC_HABLFAa_HABLFRA (HC_XA_HABLFRA << 4)
-#define HC_HABLAbias_HABLRAbias 0x00000000
-#define HC_HABLAbias_Asrc 0x00000001
-#define HC_HABLAbias_Adst 0x00000002
-#define HC_HABLAbias_Fog 0x00000003
-#define HC_HABLAbias_Aaa 0x00000004
-/* HC_SubA_HABLAop 0x0037
- */
-#define HC_HABLAop_MASK 0x00004000
-#define HC_HABLAb_MASK 0x00003f00
-#define HC_HABLAb_OPA_MASK 0x00000f00
-#define HC_HABLFAb_MASK 0x000000fc
-#define HC_HABLFAb_OPA_MASK 0x0000003c
-#define HC_HABLAshift_MASK 0x00000003
-#define HC_HABLAb_OPA (HC_XA_OPA << 8)
-#define HC_HABLAb_InvOPA (HC_XA_InvOPA << 8)
-#define HC_HABLAb_OPAp5 (HC_XA_OPAp5 << 8)
-#define HC_HABLAb_0 (HC_XA_0 << 8)
-#define HC_HABLAb_Asrc (HC_XA_Asrc << 8)
-#define HC_HABLAb_Adst (HC_XA_Adst << 8)
-#define HC_HABLAb_Fog (HC_XA_Fog << 8)
-#define HC_HABLAb_minAsrcFog (HC_XA_minAsrcFog << 8)
-#define HC_HABLAb_minAsrcAdst (HC_XA_minAsrcAdst << 8)
-#define HC_HABLAb_maxAsrcFog (HC_XA_maxAsrcFog << 8)
-#define HC_HABLAb_maxAsrcAdst (HC_XA_maxAsrcAdst << 8)
-#define HC_HABLAb_HABLRA (HC_XA_HABLRA << 8)
-#define HC_HABLFAb_OPA (HC_XA_OPA << 2)
-#define HC_HABLFAb_InvOPA (HC_XA_InvOPA << 2)
-#define HC_HABLFAb_OPAp5 (HC_XA_OPAp5 << 2)
-#define HC_HABLFAb_0 (HC_XA_0 << 2)
-#define HC_HABLFAb_Asrc (HC_XA_Asrc << 2)
-#define HC_HABLFAb_Adst (HC_XA_Adst << 2)
-#define HC_HABLFAb_Fog (HC_XA_Fog << 2)
-#define HC_HABLFAb_minAsrcFog (HC_XA_minAsrcFog << 2)
-#define HC_HABLFAb_minAsrcAdst (HC_XA_minAsrcAdst << 2)
-#define HC_HABLFAb_maxAsrcFog (HC_XA_maxAsrcFog << 2)
-#define HC_HABLFAb_maxAsrcAdst (HC_XA_maxAsrcAdst << 2)
-#define HC_HABLFAb_minAsrcInvAdst (HC_XA_minAsrcInvAdst << 2)
-#define HC_HABLFAb_HABLFRA (HC_XA_HABLFRA << 2)
-/* HC_SubA_HABLRAa 0x003d
- */
-#define HC_HABLRAa_MASK 0x00ff0000
-#define HC_HABLRFAa_MASK 0x0000ff00
-#define HC_HABLRAbias_MASK 0x000000ff
-#define HC_HABLRAa_SHIFT 16
-#define HC_HABLRFAa_SHIFT 8
-/* HC_SubA_HABLRAb 0x003e
- */
-#define HC_HABLRAb_MASK 0x0000ff00
-#define HC_HABLRFAb_MASK 0x000000ff
-#define HC_HABLRAb_SHIFT 8
-
-/* Destination Setting
- */
-#define HC_SubA_HDBBasL 0x0040
-#define HC_SubA_HDBBasH 0x0041
-#define HC_SubA_HDBFM 0x0042
-#define HC_SubA_HFBBMSKL 0x0043
-#define HC_SubA_HROP 0x0044
-/* HC_SubA_HDBFM 0x0042
- */
-#define HC_HDBFM_MASK 0x001f0000
-#define HC_HDBLoc_MASK 0x0000c000
-#define HC_HDBPit_MASK 0x00003fff
-#define HC_HDBFM_RGB555 0x00000000
-#define HC_HDBFM_RGB565 0x00010000
-#define HC_HDBFM_ARGB4444 0x00020000
-#define HC_HDBFM_ARGB1555 0x00030000
-#define HC_HDBFM_BGR555 0x00040000
-#define HC_HDBFM_BGR565 0x00050000
-#define HC_HDBFM_ABGR4444 0x00060000
-#define HC_HDBFM_ABGR1555 0x00070000
-#define HC_HDBFM_ARGB0888 0x00080000
-#define HC_HDBFM_ARGB8888 0x00090000
-#define HC_HDBFM_ABGR0888 0x000a0000
-#define HC_HDBFM_ABGR8888 0x000b0000
-#define HC_HDBLoc_Local 0x00000000
-#define HC_HDBLoc_Sys 0x00004000
-/* HC_SubA_HROP 0x0044
- */
-#define HC_HROP_MASK 0x00000f00
-#define HC_HFBBMSKH_MASK 0x000000ff
-#define HC_HROP_BLACK 0x00000000
-#define HC_HROP_DPon 0x00000100
-#define HC_HROP_DPna 0x00000200
-#define HC_HROP_Pn 0x00000300
-#define HC_HROP_PDna 0x00000400
-#define HC_HROP_Dn 0x00000500
-#define HC_HROP_DPx 0x00000600
-#define HC_HROP_DPan 0x00000700
-#define HC_HROP_DPa 0x00000800
-#define HC_HROP_DPxn 0x00000900
-#define HC_HROP_D 0x00000a00
-#define HC_HROP_DPno 0x00000b00
-#define HC_HROP_P 0x00000c00
-#define HC_HROP_PDno 0x00000d00
-#define HC_HROP_DPo 0x00000e00
-#define HC_HROP_WHITE 0x00000f00
-
-/* Fog Setting
- */
-#define HC_SubA_HFogLF 0x0050
-#define HC_SubA_HFogCL 0x0051
-#define HC_SubA_HFogCH 0x0052
-#define HC_SubA_HFogStL 0x0053
-#define HC_SubA_HFogStH 0x0054
-#define HC_SubA_HFogOOdMF 0x0055
-#define HC_SubA_HFogOOdEF 0x0056
-#define HC_SubA_HFogEndL 0x0057
-#define HC_SubA_HFogDenst 0x0058
-/* HC_SubA_FogLF 0x0050
- */
-#define HC_FogLF_MASK 0x00000010
-#define HC_FogEq_MASK 0x00000008
-#define HC_FogMD_MASK 0x00000007
-#define HC_FogMD_LocalFog 0x00000000
-#define HC_FogMD_LinearFog 0x00000002
-#define HC_FogMD_ExponentialFog 0x00000004
-#define HC_FogMD_Exponential2Fog 0x00000005
-/* #define HC_FogMD_FogTable 0x00000003 */
-
-/* HC_SubA_HFogDenst 0x0058
- */
-#define HC_FogDenst_MASK 0x001fff00
-#define HC_FogEndL_MASK 0x000000ff
-
-/* Texture subtype definitions
- */
-#define HC_SubType_Samp0 0x00000020
-#define HC_SubType_Samp1 0x00000021
-
-
-/* Texture subtype definitions
- */
-#define HC_SubType_Tex0 0x00000000
-#define HC_SubType_Tex1 0x00000001
-#define HC_SubType_TexGeneral 0x000000fe
-
-/* Attribute of texture n
- */
-#define HC_SubA_HTXnL0BasL 0x0000
-#define HC_SubA_HTXnL1BasL 0x0001
-#define HC_SubA_HTXnL2BasL 0x0002
-#define HC_SubA_HTXnL3BasL 0x0003
-#define HC_SubA_HTXnL4BasL 0x0004
-#define HC_SubA_HTXnL5BasL 0x0005
-#define HC_SubA_HTXnL6BasL 0x0006
-#define HC_SubA_HTXnL7BasL 0x0007
-#define HC_SubA_HTXnL8BasL 0x0008
-#define HC_SubA_HTXnL9BasL 0x0009
-#define HC_SubA_HTXnLaBasL 0x000a
-#define HC_SubA_HTXnLbBasL 0x000b
-#define HC_SubA_HTXnLcBasL 0x000c
-#define HC_SubA_HTXnLdBasL 0x000d
-#define HC_SubA_HTXnLeBasL 0x000e
-#define HC_SubA_HTXnLfBasL 0x000f
-#define HC_SubA_HTXnL10BasL 0x0010
-#define HC_SubA_HTXnL11BasL 0x0011
-#define HC_SubA_HTXnL012BasH 0x0020
-#define HC_SubA_HTXnL345BasH 0x0021
-#define HC_SubA_HTXnL678BasH 0x0022
-#define HC_SubA_HTXnL9abBasH 0x0023
-#define HC_SubA_HTXnLcdeBasH 0x0024
-#define HC_SubA_HTXnLf1011BasH 0x0025
-#define HC_SubA_HTXnL0Pit 0x002b
-#define HC_SubA_HTXnL1Pit 0x002c
-#define HC_SubA_HTXnL2Pit 0x002d
-#define HC_SubA_HTXnL3Pit 0x002e
-#define HC_SubA_HTXnL4Pit 0x002f
-#define HC_SubA_HTXnL5Pit 0x0030
-#define HC_SubA_HTXnL6Pit 0x0031
-#define HC_SubA_HTXnL7Pit 0x0032
-#define HC_SubA_HTXnL8Pit 0x0033
-#define HC_SubA_HTXnL9Pit 0x0034
-#define HC_SubA_HTXnLaPit 0x0035
-#define HC_SubA_HTXnLbPit 0x0036
-#define HC_SubA_HTXnLcPit 0x0037
-#define HC_SubA_HTXnLdPit 0x0038
-#define HC_SubA_HTXnLePit 0x0039
-#define HC_SubA_HTXnLfPit 0x003a
-#define HC_SubA_HTXnL10Pit 0x003b
-#define HC_SubA_HTXnL11Pit 0x003c
-#define HC_SubA_HTXnL0_5WE 0x004b
-#define HC_SubA_HTXnL6_bWE 0x004c
-#define HC_SubA_HTXnLc_11WE 0x004d
-#define HC_SubA_HTXnL0_5HE 0x0051
-#define HC_SubA_HTXnL6_bHE 0x0052
-#define HC_SubA_HTXnLc_11HE 0x0053
-#define HC_SubA_HTXnL0OS 0x0077
-#define HC_SubA_HTXnTB 0x0078
-#define HC_SubA_HTXnMPMD 0x0079
-#define HC_SubA_HTXnCLODu 0x007a
-#define HC_SubA_HTXnFM 0x007b
-#define HC_SubA_HTXnTRCH 0x007c
-#define HC_SubA_HTXnTRCL 0x007d
-#define HC_SubA_HTXnTBC 0x007e
-#define HC_SubA_HTXnTRAH 0x007f
-#define HC_SubA_HTXnTBLCsat 0x0080
-#define HC_SubA_HTXnTBLCop 0x0081
-#define HC_SubA_HTXnTBLMPfog 0x0082
-#define HC_SubA_HTXnTBLAsat 0x0083
-#define HC_SubA_HTXnTBLRCa 0x0085
-#define HC_SubA_HTXnTBLRCb 0x0086
-#define HC_SubA_HTXnTBLRCc 0x0087
-#define HC_SubA_HTXnTBLRCbias 0x0088
-#define HC_SubA_HTXnTBLRAa 0x0089
-#define HC_SubA_HTXnTBLRFog 0x008a
-#define HC_SubA_HTXnBumpM00 0x0090
-#define HC_SubA_HTXnBumpM01 0x0091
-#define HC_SubA_HTXnBumpM10 0x0092
-#define HC_SubA_HTXnBumpM11 0x0093
-#define HC_SubA_HTXnLScale 0x0094
-
-#define HC_SubA_HTXSMD 0x0000
-#define HC_SubA_HTXYUV2RGB1 0x0001
-#define HC_SubA_HTXYUV2RGB2 0x0002
-#define HC_SubA_HTXYUV2RGB3 0x0003
-#define HTXYUV2RGB4BT601 (1<<23)
-#define HTXYUV2RGB4BT709 (1<<22)
-/* HC_SubA_HTXnL012BasH 0x0020
- */
-#define HC_HTXnL0BasH_MASK 0x000000ff
-#define HC_HTXnL1BasH_MASK 0x0000ff00
-#define HC_HTXnL2BasH_MASK 0x00ff0000
-#define HC_HTXnL1BasH_SHIFT 8
-#define HC_HTXnL2BasH_SHIFT 16
-/* HC_SubA_HTXnL345BasH 0x0021
- */
-#define HC_HTXnL3BasH_MASK 0x000000ff
-#define HC_HTXnL4BasH_MASK 0x0000ff00
-#define HC_HTXnL5BasH_MASK 0x00ff0000
-#define HC_HTXnL4BasH_SHIFT 8
-#define HC_HTXnL5BasH_SHIFT 16
-/* HC_SubA_HTXnL678BasH 0x0022
- */
-#define HC_HTXnL6BasH_MASK 0x000000ff
-#define HC_HTXnL7BasH_MASK 0x0000ff00
-#define HC_HTXnL8BasH_MASK 0x00ff0000
-#define HC_HTXnL7BasH_SHIFT 8
-#define HC_HTXnL8BasH_SHIFT 16
-/* HC_SubA_HTXnL9abBasH 0x0023
- */
-#define HC_HTXnL9BasH_MASK 0x000000ff
-#define HC_HTXnLaBasH_MASK 0x0000ff00
-#define HC_HTXnLbBasH_MASK 0x00ff0000
-#define HC_HTXnLaBasH_SHIFT 8
-#define HC_HTXnLbBasH_SHIFT 16
-/* HC_SubA_HTXnLcdeBasH 0x0024
- */
-#define HC_HTXnLcBasH_MASK 0x000000ff
-#define HC_HTXnLdBasH_MASK 0x0000ff00
-#define HC_HTXnLeBasH_MASK 0x00ff0000
-#define HC_HTXnLdBasH_SHIFT 8
-#define HC_HTXnLeBasH_SHIFT 16
-/* HC_SubA_HTXnLcdeBasH 0x0025
- */
-#define HC_HTXnLfBasH_MASK 0x000000ff
-#define HC_HTXnL10BasH_MASK 0x0000ff00
-#define HC_HTXnL11BasH_MASK 0x00ff0000
-#define HC_HTXnL10BasH_SHIFT 8
-#define HC_HTXnL11BasH_SHIFT 16
-/* HC_SubA_HTXnL0Pit 0x002b
- */
-#define HC_HTXnLnPit_MASK 0x00003fff
-#define HC_HTXnEnPit_MASK 0x00080000
-#define HC_HTXnLnPitE_MASK 0x00f00000
-#define HC_HTXnLnPitE_SHIFT 20
-/* HC_SubA_HTXnL0_5WE 0x004b
- */
-#define HC_HTXnL0WE_MASK 0x0000000f
-#define HC_HTXnL1WE_MASK 0x000000f0
-#define HC_HTXnL2WE_MASK 0x00000f00
-#define HC_HTXnL3WE_MASK 0x0000f000
-#define HC_HTXnL4WE_MASK 0x000f0000
-#define HC_HTXnL5WE_MASK 0x00f00000
-#define HC_HTXnL1WE_SHIFT 4
-#define HC_HTXnL2WE_SHIFT 8
-#define HC_HTXnL3WE_SHIFT 12
-#define HC_HTXnL4WE_SHIFT 16
-#define HC_HTXnL5WE_SHIFT 20
-/* HC_SubA_HTXnL6_bWE 0x004c
- */
-#define HC_HTXnL6WE_MASK 0x0000000f
-#define HC_HTXnL7WE_MASK 0x000000f0
-#define HC_HTXnL8WE_MASK 0x00000f00
-#define HC_HTXnL9WE_MASK 0x0000f000
-#define HC_HTXnLaWE_MASK 0x000f0000
-#define HC_HTXnLbWE_MASK 0x00f00000
-#define HC_HTXnL7WE_SHIFT 4
-#define HC_HTXnL8WE_SHIFT 8
-#define HC_HTXnL9WE_SHIFT 12
-#define HC_HTXnLaWE_SHIFT 16
-#define HC_HTXnLbWE_SHIFT 20
-/* HC_SubA_HTXnLc_11WE 0x004d
- */
-#define HC_HTXnLcWE_MASK 0x0000000f
-#define HC_HTXnLdWE_MASK 0x000000f0
-#define HC_HTXnLeWE_MASK 0x00000f00
-#define HC_HTXnLfWE_MASK 0x0000f000
-#define HC_HTXnL10WE_MASK 0x000f0000
-#define HC_HTXnL11WE_MASK 0x00f00000
-#define HC_HTXnLdWE_SHIFT 4
-#define HC_HTXnLeWE_SHIFT 8
-#define HC_HTXnLfWE_SHIFT 12
-#define HC_HTXnL10WE_SHIFT 16
-#define HC_HTXnL11WE_SHIFT 20
-/* HC_SubA_HTXnL0_5HE 0x0051
- */
-#define HC_HTXnL0HE_MASK 0x0000000f
-#define HC_HTXnL1HE_MASK 0x000000f0
-#define HC_HTXnL2HE_MASK 0x00000f00
-#define HC_HTXnL3HE_MASK 0x0000f000
-#define HC_HTXnL4HE_MASK 0x000f0000
-#define HC_HTXnL5HE_MASK 0x00f00000
-#define HC_HTXnL1HE_SHIFT 4
-#define HC_HTXnL2HE_SHIFT 8
-#define HC_HTXnL3HE_SHIFT 12
-#define HC_HTXnL4HE_SHIFT 16
-#define HC_HTXnL5HE_SHIFT 20
-/* HC_SubA_HTXnL6_bHE 0x0052
- */
-#define HC_HTXnL6HE_MASK 0x0000000f
-#define HC_HTXnL7HE_MASK 0x000000f0
-#define HC_HTXnL8HE_MASK 0x00000f00
-#define HC_HTXnL9HE_MASK 0x0000f000
-#define HC_HTXnLaHE_MASK 0x000f0000
-#define HC_HTXnLbHE_MASK 0x00f00000
-#define HC_HTXnL7HE_SHIFT 4
-#define HC_HTXnL8HE_SHIFT 8
-#define HC_HTXnL9HE_SHIFT 12
-#define HC_HTXnLaHE_SHIFT 16
-#define HC_HTXnLbHE_SHIFT 20
-/* HC_SubA_HTXnLc_11HE 0x0053
- */
-#define HC_HTXnLcHE_MASK 0x0000000f
-#define HC_HTXnLdHE_MASK 0x000000f0
-#define HC_HTXnLeHE_MASK 0x00000f00
-#define HC_HTXnLfHE_MASK 0x0000f000
-#define HC_HTXnL10HE_MASK 0x000f0000
-#define HC_HTXnL11HE_MASK 0x00f00000
-#define HC_HTXnLdHE_SHIFT 4
-#define HC_HTXnLeHE_SHIFT 8
-#define HC_HTXnLfHE_SHIFT 12
-#define HC_HTXnL10HE_SHIFT 16
-#define HC_HTXnL11HE_SHIFT 20
-/* HC_SubA_HTXnL0OS 0x0077
- */
-#define HC_HTXnL0OS_MASK 0x003ff000
-#define HC_HTXnLVmax_MASK 0x00000fc0
-#define HC_HTXnLVmin_MASK 0x0000003f
-#define HC_HTXnL0OS_SHIFT 12
-#define HC_HTXnLVmax_SHIFT 6
-/* HC_SubA_HTXnTB 0x0078
- */
-#define HC_HTXnTB_MASK 0x00f00000
-#define HC_HTXnFLSe_MASK 0x0000e000
-#define HC_HTXnFLSs_MASK 0x00001c00
-#define HC_HTXnFLTe_MASK 0x00000380
-#define HC_HTXnFLTs_MASK 0x00000070
-#define HC_HTXnFLDs_MASK 0x0000000f
-#define HC_HTXnTB_NoTB 0x00000000
-#define HC_HTXnTB_TBC_S 0x00100000
-#define HC_HTXnTB_TBC_T 0x00200000
-#define HC_HTXnTB_TB_S 0x00400000
-#define HC_HTXnTB_TB_T 0x00800000
-#define HC_HTXnFLSe_Nearest 0x00000000
-#define HC_HTXnFLSe_Linear 0x00002000
-#define HC_HTXnFLSe_NonLinear 0x00004000
-#define HC_HTXnFLSe_Sharp 0x00008000
-#define HC_HTXnFLSe_Flat_Gaussian_Cubic 0x0000c000
-#define HC_HTXnFLSs_Nearest 0x00000000
-#define HC_HTXnFLSs_Linear 0x00000400
-#define HC_HTXnFLSs_NonLinear 0x00000800
-#define HC_HTXnFLSs_Flat_Gaussian_Cubic 0x00001800
-#define HC_HTXnFLTe_Nearest 0x00000000
-#define HC_HTXnFLTe_Linear 0x00000080
-#define HC_HTXnFLTe_NonLinear 0x00000100
-#define HC_HTXnFLTe_Sharp 0x00000180
-#define HC_HTXnFLTe_Flat_Gaussian_Cubic 0x00000300
-#define HC_HTXnFLTs_Nearest 0x00000000
-#define HC_HTXnFLTs_Linear 0x00000010
-#define HC_HTXnFLTs_NonLinear 0x00000020
-#define HC_HTXnFLTs_Flat_Gaussian_Cubic 0x00000060
-#define HC_HTXnFLDs_Tex0 0x00000000
-#define HC_HTXnFLDs_Nearest 0x00000001
-#define HC_HTXnFLDs_Linear 0x00000002
-#define HC_HTXnFLDs_NonLinear 0x00000003
-#define HC_HTXnFLDs_Dither 0x00000004
-#define HC_HTXnFLDs_ConstLOD 0x00000005
-#define HC_HTXnFLDs_Ani 0x00000006
-#define HC_HTXnFLDs_AniDither 0x00000007
-/* HC_SubA_HTXnMPMD 0x0079
- */
-#define HC_HTXnMPMD_SMASK 0x00070000
-#define HC_HTXnMPMD_TMASK 0x00380000
-#define HC_HTXnLODDTf_MASK 0x00000007
-#define HC_HTXnXY2ST_MASK 0x00000008
-#define HC_HTXnMPMD_Tsingle 0x00000000
-#define HC_HTXnMPMD_Tclamp 0x00080000
-#define HC_HTXnMPMD_Trepeat 0x00100000
-#define HC_HTXnMPMD_Tmirror 0x00180000
-#define HC_HTXnMPMD_Twrap 0x00200000
-#define HC_HTXnMPMD_Ssingle 0x00000000
-#define HC_HTXnMPMD_Sclamp 0x00010000
-#define HC_HTXnMPMD_Srepeat 0x00020000
-#define HC_HTXnMPMD_Smirror 0x00030000
-#define HC_HTXnMPMD_Swrap 0x00040000
-/* HC_SubA_HTXnCLODu 0x007a
- */
-#define HC_HTXnCLODu_MASK 0x000ffc00
-#define HC_HTXnCLODd_MASK 0x000003ff
-#define HC_HTXnCLODu_SHIFT 10
-/* HC_SubA_HTXnFM 0x007b
- */
-#define HC_HTXnFM_MASK 0x00ff0000
-#define HC_HTXnLoc_MASK 0x00000003
-#define HC_HTXnFM_INDEX 0x00000000
-#define HC_HTXnFM_Intensity 0x00080000
-#define HC_HTXnFM_Lum 0x00100000
-#define HC_HTXnFM_Alpha 0x00180000
-#define HC_HTXnFM_DX 0x00280000
-#define HC_HTXnFM_YUV 0x00300000
-#define HC_HTXnFM_ARGB16 0x00880000
-#define HC_HTXnFM_ARGB32 0x00980000
-#define HC_HTXnFM_ABGR16 0x00a80000
-#define HC_HTXnFM_ABGR32 0x00b80000
-#define HC_HTXnFM_RGBA16 0x00c80000
-#define HC_HTXnFM_RGBA32 0x00d80000
-#define HC_HTXnFM_BGRA16 0x00e80000
-#define HC_HTXnFM_BGRA32 0x00f80000
-#define HC_HTXnFM_BUMPMAP 0x00380000
-#define HC_HTXnFM_Index1 (HC_HTXnFM_INDEX | 0x00000000)
-#define HC_HTXnFM_Index2 (HC_HTXnFM_INDEX | 0x00010000)
-#define HC_HTXnFM_Index4 (HC_HTXnFM_INDEX | 0x00020000)
-#define HC_HTXnFM_Index8 (HC_HTXnFM_INDEX | 0x00030000)
-#define HC_HTXnFM_T1 (HC_HTXnFM_Intensity | 0x00000000)
-#define HC_HTXnFM_T2 (HC_HTXnFM_Intensity | 0x00010000)
-#define HC_HTXnFM_T4 (HC_HTXnFM_Intensity | 0x00020000)
-#define HC_HTXnFM_T8 (HC_HTXnFM_Intensity | 0x00030000)
-#define HC_HTXnFM_L1 (HC_HTXnFM_Lum | 0x00000000)
-#define HC_HTXnFM_L2 (HC_HTXnFM_Lum | 0x00010000)
-#define HC_HTXnFM_L4 (HC_HTXnFM_Lum | 0x00020000)
-#define HC_HTXnFM_L8 (HC_HTXnFM_Lum | 0x00030000)
-#define HC_HTXnFM_AL44 (HC_HTXnFM_Lum | 0x00040000)
-#define HC_HTXnFM_AL88 (HC_HTXnFM_Lum | 0x00050000)
-#define HC_HTXnFM_A1 (HC_HTXnFM_Alpha | 0x00000000)
-#define HC_HTXnFM_A2 (HC_HTXnFM_Alpha | 0x00010000)
-#define HC_HTXnFM_A4 (HC_HTXnFM_Alpha | 0x00020000)
-#define HC_HTXnFM_A8 (HC_HTXnFM_Alpha | 0x00030000)
-#define HC_HTXnFM_DX1 (HC_HTXnFM_DX | 0x00010000)
-#define HC_HTXnFM_DX23 (HC_HTXnFM_DX | 0x00020000)
-#define HC_HTXnFM_DX45 (HC_HTXnFM_DX | 0x00030000)
-/* YUV package mode */
-#define HC_HTXnFM_YUY2 (HC_HTXnFM_YUV | 0x00000000)
-/* YUV planner mode */
-#define HC_HTXnFM_YV12 (HC_HTXnFM_YUV | 0x00040000)
-/* YUV planner mode */
-#define HC_HTXnFM_IYUV (HC_HTXnFM_YUV | 0x00040000)
-#define HC_HTXnFM_RGB555 (HC_HTXnFM_ARGB16 | 0x00000000)
-#define HC_HTXnFM_RGB565 (HC_HTXnFM_ARGB16 | 0x00010000)
-#define HC_HTXnFM_ARGB1555 (HC_HTXnFM_ARGB16 | 0x00020000)
-#define HC_HTXnFM_ARGB4444 (HC_HTXnFM_ARGB16 | 0x00030000)
-#define HC_HTXnFM_ARGB0888 (HC_HTXnFM_ARGB32 | 0x00000000)
-#define HC_HTXnFM_ARGB8888 (HC_HTXnFM_ARGB32 | 0x00010000)
-#define HC_HTXnFM_BGR555 (HC_HTXnFM_ABGR16 | 0x00000000)
-#define HC_HTXnFM_BGR565 (HC_HTXnFM_ABGR16 | 0x00010000)
-#define HC_HTXnFM_ABGR1555 (HC_HTXnFM_ABGR16 | 0x00020000)
-#define HC_HTXnFM_ABGR4444 (HC_HTXnFM_ABGR16 | 0x00030000)
-#define HC_HTXnFM_ABGR0888 (HC_HTXnFM_ABGR32 | 0x00000000)
-#define HC_HTXnFM_ABGR8888 (HC_HTXnFM_ABGR32 | 0x00010000)
-#define HC_HTXnFM_RGBA5550 (HC_HTXnFM_RGBA16 | 0x00000000)
-#define HC_HTXnFM_RGBA5551 (HC_HTXnFM_RGBA16 | 0x00020000)
-#define HC_HTXnFM_RGBA4444 (HC_HTXnFM_RGBA16 | 0x00030000)
-#define HC_HTXnFM_RGBA8880 (HC_HTXnFM_RGBA32 | 0x00000000)
-#define HC_HTXnFM_RGBA8888 (HC_HTXnFM_RGBA32 | 0x00010000)
-#define HC_HTXnFM_BGRA5550 (HC_HTXnFM_BGRA16 | 0x00000000)
-#define HC_HTXnFM_BGRA5551 (HC_HTXnFM_BGRA16 | 0x00020000)
-#define HC_HTXnFM_BGRA4444 (HC_HTXnFM_BGRA16 | 0x00030000)
-#define HC_HTXnFM_BGRA8880 (HC_HTXnFM_BGRA32 | 0x00000000)
-#define HC_HTXnFM_BGRA8888 (HC_HTXnFM_BGRA32 | 0x00010000)
-#define HC_HTXnFM_VU88 (HC_HTXnFM_BUMPMAP | 0x00000000)
-#define HC_HTXnFM_LVU655 (HC_HTXnFM_BUMPMAP | 0x00010000)
-#define HC_HTXnFM_LVU888 (HC_HTXnFM_BUMPMAP | 0x00020000)
-#define HC_HTXnLoc_Local 0x00000000
-#define HC_HTXnLoc_Sys 0x00000002
-#define HC_HTXnLoc_AGP 0x00000003
-
-/* Video Texture */
-#define HC_HTXnYUV2RGBMode_RGB 0x00000000
-#define HC_HTXnYUV2RGBMode_SDTV 0x00000001
-#define HC_HTXnYUV2RGBMode_HDTV 0x00000002
-#define HC_HTXnYUV2RGBMode_TABLE 0x00000003
-
-/* HC_SubA_HTXnTRAH 0x007f
- */
-#define HC_HTXnTRAH_MASK 0x00ff0000
-#define HC_HTXnTRAL_MASK 0x0000ff00
-#define HC_HTXnTBA_MASK 0x000000ff
-#define HC_HTXnTRAH_SHIFT 16
-#define HC_HTXnTRAL_SHIFT 8
-/* HC_SubA_HTXnTBLCsat 0x0080
- *-- Define the input texture.
- */
-#define HC_XTC_TOPC 0x00000000
-#define HC_XTC_InvTOPC 0x00000010
-#define HC_XTC_TOPCp5 0x00000020
-#define HC_XTC_Cbias 0x00000000
-#define HC_XTC_InvCbias 0x00000010
-#define HC_XTC_0 0x00000000
-#define HC_XTC_Dif 0x00000001
-#define HC_XTC_Spec 0x00000002
-#define HC_XTC_Tex 0x00000003
-#define HC_XTC_Cur 0x00000004
-#define HC_XTC_Adif 0x00000005
-#define HC_XTC_Fog 0x00000006
-#define HC_XTC_Atex 0x00000007
-#define HC_XTC_Acur 0x00000008
-#define HC_XTC_HTXnTBLRC 0x00000009
-#define HC_XTC_Ctexnext 0x0000000a
-/*--
- */
-#define HC_HTXnTBLCsat_MASK 0x00800000
-#define HC_HTXnTBLCa_MASK 0x000fc000
-#define HC_HTXnTBLCb_MASK 0x00001f80
-#define HC_HTXnTBLCc_MASK 0x0000003f
-#define HC_HTXnTBLCa_TOPC (HC_XTC_TOPC << 14)
-#define HC_HTXnTBLCa_InvTOPC (HC_XTC_InvTOPC << 14)
-#define HC_HTXnTBLCa_TOPCp5 (HC_XTC_TOPCp5 << 14)
-#define HC_HTXnTBLCa_0 (HC_XTC_0 << 14)
-#define HC_HTXnTBLCa_Dif (HC_XTC_Dif << 14)
-#define HC_HTXnTBLCa_Spec (HC_XTC_Spec << 14)
-#define HC_HTXnTBLCa_Tex (HC_XTC_Tex << 14)
-#define HC_HTXnTBLCa_Cur (HC_XTC_Cur << 14)
-#define HC_HTXnTBLCa_Adif (HC_XTC_Adif << 14)
-#define HC_HTXnTBLCa_Fog (HC_XTC_Fog << 14)
-#define HC_HTXnTBLCa_Atex (HC_XTC_Atex << 14)
-#define HC_HTXnTBLCa_Acur (HC_XTC_Acur << 14)
-#define HC_HTXnTBLCa_HTXnTBLRC (HC_XTC_HTXnTBLRC << 14)
-#define HC_HTXnTBLCa_Ctexnext (HC_XTC_Ctexnext << 14)
-#define HC_HTXnTBLCb_TOPC (HC_XTC_TOPC << 7)
-#define HC_HTXnTBLCb_InvTOPC (HC_XTC_InvTOPC << 7)
-#define HC_HTXnTBLCb_TOPCp5 (HC_XTC_TOPCp5 << 7)
-#define HC_HTXnTBLCb_0 (HC_XTC_0 << 7)
-#define HC_HTXnTBLCb_Dif (HC_XTC_Dif << 7)
-#define HC_HTXnTBLCb_Spec (HC_XTC_Spec << 7)
-#define HC_HTXnTBLCb_Tex (HC_XTC_Tex << 7)
-#define HC_HTXnTBLCb_Cur (HC_XTC_Cur << 7)
-#define HC_HTXnTBLCb_Adif (HC_XTC_Adif << 7)
-#define HC_HTXnTBLCb_Fog (HC_XTC_Fog << 7)
-#define HC_HTXnTBLCb_Atex (HC_XTC_Atex << 7)
-#define HC_HTXnTBLCb_Acur (HC_XTC_Acur << 7)
-#define HC_HTXnTBLCb_HTXnTBLRC (HC_XTC_HTXnTBLRC << 7)
-#define HC_HTXnTBLCb_Ctexnext (HC_XTC_Ctexnext << 7)
-#define HC_HTXnTBLCc_TOPC (HC_XTC_TOPC << 0)
-#define HC_HTXnTBLCc_InvTOPC (HC_XTC_InvTOPC << 0)
-#define HC_HTXnTBLCc_TOPCp5 (HC_XTC_TOPCp5 << 0)
-#define HC_HTXnTBLCc_0 (HC_XTC_0 << 0)
-#define HC_HTXnTBLCc_Dif (HC_XTC_Dif << 0)
-#define HC_HTXnTBLCc_Spec (HC_XTC_Spec << 0)
-#define HC_HTXnTBLCc_Tex (HC_XTC_Tex << 0)
-#define HC_HTXnTBLCc_Cur (HC_XTC_Cur << 0)
-#define HC_HTXnTBLCc_Adif (HC_XTC_Adif << 0)
-#define HC_HTXnTBLCc_Fog (HC_XTC_Fog << 0)
-#define HC_HTXnTBLCc_Atex (HC_XTC_Atex << 0)
-#define HC_HTXnTBLCc_Acur (HC_XTC_Acur << 0)
-#define HC_HTXnTBLCc_HTXnTBLRC (HC_XTC_HTXnTBLRC << 0)
-#define HC_HTXnTBLCc_Ctexnext (HC_XTC_Ctexnext << 0)
-/* HC_SubA_HTXnTBLCop 0x0081
- */
-#define HC_HTXnTBLdot_MASK 0x00c00000
-#define HC_HTXnTBLCop_MASK 0x00380000
-#define HC_HTXnTBLCbias_MASK 0x0007c000
-#define HC_HTXnTBLCshift_MASK 0x00001800
-#define HC_HTXnTBLAop_MASK 0x00000380
-#define HC_HTXnTBLAbias_MASK 0x00000078
-#define HC_HTXnTBLAshift_MASK 0x00000003
-#define HC_HTXnTBLCop_Add 0x00000000
-#define HC_HTXnTBLCop_Sub 0x00080000
-#define HC_HTXnTBLCop_Min 0x00100000
-#define HC_HTXnTBLCop_Max 0x00180000
-#define HC_HTXnTBLCop_Mask 0x00200000
-#define HC_HTXnTBLCbias_Cbias (HC_XTC_Cbias << 14)
-#define HC_HTXnTBLCbias_InvCbias (HC_XTC_InvCbias << 14)
-#define HC_HTXnTBLCbias_0 (HC_XTC_0 << 14)
-#define HC_HTXnTBLCbias_Dif (HC_XTC_Dif << 14)
-#define HC_HTXnTBLCbias_Spec (HC_XTC_Spec << 14)
-#define HC_HTXnTBLCbias_Tex (HC_XTC_Tex << 14)
-#define HC_HTXnTBLCbias_Cur (HC_XTC_Cur << 14)
-#define HC_HTXnTBLCbias_Adif (HC_XTC_Adif << 14)
-#define HC_HTXnTBLCbias_Fog (HC_XTC_Fog << 14)
-#define HC_HTXnTBLCbias_Atex (HC_XTC_Atex << 14)
-#define HC_HTXnTBLCbias_Acur (HC_XTC_Acur << 14)
-#define HC_HTXnTBLCbias_HTXnTBLRC (HC_XTC_HTXnTBLRC << 14)
-#define HC_HTXnTBLCshift_1 0x00000000
-#define HC_HTXnTBLCshift_2 0x00000800
-#define HC_HTXnTBLCshift_No 0x00001000
-#define HC_HTXnTBLCshift_DotP 0x00001800
-/*=* John Sheng [2003.7.18] texture combine *=*/
-#define HC_HTXnTBLDOT3 0x00080000
-#define HC_HTXnTBLDOT4 0x000C0000
-
-#define HC_HTXnTBLAop_Add 0x00000000
-#define HC_HTXnTBLAop_Sub 0x00000080
-#define HC_HTXnTBLAop_Min 0x00000100
-#define HC_HTXnTBLAop_Max 0x00000180
-#define HC_HTXnTBLAop_Mask 0x00000200
-#define HC_HTXnTBLAbias_Inv 0x00000040
-#define HC_HTXnTBLAbias_Adif 0x00000000
-#define HC_HTXnTBLAbias_Fog 0x00000008
-#define HC_HTXnTBLAbias_Acur 0x00000010
-#define HC_HTXnTBLAbias_HTXnTBLRAbias 0x00000018
-#define HC_HTXnTBLAbias_Atex 0x00000020
-#define HC_HTXnTBLAshift_1 0x00000000
-#define HC_HTXnTBLAshift_2 0x00000001
-#define HC_HTXnTBLAshift_No 0x00000002
-/* #define HC_HTXnTBLAshift_DotP 0x00000003 */
-/* HC_SubA_HTXnTBLMPFog 0x0082
- */
-#define HC_HTXnTBLMPfog_MASK 0x00e00000
-#define HC_HTXnTBLMPfog_0 0x00000000
-#define HC_HTXnTBLMPfog_Adif 0x00200000
-#define HC_HTXnTBLMPfog_Fog 0x00400000
-#define HC_HTXnTBLMPfog_Atex 0x00600000
-#define HC_HTXnTBLMPfog_Acur 0x00800000
-#define HC_HTXnTBLMPfog_GHTXnTBLRFog 0x00a00000
-/* HC_SubA_HTXnTBLAsat 0x0083
- *-- Define the texture alpha input.
- */
-#define HC_XTA_TOPA 0x00000000
-#define HC_XTA_InvTOPA 0x00000008
-#define HC_XTA_TOPAp5 0x00000010
-#define HC_XTA_Adif 0x00000000
-#define HC_XTA_Fog 0x00000001
-#define HC_XTA_Acur 0x00000002
-#define HC_XTA_HTXnTBLRA 0x00000003
-#define HC_XTA_Atex 0x00000004
-#define HC_XTA_Atexnext 0x00000005
-/*--
- */
-#define HC_HTXnTBLAsat_MASK 0x00800000
-#define HC_HTXnTBLAMB_MASK 0x00700000
-#define HC_HTXnTBLAa_MASK 0x0007c000
-#define HC_HTXnTBLAb_MASK 0x00000f80
-#define HC_HTXnTBLAc_MASK 0x0000001f
-#define HC_HTXnTBLAMB_SHIFT 20
-#define HC_HTXnTBLAa_TOPA (HC_XTA_TOPA << 14)
-#define HC_HTXnTBLAa_InvTOPA (HC_XTA_InvTOPA << 14)
-#define HC_HTXnTBLAa_TOPAp5 (HC_XTA_TOPAp5 << 14)
-#define HC_HTXnTBLAa_Adif (HC_XTA_Adif << 14)
-#define HC_HTXnTBLAa_Fog (HC_XTA_Fog << 14)
-#define HC_HTXnTBLAa_Acur (HC_XTA_Acur << 14)
-#define HC_HTXnTBLAa_HTXnTBLRA (HC_XTA_HTXnTBLRA << 14)
-#define HC_HTXnTBLAa_Atex (HC_XTA_Atex << 14)
-#define HC_HTXnTBLAa_Atexnext (HC_XTA_Atexnext << 14)
-#define HC_HTXnTBLAb_TOPA (HC_XTA_TOPA << 7)
-#define HC_HTXnTBLAb_InvTOPA (HC_XTA_InvTOPA << 7)
-#define HC_HTXnTBLAb_TOPAp5 (HC_XTA_TOPAp5 << 7)
-#define HC_HTXnTBLAb_Adif (HC_XTA_Adif << 7)
-#define HC_HTXnTBLAb_Fog (HC_XTA_Fog << 7)
-#define HC_HTXnTBLAb_Acur (HC_XTA_Acur << 7)
-#define HC_HTXnTBLAb_HTXnTBLRA (HC_XTA_HTXnTBLRA << 7)
-#define HC_HTXnTBLAb_Atex (HC_XTA_Atex << 7)
-#define HC_HTXnTBLAb_Atexnext (HC_XTA_Atexnext << 7)
-#define HC_HTXnTBLAc_TOPA (HC_XTA_TOPA << 0)
-#define HC_HTXnTBLAc_InvTOPA (HC_XTA_InvTOPA << 0)
-#define HC_HTXnTBLAc_TOPAp5 (HC_XTA_TOPAp5 << 0)
-#define HC_HTXnTBLAc_Adif (HC_XTA_Adif << 0)
-#define HC_HTXnTBLAc_Fog (HC_XTA_Fog << 0)
-#define HC_HTXnTBLAc_Acur (HC_XTA_Acur << 0)
-#define HC_HTXnTBLAc_HTXnTBLRA (HC_XTA_HTXnTBLRA << 0)
-#define HC_HTXnTBLAc_Atex (HC_XTA_Atex << 0)
-#define HC_HTXnTBLAc_Atexnext (HC_XTA_Atexnext << 0)
-/* HC_SubA_HTXnTBLRAa 0x0089
- */
-#define HC_HTXnTBLRAa_MASK 0x00ff0000
-#define HC_HTXnTBLRAb_MASK 0x0000ff00
-#define HC_HTXnTBLRAc_MASK 0x000000ff
-#define HC_HTXnTBLRAa_SHIFT 16
-#define HC_HTXnTBLRAb_SHIFT 8
-#define HC_HTXnTBLRAc_SHIFT 0
-/* HC_SubA_HTXnTBLRFog 0x008a
- */
-#define HC_HTXnTBLRFog_MASK 0x0000ff00
-#define HC_HTXnTBLRAbias_MASK 0x000000ff
-#define HC_HTXnTBLRFog_SHIFT 8
-#define HC_HTXnTBLRAbias_SHIFT 0
-/* HC_SubA_HTXnLScale 0x0094
- */
-#define HC_HTXnLScale_MASK 0x0007fc00
-#define HC_HTXnLOff_MASK 0x000001ff
-#define HC_HTXnLScale_SHIFT 10
-/* HC_SubA_HTXSMD 0x0000
- */
-#define HC_HTXSMD_MASK 0x00000080
-#define HC_HTXTMD_MASK 0x00000040
-#define HC_HTXNum_MASK 0x00000038
-#define HC_HTXTRMD_MASK 0x00000006
-#define HC_HTXCHCLR_MASK 0x00000001
-#define HC_HTXNum_SHIFT 3
-
-/* Texture Palette n
- */
-#define HC_SubType_TexPalette0 0x00000000
-#define HC_SubType_TexPalette1 0x00000001
-#define HC_SubType_FogTable 0x00000010
-#define HC_SubType_Stipple 0x00000014
-/* HC_SubA_TexPalette0 0x0000
- */
-#define HC_HTPnA_MASK 0xff000000
-#define HC_HTPnR_MASK 0x00ff0000
-#define HC_HTPnG_MASK 0x0000ff00
-#define HC_HTPnB_MASK 0x000000ff
-/* HC_SubA_FogTable 0x0010
- */
-#define HC_HFPn3_MASK 0xff000000
-#define HC_HFPn2_MASK 0x00ff0000
-#define HC_HFPn1_MASK 0x0000ff00
-#define HC_HFPn_MASK 0x000000ff
-#define HC_HFPn3_SHIFT 24
-#define HC_HFPn2_SHIFT 16
-#define HC_HFPn1_SHIFT 8
-
-/* Auto Testing & Security
- */
-#define HC_SubA_HenFIFOAT 0x0000
-#define HC_SubA_HFBDrawFirst 0x0004
-#define HC_SubA_HFBBasL 0x0005
-#define HC_SubA_HFBDst 0x0006
-/* HC_SubA_HenFIFOAT 0x0000
- */
-#define HC_HenFIFOAT_MASK 0x00000020
-#define HC_HenGEMILock_MASK 0x00000010
-#define HC_HenFBASwap_MASK 0x00000008
-#define HC_HenOT_MASK 0x00000004
-#define HC_HenCMDQ_MASK 0x00000002
-#define HC_HenTXCTSU_MASK 0x00000001
-/* HC_SubA_HFBDrawFirst 0x0004
- */
-#define HC_HFBDrawFirst_MASK 0x00000800
-#define HC_HFBQueue_MASK 0x00000400
-#define HC_HFBLock_MASK 0x00000200
-#define HC_HEOF_MASK 0x00000100
-#define HC_HFBBasH_MASK 0x000000ff
-
-/* GEMI Setting
- */
-#define HC_SubA_HTArbRCM 0x0008
-#define HC_SubA_HTArbRZ 0x000a
-#define HC_SubA_HTArbWZ 0x000b
-#define HC_SubA_HTArbRTX 0x000c
-#define HC_SubA_HTArbRCW 0x000d
-#define HC_SubA_HTArbE2 0x000e
-#define HC_SubA_HArbRQCM 0x0010
-#define HC_SubA_HArbWQCM 0x0011
-#define HC_SubA_HGEMITout 0x0020
-#define HC_SubA_HFthRTXD 0x0040
-#define HC_SubA_HFthRTXA 0x0044
-#define HC_SubA_HCMDQstL 0x0050
-#define HC_SubA_HCMDQendL 0x0051
-#define HC_SubA_HCMDQLen 0x0052
-/* HC_SubA_HTArbRCM 0x0008
- */
-#define HC_HTArbRCM_MASK 0x0000ffff
-/* HC_SubA_HTArbRZ 0x000a
- */
-#define HC_HTArbRZ_MASK 0x0000ffff
-/* HC_SubA_HTArbWZ 0x000b
- */
-#define HC_HTArbWZ_MASK 0x0000ffff
-/* HC_SubA_HTArbRTX 0x000c
- */
-#define HC_HTArbRTX_MASK 0x0000ffff
-/* HC_SubA_HTArbRCW 0x000d
- */
-#define HC_HTArbRCW_MASK 0x0000ffff
-/* HC_SubA_HTArbE2 0x000e
- */
-#define HC_HTArbE2_MASK 0x0000ffff
-/* HC_SubA_HArbRQCM 0x0010
- */
-#define HC_HTArbRQCM_MASK 0x0000ffff
-/* HC_SubA_HArbWQCM 0x0011
- */
-#define HC_HArbWQCM_MASK 0x0000ffff
-/* HC_SubA_HGEMITout 0x0020
- */
-#define HC_HGEMITout_MASK 0x000f0000
-#define HC_HNPArbZC_MASK 0x0000ffff
-#define HC_HGEMITout_SHIFT 16
-/* HC_SubA_HFthRTXD 0x0040
- */
-#define HC_HFthRTXD_MASK 0x00ff0000
-#define HC_HFthRZD_MASK 0x0000ff00
-#define HC_HFthWZD_MASK 0x000000ff
-#define HC_HFthRTXD_SHIFT 16
-#define HC_HFthRZD_SHIFT 8
-/* HC_SubA_HFthRTXA 0x0044
- */
-#define HC_HFthRTXA_MASK 0x000000ff
-
-/****************************************************************************
- * Define the Halcyon Internal register access constants. For simulator only.
- ***************************************************************************/
-#define HC_SIMA_HAGPBstL 0x0000
-#define HC_SIMA_HAGPBendL 0x0001
-#define HC_SIMA_HAGPCMNT 0x0002
-#define HC_SIMA_HAGPBpL 0x0003
-#define HC_SIMA_HAGPBpH 0x0004
-#define HC_SIMA_HClipTB 0x0005
-#define HC_SIMA_HClipLR 0x0006
-#define HC_SIMA_HFPClipTL 0x0007
-#define HC_SIMA_HFPClipBL 0x0008
-#define HC_SIMA_HFPClipLL 0x0009
-#define HC_SIMA_HFPClipRL 0x000a
-#define HC_SIMA_HFPClipTBH 0x000b
-#define HC_SIMA_HFPClipLRH 0x000c
-#define HC_SIMA_HLP 0x000d
-#define HC_SIMA_HLPRF 0x000e
-#define HC_SIMA_HSolidCL 0x000f
-#define HC_SIMA_HPixGC 0x0010
-#define HC_SIMA_HSPXYOS 0x0011
-#define HC_SIMA_HCmdA 0x0012
-#define HC_SIMA_HCmdB 0x0013
-#define HC_SIMA_HEnable 0x0014
-#define HC_SIMA_HZWBBasL 0x0015
-#define HC_SIMA_HZWBBasH 0x0016
-#define HC_SIMA_HZWBType 0x0017
-#define HC_SIMA_HZBiasL 0x0018
-#define HC_SIMA_HZWBend 0x0019
-#define HC_SIMA_HZWTMD 0x001a
-#define HC_SIMA_HZWCDL 0x001b
-#define HC_SIMA_HZWCTAGnum 0x001c
-#define HC_SIMA_HZCYNum 0x001d
-#define HC_SIMA_HZWCFire 0x001e
-/* #define HC_SIMA_HSBBasL 0x001d */
-/* #define HC_SIMA_HSBBasH 0x001e */
-/* #define HC_SIMA_HSBFM 0x001f */
-#define HC_SIMA_HSTREF 0x0020
-#define HC_SIMA_HSTMD 0x0021
-#define HC_SIMA_HABBasL 0x0022
-#define HC_SIMA_HABBasH 0x0023
-#define HC_SIMA_HABFM 0x0024
-#define HC_SIMA_HATMD 0x0025
-#define HC_SIMA_HABLCsat 0x0026
-#define HC_SIMA_HABLCop 0x0027
-#define HC_SIMA_HABLAsat 0x0028
-#define HC_SIMA_HABLAop 0x0029
-#define HC_SIMA_HABLRCa 0x002a
-#define HC_SIMA_HABLRFCa 0x002b
-#define HC_SIMA_HABLRCbias 0x002c
-#define HC_SIMA_HABLRCb 0x002d
-#define HC_SIMA_HABLRFCb 0x002e
-#define HC_SIMA_HABLRAa 0x002f
-#define HC_SIMA_HABLRAb 0x0030
-#define HC_SIMA_HDBBasL 0x0031
-#define HC_SIMA_HDBBasH 0x0032
-#define HC_SIMA_HDBFM 0x0033
-#define HC_SIMA_HFBBMSKL 0x0034
-#define HC_SIMA_HROP 0x0035
-#define HC_SIMA_HFogLF 0x0036
-#define HC_SIMA_HFogCL 0x0037
-#define HC_SIMA_HFogCH 0x0038
-#define HC_SIMA_HFogStL 0x0039
-#define HC_SIMA_HFogStH 0x003a
-#define HC_SIMA_HFogOOdMF 0x003b
-#define HC_SIMA_HFogOOdEF 0x003c
-#define HC_SIMA_HFogEndL 0x003d
-#define HC_SIMA_HFogDenst 0x003e
-/*---- start of texture 0 setting ----
- */
-#define HC_SIMA_HTX0L0BasL 0x0040
-#define HC_SIMA_HTX0L1BasL 0x0041
-#define HC_SIMA_HTX0L2BasL 0x0042
-#define HC_SIMA_HTX0L3BasL 0x0043
-#define HC_SIMA_HTX0L4BasL 0x0044
-#define HC_SIMA_HTX0L5BasL 0x0045
-#define HC_SIMA_HTX0L6BasL 0x0046
-#define HC_SIMA_HTX0L7BasL 0x0047
-#define HC_SIMA_HTX0L8BasL 0x0048
-#define HC_SIMA_HTX0L9BasL 0x0049
-#define HC_SIMA_HTX0LaBasL 0x004a
-#define HC_SIMA_HTX0LbBasL 0x004b
-#define HC_SIMA_HTX0LcBasL 0x004c
-#define HC_SIMA_HTX0LdBasL 0x004d
-#define HC_SIMA_HTX0LeBasL 0x004e
-#define HC_SIMA_HTX0LfBasL 0x004f
-#define HC_SIMA_HTX0L10BasL 0x0050
-#define HC_SIMA_HTX0L11BasL 0x0051
-#define HC_SIMA_HTX0L012BasH 0x0052
-#define HC_SIMA_HTX0L345BasH 0x0053
-#define HC_SIMA_HTX0L678BasH 0x0054
-#define HC_SIMA_HTX0L9abBasH 0x0055
-#define HC_SIMA_HTX0LcdeBasH 0x0056
-#define HC_SIMA_HTX0Lf1011BasH 0x0057
-#define HC_SIMA_HTX0L0Pit 0x0058
-#define HC_SIMA_HTX0L1Pit 0x0059
-#define HC_SIMA_HTX0L2Pit 0x005a
-#define HC_SIMA_HTX0L3Pit 0x005b
-#define HC_SIMA_HTX0L4Pit 0x005c
-#define HC_SIMA_HTX0L5Pit 0x005d
-#define HC_SIMA_HTX0L6Pit 0x005e
-#define HC_SIMA_HTX0L7Pit 0x005f
-#define HC_SIMA_HTX0L8Pit 0x0060
-#define HC_SIMA_HTX0L9Pit 0x0061
-#define HC_SIMA_HTX0LaPit 0x0062
-#define HC_SIMA_HTX0LbPit 0x0063
-#define HC_SIMA_HTX0LcPit 0x0064
-#define HC_SIMA_HTX0LdPit 0x0065
-#define HC_SIMA_HTX0LePit 0x0066
-#define HC_SIMA_HTX0LfPit 0x0067
-#define HC_SIMA_HTX0L10Pit 0x0068
-#define HC_SIMA_HTX0L11Pit 0x0069
-#define HC_SIMA_HTX0L0_5WE 0x006a
-#define HC_SIMA_HTX0L6_bWE 0x006b
-#define HC_SIMA_HTX0Lc_11WE 0x006c
-#define HC_SIMA_HTX0L0_5HE 0x006d
-#define HC_SIMA_HTX0L6_bHE 0x006e
-#define HC_SIMA_HTX0Lc_11HE 0x006f
-#define HC_SIMA_HTX0L0OS 0x0070
-#define HC_SIMA_HTX0TB 0x0071
-#define HC_SIMA_HTX0MPMD 0x0072
-#define HC_SIMA_HTX0CLODu 0x0073
-#define HC_SIMA_HTX0FM 0x0074
-#define HC_SIMA_HTX0TRCH 0x0075
-#define HC_SIMA_HTX0TRCL 0x0076
-#define HC_SIMA_HTX0TBC 0x0077
-#define HC_SIMA_HTX0TRAH 0x0078
-#define HC_SIMA_HTX0TBLCsat 0x0079
-#define HC_SIMA_HTX0TBLCop 0x007a
-#define HC_SIMA_HTX0TBLMPfog 0x007b
-#define HC_SIMA_HTX0TBLAsat 0x007c
-#define HC_SIMA_HTX0TBLRCa 0x007d
-#define HC_SIMA_HTX0TBLRCb 0x007e
-#define HC_SIMA_HTX0TBLRCc 0x007f
-#define HC_SIMA_HTX0TBLRCbias 0x0080
-#define HC_SIMA_HTX0TBLRAa 0x0081
-#define HC_SIMA_HTX0TBLRFog 0x0082
-#define HC_SIMA_HTX0BumpM00 0x0083
-#define HC_SIMA_HTX0BumpM01 0x0084
-#define HC_SIMA_HTX0BumpM10 0x0085
-#define HC_SIMA_HTX0BumpM11 0x0086
-#define HC_SIMA_HTX0LScale 0x0087
-/*---- end of texture 0 setting ---- 0x008f
- */
-#define HC_SIMA_TX0TX1_OFF 0x0050
-/*---- start of texture 1 setting ----
- */
-#define HC_SIMA_HTX1L0BasL (HC_SIMA_HTX0L0BasL + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1L1BasL (HC_SIMA_HTX0L1BasL + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1L2BasL (HC_SIMA_HTX0L2BasL + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1L3BasL (HC_SIMA_HTX0L3BasL + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1L4BasL (HC_SIMA_HTX0L4BasL + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1L5BasL (HC_SIMA_HTX0L5BasL + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1L6BasL (HC_SIMA_HTX0L6BasL + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1L7BasL (HC_SIMA_HTX0L7BasL + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1L8BasL (HC_SIMA_HTX0L8BasL + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1L9BasL (HC_SIMA_HTX0L9BasL + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1LaBasL (HC_SIMA_HTX0LaBasL + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1LbBasL (HC_SIMA_HTX0LbBasL + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1LcBasL (HC_SIMA_HTX0LcBasL + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1LdBasL (HC_SIMA_HTX0LdBasL + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1LeBasL (HC_SIMA_HTX0LeBasL + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1LfBasL (HC_SIMA_HTX0LfBasL + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1L10BasL (HC_SIMA_HTX0L10BasL + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1L11BasL (HC_SIMA_HTX0L11BasL + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1L012BasH (HC_SIMA_HTX0L012BasH + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1L345BasH (HC_SIMA_HTX0L345BasH + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1L678BasH (HC_SIMA_HTX0L678BasH + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1L9abBasH (HC_SIMA_HTX0L9abBasH + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1LcdeBasH (HC_SIMA_HTX0LcdeBasH + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1Lf1011BasH (HC_SIMA_HTX0Lf1011BasH + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1L0Pit (HC_SIMA_HTX0L0Pit + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1L1Pit (HC_SIMA_HTX0L1Pit + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1L2Pit (HC_SIMA_HTX0L2Pit + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1L3Pit (HC_SIMA_HTX0L3Pit + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1L4Pit (HC_SIMA_HTX0L4Pit + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1L5Pit (HC_SIMA_HTX0L5Pit + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1L6Pit (HC_SIMA_HTX0L6Pit + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1L7Pit (HC_SIMA_HTX0L7Pit + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1L8Pit (HC_SIMA_HTX0L8Pit + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1L9Pit (HC_SIMA_HTX0L9Pit + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1LaPit (HC_SIMA_HTX0LaPit + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1LbPit (HC_SIMA_HTX0LbPit + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1LcPit (HC_SIMA_HTX0LcPit + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1LdPit (HC_SIMA_HTX0LdPit + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1LePit (HC_SIMA_HTX0LePit + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1LfPit (HC_SIMA_HTX0LfPit + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1L10Pit (HC_SIMA_HTX0L10Pit + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1L11Pit (HC_SIMA_HTX0L11Pit + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1L0_5WE (HC_SIMA_HTX0L0_5WE + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1L6_bWE (HC_SIMA_HTX0L6_bWE + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1Lc_11WE (HC_SIMA_HTX0Lc_11WE + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1L0_5HE (HC_SIMA_HTX0L0_5HE + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1L6_bHE (HC_SIMA_HTX0L6_bHE + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1Lc_11HE (HC_SIMA_HTX0Lc_11HE + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1L0OS (HC_SIMA_HTX0L0OS + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1TB (HC_SIMA_HTX0TB + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1MPMD (HC_SIMA_HTX0MPMD + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1CLODu (HC_SIMA_HTX0CLODu + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1FM (HC_SIMA_HTX0FM + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1TRCH (HC_SIMA_HTX0TRCH + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1TRCL (HC_SIMA_HTX0TRCL + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1TBC (HC_SIMA_HTX0TBC + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1TRAH (HC_SIMA_HTX0TRAH + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1LTC (HC_SIMA_HTX0LTC + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1LTA (HC_SIMA_HTX0LTA + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1TBLCsat (HC_SIMA_HTX0TBLCsat + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1TBLCop (HC_SIMA_HTX0TBLCop + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1TBLMPfog (HC_SIMA_HTX0TBLMPfog + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1TBLAsat (HC_SIMA_HTX0TBLAsat + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1TBLRCa (HC_SIMA_HTX0TBLRCa + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1TBLRCb (HC_SIMA_HTX0TBLRCb + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1TBLRCc (HC_SIMA_HTX0TBLRCc + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1TBLRCbias (HC_SIMA_HTX0TBLRCbias + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1TBLRAa (HC_SIMA_HTX0TBLRAa + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1TBLRFog (HC_SIMA_HTX0TBLRFog + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1BumpM00 (HC_SIMA_HTX0BumpM00 + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1BumpM01 (HC_SIMA_HTX0BumpM01 + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1BumpM10 (HC_SIMA_HTX0BumpM10 + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1BumpM11 (HC_SIMA_HTX0BumpM11 + HC_SIMA_TX0TX1_OFF)
-#define HC_SIMA_HTX1LScale (HC_SIMA_HTX0LScale + HC_SIMA_TX0TX1_OFF)
-/*---- end of texture 1 setting ---- 0xaf
- */
-#define HC_SIMA_HTXSMD 0x00b0
-#define HC_SIMA_HenFIFOAT 0x00b1
-#define HC_SIMA_HFBDrawFirst 0x00b2
-#define HC_SIMA_HFBBasL 0x00b3
-#define HC_SIMA_HTArbRCM 0x00b4
-#define HC_SIMA_HTArbRZ 0x00b5
-#define HC_SIMA_HTArbWZ 0x00b6
-#define HC_SIMA_HTArbRTX 0x00b7
-#define HC_SIMA_HTArbRCW 0x00b8
-#define HC_SIMA_HTArbE2 0x00b9
-#define HC_SIMA_HGEMITout 0x00ba
-#define HC_SIMA_HFthRTXD 0x00bb
-#define HC_SIMA_HFthRTXA 0x00bc
-/* Define the texture palette 0
- */
-#define HC_SIMA_HTP0 0x0100
-#define HC_SIMA_HTP1 0x0200
-#define HC_SIMA_FOGTABLE 0x0300
-#define HC_SIMA_STIPPLE 0x0400
-#define HC_SIMA_HE3Fire 0x0440
-#define HC_SIMA_TRANS_SET 0x0441
-#define HC_SIMA_HREngSt 0x0442
-#define HC_SIMA_HRFIFOempty 0x0443
-#define HC_SIMA_HRFIFOfull 0x0444
-#define HC_SIMA_HRErr 0x0445
-#define HC_SIMA_FIFOstatus 0x0446
-
-/****************************************************************************
- * Define the AGP command header.
- ***************************************************************************/
-#define HC_ACMD_MASK 0xfe000000
-#define HC_ACMD_SUB_MASK 0x0c000000
-#define HC_ACMD_HCmdA 0xee000000
-#define HC_ACMD_HCmdB 0xec000000
-#define HC_ACMD_HCmdC 0xea000000
-#define HC_ACMD_H1 0xf0000000
-#define HC_ACMD_H2 0xf2000000
-#define HC_ACMD_H3 0xf4000000
-#define HC_ACMD_H4 0xf6000000
-
-#define HC_ACMD_H1IO_MASK 0x000001ff
-#define HC_ACMD_H2IO1_MASK 0x001ff000
-#define HC_ACMD_H2IO2_MASK 0x000001ff
-#define HC_ACMD_H2IO1_SHIFT 12
-#define HC_ACMD_H2IO2_SHIFT 0
-#define HC_ACMD_H3IO_MASK 0x000001ff
-#define HC_ACMD_H3COUNT_MASK 0x01fff000
-#define HC_ACMD_H3COUNT_SHIFT 12
-#define HC_ACMD_H4ID_MASK 0x000001ff
-#define HC_ACMD_H4COUNT_MASK 0x01fffe00
-#define HC_ACMD_H4COUNT_SHIFT 9
-
-/*****************************************************************************
- * Define Header
- ****************************************************************************/
-#define HC_HEADER2 0xF210F110
-
-/*****************************************************************************
- * Define Dummy Value
- ****************************************************************************/
-#define HC_DUMMY 0xCCCCCCCC
-/*****************************************************************************
- * Define for DMA use
- ****************************************************************************/
-#define HALCYON_HEADER2 0XF210F110
-#define HALCYON_FIRECMD 0XEE100000
-#define HALCYON_FIREMASK 0XFFF00000
-#define HALCYON_CMDB 0XEC000000
-#define HALCYON_CMDBMASK 0XFFFE0000
-#define HALCYON_SUB_ADDR0 0X00000000
-#define HALCYON_HEADER1MASK 0XFFFFFC00
-#define HALCYON_HEADER1 0XF0000000
-#define HC_SubA_HAGPBstL 0x0060
-#define HC_SubA_HAGPBendL 0x0061
-#define HC_SubA_HAGPCMNT 0x0062
-#define HC_SubA_HAGPBpL 0x0063
-#define HC_SubA_HAGPBpH 0x0064
-#define HC_HAGPCMNT_MASK 0x00800000
-#define HC_HCmdErrClr_MASK 0x00400000
-#define HC_HAGPBendH_MASK 0x0000ff00
-#define HC_HAGPBstH_MASK 0x000000ff
-#define HC_HAGPBendH_SHIFT 8
-#define HC_HAGPBstH_SHIFT 0
-#define HC_HAGPBpL_MASK 0x00fffffc
-#define HC_HAGPBpID_MASK 0x00000003
-#define HC_HAGPBpID_PAUSE 0x00000000
-#define HC_HAGPBpID_JUMP 0x00000001
-#define HC_HAGPBpID_STOP 0x00000002
-#define HC_HAGPBpH_MASK 0x00ffffff
-
-
-#define VIA_VIDEO_HEADER5 0xFE040000
-#define VIA_VIDEO_HEADER6 0xFE050000
-#define VIA_VIDEO_HEADER7 0xFE060000
-#define VIA_VIDEOMASK 0xFFFF0000
-
-/*****************************************************************************
- * Define for H5 DMA use
- ****************************************************************************/
-#define H5_HC_DUMMY 0xCC000000
-
-/* Command Header Type */
-#define INV_DUMMY_MASK 0xFF000000
-#define INV_AGPHeader0 0xFE000000
-#define INV_AGPHeader1 0xFE010000
-#define INV_AGPHeader2 0xFE020000
-#define INV_AGPHeader3 0xFE030000
-#define INV_AGPHeader4 0xFE040000
-#define INV_AGPHeader5 0xFE050000
-#define INV_AGPHeader6 0xFE060000
-#define INV_AGPHeader7 0xFE070000
-#define INV_AGPHeader9 0xFE090000
-#define INV_AGPHeaderA 0xFE0A0000
-#define INV_AGPHeader40 0xFE400000
-#define INV_AGPHeader41 0xFE410000
-#define INV_AGPHeader43 0xFE430000
-#define INV_AGPHeader45 0xFE450000
-#define INV_AGPHeader47 0xFE470000
-#define INV_AGPHeader4A 0xFE4A0000
-#define INV_AGPHeader82 0xFE820000
-#define INV_AGPHeader83 0xFE830000
-#define INV_AGPHeader_MASK 0xFFFF0000
-#define INV_AGPHeader2A 0xFE2A0000
-#define INV_AGPHeader25 0xFE250000
-#define INV_AGPHeader20 0xFE200000
-#define INV_AGPHeader23 0xFE230000
-#define INV_AGPHeaderE2 0xFEE20000
-#define INV_AGPHeaderE3 0xFEE30000
-
-/*Transmission IO Space*/
-#define INV_REG_CR_TRANS 0x041C
-#define INV_REG_CR_BEGIN 0x0420
-#define INV_REG_CR_END 0x0438
-
-#define INV_REG_3D_TRANS 0x043C
-#define INV_REG_3D_BEGIN 0x0440
-#define INV_REG_3D_END 0x06FC
-
-#define INV_ParaType_CmdVdata 0x0000
-
-/* H5 Enable Setting
- */
-#define INV_HC_SubA_HEnable1 0x00
-
-#define INV_HC_HenAT4ALLRT_MASK 0x00100000
-#define INV_HC_HenATMRT3_MASK 0x00080000
-#define INV_HC_HenATMRT2_MASK 0x00040000
-#define INV_HC_HenATMRT1_MASK 0x00020000
-#define INV_HC_HenATMRT0_MASK 0x00010000
-#define INV_HC_HenSCMRT3_MASK 0x00008000
-#define INV_HC_HenSCMRT2_MASK 0x00004000
-#define INV_HC_HenSCMRT1_MASK 0x00002000
-#define INV_HC_HenSCMRT0_MASK 0x00001000
-#define INV_HC_HenFOGMRT3_MASK 0x00000800
-#define INV_HC_HenFOGMRT2_MASK 0x00000400
-#define INV_HC_HenFOGMRT1_MASK 0x00000200
-#define INV_HC_HenFOGMRT0_MASK 0x00000100
-#define INV_HC_HenABLMRT3_MASK 0x00000080
-#define INV_HC_HenABLMRT2_MASK 0x00000040
-#define INV_HC_HenABLMRT1_MASK 0x00000020
-#define INV_HC_HenABLMRT0_MASK 0x00000010
-#define INV_HC_HenDTMRT3_MASK 0x00000008
-#define INV_HC_HenDTMRT2_MASK 0x00000004
-#define INV_HC_HenDTMRT1_MASK 0x00000002
-#define INV_HC_HenDTMRT0_MASK 0x00000001
-
-#define INV_HC_SubA_HEnable2 0x01
-
-#define INV_HC_HenLUL2DR_MASK 0x00800000
-#define INV_HC_HenLDIAMOND_MASK 0x00400000
-#define INV_HC_HenPSPRITE_MASK 0x00200000
-#define INV_HC_HenC2S_MASK 0x00100000
-#define INV_HC_HenFOGPP_MASK 0x00080000
-#define INV_HC_HenSCPP_MASK 0x00040000
-#define INV_HC_HenCPP_MASK 0x00020000
-#define INV_HC_HenCZ_MASK 0x00002000
-#define INV_HC_HenVC_MASK 0x00001000
-#define INV_HC_HenCL_MASK 0x00000800
-#define INV_HC_HenPS_MASK 0x00000400
-#define INV_HC_HenWCZ_MASK 0x00000200
-#define INV_HC_HenTXCH_MASK 0x00000100
-#define INV_HC_HenBFCULL_MASK 0x00000080
-#define INV_HC_HenCW_MASK 0x00000040
-#define INV_HC_HenAA_MASK 0x00000020
-#define INV_HC_HenST_MASK 0x00000010
-#define INV_HC_HenZT_MASK 0x00000008
-#define INV_HC_HenZW_MASK 0x00000004
-#define INV_HC_HenSP_MASK 0x00000002
-#define INV_HC_HenLP_MASK 0x00000001
-
-/* H5 Miscellaneous Settings
- */
-#define INV_HC_SubA_HCClipTL 0x0080
-#define INV_HC_SubA_HCClipBL 0x0081
-#define INV_HC_SubA_HSClipTL 0x0082
-#define INV_HC_SubA_HSClipBL 0x0083
-#define INV_HC_SubA_HSolidCL 0x0086
-#define INV_HC_SubA_HSolidCH 0x0087
-#define INV_HC_SubA_HGBClipGL 0x0088
-#define INV_HC_SubA_HGBClipGR 0x0089
-
-
-#define INV_HC_ParaType_Vetex 0x00040000
-
-#endif
diff --git a/drivers/gpu/drm/via/via_dri1.c b/drivers/gpu/drm/via/via_dri1.c
deleted file mode 100644
index 217d1e84b0ea..000000000000
--- a/drivers/gpu/drm/via/via_dri1.c
+++ /dev/null
@@ -1,3630 +0,0 @@
-/*
- * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
- * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
- * Copyright 2002 Tungsten Graphics, Inc.
- * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. All Rights Reserved.
- * Copyright 2006 Tungsten Graphics Inc., Bismarck, ND., USA.
- * Copyright 2004 Digeo, Inc., Palo Alto, CA, U.S.A. All Rights Reserved.
- * Copyright 2004 The Unichrome project. All Rights Reserved.
- * Copyright 2004 BEAM Ltd.
- * Copyright 2005 Thomas Hellstrom. All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software 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, sub license,
- * 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 (including the
- * next paragraph) 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 NON-INFRINGEMENT. IN NO EVENT SHALL
- * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS 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.
- */
-
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/vmalloc.h>
-
-#include <drm/drm_drv.h>
-#include <drm/drm_file.h>
-#include <drm/drm_ioctl.h>
-#include <drm/drm_legacy.h>
-#include <drm/drm_mm.h>
-#include <drm/drm_pciids.h>
-#include <drm/drm_print.h>
-#include <drm/drm_vblank.h>
-#include <drm/via_drm.h>
-
-#include "via_3d_reg.h"
-
-#define DRIVER_AUTHOR "Various"
-
-#define DRIVER_NAME "via"
-#define DRIVER_DESC "VIA Unichrome / Pro"
-#define DRIVER_DATE "20070202"
-
-#define DRIVER_MAJOR 2
-#define DRIVER_MINOR 11
-#define DRIVER_PATCHLEVEL 1
-
-typedef enum {
- no_sequence = 0,
- z_address,
- dest_address,
- tex_address
-} drm_via_sequence_t;
-
-typedef struct {
- unsigned texture;
- uint32_t z_addr;
- uint32_t d_addr;
- uint32_t t_addr[2][10];
- uint32_t pitch[2][10];
- uint32_t height[2][10];
- uint32_t tex_level_lo[2];
- uint32_t tex_level_hi[2];
- uint32_t tex_palette_size[2];
- uint32_t tex_npot[2];
- drm_via_sequence_t unfinished;
- int agp_texture;
- int multitex;
- struct drm_device *dev;
- drm_local_map_t *map_cache;
- uint32_t vertex_count;
- int agp;
- const uint32_t *buf_start;
-} drm_via_state_t;
-
-#define VIA_PCI_BUF_SIZE 60000
-#define VIA_FIRE_BUF_SIZE 1024
-#define VIA_NUM_IRQS 4
-
-
-#define VIA_NUM_BLIT_ENGINES 2
-#define VIA_NUM_BLIT_SLOTS 8
-
-struct _drm_via_descriptor;
-
-typedef struct _drm_via_sg_info {
- struct page **pages;
- unsigned long num_pages;
- struct _drm_via_descriptor **desc_pages;
- int num_desc_pages;
- int num_desc;
- enum dma_data_direction direction;
- unsigned char *bounce_buffer;
- dma_addr_t chain_start;
- uint32_t free_on_sequence;
- unsigned int descriptors_per_page;
- int aborted;
- enum {
- dr_via_device_mapped,
- dr_via_desc_pages_alloc,
- dr_via_pages_locked,
- dr_via_pages_alloc,
- dr_via_sg_init
- } state;
-} drm_via_sg_info_t;
-
-typedef struct _drm_via_blitq {
- struct drm_device *dev;
- uint32_t cur_blit_handle;
- uint32_t done_blit_handle;
- unsigned serviced;
- unsigned head;
- unsigned cur;
- unsigned num_free;
- unsigned num_outstanding;
- unsigned long end;
- int aborting;
- int is_active;
- drm_via_sg_info_t *blits[VIA_NUM_BLIT_SLOTS];
- spinlock_t blit_lock;
- wait_queue_head_t blit_queue[VIA_NUM_BLIT_SLOTS];
- wait_queue_head_t busy_queue;
- struct work_struct wq;
- struct timer_list poll_timer;
-} drm_via_blitq_t;
-
-typedef struct drm_via_ring_buffer {
- drm_local_map_t map;
- char *virtual_start;
-} drm_via_ring_buffer_t;
-
-typedef uint32_t maskarray_t[5];
-
-typedef struct drm_via_irq {
- atomic_t irq_received;
- uint32_t pending_mask;
- uint32_t enable_mask;
- wait_queue_head_t irq_queue;
-} drm_via_irq_t;
-
-typedef struct drm_via_private {
- drm_via_sarea_t *sarea_priv;
- drm_local_map_t *sarea;
- drm_local_map_t *fb;
- drm_local_map_t *mmio;
- unsigned long agpAddr;
- wait_queue_head_t decoder_queue[VIA_NR_XVMC_LOCKS];
- char *dma_ptr;
- unsigned int dma_low;
- unsigned int dma_high;
- unsigned int dma_offset;
- uint32_t dma_wrap;
- volatile uint32_t *last_pause_ptr;
- volatile uint32_t *hw_addr_ptr;
- drm_via_ring_buffer_t ring;
- ktime_t last_vblank;
- int last_vblank_valid;
- ktime_t nsec_per_vblank;
- atomic_t vbl_received;
- drm_via_state_t hc_state;
- char pci_buf[VIA_PCI_BUF_SIZE];
- const uint32_t *fire_offsets[VIA_FIRE_BUF_SIZE];
- uint32_t num_fire_offsets;
- int chipset;
- drm_via_irq_t via_irqs[VIA_NUM_IRQS];
- unsigned num_irqs;
- maskarray_t *irq_masks;
- uint32_t irq_enable_mask;
- uint32_t irq_pending_mask;
- int *irq_map;
- unsigned int idle_fault;
- int vram_initialized;
- struct drm_mm vram_mm;
- int agp_initialized;
- struct drm_mm agp_mm;
- /** Mapping of userspace keys to mm objects */
- struct idr object_idr;
- unsigned long vram_offset;
- unsigned long agp_offset;
- drm_via_blitq_t blit_queues[VIA_NUM_BLIT_ENGINES];
- uint32_t dma_diff;
-} drm_via_private_t;
-
-struct via_file_private {
- struct list_head obj_list;
-};
-
-enum via_family {
- VIA_OTHER = 0, /* Baseline */
- VIA_PRO_GROUP_A, /* Another video engine and DMA commands */
- VIA_DX9_0 /* Same video as pro_group_a, but 3D is unsupported */
-};
-
-/* VIA MMIO register access */
-static inline u32 via_read(struct drm_via_private *dev_priv, u32 reg)
-{
- return readl((void __iomem *)(dev_priv->mmio->handle + reg));
-}
-
-static inline void via_write(struct drm_via_private *dev_priv, u32 reg,
- u32 val)
-{
- writel(val, (void __iomem *)(dev_priv->mmio->handle + reg));
-}
-
-static inline void via_write8(struct drm_via_private *dev_priv, u32 reg,
- u32 val)
-{
- writeb(val, (void __iomem *)(dev_priv->mmio->handle + reg));
-}
-
-static inline void via_write8_mask(struct drm_via_private *dev_priv,
- u32 reg, u32 mask, u32 val)
-{
- u32 tmp;
-
- tmp = readb((void __iomem *)(dev_priv->mmio->handle + reg));
- tmp = (tmp & ~mask) | (val & mask);
- writeb(tmp, (void __iomem *)(dev_priv->mmio->handle + reg));
-}
-
-/*
- * Poll in a loop waiting for 'contidition' to be true.
- * Note: A direct replacement with wait_event_interruptible_timeout()
- * will not work unless driver is updated to emit wake_up()
- * in relevant places that can impact the 'condition'
- *
- * Returns:
- * ret keeps current value if 'condition' becomes true
- * ret = -BUSY if timeout happens
- * ret = -EINTR if a signal interrupted the waiting period
- */
-#define VIA_WAIT_ON( ret, queue, timeout, condition ) \
-do { \
- DECLARE_WAITQUEUE(entry, current); \
- unsigned long end = jiffies + (timeout); \
- add_wait_queue(&(queue), &entry); \
- \
- for (;;) { \
- __set_current_state(TASK_INTERRUPTIBLE); \
- if (condition) \
- break; \
- if (time_after_eq(jiffies, end)) { \
- ret = -EBUSY; \
- break; \
- } \
- schedule_timeout((HZ/100 > 1) ? HZ/100 : 1); \
- if (signal_pending(current)) { \
- ret = -EINTR; \
- break; \
- } \
- } \
- __set_current_state(TASK_RUNNING); \
- remove_wait_queue(&(queue), &entry); \
-} while (0)
-
-int via_do_cleanup_map(struct drm_device *dev);
-
-int via_dma_cleanup(struct drm_device *dev);
-int via_driver_dma_quiescent(struct drm_device *dev);
-
-#define CMDBUF_ALIGNMENT_SIZE (0x100)
-#define CMDBUF_ALIGNMENT_MASK (0x0ff)
-
-/* defines for VIA 3D registers */
-#define VIA_REG_STATUS 0x400
-#define VIA_REG_TRANSET 0x43C
-#define VIA_REG_TRANSPACE 0x440
-
-/* VIA_REG_STATUS(0x400): Engine Status */
-#define VIA_CMD_RGTR_BUSY 0x00000080 /* Command Regulator is busy */
-#define VIA_2D_ENG_BUSY 0x00000001 /* 2D Engine is busy */
-#define VIA_3D_ENG_BUSY 0x00000002 /* 3D Engine is busy */
-#define VIA_VR_QUEUE_BUSY 0x00020000 /* Virtual Queue is busy */
-
-#define SetReg2DAGP(nReg, nData) { \
- *((uint32_t *)(vb)) = ((nReg) >> 2) | HALCYON_HEADER1; \
- *((uint32_t *)(vb) + 1) = (nData); \
- vb = ((uint32_t *)vb) + 2; \
- dev_priv->dma_low += 8; \
-}
-
-#define via_flush_write_combine() mb()
-
-#define VIA_OUT_RING_QW(w1, w2) do { \
- *vb++ = (w1); \
- *vb++ = (w2); \
- dev_priv->dma_low += 8; \
-} while (0)
-
-#define VIA_MM_ALIGN_SHIFT 4
-#define VIA_MM_ALIGN_MASK ((1 << VIA_MM_ALIGN_SHIFT) - 1)
-
-struct via_memblock {
- struct drm_mm_node mm_node;
- struct list_head owner_list;
-};
-
-#define VIA_REG_INTERRUPT 0x200
-
-/* VIA_REG_INTERRUPT */
-#define VIA_IRQ_GLOBAL (1 << 31)
-#define VIA_IRQ_VBLANK_ENABLE (1 << 19)
-#define VIA_IRQ_VBLANK_PENDING (1 << 3)
-#define VIA_IRQ_HQV0_ENABLE (1 << 11)
-#define VIA_IRQ_HQV1_ENABLE (1 << 25)
-#define VIA_IRQ_HQV0_PENDING (1 << 9)
-#define VIA_IRQ_HQV1_PENDING (1 << 10)
-#define VIA_IRQ_DMA0_DD_ENABLE (1 << 20)
-#define VIA_IRQ_DMA0_TD_ENABLE (1 << 21)
-#define VIA_IRQ_DMA1_DD_ENABLE (1 << 22)
-#define VIA_IRQ_DMA1_TD_ENABLE (1 << 23)
-#define VIA_IRQ_DMA0_DD_PENDING (1 << 4)
-#define VIA_IRQ_DMA0_TD_PENDING (1 << 5)
-#define VIA_IRQ_DMA1_DD_PENDING (1 << 6)
-#define VIA_IRQ_DMA1_TD_PENDING (1 << 7)
-
-/*
- * PCI DMA Registers
- * Channels 2 & 3 don't seem to be implemented in hardware.
- */
-
-#define VIA_PCI_DMA_MAR0 0xE40 /* Memory Address Register of Channel 0 */
-#define VIA_PCI_DMA_DAR0 0xE44 /* Device Address Register of Channel 0 */
-#define VIA_PCI_DMA_BCR0 0xE48 /* Byte Count Register of Channel 0 */
-#define VIA_PCI_DMA_DPR0 0xE4C /* Descriptor Pointer Register of Channel 0 */
-
-#define VIA_PCI_DMA_MAR1 0xE50 /* Memory Address Register of Channel 1 */
-#define VIA_PCI_DMA_DAR1 0xE54 /* Device Address Register of Channel 1 */
-#define VIA_PCI_DMA_BCR1 0xE58 /* Byte Count Register of Channel 1 */
-#define VIA_PCI_DMA_DPR1 0xE5C /* Descriptor Pointer Register of Channel 1 */
-
-#define VIA_PCI_DMA_MAR2 0xE60 /* Memory Address Register of Channel 2 */
-#define VIA_PCI_DMA_DAR2 0xE64 /* Device Address Register of Channel 2 */
-#define VIA_PCI_DMA_BCR2 0xE68 /* Byte Count Register of Channel 2 */
-#define VIA_PCI_DMA_DPR2 0xE6C /* Descriptor Pointer Register of Channel 2 */
-
-#define VIA_PCI_DMA_MAR3 0xE70 /* Memory Address Register of Channel 3 */
-#define VIA_PCI_DMA_DAR3 0xE74 /* Device Address Register of Channel 3 */
-#define VIA_PCI_DMA_BCR3 0xE78 /* Byte Count Register of Channel 3 */
-#define VIA_PCI_DMA_DPR3 0xE7C /* Descriptor Pointer Register of Channel 3 */
-
-#define VIA_PCI_DMA_MR0 0xE80 /* Mode Register of Channel 0 */
-#define VIA_PCI_DMA_MR1 0xE84 /* Mode Register of Channel 1 */
-#define VIA_PCI_DMA_MR2 0xE88 /* Mode Register of Channel 2 */
-#define VIA_PCI_DMA_MR3 0xE8C /* Mode Register of Channel 3 */
-
-#define VIA_PCI_DMA_CSR0 0xE90 /* Command/Status Register of Channel 0 */
-#define VIA_PCI_DMA_CSR1 0xE94 /* Command/Status Register of Channel 1 */
-#define VIA_PCI_DMA_CSR2 0xE98 /* Command/Status Register of Channel 2 */
-#define VIA_PCI_DMA_CSR3 0xE9C /* Command/Status Register of Channel 3 */
-
-#define VIA_PCI_DMA_PTR 0xEA0 /* Priority Type Register */
-
-/* Define for DMA engine */
-/* DPR */
-#define VIA_DMA_DPR_EC (1<<1) /* end of chain */
-#define VIA_DMA_DPR_DDIE (1<<2) /* descriptor done interrupt enable */
-#define VIA_DMA_DPR_DT (1<<3) /* direction of transfer (RO) */
-
-/* MR */
-#define VIA_DMA_MR_CM (1<<0) /* chaining mode */
-#define VIA_DMA_MR_TDIE (1<<1) /* transfer done interrupt enable */
-#define VIA_DMA_MR_HENDMACMD (1<<7) /* ? */
-
-/* CSR */
-#define VIA_DMA_CSR_DE (1<<0) /* DMA enable */
-#define VIA_DMA_CSR_TS (1<<1) /* transfer start */
-#define VIA_DMA_CSR_TA (1<<2) /* transfer abort */
-#define VIA_DMA_CSR_TD (1<<3) /* transfer done */
-#define VIA_DMA_CSR_DD (1<<4) /* descriptor done */
-#define VIA_DMA_DPR_EC (1<<1) /* end of chain */
-
-/*
- * Device-specific IRQs go here. This type might need to be extended with
- * the register if there are multiple IRQ control registers.
- * Currently we activate the HQV interrupts of Unichrome Pro group A.
- */
-
-static maskarray_t via_pro_group_a_irqs[] = {
- {VIA_IRQ_HQV0_ENABLE, VIA_IRQ_HQV0_PENDING, 0x000003D0, 0x00008010,
- 0x00000000 },
- {VIA_IRQ_HQV1_ENABLE, VIA_IRQ_HQV1_PENDING, 0x000013D0, 0x00008010,
- 0x00000000 },
- {VIA_IRQ_DMA0_TD_ENABLE, VIA_IRQ_DMA0_TD_PENDING, VIA_PCI_DMA_CSR0,
- VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008},
- {VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1,
- VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008},
-};
-static int via_num_pro_group_a = ARRAY_SIZE(via_pro_group_a_irqs);
-static int via_irqmap_pro_group_a[] = {0, 1, -1, 2, -1, 3};
-
-static maskarray_t via_unichrome_irqs[] = {
- {VIA_IRQ_DMA0_TD_ENABLE, VIA_IRQ_DMA0_TD_PENDING, VIA_PCI_DMA_CSR0,
- VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008},
- {VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1,
- VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008}
-};
-static int via_num_unichrome = ARRAY_SIZE(via_unichrome_irqs);
-static int via_irqmap_unichrome[] = {-1, -1, -1, 0, -1, 1};
-
-
-/*
- * Unmaps the DMA mappings.
- * FIXME: Is this a NoOp on x86? Also
- * FIXME: What happens if this one is called and a pending blit has previously done
- * the same DMA mappings?
- */
-#define VIA_PGDN(x) (((unsigned long)(x)) & PAGE_MASK)
-#define VIA_PGOFF(x) (((unsigned long)(x)) & ~PAGE_MASK)
-#define VIA_PFN(x) ((unsigned long)(x) >> PAGE_SHIFT)
-
-typedef struct _drm_via_descriptor {
- uint32_t mem_addr;
- uint32_t dev_addr;
- uint32_t size;
- uint32_t next;
-} drm_via_descriptor_t;
-
-typedef enum {
- state_command,
- state_header2,
- state_header1,
- state_vheader5,
- state_vheader6,
- state_error
-} verifier_state_t;
-
-typedef enum {
- no_check = 0,
- check_for_header2,
- check_for_header1,
- check_for_header2_err,
- check_for_header1_err,
- check_for_fire,
- check_z_buffer_addr0,
- check_z_buffer_addr1,
- check_z_buffer_addr_mode,
- check_destination_addr0,
- check_destination_addr1,
- check_destination_addr_mode,
- check_for_dummy,
- check_for_dd,
- check_texture_addr0,
- check_texture_addr1,
- check_texture_addr2,
- check_texture_addr3,
- check_texture_addr4,
- check_texture_addr5,
- check_texture_addr6,
- check_texture_addr7,
- check_texture_addr8,
- check_texture_addr_mode,
- check_for_vertex_count,
- check_number_texunits,
- forbidden_command
-} hazard_t;
-
-/*
- * Associates each hazard above with a possible multi-command
- * sequence. For example an address that is split over multiple
- * commands and that needs to be checked at the first command
- * that does not include any part of the address.
- */
-
-static drm_via_sequence_t seqs[] = {
- no_sequence,
- no_sequence,
- no_sequence,
- no_sequence,
- no_sequence,
- no_sequence,
- z_address,
- z_address,
- z_address,
- dest_address,
- dest_address,
- dest_address,
- no_sequence,
- no_sequence,
- tex_address,
- tex_address,
- tex_address,
- tex_address,
- tex_address,
- tex_address,
- tex_address,
- tex_address,
- tex_address,
- tex_address,
- no_sequence
-};
-
-typedef struct {
- unsigned int code;
- hazard_t hz;
-} hz_init_t;
-
-static hz_init_t init_table1[] = {
- {0xf2, check_for_header2_err},
- {0xf0, check_for_header1_err},
- {0xee, check_for_fire},
- {0xcc, check_for_dummy},
- {0xdd, check_for_dd},
- {0x00, no_check},
- {0x10, check_z_buffer_addr0},
- {0x11, check_z_buffer_addr1},
- {0x12, check_z_buffer_addr_mode},
- {0x13, no_check},
- {0x14, no_check},
- {0x15, no_check},
- {0x23, no_check},
- {0x24, no_check},
- {0x33, no_check},
- {0x34, no_check},
- {0x35, no_check},
- {0x36, no_check},
- {0x37, no_check},
- {0x38, no_check},
- {0x39, no_check},
- {0x3A, no_check},
- {0x3B, no_check},
- {0x3C, no_check},
- {0x3D, no_check},
- {0x3E, no_check},
- {0x40, check_destination_addr0},
- {0x41, check_destination_addr1},
- {0x42, check_destination_addr_mode},
- {0x43, no_check},
- {0x44, no_check},
- {0x50, no_check},
- {0x51, no_check},
- {0x52, no_check},
- {0x53, no_check},
- {0x54, no_check},
- {0x55, no_check},
- {0x56, no_check},
- {0x57, no_check},
- {0x58, no_check},
- {0x70, no_check},
- {0x71, no_check},
- {0x78, no_check},
- {0x79, no_check},
- {0x7A, no_check},
- {0x7B, no_check},
- {0x7C, no_check},
- {0x7D, check_for_vertex_count}
-};
-
-static hz_init_t init_table2[] = {
- {0xf2, check_for_header2_err},
- {0xf0, check_for_header1_err},
- {0xee, check_for_fire},
- {0xcc, check_for_dummy},
- {0x00, check_texture_addr0},
- {0x01, check_texture_addr0},
- {0x02, check_texture_addr0},
- {0x03, check_texture_addr0},
- {0x04, check_texture_addr0},
- {0x05, check_texture_addr0},
- {0x06, check_texture_addr0},
- {0x07, check_texture_addr0},
- {0x08, check_texture_addr0},
- {0x09, check_texture_addr0},
- {0x20, check_texture_addr1},
- {0x21, check_texture_addr1},
- {0x22, check_texture_addr1},
- {0x23, check_texture_addr4},
- {0x2B, check_texture_addr3},
- {0x2C, check_texture_addr3},
- {0x2D, check_texture_addr3},
- {0x2E, check_texture_addr3},
- {0x2F, check_texture_addr3},
- {0x30, check_texture_addr3},
- {0x31, check_texture_addr3},
- {0x32, check_texture_addr3},
- {0x33, check_texture_addr3},
- {0x34, check_texture_addr3},
- {0x4B, check_texture_addr5},
- {0x4C, check_texture_addr6},
- {0x51, check_texture_addr7},
- {0x52, check_texture_addr8},
- {0x77, check_texture_addr2},
- {0x78, no_check},
- {0x79, no_check},
- {0x7A, no_check},
- {0x7B, check_texture_addr_mode},
- {0x7C, no_check},
- {0x7D, no_check},
- {0x7E, no_check},
- {0x7F, no_check},
- {0x80, no_check},
- {0x81, no_check},
- {0x82, no_check},
- {0x83, no_check},
- {0x85, no_check},
- {0x86, no_check},
- {0x87, no_check},
- {0x88, no_check},
- {0x89, no_check},
- {0x8A, no_check},
- {0x90, no_check},
- {0x91, no_check},
- {0x92, no_check},
- {0x93, no_check}
-};
-
-static hz_init_t init_table3[] = {
- {0xf2, check_for_header2_err},
- {0xf0, check_for_header1_err},
- {0xcc, check_for_dummy},
- {0x00, check_number_texunits}
-};
-
-static hazard_t table1[256];
-static hazard_t table2[256];
-static hazard_t table3[256];
-
-static __inline__ int
-eat_words(const uint32_t **buf, const uint32_t *buf_end, unsigned num_words)
-{
- if ((buf_end - *buf) >= num_words) {
- *buf += num_words;
- return 0;
- }
- DRM_ERROR("Illegal termination of DMA command buffer\n");
- return 1;
-}
-
-/*
- * Partially stolen from drm_memory.h
- */
-
-static __inline__ drm_local_map_t *via_drm_lookup_agp_map(drm_via_state_t *seq,
- unsigned long offset,
- unsigned long size,
- struct drm_device *dev)
-{
- struct drm_map_list *r_list;
- drm_local_map_t *map = seq->map_cache;
-
- if (map && map->offset <= offset
- && (offset + size) <= (map->offset + map->size)) {
- return map;
- }
-
- list_for_each_entry(r_list, &dev->maplist, head) {
- map = r_list->map;
- if (!map)
- continue;
- if (map->offset <= offset
- && (offset + size) <= (map->offset + map->size)
- && !(map->flags & _DRM_RESTRICTED)
- && (map->type == _DRM_AGP)) {
- seq->map_cache = map;
- return map;
- }
- }
- return NULL;
-}
-
-/*
- * Require that all AGP texture levels reside in the same AGP map which should
- * be mappable by the client. This is not a big restriction.
- * FIXME: To actually enforce this security policy strictly, drm_rmmap
- * would have to wait for dma quiescent before removing an AGP map.
- * The via_drm_lookup_agp_map call in reality seems to take
- * very little CPU time.
- */
-
-static __inline__ int finish_current_sequence(drm_via_state_t * cur_seq)
-{
- switch (cur_seq->unfinished) {
- case z_address:
- DRM_DEBUG("Z Buffer start address is 0x%x\n", cur_seq->z_addr);
- break;
- case dest_address:
- DRM_DEBUG("Destination start address is 0x%x\n",
- cur_seq->d_addr);
- break;
- case tex_address:
- if (cur_seq->agp_texture) {
- unsigned start =
- cur_seq->tex_level_lo[cur_seq->texture];
- unsigned end = cur_seq->tex_level_hi[cur_seq->texture];
- unsigned long lo = ~0, hi = 0, tmp;
- uint32_t *addr, *pitch, *height, tex;
- unsigned i;
- int npot;
-
- if (end > 9)
- end = 9;
- if (start > 9)
- start = 9;
-
- addr =
- &(cur_seq->t_addr[tex = cur_seq->texture][start]);
- pitch = &(cur_seq->pitch[tex][start]);
- height = &(cur_seq->height[tex][start]);
- npot = cur_seq->tex_npot[tex];
- for (i = start; i <= end; ++i) {
- tmp = *addr++;
- if (tmp < lo)
- lo = tmp;
- if (i == 0 && npot)
- tmp += (*height++ * *pitch++);
- else
- tmp += (*height++ << *pitch++);
- if (tmp > hi)
- hi = tmp;
- }
-
- if (!via_drm_lookup_agp_map
- (cur_seq, lo, hi - lo, cur_seq->dev)) {
- DRM_ERROR
- ("AGP texture is not in allowed map\n");
- return 2;
- }
- }
- break;
- default:
- break;
- }
- cur_seq->unfinished = no_sequence;
- return 0;
-}
-
-static __inline__ int
-investigate_hazard(uint32_t cmd, hazard_t hz, drm_via_state_t *cur_seq)
-{
- register uint32_t tmp, *tmp_addr;
-
- if (cur_seq->unfinished && (cur_seq->unfinished != seqs[hz])) {
- int ret;
- if ((ret = finish_current_sequence(cur_seq)))
- return ret;
- }
-
- switch (hz) {
- case check_for_header2:
- if (cmd == HALCYON_HEADER2)
- return 1;
- return 0;
- case check_for_header1:
- if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1)
- return 1;
- return 0;
- case check_for_header2_err:
- if (cmd == HALCYON_HEADER2)
- return 1;
- DRM_ERROR("Illegal DMA HALCYON_HEADER2 command\n");
- break;
- case check_for_header1_err:
- if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1)
- return 1;
- DRM_ERROR("Illegal DMA HALCYON_HEADER1 command\n");
- break;
- case check_for_fire:
- if ((cmd & HALCYON_FIREMASK) == HALCYON_FIRECMD)
- return 1;
- DRM_ERROR("Illegal DMA HALCYON_FIRECMD command\n");
- break;
- case check_for_dummy:
- if (HC_DUMMY == cmd)
- return 0;
- DRM_ERROR("Illegal DMA HC_DUMMY command\n");
- break;
- case check_for_dd:
- if (0xdddddddd == cmd)
- return 0;
- DRM_ERROR("Illegal DMA 0xdddddddd command\n");
- break;
- case check_z_buffer_addr0:
- cur_seq->unfinished = z_address;
- cur_seq->z_addr = (cur_seq->z_addr & 0xFF000000) |
- (cmd & 0x00FFFFFF);
- return 0;
- case check_z_buffer_addr1:
- cur_seq->unfinished = z_address;
- cur_seq->z_addr = (cur_seq->z_addr & 0x00FFFFFF) |
- ((cmd & 0xFF) << 24);
- return 0;
- case check_z_buffer_addr_mode:
- cur_seq->unfinished = z_address;
- if ((cmd & 0x0000C000) == 0)
- return 0;
- DRM_ERROR("Attempt to place Z buffer in system memory\n");
- return 2;
- case check_destination_addr0:
- cur_seq->unfinished = dest_address;
- cur_seq->d_addr = (cur_seq->d_addr & 0xFF000000) |
- (cmd & 0x00FFFFFF);
- return 0;
- case check_destination_addr1:
- cur_seq->unfinished = dest_address;
- cur_seq->d_addr = (cur_seq->d_addr & 0x00FFFFFF) |
- ((cmd & 0xFF) << 24);
- return 0;
- case check_destination_addr_mode:
- cur_seq->unfinished = dest_address;
- if ((cmd & 0x0000C000) == 0)
- return 0;
- DRM_ERROR
- ("Attempt to place 3D drawing buffer in system memory\n");
- return 2;
- case check_texture_addr0:
- cur_seq->unfinished = tex_address;
- tmp = (cmd >> 24);
- tmp_addr = &cur_seq->t_addr[cur_seq->texture][tmp];
- *tmp_addr = (*tmp_addr & 0xFF000000) | (cmd & 0x00FFFFFF);
- return 0;
- case check_texture_addr1:
- cur_seq->unfinished = tex_address;
- tmp = ((cmd >> 24) - 0x20);
- tmp += tmp << 1;
- tmp_addr = &cur_seq->t_addr[cur_seq->texture][tmp];
- *tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF) << 24);
- tmp_addr++;
- *tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF00) << 16);
- tmp_addr++;
- *tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF0000) << 8);
- return 0;
- case check_texture_addr2:
- cur_seq->unfinished = tex_address;
- cur_seq->tex_level_lo[tmp = cur_seq->texture] = cmd & 0x3F;
- cur_seq->tex_level_hi[tmp] = (cmd & 0xFC0) >> 6;
- return 0;
- case check_texture_addr3:
- cur_seq->unfinished = tex_address;
- tmp = ((cmd >> 24) - HC_SubA_HTXnL0Pit);
- if (tmp == 0 &&
- (cmd & HC_HTXnEnPit_MASK)) {
- cur_seq->pitch[cur_seq->texture][tmp] =
- (cmd & HC_HTXnLnPit_MASK);
- cur_seq->tex_npot[cur_seq->texture] = 1;
- } else {
- cur_seq->pitch[cur_seq->texture][tmp] =
- (cmd & HC_HTXnLnPitE_MASK) >> HC_HTXnLnPitE_SHIFT;
- cur_seq->tex_npot[cur_seq->texture] = 0;
- if (cmd & 0x000FFFFF) {
- DRM_ERROR
- ("Unimplemented texture level 0 pitch mode.\n");
- return 2;
- }
- }
- return 0;
- case check_texture_addr4:
- cur_seq->unfinished = tex_address;
- tmp_addr = &cur_seq->t_addr[cur_seq->texture][9];
- *tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF) << 24);
- return 0;
- case check_texture_addr5:
- case check_texture_addr6:
- cur_seq->unfinished = tex_address;
- /*
- * Texture width. We don't care since we have the pitch.
- */
- return 0;
- case check_texture_addr7:
- cur_seq->unfinished = tex_address;
- tmp_addr = &(cur_seq->height[cur_seq->texture][0]);
- tmp_addr[5] = 1 << ((cmd & 0x00F00000) >> 20);
- tmp_addr[4] = 1 << ((cmd & 0x000F0000) >> 16);
- tmp_addr[3] = 1 << ((cmd & 0x0000F000) >> 12);
- tmp_addr[2] = 1 << ((cmd & 0x00000F00) >> 8);
- tmp_addr[1] = 1 << ((cmd & 0x000000F0) >> 4);
- tmp_addr[0] = 1 << (cmd & 0x0000000F);
- return 0;
- case check_texture_addr8:
- cur_seq->unfinished = tex_address;
- tmp_addr = &(cur_seq->height[cur_seq->texture][0]);
- tmp_addr[9] = 1 << ((cmd & 0x0000F000) >> 12);
- tmp_addr[8] = 1 << ((cmd & 0x00000F00) >> 8);
- tmp_addr[7] = 1 << ((cmd & 0x000000F0) >> 4);
- tmp_addr[6] = 1 << (cmd & 0x0000000F);
- return 0;
- case check_texture_addr_mode:
- cur_seq->unfinished = tex_address;
- if (2 == (tmp = cmd & 0x00000003)) {
- DRM_ERROR
- ("Attempt to fetch texture from system memory.\n");
- return 2;
- }
- cur_seq->agp_texture = (tmp == 3);
- cur_seq->tex_palette_size[cur_seq->texture] =
- (cmd >> 16) & 0x000000007;
- return 0;
- case check_for_vertex_count:
- cur_seq->vertex_count = cmd & 0x0000FFFF;
- return 0;
- case check_number_texunits:
- cur_seq->multitex = (cmd >> 3) & 1;
- return 0;
- default:
- DRM_ERROR("Illegal DMA data: 0x%x\n", cmd);
- return 2;
- }
- return 2;
-}
-
-static __inline__ int
-via_check_prim_list(uint32_t const **buffer, const uint32_t * buf_end,
- drm_via_state_t *cur_seq)
-{
- drm_via_private_t *dev_priv =
- (drm_via_private_t *) cur_seq->dev->dev_private;
- uint32_t a_fire, bcmd, dw_count;
- int ret = 0;
- int have_fire;
- const uint32_t *buf = *buffer;
-
- while (buf < buf_end) {
- have_fire = 0;
- if ((buf_end - buf) < 2) {
- DRM_ERROR
- ("Unexpected termination of primitive list.\n");
- ret = 1;
- break;
- }
- if ((*buf & HC_ACMD_MASK) != HC_ACMD_HCmdB)
- break;
- bcmd = *buf++;
- if ((*buf & HC_ACMD_MASK) != HC_ACMD_HCmdA) {
- DRM_ERROR("Expected Vertex List A command, got 0x%x\n",
- *buf);
- ret = 1;
- break;
- }
- a_fire =
- *buf++ | HC_HPLEND_MASK | HC_HPMValidN_MASK |
- HC_HE3Fire_MASK;
-
- /*
- * How many dwords per vertex ?
- */
-
- if (cur_seq->agp && ((bcmd & (0xF << 11)) == 0)) {
- DRM_ERROR("Illegal B command vertex data for AGP.\n");
- ret = 1;
- break;
- }
-
- dw_count = 0;
- if (bcmd & (1 << 7))
- dw_count += (cur_seq->multitex) ? 2 : 1;
- if (bcmd & (1 << 8))
- dw_count += (cur_seq->multitex) ? 2 : 1;
- if (bcmd & (1 << 9))
- dw_count++;
- if (bcmd & (1 << 10))
- dw_count++;
- if (bcmd & (1 << 11))
- dw_count++;
- if (bcmd & (1 << 12))
- dw_count++;
- if (bcmd & (1 << 13))
- dw_count++;
- if (bcmd & (1 << 14))
- dw_count++;
-
- while (buf < buf_end) {
- if (*buf == a_fire) {
- if (dev_priv->num_fire_offsets >=
- VIA_FIRE_BUF_SIZE) {
- DRM_ERROR("Fire offset buffer full.\n");
- ret = 1;
- break;
- }
- dev_priv->fire_offsets[dev_priv->
- num_fire_offsets++] =
- buf;
- have_fire = 1;
- buf++;
- if (buf < buf_end && *buf == a_fire)
- buf++;
- break;
- }
- if ((*buf == HALCYON_HEADER2) ||
- ((*buf & HALCYON_FIREMASK) == HALCYON_FIRECMD)) {
- DRM_ERROR("Missing Vertex Fire command, "
- "Stray Vertex Fire command or verifier "
- "lost sync.\n");
- ret = 1;
- break;
- }
- if ((ret = eat_words(&buf, buf_end, dw_count)))
- break;
- }
- if (buf >= buf_end && !have_fire) {
- DRM_ERROR("Missing Vertex Fire command or verifier "
- "lost sync.\n");
- ret = 1;
- break;
- }
- if (cur_seq->agp && ((buf - cur_seq->buf_start) & 0x01)) {
- DRM_ERROR("AGP Primitive list end misaligned.\n");
- ret = 1;
- break;
- }
- }
- *buffer = buf;
- return ret;
-}
-
-static __inline__ verifier_state_t
-via_check_header2(uint32_t const **buffer, const uint32_t *buf_end,
- drm_via_state_t *hc_state)
-{
- uint32_t cmd;
- int hz_mode;
- hazard_t hz;
- const uint32_t *buf = *buffer;
- const hazard_t *hz_table;
-
- if ((buf_end - buf) < 2) {
- DRM_ERROR
- ("Illegal termination of DMA HALCYON_HEADER2 sequence.\n");
- return state_error;
- }
- buf++;
- cmd = (*buf++ & 0xFFFF0000) >> 16;
-
- switch (cmd) {
- case HC_ParaType_CmdVdata:
- if (via_check_prim_list(&buf, buf_end, hc_state))
- return state_error;
- *buffer = buf;
- return state_command;
- case HC_ParaType_NotTex:
- hz_table = table1;
- break;
- case HC_ParaType_Tex:
- hc_state->texture = 0;
- hz_table = table2;
- break;
- case (HC_ParaType_Tex | (HC_SubType_Tex1 << 8)):
- hc_state->texture = 1;
- hz_table = table2;
- break;
- case (HC_ParaType_Tex | (HC_SubType_TexGeneral << 8)):
- hz_table = table3;
- break;
- case HC_ParaType_Auto:
- if (eat_words(&buf, buf_end, 2))
- return state_error;
- *buffer = buf;
- return state_command;
- case (HC_ParaType_Palette | (HC_SubType_Stipple << 8)):
- if (eat_words(&buf, buf_end, 32))
- return state_error;
- *buffer = buf;
- return state_command;
- case (HC_ParaType_Palette | (HC_SubType_TexPalette0 << 8)):
- case (HC_ParaType_Palette | (HC_SubType_TexPalette1 << 8)):
- DRM_ERROR("Texture palettes are rejected because of "
- "lack of info how to determine their size.\n");
- return state_error;
- case (HC_ParaType_Palette | (HC_SubType_FogTable << 8)):
- DRM_ERROR("Fog factor palettes are rejected because of "
- "lack of info how to determine their size.\n");
- return state_error;
- default:
-
- /*
- * There are some unimplemented HC_ParaTypes here, that
- * need to be implemented if the Mesa driver is extended.
- */
-
- DRM_ERROR("Invalid or unimplemented HALCYON_HEADER2 "
- "DMA subcommand: 0x%x. Previous dword: 0x%x\n",
- cmd, *(buf - 2));
- *buffer = buf;
- return state_error;
- }
-
- while (buf < buf_end) {
- cmd = *buf++;
- if ((hz = hz_table[cmd >> 24])) {
- if ((hz_mode = investigate_hazard(cmd, hz, hc_state))) {
- if (hz_mode == 1) {
- buf--;
- break;
- }
- return state_error;
- }
- } else if (hc_state->unfinished &&
- finish_current_sequence(hc_state)) {
- return state_error;
- }
- }
- if (hc_state->unfinished && finish_current_sequence(hc_state))
- return state_error;
- *buffer = buf;
- return state_command;
-}
-
-static __inline__ verifier_state_t
-via_parse_header2(drm_via_private_t *dev_priv, uint32_t const **buffer,
- const uint32_t *buf_end, int *fire_count)
-{
- uint32_t cmd;
- const uint32_t *buf = *buffer;
- const uint32_t *next_fire;
- int burst = 0;
-
- next_fire = dev_priv->fire_offsets[*fire_count];
- buf++;
- cmd = (*buf & 0xFFFF0000) >> 16;
- via_write(dev_priv, HC_REG_TRANS_SET + HC_REG_BASE, *buf++);
- switch (cmd) {
- case HC_ParaType_CmdVdata:
- while ((buf < buf_end) &&
- (*fire_count < dev_priv->num_fire_offsets) &&
- (*buf & HC_ACMD_MASK) == HC_ACMD_HCmdB) {
- while (buf <= next_fire) {
- via_write(dev_priv, HC_REG_TRANS_SPACE + HC_REG_BASE +
- (burst & 63), *buf++);
- burst += 4;
- }
- if ((buf < buf_end)
- && ((*buf & HALCYON_FIREMASK) == HALCYON_FIRECMD))
- buf++;
-
- if (++(*fire_count) < dev_priv->num_fire_offsets)
- next_fire = dev_priv->fire_offsets[*fire_count];
- }
- break;
- default:
- while (buf < buf_end) {
-
- if (*buf == HC_HEADER2 ||
- (*buf & HALCYON_HEADER1MASK) == HALCYON_HEADER1 ||
- (*buf & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5 ||
- (*buf & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6)
- break;
-
- via_write(dev_priv, HC_REG_TRANS_SPACE + HC_REG_BASE +
- (burst & 63), *buf++);
- burst += 4;
- }
- }
- *buffer = buf;
- return state_command;
-}
-
-static __inline__ int verify_mmio_address(uint32_t address)
-{
- if ((address > 0x3FF) && (address < 0xC00)) {
- DRM_ERROR("Invalid VIDEO DMA command. "
- "Attempt to access 3D- or command burst area.\n");
- return 1;
- } else if ((address > 0xCFF) && (address < 0x1300)) {
- DRM_ERROR("Invalid VIDEO DMA command. "
- "Attempt to access PCI DMA area.\n");
- return 1;
- } else if (address > 0x13FF) {
- DRM_ERROR("Invalid VIDEO DMA command. "
- "Attempt to access VGA registers.\n");
- return 1;
- }
- return 0;
-}
-
-static __inline__ int
-verify_video_tail(uint32_t const **buffer, const uint32_t * buf_end,
- uint32_t dwords)
-{
- const uint32_t *buf = *buffer;
-
- if (buf_end - buf < dwords) {
- DRM_ERROR("Illegal termination of video command.\n");
- return 1;
- }
- while (dwords--) {
- if (*buf++) {
- DRM_ERROR("Illegal video command tail.\n");
- return 1;
- }
- }
- *buffer = buf;
- return 0;
-}
-
-static __inline__ verifier_state_t
-via_check_header1(uint32_t const **buffer, const uint32_t * buf_end)
-{
- uint32_t cmd;
- const uint32_t *buf = *buffer;
- verifier_state_t ret = state_command;
-
- while (buf < buf_end) {
- cmd = *buf;
- if ((cmd > ((0x3FF >> 2) | HALCYON_HEADER1)) &&
- (cmd < ((0xC00 >> 2) | HALCYON_HEADER1))) {
- if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1)
- break;
- DRM_ERROR("Invalid HALCYON_HEADER1 command. "
- "Attempt to access 3D- or command burst area.\n");
- ret = state_error;
- break;
- } else if (cmd > ((0xCFF >> 2) | HALCYON_HEADER1)) {
- if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1)
- break;
- DRM_ERROR("Invalid HALCYON_HEADER1 command. "
- "Attempt to access VGA registers.\n");
- ret = state_error;
- break;
- } else {
- buf += 2;
- }
- }
- *buffer = buf;
- return ret;
-}
-
-static __inline__ verifier_state_t
-via_parse_header1(drm_via_private_t *dev_priv, uint32_t const **buffer,
- const uint32_t *buf_end)
-{
- register uint32_t cmd;
- const uint32_t *buf = *buffer;
-
- while (buf < buf_end) {
- cmd = *buf;
- if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1)
- break;
- via_write(dev_priv, (cmd & ~HALCYON_HEADER1MASK) << 2, *++buf);
- buf++;
- }
- *buffer = buf;
- return state_command;
-}
-
-static __inline__ verifier_state_t
-via_check_vheader5(uint32_t const **buffer, const uint32_t *buf_end)
-{
- uint32_t data;
- const uint32_t *buf = *buffer;
-
- if (buf_end - buf < 4) {
- DRM_ERROR("Illegal termination of video header5 command\n");
- return state_error;
- }
-
- data = *buf++ & ~VIA_VIDEOMASK;
- if (verify_mmio_address(data))
- return state_error;
-
- data = *buf++;
- if (*buf++ != 0x00F50000) {
- DRM_ERROR("Illegal header5 header data\n");
- return state_error;
- }
- if (*buf++ != 0x00000000) {
- DRM_ERROR("Illegal header5 header data\n");
- return state_error;
- }
- if (eat_words(&buf, buf_end, data))
- return state_error;
- if ((data & 3) && verify_video_tail(&buf, buf_end, 4 - (data & 3)))
- return state_error;
- *buffer = buf;
- return state_command;
-
-}
-
-static __inline__ verifier_state_t
-via_parse_vheader5(drm_via_private_t *dev_priv, uint32_t const **buffer,
- const uint32_t *buf_end)
-{
- uint32_t addr, count, i;
- const uint32_t *buf = *buffer;
-
- addr = *buf++ & ~VIA_VIDEOMASK;
- i = count = *buf;
- buf += 3;
- while (i--)
- via_write(dev_priv, addr, *buf++);
- if (count & 3)
- buf += 4 - (count & 3);
- *buffer = buf;
- return state_command;
-}
-
-static __inline__ verifier_state_t
-via_check_vheader6(uint32_t const **buffer, const uint32_t * buf_end)
-{
- uint32_t data;
- const uint32_t *buf = *buffer;
- uint32_t i;
-
- if (buf_end - buf < 4) {
- DRM_ERROR("Illegal termination of video header6 command\n");
- return state_error;
- }
- buf++;
- data = *buf++;
- if (*buf++ != 0x00F60000) {
- DRM_ERROR("Illegal header6 header data\n");
- return state_error;
- }
- if (*buf++ != 0x00000000) {
- DRM_ERROR("Illegal header6 header data\n");
- return state_error;
- }
- if ((buf_end - buf) < (data << 1)) {
- DRM_ERROR("Illegal termination of video header6 command\n");
- return state_error;
- }
- for (i = 0; i < data; ++i) {
- if (verify_mmio_address(*buf++))
- return state_error;
- buf++;
- }
- data <<= 1;
- if ((data & 3) && verify_video_tail(&buf, buf_end, 4 - (data & 3)))
- return state_error;
- *buffer = buf;
- return state_command;
-}
-
-static __inline__ verifier_state_t
-via_parse_vheader6(drm_via_private_t *dev_priv, uint32_t const **buffer,
- const uint32_t *buf_end)
-{
-
- uint32_t addr, count, i;
- const uint32_t *buf = *buffer;
-
- i = count = *++buf;
- buf += 3;
- while (i--) {
- addr = *buf++;
- via_write(dev_priv, addr, *buf++);
- }
- count <<= 1;
- if (count & 3)
- buf += 4 - (count & 3);
- *buffer = buf;
- return state_command;
-}
-
-static int
-via_verify_command_stream(const uint32_t * buf, unsigned int size,
- struct drm_device * dev, int agp)
-{
-
- drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
- drm_via_state_t *hc_state = &dev_priv->hc_state;
- drm_via_state_t saved_state = *hc_state;
- uint32_t cmd;
- const uint32_t *buf_end = buf + (size >> 2);
- verifier_state_t state = state_command;
- int cme_video;
- int supported_3d;
-
- cme_video = (dev_priv->chipset == VIA_PRO_GROUP_A ||
- dev_priv->chipset == VIA_DX9_0);
-
- supported_3d = dev_priv->chipset != VIA_DX9_0;
-
- hc_state->dev = dev;
- hc_state->unfinished = no_sequence;
- hc_state->map_cache = NULL;
- hc_state->agp = agp;
- hc_state->buf_start = buf;
- dev_priv->num_fire_offsets = 0;
-
- while (buf < buf_end) {
-
- switch (state) {
- case state_header2:
- state = via_check_header2(&buf, buf_end, hc_state);
- break;
- case state_header1:
- state = via_check_header1(&buf, buf_end);
- break;
- case state_vheader5:
- state = via_check_vheader5(&buf, buf_end);
- break;
- case state_vheader6:
- state = via_check_vheader6(&buf, buf_end);
- break;
- case state_command:
- cmd = *buf;
- if ((cmd == HALCYON_HEADER2) && supported_3d)
- state = state_header2;
- else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1)
- state = state_header1;
- else if (cme_video
- && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5)
- state = state_vheader5;
- else if (cme_video
- && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6)
- state = state_vheader6;
- else if ((cmd == HALCYON_HEADER2) && !supported_3d) {
- DRM_ERROR("Accelerated 3D is not supported on this chipset yet.\n");
- state = state_error;
- } else {
- DRM_ERROR
- ("Invalid / Unimplemented DMA HEADER command. 0x%x\n",
- cmd);
- state = state_error;
- }
- break;
- case state_error:
- default:
- *hc_state = saved_state;
- return -EINVAL;
- }
- }
- if (state == state_error) {
- *hc_state = saved_state;
- return -EINVAL;
- }
- return 0;
-}
-
-static int
-via_parse_command_stream(struct drm_device *dev, const uint32_t *buf,
- unsigned int size)
-{
-
- drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
- uint32_t cmd;
- const uint32_t *buf_end = buf + (size >> 2);
- verifier_state_t state = state_command;
- int fire_count = 0;
-
- while (buf < buf_end) {
-
- switch (state) {
- case state_header2:
- state =
- via_parse_header2(dev_priv, &buf, buf_end,
- &fire_count);
- break;
- case state_header1:
- state = via_parse_header1(dev_priv, &buf, buf_end);
- break;
- case state_vheader5:
- state = via_parse_vheader5(dev_priv, &buf, buf_end);
- break;
- case state_vheader6:
- state = via_parse_vheader6(dev_priv, &buf, buf_end);
- break;
- case state_command:
- cmd = *buf;
- if (cmd == HALCYON_HEADER2)
- state = state_header2;
- else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1)
- state = state_header1;
- else if ((cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5)
- state = state_vheader5;
- else if ((cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6)
- state = state_vheader6;
- else {
- DRM_ERROR
- ("Invalid / Unimplemented DMA HEADER command. 0x%x\n",
- cmd);
- state = state_error;
- }
- break;
- case state_error:
- default:
- return -EINVAL;
- }
- }
- if (state == state_error)
- return -EINVAL;
- return 0;
-}
-
-static void
-setup_hazard_table(hz_init_t init_table[], hazard_t table[], int size)
-{
- int i;
-
- for (i = 0; i < 256; ++i)
- table[i] = forbidden_command;
-
- for (i = 0; i < size; ++i)
- table[init_table[i].code] = init_table[i].hz;
-}
-
-static void via_init_command_verifier(void)
-{
- setup_hazard_table(init_table1, table1, ARRAY_SIZE(init_table1));
- setup_hazard_table(init_table2, table2, ARRAY_SIZE(init_table2));
- setup_hazard_table(init_table3, table3, ARRAY_SIZE(init_table3));
-}
-/*
- * Unmap a DMA mapping.
- */
-static void
-via_unmap_blit_from_device(struct pci_dev *pdev, drm_via_sg_info_t *vsg)
-{
- int num_desc = vsg->num_desc;
- unsigned cur_descriptor_page = num_desc / vsg->descriptors_per_page;
- unsigned descriptor_this_page = num_desc % vsg->descriptors_per_page;
- drm_via_descriptor_t *desc_ptr = vsg->desc_pages[cur_descriptor_page] +
- descriptor_this_page;
- dma_addr_t next = vsg->chain_start;
-
- while (num_desc--) {
- if (descriptor_this_page-- == 0) {
- cur_descriptor_page--;
- descriptor_this_page = vsg->descriptors_per_page - 1;
- desc_ptr = vsg->desc_pages[cur_descriptor_page] +
- descriptor_this_page;
- }
- dma_unmap_single(&pdev->dev, next, sizeof(*desc_ptr), DMA_TO_DEVICE);
- dma_unmap_page(&pdev->dev, desc_ptr->mem_addr, desc_ptr->size, vsg->direction);
- next = (dma_addr_t) desc_ptr->next;
- desc_ptr--;
- }
-}
-
-/*
- * If mode = 0, count how many descriptors are needed.
- * If mode = 1, Map the DMA pages for the device, put together and map also the descriptors.
- * Descriptors are run in reverse order by the hardware because we are not allowed to update the
- * 'next' field without syncing calls when the descriptor is already mapped.
- */
-static void
-via_map_blit_for_device(struct pci_dev *pdev,
- const drm_via_dmablit_t *xfer,
- drm_via_sg_info_t *vsg,
- int mode)
-{
- unsigned cur_descriptor_page = 0;
- unsigned num_descriptors_this_page = 0;
- unsigned char *mem_addr = xfer->mem_addr;
- unsigned char *cur_mem;
- unsigned char *first_addr = (unsigned char *)VIA_PGDN(mem_addr);
- uint32_t fb_addr = xfer->fb_addr;
- uint32_t cur_fb;
- unsigned long line_len;
- unsigned remaining_len;
- int num_desc = 0;
- int cur_line;
- dma_addr_t next = 0 | VIA_DMA_DPR_EC;
- drm_via_descriptor_t *desc_ptr = NULL;
-
- if (mode == 1)
- desc_ptr = vsg->desc_pages[cur_descriptor_page];
-
- for (cur_line = 0; cur_line < xfer->num_lines; ++cur_line) {
-
- line_len = xfer->line_length;
- cur_fb = fb_addr;
- cur_mem = mem_addr;
-
- while (line_len > 0) {
-
- remaining_len = min(PAGE_SIZE-VIA_PGOFF(cur_mem), line_len);
- line_len -= remaining_len;
-
- if (mode == 1) {
- desc_ptr->mem_addr =
- dma_map_page(&pdev->dev,
- vsg->pages[VIA_PFN(cur_mem) -
- VIA_PFN(first_addr)],
- VIA_PGOFF(cur_mem), remaining_len,
- vsg->direction);
- desc_ptr->dev_addr = cur_fb;
-
- desc_ptr->size = remaining_len;
- desc_ptr->next = (uint32_t) next;
- next = dma_map_single(&pdev->dev, desc_ptr, sizeof(*desc_ptr),
- DMA_TO_DEVICE);
- desc_ptr++;
- if (++num_descriptors_this_page >= vsg->descriptors_per_page) {
- num_descriptors_this_page = 0;
- desc_ptr = vsg->desc_pages[++cur_descriptor_page];
- }
- }
-
- num_desc++;
- cur_mem += remaining_len;
- cur_fb += remaining_len;
- }
-
- mem_addr += xfer->mem_stride;
- fb_addr += xfer->fb_stride;
- }
-
- if (mode == 1) {
- vsg->chain_start = next;
- vsg->state = dr_via_device_mapped;
- }
- vsg->num_desc = num_desc;
-}
-
-/*
- * Function that frees up all resources for a blit. It is usable even if the
- * blit info has only been partially built as long as the status enum is consistent
- * with the actual status of the used resources.
- */
-static void
-via_free_sg_info(struct pci_dev *pdev, drm_via_sg_info_t *vsg)
-{
- int i;
-
- switch (vsg->state) {
- case dr_via_device_mapped:
- via_unmap_blit_from_device(pdev, vsg);
- fallthrough;
- case dr_via_desc_pages_alloc:
- for (i = 0; i < vsg->num_desc_pages; ++i) {
- if (vsg->desc_pages[i] != NULL)
- free_page((unsigned long)vsg->desc_pages[i]);
- }
- kfree(vsg->desc_pages);
- fallthrough;
- case dr_via_pages_locked:
- unpin_user_pages_dirty_lock(vsg->pages, vsg->num_pages,
- (vsg->direction == DMA_FROM_DEVICE));
- fallthrough;
- case dr_via_pages_alloc:
- vfree(vsg->pages);
- fallthrough;
- default:
- vsg->state = dr_via_sg_init;
- }
- vfree(vsg->bounce_buffer);
- vsg->bounce_buffer = NULL;
- vsg->free_on_sequence = 0;
-}
-
-/*
- * Fire a blit engine.
- */
-static void
-via_fire_dmablit(struct drm_device *dev, drm_via_sg_info_t *vsg, int engine)
-{
- drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private;
-
- via_write(dev_priv, VIA_PCI_DMA_MAR0 + engine*0x10, 0);
- via_write(dev_priv, VIA_PCI_DMA_DAR0 + engine*0x10, 0);
- via_write(dev_priv, VIA_PCI_DMA_CSR0 + engine*0x04, VIA_DMA_CSR_DD | VIA_DMA_CSR_TD |
- VIA_DMA_CSR_DE);
- via_write(dev_priv, VIA_PCI_DMA_MR0 + engine*0x04, VIA_DMA_MR_CM | VIA_DMA_MR_TDIE);
- via_write(dev_priv, VIA_PCI_DMA_BCR0 + engine*0x10, 0);
- via_write(dev_priv, VIA_PCI_DMA_DPR0 + engine*0x10, vsg->chain_start);
- wmb();
- via_write(dev_priv, VIA_PCI_DMA_CSR0 + engine*0x04, VIA_DMA_CSR_DE | VIA_DMA_CSR_TS);
- via_read(dev_priv, VIA_PCI_DMA_CSR0 + engine*0x04);
-}
-
-/*
- * Obtain a page pointer array and lock all pages into system memory. A segmentation violation will
- * occur here if the calling user does not have access to the submitted address.
- */
-static int
-via_lock_all_dma_pages(drm_via_sg_info_t *vsg, drm_via_dmablit_t *xfer)
-{
- int ret;
- unsigned long first_pfn = VIA_PFN(xfer->mem_addr);
- vsg->num_pages = VIA_PFN(xfer->mem_addr + (xfer->num_lines * xfer->mem_stride - 1)) -
- first_pfn + 1;
-
- vsg->pages = vzalloc(array_size(sizeof(struct page *), vsg->num_pages));
- if (NULL == vsg->pages)
- return -ENOMEM;
- ret = pin_user_pages_fast((unsigned long)xfer->mem_addr,
- vsg->num_pages,
- vsg->direction == DMA_FROM_DEVICE ? FOLL_WRITE : 0,
- vsg->pages);
- if (ret != vsg->num_pages) {
- if (ret < 0)
- return ret;
- vsg->state = dr_via_pages_locked;
- return -EINVAL;
- }
- vsg->state = dr_via_pages_locked;
- DRM_DEBUG("DMA pages locked\n");
- return 0;
-}
-
-/*
- * Allocate DMA capable memory for the blit descriptor chain, and an array that keeps track of the
- * pages we allocate. We don't want to use kmalloc for the descriptor chain because it may be
- * quite large for some blits, and pages don't need to be contiguous.
- */
-static int
-via_alloc_desc_pages(drm_via_sg_info_t *vsg)
-{
- int i;
-
- vsg->descriptors_per_page = PAGE_SIZE / sizeof(drm_via_descriptor_t);
- vsg->num_desc_pages = (vsg->num_desc + vsg->descriptors_per_page - 1) /
- vsg->descriptors_per_page;
-
- if (NULL == (vsg->desc_pages = kcalloc(vsg->num_desc_pages, sizeof(void *), GFP_KERNEL)))
- return -ENOMEM;
-
- vsg->state = dr_via_desc_pages_alloc;
- for (i = 0; i < vsg->num_desc_pages; ++i) {
- if (NULL == (vsg->desc_pages[i] =
- (drm_via_descriptor_t *) __get_free_page(GFP_KERNEL)))
- return -ENOMEM;
- }
- DRM_DEBUG("Allocated %d pages for %d descriptors.\n", vsg->num_desc_pages,
- vsg->num_desc);
- return 0;
-}
-
-static void
-via_abort_dmablit(struct drm_device *dev, int engine)
-{
- drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private;
-
- via_write(dev_priv, VIA_PCI_DMA_CSR0 + engine*0x04, VIA_DMA_CSR_TA);
-}
-
-static void
-via_dmablit_engine_off(struct drm_device *dev, int engine)
-{
- drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private;
-
- via_write(dev_priv, VIA_PCI_DMA_CSR0 + engine*0x04, VIA_DMA_CSR_TD | VIA_DMA_CSR_DD);
-}
-
-/*
- * The dmablit part of the IRQ handler. Trying to do only reasonably fast things here.
- * The rest, like unmapping and freeing memory for done blits is done in a separate workqueue
- * task. Basically the task of the interrupt handler is to submit a new blit to the engine, while
- * the workqueue task takes care of processing associated with the old blit.
- */
-static void
-via_dmablit_handler(struct drm_device *dev, int engine, int from_irq)
-{
- drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private;
- drm_via_blitq_t *blitq = dev_priv->blit_queues + engine;
- int cur;
- int done_transfer;
- unsigned long irqsave = 0;
- uint32_t status = 0;
-
- DRM_DEBUG("DMA blit handler called. engine = %d, from_irq = %d, blitq = 0x%lx\n",
- engine, from_irq, (unsigned long) blitq);
-
- if (from_irq)
- spin_lock(&blitq->blit_lock);
- else
- spin_lock_irqsave(&blitq->blit_lock, irqsave);
-
- done_transfer = blitq->is_active &&
- ((status = via_read(dev_priv, VIA_PCI_DMA_CSR0 + engine*0x04)) & VIA_DMA_CSR_TD);
- done_transfer = done_transfer || (blitq->aborting && !(status & VIA_DMA_CSR_DE));
-
- cur = blitq->cur;
- if (done_transfer) {
-
- blitq->blits[cur]->aborted = blitq->aborting;
- blitq->done_blit_handle++;
- wake_up(blitq->blit_queue + cur);
-
- cur++;
- if (cur >= VIA_NUM_BLIT_SLOTS)
- cur = 0;
- blitq->cur = cur;
-
- /*
- * Clear transfer done flag.
- */
-
- via_write(dev_priv, VIA_PCI_DMA_CSR0 + engine*0x04, VIA_DMA_CSR_TD);
-
- blitq->is_active = 0;
- blitq->aborting = 0;
- schedule_work(&blitq->wq);
-
- } else if (blitq->is_active && time_after_eq(jiffies, blitq->end)) {
-
- /*
- * Abort transfer after one second.
- */
-
- via_abort_dmablit(dev, engine);
- blitq->aborting = 1;
- blitq->end = jiffies + HZ;
- }
-
- if (!blitq->is_active) {
- if (blitq->num_outstanding) {
- via_fire_dmablit(dev, blitq->blits[cur], engine);
- blitq->is_active = 1;
- blitq->cur = cur;
- blitq->num_outstanding--;
- blitq->end = jiffies + HZ;
- if (!timer_pending(&blitq->poll_timer))
- mod_timer(&blitq->poll_timer, jiffies + 1);
- } else {
- if (timer_pending(&blitq->poll_timer))
- del_timer(&blitq->poll_timer);
- via_dmablit_engine_off(dev, engine);
- }
- }
-
- if (from_irq)
- spin_unlock(&blitq->blit_lock);
- else
- spin_unlock_irqrestore(&blitq->blit_lock, irqsave);
-}
-
-/*
- * Check whether this blit is still active, performing necessary locking.
- */
-static int
-via_dmablit_active(drm_via_blitq_t *blitq, int engine, uint32_t handle, wait_queue_head_t **queue)
-{
- unsigned long irqsave;
- uint32_t slot;
- int active;
-
- spin_lock_irqsave(&blitq->blit_lock, irqsave);
-
- /*
- * Allow for handle wraparounds.
- */
-
- active = ((blitq->done_blit_handle - handle) > (1 << 23)) &&
- ((blitq->cur_blit_handle - handle) <= (1 << 23));
-
- if (queue && active) {
- slot = handle - blitq->done_blit_handle + blitq->cur - 1;
- if (slot >= VIA_NUM_BLIT_SLOTS)
- slot -= VIA_NUM_BLIT_SLOTS;
- *queue = blitq->blit_queue + slot;
- }
-
- spin_unlock_irqrestore(&blitq->blit_lock, irqsave);
-
- return active;
-}
-
-/*
- * Sync. Wait for at least three seconds for the blit to be performed.
- */
-static int
-via_dmablit_sync(struct drm_device *dev, uint32_t handle, int engine)
-{
-
- drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private;
- drm_via_blitq_t *blitq = dev_priv->blit_queues + engine;
- wait_queue_head_t *queue;
- int ret = 0;
-
- if (via_dmablit_active(blitq, engine, handle, &queue)) {
- VIA_WAIT_ON(ret, *queue, 3 * HZ,
- !via_dmablit_active(blitq, engine, handle, NULL));
- }
- DRM_DEBUG("DMA blit sync handle 0x%x engine %d returned %d\n",
- handle, engine, ret);
-
- return ret;
-}
-
-/*
- * A timer that regularly polls the blit engine in cases where we don't have interrupts:
- * a) Broken hardware (typically those that don't have any video capture facility).
- * b) Blit abort. The hardware doesn't send an interrupt when a blit is aborted.
- * The timer and hardware IRQ's can and do work in parallel. If the hardware has
- * irqs, it will shorten the latency somewhat.
- */
-static void
-via_dmablit_timer(struct timer_list *t)
-{
- drm_via_blitq_t *blitq = from_timer(blitq, t, poll_timer);
- struct drm_device *dev = blitq->dev;
- int engine = (int)
- (blitq - ((drm_via_private_t *)dev->dev_private)->blit_queues);
-
- DRM_DEBUG("Polling timer called for engine %d, jiffies %lu\n", engine,
- (unsigned long) jiffies);
-
- via_dmablit_handler(dev, engine, 0);
-
- if (!timer_pending(&blitq->poll_timer)) {
- mod_timer(&blitq->poll_timer, jiffies + 1);
-
- /*
- * Rerun handler to delete timer if engines are off, and
- * to shorten abort latency. This is a little nasty.
- */
-
- via_dmablit_handler(dev, engine, 0);
-
- }
-}
-
-/*
- * Workqueue task that frees data and mappings associated with a blit.
- * Also wakes up waiting processes. Each of these tasks handles one
- * blit engine only and may not be called on each interrupt.
- */
-static void
-via_dmablit_workqueue(struct work_struct *work)
-{
- drm_via_blitq_t *blitq = container_of(work, drm_via_blitq_t, wq);
- struct drm_device *dev = blitq->dev;
- struct pci_dev *pdev = to_pci_dev(dev->dev);
- unsigned long irqsave;
- drm_via_sg_info_t *cur_sg;
- int cur_released;
-
-
- DRM_DEBUG("Workqueue task called for blit engine %ld\n", (unsigned long)
- (blitq - ((drm_via_private_t *)dev->dev_private)->blit_queues));
-
- spin_lock_irqsave(&blitq->blit_lock, irqsave);
-
- while (blitq->serviced != blitq->cur) {
-
- cur_released = blitq->serviced++;
-
- DRM_DEBUG("Releasing blit slot %d\n", cur_released);
-
- if (blitq->serviced >= VIA_NUM_BLIT_SLOTS)
- blitq->serviced = 0;
-
- cur_sg = blitq->blits[cur_released];
- blitq->num_free++;
-
- spin_unlock_irqrestore(&blitq->blit_lock, irqsave);
-
- wake_up(&blitq->busy_queue);
-
- via_free_sg_info(pdev, cur_sg);
- kfree(cur_sg);
-
- spin_lock_irqsave(&blitq->blit_lock, irqsave);
- }
-
- spin_unlock_irqrestore(&blitq->blit_lock, irqsave);
-}
-
-/*
- * Init all blit engines. Currently we use two, but some hardware have 4.
- */
-static void
-via_init_dmablit(struct drm_device *dev)
-{
- int i, j;
- drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private;
- struct pci_dev *pdev = to_pci_dev(dev->dev);
- drm_via_blitq_t *blitq;
-
- pci_set_master(pdev);
-
- for (i = 0; i < VIA_NUM_BLIT_ENGINES; ++i) {
- blitq = dev_priv->blit_queues + i;
- blitq->dev = dev;
- blitq->cur_blit_handle = 0;
- blitq->done_blit_handle = 0;
- blitq->head = 0;
- blitq->cur = 0;
- blitq->serviced = 0;
- blitq->num_free = VIA_NUM_BLIT_SLOTS - 1;
- blitq->num_outstanding = 0;
- blitq->is_active = 0;
- blitq->aborting = 0;
- spin_lock_init(&blitq->blit_lock);
- for (j = 0; j < VIA_NUM_BLIT_SLOTS; ++j)
- init_waitqueue_head(blitq->blit_queue + j);
- init_waitqueue_head(&blitq->busy_queue);
- INIT_WORK(&blitq->wq, via_dmablit_workqueue);
- timer_setup(&blitq->poll_timer, via_dmablit_timer, 0);
- }
-}
-
-/*
- * Build all info and do all mappings required for a blit.
- */
-static int
-via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmablit_t *xfer)
-{
- struct pci_dev *pdev = to_pci_dev(dev->dev);
- int draw = xfer->to_fb;
- int ret = 0;
-
- vsg->direction = (draw) ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
- vsg->bounce_buffer = NULL;
-
- vsg->state = dr_via_sg_init;
-
- if (xfer->num_lines <= 0 || xfer->line_length <= 0) {
- DRM_ERROR("Zero size bitblt.\n");
- return -EINVAL;
- }
-
- /*
- * Below check is a driver limitation, not a hardware one. We
- * don't want to lock unused pages, and don't want to incoporate the
- * extra logic of avoiding them. Make sure there are no.
- * (Not a big limitation anyway.)
- */
-
- if ((xfer->mem_stride - xfer->line_length) > 2*PAGE_SIZE) {
- DRM_ERROR("Too large system memory stride. Stride: %d, "
- "Length: %d\n", xfer->mem_stride, xfer->line_length);
- return -EINVAL;
- }
-
- if ((xfer->mem_stride == xfer->line_length) &&
- (xfer->fb_stride == xfer->line_length)) {
- xfer->mem_stride *= xfer->num_lines;
- xfer->line_length = xfer->mem_stride;
- xfer->fb_stride = xfer->mem_stride;
- xfer->num_lines = 1;
- }
-
- /*
- * Don't lock an arbitrary large number of pages, since that causes a
- * DOS security hole.
- */
-
- if (xfer->num_lines > 2048 || (xfer->num_lines*xfer->mem_stride > (2048*2048*4))) {
- DRM_ERROR("Too large PCI DMA bitblt.\n");
- return -EINVAL;
- }
-
- /*
- * we allow a negative fb stride to allow flipping of images in
- * transfer.
- */
-
- if (xfer->mem_stride < xfer->line_length ||
- abs(xfer->fb_stride) < xfer->line_length) {
- DRM_ERROR("Invalid frame-buffer / memory stride.\n");
- return -EINVAL;
- }
-
- /*
- * A hardware bug seems to be worked around if system memory addresses start on
- * 16 byte boundaries. This seems a bit restrictive however. VIA is contacted
- * about this. Meanwhile, impose the following restrictions:
- */
-
-#ifdef VIA_BUGFREE
- if ((((unsigned long)xfer->mem_addr & 3) != ((unsigned long)xfer->fb_addr & 3)) ||
- ((xfer->num_lines > 1) && ((xfer->mem_stride & 3) != (xfer->fb_stride & 3)))) {
- DRM_ERROR("Invalid DRM bitblt alignment.\n");
- return -EINVAL;
- }
-#else
- if ((((unsigned long)xfer->mem_addr & 15) ||
- ((unsigned long)xfer->fb_addr & 3)) ||
- ((xfer->num_lines > 1) &&
- ((xfer->mem_stride & 15) || (xfer->fb_stride & 3)))) {
- DRM_ERROR("Invalid DRM bitblt alignment.\n");
- return -EINVAL;
- }
-#endif
-
- if (0 != (ret = via_lock_all_dma_pages(vsg, xfer))) {
- DRM_ERROR("Could not lock DMA pages.\n");
- via_free_sg_info(pdev, vsg);
- return ret;
- }
-
- via_map_blit_for_device(pdev, xfer, vsg, 0);
- if (0 != (ret = via_alloc_desc_pages(vsg))) {
- DRM_ERROR("Could not allocate DMA descriptor pages.\n");
- via_free_sg_info(pdev, vsg);
- return ret;
- }
- via_map_blit_for_device(pdev, xfer, vsg, 1);
-
- return 0;
-}
-
-/*
- * Reserve one free slot in the blit queue. Will wait for one second for one
- * to become available. Otherwise -EBUSY is returned.
- */
-static int
-via_dmablit_grab_slot(drm_via_blitq_t *blitq, int engine)
-{
- int ret = 0;
- unsigned long irqsave;
-
- DRM_DEBUG("Num free is %d\n", blitq->num_free);
- spin_lock_irqsave(&blitq->blit_lock, irqsave);
- while (blitq->num_free == 0) {
- spin_unlock_irqrestore(&blitq->blit_lock, irqsave);
-
- VIA_WAIT_ON(ret, blitq->busy_queue, HZ, blitq->num_free > 0);
- if (ret)
- return (-EINTR == ret) ? -EAGAIN : ret;
-
- spin_lock_irqsave(&blitq->blit_lock, irqsave);
- }
-
- blitq->num_free--;
- spin_unlock_irqrestore(&blitq->blit_lock, irqsave);
-
- return 0;
-}
-
-/*
- * Hand back a free slot if we changed our mind.
- */
-static void
-via_dmablit_release_slot(drm_via_blitq_t *blitq)
-{
- unsigned long irqsave;
-
- spin_lock_irqsave(&blitq->blit_lock, irqsave);
- blitq->num_free++;
- spin_unlock_irqrestore(&blitq->blit_lock, irqsave);
- wake_up(&blitq->busy_queue);
-}
-
-/*
- * Grab a free slot. Build blit info and queue a blit.
- */
-static int
-via_dmablit(struct drm_device *dev, drm_via_dmablit_t *xfer)
-{
- drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private;
- drm_via_sg_info_t *vsg;
- drm_via_blitq_t *blitq;
- int ret;
- int engine;
- unsigned long irqsave;
-
- if (dev_priv == NULL) {
- DRM_ERROR("Called without initialization.\n");
- return -EINVAL;
- }
-
- engine = (xfer->to_fb) ? 0 : 1;
- blitq = dev_priv->blit_queues + engine;
- if (0 != (ret = via_dmablit_grab_slot(blitq, engine)))
- return ret;
- if (NULL == (vsg = kmalloc(sizeof(*vsg), GFP_KERNEL))) {
- via_dmablit_release_slot(blitq);
- return -ENOMEM;
- }
- if (0 != (ret = via_build_sg_info(dev, vsg, xfer))) {
- via_dmablit_release_slot(blitq);
- kfree(vsg);
- return ret;
- }
- spin_lock_irqsave(&blitq->blit_lock, irqsave);
-
- blitq->blits[blitq->head++] = vsg;
- if (blitq->head >= VIA_NUM_BLIT_SLOTS)
- blitq->head = 0;
- blitq->num_outstanding++;
- xfer->sync.sync_handle = ++blitq->cur_blit_handle;
-
- spin_unlock_irqrestore(&blitq->blit_lock, irqsave);
- xfer->sync.engine = engine;
-
- via_dmablit_handler(dev, engine, 0);
-
- return 0;
-}
-
-/*
- * Sync on a previously submitted blit. Note that the X server use signals extensively, and
- * that there is a very big probability that this IOCTL will be interrupted by a signal. In that
- * case it returns with -EAGAIN for the signal to be delivered.
- * The caller should then reissue the IOCTL. This is similar to what is being done for drmGetLock().
- */
-static int
-via_dma_blit_sync(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_via_blitsync_t *sync = data;
- int err;
-
- if (sync->engine >= VIA_NUM_BLIT_ENGINES)
- return -EINVAL;
-
- err = via_dmablit_sync(dev, sync->sync_handle, sync->engine);
-
- if (-EINTR == err)
- err = -EAGAIN;
-
- return err;
-}
-
-/*
- * Queue a blit and hand back a handle to be used for sync. This IOCTL may be interrupted by a signal
- * while waiting for a free slot in the blit queue. In that case it returns with -EAGAIN and should
- * be reissued. See the above IOCTL code.
- */
-static int
-via_dma_blit(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_via_dmablit_t *xfer = data;
- int err;
-
- err = via_dmablit(dev, xfer);
-
- return err;
-}
-
-static u32 via_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
-{
- drm_via_private_t *dev_priv = dev->dev_private;
-
- if (pipe != 0)
- return 0;
-
- return atomic_read(&dev_priv->vbl_received);
-}
-
-static irqreturn_t via_driver_irq_handler(int irq, void *arg)
-{
- struct drm_device *dev = (struct drm_device *) arg;
- drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
- u32 status;
- int handled = 0;
- ktime_t cur_vblank;
- drm_via_irq_t *cur_irq = dev_priv->via_irqs;
- int i;
-
- status = via_read(dev_priv, VIA_REG_INTERRUPT);
- if (status & VIA_IRQ_VBLANK_PENDING) {
- atomic_inc(&dev_priv->vbl_received);
- if (!(atomic_read(&dev_priv->vbl_received) & 0x0F)) {
- cur_vblank = ktime_get();
- if (dev_priv->last_vblank_valid) {
- dev_priv->nsec_per_vblank =
- ktime_sub(cur_vblank,
- dev_priv->last_vblank) >> 4;
- }
- dev_priv->last_vblank = cur_vblank;
- dev_priv->last_vblank_valid = 1;
- }
- if (!(atomic_read(&dev_priv->vbl_received) & 0xFF)) {
- DRM_DEBUG("nsec per vblank is: %llu\n",
- ktime_to_ns(dev_priv->nsec_per_vblank));
- }
- drm_handle_vblank(dev, 0);
- handled = 1;
- }
-
- for (i = 0; i < dev_priv->num_irqs; ++i) {
- if (status & cur_irq->pending_mask) {
- atomic_inc(&cur_irq->irq_received);
- wake_up(&cur_irq->irq_queue);
- handled = 1;
- if (dev_priv->irq_map[drm_via_irq_dma0_td] == i)
- via_dmablit_handler(dev, 0, 1);
- else if (dev_priv->irq_map[drm_via_irq_dma1_td] == i)
- via_dmablit_handler(dev, 1, 1);
- }
- cur_irq++;
- }
-
- /* Acknowledge interrupts */
- via_write(dev_priv, VIA_REG_INTERRUPT, status);
-
-
- if (handled)
- return IRQ_HANDLED;
- else
- return IRQ_NONE;
-}
-
-static __inline__ void viadrv_acknowledge_irqs(drm_via_private_t *dev_priv)
-{
- u32 status;
-
- if (dev_priv) {
- /* Acknowledge interrupts */
- status = via_read(dev_priv, VIA_REG_INTERRUPT);
- via_write(dev_priv, VIA_REG_INTERRUPT, status |
- dev_priv->irq_pending_mask);
- }
-}
-
-static int via_enable_vblank(struct drm_device *dev, unsigned int pipe)
-{
- drm_via_private_t *dev_priv = dev->dev_private;
- u32 status;
-
- if (pipe != 0) {
- DRM_ERROR("%s: bad crtc %u\n", __func__, pipe);
- return -EINVAL;
- }
-
- status = via_read(dev_priv, VIA_REG_INTERRUPT);
- via_write(dev_priv, VIA_REG_INTERRUPT, status | VIA_IRQ_VBLANK_ENABLE);
-
- via_write8(dev_priv, 0x83d4, 0x11);
- via_write8_mask(dev_priv, 0x83d5, 0x30, 0x30);
-
- return 0;
-}
-
-static void via_disable_vblank(struct drm_device *dev, unsigned int pipe)
-{
- drm_via_private_t *dev_priv = dev->dev_private;
- u32 status;
-
- status = via_read(dev_priv, VIA_REG_INTERRUPT);
- via_write(dev_priv, VIA_REG_INTERRUPT, status & ~VIA_IRQ_VBLANK_ENABLE);
-
- via_write8(dev_priv, 0x83d4, 0x11);
- via_write8_mask(dev_priv, 0x83d5, 0x30, 0);
-
- if (pipe != 0)
- DRM_ERROR("%s: bad crtc %u\n", __func__, pipe);
-}
-
-static int
-via_driver_irq_wait(struct drm_device *dev, unsigned int irq, int force_sequence,
- unsigned int *sequence)
-{
- drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
- unsigned int cur_irq_sequence;
- drm_via_irq_t *cur_irq;
- int ret = 0;
- maskarray_t *masks;
- int real_irq;
-
- DRM_DEBUG("\n");
-
- if (!dev_priv) {
- DRM_ERROR("called with no initialization\n");
- return -EINVAL;
- }
-
- if (irq >= drm_via_irq_num) {
- DRM_ERROR("Trying to wait on unknown irq %d\n", irq);
- return -EINVAL;
- }
-
- real_irq = dev_priv->irq_map[irq];
-
- if (real_irq < 0) {
- DRM_ERROR("Video IRQ %d not available on this hardware.\n",
- irq);
- return -EINVAL;
- }
-
- masks = dev_priv->irq_masks;
- cur_irq = dev_priv->via_irqs + real_irq;
-
- if (masks[real_irq][2] && !force_sequence) {
- VIA_WAIT_ON(ret, cur_irq->irq_queue, 3 * HZ,
- ((via_read(dev_priv, masks[irq][2]) & masks[irq][3]) ==
- masks[irq][4]));
- cur_irq_sequence = atomic_read(&cur_irq->irq_received);
- } else {
- VIA_WAIT_ON(ret, cur_irq->irq_queue, 3 * HZ,
- (((cur_irq_sequence =
- atomic_read(&cur_irq->irq_received)) -
- *sequence) <= (1 << 23)));
- }
- *sequence = cur_irq_sequence;
- return ret;
-}
-
-
-/*
- * drm_dma.h hooks
- */
-
-static void via_driver_irq_preinstall(struct drm_device *dev)
-{
- drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
- u32 status;
- drm_via_irq_t *cur_irq;
- int i;
-
- DRM_DEBUG("dev_priv: %p\n", dev_priv);
- if (dev_priv) {
- cur_irq = dev_priv->via_irqs;
-
- dev_priv->irq_enable_mask = VIA_IRQ_VBLANK_ENABLE;
- dev_priv->irq_pending_mask = VIA_IRQ_VBLANK_PENDING;
-
- if (dev_priv->chipset == VIA_PRO_GROUP_A ||
- dev_priv->chipset == VIA_DX9_0) {
- dev_priv->irq_masks = via_pro_group_a_irqs;
- dev_priv->num_irqs = via_num_pro_group_a;
- dev_priv->irq_map = via_irqmap_pro_group_a;
- } else {
- dev_priv->irq_masks = via_unichrome_irqs;
- dev_priv->num_irqs = via_num_unichrome;
- dev_priv->irq_map = via_irqmap_unichrome;
- }
-
- for (i = 0; i < dev_priv->num_irqs; ++i) {
- atomic_set(&cur_irq->irq_received, 0);
- cur_irq->enable_mask = dev_priv->irq_masks[i][0];
- cur_irq->pending_mask = dev_priv->irq_masks[i][1];
- init_waitqueue_head(&cur_irq->irq_queue);
- dev_priv->irq_enable_mask |= cur_irq->enable_mask;
- dev_priv->irq_pending_mask |= cur_irq->pending_mask;
- cur_irq++;
-
- DRM_DEBUG("Initializing IRQ %d\n", i);
- }
-
- dev_priv->last_vblank_valid = 0;
-
- /* Clear VSync interrupt regs */
- status = via_read(dev_priv, VIA_REG_INTERRUPT);
- via_write(dev_priv, VIA_REG_INTERRUPT, status &
- ~(dev_priv->irq_enable_mask));
-
- /* Clear bits if they're already high */
- viadrv_acknowledge_irqs(dev_priv);
- }
-}
-
-static int via_driver_irq_postinstall(struct drm_device *dev)
-{
- drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
- u32 status;
-
- DRM_DEBUG("fun: %s\n", __func__);
- if (!dev_priv)
- return -EINVAL;
-
- status = via_read(dev_priv, VIA_REG_INTERRUPT);
- via_write(dev_priv, VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL
- | dev_priv->irq_enable_mask);
-
- /* Some magic, oh for some data sheets ! */
- via_write8(dev_priv, 0x83d4, 0x11);
- via_write8_mask(dev_priv, 0x83d5, 0x30, 0x30);
-
- return 0;
-}
-
-static void via_driver_irq_uninstall(struct drm_device *dev)
-{
- drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
- u32 status;
-
- DRM_DEBUG("\n");
- if (dev_priv) {
-
- /* Some more magic, oh for some data sheets ! */
-
- via_write8(dev_priv, 0x83d4, 0x11);
- via_write8_mask(dev_priv, 0x83d5, 0x30, 0);
-
- status = via_read(dev_priv, VIA_REG_INTERRUPT);
- via_write(dev_priv, VIA_REG_INTERRUPT, status &
- ~(VIA_IRQ_VBLANK_ENABLE | dev_priv->irq_enable_mask));
- }
-}
-
-static int via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_via_irqwait_t *irqwait = data;
- struct timespec64 now;
- int ret = 0;
- drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
- drm_via_irq_t *cur_irq = dev_priv->via_irqs;
- int force_sequence;
-
- if (irqwait->request.irq >= dev_priv->num_irqs) {
- DRM_ERROR("Trying to wait on unknown irq %d\n",
- irqwait->request.irq);
- return -EINVAL;
- }
-
- cur_irq += irqwait->request.irq;
-
- switch (irqwait->request.type & ~VIA_IRQ_FLAGS_MASK) {
- case VIA_IRQ_RELATIVE:
- irqwait->request.sequence +=
- atomic_read(&cur_irq->irq_received);
- irqwait->request.type &= ~_DRM_VBLANK_RELATIVE;
- break;
- case VIA_IRQ_ABSOLUTE:
- break;
- default:
- return -EINVAL;
- }
-
- if (irqwait->request.type & VIA_IRQ_SIGNAL) {
- DRM_ERROR("Signals on Via IRQs not implemented yet.\n");
- return -EINVAL;
- }
-
- force_sequence = (irqwait->request.type & VIA_IRQ_FORCE_SEQUENCE);
-
- ret = via_driver_irq_wait(dev, irqwait->request.irq, force_sequence,
- &irqwait->request.sequence);
- ktime_get_ts64(&now);
- irqwait->reply.tval_sec = now.tv_sec;
- irqwait->reply.tval_usec = now.tv_nsec / NSEC_PER_USEC;
-
- return ret;
-}
-
-static void via_init_futex(drm_via_private_t *dev_priv)
-{
- unsigned int i;
-
- DRM_DEBUG("\n");
-
- for (i = 0; i < VIA_NR_XVMC_LOCKS; ++i) {
- init_waitqueue_head(&(dev_priv->decoder_queue[i]));
- XVMCLOCKPTR(dev_priv->sarea_priv, i)->lock = 0;
- }
-}
-
-static void via_cleanup_futex(drm_via_private_t *dev_priv)
-{
-}
-
-static void via_release_futex(drm_via_private_t *dev_priv, int context)
-{
- unsigned int i;
- volatile int *lock;
-
- if (!dev_priv->sarea_priv)
- return;
-
- for (i = 0; i < VIA_NR_XVMC_LOCKS; ++i) {
- lock = (volatile int *)XVMCLOCKPTR(dev_priv->sarea_priv, i);
- if ((_DRM_LOCKING_CONTEXT(*lock) == context)) {
- if (_DRM_LOCK_IS_HELD(*lock)
- && (*lock & _DRM_LOCK_CONT)) {
- wake_up(&(dev_priv->decoder_queue[i]));
- }
- *lock = 0;
- }
- }
-}
-
-static int via_decoder_futex(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_via_futex_t *fx = data;
- volatile int *lock;
- drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
- drm_via_sarea_t *sAPriv = dev_priv->sarea_priv;
- int ret = 0;
-
- DRM_DEBUG("\n");
-
- if (fx->lock >= VIA_NR_XVMC_LOCKS)
- return -EFAULT;
-
- lock = (volatile int *)XVMCLOCKPTR(sAPriv, fx->lock);
-
- switch (fx->func) {
- case VIA_FUTEX_WAIT:
- VIA_WAIT_ON(ret, dev_priv->decoder_queue[fx->lock],
- (fx->ms / 10) * (HZ / 100), *lock != fx->val);
- return ret;
- case VIA_FUTEX_WAKE:
- wake_up(&(dev_priv->decoder_queue[fx->lock]));
- return 0;
- }
- return 0;
-}
-
-static int via_agp_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_via_agp_t *agp = data;
- drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
-
- mutex_lock(&dev->struct_mutex);
- drm_mm_init(&dev_priv->agp_mm, 0, agp->size >> VIA_MM_ALIGN_SHIFT);
-
- dev_priv->agp_initialized = 1;
- dev_priv->agp_offset = agp->offset;
- mutex_unlock(&dev->struct_mutex);
-
- DRM_DEBUG("offset = %u, size = %u\n", agp->offset, agp->size);
- return 0;
-}
-
-static int via_fb_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_via_fb_t *fb = data;
- drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
-
- mutex_lock(&dev->struct_mutex);
- drm_mm_init(&dev_priv->vram_mm, 0, fb->size >> VIA_MM_ALIGN_SHIFT);
-
- dev_priv->vram_initialized = 1;
- dev_priv->vram_offset = fb->offset;
-
- mutex_unlock(&dev->struct_mutex);
- DRM_DEBUG("offset = %u, size = %u\n", fb->offset, fb->size);
-
- return 0;
-
-}
-
-static int via_final_context(struct drm_device *dev, int context)
-{
- drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
-
- via_release_futex(dev_priv, context);
-
- /* Linux specific until context tracking code gets ported to BSD */
- /* Last context, perform cleanup */
- if (list_is_singular(&dev->ctxlist)) {
- DRM_DEBUG("Last Context\n");
- drm_legacy_irq_uninstall(dev);
- via_cleanup_futex(dev_priv);
- via_do_cleanup_map(dev);
- }
- return 1;
-}
-
-static void via_lastclose(struct drm_device *dev)
-{
- drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
-
- if (!dev_priv)
- return;
-
- mutex_lock(&dev->struct_mutex);
- if (dev_priv->vram_initialized) {
- drm_mm_takedown(&dev_priv->vram_mm);
- dev_priv->vram_initialized = 0;
- }
- if (dev_priv->agp_initialized) {
- drm_mm_takedown(&dev_priv->agp_mm);
- dev_priv->agp_initialized = 0;
- }
- mutex_unlock(&dev->struct_mutex);
-}
-
-static int via_mem_alloc(struct drm_device *dev, void *data,
- struct drm_file *file)
-{
- drm_via_mem_t *mem = data;
- int retval = 0, user_key;
- struct via_memblock *item;
- drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
- struct via_file_private *file_priv = file->driver_priv;
- unsigned long tmpSize;
-
- if (mem->type > VIA_MEM_AGP) {
- DRM_ERROR("Unknown memory type allocation\n");
- return -EINVAL;
- }
- mutex_lock(&dev->struct_mutex);
- if (0 == ((mem->type == VIA_MEM_VIDEO) ? dev_priv->vram_initialized :
- dev_priv->agp_initialized)) {
- mutex_unlock(&dev->struct_mutex);
- DRM_ERROR
- ("Attempt to allocate from uninitialized memory manager.\n");
- return -EINVAL;
- }
-
- item = kzalloc(sizeof(*item), GFP_KERNEL);
- if (!item) {
- retval = -ENOMEM;
- goto fail_alloc;
- }
-
- tmpSize = (mem->size + VIA_MM_ALIGN_MASK) >> VIA_MM_ALIGN_SHIFT;
- if (mem->type == VIA_MEM_AGP)
- retval = drm_mm_insert_node(&dev_priv->agp_mm,
- &item->mm_node,
- tmpSize);
- else
- retval = drm_mm_insert_node(&dev_priv->vram_mm,
- &item->mm_node,
- tmpSize);
- if (retval)
- goto fail_alloc;
-
- retval = idr_alloc(&dev_priv->object_idr, item, 1, 0, GFP_KERNEL);
- if (retval < 0)
- goto fail_idr;
- user_key = retval;
-
- list_add(&item->owner_list, &file_priv->obj_list);
- mutex_unlock(&dev->struct_mutex);
-
- mem->offset = ((mem->type == VIA_MEM_VIDEO) ?
- dev_priv->vram_offset : dev_priv->agp_offset) +
- ((item->mm_node.start) << VIA_MM_ALIGN_SHIFT);
- mem->index = user_key;
-
- return 0;
-
-fail_idr:
- drm_mm_remove_node(&item->mm_node);
-fail_alloc:
- kfree(item);
- mutex_unlock(&dev->struct_mutex);
-
- mem->offset = 0;
- mem->size = 0;
- mem->index = 0;
- DRM_DEBUG("Video memory allocation failed\n");
-
- return retval;
-}
-
-static int via_mem_free(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_via_private_t *dev_priv = dev->dev_private;
- drm_via_mem_t *mem = data;
- struct via_memblock *obj;
-
- mutex_lock(&dev->struct_mutex);
- obj = idr_find(&dev_priv->object_idr, mem->index);
- if (obj == NULL) {
- mutex_unlock(&dev->struct_mutex);
- return -EINVAL;
- }
-
- idr_remove(&dev_priv->object_idr, mem->index);
- list_del(&obj->owner_list);
- drm_mm_remove_node(&obj->mm_node);
- kfree(obj);
- mutex_unlock(&dev->struct_mutex);
-
- DRM_DEBUG("free = 0x%lx\n", mem->index);
-
- return 0;
-}
-
-
-static void via_reclaim_buffers_locked(struct drm_device *dev,
- struct drm_file *file)
-{
- struct via_file_private *file_priv = file->driver_priv;
- struct via_memblock *entry, *next;
-
- if (!(dev->master && file->master->lock.hw_lock))
- return;
-
- drm_legacy_idlelock_take(&file->master->lock);
-
- mutex_lock(&dev->struct_mutex);
- if (list_empty(&file_priv->obj_list)) {
- mutex_unlock(&dev->struct_mutex);
- drm_legacy_idlelock_release(&file->master->lock);
-
- return;
- }
-
- via_driver_dma_quiescent(dev);
-
- list_for_each_entry_safe(entry, next, &file_priv->obj_list,
- owner_list) {
- list_del(&entry->owner_list);
- drm_mm_remove_node(&entry->mm_node);
- kfree(entry);
- }
- mutex_unlock(&dev->struct_mutex);
-
- drm_legacy_idlelock_release(&file->master->lock);
-
- return;
-}
-
-static int via_do_init_map(struct drm_device *dev, drm_via_init_t *init)
-{
- drm_via_private_t *dev_priv = dev->dev_private;
-
- DRM_DEBUG("\n");
-
- dev_priv->sarea = drm_legacy_getsarea(dev);
- if (!dev_priv->sarea) {
- DRM_ERROR("could not find sarea!\n");
- dev->dev_private = (void *)dev_priv;
- via_do_cleanup_map(dev);
- return -EINVAL;
- }
-
- dev_priv->fb = drm_legacy_findmap(dev, init->fb_offset);
- if (!dev_priv->fb) {
- DRM_ERROR("could not find framebuffer!\n");
- dev->dev_private = (void *)dev_priv;
- via_do_cleanup_map(dev);
- return -EINVAL;
- }
- dev_priv->mmio = drm_legacy_findmap(dev, init->mmio_offset);
- if (!dev_priv->mmio) {
- DRM_ERROR("could not find mmio region!\n");
- dev->dev_private = (void *)dev_priv;
- via_do_cleanup_map(dev);
- return -EINVAL;
- }
-
- dev_priv->sarea_priv =
- (drm_via_sarea_t *) ((u8 *) dev_priv->sarea->handle +
- init->sarea_priv_offset);
-
- dev_priv->agpAddr = init->agpAddr;
-
- via_init_futex(dev_priv);
-
- via_init_dmablit(dev);
-
- dev->dev_private = (void *)dev_priv;
- return 0;
-}
-
-int via_do_cleanup_map(struct drm_device *dev)
-{
- via_dma_cleanup(dev);
-
- return 0;
-}
-
-static int via_map_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_via_init_t *init = data;
-
- DRM_DEBUG("\n");
-
- switch (init->func) {
- case VIA_INIT_MAP:
- return via_do_init_map(dev, init);
- case VIA_CLEANUP_MAP:
- return via_do_cleanup_map(dev);
- }
-
- return -EINVAL;
-}
-
-static int via_driver_load(struct drm_device *dev, unsigned long chipset)
-{
- struct pci_dev *pdev = to_pci_dev(dev->dev);
- drm_via_private_t *dev_priv;
- int ret = 0;
-
- dev_priv = kzalloc(sizeof(drm_via_private_t), GFP_KERNEL);
- if (dev_priv == NULL)
- return -ENOMEM;
-
- idr_init_base(&dev_priv->object_idr, 1);
- dev->dev_private = (void *)dev_priv;
-
- dev_priv->chipset = chipset;
-
- pci_set_master(pdev);
-
- ret = drm_vblank_init(dev, 1);
- if (ret) {
- kfree(dev_priv);
- return ret;
- }
-
- return 0;
-}
-
-static void via_driver_unload(struct drm_device *dev)
-{
- drm_via_private_t *dev_priv = dev->dev_private;
-
- idr_destroy(&dev_priv->object_idr);
-
- kfree(dev_priv);
-}
-
-static void via_cmdbuf_start(drm_via_private_t *dev_priv);
-static void via_cmdbuf_pause(drm_via_private_t *dev_priv);
-static void via_cmdbuf_reset(drm_via_private_t *dev_priv);
-static void via_cmdbuf_rewind(drm_via_private_t *dev_priv);
-static int via_wait_idle(drm_via_private_t *dev_priv);
-static void via_pad_cache(drm_via_private_t *dev_priv, int qwords);
-
-/*
- * Free space in command buffer.
- */
-
-static uint32_t via_cmdbuf_space(drm_via_private_t *dev_priv)
-{
- uint32_t agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
- uint32_t hw_addr = *(dev_priv->hw_addr_ptr) - agp_base;
-
- return ((hw_addr <= dev_priv->dma_low) ?
- (dev_priv->dma_high + hw_addr - dev_priv->dma_low) :
- (hw_addr - dev_priv->dma_low));
-}
-
-/*
- * How much does the command regulator lag behind?
- */
-
-static uint32_t via_cmdbuf_lag(drm_via_private_t *dev_priv)
-{
- uint32_t agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
- uint32_t hw_addr = *(dev_priv->hw_addr_ptr) - agp_base;
-
- return ((hw_addr <= dev_priv->dma_low) ?
- (dev_priv->dma_low - hw_addr) :
- (dev_priv->dma_wrap + dev_priv->dma_low - hw_addr));
-}
-
-/*
- * Check that the given size fits in the buffer, otherwise wait.
- */
-
-static inline int
-via_cmdbuf_wait(drm_via_private_t *dev_priv, unsigned int size)
-{
- uint32_t agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
- uint32_t cur_addr, hw_addr, next_addr;
- volatile uint32_t *hw_addr_ptr;
- uint32_t count;
- hw_addr_ptr = dev_priv->hw_addr_ptr;
- cur_addr = dev_priv->dma_low;
- next_addr = cur_addr + size + 512 * 1024;
- count = 1000000;
- do {
- hw_addr = *hw_addr_ptr - agp_base;
- if (count-- == 0) {
- DRM_ERROR
- ("via_cmdbuf_wait timed out hw %x cur_addr %x next_addr %x\n",
- hw_addr, cur_addr, next_addr);
- return -1;
- }
- if ((cur_addr < hw_addr) && (next_addr >= hw_addr))
- msleep(1);
- } while ((cur_addr < hw_addr) && (next_addr >= hw_addr));
- return 0;
-}
-
-/*
- * Checks whether buffer head has reach the end. Rewind the ring buffer
- * when necessary.
- *
- * Returns virtual pointer to ring buffer.
- */
-
-static inline uint32_t *via_check_dma(drm_via_private_t * dev_priv,
- unsigned int size)
-{
- if ((dev_priv->dma_low + size + 4 * CMDBUF_ALIGNMENT_SIZE) >
- dev_priv->dma_high) {
- via_cmdbuf_rewind(dev_priv);
- }
- if (via_cmdbuf_wait(dev_priv, size) != 0)
- return NULL;
-
- return (uint32_t *) (dev_priv->dma_ptr + dev_priv->dma_low);
-}
-
-int via_dma_cleanup(struct drm_device *dev)
-{
- if (dev->dev_private) {
- drm_via_private_t *dev_priv =
- (drm_via_private_t *) dev->dev_private;
-
- if (dev_priv->ring.virtual_start && dev_priv->mmio) {
- via_cmdbuf_reset(dev_priv);
-
- drm_legacy_ioremapfree(&dev_priv->ring.map, dev);
- dev_priv->ring.virtual_start = NULL;
- }
-
- }
-
- return 0;
-}
-
-static int via_initialize(struct drm_device *dev,
- drm_via_private_t *dev_priv,
- drm_via_dma_init_t *init)
-{
- if (!dev_priv || !dev_priv->mmio) {
- DRM_ERROR("via_dma_init called before via_map_init\n");
- return -EFAULT;
- }
-
- if (dev_priv->ring.virtual_start != NULL) {
- DRM_ERROR("called again without calling cleanup\n");
- return -EFAULT;
- }
-
- if (!dev->agp || !dev->agp->base) {
- DRM_ERROR("called with no agp memory available\n");
- return -EFAULT;
- }
-
- if (dev_priv->chipset == VIA_DX9_0) {
- DRM_ERROR("AGP DMA is not supported on this chip\n");
- return -EINVAL;
- }
-
- dev_priv->ring.map.offset = dev->agp->base + init->offset;
- dev_priv->ring.map.size = init->size;
- dev_priv->ring.map.type = 0;
- dev_priv->ring.map.flags = 0;
- dev_priv->ring.map.mtrr = 0;
-
- drm_legacy_ioremap(&dev_priv->ring.map, dev);
-
- if (dev_priv->ring.map.handle == NULL) {
- via_dma_cleanup(dev);
- DRM_ERROR("can not ioremap virtual address for"
- " ring buffer\n");
- return -ENOMEM;
- }
-
- dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
-
- dev_priv->dma_ptr = dev_priv->ring.virtual_start;
- dev_priv->dma_low = 0;
- dev_priv->dma_high = init->size;
- dev_priv->dma_wrap = init->size;
- dev_priv->dma_offset = init->offset;
- dev_priv->last_pause_ptr = NULL;
- dev_priv->hw_addr_ptr =
- (volatile uint32_t *)((char *)dev_priv->mmio->handle +
- init->reg_pause_addr);
-
- via_cmdbuf_start(dev_priv);
-
- return 0;
-}
-
-static int via_dma_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
- drm_via_dma_init_t *init = data;
- int retcode = 0;
-
- switch (init->func) {
- case VIA_INIT_DMA:
- if (!capable(CAP_SYS_ADMIN))
- retcode = -EPERM;
- else
- retcode = via_initialize(dev, dev_priv, init);
- break;
- case VIA_CLEANUP_DMA:
- if (!capable(CAP_SYS_ADMIN))
- retcode = -EPERM;
- else
- retcode = via_dma_cleanup(dev);
- break;
- case VIA_DMA_INITIALIZED:
- retcode = (dev_priv->ring.virtual_start != NULL) ?
- 0 : -EFAULT;
- break;
- default:
- retcode = -EINVAL;
- break;
- }
-
- return retcode;
-}
-
-static int via_dispatch_cmdbuffer(struct drm_device *dev, drm_via_cmdbuffer_t *cmd)
-{
- drm_via_private_t *dev_priv;
- uint32_t *vb;
- int ret;
-
- dev_priv = (drm_via_private_t *) dev->dev_private;
-
- if (dev_priv->ring.virtual_start == NULL) {
- DRM_ERROR("called without initializing AGP ring buffer.\n");
- return -EFAULT;
- }
-
- if (cmd->size > VIA_PCI_BUF_SIZE)
- return -ENOMEM;
-
- if (copy_from_user(dev_priv->pci_buf, cmd->buf, cmd->size))
- return -EFAULT;
-
- /*
- * Running this function on AGP memory is dead slow. Therefore
- * we run it on a temporary cacheable system memory buffer and
- * copy it to AGP memory when ready.
- */
-
- if ((ret =
- via_verify_command_stream((uint32_t *) dev_priv->pci_buf,
- cmd->size, dev, 1))) {
- return ret;
- }
-
- vb = via_check_dma(dev_priv, (cmd->size < 0x100) ? 0x102 : cmd->size);
- if (vb == NULL)
- return -EAGAIN;
-
- memcpy(vb, dev_priv->pci_buf, cmd->size);
-
- dev_priv->dma_low += cmd->size;
-
- /*
- * Small submissions somehow stalls the CPU. (AGP cache effects?)
- * pad to greater size.
- */
-
- if (cmd->size < 0x100)
- via_pad_cache(dev_priv, (0x100 - cmd->size) >> 3);
- via_cmdbuf_pause(dev_priv);
-
- return 0;
-}
-
-int via_driver_dma_quiescent(struct drm_device *dev)
-{
- drm_via_private_t *dev_priv = dev->dev_private;
-
- if (!via_wait_idle(dev_priv))
- return -EBUSY;
- return 0;
-}
-
-static int via_flush_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- return via_driver_dma_quiescent(dev);
-}
-
-static int via_cmdbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_via_cmdbuffer_t *cmdbuf = data;
- int ret;
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- DRM_DEBUG("buf %p size %lu\n", cmdbuf->buf, cmdbuf->size);
-
- ret = via_dispatch_cmdbuffer(dev, cmdbuf);
- return ret;
-}
-
-static int via_dispatch_pci_cmdbuffer(struct drm_device *dev,
- drm_via_cmdbuffer_t *cmd)
-{
- drm_via_private_t *dev_priv = dev->dev_private;
- int ret;
-
- if (cmd->size > VIA_PCI_BUF_SIZE)
- return -ENOMEM;
- if (copy_from_user(dev_priv->pci_buf, cmd->buf, cmd->size))
- return -EFAULT;
-
- if ((ret =
- via_verify_command_stream((uint32_t *) dev_priv->pci_buf,
- cmd->size, dev, 0))) {
- return ret;
- }
-
- ret =
- via_parse_command_stream(dev, (const uint32_t *)dev_priv->pci_buf,
- cmd->size);
- return ret;
-}
-
-static int via_pci_cmdbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_via_cmdbuffer_t *cmdbuf = data;
- int ret;
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- DRM_DEBUG("buf %p size %lu\n", cmdbuf->buf, cmdbuf->size);
-
- ret = via_dispatch_pci_cmdbuffer(dev, cmdbuf);
- return ret;
-}
-
-static inline uint32_t *via_align_buffer(drm_via_private_t *dev_priv,
- uint32_t * vb, int qw_count)
-{
- for (; qw_count > 0; --qw_count)
- VIA_OUT_RING_QW(HC_DUMMY, HC_DUMMY);
- return vb;
-}
-
-/*
- * This function is used internally by ring buffer management code.
- *
- * Returns virtual pointer to ring buffer.
- */
-static inline uint32_t *via_get_dma(drm_via_private_t *dev_priv)
-{
- return (uint32_t *) (dev_priv->dma_ptr + dev_priv->dma_low);
-}
-
-/*
- * Hooks a segment of data into the tail of the ring-buffer by
- * modifying the pause address stored in the buffer itself. If
- * the regulator has already paused, restart it.
- */
-static int via_hook_segment(drm_via_private_t *dev_priv,
- uint32_t pause_addr_hi, uint32_t pause_addr_lo,
- int no_pci_fire)
-{
- int paused, count;
- volatile uint32_t *paused_at = dev_priv->last_pause_ptr;
- uint32_t reader, ptr;
- uint32_t diff;
-
- paused = 0;
- via_flush_write_combine();
- (void) *(volatile uint32_t *)(via_get_dma(dev_priv) - 1);
-
- *paused_at = pause_addr_lo;
- via_flush_write_combine();
- (void) *paused_at;
-
- reader = *(dev_priv->hw_addr_ptr);
- ptr = ((volatile char *)paused_at - dev_priv->dma_ptr) +
- dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4;
-
- dev_priv->last_pause_ptr = via_get_dma(dev_priv) - 1;
-
- /*
- * If there is a possibility that the command reader will
- * miss the new pause address and pause on the old one,
- * In that case we need to program the new start address
- * using PCI.
- */
-
- diff = (uint32_t) (ptr - reader) - dev_priv->dma_diff;
- count = 10000000;
- while (diff == 0 && count--) {
- paused = (via_read(dev_priv, 0x41c) & 0x80000000);
- if (paused)
- break;
- reader = *(dev_priv->hw_addr_ptr);
- diff = (uint32_t) (ptr - reader) - dev_priv->dma_diff;
- }
-
- paused = via_read(dev_priv, 0x41c) & 0x80000000;
-
- if (paused && !no_pci_fire) {
- reader = *(dev_priv->hw_addr_ptr);
- diff = (uint32_t) (ptr - reader) - dev_priv->dma_diff;
- diff &= (dev_priv->dma_high - 1);
- if (diff != 0 && diff < (dev_priv->dma_high >> 1)) {
- DRM_ERROR("Paused at incorrect address. "
- "0x%08x, 0x%08x 0x%08x\n",
- ptr, reader, dev_priv->dma_diff);
- } else if (diff == 0) {
- /*
- * There is a concern that these writes may stall the PCI bus
- * if the GPU is not idle. However, idling the GPU first
- * doesn't make a difference.
- */
-
- via_write(dev_priv, VIA_REG_TRANSET, (HC_ParaType_PreCR << 16));
- via_write(dev_priv, VIA_REG_TRANSPACE, pause_addr_hi);
- via_write(dev_priv, VIA_REG_TRANSPACE, pause_addr_lo);
- via_read(dev_priv, VIA_REG_TRANSPACE);
- }
- }
- return paused;
-}
-
-static int via_wait_idle(drm_via_private_t *dev_priv)
-{
- int count = 10000000;
-
- while (!(via_read(dev_priv, VIA_REG_STATUS) & VIA_VR_QUEUE_BUSY) && --count)
- ;
-
- while (count && (via_read(dev_priv, VIA_REG_STATUS) &
- (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY |
- VIA_3D_ENG_BUSY)))
- --count;
- return count;
-}
-
-static uint32_t *via_align_cmd(drm_via_private_t *dev_priv, uint32_t cmd_type,
- uint32_t addr, uint32_t *cmd_addr_hi,
- uint32_t *cmd_addr_lo, int skip_wait)
-{
- uint32_t agp_base;
- uint32_t cmd_addr, addr_lo, addr_hi;
- uint32_t *vb;
- uint32_t qw_pad_count;
-
- if (!skip_wait)
- via_cmdbuf_wait(dev_priv, 2 * CMDBUF_ALIGNMENT_SIZE);
-
- vb = via_get_dma(dev_priv);
- VIA_OUT_RING_QW(HC_HEADER2 | ((VIA_REG_TRANSET >> 2) << 12) |
- (VIA_REG_TRANSPACE >> 2), HC_ParaType_PreCR << 16);
- agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
- qw_pad_count = (CMDBUF_ALIGNMENT_SIZE >> 3) -
- ((dev_priv->dma_low & CMDBUF_ALIGNMENT_MASK) >> 3);
-
- cmd_addr = (addr) ? addr :
- agp_base + dev_priv->dma_low - 8 + (qw_pad_count << 3);
- addr_lo = ((HC_SubA_HAGPBpL << 24) | (cmd_type & HC_HAGPBpID_MASK) |
- (cmd_addr & HC_HAGPBpL_MASK));
- addr_hi = ((HC_SubA_HAGPBpH << 24) | (cmd_addr >> 24));
-
- vb = via_align_buffer(dev_priv, vb, qw_pad_count - 1);
- VIA_OUT_RING_QW(*cmd_addr_hi = addr_hi, *cmd_addr_lo = addr_lo);
- return vb;
-}
-
-static void via_cmdbuf_start(drm_via_private_t *dev_priv)
-{
- uint32_t pause_addr_lo, pause_addr_hi;
- uint32_t start_addr, start_addr_lo;
- uint32_t end_addr, end_addr_lo;
- uint32_t command;
- uint32_t agp_base;
- uint32_t ptr;
- uint32_t reader;
- int count;
-
- dev_priv->dma_low = 0;
-
- agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
- start_addr = agp_base;
- end_addr = agp_base + dev_priv->dma_high;
-
- start_addr_lo = ((HC_SubA_HAGPBstL << 24) | (start_addr & 0xFFFFFF));
- end_addr_lo = ((HC_SubA_HAGPBendL << 24) | (end_addr & 0xFFFFFF));
- command = ((HC_SubA_HAGPCMNT << 24) | (start_addr >> 24) |
- ((end_addr & 0xff000000) >> 16));
-
- dev_priv->last_pause_ptr =
- via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0,
- &pause_addr_hi, &pause_addr_lo, 1) - 1;
-
- via_flush_write_combine();
- (void) *(volatile uint32_t *)dev_priv->last_pause_ptr;
-
- via_write(dev_priv, VIA_REG_TRANSET, (HC_ParaType_PreCR << 16));
- via_write(dev_priv, VIA_REG_TRANSPACE, command);
- via_write(dev_priv, VIA_REG_TRANSPACE, start_addr_lo);
- via_write(dev_priv, VIA_REG_TRANSPACE, end_addr_lo);
-
- via_write(dev_priv, VIA_REG_TRANSPACE, pause_addr_hi);
- via_write(dev_priv, VIA_REG_TRANSPACE, pause_addr_lo);
- wmb();
- via_write(dev_priv, VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK);
- via_read(dev_priv, VIA_REG_TRANSPACE);
-
- dev_priv->dma_diff = 0;
-
- count = 10000000;
- while (!(via_read(dev_priv, 0x41c) & 0x80000000) && count--);
-
- reader = *(dev_priv->hw_addr_ptr);
- ptr = ((volatile char *)dev_priv->last_pause_ptr - dev_priv->dma_ptr) +
- dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4;
-
- /*
- * This is the difference between where we tell the
- * command reader to pause and where it actually pauses.
- * This differs between hw implementation so we need to
- * detect it.
- */
-
- dev_priv->dma_diff = ptr - reader;
-}
-
-static void via_pad_cache(drm_via_private_t *dev_priv, int qwords)
-{
- uint32_t *vb;
-
- via_cmdbuf_wait(dev_priv, qwords + 2);
- vb = via_get_dma(dev_priv);
- VIA_OUT_RING_QW(HC_HEADER2, HC_ParaType_NotTex << 16);
- via_align_buffer(dev_priv, vb, qwords);
-}
-
-static inline void via_dummy_bitblt(drm_via_private_t *dev_priv)
-{
- uint32_t *vb = via_get_dma(dev_priv);
- SetReg2DAGP(0x0C, (0 | (0 << 16)));
- SetReg2DAGP(0x10, 0 | (0 << 16));
- SetReg2DAGP(0x0, 0x1 | 0x2000 | 0xAA000000);
-}
-
-static void via_cmdbuf_jump(drm_via_private_t *dev_priv)
-{
- uint32_t pause_addr_lo, pause_addr_hi;
- uint32_t jump_addr_lo, jump_addr_hi;
- volatile uint32_t *last_pause_ptr;
- uint32_t dma_low_save1, dma_low_save2;
-
- via_align_cmd(dev_priv, HC_HAGPBpID_JUMP, 0, &jump_addr_hi,
- &jump_addr_lo, 0);
-
- dev_priv->dma_wrap = dev_priv->dma_low;
-
- /*
- * Wrap command buffer to the beginning.
- */
-
- dev_priv->dma_low = 0;
- if (via_cmdbuf_wait(dev_priv, CMDBUF_ALIGNMENT_SIZE) != 0)
- DRM_ERROR("via_cmdbuf_jump failed\n");
-
- via_dummy_bitblt(dev_priv);
- via_dummy_bitblt(dev_priv);
-
- last_pause_ptr =
- via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi,
- &pause_addr_lo, 0) - 1;
- via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi,
- &pause_addr_lo, 0);
-
- *last_pause_ptr = pause_addr_lo;
- dma_low_save1 = dev_priv->dma_low;
-
- /*
- * Now, set a trap that will pause the regulator if it tries to rerun the old
- * command buffer. (Which may happen if via_hook_segment detecs a command regulator pause
- * and reissues the jump command over PCI, while the regulator has already taken the jump
- * and actually paused at the current buffer end).
- * There appears to be no other way to detect this condition, since the hw_addr_pointer
- * does not seem to get updated immediately when a jump occurs.
- */
-
- last_pause_ptr =
- via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi,
- &pause_addr_lo, 0) - 1;
- via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi,
- &pause_addr_lo, 0);
- *last_pause_ptr = pause_addr_lo;
-
- dma_low_save2 = dev_priv->dma_low;
- dev_priv->dma_low = dma_low_save1;
- via_hook_segment(dev_priv, jump_addr_hi, jump_addr_lo, 0);
- dev_priv->dma_low = dma_low_save2;
- via_hook_segment(dev_priv, pause_addr_hi, pause_addr_lo, 0);
-}
-
-
-static void via_cmdbuf_rewind(drm_via_private_t *dev_priv)
-{
- via_cmdbuf_jump(dev_priv);
-}
-
-static void via_cmdbuf_flush(drm_via_private_t *dev_priv, uint32_t cmd_type)
-{
- uint32_t pause_addr_lo, pause_addr_hi;
-
- via_align_cmd(dev_priv, cmd_type, 0, &pause_addr_hi, &pause_addr_lo, 0);
- via_hook_segment(dev_priv, pause_addr_hi, pause_addr_lo, 0);
-}
-
-static void via_cmdbuf_pause(drm_via_private_t *dev_priv)
-{
- via_cmdbuf_flush(dev_priv, HC_HAGPBpID_PAUSE);
-}
-
-static void via_cmdbuf_reset(drm_via_private_t *dev_priv)
-{
- via_cmdbuf_flush(dev_priv, HC_HAGPBpID_STOP);
- via_wait_idle(dev_priv);
-}
-
-/*
- * User interface to the space and lag functions.
- */
-
-static int via_cmdbuf_size(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
- drm_via_cmdbuf_size_t *d_siz = data;
- int ret = 0;
- uint32_t tmp_size, count;
- drm_via_private_t *dev_priv;
-
- DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- dev_priv = (drm_via_private_t *) dev->dev_private;
-
- if (dev_priv->ring.virtual_start == NULL) {
- DRM_ERROR("called without initializing AGP ring buffer.\n");
- return -EFAULT;
- }
-
- count = 1000000;
- tmp_size = d_siz->size;
- switch (d_siz->func) {
- case VIA_CMDBUF_SPACE:
- while (((tmp_size = via_cmdbuf_space(dev_priv)) < d_siz->size)
- && --count) {
- if (!d_siz->wait)
- break;
- }
- if (!count) {
- DRM_ERROR("VIA_CMDBUF_SPACE timed out.\n");
- ret = -EAGAIN;
- }
- break;
- case VIA_CMDBUF_LAG:
- while (((tmp_size = via_cmdbuf_lag(dev_priv)) > d_siz->size)
- && --count) {
- if (!d_siz->wait)
- break;
- }
- if (!count) {
- DRM_ERROR("VIA_CMDBUF_LAG timed out.\n");
- ret = -EAGAIN;
- }
- break;
- default:
- ret = -EFAULT;
- }
- d_siz->size = tmp_size;
-
- return ret;
-}
-
-static const struct drm_ioctl_desc via_ioctls[] = {
- DRM_IOCTL_DEF_DRV(VIA_ALLOCMEM, via_mem_alloc, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(VIA_FREEMEM, via_mem_free, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(VIA_AGP_INIT, via_agp_init, DRM_AUTH|DRM_MASTER),
- DRM_IOCTL_DEF_DRV(VIA_FB_INIT, via_fb_init, DRM_AUTH|DRM_MASTER),
- DRM_IOCTL_DEF_DRV(VIA_MAP_INIT, via_map_init, DRM_AUTH|DRM_MASTER),
- DRM_IOCTL_DEF_DRV(VIA_DEC_FUTEX, via_decoder_futex, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(VIA_DMA_INIT, via_dma_init, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(VIA_CMDBUFFER, via_cmdbuffer, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(VIA_FLUSH, via_flush_ioctl, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(VIA_PCICMD, via_pci_cmdbuffer, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(VIA_CMDBUF_SIZE, via_cmdbuf_size, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(VIA_WAIT_IRQ, via_wait_irq, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(VIA_DMA_BLIT, via_dma_blit, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(VIA_BLIT_SYNC, via_dma_blit_sync, DRM_AUTH)
-};
-
-static int via_max_ioctl = ARRAY_SIZE(via_ioctls);
-static int via_driver_open(struct drm_device *dev, struct drm_file *file)
-{
- struct via_file_private *file_priv;
-
- DRM_DEBUG_DRIVER("\n");
- file_priv = kmalloc(sizeof(*file_priv), GFP_KERNEL);
- if (!file_priv)
- return -ENOMEM;
-
- file->driver_priv = file_priv;
-
- INIT_LIST_HEAD(&file_priv->obj_list);
-
- return 0;
-}
-
-static void via_driver_postclose(struct drm_device *dev, struct drm_file *file)
-{
- struct via_file_private *file_priv = file->driver_priv;
-
- kfree(file_priv);
-}
-
-static struct pci_device_id pciidlist[] = {
- viadrv_PCI_IDS
-};
-
-static const struct file_operations via_driver_fops = {
- .owner = THIS_MODULE,
- .open = drm_open,
- .release = drm_release,
- .unlocked_ioctl = drm_ioctl,
- .mmap = drm_legacy_mmap,
- .poll = drm_poll,
- .compat_ioctl = drm_compat_ioctl,
- .llseek = noop_llseek,
-};
-
-static struct drm_driver driver = {
- .driver_features =
- DRIVER_USE_AGP | DRIVER_HAVE_IRQ | DRIVER_LEGACY,
- .load = via_driver_load,
- .unload = via_driver_unload,
- .open = via_driver_open,
- .preclose = via_reclaim_buffers_locked,
- .postclose = via_driver_postclose,
- .context_dtor = via_final_context,
- .get_vblank_counter = via_get_vblank_counter,
- .enable_vblank = via_enable_vblank,
- .disable_vblank = via_disable_vblank,
- .irq_preinstall = via_driver_irq_preinstall,
- .irq_postinstall = via_driver_irq_postinstall,
- .irq_uninstall = via_driver_irq_uninstall,
- .irq_handler = via_driver_irq_handler,
- .dma_quiescent = via_driver_dma_quiescent,
- .lastclose = via_lastclose,
- .ioctls = via_ioctls,
- .fops = &via_driver_fops,
- .name = DRIVER_NAME,
- .desc = DRIVER_DESC,
- .date = DRIVER_DATE,
- .major = DRIVER_MAJOR,
- .minor = DRIVER_MINOR,
- .patchlevel = DRIVER_PATCHLEVEL,
-};
-
-static struct pci_driver via_pci_driver = {
- .name = DRIVER_NAME,
- .id_table = pciidlist,
-};
-
-static int __init via_init(void)
-{
- driver.num_ioctls = via_max_ioctl;
- via_init_command_verifier();
- return drm_legacy_pci_init(&driver, &via_pci_driver);
-}
-
-static void __exit via_exit(void)
-{
- drm_legacy_pci_exit(&driver, &via_pci_driver);
-}
-
-module_init(via_init);
-module_exit(via_exit);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h
index b7a64c7dcc2c..af6ffb696086 100644
--- a/drivers/gpu/drm/virtio/virtgpu_drv.h
+++ b/drivers/gpu/drm/virtio/virtgpu_drv.h
@@ -165,6 +165,8 @@ struct virtio_gpu_vbuffer {
struct virtio_gpu_object_array *objs;
struct list_head list;
+
+ uint32_t seqno;
};
struct virtio_gpu_output {
@@ -194,6 +196,7 @@ struct virtio_gpu_queue {
spinlock_t qlock;
wait_queue_head_t ack_queue;
struct work_struct dequeue_work;
+ uint32_t seqno;
};
struct virtio_gpu_drv_capset {
diff --git a/drivers/gpu/drm/virtio/virtgpu_trace.h b/drivers/gpu/drm/virtio/virtgpu_trace.h
index 711ecc2bd241..031bc77689d5 100644
--- a/drivers/gpu/drm/virtio/virtgpu_trace.h
+++ b/drivers/gpu/drm/virtio/virtgpu_trace.h
@@ -9,40 +9,44 @@
#define TRACE_INCLUDE_FILE virtgpu_trace
DECLARE_EVENT_CLASS(virtio_gpu_cmd,
- TP_PROTO(struct virtqueue *vq, struct virtio_gpu_ctrl_hdr *hdr),
- TP_ARGS(vq, hdr),
+ TP_PROTO(struct virtqueue *vq, struct virtio_gpu_ctrl_hdr *hdr, u32 seqno),
+ TP_ARGS(vq, hdr, seqno),
TP_STRUCT__entry(
__field(int, dev)
__field(unsigned int, vq)
- __field(const char *, name)
+ __string(name, vq->name)
__field(u32, type)
__field(u32, flags)
__field(u64, fence_id)
__field(u32, ctx_id)
+ __field(u32, num_free)
+ __field(u32, seqno)
),
TP_fast_assign(
__entry->dev = vq->vdev->index;
__entry->vq = vq->index;
- __entry->name = vq->name;
+ __assign_str(name, vq->name);
__entry->type = le32_to_cpu(hdr->type);
__entry->flags = le32_to_cpu(hdr->flags);
__entry->fence_id = le64_to_cpu(hdr->fence_id);
__entry->ctx_id = le32_to_cpu(hdr->ctx_id);
+ __entry->num_free = vq->num_free;
+ __entry->seqno = seqno;
),
- TP_printk("vdev=%d vq=%u name=%s type=0x%x flags=0x%x fence_id=%llu ctx_id=%u",
- __entry->dev, __entry->vq, __entry->name,
+ TP_printk("vdev=%d vq=%u name=%s type=0x%x flags=0x%x fence_id=%llu ctx_id=%u num_free=%u seqno=%u",
+ __entry->dev, __entry->vq, __get_str(name),
__entry->type, __entry->flags, __entry->fence_id,
- __entry->ctx_id)
+ __entry->ctx_id, __entry->num_free, __entry->seqno)
);
DEFINE_EVENT(virtio_gpu_cmd, virtio_gpu_cmd_queue,
- TP_PROTO(struct virtqueue *vq, struct virtio_gpu_ctrl_hdr *hdr),
- TP_ARGS(vq, hdr)
+ TP_PROTO(struct virtqueue *vq, struct virtio_gpu_ctrl_hdr *hdr, u32 seqno),
+ TP_ARGS(vq, hdr, seqno)
);
DEFINE_EVENT(virtio_gpu_cmd, virtio_gpu_cmd_response,
- TP_PROTO(struct virtqueue *vq, struct virtio_gpu_ctrl_hdr *hdr),
- TP_ARGS(vq, hdr)
+ TP_PROTO(struct virtqueue *vq, struct virtio_gpu_ctrl_hdr *hdr, u32 seqno),
+ TP_ARGS(vq, hdr, seqno)
);
#endif
diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c
index 9ff8660b50ad..a04a9b20896d 100644
--- a/drivers/gpu/drm/virtio/virtgpu_vq.c
+++ b/drivers/gpu/drm/virtio/virtgpu_vq.c
@@ -215,7 +215,7 @@ void virtio_gpu_dequeue_ctrl_func(struct work_struct *work)
list_for_each_entry(entry, &reclaim_list, list) {
resp = (struct virtio_gpu_ctrl_hdr *)entry->resp_buf;
- trace_virtio_gpu_cmd_response(vgdev->ctrlq.vq, resp);
+ trace_virtio_gpu_cmd_response(vgdev->ctrlq.vq, resp, entry->seqno);
if (resp->type != cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA)) {
if (le32_to_cpu(resp->type) >= VIRTIO_GPU_RESP_ERR_UNSPEC) {
@@ -261,6 +261,10 @@ void virtio_gpu_dequeue_cursor_func(struct work_struct *work)
spin_unlock(&vgdev->cursorq.qlock);
list_for_each_entry_safe(entry, tmp, &reclaim_list, list) {
+ struct virtio_gpu_ctrl_hdr *resp =
+ (struct virtio_gpu_ctrl_hdr *)entry->resp_buf;
+
+ trace_virtio_gpu_cmd_response(vgdev->cursorq.vq, resp, entry->seqno);
list_del(&entry->list);
free_vbuf(vgdev, entry);
}
@@ -353,7 +357,8 @@ again:
ret = virtqueue_add_sgs(vq, sgs, outcnt, incnt, vbuf, GFP_ATOMIC);
WARN_ON(ret);
- trace_virtio_gpu_cmd_queue(vq, virtio_gpu_vbuf_ctrl_hdr(vbuf));
+ vbuf->seqno = ++vgdev->ctrlq.seqno;
+ trace_virtio_gpu_cmd_queue(vq, virtio_gpu_vbuf_ctrl_hdr(vbuf), vbuf->seqno);
atomic_inc(&vgdev->pending_commands);
@@ -465,8 +470,10 @@ retry:
spin_lock(&vgdev->cursorq.qlock);
goto retry;
} else {
+ vbuf->seqno = ++vgdev->cursorq.seqno;
trace_virtio_gpu_cmd_queue(vq,
- virtio_gpu_vbuf_ctrl_hdr(vbuf));
+ virtio_gpu_vbuf_ctrl_hdr(vbuf),
+ vbuf->seqno);
notify = virtqueue_kick_prepare(vq);
}
diff --git a/drivers/gpu/drm/virtio/virtgpu_vram.c b/drivers/gpu/drm/virtio/virtgpu_vram.c
index 6b45b0429fef..25df81c02783 100644
--- a/drivers/gpu/drm/virtio/virtgpu_vram.c
+++ b/drivers/gpu/drm/virtio/virtgpu_vram.c
@@ -46,7 +46,7 @@ static int virtio_gpu_vram_mmap(struct drm_gem_object *obj,
return -EINVAL;
vma->vm_pgoff -= drm_vma_node_start(&obj->vma_node);
- vma->vm_flags |= VM_MIXEDMAP | VM_DONTEXPAND;
+ vm_flags_set(vma, VM_MIXEDMAP | VM_DONTEXPAND);
vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
vma->vm_ops = &virtio_gpu_vram_vm_ops;
diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c
index 293dbca50c31..6d3a2d57d992 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.c
+++ b/drivers/gpu/drm/vkms/vkms_drv.c
@@ -57,7 +57,8 @@ static void vkms_release(struct drm_device *dev)
{
struct vkms_device *vkms = drm_device_to_vkms_device(dev);
- destroy_workqueue(vkms->output.composer_workq);
+ if (vkms->output.composer_workq)
+ destroy_workqueue(vkms->output.composer_workq);
}
static void vkms_atomic_commit_tail(struct drm_atomic_state *old_state)
@@ -91,8 +92,8 @@ static void vkms_atomic_commit_tail(struct drm_atomic_state *old_state)
static int vkms_config_show(struct seq_file *m, void *data)
{
- struct drm_info_node *node = (struct drm_info_node *)m->private;
- struct drm_device *dev = node->minor->dev;
+ struct drm_debugfs_entry *entry = m->private;
+ struct drm_device *dev = entry->dev;
struct vkms_device *vkmsdev = drm_device_to_vkms_device(dev);
seq_printf(m, "writeback=%d\n", vkmsdev->config->writeback);
@@ -102,24 +103,16 @@ static int vkms_config_show(struct seq_file *m, void *data)
return 0;
}
-static const struct drm_info_list vkms_config_debugfs_list[] = {
+static const struct drm_debugfs_info vkms_config_debugfs_list[] = {
{ "vkms_config", vkms_config_show, 0 },
};
-static void vkms_config_debugfs_init(struct drm_minor *minor)
-{
- drm_debugfs_create_files(vkms_config_debugfs_list, ARRAY_SIZE(vkms_config_debugfs_list),
- minor->debugfs_root, minor);
-}
-
static const struct drm_driver vkms_driver = {
.driver_features = DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_GEM,
.release = vkms_release,
.fops = &vkms_driver_fops,
DRM_GEM_SHMEM_DRIVER_OPS,
- .debugfs_init = vkms_config_debugfs_init,
-
.name = DRIVER_NAME,
.desc = DRIVER_DESC,
.date = DRIVER_DATE,
@@ -201,6 +194,9 @@ static int vkms_create(struct vkms_config *config)
if (ret)
goto out_devres;
+ drm_debugfs_add_files(&vkms_device->drm, vkms_config_debugfs_list,
+ ARRAY_SIZE(vkms_config_debugfs_list));
+
ret = drm_dev_register(&vkms_device->drm, 0);
if (ret)
goto out_devres;
@@ -218,6 +214,7 @@ out_unregister:
static int __init vkms_init(void)
{
+ int ret;
struct vkms_config *config;
config = kmalloc(sizeof(*config), GFP_KERNEL);
@@ -230,7 +227,11 @@ static int __init vkms_init(void)
config->writeback = enable_writeback;
config->overlay = enable_overlay;
- return vkms_create(config);
+ ret = vkms_create(config);
+ if (ret)
+ kfree(config);
+
+ return ret;
}
static void vkms_destroy(struct vkms_config *config)
diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h
index 0a67b8073f7e..4a248567efb2 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.h
+++ b/drivers/gpu/drm/vkms/vkms_drv.h
@@ -12,8 +12,8 @@
#include <drm/drm_encoder.h>
#include <drm/drm_writeback.h>
-#define XRES_MIN 20
-#define YRES_MIN 20
+#define XRES_MIN 10
+#define YRES_MIN 10
#define XRES_DEF 1024
#define YRES_DEF 768
diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_plane.c
index c3a845220e10..b3f8a115cc23 100644
--- a/drivers/gpu/drm/vkms/vkms_plane.c
+++ b/drivers/gpu/drm/vkms/vkms_plane.c
@@ -160,10 +160,44 @@ static int vkms_plane_atomic_check(struct drm_plane *plane,
return 0;
}
+static int vkms_prepare_fb(struct drm_plane *plane,
+ struct drm_plane_state *state)
+{
+ struct drm_shadow_plane_state *shadow_plane_state;
+ struct drm_framebuffer *fb = state->fb;
+ int ret;
+
+ if (!fb)
+ return 0;
+
+ shadow_plane_state = to_drm_shadow_plane_state(state);
+
+ ret = drm_gem_plane_helper_prepare_fb(plane, state);
+ if (ret)
+ return ret;
+
+ return drm_gem_fb_vmap(fb, shadow_plane_state->map, shadow_plane_state->data);
+}
+
+static void vkms_cleanup_fb(struct drm_plane *plane,
+ struct drm_plane_state *state)
+{
+ struct drm_shadow_plane_state *shadow_plane_state;
+ struct drm_framebuffer *fb = state->fb;
+
+ if (!fb)
+ return;
+
+ shadow_plane_state = to_drm_shadow_plane_state(state);
+
+ drm_gem_fb_vunmap(fb, shadow_plane_state->map);
+}
+
static const struct drm_plane_helper_funcs vkms_primary_helper_funcs = {
.atomic_update = vkms_plane_atomic_update,
.atomic_check = vkms_plane_atomic_check,
- DRM_GEM_SHADOW_PLANE_HELPER_FUNCS,
+ .prepare_fb = vkms_prepare_fb,
+ .cleanup_fb = vkms_cleanup_fb,
};
struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev,
diff --git a/drivers/gpu/drm/vmwgfx/ttm_object.h b/drivers/gpu/drm/vmwgfx/ttm_object.h
index 8098a3846bae..e6b77ee33e55 100644
--- a/drivers/gpu/drm/vmwgfx/ttm_object.h
+++ b/drivers/gpu/drm/vmwgfx/ttm_object.h
@@ -42,6 +42,8 @@
#include <linux/list.h>
#include <linux/rcupdate.h>
+#include <drm/ttm/ttm_bo.h>
+
/**
* enum ttm_object_type
*
@@ -307,4 +309,12 @@ extern int ttm_prime_handle_to_fd(struct ttm_object_file *tfile,
#define ttm_prime_object_kfree(__obj, __prime) \
kfree_rcu(__obj, __prime.base.rhead)
+static inline int ttm_bo_wait(struct ttm_buffer_object *bo, bool intr,
+ bool no_wait)
+{
+ struct ttm_operation_ctx ctx = { intr, no_wait };
+
+ return ttm_bo_wait_ctx(bo, &ctx);
+}
+
#endif
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c
index 3c06df2a5474..2b843ff4b437 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c
@@ -28,7 +28,7 @@
#include <linux/dmapool.h>
#include <linux/pci.h>
-#include <drm/ttm/ttm_bo_api.h>
+#include <drm/ttm/ttm_bo.h>
#include "vmwgfx_drv.h"
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index bd02cb0e6837..9ad28346aff7 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -40,7 +40,6 @@
#include <drm/drm_ioctl.h>
#include <drm/drm_module.h>
#include <drm/drm_sysfs.h>
-#include <drm/ttm/ttm_bo_driver.h>
#include <drm/ttm/ttm_range_manager.h>
#include <drm/ttm/ttm_placement.h>
#include <generated/utsrelease.h>
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index 5acbf5849b27..203fa32cd4c1 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -37,8 +37,10 @@
#include <drm/drm_file.h>
#include <drm/drm_rect.h>
-#include <drm/ttm/ttm_bo_driver.h>
#include <drm/ttm/ttm_execbuf_util.h>
+#include <drm/ttm/ttm_tt.h>
+#include <drm/ttm/ttm_placement.h>
+#include <drm/ttm/ttm_bo.h>
#include "ttm_object.h"
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
index c0686283ffd1..0590bb22c73a 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
@@ -29,7 +29,7 @@
#include "vmwgfx_drv.h"
#include "vmwgfx_reg.h"
-#include <drm/ttm/ttm_bo_api.h>
+#include <drm/ttm/ttm_bo.h>
#include <drm/ttm/ttm_placement.h>
#include "vmwgfx_so.h"
#include "vmwgfx_binding.h"
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c b/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c
index c482e5298e11..20158a92acc7 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c
@@ -25,7 +25,6 @@
*
**************************************************************************/
-#include <drm/ttm/ttm_bo_driver.h>
#include "vmwgfx_drv.h"
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c b/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c
index abd5e3323ebf..ceb4d3d3b965 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c
@@ -29,7 +29,6 @@
*/
#include "vmwgfx_drv.h"
-#include <drm/ttm/ttm_bo_driver.h>
#include <drm/ttm/ttm_placement.h>
#include <linux/idr.h>
#include <linux/spinlock.h>
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_system_manager.c b/drivers/gpu/drm/vmwgfx/vmwgfx_system_manager.c
index d3007bf1b8f5..ee7964cbdaca 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_system_manager.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_system_manager.c
@@ -26,7 +26,6 @@
#include "vmwgfx_drv.h"
-#include <drm/ttm/ttm_bo_driver.h>
#include <drm/ttm/ttm_device.h>
#include <drm/ttm/ttm_placement.h>
#include <drm/ttm/ttm_resource.h>
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c
index 4e3938e62c08..856a352a72a6 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c
@@ -26,7 +26,6 @@
**************************************************************************/
#include "vmwgfx_drv.h"
-#include <drm/ttm/ttm_bo_driver.h>
#include <drm/ttm/ttm_placement.h>
static const struct ttm_place vram_placement_flags = {
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c
index 265f7c48d856..90097d04b45f 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c
@@ -97,7 +97,7 @@ int vmw_mmap(struct file *filp, struct vm_area_struct *vma)
/* Use VM_PFNMAP rather than VM_MIXEDMAP if not a COW mapping */
if (!is_cow_mapping(vma->vm_flags))
- vma->vm_flags = (vma->vm_flags & ~VM_MIXEDMAP) | VM_PFNMAP;
+ vm_flags_mod(vma, VM_PFNMAP, VM_MIXEDMAP);
ttm_bo_put(bo); /* release extra ref taken by ttm_bo_mmap_obj() */
diff --git a/drivers/gpu/drm/xen/xen_drm_front_gem.c b/drivers/gpu/drm/xen/xen_drm_front_gem.c
index 4c95ebcdcc2d..3ad2b4cfd1f0 100644
--- a/drivers/gpu/drm/xen/xen_drm_front_gem.c
+++ b/drivers/gpu/drm/xen/xen_drm_front_gem.c
@@ -69,8 +69,7 @@ static int xen_drm_front_gem_object_mmap(struct drm_gem_object *gem_obj,
* vm_pgoff (used as a fake buffer offset by DRM) to 0 as we want to map
* the whole buffer.
*/
- vma->vm_flags &= ~VM_PFNMAP;
- vma->vm_flags |= VM_MIXEDMAP | VM_DONTEXPAND;
+ vm_flags_mod(vma, VM_MIXEDMAP | VM_DONTEXPAND, VM_PFNMAP);
vma->vm_pgoff = 0;
/*
diff --git a/drivers/gpu/host1x/bus.c b/drivers/gpu/host1x/bus.c
index bdee16a0bb8e..bc7271a00a94 100644
--- a/drivers/gpu/host1x/bus.c
+++ b/drivers/gpu/host1x/bus.c
@@ -338,7 +338,7 @@ static int host1x_device_match(struct device *dev, struct device_driver *drv)
return strcmp(dev_name(dev), drv->name) == 0;
}
-static int host1x_device_uevent(struct device *dev,
+static int host1x_device_uevent(const struct device *dev,
struct kobj_uevent_env *env)
{
struct device_node *np = dev->parent->of_node;
diff --git a/drivers/gpu/host1x/cdma.c b/drivers/gpu/host1x/cdma.c
index 103fda055394..d1336e438f4f 100644
--- a/drivers/gpu/host1x/cdma.c
+++ b/drivers/gpu/host1x/cdma.c
@@ -105,7 +105,7 @@ static int host1x_pushbuffer_init(struct push_buffer *pb)
pb->dma = iova_dma_addr(&host1x->iova, alloc);
err = iommu_map(host1x->domain, pb->dma, pb->phys, size,
- IOMMU_READ);
+ IOMMU_READ, GFP_KERNEL);
if (err)
goto iommu_free_iova;
} else {
@@ -490,6 +490,15 @@ resume:
host1x_hw_cdma_resume(host1x, cdma, restart_addr);
}
+static void cdma_update_work(struct work_struct *work)
+{
+ struct host1x_cdma *cdma = container_of(work, struct host1x_cdma, update_work);
+
+ mutex_lock(&cdma->lock);
+ update_cdma_locked(cdma);
+ mutex_unlock(&cdma->lock);
+}
+
/*
* Create a cdma
*/
@@ -499,6 +508,7 @@ int host1x_cdma_init(struct host1x_cdma *cdma)
mutex_init(&cdma->lock);
init_completion(&cdma->complete);
+ INIT_WORK(&cdma->update_work, cdma_update_work);
INIT_LIST_HEAD(&cdma->sync_queue);
@@ -679,7 +689,5 @@ void host1x_cdma_end(struct host1x_cdma *cdma,
*/
void host1x_cdma_update(struct host1x_cdma *cdma)
{
- mutex_lock(&cdma->lock);
- update_cdma_locked(cdma);
- mutex_unlock(&cdma->lock);
+ schedule_work(&cdma->update_work);
}
diff --git a/drivers/gpu/host1x/cdma.h b/drivers/gpu/host1x/cdma.h
index 12c4327c4df0..7fd8168af4f9 100644
--- a/drivers/gpu/host1x/cdma.h
+++ b/drivers/gpu/host1x/cdma.h
@@ -11,6 +11,7 @@
#include <linux/sched.h>
#include <linux/completion.h>
#include <linux/list.h>
+#include <linux/workqueue.h>
struct host1x_syncpt;
struct host1x_userctx_timeout;
@@ -69,6 +70,7 @@ struct host1x_cdma {
struct buffer_timeout timeout; /* channel's timeout state/wq */
bool running;
bool torndown;
+ struct work_struct update_work;
};
#define cdma_to_channel(cdma) container_of(cdma, struct host1x_channel, cdma)
diff --git a/drivers/gpu/host1x/context.c b/drivers/gpu/host1x/context.c
index c8e7994c2c9c..8beedcf080ab 100644
--- a/drivers/gpu/host1x/context.c
+++ b/drivers/gpu/host1x/context.c
@@ -35,8 +35,6 @@ int host1x_memory_context_list_init(struct host1x *host1x)
cdl->len = err / 4;
for (i = 0; i < cdl->len; i++) {
- struct iommu_fwspec *fwspec;
-
ctx = &cdl->devs[i];
ctx->host = host1x;
@@ -70,14 +68,12 @@ int host1x_memory_context_list_init(struct host1x *host1x)
goto del_devices;
}
- fwspec = dev_iommu_fwspec_get(&ctx->dev);
- if (!fwspec || !device_iommu_mapped(&ctx->dev)) {
+ if (!tegra_dev_iommu_get_stream_id(&ctx->dev, &ctx->stream_id) ||
+ !device_iommu_mapped(&ctx->dev)) {
dev_err(host1x->dev, "Context device %d has no IOMMU!\n", i);
device_del(&ctx->dev);
goto del_devices;
}
-
- ctx->stream_id = fwspec->ids[0] & 0xffff;
}
return 0;
diff --git a/drivers/gpu/host1x/debug.c b/drivers/gpu/host1x/debug.c
index 6649b04b7131..a18cc8d8caf5 100644
--- a/drivers/gpu/host1x/debug.c
+++ b/drivers/gpu/host1x/debug.c
@@ -77,6 +77,7 @@ static int show_channel(struct host1x_channel *ch, void *data, bool show_fifo)
static void show_syncpts(struct host1x *m, struct output *o, bool show_all)
{
+ unsigned long irqflags;
struct list_head *pos;
unsigned int i;
int err;
@@ -92,10 +93,10 @@ static void show_syncpts(struct host1x *m, struct output *o, bool show_all)
u32 min = host1x_syncpt_load(m->syncpt + i);
unsigned int waiters = 0;
- spin_lock(&m->syncpt[i].intr.lock);
- list_for_each(pos, &m->syncpt[i].intr.wait_head)
+ spin_lock_irqsave(&m->syncpt[i].fences.lock, irqflags);
+ list_for_each(pos, &m->syncpt[i].fences.list)
waiters++;
- spin_unlock(&m->syncpt[i].intr.lock);
+ spin_unlock_irqrestore(&m->syncpt[i].fences.lock, irqflags);
if (!kref_read(&m->syncpt[i].ref))
continue;
diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c
index f31039aca03c..4872d183d860 100644
--- a/drivers/gpu/host1x/dev.c
+++ b/drivers/gpu/host1x/dev.c
@@ -516,7 +516,7 @@ static int host1x_probe(struct platform_device *pdev)
return PTR_ERR(host->regs);
}
- syncpt_irq = platform_get_irq(pdev, 0);
+ host->syncpt_irq = platform_get_irq(pdev, 0);
if (syncpt_irq < 0)
return syncpt_irq;
@@ -578,7 +578,7 @@ static int host1x_probe(struct platform_device *pdev)
goto free_contexts;
}
- err = host1x_intr_init(host, syncpt_irq);
+ err = host1x_intr_init(host);
if (err) {
dev_err(&pdev->dev, "failed to initialize interrupts\n");
goto deinit_syncpt;
diff --git a/drivers/gpu/host1x/dev.h b/drivers/gpu/host1x/dev.h
index 920e5548cfbc..75de50fe03d0 100644
--- a/drivers/gpu/host1x/dev.h
+++ b/drivers/gpu/host1x/dev.h
@@ -74,8 +74,7 @@ struct host1x_syncpt_ops {
};
struct host1x_intr_ops {
- int (*init_host_sync)(struct host1x *host, u32 cpm,
- void (*syncpt_thresh_work)(struct work_struct *work));
+ int (*init_host_sync)(struct host1x *host, u32 cpm);
void (*set_syncpt_threshold)(
struct host1x *host, unsigned int id, u32 thresh);
void (*enable_syncpt_intr)(struct host1x *host, unsigned int id);
@@ -125,6 +124,7 @@ struct host1x {
void __iomem *regs;
void __iomem *hv_regs; /* hypervisor region */
void __iomem *common_regs;
+ int syncpt_irq;
struct host1x_syncpt *syncpt;
struct host1x_syncpt_base *bases;
struct device *dev;
@@ -138,7 +138,6 @@ struct host1x {
dma_addr_t iova_end;
struct mutex intr_mutex;
- int intr_syncpt_irq;
const struct host1x_syncpt_ops *syncpt_op;
const struct host1x_intr_ops *intr_op;
@@ -216,10 +215,9 @@ static inline void host1x_hw_syncpt_enable_protection(struct host1x *host)
return host->syncpt_op->enable_protection(host);
}
-static inline int host1x_hw_intr_init_host_sync(struct host1x *host, u32 cpm,
- void (*syncpt_thresh_work)(struct work_struct *))
+static inline int host1x_hw_intr_init_host_sync(struct host1x *host, u32 cpm)
{
- return host->intr_op->init_host_sync(host, cpm, syncpt_thresh_work);
+ return host->intr_op->init_host_sync(host, cpm);
}
static inline void host1x_hw_intr_set_syncpt_threshold(struct host1x *host,
diff --git a/drivers/gpu/host1x/fence.c b/drivers/gpu/host1x/fence.c
index df428bcbae69..139ad1afd935 100644
--- a/drivers/gpu/host1x/fence.c
+++ b/drivers/gpu/host1x/fence.c
@@ -15,22 +15,6 @@
#include "intr.h"
#include "syncpt.h"
-static DEFINE_SPINLOCK(lock);
-
-struct host1x_syncpt_fence {
- struct dma_fence base;
-
- atomic_t signaling;
-
- struct host1x_syncpt *sp;
- u32 threshold;
-
- struct host1x_waitlist *waiter;
- void *waiter_ref;
-
- struct delayed_work timeout_work;
-};
-
static const char *host1x_syncpt_fence_get_driver_name(struct dma_fence *f)
{
return "host1x";
@@ -49,11 +33,11 @@ static struct host1x_syncpt_fence *to_host1x_fence(struct dma_fence *f)
static bool host1x_syncpt_fence_enable_signaling(struct dma_fence *f)
{
struct host1x_syncpt_fence *sf = to_host1x_fence(f);
- int err;
if (host1x_syncpt_is_expired(sf->sp, sf->threshold))
return false;
+ /* Reference for interrupt path. */
dma_fence_get(f);
/*
@@ -61,24 +45,17 @@ static bool host1x_syncpt_fence_enable_signaling(struct dma_fence *f)
* reference to any fences for which 'enable_signaling' has been
* called (and that have not been signalled).
*
- * We provide a userspace API to create arbitrary syncpoint fences,
- * so we cannot normally guarantee that all fences get signalled.
- * As such, setup a timeout, so that long-lasting fences will get
- * reaped eventually.
+ * We cannot currently always guarantee that all fences get signalled
+ * or cancelled. As such, for such situations, set up a timeout, so
+ * that long-lasting fences will get reaped eventually.
*/
- schedule_delayed_work(&sf->timeout_work, msecs_to_jiffies(30000));
-
- err = host1x_intr_add_action(sf->sp->host, sf->sp, sf->threshold,
- HOST1X_INTR_ACTION_SIGNAL_FENCE, f,
- sf->waiter, &sf->waiter_ref);
- if (err) {
- cancel_delayed_work_sync(&sf->timeout_work);
- dma_fence_put(f);
- return false;
+ if (sf->timeout) {
+ /* Reference for timeout path. */
+ dma_fence_get(f);
+ schedule_delayed_work(&sf->timeout_work, msecs_to_jiffies(30000));
}
- /* intr framework takes ownership of waiter */
- sf->waiter = NULL;
+ host1x_intr_add_fence_locked(sf->sp->host, sf);
/*
* The fence may get signalled at any time after the above call,
@@ -89,37 +66,32 @@ static bool host1x_syncpt_fence_enable_signaling(struct dma_fence *f)
return true;
}
-static void host1x_syncpt_fence_release(struct dma_fence *f)
-{
- struct host1x_syncpt_fence *sf = to_host1x_fence(f);
-
- if (sf->waiter)
- kfree(sf->waiter);
-
- dma_fence_free(f);
-}
-
static const struct dma_fence_ops host1x_syncpt_fence_ops = {
.get_driver_name = host1x_syncpt_fence_get_driver_name,
.get_timeline_name = host1x_syncpt_fence_get_timeline_name,
.enable_signaling = host1x_syncpt_fence_enable_signaling,
- .release = host1x_syncpt_fence_release,
};
void host1x_fence_signal(struct host1x_syncpt_fence *f)
{
- if (atomic_xchg(&f->signaling, 1))
+ if (atomic_xchg(&f->signaling, 1)) {
+ /*
+ * Already on timeout path, but we removed the fence before
+ * timeout path could, so drop interrupt path reference.
+ */
+ dma_fence_put(&f->base);
return;
+ }
- /*
- * Cancel pending timeout work - if it races, it will
- * not get 'f->signaling' and return.
- */
- cancel_delayed_work_sync(&f->timeout_work);
-
- host1x_intr_put_ref(f->sp->host, f->sp->id, f->waiter_ref, false);
+ if (f->timeout && cancel_delayed_work(&f->timeout_work)) {
+ /*
+ * We know that the timeout path will not be entered.
+ * Safe to drop the timeout path's reference now.
+ */
+ dma_fence_put(&f->base);
+ }
- dma_fence_signal(&f->base);
+ dma_fence_signal_locked(&f->base);
dma_fence_put(&f->base);
}
@@ -129,21 +101,29 @@ static void do_fence_timeout(struct work_struct *work)
struct host1x_syncpt_fence *f =
container_of(dwork, struct host1x_syncpt_fence, timeout_work);
- if (atomic_xchg(&f->signaling, 1))
+ if (atomic_xchg(&f->signaling, 1)) {
+ /* Already on interrupt path, drop timeout path reference if any. */
+ if (f->timeout)
+ dma_fence_put(&f->base);
return;
+ }
- /*
- * Cancel pending timeout work - if it races, it will
- * not get 'f->signaling' and return.
- */
- host1x_intr_put_ref(f->sp->host, f->sp->id, f->waiter_ref, true);
+ if (host1x_intr_remove_fence(f->sp->host, f)) {
+ /*
+ * Managed to remove fence from queue, so it's safe to drop
+ * the interrupt path's reference.
+ */
+ dma_fence_put(&f->base);
+ }
dma_fence_set_error(&f->base, -ETIMEDOUT);
dma_fence_signal(&f->base);
- dma_fence_put(&f->base);
+ if (f->timeout)
+ dma_fence_put(&f->base);
}
-struct dma_fence *host1x_fence_create(struct host1x_syncpt *sp, u32 threshold)
+struct dma_fence *host1x_fence_create(struct host1x_syncpt *sp, u32 threshold,
+ bool timeout)
{
struct host1x_syncpt_fence *fence;
@@ -151,16 +131,11 @@ struct dma_fence *host1x_fence_create(struct host1x_syncpt *sp, u32 threshold)
if (!fence)
return ERR_PTR(-ENOMEM);
- fence->waiter = kzalloc(sizeof(*fence->waiter), GFP_KERNEL);
- if (!fence->waiter) {
- kfree(fence);
- return ERR_PTR(-ENOMEM);
- }
-
fence->sp = sp;
fence->threshold = threshold;
+ fence->timeout = timeout;
- dma_fence_init(&fence->base, &host1x_syncpt_fence_ops, &lock,
+ dma_fence_init(&fence->base, &host1x_syncpt_fence_ops, &sp->fences.lock,
dma_fence_context_alloc(1), 0);
INIT_DELAYED_WORK(&fence->timeout_work, do_fence_timeout);
@@ -168,3 +143,12 @@ struct dma_fence *host1x_fence_create(struct host1x_syncpt *sp, u32 threshold)
return &fence->base;
}
EXPORT_SYMBOL(host1x_fence_create);
+
+void host1x_fence_cancel(struct dma_fence *f)
+{
+ struct host1x_syncpt_fence *sf = to_host1x_fence(f);
+
+ schedule_delayed_work(&sf->timeout_work, 0);
+ flush_delayed_work(&sf->timeout_work);
+}
+EXPORT_SYMBOL(host1x_fence_cancel);
diff --git a/drivers/gpu/host1x/fence.h b/drivers/gpu/host1x/fence.h
index 70c91de82f14..f3c644c73cad 100644
--- a/drivers/gpu/host1x/fence.h
+++ b/drivers/gpu/host1x/fence.h
@@ -6,7 +6,24 @@
#ifndef HOST1X_FENCE_H
#define HOST1X_FENCE_H
-struct host1x_syncpt_fence;
+struct host1x_syncpt_fence {
+ struct dma_fence base;
+
+ atomic_t signaling;
+
+ struct host1x_syncpt *sp;
+ u32 threshold;
+ bool timeout;
+
+ struct delayed_work timeout_work;
+
+ struct list_head list;
+};
+
+struct host1x_fence_list {
+ spinlock_t lock;
+ struct list_head list;
+};
void host1x_fence_signal(struct host1x_syncpt_fence *fence);
diff --git a/drivers/gpu/host1x/hw/channel_hw.c b/drivers/gpu/host1x/hw/channel_hw.c
index 732abe0750ff..d44b8de890be 100644
--- a/drivers/gpu/host1x/hw/channel_hw.c
+++ b/drivers/gpu/host1x/hw/channel_hw.c
@@ -179,14 +179,12 @@ static inline void synchronize_syncpt_base(struct host1x_job *job)
static void host1x_channel_set_streamid(struct host1x_channel *channel)
{
#if HOST1X_HW >= 6
- u32 sid = 0x7f;
-#ifdef CONFIG_IOMMU_API
- struct iommu_fwspec *spec = dev_iommu_fwspec_get(channel->dev->parent);
- if (spec)
- sid = spec->ids[0] & 0xffff;
-#endif
+ u32 stream_id;
+
+ if (!tegra_dev_iommu_get_stream_id(channel->dev->parent, &stream_id))
+ stream_id = TEGRA_STREAM_ID_BYPASS;
- host1x_ch_writel(channel, sid, HOST1X_CHANNEL_SMMU_STREAMID);
+ host1x_ch_writel(channel, stream_id, HOST1X_CHANNEL_SMMU_STREAMID);
#endif
}
@@ -278,6 +276,14 @@ static void channel_program_cdma(struct host1x_job *job)
#endif
}
+static void job_complete_callback(struct dma_fence *fence, struct dma_fence_cb *cb)
+{
+ struct host1x_job *job = container_of(cb, struct host1x_job, fence_cb);
+
+ /* Schedules CDMA update. */
+ host1x_cdma_update(&job->channel->cdma);
+}
+
static int channel_submit(struct host1x_job *job)
{
struct host1x_channel *ch = job->channel;
@@ -285,7 +291,6 @@ static int channel_submit(struct host1x_job *job)
u32 prev_max = 0;
u32 syncval;
int err;
- struct host1x_waitlist *completed_waiter = NULL;
struct host1x *host = dev_get_drvdata(ch->dev->parent);
trace_host1x_channel_submit(dev_name(ch->dev),
@@ -298,14 +303,7 @@ static int channel_submit(struct host1x_job *job)
/* get submit lock */
err = mutex_lock_interruptible(&ch->submitlock);
if (err)
- goto error;
-
- completed_waiter = kzalloc(sizeof(*completed_waiter), GFP_KERNEL);
- if (!completed_waiter) {
- mutex_unlock(&ch->submitlock);
- err = -ENOMEM;
- goto error;
- }
+ return err;
host1x_channel_set_streamid(ch);
host1x_enable_gather_filter(ch);
@@ -315,31 +313,37 @@ static int channel_submit(struct host1x_job *job)
err = host1x_cdma_begin(&ch->cdma, job);
if (err) {
mutex_unlock(&ch->submitlock);
- goto error;
+ return err;
}
channel_program_cdma(job);
syncval = host1x_syncpt_read_max(sp);
+ /*
+ * Create fence before submitting job to HW to avoid job completing
+ * before the fence is set up.
+ */
+ job->fence = host1x_fence_create(sp, syncval, true);
+ if (WARN(IS_ERR(job->fence), "Failed to create submit complete fence")) {
+ job->fence = NULL;
+ } else {
+ err = dma_fence_add_callback(job->fence, &job->fence_cb,
+ job_complete_callback);
+ }
+
/* end CDMA submit & stash pinned hMems into sync queue */
host1x_cdma_end(&ch->cdma, job);
trace_host1x_channel_submitted(dev_name(ch->dev), prev_max, syncval);
- /* schedule a submit complete interrupt */
- err = host1x_intr_add_action(host, sp, syncval,
- HOST1X_INTR_ACTION_SUBMIT_COMPLETE, ch,
- completed_waiter, &job->waiter);
- completed_waiter = NULL;
- WARN(err, "Failed to set submit complete interrupt");
-
mutex_unlock(&ch->submitlock);
- return 0;
+ if (err == -ENOENT)
+ host1x_cdma_update(&ch->cdma);
+ else
+ WARN(err, "Failed to set submit complete interrupt");
-error:
- kfree(completed_waiter);
- return err;
+ return 0;
}
static int host1x_channel_init(struct host1x_channel *ch, struct host1x *dev,
diff --git a/drivers/gpu/host1x/hw/hw_host1x06_uclass.h b/drivers/gpu/host1x/hw/hw_host1x06_uclass.h
index 5f831438d19b..50c32de452fb 100644
--- a/drivers/gpu/host1x/hw/hw_host1x06_uclass.h
+++ b/drivers/gpu/host1x/hw/hw_host1x06_uclass.h
@@ -53,7 +53,7 @@ static inline u32 host1x_uclass_incr_syncpt_cond_f(u32 v)
host1x_uclass_incr_syncpt_cond_f(v)
static inline u32 host1x_uclass_incr_syncpt_indx_f(u32 v)
{
- return (v & 0xff) << 0;
+ return (v & 0x3ff) << 0;
}
#define HOST1X_UCLASS_INCR_SYNCPT_INDX_F(v) \
host1x_uclass_incr_syncpt_indx_f(v)
diff --git a/drivers/gpu/host1x/hw/hw_host1x07_uclass.h b/drivers/gpu/host1x/hw/hw_host1x07_uclass.h
index 8cd2ef087d5d..887b878f92f7 100644
--- a/drivers/gpu/host1x/hw/hw_host1x07_uclass.h
+++ b/drivers/gpu/host1x/hw/hw_host1x07_uclass.h
@@ -53,7 +53,7 @@ static inline u32 host1x_uclass_incr_syncpt_cond_f(u32 v)
host1x_uclass_incr_syncpt_cond_f(v)
static inline u32 host1x_uclass_incr_syncpt_indx_f(u32 v)
{
- return (v & 0xff) << 0;
+ return (v & 0x3ff) << 0;
}
#define HOST1X_UCLASS_INCR_SYNCPT_INDX_F(v) \
host1x_uclass_incr_syncpt_indx_f(v)
diff --git a/drivers/gpu/host1x/hw/hw_host1x08_uclass.h b/drivers/gpu/host1x/hw/hw_host1x08_uclass.h
index 724cccd71aa1..4fb1d090edae 100644
--- a/drivers/gpu/host1x/hw/hw_host1x08_uclass.h
+++ b/drivers/gpu/host1x/hw/hw_host1x08_uclass.h
@@ -53,7 +53,7 @@ static inline u32 host1x_uclass_incr_syncpt_cond_f(u32 v)
host1x_uclass_incr_syncpt_cond_f(v)
static inline u32 host1x_uclass_incr_syncpt_indx_f(u32 v)
{
- return (v & 0xff) << 0;
+ return (v & 0x3ff) << 0;
}
#define HOST1X_UCLASS_INCR_SYNCPT_INDX_F(v) \
host1x_uclass_incr_syncpt_indx_f(v)
diff --git a/drivers/gpu/host1x/hw/intr_hw.c b/drivers/gpu/host1x/hw/intr_hw.c
index 9acccdb139e6..b915ef7d0348 100644
--- a/drivers/gpu/host1x/hw/intr_hw.c
+++ b/drivers/gpu/host1x/hw/intr_hw.c
@@ -13,23 +13,6 @@
#include "../intr.h"
#include "../dev.h"
-/*
- * Sync point threshold interrupt service function
- * Handles sync point threshold triggers, in interrupt context
- */
-static void host1x_intr_syncpt_handle(struct host1x_syncpt *syncpt)
-{
- unsigned int id = syncpt->id;
- struct host1x *host = syncpt->host;
-
- host1x_sync_writel(host, BIT(id % 32),
- HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(id / 32));
- host1x_sync_writel(host, BIT(id % 32),
- HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(id / 32));
-
- schedule_work(&syncpt->intr.work);
-}
-
static irqreturn_t syncpt_thresh_isr(int irq, void *dev_id)
{
struct host1x *host = dev_id;
@@ -39,17 +22,20 @@ static irqreturn_t syncpt_thresh_isr(int irq, void *dev_id)
for (i = 0; i < DIV_ROUND_UP(host->info->nb_pts, 32); i++) {
reg = host1x_sync_readl(host,
HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(i));
- for_each_set_bit(id, &reg, 32) {
- struct host1x_syncpt *syncpt =
- host->syncpt + (i * 32 + id);
- host1x_intr_syncpt_handle(syncpt);
- }
+
+ host1x_sync_writel(host, reg,
+ HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(i));
+ host1x_sync_writel(host, reg,
+ HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(i));
+
+ for_each_set_bit(id, &reg, 32)
+ host1x_intr_handle_interrupt(host, i * 32 + id);
}
return IRQ_HANDLED;
}
-static void _host1x_intr_disable_all_syncpt_intrs(struct host1x *host)
+static void host1x_intr_disable_all_syncpt_intrs(struct host1x *host)
{
unsigned int i;
@@ -90,45 +76,38 @@ static void intr_hw_init(struct host1x *host, u32 cpm)
}
static int
-_host1x_intr_init_host_sync(struct host1x *host, u32 cpm,
- void (*syncpt_thresh_work)(struct work_struct *))
+host1x_intr_init_host_sync(struct host1x *host, u32 cpm)
{
- unsigned int i;
int err;
host1x_hw_intr_disable_all_syncpt_intrs(host);
- for (i = 0; i < host->info->nb_pts; i++)
- INIT_WORK(&host->syncpt[i].intr.work, syncpt_thresh_work);
-
- err = devm_request_irq(host->dev, host->intr_syncpt_irq,
+ err = devm_request_irq(host->dev, host->syncpt_irq,
syncpt_thresh_isr, IRQF_SHARED,
"host1x_syncpt", host);
- if (err < 0) {
- WARN_ON(1);
+ if (err < 0)
return err;
- }
intr_hw_init(host, cpm);
return 0;
}
-static void _host1x_intr_set_syncpt_threshold(struct host1x *host,
+static void host1x_intr_set_syncpt_threshold(struct host1x *host,
unsigned int id,
u32 thresh)
{
host1x_sync_writel(host, thresh, HOST1X_SYNC_SYNCPT_INT_THRESH(id));
}
-static void _host1x_intr_enable_syncpt_intr(struct host1x *host,
+static void host1x_intr_enable_syncpt_intr(struct host1x *host,
unsigned int id)
{
host1x_sync_writel(host, BIT(id % 32),
HOST1X_SYNC_SYNCPT_THRESH_INT_ENABLE_CPU0(id / 32));
}
-static void _host1x_intr_disable_syncpt_intr(struct host1x *host,
+static void host1x_intr_disable_syncpt_intr(struct host1x *host,
unsigned int id)
{
host1x_sync_writel(host, BIT(id % 32),
@@ -137,23 +116,10 @@ static void _host1x_intr_disable_syncpt_intr(struct host1x *host,
HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(id / 32));
}
-static int _host1x_free_syncpt_irq(struct host1x *host)
-{
- unsigned int i;
-
- devm_free_irq(host->dev, host->intr_syncpt_irq, host);
-
- for (i = 0; i < host->info->nb_pts; i++)
- cancel_work_sync(&host->syncpt[i].intr.work);
-
- return 0;
-}
-
static const struct host1x_intr_ops host1x_intr_ops = {
- .init_host_sync = _host1x_intr_init_host_sync,
- .set_syncpt_threshold = _host1x_intr_set_syncpt_threshold,
- .enable_syncpt_intr = _host1x_intr_enable_syncpt_intr,
- .disable_syncpt_intr = _host1x_intr_disable_syncpt_intr,
- .disable_all_syncpt_intrs = _host1x_intr_disable_all_syncpt_intrs,
- .free_syncpt_irq = _host1x_free_syncpt_irq,
+ .init_host_sync = host1x_intr_init_host_sync,
+ .set_syncpt_threshold = host1x_intr_set_syncpt_threshold,
+ .enable_syncpt_intr = host1x_intr_enable_syncpt_intr,
+ .disable_syncpt_intr = host1x_intr_disable_syncpt_intr,
+ .disable_all_syncpt_intrs = host1x_intr_disable_all_syncpt_intrs,
};
diff --git a/drivers/gpu/host1x/hw/syncpt_hw.c b/drivers/gpu/host1x/hw/syncpt_hw.c
index dd39d67ccec3..8cf35b2eff3d 100644
--- a/drivers/gpu/host1x/hw/syncpt_hw.c
+++ b/drivers/gpu/host1x/hw/syncpt_hw.c
@@ -106,9 +106,6 @@ static void syncpt_assign_to_channel(struct host1x_syncpt *sp,
#if HOST1X_HW >= 6
struct host1x *host = sp->host;
- if (!host->hv_regs)
- return;
-
host1x_sync_writel(host,
HOST1X_SYNC_SYNCPT_CH_APP_CH(ch ? ch->id : 0xff),
HOST1X_SYNC_SYNCPT_CH_APP(sp->id));
diff --git a/drivers/gpu/host1x/intr.c b/drivers/gpu/host1x/intr.c
index 965ba21818b1..995bfa980837 100644
--- a/drivers/gpu/host1x/intr.c
+++ b/drivers/gpu/host1x/intr.c
@@ -2,299 +2,113 @@
/*
* Tegra host1x Interrupt Management
*
- * Copyright (c) 2010-2013, NVIDIA Corporation.
+ * Copyright (c) 2010-2021, NVIDIA Corporation.
*/
#include <linux/clk.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/irq.h>
-#include <trace/events/host1x.h>
-#include "channel.h"
#include "dev.h"
#include "fence.h"
#include "intr.h"
-/* Wait list management */
-
-enum waitlist_state {
- WLS_PENDING,
- WLS_REMOVED,
- WLS_CANCELLED,
- WLS_HANDLED
-};
-
-static void waiter_release(struct kref *kref)
-{
- kfree(container_of(kref, struct host1x_waitlist, refcount));
-}
-
-/*
- * add a waiter to a waiter queue, sorted by threshold
- * returns true if it was added at the head of the queue
- */
-static bool add_waiter_to_queue(struct host1x_waitlist *waiter,
- struct list_head *queue)
-{
- struct host1x_waitlist *pos;
- u32 thresh = waiter->thresh;
-
- list_for_each_entry_reverse(pos, queue, list)
- if ((s32)(pos->thresh - thresh) <= 0) {
- list_add(&waiter->list, &pos->list);
- return false;
- }
-
- list_add(&waiter->list, queue);
- return true;
-}
-
-/*
- * run through a waiter queue for a single sync point ID
- * and gather all completed waiters into lists by actions
- */
-static void remove_completed_waiters(struct list_head *head, u32 sync,
- struct list_head completed[HOST1X_INTR_ACTION_COUNT])
+static void host1x_intr_add_fence_to_list(struct host1x_fence_list *list,
+ struct host1x_syncpt_fence *fence)
{
- struct list_head *dest;
- struct host1x_waitlist *waiter, *next, *prev;
-
- list_for_each_entry_safe(waiter, next, head, list) {
- if ((s32)(waiter->thresh - sync) > 0)
- break;
+ struct host1x_syncpt_fence *fence_in_list;
- dest = completed + waiter->action;
-
- /* consolidate submit cleanups */
- if (waiter->action == HOST1X_INTR_ACTION_SUBMIT_COMPLETE &&
- !list_empty(dest)) {
- prev = list_entry(dest->prev,
- struct host1x_waitlist, list);
- if (prev->data == waiter->data) {
- prev->count++;
- dest = NULL;
- }
+ list_for_each_entry_reverse(fence_in_list, &list->list, list) {
+ if ((s32)(fence_in_list->threshold - fence->threshold) <= 0) {
+ /* Fence in list is before us, we can insert here */
+ list_add(&fence->list, &fence_in_list->list);
+ return;
}
-
- /* PENDING->REMOVED or CANCELLED->HANDLED */
- if (atomic_inc_return(&waiter->state) == WLS_HANDLED || !dest) {
- list_del(&waiter->list);
- kref_put(&waiter->refcount, waiter_release);
- } else
- list_move_tail(&waiter->list, dest);
}
-}
-
-static void reset_threshold_interrupt(struct host1x *host,
- struct list_head *head,
- unsigned int id)
-{
- u32 thresh =
- list_first_entry(head, struct host1x_waitlist, list)->thresh;
-
- host1x_hw_intr_set_syncpt_threshold(host, id, thresh);
- host1x_hw_intr_enable_syncpt_intr(host, id);
-}
-
-static void action_submit_complete(struct host1x_waitlist *waiter)
-{
- struct host1x_channel *channel = waiter->data;
-
- host1x_cdma_update(&channel->cdma);
-
- /* Add nr_completed to trace */
- trace_host1x_channel_submit_complete(dev_name(channel->dev),
- waiter->count, waiter->thresh);
-}
-static void action_wakeup(struct host1x_waitlist *waiter)
-{
- wait_queue_head_t *wq = waiter->data;
-
- wake_up(wq);
-}
-
-static void action_wakeup_interruptible(struct host1x_waitlist *waiter)
-{
- wait_queue_head_t *wq = waiter->data;
-
- wake_up_interruptible(wq);
+ /* Add as first in list */
+ list_add(&fence->list, &list->list);
}
-static void action_signal_fence(struct host1x_waitlist *waiter)
+static void host1x_intr_update_hw_state(struct host1x *host, struct host1x_syncpt *sp)
{
- struct host1x_syncpt_fence *f = waiter->data;
-
- host1x_fence_signal(f);
-}
+ struct host1x_syncpt_fence *fence;
-typedef void (*action_handler)(struct host1x_waitlist *waiter);
+ if (!list_empty(&sp->fences.list)) {
+ fence = list_first_entry(&sp->fences.list, struct host1x_syncpt_fence, list);
-static const action_handler action_handlers[HOST1X_INTR_ACTION_COUNT] = {
- action_submit_complete,
- action_wakeup,
- action_wakeup_interruptible,
- action_signal_fence,
-};
-
-static void run_handlers(struct list_head completed[HOST1X_INTR_ACTION_COUNT])
-{
- struct list_head *head = completed;
- unsigned int i;
-
- for (i = 0; i < HOST1X_INTR_ACTION_COUNT; ++i, ++head) {
- action_handler handler = action_handlers[i];
- struct host1x_waitlist *waiter, *next;
-
- list_for_each_entry_safe(waiter, next, head, list) {
- list_del(&waiter->list);
- handler(waiter);
- WARN_ON(atomic_xchg(&waiter->state, WLS_HANDLED) !=
- WLS_REMOVED);
- kref_put(&waiter->refcount, waiter_release);
- }
+ host1x_hw_intr_set_syncpt_threshold(host, sp->id, fence->threshold);
+ host1x_hw_intr_enable_syncpt_intr(host, sp->id);
+ } else {
+ host1x_hw_intr_disable_syncpt_intr(host, sp->id);
}
}
-/*
- * Remove & handle all waiters that have completed for the given syncpt
- */
-static int process_wait_list(struct host1x *host,
- struct host1x_syncpt *syncpt,
- u32 threshold)
+void host1x_intr_add_fence_locked(struct host1x *host, struct host1x_syncpt_fence *fence)
{
- struct list_head completed[HOST1X_INTR_ACTION_COUNT];
- unsigned int i;
- int empty;
-
- for (i = 0; i < HOST1X_INTR_ACTION_COUNT; ++i)
- INIT_LIST_HEAD(completed + i);
-
- spin_lock(&syncpt->intr.lock);
-
- remove_completed_waiters(&syncpt->intr.wait_head, threshold,
- completed);
-
- empty = list_empty(&syncpt->intr.wait_head);
- if (empty)
- host1x_hw_intr_disable_syncpt_intr(host, syncpt->id);
- else
- reset_threshold_interrupt(host, &syncpt->intr.wait_head,
- syncpt->id);
-
- spin_unlock(&syncpt->intr.lock);
-
- run_handlers(completed);
-
- return empty;
-}
+ struct host1x_fence_list *fence_list = &fence->sp->fences;
-/*
- * Sync point threshold interrupt service thread function
- * Handles sync point threshold triggers, in thread context
- */
+ INIT_LIST_HEAD(&fence->list);
-static void syncpt_thresh_work(struct work_struct *work)
-{
- struct host1x_syncpt_intr *syncpt_intr =
- container_of(work, struct host1x_syncpt_intr, work);
- struct host1x_syncpt *syncpt =
- container_of(syncpt_intr, struct host1x_syncpt, intr);
- unsigned int id = syncpt->id;
- struct host1x *host = syncpt->host;
-
- (void)process_wait_list(host, syncpt,
- host1x_syncpt_load(host->syncpt + id));
+ host1x_intr_add_fence_to_list(fence_list, fence);
+ host1x_intr_update_hw_state(host, fence->sp);
}
-int host1x_intr_add_action(struct host1x *host, struct host1x_syncpt *syncpt,
- u32 thresh, enum host1x_intr_action action,
- void *data, struct host1x_waitlist *waiter,
- void **ref)
+bool host1x_intr_remove_fence(struct host1x *host, struct host1x_syncpt_fence *fence)
{
- int queue_was_empty;
-
- if (waiter == NULL) {
- pr_warn("%s: NULL waiter\n", __func__);
- return -EINVAL;
- }
-
- /* initialize a new waiter */
- INIT_LIST_HEAD(&waiter->list);
- kref_init(&waiter->refcount);
- if (ref)
- kref_get(&waiter->refcount);
- waiter->thresh = thresh;
- waiter->action = action;
- atomic_set(&waiter->state, WLS_PENDING);
- waiter->data = data;
- waiter->count = 1;
-
- spin_lock(&syncpt->intr.lock);
+ struct host1x_fence_list *fence_list = &fence->sp->fences;
+ unsigned long irqflags;
- queue_was_empty = list_empty(&syncpt->intr.wait_head);
+ spin_lock_irqsave(&fence_list->lock, irqflags);
- if (add_waiter_to_queue(waiter, &syncpt->intr.wait_head)) {
- /* added at head of list - new threshold value */
- host1x_hw_intr_set_syncpt_threshold(host, syncpt->id, thresh);
-
- /* added as first waiter - enable interrupt */
- if (queue_was_empty)
- host1x_hw_intr_enable_syncpt_intr(host, syncpt->id);
+ if (list_empty(&fence->list)) {
+ spin_unlock_irqrestore(&fence_list->lock, irqflags);
+ return false;
}
- if (ref)
- *ref = waiter;
+ list_del_init(&fence->list);
+ host1x_intr_update_hw_state(host, fence->sp);
- spin_unlock(&syncpt->intr.lock);
+ spin_unlock_irqrestore(&fence_list->lock, irqflags);
- return 0;
+ return true;
}
-void host1x_intr_put_ref(struct host1x *host, unsigned int id, void *ref,
- bool flush)
+void host1x_intr_handle_interrupt(struct host1x *host, unsigned int id)
{
- struct host1x_waitlist *waiter = ref;
- struct host1x_syncpt *syncpt;
+ struct host1x_syncpt *sp = &host->syncpt[id];
+ struct host1x_syncpt_fence *fence, *tmp;
+ unsigned int value;
- atomic_cmpxchg(&waiter->state, WLS_PENDING, WLS_CANCELLED);
+ value = host1x_syncpt_load(sp);
- syncpt = host->syncpt + id;
+ spin_lock(&sp->fences.lock);
- spin_lock(&syncpt->intr.lock);
- if (atomic_cmpxchg(&waiter->state, WLS_CANCELLED, WLS_HANDLED) ==
- WLS_CANCELLED) {
- list_del(&waiter->list);
- kref_put(&waiter->refcount, waiter_release);
- }
- spin_unlock(&syncpt->intr.lock);
+ list_for_each_entry_safe(fence, tmp, &sp->fences.list, list) {
+ if (((value - fence->threshold) & 0x80000000U) != 0U) {
+ /* Fence is not yet expired, we are done */
+ break;
+ }
- if (flush) {
- /* Wait until any concurrently executing handler has finished. */
- while (atomic_read(&waiter->state) != WLS_HANDLED)
- schedule();
+ list_del_init(&fence->list);
+ host1x_fence_signal(fence);
}
- kref_put(&waiter->refcount, waiter_release);
+ /* Re-enable interrupt if necessary */
+ host1x_intr_update_hw_state(host, sp);
+
+ spin_unlock(&sp->fences.lock);
}
-int host1x_intr_init(struct host1x *host, unsigned int irq_sync)
+int host1x_intr_init(struct host1x *host)
{
unsigned int id;
- u32 nb_pts = host1x_syncpt_nb_pts(host);
mutex_init(&host->intr_mutex);
- host->intr_syncpt_irq = irq_sync;
- for (id = 0; id < nb_pts; ++id) {
- struct host1x_syncpt *syncpt = host->syncpt + id;
+ for (id = 0; id < host1x_syncpt_nb_pts(host); ++id) {
+ struct host1x_syncpt *syncpt = &host->syncpt[id];
- spin_lock_init(&syncpt->intr.lock);
- INIT_LIST_HEAD(&syncpt->intr.wait_head);
- snprintf(syncpt->intr.thresh_irq_name,
- sizeof(syncpt->intr.thresh_irq_name),
- "host1x_sp_%02u", id);
+ spin_lock_init(&syncpt->fences.lock);
+ INIT_LIST_HEAD(&syncpt->fences.list);
}
return 0;
@@ -310,8 +124,7 @@ void host1x_intr_start(struct host1x *host)
int err;
mutex_lock(&host->intr_mutex);
- err = host1x_hw_intr_init_host_sync(host, DIV_ROUND_UP(hz, 1000000),
- syncpt_thresh_work);
+ err = host1x_hw_intr_init_host_sync(host, DIV_ROUND_UP(hz, 1000000));
if (err) {
mutex_unlock(&host->intr_mutex);
return;
@@ -321,36 +134,5 @@ void host1x_intr_start(struct host1x *host)
void host1x_intr_stop(struct host1x *host)
{
- unsigned int id;
- struct host1x_syncpt *syncpt = host->syncpt;
- u32 nb_pts = host1x_syncpt_nb_pts(host);
-
- mutex_lock(&host->intr_mutex);
-
host1x_hw_intr_disable_all_syncpt_intrs(host);
-
- for (id = 0; id < nb_pts; ++id) {
- struct host1x_waitlist *waiter, *next;
-
- list_for_each_entry_safe(waiter, next,
- &syncpt[id].intr.wait_head, list) {
- if (atomic_cmpxchg(&waiter->state,
- WLS_CANCELLED, WLS_HANDLED) == WLS_CANCELLED) {
- list_del(&waiter->list);
- kref_put(&waiter->refcount, waiter_release);
- }
- }
-
- if (!list_empty(&syncpt[id].intr.wait_head)) {
- /* output diagnostics */
- mutex_unlock(&host->intr_mutex);
- pr_warn("%s cannot stop syncpt intr id=%u\n",
- __func__, id);
- return;
- }
- }
-
- host1x_hw_intr_free_syncpt_irq(host);
-
- mutex_unlock(&host->intr_mutex);
}
diff --git a/drivers/gpu/host1x/intr.h b/drivers/gpu/host1x/intr.h
index e4c346099273..3b5610b525e5 100644
--- a/drivers/gpu/host1x/intr.h
+++ b/drivers/gpu/host1x/intr.h
@@ -2,87 +2,17 @@
/*
* Tegra host1x Interrupt Management
*
- * Copyright (c) 2010-2013, NVIDIA Corporation.
+ * Copyright (c) 2010-2021, NVIDIA Corporation.
*/
#ifndef __HOST1X_INTR_H
#define __HOST1X_INTR_H
-#include <linux/interrupt.h>
-#include <linux/workqueue.h>
-
-struct host1x_syncpt;
struct host1x;
-
-enum host1x_intr_action {
- /*
- * Perform cleanup after a submit has completed.
- * 'data' points to a channel
- */
- HOST1X_INTR_ACTION_SUBMIT_COMPLETE = 0,
-
- /*
- * Wake up a task.
- * 'data' points to a wait_queue_head_t
- */
- HOST1X_INTR_ACTION_WAKEUP,
-
- /*
- * Wake up a interruptible task.
- * 'data' points to a wait_queue_head_t
- */
- HOST1X_INTR_ACTION_WAKEUP_INTERRUPTIBLE,
-
- HOST1X_INTR_ACTION_SIGNAL_FENCE,
-
- HOST1X_INTR_ACTION_COUNT
-};
-
-struct host1x_syncpt_intr {
- spinlock_t lock;
- struct list_head wait_head;
- char thresh_irq_name[12];
- struct work_struct work;
-};
-
-struct host1x_waitlist {
- struct list_head list;
- struct kref refcount;
- u32 thresh;
- enum host1x_intr_action action;
- atomic_t state;
- void *data;
- int count;
-};
-
-/*
- * Schedule an action to be taken when a sync point reaches the given threshold.
- *
- * @id the sync point
- * @thresh the threshold
- * @action the action to take
- * @data a pointer to extra data depending on action, see above
- * @waiter waiter structure - assumes ownership
- * @ref must be passed if cancellation is possible, else NULL
- *
- * This is a non-blocking api.
- */
-int host1x_intr_add_action(struct host1x *host, struct host1x_syncpt *syncpt,
- u32 thresh, enum host1x_intr_action action,
- void *data, struct host1x_waitlist *waiter,
- void **ref);
-
-/*
- * Unreference an action submitted to host1x_intr_add_action().
- * You must call this if you passed non-NULL as ref.
- * @ref the ref returned from host1x_intr_add_action()
- * @flush wait until any pending handlers have completed before returning.
- */
-void host1x_intr_put_ref(struct host1x *host, unsigned int id, void *ref,
- bool flush);
+struct host1x_syncpt_fence;
/* Initialize host1x sync point interrupt */
-int host1x_intr_init(struct host1x *host, unsigned int irq_sync);
+int host1x_intr_init(struct host1x *host);
/* Deinitialize host1x sync point interrupt */
void host1x_intr_deinit(struct host1x *host);
@@ -93,5 +23,10 @@ void host1x_intr_start(struct host1x *host);
/* Disable host1x sync point interrupt */
void host1x_intr_stop(struct host1x *host);
-irqreturn_t host1x_syncpt_thresh_fn(void *dev_id);
+void host1x_intr_handle_interrupt(struct host1x *host, unsigned int id);
+
+void host1x_intr_add_fence_locked(struct host1x *host, struct host1x_syncpt_fence *fence);
+
+bool host1x_intr_remove_fence(struct host1x *host, struct host1x_syncpt_fence *fence);
+
#endif
diff --git a/drivers/gpu/host1x/job.c b/drivers/gpu/host1x/job.c
index b2761aa03b95..3ed49e1fd933 100644
--- a/drivers/gpu/host1x/job.c
+++ b/drivers/gpu/host1x/job.c
@@ -88,9 +88,15 @@ static void job_free(struct kref *ref)
if (job->release)
job->release(job);
- if (job->waiter)
- host1x_intr_put_ref(job->syncpt->host, job->syncpt->id,
- job->waiter, false);
+ if (job->fence) {
+ /*
+ * remove_callback is atomic w.r.t. fence signaling, so
+ * after the call returns, we know that the callback is not
+ * in execution, and the fence can be safely freed.
+ */
+ dma_fence_remove_callback(job->fence, &job->fence_cb);
+ dma_fence_put(job->fence);
+ }
if (job->syncpt)
host1x_syncpt_put(job->syncpt);
diff --git a/drivers/gpu/host1x/syncpt.c b/drivers/gpu/host1x/syncpt.c
index f87a8705f518..2d2007760eac 100644
--- a/drivers/gpu/host1x/syncpt.c
+++ b/drivers/gpu/host1x/syncpt.c
@@ -7,6 +7,7 @@
#include <linux/module.h>
#include <linux/device.h>
+#include <linux/dma-fence.h>
#include <linux/slab.h>
#include <trace/events/host1x.h>
@@ -209,17 +210,6 @@ int host1x_syncpt_incr(struct host1x_syncpt *sp)
}
EXPORT_SYMBOL(host1x_syncpt_incr);
-/*
- * Updated sync point form hardware, and returns true if syncpoint is expired,
- * false if we may need to wait
- */
-static bool syncpt_load_min_is_expired(struct host1x_syncpt *sp, u32 thresh)
-{
- host1x_hw_syncpt_load(sp->host, sp);
-
- return host1x_syncpt_is_expired(sp, thresh);
-}
-
/**
* host1x_syncpt_wait() - wait for a syncpoint to reach a given value
* @sp: host1x syncpoint
@@ -230,10 +220,10 @@ static bool syncpt_load_min_is_expired(struct host1x_syncpt *sp, u32 thresh)
int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 thresh, long timeout,
u32 *value)
{
- DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
- void *ref;
- struct host1x_waitlist *waiter;
- int err = 0, check_count = 0;
+ struct dma_fence *fence;
+ long wait_err;
+
+ host1x_hw_syncpt_load(sp->host, sp);
if (value)
*value = host1x_syncpt_load(sp);
@@ -241,73 +231,29 @@ int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 thresh, long timeout,
if (host1x_syncpt_is_expired(sp, thresh))
return 0;
- if (!timeout) {
- err = -EAGAIN;
- goto done;
- }
-
- /* allocate a waiter */
- waiter = kzalloc(sizeof(*waiter), GFP_KERNEL);
- if (!waiter) {
- err = -ENOMEM;
- goto done;
- }
-
- /* schedule a wakeup when the syncpoint value is reached */
- err = host1x_intr_add_action(sp->host, sp, thresh,
- HOST1X_INTR_ACTION_WAKEUP_INTERRUPTIBLE,
- &wq, waiter, &ref);
- if (err)
- goto done;
-
- err = -EAGAIN;
- /* Caller-specified timeout may be impractically low */
if (timeout < 0)
timeout = LONG_MAX;
+ else if (timeout == 0)
+ return -EAGAIN;
- /* wait for the syncpoint, or timeout, or signal */
- while (timeout) {
- long check = min_t(long, SYNCPT_CHECK_PERIOD, timeout);
- int remain;
-
- remain = wait_event_interruptible_timeout(wq,
- syncpt_load_min_is_expired(sp, thresh),
- check);
- if (remain > 0 || host1x_syncpt_is_expired(sp, thresh)) {
- if (value)
- *value = host1x_syncpt_load(sp);
+ fence = host1x_fence_create(sp, thresh, false);
+ if (IS_ERR(fence))
+ return PTR_ERR(fence);
- err = 0;
+ wait_err = dma_fence_wait_timeout(fence, true, timeout);
+ if (wait_err == 0)
+ host1x_fence_cancel(fence);
+ dma_fence_put(fence);
- break;
- }
-
- if (remain < 0) {
- err = remain;
- break;
- }
-
- timeout -= check;
-
- if (timeout && check_count <= MAX_STUCK_CHECK_COUNT) {
- dev_warn(sp->host->dev,
- "%s: syncpoint id %u (%s) stuck waiting %d, timeout=%ld\n",
- current->comm, sp->id, sp->name,
- thresh, timeout);
-
- host1x_debug_dump_syncpts(sp->host);
-
- if (check_count == MAX_STUCK_CHECK_COUNT)
- host1x_debug_dump(sp->host);
-
- check_count++;
- }
- }
-
- host1x_intr_put_ref(sp->host, sp->id, ref, true);
+ if (value)
+ *value = host1x_syncpt_load(sp);
-done:
- return err;
+ if (wait_err == 0)
+ return -EAGAIN;
+ else if (wait_err < 0)
+ return wait_err;
+ else
+ return 0;
}
EXPORT_SYMBOL(host1x_syncpt_wait);
diff --git a/drivers/gpu/host1x/syncpt.h b/drivers/gpu/host1x/syncpt.h
index 95cd29b79d6d..4c3f3b2f0e9c 100644
--- a/drivers/gpu/host1x/syncpt.h
+++ b/drivers/gpu/host1x/syncpt.h
@@ -14,6 +14,7 @@
#include <linux/kref.h>
#include <linux/sched.h>
+#include "fence.h"
#include "intr.h"
struct host1x;
@@ -39,7 +40,7 @@ struct host1x_syncpt {
struct host1x_syncpt_base *base;
/* interrupt data */
- struct host1x_syncpt_intr intr;
+ struct host1x_fence_list fences;
/*
* If a submission incrementing this syncpoint fails, lock it so that
diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index 118318513e2d..c35eac1116f5 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/ipu-v3/ipu-common.c
@@ -1165,6 +1165,7 @@ static int ipu_add_client_devices(struct ipu_soc *ipu, unsigned long ipu_base)
pdev = platform_device_alloc(reg->name, id++);
if (!pdev) {
ret = -ENOMEM;
+ of_node_put(of_node);
goto err_register;
}
diff --git a/drivers/greybus/core.c b/drivers/greybus/core.c
index e546c6431877..5714be740470 100644
--- a/drivers/greybus/core.c
+++ b/drivers/greybus/core.c
@@ -78,14 +78,14 @@ static int greybus_match_device(struct device *dev, struct device_driver *drv)
return 0;
}
-static int greybus_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int greybus_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct gb_host_device *hd;
- struct gb_module *module = NULL;
- struct gb_interface *intf = NULL;
- struct gb_control *control = NULL;
- struct gb_bundle *bundle = NULL;
- struct gb_svc *svc = NULL;
+ const struct gb_host_device *hd;
+ const struct gb_module *module = NULL;
+ const struct gb_interface *intf = NULL;
+ const struct gb_control *control = NULL;
+ const struct gb_bundle *bundle = NULL;
+ const struct gb_svc *svc = NULL;
if (is_gb_host_device(dev)) {
hd = to_gb_host_device(dev);
diff --git a/drivers/hid/.kunitconfig b/drivers/hid/.kunitconfig
index 04daeff5c970..675a8209c7ae 100644
--- a/drivers/hid/.kunitconfig
+++ b/drivers/hid/.kunitconfig
@@ -1,5 +1,6 @@
CONFIG_KUNIT=y
CONFIG_USB=y
CONFIG_USB_HID=y
+CONFIG_HID_BATTERY_STRENGTH=y
CONFIG_HID_UCLOGIC=y
CONFIG_HID_KUNIT_TEST=y
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index e2a5d30c8895..82f64fb31fda 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -2,13 +2,20 @@
#
# HID driver configuration
#
-menu "HID support"
- depends on INPUT
+menuconfig HID_SUPPORT
+ bool "HID bus support"
+ default y
+ depends on INPUT
+ help
+ This option adds core support for human interface device (HID).
+ You will also need drivers from the following menu to make use of it.
+
+if HID_SUPPORT
config HID
- tristate "HID bus support"
- depends on INPUT
+ tristate "HID bus core support"
default y
+ depends on INPUT
help
A human interface device (HID) is a type of computer device that
interacts directly with and takes input from humans. The term "HID"
@@ -329,6 +336,13 @@ config HID_ELO
Support for the ELO USB 4000/4500 touchscreens. Note that this is for
different devices than those handled by CONFIG_TOUCHSCREEN_USB_ELO.
+config HID_EVISION
+ tristate "EVision Keyboards Support"
+ depends on HID
+ help
+ Support for some EVision keyboards. Note that this is needed only when
+ applying customization using userspace programs.
+
config HID_EZKEY
tristate "Ezkey BTC 8193 keyboard"
default !EXPERT
@@ -1018,13 +1032,21 @@ config HID_SPEEDLINK
Support for Speedlink Vicious and Divine Cezanne mouse.
config HID_STEAM
- tristate "Steam Controller support"
+ tristate "Steam Controller/Deck support"
select POWER_SUPPLY
help
- Say Y here if you have a Steam Controller if you want to use it
+ Say Y here if you have a Steam Controller or Deck if you want to use it
without running the Steam Client. It supports both the wired and
the wireless adaptor.
+config STEAM_FF
+ bool "Steam Deck force feedback support"
+ depends on HID_STEAM
+ select INPUT_FF_MEMLESS
+ help
+ Say Y here if you want to enable force feedback support for the Steam
+ Deck.
+
config HID_STEELSERIES
tristate "Steelseries SRW-S1 steering wheel support"
help
@@ -1264,6 +1286,7 @@ config HID_MCP2221
config HID_KUNIT_TEST
tristate "KUnit tests for HID" if !KUNIT_ALL_TESTS
depends on KUNIT=y
+ depends on HID_BATTERY_STRENGTH
depends on HID_UCLOGIC
default KUNIT_ALL_TESTS
help
@@ -1279,6 +1302,8 @@ config HID_KUNIT_TEST
endmenu
+source "drivers/hid/bpf/Kconfig"
+
endif # HID
source "drivers/hid/usbhid/Kconfig"
@@ -1291,4 +1316,4 @@ source "drivers/hid/amd-sfh-hid/Kconfig"
source "drivers/hid/surface-hid/Kconfig"
-endmenu
+endif # HID_SUPPORT
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index e8014c1a2f8b..5d37cacbde33 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -5,6 +5,8 @@
hid-y := hid-core.o hid-input.o hid-quirks.o
hid-$(CONFIG_DEBUG_FS) += hid-debug.o
+obj-$(CONFIG_HID_BPF) += bpf/
+
obj-$(CONFIG_HID) += hid.o
obj-$(CONFIG_UHID) += uhid.o
@@ -45,6 +47,7 @@ obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o
obj-$(CONFIG_HID_ELAN) += hid-elan.o
obj-$(CONFIG_HID_ELECOM) += hid-elecom.o
obj-$(CONFIG_HID_ELO) += hid-elo.o
+obj-$(CONFIG_HID_EVISION) += hid-evision.o
obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o
obj-$(CONFIG_HID_FT260) += hid-ft260.o
obj-$(CONFIG_HID_GEMBIRD) += hid-gembird.o
diff --git a/drivers/hid/amd-sfh-hid/Kconfig b/drivers/hid/amd-sfh-hid/Kconfig
index db069a83e9a2..af752dd3a340 100644
--- a/drivers/hid/amd-sfh-hid/Kconfig
+++ b/drivers/hid/amd-sfh-hid/Kconfig
@@ -2,10 +2,10 @@
menu "AMD SFH HID Support"
depends on X86_64 || COMPILE_TEST
depends on PCI
- depends on HID
config AMD_SFH_HID
tristate "AMD Sensor Fusion Hub"
+ depends on HID
help
If you say yes to this option, support will be included for the
AMD Sensor Fusion Hub.
diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_hid.c b/drivers/hid/amd-sfh-hid/amd_sfh_hid.c
index 1b18291fc5af..705b52337068 100644
--- a/drivers/hid/amd-sfh-hid/amd_sfh_hid.c
+++ b/drivers/hid/amd-sfh-hid/amd_sfh_hid.c
@@ -112,7 +112,7 @@ void amdtp_hid_wakeup(struct hid_device *hid)
}
}
-static struct hid_ll_driver amdtp_hid_ll_driver = {
+static const struct hid_ll_driver amdtp_hid_ll_driver = {
.parse = amdtp_hid_parse,
.start = amdtp_hid_start,
.stop = amdtp_hid_stop,
diff --git a/drivers/hid/bpf/Kconfig b/drivers/hid/bpf/Kconfig
new file mode 100644
index 000000000000..83214bae6768
--- /dev/null
+++ b/drivers/hid/bpf/Kconfig
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0-only
+menu "HID-BPF support"
+
+config HID_BPF
+ bool "HID-BPF support"
+ depends on BPF
+ depends on BPF_SYSCALL
+ depends on DYNAMIC_FTRACE_WITH_DIRECT_CALLS
+ help
+ This option allows to support eBPF programs on the HID subsystem.
+ eBPF programs can fix HID devices in a lighter way than a full
+ kernel patch and allow a lot more flexibility.
+
+ For documentation, see Documentation/hid/hid-bpf.rst
+
+endmenu
diff --git a/drivers/hid/bpf/Makefile b/drivers/hid/bpf/Makefile
new file mode 100644
index 000000000000..cf55120cf7d6
--- /dev/null
+++ b/drivers/hid/bpf/Makefile
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for HID-BPF
+#
+
+LIBBPF_INCLUDE = $(srctree)/tools/lib
+
+obj-$(CONFIG_HID_BPF) += hid_bpf.o
+CFLAGS_hid_bpf_dispatch.o += -I$(LIBBPF_INCLUDE)
+CFLAGS_hid_bpf_jmp_table.o += -I$(LIBBPF_INCLUDE)
+hid_bpf-objs += hid_bpf_dispatch.o hid_bpf_jmp_table.o
diff --git a/drivers/hid/bpf/entrypoints/Makefile b/drivers/hid/bpf/entrypoints/Makefile
new file mode 100644
index 000000000000..a12edcfa4fe3
--- /dev/null
+++ b/drivers/hid/bpf/entrypoints/Makefile
@@ -0,0 +1,93 @@
+# SPDX-License-Identifier: GPL-2.0
+OUTPUT := .output
+abs_out := $(abspath $(OUTPUT))
+
+CLANG ?= clang
+LLC ?= llc
+LLVM_STRIP ?= llvm-strip
+
+TOOLS_PATH := $(abspath ../../../../tools)
+BPFTOOL_SRC := $(TOOLS_PATH)/bpf/bpftool
+BPFTOOL_OUTPUT := $(abs_out)/bpftool
+DEFAULT_BPFTOOL := $(BPFTOOL_OUTPUT)/bootstrap/bpftool
+BPFTOOL ?= $(DEFAULT_BPFTOOL)
+
+LIBBPF_SRC := $(TOOLS_PATH)/lib/bpf
+LIBBPF_OUTPUT := $(abs_out)/libbpf
+LIBBPF_DESTDIR := $(LIBBPF_OUTPUT)
+LIBBPF_INCLUDE := $(LIBBPF_DESTDIR)/include
+BPFOBJ := $(LIBBPF_OUTPUT)/libbpf.a
+
+INCLUDES := -I$(OUTPUT) -I$(LIBBPF_INCLUDE) -I$(TOOLS_PATH)/include/uapi
+CFLAGS := -g -Wall
+
+VMLINUX_BTF_PATHS ?= $(if $(O),$(O)/vmlinux) \
+ $(if $(KBUILD_OUTPUT),$(KBUILD_OUTPUT)/vmlinux) \
+ ../../../../vmlinux \
+ /sys/kernel/btf/vmlinux \
+ /boot/vmlinux-$(shell uname -r)
+VMLINUX_BTF ?= $(abspath $(firstword $(wildcard $(VMLINUX_BTF_PATHS))))
+ifeq ($(VMLINUX_BTF),)
+$(error Cannot find a vmlinux for VMLINUX_BTF at any of "$(VMLINUX_BTF_PATHS)")
+endif
+
+ifeq ($(V),1)
+Q =
+msg =
+else
+Q = @
+msg = @printf ' %-8s %s%s\n' "$(1)" "$(notdir $(2))" "$(if $(3), $(3))";
+MAKEFLAGS += --no-print-directory
+submake_extras := feature_display=0
+endif
+
+.DELETE_ON_ERROR:
+
+.PHONY: all clean
+
+all: entrypoints.lskel.h
+
+clean:
+ $(call msg,CLEAN)
+ $(Q)rm -rf $(OUTPUT) entrypoints
+
+entrypoints.lskel.h: $(OUTPUT)/entrypoints.bpf.o | $(BPFTOOL)
+ $(call msg,GEN-SKEL,$@)
+ $(Q)$(BPFTOOL) gen skeleton -L $< > $@
+
+
+$(OUTPUT)/entrypoints.bpf.o: entrypoints.bpf.c $(OUTPUT)/vmlinux.h $(BPFOBJ) | $(OUTPUT)
+ $(call msg,BPF,$@)
+ $(Q)$(CLANG) -g -O2 -target bpf $(INCLUDES) \
+ -c $(filter %.c,$^) -o $@ && \
+ $(LLVM_STRIP) -g $@
+
+$(OUTPUT)/vmlinux.h: $(VMLINUX_BTF) $(BPFTOOL) | $(INCLUDE_DIR)
+ifeq ($(VMLINUX_H),)
+ $(call msg,GEN,,$@)
+ $(Q)$(BPFTOOL) btf dump file $(VMLINUX_BTF) format c > $@
+else
+ $(call msg,CP,,$@)
+ $(Q)cp "$(VMLINUX_H)" $@
+endif
+
+$(OUTPUT) $(LIBBPF_OUTPUT) $(BPFTOOL_OUTPUT):
+ $(call msg,MKDIR,$@)
+ $(Q)mkdir -p $@
+
+$(BPFOBJ): $(wildcard $(LIBBPF_SRC)/*.[ch] $(LIBBPF_SRC)/Makefile) | $(LIBBPF_OUTPUT)
+ $(Q)$(MAKE) $(submake_extras) -C $(LIBBPF_SRC) \
+ OUTPUT=$(abspath $(dir $@))/ prefix= \
+ DESTDIR=$(LIBBPF_DESTDIR) $(abspath $@) install_headers
+
+ifeq ($(CROSS_COMPILE),)
+$(DEFAULT_BPFTOOL): $(BPFOBJ) | $(BPFTOOL_OUTPUT)
+ $(Q)$(MAKE) $(submake_extras) -C $(BPFTOOL_SRC) \
+ OUTPUT=$(BPFTOOL_OUTPUT)/ \
+ LIBBPF_BOOTSTRAP_OUTPUT=$(LIBBPF_OUTPUT)/ \
+ LIBBPF_BOOTSTRAP_DESTDIR=$(LIBBPF_DESTDIR)/ bootstrap
+else
+$(DEFAULT_BPFTOOL): | $(BPFTOOL_OUTPUT)
+ $(Q)$(MAKE) $(submake_extras) -C $(BPFTOOL_SRC) \
+ OUTPUT=$(BPFTOOL_OUTPUT)/ bootstrap
+endif
diff --git a/drivers/hid/bpf/entrypoints/README b/drivers/hid/bpf/entrypoints/README
new file mode 100644
index 000000000000..147e0d41509f
--- /dev/null
+++ b/drivers/hid/bpf/entrypoints/README
@@ -0,0 +1,4 @@
+WARNING:
+If you change "entrypoints.bpf.c" do "make -j" in this directory to rebuild "entrypoints.skel.h".
+Make sure to have clang 10 installed.
+See Documentation/bpf/bpf_devel_QA.rst
diff --git a/drivers/hid/bpf/entrypoints/entrypoints.bpf.c b/drivers/hid/bpf/entrypoints/entrypoints.bpf.c
new file mode 100644
index 000000000000..c22921125a1a
--- /dev/null
+++ b/drivers/hid/bpf/entrypoints/entrypoints.bpf.c
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2022 Benjamin Tissoires */
+
+#include ".output/vmlinux.h"
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_tracing.h>
+
+#define HID_BPF_MAX_PROGS 1024
+
+struct {
+ __uint(type, BPF_MAP_TYPE_PROG_ARRAY);
+ __uint(max_entries, HID_BPF_MAX_PROGS);
+ __uint(key_size, sizeof(__u32));
+ __uint(value_size, sizeof(__u32));
+} hid_jmp_table SEC(".maps");
+
+SEC("fmod_ret/__hid_bpf_tail_call")
+int BPF_PROG(hid_tail_call, struct hid_bpf_ctx *hctx)
+{
+ bpf_tail_call(ctx, &hid_jmp_table, hctx->index);
+
+ return 0;
+}
+
+char LICENSE[] SEC("license") = "GPL";
diff --git a/drivers/hid/bpf/entrypoints/entrypoints.lskel.h b/drivers/hid/bpf/entrypoints/entrypoints.lskel.h
new file mode 100644
index 000000000000..35618051598c
--- /dev/null
+++ b/drivers/hid/bpf/entrypoints/entrypoints.lskel.h
@@ -0,0 +1,248 @@
+/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
+/* THIS FILE IS AUTOGENERATED BY BPFTOOL! */
+#ifndef __ENTRYPOINTS_BPF_SKEL_H__
+#define __ENTRYPOINTS_BPF_SKEL_H__
+
+#include <bpf/skel_internal.h>
+
+struct entrypoints_bpf {
+ struct bpf_loader_ctx ctx;
+ struct {
+ struct bpf_map_desc hid_jmp_table;
+ } maps;
+ struct {
+ struct bpf_prog_desc hid_tail_call;
+ } progs;
+ struct {
+ int hid_tail_call_fd;
+ } links;
+};
+
+static inline int
+entrypoints_bpf__hid_tail_call__attach(struct entrypoints_bpf *skel)
+{
+ int prog_fd = skel->progs.hid_tail_call.prog_fd;
+ int fd = skel_raw_tracepoint_open(NULL, prog_fd);
+
+ if (fd > 0)
+ skel->links.hid_tail_call_fd = fd;
+ return fd;
+}
+
+static inline int
+entrypoints_bpf__attach(struct entrypoints_bpf *skel)
+{
+ int ret = 0;
+
+ ret = ret < 0 ? ret : entrypoints_bpf__hid_tail_call__attach(skel);
+ return ret < 0 ? ret : 0;
+}
+
+static inline void
+entrypoints_bpf__detach(struct entrypoints_bpf *skel)
+{
+ skel_closenz(skel->links.hid_tail_call_fd);
+}
+static void
+entrypoints_bpf__destroy(struct entrypoints_bpf *skel)
+{
+ if (!skel)
+ return;
+ entrypoints_bpf__detach(skel);
+ skel_closenz(skel->progs.hid_tail_call.prog_fd);
+ skel_closenz(skel->maps.hid_jmp_table.map_fd);
+ skel_free(skel);
+}
+static inline struct entrypoints_bpf *
+entrypoints_bpf__open(void)
+{
+ struct entrypoints_bpf *skel;
+
+ skel = skel_alloc(sizeof(*skel));
+ if (!skel)
+ goto cleanup;
+ skel->ctx.sz = (void *)&skel->links - (void *)skel;
+ return skel;
+cleanup:
+ entrypoints_bpf__destroy(skel);
+ return NULL;
+}
+
+static inline int
+entrypoints_bpf__load(struct entrypoints_bpf *skel)
+{
+ struct bpf_load_and_run_opts opts = {};
+ int err;
+
+ opts.ctx = (struct bpf_loader_ctx *)skel;
+ opts.data_sz = 2856;
+ opts.data = (void *)"\
+\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\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\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\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\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\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\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\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\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\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\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\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\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\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\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\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\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\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\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\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\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\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\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\x9f\xeb\x01\0\
+\x18\0\0\0\0\0\0\0\x60\x02\0\0\x60\x02\0\0\x12\x02\0\0\0\0\0\0\0\0\0\x02\x03\0\
+\0\0\x01\0\0\0\0\0\0\x01\x04\0\0\0\x20\0\0\x01\0\0\0\0\0\0\0\x03\0\0\0\0\x02\0\
+\0\0\x04\0\0\0\x03\0\0\0\x05\0\0\0\0\0\0\x01\x04\0\0\0\x20\0\0\0\0\0\0\0\0\0\0\
+\x02\x06\0\0\0\0\0\0\0\0\0\0\x03\0\0\0\0\x02\0\0\0\x04\0\0\0\0\x04\0\0\0\0\0\0\
+\0\0\0\x02\x08\0\0\0\0\0\0\0\0\0\0\x03\0\0\0\0\x02\0\0\0\x04\0\0\0\x04\0\0\0\0\
+\0\0\0\x04\0\0\x04\x20\0\0\0\x19\0\0\0\x01\0\0\0\0\0\0\0\x1e\0\0\0\x05\0\0\0\
+\x40\0\0\0\x2a\0\0\0\x07\0\0\0\x80\0\0\0\x33\0\0\0\x07\0\0\0\xc0\0\0\0\x3e\0\0\
+\0\0\0\0\x0e\x09\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\x02\x0c\0\0\0\x4c\0\0\0\0\0\0\
+\x01\x08\0\0\0\x40\0\0\0\0\0\0\0\x01\0\0\x0d\x02\0\0\0\x5f\0\0\0\x0b\0\0\0\x63\
+\0\0\0\x01\0\0\x0c\x0d\0\0\0\x09\x01\0\0\x05\0\0\x04\x20\0\0\0\x15\x01\0\0\x10\
+\0\0\0\0\0\0\0\x1b\x01\0\0\x12\0\0\0\x40\0\0\0\x1f\x01\0\0\x10\0\0\0\x80\0\0\0\
+\x2e\x01\0\0\x14\0\0\0\xa0\0\0\0\0\0\0\0\x15\0\0\0\xc0\0\0\0\x3a\x01\0\0\0\0\0\
+\x08\x11\0\0\0\x40\x01\0\0\0\0\0\x01\x04\0\0\0\x20\0\0\0\0\0\0\0\0\0\0\x02\x13\
+\0\0\0\0\0\0\0\0\0\0\x0a\x1c\0\0\0\x4d\x01\0\0\x04\0\0\x06\x04\0\0\0\x5d\x01\0\
+\0\0\0\0\0\x6e\x01\0\0\x01\0\0\0\x80\x01\0\0\x02\0\0\0\x93\x01\0\0\x03\0\0\0\0\
+\0\0\0\x02\0\0\x05\x04\0\0\0\xa4\x01\0\0\x16\0\0\0\0\0\0\0\xab\x01\0\0\x16\0\0\
+\0\0\0\0\0\xb0\x01\0\0\0\0\0\x08\x02\0\0\0\xec\x01\0\0\0\0\0\x01\x01\0\0\0\x08\
+\0\0\x01\0\0\0\0\0\0\0\x03\0\0\0\0\x17\0\0\0\x04\0\0\0\x04\0\0\0\xf1\x01\0\0\0\
+\0\0\x0e\x18\0\0\0\x01\0\0\0\xf9\x01\0\0\x01\0\0\x0f\x20\0\0\0\x0a\0\0\0\0\0\0\
+\0\x20\0\0\0\xff\x01\0\0\x01\0\0\x0f\x04\0\0\0\x19\0\0\0\0\0\0\0\x04\0\0\0\x07\
+\x02\0\0\0\0\0\x07\0\0\0\0\0\x69\x6e\x74\0\x5f\x5f\x41\x52\x52\x41\x59\x5f\x53\
+\x49\x5a\x45\x5f\x54\x59\x50\x45\x5f\x5f\0\x74\x79\x70\x65\0\x6d\x61\x78\x5f\
+\x65\x6e\x74\x72\x69\x65\x73\0\x6b\x65\x79\x5f\x73\x69\x7a\x65\0\x76\x61\x6c\
+\x75\x65\x5f\x73\x69\x7a\x65\0\x68\x69\x64\x5f\x6a\x6d\x70\x5f\x74\x61\x62\x6c\
+\x65\0\x75\x6e\x73\x69\x67\x6e\x65\x64\x20\x6c\x6f\x6e\x67\x20\x6c\x6f\x6e\x67\
+\0\x63\x74\x78\0\x68\x69\x64\x5f\x74\x61\x69\x6c\x5f\x63\x61\x6c\x6c\0\x66\x6d\
+\x6f\x64\x5f\x72\x65\x74\x2f\x5f\x5f\x68\x69\x64\x5f\x62\x70\x66\x5f\x74\x61\
+\x69\x6c\x5f\x63\x61\x6c\x6c\0\x2f\x68\x6f\x6d\x65\x2f\x62\x74\x69\x73\x73\x6f\
+\x69\x72\x2f\x53\x72\x63\x2f\x68\x69\x64\x2f\x64\x72\x69\x76\x65\x72\x73\x2f\
+\x68\x69\x64\x2f\x62\x70\x66\x2f\x65\x6e\x74\x72\x79\x70\x6f\x69\x6e\x74\x73\
+\x2f\x65\x6e\x74\x72\x79\x70\x6f\x69\x6e\x74\x73\x2e\x62\x70\x66\x2e\x63\0\x69\
+\x6e\x74\x20\x42\x50\x46\x5f\x50\x52\x4f\x47\x28\x68\x69\x64\x5f\x74\x61\x69\
+\x6c\x5f\x63\x61\x6c\x6c\x2c\x20\x73\x74\x72\x75\x63\x74\x20\x68\x69\x64\x5f\
+\x62\x70\x66\x5f\x63\x74\x78\x20\x2a\x68\x63\x74\x78\x29\0\x68\x69\x64\x5f\x62\
+\x70\x66\x5f\x63\x74\x78\0\x69\x6e\x64\x65\x78\0\x68\x69\x64\0\x61\x6c\x6c\x6f\
+\x63\x61\x74\x65\x64\x5f\x73\x69\x7a\x65\0\x72\x65\x70\x6f\x72\x74\x5f\x74\x79\
+\x70\x65\0\x5f\x5f\x75\x33\x32\0\x75\x6e\x73\x69\x67\x6e\x65\x64\x20\x69\x6e\
+\x74\0\x68\x69\x64\x5f\x72\x65\x70\x6f\x72\x74\x5f\x74\x79\x70\x65\0\x48\x49\
+\x44\x5f\x49\x4e\x50\x55\x54\x5f\x52\x45\x50\x4f\x52\x54\0\x48\x49\x44\x5f\x4f\
+\x55\x54\x50\x55\x54\x5f\x52\x45\x50\x4f\x52\x54\0\x48\x49\x44\x5f\x46\x45\x41\
+\x54\x55\x52\x45\x5f\x52\x45\x50\x4f\x52\x54\0\x48\x49\x44\x5f\x52\x45\x50\x4f\
+\x52\x54\x5f\x54\x59\x50\x45\x53\0\x72\x65\x74\x76\x61\x6c\0\x73\x69\x7a\x65\0\
+\x5f\x5f\x73\x33\x32\0\x30\x3a\x30\0\x09\x62\x70\x66\x5f\x74\x61\x69\x6c\x5f\
+\x63\x61\x6c\x6c\x28\x63\x74\x78\x2c\x20\x26\x68\x69\x64\x5f\x6a\x6d\x70\x5f\
+\x74\x61\x62\x6c\x65\x2c\x20\x68\x63\x74\x78\x2d\x3e\x69\x6e\x64\x65\x78\x29\
+\x3b\0\x63\x68\x61\x72\0\x4c\x49\x43\x45\x4e\x53\x45\0\x2e\x6d\x61\x70\x73\0\
+\x6c\x69\x63\x65\x6e\x73\x65\0\x68\x69\x64\x5f\x64\x65\x76\x69\x63\x65\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8a\x04\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x03\
+\0\0\0\x04\0\0\0\x04\0\0\0\0\x04\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x68\x69\x64\x5f\
+\x6a\x6d\x70\x5f\x74\x61\x62\x6c\x65\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\x47\x50\x4c\0\0\0\0\0\x79\x12\0\0\0\0\0\0\x61\x23\0\0\0\0\
+\0\0\x18\x52\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x85\0\0\0\x0c\0\0\0\xb7\0\0\0\0\0\0\0\
+\x95\0\0\0\0\0\0\0\0\0\0\0\x0e\0\0\0\0\0\0\0\x8e\0\0\0\xd3\0\0\0\x05\x48\0\0\
+\x01\0\0\0\x8e\0\0\0\xba\x01\0\0\x02\x50\0\0\x05\0\0\0\x8e\0\0\0\xd3\0\0\0\x05\
+\x48\0\0\x08\0\0\0\x0f\0\0\0\xb6\x01\0\0\0\0\0\0\x1a\0\0\0\x07\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\x68\x69\
+\x64\x5f\x74\x61\x69\x6c\x5f\x63\x61\x6c\x6c\0\0\0\0\0\0\0\x1a\0\0\0\0\0\0\0\
+\x08\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\x10\0\0\0\0\0\0\0\0\0\0\0\x03\0\0\0\x01\0\
+\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x10\0\0\0\0\0\0\0\x5f\
+\x5f\x68\x69\x64\x5f\x62\x70\x66\x5f\x74\x61\x69\x6c\x5f\x63\x61\x6c\x6c\0\0\0\
+\0\0";
+ opts.insns_sz = 1192;
+ opts.insns = (void *)"\
+\xbf\x16\0\0\0\0\0\0\xbf\xa1\0\0\0\0\0\0\x07\x01\0\0\x78\xff\xff\xff\xb7\x02\0\
+\0\x88\0\0\0\xb7\x03\0\0\0\0\0\0\x85\0\0\0\x71\0\0\0\x05\0\x11\0\0\0\0\0\x61\
+\xa1\x78\xff\0\0\0\0\xd5\x01\x01\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x61\xa1\x7c\xff\
+\0\0\0\0\xd5\x01\x01\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x61\xa1\x80\xff\0\0\0\0\xd5\
+\x01\x01\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x61\
+\x01\0\0\0\0\0\0\xd5\x01\x02\0\0\0\0\0\xbf\x19\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\
+\xbf\x70\0\0\0\0\0\0\x95\0\0\0\0\0\0\0\x61\x60\x08\0\0\0\0\0\x18\x61\0\0\0\0\0\
+\0\0\0\0\0\xa8\x09\0\0\x63\x01\0\0\0\0\0\0\x61\x60\x0c\0\0\0\0\0\x18\x61\0\0\0\
+\0\0\0\0\0\0\0\xa4\x09\0\0\x63\x01\0\0\0\0\0\0\x79\x60\x10\0\0\0\0\0\x18\x61\0\
+\0\0\0\0\0\0\0\0\0\x98\x09\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\
+\0\x05\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x90\x09\0\0\x7b\x01\0\0\0\0\0\0\xb7\x01\
+\0\0\x12\0\0\0\x18\x62\0\0\0\0\0\0\0\0\0\0\x90\x09\0\0\xb7\x03\0\0\x1c\0\0\0\
+\x85\0\0\0\xa6\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\xd7\xff\0\0\0\0\x63\x7a\x78\
+\xff\0\0\0\0\x61\x60\x1c\0\0\0\0\0\x15\0\x03\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\
+\0\0\xbc\x09\0\0\x63\x01\0\0\0\0\0\0\xb7\x01\0\0\0\0\0\0\x18\x62\0\0\0\0\0\0\0\
+\0\0\0\xb0\x09\0\0\xb7\x03\0\0\x48\0\0\0\x85\0\0\0\xa6\0\0\0\xbf\x07\0\0\0\0\0\
+\0\xc5\x07\xca\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x63\x71\0\0\0\0\
+\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\xf8\x09\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x90\
+\x0a\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\0\x0a\0\0\x18\x61\0\0\
+\0\0\0\0\0\0\0\0\x88\x0a\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\
+\x38\x0a\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xd0\x0a\0\0\x7b\x01\0\0\0\0\0\0\x18\
+\x60\0\0\0\0\0\0\0\0\0\0\x40\x0a\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xe0\x0a\0\0\
+\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x70\x0a\0\0\x18\x61\0\0\0\0\0\
+\0\0\0\0\0\0\x0b\0\0\x7b\x01\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\x18\x61\0\0\0\0\0\0\0\0\0\0\xf8\x0a\0\0\x7b\x01\0\0\0\0\0\0\x61\x60\x08\0\0\0\
+\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x98\x0a\0\0\x63\x01\0\0\0\0\0\0\x61\x60\x0c\0\
+\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x9c\x0a\0\0\x63\x01\0\0\0\0\0\0\x79\x60\
+\x10\0\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xa0\x0a\0\0\x7b\x01\0\0\0\0\0\0\x61\
+\xa0\x78\xff\0\0\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\xc8\x0a\0\0\x63\x01\0\0\0\0\0\
+\0\x18\x61\0\0\0\0\0\0\0\0\0\0\x10\x0b\0\0\xb7\x02\0\0\x14\0\0\0\xb7\x03\0\0\
+\x0c\0\0\0\xb7\x04\0\0\0\0\0\0\x85\0\0\0\xa7\0\0\0\xbf\x07\0\0\0\0\0\0\xc5\x07\
+\x91\xff\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\x80\x0a\0\0\x63\x70\x6c\0\0\0\0\0\
+\x77\x07\0\0\x20\0\0\0\x63\x70\x70\0\0\0\0\0\xb7\x01\0\0\x05\0\0\0\x18\x62\0\0\
+\0\0\0\0\0\0\0\0\x80\x0a\0\0\xb7\x03\0\0\x8c\0\0\0\x85\0\0\0\xa6\0\0\0\xbf\x07\
+\0\0\0\0\0\0\x18\x60\0\0\0\0\0\0\0\0\0\0\xf0\x0a\0\0\x61\x01\0\0\0\0\0\0\xd5\
+\x01\x02\0\0\0\0\0\xbf\x19\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\xc5\x07\x7f\xff\0\0\
+\0\0\x63\x7a\x80\xff\0\0\0\0\x61\xa1\x78\xff\0\0\0\0\xd5\x01\x02\0\0\0\0\0\xbf\
+\x19\0\0\0\0\0\0\x85\0\0\0\xa8\0\0\0\x61\xa0\x80\xff\0\0\0\0\x63\x06\x28\0\0\0\
+\0\0\x18\x61\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x61\x10\0\0\0\0\0\0\x63\x06\x18\0\0\0\
+\0\0\xb7\0\0\0\0\0\0\0\x95\0\0\0\0\0\0\0";
+ err = bpf_load_and_run(&opts);
+ if (err < 0)
+ return err;
+ return 0;
+}
+
+static inline struct entrypoints_bpf *
+entrypoints_bpf__open_and_load(void)
+{
+ struct entrypoints_bpf *skel;
+
+ skel = entrypoints_bpf__open();
+ if (!skel)
+ return NULL;
+ if (entrypoints_bpf__load(skel)) {
+ entrypoints_bpf__destroy(skel);
+ return NULL;
+ }
+ return skel;
+}
+
+__attribute__((unused)) static void
+entrypoints_bpf__assert(struct entrypoints_bpf *s __attribute__((unused)))
+{
+#ifdef __cplusplus
+#define _Static_assert static_assert
+#endif
+#ifdef __cplusplus
+#undef _Static_assert
+#endif
+}
+
+#endif /* __ENTRYPOINTS_BPF_SKEL_H__ */
diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c
new file mode 100644
index 000000000000..8a034a555d4c
--- /dev/null
+++ b/drivers/hid/bpf/hid_bpf_dispatch.c
@@ -0,0 +1,551 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/*
+ * HID-BPF support for Linux
+ *
+ * Copyright (c) 2022 Benjamin Tissoires
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/bitops.h>
+#include <linux/btf.h>
+#include <linux/btf_ids.h>
+#include <linux/filter.h>
+#include <linux/hid.h>
+#include <linux/hid_bpf.h>
+#include <linux/init.h>
+#include <linux/kfifo.h>
+#include <linux/minmax.h>
+#include <linux/module.h>
+#include <linux/workqueue.h>
+#include "hid_bpf_dispatch.h"
+#include "entrypoints/entrypoints.lskel.h"
+
+struct hid_bpf_ops *hid_bpf_ops;
+EXPORT_SYMBOL(hid_bpf_ops);
+
+/**
+ * hid_bpf_device_event - Called whenever an event is coming in from the device
+ *
+ * @ctx: The HID-BPF context
+ *
+ * @return %0 on success and keep processing; a positive value to change the
+ * incoming size buffer; a negative error code to interrupt the processing
+ * of this event
+ *
+ * Declare an %fmod_ret tracing bpf program to this function and attach this
+ * program through hid_bpf_attach_prog() to have this helper called for
+ * any incoming event from the device itself.
+ *
+ * The function is called while on IRQ context, so we can not sleep.
+ */
+/* never used by the kernel but declared so we can load and attach a tracepoint */
+__weak noinline int hid_bpf_device_event(struct hid_bpf_ctx *ctx)
+{
+ return 0;
+}
+
+u8 *
+dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type, u8 *data,
+ u32 *size, int interrupt)
+{
+ struct hid_bpf_ctx_kern ctx_kern = {
+ .ctx = {
+ .hid = hdev,
+ .report_type = type,
+ .allocated_size = hdev->bpf.allocated_data,
+ .size = *size,
+ },
+ .data = hdev->bpf.device_data,
+ };
+ int ret;
+
+ if (type >= HID_REPORT_TYPES)
+ return ERR_PTR(-EINVAL);
+
+ /* no program has been attached yet */
+ if (!hdev->bpf.device_data)
+ return data;
+
+ memset(ctx_kern.data, 0, hdev->bpf.allocated_data);
+ memcpy(ctx_kern.data, data, *size);
+
+ ret = hid_bpf_prog_run(hdev, HID_BPF_PROG_TYPE_DEVICE_EVENT, &ctx_kern);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ if (ret) {
+ if (ret > ctx_kern.ctx.allocated_size)
+ return ERR_PTR(-EINVAL);
+
+ *size = ret;
+ }
+
+ return ctx_kern.data;
+}
+EXPORT_SYMBOL_GPL(dispatch_hid_bpf_device_event);
+
+/**
+ * hid_bpf_rdesc_fixup - Called when the probe function parses the report
+ * descriptor of the HID device
+ *
+ * @ctx: The HID-BPF context
+ *
+ * @return 0 on success and keep processing; a positive value to change the
+ * incoming size buffer; a negative error code to interrupt the processing
+ * of this event
+ *
+ * Declare an %fmod_ret tracing bpf program to this function and attach this
+ * program through hid_bpf_attach_prog() to have this helper called before any
+ * parsing of the report descriptor by HID.
+ */
+/* never used by the kernel but declared so we can load and attach a tracepoint */
+__weak noinline int hid_bpf_rdesc_fixup(struct hid_bpf_ctx *ctx)
+{
+ return 0;
+}
+
+u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *size)
+{
+ int ret;
+ struct hid_bpf_ctx_kern ctx_kern = {
+ .ctx = {
+ .hid = hdev,
+ .size = *size,
+ .allocated_size = HID_MAX_DESCRIPTOR_SIZE,
+ },
+ };
+
+ ctx_kern.data = kzalloc(ctx_kern.ctx.allocated_size, GFP_KERNEL);
+ if (!ctx_kern.data)
+ goto ignore_bpf;
+
+ memcpy(ctx_kern.data, rdesc, min_t(unsigned int, *size, HID_MAX_DESCRIPTOR_SIZE));
+
+ ret = hid_bpf_prog_run(hdev, HID_BPF_PROG_TYPE_RDESC_FIXUP, &ctx_kern);
+ if (ret < 0)
+ goto ignore_bpf;
+
+ if (ret) {
+ if (ret > ctx_kern.ctx.allocated_size)
+ goto ignore_bpf;
+
+ *size = ret;
+ }
+
+ rdesc = krealloc(ctx_kern.data, *size, GFP_KERNEL);
+
+ return rdesc;
+
+ ignore_bpf:
+ kfree(ctx_kern.data);
+ return kmemdup(rdesc, *size, GFP_KERNEL);
+}
+EXPORT_SYMBOL_GPL(call_hid_bpf_rdesc_fixup);
+
+/**
+ * hid_bpf_get_data - Get the kernel memory pointer associated with the context @ctx
+ *
+ * @ctx: The HID-BPF context
+ * @offset: The offset within the memory
+ * @rdwr_buf_size: the const size of the buffer
+ *
+ * @returns %NULL on error, an %__u8 memory pointer on success
+ */
+noinline __u8 *
+hid_bpf_get_data(struct hid_bpf_ctx *ctx, unsigned int offset, const size_t rdwr_buf_size)
+{
+ struct hid_bpf_ctx_kern *ctx_kern;
+
+ if (!ctx)
+ return NULL;
+
+ ctx_kern = container_of(ctx, struct hid_bpf_ctx_kern, ctx);
+
+ if (rdwr_buf_size + offset > ctx->allocated_size)
+ return NULL;
+
+ return ctx_kern->data + offset;
+}
+
+/*
+ * The following set contains all functions we agree BPF programs
+ * can use.
+ */
+BTF_SET8_START(hid_bpf_kfunc_ids)
+BTF_ID_FLAGS(func, hid_bpf_get_data, KF_RET_NULL)
+BTF_SET8_END(hid_bpf_kfunc_ids)
+
+static const struct btf_kfunc_id_set hid_bpf_kfunc_set = {
+ .owner = THIS_MODULE,
+ .set = &hid_bpf_kfunc_ids,
+};
+
+static int device_match_id(struct device *dev, const void *id)
+{
+ struct hid_device *hdev = to_hid_device(dev);
+
+ return hdev->id == *(int *)id;
+}
+
+static int __hid_bpf_allocate_data(struct hid_device *hdev, u8 **data, u32 *size)
+{
+ u8 *alloc_data;
+ unsigned int i, j, max_report_len = 0;
+ size_t alloc_size = 0;
+
+ /* compute the maximum report length for this device */
+ for (i = 0; i < HID_REPORT_TYPES; i++) {
+ struct hid_report_enum *report_enum = hdev->report_enum + i;
+
+ for (j = 0; j < HID_MAX_IDS; j++) {
+ struct hid_report *report = report_enum->report_id_hash[j];
+
+ if (report)
+ max_report_len = max(max_report_len, hid_report_len(report));
+ }
+ }
+
+ /*
+ * Give us a little bit of extra space and some predictability in the
+ * buffer length we create. This way, we can tell users that they can
+ * work on chunks of 64 bytes of memory without having the bpf verifier
+ * scream at them.
+ */
+ alloc_size = DIV_ROUND_UP(max_report_len, 64) * 64;
+
+ alloc_data = kzalloc(alloc_size, GFP_KERNEL);
+ if (!alloc_data)
+ return -ENOMEM;
+
+ *data = alloc_data;
+ *size = alloc_size;
+
+ return 0;
+}
+
+static int hid_bpf_allocate_event_data(struct hid_device *hdev)
+{
+ /* hdev->bpf.device_data is already allocated, abort */
+ if (hdev->bpf.device_data)
+ return 0;
+
+ return __hid_bpf_allocate_data(hdev, &hdev->bpf.device_data, &hdev->bpf.allocated_data);
+}
+
+int hid_bpf_reconnect(struct hid_device *hdev)
+{
+ if (!test_and_set_bit(ffs(HID_STAT_REPROBED), &hdev->status))
+ return device_reprobe(&hdev->dev);
+
+ return 0;
+}
+
+/**
+ * hid_bpf_attach_prog - Attach the given @prog_fd to the given HID device
+ *
+ * @hid_id: the system unique identifier of the HID device
+ * @prog_fd: an fd in the user process representing the program to attach
+ * @flags: any logical OR combination of &enum hid_bpf_attach_flags
+ *
+ * @returns an fd of a bpf_link object on success (> %0), an error code otherwise.
+ * Closing this fd will detach the program from the HID device (unless the bpf_link
+ * is pinned to the BPF file system).
+ */
+/* called from syscall */
+noinline int
+hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags)
+{
+ struct hid_device *hdev;
+ struct device *dev;
+ int fd, err, prog_type = hid_bpf_get_prog_attach_type(prog_fd);
+
+ if (!hid_bpf_ops)
+ return -EINVAL;
+
+ if (prog_type < 0)
+ return prog_type;
+
+ if (prog_type >= HID_BPF_PROG_TYPE_MAX)
+ return -EINVAL;
+
+ if ((flags & ~HID_BPF_FLAG_MASK))
+ return -EINVAL;
+
+ dev = bus_find_device(hid_bpf_ops->bus_type, NULL, &hid_id, device_match_id);
+ if (!dev)
+ return -EINVAL;
+
+ hdev = to_hid_device(dev);
+
+ if (prog_type == HID_BPF_PROG_TYPE_DEVICE_EVENT) {
+ err = hid_bpf_allocate_event_data(hdev);
+ if (err)
+ return err;
+ }
+
+ fd = __hid_bpf_attach_prog(hdev, prog_type, prog_fd, flags);
+ if (fd < 0)
+ return fd;
+
+ if (prog_type == HID_BPF_PROG_TYPE_RDESC_FIXUP) {
+ err = hid_bpf_reconnect(hdev);
+ if (err) {
+ close_fd(fd);
+ return err;
+ }
+ }
+
+ return fd;
+}
+
+/**
+ * hid_bpf_allocate_context - Allocate a context to the given HID device
+ *
+ * @hid_id: the system unique identifier of the HID device
+ *
+ * @returns A pointer to &struct hid_bpf_ctx on success, %NULL on error.
+ */
+noinline struct hid_bpf_ctx *
+hid_bpf_allocate_context(unsigned int hid_id)
+{
+ struct hid_device *hdev;
+ struct hid_bpf_ctx_kern *ctx_kern = NULL;
+ struct device *dev;
+
+ if (!hid_bpf_ops)
+ return NULL;
+
+ dev = bus_find_device(hid_bpf_ops->bus_type, NULL, &hid_id, device_match_id);
+ if (!dev)
+ return NULL;
+
+ hdev = to_hid_device(dev);
+
+ ctx_kern = kzalloc(sizeof(*ctx_kern), GFP_KERNEL);
+ if (!ctx_kern)
+ return NULL;
+
+ ctx_kern->ctx.hid = hdev;
+
+ return &ctx_kern->ctx;
+}
+
+/**
+ * hid_bpf_release_context - Release the previously allocated context @ctx
+ *
+ * @ctx: the HID-BPF context to release
+ *
+ */
+noinline void
+hid_bpf_release_context(struct hid_bpf_ctx *ctx)
+{
+ struct hid_bpf_ctx_kern *ctx_kern;
+
+ if (!ctx)
+ return;
+
+ ctx_kern = container_of(ctx, struct hid_bpf_ctx_kern, ctx);
+
+ kfree(ctx_kern);
+}
+
+/**
+ * hid_bpf_hw_request - Communicate with a HID device
+ *
+ * @ctx: the HID-BPF context previously allocated in hid_bpf_allocate_context()
+ * @buf: a %PTR_TO_MEM buffer
+ * @buf__sz: the size of the data to transfer
+ * @rtype: the type of the report (%HID_INPUT_REPORT, %HID_FEATURE_REPORT, %HID_OUTPUT_REPORT)
+ * @reqtype: the type of the request (%HID_REQ_GET_REPORT, %HID_REQ_SET_REPORT, ...)
+ *
+ * @returns %0 on success, a negative error code otherwise.
+ */
+noinline int
+hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz,
+ enum hid_report_type rtype, enum hid_class_request reqtype)
+{
+ struct hid_device *hdev;
+ struct hid_report *report;
+ struct hid_report_enum *report_enum;
+ u8 *dma_data;
+ u32 report_len;
+ int ret;
+
+ /* check arguments */
+ if (!ctx || !hid_bpf_ops || !buf)
+ return -EINVAL;
+
+ switch (rtype) {
+ case HID_INPUT_REPORT:
+ case HID_OUTPUT_REPORT:
+ case HID_FEATURE_REPORT:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (reqtype) {
+ case HID_REQ_GET_REPORT:
+ case HID_REQ_GET_IDLE:
+ case HID_REQ_GET_PROTOCOL:
+ case HID_REQ_SET_REPORT:
+ case HID_REQ_SET_IDLE:
+ case HID_REQ_SET_PROTOCOL:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (buf__sz < 1)
+ return -EINVAL;
+
+ hdev = (struct hid_device *)ctx->hid; /* discard const */
+
+ report_enum = hdev->report_enum + rtype;
+ report = hid_bpf_ops->hid_get_report(report_enum, buf);
+ if (!report)
+ return -EINVAL;
+
+ report_len = hid_report_len(report);
+
+ if (buf__sz > report_len)
+ buf__sz = report_len;
+
+ dma_data = kmemdup(buf, buf__sz, GFP_KERNEL);
+ if (!dma_data)
+ return -ENOMEM;
+
+ ret = hid_bpf_ops->hid_hw_raw_request(hdev,
+ dma_data[0],
+ dma_data,
+ buf__sz,
+ rtype,
+ reqtype);
+
+ if (ret > 0)
+ memcpy(buf, dma_data, ret);
+
+ kfree(dma_data);
+ return ret;
+}
+
+/* our HID-BPF entrypoints */
+BTF_SET8_START(hid_bpf_fmodret_ids)
+BTF_ID_FLAGS(func, hid_bpf_device_event)
+BTF_ID_FLAGS(func, hid_bpf_rdesc_fixup)
+BTF_ID_FLAGS(func, __hid_bpf_tail_call)
+BTF_SET8_END(hid_bpf_fmodret_ids)
+
+static const struct btf_kfunc_id_set hid_bpf_fmodret_set = {
+ .owner = THIS_MODULE,
+ .set = &hid_bpf_fmodret_ids,
+};
+
+/* for syscall HID-BPF */
+BTF_SET8_START(hid_bpf_syscall_kfunc_ids)
+BTF_ID_FLAGS(func, hid_bpf_attach_prog)
+BTF_ID_FLAGS(func, hid_bpf_allocate_context, KF_ACQUIRE | KF_RET_NULL)
+BTF_ID_FLAGS(func, hid_bpf_release_context, KF_RELEASE)
+BTF_ID_FLAGS(func, hid_bpf_hw_request)
+BTF_SET8_END(hid_bpf_syscall_kfunc_ids)
+
+static const struct btf_kfunc_id_set hid_bpf_syscall_kfunc_set = {
+ .owner = THIS_MODULE,
+ .set = &hid_bpf_syscall_kfunc_ids,
+};
+
+int hid_bpf_connect_device(struct hid_device *hdev)
+{
+ struct hid_bpf_prog_list *prog_list;
+
+ rcu_read_lock();
+ prog_list = rcu_dereference(hdev->bpf.progs[HID_BPF_PROG_TYPE_DEVICE_EVENT]);
+ rcu_read_unlock();
+
+ /* only allocate BPF data if there are programs attached */
+ if (!prog_list)
+ return 0;
+
+ return hid_bpf_allocate_event_data(hdev);
+}
+EXPORT_SYMBOL_GPL(hid_bpf_connect_device);
+
+void hid_bpf_disconnect_device(struct hid_device *hdev)
+{
+ kfree(hdev->bpf.device_data);
+ hdev->bpf.device_data = NULL;
+ hdev->bpf.allocated_data = 0;
+}
+EXPORT_SYMBOL_GPL(hid_bpf_disconnect_device);
+
+void hid_bpf_destroy_device(struct hid_device *hdev)
+{
+ if (!hdev)
+ return;
+
+ /* mark the device as destroyed in bpf so we don't reattach it */
+ hdev->bpf.destroyed = true;
+
+ __hid_bpf_destroy_device(hdev);
+}
+EXPORT_SYMBOL_GPL(hid_bpf_destroy_device);
+
+void hid_bpf_device_init(struct hid_device *hdev)
+{
+ spin_lock_init(&hdev->bpf.progs_lock);
+}
+EXPORT_SYMBOL_GPL(hid_bpf_device_init);
+
+static int __init hid_bpf_init(void)
+{
+ int err;
+
+ /* Note: if we exit with an error any time here, we would entirely break HID, which
+ * is probably not something we want. So we log an error and return success.
+ *
+ * This is not a big deal: the syscall allowing to attach a BPF program to a HID device
+ * will not be available, so nobody will be able to use the functionality.
+ */
+
+ err = register_btf_fmodret_id_set(&hid_bpf_fmodret_set);
+ if (err) {
+ pr_warn("error while registering fmodret entrypoints: %d", err);
+ return 0;
+ }
+
+ err = hid_bpf_preload_skel();
+ if (err) {
+ pr_warn("error while preloading HID BPF dispatcher: %d", err);
+ return 0;
+ }
+
+ /* register tracing kfuncs after we are sure we can load our preloaded bpf program */
+ err = register_btf_kfunc_id_set(BPF_PROG_TYPE_TRACING, &hid_bpf_kfunc_set);
+ if (err) {
+ pr_warn("error while setting HID BPF tracing kfuncs: %d", err);
+ return 0;
+ }
+
+ /* register syscalls after we are sure we can load our preloaded bpf program */
+ err = register_btf_kfunc_id_set(BPF_PROG_TYPE_SYSCALL, &hid_bpf_syscall_kfunc_set);
+ if (err) {
+ pr_warn("error while setting HID BPF syscall kfuncs: %d", err);
+ return 0;
+ }
+
+ return 0;
+}
+
+static void __exit hid_bpf_exit(void)
+{
+ /* HID depends on us, so if we hit that code, we are guaranteed that hid
+ * has been removed and thus we do not need to clear the HID devices
+ */
+ hid_bpf_free_links_and_skel();
+}
+
+late_initcall(hid_bpf_init);
+module_exit(hid_bpf_exit);
+MODULE_AUTHOR("Benjamin Tissoires");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/bpf/hid_bpf_dispatch.h b/drivers/hid/bpf/hid_bpf_dispatch.h
new file mode 100644
index 000000000000..63dfc8605cd2
--- /dev/null
+++ b/drivers/hid/bpf/hid_bpf_dispatch.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _BPF_HID_BPF_DISPATCH_H
+#define _BPF_HID_BPF_DISPATCH_H
+
+#include <linux/hid.h>
+
+struct hid_bpf_ctx_kern {
+ struct hid_bpf_ctx ctx;
+ u8 *data;
+};
+
+int hid_bpf_preload_skel(void);
+void hid_bpf_free_links_and_skel(void);
+int hid_bpf_get_prog_attach_type(int prog_fd);
+int __hid_bpf_attach_prog(struct hid_device *hdev, enum hid_bpf_prog_type prog_type, int prog_fd,
+ __u32 flags);
+void __hid_bpf_destroy_device(struct hid_device *hdev);
+int hid_bpf_prog_run(struct hid_device *hdev, enum hid_bpf_prog_type type,
+ struct hid_bpf_ctx_kern *ctx_kern);
+int hid_bpf_reconnect(struct hid_device *hdev);
+
+struct bpf_prog;
+
+#endif
diff --git a/drivers/hid/bpf/hid_bpf_jmp_table.c b/drivers/hid/bpf/hid_bpf_jmp_table.c
new file mode 100644
index 000000000000..eca34b7372f9
--- /dev/null
+++ b/drivers/hid/bpf/hid_bpf_jmp_table.c
@@ -0,0 +1,565 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/*
+ * HID-BPF support for Linux
+ *
+ * Copyright (c) 2022 Benjamin Tissoires
+ */
+
+#include <linux/bitops.h>
+#include <linux/btf.h>
+#include <linux/btf_ids.h>
+#include <linux/circ_buf.h>
+#include <linux/filter.h>
+#include <linux/hid.h>
+#include <linux/hid_bpf.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/workqueue.h>
+#include "hid_bpf_dispatch.h"
+#include "entrypoints/entrypoints.lskel.h"
+
+#define HID_BPF_MAX_PROGS 1024 /* keep this in sync with preloaded bpf,
+ * needs to be a power of 2 as we use it as
+ * a circular buffer
+ */
+
+#define NEXT(idx) (((idx) + 1) & (HID_BPF_MAX_PROGS - 1))
+#define PREV(idx) (((idx) - 1) & (HID_BPF_MAX_PROGS - 1))
+
+/*
+ * represents one attached program stored in the hid jump table
+ */
+struct hid_bpf_prog_entry {
+ struct bpf_prog *prog;
+ struct hid_device *hdev;
+ enum hid_bpf_prog_type type;
+ u16 idx;
+};
+
+struct hid_bpf_jmp_table {
+ struct bpf_map *map;
+ struct hid_bpf_prog_entry entries[HID_BPF_MAX_PROGS]; /* compacted list, circular buffer */
+ int tail, head;
+ struct bpf_prog *progs[HID_BPF_MAX_PROGS]; /* idx -> progs mapping */
+ unsigned long enabled[BITS_TO_LONGS(HID_BPF_MAX_PROGS)];
+};
+
+#define FOR_ENTRIES(__i, __start, __end) \
+ for (__i = __start; CIRC_CNT(__end, __i, HID_BPF_MAX_PROGS); __i = NEXT(__i))
+
+static struct hid_bpf_jmp_table jmp_table;
+
+static DEFINE_MUTEX(hid_bpf_attach_lock); /* held when attaching/detaching programs */
+
+static void hid_bpf_release_progs(struct work_struct *work);
+
+static DECLARE_WORK(release_work, hid_bpf_release_progs);
+
+BTF_ID_LIST(hid_bpf_btf_ids)
+BTF_ID(func, hid_bpf_device_event) /* HID_BPF_PROG_TYPE_DEVICE_EVENT */
+BTF_ID(func, hid_bpf_rdesc_fixup) /* HID_BPF_PROG_TYPE_RDESC_FIXUP */
+
+static int hid_bpf_max_programs(enum hid_bpf_prog_type type)
+{
+ switch (type) {
+ case HID_BPF_PROG_TYPE_DEVICE_EVENT:
+ return HID_BPF_MAX_PROGS_PER_DEV;
+ case HID_BPF_PROG_TYPE_RDESC_FIXUP:
+ return 1;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int hid_bpf_program_count(struct hid_device *hdev,
+ struct bpf_prog *prog,
+ enum hid_bpf_prog_type type)
+{
+ int i, n = 0;
+
+ if (type >= HID_BPF_PROG_TYPE_MAX)
+ return -EINVAL;
+
+ FOR_ENTRIES(i, jmp_table.tail, jmp_table.head) {
+ struct hid_bpf_prog_entry *entry = &jmp_table.entries[i];
+
+ if (type != HID_BPF_PROG_TYPE_UNDEF && entry->type != type)
+ continue;
+
+ if (hdev && entry->hdev != hdev)
+ continue;
+
+ if (prog && entry->prog != prog)
+ continue;
+
+ n++;
+ }
+
+ return n;
+}
+
+__weak noinline int __hid_bpf_tail_call(struct hid_bpf_ctx *ctx)
+{
+ return 0;
+}
+
+int hid_bpf_prog_run(struct hid_device *hdev, enum hid_bpf_prog_type type,
+ struct hid_bpf_ctx_kern *ctx_kern)
+{
+ struct hid_bpf_prog_list *prog_list;
+ int i, idx, err = 0;
+
+ rcu_read_lock();
+ prog_list = rcu_dereference(hdev->bpf.progs[type]);
+
+ if (!prog_list)
+ goto out_unlock;
+
+ for (i = 0; i < prog_list->prog_cnt; i++) {
+ idx = prog_list->prog_idx[i];
+
+ if (!test_bit(idx, jmp_table.enabled))
+ continue;
+
+ ctx_kern->ctx.index = idx;
+ err = __hid_bpf_tail_call(&ctx_kern->ctx);
+ if (err < 0)
+ break;
+ if (err)
+ ctx_kern->ctx.retval = err;
+ }
+
+ out_unlock:
+ rcu_read_unlock();
+
+ return err;
+}
+
+/*
+ * assign the list of programs attached to a given hid device.
+ */
+static void __hid_bpf_set_hdev_progs(struct hid_device *hdev, struct hid_bpf_prog_list *new_list,
+ enum hid_bpf_prog_type type)
+{
+ struct hid_bpf_prog_list *old_list;
+
+ spin_lock(&hdev->bpf.progs_lock);
+ old_list = rcu_dereference_protected(hdev->bpf.progs[type],
+ lockdep_is_held(&hdev->bpf.progs_lock));
+ rcu_assign_pointer(hdev->bpf.progs[type], new_list);
+ spin_unlock(&hdev->bpf.progs_lock);
+ synchronize_rcu();
+
+ kfree(old_list);
+}
+
+/*
+ * allocate and populate the list of programs attached to a given hid device.
+ *
+ * Must be called under lock.
+ */
+static int hid_bpf_populate_hdev(struct hid_device *hdev, enum hid_bpf_prog_type type)
+{
+ struct hid_bpf_prog_list *new_list;
+ int i;
+
+ if (type >= HID_BPF_PROG_TYPE_MAX || !hdev)
+ return -EINVAL;
+
+ if (hdev->bpf.destroyed)
+ return 0;
+
+ new_list = kzalloc(sizeof(*new_list), GFP_KERNEL);
+ if (!new_list)
+ return -ENOMEM;
+
+ FOR_ENTRIES(i, jmp_table.tail, jmp_table.head) {
+ struct hid_bpf_prog_entry *entry = &jmp_table.entries[i];
+
+ if (entry->type == type && entry->hdev == hdev &&
+ test_bit(entry->idx, jmp_table.enabled))
+ new_list->prog_idx[new_list->prog_cnt++] = entry->idx;
+ }
+
+ __hid_bpf_set_hdev_progs(hdev, new_list, type);
+
+ return 0;
+}
+
+static void __hid_bpf_do_release_prog(int map_fd, unsigned int idx)
+{
+ skel_map_delete_elem(map_fd, &idx);
+ jmp_table.progs[idx] = NULL;
+}
+
+static void hid_bpf_release_progs(struct work_struct *work)
+{
+ int i, j, n, map_fd = -1;
+
+ if (!jmp_table.map)
+ return;
+
+ /* retrieve a fd of our prog_array map in BPF */
+ map_fd = skel_map_get_fd_by_id(jmp_table.map->id);
+ if (map_fd < 0)
+ return;
+
+ mutex_lock(&hid_bpf_attach_lock); /* protects against attaching new programs */
+
+ /* detach unused progs from HID devices */
+ FOR_ENTRIES(i, jmp_table.tail, jmp_table.head) {
+ struct hid_bpf_prog_entry *entry = &jmp_table.entries[i];
+ enum hid_bpf_prog_type type;
+ struct hid_device *hdev;
+
+ if (test_bit(entry->idx, jmp_table.enabled))
+ continue;
+
+ /* we have an attached prog */
+ if (entry->hdev) {
+ hdev = entry->hdev;
+ type = entry->type;
+
+ hid_bpf_populate_hdev(hdev, type);
+
+ /* mark all other disabled progs from hdev of the given type as detached */
+ FOR_ENTRIES(j, i, jmp_table.head) {
+ struct hid_bpf_prog_entry *next;
+
+ next = &jmp_table.entries[j];
+
+ if (test_bit(next->idx, jmp_table.enabled))
+ continue;
+
+ if (next->hdev == hdev && next->type == type)
+ next->hdev = NULL;
+ }
+
+ /* if type was rdesc fixup, reconnect device */
+ if (type == HID_BPF_PROG_TYPE_RDESC_FIXUP)
+ hid_bpf_reconnect(hdev);
+ }
+ }
+
+ /* remove all unused progs from the jump table */
+ FOR_ENTRIES(i, jmp_table.tail, jmp_table.head) {
+ struct hid_bpf_prog_entry *entry = &jmp_table.entries[i];
+
+ if (test_bit(entry->idx, jmp_table.enabled))
+ continue;
+
+ if (entry->prog)
+ __hid_bpf_do_release_prog(map_fd, entry->idx);
+ }
+
+ /* compact the entry list */
+ n = jmp_table.tail;
+ FOR_ENTRIES(i, jmp_table.tail, jmp_table.head) {
+ struct hid_bpf_prog_entry *entry = &jmp_table.entries[i];
+
+ if (!test_bit(entry->idx, jmp_table.enabled))
+ continue;
+
+ jmp_table.entries[n] = jmp_table.entries[i];
+ n = NEXT(n);
+ }
+
+ jmp_table.head = n;
+
+ mutex_unlock(&hid_bpf_attach_lock);
+
+ if (map_fd >= 0)
+ close_fd(map_fd);
+}
+
+static void hid_bpf_release_prog_at(int idx)
+{
+ int map_fd = -1;
+
+ /* retrieve a fd of our prog_array map in BPF */
+ map_fd = skel_map_get_fd_by_id(jmp_table.map->id);
+ if (map_fd < 0)
+ return;
+
+ __hid_bpf_do_release_prog(map_fd, idx);
+
+ close(map_fd);
+}
+
+/*
+ * Insert the given BPF program represented by its fd in the jmp table.
+ * Returns the index in the jump table or a negative error.
+ */
+static int hid_bpf_insert_prog(int prog_fd, struct bpf_prog *prog)
+{
+ int i, index = -1, map_fd = -1, err = -EINVAL;
+
+ /* retrieve a fd of our prog_array map in BPF */
+ map_fd = skel_map_get_fd_by_id(jmp_table.map->id);
+
+ if (map_fd < 0) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ /* find the first available index in the jmp_table */
+ for (i = 0; i < HID_BPF_MAX_PROGS; i++) {
+ if (!jmp_table.progs[i] && index < 0) {
+ /* mark the index as used */
+ jmp_table.progs[i] = prog;
+ index = i;
+ __set_bit(i, jmp_table.enabled);
+ }
+ }
+ if (index < 0) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ /* insert the program in the jump table */
+ err = skel_map_update_elem(map_fd, &index, &prog_fd, 0);
+ if (err)
+ goto out;
+
+ /* return the index */
+ err = index;
+
+ out:
+ if (err < 0)
+ __hid_bpf_do_release_prog(map_fd, index);
+ if (map_fd >= 0)
+ close_fd(map_fd);
+ return err;
+}
+
+int hid_bpf_get_prog_attach_type(int prog_fd)
+{
+ struct bpf_prog *prog = NULL;
+ int i;
+ int prog_type = HID_BPF_PROG_TYPE_UNDEF;
+
+ prog = bpf_prog_get(prog_fd);
+ if (IS_ERR(prog))
+ return PTR_ERR(prog);
+
+ for (i = 0; i < HID_BPF_PROG_TYPE_MAX; i++) {
+ if (hid_bpf_btf_ids[i] == prog->aux->attach_btf_id) {
+ prog_type = i;
+ break;
+ }
+ }
+
+ bpf_prog_put(prog);
+
+ return prog_type;
+}
+
+static void hid_bpf_link_release(struct bpf_link *link)
+{
+ struct hid_bpf_link *hid_link =
+ container_of(link, struct hid_bpf_link, link);
+
+ __clear_bit(hid_link->hid_table_index, jmp_table.enabled);
+ schedule_work(&release_work);
+}
+
+static void hid_bpf_link_dealloc(struct bpf_link *link)
+{
+ struct hid_bpf_link *hid_link =
+ container_of(link, struct hid_bpf_link, link);
+
+ kfree(hid_link);
+}
+
+static void hid_bpf_link_show_fdinfo(const struct bpf_link *link,
+ struct seq_file *seq)
+{
+ seq_printf(seq,
+ "attach_type:\tHID-BPF\n");
+}
+
+static const struct bpf_link_ops hid_bpf_link_lops = {
+ .release = hid_bpf_link_release,
+ .dealloc = hid_bpf_link_dealloc,
+ .show_fdinfo = hid_bpf_link_show_fdinfo,
+};
+
+/* called from syscall */
+noinline int
+__hid_bpf_attach_prog(struct hid_device *hdev, enum hid_bpf_prog_type prog_type,
+ int prog_fd, __u32 flags)
+{
+ struct bpf_link_primer link_primer;
+ struct hid_bpf_link *link;
+ struct bpf_prog *prog = NULL;
+ struct hid_bpf_prog_entry *prog_entry;
+ int cnt, err = -EINVAL, prog_table_idx = -1;
+
+ /* take a ref on the prog itself */
+ prog = bpf_prog_get(prog_fd);
+ if (IS_ERR(prog))
+ return PTR_ERR(prog);
+
+ mutex_lock(&hid_bpf_attach_lock);
+
+ link = kzalloc(sizeof(*link), GFP_USER);
+ if (!link) {
+ err = -ENOMEM;
+ goto err_unlock;
+ }
+
+ bpf_link_init(&link->link, BPF_LINK_TYPE_UNSPEC,
+ &hid_bpf_link_lops, prog);
+
+ /* do not attach too many programs to a given HID device */
+ cnt = hid_bpf_program_count(hdev, NULL, prog_type);
+ if (cnt < 0) {
+ err = cnt;
+ goto err_unlock;
+ }
+
+ if (cnt >= hid_bpf_max_programs(prog_type)) {
+ err = -E2BIG;
+ goto err_unlock;
+ }
+
+ prog_table_idx = hid_bpf_insert_prog(prog_fd, prog);
+ /* if the jmp table is full, abort */
+ if (prog_table_idx < 0) {
+ err = prog_table_idx;
+ goto err_unlock;
+ }
+
+ if (flags & HID_BPF_FLAG_INSERT_HEAD) {
+ /* take the previous prog_entry slot */
+ jmp_table.tail = PREV(jmp_table.tail);
+ prog_entry = &jmp_table.entries[jmp_table.tail];
+ } else {
+ /* take the next prog_entry slot */
+ prog_entry = &jmp_table.entries[jmp_table.head];
+ jmp_table.head = NEXT(jmp_table.head);
+ }
+
+ /* we steal the ref here */
+ prog_entry->prog = prog;
+ prog_entry->idx = prog_table_idx;
+ prog_entry->hdev = hdev;
+ prog_entry->type = prog_type;
+
+ /* finally store the index in the device list */
+ err = hid_bpf_populate_hdev(hdev, prog_type);
+ if (err) {
+ hid_bpf_release_prog_at(prog_table_idx);
+ goto err_unlock;
+ }
+
+ link->hid_table_index = prog_table_idx;
+
+ err = bpf_link_prime(&link->link, &link_primer);
+ if (err)
+ goto err_unlock;
+
+ mutex_unlock(&hid_bpf_attach_lock);
+
+ return bpf_link_settle(&link_primer);
+
+ err_unlock:
+ mutex_unlock(&hid_bpf_attach_lock);
+
+ bpf_prog_put(prog);
+ kfree(link);
+
+ return err;
+}
+
+void __hid_bpf_destroy_device(struct hid_device *hdev)
+{
+ int type, i;
+ struct hid_bpf_prog_list *prog_list;
+
+ rcu_read_lock();
+
+ for (type = 0; type < HID_BPF_PROG_TYPE_MAX; type++) {
+ prog_list = rcu_dereference(hdev->bpf.progs[type]);
+
+ if (!prog_list)
+ continue;
+
+ for (i = 0; i < prog_list->prog_cnt; i++)
+ __clear_bit(prog_list->prog_idx[i], jmp_table.enabled);
+ }
+
+ rcu_read_unlock();
+
+ for (type = 0; type < HID_BPF_PROG_TYPE_MAX; type++)
+ __hid_bpf_set_hdev_progs(hdev, NULL, type);
+
+ /* schedule release of all detached progs */
+ schedule_work(&release_work);
+}
+
+#define HID_BPF_PROGS_COUNT 1
+
+static struct bpf_link *links[HID_BPF_PROGS_COUNT];
+static struct entrypoints_bpf *skel;
+
+void hid_bpf_free_links_and_skel(void)
+{
+ int i;
+
+ /* the following is enough to release all programs attached to hid */
+ if (jmp_table.map)
+ bpf_map_put_with_uref(jmp_table.map);
+
+ for (i = 0; i < ARRAY_SIZE(links); i++) {
+ if (!IS_ERR_OR_NULL(links[i]))
+ bpf_link_put(links[i]);
+ }
+ entrypoints_bpf__destroy(skel);
+}
+
+#define ATTACH_AND_STORE_LINK(__name) do { \
+ err = entrypoints_bpf__##__name##__attach(skel); \
+ if (err) \
+ goto out; \
+ \
+ links[idx] = bpf_link_get_from_fd(skel->links.__name##_fd); \
+ if (IS_ERR(links[idx])) { \
+ err = PTR_ERR(links[idx]); \
+ goto out; \
+ } \
+ \
+ /* Avoid taking over stdin/stdout/stderr of init process. Zeroing out \
+ * makes skel_closenz() a no-op later in iterators_bpf__destroy(). \
+ */ \
+ close_fd(skel->links.__name##_fd); \
+ skel->links.__name##_fd = 0; \
+ idx++; \
+} while (0)
+
+int hid_bpf_preload_skel(void)
+{
+ int err, idx = 0;
+
+ skel = entrypoints_bpf__open();
+ if (!skel)
+ return -ENOMEM;
+
+ err = entrypoints_bpf__load(skel);
+ if (err)
+ goto out;
+
+ jmp_table.map = bpf_map_get_with_uref(skel->maps.hid_jmp_table.map_fd);
+ if (IS_ERR(jmp_table.map)) {
+ err = PTR_ERR(jmp_table.map);
+ goto out;
+ }
+
+ ATTACH_AND_STORE_LINK(hid_tail_call);
+
+ return 0;
+out:
+ hid_bpf_free_links_and_skel();
+ return err;
+}
diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c
index f99752b998f3..d1094bb1aa42 100644
--- a/drivers/hid/hid-asus.c
+++ b/drivers/hid/hid-asus.c
@@ -98,6 +98,7 @@ struct asus_kbd_leds {
struct hid_device *hdev;
struct work_struct work;
unsigned int brightness;
+ spinlock_t lock;
bool removed;
};
@@ -490,21 +491,42 @@ static int rog_nkey_led_init(struct hid_device *hdev)
return ret;
}
+static void asus_schedule_work(struct asus_kbd_leds *led)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&led->lock, flags);
+ if (!led->removed)
+ schedule_work(&led->work);
+ spin_unlock_irqrestore(&led->lock, flags);
+}
+
static void asus_kbd_backlight_set(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
struct asus_kbd_leds *led = container_of(led_cdev, struct asus_kbd_leds,
cdev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&led->lock, flags);
led->brightness = brightness;
- schedule_work(&led->work);
+ spin_unlock_irqrestore(&led->lock, flags);
+
+ asus_schedule_work(led);
}
static enum led_brightness asus_kbd_backlight_get(struct led_classdev *led_cdev)
{
struct asus_kbd_leds *led = container_of(led_cdev, struct asus_kbd_leds,
cdev);
+ enum led_brightness brightness;
+ unsigned long flags;
+
+ spin_lock_irqsave(&led->lock, flags);
+ brightness = led->brightness;
+ spin_unlock_irqrestore(&led->lock, flags);
- return led->brightness;
+ return brightness;
}
static void asus_kbd_backlight_work(struct work_struct *work)
@@ -512,11 +534,11 @@ static void asus_kbd_backlight_work(struct work_struct *work)
struct asus_kbd_leds *led = container_of(work, struct asus_kbd_leds, work);
u8 buf[] = { FEATURE_KBD_REPORT_ID, 0xba, 0xc5, 0xc4, 0x00 };
int ret;
+ unsigned long flags;
- if (led->removed)
- return;
-
+ spin_lock_irqsave(&led->lock, flags);
buf[4] = led->brightness;
+ spin_unlock_irqrestore(&led->lock, flags);
ret = asus_kbd_set_report(led->hdev, buf, sizeof(buf));
if (ret < 0)
@@ -584,6 +606,7 @@ static int asus_kbd_register_leds(struct hid_device *hdev)
drvdata->kbd_backlight->cdev.brightness_set = asus_kbd_backlight_set;
drvdata->kbd_backlight->cdev.brightness_get = asus_kbd_backlight_get;
INIT_WORK(&drvdata->kbd_backlight->work, asus_kbd_backlight_work);
+ spin_lock_init(&drvdata->kbd_backlight->lock);
ret = devm_led_classdev_register(&hdev->dev, &drvdata->kbd_backlight->cdev);
if (ret < 0) {
@@ -1119,9 +1142,13 @@ err_stop_hw:
static void asus_remove(struct hid_device *hdev)
{
struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
+ unsigned long flags;
if (drvdata->kbd_backlight) {
+ spin_lock_irqsave(&drvdata->kbd_backlight->lock, flags);
drvdata->kbd_backlight->removed = true;
+ spin_unlock_irqrestore(&drvdata->kbd_backlight->lock, flags);
+
cancel_work_sync(&drvdata->kbd_backlight->work);
}
diff --git a/drivers/hid/hid-bigbenff.c b/drivers/hid/hid-bigbenff.c
index e8b16665860d..a02cb517b4c4 100644
--- a/drivers/hid/hid-bigbenff.c
+++ b/drivers/hid/hid-bigbenff.c
@@ -174,6 +174,7 @@ static __u8 pid0902_rdesc_fixed[] = {
struct bigben_device {
struct hid_device *hid;
struct hid_report *report;
+ spinlock_t lock;
bool removed;
u8 led_state; /* LED1 = 1 .. LED4 = 8 */
u8 right_motor_on; /* right motor off/on 0/1 */
@@ -184,18 +185,39 @@ struct bigben_device {
struct work_struct worker;
};
+static inline void bigben_schedule_work(struct bigben_device *bigben)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&bigben->lock, flags);
+ if (!bigben->removed)
+ schedule_work(&bigben->worker);
+ spin_unlock_irqrestore(&bigben->lock, flags);
+}
static void bigben_worker(struct work_struct *work)
{
struct bigben_device *bigben = container_of(work,
struct bigben_device, worker);
struct hid_field *report_field = bigben->report->field[0];
-
- if (bigben->removed || !report_field)
+ bool do_work_led = false;
+ bool do_work_ff = false;
+ u8 *buf;
+ u32 len;
+ unsigned long flags;
+
+ buf = hid_alloc_report_buf(bigben->report, GFP_KERNEL);
+ if (!buf)
return;
+ len = hid_report_len(bigben->report);
+
+ /* LED work */
+ spin_lock_irqsave(&bigben->lock, flags);
+
if (bigben->work_led) {
bigben->work_led = false;
+ do_work_led = true;
report_field->value[0] = 0x01; /* 1 = led message */
report_field->value[1] = 0x08; /* reserved value, always 8 */
report_field->value[2] = bigben->led_state;
@@ -204,11 +226,22 @@ static void bigben_worker(struct work_struct *work)
report_field->value[5] = 0x00; /* padding */
report_field->value[6] = 0x00; /* padding */
report_field->value[7] = 0x00; /* padding */
- hid_hw_request(bigben->hid, bigben->report, HID_REQ_SET_REPORT);
+ hid_output_report(bigben->report, buf);
+ }
+
+ spin_unlock_irqrestore(&bigben->lock, flags);
+
+ if (do_work_led) {
+ hid_hw_raw_request(bigben->hid, bigben->report->id, buf, len,
+ bigben->report->type, HID_REQ_SET_REPORT);
}
+ /* FF work */
+ spin_lock_irqsave(&bigben->lock, flags);
+
if (bigben->work_ff) {
bigben->work_ff = false;
+ do_work_ff = true;
report_field->value[0] = 0x02; /* 2 = rumble effect message */
report_field->value[1] = 0x08; /* reserved value, always 8 */
report_field->value[2] = bigben->right_motor_on;
@@ -217,8 +250,17 @@ static void bigben_worker(struct work_struct *work)
report_field->value[5] = 0x00; /* padding */
report_field->value[6] = 0x00; /* padding */
report_field->value[7] = 0x00; /* padding */
- hid_hw_request(bigben->hid, bigben->report, HID_REQ_SET_REPORT);
+ hid_output_report(bigben->report, buf);
+ }
+
+ spin_unlock_irqrestore(&bigben->lock, flags);
+
+ if (do_work_ff) {
+ hid_hw_raw_request(bigben->hid, bigben->report->id, buf, len,
+ bigben->report->type, HID_REQ_SET_REPORT);
}
+
+ kfree(buf);
}
static int hid_bigben_play_effect(struct input_dev *dev, void *data,
@@ -228,6 +270,7 @@ static int hid_bigben_play_effect(struct input_dev *dev, void *data,
struct bigben_device *bigben = hid_get_drvdata(hid);
u8 right_motor_on;
u8 left_motor_force;
+ unsigned long flags;
if (!bigben) {
hid_err(hid, "no device data\n");
@@ -242,10 +285,13 @@ static int hid_bigben_play_effect(struct input_dev *dev, void *data,
if (right_motor_on != bigben->right_motor_on ||
left_motor_force != bigben->left_motor_force) {
+ spin_lock_irqsave(&bigben->lock, flags);
bigben->right_motor_on = right_motor_on;
bigben->left_motor_force = left_motor_force;
bigben->work_ff = true;
- schedule_work(&bigben->worker);
+ spin_unlock_irqrestore(&bigben->lock, flags);
+
+ bigben_schedule_work(bigben);
}
return 0;
@@ -259,6 +305,7 @@ static void bigben_set_led(struct led_classdev *led,
struct bigben_device *bigben = hid_get_drvdata(hid);
int n;
bool work;
+ unsigned long flags;
if (!bigben) {
hid_err(hid, "no device data\n");
@@ -267,6 +314,7 @@ static void bigben_set_led(struct led_classdev *led,
for (n = 0; n < NUM_LEDS; n++) {
if (led == bigben->leds[n]) {
+ spin_lock_irqsave(&bigben->lock, flags);
if (value == LED_OFF) {
work = (bigben->led_state & BIT(n));
bigben->led_state &= ~BIT(n);
@@ -274,10 +322,11 @@ static void bigben_set_led(struct led_classdev *led,
work = !(bigben->led_state & BIT(n));
bigben->led_state |= BIT(n);
}
+ spin_unlock_irqrestore(&bigben->lock, flags);
if (work) {
bigben->work_led = true;
- schedule_work(&bigben->worker);
+ bigben_schedule_work(bigben);
}
return;
}
@@ -307,8 +356,12 @@ static enum led_brightness bigben_get_led(struct led_classdev *led)
static void bigben_remove(struct hid_device *hid)
{
struct bigben_device *bigben = hid_get_drvdata(hid);
+ unsigned long flags;
+ spin_lock_irqsave(&bigben->lock, flags);
bigben->removed = true;
+ spin_unlock_irqrestore(&bigben->lock, flags);
+
cancel_work_sync(&bigben->worker);
hid_hw_stop(hid);
}
@@ -318,7 +371,6 @@ static int bigben_probe(struct hid_device *hid,
{
struct bigben_device *bigben;
struct hid_input *hidinput;
- struct list_head *report_list;
struct led_classdev *led;
char *name;
size_t name_sz;
@@ -343,14 +395,12 @@ static int bigben_probe(struct hid_device *hid,
return error;
}
- report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
- if (list_empty(report_list)) {
+ bigben->report = hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 8);
+ if (!bigben->report) {
hid_err(hid, "no output report found\n");
error = -ENODEV;
goto error_hw_stop;
}
- bigben->report = list_entry(report_list->next,
- struct hid_report, list);
if (list_empty(&hid->inputs)) {
hid_err(hid, "no inputs found\n");
@@ -362,6 +412,7 @@ static int bigben_probe(struct hid_device *hid,
set_bit(FF_RUMBLE, hidinput->input->ffbit);
INIT_WORK(&bigben->worker, bigben_worker);
+ spin_lock_init(&bigben->lock);
error = input_ff_create_memless(hidinput->input, NULL,
hid_bigben_play_effect);
@@ -402,7 +453,7 @@ static int bigben_probe(struct hid_device *hid,
bigben->left_motor_force = 0;
bigben->work_led = true;
bigben->work_ff = true;
- schedule_work(&bigben->worker);
+ bigben_schedule_work(bigben);
hid_info(hid, "LED and force feedback support for BigBen gamepad\n");
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 5c72aef3d3dd..842afc88a949 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -41,11 +41,6 @@
#define DRIVER_DESC "HID core driver"
-int hid_debug = 0;
-module_param_named(debug, hid_debug, int, 0600);
-MODULE_PARM_DESC(debug, "toggle HID debugging messages");
-EXPORT_SYMBOL_GPL(hid_debug);
-
static int hid_ignore_special_drivers = 0;
module_param_named(ignore_special_drivers, hid_ignore_special_drivers, int, 0600);
MODULE_PARM_DESC(ignore_special_drivers, "Ignore any special drivers and handle all devices by generic driver");
@@ -804,7 +799,8 @@ static void hid_scan_collection(struct hid_parser *parser, unsigned type)
int i;
if (((parser->global.usage_page << 16) == HID_UP_SENSOR) &&
- type == HID_COLLECTION_PHYSICAL)
+ (type == HID_COLLECTION_PHYSICAL ||
+ type == HID_COLLECTION_APPLICATION))
hid->group = HID_GROUP_SENSOR_HUB;
if (hid->vendor == USB_VENDOR_ID_MICROSOFT &&
@@ -1219,7 +1215,8 @@ int hid_open_report(struct hid_device *device)
return -ENODEV;
size = device->dev_rsize;
- buf = kmemdup(start, size, GFP_KERNEL);
+ /* call_hid_bpf_rdesc_fixup() ensures we work on a copy of rdesc */
+ buf = call_hid_bpf_rdesc_fixup(device, start, &size);
if (buf == NULL)
return -ENOMEM;
@@ -2046,6 +2043,12 @@ int hid_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data
report_enum = hid->report_enum + type;
hdrv = hid->driver;
+ data = dispatch_hid_bpf_device_event(hid, type, data, &size, interrupt);
+ if (IS_ERR(data)) {
+ ret = PTR_ERR(data);
+ goto unlock;
+ }
+
if (!size) {
dbg_hid("empty report\n");
ret = -1;
@@ -2160,6 +2163,10 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
int len;
int ret;
+ ret = hid_bpf_connect_device(hdev);
+ if (ret)
+ return ret;
+
if (hdev->quirks & HID_QUIRK_HIDDEV_FORCE)
connect_mask |= (HID_CONNECT_HIDDEV_FORCE | HID_CONNECT_HIDDEV);
if (hdev->quirks & HID_QUIRK_HIDINPUT_FORCE)
@@ -2261,6 +2268,8 @@ void hid_disconnect(struct hid_device *hdev)
if (hdev->claimed & HID_CLAIMED_HIDRAW)
hidraw_disconnect(hdev);
hdev->claimed = 0;
+
+ hid_bpf_disconnect_device(hdev);
}
EXPORT_SYMBOL_GPL(hid_disconnect);
@@ -2667,9 +2676,9 @@ static const struct attribute_group hid_dev_group = {
};
__ATTRIBUTE_GROUPS(hid_dev);
-static int hid_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int hid_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct hid_device *hdev = to_hid_device(dev);
+ const struct hid_device *hdev = to_hid_device(dev);
if (add_uevent_var(env, "HID_ID=%04X:%08X:%08X",
hdev->bus, hdev->vendor, hdev->product))
@@ -2796,6 +2805,8 @@ struct hid_device *hid_allocate_device(void)
sema_init(&hdev->driver_input_lock, 1);
mutex_init(&hdev->ll_open_lock);
+ hid_bpf_device_init(hdev);
+
return hdev;
}
EXPORT_SYMBOL_GPL(hid_allocate_device);
@@ -2822,6 +2833,7 @@ static void hid_remove_device(struct hid_device *hdev)
*/
void hid_destroy_device(struct hid_device *hdev)
{
+ hid_bpf_destroy_device(hdev);
hid_remove_device(hdev);
put_device(&hdev->dev);
}
@@ -2908,20 +2920,29 @@ int hid_check_keys_pressed(struct hid_device *hid)
}
EXPORT_SYMBOL_GPL(hid_check_keys_pressed);
+#ifdef CONFIG_HID_BPF
+static struct hid_bpf_ops hid_ops = {
+ .hid_get_report = hid_get_report,
+ .hid_hw_raw_request = hid_hw_raw_request,
+ .owner = THIS_MODULE,
+ .bus_type = &hid_bus_type,
+};
+#endif
+
static int __init hid_init(void)
{
int ret;
- if (hid_debug)
- pr_warn("hid_debug is now used solely for parser and driver debugging.\n"
- "debugfs is now used for inspecting the device (report descriptor, reports)\n");
-
ret = bus_register(&hid_bus_type);
if (ret) {
pr_err("can't register hid bus\n");
goto err;
}
+#ifdef CONFIG_HID_BPF
+ hid_bpf_ops = &hid_ops;
+#endif
+
ret = hidraw_init();
if (ret)
goto err_bus;
@@ -2937,6 +2958,9 @@ err:
static void __exit hid_exit(void)
{
+#ifdef CONFIG_HID_BPF
+ hid_bpf_ops = NULL;
+#endif
hid_debug_exit();
hidraw_exit();
bus_unregister(&hid_bus_type);
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c
index e213bdde543a..e7ef1ea107c9 100644
--- a/drivers/hid/hid-debug.c
+++ b/drivers/hid/hid-debug.c
@@ -975,6 +975,7 @@ static const char *keys[KEY_MAX + 1] = {
[KEY_CAMERA_ACCESS_DISABLE] = "CameraAccessDisable",
[KEY_CAMERA_ACCESS_TOGGLE] = "CameraAccessToggle",
[KEY_DICTATE] = "Dictate",
+ [KEY_MICMUTE] = "MicrophoneMute",
[KEY_BRIGHTNESS_MIN] = "BrightnessMin",
[KEY_BRIGHTNESS_MAX] = "BrightnessMax",
[KEY_BRIGHTNESS_AUTO] = "BrightnessAuto",
diff --git a/drivers/hid/hid-evision.c b/drivers/hid/hid-evision.c
new file mode 100644
index 000000000000..ef6b4b435215
--- /dev/null
+++ b/drivers/hid/hid-evision.c
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * HID driver for EVision devices
+ * For now, only ignore bogus consumer reports
+ * sent after the keyboard has been configured
+ *
+ * Copyright (c) 2022 Philippe Valembois
+ */
+
+#include <linux/device.h>
+#include <linux/input.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+static int evision_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
+ return 0;
+
+ /* Ignore key down event */
+ if ((usage->hid & HID_USAGE) >> 8 == 0x05)
+ return -1;
+ /* Ignore key up event */
+ if ((usage->hid & HID_USAGE) >> 8 == 0x06)
+ return -1;
+
+ switch (usage->hid & HID_USAGE) {
+ /* Ignore configuration saved event */
+ case 0x0401: return -1;
+ /* Ignore reset event */
+ case 0x0402: return -1;
+ }
+ return 0;
+}
+
+static const struct hid_device_id evision_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_EVISION, USB_DEVICE_ID_EVISION_ICL01) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, evision_devices);
+
+static struct hid_driver evision_driver = {
+ .name = "evision",
+ .id_table = evision_devices,
+ .input_mapping = evision_input_mapping,
+};
+module_hid_driver(evision_driver);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c
index 2a0aabd50a45..49d4a26895e7 100644
--- a/drivers/hid/hid-hyperv.c
+++ b/drivers/hid/hid-hyperv.c
@@ -424,7 +424,7 @@ static int mousevsc_hid_raw_request(struct hid_device *hid,
return 0;
}
-static struct hid_ll_driver mousevsc_ll_driver = {
+static const struct hid_ll_driver mousevsc_ll_driver = {
.parse = mousevsc_hid_parse,
.open = mousevsc_hid_open,
.close = mousevsc_hid_close,
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 9e36b4cd905e..63545cd307e5 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -448,6 +448,9 @@
#define USB_VENDOR_ID_EMS 0x2006
#define USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II 0x0118
+#define USB_VENDOR_ID_EVISION 0x320f
+#define USB_DEVICE_ID_EVISION_ICL01 0x5041
+
#define USB_VENDOR_ID_FLATFROG 0x25b5
#define USB_DEVICE_ID_MULTITOUCH_3200 0x0002
@@ -822,6 +825,7 @@
#define USB_DEVICE_ID_LOGITECH_G510_USB_AUDIO 0xc22e
#define USB_DEVICE_ID_LOGITECH_G29_WHEEL 0xc24f
#define USB_DEVICE_ID_LOGITECH_G920_WHEEL 0xc262
+#define USB_DEVICE_ID_LOGITECH_G923_XBOX_WHEEL 0xc26e
#define USB_DEVICE_ID_LOGITECH_WINGMAN_F3D 0xc283
#define USB_DEVICE_ID_LOGITECH_FORCE3D_PRO 0xc286
#define USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940 0xc287
@@ -1185,6 +1189,7 @@
#define USB_VENDOR_ID_VALVE 0x28de
#define USB_DEVICE_ID_STEAM_CONTROLLER 0x1102
#define USB_DEVICE_ID_STEAM_CONTROLLER_WIRELESS 0x1142
+#define USB_DEVICE_ID_STEAM_DECK 0x1205
#define USB_VENDOR_ID_STEELSERIES 0x1038
#define USB_DEVICE_ID_STEELSERIES_SRWS1 0x1410
@@ -1299,7 +1304,9 @@
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01 0x0042
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01_V2 0x0905
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L 0x0935
+#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_MW 0x0934
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_S 0x0909
+#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_SW 0x0933
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06 0x0078
#define USB_DEVICE_ID_UGEE_TABLET_G5 0x0074
#define USB_DEVICE_ID_UGEE_TABLET_EX07S 0x0071
diff --git a/drivers/hid/hid-input-test.c b/drivers/hid/hid-input-test.c
new file mode 100644
index 000000000000..77c2d45ac62a
--- /dev/null
+++ b/drivers/hid/hid-input-test.c
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * HID to Linux Input mapping
+ *
+ * Copyright (c) 2022 José Expósito <jose.exposito89@gmail.com>
+ */
+
+#include <kunit/test.h>
+
+static void hid_test_input_set_battery_charge_status(struct kunit *test)
+{
+ struct hid_device *dev;
+ bool handled;
+
+ dev = kunit_kzalloc(test, sizeof(*dev), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
+
+ handled = hidinput_set_battery_charge_status(dev, HID_DG_HEIGHT, 0);
+ KUNIT_EXPECT_FALSE(test, handled);
+ KUNIT_EXPECT_EQ(test, dev->battery_charge_status, POWER_SUPPLY_STATUS_UNKNOWN);
+
+ handled = hidinput_set_battery_charge_status(dev, HID_BAT_CHARGING, 0);
+ KUNIT_EXPECT_TRUE(test, handled);
+ KUNIT_EXPECT_EQ(test, dev->battery_charge_status, POWER_SUPPLY_STATUS_DISCHARGING);
+
+ handled = hidinput_set_battery_charge_status(dev, HID_BAT_CHARGING, 1);
+ KUNIT_EXPECT_TRUE(test, handled);
+ KUNIT_EXPECT_EQ(test, dev->battery_charge_status, POWER_SUPPLY_STATUS_CHARGING);
+}
+
+static void hid_test_input_get_battery_property(struct kunit *test)
+{
+ struct power_supply *psy;
+ struct hid_device *dev;
+ union power_supply_propval val;
+ int ret;
+
+ dev = kunit_kzalloc(test, sizeof(*dev), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
+ dev->battery_avoid_query = true;
+
+ psy = kunit_kzalloc(test, sizeof(*psy), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, psy);
+ psy->drv_data = dev;
+
+ dev->battery_status = HID_BATTERY_UNKNOWN;
+ dev->battery_charge_status = POWER_SUPPLY_STATUS_CHARGING;
+ ret = hidinput_get_battery_property(psy, POWER_SUPPLY_PROP_STATUS, &val);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ KUNIT_EXPECT_EQ(test, val.intval, POWER_SUPPLY_STATUS_UNKNOWN);
+
+ dev->battery_status = HID_BATTERY_REPORTED;
+ dev->battery_charge_status = POWER_SUPPLY_STATUS_CHARGING;
+ ret = hidinput_get_battery_property(psy, POWER_SUPPLY_PROP_STATUS, &val);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ KUNIT_EXPECT_EQ(test, val.intval, POWER_SUPPLY_STATUS_CHARGING);
+
+ dev->battery_status = HID_BATTERY_REPORTED;
+ dev->battery_charge_status = POWER_SUPPLY_STATUS_DISCHARGING;
+ ret = hidinput_get_battery_property(psy, POWER_SUPPLY_PROP_STATUS, &val);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ KUNIT_EXPECT_EQ(test, val.intval, POWER_SUPPLY_STATUS_DISCHARGING);
+}
+
+static struct kunit_case hid_input_tests[] = {
+ KUNIT_CASE(hid_test_input_set_battery_charge_status),
+ KUNIT_CASE(hid_test_input_get_battery_property),
+ { }
+};
+
+static struct kunit_suite hid_input_test_suite = {
+ .name = "hid_input",
+ .test_cases = hid_input_tests,
+};
+
+kunit_test_suite(hid_input_test_suite);
+
+MODULE_DESCRIPTION("HID input KUnit tests");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("José Expósito <jose.exposito89@gmail.com>");
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 77c8c49852b5..7fc967964dd8 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -378,6 +378,10 @@ static const struct hid_device_id hid_battery_quirks[] = {
HID_BATTERY_QUIRK_IGNORE },
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L),
HID_BATTERY_QUIRK_AVOID_QUERY },
+ { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_MW),
+ HID_BATTERY_QUIRK_AVOID_QUERY },
+ { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_SW),
+ HID_BATTERY_QUIRK_AVOID_QUERY },
{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_ENVY_X360_15),
HID_BATTERY_QUIRK_IGNORE },
{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_ENVY_X360_15T_DR100),
@@ -486,7 +490,7 @@ static int hidinput_get_battery_property(struct power_supply *psy,
if (dev->battery_status == HID_BATTERY_UNKNOWN)
val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
else
- val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+ val->intval = dev->battery_charge_status;
break;
case POWER_SUPPLY_PROP_SCOPE:
@@ -554,6 +558,7 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
dev->battery_max = max;
dev->battery_report_type = report_type;
dev->battery_report_id = field->report->id;
+ dev->battery_charge_status = POWER_SUPPLY_STATUS_DISCHARGING;
/*
* Stylus is normally not connected to the device and thus we
@@ -620,6 +625,20 @@ static void hidinput_update_battery(struct hid_device *dev, int value)
power_supply_changed(dev->battery);
}
}
+
+static bool hidinput_set_battery_charge_status(struct hid_device *dev,
+ unsigned int usage, int value)
+{
+ switch (usage) {
+ case HID_BAT_CHARGING:
+ dev->battery_charge_status = value ?
+ POWER_SUPPLY_STATUS_CHARGING :
+ POWER_SUPPLY_STATUS_DISCHARGING;
+ return true;
+ }
+
+ return false;
+}
#else /* !CONFIG_HID_BATTERY_STRENGTH */
static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
struct hid_field *field, bool is_percentage)
@@ -634,6 +653,12 @@ static void hidinput_cleanup_battery(struct hid_device *dev)
static void hidinput_update_battery(struct hid_device *dev, int value)
{
}
+
+static bool hidinput_set_battery_charge_status(struct hid_device *dev,
+ unsigned int usage, int value)
+{
+ return false;
+}
#endif /* CONFIG_HID_BATTERY_STRENGTH */
static bool hidinput_field_in_collection(struct hid_device *device, struct hid_field *field,
@@ -793,6 +818,14 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
break;
}
+ if ((usage->hid & 0xf0) == 0xa0) { /* SystemControl */
+ switch (usage->hid & 0xf) {
+ case 0x9: map_key_clear(KEY_MICMUTE); break;
+ default: goto ignore;
+ }
+ break;
+ }
+
if ((usage->hid & 0xf0) == 0xb0) { /* SC - Display */
switch (usage->hid & 0xf) {
case 0x05: map_key_clear(KEY_SWITCHVIDEOMODE); break;
@@ -1223,6 +1256,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
hidinput_setup_battery(device, HID_INPUT_REPORT, field, true);
usage->type = EV_PWR;
return;
+ case HID_BAT_CHARGING:
+ usage->type = EV_PWR;
+ return;
}
goto unknown;
@@ -1465,7 +1501,11 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
return;
if (usage->type == EV_PWR) {
- hidinput_update_battery(hid, value);
+ bool handled = hidinput_set_battery_charge_status(hid, usage->hid, value);
+
+ if (!handled)
+ hidinput_update_battery(hid, value);
+
return;
}
@@ -2321,3 +2361,7 @@ void hidinput_disconnect(struct hid_device *hid)
cancel_work_sync(&hid->led_work);
}
EXPORT_SYMBOL_GPL(hidinput_disconnect);
+
+#ifdef CONFIG_HID_KUNIT_TEST
+#include "hid-input-test.c"
+#endif
diff --git a/drivers/hid/hid-letsketch.c b/drivers/hid/hid-letsketch.c
index 74d17cf518ba..97f047f18136 100644
--- a/drivers/hid/hid-letsketch.c
+++ b/drivers/hid/hid-letsketch.c
@@ -238,7 +238,7 @@ static int letsketch_probe(struct hid_device *hdev, const struct hid_device_id *
char buf[256];
int i, ret;
- if (!hid_is_using_ll_driver(hdev, &usb_hid_driver))
+ if (!hid_is_usb(hdev))
return -ENODEV;
intf = to_usb_interface(hdev->dev.parent);
diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
index c358778e070b..62180414efcc 100644
--- a/drivers/hid/hid-logitech-dj.c
+++ b/drivers/hid/hid-logitech-dj.c
@@ -554,7 +554,7 @@ static const u8 hid_reportid_size_map[NUMBER_OF_HID_REPORTS] = {
#define LOGITECH_DJ_INTERFACE_NUMBER 0x02
-static struct hid_ll_driver logi_dj_ll_driver;
+static const struct hid_ll_driver logi_dj_ll_driver;
static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev);
static void delayedwork_callback(struct work_struct *work);
@@ -1506,7 +1506,7 @@ static bool logi_dj_ll_may_wakeup(struct hid_device *hid)
return hid_hw_may_wakeup(djrcv_dev->hidpp);
}
-static struct hid_ll_driver logi_dj_ll_driver = {
+static const struct hid_ll_driver logi_dj_ll_driver = {
.parse = logi_dj_ll_parse,
.start = logi_dj_ll_start,
.stop = logi_dj_ll_stop,
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
index 9c1ee8e91e0c..25dcda76d6c7 100644
--- a/drivers/hid/hid-logitech-hidpp.c
+++ b/drivers/hid/hid-logitech-hidpp.c
@@ -30,11 +30,7 @@
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");
MODULE_AUTHOR("Nestor Lopez Casado <nlopezcasad@logitech.com>");
-
-static bool disable_raw_mode;
-module_param(disable_raw_mode, bool, 0644);
-MODULE_PARM_DESC(disable_raw_mode,
- "Disable Raw mode reporting for touchpads and keep firmware gestures.");
+MODULE_AUTHOR("Bastien Nocera <hadess@hadess.net>");
static bool disable_tap_to_click;
module_param(disable_tap_to_click, bool, 0644);
@@ -71,12 +67,13 @@ MODULE_PARM_DESC(disable_tap_to_click,
/* bits 2..20 are reserved for classes */
/* #define HIDPP_QUIRK_CONNECT_EVENTS BIT(21) disabled */
#define HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS BIT(22)
-#define HIDPP_QUIRK_NO_HIDINPUT BIT(23)
+#define HIDPP_QUIRK_DELAYED_INIT BIT(23)
#define HIDPP_QUIRK_FORCE_OUTPUT_REPORTS BIT(24)
#define HIDPP_QUIRK_UNIFYING BIT(25)
#define HIDPP_QUIRK_HIDPP_WHEELS BIT(26)
#define HIDPP_QUIRK_HIDPP_EXTRA_MOUSE_BTNS BIT(27)
#define HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS BIT(28)
+#define HIDPP_QUIRK_HI_RES_SCROLL_1P0 BIT(29)
/* These are just aliases for now */
#define HIDPP_QUIRK_KBD_SCROLL_WHEEL HIDPP_QUIRK_HIDPP_WHEELS
@@ -87,8 +84,6 @@ MODULE_PARM_DESC(disable_tap_to_click,
HIDPP_CAPABILITY_HIDPP20_HI_RES_SCROLL | \
HIDPP_CAPABILITY_HIDPP20_HI_RES_WHEEL)
-#define HIDPP_QUIRK_DELAYED_INIT HIDPP_QUIRK_NO_HIDINPUT
-
#define HIDPP_CAPABILITY_HIDPP10_BATTERY BIT(0)
#define HIDPP_CAPABILITY_HIDPP20_BATTERY BIT(1)
#define HIDPP_CAPABILITY_BATTERY_MILEAGE BIT(2)
@@ -225,6 +220,16 @@ struct hidpp_device {
#define HIDPP_ERROR_INVALID_PARAM_VALUE 0x0b
#define HIDPP_ERROR_WRONG_PIN_CODE 0x0c
/* HID++ 2.0 error codes */
+#define HIDPP20_ERROR_NO_ERROR 0x00
+#define HIDPP20_ERROR_UNKNOWN 0x01
+#define HIDPP20_ERROR_INVALID_ARGS 0x02
+#define HIDPP20_ERROR_OUT_OF_RANGE 0x03
+#define HIDPP20_ERROR_HW_ERROR 0x04
+#define HIDPP20_ERROR_LOGITECH_INTERNAL 0x05
+#define HIDPP20_ERROR_INVALID_FEATURE_INDEX 0x06
+#define HIDPP20_ERROR_INVALID_FUNCTION_ID 0x07
+#define HIDPP20_ERROR_BUSY 0x08
+#define HIDPP20_ERROR_UNSUPPORTED 0x09
#define HIDPP20_ERROR 0xff
static void hidpp_connect_event(struct hidpp_device *hidpp_dev);
@@ -279,6 +284,7 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp,
struct hidpp_report *response)
{
int ret;
+ int max_retries = 3;
mutex_lock(&hidpp->send_mutex);
@@ -291,34 +297,39 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp,
*/
*response = *message;
- ret = __hidpp_send_report(hidpp->hid_dev, message);
+ for (; max_retries != 0; max_retries--) {
+ ret = __hidpp_send_report(hidpp->hid_dev, message);
- if (ret) {
- dbg_hid("__hidpp_send_report returned err: %d\n", ret);
- memset(response, 0, sizeof(struct hidpp_report));
- goto exit;
- }
+ if (ret) {
+ dbg_hid("__hidpp_send_report returned err: %d\n", ret);
+ memset(response, 0, sizeof(struct hidpp_report));
+ goto exit;
+ }
- if (!wait_event_timeout(hidpp->wait, hidpp->answer_available,
- 5*HZ)) {
- dbg_hid("%s:timeout waiting for response\n", __func__);
- memset(response, 0, sizeof(struct hidpp_report));
- ret = -ETIMEDOUT;
- }
+ if (!wait_event_timeout(hidpp->wait, hidpp->answer_available,
+ 5*HZ)) {
+ dbg_hid("%s:timeout waiting for response\n", __func__);
+ memset(response, 0, sizeof(struct hidpp_report));
+ ret = -ETIMEDOUT;
+ }
- if (response->report_id == REPORT_ID_HIDPP_SHORT &&
- response->rap.sub_id == HIDPP_ERROR) {
- ret = response->rap.params[1];
- dbg_hid("%s:got hidpp error %02X\n", __func__, ret);
- goto exit;
- }
+ if (response->report_id == REPORT_ID_HIDPP_SHORT &&
+ response->rap.sub_id == HIDPP_ERROR) {
+ ret = response->rap.params[1];
+ dbg_hid("%s:got hidpp error %02X\n", __func__, ret);
+ goto exit;
+ }
- if ((response->report_id == REPORT_ID_HIDPP_LONG ||
- response->report_id == REPORT_ID_HIDPP_VERY_LONG) &&
- response->fap.feature_index == HIDPP20_ERROR) {
- ret = response->fap.params[1];
- dbg_hid("%s:got hidpp 2.0 error %02X\n", __func__, ret);
- goto exit;
+ if ((response->report_id == REPORT_ID_HIDPP_LONG ||
+ response->report_id == REPORT_ID_HIDPP_VERY_LONG) &&
+ response->fap.feature_index == HIDPP20_ERROR) {
+ ret = response->fap.params[1];
+ if (ret != HIDPP20_ERROR_BUSY) {
+ dbg_hid("%s:got hidpp 2.0 error %02X\n", __func__, ret);
+ goto exit;
+ }
+ dbg_hid("%s:got busy hidpp 2.0 error %02X, retrying\n", __func__, ret);
+ }
}
exit:
@@ -334,8 +345,13 @@ static int hidpp_send_fap_command_sync(struct hidpp_device *hidpp,
struct hidpp_report *message;
int ret;
- if (param_count > sizeof(message->fap.params))
+ if (param_count > sizeof(message->fap.params)) {
+ hid_dbg(hidpp->hid_dev,
+ "Invalid number of parameters passed to command (%d != %llu)\n",
+ param_count,
+ (unsigned long long) sizeof(message->fap.params));
return -EINVAL;
+ }
message = kzalloc(sizeof(struct hidpp_report), GFP_KERNEL);
if (!message)
@@ -3436,11 +3452,17 @@ static int hi_res_scroll_enable(struct hidpp_device *hidpp)
ret = hidpp10_enable_scrolling_acceleration(hidpp);
multiplier = 8;
}
- if (ret)
+ if (ret) {
+ hid_dbg(hidpp->hid_dev,
+ "Could not enable hi-res scrolling: %d\n", ret);
return ret;
+ }
- if (multiplier == 0)
+ if (multiplier == 0) {
+ hid_dbg(hidpp->hid_dev,
+ "Invalid multiplier 0 from device, setting it to 1\n");
multiplier = 1;
+ }
hidpp->vertical_wheel_counter.wheel_multiplier = multiplier;
hid_dbg(hidpp->hid_dev, "wheel multiplier = %d\n", multiplier);
@@ -3472,14 +3494,8 @@ static int hidpp_initialize_hires_scroll(struct hidpp_device *hidpp)
hid_dbg(hidpp->hid_dev, "Detected HID++ 2.0 hi-res scrolling\n");
}
} else {
- struct hidpp_report response;
-
- ret = hidpp_send_rap_command_sync(hidpp,
- REPORT_ID_HIDPP_SHORT,
- HIDPP_GET_REGISTER,
- HIDPP_ENABLE_FAST_SCROLL,
- NULL, 0, &response);
- if (!ret) {
+ /* We cannot detect fast scrolling support on HID++ 1.0 devices */
+ if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_1P0) {
hidpp->capabilities |= HIDPP_CAPABILITY_HIDPP10_FAST_SCROLL;
hid_dbg(hidpp->hid_dev, "Detected HID++ 1.0 fast scroll\n");
}
@@ -4002,7 +4018,7 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
if (hidpp->capabilities & HIDPP_CAPABILITY_HI_RES_SCROLL)
hi_res_scroll_enable(hidpp);
- if (!(hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT) || hidpp->delayed_input)
+ if (!(hidpp->quirks & HIDPP_QUIRK_DELAYED_INIT) || hidpp->delayed_input)
/* if the input nodes are already created, we can stop now */
return;
@@ -4107,6 +4123,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
bool connected;
unsigned int connect_mask = HID_CONNECT_DEFAULT;
struct hidpp_ff_private_data data;
+ bool will_restart = false;
/* report_fixup needs drvdata to be set before we call hid_parse */
hidpp = devm_kzalloc(&hdev->dev, sizeof(*hidpp), GFP_KERNEL);
@@ -4147,11 +4164,6 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
hidpp_application_equals(hdev, HID_GD_KEYBOARD))
hidpp->quirks |= HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS;
- if (disable_raw_mode) {
- hidpp->quirks &= ~HIDPP_QUIRK_CLASS_WTP;
- hidpp->quirks &= ~HIDPP_QUIRK_NO_HIDINPUT;
- }
-
if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) {
ret = wtp_allocate(hdev, id);
if (ret)
@@ -4162,6 +4174,10 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
return ret;
}
+ if (hidpp->quirks & HIDPP_QUIRK_DELAYED_INIT ||
+ hidpp->quirks & HIDPP_QUIRK_UNIFYING)
+ will_restart = true;
+
INIT_WORK(&hidpp->work, delayed_work_cb);
mutex_init(&hidpp->send_mutex);
init_waitqueue_head(&hidpp->wait);
@@ -4176,7 +4192,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
* Plain USB connections need to actually call start and open
* on the transport driver to allow incoming data.
*/
- ret = hid_hw_start(hdev, 0);
+ ret = hid_hw_start(hdev, will_restart ? 0 : connect_mask);
if (ret) {
hid_err(hdev, "hw start failed\n");
goto hid_hw_start_fail;
@@ -4213,6 +4229,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
hidpp->wireless_feature_index = 0;
else if (ret)
goto hid_hw_init_fail;
+ ret = 0;
}
if (connected && (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP)) {
@@ -4227,19 +4244,21 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
hidpp_connect_event(hidpp);
- /* Reset the HID node state */
- hid_device_io_stop(hdev);
- hid_hw_close(hdev);
- hid_hw_stop(hdev);
+ if (will_restart) {
+ /* Reset the HID node state */
+ hid_device_io_stop(hdev);
+ hid_hw_close(hdev);
+ hid_hw_stop(hdev);
- if (hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT)
- connect_mask &= ~HID_CONNECT_HIDINPUT;
+ if (hidpp->quirks & HIDPP_QUIRK_DELAYED_INIT)
+ connect_mask &= ~HID_CONNECT_HIDINPUT;
- /* Now export the actual inputs and hidraw nodes to the world */
- ret = hid_hw_start(hdev, connect_mask);
- if (ret) {
- hid_err(hdev, "%s:hid_hw_start returned error\n", __func__);
- goto hid_hw_start_fail;
+ /* Now export the actual inputs and hidraw nodes to the world */
+ ret = hid_hw_start(hdev, connect_mask);
+ if (ret) {
+ hid_err(hdev, "%s:hid_hw_start returned error\n", __func__);
+ goto hid_hw_start_fail;
+ }
}
if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
@@ -4297,9 +4316,15 @@ static const struct hid_device_id hidpp_devices[] = {
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH,
USB_DEVICE_ID_LOGITECH_T651),
.driver_data = HIDPP_QUIRK_CLASS_WTP },
+ { /* Mouse Logitech Anywhere MX */
+ LDJ_DEVICE(0x1017), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 },
{ /* Mouse logitech M560 */
LDJ_DEVICE(0x402d),
.driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560 },
+ { /* Mouse Logitech M705 (firmware RQM17) */
+ LDJ_DEVICE(0x101b), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 },
+ { /* Mouse Logitech Performance MX */
+ LDJ_DEVICE(0x101a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 },
{ /* Keyboard logitech K400 */
LDJ_DEVICE(0x4024),
.driver_data = HIDPP_QUIRK_CLASS_K400 },
@@ -4348,6 +4373,9 @@ static const struct hid_device_id hidpp_devices[] = {
{ /* Logitech G920 Wheel over USB */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL),
.driver_data = HIDPP_QUIRK_CLASS_G920 | HIDPP_QUIRK_FORCE_OUTPUT_REPORTS},
+ { /* Logitech G923 Wheel (Xbox version) over USB */
+ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G923_XBOX_WHEEL),
+ .driver_data = HIDPP_QUIRK_CLASS_G920 | HIDPP_QUIRK_FORCE_OUTPUT_REPORTS },
{ /* Logitech G Pro Gaming Mouse over USB */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC088) },
@@ -4367,6 +4395,8 @@ static const struct hid_device_id hidpp_devices[] = {
{ /* MX Ergo trackball over Bluetooth */
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb01d) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb01e) },
+ { /* Signature M650 over Bluetooth */
+ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb02a) },
{ /* MX Master 3 mouse over Bluetooth */
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb023) },
{}
diff --git a/drivers/hid/hid-mcp2221.c b/drivers/hid/hid-mcp2221.c
index e61dd039354b..f74a977cf8f8 100644
--- a/drivers/hid/hid-mcp2221.c
+++ b/drivers/hid/hid-mcp2221.c
@@ -922,6 +922,9 @@ static void mcp2221_hid_unregister(void *ptr)
/* This is needed to be sure hid_hw_stop() isn't called twice by the subsystem */
static void mcp2221_remove(struct hid_device *hdev)
{
+ struct mcp2221 *mcp = hid_get_drvdata(hdev);
+
+ cancel_delayed_work_sync(&mcp->init_work);
}
#if IS_REACHABLE(CONFIG_IIO)
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 372cbdd223e0..e31be0cb8b85 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -71,6 +71,7 @@ MODULE_LICENSE("GPL");
#define MT_QUIRK_SEPARATE_APP_REPORT BIT(19)
#define MT_QUIRK_FORCE_MULTI_INPUT BIT(20)
#define MT_QUIRK_DISABLE_WAKEUP BIT(21)
+#define MT_QUIRK_ORIENTATION_INVERT BIT(22)
#define MT_INPUTMODE_TOUCHSCREEN 0x02
#define MT_INPUTMODE_TOUCHPAD 0x03
@@ -1009,6 +1010,7 @@ static int mt_process_slot(struct mt_device *td, struct input_dev *input,
struct mt_usages *slot)
{
struct input_mt *mt = input->mt;
+ struct hid_device *hdev = td->hdev;
__s32 quirks = app->quirks;
bool valid = true;
bool confidence_state = true;
@@ -1086,6 +1088,10 @@ static int mt_process_slot(struct mt_device *td, struct input_dev *input,
int orientation = wide;
int max_azimuth;
int azimuth;
+ int x;
+ int y;
+ int cx;
+ int cy;
if (slot->a != DEFAULT_ZERO) {
/*
@@ -1104,6 +1110,9 @@ static int mt_process_slot(struct mt_device *td, struct input_dev *input,
if (azimuth > max_azimuth * 2)
azimuth -= max_azimuth * 4;
orientation = -azimuth;
+ if (quirks & MT_QUIRK_ORIENTATION_INVERT)
+ orientation = -orientation;
+
}
if (quirks & MT_QUIRK_TOUCH_SIZE_SCALING) {
@@ -1115,10 +1124,23 @@ static int mt_process_slot(struct mt_device *td, struct input_dev *input,
minor = minor >> 1;
}
- input_event(input, EV_ABS, ABS_MT_POSITION_X, *slot->x);
- input_event(input, EV_ABS, ABS_MT_POSITION_Y, *slot->y);
- input_event(input, EV_ABS, ABS_MT_TOOL_X, *slot->cx);
- input_event(input, EV_ABS, ABS_MT_TOOL_Y, *slot->cy);
+ x = hdev->quirks & HID_QUIRK_X_INVERT ?
+ input_abs_get_max(input, ABS_MT_POSITION_X) - *slot->x :
+ *slot->x;
+ y = hdev->quirks & HID_QUIRK_Y_INVERT ?
+ input_abs_get_max(input, ABS_MT_POSITION_Y) - *slot->y :
+ *slot->y;
+ cx = hdev->quirks & HID_QUIRK_X_INVERT ?
+ input_abs_get_max(input, ABS_MT_POSITION_X) - *slot->cx :
+ *slot->cx;
+ cy = hdev->quirks & HID_QUIRK_Y_INVERT ?
+ input_abs_get_max(input, ABS_MT_POSITION_Y) - *slot->cy :
+ *slot->cy;
+
+ input_event(input, EV_ABS, ABS_MT_POSITION_X, x);
+ input_event(input, EV_ABS, ABS_MT_POSITION_Y, y);
+ input_event(input, EV_ABS, ABS_MT_TOOL_X, cx);
+ input_event(input, EV_ABS, ABS_MT_TOOL_Y, cy);
input_event(input, EV_ABS, ABS_MT_DISTANCE, !*slot->tip_state);
input_event(input, EV_ABS, ABS_MT_ORIENTATION, orientation);
input_event(input, EV_ABS, ABS_MT_PRESSURE, *slot->p);
@@ -1735,6 +1757,15 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID)
td->serial_maybe = true;
+
+ /* Orientation is inverted if the X or Y axes are
+ * flipped, but normalized if both are inverted.
+ */
+ if (hdev->quirks & (HID_QUIRK_X_INVERT | HID_QUIRK_Y_INVERT) &&
+ !((hdev->quirks & HID_QUIRK_X_INVERT)
+ && (hdev->quirks & HID_QUIRK_Y_INVERT)))
+ td->mtclass.quirks = MT_QUIRK_ORIENTATION_INVERT;
+
/* This allows the driver to correctly support devices
* that emit events over several HID messages.
*/
diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c
index 27c40894acab..8ac8f7b8e317 100644
--- a/drivers/hid/hid-playstation.c
+++ b/drivers/hid/hid-playstation.c
@@ -993,19 +993,22 @@ static int dualsense_get_calibration_data(struct dualsense *ds)
*/
speed_2x = (gyro_speed_plus + gyro_speed_minus);
ds->gyro_calib_data[0].abs_code = ABS_RX;
- ds->gyro_calib_data[0].bias = gyro_pitch_bias;
+ ds->gyro_calib_data[0].bias = 0;
ds->gyro_calib_data[0].sens_numer = speed_2x*DS_GYRO_RES_PER_DEG_S;
- ds->gyro_calib_data[0].sens_denom = gyro_pitch_plus - gyro_pitch_minus;
+ ds->gyro_calib_data[0].sens_denom = abs(gyro_pitch_plus - gyro_pitch_bias) +
+ abs(gyro_pitch_minus - gyro_pitch_bias);
ds->gyro_calib_data[1].abs_code = ABS_RY;
- ds->gyro_calib_data[1].bias = gyro_yaw_bias;
+ ds->gyro_calib_data[1].bias = 0;
ds->gyro_calib_data[1].sens_numer = speed_2x*DS_GYRO_RES_PER_DEG_S;
- ds->gyro_calib_data[1].sens_denom = gyro_yaw_plus - gyro_yaw_minus;
+ ds->gyro_calib_data[1].sens_denom = abs(gyro_yaw_plus - gyro_yaw_bias) +
+ abs(gyro_yaw_minus - gyro_yaw_bias);
ds->gyro_calib_data[2].abs_code = ABS_RZ;
- ds->gyro_calib_data[2].bias = gyro_roll_bias;
+ ds->gyro_calib_data[2].bias = 0;
ds->gyro_calib_data[2].sens_numer = speed_2x*DS_GYRO_RES_PER_DEG_S;
- ds->gyro_calib_data[2].sens_denom = gyro_roll_plus - gyro_roll_minus;
+ ds->gyro_calib_data[2].sens_denom = abs(gyro_roll_plus - gyro_roll_bias) +
+ abs(gyro_roll_minus - gyro_roll_bias);
/*
* Sanity check gyro calibration data. This is needed to prevent crashes
@@ -1388,8 +1391,7 @@ static int dualsense_parse_report(struct ps_device *ps_dev, struct hid_report *r
for (i = 0; i < ARRAY_SIZE(ds_report->gyro); i++) {
int raw_data = (short)le16_to_cpu(ds_report->gyro[i]);
int calib_data = mult_frac(ds->gyro_calib_data[i].sens_numer,
- raw_data - ds->gyro_calib_data[i].bias,
- ds->gyro_calib_data[i].sens_denom);
+ raw_data, ds->gyro_calib_data[i].sens_denom);
input_report_abs(ds->sensors, ds->gyro_calib_data[i].abs_code, calib_data);
}
@@ -1792,11 +1794,10 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4)
if (retries < 2) {
hid_warn(hdev, "Retrying DualShock 4 get calibration report (0x02) request\n");
continue;
- } else {
- ret = -EILSEQ;
- goto err_free;
}
+
hid_err(hdev, "Failed to retrieve DualShock4 calibration info: %d\n", ret);
+ ret = -EILSEQ;
goto err_free;
} else {
break;
@@ -1849,19 +1850,22 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4)
*/
speed_2x = (gyro_speed_plus + gyro_speed_minus);
ds4->gyro_calib_data[0].abs_code = ABS_RX;
- ds4->gyro_calib_data[0].bias = gyro_pitch_bias;
+ ds4->gyro_calib_data[0].bias = 0;
ds4->gyro_calib_data[0].sens_numer = speed_2x*DS4_GYRO_RES_PER_DEG_S;
- ds4->gyro_calib_data[0].sens_denom = gyro_pitch_plus - gyro_pitch_minus;
+ ds4->gyro_calib_data[0].sens_denom = abs(gyro_pitch_plus - gyro_pitch_bias) +
+ abs(gyro_pitch_minus - gyro_pitch_bias);
ds4->gyro_calib_data[1].abs_code = ABS_RY;
- ds4->gyro_calib_data[1].bias = gyro_yaw_bias;
+ ds4->gyro_calib_data[1].bias = 0;
ds4->gyro_calib_data[1].sens_numer = speed_2x*DS4_GYRO_RES_PER_DEG_S;
- ds4->gyro_calib_data[1].sens_denom = gyro_yaw_plus - gyro_yaw_minus;
+ ds4->gyro_calib_data[1].sens_denom = abs(gyro_yaw_plus - gyro_yaw_bias) +
+ abs(gyro_yaw_minus - gyro_yaw_bias);
ds4->gyro_calib_data[2].abs_code = ABS_RZ;
- ds4->gyro_calib_data[2].bias = gyro_roll_bias;
+ ds4->gyro_calib_data[2].bias = 0;
ds4->gyro_calib_data[2].sens_numer = speed_2x*DS4_GYRO_RES_PER_DEG_S;
- ds4->gyro_calib_data[2].sens_denom = gyro_roll_plus - gyro_roll_minus;
+ ds4->gyro_calib_data[2].sens_denom = abs(gyro_roll_plus - gyro_roll_bias) +
+ abs(gyro_roll_minus - gyro_roll_bias);
/*
* Sanity check gyro calibration data. This is needed to prevent crashes
@@ -2242,8 +2246,7 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report *
for (i = 0; i < ARRAY_SIZE(ds4_report->gyro); i++) {
int raw_data = (short)le16_to_cpu(ds4_report->gyro[i]);
int calib_data = mult_frac(ds4->gyro_calib_data[i].sens_numer,
- raw_data - ds4->gyro_calib_data[i].bias,
- ds4->gyro_calib_data[i].sens_denom);
+ raw_data, ds4->gyro_calib_data[i].sens_denom);
input_report_abs(ds4->sensors, ds4->gyro_calib_data[i].abs_code, calib_data);
}
diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
index 5bc91f68b374..66e64350f138 100644
--- a/drivers/hid/hid-quirks.c
+++ b/drivers/hid/hid-quirks.c
@@ -1237,7 +1237,7 @@ EXPORT_SYMBOL_GPL(hid_quirks_exit);
static unsigned long hid_gets_squirk(const struct hid_device *hdev)
{
const struct hid_device_id *bl_entry;
- unsigned long quirks = 0;
+ unsigned long quirks = hdev->initial_quirks;
if (hid_match_id(hdev, hid_ignore_list))
quirks |= HID_QUIRK_IGNORE;
diff --git a/drivers/hid/hid-sensor-custom.c b/drivers/hid/hid-sensor-custom.c
index f444e63e9f36..3e3f89e01d81 100644
--- a/drivers/hid/hid-sensor-custom.c
+++ b/drivers/hid/hid-sensor-custom.c
@@ -5,6 +5,7 @@
*/
#include <linux/ctype.h>
+#include <linux/dmi.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -750,114 +751,209 @@ static void hid_sensor_custom_dev_if_remove(struct hid_sensor_custom
}
-/* luid defined in FW (e.g. ISH). Maybe used to identify sensor. */
-static const char *const known_sensor_luid[] = { "020B000000000000" };
+/*
+ * Match a known custom sensor.
+ * tag and luid is mandatory.
+ */
+struct hid_sensor_custom_match {
+ const char *tag;
+ const char *luid;
+ const char *model;
+ const char *manufacturer;
+ bool check_dmi;
+ struct dmi_system_id dmi;
+};
-static int get_luid_table_index(unsigned char *usage_str)
-{
- int i;
+/*
+ * Custom sensor properties used for matching.
+ */
+struct hid_sensor_custom_properties {
+ u16 serial_num[HID_CUSTOM_MAX_FEATURE_BYTES];
+ u16 model[HID_CUSTOM_MAX_FEATURE_BYTES];
+ u16 manufacturer[HID_CUSTOM_MAX_FEATURE_BYTES];
+};
+
+static const struct hid_sensor_custom_match hid_sensor_custom_known_table[] = {
+ /*
+ * Intel Integrated Sensor Hub (ISH)
+ */
+ { /* Intel ISH hinge */
+ .tag = "INT",
+ .luid = "020B000000000000",
+ .manufacturer = "INTEL",
+ },
+ /*
+ * Lenovo Intelligent Sensing Solution (LISS)
+ */
+ { /* ambient light */
+ .tag = "LISS",
+ .luid = "0041010200000082",
+ .model = "STK3X3X Sensor",
+ .manufacturer = "Vendor 258",
+ .check_dmi = true,
+ .dmi.matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ }
+ },
+ { /* human presence */
+ .tag = "LISS",
+ .luid = "0226000171AC0081",
+ .model = "VL53L1_HOD Sensor",
+ .manufacturer = "ST_MICRO",
+ .check_dmi = true,
+ .dmi.matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ }
+ },
+ {}
+};
- for (i = 0; i < ARRAY_SIZE(known_sensor_luid); i++) {
- if (!strncmp(usage_str, known_sensor_luid[i],
- strlen(known_sensor_luid[i])))
- return i;
+static bool hid_sensor_custom_prop_match_str(const u16 *prop, const char *match,
+ size_t count)
+{
+ while (count-- && *prop && *match) {
+ if (*prop != (u16) *match)
+ return false;
+ prop++;
+ match++;
}
- return -ENODEV;
+ return (count == -1) || *prop == (u16)*match;
}
-static int get_known_custom_sensor_index(struct hid_sensor_hub_device *hsdev)
+static int hid_sensor_custom_get_prop(struct hid_sensor_hub_device *hsdev,
+ u32 prop_usage_id, size_t prop_size,
+ u16 *prop)
{
- struct hid_sensor_hub_attribute_info sensor_manufacturer = { 0 };
- struct hid_sensor_hub_attribute_info sensor_luid_info = { 0 };
- int report_size;
+ struct hid_sensor_hub_attribute_info prop_attr = { 0 };
int ret;
- static u16 w_buf[HID_CUSTOM_MAX_FEATURE_BYTES];
- static char buf[HID_CUSTOM_MAX_FEATURE_BYTES];
- int i;
- memset(w_buf, 0, sizeof(w_buf));
- memset(buf, 0, sizeof(buf));
+ memset(prop, 0, prop_size);
- /* get manufacturer info */
- ret = sensor_hub_input_get_attribute_info(hsdev,
- HID_FEATURE_REPORT, hsdev->usage,
- HID_USAGE_SENSOR_PROP_MANUFACTURER, &sensor_manufacturer);
+ ret = sensor_hub_input_get_attribute_info(hsdev, HID_FEATURE_REPORT,
+ hsdev->usage, prop_usage_id,
+ &prop_attr);
if (ret < 0)
return ret;
- report_size =
- sensor_hub_get_feature(hsdev, sensor_manufacturer.report_id,
- sensor_manufacturer.index, sizeof(w_buf),
- w_buf);
- if (report_size <= 0) {
- hid_err(hsdev->hdev,
- "Failed to get sensor manufacturer info %d\n",
- report_size);
- return -ENODEV;
+ ret = sensor_hub_get_feature(hsdev, prop_attr.report_id,
+ prop_attr.index, prop_size, prop);
+ if (ret < 0) {
+ hid_err(hsdev->hdev, "Failed to get sensor property %08x %d\n",
+ prop_usage_id, ret);
+ return ret;
}
- /* convert from wide char to char */
- for (i = 0; i < ARRAY_SIZE(buf) - 1 && w_buf[i]; i++)
- buf[i] = (char)w_buf[i];
+ return 0;
+}
- /* ensure it's ISH sensor */
- if (strncmp(buf, "INTEL", strlen("INTEL")))
- return -ENODEV;
+static bool
+hid_sensor_custom_do_match(struct hid_sensor_hub_device *hsdev,
+ const struct hid_sensor_custom_match *match,
+ const struct hid_sensor_custom_properties *prop)
+{
+ struct dmi_system_id dmi[] = { match->dmi, { 0 } };
- memset(w_buf, 0, sizeof(w_buf));
- memset(buf, 0, sizeof(buf));
+ if (!hid_sensor_custom_prop_match_str(prop->serial_num, "LUID:", 5) ||
+ !hid_sensor_custom_prop_match_str(prop->serial_num + 5, match->luid,
+ HID_CUSTOM_MAX_FEATURE_BYTES - 5))
+ return false;
- /* get real usage id */
- ret = sensor_hub_input_get_attribute_info(hsdev,
- HID_FEATURE_REPORT, hsdev->usage,
- HID_USAGE_SENSOR_PROP_SERIAL_NUM, &sensor_luid_info);
+ if (match->model &&
+ !hid_sensor_custom_prop_match_str(prop->model, match->model,
+ HID_CUSTOM_MAX_FEATURE_BYTES))
+ return false;
+
+ if (match->manufacturer &&
+ !hid_sensor_custom_prop_match_str(prop->manufacturer, match->manufacturer,
+ HID_CUSTOM_MAX_FEATURE_BYTES))
+ return false;
+
+ if (match->check_dmi && !dmi_check_system(dmi))
+ return false;
+
+ return true;
+}
+
+static int
+hid_sensor_custom_properties_get(struct hid_sensor_hub_device *hsdev,
+ struct hid_sensor_custom_properties *prop)
+{
+ int ret;
+
+ ret = hid_sensor_custom_get_prop(hsdev,
+ HID_USAGE_SENSOR_PROP_SERIAL_NUM,
+ HID_CUSTOM_MAX_FEATURE_BYTES,
+ prop->serial_num);
if (ret < 0)
return ret;
- report_size = sensor_hub_get_feature(hsdev, sensor_luid_info.report_id,
- sensor_luid_info.index, sizeof(w_buf),
- w_buf);
- if (report_size <= 0) {
- hid_err(hsdev->hdev, "Failed to get real usage info %d\n",
- report_size);
- return -ENODEV;
- }
+ /*
+ * Ignore errors on the following model and manufacturer properties.
+ * Because these are optional, it is not an error if they are missing.
+ */
- /* convert from wide char to char */
- for (i = 0; i < ARRAY_SIZE(buf) - 1 && w_buf[i]; i++)
- buf[i] = (char)w_buf[i];
+ hid_sensor_custom_get_prop(hsdev, HID_USAGE_SENSOR_PROP_MODEL,
+ HID_CUSTOM_MAX_FEATURE_BYTES,
+ prop->model);
- if (strlen(buf) != strlen(known_sensor_luid[0]) + 5) {
- hid_err(hsdev->hdev,
- "%s luid length not match %zu != (%zu + 5)\n", __func__,
- strlen(buf), strlen(known_sensor_luid[0]));
- return -ENODEV;
- }
+ hid_sensor_custom_get_prop(hsdev, HID_USAGE_SENSOR_PROP_MANUFACTURER,
+ HID_CUSTOM_MAX_FEATURE_BYTES,
+ prop->manufacturer);
- /* get table index with luid (not matching 'LUID: ' in luid) */
- return get_luid_table_index(&buf[5]);
+ return 0;
+}
+
+static int
+hid_sensor_custom_get_known(struct hid_sensor_hub_device *hsdev,
+ const struct hid_sensor_custom_match **known)
+{
+ int ret;
+ const struct hid_sensor_custom_match *match =
+ hid_sensor_custom_known_table;
+ struct hid_sensor_custom_properties *prop;
+
+ prop = kmalloc(sizeof(struct hid_sensor_custom_properties), GFP_KERNEL);
+ if (!prop)
+ return -ENOMEM;
+
+ ret = hid_sensor_custom_properties_get(hsdev, prop);
+ if (ret < 0)
+ goto out;
+
+ while (match->tag) {
+ if (hid_sensor_custom_do_match(hsdev, match, prop)) {
+ *known = match;
+ ret = 0;
+ goto out;
+ }
+ match++;
+ }
+ ret = -ENODATA;
+out:
+ kfree(prop);
+ return ret;
}
static struct platform_device *
hid_sensor_register_platform_device(struct platform_device *pdev,
struct hid_sensor_hub_device *hsdev,
- int index)
+ const struct hid_sensor_custom_match *match)
{
- char real_usage[HID_SENSOR_USAGE_LENGTH] = { 0 };
+ char real_usage[HID_SENSOR_USAGE_LENGTH];
struct platform_device *custom_pdev;
const char *dev_name;
char *c;
- /* copy real usage id */
- memcpy(real_usage, known_sensor_luid[index], 4);
+ memcpy(real_usage, match->luid, 4);
/* usage id are all lowcase */
for (c = real_usage; *c != '\0'; c++)
*c = tolower(*c);
- /* HID-SENSOR-INT-REAL_USAGE_ID */
- dev_name = kasprintf(GFP_KERNEL, "HID-SENSOR-INT-%s", real_usage);
+ /* HID-SENSOR-TAG-REAL_USAGE_ID */
+ dev_name = kasprintf(GFP_KERNEL, "HID-SENSOR-%s-%s",
+ match->tag, real_usage);
if (!dev_name)
return ERR_PTR(-ENOMEM);
@@ -873,7 +969,7 @@ static int hid_sensor_custom_probe(struct platform_device *pdev)
struct hid_sensor_custom *sensor_inst;
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
int ret;
- int index;
+ const struct hid_sensor_custom_match *match;
sensor_inst = devm_kzalloc(&pdev->dev, sizeof(*sensor_inst),
GFP_KERNEL);
@@ -888,10 +984,10 @@ static int hid_sensor_custom_probe(struct platform_device *pdev)
mutex_init(&sensor_inst->mutex);
platform_set_drvdata(pdev, sensor_inst);
- index = get_known_custom_sensor_index(hsdev);
- if (index >= 0 && index < ARRAY_SIZE(known_sensor_luid)) {
+ ret = hid_sensor_custom_get_known(hsdev, &match);
+ if (!ret) {
sensor_inst->custom_pdev =
- hid_sensor_register_platform_device(pdev, hsdev, index);
+ hid_sensor_register_platform_device(pdev, hsdev, match);
ret = PTR_ERR_OR_ZERO(sensor_inst->custom_pdev);
if (ret) {
diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c
index 6abd3e2a9094..83237b86c8ff 100644
--- a/drivers/hid/hid-sensor-hub.c
+++ b/drivers/hid/hid-sensor-hub.c
@@ -397,7 +397,8 @@ int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev,
for (i = 0; i < report->maxfield; ++i) {
field = report->field[i];
if (field->maxusage) {
- if (field->physical == usage_id &&
+ if ((field->physical == usage_id ||
+ field->application == usage_id) &&
(field->logical == attr_usage_id ||
field->usage[0].hid ==
attr_usage_id) &&
@@ -506,7 +507,8 @@ static int sensor_hub_raw_event(struct hid_device *hdev,
collection->usage);
callback = sensor_hub_get_callback(hdev,
- report->field[i]->physical,
+ report->field[i]->physical ? report->field[i]->physical :
+ report->field[i]->application,
report->field[i]->usage[0].collection_index,
&hsdev, &priv);
if (!callback) {
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 13125997ab5e..dd942061fd77 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -49,38 +49,28 @@
#define SIXAXIS_CONTROLLER_BT BIT(2)
#define BUZZ_CONTROLLER BIT(3)
#define PS3REMOTE BIT(4)
-#define DUALSHOCK4_CONTROLLER_USB BIT(5)
-#define DUALSHOCK4_CONTROLLER_BT BIT(6)
-#define DUALSHOCK4_DONGLE BIT(7)
-#define MOTION_CONTROLLER_USB BIT(8)
-#define MOTION_CONTROLLER_BT BIT(9)
-#define NAVIGATION_CONTROLLER_USB BIT(10)
-#define NAVIGATION_CONTROLLER_BT BIT(11)
-#define SINO_LITE_CONTROLLER BIT(12)
-#define FUTUREMAX_DANCE_MAT BIT(13)
-#define NSG_MR5U_REMOTE_BT BIT(14)
-#define NSG_MR7U_REMOTE_BT BIT(15)
-#define SHANWAN_GAMEPAD BIT(16)
-#define GH_GUITAR_CONTROLLER BIT(17)
-#define GHL_GUITAR_PS3WIIU BIT(18)
-#define GHL_GUITAR_PS4 BIT(19)
+#define MOTION_CONTROLLER_USB BIT(5)
+#define MOTION_CONTROLLER_BT BIT(6)
+#define NAVIGATION_CONTROLLER_USB BIT(7)
+#define NAVIGATION_CONTROLLER_BT BIT(8)
+#define SINO_LITE_CONTROLLER BIT(9)
+#define FUTUREMAX_DANCE_MAT BIT(10)
+#define NSG_MR5U_REMOTE_BT BIT(11)
+#define NSG_MR7U_REMOTE_BT BIT(12)
+#define SHANWAN_GAMEPAD BIT(13)
+#define GH_GUITAR_CONTROLLER BIT(14)
+#define GHL_GUITAR_PS3WIIU BIT(15)
+#define GHL_GUITAR_PS4 BIT(16)
#define SIXAXIS_CONTROLLER (SIXAXIS_CONTROLLER_USB | SIXAXIS_CONTROLLER_BT)
#define MOTION_CONTROLLER (MOTION_CONTROLLER_USB | MOTION_CONTROLLER_BT)
#define NAVIGATION_CONTROLLER (NAVIGATION_CONTROLLER_USB |\
NAVIGATION_CONTROLLER_BT)
-#define DUALSHOCK4_CONTROLLER (DUALSHOCK4_CONTROLLER_USB |\
- DUALSHOCK4_CONTROLLER_BT | \
- DUALSHOCK4_DONGLE)
#define SONY_LED_SUPPORT (SIXAXIS_CONTROLLER | BUZZ_CONTROLLER |\
- DUALSHOCK4_CONTROLLER | MOTION_CONTROLLER |\
- NAVIGATION_CONTROLLER)
-#define SONY_BATTERY_SUPPORT (SIXAXIS_CONTROLLER | DUALSHOCK4_CONTROLLER |\
- MOTION_CONTROLLER_BT | NAVIGATION_CONTROLLER)
-#define SONY_FF_SUPPORT (SIXAXIS_CONTROLLER | DUALSHOCK4_CONTROLLER |\
- MOTION_CONTROLLER)
-#define SONY_BT_DEVICE (SIXAXIS_CONTROLLER_BT | DUALSHOCK4_CONTROLLER_BT |\
- MOTION_CONTROLLER_BT | NAVIGATION_CONTROLLER_BT)
+ MOTION_CONTROLLER | NAVIGATION_CONTROLLER)
+#define SONY_BATTERY_SUPPORT (SIXAXIS_CONTROLLER | MOTION_CONTROLLER_BT | NAVIGATION_CONTROLLER)
+#define SONY_FF_SUPPORT (SIXAXIS_CONTROLLER | MOTION_CONTROLLER)
+#define SONY_BT_DEVICE (SIXAXIS_CONTROLLER_BT | MOTION_CONTROLLER_BT | NAVIGATION_CONTROLLER_BT)
#define NSG_MRXU_REMOTE (NSG_MR5U_REMOTE_BT | NSG_MR7U_REMOTE_BT)
#define MAX_LEDS 4
@@ -428,36 +418,6 @@ static const unsigned int sixaxis_keymap[] = {
[0x11] = BTN_MODE, /* PS */
};
-static const unsigned int ds4_absmap[] = {
- [0x30] = ABS_X,
- [0x31] = ABS_Y,
- [0x32] = ABS_RX, /* right stick X */
- [0x33] = ABS_Z, /* L2 */
- [0x34] = ABS_RZ, /* R2 */
- [0x35] = ABS_RY, /* right stick Y */
-};
-
-static const unsigned int ds4_keymap[] = {
- [0x1] = BTN_WEST, /* Square */
- [0x2] = BTN_SOUTH, /* Cross */
- [0x3] = BTN_EAST, /* Circle */
- [0x4] = BTN_NORTH, /* Triangle */
- [0x5] = BTN_TL, /* L1 */
- [0x6] = BTN_TR, /* R1 */
- [0x7] = BTN_TL2, /* L2 */
- [0x8] = BTN_TR2, /* R2 */
- [0x9] = BTN_SELECT, /* Share */
- [0xa] = BTN_START, /* Options */
- [0xb] = BTN_THUMBL, /* L3 */
- [0xc] = BTN_THUMBR, /* R3 */
- [0xd] = BTN_MODE, /* PS */
-};
-
-static const struct {int x; int y; } ds4_hat_mapping[] = {
- {0, -1}, {1, -1}, {1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1},
- {0, 0}
-};
-
static enum power_supply_property sony_battery_props[] = {
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_CAPACITY,
@@ -502,35 +462,12 @@ struct motion_output_report_02 {
u8 rumble;
};
-#define DS4_FEATURE_REPORT_0x02_SIZE 37
-#define DS4_FEATURE_REPORT_0x05_SIZE 41
-#define DS4_FEATURE_REPORT_0x81_SIZE 7
-#define DS4_FEATURE_REPORT_0xA3_SIZE 49
-#define DS4_INPUT_REPORT_0x11_SIZE 78
-#define DS4_OUTPUT_REPORT_0x05_SIZE 32
-#define DS4_OUTPUT_REPORT_0x11_SIZE 78
#define SIXAXIS_REPORT_0xF2_SIZE 17
#define SIXAXIS_REPORT_0xF5_SIZE 8
#define MOTION_REPORT_0x02_SIZE 49
-/* Offsets relative to USB input report (0x1). Bluetooth (0x11) requires an
- * additional +2.
- */
-#define DS4_INPUT_REPORT_AXIS_OFFSET 1
-#define DS4_INPUT_REPORT_BUTTON_OFFSET 5
-#define DS4_INPUT_REPORT_TIMESTAMP_OFFSET 10
-#define DS4_INPUT_REPORT_GYRO_X_OFFSET 13
-#define DS4_INPUT_REPORT_BATTERY_OFFSET 30
-#define DS4_INPUT_REPORT_TOUCHPAD_OFFSET 33
-
#define SENSOR_SUFFIX " Motion Sensors"
-#define DS4_TOUCHPAD_SUFFIX " Touchpad"
-
-/* Default to 4ms poll interval, which is same as USB (not adjustable). */
-#define DS4_BT_DEFAULT_POLL_INTERVAL_MS 4
-#define DS4_BT_MAX_POLL_INTERVAL_MS 62
-#define DS4_GYRO_RES_PER_DEG_S 1024
-#define DS4_ACC_RES_PER_G 8192
+#define TOUCHPAD_SUFFIX " Touchpad"
#define SIXAXIS_INPUT_REPORT_ACC_X_OFFSET 41
#define SIXAXIS_ACC_RES_PER_G 113
@@ -539,28 +476,8 @@ static DEFINE_SPINLOCK(sony_dev_list_lock);
static LIST_HEAD(sony_device_list);
static DEFINE_IDA(sony_device_id_allocator);
-/* Used for calibration of DS4 accelerometer and gyro. */
-struct ds4_calibration_data {
- int abs_code;
- short bias;
- /* Calibration requires scaling against a sensitivity value, which is a
- * float. Store sensitivity as a fraction to limit floating point
- * calculations until final calibration.
- */
- int sens_numer;
- int sens_denom;
-};
-
-enum ds4_dongle_state {
- DONGLE_DISCONNECTED,
- DONGLE_CALIBRATING,
- DONGLE_CONNECTED,
- DONGLE_DISABLED
-};
-
enum sony_worker {
- SONY_WORKER_STATE,
- SONY_WORKER_HOTPLUG
+ SONY_WORKER_STATE
};
struct sony_sc {
@@ -571,16 +488,11 @@ struct sony_sc {
struct input_dev *sensor_dev;
struct led_classdev *leds[MAX_LEDS];
unsigned long quirks;
- struct work_struct hotplug_worker;
struct work_struct state_worker;
void (*send_output_report)(struct sony_sc *);
struct power_supply *battery;
struct power_supply_desc battery_desc;
int device_id;
- unsigned fw_version;
- bool fw_version_created;
- unsigned hw_version;
- bool hw_version_created;
u8 *output_report_dmabuf;
#ifdef CONFIG_SONY_FF
@@ -589,7 +501,6 @@ struct sony_sc {
#endif
u8 mac_address[6];
- u8 hotplug_worker_initialized;
u8 state_worker_initialized;
u8 defer_initialization;
u8 battery_capacity;
@@ -599,14 +510,6 @@ struct sony_sc {
u8 led_delay_off[MAX_LEDS];
u8 led_count;
- bool timestamp_initialized;
- u16 prev_timestamp;
- unsigned int timestamp_us;
-
- u8 ds4_bt_poll_interval;
- enum ds4_dongle_state ds4_dongle_state;
- /* DS4 calibration data */
- struct ds4_calibration_data ds4_calib_data[6];
/* GH Live */
struct urb *ghl_urb;
struct timer_list ghl_poke_timer;
@@ -626,10 +529,6 @@ static inline void sony_schedule_work(struct sony_sc *sc,
schedule_work(&sc->state_worker);
spin_unlock_irqrestore(&sc->lock, flags);
break;
- case SONY_WORKER_HOTPLUG:
- if (sc->hotplug_worker_initialized)
- schedule_work(&sc->hotplug_worker);
- break;
}
}
@@ -700,67 +599,6 @@ static int guitar_mapping(struct hid_device *hdev, struct hid_input *hi,
return 0;
}
-static ssize_t ds4_show_poll_interval(struct device *dev,
- struct device_attribute
- *attr, char *buf)
-{
- struct hid_device *hdev = to_hid_device(dev);
- struct sony_sc *sc = hid_get_drvdata(hdev);
-
- return snprintf(buf, PAGE_SIZE, "%i\n", sc->ds4_bt_poll_interval);
-}
-
-static ssize_t ds4_store_poll_interval(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct hid_device *hdev = to_hid_device(dev);
- struct sony_sc *sc = hid_get_drvdata(hdev);
- unsigned long flags;
- u8 interval;
-
- if (kstrtou8(buf, 0, &interval))
- return -EINVAL;
-
- if (interval > DS4_BT_MAX_POLL_INTERVAL_MS)
- return -EINVAL;
-
- spin_lock_irqsave(&sc->lock, flags);
- sc->ds4_bt_poll_interval = interval;
- spin_unlock_irqrestore(&sc->lock, flags);
-
- sony_schedule_work(sc, SONY_WORKER_STATE);
-
- return count;
-}
-
-static DEVICE_ATTR(bt_poll_interval, 0644, ds4_show_poll_interval,
- ds4_store_poll_interval);
-
-static ssize_t sony_show_firmware_version(struct device *dev,
- struct device_attribute
- *attr, char *buf)
-{
- struct hid_device *hdev = to_hid_device(dev);
- struct sony_sc *sc = hid_get_drvdata(hdev);
-
- return snprintf(buf, PAGE_SIZE, "0x%04x\n", sc->fw_version);
-}
-
-static DEVICE_ATTR(firmware_version, 0444, sony_show_firmware_version, NULL);
-
-static ssize_t sony_show_hardware_version(struct device *dev,
- struct device_attribute
- *attr, char *buf)
-{
- struct hid_device *hdev = to_hid_device(dev);
- struct sony_sc *sc = hid_get_drvdata(hdev);
-
- return snprintf(buf, PAGE_SIZE, "0x%04x\n", sc->hw_version);
-}
-
-static DEVICE_ATTR(hardware_version, 0444, sony_show_hardware_version, NULL);
-
static u8 *motion_fixup(struct hid_device *hdev, u8 *rdesc,
unsigned int *rsize)
{
@@ -905,37 +743,6 @@ static int sixaxis_mapping(struct hid_device *hdev, struct hid_input *hi,
return -1;
}
-static int ds4_mapping(struct hid_device *hdev, struct hid_input *hi,
- struct hid_field *field, struct hid_usage *usage,
- unsigned long **bit, int *max)
-{
- if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) {
- unsigned int key = usage->hid & HID_USAGE;
-
- if (key >= ARRAY_SIZE(ds4_keymap))
- return -1;
-
- key = ds4_keymap[key];
- hid_map_usage_clear(hi, usage, bit, max, EV_KEY, key);
- return 1;
- } else if ((usage->hid & HID_USAGE_PAGE) == HID_UP_GENDESK) {
- unsigned int abs = usage->hid & HID_USAGE;
-
- /* Let the HID parser deal with the HAT. */
- if (usage->hid == HID_GD_HATSWITCH)
- return 0;
-
- if (abs >= ARRAY_SIZE(ds4_absmap))
- return -1;
-
- abs = ds4_absmap[abs];
- hid_map_usage_clear(hi, usage, bit, max, EV_ABS, abs);
- return 1;
- }
-
- return 0;
-}
-
static u8 *sony_report_fixup(struct hid_device *hdev, u8 *rdesc,
unsigned int *rsize)
{
@@ -1034,216 +841,6 @@ static void sixaxis_parse_report(struct sony_sc *sc, u8 *rd, int size)
}
}
-static void dualshock4_parse_report(struct sony_sc *sc, u8 *rd, int size)
-{
- struct hid_input *hidinput = list_entry(sc->hdev->inputs.next,
- struct hid_input, list);
- struct input_dev *input_dev = hidinput->input;
- unsigned long flags;
- int n, m, offset, num_touch_data, max_touch_data;
- u8 cable_state, battery_capacity;
- int battery_status;
- u16 timestamp;
-
- /* When using Bluetooth the header is 2 bytes longer, so skip these. */
- int data_offset = (sc->quirks & DUALSHOCK4_CONTROLLER_BT) ? 2 : 0;
-
- /* Second bit of third button byte is for the touchpad button. */
- offset = data_offset + DS4_INPUT_REPORT_BUTTON_OFFSET;
- input_report_key(sc->touchpad, BTN_LEFT, rd[offset+2] & 0x2);
-
- /*
- * The default behavior of the Dualshock 4 is to send reports using
- * report type 1 when running over Bluetooth. However, when feature
- * report 2 is requested during the controller initialization it starts
- * sending input reports in report 17. Since report 17 is undefined
- * in the default HID descriptor, the HID layer won't generate events.
- * While it is possible (and this was done before) to fixup the HID
- * descriptor to add this mapping, it was better to do this manually.
- * The reason is there were various pieces software both open and closed
- * source, relying on the descriptors to be the same across various
- * operating systems. If the descriptors wouldn't match some
- * applications e.g. games on Wine would not be able to function due
- * to different descriptors, which such applications are not parsing.
- */
- if (rd[0] == 17) {
- int value;
-
- offset = data_offset + DS4_INPUT_REPORT_AXIS_OFFSET;
- input_report_abs(input_dev, ABS_X, rd[offset]);
- input_report_abs(input_dev, ABS_Y, rd[offset+1]);
- input_report_abs(input_dev, ABS_RX, rd[offset+2]);
- input_report_abs(input_dev, ABS_RY, rd[offset+3]);
-
- value = rd[offset+4] & 0xf;
- if (value > 7)
- value = 8; /* Center 0, 0 */
- input_report_abs(input_dev, ABS_HAT0X, ds4_hat_mapping[value].x);
- input_report_abs(input_dev, ABS_HAT0Y, ds4_hat_mapping[value].y);
-
- input_report_key(input_dev, BTN_WEST, rd[offset+4] & 0x10);
- input_report_key(input_dev, BTN_SOUTH, rd[offset+4] & 0x20);
- input_report_key(input_dev, BTN_EAST, rd[offset+4] & 0x40);
- input_report_key(input_dev, BTN_NORTH, rd[offset+4] & 0x80);
-
- input_report_key(input_dev, BTN_TL, rd[offset+5] & 0x1);
- input_report_key(input_dev, BTN_TR, rd[offset+5] & 0x2);
- input_report_key(input_dev, BTN_TL2, rd[offset+5] & 0x4);
- input_report_key(input_dev, BTN_TR2, rd[offset+5] & 0x8);
- input_report_key(input_dev, BTN_SELECT, rd[offset+5] & 0x10);
- input_report_key(input_dev, BTN_START, rd[offset+5] & 0x20);
- input_report_key(input_dev, BTN_THUMBL, rd[offset+5] & 0x40);
- input_report_key(input_dev, BTN_THUMBR, rd[offset+5] & 0x80);
-
- input_report_key(input_dev, BTN_MODE, rd[offset+6] & 0x1);
-
- input_report_abs(input_dev, ABS_Z, rd[offset+7]);
- input_report_abs(input_dev, ABS_RZ, rd[offset+8]);
-
- input_sync(input_dev);
- }
-
- /* Convert timestamp (in 5.33us unit) to timestamp_us */
- offset = data_offset + DS4_INPUT_REPORT_TIMESTAMP_OFFSET;
- timestamp = get_unaligned_le16(&rd[offset]);
- if (!sc->timestamp_initialized) {
- sc->timestamp_us = ((unsigned int)timestamp * 16) / 3;
- sc->timestamp_initialized = true;
- } else {
- u16 delta;
-
- if (sc->prev_timestamp > timestamp)
- delta = (U16_MAX - sc->prev_timestamp + timestamp + 1);
- else
- delta = timestamp - sc->prev_timestamp;
- sc->timestamp_us += (delta * 16) / 3;
- }
- sc->prev_timestamp = timestamp;
- input_event(sc->sensor_dev, EV_MSC, MSC_TIMESTAMP, sc->timestamp_us);
-
- offset = data_offset + DS4_INPUT_REPORT_GYRO_X_OFFSET;
- for (n = 0; n < 6; n++) {
- /* Store data in int for more precision during mult_frac. */
- int raw_data = (short)((rd[offset+1] << 8) | rd[offset]);
- struct ds4_calibration_data *calib = &sc->ds4_calib_data[n];
-
- /* High precision is needed during calibration, but the
- * calibrated values are within 32-bit.
- * Note: we swap numerator 'x' and 'numer' in mult_frac for
- * precision reasons so we don't need 64-bit.
- */
- int calib_data = mult_frac(calib->sens_numer,
- raw_data - calib->bias,
- calib->sens_denom);
-
- input_report_abs(sc->sensor_dev, calib->abs_code, calib_data);
- offset += 2;
- }
- input_sync(sc->sensor_dev);
-
- /*
- * The lower 4 bits of byte 30 (or 32 for BT) contain the battery level
- * and the 5th bit contains the USB cable state.
- */
- offset = data_offset + DS4_INPUT_REPORT_BATTERY_OFFSET;
- cable_state = (rd[offset] >> 4) & 0x01;
-
- /*
- * Interpretation of the battery_capacity data depends on the cable state.
- * When no cable is connected (bit4 is 0):
- * - 0:10: percentage in units of 10%.
- * When a cable is plugged in:
- * - 0-10: percentage in units of 10%.
- * - 11: battery is full
- * - 14: not charging due to Voltage or temperature error
- * - 15: charge error
- */
- if (cable_state) {
- u8 battery_data = rd[offset] & 0xf;
-
- if (battery_data < 10) {
- /* Take the mid-point for each battery capacity value,
- * because on the hardware side 0 = 0-9%, 1=10-19%, etc.
- * This matches official platform behavior, which does
- * the same.
- */
- battery_capacity = battery_data * 10 + 5;
- battery_status = POWER_SUPPLY_STATUS_CHARGING;
- } else if (battery_data == 10) {
- battery_capacity = 100;
- battery_status = POWER_SUPPLY_STATUS_CHARGING;
- } else if (battery_data == 11) {
- battery_capacity = 100;
- battery_status = POWER_SUPPLY_STATUS_FULL;
- } else { /* 14, 15 and undefined values */
- battery_capacity = 0;
- battery_status = POWER_SUPPLY_STATUS_UNKNOWN;
- }
- } else {
- u8 battery_data = rd[offset] & 0xf;
-
- if (battery_data < 10)
- battery_capacity = battery_data * 10 + 5;
- else /* 10 */
- battery_capacity = 100;
-
- battery_status = POWER_SUPPLY_STATUS_DISCHARGING;
- }
-
- spin_lock_irqsave(&sc->lock, flags);
- sc->battery_capacity = battery_capacity;
- sc->battery_status = battery_status;
- spin_unlock_irqrestore(&sc->lock, flags);
-
- /*
- * The Dualshock 4 multi-touch trackpad data starts at offset 33 on USB
- * and 35 on Bluetooth.
- * The first byte indicates the number of touch data in the report.
- * Trackpad data starts 2 bytes later (e.g. 35 for USB).
- */
- offset = data_offset + DS4_INPUT_REPORT_TOUCHPAD_OFFSET;
- max_touch_data = (sc->quirks & DUALSHOCK4_CONTROLLER_BT) ? 4 : 3;
- if (rd[offset] > 0 && rd[offset] <= max_touch_data)
- num_touch_data = rd[offset];
- else
- num_touch_data = 1;
- offset += 1;
-
- for (m = 0; m < num_touch_data; m++) {
- /* Skip past timestamp */
- offset += 1;
-
- /*
- * The first 7 bits of the first byte is a counter and bit 8 is
- * a touch indicator that is 0 when pressed and 1 when not
- * pressed.
- * The next 3 bytes are two 12 bit touch coordinates, X and Y.
- * The data for the second touch is in the same format and
- * immediately follows the data for the first.
- */
- for (n = 0; n < 2; n++) {
- u16 x, y;
- bool active;
-
- x = rd[offset+1] | ((rd[offset+2] & 0xF) << 8);
- y = ((rd[offset+2] & 0xF0) >> 4) | (rd[offset+3] << 4);
-
- active = !(rd[offset] >> 7);
- input_mt_slot(sc->touchpad, n);
- input_mt_report_slot_state(sc->touchpad, MT_TOOL_FINGER, active);
-
- if (active) {
- input_report_abs(sc->touchpad, ABS_MT_POSITION_X, x);
- input_report_abs(sc->touchpad, ABS_MT_POSITION_Y, y);
- }
-
- offset += 4;
- }
- input_mt_sync_frame(sc->touchpad);
- input_sync(sc->touchpad);
- }
-}
-
static void nsg_mrxu_parse_report(struct sony_sc *sc, u8 *rd, int size)
{
int n, offset, relx, rely;
@@ -1350,83 +947,6 @@ static int sony_raw_event(struct hid_device *hdev, struct hid_report *report,
} else if ((sc->quirks & NAVIGATION_CONTROLLER) && rd[0] == 0x01 &&
size == 49) {
sixaxis_parse_report(sc, rd, size);
- } else if ((sc->quirks & DUALSHOCK4_CONTROLLER_USB) && rd[0] == 0x01 &&
- size == 64) {
- dualshock4_parse_report(sc, rd, size);
- } else if (((sc->quirks & DUALSHOCK4_CONTROLLER_BT) && rd[0] == 0x11 &&
- size == 78)) {
- /* CRC check */
- u8 bthdr = 0xA1;
- u32 crc;
- u32 report_crc;
-
- crc = crc32_le(0xFFFFFFFF, &bthdr, 1);
- crc = ~crc32_le(crc, rd, DS4_INPUT_REPORT_0x11_SIZE-4);
- report_crc = get_unaligned_le32(&rd[DS4_INPUT_REPORT_0x11_SIZE-4]);
- if (crc != report_crc) {
- hid_dbg(sc->hdev, "DualShock 4 input report's CRC check failed, received crc 0x%0x != 0x%0x\n",
- report_crc, crc);
- return -EILSEQ;
- }
-
- dualshock4_parse_report(sc, rd, size);
- } else if ((sc->quirks & DUALSHOCK4_DONGLE) && rd[0] == 0x01 &&
- size == 64) {
- unsigned long flags;
- enum ds4_dongle_state dongle_state;
-
- /*
- * In the case of a DS4 USB dongle, bit[2] of byte 31 indicates
- * if a DS4 is actually connected (indicated by '0').
- * For non-dongle, this bit is always 0 (connected).
- */
- bool connected = (rd[31] & 0x04) ? false : true;
-
- spin_lock_irqsave(&sc->lock, flags);
- dongle_state = sc->ds4_dongle_state;
- spin_unlock_irqrestore(&sc->lock, flags);
-
- /*
- * The dongle always sends input reports even when no
- * DS4 is attached. When a DS4 is connected, we need to
- * obtain calibration data before we can use it.
- * The code below tracks dongle state and kicks of
- * calibration when needed and only allows us to process
- * input if a DS4 is actually connected.
- */
- if (dongle_state == DONGLE_DISCONNECTED && connected) {
- hid_info(sc->hdev, "DualShock 4 USB dongle: controller connected\n");
- sony_set_leds(sc);
-
- spin_lock_irqsave(&sc->lock, flags);
- sc->ds4_dongle_state = DONGLE_CALIBRATING;
- spin_unlock_irqrestore(&sc->lock, flags);
-
- sony_schedule_work(sc, SONY_WORKER_HOTPLUG);
-
- /* Don't process the report since we don't have
- * calibration data, but let hidraw have it anyway.
- */
- return 0;
- } else if ((dongle_state == DONGLE_CONNECTED ||
- dongle_state == DONGLE_DISABLED) && !connected) {
- hid_info(sc->hdev, "DualShock 4 USB dongle: controller disconnected\n");
-
- spin_lock_irqsave(&sc->lock, flags);
- sc->ds4_dongle_state = DONGLE_DISCONNECTED;
- spin_unlock_irqrestore(&sc->lock, flags);
-
- /* Return 0, so hidraw can get the report. */
- return 0;
- } else if (dongle_state == DONGLE_CALIBRATING ||
- dongle_state == DONGLE_DISABLED ||
- dongle_state == DONGLE_DISCONNECTED) {
- /* Return 0, so hidraw can get the report. */
- return 0;
- }
-
- dualshock4_parse_report(sc, rd, size);
-
} else if ((sc->quirks & NSG_MRXU_REMOTE) && rd[0] == 0x02) {
nsg_mrxu_parse_report(sc, rd, size);
return 1;
@@ -1478,9 +998,6 @@ static int sony_mapping(struct hid_device *hdev, struct hid_input *hi,
if (sc->quirks & SIXAXIS_CONTROLLER)
return sixaxis_mapping(hdev, hi, field, usage, bit, max);
- if (sc->quirks & DUALSHOCK4_CONTROLLER)
- return ds4_mapping(hdev, hi, field, usage, bit, max);
-
if (sc->quirks & GH_GUITAR_CONTROLLER)
return guitar_mapping(hdev, hi, field, usage, bit, max);
@@ -1508,14 +1025,17 @@ static int sony_register_touchpad(struct sony_sc *sc, int touch_count,
sc->touchpad->id.product = sc->hdev->product;
sc->touchpad->id.version = sc->hdev->version;
- /* Append a suffix to the controller name as there are various
- * DS4 compatible non-Sony devices with different names.
+ /* This suffix was originally apended when hid-sony also
+ * supported DS4 devices. The DS4 was implemented using multiple
+ * evdev nodes and hence had the need to separete them out using
+ * a suffix. Other devices which were added later like Sony TV remotes
+ * inhirited this suffix.
*/
- name_sz = strlen(sc->hdev->name) + sizeof(DS4_TOUCHPAD_SUFFIX);
+ name_sz = strlen(sc->hdev->name) + sizeof(TOUCHPAD_SUFFIX);
name = devm_kzalloc(&sc->hdev->dev, name_sz, GFP_KERNEL);
if (!name)
return -ENOMEM;
- snprintf(name, name_sz, "%s" DS4_TOUCHPAD_SUFFIX, sc->hdev->name);
+ snprintf(name, name_sz, "%s" TOUCHPAD_SUFFIX, sc->hdev->name);
sc->touchpad->name = name;
/* We map the button underneath the touchpad to BTN_LEFT. */
@@ -1557,7 +1077,6 @@ static int sony_register_sensors(struct sony_sc *sc)
size_t name_sz;
char *name;
int ret;
- int range;
sc->sensor_dev = devm_input_allocate_device(&sc->hdev->dev);
if (!sc->sensor_dev)
@@ -1595,25 +1114,6 @@ static int sony_register_sensors(struct sony_sc *sc)
input_abs_set_res(sc->sensor_dev, ABS_X, SIXAXIS_ACC_RES_PER_G);
input_abs_set_res(sc->sensor_dev, ABS_Y, SIXAXIS_ACC_RES_PER_G);
input_abs_set_res(sc->sensor_dev, ABS_Z, SIXAXIS_ACC_RES_PER_G);
- } else if (sc->quirks & DUALSHOCK4_CONTROLLER) {
- range = DS4_ACC_RES_PER_G*4;
- input_set_abs_params(sc->sensor_dev, ABS_X, -range, range, 16, 0);
- input_set_abs_params(sc->sensor_dev, ABS_Y, -range, range, 16, 0);
- input_set_abs_params(sc->sensor_dev, ABS_Z, -range, range, 16, 0);
- input_abs_set_res(sc->sensor_dev, ABS_X, DS4_ACC_RES_PER_G);
- input_abs_set_res(sc->sensor_dev, ABS_Y, DS4_ACC_RES_PER_G);
- input_abs_set_res(sc->sensor_dev, ABS_Z, DS4_ACC_RES_PER_G);
-
- range = DS4_GYRO_RES_PER_DEG_S*2048;
- input_set_abs_params(sc->sensor_dev, ABS_RX, -range, range, 16, 0);
- input_set_abs_params(sc->sensor_dev, ABS_RY, -range, range, 16, 0);
- input_set_abs_params(sc->sensor_dev, ABS_RZ, -range, range, 16, 0);
- input_abs_set_res(sc->sensor_dev, ABS_RX, DS4_GYRO_RES_PER_DEG_S);
- input_abs_set_res(sc->sensor_dev, ABS_RY, DS4_GYRO_RES_PER_DEG_S);
- input_abs_set_res(sc->sensor_dev, ABS_RZ, DS4_GYRO_RES_PER_DEG_S);
-
- __set_bit(EV_MSC, sc->sensor_dev->evbit);
- __set_bit(MSC_TIMESTAMP, sc->sensor_dev->mscbit);
}
__set_bit(INPUT_PROP_ACCELEROMETER, sc->sensor_dev->propbit);
@@ -1697,224 +1197,6 @@ static int sixaxis_set_operational_bt(struct hid_device *hdev)
return ret;
}
-/*
- * Request DS4 calibration data for the motion sensors.
- * For Bluetooth this also affects the operating mode (see below).
- */
-static int dualshock4_get_calibration_data(struct sony_sc *sc)
-{
- u8 *buf;
- int ret;
- short gyro_pitch_bias, gyro_pitch_plus, gyro_pitch_minus;
- short gyro_yaw_bias, gyro_yaw_plus, gyro_yaw_minus;
- short gyro_roll_bias, gyro_roll_plus, gyro_roll_minus;
- short gyro_speed_plus, gyro_speed_minus;
- short acc_x_plus, acc_x_minus;
- short acc_y_plus, acc_y_minus;
- short acc_z_plus, acc_z_minus;
- int speed_2x;
- int range_2g;
-
- /* For Bluetooth we use a different request, which supports CRC.
- * Note: in Bluetooth mode feature report 0x02 also changes the state
- * of the controller, so that it sends input reports of type 0x11.
- */
- if (sc->quirks & (DUALSHOCK4_CONTROLLER_USB | DUALSHOCK4_DONGLE)) {
- int retries;
-
- buf = kmalloc(DS4_FEATURE_REPORT_0x02_SIZE, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- /* We should normally receive the feature report data we asked
- * for, but hidraw applications such as Steam can issue feature
- * reports as well. In particular for Dongle reconnects, Steam
- * and this function are competing resulting in often receiving
- * data for a different HID report, so retry a few times.
- */
- for (retries = 0; retries < 3; retries++) {
- ret = hid_hw_raw_request(sc->hdev, 0x02, buf,
- DS4_FEATURE_REPORT_0x02_SIZE,
- HID_FEATURE_REPORT,
- HID_REQ_GET_REPORT);
- if (ret < 0)
- goto err_stop;
-
- if (buf[0] != 0x02) {
- if (retries < 2) {
- hid_warn(sc->hdev, "Retrying DualShock 4 get calibration report (0x02) request\n");
- continue;
- } else {
- ret = -EILSEQ;
- goto err_stop;
- }
- } else {
- break;
- }
- }
- } else {
- u8 bthdr = 0xA3;
- u32 crc;
- u32 report_crc;
- int retries;
-
- buf = kmalloc(DS4_FEATURE_REPORT_0x05_SIZE, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- for (retries = 0; retries < 3; retries++) {
- ret = hid_hw_raw_request(sc->hdev, 0x05, buf,
- DS4_FEATURE_REPORT_0x05_SIZE,
- HID_FEATURE_REPORT,
- HID_REQ_GET_REPORT);
- if (ret < 0)
- goto err_stop;
-
- /* CRC check */
- crc = crc32_le(0xFFFFFFFF, &bthdr, 1);
- crc = ~crc32_le(crc, buf, DS4_FEATURE_REPORT_0x05_SIZE-4);
- report_crc = get_unaligned_le32(&buf[DS4_FEATURE_REPORT_0x05_SIZE-4]);
- if (crc != report_crc) {
- hid_warn(sc->hdev, "DualShock 4 calibration report's CRC check failed, received crc 0x%0x != 0x%0x\n",
- report_crc, crc);
- if (retries < 2) {
- hid_warn(sc->hdev, "Retrying DualShock 4 get calibration report request\n");
- continue;
- } else {
- ret = -EILSEQ;
- goto err_stop;
- }
- } else {
- break;
- }
- }
- }
-
- gyro_pitch_bias = get_unaligned_le16(&buf[1]);
- gyro_yaw_bias = get_unaligned_le16(&buf[3]);
- gyro_roll_bias = get_unaligned_le16(&buf[5]);
- if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) {
- gyro_pitch_plus = get_unaligned_le16(&buf[7]);
- gyro_pitch_minus = get_unaligned_le16(&buf[9]);
- gyro_yaw_plus = get_unaligned_le16(&buf[11]);
- gyro_yaw_minus = get_unaligned_le16(&buf[13]);
- gyro_roll_plus = get_unaligned_le16(&buf[15]);
- gyro_roll_minus = get_unaligned_le16(&buf[17]);
- } else {
- /* BT + Dongle */
- gyro_pitch_plus = get_unaligned_le16(&buf[7]);
- gyro_yaw_plus = get_unaligned_le16(&buf[9]);
- gyro_roll_plus = get_unaligned_le16(&buf[11]);
- gyro_pitch_minus = get_unaligned_le16(&buf[13]);
- gyro_yaw_minus = get_unaligned_le16(&buf[15]);
- gyro_roll_minus = get_unaligned_le16(&buf[17]);
- }
- gyro_speed_plus = get_unaligned_le16(&buf[19]);
- gyro_speed_minus = get_unaligned_le16(&buf[21]);
- acc_x_plus = get_unaligned_le16(&buf[23]);
- acc_x_minus = get_unaligned_le16(&buf[25]);
- acc_y_plus = get_unaligned_le16(&buf[27]);
- acc_y_minus = get_unaligned_le16(&buf[29]);
- acc_z_plus = get_unaligned_le16(&buf[31]);
- acc_z_minus = get_unaligned_le16(&buf[33]);
-
- /* Set gyroscope calibration and normalization parameters.
- * Data values will be normalized to 1/DS4_GYRO_RES_PER_DEG_S degree/s.
- */
- speed_2x = (gyro_speed_plus + gyro_speed_minus);
- sc->ds4_calib_data[0].abs_code = ABS_RX;
- sc->ds4_calib_data[0].bias = gyro_pitch_bias;
- sc->ds4_calib_data[0].sens_numer = speed_2x*DS4_GYRO_RES_PER_DEG_S;
- sc->ds4_calib_data[0].sens_denom = gyro_pitch_plus - gyro_pitch_minus;
-
- sc->ds4_calib_data[1].abs_code = ABS_RY;
- sc->ds4_calib_data[1].bias = gyro_yaw_bias;
- sc->ds4_calib_data[1].sens_numer = speed_2x*DS4_GYRO_RES_PER_DEG_S;
- sc->ds4_calib_data[1].sens_denom = gyro_yaw_plus - gyro_yaw_minus;
-
- sc->ds4_calib_data[2].abs_code = ABS_RZ;
- sc->ds4_calib_data[2].bias = gyro_roll_bias;
- sc->ds4_calib_data[2].sens_numer = speed_2x*DS4_GYRO_RES_PER_DEG_S;
- sc->ds4_calib_data[2].sens_denom = gyro_roll_plus - gyro_roll_minus;
-
- /* Set accelerometer calibration and normalization parameters.
- * Data values will be normalized to 1/DS4_ACC_RES_PER_G G.
- */
- range_2g = acc_x_plus - acc_x_minus;
- sc->ds4_calib_data[3].abs_code = ABS_X;
- sc->ds4_calib_data[3].bias = acc_x_plus - range_2g / 2;
- sc->ds4_calib_data[3].sens_numer = 2*DS4_ACC_RES_PER_G;
- sc->ds4_calib_data[3].sens_denom = range_2g;
-
- range_2g = acc_y_plus - acc_y_minus;
- sc->ds4_calib_data[4].abs_code = ABS_Y;
- sc->ds4_calib_data[4].bias = acc_y_plus - range_2g / 2;
- sc->ds4_calib_data[4].sens_numer = 2*DS4_ACC_RES_PER_G;
- sc->ds4_calib_data[4].sens_denom = range_2g;
-
- range_2g = acc_z_plus - acc_z_minus;
- sc->ds4_calib_data[5].abs_code = ABS_Z;
- sc->ds4_calib_data[5].bias = acc_z_plus - range_2g / 2;
- sc->ds4_calib_data[5].sens_numer = 2*DS4_ACC_RES_PER_G;
- sc->ds4_calib_data[5].sens_denom = range_2g;
-
-err_stop:
- kfree(buf);
- return ret;
-}
-
-static void dualshock4_calibration_work(struct work_struct *work)
-{
- struct sony_sc *sc = container_of(work, struct sony_sc, hotplug_worker);
- unsigned long flags;
- enum ds4_dongle_state dongle_state;
- int ret;
-
- ret = dualshock4_get_calibration_data(sc);
- if (ret < 0) {
- /* This call is very unlikely to fail for the dongle. When it
- * fails we are probably in a very bad state, so mark the
- * dongle as disabled. We will re-enable the dongle if a new
- * DS4 hotplug is detect from sony_raw_event as any issues
- * are likely resolved then (the dongle is quite stupid).
- */
- hid_err(sc->hdev, "DualShock 4 USB dongle: calibration failed, disabling device\n");
- dongle_state = DONGLE_DISABLED;
- } else {
- hid_info(sc->hdev, "DualShock 4 USB dongle: calibration completed\n");
- dongle_state = DONGLE_CONNECTED;
- }
-
- spin_lock_irqsave(&sc->lock, flags);
- sc->ds4_dongle_state = dongle_state;
- spin_unlock_irqrestore(&sc->lock, flags);
-}
-
-static int dualshock4_get_version_info(struct sony_sc *sc)
-{
- u8 *buf;
- int ret;
-
- buf = kmalloc(DS4_FEATURE_REPORT_0xA3_SIZE, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- ret = hid_hw_raw_request(sc->hdev, 0xA3, buf,
- DS4_FEATURE_REPORT_0xA3_SIZE,
- HID_FEATURE_REPORT,
- HID_REQ_GET_REPORT);
- if (ret < 0) {
- kfree(buf);
- return ret;
- }
-
- sc->hw_version = get_unaligned_le16(&buf[35]);
- sc->fw_version = get_unaligned_le16(&buf[41]);
-
- kfree(buf);
- return 0;
-}
-
static void sixaxis_set_leds_from_id(struct sony_sc *sc)
{
static const u8 sixaxis_leds[10][4] = {
@@ -1941,30 +1223,6 @@ static void sixaxis_set_leds_from_id(struct sony_sc *sc)
memcpy(sc->led_state, sixaxis_leds[id], sizeof(sixaxis_leds[id]));
}
-static void dualshock4_set_leds_from_id(struct sony_sc *sc)
-{
- /* The first 4 color/index entries match what the PS4 assigns */
- static const u8 color_code[7][3] = {
- /* Blue */ { 0x00, 0x00, 0x40 },
- /* Red */ { 0x40, 0x00, 0x00 },
- /* Green */ { 0x00, 0x40, 0x00 },
- /* Pink */ { 0x20, 0x00, 0x20 },
- /* Orange */ { 0x02, 0x01, 0x00 },
- /* Teal */ { 0x00, 0x01, 0x01 },
- /* White */ { 0x01, 0x01, 0x01 }
- };
-
- int id = sc->device_id;
-
- BUILD_BUG_ON(MAX_LEDS < ARRAY_SIZE(color_code[0]));
-
- if (id < 0)
- return;
-
- id %= 7;
- memcpy(sc->led_state, color_code[id], sizeof(color_code[id]));
-}
-
static void buzz_set_leds(struct sony_sc *sc)
{
struct hid_device *hdev = sc->hdev;
@@ -2110,13 +1368,13 @@ static int sony_leds_init(struct sony_sc *sc)
{
struct hid_device *hdev = sc->hdev;
int n, ret = 0;
- int use_ds4_names;
+ int use_color_names;
struct led_classdev *led;
size_t name_sz;
char *name;
size_t name_len;
const char *name_fmt;
- static const char * const ds4_name_str[] = { "red", "green", "blue",
+ static const char * const color_name_str[] = { "red", "green", "blue",
"global" };
u8 max_brightness[MAX_LEDS] = { [0 ... (MAX_LEDS - 1)] = 1 };
u8 use_hw_blink[MAX_LEDS] = { 0 };
@@ -2125,25 +1383,16 @@ static int sony_leds_init(struct sony_sc *sc)
if (sc->quirks & BUZZ_CONTROLLER) {
sc->led_count = 4;
- use_ds4_names = 0;
+ use_color_names = 0;
name_len = strlen("::buzz#");
name_fmt = "%s::buzz%d";
/* Validate expected report characteristics. */
if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 0, 0, 7))
return -ENODEV;
- } else if (sc->quirks & DUALSHOCK4_CONTROLLER) {
- dualshock4_set_leds_from_id(sc);
- sc->led_state[3] = 1;
- sc->led_count = 4;
- memset(max_brightness, 255, 3);
- use_hw_blink[3] = 1;
- use_ds4_names = 1;
- name_len = 0;
- name_fmt = "%s:%s";
} else if (sc->quirks & MOTION_CONTROLLER) {
sc->led_count = 3;
memset(max_brightness, 255, 3);
- use_ds4_names = 1;
+ use_color_names = 1;
name_len = 0;
name_fmt = "%s:%s";
} else if (sc->quirks & NAVIGATION_CONTROLLER) {
@@ -2152,14 +1401,14 @@ static int sony_leds_init(struct sony_sc *sc)
memcpy(sc->led_state, navigation_leds, sizeof(navigation_leds));
sc->led_count = 1;
memset(use_hw_blink, 1, 4);
- use_ds4_names = 0;
+ use_color_names = 0;
name_len = strlen("::sony#");
name_fmt = "%s::sony%d";
} else {
sixaxis_set_leds_from_id(sc);
sc->led_count = 4;
memset(use_hw_blink, 1, 4);
- use_ds4_names = 0;
+ use_color_names = 0;
name_len = strlen("::sony#");
name_fmt = "%s::sony%d";
}
@@ -2175,8 +1424,8 @@ static int sony_leds_init(struct sony_sc *sc)
for (n = 0; n < sc->led_count; n++) {
- if (use_ds4_names)
- name_sz = strlen(dev_name(&hdev->dev)) + strlen(ds4_name_str[n]) + 2;
+ if (use_color_names)
+ name_sz = strlen(dev_name(&hdev->dev)) + strlen(color_name_str[n]) + 2;
led = devm_kzalloc(&hdev->dev, sizeof(struct led_classdev) + name_sz, GFP_KERNEL);
if (!led) {
@@ -2185,9 +1434,9 @@ static int sony_leds_init(struct sony_sc *sc)
}
name = (void *)(&led[1]);
- if (use_ds4_names)
+ if (use_color_names)
snprintf(name, name_sz, name_fmt, dev_name(&hdev->dev),
- ds4_name_str[n]);
+ color_name_str[n]);
else
snprintf(name, name_sz, name_fmt, dev_name(&hdev->dev), n + 1);
led->name = name;
@@ -2273,68 +1522,6 @@ static void sixaxis_send_output_report(struct sony_sc *sc)
HID_OUTPUT_REPORT, HID_REQ_SET_REPORT);
}
-static void dualshock4_send_output_report(struct sony_sc *sc)
-{
- struct hid_device *hdev = sc->hdev;
- u8 *buf = sc->output_report_dmabuf;
- int offset;
-
- /*
- * NOTE: The lower 6 bits of buf[1] field of the Bluetooth report
- * control the interval at which Dualshock 4 reports data:
- * 0x00 - 1ms
- * 0x01 - 1ms
- * 0x02 - 2ms
- * 0x3E - 62ms
- * 0x3F - disabled
- */
- if (sc->quirks & (DUALSHOCK4_CONTROLLER_USB | DUALSHOCK4_DONGLE)) {
- memset(buf, 0, DS4_OUTPUT_REPORT_0x05_SIZE);
- buf[0] = 0x05;
- buf[1] = 0x07; /* blink + LEDs + motor */
- offset = 4;
- } else {
- memset(buf, 0, DS4_OUTPUT_REPORT_0x11_SIZE);
- buf[0] = 0x11;
- buf[1] = 0xC0 /* HID + CRC */ | sc->ds4_bt_poll_interval;
- buf[3] = 0x07; /* blink + LEDs + motor */
- offset = 6;
- }
-
-#ifdef CONFIG_SONY_FF
- buf[offset++] = sc->right;
- buf[offset++] = sc->left;
-#else
- offset += 2;
-#endif
-
- /* LED 3 is the global control */
- if (sc->led_state[3]) {
- buf[offset++] = sc->led_state[0];
- buf[offset++] = sc->led_state[1];
- buf[offset++] = sc->led_state[2];
- } else {
- offset += 3;
- }
-
- /* If both delay values are zero the DualShock 4 disables blinking. */
- buf[offset++] = sc->led_delay_on[3];
- buf[offset++] = sc->led_delay_off[3];
-
- if (sc->quirks & (DUALSHOCK4_CONTROLLER_USB | DUALSHOCK4_DONGLE))
- hid_hw_output_report(hdev, buf, DS4_OUTPUT_REPORT_0x05_SIZE);
- else {
- /* CRC generation */
- u8 bthdr = 0xA2;
- u32 crc;
-
- crc = crc32_le(0xFFFFFFFF, &bthdr, 1);
- crc = ~crc32_le(crc, buf, DS4_OUTPUT_REPORT_0x11_SIZE-4);
- put_unaligned_le32(crc, &buf[74]);
- hid_hw_output_report(hdev, buf, DS4_OUTPUT_REPORT_0x11_SIZE);
- }
-}
-
static void motion_send_output_report(struct sony_sc *sc)
{
struct hid_device *hdev = sc->hdev;
@@ -2378,14 +1565,6 @@ static int sony_allocate_output_report(struct sony_sc *sc)
devm_kmalloc(&sc->hdev->dev,
sizeof(union sixaxis_output_report_01),
GFP_KERNEL);
- else if (sc->quirks & DUALSHOCK4_CONTROLLER_BT)
- sc->output_report_dmabuf = devm_kmalloc(&sc->hdev->dev,
- DS4_OUTPUT_REPORT_0x11_SIZE,
- GFP_KERNEL);
- else if (sc->quirks & (DUALSHOCK4_CONTROLLER_USB | DUALSHOCK4_DONGLE))
- sc->output_report_dmabuf = devm_kmalloc(&sc->hdev->dev,
- DS4_OUTPUT_REPORT_0x05_SIZE,
- GFP_KERNEL);
else if (sc->quirks & MOTION_CONTROLLER)
sc->output_report_dmabuf = devm_kmalloc(&sc->hdev->dev,
MOTION_REPORT_0x02_SIZE,
@@ -2600,8 +1779,7 @@ static int sony_check_add(struct sony_sc *sc)
u8 *buf = NULL;
int n, ret;
- if ((sc->quirks & DUALSHOCK4_CONTROLLER_BT) ||
- (sc->quirks & MOTION_CONTROLLER_BT) ||
+ if ((sc->quirks & MOTION_CONTROLLER_BT) ||
(sc->quirks & NAVIGATION_CONTROLLER_BT) ||
(sc->quirks & SIXAXIS_CONTROLLER_BT)) {
/*
@@ -2614,30 +1792,6 @@ static int sony_check_add(struct sony_sc *sc)
hid_warn(sc->hdev, "UNIQ does not contain a MAC address; duplicate check skipped\n");
return 0;
}
- } else if (sc->quirks & (DUALSHOCK4_CONTROLLER_USB | DUALSHOCK4_DONGLE)) {
- buf = kmalloc(DS4_FEATURE_REPORT_0x81_SIZE, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- /*
- * The MAC address of a DS4 controller connected via USB can be
- * retrieved with feature report 0x81. The address begins at
- * offset 1.
- */
- ret = hid_hw_raw_request(sc->hdev, 0x81, buf,
- DS4_FEATURE_REPORT_0x81_SIZE, HID_FEATURE_REPORT,
- HID_REQ_GET_REPORT);
-
- if (ret != DS4_FEATURE_REPORT_0x81_SIZE) {
- hid_err(sc->hdev, "failed to retrieve feature report 0x81 with the DualShock 4 MAC address\n");
- ret = ret < 0 ? ret : -EINVAL;
- goto out_free;
- }
-
- memcpy(sc->mac_address, &buf[1], sizeof(sc->mac_address));
-
- snprintf(sc->hdev->uniq, sizeof(sc->hdev->uniq),
- "%pMR", sc->mac_address);
} else if ((sc->quirks & SIXAXIS_CONTROLLER_USB) ||
(sc->quirks & NAVIGATION_CONTROLLER_USB)) {
buf = kmalloc(SIXAXIS_REPORT_0xF2_SIZE, GFP_KERNEL);
@@ -2686,11 +1840,10 @@ static int sony_set_device_id(struct sony_sc *sc)
int ret;
/*
- * Only DualShock 4 or Sixaxis controllers get an id.
+ * Only Sixaxis controllers get an id.
* All others are set to -1.
*/
- if ((sc->quirks & SIXAXIS_CONTROLLER) ||
- (sc->quirks & DUALSHOCK4_CONTROLLER)) {
+ if (sc->quirks & SIXAXIS_CONTROLLER) {
ret = ida_simple_get(&sony_device_id_allocator, 0, 0,
GFP_KERNEL);
if (ret < 0) {
@@ -2728,8 +1881,6 @@ static inline void sony_cancel_work_sync(struct sony_sc *sc)
{
unsigned long flags;
- if (sc->hotplug_worker_initialized)
- cancel_work_sync(&sc->hotplug_worker);
if (sc->state_worker_initialized) {
spin_lock_irqsave(&sc->lock, flags);
sc->state_worker_initialized = 0;
@@ -2849,68 +2000,6 @@ static int sony_input_configured(struct hid_device *hdev,
}
sony_init_output_report(sc, sixaxis_send_output_report);
- } else if (sc->quirks & DUALSHOCK4_CONTROLLER) {
- ret = dualshock4_get_calibration_data(sc);
- if (ret < 0) {
- hid_err(hdev, "Failed to get calibration data from Dualshock 4\n");
- goto err_stop;
- }
-
- ret = dualshock4_get_version_info(sc);
- if (ret < 0) {
- hid_err(sc->hdev, "Failed to get version data from Dualshock 4\n");
- goto err_stop;
- }
-
- ret = device_create_file(&sc->hdev->dev, &dev_attr_firmware_version);
- if (ret) {
- hid_err(sc->hdev, "can't create sysfs firmware_version attribute err: %d\n", ret);
- goto err_stop;
- }
- sc->fw_version_created = true;
-
- ret = device_create_file(&sc->hdev->dev, &dev_attr_hardware_version);
- if (ret) {
- hid_err(sc->hdev, "can't create sysfs hardware_version attribute err: %d\n", ret);
- goto err_stop;
- }
- sc->hw_version_created = true;
-
- /*
- * The Dualshock 4 touchpad supports 2 touches and has a
- * resolution of 1920x942 (44.86 dots/mm).
- */
- ret = sony_register_touchpad(sc, 2, 1920, 942, 0, 0, 0);
- if (ret) {
- hid_err(sc->hdev,
- "Unable to initialize multi-touch slots: %d\n",
- ret);
- goto err_stop;
- }
-
- ret = sony_register_sensors(sc);
- if (ret) {
- hid_err(sc->hdev,
- "Unable to initialize motion sensors: %d\n", ret);
- goto err_stop;
- }
-
- if (sc->quirks & DUALSHOCK4_CONTROLLER_BT) {
- sc->ds4_bt_poll_interval = DS4_BT_DEFAULT_POLL_INTERVAL_MS;
- ret = device_create_file(&sc->hdev->dev, &dev_attr_bt_poll_interval);
- if (ret)
- hid_warn(sc->hdev,
- "can't create sysfs bt_poll_interval attribute err: %d\n",
- ret);
- }
-
- if (sc->quirks & DUALSHOCK4_DONGLE) {
- INIT_WORK(&sc->hotplug_worker, dualshock4_calibration_work);
- sc->hotplug_worker_initialized = 1;
- sc->ds4_dongle_state = DONGLE_DISCONNECTED;
- }
-
- sony_init_output_report(sc, dualshock4_send_output_report);
} else if (sc->quirks & NSG_MRXU_REMOTE) {
/*
* The NSG-MRxU touchpad supports 2 touches and has a
@@ -2960,16 +2049,6 @@ static int sony_input_configured(struct hid_device *hdev,
err_close:
hid_hw_close(hdev);
err_stop:
- /* Piggy back on the default ds4_bt_ poll_interval to determine
- * if we need to remove the file as we don't know for sure if we
- * executed that logic.
- */
- if (sc->ds4_bt_poll_interval)
- device_remove_file(&sc->hdev->dev, &dev_attr_bt_poll_interval);
- if (sc->fw_version_created)
- device_remove_file(&sc->hdev->dev, &dev_attr_firmware_version);
- if (sc->hw_version_created)
- device_remove_file(&sc->hdev->dev, &dev_attr_hardware_version);
sony_cancel_work_sync(sc);
sony_remove_dev_list(sc);
sony_release_device_id(sc);
@@ -3014,13 +2093,13 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
else if (sc->quirks & SIXAXIS_CONTROLLER)
connect_mask |= HID_CONNECT_HIDDEV_FORCE;
- /* Patch the hw version on DS3/4 compatible devices, so applications can
+ /* Patch the hw version on DS3 compatible devices, so applications can
* distinguish between the default HID mappings and the mappings defined
* by the Linux game controller spec. This is important for the SDL2
* library, which has a game controller database, which uses device ids
* in combination with version as a key.
*/
- if (sc->quirks & (SIXAXIS_CONTROLLER | DUALSHOCK4_CONTROLLER))
+ if (sc->quirks & SIXAXIS_CONTROLLER)
hdev->version |= 0x8000;
ret = hid_hw_start(hdev, connect_mask);
@@ -3091,15 +2170,6 @@ static void sony_remove(struct hid_device *hdev)
hid_hw_close(hdev);
- if (sc->quirks & DUALSHOCK4_CONTROLLER_BT)
- device_remove_file(&sc->hdev->dev, &dev_attr_bt_poll_interval);
-
- if (sc->fw_version_created)
- device_remove_file(&sc->hdev->dev, &dev_attr_firmware_version);
-
- if (sc->hw_version_created)
- device_remove_file(&sc->hdev->dev, &dev_attr_hardware_version);
-
sony_cancel_work_sync(sc);
sony_remove_dev_list(sc);
@@ -3180,17 +2250,6 @@ static const struct hid_device_id sony_devices[] = {
/* SMK-Link PS3 BD Remote Control */
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SMK, USB_DEVICE_ID_SMK_PS3_BDREMOTE),
.driver_data = PS3REMOTE },
- /* Sony Dualshock 4 controllers for PS4 */
- { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER),
- .driver_data = DUALSHOCK4_CONTROLLER_USB },
- { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER),
- .driver_data = DUALSHOCK4_CONTROLLER_BT },
- { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_2),
- .driver_data = DUALSHOCK4_CONTROLLER_USB },
- { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_2),
- .driver_data = DUALSHOCK4_CONTROLLER_BT },
- { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_DONGLE),
- .driver_data = DUALSHOCK4_DONGLE },
/* Nyko Core Controller for PS3 */
{ HID_USB_DEVICE(USB_VENDOR_ID_SINO_LITE, USB_DEVICE_ID_SINO_LITE_CONTROLLER),
.driver_data = SIXAXIS_CONTROLLER_USB | SINO_LITE_CONTROLLER },
diff --git a/drivers/hid/hid-steam.c b/drivers/hid/hid-steam.c
index 8ee43cb225fc..b110818fc945 100644
--- a/drivers/hid/hid-steam.c
+++ b/drivers/hid/hid-steam.c
@@ -3,6 +3,7 @@
* HID driver for Valve Steam Controller
*
* Copyright (c) 2018 Rodrigo Rivas Costa <rodrigorivascosta@gmail.com>
+ * Copyright (c) 2022 Valve Software
*
* Supports both the wired and wireless interfaces.
*
@@ -53,6 +54,7 @@ static DEFINE_MUTEX(steam_devices_lock);
static LIST_HEAD(steam_devices);
#define STEAM_QUIRK_WIRELESS BIT(0)
+#define STEAM_QUIRK_DECK BIT(1)
/* Touch pads are 40 mm in diameter and 65535 units */
#define STEAM_PAD_RESOLUTION 1638
@@ -60,6 +62,10 @@ static LIST_HEAD(steam_devices);
#define STEAM_TRIGGER_RESOLUTION 51
/* Joystick runs are about 5 mm and 256 units */
#define STEAM_JOYSTICK_RESOLUTION 51
+/* Trigger runs are about 6 mm and 32768 units */
+#define STEAM_DECK_TRIGGER_RESOLUTION 5461
+/* Joystick runs are about 5 mm and 32768 units */
+#define STEAM_DECK_JOYSTICK_RESOLUTION 6553
#define STEAM_PAD_FUZZ 256
@@ -85,6 +91,7 @@ static LIST_HEAD(steam_devices);
#define STEAM_CMD_FORCEFEEDBAK 0x8f
#define STEAM_CMD_REQUEST_COMM_STATUS 0xb4
#define STEAM_CMD_GET_SERIAL 0xae
+#define STEAM_CMD_HAPTIC_RUMBLE 0xeb
/* Some useful register ids */
#define STEAM_REG_LPAD_MODE 0x07
@@ -92,11 +99,14 @@ static LIST_HEAD(steam_devices);
#define STEAM_REG_RPAD_MARGIN 0x18
#define STEAM_REG_LED 0x2d
#define STEAM_REG_GYRO_MODE 0x30
+#define STEAM_REG_LPAD_CLICK_PRESSURE 0x34
+#define STEAM_REG_RPAD_CLICK_PRESSURE 0x35
/* Raw event identifiers */
#define STEAM_EV_INPUT_DATA 0x01
#define STEAM_EV_CONNECT 0x03
#define STEAM_EV_BATTERY 0x04
+#define STEAM_EV_DECK_INPUT_DATA 0x09
/* Values for GYRO_MODE (bitmask) */
#define STEAM_GYRO_MODE_OFF 0x0000
@@ -124,6 +134,10 @@ struct steam_device {
struct power_supply __rcu *battery;
u8 battery_charge;
u16 voltage;
+ struct delayed_work heartbeat;
+ struct work_struct rumble_work;
+ u16 rumble_left;
+ u16 rumble_right;
};
static int steam_recv_report(struct steam_device *steam,
@@ -193,7 +207,7 @@ static int steam_send_report(struct steam_device *steam,
*/
do {
ret = hid_hw_raw_request(steam->hdev, 0,
- buf, size + 1,
+ buf, max(size, 64) + 1,
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
if (ret != -EPIPE)
break;
@@ -219,6 +233,7 @@ static int steam_write_registers(struct steam_device *steam,
u8 reg;
u16 val;
u8 cmd[64] = {STEAM_CMD_WRITE_REGISTER, 0x00};
+ int ret;
va_list args;
va_start(args, steam);
@@ -234,7 +249,16 @@ static int steam_write_registers(struct steam_device *steam,
}
va_end(args);
- return steam_send_report(steam, cmd, 2 + cmd[1]);
+ ret = steam_send_report(steam, cmd, 2 + cmd[1]);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Sometimes a lingering report for this command can
+ * get read back instead of the last set report if
+ * this isn't explicitly queried
+ */
+ return steam_recv_report(steam, cmd, 2 + cmd[1]);
}
static int steam_get_serial(struct steam_device *steam)
@@ -270,6 +294,45 @@ static inline int steam_request_conn_status(struct steam_device *steam)
return steam_send_report_byte(steam, STEAM_CMD_REQUEST_COMM_STATUS);
}
+static inline int steam_haptic_rumble(struct steam_device *steam,
+ u16 intensity, u16 left_speed, u16 right_speed,
+ u8 left_gain, u8 right_gain)
+{
+ u8 report[11] = {STEAM_CMD_HAPTIC_RUMBLE, 9};
+
+ report[3] = intensity & 0xFF;
+ report[4] = intensity >> 8;
+ report[5] = left_speed & 0xFF;
+ report[6] = left_speed >> 8;
+ report[7] = right_speed & 0xFF;
+ report[8] = right_speed >> 8;
+ report[9] = left_gain;
+ report[10] = right_gain;
+
+ return steam_send_report(steam, report, sizeof(report));
+}
+
+static void steam_haptic_rumble_cb(struct work_struct *work)
+{
+ struct steam_device *steam = container_of(work, struct steam_device,
+ rumble_work);
+ steam_haptic_rumble(steam, 0, steam->rumble_left,
+ steam->rumble_right, 2, 0);
+}
+
+#ifdef CONFIG_STEAM_FF
+static int steam_play_effect(struct input_dev *dev, void *data,
+ struct ff_effect *effect)
+{
+ struct steam_device *steam = input_get_drvdata(dev);
+
+ steam->rumble_left = effect->u.rumble.strong_magnitude;
+ steam->rumble_right = effect->u.rumble.weak_magnitude;
+
+ return schedule_work(&steam->rumble_work);
+}
+#endif
+
static void steam_set_lizard_mode(struct steam_device *steam, bool enable)
{
if (enable) {
@@ -280,13 +343,33 @@ static void steam_set_lizard_mode(struct steam_device *steam, bool enable)
steam_write_registers(steam,
STEAM_REG_RPAD_MARGIN, 0x01, /* enable margin */
0);
+
+ cancel_delayed_work_sync(&steam->heartbeat);
} else {
/* disable esc, enter, cursor */
steam_send_report_byte(steam, STEAM_CMD_CLEAR_MAPPINGS);
- steam_write_registers(steam,
- STEAM_REG_RPAD_MODE, 0x07, /* disable mouse */
- STEAM_REG_RPAD_MARGIN, 0x00, /* disable margin */
- 0);
+
+ if (steam->quirks & STEAM_QUIRK_DECK) {
+ steam_write_registers(steam,
+ STEAM_REG_RPAD_MARGIN, 0x00, /* disable margin */
+ STEAM_REG_LPAD_MODE, 0x07, /* disable mouse */
+ STEAM_REG_RPAD_MODE, 0x07, /* disable mouse */
+ STEAM_REG_LPAD_CLICK_PRESSURE, 0xFFFF, /* disable clicky pad */
+ STEAM_REG_RPAD_CLICK_PRESSURE, 0xFFFF, /* disable clicky pad */
+ 0);
+ /*
+ * The Steam Deck has a watchdog that automatically enables
+ * lizard mode if it doesn't see any traffic for too long
+ */
+ if (!work_busy(&steam->heartbeat.work))
+ schedule_delayed_work(&steam->heartbeat, 5 * HZ);
+ } else {
+ steam_write_registers(steam,
+ STEAM_REG_RPAD_MARGIN, 0x00, /* disable margin */
+ STEAM_REG_LPAD_MODE, 0x07, /* disable mouse */
+ STEAM_REG_RPAD_MODE, 0x07, /* disable mouse */
+ 0);
+ }
}
}
@@ -413,8 +496,8 @@ static int steam_input_register(struct steam_device *steam)
input->open = steam_input_open;
input->close = steam_input_close;
- input->name = (steam->quirks & STEAM_QUIRK_WIRELESS) ?
- "Wireless Steam Controller" :
+ input->name = (steam->quirks & STEAM_QUIRK_WIRELESS) ? "Wireless Steam Controller" :
+ (steam->quirks & STEAM_QUIRK_DECK) ? "Steam Deck" :
"Steam Controller";
input->phys = hdev->phys;
input->uniq = steam->serial_no;
@@ -438,33 +521,76 @@ static int steam_input_register(struct steam_device *steam)
input_set_capability(input, EV_KEY, BTN_SELECT);
input_set_capability(input, EV_KEY, BTN_MODE);
input_set_capability(input, EV_KEY, BTN_START);
- input_set_capability(input, EV_KEY, BTN_GEAR_DOWN);
- input_set_capability(input, EV_KEY, BTN_GEAR_UP);
input_set_capability(input, EV_KEY, BTN_THUMBR);
input_set_capability(input, EV_KEY, BTN_THUMBL);
input_set_capability(input, EV_KEY, BTN_THUMB);
input_set_capability(input, EV_KEY, BTN_THUMB2);
+ if (steam->quirks & STEAM_QUIRK_DECK) {
+ input_set_capability(input, EV_KEY, BTN_BASE);
+ input_set_capability(input, EV_KEY, BTN_TRIGGER_HAPPY1);
+ input_set_capability(input, EV_KEY, BTN_TRIGGER_HAPPY2);
+ input_set_capability(input, EV_KEY, BTN_TRIGGER_HAPPY3);
+ input_set_capability(input, EV_KEY, BTN_TRIGGER_HAPPY4);
+ } else {
+ input_set_capability(input, EV_KEY, BTN_GEAR_DOWN);
+ input_set_capability(input, EV_KEY, BTN_GEAR_UP);
+ }
- input_set_abs_params(input, ABS_HAT2Y, 0, 255, 0, 0);
- input_set_abs_params(input, ABS_HAT2X, 0, 255, 0, 0);
input_set_abs_params(input, ABS_X, -32767, 32767, 0, 0);
input_set_abs_params(input, ABS_Y, -32767, 32767, 0, 0);
- input_set_abs_params(input, ABS_RX, -32767, 32767,
- STEAM_PAD_FUZZ, 0);
- input_set_abs_params(input, ABS_RY, -32767, 32767,
- STEAM_PAD_FUZZ, 0);
+
input_set_abs_params(input, ABS_HAT0X, -32767, 32767,
STEAM_PAD_FUZZ, 0);
input_set_abs_params(input, ABS_HAT0Y, -32767, 32767,
STEAM_PAD_FUZZ, 0);
- input_abs_set_res(input, ABS_X, STEAM_JOYSTICK_RESOLUTION);
- input_abs_set_res(input, ABS_Y, STEAM_JOYSTICK_RESOLUTION);
- input_abs_set_res(input, ABS_RX, STEAM_PAD_RESOLUTION);
- input_abs_set_res(input, ABS_RY, STEAM_PAD_RESOLUTION);
+
+ if (steam->quirks & STEAM_QUIRK_DECK) {
+ input_set_abs_params(input, ABS_HAT2Y, 0, 32767, 0, 0);
+ input_set_abs_params(input, ABS_HAT2X, 0, 32767, 0, 0);
+
+ input_set_abs_params(input, ABS_RX, -32767, 32767, 0, 0);
+ input_set_abs_params(input, ABS_RY, -32767, 32767, 0, 0);
+
+ input_set_abs_params(input, ABS_HAT1X, -32767, 32767,
+ STEAM_PAD_FUZZ, 0);
+ input_set_abs_params(input, ABS_HAT1Y, -32767, 32767,
+ STEAM_PAD_FUZZ, 0);
+
+ input_abs_set_res(input, ABS_X, STEAM_DECK_JOYSTICK_RESOLUTION);
+ input_abs_set_res(input, ABS_Y, STEAM_DECK_JOYSTICK_RESOLUTION);
+ input_abs_set_res(input, ABS_RX, STEAM_DECK_JOYSTICK_RESOLUTION);
+ input_abs_set_res(input, ABS_RY, STEAM_DECK_JOYSTICK_RESOLUTION);
+ input_abs_set_res(input, ABS_HAT1X, STEAM_PAD_RESOLUTION);
+ input_abs_set_res(input, ABS_HAT1Y, STEAM_PAD_RESOLUTION);
+ input_abs_set_res(input, ABS_HAT2Y, STEAM_DECK_TRIGGER_RESOLUTION);
+ input_abs_set_res(input, ABS_HAT2X, STEAM_DECK_TRIGGER_RESOLUTION);
+ } else {
+ input_set_abs_params(input, ABS_HAT2Y, 0, 255, 0, 0);
+ input_set_abs_params(input, ABS_HAT2X, 0, 255, 0, 0);
+
+ input_set_abs_params(input, ABS_RX, -32767, 32767,
+ STEAM_PAD_FUZZ, 0);
+ input_set_abs_params(input, ABS_RY, -32767, 32767,
+ STEAM_PAD_FUZZ, 0);
+
+ input_abs_set_res(input, ABS_X, STEAM_JOYSTICK_RESOLUTION);
+ input_abs_set_res(input, ABS_Y, STEAM_JOYSTICK_RESOLUTION);
+ input_abs_set_res(input, ABS_RX, STEAM_PAD_RESOLUTION);
+ input_abs_set_res(input, ABS_RY, STEAM_PAD_RESOLUTION);
+ input_abs_set_res(input, ABS_HAT2Y, STEAM_TRIGGER_RESOLUTION);
+ input_abs_set_res(input, ABS_HAT2X, STEAM_TRIGGER_RESOLUTION);
+ }
input_abs_set_res(input, ABS_HAT0X, STEAM_PAD_RESOLUTION);
input_abs_set_res(input, ABS_HAT0Y, STEAM_PAD_RESOLUTION);
- input_abs_set_res(input, ABS_HAT2Y, STEAM_TRIGGER_RESOLUTION);
- input_abs_set_res(input, ABS_HAT2X, STEAM_TRIGGER_RESOLUTION);
+
+#ifdef CONFIG_STEAM_FF
+ if (steam->quirks & STEAM_QUIRK_DECK) {
+ input_set_capability(input, EV_FF, FF_RUMBLE);
+ ret = input_ff_create_memless(input, NULL, steam_play_effect);
+ if (ret)
+ goto input_register_fail;
+ }
+#endif
ret = input_register_device(input);
if (ret)
@@ -612,6 +738,22 @@ static bool steam_is_valve_interface(struct hid_device *hdev)
return !list_empty(&rep_enum->report_list);
}
+static void steam_lizard_mode_heartbeat(struct work_struct *work)
+{
+ struct steam_device *steam = container_of(work, struct steam_device,
+ heartbeat.work);
+
+ mutex_lock(&steam->mutex);
+ if (!steam->client_opened && steam->client_hdev) {
+ steam_send_report_byte(steam, STEAM_CMD_CLEAR_MAPPINGS);
+ steam_write_registers(steam,
+ STEAM_REG_RPAD_MODE, 0x07, /* disable mouse */
+ 0);
+ schedule_delayed_work(&steam->heartbeat, 5 * HZ);
+ }
+ mutex_unlock(&steam->mutex);
+}
+
static int steam_client_ll_parse(struct hid_device *hdev)
{
struct steam_device *steam = hdev->driver_data;
@@ -674,7 +816,7 @@ static int steam_client_ll_raw_request(struct hid_device *hdev,
report_type, reqtype);
}
-static struct hid_ll_driver steam_client_ll_driver = {
+static const struct hid_ll_driver steam_client_ll_driver = {
.parse = steam_client_ll_parse,
.start = steam_client_ll_start,
.stop = steam_client_ll_stop,
@@ -750,6 +892,8 @@ static int steam_probe(struct hid_device *hdev,
steam->quirks = id->driver_data;
INIT_WORK(&steam->work_connect, steam_work_connect_cb);
INIT_LIST_HEAD(&steam->list);
+ INIT_DEFERRABLE_WORK(&steam->heartbeat, steam_lizard_mode_heartbeat);
+ INIT_WORK(&steam->rumble_work, steam_haptic_rumble_cb);
steam->client_hdev = steam_create_client_hid(hdev);
if (IS_ERR(steam->client_hdev)) {
@@ -805,6 +949,8 @@ hid_hw_start_fail:
hid_destroy_device(steam->client_hdev);
client_hdev_fail:
cancel_work_sync(&steam->work_connect);
+ cancel_delayed_work_sync(&steam->heartbeat);
+ cancel_work_sync(&steam->rumble_work);
steam_alloc_fail:
hid_err(hdev, "%s: failed with error %d\n",
__func__, ret);
@@ -821,7 +967,11 @@ static void steam_remove(struct hid_device *hdev)
}
hid_destroy_device(steam->client_hdev);
+ mutex_lock(&steam->mutex);
+ steam->client_hdev = NULL;
steam->client_opened = false;
+ cancel_delayed_work_sync(&steam->heartbeat);
+ mutex_unlock(&steam->mutex);
cancel_work_sync(&steam->work_connect);
if (steam->quirks & STEAM_QUIRK_WIRELESS) {
hid_info(hdev, "Steam wireless receiver disconnected");
@@ -906,10 +1056,10 @@ static inline s16 steam_le16(u8 *data)
* 8.5 | BTN_B | button B
* 8.6 | BTN_X | button X
* 8.7 | BTN_A | button A
- * 9.0 | BTN_DPAD_UP | lef-pad up
- * 9.1 | BTN_DPAD_RIGHT | lef-pad right
- * 9.2 | BTN_DPAD_LEFT | lef-pad left
- * 9.3 | BTN_DPAD_DOWN | lef-pad down
+ * 9.0 | BTN_DPAD_UP | left-pad up
+ * 9.1 | BTN_DPAD_RIGHT | left-pad right
+ * 9.2 | BTN_DPAD_LEFT | left-pad left
+ * 9.3 | BTN_DPAD_DOWN | left-pad down
* 9.4 | BTN_SELECT | menu left
* 9.5 | BTN_MODE | steam logo
* 9.6 | BTN_START | menu right
@@ -994,6 +1144,172 @@ static void steam_do_input_event(struct steam_device *steam,
}
/*
+ * The size for this message payload is 56.
+ * The known values are:
+ * Offset| Type | Mapped to |Meaning
+ * -------+-------+-----------+--------------------------
+ * 4-7 | u32 | -- | sequence number
+ * 8-15 | u64 | see below | buttons
+ * 16-17 | s16 | ABS_HAT0X | left-pad X value
+ * 18-19 | s16 | ABS_HAT0Y | left-pad Y value
+ * 20-21 | s16 | ABS_HAT1X | right-pad X value
+ * 22-23 | s16 | ABS_HAT1Y | right-pad Y value
+ * 24-25 | s16 | -- | accelerometer X value
+ * 26-27 | s16 | -- | accelerometer Y value
+ * 28-29 | s16 | -- | accelerometer Z value
+ * 30-31 | s16 | -- | gyro X value
+ * 32-33 | s16 | -- | gyro Y value
+ * 34-35 | s16 | -- | gyro Z value
+ * 36-37 | s16 | -- | quaternion W value
+ * 38-39 | s16 | -- | quaternion X value
+ * 40-41 | s16 | -- | quaternion Y value
+ * 42-43 | s16 | -- | quaternion Z value
+ * 44-45 | u16 | ABS_HAT2Y | left trigger (uncalibrated)
+ * 46-47 | u16 | ABS_HAT2X | right trigger (uncalibrated)
+ * 48-49 | s16 | ABS_X | left joystick X
+ * 50-51 | s16 | ABS_Y | left joystick Y
+ * 52-53 | s16 | ABS_RX | right joystick X
+ * 54-55 | s16 | ABS_RY | right joystick Y
+ * 56-57 | u16 | -- | left pad pressure
+ * 58-59 | u16 | -- | right pad pressure
+ *
+ * The buttons are:
+ * Bit | Mapped to | Description
+ * ------+------------+--------------------------------
+ * 8.0 | BTN_TR2 | right trigger fully pressed
+ * 8.1 | BTN_TL2 | left trigger fully pressed
+ * 8.2 | BTN_TR | right shoulder
+ * 8.3 | BTN_TL | left shoulder
+ * 8.4 | BTN_Y | button Y
+ * 8.5 | BTN_B | button B
+ * 8.6 | BTN_X | button X
+ * 8.7 | BTN_A | button A
+ * 9.0 | BTN_DPAD_UP | left-pad up
+ * 9.1 | BTN_DPAD_RIGHT | left-pad right
+ * 9.2 | BTN_DPAD_LEFT | left-pad left
+ * 9.3 | BTN_DPAD_DOWN | left-pad down
+ * 9.4 | BTN_SELECT | menu left
+ * 9.5 | BTN_MODE | steam logo
+ * 9.6 | BTN_START | menu right
+ * 9.7 | BTN_TRIGGER_HAPPY3 | left bottom grip button
+ * 10.0 | BTN_TRIGGER_HAPPY4 | right bottom grip button
+ * 10.1 | BTN_THUMB | left pad pressed
+ * 10.2 | BTN_THUMB2 | right pad pressed
+ * 10.3 | -- | left pad touched
+ * 10.4 | -- | right pad touched
+ * 10.5 | -- | unknown
+ * 10.6 | BTN_THUMBL | left joystick clicked
+ * 10.7 | -- | unknown
+ * 11.0 | -- | unknown
+ * 11.1 | -- | unknown
+ * 11.2 | BTN_THUMBR | right joystick clicked
+ * 11.3 | -- | unknown
+ * 11.4 | -- | unknown
+ * 11.5 | -- | unknown
+ * 11.6 | -- | unknown
+ * 11.7 | -- | unknown
+ * 12.0 | -- | unknown
+ * 12.1 | -- | unknown
+ * 12.2 | -- | unknown
+ * 12.3 | -- | unknown
+ * 12.4 | -- | unknown
+ * 12.5 | -- | unknown
+ * 12.6 | -- | unknown
+ * 12.7 | -- | unknown
+ * 13.0 | -- | unknown
+ * 13.1 | BTN_TRIGGER_HAPPY1 | left top grip button
+ * 13.2 | BTN_TRIGGER_HAPPY2 | right top grip button
+ * 13.3 | -- | unknown
+ * 13.4 | -- | unknown
+ * 13.5 | -- | unknown
+ * 13.6 | -- | left joystick touched
+ * 13.7 | -- | right joystick touched
+ * 14.0 | -- | unknown
+ * 14.1 | -- | unknown
+ * 14.2 | BTN_BASE | quick access button
+ * 14.3 | -- | unknown
+ * 14.4 | -- | unknown
+ * 14.5 | -- | unknown
+ * 14.6 | -- | unknown
+ * 14.7 | -- | unknown
+ * 15.0 | -- | unknown
+ * 15.1 | -- | unknown
+ * 15.2 | -- | unknown
+ * 15.3 | -- | unknown
+ * 15.4 | -- | unknown
+ * 15.5 | -- | unknown
+ * 15.6 | -- | unknown
+ * 15.7 | -- | unknown
+ */
+static void steam_do_deck_input_event(struct steam_device *steam,
+ struct input_dev *input, u8 *data)
+{
+ u8 b8, b9, b10, b11, b13, b14;
+ bool lpad_touched, rpad_touched;
+
+ b8 = data[8];
+ b9 = data[9];
+ b10 = data[10];
+ b11 = data[11];
+ b13 = data[13];
+ b14 = data[14];
+
+ lpad_touched = b10 & BIT(3);
+ rpad_touched = b10 & BIT(4);
+
+ if (lpad_touched) {
+ input_report_abs(input, ABS_HAT0X, steam_le16(data + 16));
+ input_report_abs(input, ABS_HAT0Y, steam_le16(data + 18));
+ } else {
+ input_report_abs(input, ABS_HAT0X, 0);
+ input_report_abs(input, ABS_HAT0Y, 0);
+ }
+
+ if (rpad_touched) {
+ input_report_abs(input, ABS_HAT1X, steam_le16(data + 20));
+ input_report_abs(input, ABS_HAT1Y, steam_le16(data + 22));
+ } else {
+ input_report_abs(input, ABS_HAT1X, 0);
+ input_report_abs(input, ABS_HAT1Y, 0);
+ }
+
+ input_report_abs(input, ABS_X, steam_le16(data + 48));
+ input_report_abs(input, ABS_Y, -steam_le16(data + 50));
+ input_report_abs(input, ABS_RX, steam_le16(data + 52));
+ input_report_abs(input, ABS_RY, -steam_le16(data + 54));
+
+ input_report_abs(input, ABS_HAT2Y, steam_le16(data + 44));
+ input_report_abs(input, ABS_HAT2X, steam_le16(data + 46));
+
+ input_event(input, EV_KEY, BTN_TR2, !!(b8 & BIT(0)));
+ input_event(input, EV_KEY, BTN_TL2, !!(b8 & BIT(1)));
+ input_event(input, EV_KEY, BTN_TR, !!(b8 & BIT(2)));
+ input_event(input, EV_KEY, BTN_TL, !!(b8 & BIT(3)));
+ input_event(input, EV_KEY, BTN_Y, !!(b8 & BIT(4)));
+ input_event(input, EV_KEY, BTN_B, !!(b8 & BIT(5)));
+ input_event(input, EV_KEY, BTN_X, !!(b8 & BIT(6)));
+ input_event(input, EV_KEY, BTN_A, !!(b8 & BIT(7)));
+ input_event(input, EV_KEY, BTN_SELECT, !!(b9 & BIT(4)));
+ input_event(input, EV_KEY, BTN_MODE, !!(b9 & BIT(5)));
+ input_event(input, EV_KEY, BTN_START, !!(b9 & BIT(6)));
+ input_event(input, EV_KEY, BTN_TRIGGER_HAPPY3, !!(b9 & BIT(7)));
+ input_event(input, EV_KEY, BTN_TRIGGER_HAPPY4, !!(b10 & BIT(0)));
+ input_event(input, EV_KEY, BTN_THUMBL, !!(b10 & BIT(6)));
+ input_event(input, EV_KEY, BTN_THUMBR, !!(b11 & BIT(2)));
+ input_event(input, EV_KEY, BTN_DPAD_UP, !!(b9 & BIT(0)));
+ input_event(input, EV_KEY, BTN_DPAD_RIGHT, !!(b9 & BIT(1)));
+ input_event(input, EV_KEY, BTN_DPAD_LEFT, !!(b9 & BIT(2)));
+ input_event(input, EV_KEY, BTN_DPAD_DOWN, !!(b9 & BIT(3)));
+ input_event(input, EV_KEY, BTN_THUMB, !!(b10 & BIT(1)));
+ input_event(input, EV_KEY, BTN_THUMB2, !!(b10 & BIT(2)));
+ input_event(input, EV_KEY, BTN_TRIGGER_HAPPY1, !!(b13 & BIT(1)));
+ input_event(input, EV_KEY, BTN_TRIGGER_HAPPY2, !!(b13 & BIT(2)));
+ input_event(input, EV_KEY, BTN_BASE, !!(b14 & BIT(2)));
+
+ input_sync(input);
+}
+
+/*
* The size for this message payload is 11.
* The known values are:
* Offset| Type | Meaning
@@ -1052,6 +1368,7 @@ static int steam_raw_event(struct hid_device *hdev,
* 0x01: input data (60 bytes)
* 0x03: wireless connect/disconnect (1 byte)
* 0x04: battery status (11 bytes)
+ * 0x09: Steam Deck input data (56 bytes)
*/
if (size != 64 || data[0] != 1 || data[1] != 0)
@@ -1067,6 +1384,15 @@ static int steam_raw_event(struct hid_device *hdev,
steam_do_input_event(steam, input, data);
rcu_read_unlock();
break;
+ case STEAM_EV_DECK_INPUT_DATA:
+ if (steam->client_opened)
+ return 0;
+ rcu_read_lock();
+ input = rcu_dereference(steam->input);
+ if (likely(input))
+ steam_do_deck_input_event(steam, input, data);
+ rcu_read_unlock();
+ break;
case STEAM_EV_CONNECT:
/*
* The payload of this event is a single byte:
@@ -1141,6 +1467,11 @@ static const struct hid_device_id steam_controllers[] = {
USB_DEVICE_ID_STEAM_CONTROLLER_WIRELESS),
.driver_data = STEAM_QUIRK_WIRELESS
},
+ { /* Steam Deck */
+ HID_USB_DEVICE(USB_VENDOR_ID_VALVE,
+ USB_DEVICE_ID_STEAM_DECK),
+ .driver_data = STEAM_QUIRK_DECK
+ },
{}
};
diff --git a/drivers/hid/hid-uclogic-core-test.c b/drivers/hid/hid-uclogic-core-test.c
new file mode 100644
index 000000000000..2bb916226a38
--- /dev/null
+++ b/drivers/hid/hid-uclogic-core-test.c
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/*
+ * HID driver for UC-Logic devices not fully compliant with HID standard
+ *
+ * Copyright (c) 2022 José Expósito <jose.exposito89@gmail.com>
+ */
+
+#include <kunit/test.h>
+#include "./hid-uclogic-params.h"
+
+#define MAX_EVENT_SIZE 12
+
+struct uclogic_raw_event_hook_test {
+ u8 event[MAX_EVENT_SIZE];
+ size_t size;
+ bool expected;
+};
+
+static struct uclogic_raw_event_hook_test hook_events[] = {
+ {
+ .event = { 0xA1, 0xB2, 0xC3, 0xD4 },
+ .size = 4,
+ },
+ {
+ .event = { 0x1F, 0x2E, 0x3D, 0x4C, 0x5B, 0x6A },
+ .size = 6,
+ },
+};
+
+static struct uclogic_raw_event_hook_test test_events[] = {
+ {
+ .event = { 0xA1, 0xB2, 0xC3, 0xD4 },
+ .size = 4,
+ .expected = true,
+ },
+ {
+ .event = { 0x1F, 0x2E, 0x3D, 0x4C, 0x5B, 0x6A },
+ .size = 6,
+ .expected = true,
+ },
+ {
+ .event = { 0xA1, 0xB2, 0xC3 },
+ .size = 3,
+ .expected = false,
+ },
+ {
+ .event = { 0xA1, 0xB2, 0xC3, 0xD4, 0x00 },
+ .size = 5,
+ .expected = false,
+ },
+ {
+ .event = { 0x2E, 0x3D, 0x4C, 0x5B, 0x6A, 0x1F },
+ .size = 6,
+ .expected = false,
+ },
+};
+
+static void hid_test_uclogic_exec_event_hook_test(struct kunit *test)
+{
+ struct uclogic_params p = {0, };
+ struct uclogic_raw_event_hook *filter;
+ bool res;
+ int n;
+
+ /* Initialize the list of events to hook */
+ p.event_hooks = kunit_kzalloc(test, sizeof(*p.event_hooks), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, p.event_hooks);
+ INIT_LIST_HEAD(&p.event_hooks->list);
+
+ for (n = 0; n < ARRAY_SIZE(hook_events); n++) {
+ filter = kunit_kzalloc(test, sizeof(*filter), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filter);
+
+ filter->size = hook_events[n].size;
+ filter->event = kunit_kzalloc(test, filter->size, GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filter->event);
+ memcpy(filter->event, &hook_events[n].event[0], filter->size);
+
+ list_add_tail(&filter->list, &p.event_hooks->list);
+ }
+
+ /* Test uclogic_exec_event_hook() */
+ for (n = 0; n < ARRAY_SIZE(test_events); n++) {
+ res = uclogic_exec_event_hook(&p, &test_events[n].event[0],
+ test_events[n].size);
+ KUNIT_ASSERT_EQ(test, res, test_events[n].expected);
+ }
+}
+
+static struct kunit_case hid_uclogic_core_test_cases[] = {
+ KUNIT_CASE(hid_test_uclogic_exec_event_hook_test),
+ {}
+};
+
+static struct kunit_suite hid_uclogic_core_test_suite = {
+ .name = "hid_uclogic_core_test",
+ .test_cases = hid_uclogic_core_test_cases,
+};
+
+kunit_test_suite(hid_uclogic_core_test_suite);
+
+MODULE_DESCRIPTION("KUnit tests for the UC-Logic driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("José Expósito <jose.exposito89@gmail.com>");
diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c
index cfbbc39807a6..f67835f9ed4c 100644
--- a/drivers/hid/hid-uclogic-core.c
+++ b/drivers/hid/hid-uclogic-core.c
@@ -22,25 +22,6 @@
#include "hid-ids.h"
-/* Driver data */
-struct uclogic_drvdata {
- /* Interface parameters */
- struct uclogic_params params;
- /* Pointer to the replacement report descriptor. NULL if none. */
- __u8 *desc_ptr;
- /*
- * Size of the replacement report descriptor.
- * Only valid if desc_ptr is not NULL
- */
- unsigned int desc_size;
- /* Pen input device */
- struct input_dev *pen_input;
- /* In-range timer */
- struct timer_list inrange_timer;
- /* Last rotary encoder state, or U8_MAX for none */
- u8 re_state;
-};
-
/**
* uclogic_inrange_timeout - handle pen in-range state timeout.
* Emulate input events normally generated when pen goes out of range for
@@ -202,6 +183,7 @@ static int uclogic_probe(struct hid_device *hdev,
}
timer_setup(&drvdata->inrange_timer, uclogic_inrange_timeout, 0);
drvdata->re_state = U8_MAX;
+ drvdata->quirks = id->driver_data;
hid_set_drvdata(hdev, drvdata);
/* Initialize the device and retrieve interface parameters */
@@ -268,6 +250,34 @@ static int uclogic_resume(struct hid_device *hdev)
#endif
/**
+ * uclogic_exec_event_hook - if the received event is hooked schedules the
+ * associated work.
+ *
+ * @p: Tablet interface report parameters.
+ * @event: Raw event.
+ * @size: The size of event.
+ *
+ * Returns:
+ * Whether the event was hooked or not.
+ */
+static bool uclogic_exec_event_hook(struct uclogic_params *p, u8 *event, int size)
+{
+ struct uclogic_raw_event_hook *curr;
+
+ if (!p->event_hooks)
+ return false;
+
+ list_for_each_entry(curr, &p->event_hooks->list, list) {
+ if (curr->size == size && memcmp(curr->event, event, size) == 0) {
+ schedule_work(&curr->work);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/**
* uclogic_raw_event_pen - handle raw pen events (pen HID reports).
*
* @drvdata: Driver data.
@@ -425,6 +435,9 @@ static int uclogic_raw_event(struct hid_device *hdev,
if (report->type != HID_INPUT_REPORT)
return 0;
+ if (uclogic_exec_event_hook(params, data, size))
+ return 0;
+
while (true) {
/* Tweak pen reports, if necessary */
if ((report_id == params->pen.id) && (size >= 2)) {
@@ -530,8 +543,14 @@ static const struct hid_device_id uclogic_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
+ USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_MW),
+ .driver_data = UCLOGIC_MOUSE_FRAME_QUIRK | UCLOGIC_BATTERY_QUIRK },
+ { HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_S) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
+ USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_SW),
+ .driver_data = UCLOGIC_MOUSE_FRAME_QUIRK | UCLOGIC_BATTERY_QUIRK },
+ { HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06) },
{ }
};
@@ -556,3 +575,7 @@ module_hid_driver(uclogic_driver);
MODULE_AUTHOR("Martin Rusko");
MODULE_AUTHOR("Nikolai Kondrashov");
MODULE_LICENSE("GPL");
+
+#ifdef CONFIG_HID_KUNIT_TEST
+#include "hid-uclogic-core-test.c"
+#endif
diff --git a/drivers/hid/hid-uclogic-params-test.c b/drivers/hid/hid-uclogic-params-test.c
index bfa7ccb7d1e8..678f50cbb160 100644
--- a/drivers/hid/hid-uclogic-params-test.c
+++ b/drivers/hid/hid-uclogic-params-test.c
@@ -174,9 +174,25 @@ static void hid_test_uclogic_parse_ugee_v2_desc(struct kunit *test)
KUNIT_EXPECT_EQ(test, params->frame_type, frame_type);
}
+static void hid_test_uclogic_params_cleanup_event_hooks(struct kunit *test)
+{
+ int res, n;
+ struct uclogic_params p = {0, };
+
+ res = uclogic_params_ugee_v2_init_event_hooks(NULL, &p);
+ KUNIT_ASSERT_EQ(test, res, 0);
+
+ /* Check that the function can be called repeatedly */
+ for (n = 0; n < 4; n++) {
+ uclogic_params_cleanup_event_hooks(&p);
+ KUNIT_EXPECT_PTR_EQ(test, p.event_hooks, NULL);
+ }
+}
+
static struct kunit_case hid_uclogic_params_test_cases[] = {
KUNIT_CASE_PARAM(hid_test_uclogic_parse_ugee_v2_desc,
uclogic_parse_ugee_v2_desc_gen_params),
+ KUNIT_CASE(hid_test_uclogic_params_cleanup_event_hooks),
{}
};
diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c
index 3c5eea3df328..9859dad36495 100644
--- a/drivers/hid/hid-uclogic-params.c
+++ b/drivers/hid/hid-uclogic-params.c
@@ -616,6 +616,31 @@ cleanup:
}
/**
+ * uclogic_params_cleanup_event_hooks - free resources used by the list of raw
+ * event hooks.
+ * Can be called repeatedly.
+ *
+ * @params: Input parameters to cleanup. Cannot be NULL.
+ */
+static void uclogic_params_cleanup_event_hooks(struct uclogic_params *params)
+{
+ struct uclogic_raw_event_hook *curr, *n;
+
+ if (!params || !params->event_hooks)
+ return;
+
+ list_for_each_entry_safe(curr, n, &params->event_hooks->list, list) {
+ cancel_work_sync(&curr->work);
+ list_del(&curr->list);
+ kfree(curr->event);
+ kfree(curr);
+ }
+
+ kfree(params->event_hooks);
+ params->event_hooks = NULL;
+}
+
+/**
* uclogic_params_cleanup - free resources used by struct uclogic_params
* (tablet interface's parameters).
* Can be called repeatedly.
@@ -631,6 +656,7 @@ void uclogic_params_cleanup(struct uclogic_params *params)
for (i = 0; i < ARRAY_SIZE(params->frame_list); i++)
uclogic_params_frame_cleanup(&params->frame_list[i]);
+ uclogic_params_cleanup_event_hooks(params);
memset(params, 0, sizeof(*params));
}
}
@@ -1021,8 +1047,8 @@ cleanup:
* Returns:
* Zero, if successful. A negative errno code on error.
*/
-static int uclogic_probe_interface(struct hid_device *hdev, u8 *magic_arr,
- int magic_size, int endpoint)
+static int uclogic_probe_interface(struct hid_device *hdev, const u8 *magic_arr,
+ size_t magic_size, int endpoint)
{
struct usb_device *udev;
unsigned int pipe = 0;
@@ -1222,6 +1248,11 @@ static int uclogic_params_ugee_v2_init_frame_mouse(struct uclogic_params *p)
*/
static bool uclogic_params_ugee_v2_has_battery(struct hid_device *hdev)
{
+ struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
+
+ if (drvdata->quirks & UCLOGIC_BATTERY_QUIRK)
+ return true;
+
/* The XP-PEN Deco LW vendor, product and version are identical to the
* Deco L. The only difference reported by their firmware is the product
* name. Add a quirk to support battery reporting on the wireless
@@ -1276,6 +1307,72 @@ static int uclogic_params_ugee_v2_init_battery(struct hid_device *hdev,
}
/**
+ * uclogic_params_ugee_v2_reconnect_work() - When a wireless tablet looses
+ * connection to the USB dongle and reconnects, either because of its physical
+ * distance or because it was switches off and on using the frame's switch,
+ * uclogic_probe_interface() needs to be called again to enable the tablet.
+ *
+ * @work: The work that triggered this function.
+ */
+static void uclogic_params_ugee_v2_reconnect_work(struct work_struct *work)
+{
+ struct uclogic_raw_event_hook *event_hook;
+
+ event_hook = container_of(work, struct uclogic_raw_event_hook, work);
+ uclogic_probe_interface(event_hook->hdev, uclogic_ugee_v2_probe_arr,
+ uclogic_ugee_v2_probe_size,
+ uclogic_ugee_v2_probe_endpoint);
+}
+
+/**
+ * uclogic_params_ugee_v2_init_event_hooks() - initialize the list of events
+ * to be hooked for UGEE v2 devices.
+ * @hdev: The HID device of the tablet interface to initialize and get
+ * parameters from.
+ * @p: Parameters to fill in, cannot be NULL.
+ *
+ * Returns:
+ * Zero, if successful. A negative errno code on error.
+ */
+static int uclogic_params_ugee_v2_init_event_hooks(struct hid_device *hdev,
+ struct uclogic_params *p)
+{
+ struct uclogic_raw_event_hook *event_hook;
+ __u8 reconnect_event[] = {
+ /* Event received on wireless tablet reconnection */
+ 0x02, 0xF8, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+ if (!p)
+ return -EINVAL;
+
+ /* The reconnection event is only received if the tablet has battery */
+ if (!uclogic_params_ugee_v2_has_battery(hdev))
+ return 0;
+
+ p->event_hooks = kzalloc(sizeof(*p->event_hooks), GFP_KERNEL);
+ if (!p->event_hooks)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&p->event_hooks->list);
+
+ event_hook = kzalloc(sizeof(*event_hook), GFP_KERNEL);
+ if (!event_hook)
+ return -ENOMEM;
+
+ INIT_WORK(&event_hook->work, uclogic_params_ugee_v2_reconnect_work);
+ event_hook->hdev = hdev;
+ event_hook->size = ARRAY_SIZE(reconnect_event);
+ event_hook->event = kmemdup(reconnect_event, event_hook->size, GFP_KERNEL);
+ if (!event_hook->event)
+ return -ENOMEM;
+
+ list_add_tail(&event_hook->list, &p->event_hooks->list);
+
+ return 0;
+}
+
+/**
* uclogic_params_ugee_v2_init() - initialize a UGEE graphics tablets by
* discovering their parameters.
*
@@ -1298,6 +1395,7 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params,
struct hid_device *hdev)
{
int rc = 0;
+ struct uclogic_drvdata *drvdata;
struct usb_interface *iface;
__u8 bInterfaceNumber;
const int str_desc_len = 12;
@@ -1305,9 +1403,6 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params,
__u8 *rdesc_pen = NULL;
s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM];
enum uclogic_params_frame_type frame_type;
- __u8 magic_arr[] = {
- 0x02, 0xb0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
- };
/* The resulting parameters (noop) */
struct uclogic_params p = {0, };
@@ -1316,6 +1411,7 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params,
goto cleanup;
}
+ drvdata = hid_get_drvdata(hdev);
iface = to_usb_interface(hdev->dev.parent);
bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber;
@@ -1337,7 +1433,9 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params,
* The specific data was discovered by sniffing the Windows driver
* traffic.
*/
- rc = uclogic_probe_interface(hdev, magic_arr, sizeof(magic_arr), 0x03);
+ rc = uclogic_probe_interface(hdev, uclogic_ugee_v2_probe_arr,
+ uclogic_ugee_v2_probe_size,
+ uclogic_ugee_v2_probe_endpoint);
if (rc) {
uclogic_params_init_invalid(&p);
goto output;
@@ -1382,6 +1480,9 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params,
p.pen.subreport_list[0].id = UCLOGIC_RDESC_V1_FRAME_ID;
/* Initialize the frame interface */
+ if (drvdata->quirks & UCLOGIC_MOUSE_FRAME_QUIRK)
+ frame_type = UCLOGIC_PARAMS_FRAME_MOUSE;
+
switch (frame_type) {
case UCLOGIC_PARAMS_FRAME_DIAL:
case UCLOGIC_PARAMS_FRAME_MOUSE:
@@ -1407,6 +1508,13 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params,
}
}
+ /* Create a list of raw events to be ignored */
+ rc = uclogic_params_ugee_v2_init_event_hooks(hdev, &p);
+ if (rc) {
+ hid_err(hdev, "error initializing event hook list: %d\n", rc);
+ goto cleanup;
+ }
+
output:
/* Output parameters */
memcpy(params, &p, sizeof(*params));
@@ -1660,7 +1768,11 @@ int uclogic_params_init(struct uclogic_params *params,
case VID_PID(USB_VENDOR_ID_UGEE,
USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L):
case VID_PID(USB_VENDOR_ID_UGEE,
+ USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_MW):
+ case VID_PID(USB_VENDOR_ID_UGEE,
USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_S):
+ case VID_PID(USB_VENDOR_ID_UGEE,
+ USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_SW):
rc = uclogic_params_ugee_v2_init(&p, hdev);
if (rc != 0)
goto cleanup;
diff --git a/drivers/hid/hid-uclogic-params.h b/drivers/hid/hid-uclogic-params.h
index a97477c02ff8..d6ffadb2f601 100644
--- a/drivers/hid/hid-uclogic-params.h
+++ b/drivers/hid/hid-uclogic-params.h
@@ -18,6 +18,10 @@
#include <linux/usb.h>
#include <linux/hid.h>
+#include <linux/list.h>
+
+#define UCLOGIC_MOUSE_FRAME_QUIRK BIT(0)
+#define UCLOGIC_BATTERY_QUIRK BIT(1)
/* Types of pen in-range reporting */
enum uclogic_params_pen_inrange {
@@ -174,6 +178,17 @@ struct uclogic_params_frame {
};
/*
+ * List of works to be performed when a certain raw event is received.
+ */
+struct uclogic_raw_event_hook {
+ struct hid_device *hdev;
+ __u8 *event;
+ size_t size;
+ struct work_struct work;
+ struct list_head list;
+};
+
+/*
* Tablet interface report parameters.
*
* Must use declarative (descriptive) language, not imperative, to simplify
@@ -213,6 +228,31 @@ struct uclogic_params {
* parts. Only valid, if "invalid" is false.
*/
struct uclogic_params_frame frame_list[3];
+ /*
+ * List of event hooks.
+ */
+ struct uclogic_raw_event_hook *event_hooks;
+};
+
+/* Driver data */
+struct uclogic_drvdata {
+ /* Interface parameters */
+ struct uclogic_params params;
+ /* Pointer to the replacement report descriptor. NULL if none. */
+ __u8 *desc_ptr;
+ /*
+ * Size of the replacement report descriptor.
+ * Only valid if desc_ptr is not NULL
+ */
+ unsigned int desc_size;
+ /* Pen input device */
+ struct input_dev *pen_input;
+ /* In-range timer */
+ struct timer_list inrange_timer;
+ /* Last rotary encoder state, or U8_MAX for none */
+ u8 re_state;
+ /* Device quirks */
+ unsigned long quirks;
};
/* Initialize a tablet interface and discover its parameters */
diff --git a/drivers/hid/hid-uclogic-rdesc-test.c b/drivers/hid/hid-uclogic-rdesc-test.c
index b429c541bf2f..90bf4e586e01 100644
--- a/drivers/hid/hid-uclogic-rdesc-test.c
+++ b/drivers/hid/hid-uclogic-rdesc-test.c
@@ -197,8 +197,7 @@ static void hid_test_uclogic_template(struct kunit *test)
params->param_list,
params->param_num);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, res);
- KUNIT_EXPECT_EQ(test, 0,
- memcmp(res, params->expected, params->template_size));
+ KUNIT_EXPECT_MEMEQ(test, res, params->expected, params->template_size);
kfree(res);
}
diff --git a/drivers/hid/hid-uclogic-rdesc.c b/drivers/hid/hid-uclogic-rdesc.c
index fb40775f5f5b..b6dfdf6356a6 100644
--- a/drivers/hid/hid-uclogic-rdesc.c
+++ b/drivers/hid/hid-uclogic-rdesc.c
@@ -859,6 +859,12 @@ const __u8 uclogic_rdesc_v2_frame_dial_arr[] = {
const size_t uclogic_rdesc_v2_frame_dial_size =
sizeof(uclogic_rdesc_v2_frame_dial_arr);
+const __u8 uclogic_ugee_v2_probe_arr[] = {
+ 0x02, 0xb0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+const size_t uclogic_ugee_v2_probe_size = sizeof(uclogic_ugee_v2_probe_arr);
+const int uclogic_ugee_v2_probe_endpoint = 0x03;
+
/* Fixed report descriptor template for UGEE v2 pen reports */
const __u8 uclogic_rdesc_ugee_v2_pen_template_arr[] = {
0x05, 0x0d, /* Usage Page (Digitizers), */
diff --git a/drivers/hid/hid-uclogic-rdesc.h b/drivers/hid/hid-uclogic-rdesc.h
index a1f78c07293f..906d068f50a9 100644
--- a/drivers/hid/hid-uclogic-rdesc.h
+++ b/drivers/hid/hid-uclogic-rdesc.h
@@ -164,6 +164,11 @@ extern const size_t uclogic_rdesc_v2_frame_dial_size;
/* Report ID for tweaked UGEE v2 battery reports */
#define UCLOGIC_RDESC_UGEE_V2_BATTERY_ID 0xba
+/* Magic data expected by UGEEv2 devices on probe */
+extern const __u8 uclogic_ugee_v2_probe_arr[];
+extern const size_t uclogic_ugee_v2_probe_size;
+extern const int uclogic_ugee_v2_probe_endpoint;
+
/* Fixed report descriptor template for UGEE v2 pen reports */
extern const __u8 uclogic_rdesc_ugee_v2_pen_template_arr[];
extern const size_t uclogic_rdesc_ugee_v2_pen_template_size;
diff --git a/drivers/hid/i2c-hid/Kconfig b/drivers/hid/i2c-hid/Kconfig
index d65abe65ce73..4439be7fa74d 100644
--- a/drivers/hid/i2c-hid/Kconfig
+++ b/drivers/hid/i2c-hid/Kconfig
@@ -1,11 +1,15 @@
# SPDX-License-Identifier: GPL-2.0-only
-menu "I2C HID support"
- depends on I2C
+menuconfig I2C_HID
+ tristate "I2C HID support"
+ default y
+ depends on I2C && INPUT && HID
+
+if I2C_HID
config I2C_HID_ACPI
tristate "HID over I2C transport layer ACPI driver"
- default n
- depends on I2C && INPUT && ACPI
+ depends on ACPI
+ select I2C_HID_CORE
help
Say Y here if you use a keyboard, a touchpad, a touchscreen, or any
other HID based devices which is connected to your computer via I2C.
@@ -19,8 +23,8 @@ config I2C_HID_ACPI
config I2C_HID_OF
tristate "HID over I2C transport layer Open Firmware driver"
- default n
- depends on I2C && INPUT && OF
+ depends on OF
+ select I2C_HID_CORE
help
Say Y here if you use a keyboard, a touchpad, a touchscreen, or any
other HID based devices which is connected to your computer via I2C.
@@ -34,8 +38,8 @@ config I2C_HID_OF
config I2C_HID_OF_ELAN
tristate "Driver for Elan hid-i2c based devices on OF systems"
- default n
- depends on I2C && INPUT && OF
+ depends on OF
+ select I2C_HID_CORE
help
Say Y here if you want support for Elan i2c devices that use
the i2c-hid protocol on Open Firmware (Device Tree)-based
@@ -49,8 +53,8 @@ config I2C_HID_OF_ELAN
config I2C_HID_OF_GOODIX
tristate "Driver for Goodix hid-i2c based devices on OF systems"
- default n
- depends on I2C && INPUT && OF
+ depends on OF
+ select I2C_HID_CORE
help
Say Y here if you want support for Goodix i2c devices that use
the i2c-hid protocol on Open Firmware (Device Tree)-based
@@ -62,10 +66,7 @@ config I2C_HID_OF_GOODIX
will be called i2c-hid-of-goodix. It will also build/depend on
the module i2c-hid.
-endmenu
-
config I2C_HID_CORE
tristate
- default y if I2C_HID_ACPI=y || I2C_HID_OF=y || I2C_HID_OF_ELAN=y || I2C_HID_OF_GOODIX=y
- default m if I2C_HID_ACPI=m || I2C_HID_OF=m || I2C_HID_OF_ELAN=m || I2C_HID_OF_GOODIX=m
- select HID
+endif
+
diff --git a/drivers/hid/i2c-hid/i2c-hid-acpi.c b/drivers/hid/i2c-hid/i2c-hid-acpi.c
index 375c77c3db74..3a7e2bcb5412 100644
--- a/drivers/hid/i2c-hid/i2c-hid-acpi.c
+++ b/drivers/hid/i2c-hid/i2c-hid-acpi.c
@@ -39,8 +39,8 @@ static const struct acpi_device_id i2c_hid_acpi_blacklist[] = {
* The CHPN0001 ACPI device, which is used to describe the Chipone
* ICN8505 controller, has a _CID of PNP0C50 but is not HID compatible.
*/
- {"CHPN0001", 0 },
- { },
+ { "CHPN0001" },
+ { }
};
/* HID I²C Device: 3cdff6f7-4267-4555-ad05-b30a3d8938de */
@@ -48,8 +48,9 @@ static guid_t i2c_hid_guid =
GUID_INIT(0x3CDFF6F7, 0x4267, 0x4555,
0xAD, 0x05, 0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE);
-static int i2c_hid_acpi_get_descriptor(struct acpi_device *adev)
+static int i2c_hid_acpi_get_descriptor(struct i2c_hid_acpi *ihid_acpi)
{
+ struct acpi_device *adev = ihid_acpi->adev;
acpi_handle handle = acpi_device_handle(adev);
union acpi_object *obj;
u16 hid_descriptor_address;
@@ -81,38 +82,31 @@ static int i2c_hid_acpi_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct i2c_hid_acpi *ihid_acpi;
- struct acpi_device *adev;
u16 hid_descriptor_address;
int ret;
- adev = ACPI_COMPANION(dev);
- if (!adev) {
- dev_err(&client->dev, "Error could not get ACPI device\n");
- return -ENODEV;
- }
-
ihid_acpi = devm_kzalloc(&client->dev, sizeof(*ihid_acpi), GFP_KERNEL);
if (!ihid_acpi)
return -ENOMEM;
- ihid_acpi->adev = adev;
+ ihid_acpi->adev = ACPI_COMPANION(dev);
ihid_acpi->ops.shutdown_tail = i2c_hid_acpi_shutdown_tail;
- ret = i2c_hid_acpi_get_descriptor(adev);
+ ret = i2c_hid_acpi_get_descriptor(ihid_acpi);
if (ret < 0)
return ret;
hid_descriptor_address = ret;
- acpi_device_fix_up_power(adev);
+ acpi_device_fix_up_power(ihid_acpi->adev);
return i2c_hid_core_probe(client, &ihid_acpi->ops,
hid_descriptor_address, 0);
}
static const struct acpi_device_id i2c_hid_acpi_match[] = {
- {"ACPI0C50", 0 },
- {"PNP0C50", 0 },
- { },
+ { "ACPI0C50" },
+ { "PNP0C50" },
+ { }
};
MODULE_DEVICE_TABLE(acpi, i2c_hid_acpi_match);
diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c
index b86b62f97108..efbba0465eef 100644
--- a/drivers/hid/i2c-hid/i2c-hid-core.c
+++ b/drivers/hid/i2c-hid/i2c-hid-core.c
@@ -67,16 +67,7 @@
#define I2C_HID_PWR_ON 0x00
#define I2C_HID_PWR_SLEEP 0x01
-/* debug option */
-static bool debug;
-module_param(debug, bool, 0444);
-MODULE_PARM_DESC(debug, "print a lot of debug information");
-
-#define i2c_hid_dbg(ihid, fmt, arg...) \
-do { \
- if (debug) \
- dev_printk(KERN_DEBUG, &(ihid)->client->dev, fmt, ##arg); \
-} while (0)
+#define i2c_hid_dbg(ihid, ...) dev_dbg(&(ihid)->client->dev, __VA_ARGS__)
struct i2c_hid_desc {
__le16 wHIDDescLength;
@@ -842,7 +833,7 @@ static void i2c_hid_close(struct hid_device *hid)
clear_bit(I2C_HID_STARTED, &ihid->flags);
}
-struct hid_ll_driver i2c_hid_ll_driver = {
+static const struct hid_ll_driver i2c_hid_ll_driver = {
.parse = i2c_hid_parse,
.start = i2c_hid_start,
.stop = i2c_hid_stop,
@@ -851,7 +842,6 @@ struct hid_ll_driver i2c_hid_ll_driver = {
.output_report = i2c_hid_output_report,
.raw_request = i2c_hid_raw_request,
};
-EXPORT_SYMBOL_GPL(i2c_hid_ll_driver);
static int i2c_hid_init_irq(struct i2c_client *client)
{
@@ -859,7 +849,7 @@ static int i2c_hid_init_irq(struct i2c_client *client)
unsigned long irqflags = 0;
int ret;
- dev_dbg(&client->dev, "Requesting IRQ: %d\n", client->irq);
+ i2c_hid_dbg(ihid, "Requesting IRQ: %d\n", client->irq);
if (!irq_get_trigger_type(client->irq))
irqflags = IRQF_TRIGGER_LOW;
@@ -1003,7 +993,7 @@ int i2c_hid_core_probe(struct i2c_client *client, struct i2chid_ops *ops,
/* Make sure there is something at this address */
ret = i2c_smbus_read_byte(client);
if (ret < 0) {
- dev_dbg(&client->dev, "nothing at this address: %d\n", ret);
+ i2c_hid_dbg(ihid, "nothing at this address: %d\n", ret);
ret = -ENXIO;
goto err_powered;
}
@@ -1035,6 +1025,10 @@ int i2c_hid_core_probe(struct i2c_client *client, struct i2chid_ops *ops,
hid->vendor = le16_to_cpu(ihid->hdesc.wVendorID);
hid->product = le16_to_cpu(ihid->hdesc.wProductID);
+ hid->initial_quirks = quirks;
+ hid->initial_quirks |= i2c_hid_get_dmi_quirks(hid->vendor,
+ hid->product);
+
snprintf(hid->name, sizeof(hid->name), "%s %04X:%04X",
client->name, (u16)hid->vendor, (u16)hid->product);
strscpy(hid->phys, dev_name(&client->dev), sizeof(hid->phys));
@@ -1048,8 +1042,6 @@ int i2c_hid_core_probe(struct i2c_client *client, struct i2chid_ops *ops,
goto err_mem_free;
}
- hid->quirks |= quirks;
-
return 0;
err_mem_free:
diff --git a/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c
index 8e0f67455c09..210f17c3a0be 100644
--- a/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c
+++ b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c
@@ -10,8 +10,10 @@
#include <linux/types.h>
#include <linux/dmi.h>
#include <linux/mod_devicetable.h>
+#include <linux/hid.h>
#include "i2c-hid.h"
+#include "../hid-ids.h"
struct i2c_hid_desc_override {
@@ -416,6 +418,28 @@ static const struct dmi_system_id i2c_hid_dmi_desc_override_table[] = {
{ } /* Terminate list */
};
+static const struct hid_device_id i2c_hid_elan_flipped_quirks = {
+ HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, USB_VENDOR_ID_ELAN, 0x2dcd),
+ HID_QUIRK_X_INVERT | HID_QUIRK_Y_INVERT
+};
+
+/*
+ * This list contains devices which have specific issues based on the system
+ * they're on and not just the device itself. The driver_data will have a
+ * specific hid device to match against.
+ */
+static const struct dmi_system_id i2c_hid_dmi_quirk_table[] = {
+ {
+ .ident = "DynaBook K50/FR",
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dynabook Inc."),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "dynabook K50/FR"),
+ },
+ .driver_data = (void *)&i2c_hid_elan_flipped_quirks,
+ },
+ { } /* Terminate list */
+};
+
struct i2c_hid_desc *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name)
{
@@ -450,3 +474,21 @@ char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name,
*size = override->hid_report_desc_size;
return override->hid_report_desc;
}
+
+u32 i2c_hid_get_dmi_quirks(const u16 vendor, const u16 product)
+{
+ u32 quirks = 0;
+ const struct dmi_system_id *system_id =
+ dmi_first_match(i2c_hid_dmi_quirk_table);
+
+ if (system_id) {
+ const struct hid_device_id *device_id =
+ (struct hid_device_id *)(system_id->driver_data);
+
+ if (device_id && device_id->vendor == vendor &&
+ device_id->product == product)
+ quirks = device_id->driver_data;
+ }
+
+ return quirks;
+}
diff --git a/drivers/hid/i2c-hid/i2c-hid-of-goodix.c b/drivers/hid/i2c-hid/i2c-hid-of-goodix.c
index 29c6cb174032..0060e3dcd775 100644
--- a/drivers/hid/i2c-hid/i2c-hid-of-goodix.c
+++ b/drivers/hid/i2c-hid/i2c-hid-of-goodix.c
@@ -26,28 +26,33 @@ struct i2c_hid_of_goodix {
struct i2chid_ops ops;
struct regulator *vdd;
- struct notifier_block nb;
+ struct regulator *vddio;
struct gpio_desc *reset_gpio;
const struct goodix_i2c_hid_timing_data *timings;
};
-static void goodix_i2c_hid_deassert_reset(struct i2c_hid_of_goodix *ihid_goodix,
- bool regulator_just_turned_on)
+static int goodix_i2c_hid_power_up(struct i2chid_ops *ops)
{
- if (regulator_just_turned_on && ihid_goodix->timings->post_power_delay_ms)
+ struct i2c_hid_of_goodix *ihid_goodix =
+ container_of(ops, struct i2c_hid_of_goodix, ops);
+ int ret;
+
+ ret = regulator_enable(ihid_goodix->vdd);
+ if (ret)
+ return ret;
+
+ ret = regulator_enable(ihid_goodix->vddio);
+ if (ret)
+ return ret;
+
+ if (ihid_goodix->timings->post_power_delay_ms)
msleep(ihid_goodix->timings->post_power_delay_ms);
gpiod_set_value_cansleep(ihid_goodix->reset_gpio, 0);
if (ihid_goodix->timings->post_gpio_reset_delay_ms)
msleep(ihid_goodix->timings->post_gpio_reset_delay_ms);
-}
-
-static int goodix_i2c_hid_power_up(struct i2chid_ops *ops)
-{
- struct i2c_hid_of_goodix *ihid_goodix =
- container_of(ops, struct i2c_hid_of_goodix, ops);
- return regulator_enable(ihid_goodix->vdd);
+ return 0;
}
static void goodix_i2c_hid_power_down(struct i2chid_ops *ops)
@@ -55,42 +60,15 @@ static void goodix_i2c_hid_power_down(struct i2chid_ops *ops)
struct i2c_hid_of_goodix *ihid_goodix =
container_of(ops, struct i2c_hid_of_goodix, ops);
+ gpiod_set_value_cansleep(ihid_goodix->reset_gpio, 1);
+ regulator_disable(ihid_goodix->vddio);
regulator_disable(ihid_goodix->vdd);
}
-static int ihid_goodix_vdd_notify(struct notifier_block *nb,
- unsigned long event,
- void *ignored)
-{
- struct i2c_hid_of_goodix *ihid_goodix =
- container_of(nb, struct i2c_hid_of_goodix, nb);
- int ret = NOTIFY_OK;
-
- switch (event) {
- case REGULATOR_EVENT_PRE_DISABLE:
- gpiod_set_value_cansleep(ihid_goodix->reset_gpio, 1);
- break;
-
- case REGULATOR_EVENT_ENABLE:
- goodix_i2c_hid_deassert_reset(ihid_goodix, true);
- break;
-
- case REGULATOR_EVENT_ABORT_DISABLE:
- goodix_i2c_hid_deassert_reset(ihid_goodix, false);
- break;
-
- default:
- ret = NOTIFY_DONE;
- break;
- }
-
- return ret;
-}
-
static int i2c_hid_of_goodix_probe(struct i2c_client *client)
{
struct i2c_hid_of_goodix *ihid_goodix;
- int ret;
+
ihid_goodix = devm_kzalloc(&client->dev, sizeof(*ihid_goodix),
GFP_KERNEL);
if (!ihid_goodix)
@@ -109,41 +87,11 @@ static int i2c_hid_of_goodix_probe(struct i2c_client *client)
if (IS_ERR(ihid_goodix->vdd))
return PTR_ERR(ihid_goodix->vdd);
- ihid_goodix->timings = device_get_match_data(&client->dev);
+ ihid_goodix->vddio = devm_regulator_get(&client->dev, "mainboard-vddio");
+ if (IS_ERR(ihid_goodix->vddio))
+ return PTR_ERR(ihid_goodix->vddio);
- /*
- * We need to control the "reset" line in lockstep with the regulator
- * actually turning on an off instead of just when we make the request.
- * This matters if the regulator is shared with another consumer.
- * - If the regulator is off then we must assert reset. The reset
- * line is active low and on some boards it could cause a current
- * leak if left high.
- * - If the regulator is on then we don't want reset asserted for very
- * long. Holding the controller in reset apparently draws extra
- * power.
- */
- ihid_goodix->nb.notifier_call = ihid_goodix_vdd_notify;
- ret = devm_regulator_register_notifier(ihid_goodix->vdd, &ihid_goodix->nb);
- if (ret)
- return dev_err_probe(&client->dev, ret,
- "regulator notifier request failed\n");
-
- /*
- * If someone else is holding the regulator on (or the regulator is
- * an always-on one) we might never be told to deassert reset. Do it
- * now... and temporarily bump the regulator reference count just to
- * make sure it is impossible for this to race with our own notifier!
- * We also assume that someone else might have _just barely_ turned
- * the regulator on so we'll do the full "post_power_delay" just in
- * case.
- */
- if (ihid_goodix->reset_gpio && regulator_is_enabled(ihid_goodix->vdd)) {
- ret = regulator_enable(ihid_goodix->vdd);
- if (ret)
- return ret;
- goodix_i2c_hid_deassert_reset(ihid_goodix, true);
- regulator_disable(ihid_goodix->vdd);
- }
+ ihid_goodix->timings = device_get_match_data(&client->dev);
return i2c_hid_core_probe(client, &ihid_goodix->ops, 0x0001, 0);
}
diff --git a/drivers/hid/i2c-hid/i2c-hid.h b/drivers/hid/i2c-hid/i2c-hid.h
index 96c75510ad3f..2c7b66d5caa0 100644
--- a/drivers/hid/i2c-hid/i2c-hid.h
+++ b/drivers/hid/i2c-hid/i2c-hid.h
@@ -9,6 +9,7 @@
struct i2c_hid_desc *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name);
char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name,
unsigned int *size);
+u32 i2c_hid_get_dmi_quirks(const u16 vendor, const u16 product);
#else
static inline struct i2c_hid_desc
*i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name)
@@ -16,6 +17,8 @@ static inline struct i2c_hid_desc
static inline char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name,
unsigned int *size)
{ return NULL; }
+static inline u32 i2c_hid_get_dmi_quirks(const u16 vendor, const u16 product)
+{ return 0; }
#endif
/**
diff --git a/drivers/hid/intel-ish-hid/Kconfig b/drivers/hid/intel-ish-hid/Kconfig
index 689da84a520d..253dc10d35ef 100644
--- a/drivers/hid/intel-ish-hid/Kconfig
+++ b/drivers/hid/intel-ish-hid/Kconfig
@@ -6,7 +6,7 @@ config INTEL_ISH_HID
tristate "Intel Integrated Sensor Hub"
default n
depends on X86
- select HID
+ depends on HID
help
The Integrated Sensor Hub (ISH) enables the ability to offload
sensor polling and algorithm processing to a dedicated low power
diff --git a/drivers/hid/intel-ish-hid/ishtp-hid.c b/drivers/hid/intel-ish-hid/ishtp-hid.c
index 14c271d7d8a9..00c6f0ebf356 100644
--- a/drivers/hid/intel-ish-hid/ishtp-hid.c
+++ b/drivers/hid/intel-ish-hid/ishtp-hid.c
@@ -183,7 +183,7 @@ void ishtp_hid_wakeup(struct hid_device *hid)
wake_up_interruptible(&hid_data->hid_wait);
}
-static struct hid_ll_driver ishtp_hid_ll_driver = {
+static const struct hid_ll_driver ishtp_hid_ll_driver = {
.parse = ishtp_hid_parse,
.start = ishtp_hid_start,
.stop = ishtp_hid_stop,
diff --git a/drivers/hid/intel-ish-hid/ishtp/bus.c b/drivers/hid/intel-ish-hid/ishtp/bus.c
index f68aba8794fe..81385ab37fa9 100644
--- a/drivers/hid/intel-ish-hid/ishtp/bus.c
+++ b/drivers/hid/intel-ish-hid/ishtp/bus.c
@@ -361,7 +361,7 @@ static struct attribute *ishtp_cl_dev_attrs[] = {
};
ATTRIBUTE_GROUPS(ishtp_cl_dev);
-static int ishtp_cl_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int ishtp_cl_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
if (add_uevent_var(env, "MODALIAS=" ISHTP_MODULE_PREFIX "%s", dev_name(dev)))
return -ENOMEM;
diff --git a/drivers/hid/surface-hid/surface_hid_core.c b/drivers/hid/surface-hid/surface_hid_core.c
index 87637f813de2..a3e9cceddfac 100644
--- a/drivers/hid/surface-hid/surface_hid_core.c
+++ b/drivers/hid/surface-hid/surface_hid_core.c
@@ -174,7 +174,7 @@ static int surface_hid_raw_request(struct hid_device *hid, unsigned char reportn
return -EIO;
}
-static struct hid_ll_driver surface_hid_ll_driver = {
+static const struct hid_ll_driver surface_hid_ll_driver = {
.start = surface_hid_start,
.stop = surface_hid_stop,
.open = surface_hid_open,
diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
index 2a918aeb0af1..f161c95a1ad2 100644
--- a/drivers/hid/uhid.c
+++ b/drivers/hid/uhid.c
@@ -387,7 +387,7 @@ static int uhid_hid_output_report(struct hid_device *hid, __u8 *buf,
return uhid_hid_output_raw(hid, buf, count, HID_OUTPUT_REPORT);
}
-struct hid_ll_driver uhid_hid_driver = {
+static const struct hid_ll_driver uhid_hid_driver = {
.start = uhid_hid_start,
.stop = uhid_hid_stop,
.open = uhid_hid_open,
@@ -396,7 +396,6 @@ struct hid_ll_driver uhid_hid_driver = {
.raw_request = uhid_hid_raw_request,
.output_report = uhid_hid_output_report,
};
-EXPORT_SYMBOL_GPL(uhid_hid_driver);
#ifdef CONFIG_COMPAT
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index be4c731aaa65..257dd73e37bf 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -1318,7 +1318,7 @@ static bool usbhid_may_wakeup(struct hid_device *hid)
return device_may_wakeup(&dev->dev);
}
-struct hid_ll_driver usb_hid_driver = {
+static const struct hid_ll_driver usb_hid_driver = {
.parse = usbhid_parse,
.start = usbhid_start,
.stop = usbhid_stop,
@@ -1332,7 +1332,12 @@ struct hid_ll_driver usb_hid_driver = {
.idle = usbhid_idle,
.may_wakeup = usbhid_may_wakeup,
};
-EXPORT_SYMBOL_GPL(usb_hid_driver);
+
+bool hid_is_usb(const struct hid_device *hdev)
+{
+ return hdev->ll_driver == &usb_hid_driver;
+}
+EXPORT_SYMBOL_GPL(hid_is_usb);
static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
diff --git a/drivers/hsi/clients/cmt_speech.c b/drivers/hsi/clients/cmt_speech.c
index 8069f795c864..daa8e1bff5d9 100644
--- a/drivers/hsi/clients/cmt_speech.c
+++ b/drivers/hsi/clients/cmt_speech.c
@@ -1264,7 +1264,7 @@ static int cs_char_mmap(struct file *file, struct vm_area_struct *vma)
if (vma_pages(vma) != 1)
return -EINVAL;
- vma->vm_flags |= VM_IO | VM_DONTDUMP | VM_DONTEXPAND;
+ vm_flags_set(vma, VM_IO | VM_DONTDUMP | VM_DONTEXPAND);
vma->vm_ops = &cs_char_vm_ops;
vma->vm_private_data = file->private_data;
diff --git a/drivers/hsi/hsi_core.c b/drivers/hsi/hsi_core.c
index 884066109699..8fda8f1d064d 100644
--- a/drivers/hsi/hsi_core.c
+++ b/drivers/hsi/hsi_core.c
@@ -30,7 +30,7 @@ static struct attribute *hsi_bus_dev_attrs[] = {
};
ATTRIBUTE_GROUPS(hsi_bus_dev);
-static int hsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int hsi_bus_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
add_uevent_var(env, "MODALIAS=hsi:%s", dev_name(dev));
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index 1901556efe79..d24dd65b33d4 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -711,9 +711,9 @@ __ATTRIBUTE_GROUPS(vmbus_bus);
* representation of the device guid (each byte of the guid will be
* represented with two hex characters.
*/
-static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env)
+static int vmbus_uevent(const struct device *device, struct kobj_uevent_env *env)
{
- struct hv_device *dev = device_to_hv_device(device);
+ const struct hv_device *dev = device_to_hv_device(device);
const char *format = "MODALIAS=vmbus:%*phN";
return add_uevent_var(env, format, UUID_SIZE, &dev->dev_type);
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 497cbfb460e5..5b3b76477b0e 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -714,6 +714,15 @@ config SENSORS_GPIO_FAN
This driver can also be built as a module. If so, the module
will be called gpio-fan.
+config SENSORS_GXP_FAN_CTRL
+ tristate "HPE GXP fan controller"
+ depends on ARCH_HPE_GXP || COMPILE_TEST
+ help
+ If you say yes here you get support for GXP fan control functionality.
+
+ The GXP controls fan function via the CPLD through the use of PWM
+ registers. This driver reports status and pwm setting of the fans.
+
config SENSORS_HIH6130
tristate "Honeywell Humidicon HIH-6130 humidity/temperature sensor"
depends on I2C
@@ -1166,6 +1175,13 @@ config SENSORS_MAX31790
This driver can also be built as a module. If so, the module
will be called max31790.
+config SENSORS_MC34VR500
+ tristate "NXP MC34VR500 hardware monitoring driver"
+ depends on I2C
+ help
+ If you say yes here you get support for the temperature and input
+ voltage sensors of the NXP MC34VR500.
+
config SENSORS_MCP3021
tristate "Microchip MCP3021 and compatibles"
depends on I2C
@@ -1516,7 +1532,7 @@ config SENSORS_NCT6775_CORE
config SENSORS_NCT6775
tristate "Platform driver for Nuvoton NCT6775F and compatibles"
depends on !PPC
- depends on ACPI_WMI || ACPI_WMI=n
+ depends on ACPI || ACPI=n
select HWMON_VID
select SENSORS_NCT6775_CORE
help
@@ -2324,7 +2340,7 @@ config SENSORS_XGENE
config SENSORS_INTEL_M10_BMC_HWMON
tristate "Intel MAX10 BMC Hardware Monitoring"
- depends on MFD_INTEL_M10_BMC
+ depends on MFD_INTEL_M10_BMC_CORE
help
This driver provides support for the hardware monitoring functionality
on Intel MAX10 BMC chip.
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 4f71d9807dae..88712b5031c8 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -83,6 +83,7 @@ obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o
obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o
obj-$(CONFIG_SENSORS_GSC) += gsc-hwmon.o
obj-$(CONFIG_SENSORS_GPIO_FAN) += gpio-fan.o
+obj-$(CONFIG_SENSORS_GXP_FAN_CTRL) += gxp-fan-ctrl.o
obj-$(CONFIG_SENSORS_HIH6130) += hih6130.o
obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o
obj-$(CONFIG_SENSORS_I5500) += i5500_temp.o
@@ -149,6 +150,7 @@ obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
obj-$(CONFIG_SENSORS_MAX6697) += max6697.o
obj-$(CONFIG_SENSORS_MAX31790) += max31790.o
obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
+obj-$(CONFIG_SENSORS_MC34VR500) += mc34vr500.o
obj-$(CONFIG_SENSORS_MCP3021) += mcp3021.o
obj-$(CONFIG_SENSORS_TC654) += tc654.o
obj-$(CONFIG_SENSORS_TPS23861) += tps23861.o
diff --git a/drivers/hwmon/aht10.c b/drivers/hwmon/aht10.c
index d76f3441ecf1..9babd69d54a3 100644
--- a/drivers/hwmon/aht10.c
+++ b/drivers/hwmon/aht10.c
@@ -79,7 +79,6 @@ struct aht10_data {
/**
* aht10_init() - Initialize an AHT10 chip
- * @client: the i2c client associated with the AHT10
* @data: the data associated with this AHT10 chip
* Return: 0 if succesfull, 1 if not
*/
@@ -124,7 +123,7 @@ static int aht10_polltime_expired(struct aht10_data *data)
/**
* aht10_read_values() - read and parse the raw data from the AHT10
- * @aht10_data: the struct aht10_data to use for the lock
+ * @data: the struct aht10_data to use for the lock
* Return: 0 if succesfull, 1 if not
*/
static int aht10_read_values(struct aht10_data *data)
diff --git a/drivers/hwmon/aquacomputer_d5next.c b/drivers/hwmon/aquacomputer_d5next.c
index 9cc10080160b..12682a610ce7 100644
--- a/drivers/hwmon/aquacomputer_d5next.c
+++ b/drivers/hwmon/aquacomputer_d5next.c
@@ -1,10 +1,11 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* hwmon driver for Aquacomputer devices (D5 Next, Farbwerk, Farbwerk 360, Octo,
- * Quadro, High Flow Next)
+ * Quadro, High Flow Next, Aquaero, Aquastream Ultimate)
*
* Aquacomputer devices send HID reports (with ID 0x01) every second to report
- * sensor values.
+ * sensor values, except for devices that communicate through the
+ * legacy way (currently, Poweradjust 3).
*
* Copyright 2021 Aleksa Savic <savicaleksa83@gmail.com>
* Copyright 2022 Jack Doan <me@jackdoan.com>
@@ -21,14 +22,20 @@
#include <asm/unaligned.h>
#define USB_VENDOR_ID_AQUACOMPUTER 0x0c70
+#define USB_PRODUCT_ID_AQUAERO 0xf001
#define USB_PRODUCT_ID_FARBWERK 0xf00a
#define USB_PRODUCT_ID_QUADRO 0xf00d
#define USB_PRODUCT_ID_D5NEXT 0xf00e
#define USB_PRODUCT_ID_FARBWERK360 0xf010
#define USB_PRODUCT_ID_OCTO 0xf011
#define USB_PRODUCT_ID_HIGHFLOWNEXT 0xf012
+#define USB_PRODUCT_ID_AQUASTREAMULT 0xf00b
+#define USB_PRODUCT_ID_POWERADJUST3 0xf0bd
-enum kinds { d5next, farbwerk, farbwerk360, octo, quadro, highflownext };
+enum kinds {
+ d5next, farbwerk, farbwerk360, octo, quadro,
+ highflownext, aquaero, poweradjust3, aquastreamult
+};
static const char *const aqc_device_names[] = {
[d5next] = "d5next",
@@ -36,16 +43,17 @@ static const char *const aqc_device_names[] = {
[farbwerk360] = "farbwerk360",
[octo] = "octo",
[quadro] = "quadro",
- [highflownext] = "highflownext"
+ [highflownext] = "highflownext",
+ [aquaero] = "aquaero",
+ [aquastreamult] = "aquastreamultimate",
+ [poweradjust3] = "poweradjust3"
};
#define DRIVER_NAME "aquacomputer_d5next"
#define STATUS_REPORT_ID 0x01
#define STATUS_UPDATE_INTERVAL (2 * HZ) /* In seconds */
-#define SERIAL_FIRST_PART 3
-#define SERIAL_SECOND_PART 5
-#define FIRMWARE_VERSION 13
+#define SERIAL_PART_OFFSET 2
#define CTRL_REPORT_ID 0x03
@@ -59,8 +67,14 @@ static u8 secondary_ctrl_report[] = {
0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x34, 0xC6
};
-/* Sensor sizes and offsets for all Aquacomputer devices */
-#define AQC_TEMP_SENSOR_SIZE 0x02
+/* Report IDs for legacy devices */
+#define POWERADJUST3_STATUS_REPORT_ID 0x03
+
+/* Info, sensor sizes and offsets for most Aquacomputer devices */
+#define AQC_SERIAL_START 0x3
+#define AQC_FIRMWARE_VERSION 0xD
+
+#define AQC_SENSOR_SIZE 0x02
#define AQC_TEMP_SENSOR_DISCONNECTED 0x7FFF
#define AQC_FAN_PERCENT_OFFSET 0x00
#define AQC_FAN_VOLTAGE_OFFSET 0x02
@@ -68,6 +82,26 @@ static u8 secondary_ctrl_report[] = {
#define AQC_FAN_POWER_OFFSET 0x06
#define AQC_FAN_SPEED_OFFSET 0x08
+/* Specs of the Aquaero fan controllers */
+#define AQUAERO_SERIAL_START 0x07
+#define AQUAERO_FIRMWARE_VERSION 0x0B
+#define AQUAERO_NUM_FANS 4
+#define AQUAERO_NUM_SENSORS 8
+#define AQUAERO_NUM_VIRTUAL_SENSORS 8
+#define AQUAERO_NUM_CALC_VIRTUAL_SENSORS 4
+#define AQUAERO_NUM_FLOW_SENSORS 2
+
+/* Sensor report offsets for Aquaero fan controllers */
+#define AQUAERO_SENSOR_START 0x65
+#define AQUAERO_VIRTUAL_SENSOR_START 0x85
+#define AQUAERO_CALC_VIRTUAL_SENSOR_START 0x95
+#define AQUAERO_FLOW_SENSORS_START 0xF9
+#define AQUAERO_FAN_VOLTAGE_OFFSET 0x04
+#define AQUAERO_FAN_CURRENT_OFFSET 0x06
+#define AQUAERO_FAN_POWER_OFFSET 0x08
+#define AQUAERO_FAN_SPEED_OFFSET 0x00
+static u16 aquaero_sensor_fan_offsets[] = { 0x167, 0x173, 0x17f, 0x18B };
+
/* Specs of the D5 Next pump */
#define D5NEXT_NUM_FANS 2
#define D5NEXT_NUM_SENSORS 1
@@ -82,12 +116,32 @@ static u8 secondary_ctrl_report[] = {
#define D5NEXT_5V_VOLTAGE 0x39
#define D5NEXT_12V_VOLTAGE 0x37
#define D5NEXT_VIRTUAL_SENSORS_START 0x3f
-static u8 d5next_sensor_fan_offsets[] = { D5NEXT_PUMP_OFFSET, D5NEXT_FAN_OFFSET };
+static u16 d5next_sensor_fan_offsets[] = { D5NEXT_PUMP_OFFSET, D5NEXT_FAN_OFFSET };
/* Control report offsets for the D5 Next pump */
#define D5NEXT_TEMP_CTRL_OFFSET 0x2D /* Temperature sensor offsets location */
static u16 d5next_ctrl_fan_offsets[] = { 0x97, 0x42 }; /* Pump and fan speed (from 0-100%) */
+/* Specs of the Aquastream Ultimate pump */
+/* Pump does not follow the standard structure, so only consider the fan */
+#define AQUASTREAMULT_NUM_FANS 1
+#define AQUASTREAMULT_NUM_SENSORS 2
+
+/* Sensor report offsets for the Aquastream Ultimate pump */
+#define AQUASTREAMULT_SENSOR_START 0x2D
+#define AQUASTREAMULT_PUMP_OFFSET 0x51
+#define AQUASTREAMULT_PUMP_VOLTAGE 0x3D
+#define AQUASTREAMULT_PUMP_CURRENT 0x53
+#define AQUASTREAMULT_PUMP_POWER 0x55
+#define AQUASTREAMULT_FAN_OFFSET 0x41
+#define AQUASTREAMULT_PRESSURE_OFFSET 0x57
+#define AQUASTREAMULT_FLOW_SENSOR_OFFSET 0x37
+#define AQUASTREAMULT_FAN_VOLTAGE_OFFSET 0x02
+#define AQUASTREAMULT_FAN_CURRENT_OFFSET 0x00
+#define AQUASTREAMULT_FAN_POWER_OFFSET 0x04
+#define AQUASTREAMULT_FAN_SPEED_OFFSET 0x06
+static u16 aquastreamult_sensor_fan_offsets[] = { AQUASTREAMULT_FAN_OFFSET };
+
/* Spec and sensor report offset for the Farbwerk RGB controller */
#define FARBWERK_NUM_SENSORS 4
#define FARBWERK_SENSOR_START 0x2f
@@ -114,7 +168,7 @@ static u16 d5next_ctrl_fan_offsets[] = { 0x97, 0x42 }; /* Pump and fan speed (fr
#define OCTO_POWER_CYCLES 0x18
#define OCTO_SENSOR_START 0x3D
#define OCTO_VIRTUAL_SENSORS_START 0x45
-static u8 octo_sensor_fan_offsets[] = { 0x7D, 0x8A, 0x97, 0xA4, 0xB1, 0xBE, 0xCB, 0xD8 };
+static u16 octo_sensor_fan_offsets[] = { 0x7D, 0x8A, 0x97, 0xA4, 0xB1, 0xBE, 0xCB, 0xD8 };
/* Control report offsets for the Octo */
#define OCTO_TEMP_CTRL_OFFSET 0xA
@@ -125,6 +179,7 @@ static u16 octo_ctrl_fan_offsets[] = { 0x5B, 0xB0, 0x105, 0x15A, 0x1AF, 0x204, 0
#define QUADRO_NUM_FANS 4
#define QUADRO_NUM_SENSORS 4
#define QUADRO_NUM_VIRTUAL_SENSORS 16
+#define QUADRO_NUM_FLOW_SENSORS 1
#define QUADRO_CTRL_REPORT_SIZE 0x3c1
/* Sensor report offsets for the Quadro */
@@ -132,7 +187,7 @@ static u16 octo_ctrl_fan_offsets[] = { 0x5B, 0xB0, 0x105, 0x15A, 0x1AF, 0x204, 0
#define QUADRO_SENSOR_START 0x34
#define QUADRO_VIRTUAL_SENSORS_START 0x3c
#define QUADRO_FLOW_SENSOR_OFFSET 0x6e
-static u8 quadro_sensor_fan_offsets[] = { 0x70, 0x7D, 0x8A, 0x97 };
+static u16 quadro_sensor_fan_offsets[] = { 0x70, 0x7D, 0x8A, 0x97 };
/* Control report offsets for the Quadro */
#define QUADRO_TEMP_CTRL_OFFSET 0xA
@@ -141,6 +196,7 @@ static u16 quadro_ctrl_fan_offsets[] = { 0x37, 0x8c, 0xe1, 0x136 }; /* Fan speed
/* Specs of High Flow Next flow sensor */
#define HIGHFLOWNEXT_NUM_SENSORS 2
+#define HIGHFLOWNEXT_NUM_FLOW_SENSORS 1
/* Sensor report offsets for the High Flow Next */
#define HIGHFLOWNEXT_SENSOR_START 85
@@ -151,6 +207,13 @@ static u16 quadro_ctrl_fan_offsets[] = { 0x37, 0x8c, 0xe1, 0x136 }; /* Fan speed
#define HIGHFLOWNEXT_5V_VOLTAGE 97
#define HIGHFLOWNEXT_5V_VOLTAGE_USB 99
+/* Specs of the Poweradjust 3 */
+#define POWERADJUST3_NUM_SENSORS 1
+#define POWERADJUST3_SENSOR_REPORT_SIZE 0x32
+
+/* Sensor report offsets for the Poweradjust 3 */
+#define POWERADJUST3_SENSOR_START 0x03
+
/* Labels for D5 Next */
static const char *const label_d5next_temp[] = {
"Coolant temp"
@@ -178,12 +241,16 @@ static const char *const label_d5next_current[] = {
"Fan current"
};
-/* Labels for Farbwerk, Farbwerk 360 and Octo and Quadro temperature sensors */
+/* Labels for Aquaero, Farbwerk, Farbwerk 360 and Octo and Quadro temperature sensors */
static const char *const label_temp_sensors[] = {
"Sensor 1",
"Sensor 2",
"Sensor 3",
- "Sensor 4"
+ "Sensor 4",
+ "Sensor 5",
+ "Sensor 6",
+ "Sensor 7",
+ "Sensor 8"
};
static const char *const label_virtual_temp_sensors[] = {
@@ -205,6 +272,13 @@ static const char *const label_virtual_temp_sensors[] = {
"Virtual sensor 16",
};
+static const char *const label_aquaero_calc_temp_sensors[] = {
+ "Calc. virtual sensor 1",
+ "Calc. virtual sensor 2",
+ "Calc. virtual sensor 3",
+ "Calc. virtual sensor 4"
+};
+
/* Labels for Octo and Quadro (except speed) */
static const char *const label_fan_speed[] = {
"Fan 1 speed",
@@ -259,6 +333,16 @@ static const char *const label_quadro_speeds[] = {
"Flow speed [dL/h]"
};
+/* Labels for Aquaero fan speeds */
+static const char *const label_aquaero_speeds[] = {
+ "Fan 1 speed",
+ "Fan 2 speed",
+ "Fan 3 speed",
+ "Fan 4 speed",
+ "Flow sensor 1 [dL/h]",
+ "Flow sensor 2 [dL/h]"
+};
+
/* Labels for High Flow Next */
static const char *const label_highflownext_temp_sensors[] = {
"Coolant temp",
@@ -280,6 +364,70 @@ static const char *const label_highflownext_voltage[] = {
"+5V USB voltage"
};
+/* Labels for Aquastream Ultimate */
+static const char *const label_aquastreamult_temp[] = {
+ "Coolant temp",
+ "External temp"
+};
+
+static const char *const label_aquastreamult_speeds[] = {
+ "Fan speed",
+ "Pump speed",
+ "Pressure [mbar]",
+ "Flow speed [dL/h]"
+};
+
+static const char *const label_aquastreamult_power[] = {
+ "Fan power",
+ "Pump power"
+};
+
+static const char *const label_aquastreamult_voltages[] = {
+ "Fan voltage",
+ "Pump voltage"
+};
+
+static const char *const label_aquastreamult_current[] = {
+ "Fan current",
+ "Pump current"
+};
+
+/* Labels for Poweradjust 3 */
+static const char *const label_poweradjust3_temp_sensors[] = {
+ "External sensor"
+};
+
+struct aqc_fan_structure_offsets {
+ u8 voltage;
+ u8 curr;
+ u8 power;
+ u8 speed;
+};
+
+/* Fan structure offsets for Aquaero */
+static struct aqc_fan_structure_offsets aqc_aquaero_fan_structure = {
+ .voltage = AQUAERO_FAN_VOLTAGE_OFFSET,
+ .curr = AQUAERO_FAN_CURRENT_OFFSET,
+ .power = AQUAERO_FAN_POWER_OFFSET,
+ .speed = AQUAERO_FAN_SPEED_OFFSET
+};
+
+/* Fan structure offsets for Aquastream Ultimate */
+static struct aqc_fan_structure_offsets aqc_aquastreamult_fan_structure = {
+ .voltage = AQUASTREAMULT_FAN_VOLTAGE_OFFSET,
+ .curr = AQUASTREAMULT_FAN_CURRENT_OFFSET,
+ .power = AQUASTREAMULT_FAN_POWER_OFFSET,
+ .speed = AQUASTREAMULT_FAN_SPEED_OFFSET
+};
+
+/* Fan structure offsets for all devices except those above */
+static struct aqc_fan_structure_offsets aqc_general_fan_structure = {
+ .voltage = AQC_FAN_VOLTAGE_OFFSET,
+ .curr = AQC_FAN_CURRENT_OFFSET,
+ .power = AQC_FAN_POWER_OFFSET,
+ .speed = AQC_FAN_SPEED_OFFSET
+};
+
struct aqc_data {
struct hid_device *hdev;
struct device *hwmon_dev;
@@ -288,6 +436,8 @@ struct aqc_data {
enum kinds kind;
const char *name;
+ int status_report_id; /* Used for legacy devices, report is stored in buffer */
+
int buffer_size;
u8 *buffer;
int checksum_start;
@@ -295,26 +445,32 @@ struct aqc_data {
int checksum_offset;
int num_fans;
- u8 *fan_sensor_offsets;
+ u16 *fan_sensor_offsets;
u16 *fan_ctrl_offsets;
int num_temp_sensors;
int temp_sensor_start_offset;
int num_virtual_temp_sensors;
int virtual_temp_sensor_start_offset;
+ int num_calc_virt_temp_sensors;
+ int calc_virt_temp_sensor_start_offset;
u16 temp_ctrl_offset;
u16 power_cycle_count_offset;
- u8 flow_sensor_offset;
+ int num_flow_sensors;
+ u8 flow_sensors_start_offset;
u8 flow_pulses_ctrl_offset;
+ struct aqc_fan_structure_offsets *fan_structure;
/* General info, same across all devices */
+ u8 serial_number_start_offset;
u32 serial_number[2];
+ u8 firmware_version_offset;
u16 firmware_version;
/* How many times the device was powered on, if available */
u32 power_cycles;
/* Sensor values */
- s32 temp_input[20]; /* Max 4 physical and 16 virtual */
+ s32 temp_input[20]; /* Max 4 physical and 16 virtual or 8 physical and 12 virtual */
u16 speed_input[8];
u32 power_input[8];
u16 voltage_input[8];
@@ -323,6 +479,7 @@ struct aqc_data {
/* Label values */
const char *const *temp_label;
const char *const *virtual_temp_label;
+ const char *const *calc_virt_temp_label; /* For Aquaero */
const char *const *speed_label;
const char *const *power_label;
const char *const *voltage_label;
@@ -443,7 +600,9 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3
}
}
- if (channel < priv->num_temp_sensors + priv->num_virtual_temp_sensors)
+ if (channel <
+ priv->num_temp_sensors + priv->num_virtual_temp_sensors +
+ priv->num_calc_virt_temp_sensors)
switch (attr) {
case hwmon_temp_label:
case hwmon_temp_input:
@@ -467,6 +626,14 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3
case hwmon_fan_input:
case hwmon_fan_label:
switch (priv->kind) {
+ case aquastreamult:
+ /*
+ * Special case to support pump RPM, fan RPM,
+ * pressure and flow sensor
+ */
+ if (channel < 4)
+ return 0444;
+ break;
case highflownext:
/* Special case to support flow sensor, water quality
* and conductivity
@@ -474,9 +641,10 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3
if (channel < 3)
return 0444;
break;
+ case aquaero:
case quadro:
- /* Special case to support flow sensor */
- if (channel < priv->num_fans + 1)
+ /* Special case to support flow sensors */
+ if (channel < priv->num_fans + priv->num_flow_sensors)
return 0444;
break;
default:
@@ -496,6 +664,11 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3
break;
case hwmon_power:
switch (priv->kind) {
+ case aquastreamult:
+ /* Special case to support pump and fan power */
+ if (channel < 2)
+ return 0444;
+ break;
case highflownext:
/* Special case to support one power sensor */
if (channel == 0)
@@ -508,8 +681,17 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3
}
break;
case hwmon_curr:
- if (channel < priv->num_fans)
- return 0444;
+ switch (priv->kind) {
+ case aquastreamult:
+ /* Special case to support pump and fan current */
+ if (channel < 2)
+ return 0444;
+ break;
+ default:
+ if (channel < priv->num_fans)
+ return 0444;
+ break;
+ }
break;
case hwmon_in:
switch (priv->kind) {
@@ -518,6 +700,7 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3
if (channel < priv->num_fans + 2)
return 0444;
break;
+ case aquastreamult:
case highflownext:
/* Special case to support two voltage sensors */
if (channel < 2)
@@ -536,14 +719,49 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3
return 0;
}
+/* Read device sensors by manually requesting the sensor report (legacy way) */
+static int aqc_legacy_read(struct aqc_data *priv)
+{
+ int ret, i, sensor_value;
+
+ mutex_lock(&priv->mutex);
+
+ memset(priv->buffer, 0x00, priv->buffer_size);
+ ret = hid_hw_raw_request(priv->hdev, priv->status_report_id, priv->buffer,
+ priv->buffer_size, HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
+ if (ret < 0)
+ goto unlock_and_return;
+
+ /* Temperature sensor readings */
+ for (i = 0; i < priv->num_temp_sensors; i++) {
+ sensor_value = get_unaligned_le16(priv->buffer + priv->temp_sensor_start_offset +
+ i * AQC_SENSOR_SIZE);
+ priv->temp_input[i] = sensor_value * 10;
+ }
+
+ priv->updated = jiffies;
+
+unlock_and_return:
+ mutex_unlock(&priv->mutex);
+ return ret;
+}
+
static int aqc_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
int channel, long *val)
{
int ret;
struct aqc_data *priv = dev_get_drvdata(dev);
- if (time_after(jiffies, priv->updated + STATUS_UPDATE_INTERVAL))
- return -ENODATA;
+ if (time_after(jiffies, priv->updated + STATUS_UPDATE_INTERVAL)) {
+ if (priv->status_report_id != 0) {
+ /* Legacy devices require manual reads */
+ ret = aqc_legacy_read(priv);
+ if (ret < 0)
+ return -ENODATA;
+ } else {
+ return -ENODATA;
+ }
+ }
switch (type) {
case hwmon_temp:
@@ -557,7 +775,7 @@ static int aqc_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
case hwmon_temp_offset:
ret =
aqc_get_ctrl_val(priv, priv->temp_ctrl_offset +
- channel * AQC_TEMP_SENSOR_SIZE, val);
+ channel * AQC_SENSOR_SIZE, val);
if (ret < 0)
return ret;
@@ -611,12 +829,20 @@ static int aqc_read_string(struct device *dev, enum hwmon_sensor_types type, u32
{
struct aqc_data *priv = dev_get_drvdata(dev);
+ /* Number of sensors that are not calculated */
+ int num_non_calc_sensors = priv->num_temp_sensors + priv->num_virtual_temp_sensors;
+
switch (type) {
case hwmon_temp:
- if (channel < priv->num_temp_sensors)
+ if (channel < priv->num_temp_sensors) {
*str = priv->temp_label[channel];
- else
- *str = priv->virtual_temp_label[channel - priv->num_temp_sensors];
+ } else {
+ if (priv->kind == aquaero && channel >= num_non_calc_sensors)
+ *str =
+ priv->calc_virt_temp_label[channel - num_non_calc_sensors];
+ else
+ *str = priv->virtual_temp_label[channel - priv->num_temp_sensors];
+ }
break;
case hwmon_fan:
*str = priv->speed_label[channel];
@@ -651,7 +877,7 @@ static int aqc_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
val = clamp_val(val, -15000, 15000) / 10;
ret =
aqc_set_ctrl_val(priv, priv->temp_ctrl_offset +
- channel * AQC_TEMP_SENSOR_SIZE, val);
+ channel * AQC_SENSOR_SIZE, val);
if (ret < 0)
return ret;
break;
@@ -789,15 +1015,16 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8
priv = hid_get_drvdata(hdev);
/* Info provided with every report */
- priv->serial_number[0] = get_unaligned_be16(data + SERIAL_FIRST_PART);
- priv->serial_number[1] = get_unaligned_be16(data + SERIAL_SECOND_PART);
- priv->firmware_version = get_unaligned_be16(data + FIRMWARE_VERSION);
+ priv->serial_number[0] = get_unaligned_be16(data + priv->serial_number_start_offset);
+ priv->serial_number[1] = get_unaligned_be16(data + priv->serial_number_start_offset +
+ SERIAL_PART_OFFSET);
+ priv->firmware_version = get_unaligned_be16(data + priv->firmware_version_offset);
/* Physical temperature sensor readings */
for (i = 0; i < priv->num_temp_sensors; i++) {
sensor_value = get_unaligned_be16(data +
priv->temp_sensor_start_offset +
- i * AQC_TEMP_SENSOR_SIZE);
+ i * AQC_SENSOR_SIZE);
if (sensor_value == AQC_TEMP_SENSOR_DISCONNECTED)
priv->temp_input[i] = -ENODATA;
else
@@ -808,7 +1035,7 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8
for (j = 0; j < priv->num_virtual_temp_sensors; j++) {
sensor_value = get_unaligned_be16(data +
priv->virtual_temp_sensor_start_offset +
- j * AQC_TEMP_SENSOR_SIZE);
+ j * AQC_SENSOR_SIZE);
if (sensor_value == AQC_TEMP_SENSOR_DISCONNECTED)
priv->temp_input[i] = -ENODATA;
else
@@ -819,15 +1046,24 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8
/* Fan speed and related readings */
for (i = 0; i < priv->num_fans; i++) {
priv->speed_input[i] =
- get_unaligned_be16(data + priv->fan_sensor_offsets[i] + AQC_FAN_SPEED_OFFSET);
+ get_unaligned_be16(data + priv->fan_sensor_offsets[i] +
+ priv->fan_structure->speed);
priv->power_input[i] =
get_unaligned_be16(data + priv->fan_sensor_offsets[i] +
- AQC_FAN_POWER_OFFSET) * 10000;
+ priv->fan_structure->power) * 10000;
priv->voltage_input[i] =
get_unaligned_be16(data + priv->fan_sensor_offsets[i] +
- AQC_FAN_VOLTAGE_OFFSET) * 10;
+ priv->fan_structure->voltage) * 10;
priv->current_input[i] =
- get_unaligned_be16(data + priv->fan_sensor_offsets[i] + AQC_FAN_CURRENT_OFFSET);
+ get_unaligned_be16(data + priv->fan_sensor_offsets[i] +
+ priv->fan_structure->curr);
+ }
+
+ /* Flow sensor readings */
+ for (j = 0; j < priv->num_flow_sensors; j++) {
+ priv->speed_input[i] = get_unaligned_be16(data + priv->flow_sensors_start_offset +
+ j * AQC_SENSOR_SIZE);
+ i++;
}
if (priv->power_cycle_count_offset != 0)
@@ -835,13 +1071,35 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8
/* Special-case sensor readings */
switch (priv->kind) {
+ case aquaero:
+ /* Read calculated virtual temp sensors */
+ i = priv->num_temp_sensors + priv->num_virtual_temp_sensors;
+ for (j = 0; j < priv->num_calc_virt_temp_sensors; j++) {
+ sensor_value = get_unaligned_be16(data +
+ priv->calc_virt_temp_sensor_start_offset +
+ j * AQC_SENSOR_SIZE);
+ if (sensor_value == AQC_TEMP_SENSOR_DISCONNECTED)
+ priv->temp_input[i] = -ENODATA;
+ else
+ priv->temp_input[i] = sensor_value * 10;
+ i++;
+ }
+ break;
+ case aquastreamult:
+ priv->speed_input[1] = get_unaligned_be16(data + AQUASTREAMULT_PUMP_OFFSET);
+ priv->speed_input[2] = get_unaligned_be16(data + AQUASTREAMULT_PRESSURE_OFFSET);
+ priv->speed_input[3] = get_unaligned_be16(data + AQUASTREAMULT_FLOW_SENSOR_OFFSET);
+
+ priv->power_input[1] = get_unaligned_be16(data + AQUASTREAMULT_PUMP_POWER) * 10000;
+
+ priv->voltage_input[1] = get_unaligned_be16(data + AQUASTREAMULT_PUMP_VOLTAGE) * 10;
+
+ priv->current_input[1] = get_unaligned_be16(data + AQUASTREAMULT_PUMP_CURRENT);
+ break;
case d5next:
priv->voltage_input[2] = get_unaligned_be16(data + D5NEXT_5V_VOLTAGE) * 10;
priv->voltage_input[3] = get_unaligned_be16(data + D5NEXT_12V_VOLTAGE) * 10;
break;
- case quadro:
- priv->speed_input[4] = get_unaligned_be16(data + priv->flow_sensor_offset);
- break;
case highflownext:
/* If external temp sensor is not connected, its power reading is also N/A */
if (priv->temp_input[1] == -ENODATA)
@@ -854,7 +1112,6 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8
priv->voltage_input[1] =
get_unaligned_be16(data + HIGHFLOWNEXT_5V_VOLTAGE_USB) * 10;
- priv->speed_input[0] = get_unaligned_be16(data + HIGHFLOWNEXT_FLOW);
priv->speed_input[1] = get_unaligned_be16(data + HIGHFLOWNEXT_WATER_QUALITY);
priv->speed_input[2] = get_unaligned_be16(data + HIGHFLOWNEXT_CONDUCTIVITY);
break;
@@ -907,9 +1164,13 @@ static void aqc_debugfs_init(struct aqc_data *priv)
dev_name(&priv->hdev->dev));
priv->debugfs = debugfs_create_dir(name, NULL);
- debugfs_create_file("serial_number", 0444, priv->debugfs, priv, &serial_number_fops);
- debugfs_create_file("firmware_version", 0444, priv->debugfs, priv, &firmware_version_fops);
+ if (priv->serial_number_start_offset != 0)
+ debugfs_create_file("serial_number", 0444, priv->debugfs, priv,
+ &serial_number_fops);
+ if (priv->firmware_version_offset != 0)
+ debugfs_create_file("firmware_version", 0444, priv->debugfs, priv,
+ &firmware_version_fops);
if (priv->power_cycle_count_offset != 0)
debugfs_create_file("power_cycles", 0444, priv->debugfs, priv, &power_cycles_fops);
}
@@ -949,6 +1210,45 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
goto fail_and_stop;
switch (hdev->product) {
+ case USB_PRODUCT_ID_AQUAERO:
+ /*
+ * Aquaero presents itself as three HID devices under the same product ID:
+ * "aquaero keyboard/mouse", "aquaero System Control" and "aquaero Device",
+ * which is the one we want to communicate with. Unlike most other Aquacomputer
+ * devices, Aquaero does not return meaningful data when explicitly requested
+ * using GET_FEATURE_REPORT.
+ *
+ * The difference between "aquaero Device" and the other two is in the collections
+ * they present. The two other devices have the type of the second element in
+ * their respective collections set to 1, while the real device has it set to 0.
+ */
+ if (hdev->collection[1].type != 0) {
+ ret = -ENODEV;
+ goto fail_and_close;
+ }
+
+ priv->kind = aquaero;
+
+ priv->num_fans = AQUAERO_NUM_FANS;
+ priv->fan_sensor_offsets = aquaero_sensor_fan_offsets;
+
+ priv->num_temp_sensors = AQUAERO_NUM_SENSORS;
+ priv->temp_sensor_start_offset = AQUAERO_SENSOR_START;
+ priv->num_virtual_temp_sensors = AQUAERO_NUM_VIRTUAL_SENSORS;
+ priv->virtual_temp_sensor_start_offset = AQUAERO_VIRTUAL_SENSOR_START;
+ priv->num_calc_virt_temp_sensors = AQUAERO_NUM_CALC_VIRTUAL_SENSORS;
+ priv->calc_virt_temp_sensor_start_offset = AQUAERO_CALC_VIRTUAL_SENSOR_START;
+ priv->num_flow_sensors = AQUAERO_NUM_FLOW_SENSORS;
+ priv->flow_sensors_start_offset = AQUAERO_FLOW_SENSORS_START;
+
+ priv->temp_label = label_temp_sensors;
+ priv->virtual_temp_label = label_virtual_temp_sensors;
+ priv->calc_virt_temp_label = label_aquaero_calc_temp_sensors;
+ priv->speed_label = label_aquaero_speeds;
+ priv->power_label = label_fan_power;
+ priv->voltage_label = label_fan_voltage;
+ priv->current_label = label_fan_current;
+ break;
case USB_PRODUCT_ID_D5NEXT:
priv->kind = d5next;
@@ -1034,11 +1334,13 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
priv->temp_sensor_start_offset = QUADRO_SENSOR_START;
priv->num_virtual_temp_sensors = QUADRO_NUM_VIRTUAL_SENSORS;
priv->virtual_temp_sensor_start_offset = QUADRO_VIRTUAL_SENSORS_START;
+ priv->num_flow_sensors = QUADRO_NUM_FLOW_SENSORS;
+ priv->flow_sensors_start_offset = QUADRO_FLOW_SENSOR_OFFSET;
+
priv->temp_ctrl_offset = QUADRO_TEMP_CTRL_OFFSET;
priv->buffer_size = QUADRO_CTRL_REPORT_SIZE;
- priv->flow_sensor_offset = QUADRO_FLOW_SENSOR_OFFSET;
priv->flow_pulses_ctrl_offset = QUADRO_FLOW_PULSES_CTRL_OFFSET;
priv->power_cycle_count_offset = QUADRO_POWER_CYCLES;
@@ -1056,6 +1358,8 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
priv->num_temp_sensors = HIGHFLOWNEXT_NUM_SENSORS;
priv->temp_sensor_start_offset = HIGHFLOWNEXT_SENSOR_START;
+ priv->num_flow_sensors = HIGHFLOWNEXT_NUM_FLOW_SENSORS;
+ priv->flow_sensors_start_offset = HIGHFLOWNEXT_FLOW;
priv->power_cycle_count_offset = QUADRO_POWER_CYCLES;
@@ -1064,10 +1368,57 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
priv->power_label = label_highflownext_power;
priv->voltage_label = label_highflownext_voltage;
break;
+ case USB_PRODUCT_ID_AQUASTREAMULT:
+ priv->kind = aquastreamult;
+
+ priv->num_fans = AQUASTREAMULT_NUM_FANS;
+ priv->fan_sensor_offsets = aquastreamult_sensor_fan_offsets;
+
+ priv->num_temp_sensors = AQUASTREAMULT_NUM_SENSORS;
+ priv->temp_sensor_start_offset = AQUASTREAMULT_SENSOR_START;
+
+ priv->temp_label = label_aquastreamult_temp;
+ priv->speed_label = label_aquastreamult_speeds;
+ priv->power_label = label_aquastreamult_power;
+ priv->voltage_label = label_aquastreamult_voltages;
+ priv->current_label = label_aquastreamult_current;
+ break;
+ case USB_PRODUCT_ID_POWERADJUST3:
+ priv->kind = poweradjust3;
+
+ priv->num_fans = 0;
+
+ priv->num_temp_sensors = POWERADJUST3_NUM_SENSORS;
+ priv->temp_sensor_start_offset = POWERADJUST3_SENSOR_START;
+ priv->buffer_size = POWERADJUST3_SENSOR_REPORT_SIZE;
+
+ priv->temp_label = label_poweradjust3_temp_sensors;
+ break;
default:
break;
}
+ switch (priv->kind) {
+ case aquaero:
+ priv->serial_number_start_offset = AQUAERO_SERIAL_START;
+ priv->firmware_version_offset = AQUAERO_FIRMWARE_VERSION;
+
+ priv->fan_structure = &aqc_aquaero_fan_structure;
+ break;
+ case poweradjust3:
+ priv->status_report_id = POWERADJUST3_STATUS_REPORT_ID;
+ break;
+ default:
+ priv->serial_number_start_offset = AQC_SERIAL_START;
+ priv->firmware_version_offset = AQC_FIRMWARE_VERSION;
+
+ if (priv->kind == aquastreamult)
+ priv->fan_structure = &aqc_aquastreamult_fan_structure;
+ else
+ priv->fan_structure = &aqc_general_fan_structure;
+ break;
+ }
+
if (priv->buffer_size != 0) {
priv->checksum_start = 0x01;
priv->checksum_length = priv->buffer_size - 3;
@@ -1115,12 +1466,15 @@ static void aqc_remove(struct hid_device *hdev)
}
static const struct hid_device_id aqc_table[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_AQUAERO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_D5NEXT) },
{ HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_FARBWERK) },
{ HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_FARBWERK360) },
{ HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_OCTO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_QUADRO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_HIGHFLOWNEXT) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_AQUASTREAMULT) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_POWERADJUST3) },
{ }
};
diff --git a/drivers/hwmon/asus-ec-sensors.c b/drivers/hwmon/asus-ec-sensors.c
index a901e4e33d81..2768b7511684 100644
--- a/drivers/hwmon/asus-ec-sensors.c
+++ b/drivers/hwmon/asus-ec-sensors.c
@@ -299,6 +299,7 @@ static const struct ec_board_info board_info_pro_art_x570_creator_wifi = {
.sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_VRM |
SENSOR_TEMP_T_SENSOR | SENSOR_FAN_CPU_OPT |
SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE,
+ .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
.family = family_amd_500_series,
};
@@ -466,6 +467,8 @@ static const struct dmi_system_id dmi_table[] = {
&board_info_strix_z690_a_gaming_wifi_d4),
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG ZENITH II EXTREME",
&board_info_zenith_ii_extreme),
+ DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG ZENITH II EXTREME ALPHA",
+ &board_info_zenith_ii_extreme),
{},
};
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index ca7a9b373bbd..30d77f451937 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -27,6 +27,7 @@
#include <asm/msr.h>
#include <asm/processor.h>
#include <asm/cpu_device_id.h>
+#include <linux/sched/isolation.h>
#define DRVNAME "coretemp"
@@ -502,6 +503,9 @@ static int create_core_data(struct platform_device *pdev, unsigned int cpu,
u32 eax, edx;
int err, index, attr_no;
+ if (!housekeeping_cpu(cpu, HK_TYPE_MISC))
+ return 0;
+
/*
* Find attr number for sysfs:
* We map the attr number to core id of the CPU
@@ -588,66 +592,49 @@ static void coretemp_remove_core(struct platform_data *pdata, int indx)
ida_free(&pdata->ida, indx - BASE_SYSFS_ATTR_NO);
}
-static int coretemp_probe(struct platform_device *pdev)
+static int coretemp_device_add(int zoneid)
{
- struct device *dev = &pdev->dev;
+ struct platform_device *pdev;
struct platform_data *pdata;
+ int err;
/* Initialize the per-zone data structures */
- pdata = devm_kzalloc(dev, sizeof(struct platform_data), GFP_KERNEL);
+ pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
- pdata->pkg_id = pdev->id;
+ pdata->pkg_id = zoneid;
ida_init(&pdata->ida);
- platform_set_drvdata(pdev, pdata);
-
- pdata->hwmon_dev = devm_hwmon_device_register_with_groups(dev, DRVNAME,
- pdata, NULL);
- return PTR_ERR_OR_ZERO(pdata->hwmon_dev);
-}
-static int coretemp_remove(struct platform_device *pdev)
-{
- struct platform_data *pdata = platform_get_drvdata(pdev);
- int i;
+ pdev = platform_device_alloc(DRVNAME, zoneid);
+ if (!pdev) {
+ err = -ENOMEM;
+ goto err_free_pdata;
+ }
- for (i = MAX_CORE_DATA - 1; i >= 0; --i)
- if (pdata->core_data[i])
- coretemp_remove_core(pdata, i);
+ err = platform_device_add(pdev);
+ if (err)
+ goto err_put_dev;
- ida_destroy(&pdata->ida);
+ platform_set_drvdata(pdev, pdata);
+ zone_devices[zoneid] = pdev;
return 0;
-}
-static struct platform_driver coretemp_driver = {
- .driver = {
- .name = DRVNAME,
- },
- .probe = coretemp_probe,
- .remove = coretemp_remove,
-};
+err_put_dev:
+ platform_device_put(pdev);
+err_free_pdata:
+ kfree(pdata);
+ return err;
+}
-static struct platform_device *coretemp_device_add(unsigned int cpu)
+static void coretemp_device_remove(int zoneid)
{
- int err, zoneid = topology_logical_die_id(cpu);
- struct platform_device *pdev;
-
- if (zoneid < 0)
- return ERR_PTR(-ENOMEM);
-
- pdev = platform_device_alloc(DRVNAME, zoneid);
- if (!pdev)
- return ERR_PTR(-ENOMEM);
-
- err = platform_device_add(pdev);
- if (err) {
- platform_device_put(pdev);
- return ERR_PTR(err);
- }
+ struct platform_device *pdev = zone_devices[zoneid];
+ struct platform_data *pdata = platform_get_drvdata(pdev);
- zone_devices[zoneid] = pdev;
- return pdev;
+ ida_destroy(&pdata->ida);
+ kfree(pdata);
+ platform_device_unregister(pdev);
}
static int coretemp_cpu_online(unsigned int cpu)
@@ -671,7 +658,10 @@ static int coretemp_cpu_online(unsigned int cpu)
if (!cpu_has(c, X86_FEATURE_DTHERM))
return -ENODEV;
- if (!pdev) {
+ pdata = platform_get_drvdata(pdev);
+ if (!pdata->hwmon_dev) {
+ struct device *hwmon;
+
/* Check the microcode version of the CPU */
if (chk_ucode_version(cpu))
return -EINVAL;
@@ -682,9 +672,11 @@ static int coretemp_cpu_online(unsigned int cpu)
* online. So, initialize per-pkg data structures and
* then bring this core online.
*/
- pdev = coretemp_device_add(cpu);
- if (IS_ERR(pdev))
- return PTR_ERR(pdev);
+ hwmon = hwmon_device_register_with_groups(&pdev->dev, DRVNAME,
+ pdata, NULL);
+ if (IS_ERR(hwmon))
+ return PTR_ERR(hwmon);
+ pdata->hwmon_dev = hwmon;
/*
* Check whether pkgtemp support is available.
@@ -694,7 +686,6 @@ static int coretemp_cpu_online(unsigned int cpu)
coretemp_add_core(pdev, cpu, 1);
}
- pdata = platform_get_drvdata(pdev);
/*
* Check whether a thread sibling is already online. If not add the
* interface for this CPU core.
@@ -713,18 +704,14 @@ static int coretemp_cpu_offline(unsigned int cpu)
struct temp_data *tdata;
int i, indx = -1, target;
- /*
- * Don't execute this on suspend as the device remove locks
- * up the machine.
- */
+ /* No need to tear down any interfaces for suspend */
if (cpuhp_tasks_frozen)
return 0;
/* If the physical CPU device does not exist, just return */
- if (!pdev)
- return 0;
-
pd = platform_get_drvdata(pdev);
+ if (!pd->hwmon_dev)
+ return 0;
for (i = 0; i < NUM_REAL_CORES; i++) {
if (pd->cpu_map[i] == topology_core_id(cpu)) {
@@ -756,13 +743,14 @@ static int coretemp_cpu_offline(unsigned int cpu)
}
/*
- * If all cores in this pkg are offline, remove the device. This
- * will invoke the platform driver remove function, which cleans up
- * the rest.
+ * If all cores in this pkg are offline, remove the interface.
*/
+ tdata = pd->core_data[PKG_SYSFS_ATTR_NO];
if (cpumask_empty(&pd->cpumask)) {
- zone_devices[topology_logical_die_id(cpu)] = NULL;
- platform_device_unregister(pdev);
+ if (tdata)
+ coretemp_remove_core(pd, PKG_SYSFS_ATTR_NO);
+ hwmon_device_unregister(pd->hwmon_dev);
+ pd->hwmon_dev = NULL;
return 0;
}
@@ -770,7 +758,6 @@ static int coretemp_cpu_offline(unsigned int cpu)
* Check whether this core is the target for the package
* interface. We need to assign it to some other cpu.
*/
- tdata = pd->core_data[PKG_SYSFS_ATTR_NO];
if (tdata && tdata->cpu == cpu) {
target = cpumask_first(&pd->cpumask);
mutex_lock(&tdata->update_lock);
@@ -789,7 +776,7 @@ static enum cpuhp_state coretemp_hp_online;
static int __init coretemp_init(void)
{
- int err;
+ int i, err;
/*
* CPUID.06H.EAX[0] indicates whether the CPU has thermal
@@ -805,20 +792,22 @@ static int __init coretemp_init(void)
if (!zone_devices)
return -ENOMEM;
- err = platform_driver_register(&coretemp_driver);
- if (err)
- goto outzone;
+ for (i = 0; i < max_zones; i++) {
+ err = coretemp_device_add(i);
+ if (err)
+ goto outzone;
+ }
err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "hwmon/coretemp:online",
coretemp_cpu_online, coretemp_cpu_offline);
if (err < 0)
- goto outdrv;
+ goto outzone;
coretemp_hp_online = err;
return 0;
-outdrv:
- platform_driver_unregister(&coretemp_driver);
outzone:
+ while (i--)
+ coretemp_device_remove(i);
kfree(zone_devices);
return err;
}
@@ -826,8 +815,11 @@ module_init(coretemp_init)
static void __exit coretemp_exit(void)
{
+ int i;
+
cpuhp_remove_state(coretemp_hp_online);
- platform_driver_unregister(&coretemp_driver);
+ for (i = 0; i < max_zones; i++)
+ coretemp_device_remove(i);
kfree(zone_devices);
}
module_exit(coretemp_exit)
diff --git a/drivers/hwmon/drivetemp.c b/drivers/hwmon/drivetemp.c
index 5bac2b0fc7bb..8e5759b42390 100644
--- a/drivers/hwmon/drivetemp.c
+++ b/drivers/hwmon/drivetemp.c
@@ -164,7 +164,7 @@ static int drivetemp_scsi_command(struct drivetemp_data *st,
u8 lba_low, u8 lba_mid, u8 lba_high)
{
u8 scsi_cmd[MAX_COMMAND_SIZE];
- int data_dir;
+ enum req_op op;
memset(scsi_cmd, 0, sizeof(scsi_cmd));
scsi_cmd[0] = ATA_16;
@@ -175,7 +175,7 @@ static int drivetemp_scsi_command(struct drivetemp_data *st,
* field.
*/
scsi_cmd[2] = 0x06;
- data_dir = DMA_TO_DEVICE;
+ op = REQ_OP_DRV_OUT;
} else {
scsi_cmd[1] = (4 << 1); /* PIO Data-in */
/*
@@ -183,7 +183,7 @@ static int drivetemp_scsi_command(struct drivetemp_data *st,
* field.
*/
scsi_cmd[2] = 0x0e;
- data_dir = DMA_FROM_DEVICE;
+ op = REQ_OP_DRV_IN;
}
scsi_cmd[4] = feature;
scsi_cmd[6] = 1; /* 1 sector */
@@ -192,9 +192,8 @@ static int drivetemp_scsi_command(struct drivetemp_data *st,
scsi_cmd[12] = lba_high;
scsi_cmd[14] = ata_command;
- return scsi_execute_req(st->sdev, scsi_cmd, data_dir,
- st->smartdata, ATA_SECT_SIZE, NULL, HZ, 5,
- NULL);
+ return scsi_execute_cmd(st->sdev, scsi_cmd, op, st->smartdata,
+ ATA_SECT_SIZE, HZ, 5, NULL);
}
static int drivetemp_ata_command(struct drivetemp_data *st, u8 feature,
diff --git a/drivers/hwmon/emc2305.c b/drivers/hwmon/emc2305.c
index 6ad055e5868e..f65467fbd86c 100644
--- a/drivers/hwmon/emc2305.c
+++ b/drivers/hwmon/emc2305.c
@@ -59,10 +59,11 @@ static const struct i2c_device_id emc2305_ids[] = {
MODULE_DEVICE_TABLE(i2c, emc2305_ids);
/**
- * @cdev: cooling device;
- * @curr_state: cooling current state;
- * @last_hwmon_state: last cooling state updated by hwmon subsystem;
- * @last_thermal_state: last cooling state updated by thermal subsystem;
+ * struct emc2305_cdev_data - device-specific cooling device state
+ * @cdev: cooling device
+ * @cur_state: cooling current state
+ * @last_hwmon_state: last cooling state updated by hwmon subsystem
+ * @last_thermal_state: last cooling state updated by thermal subsystem
*
* The 'last_hwmon_state' and 'last_thermal_state' fields are provided to support fan low limit
* speed feature. The purpose of this feature is to provides ability to limit fan speed
@@ -86,13 +87,14 @@ struct emc2305_cdev_data {
};
/**
- * @client: i2c client;
- * @hwmon_dev: hwmon device;
- * @max_state: maximum cooling state of the cooling device;
- * @pwm_num: number of PWM channels;
- * @pwm_separate: separate PWM settings for every channel;
- * @pwm_min: array of minimum PWM per channel;
- * @cdev_data: array of cooling devices data;
+ * struct emc2305_data - device-specific data
+ * @client: i2c client
+ * @hwmon_dev: hwmon device
+ * @max_state: maximum cooling state of the cooling device
+ * @pwm_num: number of PWM channels
+ * @pwm_separate: separate PWM settings for every channel
+ * @pwm_min: array of minimum PWM per channel
+ * @cdev_data: array of cooling devices data
*/
struct emc2305_data {
struct i2c_client *client;
diff --git a/drivers/hwmon/ftsteutates.c b/drivers/hwmon/ftsteutates.c
index f5b8e724a8ca..25afd9167a34 100644
--- a/drivers/hwmon/ftsteutates.c
+++ b/drivers/hwmon/ftsteutates.c
@@ -6,17 +6,14 @@
* Thilo Cestonaro <thilo.cestonaro@ts.fujitsu.com>
*/
#include <linux/err.h>
-#include <linux/fs.h>
#include <linux/hwmon.h>
-#include <linux/hwmon-sysfs.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/jiffies.h>
+#include <linux/math.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h>
-#include <linux/sysfs.h>
-#include <linux/uaccess.h>
#include <linux/watchdog.h>
#define FTS_DEVICE_ID_REG 0x0000
@@ -48,6 +45,8 @@
#define FTS_NO_TEMP_SENSORS 0x10
#define FTS_NO_VOLT_SENSORS 0x04
+#define FTS_FAN_SOURCE_INVALID 0xff
+
static const unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
static const struct i2c_device_id fts_id[] = {
@@ -187,7 +186,7 @@ static int fts_update_device(struct fts_data *data)
data->fan_source[i] = err;
} else {
data->fan_input[i] = 0;
- data->fan_source[i] = 0;
+ data->fan_source[i] = FTS_FAN_SOURCE_INVALID;
}
}
@@ -336,373 +335,243 @@ static int fts_watchdog_init(struct fts_data *data)
/* max timeout 255 minutes. */
data->wdd.max_hw_heartbeat_ms = 0xFF * 60 * MSEC_PER_SEC;
- return watchdog_register_device(&data->wdd);
-}
-
-/*****************************************************************************/
-/* SysFS handler functions */
-/*****************************************************************************/
-static ssize_t in_value_show(struct device *dev,
- struct device_attribute *devattr, char *buf)
-{
- struct fts_data *data = dev_get_drvdata(dev);
- int index = to_sensor_dev_attr(devattr)->index;
- int err;
-
- err = fts_update_device(data);
- if (err < 0)
- return err;
-
- return sprintf(buf, "%u\n", data->volt[index]);
+ return devm_watchdog_register_device(&data->client->dev, &data->wdd);
}
-static ssize_t temp_value_show(struct device *dev,
- struct device_attribute *devattr, char *buf)
+static umode_t fts_is_visible(const void *devdata, enum hwmon_sensor_types type, u32 attr,
+ int channel)
{
- struct fts_data *data = dev_get_drvdata(dev);
- int index = to_sensor_dev_attr(devattr)->index;
- int err;
-
- err = fts_update_device(data);
- if (err < 0)
- return err;
-
- return sprintf(buf, "%u\n", data->temp_input[index]);
-}
-
-static ssize_t temp_fault_show(struct device *dev,
- struct device_attribute *devattr, char *buf)
-{
- struct fts_data *data = dev_get_drvdata(dev);
- int index = to_sensor_dev_attr(devattr)->index;
- int err;
-
- err = fts_update_device(data);
- if (err < 0)
- return err;
-
- /* 00h Temperature = Sensor Error */
- return sprintf(buf, "%d\n", data->temp_input[index] == 0);
-}
-
-static ssize_t temp_alarm_show(struct device *dev,
- struct device_attribute *devattr, char *buf)
-{
- struct fts_data *data = dev_get_drvdata(dev);
- int index = to_sensor_dev_attr(devattr)->index;
- int err;
-
- err = fts_update_device(data);
- if (err < 0)
- return err;
+ switch (type) {
+ case hwmon_temp:
+ switch (attr) {
+ case hwmon_temp_input:
+ case hwmon_temp_fault:
+ return 0444;
+ case hwmon_temp_alarm:
+ return 0644;
+ default:
+ break;
+ }
+ break;
+ case hwmon_fan:
+ switch (attr) {
+ case hwmon_fan_input:
+ case hwmon_fan_fault:
+ return 0444;
+ case hwmon_fan_alarm:
+ return 0644;
+ default:
+ break;
+ }
+ break;
+ case hwmon_pwm:
+ case hwmon_in:
+ return 0444;
+ default:
+ break;
+ }
- return sprintf(buf, "%u\n", !!(data->temp_alarm & BIT(index)));
+ return 0;
}
-static ssize_t
-temp_alarm_store(struct device *dev, struct device_attribute *devattr,
- const char *buf, size_t count)
+static int fts_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel,
+ long *val)
{
struct fts_data *data = dev_get_drvdata(dev);
- int index = to_sensor_dev_attr(devattr)->index;
- long ret;
+ int ret = fts_update_device(data);
- ret = fts_update_device(data);
if (ret < 0)
return ret;
- if (kstrtoul(buf, 10, &ret) || ret != 0)
- return -EINVAL;
-
- mutex_lock(&data->update_lock);
- ret = fts_read_byte(data->client, FTS_REG_TEMP_CONTROL(index));
- if (ret < 0)
- goto error;
-
- ret = fts_write_byte(data->client, FTS_REG_TEMP_CONTROL(index),
- ret | 0x1);
- if (ret < 0)
- goto error;
+ switch (type) {
+ case hwmon_temp:
+ switch (attr) {
+ case hwmon_temp_input:
+ *val = (data->temp_input[channel] - 64) * 1000;
- data->valid = false;
- ret = count;
-error:
- mutex_unlock(&data->update_lock);
- return ret;
-}
-
-static ssize_t fan_value_show(struct device *dev,
- struct device_attribute *devattr, char *buf)
-{
- struct fts_data *data = dev_get_drvdata(dev);
- int index = to_sensor_dev_attr(devattr)->index;
- int err;
-
- err = fts_update_device(data);
- if (err < 0)
- return err;
+ return 0;
+ case hwmon_temp_alarm:
+ *val = !!(data->temp_alarm & BIT(channel));
- return sprintf(buf, "%u\n", data->fan_input[index]);
-}
+ return 0;
+ case hwmon_temp_fault:
+ /* 00h Temperature = Sensor Error */;
+ *val = (data->temp_input[channel] == 0);
-static ssize_t fan_source_show(struct device *dev,
- struct device_attribute *devattr, char *buf)
-{
- struct fts_data *data = dev_get_drvdata(dev);
- int index = to_sensor_dev_attr(devattr)->index;
- int err;
+ return 0;
+ default:
+ break;
+ }
+ break;
+ case hwmon_fan:
+ switch (attr) {
+ case hwmon_fan_input:
+ *val = data->fan_input[channel] * 60;
- err = fts_update_device(data);
- if (err < 0)
- return err;
+ return 0;
+ case hwmon_fan_alarm:
+ *val = !!(data->fan_alarm & BIT(channel));
- return sprintf(buf, "%u\n", data->fan_source[index]);
-}
+ return 0;
+ case hwmon_fan_fault:
+ *val = !(data->fan_present & BIT(channel));
-static ssize_t fan_alarm_show(struct device *dev,
- struct device_attribute *devattr, char *buf)
-{
- struct fts_data *data = dev_get_drvdata(dev);
- int index = to_sensor_dev_attr(devattr)->index;
- int err;
+ return 0;
+ default:
+ break;
+ }
+ break;
+ case hwmon_pwm:
+ switch (attr) {
+ case hwmon_pwm_auto_channels_temp:
+ if (data->fan_source[channel] == FTS_FAN_SOURCE_INVALID)
+ *val = 0;
+ else
+ *val = BIT(data->fan_source[channel]);
+
+ return 0;
+ default:
+ break;
+ }
+ break;
+ case hwmon_in:
+ switch (attr) {
+ case hwmon_in_input:
+ *val = DIV_ROUND_CLOSEST(data->volt[channel] * 3300, 255);
- err = fts_update_device(data);
- if (err < 0)
- return err;
+ return 0;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
- return sprintf(buf, "%d\n", !!(data->fan_alarm & BIT(index)));
+ return -EOPNOTSUPP;
}
-static ssize_t
-fan_alarm_store(struct device *dev, struct device_attribute *devattr,
- const char *buf, size_t count)
+static int fts_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel,
+ long val)
{
struct fts_data *data = dev_get_drvdata(dev);
- int index = to_sensor_dev_attr(devattr)->index;
- long ret;
+ int ret = fts_update_device(data);
- ret = fts_update_device(data);
if (ret < 0)
return ret;
- if (kstrtoul(buf, 10, &ret) || ret != 0)
- return -EINVAL;
-
- mutex_lock(&data->update_lock);
- ret = fts_read_byte(data->client, FTS_REG_FAN_CONTROL(index));
- if (ret < 0)
- goto error;
-
- ret = fts_write_byte(data->client, FTS_REG_FAN_CONTROL(index),
- ret | 0x1);
- if (ret < 0)
- goto error;
+ switch (type) {
+ case hwmon_temp:
+ switch (attr) {
+ case hwmon_temp_alarm:
+ if (val)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ ret = fts_read_byte(data->client, FTS_REG_TEMP_CONTROL(channel));
+ if (ret >= 0)
+ ret = fts_write_byte(data->client, FTS_REG_TEMP_CONTROL(channel),
+ ret | 0x1);
+ if (ret >= 0)
+ data->valid = false;
+
+ mutex_unlock(&data->update_lock);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+ default:
+ break;
+ }
+ break;
+ case hwmon_fan:
+ switch (attr) {
+ case hwmon_fan_alarm:
+ if (val)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ ret = fts_read_byte(data->client, FTS_REG_FAN_CONTROL(channel));
+ if (ret >= 0)
+ ret = fts_write_byte(data->client, FTS_REG_FAN_CONTROL(channel),
+ ret | 0x1);
+ if (ret >= 0)
+ data->valid = false;
+
+ mutex_unlock(&data->update_lock);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
- data->valid = false;
- ret = count;
-error:
- mutex_unlock(&data->update_lock);
- return ret;
+ return -EOPNOTSUPP;
}
-/*****************************************************************************/
-/* SysFS structs */
-/*****************************************************************************/
-
-/* Temperature sensors */
-static SENSOR_DEVICE_ATTR_RO(temp1_input, temp_value, 0);
-static SENSOR_DEVICE_ATTR_RO(temp2_input, temp_value, 1);
-static SENSOR_DEVICE_ATTR_RO(temp3_input, temp_value, 2);
-static SENSOR_DEVICE_ATTR_RO(temp4_input, temp_value, 3);
-static SENSOR_DEVICE_ATTR_RO(temp5_input, temp_value, 4);
-static SENSOR_DEVICE_ATTR_RO(temp6_input, temp_value, 5);
-static SENSOR_DEVICE_ATTR_RO(temp7_input, temp_value, 6);
-static SENSOR_DEVICE_ATTR_RO(temp8_input, temp_value, 7);
-static SENSOR_DEVICE_ATTR_RO(temp9_input, temp_value, 8);
-static SENSOR_DEVICE_ATTR_RO(temp10_input, temp_value, 9);
-static SENSOR_DEVICE_ATTR_RO(temp11_input, temp_value, 10);
-static SENSOR_DEVICE_ATTR_RO(temp12_input, temp_value, 11);
-static SENSOR_DEVICE_ATTR_RO(temp13_input, temp_value, 12);
-static SENSOR_DEVICE_ATTR_RO(temp14_input, temp_value, 13);
-static SENSOR_DEVICE_ATTR_RO(temp15_input, temp_value, 14);
-static SENSOR_DEVICE_ATTR_RO(temp16_input, temp_value, 15);
-
-static SENSOR_DEVICE_ATTR_RO(temp1_fault, temp_fault, 0);
-static SENSOR_DEVICE_ATTR_RO(temp2_fault, temp_fault, 1);
-static SENSOR_DEVICE_ATTR_RO(temp3_fault, temp_fault, 2);
-static SENSOR_DEVICE_ATTR_RO(temp4_fault, temp_fault, 3);
-static SENSOR_DEVICE_ATTR_RO(temp5_fault, temp_fault, 4);
-static SENSOR_DEVICE_ATTR_RO(temp6_fault, temp_fault, 5);
-static SENSOR_DEVICE_ATTR_RO(temp7_fault, temp_fault, 6);
-static SENSOR_DEVICE_ATTR_RO(temp8_fault, temp_fault, 7);
-static SENSOR_DEVICE_ATTR_RO(temp9_fault, temp_fault, 8);
-static SENSOR_DEVICE_ATTR_RO(temp10_fault, temp_fault, 9);
-static SENSOR_DEVICE_ATTR_RO(temp11_fault, temp_fault, 10);
-static SENSOR_DEVICE_ATTR_RO(temp12_fault, temp_fault, 11);
-static SENSOR_DEVICE_ATTR_RO(temp13_fault, temp_fault, 12);
-static SENSOR_DEVICE_ATTR_RO(temp14_fault, temp_fault, 13);
-static SENSOR_DEVICE_ATTR_RO(temp15_fault, temp_fault, 14);
-static SENSOR_DEVICE_ATTR_RO(temp16_fault, temp_fault, 15);
-
-static SENSOR_DEVICE_ATTR_RW(temp1_alarm, temp_alarm, 0);
-static SENSOR_DEVICE_ATTR_RW(temp2_alarm, temp_alarm, 1);
-static SENSOR_DEVICE_ATTR_RW(temp3_alarm, temp_alarm, 2);
-static SENSOR_DEVICE_ATTR_RW(temp4_alarm, temp_alarm, 3);
-static SENSOR_DEVICE_ATTR_RW(temp5_alarm, temp_alarm, 4);
-static SENSOR_DEVICE_ATTR_RW(temp6_alarm, temp_alarm, 5);
-static SENSOR_DEVICE_ATTR_RW(temp7_alarm, temp_alarm, 6);
-static SENSOR_DEVICE_ATTR_RW(temp8_alarm, temp_alarm, 7);
-static SENSOR_DEVICE_ATTR_RW(temp9_alarm, temp_alarm, 8);
-static SENSOR_DEVICE_ATTR_RW(temp10_alarm, temp_alarm, 9);
-static SENSOR_DEVICE_ATTR_RW(temp11_alarm, temp_alarm, 10);
-static SENSOR_DEVICE_ATTR_RW(temp12_alarm, temp_alarm, 11);
-static SENSOR_DEVICE_ATTR_RW(temp13_alarm, temp_alarm, 12);
-static SENSOR_DEVICE_ATTR_RW(temp14_alarm, temp_alarm, 13);
-static SENSOR_DEVICE_ATTR_RW(temp15_alarm, temp_alarm, 14);
-static SENSOR_DEVICE_ATTR_RW(temp16_alarm, temp_alarm, 15);
-
-static struct attribute *fts_temp_attrs[] = {
- &sensor_dev_attr_temp1_input.dev_attr.attr,
- &sensor_dev_attr_temp2_input.dev_attr.attr,
- &sensor_dev_attr_temp3_input.dev_attr.attr,
- &sensor_dev_attr_temp4_input.dev_attr.attr,
- &sensor_dev_attr_temp5_input.dev_attr.attr,
- &sensor_dev_attr_temp6_input.dev_attr.attr,
- &sensor_dev_attr_temp7_input.dev_attr.attr,
- &sensor_dev_attr_temp8_input.dev_attr.attr,
- &sensor_dev_attr_temp9_input.dev_attr.attr,
- &sensor_dev_attr_temp10_input.dev_attr.attr,
- &sensor_dev_attr_temp11_input.dev_attr.attr,
- &sensor_dev_attr_temp12_input.dev_attr.attr,
- &sensor_dev_attr_temp13_input.dev_attr.attr,
- &sensor_dev_attr_temp14_input.dev_attr.attr,
- &sensor_dev_attr_temp15_input.dev_attr.attr,
- &sensor_dev_attr_temp16_input.dev_attr.attr,
-
- &sensor_dev_attr_temp1_fault.dev_attr.attr,
- &sensor_dev_attr_temp2_fault.dev_attr.attr,
- &sensor_dev_attr_temp3_fault.dev_attr.attr,
- &sensor_dev_attr_temp4_fault.dev_attr.attr,
- &sensor_dev_attr_temp5_fault.dev_attr.attr,
- &sensor_dev_attr_temp6_fault.dev_attr.attr,
- &sensor_dev_attr_temp7_fault.dev_attr.attr,
- &sensor_dev_attr_temp8_fault.dev_attr.attr,
- &sensor_dev_attr_temp9_fault.dev_attr.attr,
- &sensor_dev_attr_temp10_fault.dev_attr.attr,
- &sensor_dev_attr_temp11_fault.dev_attr.attr,
- &sensor_dev_attr_temp12_fault.dev_attr.attr,
- &sensor_dev_attr_temp13_fault.dev_attr.attr,
- &sensor_dev_attr_temp14_fault.dev_attr.attr,
- &sensor_dev_attr_temp15_fault.dev_attr.attr,
- &sensor_dev_attr_temp16_fault.dev_attr.attr,
-
- &sensor_dev_attr_temp1_alarm.dev_attr.attr,
- &sensor_dev_attr_temp2_alarm.dev_attr.attr,
- &sensor_dev_attr_temp3_alarm.dev_attr.attr,
- &sensor_dev_attr_temp4_alarm.dev_attr.attr,
- &sensor_dev_attr_temp5_alarm.dev_attr.attr,
- &sensor_dev_attr_temp6_alarm.dev_attr.attr,
- &sensor_dev_attr_temp7_alarm.dev_attr.attr,
- &sensor_dev_attr_temp8_alarm.dev_attr.attr,
- &sensor_dev_attr_temp9_alarm.dev_attr.attr,
- &sensor_dev_attr_temp10_alarm.dev_attr.attr,
- &sensor_dev_attr_temp11_alarm.dev_attr.attr,
- &sensor_dev_attr_temp12_alarm.dev_attr.attr,
- &sensor_dev_attr_temp13_alarm.dev_attr.attr,
- &sensor_dev_attr_temp14_alarm.dev_attr.attr,
- &sensor_dev_attr_temp15_alarm.dev_attr.attr,
- &sensor_dev_attr_temp16_alarm.dev_attr.attr,
- NULL
-};
-
-/* Fans */
-static SENSOR_DEVICE_ATTR_RO(fan1_input, fan_value, 0);
-static SENSOR_DEVICE_ATTR_RO(fan2_input, fan_value, 1);
-static SENSOR_DEVICE_ATTR_RO(fan3_input, fan_value, 2);
-static SENSOR_DEVICE_ATTR_RO(fan4_input, fan_value, 3);
-static SENSOR_DEVICE_ATTR_RO(fan5_input, fan_value, 4);
-static SENSOR_DEVICE_ATTR_RO(fan6_input, fan_value, 5);
-static SENSOR_DEVICE_ATTR_RO(fan7_input, fan_value, 6);
-static SENSOR_DEVICE_ATTR_RO(fan8_input, fan_value, 7);
-
-static SENSOR_DEVICE_ATTR_RO(fan1_source, fan_source, 0);
-static SENSOR_DEVICE_ATTR_RO(fan2_source, fan_source, 1);
-static SENSOR_DEVICE_ATTR_RO(fan3_source, fan_source, 2);
-static SENSOR_DEVICE_ATTR_RO(fan4_source, fan_source, 3);
-static SENSOR_DEVICE_ATTR_RO(fan5_source, fan_source, 4);
-static SENSOR_DEVICE_ATTR_RO(fan6_source, fan_source, 5);
-static SENSOR_DEVICE_ATTR_RO(fan7_source, fan_source, 6);
-static SENSOR_DEVICE_ATTR_RO(fan8_source, fan_source, 7);
-
-static SENSOR_DEVICE_ATTR_RW(fan1_alarm, fan_alarm, 0);
-static SENSOR_DEVICE_ATTR_RW(fan2_alarm, fan_alarm, 1);
-static SENSOR_DEVICE_ATTR_RW(fan3_alarm, fan_alarm, 2);
-static SENSOR_DEVICE_ATTR_RW(fan4_alarm, fan_alarm, 3);
-static SENSOR_DEVICE_ATTR_RW(fan5_alarm, fan_alarm, 4);
-static SENSOR_DEVICE_ATTR_RW(fan6_alarm, fan_alarm, 5);
-static SENSOR_DEVICE_ATTR_RW(fan7_alarm, fan_alarm, 6);
-static SENSOR_DEVICE_ATTR_RW(fan8_alarm, fan_alarm, 7);
-
-static struct attribute *fts_fan_attrs[] = {
- &sensor_dev_attr_fan1_input.dev_attr.attr,
- &sensor_dev_attr_fan2_input.dev_attr.attr,
- &sensor_dev_attr_fan3_input.dev_attr.attr,
- &sensor_dev_attr_fan4_input.dev_attr.attr,
- &sensor_dev_attr_fan5_input.dev_attr.attr,
- &sensor_dev_attr_fan6_input.dev_attr.attr,
- &sensor_dev_attr_fan7_input.dev_attr.attr,
- &sensor_dev_attr_fan8_input.dev_attr.attr,
-
- &sensor_dev_attr_fan1_source.dev_attr.attr,
- &sensor_dev_attr_fan2_source.dev_attr.attr,
- &sensor_dev_attr_fan3_source.dev_attr.attr,
- &sensor_dev_attr_fan4_source.dev_attr.attr,
- &sensor_dev_attr_fan5_source.dev_attr.attr,
- &sensor_dev_attr_fan6_source.dev_attr.attr,
- &sensor_dev_attr_fan7_source.dev_attr.attr,
- &sensor_dev_attr_fan8_source.dev_attr.attr,
-
- &sensor_dev_attr_fan1_alarm.dev_attr.attr,
- &sensor_dev_attr_fan2_alarm.dev_attr.attr,
- &sensor_dev_attr_fan3_alarm.dev_attr.attr,
- &sensor_dev_attr_fan4_alarm.dev_attr.attr,
- &sensor_dev_attr_fan5_alarm.dev_attr.attr,
- &sensor_dev_attr_fan6_alarm.dev_attr.attr,
- &sensor_dev_attr_fan7_alarm.dev_attr.attr,
- &sensor_dev_attr_fan8_alarm.dev_attr.attr,
- NULL
+static const struct hwmon_ops fts_ops = {
+ .is_visible = fts_is_visible,
+ .read = fts_read,
+ .write = fts_write,
};
-/* Voltages */
-static SENSOR_DEVICE_ATTR_RO(in1_input, in_value, 0);
-static SENSOR_DEVICE_ATTR_RO(in2_input, in_value, 1);
-static SENSOR_DEVICE_ATTR_RO(in3_input, in_value, 2);
-static SENSOR_DEVICE_ATTR_RO(in4_input, in_value, 3);
-static struct attribute *fts_voltage_attrs[] = {
- &sensor_dev_attr_in1_input.dev_attr.attr,
- &sensor_dev_attr_in2_input.dev_attr.attr,
- &sensor_dev_attr_in3_input.dev_attr.attr,
- &sensor_dev_attr_in4_input.dev_attr.attr,
+static const struct hwmon_channel_info *fts_info[] = {
+ HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
+ HWMON_CHANNEL_INFO(temp,
+ HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
+ HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
+ HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
+ HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
+ HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
+ HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
+ HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
+ HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
+ HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
+ HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
+ HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
+ HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
+ HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
+ HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
+ HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
+ HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT
+ ),
+ HWMON_CHANNEL_INFO(fan,
+ HWMON_F_INPUT | HWMON_F_ALARM | HWMON_F_FAULT,
+ HWMON_F_INPUT | HWMON_F_ALARM | HWMON_F_FAULT,
+ HWMON_F_INPUT | HWMON_F_ALARM | HWMON_F_FAULT,
+ HWMON_F_INPUT | HWMON_F_ALARM | HWMON_F_FAULT,
+ HWMON_F_INPUT | HWMON_F_ALARM | HWMON_F_FAULT,
+ HWMON_F_INPUT | HWMON_F_ALARM | HWMON_F_FAULT,
+ HWMON_F_INPUT | HWMON_F_ALARM | HWMON_F_FAULT,
+ HWMON_F_INPUT | HWMON_F_ALARM | HWMON_F_FAULT
+ ),
+ HWMON_CHANNEL_INFO(pwm,
+ HWMON_PWM_AUTO_CHANNELS_TEMP,
+ HWMON_PWM_AUTO_CHANNELS_TEMP,
+ HWMON_PWM_AUTO_CHANNELS_TEMP,
+ HWMON_PWM_AUTO_CHANNELS_TEMP,
+ HWMON_PWM_AUTO_CHANNELS_TEMP,
+ HWMON_PWM_AUTO_CHANNELS_TEMP,
+ HWMON_PWM_AUTO_CHANNELS_TEMP,
+ HWMON_PWM_AUTO_CHANNELS_TEMP
+ ),
+ HWMON_CHANNEL_INFO(in,
+ HWMON_I_INPUT,
+ HWMON_I_INPUT,
+ HWMON_I_INPUT,
+ HWMON_I_INPUT
+ ),
NULL
};
-static const struct attribute_group fts_voltage_attr_group = {
- .attrs = fts_voltage_attrs
-};
-
-static const struct attribute_group fts_temp_attr_group = {
- .attrs = fts_temp_attrs
-};
-
-static const struct attribute_group fts_fan_attr_group = {
- .attrs = fts_fan_attrs
-};
-
-static const struct attribute_group *fts_attr_groups[] = {
- &fts_voltage_attr_group,
- &fts_temp_attr_group,
- &fts_fan_attr_group,
- NULL
+static const struct hwmon_chip_info fts_chip_info = {
+ .ops = &fts_ops,
+ .info = fts_info,
};
/*****************************************************************************/
@@ -744,13 +613,6 @@ static int fts_detect(struct i2c_client *client,
return 0;
}
-static void fts_remove(struct i2c_client *client)
-{
- struct fts_data *data = dev_get_drvdata(&client->dev);
-
- watchdog_unregister_device(&data->wdd);
-}
-
static int fts_probe(struct i2c_client *client)
{
u8 revision;
@@ -793,10 +655,8 @@ static int fts_probe(struct i2c_client *client)
return err;
revision = err;
- hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev,
- "ftsteutates",
- data,
- fts_attr_groups);
+ hwmon_dev = devm_hwmon_device_register_with_info(&client->dev, "ftsteutates", data,
+ &fts_chip_info, NULL);
if (IS_ERR(hwmon_dev))
return PTR_ERR(hwmon_dev);
@@ -819,7 +679,6 @@ static struct i2c_driver fts_driver = {
},
.id_table = fts_id,
.probe_new = fts_probe,
- .remove = fts_remove,
.detect = fts_detect,
.address_list = normal_i2c,
};
diff --git a/drivers/hwmon/gxp-fan-ctrl.c b/drivers/hwmon/gxp-fan-ctrl.c
new file mode 100644
index 000000000000..0014b8b0fd41
--- /dev/null
+++ b/drivers/hwmon/gxp-fan-ctrl.c
@@ -0,0 +1,253 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2022 Hewlett-Packard Enterprise Development Company, L.P. */
+
+#include <linux/bits.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#define OFS_FAN_INST 0 /* Is 0 because plreg base will be set at INST */
+#define OFS_FAN_FAIL 2 /* Is 2 bytes after base */
+#define OFS_SEVSTAT 0 /* Is 0 because fn2 base will be set at SEVSTAT */
+#define POWER_BIT 24
+
+struct gxp_fan_ctrl_drvdata {
+ void __iomem *base;
+ void __iomem *plreg;
+ void __iomem *fn2;
+};
+
+static bool fan_installed(struct device *dev, int fan)
+{
+ struct gxp_fan_ctrl_drvdata *drvdata = dev_get_drvdata(dev);
+ u8 val;
+
+ val = readb(drvdata->plreg + OFS_FAN_INST);
+
+ return !!(val & BIT(fan));
+}
+
+static long fan_failed(struct device *dev, int fan)
+{
+ struct gxp_fan_ctrl_drvdata *drvdata = dev_get_drvdata(dev);
+ u8 val;
+
+ val = readb(drvdata->plreg + OFS_FAN_FAIL);
+
+ return !!(val & BIT(fan));
+}
+
+static long fan_enabled(struct device *dev, int fan)
+{
+ struct gxp_fan_ctrl_drvdata *drvdata = dev_get_drvdata(dev);
+ u32 val;
+
+ /*
+ * Check the power status as if the platform is off the value
+ * reported for the PWM will be incorrect. Report fan as
+ * disabled.
+ */
+ val = readl(drvdata->fn2 + OFS_SEVSTAT);
+
+ return !!((val & BIT(POWER_BIT)) && fan_installed(dev, fan));
+}
+
+static int gxp_pwm_write(struct device *dev, u32 attr, int channel, long val)
+{
+ struct gxp_fan_ctrl_drvdata *drvdata = dev_get_drvdata(dev);
+
+ switch (attr) {
+ case hwmon_pwm_input:
+ if (val > 255 || val < 0)
+ return -EINVAL;
+ writeb(val, drvdata->base + channel);
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int gxp_fan_ctrl_write(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long val)
+{
+ switch (type) {
+ case hwmon_pwm:
+ return gxp_pwm_write(dev, attr, channel, val);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int gxp_fan_read(struct device *dev, u32 attr, int channel, long *val)
+{
+ switch (attr) {
+ case hwmon_fan_enable:
+ *val = fan_enabled(dev, channel);
+ return 0;
+ case hwmon_fan_fault:
+ *val = fan_failed(dev, channel);
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int gxp_pwm_read(struct device *dev, u32 attr, int channel, long *val)
+{
+ struct gxp_fan_ctrl_drvdata *drvdata = dev_get_drvdata(dev);
+ u32 reg;
+
+ /*
+ * Check the power status of the platform. If the platform is off
+ * the value reported for the PWM will be incorrect. In this case
+ * report a PWM of zero.
+ */
+
+ reg = readl(drvdata->fn2 + OFS_SEVSTAT);
+
+ if (reg & BIT(POWER_BIT))
+ *val = fan_installed(dev, channel) ? readb(drvdata->base + channel) : 0;
+ else
+ *val = 0;
+
+ return 0;
+}
+
+static int gxp_fan_ctrl_read(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ switch (type) {
+ case hwmon_fan:
+ return gxp_fan_read(dev, attr, channel, val);
+ case hwmon_pwm:
+ return gxp_pwm_read(dev, attr, channel, val);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static umode_t gxp_fan_ctrl_is_visible(const void *_data,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ umode_t mode = 0;
+
+ switch (type) {
+ case hwmon_fan:
+ switch (attr) {
+ case hwmon_fan_enable:
+ case hwmon_fan_fault:
+ mode = 0444;
+ break;
+ default:
+ break;
+ }
+ break;
+ case hwmon_pwm:
+ switch (attr) {
+ case hwmon_pwm_input:
+ mode = 0644;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return mode;
+}
+
+static const struct hwmon_ops gxp_fan_ctrl_ops = {
+ .is_visible = gxp_fan_ctrl_is_visible,
+ .read = gxp_fan_ctrl_read,
+ .write = gxp_fan_ctrl_write,
+};
+
+static const struct hwmon_channel_info *gxp_fan_ctrl_info[] = {
+ HWMON_CHANNEL_INFO(fan,
+ HWMON_F_FAULT | HWMON_F_ENABLE,
+ HWMON_F_FAULT | HWMON_F_ENABLE,
+ HWMON_F_FAULT | HWMON_F_ENABLE,
+ HWMON_F_FAULT | HWMON_F_ENABLE,
+ HWMON_F_FAULT | HWMON_F_ENABLE,
+ HWMON_F_FAULT | HWMON_F_ENABLE,
+ HWMON_F_FAULT | HWMON_F_ENABLE,
+ HWMON_F_FAULT | HWMON_F_ENABLE),
+ HWMON_CHANNEL_INFO(pwm,
+ HWMON_PWM_INPUT,
+ HWMON_PWM_INPUT,
+ HWMON_PWM_INPUT,
+ HWMON_PWM_INPUT,
+ HWMON_PWM_INPUT,
+ HWMON_PWM_INPUT,
+ HWMON_PWM_INPUT,
+ HWMON_PWM_INPUT),
+ NULL
+};
+
+static const struct hwmon_chip_info gxp_fan_ctrl_chip_info = {
+ .ops = &gxp_fan_ctrl_ops,
+ .info = gxp_fan_ctrl_info,
+
+};
+
+static int gxp_fan_ctrl_probe(struct platform_device *pdev)
+{
+ struct gxp_fan_ctrl_drvdata *drvdata;
+ struct device *dev = &pdev->dev;
+ struct device *hwmon_dev;
+
+ drvdata = devm_kzalloc(dev, sizeof(struct gxp_fan_ctrl_drvdata),
+ GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+
+ drvdata->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+ if (IS_ERR(drvdata->base))
+ return dev_err_probe(dev, PTR_ERR(drvdata->base),
+ "failed to map base\n");
+
+ drvdata->plreg = devm_platform_ioremap_resource_byname(pdev,
+ "pl");
+ if (IS_ERR(drvdata->plreg))
+ return dev_err_probe(dev, PTR_ERR(drvdata->plreg),
+ "failed to map plreg\n");
+
+ drvdata->fn2 = devm_platform_ioremap_resource_byname(pdev,
+ "fn2");
+ if (IS_ERR(drvdata->fn2))
+ return dev_err_probe(dev, PTR_ERR(drvdata->fn2),
+ "failed to map fn2\n");
+
+ hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev,
+ "hpe_gxp_fan_ctrl",
+ drvdata,
+ &gxp_fan_ctrl_chip_info,
+ NULL);
+
+ return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct of_device_id gxp_fan_ctrl_of_match[] = {
+ { .compatible = "hpe,gxp-fan-ctrl", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, gxp_fan_ctrl_of_match);
+
+static struct platform_driver gxp_fan_ctrl_driver = {
+ .probe = gxp_fan_ctrl_probe,
+ .driver = {
+ .name = "gxp-fan-ctrl",
+ .of_match_table = gxp_fan_ctrl_of_match,
+ },
+};
+module_platform_driver(gxp_fan_ctrl_driver);
+
+MODULE_AUTHOR("Nick Hawkins <nick.hawkins@hpe.com>");
+MODULE_DESCRIPTION("HPE GXP fan controller");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/hih6130.c b/drivers/hwmon/hih6130.c
index d9394e19fea8..3a7582824f94 100644
--- a/drivers/hwmon/hih6130.c
+++ b/drivers/hwmon/hih6130.c
@@ -150,7 +150,7 @@ out:
}
/**
- * hih6130_show_temperature() - show temperature measurement value in sysfs
+ * hih6130_temperature_show() - show temperature measurement value in sysfs
* @dev: device
* @attr: device attribute
* @buf: sysfs buffer (PAGE_SIZE) where measurement values are written to
@@ -172,7 +172,7 @@ static ssize_t hih6130_temperature_show(struct device *dev,
}
/**
- * hih6130_show_humidity() - show humidity measurement value in sysfs
+ * hih6130_humidity_show() - show humidity measurement value in sysfs
* @dev: device
* @attr: device attribute
* @buf: sysfs buffer (PAGE_SIZE) where measurement values are written to
diff --git a/drivers/hwmon/ibmpex.c b/drivers/hwmon/ibmpex.c
index 1837cccd993c..db066b368918 100644
--- a/drivers/hwmon/ibmpex.c
+++ b/drivers/hwmon/ibmpex.c
@@ -546,7 +546,7 @@ static void ibmpex_bmc_gone(int iface)
static void ibmpex_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data)
{
- struct ibmpex_bmc_data *data = (struct ibmpex_bmc_data *)user_msg_data;
+ struct ibmpex_bmc_data *data = user_msg_data;
if (msg->msgid != data->tx_msgid) {
dev_err(data->bmc_device,
diff --git a/drivers/hwmon/iio_hwmon.c b/drivers/hwmon/iio_hwmon.c
index 3aa40893fc09..4c8a80847891 100644
--- a/drivers/hwmon/iio_hwmon.c
+++ b/drivers/hwmon/iio_hwmon.c
@@ -77,9 +77,11 @@ static int iio_hwmon_probe(struct platform_device *pdev)
channels = devm_iio_channel_get_all(dev);
if (IS_ERR(channels)) {
- if (PTR_ERR(channels) == -ENODEV)
- return -EPROBE_DEFER;
- return PTR_ERR(channels);
+ ret = PTR_ERR(channels);
+ if (ret == -ENODEV)
+ ret = -EPROBE_DEFER;
+ return dev_err_probe(dev, ret,
+ "Failed to get channels\n");
}
st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
diff --git a/drivers/hwmon/intel-m10-bmc-hwmon.c b/drivers/hwmon/intel-m10-bmc-hwmon.c
index 6e82f7200d1c..2f0323c14bab 100644
--- a/drivers/hwmon/intel-m10-bmc-hwmon.c
+++ b/drivers/hwmon/intel-m10-bmc-hwmon.c
@@ -340,6 +340,231 @@ static const struct m10bmc_hwmon_board_data n5010bmc_hwmon_bdata = {
.hinfo = n5010bmc_hinfo,
};
+static const struct m10bmc_sdata n6000bmc_temp_tbl[] = {
+ { 0x444, 0x448, 0x44c, 0x0, 0x0, 500, "FPGA E-TILE Temperature #1" },
+ { 0x450, 0x454, 0x458, 0x0, 0x0, 500, "FPGA E-TILE Temperature #2" },
+ { 0x45c, 0x460, 0x464, 0x0, 0x0, 500, "FPGA E-TILE Temperature #3" },
+ { 0x468, 0x46c, 0x470, 0x0, 0x0, 500, "FPGA E-TILE Temperature #4" },
+ { 0x474, 0x478, 0x47c, 0x0, 0x0, 500, "FPGA P-TILE Temperature" },
+ { 0x484, 0x488, 0x48c, 0x0, 0x0, 500, "FPGA FABRIC Digital Temperature #1" },
+ { 0x490, 0x494, 0x498, 0x0, 0x0, 500, "FPGA FABRIC Digital Temperature #2" },
+ { 0x49c, 0x4a0, 0x4a4, 0x0, 0x0, 500, "FPGA FABRIC Digital Temperature #3" },
+ { 0x4a8, 0x4ac, 0x4b0, 0x0, 0x0, 500, "FPGA FABRIC Digital Temperature #4" },
+ { 0x4b4, 0x4b8, 0x4bc, 0x0, 0x0, 500, "FPGA FABRIC Digital Temperature #5" },
+ { 0x4c0, 0x4c4, 0x4c8, 0x0, 0x0, 500, "FPGA FABRIC Remote Digital Temperature #1" },
+ { 0x4cc, 0x4d0, 0x4d4, 0x0, 0x0, 500, "FPGA FABRIC Remote Digital Temperature #2" },
+ { 0x4d8, 0x4dc, 0x4e0, 0x0, 0x0, 500, "FPGA FABRIC Remote Digital Temperature #3" },
+ { 0x4e4, 0x4e8, 0x4ec, 0x0, 0x0, 500, "FPGA FABRIC Remote Digital Temperature #4" },
+ { 0x4f0, 0x4f4, 0x4f8, 0x52c, 0x0, 500, "Board Top Near FPGA Temperature" },
+ { 0x4fc, 0x500, 0x504, 0x52c, 0x0, 500, "Board Bottom Near CVL Temperature" },
+ { 0x508, 0x50c, 0x510, 0x52c, 0x0, 500, "Board Top East Near VRs Temperature" },
+ { 0x514, 0x518, 0x51c, 0x52c, 0x0, 500, "Columbiaville Die Temperature" },
+ { 0x520, 0x524, 0x528, 0x52c, 0x0, 500, "Board Rear Side Temperature" },
+ { 0x530, 0x534, 0x538, 0x52c, 0x0, 500, "Board Front Side Temperature" },
+ { 0x53c, 0x540, 0x544, 0x0, 0x0, 500, "QSFP1 Case Temperature" },
+ { 0x548, 0x54c, 0x550, 0x0, 0x0, 500, "QSFP2 Case Temperature" },
+ { 0x554, 0x0, 0x0, 0x0, 0x0, 500, "FPGA Core Voltage Phase 0 VR Temperature" },
+ { 0x560, 0x0, 0x0, 0x0, 0x0, 500, "FPGA Core Voltage Phase 1 VR Temperature" },
+ { 0x56c, 0x0, 0x0, 0x0, 0x0, 500, "FPGA Core Voltage Phase 2 VR Temperature" },
+ { 0x578, 0x0, 0x0, 0x0, 0x0, 500, "FPGA Core Voltage VR Controller Temperature" },
+ { 0x584, 0x0, 0x0, 0x0, 0x0, 500, "FPGA VCCH VR Temperature" },
+ { 0x590, 0x0, 0x0, 0x0, 0x0, 500, "FPGA VCC_1V2 VR Temperature" },
+ { 0x59c, 0x0, 0x0, 0x0, 0x0, 500, "FPGA VCCH, VCC_1V2 VR Controller Temperature" },
+ { 0x5a8, 0x0, 0x0, 0x0, 0x0, 500, "3V3 VR Temperature" },
+ { 0x5b4, 0x0, 0x0, 0x0, 0x0, 500, "CVL Core Voltage VR Temperature" },
+ { 0x5c4, 0x5c8, 0x5cc, 0x5c0, 0x0, 500, "FPGA P-Tile Temperature [Remote]" },
+ { 0x5d0, 0x5d4, 0x5d8, 0x5c0, 0x0, 500, "FPGA E-Tile Temperature [Remote]" },
+ { 0x5dc, 0x5e0, 0x5e4, 0x5c0, 0x0, 500, "FPGA SDM Temperature [Remote]" },
+ { 0x5e8, 0x5ec, 0x5f0, 0x5c0, 0x0, 500, "FPGA Corner Temperature [Remote]" },
+};
+
+static const struct m10bmc_sdata n6000bmc_in_tbl[] = {
+ { 0x5f4, 0x0, 0x0, 0x0, 0x0, 1, "Inlet 12V PCIe Rail Voltage" },
+ { 0x60c, 0x0, 0x0, 0x0, 0x0, 1, "Inlet 12V Aux Rail Voltage" },
+ { 0x624, 0x0, 0x0, 0x0, 0x0, 1, "Inlet 3V3 PCIe Rail Voltage" },
+ { 0x63c, 0x0, 0x0, 0x0, 0x0, 1, "FPGA Core Voltage Rail Voltage" },
+ { 0x644, 0x0, 0x0, 0x0, 0x0, 1, "FPGA VCCH Rail Voltage" },
+ { 0x64c, 0x0, 0x0, 0x0, 0x0, 1, "FPGA VCC_1V2 Rail Voltage" },
+ { 0x654, 0x0, 0x0, 0x0, 0x0, 1, "FPGA VCCH_GXER_1V1, VCCA_1V8 Voltage" },
+ { 0x664, 0x0, 0x0, 0x0, 0x0, 1, "FPGA VCCIO_1V2 Voltage" },
+ { 0x674, 0x0, 0x0, 0x0, 0x0, 1, "CVL Non Core Rails Inlet Voltage" },
+ { 0x684, 0x0, 0x0, 0x0, 0x0, 1, "MAX10 & Board CLK PWR 3V3 Inlet Voltage" },
+ { 0x694, 0x0, 0x0, 0x0, 0x0, 1, "CVL Core Voltage Rail Voltage" },
+ { 0x6ac, 0x0, 0x0, 0x0, 0x0, 1, "Board 3V3 VR Voltage" },
+ { 0x6b4, 0x0, 0x0, 0x0, 0x0, 1, "QSFP 3V3 Rail Voltage" },
+ { 0x6c4, 0x0, 0x0, 0x0, 0x0, 1, "QSFP (Primary) Supply Rail Voltage" },
+ { 0x6c8, 0x0, 0x0, 0x0, 0x0, 1, "QSFP (Secondary) Supply Rail Voltage" },
+ { 0x6cc, 0x0, 0x0, 0x0, 0x0, 1, "VCCCLK_GXER_2V5 Voltage" },
+ { 0x6d0, 0x0, 0x0, 0x0, 0x0, 1, "AVDDH_1V1_CVL Voltage" },
+ { 0x6d4, 0x0, 0x0, 0x0, 0x0, 1, "VDDH_1V8_CVL Voltage" },
+ { 0x6d8, 0x0, 0x0, 0x0, 0x0, 1, "VCCA_PLL Voltage" },
+ { 0x6e0, 0x0, 0x0, 0x0, 0x0, 1, "VCCRT_GXER_0V9 Voltage" },
+ { 0x6e8, 0x0, 0x0, 0x0, 0x0, 1, "VCCRT_GXPL_0V9 Voltage" },
+ { 0x6f0, 0x0, 0x0, 0x0, 0x0, 1, "VCCH_GXPL_1V8 Voltage" },
+ { 0x6f4, 0x0, 0x0, 0x0, 0x0, 1, "VCCPT_1V8 Voltage" },
+ { 0x6fc, 0x0, 0x0, 0x0, 0x0, 1, "VCC_3V3_M10 Voltage" },
+ { 0x700, 0x0, 0x0, 0x0, 0x0, 1, "VCC_1V8_M10 Voltage" },
+ { 0x704, 0x0, 0x0, 0x0, 0x0, 1, "VCC_1V2_EMIF1_2_3 Voltage" },
+ { 0x70c, 0x0, 0x0, 0x0, 0x0, 1, "VCC_1V2_EMIF4_5 Voltage" },
+ { 0x714, 0x0, 0x0, 0x0, 0x0, 1, "VCCA_1V8 Voltage" },
+ { 0x718, 0x0, 0x0, 0x0, 0x0, 1, "VCCH_GXER_1V1 Voltage" },
+ { 0x71c, 0x0, 0x0, 0x0, 0x0, 1, "AVDD_ETH_0V9_CVL Voltage" },
+ { 0x720, 0x0, 0x0, 0x0, 0x0, 1, "AVDD_PCIE_0V9_CVL Voltage" },
+};
+
+static const struct m10bmc_sdata n6000bmc_curr_tbl[] = {
+ { 0x600, 0x604, 0x608, 0x0, 0x0, 1, "Inlet 12V PCIe Rail Current" },
+ { 0x618, 0x61c, 0x620, 0x0, 0x0, 1, "Inlet 12V Aux Rail Current" },
+ { 0x630, 0x634, 0x638, 0x0, 0x0, 1, "Inlet 3V3 PCIe Rail Current" },
+ { 0x640, 0x0, 0x0, 0x0, 0x0, 1, "FPGA Core Voltage Rail Current" },
+ { 0x648, 0x0, 0x0, 0x0, 0x0, 1, "FPGA VCCH Rail Current" },
+ { 0x650, 0x0, 0x0, 0x0, 0x0, 1, "FPGA VCC_1V2 Rail Current" },
+ { 0x658, 0x65c, 0x660, 0x0, 0x0, 1, "FPGA VCCH_GXER_1V1, VCCA_1V8 Current" },
+ { 0x668, 0x66c, 0x670, 0x0, 0x0, 1, "FPGA VCCIO_1V2 Current" },
+ { 0x678, 0x67c, 0x680, 0x0, 0x0, 1, "CVL Non Core Rails Inlet Current" },
+ { 0x688, 0x68c, 0x690, 0x0, 0x0, 1, "MAX10 & Board CLK PWR 3V3 Inlet Current" },
+ { 0x698, 0x0, 0x0, 0x0, 0x0, 1, "CVL Core Voltage Rail Current" },
+ { 0x6b0, 0x0, 0x0, 0x0, 0x0, 1, "Board 3V3 VR Current" },
+ { 0x6b8, 0x6bc, 0x6c0, 0x0, 0x0, 1, "QSFP 3V3 Rail Current" },
+};
+
+static const struct m10bmc_sdata n6000bmc_power_tbl[] = {
+ { 0x724, 0x0, 0x0, 0x0, 0x0, 1, "Board Power" },
+};
+
+static const struct hwmon_channel_info *n6000bmc_hinfo[] = {
+ HWMON_CHANNEL_INFO(temp,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
+ HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
+ HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
+ HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
+ HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
+ HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
+ HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
+ HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
+ HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
+ HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
+ HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL),
+ HWMON_CHANNEL_INFO(in,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL),
+ HWMON_CHANNEL_INFO(curr,
+ HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_CRIT |
+ HWMON_C_LABEL,
+ HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_CRIT |
+ HWMON_C_LABEL,
+ HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_CRIT |
+ HWMON_C_LABEL,
+ HWMON_C_INPUT | HWMON_C_LABEL,
+ HWMON_C_INPUT | HWMON_C_LABEL,
+ HWMON_C_INPUT | HWMON_C_LABEL,
+ HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_CRIT |
+ HWMON_C_LABEL,
+ HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_CRIT |
+ HWMON_C_LABEL,
+ HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_CRIT |
+ HWMON_C_LABEL,
+ HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_CRIT |
+ HWMON_C_LABEL,
+ HWMON_C_INPUT | HWMON_C_LABEL,
+ HWMON_C_INPUT | HWMON_C_LABEL,
+ HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_CRIT |
+ HWMON_C_LABEL),
+ HWMON_CHANNEL_INFO(power,
+ HWMON_P_INPUT | HWMON_P_LABEL),
+ NULL
+};
+
+static const struct m10bmc_hwmon_board_data n6000bmc_hwmon_bdata = {
+ .tables = {
+ [hwmon_temp] = n6000bmc_temp_tbl,
+ [hwmon_in] = n6000bmc_in_tbl,
+ [hwmon_curr] = n6000bmc_curr_tbl,
+ [hwmon_power] = n6000bmc_power_tbl,
+ },
+
+ .hinfo = n6000bmc_hinfo,
+};
+
static umode_t
m10bmc_hwmon_is_visible(const void *data, enum hwmon_sensor_types type,
u32 attr, int channel)
@@ -549,6 +774,10 @@ static const struct platform_device_id intel_m10bmc_hwmon_ids[] = {
.name = "n5010bmc-hwmon",
.driver_data = (unsigned long)&n5010bmc_hwmon_bdata,
},
+ {
+ .name = "n6000bmc-hwmon",
+ .driver_data = (unsigned long)&n6000bmc_hwmon_bdata,
+ },
{ }
};
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 9997f76b1f4a..66f7ceaa7c3f 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -34,6 +34,7 @@
* IT8786E Super I/O chip w/LPC interface
* IT8790E Super I/O chip w/LPC interface
* IT8792E Super I/O chip w/LPC interface
+ * IT87952E Super I/O chip w/LPC interface
* Sis950 A clone of the IT8705F
*
* Copyright (C) 2001 Chris Gauthron
@@ -63,15 +64,7 @@
enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8732,
it8771, it8772, it8781, it8782, it8783, it8786, it8790,
- it8792, it8603, it8620, it8622, it8628 };
-
-static unsigned short force_id;
-module_param(force_id, ushort, 0);
-MODULE_PARM_DESC(force_id, "Override the detected device ID");
-
-static bool ignore_resource_conflict;
-module_param(ignore_resource_conflict, bool, 0);
-MODULE_PARM_DESC(ignore_resource_conflict, "Ignore ACPI resource conflict");
+ it8792, it8603, it8620, it8622, it8628, it87952 };
static struct platform_device *it87_pdev[2];
@@ -87,6 +80,14 @@ static struct platform_device *it87_pdev[2];
#define DEVID 0x20 /* Register: Device ID */
#define DEVREV 0x22 /* Register: Device Revision */
+static inline void __superio_enter(int ioreg)
+{
+ outb(0x87, ioreg);
+ outb(0x01, ioreg);
+ outb(0x55, ioreg);
+ outb(ioreg == REG_4E ? 0xaa : 0x55, ioreg);
+}
+
static inline int superio_inb(int ioreg, int reg)
{
outb(reg, ioreg);
@@ -124,17 +125,16 @@ static inline int superio_enter(int ioreg)
if (!request_muxed_region(ioreg, 2, DRVNAME))
return -EBUSY;
- outb(0x87, ioreg);
- outb(0x01, ioreg);
- outb(0x55, ioreg);
- outb(ioreg == REG_4E ? 0xaa : 0x55, ioreg);
+ __superio_enter(ioreg);
return 0;
}
-static inline void superio_exit(int ioreg)
+static inline void superio_exit(int ioreg, bool noexit)
{
- outb(0x02, ioreg);
- outb(0x02, ioreg + 1);
+ if (!noexit) {
+ outb(0x02, ioreg);
+ outb(0x02, ioreg + 1);
+ }
release_region(ioreg, 2);
}
@@ -161,6 +161,7 @@ static inline void superio_exit(int ioreg)
#define IT8622E_DEVID 0x8622
#define IT8623E_DEVID 0x8623
#define IT8628E_DEVID 0x8628
+#define IT87952E_DEVID 0x8695
#define IT87_ACT_REG 0x30
#define IT87_BASE_REG 0x60
@@ -176,6 +177,13 @@ static inline void superio_exit(int ioreg)
#define IT87_SIO_VID_REG 0xfc /* VID value */
#define IT87_SIO_BEEP_PIN_REG 0xf6 /* Beep pin mapping */
+/* Force chip IDs to specified values. Should only be used for testing */
+static unsigned short force_id[2];
+static unsigned int force_id_cnt;
+
+/* ACPI resource conflicts are ignored if this parameter is set to 1 */
+static bool ignore_resource_conflict;
+
/* Update battery voltage after every reading if true */
static bool update_vbat;
@@ -272,7 +280,7 @@ static const u8 IT87_REG_AUTO_BASE[] = { 0x60, 0x68, 0x70, 0x78, 0xa0, 0xa8 };
struct it87_devices {
const char *name;
- const char * const suffix;
+ const char * const model;
u32 features;
u8 peci_mask;
u8 old_peci_mask;
@@ -297,28 +305,35 @@ struct it87_devices {
#define FEAT_PWM_FREQ2 BIT(16) /* Separate pwm freq 2 */
#define FEAT_SIX_TEMP BIT(17) /* Up to 6 temp sensors */
#define FEAT_VIN3_5V BIT(18) /* VIN3 connected to +5V */
+/*
+ * Disabling configuration mode on some chips can result in system
+ * hang-ups and access failures to the Super-IO chip at the
+ * second SIO address. Never exit configuration mode on these
+ * chips to avoid the problem.
+ */
+#define FEAT_CONF_NOEXIT BIT(19) /* Chip should not exit conf mode */
static const struct it87_devices it87_devices[] = {
[it87] = {
.name = "it87",
- .suffix = "F",
+ .model = "IT87F",
.features = FEAT_OLD_AUTOPWM, /* may need to overwrite */
},
[it8712] = {
.name = "it8712",
- .suffix = "F",
+ .model = "IT8712F",
.features = FEAT_OLD_AUTOPWM | FEAT_VID,
/* may need to overwrite */
},
[it8716] = {
.name = "it8716",
- .suffix = "F",
+ .model = "IT8716F",
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID
| FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_PWM_FREQ2,
},
[it8718] = {
.name = "it8718",
- .suffix = "F",
+ .model = "IT8718F",
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID
| FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS
| FEAT_PWM_FREQ2,
@@ -326,7 +341,7 @@ static const struct it87_devices it87_devices[] = {
},
[it8720] = {
.name = "it8720",
- .suffix = "F",
+ .model = "IT8720F",
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID
| FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS
| FEAT_PWM_FREQ2,
@@ -334,7 +349,7 @@ static const struct it87_devices it87_devices[] = {
},
[it8721] = {
.name = "it8721",
- .suffix = "F",
+ .model = "IT8721F",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
| FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_IN7_INTERNAL
@@ -344,7 +359,7 @@ static const struct it87_devices it87_devices[] = {
},
[it8728] = {
.name = "it8728",
- .suffix = "F",
+ .model = "IT8728F",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_FIVE_FANS
| FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2,
@@ -352,7 +367,7 @@ static const struct it87_devices it87_devices[] = {
},
[it8732] = {
.name = "it8732",
- .suffix = "F",
+ .model = "IT8732F",
.features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
| FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL,
@@ -361,7 +376,7 @@ static const struct it87_devices it87_devices[] = {
},
[it8771] = {
.name = "it8771",
- .suffix = "E",
+ .model = "IT8771E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
| FEAT_PWM_FREQ2,
@@ -373,7 +388,7 @@ static const struct it87_devices it87_devices[] = {
},
[it8772] = {
.name = "it8772",
- .suffix = "E",
+ .model = "IT8772E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
| FEAT_PWM_FREQ2,
@@ -385,28 +400,28 @@ static const struct it87_devices it87_devices[] = {
},
[it8781] = {
.name = "it8781",
- .suffix = "F",
+ .model = "IT8781F",
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
| FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2,
.old_peci_mask = 0x4,
},
[it8782] = {
.name = "it8782",
- .suffix = "F",
+ .model = "IT8782F",
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
| FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2,
.old_peci_mask = 0x4,
},
[it8783] = {
.name = "it8783",
- .suffix = "E/F",
+ .model = "IT8783E/F",
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
| FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2,
.old_peci_mask = 0x4,
},
[it8786] = {
.name = "it8786",
- .suffix = "E",
+ .model = "IT8786E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
| FEAT_PWM_FREQ2,
@@ -414,24 +429,24 @@ static const struct it87_devices it87_devices[] = {
},
[it8790] = {
.name = "it8790",
- .suffix = "E",
+ .model = "IT8790E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
- | FEAT_PWM_FREQ2,
+ | FEAT_PWM_FREQ2 | FEAT_CONF_NOEXIT,
.peci_mask = 0x07,
},
[it8792] = {
.name = "it8792",
- .suffix = "E",
+ .model = "IT8792E/IT8795E",
.features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
- | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL,
+ | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_CONF_NOEXIT,
.peci_mask = 0x07,
.old_peci_mask = 0x02, /* Actually reports PCH */
},
[it8603] = {
.name = "it8603",
- .suffix = "E",
+ .model = "IT8603E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
| FEAT_AVCC3 | FEAT_PWM_FREQ2,
@@ -439,7 +454,7 @@ static const struct it87_devices it87_devices[] = {
},
[it8620] = {
.name = "it8620",
- .suffix = "E",
+ .model = "IT8620E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_SIX_FANS
| FEAT_IN7_INTERNAL | FEAT_SIX_PWM | FEAT_PWM_FREQ2
@@ -448,7 +463,7 @@ static const struct it87_devices it87_devices[] = {
},
[it8622] = {
.name = "it8622",
- .suffix = "E",
+ .model = "IT8622E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_FIVE_FANS
| FEAT_FIVE_PWM | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2
@@ -457,13 +472,22 @@ static const struct it87_devices it87_devices[] = {
},
[it8628] = {
.name = "it8628",
- .suffix = "E",
+ .model = "IT8628E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_SIX_FANS
| FEAT_IN7_INTERNAL | FEAT_SIX_PWM | FEAT_PWM_FREQ2
| FEAT_SIX_TEMP | FEAT_VIN3_5V,
.peci_mask = 0x07,
},
+ [it87952] = {
+ .name = "it87952",
+ .model = "IT87952E",
+ .features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS
+ | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
+ | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_CONF_NOEXIT,
+ .peci_mask = 0x07,
+ .old_peci_mask = 0x02, /* Actually reports PCH */
+ },
};
#define has_16bit_fans(data) ((data)->features & FEAT_16BIT_FANS)
@@ -490,6 +514,7 @@ static const struct it87_devices it87_devices[] = {
#define has_pwm_freq2(data) ((data)->features & FEAT_PWM_FREQ2)
#define has_six_temp(data) ((data)->features & FEAT_SIX_TEMP)
#define has_vin3_5v(data) ((data)->features & FEAT_VIN3_5V)
+#define has_conf_noexit(data) ((data)->features & FEAT_CONF_NOEXIT)
struct it87_sio_data {
int sioaddr;
@@ -2397,11 +2422,11 @@ static const struct attribute_group it87_group_auto_pwm = {
/* SuperIO detection - will change isa_address if a chip is found */
static int __init it87_find(int sioaddr, unsigned short *address,
- struct it87_sio_data *sio_data)
+ struct it87_sio_data *sio_data, int chip_cnt)
{
int err;
u16 chip_type;
- const struct it87_devices *config;
+ const struct it87_devices *config = NULL;
err = superio_enter(sioaddr);
if (err)
@@ -2413,8 +2438,12 @@ static int __init it87_find(int sioaddr, unsigned short *address,
if (chip_type == 0xffff)
goto exit;
- if (force_id)
- chip_type = force_id;
+ if (force_id_cnt == 1) {
+ /* If only one value given use for all chips */
+ if (force_id[0])
+ chip_type = force_id[0];
+ } else if (force_id[chip_cnt])
+ chip_type = force_id[chip_cnt];
switch (chip_type) {
case IT8705F_DEVID:
@@ -2479,6 +2508,9 @@ static int __init it87_find(int sioaddr, unsigned short *address,
case IT8628E_DEVID:
sio_data->type = it8628;
break;
+ case IT87952E_DEVID:
+ sio_data->type = it87952;
+ break;
case 0xffff: /* No device at all */
goto exit;
default:
@@ -2486,27 +2518,29 @@ static int __init it87_find(int sioaddr, unsigned short *address,
goto exit;
}
+ config = &it87_devices[sio_data->type];
+
superio_select(sioaddr, PME);
if (!(superio_inb(sioaddr, IT87_ACT_REG) & 0x01)) {
- pr_info("Device not activated, skipping\n");
+ pr_info("Device (chip %s ioreg 0x%x) not activated, skipping\n",
+ config->model, sioaddr);
goto exit;
}
*address = superio_inw(sioaddr, IT87_BASE_REG) & ~(IT87_EXTENT - 1);
if (*address == 0) {
- pr_info("Base address not set, skipping\n");
+ pr_info("Base address not set (chip %s ioreg 0x%x), skipping\n",
+ config->model, sioaddr);
goto exit;
}
err = 0;
sio_data->sioaddr = sioaddr;
sio_data->revision = superio_inb(sioaddr, DEVREV) & 0x0f;
- pr_info("Found IT%04x%s chip at 0x%x, revision %d\n", chip_type,
- it87_devices[sio_data->type].suffix,
+ pr_info("Found %s chip at 0x%x, revision %d\n",
+ it87_devices[sio_data->type].model,
*address, sio_data->revision);
- config = &it87_devices[sio_data->type];
-
/* in7 (VSB or VCCH5V) is always internal on some chips */
if (has_in7_internal(config))
sio_data->internal |= BIT(1);
@@ -2824,7 +2858,7 @@ static int __init it87_find(int sioaddr, unsigned short *address,
sio_data->skip_pwm |= dmi_data->skip_pwm;
exit:
- superio_exit(sioaddr);
+ superio_exit(sioaddr, config ? has_conf_noexit(config) : false);
return err;
}
@@ -3210,7 +3244,7 @@ static void it87_resume_sio(struct platform_device *pdev)
reg2c);
}
- superio_exit(data->sioaddr);
+ superio_exit(data->sioaddr, has_conf_noexit(data));
}
static int it87_resume(struct device *dev)
@@ -3311,6 +3345,27 @@ static int it87_dmi_cb(const struct dmi_system_id *dmi_entry)
}
/*
+ * On various Gigabyte AM4 boards (AB350, AX370), the second Super-IO chip
+ * (IT8792E) needs to be in configuration mode before accessing the first
+ * due to a bug in IT8792E which otherwise results in LPC bus access errors.
+ * This needs to be done before accessing the first Super-IO chip since
+ * the second chip may have been accessed prior to loading this driver.
+ *
+ * The problem is also reported to affect IT8795E, which is used on X299 boards
+ * and has the same chip ID as IT8792E (0x8733). It also appears to affect
+ * systems with IT8790E, which is used on some Z97X-Gaming boards as well as
+ * Z87X-OC.
+ * DMI entries for those systems will be added as they become available and
+ * as the problem is confirmed to affect those boards.
+ */
+static int it87_sio_force(const struct dmi_system_id *dmi_entry)
+{
+ __superio_enter(REG_4E);
+
+ return it87_dmi_cb(dmi_entry);
+};
+
+/*
* On the Shuttle SN68PT, FAN_CTL2 is apparently not
* connected to a fan, but to something else. One user
* has reported instant system power-off when changing
@@ -3332,7 +3387,34 @@ static struct it87_dmi_data nvidia_fn68pt = {
.driver_data = data, \
}
+#define IT87_DMI_MATCH_GBT(name, cb, data) \
+ IT87_DMI_MATCH_VND("Gigabyte Technology Co., Ltd.", name, cb, data)
+
static const struct dmi_system_id it87_dmi_table[] __initconst = {
+ IT87_DMI_MATCH_GBT("AB350", it87_sio_force, NULL),
+ /* ? + IT8792E/IT8795E */
+ IT87_DMI_MATCH_GBT("AX370", it87_sio_force, NULL),
+ /* ? + IT8792E/IT8795E */
+ IT87_DMI_MATCH_GBT("Z97X-Gaming G1", it87_sio_force, NULL),
+ /* ? + IT8790E */
+ IT87_DMI_MATCH_GBT("TRX40 AORUS XTREME", it87_sio_force, NULL),
+ /* IT8688E + IT8792E/IT8795E */
+ IT87_DMI_MATCH_GBT("Z390 AORUS ULTRA-CF", it87_sio_force, NULL),
+ /* IT8688E + IT8792E/IT8795E */
+ IT87_DMI_MATCH_GBT("B550 AORUS PRO AC", it87_sio_force, NULL),
+ /* IT8688E + IT8792E/IT8795E */
+ IT87_DMI_MATCH_GBT("X570 AORUS MASTER", it87_sio_force, NULL),
+ /* IT8688E + IT8792E/IT8795E */
+ IT87_DMI_MATCH_GBT("X570 AORUS PRO", it87_sio_force, NULL),
+ /* IT8688E + IT8792E/IT8795E */
+ IT87_DMI_MATCH_GBT("X570 AORUS PRO WIFI", it87_sio_force, NULL),
+ /* IT8688E + IT8792E/IT8795E */
+ IT87_DMI_MATCH_GBT("X570S AERO G", it87_sio_force, NULL),
+ /* IT8689E + IT87952E */
+ IT87_DMI_MATCH_GBT("Z690 AORUS PRO DDR4", it87_sio_force, NULL),
+ /* IT8689E + IT87952E */
+ IT87_DMI_MATCH_GBT("Z690 AORUS PRO", it87_sio_force, NULL),
+ /* IT8689E + IT87952E */
IT87_DMI_MATCH_VND("nVIDIA", "FN68PT", it87_dmi_cb, &nvidia_fn68pt),
{ }
@@ -3356,7 +3438,7 @@ static int __init sm_it87_init(void)
for (i = 0; i < ARRAY_SIZE(sioaddr); i++) {
memset(&sio_data, 0, sizeof(struct it87_sio_data));
isa_address[i] = 0;
- err = it87_find(sioaddr[i], &isa_address[i], &sio_data);
+ err = it87_find(sioaddr[i], &isa_address[i], &sio_data, i);
if (err || isa_address[i] == 0)
continue;
/*
@@ -3404,11 +3486,20 @@ static void __exit sm_it87_exit(void)
MODULE_AUTHOR("Chris Gauthron, Jean Delvare <jdelvare@suse.de>");
MODULE_DESCRIPTION("IT8705F/IT871xF/IT872xF hardware monitoring driver");
+
+module_param_array(force_id, ushort, &force_id_cnt, 0);
+MODULE_PARM_DESC(force_id, "Override one or more detected device ID(s)");
+
+module_param(ignore_resource_conflict, bool, 0);
+MODULE_PARM_DESC(ignore_resource_conflict, "Ignore ACPI resource conflict");
+
module_param(update_vbat, bool, 0);
MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value");
+
module_param(fix_pwm_polarity, bool, 0);
MODULE_PARM_DESC(fix_pwm_polarity,
"Force PWM polarity to active high (DANGEROUS)");
+
MODULE_LICENSE("GPL");
module_init(sm_it87_init);
diff --git a/drivers/hwmon/ltc2945.c b/drivers/hwmon/ltc2945.c
index 9adebb59f604..3494f7261ebf 100644
--- a/drivers/hwmon/ltc2945.c
+++ b/drivers/hwmon/ltc2945.c
@@ -58,6 +58,22 @@
#define CONTROL_MULT_SELECT (1 << 0)
#define CONTROL_TEST_MODE (1 << 4)
+static const struct of_device_id __maybe_unused ltc2945_of_match[] = {
+ { .compatible = "adi,ltc2945" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ltc2945_of_match);
+
+/**
+ * struct ltc2945_data - LTC2945 device data
+ * @regmap: regmap device
+ * @shunt_resistor: shunt resistor value in micro ohms (1000 by default)
+ */
+struct ltc2945_data {
+ struct regmap *regmap;
+ u32 shunt_resistor;
+};
+
static inline bool is_power_reg(u8 reg)
{
return reg < LTC2945_SENSE_H;
@@ -66,7 +82,9 @@ static inline bool is_power_reg(u8 reg)
/* Return the value from the given register in uW, mV, or mA */
static long long ltc2945_reg_to_val(struct device *dev, u8 reg)
{
- struct regmap *regmap = dev_get_drvdata(dev);
+ struct ltc2945_data *data = dev_get_drvdata(dev);
+ struct regmap *regmap = data->regmap;
+ u32 shunt_resistor = data->shunt_resistor;
unsigned int control;
u8 buf[3];
long long val;
@@ -78,10 +96,10 @@ static long long ltc2945_reg_to_val(struct device *dev, u8 reg)
return ret;
if (is_power_reg(reg)) {
- /* power */
+ /* 24-bit power */
val = (buf[0] << 16) + (buf[1] << 8) + buf[2];
} else {
- /* current, voltage */
+ /* 12-bit current, voltage */
val = (buf[0] << 4) + (buf[1] >> 4);
}
@@ -92,9 +110,7 @@ static long long ltc2945_reg_to_val(struct device *dev, u8 reg)
case LTC2945_MAX_POWER_THRES_H:
case LTC2945_MIN_POWER_THRES_H:
/*
- * Convert to uW by assuming current is measured with
- * an 1mOhm sense resistor, similar to current
- * measurements.
+ * Convert to uW
* Control register bit 0 selects if voltage at SENSE+/VDD
* or voltage at ADIN is used to measure power.
*/
@@ -108,6 +124,14 @@ static long long ltc2945_reg_to_val(struct device *dev, u8 reg)
/* 0.5 mV * 25 uV = 0.0125 uV resolution. */
val = (val * 25LL) >> 1;
}
+ val *= 1000;
+ /* Overflow check: Assuming max 24-bit power, val is at most 53 bits right now. */
+ val = DIV_ROUND_CLOSEST_ULL(val, shunt_resistor);
+ /*
+ * Overflow check: After division, depending on shunt resistor,
+ * val can still be > 32 bits so returning long long makes sense
+ */
+
break;
case LTC2945_VIN_H:
case LTC2945_MAX_VIN_H:
@@ -130,14 +154,11 @@ static long long ltc2945_reg_to_val(struct device *dev, u8 reg)
case LTC2945_MIN_SENSE_H:
case LTC2945_MAX_SENSE_THRES_H:
case LTC2945_MIN_SENSE_THRES_H:
- /*
- * 25 uV resolution. Convert to current as measured with
- * an 1 mOhm sense resistor, in mA. If a different sense
- * resistor is installed, calculate the actual current by
- * dividing the reported current by the sense resistor value
- * in mOhm.
- */
- val *= 25;
+ /* 25 uV resolution. Convert to mA. */
+ val *= 25 * 1000;
+ /* Overflow check: Assuming max 12-bit sense, val is at most 27 bits right now */
+ val = DIV_ROUND_CLOSEST_ULL(val, shunt_resistor);
+ /* Overflow check: After division, <= 27 bits */
break;
default:
return -EINVAL;
@@ -145,13 +166,18 @@ static long long ltc2945_reg_to_val(struct device *dev, u8 reg)
return val;
}
-static int ltc2945_val_to_reg(struct device *dev, u8 reg,
- unsigned long val)
+static long long ltc2945_val_to_reg(struct device *dev, u8 reg,
+ unsigned long long val)
{
- struct regmap *regmap = dev_get_drvdata(dev);
+ struct ltc2945_data *data = dev_get_drvdata(dev);
+ struct regmap *regmap = data->regmap;
+ u32 shunt_resistor = data->shunt_resistor;
unsigned int control;
int ret;
+ /* Ensure we don't overflow */
+ val = clamp_val(val, 0, U32_MAX);
+
switch (reg) {
case LTC2945_POWER_H:
case LTC2945_MAX_POWER_H:
@@ -159,9 +185,6 @@ static int ltc2945_val_to_reg(struct device *dev, u8 reg,
case LTC2945_MAX_POWER_THRES_H:
case LTC2945_MIN_POWER_THRES_H:
/*
- * Convert to register value by assuming current is measured
- * with an 1mOhm sense resistor, similar to current
- * measurements.
* Control register bit 0 selects if voltage at SENSE+/VDD
* or voltage at ADIN is used to measure power, which in turn
* determines register calculations.
@@ -171,14 +194,16 @@ static int ltc2945_val_to_reg(struct device *dev, u8 reg,
return ret;
if (control & CONTROL_MULT_SELECT) {
/* 25 mV * 25 uV = 0.625 uV resolution. */
- val = DIV_ROUND_CLOSEST(val, 625);
+ val *= shunt_resistor;
+ /* Overflow check: Assuming 32-bit val and shunt resistor, val <= 64bits */
+ val = DIV_ROUND_CLOSEST_ULL(val, 625 * 1000);
+ /* Overflow check: val is now <= 44 bits */
} else {
- /*
- * 0.5 mV * 25 uV = 0.0125 uV resolution.
- * Divide first to avoid overflow;
- * accept loss of accuracy.
- */
- val = DIV_ROUND_CLOSEST(val, 25) * 2;
+ /* 0.5 mV * 25 uV = 0.0125 uV resolution. */
+ val *= shunt_resistor;
+ /* Overflow check: Assuming 32-bit val and shunt resistor, val <= 64bits */
+ val = DIV_ROUND_CLOSEST_ULL(val, 25 * 1000) * 2;
+ /* Overflow check: val is now <= 51 bits */
}
break;
case LTC2945_VIN_H:
@@ -187,7 +212,7 @@ static int ltc2945_val_to_reg(struct device *dev, u8 reg,
case LTC2945_MAX_VIN_THRES_H:
case LTC2945_MIN_VIN_THRES_H:
/* 25 mV resolution. */
- val /= 25;
+ val = DIV_ROUND_CLOSEST_ULL(val, 25);
break;
case LTC2945_ADIN_H:
case LTC2945_MAX_ADIN_H:
@@ -202,14 +227,11 @@ static int ltc2945_val_to_reg(struct device *dev, u8 reg,
case LTC2945_MIN_SENSE_H:
case LTC2945_MAX_SENSE_THRES_H:
case LTC2945_MIN_SENSE_THRES_H:
- /*
- * 25 uV resolution. Convert to current as measured with
- * an 1 mOhm sense resistor, in mA. If a different sense
- * resistor is installed, calculate the actual current by
- * dividing the reported current by the sense resistor value
- * in mOhm.
- */
- val = DIV_ROUND_CLOSEST(val, 25);
+ /* 25 uV resolution. Convert to mA. */
+ val *= shunt_resistor;
+ /* Overflow check: Assuming 32-bit val and 32-bit shunt resistor, val is 64bits */
+ val = DIV_ROUND_CLOSEST_ULL(val, 25 * 1000);
+ /* Overflow check: val is now <= 50 bits */
break;
default:
return -EINVAL;
@@ -234,20 +256,23 @@ static ssize_t ltc2945_value_store(struct device *dev,
const char *buf, size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
- struct regmap *regmap = dev_get_drvdata(dev);
+ struct ltc2945_data *data = dev_get_drvdata(dev);
+ struct regmap *regmap = data->regmap;
u8 reg = attr->index;
- unsigned long val;
+ unsigned int val;
u8 regbuf[3];
int num_regs;
- int regval;
+ long long regval;
int ret;
- ret = kstrtoul(buf, 10, &val);
+ ret = kstrtouint(buf, 10, &val);
if (ret)
return ret;
/* convert to register value, then clamp and write result */
regval = ltc2945_val_to_reg(dev, reg, val);
+ if (regval < 0)
+ return regval;
if (is_power_reg(reg)) {
regval = clamp_val(regval, 0, 0xffffff);
regbuf[0] = regval >> 16;
@@ -269,7 +294,8 @@ static ssize_t ltc2945_history_store(struct device *dev,
const char *buf, size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
- struct regmap *regmap = dev_get_drvdata(dev);
+ struct ltc2945_data *data = dev_get_drvdata(dev);
+ struct regmap *regmap = data->regmap;
u8 reg = attr->index;
int num_regs = is_power_reg(reg) ? 3 : 2;
u8 buf_min[3] = { 0xff, 0xff, 0xff };
@@ -321,7 +347,8 @@ static ssize_t ltc2945_bool_show(struct device *dev,
struct device_attribute *da, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
- struct regmap *regmap = dev_get_drvdata(dev);
+ struct ltc2945_data *data = dev_get_drvdata(dev);
+ struct regmap *regmap = data->regmap;
unsigned int fault;
int ret;
@@ -450,6 +477,12 @@ static int ltc2945_probe(struct i2c_client *client)
struct device *dev = &client->dev;
struct device *hwmon_dev;
struct regmap *regmap;
+ struct ltc2945_data *data;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+ dev_set_drvdata(dev, data);
regmap = devm_regmap_init_i2c(client, &ltc2945_regmap_config);
if (IS_ERR(regmap)) {
@@ -457,11 +490,19 @@ static int ltc2945_probe(struct i2c_client *client)
return PTR_ERR(regmap);
}
+ data->regmap = regmap;
+ if (device_property_read_u32(dev, "shunt-resistor-micro-ohms",
+ &data->shunt_resistor))
+ data->shunt_resistor = 1000;
+
+ if (data->shunt_resistor == 0)
+ return -EINVAL;
+
/* Clear faults */
regmap_write(regmap, LTC2945_FAULT, 0x00);
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
- regmap,
+ data,
ltc2945_groups);
return PTR_ERR_OR_ZERO(hwmon_dev);
}
@@ -475,8 +516,9 @@ MODULE_DEVICE_TABLE(i2c, ltc2945_id);
static struct i2c_driver ltc2945_driver = {
.driver = {
- .name = "ltc2945",
- },
+ .name = "ltc2945",
+ .of_match_table = of_match_ptr(ltc2945_of_match),
+ },
.probe_new = ltc2945_probe,
.id_table = ltc2945_id,
};
diff --git a/drivers/hwmon/mc34vr500.c b/drivers/hwmon/mc34vr500.c
new file mode 100644
index 000000000000..6268e973049c
--- /dev/null
+++ b/drivers/hwmon/mc34vr500.c
@@ -0,0 +1,263 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * An hwmon driver for the NXP MC34VR500 PMIC
+ *
+ * Author: Mario Kicherer <dev@kicherer.org>
+ */
+
+#include <linux/bits.h>
+#include <linux/dev_printk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/hwmon.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/irqreturn.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+
+#define MC34VR500_I2C_ADDR 0x08
+#define MC34VR500_DEVICEID_VALUE 0x14
+
+/* INTSENSE0 */
+#define ENS_BIT BIT(0)
+#define LOWVINS_BIT BIT(1)
+#define THERM110S_BIT BIT(2)
+#define THERM120S_BIT BIT(3)
+#define THERM125S_BIT BIT(4)
+#define THERM130S_BIT BIT(5)
+
+#define MC34VR500_DEVICEID 0x00
+
+#define MC34VR500_SILICONREVID 0x03
+#define MC34VR500_FABID 0x04
+#define MC34VR500_INTSTAT0 0x05
+#define MC34VR500_INTMASK0 0x06
+#define MC34VR500_INTSENSE0 0x07
+
+struct mc34vr500_data {
+ struct device *hwmon_dev;
+ struct regmap *regmap;
+};
+
+static irqreturn_t mc34vr500_process_interrupt(int irq, void *userdata)
+{
+ struct mc34vr500_data *data = (struct mc34vr500_data *)userdata;
+ unsigned int reg;
+ int ret;
+
+ ret = regmap_read(data->regmap, MC34VR500_INTSTAT0, &reg);
+ if (ret < 0)
+ return IRQ_HANDLED;
+
+ if (reg) {
+ if (reg & LOWVINS_BIT)
+ hwmon_notify_event(data->hwmon_dev, hwmon_in,
+ hwmon_in_min_alarm, 0);
+
+ if (reg & THERM110S_BIT)
+ hwmon_notify_event(data->hwmon_dev, hwmon_temp,
+ hwmon_temp_max_alarm, 0);
+
+ if (reg & THERM120S_BIT)
+ hwmon_notify_event(data->hwmon_dev, hwmon_temp,
+ hwmon_temp_crit_alarm, 0);
+
+ if (reg & THERM130S_BIT)
+ hwmon_notify_event(data->hwmon_dev, hwmon_temp,
+ hwmon_temp_emergency_alarm, 0);
+
+ /* write 1 to clear */
+ regmap_write(data->regmap, MC34VR500_INTSTAT0, LOWVINS_BIT |
+ THERM110S_BIT | THERM120S_BIT | THERM130S_BIT);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static umode_t mc34vr500_is_visible(const void *data,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ switch (attr) {
+ case hwmon_in_min_alarm:
+ case hwmon_temp_max_alarm:
+ case hwmon_temp_crit_alarm:
+ case hwmon_temp_emergency_alarm:
+ return 0444;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mc34vr500_alarm_read(struct mc34vr500_data *data, int index,
+ long *val)
+{
+ unsigned int reg;
+ int ret;
+
+ ret = regmap_read(data->regmap, MC34VR500_INTSENSE0, &reg);
+ if (ret < 0)
+ return ret;
+
+ *val = !!(reg & index);
+
+ return 0;
+}
+
+static int mc34vr500_read(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ struct mc34vr500_data *data = dev_get_drvdata(dev);
+
+ switch (type) {
+ case hwmon_in:
+ switch (attr) {
+ case hwmon_in_min_alarm:
+ return mc34vr500_alarm_read(data, LOWVINS_BIT, val);
+ default:
+ return -EOPNOTSUPP;
+ }
+ case hwmon_temp:
+ switch (attr) {
+ case hwmon_temp_max_alarm:
+ return mc34vr500_alarm_read(data, THERM110S_BIT, val);
+ case hwmon_temp_crit_alarm:
+ return mc34vr500_alarm_read(data, THERM120S_BIT, val);
+ case hwmon_temp_emergency_alarm:
+ return mc34vr500_alarm_read(data, THERM130S_BIT, val);
+ default:
+ return -EOPNOTSUPP;
+ }
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static const struct hwmon_channel_info *mc34vr500_info[] = {
+ HWMON_CHANNEL_INFO(in, HWMON_I_MIN_ALARM),
+ HWMON_CHANNEL_INFO(temp, HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM
+ | HWMON_T_EMERGENCY_ALARM),
+ NULL,
+};
+
+static const struct hwmon_ops mc34vr500_hwmon_ops = {
+ .is_visible = mc34vr500_is_visible,
+ .read = mc34vr500_read,
+};
+
+static const struct hwmon_chip_info mc34vr500_chip_info = {
+ .ops = &mc34vr500_hwmon_ops,
+ .info = mc34vr500_info,
+};
+
+static const struct regmap_config mc34vr500_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = MC34VR500_INTSENSE0,
+};
+
+static int mc34vr500_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct mc34vr500_data *data;
+ struct device *hwmon_dev;
+ int ret;
+ unsigned int reg, revid, fabid;
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init_i2c(client, &mc34vr500_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ data = devm_kzalloc(dev, sizeof(struct mc34vr500_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->regmap = regmap;
+
+ ret = regmap_read(regmap, MC34VR500_DEVICEID, &reg);
+ if (ret < 0)
+ return ret;
+
+ if (reg != MC34VR500_DEVICEID_VALUE)
+ return -ENODEV;
+
+ ret = regmap_read(regmap, MC34VR500_SILICONREVID, &revid);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_read(regmap, MC34VR500_FABID, &fabid);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(dev, "mc34vr500: revid 0x%x fabid 0x%x\n", revid, fabid);
+
+ hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name,
+ data,
+ &mc34vr500_chip_info,
+ NULL);
+ if (IS_ERR(hwmon_dev))
+ return PTR_ERR(hwmon_dev);
+
+ data->hwmon_dev = hwmon_dev;
+
+ if (client->irq) {
+ ret = devm_request_threaded_irq(dev, client->irq, NULL,
+ mc34vr500_process_interrupt,
+ IRQF_TRIGGER_RISING |
+ IRQF_ONESHOT |
+ IRQF_SHARED,
+ dev_name(dev), data);
+ if (ret)
+ return ret;
+
+ /* write 1 to clear interrupts */
+ ret = regmap_write(regmap, MC34VR500_INTSTAT0, LOWVINS_BIT |
+ THERM110S_BIT | THERM120S_BIT |
+ THERM130S_BIT);
+ if (ret)
+ return ret;
+
+ /* unmask interrupts */
+ ret = regmap_write(regmap, MC34VR500_INTMASK0,
+ (unsigned int) ~(LOWVINS_BIT | THERM110S_BIT |
+ THERM120S_BIT | THERM130S_BIT));
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct i2c_device_id mc34vr500_id[] = {
+ { "mc34vr500", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, mc34vr500_id);
+
+static const struct of_device_id __maybe_unused mc34vr500_of_match[] = {
+ { .compatible = "nxp,mc34vr500" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, mc34vr500_of_match);
+
+static struct i2c_driver mc34vr500_driver = {
+ .driver = {
+ .name = "mc34vr500",
+ .of_match_table = of_match_ptr(mc34vr500_of_match),
+ },
+ .probe_new = mc34vr500_probe,
+ .id_table = mc34vr500_id,
+};
+
+module_i2c_driver(mc34vr500_driver);
+
+MODULE_AUTHOR("Mario Kicherer <dev@kicherer.org>");
+
+MODULE_DESCRIPTION("MC34VR500 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/mlxreg-fan.c b/drivers/hwmon/mlxreg-fan.c
index b48bd7c961d6..96017cc8da7e 100644
--- a/drivers/hwmon/mlxreg-fan.c
+++ b/drivers/hwmon/mlxreg-fan.c
@@ -155,6 +155,12 @@ mlxreg_fan_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
if (err)
return err;
+ if (MLXREG_FAN_GET_FAULT(regval, tacho->mask)) {
+ /* FAN is broken - return zero for FAN speed. */
+ *val = 0;
+ return 0;
+ }
+
*val = MLXREG_FAN_GET_RPM(regval, fan->divider,
fan->samples);
break;
diff --git a/drivers/hwmon/nct6775-core.c b/drivers/hwmon/nct6775-core.c
index da9ec6983e13..c54233f0369b 100644
--- a/drivers/hwmon/nct6775-core.c
+++ b/drivers/hwmon/nct6775-core.c
@@ -1150,7 +1150,7 @@ static int nct6775_write_fan_div(struct nct6775_data *data, int nr)
if (err)
return err;
reg &= 0x70 >> oddshift;
- reg |= data->fan_div[nr] & (0x7 << oddshift);
+ reg |= (data->fan_div[nr] & 0x7) << oddshift;
return nct6775_write_value(data, fandiv_reg, reg);
}
diff --git a/drivers/hwmon/nct6775-platform.c b/drivers/hwmon/nct6775-platform.c
index bf43f73dc835..76c6b564d7fc 100644
--- a/drivers/hwmon/nct6775-platform.c
+++ b/drivers/hwmon/nct6775-platform.c
@@ -17,7 +17,6 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
-#include <linux/wmi.h>
#include "nct6775.h"
@@ -107,40 +106,51 @@ struct nct6775_sio_data {
void (*sio_exit)(struct nct6775_sio_data *sio_data);
};
-#define ASUSWMI_MONITORING_GUID "466747A0-70EC-11DE-8A39-0800200C9A66"
+#define ASUSWMI_METHOD "WMBD"
#define ASUSWMI_METHODID_RSIO 0x5253494F
#define ASUSWMI_METHODID_WSIO 0x5753494F
#define ASUSWMI_METHODID_RHWM 0x5248574D
#define ASUSWMI_METHODID_WHWM 0x5748574D
#define ASUSWMI_UNSUPPORTED_METHOD 0xFFFFFFFE
+#define ASUSWMI_DEVICE_HID "PNP0C14"
+#define ASUSWMI_DEVICE_UID "ASUSWMI"
+#define ASUSMSI_DEVICE_UID "AsusMbSwInterface"
+
+#if IS_ENABLED(CONFIG_ACPI)
+/*
+ * ASUS boards have only one device with WMI "WMBD" method and have provided
+ * access to only one SuperIO chip at 0x0290.
+ */
+static struct acpi_device *asus_acpi_dev;
+#endif
static int nct6775_asuswmi_evaluate_method(u32 method_id, u8 bank, u8 reg, u8 val, u32 *retval)
{
-#if IS_ENABLED(CONFIG_ACPI_WMI)
+#if IS_ENABLED(CONFIG_ACPI)
+ acpi_handle handle = acpi_device_handle(asus_acpi_dev);
u32 args = bank | (reg << 8) | (val << 16);
- struct acpi_buffer input = { (acpi_size) sizeof(args), &args };
- struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct acpi_object_list input;
+ union acpi_object params[3];
+ unsigned long long result;
acpi_status status;
- union acpi_object *obj;
- u32 tmp = ASUSWMI_UNSUPPORTED_METHOD;
-
- status = wmi_evaluate_method(ASUSWMI_MONITORING_GUID, 0,
- method_id, &input, &output);
+ params[0].type = ACPI_TYPE_INTEGER;
+ params[0].integer.value = 0;
+ params[1].type = ACPI_TYPE_INTEGER;
+ params[1].integer.value = method_id;
+ params[2].type = ACPI_TYPE_BUFFER;
+ params[2].buffer.length = sizeof(args);
+ params[2].buffer.pointer = (void *)&args;
+ input.count = 3;
+ input.pointer = params;
+
+ status = acpi_evaluate_integer(handle, ASUSWMI_METHOD, &input, &result);
if (ACPI_FAILURE(status))
return -EIO;
- obj = output.pointer;
- if (obj && obj->type == ACPI_TYPE_INTEGER)
- tmp = obj->integer.value;
-
if (retval)
- *retval = tmp;
-
- kfree(obj);
+ *retval = (u32)result & 0xFFFFFFFF;
- if (tmp == ASUSWMI_UNSUPPORTED_METHOD)
- return -ENODEV;
return 0;
#else
return -EOPNOTSUPP;
@@ -1099,6 +1109,91 @@ static const char * const asus_wmi_boards[] = {
"TUF GAMING Z490-PLUS (WI-FI)",
};
+static const char * const asus_msi_boards[] = {
+ "EX-B660M-V5 PRO D4",
+ "PRIME B650-PLUS",
+ "PRIME B650M-A",
+ "PRIME B650M-A AX",
+ "PRIME B650M-A II",
+ "PRIME B650M-A WIFI",
+ "PRIME B650M-A WIFI II",
+ "PRIME B660M-A D4",
+ "PRIME B660M-A WIFI D4",
+ "PRIME X670-P",
+ "PRIME X670-P WIFI",
+ "PRIME X670E-PRO WIFI",
+ "Pro B660M-C-D4",
+ "ProArt B660-CREATOR D4",
+ "ProArt X670E-CREATOR WIFI",
+ "ROG CROSSHAIR X670E EXTREME",
+ "ROG CROSSHAIR X670E GENE",
+ "ROG CROSSHAIR X670E HERO",
+ "ROG MAXIMUS XIII EXTREME GLACIAL",
+ "ROG MAXIMUS Z690 EXTREME",
+ "ROG MAXIMUS Z690 EXTREME GLACIAL",
+ "ROG STRIX B650-A GAMING WIFI",
+ "ROG STRIX B650E-E GAMING WIFI",
+ "ROG STRIX B650E-F GAMING WIFI",
+ "ROG STRIX B650E-I GAMING WIFI",
+ "ROG STRIX B660-A GAMING WIFI D4",
+ "ROG STRIX B660-F GAMING WIFI",
+ "ROG STRIX B660-G GAMING WIFI",
+ "ROG STRIX B660-I GAMING WIFI",
+ "ROG STRIX X670E-A GAMING WIFI",
+ "ROG STRIX X670E-E GAMING WIFI",
+ "ROG STRIX X670E-F GAMING WIFI",
+ "ROG STRIX X670E-I GAMING WIFI",
+ "ROG STRIX Z590-A GAMING WIFI II",
+ "ROG STRIX Z690-A GAMING WIFI D4",
+ "TUF GAMING B650-PLUS",
+ "TUF GAMING B650-PLUS WIFI",
+ "TUF GAMING B650M-PLUS",
+ "TUF GAMING B650M-PLUS WIFI",
+ "TUF GAMING B660M-PLUS WIFI",
+ "TUF GAMING X670E-PLUS",
+ "TUF GAMING X670E-PLUS WIFI",
+ "TUF GAMING Z590-PLUS WIFI",
+};
+
+#if IS_ENABLED(CONFIG_ACPI)
+/*
+ * Callback for acpi_bus_for_each_dev() to find the right device
+ * by _UID and _HID and return 1 to stop iteration.
+ */
+static int nct6775_asuswmi_device_match(struct device *dev, void *data)
+{
+ struct acpi_device *adev = to_acpi_device(dev);
+ const char *uid = acpi_device_uid(adev);
+ const char *hid = acpi_device_hid(adev);
+
+ if (hid && !strcmp(hid, ASUSWMI_DEVICE_HID) && uid && !strcmp(uid, data)) {
+ asus_acpi_dev = adev;
+ return 1;
+ }
+
+ return 0;
+}
+#endif
+
+static enum sensor_access nct6775_determine_access(const char *device_uid)
+{
+#if IS_ENABLED(CONFIG_ACPI)
+ u8 tmp;
+
+ acpi_bus_for_each_dev(nct6775_asuswmi_device_match, (void *)device_uid);
+ if (!asus_acpi_dev)
+ return access_direct;
+
+ /* if reading chip id via ACPI succeeds, use WMI "WMBD" method for access */
+ if (!nct6775_asuswmi_read(0, NCT6775_PORT_CHIPID, &tmp) && tmp) {
+ pr_debug("Using Asus WMBD method of %s to access %#x chip.\n", device_uid, tmp);
+ return access_asuswmi;
+ }
+#endif
+
+ return access_direct;
+}
+
static int __init sensors_nct6775_platform_init(void)
{
int i, err;
@@ -1109,7 +1204,6 @@ static int __init sensors_nct6775_platform_init(void)
int sioaddr[2] = { 0x2e, 0x4e };
enum sensor_access access = access_direct;
const char *board_vendor, *board_name;
- u8 tmp;
err = platform_driver_register(&nct6775_driver);
if (err)
@@ -1122,15 +1216,13 @@ static int __init sensors_nct6775_platform_init(void)
!strcmp(board_vendor, "ASUSTeK COMPUTER INC.")) {
err = match_string(asus_wmi_boards, ARRAY_SIZE(asus_wmi_boards),
board_name);
- if (err >= 0) {
- /* if reading chip id via WMI succeeds, use WMI */
- if (!nct6775_asuswmi_read(0, NCT6775_PORT_CHIPID, &tmp) && tmp) {
- pr_info("Using Asus WMI to access %#x chip.\n", tmp);
- access = access_asuswmi;
- } else {
- pr_err("Can't read ChipID by Asus WMI.\n");
- }
- }
+ if (err >= 0)
+ access = nct6775_determine_access(ASUSWMI_DEVICE_UID);
+
+ err = match_string(asus_msi_boards, ARRAY_SIZE(asus_msi_boards),
+ board_name);
+ if (err >= 0)
+ access = nct6775_determine_access(ASUSMSI_DEVICE_UID);
}
/*
diff --git a/drivers/hwmon/nzxt-smart2.c b/drivers/hwmon/nzxt-smart2.c
index 533f38b0b4e9..2b93ba89610a 100644
--- a/drivers/hwmon/nzxt-smart2.c
+++ b/drivers/hwmon/nzxt-smart2.c
@@ -791,6 +791,7 @@ static const struct hid_device_id nzxt_smart2_hid_id_table[] = {
{ HID_USB_DEVICE(0x1e71, 0x2009) }, /* NZXT RGB & Fan Controller */
{ HID_USB_DEVICE(0x1e71, 0x200e) }, /* NZXT RGB & Fan Controller */
{ HID_USB_DEVICE(0x1e71, 0x2010) }, /* NZXT RGB & Fan Controller */
+ { HID_USB_DEVICE(0x1e71, 0x2019) }, /* NZXT RGB & Fan Controller */
{},
};
diff --git a/drivers/hwmon/oxp-sensors.c b/drivers/hwmon/oxp-sensors.c
index f84ec8f8eda9..36872b57912a 100644
--- a/drivers/hwmon/oxp-sensors.c
+++ b/drivers/hwmon/oxp-sensors.c
@@ -1,12 +1,12 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Platform driver for OXP Handhelds that expose fan reading and control
- * via hwmon sysfs.
+ * Platform driver for OneXPlayer, AOK ZOE, and Aya Neo Handhelds that expose
+ * fan reading and control via hwmon sysfs.
*
- * Old boards have the same DMI strings and they are told appart by the
- * boot cpu vendor (Intel/AMD). Currently only AMD boards are supported
- * but the code is made to be simple to add other handheld boards in the
- * future.
+ * Old OXP boards have the same DMI strings and they are told apart by
+ * the boot cpu vendor (Intel/AMD). Currently only AMD boards are
+ * supported but the code is made to be simple to add other handheld
+ * boards in the future.
* Fan control is provided via pwm interface in the range [0-255].
* Old AMD boards use [0-100] as range in the EC, the written value is
* scaled to accommodate for that. Newer boards like the mini PRO and
@@ -42,6 +42,8 @@ static bool unlock_global_acpi_lock(void)
enum oxp_board {
aok_zoe_a1 = 1,
+ aya_neo_air,
+ aya_neo_air_pro,
oxp_mini_amd,
oxp_mini_amd_pro,
};
@@ -62,6 +64,20 @@ static const struct dmi_system_id dmi_table[] = {
},
{
.matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR"),
+ },
+ .driver_data = (void *) &(enum oxp_board) {aya_neo_air},
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR Pro"),
+ },
+ .driver_data = (void *) &(enum oxp_board) {aya_neo_air_pro},
+ },
+ {
+ .matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONE XPLAYER"),
},
@@ -161,8 +177,17 @@ static int oxp_platform_read(struct device *dev, enum hwmon_sensor_types type,
ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val);
if (ret)
return ret;
- if (board == oxp_mini_amd)
+ switch (board) {
+ case aya_neo_air:
+ case aya_neo_air_pro:
+ case oxp_mini_amd:
*val = (*val * 255) / 100;
+ break;
+ case oxp_mini_amd_pro:
+ case aok_zoe_a1:
+ default:
+ break;
+ }
return 0;
case hwmon_pwm_enable:
return read_from_ec(OXP_SENSOR_PWM_ENABLE_REG, 1, val);
@@ -191,8 +216,17 @@ static int oxp_platform_write(struct device *dev, enum hwmon_sensor_types type,
case hwmon_pwm_input:
if (val < 0 || val > 255)
return -EINVAL;
- if (board == oxp_mini_amd)
+ switch (board) {
+ case aya_neo_air:
+ case aya_neo_air_pro:
+ case oxp_mini_amd:
val = (val * 100) / 255;
+ break;
+ case aok_zoe_a1:
+ case oxp_mini_amd_pro:
+ default:
+ break;
+ }
return write_to_ec(dev, OXP_SENSOR_PWM_REG, val);
default:
break;
@@ -233,7 +267,7 @@ static int oxp_platform_probe(struct platform_device *pdev)
/*
* Have to check for AMD processor here because DMI strings are the
- * same between Intel and AMD boards, the only way to tell them appart
+ * same between Intel and AMD boards, the only way to tell them apart
* is the CPU.
* Intel boards seem to have different EC registers and values to
* read/write.
diff --git a/drivers/hwmon/peci/cputemp.c b/drivers/hwmon/peci/cputemp.c
index 57470fda5f6c..30850a479f61 100644
--- a/drivers/hwmon/peci/cputemp.c
+++ b/drivers/hwmon/peci/cputemp.c
@@ -402,7 +402,7 @@ static int create_temp_label(struct peci_cputemp *priv)
unsigned long core_max = find_last_bit(priv->core_mask, CORE_NUMS_MAX);
int i;
- priv->coretemp_label = devm_kzalloc(priv->dev, core_max * sizeof(char *), GFP_KERNEL);
+ priv->coretemp_label = devm_kzalloc(priv->dev, (core_max + 1) * sizeof(char *), GFP_KERNEL);
if (!priv->coretemp_label)
return -ENOMEM;
diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig
index 89668af67206..59d9a7430499 100644
--- a/drivers/hwmon/pmbus/Kconfig
+++ b/drivers/hwmon/pmbus/Kconfig
@@ -237,10 +237,10 @@ config SENSORS_MAX16064
be called max16064.
config SENSORS_MAX16601
- tristate "Maxim MAX16508, MAX16601, MAX16602"
+ tristate "Maxim MAX16508, MAX16600, MAX16601, and MAX16602"
help
If you say yes here you get hardware monitoring support for Maxim
- MAX16508, MAX16601 and MAX16602.
+ MAX16508, MAX16600, MAX16601, and MAX16602.
This driver can also be built as a module. If so, the module will
be called max16601.
@@ -317,6 +317,22 @@ config SENSORS_MP5023
This driver can also be built as a module. If so, the module will
be called mp5023.
+config SENSORS_MPQ7932_REGULATOR
+ bool "Regulator support for MPQ7932"
+ depends on SENSORS_MPQ7932 && REGULATOR
+ help
+ If you say yes here you get six integrated buck converter regulator
+ support for power management IC MPS MPQ7932.
+
+config SENSORS_MPQ7932
+ tristate "MPS MPQ7932"
+ help
+ If you say yes here you get hardware monitoring functionality support
+ for power management IC MPS MPQ7932.
+
+ This driver can also be built as a module. If so, the module will
+ be called mpq7932.
+
config SENSORS_PIM4328
tristate "Flex PIM4328 and compatibles"
help
@@ -379,6 +395,22 @@ config SENSORS_STPDDC60
This driver can also be built as a module. If so, the module will
be called stpddc60.
+config SENSORS_TDA38640
+ tristate "Infineon TDA38640"
+ help
+ If you say yes here you get hardware monitoring support for Infineon
+ TDA38640.
+
+ This driver can also be built as a module. If so, the module will
+ be called tda38640.
+
+config SENSORS_TDA38640_REGULATOR
+ bool "Regulator support for TDA38640 and compatibles"
+ depends on SENSORS_TDA38640 && REGULATOR
+ help
+ If you say yes here you get regulator support for Infineon
+ TDA38640 as regulator.
+
config SENSORS_TPS40422
tristate "TI TPS40422"
help
diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile
index 0002dbe22d52..3ae019916267 100644
--- a/drivers/hwmon/pmbus/Makefile
+++ b/drivers/hwmon/pmbus/Makefile
@@ -34,11 +34,13 @@ obj-$(CONFIG_SENSORS_MAX8688) += max8688.o
obj-$(CONFIG_SENSORS_MP2888) += mp2888.o
obj-$(CONFIG_SENSORS_MP2975) += mp2975.o
obj-$(CONFIG_SENSORS_MP5023) += mp5023.o
+obj-$(CONFIG_SENSORS_MPQ7932) += mpq7932.o
obj-$(CONFIG_SENSORS_PLI1209BC) += pli1209bc.o
obj-$(CONFIG_SENSORS_PM6764TR) += pm6764tr.o
obj-$(CONFIG_SENSORS_PXE1610) += pxe1610.o
obj-$(CONFIG_SENSORS_Q54SJ108A2) += q54sj108a2.o
obj-$(CONFIG_SENSORS_STPDDC60) += stpddc60.o
+obj-$(CONFIG_SENSORS_TDA38640) += tda38640.o
obj-$(CONFIG_SENSORS_TPS40422) += tps40422.o
obj-$(CONFIG_SENSORS_TPS53679) += tps53679.o
obj-$(CONFIG_SENSORS_TPS546D24) += tps546d24.o
diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c
index 79f480b4425d..91df8e895147 100644
--- a/drivers/hwmon/pmbus/ltc2978.c
+++ b/drivers/hwmon/pmbus/ltc2978.c
@@ -570,14 +570,14 @@ MODULE_DEVICE_TABLE(i2c, ltc2978_id);
#define LTC2978_N_VOLTAGES ((LTC2978_MAX_UV / LTC2978_UV_STEP) + 1)
static const struct regulator_desc ltc2978_reg_desc[] = {
- PMBUS_REGULATOR_STEP("vout", 0, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
- PMBUS_REGULATOR_STEP("vout", 1, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
- PMBUS_REGULATOR_STEP("vout", 2, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
- PMBUS_REGULATOR_STEP("vout", 3, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
- PMBUS_REGULATOR_STEP("vout", 4, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
- PMBUS_REGULATOR_STEP("vout", 5, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
- PMBUS_REGULATOR_STEP("vout", 6, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
- PMBUS_REGULATOR_STEP("vout", 7, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
+ PMBUS_REGULATOR_STEP("vout", 0, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0),
+ PMBUS_REGULATOR_STEP("vout", 1, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0),
+ PMBUS_REGULATOR_STEP("vout", 2, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0),
+ PMBUS_REGULATOR_STEP("vout", 3, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0),
+ PMBUS_REGULATOR_STEP("vout", 4, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0),
+ PMBUS_REGULATOR_STEP("vout", 5, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0),
+ PMBUS_REGULATOR_STEP("vout", 6, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0),
+ PMBUS_REGULATOR_STEP("vout", 7, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0),
};
static const struct regulator_desc ltc2978_reg_desc_default[] = {
diff --git a/drivers/hwmon/pmbus/max16601.c b/drivers/hwmon/pmbus/max16601.c
index b628405e6586..6724f723f74c 100644
--- a/drivers/hwmon/pmbus/max16601.c
+++ b/drivers/hwmon/pmbus/max16601.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * Hardware monitoring driver for Maxim MAX16508, MAX16601 and MAX16602.
+ * Hardware monitoring driver for Maxim MAX16508, MAX16600, MAX16601,
+ * and MAX16602.
*
* Implementation notes:
*
@@ -31,7 +32,7 @@
#include "pmbus.h"
-enum chips { max16508, max16601, max16602 };
+enum chips { max16508, max16600, max16601, max16602 };
#define REG_DEFAULT_NUM_POP 0xc4
#define REG_SETPT_DVID 0xd1
@@ -202,7 +203,7 @@ static int max16601_identify(struct i2c_client *client,
else
info->vrm_version[0] = vr12;
- if (data->id != max16601 && data->id != max16602)
+ if (data->id != max16600 && data->id != max16601 && data->id != max16602)
return 0;
reg = i2c_smbus_read_byte_data(client, REG_DEFAULT_NUM_POP);
@@ -263,6 +264,7 @@ static void max16601_remove(void *_data)
static const struct i2c_device_id max16601_id[] = {
{"max16508", max16508},
+ {"max16600", max16600},
{"max16601", max16601},
{"max16602", max16602},
{}
@@ -281,11 +283,13 @@ static int max16601_get_id(struct i2c_client *client)
return -ENODEV;
/*
- * PMBUS_IC_DEVICE_ID is expected to return "MAX16601y.xx" or
- * MAX16602y.xx or "MAX16500y.xx".cdxxcccccccccc
+ * PMBUS_IC_DEVICE_ID is expected to return MAX1660[012]y.xx" or
+ * "MAX16500y.xx".cdxxcccccccccc
*/
if (!strncmp(buf, "MAX16500", 8)) {
id = max16508;
+ } else if (!strncmp(buf, "MAX16600", 8)) {
+ id = max16600;
} else if (!strncmp(buf, "MAX16601", 8)) {
id = max16601;
} else if (!strncmp(buf, "MAX16602", 8)) {
diff --git a/drivers/hwmon/pmbus/mpq7932.c b/drivers/hwmon/pmbus/mpq7932.c
new file mode 100644
index 000000000000..ff939881dc3b
--- /dev/null
+++ b/drivers/hwmon/pmbus/mpq7932.c
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * mpq7932.c - hwmon with optional regulator driver for mps mpq7932
+ * Copyright 2022 Monolithic Power Systems, Inc
+ *
+ * Author: Saravanan Sekar <saravanan@linumiz.com>
+ */
+
+#include <linux/bits.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/pmbus.h>
+#include "pmbus.h"
+
+#define MPQ7932_BUCK_UV_MIN 206250
+#define MPQ7932_UV_STEP 6250
+#define MPQ7932_N_VOLTAGES 256
+#define MPQ7932_VOUT_MAX 0xFF
+#define MPQ7932_NUM_PAGES 6
+
+#define MPQ7932_TON_DELAY 0x60
+#define MPQ7932_VOUT_STARTUP_SLEW 0xA3
+#define MPQ7932_VOUT_SHUTDOWN_SLEW 0xA5
+#define MPQ7932_VOUT_SLEW_MASK GENMASK(1, 0)
+#define MPQ7932_TON_DELAY_MASK GENMASK(4, 0)
+
+struct mpq7932_data {
+ struct pmbus_driver_info info;
+ struct pmbus_platform_data pdata;
+};
+
+#if IS_ENABLED(CONFIG_SENSORS_MPQ7932_REGULATOR)
+static struct regulator_desc mpq7932_regulators_desc[] = {
+ PMBUS_REGULATOR_STEP("buck", 0, MPQ7932_N_VOLTAGES,
+ MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN),
+ PMBUS_REGULATOR_STEP("buck", 1, MPQ7932_N_VOLTAGES,
+ MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN),
+ PMBUS_REGULATOR_STEP("buck", 2, MPQ7932_N_VOLTAGES,
+ MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN),
+ PMBUS_REGULATOR_STEP("buck", 3, MPQ7932_N_VOLTAGES,
+ MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN),
+ PMBUS_REGULATOR_STEP("buck", 4, MPQ7932_N_VOLTAGES,
+ MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN),
+ PMBUS_REGULATOR_STEP("buck", 5, MPQ7932_N_VOLTAGES,
+ MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN),
+};
+#endif
+
+static int mpq7932_write_word_data(struct i2c_client *client, int page, int reg,
+ u16 word)
+{
+ switch (reg) {
+ /*
+ * chip supports only byte access for VOUT_COMMAND otherwise
+ * access results -EREMOTEIO
+ */
+ case PMBUS_VOUT_COMMAND:
+ return pmbus_write_byte_data(client, page, reg, word & 0xFF);
+
+ default:
+ return -ENODATA;
+ }
+}
+
+static int mpq7932_read_word_data(struct i2c_client *client, int page,
+ int phase, int reg)
+{
+ switch (reg) {
+ /*
+ * chip supports neither (PMBUS_VOUT_MARGIN_HIGH, PMBUS_VOUT_MARGIN_LOW)
+ * nor (PMBUS_MFR_VOUT_MIN, PMBUS_MFR_VOUT_MAX). As a result set voltage
+ * fails due to error in pmbus_regulator_get_low_margin, so faked.
+ */
+ case PMBUS_MFR_VOUT_MIN:
+ return 0;
+
+ case PMBUS_MFR_VOUT_MAX:
+ return MPQ7932_VOUT_MAX;
+
+ /*
+ * chip supports only byte access for VOUT_COMMAND otherwise
+ * access results in -EREMOTEIO
+ */
+ case PMBUS_READ_VOUT:
+ return pmbus_read_byte_data(client, page, PMBUS_VOUT_COMMAND);
+
+ default:
+ return -ENODATA;
+ }
+}
+
+static int mpq7932_probe(struct i2c_client *client)
+{
+ struct mpq7932_data *data;
+ struct pmbus_driver_info *info;
+ struct device *dev = &client->dev;
+ int i;
+
+ data = devm_kzalloc(dev, sizeof(struct mpq7932_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ info = &data->info;
+ info->pages = MPQ7932_NUM_PAGES;
+ info->format[PSC_VOLTAGE_OUT] = direct;
+ info->m[PSC_VOLTAGE_OUT] = 160;
+ info->b[PSC_VOLTAGE_OUT] = -33;
+ for (i = 0; i < info->pages; i++) {
+ info->func[i] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+ | PMBUS_HAVE_STATUS_TEMP;
+ }
+
+#if IS_ENABLED(CONFIG_SENSORS_MPQ7932_REGULATOR)
+ info->num_regulators = ARRAY_SIZE(mpq7932_regulators_desc);
+ info->reg_desc = mpq7932_regulators_desc;
+#endif
+
+ info->read_word_data = mpq7932_read_word_data;
+ info->write_word_data = mpq7932_write_word_data;
+
+ data->pdata.flags = PMBUS_NO_CAPABILITY;
+ dev->platform_data = &data->pdata;
+
+ return pmbus_do_probe(client, info);
+}
+
+static const struct of_device_id mpq7932_of_match[] = {
+ { .compatible = "mps,mpq7932"},
+ {},
+};
+MODULE_DEVICE_TABLE(of, mpq7932_of_match);
+
+static const struct i2c_device_id mpq7932_id[] = {
+ { "mpq7932", },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, mpq7932_id);
+
+static struct i2c_driver mpq7932_regulator_driver = {
+ .driver = {
+ .name = "mpq7932",
+ .of_match_table = mpq7932_of_match,
+ },
+ .probe_new = mpq7932_probe,
+ .id_table = mpq7932_id,
+};
+module_i2c_driver(mpq7932_regulator_driver);
+
+MODULE_AUTHOR("Saravanan Sekar <saravanan@linumiz.com>");
+MODULE_DESCRIPTION("MPQ7932 PMIC regulator driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h
index 10fb17879f8e..713ea7915425 100644
--- a/drivers/hwmon/pmbus/pmbus.h
+++ b/drivers/hwmon/pmbus/pmbus.h
@@ -464,7 +464,7 @@ struct pmbus_driver_info {
extern const struct regulator_ops pmbus_regulator_ops;
/* Macros for filling in array of struct regulator_desc */
-#define PMBUS_REGULATOR_STEP(_name, _id, _voltages, _step) \
+#define PMBUS_REGULATOR_STEP(_name, _id, _voltages, _step, _min_uV) \
[_id] = { \
.name = (_name # _id), \
.id = (_id), \
@@ -475,9 +475,10 @@ extern const struct regulator_ops pmbus_regulator_ops;
.owner = THIS_MODULE, \
.n_voltages = _voltages, \
.uV_step = _step, \
+ .min_uV = _min_uV, \
}
-#define PMBUS_REGULATOR(_name, _id) PMBUS_REGULATOR_STEP(_name, _id, 0, 0)
+#define PMBUS_REGULATOR(_name, _id) PMBUS_REGULATOR_STEP(_name, _id, 0, 0, 0)
/* Function declarations */
diff --git a/drivers/hwmon/pmbus/tda38640.c b/drivers/hwmon/pmbus/tda38640.c
new file mode 100644
index 000000000000..c3e781319cd1
--- /dev/null
+++ b/drivers/hwmon/pmbus/tda38640.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Hardware monitoring driver for Infineon TDA38640
+ *
+ * Copyright (c) 2023 9elements GmbH
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/regulator/driver.h>
+#include "pmbus.h"
+
+static const struct regulator_desc __maybe_unused tda38640_reg_desc[] = {
+ PMBUS_REGULATOR("vout", 0),
+};
+
+static struct pmbus_driver_info tda38640_info = {
+ .pages = 1,
+ .format[PSC_VOLTAGE_IN] = linear,
+ .format[PSC_VOLTAGE_OUT] = linear,
+ .format[PSC_CURRENT_OUT] = linear,
+ .format[PSC_CURRENT_IN] = linear,
+ .format[PSC_POWER] = linear,
+ .format[PSC_TEMPERATURE] = linear,
+
+ .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
+ | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP
+ | PMBUS_HAVE_IIN
+ | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+ | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
+ | PMBUS_HAVE_POUT | PMBUS_HAVE_PIN,
+#if IS_ENABLED(CONFIG_SENSORS_TDA38640_REGULATOR)
+ .num_regulators = 1,
+ .reg_desc = tda38640_reg_desc,
+#endif
+};
+
+static int tda38640_probe(struct i2c_client *client)
+{
+ return pmbus_do_probe(client, &tda38640_info);
+}
+
+static const struct i2c_device_id tda38640_id[] = {
+ {"tda38640", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, tda38640_id);
+
+static const struct of_device_id __maybe_unused tda38640_of_match[] = {
+ { .compatible = "infineon,tda38640"},
+ { },
+};
+MODULE_DEVICE_TABLE(of, tda38640_of_match);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver tda38640_driver = {
+ .driver = {
+ .name = "tda38640",
+ .of_match_table = of_match_ptr(tda38640_of_match),
+ },
+ .probe_new = tda38640_probe,
+ .id_table = tda38640_id,
+};
+
+module_i2c_driver(tda38640_driver);
+
+MODULE_AUTHOR("Patrick Rudolph <patrick.rudolph@9elements.com>");
+MODULE_DESCRIPTION("PMBus driver for Infineon TDA38640");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c
index ae4d14257a11..32a41fc56fc9 100644
--- a/drivers/hwmon/sht15.c
+++ b/drivers/hwmon/sht15.c
@@ -668,7 +668,7 @@ static inline int sht15_calc_humid(struct sht15_data *data)
}
/**
- * sht15_show_status() - show status information in sysfs
+ * sht15_status_show() - show status information in sysfs
* @dev: device.
* @attr: device attribute.
* @buf: sysfs buffer where information is written to.
@@ -690,7 +690,7 @@ static ssize_t sht15_status_show(struct device *dev,
}
/**
- * sht15_store_heater() - change heater state via sysfs
+ * sht15_status_store() - change heater state via sysfs
* @dev: device.
* @attr: device attribute.
* @buf: sysfs buffer to read the new heater state from.
@@ -725,7 +725,7 @@ static ssize_t sht15_status_store(struct device *dev,
}
/**
- * sht15_show_temp() - show temperature measurement value in sysfs
+ * sht15_temp_show() - show temperature measurement value in sysfs
* @dev: device.
* @attr: device attribute.
* @buf: sysfs buffer where measurement values are written to.
@@ -747,7 +747,7 @@ static ssize_t sht15_temp_show(struct device *dev,
}
/**
- * sht15_show_humidity() - show humidity measurement value in sysfs
+ * sht15_humidity_show() - show humidity measurement value in sysfs
* @dev: device.
* @attr: device attribute.
* @buf: sysfs buffer where measurement values are written to.
diff --git a/drivers/hwmon/sht21.c b/drivers/hwmon/sht21.c
index e23dbf287233..f50b90198f23 100644
--- a/drivers/hwmon/sht21.c
+++ b/drivers/hwmon/sht21.c
@@ -114,7 +114,7 @@ out:
}
/**
- * sht21_show_temperature() - show temperature measurement value in sysfs
+ * sht21_temperature_show() - show temperature measurement value in sysfs
* @dev: device
* @attr: device attribute
* @buf: sysfs buffer (PAGE_SIZE) where measurement values are written to
@@ -136,7 +136,7 @@ static ssize_t sht21_temperature_show(struct device *dev,
}
/**
- * sht21_show_humidity() - show humidity measurement value in sysfs
+ * sht21_humidity_show() - show humidity measurement value in sysfs
* @dev: device
* @attr: device attribute
* @buf: sysfs buffer (PAGE_SIZE) where measurement values are written to
diff --git a/drivers/hwspinlock/hwspinlock_core.c b/drivers/hwspinlock/hwspinlock_core.c
index fd5f5c5a5244..22b8f2a70b3b 100644
--- a/drivers/hwspinlock/hwspinlock_core.c
+++ b/drivers/hwspinlock/hwspinlock_core.c
@@ -367,7 +367,7 @@ int of_hwspin_lock_get_id(struct device_node *np, int index)
continue;
}
- if (hwlock->bank->dev->of_node == args.np) {
+ if (device_match_of_node(hwlock->bank->dev, args.np)) {
ret = 0;
break;
}
diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/coresight/Kconfig
index 45c1eb5dfcb7..2b5bbfffbc4f 100644
--- a/drivers/hwtracing/coresight/Kconfig
+++ b/drivers/hwtracing/coresight/Kconfig
@@ -201,4 +201,39 @@ config CORESIGHT_TRBE
To compile this driver as a module, choose M here: the module will be
called coresight-trbe.
+
+config ULTRASOC_SMB
+ tristate "Ultrasoc system memory buffer drivers"
+ depends on ACPI || COMPILE_TEST
+ depends on ARM64 && CORESIGHT_LINKS_AND_SINKS
+ help
+ This driver provides support for the Ultrasoc system memory buffer (SMB).
+ SMB is responsible for receiving the trace data from Coresight ETM devices
+ and storing them to a system buffer.
+
+ To compile this driver as a module, choose M here: the module will be
+ called ultrasoc-smb.
+
+config CORESIGHT_TPDM
+ tristate "CoreSight Trace, Profiling & Diagnostics Monitor driver"
+ select CORESIGHT_LINKS_AND_SINKS
+ select CORESIGHT_TPDA
+ help
+ This driver provides support for configuring monitor. Monitors are
+ primarily responsible for data set collection and support the
+ ability to collect any permutation of data set types.
+
+ To compile this driver as a module, choose M here: the module will be
+ called coresight-tpdm.
+
+config CORESIGHT_TPDA
+ tristate "CoreSight Trace, Profiling & Diagnostics Aggregator driver"
+ help
+ This driver provides support for configuring aggregator. This is
+ primarily useful for pulling the data sets from one or more
+ attached monitors and pushing the resultant data out. Multiple
+ monitors are connected on different input ports of TPDA.
+
+ To compile this driver as a module, choose M here: the module will be
+ called coresight-tpda.
endif
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile
index b6c4a48140ec..33bcc3f7b8ae 100644
--- a/drivers/hwtracing/coresight/Makefile
+++ b/drivers/hwtracing/coresight/Makefile
@@ -6,7 +6,7 @@ obj-$(CONFIG_CORESIGHT) += coresight.o
coresight-y := coresight-core.o coresight-etm-perf.o coresight-platform.o \
coresight-sysfs.o coresight-syscfg.o coresight-config.o \
coresight-cfg-preload.o coresight-cfg-afdo.o \
- coresight-syscfg-configfs.o
+ coresight-syscfg-configfs.o coresight-trace-id.o
obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o
coresight-tmc-y := coresight-tmc-core.o coresight-tmc-etf.o \
coresight-tmc-etr.o
@@ -25,5 +25,8 @@ obj-$(CONFIG_CORESIGHT_CPU_DEBUG) += coresight-cpu-debug.o
obj-$(CONFIG_CORESIGHT_CATU) += coresight-catu.o
obj-$(CONFIG_CORESIGHT_CTI) += coresight-cti.o
obj-$(CONFIG_CORESIGHT_TRBE) += coresight-trbe.o
+obj-$(CONFIG_CORESIGHT_TPDM) += coresight-tpdm.o
+obj-$(CONFIG_CORESIGHT_TPDA) += coresight-tpda.o
coresight-cti-y := coresight-cti-core.o coresight-cti-platform.o \
coresight-cti-sysfs.o
+obj-$(CONFIG_ULTRASOC_SMB) += ultrasoc-smb.o
diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index f3068175ca9d..d3bf82c0de1d 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -8,6 +8,7 @@
#include <linux/types.h>
#include <linux/device.h>
#include <linux/io.h>
+#include <linux/idr.h>
#include <linux/err.h>
#include <linux/export.h>
#include <linux/slab.h>
@@ -26,6 +27,13 @@
static DEFINE_MUTEX(coresight_mutex);
static DEFINE_PER_CPU(struct coresight_device *, csdev_sink);
+/*
+ * Use IDR to map the hash of the source's device name
+ * to the pointer of path for the source. The idr is for
+ * the sources which aren't associated with CPU.
+ */
+static DEFINE_IDR(path_idr);
+
/**
* struct coresight_node - elements of a path, from source to sink
* @csdev: Address of an element.
@@ -43,14 +51,6 @@ struct coresight_node {
static DEFINE_PER_CPU(struct list_head *, tracer_path);
/*
- * As of this writing only a single STM can be found in CS topologies. Since
- * there is no way to know if we'll ever see more and what kind of
- * configuration they will enact, for the time being only define a single path
- * for STM.
- */
-static struct list_head *stm_path;
-
-/*
* When losing synchronisation a new barrier packet needs to be inserted at the
* beginning of the data collected in a buffer. That way the decoder knows that
* it needs to look for another sync sequence.
@@ -112,45 +112,6 @@ struct coresight_device *coresight_get_percpu_sink(int cpu)
}
EXPORT_SYMBOL_GPL(coresight_get_percpu_sink);
-static int coresight_id_match(struct device *dev, void *data)
-{
- int trace_id, i_trace_id;
- struct coresight_device *csdev, *i_csdev;
-
- csdev = data;
- i_csdev = to_coresight_device(dev);
-
- /*
- * No need to care about oneself and components that are not
- * sources or not enabled
- */
- if (i_csdev == csdev || !i_csdev->enable ||
- i_csdev->type != CORESIGHT_DEV_TYPE_SOURCE)
- return 0;
-
- /* Get the source ID for both components */
- trace_id = source_ops(csdev)->trace_id(csdev);
- i_trace_id = source_ops(i_csdev)->trace_id(i_csdev);
-
- /* All you need is one */
- if (trace_id == i_trace_id)
- return 1;
-
- return 0;
-}
-
-static int coresight_source_is_unique(struct coresight_device *csdev)
-{
- int trace_id = source_ops(csdev)->trace_id(csdev);
-
- /* this shouldn't happen */
- if (trace_id < 0)
- return 0;
-
- return !bus_for_each_dev(&coresight_bustype, NULL,
- csdev, coresight_id_match);
-}
-
static int coresight_find_link_inport(struct coresight_device *csdev,
struct coresight_device *parent)
{
@@ -459,12 +420,6 @@ static int coresight_enable_source(struct coresight_device *csdev, u32 mode)
{
int ret;
- if (!coresight_source_is_unique(csdev)) {
- dev_warn(&csdev->dev, "traceID %d not unique\n",
- source_ops(csdev)->trace_id(csdev));
- return -EINVAL;
- }
-
if (!csdev->enable) {
if (source_ops(csdev)->enable) {
ret = coresight_control_assoc_ectdev(csdev, true);
@@ -1106,7 +1061,8 @@ static int coresight_validate_source(struct coresight_device *csdev,
}
if (subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_PROC &&
- subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE) {
+ subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE &&
+ subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS) {
dev_err(&csdev->dev, "wrong device subtype in %s\n", function);
return -EINVAL;
}
@@ -1120,6 +1076,7 @@ int coresight_enable(struct coresight_device *csdev)
struct coresight_device *sink;
struct list_head *path;
enum coresight_dev_subtype_source subtype;
+ u32 hash;
subtype = csdev->subtype.source_subtype;
@@ -1174,7 +1131,15 @@ int coresight_enable(struct coresight_device *csdev)
per_cpu(tracer_path, cpu) = path;
break;
case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE:
- stm_path = path;
+ case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS:
+ /*
+ * Use the hash of source's device name as ID
+ * and map the ID to the pointer of the path.
+ */
+ hash = hashlen_hash(hashlen_string(NULL, dev_name(&csdev->dev)));
+ ret = idr_alloc_u32(&path_idr, path, &hash, hash, GFP_KERNEL);
+ if (ret)
+ goto err_source;
break;
default:
/* We can't be here */
@@ -1198,6 +1163,7 @@ void coresight_disable(struct coresight_device *csdev)
{
int cpu, ret;
struct list_head *path = NULL;
+ u32 hash;
mutex_lock(&coresight_mutex);
@@ -1215,8 +1181,15 @@ void coresight_disable(struct coresight_device *csdev)
per_cpu(tracer_path, cpu) = NULL;
break;
case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE:
- path = stm_path;
- stm_path = NULL;
+ case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS:
+ hash = hashlen_hash(hashlen_string(NULL, dev_name(&csdev->dev)));
+ /* Find the path by the hash. */
+ path = idr_find(&path_idr, hash);
+ if (path == NULL) {
+ pr_err("Path is not found for %s\n", dev_name(&csdev->dev));
+ goto out;
+ }
+ idr_remove(&path_idr, hash);
break;
default:
/* We can't be here */
diff --git a/drivers/hwtracing/coresight/coresight-cti-core.c b/drivers/hwtracing/coresight/coresight-cti-core.c
index d2cf4f4848e1..277c890a1f1f 100644
--- a/drivers/hwtracing/coresight/coresight-cti-core.c
+++ b/drivers/hwtracing/coresight/coresight-cti-core.c
@@ -107,12 +107,12 @@ static int cti_enable_hw(struct cti_drvdata *drvdata)
cti_write_all_hw_regs(drvdata);
config->hw_enabled = true;
- atomic_inc(&drvdata->config.enable_req_count);
+ drvdata->config.enable_req_count++;
spin_unlock_irqrestore(&drvdata->spinlock, flags);
return rc;
cti_state_unchanged:
- atomic_inc(&drvdata->config.enable_req_count);
+ drvdata->config.enable_req_count++;
/* cannot enable due to error */
cti_err_not_enabled:
@@ -129,7 +129,7 @@ static void cti_cpuhp_enable_hw(struct cti_drvdata *drvdata)
config->hw_powered = true;
/* no need to do anything if no enable request */
- if (!atomic_read(&drvdata->config.enable_req_count))
+ if (!drvdata->config.enable_req_count)
goto cti_hp_not_enabled;
/* try to claim the device */
@@ -151,11 +151,18 @@ static int cti_disable_hw(struct cti_drvdata *drvdata)
{
struct cti_config *config = &drvdata->config;
struct coresight_device *csdev = drvdata->csdev;
+ int ret = 0;
spin_lock(&drvdata->spinlock);
+ /* don't allow negative refcounts, return an error */
+ if (!drvdata->config.enable_req_count) {
+ ret = -EINVAL;
+ goto cti_not_disabled;
+ }
+
/* check refcount - disable on 0 */
- if (atomic_dec_return(&drvdata->config.enable_req_count) > 0)
+ if (--drvdata->config.enable_req_count > 0)
goto cti_not_disabled;
/* no need to do anything if disabled or cpu unpowered */
@@ -171,12 +178,12 @@ static int cti_disable_hw(struct cti_drvdata *drvdata)
coresight_disclaim_device_unlocked(csdev);
CS_LOCK(drvdata->base);
spin_unlock(&drvdata->spinlock);
- return 0;
+ return ret;
/* not disabled this call */
cti_not_disabled:
spin_unlock(&drvdata->spinlock);
- return 0;
+ return ret;
}
void cti_write_single_reg(struct cti_drvdata *drvdata, int offset, u32 value)
@@ -232,7 +239,7 @@ static void cti_set_default_config(struct device *dev,
/* Most regs default to 0 as zalloc'ed except...*/
config->trig_filter_enable = true;
config->ctigate = GENMASK(config->nr_ctm_channels - 1, 0);
- atomic_set(&config->enable_req_count, 0);
+ config->enable_req_count = 0;
}
/*
@@ -689,7 +696,7 @@ static int cti_cpu_pm_notify(struct notifier_block *nb, unsigned long cmd,
drvdata->config.hw_enabled = false;
/* check enable reference count to enable HW */
- if (atomic_read(&drvdata->config.enable_req_count)) {
+ if (drvdata->config.enable_req_count) {
/* check we can claim the device as we re-power */
if (coresight_claim_device(csdev))
goto cti_notify_exit;
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
index 6d59c815ecf5..e528cff9d4e2 100644
--- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c
@@ -84,8 +84,8 @@ static ssize_t enable_show(struct device *dev,
bool enabled, powered;
struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- enable_req = atomic_read(&drvdata->config.enable_req_count);
spin_lock(&drvdata->spinlock);
+ enable_req = drvdata->config.enable_req_count;
powered = drvdata->config.hw_powered;
enabled = drvdata->config.hw_enabled;
spin_unlock(&drvdata->spinlock);
@@ -108,10 +108,19 @@ static ssize_t enable_store(struct device *dev,
if (ret)
return ret;
- if (val)
+ if (val) {
+ ret = pm_runtime_resume_and_get(dev->parent);
+ if (ret)
+ return ret;
ret = cti_enable(drvdata->csdev);
- else
+ if (ret)
+ pm_runtime_put(dev->parent);
+ } else {
ret = cti_disable(drvdata->csdev);
+ if (!ret)
+ pm_runtime_put(dev->parent);
+ }
+
if (ret)
return ret;
return size;
diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h
index acf7b545e6b9..8b106b13a244 100644
--- a/drivers/hwtracing/coresight/coresight-cti.h
+++ b/drivers/hwtracing/coresight/coresight-cti.h
@@ -141,7 +141,7 @@ struct cti_config {
int nr_trig_max;
/* cti enable control */
- atomic_t enable_req_count;
+ int enable_req_count;
bool hw_enabled;
bool hw_powered;
diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c
index 43bbd5dc3d3b..a48c97da8165 100644
--- a/drivers/hwtracing/coresight/coresight-etm-perf.c
+++ b/drivers/hwtracing/coresight/coresight-etm-perf.c
@@ -4,6 +4,7 @@
* Author: Mathieu Poirier <mathieu.poirier@linaro.org>
*/
+#include <linux/bitfield.h>
#include <linux/coresight.h>
#include <linux/coresight-pmu.h>
#include <linux/cpumask.h>
@@ -22,6 +23,7 @@
#include "coresight-etm-perf.h"
#include "coresight-priv.h"
#include "coresight-syscfg.h"
+#include "coresight-trace-id.h"
static struct pmu etm_pmu;
static bool etm_perf_up;
@@ -228,8 +230,12 @@ static void free_event_data(struct work_struct *work)
if (!(IS_ERR_OR_NULL(*ppath)))
coresight_release_path(*ppath);
*ppath = NULL;
+ coresight_trace_id_put_cpu_id(cpu);
}
+ /* mark perf event as done for trace id allocator */
+ coresight_trace_id_perf_stop();
+
free_percpu(event_data->path);
kfree(event_data);
}
@@ -300,6 +306,7 @@ static void *etm_setup_aux(struct perf_event *event, void **pages,
{
u32 id, cfg_hash;
int cpu = event->cpu;
+ int trace_id;
cpumask_t *mask;
struct coresight_device *sink = NULL;
struct coresight_device *user_sink = NULL, *last_sink = NULL;
@@ -316,6 +323,9 @@ static void *etm_setup_aux(struct perf_event *event, void **pages,
sink = user_sink = coresight_get_sink_by_id(id);
}
+ /* tell the trace ID allocator that a perf event is starting up */
+ coresight_trace_id_perf_start();
+
/* check if user wants a coresight configuration selected */
cfg_hash = (u32)((event->attr.config2 & GENMASK_ULL(63, 32)) >> 32);
if (cfg_hash) {
@@ -388,6 +398,13 @@ static void *etm_setup_aux(struct perf_event *event, void **pages,
continue;
}
+ /* ensure we can allocate a trace ID for this CPU */
+ trace_id = coresight_trace_id_get_cpu_id(cpu);
+ if (!IS_VALID_CS_TRACE_ID(trace_id)) {
+ cpumask_clear_cpu(cpu, mask);
+ continue;
+ }
+
*etm_event_cpu_path_ptr(event_data, cpu) = path;
}
@@ -432,6 +449,7 @@ static void etm_event_start(struct perf_event *event, int flags)
struct perf_output_handle *handle = &ctxt->handle;
struct coresight_device *sink, *csdev = per_cpu(csdev_src, cpu);
struct list_head *path;
+ u64 hw_id;
if (!csdev)
goto fail;
@@ -477,6 +495,19 @@ static void etm_event_start(struct perf_event *event, int flags)
if (source_ops(csdev)->enable(csdev, event, CS_MODE_PERF))
goto fail_disable_path;
+ /*
+ * output cpu / trace ID in perf record, once for the lifetime
+ * of the event.
+ */
+ if (!cpumask_test_cpu(cpu, &event_data->aux_hwid_done)) {
+ cpumask_set_cpu(cpu, &event_data->aux_hwid_done);
+ hw_id = FIELD_PREP(CS_AUX_HW_ID_VERSION_MASK,
+ CS_AUX_HW_ID_CURR_VERSION);
+ hw_id |= FIELD_PREP(CS_AUX_HW_ID_TRACE_ID_MASK,
+ coresight_trace_id_read_cpu_id(cpu));
+ perf_report_aux_output_id(event, hw_id);
+ }
+
out:
/* Tell the perf core the event is alive */
event->hw.state = 0;
diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.h b/drivers/hwtracing/coresight/coresight-etm-perf.h
index 468f7799ab4f..bebbadee2ceb 100644
--- a/drivers/hwtracing/coresight/coresight-etm-perf.h
+++ b/drivers/hwtracing/coresight/coresight-etm-perf.h
@@ -48,6 +48,7 @@ struct etm_filters {
* struct etm_event_data - Coresight specifics associated to an event
* @work: Handle to free allocated memory outside IRQ context.
* @mask: Hold the CPU(s) this event was set for.
+ * @aux_hwid_done: Whether a CPU has emitted the TraceID packet or not.
* @snk_config: The sink configuration.
* @cfg_hash: The hash id of any coresight config selected.
* @path: An array of path, each slot for one CPU.
@@ -55,6 +56,7 @@ struct etm_filters {
struct etm_event_data {
struct work_struct work;
cpumask_t mask;
+ cpumask_t aux_hwid_done;
void *snk_config;
u32 cfg_hash;
struct list_head * __percpu *path;
diff --git a/drivers/hwtracing/coresight/coresight-etm.h b/drivers/hwtracing/coresight/coresight-etm.h
index f3ab96eaf44e..9a0d08b092ae 100644
--- a/drivers/hwtracing/coresight/coresight-etm.h
+++ b/drivers/hwtracing/coresight/coresight-etm.h
@@ -283,8 +283,9 @@ static inline unsigned int etm_readl(struct etm_drvdata *drvdata, u32 off)
}
extern const struct attribute_group *coresight_etm_groups[];
-int etm_get_trace_id(struct etm_drvdata *drvdata);
void etm_set_default(struct etm_config *config);
void etm_config_trace_mode(struct etm_config *config);
struct etm_config *get_etm_config(struct etm_drvdata *drvdata);
+int etm_read_alloc_trace_id(struct etm_drvdata *drvdata);
+void etm_release_trace_id(struct etm_drvdata *drvdata);
#endif
diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c
index d0ab9933472b..afc57195ee52 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c
@@ -32,6 +32,7 @@
#include "coresight-etm.h"
#include "coresight-etm-perf.h"
+#include "coresight-trace-id.h"
/*
* Not really modular but using module_param is the easiest way to
@@ -454,52 +455,59 @@ static int etm_cpu_id(struct coresight_device *csdev)
return drvdata->cpu;
}
-int etm_get_trace_id(struct etm_drvdata *drvdata)
+int etm_read_alloc_trace_id(struct etm_drvdata *drvdata)
{
- unsigned long flags;
- int trace_id = -1;
- struct device *etm_dev;
+ int trace_id;
- if (!drvdata)
- goto out;
-
- etm_dev = drvdata->csdev->dev.parent;
- if (!local_read(&drvdata->mode))
- return drvdata->traceid;
-
- pm_runtime_get_sync(etm_dev);
-
- spin_lock_irqsave(&drvdata->spinlock, flags);
-
- CS_UNLOCK(drvdata->base);
- trace_id = (etm_readl(drvdata, ETMTRACEIDR) & ETM_TRACEID_MASK);
- CS_LOCK(drvdata->base);
-
- spin_unlock_irqrestore(&drvdata->spinlock, flags);
- pm_runtime_put(etm_dev);
-
-out:
+ /*
+ * This will allocate a trace ID to the cpu,
+ * or return the one currently allocated.
+ *
+ * trace id function has its own lock
+ */
+ trace_id = coresight_trace_id_get_cpu_id(drvdata->cpu);
+ if (IS_VALID_CS_TRACE_ID(trace_id))
+ drvdata->traceid = (u8)trace_id;
+ else
+ dev_err(&drvdata->csdev->dev,
+ "Failed to allocate trace ID for %s on CPU%d\n",
+ dev_name(&drvdata->csdev->dev), drvdata->cpu);
return trace_id;
-
}
-static int etm_trace_id(struct coresight_device *csdev)
+void etm_release_trace_id(struct etm_drvdata *drvdata)
{
- struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
-
- return etm_get_trace_id(drvdata);
+ coresight_trace_id_put_cpu_id(drvdata->cpu);
}
static int etm_enable_perf(struct coresight_device *csdev,
struct perf_event *event)
{
struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+ int trace_id;
if (WARN_ON_ONCE(drvdata->cpu != smp_processor_id()))
return -EINVAL;
/* Configure the tracer based on the session's specifics */
etm_parse_event_config(drvdata, event);
+
+ /*
+ * perf allocates cpu ids as part of _setup_aux() - device needs to use
+ * the allocated ID. This reads the current version without allocation.
+ *
+ * This does not use the trace id lock to prevent lock_dep issues
+ * with perf locks - we know the ID cannot change until perf shuts down
+ * the session
+ */
+ trace_id = coresight_trace_id_read_cpu_id(drvdata->cpu);
+ if (!IS_VALID_CS_TRACE_ID(trace_id)) {
+ dev_err(&drvdata->csdev->dev, "Failed to set trace ID for %s on CPU%d\n",
+ dev_name(&drvdata->csdev->dev), drvdata->cpu);
+ return -EINVAL;
+ }
+ drvdata->traceid = (u8)trace_id;
+
/* And enable it */
return etm_enable_hw(drvdata);
}
@@ -512,6 +520,11 @@ static int etm_enable_sysfs(struct coresight_device *csdev)
spin_lock(&drvdata->spinlock);
+ /* sysfs needs to allocate and set a trace ID */
+ ret = etm_read_alloc_trace_id(drvdata);
+ if (ret < 0)
+ goto unlock_enable_sysfs;
+
/*
* Configure the ETM only if the CPU is online. If it isn't online
* hw configuration will take place on the local CPU during bring up.
@@ -528,6 +541,10 @@ static int etm_enable_sysfs(struct coresight_device *csdev)
ret = -ENODEV;
}
+ if (ret)
+ etm_release_trace_id(drvdata);
+
+unlock_enable_sysfs:
spin_unlock(&drvdata->spinlock);
if (!ret)
@@ -611,6 +628,12 @@ static void etm_disable_perf(struct coresight_device *csdev)
coresight_disclaim_device_unlocked(csdev);
CS_LOCK(drvdata->base);
+
+ /*
+ * perf will release trace ids when _free_aux()
+ * is called at the end of the session
+ */
+
}
static void etm_disable_sysfs(struct coresight_device *csdev)
@@ -635,6 +658,13 @@ static void etm_disable_sysfs(struct coresight_device *csdev)
spin_unlock(&drvdata->spinlock);
cpus_read_unlock();
+ /*
+ * we only release trace IDs when resetting sysfs.
+ * This permits sysfs users to read the trace ID after the trace
+ * session has completed. This maintains operational behaviour with
+ * prior trace id allocation method
+ */
+
dev_dbg(&csdev->dev, "ETM tracing disabled\n");
}
@@ -671,7 +701,6 @@ static void etm_disable(struct coresight_device *csdev,
static const struct coresight_ops_source etm_source_ops = {
.cpu_id = etm_cpu_id,
- .trace_id = etm_trace_id,
.enable = etm_enable,
.disable = etm_disable,
};
@@ -781,11 +810,6 @@ static void etm_init_arch_data(void *info)
CS_LOCK(drvdata->base);
}
-static void etm_init_trace_id(struct etm_drvdata *drvdata)
-{
- drvdata->traceid = coresight_get_trace_id(drvdata->cpu);
-}
-
static int __init etm_hp_setup(void)
{
int ret;
@@ -871,7 +895,6 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id)
if (etm_arch_supported(drvdata->arch) == false)
return -EINVAL;
- etm_init_trace_id(drvdata);
etm_set_default(&drvdata->config);
pdata = coresight_get_platform_data(dev);
diff --git a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
index fd81eca3ec18..2f271b7fb048 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
@@ -85,6 +85,7 @@ static ssize_t reset_store(struct device *dev,
}
etm_set_default(config);
+ etm_release_trace_id(drvdata);
spin_unlock(&drvdata->spinlock);
}
@@ -1189,30 +1190,16 @@ static DEVICE_ATTR_RO(cpu);
static ssize_t traceid_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- unsigned long val;
- struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- val = etm_get_trace_id(drvdata);
-
- return sprintf(buf, "%#lx\n", val);
-}
-
-static ssize_t traceid_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- int ret;
- unsigned long val;
+ int trace_id;
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
- ret = kstrtoul(buf, 16, &val);
- if (ret)
- return ret;
+ trace_id = etm_read_alloc_trace_id(drvdata);
+ if (trace_id < 0)
+ return trace_id;
- drvdata->traceid = val & ETM_TRACEID_MASK;
- return size;
+ return sysfs_emit(buf, "%#x\n", trace_id);
}
-static DEVICE_ATTR_RW(traceid);
+static DEVICE_ATTR_RO(traceid);
static struct attribute *coresight_etm_attrs[] = {
&dev_attr_nr_addr_cmp.attr,
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
index 1cc052979e01..1ea8f173cca0 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
@@ -42,6 +42,7 @@
#include "coresight-etm4x-cfg.h"
#include "coresight-self-hosted-trace.h"
#include "coresight-syscfg.h"
+#include "coresight-trace-id.h"
static int boot_enable;
module_param(boot_enable, int, 0444);
@@ -230,11 +231,28 @@ static int etm4_cpu_id(struct coresight_device *csdev)
return drvdata->cpu;
}
-static int etm4_trace_id(struct coresight_device *csdev)
+int etm4_read_alloc_trace_id(struct etmv4_drvdata *drvdata)
{
- struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+ int trace_id;
+
+ /*
+ * This will allocate a trace ID to the cpu,
+ * or return the one currently allocated.
+ * The trace id function has its own lock
+ */
+ trace_id = coresight_trace_id_get_cpu_id(drvdata->cpu);
+ if (IS_VALID_CS_TRACE_ID(trace_id))
+ drvdata->trcid = (u8)trace_id;
+ else
+ dev_err(&drvdata->csdev->dev,
+ "Failed to allocate trace ID for %s on CPU%d\n",
+ dev_name(&drvdata->csdev->dev), drvdata->cpu);
+ return trace_id;
+}
- return drvdata->trcid;
+void etm4_release_trace_id(struct etmv4_drvdata *drvdata)
+{
+ coresight_trace_id_put_cpu_id(drvdata->cpu);
}
struct etm4_enable_arg {
@@ -427,8 +445,10 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
etm4x_relaxed_write32(csa, config->vipcssctlr, TRCVIPCSSCTLR);
for (i = 0; i < drvdata->nrseqstate - 1; i++)
etm4x_relaxed_write32(csa, config->seq_ctrl[i], TRCSEQEVRn(i));
- etm4x_relaxed_write32(csa, config->seq_rst, TRCSEQRSTEVR);
- etm4x_relaxed_write32(csa, config->seq_state, TRCSEQSTR);
+ if (drvdata->nrseqstate) {
+ etm4x_relaxed_write32(csa, config->seq_rst, TRCSEQRSTEVR);
+ etm4x_relaxed_write32(csa, config->seq_state, TRCSEQSTR);
+ }
etm4x_relaxed_write32(csa, config->ext_inp, TRCEXTINSELR);
for (i = 0; i < drvdata->nr_cntr; i++) {
etm4x_relaxed_write32(csa, config->cntrldvr[i], TRCCNTRLDVRn(i));
@@ -720,7 +740,7 @@ out:
static int etm4_enable_perf(struct coresight_device *csdev,
struct perf_event *event)
{
- int ret = 0;
+ int ret = 0, trace_id;
struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
if (WARN_ON_ONCE(drvdata->cpu != smp_processor_id())) {
@@ -732,6 +752,24 @@ static int etm4_enable_perf(struct coresight_device *csdev,
ret = etm4_parse_event_config(csdev, event);
if (ret)
goto out;
+
+ /*
+ * perf allocates cpu ids as part of _setup_aux() - device needs to use
+ * the allocated ID. This reads the current version without allocation.
+ *
+ * This does not use the trace id lock to prevent lock_dep issues
+ * with perf locks - we know the ID cannot change until perf shuts down
+ * the session
+ */
+ trace_id = coresight_trace_id_read_cpu_id(drvdata->cpu);
+ if (!IS_VALID_CS_TRACE_ID(trace_id)) {
+ dev_err(&drvdata->csdev->dev, "Failed to set trace ID for %s on CPU%d\n",
+ dev_name(&drvdata->csdev->dev), drvdata->cpu);
+ ret = -EINVAL;
+ goto out;
+ }
+ drvdata->trcid = (u8)trace_id;
+
/* And enable it */
ret = etm4_enable_hw(drvdata);
@@ -756,6 +794,11 @@ static int etm4_enable_sysfs(struct coresight_device *csdev)
spin_lock(&drvdata->spinlock);
+ /* sysfs needs to read and allocate a trace ID */
+ ret = etm4_read_alloc_trace_id(drvdata);
+ if (ret < 0)
+ goto unlock_sysfs_enable;
+
/*
* Executing etm4_enable_hw on the cpu whose ETM is being enabled
* ensures that register writes occur when cpu is powered.
@@ -767,6 +810,11 @@ static int etm4_enable_sysfs(struct coresight_device *csdev)
ret = arg.rc;
if (!ret)
drvdata->sticky_enable = true;
+
+ if (ret)
+ etm4_release_trace_id(drvdata);
+
+unlock_sysfs_enable:
spin_unlock(&drvdata->spinlock);
if (!ret)
@@ -898,6 +946,11 @@ static int etm4_disable_perf(struct coresight_device *csdev,
/* TRCVICTLR::SSSTATUS, bit[9] */
filters->ssstatus = (control & BIT(9));
+ /*
+ * perf will release trace ids when _free_aux() is
+ * called at the end of the session.
+ */
+
return 0;
}
@@ -923,6 +976,13 @@ static void etm4_disable_sysfs(struct coresight_device *csdev)
spin_unlock(&drvdata->spinlock);
cpus_read_unlock();
+ /*
+ * we only release trace IDs when resetting sysfs.
+ * This permits sysfs users to read the trace ID after the trace
+ * session has completed. This maintains operational behaviour with
+ * prior trace id allocation method
+ */
+
dev_dbg(&csdev->dev, "ETM tracing disabled\n");
}
@@ -956,7 +1016,6 @@ static void etm4_disable(struct coresight_device *csdev,
static const struct coresight_ops_source etm4_source_ops = {
.cpu_id = etm4_cpu_id,
- .trace_id = etm4_trace_id,
.enable = etm4_enable,
.disable = etm4_disable,
};
@@ -1565,11 +1624,6 @@ static int etm4_dying_cpu(unsigned int cpu)
return 0;
}
-static void etm4_init_trace_id(struct etmv4_drvdata *drvdata)
-{
- drvdata->trcid = coresight_get_trace_id(drvdata->cpu);
-}
-
static int __etm4_cpu_save(struct etmv4_drvdata *drvdata)
{
int i, ret = 0;
@@ -1634,8 +1688,10 @@ static int __etm4_cpu_save(struct etmv4_drvdata *drvdata)
for (i = 0; i < drvdata->nrseqstate - 1; i++)
state->trcseqevr[i] = etm4x_read32(csa, TRCSEQEVRn(i));
- state->trcseqrstevr = etm4x_read32(csa, TRCSEQRSTEVR);
- state->trcseqstr = etm4x_read32(csa, TRCSEQSTR);
+ if (drvdata->nrseqstate) {
+ state->trcseqrstevr = etm4x_read32(csa, TRCSEQRSTEVR);
+ state->trcseqstr = etm4x_read32(csa, TRCSEQSTR);
+ }
state->trcextinselr = etm4x_read32(csa, TRCEXTINSELR);
for (i = 0; i < drvdata->nr_cntr; i++) {
@@ -1763,8 +1819,10 @@ static void __etm4_cpu_restore(struct etmv4_drvdata *drvdata)
for (i = 0; i < drvdata->nrseqstate - 1; i++)
etm4x_relaxed_write32(csa, state->trcseqevr[i], TRCSEQEVRn(i));
- etm4x_relaxed_write32(csa, state->trcseqrstevr, TRCSEQRSTEVR);
- etm4x_relaxed_write32(csa, state->trcseqstr, TRCSEQSTR);
+ if (drvdata->nrseqstate) {
+ etm4x_relaxed_write32(csa, state->trcseqrstevr, TRCSEQRSTEVR);
+ etm4x_relaxed_write32(csa, state->trcseqstr, TRCSEQSTR);
+ }
etm4x_relaxed_write32(csa, state->trcextinselr, TRCEXTINSELR);
for (i = 0; i < drvdata->nr_cntr; i++) {
@@ -1946,7 +2004,6 @@ static int etm4_add_coresight_dev(struct etm4_init_arg *init_arg)
if (!desc.name)
return -ENOMEM;
- etm4_init_trace_id(drvdata);
etm4_set_default(&drvdata->config);
pdata = coresight_get_platform_data(dev);
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
index 9cac848cffaf..5e62aa40ecd0 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
@@ -266,10 +266,11 @@ static ssize_t reset_store(struct device *dev,
config->vmid_mask0 = 0x0;
config->vmid_mask1 = 0x0;
- drvdata->trcid = drvdata->cpu + 1;
-
spin_unlock(&drvdata->spinlock);
+ /* for sysfs - only release trace id when resetting */
+ etm4_release_trace_id(drvdata);
+
cscfg_csdev_reset_feats(to_coresight_device(dev));
return size;
@@ -2392,6 +2393,26 @@ static struct attribute *coresight_etmv4_attrs[] = {
NULL,
};
+/*
+ * Trace ID allocated dynamically on enable - but also allocate on read
+ * in case sysfs or perf read before enable to ensure consistent metadata
+ * information for trace decode
+ */
+static ssize_t trctraceid_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int trace_id;
+ struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+ trace_id = etm4_read_alloc_trace_id(drvdata);
+ if (trace_id < 0)
+ return trace_id;
+
+ return sysfs_emit(buf, "0x%x\n", trace_id);
+}
+static DEVICE_ATTR_RO(trctraceid);
+
struct etmv4_reg {
struct coresight_device *csdev;
u32 offset;
@@ -2528,7 +2549,7 @@ static struct attribute *coresight_etmv4_mgmt_attrs[] = {
coresight_etm4x_reg(trcpidr3, TRCPIDR3),
coresight_etm4x_reg(trcoslsr, TRCOSLSR),
coresight_etm4x_reg(trcconfig, TRCCONFIGR),
- coresight_etm4x_reg(trctraceid, TRCTRACEIDR),
+ &dev_attr_trctraceid.attr,
coresight_etm4x_reg(trcdevarch, TRCDEVARCH),
NULL,
};
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
index 4b21bb79f168..434f4e95ee17 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.h
+++ b/drivers/hwtracing/coresight/coresight-etm4x.h
@@ -1095,4 +1095,7 @@ static inline bool etm4x_is_ete(struct etmv4_drvdata *drvdata)
{
return drvdata->arch >= ETM_ARCH_ETE;
}
+
+int etm4_read_alloc_trace_id(struct etmv4_drvdata *drvdata);
+void etm4_release_trace_id(struct etmv4_drvdata *drvdata);
#endif
diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c
index 463f449cfb79..66a614c5492c 100644
--- a/drivers/hwtracing/coresight/coresight-stm.c
+++ b/drivers/hwtracing/coresight/coresight-stm.c
@@ -31,6 +31,7 @@
#include <linux/stm.h>
#include "coresight-priv.h"
+#include "coresight-trace-id.h"
#define STMDMASTARTR 0xc04
#define STMDMASTOPR 0xc08
@@ -280,15 +281,7 @@ static void stm_disable(struct coresight_device *csdev,
}
}
-static int stm_trace_id(struct coresight_device *csdev)
-{
- struct stm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
-
- return drvdata->traceid;
-}
-
static const struct coresight_ops_source stm_source_ops = {
- .trace_id = stm_trace_id,
.enable = stm_enable,
.disable = stm_disable,
};
@@ -615,24 +608,7 @@ static ssize_t traceid_show(struct device *dev,
val = drvdata->traceid;
return sprintf(buf, "%#lx\n", val);
}
-
-static ssize_t traceid_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- int ret;
- unsigned long val;
- struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent);
-
- ret = kstrtoul(buf, 16, &val);
- if (ret)
- return ret;
-
- /* traceid field is 7bit wide on STM32 */
- drvdata->traceid = val & 0x7f;
- return size;
-}
-static DEVICE_ATTR_RW(traceid);
+static DEVICE_ATTR_RO(traceid);
static struct attribute *coresight_stm_attrs[] = {
&dev_attr_hwevent_enable.attr,
@@ -803,14 +779,6 @@ static void stm_init_default_data(struct stm_drvdata *drvdata)
*/
drvdata->stmsper = ~0x0;
- /*
- * The trace ID value for *ETM* tracers start at CPU_ID * 2 + 0x10 and
- * anything equal to or higher than 0x70 is reserved. Since 0x00 is
- * also reserved the STM trace ID needs to be higher than 0x00 and
- * lowner than 0x10.
- */
- drvdata->traceid = 0x1;
-
/* Set invariant transaction timing on all channels */
bitmap_clear(drvdata->chs.guaranteed, 0, drvdata->numsp);
}
@@ -838,7 +806,7 @@ static void stm_init_generic_data(struct stm_drvdata *drvdata,
static int stm_probe(struct amba_device *adev, const struct amba_id *id)
{
- int ret;
+ int ret, trace_id;
void __iomem *base;
struct device *dev = &adev->dev;
struct coresight_platform_data *pdata = NULL;
@@ -922,12 +890,22 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id)
goto stm_unregister;
}
+ trace_id = coresight_trace_id_get_system_id();
+ if (trace_id < 0) {
+ ret = trace_id;
+ goto cs_unregister;
+ }
+ drvdata->traceid = (u8)trace_id;
+
pm_runtime_put(&adev->dev);
dev_info(&drvdata->csdev->dev, "%s initialized\n",
(char *)coresight_get_uci_data(id));
return 0;
+cs_unregister:
+ coresight_unregister(drvdata->csdev);
+
stm_unregister:
stm_unregister_device(&drvdata->stm);
return ret;
@@ -937,6 +915,7 @@ static void stm_remove(struct amba_device *adev)
{
struct stm_drvdata *drvdata = dev_get_drvdata(&adev->dev);
+ coresight_trace_id_put_system_id(drvdata->traceid);
coresight_unregister(drvdata->csdev);
stm_unregister_device(&drvdata->stm);
diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c
index 07abf28ad725..c106d142e632 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-core.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-core.c
@@ -31,7 +31,7 @@ DEFINE_CORESIGHT_DEVLIST(etb_devs, "tmc_etb");
DEFINE_CORESIGHT_DEVLIST(etf_devs, "tmc_etf");
DEFINE_CORESIGHT_DEVLIST(etr_devs, "tmc_etr");
-void tmc_wait_for_tmcready(struct tmc_drvdata *drvdata)
+int tmc_wait_for_tmcready(struct tmc_drvdata *drvdata)
{
struct coresight_device *csdev = drvdata->csdev;
struct csdev_access *csa = &csdev->access;
@@ -40,7 +40,9 @@ void tmc_wait_for_tmcready(struct tmc_drvdata *drvdata)
if (coresight_timeout(csa, TMC_STS, TMC_STS_TMCREADY_BIT, 1)) {
dev_err(&csdev->dev,
"timeout while waiting for TMC to be Ready\n");
+ return -EBUSY;
}
+ return 0;
}
void tmc_flush_and_stop(struct tmc_drvdata *drvdata)
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
index 4c4cbd1f7258..0ab1f73c2d06 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
@@ -16,12 +16,20 @@
static int tmc_set_etf_buffer(struct coresight_device *csdev,
struct perf_output_handle *handle);
-static void __tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
+static int __tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
{
+ int rc = 0;
+
CS_UNLOCK(drvdata->base);
/* Wait for TMCSReady bit to be set */
- tmc_wait_for_tmcready(drvdata);
+ rc = tmc_wait_for_tmcready(drvdata);
+ if (rc) {
+ dev_err(&drvdata->csdev->dev,
+ "Failed to enable: TMC not ready\n");
+ CS_LOCK(drvdata->base);
+ return rc;
+ }
writel_relaxed(TMC_MODE_CIRCULAR_BUFFER, drvdata->base + TMC_MODE);
writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI |
@@ -33,6 +41,7 @@ static void __tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
tmc_enable_hw(drvdata);
CS_LOCK(drvdata->base);
+ return rc;
}
static int tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
@@ -42,8 +51,10 @@ static int tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
if (rc)
return rc;
- __tmc_etb_enable_hw(drvdata);
- return 0;
+ rc = __tmc_etb_enable_hw(drvdata);
+ if (rc)
+ coresight_disclaim_device(drvdata->csdev);
+ return rc;
}
static void tmc_etb_dump_hw(struct tmc_drvdata *drvdata)
@@ -91,12 +102,20 @@ static void tmc_etb_disable_hw(struct tmc_drvdata *drvdata)
coresight_disclaim_device(drvdata->csdev);
}
-static void __tmc_etf_enable_hw(struct tmc_drvdata *drvdata)
+static int __tmc_etf_enable_hw(struct tmc_drvdata *drvdata)
{
+ int rc = 0;
+
CS_UNLOCK(drvdata->base);
/* Wait for TMCSReady bit to be set */
- tmc_wait_for_tmcready(drvdata);
+ rc = tmc_wait_for_tmcready(drvdata);
+ if (rc) {
+ dev_err(&drvdata->csdev->dev,
+ "Failed to enable : TMC is not ready\n");
+ CS_LOCK(drvdata->base);
+ return rc;
+ }
writel_relaxed(TMC_MODE_HARDWARE_FIFO, drvdata->base + TMC_MODE);
writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI,
@@ -105,6 +124,7 @@ static void __tmc_etf_enable_hw(struct tmc_drvdata *drvdata)
tmc_enable_hw(drvdata);
CS_LOCK(drvdata->base);
+ return rc;
}
static int tmc_etf_enable_hw(struct tmc_drvdata *drvdata)
@@ -114,8 +134,10 @@ static int tmc_etf_enable_hw(struct tmc_drvdata *drvdata)
if (rc)
return rc;
- __tmc_etf_enable_hw(drvdata);
- return 0;
+ rc = __tmc_etf_enable_hw(drvdata);
+ if (rc)
+ coresight_disclaim_device(drvdata->csdev);
+ return rc;
}
static void tmc_etf_disable_hw(struct tmc_drvdata *drvdata)
@@ -639,6 +661,7 @@ int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata)
char *buf = NULL;
enum tmc_mode mode;
unsigned long flags;
+ int rc = 0;
/* config types are set a boot time and never change */
if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETB &&
@@ -664,7 +687,11 @@ int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata)
* can't be NULL.
*/
memset(drvdata->buf, 0, drvdata->size);
- __tmc_etb_enable_hw(drvdata);
+ rc = __tmc_etb_enable_hw(drvdata);
+ if (rc) {
+ spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ return rc;
+ }
} else {
/*
* The ETB/ETF is not tracing and the buffer was just read.
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index 867ad8bb9b0c..918d461fcf4a 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -983,15 +983,22 @@ static void tmc_sync_etr_buf(struct tmc_drvdata *drvdata)
etr_buf->ops->sync(etr_buf, rrp, rwp);
}
-static void __tmc_etr_enable_hw(struct tmc_drvdata *drvdata)
+static int __tmc_etr_enable_hw(struct tmc_drvdata *drvdata)
{
u32 axictl, sts;
struct etr_buf *etr_buf = drvdata->etr_buf;
+ int rc = 0;
CS_UNLOCK(drvdata->base);
/* Wait for TMCSReady bit to be set */
- tmc_wait_for_tmcready(drvdata);
+ rc = tmc_wait_for_tmcready(drvdata);
+ if (rc) {
+ dev_err(&drvdata->csdev->dev,
+ "Failed to enable : TMC not ready\n");
+ CS_LOCK(drvdata->base);
+ return rc;
+ }
writel_relaxed(etr_buf->size / 4, drvdata->base + TMC_RSZ);
writel_relaxed(TMC_MODE_CIRCULAR_BUFFER, drvdata->base + TMC_MODE);
@@ -1032,6 +1039,7 @@ static void __tmc_etr_enable_hw(struct tmc_drvdata *drvdata)
tmc_enable_hw(drvdata);
CS_LOCK(drvdata->base);
+ return rc;
}
static int tmc_etr_enable_hw(struct tmc_drvdata *drvdata,
@@ -1060,7 +1068,12 @@ static int tmc_etr_enable_hw(struct tmc_drvdata *drvdata,
rc = coresight_claim_device(drvdata->csdev);
if (!rc) {
drvdata->etr_buf = etr_buf;
- __tmc_etr_enable_hw(drvdata);
+ rc = __tmc_etr_enable_hw(drvdata);
+ if (rc) {
+ drvdata->etr_buf = NULL;
+ coresight_disclaim_device(drvdata->csdev);
+ tmc_etr_disable_catu(drvdata);
+ }
}
return rc;
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index 66959557cf39..01c0382a29c0 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -255,7 +255,7 @@ struct tmc_sg_table {
};
/* Generic functions */
-void tmc_wait_for_tmcready(struct tmc_drvdata *drvdata);
+int tmc_wait_for_tmcready(struct tmc_drvdata *drvdata);
void tmc_flush_and_stop(struct tmc_drvdata *drvdata);
void tmc_enable_hw(struct tmc_drvdata *drvdata);
void tmc_disable_hw(struct tmc_drvdata *drvdata);
diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c
new file mode 100644
index 000000000000..f712e112ecff
--- /dev/null
+++ b/drivers/hwtracing/coresight/coresight-tpda.c
@@ -0,0 +1,211 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/amba/bus.h>
+#include <linux/bitfield.h>
+#include <linux/coresight.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include "coresight-priv.h"
+#include "coresight-tpda.h"
+#include "coresight-trace-id.h"
+
+DEFINE_CORESIGHT_DEVLIST(tpda_devs, "tpda");
+
+/* Settings pre enabling port control register */
+static void tpda_enable_pre_port(struct tpda_drvdata *drvdata)
+{
+ u32 val;
+
+ val = readl_relaxed(drvdata->base + TPDA_CR);
+ val &= ~TPDA_CR_ATID;
+ val |= FIELD_PREP(TPDA_CR_ATID, drvdata->atid);
+ writel_relaxed(val, drvdata->base + TPDA_CR);
+}
+
+static void tpda_enable_port(struct tpda_drvdata *drvdata, int port)
+{
+ u32 val;
+
+ val = readl_relaxed(drvdata->base + TPDA_Pn_CR(port));
+ /* Enable the port */
+ val |= TPDA_Pn_CR_ENA;
+ writel_relaxed(val, drvdata->base + TPDA_Pn_CR(port));
+}
+
+static void __tpda_enable(struct tpda_drvdata *drvdata, int port)
+{
+ CS_UNLOCK(drvdata->base);
+
+ if (!drvdata->csdev->enable)
+ tpda_enable_pre_port(drvdata);
+
+ tpda_enable_port(drvdata, port);
+
+ CS_LOCK(drvdata->base);
+}
+
+static int tpda_enable(struct coresight_device *csdev, int inport, int outport)
+{
+ struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+ spin_lock(&drvdata->spinlock);
+ if (atomic_read(&csdev->refcnt[inport]) == 0)
+ __tpda_enable(drvdata, inport);
+
+ atomic_inc(&csdev->refcnt[inport]);
+ spin_unlock(&drvdata->spinlock);
+
+ dev_dbg(drvdata->dev, "TPDA inport %d enabled.\n", inport);
+ return 0;
+}
+
+static void __tpda_disable(struct tpda_drvdata *drvdata, int port)
+{
+ u32 val;
+
+ CS_UNLOCK(drvdata->base);
+
+ val = readl_relaxed(drvdata->base + TPDA_Pn_CR(port));
+ val &= ~TPDA_Pn_CR_ENA;
+ writel_relaxed(val, drvdata->base + TPDA_Pn_CR(port));
+
+ CS_LOCK(drvdata->base);
+}
+
+static void tpda_disable(struct coresight_device *csdev, int inport,
+ int outport)
+{
+ struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+ spin_lock(&drvdata->spinlock);
+ if (atomic_dec_return(&csdev->refcnt[inport]) == 0)
+ __tpda_disable(drvdata, inport);
+
+ spin_unlock(&drvdata->spinlock);
+
+ dev_dbg(drvdata->dev, "TPDA inport %d disabled\n", inport);
+}
+
+static const struct coresight_ops_link tpda_link_ops = {
+ .enable = tpda_enable,
+ .disable = tpda_disable,
+};
+
+static const struct coresight_ops tpda_cs_ops = {
+ .link_ops = &tpda_link_ops,
+};
+
+static int tpda_init_default_data(struct tpda_drvdata *drvdata)
+{
+ int atid;
+ /*
+ * TPDA must has a unique atid. This atid can uniquely
+ * identify the TPDM trace source connected to the TPDA.
+ * The TPDMs which are connected to same TPDA share the
+ * same trace-id. When TPDA does packetization, different
+ * port will have unique channel number for decoding.
+ */
+ atid = coresight_trace_id_get_system_id();
+ if (atid < 0)
+ return atid;
+
+ drvdata->atid = atid;
+ return 0;
+}
+
+static int tpda_probe(struct amba_device *adev, const struct amba_id *id)
+{
+ int ret;
+ struct device *dev = &adev->dev;
+ struct coresight_platform_data *pdata;
+ struct tpda_drvdata *drvdata;
+ struct coresight_desc desc = { 0 };
+ void __iomem *base;
+
+ pdata = coresight_get_platform_data(dev);
+ if (IS_ERR(pdata))
+ return PTR_ERR(pdata);
+ adev->dev.platform_data = pdata;
+
+ drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+
+ drvdata->dev = &adev->dev;
+ dev_set_drvdata(dev, drvdata);
+
+ base = devm_ioremap_resource(dev, &adev->res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+ drvdata->base = base;
+
+ spin_lock_init(&drvdata->spinlock);
+
+ ret = tpda_init_default_data(drvdata);
+ if (ret)
+ return ret;
+
+ desc.name = coresight_alloc_device_name(&tpda_devs, dev);
+ if (!desc.name)
+ return -ENOMEM;
+ desc.type = CORESIGHT_DEV_TYPE_LINK;
+ desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_MERG;
+ desc.ops = &tpda_cs_ops;
+ desc.pdata = adev->dev.platform_data;
+ desc.dev = &adev->dev;
+ desc.access = CSDEV_ACCESS_IOMEM(base);
+ drvdata->csdev = coresight_register(&desc);
+ if (IS_ERR(drvdata->csdev))
+ return PTR_ERR(drvdata->csdev);
+
+ pm_runtime_put(&adev->dev);
+
+ dev_dbg(drvdata->dev, "TPDA initialized\n");
+ return 0;
+}
+
+static void tpda_remove(struct amba_device *adev)
+{
+ struct tpda_drvdata *drvdata = dev_get_drvdata(&adev->dev);
+
+ coresight_trace_id_put_system_id(drvdata->atid);
+ coresight_unregister(drvdata->csdev);
+}
+
+/*
+ * Different TPDA has different periph id.
+ * The difference is 0-7 bits' value. So ignore 0-7 bits.
+ */
+static struct amba_id tpda_ids[] = {
+ {
+ .id = 0x000f0f00,
+ .mask = 0x000fff00,
+ },
+ { 0, 0},
+};
+
+static struct amba_driver tpda_driver = {
+ .drv = {
+ .name = "coresight-tpda",
+ .owner = THIS_MODULE,
+ .suppress_bind_attrs = true,
+ },
+ .probe = tpda_probe,
+ .remove = tpda_remove,
+ .id_table = tpda_ids,
+};
+
+module_amba_driver(tpda_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Trace, Profiling & Diagnostic Aggregator driver");
diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/hwtracing/coresight/coresight-tpda.h
new file mode 100644
index 000000000000..0399678df312
--- /dev/null
+++ b/drivers/hwtracing/coresight/coresight-tpda.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _CORESIGHT_CORESIGHT_TPDA_H
+#define _CORESIGHT_CORESIGHT_TPDA_H
+
+#define TPDA_CR (0x000)
+#define TPDA_Pn_CR(n) (0x004 + (n * 4))
+/* Aggregator port enable bit */
+#define TPDA_Pn_CR_ENA BIT(0)
+
+#define TPDA_MAX_INPORTS 32
+
+/* Bits 6 ~ 12 is for atid value */
+#define TPDA_CR_ATID GENMASK(12, 6)
+
+/**
+ * struct tpda_drvdata - specifics associated to an TPDA component
+ * @base: memory mapped base address for this component.
+ * @dev: The device entity associated to this component.
+ * @csdev: component vitals needed by the framework.
+ * @spinlock: lock for the drvdata value.
+ * @enable: enable status of the component.
+ */
+struct tpda_drvdata {
+ void __iomem *base;
+ struct device *dev;
+ struct coresight_device *csdev;
+ spinlock_t spinlock;
+ u8 atid;
+};
+
+#endif /* _CORESIGHT_CORESIGHT_TPDA_H */
diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c
new file mode 100644
index 000000000000..9479a5e8c672
--- /dev/null
+++ b/drivers/hwtracing/coresight/coresight-tpdm.c
@@ -0,0 +1,259 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/amba/bus.h>
+#include <linux/bitmap.h>
+#include <linux/coresight.h>
+#include <linux/coresight-pmu.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+
+#include "coresight-priv.h"
+#include "coresight-tpdm.h"
+
+DEFINE_CORESIGHT_DEVLIST(tpdm_devs, "tpdm");
+
+static void tpdm_enable_dsb(struct tpdm_drvdata *drvdata)
+{
+ u32 val;
+
+ /* Set the enable bit of DSB control register to 1 */
+ val = readl_relaxed(drvdata->base + TPDM_DSB_CR);
+ val |= TPDM_DSB_CR_ENA;
+ writel_relaxed(val, drvdata->base + TPDM_DSB_CR);
+}
+
+/* TPDM enable operations */
+static void __tpdm_enable(struct tpdm_drvdata *drvdata)
+{
+ CS_UNLOCK(drvdata->base);
+
+ /* Check if DSB datasets is present for TPDM. */
+ if (drvdata->datasets & TPDM_PIDR0_DS_DSB)
+ tpdm_enable_dsb(drvdata);
+
+ CS_LOCK(drvdata->base);
+}
+
+static int tpdm_enable(struct coresight_device *csdev,
+ struct perf_event *event, u32 mode)
+{
+ struct tpdm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+ spin_lock(&drvdata->spinlock);
+ if (drvdata->enable) {
+ spin_unlock(&drvdata->spinlock);
+ return -EBUSY;
+ }
+
+ __tpdm_enable(drvdata);
+ drvdata->enable = true;
+ spin_unlock(&drvdata->spinlock);
+
+ dev_dbg(drvdata->dev, "TPDM tracing enabled\n");
+ return 0;
+}
+
+static void tpdm_disable_dsb(struct tpdm_drvdata *drvdata)
+{
+ u32 val;
+
+ /* Set the enable bit of DSB control register to 0 */
+ val = readl_relaxed(drvdata->base + TPDM_DSB_CR);
+ val &= ~TPDM_DSB_CR_ENA;
+ writel_relaxed(val, drvdata->base + TPDM_DSB_CR);
+}
+
+/* TPDM disable operations */
+static void __tpdm_disable(struct tpdm_drvdata *drvdata)
+{
+ CS_UNLOCK(drvdata->base);
+
+ /* Check if DSB datasets is present for TPDM. */
+ if (drvdata->datasets & TPDM_PIDR0_DS_DSB)
+ tpdm_disable_dsb(drvdata);
+
+ CS_LOCK(drvdata->base);
+}
+
+static void tpdm_disable(struct coresight_device *csdev,
+ struct perf_event *event)
+{
+ struct tpdm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+ spin_lock(&drvdata->spinlock);
+ if (!drvdata->enable) {
+ spin_unlock(&drvdata->spinlock);
+ return;
+ }
+
+ __tpdm_disable(drvdata);
+ drvdata->enable = false;
+ spin_unlock(&drvdata->spinlock);
+
+ dev_dbg(drvdata->dev, "TPDM tracing disabled\n");
+}
+
+static const struct coresight_ops_source tpdm_source_ops = {
+ .enable = tpdm_enable,
+ .disable = tpdm_disable,
+};
+
+static const struct coresight_ops tpdm_cs_ops = {
+ .source_ops = &tpdm_source_ops,
+};
+
+static void tpdm_init_default_data(struct tpdm_drvdata *drvdata)
+{
+ u32 pidr;
+
+ CS_UNLOCK(drvdata->base);
+ /* Get the datasets present on the TPDM. */
+ pidr = readl_relaxed(drvdata->base + CORESIGHT_PERIPHIDR0);
+ drvdata->datasets |= pidr & GENMASK(TPDM_DATASETS - 1, 0);
+ CS_LOCK(drvdata->base);
+}
+
+/*
+ * value 1: 64 bits test data
+ * value 2: 32 bits test data
+ */
+static ssize_t integration_test_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t size)
+{
+ int i, ret = 0;
+ unsigned long val;
+ struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+ ret = kstrtoul(buf, 10, &val);
+ if (ret)
+ return ret;
+
+ if (val != 1 && val != 2)
+ return -EINVAL;
+
+ if (!drvdata->enable)
+ return -EINVAL;
+
+ if (val == 1)
+ val = ATBCNTRL_VAL_64;
+ else
+ val = ATBCNTRL_VAL_32;
+ CS_UNLOCK(drvdata->base);
+ writel_relaxed(0x1, drvdata->base + TPDM_ITCNTRL);
+
+ for (i = 0; i < INTEGRATION_TEST_CYCLE; i++)
+ writel_relaxed(val, drvdata->base + TPDM_ITATBCNTRL);
+
+ writel_relaxed(0, drvdata->base + TPDM_ITCNTRL);
+ CS_LOCK(drvdata->base);
+ return size;
+}
+static DEVICE_ATTR_WO(integration_test);
+
+static struct attribute *tpdm_attrs[] = {
+ &dev_attr_integration_test.attr,
+ NULL,
+};
+
+static struct attribute_group tpdm_attr_grp = {
+ .attrs = tpdm_attrs,
+};
+
+static const struct attribute_group *tpdm_attr_grps[] = {
+ &tpdm_attr_grp,
+ NULL,
+};
+
+static int tpdm_probe(struct amba_device *adev, const struct amba_id *id)
+{
+ void __iomem *base;
+ struct device *dev = &adev->dev;
+ struct coresight_platform_data *pdata;
+ struct tpdm_drvdata *drvdata;
+ struct coresight_desc desc = { 0 };
+
+ pdata = coresight_get_platform_data(dev);
+ if (IS_ERR(pdata))
+ return PTR_ERR(pdata);
+ adev->dev.platform_data = pdata;
+
+ /* driver data*/
+ drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+ drvdata->dev = &adev->dev;
+ dev_set_drvdata(dev, drvdata);
+
+ base = devm_ioremap_resource(dev, &adev->res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ drvdata->base = base;
+
+ /* Set up coresight component description */
+ desc.name = coresight_alloc_device_name(&tpdm_devs, dev);
+ if (!desc.name)
+ return -ENOMEM;
+ desc.type = CORESIGHT_DEV_TYPE_SOURCE;
+ desc.subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS;
+ desc.ops = &tpdm_cs_ops;
+ desc.pdata = adev->dev.platform_data;
+ desc.dev = &adev->dev;
+ desc.access = CSDEV_ACCESS_IOMEM(base);
+ desc.groups = tpdm_attr_grps;
+ drvdata->csdev = coresight_register(&desc);
+ if (IS_ERR(drvdata->csdev))
+ return PTR_ERR(drvdata->csdev);
+
+ spin_lock_init(&drvdata->spinlock);
+ tpdm_init_default_data(drvdata);
+ /* Decrease pm refcount when probe is done.*/
+ pm_runtime_put(&adev->dev);
+
+ return 0;
+}
+
+static void tpdm_remove(struct amba_device *adev)
+{
+ struct tpdm_drvdata *drvdata = dev_get_drvdata(&adev->dev);
+
+ coresight_unregister(drvdata->csdev);
+}
+
+/*
+ * Different TPDM has different periph id.
+ * The difference is 0-7 bits' value. So ignore 0-7 bits.
+ */
+static struct amba_id tpdm_ids[] = {
+ {
+ .id = 0x000f0e00,
+ .mask = 0x000fff00,
+ },
+ { 0, 0},
+};
+
+static struct amba_driver tpdm_driver = {
+ .drv = {
+ .name = "coresight-tpdm",
+ .owner = THIS_MODULE,
+ .suppress_bind_attrs = true,
+ },
+ .probe = tpdm_probe,
+ .id_table = tpdm_ids,
+ .remove = tpdm_remove,
+};
+
+module_amba_driver(tpdm_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Trace, Profiling & Diagnostic Monitor driver");
diff --git a/drivers/hwtracing/coresight/coresight-tpdm.h b/drivers/hwtracing/coresight/coresight-tpdm.h
new file mode 100644
index 000000000000..543854043a2d
--- /dev/null
+++ b/drivers/hwtracing/coresight/coresight-tpdm.h
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _CORESIGHT_CORESIGHT_TPDM_H
+#define _CORESIGHT_CORESIGHT_TPDM_H
+
+/* The max number of the datasets that TPDM supports */
+#define TPDM_DATASETS 7
+
+/* DSB Subunit Registers */
+#define TPDM_DSB_CR (0x780)
+/* Enable bit for DSB subunit */
+#define TPDM_DSB_CR_ENA BIT(0)
+
+/* TPDM integration test registers */
+#define TPDM_ITATBCNTRL (0xEF0)
+#define TPDM_ITCNTRL (0xF00)
+
+/* Register value for integration test */
+#define ATBCNTRL_VAL_32 0xC00F1409
+#define ATBCNTRL_VAL_64 0xC01F1409
+
+/*
+ * Number of cycles to write value when
+ * integration test.
+ */
+#define INTEGRATION_TEST_CYCLE 10
+
+/**
+ * The bits of PERIPHIDR0 register.
+ * The fields [6:0] of PERIPHIDR0 are used to determine what
+ * interfaces and subunits are present on a given TPDM.
+ *
+ * PERIPHIDR0[0] : Fix to 1 if ImplDef subunit present, else 0
+ * PERIPHIDR0[1] : Fix to 1 if DSB subunit present, else 0
+ */
+
+#define TPDM_PIDR0_DS_IMPDEF BIT(0)
+#define TPDM_PIDR0_DS_DSB BIT(1)
+
+/**
+ * struct tpdm_drvdata - specifics associated to an TPDM component
+ * @base: memory mapped base address for this component.
+ * @dev: The device entity associated to this component.
+ * @csdev: component vitals needed by the framework.
+ * @spinlock: lock for the drvdata value.
+ * @enable: enable status of the component.
+ * @datasets: The datasets types present of the TPDM.
+ */
+
+struct tpdm_drvdata {
+ void __iomem *base;
+ struct device *dev;
+ struct coresight_device *csdev;
+ spinlock_t spinlock;
+ bool enable;
+ unsigned long datasets;
+};
+
+#endif /* _CORESIGHT_CORESIGHT_TPDM_H */
diff --git a/drivers/hwtracing/coresight/coresight-trace-id.c b/drivers/hwtracing/coresight/coresight-trace-id.c
new file mode 100644
index 000000000000..af5b4ef59cea
--- /dev/null
+++ b/drivers/hwtracing/coresight/coresight-trace-id.c
@@ -0,0 +1,297 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022, Linaro Limited, All rights reserved.
+ * Author: Mike Leach <mike.leach@linaro.org>
+ */
+#include <linux/coresight-pmu.h>
+#include <linux/cpumask.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include "coresight-trace-id.h"
+
+/* Default trace ID map. Used on systems that don't require per sink mappings */
+static struct coresight_trace_id_map id_map_default;
+
+/* maintain a record of the mapping of IDs and pending releases per cpu */
+static DEFINE_PER_CPU(atomic_t, cpu_id) = ATOMIC_INIT(0);
+static cpumask_t cpu_id_release_pending;
+
+/* perf session active counter */
+static atomic_t perf_cs_etm_session_active = ATOMIC_INIT(0);
+
+/* lock to protect id_map and cpu data */
+static DEFINE_SPINLOCK(id_map_lock);
+
+/* #define TRACE_ID_DEBUG 1 */
+#if defined(TRACE_ID_DEBUG) || defined(CONFIG_COMPILE_TEST)
+
+static void coresight_trace_id_dump_table(struct coresight_trace_id_map *id_map,
+ const char *func_name)
+{
+ pr_debug("%s id_map::\n", func_name);
+ pr_debug("Used = %*pb\n", CORESIGHT_TRACE_IDS_MAX, id_map->used_ids);
+ pr_debug("Pend = %*pb\n", CORESIGHT_TRACE_IDS_MAX, id_map->pend_rel_ids);
+}
+#define DUMP_ID_MAP(map) coresight_trace_id_dump_table(map, __func__)
+#define DUMP_ID_CPU(cpu, id) pr_debug("%s called; cpu=%d, id=%d\n", __func__, cpu, id)
+#define DUMP_ID(id) pr_debug("%s called; id=%d\n", __func__, id)
+#define PERF_SESSION(n) pr_debug("%s perf count %d\n", __func__, n)
+#else
+#define DUMP_ID_MAP(map)
+#define DUMP_ID(id)
+#define DUMP_ID_CPU(cpu, id)
+#define PERF_SESSION(n)
+#endif
+
+/* unlocked read of current trace ID value for given CPU */
+static int _coresight_trace_id_read_cpu_id(int cpu)
+{
+ return atomic_read(&per_cpu(cpu_id, cpu));
+}
+
+/* look for next available odd ID, return 0 if none found */
+static int coresight_trace_id_find_odd_id(struct coresight_trace_id_map *id_map)
+{
+ int found_id = 0, bit = 1, next_id;
+
+ while ((bit < CORESIGHT_TRACE_ID_RES_TOP) && !found_id) {
+ /*
+ * bitmap length of CORESIGHT_TRACE_ID_RES_TOP,
+ * search from offset `bit`.
+ */
+ next_id = find_next_zero_bit(id_map->used_ids,
+ CORESIGHT_TRACE_ID_RES_TOP, bit);
+ if ((next_id < CORESIGHT_TRACE_ID_RES_TOP) && (next_id & 0x1))
+ found_id = next_id;
+ else
+ bit = next_id + 1;
+ }
+ return found_id;
+}
+
+/*
+ * Allocate new ID and set in use
+ *
+ * if @preferred_id is a valid id then try to use that value if available.
+ * if @preferred_id is not valid and @prefer_odd_id is true, try for odd id.
+ *
+ * Otherwise allocate next available ID.
+ */
+static int coresight_trace_id_alloc_new_id(struct coresight_trace_id_map *id_map,
+ int preferred_id, bool prefer_odd_id)
+{
+ int id = 0;
+
+ /* for backwards compatibility, cpu IDs may use preferred value */
+ if (IS_VALID_CS_TRACE_ID(preferred_id) &&
+ !test_bit(preferred_id, id_map->used_ids)) {
+ id = preferred_id;
+ goto trace_id_allocated;
+ } else if (prefer_odd_id) {
+ /* may use odd ids to avoid preferred legacy cpu IDs */
+ id = coresight_trace_id_find_odd_id(id_map);
+ if (id)
+ goto trace_id_allocated;
+ }
+
+ /*
+ * skip reserved bit 0, look at bitmap length of
+ * CORESIGHT_TRACE_ID_RES_TOP from offset of bit 1.
+ */
+ id = find_next_zero_bit(id_map->used_ids, CORESIGHT_TRACE_ID_RES_TOP, 1);
+ if (id >= CORESIGHT_TRACE_ID_RES_TOP)
+ return -EINVAL;
+
+ /* mark as used */
+trace_id_allocated:
+ set_bit(id, id_map->used_ids);
+ return id;
+}
+
+static void coresight_trace_id_free(int id, struct coresight_trace_id_map *id_map)
+{
+ if (WARN(!IS_VALID_CS_TRACE_ID(id), "Invalid Trace ID %d\n", id))
+ return;
+ if (WARN(!test_bit(id, id_map->used_ids), "Freeing unused ID %d\n", id))
+ return;
+ clear_bit(id, id_map->used_ids);
+}
+
+static void coresight_trace_id_set_pend_rel(int id, struct coresight_trace_id_map *id_map)
+{
+ if (WARN(!IS_VALID_CS_TRACE_ID(id), "Invalid Trace ID %d\n", id))
+ return;
+ set_bit(id, id_map->pend_rel_ids);
+}
+
+/*
+ * release all pending IDs for all current maps & clear CPU associations
+ *
+ * This currently operates on the default id map, but may be extended to
+ * operate on all registered id maps if per sink id maps are used.
+ */
+static void coresight_trace_id_release_all_pending(void)
+{
+ struct coresight_trace_id_map *id_map = &id_map_default;
+ unsigned long flags;
+ int cpu, bit;
+
+ spin_lock_irqsave(&id_map_lock, flags);
+ for_each_set_bit(bit, id_map->pend_rel_ids, CORESIGHT_TRACE_ID_RES_TOP) {
+ clear_bit(bit, id_map->used_ids);
+ clear_bit(bit, id_map->pend_rel_ids);
+ }
+ for_each_cpu(cpu, &cpu_id_release_pending) {
+ atomic_set(&per_cpu(cpu_id, cpu), 0);
+ cpumask_clear_cpu(cpu, &cpu_id_release_pending);
+ }
+ spin_unlock_irqrestore(&id_map_lock, flags);
+ DUMP_ID_MAP(id_map);
+}
+
+static int coresight_trace_id_map_get_cpu_id(int cpu, struct coresight_trace_id_map *id_map)
+{
+ unsigned long flags;
+ int id;
+
+ spin_lock_irqsave(&id_map_lock, flags);
+
+ /* check for existing allocation for this CPU */
+ id = _coresight_trace_id_read_cpu_id(cpu);
+ if (id)
+ goto get_cpu_id_clr_pend;
+
+ /*
+ * Find a new ID.
+ *
+ * Use legacy values where possible in the dynamic trace ID allocator to
+ * allow older tools to continue working if they are not upgraded at the
+ * same time as the kernel drivers.
+ *
+ * If the generated legacy ID is invalid, or not available then the next
+ * available dynamic ID will be used.
+ */
+ id = coresight_trace_id_alloc_new_id(id_map,
+ CORESIGHT_LEGACY_CPU_TRACE_ID(cpu),
+ false);
+ if (!IS_VALID_CS_TRACE_ID(id))
+ goto get_cpu_id_out_unlock;
+
+ /* allocate the new id to the cpu */
+ atomic_set(&per_cpu(cpu_id, cpu), id);
+
+get_cpu_id_clr_pend:
+ /* we are (re)using this ID - so ensure it is not marked for release */
+ cpumask_clear_cpu(cpu, &cpu_id_release_pending);
+ clear_bit(id, id_map->pend_rel_ids);
+
+get_cpu_id_out_unlock:
+ spin_unlock_irqrestore(&id_map_lock, flags);
+
+ DUMP_ID_CPU(cpu, id);
+ DUMP_ID_MAP(id_map);
+ return id;
+}
+
+static void coresight_trace_id_map_put_cpu_id(int cpu, struct coresight_trace_id_map *id_map)
+{
+ unsigned long flags;
+ int id;
+
+ /* check for existing allocation for this CPU */
+ id = _coresight_trace_id_read_cpu_id(cpu);
+ if (!id)
+ return;
+
+ spin_lock_irqsave(&id_map_lock, flags);
+
+ if (atomic_read(&perf_cs_etm_session_active)) {
+ /* set release at pending if perf still active */
+ coresight_trace_id_set_pend_rel(id, id_map);
+ cpumask_set_cpu(cpu, &cpu_id_release_pending);
+ } else {
+ /* otherwise clear id */
+ coresight_trace_id_free(id, id_map);
+ atomic_set(&per_cpu(cpu_id, cpu), 0);
+ }
+
+ spin_unlock_irqrestore(&id_map_lock, flags);
+ DUMP_ID_CPU(cpu, id);
+ DUMP_ID_MAP(id_map);
+}
+
+static int coresight_trace_id_map_get_system_id(struct coresight_trace_id_map *id_map)
+{
+ unsigned long flags;
+ int id;
+
+ spin_lock_irqsave(&id_map_lock, flags);
+ /* prefer odd IDs for system components to avoid legacy CPU IDS */
+ id = coresight_trace_id_alloc_new_id(id_map, 0, true);
+ spin_unlock_irqrestore(&id_map_lock, flags);
+
+ DUMP_ID(id);
+ DUMP_ID_MAP(id_map);
+ return id;
+}
+
+static void coresight_trace_id_map_put_system_id(struct coresight_trace_id_map *id_map, int id)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&id_map_lock, flags);
+ coresight_trace_id_free(id, id_map);
+ spin_unlock_irqrestore(&id_map_lock, flags);
+
+ DUMP_ID(id);
+ DUMP_ID_MAP(id_map);
+}
+
+/* API functions */
+
+int coresight_trace_id_get_cpu_id(int cpu)
+{
+ return coresight_trace_id_map_get_cpu_id(cpu, &id_map_default);
+}
+EXPORT_SYMBOL_GPL(coresight_trace_id_get_cpu_id);
+
+void coresight_trace_id_put_cpu_id(int cpu)
+{
+ coresight_trace_id_map_put_cpu_id(cpu, &id_map_default);
+}
+EXPORT_SYMBOL_GPL(coresight_trace_id_put_cpu_id);
+
+int coresight_trace_id_read_cpu_id(int cpu)
+{
+ return _coresight_trace_id_read_cpu_id(cpu);
+}
+EXPORT_SYMBOL_GPL(coresight_trace_id_read_cpu_id);
+
+int coresight_trace_id_get_system_id(void)
+{
+ return coresight_trace_id_map_get_system_id(&id_map_default);
+}
+EXPORT_SYMBOL_GPL(coresight_trace_id_get_system_id);
+
+void coresight_trace_id_put_system_id(int id)
+{
+ coresight_trace_id_map_put_system_id(&id_map_default, id);
+}
+EXPORT_SYMBOL_GPL(coresight_trace_id_put_system_id);
+
+void coresight_trace_id_perf_start(void)
+{
+ atomic_inc(&perf_cs_etm_session_active);
+ PERF_SESSION(atomic_read(&perf_cs_etm_session_active));
+}
+EXPORT_SYMBOL_GPL(coresight_trace_id_perf_start);
+
+void coresight_trace_id_perf_stop(void)
+{
+ if (!atomic_dec_return(&perf_cs_etm_session_active))
+ coresight_trace_id_release_all_pending();
+ PERF_SESSION(atomic_read(&perf_cs_etm_session_active));
+}
+EXPORT_SYMBOL_GPL(coresight_trace_id_perf_stop);
diff --git a/drivers/hwtracing/coresight/coresight-trace-id.h b/drivers/hwtracing/coresight/coresight-trace-id.h
new file mode 100644
index 000000000000..3797777d367e
--- /dev/null
+++ b/drivers/hwtracing/coresight/coresight-trace-id.h
@@ -0,0 +1,156 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright(C) 2022 Linaro Limited. All rights reserved.
+ * Author: Mike Leach <mike.leach@linaro.org>
+ */
+
+#ifndef _CORESIGHT_TRACE_ID_H
+#define _CORESIGHT_TRACE_ID_H
+
+/*
+ * Coresight trace ID allocation API
+ *
+ * With multi cpu systems, and more additional trace sources a scalable
+ * trace ID reservation system is required.
+ *
+ * The system will allocate Ids on a demand basis, and allow them to be
+ * released when done.
+ *
+ * In order to ensure that a consistent cpu / ID matching is maintained
+ * throughout a perf cs_etm event session - a session in progress flag will
+ * be maintained, and released IDs not cleared until the perf session is
+ * complete. This allows the same CPU to be re-allocated its prior ID.
+ *
+ *
+ * Trace ID maps will be created and initialised to prevent architecturally
+ * reserved IDs from being allocated.
+ *
+ * API permits multiple maps to be maintained - for large systems where
+ * different sets of cpus trace into different independent sinks.
+ */
+
+#include <linux/bitops.h>
+#include <linux/types.h>
+
+
+/* architecturally we have 128 IDs some of which are reserved */
+#define CORESIGHT_TRACE_IDS_MAX 128
+
+/* ID 0 is reserved */
+#define CORESIGHT_TRACE_ID_RES_0 0
+
+/* ID 0x70 onwards are reserved */
+#define CORESIGHT_TRACE_ID_RES_TOP 0x70
+
+/* check an ID is in the valid range */
+#define IS_VALID_CS_TRACE_ID(id) \
+ ((id > CORESIGHT_TRACE_ID_RES_0) && (id < CORESIGHT_TRACE_ID_RES_TOP))
+
+/**
+ * Trace ID map.
+ *
+ * @used_ids: Bitmap to register available (bit = 0) and in use (bit = 1) IDs.
+ * Initialised so that the reserved IDs are permanently marked as
+ * in use.
+ * @pend_rel_ids: CPU IDs that have been released by the trace source but not
+ * yet marked as available, to allow re-allocation to the same
+ * CPU during a perf session.
+ */
+struct coresight_trace_id_map {
+ DECLARE_BITMAP(used_ids, CORESIGHT_TRACE_IDS_MAX);
+ DECLARE_BITMAP(pend_rel_ids, CORESIGHT_TRACE_IDS_MAX);
+};
+
+/* Allocate and release IDs for a single default trace ID map */
+
+/**
+ * Read and optionally allocate a CoreSight trace ID and associate with a CPU.
+ *
+ * Function will read the current trace ID for the associated CPU,
+ * allocating an new ID if one is not currently allocated.
+ *
+ * Numeric ID values allocated use legacy allocation algorithm if possible,
+ * otherwise any available ID is used.
+ *
+ * @cpu: The CPU index to allocate for.
+ *
+ * return: CoreSight trace ID or -EINVAL if allocation impossible.
+ */
+int coresight_trace_id_get_cpu_id(int cpu);
+
+/**
+ * Release an allocated trace ID associated with the CPU.
+ *
+ * This will release the CoreSight trace ID associated with the CPU,
+ * unless a perf session is in operation.
+ *
+ * If a perf session is in operation then the ID will be marked as pending
+ * release.
+ *
+ * @cpu: The CPU index to release the associated trace ID.
+ */
+void coresight_trace_id_put_cpu_id(int cpu);
+
+/**
+ * Read the current allocated CoreSight Trace ID value for the CPU.
+ *
+ * Fast read of the current value that does not allocate if no ID allocated
+ * for the CPU.
+ *
+ * Used in perf context where it is known that the value for the CPU will not
+ * be changing, when perf starts and event on a core and outputs the Trace ID
+ * for the CPU as a packet in the data file. IDs cannot change during a perf
+ * session.
+ *
+ * This function does not take the lock protecting the ID lists, avoiding
+ * locking dependency issues with perf locks.
+ *
+ * @cpu: The CPU index to read.
+ *
+ * return: current value, will be 0 if unallocated.
+ */
+int coresight_trace_id_read_cpu_id(int cpu);
+
+/**
+ * Allocate a CoreSight trace ID for a system component.
+ *
+ * Unconditionally allocates a Trace ID, without associating the ID with a CPU.
+ *
+ * Used to allocate IDs for system trace sources such as STM.
+ *
+ * return: Trace ID or -EINVAL if allocation is impossible.
+ */
+int coresight_trace_id_get_system_id(void);
+
+/**
+ * Release an allocated system trace ID.
+ *
+ * Unconditionally release a trace ID allocated to a system component.
+ *
+ * @id: value of trace ID allocated.
+ */
+void coresight_trace_id_put_system_id(int id);
+
+/* notifiers for perf session start and stop */
+
+/**
+ * Notify the Trace ID allocator that a perf session is starting.
+ *
+ * Increase the perf session reference count - called by perf when setting up
+ * a trace event.
+ *
+ * This reference count is used by the ID allocator to ensure that trace IDs
+ * associated with a CPU cannot change or be released during a perf session.
+ */
+void coresight_trace_id_perf_start(void);
+
+/**
+ * Notify the ID allocator that a perf session is stopping.
+ *
+ * Decrease the perf session reference count.
+ * if this causes the count to go to zero, then all Trace IDs marked as pending
+ * release, will be released.
+ */
+void coresight_trace_id_perf_stop(void);
+
+#endif /* _CORESIGHT_TRACE_ID_H */
diff --git a/drivers/hwtracing/coresight/ultrasoc-smb.c b/drivers/hwtracing/coresight/ultrasoc-smb.c
new file mode 100644
index 000000000000..b317342c7ce5
--- /dev/null
+++ b/drivers/hwtracing/coresight/ultrasoc-smb.c
@@ -0,0 +1,648 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Siemens System Memory Buffer driver.
+ * Copyright(c) 2022, HiSilicon Limited.
+ */
+
+#include <linux/atomic.h>
+#include <linux/acpi.h>
+#include <linux/circ_buf.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+
+#include "coresight-etm-perf.h"
+#include "coresight-priv.h"
+#include "ultrasoc-smb.h"
+
+DEFINE_CORESIGHT_DEVLIST(sink_devs, "ultra_smb");
+
+#define ULTRASOC_SMB_DSM_UUID "82ae1283-7f6a-4cbe-aa06-53e8fb24db18"
+
+static bool smb_buffer_not_empty(struct smb_drv_data *drvdata)
+{
+ u32 buf_status = readl(drvdata->base + SMB_LB_INT_STS_REG);
+
+ return FIELD_GET(SMB_LB_INT_STS_NOT_EMPTY_MSK, buf_status);
+}
+
+static void smb_update_data_size(struct smb_drv_data *drvdata)
+{
+ struct smb_data_buffer *sdb = &drvdata->sdb;
+ u32 buf_wrptr;
+
+ buf_wrptr = readl(drvdata->base + SMB_LB_WR_ADDR_REG) -
+ sdb->buf_hw_base;
+
+ /* Buffer is full */
+ if (buf_wrptr == sdb->buf_rdptr && smb_buffer_not_empty(drvdata)) {
+ sdb->data_size = sdb->buf_size;
+ return;
+ }
+
+ /* The buffer mode is circular buffer mode */
+ sdb->data_size = CIRC_CNT(buf_wrptr, sdb->buf_rdptr,
+ sdb->buf_size);
+}
+
+/*
+ * The read pointer adds @nbytes bytes (may round up to the beginning)
+ * after the data is read or discarded, while needing to update the
+ * available data size.
+ */
+static void smb_update_read_ptr(struct smb_drv_data *drvdata, u32 nbytes)
+{
+ struct smb_data_buffer *sdb = &drvdata->sdb;
+
+ sdb->buf_rdptr += nbytes;
+ sdb->buf_rdptr %= sdb->buf_size;
+ writel(sdb->buf_hw_base + sdb->buf_rdptr,
+ drvdata->base + SMB_LB_RD_ADDR_REG);
+
+ sdb->data_size -= nbytes;
+}
+
+static void smb_reset_buffer(struct smb_drv_data *drvdata)
+{
+ struct smb_data_buffer *sdb = &drvdata->sdb;
+ u32 write_ptr;
+
+ /*
+ * We must flush and discard any data left in hardware path
+ * to avoid corrupting the next session.
+ * Note: The write pointer will never exceed the read pointer.
+ */
+ writel(SMB_LB_PURGE_PURGED, drvdata->base + SMB_LB_PURGE_REG);
+
+ /* Reset SMB logical buffer status flags */
+ writel(SMB_LB_INT_STS_RESET, drvdata->base + SMB_LB_INT_STS_REG);
+
+ write_ptr = readl(drvdata->base + SMB_LB_WR_ADDR_REG);
+
+ /* Do nothing, not data left in hardware path */
+ if (!write_ptr || write_ptr == sdb->buf_rdptr + sdb->buf_hw_base)
+ return;
+
+ /*
+ * The SMB_LB_WR_ADDR_REG register is read-only,
+ * Synchronize the read pointer to write pointer.
+ */
+ writel(write_ptr, drvdata->base + SMB_LB_RD_ADDR_REG);
+ sdb->buf_rdptr = write_ptr - sdb->buf_hw_base;
+}
+
+static int smb_open(struct inode *inode, struct file *file)
+{
+ struct smb_drv_data *drvdata = container_of(file->private_data,
+ struct smb_drv_data, miscdev);
+ int ret = 0;
+
+ mutex_lock(&drvdata->mutex);
+
+ if (drvdata->reading) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ if (atomic_read(drvdata->csdev->refcnt)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ smb_update_data_size(drvdata);
+
+ drvdata->reading = true;
+out:
+ mutex_unlock(&drvdata->mutex);
+
+ return ret;
+}
+
+static ssize_t smb_read(struct file *file, char __user *data, size_t len,
+ loff_t *ppos)
+{
+ struct smb_drv_data *drvdata = container_of(file->private_data,
+ struct smb_drv_data, miscdev);
+ struct smb_data_buffer *sdb = &drvdata->sdb;
+ struct device *dev = &drvdata->csdev->dev;
+ ssize_t to_copy = 0;
+
+ if (!len)
+ return 0;
+
+ mutex_lock(&drvdata->mutex);
+
+ if (!sdb->data_size)
+ goto out;
+
+ to_copy = min(sdb->data_size, len);
+
+ /* Copy parts of trace data when read pointer wrap around SMB buffer */
+ if (sdb->buf_rdptr + to_copy > sdb->buf_size)
+ to_copy = sdb->buf_size - sdb->buf_rdptr;
+
+ if (copy_to_user(data, sdb->buf_base + sdb->buf_rdptr, to_copy)) {
+ dev_dbg(dev, "Failed to copy data to user\n");
+ to_copy = -EFAULT;
+ goto out;
+ }
+
+ *ppos += to_copy;
+
+ smb_update_read_ptr(drvdata, to_copy);
+
+ dev_dbg(dev, "%zu bytes copied\n", to_copy);
+out:
+ if (!sdb->data_size)
+ smb_reset_buffer(drvdata);
+ mutex_unlock(&drvdata->mutex);
+
+ return to_copy;
+}
+
+static int smb_release(struct inode *inode, struct file *file)
+{
+ struct smb_drv_data *drvdata = container_of(file->private_data,
+ struct smb_drv_data, miscdev);
+
+ mutex_lock(&drvdata->mutex);
+ drvdata->reading = false;
+ mutex_unlock(&drvdata->mutex);
+
+ return 0;
+}
+
+static const struct file_operations smb_fops = {
+ .owner = THIS_MODULE,
+ .open = smb_open,
+ .read = smb_read,
+ .release = smb_release,
+ .llseek = no_llseek,
+};
+
+static ssize_t buf_size_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct smb_drv_data *drvdata = dev_get_drvdata(dev->parent);
+
+ return sysfs_emit(buf, "0x%lx\n", drvdata->sdb.buf_size);
+}
+static DEVICE_ATTR_RO(buf_size);
+
+static struct attribute *smb_sink_attrs[] = {
+ coresight_simple_reg32(read_pos, SMB_LB_RD_ADDR_REG),
+ coresight_simple_reg32(write_pos, SMB_LB_WR_ADDR_REG),
+ coresight_simple_reg32(buf_status, SMB_LB_INT_STS_REG),
+ &dev_attr_buf_size.attr,
+ NULL
+};
+
+static const struct attribute_group smb_sink_group = {
+ .attrs = smb_sink_attrs,
+ .name = "mgmt",
+};
+
+static const struct attribute_group *smb_sink_groups[] = {
+ &smb_sink_group,
+ NULL
+};
+
+static void smb_enable_hw(struct smb_drv_data *drvdata)
+{
+ writel(SMB_GLB_EN_HW_ENABLE, drvdata->base + SMB_GLB_EN_REG);
+}
+
+static void smb_disable_hw(struct smb_drv_data *drvdata)
+{
+ writel(0x0, drvdata->base + SMB_GLB_EN_REG);
+}
+
+static void smb_enable_sysfs(struct coresight_device *csdev)
+{
+ struct smb_drv_data *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+ if (drvdata->mode != CS_MODE_DISABLED)
+ return;
+
+ smb_enable_hw(drvdata);
+ drvdata->mode = CS_MODE_SYSFS;
+}
+
+static int smb_enable_perf(struct coresight_device *csdev, void *data)
+{
+ struct smb_drv_data *drvdata = dev_get_drvdata(csdev->dev.parent);
+ struct perf_output_handle *handle = data;
+ struct cs_buffers *buf = etm_perf_sink_config(handle);
+ pid_t pid;
+
+ if (!buf)
+ return -EINVAL;
+
+ /* Get a handle on the pid of the target process */
+ pid = buf->pid;
+
+ /* Device is already in used by other session */
+ if (drvdata->pid != -1 && drvdata->pid != pid)
+ return -EBUSY;
+
+ if (drvdata->pid == -1) {
+ smb_enable_hw(drvdata);
+ drvdata->pid = pid;
+ drvdata->mode = CS_MODE_PERF;
+ }
+
+ return 0;
+}
+
+static int smb_enable(struct coresight_device *csdev, u32 mode, void *data)
+{
+ struct smb_drv_data *drvdata = dev_get_drvdata(csdev->dev.parent);
+ int ret = 0;
+
+ mutex_lock(&drvdata->mutex);
+
+ /* Do nothing, the trace data is reading by other interface now */
+ if (drvdata->reading) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ /* Do nothing, the SMB is already enabled as other mode */
+ if (drvdata->mode != CS_MODE_DISABLED && drvdata->mode != mode) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ switch (mode) {
+ case CS_MODE_SYSFS:
+ smb_enable_sysfs(csdev);
+ break;
+ case CS_MODE_PERF:
+ ret = smb_enable_perf(csdev, data);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ if (ret)
+ goto out;
+
+ atomic_inc(csdev->refcnt);
+
+ dev_dbg(&csdev->dev, "Ultrasoc SMB enabled\n");
+out:
+ mutex_unlock(&drvdata->mutex);
+
+ return ret;
+}
+
+static int smb_disable(struct coresight_device *csdev)
+{
+ struct smb_drv_data *drvdata = dev_get_drvdata(csdev->dev.parent);
+ int ret = 0;
+
+ mutex_lock(&drvdata->mutex);
+
+ if (drvdata->reading) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ if (atomic_dec_return(csdev->refcnt)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ /* Complain if we (somehow) got out of sync */
+ WARN_ON_ONCE(drvdata->mode == CS_MODE_DISABLED);
+
+ smb_disable_hw(drvdata);
+
+ /* Dissociate from the target process. */
+ drvdata->pid = -1;
+ drvdata->mode = CS_MODE_DISABLED;
+
+ dev_dbg(&csdev->dev, "Ultrasoc SMB disabled\n");
+out:
+ mutex_unlock(&drvdata->mutex);
+
+ return ret;
+}
+
+static void *smb_alloc_buffer(struct coresight_device *csdev,
+ struct perf_event *event, void **pages,
+ int nr_pages, bool overwrite)
+{
+ struct cs_buffers *buf;
+ int node;
+
+ node = (event->cpu == -1) ? NUMA_NO_NODE : cpu_to_node(event->cpu);
+ buf = kzalloc_node(sizeof(struct cs_buffers), GFP_KERNEL, node);
+ if (!buf)
+ return NULL;
+
+ buf->snapshot = overwrite;
+ buf->nr_pages = nr_pages;
+ buf->data_pages = pages;
+ buf->pid = task_pid_nr(event->owner);
+
+ return buf;
+}
+
+static void smb_free_buffer(void *config)
+{
+ struct cs_buffers *buf = config;
+
+ kfree(buf);
+}
+
+static void smb_sync_perf_buffer(struct smb_drv_data *drvdata,
+ struct cs_buffers *buf,
+ unsigned long head)
+{
+ struct smb_data_buffer *sdb = &drvdata->sdb;
+ char **dst_pages = (char **)buf->data_pages;
+ unsigned long to_copy;
+ long pg_idx, pg_offset;
+
+ pg_idx = head >> PAGE_SHIFT;
+ pg_offset = head & (PAGE_SIZE - 1);
+
+ while (sdb->data_size) {
+ unsigned long pg_space = PAGE_SIZE - pg_offset;
+
+ to_copy = min(sdb->data_size, pg_space);
+
+ /* Copy parts of trace data when read pointer wrap around */
+ if (sdb->buf_rdptr + to_copy > sdb->buf_size)
+ to_copy = sdb->buf_size - sdb->buf_rdptr;
+
+ memcpy(dst_pages[pg_idx] + pg_offset,
+ sdb->buf_base + sdb->buf_rdptr, to_copy);
+
+ pg_offset += to_copy;
+ if (pg_offset >= PAGE_SIZE) {
+ pg_offset = 0;
+ pg_idx++;
+ pg_idx %= buf->nr_pages;
+ }
+ smb_update_read_ptr(drvdata, to_copy);
+ }
+
+ smb_reset_buffer(drvdata);
+}
+
+static unsigned long smb_update_buffer(struct coresight_device *csdev,
+ struct perf_output_handle *handle,
+ void *sink_config)
+{
+ struct smb_drv_data *drvdata = dev_get_drvdata(csdev->dev.parent);
+ struct smb_data_buffer *sdb = &drvdata->sdb;
+ struct cs_buffers *buf = sink_config;
+ unsigned long data_size = 0;
+ bool lost = false;
+
+ if (!buf)
+ return 0;
+
+ mutex_lock(&drvdata->mutex);
+
+ /* Don't do anything if another tracer is using this sink. */
+ if (atomic_read(csdev->refcnt) != 1)
+ goto out;
+
+ smb_disable_hw(drvdata);
+ smb_update_data_size(drvdata);
+
+ /*
+ * The SMB buffer may be bigger than the space available in the
+ * perf ring buffer (handle->size). If so advance the offset so
+ * that we get the latest trace data.
+ */
+ if (sdb->data_size > handle->size) {
+ smb_update_read_ptr(drvdata, sdb->data_size - handle->size);
+ lost = true;
+ }
+
+ data_size = sdb->data_size;
+ smb_sync_perf_buffer(drvdata, buf, handle->head);
+ if (!buf->snapshot && lost)
+ perf_aux_output_flag(handle, PERF_AUX_FLAG_TRUNCATED);
+out:
+ mutex_unlock(&drvdata->mutex);
+
+ return data_size;
+}
+
+static const struct coresight_ops_sink smb_cs_ops = {
+ .enable = smb_enable,
+ .disable = smb_disable,
+ .alloc_buffer = smb_alloc_buffer,
+ .free_buffer = smb_free_buffer,
+ .update_buffer = smb_update_buffer,
+};
+
+static const struct coresight_ops cs_ops = {
+ .sink_ops = &smb_cs_ops,
+};
+
+static int smb_init_data_buffer(struct platform_device *pdev,
+ struct smb_data_buffer *sdb)
+{
+ struct resource *res;
+ void *base;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, SMB_BUF_ADDR_RES);
+ if (!res) {
+ dev_err(&pdev->dev, "SMB device failed to get resource\n");
+ return -EINVAL;
+ }
+
+ sdb->buf_rdptr = 0;
+ sdb->buf_hw_base = FIELD_GET(SMB_BUF_ADDR_LO_MSK, res->start);
+ sdb->buf_size = resource_size(res);
+ if (sdb->buf_size == 0)
+ return -EINVAL;
+
+ /*
+ * This is a chunk of memory, use classic mapping with better
+ * performance.
+ */
+ base = devm_memremap(&pdev->dev, sdb->buf_hw_base, sdb->buf_size,
+ MEMREMAP_WB);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ sdb->buf_base = base;
+
+ return 0;
+}
+
+static void smb_init_hw(struct smb_drv_data *drvdata)
+{
+ smb_disable_hw(drvdata);
+ smb_reset_buffer(drvdata);
+
+ writel(SMB_LB_CFG_LO_DEFAULT, drvdata->base + SMB_LB_CFG_LO_REG);
+ writel(SMB_LB_CFG_HI_DEFAULT, drvdata->base + SMB_LB_CFG_HI_REG);
+ writel(SMB_GLB_CFG_DEFAULT, drvdata->base + SMB_GLB_CFG_REG);
+ writel(SMB_GLB_INT_CFG, drvdata->base + SMB_GLB_INT_REG);
+ writel(SMB_LB_INT_CTRL_CFG, drvdata->base + SMB_LB_INT_CTRL_REG);
+}
+
+static int smb_register_sink(struct platform_device *pdev,
+ struct smb_drv_data *drvdata)
+{
+ struct coresight_platform_data *pdata = NULL;
+ struct coresight_desc desc = { 0 };
+ int ret;
+
+ pdata = coresight_get_platform_data(&pdev->dev);
+ if (IS_ERR(pdata))
+ return PTR_ERR(pdata);
+
+ desc.type = CORESIGHT_DEV_TYPE_SINK;
+ desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
+ desc.ops = &cs_ops;
+ desc.pdata = pdata;
+ desc.dev = &pdev->dev;
+ desc.groups = smb_sink_groups;
+ desc.name = coresight_alloc_device_name(&sink_devs, &pdev->dev);
+ if (!desc.name) {
+ dev_err(&pdev->dev, "Failed to alloc coresight device name");
+ return -ENOMEM;
+ }
+ desc.access = CSDEV_ACCESS_IOMEM(drvdata->base);
+
+ drvdata->csdev = coresight_register(&desc);
+ if (IS_ERR(drvdata->csdev))
+ return PTR_ERR(drvdata->csdev);
+
+ drvdata->miscdev.name = desc.name;
+ drvdata->miscdev.minor = MISC_DYNAMIC_MINOR;
+ drvdata->miscdev.fops = &smb_fops;
+ ret = misc_register(&drvdata->miscdev);
+ if (ret) {
+ coresight_unregister(drvdata->csdev);
+ dev_err(&pdev->dev, "Failed to register misc, ret=%d\n", ret);
+ }
+
+ return ret;
+}
+
+static void smb_unregister_sink(struct smb_drv_data *drvdata)
+{
+ misc_deregister(&drvdata->miscdev);
+ coresight_unregister(drvdata->csdev);
+}
+
+static int smb_config_inport(struct device *dev, bool enable)
+{
+ u64 func = enable ? 1 : 0;
+ union acpi_object *obj;
+ guid_t guid;
+ u64 rev = 0;
+
+ /*
+ * Using DSM calls to enable/disable ultrasoc hardwares on
+ * tracing path, to prevent ultrasoc packet format being exposed.
+ */
+ if (guid_parse(ULTRASOC_SMB_DSM_UUID, &guid)) {
+ dev_err(dev, "Get GUID failed\n");
+ return -EINVAL;
+ }
+
+ obj = acpi_evaluate_dsm(ACPI_HANDLE(dev), &guid, rev, func, NULL);
+ if (!obj) {
+ dev_err(dev, "ACPI handle failed\n");
+ return -ENODEV;
+ }
+
+ ACPI_FREE(obj);
+
+ return 0;
+}
+
+static int smb_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct smb_drv_data *drvdata;
+ int ret;
+
+ drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+
+ drvdata->base = devm_platform_ioremap_resource(pdev, SMB_REG_ADDR_RES);
+ if (IS_ERR(drvdata->base)) {
+ dev_err(dev, "Failed to ioremap resource\n");
+ return PTR_ERR(drvdata->base);
+ }
+
+ smb_init_hw(drvdata);
+
+ ret = smb_init_data_buffer(pdev, &drvdata->sdb);
+ if (ret) {
+ dev_err(dev, "Failed to init buffer, ret = %d\n", ret);
+ return ret;
+ }
+
+ mutex_init(&drvdata->mutex);
+ drvdata->pid = -1;
+
+ ret = smb_register_sink(pdev, drvdata);
+ if (ret) {
+ dev_err(dev, "Failed to register SMB sink\n");
+ return ret;
+ }
+
+ ret = smb_config_inport(dev, true);
+ if (ret) {
+ smb_unregister_sink(drvdata);
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, drvdata);
+
+ return 0;
+}
+
+static int smb_remove(struct platform_device *pdev)
+{
+ struct smb_drv_data *drvdata = platform_get_drvdata(pdev);
+ int ret;
+
+ ret = smb_config_inport(&pdev->dev, false);
+ if (ret)
+ return ret;
+
+ smb_unregister_sink(drvdata);
+
+ return 0;
+}
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id ultrasoc_smb_acpi_match[] = {
+ {"HISI03A1", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(acpi, ultrasoc_smb_acpi_match);
+#endif
+
+static struct platform_driver smb_driver = {
+ .driver = {
+ .name = "ultrasoc-smb",
+ .acpi_match_table = ACPI_PTR(ultrasoc_smb_acpi_match),
+ .suppress_bind_attrs = true,
+ },
+ .probe = smb_probe,
+ .remove = smb_remove,
+};
+module_platform_driver(smb_driver);
+
+MODULE_DESCRIPTION("UltraSoc SMB CoreSight driver");
+MODULE_LICENSE("Dual MIT/GPL");
+MODULE_AUTHOR("Jonathan Zhou <jonathan.zhouwen@huawei.com>");
+MODULE_AUTHOR("Qi Liu <liuqi115@huawei.com>");
diff --git a/drivers/hwtracing/coresight/ultrasoc-smb.h b/drivers/hwtracing/coresight/ultrasoc-smb.h
new file mode 100644
index 000000000000..7dfbe42e37a0
--- /dev/null
+++ b/drivers/hwtracing/coresight/ultrasoc-smb.h
@@ -0,0 +1,125 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+/*
+ * Siemens System Memory Buffer driver.
+ * Copyright(c) 2022, HiSilicon Limited.
+ */
+
+#ifndef _ULTRASOC_SMB_H
+#define _ULTRASOC_SMB_H
+
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+
+/* Offset of SMB global registers */
+#define SMB_GLB_CFG_REG 0x00
+#define SMB_GLB_EN_REG 0x04
+#define SMB_GLB_INT_REG 0x08
+
+/* Offset of SMB logical buffer registers */
+#define SMB_LB_CFG_LO_REG 0x40
+#define SMB_LB_CFG_HI_REG 0x44
+#define SMB_LB_INT_CTRL_REG 0x48
+#define SMB_LB_INT_STS_REG 0x4c
+#define SMB_LB_RD_ADDR_REG 0x5c
+#define SMB_LB_WR_ADDR_REG 0x60
+#define SMB_LB_PURGE_REG 0x64
+
+/* Set global config register */
+#define SMB_GLB_CFG_BURST_LEN_MSK GENMASK(11, 4)
+#define SMB_GLB_CFG_IDLE_PRD_MSK GENMASK(15, 12)
+#define SMB_GLB_CFG_MEM_WR_MSK GENMASK(21, 16)
+#define SMB_GLB_CFG_MEM_RD_MSK GENMASK(27, 22)
+#define SMB_GLB_CFG_DEFAULT (FIELD_PREP(SMB_GLB_CFG_BURST_LEN_MSK, 0xf) | \
+ FIELD_PREP(SMB_GLB_CFG_IDLE_PRD_MSK, 0xf) | \
+ FIELD_PREP(SMB_GLB_CFG_MEM_WR_MSK, 0x3) | \
+ FIELD_PREP(SMB_GLB_CFG_MEM_RD_MSK, 0x1b))
+
+#define SMB_GLB_EN_HW_ENABLE BIT(0)
+
+/* Set global interrupt control register */
+#define SMB_GLB_INT_EN BIT(0)
+#define SMB_GLB_INT_PULSE BIT(1) /* Interrupt type: 1 - Pulse */
+#define SMB_GLB_INT_ACT_H BIT(2) /* Interrupt polarity: 1 - Active high */
+#define SMB_GLB_INT_CFG (SMB_GLB_INT_EN | SMB_GLB_INT_PULSE | \
+ SMB_GLB_INT_ACT_H)
+
+/* Set logical buffer config register lower 32 bits */
+#define SMB_LB_CFG_LO_EN BIT(0)
+#define SMB_LB_CFG_LO_SINGLE_END BIT(1)
+#define SMB_LB_CFG_LO_INIT BIT(8)
+#define SMB_LB_CFG_LO_CONT BIT(11)
+#define SMB_LB_CFG_LO_FLOW_MSK GENMASK(19, 16)
+#define SMB_LB_CFG_LO_DEFAULT (SMB_LB_CFG_LO_EN | SMB_LB_CFG_LO_SINGLE_END | \
+ SMB_LB_CFG_LO_INIT | SMB_LB_CFG_LO_CONT | \
+ FIELD_PREP(SMB_LB_CFG_LO_FLOW_MSK, 0xf))
+
+/* Set logical buffer config register upper 32 bits */
+#define SMB_LB_CFG_HI_RANGE_UP_MSK GENMASK(15, 8)
+#define SMB_LB_CFG_HI_DEFAULT FIELD_PREP(SMB_LB_CFG_HI_RANGE_UP_MSK, 0xff)
+
+/*
+ * Set logical buffer interrupt control register.
+ * The register control the validity of both real-time events and
+ * interrupts. When logical buffer status changes causes to issue
+ * an interrupt at the same time as it issues a real-time event.
+ * Real-time events are used in SMB driver, which needs to get the buffer
+ * status. Interrupts are used in debugger mode.
+ * SMB_LB_INT_CTRL_BUF_NOTE_MASK control which events flags or interrupts
+ * are valid.
+ */
+#define SMB_LB_INT_CTRL_EN BIT(0)
+#define SMB_LB_INT_CTRL_BUF_NOTE_MSK GENMASK(11, 8)
+#define SMB_LB_INT_CTRL_CFG (SMB_LB_INT_CTRL_EN | \
+ FIELD_PREP(SMB_LB_INT_CTRL_BUF_NOTE_MSK, 0xf))
+
+/* Set logical buffer interrupt status register */
+#define SMB_LB_INT_STS_NOT_EMPTY_MSK BIT(0)
+#define SMB_LB_INT_STS_BUF_RESET_MSK GENMASK(3, 0)
+#define SMB_LB_INT_STS_RESET FIELD_PREP(SMB_LB_INT_STS_BUF_RESET_MSK, 0xf)
+
+#define SMB_LB_PURGE_PURGED BIT(0)
+
+#define SMB_REG_ADDR_RES 0
+#define SMB_BUF_ADDR_RES 1
+#define SMB_BUF_ADDR_LO_MSK GENMASK(31, 0)
+
+/**
+ * struct smb_data_buffer - Details of the buffer used by SMB
+ * @buf_base: Memory mapped base address of SMB.
+ * @buf_hw_base: SMB buffer start Physical base address, only used 32bits.
+ * @buf_size: Size of the buffer.
+ * @data_size: Size of the available trace data for SMB.
+ * @buf_rdptr: Current read position (index) within the buffer.
+ */
+struct smb_data_buffer {
+ void *buf_base;
+ u32 buf_hw_base;
+ unsigned long buf_size;
+ unsigned long data_size;
+ unsigned long buf_rdptr;
+};
+
+/**
+ * struct smb_drv_data - specifics associated to an SMB component
+ * @base: Memory mapped base address for SMB component.
+ * @csdev: Component vitals needed by the framework.
+ * @sdb: Data buffer for SMB.
+ * @miscdev: Specifics to handle "/dev/xyz.smb" entry.
+ * @mutex: Control data access to one at a time.
+ * @reading: Synchronise user space access to SMB buffer.
+ * @pid: Process ID of the process being monitored by the
+ * session that is using this component.
+ * @mode: How this SMB is being used, perf mode or sysfs mode.
+ */
+struct smb_drv_data {
+ void __iomem *base;
+ struct coresight_device *csdev;
+ struct smb_data_buffer sdb;
+ struct miscdevice miscdev;
+ struct mutex mutex;
+ bool reading;
+ pid_t pid;
+ u32 mode;
+};
+
+#endif
diff --git a/drivers/hwtracing/intel_th/core.c b/drivers/hwtracing/intel_th/core.c
index 7e753a75d23b..cc7f879bb175 100644
--- a/drivers/hwtracing/intel_th/core.c
+++ b/drivers/hwtracing/intel_th/core.c
@@ -185,11 +185,11 @@ static struct device_type intel_th_source_device_type = {
.release = intel_th_device_release,
};
-static char *intel_th_output_devnode(struct device *dev, umode_t *mode,
+static char *intel_th_output_devnode(const struct device *dev, umode_t *mode,
kuid_t *uid, kgid_t *gid)
{
- struct intel_th_device *thdev = to_intel_th_device(dev);
- struct intel_th *th = to_intel_th(thdev);
+ const struct intel_th_device *thdev = to_intel_th_device(dev);
+ const struct intel_th *th = to_intel_th(thdev);
char *node;
if (thdev->id >= 0)
diff --git a/drivers/hwtracing/intel_th/intel_th.h b/drivers/hwtracing/intel_th/intel_th.h
index 0ffb42990175..6cbba733f259 100644
--- a/drivers/hwtracing/intel_th/intel_th.h
+++ b/drivers/hwtracing/intel_th/intel_th.h
@@ -205,7 +205,7 @@ struct intel_th_driver {
* INTEL_TH_SWITCH and INTEL_TH_SOURCE are children of the intel_th device.
*/
static inline struct intel_th_device *
-to_intel_th_parent(struct intel_th_device *thdev)
+to_intel_th_parent(const struct intel_th_device *thdev)
{
struct device *parent = thdev->dev.parent;
@@ -215,7 +215,7 @@ to_intel_th_parent(struct intel_th_device *thdev)
return to_intel_th_device(parent);
}
-static inline struct intel_th *to_intel_th(struct intel_th_device *thdev)
+static inline struct intel_th *to_intel_th(const struct intel_th_device *thdev)
{
if (thdev->type == INTEL_TH_OUTPUT)
thdev = to_intel_th_parent(thdev);
diff --git a/drivers/hwtracing/intel_th/msu.c b/drivers/hwtracing/intel_th/msu.c
index 6c8215a47a60..9621efe0e95c 100644
--- a/drivers/hwtracing/intel_th/msu.c
+++ b/drivers/hwtracing/intel_th/msu.c
@@ -1659,7 +1659,7 @@ out:
atomic_dec(&msc->user_count);
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- vma->vm_flags |= VM_DONTEXPAND | VM_DONTCOPY;
+ vm_flags_set(vma, VM_DONTEXPAND | VM_DONTCOPY);
vma->vm_ops = &msc_mmap_ops;
return ret;
}
diff --git a/drivers/hwtracing/ptt/hisi_ptt.c b/drivers/hwtracing/ptt/hisi_ptt.c
index 5d5526aa60c4..30f1525639b5 100644
--- a/drivers/hwtracing/ptt/hisi_ptt.c
+++ b/drivers/hwtracing/ptt/hisi_ptt.c
@@ -356,8 +356,18 @@ static int hisi_ptt_register_irq(struct hisi_ptt *hisi_ptt)
static int hisi_ptt_init_filters(struct pci_dev *pdev, void *data)
{
+ struct pci_dev *root_port = pcie_find_root_port(pdev);
struct hisi_ptt_filter_desc *filter;
struct hisi_ptt *hisi_ptt = data;
+ u32 port_devid;
+
+ if (!root_port)
+ return 0;
+
+ port_devid = PCI_DEVID(root_port->bus->number, root_port->devfn);
+ if (port_devid < hisi_ptt->lower_bdf ||
+ port_devid > hisi_ptt->upper_bdf)
+ return 0;
/*
* We won't fail the probe if filter allocation failed here. The filters
diff --git a/drivers/hwtracing/stm/core.c b/drivers/hwtracing/stm/core.c
index 2712e699ba08..534fbefc7f6a 100644
--- a/drivers/hwtracing/stm/core.c
+++ b/drivers/hwtracing/stm/core.c
@@ -715,7 +715,7 @@ static int stm_char_mmap(struct file *file, struct vm_area_struct *vma)
pm_runtime_get_sync(&stm->dev);
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
+ vm_flags_set(vma, VM_IO | VM_DONTEXPAND | VM_DONTDUMP);
vma->vm_ops = &stm_mmap_vmops;
vm_iomap_memory(vma, phys, size);
diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c
index fc90293afcbf..eddf25b90ca8 100644
--- a/drivers/i2c/algos/i2c-algo-bit.c
+++ b/drivers/i2c/algos/i2c-algo-bit.c
@@ -184,8 +184,9 @@ static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c)
/* read ack: SDA should be pulled down by slave, or it may
* NAK (usually to report problems with the data we wrote).
+ * Always report ACK if SDA is write-only.
*/
- ack = !getsda(adap); /* ack: sda is pulled low -> success */
+ ack = !adap->getsda || !getsda(adap); /* ack: sda is pulled low -> success */
bit_dbg(2, &i2c_adap->dev, "i2c_outb: 0x%02x %s\n", (int)c,
ack ? "A" : "NA");
@@ -238,71 +239,55 @@ static int test_bus(struct i2c_adapter *i2c_adap)
return -ENODEV;
}
+ if (adap->getsda == NULL)
+ pr_info("%s: SDA is write-only, testing not possible\n", name);
if (adap->getscl == NULL)
- pr_info("%s: Testing SDA only, SCL is not readable\n", name);
+ pr_info("%s: SCL is write-only, testing not possible\n", name);
- sda = getsda(adap);
- scl = (adap->getscl == NULL) ? 1 : getscl(adap);
+ sda = adap->getsda ? getsda(adap) : 1;
+ scl = adap->getscl ? getscl(adap) : 1;
if (!scl || !sda) {
- printk(KERN_WARNING
- "%s: bus seems to be busy (scl=%d, sda=%d)\n",
- name, scl, sda);
+ pr_warn("%s: bus seems to be busy (scl=%d, sda=%d)\n", name, scl, sda);
goto bailout;
}
sdalo(adap);
- sda = getsda(adap);
- scl = (adap->getscl == NULL) ? 1 : getscl(adap);
- if (sda) {
- printk(KERN_WARNING "%s: SDA stuck high!\n", name);
+ if (adap->getsda && getsda(adap)) {
+ pr_warn("%s: SDA stuck high!\n", name);
goto bailout;
}
- if (!scl) {
- printk(KERN_WARNING
- "%s: SCL unexpected low while pulling SDA low!\n",
- name);
+ if (adap->getscl && !getscl(adap)) {
+ pr_warn("%s: SCL unexpected low while pulling SDA low!\n", name);
goto bailout;
}
sdahi(adap);
- sda = getsda(adap);
- scl = (adap->getscl == NULL) ? 1 : getscl(adap);
- if (!sda) {
- printk(KERN_WARNING "%s: SDA stuck low!\n", name);
+ if (adap->getsda && !getsda(adap)) {
+ pr_warn("%s: SDA stuck low!\n", name);
goto bailout;
}
- if (!scl) {
- printk(KERN_WARNING
- "%s: SCL unexpected low while pulling SDA high!\n",
- name);
+ if (adap->getscl && !getscl(adap)) {
+ pr_warn("%s: SCL unexpected low while pulling SDA high!\n", name);
goto bailout;
}
scllo(adap);
- sda = getsda(adap);
- scl = (adap->getscl == NULL) ? 0 : getscl(adap);
- if (scl) {
- printk(KERN_WARNING "%s: SCL stuck high!\n", name);
+ if (adap->getscl && getscl(adap)) {
+ pr_warn("%s: SCL stuck high!\n", name);
goto bailout;
}
- if (!sda) {
- printk(KERN_WARNING
- "%s: SDA unexpected low while pulling SCL low!\n",
- name);
+ if (adap->getsda && !getsda(adap)) {
+ pr_warn("%s: SDA unexpected low while pulling SCL low!\n", name);
goto bailout;
}
sclhi(adap);
- sda = getsda(adap);
- scl = (adap->getscl == NULL) ? 1 : getscl(adap);
- if (!scl) {
- printk(KERN_WARNING "%s: SCL stuck low!\n", name);
+ if (adap->getscl && !getscl(adap)) {
+ pr_warn("%s: SCL stuck low!\n", name);
goto bailout;
}
- if (!sda) {
- printk(KERN_WARNING
- "%s: SDA unexpected low while pulling SCL high!\n",
- name);
+ if (adap->getsda && !getsda(adap)) {
+ pr_warn("%s: SDA unexpected low while pulling SCL high!\n", name);
goto bailout;
}
@@ -420,6 +405,10 @@ static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
unsigned char *temp = msg->buf;
int count = msg->len;
const unsigned flags = msg->flags;
+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+
+ if (!adap->getsda)
+ return -EOPNOTSUPP;
while (count > 0) {
inval = i2c_inb(i2c_adap);
@@ -670,11 +659,15 @@ static int __i2c_bit_add_bus(struct i2c_adapter *adap,
if (ret < 0)
return ret;
- /* Complain if SCL can't be read */
- if (bit_adap->getscl == NULL) {
+ if (bit_adap->getsda == NULL)
+ dev_warn(&adap->dev, "Not I2C compliant: can't read SDA\n");
+
+ if (bit_adap->getscl == NULL)
dev_warn(&adap->dev, "Not I2C compliant: can't read SCL\n");
+
+ if (bit_adap->getsda == NULL || bit_adap->getscl == NULL)
dev_warn(&adap->dev, "Bus may be unreliable\n");
- }
+
return 0;
}
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index d4975444a32d..9b8e84f20604 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -659,6 +659,13 @@ config I2C_GPIO_FAULT_INJECTOR
faults to an I2C bus, so another bus master can be stress-tested.
This is for debugging. If unsure, say 'no'.
+config I2C_GXP
+ tristate "GXP I2C Interface"
+ depends on ARCH_HPE_GXP || COMPILE_TEST
+ help
+ This enables support for GXP I2C interface. The I2C engines can be
+ either I2C master or I2C slaves.
+
config I2C_HIGHLANDER
tristate "Highlander FPGA SMBus interface"
depends on SH_HIGHLANDER || COMPILE_TEST
@@ -761,6 +768,17 @@ config I2C_LPC2K
This driver can also be built as a module. If so, the module
will be called i2c-lpc2k.
+config I2C_LS2X
+ tristate "Loongson LS2X I2C adapter"
+ depends on MACH_LOONGSON64 || COMPILE_TEST
+ help
+ If you say yes to this option, support will be included for the
+ I2C interface on the Loongson-2K SoCs and Loongson LS7A bridge
+ chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-ls2x.
+
config I2C_MLXBF
tristate "Mellanox BlueField I2C controller"
depends on MELLANOX_PLATFORM && ARM64
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index e73cdb1d2b5a..af56fe2c75c0 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -77,6 +77,7 @@ obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
obj-$(CONFIG_I2C_JZ4780) += i2c-jz4780.o
obj-$(CONFIG_I2C_KEMPLD) += i2c-kempld.o
obj-$(CONFIG_I2C_LPC2K) += i2c-lpc2k.o
+obj-$(CONFIG_I2C_LS2X) += i2c-ls2x.o
obj-$(CONFIG_I2C_MESON) += i2c-meson.o
obj-$(CONFIG_I2C_MICROCHIP_CORE) += i2c-microchip-corei2c.o
obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
@@ -127,6 +128,7 @@ obj-$(CONFIG_I2C_THUNDERX) += i2c-thunderx.o
obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o
obj-$(CONFIG_I2C_XLP9XX) += i2c-xlp9xx.o
obj-$(CONFIG_I2C_RCAR) += i2c-rcar.o
+obj-$(CONFIG_I2C_GXP) += i2c-gxp.o
# External I2C/SMBus adapter drivers
obj-$(CONFIG_I2C_DIOLAN_U2C) += i2c-diolan-u2c.o
diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c
index c64c381b69b7..d3c99c5b3247 100644
--- a/drivers/i2c/busses/i2c-aspeed.c
+++ b/drivers/i2c/busses/i2c-aspeed.c
@@ -979,15 +979,13 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev)
const struct of_device_id *match;
struct aspeed_i2c_bus *bus;
struct clk *parent_clk;
- struct resource *res;
int irq, ret;
bus = devm_kzalloc(&pdev->dev, sizeof(*bus), GFP_KERNEL);
if (!bus)
return -ENOMEM;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- bus->base = devm_ioremap_resource(&pdev->dev, res);
+ bus->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(bus->base))
return PTR_ERR(bus->base);
diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c
index 99bd24d0e6a5..7b42d35b1294 100644
--- a/drivers/i2c/busses/i2c-au1550.c
+++ b/drivers/i2c/busses/i2c-au1550.c
@@ -302,7 +302,6 @@ static int
i2c_au1550_probe(struct platform_device *pdev)
{
struct i2c_au1550_data *priv;
- struct resource *r;
int ret;
priv = devm_kzalloc(&pdev->dev, sizeof(struct i2c_au1550_data),
@@ -310,8 +309,7 @@ i2c_au1550_probe(struct platform_device *pdev)
if (!priv)
return -ENOMEM;
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- priv->psc_base = devm_ioremap_resource(&pdev->dev, r);
+ priv->psc_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(priv->psc_base))
return PTR_ERR(priv->psc_base);
diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c
index f72c6576d8a3..09a077b31bfe 100644
--- a/drivers/i2c/busses/i2c-bcm2835.c
+++ b/drivers/i2c/busses/i2c-bcm2835.c
@@ -407,7 +407,6 @@ static const struct i2c_adapter_quirks bcm2835_i2c_quirks = {
static int bcm2835_i2c_probe(struct platform_device *pdev)
{
struct bcm2835_i2c_dev *i2c_dev;
- struct resource *mem;
int ret;
struct i2c_adapter *adap;
struct clk *mclk;
@@ -420,8 +419,7 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
i2c_dev->dev = &pdev->dev;
init_completion(&i2c_dev->completion);
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- i2c_dev->regs = devm_ioremap_resource(&pdev->dev, mem);
+ i2c_dev->regs = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(i2c_dev->regs))
return PTR_ERR(i2c_dev->regs);
diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c
index f58943cb1341..b5d22e7282c2 100644
--- a/drivers/i2c/busses/i2c-cadence.c
+++ b/drivers/i2c/busses/i2c-cadence.c
@@ -115,8 +115,6 @@
#define CNDS_I2C_PM_TIMEOUT 1000 /* ms */
#define CDNS_I2C_FIFO_DEPTH 16
-/* FIFO depth at which the DATA interrupt occurs */
-#define CDNS_I2C_DATA_INTR_DEPTH (CDNS_I2C_FIFO_DEPTH - 2)
#define CDNS_I2C_MAX_TRANSFER_SIZE 255
/* Transfer size in multiples of data interrupt depth */
#define CDNS_I2C_TRANSFER_SIZE (CDNS_I2C_MAX_TRANSFER_SIZE - 3)
@@ -175,7 +173,6 @@ enum cdns_i2c_slave_state {
* @send_count: Number of bytes still expected to send
* @recv_count: Number of bytes still expected to receive
* @curr_recv_count: Number of bytes to be received in current transfer
- * @irq: IRQ number
* @input_clk: Input clock to I2C controller
* @i2c_clk: Maximum I2C clock speed
* @bus_hold_flag: Flag used in repeated start for clearing HOLD bit
@@ -200,7 +197,6 @@ struct cdns_i2c {
unsigned int send_count;
unsigned int recv_count;
unsigned int curr_recv_count;
- int irq;
unsigned long input_clk;
unsigned int i2c_clk;
unsigned int bus_hold_flag;
@@ -616,9 +612,7 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
}
/* Determine hold_clear based on number of bytes to receive and hold flag */
- if (!id->bus_hold_flag &&
- ((id->p_msg->flags & I2C_M_RECV_LEN) != I2C_M_RECV_LEN) &&
- (id->recv_count <= CDNS_I2C_FIFO_DEPTH)) {
+ if (!id->bus_hold_flag && id->recv_count <= CDNS_I2C_FIFO_DEPTH) {
if (cdns_i2c_readreg(CDNS_I2C_CR_OFFSET) & CDNS_I2C_CR_HOLD) {
hold_clear = true;
if (id->quirks & CDNS_I2C_BROKEN_HOLD_BIT)
@@ -1246,7 +1240,7 @@ static int cdns_i2c_probe(struct platform_device *pdev)
{
struct resource *r_mem;
struct cdns_i2c *id;
- int ret;
+ int ret, irq;
const struct of_device_id *match;
id = devm_kzalloc(&pdev->dev, sizeof(*id), GFP_KERNEL);
@@ -1277,10 +1271,9 @@ static int cdns_i2c_probe(struct platform_device *pdev)
if (IS_ERR(id->membase))
return PTR_ERR(id->membase);
- ret = platform_get_irq(pdev, 0);
- if (ret < 0)
- return ret;
- id->irq = ret;
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
id->adap.owner = THIS_MODULE;
id->adap.dev.of_node = pdev->dev.of_node;
@@ -1331,10 +1324,10 @@ static int cdns_i2c_probe(struct platform_device *pdev)
goto err_clk_dis;
}
- ret = devm_request_irq(&pdev->dev, id->irq, cdns_i2c_isr, 0,
+ ret = devm_request_irq(&pdev->dev, irq, cdns_i2c_isr, 0,
DRIVER_NAME, id);
if (ret) {
- dev_err(&pdev->dev, "cannot get irq %d\n", id->irq);
+ dev_err(&pdev->dev, "cannot get irq %d\n", irq);
goto err_clk_dis;
}
cdns_i2c_init(id);
@@ -1344,7 +1337,7 @@ static int cdns_i2c_probe(struct platform_device *pdev)
goto err_clk_dis;
dev_info(&pdev->dev, "%u kHz mmio %08lx irq %d\n",
- id->i2c_clk / 1000, (unsigned long)r_mem->start, id->irq);
+ id->i2c_clk / 1000, (unsigned long)r_mem->start, irq);
return 0;
diff --git a/drivers/i2c/busses/i2c-cht-wc.c b/drivers/i2c/busses/i2c-cht-wc.c
index 190abdc46dd3..2b2c3d090089 100644
--- a/drivers/i2c/busses/i2c-cht-wc.c
+++ b/drivers/i2c/busses/i2c-cht-wc.c
@@ -380,6 +380,49 @@ static struct i2c_board_info lenovo_yogabook1_board_info = {
.platform_data = &bq2589x_pdata,
};
+/********** Lenovo Yogabook YT3-X90F charger settings **********/
+static const char * const lenovo_yt3_bq25892_1_suppliers[] = { "cht_wcove_pwrsrc" };
+
+/*
+ * bq25892 charger settings for the round li-ion cells in the hinge,
+ * this is the main / biggest battery.
+ */
+static const struct property_entry lenovo_yt3_bq25892_1_props[] = {
+ PROPERTY_ENTRY_STRING_ARRAY("supplied-from", lenovo_yt3_bq25892_1_suppliers),
+ PROPERTY_ENTRY_STRING("linux,secondary-charger-name", "bq25890-charger-0"),
+ PROPERTY_ENTRY_U32("linux,iinlim-percentage", 60),
+ PROPERTY_ENTRY_U32("linux,pump-express-vbus-max", 12000000),
+ PROPERTY_ENTRY_BOOL("linux,skip-reset"),
+ /*
+ * The firmware sets everything to the defaults, leading to a low(ish)
+ * charge-current and battery-voltage of 2048mA resp 4.2V. Use the
+ * Android values instead of "linux,read-back-settings" to fix this.
+ */
+ PROPERTY_ENTRY_U32("ti,charge-current", 3072000),
+ PROPERTY_ENTRY_U32("ti,battery-regulation-voltage", 4352000),
+ PROPERTY_ENTRY_U32("ti,termination-current", 128000),
+ PROPERTY_ENTRY_U32("ti,precharge-current", 128000),
+ PROPERTY_ENTRY_U32("ti,minimum-sys-voltage", 3700000),
+ PROPERTY_ENTRY_BOOL("ti,use-ilim-pin"),
+ /* Set 5V boost current-limit to 1.2A (MAX/POR values are 2.45A/1.4A) */
+ PROPERTY_ENTRY_U32("ti,boost-voltage", 4998000),
+ PROPERTY_ENTRY_U32("ti,boost-max-current", 1200000),
+ { }
+};
+
+static const struct software_node lenovo_yt3_bq25892_1_node = {
+ .properties = lenovo_yt3_bq25892_1_props,
+};
+
+/* bq25892 charger for the round li-ion cells in the hinge */
+static struct i2c_board_info lenovo_yoga_tab3_board_info = {
+ .type = "bq25892",
+ .addr = 0x6b,
+ .dev_name = "bq25892_1",
+ .swnode = &lenovo_yt3_bq25892_1_node,
+ .platform_data = &bq2589x_pdata,
+};
+
static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev)
{
struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
@@ -459,6 +502,9 @@ static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev)
case INTEL_CHT_WC_LENOVO_YOGABOOK1:
board_info = &lenovo_yogabook1_board_info;
break;
+ case INTEL_CHT_WC_LENOVO_YT3_X90:
+ board_info = &lenovo_yoga_tab3_board_info;
+ break;
default:
dev_warn(&pdev->dev, "Unknown model, not instantiating charger device\n");
break;
diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c
index 581e02cc979a..0dc6b1ce663f 100644
--- a/drivers/i2c/busses/i2c-designware-common.c
+++ b/drivers/i2c/busses/i2c-designware-common.c
@@ -391,7 +391,7 @@ u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset)
int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev)
{
- u32 reg;
+ unsigned int reg;
int ret;
ret = i2c_dw_acquire_lock(dev);
@@ -442,7 +442,7 @@ err_release_lock:
void __i2c_dw_disable(struct dw_i2c_dev *dev)
{
int timeout = 100;
- u32 status;
+ unsigned int status;
do {
__i2c_dw_disable_nowait(dev);
@@ -465,7 +465,7 @@ void __i2c_dw_disable(struct dw_i2c_dev *dev)
dev_warn(dev->dev, "timeout in disabling adapter\n");
}
-unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev)
+u32 i2c_dw_clk_rate(struct dw_i2c_dev *dev)
{
/*
* Clock is not necessary if we got LCNT/HCNT values directly from
@@ -527,7 +527,7 @@ void i2c_dw_release_lock(struct dw_i2c_dev *dev)
*/
int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev)
{
- u32 status;
+ unsigned int status;
int ret;
ret = regmap_read_poll_timeout(dev->map, DW_IC_STATUS, status,
@@ -571,7 +571,8 @@ int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev)
int i2c_dw_set_fifo_size(struct dw_i2c_dev *dev)
{
- u32 param, tx_fifo_depth, rx_fifo_depth;
+ u32 tx_fifo_depth, rx_fifo_depth;
+ unsigned int param;
int ret;
/*
@@ -611,7 +612,7 @@ u32 i2c_dw_func(struct i2c_adapter *adap)
void i2c_dw_disable(struct dw_i2c_dev *dev)
{
- u32 dummy;
+ unsigned int dummy;
int ret;
ret = i2c_dw_acquire_lock(dev);
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index 95ebc5eaa5d1..050d8c63ad3c 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -37,6 +37,7 @@
#define DW_IC_CON_STOP_DET_IFADDRESSED BIT(7)
#define DW_IC_CON_TX_EMPTY_CTRL BIT(8)
#define DW_IC_CON_RX_FIFO_FULL_HLD_CTRL BIT(9)
+#define DW_IC_CON_BUS_CLEAR_CTRL BIT(11)
#define DW_IC_DATA_CMD_DAT GENMASK(7, 0)
@@ -264,7 +265,7 @@ struct dw_i2c_dev {
u8 *rx_buf;
int msg_err;
unsigned int status;
- u32 abort_source;
+ unsigned int abort_source;
int irq;
u32 flags;
struct i2c_adapter adapter;
@@ -320,7 +321,7 @@ int i2c_dw_init_regmap(struct dw_i2c_dev *dev);
u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset);
u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset);
int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev);
-unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev);
+u32 i2c_dw_clk_rate(struct dw_i2c_dev *dev);
int i2c_dw_prepare_clk(struct dw_i2c_dev *dev, bool prepare);
int i2c_dw_acquire_lock(struct dw_i2c_dev *dev);
void i2c_dw_release_lock(struct dw_i2c_dev *dev);
diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c
index 45f569155bfe..55ea91a63382 100644
--- a/drivers/i2c/busses/i2c-designware-master.c
+++ b/drivers/i2c/busses/i2c-designware-master.c
@@ -39,7 +39,7 @@ static void i2c_dw_configure_fifo_master(struct dw_i2c_dev *dev)
static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
{
- u32 comp_param1;
+ unsigned int comp_param1;
u32 sda_falling_time, scl_falling_time;
struct i2c_timings *t = &dev->timings;
const char *fp_str = "";
@@ -211,7 +211,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
{
struct i2c_msg *msgs = dev->msgs;
u32 ic_con = 0, ic_tar = 0;
- u32 dummy;
+ unsigned int dummy;
/* Disable the adapter */
__i2c_dw_disable(dev);
@@ -287,7 +287,7 @@ static int amd_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs,
int msg_wrt_idx, msg_itr_lmt, buf_len, data_idx;
int cmd = 0, status;
u8 *tx_buf;
- u32 val;
+ unsigned int val;
/*
* In order to enable the interrupt for UCSI i.e. AMD NAVI GPU card,
@@ -505,7 +505,8 @@ i2c_dw_read(struct dw_i2c_dev *dev)
unsigned int rx_valid;
for (; dev->msg_read_idx < dev->msgs_num; dev->msg_read_idx++) {
- u32 len, tmp;
+ unsigned int tmp;
+ u32 len;
u8 *buf;
if (!(msgs[dev->msg_read_idx].flags & I2C_M_RD))
@@ -653,7 +654,7 @@ static const struct i2c_adapter_quirks i2c_dw_quirks = {
static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
{
- u32 stat, dummy;
+ unsigned int stat, dummy;
/*
* The IC_INTR_STAT register just indicates "enabled" interrupts.
@@ -714,7 +715,7 @@ static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
{
struct dw_i2c_dev *dev = dev_id;
- u32 stat, enabled;
+ unsigned int stat, enabled;
regmap_read(dev->map, DW_IC_ENABLE, &enabled);
regmap_read(dev->map, DW_IC_RAW_INTR_STAT, &stat);
@@ -865,6 +866,7 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev)
{
struct i2c_adapter *adap = &dev->adapter;
unsigned long irq_flags;
+ unsigned int ic_con;
int ret;
init_completion(&dev->cmd_complete);
@@ -884,6 +886,25 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev)
if (ret)
return ret;
+ /* Lock the bus for accessing DW_IC_CON */
+ ret = i2c_dw_acquire_lock(dev);
+ if (ret)
+ return ret;
+
+ /*
+ * On AMD platforms BIOS advertises the bus clear feature
+ * and enables the SCL/SDA stuck low. SMU FW does the
+ * bus recovery process. Driver should not ignore this BIOS
+ * advertisement of bus clear feature.
+ */
+ ret = regmap_read(dev->map, DW_IC_CON, &ic_con);
+ i2c_dw_release_lock(dev);
+ if (ret)
+ return ret;
+
+ if (ic_con & DW_IC_CON_BUS_CLEAR_CTRL)
+ dev->master_cfg |= DW_IC_CON_BUS_CLEAR_CTRL;
+
ret = dev->init(dev);
if (ret)
return ret;
diff --git a/drivers/i2c/busses/i2c-designware-slave.c b/drivers/i2c/busses/i2c-designware-slave.c
index c6d2e4c2ac23..cec25054bb24 100644
--- a/drivers/i2c/busses/i2c-designware-slave.c
+++ b/drivers/i2c/busses/i2c-designware-slave.c
@@ -98,7 +98,7 @@ static int i2c_dw_unreg_slave(struct i2c_client *slave)
static u32 i2c_dw_read_clear_intrbits_slave(struct dw_i2c_dev *dev)
{
- u32 stat, dummy;
+ unsigned int stat, dummy;
/*
* The IC_INTR_STAT register just indicates "enabled" interrupts.
@@ -150,7 +150,7 @@ static u32 i2c_dw_read_clear_intrbits_slave(struct dw_i2c_dev *dev)
static irqreturn_t i2c_dw_isr_slave(int this_irq, void *dev_id)
{
struct dw_i2c_dev *dev = dev_id;
- u32 raw_stat, stat, enabled, tmp;
+ unsigned int raw_stat, stat, enabled, tmp;
u8 val = 0, slave_activity;
regmap_read(dev->map, DW_IC_ENABLE, &enabled);
diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c
index 0e4385a9bcf7..1794c0399f22 100644
--- a/drivers/i2c/busses/i2c-gpio.c
+++ b/drivers/i2c/busses/i2c-gpio.c
@@ -13,9 +13,9 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/module.h>
-#include <linux/of.h>
#include <linux/platform_data/i2c-gpio.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/slab.h>
struct i2c_gpio_private_data {
@@ -300,22 +300,29 @@ static inline void i2c_gpio_fault_injector_init(struct platform_device *pdev) {}
static inline void i2c_gpio_fault_injector_exit(struct platform_device *pdev) {}
#endif /* CONFIG_I2C_GPIO_FAULT_INJECTOR*/
-static void of_i2c_gpio_get_props(struct device_node *np,
- struct i2c_gpio_platform_data *pdata)
+/* Get i2c-gpio properties from DT or ACPI table */
+static void i2c_gpio_get_properties(struct device *dev,
+ struct i2c_gpio_platform_data *pdata)
{
u32 reg;
- of_property_read_u32(np, "i2c-gpio,delay-us", &pdata->udelay);
+ device_property_read_u32(dev, "i2c-gpio,delay-us", &pdata->udelay);
- if (!of_property_read_u32(np, "i2c-gpio,timeout-ms", &reg))
+ if (!device_property_read_u32(dev, "i2c-gpio,timeout-ms", &reg))
pdata->timeout = msecs_to_jiffies(reg);
pdata->sda_is_open_drain =
- of_property_read_bool(np, "i2c-gpio,sda-open-drain");
+ device_property_read_bool(dev, "i2c-gpio,sda-open-drain");
pdata->scl_is_open_drain =
- of_property_read_bool(np, "i2c-gpio,scl-open-drain");
+ device_property_read_bool(dev, "i2c-gpio,scl-open-drain");
pdata->scl_is_output_only =
- of_property_read_bool(np, "i2c-gpio,scl-output-only");
+ device_property_read_bool(dev, "i2c-gpio,scl-output-only");
+ pdata->sda_is_output_only =
+ device_property_read_bool(dev, "i2c-gpio,sda-output-only");
+ pdata->sda_has_no_pullup =
+ device_property_read_bool(dev, "i2c-gpio,sda-has-no-pullup");
+ pdata->scl_has_no_pullup =
+ device_property_read_bool(dev, "i2c-gpio,scl-has-no-pullup");
}
static struct gpio_desc *i2c_gpio_get_desc(struct device *dev,
@@ -361,7 +368,7 @@ static int i2c_gpio_probe(struct platform_device *pdev)
struct i2c_algo_bit_data *bit_data;
struct i2c_adapter *adap;
struct device *dev = &pdev->dev;
- struct device_node *np = dev->of_node;
+ struct fwnode_handle *fwnode = dev_fwnode(dev);
enum gpiod_flags gflags;
int ret;
@@ -373,8 +380,8 @@ static int i2c_gpio_probe(struct platform_device *pdev)
bit_data = &priv->bit_data;
pdata = &priv->pdata;
- if (np) {
- of_i2c_gpio_get_props(np, pdata);
+ if (fwnode) {
+ i2c_gpio_get_properties(dev, pdata);
} else {
/*
* If all platform data settings are zero it is OK
@@ -392,7 +399,7 @@ static int i2c_gpio_probe(struct platform_device *pdev)
* handle them as we handle any other output. Else we enforce open
* drain as this is required for an I2C bus.
*/
- if (pdata->sda_is_open_drain)
+ if (pdata->sda_is_open_drain || pdata->sda_has_no_pullup)
gflags = GPIOD_OUT_HIGH;
else
gflags = GPIOD_OUT_HIGH_OPEN_DRAIN;
@@ -400,7 +407,7 @@ static int i2c_gpio_probe(struct platform_device *pdev)
if (IS_ERR(priv->sda))
return PTR_ERR(priv->sda);
- if (pdata->scl_is_open_drain)
+ if (pdata->scl_is_open_drain || pdata->scl_has_no_pullup)
gflags = GPIOD_OUT_HIGH;
else
gflags = GPIOD_OUT_HIGH_OPEN_DRAIN;
@@ -418,7 +425,8 @@ static int i2c_gpio_probe(struct platform_device *pdev)
if (!pdata->scl_is_output_only)
bit_data->getscl = i2c_gpio_getscl;
- bit_data->getsda = i2c_gpio_getsda;
+ if (!pdata->sda_is_output_only)
+ bit_data->getsda = i2c_gpio_getsda;
if (pdata->udelay)
bit_data->udelay = pdata->udelay;
@@ -435,7 +443,7 @@ static int i2c_gpio_probe(struct platform_device *pdev)
bit_data->data = priv;
adap->owner = THIS_MODULE;
- if (np)
+ if (fwnode)
strscpy(adap->name, dev_name(dev), sizeof(adap->name));
else
snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id);
@@ -443,7 +451,7 @@ static int i2c_gpio_probe(struct platform_device *pdev)
adap->algo_data = bit_data;
adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
adap->dev.parent = dev;
- adap->dev.of_node = np;
+ device_set_node(&adap->dev, fwnode);
adap->nr = pdev->id;
ret = i2c_bit_add_numbered_bus(adap);
@@ -489,10 +497,17 @@ static const struct of_device_id i2c_gpio_dt_ids[] = {
MODULE_DEVICE_TABLE(of, i2c_gpio_dt_ids);
+static const struct acpi_device_id i2c_gpio_acpi_match[] = {
+ { "LOON0005" }, /* LoongArch */
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, i2c_gpio_acpi_match);
+
static struct platform_driver i2c_gpio_driver = {
.driver = {
.name = "i2c-gpio",
.of_match_table = i2c_gpio_dt_ids,
+ .acpi_match_table = i2c_gpio_acpi_match,
},
.probe = i2c_gpio_probe,
.remove = i2c_gpio_remove,
diff --git a/drivers/i2c/busses/i2c-gxp.c b/drivers/i2c/busses/i2c-gxp.c
new file mode 100644
index 000000000000..da4c8e5a8039
--- /dev/null
+++ b/drivers/i2c/busses/i2c-gxp.c
@@ -0,0 +1,620 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2022 Hewlett-Packard Enterprise Development Company, L.P. */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+#define GXP_MAX_I2C_ENGINE 10
+static const char * const gxp_i2c_name[] = {
+ "gxp-i2c0", "gxp-i2c1", "gxp-i2c2", "gxp-i2c3",
+ "gxp-i2c4", "gxp-i2c5", "gxp-i2c6", "gxp-i2c7",
+ "gxp-i2c8", "gxp-i2c9" };
+
+/* GXP I2C Global interrupt status/enable register*/
+#define GXP_I2CINTSTAT 0x00
+#define GXP_I2CINTEN 0x04
+
+/* GXP I2C registers */
+#define GXP_I2CSTAT 0x00
+#define MASK_STOP_EVENT 0x20
+#define MASK_ACK 0x08
+#define MASK_RW 0x04
+#define GXP_I2CEVTERR 0x01
+#define MASK_SLAVE_CMD_EVENT 0x01
+#define MASK_SLAVE_DATA_EVENT 0x02
+#define MASK_MASTER_EVENT 0x10
+#define GXP_I2CSNPDAT 0x02
+#define GXP_I2CMCMD 0x04
+#define GXP_I2CSCMD 0x06
+#define GXP_I2CSNPAA 0x09
+#define GXP_I2CADVFEAT 0x0A
+#define GXP_I2COWNADR 0x0B
+#define GXP_I2CFREQDIV 0x0C
+#define GXP_I2CFLTFAIR 0x0D
+#define GXP_I2CTMOEDG 0x0E
+#define GXP_I2CCYCTIM 0x0F
+
+/* I2CSCMD Bits */
+#define SNOOP_EVT_CLR 0x80
+#define SLAVE_EVT_CLR 0x40
+#define SNOOP_EVT_MASK 0x20
+#define SLAVE_EVT_MASK 0x10
+#define SLAVE_ACK_ENAB 0x08
+#define SLAVE_EVT_STALL 0x01
+
+/* I2CMCMD Bits */
+#define MASTER_EVT_CLR 0x80
+#define MASTER_ACK_ENAB 0x08
+#define RW_CMD 0x04
+#define STOP_CMD 0x02
+#define START_CMD 0x01
+
+/* I2CTMOEDG value */
+#define GXP_DATA_EDGE_RST_CTRL 0x0a /* 30ns */
+
+/* I2CFLTFAIR Bits */
+#define FILTER_CNT 0x30
+#define FAIRNESS_CNT 0x02
+
+enum {
+ GXP_I2C_IDLE = 0,
+ GXP_I2C_ADDR_PHASE,
+ GXP_I2C_RDATA_PHASE,
+ GXP_I2C_WDATA_PHASE,
+ GXP_I2C_ADDR_NACK,
+ GXP_I2C_DATA_NACK,
+ GXP_I2C_ERROR,
+ GXP_I2C_COMP
+};
+
+struct gxp_i2c_drvdata {
+ struct device *dev;
+ void __iomem *base;
+ struct i2c_timings t;
+ u32 engine;
+ int irq;
+ struct completion completion;
+ struct i2c_adapter adapter;
+ struct i2c_msg *curr_msg;
+ int msgs_remaining;
+ int msgs_num;
+ u8 *buf;
+ size_t buf_remaining;
+ unsigned char state;
+ struct i2c_client *slave;
+ unsigned char stopped;
+};
+
+static struct regmap *i2cg_map;
+
+static void gxp_i2c_start(struct gxp_i2c_drvdata *drvdata)
+{
+ u16 value;
+
+ drvdata->buf = drvdata->curr_msg->buf;
+ drvdata->buf_remaining = drvdata->curr_msg->len;
+
+ /* Note: Address in struct i2c_msg is 7 bits */
+ value = drvdata->curr_msg->addr << 9;
+
+ /* Read or Write */
+ value |= drvdata->curr_msg->flags & I2C_M_RD ? RW_CMD | START_CMD : START_CMD;
+
+ drvdata->state = GXP_I2C_ADDR_PHASE;
+ writew(value, drvdata->base + GXP_I2CMCMD);
+}
+
+static int gxp_i2c_master_xfer(struct i2c_adapter *adapter,
+ struct i2c_msg *msgs, int num)
+{
+ int ret;
+ struct gxp_i2c_drvdata *drvdata = i2c_get_adapdata(adapter);
+ unsigned long time_left;
+
+ drvdata->msgs_remaining = num;
+ drvdata->curr_msg = msgs;
+ drvdata->msgs_num = num;
+ reinit_completion(&drvdata->completion);
+
+ gxp_i2c_start(drvdata);
+
+ time_left = wait_for_completion_timeout(&drvdata->completion,
+ adapter->timeout);
+ ret = num - drvdata->msgs_remaining;
+ if (time_left == 0) {
+ switch (drvdata->state) {
+ case GXP_I2C_WDATA_PHASE:
+ break;
+ case GXP_I2C_RDATA_PHASE:
+ break;
+ case GXP_I2C_ADDR_PHASE:
+ break;
+ default:
+ break;
+ }
+ return -ETIMEDOUT;
+ }
+
+ if (drvdata->state == GXP_I2C_ADDR_NACK ||
+ drvdata->state == GXP_I2C_DATA_NACK)
+ return -EIO;
+
+ return ret;
+}
+
+static u32 gxp_i2c_func(struct i2c_adapter *adap)
+{
+ if (IS_ENABLED(CONFIG_I2C_SLAVE))
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SLAVE;
+
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+static int gxp_i2c_reg_slave(struct i2c_client *slave)
+{
+ struct gxp_i2c_drvdata *drvdata = i2c_get_adapdata(slave->adapter);
+
+ if (drvdata->slave)
+ return -EBUSY;
+
+ if (slave->flags & I2C_CLIENT_TEN)
+ return -EAFNOSUPPORT;
+
+ drvdata->slave = slave;
+
+ writeb(slave->addr << 1, drvdata->base + GXP_I2COWNADR);
+ writeb(SLAVE_EVT_CLR | SNOOP_EVT_MASK | SLAVE_ACK_ENAB |
+ SLAVE_EVT_STALL, drvdata->base + GXP_I2CSCMD);
+
+ return 0;
+}
+
+static int gxp_i2c_unreg_slave(struct i2c_client *slave)
+{
+ struct gxp_i2c_drvdata *drvdata = i2c_get_adapdata(slave->adapter);
+
+ WARN_ON(!drvdata->slave);
+
+ writeb(0x00, drvdata->base + GXP_I2COWNADR);
+ writeb(SNOOP_EVT_CLR | SLAVE_EVT_CLR | SNOOP_EVT_MASK |
+ SLAVE_EVT_MASK, drvdata->base + GXP_I2CSCMD);
+
+ drvdata->slave = NULL;
+
+ return 0;
+}
+#endif
+
+static const struct i2c_algorithm gxp_i2c_algo = {
+ .master_xfer = gxp_i2c_master_xfer,
+ .functionality = gxp_i2c_func,
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+ .reg_slave = gxp_i2c_reg_slave,
+ .unreg_slave = gxp_i2c_unreg_slave,
+#endif
+};
+
+static void gxp_i2c_stop(struct gxp_i2c_drvdata *drvdata)
+{
+ /* Clear event and send stop */
+ writeb(MASTER_EVT_CLR | STOP_CMD, drvdata->base + GXP_I2CMCMD);
+
+ complete(&drvdata->completion);
+}
+
+static void gxp_i2c_restart(struct gxp_i2c_drvdata *drvdata)
+{
+ u16 value;
+
+ drvdata->buf = drvdata->curr_msg->buf;
+ drvdata->buf_remaining = drvdata->curr_msg->len;
+
+ value = drvdata->curr_msg->addr << 9;
+
+ if (drvdata->curr_msg->flags & I2C_M_RD) {
+ /* Read and clear master event */
+ value |= MASTER_EVT_CLR | RW_CMD | START_CMD;
+ } else {
+ /* Write and clear master event */
+ value |= MASTER_EVT_CLR | START_CMD;
+ }
+
+ drvdata->state = GXP_I2C_ADDR_PHASE;
+
+ writew(value, drvdata->base + GXP_I2CMCMD);
+}
+
+static void gxp_i2c_chk_addr_ack(struct gxp_i2c_drvdata *drvdata)
+{
+ u16 value;
+
+ value = readb(drvdata->base + GXP_I2CSTAT);
+ if (!(value & MASK_ACK)) {
+ /* Got no ack, stop */
+ drvdata->state = GXP_I2C_ADDR_NACK;
+ gxp_i2c_stop(drvdata);
+ return;
+ }
+
+ if (drvdata->curr_msg->flags & I2C_M_RD) {
+ /* Start to read data from slave */
+ if (drvdata->buf_remaining == 0) {
+ /* No more data to read, stop */
+ drvdata->msgs_remaining--;
+ drvdata->state = GXP_I2C_COMP;
+ gxp_i2c_stop(drvdata);
+ return;
+ }
+ drvdata->state = GXP_I2C_RDATA_PHASE;
+
+ if (drvdata->buf_remaining == 1) {
+ /* The last data, do not ack */
+ writeb(MASTER_EVT_CLR | RW_CMD,
+ drvdata->base + GXP_I2CMCMD);
+ } else {
+ /* Read data and ack it */
+ writeb(MASTER_EVT_CLR | MASTER_ACK_ENAB |
+ RW_CMD, drvdata->base + GXP_I2CMCMD);
+ }
+ } else {
+ /* Start to write first data to slave */
+ if (drvdata->buf_remaining == 0) {
+ /* No more data to write, stop */
+ drvdata->msgs_remaining--;
+ drvdata->state = GXP_I2C_COMP;
+ gxp_i2c_stop(drvdata);
+ return;
+ }
+ value = *drvdata->buf;
+ value = value << 8;
+ /* Clear master event */
+ value |= MASTER_EVT_CLR;
+ drvdata->buf++;
+ drvdata->buf_remaining--;
+ drvdata->state = GXP_I2C_WDATA_PHASE;
+ writew(value, drvdata->base + GXP_I2CMCMD);
+ }
+}
+
+static void gxp_i2c_ack_data(struct gxp_i2c_drvdata *drvdata)
+{
+ u8 value;
+
+ /* Store the data returned */
+ value = readb(drvdata->base + GXP_I2CSNPDAT);
+ *drvdata->buf = value;
+ drvdata->buf++;
+ drvdata->buf_remaining--;
+
+ if (drvdata->buf_remaining == 0) {
+ /* No more data, this message is completed. */
+ drvdata->msgs_remaining--;
+
+ if (drvdata->msgs_remaining == 0) {
+ /* No more messages, stop */
+ drvdata->state = GXP_I2C_COMP;
+ gxp_i2c_stop(drvdata);
+ return;
+ }
+ /* Move to next message and start transfer */
+ drvdata->curr_msg++;
+ gxp_i2c_restart(drvdata);
+ return;
+ }
+
+ /* Ack the slave to make it send next byte */
+ drvdata->state = GXP_I2C_RDATA_PHASE;
+ if (drvdata->buf_remaining == 1) {
+ /* The last data, do not ack */
+ writeb(MASTER_EVT_CLR | RW_CMD,
+ drvdata->base + GXP_I2CMCMD);
+ } else {
+ /* Read data and ack it */
+ writeb(MASTER_EVT_CLR | MASTER_ACK_ENAB |
+ RW_CMD, drvdata->base + GXP_I2CMCMD);
+ }
+}
+
+static void gxp_i2c_chk_data_ack(struct gxp_i2c_drvdata *drvdata)
+{
+ u16 value;
+
+ value = readb(drvdata->base + GXP_I2CSTAT);
+ if (!(value & MASK_ACK)) {
+ /* Received No ack, stop */
+ drvdata->state = GXP_I2C_DATA_NACK;
+ gxp_i2c_stop(drvdata);
+ return;
+ }
+
+ /* Got ack, check if there is more data to write */
+ if (drvdata->buf_remaining == 0) {
+ /* No more data, this message is completed */
+ drvdata->msgs_remaining--;
+
+ if (drvdata->msgs_remaining == 0) {
+ /* No more messages, stop */
+ drvdata->state = GXP_I2C_COMP;
+ gxp_i2c_stop(drvdata);
+ return;
+ }
+ /* Move to next message and start transfer */
+ drvdata->curr_msg++;
+ gxp_i2c_restart(drvdata);
+ return;
+ }
+
+ /* Write data to slave */
+ value = *drvdata->buf;
+ value = value << 8;
+
+ /* Clear master event */
+ value |= MASTER_EVT_CLR;
+ drvdata->buf++;
+ drvdata->buf_remaining--;
+ drvdata->state = GXP_I2C_WDATA_PHASE;
+ writew(value, drvdata->base + GXP_I2CMCMD);
+}
+
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+static bool gxp_i2c_slave_irq_handler(struct gxp_i2c_drvdata *drvdata)
+{
+ u8 value;
+ u8 buf;
+ int ret;
+
+ value = readb(drvdata->base + GXP_I2CEVTERR);
+
+ /* Received start or stop event */
+ if (value & MASK_SLAVE_CMD_EVENT) {
+ value = readb(drvdata->base + GXP_I2CSTAT);
+ /* Master sent stop */
+ if (value & MASK_STOP_EVENT) {
+ if (drvdata->stopped == 0)
+ i2c_slave_event(drvdata->slave, I2C_SLAVE_STOP, &buf);
+ writeb(SLAVE_EVT_CLR | SNOOP_EVT_MASK |
+ SLAVE_ACK_ENAB | SLAVE_EVT_STALL, drvdata->base + GXP_I2CSCMD);
+ drvdata->stopped = 1;
+ } else {
+ /* Master sent start and wants to read */
+ drvdata->stopped = 0;
+ if (value & MASK_RW) {
+ i2c_slave_event(drvdata->slave,
+ I2C_SLAVE_READ_REQUESTED, &buf);
+ value = buf << 8 | (SLAVE_EVT_CLR | SNOOP_EVT_MASK |
+ SLAVE_EVT_STALL);
+ writew(value, drvdata->base + GXP_I2CSCMD);
+ } else {
+ /* Master wants to write to us */
+ ret = i2c_slave_event(drvdata->slave,
+ I2C_SLAVE_WRITE_REQUESTED, &buf);
+ if (!ret) {
+ /* Ack next byte from master */
+ writeb(SLAVE_EVT_CLR | SNOOP_EVT_MASK |
+ SLAVE_ACK_ENAB | SLAVE_EVT_STALL,
+ drvdata->base + GXP_I2CSCMD);
+ } else {
+ /* Nack next byte from master */
+ writeb(SLAVE_EVT_CLR | SNOOP_EVT_MASK |
+ SLAVE_EVT_STALL, drvdata->base + GXP_I2CSCMD);
+ }
+ }
+ }
+ } else if (value & MASK_SLAVE_DATA_EVENT) {
+ value = readb(drvdata->base + GXP_I2CSTAT);
+ /* Master wants to read */
+ if (value & MASK_RW) {
+ /* Master wants another byte */
+ if (value & MASK_ACK) {
+ i2c_slave_event(drvdata->slave,
+ I2C_SLAVE_READ_PROCESSED, &buf);
+ value = buf << 8 | (SLAVE_EVT_CLR | SNOOP_EVT_MASK |
+ SLAVE_EVT_STALL);
+ writew(value, drvdata->base + GXP_I2CSCMD);
+ } else {
+ /* No more bytes needed */
+ writew(SLAVE_EVT_CLR | SNOOP_EVT_MASK |
+ SLAVE_ACK_ENAB | SLAVE_EVT_STALL,
+ drvdata->base + GXP_I2CSCMD);
+ }
+ } else {
+ /* Master wants to write to us */
+ value = readb(drvdata->base + GXP_I2CSNPDAT);
+ buf = (uint8_t)value;
+ ret = i2c_slave_event(drvdata->slave,
+ I2C_SLAVE_WRITE_RECEIVED, &buf);
+ if (!ret) {
+ /* Ack next byte from master */
+ writeb(SLAVE_EVT_CLR | SNOOP_EVT_MASK |
+ SLAVE_ACK_ENAB | SLAVE_EVT_STALL,
+ drvdata->base + GXP_I2CSCMD);
+ } else {
+ /* Nack next byte from master */
+ writeb(SLAVE_EVT_CLR | SNOOP_EVT_MASK |
+ SLAVE_EVT_STALL, drvdata->base + GXP_I2CSCMD);
+ }
+ }
+ } else {
+ return false;
+ }
+
+ return true;
+}
+#endif
+
+static irqreturn_t gxp_i2c_irq_handler(int irq, void *_drvdata)
+{
+ struct gxp_i2c_drvdata *drvdata = (struct gxp_i2c_drvdata *)_drvdata;
+ u32 value;
+
+ /* Check if the interrupt is for the current engine */
+ regmap_read(i2cg_map, GXP_I2CINTSTAT, &value);
+ if (!(value & BIT(drvdata->engine)))
+ return IRQ_NONE;
+
+ value = readb(drvdata->base + GXP_I2CEVTERR);
+
+ /* Error */
+ if (value & ~(MASK_MASTER_EVENT | MASK_SLAVE_CMD_EVENT |
+ MASK_SLAVE_DATA_EVENT)) {
+ /* Clear all events */
+ writeb(0x00, drvdata->base + GXP_I2CEVTERR);
+ drvdata->state = GXP_I2C_ERROR;
+ gxp_i2c_stop(drvdata);
+ return IRQ_HANDLED;
+ }
+
+ if (IS_ENABLED(CONFIG_I2C_SLAVE)) {
+ /* Slave mode */
+ if (value & (MASK_SLAVE_CMD_EVENT | MASK_SLAVE_DATA_EVENT)) {
+ if (gxp_i2c_slave_irq_handler(drvdata))
+ return IRQ_HANDLED;
+ return IRQ_NONE;
+ }
+ }
+
+ /* Master mode */
+ switch (drvdata->state) {
+ case GXP_I2C_ADDR_PHASE:
+ gxp_i2c_chk_addr_ack(drvdata);
+ break;
+
+ case GXP_I2C_RDATA_PHASE:
+ gxp_i2c_ack_data(drvdata);
+ break;
+
+ case GXP_I2C_WDATA_PHASE:
+ gxp_i2c_chk_data_ack(drvdata);
+ break;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void gxp_i2c_init(struct gxp_i2c_drvdata *drvdata)
+{
+ drvdata->state = GXP_I2C_IDLE;
+ writeb(2000000 / drvdata->t.bus_freq_hz,
+ drvdata->base + GXP_I2CFREQDIV);
+ writeb(FILTER_CNT | FAIRNESS_CNT,
+ drvdata->base + GXP_I2CFLTFAIR);
+ writeb(GXP_DATA_EDGE_RST_CTRL, drvdata->base + GXP_I2CTMOEDG);
+ writeb(0x00, drvdata->base + GXP_I2CCYCTIM);
+ writeb(0x00, drvdata->base + GXP_I2CSNPAA);
+ writeb(0x00, drvdata->base + GXP_I2CADVFEAT);
+ writeb(SNOOP_EVT_CLR | SLAVE_EVT_CLR | SNOOP_EVT_MASK |
+ SLAVE_EVT_MASK, drvdata->base + GXP_I2CSCMD);
+ writeb(MASTER_EVT_CLR, drvdata->base + GXP_I2CMCMD);
+ writeb(0x00, drvdata->base + GXP_I2CEVTERR);
+ writeb(0x00, drvdata->base + GXP_I2COWNADR);
+}
+
+static int gxp_i2c_probe(struct platform_device *pdev)
+{
+ struct gxp_i2c_drvdata *drvdata;
+ int rc;
+ struct i2c_adapter *adapter;
+
+ if (!i2cg_map) {
+ i2cg_map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+ "hpe,sysreg");
+ if (IS_ERR(i2cg_map)) {
+ return dev_err_probe(&pdev->dev, IS_ERR(i2cg_map),
+ "failed to map i2cg_handle\n");
+ }
+
+ /* Disable interrupt */
+ regmap_update_bits(i2cg_map, GXP_I2CINTEN, 0x00000FFF, 0);
+ }
+
+ drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata),
+ GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, drvdata);
+ drvdata->dev = &pdev->dev;
+ init_completion(&drvdata->completion);
+
+ drvdata->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(drvdata->base))
+ return PTR_ERR(drvdata->base);
+
+ /* Use physical memory address to determine which I2C engine this is. */
+ drvdata->engine = ((size_t)drvdata->base & 0xf00) >> 8;
+
+ if (drvdata->engine >= GXP_MAX_I2C_ENGINE) {
+ return dev_err_probe(&pdev->dev, -EINVAL, "i2c engine% is unsupported\n",
+ drvdata->engine);
+ }
+
+ rc = platform_get_irq(pdev, 0);
+ if (rc < 0)
+ return rc;
+
+ drvdata->irq = rc;
+ rc = devm_request_irq(&pdev->dev, drvdata->irq, gxp_i2c_irq_handler,
+ IRQF_SHARED, gxp_i2c_name[drvdata->engine], drvdata);
+ if (rc < 0)
+ return dev_err_probe(&pdev->dev, rc, "irq request failed\n");
+
+ i2c_parse_fw_timings(&pdev->dev, &drvdata->t, true);
+
+ gxp_i2c_init(drvdata);
+
+ /* Enable interrupt */
+ regmap_update_bits(i2cg_map, GXP_I2CINTEN, BIT(drvdata->engine),
+ BIT(drvdata->engine));
+
+ adapter = &drvdata->adapter;
+ i2c_set_adapdata(adapter, drvdata);
+
+ adapter->owner = THIS_MODULE;
+ strscpy(adapter->name, "HPE GXP I2C adapter", sizeof(adapter->name));
+ adapter->algo = &gxp_i2c_algo;
+ adapter->dev.parent = &pdev->dev;
+ adapter->dev.of_node = pdev->dev.of_node;
+
+ rc = i2c_add_adapter(adapter);
+ if (rc)
+ return dev_err_probe(&pdev->dev, rc, "i2c add adapter failed\n");
+
+ return 0;
+}
+
+static int gxp_i2c_remove(struct platform_device *pdev)
+{
+ struct gxp_i2c_drvdata *drvdata = platform_get_drvdata(pdev);
+
+ /* Disable interrupt */
+ regmap_update_bits(i2cg_map, GXP_I2CINTEN, BIT(drvdata->engine), 0);
+ i2c_del_adapter(&drvdata->adapter);
+
+ return 0;
+}
+
+static const struct of_device_id gxp_i2c_of_match[] = {
+ { .compatible = "hpe,gxp-i2c" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, gxp_i2c_of_match);
+
+static struct platform_driver gxp_i2c_driver = {
+ .probe = gxp_i2c_probe,
+ .remove = gxp_i2c_remove,
+ .driver = {
+ .name = "gxp-i2c",
+ .of_match_table = gxp_i2c_of_match,
+ },
+};
+module_platform_driver(gxp_i2c_driver);
+
+MODULE_AUTHOR("Nick Hawkins <nick.hawkins@hpe.com>");
+MODULE_DESCRIPTION("HPE GXP I2C bus driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 1fda1eaa6d6a..ac5326747c51 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -434,7 +434,7 @@ static int i801_wait_intr(struct i801_priv *priv)
busy = status & SMBHSTSTS_HOST_BUSY;
status &= STATUS_ERROR_FLAGS | SMBHSTSTS_INTR;
if (!busy && status)
- return status;
+ return status & STATUS_ERROR_FLAGS;
} while (time_is_after_eq_jiffies(timeout));
return -ETIMEDOUT;
@@ -458,26 +458,20 @@ static int i801_wait_byte_done(struct i801_priv *priv)
static int i801_transaction(struct i801_priv *priv, int xact)
{
- int status;
unsigned long result;
const struct i2c_adapter *adap = &priv->adapter;
- status = i801_check_pre(priv);
- if (status < 0)
- return status;
-
if (priv->features & FEATURE_IRQ) {
reinit_completion(&priv->done);
outb_p(xact | SMBHSTCNT_INTREN | SMBHSTCNT_START,
SMBHSTCNT(priv));
result = wait_for_completion_timeout(&priv->done, adap->timeout);
- return i801_check_post(priv, result ? priv->status : -ETIMEDOUT);
+ return result ? priv->status : -ETIMEDOUT;
}
outb_p(xact | SMBHSTCNT_START, SMBHSTCNT(priv));
- status = i801_wait_intr(priv);
- return i801_check_post(priv, status);
+ return i801_wait_intr(priv);
}
static int i801_block_transaction_by_block(struct i801_priv *priv,
@@ -511,19 +505,23 @@ static int i801_block_transaction_by_block(struct i801_priv *priv,
status = i801_transaction(priv, xact);
if (status)
- return status;
+ goto out;
if (read_write == I2C_SMBUS_READ ||
command == I2C_SMBUS_BLOCK_PROC_CALL) {
len = inb_p(SMBHSTDAT0(priv));
- if (len < 1 || len > I2C_SMBUS_BLOCK_MAX)
- return -EPROTO;
+ if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) {
+ status = -EPROTO;
+ goto out;
+ }
data->block[0] = len;
for (i = 0; i < len; i++)
data->block[i + 1] = inb_p(SMBBLKDAT(priv));
}
- return 0;
+out:
+ outb_p(inb_p(SMBAUXCTL(priv)) & ~SMBAUXCTL_E32B, SMBAUXCTL(priv));
+ return status;
}
static void i801_isr_byte_done(struct i801_priv *priv)
@@ -558,9 +556,6 @@ static void i801_isr_byte_done(struct i801_priv *priv)
/* Write next byte, except for IRQ after last byte */
outb_p(priv->data[++priv->count], SMBBLKDAT(priv));
}
-
- /* Clear BYTE_DONE to continue with next byte */
- outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv));
}
static irqreturn_t i801_host_notify_isr(struct i801_priv *priv)
@@ -590,7 +585,6 @@ static irqreturn_t i801_host_notify_isr(struct i801_priv *priv)
* BUS_ERR - SMI# transaction collision
* FAILED - transaction was canceled due to a KILL request
* When any of these occur, update ->status and signal completion.
- * ->status must be cleared before kicking off the next transaction.
*
* 2) For byte-by-byte (I2C read/write) transactions, one BYTE_DONE interrupt
* occurs for each byte of a byte-by-byte to prepare the next byte.
@@ -615,25 +609,20 @@ static irqreturn_t i801_isr(int irq, void *dev_id)
}
status = inb_p(SMBHSTSTS(priv));
- if (status & SMBHSTSTS_BYTE_DONE)
+ if ((status & (SMBHSTSTS_BYTE_DONE | STATUS_ERROR_FLAGS)) == SMBHSTSTS_BYTE_DONE)
i801_isr_byte_done(priv);
/*
- * Clear remaining IRQ sources: Completion of last command, errors
- * and the SMB_ALERT signal. SMB_ALERT status is set after signal
- * assertion independently of the interrupt generation being blocked
- * or not so clear it always when the status is set.
- */
- status &= SMBHSTSTS_INTR | STATUS_ERROR_FLAGS | SMBHSTSTS_SMBALERT_STS;
- if (status)
- outb_p(status, SMBHSTSTS(priv));
- status &= ~SMBHSTSTS_SMBALERT_STS; /* SMB_ALERT not reported */
- /*
- * Report transaction result.
- * ->status must be cleared before the next transaction is started.
+ * Clear IRQ sources: SMB_ALERT status is set after signal assertion
+ * independently of the interrupt generation being blocked or not
+ * so clear it always when the status is set.
*/
+ status &= STATUS_FLAGS | SMBHSTSTS_SMBALERT_STS;
+ outb_p(status, SMBHSTSTS(priv));
+
+ status &= STATUS_ERROR_FLAGS | SMBHSTSTS_INTR;
if (status) {
- priv->status = status;
+ priv->status = status & STATUS_ERROR_FLAGS;
complete(&priv->done);
}
@@ -658,10 +647,6 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
if (command == I2C_SMBUS_BLOCK_PROC_CALL)
return -EOPNOTSUPP;
- status = i801_check_pre(priv);
- if (status < 0)
- return status;
-
len = data->block[0];
if (read_write == I2C_SMBUS_WRITE) {
@@ -687,7 +672,7 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
reinit_completion(&priv->done);
outb_p(priv->cmd | SMBHSTCNT_START, SMBHSTCNT(priv));
result = wait_for_completion_timeout(&priv->done, adap->timeout);
- return i801_check_post(priv, result ? priv->status : -ETIMEDOUT);
+ return result ? priv->status : -ETIMEDOUT;
}
for (i = 1; i <= len; i++) {
@@ -701,7 +686,7 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
status = i801_wait_byte_done(priv);
if (status)
- goto exit;
+ return status;
if (i == 1 && read_write == I2C_SMBUS_READ
&& command != I2C_SMBUS_I2C_BLOCK_DATA) {
@@ -731,14 +716,82 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv));
}
- status = i801_wait_intr(priv);
-exit:
- return i801_check_post(priv, status);
+ return i801_wait_intr(priv);
+}
+
+static void i801_set_hstadd(struct i801_priv *priv, u8 addr, char read_write)
+{
+ outb_p((addr << 1) | (read_write & 0x01), SMBHSTADD(priv));
+}
+
+/* Single value transaction function */
+static int i801_simple_transaction(struct i801_priv *priv, union i2c_smbus_data *data,
+ u8 addr, u8 hstcmd, char read_write, int command)
+{
+ int xact, ret;
+
+ switch (command) {
+ case I2C_SMBUS_QUICK:
+ i801_set_hstadd(priv, addr, read_write);
+ xact = I801_QUICK;
+ break;
+ case I2C_SMBUS_BYTE:
+ i801_set_hstadd(priv, addr, read_write);
+ if (read_write == I2C_SMBUS_WRITE)
+ outb_p(hstcmd, SMBHSTCMD(priv));
+ xact = I801_BYTE;
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ i801_set_hstadd(priv, addr, read_write);
+ if (read_write == I2C_SMBUS_WRITE)
+ outb_p(data->byte, SMBHSTDAT0(priv));
+ outb_p(hstcmd, SMBHSTCMD(priv));
+ xact = I801_BYTE_DATA;
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ i801_set_hstadd(priv, addr, read_write);
+ if (read_write == I2C_SMBUS_WRITE) {
+ outb_p(data->word & 0xff, SMBHSTDAT0(priv));
+ outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1(priv));
+ }
+ outb_p(hstcmd, SMBHSTCMD(priv));
+ xact = I801_WORD_DATA;
+ break;
+ case I2C_SMBUS_PROC_CALL:
+ i801_set_hstadd(priv, addr, I2C_SMBUS_WRITE);
+ outb_p(data->word & 0xff, SMBHSTDAT0(priv));
+ outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1(priv));
+ outb_p(hstcmd, SMBHSTCMD(priv));
+ read_write = I2C_SMBUS_READ;
+ xact = I801_PROC_CALL;
+ break;
+ default:
+ pci_err(priv->pci_dev, "Unsupported transaction %d\n", command);
+ return -EOPNOTSUPP;
+ }
+
+ ret = i801_transaction(priv, xact);
+ if (ret || read_write == I2C_SMBUS_WRITE)
+ return ret;
+
+ switch (command) {
+ case I2C_SMBUS_BYTE:
+ case I2C_SMBUS_BYTE_DATA:
+ data->byte = inb_p(SMBHSTDAT0(priv));
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ case I2C_SMBUS_PROC_CALL:
+ data->word = inb_p(SMBHSTDAT0(priv)) +
+ (inb_p(SMBHSTDAT1(priv)) << 8);
+ break;
+ }
+
+ return 0;
}
/* Block transaction function */
static int i801_block_transaction(struct i801_priv *priv, union i2c_smbus_data *data,
- char read_write, int command)
+ u8 addr, u8 hstcmd, char read_write, int command)
{
int result = 0;
unsigned char hostc;
@@ -748,7 +801,29 @@ static int i801_block_transaction(struct i801_priv *priv, union i2c_smbus_data *
else if (data->block[0] < 1 || data->block[0] > I2C_SMBUS_BLOCK_MAX)
return -EPROTO;
- if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
+ switch (command) {
+ case I2C_SMBUS_BLOCK_DATA:
+ i801_set_hstadd(priv, addr, read_write);
+ outb_p(hstcmd, SMBHSTCMD(priv));
+ break;
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ /*
+ * NB: page 240 of ICH5 datasheet shows that the R/#W
+ * bit should be cleared here, even when reading.
+ * However if SPD Write Disable is set (Lynx Point and later),
+ * the read will fail if we don't set the R/#W bit.
+ */
+ i801_set_hstadd(priv, addr,
+ priv->original_hstcfg & SMBHSTCFG_SPD_WD ?
+ read_write : I2C_SMBUS_WRITE);
+ if (read_write == I2C_SMBUS_READ) {
+ /* NB: page 240 of ICH5 datasheet also shows
+ * that DATA1 is the cmd field when reading
+ */
+ outb_p(hstcmd, SMBHSTDAT1(priv));
+ } else
+ outb_p(hstcmd, SMBHSTCMD(priv));
+
if (read_write == I2C_SMBUS_WRITE) {
/* set I2C_EN bit in configuration register */
pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &hostc);
@@ -759,6 +834,12 @@ static int i801_block_transaction(struct i801_priv *priv, union i2c_smbus_data *
"I2C block read is unsupported!\n");
return -EOPNOTSUPP;
}
+ break;
+ case I2C_SMBUS_BLOCK_PROC_CALL:
+ /* Needs to be flagged as write transaction */
+ i801_set_hstadd(priv, addr, I2C_SMBUS_WRITE);
+ outb_p(hstcmd, SMBHSTCMD(priv));
+ break;
}
/* Experience has shown that the block buffer can only be used for
@@ -787,9 +868,7 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
unsigned short flags, char read_write, u8 command,
int size, union i2c_smbus_data *data)
{
- int hwpec;
- int block = 0;
- int ret, xact;
+ int hwpec, ret;
struct i801_priv *priv = i2c_get_adapdata(adap);
mutex_lock(&priv->acpi_lock);
@@ -800,127 +879,34 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
pm_runtime_get_sync(&priv->pci_dev->dev);
+ ret = i801_check_pre(priv);
+ if (ret)
+ goto out;
+
hwpec = (priv->features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC)
&& size != I2C_SMBUS_QUICK
&& size != I2C_SMBUS_I2C_BLOCK_DATA;
- switch (size) {
- case I2C_SMBUS_QUICK:
- outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
- SMBHSTADD(priv));
- xact = I801_QUICK;
- break;
- case I2C_SMBUS_BYTE:
- outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
- SMBHSTADD(priv));
- if (read_write == I2C_SMBUS_WRITE)
- outb_p(command, SMBHSTCMD(priv));
- xact = I801_BYTE;
- break;
- case I2C_SMBUS_BYTE_DATA:
- outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
- SMBHSTADD(priv));
- outb_p(command, SMBHSTCMD(priv));
- if (read_write == I2C_SMBUS_WRITE)
- outb_p(data->byte, SMBHSTDAT0(priv));
- xact = I801_BYTE_DATA;
- break;
- case I2C_SMBUS_WORD_DATA:
- outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
- SMBHSTADD(priv));
- outb_p(command, SMBHSTCMD(priv));
- if (read_write == I2C_SMBUS_WRITE) {
- outb_p(data->word & 0xff, SMBHSTDAT0(priv));
- outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1(priv));
- }
- xact = I801_WORD_DATA;
- break;
- case I2C_SMBUS_PROC_CALL:
- outb_p((addr & 0x7f) << 1, SMBHSTADD(priv));
- outb_p(command, SMBHSTCMD(priv));
- outb_p(data->word & 0xff, SMBHSTDAT0(priv));
- outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1(priv));
- xact = I801_PROC_CALL;
- read_write = I2C_SMBUS_READ;
- break;
- case I2C_SMBUS_BLOCK_DATA:
- outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
- SMBHSTADD(priv));
- outb_p(command, SMBHSTCMD(priv));
- block = 1;
- break;
- case I2C_SMBUS_I2C_BLOCK_DATA:
- /*
- * NB: page 240 of ICH5 datasheet shows that the R/#W
- * bit should be cleared here, even when reading.
- * However if SPD Write Disable is set (Lynx Point and later),
- * the read will fail if we don't set the R/#W bit.
- */
- outb_p(((addr & 0x7f) << 1) |
- ((priv->original_hstcfg & SMBHSTCFG_SPD_WD) ?
- (read_write & 0x01) : 0),
- SMBHSTADD(priv));
- if (read_write == I2C_SMBUS_READ) {
- /* NB: page 240 of ICH5 datasheet also shows
- * that DATA1 is the cmd field when reading */
- outb_p(command, SMBHSTDAT1(priv));
- } else
- outb_p(command, SMBHSTCMD(priv));
- block = 1;
- break;
- case I2C_SMBUS_BLOCK_PROC_CALL:
- /*
- * Bit 0 of the slave address register always indicate a write
- * command.
- */
- outb_p((addr & 0x7f) << 1, SMBHSTADD(priv));
- outb_p(command, SMBHSTCMD(priv));
- block = 1;
- break;
- default:
- dev_err(&priv->pci_dev->dev, "Unsupported transaction %d\n",
- size);
- ret = -EOPNOTSUPP;
- goto out;
- }
-
if (hwpec) /* enable/disable hardware PEC */
outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_CRC, SMBAUXCTL(priv));
else
outb_p(inb_p(SMBAUXCTL(priv)) & (~SMBAUXCTL_CRC),
SMBAUXCTL(priv));
- if (block)
- ret = i801_block_transaction(priv, data, read_write, size);
+ if (size == I2C_SMBUS_BLOCK_DATA ||
+ size == I2C_SMBUS_I2C_BLOCK_DATA ||
+ size == I2C_SMBUS_BLOCK_PROC_CALL)
+ ret = i801_block_transaction(priv, data, addr, command, read_write, size);
else
- ret = i801_transaction(priv, xact);
-
- /* Some BIOSes don't like it when PEC is enabled at reboot or resume
- time, so we forcibly disable it after every transaction. Turn off
- E32B for the same reason. */
- if (hwpec || block)
- outb_p(inb_p(SMBAUXCTL(priv)) &
- ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));
-
- if (block)
- goto out;
- if (ret)
- goto out;
- if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK))
- goto out;
+ ret = i801_simple_transaction(priv, data, addr, command, read_write, size);
- switch (xact) {
- case I801_BYTE: /* Result put in SMBHSTDAT0 */
- case I801_BYTE_DATA:
- data->byte = inb_p(SMBHSTDAT0(priv));
- break;
- case I801_WORD_DATA:
- case I801_PROC_CALL:
- data->word = inb_p(SMBHSTDAT0(priv)) +
- (inb_p(SMBHSTDAT1(priv)) << 8);
- break;
- }
+ ret = i801_check_post(priv, ret);
+ /* Some BIOSes don't like it when PEC is enabled at reboot or resume
+ * time, so we forcibly disable it after every transaction.
+ */
+ if (hwpec)
+ outb_p(inb_p(SMBAUXCTL(priv)) & ~SMBAUXCTL_CRC, SMBAUXCTL(priv));
out:
/*
* Unlock the SMBus device for use by BIOS/ACPI,
@@ -1667,6 +1653,10 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
}
priv->features &= ~disable_features;
+ /* The block process call uses block buffer mode */
+ if (!(priv->features & FEATURE_BLOCK_BUFFER))
+ priv->features &= ~FEATURE_BLOCK_PROC;
+
err = pcim_enable_device(dev);
if (err) {
dev_err(&dev->dev, "Failed to enable SMBus PCI device (%d)\n",
@@ -1714,11 +1704,6 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
outb_p(inb_p(SMBAUXCTL(priv)) &
~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));
- /* Remember original Interrupt and Host Notify settings */
- priv->original_hstcnt = inb_p(SMBHSTCNT(priv)) & ~SMBHSTCNT_KILL;
- if (priv->features & FEATURE_HOST_NOTIFY)
- priv->original_slvcmd = inb_p(SMBSLVCMD(priv));
-
/* Default timeout in interrupt mode: 200 ms */
priv->adapter.timeout = HZ / 5;
@@ -1748,6 +1733,15 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
dev_info(&dev->dev, "SMBus using %s\n",
priv->features & FEATURE_IRQ ? "PCI interrupt" : "polling");
+ /* Host notification uses an interrupt */
+ if (!(priv->features & FEATURE_IRQ))
+ priv->features &= ~FEATURE_HOST_NOTIFY;
+
+ /* Remember original Interrupt and Host Notify settings */
+ priv->original_hstcnt = inb_p(SMBHSTCNT(priv)) & ~SMBHSTCNT_KILL;
+ if (priv->features & FEATURE_HOST_NOTIFY)
+ priv->original_slvcmd = inb_p(SMBSLVCMD(priv));
+
i801_add_tco(priv);
snprintf(priv->adapter.name, sizeof(priv->adapter.name),
diff --git a/drivers/i2c/busses/i2c-ls2x.c b/drivers/i2c/busses/i2c-ls2x.c
new file mode 100644
index 000000000000..ebae6035701d
--- /dev/null
+++ b/drivers/i2c/busses/i2c-ls2x.c
@@ -0,0 +1,370 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Loongson-2K/Loongson LS7A I2C master mode driver
+ *
+ * Copyright (C) 2013 Loongson Technology Corporation Limited.
+ * Copyright (C) 2014-2017 Lemote, Inc.
+ * Copyright (C) 2018-2022 Loongson Technology Corporation Limited.
+ *
+ * Originally written by liushaozong
+ * Rewritten for mainline by Binbin Zhou <zhoubinbin@loongson.cn>
+ */
+
+#include <linux/bits.h>
+#include <linux/completion.h>
+#include <linux/device.h>
+#include <linux/iopoll.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/units.h>
+
+/* I2C Registers */
+#define I2C_LS2X_PRER 0x0 /* Freq Division Register(16 bits) */
+#define I2C_LS2X_CTR 0x2 /* Control Register */
+#define I2C_LS2X_TXR 0x3 /* Transport Data Register */
+#define I2C_LS2X_RXR 0x3 /* Receive Data Register */
+#define I2C_LS2X_CR 0x4 /* Command Control Register */
+#define I2C_LS2X_SR 0x4 /* State Register */
+
+/* Command Control Register Bit */
+#define LS2X_CR_START BIT(7) /* Start signal */
+#define LS2X_CR_STOP BIT(6) /* Stop signal */
+#define LS2X_CR_READ BIT(5) /* Read signal */
+#define LS2X_CR_WRITE BIT(4) /* Write signal */
+#define LS2X_CR_ACK BIT(3) /* Response signal */
+#define LS2X_CR_IACK BIT(0) /* Interrupt response signal */
+
+/* State Register Bit */
+#define LS2X_SR_NOACK BIT(7) /* Receive NACK */
+#define LS2X_SR_BUSY BIT(6) /* Bus busy state */
+#define LS2X_SR_AL BIT(5) /* Arbitration lost */
+#define LS2X_SR_TIP BIT(1) /* Transmission state */
+#define LS2X_SR_IF BIT(0) /* Interrupt flag */
+
+/* Control Register Bit */
+#define LS2X_CTR_EN BIT(7) /* 0: I2c frequency setting 1: Normal */
+#define LS2X_CTR_IEN BIT(6) /* Enable i2c interrupt */
+#define LS2X_CTR_MST BIT(5) /* 0: Slave mode 1: Master mode */
+#define CTR_FREQ_MASK GENMASK(7, 6)
+#define CTR_READY_MASK GENMASK(7, 5)
+
+/* The PCLK frequency from LPB */
+#define LS2X_I2C_PCLK_FREQ (50 * HZ_PER_MHZ)
+
+/* The default bus frequency, which is an empirical value */
+#define LS2X_I2C_FREQ_STD (33 * HZ_PER_KHZ)
+
+struct ls2x_i2c_priv {
+ struct i2c_adapter adapter;
+ void __iomem *base;
+ struct i2c_timings i2c_t;
+ struct completion cmd_complete;
+};
+
+/*
+ * Interrupt service routine.
+ * This gets called whenever an I2C interrupt occurs.
+ */
+static irqreturn_t ls2x_i2c_isr(int this_irq, void *dev_id)
+{
+ struct ls2x_i2c_priv *priv = dev_id;
+
+ if (!(readb(priv->base + I2C_LS2X_SR) & LS2X_SR_IF))
+ return IRQ_NONE;
+
+ writeb(LS2X_CR_IACK, priv->base + I2C_LS2X_CR);
+ complete(&priv->cmd_complete);
+ return IRQ_HANDLED;
+}
+
+/*
+ * The ls2x i2c controller supports standard mode and fast mode, so the
+ * maximum bus frequency is '400kHz'.
+ * The bus frequency is set to the empirical value of '33KHz' by default,
+ * but it can also be taken from ACPI or FDT for compatibility with more
+ * devices.
+ */
+static void ls2x_i2c_adjust_bus_speed(struct ls2x_i2c_priv *priv)
+{
+ struct i2c_timings *t = &priv->i2c_t;
+ struct device *dev = priv->adapter.dev.parent;
+ u32 acpi_speed = i2c_acpi_find_bus_speed(dev);
+
+ i2c_parse_fw_timings(dev, t, false);
+
+ if (acpi_speed || t->bus_freq_hz)
+ t->bus_freq_hz = max(t->bus_freq_hz, acpi_speed);
+ else
+ t->bus_freq_hz = LS2X_I2C_FREQ_STD;
+
+ /* Calculate and set i2c frequency. */
+ writew(LS2X_I2C_PCLK_FREQ / (5 * t->bus_freq_hz) - 1,
+ priv->base + I2C_LS2X_PRER);
+}
+
+static void ls2x_i2c_init(struct ls2x_i2c_priv *priv)
+{
+ /* Set i2c frequency setting mode and disable interrupts. */
+ writeb(readb(priv->base + I2C_LS2X_CTR) & ~CTR_FREQ_MASK,
+ priv->base + I2C_LS2X_CTR);
+
+ ls2x_i2c_adjust_bus_speed(priv);
+
+ /* Set i2c normal operating mode and enable interrupts. */
+ writeb(readb(priv->base + I2C_LS2X_CTR) | CTR_READY_MASK,
+ priv->base + I2C_LS2X_CTR);
+}
+
+static int ls2x_i2c_xfer_byte(struct ls2x_i2c_priv *priv, u8 txdata, u8 *rxdatap)
+{
+ u8 rxdata;
+ unsigned long time_left;
+
+ writeb(txdata, priv->base + I2C_LS2X_CR);
+
+ time_left = wait_for_completion_timeout(&priv->cmd_complete,
+ priv->adapter.timeout);
+ if (!time_left)
+ return -ETIMEDOUT;
+
+ rxdata = readb(priv->base + I2C_LS2X_SR);
+ if (rxdatap)
+ *rxdatap = rxdata;
+
+ return 0;
+}
+
+static int ls2x_i2c_send_byte(struct ls2x_i2c_priv *priv, u8 txdata)
+{
+ int ret;
+ u8 rxdata;
+
+ ret = ls2x_i2c_xfer_byte(priv, txdata, &rxdata);
+ if (ret)
+ return ret;
+
+ if (rxdata & LS2X_SR_AL)
+ return -EAGAIN;
+
+ if (rxdata & LS2X_SR_NOACK)
+ return -ENXIO;
+
+ return 0;
+}
+
+static int ls2x_i2c_stop(struct ls2x_i2c_priv *priv)
+{
+ u8 value;
+
+ writeb(LS2X_CR_STOP, priv->base + I2C_LS2X_CR);
+ return readb_poll_timeout(priv->base + I2C_LS2X_SR, value,
+ !(value & LS2X_SR_BUSY), 100,
+ jiffies_to_usecs(priv->adapter.timeout));
+}
+
+static int ls2x_i2c_start(struct ls2x_i2c_priv *priv, struct i2c_msg *msgs)
+{
+ reinit_completion(&priv->cmd_complete);
+
+ writeb(i2c_8bit_addr_from_msg(msgs), priv->base + I2C_LS2X_TXR);
+ return ls2x_i2c_send_byte(priv, LS2X_CR_START | LS2X_CR_WRITE);
+}
+
+static int ls2x_i2c_rx(struct ls2x_i2c_priv *priv, struct i2c_msg *msg)
+{
+ int ret;
+ u8 rxdata, *buf = msg->buf;
+ u16 len = msg->len;
+
+ /* Contains steps to send start condition and address. */
+ ret = ls2x_i2c_start(priv, msg);
+ if (ret)
+ return ret;
+
+ while (len--) {
+ ret = ls2x_i2c_xfer_byte(priv,
+ LS2X_CR_READ | (len ? 0 : LS2X_CR_ACK),
+ &rxdata);
+ if (ret)
+ return ret;
+
+ *buf++ = readb(priv->base + I2C_LS2X_RXR);
+ }
+
+ return 0;
+}
+
+static int ls2x_i2c_tx(struct ls2x_i2c_priv *priv, struct i2c_msg *msg)
+{
+ int ret;
+ u8 *buf = msg->buf;
+ u16 len = msg->len;
+
+ /* Contains steps to send start condition and address. */
+ ret = ls2x_i2c_start(priv, msg);
+ if (ret)
+ return ret;
+
+ while (len--) {
+ writeb(*buf++, priv->base + I2C_LS2X_TXR);
+
+ ret = ls2x_i2c_send_byte(priv, LS2X_CR_WRITE);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ls2x_i2c_xfer_one(struct ls2x_i2c_priv *priv,
+ struct i2c_msg *msg, bool stop)
+{
+ int ret;
+
+ if (msg->flags & I2C_M_RD)
+ ret = ls2x_i2c_rx(priv, msg);
+ else
+ ret = ls2x_i2c_tx(priv, msg);
+
+ if (ret < 0) {
+ /* Fatel error. Needs reinit. */
+ if (ret == -ETIMEDOUT)
+ ls2x_i2c_init(priv);
+
+ return ret;
+ }
+
+ if (stop) {
+ /* Failed to issue STOP. Needs reinit. */
+ ret = ls2x_i2c_stop(priv);
+ if (ret)
+ ls2x_i2c_init(priv);
+ }
+
+ return ret;
+}
+
+static int ls2x_i2c_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num)
+{
+ int ret;
+ struct i2c_msg *msg, *emsg = msgs + num;
+ struct ls2x_i2c_priv *priv = i2c_get_adapdata(adap);
+
+ for (msg = msgs; msg < emsg; msg++) {
+ ret = ls2x_i2c_xfer_one(priv, msg, msg == emsg - 1);
+ if (ret)
+ return ret;
+ }
+
+ return num;
+}
+
+static unsigned int ls2x_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm ls2x_i2c_algo = {
+ .master_xfer = ls2x_i2c_master_xfer,
+ .functionality = ls2x_i2c_func,
+};
+
+static int ls2x_i2c_probe(struct platform_device *pdev)
+{
+ int ret, irq;
+ struct i2c_adapter *adap;
+ struct ls2x_i2c_priv *priv;
+ struct device *dev = &pdev->dev;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ /* Map hardware registers */
+ priv->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ /* Add the i2c adapter */
+ adap = &priv->adapter;
+ adap->retries = 5;
+ adap->nr = pdev->id;
+ adap->dev.parent = dev;
+ adap->owner = THIS_MODULE;
+ adap->algo = &ls2x_i2c_algo;
+ adap->timeout = msecs_to_jiffies(100);
+ device_set_node(&adap->dev, dev_fwnode(dev));
+ i2c_set_adapdata(adap, priv);
+ strscpy(adap->name, pdev->name, sizeof(adap->name));
+ init_completion(&priv->cmd_complete);
+ platform_set_drvdata(pdev, priv);
+
+ ls2x_i2c_init(priv);
+
+ ret = devm_request_irq(dev, irq, ls2x_i2c_isr, IRQF_SHARED, "ls2x-i2c",
+ priv);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Unable to request irq %d\n", irq);
+
+ return devm_i2c_add_adapter(dev, adap);
+}
+
+static int ls2x_i2c_suspend(struct device *dev)
+{
+ struct ls2x_i2c_priv *priv = dev_get_drvdata(dev);
+
+ /* Disable interrupts */
+ writeb(readb(priv->base + I2C_LS2X_CTR) & ~LS2X_CTR_IEN,
+ priv->base + I2C_LS2X_CTR);
+
+ return 0;
+}
+
+static int ls2x_i2c_resume(struct device *dev)
+{
+ ls2x_i2c_init(dev_get_drvdata(dev));
+ return 0;
+}
+
+static DEFINE_RUNTIME_DEV_PM_OPS(ls2x_i2c_pm_ops,
+ ls2x_i2c_suspend, ls2x_i2c_resume, NULL);
+
+static const struct of_device_id ls2x_i2c_id_table[] = {
+ { .compatible = "loongson,ls2k-i2c" },
+ { .compatible = "loongson,ls7a-i2c" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ls2x_i2c_id_table);
+
+static const struct acpi_device_id ls2x_i2c_acpi_match[] = {
+ { "LOON0004" }, /* Loongson LS7A */
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, ls2x_i2c_acpi_match);
+
+static struct platform_driver ls2x_i2c_driver = {
+ .probe = ls2x_i2c_probe,
+ .driver = {
+ .name = "ls2x-i2c",
+ .pm = pm_sleep_ptr(&ls2x_i2c_pm_ops),
+ .of_match_table = ls2x_i2c_id_table,
+ .acpi_match_table = ls2x_i2c_acpi_match,
+ },
+};
+module_platform_driver(ls2x_i2c_driver);
+
+MODULE_DESCRIPTION("Loongson LS2X I2C Bus driver");
+MODULE_AUTHOR("Loongson Technology Corporation Limited");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
index d80e59340d97..43dd966d5ef5 100644
--- a/drivers/i2c/busses/i2c-mt65xx.c
+++ b/drivers/i2c/busses/i2c-mt65xx.c
@@ -1366,20 +1366,17 @@ static int mtk_i2c_probe(struct platform_device *pdev)
{
int ret = 0;
struct mtk_i2c *i2c;
- struct resource *res;
int i, irq, speed_clk;
i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
if (!i2c)
return -ENOMEM;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- i2c->base = devm_ioremap_resource(&pdev->dev, res);
+ i2c->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(i2c->base))
return PTR_ERR(i2c->base);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- i2c->pdmabase = devm_ioremap_resource(&pdev->dev, res);
+ i2c->pdmabase = devm_platform_get_and_ioremap_resource(pdev, 1, NULL);
if (IS_ERR(i2c->pdmabase))
return PTR_ERR(i2c->pdmabase);
diff --git a/drivers/i2c/busses/i2c-nvidia-gpu.c b/drivers/i2c/busses/i2c-nvidia-gpu.c
index 12e330cd7635..a8b99e7f6262 100644
--- a/drivers/i2c/busses/i2c-nvidia-gpu.c
+++ b/drivers/i2c/busses/i2c-nvidia-gpu.c
@@ -259,8 +259,8 @@ static const struct pci_device_id gpu_i2c_ids[] = {
MODULE_DEVICE_TABLE(pci, gpu_i2c_ids);
static const struct property_entry ccgx_props[] = {
- /* Use FW built for NVIDIA (nv) only */
- PROPERTY_ENTRY_U16("ccgx,firmware-build", ('n' << 8) | 'v'),
+ /* Use FW built for NVIDIA GPU only */
+ PROPERTY_ENTRY_STRING("firmware-name", "nvidia,gpu"),
{ }
};
diff --git a/drivers/i2c/busses/i2c-qcom-cci.c b/drivers/i2c/busses/i2c-qcom-cci.c
index a4b97fe3c3a5..01358472680c 100644
--- a/drivers/i2c/busses/i2c-qcom-cci.c
+++ b/drivers/i2c/busses/i2c-qcom-cci.c
@@ -811,9 +811,15 @@ static const struct cci_data cci_v2_data = {
static const struct of_device_id cci_dt_match[] = {
{ .compatible = "qcom,msm8226-cci", .data = &cci_v1_data},
- { .compatible = "qcom,msm8916-cci", .data = &cci_v1_data},
{ .compatible = "qcom,msm8974-cci", .data = &cci_v1_5_data},
{ .compatible = "qcom,msm8996-cci", .data = &cci_v2_data},
+
+
+ /*
+ * Legacy compatibles kept for backwards compatibility.
+ * Do not add any new ones unless they introduce a new config
+ */
+ { .compatible = "qcom,msm8916-cci", .data = &cci_v1_data},
{ .compatible = "qcom,sdm845-cci", .data = &cci_v2_data},
{ .compatible = "qcom,sm8250-cci", .data = &cci_v2_data},
{ .compatible = "qcom,sm8450-cci", .data = &cci_v2_data},
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index fd70794bfcee..83909b02a03e 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -14,7 +14,7 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
-#include <linux/qcom-geni-se.h>
+#include <linux/soc/qcom/geni-se.h>
#include <linux/spinlock.h>
#define SE_I2C_TX_TRANS_LEN 0x26c
@@ -1025,7 +1025,7 @@ static const struct dev_pm_ops geni_i2c_pm_ops = {
NULL)
};
-const struct geni_i2c_desc i2c_master_hub = {
+static const struct geni_i2c_desc i2c_master_hub = {
.has_core_clk = true,
.icc_ddr = NULL,
.no_dma_support = true,
diff --git a/drivers/i2c/busses/i2c-st.c b/drivers/i2c/busses/i2c-st.c
index 88482316d22a..f823913b75a6 100644
--- a/drivers/i2c/busses/i2c-st.c
+++ b/drivers/i2c/busses/i2c-st.c
@@ -740,7 +740,6 @@ static int st_i2c_xfer(struct i2c_adapter *i2c_adap,
return (ret < 0) ? ret : i;
}
-#ifdef CONFIG_PM_SLEEP
static int st_i2c_suspend(struct device *dev)
{
struct st_i2c_dev *i2c_dev = dev_get_drvdata(dev);
@@ -762,11 +761,7 @@ static int st_i2c_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(st_i2c_pm, st_i2c_suspend, st_i2c_resume);
-#define ST_I2C_PM (&st_i2c_pm)
-#else
-#define ST_I2C_PM NULL
-#endif
+static DEFINE_SIMPLE_DEV_PM_OPS(st_i2c_pm, st_i2c_suspend, st_i2c_resume);
static u32 st_i2c_func(struct i2c_adapter *adap)
{
@@ -901,7 +896,7 @@ static struct platform_driver st_i2c_driver = {
.driver = {
.name = "st-i2c",
.of_match_table = st_i2c_match,
- .pm = ST_I2C_PM,
+ .pm = pm_sleep_ptr(&st_i2c_pm),
},
.probe = st_i2c_probe,
.remove = st_i2c_remove,
diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c
index bee5a2ef1f22..dbb792fc197e 100644
--- a/drivers/i2c/busses/i2c-xiic.c
+++ b/drivers/i2c/busses/i2c-xiic.c
@@ -32,6 +32,8 @@
#include <linux/pm_runtime.h>
#define DRIVER_NAME "xiic-i2c"
+#define DYNAMIC_MODE_READ_BROKEN_BIT BIT(0)
+#define SMBUS_BLOCK_READ_MIN_LEN 3
enum xilinx_i2c_state {
STATE_DONE,
@@ -44,6 +46,12 @@ enum xiic_endian {
BIG
};
+enum i2c_scl_freq {
+ REG_VALUES_100KHZ = 0,
+ REG_VALUES_400KHZ = 1,
+ REG_VALUES_1MHZ = 2
+};
+
/**
* struct xiic_i2c - Internal representation of the XIIC I2C bus
* @dev: Pointer to device structure
@@ -60,6 +68,12 @@ enum xiic_endian {
* @clk: Pointer to AXI4-lite input clock
* @state: See STATE_
* @singlemaster: Indicates bus is single master
+ * @dynamic: Mode of controller
+ * @prev_msg_tx: Previous message is Tx
+ * @quirks: To hold platform specific bug info
+ * @smbus_block_read: Flag to handle block read
+ * @input_clk: Input clock to I2C controller
+ * @i2c_clk: I2C SCL frequency
*/
struct xiic_i2c {
struct device *dev;
@@ -76,6 +90,39 @@ struct xiic_i2c {
struct clk *clk;
enum xilinx_i2c_state state;
bool singlemaster;
+ bool dynamic;
+ bool prev_msg_tx;
+ u32 quirks;
+ bool smbus_block_read;
+ unsigned long input_clk;
+ unsigned int i2c_clk;
+};
+
+struct xiic_version_data {
+ u32 quirks;
+};
+
+/**
+ * struct timing_regs - AXI I2C timing registers that depend on I2C spec
+ * @tsusta: setup time for a repeated START condition
+ * @tsusto: setup time for a STOP condition
+ * @thdsta: hold time for a repeated START condition
+ * @tsudat: setup time for data
+ * @tbuf: bus free time between STOP and START
+ */
+struct timing_regs {
+ unsigned int tsusta;
+ unsigned int tsusto;
+ unsigned int thdsta;
+ unsigned int tsudat;
+ unsigned int tbuf;
+};
+
+/* Reg values in ns derived from I2C spec and AXI I2C PG for different frequencies */
+static const struct timing_regs timing_reg_values[] = {
+ { 5700, 5000, 4300, 550, 5000 }, /* Reg values for 100KHz */
+ { 900, 900, 900, 400, 1600 }, /* Reg values for 400KHz */
+ { 380, 380, 380, 170, 620 }, /* Reg values for 1MHz */
};
#define XIIC_MSB_OFFSET 0
@@ -96,6 +143,19 @@ struct xiic_i2c {
#define XIIC_RFD_REG_OFFSET (0x20 + XIIC_REG_OFFSET) /* Rx FIFO Depth reg */
#define XIIC_GPO_REG_OFFSET (0x24 + XIIC_REG_OFFSET) /* Output Register */
+/*
+ * Timing register offsets from RegisterBase. These are used only for
+ * setting i2c clock frequency for the line.
+ */
+#define XIIC_TSUSTA_REG_OFFSET (0x28 + XIIC_REG_OFFSET) /* TSUSTA Register */
+#define XIIC_TSUSTO_REG_OFFSET (0x2C + XIIC_REG_OFFSET) /* TSUSTO Register */
+#define XIIC_THDSTA_REG_OFFSET (0x30 + XIIC_REG_OFFSET) /* THDSTA Register */
+#define XIIC_TSUDAT_REG_OFFSET (0x34 + XIIC_REG_OFFSET) /* TSUDAT Register */
+#define XIIC_TBUF_REG_OFFSET (0x38 + XIIC_REG_OFFSET) /* TBUF Register */
+#define XIIC_THIGH_REG_OFFSET (0x3C + XIIC_REG_OFFSET) /* THIGH Register */
+#define XIIC_TLOW_REG_OFFSET (0x40 + XIIC_REG_OFFSET) /* TLOW Register */
+#define XIIC_THDDAT_REG_OFFSET (0x44 + XIIC_REG_OFFSET) /* THDDAT Register */
+
/* Control Register masks */
#define XIIC_CR_ENABLE_DEVICE_MASK 0x01 /* Device enable = 1 */
#define XIIC_CR_TX_FIFO_RESET_MASK 0x02 /* Transmit FIFO reset=1 */
@@ -143,6 +203,9 @@ struct xiic_i2c {
#define XIIC_TX_DYN_START_MASK 0x0100 /* 1 = Set dynamic start */
#define XIIC_TX_DYN_STOP_MASK 0x0200 /* 1 = Set dynamic stop */
+/* Dynamic mode constants */
+#define MAX_READ_LENGTH_DYNAMIC 255 /* Max length for dynamic read */
+
/*
* The following constants define the register offsets for the Interrupt
* registers. There are some holes in the memory map for reserved addresses
@@ -275,12 +338,120 @@ static int xiic_clear_rx_fifo(struct xiic_i2c *i2c)
return 0;
}
+static int xiic_wait_tx_empty(struct xiic_i2c *i2c)
+{
+ u8 isr;
+ unsigned long timeout;
+
+ timeout = jiffies + XIIC_I2C_TIMEOUT;
+ for (isr = xiic_getreg32(i2c, XIIC_IISR_OFFSET);
+ !(isr & XIIC_INTR_TX_EMPTY_MASK);
+ isr = xiic_getreg32(i2c, XIIC_IISR_OFFSET)) {
+ if (time_after(jiffies, timeout)) {
+ dev_err(i2c->dev, "Timeout waiting at Tx empty\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * xiic_setclk - Sets the configured clock rate
+ * @i2c: Pointer to the xiic device structure
+ *
+ * The timing register values are calculated according to the input clock
+ * frequency and configured scl frequency. For details, please refer the
+ * AXI I2C PG and NXP I2C Spec.
+ * Supported frequencies are 100KHz, 400KHz and 1MHz.
+ *
+ * Return: 0 on success (Supported frequency selected or not configurable in SW)
+ * -EINVAL on failure (scl frequency not supported or THIGH is 0)
+ */
+static int xiic_setclk(struct xiic_i2c *i2c)
+{
+ unsigned int clk_in_mhz;
+ unsigned int index = 0;
+ u32 reg_val;
+
+ dev_dbg(i2c->adap.dev.parent,
+ "%s entry, i2c->input_clk: %ld, i2c->i2c_clk: %d\n",
+ __func__, i2c->input_clk, i2c->i2c_clk);
+
+ /* If not specified in DT, do not configure in SW. Rely only on Vivado design */
+ if (!i2c->i2c_clk || !i2c->input_clk)
+ return 0;
+
+ clk_in_mhz = DIV_ROUND_UP(i2c->input_clk, 1000000);
+
+ switch (i2c->i2c_clk) {
+ case I2C_MAX_FAST_MODE_PLUS_FREQ:
+ index = REG_VALUES_1MHZ;
+ break;
+ case I2C_MAX_FAST_MODE_FREQ:
+ index = REG_VALUES_400KHZ;
+ break;
+ case I2C_MAX_STANDARD_MODE_FREQ:
+ index = REG_VALUES_100KHZ;
+ break;
+ default:
+ dev_warn(i2c->adap.dev.parent, "Unsupported scl frequency\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Value to be stored in a register is the number of clock cycles required
+ * for the time duration. So the time is divided by the input clock time
+ * period to get the number of clock cycles required. Refer Xilinx AXI I2C
+ * PG document and I2C specification for further details.
+ */
+
+ /* THIGH - Depends on SCL clock frequency(i2c_clk) as below */
+ reg_val = (DIV_ROUND_UP(i2c->input_clk, 2 * i2c->i2c_clk)) - 7;
+ if (reg_val == 0)
+ return -EINVAL;
+
+ xiic_setreg32(i2c, XIIC_THIGH_REG_OFFSET, reg_val - 1);
+
+ /* TLOW - Value same as THIGH */
+ xiic_setreg32(i2c, XIIC_TLOW_REG_OFFSET, reg_val - 1);
+
+ /* TSUSTA */
+ reg_val = (timing_reg_values[index].tsusta * clk_in_mhz) / 1000;
+ xiic_setreg32(i2c, XIIC_TSUSTA_REG_OFFSET, reg_val - 1);
+
+ /* TSUSTO */
+ reg_val = (timing_reg_values[index].tsusto * clk_in_mhz) / 1000;
+ xiic_setreg32(i2c, XIIC_TSUSTO_REG_OFFSET, reg_val - 1);
+
+ /* THDSTA */
+ reg_val = (timing_reg_values[index].thdsta * clk_in_mhz) / 1000;
+ xiic_setreg32(i2c, XIIC_THDSTA_REG_OFFSET, reg_val - 1);
+
+ /* TSUDAT */
+ reg_val = (timing_reg_values[index].tsudat * clk_in_mhz) / 1000;
+ xiic_setreg32(i2c, XIIC_TSUDAT_REG_OFFSET, reg_val - 1);
+
+ /* TBUF */
+ reg_val = (timing_reg_values[index].tbuf * clk_in_mhz) / 1000;
+ xiic_setreg32(i2c, XIIC_TBUF_REG_OFFSET, reg_val - 1);
+
+ /* THDDAT */
+ xiic_setreg32(i2c, XIIC_THDDAT_REG_OFFSET, 1);
+
+ return 0;
+}
+
static int xiic_reinit(struct xiic_i2c *i2c)
{
int ret;
xiic_setreg32(i2c, XIIC_RESETR_OFFSET, XIIC_RESET_MASK);
+ ret = xiic_setclk(i2c);
+ if (ret)
+ return ret;
+
/* Set receive Fifo depth to maximum (zero based). */
xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, IIC_RX_FIFO_DEPTH - 1);
@@ -314,15 +485,72 @@ static void xiic_deinit(struct xiic_i2c *i2c)
xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, cr & ~XIIC_CR_ENABLE_DEVICE_MASK);
}
+static void xiic_smbus_block_read_setup(struct xiic_i2c *i2c)
+{
+ u8 rxmsg_len, rfd_set = 0;
+
+ /*
+ * Clear the I2C_M_RECV_LEN flag to avoid setting
+ * message length again
+ */
+ i2c->rx_msg->flags &= ~I2C_M_RECV_LEN;
+
+ /* Set smbus_block_read flag to identify in isr */
+ i2c->smbus_block_read = true;
+
+ /* Read byte from rx fifo and set message length */
+ rxmsg_len = xiic_getreg8(i2c, XIIC_DRR_REG_OFFSET);
+
+ i2c->rx_msg->buf[i2c->rx_pos++] = rxmsg_len;
+
+ /* Check if received length is valid */
+ if (rxmsg_len <= I2C_SMBUS_BLOCK_MAX) {
+ /* Set Receive fifo depth */
+ if (rxmsg_len > IIC_RX_FIFO_DEPTH) {
+ /*
+ * When Rx msg len greater than or equal to Rx fifo capacity
+ * Receive fifo depth should set to Rx fifo capacity minus 1
+ */
+ rfd_set = IIC_RX_FIFO_DEPTH - 1;
+ i2c->rx_msg->len = rxmsg_len + 1;
+ } else if ((rxmsg_len == 1) ||
+ (rxmsg_len == 0)) {
+ /*
+ * Minimum of 3 bytes required to exit cleanly. 1 byte
+ * already received, Second byte is being received. Have
+ * to set NACK in read_rx before receiving the last byte
+ */
+ rfd_set = 0;
+ i2c->rx_msg->len = SMBUS_BLOCK_READ_MIN_LEN;
+ } else {
+ /*
+ * When Rx msg len less than Rx fifo capacity
+ * Receive fifo depth should set to Rx msg len minus 2
+ */
+ rfd_set = rxmsg_len - 2;
+ i2c->rx_msg->len = rxmsg_len + 1;
+ }
+ xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, rfd_set);
+
+ return;
+ }
+
+ /* Invalid message length, trigger STATE_ERROR with tx_msg_len in ISR */
+ i2c->tx_msg->len = 3;
+ i2c->smbus_block_read = false;
+ dev_err(i2c->adap.dev.parent, "smbus_block_read Invalid msg length\n");
+}
+
static void xiic_read_rx(struct xiic_i2c *i2c)
{
- u8 bytes_in_fifo;
+ u8 bytes_in_fifo, cr = 0, bytes_to_read = 0;
+ u32 bytes_rem = 0;
int i;
bytes_in_fifo = xiic_getreg8(i2c, XIIC_RFO_REG_OFFSET) + 1;
dev_dbg(i2c->adap.dev.parent,
- "%s entry, bytes in fifo: %d, msg: %d, SR: 0x%x, CR: 0x%x\n",
+ "%s entry, bytes in fifo: %d, rem: %d, SR: 0x%x, CR: 0x%x\n",
__func__, bytes_in_fifo, xiic_rx_space(i2c),
xiic_getreg8(i2c, XIIC_SR_REG_OFFSET),
xiic_getreg8(i2c, XIIC_CR_REG_OFFSET));
@@ -330,13 +558,58 @@ static void xiic_read_rx(struct xiic_i2c *i2c)
if (bytes_in_fifo > xiic_rx_space(i2c))
bytes_in_fifo = xiic_rx_space(i2c);
- for (i = 0; i < bytes_in_fifo; i++)
+ bytes_to_read = bytes_in_fifo;
+
+ if (!i2c->dynamic) {
+ bytes_rem = xiic_rx_space(i2c) - bytes_in_fifo;
+
+ /* Set msg length if smbus_block_read */
+ if (i2c->rx_msg->flags & I2C_M_RECV_LEN) {
+ xiic_smbus_block_read_setup(i2c);
+ return;
+ }
+
+ if (bytes_rem > IIC_RX_FIFO_DEPTH) {
+ bytes_to_read = bytes_in_fifo;
+ } else if (bytes_rem > 1) {
+ bytes_to_read = bytes_rem - 1;
+ } else if (bytes_rem == 1) {
+ bytes_to_read = 1;
+ /* Set NACK in CR to indicate slave transmitter */
+ cr = xiic_getreg8(i2c, XIIC_CR_REG_OFFSET);
+ xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, cr |
+ XIIC_CR_NO_ACK_MASK);
+ } else if (bytes_rem == 0) {
+ bytes_to_read = bytes_in_fifo;
+
+ /* Generate stop on the bus if it is last message */
+ if (i2c->nmsgs == 1) {
+ cr = xiic_getreg8(i2c, XIIC_CR_REG_OFFSET);
+ xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, cr &
+ ~XIIC_CR_MSMS_MASK);
+ }
+
+ /* Make TXACK=0, clean up for next transaction */
+ cr = xiic_getreg8(i2c, XIIC_CR_REG_OFFSET);
+ xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, cr &
+ ~XIIC_CR_NO_ACK_MASK);
+ }
+ }
+
+ /* Read the fifo */
+ for (i = 0; i < bytes_to_read; i++) {
i2c->rx_msg->buf[i2c->rx_pos++] =
xiic_getreg8(i2c, XIIC_DRR_REG_OFFSET);
+ }
- xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET,
- (xiic_rx_space(i2c) > IIC_RX_FIFO_DEPTH) ?
- IIC_RX_FIFO_DEPTH - 1 : xiic_rx_space(i2c) - 1);
+ if (i2c->dynamic) {
+ u8 bytes;
+
+ /* Receive remaining bytes if less than fifo depth */
+ bytes = min_t(u8, xiic_rx_space(i2c), IIC_RX_FIFO_DEPTH);
+ bytes--;
+ xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, bytes);
+ }
}
static int xiic_tx_fifo_space(struct xiic_i2c *i2c)
@@ -360,7 +633,22 @@ static void xiic_fill_tx_fifo(struct xiic_i2c *i2c)
if (!xiic_tx_space(i2c) && i2c->nmsgs == 1) {
/* last message in transfer -> STOP */
- data |= XIIC_TX_DYN_STOP_MASK;
+ if (i2c->dynamic) {
+ data |= XIIC_TX_DYN_STOP_MASK;
+ } else {
+ u8 cr;
+ int status;
+
+ /* Wait till FIFO is empty so STOP is sent last */
+ status = xiic_wait_tx_empty(i2c);
+ if (status)
+ return;
+
+ /* Write to CR to stop */
+ cr = xiic_getreg8(i2c, XIIC_CR_REG_OFFSET);
+ xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, cr &
+ ~XIIC_CR_MSMS_MASK);
+ }
dev_dbg(i2c->adap.dev.parent, "%s TX STOP\n", __func__);
}
xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, data);
@@ -401,7 +689,9 @@ static irqreturn_t xiic_process(int irq, void *dev_id)
dev_dbg(i2c->adap.dev.parent, "%s: SR: 0x%x, msg: %p, nmsgs: %d\n",
__func__, xiic_getreg8(i2c, XIIC_SR_REG_OFFSET),
i2c->tx_msg, i2c->nmsgs);
-
+ dev_dbg(i2c->adap.dev.parent, "%s, ISR: 0x%x, CR: 0x%x\n",
+ __func__, xiic_getreg32(i2c, XIIC_IISR_OFFSET),
+ xiic_getreg8(i2c, XIIC_CR_REG_OFFSET));
/* Service requesting interrupt */
if ((pend & XIIC_INTR_ARB_LOST_MASK) ||
@@ -512,6 +802,12 @@ static irqreturn_t xiic_process(int irq, void *dev_id)
/* The bus is not busy, disable BusNotBusy interrupt */
xiic_irq_dis(i2c, XIIC_INTR_BNB_MASK);
+ if (i2c->tx_msg && i2c->smbus_block_read) {
+ i2c->smbus_block_read = false;
+ /* Set requested message len=1 to indicate STATE_DONE */
+ i2c->tx_msg->len = 1;
+ }
+
if (!i2c->tx_msg)
goto out;
@@ -579,31 +875,113 @@ static int xiic_busy(struct xiic_i2c *i2c)
static void xiic_start_recv(struct xiic_i2c *i2c)
{
u16 rx_watermark;
+ u8 cr = 0, rfd_set = 0;
struct i2c_msg *msg = i2c->rx_msg = i2c->tx_msg;
- /* Clear and enable Rx full interrupt. */
- xiic_irq_clr_en(i2c, XIIC_INTR_RX_FULL_MASK | XIIC_INTR_TX_ERROR_MASK);
+ dev_dbg(i2c->adap.dev.parent, "%s entry, ISR: 0x%x, CR: 0x%x\n",
+ __func__, xiic_getreg32(i2c, XIIC_IISR_OFFSET),
+ xiic_getreg8(i2c, XIIC_CR_REG_OFFSET));
- /* we want to get all but last byte, because the TX_ERROR IRQ is used
- * to inidicate error ACK on the address, and negative ack on the last
- * received byte, so to not mix them receive all but last.
- * In the case where there is only one byte to receive
- * we can check if ERROR and RX full is set at the same time
- */
- rx_watermark = msg->len;
- if (rx_watermark > IIC_RX_FIFO_DEPTH)
- rx_watermark = IIC_RX_FIFO_DEPTH;
- xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, (u8)(rx_watermark - 1));
+ /* Disable Tx interrupts */
+ xiic_irq_dis(i2c, XIIC_INTR_TX_HALF_MASK | XIIC_INTR_TX_EMPTY_MASK);
+
+ if (i2c->dynamic) {
+ u8 bytes;
+ u16 val;
+
+ /* Clear and enable Rx full interrupt. */
+ xiic_irq_clr_en(i2c, XIIC_INTR_RX_FULL_MASK |
+ XIIC_INTR_TX_ERROR_MASK);
+
+ /*
+ * We want to get all but last byte, because the TX_ERROR IRQ
+ * is used to indicate error ACK on the address, and
+ * negative ack on the last received byte, so to not mix
+ * them receive all but last.
+ * In the case where there is only one byte to receive
+ * we can check if ERROR and RX full is set at the same time
+ */
+ rx_watermark = msg->len;
+ bytes = min_t(u8, rx_watermark, IIC_RX_FIFO_DEPTH);
+
+ if (rx_watermark > 0)
+ bytes--;
+ xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, bytes);
- if (!(msg->flags & I2C_M_NOSTART))
/* write the address */
xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET,
- i2c_8bit_addr_from_msg(msg) | XIIC_TX_DYN_START_MASK);
+ i2c_8bit_addr_from_msg(msg) |
+ XIIC_TX_DYN_START_MASK);
+
+ /* If last message, include dynamic stop bit with length */
+ val = (i2c->nmsgs == 1) ? XIIC_TX_DYN_STOP_MASK : 0;
+ val |= msg->len;
+
+ xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, val);
+
+ xiic_irq_clr_en(i2c, XIIC_INTR_BNB_MASK);
+ } else {
+ /*
+ * If previous message is Tx, make sure that Tx FIFO is empty
+ * before starting a new transfer as the repeated start in
+ * standard mode can corrupt the transaction if there are
+ * still bytes to be transmitted in FIFO
+ */
+ if (i2c->prev_msg_tx) {
+ int status;
+
+ status = xiic_wait_tx_empty(i2c);
+ if (status)
+ return;
+ }
- xiic_irq_clr_en(i2c, XIIC_INTR_BNB_MASK);
+ cr = xiic_getreg8(i2c, XIIC_CR_REG_OFFSET);
- xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET,
- msg->len | ((i2c->nmsgs == 1) ? XIIC_TX_DYN_STOP_MASK : 0));
+ /* Set Receive fifo depth */
+ rx_watermark = msg->len;
+ if (rx_watermark > IIC_RX_FIFO_DEPTH) {
+ rfd_set = IIC_RX_FIFO_DEPTH - 1;
+ } else if (rx_watermark == 1) {
+ rfd_set = rx_watermark - 1;
+
+ /* Set No_ACK, except for smbus_block_read */
+ if (!(i2c->rx_msg->flags & I2C_M_RECV_LEN)) {
+ /* Handle single byte transfer separately */
+ cr |= XIIC_CR_NO_ACK_MASK;
+ }
+ } else if (rx_watermark == 0) {
+ rfd_set = rx_watermark;
+ } else {
+ rfd_set = rx_watermark - 2;
+ }
+ /* Check if RSTA should be set */
+ if (cr & XIIC_CR_MSMS_MASK) {
+ /* Already a master, RSTA should be set */
+ xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, (cr |
+ XIIC_CR_REPEATED_START_MASK) &
+ ~(XIIC_CR_DIR_IS_TX_MASK));
+ }
+
+ xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, rfd_set);
+
+ /* Clear and enable Rx full and transmit complete interrupts */
+ xiic_irq_clr_en(i2c, XIIC_INTR_RX_FULL_MASK |
+ XIIC_INTR_TX_ERROR_MASK);
+
+ /* Write the address */
+ xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET,
+ i2c_8bit_addr_from_msg(msg));
+
+ /* Write to Control Register,to start transaction in Rx mode */
+ if ((cr & XIIC_CR_MSMS_MASK) == 0) {
+ xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, (cr |
+ XIIC_CR_MSMS_MASK)
+ & ~(XIIC_CR_DIR_IS_TX_MASK));
+ }
+ dev_dbg(i2c->adap.dev.parent, "%s end, ISR: 0x%x, CR: 0x%x\n",
+ __func__, xiic_getreg32(i2c, XIIC_IISR_OFFSET),
+ xiic_getreg8(i2c, XIIC_CR_REG_OFFSET));
+ }
if (i2c->nmsgs == 1)
/* very last, enable bus not busy as well */
@@ -611,10 +989,17 @@ static void xiic_start_recv(struct xiic_i2c *i2c)
/* the message is tx:ed */
i2c->tx_pos = msg->len;
+
+ /* Enable interrupts */
+ xiic_setreg32(i2c, XIIC_DGIER_OFFSET, XIIC_GINTR_ENABLE_MASK);
+
+ i2c->prev_msg_tx = false;
}
static void xiic_start_send(struct xiic_i2c *i2c)
{
+ u8 cr = 0;
+ u16 data;
struct i2c_msg *msg = i2c->tx_msg;
dev_dbg(i2c->adap.dev.parent, "%s entry, msg: %p, len: %d",
@@ -623,24 +1008,70 @@ static void xiic_start_send(struct xiic_i2c *i2c)
__func__, xiic_getreg32(i2c, XIIC_IISR_OFFSET),
xiic_getreg8(i2c, XIIC_CR_REG_OFFSET));
- if (!(msg->flags & I2C_M_NOSTART)) {
+ if (i2c->dynamic) {
/* write the address */
- u16 data = i2c_8bit_addr_from_msg(msg) |
- XIIC_TX_DYN_START_MASK;
- if ((i2c->nmsgs == 1) && msg->len == 0)
+ data = i2c_8bit_addr_from_msg(msg) |
+ XIIC_TX_DYN_START_MASK;
+
+ if (i2c->nmsgs == 1 && msg->len == 0)
/* no data and last message -> add STOP */
data |= XIIC_TX_DYN_STOP_MASK;
xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, data);
- }
- /* Clear any pending Tx empty, Tx Error and then enable them. */
- xiic_irq_clr_en(i2c, XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_ERROR_MASK |
- XIIC_INTR_BNB_MASK |
- ((i2c->nmsgs > 1 || xiic_tx_space(i2c)) ?
- XIIC_INTR_TX_HALF_MASK : 0));
+ /* Clear any pending Tx empty, Tx Error and then enable them */
+ xiic_irq_clr_en(i2c, XIIC_INTR_TX_EMPTY_MASK |
+ XIIC_INTR_TX_ERROR_MASK |
+ XIIC_INTR_BNB_MASK |
+ ((i2c->nmsgs > 1 || xiic_tx_space(i2c)) ?
+ XIIC_INTR_TX_HALF_MASK : 0));
+
+ xiic_fill_tx_fifo(i2c);
+ } else {
+ /*
+ * If previous message is Tx, make sure that Tx FIFO is empty
+ * before starting a new transfer as the repeated start in
+ * standard mode can corrupt the transaction if there are
+ * still bytes to be transmitted in FIFO
+ */
+ if (i2c->prev_msg_tx) {
+ int status;
+
+ status = xiic_wait_tx_empty(i2c);
+ if (status)
+ return;
+ }
+ /* Check if RSTA should be set */
+ cr = xiic_getreg8(i2c, XIIC_CR_REG_OFFSET);
+ if (cr & XIIC_CR_MSMS_MASK) {
+ /* Already a master, RSTA should be set */
+ xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, (cr |
+ XIIC_CR_REPEATED_START_MASK |
+ XIIC_CR_DIR_IS_TX_MASK) &
+ ~(XIIC_CR_NO_ACK_MASK));
+ }
+
+ /* Write address to FIFO */
+ data = i2c_8bit_addr_from_msg(msg);
+ xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, data);
+
+ /* Fill fifo */
+ xiic_fill_tx_fifo(i2c);
- xiic_fill_tx_fifo(i2c);
+ if ((cr & XIIC_CR_MSMS_MASK) == 0) {
+ /* Start Tx by writing to CR */
+ cr = xiic_getreg8(i2c, XIIC_CR_REG_OFFSET);
+ xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, cr |
+ XIIC_CR_MSMS_MASK |
+ XIIC_CR_DIR_IS_TX_MASK);
+ }
+
+ /* Clear any pending Tx empty, Tx Error and then enable them */
+ xiic_irq_clr_en(i2c, XIIC_INTR_TX_EMPTY_MASK |
+ XIIC_INTR_TX_ERROR_MASK |
+ XIIC_INTR_BNB_MASK);
+ }
+ i2c->prev_msg_tx = true;
}
static void __xiic_start_xfer(struct xiic_i2c *i2c)
@@ -666,7 +1097,8 @@ static void __xiic_start_xfer(struct xiic_i2c *i2c)
static int xiic_start_xfer(struct xiic_i2c *i2c, struct i2c_msg *msgs, int num)
{
- int ret;
+ bool broken_read, max_read_len, smbus_blk_read;
+ int ret, count;
mutex_lock(&i2c->lock);
@@ -679,6 +1111,34 @@ static int xiic_start_xfer(struct xiic_i2c *i2c, struct i2c_msg *msgs, int num)
i2c->nmsgs = num;
init_completion(&i2c->completion);
+ /* Decide standard mode or Dynamic mode */
+ i2c->dynamic = true;
+
+ /* Initialize prev message type */
+ i2c->prev_msg_tx = false;
+
+ /*
+ * Scan through nmsgs, use dynamic mode when none of the below three
+ * conditions occur. We need standard mode even if one condition holds
+ * true in the entire array of messages in a single transfer.
+ * If read transaction as dynamic mode is broken for delayed reads
+ * in xlnx,axi-iic-2.0 / xlnx,xps-iic-2.00.a IP versions.
+ * If read length is > 255 bytes.
+ * If smbus_block_read transaction.
+ */
+ for (count = 0; count < i2c->nmsgs; count++) {
+ broken_read = (i2c->quirks & DYNAMIC_MODE_READ_BROKEN_BIT) &&
+ (i2c->tx_msg[count].flags & I2C_M_RD);
+ max_read_len = (i2c->tx_msg[count].flags & I2C_M_RD) &&
+ (i2c->tx_msg[count].len > MAX_READ_LENGTH_DYNAMIC);
+ smbus_blk_read = (i2c->tx_msg[count].flags & I2C_M_RECV_LEN);
+
+ if (broken_read || max_read_len || smbus_blk_read) {
+ i2c->dynamic = false;
+ break;
+ }
+ }
+
ret = xiic_reinit(i2c);
if (!ret)
__xiic_start_xfer(i2c);
@@ -714,10 +1174,6 @@ static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
i2c->rx_msg = NULL;
i2c->nmsgs = 0;
err = -ETIMEDOUT;
- } else if (err < 0) { /* Completion error */
- i2c->tx_msg = NULL;
- i2c->rx_msg = NULL;
- i2c->nmsgs = 0;
} else {
err = (i2c->state == STATE_DONE) ? num : -EIO;
}
@@ -729,7 +1185,7 @@ static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
static u32 xiic_func(struct i2c_adapter *adap)
{
- return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_BLOCK_DATA;
}
static const struct i2c_algorithm xiic_algorithm = {
@@ -737,21 +1193,30 @@ static const struct i2c_algorithm xiic_algorithm = {
.functionality = xiic_func,
};
-static const struct i2c_adapter_quirks xiic_quirks = {
- .max_read_len = 255,
-};
-
static const struct i2c_adapter xiic_adapter = {
.owner = THIS_MODULE,
.class = I2C_CLASS_DEPRECATED,
.algo = &xiic_algorithm,
- .quirks = &xiic_quirks,
};
+static const struct xiic_version_data xiic_2_00 = {
+ .quirks = DYNAMIC_MODE_READ_BROKEN_BIT,
+};
+
+#if defined(CONFIG_OF)
+static const struct of_device_id xiic_of_match[] = {
+ { .compatible = "xlnx,xps-iic-2.00.a", .data = &xiic_2_00 },
+ { .compatible = "xlnx,axi-iic-2.1", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, xiic_of_match);
+#endif
+
static int xiic_i2c_probe(struct platform_device *pdev)
{
struct xiic_i2c *i2c;
struct xiic_i2c_platform_data *pdata;
+ const struct of_device_id *match;
struct resource *res;
int ret, irq;
u8 i;
@@ -761,6 +1226,13 @@ static int xiic_i2c_probe(struct platform_device *pdev)
if (!i2c)
return -ENOMEM;
+ match = of_match_node(xiic_of_match, pdev->dev.of_node);
+ if (match && match->data) {
+ const struct xiic_version_data *data = match->data;
+
+ i2c->quirks = data->quirks;
+ }
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
i2c->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(i2c->base))
@@ -798,6 +1270,15 @@ static int xiic_i2c_probe(struct platform_device *pdev)
pm_runtime_use_autosuspend(i2c->dev);
pm_runtime_set_active(i2c->dev);
pm_runtime_enable(i2c->dev);
+
+ /* SCL frequency configuration */
+ i2c->input_clk = clk_get_rate(i2c->clk);
+ ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
+ &i2c->i2c_clk);
+ /* If clock-frequency not specified in DT, do not configure in SW */
+ if (ret || i2c->i2c_clk > I2C_MAX_FAST_MODE_PLUS_FREQ)
+ i2c->i2c_clk = 0;
+
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
xiic_process, IRQF_ONESHOT,
pdev->name, i2c);
@@ -841,6 +1322,9 @@ static int xiic_i2c_probe(struct platform_device *pdev)
i2c_new_client_device(&i2c->adap, pdata->devices + i);
}
+ dev_dbg(&pdev->dev, "mmio %08lx irq %d scl clock frequency %d\n",
+ (unsigned long)res->start, irq, i2c->i2c_clk);
+
return 0;
err_clk_dis:
@@ -875,14 +1359,6 @@ static int xiic_i2c_remove(struct platform_device *pdev)
return 0;
}
-#if defined(CONFIG_OF)
-static const struct of_device_id xiic_of_match[] = {
- { .compatible = "xlnx,xps-iic-2.00.a", },
- {},
-};
-MODULE_DEVICE_TABLE(of, xiic_of_match);
-#endif
-
static int __maybe_unused xiic_i2c_runtime_suspend(struct device *dev)
{
struct xiic_i2c *i2c = dev_get_drvdata(dev);
diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c
index b47e255fc6f1..cb5fa971d67e 100644
--- a/drivers/i2c/i2c-core-base.c
+++ b/drivers/i2c/i2c-core-base.c
@@ -34,6 +34,7 @@
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/pinctrl/consumer.h>
+#include <linux/pinctrl/devinfo.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
#include <linux/pm_wakeirq.h>
@@ -136,9 +137,9 @@ static int i2c_device_match(struct device *dev, struct device_driver *drv)
return 0;
}
-static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int i2c_device_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct i2c_client *client = to_i2c_client(dev);
+ const struct i2c_client *client = to_i2c_client(dev);
int rc;
rc = of_device_uevent_modalias(dev, env);
@@ -282,7 +283,9 @@ static void i2c_gpio_init_pinctrl_recovery(struct i2c_adapter *adap)
{
struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
struct device *dev = &adap->dev;
- struct pinctrl *p = bri->pinctrl;
+ struct pinctrl *p = bri->pinctrl ?: dev_pinctrl(dev->parent);
+
+ bri->pinctrl = p;
/*
* we can't change states without pinctrl, so remove the states if
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index ab0adaa130da..107623c4cc14 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -653,12 +653,12 @@ static int i2cdev_attach_adapter(struct device *dev, void *dummy)
int res;
if (dev->type != &i2c_adapter_type)
- return 0;
+ return NOTIFY_DONE;
adap = to_i2c_adapter(dev);
i2c_dev = get_free_i2c_dev(adap);
if (IS_ERR(i2c_dev))
- return PTR_ERR(i2c_dev);
+ return NOTIFY_DONE;
cdev_init(&i2c_dev->cdev, &i2cdev_fops);
i2c_dev->cdev.owner = THIS_MODULE;
@@ -678,11 +678,11 @@ static int i2cdev_attach_adapter(struct device *dev, void *dummy)
goto err_put_i2c_dev;
pr_debug("adapter [%s] registered as minor %d\n", adap->name, adap->nr);
- return 0;
+ return NOTIFY_OK;
err_put_i2c_dev:
put_i2c_dev(i2c_dev, false);
- return res;
+ return NOTIFY_DONE;
}
static int i2cdev_detach_adapter(struct device *dev, void *dummy)
@@ -691,17 +691,17 @@ static int i2cdev_detach_adapter(struct device *dev, void *dummy)
struct i2c_dev *i2c_dev;
if (dev->type != &i2c_adapter_type)
- return 0;
+ return NOTIFY_DONE;
adap = to_i2c_adapter(dev);
i2c_dev = i2c_dev_get_by_minor(adap->nr);
if (!i2c_dev) /* attach_adapter must have failed */
- return 0;
+ return NOTIFY_DONE;
put_i2c_dev(i2c_dev, true);
pr_debug("adapter [%s] unregistered\n", adap->name);
- return 0;
+ return NOTIFY_OK;
}
static int i2cdev_notifier_call(struct notifier_block *nb, unsigned long action,
@@ -716,7 +716,7 @@ static int i2cdev_notifier_call(struct notifier_block *nb, unsigned long action,
return i2cdev_detach_adapter(dev, NULL);
}
- return 0;
+ return NOTIFY_DONE;
}
static struct notifier_block i2cdev_notifier = {
diff --git a/drivers/i3c/device.c b/drivers/i3c/device.c
index 9762630b917e..1a6a8703dbc3 100644
--- a/drivers/i3c/device.c
+++ b/drivers/i3c/device.c
@@ -78,7 +78,7 @@ EXPORT_SYMBOL_GPL(i3c_device_do_setdasa);
*
* Retrieve I3C dev info.
*/
-void i3c_device_get_info(struct i3c_device *dev,
+void i3c_device_get_info(const struct i3c_device *dev,
struct i3c_device_info *info)
{
if (!info)
@@ -209,18 +209,6 @@ struct device *i3cdev_to_dev(struct i3c_device *i3cdev)
EXPORT_SYMBOL_GPL(i3cdev_to_dev);
/**
- * dev_to_i3cdev() - Returns the I3C device containing @dev
- * @dev: device object
- *
- * Return: a pointer to an I3C device object.
- */
-struct i3c_device *dev_to_i3cdev(struct device *dev)
-{
- return container_of(dev, struct i3c_device, dev);
-}
-EXPORT_SYMBOL_GPL(dev_to_i3cdev);
-
-/**
* i3c_device_match_id() - Returns the i3c_device_id entry matching @i3cdev
* @i3cdev: I3C device
* @id_table: I3C device match table
diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
index d7e6f6c99aea..54e4c34b4a22 100644
--- a/drivers/i3c/master.c
+++ b/drivers/i3c/master.c
@@ -273,9 +273,9 @@ static struct attribute *i3c_device_attrs[] = {
};
ATTRIBUTE_GROUPS(i3c_device);
-static int i3c_device_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int i3c_device_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct i3c_device *i3cdev = dev_to_i3cdev(dev);
+ const struct i3c_device *i3cdev = dev_to_i3cdev(dev);
struct i3c_device_info devinfo;
u16 manuf, part, ext;
@@ -1438,6 +1438,7 @@ static int i3c_master_early_i3c_dev_add(struct i3c_master_controller *master,
{
struct i3c_device_info info = {
.static_addr = boardinfo->static_addr,
+ .pid = boardinfo->pid,
};
struct i3c_dev_desc *i3cdev;
int ret;
diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c
index 51a8608203de..48954d3e6571 100644
--- a/drivers/i3c/master/dw-i3c-master.c
+++ b/drivers/i3c/master/dw-i3c-master.c
@@ -531,7 +531,7 @@ static int dw_i3c_clk_cfg(struct dw_i3c_master *master)
if (hcnt < SCL_I3C_TIMING_CNT_MIN)
hcnt = SCL_I3C_TIMING_CNT_MIN;
- lcnt = DIV_ROUND_UP(core_rate, I3C_BUS_TYP_I3C_SCL_RATE) - hcnt;
+ lcnt = DIV_ROUND_UP(core_rate, master->base.bus.scl_rate.i3c) - hcnt;
if (lcnt < SCL_I3C_TIMING_CNT_MIN)
lcnt = SCL_I3C_TIMING_CNT_MIN;
@@ -541,7 +541,8 @@ static int dw_i3c_clk_cfg(struct dw_i3c_master *master)
if (!(readl(master->regs + DEVICE_CTRL) & DEV_CTRL_I2C_SLAVE_PRESENT))
writel(BUS_I3C_MST_FREE(lcnt), master->regs + BUS_FREE_TIMING);
- lcnt = DIV_ROUND_UP(I3C_BUS_TLOW_OD_MIN_NS, core_period);
+ lcnt = max_t(u8,
+ DIV_ROUND_UP(I3C_BUS_TLOW_OD_MIN_NS, core_period), lcnt);
scl_timing = SCL_I3C_TIMING_HCNT(hcnt) | SCL_I3C_TIMING_LCNT(lcnt);
writel(scl_timing, master->regs + SCL_I3C_OD_TIMING);
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index 03ac410c162e..b6b45d359f28 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -380,7 +380,7 @@ config IIO_ST_ACCEL_3AXIS
select IIO_TRIGGERED_BUFFER if (IIO_BUFFER)
help
Say yes here to build support for STMicroelectronics accelerometers:
- LSM303DLH, LSM303DLHC, LIS3DH, LSM330D, LSM330DL, LSM330DLC,
+ LSM303C, LSM303DLH, LSM303DLHC, LIS3DH, LSM330D, LSM330DL, LSM330DLC,
LIS331DLH, LSM303DL, LSM303DLM, LSM330, LIS2DH12, H3LIS331DL,
LNG2DM, LIS3DE, LIS2DE12, LIS2HH12
diff --git a/drivers/iio/accel/bma400.h b/drivers/iio/accel/bma400.h
index 36edbaff4f7f..932358b45f17 100644
--- a/drivers/iio/accel/bma400.h
+++ b/drivers/iio/accel/bma400.h
@@ -141,10 +141,6 @@
#define BMA400_SCALE_MIN 9577
#define BMA400_SCALE_MAX 76617
-#define BMA400_NUM_REGULATORS 2
-#define BMA400_VDD_REGULATOR 0
-#define BMA400_VDDIO_REGULATOR 1
-
extern const struct regmap_config bma400_regmap_config;
int bma400_probe(struct device *dev, struct regmap *regmap, int irq,
diff --git a/drivers/iio/accel/bma400_core.c b/drivers/iio/accel/bma400_core.c
index b612d0146d4d..623f37cbaf50 100644
--- a/drivers/iio/accel/bma400_core.c
+++ b/drivers/iio/accel/bma400_core.c
@@ -98,7 +98,6 @@ enum bma400_activity {
struct bma400_data {
struct device *dev;
struct regmap *regmap;
- struct regulator_bulk_data regulators[BMA400_NUM_REGULATORS];
struct mutex mutex; /* data register lock */
struct iio_mount_matrix orientation;
enum bma400_power_mode power_mode;
@@ -832,13 +831,6 @@ static void bma400_init_tables(void)
}
}
-static void bma400_regulators_disable(void *data_ptr)
-{
- struct bma400_data *data = data_ptr;
-
- regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators);
-}
-
static void bma400_power_disable(void *data_ptr)
{
struct bma400_data *data = data_ptr;
@@ -868,30 +860,17 @@ static enum iio_modifier bma400_act_to_mod(enum bma400_activity activity)
static int bma400_init(struct bma400_data *data)
{
+ static const char * const regulator_names[] = { "vdd", "vddio" };
unsigned int val;
int ret;
- data->regulators[BMA400_VDD_REGULATOR].supply = "vdd";
- data->regulators[BMA400_VDDIO_REGULATOR].supply = "vddio";
- ret = devm_regulator_bulk_get(data->dev,
- ARRAY_SIZE(data->regulators),
- data->regulators);
+ ret = devm_regulator_bulk_get_enable(data->dev,
+ ARRAY_SIZE(regulator_names),
+ regulator_names);
if (ret)
return dev_err_probe(data->dev, ret, "Failed to get regulators: %d\n",
ret);
- ret = regulator_bulk_enable(ARRAY_SIZE(data->regulators),
- data->regulators);
- if (ret) {
- dev_err(data->dev, "Failed to enable regulators: %d\n",
- ret);
- return ret;
- }
-
- ret = devm_add_action_or_reset(data->dev, bma400_regulators_disable, data);
- if (ret)
- return ret;
-
/* Try to read chip_id register. It must return 0x90. */
ret = regmap_read(data->regmap, BMA400_CHIP_ID_REG, &val);
if (ret) {
diff --git a/drivers/iio/accel/mma9551_core.c b/drivers/iio/accel/mma9551_core.c
index 64ca7d7a9673..b898f865fb87 100644
--- a/drivers/iio/accel/mma9551_core.c
+++ b/drivers/iio/accel/mma9551_core.c
@@ -296,9 +296,12 @@ int mma9551_read_config_word(struct i2c_client *client, u8 app_id,
ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_CONFIG,
reg, NULL, 0, (u8 *)&v, 2);
+ if (ret < 0)
+ return ret;
+
*val = be16_to_cpu(v);
- return ret;
+ return 0;
}
EXPORT_SYMBOL_NS(mma9551_read_config_word, IIO_MMA9551);
@@ -354,9 +357,12 @@ int mma9551_read_status_word(struct i2c_client *client, u8 app_id,
ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS,
reg, NULL, 0, (u8 *)&v, 2);
+ if (ret < 0)
+ return ret;
+
*val = be16_to_cpu(v);
- return ret;
+ return 0;
}
EXPORT_SYMBOL_NS(mma9551_read_status_word, IIO_MMA9551);
diff --git a/drivers/iio/accel/st_accel.h b/drivers/iio/accel/st_accel.h
index 5b0f54e33d9e..56ed0c776d4a 100644
--- a/drivers/iio/accel/st_accel.h
+++ b/drivers/iio/accel/st_accel.h
@@ -37,6 +37,7 @@
#define LIS2DE12_ACCEL_DEV_NAME "lis2de12"
#define LIS2HH12_ACCEL_DEV_NAME "lis2hh12"
#define LIS302DL_ACCEL_DEV_NAME "lis302dl"
+#define LSM303C_ACCEL_DEV_NAME "lsm303c_accel"
#define SC7A20_ACCEL_DEV_NAME "sc7a20"
diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c
index c8c8eb15c34e..6b8562f684d5 100644
--- a/drivers/iio/accel/st_accel_core.c
+++ b/drivers/iio/accel/st_accel_core.c
@@ -929,6 +929,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
[0] = LIS2HH12_ACCEL_DEV_NAME,
+ [1] = LSM303C_ACCEL_DEV_NAME,
},
.ch = (struct iio_chan_spec *)st_accel_16bit_channels,
.odr = {
diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c
index 45ee0ddc133c..3f02fd5d5946 100644
--- a/drivers/iio/accel/st_accel_i2c.c
+++ b/drivers/iio/accel/st_accel_i2c.c
@@ -112,6 +112,10 @@ static const struct of_device_id st_accel_of_match[] = {
.data = LIS302DL_ACCEL_DEV_NAME,
},
{
+ .compatible = "st,lsm303c-accel",
+ .data = LSM303C_ACCEL_DEV_NAME,
+ },
+ {
.compatible = "silan,sc7a20",
.data = SC7A20_ACCEL_DEV_NAME,
},
@@ -151,6 +155,7 @@ static const struct i2c_device_id st_accel_id_table[] = {
{ LIS2DE12_ACCEL_DEV_NAME },
{ LIS2HH12_ACCEL_DEV_NAME },
{ LIS302DL_ACCEL_DEV_NAME },
+ { LSM303C_ACCEL_DEV_NAME },
{ SC7A20_ACCEL_DEV_NAME },
{},
};
diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c
index 6c0917750288..5740dc1820bd 100644
--- a/drivers/iio/accel/st_accel_spi.c
+++ b/drivers/iio/accel/st_accel_spi.c
@@ -96,6 +96,10 @@ static const struct of_device_id st_accel_of_match[] = {
.compatible = "st,lis302dl",
.data = LIS302DL_ACCEL_DEV_NAME,
},
+ {
+ .compatible = "st,lsm303c-accel",
+ .data = LSM303C_ACCEL_DEV_NAME,
+ },
{}
};
MODULE_DEVICE_TABLE(of, st_accel_of_match);
@@ -152,6 +156,7 @@ static const struct spi_device_id st_accel_id_table[] = {
{ LIS3DHH_ACCEL_DEV_NAME },
{ LIS3DE_ACCEL_DEV_NAME },
{ LIS302DL_ACCEL_DEV_NAME },
+ { LSM303C_ACCEL_DEV_NAME },
{},
};
MODULE_DEVICE_TABLE(spi, st_accel_id_table);
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 99cd305b59d9..45af2302be53 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -441,7 +441,8 @@ config ENVELOPE_DETECTOR
config EP93XX_ADC
tristate "Cirrus Logic EP93XX ADC driver"
- depends on ARCH_EP93XX
+ depends on ARCH_EP93XX || COMPILE_TEST
+ depends on HAS_IOMEM
help
Driver for the ADC module on the EP93XX series of SoC from Cirrus Logic.
It's recommended to switch on CONFIG_HIGH_RES_TIMERS option, in this
@@ -565,6 +566,16 @@ config IMX8QXP_ADC
This driver can also be built as a module. If so, the module will be
called imx8qxp-adc.
+config IMX93_ADC
+ tristate "IMX93 ADC driver"
+ depends on ARCH_MXC || COMPILE_TEST
+ depends on HAS_IOMEM
+ help
+ Say yes here to build support for IMX93 ADC.
+
+ This driver can also be built as a module. If so, the module will be
+ called imx93_adc.
+
config LP8788_ADC
tristate "LP8788 ADC driver"
depends on MFD_LP8788
@@ -1207,6 +1218,17 @@ config TI_ADS1015
This driver can also be built as a module. If so, the module will be
called ti-ads1015.
+config TI_ADS7924
+ tristate "Texas Instruments ADS7924 ADC"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ If you say yes here you get support for Texas Instruments ADS7924
+ 4 channels, 12-bit I2C ADC chip.
+
+ This driver can also be built as a module. If so, the module will be
+ called ti-ads7924.
+
config TI_ADS7950
tristate "Texas Instruments ADS7950 ADC driver"
depends on SPI && GPIOLIB
@@ -1274,6 +1296,16 @@ config TI_AM335X_ADC
To compile this driver as a module, choose M here: the module will be
called ti_am335x_adc.
+config TI_LMP92064
+ tristate "Texas Instruments LMP92064 ADC driver"
+ depends on SPI
+ help
+ Say yes here to build support for the LMP92064 Precision Current and Voltage
+ sensor.
+
+ This driver can also be built as a module. If so, the module will be called
+ ti-lmp92064.
+
config TI_TLC4541
tristate "Texas Instruments TLC4541 ADC driver"
depends on SPI
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 4ef41a7dfac6..36c18177322a 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -49,6 +49,7 @@ obj-$(CONFIG_HI8435) += hi8435.o
obj-$(CONFIG_HX711) += hx711.o
obj-$(CONFIG_IMX7D_ADC) += imx7d_adc.o
obj-$(CONFIG_IMX8QXP_ADC) += imx8qxp-adc.o
+obj-$(CONFIG_IMX93_ADC) += imx93_adc.o
obj-$(CONFIG_INA2XX_ADC) += ina2xx-adc.o
obj-$(CONFIG_INGENIC_ADC) += ingenic-adc.o
obj-$(CONFIG_INTEL_MRFLD_ADC) += intel_mrfld_adc.o
@@ -107,12 +108,14 @@ obj-$(CONFIG_TI_ADC108S102) += ti-adc108s102.o
obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o
obj-$(CONFIG_TI_ADC161S626) += ti-adc161s626.o
obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o
+obj-$(CONFIG_TI_ADS7924) += ti-ads7924.o
obj-$(CONFIG_TI_ADS7950) += ti-ads7950.o
obj-$(CONFIG_TI_ADS8344) += ti-ads8344.o
obj-$(CONFIG_TI_ADS8688) += ti-ads8688.o
obj-$(CONFIG_TI_ADS124S08) += ti-ads124s08.o
obj-$(CONFIG_TI_ADS131E08) += ti-ads131e08.o
obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o
+obj-$(CONFIG_TI_LMP92064) += ti-lmp92064.o
obj-$(CONFIG_TI_TLC4541) += ti-tlc4541.o
obj-$(CONFIG_TI_TSC2046) += ti-tsc2046.o
obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o
diff --git a/drivers/iio/adc/ad7291.c b/drivers/iio/adc/ad7291.c
index 3dd0105f63d7..f9ee189925de 100644
--- a/drivers/iio/adc/ad7291.c
+++ b/drivers/iio/adc/ad7291.c
@@ -179,7 +179,7 @@ static unsigned int ad7291_threshold_reg(const struct iio_chan_spec *chan,
offset = AD7291_VOLTAGE_OFFSET;
break;
default:
- return 0;
+ return 0;
}
switch (info) {
diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c
index ed4f8501bda8..50d02e5fc6fc 100644
--- a/drivers/iio/adc/at91-sama5d2_adc.c
+++ b/drivers/iio/adc/at91-sama5d2_adc.c
@@ -2181,7 +2181,7 @@ static ssize_t at91_adc_get_fifo_state(struct device *dev,
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct at91_adc_state *st = iio_priv(indio_dev);
- return scnprintf(buf, PAGE_SIZE, "%d\n", !!st->dma_st.dma_chan);
+ return sysfs_emit(buf, "%d\n", !!st->dma_st.dma_chan);
}
static ssize_t at91_adc_get_watermark(struct device *dev,
@@ -2190,7 +2190,7 @@ static ssize_t at91_adc_get_watermark(struct device *dev,
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct at91_adc_state *st = iio_priv(indio_dev);
- return scnprintf(buf, PAGE_SIZE, "%d\n", st->dma_st.watermark);
+ return sysfs_emit(buf, "%d\n", st->dma_st.watermark);
}
static IIO_DEVICE_ATTR(hwfifo_enabled, 0444,
diff --git a/drivers/iio/adc/ep93xx_adc.c b/drivers/iio/adc/ep93xx_adc.c
index fd5a9404c8dc..a35e6cead67d 100644
--- a/drivers/iio/adc/ep93xx_adc.c
+++ b/drivers/iio/adc/ep93xx_adc.c
@@ -21,6 +21,7 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
+#include <linux/of.h>
/*
* This code could benefit from real HR Timers, but jiffy granularity would
@@ -227,9 +228,16 @@ static int ep93xx_adc_remove(struct platform_device *pdev)
return 0;
}
+static const struct of_device_id ep93xx_adc_of_ids[] = {
+ { .compatible = "cirrus,ep9301-adc" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, ep93xx_adc_of_ids);
+
static struct platform_driver ep93xx_adc_driver = {
.driver = {
.name = "ep93xx-adc",
+ .of_match_table = ep93xx_adc_of_ids,
},
.probe = ep93xx_adc_probe,
.remove = ep93xx_adc_remove,
diff --git a/drivers/iio/adc/imx93_adc.c b/drivers/iio/adc/imx93_adc.c
new file mode 100644
index 000000000000..a775d2e40567
--- /dev/null
+++ b/drivers/iio/adc/imx93_adc.c
@@ -0,0 +1,484 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * NXP i.MX93 ADC driver
+ *
+ * Copyright 2023 NXP
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/err.h>
+#include <linux/iio/iio.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+
+#define IMX93_ADC_DRIVER_NAME "imx93-adc"
+
+/* Register map definition */
+#define IMX93_ADC_MCR 0x00
+#define IMX93_ADC_MSR 0x04
+#define IMX93_ADC_ISR 0x10
+#define IMX93_ADC_IMR 0x20
+#define IMX93_ADC_CIMR0 0x24
+#define IMX93_ADC_CTR0 0x94
+#define IMX93_ADC_NCMR0 0xA4
+#define IMX93_ADC_PCDR0 0x100
+#define IMX93_ADC_PCDR1 0x104
+#define IMX93_ADC_PCDR2 0x108
+#define IMX93_ADC_PCDR3 0x10c
+#define IMX93_ADC_PCDR4 0x110
+#define IMX93_ADC_PCDR5 0x114
+#define IMX93_ADC_PCDR6 0x118
+#define IMX93_ADC_PCDR7 0x11c
+#define IMX93_ADC_CALSTAT 0x39C
+
+/* ADC bit shift */
+#define IMX93_ADC_MCR_MODE_MASK BIT(29)
+#define IMX93_ADC_MCR_NSTART_MASK BIT(24)
+#define IMX93_ADC_MCR_CALSTART_MASK BIT(14)
+#define IMX93_ADC_MCR_ADCLKSE_MASK BIT(8)
+#define IMX93_ADC_MCR_PWDN_MASK BIT(0)
+#define IMX93_ADC_MSR_CALFAIL_MASK BIT(30)
+#define IMX93_ADC_MSR_CALBUSY_MASK BIT(29)
+#define IMX93_ADC_MSR_ADCSTATUS_MASK GENMASK(2, 0)
+#define IMX93_ADC_ISR_ECH_MASK BIT(0)
+#define IMX93_ADC_ISR_EOC_MASK BIT(1)
+#define IMX93_ADC_ISR_EOC_ECH_MASK (IMX93_ADC_ISR_EOC_MASK | \
+ IMX93_ADC_ISR_ECH_MASK)
+#define IMX93_ADC_IMR_JEOC_MASK BIT(3)
+#define IMX93_ADC_IMR_JECH_MASK BIT(2)
+#define IMX93_ADC_IMR_EOC_MASK BIT(1)
+#define IMX93_ADC_IMR_ECH_MASK BIT(0)
+#define IMX93_ADC_PCDR_CDATA_MASK GENMASK(11, 0)
+
+/* ADC status */
+#define IMX93_ADC_MSR_ADCSTATUS_IDLE 0
+#define IMX93_ADC_MSR_ADCSTATUS_POWER_DOWN 1
+#define IMX93_ADC_MSR_ADCSTATUS_WAIT_STATE 2
+#define IMX93_ADC_MSR_ADCSTATUS_BUSY_IN_CALIBRATION 3
+#define IMX93_ADC_MSR_ADCSTATUS_SAMPLE 4
+#define IMX93_ADC_MSR_ADCSTATUS_CONVERSION 6
+
+#define IMX93_ADC_TIMEOUT msecs_to_jiffies(100)
+
+struct imx93_adc {
+ struct device *dev;
+ void __iomem *regs;
+ struct clk *ipg_clk;
+ int irq;
+ struct regulator *vref;
+ /* lock to protect against multiple access to the device */
+ struct mutex lock;
+ struct completion completion;
+};
+
+#define IMX93_ADC_CHAN(_idx) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = (_idx), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+}
+
+static const struct iio_chan_spec imx93_adc_iio_channels[] = {
+ IMX93_ADC_CHAN(0),
+ IMX93_ADC_CHAN(1),
+ IMX93_ADC_CHAN(2),
+ IMX93_ADC_CHAN(3),
+};
+
+static void imx93_adc_power_down(struct imx93_adc *adc)
+{
+ u32 mcr, msr;
+ int ret;
+
+ mcr = readl(adc->regs + IMX93_ADC_MCR);
+ mcr |= FIELD_PREP(IMX93_ADC_MCR_PWDN_MASK, 1);
+ writel(mcr, adc->regs + IMX93_ADC_MCR);
+
+ ret = readl_poll_timeout(adc->regs + IMX93_ADC_MSR, msr,
+ ((msr & IMX93_ADC_MSR_ADCSTATUS_MASK) ==
+ IMX93_ADC_MSR_ADCSTATUS_POWER_DOWN),
+ 1, 50);
+ if (ret == -ETIMEDOUT)
+ dev_warn(adc->dev,
+ "ADC do not in power down mode, current MSR is %x\n",
+ msr);
+}
+
+static void imx93_adc_power_up(struct imx93_adc *adc)
+{
+ u32 mcr;
+
+ /* bring ADC out of power down state, in idle state */
+ mcr = readl(adc->regs + IMX93_ADC_MCR);
+ mcr &= ~FIELD_PREP(IMX93_ADC_MCR_PWDN_MASK, 1);
+ writel(mcr, adc->regs + IMX93_ADC_MCR);
+}
+
+static void imx93_adc_config_ad_clk(struct imx93_adc *adc)
+{
+ u32 mcr;
+
+ /* put adc in power down mode */
+ imx93_adc_power_down(adc);
+
+ /* config the AD_CLK equal to bus clock */
+ mcr = readl(adc->regs + IMX93_ADC_MCR);
+ mcr |= FIELD_PREP(IMX93_ADC_MCR_ADCLKSE_MASK, 1);
+ writel(mcr, adc->regs + IMX93_ADC_MCR);
+
+ imx93_adc_power_up(adc);
+}
+
+static int imx93_adc_calibration(struct imx93_adc *adc)
+{
+ u32 mcr, msr;
+ int ret;
+
+ /* make sure ADC in power down mode */
+ imx93_adc_power_down(adc);
+
+ /* config SAR controller operating clock */
+ mcr = readl(adc->regs + IMX93_ADC_MCR);
+ mcr &= ~FIELD_PREP(IMX93_ADC_MCR_ADCLKSE_MASK, 1);
+ writel(mcr, adc->regs + IMX93_ADC_MCR);
+
+ imx93_adc_power_up(adc);
+
+ /*
+ * TODO: we use the default TSAMP/NRSMPL/AVGEN in MCR,
+ * can add the setting of these bit if need in future.
+ */
+
+ /* run calibration */
+ mcr = readl(adc->regs + IMX93_ADC_MCR);
+ mcr |= FIELD_PREP(IMX93_ADC_MCR_CALSTART_MASK, 1);
+ writel(mcr, adc->regs + IMX93_ADC_MCR);
+
+ /* wait calibration to be finished */
+ ret = readl_poll_timeout(adc->regs + IMX93_ADC_MSR, msr,
+ !(msr & IMX93_ADC_MSR_CALBUSY_MASK), 1000, 2000000);
+ if (ret == -ETIMEDOUT) {
+ dev_warn(adc->dev, "ADC do not finish calibration in 2 min!\n");
+ imx93_adc_power_down(adc);
+ return ret;
+ }
+
+ /* check whether calbration is success or not */
+ msr = readl(adc->regs + IMX93_ADC_MSR);
+ if (msr & IMX93_ADC_MSR_CALFAIL_MASK) {
+ dev_warn(adc->dev, "ADC calibration failed!\n");
+ imx93_adc_power_down(adc);
+ return -EAGAIN;
+ }
+
+ return 0;
+}
+
+static int imx93_adc_read_channel_conversion(struct imx93_adc *adc,
+ int channel_number,
+ int *result)
+{
+ u32 channel;
+ u32 imr, mcr, pcda;
+ long ret;
+
+ reinit_completion(&adc->completion);
+
+ /* config channel mask register */
+ channel = 1 << channel_number;
+ writel(channel, adc->regs + IMX93_ADC_NCMR0);
+
+ /* TODO: can config desired sample time in CTRn if need */
+
+ /* config interrupt mask */
+ imr = FIELD_PREP(IMX93_ADC_IMR_EOC_MASK, 1);
+ writel(imr, adc->regs + IMX93_ADC_IMR);
+ writel(channel, adc->regs + IMX93_ADC_CIMR0);
+
+ /* config one-shot mode */
+ mcr = readl(adc->regs + IMX93_ADC_MCR);
+ mcr &= ~FIELD_PREP(IMX93_ADC_MCR_MODE_MASK, 1);
+ writel(mcr, adc->regs + IMX93_ADC_MCR);
+
+ /* start normal conversion */
+ mcr = readl(adc->regs + IMX93_ADC_MCR);
+ mcr |= FIELD_PREP(IMX93_ADC_MCR_NSTART_MASK, 1);
+ writel(mcr, adc->regs + IMX93_ADC_MCR);
+
+ ret = wait_for_completion_interruptible_timeout(&adc->completion,
+ IMX93_ADC_TIMEOUT);
+ if (ret == 0)
+ return -ETIMEDOUT;
+
+ if (ret < 0)
+ return ret;
+
+ pcda = readl(adc->regs + IMX93_ADC_PCDR0 + channel_number * 4);
+
+ *result = FIELD_GET(IMX93_ADC_PCDR_CDATA_MASK, pcda);
+
+ return ret;
+}
+
+static int imx93_adc_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct imx93_adc *adc = iio_priv(indio_dev);
+ struct device *dev = adc->dev;
+ long ret;
+ u32 vref_uv;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ pm_runtime_get_sync(dev);
+ mutex_lock(&adc->lock);
+ ret = imx93_adc_read_channel_conversion(adc, chan->channel, val);
+ mutex_unlock(&adc->lock);
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_sync_autosuspend(dev);
+ if (ret < 0)
+ return ret;
+
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ ret = vref_uv = regulator_get_voltage(adc->vref);
+ if (ret < 0)
+ return ret;
+ *val = vref_uv / 1000;
+ *val2 = 12;
+ return IIO_VAL_FRACTIONAL_LOG2;
+
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *val = clk_get_rate(adc->ipg_clk);
+ return IIO_VAL_INT;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static irqreturn_t imx93_adc_isr(int irq, void *dev_id)
+{
+ struct imx93_adc *adc = dev_id;
+ u32 isr, eoc, unexpected;
+
+ isr = readl(adc->regs + IMX93_ADC_ISR);
+
+ if (FIELD_GET(IMX93_ADC_ISR_EOC_ECH_MASK, isr)) {
+ eoc = isr & IMX93_ADC_ISR_EOC_ECH_MASK;
+ writel(eoc, adc->regs + IMX93_ADC_ISR);
+ complete(&adc->completion);
+ }
+
+ unexpected = isr & ~IMX93_ADC_ISR_EOC_ECH_MASK;
+ if (unexpected) {
+ writel(unexpected, adc->regs + IMX93_ADC_ISR);
+ dev_err(adc->dev, "Unexpected interrupt 0x%08x.\n", unexpected);
+ return IRQ_NONE;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static const struct iio_info imx93_adc_iio_info = {
+ .read_raw = &imx93_adc_read_raw,
+};
+
+static int imx93_adc_probe(struct platform_device *pdev)
+{
+ struct imx93_adc *adc;
+ struct iio_dev *indio_dev;
+ struct device *dev = &pdev->dev;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*adc));
+ if (!indio_dev)
+ return dev_err_probe(dev, -ENOMEM,
+ "Failed allocating iio device\n");
+
+ adc = iio_priv(indio_dev);
+ adc->dev = dev;
+
+ mutex_init(&adc->lock);
+ adc->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(adc->regs))
+ return dev_err_probe(dev, PTR_ERR(adc->regs),
+ "Failed getting ioremap resource\n");
+
+ /* The third irq is for ADC conversion usage */
+ adc->irq = platform_get_irq(pdev, 2);
+ if (adc->irq < 0)
+ return adc->irq;
+
+ adc->ipg_clk = devm_clk_get(dev, "ipg");
+ if (IS_ERR(adc->ipg_clk))
+ return dev_err_probe(dev, PTR_ERR(adc->ipg_clk),
+ "Failed getting clock.\n");
+
+ adc->vref = devm_regulator_get(dev, "vref");
+ if (IS_ERR(adc->vref))
+ return dev_err_probe(dev, PTR_ERR(adc->vref),
+ "Failed getting reference voltage.\n");
+
+ ret = regulator_enable(adc->vref);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to enable reference voltage.\n");
+
+ platform_set_drvdata(pdev, indio_dev);
+
+ init_completion(&adc->completion);
+
+ indio_dev->name = "imx93-adc";
+ indio_dev->info = &imx93_adc_iio_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = imx93_adc_iio_channels;
+ indio_dev->num_channels = ARRAY_SIZE(imx93_adc_iio_channels);
+
+ ret = clk_prepare_enable(adc->ipg_clk);
+ if (ret) {
+ dev_err_probe(dev, ret,
+ "Failed to enable ipg clock.\n");
+ goto error_regulator_disable;
+ }
+
+ ret = request_irq(adc->irq, imx93_adc_isr, 0, IMX93_ADC_DRIVER_NAME, adc);
+ if (ret < 0) {
+ dev_err_probe(dev, ret,
+ "Failed requesting irq, irq = %d\n", adc->irq);
+ goto error_ipg_clk_disable;
+ }
+
+ ret = imx93_adc_calibration(adc);
+ if (ret < 0)
+ goto error_free_adc_irq;
+
+ imx93_adc_config_ad_clk(adc);
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err_probe(dev, ret,
+ "Failed to register this iio device.\n");
+ goto error_adc_power_down;
+ }
+
+ pm_runtime_set_active(dev);
+ pm_runtime_set_autosuspend_delay(dev, 50);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_enable(dev);
+
+ return 0;
+
+error_adc_power_down:
+ imx93_adc_power_down(adc);
+error_free_adc_irq:
+ free_irq(adc->irq, adc);
+error_ipg_clk_disable:
+ clk_disable_unprepare(adc->ipg_clk);
+error_regulator_disable:
+ regulator_disable(adc->vref);
+
+ return ret;
+}
+
+static int imx93_adc_remove(struct platform_device *pdev)
+{
+ struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+ struct imx93_adc *adc = iio_priv(indio_dev);
+ struct device *dev = adc->dev;
+
+ /* adc power down need clock on */
+ pm_runtime_get_sync(dev);
+
+ pm_runtime_disable(dev);
+ pm_runtime_dont_use_autosuspend(dev);
+ pm_runtime_put_noidle(dev);
+
+ iio_device_unregister(indio_dev);
+ imx93_adc_power_down(adc);
+ free_irq(adc->irq, adc);
+ clk_disable_unprepare(adc->ipg_clk);
+ regulator_disable(adc->vref);
+
+ return 0;
+}
+
+static int imx93_adc_runtime_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct imx93_adc *adc = iio_priv(indio_dev);
+
+ imx93_adc_power_down(adc);
+ clk_disable_unprepare(adc->ipg_clk);
+ regulator_disable(adc->vref);
+
+ return 0;
+}
+
+static int imx93_adc_runtime_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct imx93_adc *adc = iio_priv(indio_dev);
+ int ret;
+
+ ret = regulator_enable(adc->vref);
+ if (ret) {
+ dev_err(dev,
+ "Can't enable adc reference top voltage, err = %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(adc->ipg_clk);
+ if (ret) {
+ dev_err(dev, "Could not prepare or enable clock.\n");
+ goto err_disable_reg;
+ }
+
+ imx93_adc_power_up(adc);
+
+ return 0;
+
+err_disable_reg:
+ regulator_disable(adc->vref);
+
+ return ret;
+}
+
+static DEFINE_RUNTIME_DEV_PM_OPS(imx93_adc_pm_ops,
+ imx93_adc_runtime_suspend,
+ imx93_adc_runtime_resume, NULL);
+
+static const struct of_device_id imx93_adc_match[] = {
+ { .compatible = "nxp,imx93-adc", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx93_adc_match);
+
+static struct platform_driver imx93_adc_driver = {
+ .probe = imx93_adc_probe,
+ .remove = imx93_adc_remove,
+ .driver = {
+ .name = IMX93_ADC_DRIVER_NAME,
+ .of_match_table = imx93_adc_match,
+ .pm = pm_ptr(&imx93_adc_pm_ops),
+ },
+};
+
+module_platform_driver(imx93_adc_driver);
+
+MODULE_DESCRIPTION("NXP i.MX93 ADC driver");
+MODULE_AUTHOR("Haibo Chen <haibo.chen@nxp.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/adc/max11410.c b/drivers/iio/adc/max11410.c
index fdc9f03135b5..b74b689ee7de 100644
--- a/drivers/iio/adc/max11410.c
+++ b/drivers/iio/adc/max11410.c
@@ -4,7 +4,6 @@
*
* Copyright 2022 Analog Devices Inc.
*/
-#include <asm-generic/unaligned.h>
#include <linux/bitfield.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -16,6 +15,8 @@
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
+#include <asm/unaligned.h>
+
#include <linux/iio/buffer.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/trigger.h>
diff --git a/drivers/iio/adc/qcom-spmi-adc5.c b/drivers/iio/adc/qcom-spmi-adc5.c
index 821fee60a765..e90c299c913a 100644
--- a/drivers/iio/adc/qcom-spmi-adc5.c
+++ b/drivers/iio/adc/qcom-spmi-adc5.c
@@ -543,6 +543,8 @@ static const struct adc5_channels adc5_chans_pmic[ADC5_MAX_CHANNEL] = {
SCALE_HW_CALIB_DEFAULT)
[ADC5_XO_THERM_100K_PU] = ADC5_CHAN_TEMP("xo_therm", 0,
SCALE_HW_CALIB_XOTHERM)
+ [ADC5_BAT_ID_100K_PU] = ADC5_CHAN_TEMP("bat_id", 0,
+ SCALE_HW_CALIB_DEFAULT)
[ADC5_AMUX_THM1_100K_PU] = ADC5_CHAN_TEMP("amux_thm1_100k_pu", 0,
SCALE_HW_CALIB_THERM_100K_PULLUP)
[ADC5_AMUX_THM2_100K_PU] = ADC5_CHAN_TEMP("amux_thm2_100k_pu", 0,
@@ -894,10 +896,8 @@ static int adc5_probe(struct platform_device *pdev)
mutex_init(&adc->lock);
ret = adc5_get_fw_data(adc);
- if (ret) {
- dev_err(dev, "adc get dt data failed\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "adc get dt data failed\n");
irq_eoc = platform_get_irq(pdev, 0);
if (irq_eoc < 0) {
diff --git a/drivers/iio/adc/stm32-dfsdm-core.c b/drivers/iio/adc/stm32-dfsdm-core.c
index a3d4de6ba4c2..0362df285a57 100644
--- a/drivers/iio/adc/stm32-dfsdm-core.c
+++ b/drivers/iio/adc/stm32-dfsdm-core.c
@@ -6,6 +6,7 @@
* Author(s): Arnaud Pouliquen <arnaud.pouliquen@st.com> for STMicroelectronics.
*/
+#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -19,7 +20,15 @@
#include "stm32-dfsdm.h"
+/**
+ * struct stm32_dfsdm_dev_data - DFSDM compatible configuration data
+ * @ipid: DFSDM identification number. Used only if hardware provides identification registers
+ * @num_filters: DFSDM number of filters. Unused if identification registers are available
+ * @num_channels: DFSDM number of channels. Unused if identification registers are available
+ * @regmap_cfg: SAI register map configuration pointer
+ */
struct stm32_dfsdm_dev_data {
+ u32 ipid;
unsigned int num_filters;
unsigned int num_channels;
const struct regmap_config *regmap_cfg;
@@ -27,8 +36,6 @@ struct stm32_dfsdm_dev_data {
#define STM32H7_DFSDM_NUM_FILTERS 4
#define STM32H7_DFSDM_NUM_CHANNELS 8
-#define STM32MP1_DFSDM_NUM_FILTERS 6
-#define STM32MP1_DFSDM_NUM_CHANNELS 8
static bool stm32_dfsdm_volatile_reg(struct device *dev, unsigned int reg)
{
@@ -75,8 +82,7 @@ static const struct regmap_config stm32mp1_dfsdm_regmap_cfg = {
};
static const struct stm32_dfsdm_dev_data stm32mp1_dfsdm_data = {
- .num_filters = STM32MP1_DFSDM_NUM_FILTERS,
- .num_channels = STM32MP1_DFSDM_NUM_CHANNELS,
+ .ipid = STM32MP15_IPIDR_NUMBER,
.regmap_cfg = &stm32mp1_dfsdm_regmap_cfg,
};
@@ -295,6 +301,65 @@ static const struct of_device_id stm32_dfsdm_of_match[] = {
};
MODULE_DEVICE_TABLE(of, stm32_dfsdm_of_match);
+static int stm32_dfsdm_probe_identification(struct platform_device *pdev,
+ struct dfsdm_priv *priv,
+ const struct stm32_dfsdm_dev_data *dev_data)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *child;
+ struct stm32_dfsdm *dfsdm = &priv->dfsdm;
+ const char *compat;
+ int ret, count = 0;
+ u32 id, val;
+
+ if (!dev_data->ipid) {
+ dfsdm->num_fls = dev_data->num_filters;
+ dfsdm->num_chs = dev_data->num_channels;
+ return 0;
+ }
+
+ ret = regmap_read(dfsdm->regmap, DFSDM_IPIDR, &id);
+ if (ret)
+ return ret;
+
+ if (id != dev_data->ipid) {
+ dev_err(&pdev->dev, "Unexpected IP version: 0x%x", id);
+ return -EINVAL;
+ }
+
+ for_each_child_of_node(np, child) {
+ ret = of_property_read_string(child, "compatible", &compat);
+ if (ret)
+ continue;
+ /* Count only child nodes with dfsdm compatible */
+ if (strstr(compat, "dfsdm"))
+ count++;
+ }
+
+ ret = regmap_read(dfsdm->regmap, DFSDM_HWCFGR, &val);
+ if (ret)
+ return ret;
+
+ dfsdm->num_fls = FIELD_GET(DFSDM_HWCFGR_NBF_MASK, val);
+ dfsdm->num_chs = FIELD_GET(DFSDM_HWCFGR_NBT_MASK, val);
+
+ if (count > dfsdm->num_fls) {
+ dev_err(&pdev->dev, "Unexpected child number: %d", count);
+ return -EINVAL;
+ }
+
+ ret = regmap_read(dfsdm->regmap, DFSDM_VERR, &val);
+ if (ret)
+ return ret;
+
+ dev_dbg(&pdev->dev, "DFSDM version: %lu.%lu. %d channels/%d filters\n",
+ FIELD_GET(DFSDM_VERR_MAJREV_MASK, val),
+ FIELD_GET(DFSDM_VERR_MINREV_MASK, val),
+ dfsdm->num_chs, dfsdm->num_fls);
+
+ return 0;
+}
+
static int stm32_dfsdm_probe(struct platform_device *pdev)
{
struct dfsdm_priv *priv;
@@ -311,18 +376,6 @@ static int stm32_dfsdm_probe(struct platform_device *pdev)
dev_data = of_device_get_match_data(&pdev->dev);
dfsdm = &priv->dfsdm;
- dfsdm->fl_list = devm_kcalloc(&pdev->dev, dev_data->num_filters,
- sizeof(*dfsdm->fl_list), GFP_KERNEL);
- if (!dfsdm->fl_list)
- return -ENOMEM;
-
- dfsdm->num_fls = dev_data->num_filters;
- dfsdm->ch_list = devm_kcalloc(&pdev->dev, dev_data->num_channels,
- sizeof(*dfsdm->ch_list),
- GFP_KERNEL);
- if (!dfsdm->ch_list)
- return -ENOMEM;
- dfsdm->num_chs = dev_data->num_channels;
ret = stm32_dfsdm_parse_of(pdev, priv);
if (ret < 0)
@@ -338,6 +391,20 @@ static int stm32_dfsdm_probe(struct platform_device *pdev)
return ret;
}
+ ret = stm32_dfsdm_probe_identification(pdev, priv, dev_data);
+ if (ret < 0)
+ return ret;
+
+ dfsdm->fl_list = devm_kcalloc(&pdev->dev, dfsdm->num_fls,
+ sizeof(*dfsdm->fl_list), GFP_KERNEL);
+ if (!dfsdm->fl_list)
+ return -ENOMEM;
+
+ dfsdm->ch_list = devm_kcalloc(&pdev->dev, dfsdm->num_chs,
+ sizeof(*dfsdm->ch_list), GFP_KERNEL);
+ if (!dfsdm->ch_list)
+ return -ENOMEM;
+
platform_set_drvdata(pdev, dfsdm);
ret = stm32_dfsdm_clk_prepare_enable(dfsdm);
diff --git a/drivers/iio/adc/stm32-dfsdm.h b/drivers/iio/adc/stm32-dfsdm.h
index 4afc1f528b78..570a1552aec4 100644
--- a/drivers/iio/adc/stm32-dfsdm.h
+++ b/drivers/iio/adc/stm32-dfsdm.h
@@ -13,25 +13,29 @@
/*
* STM32 DFSDM - global register map
- * ________________________________________________________
- * | Offset | Registers block |
- * --------------------------------------------------------
- * | 0x000 | CHANNEL 0 + COMMON CHANNEL FIELDS |
- * --------------------------------------------------------
- * | 0x020 | CHANNEL 1 |
- * --------------------------------------------------------
- * | ... | ..... |
- * --------------------------------------------------------
- * | 0x0E0 | CHANNEL 7 |
- * --------------------------------------------------------
- * | 0x100 | FILTER 0 + COMMON FILTER FIELDs |
- * --------------------------------------------------------
- * | 0x200 | FILTER 1 |
- * --------------------------------------------------------
- * | 0x300 | FILTER 2 |
- * --------------------------------------------------------
- * | 0x400 | FILTER 3 |
- * --------------------------------------------------------
+ * __________________________________________________________
+ * | Offset | Registers block |
+ * ----------------------------------------------------------
+ * | 0x000 | CHANNEL 0 + COMMON CHANNEL FIELDS |
+ * ----------------------------------------------------------
+ * | 0x020 | CHANNEL 1 |
+ * ----------------------------------------------------------
+ * | ... | ..... |
+ * ----------------------------------------------------------
+ * | 0x20 x n | CHANNEL n |
+ * ----------------------------------------------------------
+ * | 0x100 | FILTER 0 + COMMON FILTER FIELDs |
+ * ----------------------------------------------------------
+ * | 0x200 | FILTER 1 |
+ * ----------------------------------------------------------
+ * | | ..... |
+ * ----------------------------------------------------------
+ * | 0x100 x m | FILTER m |
+ * ----------------------------------------------------------
+ * | | ..... |
+ * ----------------------------------------------------------
+ * | 0x7F0-7FC | Identification registers |
+ * ----------------------------------------------------------
*/
/*
@@ -231,6 +235,24 @@
#define DFSDM_AWCFR_AWHTF_MASK GENMASK(15, 8)
#define DFSDM_AWCFR_AWHTF(v) FIELD_PREP(DFSDM_AWCFR_AWHTF_MASK, v)
+/*
+ * Identification register definitions
+ */
+#define DFSDM_HWCFGR 0x7F0
+#define DFSDM_VERR 0x7F4
+#define DFSDM_IPIDR 0x7F8
+#define DFSDM_SIDR 0x7FC
+
+/* HWCFGR: Hardware configuration register */
+#define DFSDM_HWCFGR_NBT_MASK GENMASK(7, 0)
+#define DFSDM_HWCFGR_NBF_MASK GENMASK(15, 8)
+
+/* VERR: Version register */
+#define DFSDM_VERR_MINREV_MASK GENMASK(3, 0)
+#define DFSDM_VERR_MAJREV_MASK GENMASK(7, 4)
+
+#define STM32MP15_IPIDR_NUMBER 0x00110031
+
/* DFSDM filter order */
enum stm32_dfsdm_sinc_order {
DFSDM_FASTSINC_ORDER, /* FastSinc filter type */
diff --git a/drivers/iio/adc/ti-adc128s052.c b/drivers/iio/adc/ti-adc128s052.c
index b3d5b9b7255b..a456ea78462f 100644
--- a/drivers/iio/adc/ti-adc128s052.c
+++ b/drivers/iio/adc/ti-adc128s052.c
@@ -9,14 +9,13 @@
* https://www.ti.com/lit/ds/symlink/adc124s021.pdf
*/
-#include <linux/acpi.h>
#include <linux/err.h>
-#include <linux/spi/spi.h>
-#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/iio/iio.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
#include <linux/property.h>
#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
struct adc128_configuration {
const struct iio_chan_spec *channels;
@@ -139,16 +138,11 @@ static void adc128_disable_regulator(void *reg)
static int adc128_probe(struct spi_device *spi)
{
+ const struct adc128_configuration *config;
struct iio_dev *indio_dev;
- unsigned int config;
struct adc128 *adc;
int ret;
- if (dev_fwnode(&spi->dev))
- config = (unsigned long) device_get_match_data(&spi->dev);
- else
- config = spi_get_device_id(spi)->driver_data;
-
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
if (!indio_dev)
return -ENOMEM;
@@ -160,8 +154,10 @@ static int adc128_probe(struct spi_device *spi)
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &adc128_info;
- indio_dev->channels = adc128_config[config].channels;
- indio_dev->num_channels = adc128_config[config].num_channels;
+ config = spi_get_device_match_data(spi);
+
+ indio_dev->channels = config->channels;
+ indio_dev->num_channels = config->num_channels;
adc->reg = devm_regulator_get(&spi->dev, "vref");
if (IS_ERR(adc->reg))
@@ -181,42 +177,40 @@ static int adc128_probe(struct spi_device *spi)
}
static const struct of_device_id adc128_of_match[] = {
- { .compatible = "ti,adc128s052", .data = (void*)0L, },
- { .compatible = "ti,adc122s021", .data = (void*)1L, },
- { .compatible = "ti,adc122s051", .data = (void*)1L, },
- { .compatible = "ti,adc122s101", .data = (void*)1L, },
- { .compatible = "ti,adc124s021", .data = (void*)2L, },
- { .compatible = "ti,adc124s051", .data = (void*)2L, },
- { .compatible = "ti,adc124s101", .data = (void*)2L, },
+ { .compatible = "ti,adc128s052", .data = &adc128_config[0] },
+ { .compatible = "ti,adc122s021", .data = &adc128_config[1] },
+ { .compatible = "ti,adc122s051", .data = &adc128_config[1] },
+ { .compatible = "ti,adc122s101", .data = &adc128_config[1] },
+ { .compatible = "ti,adc124s021", .data = &adc128_config[2] },
+ { .compatible = "ti,adc124s051", .data = &adc128_config[2] },
+ { .compatible = "ti,adc124s101", .data = &adc128_config[2] },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, adc128_of_match);
static const struct spi_device_id adc128_id[] = {
- { "adc128s052", 0 }, /* index into adc128_config */
- { "adc122s021", 1 },
- { "adc122s051", 1 },
- { "adc122s101", 1 },
- { "adc124s021", 2 },
- { "adc124s051", 2 },
- { "adc124s101", 2 },
+ { "adc128s052", (kernel_ulong_t)&adc128_config[0] },
+ { "adc122s021", (kernel_ulong_t)&adc128_config[1] },
+ { "adc122s051", (kernel_ulong_t)&adc128_config[1] },
+ { "adc122s101", (kernel_ulong_t)&adc128_config[1] },
+ { "adc124s021", (kernel_ulong_t)&adc128_config[2] },
+ { "adc124s051", (kernel_ulong_t)&adc128_config[2] },
+ { "adc124s101", (kernel_ulong_t)&adc128_config[2] },
{ }
};
MODULE_DEVICE_TABLE(spi, adc128_id);
-#ifdef CONFIG_ACPI
static const struct acpi_device_id adc128_acpi_match[] = {
- { "AANT1280", 2 }, /* ADC124S021 compatible ACPI ID */
+ { "AANT1280", (kernel_ulong_t)&adc128_config[2] },
{ }
};
MODULE_DEVICE_TABLE(acpi, adc128_acpi_match);
-#endif
static struct spi_driver adc128_driver = {
.driver = {
.name = "adc128s052",
.of_match_table = adc128_of_match,
- .acpi_match_table = ACPI_PTR(adc128_acpi_match),
+ .acpi_match_table = adc128_acpi_match,
},
.probe = adc128_probe,
.id_table = adc128_id,
diff --git a/drivers/iio/adc/ti-ads7924.c b/drivers/iio/adc/ti-ads7924.c
new file mode 100644
index 000000000000..b02abb026966
--- /dev/null
+++ b/drivers/iio/adc/ti-ads7924.c
@@ -0,0 +1,474 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * IIO driver for Texas Instruments ADS7924 ADC, 12-bit, 4-Channels, I2C
+ *
+ * Author: Hugo Villeneuve <hvilleneuve@dimonoff.com>
+ * Copyright 2022 DimOnOff
+ *
+ * based on iio/adc/ti-ads1015.c
+ * Copyright (c) 2016, Intel Corporation.
+ *
+ * Datasheet: https://www.ti.com/lit/gpn/ads7924
+ */
+
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/types.h>
+
+#define ADS7924_CHANNELS 4
+#define ADS7924_BITS 12
+#define ADS7924_DATA_SHIFT 4
+
+/* Registers. */
+#define ADS7924_MODECNTRL_REG 0x00
+#define ADS7924_INTCNTRL_REG 0x01
+#define ADS7924_DATA0_U_REG 0x02
+#define ADS7924_DATA0_L_REG 0x03
+#define ADS7924_DATA1_U_REG 0x04
+#define ADS7924_DATA1_L_REG 0x05
+#define ADS7924_DATA2_U_REG 0x06
+#define ADS7924_DATA2_L_REG 0x07
+#define ADS7924_DATA3_U_REG 0x08
+#define ADS7924_DATA3_L_REG 0x09
+#define ADS7924_ULR0_REG 0x0A
+#define ADS7924_LLR0_REG 0x0B
+#define ADS7924_ULR1_REG 0x0C
+#define ADS7924_LLR1_REG 0x0D
+#define ADS7924_ULR2_REG 0x0E
+#define ADS7924_LLR2_REG 0x0F
+#define ADS7924_ULR3_REG 0x10
+#define ADS7924_LLR3_REG 0x11
+#define ADS7924_INTCONFIG_REG 0x12
+#define ADS7924_SLPCONFIG_REG 0x13
+#define ADS7924_ACQCONFIG_REG 0x14
+#define ADS7924_PWRCONFIG_REG 0x15
+#define ADS7924_RESET_REG 0x16
+
+/*
+ * Register address INC bit: when set to '1', the register address is
+ * automatically incremented after every register read which allows convenient
+ * reading of multiple registers. Set INC to '0' when reading a single register.
+ */
+#define ADS7924_AUTO_INCREMENT_BIT BIT(7)
+
+#define ADS7924_MODECNTRL_MODE_MASK GENMASK(7, 2)
+
+#define ADS7924_MODECNTRL_SEL_MASK GENMASK(1, 0)
+
+#define ADS7924_CFG_INTPOL_BIT 1
+#define ADS7924_CFG_INTTRIG_BIT 0
+
+#define ADS7924_CFG_INTPOL_MASK BIT(ADS7924_CFG_INTPOL_BIT)
+#define ADS7924_CFG_INTTRIG_MASK BIT(ADS7924_CFG_INTTRIG_BIT)
+
+/* Interrupt pin polarity */
+#define ADS7924_CFG_INTPOL_LOW 0
+#define ADS7924_CFG_INTPOL_HIGH 1
+
+/* Interrupt pin signaling */
+#define ADS7924_CFG_INTTRIG_LEVEL 0
+#define ADS7924_CFG_INTTRIG_EDGE 1
+
+/* Mode control values */
+#define ADS7924_MODECNTRL_IDLE 0x00
+#define ADS7924_MODECNTRL_AWAKE 0x20
+#define ADS7924_MODECNTRL_MANUAL_SINGLE 0x30
+#define ADS7924_MODECNTRL_MANUAL_SCAN 0x32
+#define ADS7924_MODECNTRL_AUTO_SINGLE 0x31
+#define ADS7924_MODECNTRL_AUTO_SCAN 0x33
+#define ADS7924_MODECNTRL_AUTO_SINGLE_SLEEP 0x39
+#define ADS7924_MODECNTRL_AUTO_SCAN_SLEEP 0x3B
+#define ADS7924_MODECNTRL_AUTO_BURST_SLEEP 0x3F
+
+#define ADS7924_ACQTIME_MASK GENMASK(4, 0)
+
+#define ADS7924_PWRUPTIME_MASK GENMASK(4, 0)
+
+/*
+ * The power-up time is allowed to elapse whenever the device has been shutdown
+ * in idle mode. Power-up time can allow external circuits, such as an
+ * operational amplifier, between the MUXOUT and ADCIN pins to turn on.
+ * The nominal time programmed by the PUTIME[4:0] register bits is given by:
+ * t PU = PWRUPTIME[4:0] × 2 μs
+ * If a power-up time is not required, set the bits to '0' to effectively bypass.
+ */
+#define ADS7924_PWRUPTIME_US 0 /* Bypass (0us). */
+
+/*
+ * Acquisition Time according to ACQTIME[4:0] register bits.
+ * The Acquisition Time is given by:
+ * t ACQ = (ACQTIME[4:0] × 2 μs) + 6 μs
+ * Using default value of 0 for ACQTIME[4:0] results in a minimum acquisition
+ * time of 6us.
+ */
+#define ADS7924_ACQTIME_US 6
+
+/* The conversion time is always 4μs and cannot be programmed by the user. */
+#define ADS7924_CONVTIME_US 4
+
+#define ADS7924_TOTAL_CONVTIME_US (ADS7924_PWRUPTIME_US + ADS7924_ACQTIME_US + \
+ ADS7924_CONVTIME_US)
+
+#define ADS7924_V_CHAN(_chan, _addr) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = _chan, \
+ .address = _addr, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .datasheet_name = "AIN"#_chan, \
+}
+
+struct ads7924_data {
+ struct device *dev;
+ struct regmap *regmap;
+ struct regulator *vref_reg;
+
+ /* GPIO descriptor for device hard-reset pin. */
+ struct gpio_desc *reset_gpio;
+
+ /*
+ * Protects ADC ops, e.g: concurrent sysfs/buffered
+ * data reads, configuration updates
+ */
+ struct mutex lock;
+
+ /*
+ * Set to true when the ADC is switched to the continuous-conversion
+ * mode and exits from a power-down state. This flag is used to avoid
+ * getting the stale result from the conversion register.
+ */
+ bool conv_invalid;
+};
+
+static bool ads7924_is_writeable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case ADS7924_MODECNTRL_REG:
+ case ADS7924_INTCNTRL_REG:
+ case ADS7924_ULR0_REG:
+ case ADS7924_LLR0_REG:
+ case ADS7924_ULR1_REG:
+ case ADS7924_LLR1_REG:
+ case ADS7924_ULR2_REG:
+ case ADS7924_LLR2_REG:
+ case ADS7924_ULR3_REG:
+ case ADS7924_LLR3_REG:
+ case ADS7924_INTCONFIG_REG:
+ case ADS7924_SLPCONFIG_REG:
+ case ADS7924_ACQCONFIG_REG:
+ case ADS7924_PWRCONFIG_REG:
+ case ADS7924_RESET_REG:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config ads7924_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = ADS7924_RESET_REG,
+ .writeable_reg = ads7924_is_writeable_reg,
+};
+
+static const struct iio_chan_spec ads7924_channels[] = {
+ ADS7924_V_CHAN(0, ADS7924_DATA0_U_REG),
+ ADS7924_V_CHAN(1, ADS7924_DATA1_U_REG),
+ ADS7924_V_CHAN(2, ADS7924_DATA2_U_REG),
+ ADS7924_V_CHAN(3, ADS7924_DATA3_U_REG),
+};
+
+static int ads7924_get_adc_result(struct ads7924_data *data,
+ struct iio_chan_spec const *chan, int *val)
+{
+ int ret;
+ __be16 be_val;
+
+ if (chan->channel < 0 || chan->channel >= ADS7924_CHANNELS)
+ return -EINVAL;
+
+ if (data->conv_invalid) {
+ int conv_time;
+
+ conv_time = ADS7924_TOTAL_CONVTIME_US;
+ /* Allow 10% for internal clock inaccuracy. */
+ conv_time += conv_time / 10;
+ usleep_range(conv_time, conv_time + 1);
+ data->conv_invalid = false;
+ }
+
+ ret = regmap_raw_read(data->regmap, ADS7924_AUTO_INCREMENT_BIT |
+ chan->address, &be_val, sizeof(be_val));
+ if (ret)
+ return ret;
+
+ *val = be16_to_cpu(be_val) >> ADS7924_DATA_SHIFT;
+
+ return 0;
+}
+
+static int ads7924_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ int ret, vref_uv;
+ struct ads7924_data *data = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ mutex_lock(&data->lock);
+ ret = ads7924_get_adc_result(data, chan, val);
+ mutex_unlock(&data->lock);
+ if (ret < 0)
+ return ret;
+
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ vref_uv = regulator_get_voltage(data->vref_reg);
+ if (vref_uv < 0)
+ return vref_uv;
+
+ *val = vref_uv / 1000; /* Convert reg voltage to mV */
+ *val2 = ADS7924_BITS;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info ads7924_info = {
+ .read_raw = ads7924_read_raw,
+};
+
+static int ads7924_get_channels_config(struct i2c_client *client,
+ struct iio_dev *indio_dev)
+{
+ struct ads7924_data *priv = iio_priv(indio_dev);
+ struct device *dev = priv->dev;
+ struct fwnode_handle *node;
+ int num_channels = 0;
+
+ device_for_each_child_node(dev, node) {
+ u32 pval;
+ unsigned int channel;
+
+ if (fwnode_property_read_u32(node, "reg", &pval)) {
+ dev_err(dev, "invalid reg on %pfw\n", node);
+ continue;
+ }
+
+ channel = pval;
+ if (channel >= ADS7924_CHANNELS) {
+ dev_err(dev, "invalid channel index %d on %pfw\n",
+ channel, node);
+ continue;
+ }
+
+ num_channels++;
+ }
+
+ if (!num_channels)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int ads7924_set_conv_mode(struct ads7924_data *data, int mode)
+{
+ int ret;
+ unsigned int mode_field;
+ struct device *dev = data->dev;
+
+ /*
+ * When switching between modes, be sure to first select the Awake mode
+ * and then switch to the desired mode. This procedure ensures the
+ * internal control logic is properly synchronized.
+ */
+ if (mode != ADS7924_MODECNTRL_IDLE) {
+ mode_field = FIELD_PREP(ADS7924_MODECNTRL_MODE_MASK,
+ ADS7924_MODECNTRL_AWAKE);
+
+ ret = regmap_update_bits(data->regmap, ADS7924_MODECNTRL_REG,
+ ADS7924_MODECNTRL_MODE_MASK,
+ mode_field);
+ if (ret) {
+ dev_err(dev, "failed to set awake mode (%pe)\n",
+ ERR_PTR(ret));
+ return ret;
+ }
+ }
+
+ mode_field = FIELD_PREP(ADS7924_MODECNTRL_MODE_MASK, mode);
+
+ ret = regmap_update_bits(data->regmap, ADS7924_MODECNTRL_REG,
+ ADS7924_MODECNTRL_MODE_MASK, mode_field);
+ if (ret)
+ dev_err(dev, "failed to set mode %d (%pe)\n", mode,
+ ERR_PTR(ret));
+
+ return ret;
+}
+
+static int ads7924_reset(struct iio_dev *indio_dev)
+{
+ struct ads7924_data *data = iio_priv(indio_dev);
+
+ if (data->reset_gpio) {
+ gpiod_set_value(data->reset_gpio, 1); /* Assert. */
+ /* Educated guess: assert time not specified in datasheet... */
+ mdelay(100);
+ gpiod_set_value(data->reset_gpio, 0); /* Deassert. */
+ return 0;
+ }
+
+ /*
+ * A write of 10101010 to this register will generate a
+ * software reset of the ADS7924.
+ */
+ return regmap_write(data->regmap, ADS7924_RESET_REG, 0b10101010);
+};
+
+static void ads7924_reg_disable(void *data)
+{
+ regulator_disable(data);
+}
+
+static void ads7924_set_idle_mode(void *data)
+{
+ ads7924_set_conv_mode(data, ADS7924_MODECNTRL_IDLE);
+}
+
+static int ads7924_probe(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev;
+ struct ads7924_data *data;
+ struct device *dev = &client->dev;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (!indio_dev)
+ return dev_err_probe(dev, -ENOMEM,
+ "failed to allocate iio device\n");
+
+ data = iio_priv(indio_dev);
+
+ data->dev = dev;
+
+ /* Initialize the reset GPIO as output with an initial value of 0. */
+ data->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(data->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(data->reset_gpio),
+ "failed to get request reset GPIO\n");
+
+ mutex_init(&data->lock);
+
+ indio_dev->name = "ads7924";
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ indio_dev->channels = ads7924_channels;
+ indio_dev->num_channels = ARRAY_SIZE(ads7924_channels);
+ indio_dev->info = &ads7924_info;
+
+ ret = ads7924_get_channels_config(client, indio_dev);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "failed to get channels configuration\n");
+
+ data->regmap = devm_regmap_init_i2c(client, &ads7924_regmap_config);
+ if (IS_ERR(data->regmap))
+ return dev_err_probe(dev, PTR_ERR(data->regmap),
+ "failed to init regmap\n");
+
+ data->vref_reg = devm_regulator_get(dev, "vref");
+ if (IS_ERR(data->vref_reg))
+ return dev_err_probe(dev, PTR_ERR(data->vref_reg),
+ "failed to get vref regulator\n");
+
+ ret = regulator_enable(data->vref_reg);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to enable regulator\n");
+
+ ret = devm_add_action_or_reset(dev, ads7924_reg_disable, data->vref_reg);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to add regulator disable action\n");
+
+ ret = ads7924_reset(indio_dev);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "failed to reset device\n");
+
+ ret = ads7924_set_conv_mode(data, ADS7924_MODECNTRL_AUTO_SCAN);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to set conversion mode\n");
+
+ ret = devm_add_action_or_reset(dev, ads7924_set_idle_mode, data);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to add idle mode action\n");
+
+ /* Use minimum signal acquire time. */
+ ret = regmap_update_bits(data->regmap, ADS7924_ACQCONFIG_REG,
+ ADS7924_ACQTIME_MASK,
+ FIELD_PREP(ADS7924_ACQTIME_MASK, 0));
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "failed to configure signal acquire time\n");
+
+ /* Disable power-up time. */
+ ret = regmap_update_bits(data->regmap, ADS7924_PWRCONFIG_REG,
+ ADS7924_PWRUPTIME_MASK,
+ FIELD_PREP(ADS7924_PWRUPTIME_MASK, 0));
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "failed to configure power-up time\n");
+
+ data->conv_invalid = true;
+
+ ret = devm_iio_device_register(dev, indio_dev);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "failed to register IIO device\n");
+
+ return 0;
+}
+
+static const struct i2c_device_id ads7924_id[] = {
+ { "ads7924", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, ads7924_id);
+
+static const struct of_device_id ads7924_of_match[] = {
+ { .compatible = "ti,ads7924", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, ads7924_of_match);
+
+static struct i2c_driver ads7924_driver = {
+ .driver = {
+ .name = "ads7924",
+ .of_match_table = ads7924_of_match,
+ },
+ .probe_new = ads7924_probe,
+ .id_table = ads7924_id,
+};
+
+module_i2c_driver(ads7924_driver);
+
+MODULE_AUTHOR("Hugo Villeneuve <hvilleneuve@dimonoff.com>");
+MODULE_DESCRIPTION("Texas Instruments ADS7924 ADC I2C driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/adc/ti-lmp92064.c b/drivers/iio/adc/ti-lmp92064.c
new file mode 100644
index 000000000000..c30ed824924f
--- /dev/null
+++ b/drivers/iio/adc/ti-lmp92064.c
@@ -0,0 +1,332 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Texas Instruments LMP92064 SPI ADC driver
+ *
+ * Copyright (c) 2022 Leonard Göhrs <kernel@pengutronix.de>, Pengutronix
+ *
+ * Based on linux/drivers/iio/adc/ti-tsc2046.c
+ * Copyright (c) 2021 Oleksij Rempel <kernel@pengutronix.de>, Pengutronix
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/driver.h>
+
+#define TI_LMP92064_REG_CONFIG_A 0x0000
+#define TI_LMP92064_REG_CONFIG_B 0x0001
+#define TI_LMP92064_REG_CHIP_REV 0x0006
+
+#define TI_LMP92064_REG_MFR_ID1 0x000C
+#define TI_LMP92064_REG_MFR_ID2 0x000D
+
+#define TI_LMP92064_REG_REG_UPDATE 0x000F
+#define TI_LMP92064_REG_CONFIG_REG 0x0100
+#define TI_LMP92064_REG_STATUS 0x0103
+
+#define TI_LMP92064_REG_DATA_VOUT_LSB 0x0200
+#define TI_LMP92064_REG_DATA_VOUT_MSB 0x0201
+#define TI_LMP92064_REG_DATA_COUT_LSB 0x0202
+#define TI_LMP92064_REG_DATA_COUT_MSB 0x0203
+
+#define TI_LMP92064_VAL_CONFIG_A 0x99
+#define TI_LMP92064_VAL_CONFIG_B 0x00
+#define TI_LMP92064_VAL_STATUS_OK 0x01
+
+/*
+ * Channel number definitions for the two channels of the device
+ * - IN Current (INC)
+ * - IN Voltage (INV)
+ */
+#define TI_LMP92064_CHAN_INC 0
+#define TI_LMP92064_CHAN_INV 1
+
+static const struct regmap_range lmp92064_readable_reg_ranges[] = {
+ regmap_reg_range(TI_LMP92064_REG_CONFIG_A, TI_LMP92064_REG_CHIP_REV),
+ regmap_reg_range(TI_LMP92064_REG_MFR_ID1, TI_LMP92064_REG_MFR_ID2),
+ regmap_reg_range(TI_LMP92064_REG_REG_UPDATE, TI_LMP92064_REG_REG_UPDATE),
+ regmap_reg_range(TI_LMP92064_REG_CONFIG_REG, TI_LMP92064_REG_CONFIG_REG),
+ regmap_reg_range(TI_LMP92064_REG_STATUS, TI_LMP92064_REG_STATUS),
+ regmap_reg_range(TI_LMP92064_REG_DATA_VOUT_LSB, TI_LMP92064_REG_DATA_COUT_MSB),
+};
+
+static const struct regmap_access_table lmp92064_readable_regs = {
+ .yes_ranges = lmp92064_readable_reg_ranges,
+ .n_yes_ranges = ARRAY_SIZE(lmp92064_readable_reg_ranges),
+};
+
+static const struct regmap_range lmp92064_writable_reg_ranges[] = {
+ regmap_reg_range(TI_LMP92064_REG_CONFIG_A, TI_LMP92064_REG_CONFIG_B),
+ regmap_reg_range(TI_LMP92064_REG_REG_UPDATE, TI_LMP92064_REG_REG_UPDATE),
+ regmap_reg_range(TI_LMP92064_REG_CONFIG_REG, TI_LMP92064_REG_CONFIG_REG),
+};
+
+static const struct regmap_access_table lmp92064_writable_regs = {
+ .yes_ranges = lmp92064_writable_reg_ranges,
+ .n_yes_ranges = ARRAY_SIZE(lmp92064_writable_reg_ranges),
+};
+
+static const struct regmap_config lmp92064_spi_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .max_register = TI_LMP92064_REG_DATA_COUT_MSB,
+ .rd_table = &lmp92064_readable_regs,
+ .wr_table = &lmp92064_writable_regs,
+};
+
+struct lmp92064_adc_priv {
+ int shunt_resistor_uohm;
+ struct spi_device *spi;
+ struct regmap *regmap;
+};
+
+static const struct iio_chan_spec lmp92064_adc_channels[] = {
+ {
+ .type = IIO_CURRENT,
+ .address = TI_LMP92064_CHAN_INC,
+ .info_mask_separate =
+ BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
+ .datasheet_name = "INC",
+ },
+ {
+ .type = IIO_VOLTAGE,
+ .address = TI_LMP92064_CHAN_INV,
+ .info_mask_separate =
+ BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
+ .datasheet_name = "INV",
+ },
+};
+
+static int lmp92064_read_meas(struct lmp92064_adc_priv *priv, u16 *res)
+{
+ __be16 raw[2];
+ int ret;
+
+ /*
+ * The ADC only latches in new samples if all DATA registers are read
+ * in descending sequential order.
+ * The ADC auto-decrements the register index with each clocked byte.
+ * Read both channels in single SPI transfer by selecting the highest
+ * register using the command below and clocking out all four data
+ * bytes.
+ */
+
+ ret = regmap_bulk_read(priv->regmap, TI_LMP92064_REG_DATA_COUT_MSB,
+ &raw, sizeof(raw));
+
+ if (ret) {
+ dev_err(&priv->spi->dev, "regmap_bulk_read failed: %pe\n",
+ ERR_PTR(ret));
+ return ret;
+ }
+
+ res[0] = be16_to_cpu(raw[0]);
+ res[1] = be16_to_cpu(raw[1]);
+
+ return 0;
+}
+
+static int lmp92064_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ struct lmp92064_adc_priv *priv = iio_priv(indio_dev);
+ u16 raw[2];
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = lmp92064_read_meas(priv, raw);
+ if (ret < 0)
+ return ret;
+
+ *val = (chan->address == TI_LMP92064_CHAN_INC) ? raw[0] : raw[1];
+
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ if (chan->address == TI_LMP92064_CHAN_INC) {
+ /*
+ * processed (mA) = raw * current_lsb (mA)
+ * current_lsb (mA) = shunt_voltage_lsb (nV) / shunt_resistor (uOhm)
+ * shunt_voltage_lsb (nV) = 81920000 / 4096 = 20000
+ */
+ *val = 20000;
+ *val2 = priv->shunt_resistor_uohm;
+ } else {
+ /*
+ * processed (mV) = raw * voltage_lsb (mV)
+ * voltage_lsb (mV) = 2048 / 4096
+ */
+ *val = 2048;
+ *val2 = 4096;
+ }
+ return IIO_VAL_FRACTIONAL;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int lmp92064_reset(struct lmp92064_adc_priv *priv,
+ struct gpio_desc *gpio_reset)
+{
+ unsigned int status;
+ int ret, i;
+
+ if (gpio_reset) {
+ /*
+ * Perform a hard reset if gpio_reset is available.
+ * The datasheet specifies a very low 3.5ns reset pulse duration and does not
+ * specify how long to wait after a reset to access the device.
+ * Use more conservative pulse lengths to allow analog RC filtering of the
+ * reset line at the board level (as recommended in the datasheet).
+ */
+ gpiod_set_value_cansleep(gpio_reset, 1);
+ usleep_range(1, 10);
+ gpiod_set_value_cansleep(gpio_reset, 0);
+ usleep_range(500, 750);
+ } else {
+ /*
+ * Perform a soft-reset if not.
+ * Also write default values to the config registers that are not
+ * affected by soft reset.
+ */
+ ret = regmap_write(priv->regmap, TI_LMP92064_REG_CONFIG_A,
+ TI_LMP92064_VAL_CONFIG_A);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_write(priv->regmap, TI_LMP92064_REG_CONFIG_B,
+ TI_LMP92064_VAL_CONFIG_B);
+ if (ret < 0)
+ return ret;
+ }
+
+ /*
+ * Wait for the device to signal readiness to prevent reading bogus data
+ * and make sure device is actually connected.
+ * The datasheet does not specify how long this takes but usually it is
+ * not more than 3-4 iterations of this loop.
+ */
+ for (i = 0; i < 10; i++) {
+ ret = regmap_read(priv->regmap, TI_LMP92064_REG_STATUS, &status);
+ if (ret < 0)
+ return ret;
+
+ if (status == TI_LMP92064_VAL_STATUS_OK)
+ return 0;
+
+ usleep_range(1000, 2000);
+ }
+
+ /*
+ * No (correct) response received.
+ * Device is mostly likely not connected to the bus.
+ */
+ return -ENXIO;
+}
+
+static const struct iio_info lmp92064_adc_info = {
+ .read_raw = lmp92064_read_raw,
+};
+
+static int lmp92064_adc_probe(struct spi_device *spi)
+{
+ struct device *dev = &spi->dev;
+ struct lmp92064_adc_priv *priv;
+ struct gpio_desc *gpio_reset;
+ struct iio_dev *indio_dev;
+ u32 shunt_resistor_uohm;
+ struct regmap *regmap;
+ int ret;
+
+ ret = spi_setup(spi);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Error in SPI setup\n");
+
+ regmap = devm_regmap_init_spi(spi, &lmp92064_spi_regmap_config);
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap),
+ "Failed to set up SPI regmap\n");
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ priv = iio_priv(indio_dev);
+
+ priv->spi = spi;
+ priv->regmap = regmap;
+
+ ret = device_property_read_u32(dev, "shunt-resistor-micro-ohms",
+ &shunt_resistor_uohm);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "Failed to get shunt-resistor value\n");
+
+ /*
+ * The shunt resistance is passed to userspace as the denominator of an iio
+ * fraction. Make sure it is in range for that.
+ */
+ if (shunt_resistor_uohm == 0 || shunt_resistor_uohm > INT_MAX) {
+ dev_err(dev, "Shunt resistance is out of range\n");
+ return -EINVAL;
+ }
+
+ priv->shunt_resistor_uohm = shunt_resistor_uohm;
+
+ ret = devm_regulator_get_enable(dev, "vdd");
+ if (ret)
+ return ret;
+
+ ret = devm_regulator_get_enable(dev, "vdig");
+ if (ret)
+ return ret;
+
+ gpio_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(gpio_reset))
+ return dev_err_probe(dev, PTR_ERR(gpio_reset),
+ "Failed to get GPIO reset pin\n");
+
+ ret = lmp92064_reset(priv, gpio_reset);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to reset device\n");
+
+ indio_dev->name = "lmp92064";
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = lmp92064_adc_channels;
+ indio_dev->num_channels = ARRAY_SIZE(lmp92064_adc_channels);
+ indio_dev->info = &lmp92064_adc_info;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct spi_device_id lmp92064_id_table[] = {
+ { "lmp92064" },
+ {}
+};
+MODULE_DEVICE_TABLE(spi, lmp92064_id_table);
+
+static const struct of_device_id lmp92064_of_table[] = {
+ { .compatible = "ti,lmp92064" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, lmp92064_of_table);
+
+static struct spi_driver lmp92064_adc_driver = {
+ .driver = {
+ .name = "lmp92064",
+ .of_match_table = lmp92064_of_table,
+ },
+ .probe = lmp92064_adc_probe,
+ .id_table = lmp92064_id_table,
+};
+module_spi_driver(lmp92064_adc_driver);
+
+MODULE_AUTHOR("Leonard Göhrs <kernel@pengutronix.de>");
+MODULE_DESCRIPTION("TI LMP92064 ADC");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/adc/xilinx-ams.c b/drivers/iio/adc/xilinx-ams.c
index a507d2e17079..34cf336b3490 100644
--- a/drivers/iio/adc/xilinx-ams.c
+++ b/drivers/iio/adc/xilinx-ams.c
@@ -1220,8 +1220,7 @@ static int ams_init_module(struct iio_dev *indio_dev,
int num_channels = 0;
int ret;
- if (fwnode_property_match_string(fwnode, "compatible",
- "xlnx,zynqmp-ams-ps") == 0) {
+ if (fwnode_device_is_compatible(fwnode, "xlnx,zynqmp-ams-ps")) {
ams->ps_base = fwnode_iomap(fwnode, 0);
if (!ams->ps_base)
return -ENXIO;
@@ -1232,8 +1231,7 @@ static int ams_init_module(struct iio_dev *indio_dev,
/* add PS channels to iio device channels */
memcpy(channels, ams_ps_channels, sizeof(ams_ps_channels));
num_channels = ARRAY_SIZE(ams_ps_channels);
- } else if (fwnode_property_match_string(fwnode, "compatible",
- "xlnx,zynqmp-ams-pl") == 0) {
+ } else if (fwnode_device_is_compatible(fwnode, "xlnx,zynqmp-ams-pl")) {
ams->pl_base = fwnode_iomap(fwnode, 0);
if (!ams->pl_base)
return -ENXIO;
@@ -1247,8 +1245,7 @@ static int ams_init_module(struct iio_dev *indio_dev,
num_channels += AMS_PL_MAX_FIXED_CHANNEL;
num_channels = ams_get_ext_chan(fwnode, channels,
num_channels);
- } else if (fwnode_property_match_string(fwnode, "compatible",
- "xlnx,zynqmp-ams") == 0) {
+ } else if (fwnode_device_is_compatible(fwnode, "xlnx,zynqmp-ams")) {
/* add AMS channels to iio device channels */
memcpy(channels, ams_ctrl_channels, sizeof(ams_ctrl_channels));
num_channels += ARRAY_SIZE(ams_ctrl_channels);
diff --git a/drivers/iio/cdc/ad7746.c b/drivers/iio/cdc/ad7746.c
index 6f68651ce1d5..a1db5469f2d1 100644
--- a/drivers/iio/cdc/ad7746.c
+++ b/drivers/iio/cdc/ad7746.c
@@ -285,8 +285,7 @@ static int ad7746_select_channel(struct iio_dev *indio_dev,
if (ret < 0)
return ret;
- if (chip->capdac_set != chan->channel)
- chip->capdac_set = chan->channel;
+ chip->capdac_set = chan->channel;
break;
case IIO_VOLTAGE:
case IIO_TEMP:
diff --git a/drivers/iio/chemical/scd30_core.c b/drivers/iio/chemical/scd30_core.c
index 682fca39d14d..7be5a45cf71a 100644
--- a/drivers/iio/chemical/scd30_core.c
+++ b/drivers/iio/chemical/scd30_core.c
@@ -354,7 +354,7 @@ static ssize_t sampling_frequency_available_show(struct device *dev, struct devi
ssize_t len = 0;
do {
- len += scnprintf(buf + len, PAGE_SIZE - len, "0.%09u ", 1000000000 / i);
+ len += sysfs_emit_at(buf, len, "0.%09u ", 1000000000 / i);
/*
* Not all values fit PAGE_SIZE buffer hence print every 6th
* (each frequency differs by 6s in time domain from the
@@ -380,7 +380,7 @@ static ssize_t calibration_auto_enable_show(struct device *dev, struct device_at
ret = scd30_command_read(state, CMD_ASC, &val);
mutex_unlock(&state->lock);
- return ret ?: sprintf(buf, "%d\n", val);
+ return ret ?: sysfs_emit(buf, "%d\n", val);
}
static ssize_t calibration_auto_enable_store(struct device *dev, struct device_attribute *attr,
@@ -414,7 +414,7 @@ static ssize_t calibration_forced_value_show(struct device *dev, struct device_a
ret = scd30_command_read(state, CMD_FRC, &val);
mutex_unlock(&state->lock);
- return ret ?: sprintf(buf, "%d\n", val);
+ return ret ?: sysfs_emit(buf, "%d\n", val);
}
static ssize_t calibration_forced_value_store(struct device *dev, struct device_attribute *attr,
@@ -642,10 +642,8 @@ static int scd30_setup_trigger(struct iio_dev *indio_dev)
trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name,
iio_device_id(indio_dev));
- if (!trig) {
- dev_err(dev, "failed to allocate trigger\n");
- return -ENOMEM;
- }
+ if (!trig)
+ return dev_err_probe(dev, -ENOMEM, "failed to allocate trigger\n");
trig->ops = &scd30_trigger_ops;
iio_trigger_set_drvdata(trig, indio_dev);
@@ -667,9 +665,9 @@ static int scd30_setup_trigger(struct iio_dev *indio_dev)
IRQF_NO_AUTOEN,
indio_dev->name, indio_dev);
if (ret)
- dev_err(dev, "failed to request irq\n");
+ return dev_err_probe(dev, ret, "failed to request irq\n");
- return ret;
+ return 0;
}
int scd30_probe(struct device *dev, int irq, const char *name, void *priv,
@@ -717,17 +715,13 @@ int scd30_probe(struct device *dev, int irq, const char *name, void *priv,
return ret;
ret = scd30_reset(state);
- if (ret) {
- dev_err(dev, "failed to reset device: %d\n", ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to reset device\n");
if (state->irq > 0) {
ret = scd30_setup_trigger(indio_dev);
- if (ret) {
- dev_err(dev, "failed to setup trigger: %d\n", ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to setup trigger\n");
}
ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, scd30_trigger_handler, NULL);
@@ -735,23 +729,17 @@ int scd30_probe(struct device *dev, int irq, const char *name, void *priv,
return ret;
ret = scd30_command_read(state, CMD_FW_VERSION, &val);
- if (ret) {
- dev_err(dev, "failed to read firmware version: %d\n", ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to read firmware version\n");
dev_info(dev, "firmware version: %d.%d\n", val >> 8, (char)val);
ret = scd30_command_write(state, CMD_MEAS_INTERVAL, state->meas_interval);
- if (ret) {
- dev_err(dev, "failed to set measurement interval: %d\n", ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to set measurement interval\n");
ret = scd30_command_write(state, CMD_START_MEAS, state->pressure_comp);
- if (ret) {
- dev_err(dev, "failed to start measurement: %d\n", ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to start measurement\n");
ret = devm_add_action_or_reset(dev, scd30_stop_meas, state);
if (ret)
diff --git a/drivers/iio/common/scmi_sensors/scmi_iio.c b/drivers/iio/common/scmi_sensors/scmi_iio.c
index d92f7f651f7b..0c2caf3570db 100644
--- a/drivers/iio/common/scmi_sensors/scmi_iio.c
+++ b/drivers/iio/common/scmi_sensors/scmi_iio.c
@@ -400,12 +400,12 @@ static ssize_t scmi_iio_get_raw_available(struct iio_dev *iio_dev,
rem = do_div(resolution,
int_pow(10, abs(exponent))
);
- len = scnprintf(buf, PAGE_SIZE,
+ len = sysfs_emit(buf,
"[%lld %llu.%llu %lld]\n", min_range,
resolution, rem, max_range);
} else {
resolution = resolution * int_pow(10, exponent);
- len = scnprintf(buf, PAGE_SIZE, "[%lld %llu %lld]\n",
+ len = sysfs_emit(buf, "[%lld %llu %lld]\n",
min_range, resolution, max_range);
}
}
diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
index 80521bd28d0f..d3f90cf86143 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -162,10 +162,10 @@ config AD5696_I2C
depends on I2C
select AD5686
help
- Say yes here to build support for Analog Devices AD5311R, AD5338R,
- AD5671R, AD5673R, AD5675R, AD5677R, AD5691R, AD5692R, AD5693, AD5693R,
- AD5694, AD5694R, AD5695R, AD5696, and AD5696R Digital to Analog
- converters.
+ Say yes here to build support for Analog Devices AD5311R, AD5337,
+ AD5338R, AD5671R, AD5673R, AD5675R, AD5677R, AD5691R, AD5692R, AD5693,
+ AD5693R, AD5694, AD5694R, AD5695R, AD5696, and AD5696R Digital to
+ Analog converters.
To compile this driver as a module, choose M here: the module will be
called ad5696.
@@ -357,6 +357,19 @@ config MAX517
This driver can also be built as a module. If so, the module
will be called max517.
+config MAX5522
+ tristate "Maxim MAX5522 DAC driver"
+ depends on SPI_MASTER
+ select REGMAP_SPI
+ help
+ Say Y here if you want to build a driver for the Maxim MAX5522.
+
+ MAX5522 is a dual, ultra-low-power, 10-Bit, voltage-output
+ digital to analog converter (DAC) offering rail-to-rail buffered
+ voltage outputs.
+
+ If compiled as a module, it will be called max5522.
+
config MAX5821
tristate "Maxim MAX5821 DAC driver"
depends on I2C
diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile
index ec3e42713f00..6c74fea21736 100644
--- a/drivers/iio/dac/Makefile
+++ b/drivers/iio/dac/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_LTC2632) += ltc2632.o
obj-$(CONFIG_LTC2688) += ltc2688.o
obj-$(CONFIG_M62332) += m62332.o
obj-$(CONFIG_MAX517) += max517.o
+obj-$(CONFIG_MAX5522) += max5522.o
obj-$(CONFIG_MAX5821) += max5821.o
obj-$(CONFIG_MCP4725) += mcp4725.o
obj-$(CONFIG_MCP4922) += mcp4922.o
diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c
index 15361d8bbf94..57cc0f0eedc6 100644
--- a/drivers/iio/dac/ad5686.c
+++ b/drivers/iio/dac/ad5686.c
@@ -258,6 +258,7 @@ static const struct iio_chan_spec name[] = { \
DECLARE_AD5693_CHANNELS(ad5310r_channels, 10, 2);
DECLARE_AD5693_CHANNELS(ad5311r_channels, 10, 6);
+DECLARE_AD5338_CHANNELS(ad5337r_channels, 8, 8);
DECLARE_AD5338_CHANNELS(ad5338r_channels, 10, 6);
DECLARE_AD5676_CHANNELS(ad5672_channels, 12, 4);
DECLARE_AD5679_CHANNELS(ad5674r_channels, 12, 4);
@@ -283,6 +284,12 @@ static const struct ad5686_chip_info ad5686_chip_info_tbl[] = {
.num_channels = 1,
.regmap_type = AD5693_REGMAP,
},
+ [ID_AD5337R] = {
+ .channels = ad5337r_channels,
+ .int_vref_mv = 2500,
+ .num_channels = 2,
+ .regmap_type = AD5686_REGMAP,
+ },
[ID_AD5338R] = {
.channels = ad5338r_channels,
.int_vref_mv = 2500,
diff --git a/drivers/iio/dac/ad5686.h b/drivers/iio/dac/ad5686.h
index b7ade3a6b9b6..760f852911df 100644
--- a/drivers/iio/dac/ad5686.h
+++ b/drivers/iio/dac/ad5686.h
@@ -54,6 +54,7 @@
enum ad5686_supported_device_ids {
ID_AD5310R,
ID_AD5311R,
+ ID_AD5337R,
ID_AD5338R,
ID_AD5671R,
ID_AD5672R,
diff --git a/drivers/iio/dac/ad5696-i2c.c b/drivers/iio/dac/ad5696-i2c.c
index 160e80cf9135..8a95f0278018 100644
--- a/drivers/iio/dac/ad5696-i2c.c
+++ b/drivers/iio/dac/ad5696-i2c.c
@@ -72,6 +72,7 @@ static void ad5686_i2c_remove(struct i2c_client *i2c)
static const struct i2c_device_id ad5686_i2c_id[] = {
{"ad5311r", ID_AD5311R},
+ {"ad5337r", ID_AD5337R},
{"ad5338r", ID_AD5338R},
{"ad5671r", ID_AD5671R},
{"ad5673r", ID_AD5673R},
@@ -92,6 +93,7 @@ MODULE_DEVICE_TABLE(i2c, ad5686_i2c_id);
static const struct of_device_id ad5686_of_match[] = {
{ .compatible = "adi,ad5311r" },
+ { .compatible = "adi,ad5337r" },
{ .compatible = "adi,ad5338r" },
{ .compatible = "adi,ad5671r" },
{ .compatible = "adi,ad5675r" },
diff --git a/drivers/iio/dac/max5522.c b/drivers/iio/dac/max5522.c
new file mode 100644
index 000000000000..00ba4e98fb9c
--- /dev/null
+++ b/drivers/iio/dac/max5522.c
@@ -0,0 +1,207 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Maxim MAX5522
+ * Dual, Ultra-Low-Power 10-Bit, Voltage-Output DACs
+ *
+ * Copyright 2022 Timesys Corp.
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+
+#include <linux/iio/iio.h>
+
+#define MAX5522_MAX_ADDR 15
+#define MAX5522_CTRL_NONE 0
+#define MAX5522_CTRL_LOAD_IN_A 9
+#define MAX5522_CTRL_LOAD_IN_B 10
+
+#define MAX5522_REG_DATA(x) ((x) + MAX5522_CTRL_LOAD_IN_A)
+
+struct max5522_chip_info {
+ const char *name;
+ const struct iio_chan_spec *channels;
+ unsigned int num_channels;
+};
+
+struct max5522_state {
+ struct regmap *regmap;
+ const struct max5522_chip_info *chip_info;
+ unsigned short dac_cache[2];
+ struct regulator *vrefin_reg;
+};
+
+#define MAX5522_CHANNEL(chan) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .output = 1, \
+ .channel = chan, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 10, \
+ .storagebits = 16, \
+ .shift = 2, \
+ } \
+}
+
+const struct iio_chan_spec max5522_channels[] = {
+ MAX5522_CHANNEL(0),
+ MAX5522_CHANNEL(1),
+};
+
+enum max5522_type {
+ ID_MAX5522,
+};
+
+static const struct max5522_chip_info max5522_chip_info_tbl[] = {
+ [ID_MAX5522] = {
+ .name = "max5522",
+ .channels = max5522_channels,
+ .num_channels = 2,
+ },
+};
+
+static inline int max5522_info_to_reg(struct iio_chan_spec const *chan)
+{
+ return MAX5522_REG_DATA(chan->channel);
+}
+
+static int max5522_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long info)
+{
+ struct max5522_state *state = iio_priv(indio_dev);
+ int ret;
+
+ switch (info) {
+ case IIO_CHAN_INFO_RAW:
+ *val = state->dac_cache[chan->channel];
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ ret = regulator_get_voltage(state->vrefin_reg);
+ if (ret < 0)
+ return -EINVAL;
+ *val = ret / 1000;
+ *val2 = 10;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ default:
+ return -EINVAL;
+ }
+
+ return -EINVAL;
+}
+
+static int max5522_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long info)
+{
+ struct max5522_state *state = iio_priv(indio_dev);
+ int rval;
+
+ if (val > 1023 || val < 0)
+ return -EINVAL;
+
+ rval = regmap_write(state->regmap, max5522_info_to_reg(chan),
+ val << chan->scan_type.shift);
+ if (rval < 0)
+ return rval;
+
+ state->dac_cache[chan->channel] = val;
+
+ return 0;
+}
+
+static const struct iio_info max5522_info = {
+ .read_raw = max5522_read_raw,
+ .write_raw = max5522_write_raw,
+};
+
+static const struct regmap_config max5522_regmap_config = {
+ .reg_bits = 4,
+ .val_bits = 12,
+ .max_register = MAX5522_MAX_ADDR,
+};
+
+static int max5522_spi_probe(struct spi_device *spi)
+{
+ const struct spi_device_id *id = spi_get_device_id(spi);
+ struct iio_dev *indio_dev;
+ struct max5522_state *state;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*state));
+ if (indio_dev == NULL) {
+ dev_err(&spi->dev, "failed to allocate iio device\n");
+ return -ENOMEM;
+ }
+
+ state = iio_priv(indio_dev);
+ state->chip_info = device_get_match_data(&spi->dev);
+ if (!state->chip_info) {
+ state->chip_info =
+ (struct max5522_chip_info *)(id->driver_data);
+ if (!state->chip_info)
+ return -EINVAL;
+ }
+
+ state->vrefin_reg = devm_regulator_get(&spi->dev, "vrefin");
+ if (IS_ERR(state->vrefin_reg))
+ return dev_err_probe(&spi->dev, PTR_ERR(state->vrefin_reg),
+ "Vrefin regulator not specified\n");
+
+ ret = regulator_enable(state->vrefin_reg);
+ if (ret) {
+ return dev_err_probe(&spi->dev, ret,
+ "Failed to enable vref regulators\n");
+ }
+
+ state->regmap = devm_regmap_init_spi(spi, &max5522_regmap_config);
+
+ if (IS_ERR(state->regmap))
+ return PTR_ERR(state->regmap);
+
+ indio_dev->info = &max5522_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = max5522_channels;
+ indio_dev->num_channels = ARRAY_SIZE(max5522_channels);
+ indio_dev->name = max5522_chip_info_tbl[ID_MAX5522].name;
+
+ return devm_iio_device_register(&spi->dev, indio_dev);
+}
+
+static const struct spi_device_id max5522_ids[] = {
+ { "max5522", (kernel_ulong_t)&max5522_chip_info_tbl[ID_MAX5522] },
+ {}
+};
+MODULE_DEVICE_TABLE(spi, max5522_ids);
+
+static const struct of_device_id max5522_of_match[] = {
+ {
+ .compatible = "maxim,max5522",
+ .data = &max5522_chip_info_tbl[ID_MAX5522],
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, max5522_of_match);
+
+static struct spi_driver max5522_spi_driver = {
+ .driver = {
+ .name = "max5522",
+ .of_match_table = max5522_of_match,
+ },
+ .probe = max5522_spi_probe,
+ .id_table = max5522_ids,
+};
+module_spi_driver(max5522_spi_driver);
+
+MODULE_AUTHOR("Angelo Dureghello <angelo.dureghello@timesys.com");
+MODULE_DESCRIPTION("MAX5522 DAC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/imu/bno055/bno055_ser_trace.c b/drivers/iio/imu/bno055/bno055_ser_trace.c
index 48397b66daef..ab564186d19c 100644
--- a/drivers/iio/imu/bno055/bno055_ser_trace.c
+++ b/drivers/iio/imu/bno055/bno055_ser_trace.c
@@ -1,4 +1,4 @@
-//SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0
/*
* bno055_ser Trace Support
diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c
index e692dfeeda44..53ba020fa5d0 100644
--- a/drivers/iio/imu/kmx61.c
+++ b/drivers/iio/imu/kmx61.c
@@ -649,7 +649,7 @@ static int kmx61_chip_update_thresholds(struct kmx61_data *data)
KMX61_REG_WUF_TIMER,
data->wake_duration);
if (ret < 0) {
- dev_err(&data->client->dev, "Errow writing reg_wuf_timer\n");
+ dev_err(&data->client->dev, "Error writing reg_wuf_timer\n");
return ret;
}
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
index 5b6f195748fc..499fcf8875b4 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
@@ -93,7 +93,7 @@ enum st_lsm6dsx_hw_id {
.endianness = IIO_LE, \
}, \
.event_spec = &st_lsm6dsx_event, \
- .ext_info = st_lsm6dsx_accel_ext_info, \
+ .ext_info = st_lsm6dsx_ext_info, \
.num_event_specs = 1, \
}
@@ -113,6 +113,7 @@ enum st_lsm6dsx_hw_id {
.storagebits = 16, \
.endianness = IIO_LE, \
}, \
+ .ext_info = st_lsm6dsx_ext_info, \
}
struct st_lsm6dsx_reg {
@@ -528,7 +529,7 @@ st_lsm6dsx_device_set_enable(struct st_lsm6dsx_sensor *sensor, bool enable)
}
static const
-struct iio_chan_spec_ext_info __maybe_unused st_lsm6dsx_accel_ext_info[] = {
+struct iio_chan_spec_ext_info __maybe_unused st_lsm6dsx_ext_info[] = {
IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, st_lsm6dsx_get_mount_matrix),
{ }
};
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c
index f2b64b4956a3..c1b444520d2a 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c
@@ -704,18 +704,18 @@ static ssize_t st_lsm6dsx_shub_scale_avail(struct device *dev,
static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(st_lsm6dsx_shub_sampling_freq_avail);
static IIO_DEVICE_ATTR(in_scale_available, 0444,
st_lsm6dsx_shub_scale_avail, NULL, 0);
-static struct attribute *st_lsm6dsx_ext_attributes[] = {
+static struct attribute *st_lsm6dsx_shub_attributes[] = {
&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
&iio_dev_attr_in_scale_available.dev_attr.attr,
NULL,
};
-static const struct attribute_group st_lsm6dsx_ext_attribute_group = {
- .attrs = st_lsm6dsx_ext_attributes,
+static const struct attribute_group st_lsm6dsx_shub_attribute_group = {
+ .attrs = st_lsm6dsx_shub_attributes,
};
-static const struct iio_info st_lsm6dsx_ext_info = {
- .attrs = &st_lsm6dsx_ext_attribute_group,
+static const struct iio_info st_lsm6dsx_shub_info = {
+ .attrs = &st_lsm6dsx_shub_attribute_group,
.read_raw = st_lsm6dsx_shub_read_raw,
.write_raw = st_lsm6dsx_shub_write_raw,
.hwfifo_set_watermark = st_lsm6dsx_set_watermark,
@@ -737,7 +737,7 @@ st_lsm6dsx_shub_alloc_iiodev(struct st_lsm6dsx_hw *hw,
return NULL;
iio_dev->modes = INDIO_DIRECT_MODE;
- iio_dev->info = &st_lsm6dsx_ext_info;
+ iio_dev->info = &st_lsm6dsx_shub_info;
sensor = iio_priv(iio_dev);
sensor->id = id;
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index 52e690f031cb..c117f50d0cf3 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -8,30 +8,32 @@
#define pr_fmt(fmt) "iio-core: " fmt
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/idr.h>
-#include <linux/kdev_t.h>
-#include <linux/err.h>
+#include <linux/anon_inodes.h>
+#include <linux/cdev.h>
+#include <linux/debugfs.h>
#include <linux/device.h>
+#include <linux/err.h>
#include <linux/fs.h>
+#include <linux/idr.h>
+#include <linux/kdev_t.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/poll.h>
#include <linux/property.h>
#include <linux/sched.h>
-#include <linux/wait.h>
-#include <linux/cdev.h>
#include <linux/slab.h>
-#include <linux/anon_inodes.h>
-#include <linux/debugfs.h>
-#include <linux/mutex.h>
-#include <linux/iio/iio.h>
+#include <linux/wait.h>
+
+#include <linux/iio/buffer.h>
+#include <linux/iio/buffer_impl.h>
+#include <linux/iio/events.h>
#include <linux/iio/iio-opaque.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
#include "iio_core.h"
#include "iio_core_trigger.h"
-#include <linux/iio/sysfs.h>
-#include <linux/iio/events.h>
-#include <linux/iio/buffer.h>
-#include <linux/iio/buffer_impl.h>
/* IDA to assign each registered device a unique id */
static DEFINE_IDA(iio_ida);
@@ -205,36 +207,6 @@ bool iio_buffer_enabled(struct iio_dev *indio_dev)
}
EXPORT_SYMBOL_GPL(iio_buffer_enabled);
-/**
- * iio_sysfs_match_string_with_gaps - matches given string in an array with gaps
- * @array: array of strings
- * @n: number of strings in the array
- * @str: string to match with
- *
- * Returns index of @str in the @array or -EINVAL, similar to match_string().
- * Uses sysfs_streq instead of strcmp for matching.
- *
- * This routine will look for a string in an array of strings.
- * The search will continue until the element is found or the n-th element
- * is reached, regardless of any NULL elements in the array.
- */
-static int iio_sysfs_match_string_with_gaps(const char * const *array, size_t n,
- const char *str)
-{
- const char *item;
- int index;
-
- for (index = 0; index < n; index++) {
- item = array[index];
- if (!item)
- continue;
- if (sysfs_streq(item, str))
- return index;
- }
-
- return -EINVAL;
-}
-
#if defined(CONFIG_DEBUG_FS)
/*
* There's also a CONFIG_DEBUG_FS guard in include/linux/iio/iio.h for
@@ -569,7 +541,7 @@ ssize_t iio_enum_write(struct iio_dev *indio_dev,
if (!e->set)
return -EINVAL;
- ret = iio_sysfs_match_string_with_gaps(e->items, e->num_items, buf);
+ ret = __sysfs_match_string(e->items, e->num_items, buf);
if (ret < 0)
return ret;
diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile
index 6f23817fae6f..d74d2b5ff14c 100644
--- a/drivers/iio/light/Makefile
+++ b/drivers/iio/light/Makefile
@@ -39,7 +39,6 @@ obj-$(CONFIG_NOA1305) += noa1305.o
obj-$(CONFIG_OPT3001) += opt3001.o
obj-$(CONFIG_PA12203001) += pa12203001.o
obj-$(CONFIG_RPR0521) += rpr0521.o
-obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o
obj-$(CONFIG_SI1133) += si1133.o
obj-$(CONFIG_SI1145) += si1145.o
obj-$(CONFIG_STK3310) += stk3310.o
@@ -48,6 +47,7 @@ obj-$(CONFIG_ST_UVIS25_I2C) += st_uvis25_i2c.o
obj-$(CONFIG_ST_UVIS25_SPI) += st_uvis25_spi.o
obj-$(CONFIG_TCS3414) += tcs3414.o
obj-$(CONFIG_TCS3472) += tcs3472.o
+obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o
obj-$(CONFIG_TSL2583) += tsl2583.o
obj-$(CONFIG_TSL2591) += tsl2591.o
obj-$(CONFIG_TSL2772) += tsl2772.o
diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c
index 5a1a625d8d16..eb1aedad7edc 100644
--- a/drivers/iio/light/hid-sensor-als.c
+++ b/drivers/iio/light/hid-sensor-als.c
@@ -86,6 +86,7 @@ static int als_read_raw(struct iio_dev *indio_dev,
long mask)
{
struct als_state *als_state = iio_priv(indio_dev);
+ struct hid_sensor_hub_device *hsdev = als_state->common_attributes.hsdev;
int report_id = -1;
u32 address;
int ret_type;
@@ -110,11 +111,8 @@ static int als_read_raw(struct iio_dev *indio_dev,
hid_sensor_power_state(&als_state->common_attributes,
true);
*val = sensor_hub_input_attr_get_raw_value(
- als_state->common_attributes.hsdev,
- HID_USAGE_SENSOR_ALS, address,
- report_id,
- SENSOR_HUB_SYNC,
- min < 0);
+ hsdev, hsdev->usage, address, report_id,
+ SENSOR_HUB_SYNC, min < 0);
hid_sensor_power_state(&als_state->common_attributes,
false);
} else {
@@ -259,9 +257,7 @@ static int als_parse_report(struct platform_device *pdev,
dev_dbg(&pdev->dev, "als %x:%x\n", st->als_illum.index,
st->als_illum.report_id);
- st->scale_precision = hid_sensor_format_scale(
- HID_USAGE_SENSOR_ALS,
- &st->als_illum,
+ st->scale_precision = hid_sensor_format_scale(usage_id, &st->als_illum,
&st->scale_pre_decml, &st->scale_post_decml);
return ret;
@@ -285,7 +281,8 @@ static int hid_als_probe(struct platform_device *pdev)
als_state->common_attributes.hsdev = hsdev;
als_state->common_attributes.pdev = pdev;
- ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_ALS,
+ ret = hid_sensor_parse_common_attributes(hsdev,
+ hsdev->usage,
&als_state->common_attributes,
als_sensitivity_addresses,
ARRAY_SIZE(als_sensitivity_addresses));
@@ -303,7 +300,8 @@ static int hid_als_probe(struct platform_device *pdev)
ret = als_parse_report(pdev, hsdev,
(struct iio_chan_spec *)indio_dev->channels,
- HID_USAGE_SENSOR_ALS, als_state);
+ hsdev->usage,
+ als_state);
if (ret) {
dev_err(&pdev->dev, "failed to setup attributes\n");
return ret;
@@ -333,8 +331,7 @@ static int hid_als_probe(struct platform_device *pdev)
als_state->callbacks.send_event = als_proc_event;
als_state->callbacks.capture_sample = als_capture_sample;
als_state->callbacks.pdev = pdev;
- ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_ALS,
- &als_state->callbacks);
+ ret = sensor_hub_register_callback(hsdev, hsdev->usage, &als_state->callbacks);
if (ret < 0) {
dev_err(&pdev->dev, "callback reg failed\n");
goto error_iio_unreg;
@@ -356,7 +353,7 @@ static int hid_als_remove(struct platform_device *pdev)
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct als_state *als_state = iio_priv(indio_dev);
- sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_ALS);
+ sensor_hub_remove_callback(hsdev, hsdev->usage);
iio_device_unregister(indio_dev);
hid_sensor_remove_trigger(indio_dev, &als_state->common_attributes);
@@ -368,6 +365,10 @@ static const struct platform_device_id hid_als_ids[] = {
/* Format: HID-SENSOR-usage_id_in_hex_lowercase */
.name = "HID-SENSOR-200041",
},
+ {
+ /* Format: HID-SENSOR-custom_sensor_tag-usage_id_in_hex_lowercase */
+ .name = "HID-SENSOR-LISS-0041",
+ },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, hid_als_ids);
diff --git a/drivers/iio/light/hid-sensor-prox.c b/drivers/iio/light/hid-sensor-prox.c
index f10fa2abfe72..a47591e1bad9 100644
--- a/drivers/iio/light/hid-sensor-prox.c
+++ b/drivers/iio/light/hid-sensor-prox.c
@@ -61,6 +61,7 @@ static int prox_read_raw(struct iio_dev *indio_dev,
long mask)
{
struct prox_state *prox_state = iio_priv(indio_dev);
+ struct hid_sensor_hub_device *hsdev;
int report_id = -1;
u32 address;
int ret_type;
@@ -75,6 +76,7 @@ static int prox_read_raw(struct iio_dev *indio_dev,
report_id = prox_state->prox_attr.report_id;
min = prox_state->prox_attr.logical_minimum;
address = HID_USAGE_SENSOR_HUMAN_PRESENCE;
+ hsdev = prox_state->common_attributes.hsdev;
break;
default:
report_id = -1;
@@ -84,11 +86,8 @@ static int prox_read_raw(struct iio_dev *indio_dev,
hid_sensor_power_state(&prox_state->common_attributes,
true);
*val = sensor_hub_input_attr_get_raw_value(
- prox_state->common_attributes.hsdev,
- HID_USAGE_SENSOR_PROX, address,
- report_id,
- SENSOR_HUB_SYNC,
- min < 0);
+ hsdev, hsdev->usage, address, report_id,
+ SENSOR_HUB_SYNC, min < 0);
hid_sensor_power_state(&prox_state->common_attributes,
false);
} else {
@@ -191,10 +190,16 @@ static int prox_capture_sample(struct hid_sensor_hub_device *hsdev,
switch (usage_id) {
case HID_USAGE_SENSOR_HUMAN_PRESENCE:
- prox_state->human_presence = *(u32 *)raw_data;
- ret = 0;
- break;
- default:
+ switch (raw_len) {
+ case 1:
+ prox_state->human_presence = *(u8 *)raw_data;
+ return 0;
+ case 4:
+ prox_state->human_presence = *(u32 *)raw_data;
+ return 0;
+ default:
+ break;
+ }
break;
}
@@ -244,7 +249,7 @@ static int hid_prox_probe(struct platform_device *pdev)
prox_state->common_attributes.hsdev = hsdev;
prox_state->common_attributes.pdev = pdev;
- ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_PROX,
+ ret = hid_sensor_parse_common_attributes(hsdev, hsdev->usage,
&prox_state->common_attributes,
prox_sensitivity_addresses,
ARRAY_SIZE(prox_sensitivity_addresses));
@@ -262,7 +267,7 @@ static int hid_prox_probe(struct platform_device *pdev)
ret = prox_parse_report(pdev, hsdev,
(struct iio_chan_spec *)indio_dev->channels,
- HID_USAGE_SENSOR_PROX, prox_state);
+ hsdev->usage, prox_state);
if (ret) {
dev_err(&pdev->dev, "failed to setup attributes\n");
return ret;
@@ -291,8 +296,8 @@ static int hid_prox_probe(struct platform_device *pdev)
prox_state->callbacks.send_event = prox_proc_event;
prox_state->callbacks.capture_sample = prox_capture_sample;
prox_state->callbacks.pdev = pdev;
- ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_PROX,
- &prox_state->callbacks);
+ ret = sensor_hub_register_callback(hsdev, hsdev->usage,
+ &prox_state->callbacks);
if (ret < 0) {
dev_err(&pdev->dev, "callback reg failed\n");
goto error_iio_unreg;
@@ -314,7 +319,7 @@ static int hid_prox_remove(struct platform_device *pdev)
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct prox_state *prox_state = iio_priv(indio_dev);
- sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_PROX);
+ sensor_hub_remove_callback(hsdev, hsdev->usage);
iio_device_unregister(indio_dev);
hid_sensor_remove_trigger(indio_dev, &prox_state->common_attributes);
@@ -326,6 +331,10 @@ static const struct platform_device_id hid_prox_ids[] = {
/* Format: HID-SENSOR-usage_id_in_hex_lowercase */
.name = "HID-SENSOR-200011",
},
+ {
+ /* Format: HID-SENSOR-tag-usage_id_in_hex_lowercase */
+ .name = "HID-SENSOR-LISS-0226",
+ },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, hid_prox_ids);
diff --git a/drivers/iio/light/max44009.c b/drivers/iio/light/max44009.c
index 801e5a0ad496..3dadace09fe2 100644
--- a/drivers/iio/light/max44009.c
+++ b/drivers/iio/light/max44009.c
@@ -487,8 +487,7 @@ static irqreturn_t max44009_threaded_irq_handler(int irq, void *p)
return IRQ_NONE;
}
-static int max44009_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int max44009_probe(struct i2c_client *client)
{
struct max44009_data *data;
struct iio_dev *indio_dev;
@@ -538,7 +537,7 @@ static struct i2c_driver max44009_driver = {
.driver = {
.name = MAX44009_DRV_NAME,
},
- .probe = max44009_probe,
+ .probe_new = max44009_probe,
.id_table = max44009_id,
};
module_i2c_driver(max44009_driver);
diff --git a/drivers/iio/light/tsl2563.c b/drivers/iio/light/tsl2563.c
index d0e42b73203a..f2f55239a072 100644
--- a/drivers/iio/light/tsl2563.c
+++ b/drivers/iio/light/tsl2563.c
@@ -11,69 +11,63 @@
* Amit Kucheria <amit.kucheria@verdurent.com>
*/
-#include <linux/module.h>
-#include <linux/mod_devicetable.h>
-#include <linux/property.h>
+#include <linux/bits.h>
+#include <linux/delay.h>
+#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
-#include <linux/sched.h>
+#include <linux/math.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
#include <linux/mutex.h>
-#include <linux/delay.h>
#include <linux/pm.h>
-#include <linux/err.h>
+#include <linux/property.h>
+#include <linux/sched.h>
#include <linux/slab.h>
+#include <linux/iio/events.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
-#include <linux/iio/events.h>
-#include <linux/platform_data/tsl2563.h>
/* Use this many bits for fraction part. */
#define ADC_FRAC_BITS 14
/* Given number of 1/10000's in ADC_FRAC_BITS precision. */
-#define FRAC10K(f) (((f) * (1L << (ADC_FRAC_BITS))) / (10000))
+#define FRAC10K(f) (((f) * BIT(ADC_FRAC_BITS)) / (10000))
/* Bits used for fraction in calibration coefficients.*/
#define CALIB_FRAC_BITS 10
-/* 0.5 in CALIB_FRAC_BITS precision */
-#define CALIB_FRAC_HALF (1 << (CALIB_FRAC_BITS - 1))
-/* Make a fraction from a number n that was multiplied with b. */
-#define CALIB_FRAC(n, b) (((n) << CALIB_FRAC_BITS) / (b))
/* Decimal 10^(digits in sysfs presentation) */
#define CALIB_BASE_SYSFS 1000
-#define TSL2563_CMD 0x80
-#define TSL2563_CLEARINT 0x40
+#define TSL2563_CMD BIT(7)
+#define TSL2563_CLEARINT BIT(6)
#define TSL2563_REG_CTRL 0x00
#define TSL2563_REG_TIMING 0x01
-#define TSL2563_REG_LOWLOW 0x02 /* data0 low threshold, 2 bytes */
-#define TSL2563_REG_LOWHIGH 0x03
-#define TSL2563_REG_HIGHLOW 0x04 /* data0 high threshold, 2 bytes */
-#define TSL2563_REG_HIGHHIGH 0x05
+#define TSL2563_REG_LOW 0x02 /* data0 low threshold, 2 bytes */
+#define TSL2563_REG_HIGH 0x04 /* data0 high threshold, 2 bytes */
#define TSL2563_REG_INT 0x06
#define TSL2563_REG_ID 0x0a
-#define TSL2563_REG_DATA0LOW 0x0c /* broadband sensor value, 2 bytes */
-#define TSL2563_REG_DATA0HIGH 0x0d
-#define TSL2563_REG_DATA1LOW 0x0e /* infrared sensor value, 2 bytes */
-#define TSL2563_REG_DATA1HIGH 0x0f
+#define TSL2563_REG_DATA0 0x0c /* broadband sensor value, 2 bytes */
+#define TSL2563_REG_DATA1 0x0e /* infrared sensor value, 2 bytes */
#define TSL2563_CMD_POWER_ON 0x03
#define TSL2563_CMD_POWER_OFF 0x00
-#define TSL2563_CTRL_POWER_MASK 0x03
+#define TSL2563_CTRL_POWER_MASK GENMASK(1, 0)
#define TSL2563_TIMING_13MS 0x00
#define TSL2563_TIMING_100MS 0x01
#define TSL2563_TIMING_400MS 0x02
-#define TSL2563_TIMING_MASK 0x03
+#define TSL2563_TIMING_MASK GENMASK(1, 0)
#define TSL2563_TIMING_GAIN16 0x10
#define TSL2563_TIMING_GAIN1 0x00
#define TSL2563_INT_DISABLED 0x00
#define TSL2563_INT_LEVEL 0x10
-#define TSL2563_INT_PERSIST(n) ((n) & 0x0F)
+#define TSL2563_INT_MASK GENMASK(5, 4)
+#define TSL2563_INT_PERSIST(n) ((n) & GENMASK(3, 0))
struct tsl2563_gainlevel_coeff {
u8 gaintime;
@@ -161,24 +155,16 @@ static int tsl2563_configure(struct tsl2563_chip *chip)
chip->gainlevel->gaintime);
if (ret)
goto error_ret;
- ret = i2c_smbus_write_byte_data(chip->client,
- TSL2563_CMD | TSL2563_REG_HIGHLOW,
- chip->high_thres & 0xFF);
- if (ret)
- goto error_ret;
- ret = i2c_smbus_write_byte_data(chip->client,
- TSL2563_CMD | TSL2563_REG_HIGHHIGH,
- (chip->high_thres >> 8) & 0xFF);
+ ret = i2c_smbus_write_word_data(chip->client,
+ TSL2563_CMD | TSL2563_REG_HIGH,
+ chip->high_thres);
if (ret)
goto error_ret;
- ret = i2c_smbus_write_byte_data(chip->client,
- TSL2563_CMD | TSL2563_REG_LOWLOW,
- chip->low_thres & 0xFF);
+ ret = i2c_smbus_write_word_data(chip->client,
+ TSL2563_CMD | TSL2563_REG_LOW,
+ chip->low_thres);
if (ret)
goto error_ret;
- ret = i2c_smbus_write_byte_data(chip->client,
- TSL2563_CMD | TSL2563_REG_LOWHIGH,
- (chip->low_thres >> 8) & 0xFF);
/*
* Interrupt register is automatically written anyway if it is relevant
* so is not here.
@@ -223,6 +209,24 @@ static int tsl2563_read_id(struct tsl2563_chip *chip, u8 *id)
return 0;
}
+static int tsl2563_configure_irq(struct tsl2563_chip *chip, bool enable)
+{
+ int ret;
+
+ chip->intr &= ~TSL2563_INT_MASK;
+ if (enable)
+ chip->intr |= TSL2563_INT_LEVEL;
+
+ ret = i2c_smbus_write_byte_data(chip->client,
+ TSL2563_CMD | TSL2563_REG_INT,
+ chip->intr);
+ if (ret < 0)
+ return ret;
+
+ chip->int_enabled = enable;
+ return 0;
+}
+
/*
* "Normalized" ADC value is one obtained with 400ms of integration time and
* 16x gain. This function returns the number of bits of shift needed to
@@ -325,13 +329,13 @@ static int tsl2563_get_adc(struct tsl2563_chip *chip)
while (retry) {
ret = i2c_smbus_read_word_data(client,
- TSL2563_CMD | TSL2563_REG_DATA0LOW);
+ TSL2563_CMD | TSL2563_REG_DATA0);
if (ret < 0)
goto out;
adc0 = ret;
ret = i2c_smbus_read_word_data(client,
- TSL2563_CMD | TSL2563_REG_DATA1LOW);
+ TSL2563_CMD | TSL2563_REG_DATA1);
if (ret < 0)
goto out;
adc1 = ret;
@@ -352,12 +356,12 @@ out:
static inline int tsl2563_calib_to_sysfs(u32 calib)
{
- return (int) (((calib * CALIB_BASE_SYSFS) +
- CALIB_FRAC_HALF) >> CALIB_FRAC_BITS);
+ return (int)DIV_ROUND_CLOSEST(calib * CALIB_BASE_SYSFS, BIT(CALIB_FRAC_BITS));
}
static inline u32 tsl2563_calib_from_sysfs(int value)
{
+ /* Make a fraction from a number n that was multiplied with b. */
return (((u32) value) << CALIB_FRAC_BITS) / CALIB_BASE_SYSFS;
}
@@ -584,20 +588,18 @@ static int tsl2563_write_thresh(struct iio_dev *indio_dev,
{
struct tsl2563_chip *chip = iio_priv(indio_dev);
int ret;
- u8 address;
+
+ mutex_lock(&chip->lock);
if (dir == IIO_EV_DIR_RISING)
- address = TSL2563_REG_HIGHLOW;
+ ret = i2c_smbus_write_word_data(chip->client,
+ TSL2563_CMD | TSL2563_REG_HIGH, val);
else
- address = TSL2563_REG_LOWLOW;
- mutex_lock(&chip->lock);
- ret = i2c_smbus_write_byte_data(chip->client, TSL2563_CMD | address,
- val & 0xFF);
+ ret = i2c_smbus_write_word_data(chip->client,
+ TSL2563_CMD | TSL2563_REG_LOW, val);
if (ret)
goto error_ret;
- ret = i2c_smbus_write_byte_data(chip->client,
- TSL2563_CMD | (address + 1),
- (val >> 8) & 0xFF);
+
if (dir == IIO_EV_DIR_RISING)
chip->high_thres = val;
else
@@ -634,9 +636,7 @@ static int tsl2563_write_interrupt_config(struct iio_dev *indio_dev,
int ret = 0;
mutex_lock(&chip->lock);
- if (state && !(chip->intr & 0x30)) {
- chip->intr &= ~0x30;
- chip->intr |= 0x10;
+ if (state && !(chip->intr & TSL2563_INT_MASK)) {
/* ensure the chip is actually on */
cancel_delayed_work_sync(&chip->poweroff_work);
if (!tsl2563_get_power(chip)) {
@@ -647,18 +647,11 @@ static int tsl2563_write_interrupt_config(struct iio_dev *indio_dev,
if (ret)
goto out;
}
- ret = i2c_smbus_write_byte_data(chip->client,
- TSL2563_CMD | TSL2563_REG_INT,
- chip->intr);
- chip->int_enabled = true;
+ ret = tsl2563_configure_irq(chip, true);
}
- if (!state && (chip->intr & 0x30)) {
- chip->intr &= ~0x30;
- ret = i2c_smbus_write_byte_data(chip->client,
- TSL2563_CMD | TSL2563_REG_INT,
- chip->intr);
- chip->int_enabled = false;
+ if (!state && (chip->intr & TSL2563_INT_MASK)) {
+ ret = tsl2563_configure_irq(chip, false);
/* now the interrupt is not enabled, we can go to sleep */
schedule_delayed_work(&chip->poweroff_work, 5 * HZ);
}
@@ -682,7 +675,7 @@ static int tsl2563_read_interrupt_config(struct iio_dev *indio_dev,
if (ret < 0)
return ret;
- return !!(ret & 0x30);
+ return !!(ret & TSL2563_INT_MASK);
}
static const struct iio_info tsl2563_info_no_irq = {
@@ -701,13 +694,14 @@ static const struct iio_info tsl2563_info = {
static int tsl2563_probe(struct i2c_client *client)
{
+ struct device *dev = &client->dev;
struct iio_dev *indio_dev;
struct tsl2563_chip *chip;
- struct tsl2563_platform_data *pdata = client->dev.platform_data;
- int err = 0;
+ unsigned long irq_flags;
u8 id = 0;
+ int err;
- indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*chip));
if (!indio_dev)
return -ENOMEM;
@@ -717,16 +711,12 @@ static int tsl2563_probe(struct i2c_client *client)
chip->client = client;
err = tsl2563_detect(chip);
- if (err) {
- dev_err(&client->dev, "detect error %d\n", -err);
- return err;
- }
+ if (err)
+ return dev_err_probe(dev, err, "detect error\n");
err = tsl2563_read_id(chip, &id);
- if (err) {
- dev_err(&client->dev, "read id error %d\n", -err);
- return err;
- }
+ if (err)
+ return dev_err_probe(dev, err, "read id error\n");
mutex_init(&chip->lock);
@@ -738,16 +728,10 @@ static int tsl2563_probe(struct i2c_client *client)
chip->calib0 = tsl2563_calib_from_sysfs(CALIB_BASE_SYSFS);
chip->calib1 = tsl2563_calib_from_sysfs(CALIB_BASE_SYSFS);
- if (pdata) {
- chip->cover_comp_gain = pdata->cover_comp_gain;
- } else {
- err = device_property_read_u32(&client->dev, "amstaos,cover-comp-gain",
- &chip->cover_comp_gain);
- if (err)
- chip->cover_comp_gain = 1;
- }
+ chip->cover_comp_gain = 1;
+ device_property_read_u32(dev, "amstaos,cover-comp-gain", &chip->cover_comp_gain);
- dev_info(&client->dev, "model %d, rev. %d\n", id >> 4, id & 0x0f);
+ dev_info(dev, "model %d, rev. %d\n", id >> 4, id & 0x0f);
indio_dev->name = client->name;
indio_dev->channels = tsl2563_channels;
indio_dev->num_channels = ARRAY_SIZE(tsl2563_channels);
@@ -759,23 +743,24 @@ static int tsl2563_probe(struct i2c_client *client)
indio_dev->info = &tsl2563_info_no_irq;
if (client->irq) {
- err = devm_request_threaded_irq(&client->dev, client->irq,
+ irq_flags = irq_get_trigger_type(client->irq);
+ if (irq_flags == IRQF_TRIGGER_NONE)
+ irq_flags = IRQF_TRIGGER_RISING;
+ irq_flags |= IRQF_ONESHOT;
+
+ err = devm_request_threaded_irq(dev, client->irq,
NULL,
&tsl2563_event_handler,
- IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ irq_flags,
"tsl2563_event",
indio_dev);
- if (err) {
- dev_err(&client->dev, "irq request error %d\n", -err);
- return err;
- }
+ if (err)
+ return dev_err_probe(dev, err, "irq request error\n");
}
err = tsl2563_configure(chip);
- if (err) {
- dev_err(&client->dev, "configure error %d\n", -err);
- return err;
- }
+ if (err)
+ return dev_err_probe(dev, err, "configure error\n");
INIT_DELAYED_WORK(&chip->poweroff_work, tsl2563_poweroff_work);
@@ -784,7 +769,7 @@ static int tsl2563_probe(struct i2c_client *client)
err = iio_device_register(indio_dev);
if (err) {
- dev_err(&client->dev, "iio registration error %d\n", -err);
+ dev_err_probe(dev, err, "iio registration error\n");
goto fail;
}
@@ -804,15 +789,13 @@ static void tsl2563_remove(struct i2c_client *client)
if (!chip->int_enabled)
cancel_delayed_work_sync(&chip->poweroff_work);
/* Ensure that interrupts are disabled - then flush any bottom halves */
- chip->intr &= ~0x30;
- i2c_smbus_write_byte_data(chip->client, TSL2563_CMD | TSL2563_REG_INT,
- chip->intr);
+ tsl2563_configure_irq(chip, false);
tsl2563_set_power(chip, 0);
}
static int tsl2563_suspend(struct device *dev)
{
- struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct tsl2563_chip *chip = iio_priv(indio_dev);
int ret;
@@ -831,7 +814,7 @@ out:
static int tsl2563_resume(struct device *dev)
{
- struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct tsl2563_chip *chip = iio_priv(indio_dev);
int ret;
diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c
index cc1a2062e76d..6bdfce9747f9 100644
--- a/drivers/iio/light/vcnl4000.c
+++ b/drivers/iio/light/vcnl4000.c
@@ -60,8 +60,11 @@
#define VCNL4200_AL_CONF 0x00 /* Ambient light configuration */
#define VCNL4200_PS_CONF1 0x03 /* Proximity configuration */
+#define VCNL4040_PS_THDL_LM 0x06 /* Proximity threshold low */
+#define VCNL4040_PS_THDH_LM 0x07 /* Proximity threshold high */
#define VCNL4200_PS_DATA 0x08 /* Proximity data */
#define VCNL4200_AL_DATA 0x09 /* Ambient light data */
+#define VCNL4040_INT_FLAGS 0x0b /* Interrupt register */
#define VCNL4200_DEV_ID 0x0e /* Device ID, slave address and version */
#define VCNL4040_DEV_ID 0x0c /* Device ID and version */
@@ -78,6 +81,9 @@
#define VCNL4040_ALS_CONF_ALS_SHUTDOWN BIT(0)
#define VCNL4040_PS_CONF1_PS_SHUTDOWN BIT(0)
#define VCNL4040_PS_CONF2_PS_IT GENMASK(3, 1) /* Proximity integration time */
+#define VCNL4040_PS_CONF2_PS_INT GENMASK(9, 8) /* Proximity interrupt mode */
+#define VCNL4040_PS_IF_AWAY BIT(8) /* Proximity event cross low threshold */
+#define VCNL4040_PS_IF_CLOSE BIT(9) /* Proximity event cross high threshold */
/* Bit masks for interrupt registers. */
#define VCNL4010_INT_THR_SEL BIT(0) /* Select threshold interrupt source */
@@ -138,6 +144,7 @@ struct vcnl4000_data {
enum vcnl4000_device_ids id;
int rev;
int al_scale;
+ u8 ps_int; /* proximity interrupt mode */
const struct vcnl4000_chip_spec *chip_spec;
struct mutex vcnl4000_lock;
struct vcnl4200_channel vcnl4200_al;
@@ -150,11 +157,13 @@ struct vcnl4000_chip_spec {
struct iio_chan_spec const *channels;
const int num_channels;
const struct iio_info *info;
- bool irq_support;
+ const struct iio_buffer_setup_ops *buffer_setup_ops;
int (*init)(struct vcnl4000_data *data);
int (*measure_light)(struct vcnl4000_data *data, int *val);
int (*measure_proximity)(struct vcnl4000_data *data, int *val);
int (*set_power_state)(struct vcnl4000_data *data, bool on);
+ irqreturn_t (*irq_thread)(int irq, void *priv);
+ irqreturn_t (*trig_buffer_func)(int irq, void *priv);
};
static const struct i2c_device_id vcnl4000_id[] = {
@@ -254,6 +263,10 @@ static int vcnl4200_set_power_state(struct vcnl4000_data *data, bool on)
{
int ret;
+ /* Do not power down if interrupts are enabled */
+ if (!on && data->ps_int)
+ return 0;
+
ret = vcnl4000_write_als_enable(data, on);
if (ret < 0)
return ret;
@@ -295,6 +308,7 @@ static int vcnl4200_init(struct vcnl4000_data *data)
dev_dbg(&data->client->dev, "device id 0x%x", id);
data->rev = (ret >> 8) & 0xf;
+ data->ps_int = 0;
data->vcnl4200_al.reg = VCNL4200_AL_DATA;
data->vcnl4200_ps.reg = VCNL4200_PS_DATA;
@@ -795,6 +809,64 @@ static int vcnl4010_write_event(struct iio_dev *indio_dev,
}
}
+static int vcnl4040_read_event(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int *val, int *val2)
+{
+ int ret;
+ struct vcnl4000_data *data = iio_priv(indio_dev);
+
+ switch (dir) {
+ case IIO_EV_DIR_RISING:
+ ret = i2c_smbus_read_word_data(data->client,
+ VCNL4040_PS_THDH_LM);
+ if (ret < 0)
+ return ret;
+ *val = ret;
+ return IIO_VAL_INT;
+ case IIO_EV_DIR_FALLING:
+ ret = i2c_smbus_read_word_data(data->client,
+ VCNL4040_PS_THDL_LM);
+ if (ret < 0)
+ return ret;
+ *val = ret;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int vcnl4040_write_event(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int val, int val2)
+{
+ int ret;
+ struct vcnl4000_data *data = iio_priv(indio_dev);
+
+ switch (dir) {
+ case IIO_EV_DIR_RISING:
+ ret = i2c_smbus_write_word_data(data->client,
+ VCNL4040_PS_THDH_LM, val);
+ if (ret < 0)
+ return ret;
+ return IIO_VAL_INT;
+ case IIO_EV_DIR_FALLING:
+ ret = i2c_smbus_write_word_data(data->client,
+ VCNL4040_PS_THDL_LM, val);
+ if (ret < 0)
+ return ret;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
static bool vcnl4010_is_thr_enabled(struct vcnl4000_data *data)
{
int ret;
@@ -877,6 +949,86 @@ static int vcnl4010_write_event_config(struct iio_dev *indio_dev,
}
}
+static int vcnl4040_read_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir)
+{
+ int ret;
+ struct vcnl4000_data *data = iio_priv(indio_dev);
+
+ ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);
+ if (ret < 0)
+ return ret;
+
+ data->ps_int = FIELD_GET(VCNL4040_PS_CONF2_PS_INT, ret);
+
+ return (dir == IIO_EV_DIR_RISING) ?
+ FIELD_GET(VCNL4040_PS_IF_AWAY, ret) :
+ FIELD_GET(VCNL4040_PS_IF_CLOSE, ret);
+}
+
+static int vcnl4040_write_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir, int state)
+{
+ int ret;
+ u16 val, mask;
+ struct vcnl4000_data *data = iio_priv(indio_dev);
+
+ mutex_lock(&data->vcnl4000_lock);
+
+ ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);
+ if (ret < 0)
+ goto out;
+
+ if (dir == IIO_EV_DIR_RISING)
+ mask = VCNL4040_PS_IF_AWAY;
+ else
+ mask = VCNL4040_PS_IF_CLOSE;
+
+ val = state ? (ret | mask) : (ret & ~mask);
+
+ data->ps_int = FIELD_GET(VCNL4040_PS_CONF2_PS_INT, val);
+ ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, val);
+
+out:
+ mutex_unlock(&data->vcnl4000_lock);
+ data->chip_spec->set_power_state(data, data->ps_int != 0);
+
+ return ret;
+}
+
+static irqreturn_t vcnl4040_irq_thread(int irq, void *p)
+{
+ struct iio_dev *indio_dev = p;
+ struct vcnl4000_data *data = iio_priv(indio_dev);
+ int ret;
+
+ ret = i2c_smbus_read_word_data(data->client, VCNL4040_INT_FLAGS);
+ if (ret < 0)
+ return IRQ_HANDLED;
+
+ if (ret & VCNL4040_PS_IF_CLOSE) {
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_RISING),
+ iio_get_time_ns(indio_dev));
+ }
+
+ if (ret & VCNL4040_PS_IF_AWAY) {
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_FALLING),
+ iio_get_time_ns(indio_dev));
+ }
+
+ return IRQ_HANDLED;
+}
+
static ssize_t vcnl4000_read_near_level(struct iio_dev *indio_dev,
uintptr_t priv,
const struct iio_chan_spec *chan,
@@ -887,6 +1039,134 @@ static ssize_t vcnl4000_read_near_level(struct iio_dev *indio_dev,
return sprintf(buf, "%u\n", data->near_level);
}
+static irqreturn_t vcnl4010_irq_thread(int irq, void *p)
+{
+ struct iio_dev *indio_dev = p;
+ struct vcnl4000_data *data = iio_priv(indio_dev);
+ unsigned long isr;
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(data->client, VCNL4010_ISR);
+ if (ret < 0)
+ goto end;
+
+ isr = ret;
+
+ if (isr & VCNL4010_INT_THR) {
+ if (test_bit(VCNL4010_INT_THR_LOW, &isr)) {
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(
+ IIO_PROXIMITY,
+ 1,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_FALLING),
+ iio_get_time_ns(indio_dev));
+ }
+
+ if (test_bit(VCNL4010_INT_THR_HIGH, &isr)) {
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(
+ IIO_PROXIMITY,
+ 1,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_RISING),
+ iio_get_time_ns(indio_dev));
+ }
+
+ i2c_smbus_write_byte_data(data->client, VCNL4010_ISR,
+ isr & VCNL4010_INT_THR);
+ }
+
+ if (isr & VCNL4010_INT_DRDY && iio_buffer_enabled(indio_dev))
+ iio_trigger_poll_chained(indio_dev->trig);
+
+end:
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t vcnl4010_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct vcnl4000_data *data = iio_priv(indio_dev);
+ const unsigned long *active_scan_mask = indio_dev->active_scan_mask;
+ u16 buffer[8] __aligned(8) = {0}; /* 1x16-bit + naturally aligned ts */
+ bool data_read = false;
+ unsigned long isr;
+ int val = 0;
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(data->client, VCNL4010_ISR);
+ if (ret < 0)
+ goto end;
+
+ isr = ret;
+
+ if (test_bit(0, active_scan_mask)) {
+ if (test_bit(VCNL4010_INT_PROXIMITY, &isr)) {
+ ret = vcnl4000_read_data(data,
+ VCNL4000_PS_RESULT_HI,
+ &val);
+ if (ret < 0)
+ goto end;
+
+ buffer[0] = val;
+ data_read = true;
+ }
+ }
+
+ ret = i2c_smbus_write_byte_data(data->client, VCNL4010_ISR,
+ isr & VCNL4010_INT_DRDY);
+ if (ret < 0)
+ goto end;
+
+ if (!data_read)
+ goto end;
+
+ iio_push_to_buffers_with_timestamp(indio_dev, buffer,
+ iio_get_time_ns(indio_dev));
+
+end:
+ iio_trigger_notify_done(indio_dev->trig);
+ return IRQ_HANDLED;
+}
+
+static int vcnl4010_buffer_postenable(struct iio_dev *indio_dev)
+{
+ struct vcnl4000_data *data = iio_priv(indio_dev);
+ int ret;
+ int cmd;
+
+ /* Do not enable the buffer if we are already capturing events. */
+ if (vcnl4010_is_in_periodic_mode(data))
+ return -EBUSY;
+
+ ret = i2c_smbus_write_byte_data(data->client, VCNL4010_INT_CTRL,
+ VCNL4010_INT_PROX_EN);
+ if (ret < 0)
+ return ret;
+
+ cmd = VCNL4000_SELF_TIMED_EN | VCNL4000_PROX_EN;
+ return i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND, cmd);
+}
+
+static int vcnl4010_buffer_predisable(struct iio_dev *indio_dev)
+{
+ struct vcnl4000_data *data = iio_priv(indio_dev);
+ int ret;
+
+ ret = i2c_smbus_write_byte_data(data->client, VCNL4010_INT_CTRL, 0);
+ if (ret < 0)
+ return ret;
+
+ return i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND, 0);
+}
+
+static const struct iio_buffer_setup_ops vcnl4010_buffer_ops = {
+ .postenable = &vcnl4010_buffer_postenable,
+ .predisable = &vcnl4010_buffer_predisable,
+};
+
static const struct iio_chan_spec_ext_info vcnl4000_ext_info[] = {
{
.name = "nearlevel",
@@ -912,6 +1192,18 @@ static const struct iio_event_spec vcnl4000_event_spec[] = {
}
};
+static const struct iio_event_spec vcnl4040_event_spec[] = {
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_RISING,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE),
+ }, {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_FALLING,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE),
+ },
+};
+
static const struct iio_chan_spec vcnl4000_channels[] = {
{
.type = IIO_LIGHT,
@@ -960,6 +1252,8 @@ static const struct iio_chan_spec vcnl4040_channels[] = {
BIT(IIO_CHAN_INFO_INT_TIME),
.info_mask_separate_available = BIT(IIO_CHAN_INFO_INT_TIME),
.ext_info = vcnl4000_ext_info,
+ .event_spec = vcnl4040_event_spec,
+ .num_event_specs = ARRAY_SIZE(vcnl4040_event_spec),
}
};
@@ -980,6 +1274,10 @@ static const struct iio_info vcnl4010_info = {
static const struct iio_info vcnl4040_info = {
.read_raw = vcnl4000_read_raw,
.write_raw = vcnl4040_write_raw,
+ .read_event_value = vcnl4040_read_event,
+ .write_event_value = vcnl4040_write_event,
+ .read_event_config = vcnl4040_read_event_config,
+ .write_event_config = vcnl4040_write_event_config,
.read_avail = vcnl4040_read_avail,
};
@@ -993,7 +1291,6 @@ static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = {
.channels = vcnl4000_channels,
.num_channels = ARRAY_SIZE(vcnl4000_channels),
.info = &vcnl4000_info,
- .irq_support = false,
},
[VCNL4010] = {
.prod = "VCNL4010/4020",
@@ -1004,7 +1301,9 @@ static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = {
.channels = vcnl4010_channels,
.num_channels = ARRAY_SIZE(vcnl4010_channels),
.info = &vcnl4010_info,
- .irq_support = true,
+ .irq_thread = vcnl4010_irq_thread,
+ .trig_buffer_func = vcnl4010_trigger_handler,
+ .buffer_setup_ops = &vcnl4010_buffer_ops,
},
[VCNL4040] = {
.prod = "VCNL4040",
@@ -1015,7 +1314,7 @@ static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = {
.channels = vcnl4040_channels,
.num_channels = ARRAY_SIZE(vcnl4040_channels),
.info = &vcnl4040_info,
- .irq_support = false,
+ .irq_thread = vcnl4040_irq_thread,
},
[VCNL4200] = {
.prod = "VCNL4200",
@@ -1026,138 +1325,9 @@ static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = {
.channels = vcnl4000_channels,
.num_channels = ARRAY_SIZE(vcnl4000_channels),
.info = &vcnl4000_info,
- .irq_support = false,
},
};
-static irqreturn_t vcnl4010_irq_thread(int irq, void *p)
-{
- struct iio_dev *indio_dev = p;
- struct vcnl4000_data *data = iio_priv(indio_dev);
- unsigned long isr;
- int ret;
-
- ret = i2c_smbus_read_byte_data(data->client, VCNL4010_ISR);
- if (ret < 0)
- goto end;
-
- isr = ret;
-
- if (isr & VCNL4010_INT_THR) {
- if (test_bit(VCNL4010_INT_THR_LOW, &isr)) {
- iio_push_event(indio_dev,
- IIO_UNMOD_EVENT_CODE(
- IIO_PROXIMITY,
- 1,
- IIO_EV_TYPE_THRESH,
- IIO_EV_DIR_FALLING),
- iio_get_time_ns(indio_dev));
- }
-
- if (test_bit(VCNL4010_INT_THR_HIGH, &isr)) {
- iio_push_event(indio_dev,
- IIO_UNMOD_EVENT_CODE(
- IIO_PROXIMITY,
- 1,
- IIO_EV_TYPE_THRESH,
- IIO_EV_DIR_RISING),
- iio_get_time_ns(indio_dev));
- }
-
- i2c_smbus_write_byte_data(data->client, VCNL4010_ISR,
- isr & VCNL4010_INT_THR);
- }
-
- if (isr & VCNL4010_INT_DRDY && iio_buffer_enabled(indio_dev))
- iio_trigger_poll_chained(indio_dev->trig);
-
-end:
- return IRQ_HANDLED;
-}
-
-static irqreturn_t vcnl4010_trigger_handler(int irq, void *p)
-{
- struct iio_poll_func *pf = p;
- struct iio_dev *indio_dev = pf->indio_dev;
- struct vcnl4000_data *data = iio_priv(indio_dev);
- const unsigned long *active_scan_mask = indio_dev->active_scan_mask;
- u16 buffer[8] __aligned(8) = {0}; /* 1x16-bit + naturally aligned ts */
- bool data_read = false;
- unsigned long isr;
- int val = 0;
- int ret;
-
- ret = i2c_smbus_read_byte_data(data->client, VCNL4010_ISR);
- if (ret < 0)
- goto end;
-
- isr = ret;
-
- if (test_bit(0, active_scan_mask)) {
- if (test_bit(VCNL4010_INT_PROXIMITY, &isr)) {
- ret = vcnl4000_read_data(data,
- VCNL4000_PS_RESULT_HI,
- &val);
- if (ret < 0)
- goto end;
-
- buffer[0] = val;
- data_read = true;
- }
- }
-
- ret = i2c_smbus_write_byte_data(data->client, VCNL4010_ISR,
- isr & VCNL4010_INT_DRDY);
- if (ret < 0)
- goto end;
-
- if (!data_read)
- goto end;
-
- iio_push_to_buffers_with_timestamp(indio_dev, buffer,
- iio_get_time_ns(indio_dev));
-
-end:
- iio_trigger_notify_done(indio_dev->trig);
- return IRQ_HANDLED;
-}
-
-static int vcnl4010_buffer_postenable(struct iio_dev *indio_dev)
-{
- struct vcnl4000_data *data = iio_priv(indio_dev);
- int ret;
- int cmd;
-
- /* Do not enable the buffer if we are already capturing events. */
- if (vcnl4010_is_in_periodic_mode(data))
- return -EBUSY;
-
- ret = i2c_smbus_write_byte_data(data->client, VCNL4010_INT_CTRL,
- VCNL4010_INT_PROX_EN);
- if (ret < 0)
- return ret;
-
- cmd = VCNL4000_SELF_TIMED_EN | VCNL4000_PROX_EN;
- return i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND, cmd);
-}
-
-static int vcnl4010_buffer_predisable(struct iio_dev *indio_dev)
-{
- struct vcnl4000_data *data = iio_priv(indio_dev);
- int ret;
-
- ret = i2c_smbus_write_byte_data(data->client, VCNL4010_INT_CTRL, 0);
- if (ret < 0)
- return ret;
-
- return i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND, 0);
-}
-
-static const struct iio_buffer_setup_ops vcnl4010_buffer_ops = {
- .postenable = &vcnl4010_buffer_postenable,
- .predisable = &vcnl4010_buffer_predisable,
-};
-
static const struct iio_trigger_ops vcnl4010_trigger_ops = {
.validate_device = iio_trigger_validate_own_device,
};
@@ -1214,22 +1384,25 @@ static int vcnl4000_probe(struct i2c_client *client)
indio_dev->name = VCNL4000_DRV_NAME;
indio_dev->modes = INDIO_DIRECT_MODE;
- if (client->irq && data->chip_spec->irq_support) {
+ if (data->chip_spec->trig_buffer_func &&
+ data->chip_spec->buffer_setup_ops) {
ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev,
NULL,
- vcnl4010_trigger_handler,
- &vcnl4010_buffer_ops);
+ data->chip_spec->trig_buffer_func,
+ data->chip_spec->buffer_setup_ops);
if (ret < 0) {
dev_err(&client->dev,
"unable to setup iio triggered buffer\n");
return ret;
}
+ }
+ if (client->irq && data->chip_spec->irq_thread) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
- NULL, vcnl4010_irq_thread,
+ NULL, data->chip_spec->irq_thread,
IRQF_TRIGGER_FALLING |
IRQF_ONESHOT,
- "vcnl4010_irq",
+ "vcnl4000_irq",
indio_dev);
if (ret < 0) {
dev_err(&client->dev, "irq request failed\n");
diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig
index b91fc5e6a26e..38532d840f2a 100644
--- a/drivers/iio/magnetometer/Kconfig
+++ b/drivers/iio/magnetometer/Kconfig
@@ -119,7 +119,7 @@ config IIO_ST_MAGN_3AXIS
select IIO_TRIGGERED_BUFFER if (IIO_BUFFER)
help
Say yes here to build support for STMicroelectronics magnetometers:
- LSM303DLHC, LSM303DLM, LIS3MDL.
+ LSM303C, LSM303DLHC, LSM303DLM, LIS3MDL.
Also need to enable at least one of I2C and SPI interface drivers
below.
@@ -208,6 +208,18 @@ config SENSORS_RM3100_SPI
To compile this driver as a module, choose M here: the module
will be called rm3100-spi.
+config TI_TMAG5273
+ tristate "TI TMAG5273 Low-Power Linear 3D Hall-Effect Sensor"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ Say Y here to add support for the TI TMAG5273 Low-Power
+ Linear 3D Hall-Effect Sensor.
+
+ This driver can also be compiled as a module.
+ To compile this driver as a module, choose M here: the module
+ will be called tmag5273.
+
config YAMAHA_YAS530
tristate "Yamaha YAS530 family of 3-Axis Magnetometers (I2C)"
depends on I2C
diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile
index b9f45b7fafc3..b1c784ea71c8 100644
--- a/drivers/iio/magnetometer/Makefile
+++ b/drivers/iio/magnetometer/Makefile
@@ -29,4 +29,6 @@ obj-$(CONFIG_SENSORS_RM3100) += rm3100-core.o
obj-$(CONFIG_SENSORS_RM3100_I2C) += rm3100-i2c.o
obj-$(CONFIG_SENSORS_RM3100_SPI) += rm3100-spi.o
+obj-$(CONFIG_TI_TMAG5273) += tmag5273.o
+
obj-$(CONFIG_YAMAHA_YAS530) += yamaha-yas530.o
diff --git a/drivers/iio/magnetometer/st_magn.h b/drivers/iio/magnetometer/st_magn.h
index 785b7f7b8b06..89945984d966 100644
--- a/drivers/iio/magnetometer/st_magn.h
+++ b/drivers/iio/magnetometer/st_magn.h
@@ -22,6 +22,7 @@
#define LIS2MDL_MAGN_DEV_NAME "lis2mdl"
#define LSM9DS1_MAGN_DEV_NAME "lsm9ds1_magn"
#define IIS2MDC_MAGN_DEV_NAME "iis2mdc"
+#define LSM303C_MAGN_DEV_NAME "lsm303c_magn"
#ifdef CONFIG_IIO_BUFFER
int st_magn_allocate_ring(struct iio_dev *indio_dev);
diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c
index e2fd233b3626..8faa7409d9e1 100644
--- a/drivers/iio/magnetometer/st_magn_core.c
+++ b/drivers/iio/magnetometer/st_magn_core.c
@@ -305,6 +305,7 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = {
.sensors_supported = {
[0] = LIS3MDL_MAGN_DEV_NAME,
[1] = LSM9DS1_MAGN_DEV_NAME,
+ [2] = LSM303C_MAGN_DEV_NAME,
},
.ch = (struct iio_chan_spec *)st_magn_2_16bit_channels,
.odr = {
diff --git a/drivers/iio/magnetometer/st_magn_i2c.c b/drivers/iio/magnetometer/st_magn_i2c.c
index b4098d3b3813..cc0e0e94b129 100644
--- a/drivers/iio/magnetometer/st_magn_i2c.c
+++ b/drivers/iio/magnetometer/st_magn_i2c.c
@@ -50,6 +50,10 @@ static const struct of_device_id st_magn_of_match[] = {
.compatible = "st,iis2mdc",
.data = IIS2MDC_MAGN_DEV_NAME,
},
+ {
+ .compatible = "st,lsm303c-magn",
+ .data = LSM303C_MAGN_DEV_NAME,
+ },
{},
};
MODULE_DEVICE_TABLE(of, st_magn_of_match);
@@ -97,6 +101,7 @@ static const struct i2c_device_id st_magn_id_table[] = {
{ LIS2MDL_MAGN_DEV_NAME },
{ LSM9DS1_MAGN_DEV_NAME },
{ IIS2MDC_MAGN_DEV_NAME },
+ { LSM303C_MAGN_DEV_NAME },
{},
};
MODULE_DEVICE_TABLE(i2c, st_magn_id_table);
diff --git a/drivers/iio/magnetometer/st_magn_spi.c b/drivers/iio/magnetometer/st_magn_spi.c
index 6ddc4318564a..f203e1f87eec 100644
--- a/drivers/iio/magnetometer/st_magn_spi.c
+++ b/drivers/iio/magnetometer/st_magn_spi.c
@@ -45,6 +45,10 @@ static const struct of_device_id st_magn_of_match[] = {
.compatible = "st,iis2mdc",
.data = IIS2MDC_MAGN_DEV_NAME,
},
+ {
+ .compatible = "st,lsm303c-magn",
+ .data = LSM303C_MAGN_DEV_NAME,
+ },
{}
};
MODULE_DEVICE_TABLE(of, st_magn_of_match);
@@ -89,6 +93,7 @@ static const struct spi_device_id st_magn_id_table[] = {
{ LIS2MDL_MAGN_DEV_NAME },
{ LSM9DS1_MAGN_DEV_NAME },
{ IIS2MDC_MAGN_DEV_NAME },
+ { LSM303C_MAGN_DEV_NAME },
{},
};
MODULE_DEVICE_TABLE(spi, st_magn_id_table);
diff --git a/drivers/iio/magnetometer/tmag5273.c b/drivers/iio/magnetometer/tmag5273.c
new file mode 100644
index 000000000000..28bb7efe8df8
--- /dev/null
+++ b/drivers/iio/magnetometer/tmag5273.c
@@ -0,0 +1,743 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Driver for the TI TMAG5273 Low-Power Linear 3D Hall-Effect Sensor
+ *
+ * Copyright (C) 2022 WolfVision GmbH
+ *
+ * Author: Gerald Loacker <gerald.loacker@wolfvision.net>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/pm_runtime.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define TMAG5273_DEVICE_CONFIG_1 0x00
+#define TMAG5273_DEVICE_CONFIG_2 0x01
+#define TMAG5273_SENSOR_CONFIG_1 0x02
+#define TMAG5273_SENSOR_CONFIG_2 0x03
+#define TMAG5273_X_THR_CONFIG 0x04
+#define TMAG5273_Y_THR_CONFIG 0x05
+#define TMAG5273_Z_THR_CONFIG 0x06
+#define TMAG5273_T_CONFIG 0x07
+#define TMAG5273_INT_CONFIG_1 0x08
+#define TMAG5273_MAG_GAIN_CONFIG 0x09
+#define TMAG5273_MAG_OFFSET_CONFIG_1 0x0A
+#define TMAG5273_MAG_OFFSET_CONFIG_2 0x0B
+#define TMAG5273_I2C_ADDRESS 0x0C
+#define TMAG5273_DEVICE_ID 0x0D
+#define TMAG5273_MANUFACTURER_ID_LSB 0x0E
+#define TMAG5273_MANUFACTURER_ID_MSB 0x0F
+#define TMAG5273_T_MSB_RESULT 0x10
+#define TMAG5273_T_LSB_RESULT 0x11
+#define TMAG5273_X_MSB_RESULT 0x12
+#define TMAG5273_X_LSB_RESULT 0x13
+#define TMAG5273_Y_MSB_RESULT 0x14
+#define TMAG5273_Y_LSB_RESULT 0x15
+#define TMAG5273_Z_MSB_RESULT 0x16
+#define TMAG5273_Z_LSB_RESULT 0x17
+#define TMAG5273_CONV_STATUS 0x18
+#define TMAG5273_ANGLE_RESULT_MSB 0x19
+#define TMAG5273_ANGLE_RESULT_LSB 0x1A
+#define TMAG5273_MAGNITUDE_RESULT 0x1B
+#define TMAG5273_DEVICE_STATUS 0x1C
+#define TMAG5273_MAX_REG TMAG5273_DEVICE_STATUS
+
+#define TMAG5273_AUTOSLEEP_DELAY_MS 5000
+#define TMAG5273_MAX_AVERAGE 32
+
+/*
+ * bits in the TMAG5273_MANUFACTURER_ID_LSB / MSB register
+ * 16-bit unique manufacturer ID 0x49 / 0x54 = "TI"
+ */
+#define TMAG5273_MANUFACTURER_ID 0x5449
+
+/* bits in the TMAG5273_DEVICE_CONFIG_1 register */
+#define TMAG5273_AVG_MODE_MASK GENMASK(4, 2)
+#define TMAG5273_AVG_1_MODE FIELD_PREP(TMAG5273_AVG_MODE_MASK, 0)
+#define TMAG5273_AVG_2_MODE FIELD_PREP(TMAG5273_AVG_MODE_MASK, 1)
+#define TMAG5273_AVG_4_MODE FIELD_PREP(TMAG5273_AVG_MODE_MASK, 2)
+#define TMAG5273_AVG_8_MODE FIELD_PREP(TMAG5273_AVG_MODE_MASK, 3)
+#define TMAG5273_AVG_16_MODE FIELD_PREP(TMAG5273_AVG_MODE_MASK, 4)
+#define TMAG5273_AVG_32_MODE FIELD_PREP(TMAG5273_AVG_MODE_MASK, 5)
+
+/* bits in the TMAG5273_DEVICE_CONFIG_2 register */
+#define TMAG5273_OP_MODE_MASK GENMASK(1, 0)
+#define TMAG5273_OP_MODE_STANDBY FIELD_PREP(TMAG5273_OP_MODE_MASK, 0)
+#define TMAG5273_OP_MODE_SLEEP FIELD_PREP(TMAG5273_OP_MODE_MASK, 1)
+#define TMAG5273_OP_MODE_CONT FIELD_PREP(TMAG5273_OP_MODE_MASK, 2)
+#define TMAG5273_OP_MODE_WAKEUP FIELD_PREP(TMAG5273_OP_MODE_MASK, 3)
+
+/* bits in the TMAG5273_SENSOR_CONFIG_1 register */
+#define TMAG5273_MAG_CH_EN_MASK GENMASK(7, 4)
+#define TMAG5273_MAG_CH_EN_X_Y_Z 7
+
+/* bits in the TMAG5273_SENSOR_CONFIG_2 register */
+#define TMAG5273_Z_RANGE_MASK BIT(0)
+#define TMAG5273_X_Y_RANGE_MASK BIT(1)
+#define TMAG5273_ANGLE_EN_MASK GENMASK(3, 2)
+#define TMAG5273_ANGLE_EN_OFF 0
+#define TMAG5273_ANGLE_EN_X_Y 1
+#define TMAG5273_ANGLE_EN_Y_Z 2
+#define TMAG5273_ANGLE_EN_X_Z 3
+
+/* bits in the TMAG5273_T_CONFIG register */
+#define TMAG5273_T_CH_EN BIT(0)
+
+/* bits in the TMAG5273_DEVICE_ID register */
+#define TMAG5273_VERSION_MASK GENMASK(1, 0)
+
+/* bits in the TMAG5273_CONV_STATUS register */
+#define TMAG5273_CONV_STATUS_COMPLETE BIT(0)
+
+enum tmag5273_channels {
+ TEMPERATURE = 0,
+ AXIS_X,
+ AXIS_Y,
+ AXIS_Z,
+ ANGLE,
+ MAGNITUDE,
+};
+
+enum tmag5273_scale_index {
+ MAGN_RANGE_LOW = 0,
+ MAGN_RANGE_HIGH,
+ MAGN_RANGE_NUM
+};
+
+/* state container for the TMAG5273 driver */
+struct tmag5273_data {
+ struct device *dev;
+ unsigned int devid;
+ unsigned int version;
+ char name[16];
+ unsigned int conv_avg;
+ unsigned int scale;
+ enum tmag5273_scale_index scale_index;
+ unsigned int angle_measurement;
+ struct regmap *map;
+ struct regulator *vcc;
+
+ /*
+ * Locks the sensor for exclusive use during a measurement (which
+ * involves several register transactions so the regmap lock is not
+ * enough) so that measurements get serialized in a
+ * first-come-first-serve manner.
+ */
+ struct mutex lock;
+};
+
+static const char *const tmag5273_angle_names[] = { "off", "x-y", "y-z", "x-z" };
+
+/*
+ * Averaging enables additional sampling of the sensor data to reduce the noise
+ * effect, but also increases conversion time.
+ */
+static const unsigned int tmag5273_avg_table[] = {
+ 1, 2, 4, 8, 16, 32,
+};
+
+/*
+ * Magnetic resolution in Gauss for different TMAG5273 versions.
+ * Scale[Gauss] = Range[mT] * 1000 / 2^15 * 10, (1 mT = 10 Gauss)
+ * Only version 1 and 2 are valid, version 0 and 3 are reserved.
+ */
+static const struct iio_val_int_plus_micro tmag5273_scale[][MAGN_RANGE_NUM] = {
+ { { 0, 0 }, { 0, 0 } },
+ { { 0, 12200 }, { 0, 24400 } },
+ { { 0, 40600 }, { 0, 81200 } },
+ { { 0, 0 }, { 0, 0 } },
+};
+
+static int tmag5273_get_measure(struct tmag5273_data *data, s16 *t, s16 *x,
+ s16 *y, s16 *z, u16 *angle, u16 *magnitude)
+{
+ unsigned int status, val;
+ __be16 reg_data[4];
+ int ret;
+
+ mutex_lock(&data->lock);
+
+ /*
+ * Max. conversion time is 2425 us in 32x averaging mode for all three
+ * channels. Since we are in continuous measurement mode, a measurement
+ * may already be there, so poll for completed measurement with
+ * timeout.
+ */
+ ret = regmap_read_poll_timeout(data->map, TMAG5273_CONV_STATUS, status,
+ status & TMAG5273_CONV_STATUS_COMPLETE,
+ 100, 10000);
+ if (ret) {
+ dev_err(data->dev, "timeout waiting for measurement\n");
+ goto out_unlock;
+ }
+
+ ret = regmap_bulk_read(data->map, TMAG5273_T_MSB_RESULT, reg_data,
+ sizeof(reg_data));
+ if (ret)
+ goto out_unlock;
+ *t = be16_to_cpu(reg_data[0]);
+ *x = be16_to_cpu(reg_data[1]);
+ *y = be16_to_cpu(reg_data[2]);
+ *z = be16_to_cpu(reg_data[3]);
+
+ ret = regmap_bulk_read(data->map, TMAG5273_ANGLE_RESULT_MSB,
+ &reg_data[0], sizeof(reg_data[0]));
+ if (ret)
+ goto out_unlock;
+ /*
+ * angle has 9 bits integer value and 4 bits fractional part
+ * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+ * 0 0 0 a a a a a a a a a f f f f
+ */
+ *angle = be16_to_cpu(reg_data[0]);
+
+ ret = regmap_read(data->map, TMAG5273_MAGNITUDE_RESULT, &val);
+ if (ret < 0)
+ goto out_unlock;
+ *magnitude = val;
+
+out_unlock:
+ mutex_unlock(&data->lock);
+ return ret;
+}
+
+static int tmag5273_write_osr(struct tmag5273_data *data, int val)
+{
+ int i;
+
+ if (val == data->conv_avg)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(tmag5273_avg_table); i++) {
+ if (tmag5273_avg_table[i] == val)
+ break;
+ }
+ if (i == ARRAY_SIZE(tmag5273_avg_table))
+ return -EINVAL;
+ data->conv_avg = val;
+
+ return regmap_update_bits(data->map, TMAG5273_DEVICE_CONFIG_1,
+ TMAG5273_AVG_MODE_MASK,
+ FIELD_PREP(TMAG5273_AVG_MODE_MASK, i));
+}
+
+static int tmag5273_write_scale(struct tmag5273_data *data, int scale_micro)
+{
+ u32 value;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(tmag5273_scale[0]); i++) {
+ if (tmag5273_scale[data->version][i].micro == scale_micro)
+ break;
+ }
+ if (i == ARRAY_SIZE(tmag5273_scale[0]))
+ return -EINVAL;
+ data->scale_index = i;
+
+ if (data->scale_index == MAGN_RANGE_LOW)
+ value = 0;
+ else
+ value = TMAG5273_Z_RANGE_MASK | TMAG5273_X_Y_RANGE_MASK;
+
+ return regmap_update_bits(data->map, TMAG5273_SENSOR_CONFIG_2,
+ TMAG5273_Z_RANGE_MASK | TMAG5273_X_Y_RANGE_MASK, value);
+}
+
+static int tmag5273_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long mask)
+{
+ struct tmag5273_data *data = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ *vals = tmag5273_avg_table;
+ *type = IIO_VAL_INT;
+ *length = ARRAY_SIZE(tmag5273_avg_table);
+ return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ case IIO_MAGN:
+ *type = IIO_VAL_INT_PLUS_MICRO;
+ *vals = (int *)tmag5273_scale[data->version];
+ *length = ARRAY_SIZE(tmag5273_scale[data->version]) *
+ MAGN_RANGE_NUM;
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int tmag5273_read_raw(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, int *val,
+ int *val2, long mask)
+{
+ struct tmag5273_data *data = iio_priv(indio_dev);
+ s16 t, x, y, z;
+ u16 angle, magnitude;
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_PROCESSED:
+ case IIO_CHAN_INFO_RAW:
+ ret = pm_runtime_resume_and_get(data->dev);
+ if (ret < 0)
+ return ret;
+
+ ret = tmag5273_get_measure(data, &t, &x, &y, &z, &angle, &magnitude);
+ if (ret)
+ return ret;
+
+ pm_runtime_mark_last_busy(data->dev);
+ pm_runtime_put_autosuspend(data->dev);
+
+ switch (chan->address) {
+ case TEMPERATURE:
+ *val = t;
+ return IIO_VAL_INT;
+ case AXIS_X:
+ *val = x;
+ return IIO_VAL_INT;
+ case AXIS_Y:
+ *val = y;
+ return IIO_VAL_INT;
+ case AXIS_Z:
+ *val = z;
+ return IIO_VAL_INT;
+ case ANGLE:
+ *val = angle;
+ return IIO_VAL_INT;
+ case MAGNITUDE:
+ *val = magnitude;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ case IIO_TEMP:
+ /*
+ * Convert device specific value to millicelsius.
+ * Resolution from the sensor is 60.1 LSB/celsius and
+ * the reference value at 25 celsius is 17508 LSBs.
+ */
+ *val = 10000;
+ *val2 = 601;
+ return IIO_VAL_FRACTIONAL;
+ case IIO_MAGN:
+ /* Magnetic resolution in uT */
+ *val = 0;
+ *val2 = tmag5273_scale[data->version]
+ [data->scale_index].micro;
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_ANGL:
+ /*
+ * Angle is in degrees and has four fractional bits,
+ * therefore use 1/16 * pi/180 to convert to radians.
+ */
+ *val = 1000;
+ *val2 = 916732;
+ return IIO_VAL_FRACTIONAL;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_OFFSET:
+ switch (chan->type) {
+ case IIO_TEMP:
+ *val = -266314;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ *val = data->conv_avg;
+ return IIO_VAL_INT;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int tmag5273_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val,
+ int val2, long mask)
+{
+ struct tmag5273_data *data = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ return tmag5273_write_osr(data, val);
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ case IIO_MAGN:
+ if (val)
+ return -EINVAL;
+ return tmag5273_write_scale(data, val2);
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+#define TMAG5273_AXIS_CHANNEL(axis, index) \
+ { \
+ .type = IIO_MAGN, \
+ .modified = 1, \
+ .channel2 = IIO_MOD_##axis, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_shared_by_type_available = \
+ BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_shared_by_all = \
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
+ .info_mask_shared_by_all_available = \
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
+ .address = index, \
+ .scan_index = index, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = 16, \
+ .storagebits = 16, \
+ .endianness = IIO_CPU, \
+ }, \
+ }
+
+static const struct iio_chan_spec tmag5273_channels[] = {
+ {
+ .type = IIO_TEMP,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_OFFSET),
+ .address = TEMPERATURE,
+ .scan_index = TEMPERATURE,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 16,
+ .storagebits = 16,
+ .endianness = IIO_CPU,
+ },
+ },
+ TMAG5273_AXIS_CHANNEL(X, AXIS_X),
+ TMAG5273_AXIS_CHANNEL(Y, AXIS_Y),
+ TMAG5273_AXIS_CHANNEL(Z, AXIS_Z),
+ {
+ .type = IIO_ANGL,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+ .info_mask_shared_by_all =
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_all_available =
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .address = ANGLE,
+ .scan_index = ANGLE,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 16,
+ .storagebits = 16,
+ .endianness = IIO_CPU,
+ },
+ },
+ {
+ .type = IIO_DISTANCE,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_all =
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_all_available =
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .address = MAGNITUDE,
+ .scan_index = MAGNITUDE,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 16,
+ .storagebits = 16,
+ .endianness = IIO_CPU,
+ },
+ },
+ IIO_CHAN_SOFT_TIMESTAMP(6),
+};
+
+static const struct iio_info tmag5273_info = {
+ .read_avail = tmag5273_read_avail,
+ .read_raw = tmag5273_read_raw,
+ .write_raw = tmag5273_write_raw,
+};
+
+static bool tmag5273_volatile_reg(struct device *dev, unsigned int reg)
+{
+ return reg >= TMAG5273_T_MSB_RESULT && reg <= TMAG5273_MAGNITUDE_RESULT;
+}
+
+static const struct regmap_config tmag5273_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = TMAG5273_MAX_REG,
+ .volatile_reg = tmag5273_volatile_reg,
+};
+
+static int tmag5273_set_operating_mode(struct tmag5273_data *data,
+ unsigned int val)
+{
+ return regmap_write(data->map, TMAG5273_DEVICE_CONFIG_2, val);
+}
+
+static void tmag5273_read_device_property(struct tmag5273_data *data)
+{
+ struct device *dev = data->dev;
+ const char *str;
+ int ret;
+
+ data->angle_measurement = TMAG5273_ANGLE_EN_X_Y;
+
+ ret = device_property_read_string(dev, "ti,angle-measurement", &str);
+ if (ret)
+ return;
+
+ ret = match_string(tmag5273_angle_names,
+ ARRAY_SIZE(tmag5273_angle_names), str);
+ if (ret >= 0)
+ data->angle_measurement = ret;
+}
+
+static void tmag5273_wake_up(struct tmag5273_data *data)
+{
+ int val;
+
+ /* Wake up the chip by sending a dummy I2C command */
+ regmap_read(data->map, TMAG5273_DEVICE_ID, &val);
+ /*
+ * Time to go to stand-by mode from sleep mode is 50us
+ * typically, during this time no I2C access is possible.
+ */
+ usleep_range(80, 200);
+}
+
+static int tmag5273_chip_init(struct tmag5273_data *data)
+{
+ int ret;
+
+ ret = regmap_write(data->map, TMAG5273_DEVICE_CONFIG_1,
+ TMAG5273_AVG_32_MODE);
+ if (ret)
+ return ret;
+ data->conv_avg = 32;
+
+ ret = regmap_write(data->map, TMAG5273_DEVICE_CONFIG_2,
+ TMAG5273_OP_MODE_CONT);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(data->map, TMAG5273_SENSOR_CONFIG_1,
+ FIELD_PREP(TMAG5273_MAG_CH_EN_MASK,
+ TMAG5273_MAG_CH_EN_X_Y_Z));
+ if (ret)
+ return ret;
+
+ ret = regmap_write(data->map, TMAG5273_SENSOR_CONFIG_2,
+ FIELD_PREP(TMAG5273_ANGLE_EN_MASK,
+ data->angle_measurement));
+ if (ret)
+ return ret;
+ data->scale_index = MAGN_RANGE_LOW;
+
+ return regmap_write(data->map, TMAG5273_T_CONFIG, TMAG5273_T_CH_EN);
+}
+
+static int tmag5273_check_device_id(struct tmag5273_data *data)
+{
+ __le16 devid;
+ int val, ret;
+
+ ret = regmap_read(data->map, TMAG5273_DEVICE_ID, &val);
+ if (ret)
+ return dev_err_probe(data->dev, ret, "failed to power on device\n");
+ data->version = FIELD_PREP(TMAG5273_VERSION_MASK, val);
+
+ ret = regmap_bulk_read(data->map, TMAG5273_MANUFACTURER_ID_LSB, &devid,
+ sizeof(devid));
+ if (ret)
+ return dev_err_probe(data->dev, ret, "failed to read device ID\n");
+ data->devid = le16_to_cpu(devid);
+
+ switch (data->devid) {
+ case TMAG5273_MANUFACTURER_ID:
+ /*
+ * The device name matches the orderable part number. 'x' stands
+ * for A, B, C or D devices, which have different I2C addresses.
+ * Versions 1 or 2 (0 and 3 is reserved) stands for different
+ * magnetic strengths.
+ */
+ snprintf(data->name, sizeof(data->name), "tmag5273x%1u", data->version);
+ if (data->version < 1 || data->version > 2)
+ dev_warn(data->dev, "Unsupported device %s\n", data->name);
+ return 0;
+ default:
+ /*
+ * Only print warning in case of unknown device ID to allow
+ * fallback compatible in device tree.
+ */
+ dev_warn(data->dev, "Unknown device ID 0x%x\n", data->devid);
+ return 0;
+ }
+}
+
+static void tmag5273_power_down(void *data)
+{
+ tmag5273_set_operating_mode(data, TMAG5273_OP_MODE_SLEEP);
+}
+
+static int tmag5273_probe(struct i2c_client *i2c)
+{
+ struct device *dev = &i2c->dev;
+ struct tmag5273_data *data;
+ struct iio_dev *indio_dev;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+ data->dev = dev;
+ i2c_set_clientdata(i2c, indio_dev);
+
+ data->map = devm_regmap_init_i2c(i2c, &tmag5273_regmap_config);
+ if (IS_ERR(data->map))
+ return dev_err_probe(dev, PTR_ERR(data->map),
+ "failed to allocate register map\n");
+
+ mutex_init(&data->lock);
+
+ ret = devm_regulator_get_enable(dev, "vcc");
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to enable regulator\n");
+
+ tmag5273_wake_up(data);
+
+ ret = tmag5273_check_device_id(data);
+ if (ret)
+ return ret;
+
+ ret = tmag5273_set_operating_mode(data, TMAG5273_OP_MODE_CONT);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to power on device\n");
+
+ /*
+ * Register powerdown deferred callback which suspends the chip
+ * after module unloaded.
+ *
+ * TMAG5273 should be in SUSPEND mode in the two cases:
+ * 1) When driver is loaded, but we do not have any data or
+ * configuration requests to it (we are solving it using
+ * autosuspend feature).
+ * 2) When driver is unloaded and device is not used (devm action is
+ * used in this case).
+ */
+ ret = devm_add_action_or_reset(dev, tmag5273_power_down, data);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to add powerdown action\n");
+
+ ret = pm_runtime_set_active(dev);
+ if (ret < 0)
+ return ret;
+
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ return ret;
+
+ pm_runtime_get_noresume(dev);
+ pm_runtime_set_autosuspend_delay(dev, TMAG5273_AUTOSLEEP_DELAY_MS);
+ pm_runtime_use_autosuspend(dev);
+
+ tmag5273_read_device_property(data);
+
+ ret = tmag5273_chip_init(data);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to init device\n");
+
+ indio_dev->info = &tmag5273_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->name = data->name;
+ indio_dev->channels = tmag5273_channels;
+ indio_dev->num_channels = ARRAY_SIZE(tmag5273_channels);
+
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+
+ ret = devm_iio_device_register(dev, indio_dev);
+ if (ret)
+ return dev_err_probe(dev, ret, "device register failed\n");
+
+ return 0;
+}
+
+static int tmag5273_runtime_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct tmag5273_data *data = iio_priv(indio_dev);
+ int ret;
+
+ ret = tmag5273_set_operating_mode(data, TMAG5273_OP_MODE_SLEEP);
+ if (ret)
+ dev_err(dev, "failed to power off device (%pe)\n", ERR_PTR(ret));
+
+ return ret;
+}
+
+static int tmag5273_runtime_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct tmag5273_data *data = iio_priv(indio_dev);
+ int ret;
+
+ tmag5273_wake_up(data);
+
+ ret = tmag5273_set_operating_mode(data, TMAG5273_OP_MODE_CONT);
+ if (ret)
+ dev_err(dev, "failed to power on device (%pe)\n", ERR_PTR(ret));
+
+ return ret;
+}
+
+static DEFINE_RUNTIME_DEV_PM_OPS(tmag5273_pm_ops,
+ tmag5273_runtime_suspend, tmag5273_runtime_resume,
+ NULL);
+
+static const struct i2c_device_id tmag5273_id[] = {
+ { "tmag5273" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(i2c, tmag5273_id);
+
+static const struct of_device_id tmag5273_of_match[] = {
+ { .compatible = "ti,tmag5273" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, tmag5273_of_match);
+
+static struct i2c_driver tmag5273_driver = {
+ .driver = {
+ .name = "tmag5273",
+ .of_match_table = tmag5273_of_match,
+ .pm = pm_ptr(&tmag5273_pm_ops),
+ },
+ .probe_new = tmag5273_probe,
+ .id_table = tmag5273_id,
+};
+module_i2c_driver(tmag5273_driver);
+
+MODULE_DESCRIPTION("TI TMAG5273 Low-Power Linear 3D Hall-Effect Sensor driver");
+MODULE_AUTHOR("Gerald Loacker <gerald.loacker@wolfvision.net>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/pressure/ms5611.h b/drivers/iio/pressure/ms5611.h
index 550b75b7186f..a78acd3fb18f 100644
--- a/drivers/iio/pressure/ms5611.h
+++ b/drivers/iio/pressure/ms5611.h
@@ -13,8 +13,6 @@
#include <linux/iio/iio.h>
#include <linux/mutex.h>
-struct regulator;
-
#define MS5611_RESET 0x1e
#define MS5611_READ_ADC 0x00
#define MS5611_READ_PROM_WORD 0xA0
@@ -52,11 +50,9 @@ struct ms5611_state {
int (*compensate_temp_and_pressure)(struct ms5611_state *st, s32 *temp,
s32 *pressure);
- struct regulator *vdd;
};
int ms5611_probe(struct iio_dev *indio_dev, struct device *dev,
const char *name, int type);
-void ms5611_remove(struct iio_dev *indio_dev);
#endif /* _MS5611_H */
diff --git a/drivers/iio/pressure/ms5611_core.c b/drivers/iio/pressure/ms5611_core.c
index c564a1d6cafe..627497e61a63 100644
--- a/drivers/iio/pressure/ms5611_core.c
+++ b/drivers/iio/pressure/ms5611_core.c
@@ -380,40 +380,21 @@ static const struct iio_info ms5611_info = {
static int ms5611_init(struct iio_dev *indio_dev)
{
int ret;
- struct ms5611_state *st = iio_priv(indio_dev);
/* Enable attached regulator if any. */
- st->vdd = devm_regulator_get(indio_dev->dev.parent, "vdd");
- if (IS_ERR(st->vdd))
- return PTR_ERR(st->vdd);
-
- ret = regulator_enable(st->vdd);
- if (ret) {
- dev_err(indio_dev->dev.parent,
- "failed to enable Vdd supply: %d\n", ret);
+ ret = devm_regulator_get_enable(indio_dev->dev.parent, "vdd");
+ if (ret)
return ret;
- }
ret = ms5611_reset(indio_dev);
if (ret < 0)
- goto err_regulator_disable;
+ return ret;
ret = ms5611_read_prom(indio_dev);
if (ret < 0)
- goto err_regulator_disable;
+ return ret;
return 0;
-
-err_regulator_disable:
- regulator_disable(st->vdd);
- return ret;
-}
-
-static void ms5611_fini(const struct iio_dev *indio_dev)
-{
- const struct ms5611_state *st = iio_priv(indio_dev);
-
- regulator_disable(st->vdd);
}
int ms5611_probe(struct iio_dev *indio_dev, struct device *dev,
@@ -453,37 +434,23 @@ int ms5611_probe(struct iio_dev *indio_dev, struct device *dev,
if (ret < 0)
return ret;
- ret = iio_triggered_buffer_setup(indio_dev, NULL,
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
ms5611_trigger_handler, NULL);
if (ret < 0) {
dev_err(dev, "iio triggered buffer setup failed\n");
- goto err_fini;
+ return ret;
}
- ret = iio_device_register(indio_dev);
+ ret = devm_iio_device_register(dev, indio_dev);
if (ret < 0) {
dev_err(dev, "unable to register iio device\n");
- goto err_buffer_cleanup;
+ return ret;
}
return 0;
-
-err_buffer_cleanup:
- iio_triggered_buffer_cleanup(indio_dev);
-err_fini:
- ms5611_fini(indio_dev);
- return ret;
}
EXPORT_SYMBOL_NS(ms5611_probe, IIO_MS5611);
-void ms5611_remove(struct iio_dev *indio_dev)
-{
- iio_device_unregister(indio_dev);
- iio_triggered_buffer_cleanup(indio_dev);
- ms5611_fini(indio_dev);
-}
-EXPORT_SYMBOL_NS(ms5611_remove, IIO_MS5611);
-
MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>");
MODULE_DESCRIPTION("MS5611 core driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/pressure/ms5611_i2c.c b/drivers/iio/pressure/ms5611_i2c.c
index caf882497656..e3c68a3ed76a 100644
--- a/drivers/iio/pressure/ms5611_i2c.c
+++ b/drivers/iio/pressure/ms5611_i2c.c
@@ -105,11 +105,6 @@ static int ms5611_i2c_probe(struct i2c_client *client)
return ms5611_probe(indio_dev, &client->dev, id->name, id->driver_data);
}
-static void ms5611_i2c_remove(struct i2c_client *client)
-{
- ms5611_remove(i2c_get_clientdata(client));
-}
-
static const struct of_device_id ms5611_i2c_matches[] = {
{ .compatible = "meas,ms5611" },
{ .compatible = "meas,ms5607" },
@@ -131,7 +126,6 @@ static struct i2c_driver ms5611_driver = {
},
.id_table = ms5611_id,
.probe_new = ms5611_i2c_probe,
- .remove = ms5611_i2c_remove,
};
module_i2c_driver(ms5611_driver);
diff --git a/drivers/iio/pressure/ms5611_spi.c b/drivers/iio/pressure/ms5611_spi.c
index a0a7205c9c3a..cc9d1f68c53c 100644
--- a/drivers/iio/pressure/ms5611_spi.c
+++ b/drivers/iio/pressure/ms5611_spi.c
@@ -107,11 +107,6 @@ static int ms5611_spi_probe(struct spi_device *spi)
spi_get_device_id(spi)->driver_data);
}
-static void ms5611_spi_remove(struct spi_device *spi)
-{
- ms5611_remove(spi_get_drvdata(spi));
-}
-
static const struct of_device_id ms5611_spi_matches[] = {
{ .compatible = "meas,ms5611" },
{ .compatible = "meas,ms5607" },
@@ -133,7 +128,6 @@ static struct spi_driver ms5611_driver = {
},
.id_table = ms5611_id,
.probe = ms5611_spi_probe,
- .remove = ms5611_spi_remove,
};
module_spi_driver(ms5611_driver);
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index 68721ff10255..308155937713 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -479,13 +479,20 @@ static int compare_netdev_and_ip(int ifindex_a, struct sockaddr *sa,
if (sa->sa_family != sb->sa_family)
return sa->sa_family - sb->sa_family;
- if (sa->sa_family == AF_INET)
- return memcmp((char *)&((struct sockaddr_in *)sa)->sin_addr,
- (char *)&((struct sockaddr_in *)sb)->sin_addr,
+ if (sa->sa_family == AF_INET &&
+ __builtin_object_size(sa, 0) >= sizeof(struct sockaddr_in)) {
+ return memcmp(&((struct sockaddr_in *)sa)->sin_addr,
+ &((struct sockaddr_in *)sb)->sin_addr,
sizeof(((struct sockaddr_in *)sa)->sin_addr));
+ }
+
+ if (sa->sa_family == AF_INET6 &&
+ __builtin_object_size(sa, 0) >= sizeof(struct sockaddr_in6)) {
+ return ipv6_addr_cmp(&((struct sockaddr_in6 *)sa)->sin6_addr,
+ &((struct sockaddr_in6 *)sb)->sin6_addr);
+ }
- return ipv6_addr_cmp(&((struct sockaddr_in6 *)sa)->sin6_addr,
- &((struct sockaddr_in6 *)sb)->sin6_addr);
+ return -1;
}
static int cma_add_id_to_tree(struct rdma_id_private *node_id_priv)
@@ -2819,8 +2826,8 @@ int rdma_set_min_rnr_timer(struct rdma_cm_id *id, u8 min_rnr_timer)
}
EXPORT_SYMBOL(rdma_set_min_rnr_timer);
-static void route_set_path_rec_inbound(struct cma_work *work,
- struct sa_path_rec *path_rec)
+static int route_set_path_rec_inbound(struct cma_work *work,
+ struct sa_path_rec *path_rec)
{
struct rdma_route *route = &work->id->id.route;
@@ -2828,14 +2835,15 @@ static void route_set_path_rec_inbound(struct cma_work *work,
route->path_rec_inbound =
kzalloc(sizeof(*route->path_rec_inbound), GFP_KERNEL);
if (!route->path_rec_inbound)
- return;
+ return -ENOMEM;
}
*route->path_rec_inbound = *path_rec;
+ return 0;
}
-static void route_set_path_rec_outbound(struct cma_work *work,
- struct sa_path_rec *path_rec)
+static int route_set_path_rec_outbound(struct cma_work *work,
+ struct sa_path_rec *path_rec)
{
struct rdma_route *route = &work->id->id.route;
@@ -2843,14 +2851,15 @@ static void route_set_path_rec_outbound(struct cma_work *work,
route->path_rec_outbound =
kzalloc(sizeof(*route->path_rec_outbound), GFP_KERNEL);
if (!route->path_rec_outbound)
- return;
+ return -ENOMEM;
}
*route->path_rec_outbound = *path_rec;
+ return 0;
}
static void cma_query_handler(int status, struct sa_path_rec *path_rec,
- int num_prs, void *context)
+ unsigned int num_prs, void *context)
{
struct cma_work *work = context;
struct rdma_route *route;
@@ -2865,13 +2874,15 @@ static void cma_query_handler(int status, struct sa_path_rec *path_rec,
if (!path_rec[i].flags || (path_rec[i].flags & IB_PATH_GMP))
*route->path_rec = path_rec[i];
else if (path_rec[i].flags & IB_PATH_INBOUND)
- route_set_path_rec_inbound(work, &path_rec[i]);
+ status = route_set_path_rec_inbound(work, &path_rec[i]);
else if (path_rec[i].flags & IB_PATH_OUTBOUND)
- route_set_path_rec_outbound(work, &path_rec[i]);
- }
- if (!route->path_rec) {
- status = -EINVAL;
- goto fail;
+ status = route_set_path_rec_outbound(work,
+ &path_rec[i]);
+ else
+ status = -EINVAL;
+
+ if (status)
+ goto fail;
}
route->num_pri_alt_paths = 1;
@@ -3541,121 +3552,6 @@ err:
return ret;
}
-static int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
- const struct sockaddr *dst_addr)
-{
- struct sockaddr_storage zero_sock = {};
-
- if (src_addr && src_addr->sa_family)
- return rdma_bind_addr(id, src_addr);
-
- /*
- * When the src_addr is not specified, automatically supply an any addr
- */
- zero_sock.ss_family = dst_addr->sa_family;
- if (IS_ENABLED(CONFIG_IPV6) && dst_addr->sa_family == AF_INET6) {
- struct sockaddr_in6 *src_addr6 =
- (struct sockaddr_in6 *)&zero_sock;
- struct sockaddr_in6 *dst_addr6 =
- (struct sockaddr_in6 *)dst_addr;
-
- src_addr6->sin6_scope_id = dst_addr6->sin6_scope_id;
- if (ipv6_addr_type(&dst_addr6->sin6_addr) & IPV6_ADDR_LINKLOCAL)
- id->route.addr.dev_addr.bound_dev_if =
- dst_addr6->sin6_scope_id;
- } else if (dst_addr->sa_family == AF_IB) {
- ((struct sockaddr_ib *)&zero_sock)->sib_pkey =
- ((struct sockaddr_ib *)dst_addr)->sib_pkey;
- }
- return rdma_bind_addr(id, (struct sockaddr *)&zero_sock);
-}
-
-/*
- * If required, resolve the source address for bind and leave the id_priv in
- * state RDMA_CM_ADDR_BOUND. This oddly uses the state to determine the prior
- * calls made by ULP, a previously bound ID will not be re-bound and src_addr is
- * ignored.
- */
-static int resolve_prepare_src(struct rdma_id_private *id_priv,
- struct sockaddr *src_addr,
- const struct sockaddr *dst_addr)
-{
- int ret;
-
- memcpy(cma_dst_addr(id_priv), dst_addr, rdma_addr_size(dst_addr));
- if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_ADDR_QUERY)) {
- /* For a well behaved ULP state will be RDMA_CM_IDLE */
- ret = cma_bind_addr(&id_priv->id, src_addr, dst_addr);
- if (ret)
- goto err_dst;
- if (WARN_ON(!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND,
- RDMA_CM_ADDR_QUERY))) {
- ret = -EINVAL;
- goto err_dst;
- }
- }
-
- if (cma_family(id_priv) != dst_addr->sa_family) {
- ret = -EINVAL;
- goto err_state;
- }
- return 0;
-
-err_state:
- cma_comp_exch(id_priv, RDMA_CM_ADDR_QUERY, RDMA_CM_ADDR_BOUND);
-err_dst:
- memset(cma_dst_addr(id_priv), 0, rdma_addr_size(dst_addr));
- return ret;
-}
-
-int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
- const struct sockaddr *dst_addr, unsigned long timeout_ms)
-{
- struct rdma_id_private *id_priv =
- container_of(id, struct rdma_id_private, id);
- int ret;
-
- ret = resolve_prepare_src(id_priv, src_addr, dst_addr);
- if (ret)
- return ret;
-
- if (cma_any_addr(dst_addr)) {
- ret = cma_resolve_loopback(id_priv);
- } else {
- if (dst_addr->sa_family == AF_IB) {
- ret = cma_resolve_ib_addr(id_priv);
- } else {
- /*
- * The FSM can return back to RDMA_CM_ADDR_BOUND after
- * rdma_resolve_ip() is called, eg through the error
- * path in addr_handler(). If this happens the existing
- * request must be canceled before issuing a new one.
- * Since canceling a request is a bit slow and this
- * oddball path is rare, keep track once a request has
- * been issued. The track turns out to be a permanent
- * state since this is the only cancel as it is
- * immediately before rdma_resolve_ip().
- */
- if (id_priv->used_resolve_ip)
- rdma_addr_cancel(&id->route.addr.dev_addr);
- else
- id_priv->used_resolve_ip = 1;
- ret = rdma_resolve_ip(cma_src_addr(id_priv), dst_addr,
- &id->route.addr.dev_addr,
- timeout_ms, addr_handler,
- false, id_priv);
- }
- }
- if (ret)
- goto err;
-
- return 0;
-err:
- cma_comp_exch(id_priv, RDMA_CM_ADDR_QUERY, RDMA_CM_ADDR_BOUND);
- return ret;
-}
-EXPORT_SYMBOL(rdma_resolve_addr);
-
int rdma_set_reuseaddr(struct rdma_cm_id *id, int reuse)
{
struct rdma_id_private *id_priv;
@@ -4058,27 +3954,26 @@ err:
}
EXPORT_SYMBOL(rdma_listen);
-int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
+static int rdma_bind_addr_dst(struct rdma_id_private *id_priv,
+ struct sockaddr *addr, const struct sockaddr *daddr)
{
- struct rdma_id_private *id_priv;
+ struct sockaddr *id_daddr;
int ret;
- struct sockaddr *daddr;
if (addr->sa_family != AF_INET && addr->sa_family != AF_INET6 &&
addr->sa_family != AF_IB)
return -EAFNOSUPPORT;
- id_priv = container_of(id, struct rdma_id_private, id);
if (!cma_comp_exch(id_priv, RDMA_CM_IDLE, RDMA_CM_ADDR_BOUND))
return -EINVAL;
- ret = cma_check_linklocal(&id->route.addr.dev_addr, addr);
+ ret = cma_check_linklocal(&id_priv->id.route.addr.dev_addr, addr);
if (ret)
goto err1;
memcpy(cma_src_addr(id_priv), addr, rdma_addr_size(addr));
if (!cma_any_addr(addr)) {
- ret = cma_translate_addr(addr, &id->route.addr.dev_addr);
+ ret = cma_translate_addr(addr, &id_priv->id.route.addr.dev_addr);
if (ret)
goto err1;
@@ -4098,8 +3993,10 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
}
#endif
}
- daddr = cma_dst_addr(id_priv);
- daddr->sa_family = addr->sa_family;
+ id_daddr = cma_dst_addr(id_priv);
+ if (daddr != id_daddr)
+ memcpy(id_daddr, daddr, rdma_addr_size(addr));
+ id_daddr->sa_family = addr->sa_family;
ret = cma_get_port(id_priv);
if (ret)
@@ -4115,6 +4012,127 @@ err1:
cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_IDLE);
return ret;
}
+
+static int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
+ const struct sockaddr *dst_addr)
+{
+ struct rdma_id_private *id_priv =
+ container_of(id, struct rdma_id_private, id);
+ struct sockaddr_storage zero_sock = {};
+
+ if (src_addr && src_addr->sa_family)
+ return rdma_bind_addr_dst(id_priv, src_addr, dst_addr);
+
+ /*
+ * When the src_addr is not specified, automatically supply an any addr
+ */
+ zero_sock.ss_family = dst_addr->sa_family;
+ if (IS_ENABLED(CONFIG_IPV6) && dst_addr->sa_family == AF_INET6) {
+ struct sockaddr_in6 *src_addr6 =
+ (struct sockaddr_in6 *)&zero_sock;
+ struct sockaddr_in6 *dst_addr6 =
+ (struct sockaddr_in6 *)dst_addr;
+
+ src_addr6->sin6_scope_id = dst_addr6->sin6_scope_id;
+ if (ipv6_addr_type(&dst_addr6->sin6_addr) & IPV6_ADDR_LINKLOCAL)
+ id->route.addr.dev_addr.bound_dev_if =
+ dst_addr6->sin6_scope_id;
+ } else if (dst_addr->sa_family == AF_IB) {
+ ((struct sockaddr_ib *)&zero_sock)->sib_pkey =
+ ((struct sockaddr_ib *)dst_addr)->sib_pkey;
+ }
+ return rdma_bind_addr_dst(id_priv, (struct sockaddr *)&zero_sock, dst_addr);
+}
+
+/*
+ * If required, resolve the source address for bind and leave the id_priv in
+ * state RDMA_CM_ADDR_BOUND. This oddly uses the state to determine the prior
+ * calls made by ULP, a previously bound ID will not be re-bound and src_addr is
+ * ignored.
+ */
+static int resolve_prepare_src(struct rdma_id_private *id_priv,
+ struct sockaddr *src_addr,
+ const struct sockaddr *dst_addr)
+{
+ int ret;
+
+ if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_ADDR_QUERY)) {
+ /* For a well behaved ULP state will be RDMA_CM_IDLE */
+ ret = cma_bind_addr(&id_priv->id, src_addr, dst_addr);
+ if (ret)
+ return ret;
+ if (WARN_ON(!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND,
+ RDMA_CM_ADDR_QUERY)))
+ return -EINVAL;
+
+ }
+
+ if (cma_family(id_priv) != dst_addr->sa_family) {
+ ret = -EINVAL;
+ goto err_state;
+ }
+ return 0;
+
+err_state:
+ cma_comp_exch(id_priv, RDMA_CM_ADDR_QUERY, RDMA_CM_ADDR_BOUND);
+ return ret;
+}
+
+int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
+ const struct sockaddr *dst_addr, unsigned long timeout_ms)
+{
+ struct rdma_id_private *id_priv =
+ container_of(id, struct rdma_id_private, id);
+ int ret;
+
+ ret = resolve_prepare_src(id_priv, src_addr, dst_addr);
+ if (ret)
+ return ret;
+
+ if (cma_any_addr(dst_addr)) {
+ ret = cma_resolve_loopback(id_priv);
+ } else {
+ if (dst_addr->sa_family == AF_IB) {
+ ret = cma_resolve_ib_addr(id_priv);
+ } else {
+ /*
+ * The FSM can return back to RDMA_CM_ADDR_BOUND after
+ * rdma_resolve_ip() is called, eg through the error
+ * path in addr_handler(). If this happens the existing
+ * request must be canceled before issuing a new one.
+ * Since canceling a request is a bit slow and this
+ * oddball path is rare, keep track once a request has
+ * been issued. The track turns out to be a permanent
+ * state since this is the only cancel as it is
+ * immediately before rdma_resolve_ip().
+ */
+ if (id_priv->used_resolve_ip)
+ rdma_addr_cancel(&id->route.addr.dev_addr);
+ else
+ id_priv->used_resolve_ip = 1;
+ ret = rdma_resolve_ip(cma_src_addr(id_priv), dst_addr,
+ &id->route.addr.dev_addr,
+ timeout_ms, addr_handler,
+ false, id_priv);
+ }
+ }
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ cma_comp_exch(id_priv, RDMA_CM_ADDR_QUERY, RDMA_CM_ADDR_BOUND);
+ return ret;
+}
+EXPORT_SYMBOL(rdma_resolve_addr);
+
+int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
+{
+ struct rdma_id_private *id_priv =
+ container_of(id, struct rdma_id_private, id);
+
+ return rdma_bind_addr_dst(id_priv, addr, cma_dst_addr(id_priv));
+}
EXPORT_SYMBOL(rdma_bind_addr);
static int cma_format_hdr(void *hdr, struct rdma_id_private *id_priv)
diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c
index 0de83d9a4985..59179cfc20ef 100644
--- a/drivers/infiniband/core/sa_query.c
+++ b/drivers/infiniband/core/sa_query.c
@@ -106,7 +106,7 @@ struct ib_sa_device {
struct ib_sa_query {
void (*callback)(struct ib_sa_query *sa_query, int status,
- int num_prs, struct ib_sa_mad *mad);
+ struct ib_sa_mad *mad);
void (*release)(struct ib_sa_query *);
struct ib_sa_client *client;
struct ib_sa_port *port;
@@ -118,12 +118,6 @@ struct ib_sa_query {
u32 seq; /* Local svc request sequence number */
unsigned long timeout; /* Local svc timeout */
u8 path_use; /* How will the pathrecord be used */
-
- /* A separate buffer to save pathrecords of a response, as in cases
- * like IB/netlink, mulptiple pathrecords are supported, so that
- * mad->data is not large enough to hold them
- */
- void *resp_pr_data;
};
#define IB_SA_ENABLE_LOCAL_SERVICE 0x00000001
@@ -132,7 +126,7 @@ struct ib_sa_query {
struct ib_sa_path_query {
void (*callback)(int status, struct sa_path_rec *rec,
- int num_paths, void *context);
+ unsigned int num_paths, void *context);
void *context;
struct ib_sa_query sa_query;
struct sa_path_rec *conv_pr;
@@ -690,6 +684,8 @@ static const struct ib_field guidinfo_rec_table[] = {
.size_bits = 512 },
};
+#define RDMA_PRIMARY_PATH_MAX_REC_NUM 3
+
static inline void ib_sa_disable_local_svc(struct ib_sa_query *query)
{
query->flags &= ~IB_SA_ENABLE_LOCAL_SERVICE;
@@ -874,30 +870,21 @@ static void send_handler(struct ib_mad_agent *agent,
static void ib_nl_process_good_resolve_rsp(struct ib_sa_query *query,
const struct nlmsghdr *nlh)
{
- struct ib_path_rec_data *srec, *drec;
+ struct sa_path_rec recs[RDMA_PRIMARY_PATH_MAX_REC_NUM];
struct ib_sa_path_query *path_query;
+ struct ib_path_rec_data *rec_data;
struct ib_mad_send_wc mad_send_wc;
const struct nlattr *head, *curr;
struct ib_sa_mad *mad = NULL;
- int len, rem, num_prs = 0;
+ int len, rem, status = -EIO;
+ unsigned int num_prs = 0;
u32 mask = 0;
- int status = -EIO;
if (!query->callback)
goto out;
path_query = container_of(query, struct ib_sa_path_query, sa_query);
mad = query->mad_buf->mad;
- if (!path_query->conv_pr &&
- (be16_to_cpu(mad->mad_hdr.attr_id) == IB_SA_ATTR_PATH_REC)) {
- /* Need a larger buffer for possible multiple PRs */
- query->resp_pr_data = kvcalloc(RDMA_PRIMARY_PATH_MAX_REC_NUM,
- sizeof(*drec), GFP_KERNEL);
- if (!query->resp_pr_data) {
- query->callback(query, -ENOMEM, 0, NULL);
- return;
- }
- }
head = (const struct nlattr *) nlmsg_data(nlh);
len = nlmsg_len(nlh);
@@ -917,36 +904,41 @@ static void ib_nl_process_good_resolve_rsp(struct ib_sa_query *query,
break;
}
- drec = (struct ib_path_rec_data *)query->resp_pr_data;
nla_for_each_attr(curr, head, len, rem) {
if (curr->nla_type != LS_NLA_TYPE_PATH_RECORD)
continue;
- srec = nla_data(curr);
- if ((srec->flags & mask) != mask)
+ rec_data = nla_data(curr);
+ if ((rec_data->flags & mask) != mask)
continue;
- status = 0;
- if (!drec) {
- memcpy(mad->data, srec->path_rec,
- sizeof(srec->path_rec));
- num_prs = 1;
- break;
+ if ((query->flags & IB_SA_QUERY_OPA) ||
+ path_query->conv_pr) {
+ mad->mad_hdr.method |= IB_MGMT_METHOD_RESP;
+ memcpy(mad->data, rec_data->path_rec,
+ sizeof(rec_data->path_rec));
+ query->callback(query, 0, mad);
+ goto out;
}
- memcpy(drec, srec, sizeof(*drec));
- drec++;
+ status = 0;
+ ib_unpack(path_rec_table, ARRAY_SIZE(path_rec_table),
+ rec_data->path_rec, &recs[num_prs]);
+ recs[num_prs].flags = rec_data->flags;
+ recs[num_prs].rec_type = SA_PATH_REC_TYPE_IB;
+ sa_path_set_dmac_zero(&recs[num_prs]);
+
num_prs++;
if (num_prs >= RDMA_PRIMARY_PATH_MAX_REC_NUM)
break;
}
- if (!status)
+ if (!status) {
mad->mad_hdr.method |= IB_MGMT_METHOD_RESP;
-
- query->callback(query, status, num_prs, mad);
- kvfree(query->resp_pr_data);
- query->resp_pr_data = NULL;
+ path_query->callback(status, recs, num_prs,
+ path_query->context);
+ } else
+ query->callback(query, status, mad);
out:
mad_send_wc.send_buf = query->mad_buf;
@@ -1451,11 +1443,26 @@ static int opa_pr_query_possible(struct ib_sa_client *client,
return PR_IB_SUPPORTED;
}
-static void ib_sa_pr_callback_single(struct ib_sa_path_query *query,
- int status, struct ib_sa_mad *mad)
+static void ib_sa_path_rec_callback(struct ib_sa_query *sa_query,
+ int status, struct ib_sa_mad *mad)
{
+ struct ib_sa_path_query *query =
+ container_of(sa_query, struct ib_sa_path_query, sa_query);
struct sa_path_rec rec = {};
+ if (!mad) {
+ query->callback(status, NULL, 0, query->context);
+ return;
+ }
+
+ if (sa_query->flags & IB_SA_QUERY_OPA) {
+ ib_unpack(opa_path_rec_table, ARRAY_SIZE(opa_path_rec_table),
+ mad->data, &rec);
+ rec.rec_type = SA_PATH_REC_TYPE_OPA;
+ query->callback(status, &rec, 1, query->context);
+ return;
+ }
+
ib_unpack(path_rec_table, ARRAY_SIZE(path_rec_table),
mad->data, &rec);
rec.rec_type = SA_PATH_REC_TYPE_IB;
@@ -1472,71 +1479,6 @@ static void ib_sa_pr_callback_single(struct ib_sa_path_query *query,
}
}
-/**
- * ib_sa_pr_callback_multiple() - Parse path records then do callback.
- *
- * In a multiple-PR case the PRs are saved in "query->resp_pr_data"
- * (instead of"mad->data") and with "ib_path_rec_data" structure format,
- * so that rec->flags can be set to indicate the type of PR.
- * This is valid only in IB fabric.
- */
-static void ib_sa_pr_callback_multiple(struct ib_sa_path_query *query,
- int status, int num_prs,
- struct ib_path_rec_data *rec_data)
-{
- struct sa_path_rec *rec;
- int i;
-
- rec = kvcalloc(num_prs, sizeof(*rec), GFP_KERNEL);
- if (!rec) {
- query->callback(-ENOMEM, NULL, 0, query->context);
- return;
- }
-
- for (i = 0; i < num_prs; i++) {
- ib_unpack(path_rec_table, ARRAY_SIZE(path_rec_table),
- rec_data[i].path_rec, rec + i);
- rec[i].rec_type = SA_PATH_REC_TYPE_IB;
- sa_path_set_dmac_zero(rec + i);
- rec[i].flags = rec_data[i].flags;
- }
-
- query->callback(status, rec, num_prs, query->context);
- kvfree(rec);
-}
-
-static void ib_sa_path_rec_callback(struct ib_sa_query *sa_query,
- int status, int num_prs,
- struct ib_sa_mad *mad)
-{
- struct ib_sa_path_query *query =
- container_of(sa_query, struct ib_sa_path_query, sa_query);
- struct sa_path_rec rec;
-
- if (!mad || !num_prs) {
- query->callback(status, NULL, 0, query->context);
- return;
- }
-
- if (sa_query->flags & IB_SA_QUERY_OPA) {
- if (num_prs != 1) {
- query->callback(-EINVAL, NULL, 0, query->context);
- return;
- }
-
- ib_unpack(opa_path_rec_table, ARRAY_SIZE(opa_path_rec_table),
- mad->data, &rec);
- rec.rec_type = SA_PATH_REC_TYPE_OPA;
- query->callback(status, &rec, num_prs, query->context);
- } else {
- if (!sa_query->resp_pr_data)
- ib_sa_pr_callback_single(query, status, mad);
- else
- ib_sa_pr_callback_multiple(query, status, num_prs,
- sa_query->resp_pr_data);
- }
-}
-
static void ib_sa_path_rec_release(struct ib_sa_query *sa_query)
{
struct ib_sa_path_query *query =
@@ -1578,7 +1520,7 @@ int ib_sa_path_rec_get(struct ib_sa_client *client,
unsigned long timeout_ms, gfp_t gfp_mask,
void (*callback)(int status,
struct sa_path_rec *resp,
- int num_paths, void *context),
+ unsigned int num_paths, void *context),
void *context,
struct ib_sa_query **sa_query)
{
@@ -1677,8 +1619,7 @@ err1:
EXPORT_SYMBOL(ib_sa_path_rec_get);
static void ib_sa_mcmember_rec_callback(struct ib_sa_query *sa_query,
- int status, int num_prs,
- struct ib_sa_mad *mad)
+ int status, struct ib_sa_mad *mad)
{
struct ib_sa_mcmember_query *query =
container_of(sa_query, struct ib_sa_mcmember_query, sa_query);
@@ -1769,8 +1710,7 @@ err1:
/* Support GuidInfoRecord */
static void ib_sa_guidinfo_rec_callback(struct ib_sa_query *sa_query,
- int status, int num_paths,
- struct ib_sa_mad *mad)
+ int status, struct ib_sa_mad *mad)
{
struct ib_sa_guidinfo_query *query =
container_of(sa_query, struct ib_sa_guidinfo_query, sa_query);
@@ -1879,8 +1819,7 @@ static void ib_classportinfo_cb(void *context)
}
static void ib_sa_classport_info_rec_callback(struct ib_sa_query *sa_query,
- int status, int num_prs,
- struct ib_sa_mad *mad)
+ int status, struct ib_sa_mad *mad)
{
unsigned long flags;
struct ib_sa_classport_info_query *query =
@@ -2055,13 +1994,13 @@ static void send_handler(struct ib_mad_agent *agent,
/* No callback -- already got recv */
break;
case IB_WC_RESP_TIMEOUT_ERR:
- query->callback(query, -ETIMEDOUT, 0, NULL);
+ query->callback(query, -ETIMEDOUT, NULL);
break;
case IB_WC_WR_FLUSH_ERR:
- query->callback(query, -EINTR, 0, NULL);
+ query->callback(query, -EINTR, NULL);
break;
default:
- query->callback(query, -EIO, 0, NULL);
+ query->callback(query, -EIO, NULL);
break;
}
@@ -2089,10 +2028,10 @@ static void recv_handler(struct ib_mad_agent *mad_agent,
if (mad_recv_wc->wc->status == IB_WC_SUCCESS)
query->callback(query,
mad_recv_wc->recv_buf.mad->mad_hdr.status ?
- -EINVAL : 0, 1,
+ -EINVAL : 0,
(struct ib_sa_mad *) mad_recv_wc->recv_buf.mad);
else
- query->callback(query, -EIO, 0, NULL);
+ query->callback(query, -EIO, NULL);
}
ib_free_recv_mad(mad_recv_wc);
diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c
index 499a425a3379..ced615b5ea09 100644
--- a/drivers/infiniband/hw/cxgb4/cm.c
+++ b/drivers/infiniband/hw/cxgb4/cm.c
@@ -2676,6 +2676,9 @@ static int pass_establish(struct c4iw_dev *dev, struct sk_buff *skb)
u16 tcp_opt = ntohs(req->tcp_opt);
ep = get_ep_from_tid(dev, tid);
+ if (!ep)
+ return 0;
+
pr_debug("ep %p tid %u\n", ep, ep->hwtid);
ep->snd_seq = be32_to_cpu(req->snd_isn);
ep->rcv_seq = be32_to_cpu(req->rcv_isn);
@@ -4144,6 +4147,10 @@ static int rx_pkt(struct c4iw_dev *dev, struct sk_buff *skb)
if (neigh->dev->flags & IFF_LOOPBACK) {
pdev = ip_dev_find(&init_net, iph->daddr);
+ if (!pdev) {
+ pr_err("%s - failed to find device!\n", __func__);
+ goto free_dst;
+ }
e = cxgb4_l2t_get(dev->rdev.lldi.l2t, neigh,
pdev, 0);
pi = (struct port_info *)netdev_priv(pdev);
diff --git a/drivers/infiniband/hw/cxgb4/cq.c b/drivers/infiniband/hw/cxgb4/cq.c
index c7e8d7b3baa1..7e2835dcbc1c 100644
--- a/drivers/infiniband/hw/cxgb4/cq.c
+++ b/drivers/infiniband/hw/cxgb4/cq.c
@@ -767,7 +767,7 @@ static int __c4iw_poll_cq_one(struct c4iw_cq *chp, struct c4iw_qp *qhp,
goto out;
wc->wr_id = cookie;
- wc->qp = qhp ? &qhp->ibqp : NULL;
+ wc->qp = &qhp->ibqp;
wc->vendor_err = CQE_STATUS(&cqe);
wc->wc_flags = 0;
diff --git a/drivers/infiniband/hw/cxgb4/restrack.c b/drivers/infiniband/hw/cxgb4/restrack.c
index ff645b955a08..fd22c85d35f4 100644
--- a/drivers/infiniband/hw/cxgb4/restrack.c
+++ b/drivers/infiniband/hw/cxgb4/restrack.c
@@ -238,7 +238,7 @@ int c4iw_fill_res_cm_id_entry(struct sk_buff *msg,
if (rdma_nl_put_driver_u64_hex(msg, "history", epcp->history))
goto err_cancel_table;
- if (epcp->state == LISTEN) {
+ if (listen_ep) {
if (rdma_nl_put_driver_u32(msg, "stid", listen_ep->stid))
goto err_cancel_table;
if (rdma_nl_put_driver_u32(msg, "backlog", listen_ep->backlog))
diff --git a/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h b/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h
index a2f5e29ef226..1f79537fc8d1 100644
--- a/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h
+++ b/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h
@@ -122,9 +122,7 @@ struct fw_ri_dsgl {
__be16 nsge;
__be32 len0;
__be64 addr0;
-#ifndef C99_NOT_SUPPORTED
struct fw_ri_dsge_pair sge[];
-#endif
};
struct fw_ri_sge {
@@ -138,9 +136,7 @@ struct fw_ri_isgl {
__u8 r1;
__be16 nsge;
__be32 r2;
-#ifndef C99_NOT_SUPPORTED
struct fw_ri_sge sge[];
-#endif
};
struct fw_ri_immd {
@@ -148,9 +144,7 @@ struct fw_ri_immd {
__u8 r1;
__be16 r2;
__be32 immdlen;
-#ifndef C99_NOT_SUPPORTED
__u8 data[];
-#endif
};
struct fw_ri_tpte {
@@ -320,9 +314,7 @@ struct fw_ri_res_wr {
__be32 op_nres;
__be32 len16_pkd;
__u64 cookie;
-#ifndef C99_NOT_SUPPORTED
struct fw_ri_res res[];
-#endif
};
#define FW_RI_RES_WR_NRES_S 0
@@ -562,12 +554,10 @@ struct fw_ri_rdma_write_wr {
__be32 plen;
__be32 stag_sink;
__be64 to_sink;
-#ifndef C99_NOT_SUPPORTED
union {
- struct fw_ri_immd immd_src[0];
- struct fw_ri_isgl isgl_src[0];
+ DECLARE_FLEX_ARRAY(struct fw_ri_immd, immd_src);
+ DECLARE_FLEX_ARRAY(struct fw_ri_isgl, isgl_src);
} u;
-#endif
};
struct fw_ri_send_wr {
@@ -581,12 +571,10 @@ struct fw_ri_send_wr {
__be32 plen;
__be32 r3;
__be64 r4;
-#ifndef C99_NOT_SUPPORTED
union {
- struct fw_ri_immd immd_src[0];
- struct fw_ri_isgl isgl_src[0];
+ DECLARE_FLEX_ARRAY(struct fw_ri_immd, immd_src);
+ DECLARE_FLEX_ARRAY(struct fw_ri_isgl, isgl_src);
} u;
-#endif
};
#define FW_RI_SEND_WR_SENDOP_S 0
@@ -618,12 +606,10 @@ struct fw_ri_rdma_write_cmpl_wr {
struct fw_ri_isgl isgl_src;
} u_cmpl;
__be64 r3;
-#ifndef C99_NOT_SUPPORTED
union fw_ri_write {
- struct fw_ri_immd immd_src[0];
- struct fw_ri_isgl isgl_src[0];
+ DECLARE_FLEX_ARRAY(struct fw_ri_immd, immd_src);
+ DECLARE_FLEX_ARRAY(struct fw_ri_isgl, isgl_src);
} u;
-#endif
};
struct fw_ri_rdma_read_wr {
diff --git a/drivers/infiniband/hw/erdma/erdma_hw.h b/drivers/infiniband/hw/erdma/erdma_hw.h
index ab371fec610c..4c38d99c73f1 100644
--- a/drivers/infiniband/hw/erdma/erdma_hw.h
+++ b/drivers/infiniband/hw/erdma/erdma_hw.h
@@ -397,7 +397,7 @@ struct erdma_write_sqe {
__le32 rsvd;
- struct erdma_sge sgl[0];
+ struct erdma_sge sgl[];
};
struct erdma_send_sqe {
@@ -408,7 +408,7 @@ struct erdma_send_sqe {
};
__le32 length;
- struct erdma_sge sgl[0];
+ struct erdma_sge sgl[];
};
struct erdma_readreq_sqe {
diff --git a/drivers/infiniband/hw/erdma/erdma_verbs.c b/drivers/infiniband/hw/erdma/erdma_verbs.c
index 5dab1e87975b..9c30d78730aa 100644
--- a/drivers/infiniband/hw/erdma/erdma_verbs.c
+++ b/drivers/infiniband/hw/erdma/erdma_verbs.c
@@ -1110,12 +1110,14 @@ int erdma_mmap(struct ib_ucontext *ctx, struct vm_area_struct *vma)
prot = pgprot_device(vma->vm_page_prot);
break;
default:
- return -EINVAL;
+ err = -EINVAL;
+ goto put_entry;
}
err = rdma_user_mmap_io(ctx, vma, PFN_DOWN(entry->address), PAGE_SIZE,
prot, rdma_entry);
+put_entry:
rdma_user_mmap_entry_put(rdma_entry);
return err;
}
diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c
index ebe970f76232..90b672feed83 100644
--- a/drivers/infiniband/hw/hfi1/chip.c
+++ b/drivers/infiniband/hw/hfi1/chip.c
@@ -1056,7 +1056,7 @@ static void read_link_down_reason(struct hfi1_devdata *dd, u8 *ldr);
static void handle_temp_err(struct hfi1_devdata *dd);
static void dc_shutdown(struct hfi1_devdata *dd);
static void dc_start(struct hfi1_devdata *dd);
-static int qos_rmt_entries(struct hfi1_devdata *dd, unsigned int *mp,
+static int qos_rmt_entries(unsigned int n_krcv_queues, unsigned int *mp,
unsigned int *np);
static void clear_full_mgmt_pkey(struct hfi1_pportdata *ppd);
static int wait_link_transfer_active(struct hfi1_devdata *dd, int wait_ms);
@@ -13362,7 +13362,6 @@ static int set_up_context_variables(struct hfi1_devdata *dd)
int ret;
unsigned ngroups;
int rmt_count;
- int user_rmt_reduced;
u32 n_usr_ctxts;
u32 send_contexts = chip_send_contexts(dd);
u32 rcv_contexts = chip_rcv_contexts(dd);
@@ -13421,28 +13420,34 @@ static int set_up_context_variables(struct hfi1_devdata *dd)
(num_kernel_contexts + n_usr_ctxts),
&node_affinity.real_cpu_mask);
/*
- * The RMT entries are currently allocated as shown below:
- * 1. QOS (0 to 128 entries);
- * 2. FECN (num_kernel_context - 1 + num_user_contexts +
- * num_netdev_contexts);
- * 3. netdev (num_netdev_contexts).
- * It should be noted that FECN oversubscribe num_netdev_contexts
- * entries of RMT because both netdev and PSM could allocate any receive
- * context between dd->first_dyn_alloc_text and dd->num_rcv_contexts,
- * and PSM FECN must reserve an RMT entry for each possible PSM receive
- * context.
+ * RMT entries are allocated as follows:
+ * 1. QOS (0 to 128 entries)
+ * 2. FECN (num_kernel_context - 1 [a] + num_user_contexts +
+ * num_netdev_contexts [b])
+ * 3. netdev (NUM_NETDEV_MAP_ENTRIES)
+ *
+ * Notes:
+ * [a] Kernel contexts (except control) are included in FECN if kernel
+ * TID_RDMA is active.
+ * [b] Netdev and user contexts are randomly allocated from the same
+ * context pool, so FECN must cover all contexts in the pool.
*/
- rmt_count = qos_rmt_entries(dd, NULL, NULL) + (num_netdev_contexts * 2);
- if (HFI1_CAP_IS_KSET(TID_RDMA))
- rmt_count += num_kernel_contexts - 1;
- if (rmt_count + n_usr_ctxts > NUM_MAP_ENTRIES) {
- user_rmt_reduced = NUM_MAP_ENTRIES - rmt_count;
- dd_dev_err(dd,
- "RMT size is reducing the number of user receive contexts from %u to %d\n",
- n_usr_ctxts,
- user_rmt_reduced);
- /* recalculate */
- n_usr_ctxts = user_rmt_reduced;
+ rmt_count = qos_rmt_entries(num_kernel_contexts - 1, NULL, NULL)
+ + (HFI1_CAP_IS_KSET(TID_RDMA) ? num_kernel_contexts - 1
+ : 0)
+ + n_usr_ctxts
+ + num_netdev_contexts
+ + NUM_NETDEV_MAP_ENTRIES;
+ if (rmt_count > NUM_MAP_ENTRIES) {
+ int over = rmt_count - NUM_MAP_ENTRIES;
+ /* try to squish user contexts, minimum of 1 */
+ if (over >= n_usr_ctxts) {
+ dd_dev_err(dd, "RMT overflow: reduce the requested number of contexts\n");
+ return -EINVAL;
+ }
+ dd_dev_err(dd, "RMT overflow: reducing # user contexts from %u to %u\n",
+ n_usr_ctxts, n_usr_ctxts - over);
+ n_usr_ctxts -= over;
}
/* the first N are kernel contexts, the rest are user/netdev contexts */
@@ -14299,15 +14304,15 @@ static void clear_rsm_rule(struct hfi1_devdata *dd, u8 rule_index)
}
/* return the number of RSM map table entries that will be used for QOS */
-static int qos_rmt_entries(struct hfi1_devdata *dd, unsigned int *mp,
+static int qos_rmt_entries(unsigned int n_krcv_queues, unsigned int *mp,
unsigned int *np)
{
int i;
unsigned int m, n;
- u8 max_by_vl = 0;
+ uint max_by_vl = 0;
/* is QOS active at all? */
- if (dd->n_krcv_queues <= MIN_KERNEL_KCTXTS ||
+ if (n_krcv_queues < MIN_KERNEL_KCTXTS ||
num_vls == 1 ||
krcvqsset <= 1)
goto no_qos;
@@ -14365,7 +14370,7 @@ static void init_qos(struct hfi1_devdata *dd, struct rsm_map_table *rmt)
if (!rmt)
goto bail;
- rmt_entries = qos_rmt_entries(dd, &m, &n);
+ rmt_entries = qos_rmt_entries(dd->n_krcv_queues - 1, &m, &n);
if (rmt_entries == 0)
goto bail;
qpns_per_vl = 1 << m;
diff --git a/drivers/infiniband/hw/hfi1/exp_rcv.h b/drivers/infiniband/hw/hfi1/exp_rcv.h
index c6291bbf723c..41f7fe5d1839 100644
--- a/drivers/infiniband/hw/hfi1/exp_rcv.h
+++ b/drivers/infiniband/hw/hfi1/exp_rcv.h
@@ -133,12 +133,13 @@ static inline struct tid_group *tid_group_pop(struct exp_tid_set *set)
return grp;
}
-static inline u32 rcventry2tidinfo(u32 rcventry)
+static inline u32 create_tid(u32 rcventry, u32 npages)
{
u32 pair = rcventry & ~0x1;
return EXP_TID_SET(IDX, pair >> 1) |
- EXP_TID_SET(CTRL, 1 << (rcventry - pair));
+ EXP_TID_SET(CTRL, 1 << (rcventry - pair)) |
+ EXP_TID_SET(LEN, npages);
}
/**
diff --git a/drivers/infiniband/hw/hfi1/file_ops.c b/drivers/infiniband/hw/hfi1/file_ops.c
index 7c5d487ec916..b1d6ca7e9708 100644
--- a/drivers/infiniband/hw/hfi1/file_ops.c
+++ b/drivers/infiniband/hw/hfi1/file_ops.c
@@ -306,6 +306,17 @@ static ssize_t hfi1_write_iter(struct kiocb *kiocb, struct iov_iter *from)
return reqs;
}
+static inline void mmap_cdbg(u16 ctxt, u8 subctxt, u8 type, u8 mapio, u8 vmf,
+ u64 memaddr, void *memvirt, dma_addr_t memdma,
+ ssize_t memlen, struct vm_area_struct *vma)
+{
+ hfi1_cdbg(PROC,
+ "%u:%u type:%u io/vf/dma:%d/%d/%d, addr:0x%llx, len:%lu(%lu), flags:0x%lx",
+ ctxt, subctxt, type, mapio, vmf, !!memdma,
+ memaddr ?: (u64)memvirt, memlen,
+ vma->vm_end - vma->vm_start, vma->vm_flags);
+}
+
static int hfi1_file_mmap(struct file *fp, struct vm_area_struct *vma)
{
struct hfi1_filedata *fd = fp->private_data;
@@ -315,6 +326,7 @@ static int hfi1_file_mmap(struct file *fp, struct vm_area_struct *vma)
u64 token = vma->vm_pgoff << PAGE_SHIFT,
memaddr = 0;
void *memvirt = NULL;
+ dma_addr_t memdma = 0;
u8 subctxt, mapio = 0, vmf = 0, type;
ssize_t memlen = 0;
int ret = 0;
@@ -334,6 +346,11 @@ static int hfi1_file_mmap(struct file *fp, struct vm_area_struct *vma)
goto done;
}
+ /*
+ * vm_pgoff is used as a buffer selector cookie. Always mmap from
+ * the beginning.
+ */
+ vma->vm_pgoff = 0;
flags = vma->vm_flags;
switch (type) {
@@ -355,7 +372,8 @@ static int hfi1_file_mmap(struct file *fp, struct vm_area_struct *vma)
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
mapio = 1;
break;
- case PIO_CRED:
+ case PIO_CRED: {
+ u64 cr_page_offset;
if (flags & VM_WRITE) {
ret = -EPERM;
goto done;
@@ -365,10 +383,11 @@ static int hfi1_file_mmap(struct file *fp, struct vm_area_struct *vma)
* second or third page allocated for credit returns (if number
* of enabled contexts > 64 and 128 respectively).
*/
- memvirt = dd->cr_base[uctxt->numa_id].va;
- memaddr = virt_to_phys(memvirt) +
- (((u64)uctxt->sc->hw_free -
- (u64)dd->cr_base[uctxt->numa_id].va) & PAGE_MASK);
+ cr_page_offset = ((u64)uctxt->sc->hw_free -
+ (u64)dd->cr_base[uctxt->numa_id].va) &
+ PAGE_MASK;
+ memvirt = dd->cr_base[uctxt->numa_id].va + cr_page_offset;
+ memdma = dd->cr_base[uctxt->numa_id].dma + cr_page_offset;
memlen = PAGE_SIZE;
flags &= ~VM_MAYWRITE;
flags |= VM_DONTCOPY | VM_DONTEXPAND;
@@ -378,14 +397,16 @@ static int hfi1_file_mmap(struct file *fp, struct vm_area_struct *vma)
* memory been flagged as non-cached?
*/
/* vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); */
- mapio = 1;
break;
+ }
case RCV_HDRQ:
memlen = rcvhdrq_size(uctxt);
memvirt = uctxt->rcvhdrq;
+ memdma = uctxt->rcvhdrq_dma;
break;
case RCV_EGRBUF: {
- unsigned long addr;
+ unsigned long vm_start_save;
+ unsigned long vm_end_save;
int i;
/*
* The RcvEgr buffer need to be handled differently
@@ -403,25 +424,35 @@ static int hfi1_file_mmap(struct file *fp, struct vm_area_struct *vma)
ret = -EPERM;
goto done;
}
- vma->vm_flags &= ~VM_MAYWRITE;
- addr = vma->vm_start;
+ vm_flags_clear(vma, VM_MAYWRITE);
+ /*
+ * Mmap multiple separate allocations into a single vma. From
+ * here, dma_mmap_coherent() calls dma_direct_mmap(), which
+ * requires the mmap to exactly fill the vma starting at
+ * vma_start. Adjust the vma start and end for each eager
+ * buffer segment mapped. Restore the originals when done.
+ */
+ vm_start_save = vma->vm_start;
+ vm_end_save = vma->vm_end;
+ vma->vm_end = vma->vm_start;
for (i = 0 ; i < uctxt->egrbufs.numbufs; i++) {
memlen = uctxt->egrbufs.buffers[i].len;
memvirt = uctxt->egrbufs.buffers[i].addr;
- ret = remap_pfn_range(
- vma, addr,
- /*
- * virt_to_pfn() does the same, but
- * it's not available on x86_64
- * when CONFIG_MMU is enabled.
- */
- PFN_DOWN(__pa(memvirt)),
- memlen,
- vma->vm_page_prot);
- if (ret < 0)
+ memdma = uctxt->egrbufs.buffers[i].dma;
+ vma->vm_end += memlen;
+ mmap_cdbg(ctxt, subctxt, type, mapio, vmf, memaddr,
+ memvirt, memdma, memlen, vma);
+ ret = dma_mmap_coherent(&dd->pcidev->dev, vma,
+ memvirt, memdma, memlen);
+ if (ret < 0) {
+ vma->vm_start = vm_start_save;
+ vma->vm_end = vm_end_save;
goto done;
- addr += memlen;
+ }
+ vma->vm_start += memlen;
}
+ vma->vm_start = vm_start_save;
+ vma->vm_end = vm_end_save;
ret = 0;
goto done;
}
@@ -481,6 +512,7 @@ static int hfi1_file_mmap(struct file *fp, struct vm_area_struct *vma)
}
memlen = PAGE_SIZE;
memvirt = (void *)hfi1_rcvhdrtail_kvaddr(uctxt);
+ memdma = uctxt->rcvhdrqtailaddr_dma;
flags &= ~VM_MAYWRITE;
break;
case SUBCTXT_UREGS:
@@ -528,15 +560,16 @@ static int hfi1_file_mmap(struct file *fp, struct vm_area_struct *vma)
goto done;
}
- vma->vm_flags = flags;
- hfi1_cdbg(PROC,
- "%u:%u type:%u io/vf:%d/%d, addr:0x%llx, len:%lu(%lu), flags:0x%lx\n",
- ctxt, subctxt, type, mapio, vmf, memaddr, memlen,
- vma->vm_end - vma->vm_start, vma->vm_flags);
+ vm_flags_reset(vma, flags);
+ mmap_cdbg(ctxt, subctxt, type, mapio, vmf, memaddr, memvirt, memdma,
+ memlen, vma);
if (vmf) {
vma->vm_pgoff = PFN_DOWN(memaddr);
vma->vm_ops = &vm_ops;
ret = 0;
+ } else if (memdma) {
+ ret = dma_mmap_coherent(&dd->pcidev->dev, vma,
+ memvirt, memdma, memlen);
} else if (mapio) {
ret = io_remap_pfn_range(vma, vma->vm_start,
PFN_DOWN(memaddr),
diff --git a/drivers/infiniband/hw/hfi1/init.c b/drivers/infiniband/hw/hfi1/init.c
index 24c0f0d257fc..62b6c5020039 100644
--- a/drivers/infiniband/hw/hfi1/init.c
+++ b/drivers/infiniband/hw/hfi1/init.c
@@ -464,7 +464,7 @@ bail:
*
* This wrapper is the free function that matches hfi1_create_ctxtdata().
* When a context is done being used (kernel or user), this function is called
- * for the "final" put to match the kref init from hf1i_create_ctxtdata().
+ * for the "final" put to match the kref init from hfi1_create_ctxtdata().
* Other users of the context do a get/put sequence to make sure that the
* structure isn't removed while in use.
*/
diff --git a/drivers/infiniband/hw/hfi1/sdma.c b/drivers/infiniband/hw/hfi1/sdma.c
index a95b654f5254..8ed20392e9f0 100644
--- a/drivers/infiniband/hw/hfi1/sdma.c
+++ b/drivers/infiniband/hw/hfi1/sdma.c
@@ -3160,8 +3160,7 @@ int _pad_sdma_tx_descs(struct hfi1_devdata *dd, struct sdma_txreq *tx)
{
int rval = 0;
- tx->num_desc++;
- if ((unlikely(tx->num_desc == tx->desc_limit))) {
+ if ((unlikely(tx->num_desc + 1 == tx->desc_limit))) {
rval = _extend_sdma_tx_descs(dd, tx);
if (rval) {
__sdma_txclean(dd, tx);
@@ -3174,6 +3173,7 @@ int _pad_sdma_tx_descs(struct hfi1_devdata *dd, struct sdma_txreq *tx)
SDMA_MAP_NONE,
dd->sdma_pad_phys,
sizeof(u32) - (tx->packet_len & (sizeof(u32) - 1)));
+ tx->num_desc++;
_sdma_close_tx(dd, tx);
return rval;
}
diff --git a/drivers/infiniband/hw/hfi1/sdma.h b/drivers/infiniband/hw/hfi1/sdma.h
index d8170fcbfbdd..b023fc461bd5 100644
--- a/drivers/infiniband/hw/hfi1/sdma.h
+++ b/drivers/infiniband/hw/hfi1/sdma.h
@@ -631,14 +631,13 @@ static inline void sdma_txclean(struct hfi1_devdata *dd, struct sdma_txreq *tx)
static inline void _sdma_close_tx(struct hfi1_devdata *dd,
struct sdma_txreq *tx)
{
- tx->descp[tx->num_desc].qw[0] |=
- SDMA_DESC0_LAST_DESC_FLAG;
- tx->descp[tx->num_desc].qw[1] |=
- dd->default_desc1;
+ u16 last_desc = tx->num_desc - 1;
+
+ tx->descp[last_desc].qw[0] |= SDMA_DESC0_LAST_DESC_FLAG;
+ tx->descp[last_desc].qw[1] |= dd->default_desc1;
if (tx->flags & SDMA_TXREQ_F_URGENT)
- tx->descp[tx->num_desc].qw[1] |=
- (SDMA_DESC1_HEAD_TO_HOST_FLAG |
- SDMA_DESC1_INT_REQ_FLAG);
+ tx->descp[last_desc].qw[1] |= (SDMA_DESC1_HEAD_TO_HOST_FLAG |
+ SDMA_DESC1_INT_REQ_FLAG);
}
static inline int _sdma_txadd_daddr(
@@ -655,6 +654,7 @@ static inline int _sdma_txadd_daddr(
type,
addr, len);
WARN_ON(len > tx->tlen);
+ tx->num_desc++;
tx->tlen -= len;
/* special cases for last */
if (!tx->tlen) {
@@ -666,7 +666,6 @@ static inline int _sdma_txadd_daddr(
_sdma_close_tx(dd, tx);
}
}
- tx->num_desc++;
return rval;
}
diff --git a/drivers/infiniband/hw/hfi1/user_exp_rcv.c b/drivers/infiniband/hw/hfi1/user_exp_rcv.c
index 350884d5f089..96058baf36ed 100644
--- a/drivers/infiniband/hw/hfi1/user_exp_rcv.c
+++ b/drivers/infiniband/hw/hfi1/user_exp_rcv.c
@@ -27,8 +27,7 @@ static bool tid_cover_invalidate(struct mmu_interval_notifier *mni,
const struct mmu_notifier_range *range,
unsigned long cur_seq);
static int program_rcvarray(struct hfi1_filedata *fd, struct tid_user_buf *,
- struct tid_group *grp,
- unsigned int start, u16 count,
+ struct tid_group *grp, u16 count,
u32 *tidlist, unsigned int *tididx,
unsigned int *pmapped);
static int unprogram_rcvarray(struct hfi1_filedata *fd, u32 tidinfo);
@@ -250,7 +249,7 @@ int hfi1_user_exp_rcv_setup(struct hfi1_filedata *fd,
int ret = 0, need_group = 0, pinned;
struct hfi1_ctxtdata *uctxt = fd->uctxt;
struct hfi1_devdata *dd = uctxt->dd;
- unsigned int ngroups, pageidx = 0, pageset_count,
+ unsigned int ngroups, pageset_count,
tididx = 0, mapped, mapped_pages = 0;
u32 *tidlist = NULL;
struct tid_user_buf *tidbuf;
@@ -332,7 +331,7 @@ int hfi1_user_exp_rcv_setup(struct hfi1_filedata *fd,
tid_group_pop(&uctxt->tid_group_list);
ret = program_rcvarray(fd, tidbuf, grp,
- pageidx, dd->rcv_entries.group_size,
+ dd->rcv_entries.group_size,
tidlist, &tididx, &mapped);
/*
* If there was a failure to program the RcvArray
@@ -348,11 +347,10 @@ int hfi1_user_exp_rcv_setup(struct hfi1_filedata *fd,
tid_group_add_tail(grp, &uctxt->tid_full_list);
ngroups--;
- pageidx += ret;
mapped_pages += mapped;
}
- while (pageidx < pageset_count) {
+ while (tididx < pageset_count) {
struct tid_group *grp, *ptr;
/*
* If we don't have any partially used tid groups, check
@@ -374,11 +372,11 @@ int hfi1_user_exp_rcv_setup(struct hfi1_filedata *fd,
*/
list_for_each_entry_safe(grp, ptr, &uctxt->tid_used_list.list,
list) {
- unsigned use = min_t(unsigned, pageset_count - pageidx,
+ unsigned use = min_t(unsigned, pageset_count - tididx,
grp->size - grp->used);
ret = program_rcvarray(fd, tidbuf, grp,
- pageidx, use, tidlist,
+ use, tidlist,
&tididx, &mapped);
if (ret < 0) {
hfi1_cdbg(TID,
@@ -390,11 +388,10 @@ int hfi1_user_exp_rcv_setup(struct hfi1_filedata *fd,
tid_group_move(grp,
&uctxt->tid_used_list,
&uctxt->tid_full_list);
- pageidx += ret;
mapped_pages += mapped;
need_group = 0;
/* Check if we are done so we break out early */
- if (pageidx >= pageset_count)
+ if (tididx >= pageset_count)
break;
} else if (WARN_ON(ret == 0)) {
/*
@@ -638,7 +635,6 @@ static u32 find_phys_blocks(struct tid_user_buf *tidbuf, unsigned int npages)
* struct tid_pageset holding information on physically contiguous
* chunks from the user buffer), and other fields.
* @grp: RcvArray group
- * @start: starting index into sets array
* @count: number of struct tid_pageset's to program
* @tidlist: the array of u32 elements when the information about the
* programmed RcvArray entries is to be encoded.
@@ -658,14 +654,14 @@ static u32 find_phys_blocks(struct tid_user_buf *tidbuf, unsigned int npages)
* number of RcvArray entries programmed.
*/
static int program_rcvarray(struct hfi1_filedata *fd, struct tid_user_buf *tbuf,
- struct tid_group *grp,
- unsigned int start, u16 count,
+ struct tid_group *grp, u16 count,
u32 *tidlist, unsigned int *tididx,
unsigned int *pmapped)
{
struct hfi1_ctxtdata *uctxt = fd->uctxt;
struct hfi1_devdata *dd = uctxt->dd;
u16 idx;
+ unsigned int start = *tididx;
u32 tidinfo = 0, rcventry, useidx = 0;
int mapped = 0;
@@ -710,8 +706,7 @@ static int program_rcvarray(struct hfi1_filedata *fd, struct tid_user_buf *tbuf,
return ret;
mapped += npages;
- tidinfo = rcventry2tidinfo(rcventry - uctxt->expected_base) |
- EXP_TID_SET(LEN, npages);
+ tidinfo = create_tid(rcventry - uctxt->expected_base, npages);
tidlist[(*tididx)++] = tidinfo;
grp->used++;
grp->map |= 1 << useidx++;
@@ -795,20 +790,20 @@ static int unprogram_rcvarray(struct hfi1_filedata *fd, u32 tidinfo)
struct hfi1_ctxtdata *uctxt = fd->uctxt;
struct hfi1_devdata *dd = uctxt->dd;
struct tid_rb_node *node;
- u8 tidctrl = EXP_TID_GET(tidinfo, CTRL);
+ u32 tidctrl = EXP_TID_GET(tidinfo, CTRL);
u32 tididx = EXP_TID_GET(tidinfo, IDX) << 1, rcventry;
- if (tididx >= uctxt->expected_count) {
- dd_dev_err(dd, "Invalid RcvArray entry (%u) index for ctxt %u\n",
- tididx, uctxt->ctxt);
- return -EINVAL;
- }
-
- if (tidctrl == 0x3)
+ if (tidctrl == 0x3 || tidctrl == 0x0)
return -EINVAL;
rcventry = tididx + (tidctrl - 1);
+ if (rcventry >= uctxt->expected_count) {
+ dd_dev_err(dd, "Invalid RcvArray entry (%u) index for ctxt %u\n",
+ rcventry, uctxt->ctxt);
+ return -EINVAL;
+ }
+
node = fd->entry_to_rb[rcventry];
if (!node || node->rcventry != (uctxt->expected_base + rcventry))
return -EBADF;
@@ -920,9 +915,8 @@ static bool tid_rb_invalidate(struct mmu_interval_notifier *mni,
spin_lock(&fdata->invalid_lock);
if (fdata->invalid_tid_idx < uctxt->expected_count) {
fdata->invalid_tids[fdata->invalid_tid_idx] =
- rcventry2tidinfo(node->rcventry - uctxt->expected_base);
- fdata->invalid_tids[fdata->invalid_tid_idx] |=
- EXP_TID_SET(LEN, node->npages);
+ create_tid(node->rcventry - uctxt->expected_base,
+ node->npages);
if (!fdata->invalid_tid_idx) {
unsigned long *ev;
diff --git a/drivers/infiniband/hw/hfi1/user_pages.c b/drivers/infiniband/hw/hfi1/user_pages.c
index 7bce963e2ae6..36aaedc65145 100644
--- a/drivers/infiniband/hw/hfi1/user_pages.c
+++ b/drivers/infiniband/hw/hfi1/user_pages.c
@@ -29,33 +29,52 @@ MODULE_PARM_DESC(cache_size, "Send and receive side cache size limit (in MB)");
bool hfi1_can_pin_pages(struct hfi1_devdata *dd, struct mm_struct *mm,
u32 nlocked, u32 npages)
{
- unsigned long ulimit = rlimit(RLIMIT_MEMLOCK), pinned, cache_limit,
- size = (cache_size * (1UL << 20)); /* convert to bytes */
- unsigned int usr_ctxts =
- dd->num_rcv_contexts - dd->first_dyn_alloc_ctxt;
- bool can_lock = capable(CAP_IPC_LOCK);
+ unsigned long ulimit_pages;
+ unsigned long cache_limit_pages;
+ unsigned int usr_ctxts;
/*
- * Calculate per-cache size. The calculation below uses only a quarter
- * of the available per-context limit. This leaves space for other
- * pinning. Should we worry about shared ctxts?
+ * Perform RLIMIT_MEMLOCK based checks unless CAP_IPC_LOCK is present.
*/
- cache_limit = (ulimit / usr_ctxts) / 4;
-
- /* If ulimit isn't set to "unlimited" and is smaller than cache_size. */
- if (ulimit != (-1UL) && size > cache_limit)
- size = cache_limit;
-
- /* Convert to number of pages */
- size = DIV_ROUND_UP(size, PAGE_SIZE);
-
- pinned = atomic64_read(&mm->pinned_vm);
+ if (!capable(CAP_IPC_LOCK)) {
+ ulimit_pages =
+ DIV_ROUND_DOWN_ULL(rlimit(RLIMIT_MEMLOCK), PAGE_SIZE);
+
+ /*
+ * Pinning these pages would exceed this process's locked memory
+ * limit.
+ */
+ if (atomic64_read(&mm->pinned_vm) + npages > ulimit_pages)
+ return false;
+
+ /*
+ * Only allow 1/4 of the user's RLIMIT_MEMLOCK to be used for HFI
+ * caches. This fraction is then equally distributed among all
+ * existing user contexts. Note that if RLIMIT_MEMLOCK is
+ * 'unlimited' (-1), the value of this limit will be > 2^42 pages
+ * (2^64 / 2^12 / 2^8 / 2^2).
+ *
+ * The effectiveness of this check may be reduced if I/O occurs on
+ * some user contexts before all user contexts are created. This
+ * check assumes that this process is the only one using this
+ * context (e.g., the corresponding fd was not passed to another
+ * process for concurrent access) as there is no per-context,
+ * per-process tracking of pinned pages. It also assumes that each
+ * user context has only one cache to limit.
+ */
+ usr_ctxts = dd->num_rcv_contexts - dd->first_dyn_alloc_ctxt;
+ if (nlocked + npages > (ulimit_pages / usr_ctxts / 4))
+ return false;
+ }
- /* First, check the absolute limit against all pinned pages. */
- if (pinned + npages >= ulimit && !can_lock)
+ /*
+ * Pinning these pages would exceed the size limit for this cache.
+ */
+ cache_limit_pages = cache_size * (1024 * 1024) / PAGE_SIZE;
+ if (nlocked + npages > cache_limit_pages)
return false;
- return ((nlocked + npages) <= size) || can_lock;
+ return true;
}
int hfi1_acquire_user_pages(struct mm_struct *mm, unsigned long vaddr, size_t npages,
diff --git a/drivers/infiniband/hw/hfi1/verbs.c b/drivers/infiniband/hw/hfi1/verbs.c
index e6e17984553c..7f6d7fc7951d 100644
--- a/drivers/infiniband/hw/hfi1/verbs.c
+++ b/drivers/infiniband/hw/hfi1/verbs.c
@@ -1598,13 +1598,11 @@ static const char * const driver_cntr_names[] = {
"DRIVER_EgrHdrFull"
};
-static DEFINE_MUTEX(cntr_names_lock); /* protects the *_cntr_names bufers */
static struct rdma_stat_desc *dev_cntr_descs;
static struct rdma_stat_desc *port_cntr_descs;
int num_driver_cntrs = ARRAY_SIZE(driver_cntr_names);
static int num_dev_cntrs;
static int num_port_cntrs;
-static int cntr_names_initialized;
/*
* Convert a list of names separated by '\n' into an array of NULL terminated
@@ -1615,8 +1613,8 @@ static int init_cntr_names(const char *names_in, const size_t names_len,
int num_extra_names, int *num_cntrs,
struct rdma_stat_desc **cntr_descs)
{
- struct rdma_stat_desc *q;
- char *names_out, *p;
+ struct rdma_stat_desc *names_out;
+ char *p;
int i, n;
n = 0;
@@ -1624,65 +1622,45 @@ static int init_cntr_names(const char *names_in, const size_t names_len,
if (names_in[i] == '\n')
n++;
- names_out =
- kzalloc((n + num_extra_names) * sizeof(*q) + names_len,
- GFP_KERNEL);
+ names_out = kzalloc((n + num_extra_names) * sizeof(*names_out)
+ + names_len,
+ GFP_KERNEL);
if (!names_out) {
*num_cntrs = 0;
*cntr_descs = NULL;
return -ENOMEM;
}
- p = names_out + (n + num_extra_names) * sizeof(*q);
+ p = (char *)&names_out[n + num_extra_names];
memcpy(p, names_in, names_len);
- q = (struct rdma_stat_desc *)names_out;
for (i = 0; i < n; i++) {
- q[i].name = p;
+ names_out[i].name = p;
p = strchr(p, '\n');
*p++ = '\0';
}
*num_cntrs = n;
- *cntr_descs = (struct rdma_stat_desc *)names_out;
+ *cntr_descs = names_out;
return 0;
}
-static int init_counters(struct ib_device *ibdev)
-{
- struct hfi1_devdata *dd = dd_from_ibdev(ibdev);
- int i, err = 0;
-
- mutex_lock(&cntr_names_lock);
- if (cntr_names_initialized)
- goto out_unlock;
-
- err = init_cntr_names(dd->cntrnames, dd->cntrnameslen, num_driver_cntrs,
- &num_dev_cntrs, &dev_cntr_descs);
- if (err)
- goto out_unlock;
-
- for (i = 0; i < num_driver_cntrs; i++)
- dev_cntr_descs[num_dev_cntrs + i].name = driver_cntr_names[i];
-
- err = init_cntr_names(dd->portcntrnames, dd->portcntrnameslen, 0,
- &num_port_cntrs, &port_cntr_descs);
- if (err) {
- kfree(dev_cntr_descs);
- dev_cntr_descs = NULL;
- goto out_unlock;
- }
- cntr_names_initialized = 1;
-
-out_unlock:
- mutex_unlock(&cntr_names_lock);
- return err;
-}
-
static struct rdma_hw_stats *hfi1_alloc_hw_device_stats(struct ib_device *ibdev)
{
- if (init_counters(ibdev))
- return NULL;
+ if (!dev_cntr_descs) {
+ struct hfi1_devdata *dd = dd_from_ibdev(ibdev);
+ int i, err;
+
+ err = init_cntr_names(dd->cntrnames, dd->cntrnameslen,
+ num_driver_cntrs,
+ &num_dev_cntrs, &dev_cntr_descs);
+ if (err)
+ return NULL;
+
+ for (i = 0; i < num_driver_cntrs; i++)
+ dev_cntr_descs[num_dev_cntrs + i].name =
+ driver_cntr_names[i];
+ }
return rdma_alloc_hw_stats_struct(dev_cntr_descs,
num_dev_cntrs + num_driver_cntrs,
RDMA_HW_STATS_DEFAULT_LIFESPAN);
@@ -1691,8 +1669,16 @@ static struct rdma_hw_stats *hfi1_alloc_hw_device_stats(struct ib_device *ibdev)
static struct rdma_hw_stats *hfi_alloc_hw_port_stats(struct ib_device *ibdev,
u32 port_num)
{
- if (init_counters(ibdev))
- return NULL;
+ if (!port_cntr_descs) {
+ struct hfi1_devdata *dd = dd_from_ibdev(ibdev);
+ int err;
+
+ err = init_cntr_names(dd->portcntrnames, dd->portcntrnameslen,
+ 0,
+ &num_port_cntrs, &port_cntr_descs);
+ if (err)
+ return NULL;
+ }
return rdma_alloc_hw_stats_struct(port_cntr_descs, num_port_cntrs,
RDMA_HW_STATS_DEFAULT_LIFESPAN);
}
@@ -1917,13 +1903,10 @@ void hfi1_unregister_ib_device(struct hfi1_devdata *dd)
del_timer_sync(&dev->mem_timer);
verbs_txreq_exit(dev);
- mutex_lock(&cntr_names_lock);
kfree(dev_cntr_descs);
kfree(port_cntr_descs);
dev_cntr_descs = NULL;
port_cntr_descs = NULL;
- cntr_names_initialized = 0;
- mutex_unlock(&cntr_names_lock);
}
void hfi1_cnp_rcv(struct hfi1_packet *packet)
diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h
index f701cc86896b..84239b907de2 100644
--- a/drivers/infiniband/hw/hns/hns_roce_device.h
+++ b/drivers/infiniband/hw/hns/hns_roce_device.h
@@ -144,6 +144,7 @@ enum {
HNS_ROCE_CAP_FLAG_DIRECT_WQE = BIT(12),
HNS_ROCE_CAP_FLAG_SDI_MODE = BIT(14),
HNS_ROCE_CAP_FLAG_STASH = BIT(17),
+ HNS_ROCE_CAP_FLAG_CQE_INLINE = BIT(19),
};
#define HNS_ROCE_DB_TYPE_COUNT 2
@@ -567,21 +568,6 @@ struct hns_roce_mbox_msg {
struct hns_roce_dev;
-struct hns_roce_rinl_sge {
- void *addr;
- u32 len;
-};
-
-struct hns_roce_rinl_wqe {
- struct hns_roce_rinl_sge *sg_list;
- u32 sge_cnt;
-};
-
-struct hns_roce_rinl_buf {
- struct hns_roce_rinl_wqe *wqe_list;
- u32 wqe_cnt;
-};
-
enum {
HNS_ROCE_FLUSH_FLAG = 0,
};
@@ -632,7 +618,6 @@ struct hns_roce_qp {
/* 0: flush needed, 1: unneeded */
unsigned long flush_flag;
struct hns_roce_work flush_work;
- struct hns_roce_rinl_buf rq_inl_buf;
struct list_head node; /* all qps are on a list */
struct list_head rq_node; /* all recv qps are on a list */
struct list_head sq_node; /* all send qps are on a list */
@@ -887,7 +872,7 @@ struct hns_roce_hw {
u32 step_idx);
int (*modify_qp)(struct ib_qp *ibqp, const struct ib_qp_attr *attr,
int attr_mask, enum ib_qp_state cur_state,
- enum ib_qp_state new_state);
+ enum ib_qp_state new_state, struct ib_udata *udata);
int (*qp_flow_control_init)(struct hns_roce_dev *hr_dev,
struct hns_roce_qp *hr_qp);
void (*dereg_mr)(struct hns_roce_dev *hr_dev);
diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
index b2421883993b..dbf97fe5948f 100644
--- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
+++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
@@ -821,22 +821,10 @@ static void fill_recv_sge_to_wqe(const struct ib_recv_wr *wr, void *wqe,
static void fill_rq_wqe(struct hns_roce_qp *hr_qp, const struct ib_recv_wr *wr,
u32 wqe_idx, u32 max_sge)
{
- struct hns_roce_rinl_sge *sge_list;
void *wqe = NULL;
- u32 i;
wqe = hns_roce_get_recv_wqe(hr_qp, wqe_idx);
fill_recv_sge_to_wqe(wr, wqe, max_sge, hr_qp->rq.rsv_sge);
-
- /* rq support inline data */
- if (hr_qp->rq_inl_buf.wqe_cnt) {
- sge_list = hr_qp->rq_inl_buf.wqe_list[wqe_idx].sg_list;
- hr_qp->rq_inl_buf.wqe_list[wqe_idx].sge_cnt = (u32)wr->num_sge;
- for (i = 0; i < wr->num_sge; i++) {
- sge_list[i].addr = (void *)(u64)wr->sg_list[i].addr;
- sge_list[i].len = wr->sg_list[i].length;
- }
- }
}
static int hns_roce_v2_post_recv(struct ib_qp *ibqp,
@@ -2849,7 +2837,7 @@ static int free_mr_modify_rsv_qp(struct hns_roce_dev *hr_dev,
attr->port_num = 1;
attr->qp_access_flags = IB_ACCESS_REMOTE_WRITE;
ret = hr_dev->hw->modify_qp(&hr_qp->ibqp, attr, mask, IB_QPS_INIT,
- IB_QPS_INIT);
+ IB_QPS_INIT, NULL);
if (ret) {
ibdev_err(ibdev, "failed to modify qp to init, ret = %d.\n",
ret);
@@ -2871,7 +2859,7 @@ static int free_mr_modify_rsv_qp(struct hns_roce_dev *hr_dev,
rdma_ah_set_sl(&attr->ah_attr, (u8)sl_num);
ret = hr_dev->hw->modify_qp(&hr_qp->ibqp, attr, mask, IB_QPS_INIT,
- IB_QPS_RTR);
+ IB_QPS_RTR, NULL);
hr_dev->loop_idc = loopback;
if (ret) {
ibdev_err(ibdev, "failed to modify qp to rtr, ret = %d.\n",
@@ -2886,7 +2874,7 @@ static int free_mr_modify_rsv_qp(struct hns_roce_dev *hr_dev,
attr->retry_cnt = HNS_ROCE_FREE_MR_USED_QP_RETRY_CNT;
attr->timeout = HNS_ROCE_FREE_MR_USED_QP_TIMEOUT;
ret = hr_dev->hw->modify_qp(&hr_qp->ibqp, attr, mask, IB_QPS_RTR,
- IB_QPS_RTS);
+ IB_QPS_RTS, NULL);
if (ret)
ibdev_err(ibdev, "failed to modify qp to rts, ret = %d.\n",
ret);
@@ -3730,39 +3718,6 @@ static int hns_roce_v2_req_notify_cq(struct ib_cq *ibcq,
return 0;
}
-static int hns_roce_handle_recv_inl_wqe(struct hns_roce_v2_cqe *cqe,
- struct hns_roce_qp *qp,
- struct ib_wc *wc)
-{
- struct hns_roce_rinl_sge *sge_list;
- u32 wr_num, wr_cnt, sge_num;
- u32 sge_cnt, data_len, size;
- void *wqe_buf;
-
- wr_num = hr_reg_read(cqe, CQE_WQE_IDX);
- wr_cnt = wr_num & (qp->rq.wqe_cnt - 1);
-
- sge_list = qp->rq_inl_buf.wqe_list[wr_cnt].sg_list;
- sge_num = qp->rq_inl_buf.wqe_list[wr_cnt].sge_cnt;
- wqe_buf = hns_roce_get_recv_wqe(qp, wr_cnt);
- data_len = wc->byte_len;
-
- for (sge_cnt = 0; (sge_cnt < sge_num) && (data_len); sge_cnt++) {
- size = min(sge_list[sge_cnt].len, data_len);
- memcpy((void *)sge_list[sge_cnt].addr, wqe_buf, size);
-
- data_len -= size;
- wqe_buf += size;
- }
-
- if (unlikely(data_len)) {
- wc->status = IB_WC_LOC_LEN_ERR;
- return -EAGAIN;
- }
-
- return 0;
-}
-
static int sw_comp(struct hns_roce_qp *hr_qp, struct hns_roce_wq *wq,
int num_entries, struct ib_wc *wc)
{
@@ -3974,22 +3929,10 @@ static void fill_send_wc(struct ib_wc *wc, struct hns_roce_v2_cqe *cqe)
wc->opcode = ib_opcode;
}
-static inline bool is_rq_inl_enabled(struct ib_wc *wc, u32 hr_opcode,
- struct hns_roce_v2_cqe *cqe)
-{
- return wc->qp->qp_type != IB_QPT_UD && wc->qp->qp_type != IB_QPT_GSI &&
- (hr_opcode == HNS_ROCE_V2_OPCODE_SEND ||
- hr_opcode == HNS_ROCE_V2_OPCODE_SEND_WITH_IMM ||
- hr_opcode == HNS_ROCE_V2_OPCODE_SEND_WITH_INV) &&
- hr_reg_read(cqe, CQE_RQ_INLINE);
-}
-
static int fill_recv_wc(struct ib_wc *wc, struct hns_roce_v2_cqe *cqe)
{
- struct hns_roce_qp *qp = to_hr_qp(wc->qp);
u32 hr_opcode;
int ib_opcode;
- int ret;
wc->byte_len = le32_to_cpu(cqe->byte_cnt);
@@ -4014,12 +3957,6 @@ static int fill_recv_wc(struct ib_wc *wc, struct hns_roce_v2_cqe *cqe)
else
wc->opcode = ib_opcode;
- if (is_rq_inl_enabled(wc, hr_opcode, cqe)) {
- ret = hns_roce_handle_recv_inl_wqe(cqe, qp, wc);
- if (unlikely(ret))
- return ret;
- }
-
wc->sl = hr_reg_read(cqe, CQE_SL);
wc->src_qp = hr_reg_read(cqe, CQE_RMT_QPN);
wc->slid = 0;
@@ -4445,10 +4382,6 @@ static void modify_qp_reset_to_init(struct ib_qp *ibqp,
hr_reg_write(context, QPC_RQ_DB_RECORD_ADDR_H,
upper_32_bits(hr_qp->rdb.dma));
- if (ibqp->qp_type != IB_QPT_UD && ibqp->qp_type != IB_QPT_GSI)
- hr_reg_write_bool(context, QPC_RQIE,
- hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RQ_INLINE);
-
hr_reg_write(context, QPC_RX_CQN, get_cqn(ibqp->recv_cq));
if (ibqp->srq) {
@@ -4639,8 +4572,11 @@ static inline enum ib_mtu get_mtu(struct ib_qp *ibqp,
static int modify_qp_init_to_rtr(struct ib_qp *ibqp,
const struct ib_qp_attr *attr, int attr_mask,
struct hns_roce_v2_qp_context *context,
- struct hns_roce_v2_qp_context *qpc_mask)
+ struct hns_roce_v2_qp_context *qpc_mask,
+ struct ib_udata *udata)
{
+ struct hns_roce_ucontext *uctx = rdma_udata_to_drv_context(udata,
+ struct hns_roce_ucontext, ibucontext);
struct hns_roce_dev *hr_dev = to_hr_dev(ibqp->device);
struct hns_roce_qp *hr_qp = to_hr_qp(ibqp);
struct ib_device *ibdev = &hr_dev->ib_dev;
@@ -4760,6 +4696,26 @@ static int modify_qp_init_to_rtr(struct ib_qp *ibqp,
hr_reg_write(context, QPC_LP_SGEN_INI, 3);
hr_reg_clear(qpc_mask, QPC_LP_SGEN_INI);
+ if (udata && ibqp->qp_type == IB_QPT_RC &&
+ (uctx->config & HNS_ROCE_RQ_INLINE_FLAGS)) {
+ hr_reg_write_bool(context, QPC_RQIE,
+ hr_dev->caps.flags &
+ HNS_ROCE_CAP_FLAG_RQ_INLINE);
+ hr_reg_clear(qpc_mask, QPC_RQIE);
+ }
+
+ if (udata &&
+ (ibqp->qp_type == IB_QPT_RC || ibqp->qp_type == IB_QPT_XRC_TGT) &&
+ (uctx->config & HNS_ROCE_CQE_INLINE_FLAGS)) {
+ hr_reg_write_bool(context, QPC_CQEIE,
+ hr_dev->caps.flags &
+ HNS_ROCE_CAP_FLAG_CQE_INLINE);
+ hr_reg_clear(qpc_mask, QPC_CQEIE);
+
+ hr_reg_write(context, QPC_CQEIS, 0);
+ hr_reg_clear(qpc_mask, QPC_CQEIS);
+ }
+
return 0;
}
@@ -5107,7 +5063,8 @@ static int hns_roce_v2_set_abs_fields(struct ib_qp *ibqp,
enum ib_qp_state cur_state,
enum ib_qp_state new_state,
struct hns_roce_v2_qp_context *context,
- struct hns_roce_v2_qp_context *qpc_mask)
+ struct hns_roce_v2_qp_context *qpc_mask,
+ struct ib_udata *udata)
{
struct hns_roce_dev *hr_dev = to_hr_dev(ibqp->device);
int ret = 0;
@@ -5124,7 +5081,7 @@ static int hns_roce_v2_set_abs_fields(struct ib_qp *ibqp,
modify_qp_init_to_init(ibqp, attr, context, qpc_mask);
} else if (cur_state == IB_QPS_INIT && new_state == IB_QPS_RTR) {
ret = modify_qp_init_to_rtr(ibqp, attr, attr_mask, context,
- qpc_mask);
+ qpc_mask, udata);
} else if (cur_state == IB_QPS_RTR && new_state == IB_QPS_RTS) {
ret = modify_qp_rtr_to_rts(ibqp, attr, attr_mask, context,
qpc_mask);
@@ -5329,7 +5286,7 @@ static void v2_set_flushed_fields(struct ib_qp *ibqp,
static int hns_roce_v2_modify_qp(struct ib_qp *ibqp,
const struct ib_qp_attr *attr,
int attr_mask, enum ib_qp_state cur_state,
- enum ib_qp_state new_state)
+ enum ib_qp_state new_state, struct ib_udata *udata)
{
struct hns_roce_dev *hr_dev = to_hr_dev(ibqp->device);
struct hns_roce_qp *hr_qp = to_hr_qp(ibqp);
@@ -5352,7 +5309,7 @@ static int hns_roce_v2_modify_qp(struct ib_qp *ibqp,
memset(qpc_mask, 0xff, hr_dev->caps.qpc_sz);
ret = hns_roce_v2_set_abs_fields(ibqp, attr, attr_mask, cur_state,
- new_state, context, qpc_mask);
+ new_state, context, qpc_mask, udata);
if (ret)
goto out;
@@ -5555,7 +5512,7 @@ static int hns_roce_v2_destroy_qp_common(struct hns_roce_dev *hr_dev,
if (modify_qp_is_ok(hr_qp)) {
/* Modify qp to reset before destroying qp */
ret = hns_roce_v2_modify_qp(&hr_qp->ibqp, NULL, 0,
- hr_qp->state, IB_QPS_RESET);
+ hr_qp->state, IB_QPS_RESET, udata);
if (ret)
ibdev_err(ibdev,
"failed to modify QP to RST, ret = %d.\n",
diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h
index b1b3e1e0b84e..af9d00225cdf 100644
--- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h
+++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h
@@ -531,7 +531,8 @@ struct hns_roce_v2_qp_context {
#define QPC_RQ_RTY_TX_ERR QPC_FIELD_LOC(607, 607)
#define QPC_RX_CQN QPC_FIELD_LOC(631, 608)
#define QPC_XRC_QP_TYPE QPC_FIELD_LOC(632, 632)
-#define QPC_RSV3 QPC_FIELD_LOC(634, 633)
+#define QPC_CQEIE QPC_FIELD_LOC(633, 633)
+#define QPC_CQEIS QPC_FIELD_LOC(634, 634)
#define QPC_MIN_RNR_TIME QPC_FIELD_LOC(639, 635)
#define QPC_RQ_PRODUCER_IDX QPC_FIELD_LOC(655, 640)
#define QPC_RQ_CONSUMER_IDX QPC_FIELD_LOC(671, 656)
diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c
index 8ba68ac12388..485e110ca433 100644
--- a/drivers/infiniband/hw/hns/hns_roce_main.c
+++ b/drivers/infiniband/hw/hns/hns_roce_main.c
@@ -379,6 +379,18 @@ static int hns_roce_alloc_ucontext(struct ib_ucontext *uctx,
resp.max_inline_data = hr_dev->caps.max_sq_inline;
}
+ if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RQ_INLINE) {
+ context->config |= ucmd.config & HNS_ROCE_RQ_INLINE_FLAGS;
+ if (context->config & HNS_ROCE_RQ_INLINE_FLAGS)
+ resp.config |= HNS_ROCE_RSP_RQ_INLINE_FLAGS;
+ }
+
+ if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_CQE_INLINE) {
+ context->config |= ucmd.config & HNS_ROCE_CQE_INLINE_FLAGS;
+ if (context->config & HNS_ROCE_CQE_INLINE_FLAGS)
+ resp.config |= HNS_ROCE_RSP_CQE_INLINE_FLAGS;
+ }
+
ret = hns_roce_uar_alloc(hr_dev, &context->uar);
if (ret)
goto error_fail_uar_alloc;
@@ -443,14 +455,15 @@ static int hns_roce_mmap(struct ib_ucontext *uctx, struct vm_area_struct *vma)
prot = pgprot_device(vma->vm_page_prot);
break;
default:
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
ret = rdma_user_mmap_io(uctx, vma, pfn, rdma_entry->npages * PAGE_SIZE,
prot, rdma_entry);
+out:
rdma_user_mmap_entry_put(rdma_entry);
-
return ret;
}
diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c
index 0ae335fb205c..d855a917f4cf 100644
--- a/drivers/infiniband/hw/hns/hns_roce_qp.c
+++ b/drivers/infiniband/hw/hns/hns_roce_qp.c
@@ -433,7 +433,6 @@ static int set_rq_size(struct hns_roce_dev *hr_dev, struct ib_qp_cap *cap,
if (!has_rq) {
hr_qp->rq.wqe_cnt = 0;
hr_qp->rq.max_gs = 0;
- hr_qp->rq_inl_buf.wqe_cnt = 0;
cap->max_recv_wr = 0;
cap->max_recv_sge = 0;
@@ -463,12 +462,6 @@ static int set_rq_size(struct hns_roce_dev *hr_dev, struct ib_qp_cap *cap,
hr_qp->rq.max_gs);
hr_qp->rq.wqe_cnt = cnt;
- if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RQ_INLINE &&
- hr_qp->ibqp.qp_type != IB_QPT_UD &&
- hr_qp->ibqp.qp_type != IB_QPT_GSI)
- hr_qp->rq_inl_buf.wqe_cnt = cnt;
- else
- hr_qp->rq_inl_buf.wqe_cnt = 0;
cap->max_recv_wr = cnt;
cap->max_recv_sge = hr_qp->rq.max_gs - hr_qp->rq.rsv_sge;
@@ -732,49 +725,6 @@ static int hns_roce_qp_has_rq(struct ib_qp_init_attr *attr)
return 1;
}
-static int alloc_rq_inline_buf(struct hns_roce_qp *hr_qp,
- struct ib_qp_init_attr *init_attr)
-{
- u32 max_recv_sge = init_attr->cap.max_recv_sge;
- u32 wqe_cnt = hr_qp->rq_inl_buf.wqe_cnt;
- struct hns_roce_rinl_wqe *wqe_list;
- int i;
-
- /* allocate recv inline buf */
- wqe_list = kcalloc(wqe_cnt, sizeof(struct hns_roce_rinl_wqe),
- GFP_KERNEL);
- if (!wqe_list)
- goto err;
-
- /* Allocate a continuous buffer for all inline sge we need */
- wqe_list[0].sg_list = kcalloc(wqe_cnt, (max_recv_sge *
- sizeof(struct hns_roce_rinl_sge)),
- GFP_KERNEL);
- if (!wqe_list[0].sg_list)
- goto err_wqe_list;
-
- /* Assign buffers of sg_list to each inline wqe */
- for (i = 1; i < wqe_cnt; i++)
- wqe_list[i].sg_list = &wqe_list[0].sg_list[i * max_recv_sge];
-
- hr_qp->rq_inl_buf.wqe_list = wqe_list;
-
- return 0;
-
-err_wqe_list:
- kfree(wqe_list);
-
-err:
- return -ENOMEM;
-}
-
-static void free_rq_inline_buf(struct hns_roce_qp *hr_qp)
-{
- if (hr_qp->rq_inl_buf.wqe_list)
- kfree(hr_qp->rq_inl_buf.wqe_list[0].sg_list);
- kfree(hr_qp->rq_inl_buf.wqe_list);
-}
-
static int alloc_qp_buf(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
struct ib_qp_init_attr *init_attr,
struct ib_udata *udata, unsigned long addr)
@@ -783,18 +733,6 @@ static int alloc_qp_buf(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
struct hns_roce_buf_attr buf_attr = {};
int ret;
- if (!udata && hr_qp->rq_inl_buf.wqe_cnt) {
- ret = alloc_rq_inline_buf(hr_qp, init_attr);
- if (ret) {
- ibdev_err(ibdev,
- "failed to alloc inline buf, ret = %d.\n",
- ret);
- return ret;
- }
- } else {
- hr_qp->rq_inl_buf.wqe_list = NULL;
- }
-
ret = set_wqe_buf_attr(hr_dev, hr_qp, &buf_attr);
if (ret) {
ibdev_err(ibdev, "failed to split WQE buf, ret = %d.\n", ret);
@@ -814,7 +752,6 @@ static int alloc_qp_buf(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
return 0;
err_inline:
- free_rq_inline_buf(hr_qp);
return ret;
}
@@ -822,7 +759,6 @@ err_inline:
static void free_qp_buf(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp)
{
hns_roce_mtr_destroy(hr_dev, &hr_qp->mtr);
- free_rq_inline_buf(hr_qp);
}
static inline bool user_qp_has_sdb(struct hns_roce_dev *hr_dev,
@@ -1410,7 +1346,7 @@ int hns_roce_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
goto out;
ret = hr_dev->hw->modify_qp(ibqp, attr, attr_mask, cur_state,
- new_state);
+ new_state, udata);
out:
mutex_unlock(&hr_qp->mutex);
diff --git a/drivers/infiniband/hw/irdma/hw.c b/drivers/infiniband/hw/irdma/hw.c
index ab246447520b..2e1e2bad0401 100644
--- a/drivers/infiniband/hw/irdma/hw.c
+++ b/drivers/infiniband/hw/irdma/hw.c
@@ -483,6 +483,8 @@ static int irdma_save_msix_info(struct irdma_pci_f *rf)
iw_qvlist->num_vectors = rf->msix_count;
if (rf->msix_count <= num_online_cpus())
rf->msix_shared = true;
+ else if (rf->msix_count > num_online_cpus() + 1)
+ rf->msix_count = num_online_cpus() + 1;
pmsix = rf->msix_entries;
for (i = 0, ceq_idx = 0; i < rf->msix_count; i++, iw_qvinfo++) {
diff --git a/drivers/infiniband/hw/irdma/verbs.c b/drivers/infiniband/hw/irdma/verbs.c
index f6973ea55eda..1b2e3e800c9a 100644
--- a/drivers/infiniband/hw/irdma/verbs.c
+++ b/drivers/infiniband/hw/irdma/verbs.c
@@ -2745,6 +2745,162 @@ static int irdma_hwreg_mr(struct irdma_device *iwdev, struct irdma_mr *iwmr,
return ret;
}
+static int irdma_reg_user_mr_type_mem(struct irdma_mr *iwmr, int access)
+{
+ struct irdma_device *iwdev = to_iwdev(iwmr->ibmr.device);
+ struct irdma_pbl *iwpbl = &iwmr->iwpbl;
+ bool use_pbles;
+ u32 stag;
+ int err;
+
+ use_pbles = iwmr->page_cnt != 1;
+
+ err = irdma_setup_pbles(iwdev->rf, iwmr, use_pbles, false);
+ if (err)
+ return err;
+
+ if (use_pbles) {
+ err = irdma_check_mr_contiguous(&iwpbl->pble_alloc,
+ iwmr->page_size);
+ if (err) {
+ irdma_free_pble(iwdev->rf->pble_rsrc, &iwpbl->pble_alloc);
+ iwpbl->pbl_allocated = false;
+ }
+ }
+
+ stag = irdma_create_stag(iwdev);
+ if (!stag) {
+ err = -ENOMEM;
+ goto free_pble;
+ }
+
+ iwmr->stag = stag;
+ iwmr->ibmr.rkey = stag;
+ iwmr->ibmr.lkey = stag;
+ err = irdma_hwreg_mr(iwdev, iwmr, access);
+ if (err)
+ goto err_hwreg;
+
+ return 0;
+
+err_hwreg:
+ irdma_free_stag(iwdev, stag);
+
+free_pble:
+ if (iwpbl->pble_alloc.level != PBLE_LEVEL_0 && iwpbl->pbl_allocated)
+ irdma_free_pble(iwdev->rf->pble_rsrc, &iwpbl->pble_alloc);
+
+ return err;
+}
+
+static struct irdma_mr *irdma_alloc_iwmr(struct ib_umem *region,
+ struct ib_pd *pd, u64 virt,
+ enum irdma_memreg_type reg_type)
+{
+ struct irdma_device *iwdev = to_iwdev(pd->device);
+ struct irdma_pbl *iwpbl = NULL;
+ struct irdma_mr *iwmr = NULL;
+ unsigned long pgsz_bitmap;
+
+ iwmr = kzalloc(sizeof(*iwmr), GFP_KERNEL);
+ if (!iwmr)
+ return ERR_PTR(-ENOMEM);
+
+ iwpbl = &iwmr->iwpbl;
+ iwpbl->iwmr = iwmr;
+ iwmr->region = region;
+ iwmr->ibmr.pd = pd;
+ iwmr->ibmr.device = pd->device;
+ iwmr->ibmr.iova = virt;
+ iwmr->type = reg_type;
+
+ pgsz_bitmap = (reg_type == IRDMA_MEMREG_TYPE_MEM) ?
+ iwdev->rf->sc_dev.hw_attrs.page_size_cap : PAGE_SIZE;
+
+ iwmr->page_size = ib_umem_find_best_pgsz(region, pgsz_bitmap, virt);
+ if (unlikely(!iwmr->page_size)) {
+ kfree(iwmr);
+ return ERR_PTR(-EOPNOTSUPP);
+ }
+
+ iwmr->len = region->length;
+ iwpbl->user_base = virt;
+ iwmr->page_cnt = ib_umem_num_dma_blocks(region, iwmr->page_size);
+
+ return iwmr;
+}
+
+static void irdma_free_iwmr(struct irdma_mr *iwmr)
+{
+ kfree(iwmr);
+}
+
+static int irdma_reg_user_mr_type_qp(struct irdma_mem_reg_req req,
+ struct ib_udata *udata,
+ struct irdma_mr *iwmr)
+{
+ struct irdma_device *iwdev = to_iwdev(iwmr->ibmr.device);
+ struct irdma_pbl *iwpbl = &iwmr->iwpbl;
+ struct irdma_ucontext *ucontext = NULL;
+ unsigned long flags;
+ bool use_pbles;
+ u32 total;
+ int err;
+
+ total = req.sq_pages + req.rq_pages + 1;
+ if (total > iwmr->page_cnt)
+ return -EINVAL;
+
+ total = req.sq_pages + req.rq_pages;
+ use_pbles = total > 2;
+ err = irdma_handle_q_mem(iwdev, &req, iwpbl, use_pbles);
+ if (err)
+ return err;
+
+ ucontext = rdma_udata_to_drv_context(udata, struct irdma_ucontext,
+ ibucontext);
+ spin_lock_irqsave(&ucontext->qp_reg_mem_list_lock, flags);
+ list_add_tail(&iwpbl->list, &ucontext->qp_reg_mem_list);
+ iwpbl->on_list = true;
+ spin_unlock_irqrestore(&ucontext->qp_reg_mem_list_lock, flags);
+
+ return 0;
+}
+
+static int irdma_reg_user_mr_type_cq(struct irdma_mem_reg_req req,
+ struct ib_udata *udata,
+ struct irdma_mr *iwmr)
+{
+ struct irdma_device *iwdev = to_iwdev(iwmr->ibmr.device);
+ struct irdma_pbl *iwpbl = &iwmr->iwpbl;
+ struct irdma_ucontext *ucontext = NULL;
+ u8 shadow_pgcnt = 1;
+ unsigned long flags;
+ bool use_pbles;
+ u32 total;
+ int err;
+
+ if (iwdev->rf->sc_dev.hw_attrs.uk_attrs.feature_flags & IRDMA_FEATURE_CQ_RESIZE)
+ shadow_pgcnt = 0;
+ total = req.cq_pages + shadow_pgcnt;
+ if (total > iwmr->page_cnt)
+ return -EINVAL;
+
+ use_pbles = req.cq_pages > 1;
+ err = irdma_handle_q_mem(iwdev, &req, iwpbl, use_pbles);
+ if (err)
+ return err;
+
+ ucontext = rdma_udata_to_drv_context(udata, struct irdma_ucontext,
+ ibucontext);
+ spin_lock_irqsave(&ucontext->cq_reg_mem_list_lock, flags);
+ list_add_tail(&iwpbl->list, &ucontext->cq_reg_mem_list);
+ iwpbl->on_list = true;
+ spin_unlock_irqrestore(&ucontext->cq_reg_mem_list_lock, flags);
+
+ return 0;
+}
+
/**
* irdma_reg_user_mr - Register a user memory region
* @pd: ptr of pd
@@ -2760,18 +2916,10 @@ static struct ib_mr *irdma_reg_user_mr(struct ib_pd *pd, u64 start, u64 len,
{
#define IRDMA_MEM_REG_MIN_REQ_LEN offsetofend(struct irdma_mem_reg_req, sq_pages)
struct irdma_device *iwdev = to_iwdev(pd->device);
- struct irdma_ucontext *ucontext;
- struct irdma_pble_alloc *palloc;
- struct irdma_pbl *iwpbl;
- struct irdma_mr *iwmr;
- struct ib_umem *region;
- struct irdma_mem_reg_req req;
- u32 total, stag = 0;
- u8 shadow_pgcnt = 1;
- bool use_pbles = false;
- unsigned long flags;
- int err = -EINVAL;
- int ret;
+ struct irdma_mem_reg_req req = {};
+ struct ib_umem *region = NULL;
+ struct irdma_mr *iwmr = NULL;
+ int err;
if (len > iwdev->rf->sc_dev.hw_attrs.max_mr_size)
return ERR_PTR(-EINVAL);
@@ -2792,122 +2940,80 @@ static struct ib_mr *irdma_reg_user_mr(struct ib_pd *pd, u64 start, u64 len,
return ERR_PTR(-EFAULT);
}
- iwmr = kzalloc(sizeof(*iwmr), GFP_KERNEL);
- if (!iwmr) {
+ iwmr = irdma_alloc_iwmr(region, pd, virt, req.reg_type);
+ if (IS_ERR(iwmr)) {
ib_umem_release(region);
- return ERR_PTR(-ENOMEM);
- }
-
- iwpbl = &iwmr->iwpbl;
- iwpbl->iwmr = iwmr;
- iwmr->region = region;
- iwmr->ibmr.pd = pd;
- iwmr->ibmr.device = pd->device;
- iwmr->ibmr.iova = virt;
- iwmr->page_size = PAGE_SIZE;
-
- if (req.reg_type == IRDMA_MEMREG_TYPE_MEM) {
- iwmr->page_size = ib_umem_find_best_pgsz(region,
- iwdev->rf->sc_dev.hw_attrs.page_size_cap,
- virt);
- if (unlikely(!iwmr->page_size)) {
- kfree(iwmr);
- ib_umem_release(region);
- return ERR_PTR(-EOPNOTSUPP);
- }
+ return (struct ib_mr *)iwmr;
}
- iwmr->len = region->length;
- iwpbl->user_base = virt;
- palloc = &iwpbl->pble_alloc;
- iwmr->type = req.reg_type;
- iwmr->page_cnt = ib_umem_num_dma_blocks(region, iwmr->page_size);
switch (req.reg_type) {
case IRDMA_MEMREG_TYPE_QP:
- total = req.sq_pages + req.rq_pages + shadow_pgcnt;
- if (total > iwmr->page_cnt) {
- err = -EINVAL;
- goto error;
- }
- total = req.sq_pages + req.rq_pages;
- use_pbles = (total > 2);
- err = irdma_handle_q_mem(iwdev, &req, iwpbl, use_pbles);
+ err = irdma_reg_user_mr_type_qp(req, udata, iwmr);
if (err)
goto error;
- ucontext = rdma_udata_to_drv_context(udata, struct irdma_ucontext,
- ibucontext);
- spin_lock_irqsave(&ucontext->qp_reg_mem_list_lock, flags);
- list_add_tail(&iwpbl->list, &ucontext->qp_reg_mem_list);
- iwpbl->on_list = true;
- spin_unlock_irqrestore(&ucontext->qp_reg_mem_list_lock, flags);
break;
case IRDMA_MEMREG_TYPE_CQ:
- if (iwdev->rf->sc_dev.hw_attrs.uk_attrs.feature_flags & IRDMA_FEATURE_CQ_RESIZE)
- shadow_pgcnt = 0;
- total = req.cq_pages + shadow_pgcnt;
- if (total > iwmr->page_cnt) {
- err = -EINVAL;
- goto error;
- }
-
- use_pbles = (req.cq_pages > 1);
- err = irdma_handle_q_mem(iwdev, &req, iwpbl, use_pbles);
+ err = irdma_reg_user_mr_type_cq(req, udata, iwmr);
if (err)
goto error;
-
- ucontext = rdma_udata_to_drv_context(udata, struct irdma_ucontext,
- ibucontext);
- spin_lock_irqsave(&ucontext->cq_reg_mem_list_lock, flags);
- list_add_tail(&iwpbl->list, &ucontext->cq_reg_mem_list);
- iwpbl->on_list = true;
- spin_unlock_irqrestore(&ucontext->cq_reg_mem_list_lock, flags);
break;
case IRDMA_MEMREG_TYPE_MEM:
- use_pbles = (iwmr->page_cnt != 1);
-
- err = irdma_setup_pbles(iwdev->rf, iwmr, use_pbles, false);
+ err = irdma_reg_user_mr_type_mem(iwmr, access);
if (err)
goto error;
- if (use_pbles) {
- ret = irdma_check_mr_contiguous(palloc,
- iwmr->page_size);
- if (ret) {
- irdma_free_pble(iwdev->rf->pble_rsrc, palloc);
- iwpbl->pbl_allocated = false;
- }
- }
-
- stag = irdma_create_stag(iwdev);
- if (!stag) {
- err = -ENOMEM;
- goto error;
- }
-
- iwmr->stag = stag;
- iwmr->ibmr.rkey = stag;
- iwmr->ibmr.lkey = stag;
- err = irdma_hwreg_mr(iwdev, iwmr, access);
- if (err) {
- irdma_free_stag(iwdev, stag);
- goto error;
- }
-
break;
default:
+ err = -EINVAL;
goto error;
}
- iwmr->type = req.reg_type;
-
return &iwmr->ibmr;
-
error:
- if (palloc->level != PBLE_LEVEL_0 && iwpbl->pbl_allocated)
- irdma_free_pble(iwdev->rf->pble_rsrc, palloc);
ib_umem_release(region);
- kfree(iwmr);
+ irdma_free_iwmr(iwmr);
+
+ return ERR_PTR(err);
+}
+
+static struct ib_mr *irdma_reg_user_mr_dmabuf(struct ib_pd *pd, u64 start,
+ u64 len, u64 virt,
+ int fd, int access,
+ struct ib_udata *udata)
+{
+ struct irdma_device *iwdev = to_iwdev(pd->device);
+ struct ib_umem_dmabuf *umem_dmabuf;
+ struct irdma_mr *iwmr;
+ int err;
+
+ if (len > iwdev->rf->sc_dev.hw_attrs.max_mr_size)
+ return ERR_PTR(-EINVAL);
+
+ umem_dmabuf = ib_umem_dmabuf_get_pinned(pd->device, start, len, fd, access);
+ if (IS_ERR(umem_dmabuf)) {
+ err = PTR_ERR(umem_dmabuf);
+ ibdev_dbg(&iwdev->ibdev, "Failed to get dmabuf umem[%d]\n", err);
+ return ERR_PTR(err);
+ }
+
+ iwmr = irdma_alloc_iwmr(&umem_dmabuf->umem, pd, virt, IRDMA_MEMREG_TYPE_MEM);
+ if (IS_ERR(iwmr)) {
+ err = PTR_ERR(iwmr);
+ goto err_release;
+ }
+
+ err = irdma_reg_user_mr_type_mem(iwmr, access);
+ if (err)
+ goto err_iwmr;
+
+ return &iwmr->ibmr;
+
+err_iwmr:
+ irdma_free_iwmr(iwmr);
+
+err_release:
+ ib_umem_release(&umem_dmabuf->umem);
return ERR_PTR(err);
}
@@ -4418,6 +4524,7 @@ static const struct ib_device_ops irdma_dev_ops = {
.query_port = irdma_query_port,
.query_qp = irdma_query_qp,
.reg_user_mr = irdma_reg_user_mr,
+ .reg_user_mr_dmabuf = irdma_reg_user_mr_dmabuf,
.req_notify_cq = irdma_req_notify_cq,
.resize_cq = irdma_resize_cq,
INIT_RDMA_OBJ_SIZE(ib_pd, irdma_pd, ibpd),
diff --git a/drivers/infiniband/hw/mana/main.c b/drivers/infiniband/hw/mana/main.c
index 8b3bc302d6f3..7be4c3adb4e2 100644
--- a/drivers/infiniband/hw/mana/main.c
+++ b/drivers/infiniband/hw/mana/main.c
@@ -249,7 +249,8 @@ static int
mana_ib_gd_first_dma_region(struct mana_ib_dev *dev,
struct gdma_context *gc,
struct gdma_create_dma_region_req *create_req,
- size_t num_pages, mana_handle_t *gdma_region)
+ size_t num_pages, mana_handle_t *gdma_region,
+ u32 expected_status)
{
struct gdma_create_dma_region_resp create_resp = {};
unsigned int create_req_msg_size;
@@ -261,7 +262,7 @@ mana_ib_gd_first_dma_region(struct mana_ib_dev *dev,
err = mana_gd_send_request(gc, create_req_msg_size, create_req,
sizeof(create_resp), &create_resp);
- if (err || create_resp.hdr.status) {
+ if (err || create_resp.hdr.status != expected_status) {
ibdev_dbg(&dev->ib_dev,
"Failed to create DMA region: %d, 0x%x\n",
err, create_resp.hdr.status);
@@ -372,14 +373,21 @@ int mana_ib_gd_create_dma_region(struct mana_ib_dev *dev, struct ib_umem *umem,
page_addr_list = create_req->page_addr_list;
rdma_umem_for_each_dma_block(umem, &biter, page_sz) {
+ u32 expected_status = 0;
+
page_addr_list[tail++] = rdma_block_iter_dma_address(&biter);
if (tail < num_pages_to_handle)
continue;
+ if (num_pages_processed + num_pages_to_handle <
+ num_pages_total)
+ expected_status = GDMA_STATUS_MORE_ENTRIES;
+
if (!num_pages_processed) {
/* First create message */
err = mana_ib_gd_first_dma_region(dev, gc, create_req,
- tail, gdma_region);
+ tail, gdma_region,
+ expected_status);
if (err)
goto out;
@@ -392,14 +400,8 @@ int mana_ib_gd_create_dma_region(struct mana_ib_dev *dev, struct ib_umem *umem,
page_addr_list = add_req->page_addr_list;
} else {
/* Subsequent create messages */
- u32 expected_s = 0;
-
- if (num_pages_processed + num_pages_to_handle <
- num_pages_total)
- expected_s = GDMA_STATUS_MORE_ENTRIES;
-
err = mana_ib_gd_add_dma_region(dev, gc, add_req, tail,
- expected_s);
+ expected_status);
if (err)
break;
}
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
index dceebcd885bb..b18e9f2adc82 100644
--- a/drivers/infiniband/hw/mlx4/main.c
+++ b/drivers/infiniband/hw/mlx4/main.c
@@ -3303,6 +3303,10 @@ static int __init mlx4_ib_init(void)
if (!wq)
return -ENOMEM;
+ err = mlx4_ib_qp_event_init();
+ if (err)
+ goto clean_qp_event;
+
err = mlx4_ib_cm_init();
if (err)
goto clean_wq;
@@ -3324,6 +3328,9 @@ clean_cm:
mlx4_ib_cm_destroy();
clean_wq:
+ mlx4_ib_qp_event_cleanup();
+
+clean_qp_event:
destroy_workqueue(wq);
return err;
}
@@ -3333,6 +3340,7 @@ static void __exit mlx4_ib_cleanup(void)
mlx4_unregister_interface(&mlx4_ib_interface);
mlx4_ib_mcg_destroy();
mlx4_ib_cm_destroy();
+ mlx4_ib_qp_event_cleanup();
destroy_workqueue(wq);
}
diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h
index 6a3b0f121045..17fee1e73a45 100644
--- a/drivers/infiniband/hw/mlx4/mlx4_ib.h
+++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h
@@ -940,4 +940,7 @@ int mlx4_ib_umem_calc_optimal_mtt_size(struct ib_umem *umem, u64 start_va,
int mlx4_ib_cm_init(void);
void mlx4_ib_cm_destroy(void);
+int mlx4_ib_qp_event_init(void);
+void mlx4_ib_qp_event_cleanup(void);
+
#endif /* MLX4_IB_H */
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c
index b17d6ebc5b70..884825b2e5f7 100644
--- a/drivers/infiniband/hw/mlx4/qp.c
+++ b/drivers/infiniband/hw/mlx4/qp.c
@@ -102,6 +102,14 @@ enum mlx4_ib_source_type {
MLX4_IB_RWQ_SRC = 1,
};
+struct mlx4_ib_qp_event_work {
+ struct work_struct work;
+ struct mlx4_qp *qp;
+ enum mlx4_event type;
+};
+
+static struct workqueue_struct *mlx4_ib_qp_event_wq;
+
static int is_tunnel_qp(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp)
{
if (!mlx4_is_master(dev->dev))
@@ -200,50 +208,77 @@ static void stamp_send_wqe(struct mlx4_ib_qp *qp, int n)
}
}
+static void mlx4_ib_handle_qp_event(struct work_struct *_work)
+{
+ struct mlx4_ib_qp_event_work *qpe_work =
+ container_of(_work, struct mlx4_ib_qp_event_work, work);
+ struct ib_qp *ibqp = &to_mibqp(qpe_work->qp)->ibqp;
+ struct ib_event event = {};
+
+ event.device = ibqp->device;
+ event.element.qp = ibqp;
+
+ switch (qpe_work->type) {
+ case MLX4_EVENT_TYPE_PATH_MIG:
+ event.event = IB_EVENT_PATH_MIG;
+ break;
+ case MLX4_EVENT_TYPE_COMM_EST:
+ event.event = IB_EVENT_COMM_EST;
+ break;
+ case MLX4_EVENT_TYPE_SQ_DRAINED:
+ event.event = IB_EVENT_SQ_DRAINED;
+ break;
+ case MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE:
+ event.event = IB_EVENT_QP_LAST_WQE_REACHED;
+ break;
+ case MLX4_EVENT_TYPE_WQ_CATAS_ERROR:
+ event.event = IB_EVENT_QP_FATAL;
+ break;
+ case MLX4_EVENT_TYPE_PATH_MIG_FAILED:
+ event.event = IB_EVENT_PATH_MIG_ERR;
+ break;
+ case MLX4_EVENT_TYPE_WQ_INVAL_REQ_ERROR:
+ event.event = IB_EVENT_QP_REQ_ERR;
+ break;
+ case MLX4_EVENT_TYPE_WQ_ACCESS_ERROR:
+ event.event = IB_EVENT_QP_ACCESS_ERR;
+ break;
+ default:
+ pr_warn("Unexpected event type %d on QP %06x\n",
+ qpe_work->type, qpe_work->qp->qpn);
+ goto out;
+ }
+
+ ibqp->event_handler(&event, ibqp->qp_context);
+
+out:
+ mlx4_put_qp(qpe_work->qp);
+ kfree(qpe_work);
+}
+
static void mlx4_ib_qp_event(struct mlx4_qp *qp, enum mlx4_event type)
{
- struct ib_event event;
struct ib_qp *ibqp = &to_mibqp(qp)->ibqp;
+ struct mlx4_ib_qp_event_work *qpe_work;
if (type == MLX4_EVENT_TYPE_PATH_MIG)
to_mibqp(qp)->port = to_mibqp(qp)->alt_port;
- if (ibqp->event_handler) {
- event.device = ibqp->device;
- event.element.qp = ibqp;
- switch (type) {
- case MLX4_EVENT_TYPE_PATH_MIG:
- event.event = IB_EVENT_PATH_MIG;
- break;
- case MLX4_EVENT_TYPE_COMM_EST:
- event.event = IB_EVENT_COMM_EST;
- break;
- case MLX4_EVENT_TYPE_SQ_DRAINED:
- event.event = IB_EVENT_SQ_DRAINED;
- break;
- case MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE:
- event.event = IB_EVENT_QP_LAST_WQE_REACHED;
- break;
- case MLX4_EVENT_TYPE_WQ_CATAS_ERROR:
- event.event = IB_EVENT_QP_FATAL;
- break;
- case MLX4_EVENT_TYPE_PATH_MIG_FAILED:
- event.event = IB_EVENT_PATH_MIG_ERR;
- break;
- case MLX4_EVENT_TYPE_WQ_INVAL_REQ_ERROR:
- event.event = IB_EVENT_QP_REQ_ERR;
- break;
- case MLX4_EVENT_TYPE_WQ_ACCESS_ERROR:
- event.event = IB_EVENT_QP_ACCESS_ERR;
- break;
- default:
- pr_warn("Unexpected event type %d "
- "on QP %06x\n", type, qp->qpn);
- return;
- }
+ if (!ibqp->event_handler)
+ goto out_no_handler;
- ibqp->event_handler(&event, ibqp->qp_context);
- }
+ qpe_work = kzalloc(sizeof(*qpe_work), GFP_ATOMIC);
+ if (!qpe_work)
+ goto out_no_handler;
+
+ qpe_work->qp = qp;
+ qpe_work->type = type;
+ INIT_WORK(&qpe_work->work, mlx4_ib_handle_qp_event);
+ queue_work(mlx4_ib_qp_event_wq, &qpe_work->work);
+ return;
+
+out_no_handler:
+ mlx4_put_qp(qp);
}
static void mlx4_ib_wq_event(struct mlx4_qp *qp, enum mlx4_event type)
@@ -4468,3 +4503,17 @@ void mlx4_ib_drain_rq(struct ib_qp *qp)
handle_drain_completion(cq, &rdrain, dev);
}
+
+int mlx4_ib_qp_event_init(void)
+{
+ mlx4_ib_qp_event_wq = alloc_ordered_workqueue("mlx4_ib_qp_event_wq", 0);
+ if (!mlx4_ib_qp_event_wq)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void mlx4_ib_qp_event_cleanup(void)
+{
+ destroy_workqueue(mlx4_ib_qp_event_wq);
+}
diff --git a/drivers/infiniband/hw/mlx5/cmd.c b/drivers/infiniband/hw/mlx5/cmd.c
index ff3742b0460a..1d0c8d5e745b 100644
--- a/drivers/infiniband/hw/mlx5/cmd.c
+++ b/drivers/infiniband/hw/mlx5/cmd.c
@@ -5,34 +5,41 @@
#include "cmd.h"
-int mlx5_cmd_dump_fill_mkey(struct mlx5_core_dev *dev, u32 *mkey)
+int mlx5r_cmd_query_special_mkeys(struct mlx5_ib_dev *dev)
{
u32 out[MLX5_ST_SZ_DW(query_special_contexts_out)] = {};
u32 in[MLX5_ST_SZ_DW(query_special_contexts_in)] = {};
+ bool is_terminate, is_dump, is_null;
int err;
- MLX5_SET(query_special_contexts_in, in, opcode,
- MLX5_CMD_OP_QUERY_SPECIAL_CONTEXTS);
- err = mlx5_cmd_exec_inout(dev, query_special_contexts, in, out);
- if (!err)
- *mkey = MLX5_GET(query_special_contexts_out, out,
- dump_fill_mkey);
- return err;
-}
+ is_terminate = MLX5_CAP_GEN(dev->mdev, terminate_scatter_list_mkey);
+ is_dump = MLX5_CAP_GEN(dev->mdev, dump_fill_mkey);
+ is_null = MLX5_CAP_GEN(dev->mdev, null_mkey);
-int mlx5_cmd_null_mkey(struct mlx5_core_dev *dev, u32 *null_mkey)
-{
- u32 out[MLX5_ST_SZ_DW(query_special_contexts_out)] = {};
- u32 in[MLX5_ST_SZ_DW(query_special_contexts_in)] = {};
- int err;
+ dev->mkeys.terminate_scatter_list_mkey = MLX5_TERMINATE_SCATTER_LIST_LKEY;
+ if (!is_terminate && !is_dump && !is_null)
+ return 0;
MLX5_SET(query_special_contexts_in, in, opcode,
MLX5_CMD_OP_QUERY_SPECIAL_CONTEXTS);
- err = mlx5_cmd_exec_inout(dev, query_special_contexts, in, out);
- if (!err)
- *null_mkey = MLX5_GET(query_special_contexts_out, out,
- null_mkey);
- return err;
+ err = mlx5_cmd_exec_inout(dev->mdev, query_special_contexts, in, out);
+ if (err)
+ return err;
+
+ if (is_dump)
+ dev->mkeys.dump_fill_mkey = MLX5_GET(query_special_contexts_out,
+ out, dump_fill_mkey);
+
+ if (is_null)
+ dev->mkeys.null_mkey = cpu_to_be32(
+ MLX5_GET(query_special_contexts_out, out, null_mkey));
+
+ if (is_terminate)
+ dev->mkeys.terminate_scatter_list_mkey =
+ cpu_to_be32(MLX5_GET(query_special_contexts_out, out,
+ terminate_scatter_list_mkey));
+
+ return 0;
}
int mlx5_cmd_query_cong_params(struct mlx5_core_dev *dev, int cong_point,
diff --git a/drivers/infiniband/hw/mlx5/cmd.h b/drivers/infiniband/hw/mlx5/cmd.h
index ee46638db5de..93a971a40d11 100644
--- a/drivers/infiniband/hw/mlx5/cmd.h
+++ b/drivers/infiniband/hw/mlx5/cmd.h
@@ -37,8 +37,7 @@
#include <linux/kernel.h>
#include <linux/mlx5/driver.h>
-int mlx5_cmd_dump_fill_mkey(struct mlx5_core_dev *dev, u32 *mkey);
-int mlx5_cmd_null_mkey(struct mlx5_core_dev *dev, u32 *null_mkey);
+int mlx5r_cmd_query_special_mkeys(struct mlx5_ib_dev *dev);
int mlx5_cmd_query_cong_params(struct mlx5_core_dev *dev, int cong_point,
void *out);
int mlx5_cmd_dealloc_pd(struct mlx5_core_dev *dev, u32 pdn, u16 uid);
diff --git a/drivers/infiniband/hw/mlx5/cong.c b/drivers/infiniband/hw/mlx5/cong.c
index 290ea8ac3838..f87531318feb 100644
--- a/drivers/infiniband/hw/mlx5/cong.c
+++ b/drivers/infiniband/hw/mlx5/cong.c
@@ -38,6 +38,7 @@
enum mlx5_ib_cong_node_type {
MLX5_IB_RROCE_ECN_RP = 1,
MLX5_IB_RROCE_ECN_NP = 2,
+ MLX5_IB_RROCE_GENERAL = 3,
};
static const char * const mlx5_ib_dbg_cc_name[] = {
@@ -61,6 +62,8 @@ static const char * const mlx5_ib_dbg_cc_name[] = {
"np_cnp_dscp",
"np_cnp_prio_mode",
"np_cnp_prio",
+ "rtt_resp_dscp_valid",
+ "rtt_resp_dscp",
};
#define MLX5_IB_RP_CLAMP_TGT_RATE_ATTR BIT(1)
@@ -84,14 +87,18 @@ static const char * const mlx5_ib_dbg_cc_name[] = {
#define MLX5_IB_NP_CNP_DSCP_ATTR BIT(3)
#define MLX5_IB_NP_CNP_PRIO_MODE_ATTR BIT(4)
+#define MLX5_IB_GENERAL_RTT_RESP_DSCP_ATTR BIT(0)
+
static enum mlx5_ib_cong_node_type
mlx5_ib_param_to_node(enum mlx5_ib_dbg_cc_types param_offset)
{
- if (param_offset >= MLX5_IB_DBG_CC_RP_CLAMP_TGT_RATE &&
- param_offset <= MLX5_IB_DBG_CC_RP_GD)
+ if (param_offset <= MLX5_IB_DBG_CC_RP_GD)
return MLX5_IB_RROCE_ECN_RP;
- else
+
+ if (param_offset <= MLX5_IB_DBG_CC_NP_CNP_PRIO)
return MLX5_IB_RROCE_ECN_NP;
+
+ return MLX5_IB_RROCE_GENERAL;
}
static u32 mlx5_get_cc_param_val(void *field, int offset)
@@ -157,6 +164,12 @@ static u32 mlx5_get_cc_param_val(void *field, int offset)
case MLX5_IB_DBG_CC_NP_CNP_PRIO:
return MLX5_GET(cong_control_r_roce_ecn_np, field,
cnp_802p_prio);
+ case MLX5_IB_DBG_CC_GENERAL_RTT_RESP_DSCP_VALID:
+ return MLX5_GET(cong_control_r_roce_general, field,
+ rtt_resp_dscp_valid);
+ case MLX5_IB_DBG_CC_GENERAL_RTT_RESP_DSCP:
+ return MLX5_GET(cong_control_r_roce_general, field,
+ rtt_resp_dscp);
default:
return 0;
}
@@ -264,6 +277,15 @@ static void mlx5_ib_set_cc_param_mask_val(void *field, int offset,
MLX5_SET(cong_control_r_roce_ecn_np, field, cnp_prio_mode, 0);
MLX5_SET(cong_control_r_roce_ecn_np, field, cnp_802p_prio, var);
break;
+ case MLX5_IB_DBG_CC_GENERAL_RTT_RESP_DSCP_VALID:
+ *attr_mask |= MLX5_IB_GENERAL_RTT_RESP_DSCP_ATTR;
+ MLX5_SET(cong_control_r_roce_general, field, rtt_resp_dscp_valid, var);
+ break;
+ case MLX5_IB_DBG_CC_GENERAL_RTT_RESP_DSCP:
+ *attr_mask |= MLX5_IB_GENERAL_RTT_RESP_DSCP_ATTR;
+ MLX5_SET(cong_control_r_roce_general, field, rtt_resp_dscp_valid, 1);
+ MLX5_SET(cong_control_r_roce_general, field, rtt_resp_dscp, var);
+ break;
}
}
diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c
index dc32e4518a28..5b988db66b8f 100644
--- a/drivers/infiniband/hw/mlx5/main.c
+++ b/drivers/infiniband/hw/mlx5/main.c
@@ -1756,13 +1756,9 @@ static int set_ucontext_resp(struct ib_ucontext *uctx,
struct mlx5_ib_dev *dev = to_mdev(ibdev);
struct mlx5_ib_ucontext *context = to_mucontext(uctx);
struct mlx5_bfreg_info *bfregi = &context->bfregi;
- int err;
if (MLX5_CAP_GEN(dev->mdev, dump_fill_mkey)) {
- err = mlx5_cmd_dump_fill_mkey(dev->mdev,
- &resp->dump_fill_mkey);
- if (err)
- return err;
+ resp->dump_fill_mkey = dev->mkeys.dump_fill_mkey;
resp->comp_mask |=
MLX5_IB_ALLOC_UCONTEXT_RESP_MASK_DUMP_FILL_MKEY;
}
@@ -2087,7 +2083,7 @@ static int mlx5_ib_mmap_clock_info_page(struct mlx5_ib_dev *dev,
if (vma->vm_flags & (VM_WRITE | VM_EXEC))
return -EPERM;
- vma->vm_flags &= ~VM_MAYWRITE;
+ vm_flags_clear(vma, VM_MAYWRITE);
if (!dev->mdev->clock_info)
return -EOPNOTSUPP;
@@ -2311,7 +2307,7 @@ static int mlx5_ib_mmap(struct ib_ucontext *ibcontext, struct vm_area_struct *vm
if (vma->vm_flags & VM_WRITE)
return -EPERM;
- vma->vm_flags &= ~VM_MAYWRITE;
+ vm_flags_clear(vma, VM_MAYWRITE);
/* Don't expose to user-space information it shouldn't have */
if (PAGE_SIZE > 4096)
@@ -3666,6 +3662,10 @@ static int mlx5_ib_stage_init_init(struct mlx5_ib_dev *dev)
dev->port[i].roce.last_port_state = IB_PORT_DOWN;
}
+ err = mlx5r_cmd_query_special_mkeys(dev);
+ if (err)
+ return err;
+
err = mlx5_ib_init_multiport_master(dev);
if (err)
return err;
@@ -4030,12 +4030,7 @@ static int mlx5_ib_stage_ib_reg_init(struct mlx5_ib_dev *dev)
static void mlx5_ib_stage_pre_ib_reg_umr_cleanup(struct mlx5_ib_dev *dev)
{
- int err;
-
- err = mlx5_mkey_cache_cleanup(dev);
- if (err)
- mlx5_ib_warn(dev, "mr cache cleanup failed\n");
-
+ mlx5_mkey_cache_cleanup(dev);
mlx5r_umr_resource_cleanup(dev);
}
@@ -4433,6 +4428,10 @@ static int __init mlx5_ib_init(void)
return -ENOMEM;
}
+ ret = mlx5_ib_qp_event_init();
+ if (ret)
+ goto qp_event_err;
+
mlx5_ib_odp_init();
ret = mlx5r_rep_init();
if (ret)
@@ -4450,6 +4449,8 @@ drv_err:
mp_err:
mlx5r_rep_cleanup();
rep_err:
+ mlx5_ib_qp_event_cleanup();
+qp_event_err:
destroy_workqueue(mlx5_ib_event_wq);
free_page((unsigned long)xlt_emergency_page);
return ret;
@@ -4461,6 +4462,7 @@ static void __exit mlx5_ib_cleanup(void)
auxiliary_driver_unregister(&mlx5r_mp_driver);
mlx5r_rep_cleanup();
+ mlx5_ib_qp_event_cleanup();
destroy_workqueue(mlx5_ib_event_wq);
free_page((unsigned long)xlt_emergency_page);
}
diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h
index 7394e7f36ba7..efa4dc6e7dee 100644
--- a/drivers/infiniband/hw/mlx5/mlx5_ib.h
+++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h
@@ -617,12 +617,21 @@ enum mlx5_mkey_type {
MLX5_MKEY_INDIRECT_DEVX,
};
+struct mlx5r_cache_rb_key {
+ u8 ats:1;
+ unsigned int access_mode;
+ unsigned int access_flags;
+ unsigned int ndescs;
+};
+
struct mlx5_ib_mkey {
u32 key;
enum mlx5_mkey_type type;
unsigned int ndescs;
struct wait_queue_head wait;
refcount_t usecount;
+ /* User Mkey must hold either a rb_key or a cache_ent. */
+ struct mlx5r_cache_rb_key rb_key;
struct mlx5_cache_ent *cache_ent;
};
@@ -737,11 +746,11 @@ struct mlx5_cache_ent {
unsigned long reserved;
char name[4];
- u32 order;
- u32 access_mode;
- u32 page;
- unsigned int ndescs;
+ struct rb_node node;
+ struct mlx5r_cache_rb_key rb_key;
+
+ u8 is_tmp:1;
u8 disabled:1;
u8 fill_to_high_water:1;
@@ -771,9 +780,11 @@ struct mlx5r_async_create_mkey {
struct mlx5_mkey_cache {
struct workqueue_struct *wq;
- struct mlx5_cache_ent ent[MAX_MKEY_CACHE_ENTRIES];
- struct dentry *root;
+ struct rb_root rb_root;
+ struct mutex rb_lock;
+ struct dentry *fs_root;
unsigned long last_add;
+ struct delayed_work remove_ent_dwork;
};
struct mlx5_ib_port_resources {
@@ -877,6 +888,8 @@ enum mlx5_ib_dbg_cc_types {
MLX5_IB_DBG_CC_NP_CNP_DSCP,
MLX5_IB_DBG_CC_NP_CNP_PRIO_MODE,
MLX5_IB_DBG_CC_NP_CNP_PRIO,
+ MLX5_IB_DBG_CC_GENERAL_RTT_RESP_DSCP_VALID,
+ MLX5_IB_DBG_CC_GENERAL_RTT_RESP_DSCP,
MLX5_IB_DBG_CC_MAX,
};
@@ -1054,6 +1067,13 @@ struct mlx5_port_caps {
u8 ext_port_cap;
};
+
+struct mlx5_special_mkeys {
+ u32 dump_fill_mkey;
+ __be32 null_mkey;
+ __be32 terminate_scatter_list_mkey;
+};
+
struct mlx5_ib_dev {
struct ib_device ib_dev;
struct mlx5_core_dev *mdev;
@@ -1084,7 +1104,6 @@ struct mlx5_ib_dev {
struct xarray odp_mkeys;
- u32 null_mkey;
struct mlx5_ib_flow_db *flow_db;
/* protect resources needed as part of reset flow */
spinlock_t reset_flow_resource_lock;
@@ -1113,6 +1132,7 @@ struct mlx5_ib_dev {
struct mlx5_port_caps port_caps[MLX5_MAX_PORTS];
u16 pkey_table_len;
u8 lag_ports;
+ struct mlx5_special_mkeys mkeys;
};
static inline struct mlx5_ib_cq *to_mibcq(struct mlx5_core_cq *mcq)
@@ -1319,11 +1339,15 @@ void mlx5_ib_populate_pas(struct ib_umem *umem, size_t page_size, __be64 *pas,
void mlx5_ib_copy_pas(u64 *old, u64 *new, int step, int num);
int mlx5_ib_get_cqe_size(struct ib_cq *ibcq);
int mlx5_mkey_cache_init(struct mlx5_ib_dev *dev);
-int mlx5_mkey_cache_cleanup(struct mlx5_ib_dev *dev);
+void mlx5_mkey_cache_cleanup(struct mlx5_ib_dev *dev);
+struct mlx5_cache_ent *
+mlx5r_cache_create_ent_locked(struct mlx5_ib_dev *dev,
+ struct mlx5r_cache_rb_key rb_key,
+ bool persistent_entry);
struct mlx5_ib_mr *mlx5_mr_cache_alloc(struct mlx5_ib_dev *dev,
- struct mlx5_cache_ent *ent,
- int access_flags);
+ int access_flags, int access_mode,
+ int ndescs);
int mlx5_ib_check_mr_status(struct ib_mr *ibmr, u32 check_mask,
struct ib_mr_status *mr_status);
@@ -1347,7 +1371,7 @@ int mlx5r_odp_create_eq(struct mlx5_ib_dev *dev, struct mlx5_ib_pf_eq *eq);
void mlx5_ib_odp_cleanup_one(struct mlx5_ib_dev *ibdev);
int __init mlx5_ib_odp_init(void);
void mlx5_ib_odp_cleanup(void);
-void mlx5_odp_init_mkey_cache_entry(struct mlx5_cache_ent *ent);
+int mlx5_odp_init_mkey_cache(struct mlx5_ib_dev *dev);
void mlx5_odp_populate_xlt(void *xlt, size_t idx, size_t nentries,
struct mlx5_ib_mr *mr, int flags);
@@ -1366,7 +1390,10 @@ static inline int mlx5r_odp_create_eq(struct mlx5_ib_dev *dev,
static inline void mlx5_ib_odp_cleanup_one(struct mlx5_ib_dev *ibdev) {}
static inline int mlx5_ib_odp_init(void) { return 0; }
static inline void mlx5_ib_odp_cleanup(void) {}
-static inline void mlx5_odp_init_mkey_cache_entry(struct mlx5_cache_ent *ent) {}
+static inline int mlx5_odp_init_mkey_cache(struct mlx5_ib_dev *dev)
+{
+ return 0;
+}
static inline void mlx5_odp_populate_xlt(void *xlt, size_t idx, size_t nentries,
struct mlx5_ib_mr *mr, int flags) {}
diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c
index 053fe946e45a..67356f515261 100644
--- a/drivers/infiniband/hw/mlx5/mr.c
+++ b/drivers/infiniband/hw/mlx5/mr.c
@@ -140,19 +140,16 @@ static void create_mkey_warn(struct mlx5_ib_dev *dev, int status, void *out)
mlx5_cmd_out_err(dev->mdev, MLX5_CMD_OP_CREATE_MKEY, 0, out);
}
-
-static int push_mkey(struct mlx5_cache_ent *ent, bool limit_pendings,
- void *to_store)
+static int push_mkey_locked(struct mlx5_cache_ent *ent, bool limit_pendings,
+ void *to_store)
{
XA_STATE(xas, &ent->mkeys, 0);
void *curr;
- xa_lock_irq(&ent->mkeys);
if (limit_pendings &&
- (ent->reserved - ent->stored) > MAX_PENDING_REG_MR) {
- xa_unlock_irq(&ent->mkeys);
+ (ent->reserved - ent->stored) > MAX_PENDING_REG_MR)
return -EAGAIN;
- }
+
while (1) {
/*
* This is cmpxchg (NULL, XA_ZERO_ENTRY) however this version
@@ -191,6 +188,7 @@ static int push_mkey(struct mlx5_cache_ent *ent, bool limit_pendings,
break;
xa_lock_irq(&ent->mkeys);
}
+ xa_lock_irq(&ent->mkeys);
if (xas_error(&xas))
return xas_error(&xas);
if (WARN_ON(curr))
@@ -198,6 +196,17 @@ static int push_mkey(struct mlx5_cache_ent *ent, bool limit_pendings,
return 0;
}
+static int push_mkey(struct mlx5_cache_ent *ent, bool limit_pendings,
+ void *to_store)
+{
+ int ret;
+
+ xa_lock_irq(&ent->mkeys);
+ ret = push_mkey_locked(ent, limit_pendings, to_store);
+ xa_unlock_irq(&ent->mkeys);
+ return ret;
+}
+
static void undo_push_reserve_mkey(struct mlx5_cache_ent *ent)
{
void *old;
@@ -292,12 +301,14 @@ static void set_cache_mkc(struct mlx5_cache_ent *ent, void *mkc)
set_mkc_access_pd_addr_fields(mkc, 0, 0, ent->dev->umrc.pd);
MLX5_SET(mkc, mkc, free, 1);
MLX5_SET(mkc, mkc, umr_en, 1);
- MLX5_SET(mkc, mkc, access_mode_1_0, ent->access_mode & 0x3);
- MLX5_SET(mkc, mkc, access_mode_4_2, (ent->access_mode >> 2) & 0x7);
+ MLX5_SET(mkc, mkc, access_mode_1_0, ent->rb_key.access_mode & 0x3);
+ MLX5_SET(mkc, mkc, access_mode_4_2,
+ (ent->rb_key.access_mode >> 2) & 0x7);
MLX5_SET(mkc, mkc, translations_octword_size,
- get_mkc_octo_size(ent->access_mode, ent->ndescs));
- MLX5_SET(mkc, mkc, log_page_size, ent->page);
+ get_mkc_octo_size(ent->rb_key.access_mode,
+ ent->rb_key.ndescs));
+ MLX5_SET(mkc, mkc, log_page_size, PAGE_SHIFT);
}
/* Asynchronously schedule new MRs to be populated in the cache. */
@@ -515,18 +526,22 @@ static const struct file_operations limit_fops = {
static bool someone_adding(struct mlx5_mkey_cache *cache)
{
- unsigned int i;
-
- for (i = 0; i < MAX_MKEY_CACHE_ENTRIES; i++) {
- struct mlx5_cache_ent *ent = &cache->ent[i];
- bool ret;
+ struct mlx5_cache_ent *ent;
+ struct rb_node *node;
+ bool ret;
+ mutex_lock(&cache->rb_lock);
+ for (node = rb_first(&cache->rb_root); node; node = rb_next(node)) {
+ ent = rb_entry(node, struct mlx5_cache_ent, node);
xa_lock_irq(&ent->mkeys);
ret = ent->stored < ent->limit;
xa_unlock_irq(&ent->mkeys);
- if (ret)
+ if (ret) {
+ mutex_unlock(&cache->rb_lock);
return true;
+ }
}
+ mutex_unlock(&cache->rb_lock);
return false;
}
@@ -539,7 +554,7 @@ static void queue_adjust_cache_locked(struct mlx5_cache_ent *ent)
{
lockdep_assert_held(&ent->mkeys.xa_lock);
- if (ent->disabled || READ_ONCE(ent->dev->fill_delay))
+ if (ent->disabled || READ_ONCE(ent->dev->fill_delay) || ent->is_tmp)
return;
if (ent->stored < ent->limit) {
ent->fill_to_high_water = true;
@@ -590,8 +605,8 @@ static void __cache_work_func(struct mlx5_cache_ent *ent)
if (err != -EAGAIN) {
mlx5_ib_warn(
dev,
- "command failed order %d, err %d\n",
- ent->order, err);
+ "add keys command failed, err %d\n",
+ err);
queue_delayed_work(cache->wq, &ent->dwork,
msecs_to_jiffies(1000));
}
@@ -637,16 +652,99 @@ static void delayed_cache_work_func(struct work_struct *work)
__cache_work_func(ent);
}
-struct mlx5_ib_mr *mlx5_mr_cache_alloc(struct mlx5_ib_dev *dev,
- struct mlx5_cache_ent *ent,
- int access_flags)
+static int cache_ent_key_cmp(struct mlx5r_cache_rb_key key1,
+ struct mlx5r_cache_rb_key key2)
+{
+ int res;
+
+ res = key1.ats - key2.ats;
+ if (res)
+ return res;
+
+ res = key1.access_mode - key2.access_mode;
+ if (res)
+ return res;
+
+ res = key1.access_flags - key2.access_flags;
+ if (res)
+ return res;
+
+ /*
+ * keep ndescs the last in the compare table since the find function
+ * searches for an exact match on all properties and only closest
+ * match in size.
+ */
+ return key1.ndescs - key2.ndescs;
+}
+
+static int mlx5_cache_ent_insert(struct mlx5_mkey_cache *cache,
+ struct mlx5_cache_ent *ent)
+{
+ struct rb_node **new = &cache->rb_root.rb_node, *parent = NULL;
+ struct mlx5_cache_ent *cur;
+ int cmp;
+
+ /* Figure out where to put new node */
+ while (*new) {
+ cur = rb_entry(*new, struct mlx5_cache_ent, node);
+ parent = *new;
+ cmp = cache_ent_key_cmp(cur->rb_key, ent->rb_key);
+ if (cmp > 0)
+ new = &((*new)->rb_left);
+ if (cmp < 0)
+ new = &((*new)->rb_right);
+ if (cmp == 0) {
+ mutex_unlock(&cache->rb_lock);
+ return -EEXIST;
+ }
+ }
+
+ /* Add new node and rebalance tree. */
+ rb_link_node(&ent->node, parent, new);
+ rb_insert_color(&ent->node, &cache->rb_root);
+
+ return 0;
+}
+
+static struct mlx5_cache_ent *
+mkey_cache_ent_from_rb_key(struct mlx5_ib_dev *dev,
+ struct mlx5r_cache_rb_key rb_key)
+{
+ struct rb_node *node = dev->cache.rb_root.rb_node;
+ struct mlx5_cache_ent *cur, *smallest = NULL;
+ int cmp;
+
+ /*
+ * Find the smallest ent with order >= requested_order.
+ */
+ while (node) {
+ cur = rb_entry(node, struct mlx5_cache_ent, node);
+ cmp = cache_ent_key_cmp(cur->rb_key, rb_key);
+ if (cmp > 0) {
+ smallest = cur;
+ node = node->rb_left;
+ }
+ if (cmp < 0)
+ node = node->rb_right;
+ if (cmp == 0)
+ return cur;
+ }
+
+ return (smallest &&
+ smallest->rb_key.access_mode == rb_key.access_mode &&
+ smallest->rb_key.access_flags == rb_key.access_flags &&
+ smallest->rb_key.ats == rb_key.ats) ?
+ smallest :
+ NULL;
+}
+
+static struct mlx5_ib_mr *_mlx5_mr_cache_alloc(struct mlx5_ib_dev *dev,
+ struct mlx5_cache_ent *ent,
+ int access_flags)
{
struct mlx5_ib_mr *mr;
int err;
- if (!mlx5r_umr_can_reconfig(dev, 0, access_flags))
- return ERR_PTR(-EOPNOTSUPP);
-
mr = kzalloc(sizeof(*mr), GFP_KERNEL);
if (!mr)
return ERR_PTR(-ENOMEM);
@@ -677,10 +775,48 @@ struct mlx5_ib_mr *mlx5_mr_cache_alloc(struct mlx5_ib_dev *dev,
return mr;
}
-static void clean_keys(struct mlx5_ib_dev *dev, int c)
+static int get_unchangeable_access_flags(struct mlx5_ib_dev *dev,
+ int access_flags)
+{
+ int ret = 0;
+
+ if ((access_flags & IB_ACCESS_REMOTE_ATOMIC) &&
+ MLX5_CAP_GEN(dev->mdev, atomic) &&
+ MLX5_CAP_GEN(dev->mdev, umr_modify_atomic_disabled))
+ ret |= IB_ACCESS_REMOTE_ATOMIC;
+
+ if ((access_flags & IB_ACCESS_RELAXED_ORDERING) &&
+ MLX5_CAP_GEN(dev->mdev, relaxed_ordering_write) &&
+ !MLX5_CAP_GEN(dev->mdev, relaxed_ordering_write_umr))
+ ret |= IB_ACCESS_RELAXED_ORDERING;
+
+ if ((access_flags & IB_ACCESS_RELAXED_ORDERING) &&
+ MLX5_CAP_GEN(dev->mdev, relaxed_ordering_read) &&
+ !MLX5_CAP_GEN(dev->mdev, relaxed_ordering_read_umr))
+ ret |= IB_ACCESS_RELAXED_ORDERING;
+
+ return ret;
+}
+
+struct mlx5_ib_mr *mlx5_mr_cache_alloc(struct mlx5_ib_dev *dev,
+ int access_flags, int access_mode,
+ int ndescs)
+{
+ struct mlx5r_cache_rb_key rb_key = {
+ .ndescs = ndescs,
+ .access_mode = access_mode,
+ .access_flags = get_unchangeable_access_flags(dev, access_flags)
+ };
+ struct mlx5_cache_ent *ent = mkey_cache_ent_from_rb_key(dev, rb_key);
+
+ if (!ent)
+ return ERR_PTR(-EOPNOTSUPP);
+
+ return _mlx5_mr_cache_alloc(dev, ent, access_flags);
+}
+
+static void clean_keys(struct mlx5_ib_dev *dev, struct mlx5_cache_ent *ent)
{
- struct mlx5_mkey_cache *cache = &dev->cache;
- struct mlx5_cache_ent *ent = &cache->ent[c];
u32 mkey;
cancel_delayed_work(&ent->dwork);
@@ -699,31 +835,39 @@ static void mlx5_mkey_cache_debugfs_cleanup(struct mlx5_ib_dev *dev)
if (!mlx5_debugfs_root || dev->is_rep)
return;
- debugfs_remove_recursive(dev->cache.root);
- dev->cache.root = NULL;
+ debugfs_remove_recursive(dev->cache.fs_root);
+ dev->cache.fs_root = NULL;
}
-static void mlx5_mkey_cache_debugfs_init(struct mlx5_ib_dev *dev)
+static void mlx5_mkey_cache_debugfs_add_ent(struct mlx5_ib_dev *dev,
+ struct mlx5_cache_ent *ent)
{
- struct mlx5_mkey_cache *cache = &dev->cache;
- struct mlx5_cache_ent *ent;
+ int order = order_base_2(ent->rb_key.ndescs);
struct dentry *dir;
- int i;
if (!mlx5_debugfs_root || dev->is_rep)
return;
- cache->root = debugfs_create_dir("mr_cache", mlx5_debugfs_get_dev_root(dev->mdev));
+ if (ent->rb_key.access_mode == MLX5_MKC_ACCESS_MODE_KSM)
+ order = MLX5_IMR_KSM_CACHE_ENTRY + 2;
- for (i = 0; i < MAX_MKEY_CACHE_ENTRIES; i++) {
- ent = &cache->ent[i];
- sprintf(ent->name, "%d", ent->order);
- dir = debugfs_create_dir(ent->name, cache->root);
- debugfs_create_file("size", 0600, dir, ent, &size_fops);
- debugfs_create_file("limit", 0600, dir, ent, &limit_fops);
- debugfs_create_ulong("cur", 0400, dir, &ent->stored);
- debugfs_create_u32("miss", 0600, dir, &ent->miss);
- }
+ sprintf(ent->name, "%d", order);
+ dir = debugfs_create_dir(ent->name, dev->cache.fs_root);
+ debugfs_create_file("size", 0600, dir, ent, &size_fops);
+ debugfs_create_file("limit", 0600, dir, ent, &limit_fops);
+ debugfs_create_ulong("cur", 0400, dir, &ent->stored);
+ debugfs_create_u32("miss", 0600, dir, &ent->miss);
+}
+
+static void mlx5_mkey_cache_debugfs_init(struct mlx5_ib_dev *dev)
+{
+ struct dentry *dbg_root = mlx5_debugfs_get_dev_root(dev->mdev);
+ struct mlx5_mkey_cache *cache = &dev->cache;
+
+ if (!mlx5_debugfs_root || dev->is_rep)
+ return;
+
+ cache->fs_root = debugfs_create_dir("mr_cache", dbg_root);
}
static void delay_time_func(struct timer_list *t)
@@ -733,13 +877,100 @@ static void delay_time_func(struct timer_list *t)
WRITE_ONCE(dev->fill_delay, 0);
}
+struct mlx5_cache_ent *
+mlx5r_cache_create_ent_locked(struct mlx5_ib_dev *dev,
+ struct mlx5r_cache_rb_key rb_key,
+ bool persistent_entry)
+{
+ struct mlx5_cache_ent *ent;
+ int order;
+ int ret;
+
+ ent = kzalloc(sizeof(*ent), GFP_KERNEL);
+ if (!ent)
+ return ERR_PTR(-ENOMEM);
+
+ xa_init_flags(&ent->mkeys, XA_FLAGS_LOCK_IRQ);
+ ent->rb_key = rb_key;
+ ent->dev = dev;
+ ent->is_tmp = !persistent_entry;
+
+ INIT_DELAYED_WORK(&ent->dwork, delayed_cache_work_func);
+
+ ret = mlx5_cache_ent_insert(&dev->cache, ent);
+ if (ret) {
+ kfree(ent);
+ return ERR_PTR(ret);
+ }
+
+ if (persistent_entry) {
+ if (rb_key.access_mode == MLX5_MKC_ACCESS_MODE_KSM)
+ order = MLX5_IMR_KSM_CACHE_ENTRY;
+ else
+ order = order_base_2(rb_key.ndescs) - 2;
+
+ if ((dev->mdev->profile.mask & MLX5_PROF_MASK_MR_CACHE) &&
+ !dev->is_rep && mlx5_core_is_pf(dev->mdev) &&
+ mlx5r_umr_can_load_pas(dev, 0))
+ ent->limit = dev->mdev->profile.mr_cache[order].limit;
+ else
+ ent->limit = 0;
+
+ mlx5_mkey_cache_debugfs_add_ent(dev, ent);
+ } else {
+ mod_delayed_work(ent->dev->cache.wq,
+ &ent->dev->cache.remove_ent_dwork,
+ msecs_to_jiffies(30 * 1000));
+ }
+
+ return ent;
+}
+
+static void remove_ent_work_func(struct work_struct *work)
+{
+ struct mlx5_mkey_cache *cache;
+ struct mlx5_cache_ent *ent;
+ struct rb_node *cur;
+
+ cache = container_of(work, struct mlx5_mkey_cache,
+ remove_ent_dwork.work);
+ mutex_lock(&cache->rb_lock);
+ cur = rb_last(&cache->rb_root);
+ while (cur) {
+ ent = rb_entry(cur, struct mlx5_cache_ent, node);
+ cur = rb_prev(cur);
+ mutex_unlock(&cache->rb_lock);
+
+ xa_lock_irq(&ent->mkeys);
+ if (!ent->is_tmp) {
+ xa_unlock_irq(&ent->mkeys);
+ mutex_lock(&cache->rb_lock);
+ continue;
+ }
+ xa_unlock_irq(&ent->mkeys);
+
+ clean_keys(ent->dev, ent);
+ mutex_lock(&cache->rb_lock);
+ }
+ mutex_unlock(&cache->rb_lock);
+}
+
int mlx5_mkey_cache_init(struct mlx5_ib_dev *dev)
{
struct mlx5_mkey_cache *cache = &dev->cache;
+ struct rb_root *root = &dev->cache.rb_root;
+ struct mlx5r_cache_rb_key rb_key = {
+ .access_mode = MLX5_MKC_ACCESS_MODE_MTT,
+ };
struct mlx5_cache_ent *ent;
+ struct rb_node *node;
+ int ret;
int i;
mutex_init(&dev->slow_path_mutex);
+ mutex_init(&dev->cache.rb_lock);
+ dev->cache.rb_root = RB_ROOT;
+ INIT_DELAYED_WORK(&dev->cache.remove_ent_dwork, remove_ent_work_func);
cache->wq = alloc_ordered_workqueue("mkey_cache", WQ_MEM_RECLAIM);
if (!cache->wq) {
mlx5_ib_warn(dev, "failed to create work queue\n");
@@ -748,52 +979,51 @@ int mlx5_mkey_cache_init(struct mlx5_ib_dev *dev)
mlx5_cmd_init_async_ctx(dev->mdev, &dev->async_ctx);
timer_setup(&dev->delay_timer, delay_time_func, 0);
- for (i = 0; i < MAX_MKEY_CACHE_ENTRIES; i++) {
- ent = &cache->ent[i];
- xa_init_flags(&ent->mkeys, XA_FLAGS_LOCK_IRQ);
- ent->order = i + 2;
- ent->dev = dev;
- ent->limit = 0;
-
- INIT_DELAYED_WORK(&ent->dwork, delayed_cache_work_func);
-
- if (i > MKEY_CACHE_LAST_STD_ENTRY) {
- mlx5_odp_init_mkey_cache_entry(ent);
- continue;
+ mlx5_mkey_cache_debugfs_init(dev);
+ mutex_lock(&cache->rb_lock);
+ for (i = 0; i <= mkey_cache_max_order(dev); i++) {
+ rb_key.ndescs = 1 << (i + 2);
+ ent = mlx5r_cache_create_ent_locked(dev, rb_key, true);
+ if (IS_ERR(ent)) {
+ ret = PTR_ERR(ent);
+ goto err;
}
+ }
- if (ent->order > mkey_cache_max_order(dev))
- continue;
+ ret = mlx5_odp_init_mkey_cache(dev);
+ if (ret)
+ goto err;
- ent->page = PAGE_SHIFT;
- ent->ndescs = 1 << ent->order;
- ent->access_mode = MLX5_MKC_ACCESS_MODE_MTT;
- if ((dev->mdev->profile.mask & MLX5_PROF_MASK_MR_CACHE) &&
- !dev->is_rep && mlx5_core_is_pf(dev->mdev) &&
- mlx5r_umr_can_load_pas(dev, 0))
- ent->limit = dev->mdev->profile.mr_cache[i].limit;
- else
- ent->limit = 0;
+ mutex_unlock(&cache->rb_lock);
+ for (node = rb_first(root); node; node = rb_next(node)) {
+ ent = rb_entry(node, struct mlx5_cache_ent, node);
xa_lock_irq(&ent->mkeys);
queue_adjust_cache_locked(ent);
xa_unlock_irq(&ent->mkeys);
}
- mlx5_mkey_cache_debugfs_init(dev);
-
return 0;
+
+err:
+ mutex_unlock(&cache->rb_lock);
+ mlx5_mkey_cache_debugfs_cleanup(dev);
+ mlx5_ib_warn(dev, "failed to create mkey cache entry\n");
+ return ret;
}
-int mlx5_mkey_cache_cleanup(struct mlx5_ib_dev *dev)
+void mlx5_mkey_cache_cleanup(struct mlx5_ib_dev *dev)
{
- unsigned int i;
+ struct rb_root *root = &dev->cache.rb_root;
+ struct mlx5_cache_ent *ent;
+ struct rb_node *node;
if (!dev->cache.wq)
- return 0;
-
- for (i = 0; i < MAX_MKEY_CACHE_ENTRIES; i++) {
- struct mlx5_cache_ent *ent = &dev->cache.ent[i];
+ return;
+ cancel_delayed_work_sync(&dev->cache.remove_ent_dwork);
+ mutex_lock(&dev->cache.rb_lock);
+ for (node = rb_first(root); node; node = rb_next(node)) {
+ ent = rb_entry(node, struct mlx5_cache_ent, node);
xa_lock_irq(&ent->mkeys);
ent->disabled = true;
xa_unlock_irq(&ent->mkeys);
@@ -803,13 +1033,18 @@ int mlx5_mkey_cache_cleanup(struct mlx5_ib_dev *dev)
mlx5_mkey_cache_debugfs_cleanup(dev);
mlx5_cmd_cleanup_async_ctx(&dev->async_ctx);
- for (i = 0; i < MAX_MKEY_CACHE_ENTRIES; i++)
- clean_keys(dev, i);
+ node = rb_first(root);
+ while (node) {
+ ent = rb_entry(node, struct mlx5_cache_ent, node);
+ node = rb_next(node);
+ clean_keys(dev, ent);
+ rb_erase(&ent->node, root);
+ kfree(ent);
+ }
+ mutex_unlock(&dev->cache.rb_lock);
destroy_workqueue(dev->cache.wq);
del_timer_sync(&dev->delay_timer);
-
- return 0;
}
struct ib_mr *mlx5_ib_get_dma_mr(struct ib_pd *pd, int acc)
@@ -873,23 +1108,10 @@ static int get_octo_len(u64 addr, u64 len, int page_shift)
static int mkey_cache_max_order(struct mlx5_ib_dev *dev)
{
if (MLX5_CAP_GEN(dev->mdev, umr_extended_translation_offset))
- return MKEY_CACHE_LAST_STD_ENTRY + 2;
+ return MKEY_CACHE_LAST_STD_ENTRY;
return MLX5_MAX_UMR_SHIFT;
}
-static struct mlx5_cache_ent *mkey_cache_ent_from_order(struct mlx5_ib_dev *dev,
- unsigned int order)
-{
- struct mlx5_mkey_cache *cache = &dev->cache;
-
- if (order < cache->ent[0].order)
- return &cache->ent[0];
- order = order - cache->ent[0].order;
- if (order > MKEY_CACHE_LAST_STD_ENTRY)
- return NULL;
- return &cache->ent[order];
-}
-
static void set_mr_fields(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr,
u64 length, int access_flags, u64 iova)
{
@@ -916,6 +1138,9 @@ static struct mlx5_ib_mr *alloc_cacheable_mr(struct ib_pd *pd,
struct ib_umem *umem, u64 iova,
int access_flags)
{
+ struct mlx5r_cache_rb_key rb_key = {
+ .access_mode = MLX5_MKC_ACCESS_MODE_MTT,
+ };
struct mlx5_ib_dev *dev = to_mdev(pd->device);
struct mlx5_cache_ent *ent;
struct mlx5_ib_mr *mr;
@@ -928,22 +1153,26 @@ static struct mlx5_ib_mr *alloc_cacheable_mr(struct ib_pd *pd,
0, iova);
if (WARN_ON(!page_size))
return ERR_PTR(-EINVAL);
- ent = mkey_cache_ent_from_order(
- dev, order_base_2(ib_umem_num_dma_blocks(umem, page_size)));
+
+ rb_key.ndescs = ib_umem_num_dma_blocks(umem, page_size);
+ rb_key.ats = mlx5_umem_needs_ats(dev, umem, access_flags);
+ rb_key.access_flags = get_unchangeable_access_flags(dev, access_flags);
+ ent = mkey_cache_ent_from_rb_key(dev, rb_key);
/*
- * Matches access in alloc_cache_mr(). If the MR can't come from the
- * cache then synchronously create an uncached one.
+ * If the MR can't come from the cache then synchronously create an uncached
+ * one.
*/
- if (!ent || ent->limit == 0 ||
- !mlx5r_umr_can_reconfig(dev, 0, access_flags) ||
- mlx5_umem_needs_ats(dev, umem, access_flags)) {
+ if (!ent) {
mutex_lock(&dev->slow_path_mutex);
mr = reg_create(pd, umem, iova, access_flags, page_size, false);
mutex_unlock(&dev->slow_path_mutex);
+ if (IS_ERR(mr))
+ return mr;
+ mr->mmkey.rb_key = rb_key;
return mr;
}
- mr = mlx5_mr_cache_alloc(dev, ent, access_flags);
+ mr = _mlx5_mr_cache_alloc(dev, ent, access_flags);
if (IS_ERR(mr))
return mr;
@@ -1030,6 +1259,7 @@ static struct mlx5_ib_mr *reg_create(struct ib_pd *pd, struct ib_umem *umem,
goto err_2;
}
mr->mmkey.type = MLX5_MKEY_MR;
+ mr->mmkey.ndescs = get_octo_len(iova, umem->length, mr->page_shift);
mr->umem = umem;
set_mr_fields(dev, mr, umem->length, access_flags, iova);
kvfree(in);
@@ -1372,7 +1602,7 @@ static bool can_use_umr_rereg_pas(struct mlx5_ib_mr *mr,
mlx5_umem_find_best_pgsz(new_umem, mkc, log_page_size, 0, iova);
if (WARN_ON(!*page_size))
return false;
- return (1ULL << mr->mmkey.cache_ent->order) >=
+ return (mr->mmkey.cache_ent->rb_key.ndescs) >=
ib_umem_num_dma_blocks(new_umem, *page_size);
}
@@ -1567,6 +1797,49 @@ mlx5_free_priv_descs(struct mlx5_ib_mr *mr)
}
}
+static int cache_ent_find_and_store(struct mlx5_ib_dev *dev,
+ struct mlx5_ib_mr *mr)
+{
+ struct mlx5_mkey_cache *cache = &dev->cache;
+ struct mlx5_cache_ent *ent;
+ int ret;
+
+ if (mr->mmkey.cache_ent) {
+ xa_lock_irq(&mr->mmkey.cache_ent->mkeys);
+ mr->mmkey.cache_ent->in_use--;
+ goto end;
+ }
+
+ mutex_lock(&cache->rb_lock);
+ ent = mkey_cache_ent_from_rb_key(dev, mr->mmkey.rb_key);
+ if (ent) {
+ if (ent->rb_key.ndescs == mr->mmkey.rb_key.ndescs) {
+ if (ent->disabled) {
+ mutex_unlock(&cache->rb_lock);
+ return -EOPNOTSUPP;
+ }
+ mr->mmkey.cache_ent = ent;
+ xa_lock_irq(&mr->mmkey.cache_ent->mkeys);
+ mutex_unlock(&cache->rb_lock);
+ goto end;
+ }
+ }
+
+ ent = mlx5r_cache_create_ent_locked(dev, mr->mmkey.rb_key, false);
+ mutex_unlock(&cache->rb_lock);
+ if (IS_ERR(ent))
+ return PTR_ERR(ent);
+
+ mr->mmkey.cache_ent = ent;
+ xa_lock_irq(&mr->mmkey.cache_ent->mkeys);
+
+end:
+ ret = push_mkey_locked(mr->mmkey.cache_ent, false,
+ xa_mk_value(mr->mmkey.key));
+ xa_unlock_irq(&mr->mmkey.cache_ent->mkeys);
+ return ret;
+}
+
int mlx5_ib_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata)
{
struct mlx5_ib_mr *mr = to_mmr(ibmr);
@@ -1612,16 +1885,11 @@ int mlx5_ib_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata)
}
/* Stop DMA */
- if (mr->mmkey.cache_ent) {
- xa_lock_irq(&mr->mmkey.cache_ent->mkeys);
- mr->mmkey.cache_ent->in_use--;
- xa_unlock_irq(&mr->mmkey.cache_ent->mkeys);
-
+ if (mr->umem && mlx5r_umr_can_load_pas(dev, mr->umem->length))
if (mlx5r_umr_revoke_mr(mr) ||
- push_mkey(mr->mmkey.cache_ent, false,
- xa_mk_value(mr->mmkey.key)))
+ cache_ent_find_and_store(dev, mr))
mr->mmkey.cache_ent = NULL;
- }
+
if (!mr->mmkey.cache_ent) {
rc = destroy_mkey(to_mdev(mr->ibmr.device), mr);
if (rc)
diff --git a/drivers/infiniband/hw/mlx5/odp.c b/drivers/infiniband/hw/mlx5/odp.c
index e6e021af6aa9..4a04cbc5b78a 100644
--- a/drivers/infiniband/hw/mlx5/odp.c
+++ b/drivers/infiniband/hw/mlx5/odp.c
@@ -104,7 +104,7 @@ static void populate_klm(struct mlx5_klm *pklm, size_t idx, size_t nentries,
if (flags & MLX5_IB_UPD_XLT_ZAP) {
for (; pklm != end; pklm++, idx++) {
pklm->bcount = cpu_to_be32(MLX5_IMR_MTT_SIZE);
- pklm->key = cpu_to_be32(mr_to_mdev(imr)->null_mkey);
+ pklm->key = mr_to_mdev(imr)->mkeys.null_mkey;
pklm->va = 0;
}
return;
@@ -137,7 +137,7 @@ static void populate_klm(struct mlx5_klm *pklm, size_t idx, size_t nentries,
pklm->key = cpu_to_be32(mtt->ibmr.lkey);
pklm->va = cpu_to_be64(idx * MLX5_IMR_MTT_SIZE);
} else {
- pklm->key = cpu_to_be32(mr_to_mdev(imr)->null_mkey);
+ pklm->key = mr_to_mdev(imr)->mkeys.null_mkey;
pklm->va = 0;
}
}
@@ -417,8 +417,9 @@ static struct mlx5_ib_mr *implicit_get_child_mr(struct mlx5_ib_mr *imr,
if (IS_ERR(odp))
return ERR_CAST(odp);
- mr = mlx5_mr_cache_alloc(dev, &dev->cache.ent[MLX5_IMR_MTT_CACHE_ENTRY],
- imr->access_flags);
+ mr = mlx5_mr_cache_alloc(dev, imr->access_flags,
+ MLX5_MKC_ACCESS_MODE_MTT,
+ MLX5_IMR_MTT_ENTRIES);
if (IS_ERR(mr)) {
ib_umem_odp_release(odp);
return mr;
@@ -492,9 +493,8 @@ struct mlx5_ib_mr *mlx5_ib_alloc_implicit_mr(struct mlx5_ib_pd *pd,
if (IS_ERR(umem_odp))
return ERR_CAST(umem_odp);
- imr = mlx5_mr_cache_alloc(dev,
- &dev->cache.ent[MLX5_IMR_KSM_CACHE_ENTRY],
- access_flags);
+ imr = mlx5_mr_cache_alloc(dev, access_flags, MLX5_MKC_ACCESS_MODE_KSM,
+ mlx5_imr_ksm_entries);
if (IS_ERR(imr)) {
ib_umem_odp_release(umem_odp);
return imr;
@@ -986,7 +986,7 @@ static int pagefault_data_segments(struct mlx5_ib_dev *dev,
{
int ret = 0, npages = 0;
u64 io_virt;
- u32 key;
+ __be32 key;
u32 byte_count;
size_t bcnt;
int inline_segment;
@@ -1000,7 +1000,7 @@ static int pagefault_data_segments(struct mlx5_ib_dev *dev,
struct mlx5_wqe_data_seg *dseg = wqe;
io_virt = be64_to_cpu(dseg->addr);
- key = be32_to_cpu(dseg->lkey);
+ key = dseg->lkey;
byte_count = be32_to_cpu(dseg->byte_count);
inline_segment = !!(byte_count & MLX5_INLINE_SEG);
bcnt = byte_count & ~MLX5_INLINE_SEG;
@@ -1014,7 +1014,8 @@ static int pagefault_data_segments(struct mlx5_ib_dev *dev,
}
/* receive WQE end of sg list. */
- if (receive_queue && bcnt == 0 && key == MLX5_INVALID_LKEY &&
+ if (receive_queue && bcnt == 0 &&
+ key == dev->mkeys.terminate_scatter_list_mkey &&
io_virt == 0)
break;
@@ -1034,7 +1035,7 @@ static int pagefault_data_segments(struct mlx5_ib_dev *dev,
continue;
}
- ret = pagefault_single_data_segment(dev, NULL, key,
+ ret = pagefault_single_data_segment(dev, NULL, be32_to_cpu(key),
io_virt, bcnt,
&pfault->bytes_committed,
bytes_mapped);
@@ -1587,26 +1588,22 @@ mlx5_ib_odp_destroy_eq(struct mlx5_ib_dev *dev, struct mlx5_ib_pf_eq *eq)
return err;
}
-void mlx5_odp_init_mkey_cache_entry(struct mlx5_cache_ent *ent)
+int mlx5_odp_init_mkey_cache(struct mlx5_ib_dev *dev)
{
- if (!(ent->dev->odp_caps.general_caps & IB_ODP_SUPPORT_IMPLICIT))
- return;
+ struct mlx5r_cache_rb_key rb_key = {
+ .access_mode = MLX5_MKC_ACCESS_MODE_KSM,
+ .ndescs = mlx5_imr_ksm_entries,
+ };
+ struct mlx5_cache_ent *ent;
- switch (ent->order - 2) {
- case MLX5_IMR_MTT_CACHE_ENTRY:
- ent->page = PAGE_SHIFT;
- ent->ndescs = MLX5_IMR_MTT_ENTRIES;
- ent->access_mode = MLX5_MKC_ACCESS_MODE_MTT;
- ent->limit = 0;
- break;
+ if (!(dev->odp_caps.general_caps & IB_ODP_SUPPORT_IMPLICIT))
+ return 0;
- case MLX5_IMR_KSM_CACHE_ENTRY:
- ent->page = MLX5_KSM_PAGE_SHIFT;
- ent->ndescs = mlx5_imr_ksm_entries;
- ent->access_mode = MLX5_MKC_ACCESS_MODE_KSM;
- ent->limit = 0;
- break;
- }
+ ent = mlx5r_cache_create_ent_locked(dev, rb_key, true);
+ if (IS_ERR(ent))
+ return PTR_ERR(ent);
+
+ return 0;
}
static const struct ib_device_ops mlx5_ib_dev_odp_ops = {
@@ -1615,25 +1612,15 @@ static const struct ib_device_ops mlx5_ib_dev_odp_ops = {
int mlx5_ib_odp_init_one(struct mlx5_ib_dev *dev)
{
- int ret = 0;
-
internal_fill_odp_caps(dev);
if (!(dev->odp_caps.general_caps & IB_ODP_SUPPORT))
- return ret;
+ return 0;
ib_set_device_ops(&dev->ib_dev, &mlx5_ib_dev_odp_ops);
- if (dev->odp_caps.general_caps & IB_ODP_SUPPORT_IMPLICIT) {
- ret = mlx5_cmd_null_mkey(dev->mdev, &dev->null_mkey);
- if (ret) {
- mlx5_ib_err(dev, "Error getting null_mkey %d\n", ret);
- return ret;
- }
- }
-
mutex_init(&dev->odp_eq_mutex);
- return ret;
+ return 0;
}
void mlx5_ib_odp_cleanup_one(struct mlx5_ib_dev *dev)
diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c
index cf953d23d18d..7cc3b973dec7 100644
--- a/drivers/infiniband/hw/mlx5/qp.c
+++ b/drivers/infiniband/hw/mlx5/qp.c
@@ -71,6 +71,14 @@ struct mlx5_modify_raw_qp_param {
u32 port;
};
+struct mlx5_ib_qp_event_work {
+ struct work_struct work;
+ struct mlx5_core_qp *qp;
+ int type;
+};
+
+static struct workqueue_struct *mlx5_ib_qp_event_wq;
+
static void get_cqs(enum ib_qp_type qp_type,
struct ib_cq *ib_send_cq, struct ib_cq *ib_recv_cq,
struct mlx5_ib_cq **send_cq, struct mlx5_ib_cq **recv_cq);
@@ -302,51 +310,120 @@ int mlx5_ib_read_wqe_srq(struct mlx5_ib_srq *srq, int wqe_index, void *buffer,
return mlx5_ib_read_user_wqe_srq(srq, wqe_index, buffer, buflen, bc);
}
+static void mlx5_ib_qp_err_syndrome(struct ib_qp *ibqp)
+{
+ struct mlx5_ib_dev *dev = to_mdev(ibqp->device);
+ int outlen = MLX5_ST_SZ_BYTES(query_qp_out);
+ struct mlx5_ib_qp *qp = to_mqp(ibqp);
+ void *pas_ext_union, *err_syn;
+ u32 *outb;
+ int err;
+
+ if (!MLX5_CAP_GEN(dev->mdev, qpc_extension) ||
+ !MLX5_CAP_GEN(dev->mdev, qp_error_syndrome))
+ return;
+
+ outb = kzalloc(outlen, GFP_KERNEL);
+ if (!outb)
+ return;
+
+ err = mlx5_core_qp_query(dev, &qp->trans_qp.base.mqp, outb, outlen,
+ true);
+ if (err)
+ goto out;
+
+ pas_ext_union =
+ MLX5_ADDR_OF(query_qp_out, outb, qp_pas_or_qpc_ext_and_pas);
+ err_syn = MLX5_ADDR_OF(qpc_extension_and_pas_list_in, pas_ext_union,
+ qpc_data_extension.error_syndrome);
+
+ pr_err("%s/%d: QP %d error: %s (0x%x 0x%x 0x%x)\n",
+ ibqp->device->name, ibqp->port, ibqp->qp_num,
+ ib_wc_status_msg(
+ MLX5_GET(cqe_error_syndrome, err_syn, syndrome)),
+ MLX5_GET(cqe_error_syndrome, err_syn, vendor_error_syndrome),
+ MLX5_GET(cqe_error_syndrome, err_syn, hw_syndrome_type),
+ MLX5_GET(cqe_error_syndrome, err_syn, hw_error_syndrome));
+out:
+ kfree(outb);
+}
+
+static void mlx5_ib_handle_qp_event(struct work_struct *_work)
+{
+ struct mlx5_ib_qp_event_work *qpe_work =
+ container_of(_work, struct mlx5_ib_qp_event_work, work);
+ struct ib_qp *ibqp = &to_mibqp(qpe_work->qp)->ibqp;
+ struct ib_event event = {};
+
+ event.device = ibqp->device;
+ event.element.qp = ibqp;
+ switch (qpe_work->type) {
+ case MLX5_EVENT_TYPE_PATH_MIG:
+ event.event = IB_EVENT_PATH_MIG;
+ break;
+ case MLX5_EVENT_TYPE_COMM_EST:
+ event.event = IB_EVENT_COMM_EST;
+ break;
+ case MLX5_EVENT_TYPE_SQ_DRAINED:
+ event.event = IB_EVENT_SQ_DRAINED;
+ break;
+ case MLX5_EVENT_TYPE_SRQ_LAST_WQE:
+ event.event = IB_EVENT_QP_LAST_WQE_REACHED;
+ break;
+ case MLX5_EVENT_TYPE_WQ_CATAS_ERROR:
+ event.event = IB_EVENT_QP_FATAL;
+ break;
+ case MLX5_EVENT_TYPE_PATH_MIG_FAILED:
+ event.event = IB_EVENT_PATH_MIG_ERR;
+ break;
+ case MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR:
+ event.event = IB_EVENT_QP_REQ_ERR;
+ break;
+ case MLX5_EVENT_TYPE_WQ_ACCESS_ERROR:
+ event.event = IB_EVENT_QP_ACCESS_ERR;
+ break;
+ default:
+ pr_warn("mlx5_ib: Unexpected event type %d on QP %06x\n",
+ qpe_work->type, qpe_work->qp->qpn);
+ goto out;
+ }
+
+ if ((event.event == IB_EVENT_QP_FATAL) ||
+ (event.event == IB_EVENT_QP_ACCESS_ERR))
+ mlx5_ib_qp_err_syndrome(ibqp);
+
+ ibqp->event_handler(&event, ibqp->qp_context);
+
+out:
+ mlx5_core_res_put(&qpe_work->qp->common);
+ kfree(qpe_work);
+}
+
static void mlx5_ib_qp_event(struct mlx5_core_qp *qp, int type)
{
struct ib_qp *ibqp = &to_mibqp(qp)->ibqp;
- struct ib_event event;
+ struct mlx5_ib_qp_event_work *qpe_work;
if (type == MLX5_EVENT_TYPE_PATH_MIG) {
/* This event is only valid for trans_qps */
to_mibqp(qp)->port = to_mibqp(qp)->trans_qp.alt_port;
}
- if (ibqp->event_handler) {
- event.device = ibqp->device;
- event.element.qp = ibqp;
- switch (type) {
- case MLX5_EVENT_TYPE_PATH_MIG:
- event.event = IB_EVENT_PATH_MIG;
- break;
- case MLX5_EVENT_TYPE_COMM_EST:
- event.event = IB_EVENT_COMM_EST;
- break;
- case MLX5_EVENT_TYPE_SQ_DRAINED:
- event.event = IB_EVENT_SQ_DRAINED;
- break;
- case MLX5_EVENT_TYPE_SRQ_LAST_WQE:
- event.event = IB_EVENT_QP_LAST_WQE_REACHED;
- break;
- case MLX5_EVENT_TYPE_WQ_CATAS_ERROR:
- event.event = IB_EVENT_QP_FATAL;
- break;
- case MLX5_EVENT_TYPE_PATH_MIG_FAILED:
- event.event = IB_EVENT_PATH_MIG_ERR;
- break;
- case MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR:
- event.event = IB_EVENT_QP_REQ_ERR;
- break;
- case MLX5_EVENT_TYPE_WQ_ACCESS_ERROR:
- event.event = IB_EVENT_QP_ACCESS_ERR;
- break;
- default:
- pr_warn("mlx5_ib: Unexpected event type %d on QP %06x\n", type, qp->qpn);
- return;
- }
+ if (!ibqp->event_handler)
+ goto out_no_handler;
- ibqp->event_handler(&event, ibqp->qp_context);
- }
+ qpe_work = kzalloc(sizeof(*qpe_work), GFP_ATOMIC);
+ if (!qpe_work)
+ goto out_no_handler;
+
+ qpe_work->qp = qp;
+ qpe_work->type = type;
+ INIT_WORK(&qpe_work->work, mlx5_ib_handle_qp_event);
+ queue_work(mlx5_ib_qp_event_wq, &qpe_work->work);
+ return;
+
+out_no_handler:
+ mlx5_core_res_put(&qp->common);
}
static int set_rq_size(struct mlx5_ib_dev *dev, struct ib_qp_cap *cap,
@@ -4827,7 +4904,8 @@ static int query_qp_attr(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
if (!outb)
return -ENOMEM;
- err = mlx5_core_qp_query(dev, &qp->trans_qp.base.mqp, outb, outlen);
+ err = mlx5_core_qp_query(dev, &qp->trans_qp.base.mqp, outb, outlen,
+ false);
if (err)
goto out;
@@ -5720,3 +5798,17 @@ out:
mutex_unlock(&mqp->mutex);
return err;
}
+
+int mlx5_ib_qp_event_init(void)
+{
+ mlx5_ib_qp_event_wq = alloc_ordered_workqueue("mlx5_ib_qp_event_wq", 0);
+ if (!mlx5_ib_qp_event_wq)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void mlx5_ib_qp_event_cleanup(void)
+{
+ destroy_workqueue(mlx5_ib_qp_event_wq);
+}
diff --git a/drivers/infiniband/hw/mlx5/qp.h b/drivers/infiniband/hw/mlx5/qp.h
index 5d4e140db99c..77f9b4a54816 100644
--- a/drivers/infiniband/hw/mlx5/qp.h
+++ b/drivers/infiniband/hw/mlx5/qp.h
@@ -20,7 +20,7 @@ int mlx5_core_qp_modify(struct mlx5_ib_dev *dev, u16 opcode, u32 opt_param_mask,
int mlx5_core_destroy_qp(struct mlx5_ib_dev *dev, struct mlx5_core_qp *qp);
int mlx5_core_destroy_dct(struct mlx5_ib_dev *dev, struct mlx5_core_dct *dct);
int mlx5_core_qp_query(struct mlx5_ib_dev *dev, struct mlx5_core_qp *qp,
- u32 *out, int outlen);
+ u32 *out, int outlen, bool qpc_ext);
int mlx5_core_dct_query(struct mlx5_ib_dev *dev, struct mlx5_core_dct *dct,
u32 *out, int outlen);
@@ -44,4 +44,6 @@ void mlx5_core_res_put(struct mlx5_core_rsc_common *res);
int mlx5_core_xrcd_alloc(struct mlx5_ib_dev *dev, u32 *xrcdn);
int mlx5_core_xrcd_dealloc(struct mlx5_ib_dev *dev, u32 xrcdn);
int mlx5_ib_qp_set_counter(struct ib_qp *qp, struct rdma_counter *counter);
+int mlx5_ib_qp_event_init(void);
+void mlx5_ib_qp_event_cleanup(void);
#endif /* _MLX5_IB_QP_H */
diff --git a/drivers/infiniband/hw/mlx5/qpc.c b/drivers/infiniband/hw/mlx5/qpc.c
index 542e4c63a8de..bae0334d6e7f 100644
--- a/drivers/infiniband/hw/mlx5/qpc.c
+++ b/drivers/infiniband/hw/mlx5/qpc.c
@@ -135,7 +135,8 @@ static int rsc_event_notifier(struct notifier_block *nb,
case MLX5_RES_SQ:
qp = (struct mlx5_core_qp *)common;
qp->event(qp, event_type);
- break;
+ /* Need to put resource in event handler */
+ return NOTIFY_OK;
case MLX5_RES_DCT:
dct = (struct mlx5_core_dct *)common;
if (event_type == MLX5_EVENT_TYPE_DCT_DRAINED)
@@ -504,12 +505,14 @@ void mlx5_cleanup_qp_table(struct mlx5_ib_dev *dev)
}
int mlx5_core_qp_query(struct mlx5_ib_dev *dev, struct mlx5_core_qp *qp,
- u32 *out, int outlen)
+ u32 *out, int outlen, bool qpc_ext)
{
u32 in[MLX5_ST_SZ_DW(query_qp_in)] = {};
MLX5_SET(query_qp_in, in, opcode, MLX5_CMD_OP_QUERY_QP);
MLX5_SET(query_qp_in, in, qpn, qp->qpn);
+ MLX5_SET(query_qp_in, in, qpc_ext, qpc_ext);
+
return mlx5_cmd_exec(dev->mdev, in, sizeof(in), out, outlen);
}
diff --git a/drivers/infiniband/hw/mlx5/srq.c b/drivers/infiniband/hw/mlx5/srq.c
index 09b365a98bbf..a056ea835da5 100644
--- a/drivers/infiniband/hw/mlx5/srq.c
+++ b/drivers/infiniband/hw/mlx5/srq.c
@@ -447,7 +447,7 @@ int mlx5_ib_post_srq_recv(struct ib_srq *ibsrq, const struct ib_recv_wr *wr,
if (i < srq->msrq.max_avail_gather) {
scat[i].byte_count = 0;
- scat[i].lkey = cpu_to_be32(MLX5_INVALID_LKEY);
+ scat[i].lkey = dev->mkeys.terminate_scatter_list_mkey;
scat[i].addr = 0;
}
}
diff --git a/drivers/infiniband/hw/mlx5/umr.c b/drivers/infiniband/hw/mlx5/umr.c
index 029e9536ec28..55f4e048d947 100644
--- a/drivers/infiniband/hw/mlx5/umr.c
+++ b/drivers/infiniband/hw/mlx5/umr.c
@@ -636,9 +636,7 @@ int mlx5r_umr_update_mr_pas(struct mlx5_ib_mr *mr, unsigned int flags)
mlx5r_umr_set_update_xlt_data_seg(&wqe.data_seg, &sg);
cur_mtt = mtt;
- rdma_for_each_block(mr->umem->sgt_append.sgt.sgl, &biter,
- mr->umem->sgt_append.sgt.nents,
- BIT(mr->page_shift)) {
+ rdma_umem_for_each_dma_block(mr->umem, &biter, BIT(mr->page_shift)) {
if (cur_mtt == (void *)mtt + sg.length) {
dma_sync_single_for_device(ddev, sg.addr, sg.length,
DMA_TO_DEVICE);
diff --git a/drivers/infiniband/hw/mlx5/wr.c b/drivers/infiniband/hw/mlx5/wr.c
index 855f3f4fefad..df1d1b0a3ef7 100644
--- a/drivers/infiniband/hw/mlx5/wr.c
+++ b/drivers/infiniband/hw/mlx5/wr.c
@@ -1252,7 +1252,7 @@ int mlx5_ib_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr,
if (i < qp->rq.max_gs) {
scat[i].byte_count = 0;
- scat[i].lkey = cpu_to_be32(MLX5_INVALID_LKEY);
+ scat[i].lkey = dev->mkeys.terminate_scatter_list_mkey;
scat[i].addr = 0;
}
diff --git a/drivers/infiniband/hw/qib/qib_file_ops.c b/drivers/infiniband/hw/qib/qib_file_ops.c
index 3937144b2ae5..80fe92a21f96 100644
--- a/drivers/infiniband/hw/qib/qib_file_ops.c
+++ b/drivers/infiniband/hw/qib/qib_file_ops.c
@@ -733,7 +733,7 @@ static int qib_mmap_mem(struct vm_area_struct *vma, struct qib_ctxtdata *rcd,
}
/* don't allow them to later change with mprotect */
- vma->vm_flags &= ~VM_MAYWRITE;
+ vm_flags_clear(vma, VM_MAYWRITE);
}
pfn = virt_to_phys(kvaddr) >> PAGE_SHIFT;
@@ -769,7 +769,7 @@ static int mmap_ureg(struct vm_area_struct *vma, struct qib_devdata *dd,
phys = dd->physaddr + ureg;
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND;
+ vm_flags_set(vma, VM_DONTCOPY | VM_DONTEXPAND);
ret = io_remap_pfn_range(vma, vma->vm_start,
phys >> PAGE_SHIFT,
vma->vm_end - vma->vm_start,
@@ -810,8 +810,7 @@ static int mmap_piobufs(struct vm_area_struct *vma,
* don't allow them to later change to readable with mprotect (for when
* not initially mapped readable, as is normally the case)
*/
- vma->vm_flags &= ~VM_MAYREAD;
- vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND;
+ vm_flags_mod(vma, VM_DONTCOPY | VM_DONTEXPAND, VM_MAYREAD);
/* We used PAT if wc_cookie == 0 */
if (!dd->wc_cookie)
@@ -852,7 +851,7 @@ static int mmap_rcvegrbufs(struct vm_area_struct *vma,
goto bail;
}
/* don't allow them to later change to writable with mprotect */
- vma->vm_flags &= ~VM_MAYWRITE;
+ vm_flags_clear(vma, VM_MAYWRITE);
start = vma->vm_start;
@@ -944,7 +943,7 @@ static int mmap_kvaddr(struct vm_area_struct *vma, u64 pgaddr,
* Don't allow permission to later change to writable
* with mprotect.
*/
- vma->vm_flags &= ~VM_MAYWRITE;
+ vm_flags_clear(vma, VM_MAYWRITE);
} else
goto bail;
len = vma->vm_end - vma->vm_start;
@@ -955,7 +954,7 @@ static int mmap_kvaddr(struct vm_area_struct *vma, u64 pgaddr,
vma->vm_pgoff = (unsigned long) addr >> PAGE_SHIFT;
vma->vm_ops = &qib_file_vm_ops;
- vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
+ vm_flags_set(vma, VM_DONTEXPAND | VM_DONTDUMP);
ret = 1;
bail:
diff --git a/drivers/infiniband/hw/usnic/usnic_ib_verbs.c b/drivers/infiniband/hw/usnic/usnic_ib_verbs.c
index 6e8c4fbb8083..6289238cc5af 100644
--- a/drivers/infiniband/hw/usnic/usnic_ib_verbs.c
+++ b/drivers/infiniband/hw/usnic/usnic_ib_verbs.c
@@ -672,7 +672,7 @@ int usnic_ib_mmap(struct ib_ucontext *context,
usnic_dbg("\n");
us_ibdev = to_usdev(context->device);
- vma->vm_flags |= VM_IO;
+ vm_flags_set(vma, VM_IO);
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
vfid = vma->vm_pgoff;
usnic_dbg("Page Offset %lu PAGE_SHIFT %u VFID %u\n",
diff --git a/drivers/infiniband/hw/usnic/usnic_uiom.c b/drivers/infiniband/hw/usnic/usnic_uiom.c
index a2857accc427..2a5cac2658ec 100644
--- a/drivers/infiniband/hw/usnic/usnic_uiom.c
+++ b/drivers/infiniband/hw/usnic/usnic_uiom.c
@@ -276,8 +276,8 @@ iter_chunk:
size = pa_end - pa_start + PAGE_SIZE;
usnic_dbg("va 0x%lx pa %pa size 0x%zx flags 0x%x",
va_start, &pa_start, size, flags);
- err = iommu_map_atomic(pd->domain, va_start,
- pa_start, size, flags);
+ err = iommu_map(pd->domain, va_start, pa_start,
+ size, flags, GFP_ATOMIC);
if (err) {
usnic_err("Failed to map va 0x%lx pa %pa size 0x%zx with err %d\n",
va_start, &pa_start, size, err);
@@ -293,8 +293,8 @@ iter_chunk:
size = pa - pa_start + PAGE_SIZE;
usnic_dbg("va 0x%lx pa %pa size 0x%zx flags 0x%x\n",
va_start, &pa_start, size, flags);
- err = iommu_map_atomic(pd->domain, va_start,
- pa_start, size, flags);
+ err = iommu_map(pd->domain, va_start, pa_start,
+ size, flags, GFP_ATOMIC);
if (err) {
usnic_err("Failed to map va 0x%lx pa %pa size 0x%zx with err %d\n",
va_start, &pa_start, size, err);
diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c
index 19176583dbde..9f54aa90a35a 100644
--- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c
+++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c
@@ -408,7 +408,7 @@ int pvrdma_mmap(struct ib_ucontext *ibcontext, struct vm_area_struct *vma)
}
/* Map UAR to kernel space, VM_LOCKED? */
- vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND;
+ vm_flags_set(vma, VM_DONTCOPY | VM_DONTEXPAND);
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
if (io_remap_pfn_range(vma, start, context->uar.pfn, size,
vma->vm_page_prot))
diff --git a/drivers/infiniband/sw/rxe/rxe.h b/drivers/infiniband/sw/rxe/rxe.h
index ab334900fcc3..2415f3704f57 100644
--- a/drivers/infiniband/sw/rxe/rxe.h
+++ b/drivers/infiniband/sw/rxe/rxe.h
@@ -57,6 +57,44 @@
#define rxe_dbg_mw(mw, fmt, ...) ibdev_dbg((mw)->ibmw.device, \
"mw#%d %s: " fmt, (mw)->elem.index, __func__, ##__VA_ARGS__)
+/* responder states */
+enum resp_states {
+ RESPST_NONE,
+ RESPST_GET_REQ,
+ RESPST_CHK_PSN,
+ RESPST_CHK_OP_SEQ,
+ RESPST_CHK_OP_VALID,
+ RESPST_CHK_RESOURCE,
+ RESPST_CHK_LENGTH,
+ RESPST_CHK_RKEY,
+ RESPST_EXECUTE,
+ RESPST_READ_REPLY,
+ RESPST_ATOMIC_REPLY,
+ RESPST_ATOMIC_WRITE_REPLY,
+ RESPST_PROCESS_FLUSH,
+ RESPST_COMPLETE,
+ RESPST_ACKNOWLEDGE,
+ RESPST_CLEANUP,
+ RESPST_DUPLICATE_REQUEST,
+ RESPST_ERR_MALFORMED_WQE,
+ RESPST_ERR_UNSUPPORTED_OPCODE,
+ RESPST_ERR_MISALIGNED_ATOMIC,
+ RESPST_ERR_PSN_OUT_OF_SEQ,
+ RESPST_ERR_MISSING_OPCODE_FIRST,
+ RESPST_ERR_MISSING_OPCODE_LAST_C,
+ RESPST_ERR_MISSING_OPCODE_LAST_D1E,
+ RESPST_ERR_TOO_MANY_RDMA_ATM_REQ,
+ RESPST_ERR_RNR,
+ RESPST_ERR_RKEY_VIOLATION,
+ RESPST_ERR_INVALIDATE_RKEY,
+ RESPST_ERR_LENGTH,
+ RESPST_ERR_CQ_OVERFLOW,
+ RESPST_ERROR,
+ RESPST_RESET,
+ RESPST_DONE,
+ RESPST_EXIT,
+};
+
void rxe_set_mtu(struct rxe_dev *rxe, unsigned int dev_mtu);
int rxe_add(struct rxe_dev *rxe, unsigned int mtu, const char *ibdev_name);
diff --git a/drivers/infiniband/sw/rxe/rxe_loc.h b/drivers/infiniband/sw/rxe/rxe_loc.h
index 948ce4902b10..1bb0cb479eb1 100644
--- a/drivers/infiniband/sw/rxe/rxe_loc.h
+++ b/drivers/infiniband/sw/rxe/rxe_loc.h
@@ -64,12 +64,16 @@ void rxe_mr_init_dma(int access, struct rxe_mr *mr);
int rxe_mr_init_user(struct rxe_dev *rxe, u64 start, u64 length, u64 iova,
int access, struct rxe_mr *mr);
int rxe_mr_init_fast(int max_pages, struct rxe_mr *mr);
-int rxe_flush_pmem_iova(struct rxe_mr *mr, u64 iova, int length);
-int rxe_mr_copy(struct rxe_mr *mr, u64 iova, void *addr, int length,
- enum rxe_mr_copy_dir dir);
+int rxe_flush_pmem_iova(struct rxe_mr *mr, u64 iova, unsigned int length);
+int rxe_mr_copy(struct rxe_mr *mr, u64 iova, void *addr,
+ unsigned int length, enum rxe_mr_copy_dir dir);
int copy_data(struct rxe_pd *pd, int access, struct rxe_dma_info *dma,
void *addr, int length, enum rxe_mr_copy_dir dir);
-void *iova_to_vaddr(struct rxe_mr *mr, u64 iova, int length);
+int rxe_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg,
+ int sg_nents, unsigned int *sg_offset);
+int rxe_mr_do_atomic_op(struct rxe_mr *mr, u64 iova, int opcode,
+ u64 compare, u64 swap_add, u64 *orig_val);
+int rxe_mr_do_atomic_write(struct rxe_mr *mr, u64 iova, u64 value);
struct rxe_mr *lookup_mr(struct rxe_pd *pd, int access, u32 key,
enum rxe_mr_lookup_type type);
int mr_check_range(struct rxe_mr *mr, u64 iova, size_t length);
diff --git a/drivers/infiniband/sw/rxe/rxe_mr.c b/drivers/infiniband/sw/rxe/rxe_mr.c
index 072eac4b65d2..b10aa1580a64 100644
--- a/drivers/infiniband/sw/rxe/rxe_mr.c
+++ b/drivers/infiniband/sw/rxe/rxe_mr.c
@@ -26,22 +26,22 @@ u8 rxe_get_next_key(u32 last_key)
int mr_check_range(struct rxe_mr *mr, u64 iova, size_t length)
{
-
-
switch (mr->ibmr.type) {
case IB_MR_TYPE_DMA:
return 0;
case IB_MR_TYPE_USER:
case IB_MR_TYPE_MEM_REG:
- if (iova < mr->ibmr.iova || length > mr->ibmr.length ||
- iova > mr->ibmr.iova + mr->ibmr.length - length)
- return -EFAULT;
+ if (iova < mr->ibmr.iova ||
+ iova + length > mr->ibmr.iova + mr->ibmr.length) {
+ rxe_dbg_mr(mr, "iova/length out of range");
+ return -EINVAL;
+ }
return 0;
default:
- rxe_dbg_mr(mr, "type (%d) not supported\n", mr->ibmr.type);
- return -EFAULT;
+ rxe_dbg_mr(mr, "mr type not supported\n");
+ return -EINVAL;
}
}
@@ -62,57 +62,31 @@ static void rxe_mr_init(int access, struct rxe_mr *mr)
mr->lkey = mr->ibmr.lkey = lkey;
mr->rkey = mr->ibmr.rkey = rkey;
+ mr->access = access;
+ mr->ibmr.page_size = PAGE_SIZE;
+ mr->page_mask = PAGE_MASK;
+ mr->page_shift = PAGE_SHIFT;
mr->state = RXE_MR_STATE_INVALID;
}
-static int rxe_mr_alloc(struct rxe_mr *mr, int num_buf)
-{
- int i;
- int num_map;
- struct rxe_map **map = mr->map;
-
- num_map = (num_buf + RXE_BUF_PER_MAP - 1) / RXE_BUF_PER_MAP;
-
- mr->map = kmalloc_array(num_map, sizeof(*map), GFP_KERNEL);
- if (!mr->map)
- goto err1;
-
- for (i = 0; i < num_map; i++) {
- mr->map[i] = kmalloc(sizeof(**map), GFP_KERNEL);
- if (!mr->map[i])
- goto err2;
- }
-
- BUILD_BUG_ON(!is_power_of_2(RXE_BUF_PER_MAP));
-
- mr->map_shift = ilog2(RXE_BUF_PER_MAP);
- mr->map_mask = RXE_BUF_PER_MAP - 1;
-
- mr->num_buf = num_buf;
- mr->num_map = num_map;
- mr->max_buf = num_map * RXE_BUF_PER_MAP;
-
- return 0;
-
-err2:
- for (i--; i >= 0; i--)
- kfree(mr->map[i]);
-
- kfree(mr->map);
- mr->map = NULL;
-err1:
- return -ENOMEM;
-}
-
void rxe_mr_init_dma(int access, struct rxe_mr *mr)
{
rxe_mr_init(access, mr);
- mr->access = access;
mr->state = RXE_MR_STATE_VALID;
mr->ibmr.type = IB_MR_TYPE_DMA;
}
+static unsigned long rxe_mr_iova_to_index(struct rxe_mr *mr, u64 iova)
+{
+ return (iova >> mr->page_shift) - (mr->ibmr.iova >> mr->page_shift);
+}
+
+static unsigned long rxe_mr_iova_to_page_offset(struct rxe_mr *mr, u64 iova)
+{
+ return iova & (mr_page_size(mr) - 1);
+}
+
static bool is_pmem_page(struct page *pg)
{
unsigned long paddr = page_to_phys(pg);
@@ -122,86 +96,98 @@ static bool is_pmem_page(struct page *pg)
IORES_DESC_PERSISTENT_MEMORY);
}
+static int rxe_mr_fill_pages_from_sgt(struct rxe_mr *mr, struct sg_table *sgt)
+{
+ XA_STATE(xas, &mr->page_list, 0);
+ struct sg_page_iter sg_iter;
+ struct page *page;
+ bool persistent = !!(mr->access & IB_ACCESS_FLUSH_PERSISTENT);
+
+ __sg_page_iter_start(&sg_iter, sgt->sgl, sgt->orig_nents, 0);
+ if (!__sg_page_iter_next(&sg_iter))
+ return 0;
+
+ do {
+ xas_lock(&xas);
+ while (true) {
+ page = sg_page_iter_page(&sg_iter);
+
+ if (persistent && !is_pmem_page(page)) {
+ rxe_dbg_mr(mr, "Page can't be persistent\n");
+ xas_set_err(&xas, -EINVAL);
+ break;
+ }
+
+ xas_store(&xas, page);
+ if (xas_error(&xas))
+ break;
+ xas_next(&xas);
+ if (!__sg_page_iter_next(&sg_iter))
+ break;
+ }
+ xas_unlock(&xas);
+ } while (xas_nomem(&xas, GFP_KERNEL));
+
+ return xas_error(&xas);
+}
+
int rxe_mr_init_user(struct rxe_dev *rxe, u64 start, u64 length, u64 iova,
int access, struct rxe_mr *mr)
{
- struct rxe_map **map;
- struct rxe_phys_buf *buf = NULL;
- struct ib_umem *umem;
- struct sg_page_iter sg_iter;
- int num_buf;
- void *vaddr;
+ struct ib_umem *umem;
int err;
+ rxe_mr_init(access, mr);
+
+ xa_init(&mr->page_list);
+
umem = ib_umem_get(&rxe->ib_dev, start, length, access);
if (IS_ERR(umem)) {
rxe_dbg_mr(mr, "Unable to pin memory region err = %d\n",
(int)PTR_ERR(umem));
- err = PTR_ERR(umem);
- goto err_out;
+ return PTR_ERR(umem);
}
- num_buf = ib_umem_num_pages(umem);
-
- rxe_mr_init(access, mr);
-
- err = rxe_mr_alloc(mr, num_buf);
+ err = rxe_mr_fill_pages_from_sgt(mr, &umem->sgt_append.sgt);
if (err) {
- rxe_dbg_mr(mr, "Unable to allocate memory for map\n");
- goto err_release_umem;
+ ib_umem_release(umem);
+ return err;
}
- mr->page_shift = PAGE_SHIFT;
- mr->page_mask = PAGE_SIZE - 1;
-
- num_buf = 0;
- map = mr->map;
- if (length > 0) {
- bool persistent_access = access & IB_ACCESS_FLUSH_PERSISTENT;
-
- buf = map[0]->buf;
- for_each_sgtable_page (&umem->sgt_append.sgt, &sg_iter, 0) {
- struct page *pg = sg_page_iter_page(&sg_iter);
+ mr->umem = umem;
+ mr->ibmr.type = IB_MR_TYPE_USER;
+ mr->state = RXE_MR_STATE_VALID;
- if (persistent_access && !is_pmem_page(pg)) {
- rxe_dbg_mr(mr, "Unable to register persistent access to non-pmem device\n");
- err = -EINVAL;
- goto err_release_umem;
- }
+ return 0;
+}
- if (num_buf >= RXE_BUF_PER_MAP) {
- map++;
- buf = map[0]->buf;
- num_buf = 0;
- }
+static int rxe_mr_alloc(struct rxe_mr *mr, int num_buf)
+{
+ XA_STATE(xas, &mr->page_list, 0);
+ int i = 0;
+ int err;
- vaddr = page_address(pg);
- if (!vaddr) {
- rxe_dbg_mr(mr, "Unable to get virtual address\n");
- err = -ENOMEM;
- goto err_release_umem;
- }
- buf->addr = (uintptr_t)vaddr;
- buf->size = PAGE_SIZE;
- num_buf++;
- buf++;
+ xa_init(&mr->page_list);
+ do {
+ xas_lock(&xas);
+ while (i != num_buf) {
+ xas_store(&xas, XA_ZERO_ENTRY);
+ if (xas_error(&xas))
+ break;
+ xas_next(&xas);
+ i++;
}
- }
+ xas_unlock(&xas);
+ } while (xas_nomem(&xas, GFP_KERNEL));
- mr->umem = umem;
- mr->access = access;
- mr->offset = ib_umem_offset(umem);
- mr->state = RXE_MR_STATE_VALID;
- mr->ibmr.type = IB_MR_TYPE_USER;
- mr->ibmr.page_size = PAGE_SIZE;
+ err = xas_error(&xas);
+ if (err)
+ return err;
- return 0;
+ mr->num_buf = num_buf;
-err_release_umem:
- ib_umem_release(umem);
-err_out:
- return err;
+ return 0;
}
int rxe_mr_init_fast(int max_pages, struct rxe_mr *mr)
@@ -215,7 +201,6 @@ int rxe_mr_init_fast(int max_pages, struct rxe_mr *mr)
if (err)
goto err1;
- mr->max_buf = max_pages;
mr->state = RXE_MR_STATE_FREE;
mr->ibmr.type = IB_MR_TYPE_MEM_REG;
@@ -225,187 +210,125 @@ err1:
return err;
}
-static void lookup_iova(struct rxe_mr *mr, u64 iova, int *m_out, int *n_out,
- size_t *offset_out)
+static int rxe_set_page(struct ib_mr *ibmr, u64 iova)
{
- size_t offset = iova - mr->ibmr.iova + mr->offset;
- int map_index;
- int buf_index;
- u64 length;
-
- if (likely(mr->page_shift)) {
- *offset_out = offset & mr->page_mask;
- offset >>= mr->page_shift;
- *n_out = offset & mr->map_mask;
- *m_out = offset >> mr->map_shift;
- } else {
- map_index = 0;
- buf_index = 0;
+ struct rxe_mr *mr = to_rmr(ibmr);
+ struct page *page = virt_to_page(iova & mr->page_mask);
+ bool persistent = !!(mr->access & IB_ACCESS_FLUSH_PERSISTENT);
+ int err;
- length = mr->map[map_index]->buf[buf_index].size;
+ if (persistent && !is_pmem_page(page)) {
+ rxe_dbg_mr(mr, "Page cannot be persistent\n");
+ return -EINVAL;
+ }
- while (offset >= length) {
- offset -= length;
- buf_index++;
+ if (unlikely(mr->nbuf == mr->num_buf))
+ return -ENOMEM;
- if (buf_index == RXE_BUF_PER_MAP) {
- map_index++;
- buf_index = 0;
- }
- length = mr->map[map_index]->buf[buf_index].size;
- }
+ err = xa_err(xa_store(&mr->page_list, mr->nbuf, page, GFP_KERNEL));
+ if (err)
+ return err;
- *m_out = map_index;
- *n_out = buf_index;
- *offset_out = offset;
- }
+ mr->nbuf++;
+ return 0;
}
-void *iova_to_vaddr(struct rxe_mr *mr, u64 iova, int length)
+int rxe_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sgl,
+ int sg_nents, unsigned int *sg_offset)
{
- size_t offset;
- int m, n;
- void *addr;
-
- if (mr->state != RXE_MR_STATE_VALID) {
- rxe_dbg_mr(mr, "Not in valid state\n");
- addr = NULL;
- goto out;
- }
-
- if (!mr->map) {
- addr = (void *)(uintptr_t)iova;
- goto out;
- }
-
- if (mr_check_range(mr, iova, length)) {
- rxe_dbg_mr(mr, "Range violation\n");
- addr = NULL;
- goto out;
- }
-
- lookup_iova(mr, iova, &m, &n, &offset);
-
- if (offset + length > mr->map[m]->buf[n].size) {
- rxe_dbg_mr(mr, "Crosses page boundary\n");
- addr = NULL;
- goto out;
- }
+ struct rxe_mr *mr = to_rmr(ibmr);
+ unsigned int page_size = mr_page_size(mr);
- addr = (void *)(uintptr_t)mr->map[m]->buf[n].addr + offset;
+ mr->nbuf = 0;
+ mr->page_shift = ilog2(page_size);
+ mr->page_mask = ~((u64)page_size - 1);
+ mr->page_offset = mr->ibmr.iova & (page_size - 1);
-out:
- return addr;
+ return ib_sg_to_pages(ibmr, sgl, sg_nents, sg_offset, rxe_set_page);
}
-int rxe_flush_pmem_iova(struct rxe_mr *mr, u64 iova, int length)
+static int rxe_mr_copy_xarray(struct rxe_mr *mr, u64 iova, void *addr,
+ unsigned int length, enum rxe_mr_copy_dir dir)
{
- size_t offset;
-
- if (length == 0)
- return 0;
-
- if (mr->ibmr.type == IB_MR_TYPE_DMA)
- return -EFAULT;
+ unsigned int page_offset = rxe_mr_iova_to_page_offset(mr, iova);
+ unsigned long index = rxe_mr_iova_to_index(mr, iova);
+ unsigned int bytes;
+ struct page *page;
+ void *va;
- offset = (iova - mr->ibmr.iova + mr->offset) & mr->page_mask;
- while (length > 0) {
- u8 *va;
- int bytes;
-
- bytes = mr->ibmr.page_size - offset;
- if (bytes > length)
- bytes = length;
-
- va = iova_to_vaddr(mr, iova, length);
- if (!va)
+ while (length) {
+ page = xa_load(&mr->page_list, index);
+ if (!page)
return -EFAULT;
- arch_wb_cache_pmem(va, bytes);
-
+ bytes = min_t(unsigned int, length,
+ mr_page_size(mr) - page_offset);
+ va = kmap_local_page(page);
+ if (dir == RXE_FROM_MR_OBJ)
+ memcpy(addr, va + page_offset, bytes);
+ else
+ memcpy(va + page_offset, addr, bytes);
+ kunmap_local(va);
+
+ page_offset = 0;
+ addr += bytes;
length -= bytes;
- iova += bytes;
- offset = 0;
+ index++;
}
return 0;
}
-/* copy data from a range (vaddr, vaddr+length-1) to or from
- * a mr object starting at iova.
- */
-int rxe_mr_copy(struct rxe_mr *mr, u64 iova, void *addr, int length,
- enum rxe_mr_copy_dir dir)
+static void rxe_mr_copy_dma(struct rxe_mr *mr, u64 iova, void *addr,
+ unsigned int length, enum rxe_mr_copy_dir dir)
{
- int err;
- int bytes;
- u8 *va;
- struct rxe_map **map;
- struct rxe_phys_buf *buf;
- int m;
- int i;
- size_t offset;
+ unsigned int page_offset = iova & (PAGE_SIZE - 1);
+ unsigned int bytes;
+ struct page *page;
+ u8 *va;
- if (length == 0)
- return 0;
-
- if (mr->ibmr.type == IB_MR_TYPE_DMA) {
- u8 *src, *dest;
+ while (length) {
+ page = virt_to_page(iova & mr->page_mask);
+ bytes = min_t(unsigned int, length,
+ PAGE_SIZE - page_offset);
+ va = kmap_local_page(page);
+
+ if (dir == RXE_TO_MR_OBJ)
+ memcpy(va + page_offset, addr, bytes);
+ else
+ memcpy(addr, va + page_offset, bytes);
+
+ kunmap_local(va);
+ page_offset = 0;
+ iova += bytes;
+ addr += bytes;
+ length -= bytes;
+ }
+}
- src = (dir == RXE_TO_MR_OBJ) ? addr : ((void *)(uintptr_t)iova);
+int rxe_mr_copy(struct rxe_mr *mr, u64 iova, void *addr,
+ unsigned int length, enum rxe_mr_copy_dir dir)
+{
+ int err;
- dest = (dir == RXE_TO_MR_OBJ) ? ((void *)(uintptr_t)iova) : addr;
+ if (length == 0)
+ return 0;
- memcpy(dest, src, length);
+ if (WARN_ON(!mr))
+ return -EINVAL;
+ if (mr->ibmr.type == IB_MR_TYPE_DMA) {
+ rxe_mr_copy_dma(mr, iova, addr, length, dir);
return 0;
}
- WARN_ON_ONCE(!mr->map);
-
err = mr_check_range(mr, iova, length);
- if (err) {
- err = -EFAULT;
- goto err1;
- }
-
- lookup_iova(mr, iova, &m, &i, &offset);
-
- map = mr->map + m;
- buf = map[0]->buf + i;
-
- while (length > 0) {
- u8 *src, *dest;
-
- va = (u8 *)(uintptr_t)buf->addr + offset;
- src = (dir == RXE_TO_MR_OBJ) ? addr : va;
- dest = (dir == RXE_TO_MR_OBJ) ? va : addr;
-
- bytes = buf->size - offset;
-
- if (bytes > length)
- bytes = length;
-
- memcpy(dest, src, bytes);
-
- length -= bytes;
- addr += bytes;
-
- offset = 0;
- buf++;
- i++;
-
- if (i == RXE_BUF_PER_MAP) {
- i = 0;
- map++;
- buf = map[0]->buf;
- }
+ if (unlikely(err)) {
+ rxe_dbg_mr(mr, "iova out of range");
+ return err;
}
- return 0;
-
-err1:
- return err;
+ return rxe_mr_copy_xarray(mr, iova, addr, length, dir);
}
/* copy data in or out of a wqe, i.e. sg list
@@ -477,7 +400,6 @@ int copy_data(
if (bytes > 0) {
iova = sge->addr + offset;
-
err = rxe_mr_copy(mr, iova, addr, bytes, dir);
if (err)
goto err2;
@@ -504,6 +426,165 @@ err1:
return err;
}
+int rxe_flush_pmem_iova(struct rxe_mr *mr, u64 iova, unsigned int length)
+{
+ unsigned int page_offset;
+ unsigned long index;
+ struct page *page;
+ unsigned int bytes;
+ int err;
+ u8 *va;
+
+ /* mr must be valid even if length is zero */
+ if (WARN_ON(!mr))
+ return -EINVAL;
+
+ if (length == 0)
+ return 0;
+
+ if (mr->ibmr.type == IB_MR_TYPE_DMA)
+ return -EFAULT;
+
+ err = mr_check_range(mr, iova, length);
+ if (err)
+ return err;
+
+ while (length > 0) {
+ index = rxe_mr_iova_to_index(mr, iova);
+ page = xa_load(&mr->page_list, index);
+ page_offset = rxe_mr_iova_to_page_offset(mr, iova);
+ if (!page)
+ return -EFAULT;
+ bytes = min_t(unsigned int, length,
+ mr_page_size(mr) - page_offset);
+
+ va = kmap_local_page(page);
+ arch_wb_cache_pmem(va + page_offset, bytes);
+ kunmap_local(va);
+
+ length -= bytes;
+ iova += bytes;
+ page_offset = 0;
+ }
+
+ return 0;
+}
+
+/* Guarantee atomicity of atomic operations at the machine level. */
+static DEFINE_SPINLOCK(atomic_ops_lock);
+
+int rxe_mr_do_atomic_op(struct rxe_mr *mr, u64 iova, int opcode,
+ u64 compare, u64 swap_add, u64 *orig_val)
+{
+ unsigned int page_offset;
+ struct page *page;
+ u64 value;
+ u64 *va;
+
+ if (unlikely(mr->state != RXE_MR_STATE_VALID)) {
+ rxe_dbg_mr(mr, "mr not in valid state");
+ return RESPST_ERR_RKEY_VIOLATION;
+ }
+
+ if (mr->ibmr.type == IB_MR_TYPE_DMA) {
+ page_offset = iova & (PAGE_SIZE - 1);
+ page = virt_to_page(iova & PAGE_MASK);
+ } else {
+ unsigned long index;
+ int err;
+
+ err = mr_check_range(mr, iova, sizeof(value));
+ if (err) {
+ rxe_dbg_mr(mr, "iova out of range");
+ return RESPST_ERR_RKEY_VIOLATION;
+ }
+ page_offset = rxe_mr_iova_to_page_offset(mr, iova);
+ index = rxe_mr_iova_to_index(mr, iova);
+ page = xa_load(&mr->page_list, index);
+ if (!page)
+ return RESPST_ERR_RKEY_VIOLATION;
+ }
+
+ if (unlikely(page_offset & 0x7)) {
+ rxe_dbg_mr(mr, "iova not aligned");
+ return RESPST_ERR_MISALIGNED_ATOMIC;
+ }
+
+ va = kmap_local_page(page);
+
+ spin_lock_bh(&atomic_ops_lock);
+ value = *orig_val = va[page_offset >> 3];
+
+ if (opcode == IB_OPCODE_RC_COMPARE_SWAP) {
+ if (value == compare)
+ va[page_offset >> 3] = swap_add;
+ } else {
+ value += swap_add;
+ va[page_offset >> 3] = value;
+ }
+ spin_unlock_bh(&atomic_ops_lock);
+
+ kunmap_local(va);
+
+ return 0;
+}
+
+#if defined CONFIG_64BIT
+/* only implemented or called for 64 bit architectures */
+int rxe_mr_do_atomic_write(struct rxe_mr *mr, u64 iova, u64 value)
+{
+ unsigned int page_offset;
+ struct page *page;
+ u64 *va;
+
+ /* See IBA oA19-28 */
+ if (unlikely(mr->state != RXE_MR_STATE_VALID)) {
+ rxe_dbg_mr(mr, "mr not in valid state");
+ return RESPST_ERR_RKEY_VIOLATION;
+ }
+
+ if (mr->ibmr.type == IB_MR_TYPE_DMA) {
+ page_offset = iova & (PAGE_SIZE - 1);
+ page = virt_to_page(iova & PAGE_MASK);
+ } else {
+ unsigned long index;
+ int err;
+
+ /* See IBA oA19-28 */
+ err = mr_check_range(mr, iova, sizeof(value));
+ if (unlikely(err)) {
+ rxe_dbg_mr(mr, "iova out of range");
+ return RESPST_ERR_RKEY_VIOLATION;
+ }
+ page_offset = rxe_mr_iova_to_page_offset(mr, iova);
+ index = rxe_mr_iova_to_index(mr, iova);
+ page = xa_load(&mr->page_list, index);
+ if (!page)
+ return RESPST_ERR_RKEY_VIOLATION;
+ }
+
+ /* See IBA A19.4.2 */
+ if (unlikely(page_offset & 0x7)) {
+ rxe_dbg_mr(mr, "misaligned address");
+ return RESPST_ERR_MISALIGNED_ATOMIC;
+ }
+
+ va = kmap_local_page(page);
+
+ /* Do atomic write after all prior operations have completed */
+ smp_store_release(&va[page_offset >> 3], value);
+
+ kunmap_local(va);
+
+ return 0;
+}
+#else
+int rxe_mr_do_atomic_write(struct rxe_mr *mr, u64 iova, u64 value)
+{
+ return RESPST_ERR_UNSUPPORTED_OPCODE;
+}
+#endif
+
int advance_dma_data(struct rxe_dma_info *dma, unsigned int length)
{
struct rxe_sge *sge = &dma->sge[dma->cur_sge];
@@ -537,12 +618,6 @@ int advance_dma_data(struct rxe_dma_info *dma, unsigned int length)
return 0;
}
-/* (1) find the mr corresponding to lkey/rkey
- * depending on lookup_type
- * (2) verify that the (qp) pd matches the mr pd
- * (3) verify that the mr can support the requested access
- * (4) verify that mr state is valid
- */
struct rxe_mr *lookup_mr(struct rxe_pd *pd, int access, u32 key,
enum rxe_mr_lookup_type type)
{
@@ -656,22 +731,17 @@ int rxe_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata)
return -EINVAL;
rxe_cleanup(mr);
-
+ kfree_rcu(mr);
return 0;
}
void rxe_mr_cleanup(struct rxe_pool_elem *elem)
{
struct rxe_mr *mr = container_of(elem, typeof(*mr), elem);
- int i;
rxe_put(mr_pd(mr));
ib_umem_release(mr->umem);
- if (mr->map) {
- for (i = 0; i < mr->num_map; i++)
- kfree(mr->map[i]);
-
- kfree(mr->map);
- }
+ if (mr->ibmr.type != IB_MR_TYPE_DMA)
+ xa_destroy(&mr->page_list);
}
diff --git a/drivers/infiniband/sw/rxe/rxe_pool.c b/drivers/infiniband/sw/rxe/rxe_pool.c
index 1151c0b5ccea..6215c6de3a84 100644
--- a/drivers/infiniband/sw/rxe/rxe_pool.c
+++ b/drivers/infiniband/sw/rxe/rxe_pool.c
@@ -116,55 +116,12 @@ void rxe_pool_cleanup(struct rxe_pool *pool)
WARN_ON(!xa_empty(&pool->xa));
}
-void *rxe_alloc(struct rxe_pool *pool)
-{
- struct rxe_pool_elem *elem;
- void *obj;
- int err;
-
- if (WARN_ON(!(pool->type == RXE_TYPE_MR)))
- return NULL;
-
- if (atomic_inc_return(&pool->num_elem) > pool->max_elem)
- goto err_cnt;
-
- obj = kzalloc(pool->elem_size, GFP_KERNEL);
- if (!obj)
- goto err_cnt;
-
- elem = (struct rxe_pool_elem *)((u8 *)obj + pool->elem_offset);
-
- elem->pool = pool;
- elem->obj = obj;
- kref_init(&elem->ref_cnt);
- init_completion(&elem->complete);
-
- /* allocate index in array but leave pointer as NULL so it
- * can't be looked up until rxe_finalize() is called
- */
- err = xa_alloc_cyclic(&pool->xa, &elem->index, NULL, pool->limit,
- &pool->next, GFP_KERNEL);
- if (err < 0)
- goto err_free;
-
- return obj;
-
-err_free:
- kfree(obj);
-err_cnt:
- atomic_dec(&pool->num_elem);
- return NULL;
-}
-
int __rxe_add_to_pool(struct rxe_pool *pool, struct rxe_pool_elem *elem,
bool sleepable)
{
int err;
gfp_t gfp_flags;
- if (WARN_ON(pool->type == RXE_TYPE_MR))
- return -EINVAL;
-
if (atomic_inc_return(&pool->num_elem) > pool->max_elem)
goto err_cnt;
@@ -275,9 +232,6 @@ int __rxe_cleanup(struct rxe_pool_elem *elem, bool sleepable)
if (pool->cleanup)
pool->cleanup(elem);
- if (pool->type == RXE_TYPE_MR)
- kfree_rcu(elem->obj);
-
atomic_dec(&pool->num_elem);
return err;
diff --git a/drivers/infiniband/sw/rxe/rxe_pool.h b/drivers/infiniband/sw/rxe/rxe_pool.h
index 9d83cb32092f..b42e26427a70 100644
--- a/drivers/infiniband/sw/rxe/rxe_pool.h
+++ b/drivers/infiniband/sw/rxe/rxe_pool.h
@@ -54,9 +54,6 @@ void rxe_pool_init(struct rxe_dev *rxe, struct rxe_pool *pool,
/* free resources from object pool */
void rxe_pool_cleanup(struct rxe_pool *pool);
-/* allocate an object from pool */
-void *rxe_alloc(struct rxe_pool *pool);
-
/* connect already allocated object to pool */
int __rxe_add_to_pool(struct rxe_pool *pool, struct rxe_pool_elem *elem,
bool sleepable);
diff --git a/drivers/infiniband/sw/rxe/rxe_queue.h b/drivers/infiniband/sw/rxe/rxe_queue.h
index ed44042782fa..c711cb98b949 100644
--- a/drivers/infiniband/sw/rxe/rxe_queue.h
+++ b/drivers/infiniband/sw/rxe/rxe_queue.h
@@ -35,19 +35,26 @@
/**
* enum queue_type - type of queue
* @QUEUE_TYPE_TO_CLIENT: Queue is written by rxe driver and
- * read by client. Used by rxe driver only.
+ * read by client which may be a user space
+ * application or a kernel ulp.
+ * Used by rxe internals only.
* @QUEUE_TYPE_FROM_CLIENT: Queue is written by client and
- * read by rxe driver. Used by rxe driver only.
- * @QUEUE_TYPE_TO_DRIVER: Queue is written by client and
- * read by rxe driver. Used by kernel client only.
- * @QUEUE_TYPE_FROM_DRIVER: Queue is written by rxe driver and
- * read by client. Used by kernel client only.
+ * read by rxe driver.
+ * Used by rxe internals only.
+ * @QUEUE_TYPE_FROM_ULP: Queue is written by kernel ulp and
+ * read by rxe driver.
+ * Used by kernel verbs APIs only on
+ * behalf of ulps.
+ * @QUEUE_TYPE_TO_ULP: Queue is written by rxe driver and
+ * read by kernel ulp.
+ * Used by kernel verbs APIs only on
+ * behalf of ulps.
*/
enum queue_type {
QUEUE_TYPE_TO_CLIENT,
QUEUE_TYPE_FROM_CLIENT,
- QUEUE_TYPE_TO_DRIVER,
- QUEUE_TYPE_FROM_DRIVER,
+ QUEUE_TYPE_FROM_ULP,
+ QUEUE_TYPE_TO_ULP,
};
struct rxe_queue_buf;
@@ -62,9 +69,9 @@ struct rxe_queue {
u32 index_mask;
enum queue_type type;
/* private copy of index for shared queues between
- * kernel space and user space. Kernel reads and writes
+ * driver and clients. Driver reads and writes
* this copy and then replicates to rxe_queue_buf
- * for read access by user space.
+ * for read access by clients.
*/
u32 index;
};
@@ -97,19 +104,21 @@ static inline u32 queue_get_producer(const struct rxe_queue *q,
switch (type) {
case QUEUE_TYPE_FROM_CLIENT:
- /* protect user index */
+ /* used by rxe, client owns the index */
prod = smp_load_acquire(&q->buf->producer_index);
break;
case QUEUE_TYPE_TO_CLIENT:
+ /* used by rxe which owns the index */
prod = q->index;
break;
- case QUEUE_TYPE_FROM_DRIVER:
- /* protect driver index */
- prod = smp_load_acquire(&q->buf->producer_index);
- break;
- case QUEUE_TYPE_TO_DRIVER:
+ case QUEUE_TYPE_FROM_ULP:
+ /* used by ulp which owns the index */
prod = q->buf->producer_index;
break;
+ case QUEUE_TYPE_TO_ULP:
+ /* used by ulp, rxe owns the index */
+ prod = smp_load_acquire(&q->buf->producer_index);
+ break;
}
return prod;
@@ -122,19 +131,21 @@ static inline u32 queue_get_consumer(const struct rxe_queue *q,
switch (type) {
case QUEUE_TYPE_FROM_CLIENT:
+ /* used by rxe which owns the index */
cons = q->index;
break;
case QUEUE_TYPE_TO_CLIENT:
- /* protect user index */
+ /* used by rxe, client owns the index */
cons = smp_load_acquire(&q->buf->consumer_index);
break;
- case QUEUE_TYPE_FROM_DRIVER:
- cons = q->buf->consumer_index;
- break;
- case QUEUE_TYPE_TO_DRIVER:
- /* protect driver index */
+ case QUEUE_TYPE_FROM_ULP:
+ /* used by ulp, rxe owns the index */
cons = smp_load_acquire(&q->buf->consumer_index);
break;
+ case QUEUE_TYPE_TO_ULP:
+ /* used by ulp which owns the index */
+ cons = q->buf->consumer_index;
+ break;
}
return cons;
@@ -172,24 +183,31 @@ static inline void queue_advance_producer(struct rxe_queue *q,
switch (type) {
case QUEUE_TYPE_FROM_CLIENT:
- pr_warn("%s: attempt to advance client index\n",
- __func__);
+ /* used by rxe, client owns the index */
+ if (WARN_ON(1))
+ pr_warn("%s: attempt to advance client index\n",
+ __func__);
break;
case QUEUE_TYPE_TO_CLIENT:
+ /* used by rxe which owns the index */
prod = q->index;
prod = (prod + 1) & q->index_mask;
q->index = prod;
- /* protect user index */
+ /* release so client can read it safely */
smp_store_release(&q->buf->producer_index, prod);
break;
- case QUEUE_TYPE_FROM_DRIVER:
- pr_warn("%s: attempt to advance driver index\n",
- __func__);
- break;
- case QUEUE_TYPE_TO_DRIVER:
+ case QUEUE_TYPE_FROM_ULP:
+ /* used by ulp which owns the index */
prod = q->buf->producer_index;
prod = (prod + 1) & q->index_mask;
- q->buf->producer_index = prod;
+ /* release so rxe can read it safely */
+ smp_store_release(&q->buf->producer_index, prod);
+ break;
+ case QUEUE_TYPE_TO_ULP:
+ /* used by ulp, rxe owns the index */
+ if (WARN_ON(1))
+ pr_warn("%s: attempt to advance driver index\n",
+ __func__);
break;
}
}
@@ -201,24 +219,30 @@ static inline void queue_advance_consumer(struct rxe_queue *q,
switch (type) {
case QUEUE_TYPE_FROM_CLIENT:
- cons = q->index;
- cons = (cons + 1) & q->index_mask;
+ /* used by rxe which owns the index */
+ cons = (q->index + 1) & q->index_mask;
q->index = cons;
- /* protect user index */
+ /* release so client can read it safely */
smp_store_release(&q->buf->consumer_index, cons);
break;
case QUEUE_TYPE_TO_CLIENT:
- pr_warn("%s: attempt to advance client index\n",
- __func__);
+ /* used by rxe, client owns the index */
+ if (WARN_ON(1))
+ pr_warn("%s: attempt to advance client index\n",
+ __func__);
+ break;
+ case QUEUE_TYPE_FROM_ULP:
+ /* used by ulp, rxe owns the index */
+ if (WARN_ON(1))
+ pr_warn("%s: attempt to advance driver index\n",
+ __func__);
break;
- case QUEUE_TYPE_FROM_DRIVER:
+ case QUEUE_TYPE_TO_ULP:
+ /* used by ulp which owns the index */
cons = q->buf->consumer_index;
cons = (cons + 1) & q->index_mask;
- q->buf->consumer_index = cons;
- break;
- case QUEUE_TYPE_TO_DRIVER:
- pr_warn("%s: attempt to advance driver index\n",
- __func__);
+ /* release so rxe can read it safely */
+ smp_store_release(&q->buf->consumer_index, cons);
break;
}
}
diff --git a/drivers/infiniband/sw/rxe/rxe_resp.c b/drivers/infiniband/sw/rxe/rxe_resp.c
index c74972244f08..0cc1ba91d48c 100644
--- a/drivers/infiniband/sw/rxe/rxe_resp.c
+++ b/drivers/infiniband/sw/rxe/rxe_resp.c
@@ -10,43 +10,6 @@
#include "rxe_loc.h"
#include "rxe_queue.h"
-enum resp_states {
- RESPST_NONE,
- RESPST_GET_REQ,
- RESPST_CHK_PSN,
- RESPST_CHK_OP_SEQ,
- RESPST_CHK_OP_VALID,
- RESPST_CHK_RESOURCE,
- RESPST_CHK_LENGTH,
- RESPST_CHK_RKEY,
- RESPST_EXECUTE,
- RESPST_READ_REPLY,
- RESPST_ATOMIC_REPLY,
- RESPST_ATOMIC_WRITE_REPLY,
- RESPST_PROCESS_FLUSH,
- RESPST_COMPLETE,
- RESPST_ACKNOWLEDGE,
- RESPST_CLEANUP,
- RESPST_DUPLICATE_REQUEST,
- RESPST_ERR_MALFORMED_WQE,
- RESPST_ERR_UNSUPPORTED_OPCODE,
- RESPST_ERR_MISALIGNED_ATOMIC,
- RESPST_ERR_PSN_OUT_OF_SEQ,
- RESPST_ERR_MISSING_OPCODE_FIRST,
- RESPST_ERR_MISSING_OPCODE_LAST_C,
- RESPST_ERR_MISSING_OPCODE_LAST_D1E,
- RESPST_ERR_TOO_MANY_RDMA_ATM_REQ,
- RESPST_ERR_RNR,
- RESPST_ERR_RKEY_VIOLATION,
- RESPST_ERR_INVALIDATE_RKEY,
- RESPST_ERR_LENGTH,
- RESPST_ERR_CQ_OVERFLOW,
- RESPST_ERROR,
- RESPST_RESET,
- RESPST_DONE,
- RESPST_EXIT,
-};
-
static char *resp_state_name[] = {
[RESPST_NONE] = "NONE",
[RESPST_GET_REQ] = "GET_REQ",
@@ -457,13 +420,23 @@ static enum resp_states rxe_resp_check_length(struct rxe_qp *qp,
return RESPST_CHK_RKEY;
}
+/* if the reth length field is zero we can assume nothing
+ * about the rkey value and should not validate or use it.
+ * Instead set qp->resp.rkey to 0 which is an invalid rkey
+ * value since the minimum index part is 1.
+ */
static void qp_resp_from_reth(struct rxe_qp *qp, struct rxe_pkt_info *pkt)
{
+ unsigned int length = reth_len(pkt);
+
qp->resp.va = reth_va(pkt);
qp->resp.offset = 0;
- qp->resp.rkey = reth_rkey(pkt);
- qp->resp.resid = reth_len(pkt);
- qp->resp.length = reth_len(pkt);
+ qp->resp.resid = length;
+ qp->resp.length = length;
+ if (pkt->mask & RXE_READ_OR_WRITE_MASK && length == 0)
+ qp->resp.rkey = 0;
+ else
+ qp->resp.rkey = reth_rkey(pkt);
}
static void qp_resp_from_atmeth(struct rxe_qp *qp, struct rxe_pkt_info *pkt)
@@ -474,6 +447,10 @@ static void qp_resp_from_atmeth(struct rxe_qp *qp, struct rxe_pkt_info *pkt)
qp->resp.resid = sizeof(u64);
}
+/* resolve the packet rkey to qp->resp.mr or set qp->resp.mr to NULL
+ * if an invalid rkey is received or the rdma length is zero. For middle
+ * or last packets use the stored value of mr.
+ */
static enum resp_states check_rkey(struct rxe_qp *qp,
struct rxe_pkt_info *pkt)
{
@@ -510,10 +487,12 @@ static enum resp_states check_rkey(struct rxe_qp *qp,
return RESPST_EXECUTE;
}
- /* A zero-byte op is not required to set an addr or rkey. See C9-88 */
+ /* A zero-byte read or write op is not required to
+ * set an addr or rkey. See C9-88
+ */
if ((pkt->mask & RXE_READ_OR_WRITE_MASK) &&
- (pkt->mask & RXE_RETH_MASK) &&
- reth_len(pkt) == 0) {
+ (pkt->mask & RXE_RETH_MASK) && reth_len(pkt) == 0) {
+ qp->resp.mr = NULL;
return RESPST_EXECUTE;
}
@@ -592,6 +571,7 @@ skip_check_range:
return RESPST_EXECUTE;
err:
+ qp->resp.mr = NULL;
if (mr)
rxe_put(mr);
if (mw)
@@ -725,17 +705,12 @@ static enum resp_states process_flush(struct rxe_qp *qp,
return RESPST_ACKNOWLEDGE;
}
-/* Guarantee atomicity of atomic operations at the machine level. */
-static DEFINE_SPINLOCK(atomic_ops_lock);
-
static enum resp_states atomic_reply(struct rxe_qp *qp,
- struct rxe_pkt_info *pkt)
+ struct rxe_pkt_info *pkt)
{
- u64 *vaddr;
- enum resp_states ret;
struct rxe_mr *mr = qp->resp.mr;
struct resp_res *res = qp->resp.res;
- u64 value;
+ int err;
if (!res) {
res = rxe_prepare_res(qp, pkt, RXE_ATOMIC_MASK);
@@ -743,32 +718,14 @@ static enum resp_states atomic_reply(struct rxe_qp *qp,
}
if (!res->replay) {
- if (mr->state != RXE_MR_STATE_VALID) {
- ret = RESPST_ERR_RKEY_VIOLATION;
- goto out;
- }
-
- vaddr = iova_to_vaddr(mr, qp->resp.va + qp->resp.offset,
- sizeof(u64));
-
- /* check vaddr is 8 bytes aligned. */
- if (!vaddr || (uintptr_t)vaddr & 7) {
- ret = RESPST_ERR_MISALIGNED_ATOMIC;
- goto out;
- }
+ u64 iova = qp->resp.va + qp->resp.offset;
- spin_lock_bh(&atomic_ops_lock);
- res->atomic.orig_val = value = *vaddr;
-
- if (pkt->opcode == IB_OPCODE_RC_COMPARE_SWAP) {
- if (value == atmeth_comp(pkt))
- value = atmeth_swap_add(pkt);
- } else {
- value += atmeth_swap_add(pkt);
- }
-
- *vaddr = value;
- spin_unlock_bh(&atomic_ops_lock);
+ err = rxe_mr_do_atomic_op(mr, iova, pkt->opcode,
+ atmeth_comp(pkt),
+ atmeth_swap_add(pkt),
+ &res->atomic.orig_val);
+ if (err)
+ return err;
qp->resp.msn++;
@@ -780,35 +737,35 @@ static enum resp_states atomic_reply(struct rxe_qp *qp,
qp->resp.status = IB_WC_SUCCESS;
}
- ret = RESPST_ACKNOWLEDGE;
-out:
- return ret;
+ return RESPST_ACKNOWLEDGE;
}
-#ifdef CONFIG_64BIT
-static enum resp_states do_atomic_write(struct rxe_qp *qp,
- struct rxe_pkt_info *pkt)
+static enum resp_states atomic_write_reply(struct rxe_qp *qp,
+ struct rxe_pkt_info *pkt)
{
- struct rxe_mr *mr = qp->resp.mr;
- int payload = payload_size(pkt);
- u64 src, *dst;
-
- if (mr->state != RXE_MR_STATE_VALID)
- return RESPST_ERR_RKEY_VIOLATION;
+ struct resp_res *res = qp->resp.res;
+ struct rxe_mr *mr;
+ u64 value;
+ u64 iova;
+ int err;
- memcpy(&src, payload_addr(pkt), payload);
+ if (!res) {
+ res = rxe_prepare_res(qp, pkt, RXE_ATOMIC_WRITE_MASK);
+ qp->resp.res = res;
+ }
- dst = iova_to_vaddr(mr, qp->resp.va + qp->resp.offset, payload);
- /* check vaddr is 8 bytes aligned. */
- if (!dst || (uintptr_t)dst & 7)
- return RESPST_ERR_MISALIGNED_ATOMIC;
+ if (res->replay)
+ return RESPST_ACKNOWLEDGE;
- /* Do atomic write after all prior operations have completed */
- smp_store_release(dst, src);
+ mr = qp->resp.mr;
+ value = *(u64 *)payload_addr(pkt);
+ iova = qp->resp.va + qp->resp.offset;
- /* decrease resp.resid to zero */
- qp->resp.resid -= sizeof(payload);
+ err = rxe_mr_do_atomic_write(mr, iova, value);
+ if (err)
+ return err;
+ qp->resp.resid = 0;
qp->resp.msn++;
/* next expected psn, read handles this separately */
@@ -817,29 +774,8 @@ static enum resp_states do_atomic_write(struct rxe_qp *qp,
qp->resp.opcode = pkt->opcode;
qp->resp.status = IB_WC_SUCCESS;
- return RESPST_ACKNOWLEDGE;
-}
-#else
-static enum resp_states do_atomic_write(struct rxe_qp *qp,
- struct rxe_pkt_info *pkt)
-{
- return RESPST_ERR_UNSUPPORTED_OPCODE;
-}
-#endif /* CONFIG_64BIT */
-static enum resp_states atomic_write_reply(struct rxe_qp *qp,
- struct rxe_pkt_info *pkt)
-{
- struct resp_res *res = qp->resp.res;
-
- if (!res) {
- res = rxe_prepare_res(qp, pkt, RXE_ATOMIC_WRITE_MASK);
- qp->resp.res = res;
- }
-
- if (res->replay)
- return RESPST_ACKNOWLEDGE;
- return do_atomic_write(qp, pkt);
+ return RESPST_ACKNOWLEDGE;
}
static struct sk_buff *prepare_ack_packet(struct rxe_qp *qp,
@@ -966,7 +902,11 @@ static enum resp_states read_reply(struct rxe_qp *qp,
}
if (res->state == rdatm_res_state_new) {
- if (!res->replay) {
+ if (!res->replay || qp->resp.length == 0) {
+ /* if length == 0 mr will be NULL (is ok)
+ * otherwise qp->resp.mr holds a ref on mr
+ * which we transfer to mr and drop below.
+ */
mr = qp->resp.mr;
qp->resp.mr = NULL;
} else {
@@ -980,6 +920,10 @@ static enum resp_states read_reply(struct rxe_qp *qp,
else
opcode = IB_OPCODE_RC_RDMA_READ_RESPONSE_FIRST;
} else {
+ /* re-lookup mr from rkey on all later packets.
+ * length will be non-zero. This can fail if someone
+ * modifies or destroys the mr since the first packet.
+ */
mr = rxe_recheck_mr(qp, res->read.rkey);
if (!mr)
return RESPST_ERR_RKEY_VIOLATION;
@@ -997,18 +941,16 @@ static enum resp_states read_reply(struct rxe_qp *qp,
skb = prepare_ack_packet(qp, &ack_pkt, opcode, payload,
res->cur_psn, AETH_ACK_UNLIMITED);
if (!skb) {
- if (mr)
- rxe_put(mr);
- return RESPST_ERR_RNR;
+ state = RESPST_ERR_RNR;
+ goto err_out;
}
err = rxe_mr_copy(mr, res->read.va, payload_addr(&ack_pkt),
payload, RXE_FROM_MR_OBJ);
- if (mr)
- rxe_put(mr);
if (err) {
kfree_skb(skb);
- return RESPST_ERR_RKEY_VIOLATION;
+ state = RESPST_ERR_RKEY_VIOLATION;
+ goto err_out;
}
if (bth_pad(&ack_pkt)) {
@@ -1017,9 +959,12 @@ static enum resp_states read_reply(struct rxe_qp *qp,
memset(pad, 0, bth_pad(&ack_pkt));
}
+ /* rxe_xmit_packet always consumes the skb */
err = rxe_xmit_packet(qp, &ack_pkt, skb);
- if (err)
- return RESPST_ERR_RNR;
+ if (err) {
+ state = RESPST_ERR_RNR;
+ goto err_out;
+ }
res->read.va += payload;
res->read.resid -= payload;
@@ -1036,6 +981,9 @@ static enum resp_states read_reply(struct rxe_qp *qp,
state = RESPST_CLEANUP;
}
+err_out:
+ if (mr)
+ rxe_put(mr);
return state;
}
diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.c b/drivers/infiniband/sw/rxe/rxe_verbs.c
index 025b35bf014e..e14050a69276 100644
--- a/drivers/infiniband/sw/rxe/rxe_verbs.c
+++ b/drivers/infiniband/sw/rxe/rxe_verbs.c
@@ -245,7 +245,7 @@ static int post_one_recv(struct rxe_rq *rq, const struct ib_recv_wr *ibwr)
int num_sge = ibwr->num_sge;
int full;
- full = queue_full(rq->queue, QUEUE_TYPE_TO_DRIVER);
+ full = queue_full(rq->queue, QUEUE_TYPE_FROM_ULP);
if (unlikely(full))
return -ENOMEM;
@@ -256,7 +256,7 @@ static int post_one_recv(struct rxe_rq *rq, const struct ib_recv_wr *ibwr)
for (i = 0; i < num_sge; i++)
length += ibwr->sg_list[i].length;
- recv_wqe = queue_producer_addr(rq->queue, QUEUE_TYPE_TO_DRIVER);
+ recv_wqe = queue_producer_addr(rq->queue, QUEUE_TYPE_FROM_ULP);
recv_wqe->wr_id = ibwr->wr_id;
memcpy(recv_wqe->dma.sge, ibwr->sg_list,
@@ -268,7 +268,7 @@ static int post_one_recv(struct rxe_rq *rq, const struct ib_recv_wr *ibwr)
recv_wqe->dma.cur_sge = 0;
recv_wqe->dma.sge_offset = 0;
- queue_advance_producer(rq->queue, QUEUE_TYPE_TO_DRIVER);
+ queue_advance_producer(rq->queue, QUEUE_TYPE_FROM_ULP);
return 0;
}
@@ -623,17 +623,17 @@ static int post_one_send(struct rxe_qp *qp, const struct ib_send_wr *ibwr,
spin_lock_irqsave(&qp->sq.sq_lock, flags);
- full = queue_full(sq->queue, QUEUE_TYPE_TO_DRIVER);
+ full = queue_full(sq->queue, QUEUE_TYPE_FROM_ULP);
if (unlikely(full)) {
spin_unlock_irqrestore(&qp->sq.sq_lock, flags);
return -ENOMEM;
}
- send_wqe = queue_producer_addr(sq->queue, QUEUE_TYPE_TO_DRIVER);
+ send_wqe = queue_producer_addr(sq->queue, QUEUE_TYPE_FROM_ULP);
init_send_wqe(qp, ibwr, mask, length, send_wqe);
- queue_advance_producer(sq->queue, QUEUE_TYPE_TO_DRIVER);
+ queue_advance_producer(sq->queue, QUEUE_TYPE_FROM_ULP);
spin_unlock_irqrestore(&qp->sq.sq_lock, flags);
@@ -821,12 +821,12 @@ static int rxe_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc)
spin_lock_irqsave(&cq->cq_lock, flags);
for (i = 0; i < num_entries; i++) {
- cqe = queue_head(cq->queue, QUEUE_TYPE_FROM_DRIVER);
+ cqe = queue_head(cq->queue, QUEUE_TYPE_TO_ULP);
if (!cqe)
break;
memcpy(wc++, &cqe->ibwc, sizeof(*wc));
- queue_advance_consumer(cq->queue, QUEUE_TYPE_FROM_DRIVER);
+ queue_advance_consumer(cq->queue, QUEUE_TYPE_TO_ULP);
}
spin_unlock_irqrestore(&cq->cq_lock, flags);
@@ -838,7 +838,7 @@ static int rxe_peek_cq(struct ib_cq *ibcq, int wc_cnt)
struct rxe_cq *cq = to_rcq(ibcq);
int count;
- count = queue_count(cq->queue, QUEUE_TYPE_FROM_DRIVER);
+ count = queue_count(cq->queue, QUEUE_TYPE_TO_ULP);
return (count > wc_cnt) ? wc_cnt : count;
}
@@ -854,7 +854,7 @@ static int rxe_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags)
if (cq->notify != IB_CQ_NEXT_COMP)
cq->notify = flags & IB_CQ_SOLICITED_MASK;
- empty = queue_empty(cq->queue, QUEUE_TYPE_FROM_DRIVER);
+ empty = queue_empty(cq->queue, QUEUE_TYPE_TO_ULP);
if ((flags & IB_CQ_REPORT_MISSED_EVENTS) && !empty)
ret = 1;
@@ -869,10 +869,17 @@ static struct ib_mr *rxe_get_dma_mr(struct ib_pd *ibpd, int access)
struct rxe_dev *rxe = to_rdev(ibpd->device);
struct rxe_pd *pd = to_rpd(ibpd);
struct rxe_mr *mr;
+ int err;
- mr = rxe_alloc(&rxe->mr_pool);
- if (!mr)
- return ERR_PTR(-ENOMEM);
+ mr = kzalloc(sizeof(*mr), GFP_KERNEL);
+ if (!mr) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+ err = rxe_add_to_pool(&rxe->mr_pool, mr);
+ if (err)
+ goto err_free;
rxe_get(pd);
mr->ibmr.pd = ibpd;
@@ -880,8 +887,12 @@ static struct ib_mr *rxe_get_dma_mr(struct ib_pd *ibpd, int access)
rxe_mr_init_dma(access, mr);
rxe_finalize(mr);
-
return &mr->ibmr;
+
+err_free:
+ kfree(mr);
+err_out:
+ return ERR_PTR(err);
}
static struct ib_mr *rxe_reg_user_mr(struct ib_pd *ibpd,
@@ -895,9 +906,15 @@ static struct ib_mr *rxe_reg_user_mr(struct ib_pd *ibpd,
struct rxe_pd *pd = to_rpd(ibpd);
struct rxe_mr *mr;
- mr = rxe_alloc(&rxe->mr_pool);
- if (!mr)
- return ERR_PTR(-ENOMEM);
+ mr = kzalloc(sizeof(*mr), GFP_KERNEL);
+ if (!mr) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+ err = rxe_add_to_pool(&rxe->mr_pool, mr);
+ if (err)
+ goto err_free;
rxe_get(pd);
mr->ibmr.pd = ibpd;
@@ -905,14 +922,16 @@ static struct ib_mr *rxe_reg_user_mr(struct ib_pd *ibpd,
err = rxe_mr_init_user(rxe, start, length, iova, access, mr);
if (err)
- goto err1;
+ goto err_cleanup;
rxe_finalize(mr);
-
return &mr->ibmr;
-err1:
+err_cleanup:
rxe_cleanup(mr);
+err_free:
+ kfree(mr);
+err_out:
return ERR_PTR(err);
}
@@ -927,9 +946,15 @@ static struct ib_mr *rxe_alloc_mr(struct ib_pd *ibpd, enum ib_mr_type mr_type,
if (mr_type != IB_MR_TYPE_MEM_REG)
return ERR_PTR(-EINVAL);
- mr = rxe_alloc(&rxe->mr_pool);
- if (!mr)
- return ERR_PTR(-ENOMEM);
+ mr = kzalloc(sizeof(*mr), GFP_KERNEL);
+ if (!mr) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+ err = rxe_add_to_pool(&rxe->mr_pool, mr);
+ if (err)
+ goto err_free;
rxe_get(pd);
mr->ibmr.pd = ibpd;
@@ -937,53 +962,19 @@ static struct ib_mr *rxe_alloc_mr(struct ib_pd *ibpd, enum ib_mr_type mr_type,
err = rxe_mr_init_fast(max_num_sg, mr);
if (err)
- goto err1;
+ goto err_cleanup;
rxe_finalize(mr);
-
return &mr->ibmr;
-err1:
+err_cleanup:
rxe_cleanup(mr);
+err_free:
+ kfree(mr);
+err_out:
return ERR_PTR(err);
}
-static int rxe_set_page(struct ib_mr *ibmr, u64 addr)
-{
- struct rxe_mr *mr = to_rmr(ibmr);
- struct rxe_map *map;
- struct rxe_phys_buf *buf;
-
- if (unlikely(mr->nbuf == mr->num_buf))
- return -ENOMEM;
-
- map = mr->map[mr->nbuf / RXE_BUF_PER_MAP];
- buf = &map->buf[mr->nbuf % RXE_BUF_PER_MAP];
-
- buf->addr = addr;
- buf->size = ibmr->page_size;
- mr->nbuf++;
-
- return 0;
-}
-
-static int rxe_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg,
- int sg_nents, unsigned int *sg_offset)
-{
- struct rxe_mr *mr = to_rmr(ibmr);
- int n;
-
- mr->nbuf = 0;
-
- n = ib_sg_to_pages(ibmr, sg, sg_nents, sg_offset, rxe_set_page);
-
- mr->page_shift = ilog2(ibmr->page_size);
- mr->page_mask = ibmr->page_size - 1;
- mr->offset = ibmr->iova & mr->page_mask;
-
- return n;
-}
-
static ssize_t parent_show(struct device *device,
struct device_attribute *attr, char *buf)
{
diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.h b/drivers/infiniband/sw/rxe/rxe_verbs.h
index 19ddfa890480..c269ae2a3224 100644
--- a/drivers/infiniband/sw/rxe/rxe_verbs.h
+++ b/drivers/infiniband/sw/rxe/rxe_verbs.h
@@ -283,17 +283,6 @@ enum rxe_mr_lookup_type {
RXE_LOOKUP_REMOTE,
};
-#define RXE_BUF_PER_MAP (PAGE_SIZE / sizeof(struct rxe_phys_buf))
-
-struct rxe_phys_buf {
- u64 addr;
- u64 size;
-};
-
-struct rxe_map {
- struct rxe_phys_buf buf[RXE_BUF_PER_MAP];
-};
-
static inline int rkey_is_mw(u32 rkey)
{
u32 index = rkey >> 8;
@@ -310,25 +299,24 @@ struct rxe_mr {
u32 lkey;
u32 rkey;
enum rxe_mr_state state;
- u32 offset;
int access;
+ atomic_t num_mw;
- int page_shift;
- int page_mask;
- int map_shift;
- int map_mask;
+ unsigned int page_offset;
+ unsigned int page_shift;
+ u64 page_mask;
u32 num_buf;
u32 nbuf;
- u32 max_buf;
- u32 num_map;
-
- atomic_t num_mw;
-
- struct rxe_map **map;
+ struct xarray page_list;
};
+static inline unsigned int mr_page_size(struct rxe_mr *mr)
+{
+ return mr ? mr->ibmr.page_size : PAGE_SIZE;
+}
+
enum rxe_mw_state {
RXE_MW_STATE_INVALID = RXE_MR_STATE_INVALID,
RXE_MW_STATE_FREE = RXE_MR_STATE_FREE,
diff --git a/drivers/infiniband/sw/siw/siw_mem.c b/drivers/infiniband/sw/siw/siw_mem.c
index b2b33dd3b4fa..f51ab2ccf151 100644
--- a/drivers/infiniband/sw/siw/siw_mem.c
+++ b/drivers/infiniband/sw/siw/siw_mem.c
@@ -398,7 +398,7 @@ struct siw_umem *siw_umem_get(u64 start, u64 len, bool writable)
mlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
- if (num_pages + atomic64_read(&mm_s->pinned_vm) > mlock_limit) {
+ if (atomic64_add_return(num_pages, &mm_s->pinned_vm) > mlock_limit) {
rv = -ENOMEM;
goto out_sem_up;
}
@@ -411,30 +411,27 @@ struct siw_umem *siw_umem_get(u64 start, u64 len, bool writable)
goto out_sem_up;
}
for (i = 0; num_pages; i++) {
- int got, nents = min_t(int, num_pages, PAGES_PER_CHUNK);
-
- umem->page_chunk[i].plist =
+ int nents = min_t(int, num_pages, PAGES_PER_CHUNK);
+ struct page **plist =
kcalloc(nents, sizeof(struct page *), GFP_KERNEL);
- if (!umem->page_chunk[i].plist) {
+
+ if (!plist) {
rv = -ENOMEM;
goto out_sem_up;
}
- got = 0;
+ umem->page_chunk[i].plist = plist;
while (nents) {
- struct page **plist = &umem->page_chunk[i].plist[got];
-
rv = pin_user_pages(first_page_va, nents, foll_flags,
plist, NULL);
if (rv < 0)
goto out_sem_up;
umem->num_pages += rv;
- atomic64_add(rv, &mm_s->pinned_vm);
first_page_va += rv * PAGE_SIZE;
+ plist += rv;
nents -= rv;
- got += rv;
+ num_pages -= rv;
}
- num_pages -= got;
}
out_sem_up:
mmap_read_unlock(mm_s);
@@ -442,6 +439,10 @@ out_sem_up:
if (rv > 0)
return umem;
+ /* Adjust accounting for pages not pinned */
+ if (num_pages)
+ atomic64_sub(num_pages, &mm_s->pinned_vm);
+
siw_umem_release(umem, false);
return ERR_PTR(rv);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index f10d4bcf87d2..cf8b0822f5c8 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -742,7 +742,7 @@ void ipoib_flush_paths(struct net_device *dev)
static void path_rec_completion(int status,
struct sa_path_rec *pathrec,
- int num_prs, void *path_ptr)
+ unsigned int num_prs, void *path_ptr)
{
struct ipoib_path *path = path_ptr;
struct net_device *dev = path->dev;
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index 620ae5b2d80d..6b7603765383 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -446,7 +446,7 @@ iscsi_iser_conn_create(struct iscsi_cls_session *cls_session,
* @is_leading: indicate if this is the session leading connection (MCS)
*
* Return: zero on success, $error if iscsi_conn_bind fails and
- * -EINVAL in case end-point doesn't exsits anymore or iser connection
+ * -EINVAL in case end-point doesn't exists anymore or iser connection
* state is not UP (teardown already started).
*/
static int iscsi_iser_conn_bind(struct iscsi_cls_session *cls_session,
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index b4d6a4a5ae81..df21b30b7735 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -699,7 +699,7 @@ static void srp_free_ch_ib(struct srp_target_port *target,
static void srp_path_rec_completion(int status,
struct sa_path_rec *pathrec,
- int num_paths, void *ch_ptr)
+ unsigned int num_paths, void *ch_ptr)
{
struct srp_rdma_ch *ch = ch_ptr;
struct srp_target_port *target = ch->target;
diff --git a/drivers/input/input.c b/drivers/input/input.c
index ca2e3dd7188b..37e876d45eb9 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -19,6 +19,7 @@
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <linux/seq_file.h>
+#include <linux/pm.h>
#include <linux/poll.h>
#include <linux/device.h>
#include <linux/kstrtox.h>
@@ -1372,7 +1373,7 @@ INPUT_DEV_STRING_ATTR_SHOW(phys);
INPUT_DEV_STRING_ATTR_SHOW(uniq);
static int input_print_modalias_bits(char *buf, int size,
- char name, unsigned long *bm,
+ char name, const unsigned long *bm,
unsigned int min_bit, unsigned int max_bit)
{
int len = 0, i;
@@ -1384,7 +1385,7 @@ static int input_print_modalias_bits(char *buf, int size,
return len;
}
-static int input_print_modalias(char *buf, int size, struct input_dev *id,
+static int input_print_modalias(char *buf, int size, const struct input_dev *id,
int add_cr)
{
int len;
@@ -1432,7 +1433,7 @@ static ssize_t input_dev_show_modalias(struct device *dev,
}
static DEVICE_ATTR(modalias, S_IRUGO, input_dev_show_modalias, NULL);
-static int input_print_bitmap(char *buf, int buf_size, unsigned long *bitmap,
+static int input_print_bitmap(char *buf, int buf_size, const unsigned long *bitmap,
int max, int add_cr);
static ssize_t input_dev_show_properties(struct device *dev,
@@ -1524,7 +1525,7 @@ static const struct attribute_group input_dev_id_attr_group = {
.attrs = input_dev_id_attrs,
};
-static int input_print_bitmap(char *buf, int buf_size, unsigned long *bitmap,
+static int input_print_bitmap(char *buf, int buf_size, const unsigned long *bitmap,
int max, int add_cr)
{
int i;
@@ -1621,7 +1622,7 @@ static void input_dev_release(struct device *device)
* device bitfields.
*/
static int input_add_uevent_bm_var(struct kobj_uevent_env *env,
- const char *name, unsigned long *bitmap, int max)
+ const char *name, const unsigned long *bitmap, int max)
{
int len;
@@ -1639,7 +1640,7 @@ static int input_add_uevent_bm_var(struct kobj_uevent_env *env,
}
static int input_add_uevent_modalias_var(struct kobj_uevent_env *env,
- struct input_dev *dev)
+ const struct input_dev *dev)
{
int len;
@@ -1677,9 +1678,9 @@ static int input_add_uevent_modalias_var(struct kobj_uevent_env *env,
return err; \
} while (0)
-static int input_dev_uevent(struct device *device, struct kobj_uevent_env *env)
+static int input_dev_uevent(const struct device *device, struct kobj_uevent_env *env)
{
- struct input_dev *dev = to_input_dev(device);
+ const struct input_dev *dev = to_input_dev(device);
INPUT_ADD_HOTPLUG_VAR("PRODUCT=%x/%x/%x/%x",
dev->id.bustype, dev->id.vendor,
@@ -1828,7 +1829,6 @@ out:
return ret;
}
-#ifdef CONFIG_PM_SLEEP
static int input_dev_suspend(struct device *dev)
{
struct input_dev *input_dev = to_input_dev(dev);
@@ -1903,15 +1903,12 @@ static const struct dev_pm_ops input_dev_pm_ops = {
.poweroff = input_dev_poweroff,
.restore = input_dev_resume,
};
-#endif /* CONFIG_PM */
static const struct device_type input_dev_type = {
.groups = input_dev_attr_groups,
.release = input_dev_release,
.uevent = input_dev_uevent,
-#ifdef CONFIG_PM_SLEEP
- .pm = &input_dev_pm_ops,
-#endif
+ .pm = pm_sleep_ptr(&input_dev_pm_ops),
};
static char *input_devnode(const struct device *dev, umode_t *mode)
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index 2959d80f7fdb..f642ec8e92dd 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -359,6 +359,7 @@ static const struct xpad_device {
{ 0x24c6, 0xfafe, "Rock Candy Gamepad for Xbox 360", 0, XTYPE_XBOX360 },
{ 0x2563, 0x058d, "OneXPlayer Gamepad", 0, XTYPE_XBOX360 },
{ 0x2dc8, 0x2000, "8BitDo Pro 2 Wired Controller fox Xbox", 0, XTYPE_XBOXONE },
+ { 0x2dc8, 0x3106, "8BitDo Pro 2 Wired Controller", 0, XTYPE_XBOX360 },
{ 0x31e3, 0x1100, "Wooting One", 0, XTYPE_XBOX360 },
{ 0x31e3, 0x1200, "Wooting Two", 0, XTYPE_XBOX360 },
{ 0x31e3, 0x1210, "Wooting Lekker", 0, XTYPE_XBOX360 },
@@ -492,6 +493,7 @@ static const struct usb_device_id xpad_table[] = {
XPAD_XBOXONE_VENDOR(0x24c6), /* PowerA Controllers */
XPAD_XBOX360_VENDOR(0x2563), /* OneXPlayer Gamepad */
XPAD_XBOX360_VENDOR(0x260d), /* Dareu H101 */
+ XPAD_XBOX360_VENDOR(0x2dc8), /* 8BitDo Pro 2 Wired Controller */
XPAD_XBOXONE_VENDOR(0x2dc8), /* 8BitDo Pro 2 Wired Controller for Xbox */
XPAD_XBOXONE_VENDOR(0x2e24), /* Hyperkin Duke X-Box One pad */
XPAD_XBOX360_VENDOR(0x2f24), /* GameSir Controllers */
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index d98650426dc2..1d0c5f4c0f99 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -557,7 +557,7 @@ config KEYBOARD_PMIC8XXX
help
Say Y here if you want to enable the driver for the PMIC8XXX
keypad provided as a reference design from Qualcomm. This is intended
- to support upto 18x8 matrix based keypad design.
+ to support up to 18x8 matrix-based keypad design.
To compile this driver as a module, choose M here: the module will
be called pmic8xxx-keypad.
diff --git a/drivers/input/keyboard/applespi.c b/drivers/input/keyboard/applespi.c
index 91a9810f6980..cf25177b4830 100644
--- a/drivers/input/keyboard/applespi.c
+++ b/drivers/input/keyboard/applespi.c
@@ -1876,7 +1876,7 @@ static int applespi_poweroff_late(struct device *dev)
return 0;
}
-static int __maybe_unused applespi_suspend(struct device *dev)
+static int applespi_suspend(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
struct applespi_data *applespi = spi_get_drvdata(spi);
@@ -1903,7 +1903,7 @@ static int __maybe_unused applespi_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused applespi_resume(struct device *dev)
+static int applespi_resume(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
struct applespi_data *applespi = spi_get_drvdata(spi);
@@ -1947,15 +1947,15 @@ static const struct acpi_device_id applespi_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, applespi_acpi_match);
static const struct dev_pm_ops applespi_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(applespi_suspend, applespi_resume)
- .poweroff_late = applespi_poweroff_late,
+ SYSTEM_SLEEP_PM_OPS(applespi_suspend, applespi_resume)
+ .poweroff_late = pm_sleep_ptr(applespi_poweroff_late),
};
static struct spi_driver applespi_driver = {
.driver = {
.name = "applespi",
.acpi_match_table = applespi_acpi_match,
- .pm = &applespi_pm_ops,
+ .pm = pm_sleep_ptr(&applespi_pm_ops),
},
.probe = applespi_probe,
.remove = applespi_remove,
diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c
index 79afd0386e3f..040696d0e49c 100644
--- a/drivers/input/keyboard/cap11xx.c
+++ b/drivers/input/keyboard/cap11xx.c
@@ -98,14 +98,20 @@ enum {
CAP1106,
CAP1126,
CAP1188,
+ CAP1203,
CAP1206,
+ CAP1293,
+ CAP1298
};
static const struct cap11xx_hw_model cap11xx_devices[] = {
[CAP1106] = { .product_id = 0x55, .num_channels = 6, .num_leds = 0, .no_gain = false },
[CAP1126] = { .product_id = 0x53, .num_channels = 6, .num_leds = 2, .no_gain = false },
[CAP1188] = { .product_id = 0x50, .num_channels = 8, .num_leds = 8, .no_gain = false },
+ [CAP1203] = { .product_id = 0x6d, .num_channels = 3, .num_leds = 0, .no_gain = true },
[CAP1206] = { .product_id = 0x67, .num_channels = 6, .num_leds = 0, .no_gain = true },
+ [CAP1293] = { .product_id = 0x6f, .num_channels = 3, .num_leds = 0, .no_gain = false },
+ [CAP1298] = { .product_id = 0x71, .num_channels = 8, .num_leds = 0, .no_gain = false },
};
static const struct reg_default cap11xx_reg_defaults[] = {
@@ -377,7 +383,8 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client)
if (error < 0)
return error;
- dev_info(dev, "CAP11XX detected, revision 0x%02x\n", rev);
+ dev_info(dev, "CAP11XX detected, model %s, revision 0x%02x\n",
+ id->name, rev);
node = dev->of_node;
if (!of_property_read_u32(node, "microchip,sensor-gain", &gain32)) {
@@ -390,7 +397,9 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client)
dev_err(dev, "Invalid sensor-gain value %d\n", gain32);
}
- if (id->driver_data != CAP1206) {
+ if (id->driver_data == CAP1106 ||
+ id->driver_data == CAP1126 ||
+ id->driver_data == CAP1188) {
if (of_property_read_bool(node, "microchip,irq-active-high")) {
error = regmap_update_bits(priv->regmap,
CAP11XX_REG_CONFIG2,
@@ -483,7 +492,10 @@ static const struct of_device_id cap11xx_dt_ids[] = {
{ .compatible = "microchip,cap1106", },
{ .compatible = "microchip,cap1126", },
{ .compatible = "microchip,cap1188", },
+ { .compatible = "microchip,cap1203", },
{ .compatible = "microchip,cap1206", },
+ { .compatible = "microchip,cap1293", },
+ { .compatible = "microchip,cap1298", },
{}
};
MODULE_DEVICE_TABLE(of, cap11xx_dt_ids);
@@ -492,7 +504,10 @@ static const struct i2c_device_id cap11xx_i2c_ids[] = {
{ "cap1106", CAP1106 },
{ "cap1126", CAP1126 },
{ "cap1188", CAP1188 },
+ { "cap1203", CAP1203 },
{ "cap1206", CAP1206 },
+ { "cap1293", CAP1293 },
+ { "cap1298", CAP1298 },
{}
};
MODULE_DEVICE_TABLE(i2c, cap11xx_i2c_ids);
diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c
index 6f435125ec03..e7ecfca838df 100644
--- a/drivers/input/keyboard/cros_ec_keyb.c
+++ b/drivers/input/keyboard/cros_ec_keyb.c
@@ -100,6 +100,21 @@ static const struct cros_ec_bs_map cros_ec_keyb_bs[] = {
.code = KEY_VOLUMEDOWN,
.bit = EC_MKBP_VOL_DOWN,
},
+ {
+ .ev_type = EV_KEY,
+ .code = KEY_BRIGHTNESSUP,
+ .bit = EC_MKBP_BRI_UP,
+ },
+ {
+ .ev_type = EV_KEY,
+ .code = KEY_BRIGHTNESSDOWN,
+ .bit = EC_MKBP_BRI_DOWN,
+ },
+ {
+ .ev_type = EV_KEY,
+ .code = KEY_SCREENLOCK,
+ .bit = EC_MKBP_SCREEN_LOCK,
+ },
/* Switches */
{
diff --git a/drivers/input/keyboard/mtk-pmic-keys.c b/drivers/input/keyboard/mtk-pmic-keys.c
index 3d4ffa25e3df..4364c3401ff1 100644
--- a/drivers/input/keyboard/mtk-pmic-keys.c
+++ b/drivers/input/keyboard/mtk-pmic-keys.c
@@ -10,6 +10,7 @@
#include <linux/kernel.h>
#include <linux/mfd/mt6323/registers.h>
#include <linux/mfd/mt6331/registers.h>
+#include <linux/mfd/mt6357/registers.h>
#include <linux/mfd/mt6358/registers.h>
#include <linux/mfd/mt6397/core.h>
#include <linux/mfd/mt6397/registers.h>
@@ -90,6 +91,19 @@ static const struct mtk_pmic_regs mt6331_regs = {
.rst_lprst_mask = MTK_PMIC_MT6331_RST_DU_MASK,
};
+static const struct mtk_pmic_regs mt6357_regs = {
+ .keys_regs[MTK_PMIC_PWRKEY_INDEX] =
+ MTK_PMIC_KEYS_REGS(MT6357_TOPSTATUS,
+ 0x2, MT6357_PSC_TOP_INT_CON0, 0x5,
+ MTK_PMIC_PWRKEY_RST),
+ .keys_regs[MTK_PMIC_HOMEKEY_INDEX] =
+ MTK_PMIC_KEYS_REGS(MT6357_TOPSTATUS,
+ 0x8, MT6357_PSC_TOP_INT_CON0, 0xa,
+ MTK_PMIC_HOMEKEY_INDEX),
+ .pmic_rst_reg = MT6357_TOP_RST_MISC,
+ .rst_lprst_mask = MTK_PMIC_RST_DU_MASK,
+};
+
static const struct mtk_pmic_regs mt6358_regs = {
.keys_regs[MTK_PMIC_PWRKEY_INDEX] =
MTK_PMIC_KEYS_REGS(MT6358_TOPSTATUS,
@@ -277,6 +291,9 @@ static const struct of_device_id of_mtk_pmic_keys_match_tbl[] = {
.compatible = "mediatek,mt6331-keys",
.data = &mt6331_regs,
}, {
+ .compatible = "mediatek,mt6357-keys",
+ .data = &mt6357_regs,
+ }, {
.compatible = "mediatek,mt6358-keys",
.data = &mt6358_regs,
}, {
diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c
index ee9d04a3f0d5..4426120398b0 100644
--- a/drivers/input/keyboard/omap4-keypad.c
+++ b/drivers/input/keyboard/omap4-keypad.c
@@ -310,7 +310,7 @@ static int omap4_keypad_check_revision(struct device *dev,
* Interrupt may not happen for key-up events. We must clear stuck
* key-up events after the keyboard hardware has auto-idled.
*/
-static int __maybe_unused omap4_keypad_runtime_suspend(struct device *dev)
+static int omap4_keypad_runtime_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct omap4_keypad *keypad_data = platform_get_drvdata(pdev);
@@ -328,7 +328,7 @@ static int __maybe_unused omap4_keypad_runtime_suspend(struct device *dev)
}
static const struct dev_pm_ops omap4_keypad_pm_ops = {
- SET_RUNTIME_PM_OPS(omap4_keypad_runtime_suspend, NULL, NULL)
+ RUNTIME_PM_OPS(omap4_keypad_runtime_suspend, NULL, NULL)
};
static void omap4_disable_pm(void *d)
@@ -488,7 +488,7 @@ static struct platform_driver omap4_keypad_driver = {
.driver = {
.name = "omap4-keypad",
.of_match_table = omap_keypad_dt_match,
- .pm = &omap4_keypad_pm_ops,
+ .pm = pm_ptr(&omap4_keypad_pm_ops),
},
};
module_platform_driver(omap4_keypad_driver);
diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c
index df0258dcf89e..09e883ea1352 100644
--- a/drivers/input/keyboard/samsung-keypad.c
+++ b/drivers/input/keyboard/samsung-keypad.c
@@ -458,7 +458,6 @@ static int samsung_keypad_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
static int samsung_keypad_runtime_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -503,9 +502,7 @@ static int samsung_keypad_runtime_resume(struct device *dev)
return 0;
}
-#endif
-#ifdef CONFIG_PM_SLEEP
static void samsung_keypad_toggle_wakeup(struct samsung_keypad *keypad,
bool enable)
{
@@ -563,12 +560,11 @@ static int samsung_keypad_resume(struct device *dev)
return 0;
}
-#endif
static const struct dev_pm_ops samsung_keypad_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(samsung_keypad_suspend, samsung_keypad_resume)
- SET_RUNTIME_PM_OPS(samsung_keypad_runtime_suspend,
- samsung_keypad_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(samsung_keypad_suspend, samsung_keypad_resume)
+ RUNTIME_PM_OPS(samsung_keypad_runtime_suspend,
+ samsung_keypad_runtime_resume, NULL)
};
#ifdef CONFIG_OF
@@ -598,7 +594,7 @@ static struct platform_driver samsung_keypad_driver = {
.driver = {
.name = "samsung-keypad",
.of_match_table = of_match_ptr(samsung_keypad_dt_match),
- .pm = &samsung_keypad_pm_ops,
+ .pm = pm_ptr(&samsung_keypad_pm_ops),
},
.id_table = samsung_keypad_driver_ids,
};
diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c
index 4bb7c533147c..a50fa9915381 100644
--- a/drivers/input/keyboard/spear-keyboard.c
+++ b/drivers/input/keyboard/spear-keyboard.c
@@ -186,7 +186,6 @@ static int spear_kbd_probe(struct platform_device *pdev)
const struct matrix_keymap_data *keymap = pdata ? pdata->keymap : NULL;
struct spear_kbd *kbd;
struct input_dev *input_dev;
- struct resource *res;
int irq;
int error;
@@ -219,8 +218,7 @@ static int spear_kbd_probe(struct platform_device *pdev)
kbd->suspended_rate = pdata->suspended_rate;
}
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- kbd->io_base = devm_ioremap_resource(&pdev->dev, res);
+ kbd->io_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(kbd->io_base))
return PTR_ERR(kbd->io_base);
diff --git a/drivers/input/keyboard/st-keyscan.c b/drivers/input/keyboard/st-keyscan.c
index 13735a5e8391..b6e83324f97a 100644
--- a/drivers/input/keyboard/st-keyscan.c
+++ b/drivers/input/keyboard/st-keyscan.c
@@ -125,7 +125,6 @@ static int keyscan_probe(struct platform_device *pdev)
{
struct st_keyscan *keypad_data;
struct input_dev *input_dev;
- struct resource *res;
int error;
if (!pdev->dev.of_node) {
@@ -169,8 +168,7 @@ static int keyscan_probe(struct platform_device *pdev)
input_set_drvdata(input_dev, keypad_data);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- keypad_data->base = devm_ioremap_resource(&pdev->dev, res);
+ keypad_data->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(keypad_data->base))
return PTR_ERR(keypad_data->base);
diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c
index 1eba06bcf27a..da4019cf0c83 100644
--- a/drivers/input/keyboard/tegra-kbc.c
+++ b/drivers/input/keyboard/tegra-kbc.c
@@ -598,7 +598,6 @@ MODULE_DEVICE_TABLE(of, tegra_kbc_of_match);
static int tegra_kbc_probe(struct platform_device *pdev)
{
struct tegra_kbc *kbc;
- struct resource *res;
int err;
int num_rows = 0;
unsigned int debounce_cnt;
@@ -642,8 +641,7 @@ static int tegra_kbc_probe(struct platform_device *pdev)
timer_setup(&kbc->timer, tegra_kbc_keypress_timer, 0);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- kbc->mmio = devm_ioremap_resource(&pdev->dev, res);
+ kbc->mmio = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(kbc->mmio))
return PTR_ERR(kbc->mmio);
diff --git a/drivers/input/misc/88pm860x_onkey.c b/drivers/input/misc/88pm860x_onkey.c
index 685995cad73f..0f8b7ffb3aff 100644
--- a/drivers/input/misc/88pm860x_onkey.c
+++ b/drivers/input/misc/88pm860x_onkey.c
@@ -110,7 +110,7 @@ static int pm860x_onkey_probe(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused pm860x_onkey_suspend(struct device *dev)
+static int pm860x_onkey_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
@@ -119,7 +119,7 @@ static int __maybe_unused pm860x_onkey_suspend(struct device *dev)
chip->wakeup_flag |= 1 << PM8607_IRQ_ONKEY;
return 0;
}
-static int __maybe_unused pm860x_onkey_resume(struct device *dev)
+static int pm860x_onkey_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
@@ -129,12 +129,13 @@ static int __maybe_unused pm860x_onkey_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(pm860x_onkey_pm_ops, pm860x_onkey_suspend, pm860x_onkey_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(pm860x_onkey_pm_ops,
+ pm860x_onkey_suspend, pm860x_onkey_resume);
static struct platform_driver pm860x_onkey_driver = {
.driver = {
.name = "88pm860x-onkey",
- .pm = &pm860x_onkey_pm_ops,
+ .pm = pm_sleep_ptr(&pm860x_onkey_pm_ops),
},
.probe = pm860x_onkey_probe,
};
diff --git a/drivers/input/misc/ad714x-i2c.c b/drivers/input/misc/ad714x-i2c.c
index 5ef518a50e63..d8e39f4a57ac 100644
--- a/drivers/input/misc/ad714x-i2c.c
+++ b/drivers/input/misc/ad714x-i2c.c
@@ -12,18 +12,6 @@
#include <linux/pm.h>
#include "ad714x.h"
-static int __maybe_unused ad714x_i2c_suspend(struct device *dev)
-{
- return ad714x_disable(i2c_get_clientdata(to_i2c_client(dev)));
-}
-
-static int __maybe_unused ad714x_i2c_resume(struct device *dev)
-{
- return ad714x_enable(i2c_get_clientdata(to_i2c_client(dev)));
-}
-
-static SIMPLE_DEV_PM_OPS(ad714x_i2c_pm, ad714x_i2c_suspend, ad714x_i2c_resume);
-
static int ad714x_i2c_write(struct ad714x_chip *chip,
unsigned short reg, unsigned short data)
{
@@ -96,7 +84,7 @@ MODULE_DEVICE_TABLE(i2c, ad714x_id);
static struct i2c_driver ad714x_i2c_driver = {
.driver = {
.name = "ad714x_captouch",
- .pm = &ad714x_i2c_pm,
+ .pm = pm_sleep_ptr(&ad714x_pm),
},
.probe_new = ad714x_i2c_probe,
.id_table = ad714x_id,
diff --git a/drivers/input/misc/ad714x-spi.c b/drivers/input/misc/ad714x-spi.c
index 7d3bf434620f..eb13b4cd6594 100644
--- a/drivers/input/misc/ad714x-spi.c
+++ b/drivers/input/misc/ad714x-spi.c
@@ -15,18 +15,6 @@
#define AD714x_SPI_CMD_PREFIX 0xE000 /* bits 15:11 */
#define AD714x_SPI_READ BIT(10)
-static int __maybe_unused ad714x_spi_suspend(struct device *dev)
-{
- return ad714x_disable(spi_get_drvdata(to_spi_device(dev)));
-}
-
-static int __maybe_unused ad714x_spi_resume(struct device *dev)
-{
- return ad714x_enable(spi_get_drvdata(to_spi_device(dev)));
-}
-
-static SIMPLE_DEV_PM_OPS(ad714x_spi_pm, ad714x_spi_suspend, ad714x_spi_resume);
-
static int ad714x_spi_read(struct ad714x_chip *chip,
unsigned short reg, unsigned short *data, size_t len)
{
@@ -103,7 +91,7 @@ static int ad714x_spi_probe(struct spi_device *spi)
static struct spi_driver ad714x_spi_driver = {
.driver = {
.name = "ad714x_captouch",
- .pm = &ad714x_spi_pm,
+ .pm = pm_sleep_ptr(&ad714x_pm),
},
.probe = ad714x_spi_probe,
};
diff --git a/drivers/input/misc/ad714x.c b/drivers/input/misc/ad714x.c
index 43132d98feda..1acd8429c56c 100644
--- a/drivers/input/misc/ad714x.c
+++ b/drivers/input/misc/ad714x.c
@@ -1162,9 +1162,9 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
}
EXPORT_SYMBOL(ad714x_probe);
-#ifdef CONFIG_PM
-int ad714x_disable(struct ad714x_chip *ad714x)
+static int ad714x_suspend(struct device *dev)
{
+ struct ad714x_chip *ad714x = dev_get_drvdata(dev);
unsigned short data;
dev_dbg(ad714x->dev, "%s enter\n", __func__);
@@ -1178,10 +1178,10 @@ int ad714x_disable(struct ad714x_chip *ad714x)
return 0;
}
-EXPORT_SYMBOL(ad714x_disable);
-int ad714x_enable(struct ad714x_chip *ad714x)
+static int ad714x_resume(struct device *dev)
{
+ struct ad714x_chip *ad714x = dev_get_drvdata(dev);
dev_dbg(ad714x->dev, "%s enter\n", __func__);
mutex_lock(&ad714x->mutex);
@@ -1201,8 +1201,8 @@ int ad714x_enable(struct ad714x_chip *ad714x)
return 0;
}
-EXPORT_SYMBOL(ad714x_enable);
-#endif
+
+EXPORT_SIMPLE_DEV_PM_OPS(ad714x_pm, ad714x_suspend, ad714x_resume);
MODULE_DESCRIPTION("Analog Devices AD714X Capacitance Touch Sensor Driver");
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
diff --git a/drivers/input/misc/ad714x.h b/drivers/input/misc/ad714x.h
index af847b5f0d0e..dafa12325f27 100644
--- a/drivers/input/misc/ad714x.h
+++ b/drivers/input/misc/ad714x.h
@@ -8,6 +8,7 @@
#ifndef _AD714X_H_
#define _AD714X_H_
+#include <linux/pm.h>
#include <linux/types.h>
#define STAGE_NUM 12
@@ -45,8 +46,7 @@ struct ad714x_chip {
};
-int ad714x_disable(struct ad714x_chip *ad714x);
-int ad714x_enable(struct ad714x_chip *ad714x);
+extern const struct dev_pm_ops ad714x_pm;
struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
ad714x_read_t read, ad714x_write_t write);
diff --git a/drivers/input/misc/adxl34x-i2c.c b/drivers/input/misc/adxl34x-i2c.c
index a8ceea36d80a..1c75d98c85a7 100644
--- a/drivers/input/misc/adxl34x-i2c.c
+++ b/drivers/input/misc/adxl34x-i2c.c
@@ -105,29 +105,6 @@ static void adxl34x_i2c_remove(struct i2c_client *client)
adxl34x_remove(ac);
}
-static int __maybe_unused adxl34x_i2c_suspend(struct device *dev)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct adxl34x *ac = i2c_get_clientdata(client);
-
- adxl34x_suspend(ac);
-
- return 0;
-}
-
-static int __maybe_unused adxl34x_i2c_resume(struct device *dev)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct adxl34x *ac = i2c_get_clientdata(client);
-
- adxl34x_resume(ac);
-
- return 0;
-}
-
-static SIMPLE_DEV_PM_OPS(adxl34x_i2c_pm, adxl34x_i2c_suspend,
- adxl34x_i2c_resume);
-
static const struct i2c_device_id adxl34x_id[] = {
{ "adxl34x", 0 },
{ }
@@ -155,7 +132,7 @@ MODULE_DEVICE_TABLE(of, adxl34x_of_id);
static struct i2c_driver adxl34x_driver = {
.driver = {
.name = "adxl34x",
- .pm = &adxl34x_i2c_pm,
+ .pm = pm_sleep_ptr(&adxl34x_pm),
.of_match_table = adxl34x_of_id,
},
.probe_new = adxl34x_i2c_probe,
diff --git a/drivers/input/misc/adxl34x-spi.c b/drivers/input/misc/adxl34x-spi.c
index 91e44d4c66f7..f1094a8ccdd5 100644
--- a/drivers/input/misc/adxl34x-spi.c
+++ b/drivers/input/misc/adxl34x-spi.c
@@ -94,33 +94,10 @@ static void adxl34x_spi_remove(struct spi_device *spi)
adxl34x_remove(ac);
}
-static int __maybe_unused adxl34x_spi_suspend(struct device *dev)
-{
- struct spi_device *spi = to_spi_device(dev);
- struct adxl34x *ac = spi_get_drvdata(spi);
-
- adxl34x_suspend(ac);
-
- return 0;
-}
-
-static int __maybe_unused adxl34x_spi_resume(struct device *dev)
-{
- struct spi_device *spi = to_spi_device(dev);
- struct adxl34x *ac = spi_get_drvdata(spi);
-
- adxl34x_resume(ac);
-
- return 0;
-}
-
-static SIMPLE_DEV_PM_OPS(adxl34x_spi_pm, adxl34x_spi_suspend,
- adxl34x_spi_resume);
-
static struct spi_driver adxl34x_driver = {
.driver = {
.name = "adxl34x",
- .pm = &adxl34x_spi_pm,
+ .pm = pm_sleep_ptr(&adxl34x_pm),
},
.probe = adxl34x_spi_probe,
.remove = adxl34x_spi_remove,
diff --git a/drivers/input/misc/adxl34x.c b/drivers/input/misc/adxl34x.c
index a4af314392a9..eecca671b588 100644
--- a/drivers/input/misc/adxl34x.c
+++ b/drivers/input/misc/adxl34x.c
@@ -412,8 +412,10 @@ static void __adxl34x_enable(struct adxl34x *ac)
AC_WRITE(ac, POWER_CTL, ac->pdata.power_mode | PCTL_MEASURE);
}
-void adxl34x_suspend(struct adxl34x *ac)
+static int adxl34x_suspend(struct device *dev)
{
+ struct adxl34x *ac = dev_get_drvdata(dev);
+
mutex_lock(&ac->mutex);
if (!ac->suspended && !ac->disabled && ac->opened)
@@ -422,11 +424,14 @@ void adxl34x_suspend(struct adxl34x *ac)
ac->suspended = true;
mutex_unlock(&ac->mutex);
+
+ return 0;
}
-EXPORT_SYMBOL_GPL(adxl34x_suspend);
-void adxl34x_resume(struct adxl34x *ac)
+static int adxl34x_resume(struct device *dev)
{
+ struct adxl34x *ac = dev_get_drvdata(dev);
+
mutex_lock(&ac->mutex);
if (ac->suspended && !ac->disabled && ac->opened)
@@ -435,8 +440,9 @@ void adxl34x_resume(struct adxl34x *ac)
ac->suspended = false;
mutex_unlock(&ac->mutex);
+
+ return 0;
}
-EXPORT_SYMBOL_GPL(adxl34x_resume);
static ssize_t adxl34x_disable_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -906,6 +912,8 @@ void adxl34x_remove(struct adxl34x *ac)
}
EXPORT_SYMBOL_GPL(adxl34x_remove);
+EXPORT_GPL_SIMPLE_DEV_PM_OPS(adxl34x_pm, adxl34x_suspend, adxl34x_resume);
+
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("ADXL345/346 Three-Axis Digital Accelerometer Driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/adxl34x.h b/drivers/input/misc/adxl34x.h
index febf85270fff..f9272a2e7a96 100644
--- a/drivers/input/misc/adxl34x.h
+++ b/drivers/input/misc/adxl34x.h
@@ -20,11 +20,11 @@ struct adxl34x_bus_ops {
int (*write)(struct device *, unsigned char, unsigned char);
};
-void adxl34x_suspend(struct adxl34x *ac);
-void adxl34x_resume(struct adxl34x *ac);
struct adxl34x *adxl34x_probe(struct device *dev, int irq,
bool fifo_delay_default,
const struct adxl34x_bus_ops *bops);
void adxl34x_remove(struct adxl34x *ac);
+extern const struct dev_pm_ops adxl34x_pm;
+
#endif
diff --git a/drivers/input/misc/axp20x-pek.c b/drivers/input/misc/axp20x-pek.c
index 04da7916eb70..4581606a28d6 100644
--- a/drivers/input/misc/axp20x-pek.c
+++ b/drivers/input/misc/axp20x-pek.c
@@ -336,7 +336,7 @@ static int axp20x_pek_probe(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused axp20x_pek_suspend(struct device *dev)
+static int axp20x_pek_suspend(struct device *dev)
{
struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev);
@@ -355,7 +355,7 @@ static int __maybe_unused axp20x_pek_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused axp20x_pek_resume(struct device *dev)
+static int axp20x_pek_resume(struct device *dev)
{
struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev);
@@ -389,10 +389,8 @@ static int __maybe_unused axp20x_pek_resume_noirq(struct device *dev)
}
static const struct dev_pm_ops axp20x_pek_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(axp20x_pek_suspend, axp20x_pek_resume)
-#ifdef CONFIG_PM_SLEEP
- .resume_noirq = axp20x_pek_resume_noirq,
-#endif
+ SYSTEM_SLEEP_PM_OPS(axp20x_pek_suspend, axp20x_pek_resume)
+ .resume_noirq = pm_sleep_ptr(axp20x_pek_resume_noirq),
};
static const struct platform_device_id axp_pek_id_match[] = {
@@ -413,7 +411,7 @@ static struct platform_driver axp20x_pek_driver = {
.id_table = axp_pek_id_match,
.driver = {
.name = "axp20x-pek",
- .pm = &axp20x_pek_pm_ops,
+ .pm = pm_sleep_ptr(&axp20x_pek_pm_ops),
.dev_groups = axp20x_groups,
},
};
diff --git a/drivers/input/misc/cma3000_d0x_i2c.c b/drivers/input/misc/cma3000_d0x_i2c.c
index 75442c1230b1..136eb3715870 100644
--- a/drivers/input/misc/cma3000_d0x_i2c.c
+++ b/drivers/input/misc/cma3000_d0x_i2c.c
@@ -64,7 +64,6 @@ static void cma3000_i2c_remove(struct i2c_client *client)
cma3000_exit(data);
}
-#ifdef CONFIG_PM
static int cma3000_i2c_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -89,7 +88,6 @@ static const struct dev_pm_ops cma3000_i2c_pm_ops = {
.suspend = cma3000_i2c_suspend,
.resume = cma3000_i2c_resume,
};
-#endif
static const struct i2c_device_id cma3000_i2c_id[] = {
{ "cma3000_d01", 0 },
@@ -104,9 +102,7 @@ static struct i2c_driver cma3000_i2c_driver = {
.id_table = cma3000_i2c_id,
.driver = {
.name = "cma3000_i2c_accl",
-#ifdef CONFIG_PM
- .pm = &cma3000_i2c_pm_ops,
-#endif
+ .pm = pm_sleep_ptr(&cma3000_i2c_pm_ops),
},
};
diff --git a/drivers/input/misc/da7280.c b/drivers/input/misc/da7280.c
index dcdea33b1a8f..b85a19e3554f 100644
--- a/drivers/input/misc/da7280.c
+++ b/drivers/input/misc/da7280.c
@@ -1260,7 +1260,7 @@ static int da7280_probe(struct i2c_client *client)
return 0;
}
-static int __maybe_unused da7280_suspend(struct device *dev)
+static int da7280_suspend(struct device *dev)
{
struct da7280_haptic *haptics = dev_get_drvdata(dev);
@@ -1281,7 +1281,7 @@ static int __maybe_unused da7280_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused da7280_resume(struct device *dev)
+static int da7280_resume(struct device *dev)
{
struct da7280_haptic *haptics = dev_get_drvdata(dev);
int retval;
@@ -1313,13 +1313,13 @@ static const struct i2c_device_id da7280_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, da7280_i2c_id);
-static SIMPLE_DEV_PM_OPS(da7280_pm_ops, da7280_suspend, da7280_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(da7280_pm_ops, da7280_suspend, da7280_resume);
static struct i2c_driver da7280_driver = {
.driver = {
.name = "da7280",
.of_match_table = of_match_ptr(da7280_of_match),
- .pm = &da7280_pm_ops,
+ .pm = pm_sleep_ptr(&da7280_pm_ops),
},
.probe_new = da7280_probe,
.id_table = da7280_i2c_id,
diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c
index 3a51ee5e935a..8a9ebfc04a2d 100644
--- a/drivers/input/misc/drv260x.c
+++ b/drivers/input/misc/drv260x.c
@@ -572,7 +572,7 @@ static int drv260x_probe(struct i2c_client *client)
return 0;
}
-static int __maybe_unused drv260x_suspend(struct device *dev)
+static int drv260x_suspend(struct device *dev)
{
struct drv260x_data *haptics = dev_get_drvdata(dev);
int ret = 0;
@@ -604,7 +604,7 @@ out:
return ret;
}
-static int __maybe_unused drv260x_resume(struct device *dev)
+static int drv260x_resume(struct device *dev)
{
struct drv260x_data *haptics = dev_get_drvdata(dev);
int ret = 0;
@@ -635,7 +635,7 @@ out:
return ret;
}
-static SIMPLE_DEV_PM_OPS(drv260x_pm_ops, drv260x_suspend, drv260x_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(drv260x_pm_ops, drv260x_suspend, drv260x_resume);
static const struct i2c_device_id drv260x_id[] = {
{ "drv2605l", 0 },
@@ -657,7 +657,7 @@ static struct i2c_driver drv260x_driver = {
.driver = {
.name = "drv260x-haptics",
.of_match_table = drv260x_of_match,
- .pm = &drv260x_pm_ops,
+ .pm = pm_sleep_ptr(&drv260x_pm_ops),
},
.id_table = drv260x_id,
};
diff --git a/drivers/input/misc/drv2665.c b/drivers/input/misc/drv2665.c
index c2a2ff980c06..9145096f80ea 100644
--- a/drivers/input/misc/drv2665.c
+++ b/drivers/input/misc/drv2665.c
@@ -222,7 +222,7 @@ static int drv2665_probe(struct i2c_client *client)
return 0;
}
-static int __maybe_unused drv2665_suspend(struct device *dev)
+static int drv2665_suspend(struct device *dev)
{
struct drv2665_data *haptics = dev_get_drvdata(dev);
int ret = 0;
@@ -251,7 +251,7 @@ out:
return ret;
}
-static int __maybe_unused drv2665_resume(struct device *dev)
+static int drv2665_resume(struct device *dev)
{
struct drv2665_data *haptics = dev_get_drvdata(dev);
int ret = 0;
@@ -280,7 +280,7 @@ out:
return ret;
}
-static SIMPLE_DEV_PM_OPS(drv2665_pm_ops, drv2665_suspend, drv2665_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(drv2665_pm_ops, drv2665_suspend, drv2665_resume);
static const struct i2c_device_id drv2665_id[] = {
{ "drv2665", 0 },
@@ -301,7 +301,7 @@ static struct i2c_driver drv2665_driver = {
.driver = {
.name = "drv2665-haptics",
.of_match_table = of_match_ptr(drv2665_of_match),
- .pm = &drv2665_pm_ops,
+ .pm = pm_sleep_ptr(&drv2665_pm_ops),
},
.id_table = drv2665_id,
};
diff --git a/drivers/input/misc/drv2667.c b/drivers/input/misc/drv2667.c
index da7ac63dce4c..88b4dbe3e5b5 100644
--- a/drivers/input/misc/drv2667.c
+++ b/drivers/input/misc/drv2667.c
@@ -399,7 +399,7 @@ static int drv2667_probe(struct i2c_client *client)
return 0;
}
-static int __maybe_unused drv2667_suspend(struct device *dev)
+static int drv2667_suspend(struct device *dev)
{
struct drv2667_data *haptics = dev_get_drvdata(dev);
int ret = 0;
@@ -428,7 +428,7 @@ out:
return ret;
}
-static int __maybe_unused drv2667_resume(struct device *dev)
+static int drv2667_resume(struct device *dev)
{
struct drv2667_data *haptics = dev_get_drvdata(dev);
int ret = 0;
@@ -457,7 +457,7 @@ out:
return ret;
}
-static SIMPLE_DEV_PM_OPS(drv2667_pm_ops, drv2667_suspend, drv2667_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(drv2667_pm_ops, drv2667_suspend, drv2667_resume);
static const struct i2c_device_id drv2667_id[] = {
{ "drv2667", 0 },
@@ -478,7 +478,7 @@ static struct i2c_driver drv2667_driver = {
.driver = {
.name = "drv2667-haptics",
.of_match_table = of_match_ptr(drv2667_of_match),
- .pm = &drv2667_pm_ops,
+ .pm = pm_sleep_ptr(&drv2667_pm_ops),
},
.id_table = drv2667_id,
};
diff --git a/drivers/input/misc/e3x0-button.c b/drivers/input/misc/e3x0-button.c
index e2fde6e1553f..5bd527117470 100644
--- a/drivers/input/misc/e3x0-button.c
+++ b/drivers/input/misc/e3x0-button.c
@@ -35,7 +35,7 @@ static irqreturn_t e3x0_button_press_handler(int irq, void *data)
return IRQ_HANDLED;
}
-static int __maybe_unused e3x0_button_suspend(struct device *dev)
+static int e3x0_button_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -45,7 +45,7 @@ static int __maybe_unused e3x0_button_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused e3x0_button_resume(struct device *dev)
+static int e3x0_button_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -55,8 +55,8 @@ static int __maybe_unused e3x0_button_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(e3x0_button_pm_ops,
- e3x0_button_suspend, e3x0_button_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(e3x0_button_pm_ops,
+ e3x0_button_suspend, e3x0_button_resume);
static int e3x0_button_probe(struct platform_device *pdev)
{
@@ -122,7 +122,7 @@ static struct platform_driver e3x0_button_driver = {
.driver = {
.name = "e3x0-button",
.of_match_table = of_match_ptr(e3x0_button_match),
- .pm = &e3x0_button_pm_ops,
+ .pm = pm_sleep_ptr(&e3x0_button_pm_ops),
},
.probe = e3x0_button_probe,
};
diff --git a/drivers/input/misc/gpio-vibra.c b/drivers/input/misc/gpio-vibra.c
index f79f75595dd7..134a1309ba92 100644
--- a/drivers/input/misc/gpio-vibra.c
+++ b/drivers/input/misc/gpio-vibra.c
@@ -157,7 +157,7 @@ static int gpio_vibrator_probe(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused gpio_vibrator_suspend(struct device *dev)
+static int gpio_vibrator_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct gpio_vibrator *vibrator = platform_get_drvdata(pdev);
@@ -169,7 +169,7 @@ static int __maybe_unused gpio_vibrator_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused gpio_vibrator_resume(struct device *dev)
+static int gpio_vibrator_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct gpio_vibrator *vibrator = platform_get_drvdata(pdev);
@@ -180,8 +180,8 @@ static int __maybe_unused gpio_vibrator_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(gpio_vibrator_pm_ops,
- gpio_vibrator_suspend, gpio_vibrator_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(gpio_vibrator_pm_ops,
+ gpio_vibrator_suspend, gpio_vibrator_resume);
#ifdef CONFIG_OF
static const struct of_device_id gpio_vibra_dt_match_table[] = {
@@ -195,7 +195,7 @@ static struct platform_driver gpio_vibrator_driver = {
.probe = gpio_vibrator_probe,
.driver = {
.name = "gpio-vibrator",
- .pm = &gpio_vibrator_pm_ops,
+ .pm = pm_sleep_ptr(&gpio_vibrator_pm_ops),
.of_match_table = of_match_ptr(gpio_vibra_dt_match_table),
},
};
diff --git a/drivers/input/misc/iqs269a.c b/drivers/input/misc/iqs269a.c
index a348247d3d38..f4c3aff3895b 100644
--- a/drivers/input/misc/iqs269a.c
+++ b/drivers/input/misc/iqs269a.c
@@ -9,6 +9,7 @@
* axial sliders presented by the device.
*/
+#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/err.h>
@@ -96,8 +97,6 @@
#define IQS269_MISC_B_TRACKING_UI_ENABLE BIT(4)
#define IQS269_MISC_B_FILT_STR_SLIDER GENMASK(1, 0)
-#define IQS269_CHx_SETTINGS 0x8C
-
#define IQS269_CHx_ENG_A_MEAS_CAP_SIZE BIT(15)
#define IQS269_CHx_ENG_A_RX_GND_INACTIVE BIT(13)
#define IQS269_CHx_ENG_A_LOCAL_CAP_SIZE BIT(12)
@@ -146,14 +145,7 @@
#define IQS269_NUM_CH 8
#define IQS269_NUM_SL 2
-#define IQS269_ATI_POLL_SLEEP_US (iqs269->delay_mult * 10000)
-#define IQS269_ATI_POLL_TIMEOUT_US (iqs269->delay_mult * 500000)
-#define IQS269_ATI_STABLE_DELAY_MS (iqs269->delay_mult * 150)
-
-#define IQS269_PWR_MODE_POLL_SLEEP_US IQS269_ATI_POLL_SLEEP_US
-#define IQS269_PWR_MODE_POLL_TIMEOUT_US IQS269_ATI_POLL_TIMEOUT_US
-
-#define iqs269_irq_wait() usleep_range(100, 150)
+#define iqs269_irq_wait() usleep_range(200, 250)
enum iqs269_local_cap_size {
IQS269_LOCAL_CAP_SIZE_0,
@@ -245,6 +237,18 @@ struct iqs269_ver_info {
u8 padding;
} __packed;
+struct iqs269_ch_reg {
+ u8 rx_enable;
+ u8 tx_enable;
+ __be16 engine_a;
+ __be16 engine_b;
+ __be16 ati_comp;
+ u8 thresh[3];
+ u8 hyst;
+ u8 assoc_select;
+ u8 assoc_weight;
+} __packed;
+
struct iqs269_sys_reg {
__be16 general;
u8 active;
@@ -266,18 +270,7 @@ struct iqs269_sys_reg {
u8 timeout_swipe;
u8 thresh_swipe;
u8 redo_ati;
-} __packed;
-
-struct iqs269_ch_reg {
- u8 rx_enable;
- u8 tx_enable;
- __be16 engine_a;
- __be16 engine_b;
- __be16 ati_comp;
- u8 thresh[3];
- u8 hyst;
- u8 assoc_select;
- u8 assoc_weight;
+ struct iqs269_ch_reg ch_reg[IQS269_NUM_CH];
} __packed;
struct iqs269_flags {
@@ -292,13 +285,11 @@ struct iqs269_private {
struct regmap *regmap;
struct mutex lock;
struct iqs269_switch_desc switches[ARRAY_SIZE(iqs269_events)];
- struct iqs269_ch_reg ch_reg[IQS269_NUM_CH];
struct iqs269_sys_reg sys_reg;
+ struct completion ati_done;
struct input_dev *keypad;
struct input_dev *slider[IQS269_NUM_SL];
unsigned int keycode[ARRAY_SIZE(iqs269_events) * IQS269_NUM_CH];
- unsigned int suspend_mode;
- unsigned int delay_mult;
unsigned int ch_num;
bool hall_enable;
bool ati_current;
@@ -307,6 +298,7 @@ struct iqs269_private {
static int iqs269_ati_mode_set(struct iqs269_private *iqs269,
unsigned int ch_num, unsigned int mode)
{
+ struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg;
u16 engine_a;
if (ch_num >= IQS269_NUM_CH)
@@ -317,12 +309,12 @@ static int iqs269_ati_mode_set(struct iqs269_private *iqs269,
mutex_lock(&iqs269->lock);
- engine_a = be16_to_cpu(iqs269->ch_reg[ch_num].engine_a);
+ engine_a = be16_to_cpu(ch_reg[ch_num].engine_a);
engine_a &= ~IQS269_CHx_ENG_A_ATI_MODE_MASK;
engine_a |= (mode << IQS269_CHx_ENG_A_ATI_MODE_SHIFT);
- iqs269->ch_reg[ch_num].engine_a = cpu_to_be16(engine_a);
+ ch_reg[ch_num].engine_a = cpu_to_be16(engine_a);
iqs269->ati_current = false;
mutex_unlock(&iqs269->lock);
@@ -333,13 +325,14 @@ static int iqs269_ati_mode_set(struct iqs269_private *iqs269,
static int iqs269_ati_mode_get(struct iqs269_private *iqs269,
unsigned int ch_num, unsigned int *mode)
{
+ struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg;
u16 engine_a;
if (ch_num >= IQS269_NUM_CH)
return -EINVAL;
mutex_lock(&iqs269->lock);
- engine_a = be16_to_cpu(iqs269->ch_reg[ch_num].engine_a);
+ engine_a = be16_to_cpu(ch_reg[ch_num].engine_a);
mutex_unlock(&iqs269->lock);
engine_a &= IQS269_CHx_ENG_A_ATI_MODE_MASK;
@@ -351,6 +344,7 @@ static int iqs269_ati_mode_get(struct iqs269_private *iqs269,
static int iqs269_ati_base_set(struct iqs269_private *iqs269,
unsigned int ch_num, unsigned int base)
{
+ struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg;
u16 engine_b;
if (ch_num >= IQS269_NUM_CH)
@@ -379,12 +373,12 @@ static int iqs269_ati_base_set(struct iqs269_private *iqs269,
mutex_lock(&iqs269->lock);
- engine_b = be16_to_cpu(iqs269->ch_reg[ch_num].engine_b);
+ engine_b = be16_to_cpu(ch_reg[ch_num].engine_b);
engine_b &= ~IQS269_CHx_ENG_B_ATI_BASE_MASK;
engine_b |= base;
- iqs269->ch_reg[ch_num].engine_b = cpu_to_be16(engine_b);
+ ch_reg[ch_num].engine_b = cpu_to_be16(engine_b);
iqs269->ati_current = false;
mutex_unlock(&iqs269->lock);
@@ -395,13 +389,14 @@ static int iqs269_ati_base_set(struct iqs269_private *iqs269,
static int iqs269_ati_base_get(struct iqs269_private *iqs269,
unsigned int ch_num, unsigned int *base)
{
+ struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg;
u16 engine_b;
if (ch_num >= IQS269_NUM_CH)
return -EINVAL;
mutex_lock(&iqs269->lock);
- engine_b = be16_to_cpu(iqs269->ch_reg[ch_num].engine_b);
+ engine_b = be16_to_cpu(ch_reg[ch_num].engine_b);
mutex_unlock(&iqs269->lock);
switch (engine_b & IQS269_CHx_ENG_B_ATI_BASE_MASK) {
@@ -429,6 +424,7 @@ static int iqs269_ati_base_get(struct iqs269_private *iqs269,
static int iqs269_ati_target_set(struct iqs269_private *iqs269,
unsigned int ch_num, unsigned int target)
{
+ struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg;
u16 engine_b;
if (ch_num >= IQS269_NUM_CH)
@@ -439,12 +435,12 @@ static int iqs269_ati_target_set(struct iqs269_private *iqs269,
mutex_lock(&iqs269->lock);
- engine_b = be16_to_cpu(iqs269->ch_reg[ch_num].engine_b);
+ engine_b = be16_to_cpu(ch_reg[ch_num].engine_b);
engine_b &= ~IQS269_CHx_ENG_B_ATI_TARGET_MASK;
engine_b |= target / 32;
- iqs269->ch_reg[ch_num].engine_b = cpu_to_be16(engine_b);
+ ch_reg[ch_num].engine_b = cpu_to_be16(engine_b);
iqs269->ati_current = false;
mutex_unlock(&iqs269->lock);
@@ -455,13 +451,14 @@ static int iqs269_ati_target_set(struct iqs269_private *iqs269,
static int iqs269_ati_target_get(struct iqs269_private *iqs269,
unsigned int ch_num, unsigned int *target)
{
+ struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg;
u16 engine_b;
if (ch_num >= IQS269_NUM_CH)
return -EINVAL;
mutex_lock(&iqs269->lock);
- engine_b = be16_to_cpu(iqs269->ch_reg[ch_num].engine_b);
+ engine_b = be16_to_cpu(ch_reg[ch_num].engine_b);
mutex_unlock(&iqs269->lock);
*target = (engine_b & IQS269_CHx_ENG_B_ATI_TARGET_MASK) * 32;
@@ -531,13 +528,7 @@ static int iqs269_parse_chan(struct iqs269_private *iqs269,
if (fwnode_property_present(ch_node, "azoteq,slider1-select"))
iqs269->sys_reg.slider_select[1] |= BIT(reg);
- ch_reg = &iqs269->ch_reg[reg];
-
- error = regmap_raw_read(iqs269->regmap,
- IQS269_CHx_SETTINGS + reg * sizeof(*ch_reg) / 2,
- ch_reg, sizeof(*ch_reg));
- if (error)
- return error;
+ ch_reg = &iqs269->sys_reg.ch_reg[reg];
error = iqs269_parse_mask(ch_node, "azoteq,rx-enable",
&ch_reg->rx_enable);
@@ -694,6 +685,7 @@ static int iqs269_parse_chan(struct iqs269_private *iqs269,
dev_err(&client->dev,
"Invalid channel %u threshold: %u\n",
reg, val);
+ fwnode_handle_put(ev_node);
return -EINVAL;
}
@@ -707,6 +699,7 @@ static int iqs269_parse_chan(struct iqs269_private *iqs269,
dev_err(&client->dev,
"Invalid channel %u hysteresis: %u\n",
reg, val);
+ fwnode_handle_put(ev_node);
return -EINVAL;
}
@@ -721,8 +714,16 @@ static int iqs269_parse_chan(struct iqs269_private *iqs269,
}
}
- if (fwnode_property_read_u32(ev_node, "linux,code", &val))
+ error = fwnode_property_read_u32(ev_node, "linux,code", &val);
+ fwnode_handle_put(ev_node);
+ if (error == -EINVAL) {
continue;
+ } else if (error) {
+ dev_err(&client->dev,
+ "Failed to read channel %u code: %d\n", reg,
+ error);
+ return error;
+ }
switch (reg) {
case IQS269_CHx_HALL_ACTIVE:
@@ -759,17 +760,6 @@ static int iqs269_parse_prop(struct iqs269_private *iqs269)
iqs269->hall_enable = device_property_present(&client->dev,
"azoteq,hall-enable");
- if (!device_property_read_u32(&client->dev, "azoteq,suspend-mode",
- &val)) {
- if (val > IQS269_SYS_SETTINGS_PWR_MODE_MAX) {
- dev_err(&client->dev, "Invalid suspend mode: %u\n",
- val);
- return -EINVAL;
- }
-
- iqs269->suspend_mode = val;
- }
-
error = regmap_raw_read(iqs269->regmap, IQS269_SYS_SETTINGS, sys_reg,
sizeof(*sys_reg));
if (error)
@@ -980,13 +970,8 @@ static int iqs269_parse_prop(struct iqs269_private *iqs269)
general = be16_to_cpu(sys_reg->general);
- if (device_property_present(&client->dev, "azoteq,clk-div")) {
+ if (device_property_present(&client->dev, "azoteq,clk-div"))
general |= IQS269_SYS_SETTINGS_CLK_DIV;
- iqs269->delay_mult = 4;
- } else {
- general &= ~IQS269_SYS_SETTINGS_CLK_DIV;
- iqs269->delay_mult = 1;
- }
/*
* Configure the device to automatically switch between normal and low-
@@ -997,6 +982,17 @@ static int iqs269_parse_prop(struct iqs269_private *iqs269)
general &= ~IQS269_SYS_SETTINGS_DIS_AUTO;
general &= ~IQS269_SYS_SETTINGS_PWR_MODE_MASK;
+ if (!device_property_read_u32(&client->dev, "azoteq,suspend-mode",
+ &val)) {
+ if (val > IQS269_SYS_SETTINGS_PWR_MODE_MAX) {
+ dev_err(&client->dev, "Invalid suspend mode: %u\n",
+ val);
+ return -EINVAL;
+ }
+
+ general |= (val << IQS269_SYS_SETTINGS_PWR_MODE_SHIFT);
+ }
+
if (!device_property_read_u32(&client->dev, "azoteq,ulp-update",
&val)) {
if (val > IQS269_SYS_SETTINGS_ULP_UPDATE_MAX) {
@@ -1032,10 +1028,7 @@ static int iqs269_parse_prop(struct iqs269_private *iqs269)
static int iqs269_dev_init(struct iqs269_private *iqs269)
{
- struct iqs269_sys_reg *sys_reg = &iqs269->sys_reg;
- struct iqs269_ch_reg *ch_reg;
- unsigned int val;
- int error, i;
+ int error;
mutex_lock(&iqs269->lock);
@@ -1045,38 +1038,17 @@ static int iqs269_dev_init(struct iqs269_private *iqs269)
if (error)
goto err_mutex;
- for (i = 0; i < IQS269_NUM_CH; i++) {
- if (!(sys_reg->active & BIT(i)))
- continue;
-
- ch_reg = &iqs269->ch_reg[i];
-
- error = regmap_raw_write(iqs269->regmap,
- IQS269_CHx_SETTINGS + i *
- sizeof(*ch_reg) / 2, ch_reg,
- sizeof(*ch_reg));
- if (error)
- goto err_mutex;
- }
-
- /*
- * The REDO-ATI and ATI channel selection fields must be written in the
- * same block write, so every field between registers 0x80 through 0x8B
- * (inclusive) must be written as well.
- */
- error = regmap_raw_write(iqs269->regmap, IQS269_SYS_SETTINGS, sys_reg,
- sizeof(*sys_reg));
+ error = regmap_raw_write(iqs269->regmap, IQS269_SYS_SETTINGS,
+ &iqs269->sys_reg, sizeof(iqs269->sys_reg));
if (error)
goto err_mutex;
- error = regmap_read_poll_timeout(iqs269->regmap, IQS269_SYS_FLAGS, val,
- !(val & IQS269_SYS_FLAGS_IN_ATI),
- IQS269_ATI_POLL_SLEEP_US,
- IQS269_ATI_POLL_TIMEOUT_US);
- if (error)
- goto err_mutex;
+ /*
+ * The following delay gives the device time to deassert its RDY output
+ * so as to prevent an interrupt from being serviced prematurely.
+ */
+ usleep_range(2000, 2100);
- msleep(IQS269_ATI_STABLE_DELAY_MS);
iqs269->ati_current = true;
err_mutex:
@@ -1088,10 +1060,8 @@ err_mutex:
static int iqs269_input_init(struct iqs269_private *iqs269)
{
struct i2c_client *client = iqs269->client;
- struct iqs269_flags flags;
unsigned int sw_code, keycode;
int error, i, j;
- u8 dir_mask, state;
iqs269->keypad = devm_input_allocate_device(&client->dev);
if (!iqs269->keypad)
@@ -1104,23 +1074,7 @@ static int iqs269_input_init(struct iqs269_private *iqs269)
iqs269->keypad->name = "iqs269a_keypad";
iqs269->keypad->id.bustype = BUS_I2C;
- if (iqs269->hall_enable) {
- error = regmap_raw_read(iqs269->regmap, IQS269_SYS_FLAGS,
- &flags, sizeof(flags));
- if (error) {
- dev_err(&client->dev,
- "Failed to read initial status: %d\n", error);
- return error;
- }
- }
-
for (i = 0; i < ARRAY_SIZE(iqs269_events); i++) {
- dir_mask = flags.states[IQS269_ST_OFFS_DIR];
- if (!iqs269_events[i].dir_up)
- dir_mask = ~dir_mask;
-
- state = flags.states[iqs269_events[i].st_offs] & dir_mask;
-
sw_code = iqs269->switches[i].code;
for (j = 0; j < IQS269_NUM_CH; j++) {
@@ -1133,13 +1087,9 @@ static int iqs269_input_init(struct iqs269_private *iqs269)
switch (j) {
case IQS269_CHx_HALL_ACTIVE:
if (iqs269->hall_enable &&
- iqs269->switches[i].enabled) {
+ iqs269->switches[i].enabled)
input_set_capability(iqs269->keypad,
EV_SW, sw_code);
- input_report_switch(iqs269->keypad,
- sw_code,
- state & BIT(j));
- }
fallthrough;
case IQS269_CHx_HALL_INACTIVE:
@@ -1155,14 +1105,6 @@ static int iqs269_input_init(struct iqs269_private *iqs269)
}
}
- input_sync(iqs269->keypad);
-
- error = input_register_device(iqs269->keypad);
- if (error) {
- dev_err(&client->dev, "Failed to register keypad: %d\n", error);
- return error;
- }
-
for (i = 0; i < IQS269_NUM_SL; i++) {
if (!iqs269->sys_reg.slider_select[i])
continue;
@@ -1222,6 +1164,9 @@ static int iqs269_report(struct iqs269_private *iqs269)
return error;
}
+ if (be16_to_cpu(flags.system) & IQS269_SYS_FLAGS_IN_ATI)
+ return 0;
+
error = regmap_raw_read(iqs269->regmap, IQS269_SLIDER_X, slider_x,
sizeof(slider_x));
if (error) {
@@ -1284,6 +1229,12 @@ static int iqs269_report(struct iqs269_private *iqs269)
input_sync(iqs269->keypad);
+ /*
+ * The following completion signals that ATI has finished, any initial
+ * switch states have been reported and the keypad can be registered.
+ */
+ complete_all(&iqs269->ati_done);
+
return 0;
}
@@ -1315,6 +1266,9 @@ static ssize_t counts_show(struct device *dev,
if (!iqs269->ati_current || iqs269->hall_enable)
return -EPERM;
+ if (!completion_done(&iqs269->ati_done))
+ return -EBUSY;
+
/*
* Unsolicited I2C communication prompts the device to assert its RDY
* pin, so disable the interrupt line until the operation is finished
@@ -1339,6 +1293,7 @@ static ssize_t hall_bin_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct iqs269_private *iqs269 = dev_get_drvdata(dev);
+ struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg;
struct i2c_client *client = iqs269->client;
unsigned int val;
int error;
@@ -1353,8 +1308,8 @@ static ssize_t hall_bin_show(struct device *dev,
if (error)
return error;
- switch (iqs269->ch_reg[IQS269_CHx_HALL_ACTIVE].rx_enable &
- iqs269->ch_reg[IQS269_CHx_HALL_INACTIVE].rx_enable) {
+ switch (ch_reg[IQS269_CHx_HALL_ACTIVE].rx_enable &
+ ch_reg[IQS269_CHx_HALL_INACTIVE].rx_enable) {
case IQS269_HALL_PAD_R:
val &= IQS269_CAL_DATA_A_HALL_BIN_R_MASK;
val >>= IQS269_CAL_DATA_A_HALL_BIN_R_SHIFT;
@@ -1434,9 +1389,10 @@ static ssize_t rx_enable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct iqs269_private *iqs269 = dev_get_drvdata(dev);
+ struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg;
return scnprintf(buf, PAGE_SIZE, "%u\n",
- iqs269->ch_reg[iqs269->ch_num].rx_enable);
+ ch_reg[iqs269->ch_num].rx_enable);
}
static ssize_t rx_enable_store(struct device *dev,
@@ -1444,6 +1400,7 @@ static ssize_t rx_enable_store(struct device *dev,
size_t count)
{
struct iqs269_private *iqs269 = dev_get_drvdata(dev);
+ struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg;
unsigned int val;
int error;
@@ -1456,7 +1413,7 @@ static ssize_t rx_enable_store(struct device *dev,
mutex_lock(&iqs269->lock);
- iqs269->ch_reg[iqs269->ch_num].rx_enable = val;
+ ch_reg[iqs269->ch_num].rx_enable = val;
iqs269->ati_current = false;
mutex_unlock(&iqs269->lock);
@@ -1568,7 +1525,9 @@ static ssize_t ati_trigger_show(struct device *dev,
{
struct iqs269_private *iqs269 = dev_get_drvdata(dev);
- return scnprintf(buf, PAGE_SIZE, "%u\n", iqs269->ati_current);
+ return scnprintf(buf, PAGE_SIZE, "%u\n",
+ iqs269->ati_current &&
+ completion_done(&iqs269->ati_done));
}
static ssize_t ati_trigger_store(struct device *dev,
@@ -1588,6 +1547,7 @@ static ssize_t ati_trigger_store(struct device *dev,
return count;
disable_irq(client->irq);
+ reinit_completion(&iqs269->ati_done);
error = iqs269_dev_init(iqs269);
@@ -1597,6 +1557,10 @@ static ssize_t ati_trigger_store(struct device *dev,
if (error)
return error;
+ if (!wait_for_completion_timeout(&iqs269->ati_done,
+ msecs_to_jiffies(2000)))
+ return -ETIMEDOUT;
+
return count;
}
@@ -1655,6 +1619,7 @@ static int iqs269_probe(struct i2c_client *client)
}
mutex_init(&iqs269->lock);
+ init_completion(&iqs269->ati_done);
error = regmap_raw_read(iqs269->regmap, IQS269_VER_INFO, &ver_info,
sizeof(ver_info));
@@ -1690,6 +1655,22 @@ static int iqs269_probe(struct i2c_client *client)
return error;
}
+ if (!wait_for_completion_timeout(&iqs269->ati_done,
+ msecs_to_jiffies(2000))) {
+ dev_err(&client->dev, "Failed to complete ATI\n");
+ return -ETIMEDOUT;
+ }
+
+ /*
+ * The keypad may include one or more switches and is not registered
+ * until ATI is complete and the initial switch states are read.
+ */
+ error = input_register_device(iqs269->keypad);
+ if (error) {
+ dev_err(&client->dev, "Failed to register keypad: %d\n", error);
+ return error;
+ }
+
error = devm_device_add_group(&client->dev, &iqs269_attr_group);
if (error)
dev_err(&client->dev, "Failed to add attributes: %d\n", error);
@@ -1697,113 +1678,61 @@ static int iqs269_probe(struct i2c_client *client)
return error;
}
-static int __maybe_unused iqs269_suspend(struct device *dev)
+static u16 iqs269_general_get(struct iqs269_private *iqs269)
+{
+ u16 general = be16_to_cpu(iqs269->sys_reg.general);
+
+ general &= ~IQS269_SYS_SETTINGS_REDO_ATI;
+ general &= ~IQS269_SYS_SETTINGS_ACK_RESET;
+
+ return general | IQS269_SYS_SETTINGS_DIS_AUTO;
+}
+
+static int iqs269_suspend(struct device *dev)
{
struct iqs269_private *iqs269 = dev_get_drvdata(dev);
struct i2c_client *client = iqs269->client;
- unsigned int val;
int error;
+ u16 general = iqs269_general_get(iqs269);
- if (!iqs269->suspend_mode)
+ if (!(general & IQS269_SYS_SETTINGS_PWR_MODE_MASK))
return 0;
disable_irq(client->irq);
- /*
- * Automatic power mode switching must be disabled before the device is
- * forced into any particular power mode. In this case, the device will
- * transition into normal-power mode.
- */
- error = regmap_update_bits(iqs269->regmap, IQS269_SYS_SETTINGS,
- IQS269_SYS_SETTINGS_DIS_AUTO, ~0);
- if (error)
- goto err_irq;
-
- /*
- * The following check ensures the device has completed its transition
- * into normal-power mode before a manual mode switch is performed.
- */
- error = regmap_read_poll_timeout(iqs269->regmap, IQS269_SYS_FLAGS, val,
- !(val & IQS269_SYS_FLAGS_PWR_MODE_MASK),
- IQS269_PWR_MODE_POLL_SLEEP_US,
- IQS269_PWR_MODE_POLL_TIMEOUT_US);
- if (error)
- goto err_irq;
-
- error = regmap_update_bits(iqs269->regmap, IQS269_SYS_SETTINGS,
- IQS269_SYS_SETTINGS_PWR_MODE_MASK,
- iqs269->suspend_mode <<
- IQS269_SYS_SETTINGS_PWR_MODE_SHIFT);
- if (error)
- goto err_irq;
+ error = regmap_write(iqs269->regmap, IQS269_SYS_SETTINGS, general);
- /*
- * This last check ensures the device has completed its transition into
- * the desired power mode to prevent any spurious interrupts from being
- * triggered after iqs269_suspend has already returned.
- */
- error = regmap_read_poll_timeout(iqs269->regmap, IQS269_SYS_FLAGS, val,
- (val & IQS269_SYS_FLAGS_PWR_MODE_MASK)
- == (iqs269->suspend_mode <<
- IQS269_SYS_FLAGS_PWR_MODE_SHIFT),
- IQS269_PWR_MODE_POLL_SLEEP_US,
- IQS269_PWR_MODE_POLL_TIMEOUT_US);
-
-err_irq:
iqs269_irq_wait();
enable_irq(client->irq);
return error;
}
-static int __maybe_unused iqs269_resume(struct device *dev)
+static int iqs269_resume(struct device *dev)
{
struct iqs269_private *iqs269 = dev_get_drvdata(dev);
struct i2c_client *client = iqs269->client;
- unsigned int val;
int error;
+ u16 general = iqs269_general_get(iqs269);
- if (!iqs269->suspend_mode)
+ if (!(general & IQS269_SYS_SETTINGS_PWR_MODE_MASK))
return 0;
disable_irq(client->irq);
- error = regmap_update_bits(iqs269->regmap, IQS269_SYS_SETTINGS,
- IQS269_SYS_SETTINGS_PWR_MODE_MASK, 0);
- if (error)
- goto err_irq;
-
- /*
- * This check ensures the device has returned to normal-power mode
- * before automatic power mode switching is re-enabled.
- */
- error = regmap_read_poll_timeout(iqs269->regmap, IQS269_SYS_FLAGS, val,
- !(val & IQS269_SYS_FLAGS_PWR_MODE_MASK),
- IQS269_PWR_MODE_POLL_SLEEP_US,
- IQS269_PWR_MODE_POLL_TIMEOUT_US);
- if (error)
- goto err_irq;
-
- error = regmap_update_bits(iqs269->regmap, IQS269_SYS_SETTINGS,
- IQS269_SYS_SETTINGS_DIS_AUTO, 0);
- if (error)
- goto err_irq;
-
- /*
- * This step reports any events that may have been "swallowed" as a
- * result of polling PWR_MODE (which automatically acknowledges any
- * pending interrupts).
- */
- error = iqs269_report(iqs269);
+ error = regmap_write(iqs269->regmap, IQS269_SYS_SETTINGS,
+ general & ~IQS269_SYS_SETTINGS_PWR_MODE_MASK);
+ if (!error)
+ error = regmap_write(iqs269->regmap, IQS269_SYS_SETTINGS,
+ general & ~IQS269_SYS_SETTINGS_DIS_AUTO);
-err_irq:
iqs269_irq_wait();
enable_irq(client->irq);
return error;
}
-static SIMPLE_DEV_PM_OPS(iqs269_pm, iqs269_suspend, iqs269_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(iqs269_pm, iqs269_suspend, iqs269_resume);
static const struct of_device_id iqs269_of_match[] = {
{ .compatible = "azoteq,iqs269a" },
@@ -1815,7 +1744,7 @@ static struct i2c_driver iqs269_i2c_driver = {
.driver = {
.name = "iqs269a",
.of_match_table = iqs269_of_match,
- .pm = &iqs269_pm,
+ .pm = pm_sleep_ptr(&iqs269_pm),
},
.probe_new = iqs269_probe,
};
diff --git a/drivers/input/misc/iqs626a.c b/drivers/input/misc/iqs626a.c
index 23b5dd9552dc..90f997a905b5 100644
--- a/drivers/input/misc/iqs626a.c
+++ b/drivers/input/misc/iqs626a.c
@@ -458,18 +458,15 @@ struct iqs626_private {
static noinline_for_stack int
iqs626_parse_events(struct iqs626_private *iqs626,
- const struct fwnode_handle *ch_node,
- enum iqs626_ch_id ch_id)
+ struct fwnode_handle *ch_node, enum iqs626_ch_id ch_id)
{
struct iqs626_sys_reg *sys_reg = &iqs626->sys_reg;
struct i2c_client *client = iqs626->client;
- const struct fwnode_handle *ev_node;
+ struct fwnode_handle *ev_node;
const char *ev_name;
u8 *thresh, *hyst;
- unsigned int thresh_tp[IQS626_NUM_CH_TP_3];
unsigned int val;
- int num_ch = iqs626_channels[ch_id].num_ch;
- int error, i, j;
+ int i;
switch (ch_id) {
case IQS626_CH_ULP_0:
@@ -509,7 +506,7 @@ iqs626_parse_events(struct iqs626_private *iqs626,
* Trackpad touch events are simply described under the
* trackpad child node.
*/
- ev_node = ch_node;
+ ev_node = fwnode_handle_get(ch_node);
} else {
ev_name = iqs626_events[i].name;
ev_node = fwnode_get_named_child_node(ch_node, ev_name);
@@ -533,6 +530,7 @@ iqs626_parse_events(struct iqs626_private *iqs626,
dev_err(&client->dev,
"Invalid input type: %u\n",
val);
+ fwnode_handle_put(ev_node);
return -EINVAL;
}
@@ -547,6 +545,7 @@ iqs626_parse_events(struct iqs626_private *iqs626,
dev_err(&client->dev,
"Invalid %s channel hysteresis: %u\n",
fwnode_get_name(ch_node), val);
+ fwnode_handle_put(ev_node);
return -EINVAL;
}
@@ -567,6 +566,7 @@ iqs626_parse_events(struct iqs626_private *iqs626,
dev_err(&client->dev,
"Invalid %s channel threshold: %u\n",
fwnode_get_name(ch_node), val);
+ fwnode_handle_put(ev_node);
return -EINVAL;
}
@@ -574,32 +574,9 @@ iqs626_parse_events(struct iqs626_private *iqs626,
*thresh = val;
else
*(thresh + iqs626_events[i].th_offs) = val;
-
- continue;
- }
-
- if (!fwnode_property_present(ev_node, "azoteq,thresh"))
- continue;
-
- error = fwnode_property_read_u32_array(ev_node, "azoteq,thresh",
- thresh_tp, num_ch);
- if (error) {
- dev_err(&client->dev,
- "Failed to read %s channel thresholds: %d\n",
- fwnode_get_name(ch_node), error);
- return error;
}
- for (j = 0; j < num_ch; j++) {
- if (thresh_tp[j] > IQS626_CHx_THRESH_MAX) {
- dev_err(&client->dev,
- "Invalid %s channel threshold: %u\n",
- fwnode_get_name(ch_node), thresh_tp[j]);
- return -EINVAL;
- }
-
- sys_reg->tp_grp_reg.ch_reg_tp[j].thresh = thresh_tp[j];
- }
+ fwnode_handle_put(ev_node);
}
return 0;
@@ -607,16 +584,13 @@ iqs626_parse_events(struct iqs626_private *iqs626,
static noinline_for_stack int
iqs626_parse_ati_target(struct iqs626_private *iqs626,
- const struct fwnode_handle *ch_node,
- enum iqs626_ch_id ch_id)
+ struct fwnode_handle *ch_node, enum iqs626_ch_id ch_id)
{
struct iqs626_sys_reg *sys_reg = &iqs626->sys_reg;
struct i2c_client *client = iqs626->client;
- unsigned int ati_base[IQS626_NUM_CH_TP_3];
unsigned int val;
u8 *ati_target;
- int num_ch = iqs626_channels[ch_id].num_ch;
- int error, i;
+ int i;
switch (ch_id) {
case IQS626_CH_ULP_0:
@@ -683,40 +657,13 @@ iqs626_parse_ati_target(struct iqs626_private *iqs626,
*ati_target &= ~IQS626_CHx_ATI_BASE_MASK;
*ati_target |= val;
-
- return 0;
- }
-
- if (!fwnode_property_present(ch_node, "azoteq,ati-base"))
- return 0;
-
- error = fwnode_property_read_u32_array(ch_node, "azoteq,ati-base",
- ati_base, num_ch);
- if (error) {
- dev_err(&client->dev,
- "Failed to read %s channel ATI bases: %d\n",
- fwnode_get_name(ch_node), error);
- return error;
- }
-
- for (i = 0; i < num_ch; i++) {
- if (ati_base[i] < IQS626_TPx_ATI_BASE_MIN ||
- ati_base[i] > IQS626_TPx_ATI_BASE_MAX) {
- dev_err(&client->dev,
- "Invalid %s channel ATI base: %u\n",
- fwnode_get_name(ch_node), ati_base[i]);
- return -EINVAL;
- }
-
- ati_base[i] -= IQS626_TPx_ATI_BASE_MIN;
- sys_reg->tp_grp_reg.ch_reg_tp[i].ati_base = ati_base[i];
}
return 0;
}
static int iqs626_parse_pins(struct iqs626_private *iqs626,
- const struct fwnode_handle *ch_node,
+ struct fwnode_handle *ch_node,
const char *propname, u8 *enable)
{
struct i2c_client *client = iqs626->client;
@@ -764,13 +711,14 @@ static int iqs626_parse_pins(struct iqs626_private *iqs626,
}
static int iqs626_parse_trackpad(struct iqs626_private *iqs626,
- const struct fwnode_handle *ch_node)
+ struct fwnode_handle *ch_node,
+ enum iqs626_ch_id ch_id)
{
struct iqs626_sys_reg *sys_reg = &iqs626->sys_reg;
struct i2c_client *client = iqs626->client;
u8 *hyst = &sys_reg->tp_grp_reg.hyst;
+ int error, count, i;
unsigned int val;
- int error, count;
if (!fwnode_property_read_u32(ch_node, "azoteq,lta-update", &val)) {
if (val > IQS626_MISC_A_TPx_LTA_UPDATE_MAX) {
@@ -823,6 +771,48 @@ static int iqs626_parse_trackpad(struct iqs626_private *iqs626,
*hyst |= (val << IQS626_FILT_STR_LP_TPx_SHIFT);
}
+ for (i = 0; i < iqs626_channels[ch_id].num_ch; i++) {
+ u8 *ati_base = &sys_reg->tp_grp_reg.ch_reg_tp[i].ati_base;
+ u8 *thresh = &sys_reg->tp_grp_reg.ch_reg_tp[i].thresh;
+ struct fwnode_handle *tc_node;
+ char tc_name[10];
+
+ snprintf(tc_name, sizeof(tc_name), "channel-%d", i);
+
+ tc_node = fwnode_get_named_child_node(ch_node, tc_name);
+ if (!tc_node)
+ continue;
+
+ if (!fwnode_property_read_u32(tc_node, "azoteq,ati-base",
+ &val)) {
+ if (val < IQS626_TPx_ATI_BASE_MIN ||
+ val > IQS626_TPx_ATI_BASE_MAX) {
+ dev_err(&client->dev,
+ "Invalid %s %s ATI base: %u\n",
+ fwnode_get_name(ch_node), tc_name, val);
+ fwnode_handle_put(tc_node);
+ return -EINVAL;
+ }
+
+ *ati_base = val - IQS626_TPx_ATI_BASE_MIN;
+ }
+
+ if (!fwnode_property_read_u32(tc_node, "azoteq,thresh",
+ &val)) {
+ if (val > IQS626_CHx_THRESH_MAX) {
+ dev_err(&client->dev,
+ "Invalid %s %s threshold: %u\n",
+ fwnode_get_name(ch_node), tc_name, val);
+ fwnode_handle_put(tc_node);
+ return -EINVAL;
+ }
+
+ *thresh = val;
+ }
+
+ fwnode_handle_put(tc_node);
+ }
+
if (!fwnode_property_present(ch_node, "linux,keycodes"))
return 0;
@@ -889,8 +879,7 @@ static int iqs626_parse_trackpad(struct iqs626_private *iqs626,
static noinline_for_stack int
iqs626_parse_channel(struct iqs626_private *iqs626,
- const struct fwnode_handle *ch_node,
- enum iqs626_ch_id ch_id)
+ struct fwnode_handle *ch_node, enum iqs626_ch_id ch_id)
{
struct iqs626_sys_reg *sys_reg = &iqs626->sys_reg;
struct i2c_client *client = iqs626->client;
@@ -924,6 +913,20 @@ iqs626_parse_channel(struct iqs626_private *iqs626,
return -EINVAL;
}
+ error = iqs626_parse_ati_target(iqs626, ch_node, ch_id);
+ if (error)
+ return error;
+
+ error = iqs626_parse_events(iqs626, ch_node, ch_id);
+ if (error)
+ return error;
+
+ if (!fwnode_property_present(ch_node, "azoteq,ati-exclude"))
+ sys_reg->redo_ati |= iqs626_channels[ch_id].active;
+
+ if (!fwnode_property_present(ch_node, "azoteq,reseed-disable"))
+ sys_reg->reseed |= iqs626_channels[ch_id].active;
+
*engine |= IQS626_CHx_ENG_0_MEAS_CAP_SIZE;
if (fwnode_property_present(ch_node, "azoteq,meas-cap-decrease"))
*engine &= ~IQS626_CHx_ENG_0_MEAS_CAP_SIZE;
@@ -1057,7 +1060,7 @@ iqs626_parse_channel(struct iqs626_private *iqs626,
*(engine + 1) |= IQS626_CHx_ENG_1_ATI_BAND_TIGHTEN;
if (ch_id == IQS626_CH_TP_2 || ch_id == IQS626_CH_TP_3)
- return iqs626_parse_trackpad(iqs626, ch_node);
+ return iqs626_parse_trackpad(iqs626, ch_node, ch_id);
if (ch_id == IQS626_CH_ULP_0) {
sys_reg->ch_reg_ulp.hyst &= ~IQS626_ULP_PROJ_ENABLE;
@@ -1378,23 +1381,10 @@ static int iqs626_parse_prop(struct iqs626_private *iqs626)
continue;
error = iqs626_parse_channel(iqs626, ch_node, i);
+ fwnode_handle_put(ch_node);
if (error)
return error;
- error = iqs626_parse_ati_target(iqs626, ch_node, i);
- if (error)
- return error;
-
- error = iqs626_parse_events(iqs626, ch_node, i);
- if (error)
- return error;
-
- if (!fwnode_property_present(ch_node, "azoteq,ati-exclude"))
- sys_reg->redo_ati |= iqs626_channels[i].active;
-
- if (!fwnode_property_present(ch_node, "azoteq,reseed-disable"))
- sys_reg->reseed |= iqs626_channels[i].active;
-
sys_reg->active |= iqs626_channels[i].active;
}
@@ -1712,7 +1702,7 @@ static int iqs626_probe(struct i2c_client *client)
return error;
}
-static int __maybe_unused iqs626_suspend(struct device *dev)
+static int iqs626_suspend(struct device *dev)
{
struct iqs626_private *iqs626 = dev_get_drvdata(dev);
struct i2c_client *client = iqs626->client;
@@ -1771,7 +1761,7 @@ err_irq:
return error;
}
-static int __maybe_unused iqs626_resume(struct device *dev)
+static int iqs626_resume(struct device *dev)
{
struct iqs626_private *iqs626 = dev_get_drvdata(dev);
struct i2c_client *client = iqs626->client;
@@ -1818,7 +1808,7 @@ err_irq:
return error;
}
-static SIMPLE_DEV_PM_OPS(iqs626_pm, iqs626_suspend, iqs626_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(iqs626_pm, iqs626_suspend, iqs626_resume);
static const struct of_device_id iqs626_of_match[] = {
{ .compatible = "azoteq,iqs626a" },
@@ -1830,7 +1820,7 @@ static struct i2c_driver iqs626_i2c_driver = {
.driver = {
.name = "iqs626a",
.of_match_table = iqs626_of_match,
- .pm = &iqs626_pm,
+ .pm = pm_sleep_ptr(&iqs626_pm),
},
.probe_new = iqs626_probe,
};
diff --git a/drivers/input/misc/kxtj9.c b/drivers/input/misc/kxtj9.c
index 7e73e6e0730f..4e806d56c55d 100644
--- a/drivers/input/misc/kxtj9.c
+++ b/drivers/input/misc/kxtj9.c
@@ -494,7 +494,7 @@ static int kxtj9_probe(struct i2c_client *client)
return 0;
}
-static int __maybe_unused kxtj9_suspend(struct device *dev)
+static int kxtj9_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct kxtj9_data *tj9 = i2c_get_clientdata(client);
@@ -509,7 +509,7 @@ static int __maybe_unused kxtj9_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused kxtj9_resume(struct device *dev)
+static int kxtj9_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct kxtj9_data *tj9 = i2c_get_clientdata(client);
@@ -524,7 +524,7 @@ static int __maybe_unused kxtj9_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(kxtj9_pm_ops, kxtj9_suspend, kxtj9_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(kxtj9_pm_ops, kxtj9_suspend, kxtj9_resume);
static const struct i2c_device_id kxtj9_id[] = {
{ NAME, 0 },
@@ -536,7 +536,7 @@ MODULE_DEVICE_TABLE(i2c, kxtj9_id);
static struct i2c_driver kxtj9_driver = {
.driver = {
.name = NAME,
- .pm = &kxtj9_pm_ops,
+ .pm = pm_sleep_ptr(&kxtj9_pm_ops),
},
.probe_new = kxtj9_probe,
.id_table = kxtj9_id,
diff --git a/drivers/input/misc/max77693-haptic.c b/drivers/input/misc/max77693-haptic.c
index 4369d3c04d38..80f4416ffe2f 100644
--- a/drivers/input/misc/max77693-haptic.c
+++ b/drivers/input/misc/max77693-haptic.c
@@ -375,7 +375,7 @@ static int max77693_haptic_probe(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused max77693_haptic_suspend(struct device *dev)
+static int max77693_haptic_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct max77693_haptic *haptic = platform_get_drvdata(pdev);
@@ -388,7 +388,7 @@ static int __maybe_unused max77693_haptic_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused max77693_haptic_resume(struct device *dev)
+static int max77693_haptic_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct max77693_haptic *haptic = platform_get_drvdata(pdev);
@@ -401,8 +401,9 @@ static int __maybe_unused max77693_haptic_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(max77693_haptic_pm_ops,
- max77693_haptic_suspend, max77693_haptic_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(max77693_haptic_pm_ops,
+ max77693_haptic_suspend,
+ max77693_haptic_resume);
static const struct platform_device_id max77693_haptic_id[] = {
{ "max77693-haptic", TYPE_MAX77693 },
@@ -414,7 +415,7 @@ MODULE_DEVICE_TABLE(platform, max77693_haptic_id);
static struct platform_driver max77693_haptic_driver = {
.driver = {
.name = "max77693-haptic",
- .pm = &max77693_haptic_pm_ops,
+ .pm = pm_sleep_ptr(&max77693_haptic_pm_ops),
},
.probe = max77693_haptic_probe,
.id_table = max77693_haptic_id,
diff --git a/drivers/input/misc/max8925_onkey.c b/drivers/input/misc/max8925_onkey.c
index 4770cb55631a..62619e4fed20 100644
--- a/drivers/input/misc/max8925_onkey.c
+++ b/drivers/input/misc/max8925_onkey.c
@@ -129,7 +129,7 @@ static int max8925_onkey_probe(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused max8925_onkey_suspend(struct device *dev)
+static int max8925_onkey_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct max8925_onkey_info *info = platform_get_drvdata(pdev);
@@ -143,7 +143,7 @@ static int __maybe_unused max8925_onkey_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused max8925_onkey_resume(struct device *dev)
+static int max8925_onkey_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct max8925_onkey_info *info = platform_get_drvdata(pdev);
@@ -157,12 +157,13 @@ static int __maybe_unused max8925_onkey_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(max8925_onkey_pm_ops, max8925_onkey_suspend, max8925_onkey_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(max8925_onkey_pm_ops,
+ max8925_onkey_suspend, max8925_onkey_resume);
static struct platform_driver max8925_onkey_driver = {
.driver = {
.name = "max8925-onkey",
- .pm = &max8925_onkey_pm_ops,
+ .pm = pm_sleep_ptr(&max8925_onkey_pm_ops),
},
.probe = max8925_onkey_probe,
};
diff --git a/drivers/input/misc/max8997_haptic.c b/drivers/input/misc/max8997_haptic.c
index 99cbc5ee89d1..c4dff476d479 100644
--- a/drivers/input/misc/max8997_haptic.c
+++ b/drivers/input/misc/max8997_haptic.c
@@ -366,7 +366,7 @@ static int max8997_haptic_remove(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused max8997_haptic_suspend(struct device *dev)
+static int max8997_haptic_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct max8997_haptic *chip = platform_get_drvdata(pdev);
@@ -376,7 +376,8 @@ static int __maybe_unused max8997_haptic_suspend(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(max8997_haptic_pm_ops, max8997_haptic_suspend, NULL);
+static DEFINE_SIMPLE_DEV_PM_OPS(max8997_haptic_pm_ops,
+ max8997_haptic_suspend, NULL);
static const struct platform_device_id max8997_haptic_id[] = {
{ "max8997-haptic", 0 },
@@ -387,7 +388,7 @@ MODULE_DEVICE_TABLE(platform, max8997_haptic_id);
static struct platform_driver max8997_haptic_driver = {
.driver = {
.name = "max8997-haptic",
- .pm = &max8997_haptic_pm_ops,
+ .pm = pm_sleep_ptr(&max8997_haptic_pm_ops),
},
.probe = max8997_haptic_probe,
.remove = max8997_haptic_remove,
diff --git a/drivers/input/misc/palmas-pwrbutton.c b/drivers/input/misc/palmas-pwrbutton.c
index 465e6693077a..7e361727b0d9 100644
--- a/drivers/input/misc/palmas-pwrbutton.c
+++ b/drivers/input/misc/palmas-pwrbutton.c
@@ -266,7 +266,7 @@ static int palmas_pwron_remove(struct platform_device *pdev)
*
* Return: 0
*/
-static int __maybe_unused palmas_pwron_suspend(struct device *dev)
+static int palmas_pwron_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct palmas_pwron *pwron = platform_get_drvdata(pdev);
@@ -287,7 +287,7 @@ static int __maybe_unused palmas_pwron_suspend(struct device *dev)
*
* Return: 0
*/
-static int __maybe_unused palmas_pwron_resume(struct device *dev)
+static int palmas_pwron_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct palmas_pwron *pwron = platform_get_drvdata(pdev);
@@ -298,8 +298,8 @@ static int __maybe_unused palmas_pwron_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(palmas_pwron_pm,
- palmas_pwron_suspend, palmas_pwron_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(palmas_pwron_pm,
+ palmas_pwron_suspend, palmas_pwron_resume);
#ifdef CONFIG_OF
static const struct of_device_id of_palmas_pwr_match[] = {
@@ -316,7 +316,7 @@ static struct platform_driver palmas_pwron_driver = {
.driver = {
.name = "palmas_pwrbutton",
.of_match_table = of_match_ptr(of_palmas_pwr_match),
- .pm = &palmas_pwron_pm,
+ .pm = pm_sleep_ptr(&palmas_pwron_pm),
},
};
module_platform_driver(palmas_pwron_driver);
diff --git a/drivers/input/misc/pcf8574_keypad.c b/drivers/input/misc/pcf8574_keypad.c
index fd1ff3f1cd92..6323c3d37ef7 100644
--- a/drivers/input/misc/pcf8574_keypad.c
+++ b/drivers/input/misc/pcf8574_keypad.c
@@ -167,7 +167,6 @@ static void pcf8574_kp_remove(struct i2c_client *client)
kfree(lp);
}
-#ifdef CONFIG_PM
static int pcf8574_kp_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -186,15 +185,8 @@ static int pcf8574_kp_suspend(struct device *dev)
return 0;
}
-static const struct dev_pm_ops pcf8574_kp_pm_ops = {
- .suspend = pcf8574_kp_suspend,
- .resume = pcf8574_kp_resume,
-};
-
-#else
-# define pcf8574_kp_resume NULL
-# define pcf8574_kp_suspend NULL
-#endif
+static DEFINE_SIMPLE_DEV_PM_OPS(pcf8574_kp_pm_ops,
+ pcf8574_kp_suspend, pcf8574_kp_resume);
static const struct i2c_device_id pcf8574_kp_id[] = {
{ DRV_NAME, 0 },
@@ -205,9 +197,7 @@ MODULE_DEVICE_TABLE(i2c, pcf8574_kp_id);
static struct i2c_driver pcf8574_kp_driver = {
.driver = {
.name = DRV_NAME,
-#ifdef CONFIG_PM
- .pm = &pcf8574_kp_pm_ops,
-#endif
+ .pm = pm_sleep_ptr(&pcf8574_kp_pm_ops),
},
.probe_new = pcf8574_kp_probe,
.remove = pcf8574_kp_remove,
diff --git a/drivers/input/misc/pm8941-pwrkey.c b/drivers/input/misc/pm8941-pwrkey.c
index 549df01b6ee3..b6a27ebae977 100644
--- a/drivers/input/misc/pm8941-pwrkey.c
+++ b/drivers/input/misc/pm8941-pwrkey.c
@@ -217,7 +217,7 @@ static int pm8941_pwrkey_sw_debounce_init(struct pm8941_pwrkey *pwrkey)
return 0;
}
-static int __maybe_unused pm8941_pwrkey_suspend(struct device *dev)
+static int pm8941_pwrkey_suspend(struct device *dev)
{
struct pm8941_pwrkey *pwrkey = dev_get_drvdata(dev);
@@ -227,7 +227,7 @@ static int __maybe_unused pm8941_pwrkey_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused pm8941_pwrkey_resume(struct device *dev)
+static int pm8941_pwrkey_resume(struct device *dev)
{
struct pm8941_pwrkey *pwrkey = dev_get_drvdata(dev);
@@ -237,8 +237,8 @@ static int __maybe_unused pm8941_pwrkey_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(pm8941_pwr_key_pm_ops,
- pm8941_pwrkey_suspend, pm8941_pwrkey_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(pm8941_pwr_key_pm_ops,
+ pm8941_pwrkey_suspend, pm8941_pwrkey_resume);
static int pm8941_pwrkey_probe(struct platform_device *pdev)
{
@@ -460,7 +460,7 @@ static struct platform_driver pm8941_pwrkey_driver = {
.remove = pm8941_pwrkey_remove,
.driver = {
.name = "pm8941-pwrkey",
- .pm = &pm8941_pwr_key_pm_ops,
+ .pm = pm_sleep_ptr(&pm8941_pwr_key_pm_ops),
.of_match_table = of_match_ptr(pm8941_pwr_key_id_table),
},
};
diff --git a/drivers/input/misc/pm8xxx-vibrator.c b/drivers/input/misc/pm8xxx-vibrator.c
index 53ad25eaf1a2..04cb87efd799 100644
--- a/drivers/input/misc/pm8xxx-vibrator.c
+++ b/drivers/input/misc/pm8xxx-vibrator.c
@@ -226,7 +226,7 @@ static int pm8xxx_vib_probe(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused pm8xxx_vib_suspend(struct device *dev)
+static int pm8xxx_vib_suspend(struct device *dev)
{
struct pm8xxx_vib *vib = dev_get_drvdata(dev);
@@ -236,7 +236,7 @@ static int __maybe_unused pm8xxx_vib_suspend(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(pm8xxx_vib_pm_ops, pm8xxx_vib_suspend, NULL);
+static DEFINE_SIMPLE_DEV_PM_OPS(pm8xxx_vib_pm_ops, pm8xxx_vib_suspend, NULL);
static const struct of_device_id pm8xxx_vib_id_table[] = {
{ .compatible = "qcom,pm8058-vib", .data = &pm8058_regs },
@@ -250,7 +250,7 @@ static struct platform_driver pm8xxx_vib_driver = {
.probe = pm8xxx_vib_probe,
.driver = {
.name = "pm8xxx-vib",
- .pm = &pm8xxx_vib_pm_ops,
+ .pm = pm_sleep_ptr(&pm8xxx_vib_pm_ops),
.of_match_table = pm8xxx_vib_id_table,
},
};
diff --git a/drivers/input/misc/pmic8xxx-pwrkey.c b/drivers/input/misc/pmic8xxx-pwrkey.c
index 0e818a3d28c5..89fb137e3715 100644
--- a/drivers/input/misc/pmic8xxx-pwrkey.c
+++ b/drivers/input/misc/pmic8xxx-pwrkey.c
@@ -100,7 +100,7 @@ static irqreturn_t pwrkey_release_irq(int irq, void *_pwr)
return IRQ_HANDLED;
}
-static int __maybe_unused pmic8xxx_pwrkey_suspend(struct device *dev)
+static int pmic8xxx_pwrkey_suspend(struct device *dev)
{
struct pmic8xxx_pwrkey *pwrkey = dev_get_drvdata(dev);
@@ -110,7 +110,7 @@ static int __maybe_unused pmic8xxx_pwrkey_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused pmic8xxx_pwrkey_resume(struct device *dev)
+static int pmic8xxx_pwrkey_resume(struct device *dev)
{
struct pmic8xxx_pwrkey *pwrkey = dev_get_drvdata(dev);
@@ -120,7 +120,7 @@ static int __maybe_unused pmic8xxx_pwrkey_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(pm8xxx_pwr_key_pm_ops,
+static DEFINE_SIMPLE_DEV_PM_OPS(pm8xxx_pwr_key_pm_ops,
pmic8xxx_pwrkey_suspend, pmic8xxx_pwrkey_resume);
static void pmic8xxx_pwrkey_shutdown(struct platform_device *pdev)
@@ -442,7 +442,7 @@ static struct platform_driver pmic8xxx_pwrkey_driver = {
.shutdown = pmic8xxx_pwrkey_shutdown,
.driver = {
.name = "pm8xxx-pwrkey",
- .pm = &pm8xxx_pwr_key_pm_ops,
+ .pm = pm_sleep_ptr(&pm8xxx_pwr_key_pm_ops),
.of_match_table = pm8xxx_pwr_key_id_table,
},
};
diff --git a/drivers/input/misc/pwm-beeper.c b/drivers/input/misc/pwm-beeper.c
index d6b12477748a..3cf1812384e6 100644
--- a/drivers/input/misc/pwm-beeper.c
+++ b/drivers/input/misc/pwm-beeper.c
@@ -203,7 +203,7 @@ static int pwm_beeper_probe(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused pwm_beeper_suspend(struct device *dev)
+static int pwm_beeper_suspend(struct device *dev)
{
struct pwm_beeper *beeper = dev_get_drvdata(dev);
@@ -221,7 +221,7 @@ static int __maybe_unused pwm_beeper_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused pwm_beeper_resume(struct device *dev)
+static int pwm_beeper_resume(struct device *dev)
{
struct pwm_beeper *beeper = dev_get_drvdata(dev);
@@ -235,8 +235,8 @@ static int __maybe_unused pwm_beeper_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(pwm_beeper_pm_ops,
- pwm_beeper_suspend, pwm_beeper_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(pwm_beeper_pm_ops,
+ pwm_beeper_suspend, pwm_beeper_resume);
#ifdef CONFIG_OF
static const struct of_device_id pwm_beeper_match[] = {
@@ -250,7 +250,7 @@ static struct platform_driver pwm_beeper_driver = {
.probe = pwm_beeper_probe,
.driver = {
.name = "pwm-beeper",
- .pm = &pwm_beeper_pm_ops,
+ .pm = pm_sleep_ptr(&pwm_beeper_pm_ops),
.of_match_table = of_match_ptr(pwm_beeper_match),
},
};
diff --git a/drivers/input/misc/pwm-vibra.c b/drivers/input/misc/pwm-vibra.c
index 81e777a04b88..d0e58a7cdfa3 100644
--- a/drivers/input/misc/pwm-vibra.c
+++ b/drivers/input/misc/pwm-vibra.c
@@ -222,7 +222,7 @@ static int pwm_vibrator_probe(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused pwm_vibrator_suspend(struct device *dev)
+static int pwm_vibrator_suspend(struct device *dev)
{
struct pwm_vibrator *vibrator = dev_get_drvdata(dev);
@@ -233,7 +233,7 @@ static int __maybe_unused pwm_vibrator_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused pwm_vibrator_resume(struct device *dev)
+static int pwm_vibrator_resume(struct device *dev)
{
struct pwm_vibrator *vibrator = dev_get_drvdata(dev);
@@ -243,8 +243,8 @@ static int __maybe_unused pwm_vibrator_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(pwm_vibrator_pm_ops,
- pwm_vibrator_suspend, pwm_vibrator_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(pwm_vibrator_pm_ops,
+ pwm_vibrator_suspend, pwm_vibrator_resume);
#ifdef CONFIG_OF
static const struct of_device_id pwm_vibra_dt_match_table[] = {
@@ -258,7 +258,7 @@ static struct platform_driver pwm_vibrator_driver = {
.probe = pwm_vibrator_probe,
.driver = {
.name = "pwm-vibrator",
- .pm = &pwm_vibrator_pm_ops,
+ .pm = pm_sleep_ptr(&pwm_vibrator_pm_ops),
.of_match_table = of_match_ptr(pwm_vibra_dt_match_table),
},
};
diff --git a/drivers/input/misc/regulator-haptic.c b/drivers/input/misc/regulator-haptic.c
index a661e77545c5..02f73b7c0462 100644
--- a/drivers/input/misc/regulator-haptic.c
+++ b/drivers/input/misc/regulator-haptic.c
@@ -201,7 +201,7 @@ static int regulator_haptic_probe(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused regulator_haptic_suspend(struct device *dev)
+static int regulator_haptic_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct regulator_haptic *haptic = platform_get_drvdata(pdev);
@@ -220,7 +220,7 @@ static int __maybe_unused regulator_haptic_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused regulator_haptic_resume(struct device *dev)
+static int regulator_haptic_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct regulator_haptic *haptic = platform_get_drvdata(pdev);
@@ -239,7 +239,7 @@ static int __maybe_unused regulator_haptic_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(regulator_haptic_pm_ops,
+static DEFINE_SIMPLE_DEV_PM_OPS(regulator_haptic_pm_ops,
regulator_haptic_suspend, regulator_haptic_resume);
static const struct of_device_id regulator_haptic_dt_match[] = {
@@ -253,7 +253,7 @@ static struct platform_driver regulator_haptic_driver = {
.driver = {
.name = "regulator-haptic",
.of_match_table = regulator_haptic_dt_match,
- .pm = &regulator_haptic_pm_ops,
+ .pm = pm_sleep_ptr(&regulator_haptic_pm_ops),
},
};
module_platform_driver(regulator_haptic_driver);
diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c
index 6d613f2a017c..22ec62083065 100644
--- a/drivers/input/misc/rotary_encoder.c
+++ b/drivers/input/misc/rotary_encoder.c
@@ -317,7 +317,7 @@ static int rotary_encoder_probe(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused rotary_encoder_suspend(struct device *dev)
+static int rotary_encoder_suspend(struct device *dev)
{
struct rotary_encoder *encoder = dev_get_drvdata(dev);
unsigned int i;
@@ -330,7 +330,7 @@ static int __maybe_unused rotary_encoder_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused rotary_encoder_resume(struct device *dev)
+static int rotary_encoder_resume(struct device *dev)
{
struct rotary_encoder *encoder = dev_get_drvdata(dev);
unsigned int i;
@@ -343,8 +343,8 @@ static int __maybe_unused rotary_encoder_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(rotary_encoder_pm_ops,
- rotary_encoder_suspend, rotary_encoder_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(rotary_encoder_pm_ops,
+ rotary_encoder_suspend, rotary_encoder_resume);
#ifdef CONFIG_OF
static const struct of_device_id rotary_encoder_of_match[] = {
@@ -358,7 +358,7 @@ static struct platform_driver rotary_encoder_driver = {
.probe = rotary_encoder_probe,
.driver = {
.name = DRV_NAME,
- .pm = &rotary_encoder_pm_ops,
+ .pm = pm_sleep_ptr(&rotary_encoder_pm_ops),
.of_match_table = of_match_ptr(rotary_encoder_of_match),
}
};
diff --git a/drivers/input/misc/stpmic1_onkey.c b/drivers/input/misc/stpmic1_onkey.c
index d8dc2f2f8000..d5ebca7b90a5 100644
--- a/drivers/input/misc/stpmic1_onkey.c
+++ b/drivers/input/misc/stpmic1_onkey.c
@@ -142,7 +142,7 @@ static int stpmic1_onkey_probe(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused stpmic1_onkey_suspend(struct device *dev)
+static int stpmic1_onkey_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct stpmic1_onkey *onkey = platform_get_drvdata(pdev);
@@ -154,7 +154,7 @@ static int __maybe_unused stpmic1_onkey_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused stpmic1_onkey_resume(struct device *dev)
+static int stpmic1_onkey_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct stpmic1_onkey *onkey = platform_get_drvdata(pdev);
@@ -166,9 +166,9 @@ static int __maybe_unused stpmic1_onkey_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(stpmic1_onkey_pm,
- stpmic1_onkey_suspend,
- stpmic1_onkey_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(stpmic1_onkey_pm,
+ stpmic1_onkey_suspend,
+ stpmic1_onkey_resume);
static const struct of_device_id of_stpmic1_onkey_match[] = {
{ .compatible = "st,stpmic1-onkey" },
@@ -182,7 +182,7 @@ static struct platform_driver stpmic1_onkey_driver = {
.driver = {
.name = "stpmic1_onkey",
.of_match_table = of_match_ptr(of_stpmic1_onkey_match),
- .pm = &stpmic1_onkey_pm,
+ .pm = pm_sleep_ptr(&stpmic1_onkey_pm),
},
};
module_platform_driver(stpmic1_onkey_driver);
diff --git a/drivers/input/misc/twl4030-vibra.c b/drivers/input/misc/twl4030-vibra.c
index 5619996da86f..101548b35ee3 100644
--- a/drivers/input/misc/twl4030-vibra.c
+++ b/drivers/input/misc/twl4030-vibra.c
@@ -143,7 +143,7 @@ static void twl4030_vibra_close(struct input_dev *input)
}
/*** Module ***/
-static int __maybe_unused twl4030_vibra_suspend(struct device *dev)
+static int twl4030_vibra_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct vibra_info *info = platform_get_drvdata(pdev);
@@ -154,14 +154,14 @@ static int __maybe_unused twl4030_vibra_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused twl4030_vibra_resume(struct device *dev)
+static int twl4030_vibra_resume(struct device *dev)
{
vibra_disable_leds();
return 0;
}
-static SIMPLE_DEV_PM_OPS(twl4030_vibra_pm_ops,
- twl4030_vibra_suspend, twl4030_vibra_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(twl4030_vibra_pm_ops,
+ twl4030_vibra_suspend, twl4030_vibra_resume);
static bool twl4030_vibra_check_coexist(struct device_node *parent)
{
@@ -234,7 +234,7 @@ static struct platform_driver twl4030_vibra_driver = {
.probe = twl4030_vibra_probe,
.driver = {
.name = "twl4030-vibra",
- .pm = &twl4030_vibra_pm_ops,
+ .pm = pm_sleep_ptr(&twl4030_vibra_pm_ops),
},
};
module_platform_driver(twl4030_vibra_driver);
diff --git a/drivers/input/misc/twl6040-vibra.c b/drivers/input/misc/twl6040-vibra.c
index bf6644927630..78f0b63e5c20 100644
--- a/drivers/input/misc/twl6040-vibra.c
+++ b/drivers/input/misc/twl6040-vibra.c
@@ -210,7 +210,7 @@ static void twl6040_vibra_close(struct input_dev *input)
twl6040_vibra_disable(info);
}
-static int __maybe_unused twl6040_vibra_suspend(struct device *dev)
+static int twl6040_vibra_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct vibra_info *info = platform_get_drvdata(pdev);
@@ -223,7 +223,8 @@ static int __maybe_unused twl6040_vibra_suspend(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(twl6040_vibra_pm_ops, twl6040_vibra_suspend, NULL);
+static DEFINE_SIMPLE_DEV_PM_OPS(twl6040_vibra_pm_ops,
+ twl6040_vibra_suspend, NULL);
static int twl6040_vibra_probe(struct platform_device *pdev)
{
@@ -354,7 +355,7 @@ static struct platform_driver twl6040_vibra_driver = {
.probe = twl6040_vibra_probe,
.driver = {
.name = "twl6040-vibra",
- .pm = &twl6040_vibra_pm_ops,
+ .pm = pm_sleep_ptr(&twl6040_vibra_pm_ops),
},
};
module_platform_driver(twl6040_vibra_driver);
diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c
index 80dfd72a02d3..111cb70cde46 100644
--- a/drivers/input/misc/wistron_btns.c
+++ b/drivers/input/misc/wistron_btns.c
@@ -1295,7 +1295,6 @@ static int wistron_remove(struct platform_device *dev)
return 0;
}
-#ifdef CONFIG_PM
static int wistron_suspend(struct device *dev)
{
if (have_wifi)
@@ -1330,14 +1329,11 @@ static const struct dev_pm_ops wistron_pm_ops = {
.poweroff = wistron_suspend,
.restore = wistron_resume,
};
-#endif
static struct platform_driver wistron_driver = {
.driver = {
.name = "wistron-bios",
-#ifdef CONFIG_PM
- .pm = &wistron_pm_ops,
-#endif
+ .pm = pm_sleep_ptr(&wistron_pm_ops),
},
.probe = wistron_probe,
.remove = wistron_remove,
diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c
index 7e88a6ec7989..dd7b0d70d791 100644
--- a/drivers/input/mouse/cyapa.c
+++ b/drivers/input/mouse/cyapa.c
@@ -1349,7 +1349,7 @@ static int cyapa_probe(struct i2c_client *client)
return 0;
}
-static int __maybe_unused cyapa_suspend(struct device *dev)
+static int cyapa_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct cyapa *cyapa = i2c_get_clientdata(client);
@@ -1397,7 +1397,7 @@ static int __maybe_unused cyapa_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused cyapa_resume(struct device *dev)
+static int cyapa_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct cyapa *cyapa = i2c_get_clientdata(client);
@@ -1424,7 +1424,7 @@ static int __maybe_unused cyapa_resume(struct device *dev)
return 0;
}
-static int __maybe_unused cyapa_runtime_suspend(struct device *dev)
+static int cyapa_runtime_suspend(struct device *dev)
{
struct cyapa *cyapa = dev_get_drvdata(dev);
int error;
@@ -1439,7 +1439,7 @@ static int __maybe_unused cyapa_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused cyapa_runtime_resume(struct device *dev)
+static int cyapa_runtime_resume(struct device *dev)
{
struct cyapa *cyapa = dev_get_drvdata(dev);
int error;
@@ -1453,8 +1453,8 @@ static int __maybe_unused cyapa_runtime_resume(struct device *dev)
}
static const struct dev_pm_ops cyapa_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(cyapa_suspend, cyapa_resume)
- SET_RUNTIME_PM_OPS(cyapa_runtime_suspend, cyapa_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(cyapa_suspend, cyapa_resume)
+ RUNTIME_PM_OPS(cyapa_runtime_suspend, cyapa_runtime_resume, NULL)
};
static const struct i2c_device_id cyapa_id_table[] = {
@@ -1484,7 +1484,7 @@ MODULE_DEVICE_TABLE(of, cyapa_of_match);
static struct i2c_driver cyapa_driver = {
.driver = {
.name = "cyapa",
- .pm = &cyapa_pm_ops,
+ .pm = pm_ptr(&cyapa_pm_ops),
.acpi_match_table = ACPI_PTR(cyapa_acpi_id),
.of_match_table = of_match_ptr(cyapa_of_match),
},
diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c
index 76729ada1582..5f0d75a45c80 100644
--- a/drivers/input/mouse/elan_i2c_core.c
+++ b/drivers/input/mouse/elan_i2c_core.c
@@ -1328,7 +1328,7 @@ static int elan_probe(struct i2c_client *client)
return 0;
}
-static int __maybe_unused elan_suspend(struct device *dev)
+static int elan_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct elan_tp_data *data = i2c_get_clientdata(client);
@@ -1365,7 +1365,7 @@ err:
return ret;
}
-static int __maybe_unused elan_resume(struct device *dev)
+static int elan_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct elan_tp_data *data = i2c_get_clientdata(client);
@@ -1394,7 +1394,7 @@ err:
return error;
}
-static SIMPLE_DEV_PM_OPS(elan_pm_ops, elan_suspend, elan_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(elan_pm_ops, elan_suspend, elan_resume);
static const struct i2c_device_id elan_id[] = {
{ DRIVER_NAME, 0 },
@@ -1418,7 +1418,7 @@ MODULE_DEVICE_TABLE(of, elan_of_match);
static struct i2c_driver elan_driver = {
.driver = {
.name = DRIVER_NAME,
- .pm = &elan_pm_ops,
+ .pm = pm_sleep_ptr(&elan_pm_ops),
.acpi_match_table = ACPI_PTR(elan_acpi_id),
.of_match_table = of_match_ptr(elan_of_match),
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
diff --git a/drivers/input/mouse/navpoint.c b/drivers/input/mouse/navpoint.c
index 4d67575bb276..2b7b86eef280 100644
--- a/drivers/input/mouse/navpoint.c
+++ b/drivers/input/mouse/navpoint.c
@@ -315,7 +315,7 @@ static int navpoint_remove(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused navpoint_suspend(struct device *dev)
+static int navpoint_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct navpoint *navpoint = platform_get_drvdata(pdev);
@@ -329,7 +329,7 @@ static int __maybe_unused navpoint_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused navpoint_resume(struct device *dev)
+static int navpoint_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct navpoint *navpoint = platform_get_drvdata(pdev);
@@ -343,14 +343,15 @@ static int __maybe_unused navpoint_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(navpoint_pm_ops, navpoint_suspend, navpoint_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(navpoint_pm_ops,
+ navpoint_suspend, navpoint_resume);
static struct platform_driver navpoint_driver = {
.probe = navpoint_probe,
.remove = navpoint_remove,
.driver = {
.name = "navpoint",
- .pm = &navpoint_pm_ops,
+ .pm = pm_sleep_ptr(&navpoint_pm_ops),
},
};
diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c
index 6487c8c60d5e..068692a8aba5 100644
--- a/drivers/input/mouse/synaptics_i2c.c
+++ b/drivers/input/mouse/synaptics_i2c.c
@@ -597,7 +597,7 @@ static void synaptics_i2c_remove(struct i2c_client *client)
kfree(touch);
}
-static int __maybe_unused synaptics_i2c_suspend(struct device *dev)
+static int synaptics_i2c_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct synaptics_i2c *touch = i2c_get_clientdata(client);
@@ -610,7 +610,7 @@ static int __maybe_unused synaptics_i2c_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused synaptics_i2c_resume(struct device *dev)
+static int synaptics_i2c_resume(struct device *dev)
{
int ret;
struct i2c_client *client = to_i2c_client(dev);
@@ -626,8 +626,8 @@ static int __maybe_unused synaptics_i2c_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(synaptics_i2c_pm, synaptics_i2c_suspend,
- synaptics_i2c_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(synaptics_i2c_pm, synaptics_i2c_suspend,
+ synaptics_i2c_resume);
static const struct i2c_device_id synaptics_i2c_id_table[] = {
{ "synaptics_i2c", 0 },
@@ -647,7 +647,7 @@ static struct i2c_driver synaptics_i2c_driver = {
.driver = {
.name = DRIVER_NAME,
.of_match_table = of_match_ptr(synaptics_i2c_of_match),
- .pm = &synaptics_i2c_pm,
+ .pm = pm_sleep_ptr(&synaptics_i2c_pm),
},
.probe_new = synaptics_i2c_probe,
diff --git a/drivers/input/rmi4/rmi_i2c.c b/drivers/input/rmi4/rmi_i2c.c
index f2b75c6d3224..d69569ce8d8d 100644
--- a/drivers/input/rmi4/rmi_i2c.c
+++ b/drivers/input/rmi4/rmi_i2c.c
@@ -287,7 +287,6 @@ static int rmi_i2c_probe(struct i2c_client *client)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
static int rmi_i2c_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -323,9 +322,7 @@ static int rmi_i2c_resume(struct device *dev)
return ret;
}
-#endif
-#ifdef CONFIG_PM
static int rmi_i2c_runtime_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -361,12 +358,10 @@ static int rmi_i2c_runtime_resume(struct device *dev)
return 0;
}
-#endif
static const struct dev_pm_ops rmi_i2c_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(rmi_i2c_suspend, rmi_i2c_resume)
- SET_RUNTIME_PM_OPS(rmi_i2c_runtime_suspend, rmi_i2c_runtime_resume,
- NULL)
+ SYSTEM_SLEEP_PM_OPS(rmi_i2c_suspend, rmi_i2c_resume)
+ RUNTIME_PM_OPS(rmi_i2c_runtime_suspend, rmi_i2c_runtime_resume, NULL)
};
static const struct i2c_device_id rmi_id[] = {
@@ -378,7 +373,7 @@ MODULE_DEVICE_TABLE(i2c, rmi_id);
static struct i2c_driver rmi_i2c_driver = {
.driver = {
.name = "rmi4_i2c",
- .pm = &rmi_i2c_pm,
+ .pm = pm_ptr(&rmi_i2c_pm),
.of_match_table = of_match_ptr(rmi_i2c_of_match),
},
.id_table = rmi_id,
diff --git a/drivers/input/rmi4/rmi_smbus.c b/drivers/input/rmi4/rmi_smbus.c
index 8a9ee2bd7402..4bf0e1df6a4a 100644
--- a/drivers/input/rmi4/rmi_smbus.c
+++ b/drivers/input/rmi4/rmi_smbus.c
@@ -344,7 +344,7 @@ static void rmi_smb_remove(struct i2c_client *client)
rmi_unregister_transport_device(&rmi_smb->xport);
}
-static int __maybe_unused rmi_smb_suspend(struct device *dev)
+static int rmi_smb_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
@@ -357,7 +357,7 @@ static int __maybe_unused rmi_smb_suspend(struct device *dev)
return ret;
}
-static int __maybe_unused rmi_smb_runtime_suspend(struct device *dev)
+static int rmi_smb_runtime_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
@@ -370,7 +370,7 @@ static int __maybe_unused rmi_smb_runtime_suspend(struct device *dev)
return ret;
}
-static int __maybe_unused rmi_smb_resume(struct device *dev)
+static int rmi_smb_resume(struct device *dev)
{
struct i2c_client *client = container_of(dev, struct i2c_client, dev);
struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
@@ -388,7 +388,7 @@ static int __maybe_unused rmi_smb_resume(struct device *dev)
return 0;
}
-static int __maybe_unused rmi_smb_runtime_resume(struct device *dev)
+static int rmi_smb_runtime_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
@@ -402,9 +402,8 @@ static int __maybe_unused rmi_smb_runtime_resume(struct device *dev)
}
static const struct dev_pm_ops rmi_smb_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(rmi_smb_suspend, rmi_smb_resume)
- SET_RUNTIME_PM_OPS(rmi_smb_runtime_suspend, rmi_smb_runtime_resume,
- NULL)
+ SYSTEM_SLEEP_PM_OPS(rmi_smb_suspend, rmi_smb_resume)
+ RUNTIME_PM_OPS(rmi_smb_runtime_suspend, rmi_smb_runtime_resume, NULL)
};
static const struct i2c_device_id rmi_id[] = {
@@ -416,7 +415,7 @@ MODULE_DEVICE_TABLE(i2c, rmi_id);
static struct i2c_driver rmi_smb_driver = {
.driver = {
.name = "rmi4_smbus",
- .pm = &rmi_smb_pm,
+ .pm = pm_ptr(&rmi_smb_pm),
},
.id_table = rmi_id,
.probe_new = rmi_smb_probe,
diff --git a/drivers/input/rmi4/rmi_spi.c b/drivers/input/rmi4/rmi_spi.c
index c82edda66b23..852aeb0b2c07 100644
--- a/drivers/input/rmi4/rmi_spi.c
+++ b/drivers/input/rmi4/rmi_spi.c
@@ -447,7 +447,6 @@ static int rmi_spi_probe(struct spi_device *spi)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
static int rmi_spi_suspend(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
@@ -473,9 +472,7 @@ static int rmi_spi_resume(struct device *dev)
return ret;
}
-#endif
-#ifdef CONFIG_PM
static int rmi_spi_runtime_suspend(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
@@ -501,16 +498,14 @@ static int rmi_spi_runtime_resume(struct device *dev)
return 0;
}
-#endif
static const struct dev_pm_ops rmi_spi_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(rmi_spi_suspend, rmi_spi_resume)
- SET_RUNTIME_PM_OPS(rmi_spi_runtime_suspend, rmi_spi_runtime_resume,
- NULL)
+ SYSTEM_SLEEP_PM_OPS(rmi_spi_suspend, rmi_spi_resume)
+ RUNTIME_PM_OPS(rmi_spi_runtime_suspend, rmi_spi_runtime_resume, NULL)
};
static const struct spi_device_id rmi_id[] = {
- { "rmi4_spi", 0 },
+ { "rmi4-spi", 0 },
{ }
};
MODULE_DEVICE_TABLE(spi, rmi_id);
@@ -518,7 +513,7 @@ MODULE_DEVICE_TABLE(spi, rmi_id);
static struct spi_driver rmi_spi_driver = {
.driver = {
.name = "rmi4_spi",
- .pm = &rmi_spi_pm,
+ .pm = pm_ptr(&rmi_spi_pm),
.of_match_table = of_match_ptr(rmi_spi_of_match),
},
.id_table = rmi_id,
diff --git a/drivers/input/serio/altera_ps2.c b/drivers/input/serio/altera_ps2.c
index 3a92304f64fb..9f8d7b332d1b 100644
--- a/drivers/input/serio/altera_ps2.c
+++ b/drivers/input/serio/altera_ps2.c
@@ -78,7 +78,6 @@ static void altera_ps2_close(struct serio *io)
static int altera_ps2_probe(struct platform_device *pdev)
{
struct ps2if *ps2if;
- struct resource *res;
struct serio *serio;
int error, irq;
@@ -86,8 +85,7 @@ static int altera_ps2_probe(struct platform_device *pdev)
if (!ps2if)
return -ENOMEM;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- ps2if->base = devm_ioremap_resource(&pdev->dev, res);
+ ps2if->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(ps2if->base))
return PTR_ERR(ps2if->base);
diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c
index c391700fc4ae..8fbfa448be4a 100644
--- a/drivers/input/serio/ambakmi.c
+++ b/drivers/input/serio/ambakmi.c
@@ -170,7 +170,7 @@ static void amba_kmi_remove(struct amba_device *dev)
amba_release_regions(dev);
}
-static int __maybe_unused amba_kmi_resume(struct device *dev)
+static int amba_kmi_resume(struct device *dev)
{
struct amba_kmi_port *kmi = dev_get_drvdata(dev);
@@ -180,7 +180,7 @@ static int __maybe_unused amba_kmi_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(amba_kmi_dev_pm_ops, NULL, amba_kmi_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(amba_kmi_dev_pm_ops, NULL, amba_kmi_resume);
static const struct amba_id amba_kmi_idtable[] = {
{
@@ -196,7 +196,7 @@ static struct amba_driver ambakmi_driver = {
.drv = {
.name = "kmi-pl050",
.owner = THIS_MODULE,
- .pm = &amba_kmi_dev_pm_ops,
+ .pm = pm_sleep_ptr(&amba_kmi_dev_pm_ops),
},
.id_table = amba_kmi_idtable,
.probe = amba_kmi_probe,
diff --git a/drivers/input/serio/apbps2.c b/drivers/input/serio/apbps2.c
index 9c9ce097f8bf..513d96e40e0e 100644
--- a/drivers/input/serio/apbps2.c
+++ b/drivers/input/serio/apbps2.c
@@ -132,7 +132,6 @@ static int apbps2_of_probe(struct platform_device *ofdev)
struct apbps2_priv *priv;
int irq, err;
u32 freq_hz;
- struct resource *res;
priv = devm_kzalloc(&ofdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv) {
@@ -141,8 +140,7 @@ static int apbps2_of_probe(struct platform_device *ofdev)
}
/* Find Device Address */
- res = platform_get_resource(ofdev, IORESOURCE_MEM, 0);
- priv->regs = devm_ioremap_resource(&ofdev->dev, res);
+ priv->regs = devm_platform_get_and_ioremap_resource(ofdev, 0, NULL);
if (IS_ERR(priv->regs))
return PTR_ERR(priv->regs);
diff --git a/drivers/input/serio/arc_ps2.c b/drivers/input/serio/arc_ps2.c
index 0af9fba5d16d..a6debb13d527 100644
--- a/drivers/input/serio/arc_ps2.c
+++ b/drivers/input/serio/arc_ps2.c
@@ -182,7 +182,6 @@ static int arc_ps2_create_port(struct platform_device *pdev,
static int arc_ps2_probe(struct platform_device *pdev)
{
struct arc_ps2_data *arc_ps2;
- struct resource *res;
int irq;
int error, id, i;
@@ -197,8 +196,7 @@ static int arc_ps2_probe(struct platform_device *pdev)
return -ENOMEM;
}
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- arc_ps2->addr = devm_ioremap_resource(&pdev->dev, res);
+ arc_ps2->addr = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(arc_ps2->addr))
return PTR_ERR(arc_ps2->addr);
diff --git a/drivers/input/serio/olpc_apsp.c b/drivers/input/serio/olpc_apsp.c
index 04d2db982fb8..33a8e5889bd8 100644
--- a/drivers/input/serio/olpc_apsp.c
+++ b/drivers/input/serio/olpc_apsp.c
@@ -169,7 +169,6 @@ static int olpc_apsp_probe(struct platform_device *pdev)
{
struct serio *kb_serio, *pad_serio;
struct olpc_apsp *priv;
- struct resource *res;
int error;
priv = devm_kzalloc(&pdev->dev, sizeof(struct olpc_apsp), GFP_KERNEL);
@@ -178,8 +177,7 @@ static int olpc_apsp_probe(struct platform_device *pdev)
priv->dev = &pdev->dev;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- priv->base = devm_ioremap_resource(&pdev->dev, res);
+ priv->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(priv->base)) {
dev_err(&pdev->dev, "Failed to map WTM registers\n");
return PTR_ERR(priv->base);
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index 15ce3202322f..767fc9efb4a8 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -895,9 +895,9 @@ static int serio_bus_match(struct device *dev, struct device_driver *drv)
return err; \
} while (0)
-static int serio_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int serio_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct serio *serio;
+ const struct serio *serio;
if (!dev)
return -ENODEV;
diff --git a/drivers/input/touchscreen/ad7877.c b/drivers/input/touchscreen/ad7877.c
index 08f5372f0bfd..edb36d663f22 100644
--- a/drivers/input/touchscreen/ad7877.c
+++ b/drivers/input/touchscreen/ad7877.c
@@ -788,7 +788,7 @@ static int ad7877_probe(struct spi_device *spi)
return 0;
}
-static int __maybe_unused ad7877_suspend(struct device *dev)
+static int ad7877_suspend(struct device *dev)
{
struct ad7877 *ts = dev_get_drvdata(dev);
@@ -797,7 +797,7 @@ static int __maybe_unused ad7877_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused ad7877_resume(struct device *dev)
+static int ad7877_resume(struct device *dev)
{
struct ad7877 *ts = dev_get_drvdata(dev);
@@ -806,12 +806,12 @@ static int __maybe_unused ad7877_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(ad7877_pm, ad7877_suspend, ad7877_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(ad7877_pm, ad7877_suspend, ad7877_resume);
static struct spi_driver ad7877_driver = {
.driver = {
.name = "ad7877",
- .pm = &ad7877_pm,
+ .pm = pm_sleep_ptr(&ad7877_pm),
},
.probe = ad7877_probe,
};
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index bed68a68f330..17f11bce8113 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -843,14 +843,8 @@ static void ads7846_report_state(struct ads7846 *ts)
if (x == MAX_12BIT)
x = 0;
- if (ts->model == 7843) {
+ if (ts->model == 7843 || ts->model == 7845) {
Rt = ts->pressure_max / 2;
- } else if (ts->model == 7845) {
- if (get_pendown_state(ts))
- Rt = ts->pressure_max / 2;
- else
- Rt = 0;
- dev_vdbg(&ts->spi->dev, "x/y: %d/%d, PD %d\n", x, y, Rt);
} else if (likely(x && z1)) {
/* compute touch pressure resistance using equation #2 */
Rt = z2;
@@ -944,7 +938,7 @@ static irqreturn_t ads7846_irq(int irq, void *handle)
return IRQ_HANDLED;
}
-static int __maybe_unused ads7846_suspend(struct device *dev)
+static int ads7846_suspend(struct device *dev)
{
struct ads7846 *ts = dev_get_drvdata(dev);
@@ -966,7 +960,7 @@ static int __maybe_unused ads7846_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused ads7846_resume(struct device *dev)
+static int ads7846_resume(struct device *dev)
{
struct ads7846 *ts = dev_get_drvdata(dev);
@@ -988,7 +982,7 @@ static int __maybe_unused ads7846_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(ads7846_pm, ads7846_suspend, ads7846_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(ads7846_pm, ads7846_suspend, ads7846_resume);
static int ads7846_setup_pendown(struct spi_device *spi,
struct ads7846 *ts,
@@ -1066,6 +1060,9 @@ static int ads7846_setup_spi_msg(struct ads7846 *ts,
struct ads7846_buf_layout *l = &packet->l[cmd_idx];
unsigned int max_count;
+ if (cmd_idx == packet->cmds - 1)
+ cmd_idx = ADS7846_PWDOWN;
+
if (ads7846_cmd_need_settle(cmd_idx))
max_count = packet->count + packet->count_skip;
else
@@ -1102,7 +1099,12 @@ static int ads7846_setup_spi_msg(struct ads7846 *ts,
for (cmd_idx = 0; cmd_idx < packet->cmds; cmd_idx++) {
struct ads7846_buf_layout *l = &packet->l[cmd_idx];
- u8 cmd = ads7846_get_cmd(cmd_idx, vref);
+ u8 cmd;
+
+ if (cmd_idx == packet->cmds - 1)
+ cmd_idx = ADS7846_PWDOWN;
+
+ cmd = ads7846_get_cmd(cmd_idx, vref);
for (b = 0; b < l->count; b++)
packet->tx[l->offset + b].cmd = cmd;
@@ -1316,8 +1318,9 @@ static int ads7846_probe(struct spi_device *spi)
pdata->y_min ? : 0,
pdata->y_max ? : MAX_12BIT,
0, 0);
- input_set_abs_params(input_dev, ABS_PRESSURE,
- pdata->pressure_min, pdata->pressure_max, 0, 0);
+ if (ts->model != 7845)
+ input_set_abs_params(input_dev, ABS_PRESSURE,
+ pdata->pressure_min, pdata->pressure_max, 0, 0);
/*
* Parse common framework properties. Must be done here to ensure the
@@ -1421,7 +1424,7 @@ static void ads7846_remove(struct spi_device *spi)
static struct spi_driver ads7846_driver = {
.driver = {
.name = "ads7846",
- .pm = &ads7846_pm,
+ .pm = pm_sleep_ptr(&ads7846_pm),
.of_match_table = of_match_ptr(ads7846_dt_ids),
},
.probe = ads7846_probe,
diff --git a/drivers/input/touchscreen/ar1021_i2c.c b/drivers/input/touchscreen/ar1021_i2c.c
index 25bcc677e98b..3a5b65cae360 100644
--- a/drivers/input/touchscreen/ar1021_i2c.c
+++ b/drivers/input/touchscreen/ar1021_i2c.c
@@ -142,7 +142,7 @@ static int ar1021_i2c_probe(struct i2c_client *client)
return 0;
}
-static int __maybe_unused ar1021_i2c_suspend(struct device *dev)
+static int ar1021_i2c_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -151,7 +151,7 @@ static int __maybe_unused ar1021_i2c_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused ar1021_i2c_resume(struct device *dev)
+static int ar1021_i2c_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -160,7 +160,8 @@ static int __maybe_unused ar1021_i2c_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(ar1021_i2c_pm, ar1021_i2c_suspend, ar1021_i2c_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(ar1021_i2c_pm,
+ ar1021_i2c_suspend, ar1021_i2c_resume);
static const struct i2c_device_id ar1021_i2c_id[] = {
{ "ar1021", 0 },
@@ -177,7 +178,7 @@ MODULE_DEVICE_TABLE(of, ar1021_i2c_of_match);
static struct i2c_driver ar1021_i2c_driver = {
.driver = {
.name = "ar1021_i2c",
- .pm = &ar1021_i2c_pm,
+ .pm = pm_sleep_ptr(&ar1021_i2c_pm),
.of_match_table = ar1021_i2c_of_match,
},
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 39ef2664b852..996bf434e1cb 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -3296,7 +3296,7 @@ static void mxt_remove(struct i2c_client *client)
data->regulators);
}
-static int __maybe_unused mxt_suspend(struct device *dev)
+static int mxt_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct mxt_data *data = i2c_get_clientdata(client);
@@ -3317,7 +3317,7 @@ static int __maybe_unused mxt_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused mxt_resume(struct device *dev)
+static int mxt_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct mxt_data *data = i2c_get_clientdata(client);
@@ -3338,7 +3338,7 @@ static int __maybe_unused mxt_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(mxt_pm_ops, mxt_suspend, mxt_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(mxt_pm_ops, mxt_suspend, mxt_resume);
static const struct of_device_id mxt_of_match[] = {
{ .compatible = "atmel,maxtouch", },
@@ -3375,7 +3375,7 @@ static struct i2c_driver mxt_driver = {
.name = "atmel_mxt_ts",
.of_match_table = mxt_of_match,
.acpi_match_table = ACPI_PTR(mxt_acpi_id),
- .pm = &mxt_pm_ops,
+ .pm = pm_sleep_ptr(&mxt_pm_ops),
},
.probe_new = mxt_probe,
.remove = mxt_remove,
diff --git a/drivers/input/touchscreen/auo-pixcir-ts.c b/drivers/input/touchscreen/auo-pixcir-ts.c
index a4a1d58aeeac..5359efc80b2b 100644
--- a/drivers/input/touchscreen/auo-pixcir-ts.c
+++ b/drivers/input/touchscreen/auo-pixcir-ts.c
@@ -410,7 +410,7 @@ static void auo_pixcir_input_close(struct input_dev *dev)
auo_pixcir_stop(ts);
}
-static int __maybe_unused auo_pixcir_suspend(struct device *dev)
+static int auo_pixcir_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct auo_pixcir_ts *ts = i2c_get_clientdata(client);
@@ -442,7 +442,7 @@ unlock:
return ret;
}
-static int __maybe_unused auo_pixcir_resume(struct device *dev)
+static int auo_pixcir_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct auo_pixcir_ts *ts = i2c_get_clientdata(client);
@@ -472,8 +472,8 @@ unlock:
return ret;
}
-static SIMPLE_DEV_PM_OPS(auo_pixcir_pm_ops,
- auo_pixcir_suspend, auo_pixcir_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(auo_pixcir_pm_ops,
+ auo_pixcir_suspend, auo_pixcir_resume);
static void auo_pixcir_reset(void *data)
{
@@ -633,7 +633,7 @@ MODULE_DEVICE_TABLE(of, auo_pixcir_ts_dt_idtable);
static struct i2c_driver auo_pixcir_driver = {
.driver = {
.name = "auo_pixcir_ts",
- .pm = &auo_pixcir_pm_ops,
+ .pm = pm_sleep_ptr(&auo_pixcir_pm_ops),
.of_match_table = of_match_ptr(auo_pixcir_ts_dt_idtable),
},
.probe_new = auo_pixcir_probe,
diff --git a/drivers/input/touchscreen/bu21013_ts.c b/drivers/input/touchscreen/bu21013_ts.c
index 5a4dbd39a372..c994ab6f4e58 100644
--- a/drivers/input/touchscreen/bu21013_ts.c
+++ b/drivers/input/touchscreen/bu21013_ts.c
@@ -560,7 +560,7 @@ static void bu21013_remove(struct i2c_client *client)
/* The resources will be freed by devm */
}
-static int __maybe_unused bu21013_suspend(struct device *dev)
+static int bu21013_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct bu21013_ts *ts = i2c_get_clientdata(client);
@@ -575,7 +575,7 @@ static int __maybe_unused bu21013_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused bu21013_resume(struct device *dev)
+static int bu21013_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct bu21013_ts *ts = i2c_get_clientdata(client);
@@ -604,7 +604,7 @@ static int __maybe_unused bu21013_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(bu21013_dev_pm_ops, bu21013_suspend, bu21013_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(bu21013_dev_pm_ops, bu21013_suspend, bu21013_resume);
static const struct i2c_device_id bu21013_id[] = {
{ DRIVER_TP, 0 },
@@ -615,7 +615,7 @@ MODULE_DEVICE_TABLE(i2c, bu21013_id);
static struct i2c_driver bu21013_driver = {
.driver = {
.name = DRIVER_TP,
- .pm = &bu21013_dev_pm_ops,
+ .pm = pm_sleep_ptr(&bu21013_dev_pm_ops),
},
.probe_new = bu21013_probe,
.remove = bu21013_remove,
diff --git a/drivers/input/touchscreen/bu21029_ts.c b/drivers/input/touchscreen/bu21029_ts.c
index 215f4dc5105d..8f1442894ff9 100644
--- a/drivers/input/touchscreen/bu21029_ts.c
+++ b/drivers/input/touchscreen/bu21029_ts.c
@@ -422,7 +422,7 @@ static int bu21029_probe(struct i2c_client *client)
return 0;
}
-static int __maybe_unused bu21029_suspend(struct device *dev)
+static int bu21029_suspend(struct device *dev)
{
struct i2c_client *i2c = to_i2c_client(dev);
struct bu21029_ts_data *bu21029 = i2c_get_clientdata(i2c);
@@ -437,7 +437,7 @@ static int __maybe_unused bu21029_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused bu21029_resume(struct device *dev)
+static int bu21029_resume(struct device *dev)
{
struct i2c_client *i2c = to_i2c_client(dev);
struct bu21029_ts_data *bu21029 = i2c_get_clientdata(i2c);
@@ -451,7 +451,7 @@ static int __maybe_unused bu21029_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(bu21029_pm_ops, bu21029_suspend, bu21029_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(bu21029_pm_ops, bu21029_suspend, bu21029_resume);
static const struct i2c_device_id bu21029_ids[] = {
{ DRIVER_NAME, 0 },
@@ -471,7 +471,7 @@ static struct i2c_driver bu21029_driver = {
.driver = {
.name = DRIVER_NAME,
.of_match_table = of_match_ptr(bu21029_of_ids),
- .pm = &bu21029_pm_ops,
+ .pm = pm_sleep_ptr(&bu21029_pm_ops),
},
.id_table = bu21029_ids,
.probe_new = bu21029_probe,
diff --git a/drivers/input/touchscreen/chipone_icn8318.c b/drivers/input/touchscreen/chipone_icn8318.c
index f6769e4bd4f2..32b714a6ed2d 100644
--- a/drivers/input/touchscreen/chipone_icn8318.c
+++ b/drivers/input/touchscreen/chipone_icn8318.c
@@ -148,7 +148,6 @@ static void icn8318_stop(struct input_dev *dev)
gpiod_set_value_cansleep(data->wake_gpio, 0);
}
-#ifdef CONFIG_PM_SLEEP
static int icn8318_suspend(struct device *dev)
{
struct icn8318_data *data = i2c_get_clientdata(to_i2c_client(dev));
@@ -172,9 +171,8 @@ static int icn8318_resume(struct device *dev)
return 0;
}
-#endif
-static SIMPLE_DEV_PM_OPS(icn8318_pm_ops, icn8318_suspend, icn8318_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(icn8318_pm_ops, icn8318_suspend, icn8318_resume);
static int icn8318_probe(struct i2c_client *client)
{
@@ -263,7 +261,7 @@ MODULE_DEVICE_TABLE(i2c, icn8318_i2c_id);
static struct i2c_driver icn8318_driver = {
.driver = {
.name = "chipone_icn8318",
- .pm = &icn8318_pm_ops,
+ .pm = pm_sleep_ptr(&icn8318_pm_ops),
.of_match_table = icn8318_of_match,
},
.probe_new = icn8318_probe,
diff --git a/drivers/input/touchscreen/chipone_icn8505.c b/drivers/input/touchscreen/chipone_icn8505.c
index c421f4be2700..246bee0bee53 100644
--- a/drivers/input/touchscreen/chipone_icn8505.c
+++ b/drivers/input/touchscreen/chipone_icn8505.c
@@ -460,7 +460,7 @@ static int icn8505_probe(struct i2c_client *client)
return 0;
}
-static int __maybe_unused icn8505_suspend(struct device *dev)
+static int icn8505_suspend(struct device *dev)
{
struct icn8505_data *icn8505 = i2c_get_clientdata(to_i2c_client(dev));
@@ -471,7 +471,7 @@ static int __maybe_unused icn8505_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused icn8505_resume(struct device *dev)
+static int icn8505_resume(struct device *dev)
{
struct icn8505_data *icn8505 = i2c_get_clientdata(to_i2c_client(dev));
int error;
@@ -484,7 +484,7 @@ static int __maybe_unused icn8505_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(icn8505_pm_ops, icn8505_suspend, icn8505_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(icn8505_pm_ops, icn8505_suspend, icn8505_resume);
static const struct acpi_device_id icn8505_acpi_match[] = {
{ "CHPN0001" },
@@ -495,7 +495,7 @@ MODULE_DEVICE_TABLE(acpi, icn8505_acpi_match);
static struct i2c_driver icn8505_driver = {
.driver = {
.name = "chipone_icn8505",
- .pm = &icn8505_pm_ops,
+ .pm = pm_sleep_ptr(&icn8505_pm_ops),
.acpi_match_table = icn8505_acpi_match,
},
.probe_new = icn8505_probe,
diff --git a/drivers/input/touchscreen/cy8ctma140.c b/drivers/input/touchscreen/cy8ctma140.c
index 3a91d948b7f6..cd86477d971a 100644
--- a/drivers/input/touchscreen/cy8ctma140.c
+++ b/drivers/input/touchscreen/cy8ctma140.c
@@ -296,7 +296,7 @@ static int cy8ctma140_probe(struct i2c_client *client)
return 0;
}
-static int __maybe_unused cy8ctma140_suspend(struct device *dev)
+static int cy8ctma140_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct cy8ctma140 *ts = i2c_get_clientdata(client);
@@ -307,7 +307,7 @@ static int __maybe_unused cy8ctma140_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused cy8ctma140_resume(struct device *dev)
+static int cy8ctma140_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct cy8ctma140 *ts = i2c_get_clientdata(client);
@@ -322,7 +322,8 @@ static int __maybe_unused cy8ctma140_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(cy8ctma140_pm, cy8ctma140_suspend, cy8ctma140_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(cy8ctma140_pm,
+ cy8ctma140_suspend, cy8ctma140_resume);
static const struct i2c_device_id cy8ctma140_idtable[] = {
{ CY8CTMA140_NAME, 0 },
@@ -339,7 +340,7 @@ MODULE_DEVICE_TABLE(of, cy8ctma140_of_match);
static struct i2c_driver cy8ctma140_driver = {
.driver = {
.name = CY8CTMA140_NAME,
- .pm = &cy8ctma140_pm,
+ .pm = pm_sleep_ptr(&cy8ctma140_pm),
.of_match_table = cy8ctma140_of_match,
},
.id_table = cy8ctma140_idtable,
diff --git a/drivers/input/touchscreen/cy8ctmg110_ts.c b/drivers/input/touchscreen/cy8ctmg110_ts.c
index 7c2b7309dbaf..dcf50fbf6dc7 100644
--- a/drivers/input/touchscreen/cy8ctmg110_ts.c
+++ b/drivers/input/touchscreen/cy8ctmg110_ts.c
@@ -237,7 +237,7 @@ static int cy8ctmg110_probe(struct i2c_client *client)
return 0;
}
-static int __maybe_unused cy8ctmg110_suspend(struct device *dev)
+static int cy8ctmg110_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct cy8ctmg110 *ts = i2c_get_clientdata(client);
@@ -250,7 +250,7 @@ static int __maybe_unused cy8ctmg110_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused cy8ctmg110_resume(struct device *dev)
+static int cy8ctmg110_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct cy8ctmg110 *ts = i2c_get_clientdata(client);
@@ -263,7 +263,8 @@ static int __maybe_unused cy8ctmg110_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(cy8ctmg110_pm, cy8ctmg110_suspend, cy8ctmg110_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(cy8ctmg110_pm,
+ cy8ctmg110_suspend, cy8ctmg110_resume);
static const struct i2c_device_id cy8ctmg110_idtable[] = {
{ CY8CTMG110_DRIVER_NAME, 1 },
@@ -275,7 +276,7 @@ MODULE_DEVICE_TABLE(i2c, cy8ctmg110_idtable);
static struct i2c_driver cy8ctmg110_driver = {
.driver = {
.name = CY8CTMG110_DRIVER_NAME,
- .pm = &cy8ctmg110_pm,
+ .pm = pm_sleep_ptr(&cy8ctmg110_pm),
},
.id_table = cy8ctmg110_idtable,
.probe_new = cy8ctmg110_probe,
diff --git a/drivers/input/touchscreen/cyttsp4_core.c b/drivers/input/touchscreen/cyttsp4_core.c
index dccbcb942fe5..0cd6f626adec 100644
--- a/drivers/input/touchscreen/cyttsp4_core.c
+++ b/drivers/input/touchscreen/cyttsp4_core.c
@@ -1744,7 +1744,6 @@ static void cyttsp4_free_si_ptrs(struct cyttsp4 *cd)
kfree(si->btn_rec_data);
}
-#ifdef CONFIG_PM
static int cyttsp4_core_sleep(struct cyttsp4 *cd)
{
int rc;
@@ -1877,13 +1876,9 @@ static int cyttsp4_core_resume(struct device *dev)
return 0;
}
-#endif
-const struct dev_pm_ops cyttsp4_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(cyttsp4_core_suspend, cyttsp4_core_resume)
- SET_RUNTIME_PM_OPS(cyttsp4_core_suspend, cyttsp4_core_resume, NULL)
-};
-EXPORT_SYMBOL_GPL(cyttsp4_pm_ops);
+EXPORT_GPL_RUNTIME_DEV_PM_OPS(cyttsp4_pm_ops,
+ cyttsp4_core_suspend, cyttsp4_core_resume, NULL);
static int cyttsp4_mt_open(struct input_dev *input)
{
diff --git a/drivers/input/touchscreen/cyttsp4_i2c.c b/drivers/input/touchscreen/cyttsp4_i2c.c
index c260bab0c62c..ec7a4779f3fb 100644
--- a/drivers/input/touchscreen/cyttsp4_i2c.c
+++ b/drivers/input/touchscreen/cyttsp4_i2c.c
@@ -58,7 +58,7 @@ MODULE_DEVICE_TABLE(i2c, cyttsp4_i2c_id);
static struct i2c_driver cyttsp4_i2c_driver = {
.driver = {
.name = CYTTSP4_I2C_NAME,
- .pm = &cyttsp4_pm_ops,
+ .pm = pm_ptr(&cyttsp4_pm_ops),
},
.probe_new = cyttsp4_i2c_probe,
.remove = cyttsp4_i2c_remove,
diff --git a/drivers/input/touchscreen/cyttsp4_spi.c b/drivers/input/touchscreen/cyttsp4_spi.c
index 5d7db84f2749..944fbbe9113e 100644
--- a/drivers/input/touchscreen/cyttsp4_spi.c
+++ b/drivers/input/touchscreen/cyttsp4_spi.c
@@ -173,7 +173,7 @@ static void cyttsp4_spi_remove(struct spi_device *spi)
static struct spi_driver cyttsp4_spi_driver = {
.driver = {
.name = CYTTSP4_SPI_NAME,
- .pm = &cyttsp4_pm_ops,
+ .pm = pm_ptr(&cyttsp4_pm_ops),
},
.probe = cyttsp4_spi_probe,
.remove = cyttsp4_spi_remove,
diff --git a/drivers/input/touchscreen/cyttsp5.c b/drivers/input/touchscreen/cyttsp5.c
index 4a23d6231382..16caffa35dd9 100644
--- a/drivers/input/touchscreen/cyttsp5.c
+++ b/drivers/input/touchscreen/cyttsp5.c
@@ -29,7 +29,7 @@
#define CY_MAX_INPUT 512
#define CYTTSP5_PREALLOCATED_CMD_BUFFER 32
#define CY_BITS_PER_BTN 1
-#define CY_NUM_BTN_EVENT_ID GENMASK(CY_BITS_PER_BTN, 0)
+#define CY_NUM_BTN_EVENT_ID GENMASK(CY_BITS_PER_BTN - 1, 0)
#define MAX_AREA 255
#define HID_OUTPUT_BL_SOP 0x1
diff --git a/drivers/input/touchscreen/cyttsp_core.c b/drivers/input/touchscreen/cyttsp_core.c
index 1dbd849c9613..132ed5786e84 100644
--- a/drivers/input/touchscreen/cyttsp_core.c
+++ b/drivers/input/touchscreen/cyttsp_core.c
@@ -491,7 +491,7 @@ static int cyttsp_disable(struct cyttsp *ts)
return 0;
}
-static int __maybe_unused cyttsp_suspend(struct device *dev)
+static int cyttsp_suspend(struct device *dev)
{
struct cyttsp *ts = dev_get_drvdata(dev);
int retval = 0;
@@ -509,7 +509,7 @@ static int __maybe_unused cyttsp_suspend(struct device *dev)
return retval;
}
-static int __maybe_unused cyttsp_resume(struct device *dev)
+static int cyttsp_resume(struct device *dev)
{
struct cyttsp *ts = dev_get_drvdata(dev);
@@ -525,8 +525,7 @@ static int __maybe_unused cyttsp_resume(struct device *dev)
return 0;
}
-SIMPLE_DEV_PM_OPS(cyttsp_pm_ops, cyttsp_suspend, cyttsp_resume);
-EXPORT_SYMBOL_GPL(cyttsp_pm_ops);
+EXPORT_GPL_SIMPLE_DEV_PM_OPS(cyttsp_pm_ops, cyttsp_suspend, cyttsp_resume);
static int cyttsp_open(struct input_dev *dev)
{
diff --git a/drivers/input/touchscreen/cyttsp_i2c.c b/drivers/input/touchscreen/cyttsp_i2c.c
index 0155a1626adf..3f91cb43ec82 100644
--- a/drivers/input/touchscreen/cyttsp_i2c.c
+++ b/drivers/input/touchscreen/cyttsp_i2c.c
@@ -63,7 +63,7 @@ MODULE_DEVICE_TABLE(of, cyttsp_of_i2c_match);
static struct i2c_driver cyttsp_i2c_driver = {
.driver = {
.name = CY_I2C_NAME,
- .pm = &cyttsp_pm_ops,
+ .pm = pm_sleep_ptr(&cyttsp_pm_ops),
.of_match_table = cyttsp_of_i2c_match,
},
.probe_new = cyttsp_i2c_probe,
diff --git a/drivers/input/touchscreen/cyttsp_spi.c b/drivers/input/touchscreen/cyttsp_spi.c
index 30c6fbf86a86..ada17f2dadf3 100644
--- a/drivers/input/touchscreen/cyttsp_spi.c
+++ b/drivers/input/touchscreen/cyttsp_spi.c
@@ -172,7 +172,7 @@ MODULE_DEVICE_TABLE(of, cyttsp_of_spi_match);
static struct spi_driver cyttsp_spi_driver = {
.driver = {
.name = CY_SPI_NAME,
- .pm = &cyttsp_pm_ops,
+ .pm = pm_sleep_ptr(&cyttsp_pm_ops),
.of_match_table = cyttsp_of_spi_match,
},
.probe = cyttsp_spi_probe,
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c
index ddd0f1f62458..2746649561c7 100644
--- a/drivers/input/touchscreen/edt-ft5x06.c
+++ b/drivers/input/touchscreen/edt-ft5x06.c
@@ -931,7 +931,7 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
} else {
/* If it is not an EDT M06/M12 touchscreen, then the model
* detection is a bit hairy. The different ft5x06
- * firmares around don't reliably implement the
+ * firmwares around don't reliably implement the
* identification registers. Well, we'll take a shot.
*
* The main difference between generic focaltec based
@@ -1353,7 +1353,7 @@ static void edt_ft5x06_ts_remove(struct i2c_client *client)
edt_ft5x06_ts_teardown_debugfs(tsdata);
}
-static int __maybe_unused edt_ft5x06_ts_suspend(struct device *dev)
+static int edt_ft5x06_ts_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
@@ -1396,7 +1396,7 @@ static int __maybe_unused edt_ft5x06_ts_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused edt_ft5x06_ts_resume(struct device *dev)
+static int edt_ft5x06_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
@@ -1459,8 +1459,8 @@ static int __maybe_unused edt_ft5x06_ts_resume(struct device *dev)
return ret;
}
-static SIMPLE_DEV_PM_OPS(edt_ft5x06_ts_pm_ops,
- edt_ft5x06_ts_suspend, edt_ft5x06_ts_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(edt_ft5x06_ts_pm_ops,
+ edt_ft5x06_ts_suspend, edt_ft5x06_ts_resume);
static const struct edt_i2c_chip_data edt_ft5x06_data = {
.max_support_points = 5,
@@ -1500,7 +1500,7 @@ static struct i2c_driver edt_ft5x06_ts_driver = {
.driver = {
.name = "edt_ft5x06",
.of_match_table = edt_ft5x06_of_match,
- .pm = &edt_ft5x06_ts_pm_ops,
+ .pm = pm_sleep_ptr(&edt_ft5x06_ts_pm_ops),
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
.id_table = edt_ft5x06_ts_id,
diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c
index c8ab03f49227..56fa21688bdb 100644
--- a/drivers/input/touchscreen/eeti_ts.c
+++ b/drivers/input/touchscreen/eeti_ts.c
@@ -232,7 +232,7 @@ static int eeti_ts_probe(struct i2c_client *client)
return 0;
}
-static int __maybe_unused eeti_ts_suspend(struct device *dev)
+static int eeti_ts_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct eeti_ts *eeti = i2c_get_clientdata(client);
@@ -251,7 +251,7 @@ static int __maybe_unused eeti_ts_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused eeti_ts_resume(struct device *dev)
+static int eeti_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct eeti_ts *eeti = i2c_get_clientdata(client);
@@ -270,7 +270,7 @@ static int __maybe_unused eeti_ts_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(eeti_ts_pm, eeti_ts_suspend, eeti_ts_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(eeti_ts_pm, eeti_ts_suspend, eeti_ts_resume);
static const struct i2c_device_id eeti_ts_id[] = {
{ "eeti_ts", 0 },
@@ -288,7 +288,7 @@ static const struct of_device_id of_eeti_ts_match[] = {
static struct i2c_driver eeti_ts_driver = {
.driver = {
.name = "eeti_ts",
- .pm = &eeti_ts_pm,
+ .pm = pm_sleep_ptr(&eeti_ts_pm),
.of_match_table = of_match_ptr(of_eeti_ts_match),
},
.probe_new = eeti_ts_probe,
diff --git a/drivers/input/touchscreen/egalax_ts.c b/drivers/input/touchscreen/egalax_ts.c
index 742d47a75ac1..1a9805938e6d 100644
--- a/drivers/input/touchscreen/egalax_ts.c
+++ b/drivers/input/touchscreen/egalax_ts.c
@@ -223,7 +223,7 @@ static const struct i2c_device_id egalax_ts_id[] = {
};
MODULE_DEVICE_TABLE(i2c, egalax_ts_id);
-static int __maybe_unused egalax_ts_suspend(struct device *dev)
+static int egalax_ts_suspend(struct device *dev)
{
static const u8 suspend_cmd[MAX_I2C_DATA_LEN] = {
0x3, 0x6, 0xa, 0x3, 0x36, 0x3f, 0x2, 0, 0, 0
@@ -238,7 +238,7 @@ static int __maybe_unused egalax_ts_suspend(struct device *dev)
return ret > 0 ? 0 : ret;
}
-static int __maybe_unused egalax_ts_resume(struct device *dev)
+static int egalax_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -248,7 +248,8 @@ static int __maybe_unused egalax_ts_resume(struct device *dev)
return egalax_wake_up_device(client);
}
-static SIMPLE_DEV_PM_OPS(egalax_ts_pm_ops, egalax_ts_suspend, egalax_ts_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(egalax_ts_pm_ops,
+ egalax_ts_suspend, egalax_ts_resume);
static const struct of_device_id egalax_ts_dt_ids[] = {
{ .compatible = "eeti,egalax_ts" },
@@ -259,7 +260,7 @@ MODULE_DEVICE_TABLE(of, egalax_ts_dt_ids);
static struct i2c_driver egalax_ts_driver = {
.driver = {
.name = "egalax_ts",
- .pm = &egalax_ts_pm_ops,
+ .pm = pm_sleep_ptr(&egalax_ts_pm_ops),
.of_match_table = egalax_ts_dt_ids,
},
.id_table = egalax_ts_id,
diff --git a/drivers/input/touchscreen/ektf2127.c b/drivers/input/touchscreen/ektf2127.c
index 328841eaa1b7..e6f1e46d003d 100644
--- a/drivers/input/touchscreen/ektf2127.c
+++ b/drivers/input/touchscreen/ektf2127.c
@@ -177,7 +177,7 @@ static void ektf2127_stop(struct input_dev *dev)
gpiod_set_value_cansleep(ts->power_gpios, 0);
}
-static int __maybe_unused ektf2127_suspend(struct device *dev)
+static int ektf2127_suspend(struct device *dev)
{
struct ektf2127_ts *ts = i2c_get_clientdata(to_i2c_client(dev));
@@ -189,7 +189,7 @@ static int __maybe_unused ektf2127_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused ektf2127_resume(struct device *dev)
+static int ektf2127_resume(struct device *dev)
{
struct ektf2127_ts *ts = i2c_get_clientdata(to_i2c_client(dev));
@@ -201,8 +201,8 @@ static int __maybe_unused ektf2127_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(ektf2127_pm_ops, ektf2127_suspend,
- ektf2127_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(ektf2127_pm_ops, ektf2127_suspend,
+ ektf2127_resume);
static int ektf2127_query_dimension(struct i2c_client *client, bool width)
{
@@ -348,7 +348,7 @@ MODULE_DEVICE_TABLE(i2c, ektf2127_i2c_id);
static struct i2c_driver ektf2127_driver = {
.driver = {
.name = "elan_ektf2127",
- .pm = &ektf2127_pm_ops,
+ .pm = pm_sleep_ptr(&ektf2127_pm_ops),
.of_match_table = of_match_ptr(ektf2127_of_match),
},
.probe_new = ektf2127_probe,
diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c
index 5452b50f8a77..8a16eb51481f 100644
--- a/drivers/input/touchscreen/elants_i2c.c
+++ b/drivers/input/touchscreen/elants_i2c.c
@@ -1572,7 +1572,7 @@ static int elants_i2c_probe(struct i2c_client *client)
return 0;
}
-static int __maybe_unused elants_i2c_suspend(struct device *dev)
+static int elants_i2c_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct elants_data *ts = i2c_get_clientdata(client);
@@ -1611,7 +1611,7 @@ static int __maybe_unused elants_i2c_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused elants_i2c_resume(struct device *dev)
+static int elants_i2c_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct elants_data *ts = i2c_get_clientdata(client);
@@ -1644,8 +1644,8 @@ static int __maybe_unused elants_i2c_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(elants_i2c_pm_ops,
- elants_i2c_suspend, elants_i2c_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(elants_i2c_pm_ops,
+ elants_i2c_suspend, elants_i2c_resume);
static const struct i2c_device_id elants_i2c_id[] = {
{ DEVICE_NAME, EKTH3500 },
@@ -1677,7 +1677,7 @@ static struct i2c_driver elants_i2c_driver = {
.id_table = elants_i2c_id,
.driver = {
.name = DEVICE_NAME,
- .pm = &elants_i2c_pm_ops,
+ .pm = pm_sleep_ptr(&elants_i2c_pm_ops),
.acpi_match_table = ACPI_PTR(elants_acpi_id),
.of_match_table = of_match_ptr(elants_of_match),
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
diff --git a/drivers/input/touchscreen/exc3000.c b/drivers/input/touchscreen/exc3000.c
index 4b7eee01c6aa..69eae79e2087 100644
--- a/drivers/input/touchscreen/exc3000.c
+++ b/drivers/input/touchscreen/exc3000.c
@@ -109,6 +109,11 @@ static inline void exc3000_schedule_timer(struct exc3000_data *data)
mod_timer(&data->timer, jiffies + msecs_to_jiffies(EXC3000_TIMEOUT_MS));
}
+static void exc3000_shutdown_timer(void *timer)
+{
+ timer_shutdown_sync(timer);
+}
+
static int exc3000_read_frame(struct exc3000_data *data, u8 *buf)
{
struct i2c_client *client = data->client;
@@ -386,6 +391,11 @@ static int exc3000_probe(struct i2c_client *client)
if (error)
return error;
+ error = devm_add_action_or_reset(&client->dev, exc3000_shutdown_timer,
+ &data->timer);
+ if (error)
+ return error;
+
error = devm_request_threaded_irq(&client->dev, client->irq,
NULL, exc3000_interrupt, IRQF_ONESHOT,
client->name, data);
diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c
index 8a0a8078de8f..b348172f19c3 100644
--- a/drivers/input/touchscreen/goodix.c
+++ b/drivers/input/touchscreen/goodix.c
@@ -1401,7 +1401,7 @@ static void goodix_ts_remove(struct i2c_client *client)
wait_for_completion(&ts->firmware_loading_complete);
}
-static int __maybe_unused goodix_suspend(struct device *dev)
+static int goodix_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct goodix_ts_data *ts = i2c_get_clientdata(client);
@@ -1448,7 +1448,7 @@ static int __maybe_unused goodix_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused goodix_resume(struct device *dev)
+static int goodix_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct goodix_ts_data *ts = i2c_get_clientdata(client);
@@ -1497,7 +1497,7 @@ static int __maybe_unused goodix_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(goodix_pm_ops, goodix_suspend, goodix_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(goodix_pm_ops, goodix_suspend, goodix_resume);
static const struct i2c_device_id goodix_ts_id[] = {
{ "GDIX1001:00", 0 },
@@ -1543,7 +1543,7 @@ static struct i2c_driver goodix_ts_driver = {
.name = "Goodix-TS",
.acpi_match_table = ACPI_PTR(goodix_acpi_match),
.of_match_table = of_match_ptr(goodix_of_match),
- .pm = &goodix_pm_ops,
+ .pm = pm_sleep_ptr(&goodix_pm_ops),
},
};
module_i2c_driver(goodix_ts_driver);
diff --git a/drivers/input/touchscreen/hideep.c b/drivers/input/touchscreen/hideep.c
index ff4bb4c14898..bd454d93f1f7 100644
--- a/drivers/input/touchscreen/hideep.c
+++ b/drivers/input/touchscreen/hideep.c
@@ -959,7 +959,7 @@ static const struct attribute_group hideep_ts_attr_group = {
.attrs = hideep_ts_sysfs_entries,
};
-static int __maybe_unused hideep_suspend(struct device *dev)
+static int hideep_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct hideep_ts *ts = i2c_get_clientdata(client);
@@ -970,7 +970,7 @@ static int __maybe_unused hideep_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused hideep_resume(struct device *dev)
+static int hideep_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct hideep_ts *ts = i2c_get_clientdata(client);
@@ -987,7 +987,7 @@ static int __maybe_unused hideep_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(hideep_pm_ops, hideep_suspend, hideep_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(hideep_pm_ops, hideep_suspend, hideep_resume);
static const struct regmap_config hideep_regmap_config = {
.reg_bits = 16,
@@ -1108,7 +1108,7 @@ static struct i2c_driver hideep_driver = {
.name = HIDEEP_I2C_NAME,
.of_match_table = of_match_ptr(hideep_match_table),
.acpi_match_table = ACPI_PTR(hideep_acpi_id),
- .pm = &hideep_pm_ops,
+ .pm = pm_sleep_ptr(&hideep_pm_ops),
},
.id_table = hideep_i2c_id,
.probe_new = hideep_probe,
diff --git a/drivers/input/touchscreen/ilitek_ts_i2c.c b/drivers/input/touchscreen/ilitek_ts_i2c.c
index e6ade3775a8a..d69809338498 100644
--- a/drivers/input/touchscreen/ilitek_ts_i2c.c
+++ b/drivers/input/touchscreen/ilitek_ts_i2c.c
@@ -604,7 +604,7 @@ static int ilitek_ts_i2c_probe(struct i2c_client *client)
return 0;
}
-static int __maybe_unused ilitek_suspend(struct device *dev)
+static int ilitek_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct ilitek_ts_data *ts = i2c_get_clientdata(client);
@@ -621,7 +621,7 @@ static int __maybe_unused ilitek_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused ilitek_resume(struct device *dev)
+static int ilitek_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct ilitek_ts_data *ts = i2c_get_clientdata(client);
@@ -640,7 +640,7 @@ static int __maybe_unused ilitek_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(ilitek_pm_ops, ilitek_suspend, ilitek_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(ilitek_pm_ops, ilitek_suspend, ilitek_resume);
static const struct i2c_device_id ilitek_ts_i2c_id[] = {
{ ILITEK_TS_NAME, 0 },
@@ -675,7 +675,7 @@ MODULE_DEVICE_TABLE(of, ilitek_ts_i2c_match);
static struct i2c_driver ilitek_ts_i2c_driver = {
.driver = {
.name = ILITEK_TS_NAME,
- .pm = &ilitek_pm_ops,
+ .pm = pm_sleep_ptr(&ilitek_pm_ops),
.of_match_table = of_match_ptr(ilitek_ts_i2c_match),
.acpi_match_table = ACPI_PTR(ilitekts_acpi_id),
},
diff --git a/drivers/input/touchscreen/imagis.c b/drivers/input/touchscreen/imagis.c
index e2697e6c6d2a..de1b16e94bb8 100644
--- a/drivers/input/touchscreen/imagis.c
+++ b/drivers/input/touchscreen/imagis.c
@@ -309,7 +309,7 @@ static int imagis_probe(struct i2c_client *i2c)
return 0;
}
-static int __maybe_unused imagis_suspend(struct device *dev)
+static int imagis_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct imagis_ts *ts = i2c_get_clientdata(client);
@@ -325,7 +325,7 @@ static int __maybe_unused imagis_suspend(struct device *dev)
return retval;
}
-static int __maybe_unused imagis_resume(struct device *dev)
+static int imagis_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct imagis_ts *ts = i2c_get_clientdata(client);
@@ -341,7 +341,7 @@ static int __maybe_unused imagis_resume(struct device *dev)
return retval;
}
-static SIMPLE_DEV_PM_OPS(imagis_pm_ops, imagis_suspend, imagis_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(imagis_pm_ops, imagis_suspend, imagis_resume);
#ifdef CONFIG_OF
static const struct of_device_id imagis_of_match[] = {
@@ -354,7 +354,7 @@ MODULE_DEVICE_TABLE(of, imagis_of_match);
static struct i2c_driver imagis_ts_driver = {
.driver = {
.name = "imagis-touchscreen",
- .pm = &imagis_pm_ops,
+ .pm = pm_sleep_ptr(&imagis_pm_ops),
.of_match_table = of_match_ptr(imagis_of_match),
},
.probe_new = imagis_probe,
diff --git a/drivers/input/touchscreen/imx6ul_tsc.c b/drivers/input/touchscreen/imx6ul_tsc.c
index 2d4facf70cdb..6ac8fa84ed9f 100644
--- a/drivers/input/touchscreen/imx6ul_tsc.c
+++ b/drivers/input/touchscreen/imx6ul_tsc.c
@@ -512,7 +512,7 @@ static int imx6ul_tsc_probe(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused imx6ul_tsc_suspend(struct device *dev)
+static int imx6ul_tsc_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct imx6ul_tsc *tsc = platform_get_drvdata(pdev);
@@ -528,7 +528,7 @@ static int __maybe_unused imx6ul_tsc_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused imx6ul_tsc_resume(struct device *dev)
+static int imx6ul_tsc_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct imx6ul_tsc *tsc = platform_get_drvdata(pdev);
@@ -545,8 +545,8 @@ static int __maybe_unused imx6ul_tsc_resume(struct device *dev)
return retval;
}
-static SIMPLE_DEV_PM_OPS(imx6ul_tsc_pm_ops,
- imx6ul_tsc_suspend, imx6ul_tsc_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(imx6ul_tsc_pm_ops,
+ imx6ul_tsc_suspend, imx6ul_tsc_resume);
static const struct of_device_id imx6ul_tsc_match[] = {
{ .compatible = "fsl,imx6ul-tsc", },
@@ -558,7 +558,7 @@ static struct platform_driver imx6ul_tsc_driver = {
.driver = {
.name = "imx6ul-tsc",
.of_match_table = imx6ul_tsc_match,
- .pm = &imx6ul_tsc_pm_ops,
+ .pm = pm_sleep_ptr(&imx6ul_tsc_pm_ops),
},
.probe = imx6ul_tsc_probe,
};
diff --git a/drivers/input/touchscreen/ipaq-micro-ts.c b/drivers/input/touchscreen/ipaq-micro-ts.c
index 0eb5689fe65f..94720c41c9be 100644
--- a/drivers/input/touchscreen/ipaq-micro-ts.c
+++ b/drivers/input/touchscreen/ipaq-micro-ts.c
@@ -119,7 +119,7 @@ static int micro_ts_probe(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused micro_ts_suspend(struct device *dev)
+static int micro_ts_suspend(struct device *dev)
{
struct touchscreen_data *ts = dev_get_drvdata(dev);
@@ -128,7 +128,7 @@ static int __maybe_unused micro_ts_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused micro_ts_resume(struct device *dev)
+static int micro_ts_resume(struct device *dev)
{
struct touchscreen_data *ts = dev_get_drvdata(dev);
struct input_dev *input = ts->input;
@@ -143,14 +143,13 @@ static int __maybe_unused micro_ts_resume(struct device *dev)
return 0;
}
-static const struct dev_pm_ops micro_ts_dev_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(micro_ts_suspend, micro_ts_resume)
-};
+static DEFINE_SIMPLE_DEV_PM_OPS(micro_ts_dev_pm_ops,
+ micro_ts_suspend, micro_ts_resume);
static struct platform_driver micro_ts_device_driver = {
.driver = {
.name = "ipaq-micro-ts",
- .pm = &micro_ts_dev_pm_ops,
+ .pm = pm_sleep_ptr(&micro_ts_dev_pm_ops),
},
.probe = micro_ts_probe,
};
diff --git a/drivers/input/touchscreen/iqs5xx.c b/drivers/input/touchscreen/iqs5xx.c
index dc3137a34f35..c73e9c5c0077 100644
--- a/drivers/input/touchscreen/iqs5xx.c
+++ b/drivers/input/touchscreen/iqs5xx.c
@@ -979,7 +979,7 @@ static const struct attribute_group iqs5xx_attr_group = {
.attrs = iqs5xx_attrs,
};
-static int __maybe_unused iqs5xx_suspend(struct device *dev)
+static int iqs5xx_suspend(struct device *dev)
{
struct iqs5xx_private *iqs5xx = dev_get_drvdata(dev);
struct input_dev *input = iqs5xx->input;
@@ -998,7 +998,7 @@ static int __maybe_unused iqs5xx_suspend(struct device *dev)
return error;
}
-static int __maybe_unused iqs5xx_resume(struct device *dev)
+static int iqs5xx_resume(struct device *dev)
{
struct iqs5xx_private *iqs5xx = dev_get_drvdata(dev);
struct input_dev *input = iqs5xx->input;
@@ -1017,7 +1017,7 @@ static int __maybe_unused iqs5xx_resume(struct device *dev)
return error;
}
-static SIMPLE_DEV_PM_OPS(iqs5xx_pm, iqs5xx_suspend, iqs5xx_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(iqs5xx_pm, iqs5xx_suspend, iqs5xx_resume);
static int iqs5xx_probe(struct i2c_client *client)
{
@@ -1090,7 +1090,7 @@ static struct i2c_driver iqs5xx_i2c_driver = {
.driver = {
.name = "iqs5xx",
.of_match_table = iqs5xx_of_match,
- .pm = &iqs5xx_pm,
+ .pm = pm_sleep_ptr(&iqs5xx_pm),
},
.id_table = iqs5xx_id,
.probe_new = iqs5xx_probe,
diff --git a/drivers/input/touchscreen/mcs5000_ts.c b/drivers/input/touchscreen/mcs5000_ts.c
index ea9517cad695..704e36087ca2 100644
--- a/drivers/input/touchscreen/mcs5000_ts.c
+++ b/drivers/input/touchscreen/mcs5000_ts.c
@@ -241,7 +241,7 @@ static int mcs5000_ts_probe(struct i2c_client *client)
return 0;
}
-static int __maybe_unused mcs5000_ts_suspend(struct device *dev)
+static int mcs5000_ts_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -251,7 +251,7 @@ static int __maybe_unused mcs5000_ts_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused mcs5000_ts_resume(struct device *dev)
+static int mcs5000_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct mcs5000_ts_data *data = i2c_get_clientdata(client);
@@ -262,7 +262,8 @@ static int __maybe_unused mcs5000_ts_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(mcs5000_ts_pm, mcs5000_ts_suspend, mcs5000_ts_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(mcs5000_ts_pm,
+ mcs5000_ts_suspend, mcs5000_ts_resume);
static const struct i2c_device_id mcs5000_ts_id[] = {
{ "mcs5000_ts", 0 },
@@ -274,7 +275,7 @@ static struct i2c_driver mcs5000_ts_driver = {
.probe_new = mcs5000_ts_probe,
.driver = {
.name = "mcs5000_ts",
- .pm = &mcs5000_ts_pm,
+ .pm = pm_sleep_ptr(&mcs5000_ts_pm),
},
.id_table = mcs5000_ts_id,
};
diff --git a/drivers/input/touchscreen/melfas_mip4.c b/drivers/input/touchscreen/melfas_mip4.c
index 4ee8ed4c930c..acdfbdea2b6e 100644
--- a/drivers/input/touchscreen/melfas_mip4.c
+++ b/drivers/input/touchscreen/melfas_mip4.c
@@ -1528,7 +1528,7 @@ static int mip4_probe(struct i2c_client *client)
return 0;
}
-static int __maybe_unused mip4_suspend(struct device *dev)
+static int mip4_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct mip4_ts *ts = i2c_get_clientdata(client);
@@ -1546,7 +1546,7 @@ static int __maybe_unused mip4_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused mip4_resume(struct device *dev)
+static int mip4_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct mip4_ts *ts = i2c_get_clientdata(client);
@@ -1564,7 +1564,7 @@ static int __maybe_unused mip4_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(mip4_pm_ops, mip4_suspend, mip4_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(mip4_pm_ops, mip4_suspend, mip4_resume);
#ifdef CONFIG_OF
static const struct of_device_id mip4_of_match[] = {
@@ -1595,7 +1595,7 @@ static struct i2c_driver mip4_driver = {
.name = MIP4_DEVICE_NAME,
.of_match_table = of_match_ptr(mip4_of_match),
.acpi_match_table = ACPI_PTR(mip4_acpi_match),
- .pm = &mip4_pm_ops,
+ .pm = pm_sleep_ptr(&mip4_pm_ops),
},
};
module_i2c_driver(mip4_driver);
diff --git a/drivers/input/touchscreen/migor_ts.c b/drivers/input/touchscreen/migor_ts.c
index ff0f605f3a3a..69fcc88d4f80 100644
--- a/drivers/input/touchscreen/migor_ts.c
+++ b/drivers/input/touchscreen/migor_ts.c
@@ -186,7 +186,7 @@ static void migor_ts_remove(struct i2c_client *client)
dev_set_drvdata(&client->dev, NULL);
}
-static int __maybe_unused migor_ts_suspend(struct device *dev)
+static int migor_ts_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct migor_ts_priv *priv = i2c_get_clientdata(client);
@@ -197,7 +197,7 @@ static int __maybe_unused migor_ts_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused migor_ts_resume(struct device *dev)
+static int migor_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct migor_ts_priv *priv = i2c_get_clientdata(client);
@@ -208,7 +208,7 @@ static int __maybe_unused migor_ts_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(migor_ts_pm, migor_ts_suspend, migor_ts_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(migor_ts_pm, migor_ts_suspend, migor_ts_resume);
static const struct i2c_device_id migor_ts_id[] = {
{ "migor_ts", 0 },
@@ -219,7 +219,7 @@ MODULE_DEVICE_TABLE(i2c, migor_ts_id);
static struct i2c_driver migor_ts_driver = {
.driver = {
.name = "migor_ts",
- .pm = &migor_ts_pm,
+ .pm = pm_sleep_ptr(&migor_ts_pm),
},
.probe_new = migor_ts_probe,
.remove = migor_ts_remove,
diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c
index 758b669391a7..4dbca1aad89d 100644
--- a/drivers/input/touchscreen/mms114.c
+++ b/drivers/input/touchscreen/mms114.c
@@ -557,7 +557,7 @@ static int mms114_probe(struct i2c_client *client)
return 0;
}
-static int __maybe_unused mms114_suspend(struct device *dev)
+static int mms114_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct mms114_data *data = i2c_get_clientdata(client);
@@ -581,7 +581,7 @@ static int __maybe_unused mms114_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused mms114_resume(struct device *dev)
+static int mms114_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct mms114_data *data = i2c_get_clientdata(client);
@@ -601,7 +601,7 @@ static int __maybe_unused mms114_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(mms114_pm_ops, mms114_suspend, mms114_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(mms114_pm_ops, mms114_suspend, mms114_resume);
static const struct i2c_device_id mms114_id[] = {
{ "mms114", 0 },
@@ -635,7 +635,7 @@ MODULE_DEVICE_TABLE(of, mms114_dt_match);
static struct i2c_driver mms114_driver = {
.driver = {
.name = "mms114",
- .pm = &mms114_pm_ops,
+ .pm = pm_sleep_ptr(&mms114_pm_ops),
.of_match_table = of_match_ptr(mms114_dt_match),
},
.probe_new = mms114_probe,
diff --git a/drivers/input/touchscreen/msg2638.c b/drivers/input/touchscreen/msg2638.c
index 4c0816b09d33..b23db689d995 100644
--- a/drivers/input/touchscreen/msg2638.c
+++ b/drivers/input/touchscreen/msg2638.c
@@ -441,7 +441,7 @@ static int msg2638_ts_probe(struct i2c_client *client)
return 0;
}
-static int __maybe_unused msg2638_suspend(struct device *dev)
+static int msg2638_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct msg2638_ts_data *msg2638 = i2c_get_clientdata(client);
@@ -456,7 +456,7 @@ static int __maybe_unused msg2638_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused msg2638_resume(struct device *dev)
+static int msg2638_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct msg2638_ts_data *msg2638 = i2c_get_clientdata(client);
@@ -472,7 +472,7 @@ static int __maybe_unused msg2638_resume(struct device *dev)
return ret;
}
-static SIMPLE_DEV_PM_OPS(msg2638_pm_ops, msg2638_suspend, msg2638_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(msg2638_pm_ops, msg2638_suspend, msg2638_resume);
static const struct msg_chip_data msg2138_data = {
.irq_handler = msg2138_ts_irq_handler,
@@ -495,7 +495,7 @@ static struct i2c_driver msg2638_ts_driver = {
.probe_new = msg2638_ts_probe,
.driver = {
.name = "MStar-TS",
- .pm = &msg2638_pm_ops,
+ .pm = pm_sleep_ptr(&msg2638_pm_ops),
.of_match_table = msg2638_of_match,
},
};
diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index 7959947a3458..f09f4831bad4 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -405,7 +405,7 @@ static void pixcir_input_close(struct input_dev *dev)
pixcir_stop(ts);
}
-static int __maybe_unused pixcir_i2c_ts_suspend(struct device *dev)
+static int pixcir_i2c_ts_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct pixcir_i2c_ts_data *ts = i2c_get_clientdata(client);
@@ -432,7 +432,7 @@ unlock:
return ret;
}
-static int __maybe_unused pixcir_i2c_ts_resume(struct device *dev)
+static int pixcir_i2c_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct pixcir_i2c_ts_data *ts = i2c_get_clientdata(client);
@@ -459,8 +459,8 @@ unlock:
return ret;
}
-static SIMPLE_DEV_PM_OPS(pixcir_dev_pm_ops,
- pixcir_i2c_ts_suspend, pixcir_i2c_ts_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(pixcir_dev_pm_ops,
+ pixcir_i2c_ts_suspend, pixcir_i2c_ts_resume);
static int pixcir_i2c_ts_probe(struct i2c_client *client)
{
@@ -614,7 +614,7 @@ MODULE_DEVICE_TABLE(of, pixcir_of_match);
static struct i2c_driver pixcir_i2c_ts_driver = {
.driver = {
.name = "pixcir_ts",
- .pm = &pixcir_dev_pm_ops,
+ .pm = pm_sleep_ptr(&pixcir_dev_pm_ops),
.of_match_table = of_match_ptr(pixcir_of_match),
},
.probe_new = pixcir_i2c_ts_probe,
diff --git a/drivers/input/touchscreen/raydium_i2c_ts.c b/drivers/input/touchscreen/raydium_i2c_ts.c
index d690a17240c2..49a06d3876cf 100644
--- a/drivers/input/touchscreen/raydium_i2c_ts.c
+++ b/drivers/input/touchscreen/raydium_i2c_ts.c
@@ -1197,7 +1197,7 @@ static int raydium_i2c_probe(struct i2c_client *client)
return 0;
}
-static void __maybe_unused raydium_enter_sleep(struct i2c_client *client)
+static void raydium_enter_sleep(struct i2c_client *client)
{
static const u8 sleep_cmd[] = { 0x5A, 0xff, 0x00, 0x0f };
int error;
@@ -1209,7 +1209,7 @@ static void __maybe_unused raydium_enter_sleep(struct i2c_client *client)
"sleep command failed: %d\n", error);
}
-static int __maybe_unused raydium_i2c_suspend(struct device *dev)
+static int raydium_i2c_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct raydium_data *ts = i2c_get_clientdata(client);
@@ -1229,7 +1229,7 @@ static int __maybe_unused raydium_i2c_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused raydium_i2c_resume(struct device *dev)
+static int raydium_i2c_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct raydium_data *ts = i2c_get_clientdata(client);
@@ -1246,8 +1246,8 @@ static int __maybe_unused raydium_i2c_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(raydium_i2c_pm_ops,
- raydium_i2c_suspend, raydium_i2c_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(raydium_i2c_pm_ops,
+ raydium_i2c_suspend, raydium_i2c_resume);
static const struct i2c_device_id raydium_i2c_id[] = {
{ "raydium_i2c", 0 },
@@ -1277,7 +1277,7 @@ static struct i2c_driver raydium_i2c_driver = {
.id_table = raydium_i2c_id,
.driver = {
.name = "raydium_ts",
- .pm = &raydium_i2c_pm_ops,
+ .pm = pm_sleep_ptr(&raydium_i2c_pm_ops),
.acpi_match_table = ACPI_PTR(raydium_acpi_id),
.of_match_table = of_match_ptr(raydium_of_match),
},
diff --git a/drivers/input/touchscreen/s6sy761.c b/drivers/input/touchscreen/s6sy761.c
index cc417c03aaca..371cf4848ad5 100644
--- a/drivers/input/touchscreen/s6sy761.c
+++ b/drivers/input/touchscreen/s6sy761.c
@@ -479,7 +479,7 @@ static void s6sy761_remove(struct i2c_client *client)
pm_runtime_disable(&client->dev);
}
-static int __maybe_unused s6sy761_runtime_suspend(struct device *dev)
+static int s6sy761_runtime_suspend(struct device *dev)
{
struct s6sy761_data *sdata = dev_get_drvdata(dev);
@@ -487,7 +487,7 @@ static int __maybe_unused s6sy761_runtime_suspend(struct device *dev)
S6SY761_APPLICATION_MODE, S6SY761_APP_SLEEP);
}
-static int __maybe_unused s6sy761_runtime_resume(struct device *dev)
+static int s6sy761_runtime_resume(struct device *dev)
{
struct s6sy761_data *sdata = dev_get_drvdata(dev);
@@ -495,7 +495,7 @@ static int __maybe_unused s6sy761_runtime_resume(struct device *dev)
S6SY761_APPLICATION_MODE, S6SY761_APP_NORMAL);
}
-static int __maybe_unused s6sy761_suspend(struct device *dev)
+static int s6sy761_suspend(struct device *dev)
{
struct s6sy761_data *sdata = dev_get_drvdata(dev);
@@ -504,7 +504,7 @@ static int __maybe_unused s6sy761_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused s6sy761_resume(struct device *dev)
+static int s6sy761_resume(struct device *dev)
{
struct s6sy761_data *sdata = dev_get_drvdata(dev);
@@ -514,9 +514,8 @@ static int __maybe_unused s6sy761_resume(struct device *dev)
}
static const struct dev_pm_ops s6sy761_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(s6sy761_suspend, s6sy761_resume)
- SET_RUNTIME_PM_OPS(s6sy761_runtime_suspend,
- s6sy761_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(s6sy761_suspend, s6sy761_resume)
+ RUNTIME_PM_OPS(s6sy761_runtime_suspend, s6sy761_runtime_resume, NULL)
};
#ifdef CONFIG_OF
@@ -537,7 +536,7 @@ static struct i2c_driver s6sy761_driver = {
.driver = {
.name = S6SY761_DEV_NAME,
.of_match_table = of_match_ptr(s6sy761_of_match),
- .pm = &s6sy761_pm_ops,
+ .pm = pm_ptr(&s6sy761_pm_ops),
},
.probe_new = s6sy761_probe,
.remove = s6sy761_remove,
diff --git a/drivers/input/touchscreen/silead.c b/drivers/input/touchscreen/silead.c
index 8a7351c4414c..a37fac089010 100644
--- a/drivers/input/touchscreen/silead.c
+++ b/drivers/input/touchscreen/silead.c
@@ -736,7 +736,7 @@ static int silead_ts_probe(struct i2c_client *client)
return 0;
}
-static int __maybe_unused silead_ts_suspend(struct device *dev)
+static int silead_ts_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -745,7 +745,7 @@ static int __maybe_unused silead_ts_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused silead_ts_resume(struct device *dev)
+static int silead_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
bool second_try = false;
@@ -784,7 +784,7 @@ static int __maybe_unused silead_ts_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(silead_ts_pm, silead_ts_suspend, silead_ts_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(silead_ts_pm, silead_ts_suspend, silead_ts_resume);
static const struct i2c_device_id silead_ts_id[] = {
{ "gsl1680", 0 },
@@ -832,7 +832,7 @@ static struct i2c_driver silead_ts_driver = {
.name = SILEAD_TS_NAME,
.acpi_match_table = ACPI_PTR(silead_ts_acpi_match),
.of_match_table = of_match_ptr(silead_ts_of_match),
- .pm = &silead_ts_pm,
+ .pm = pm_sleep_ptr(&silead_ts_pm),
},
};
module_i2c_driver(silead_ts_driver);
diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c
index bd68633dc6c0..f49566dc96f8 100644
--- a/drivers/input/touchscreen/st1232.c
+++ b/drivers/input/touchscreen/st1232.c
@@ -340,7 +340,7 @@ static int st1232_ts_probe(struct i2c_client *client)
return 0;
}
-static int __maybe_unused st1232_ts_suspend(struct device *dev)
+static int st1232_ts_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct st1232_ts_data *ts = i2c_get_clientdata(client);
@@ -353,7 +353,7 @@ static int __maybe_unused st1232_ts_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused st1232_ts_resume(struct device *dev)
+static int st1232_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct st1232_ts_data *ts = i2c_get_clientdata(client);
@@ -366,8 +366,8 @@ static int __maybe_unused st1232_ts_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(st1232_ts_pm_ops,
- st1232_ts_suspend, st1232_ts_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(st1232_ts_pm_ops,
+ st1232_ts_suspend, st1232_ts_resume);
static const struct i2c_device_id st1232_ts_id[] = {
{ ST1232_TS_NAME, (unsigned long)&st1232_chip_info },
@@ -390,7 +390,7 @@ static struct i2c_driver st1232_ts_driver = {
.name = ST1232_TS_NAME,
.of_match_table = st1232_ts_dt_ids,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
- .pm = &st1232_ts_pm_ops,
+ .pm = pm_sleep_ptr(&st1232_ts_pm_ops),
},
};
diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c
index d092e89d40e8..fdbf5e68943c 100644
--- a/drivers/input/touchscreen/stmfts.c
+++ b/drivers/input/touchscreen/stmfts.c
@@ -742,7 +742,7 @@ static void stmfts_remove(struct i2c_client *client)
pm_runtime_disable(&client->dev);
}
-static int __maybe_unused stmfts_runtime_suspend(struct device *dev)
+static int stmfts_runtime_suspend(struct device *dev)
{
struct stmfts_data *sdata = dev_get_drvdata(dev);
int ret;
@@ -754,7 +754,7 @@ static int __maybe_unused stmfts_runtime_suspend(struct device *dev)
return ret;
}
-static int __maybe_unused stmfts_runtime_resume(struct device *dev)
+static int stmfts_runtime_resume(struct device *dev)
{
struct stmfts_data *sdata = dev_get_drvdata(dev);
int ret;
@@ -766,7 +766,7 @@ static int __maybe_unused stmfts_runtime_resume(struct device *dev)
return ret;
}
-static int __maybe_unused stmfts_suspend(struct device *dev)
+static int stmfts_suspend(struct device *dev)
{
struct stmfts_data *sdata = dev_get_drvdata(dev);
@@ -775,7 +775,7 @@ static int __maybe_unused stmfts_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused stmfts_resume(struct device *dev)
+static int stmfts_resume(struct device *dev)
{
struct stmfts_data *sdata = dev_get_drvdata(dev);
@@ -783,8 +783,8 @@ static int __maybe_unused stmfts_resume(struct device *dev)
}
static const struct dev_pm_ops stmfts_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(stmfts_suspend, stmfts_resume)
- SET_RUNTIME_PM_OPS(stmfts_runtime_suspend, stmfts_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(stmfts_suspend, stmfts_resume)
+ RUNTIME_PM_OPS(stmfts_runtime_suspend, stmfts_runtime_resume, NULL)
};
#ifdef CONFIG_OF
@@ -805,7 +805,7 @@ static struct i2c_driver stmfts_driver = {
.driver = {
.name = STMFTS_DEV_NAME,
.of_match_table = of_match_ptr(stmfts_of_match),
- .pm = &stmfts_pm_ops,
+ .pm = pm_ptr(&stmfts_pm_ops),
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
.probe_new = stmfts_probe,
diff --git a/drivers/input/touchscreen/surface3_spi.c b/drivers/input/touchscreen/surface3_spi.c
index 1da23e5585a0..31d140248f2e 100644
--- a/drivers/input/touchscreen/surface3_spi.c
+++ b/drivers/input/touchscreen/surface3_spi.c
@@ -369,7 +369,7 @@ static int surface3_spi_probe(struct spi_device *spi)
return 0;
}
-static int __maybe_unused surface3_spi_suspend(struct device *dev)
+static int surface3_spi_suspend(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
struct surface3_ts_data *data = spi_get_drvdata(spi);
@@ -381,7 +381,7 @@ static int __maybe_unused surface3_spi_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused surface3_spi_resume(struct device *dev)
+static int surface3_spi_resume(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
struct surface3_ts_data *data = spi_get_drvdata(spi);
@@ -393,9 +393,9 @@ static int __maybe_unused surface3_spi_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(surface3_spi_pm_ops,
- surface3_spi_suspend,
- surface3_spi_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(surface3_spi_pm_ops,
+ surface3_spi_suspend,
+ surface3_spi_resume);
#ifdef CONFIG_ACPI
static const struct acpi_device_id surface3_spi_acpi_match[] = {
@@ -409,7 +409,7 @@ static struct spi_driver surface3_spi_driver = {
.driver = {
.name = "Surface3-spi",
.acpi_match_table = ACPI_PTR(surface3_spi_acpi_match),
- .pm = &surface3_spi_pm_ops,
+ .pm = pm_sleep_ptr(&surface3_spi_pm_ops),
},
.probe = surface3_spi_probe,
};
diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c
index f2fb6a9a1a57..decf2d24a115 100644
--- a/drivers/input/touchscreen/ti_am335x_tsc.c
+++ b/drivers/input/touchscreen/ti_am335x_tsc.c
@@ -512,7 +512,7 @@ static int titsc_remove(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused titsc_suspend(struct device *dev)
+static int titsc_suspend(struct device *dev)
{
struct titsc *ts_dev = dev_get_drvdata(dev);
unsigned int idle;
@@ -527,7 +527,7 @@ static int __maybe_unused titsc_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused titsc_resume(struct device *dev)
+static int titsc_resume(struct device *dev)
{
struct titsc *ts_dev = dev_get_drvdata(dev);
@@ -543,7 +543,7 @@ static int __maybe_unused titsc_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(titsc_pm_ops, titsc_suspend, titsc_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(titsc_pm_ops, titsc_suspend, titsc_resume);
static const struct of_device_id ti_tsc_dt_ids[] = {
{ .compatible = "ti,am3359-tsc", },
@@ -556,7 +556,7 @@ static struct platform_driver ti_tsc_driver = {
.remove = titsc_remove,
.driver = {
.name = "TI-am335x-tsc",
- .pm = &titsc_pm_ops,
+ .pm = pm_sleep_ptr(&titsc_pm_ops),
.of_match_table = ti_tsc_dt_ids,
},
};
diff --git a/drivers/input/touchscreen/tsc2004.c b/drivers/input/touchscreen/tsc2004.c
index 575768b587bb..45f39eb20638 100644
--- a/drivers/input/touchscreen/tsc2004.c
+++ b/drivers/input/touchscreen/tsc2004.c
@@ -65,7 +65,7 @@ static struct i2c_driver tsc2004_driver = {
.driver = {
.name = "tsc2004",
.of_match_table = of_match_ptr(tsc2004_of_match),
- .pm = &tsc200x_pm_ops,
+ .pm = pm_sleep_ptr(&tsc200x_pm_ops),
},
.id_table = tsc2004_idtable,
.probe_new = tsc2004_probe,
diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c
index 555dfe98b3c4..b6dfbcfc8c19 100644
--- a/drivers/input/touchscreen/tsc2005.c
+++ b/drivers/input/touchscreen/tsc2005.c
@@ -81,7 +81,7 @@ static struct spi_driver tsc2005_driver = {
.driver = {
.name = "tsc2005",
.of_match_table = of_match_ptr(tsc2005_of_match),
- .pm = &tsc200x_pm_ops,
+ .pm = pm_sleep_ptr(&tsc200x_pm_ops),
},
.probe = tsc2005_probe,
.remove = tsc2005_remove,
diff --git a/drivers/input/touchscreen/tsc200x-core.c b/drivers/input/touchscreen/tsc200x-core.c
index 72c7258b93a5..b799f26fcf8f 100644
--- a/drivers/input/touchscreen/tsc200x-core.c
+++ b/drivers/input/touchscreen/tsc200x-core.c
@@ -588,7 +588,7 @@ void tsc200x_remove(struct device *dev)
}
EXPORT_SYMBOL_GPL(tsc200x_remove);
-static int __maybe_unused tsc200x_suspend(struct device *dev)
+static int tsc200x_suspend(struct device *dev)
{
struct tsc200x *ts = dev_get_drvdata(dev);
@@ -604,7 +604,7 @@ static int __maybe_unused tsc200x_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused tsc200x_resume(struct device *dev)
+static int tsc200x_resume(struct device *dev)
{
struct tsc200x *ts = dev_get_drvdata(dev);
@@ -620,8 +620,7 @@ static int __maybe_unused tsc200x_resume(struct device *dev)
return 0;
}
-SIMPLE_DEV_PM_OPS(tsc200x_pm_ops, tsc200x_suspend, tsc200x_resume);
-EXPORT_SYMBOL_GPL(tsc200x_pm_ops);
+EXPORT_GPL_SIMPLE_DEV_PM_OPS(tsc200x_pm_ops, tsc200x_suspend, tsc200x_resume);
MODULE_AUTHOR("Lauri Leukkunen <lauri.leukkunen@nokia.com>");
MODULE_DESCRIPTION("TSC200x Touchscreen Driver Core");
diff --git a/drivers/input/touchscreen/wacom_i2c.c b/drivers/input/touchscreen/wacom_i2c.c
index c9188ee00c62..a145b9105255 100644
--- a/drivers/input/touchscreen/wacom_i2c.c
+++ b/drivers/input/touchscreen/wacom_i2c.c
@@ -232,7 +232,7 @@ static int wacom_i2c_probe(struct i2c_client *client)
return 0;
}
-static int __maybe_unused wacom_i2c_suspend(struct device *dev)
+static int wacom_i2c_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -241,7 +241,7 @@ static int __maybe_unused wacom_i2c_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused wacom_i2c_resume(struct device *dev)
+static int wacom_i2c_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -250,7 +250,7 @@ static int __maybe_unused wacom_i2c_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(wacom_i2c_pm, wacom_i2c_suspend, wacom_i2c_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(wacom_i2c_pm, wacom_i2c_suspend, wacom_i2c_resume);
static const struct i2c_device_id wacom_i2c_id[] = {
{ "WAC_I2C_EMR", 0 },
@@ -261,7 +261,7 @@ MODULE_DEVICE_TABLE(i2c, wacom_i2c_id);
static struct i2c_driver wacom_i2c_driver = {
.driver = {
.name = "wacom_i2c",
- .pm = &wacom_i2c_pm,
+ .pm = pm_sleep_ptr(&wacom_i2c_pm),
},
.probe_new = wacom_i2c_probe,
diff --git a/drivers/input/touchscreen/wdt87xx_i2c.c b/drivers/input/touchscreen/wdt87xx_i2c.c
index 3f87db5cdca4..771962af3d0a 100644
--- a/drivers/input/touchscreen/wdt87xx_i2c.c
+++ b/drivers/input/touchscreen/wdt87xx_i2c.c
@@ -1113,7 +1113,7 @@ static int wdt87xx_ts_probe(struct i2c_client *client)
return 0;
}
-static int __maybe_unused wdt87xx_suspend(struct device *dev)
+static int wdt87xx_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
int error;
@@ -1132,7 +1132,7 @@ static int __maybe_unused wdt87xx_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused wdt87xx_resume(struct device *dev)
+static int wdt87xx_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
int error;
@@ -1154,7 +1154,7 @@ static int __maybe_unused wdt87xx_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(wdt87xx_pm_ops, wdt87xx_suspend, wdt87xx_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(wdt87xx_pm_ops, wdt87xx_suspend, wdt87xx_resume);
static const struct i2c_device_id wdt87xx_dev_id[] = {
{ WDT87XX_NAME, 0 },
@@ -1173,7 +1173,7 @@ static struct i2c_driver wdt87xx_driver = {
.id_table = wdt87xx_dev_id,
.driver = {
.name = WDT87XX_NAME,
- .pm = &wdt87xx_pm_ops,
+ .pm = pm_sleep_ptr(&wdt87xx_pm_ops),
.acpi_match_table = ACPI_PTR(wdt87xx_acpi_id),
},
};
diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c
index f51ab5614532..ac3b3dd59488 100644
--- a/drivers/input/touchscreen/wm97xx-core.c
+++ b/drivers/input/touchscreen/wm97xx-core.c
@@ -763,7 +763,7 @@ static int wm97xx_mfd_remove(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused wm97xx_suspend(struct device *dev)
+static int wm97xx_suspend(struct device *dev)
{
struct wm97xx *wm = dev_get_drvdata(dev);
u16 reg;
@@ -797,7 +797,7 @@ static int __maybe_unused wm97xx_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused wm97xx_resume(struct device *dev)
+static int wm97xx_resume(struct device *dev)
{
struct wm97xx *wm = dev_get_drvdata(dev);
@@ -833,7 +833,7 @@ static int __maybe_unused wm97xx_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(wm97xx_pm_ops, wm97xx_suspend, wm97xx_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(wm97xx_pm_ops, wm97xx_suspend, wm97xx_resume);
/*
* Machine specific operations
@@ -869,13 +869,13 @@ static struct device_driver wm97xx_driver = {
.owner = THIS_MODULE,
.probe = wm97xx_probe,
.remove = wm97xx_remove,
- .pm = &wm97xx_pm_ops,
+ .pm = pm_sleep_ptr(&wm97xx_pm_ops),
};
static struct platform_driver wm97xx_mfd_driver = {
.driver = {
.name = "wm97xx-ts",
- .pm = &wm97xx_pm_ops,
+ .pm = pm_sleep_ptr(&wm97xx_pm_ops),
},
.probe = wm97xx_mfd_probe,
.remove = wm97xx_mfd_remove,
diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c
index 24e78ca83fa3..76b194285e1c 100644
--- a/drivers/input/touchscreen/zforce_ts.c
+++ b/drivers/input/touchscreen/zforce_ts.c
@@ -608,7 +608,7 @@ static void zforce_input_close(struct input_dev *dev)
return;
}
-static int __maybe_unused zforce_suspend(struct device *dev)
+static int zforce_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct zforce_ts *ts = i2c_get_clientdata(client);
@@ -653,7 +653,7 @@ unlock:
return ret;
}
-static int __maybe_unused zforce_resume(struct device *dev)
+static int zforce_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct zforce_ts *ts = i2c_get_clientdata(client);
@@ -691,7 +691,7 @@ unlock:
return ret;
}
-static SIMPLE_DEV_PM_OPS(zforce_pm_ops, zforce_suspend, zforce_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(zforce_pm_ops, zforce_suspend, zforce_resume);
static void zforce_reset(void *data)
{
@@ -941,7 +941,7 @@ MODULE_DEVICE_TABLE(of, zforce_dt_idtable);
static struct i2c_driver zforce_driver = {
.driver = {
.name = "zforce-ts",
- .pm = &zforce_pm_ops,
+ .pm = pm_sleep_ptr(&zforce_pm_ops),
.of_match_table = of_match_ptr(zforce_dt_idtable),
},
.probe_new = zforce_probe,
diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c
index 52f9e9eaab14..cdf9bcd744db 100644
--- a/drivers/input/touchscreen/zinitix.c
+++ b/drivers/input/touchscreen/zinitix.c
@@ -562,7 +562,7 @@ static int zinitix_ts_probe(struct i2c_client *client)
return 0;
}
-static int __maybe_unused zinitix_suspend(struct device *dev)
+static int zinitix_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct bt541_ts_data *bt541 = i2c_get_clientdata(client);
@@ -577,7 +577,7 @@ static int __maybe_unused zinitix_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused zinitix_resume(struct device *dev)
+static int zinitix_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct bt541_ts_data *bt541 = i2c_get_clientdata(client);
@@ -593,7 +593,7 @@ static int __maybe_unused zinitix_resume(struct device *dev)
return ret;
}
-static SIMPLE_DEV_PM_OPS(zinitix_pm_ops, zinitix_suspend, zinitix_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(zinitix_pm_ops, zinitix_suspend, zinitix_resume);
#ifdef CONFIG_OF
static const struct of_device_id zinitix_of_match[] = {
@@ -620,7 +620,7 @@ static struct i2c_driver zinitix_ts_driver = {
.probe_new = zinitix_ts_probe,
.driver = {
.name = "Zinitix-TS",
- .pm = &zinitix_pm_ops,
+ .pm = pm_sleep_ptr(&zinitix_pm_ops),
.of_match_table = of_match_ptr(zinitix_of_match),
},
};
diff --git a/drivers/interconnect/core.c b/drivers/interconnect/core.c
index 25debded65a8..0f392f59b135 100644
--- a/drivers/interconnect/core.c
+++ b/drivers/interconnect/core.c
@@ -1079,15 +1079,19 @@ void icc_provider_del(struct icc_provider *provider)
}
EXPORT_SYMBOL_GPL(icc_provider_del);
+static const struct of_device_id __maybe_unused ignore_list[] = {
+ { .compatible = "qcom,sc7180-ipa-virt" },
+ { .compatible = "qcom,sc8180x-ipa-virt" },
+ { .compatible = "qcom,sdx55-ipa-virt" },
+ { .compatible = "qcom,sm8150-ipa-virt" },
+ { .compatible = "qcom,sm8250-ipa-virt" },
+ {}
+};
+
static int of_count_icc_providers(struct device_node *np)
{
struct device_node *child;
int count = 0;
- const struct of_device_id __maybe_unused ignore_list[] = {
- { .compatible = "qcom,sc7180-ipa-virt" },
- { .compatible = "qcom,sdx55-ipa-virt" },
- {}
- };
for_each_available_child_of_node(np, child) {
if (of_property_read_bool(child, "#interconnect-cells") &&
diff --git a/drivers/interconnect/qcom/Kconfig b/drivers/interconnect/qcom/Kconfig
index cd689b782f97..92d65c7bda23 100644
--- a/drivers/interconnect/qcom/Kconfig
+++ b/drivers/interconnect/qcom/Kconfig
@@ -92,6 +92,15 @@ config INTERCONNECT_QCOM_RPMH_POSSIBLE
config INTERCONNECT_QCOM_RPMH
tristate
+config INTERCONNECT_QCOM_SA8775P
+ tristate "Qualcomm SA8775P interconnect driver"
+ depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
+ select INTERCONNECT_QCOM_RPMH
+ select INTERCONNECT_QCOM_BCM_VOTER
+ help
+ This is a driver for the Qualcomm Network-on-Chip on sa8775p-based
+ platforms.
+
config INTERCONNECT_QCOM_SC7180
tristate "Qualcomm SC7180 interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
@@ -137,6 +146,15 @@ config INTERCONNECT_QCOM_SDM660
This is a driver for the Qualcomm Network-on-Chip on sdm660-based
platforms.
+config INTERCONNECT_QCOM_SDM670
+ tristate "Qualcomm SDM670 interconnect driver"
+ depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
+ select INTERCONNECT_QCOM_RPMH
+ select INTERCONNECT_QCOM_BCM_VOTER
+ help
+ This is a driver for the Qualcomm Network-on-Chip on sdm670-based
+ platforms.
+
config INTERCONNECT_QCOM_SDM845
tristate "Qualcomm SDM845 interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
diff --git a/drivers/interconnect/qcom/Makefile b/drivers/interconnect/qcom/Makefile
index 3fd4c2713c4a..ab988926433c 100644
--- a/drivers/interconnect/qcom/Makefile
+++ b/drivers/interconnect/qcom/Makefile
@@ -13,11 +13,13 @@ qnoc-qcm2290-objs := qcm2290.o
qnoc-qcs404-objs := qcs404.o
qnoc-qdu1000-objs := qdu1000.o
icc-rpmh-obj := icc-rpmh.o
+qnoc-sa8775p-objs := sa8775p.o
qnoc-sc7180-objs := sc7180.o
qnoc-sc7280-objs := sc7280.o
qnoc-sc8180x-objs := sc8180x.o
qnoc-sc8280xp-objs := sc8280xp.o
qnoc-sdm660-objs := sdm660.o
+qnoc-sdm670-objs := sdm670.o
qnoc-sdm845-objs := sdm845.o
qnoc-sdx55-objs := sdx55.o
qnoc-sdx65-objs := sdx65.o
@@ -39,11 +41,13 @@ obj-$(CONFIG_INTERCONNECT_QCOM_QCM2290) += qnoc-qcm2290.o
obj-$(CONFIG_INTERCONNECT_QCOM_QCS404) += qnoc-qcs404.o
obj-$(CONFIG_INTERCONNECT_QCOM_QDU1000) += qnoc-qdu1000.o
obj-$(CONFIG_INTERCONNECT_QCOM_RPMH) += icc-rpmh.o
+obj-$(CONFIG_INTERCONNECT_QCOM_SA8775P) += qnoc-sa8775p.o
obj-$(CONFIG_INTERCONNECT_QCOM_SC7180) += qnoc-sc7180.o
obj-$(CONFIG_INTERCONNECT_QCOM_SC7280) += qnoc-sc7280.o
obj-$(CONFIG_INTERCONNECT_QCOM_SC8180X) += qnoc-sc8180x.o
obj-$(CONFIG_INTERCONNECT_QCOM_SC8280XP) += qnoc-sc8280xp.o
obj-$(CONFIG_INTERCONNECT_QCOM_SDM660) += qnoc-sdm660.o
+obj-$(CONFIG_INTERCONNECT_QCOM_SDM670) += qnoc-sdm670.o
obj-$(CONFIG_INTERCONNECT_QCOM_SDM845) += qnoc-sdm845.o
obj-$(CONFIG_INTERCONNECT_QCOM_SDX55) += qnoc-sdx55.o
obj-$(CONFIG_INTERCONNECT_QCOM_SDX65) += qnoc-sdx65.o
diff --git a/drivers/interconnect/qcom/sa8775p.c b/drivers/interconnect/qcom/sa8775p.c
new file mode 100644
index 000000000000..da21cc31a580
--- /dev/null
+++ b/drivers/interconnect/qcom/sa8775p.c
@@ -0,0 +1,2541 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2023, Linaro Limited
+ */
+
+#include <linux/device.h>
+#include <linux/interconnect.h>
+#include <linux/interconnect-provider.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <dt-bindings/interconnect/qcom,sa8775p-rpmh.h>
+
+#include "bcm-voter.h"
+#include "icc-rpmh.h"
+
+#define SA8775P_MASTER_GPU_TCU 0
+#define SA8775P_MASTER_PCIE_TCU 1
+#define SA8775P_MASTER_SYS_TCU 2
+#define SA8775P_MASTER_APPSS_PROC 3
+#define SA8775P_MASTER_LLCC 4
+#define SA8775P_MASTER_CNOC_LPASS_AG_NOC 5
+#define SA8775P_MASTER_GIC_AHB 6
+#define SA8775P_MASTER_CDSP_NOC_CFG 7
+#define SA8775P_MASTER_CDSPB_NOC_CFG 8
+#define SA8775P_MASTER_QDSS_BAM 9
+#define SA8775P_MASTER_QUP_0 10
+#define SA8775P_MASTER_QUP_1 11
+#define SA8775P_MASTER_QUP_2 12
+#define SA8775P_MASTER_A1NOC_SNOC 13
+#define SA8775P_MASTER_A2NOC_SNOC 14
+#define SA8775P_MASTER_CAMNOC_HF 15
+#define SA8775P_MASTER_CAMNOC_ICP 16
+#define SA8775P_MASTER_CAMNOC_SF 17
+#define SA8775P_MASTER_COMPUTE_NOC 18
+#define SA8775P_MASTER_COMPUTE_NOC_1 19
+#define SA8775P_MASTER_CNOC_A2NOC 20
+#define SA8775P_MASTER_CNOC_DC_NOC 21
+#define SA8775P_MASTER_GEM_NOC_CFG 22
+#define SA8775P_MASTER_GEM_NOC_CNOC 23
+#define SA8775P_MASTER_GEM_NOC_PCIE_SNOC 24
+#define SA8775P_MASTER_GPDSP_SAIL 25
+#define SA8775P_MASTER_GFX3D 26
+#define SA8775P_MASTER_LPASS_ANOC 27
+#define SA8775P_MASTER_MDP0 28
+#define SA8775P_MASTER_MDP1 29
+#define SA8775P_MASTER_MDP_CORE1_0 30
+#define SA8775P_MASTER_MDP_CORE1_1 31
+#define SA8775P_MASTER_MNOC_HF_MEM_NOC 32
+#define SA8775P_MASTER_CNOC_MNOC_HF_CFG 33
+#define SA8775P_MASTER_MNOC_SF_MEM_NOC 34
+#define SA8775P_MASTER_CNOC_MNOC_SF_CFG 35
+#define SA8775P_MASTER_ANOC_PCIE_GEM_NOC 36
+#define SA8775P_MASTER_SNOC_CFG 37
+#define SA8775P_MASTER_SNOC_GC_MEM_NOC 38
+#define SA8775P_MASTER_SNOC_SF_MEM_NOC 39
+#define SA8775P_MASTER_VIDEO_P0 40
+#define SA8775P_MASTER_VIDEO_P1 41
+#define SA8775P_MASTER_VIDEO_PROC 42
+#define SA8775P_MASTER_VIDEO_V_PROC 43
+#define SA8775P_MASTER_QUP_CORE_0 44
+#define SA8775P_MASTER_QUP_CORE_1 45
+#define SA8775P_MASTER_QUP_CORE_2 46
+#define SA8775P_MASTER_QUP_CORE_3 47
+#define SA8775P_MASTER_CRYPTO_CORE0 48
+#define SA8775P_MASTER_CRYPTO_CORE1 49
+#define SA8775P_MASTER_DSP0 50
+#define SA8775P_MASTER_DSP1 51
+#define SA8775P_MASTER_IPA 52
+#define SA8775P_MASTER_LPASS_PROC 53
+#define SA8775P_MASTER_CDSP_PROC 54
+#define SA8775P_MASTER_CDSP_PROC_B 55
+#define SA8775P_MASTER_PIMEM 56
+#define SA8775P_MASTER_QUP_3 57
+#define SA8775P_MASTER_EMAC 58
+#define SA8775P_MASTER_EMAC_1 59
+#define SA8775P_MASTER_GIC 60
+#define SA8775P_MASTER_PCIE_0 61
+#define SA8775P_MASTER_PCIE_1 62
+#define SA8775P_MASTER_QDSS_ETR_0 63
+#define SA8775P_MASTER_QDSS_ETR_1 64
+#define SA8775P_MASTER_SDC 65
+#define SA8775P_MASTER_UFS_CARD 66
+#define SA8775P_MASTER_UFS_MEM 67
+#define SA8775P_MASTER_USB2 68
+#define SA8775P_MASTER_USB3_0 69
+#define SA8775P_MASTER_USB3_1 70
+#define SA8775P_SLAVE_EBI1 512
+#define SA8775P_SLAVE_AHB2PHY_0 513
+#define SA8775P_SLAVE_AHB2PHY_1 514
+#define SA8775P_SLAVE_AHB2PHY_2 515
+#define SA8775P_SLAVE_AHB2PHY_3 516
+#define SA8775P_SLAVE_ANOC_THROTTLE_CFG 517
+#define SA8775P_SLAVE_AOSS 518
+#define SA8775P_SLAVE_APPSS 519
+#define SA8775P_SLAVE_BOOT_ROM 520
+#define SA8775P_SLAVE_CAMERA_CFG 521
+#define SA8775P_SLAVE_CAMERA_NRT_THROTTLE_CFG 522
+#define SA8775P_SLAVE_CAMERA_RT_THROTTLE_CFG 523
+#define SA8775P_SLAVE_CLK_CTL 524
+#define SA8775P_SLAVE_CDSP_CFG 525
+#define SA8775P_SLAVE_CDSP1_CFG 526
+#define SA8775P_SLAVE_RBCPR_CX_CFG 527
+#define SA8775P_SLAVE_RBCPR_MMCX_CFG 528
+#define SA8775P_SLAVE_RBCPR_MX_CFG 529
+#define SA8775P_SLAVE_CPR_NSPCX 530
+#define SA8775P_SLAVE_CRYPTO_0_CFG 531
+#define SA8775P_SLAVE_CX_RDPM 532
+#define SA8775P_SLAVE_DISPLAY_CFG 533
+#define SA8775P_SLAVE_DISPLAY_RT_THROTTLE_CFG 534
+#define SA8775P_SLAVE_DISPLAY1_CFG 535
+#define SA8775P_SLAVE_DISPLAY1_RT_THROTTLE_CFG 536
+#define SA8775P_SLAVE_EMAC_CFG 537
+#define SA8775P_SLAVE_EMAC1_CFG 538
+#define SA8775P_SLAVE_GP_DSP0_CFG 539
+#define SA8775P_SLAVE_GP_DSP1_CFG 540
+#define SA8775P_SLAVE_GPDSP0_THROTTLE_CFG 541
+#define SA8775P_SLAVE_GPDSP1_THROTTLE_CFG 542
+#define SA8775P_SLAVE_GPU_TCU_THROTTLE_CFG 543
+#define SA8775P_SLAVE_GFX3D_CFG 544
+#define SA8775P_SLAVE_HWKM 545
+#define SA8775P_SLAVE_IMEM_CFG 546
+#define SA8775P_SLAVE_IPA_CFG 547
+#define SA8775P_SLAVE_IPC_ROUTER_CFG 548
+#define SA8775P_SLAVE_LLCC_CFG 549
+#define SA8775P_SLAVE_LPASS 550
+#define SA8775P_SLAVE_LPASS_CORE_CFG 551
+#define SA8775P_SLAVE_LPASS_LPI_CFG 552
+#define SA8775P_SLAVE_LPASS_MPU_CFG 553
+#define SA8775P_SLAVE_LPASS_THROTTLE_CFG 554
+#define SA8775P_SLAVE_LPASS_TOP_CFG 555
+#define SA8775P_SLAVE_MX_RDPM 556
+#define SA8775P_SLAVE_MXC_RDPM 557
+#define SA8775P_SLAVE_PCIE_0_CFG 558
+#define SA8775P_SLAVE_PCIE_1_CFG 559
+#define SA8775P_SLAVE_PCIE_RSC_CFG 560
+#define SA8775P_SLAVE_PCIE_TCU_THROTTLE_CFG 561
+#define SA8775P_SLAVE_PCIE_THROTTLE_CFG 562
+#define SA8775P_SLAVE_PDM 563
+#define SA8775P_SLAVE_PIMEM_CFG 564
+#define SA8775P_SLAVE_PKA_WRAPPER_CFG 565
+#define SA8775P_SLAVE_QDSS_CFG 566
+#define SA8775P_SLAVE_QM_CFG 567
+#define SA8775P_SLAVE_QM_MPU_CFG 568
+#define SA8775P_SLAVE_QUP_0 569
+#define SA8775P_SLAVE_QUP_1 570
+#define SA8775P_SLAVE_QUP_2 571
+#define SA8775P_SLAVE_QUP_3 572
+#define SA8775P_SLAVE_SAIL_THROTTLE_CFG 573
+#define SA8775P_SLAVE_SDC1 574
+#define SA8775P_SLAVE_SECURITY 575
+#define SA8775P_SLAVE_SNOC_THROTTLE_CFG 576
+#define SA8775P_SLAVE_TCSR 577
+#define SA8775P_SLAVE_TLMM 578
+#define SA8775P_SLAVE_TSC_CFG 579
+#define SA8775P_SLAVE_UFS_CARD_CFG 580
+#define SA8775P_SLAVE_UFS_MEM_CFG 581
+#define SA8775P_SLAVE_USB2 582
+#define SA8775P_SLAVE_USB3_0 583
+#define SA8775P_SLAVE_USB3_1 584
+#define SA8775P_SLAVE_VENUS_CFG 585
+#define SA8775P_SLAVE_VENUS_CVP_THROTTLE_CFG 586
+#define SA8775P_SLAVE_VENUS_V_CPU_THROTTLE_CFG 587
+#define SA8775P_SLAVE_VENUS_VCODEC_THROTTLE_CFG 588
+#define SA8775P_SLAVE_A1NOC_SNOC 589
+#define SA8775P_SLAVE_A2NOC_SNOC 590
+#define SA8775P_SLAVE_DDRSS_CFG 591
+#define SA8775P_SLAVE_GEM_NOC_CNOC 592
+#define SA8775P_SLAVE_GEM_NOC_CFG 593
+#define SA8775P_SLAVE_SNOC_GEM_NOC_GC 594
+#define SA8775P_SLAVE_SNOC_GEM_NOC_SF 595
+#define SA8775P_SLAVE_GP_DSP_SAIL_NOC 596
+#define SA8775P_SLAVE_GPDSP_NOC_CFG 597
+#define SA8775P_SLAVE_HCP_A 598
+#define SA8775P_SLAVE_LLCC 599
+#define SA8775P_SLAVE_MNOC_HF_MEM_NOC 600
+#define SA8775P_SLAVE_MNOC_SF_MEM_NOC 601
+#define SA8775P_SLAVE_CNOC_MNOC_HF_CFG 602
+#define SA8775P_SLAVE_CNOC_MNOC_SF_CFG 603
+#define SA8775P_SLAVE_CDSP_MEM_NOC 604
+#define SA8775P_SLAVE_CDSPB_MEM_NOC 605
+#define SA8775P_SLAVE_HCP_B 606
+#define SA8775P_SLAVE_GEM_NOC_PCIE_CNOC 607
+#define SA8775P_SLAVE_PCIE_ANOC_CFG 608
+#define SA8775P_SLAVE_ANOC_PCIE_GEM_NOC 609
+#define SA8775P_SLAVE_SNOC_CFG 610
+#define SA8775P_SLAVE_LPASS_SNOC 611
+#define SA8775P_SLAVE_QUP_CORE_0 612
+#define SA8775P_SLAVE_QUP_CORE_1 613
+#define SA8775P_SLAVE_QUP_CORE_2 614
+#define SA8775P_SLAVE_QUP_CORE_3 615
+#define SA8775P_SLAVE_BOOT_IMEM 616
+#define SA8775P_SLAVE_IMEM 617
+#define SA8775P_SLAVE_PIMEM 618
+#define SA8775P_SLAVE_SERVICE_NSP_NOC 619
+#define SA8775P_SLAVE_SERVICE_NSPB_NOC 620
+#define SA8775P_SLAVE_SERVICE_GEM_NOC_1 621
+#define SA8775P_SLAVE_SERVICE_MNOC_HF 622
+#define SA8775P_SLAVE_SERVICE_MNOC_SF 623
+#define SA8775P_SLAVE_SERVICES_LPASS_AML_NOC 624
+#define SA8775P_SLAVE_SERVICE_LPASS_AG_NOC 625
+#define SA8775P_SLAVE_SERVICE_GEM_NOC_2 626
+#define SA8775P_SLAVE_SERVICE_SNOC 627
+#define SA8775P_SLAVE_SERVICE_GEM_NOC 628
+#define SA8775P_SLAVE_SERVICE_GEM_NOC2 629
+#define SA8775P_SLAVE_PCIE_0 630
+#define SA8775P_SLAVE_PCIE_1 631
+#define SA8775P_SLAVE_QDSS_STM 632
+#define SA8775P_SLAVE_TCU 633
+
+static struct qcom_icc_node qxm_qup3 = {
+ .name = "qxm_qup3",
+ .id = SA8775P_MASTER_QUP_3,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_A1NOC_SNOC },
+};
+
+static struct qcom_icc_node xm_emac_0 = {
+ .name = "xm_emac_0",
+ .id = SA8775P_MASTER_EMAC,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_A1NOC_SNOC },
+};
+
+static struct qcom_icc_node xm_emac_1 = {
+ .name = "xm_emac_1",
+ .id = SA8775P_MASTER_EMAC_1,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_A1NOC_SNOC },
+};
+
+static struct qcom_icc_node xm_sdc1 = {
+ .name = "xm_sdc1",
+ .id = SA8775P_MASTER_SDC,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_A1NOC_SNOC },
+};
+
+static struct qcom_icc_node xm_ufs_mem = {
+ .name = "xm_ufs_mem",
+ .id = SA8775P_MASTER_UFS_MEM,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_A1NOC_SNOC },
+};
+
+static struct qcom_icc_node xm_usb2_2 = {
+ .name = "xm_usb2_2",
+ .id = SA8775P_MASTER_USB2,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_A1NOC_SNOC },
+};
+
+static struct qcom_icc_node xm_usb3_0 = {
+ .name = "xm_usb3_0",
+ .id = SA8775P_MASTER_USB3_0,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_A1NOC_SNOC },
+};
+
+static struct qcom_icc_node xm_usb3_1 = {
+ .name = "xm_usb3_1",
+ .id = SA8775P_MASTER_USB3_1,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_A1NOC_SNOC },
+};
+
+static struct qcom_icc_node qhm_qdss_bam = {
+ .name = "qhm_qdss_bam",
+ .id = SA8775P_MASTER_QDSS_BAM,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_A2NOC_SNOC },
+};
+
+static struct qcom_icc_node qhm_qup0 = {
+ .name = "qhm_qup0",
+ .id = SA8775P_MASTER_QUP_0,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_A2NOC_SNOC },
+};
+
+static struct qcom_icc_node qhm_qup1 = {
+ .name = "qhm_qup1",
+ .id = SA8775P_MASTER_QUP_1,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_A2NOC_SNOC },
+};
+
+static struct qcom_icc_node qhm_qup2 = {
+ .name = "qhm_qup2",
+ .id = SA8775P_MASTER_QUP_2,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_A2NOC_SNOC },
+};
+
+static struct qcom_icc_node qnm_cnoc_datapath = {
+ .name = "qnm_cnoc_datapath",
+ .id = SA8775P_MASTER_CNOC_A2NOC,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_A2NOC_SNOC },
+};
+
+static struct qcom_icc_node qxm_crypto_0 = {
+ .name = "qxm_crypto_0",
+ .id = SA8775P_MASTER_CRYPTO_CORE0,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_A2NOC_SNOC },
+};
+
+static struct qcom_icc_node qxm_crypto_1 = {
+ .name = "qxm_crypto_1",
+ .id = SA8775P_MASTER_CRYPTO_CORE1,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_A2NOC_SNOC },
+};
+
+static struct qcom_icc_node qxm_ipa = {
+ .name = "qxm_ipa",
+ .id = SA8775P_MASTER_IPA,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_A2NOC_SNOC },
+};
+
+static struct qcom_icc_node xm_qdss_etr_0 = {
+ .name = "xm_qdss_etr_0",
+ .id = SA8775P_MASTER_QDSS_ETR_0,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_A2NOC_SNOC },
+};
+
+static struct qcom_icc_node xm_qdss_etr_1 = {
+ .name = "xm_qdss_etr_1",
+ .id = SA8775P_MASTER_QDSS_ETR_1,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_A2NOC_SNOC },
+};
+
+static struct qcom_icc_node xm_ufs_card = {
+ .name = "xm_ufs_card",
+ .id = SA8775P_MASTER_UFS_CARD,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_A2NOC_SNOC },
+};
+
+static struct qcom_icc_node qup0_core_master = {
+ .name = "qup0_core_master",
+ .id = SA8775P_MASTER_QUP_CORE_0,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_QUP_CORE_0 },
+};
+
+static struct qcom_icc_node qup1_core_master = {
+ .name = "qup1_core_master",
+ .id = SA8775P_MASTER_QUP_CORE_1,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_QUP_CORE_1 },
+};
+
+static struct qcom_icc_node qup2_core_master = {
+ .name = "qup2_core_master",
+ .id = SA8775P_MASTER_QUP_CORE_2,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_QUP_CORE_2 },
+};
+
+static struct qcom_icc_node qup3_core_master = {
+ .name = "qup3_core_master",
+ .id = SA8775P_MASTER_QUP_CORE_3,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_QUP_CORE_3 },
+};
+
+static struct qcom_icc_node qnm_gemnoc_cnoc = {
+ .name = "qnm_gemnoc_cnoc",
+ .id = SA8775P_MASTER_GEM_NOC_CNOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 82,
+ .links = { SA8775P_SLAVE_AHB2PHY_0,
+ SA8775P_SLAVE_AHB2PHY_1,
+ SA8775P_SLAVE_AHB2PHY_2,
+ SA8775P_SLAVE_AHB2PHY_3,
+ SA8775P_SLAVE_ANOC_THROTTLE_CFG,
+ SA8775P_SLAVE_AOSS,
+ SA8775P_SLAVE_APPSS,
+ SA8775P_SLAVE_BOOT_ROM,
+ SA8775P_SLAVE_CAMERA_CFG,
+ SA8775P_SLAVE_CAMERA_NRT_THROTTLE_CFG,
+ SA8775P_SLAVE_CAMERA_RT_THROTTLE_CFG,
+ SA8775P_SLAVE_CLK_CTL,
+ SA8775P_SLAVE_CDSP_CFG,
+ SA8775P_SLAVE_CDSP1_CFG,
+ SA8775P_SLAVE_RBCPR_CX_CFG,
+ SA8775P_SLAVE_RBCPR_MMCX_CFG,
+ SA8775P_SLAVE_RBCPR_MX_CFG,
+ SA8775P_SLAVE_CPR_NSPCX,
+ SA8775P_SLAVE_CRYPTO_0_CFG,
+ SA8775P_SLAVE_CX_RDPM,
+ SA8775P_SLAVE_DISPLAY_CFG,
+ SA8775P_SLAVE_DISPLAY_RT_THROTTLE_CFG,
+ SA8775P_SLAVE_DISPLAY1_CFG,
+ SA8775P_SLAVE_DISPLAY1_RT_THROTTLE_CFG,
+ SA8775P_SLAVE_EMAC_CFG,
+ SA8775P_SLAVE_EMAC1_CFG,
+ SA8775P_SLAVE_GP_DSP0_CFG,
+ SA8775P_SLAVE_GP_DSP1_CFG,
+ SA8775P_SLAVE_GPDSP0_THROTTLE_CFG,
+ SA8775P_SLAVE_GPDSP1_THROTTLE_CFG,
+ SA8775P_SLAVE_GPU_TCU_THROTTLE_CFG,
+ SA8775P_SLAVE_GFX3D_CFG,
+ SA8775P_SLAVE_HWKM,
+ SA8775P_SLAVE_IMEM_CFG,
+ SA8775P_SLAVE_IPA_CFG,
+ SA8775P_SLAVE_IPC_ROUTER_CFG,
+ SA8775P_SLAVE_LPASS,
+ SA8775P_SLAVE_LPASS_THROTTLE_CFG,
+ SA8775P_SLAVE_MX_RDPM,
+ SA8775P_SLAVE_MXC_RDPM,
+ SA8775P_SLAVE_PCIE_0_CFG,
+ SA8775P_SLAVE_PCIE_1_CFG,
+ SA8775P_SLAVE_PCIE_RSC_CFG,
+ SA8775P_SLAVE_PCIE_TCU_THROTTLE_CFG,
+ SA8775P_SLAVE_PCIE_THROTTLE_CFG,
+ SA8775P_SLAVE_PDM,
+ SA8775P_SLAVE_PIMEM_CFG,
+ SA8775P_SLAVE_PKA_WRAPPER_CFG,
+ SA8775P_SLAVE_QDSS_CFG,
+ SA8775P_SLAVE_QM_CFG,
+ SA8775P_SLAVE_QM_MPU_CFG,
+ SA8775P_SLAVE_QUP_0,
+ SA8775P_SLAVE_QUP_1,
+ SA8775P_SLAVE_QUP_2,
+ SA8775P_SLAVE_QUP_3,
+ SA8775P_SLAVE_SAIL_THROTTLE_CFG,
+ SA8775P_SLAVE_SDC1,
+ SA8775P_SLAVE_SECURITY,
+ SA8775P_SLAVE_SNOC_THROTTLE_CFG,
+ SA8775P_SLAVE_TCSR,
+ SA8775P_SLAVE_TLMM,
+ SA8775P_SLAVE_TSC_CFG,
+ SA8775P_SLAVE_UFS_CARD_CFG,
+ SA8775P_SLAVE_UFS_MEM_CFG,
+ SA8775P_SLAVE_USB2,
+ SA8775P_SLAVE_USB3_0,
+ SA8775P_SLAVE_USB3_1,
+ SA8775P_SLAVE_VENUS_CFG,
+ SA8775P_SLAVE_VENUS_CVP_THROTTLE_CFG,
+ SA8775P_SLAVE_VENUS_V_CPU_THROTTLE_CFG,
+ SA8775P_SLAVE_VENUS_VCODEC_THROTTLE_CFG,
+ SA8775P_SLAVE_DDRSS_CFG,
+ SA8775P_SLAVE_GPDSP_NOC_CFG,
+ SA8775P_SLAVE_CNOC_MNOC_HF_CFG,
+ SA8775P_SLAVE_CNOC_MNOC_SF_CFG,
+ SA8775P_SLAVE_PCIE_ANOC_CFG,
+ SA8775P_SLAVE_SNOC_CFG,
+ SA8775P_SLAVE_BOOT_IMEM,
+ SA8775P_SLAVE_IMEM,
+ SA8775P_SLAVE_PIMEM,
+ SA8775P_SLAVE_QDSS_STM,
+ SA8775P_SLAVE_TCU
+ },
+};
+
+static struct qcom_icc_node qnm_gemnoc_pcie = {
+ .name = "qnm_gemnoc_pcie",
+ .id = SA8775P_MASTER_GEM_NOC_PCIE_SNOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 2,
+ .links = { SA8775P_SLAVE_PCIE_0,
+ SA8775P_SLAVE_PCIE_1
+ },
+};
+
+static struct qcom_icc_node qnm_cnoc_dc_noc = {
+ .name = "qnm_cnoc_dc_noc",
+ .id = SA8775P_MASTER_CNOC_DC_NOC,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 2,
+ .links = { SA8775P_SLAVE_LLCC_CFG,
+ SA8775P_SLAVE_GEM_NOC_CFG
+ },
+};
+
+static struct qcom_icc_node alm_gpu_tcu = {
+ .name = "alm_gpu_tcu",
+ .id = SA8775P_MASTER_GPU_TCU,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 2,
+ .links = { SA8775P_SLAVE_GEM_NOC_CNOC,
+ SA8775P_SLAVE_LLCC
+ },
+};
+
+static struct qcom_icc_node alm_pcie_tcu = {
+ .name = "alm_pcie_tcu",
+ .id = SA8775P_MASTER_PCIE_TCU,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 2,
+ .links = { SA8775P_SLAVE_GEM_NOC_CNOC,
+ SA8775P_SLAVE_LLCC
+ },
+};
+
+static struct qcom_icc_node alm_sys_tcu = {
+ .name = "alm_sys_tcu",
+ .id = SA8775P_MASTER_SYS_TCU,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 2,
+ .links = { SA8775P_SLAVE_GEM_NOC_CNOC,
+ SA8775P_SLAVE_LLCC
+ },
+};
+
+static struct qcom_icc_node chm_apps = {
+ .name = "chm_apps",
+ .id = SA8775P_MASTER_APPSS_PROC,
+ .channels = 4,
+ .buswidth = 32,
+ .num_links = 3,
+ .links = { SA8775P_SLAVE_GEM_NOC_CNOC,
+ SA8775P_SLAVE_LLCC,
+ SA8775P_SLAVE_GEM_NOC_PCIE_CNOC
+ },
+};
+
+static struct qcom_icc_node qnm_cmpnoc0 = {
+ .name = "qnm_cmpnoc0",
+ .id = SA8775P_MASTER_COMPUTE_NOC,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 2,
+ .links = { SA8775P_SLAVE_GEM_NOC_CNOC,
+ SA8775P_SLAVE_LLCC
+ },
+};
+
+static struct qcom_icc_node qnm_cmpnoc1 = {
+ .name = "qnm_cmpnoc1",
+ .id = SA8775P_MASTER_COMPUTE_NOC_1,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 2,
+ .links = { SA8775P_SLAVE_GEM_NOC_CNOC,
+ SA8775P_SLAVE_LLCC
+ },
+};
+
+static struct qcom_icc_node qnm_gemnoc_cfg = {
+ .name = "qnm_gemnoc_cfg",
+ .id = SA8775P_MASTER_GEM_NOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 4,
+ .links = { SA8775P_SLAVE_SERVICE_GEM_NOC_1,
+ SA8775P_SLAVE_SERVICE_GEM_NOC_2,
+ SA8775P_SLAVE_SERVICE_GEM_NOC,
+ SA8775P_SLAVE_SERVICE_GEM_NOC2
+ },
+};
+
+static struct qcom_icc_node qnm_gpdsp_sail = {
+ .name = "qnm_gpdsp_sail",
+ .id = SA8775P_MASTER_GPDSP_SAIL,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 2,
+ .links = { SA8775P_SLAVE_GEM_NOC_CNOC,
+ SA8775P_SLAVE_LLCC
+ },
+};
+
+static struct qcom_icc_node qnm_gpu = {
+ .name = "qnm_gpu",
+ .id = SA8775P_MASTER_GFX3D,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 2,
+ .links = { SA8775P_SLAVE_GEM_NOC_CNOC,
+ SA8775P_SLAVE_LLCC
+ },
+};
+
+static struct qcom_icc_node qnm_mnoc_hf = {
+ .name = "qnm_mnoc_hf",
+ .id = SA8775P_MASTER_MNOC_HF_MEM_NOC,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 2,
+ .links = { SA8775P_SLAVE_LLCC,
+ SA8775P_SLAVE_GEM_NOC_PCIE_CNOC
+ },
+};
+
+static struct qcom_icc_node qnm_mnoc_sf = {
+ .name = "qnm_mnoc_sf",
+ .id = SA8775P_MASTER_MNOC_SF_MEM_NOC,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 3,
+ .links = { SA8775P_SLAVE_GEM_NOC_CNOC,
+ SA8775P_SLAVE_LLCC,
+ SA8775P_SLAVE_GEM_NOC_PCIE_CNOC
+ },
+};
+
+static struct qcom_icc_node qnm_pcie = {
+ .name = "qnm_pcie",
+ .id = SA8775P_MASTER_ANOC_PCIE_GEM_NOC,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 2,
+ .links = { SA8775P_SLAVE_GEM_NOC_CNOC,
+ SA8775P_SLAVE_LLCC
+ },
+};
+
+static struct qcom_icc_node qnm_snoc_gc = {
+ .name = "qnm_snoc_gc",
+ .id = SA8775P_MASTER_SNOC_GC_MEM_NOC,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_LLCC },
+};
+
+static struct qcom_icc_node qnm_snoc_sf = {
+ .name = "qnm_snoc_sf",
+ .id = SA8775P_MASTER_SNOC_SF_MEM_NOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 3,
+ .links = { SA8775P_SLAVE_GEM_NOC_CNOC,
+ SA8775P_SLAVE_LLCC,
+ SA8775P_SLAVE_GEM_NOC_PCIE_CNOC },
+};
+
+static struct qcom_icc_node qxm_dsp0 = {
+ .name = "qxm_dsp0",
+ .id = SA8775P_MASTER_DSP0,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_GP_DSP_SAIL_NOC },
+};
+
+static struct qcom_icc_node qxm_dsp1 = {
+ .name = "qxm_dsp1",
+ .id = SA8775P_MASTER_DSP1,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_GP_DSP_SAIL_NOC },
+};
+
+static struct qcom_icc_node qhm_config_noc = {
+ .name = "qhm_config_noc",
+ .id = SA8775P_MASTER_CNOC_LPASS_AG_NOC,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 6,
+ .links = { SA8775P_SLAVE_LPASS_CORE_CFG,
+ SA8775P_SLAVE_LPASS_LPI_CFG,
+ SA8775P_SLAVE_LPASS_MPU_CFG,
+ SA8775P_SLAVE_LPASS_TOP_CFG,
+ SA8775P_SLAVE_SERVICES_LPASS_AML_NOC,
+ SA8775P_SLAVE_SERVICE_LPASS_AG_NOC
+ },
+};
+
+static struct qcom_icc_node qxm_lpass_dsp = {
+ .name = "qxm_lpass_dsp",
+ .id = SA8775P_MASTER_LPASS_PROC,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 4,
+ .links = { SA8775P_SLAVE_LPASS_TOP_CFG,
+ SA8775P_SLAVE_LPASS_SNOC,
+ SA8775P_SLAVE_SERVICES_LPASS_AML_NOC,
+ SA8775P_SLAVE_SERVICE_LPASS_AG_NOC
+ },
+};
+
+static struct qcom_icc_node llcc_mc = {
+ .name = "llcc_mc",
+ .id = SA8775P_MASTER_LLCC,
+ .channels = 8,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_EBI1 },
+};
+
+static struct qcom_icc_node qnm_camnoc_hf = {
+ .name = "qnm_camnoc_hf",
+ .id = SA8775P_MASTER_CAMNOC_HF,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_MNOC_HF_MEM_NOC },
+};
+
+static struct qcom_icc_node qnm_camnoc_icp = {
+ .name = "qnm_camnoc_icp",
+ .id = SA8775P_MASTER_CAMNOC_ICP,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qnm_camnoc_sf = {
+ .name = "qnm_camnoc_sf",
+ .id = SA8775P_MASTER_CAMNOC_SF,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qnm_mdp0_0 = {
+ .name = "qnm_mdp0_0",
+ .id = SA8775P_MASTER_MDP0,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_MNOC_HF_MEM_NOC },
+};
+
+static struct qcom_icc_node qnm_mdp0_1 = {
+ .name = "qnm_mdp0_1",
+ .id = SA8775P_MASTER_MDP1,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_MNOC_HF_MEM_NOC },
+};
+
+static struct qcom_icc_node qnm_mdp1_0 = {
+ .name = "qnm_mdp1_0",
+ .id = SA8775P_MASTER_MDP_CORE1_0,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_MNOC_HF_MEM_NOC },
+};
+
+static struct qcom_icc_node qnm_mdp1_1 = {
+ .name = "qnm_mdp1_1",
+ .id = SA8775P_MASTER_MDP_CORE1_1,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_MNOC_HF_MEM_NOC },
+};
+
+static struct qcom_icc_node qnm_mnoc_hf_cfg = {
+ .name = "qnm_mnoc_hf_cfg",
+ .id = SA8775P_MASTER_CNOC_MNOC_HF_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_SERVICE_MNOC_HF },
+};
+
+static struct qcom_icc_node qnm_mnoc_sf_cfg = {
+ .name = "qnm_mnoc_sf_cfg",
+ .id = SA8775P_MASTER_CNOC_MNOC_SF_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_SERVICE_MNOC_SF },
+};
+
+static struct qcom_icc_node qnm_video0 = {
+ .name = "qnm_video0",
+ .id = SA8775P_MASTER_VIDEO_P0,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qnm_video1 = {
+ .name = "qnm_video1",
+ .id = SA8775P_MASTER_VIDEO_P1,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qnm_video_cvp = {
+ .name = "qnm_video_cvp",
+ .id = SA8775P_MASTER_VIDEO_PROC,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qnm_video_v_cpu = {
+ .name = "qnm_video_v_cpu",
+ .id = SA8775P_MASTER_VIDEO_V_PROC,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qhm_nsp_noc_config = {
+ .name = "qhm_nsp_noc_config",
+ .id = SA8775P_MASTER_CDSP_NOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_SERVICE_NSP_NOC },
+};
+
+static struct qcom_icc_node qxm_nsp = {
+ .name = "qxm_nsp",
+ .id = SA8775P_MASTER_CDSP_PROC,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 2,
+ .links = { SA8775P_SLAVE_HCP_A, SLAVE_CDSP_MEM_NOC },
+};
+
+static struct qcom_icc_node qhm_nspb_noc_config = {
+ .name = "qhm_nspb_noc_config",
+ .id = SA8775P_MASTER_CDSPB_NOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_SERVICE_NSPB_NOC },
+};
+
+static struct qcom_icc_node qxm_nspb = {
+ .name = "qxm_nspb",
+ .id = SA8775P_MASTER_CDSP_PROC_B,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 2,
+ .links = { SA8775P_SLAVE_HCP_B, SLAVE_CDSPB_MEM_NOC },
+};
+
+static struct qcom_icc_node xm_pcie3_0 = {
+ .name = "xm_pcie3_0",
+ .id = SA8775P_MASTER_PCIE_0,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_ANOC_PCIE_GEM_NOC },
+};
+
+static struct qcom_icc_node xm_pcie3_1 = {
+ .name = "xm_pcie3_1",
+ .id = SA8775P_MASTER_PCIE_1,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_ANOC_PCIE_GEM_NOC },
+};
+
+static struct qcom_icc_node qhm_gic = {
+ .name = "qhm_gic",
+ .id = SA8775P_MASTER_GIC_AHB,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_SNOC_GEM_NOC_SF },
+};
+
+static struct qcom_icc_node qnm_aggre1_noc = {
+ .name = "qnm_aggre1_noc",
+ .id = SA8775P_MASTER_A1NOC_SNOC,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_SNOC_GEM_NOC_SF },
+};
+
+static struct qcom_icc_node qnm_aggre2_noc = {
+ .name = "qnm_aggre2_noc",
+ .id = SA8775P_MASTER_A2NOC_SNOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_SNOC_GEM_NOC_SF },
+};
+
+static struct qcom_icc_node qnm_lpass_noc = {
+ .name = "qnm_lpass_noc",
+ .id = SA8775P_MASTER_LPASS_ANOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_SNOC_GEM_NOC_SF },
+};
+
+static struct qcom_icc_node qnm_snoc_cfg = {
+ .name = "qnm_snoc_cfg",
+ .id = SA8775P_MASTER_SNOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_SERVICE_SNOC },
+};
+
+static struct qcom_icc_node qxm_pimem = {
+ .name = "qxm_pimem",
+ .id = SA8775P_MASTER_PIMEM,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_SNOC_GEM_NOC_GC },
+};
+
+static struct qcom_icc_node xm_gic = {
+ .name = "xm_gic",
+ .id = SA8775P_MASTER_GIC,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SA8775P_SLAVE_SNOC_GEM_NOC_GC },
+};
+
+static struct qcom_icc_node qns_a1noc_snoc = {
+ .name = "qns_a1noc_snoc",
+ .id = SA8775P_SLAVE_A1NOC_SNOC,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SA8775P_MASTER_A1NOC_SNOC },
+};
+
+static struct qcom_icc_node qns_a2noc_snoc = {
+ .name = "qns_a2noc_snoc",
+ .id = SA8775P_SLAVE_A2NOC_SNOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SA8775P_MASTER_A2NOC_SNOC },
+};
+
+static struct qcom_icc_node qup0_core_slave = {
+ .name = "qup0_core_slave",
+ .id = SA8775P_SLAVE_QUP_CORE_0,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qup1_core_slave = {
+ .name = "qup1_core_slave",
+ .id = SA8775P_SLAVE_QUP_CORE_1,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qup2_core_slave = {
+ .name = "qup2_core_slave",
+ .id = SA8775P_SLAVE_QUP_CORE_2,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qup3_core_slave = {
+ .name = "qup3_core_slave",
+ .id = SA8775P_SLAVE_QUP_CORE_3,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_ahb2phy0 = {
+ .name = "qhs_ahb2phy0",
+ .id = SA8775P_SLAVE_AHB2PHY_0,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_ahb2phy1 = {
+ .name = "qhs_ahb2phy1",
+ .id = SA8775P_SLAVE_AHB2PHY_1,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_ahb2phy2 = {
+ .name = "qhs_ahb2phy2",
+ .id = SA8775P_SLAVE_AHB2PHY_2,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_ahb2phy3 = {
+ .name = "qhs_ahb2phy3",
+ .id = SA8775P_SLAVE_AHB2PHY_3,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_anoc_throttle_cfg = {
+ .name = "qhs_anoc_throttle_cfg",
+ .id = SA8775P_SLAVE_ANOC_THROTTLE_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_aoss = {
+ .name = "qhs_aoss",
+ .id = SA8775P_SLAVE_AOSS,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_apss = {
+ .name = "qhs_apss",
+ .id = SA8775P_SLAVE_APPSS,
+ .channels = 1,
+ .buswidth = 8,
+};
+
+static struct qcom_icc_node qhs_boot_rom = {
+ .name = "qhs_boot_rom",
+ .id = SA8775P_SLAVE_BOOT_ROM,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_camera_cfg = {
+ .name = "qhs_camera_cfg",
+ .id = SA8775P_SLAVE_CAMERA_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_camera_nrt_throttle_cfg = {
+ .name = "qhs_camera_nrt_throttle_cfg",
+ .id = SA8775P_SLAVE_CAMERA_NRT_THROTTLE_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_camera_rt_throttle_cfg = {
+ .name = "qhs_camera_rt_throttle_cfg",
+ .id = SA8775P_SLAVE_CAMERA_RT_THROTTLE_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_clk_ctl = {
+ .name = "qhs_clk_ctl",
+ .id = SA8775P_SLAVE_CLK_CTL,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_compute0_cfg = {
+ .name = "qhs_compute0_cfg",
+ .id = SA8775P_SLAVE_CDSP_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SA8775P_MASTER_CDSP_NOC_CFG },
+};
+
+static struct qcom_icc_node qhs_compute1_cfg = {
+ .name = "qhs_compute1_cfg",
+ .id = SA8775P_SLAVE_CDSP1_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SA8775P_MASTER_CDSPB_NOC_CFG },
+};
+
+static struct qcom_icc_node qhs_cpr_cx = {
+ .name = "qhs_cpr_cx",
+ .id = SA8775P_SLAVE_RBCPR_CX_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_cpr_mmcx = {
+ .name = "qhs_cpr_mmcx",
+ .id = SA8775P_SLAVE_RBCPR_MMCX_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_cpr_mx = {
+ .name = "qhs_cpr_mx",
+ .id = SA8775P_SLAVE_RBCPR_MX_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_cpr_nspcx = {
+ .name = "qhs_cpr_nspcx",
+ .id = SA8775P_SLAVE_CPR_NSPCX,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_crypto0_cfg = {
+ .name = "qhs_crypto0_cfg",
+ .id = SA8775P_SLAVE_CRYPTO_0_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_cx_rdpm = {
+ .name = "qhs_cx_rdpm",
+ .id = SA8775P_SLAVE_CX_RDPM,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_display0_cfg = {
+ .name = "qhs_display0_cfg",
+ .id = SA8775P_SLAVE_DISPLAY_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_display0_rt_throttle_cfg = {
+ .name = "qhs_display0_rt_throttle_cfg",
+ .id = SA8775P_SLAVE_DISPLAY_RT_THROTTLE_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_display1_cfg = {
+ .name = "qhs_display1_cfg",
+ .id = SA8775P_SLAVE_DISPLAY1_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_display1_rt_throttle_cfg = {
+ .name = "qhs_display1_rt_throttle_cfg",
+ .id = SA8775P_SLAVE_DISPLAY1_RT_THROTTLE_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_emac0_cfg = {
+ .name = "qhs_emac0_cfg",
+ .id = SA8775P_SLAVE_EMAC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_emac1_cfg = {
+ .name = "qhs_emac1_cfg",
+ .id = SA8775P_SLAVE_EMAC1_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_gp_dsp0_cfg = {
+ .name = "qhs_gp_dsp0_cfg",
+ .id = SA8775P_SLAVE_GP_DSP0_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_gp_dsp1_cfg = {
+ .name = "qhs_gp_dsp1_cfg",
+ .id = SA8775P_SLAVE_GP_DSP1_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_gpdsp0_throttle_cfg = {
+ .name = "qhs_gpdsp0_throttle_cfg",
+ .id = SA8775P_SLAVE_GPDSP0_THROTTLE_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_gpdsp1_throttle_cfg = {
+ .name = "qhs_gpdsp1_throttle_cfg",
+ .id = SA8775P_SLAVE_GPDSP1_THROTTLE_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_gpu_tcu_throttle_cfg = {
+ .name = "qhs_gpu_tcu_throttle_cfg",
+ .id = SA8775P_SLAVE_GPU_TCU_THROTTLE_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_gpuss_cfg = {
+ .name = "qhs_gpuss_cfg",
+ .id = SA8775P_SLAVE_GFX3D_CFG,
+ .channels = 1,
+ .buswidth = 8,
+};
+
+static struct qcom_icc_node qhs_hwkm = {
+ .name = "qhs_hwkm",
+ .id = SA8775P_SLAVE_HWKM,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_imem_cfg = {
+ .name = "qhs_imem_cfg",
+ .id = SA8775P_SLAVE_IMEM_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_ipa = {
+ .name = "qhs_ipa",
+ .id = SA8775P_SLAVE_IPA_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_ipc_router = {
+ .name = "qhs_ipc_router",
+ .id = SA8775P_SLAVE_IPC_ROUTER_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_lpass_cfg = {
+ .name = "qhs_lpass_cfg",
+ .id = SA8775P_SLAVE_LPASS,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SA8775P_MASTER_CNOC_LPASS_AG_NOC },
+};
+
+static struct qcom_icc_node qhs_lpass_throttle_cfg = {
+ .name = "qhs_lpass_throttle_cfg",
+ .id = SA8775P_SLAVE_LPASS_THROTTLE_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_mx_rdpm = {
+ .name = "qhs_mx_rdpm",
+ .id = SA8775P_SLAVE_MX_RDPM,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_mxc_rdpm = {
+ .name = "qhs_mxc_rdpm",
+ .id = SA8775P_SLAVE_MXC_RDPM,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_pcie0_cfg = {
+ .name = "qhs_pcie0_cfg",
+ .id = SA8775P_SLAVE_PCIE_0_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_pcie1_cfg = {
+ .name = "qhs_pcie1_cfg",
+ .id = SA8775P_SLAVE_PCIE_1_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_pcie_rsc_cfg = {
+ .name = "qhs_pcie_rsc_cfg",
+ .id = SA8775P_SLAVE_PCIE_RSC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_pcie_tcu_throttle_cfg = {
+ .name = "qhs_pcie_tcu_throttle_cfg",
+ .id = SA8775P_SLAVE_PCIE_TCU_THROTTLE_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_pcie_throttle_cfg = {
+ .name = "qhs_pcie_throttle_cfg",
+ .id = SA8775P_SLAVE_PCIE_THROTTLE_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_pdm = {
+ .name = "qhs_pdm",
+ .id = SA8775P_SLAVE_PDM,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_pimem_cfg = {
+ .name = "qhs_pimem_cfg",
+ .id = SA8775P_SLAVE_PIMEM_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_pke_wrapper_cfg = {
+ .name = "qhs_pke_wrapper_cfg",
+ .id = SA8775P_SLAVE_PKA_WRAPPER_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_qdss_cfg = {
+ .name = "qhs_qdss_cfg",
+ .id = SA8775P_SLAVE_QDSS_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_qm_cfg = {
+ .name = "qhs_qm_cfg",
+ .id = SA8775P_SLAVE_QM_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_qm_mpu_cfg = {
+ .name = "qhs_qm_mpu_cfg",
+ .id = SA8775P_SLAVE_QM_MPU_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_qup0 = {
+ .name = "qhs_qup0",
+ .id = SA8775P_SLAVE_QUP_0,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_qup1 = {
+ .name = "qhs_qup1",
+ .id = SA8775P_SLAVE_QUP_1,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_qup2 = {
+ .name = "qhs_qup2",
+ .id = SA8775P_SLAVE_QUP_2,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_qup3 = {
+ .name = "qhs_qup3",
+ .id = SA8775P_SLAVE_QUP_3,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_sail_throttle_cfg = {
+ .name = "qhs_sail_throttle_cfg",
+ .id = SA8775P_SLAVE_SAIL_THROTTLE_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_sdc1 = {
+ .name = "qhs_sdc1",
+ .id = SA8775P_SLAVE_SDC1,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_security = {
+ .name = "qhs_security",
+ .id = SA8775P_SLAVE_SECURITY,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_snoc_throttle_cfg = {
+ .name = "qhs_snoc_throttle_cfg",
+ .id = SA8775P_SLAVE_SNOC_THROTTLE_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_tcsr = {
+ .name = "qhs_tcsr",
+ .id = SA8775P_SLAVE_TCSR,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_tlmm = {
+ .name = "qhs_tlmm",
+ .id = SA8775P_SLAVE_TLMM,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_tsc_cfg = {
+ .name = "qhs_tsc_cfg",
+ .id = SA8775P_SLAVE_TSC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_ufs_card_cfg = {
+ .name = "qhs_ufs_card_cfg",
+ .id = SA8775P_SLAVE_UFS_CARD_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_ufs_mem_cfg = {
+ .name = "qhs_ufs_mem_cfg",
+ .id = SA8775P_SLAVE_UFS_MEM_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_usb2_0 = {
+ .name = "qhs_usb2_0",
+ .id = SA8775P_SLAVE_USB2,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_usb3_0 = {
+ .name = "qhs_usb3_0",
+ .id = SA8775P_SLAVE_USB3_0,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_usb3_1 = {
+ .name = "qhs_usb3_1",
+ .id = SA8775P_SLAVE_USB3_1,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_venus_cfg = {
+ .name = "qhs_venus_cfg",
+ .id = SA8775P_SLAVE_VENUS_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_venus_cvp_throttle_cfg = {
+ .name = "qhs_venus_cvp_throttle_cfg",
+ .id = SA8775P_SLAVE_VENUS_CVP_THROTTLE_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_venus_v_cpu_throttle_cfg = {
+ .name = "qhs_venus_v_cpu_throttle_cfg",
+ .id = SA8775P_SLAVE_VENUS_V_CPU_THROTTLE_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_venus_vcodec_throttle_cfg = {
+ .name = "qhs_venus_vcodec_throttle_cfg",
+ .id = SA8775P_SLAVE_VENUS_VCODEC_THROTTLE_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qns_ddrss_cfg = {
+ .name = "qns_ddrss_cfg",
+ .id = SA8775P_SLAVE_DDRSS_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SA8775P_MASTER_CNOC_DC_NOC },
+};
+
+static struct qcom_icc_node qns_gpdsp_noc_cfg = {
+ .name = "qns_gpdsp_noc_cfg",
+ .id = SA8775P_SLAVE_GPDSP_NOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qns_mnoc_hf_cfg = {
+ .name = "qns_mnoc_hf_cfg",
+ .id = SA8775P_SLAVE_CNOC_MNOC_HF_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SA8775P_MASTER_CNOC_MNOC_HF_CFG },
+};
+
+static struct qcom_icc_node qns_mnoc_sf_cfg = {
+ .name = "qns_mnoc_sf_cfg",
+ .id = SA8775P_SLAVE_CNOC_MNOC_SF_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SA8775P_MASTER_CNOC_MNOC_SF_CFG },
+};
+
+static struct qcom_icc_node qns_pcie_anoc_cfg = {
+ .name = "qns_pcie_anoc_cfg",
+ .id = SA8775P_SLAVE_PCIE_ANOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qns_snoc_cfg = {
+ .name = "qns_snoc_cfg",
+ .id = SA8775P_SLAVE_SNOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SA8775P_MASTER_SNOC_CFG },
+};
+
+static struct qcom_icc_node qxs_boot_imem = {
+ .name = "qxs_boot_imem",
+ .id = SA8775P_SLAVE_BOOT_IMEM,
+ .channels = 1,
+ .buswidth = 16,
+};
+
+static struct qcom_icc_node qxs_imem = {
+ .name = "qxs_imem",
+ .id = SA8775P_SLAVE_IMEM,
+ .channels = 1,
+ .buswidth = 8,
+};
+
+static struct qcom_icc_node qxs_pimem = {
+ .name = "qxs_pimem",
+ .id = SA8775P_SLAVE_PIMEM,
+ .channels = 1,
+ .buswidth = 8,
+};
+
+static struct qcom_icc_node xs_pcie_0 = {
+ .name = "xs_pcie_0",
+ .id = SA8775P_SLAVE_PCIE_0,
+ .channels = 1,
+ .buswidth = 16,
+};
+
+static struct qcom_icc_node xs_pcie_1 = {
+ .name = "xs_pcie_1",
+ .id = SA8775P_SLAVE_PCIE_1,
+ .channels = 1,
+ .buswidth = 32,
+};
+
+static struct qcom_icc_node xs_qdss_stm = {
+ .name = "xs_qdss_stm",
+ .id = SA8775P_SLAVE_QDSS_STM,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node xs_sys_tcu_cfg = {
+ .name = "xs_sys_tcu_cfg",
+ .id = SA8775P_SLAVE_TCU,
+ .channels = 1,
+ .buswidth = 8,
+};
+
+static struct qcom_icc_node qhs_llcc = {
+ .name = "qhs_llcc",
+ .id = SA8775P_SLAVE_LLCC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qns_gemnoc = {
+ .name = "qns_gemnoc",
+ .id = SA8775P_SLAVE_GEM_NOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SA8775P_MASTER_GEM_NOC_CFG },
+};
+
+static struct qcom_icc_node qns_gem_noc_cnoc = {
+ .name = "qns_gem_noc_cnoc",
+ .id = SA8775P_SLAVE_GEM_NOC_CNOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SA8775P_MASTER_GEM_NOC_CNOC },
+};
+
+static struct qcom_icc_node qns_llcc = {
+ .name = "qns_llcc",
+ .id = SA8775P_SLAVE_LLCC,
+ .channels = 6,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SA8775P_MASTER_LLCC },
+};
+
+static struct qcom_icc_node qns_pcie = {
+ .name = "qns_pcie",
+ .id = SA8775P_SLAVE_GEM_NOC_PCIE_CNOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SA8775P_MASTER_GEM_NOC_PCIE_SNOC },
+};
+
+static struct qcom_icc_node srvc_even_gemnoc = {
+ .name = "srvc_even_gemnoc",
+ .id = SA8775P_SLAVE_SERVICE_GEM_NOC_1,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node srvc_odd_gemnoc = {
+ .name = "srvc_odd_gemnoc",
+ .id = SA8775P_SLAVE_SERVICE_GEM_NOC_2,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node srvc_sys_gemnoc = {
+ .name = "srvc_sys_gemnoc",
+ .id = SA8775P_SLAVE_SERVICE_GEM_NOC,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node srvc_sys_gemnoc_2 = {
+ .name = "srvc_sys_gemnoc_2",
+ .id = SA8775P_SLAVE_SERVICE_GEM_NOC2,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qns_gp_dsp_sail_noc = {
+ .name = "qns_gp_dsp_sail_noc",
+ .id = SA8775P_SLAVE_GP_DSP_SAIL_NOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SA8775P_MASTER_GPDSP_SAIL },
+};
+
+static struct qcom_icc_node qhs_lpass_core = {
+ .name = "qhs_lpass_core",
+ .id = SA8775P_SLAVE_LPASS_CORE_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_lpass_lpi = {
+ .name = "qhs_lpass_lpi",
+ .id = SA8775P_SLAVE_LPASS_LPI_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_lpass_mpu = {
+ .name = "qhs_lpass_mpu",
+ .id = SA8775P_SLAVE_LPASS_MPU_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_lpass_top = {
+ .name = "qhs_lpass_top",
+ .id = SA8775P_SLAVE_LPASS_TOP_CFG,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qns_sysnoc = {
+ .name = "qns_sysnoc",
+ .id = SA8775P_SLAVE_LPASS_SNOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SA8775P_MASTER_LPASS_ANOC },
+};
+
+static struct qcom_icc_node srvc_niu_aml_noc = {
+ .name = "srvc_niu_aml_noc",
+ .id = SA8775P_SLAVE_SERVICES_LPASS_AML_NOC,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node srvc_niu_lpass_agnoc = {
+ .name = "srvc_niu_lpass_agnoc",
+ .id = SA8775P_SLAVE_SERVICE_LPASS_AG_NOC,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node ebi = {
+ .name = "ebi",
+ .id = SA8775P_SLAVE_EBI1,
+ .channels = 8,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qns_mem_noc_hf = {
+ .name = "qns_mem_noc_hf",
+ .id = SA8775P_SLAVE_MNOC_HF_MEM_NOC,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SA8775P_MASTER_MNOC_HF_MEM_NOC },
+};
+
+static struct qcom_icc_node qns_mem_noc_sf = {
+ .name = "qns_mem_noc_sf",
+ .id = SA8775P_SLAVE_MNOC_SF_MEM_NOC,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SA8775P_MASTER_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node srvc_mnoc_hf = {
+ .name = "srvc_mnoc_hf",
+ .id = SA8775P_SLAVE_SERVICE_MNOC_HF,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node srvc_mnoc_sf = {
+ .name = "srvc_mnoc_sf",
+ .id = SA8775P_SLAVE_SERVICE_MNOC_SF,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qns_hcp = {
+ .name = "qns_hcp",
+ .id = SA8775P_SLAVE_HCP_A,
+ .channels = 2,
+ .buswidth = 32,
+};
+
+static struct qcom_icc_node qns_nsp_gemnoc = {
+ .name = "qns_nsp_gemnoc",
+ .id = SA8775P_SLAVE_CDSP_MEM_NOC,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SA8775P_MASTER_COMPUTE_NOC },
+};
+
+static struct qcom_icc_node service_nsp_noc = {
+ .name = "service_nsp_noc",
+ .id = SA8775P_SLAVE_SERVICE_NSP_NOC,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qns_nspb_gemnoc = {
+ .name = "qns_nspb_gemnoc",
+ .id = SA8775P_SLAVE_CDSPB_MEM_NOC,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SA8775P_MASTER_COMPUTE_NOC_1 },
+};
+
+static struct qcom_icc_node qns_nspb_hcp = {
+ .name = "qns_nspb_hcp",
+ .id = SA8775P_SLAVE_HCP_B,
+ .channels = 2,
+ .buswidth = 32,
+};
+
+static struct qcom_icc_node service_nspb_noc = {
+ .name = "service_nspb_noc",
+ .id = SA8775P_SLAVE_SERVICE_NSPB_NOC,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_node qns_pcie_mem_noc = {
+ .name = "qns_pcie_mem_noc",
+ .id = SA8775P_SLAVE_ANOC_PCIE_GEM_NOC,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SA8775P_MASTER_ANOC_PCIE_GEM_NOC },
+};
+
+static struct qcom_icc_node qns_gemnoc_gc = {
+ .name = "qns_gemnoc_gc",
+ .id = SA8775P_SLAVE_SNOC_GEM_NOC_GC,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SA8775P_MASTER_SNOC_GC_MEM_NOC },
+};
+
+static struct qcom_icc_node qns_gemnoc_sf = {
+ .name = "qns_gemnoc_sf",
+ .id = SA8775P_SLAVE_SNOC_GEM_NOC_SF,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SA8775P_MASTER_SNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node srvc_snoc = {
+ .name = "srvc_snoc",
+ .id = SA8775P_SLAVE_SERVICE_SNOC,
+ .channels = 1,
+ .buswidth = 4,
+};
+
+static struct qcom_icc_bcm bcm_acv = {
+ .name = "ACV",
+ .num_nodes = 1,
+ .nodes = { &ebi },
+};
+
+static struct qcom_icc_bcm bcm_ce0 = {
+ .name = "CE0",
+ .num_nodes = 2,
+ .nodes = { &qxm_crypto_0, &qxm_crypto_1 },
+};
+
+static struct qcom_icc_bcm bcm_cn0 = {
+ .name = "CN0",
+ .keepalive = true,
+ .num_nodes = 2,
+ .nodes = { &qnm_gemnoc_cnoc, &qnm_gemnoc_pcie },
+};
+
+static struct qcom_icc_bcm bcm_cn1 = {
+ .name = "CN1",
+ .num_nodes = 76,
+ .nodes = { &qhs_ahb2phy0, &qhs_ahb2phy1,
+ &qhs_ahb2phy2, &qhs_ahb2phy3,
+ &qhs_anoc_throttle_cfg, &qhs_aoss,
+ &qhs_apss, &qhs_boot_rom,
+ &qhs_camera_cfg, &qhs_camera_nrt_throttle_cfg,
+ &qhs_camera_rt_throttle_cfg, &qhs_clk_ctl,
+ &qhs_compute0_cfg, &qhs_compute1_cfg,
+ &qhs_cpr_cx, &qhs_cpr_mmcx,
+ &qhs_cpr_mx, &qhs_cpr_nspcx,
+ &qhs_crypto0_cfg, &qhs_cx_rdpm,
+ &qhs_display0_cfg, &qhs_display0_rt_throttle_cfg,
+ &qhs_display1_cfg, &qhs_display1_rt_throttle_cfg,
+ &qhs_emac0_cfg, &qhs_emac1_cfg,
+ &qhs_gp_dsp0_cfg, &qhs_gp_dsp1_cfg,
+ &qhs_gpdsp0_throttle_cfg, &qhs_gpdsp1_throttle_cfg,
+ &qhs_gpu_tcu_throttle_cfg, &qhs_gpuss_cfg,
+ &qhs_hwkm, &qhs_imem_cfg,
+ &qhs_ipa, &qhs_ipc_router,
+ &qhs_lpass_cfg, &qhs_lpass_throttle_cfg,
+ &qhs_mx_rdpm, &qhs_mxc_rdpm,
+ &qhs_pcie0_cfg, &qhs_pcie1_cfg,
+ &qhs_pcie_rsc_cfg, &qhs_pcie_tcu_throttle_cfg,
+ &qhs_pcie_throttle_cfg, &qhs_pdm,
+ &qhs_pimem_cfg, &qhs_pke_wrapper_cfg,
+ &qhs_qdss_cfg, &qhs_qm_cfg,
+ &qhs_qm_mpu_cfg, &qhs_sail_throttle_cfg,
+ &qhs_sdc1, &qhs_security,
+ &qhs_snoc_throttle_cfg, &qhs_tcsr,
+ &qhs_tlmm, &qhs_tsc_cfg,
+ &qhs_ufs_card_cfg, &qhs_ufs_mem_cfg,
+ &qhs_usb2_0, &qhs_usb3_0,
+ &qhs_usb3_1, &qhs_venus_cfg,
+ &qhs_venus_cvp_throttle_cfg, &qhs_venus_v_cpu_throttle_cfg,
+ &qhs_venus_vcodec_throttle_cfg, &qns_ddrss_cfg,
+ &qns_gpdsp_noc_cfg, &qns_mnoc_hf_cfg,
+ &qns_mnoc_sf_cfg, &qns_pcie_anoc_cfg,
+ &qns_snoc_cfg, &qxs_boot_imem,
+ &qxs_imem, &xs_sys_tcu_cfg },
+};
+
+static struct qcom_icc_bcm bcm_cn2 = {
+ .name = "CN2",
+ .num_nodes = 4,
+ .nodes = { &qhs_qup0, &qhs_qup1,
+ &qhs_qup2, &qhs_qup3 },
+};
+
+static struct qcom_icc_bcm bcm_cn3 = {
+ .name = "CN3",
+ .num_nodes = 2,
+ .nodes = { &xs_pcie_0, &xs_pcie_1 },
+};
+
+static struct qcom_icc_bcm bcm_gna0 = {
+ .name = "GNA0",
+ .num_nodes = 1,
+ .nodes = { &qxm_dsp0 },
+};
+
+static struct qcom_icc_bcm bcm_gnb0 = {
+ .name = "GNB0",
+ .num_nodes = 1,
+ .nodes = { &qxm_dsp1 },
+};
+
+static struct qcom_icc_bcm bcm_mc0 = {
+ .name = "MC0",
+ .keepalive = true,
+ .num_nodes = 1,
+ .nodes = { &ebi },
+};
+
+static struct qcom_icc_bcm bcm_mm0 = {
+ .name = "MM0",
+ .keepalive = true,
+ .num_nodes = 5,
+ .nodes = { &qnm_camnoc_hf, &qnm_mdp0_0,
+ &qnm_mdp0_1, &qnm_mdp1_0,
+ &qns_mem_noc_hf },
+};
+
+static struct qcom_icc_bcm bcm_mm1 = {
+ .name = "MM1",
+ .num_nodes = 7,
+ .nodes = { &qnm_camnoc_icp, &qnm_camnoc_sf,
+ &qnm_video0, &qnm_video1,
+ &qnm_video_cvp, &qnm_video_v_cpu,
+ &qns_mem_noc_sf },
+};
+
+static struct qcom_icc_bcm bcm_nsa0 = {
+ .name = "NSA0",
+ .num_nodes = 2,
+ .nodes = { &qns_hcp, &qns_nsp_gemnoc },
+};
+
+static struct qcom_icc_bcm bcm_nsa1 = {
+ .name = "NSA1",
+ .num_nodes = 1,
+ .nodes = { &qxm_nsp },
+};
+
+static struct qcom_icc_bcm bcm_nsb0 = {
+ .name = "NSB0",
+ .num_nodes = 2,
+ .nodes = { &qns_nspb_gemnoc, &qns_nspb_hcp },
+};
+
+static struct qcom_icc_bcm bcm_nsb1 = {
+ .name = "NSB1",
+ .num_nodes = 1,
+ .nodes = { &qxm_nspb },
+};
+
+static struct qcom_icc_bcm bcm_pci0 = {
+ .name = "PCI0",
+ .num_nodes = 1,
+ .nodes = { &qns_pcie_mem_noc },
+};
+
+static struct qcom_icc_bcm bcm_qup0 = {
+ .name = "QUP0",
+ .vote_scale = 1,
+ .num_nodes = 1,
+ .nodes = { &qup0_core_slave },
+};
+
+static struct qcom_icc_bcm bcm_qup1 = {
+ .name = "QUP1",
+ .vote_scale = 1,
+ .num_nodes = 1,
+ .nodes = { &qup1_core_slave },
+};
+
+static struct qcom_icc_bcm bcm_qup2 = {
+ .name = "QUP2",
+ .vote_scale = 1,
+ .num_nodes = 2,
+ .nodes = { &qup2_core_slave, &qup3_core_slave },
+};
+
+static struct qcom_icc_bcm bcm_sh0 = {
+ .name = "SH0",
+ .keepalive = true,
+ .num_nodes = 1,
+ .nodes = { &qns_llcc },
+};
+
+static struct qcom_icc_bcm bcm_sh2 = {
+ .name = "SH2",
+ .num_nodes = 1,
+ .nodes = { &chm_apps },
+};
+
+static struct qcom_icc_bcm bcm_sn0 = {
+ .name = "SN0",
+ .keepalive = true,
+ .num_nodes = 1,
+ .nodes = { &qns_gemnoc_sf },
+};
+
+static struct qcom_icc_bcm bcm_sn1 = {
+ .name = "SN1",
+ .num_nodes = 1,
+ .nodes = { &qns_gemnoc_gc },
+};
+
+static struct qcom_icc_bcm bcm_sn2 = {
+ .name = "SN2",
+ .num_nodes = 1,
+ .nodes = { &qxs_pimem },
+};
+
+static struct qcom_icc_bcm bcm_sn3 = {
+ .name = "SN3",
+ .num_nodes = 2,
+ .nodes = { &qns_a1noc_snoc, &qnm_aggre1_noc },
+};
+
+static struct qcom_icc_bcm bcm_sn4 = {
+ .name = "SN4",
+ .num_nodes = 2,
+ .nodes = { &qns_a2noc_snoc, &qnm_aggre2_noc },
+};
+
+static struct qcom_icc_bcm bcm_sn9 = {
+ .name = "SN9",
+ .num_nodes = 2,
+ .nodes = { &qns_sysnoc, &qnm_lpass_noc },
+};
+
+static struct qcom_icc_bcm bcm_sn10 = {
+ .name = "SN10",
+ .num_nodes = 1,
+ .nodes = { &xs_qdss_stm },
+};
+
+static struct qcom_icc_bcm *aggre1_noc_bcms[] = {
+ &bcm_sn3,
+};
+
+static struct qcom_icc_node *aggre1_noc_nodes[] = {
+ [MASTER_QUP_3] = &qxm_qup3,
+ [MASTER_EMAC] = &xm_emac_0,
+ [MASTER_EMAC_1] = &xm_emac_1,
+ [MASTER_SDC] = &xm_sdc1,
+ [MASTER_UFS_MEM] = &xm_ufs_mem,
+ [MASTER_USB2] = &xm_usb2_2,
+ [MASTER_USB3_0] = &xm_usb3_0,
+ [MASTER_USB3_1] = &xm_usb3_1,
+ [SLAVE_A1NOC_SNOC] = &qns_a1noc_snoc,
+};
+
+static const struct qcom_icc_desc sa8775p_aggre1_noc = {
+ .nodes = aggre1_noc_nodes,
+ .num_nodes = ARRAY_SIZE(aggre1_noc_nodes),
+ .bcms = aggre1_noc_bcms,
+ .num_bcms = ARRAY_SIZE(aggre1_noc_bcms),
+};
+
+static struct qcom_icc_bcm *aggre2_noc_bcms[] = {
+ &bcm_ce0,
+ &bcm_sn4,
+};
+
+static struct qcom_icc_node *aggre2_noc_nodes[] = {
+ [MASTER_QDSS_BAM] = &qhm_qdss_bam,
+ [MASTER_QUP_0] = &qhm_qup0,
+ [MASTER_QUP_1] = &qhm_qup1,
+ [MASTER_QUP_2] = &qhm_qup2,
+ [MASTER_CNOC_A2NOC] = &qnm_cnoc_datapath,
+ [MASTER_CRYPTO_CORE0] = &qxm_crypto_0,
+ [MASTER_CRYPTO_CORE1] = &qxm_crypto_1,
+ [MASTER_IPA] = &qxm_ipa,
+ [MASTER_QDSS_ETR_0] = &xm_qdss_etr_0,
+ [MASTER_QDSS_ETR_1] = &xm_qdss_etr_1,
+ [MASTER_UFS_CARD] = &xm_ufs_card,
+ [SLAVE_A2NOC_SNOC] = &qns_a2noc_snoc,
+};
+
+static const struct qcom_icc_desc sa8775p_aggre2_noc = {
+ .nodes = aggre2_noc_nodes,
+ .num_nodes = ARRAY_SIZE(aggre2_noc_nodes),
+ .bcms = aggre2_noc_bcms,
+ .num_bcms = ARRAY_SIZE(aggre2_noc_bcms),
+};
+
+static struct qcom_icc_bcm *clk_virt_bcms[] = {
+ &bcm_qup0,
+ &bcm_qup1,
+ &bcm_qup2,
+};
+
+static struct qcom_icc_node *clk_virt_nodes[] = {
+ [MASTER_QUP_CORE_0] = &qup0_core_master,
+ [MASTER_QUP_CORE_1] = &qup1_core_master,
+ [MASTER_QUP_CORE_2] = &qup2_core_master,
+ [MASTER_QUP_CORE_3] = &qup3_core_master,
+ [SLAVE_QUP_CORE_0] = &qup0_core_slave,
+ [SLAVE_QUP_CORE_1] = &qup1_core_slave,
+ [SLAVE_QUP_CORE_2] = &qup2_core_slave,
+ [SLAVE_QUP_CORE_3] = &qup3_core_slave,
+};
+
+static const struct qcom_icc_desc sa8775p_clk_virt = {
+ .nodes = clk_virt_nodes,
+ .num_nodes = ARRAY_SIZE(clk_virt_nodes),
+ .bcms = clk_virt_bcms,
+ .num_bcms = ARRAY_SIZE(clk_virt_bcms),
+};
+
+static struct qcom_icc_bcm *config_noc_bcms[] = {
+ &bcm_cn0,
+ &bcm_cn1,
+ &bcm_cn2,
+ &bcm_cn3,
+ &bcm_sn2,
+ &bcm_sn10,
+};
+
+static struct qcom_icc_node *config_noc_nodes[] = {
+ [MASTER_GEM_NOC_CNOC] = &qnm_gemnoc_cnoc,
+ [MASTER_GEM_NOC_PCIE_SNOC] = &qnm_gemnoc_pcie,
+ [SLAVE_AHB2PHY_0] = &qhs_ahb2phy0,
+ [SLAVE_AHB2PHY_1] = &qhs_ahb2phy1,
+ [SLAVE_AHB2PHY_2] = &qhs_ahb2phy2,
+ [SLAVE_AHB2PHY_3] = &qhs_ahb2phy3,
+ [SLAVE_ANOC_THROTTLE_CFG] = &qhs_anoc_throttle_cfg,
+ [SLAVE_AOSS] = &qhs_aoss,
+ [SLAVE_APPSS] = &qhs_apss,
+ [SLAVE_BOOT_ROM] = &qhs_boot_rom,
+ [SLAVE_CAMERA_CFG] = &qhs_camera_cfg,
+ [SLAVE_CAMERA_NRT_THROTTLE_CFG] = &qhs_camera_nrt_throttle_cfg,
+ [SLAVE_CAMERA_RT_THROTTLE_CFG] = &qhs_camera_rt_throttle_cfg,
+ [SLAVE_CLK_CTL] = &qhs_clk_ctl,
+ [SLAVE_CDSP_CFG] = &qhs_compute0_cfg,
+ [SLAVE_CDSP1_CFG] = &qhs_compute1_cfg,
+ [SLAVE_RBCPR_CX_CFG] = &qhs_cpr_cx,
+ [SLAVE_RBCPR_MMCX_CFG] = &qhs_cpr_mmcx,
+ [SLAVE_RBCPR_MX_CFG] = &qhs_cpr_mx,
+ [SLAVE_CPR_NSPCX] = &qhs_cpr_nspcx,
+ [SLAVE_CRYPTO_0_CFG] = &qhs_crypto0_cfg,
+ [SLAVE_CX_RDPM] = &qhs_cx_rdpm,
+ [SLAVE_DISPLAY_CFG] = &qhs_display0_cfg,
+ [SLAVE_DISPLAY_RT_THROTTLE_CFG] = &qhs_display0_rt_throttle_cfg,
+ [SLAVE_DISPLAY1_CFG] = &qhs_display1_cfg,
+ [SLAVE_DISPLAY1_RT_THROTTLE_CFG] = &qhs_display1_rt_throttle_cfg,
+ [SLAVE_EMAC_CFG] = &qhs_emac0_cfg,
+ [SLAVE_EMAC1_CFG] = &qhs_emac1_cfg,
+ [SLAVE_GP_DSP0_CFG] = &qhs_gp_dsp0_cfg,
+ [SLAVE_GP_DSP1_CFG] = &qhs_gp_dsp1_cfg,
+ [SLAVE_GPDSP0_THROTTLE_CFG] = &qhs_gpdsp0_throttle_cfg,
+ [SLAVE_GPDSP1_THROTTLE_CFG] = &qhs_gpdsp1_throttle_cfg,
+ [SLAVE_GPU_TCU_THROTTLE_CFG] = &qhs_gpu_tcu_throttle_cfg,
+ [SLAVE_GFX3D_CFG] = &qhs_gpuss_cfg,
+ [SLAVE_HWKM] = &qhs_hwkm,
+ [SLAVE_IMEM_CFG] = &qhs_imem_cfg,
+ [SLAVE_IPA_CFG] = &qhs_ipa,
+ [SLAVE_IPC_ROUTER_CFG] = &qhs_ipc_router,
+ [SLAVE_LPASS] = &qhs_lpass_cfg,
+ [SLAVE_LPASS_THROTTLE_CFG] = &qhs_lpass_throttle_cfg,
+ [SLAVE_MX_RDPM] = &qhs_mx_rdpm,
+ [SLAVE_MXC_RDPM] = &qhs_mxc_rdpm,
+ [SLAVE_PCIE_0_CFG] = &qhs_pcie0_cfg,
+ [SLAVE_PCIE_1_CFG] = &qhs_pcie1_cfg,
+ [SLAVE_PCIE_RSC_CFG] = &qhs_pcie_rsc_cfg,
+ [SLAVE_PCIE_TCU_THROTTLE_CFG] = &qhs_pcie_tcu_throttle_cfg,
+ [SLAVE_PCIE_THROTTLE_CFG] = &qhs_pcie_throttle_cfg,
+ [SLAVE_PDM] = &qhs_pdm,
+ [SLAVE_PIMEM_CFG] = &qhs_pimem_cfg,
+ [SLAVE_PKA_WRAPPER_CFG] = &qhs_pke_wrapper_cfg,
+ [SLAVE_QDSS_CFG] = &qhs_qdss_cfg,
+ [SLAVE_QM_CFG] = &qhs_qm_cfg,
+ [SLAVE_QM_MPU_CFG] = &qhs_qm_mpu_cfg,
+ [SLAVE_QUP_0] = &qhs_qup0,
+ [SLAVE_QUP_1] = &qhs_qup1,
+ [SLAVE_QUP_2] = &qhs_qup2,
+ [SLAVE_QUP_3] = &qhs_qup3,
+ [SLAVE_SAIL_THROTTLE_CFG] = &qhs_sail_throttle_cfg,
+ [SLAVE_SDC1] = &qhs_sdc1,
+ [SLAVE_SECURITY] = &qhs_security,
+ [SLAVE_SNOC_THROTTLE_CFG] = &qhs_snoc_throttle_cfg,
+ [SLAVE_TCSR] = &qhs_tcsr,
+ [SLAVE_TLMM] = &qhs_tlmm,
+ [SLAVE_TSC_CFG] = &qhs_tsc_cfg,
+ [SLAVE_UFS_CARD_CFG] = &qhs_ufs_card_cfg,
+ [SLAVE_UFS_MEM_CFG] = &qhs_ufs_mem_cfg,
+ [SLAVE_USB2] = &qhs_usb2_0,
+ [SLAVE_USB3_0] = &qhs_usb3_0,
+ [SLAVE_USB3_1] = &qhs_usb3_1,
+ [SLAVE_VENUS_CFG] = &qhs_venus_cfg,
+ [SLAVE_VENUS_CVP_THROTTLE_CFG] = &qhs_venus_cvp_throttle_cfg,
+ [SLAVE_VENUS_V_CPU_THROTTLE_CFG] = &qhs_venus_v_cpu_throttle_cfg,
+ [SLAVE_VENUS_VCODEC_THROTTLE_CFG] = &qhs_venus_vcodec_throttle_cfg,
+ [SLAVE_DDRSS_CFG] = &qns_ddrss_cfg,
+ [SLAVE_GPDSP_NOC_CFG] = &qns_gpdsp_noc_cfg,
+ [SLAVE_CNOC_MNOC_HF_CFG] = &qns_mnoc_hf_cfg,
+ [SLAVE_CNOC_MNOC_SF_CFG] = &qns_mnoc_sf_cfg,
+ [SLAVE_PCIE_ANOC_CFG] = &qns_pcie_anoc_cfg,
+ [SLAVE_SNOC_CFG] = &qns_snoc_cfg,
+ [SLAVE_BOOT_IMEM] = &qxs_boot_imem,
+ [SLAVE_IMEM] = &qxs_imem,
+ [SLAVE_PIMEM] = &qxs_pimem,
+ [SLAVE_PCIE_0] = &xs_pcie_0,
+ [SLAVE_PCIE_1] = &xs_pcie_1,
+ [SLAVE_QDSS_STM] = &xs_qdss_stm,
+ [SLAVE_TCU] = &xs_sys_tcu_cfg,
+};
+
+static const struct qcom_icc_desc sa8775p_config_noc = {
+ .nodes = config_noc_nodes,
+ .num_nodes = ARRAY_SIZE(config_noc_nodes),
+ .bcms = config_noc_bcms,
+ .num_bcms = ARRAY_SIZE(config_noc_bcms),
+};
+
+static struct qcom_icc_bcm *dc_noc_bcms[] = {
+};
+
+static struct qcom_icc_node *dc_noc_nodes[] = {
+ [MASTER_CNOC_DC_NOC] = &qnm_cnoc_dc_noc,
+ [SLAVE_LLCC_CFG] = &qhs_llcc,
+ [SLAVE_GEM_NOC_CFG] = &qns_gemnoc,
+};
+
+static const struct qcom_icc_desc sa8775p_dc_noc = {
+ .nodes = dc_noc_nodes,
+ .num_nodes = ARRAY_SIZE(dc_noc_nodes),
+ .bcms = dc_noc_bcms,
+ .num_bcms = ARRAY_SIZE(dc_noc_bcms),
+};
+
+static struct qcom_icc_bcm *gem_noc_bcms[] = {
+ &bcm_sh0,
+ &bcm_sh2,
+};
+
+static struct qcom_icc_node *gem_noc_nodes[] = {
+ [MASTER_GPU_TCU] = &alm_gpu_tcu,
+ [MASTER_PCIE_TCU] = &alm_pcie_tcu,
+ [MASTER_SYS_TCU] = &alm_sys_tcu,
+ [MASTER_APPSS_PROC] = &chm_apps,
+ [MASTER_COMPUTE_NOC] = &qnm_cmpnoc0,
+ [MASTER_COMPUTE_NOC_1] = &qnm_cmpnoc1,
+ [MASTER_GEM_NOC_CFG] = &qnm_gemnoc_cfg,
+ [MASTER_GPDSP_SAIL] = &qnm_gpdsp_sail,
+ [MASTER_GFX3D] = &qnm_gpu,
+ [MASTER_MNOC_HF_MEM_NOC] = &qnm_mnoc_hf,
+ [MASTER_MNOC_SF_MEM_NOC] = &qnm_mnoc_sf,
+ [MASTER_ANOC_PCIE_GEM_NOC] = &qnm_pcie,
+ [MASTER_SNOC_GC_MEM_NOC] = &qnm_snoc_gc,
+ [MASTER_SNOC_SF_MEM_NOC] = &qnm_snoc_sf,
+ [SLAVE_GEM_NOC_CNOC] = &qns_gem_noc_cnoc,
+ [SLAVE_LLCC] = &qns_llcc,
+ [SLAVE_GEM_NOC_PCIE_CNOC] = &qns_pcie,
+ [SLAVE_SERVICE_GEM_NOC_1] = &srvc_even_gemnoc,
+ [SLAVE_SERVICE_GEM_NOC_2] = &srvc_odd_gemnoc,
+ [SLAVE_SERVICE_GEM_NOC] = &srvc_sys_gemnoc,
+ [SLAVE_SERVICE_GEM_NOC2] = &srvc_sys_gemnoc_2,
+};
+
+static const struct qcom_icc_desc sa8775p_gem_noc = {
+ .nodes = gem_noc_nodes,
+ .num_nodes = ARRAY_SIZE(gem_noc_nodes),
+ .bcms = gem_noc_bcms,
+ .num_bcms = ARRAY_SIZE(gem_noc_bcms),
+};
+
+static struct qcom_icc_bcm *gpdsp_anoc_bcms[] = {
+ &bcm_gna0,
+ &bcm_gnb0,
+};
+
+static struct qcom_icc_node *gpdsp_anoc_nodes[] = {
+ [MASTER_DSP0] = &qxm_dsp0,
+ [MASTER_DSP1] = &qxm_dsp1,
+ [SLAVE_GP_DSP_SAIL_NOC] = &qns_gp_dsp_sail_noc,
+};
+
+static const struct qcom_icc_desc sa8775p_gpdsp_anoc = {
+ .nodes = gpdsp_anoc_nodes,
+ .num_nodes = ARRAY_SIZE(gpdsp_anoc_nodes),
+ .bcms = gpdsp_anoc_bcms,
+ .num_bcms = ARRAY_SIZE(gpdsp_anoc_bcms),
+};
+
+static struct qcom_icc_bcm *lpass_ag_noc_bcms[] = {
+ &bcm_sn9,
+};
+
+static struct qcom_icc_node *lpass_ag_noc_nodes[] = {
+ [MASTER_CNOC_LPASS_AG_NOC] = &qhm_config_noc,
+ [MASTER_LPASS_PROC] = &qxm_lpass_dsp,
+ [SLAVE_LPASS_CORE_CFG] = &qhs_lpass_core,
+ [SLAVE_LPASS_LPI_CFG] = &qhs_lpass_lpi,
+ [SLAVE_LPASS_MPU_CFG] = &qhs_lpass_mpu,
+ [SLAVE_LPASS_TOP_CFG] = &qhs_lpass_top,
+ [SLAVE_LPASS_SNOC] = &qns_sysnoc,
+ [SLAVE_SERVICES_LPASS_AML_NOC] = &srvc_niu_aml_noc,
+ [SLAVE_SERVICE_LPASS_AG_NOC] = &srvc_niu_lpass_agnoc,
+};
+
+static const struct qcom_icc_desc sa8775p_lpass_ag_noc = {
+ .nodes = lpass_ag_noc_nodes,
+ .num_nodes = ARRAY_SIZE(lpass_ag_noc_nodes),
+ .bcms = lpass_ag_noc_bcms,
+ .num_bcms = ARRAY_SIZE(lpass_ag_noc_bcms),
+};
+
+static struct qcom_icc_bcm *mc_virt_bcms[] = {
+ &bcm_acv,
+ &bcm_mc0,
+};
+
+static struct qcom_icc_node *mc_virt_nodes[] = {
+ [MASTER_LLCC] = &llcc_mc,
+ [SLAVE_EBI1] = &ebi,
+};
+
+static const struct qcom_icc_desc sa8775p_mc_virt = {
+ .nodes = mc_virt_nodes,
+ .num_nodes = ARRAY_SIZE(mc_virt_nodes),
+ .bcms = mc_virt_bcms,
+ .num_bcms = ARRAY_SIZE(mc_virt_bcms),
+};
+
+static struct qcom_icc_bcm *mmss_noc_bcms[] = {
+ &bcm_mm0,
+ &bcm_mm1,
+};
+
+static struct qcom_icc_node *mmss_noc_nodes[] = {
+ [MASTER_CAMNOC_HF] = &qnm_camnoc_hf,
+ [MASTER_CAMNOC_ICP] = &qnm_camnoc_icp,
+ [MASTER_CAMNOC_SF] = &qnm_camnoc_sf,
+ [MASTER_MDP0] = &qnm_mdp0_0,
+ [MASTER_MDP1] = &qnm_mdp0_1,
+ [MASTER_MDP_CORE1_0] = &qnm_mdp1_0,
+ [MASTER_MDP_CORE1_1] = &qnm_mdp1_1,
+ [MASTER_CNOC_MNOC_HF_CFG] = &qnm_mnoc_hf_cfg,
+ [MASTER_CNOC_MNOC_SF_CFG] = &qnm_mnoc_sf_cfg,
+ [MASTER_VIDEO_P0] = &qnm_video0,
+ [MASTER_VIDEO_P1] = &qnm_video1,
+ [MASTER_VIDEO_PROC] = &qnm_video_cvp,
+ [MASTER_VIDEO_V_PROC] = &qnm_video_v_cpu,
+ [SLAVE_MNOC_HF_MEM_NOC] = &qns_mem_noc_hf,
+ [SLAVE_MNOC_SF_MEM_NOC] = &qns_mem_noc_sf,
+ [SLAVE_SERVICE_MNOC_HF] = &srvc_mnoc_hf,
+ [SLAVE_SERVICE_MNOC_SF] = &srvc_mnoc_sf,
+};
+
+static const struct qcom_icc_desc sa8775p_mmss_noc = {
+ .nodes = mmss_noc_nodes,
+ .num_nodes = ARRAY_SIZE(mmss_noc_nodes),
+ .bcms = mmss_noc_bcms,
+ .num_bcms = ARRAY_SIZE(mmss_noc_bcms),
+};
+
+static struct qcom_icc_bcm *nspa_noc_bcms[] = {
+ &bcm_nsa0,
+ &bcm_nsa1,
+};
+
+static struct qcom_icc_node *nspa_noc_nodes[] = {
+ [MASTER_CDSP_NOC_CFG] = &qhm_nsp_noc_config,
+ [MASTER_CDSP_PROC] = &qxm_nsp,
+ [SLAVE_HCP_A] = &qns_hcp,
+ [SLAVE_CDSP_MEM_NOC] = &qns_nsp_gemnoc,
+ [SLAVE_SERVICE_NSP_NOC] = &service_nsp_noc,
+};
+
+static const struct qcom_icc_desc sa8775p_nspa_noc = {
+ .nodes = nspa_noc_nodes,
+ .num_nodes = ARRAY_SIZE(nspa_noc_nodes),
+ .bcms = nspa_noc_bcms,
+ .num_bcms = ARRAY_SIZE(nspa_noc_bcms),
+};
+
+static struct qcom_icc_bcm *nspb_noc_bcms[] = {
+ &bcm_nsb0,
+ &bcm_nsb1,
+};
+
+static struct qcom_icc_node *nspb_noc_nodes[] = {
+ [MASTER_CDSPB_NOC_CFG] = &qhm_nspb_noc_config,
+ [MASTER_CDSP_PROC_B] = &qxm_nspb,
+ [SLAVE_CDSPB_MEM_NOC] = &qns_nspb_gemnoc,
+ [SLAVE_HCP_B] = &qns_nspb_hcp,
+ [SLAVE_SERVICE_NSPB_NOC] = &service_nspb_noc,
+};
+
+static const struct qcom_icc_desc sa8775p_nspb_noc = {
+ .nodes = nspb_noc_nodes,
+ .num_nodes = ARRAY_SIZE(nspb_noc_nodes),
+ .bcms = nspb_noc_bcms,
+ .num_bcms = ARRAY_SIZE(nspb_noc_bcms),
+};
+
+static struct qcom_icc_bcm *pcie_anoc_bcms[] = {
+ &bcm_pci0,
+};
+
+static struct qcom_icc_node *pcie_anoc_nodes[] = {
+ [MASTER_PCIE_0] = &xm_pcie3_0,
+ [MASTER_PCIE_1] = &xm_pcie3_1,
+ [SLAVE_ANOC_PCIE_GEM_NOC] = &qns_pcie_mem_noc,
+};
+
+static const struct qcom_icc_desc sa8775p_pcie_anoc = {
+ .nodes = pcie_anoc_nodes,
+ .num_nodes = ARRAY_SIZE(pcie_anoc_nodes),
+ .bcms = pcie_anoc_bcms,
+ .num_bcms = ARRAY_SIZE(pcie_anoc_bcms),
+};
+
+static struct qcom_icc_bcm *system_noc_bcms[] = {
+ &bcm_sn0,
+ &bcm_sn1,
+ &bcm_sn3,
+ &bcm_sn4,
+ &bcm_sn9,
+};
+
+static struct qcom_icc_node *system_noc_nodes[] = {
+ [MASTER_GIC_AHB] = &qhm_gic,
+ [MASTER_A1NOC_SNOC] = &qnm_aggre1_noc,
+ [MASTER_A2NOC_SNOC] = &qnm_aggre2_noc,
+ [MASTER_LPASS_ANOC] = &qnm_lpass_noc,
+ [MASTER_SNOC_CFG] = &qnm_snoc_cfg,
+ [MASTER_PIMEM] = &qxm_pimem,
+ [MASTER_GIC] = &xm_gic,
+ [SLAVE_SNOC_GEM_NOC_GC] = &qns_gemnoc_gc,
+ [SLAVE_SNOC_GEM_NOC_SF] = &qns_gemnoc_sf,
+ [SLAVE_SERVICE_SNOC] = &srvc_snoc,
+};
+
+static const struct qcom_icc_desc sa8775p_system_noc = {
+ .nodes = system_noc_nodes,
+ .num_nodes = ARRAY_SIZE(system_noc_nodes),
+ .bcms = system_noc_bcms,
+ .num_bcms = ARRAY_SIZE(system_noc_bcms),
+};
+
+static const struct of_device_id qnoc_of_match[] = {
+ { .compatible = "qcom,sa8775p-aggre1-noc", .data = &sa8775p_aggre1_noc, },
+ { .compatible = "qcom,sa8775p-aggre2-noc", .data = &sa8775p_aggre2_noc, },
+ { .compatible = "qcom,sa8775p-clk-virt", .data = &sa8775p_clk_virt, },
+ { .compatible = "qcom,sa8775p-config-noc", .data = &sa8775p_config_noc, },
+ { .compatible = "qcom,sa8775p-dc-noc", .data = &sa8775p_dc_noc, },
+ { .compatible = "qcom,sa8775p-gem-noc", .data = &sa8775p_gem_noc, },
+ { .compatible = "qcom,sa8775p-gpdsp-anoc", .data = &sa8775p_gpdsp_anoc, },
+ { .compatible = "qcom,sa8775p-lpass-ag-noc", .data = &sa8775p_lpass_ag_noc, },
+ { .compatible = "qcom,sa8775p-mc-virt", .data = &sa8775p_mc_virt, },
+ { .compatible = "qcom,sa8775p-mmss-noc", .data = &sa8775p_mmss_noc, },
+ { .compatible = "qcom,sa8775p-nspa-noc", .data = &sa8775p_nspa_noc, },
+ { .compatible = "qcom,sa8775p-nspb-noc", .data = &sa8775p_nspb_noc, },
+ { .compatible = "qcom,sa8775p-pcie-anoc", .data = &sa8775p_pcie_anoc, },
+ { .compatible = "qcom,sa8775p-system-noc", .data = &sa8775p_system_noc, },
+ { }
+};
+MODULE_DEVICE_TABLE(of, qnoc_of_match);
+
+static struct platform_driver qnoc_driver = {
+ .probe = qcom_icc_rpmh_probe,
+ .remove = qcom_icc_rpmh_remove,
+ .driver = {
+ .name = "qnoc-sa8775p",
+ .of_match_table = qnoc_of_match,
+ .sync_state = icc_sync_state,
+ },
+};
+
+static int __init qnoc_driver_init(void)
+{
+ return platform_driver_register(&qnoc_driver);
+}
+core_initcall(qnoc_driver_init);
+
+static void __exit qnoc_driver_exit(void)
+{
+ platform_driver_unregister(&qnoc_driver);
+}
+module_exit(qnoc_driver_exit);
+
+MODULE_DESCRIPTION("Qualcomm Technologies, Inc. SA8775P NoC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/interconnect/qcom/sc7180.h b/drivers/interconnect/qcom/sc7180.h
index c6212a10c2f6..7a2b3eb00923 100644
--- a/drivers/interconnect/qcom/sc7180.h
+++ b/drivers/interconnect/qcom/sc7180.h
@@ -11,7 +11,7 @@
#define SC7180_MASTER_APPSS_PROC 0
#define SC7180_MASTER_SYS_TCU 1
#define SC7180_MASTER_NPU_SYS 2
-#define SC7180_MASTER_IPA_CORE 3
+/* 3 was used by MASTER_IPA_CORE, now represented as RPMh clock */
#define SC7180_MASTER_LLCC 4
#define SC7180_MASTER_A1NOC_CFG 5
#define SC7180_MASTER_A2NOC_CFG 6
@@ -58,7 +58,7 @@
#define SC7180_MASTER_USB3 47
#define SC7180_MASTER_EMMC 48
#define SC7180_SLAVE_EBI1 49
-#define SC7180_SLAVE_IPA_CORE 50
+/* 50 was used by SLAVE_IPA_CORE, now represented as RPMh clock */
#define SC7180_SLAVE_A1NOC_CFG 51
#define SC7180_SLAVE_A2NOC_CFG 52
#define SC7180_SLAVE_AHB2PHY_SOUTH 53
diff --git a/drivers/interconnect/qcom/sc8180x.c b/drivers/interconnect/qcom/sc8180x.c
index 0f515bf10bd7..c76e3a6a98cd 100644
--- a/drivers/interconnect/qcom/sc8180x.c
+++ b/drivers/interconnect/qcom/sc8180x.c
@@ -469,15 +469,6 @@ static struct qcom_icc_node mas_qxm_ecc = {
.links = { SC8180X_SLAVE_LLCC }
};
-static struct qcom_icc_node mas_ipa_core_master = {
- .name = "mas_ipa_core_master",
- .id = SC8180X_MASTER_IPA_CORE,
- .channels = 1,
- .buswidth = 8,
- .num_links = 1,
- .links = { SC8180X_SLAVE_IPA_CORE }
-};
-
static struct qcom_icc_node mas_llcc_mc = {
.name = "mas_llcc_mc",
.id = SC8180X_MASTER_LLCC,
@@ -1201,13 +1192,6 @@ static struct qcom_icc_node slv_srvc_gemnoc1 = {
.buswidth = 4
};
-static struct qcom_icc_node slv_ipa_core_slave = {
- .name = "slv_ipa_core_slave",
- .id = SC8180X_SLAVE_IPA_CORE,
- .channels = 1,
- .buswidth = 8
-};
-
static struct qcom_icc_node slv_ebi = {
.name = "slv_ebi",
.id = SC8180X_SLAVE_EBI_CH0,
@@ -1524,11 +1508,6 @@ static struct qcom_icc_bcm bcm_co2 = {
.nodes = { &mas_qnm_npu }
};
-static struct qcom_icc_bcm bcm_ip0 = {
- .name = "IP0",
- .nodes = { &slv_ipa_core_slave }
-};
-
static struct qcom_icc_bcm bcm_sn3 = {
.name = "SN3",
.keepalive = true,
@@ -1604,10 +1583,6 @@ static struct qcom_icc_bcm * const gem_noc_bcms[] = {
&bcm_sh3,
};
-static struct qcom_icc_bcm * const ipa_virt_bcms[] = {
- &bcm_ip0,
-};
-
static struct qcom_icc_bcm * const mc_virt_bcms[] = {
&bcm_mc0,
&bcm_acv,
@@ -1766,11 +1741,6 @@ static struct qcom_icc_node * const gem_noc_nodes[] = {
[SLAVE_SERVICE_GEM_NOC_1] = &slv_srvc_gemnoc1,
};
-static struct qcom_icc_node * const ipa_virt_nodes[] = {
- [MASTER_IPA_CORE] = &mas_ipa_core_master,
- [SLAVE_IPA_CORE] = &slv_ipa_core_slave,
-};
-
static struct qcom_icc_node * const mc_virt_nodes[] = {
[MASTER_LLCC] = &mas_llcc_mc,
[SLAVE_EBI_CH0] = &slv_ebi,
@@ -1857,13 +1827,6 @@ static const struct qcom_icc_desc sc8180x_gem_noc = {
.num_bcms = ARRAY_SIZE(gem_noc_bcms),
};
-static const struct qcom_icc_desc sc8180x_ipa_virt = {
- .nodes = ipa_virt_nodes,
- .num_nodes = ARRAY_SIZE(ipa_virt_nodes),
- .bcms = ipa_virt_bcms,
- .num_bcms = ARRAY_SIZE(ipa_virt_bcms),
-};
-
static const struct qcom_icc_desc sc8180x_mc_virt = {
.nodes = mc_virt_nodes,
.num_nodes = ARRAY_SIZE(mc_virt_nodes),
@@ -1913,7 +1876,6 @@ static const struct of_device_id qnoc_of_match[] = {
{ .compatible = "qcom,sc8180x-config-noc", .data = &sc8180x_config_noc },
{ .compatible = "qcom,sc8180x-dc-noc", .data = &sc8180x_dc_noc },
{ .compatible = "qcom,sc8180x-gem-noc", .data = &sc8180x_gem_noc },
- { .compatible = "qcom,sc8180x-ipa-virt", .data = &sc8180x_ipa_virt },
{ .compatible = "qcom,sc8180x-mc-virt", .data = &sc8180x_mc_virt },
{ .compatible = "qcom,sc8180x-mmss-noc", .data = &sc8180x_mmss_noc },
{ .compatible = "qcom,sc8180x-qup-virt", .data = &sc8180x_qup_virt },
diff --git a/drivers/interconnect/qcom/sc8180x.h b/drivers/interconnect/qcom/sc8180x.h
index 2eafd35543c7..c138dcd350f1 100644
--- a/drivers/interconnect/qcom/sc8180x.h
+++ b/drivers/interconnect/qcom/sc8180x.h
@@ -51,7 +51,7 @@
#define SC8180X_MASTER_SNOC_GC_MEM_NOC 41
#define SC8180X_MASTER_SNOC_SF_MEM_NOC 42
#define SC8180X_MASTER_ECC 43
-#define SC8180X_MASTER_IPA_CORE 44
+/* 44 was used by MASTER_IPA_CORE, now represented as RPMh clock */
#define SC8180X_MASTER_LLCC 45
#define SC8180X_MASTER_CNOC_MNOC_CFG 46
#define SC8180X_MASTER_CAMNOC_HF0 47
@@ -146,7 +146,7 @@
#define SC8180X_SLAVE_LLCC 136
#define SC8180X_SLAVE_SERVICE_GEM_NOC 137
#define SC8180X_SLAVE_SERVICE_GEM_NOC_1 138
-#define SC8180X_SLAVE_IPA_CORE 139
+/* 139 was used by SLAVE_IPA_CORE, now represented as RPMh clock */
#define SC8180X_SLAVE_EBI_CH0 140
#define SC8180X_SLAVE_MNOC_SF_MEM_NOC 141
#define SC8180X_SLAVE_MNOC_HF_MEM_NOC 142
diff --git a/drivers/interconnect/qcom/sc8280xp.c b/drivers/interconnect/qcom/sc8280xp.c
index 507fe5f89791..e56df893ec3e 100644
--- a/drivers/interconnect/qcom/sc8280xp.c
+++ b/drivers/interconnect/qcom/sc8280xp.c
@@ -284,15 +284,6 @@ static struct qcom_icc_node xm_ufs_card = {
.links = { SC8280XP_SLAVE_A2NOC_SNOC },
};
-static struct qcom_icc_node ipa_core_master = {
- .name = "ipa_core_master",
- .id = SC8280XP_MASTER_IPA_CORE,
- .channels = 1,
- .buswidth = 8,
- .num_links = 1,
- .links = { SC8280XP_SLAVE_IPA_CORE },
-};
-
static struct qcom_icc_node qup0_core_master = {
.name = "qup0_core_master",
.id = SC8280XP_MASTER_QUP_CORE_0,
@@ -882,13 +873,6 @@ static struct qcom_icc_node srvc_aggre2_noc = {
.buswidth = 4,
};
-static struct qcom_icc_node ipa_core_slave = {
- .name = "ipa_core_slave",
- .id = SC8280XP_SLAVE_IPA_CORE,
- .channels = 1,
- .buswidth = 8,
-};
-
static struct qcom_icc_node qup0_core_slave = {
.name = "qup0_core_slave",
.id = SC8280XP_SLAVE_QUP_CORE_0,
@@ -1845,12 +1829,6 @@ static struct qcom_icc_bcm bcm_cn3 = {
},
};
-static struct qcom_icc_bcm bcm_ip0 = {
- .name = "IP0",
- .num_nodes = 1,
- .nodes = { &ipa_core_slave },
-};
-
static struct qcom_icc_bcm bcm_mc0 = {
.name = "MC0",
.keepalive = true,
@@ -2077,18 +2055,15 @@ static const struct qcom_icc_desc sc8280xp_aggre2_noc = {
};
static struct qcom_icc_bcm * const clk_virt_bcms[] = {
- &bcm_ip0,
&bcm_qup0,
&bcm_qup1,
&bcm_qup2,
};
static struct qcom_icc_node * const clk_virt_nodes[] = {
- [MASTER_IPA_CORE] = &ipa_core_master,
[MASTER_QUP_CORE_0] = &qup0_core_master,
[MASTER_QUP_CORE_1] = &qup1_core_master,
[MASTER_QUP_CORE_2] = &qup2_core_master,
- [SLAVE_IPA_CORE] = &ipa_core_slave,
[SLAVE_QUP_CORE_0] = &qup0_core_slave,
[SLAVE_QUP_CORE_1] = &qup1_core_slave,
[SLAVE_QUP_CORE_2] = &qup2_core_slave,
diff --git a/drivers/interconnect/qcom/sc8280xp.h b/drivers/interconnect/qcom/sc8280xp.h
index 74d8fa412d65..c5c410fd5ec3 100644
--- a/drivers/interconnect/qcom/sc8280xp.h
+++ b/drivers/interconnect/qcom/sc8280xp.h
@@ -10,7 +10,7 @@
#define SC8280XP_MASTER_PCIE_TCU 1
#define SC8280XP_MASTER_SYS_TCU 2
#define SC8280XP_MASTER_APPSS_PROC 3
-#define SC8280XP_MASTER_IPA_CORE 4
+/* 4 was used by SLAVE_IPA_CORE, now represented as RPMh clock */
#define SC8280XP_MASTER_LLCC 5
#define SC8280XP_MASTER_CNOC_LPASS_AG_NOC 6
#define SC8280XP_MASTER_CDSP_NOC_CFG 7
@@ -84,7 +84,7 @@
#define SC8280XP_MASTER_USB4_0 75
#define SC8280XP_MASTER_USB4_1 76
#define SC8280XP_SLAVE_EBI1 512
-#define SC8280XP_SLAVE_IPA_CORE 513
+/* 513 was used by SLAVE_IPA_CORE, now represented as RPMh clock */
#define SC8280XP_SLAVE_AHB2PHY_0 514
#define SC8280XP_SLAVE_AHB2PHY_1 515
#define SC8280XP_SLAVE_AHB2PHY_2 516
diff --git a/drivers/interconnect/qcom/sdm670.c b/drivers/interconnect/qcom/sdm670.c
new file mode 100644
index 000000000000..bda955035518
--- /dev/null
+++ b/drivers/interconnect/qcom/sdm670.c
@@ -0,0 +1,440 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/device.h>
+#include <linux/interconnect.h>
+#include <linux/interconnect-provider.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <dt-bindings/interconnect/qcom,sdm670-rpmh.h>
+
+#include "bcm-voter.h"
+#include "icc-rpmh.h"
+#include "sdm670.h"
+
+DEFINE_QNODE(qhm_a1noc_cfg, SDM670_MASTER_A1NOC_CFG, 1, 4, SDM670_SLAVE_SERVICE_A1NOC);
+DEFINE_QNODE(qhm_qup1, SDM670_MASTER_BLSP_1, 1, 4, SDM670_SLAVE_A1NOC_SNOC);
+DEFINE_QNODE(qhm_tsif, SDM670_MASTER_TSIF, 1, 4, SDM670_SLAVE_A1NOC_SNOC);
+DEFINE_QNODE(xm_emmc, SDM670_MASTER_EMMC, 1, 8, SDM670_SLAVE_A1NOC_SNOC);
+DEFINE_QNODE(xm_sdc2, SDM670_MASTER_SDCC_2, 1, 8, SDM670_SLAVE_A1NOC_SNOC);
+DEFINE_QNODE(xm_sdc4, SDM670_MASTER_SDCC_4, 1, 8, SDM670_SLAVE_A1NOC_SNOC);
+DEFINE_QNODE(xm_ufs_mem, SDM670_MASTER_UFS_MEM, 1, 8, SDM670_SLAVE_A1NOC_SNOC);
+DEFINE_QNODE(qhm_a2noc_cfg, SDM670_MASTER_A2NOC_CFG, 1, 4, SDM670_SLAVE_SERVICE_A2NOC);
+DEFINE_QNODE(qhm_qdss_bam, SDM670_MASTER_QDSS_BAM, 1, 4, SDM670_SLAVE_A2NOC_SNOC);
+DEFINE_QNODE(qhm_qup2, SDM670_MASTER_BLSP_2, 1, 4, SDM670_SLAVE_A2NOC_SNOC);
+DEFINE_QNODE(qnm_cnoc, SDM670_MASTER_CNOC_A2NOC, 1, 8, SDM670_SLAVE_A2NOC_SNOC);
+DEFINE_QNODE(qxm_crypto, SDM670_MASTER_CRYPTO_CORE_0, 1, 8, SDM670_SLAVE_A2NOC_SNOC);
+DEFINE_QNODE(qxm_ipa, SDM670_MASTER_IPA, 1, 8, SDM670_SLAVE_A2NOC_SNOC);
+DEFINE_QNODE(xm_qdss_etr, SDM670_MASTER_QDSS_ETR, 1, 8, SDM670_SLAVE_A2NOC_SNOC);
+DEFINE_QNODE(xm_usb3_0, SDM670_MASTER_USB3, 1, 8, SDM670_SLAVE_A2NOC_SNOC);
+DEFINE_QNODE(qxm_camnoc_hf0_uncomp, SDM670_MASTER_CAMNOC_HF0_UNCOMP, 1, 32, SDM670_SLAVE_CAMNOC_UNCOMP);
+DEFINE_QNODE(qxm_camnoc_hf1_uncomp, SDM670_MASTER_CAMNOC_HF1_UNCOMP, 1, 32, SDM670_SLAVE_CAMNOC_UNCOMP);
+DEFINE_QNODE(qxm_camnoc_sf_uncomp, SDM670_MASTER_CAMNOC_SF_UNCOMP, 1, 32, SDM670_SLAVE_CAMNOC_UNCOMP);
+DEFINE_QNODE(qhm_spdm, SDM670_MASTER_SPDM, 1, 4, SDM670_SLAVE_CNOC_A2NOC);
+DEFINE_QNODE(qnm_snoc, SDM670_MASTER_SNOC_CNOC, 1, 8, SDM670_SLAVE_TLMM_SOUTH, SDM670_SLAVE_CAMERA_CFG, SDM670_SLAVE_SDCC_4, SDM670_SLAVE_SDCC_2, SDM670_SLAVE_CNOC_MNOC_CFG, SDM670_SLAVE_UFS_MEM_CFG, SDM670_SLAVE_GLM, SDM670_SLAVE_PDM, SDM670_SLAVE_A2NOC_CFG, SDM670_SLAVE_QDSS_CFG, SDM670_SLAVE_DISPLAY_CFG, SDM670_SLAVE_TCSR, SDM670_SLAVE_DCC_CFG, SDM670_SLAVE_CNOC_DDRSS, SDM670_SLAVE_SNOC_CFG, SDM670_SLAVE_SOUTH_PHY_CFG, SDM670_SLAVE_GRAPHICS_3D_CFG, SDM670_SLAVE_VENUS_CFG, SDM670_SLAVE_TSIF, SDM670_SLAVE_CDSP_CFG, SDM670_SLAVE_AOP, SDM670_SLAVE_BLSP_2, SDM670_SLAVE_SERVICE_CNOC, SDM670_SLAVE_USB3, SDM670_SLAVE_IPA_CFG, SDM670_SLAVE_RBCPR_CX_CFG, SDM670_SLAVE_A1NOC_CFG, SDM670_SLAVE_AOSS, SDM670_SLAVE_PRNG, SDM670_SLAVE_VSENSE_CTRL_CFG, SDM670_SLAVE_EMMC_CFG, SDM670_SLAVE_BLSP_1, SDM670_SLAVE_SPDM_WRAPPER, SDM670_SLAVE_CRYPTO_0_CFG, SDM670_SLAVE_PIMEM_CFG, SDM670_SLAVE_TLMM_NORTH, SDM670_SLAVE_CLK_CTL, SDM670_SLAVE_IMEM_CFG);
+DEFINE_QNODE(qhm_cnoc, SDM670_MASTER_CNOC_DC_NOC, 1, 4, SDM670_SLAVE_MEM_NOC_CFG, SDM670_SLAVE_LLCC_CFG);
+DEFINE_QNODE(acm_l3, SDM670_MASTER_AMPSS_M0, 1, 16, SDM670_SLAVE_SERVICE_GNOC, SDM670_SLAVE_GNOC_SNOC, SDM670_SLAVE_GNOC_MEM_NOC);
+DEFINE_QNODE(pm_gnoc_cfg, SDM670_MASTER_GNOC_CFG, 1, 4, SDM670_SLAVE_SERVICE_GNOC);
+DEFINE_QNODE(llcc_mc, SDM670_MASTER_LLCC, 2, 4, SDM670_SLAVE_EBI_CH0);
+DEFINE_QNODE(acm_tcu, SDM670_MASTER_TCU_0, 1, 8, SDM670_SLAVE_MEM_NOC_GNOC, SDM670_SLAVE_LLCC, SDM670_SLAVE_MEM_NOC_SNOC);
+DEFINE_QNODE(qhm_memnoc_cfg, SDM670_MASTER_MEM_NOC_CFG, 1, 4, SDM670_SLAVE_SERVICE_MEM_NOC, SDM670_SLAVE_MSS_PROC_MS_MPU_CFG);
+DEFINE_QNODE(qnm_apps, SDM670_MASTER_GNOC_MEM_NOC, 2, 32, SDM670_SLAVE_LLCC);
+DEFINE_QNODE(qnm_mnoc_hf, SDM670_MASTER_MNOC_HF_MEM_NOC, 2, 32, SDM670_SLAVE_LLCC);
+DEFINE_QNODE(qnm_mnoc_sf, SDM670_MASTER_MNOC_SF_MEM_NOC, 1, 32, SDM670_SLAVE_MEM_NOC_GNOC, SDM670_SLAVE_LLCC, SDM670_SLAVE_MEM_NOC_SNOC);
+DEFINE_QNODE(qnm_snoc_gc, SDM670_MASTER_SNOC_GC_MEM_NOC, 1, 8, SDM670_SLAVE_LLCC);
+DEFINE_QNODE(qnm_snoc_sf, SDM670_MASTER_SNOC_SF_MEM_NOC, 1, 16, SDM670_SLAVE_MEM_NOC_GNOC, SDM670_SLAVE_LLCC);
+DEFINE_QNODE(qxm_gpu, SDM670_MASTER_GRAPHICS_3D, 2, 32, SDM670_SLAVE_MEM_NOC_GNOC, SDM670_SLAVE_LLCC, SDM670_SLAVE_MEM_NOC_SNOC);
+DEFINE_QNODE(qhm_mnoc_cfg, SDM670_MASTER_CNOC_MNOC_CFG, 1, 4, SDM670_SLAVE_SERVICE_MNOC);
+DEFINE_QNODE(qxm_camnoc_hf0, SDM670_MASTER_CAMNOC_HF0, 1, 32, SDM670_SLAVE_MNOC_HF_MEM_NOC);
+DEFINE_QNODE(qxm_camnoc_hf1, SDM670_MASTER_CAMNOC_HF1, 1, 32, SDM670_SLAVE_MNOC_HF_MEM_NOC);
+DEFINE_QNODE(qxm_camnoc_sf, SDM670_MASTER_CAMNOC_SF, 1, 32, SDM670_SLAVE_MNOC_SF_MEM_NOC);
+DEFINE_QNODE(qxm_mdp0, SDM670_MASTER_MDP_PORT0, 1, 32, SDM670_SLAVE_MNOC_HF_MEM_NOC);
+DEFINE_QNODE(qxm_mdp1, SDM670_MASTER_MDP_PORT1, 1, 32, SDM670_SLAVE_MNOC_HF_MEM_NOC);
+DEFINE_QNODE(qxm_rot, SDM670_MASTER_ROTATOR, 1, 32, SDM670_SLAVE_MNOC_SF_MEM_NOC);
+DEFINE_QNODE(qxm_venus0, SDM670_MASTER_VIDEO_P0, 1, 32, SDM670_SLAVE_MNOC_SF_MEM_NOC);
+DEFINE_QNODE(qxm_venus1, SDM670_MASTER_VIDEO_P1, 1, 32, SDM670_SLAVE_MNOC_SF_MEM_NOC);
+DEFINE_QNODE(qxm_venus_arm9, SDM670_MASTER_VIDEO_PROC, 1, 8, SDM670_SLAVE_MNOC_SF_MEM_NOC);
+DEFINE_QNODE(qhm_snoc_cfg, SDM670_MASTER_SNOC_CFG, 1, 4, SDM670_SLAVE_SERVICE_SNOC);
+DEFINE_QNODE(qnm_aggre1_noc, SDM670_MASTER_A1NOC_SNOC, 1, 16, SDM670_SLAVE_PIMEM, SDM670_SLAVE_SNOC_MEM_NOC_SF, SDM670_SLAVE_OCIMEM, SDM670_SLAVE_APPSS, SDM670_SLAVE_SNOC_CNOC, SDM670_SLAVE_QDSS_STM);
+DEFINE_QNODE(qnm_aggre2_noc, SDM670_MASTER_A2NOC_SNOC, 1, 16, SDM670_SLAVE_PIMEM, SDM670_SLAVE_SNOC_MEM_NOC_SF, SDM670_SLAVE_OCIMEM, SDM670_SLAVE_APPSS, SDM670_SLAVE_SNOC_CNOC, SDM670_SLAVE_TCU, SDM670_SLAVE_QDSS_STM);
+DEFINE_QNODE(qnm_gladiator_sodv, SDM670_MASTER_GNOC_SNOC, 1, 8, SDM670_SLAVE_PIMEM, SDM670_SLAVE_OCIMEM, SDM670_SLAVE_APPSS, SDM670_SLAVE_SNOC_CNOC, SDM670_SLAVE_TCU, SDM670_SLAVE_QDSS_STM);
+DEFINE_QNODE(qnm_memnoc, SDM670_MASTER_MEM_NOC_SNOC, 1, 8, SDM670_SLAVE_OCIMEM, SDM670_SLAVE_APPSS, SDM670_SLAVE_PIMEM, SDM670_SLAVE_SNOC_CNOC, SDM670_SLAVE_QDSS_STM);
+DEFINE_QNODE(qxm_pimem, SDM670_MASTER_PIMEM, 1, 8, SDM670_SLAVE_OCIMEM, SDM670_SLAVE_SNOC_MEM_NOC_GC);
+DEFINE_QNODE(xm_gic, SDM670_MASTER_GIC, 1, 8, SDM670_SLAVE_OCIMEM, SDM670_SLAVE_SNOC_MEM_NOC_GC);
+DEFINE_QNODE(qns_a1noc_snoc, SDM670_SLAVE_A1NOC_SNOC, 1, 16, SDM670_MASTER_A1NOC_SNOC);
+DEFINE_QNODE(srvc_aggre1_noc, SDM670_SLAVE_SERVICE_A1NOC, 1, 4);
+DEFINE_QNODE(qns_a2noc_snoc, SDM670_SLAVE_A2NOC_SNOC, 1, 16, SDM670_MASTER_A2NOC_SNOC);
+DEFINE_QNODE(srvc_aggre2_noc, SDM670_SLAVE_SERVICE_A2NOC, 1, 4);
+DEFINE_QNODE(qns_camnoc_uncomp, SDM670_SLAVE_CAMNOC_UNCOMP, 1, 32);
+DEFINE_QNODE(qhs_a1_noc_cfg, SDM670_SLAVE_A1NOC_CFG, 1, 4, SDM670_MASTER_A1NOC_CFG);
+DEFINE_QNODE(qhs_a2_noc_cfg, SDM670_SLAVE_A2NOC_CFG, 1, 4, SDM670_MASTER_A2NOC_CFG);
+DEFINE_QNODE(qhs_aop, SDM670_SLAVE_AOP, 1, 4);
+DEFINE_QNODE(qhs_aoss, SDM670_SLAVE_AOSS, 1, 4);
+DEFINE_QNODE(qhs_camera_cfg, SDM670_SLAVE_CAMERA_CFG, 1, 4);
+DEFINE_QNODE(qhs_clk_ctl, SDM670_SLAVE_CLK_CTL, 1, 4);
+DEFINE_QNODE(qhs_compute_dsp_cfg, SDM670_SLAVE_CDSP_CFG, 1, 4);
+DEFINE_QNODE(qhs_cpr_cx, SDM670_SLAVE_RBCPR_CX_CFG, 1, 4);
+DEFINE_QNODE(qhs_crypto0_cfg, SDM670_SLAVE_CRYPTO_0_CFG, 1, 4);
+DEFINE_QNODE(qhs_dcc_cfg, SDM670_SLAVE_DCC_CFG, 1, 4, SDM670_MASTER_CNOC_DC_NOC);
+DEFINE_QNODE(qhs_ddrss_cfg, SDM670_SLAVE_CNOC_DDRSS, 1, 4);
+DEFINE_QNODE(qhs_display_cfg, SDM670_SLAVE_DISPLAY_CFG, 1, 4);
+DEFINE_QNODE(qhs_emmc_cfg, SDM670_SLAVE_EMMC_CFG, 1, 4);
+DEFINE_QNODE(qhs_glm, SDM670_SLAVE_GLM, 1, 4);
+DEFINE_QNODE(qhs_gpuss_cfg, SDM670_SLAVE_GRAPHICS_3D_CFG, 1, 8);
+DEFINE_QNODE(qhs_imem_cfg, SDM670_SLAVE_IMEM_CFG, 1, 4);
+DEFINE_QNODE(qhs_ipa, SDM670_SLAVE_IPA_CFG, 1, 4);
+DEFINE_QNODE(qhs_mnoc_cfg, SDM670_SLAVE_CNOC_MNOC_CFG, 1, 4, SDM670_MASTER_CNOC_MNOC_CFG);
+DEFINE_QNODE(qhs_pdm, SDM670_SLAVE_PDM, 1, 4);
+DEFINE_QNODE(qhs_phy_refgen_south, SDM670_SLAVE_SOUTH_PHY_CFG, 1, 4);
+DEFINE_QNODE(qhs_pimem_cfg, SDM670_SLAVE_PIMEM_CFG, 1, 4);
+DEFINE_QNODE(qhs_prng, SDM670_SLAVE_PRNG, 1, 4);
+DEFINE_QNODE(qhs_qdss_cfg, SDM670_SLAVE_QDSS_CFG, 1, 4);
+DEFINE_QNODE(qhs_qupv3_north, SDM670_SLAVE_BLSP_2, 1, 4);
+DEFINE_QNODE(qhs_qupv3_south, SDM670_SLAVE_BLSP_1, 1, 4);
+DEFINE_QNODE(qhs_sdc2, SDM670_SLAVE_SDCC_2, 1, 4);
+DEFINE_QNODE(qhs_sdc4, SDM670_SLAVE_SDCC_4, 1, 4);
+DEFINE_QNODE(qhs_snoc_cfg, SDM670_SLAVE_SNOC_CFG, 1, 4, SDM670_MASTER_SNOC_CFG);
+DEFINE_QNODE(qhs_spdm, SDM670_SLAVE_SPDM_WRAPPER, 1, 4);
+DEFINE_QNODE(qhs_tcsr, SDM670_SLAVE_TCSR, 1, 4);
+DEFINE_QNODE(qhs_tlmm_north, SDM670_SLAVE_TLMM_NORTH, 1, 4);
+DEFINE_QNODE(qhs_tlmm_south, SDM670_SLAVE_TLMM_SOUTH, 1, 4);
+DEFINE_QNODE(qhs_tsif, SDM670_SLAVE_TSIF, 1, 4);
+DEFINE_QNODE(qhs_ufs_mem_cfg, SDM670_SLAVE_UFS_MEM_CFG, 1, 4);
+DEFINE_QNODE(qhs_usb3_0, SDM670_SLAVE_USB3, 1, 4);
+DEFINE_QNODE(qhs_venus_cfg, SDM670_SLAVE_VENUS_CFG, 1, 4);
+DEFINE_QNODE(qhs_vsense_ctrl_cfg, SDM670_SLAVE_VSENSE_CTRL_CFG, 1, 4);
+DEFINE_QNODE(qns_cnoc_a2noc, SDM670_SLAVE_CNOC_A2NOC, 1, 8, SDM670_MASTER_CNOC_A2NOC);
+DEFINE_QNODE(srvc_cnoc, SDM670_SLAVE_SERVICE_CNOC, 1, 4);
+DEFINE_QNODE(qhs_llcc, SDM670_SLAVE_LLCC_CFG, 1, 4);
+DEFINE_QNODE(qhs_memnoc, SDM670_SLAVE_MEM_NOC_CFG, 1, 4, SDM670_MASTER_MEM_NOC_CFG);
+DEFINE_QNODE(qns_gladiator_sodv, SDM670_SLAVE_GNOC_SNOC, 1, 8, SDM670_MASTER_GNOC_SNOC);
+DEFINE_QNODE(qns_gnoc_memnoc, SDM670_SLAVE_GNOC_MEM_NOC, 2, 32, SDM670_MASTER_GNOC_MEM_NOC);
+DEFINE_QNODE(srvc_gnoc, SDM670_SLAVE_SERVICE_GNOC, 1, 4);
+DEFINE_QNODE(ebi, SDM670_SLAVE_EBI_CH0, 2, 4);
+DEFINE_QNODE(qhs_mdsp_ms_mpu_cfg, SDM670_SLAVE_MSS_PROC_MS_MPU_CFG, 1, 4);
+DEFINE_QNODE(qns_apps_io, SDM670_SLAVE_MEM_NOC_GNOC, 1, 32);
+DEFINE_QNODE(qns_llcc, SDM670_SLAVE_LLCC, 2, 16, SDM670_MASTER_LLCC);
+DEFINE_QNODE(qns_memnoc_snoc, SDM670_SLAVE_MEM_NOC_SNOC, 1, 8, SDM670_MASTER_MEM_NOC_SNOC);
+DEFINE_QNODE(srvc_memnoc, SDM670_SLAVE_SERVICE_MEM_NOC, 1, 4);
+DEFINE_QNODE(qns2_mem_noc, SDM670_SLAVE_MNOC_SF_MEM_NOC, 1, 32, SDM670_MASTER_MNOC_SF_MEM_NOC);
+DEFINE_QNODE(qns_mem_noc_hf, SDM670_SLAVE_MNOC_HF_MEM_NOC, 2, 32, SDM670_MASTER_MNOC_HF_MEM_NOC);
+DEFINE_QNODE(srvc_mnoc, SDM670_SLAVE_SERVICE_MNOC, 1, 4);
+DEFINE_QNODE(qhs_apss, SDM670_SLAVE_APPSS, 1, 8);
+DEFINE_QNODE(qns_cnoc, SDM670_SLAVE_SNOC_CNOC, 1, 8, SDM670_MASTER_SNOC_CNOC);
+DEFINE_QNODE(qns_memnoc_gc, SDM670_SLAVE_SNOC_MEM_NOC_GC, 1, 8, SDM670_MASTER_SNOC_GC_MEM_NOC);
+DEFINE_QNODE(qns_memnoc_sf, SDM670_SLAVE_SNOC_MEM_NOC_SF, 1, 16, SDM670_MASTER_SNOC_SF_MEM_NOC);
+DEFINE_QNODE(qxs_imem, SDM670_SLAVE_OCIMEM, 1, 8);
+DEFINE_QNODE(qxs_pimem, SDM670_SLAVE_PIMEM, 1, 8);
+DEFINE_QNODE(srvc_snoc, SDM670_SLAVE_SERVICE_SNOC, 1, 4);
+DEFINE_QNODE(xs_qdss_stm, SDM670_SLAVE_QDSS_STM, 1, 4);
+DEFINE_QNODE(xs_sys_tcu_cfg, SDM670_SLAVE_TCU, 1, 8);
+
+DEFINE_QBCM(bcm_acv, "ACV", false, &ebi);
+DEFINE_QBCM(bcm_mc0, "MC0", true, &ebi);
+DEFINE_QBCM(bcm_sh0, "SH0", true, &qns_llcc);
+DEFINE_QBCM(bcm_mm0, "MM0", true, &qns_mem_noc_hf);
+DEFINE_QBCM(bcm_sh1, "SH1", false, &qns_apps_io);
+DEFINE_QBCM(bcm_mm1, "MM1", true, &qxm_camnoc_hf0_uncomp, &qxm_camnoc_hf1_uncomp, &qxm_camnoc_sf_uncomp, &qxm_camnoc_hf0, &qxm_camnoc_hf1, &qxm_mdp0, &qxm_mdp1);
+DEFINE_QBCM(bcm_sh2, "SH2", false, &qns_memnoc_snoc);
+DEFINE_QBCM(bcm_mm2, "MM2", false, &qns2_mem_noc);
+DEFINE_QBCM(bcm_sh3, "SH3", false, &acm_tcu);
+DEFINE_QBCM(bcm_mm3, "MM3", false, &qxm_camnoc_sf, &qxm_rot, &qxm_venus0, &qxm_venus1, &qxm_venus_arm9);
+DEFINE_QBCM(bcm_sh5, "SH5", false, &qnm_apps);
+DEFINE_QBCM(bcm_sn0, "SN0", true, &qns_memnoc_sf);
+DEFINE_QBCM(bcm_ce0, "CE0", false, &qxm_crypto);
+DEFINE_QBCM(bcm_cn0, "CN0", true, &qhm_spdm, &qnm_snoc, &qhs_a1_noc_cfg, &qhs_a2_noc_cfg, &qhs_aop, &qhs_aoss, &qhs_camera_cfg, &qhs_clk_ctl, &qhs_compute_dsp_cfg, &qhs_cpr_cx, &qhs_crypto0_cfg, &qhs_dcc_cfg, &qhs_ddrss_cfg, &qhs_display_cfg, &qhs_emmc_cfg, &qhs_glm, &qhs_gpuss_cfg, &qhs_imem_cfg, &qhs_ipa, &qhs_mnoc_cfg, &qhs_pdm, &qhs_phy_refgen_south, &qhs_pimem_cfg, &qhs_prng, &qhs_qdss_cfg, &qhs_qupv3_north, &qhs_qupv3_south, &qhs_sdc2, &qhs_sdc4, &qhs_snoc_cfg, &qhs_spdm, &qhs_tcsr, &qhs_tlmm_north, &qhs_tlmm_south, &qhs_tsif, &qhs_ufs_mem_cfg, &qhs_usb3_0, &qhs_venus_cfg, &qhs_vsense_ctrl_cfg, &qns_cnoc_a2noc, &srvc_cnoc);
+DEFINE_QBCM(bcm_qup0, "QUP0", false, &qhm_qup1, &qhm_qup2);
+DEFINE_QBCM(bcm_sn1, "SN1", false, &qxs_imem);
+DEFINE_QBCM(bcm_sn2, "SN2", false, &qns_memnoc_gc);
+DEFINE_QBCM(bcm_sn3, "SN3", false, &qns_cnoc);
+DEFINE_QBCM(bcm_sn4, "SN4", false, &qxm_pimem, &qxs_pimem);
+DEFINE_QBCM(bcm_sn5, "SN5", false, &xs_qdss_stm);
+DEFINE_QBCM(bcm_sn8, "SN8", false, &qnm_aggre1_noc, &srvc_aggre1_noc);
+DEFINE_QBCM(bcm_sn10, "SN10", false, &qnm_aggre2_noc, &srvc_aggre2_noc);
+DEFINE_QBCM(bcm_sn11, "SN11", false, &qnm_gladiator_sodv, &xm_gic);
+DEFINE_QBCM(bcm_sn13, "SN13", false, &qnm_memnoc);
+
+static struct qcom_icc_bcm * const aggre1_noc_bcms[] = {
+ &bcm_qup0,
+ &bcm_sn8,
+};
+
+static struct qcom_icc_node * const aggre1_noc_nodes[] = {
+ [MASTER_A1NOC_CFG] = &qhm_a1noc_cfg,
+ [MASTER_BLSP_1] = &qhm_qup1,
+ [MASTER_TSIF] = &qhm_tsif,
+ [MASTER_EMMC] = &xm_emmc,
+ [MASTER_SDCC_2] = &xm_sdc2,
+ [MASTER_SDCC_4] = &xm_sdc4,
+ [MASTER_UFS_MEM] = &xm_ufs_mem,
+ [SLAVE_A1NOC_SNOC] = &qns_a1noc_snoc,
+ [SLAVE_SERVICE_A1NOC] = &srvc_aggre1_noc,
+};
+
+static const struct qcom_icc_desc sdm670_aggre1_noc = {
+ .nodes = aggre1_noc_nodes,
+ .num_nodes = ARRAY_SIZE(aggre1_noc_nodes),
+ .bcms = aggre1_noc_bcms,
+ .num_bcms = ARRAY_SIZE(aggre1_noc_bcms),
+};
+
+static struct qcom_icc_bcm * const aggre2_noc_bcms[] = {
+ &bcm_ce0,
+ &bcm_qup0,
+ &bcm_sn10,
+};
+
+static struct qcom_icc_node * const aggre2_noc_nodes[] = {
+ [MASTER_A2NOC_CFG] = &qhm_a2noc_cfg,
+ [MASTER_QDSS_BAM] = &qhm_qdss_bam,
+ [MASTER_BLSP_2] = &qhm_qup2,
+ [MASTER_CNOC_A2NOC] = &qnm_cnoc,
+ [MASTER_CRYPTO_CORE_0] = &qxm_crypto,
+ [MASTER_IPA] = &qxm_ipa,
+ [MASTER_QDSS_ETR] = &xm_qdss_etr,
+ [MASTER_USB3] = &xm_usb3_0,
+ [SLAVE_A2NOC_SNOC] = &qns_a2noc_snoc,
+ [SLAVE_SERVICE_A2NOC] = &srvc_aggre2_noc,
+};
+
+static const struct qcom_icc_desc sdm670_aggre2_noc = {
+ .nodes = aggre2_noc_nodes,
+ .num_nodes = ARRAY_SIZE(aggre2_noc_nodes),
+ .bcms = aggre2_noc_bcms,
+ .num_bcms = ARRAY_SIZE(aggre2_noc_bcms),
+};
+
+static struct qcom_icc_bcm * const config_noc_bcms[] = {
+ &bcm_cn0,
+};
+
+static struct qcom_icc_node * const config_noc_nodes[] = {
+ [MASTER_SPDM] = &qhm_spdm,
+ [MASTER_SNOC_CNOC] = &qnm_snoc,
+ [SLAVE_A1NOC_CFG] = &qhs_a1_noc_cfg,
+ [SLAVE_A2NOC_CFG] = &qhs_a2_noc_cfg,
+ [SLAVE_AOP] = &qhs_aop,
+ [SLAVE_AOSS] = &qhs_aoss,
+ [SLAVE_CAMERA_CFG] = &qhs_camera_cfg,
+ [SLAVE_CLK_CTL] = &qhs_clk_ctl,
+ [SLAVE_CDSP_CFG] = &qhs_compute_dsp_cfg,
+ [SLAVE_RBCPR_CX_CFG] = &qhs_cpr_cx,
+ [SLAVE_CRYPTO_0_CFG] = &qhs_crypto0_cfg,
+ [SLAVE_DCC_CFG] = &qhs_dcc_cfg,
+ [SLAVE_CNOC_DDRSS] = &qhs_ddrss_cfg,
+ [SLAVE_DISPLAY_CFG] = &qhs_display_cfg,
+ [SLAVE_EMMC_CFG] = &qhs_emmc_cfg,
+ [SLAVE_GLM] = &qhs_glm,
+ [SLAVE_GRAPHICS_3D_CFG] = &qhs_gpuss_cfg,
+ [SLAVE_IMEM_CFG] = &qhs_imem_cfg,
+ [SLAVE_IPA_CFG] = &qhs_ipa,
+ [SLAVE_CNOC_MNOC_CFG] = &qhs_mnoc_cfg,
+ [SLAVE_PDM] = &qhs_pdm,
+ [SLAVE_SOUTH_PHY_CFG] = &qhs_phy_refgen_south,
+ [SLAVE_PIMEM_CFG] = &qhs_pimem_cfg,
+ [SLAVE_PRNG] = &qhs_prng,
+ [SLAVE_QDSS_CFG] = &qhs_qdss_cfg,
+ [SLAVE_BLSP_2] = &qhs_qupv3_north,
+ [SLAVE_BLSP_1] = &qhs_qupv3_south,
+ [SLAVE_SDCC_2] = &qhs_sdc2,
+ [SLAVE_SDCC_4] = &qhs_sdc4,
+ [SLAVE_SNOC_CFG] = &qhs_snoc_cfg,
+ [SLAVE_SPDM_WRAPPER] = &qhs_spdm,
+ [SLAVE_TCSR] = &qhs_tcsr,
+ [SLAVE_TLMM_NORTH] = &qhs_tlmm_north,
+ [SLAVE_TLMM_SOUTH] = &qhs_tlmm_south,
+ [SLAVE_TSIF] = &qhs_tsif,
+ [SLAVE_UFS_MEM_CFG] = &qhs_ufs_mem_cfg,
+ [SLAVE_USB3] = &qhs_usb3_0,
+ [SLAVE_VENUS_CFG] = &qhs_venus_cfg,
+ [SLAVE_VSENSE_CTRL_CFG] = &qhs_vsense_ctrl_cfg,
+ [SLAVE_CNOC_A2NOC] = &qns_cnoc_a2noc,
+ [SLAVE_SERVICE_CNOC] = &srvc_cnoc,
+};
+
+static const struct qcom_icc_desc sdm670_config_noc = {
+ .nodes = config_noc_nodes,
+ .num_nodes = ARRAY_SIZE(config_noc_nodes),
+ .bcms = config_noc_bcms,
+ .num_bcms = ARRAY_SIZE(config_noc_bcms),
+};
+
+static struct qcom_icc_bcm * const dc_noc_bcms[] = {
+};
+
+static struct qcom_icc_node * const dc_noc_nodes[] = {
+ [MASTER_CNOC_DC_NOC] = &qhm_cnoc,
+ [SLAVE_LLCC_CFG] = &qhs_llcc,
+ [SLAVE_MEM_NOC_CFG] = &qhs_memnoc,
+};
+
+static const struct qcom_icc_desc sdm670_dc_noc = {
+ .nodes = dc_noc_nodes,
+ .num_nodes = ARRAY_SIZE(dc_noc_nodes),
+ .bcms = dc_noc_bcms,
+ .num_bcms = ARRAY_SIZE(dc_noc_bcms),
+};
+
+static struct qcom_icc_bcm * const gladiator_noc_bcms[] = {
+};
+
+static struct qcom_icc_node * const gladiator_noc_nodes[] = {
+ [MASTER_AMPSS_M0] = &acm_l3,
+ [MASTER_GNOC_CFG] = &pm_gnoc_cfg,
+ [SLAVE_GNOC_SNOC] = &qns_gladiator_sodv,
+ [SLAVE_GNOC_MEM_NOC] = &qns_gnoc_memnoc,
+ [SLAVE_SERVICE_GNOC] = &srvc_gnoc,
+};
+
+static const struct qcom_icc_desc sdm670_gladiator_noc = {
+ .nodes = gladiator_noc_nodes,
+ .num_nodes = ARRAY_SIZE(gladiator_noc_nodes),
+ .bcms = gladiator_noc_bcms,
+ .num_bcms = ARRAY_SIZE(gladiator_noc_bcms),
+};
+
+static struct qcom_icc_bcm * const mem_noc_bcms[] = {
+ &bcm_acv,
+ &bcm_mc0,
+ &bcm_sh0,
+ &bcm_sh1,
+ &bcm_sh2,
+ &bcm_sh3,
+ &bcm_sh5,
+};
+
+static struct qcom_icc_node * const mem_noc_nodes[] = {
+ [MASTER_TCU_0] = &acm_tcu,
+ [MASTER_MEM_NOC_CFG] = &qhm_memnoc_cfg,
+ [MASTER_GNOC_MEM_NOC] = &qnm_apps,
+ [MASTER_MNOC_HF_MEM_NOC] = &qnm_mnoc_hf,
+ [MASTER_MNOC_SF_MEM_NOC] = &qnm_mnoc_sf,
+ [MASTER_SNOC_GC_MEM_NOC] = &qnm_snoc_gc,
+ [MASTER_SNOC_SF_MEM_NOC] = &qnm_snoc_sf,
+ [MASTER_GRAPHICS_3D] = &qxm_gpu,
+ [SLAVE_MSS_PROC_MS_MPU_CFG] = &qhs_mdsp_ms_mpu_cfg,
+ [SLAVE_MEM_NOC_GNOC] = &qns_apps_io,
+ [SLAVE_LLCC] = &qns_llcc,
+ [SLAVE_MEM_NOC_SNOC] = &qns_memnoc_snoc,
+ [SLAVE_SERVICE_MEM_NOC] = &srvc_memnoc,
+ [MASTER_LLCC] = &llcc_mc,
+ [SLAVE_EBI_CH0] = &ebi,
+};
+
+static const struct qcom_icc_desc sdm670_mem_noc = {
+ .nodes = mem_noc_nodes,
+ .num_nodes = ARRAY_SIZE(mem_noc_nodes),
+ .bcms = mem_noc_bcms,
+ .num_bcms = ARRAY_SIZE(mem_noc_bcms),
+};
+
+static struct qcom_icc_bcm * const mmss_noc_bcms[] = {
+ &bcm_mm0,
+ &bcm_mm1,
+ &bcm_mm2,
+ &bcm_mm3,
+};
+
+static struct qcom_icc_node * const mmss_noc_nodes[] = {
+ [MASTER_CNOC_MNOC_CFG] = &qhm_mnoc_cfg,
+ [MASTER_CAMNOC_HF0] = &qxm_camnoc_hf0,
+ [MASTER_CAMNOC_HF1] = &qxm_camnoc_hf1,
+ [MASTER_CAMNOC_SF] = &qxm_camnoc_sf,
+ [MASTER_MDP_PORT0] = &qxm_mdp0,
+ [MASTER_MDP_PORT1] = &qxm_mdp1,
+ [MASTER_ROTATOR] = &qxm_rot,
+ [MASTER_VIDEO_P0] = &qxm_venus0,
+ [MASTER_VIDEO_P1] = &qxm_venus1,
+ [MASTER_VIDEO_PROC] = &qxm_venus_arm9,
+ [SLAVE_MNOC_SF_MEM_NOC] = &qns2_mem_noc,
+ [SLAVE_MNOC_HF_MEM_NOC] = &qns_mem_noc_hf,
+ [SLAVE_SERVICE_MNOC] = &srvc_mnoc,
+};
+
+static const struct qcom_icc_desc sdm670_mmss_noc = {
+ .nodes = mmss_noc_nodes,
+ .num_nodes = ARRAY_SIZE(mmss_noc_nodes),
+ .bcms = mmss_noc_bcms,
+ .num_bcms = ARRAY_SIZE(mmss_noc_bcms),
+};
+
+static struct qcom_icc_bcm * const system_noc_bcms[] = {
+ &bcm_mm1,
+ &bcm_sn0,
+ &bcm_sn1,
+ &bcm_sn10,
+ &bcm_sn11,
+ &bcm_sn13,
+ &bcm_sn2,
+ &bcm_sn3,
+ &bcm_sn4,
+ &bcm_sn5,
+ &bcm_sn8,
+};
+
+static struct qcom_icc_node * const system_noc_nodes[] = {
+ [MASTER_SNOC_CFG] = &qhm_snoc_cfg,
+ [MASTER_A1NOC_SNOC] = &qnm_aggre1_noc,
+ [MASTER_A2NOC_SNOC] = &qnm_aggre2_noc,
+ [MASTER_GNOC_SNOC] = &qnm_gladiator_sodv,
+ [MASTER_MEM_NOC_SNOC] = &qnm_memnoc,
+ [MASTER_PIMEM] = &qxm_pimem,
+ [MASTER_GIC] = &xm_gic,
+ [SLAVE_APPSS] = &qhs_apss,
+ [SLAVE_SNOC_CNOC] = &qns_cnoc,
+ [SLAVE_SNOC_MEM_NOC_GC] = &qns_memnoc_gc,
+ [SLAVE_SNOC_MEM_NOC_SF] = &qns_memnoc_sf,
+ [SLAVE_OCIMEM] = &qxs_imem,
+ [SLAVE_PIMEM] = &qxs_pimem,
+ [SLAVE_SERVICE_SNOC] = &srvc_snoc,
+ [SLAVE_QDSS_STM] = &xs_qdss_stm,
+ [SLAVE_TCU] = &xs_sys_tcu_cfg,
+ [MASTER_CAMNOC_HF0_UNCOMP] = &qxm_camnoc_hf0_uncomp,
+ [MASTER_CAMNOC_HF1_UNCOMP] = &qxm_camnoc_hf1_uncomp,
+ [MASTER_CAMNOC_SF_UNCOMP] = &qxm_camnoc_sf_uncomp,
+ [SLAVE_CAMNOC_UNCOMP] = &qns_camnoc_uncomp,
+};
+
+static const struct qcom_icc_desc sdm670_system_noc = {
+ .nodes = system_noc_nodes,
+ .num_nodes = ARRAY_SIZE(system_noc_nodes),
+ .bcms = system_noc_bcms,
+ .num_bcms = ARRAY_SIZE(system_noc_bcms),
+};
+
+static const struct of_device_id qnoc_of_match[] = {
+ { .compatible = "qcom,sdm670-aggre1-noc",
+ .data = &sdm670_aggre1_noc},
+ { .compatible = "qcom,sdm670-aggre2-noc",
+ .data = &sdm670_aggre2_noc},
+ { .compatible = "qcom,sdm670-config-noc",
+ .data = &sdm670_config_noc},
+ { .compatible = "qcom,sdm670-dc-noc",
+ .data = &sdm670_dc_noc},
+ { .compatible = "qcom,sdm670-gladiator-noc",
+ .data = &sdm670_gladiator_noc},
+ { .compatible = "qcom,sdm670-mem-noc",
+ .data = &sdm670_mem_noc},
+ { .compatible = "qcom,sdm670-mmss-noc",
+ .data = &sdm670_mmss_noc},
+ { .compatible = "qcom,sdm670-system-noc",
+ .data = &sdm670_system_noc},
+ { }
+};
+MODULE_DEVICE_TABLE(of, qnoc_of_match);
+
+static struct platform_driver qnoc_driver = {
+ .probe = qcom_icc_rpmh_probe,
+ .remove = qcom_icc_rpmh_remove,
+ .driver = {
+ .name = "qnoc-sdm670",
+ .of_match_table = qnoc_of_match,
+ .sync_state = icc_sync_state,
+ },
+};
+module_platform_driver(qnoc_driver);
+
+MODULE_DESCRIPTION("Qualcomm SDM670 NoC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/interconnect/qcom/sdm670.h b/drivers/interconnect/qcom/sdm670.h
new file mode 100644
index 000000000000..14155f244c43
--- /dev/null
+++ b/drivers/interconnect/qcom/sdm670.h
@@ -0,0 +1,128 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Qualcomm #define SDM670 interconnect IDs
+ *
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef __DRIVERS_INTERCONNECT_QCOM_SDM670_H
+#define __DRIVERS_INTERCONNECT_QCOM_SDM670_H
+
+#define SDM670_MASTER_A1NOC_CFG 0
+#define SDM670_MASTER_A1NOC_SNOC 1
+#define SDM670_MASTER_A2NOC_CFG 2
+#define SDM670_MASTER_A2NOC_SNOC 3
+#define SDM670_MASTER_AMPSS_M0 4
+#define SDM670_MASTER_BLSP_1 5
+#define SDM670_MASTER_BLSP_2 6
+#define SDM670_MASTER_CAMNOC_HF0 7
+#define SDM670_MASTER_CAMNOC_HF0_UNCOMP 8
+#define SDM670_MASTER_CAMNOC_HF1 9
+#define SDM670_MASTER_CAMNOC_HF1_UNCOMP 10
+#define SDM670_MASTER_CAMNOC_SF 11
+#define SDM670_MASTER_CAMNOC_SF_UNCOMP 12
+#define SDM670_MASTER_CNOC_A2NOC 13
+#define SDM670_MASTER_CNOC_DC_NOC 14
+#define SDM670_MASTER_CNOC_MNOC_CFG 15
+#define SDM670_MASTER_CRYPTO_CORE_0 16
+#define SDM670_MASTER_EMMC 17
+#define SDM670_MASTER_GIC 18
+#define SDM670_MASTER_GNOC_CFG 19
+#define SDM670_MASTER_GNOC_MEM_NOC 20
+#define SDM670_MASTER_GNOC_SNOC 21
+#define SDM670_MASTER_GRAPHICS_3D 22
+#define SDM670_MASTER_IPA 23
+#define SDM670_MASTER_LLCC 24
+#define SDM670_MASTER_MDP_PORT0 25
+#define SDM670_MASTER_MDP_PORT1 26
+#define SDM670_MASTER_MEM_NOC_CFG 27
+#define SDM670_MASTER_MEM_NOC_SNOC 28
+#define SDM670_MASTER_MNOC_HF_MEM_NOC 29
+#define SDM670_MASTER_MNOC_SF_MEM_NOC 30
+#define SDM670_MASTER_PIMEM 31
+#define SDM670_MASTER_QDSS_BAM 32
+#define SDM670_MASTER_QDSS_ETR 33
+#define SDM670_MASTER_ROTATOR 34
+#define SDM670_MASTER_SDCC_2 35
+#define SDM670_MASTER_SDCC_4 36
+#define SDM670_MASTER_SNOC_CFG 37
+#define SDM670_MASTER_SNOC_CNOC 38
+#define SDM670_MASTER_SNOC_GC_MEM_NOC 39
+#define SDM670_MASTER_SNOC_SF_MEM_NOC 40
+#define SDM670_MASTER_SPDM 41
+#define SDM670_MASTER_TCU_0 42
+#define SDM670_MASTER_TSIF 43
+#define SDM670_MASTER_UFS_MEM 44
+#define SDM670_MASTER_USB3 45
+#define SDM670_MASTER_VIDEO_P0 46
+#define SDM670_MASTER_VIDEO_P1 47
+#define SDM670_MASTER_VIDEO_PROC 48
+#define SDM670_SLAVE_A1NOC_CFG 49
+#define SDM670_SLAVE_A1NOC_SNOC 50
+#define SDM670_SLAVE_A2NOC_CFG 51
+#define SDM670_SLAVE_A2NOC_SNOC 52
+#define SDM670_SLAVE_AOP 53
+#define SDM670_SLAVE_AOSS 54
+#define SDM670_SLAVE_APPSS 55
+#define SDM670_SLAVE_BLSP_1 56
+#define SDM670_SLAVE_BLSP_2 57
+#define SDM670_SLAVE_CAMERA_CFG 58
+#define SDM670_SLAVE_CAMNOC_UNCOMP 59
+#define SDM670_SLAVE_CDSP_CFG 60
+#define SDM670_SLAVE_CLK_CTL 61
+#define SDM670_SLAVE_CNOC_A2NOC 62
+#define SDM670_SLAVE_CNOC_DDRSS 63
+#define SDM670_SLAVE_CNOC_MNOC_CFG 64
+#define SDM670_SLAVE_CRYPTO_0_CFG 65
+#define SDM670_SLAVE_DCC_CFG 66
+#define SDM670_SLAVE_DISPLAY_CFG 67
+#define SDM670_SLAVE_EBI_CH0 68
+#define SDM670_SLAVE_EMMC_CFG 69
+#define SDM670_SLAVE_GLM 70
+#define SDM670_SLAVE_GNOC_MEM_NOC 71
+#define SDM670_SLAVE_GNOC_SNOC 72
+#define SDM670_SLAVE_GRAPHICS_3D_CFG 73
+#define SDM670_SLAVE_IMEM_CFG 74
+#define SDM670_SLAVE_IPA_CFG 75
+#define SDM670_SLAVE_LLCC 76
+#define SDM670_SLAVE_LLCC_CFG 77
+#define SDM670_SLAVE_MEM_NOC_CFG 78
+#define SDM670_SLAVE_MEM_NOC_GNOC 79
+#define SDM670_SLAVE_MEM_NOC_SNOC 80
+#define SDM670_SLAVE_MNOC_HF_MEM_NOC 81
+#define SDM670_SLAVE_MNOC_SF_MEM_NOC 82
+#define SDM670_SLAVE_MSS_PROC_MS_MPU_CFG 83
+#define SDM670_SLAVE_OCIMEM 84
+#define SDM670_SLAVE_PDM 85
+#define SDM670_SLAVE_PIMEM 86
+#define SDM670_SLAVE_PIMEM_CFG 87
+#define SDM670_SLAVE_PRNG 88
+#define SDM670_SLAVE_QDSS_CFG 89
+#define SDM670_SLAVE_QDSS_STM 90
+#define SDM670_SLAVE_RBCPR_CX_CFG 91
+#define SDM670_SLAVE_SDCC_2 92
+#define SDM670_SLAVE_SDCC_4 93
+#define SDM670_SLAVE_SERVICE_A1NOC 94
+#define SDM670_SLAVE_SERVICE_A2NOC 95
+#define SDM670_SLAVE_SERVICE_CNOC 96
+#define SDM670_SLAVE_SERVICE_GNOC 97
+#define SDM670_SLAVE_SERVICE_MEM_NOC 98
+#define SDM670_SLAVE_SERVICE_MNOC 99
+#define SDM670_SLAVE_SERVICE_SNOC 100
+#define SDM670_SLAVE_SNOC_CFG 101
+#define SDM670_SLAVE_SNOC_CNOC 102
+#define SDM670_SLAVE_SNOC_MEM_NOC_GC 103
+#define SDM670_SLAVE_SNOC_MEM_NOC_SF 104
+#define SDM670_SLAVE_SOUTH_PHY_CFG 105
+#define SDM670_SLAVE_SPDM_WRAPPER 106
+#define SDM670_SLAVE_TCSR 107
+#define SDM670_SLAVE_TCU 108
+#define SDM670_SLAVE_TLMM_NORTH 109
+#define SDM670_SLAVE_TLMM_SOUTH 110
+#define SDM670_SLAVE_TSIF 111
+#define SDM670_SLAVE_UFS_MEM_CFG 112
+#define SDM670_SLAVE_USB3 113
+#define SDM670_SLAVE_VENUS_CFG 114
+#define SDM670_SLAVE_VSENSE_CTRL_CFG 115
+
+#endif
diff --git a/drivers/interconnect/qcom/sdx55.h b/drivers/interconnect/qcom/sdx55.h
index deff8afe0631..46cbabec8aa1 100644
--- a/drivers/interconnect/qcom/sdx55.h
+++ b/drivers/interconnect/qcom/sdx55.h
@@ -6,7 +6,7 @@
#ifndef __DRIVERS_INTERCONNECT_QCOM_SDX55_H
#define __DRIVERS_INTERCONNECT_QCOM_SDX55_H
-#define SDX55_MASTER_IPA_CORE 0
+/* 0 was used by MASTER_IPA_CORE, now represented as RPMh clock */
#define SDX55_MASTER_LLCC 1
#define SDX55_MASTER_TCU_0 2
#define SDX55_MASTER_SNOC_GC_MEM_NOC 3
@@ -28,7 +28,7 @@
#define SDX55_MASTER_QDSS_ETR 19
#define SDX55_MASTER_SDCC_1 20
#define SDX55_MASTER_USB3 21
-#define SDX55_SLAVE_IPA_CORE 22
+/* 22 was used by SLAVE_IPA_CORE, now represented as RPMh clock */
#define SDX55_SLAVE_EBI_CH0 23
#define SDX55_SLAVE_LLCC 24
#define SDX55_SLAVE_MEM_NOC_SNOC 25
diff --git a/drivers/interconnect/qcom/sm8150.c b/drivers/interconnect/qcom/sm8150.c
index 1d04a4bfea80..c5ab29322164 100644
--- a/drivers/interconnect/qcom/sm8150.c
+++ b/drivers/interconnect/qcom/sm8150.c
@@ -56,7 +56,6 @@ DEFINE_QNODE(qnm_pcie, SM8150_MASTER_GEM_NOC_PCIE_SNOC, 1, 16, SM8150_SLAVE_LLCC
DEFINE_QNODE(qnm_snoc_gc, SM8150_MASTER_SNOC_GC_MEM_NOC, 1, 8, SM8150_SLAVE_LLCC);
DEFINE_QNODE(qnm_snoc_sf, SM8150_MASTER_SNOC_SF_MEM_NOC, 1, 16, SM8150_SLAVE_LLCC);
DEFINE_QNODE(qxm_ecc, SM8150_MASTER_ECC, 2, 32, SM8150_SLAVE_LLCC);
-DEFINE_QNODE(ipa_core_master, SM8150_MASTER_IPA_CORE, 1, 8, SM8150_SLAVE_IPA_CORE);
DEFINE_QNODE(llcc_mc, SM8150_MASTER_LLCC, 4, 4, SM8150_SLAVE_EBI_CH0);
DEFINE_QNODE(qhm_mnoc_cfg, SM8150_MASTER_CNOC_MNOC_CFG, 1, 4, SM8150_SLAVE_SERVICE_MNOC);
DEFINE_QNODE(qxm_camnoc_hf0, SM8150_MASTER_CAMNOC_HF0, 1, 32, SM8150_SLAVE_MNOC_HF_MEM_NOC);
@@ -139,7 +138,6 @@ DEFINE_QNODE(qns_ecc, SM8150_SLAVE_ECC, 1, 32);
DEFINE_QNODE(qns_gem_noc_snoc, SM8150_SLAVE_GEM_NOC_SNOC, 1, 8, SM8150_MASTER_GEM_NOC_SNOC);
DEFINE_QNODE(qns_llcc, SM8150_SLAVE_LLCC, 4, 16, SM8150_MASTER_LLCC);
DEFINE_QNODE(srvc_gemnoc, SM8150_SLAVE_SERVICE_GEM_NOC, 1, 4);
-DEFINE_QNODE(ipa_core_slave, SM8150_SLAVE_IPA_CORE, 1, 8);
DEFINE_QNODE(ebi, SM8150_SLAVE_EBI_CH0, 4, 4);
DEFINE_QNODE(qns2_mem_noc, SM8150_SLAVE_MNOC_SF_MEM_NOC, 1, 32, SM8150_MASTER_MNOC_SF_MEM_NOC);
DEFINE_QNODE(qns_mem_noc_hf, SM8150_SLAVE_MNOC_HF_MEM_NOC, 2, 32, SM8150_MASTER_MNOC_HF_MEM_NOC);
@@ -172,7 +170,6 @@ DEFINE_QBCM(bcm_co0, "CO0", false, &qns_cdsp_mem_noc);
DEFINE_QBCM(bcm_ce0, "CE0", false, &qxm_crypto);
DEFINE_QBCM(bcm_sn1, "SN1", false, &qxs_imem);
DEFINE_QBCM(bcm_co1, "CO1", false, &qnm_npu);
-DEFINE_QBCM(bcm_ip0, "IP0", false, &ipa_core_slave);
DEFINE_QBCM(bcm_cn0, "CN0", true, &qhm_spdm, &qnm_snoc, &qhs_a1_noc_cfg, &qhs_a2_noc_cfg, &qhs_ahb2phy_south, &qhs_aop, &qhs_aoss, &qhs_camera_cfg, &qhs_clk_ctl, &qhs_compute_dsp, &qhs_cpr_cx, &qhs_cpr_mmcx, &qhs_cpr_mx, &qhs_crypto0_cfg, &qhs_ddrss_cfg, &qhs_display_cfg, &qhs_emac_cfg, &qhs_glm, &qhs_gpuss_cfg, &qhs_imem_cfg, &qhs_ipa, &qhs_mnoc_cfg, &qhs_npu_cfg, &qhs_pcie0_cfg, &qhs_pcie1_cfg, &qhs_phy_refgen_north, &qhs_pimem_cfg, &qhs_prng, &qhs_qdss_cfg, &qhs_qspi, &qhs_qupv3_east, &qhs_qupv3_north, &qhs_qupv3_south, &qhs_sdc2, &qhs_sdc4, &qhs_snoc_cfg, &qhs_spdm, &qhs_spss_cfg, &qhs_ssc_cfg, &qhs_tcsr, &qhs_tlmm_east, &qhs_tlmm_north, &qhs_tlmm_south, &qhs_tlmm_west, &qhs_tsif, &qhs_ufs_card_cfg, &qhs_ufs_mem_cfg, &qhs_usb3_0, &qhs_usb3_1, &qhs_venus_cfg, &qhs_vsense_ctrl_cfg, &qns_cnoc_a2noc, &srvc_cnoc);
DEFINE_QBCM(bcm_qup0, "QUP0", false, &qhm_qup0, &qhm_qup1, &qhm_qup2);
DEFINE_QBCM(bcm_sn2, "SN2", false, &qns_gemnoc_gc);
@@ -398,22 +395,6 @@ static const struct qcom_icc_desc sm8150_gem_noc = {
.num_bcms = ARRAY_SIZE(gem_noc_bcms),
};
-static struct qcom_icc_bcm * const ipa_virt_bcms[] = {
- &bcm_ip0,
-};
-
-static struct qcom_icc_node * const ipa_virt_nodes[] = {
- [MASTER_IPA_CORE] = &ipa_core_master,
- [SLAVE_IPA_CORE] = &ipa_core_slave,
-};
-
-static const struct qcom_icc_desc sm8150_ipa_virt = {
- .nodes = ipa_virt_nodes,
- .num_nodes = ARRAY_SIZE(ipa_virt_nodes),
- .bcms = ipa_virt_bcms,
- .num_bcms = ARRAY_SIZE(ipa_virt_bcms),
-};
-
static struct qcom_icc_bcm * const mc_virt_bcms[] = {
&bcm_acv,
&bcm_mc0,
@@ -517,8 +498,6 @@ static const struct of_device_id qnoc_of_match[] = {
.data = &sm8150_dc_noc},
{ .compatible = "qcom,sm8150-gem-noc",
.data = &sm8150_gem_noc},
- { .compatible = "qcom,sm8150-ipa-virt",
- .data = &sm8150_ipa_virt},
{ .compatible = "qcom,sm8150-mc-virt",
.data = &sm8150_mc_virt},
{ .compatible = "qcom,sm8150-mmss-noc",
diff --git a/drivers/interconnect/qcom/sm8150.h b/drivers/interconnect/qcom/sm8150.h
index 97996f64d799..023161681fb8 100644
--- a/drivers/interconnect/qcom/sm8150.h
+++ b/drivers/interconnect/qcom/sm8150.h
@@ -35,7 +35,7 @@
#define SM8150_MASTER_GPU_TCU 24
#define SM8150_MASTER_GRAPHICS_3D 25
#define SM8150_MASTER_IPA 26
-#define SM8150_MASTER_IPA_CORE 27
+/* 27 was used by SLAVE_IPA_CORE, now represented as RPMh clock */
#define SM8150_MASTER_LLCC 28
#define SM8150_MASTER_MDP_PORT0 29
#define SM8150_MASTER_MDP_PORT1 30
@@ -94,7 +94,7 @@
#define SM8150_SLAVE_GRAPHICS_3D_CFG 83
#define SM8150_SLAVE_IMEM_CFG 84
#define SM8150_SLAVE_IPA_CFG 85
-#define SM8150_SLAVE_IPA_CORE 86
+/* 86 was used by SLAVE_IPA_CORE, now represented as RPMh clock */
#define SM8150_SLAVE_LLCC 87
#define SM8150_SLAVE_LLCC_CFG 88
#define SM8150_SLAVE_MNOC_HF_MEM_NOC 89
diff --git a/drivers/interconnect/qcom/sm8250.c b/drivers/interconnect/qcom/sm8250.c
index 5cdb058fa095..e3bb008cb219 100644
--- a/drivers/interconnect/qcom/sm8250.c
+++ b/drivers/interconnect/qcom/sm8250.c
@@ -51,7 +51,6 @@ DEFINE_QNODE(qnm_mnoc_sf, SM8250_MASTER_MNOC_SF_MEM_NOC, 2, 32, SM8250_SLAVE_LLC
DEFINE_QNODE(qnm_pcie, SM8250_MASTER_ANOC_PCIE_GEM_NOC, 1, 16, SM8250_SLAVE_LLCC, SM8250_SLAVE_GEM_NOC_SNOC);
DEFINE_QNODE(qnm_snoc_gc, SM8250_MASTER_SNOC_GC_MEM_NOC, 1, 8, SM8250_SLAVE_LLCC);
DEFINE_QNODE(qnm_snoc_sf, SM8250_MASTER_SNOC_SF_MEM_NOC, 1, 16, SM8250_SLAVE_LLCC, SM8250_SLAVE_GEM_NOC_SNOC, SM8250_SLAVE_MEM_NOC_PCIE_SNOC);
-DEFINE_QNODE(ipa_core_master, SM8250_MASTER_IPA_CORE, 1, 8, SM8250_SLAVE_IPA_CORE);
DEFINE_QNODE(llcc_mc, SM8250_MASTER_LLCC, 4, 4, SM8250_SLAVE_EBI_CH0);
DEFINE_QNODE(qhm_mnoc_cfg, SM8250_MASTER_CNOC_MNOC_CFG, 1, 4, SM8250_SLAVE_SERVICE_MNOC);
DEFINE_QNODE(qnm_camnoc_hf, SM8250_MASTER_CAMNOC_HF, 2, 32, SM8250_SLAVE_MNOC_HF_MEM_NOC);
@@ -138,7 +137,6 @@ DEFINE_QNODE(qns_sys_pcie, SM8250_SLAVE_MEM_NOC_PCIE_SNOC, 1, 8, SM8250_MASTER_G
DEFINE_QNODE(srvc_even_gemnoc, SM8250_SLAVE_SERVICE_GEM_NOC_1, 1, 4);
DEFINE_QNODE(srvc_odd_gemnoc, SM8250_SLAVE_SERVICE_GEM_NOC_2, 1, 4);
DEFINE_QNODE(srvc_sys_gemnoc, SM8250_SLAVE_SERVICE_GEM_NOC, 1, 4);
-DEFINE_QNODE(ipa_core_slave, SM8250_SLAVE_IPA_CORE, 1, 8);
DEFINE_QNODE(ebi, SM8250_SLAVE_EBI_CH0, 4, 4);
DEFINE_QNODE(qns_mem_noc_hf, SM8250_SLAVE_MNOC_HF_MEM_NOC, 2, 32, SM8250_MASTER_MNOC_HF_MEM_NOC);
DEFINE_QNODE(qns_mem_noc_sf, SM8250_SLAVE_MNOC_SF_MEM_NOC, 2, 32, SM8250_MASTER_MNOC_SF_MEM_NOC);
@@ -171,7 +169,6 @@ DEFINE_QBCM(bcm_mc0, "MC0", true, &ebi);
DEFINE_QBCM(bcm_sh0, "SH0", true, &qns_llcc);
DEFINE_QBCM(bcm_mm0, "MM0", true, &qns_mem_noc_hf);
DEFINE_QBCM(bcm_ce0, "CE0", false, &qxm_crypto);
-DEFINE_QBCM(bcm_ip0, "IP0", false, &ipa_core_slave);
DEFINE_QBCM(bcm_mm1, "MM1", false, &qnm_camnoc_hf, &qxm_mdp0, &qxm_mdp1);
DEFINE_QBCM(bcm_sh2, "SH2", false, &alm_gpu_tcu, &alm_sys_tcu);
DEFINE_QBCM(bcm_mm2, "MM2", false, &qns_mem_noc_sf);
@@ -386,22 +383,6 @@ static const struct qcom_icc_desc sm8250_gem_noc = {
.num_bcms = ARRAY_SIZE(gem_noc_bcms),
};
-static struct qcom_icc_bcm * const ipa_virt_bcms[] = {
- &bcm_ip0,
-};
-
-static struct qcom_icc_node * const ipa_virt_nodes[] = {
- [MASTER_IPA_CORE] = &ipa_core_master,
- [SLAVE_IPA_CORE] = &ipa_core_slave,
-};
-
-static const struct qcom_icc_desc sm8250_ipa_virt = {
- .nodes = ipa_virt_nodes,
- .num_nodes = ARRAY_SIZE(ipa_virt_nodes),
- .bcms = ipa_virt_bcms,
- .num_bcms = ARRAY_SIZE(ipa_virt_bcms),
-};
-
static struct qcom_icc_bcm * const mc_virt_bcms[] = {
&bcm_acv,
&bcm_mc0,
@@ -531,8 +512,6 @@ static const struct of_device_id qnoc_of_match[] = {
.data = &sm8250_dc_noc},
{ .compatible = "qcom,sm8250-gem-noc",
.data = &sm8250_gem_noc},
- { .compatible = "qcom,sm8250-ipa-virt",
- .data = &sm8250_ipa_virt},
{ .compatible = "qcom,sm8250-mc-virt",
.data = &sm8250_mc_virt},
{ .compatible = "qcom,sm8250-mmss-noc",
diff --git a/drivers/interconnect/qcom/sm8250.h b/drivers/interconnect/qcom/sm8250.h
index b31fb431a20f..e3fc56bc7ca0 100644
--- a/drivers/interconnect/qcom/sm8250.h
+++ b/drivers/interconnect/qcom/sm8250.h
@@ -31,7 +31,7 @@
#define SM8250_MASTER_GPU_TCU 20
#define SM8250_MASTER_GRAPHICS_3D 21
#define SM8250_MASTER_IPA 22
-#define SM8250_MASTER_IPA_CORE 23
+/* 23 was used by MASTER_IPA_CORE, now represented as RPMh clock */
#define SM8250_MASTER_LLCC 24
#define SM8250_MASTER_MDP_PORT0 25
#define SM8250_MASTER_MDP_PORT1 26
@@ -92,7 +92,7 @@
#define SM8250_SLAVE_GRAPHICS_3D_CFG 81
#define SM8250_SLAVE_IMEM_CFG 82
#define SM8250_SLAVE_IPA_CFG 83
-#define SM8250_SLAVE_IPA_CORE 84
+/* 84 was used by SLAVE_IPA_CORE, now represented as RPMh clock */
#define SM8250_SLAVE_IPC_ROUTER_CFG 85
#define SM8250_SLAVE_ISENSE_CFG 86
#define SM8250_SLAVE_LLCC 87
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 79707685d54a..889c7efd050b 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -32,7 +32,8 @@ config IOMMU_IO_PGTABLE
config IOMMU_IO_PGTABLE_LPAE
bool "ARMv7/v8 Long Descriptor Format"
select IOMMU_IO_PGTABLE
- depends on ARM || ARM64 || (COMPILE_TEST && !GENERIC_ATOMIC64)
+ depends on ARM || ARM64 || COMPILE_TEST
+ depends on !GENERIC_ATOMIC64 # for cpmxchg64()
help
Enable support for the ARM long descriptor pagetable format.
This allocator supports 4K/2M/1G, 16K/32M and 64K/512M page
@@ -70,7 +71,8 @@ config IOMMU_IO_PGTABLE_ARMV7S_SELFTEST
config IOMMU_IO_PGTABLE_DART
bool "Apple DART Formats"
select IOMMU_IO_PGTABLE
- depends on ARM64 || (COMPILE_TEST && !GENERIC_ATOMIC64)
+ depends on ARM64 || COMPILE_TEST
+ depends on !GENERIC_ATOMIC64 # for cpmxchg64()
help
Enable support for the Apple DART pagetable formats. These include
the t8020 and t6000/t8110 DART formats used in Apple M1/M2 family
@@ -284,7 +286,8 @@ config EXYNOS_IOMMU_DEBUG
config IPMMU_VMSA
bool "Renesas VMSA-compatible IPMMU"
- depends on ARCH_RENESAS || (COMPILE_TEST && !GENERIC_ATOMIC64)
+ depends on ARCH_RENESAS || COMPILE_TEST
+ depends on !GENERIC_ATOMIC64 # for IOMMU_IO_PGTABLE_LPAE
select IOMMU_API
select IOMMU_IO_PGTABLE_LPAE
select ARM_DMA_USE_IOMMU
@@ -304,7 +307,8 @@ config SPAPR_TCE_IOMMU
config APPLE_DART
tristate "Apple DART IOMMU Support"
- depends on ARCH_APPLE || (COMPILE_TEST && !GENERIC_ATOMIC64)
+ depends on ARCH_APPLE || COMPILE_TEST
+ depends on !GENERIC_ATOMIC64 # for IOMMU_IO_PGTABLE_DART
select IOMMU_API
select IOMMU_IO_PGTABLE_DART
default ARCH_APPLE
@@ -319,7 +323,8 @@ config APPLE_DART
# ARM IOMMU support
config ARM_SMMU
tristate "ARM Ltd. System MMU (SMMU) Support"
- depends on ARM64 || ARM || (COMPILE_TEST && !GENERIC_ATOMIC64)
+ depends on ARM64 || ARM || COMPILE_TEST
+ depends on !GENERIC_ATOMIC64 # for IOMMU_IO_PGTABLE_LPAE
select IOMMU_API
select IOMMU_IO_PGTABLE_LPAE
select ARM_DMA_USE_IOMMU if ARM
@@ -466,7 +471,8 @@ config MTK_IOMMU_V1
config QCOM_IOMMU
# Note: iommu drivers cannot (yet?) be built as modules
bool "Qualcomm IOMMU Support"
- depends on ARCH_QCOM || (COMPILE_TEST && !GENERIC_ATOMIC64)
+ depends on ARCH_QCOM || COMPILE_TEST
+ depends on !GENERIC_ATOMIC64 # for IOMMU_IO_PGTABLE_LPAE
select QCOM_SCM
select IOMMU_API
select IOMMU_IO_PGTABLE_LPAE
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 467b194975b3..19a46b9f7357 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -3475,15 +3475,26 @@ found:
return 1;
}
+#define ACPIID_LEN (ACPIHID_UID_LEN + ACPIHID_HID_LEN)
+
static int __init parse_ivrs_acpihid(char *str)
{
u32 seg = 0, bus, dev, fn;
char *hid, *uid, *p, *addr;
- char acpiid[ACPIHID_UID_LEN + ACPIHID_HID_LEN] = {0};
+ char acpiid[ACPIID_LEN] = {0};
int i;
addr = strchr(str, '@');
if (!addr) {
+ addr = strchr(str, '=');
+ if (!addr)
+ goto not_found;
+
+ ++addr;
+
+ if (strlen(addr) > ACPIID_LEN)
+ goto not_found;
+
if (sscanf(str, "[%x:%x.%x]=%s", &bus, &dev, &fn, acpiid) == 4 ||
sscanf(str, "[%x:%x:%x.%x]=%s", &seg, &bus, &dev, &fn, acpiid) == 5) {
pr_warn("ivrs_acpihid%s option format deprecated; use ivrs_acpihid=%s@%04x:%02x:%02x.%d instead\n",
@@ -3496,6 +3507,9 @@ static int __init parse_ivrs_acpihid(char *str)
/* We have the '@', make it the terminator to get just the acpiid */
*addr++ = 0;
+ if (strlen(str) > ACPIID_LEN + 1)
+ goto not_found;
+
if (sscanf(str, "=%s", acpiid) != 1)
goto not_found;
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index cbeaab55c0db..5a505ba5467e 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -558,6 +558,15 @@ static void amd_iommu_report_page_fault(struct amd_iommu *iommu,
* prevent logging it.
*/
if (IS_IOMMU_MEM_TRANSACTION(flags)) {
+ /* Device not attached to domain properly */
+ if (dev_data->domain == NULL) {
+ pr_err_ratelimited("Event logged [Device not attached to domain properly]\n");
+ pr_err_ratelimited(" device=%04x:%02x:%02x.%x domain=0x%04x\n",
+ iommu->pci_seg->id, PCI_BUS_NUM(devid), PCI_SLOT(devid),
+ PCI_FUNC(devid), domain_id);
+ goto out;
+ }
+
if (!report_iommu_fault(&dev_data->domain->domain,
&pdev->dev, address,
IS_WRITE_REQUEST(flags) ?
@@ -667,7 +676,14 @@ retry:
event[0], event[1], event[2], event[3]);
}
- memset(__evt, 0, 4 * sizeof(u32));
+ /*
+ * To detect the hardware errata 732 we need to clear the
+ * entry back to zero. This issue does not exist on SNP
+ * enabled system. Also this buffer is not writeable on
+ * SNP enabled system.
+ */
+ if (!amd_iommu_snp_en)
+ memset(__evt, 0, 4 * sizeof(u32));
}
static void iommu_poll_events(struct amd_iommu *iommu)
@@ -736,10 +752,13 @@ static void iommu_poll_ppr_log(struct amd_iommu *iommu)
entry[1] = raw[1];
/*
- * To detect the hardware bug we need to clear the entry
- * back to zero.
+ * To detect the hardware errata 733 we need to clear the
+ * entry back to zero. This issue does not exist on SNP
+ * enabled system. Also this buffer is not writeable on
+ * SNP enabled system.
*/
- raw[0] = raw[1] = 0UL;
+ if (!amd_iommu_snp_en)
+ raw[0] = raw[1] = 0UL;
/* Update head pointer of hardware ring-buffer */
head = (head + PPR_ENTRY_SIZE) % PPR_LOG_SIZE;
@@ -1702,27 +1721,29 @@ static int pdev_pri_ats_enable(struct pci_dev *pdev)
/* Only allow access to user-accessible pages */
ret = pci_enable_pasid(pdev, 0);
if (ret)
- goto out_err;
+ return ret;
/* First reset the PRI state of the device */
ret = pci_reset_pri(pdev);
if (ret)
- goto out_err;
+ goto out_err_pasid;
/* Enable PRI */
/* FIXME: Hardcode number of outstanding requests for now */
ret = pci_enable_pri(pdev, 32);
if (ret)
- goto out_err;
+ goto out_err_pasid;
ret = pci_enable_ats(pdev, PAGE_SHIFT);
if (ret)
- goto out_err;
+ goto out_err_pri;
return 0;
-out_err:
+out_err_pri:
pci_disable_pri(pdev);
+
+out_err_pasid:
pci_disable_pasid(pdev);
return ret;
@@ -2072,6 +2093,10 @@ static struct protection_domain *protection_domain_alloc(unsigned int type)
if (ret)
goto out_err;
+ /* No need to allocate io pgtable ops in passthrough mode */
+ if (type == IOMMU_DOMAIN_IDENTITY)
+ return domain;
+
pgtbl_ops = alloc_io_pgtable_ops(pgtable, &domain->iop.pgtbl_cfg, domain);
if (!pgtbl_ops) {
domain_id_free(domain->id);
@@ -2126,31 +2151,6 @@ static void amd_iommu_domain_free(struct iommu_domain *dom)
protection_domain_free(domain);
}
-static void amd_iommu_detach_device(struct iommu_domain *dom,
- struct device *dev)
-{
- struct iommu_dev_data *dev_data = dev_iommu_priv_get(dev);
- struct amd_iommu *iommu;
-
- if (!check_device(dev))
- return;
-
- if (dev_data->domain != NULL)
- detach_device(dev);
-
- iommu = rlookup_amd_iommu(dev);
- if (!iommu)
- return;
-
-#ifdef CONFIG_IRQ_REMAP
- if (AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir) &&
- (dom->type == IOMMU_DOMAIN_UNMANAGED))
- dev_data->use_vapic = 0;
-#endif
-
- iommu_completion_wait(iommu);
-}
-
static int amd_iommu_attach_device(struct iommu_domain *dom,
struct device *dev)
{
@@ -2159,6 +2159,13 @@ static int amd_iommu_attach_device(struct iommu_domain *dom,
struct amd_iommu *iommu = rlookup_amd_iommu(dev);
int ret;
+ /*
+ * Skip attach device to domain if new domain is same as
+ * devices current domain
+ */
+ if (dev_data->domain == domain)
+ return 0;
+
dev_data->defer_attach = false;
if (dev_data->domain)
@@ -2271,8 +2278,6 @@ static bool amd_iommu_capable(struct device *dev, enum iommu_cap cap)
switch (cap) {
case IOMMU_CAP_CACHE_COHERENCY:
return true;
- case IOMMU_CAP_INTR_REMAP:
- return (irq_remapping_enabled == 1);
case IOMMU_CAP_NOEXEC:
return false;
case IOMMU_CAP_PRE_BOOT_PROTECTION:
@@ -2387,12 +2392,17 @@ static int amd_iommu_def_domain_type(struct device *dev)
return 0;
/*
- * Do not identity map IOMMUv2 capable devices when memory encryption is
- * active, because some of those devices (AMD GPUs) don't have the
- * encryption bit in their DMA-mask and require remapping.
+ * Do not identity map IOMMUv2 capable devices when:
+ * - memory encryption is active, because some of those devices
+ * (AMD GPUs) don't have the encryption bit in their DMA-mask
+ * and require remapping.
+ * - SNP is enabled, because it prohibits DTE[Mode]=0.
*/
- if (!cc_platform_has(CC_ATTR_MEM_ENCRYPT) && dev_data->iommu_v2)
+ if (dev_data->iommu_v2 &&
+ !cc_platform_has(CC_ATTR_MEM_ENCRYPT) &&
+ !amd_iommu_snp_en) {
return IOMMU_DOMAIN_IDENTITY;
+ }
return 0;
}
@@ -2416,7 +2426,6 @@ const struct iommu_ops amd_iommu_ops = {
.def_domain_type = amd_iommu_def_domain_type,
.default_domain_ops = &(const struct iommu_domain_ops) {
.attach_dev = amd_iommu_attach_device,
- .detach_dev = amd_iommu_detach_device,
.map_pages = amd_iommu_map_pages,
.unmap_pages = amd_iommu_unmap_pages,
.iotlb_sync_map = amd_iommu_iotlb_sync_map,
@@ -3671,7 +3680,8 @@ int amd_iommu_create_irq_domain(struct amd_iommu *iommu)
}
irq_domain_update_bus_token(iommu->ir_domain, DOMAIN_BUS_AMDVI);
- iommu->ir_domain->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT;
+ iommu->ir_domain->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT |
+ IRQ_DOMAIN_FLAG_ISOLATED_MSI;
if (amd_iommu_np_cache)
iommu->ir_domain->msi_parent_ops = &virt_amdvi_msi_parent_ops;
diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c
index 4f4a323be0d0..06169d36eab8 100644
--- a/drivers/iommu/apple-dart.c
+++ b/drivers/iommu/apple-dart.c
@@ -34,57 +34,154 @@
#include "dma-iommu.h"
-#define DART_MAX_STREAMS 16
+#define DART_MAX_STREAMS 256
#define DART_MAX_TTBR 4
#define MAX_DARTS_PER_DEVICE 2
-#define DART_STREAM_ALL 0xffff
+/* Common registers */
#define DART_PARAMS1 0x00
-#define DART_PARAMS_PAGE_SHIFT GENMASK(27, 24)
+#define DART_PARAMS1_PAGE_SHIFT GENMASK(27, 24)
#define DART_PARAMS2 0x04
-#define DART_PARAMS_BYPASS_SUPPORT BIT(0)
+#define DART_PARAMS2_BYPASS_SUPPORT BIT(0)
-#define DART_STREAM_COMMAND 0x20
-#define DART_STREAM_COMMAND_BUSY BIT(2)
-#define DART_STREAM_COMMAND_INVALIDATE BIT(20)
+/* T8020/T6000 registers */
-#define DART_STREAM_SELECT 0x34
+#define DART_T8020_STREAM_COMMAND 0x20
+#define DART_T8020_STREAM_COMMAND_BUSY BIT(2)
+#define DART_T8020_STREAM_COMMAND_INVALIDATE BIT(20)
-#define DART_ERROR 0x40
-#define DART_ERROR_STREAM GENMASK(27, 24)
-#define DART_ERROR_CODE GENMASK(11, 0)
-#define DART_ERROR_FLAG BIT(31)
+#define DART_T8020_STREAM_SELECT 0x34
-#define DART_ERROR_READ_FAULT BIT(4)
-#define DART_ERROR_WRITE_FAULT BIT(3)
-#define DART_ERROR_NO_PTE BIT(2)
-#define DART_ERROR_NO_PMD BIT(1)
-#define DART_ERROR_NO_TTBR BIT(0)
+#define DART_T8020_ERROR 0x40
+#define DART_T8020_ERROR_STREAM GENMASK(27, 24)
+#define DART_T8020_ERROR_CODE GENMASK(11, 0)
+#define DART_T8020_ERROR_FLAG BIT(31)
-#define DART_CONFIG 0x60
-#define DART_CONFIG_LOCK BIT(15)
+#define DART_T8020_ERROR_READ_FAULT BIT(4)
+#define DART_T8020_ERROR_WRITE_FAULT BIT(3)
+#define DART_T8020_ERROR_NO_PTE BIT(2)
+#define DART_T8020_ERROR_NO_PMD BIT(1)
+#define DART_T8020_ERROR_NO_TTBR BIT(0)
-#define DART_STREAM_COMMAND_BUSY_TIMEOUT 100
-
-#define DART_ERROR_ADDR_HI 0x54
-#define DART_ERROR_ADDR_LO 0x50
-
-#define DART_STREAMS_ENABLE 0xfc
+#define DART_T8020_CONFIG 0x60
+#define DART_T8020_CONFIG_LOCK BIT(15)
-#define DART_TCR(sid) (0x100 + 4 * (sid))
-#define DART_TCR_TRANSLATE_ENABLE BIT(7)
-#define DART_TCR_BYPASS0_ENABLE BIT(8)
-#define DART_TCR_BYPASS1_ENABLE BIT(12)
+#define DART_STREAM_COMMAND_BUSY_TIMEOUT 100
-#define DART_TTBR(sid, idx) (0x200 + 16 * (sid) + 4 * (idx))
-#define DART_TTBR_VALID BIT(31)
-#define DART_TTBR_SHIFT 12
+#define DART_T8020_ERROR_ADDR_HI 0x54
+#define DART_T8020_ERROR_ADDR_LO 0x50
+
+#define DART_T8020_STREAMS_ENABLE 0xfc
+
+#define DART_T8020_TCR 0x100
+#define DART_T8020_TCR_TRANSLATE_ENABLE BIT(7)
+#define DART_T8020_TCR_BYPASS_DART BIT(8)
+#define DART_T8020_TCR_BYPASS_DAPF BIT(12)
+
+#define DART_T8020_TTBR 0x200
+#define DART_T8020_TTBR_VALID BIT(31)
+#define DART_T8020_TTBR_ADDR_FIELD_SHIFT 0
+#define DART_T8020_TTBR_SHIFT 12
+
+/* T8110 registers */
+
+#define DART_T8110_PARAMS3 0x08
+#define DART_T8110_PARAMS3_PA_WIDTH GENMASK(29, 24)
+#define DART_T8110_PARAMS3_VA_WIDTH GENMASK(21, 16)
+#define DART_T8110_PARAMS3_VER_MAJ GENMASK(15, 8)
+#define DART_T8110_PARAMS3_VER_MIN GENMASK(7, 0)
+
+#define DART_T8110_PARAMS4 0x0c
+#define DART_T8110_PARAMS4_NUM_CLIENTS GENMASK(24, 16)
+#define DART_T8110_PARAMS4_NUM_SIDS GENMASK(8, 0)
+
+#define DART_T8110_TLB_CMD 0x80
+#define DART_T8110_TLB_CMD_BUSY BIT(31)
+#define DART_T8110_TLB_CMD_OP GENMASK(10, 8)
+#define DART_T8110_TLB_CMD_OP_FLUSH_ALL 0
+#define DART_T8110_TLB_CMD_OP_FLUSH_SID 1
+#define DART_T8110_TLB_CMD_STREAM GENMASK(7, 0)
+
+#define DART_T8110_ERROR 0x100
+#define DART_T8110_ERROR_STREAM GENMASK(27, 20)
+#define DART_T8110_ERROR_CODE GENMASK(14, 0)
+#define DART_T8110_ERROR_FLAG BIT(31)
+
+#define DART_T8110_ERROR_MASK 0x104
+
+#define DART_T8110_ERROR_READ_FAULT BIT(5)
+#define DART_T8110_ERROR_WRITE_FAULT BIT(4)
+#define DART_T8110_ERROR_NO_PTE BIT(3)
+#define DART_T8110_ERROR_NO_PMD BIT(2)
+#define DART_T8110_ERROR_NO_PGD BIT(1)
+#define DART_T8110_ERROR_NO_TTBR BIT(0)
+
+#define DART_T8110_ERROR_ADDR_LO 0x170
+#define DART_T8110_ERROR_ADDR_HI 0x174
+
+#define DART_T8110_PROTECT 0x200
+#define DART_T8110_UNPROTECT 0x204
+#define DART_T8110_PROTECT_LOCK 0x208
+#define DART_T8110_PROTECT_TTBR_TCR BIT(0)
+
+#define DART_T8110_ENABLE_STREAMS 0xc00
+#define DART_T8110_DISABLE_STREAMS 0xc20
+
+#define DART_T8110_TCR 0x1000
+#define DART_T8110_TCR_REMAP GENMASK(11, 8)
+#define DART_T8110_TCR_REMAP_EN BIT(7)
+#define DART_T8110_TCR_BYPASS_DAPF BIT(2)
+#define DART_T8110_TCR_BYPASS_DART BIT(1)
+#define DART_T8110_TCR_TRANSLATE_ENABLE BIT(0)
+
+#define DART_T8110_TTBR 0x1400
+#define DART_T8110_TTBR_VALID BIT(0)
+#define DART_T8110_TTBR_ADDR_FIELD_SHIFT 2
+#define DART_T8110_TTBR_SHIFT 14
+
+#define DART_TCR(dart, sid) ((dart)->hw->tcr + ((sid) << 2))
+
+#define DART_TTBR(dart, sid, idx) ((dart)->hw->ttbr + \
+ (((dart)->hw->ttbr_count * (sid)) << 2) + \
+ ((idx) << 2))
+
+struct apple_dart_stream_map;
+
+enum dart_type {
+ DART_T8020,
+ DART_T6000,
+ DART_T8110,
+};
struct apple_dart_hw {
+ enum dart_type type;
+ irqreturn_t (*irq_handler)(int irq, void *dev);
+ int (*invalidate_tlb)(struct apple_dart_stream_map *stream_map);
+
u32 oas;
enum io_pgtable_fmt fmt;
+
+ int max_sid_count;
+
+ u64 lock;
+ u64 lock_bit;
+
+ u64 error;
+
+ u64 enable_streams;
+
+ u64 tcr;
+ u64 tcr_enabled;
+ u64 tcr_disabled;
+ u64 tcr_bypass;
+
+ u64 ttbr;
+ u64 ttbr_valid;
+ u64 ttbr_addr_field_shift;
+ u64 ttbr_shift;
+ int ttbr_count;
};
/*
@@ -115,12 +212,18 @@ struct apple_dart {
spinlock_t lock;
+ u32 ias;
+ u32 oas;
u32 pgsize;
+ u32 num_streams;
u32 supports_bypass : 1;
u32 force_bypass : 1;
struct iommu_group *sid2group[DART_MAX_STREAMS];
struct iommu_device iommu;
+
+ u32 save_tcr[DART_MAX_STREAMS];
+ u32 save_ttbr[DART_MAX_STREAMS][DART_MAX_TTBR];
};
/*
@@ -140,11 +243,11 @@ struct apple_dart {
*/
struct apple_dart_stream_map {
struct apple_dart *dart;
- unsigned long sidmap;
+ DECLARE_BITMAP(sidmap, DART_MAX_STREAMS);
};
struct apple_dart_atomic_stream_map {
struct apple_dart *dart;
- atomic64_t sidmap;
+ atomic_long_t sidmap[BITS_TO_LONGS(DART_MAX_STREAMS)];
};
/*
@@ -202,50 +305,55 @@ static struct apple_dart_domain *to_dart_domain(struct iommu_domain *dom)
static void
apple_dart_hw_enable_translation(struct apple_dart_stream_map *stream_map)
{
+ struct apple_dart *dart = stream_map->dart;
int sid;
- for_each_set_bit(sid, &stream_map->sidmap, DART_MAX_STREAMS)
- writel(DART_TCR_TRANSLATE_ENABLE,
- stream_map->dart->regs + DART_TCR(sid));
+ for_each_set_bit(sid, stream_map->sidmap, dart->num_streams)
+ writel(dart->hw->tcr_enabled, dart->regs + DART_TCR(dart, sid));
}
static void apple_dart_hw_disable_dma(struct apple_dart_stream_map *stream_map)
{
+ struct apple_dart *dart = stream_map->dart;
int sid;
- for_each_set_bit(sid, &stream_map->sidmap, DART_MAX_STREAMS)
- writel(0, stream_map->dart->regs + DART_TCR(sid));
+ for_each_set_bit(sid, stream_map->sidmap, dart->num_streams)
+ writel(dart->hw->tcr_disabled, dart->regs + DART_TCR(dart, sid));
}
static void
apple_dart_hw_enable_bypass(struct apple_dart_stream_map *stream_map)
{
+ struct apple_dart *dart = stream_map->dart;
int sid;
WARN_ON(!stream_map->dart->supports_bypass);
- for_each_set_bit(sid, &stream_map->sidmap, DART_MAX_STREAMS)
- writel(DART_TCR_BYPASS0_ENABLE | DART_TCR_BYPASS1_ENABLE,
- stream_map->dart->regs + DART_TCR(sid));
+ for_each_set_bit(sid, stream_map->sidmap, dart->num_streams)
+ writel(dart->hw->tcr_bypass,
+ dart->regs + DART_TCR(dart, sid));
}
static void apple_dart_hw_set_ttbr(struct apple_dart_stream_map *stream_map,
u8 idx, phys_addr_t paddr)
{
+ struct apple_dart *dart = stream_map->dart;
int sid;
- WARN_ON(paddr & ((1 << DART_TTBR_SHIFT) - 1));
- for_each_set_bit(sid, &stream_map->sidmap, DART_MAX_STREAMS)
- writel(DART_TTBR_VALID | (paddr >> DART_TTBR_SHIFT),
- stream_map->dart->regs + DART_TTBR(sid, idx));
+ WARN_ON(paddr & ((1 << dart->hw->ttbr_shift) - 1));
+ for_each_set_bit(sid, stream_map->sidmap, dart->num_streams)
+ writel(dart->hw->ttbr_valid |
+ (paddr >> dart->hw->ttbr_shift) << dart->hw->ttbr_addr_field_shift,
+ dart->regs + DART_TTBR(dart, sid, idx));
}
static void apple_dart_hw_clear_ttbr(struct apple_dart_stream_map *stream_map,
u8 idx)
{
+ struct apple_dart *dart = stream_map->dart;
int sid;
- for_each_set_bit(sid, &stream_map->sidmap, DART_MAX_STREAMS)
- writel(0, stream_map->dart->regs + DART_TTBR(sid, idx));
+ for_each_set_bit(sid, stream_map->sidmap, dart->num_streams)
+ writel(0, dart->regs + DART_TTBR(dart, sid, idx));
}
static void
@@ -253,12 +361,12 @@ apple_dart_hw_clear_all_ttbrs(struct apple_dart_stream_map *stream_map)
{
int i;
- for (i = 0; i < DART_MAX_TTBR; ++i)
+ for (i = 0; i < stream_map->dart->hw->ttbr_count; ++i)
apple_dart_hw_clear_ttbr(stream_map, i);
}
static int
-apple_dart_hw_stream_command(struct apple_dart_stream_map *stream_map,
+apple_dart_t8020_hw_stream_command(struct apple_dart_stream_map *stream_map,
u32 command)
{
unsigned long flags;
@@ -267,12 +375,12 @@ apple_dart_hw_stream_command(struct apple_dart_stream_map *stream_map,
spin_lock_irqsave(&stream_map->dart->lock, flags);
- writel(stream_map->sidmap, stream_map->dart->regs + DART_STREAM_SELECT);
- writel(command, stream_map->dart->regs + DART_STREAM_COMMAND);
+ writel(stream_map->sidmap[0], stream_map->dart->regs + DART_T8020_STREAM_SELECT);
+ writel(command, stream_map->dart->regs + DART_T8020_STREAM_COMMAND);
ret = readl_poll_timeout_atomic(
- stream_map->dart->regs + DART_STREAM_COMMAND, command_reg,
- !(command_reg & DART_STREAM_COMMAND_BUSY), 1,
+ stream_map->dart->regs + DART_T8020_STREAM_COMMAND, command_reg,
+ !(command_reg & DART_T8020_STREAM_COMMAND_BUSY), 1,
DART_STREAM_COMMAND_BUSY_TIMEOUT);
spin_unlock_irqrestore(&stream_map->dart->lock, flags);
@@ -280,7 +388,45 @@ apple_dart_hw_stream_command(struct apple_dart_stream_map *stream_map,
if (ret) {
dev_err(stream_map->dart->dev,
"busy bit did not clear after command %x for streams %lx\n",
- command, stream_map->sidmap);
+ command, stream_map->sidmap[0]);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+apple_dart_t8110_hw_tlb_command(struct apple_dart_stream_map *stream_map,
+ u32 command)
+{
+ struct apple_dart *dart = stream_map->dart;
+ unsigned long flags;
+ int ret = 0;
+ int sid;
+
+ spin_lock_irqsave(&dart->lock, flags);
+
+ for_each_set_bit(sid, stream_map->sidmap, dart->num_streams) {
+ u32 val = FIELD_PREP(DART_T8110_TLB_CMD_OP, command) |
+ FIELD_PREP(DART_T8110_TLB_CMD_STREAM, sid);
+ writel(val, dart->regs + DART_T8110_TLB_CMD);
+
+ ret = readl_poll_timeout_atomic(
+ dart->regs + DART_T8110_TLB_CMD, val,
+ !(val & DART_T8110_TLB_CMD_BUSY), 1,
+ DART_STREAM_COMMAND_BUSY_TIMEOUT);
+
+ if (ret)
+ break;
+
+ }
+
+ spin_unlock_irqrestore(&dart->lock, flags);
+
+ if (ret) {
+ dev_err(stream_map->dart->dev,
+ "busy bit did not clear after command %x for stream %d\n",
+ command, sid);
return ret;
}
@@ -288,48 +434,64 @@ apple_dart_hw_stream_command(struct apple_dart_stream_map *stream_map,
}
static int
-apple_dart_hw_invalidate_tlb(struct apple_dart_stream_map *stream_map)
+apple_dart_t8020_hw_invalidate_tlb(struct apple_dart_stream_map *stream_map)
+{
+ return apple_dart_t8020_hw_stream_command(
+ stream_map, DART_T8020_STREAM_COMMAND_INVALIDATE);
+}
+
+static int
+apple_dart_t8110_hw_invalidate_tlb(struct apple_dart_stream_map *stream_map)
{
- return apple_dart_hw_stream_command(stream_map,
- DART_STREAM_COMMAND_INVALIDATE);
+ return apple_dart_t8110_hw_tlb_command(
+ stream_map, DART_T8110_TLB_CMD_OP_FLUSH_SID);
}
static int apple_dart_hw_reset(struct apple_dart *dart)
{
u32 config;
struct apple_dart_stream_map stream_map;
+ int i;
- config = readl(dart->regs + DART_CONFIG);
- if (config & DART_CONFIG_LOCK) {
+ config = readl(dart->regs + dart->hw->lock);
+ if (config & dart->hw->lock_bit) {
dev_err(dart->dev, "DART is locked down until reboot: %08x\n",
config);
return -EINVAL;
}
stream_map.dart = dart;
- stream_map.sidmap = DART_STREAM_ALL;
+ bitmap_zero(stream_map.sidmap, DART_MAX_STREAMS);
+ bitmap_set(stream_map.sidmap, 0, dart->num_streams);
apple_dart_hw_disable_dma(&stream_map);
apple_dart_hw_clear_all_ttbrs(&stream_map);
/* enable all streams globally since TCR is used to control isolation */
- writel(DART_STREAM_ALL, dart->regs + DART_STREAMS_ENABLE);
+ for (i = 0; i < BITS_TO_U32(dart->num_streams); i++)
+ writel(U32_MAX, dart->regs + dart->hw->enable_streams + 4 * i);
/* clear any pending errors before the interrupt is unmasked */
- writel(readl(dart->regs + DART_ERROR), dart->regs + DART_ERROR);
+ writel(readl(dart->regs + dart->hw->error), dart->regs + dart->hw->error);
+
+ if (dart->hw->type == DART_T8110)
+ writel(0, dart->regs + DART_T8110_ERROR_MASK);
- return apple_dart_hw_invalidate_tlb(&stream_map);
+ return dart->hw->invalidate_tlb(&stream_map);
}
static void apple_dart_domain_flush_tlb(struct apple_dart_domain *domain)
{
- int i;
+ int i, j;
struct apple_dart_atomic_stream_map *domain_stream_map;
struct apple_dart_stream_map stream_map;
for_each_stream_map(i, domain, domain_stream_map) {
stream_map.dart = domain_stream_map->dart;
- stream_map.sidmap = atomic64_read(&domain_stream_map->sidmap);
- apple_dart_hw_invalidate_tlb(&stream_map);
+
+ for (j = 0; j < BITS_TO_LONGS(stream_map.dart->num_streams); j++)
+ stream_map.sidmap[j] = atomic_long_read(&domain_stream_map->sidmap[j]);
+
+ stream_map.dart->hw->invalidate_tlb(&stream_map);
}
}
@@ -399,11 +561,11 @@ apple_dart_setup_translation(struct apple_dart_domain *domain,
for (i = 0; i < pgtbl_cfg->apple_dart_cfg.n_ttbrs; ++i)
apple_dart_hw_set_ttbr(stream_map, i,
pgtbl_cfg->apple_dart_cfg.ttbr[i]);
- for (; i < DART_MAX_TTBR; ++i)
+ for (; i < stream_map->dart->hw->ttbr_count; ++i)
apple_dart_hw_clear_ttbr(stream_map, i);
apple_dart_hw_enable_translation(stream_map);
- apple_dart_hw_invalidate_tlb(stream_map);
+ stream_map->dart->hw->invalidate_tlb(stream_map);
}
static int apple_dart_finalize_domain(struct iommu_domain *domain,
@@ -413,7 +575,7 @@ static int apple_dart_finalize_domain(struct iommu_domain *domain,
struct apple_dart *dart = cfg->stream_maps[0].dart;
struct io_pgtable_cfg pgtbl_cfg;
int ret = 0;
- int i;
+ int i, j;
mutex_lock(&dart_domain->init_lock);
@@ -422,14 +584,15 @@ static int apple_dart_finalize_domain(struct iommu_domain *domain,
for (i = 0; i < MAX_DARTS_PER_DEVICE; ++i) {
dart_domain->stream_maps[i].dart = cfg->stream_maps[i].dart;
- atomic64_set(&dart_domain->stream_maps[i].sidmap,
- cfg->stream_maps[i].sidmap);
+ for (j = 0; j < BITS_TO_LONGS(dart->num_streams); j++)
+ atomic_long_set(&dart_domain->stream_maps[i].sidmap[j],
+ cfg->stream_maps[i].sidmap[j]);
}
pgtbl_cfg = (struct io_pgtable_cfg){
.pgsize_bitmap = dart->pgsize,
- .ias = 32,
- .oas = dart->hw->oas,
+ .ias = dart->ias,
+ .oas = dart->oas,
.coherent_walk = 1,
.iommu_dev = dart->dev,
};
@@ -443,7 +606,7 @@ static int apple_dart_finalize_domain(struct iommu_domain *domain,
domain->pgsize_bitmap = pgtbl_cfg.pgsize_bitmap;
domain->geometry.aperture_start = 0;
- domain->geometry.aperture_end = DMA_BIT_MASK(32);
+ domain->geometry.aperture_end = (dma_addr_t)DMA_BIT_MASK(dart->ias);
domain->geometry.force_aperture = true;
dart_domain->finalized = true;
@@ -458,7 +621,7 @@ apple_dart_mod_streams(struct apple_dart_atomic_stream_map *domain_maps,
struct apple_dart_stream_map *master_maps,
bool add_streams)
{
- int i;
+ int i, j;
for (i = 0; i < MAX_DARTS_PER_DEVICE; ++i) {
if (domain_maps[i].dart != master_maps[i].dart)
@@ -468,12 +631,14 @@ apple_dart_mod_streams(struct apple_dart_atomic_stream_map *domain_maps,
for (i = 0; i < MAX_DARTS_PER_DEVICE; ++i) {
if (!domain_maps[i].dart)
break;
- if (add_streams)
- atomic64_or(master_maps[i].sidmap,
- &domain_maps[i].sidmap);
- else
- atomic64_and(~master_maps[i].sidmap,
- &domain_maps[i].sidmap);
+ for (j = 0; j < BITS_TO_LONGS(domain_maps[i].dart->num_streams); j++) {
+ if (add_streams)
+ atomic_long_or(master_maps[i].sidmap[j],
+ &domain_maps[i].sidmap[j]);
+ else
+ atomic_long_and(~master_maps[i].sidmap[j],
+ &domain_maps[i].sidmap[j]);
+ }
}
return 0;
@@ -486,13 +651,6 @@ static int apple_dart_domain_add_streams(struct apple_dart_domain *domain,
true);
}
-static int apple_dart_domain_remove_streams(struct apple_dart_domain *domain,
- struct apple_dart_master_cfg *cfg)
-{
- return apple_dart_mod_streams(domain->stream_maps, cfg->stream_maps,
- false);
-}
-
static int apple_dart_attach_dev(struct iommu_domain *domain,
struct device *dev)
{
@@ -535,22 +693,6 @@ static int apple_dart_attach_dev(struct iommu_domain *domain,
return ret;
}
-static void apple_dart_detach_dev(struct iommu_domain *domain,
- struct device *dev)
-{
- int i;
- struct apple_dart_stream_map *stream_map;
- struct apple_dart_master_cfg *cfg = dev_iommu_priv_get(dev);
- struct apple_dart_domain *dart_domain = to_dart_domain(domain);
-
- for_each_stream_map(i, cfg, stream_map)
- apple_dart_hw_disable_dma(stream_map);
-
- if (domain->type == IOMMU_DOMAIN_DMA ||
- domain->type == IOMMU_DOMAIN_UNMANAGED)
- apple_dart_domain_remove_streams(dart_domain, cfg);
-}
-
static struct iommu_device *apple_dart_probe_device(struct device *dev)
{
struct apple_dart_master_cfg *cfg = dev_iommu_priv_get(dev);
@@ -637,14 +779,14 @@ static int apple_dart_of_xlate(struct device *dev, struct of_phandle_args *args)
for (i = 0; i < MAX_DARTS_PER_DEVICE; ++i) {
if (cfg->stream_maps[i].dart == dart) {
- cfg->stream_maps[i].sidmap |= 1 << sid;
+ set_bit(sid, cfg->stream_maps[i].sidmap);
return 0;
}
}
for (i = 0; i < MAX_DARTS_PER_DEVICE; ++i) {
if (!cfg->stream_maps[i].dart) {
cfg->stream_maps[i].dart = dart;
- cfg->stream_maps[i].sidmap = 1 << sid;
+ set_bit(sid, cfg->stream_maps[i].sidmap);
return 0;
}
}
@@ -663,13 +805,36 @@ static void apple_dart_release_group(void *iommu_data)
mutex_lock(&apple_dart_groups_lock);
for_each_stream_map(i, group_master_cfg, stream_map)
- for_each_set_bit(sid, &stream_map->sidmap, DART_MAX_STREAMS)
+ for_each_set_bit(sid, stream_map->sidmap, stream_map->dart->num_streams)
stream_map->dart->sid2group[sid] = NULL;
kfree(iommu_data);
mutex_unlock(&apple_dart_groups_lock);
}
+static int apple_dart_merge_master_cfg(struct apple_dart_master_cfg *dst,
+ struct apple_dart_master_cfg *src)
+{
+ /*
+ * We know that this function is only called for groups returned from
+ * pci_device_group and that all Apple Silicon platforms never spread
+ * PCIe devices from the same bus across multiple DARTs such that we can
+ * just assume that both src and dst only have the same single DART.
+ */
+ if (src->stream_maps[1].dart)
+ return -EINVAL;
+ if (dst->stream_maps[1].dart)
+ return -EINVAL;
+ if (src->stream_maps[0].dart != dst->stream_maps[0].dart)
+ return -EINVAL;
+
+ bitmap_or(dst->stream_maps[0].sidmap,
+ dst->stream_maps[0].sidmap,
+ src->stream_maps[0].sidmap,
+ dst->stream_maps[0].dart->num_streams);
+ return 0;
+}
+
static struct iommu_group *apple_dart_device_group(struct device *dev)
{
int i, sid;
@@ -682,7 +847,7 @@ static struct iommu_group *apple_dart_device_group(struct device *dev)
mutex_lock(&apple_dart_groups_lock);
for_each_stream_map(i, cfg, stream_map) {
- for_each_set_bit(sid, &stream_map->sidmap, DART_MAX_STREAMS) {
+ for_each_set_bit(sid, stream_map->sidmap, stream_map->dart->num_streams) {
struct iommu_group *stream_group =
stream_map->dart->sid2group[sid];
@@ -711,17 +876,31 @@ static struct iommu_group *apple_dart_device_group(struct device *dev)
if (!group)
goto out;
- group_master_cfg = kmemdup(cfg, sizeof(*group_master_cfg), GFP_KERNEL);
- if (!group_master_cfg) {
- iommu_group_put(group);
- goto out;
- }
+ group_master_cfg = iommu_group_get_iommudata(group);
+ if (group_master_cfg) {
+ int ret;
+
+ ret = apple_dart_merge_master_cfg(group_master_cfg, cfg);
+ if (ret) {
+ dev_err(dev, "Failed to merge DART IOMMU grups.\n");
+ iommu_group_put(group);
+ res = ERR_PTR(ret);
+ goto out;
+ }
+ } else {
+ group_master_cfg = kmemdup(cfg, sizeof(*group_master_cfg),
+ GFP_KERNEL);
+ if (!group_master_cfg) {
+ iommu_group_put(group);
+ goto out;
+ }
- iommu_group_set_iommudata(group, group_master_cfg,
- apple_dart_release_group);
+ iommu_group_set_iommudata(group, group_master_cfg,
+ apple_dart_release_group);
+ }
for_each_stream_map(i, cfg, stream_map)
- for_each_set_bit(sid, &stream_map->sidmap, DART_MAX_STREAMS)
+ for_each_set_bit(sid, stream_map->sidmap, stream_map->dart->num_streams)
stream_map->dart->sid2group[sid] = group;
res = group;
@@ -780,7 +959,6 @@ static const struct iommu_ops apple_dart_iommu_ops = {
.owner = THIS_MODULE,
.default_domain_ops = &(const struct iommu_domain_ops) {
.attach_dev = apple_dart_attach_dev,
- .detach_dev = apple_dart_detach_dev,
.map_pages = apple_dart_map_pages,
.unmap_pages = apple_dart_unmap_pages,
.flush_iotlb_all = apple_dart_flush_iotlb_all,
@@ -791,30 +969,69 @@ static const struct iommu_ops apple_dart_iommu_ops = {
}
};
-static irqreturn_t apple_dart_irq(int irq, void *dev)
+static irqreturn_t apple_dart_t8020_irq(int irq, void *dev)
+{
+ struct apple_dart *dart = dev;
+ const char *fault_name = NULL;
+ u32 error = readl(dart->regs + DART_T8020_ERROR);
+ u32 error_code = FIELD_GET(DART_T8020_ERROR_CODE, error);
+ u32 addr_lo = readl(dart->regs + DART_T8020_ERROR_ADDR_LO);
+ u32 addr_hi = readl(dart->regs + DART_T8020_ERROR_ADDR_HI);
+ u64 addr = addr_lo | (((u64)addr_hi) << 32);
+ u8 stream_idx = FIELD_GET(DART_T8020_ERROR_STREAM, error);
+
+ if (!(error & DART_T8020_ERROR_FLAG))
+ return IRQ_NONE;
+
+ /* there should only be a single bit set but let's use == to be sure */
+ if (error_code == DART_T8020_ERROR_READ_FAULT)
+ fault_name = "READ FAULT";
+ else if (error_code == DART_T8020_ERROR_WRITE_FAULT)
+ fault_name = "WRITE FAULT";
+ else if (error_code == DART_T8020_ERROR_NO_PTE)
+ fault_name = "NO PTE FOR IOVA";
+ else if (error_code == DART_T8020_ERROR_NO_PMD)
+ fault_name = "NO PMD FOR IOVA";
+ else if (error_code == DART_T8020_ERROR_NO_TTBR)
+ fault_name = "NO TTBR FOR IOVA";
+ else
+ fault_name = "unknown";
+
+ dev_err_ratelimited(
+ dart->dev,
+ "translation fault: status:0x%x stream:%d code:0x%x (%s) at 0x%llx",
+ error, stream_idx, error_code, fault_name, addr);
+
+ writel(error, dart->regs + DART_T8020_ERROR);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t apple_dart_t8110_irq(int irq, void *dev)
{
struct apple_dart *dart = dev;
const char *fault_name = NULL;
- u32 error = readl(dart->regs + DART_ERROR);
- u32 error_code = FIELD_GET(DART_ERROR_CODE, error);
- u32 addr_lo = readl(dart->regs + DART_ERROR_ADDR_LO);
- u32 addr_hi = readl(dart->regs + DART_ERROR_ADDR_HI);
+ u32 error = readl(dart->regs + DART_T8110_ERROR);
+ u32 error_code = FIELD_GET(DART_T8110_ERROR_CODE, error);
+ u32 addr_lo = readl(dart->regs + DART_T8110_ERROR_ADDR_LO);
+ u32 addr_hi = readl(dart->regs + DART_T8110_ERROR_ADDR_HI);
u64 addr = addr_lo | (((u64)addr_hi) << 32);
- u8 stream_idx = FIELD_GET(DART_ERROR_STREAM, error);
+ u8 stream_idx = FIELD_GET(DART_T8110_ERROR_STREAM, error);
- if (!(error & DART_ERROR_FLAG))
+ if (!(error & DART_T8110_ERROR_FLAG))
return IRQ_NONE;
/* there should only be a single bit set but let's use == to be sure */
- if (error_code == DART_ERROR_READ_FAULT)
+ if (error_code == DART_T8110_ERROR_READ_FAULT)
fault_name = "READ FAULT";
- else if (error_code == DART_ERROR_WRITE_FAULT)
+ else if (error_code == DART_T8110_ERROR_WRITE_FAULT)
fault_name = "WRITE FAULT";
- else if (error_code == DART_ERROR_NO_PTE)
+ else if (error_code == DART_T8110_ERROR_NO_PTE)
fault_name = "NO PTE FOR IOVA";
- else if (error_code == DART_ERROR_NO_PMD)
+ else if (error_code == DART_T8110_ERROR_NO_PMD)
fault_name = "NO PMD FOR IOVA";
- else if (error_code == DART_ERROR_NO_TTBR)
+ else if (error_code == DART_T8110_ERROR_NO_PGD)
+ fault_name = "NO PGD FOR IOVA";
+ else if (error_code == DART_T8110_ERROR_NO_TTBR)
fault_name = "NO TTBR FOR IOVA";
else
fault_name = "unknown";
@@ -824,14 +1041,14 @@ static irqreturn_t apple_dart_irq(int irq, void *dev)
"translation fault: status:0x%x stream:%d code:0x%x (%s) at 0x%llx",
error, stream_idx, error_code, fault_name, addr);
- writel(error, dart->regs + DART_ERROR);
+ writel(error, dart->regs + DART_T8110_ERROR);
return IRQ_HANDLED;
}
static int apple_dart_probe(struct platform_device *pdev)
{
int ret;
- u32 dart_params[2];
+ u32 dart_params[4];
struct resource *res;
struct apple_dart *dart;
struct device *dev = &pdev->dev;
@@ -866,17 +1083,42 @@ static int apple_dart_probe(struct platform_device *pdev)
if (ret)
return ret;
- ret = apple_dart_hw_reset(dart);
- if (ret)
- goto err_clk_disable;
-
dart_params[0] = readl(dart->regs + DART_PARAMS1);
dart_params[1] = readl(dart->regs + DART_PARAMS2);
- dart->pgsize = 1 << FIELD_GET(DART_PARAMS_PAGE_SHIFT, dart_params[0]);
- dart->supports_bypass = dart_params[1] & DART_PARAMS_BYPASS_SUPPORT;
+ dart->pgsize = 1 << FIELD_GET(DART_PARAMS1_PAGE_SHIFT, dart_params[0]);
+ dart->supports_bypass = dart_params[1] & DART_PARAMS2_BYPASS_SUPPORT;
+
+ switch (dart->hw->type) {
+ case DART_T8020:
+ case DART_T6000:
+ dart->ias = 32;
+ dart->oas = dart->hw->oas;
+ dart->num_streams = dart->hw->max_sid_count;
+ break;
+
+ case DART_T8110:
+ dart_params[2] = readl(dart->regs + DART_T8110_PARAMS3);
+ dart_params[3] = readl(dart->regs + DART_T8110_PARAMS4);
+ dart->ias = FIELD_GET(DART_T8110_PARAMS3_VA_WIDTH, dart_params[2]);
+ dart->oas = FIELD_GET(DART_T8110_PARAMS3_PA_WIDTH, dart_params[2]);
+ dart->num_streams = FIELD_GET(DART_T8110_PARAMS4_NUM_SIDS, dart_params[3]);
+ break;
+ }
+
+ if (dart->num_streams > DART_MAX_STREAMS) {
+ dev_err(&pdev->dev, "Too many streams (%d > %d)\n",
+ dart->num_streams, DART_MAX_STREAMS);
+ ret = -EINVAL;
+ goto err_clk_disable;
+ }
+
dart->force_bypass = dart->pgsize > PAGE_SIZE;
- ret = request_irq(dart->irq, apple_dart_irq, IRQF_SHARED,
+ ret = apple_dart_hw_reset(dart);
+ if (ret)
+ goto err_clk_disable;
+
+ ret = request_irq(dart->irq, dart->hw->irq_handler, IRQF_SHARED,
"apple-dart fault handler", dart);
if (ret)
goto err_clk_disable;
@@ -894,8 +1136,8 @@ static int apple_dart_probe(struct platform_device *pdev)
dev_info(
&pdev->dev,
- "DART [pagesize %x, bypass support: %d, bypass forced: %d] initialized\n",
- dart->pgsize, dart->supports_bypass, dart->force_bypass);
+ "DART [pagesize %x, %d streams, bypass support: %d, bypass forced: %d] initialized\n",
+ dart->pgsize, dart->num_streams, dart->supports_bypass, dart->force_bypass);
return 0;
err_sysfs_remove:
@@ -924,16 +1166,123 @@ static int apple_dart_remove(struct platform_device *pdev)
}
static const struct apple_dart_hw apple_dart_hw_t8103 = {
+ .type = DART_T8020,
+ .irq_handler = apple_dart_t8020_irq,
+ .invalidate_tlb = apple_dart_t8020_hw_invalidate_tlb,
.oas = 36,
.fmt = APPLE_DART,
+ .max_sid_count = 16,
+
+ .enable_streams = DART_T8020_STREAMS_ENABLE,
+ .lock = DART_T8020_CONFIG,
+ .lock_bit = DART_T8020_CONFIG_LOCK,
+
+ .error = DART_T8020_ERROR,
+
+ .tcr = DART_T8020_TCR,
+ .tcr_enabled = DART_T8020_TCR_TRANSLATE_ENABLE,
+ .tcr_disabled = 0,
+ .tcr_bypass = DART_T8020_TCR_BYPASS_DAPF | DART_T8020_TCR_BYPASS_DART,
+
+ .ttbr = DART_T8020_TTBR,
+ .ttbr_valid = DART_T8020_TTBR_VALID,
+ .ttbr_addr_field_shift = DART_T8020_TTBR_ADDR_FIELD_SHIFT,
+ .ttbr_shift = DART_T8020_TTBR_SHIFT,
+ .ttbr_count = 4,
};
static const struct apple_dart_hw apple_dart_hw_t6000 = {
+ .type = DART_T6000,
+ .irq_handler = apple_dart_t8020_irq,
+ .invalidate_tlb = apple_dart_t8020_hw_invalidate_tlb,
.oas = 42,
.fmt = APPLE_DART2,
+ .max_sid_count = 16,
+
+ .enable_streams = DART_T8020_STREAMS_ENABLE,
+ .lock = DART_T8020_CONFIG,
+ .lock_bit = DART_T8020_CONFIG_LOCK,
+
+ .error = DART_T8020_ERROR,
+
+ .tcr = DART_T8020_TCR,
+ .tcr_enabled = DART_T8020_TCR_TRANSLATE_ENABLE,
+ .tcr_disabled = 0,
+ .tcr_bypass = DART_T8020_TCR_BYPASS_DAPF | DART_T8020_TCR_BYPASS_DART,
+
+ .ttbr = DART_T8020_TTBR,
+ .ttbr_valid = DART_T8020_TTBR_VALID,
+ .ttbr_addr_field_shift = DART_T8020_TTBR_ADDR_FIELD_SHIFT,
+ .ttbr_shift = DART_T8020_TTBR_SHIFT,
+ .ttbr_count = 4,
};
+static const struct apple_dart_hw apple_dart_hw_t8110 = {
+ .type = DART_T8110,
+ .irq_handler = apple_dart_t8110_irq,
+ .invalidate_tlb = apple_dart_t8110_hw_invalidate_tlb,
+ .fmt = APPLE_DART2,
+ .max_sid_count = 256,
+
+ .enable_streams = DART_T8110_ENABLE_STREAMS,
+ .lock = DART_T8110_PROTECT,
+ .lock_bit = DART_T8110_PROTECT_TTBR_TCR,
+
+ .error = DART_T8110_ERROR,
+
+ .tcr = DART_T8110_TCR,
+ .tcr_enabled = DART_T8110_TCR_TRANSLATE_ENABLE,
+ .tcr_disabled = 0,
+ .tcr_bypass = DART_T8110_TCR_BYPASS_DAPF | DART_T8110_TCR_BYPASS_DART,
+
+ .ttbr = DART_T8110_TTBR,
+ .ttbr_valid = DART_T8110_TTBR_VALID,
+ .ttbr_addr_field_shift = DART_T8110_TTBR_ADDR_FIELD_SHIFT,
+ .ttbr_shift = DART_T8110_TTBR_SHIFT,
+ .ttbr_count = 1,
+};
+
+static __maybe_unused int apple_dart_suspend(struct device *dev)
+{
+ struct apple_dart *dart = dev_get_drvdata(dev);
+ unsigned int sid, idx;
+
+ for (sid = 0; sid < dart->num_streams; sid++) {
+ dart->save_tcr[sid] = readl_relaxed(dart->regs + DART_TCR(dart, sid));
+ for (idx = 0; idx < dart->hw->ttbr_count; idx++)
+ dart->save_ttbr[sid][idx] =
+ readl(dart->regs + DART_TTBR(dart, sid, idx));
+ }
+
+ return 0;
+}
+
+static __maybe_unused int apple_dart_resume(struct device *dev)
+{
+ struct apple_dart *dart = dev_get_drvdata(dev);
+ unsigned int sid, idx;
+ int ret;
+
+ ret = apple_dart_hw_reset(dart);
+ if (ret) {
+ dev_err(dev, "Failed to reset DART on resume\n");
+ return ret;
+ }
+
+ for (sid = 0; sid < dart->num_streams; sid++) {
+ for (idx = 0; idx < dart->hw->ttbr_count; idx++)
+ writel(dart->save_ttbr[sid][idx],
+ dart->regs + DART_TTBR(dart, sid, idx));
+ writel(dart->save_tcr[sid], dart->regs + DART_TCR(dart, sid));
+ }
+
+ return 0;
+}
+
+DEFINE_SIMPLE_DEV_PM_OPS(apple_dart_pm_ops, apple_dart_suspend, apple_dart_resume);
+
static const struct of_device_id apple_dart_of_match[] = {
{ .compatible = "apple,t8103-dart", .data = &apple_dart_hw_t8103 },
+ { .compatible = "apple,t8110-dart", .data = &apple_dart_hw_t8110 },
{ .compatible = "apple,t6000-dart", .data = &apple_dart_hw_t6000 },
{},
};
@@ -944,6 +1293,7 @@ static struct platform_driver apple_dart_driver = {
.name = "apple-dart",
.of_match_table = apple_dart_of_match,
.suppress_bind_attrs = true,
+ .pm = pm_sleep_ptr(&apple_dart_pm_ops),
},
.probe = apple_dart_probe,
.remove = apple_dart_remove,
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom-debug.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom-debug.c
index 74e9ef2fd580..b5b14108e086 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom-debug.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom-debug.c
@@ -4,7 +4,7 @@
*/
#include <linux/of_device.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/ratelimit.h>
#include "arm-smmu.h"
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
index 91d404deb115..d1b296b95c86 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
@@ -7,7 +7,7 @@
#include <linux/adreno-smmu-priv.h>
#include <linux/delay.h>
#include <linux/of_device.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include "arm-smmu.h"
#include "arm-smmu-qcom.h"
@@ -250,6 +250,8 @@ static const struct of_device_id qcom_smmu_client_of_match[] __maybe_unused = {
{ .compatible = "qcom,sc7280-mdss" },
{ .compatible = "qcom,sc7280-mss-pil" },
{ .compatible = "qcom,sc8180x-mdss" },
+ { .compatible = "qcom,sc8280xp-mdss" },
+ { .compatible = "qcom,sm8150-mdss" },
{ .compatible = "qcom,sm8250-mdss" },
{ .compatible = "qcom,sdm845-mdss" },
{ .compatible = "qcom,sdm845-mss-pil" },
diff --git a/drivers/iommu/arm/arm-smmu/qcom_iommu.c b/drivers/iommu/arm/arm-smmu/qcom_iommu.c
index 270c3d9128ba..c8b70f476cd8 100644
--- a/drivers/iommu/arm/arm-smmu/qcom_iommu.c
+++ b/drivers/iommu/arm/arm-smmu/qcom_iommu.c
@@ -27,7 +27,7 @@
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
@@ -387,28 +387,6 @@ static int qcom_iommu_attach_dev(struct iommu_domain *domain, struct device *dev
return 0;
}
-static void qcom_iommu_detach_dev(struct iommu_domain *domain, struct device *dev)
-{
- struct qcom_iommu_domain *qcom_domain = to_qcom_iommu_domain(domain);
- struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
- struct qcom_iommu_dev *qcom_iommu = to_iommu(dev);
- unsigned i;
-
- if (WARN_ON(!qcom_domain->iommu))
- return;
-
- pm_runtime_get_sync(qcom_iommu->dev);
- for (i = 0; i < fwspec->num_ids; i++) {
- struct qcom_iommu_ctx *ctx = to_ctx(qcom_domain, fwspec->ids[i]);
-
- /* Disable the context bank: */
- iommu_writel(ctx, ARM_SMMU_CB_SCTLR, 0);
-
- ctx->domain = NULL;
- }
- pm_runtime_put_sync(qcom_iommu->dev);
-}
-
static int qcom_iommu_map(struct iommu_domain *domain, unsigned long iova,
phys_addr_t paddr, size_t pgsize, size_t pgcount,
int prot, gfp_t gfp, size_t *mapped)
@@ -583,7 +561,6 @@ static const struct iommu_ops qcom_iommu_ops = {
.pgsize_bitmap = SZ_4K | SZ_64K | SZ_1M | SZ_16M,
.default_domain_ops = &(const struct iommu_domain_ops) {
.attach_dev = qcom_iommu_attach_dev,
- .detach_dev = qcom_iommu_detach_dev,
.map_pages = qcom_iommu_map,
.unmap_pages = qcom_iommu_unmap,
.flush_iotlb_all = qcom_iommu_flush_iotlb_all,
diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index f798c44e0903..99b2646cb5c7 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -23,6 +23,7 @@
#include <linux/memremap.h>
#include <linux/mm.h>
#include <linux/mutex.h>
+#include <linux/of_iommu.h>
#include <linux/pci.h>
#include <linux/scatterlist.h>
#include <linux/spinlock.h>
@@ -391,6 +392,8 @@ void iommu_dma_get_resv_regions(struct device *dev, struct list_head *list)
if (!is_of_node(dev_iommu_fwspec_get(dev)->iommu_fwnode))
iort_iommu_get_resv_regions(dev, list);
+ if (dev->of_node)
+ of_iommu_get_resv_regions(dev, list);
}
EXPORT_SYMBOL(iommu_dma_get_resv_regions);
@@ -713,7 +716,7 @@ static dma_addr_t __iommu_dma_map(struct device *dev, phys_addr_t phys,
if (!iova)
return DMA_MAPPING_ERROR;
- if (iommu_map_atomic(domain, iova, phys - iova_off, size, prot)) {
+ if (iommu_map(domain, iova, phys - iova_off, size, prot, GFP_ATOMIC)) {
iommu_dma_free_iova(cookie, iova, size, NULL);
return DMA_MAPPING_ERROR;
}
@@ -822,7 +825,14 @@ static struct page **__iommu_dma_alloc_noncontiguous(struct device *dev,
if (!iova)
goto out_free_pages;
- if (sg_alloc_table_from_pages(sgt, pages, count, 0, size, GFP_KERNEL))
+ /*
+ * Remove the zone/policy flags from the GFP - these are applied to the
+ * __iommu_dma_alloc_pages() but are not used for the supporting
+ * internal allocations that follow.
+ */
+ gfp &= ~(__GFP_DMA | __GFP_DMA32 | __GFP_HIGHMEM | __GFP_COMP);
+
+ if (sg_alloc_table_from_pages(sgt, pages, count, 0, size, gfp))
goto out_free_iova;
if (!(ioprot & IOMMU_CACHE)) {
@@ -833,7 +843,8 @@ static struct page **__iommu_dma_alloc_noncontiguous(struct device *dev,
arch_dma_prep_coherent(sg_page(sg), sg->length);
}
- ret = iommu_map_sg_atomic(domain, iova, sgt->sgl, sgt->orig_nents, ioprot);
+ ret = iommu_map_sg(domain, iova, sgt->sgl, sgt->orig_nents, ioprot,
+ gfp);
if (ret < 0 || ret < size)
goto out_free_sg;
@@ -1281,7 +1292,7 @@ static int iommu_dma_map_sg(struct device *dev, struct scatterlist *sg,
* We'll leave any physical concatenation to the IOMMU driver's
* implementation - it knows better than we do.
*/
- ret = iommu_map_sg_atomic(domain, iova, sg, nents, prot);
+ ret = iommu_map_sg(domain, iova, sg, nents, prot, GFP_ATOMIC);
if (ret < 0 || ret < iova_len)
goto out_free_iova;
@@ -1615,7 +1626,7 @@ static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev,
if (!iova)
goto out_free_page;
- if (iommu_map(domain, iova, msi_addr, size, prot))
+ if (iommu_map(domain, iova, msi_addr, size, prot, GFP_KERNEL))
goto out_free_iova;
INIT_LIST_HEAD(&msi_page->list);
diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index b0cde2211987..483aaaeb6dae 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -185,38 +185,43 @@ static sysmmu_pte_t *page_entry(sysmmu_pte_t *sent, sysmmu_iova_t iova)
lv2table_base(sent)) + lv2ent_offset(iova);
}
-/*
- * IOMMU fault information register
- */
-struct sysmmu_fault_info {
- unsigned int bit; /* bit number in STATUS register */
- unsigned short addr_reg; /* register to read VA fault address */
+struct sysmmu_fault {
+ sysmmu_iova_t addr; /* IOVA address that caused fault */
+ const char *name; /* human readable fault name */
+ unsigned int type; /* fault type for report_iommu_fault() */
+};
+
+struct sysmmu_v1_fault_info {
+ unsigned short addr_reg; /* register to read IOVA fault address */
const char *name; /* human readable fault name */
unsigned int type; /* fault type for report_iommu_fault */
};
-static const struct sysmmu_fault_info sysmmu_faults[] = {
- { 0, REG_PAGE_FAULT_ADDR, "PAGE", IOMMU_FAULT_READ },
- { 1, REG_AR_FAULT_ADDR, "AR MULTI-HIT", IOMMU_FAULT_READ },
- { 2, REG_AW_FAULT_ADDR, "AW MULTI-HIT", IOMMU_FAULT_WRITE },
- { 3, REG_DEFAULT_SLAVE_ADDR, "BUS ERROR", IOMMU_FAULT_READ },
- { 4, REG_AR_FAULT_ADDR, "AR SECURITY PROTECTION", IOMMU_FAULT_READ },
- { 5, REG_AR_FAULT_ADDR, "AR ACCESS PROTECTION", IOMMU_FAULT_READ },
- { 6, REG_AW_FAULT_ADDR, "AW SECURITY PROTECTION", IOMMU_FAULT_WRITE },
- { 7, REG_AW_FAULT_ADDR, "AW ACCESS PROTECTION", IOMMU_FAULT_WRITE },
+static const struct sysmmu_v1_fault_info sysmmu_v1_faults[] = {
+ { REG_PAGE_FAULT_ADDR, "PAGE", IOMMU_FAULT_READ },
+ { REG_AR_FAULT_ADDR, "MULTI-HIT", IOMMU_FAULT_READ },
+ { REG_AW_FAULT_ADDR, "MULTI-HIT", IOMMU_FAULT_WRITE },
+ { REG_DEFAULT_SLAVE_ADDR, "BUS ERROR", IOMMU_FAULT_READ },
+ { REG_AR_FAULT_ADDR, "SECURITY PROTECTION", IOMMU_FAULT_READ },
+ { REG_AR_FAULT_ADDR, "ACCESS PROTECTION", IOMMU_FAULT_READ },
+ { REG_AW_FAULT_ADDR, "SECURITY PROTECTION", IOMMU_FAULT_WRITE },
+ { REG_AW_FAULT_ADDR, "ACCESS PROTECTION", IOMMU_FAULT_WRITE },
+};
+
+/* SysMMU v5 has the same faults for AR (0..4 bits) and AW (16..20 bits) */
+static const char * const sysmmu_v5_fault_names[] = {
+ "PTW",
+ "PAGE",
+ "MULTI-HIT",
+ "ACCESS PROTECTION",
+ "SECURITY PROTECTION"
};
-static const struct sysmmu_fault_info sysmmu_v5_faults[] = {
- { 0, REG_V5_FAULT_AR_VA, "AR PTW", IOMMU_FAULT_READ },
- { 1, REG_V5_FAULT_AR_VA, "AR PAGE", IOMMU_FAULT_READ },
- { 2, REG_V5_FAULT_AR_VA, "AR MULTI-HIT", IOMMU_FAULT_READ },
- { 3, REG_V5_FAULT_AR_VA, "AR ACCESS PROTECTION", IOMMU_FAULT_READ },
- { 4, REG_V5_FAULT_AR_VA, "AR SECURITY PROTECTION", IOMMU_FAULT_READ },
- { 16, REG_V5_FAULT_AW_VA, "AW PTW", IOMMU_FAULT_WRITE },
- { 17, REG_V5_FAULT_AW_VA, "AW PAGE", IOMMU_FAULT_WRITE },
- { 18, REG_V5_FAULT_AW_VA, "AW MULTI-HIT", IOMMU_FAULT_WRITE },
- { 19, REG_V5_FAULT_AW_VA, "AW ACCESS PROTECTION", IOMMU_FAULT_WRITE },
- { 20, REG_V5_FAULT_AW_VA, "AW SECURITY PROTECTION", IOMMU_FAULT_WRITE },
+static const char * const sysmmu_v7_fault_names[] = {
+ "PTW",
+ "PAGE",
+ "ACCESS PROTECTION",
+ "RESERVED"
};
/*
@@ -246,9 +251,12 @@ struct exynos_iommu_domain {
struct iommu_domain domain; /* generic domain data structure */
};
+struct sysmmu_drvdata;
+
/*
* SysMMU version specific data. Contains offsets for the registers which can
* be found in different SysMMU variants, but have different offset values.
+ * Also contains version specific callbacks to abstract the hardware.
*/
struct sysmmu_variant {
u32 pt_base; /* page table base address (physical) */
@@ -259,6 +267,11 @@ struct sysmmu_variant {
u32 flush_end; /* end address of range invalidation */
u32 int_status; /* interrupt status information */
u32 int_clear; /* clear the interrupt */
+ u32 fault_va; /* IOVA address that caused fault */
+ u32 fault_info; /* fault transaction info */
+
+ int (*get_fault_info)(struct sysmmu_drvdata *data, unsigned int itype,
+ struct sysmmu_fault *fault);
};
/*
@@ -293,6 +306,59 @@ struct sysmmu_drvdata {
#define SYSMMU_REG(data, reg) ((data)->sfrbase + (data)->variant->reg)
+static int exynos_sysmmu_v1_get_fault_info(struct sysmmu_drvdata *data,
+ unsigned int itype,
+ struct sysmmu_fault *fault)
+{
+ const struct sysmmu_v1_fault_info *finfo;
+
+ if (itype >= ARRAY_SIZE(sysmmu_v1_faults))
+ return -ENXIO;
+
+ finfo = &sysmmu_v1_faults[itype];
+ fault->addr = readl(data->sfrbase + finfo->addr_reg);
+ fault->name = finfo->name;
+ fault->type = finfo->type;
+
+ return 0;
+}
+
+static int exynos_sysmmu_v5_get_fault_info(struct sysmmu_drvdata *data,
+ unsigned int itype,
+ struct sysmmu_fault *fault)
+{
+ unsigned int addr_reg;
+
+ if (itype < ARRAY_SIZE(sysmmu_v5_fault_names)) {
+ fault->type = IOMMU_FAULT_READ;
+ addr_reg = REG_V5_FAULT_AR_VA;
+ } else if (itype >= 16 && itype <= 20) {
+ fault->type = IOMMU_FAULT_WRITE;
+ addr_reg = REG_V5_FAULT_AW_VA;
+ itype -= 16;
+ } else {
+ return -ENXIO;
+ }
+
+ fault->name = sysmmu_v5_fault_names[itype];
+ fault->addr = readl(data->sfrbase + addr_reg);
+
+ return 0;
+}
+
+static int exynos_sysmmu_v7_get_fault_info(struct sysmmu_drvdata *data,
+ unsigned int itype,
+ struct sysmmu_fault *fault)
+{
+ u32 info = readl(SYSMMU_REG(data, fault_info));
+
+ fault->addr = readl(SYSMMU_REG(data, fault_va));
+ fault->name = sysmmu_v7_fault_names[itype % 4];
+ fault->type = (info & BIT(20)) ? IOMMU_FAULT_WRITE : IOMMU_FAULT_READ;
+
+ return 0;
+}
+
/* SysMMU v1..v3 */
static const struct sysmmu_variant sysmmu_v1_variant = {
.flush_all = 0x0c,
@@ -300,9 +366,11 @@ static const struct sysmmu_variant sysmmu_v1_variant = {
.pt_base = 0x14,
.int_status = 0x18,
.int_clear = 0x1c,
+
+ .get_fault_info = exynos_sysmmu_v1_get_fault_info,
};
-/* SysMMU v5 and v7 (non-VM capable) */
+/* SysMMU v5 */
static const struct sysmmu_variant sysmmu_v5_variant = {
.pt_base = 0x0c,
.flush_all = 0x10,
@@ -312,9 +380,27 @@ static const struct sysmmu_variant sysmmu_v5_variant = {
.flush_end = 0x24,
.int_status = 0x60,
.int_clear = 0x64,
+
+ .get_fault_info = exynos_sysmmu_v5_get_fault_info,
};
-/* SysMMU v7: VM capable register set */
+/* SysMMU v7: non-VM capable register layout */
+static const struct sysmmu_variant sysmmu_v7_variant = {
+ .pt_base = 0x0c,
+ .flush_all = 0x10,
+ .flush_entry = 0x14,
+ .flush_range = 0x18,
+ .flush_start = 0x20,
+ .flush_end = 0x24,
+ .int_status = 0x60,
+ .int_clear = 0x64,
+ .fault_va = 0x70,
+ .fault_info = 0x78,
+
+ .get_fault_info = exynos_sysmmu_v7_get_fault_info,
+};
+
+/* SysMMU v7: VM capable register layout */
static const struct sysmmu_variant sysmmu_v7_vm_variant = {
.pt_base = 0x800c,
.flush_all = 0x8010,
@@ -324,6 +410,10 @@ static const struct sysmmu_variant sysmmu_v7_vm_variant = {
.flush_end = 0x8024,
.int_status = 0x60,
.int_clear = 0x64,
+ .fault_va = 0x1000,
+ .fault_info = 0x1004,
+
+ .get_fault_info = exynos_sysmmu_v7_get_fault_info,
};
static struct exynos_iommu_domain *to_exynos_domain(struct iommu_domain *dom)
@@ -446,75 +536,63 @@ static void __sysmmu_get_version(struct sysmmu_drvdata *data)
if (data->has_vcr)
data->variant = &sysmmu_v7_vm_variant;
else
- data->variant = &sysmmu_v5_variant;
+ data->variant = &sysmmu_v7_variant;
}
__sysmmu_disable_clocks(data);
}
static void show_fault_information(struct sysmmu_drvdata *data,
- const struct sysmmu_fault_info *finfo,
- sysmmu_iova_t fault_addr)
+ const struct sysmmu_fault *fault)
{
sysmmu_pte_t *ent;
- dev_err(data->sysmmu, "%s: %s FAULT occurred at %#x\n",
- dev_name(data->master), finfo->name, fault_addr);
+ dev_err(data->sysmmu, "%s: [%s] %s FAULT occurred at %#x\n",
+ dev_name(data->master),
+ fault->type == IOMMU_FAULT_READ ? "READ" : "WRITE",
+ fault->name, fault->addr);
dev_dbg(data->sysmmu, "Page table base: %pa\n", &data->pgtable);
- ent = section_entry(phys_to_virt(data->pgtable), fault_addr);
+ ent = section_entry(phys_to_virt(data->pgtable), fault->addr);
dev_dbg(data->sysmmu, "\tLv1 entry: %#x\n", *ent);
if (lv1ent_page(ent)) {
- ent = page_entry(ent, fault_addr);
+ ent = page_entry(ent, fault->addr);
dev_dbg(data->sysmmu, "\t Lv2 entry: %#x\n", *ent);
}
}
static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
{
- /* SYSMMU is in blocked state when interrupt occurred. */
struct sysmmu_drvdata *data = dev_id;
- const struct sysmmu_fault_info *finfo;
- unsigned int i, n, itype;
- sysmmu_iova_t fault_addr;
+ unsigned int itype;
+ struct sysmmu_fault fault;
int ret = -ENOSYS;
WARN_ON(!data->active);
- if (MMU_MAJ_VER(data->version) < 5) {
- finfo = sysmmu_faults;
- n = ARRAY_SIZE(sysmmu_faults);
- } else {
- finfo = sysmmu_v5_faults;
- n = ARRAY_SIZE(sysmmu_v5_faults);
- }
-
spin_lock(&data->lock);
-
clk_enable(data->clk_master);
itype = __ffs(readl(SYSMMU_REG(data, int_status)));
- for (i = 0; i < n; i++, finfo++)
- if (finfo->bit == itype)
- break;
- /* unknown/unsupported fault */
- BUG_ON(i == n);
-
- /* print debug message */
- fault_addr = readl(data->sfrbase + finfo->addr_reg);
- show_fault_information(data, finfo, fault_addr);
-
- if (data->domain)
- ret = report_iommu_fault(&data->domain->domain,
- data->master, fault_addr, finfo->type);
- /* fault is not recovered by fault handler */
- BUG_ON(ret != 0);
+ ret = data->variant->get_fault_info(data, itype, &fault);
+ if (ret) {
+ dev_err(data->sysmmu, "Unhandled interrupt bit %u\n", itype);
+ goto out;
+ }
+ show_fault_information(data, &fault);
+ if (data->domain) {
+ ret = report_iommu_fault(&data->domain->domain, data->master,
+ fault.addr, fault.type);
+ }
+ if (ret)
+ panic("Unrecoverable System MMU Fault!");
+
+out:
writel(1 << itype, SYSMMU_REG(data, int_clear));
+ /* SysMMU is in blocked state when interrupt occurred */
sysmmu_unblock(data);
-
clk_disable(data->clk_master);
-
spin_unlock(&data->lock);
return IRQ_HANDLED;
@@ -1346,8 +1424,10 @@ static void exynos_iommu_release_device(struct device *dev)
struct iommu_group *group = iommu_group_get(dev);
if (group) {
+#ifndef CONFIG_ARM
WARN_ON(owner->domain !=
iommu_group_default_domain(group));
+#endif
exynos_iommu_detach_device(owner->domain, dev);
iommu_group_put(group);
}
@@ -1398,13 +1478,15 @@ static int exynos_iommu_of_xlate(struct device *dev,
static const struct iommu_ops exynos_iommu_ops = {
.domain_alloc = exynos_iommu_domain_alloc,
.device_group = generic_device_group,
+#ifdef CONFIG_ARM
+ .set_platform_dma_ops = exynos_iommu_release_device,
+#endif
.probe_device = exynos_iommu_probe_device,
.release_device = exynos_iommu_release_device,
.pgsize_bitmap = SECT_SIZE | LPAGE_SIZE | SPAGE_SIZE,
.of_xlate = exynos_iommu_of_xlate,
.default_domain_ops = &(const struct iommu_domain_ops) {
.attach_dev = exynos_iommu_attach_device,
- .detach_dev = exynos_iommu_detach_device,
.map = exynos_iommu_map,
.unmap = exynos_iommu_unmap,
.iova_to_phys = exynos_iommu_iova_to_phys,
@@ -1446,7 +1528,7 @@ static int __init exynos_iommu_init(void)
return 0;
err_reg_driver:
- platform_driver_unregister(&exynos_sysmmu_driver);
+ kmem_cache_free(lv2table_kmem_cache, zero_lv2_table);
err_zero_lv2:
kmem_cache_destroy(lv2table_kmem_cache);
return ret;
diff --git a/drivers/iommu/fsl_pamu_domain.c b/drivers/iommu/fsl_pamu_domain.c
index 4408ac3c49b6..bce372297099 100644
--- a/drivers/iommu/fsl_pamu_domain.c
+++ b/drivers/iommu/fsl_pamu_domain.c
@@ -283,9 +283,9 @@ static int fsl_pamu_attach_device(struct iommu_domain *domain,
return ret;
}
-static void fsl_pamu_detach_device(struct iommu_domain *domain,
- struct device *dev)
+static void fsl_pamu_set_platform_dma(struct device *dev)
{
+ struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
struct fsl_dma_domain *dma_domain = to_fsl_dma_domain(domain);
const u32 *prop;
int len;
@@ -452,9 +452,9 @@ static const struct iommu_ops fsl_pamu_ops = {
.domain_alloc = fsl_pamu_domain_alloc,
.probe_device = fsl_pamu_probe_device,
.device_group = fsl_pamu_device_group,
+ .set_platform_dma_ops = fsl_pamu_set_platform_dma,
.default_domain_ops = &(const struct iommu_domain_ops) {
.attach_dev = fsl_pamu_attach_device,
- .detach_dev = fsl_pamu_detach_device,
.iova_to_phys = fsl_pamu_iova_to_phys,
.free = fsl_pamu_domain_free,
}
diff --git a/drivers/iommu/intel/Kconfig b/drivers/iommu/intel/Kconfig
index b7dff5092fd2..12e1e90fdae1 100644
--- a/drivers/iommu/intel/Kconfig
+++ b/drivers/iommu/intel/Kconfig
@@ -96,4 +96,15 @@ config INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON
passing intel_iommu=sm_on to the kernel. If not sure, please use
the default value.
+config INTEL_IOMMU_PERF_EVENTS
+ def_bool y
+ bool "Intel IOMMU performance events"
+ depends on INTEL_IOMMU && PERF_EVENTS
+ help
+ Selecting this option will enable the performance monitoring
+ infrastructure in the Intel IOMMU. It collects information about
+ key events occurring during operation of the remapping hardware,
+ to aid performance tuning and debug. These are available on modern
+ processors which support Intel VT-d 4.0 and later.
+
endif # INTEL_IOMMU
diff --git a/drivers/iommu/intel/Makefile b/drivers/iommu/intel/Makefile
index fa0dae16441c..7af3b8a4f2a0 100644
--- a/drivers/iommu/intel/Makefile
+++ b/drivers/iommu/intel/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_DMAR_PERF) += perf.o
obj-$(CONFIG_INTEL_IOMMU_DEBUGFS) += debugfs.o
obj-$(CONFIG_INTEL_IOMMU_SVM) += svm.o
obj-$(CONFIG_IRQ_REMAP) += irq_remapping.o
+obj-$(CONFIG_INTEL_IOMMU_PERF_EVENTS) += perfmon.o
diff --git a/drivers/iommu/intel/dmar.c b/drivers/iommu/intel/dmar.c
index b00a0ceb2d13..6acfe879589c 100644
--- a/drivers/iommu/intel/dmar.c
+++ b/drivers/iommu/intel/dmar.c
@@ -34,6 +34,7 @@
#include "../irq_remapping.h"
#include "perf.h"
#include "trace.h"
+#include "perfmon.h"
typedef int (*dmar_res_handler_t)(struct acpi_dmar_header *, void *);
struct dmar_res_callback {
@@ -427,6 +428,8 @@ static int dmar_parse_one_drhd(struct acpi_dmar_header *header, void *arg)
memcpy(dmaru->hdr, header, header->length);
dmaru->reg_base_addr = drhd->address;
dmaru->segment = drhd->segment;
+ /* The size of the register set is 2 ^ N 4 KB pages. */
+ dmaru->reg_size = 1UL << (drhd->size + 12);
dmaru->include_all = drhd->flags & 0x1; /* BIT0: INCLUDE_ALL */
dmaru->devices = dmar_alloc_dev_scope((void *)(drhd + 1),
((void *)drhd) + drhd->header.length,
@@ -956,17 +959,18 @@ static void unmap_iommu(struct intel_iommu *iommu)
/**
* map_iommu: map the iommu's registers
* @iommu: the iommu to map
- * @phys_addr: the physical address of the base resgister
+ * @drhd: DMA remapping hardware definition structure
*
* Memory map the iommu's registers. Start w/ a single page, and
* possibly expand if that turns out to be insufficent.
*/
-static int map_iommu(struct intel_iommu *iommu, u64 phys_addr)
+static int map_iommu(struct intel_iommu *iommu, struct dmar_drhd_unit *drhd)
{
+ u64 phys_addr = drhd->reg_base_addr;
int map_size, err=0;
iommu->reg_phys = phys_addr;
- iommu->reg_size = VTD_PAGE_SIZE;
+ iommu->reg_size = drhd->reg_size;
if (!request_mem_region(iommu->reg_phys, iommu->reg_size, iommu->name)) {
pr_err("Can't reserve memory\n");
@@ -1013,6 +1017,16 @@ static int map_iommu(struct intel_iommu *iommu, u64 phys_addr)
goto release;
}
}
+
+ if (cap_ecmds(iommu->cap)) {
+ int i;
+
+ for (i = 0; i < DMA_MAX_NUM_ECMDCAP; i++) {
+ iommu->ecmdcap[i] = dmar_readq(iommu->reg + DMAR_ECCAP_REG +
+ i * DMA_ECMD_REG_STEP);
+ }
+ }
+
err = 0;
goto out;
@@ -1050,7 +1064,7 @@ static int alloc_iommu(struct dmar_drhd_unit *drhd)
}
sprintf(iommu->name, "dmar%d", iommu->seq_id);
- err = map_iommu(iommu, drhd->reg_base_addr);
+ err = map_iommu(iommu, drhd);
if (err) {
pr_err("Failed to map %s\n", iommu->name);
goto error_free_seq_id;
@@ -1103,6 +1117,9 @@ static int alloc_iommu(struct dmar_drhd_unit *drhd)
if (sts & DMA_GSTS_QIES)
iommu->gcmd |= DMA_GCMD_QIE;
+ if (alloc_iommu_pmu(iommu))
+ pr_debug("Cannot alloc PMU for iommu (seq_id = %d)\n", iommu->seq_id);
+
raw_spin_lock_init(&iommu->register_lock);
/*
@@ -1127,6 +1144,8 @@ static int alloc_iommu(struct dmar_drhd_unit *drhd)
err = iommu_device_register(&iommu->iommu, &intel_iommu_ops, NULL);
if (err)
goto err_sysfs;
+
+ iommu_pmu_register(iommu);
}
drhd->iommu = iommu;
@@ -1137,6 +1156,7 @@ static int alloc_iommu(struct dmar_drhd_unit *drhd)
err_sysfs:
iommu_device_sysfs_remove(&iommu->iommu);
err_unmap:
+ free_iommu_pmu(iommu);
unmap_iommu(iommu);
error_free_seq_id:
ida_free(&dmar_seq_ids, iommu->seq_id);
@@ -1148,10 +1168,13 @@ error:
static void free_iommu(struct intel_iommu *iommu)
{
if (intel_iommu_enabled && !iommu->drhd->ignored) {
+ iommu_pmu_unregister(iommu);
iommu_device_unregister(&iommu->iommu);
iommu_device_sysfs_remove(&iommu->iommu);
}
+ free_iommu_pmu(iommu);
+
if (iommu->irq) {
if (iommu->pr_irq) {
free_irq(iommu->pr_irq, iommu);
@@ -1859,6 +1882,8 @@ static inline int dmar_msi_reg(struct intel_iommu *iommu, int irq)
return DMAR_FECTL_REG;
else if (iommu->pr_irq == irq)
return DMAR_PECTL_REG;
+ else if (iommu->perf_irq == irq)
+ return DMAR_PERFINTRCTL_REG;
else
BUG();
}
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index 59df7e42fd53..7c2f4bd33582 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -16,7 +16,6 @@
#include <linux/crash_dump.h>
#include <linux/dma-direct.h>
#include <linux/dmi.h>
-#include <linux/intel-svm.h>
#include <linux/memory.h>
#include <linux/pci.h>
#include <linux/pci-ats.h>
@@ -30,6 +29,7 @@
#include "../iommu-sva.h"
#include "pasid.h"
#include "cap_audit.h"
+#include "perfmon.h"
#define ROOT_SIZE VTD_PAGE_SIZE
#define CONTEXT_SIZE VTD_PAGE_SIZE
@@ -362,12 +362,12 @@ static int __init intel_iommu_setup(char *str)
}
__setup("intel_iommu=", intel_iommu_setup);
-void *alloc_pgtable_page(int node)
+void *alloc_pgtable_page(int node, gfp_t gfp)
{
struct page *page;
void *vaddr = NULL;
- page = alloc_pages_node(node, GFP_ATOMIC | __GFP_ZERO, 0);
+ page = alloc_pages_node(node, gfp | __GFP_ZERO, 0);
if (page)
vaddr = page_address(page);
return vaddr;
@@ -612,7 +612,7 @@ struct context_entry *iommu_context_addr(struct intel_iommu *iommu, u8 bus,
if (!alloc)
return NULL;
- context = alloc_pgtable_page(iommu->node);
+ context = alloc_pgtable_page(iommu->node, GFP_ATOMIC);
if (!context)
return NULL;
@@ -908,7 +908,8 @@ pgtable_walk:
#endif
static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
- unsigned long pfn, int *target_level)
+ unsigned long pfn, int *target_level,
+ gfp_t gfp)
{
struct dma_pte *parent, *pte;
int level = agaw_to_level(domain->agaw);
@@ -935,7 +936,7 @@ static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
if (!dma_pte_present(pte)) {
uint64_t pteval;
- tmp_page = alloc_pgtable_page(domain->nid);
+ tmp_page = alloc_pgtable_page(domain->nid, gfp);
if (!tmp_page)
return NULL;
@@ -1186,7 +1187,7 @@ static int iommu_alloc_root_entry(struct intel_iommu *iommu)
{
struct root_entry *root;
- root = (struct root_entry *)alloc_pgtable_page(iommu->node);
+ root = (struct root_entry *)alloc_pgtable_page(iommu->node, GFP_ATOMIC);
if (!root) {
pr_err("Allocating root entry for %s failed\n",
iommu->name);
@@ -2150,7 +2151,8 @@ static void switch_to_super_page(struct dmar_domain *domain,
while (start_pfn <= end_pfn) {
if (!pte)
- pte = pfn_to_dma_pte(domain, start_pfn, &level);
+ pte = pfn_to_dma_pte(domain, start_pfn, &level,
+ GFP_ATOMIC);
if (dma_pte_present(pte)) {
dma_pte_free_pagetable(domain, start_pfn,
@@ -2172,7 +2174,8 @@ static void switch_to_super_page(struct dmar_domain *domain,
static int
__domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
- unsigned long phys_pfn, unsigned long nr_pages, int prot)
+ unsigned long phys_pfn, unsigned long nr_pages, int prot,
+ gfp_t gfp)
{
struct dma_pte *first_pte = NULL, *pte = NULL;
unsigned int largepage_lvl = 0;
@@ -2202,7 +2205,8 @@ __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
largepage_lvl = hardware_largepage_caps(domain, iov_pfn,
phys_pfn, nr_pages);
- pte = pfn_to_dma_pte(domain, iov_pfn, &largepage_lvl);
+ pte = pfn_to_dma_pte(domain, iov_pfn, &largepage_lvl,
+ gfp);
if (!pte)
return -ENOMEM;
first_pte = pte;
@@ -2368,7 +2372,7 @@ static int iommu_domain_identity_map(struct dmar_domain *domain,
return __domain_mapping(domain, first_vpfn,
first_vpfn, last_vpfn - first_vpfn + 1,
- DMA_PTE_READ|DMA_PTE_WRITE);
+ DMA_PTE_READ|DMA_PTE_WRITE, GFP_KERNEL);
}
static int md_domain_init(struct dmar_domain *domain, int guest_width);
@@ -2676,7 +2680,7 @@ static int copy_context_table(struct intel_iommu *iommu,
if (!old_ce)
goto out;
- new_ce = alloc_pgtable_page(iommu->node);
+ new_ce = alloc_pgtable_page(iommu->node, GFP_KERNEL);
if (!new_ce)
goto out_unmap;
@@ -4005,7 +4009,8 @@ int __init intel_iommu_init(void)
* is likely to be much lower than the overhead of synchronizing
* the virtual and physical IOMMU page-tables.
*/
- if (cap_caching_mode(iommu->cap)) {
+ if (cap_caching_mode(iommu->cap) &&
+ !first_level_by_default(IOMMU_DOMAIN_DMA)) {
pr_info_once("IOMMU batching disallowed due to virtualization\n");
iommu_set_dma_strict();
}
@@ -4013,6 +4018,8 @@ int __init intel_iommu_init(void)
intel_iommu_groups,
"%s", iommu->name);
iommu_device_register(&iommu->iommu, &intel_iommu_ops, NULL);
+
+ iommu_pmu_register(iommu);
}
up_read(&dmar_global_lock);
@@ -4136,7 +4143,7 @@ static int md_domain_init(struct dmar_domain *domain, int guest_width)
domain->max_addr = 0;
/* always allocate the top pgd */
- domain->pgd = alloc_pgtable_page(domain->nid);
+ domain->pgd = alloc_pgtable_page(domain->nid, GFP_ATOMIC);
if (!domain->pgd)
return -ENOMEM;
domain_flush_cache(domain, domain->pgd, PAGE_SIZE);
@@ -4298,7 +4305,7 @@ static int intel_iommu_map(struct iommu_domain *domain,
the low bits of hpa would take us onto the next page */
size = aligned_nrpages(hpa, size);
return __domain_mapping(dmar_domain, iova >> VTD_PAGE_SHIFT,
- hpa >> VTD_PAGE_SHIFT, size, prot);
+ hpa >> VTD_PAGE_SHIFT, size, prot, gfp);
}
static int intel_iommu_map_pages(struct iommu_domain *domain,
@@ -4333,7 +4340,8 @@ static size_t intel_iommu_unmap(struct iommu_domain *domain,
/* Cope with horrid API which requires us to unmap more than the
size argument if it happens to be a large-page mapping. */
- BUG_ON(!pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT, &level));
+ BUG_ON(!pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT, &level,
+ GFP_ATOMIC));
if (size < VTD_PAGE_SIZE << level_to_offset_bits(level))
size = VTD_PAGE_SIZE << level_to_offset_bits(level);
@@ -4346,7 +4354,12 @@ static size_t intel_iommu_unmap(struct iommu_domain *domain,
if (dmar_domain->max_addr == iova + size)
dmar_domain->max_addr = iova;
- iommu_iotlb_gather_add_page(domain, gather, iova, size);
+ /*
+ * We do not use page-selective IOTLB invalidation in flush queue,
+ * so there is no need to track page and sync iotlb.
+ */
+ if (!iommu_iotlb_gather_queued(gather))
+ iommu_iotlb_gather_add_page(domain, gather, iova, size);
return size;
}
@@ -4392,7 +4405,8 @@ static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
int level = 0;
u64 phys = 0;
- pte = pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT, &level);
+ pte = pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT, &level,
+ GFP_ATOMIC);
if (pte && dma_pte_present(pte))
phys = dma_pte_addr(pte) +
(iova & (BIT_MASK(level_to_offset_bits(level) +
@@ -4464,8 +4478,6 @@ static bool intel_iommu_capable(struct device *dev, enum iommu_cap cap)
switch (cap) {
case IOMMU_CAP_CACHE_COHERENCY:
return true;
- case IOMMU_CAP_INTR_REMAP:
- return irq_remapping_enabled == 1;
case IOMMU_CAP_PRE_BOOT_PROTECTION:
return dmar_platform_optin();
case IOMMU_CAP_ENFORCE_CACHE_COHERENCY:
@@ -4642,8 +4654,12 @@ static int intel_iommu_enable_sva(struct device *dev)
return -EINVAL;
ret = iopf_queue_add_device(iommu->iopf_queue, dev);
- if (!ret)
- ret = iommu_register_device_fault_handler(dev, iommu_queue_iopf, dev);
+ if (ret)
+ return ret;
+
+ ret = iommu_register_device_fault_handler(dev, iommu_queue_iopf, dev);
+ if (ret)
+ iopf_queue_remove_device(iommu->iopf_queue, dev);
return ret;
}
@@ -4655,8 +4671,12 @@ static int intel_iommu_disable_sva(struct device *dev)
int ret;
ret = iommu_unregister_device_fault_handler(dev);
- if (!ret)
- ret = iopf_queue_remove_device(iommu->iopf_queue, dev);
+ if (ret)
+ return ret;
+
+ ret = iopf_queue_remove_device(iommu->iopf_queue, dev);
+ if (ret)
+ iommu_register_device_fault_handler(dev, iommu_queue_iopf, dev);
return ret;
}
@@ -5023,3 +5043,59 @@ void quirk_extra_dev_tlb_flush(struct device_domain_info *info,
pasid, qdep, address, mask);
}
}
+
+#define ecmd_get_status_code(res) (((res) & 0xff) >> 1)
+
+/*
+ * Function to submit a command to the enhanced command interface. The
+ * valid enhanced command descriptions are defined in Table 47 of the
+ * VT-d spec. The VT-d hardware implementation may support some but not
+ * all commands, which can be determined by checking the Enhanced
+ * Command Capability Register.
+ *
+ * Return values:
+ * - 0: Command successful without any error;
+ * - Negative: software error value;
+ * - Nonzero positive: failure status code defined in Table 48.
+ */
+int ecmd_submit_sync(struct intel_iommu *iommu, u8 ecmd, u64 oa, u64 ob)
+{
+ unsigned long flags;
+ u64 res;
+ int ret;
+
+ if (!cap_ecmds(iommu->cap))
+ return -ENODEV;
+
+ raw_spin_lock_irqsave(&iommu->register_lock, flags);
+
+ res = dmar_readq(iommu->reg + DMAR_ECRSP_REG);
+ if (res & DMA_ECMD_ECRSP_IP) {
+ ret = -EBUSY;
+ goto err;
+ }
+
+ /*
+ * Unconditionally write the operand B, because
+ * - There is no side effect if an ecmd doesn't require an
+ * operand B, but we set the register to some value.
+ * - It's not invoked in any critical path. The extra MMIO
+ * write doesn't bring any performance concerns.
+ */
+ dmar_writeq(iommu->reg + DMAR_ECEO_REG, ob);
+ dmar_writeq(iommu->reg + DMAR_ECMD_REG, ecmd | (oa << DMA_ECMD_OA_SHIFT));
+
+ IOMMU_WAIT_OP(iommu, DMAR_ECRSP_REG, dmar_readq,
+ !(res & DMA_ECMD_ECRSP_IP), res);
+
+ if (res & DMA_ECMD_ECRSP_IP) {
+ ret = -ETIMEDOUT;
+ goto err;
+ }
+
+ ret = ecmd_get_status_code(res);
+err:
+ raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
+
+ return ret;
+}
diff --git a/drivers/iommu/intel/iommu.h b/drivers/iommu/intel/iommu.h
index 06e61e474856..d6df3b865812 100644
--- a/drivers/iommu/intel/iommu.h
+++ b/drivers/iommu/intel/iommu.h
@@ -22,6 +22,7 @@
#include <linux/ioasid.h>
#include <linux/bitfield.h>
#include <linux/xarray.h>
+#include <linux/perf_event.h>
#include <asm/cacheflush.h>
#include <asm/iommu.h>
@@ -125,6 +126,17 @@
#define DMAR_MTRR_PHYSMASK8_REG 0x208
#define DMAR_MTRR_PHYSBASE9_REG 0x210
#define DMAR_MTRR_PHYSMASK9_REG 0x218
+#define DMAR_PERFCAP_REG 0x300
+#define DMAR_PERFCFGOFF_REG 0x310
+#define DMAR_PERFOVFOFF_REG 0x318
+#define DMAR_PERFCNTROFF_REG 0x31c
+#define DMAR_PERFINTRSTS_REG 0x324
+#define DMAR_PERFINTRCTL_REG 0x328
+#define DMAR_PERFEVNTCAP_REG 0x380
+#define DMAR_ECMD_REG 0x400
+#define DMAR_ECEO_REG 0x408
+#define DMAR_ECRSP_REG 0x410
+#define DMAR_ECCAP_REG 0x430
#define DMAR_VCCAP_REG 0xe30 /* Virtual command capability register */
#define DMAR_VCMD_REG 0xe00 /* Virtual command register */
#define DMAR_VCRSP_REG 0xe10 /* Virtual command response register */
@@ -148,6 +160,7 @@
*/
#define cap_esrtps(c) (((c) >> 63) & 1)
#define cap_esirtps(c) (((c) >> 62) & 1)
+#define cap_ecmds(c) (((c) >> 61) & 1)
#define cap_fl5lp_support(c) (((c) >> 60) & 1)
#define cap_pi_support(c) (((c) >> 59) & 1)
#define cap_fl1gp_support(c) (((c) >> 56) & 1)
@@ -179,7 +192,8 @@
* Extended Capability Register
*/
-#define ecap_rps(e) (((e) >> 49) & 0x1)
+#define ecap_pms(e) (((e) >> 51) & 0x1)
+#define ecap_rps(e) (((e) >> 49) & 0x1)
#define ecap_smpwc(e) (((e) >> 48) & 0x1)
#define ecap_flts(e) (((e) >> 47) & 0x1)
#define ecap_slts(e) (((e) >> 46) & 0x1)
@@ -210,6 +224,22 @@
#define ecap_max_handle_mask(e) (((e) >> 20) & 0xf)
#define ecap_sc_support(e) (((e) >> 7) & 0x1) /* Snooping Control */
+/*
+ * Decoding Perf Capability Register
+ */
+#define pcap_num_cntr(p) ((p) & 0xffff)
+#define pcap_cntr_width(p) (((p) >> 16) & 0x7f)
+#define pcap_num_event_group(p) (((p) >> 24) & 0x1f)
+#define pcap_filters_mask(p) (((p) >> 32) & 0x1f)
+#define pcap_interrupt(p) (((p) >> 50) & 0x1)
+/* The counter stride is calculated as 2 ^ (x+10) bytes */
+#define pcap_cntr_stride(p) (1ULL << ((((p) >> 52) & 0x7) + 10))
+
+/*
+ * Decoding Perf Event Capability Register
+ */
+#define pecap_es(p) ((p) & 0xfffffff)
+
/* Virtual command interface capability */
#define vccap_pasid(v) (((v) & DMA_VCS_PAS)) /* PASID allocation */
@@ -281,6 +311,26 @@
#define DMA_CCMD_SID(s) (((u64)((s) & 0xffff)) << 16)
#define DMA_CCMD_DID(d) ((u64)((d) & 0xffff))
+/* ECMD_REG */
+#define DMA_MAX_NUM_ECMD 256
+#define DMA_MAX_NUM_ECMDCAP (DMA_MAX_NUM_ECMD / 64)
+#define DMA_ECMD_REG_STEP 8
+#define DMA_ECMD_ENABLE 0xf0
+#define DMA_ECMD_DISABLE 0xf1
+#define DMA_ECMD_FREEZE 0xf4
+#define DMA_ECMD_UNFREEZE 0xf5
+#define DMA_ECMD_OA_SHIFT 16
+#define DMA_ECMD_ECRSP_IP 0x1
+#define DMA_ECMD_ECCAP3 3
+#define DMA_ECMD_ECCAP3_ECNTS BIT_ULL(48)
+#define DMA_ECMD_ECCAP3_DCNTS BIT_ULL(49)
+#define DMA_ECMD_ECCAP3_FCNTS BIT_ULL(52)
+#define DMA_ECMD_ECCAP3_UFCNTS BIT_ULL(53)
+#define DMA_ECMD_ECCAP3_ESSENTIAL (DMA_ECMD_ECCAP3_ECNTS | \
+ DMA_ECMD_ECCAP3_DCNTS | \
+ DMA_ECMD_ECCAP3_FCNTS | \
+ DMA_ECMD_ECCAP3_UFCNTS)
+
/* FECTL_REG */
#define DMA_FECTL_IM (((u32)1) << 31)
@@ -309,6 +359,9 @@
#define DMA_VCS_PAS ((u64)1)
+/* PERFINTRSTS_REG */
+#define DMA_PERFINTRSTS_PIS ((u32)1)
+
#define IOMMU_WAIT_OP(iommu, offset, op, cond, sts) \
do { \
cycles_t start_time = get_cycles(); \
@@ -438,6 +491,11 @@ struct q_inval {
int free_cnt;
};
+/* Page Request Queue depth */
+#define PRQ_ORDER 4
+#define PRQ_RING_MASK ((0x1000 << PRQ_ORDER) - 0x20)
+#define PRQ_DEPTH ((0x1000 << PRQ_ORDER) >> 5)
+
struct dmar_pci_notify_info;
#ifdef CONFIG_IRQ_REMAP
@@ -554,6 +612,40 @@ struct dmar_domain {
iommu core */
};
+/*
+ * In theory, the VT-d 4.0 spec can support up to 2 ^ 16 counters.
+ * But in practice, there are only 14 counters for the existing
+ * platform. Setting the max number of counters to 64 should be good
+ * enough for a long time. Also, supporting more than 64 counters
+ * requires more extras, e.g., extra freeze and overflow registers,
+ * which is not necessary for now.
+ */
+#define IOMMU_PMU_IDX_MAX 64
+
+struct iommu_pmu {
+ struct intel_iommu *iommu;
+ u32 num_cntr; /* Number of counters */
+ u32 num_eg; /* Number of event group */
+ u32 cntr_width; /* Counter width */
+ u32 cntr_stride; /* Counter Stride */
+ u32 filter; /* Bitmask of filter support */
+ void __iomem *base; /* the PerfMon base address */
+ void __iomem *cfg_reg; /* counter configuration base address */
+ void __iomem *cntr_reg; /* counter 0 address*/
+ void __iomem *overflow; /* overflow status register */
+
+ u64 *evcap; /* Indicates all supported events */
+ u32 **cntr_evcap; /* Supported events of each counter. */
+
+ struct pmu pmu;
+ DECLARE_BITMAP(used_mask, IOMMU_PMU_IDX_MAX);
+ struct perf_event *event_list[IOMMU_PMU_IDX_MAX];
+ unsigned char irq_name[16];
+};
+
+#define IOMMU_IRQ_ID_OFFSET_PRQ (DMAR_UNITS_SUPPORTED)
+#define IOMMU_IRQ_ID_OFFSET_PERF (2 * DMAR_UNITS_SUPPORTED)
+
struct intel_iommu {
void __iomem *reg; /* Pointer to hardware regs, virtual addr */
u64 reg_phys; /* physical address of hw register set */
@@ -561,12 +653,13 @@ struct intel_iommu {
u64 cap;
u64 ecap;
u64 vccap;
+ u64 ecmdcap[DMA_MAX_NUM_ECMDCAP];
u32 gcmd; /* Holds TE, EAFL. Don't need SRTP, SFL, WBF */
raw_spinlock_t register_lock; /* protect register handling */
int seq_id; /* sequence id of the iommu */
int agaw; /* agaw of this iommu */
int msagaw; /* max sagaw of this iommu */
- unsigned int irq, pr_irq;
+ unsigned int irq, pr_irq, perf_irq;
u16 segment; /* PCI segment# */
unsigned char name[13]; /* Device Name */
@@ -600,6 +693,8 @@ struct intel_iommu {
struct dmar_drhd_unit *drhd;
void *perf_statistic;
+
+ struct iommu_pmu *pmu;
};
/* PCI domain-device relationship */
@@ -737,7 +832,7 @@ int qi_submit_sync(struct intel_iommu *iommu, struct qi_desc *desc,
extern int dmar_ir_support(void);
-void *alloc_pgtable_page(int node);
+void *alloc_pgtable_page(int node, gfp_t gfp);
void free_pgtable_page(void *vaddr);
void iommu_flush_write_buffer(struct intel_iommu *iommu);
struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devfn);
@@ -756,19 +851,13 @@ struct intel_svm_dev {
struct rcu_head rcu;
struct device *dev;
struct intel_iommu *iommu;
- struct iommu_sva sva;
- u32 pasid;
- int users;
u16 did;
- u16 dev_iotlb:1;
u16 sid, qdep;
};
struct intel_svm {
struct mmu_notifier notifier;
struct mm_struct *mm;
-
- unsigned int flags;
u32 pasid;
struct list_head devs;
};
@@ -800,6 +889,14 @@ extern const struct iommu_ops intel_iommu_ops;
extern int intel_iommu_sm;
extern int iommu_calculate_agaw(struct intel_iommu *iommu);
extern int iommu_calculate_max_sagaw(struct intel_iommu *iommu);
+int ecmd_submit_sync(struct intel_iommu *iommu, u8 ecmd, u64 oa, u64 ob);
+
+static inline bool ecmd_has_pmu_essential(struct intel_iommu *iommu)
+{
+ return (iommu->ecmdcap[DMA_ECMD_ECCAP3] & DMA_ECMD_ECCAP3_ESSENTIAL) ==
+ DMA_ECMD_ECCAP3_ESSENTIAL;
+}
+
extern int dmar_disabled;
extern int intel_iommu_enabled;
#else
diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c
index f58f5f57af78..6d01fa078c36 100644
--- a/drivers/iommu/intel/irq_remapping.c
+++ b/drivers/iommu/intel/irq_remapping.c
@@ -573,7 +573,8 @@ static int intel_setup_irq_remapping(struct intel_iommu *iommu)
}
irq_domain_update_bus_token(iommu->ir_domain, DOMAIN_BUS_DMAR);
- iommu->ir_domain->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT;
+ iommu->ir_domain->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT |
+ IRQ_DOMAIN_FLAG_ISOLATED_MSI;
if (cap_caching_mode(iommu->cap))
iommu->ir_domain->msi_parent_ops = &virt_dmar_msi_parent_ops;
diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c
index fb3c7020028d..633e0a4a01e7 100644
--- a/drivers/iommu/intel/pasid.c
+++ b/drivers/iommu/intel/pasid.c
@@ -128,6 +128,9 @@ int intel_pasid_alloc_table(struct device *dev)
pasid_table->max_pasid = 1 << (order + PAGE_SHIFT + 3);
info->pasid_table = pasid_table;
+ if (!ecap_coherent(info->iommu->ecap))
+ clflush_cache_range(pasid_table->table, size);
+
return 0;
}
@@ -200,7 +203,7 @@ static struct pasid_entry *intel_pasid_get_entry(struct device *dev, u32 pasid)
retry:
entries = get_pasid_table_from_pde(&dir[dir_index]);
if (!entries) {
- entries = alloc_pgtable_page(info->iommu->node);
+ entries = alloc_pgtable_page(info->iommu->node, GFP_ATOMIC);
if (!entries)
return NULL;
@@ -215,6 +218,10 @@ retry:
free_pgtable_page(entries);
goto retry;
}
+ if (!ecap_coherent(info->iommu->ecap)) {
+ clflush_cache_range(entries, VTD_PAGE_SIZE);
+ clflush_cache_range(&dir[dir_index].val, sizeof(*dir));
+ }
}
return &entries[index];
@@ -365,6 +372,16 @@ static inline void pasid_set_page_snoop(struct pasid_entry *pe, bool value)
}
/*
+ * Setup No Execute Enable bit (Bit 133) of a scalable mode PASID
+ * entry. It is required when XD bit of the first level page table
+ * entry is about to be set.
+ */
+static inline void pasid_set_nxe(struct pasid_entry *pe)
+{
+ pasid_set_bits(&pe->val[2], 1 << 5, 1 << 5);
+}
+
+/*
* Setup the Page Snoop (PGSNP) field (Bit 88) of a scalable mode
* PASID entry.
*/
@@ -557,6 +574,7 @@ int intel_pasid_setup_first_level(struct intel_iommu *iommu,
pasid_set_domain_id(pte, did);
pasid_set_address_width(pte, iommu->agaw);
pasid_set_page_snoop(pte, !!ecap_smpwc(iommu->ecap));
+ pasid_set_nxe(pte);
/* Setup Present and PASID Granular Transfer Type: */
pasid_set_translation_type(pte, PASID_ENTRY_PGTT_FL_ONLY);
diff --git a/drivers/iommu/intel/perfmon.c b/drivers/iommu/intel/perfmon.c
new file mode 100644
index 000000000000..e17d9743a0d8
--- /dev/null
+++ b/drivers/iommu/intel/perfmon.c
@@ -0,0 +1,877 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Support Intel IOMMU PerfMon
+ * Copyright(c) 2023 Intel Corporation.
+ */
+#define pr_fmt(fmt) "DMAR: " fmt
+#define dev_fmt(fmt) pr_fmt(fmt)
+
+#include <linux/dmar.h>
+#include "iommu.h"
+#include "perfmon.h"
+
+PMU_FORMAT_ATTR(event, "config:0-27"); /* ES: Events Select */
+PMU_FORMAT_ATTR(event_group, "config:28-31"); /* EGI: Event Group Index */
+
+static struct attribute *iommu_pmu_format_attrs[] = {
+ &format_attr_event_group.attr,
+ &format_attr_event.attr,
+ NULL
+};
+
+static struct attribute_group iommu_pmu_format_attr_group = {
+ .name = "format",
+ .attrs = iommu_pmu_format_attrs,
+};
+
+/* The available events are added in attr_update later */
+static struct attribute *attrs_empty[] = {
+ NULL
+};
+
+static struct attribute_group iommu_pmu_events_attr_group = {
+ .name = "events",
+ .attrs = attrs_empty,
+};
+
+static cpumask_t iommu_pmu_cpu_mask;
+
+static ssize_t
+cpumask_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return cpumap_print_to_pagebuf(true, buf, &iommu_pmu_cpu_mask);
+}
+static DEVICE_ATTR_RO(cpumask);
+
+static struct attribute *iommu_pmu_cpumask_attrs[] = {
+ &dev_attr_cpumask.attr,
+ NULL
+};
+
+static struct attribute_group iommu_pmu_cpumask_attr_group = {
+ .attrs = iommu_pmu_cpumask_attrs,
+};
+
+static const struct attribute_group *iommu_pmu_attr_groups[] = {
+ &iommu_pmu_format_attr_group,
+ &iommu_pmu_events_attr_group,
+ &iommu_pmu_cpumask_attr_group,
+ NULL
+};
+
+static inline struct iommu_pmu *dev_to_iommu_pmu(struct device *dev)
+{
+ /*
+ * The perf_event creates its own dev for each PMU.
+ * See pmu_dev_alloc()
+ */
+ return container_of(dev_get_drvdata(dev), struct iommu_pmu, pmu);
+}
+
+#define IOMMU_PMU_ATTR(_name, _format, _filter) \
+ PMU_FORMAT_ATTR(_name, _format); \
+ \
+static struct attribute *_name##_attr[] = { \
+ &format_attr_##_name.attr, \
+ NULL \
+}; \
+ \
+static umode_t \
+_name##_is_visible(struct kobject *kobj, struct attribute *attr, int i) \
+{ \
+ struct device *dev = kobj_to_dev(kobj); \
+ struct iommu_pmu *iommu_pmu = dev_to_iommu_pmu(dev); \
+ \
+ if (!iommu_pmu) \
+ return 0; \
+ return (iommu_pmu->filter & _filter) ? attr->mode : 0; \
+} \
+ \
+static struct attribute_group _name = { \
+ .name = "format", \
+ .attrs = _name##_attr, \
+ .is_visible = _name##_is_visible, \
+};
+
+IOMMU_PMU_ATTR(filter_requester_id_en, "config1:0", IOMMU_PMU_FILTER_REQUESTER_ID);
+IOMMU_PMU_ATTR(filter_domain_en, "config1:1", IOMMU_PMU_FILTER_DOMAIN);
+IOMMU_PMU_ATTR(filter_pasid_en, "config1:2", IOMMU_PMU_FILTER_PASID);
+IOMMU_PMU_ATTR(filter_ats_en, "config1:3", IOMMU_PMU_FILTER_ATS);
+IOMMU_PMU_ATTR(filter_page_table_en, "config1:4", IOMMU_PMU_FILTER_PAGE_TABLE);
+IOMMU_PMU_ATTR(filter_requester_id, "config1:16-31", IOMMU_PMU_FILTER_REQUESTER_ID);
+IOMMU_PMU_ATTR(filter_domain, "config1:32-47", IOMMU_PMU_FILTER_DOMAIN);
+IOMMU_PMU_ATTR(filter_pasid, "config2:0-21", IOMMU_PMU_FILTER_PASID);
+IOMMU_PMU_ATTR(filter_ats, "config2:24-28", IOMMU_PMU_FILTER_ATS);
+IOMMU_PMU_ATTR(filter_page_table, "config2:32-36", IOMMU_PMU_FILTER_PAGE_TABLE);
+
+#define iommu_pmu_en_requester_id(e) ((e) & 0x1)
+#define iommu_pmu_en_domain(e) (((e) >> 1) & 0x1)
+#define iommu_pmu_en_pasid(e) (((e) >> 2) & 0x1)
+#define iommu_pmu_en_ats(e) (((e) >> 3) & 0x1)
+#define iommu_pmu_en_page_table(e) (((e) >> 4) & 0x1)
+#define iommu_pmu_get_requester_id(filter) (((filter) >> 16) & 0xffff)
+#define iommu_pmu_get_domain(filter) (((filter) >> 32) & 0xffff)
+#define iommu_pmu_get_pasid(filter) ((filter) & 0x3fffff)
+#define iommu_pmu_get_ats(filter) (((filter) >> 24) & 0x1f)
+#define iommu_pmu_get_page_table(filter) (((filter) >> 32) & 0x1f)
+
+#define iommu_pmu_set_filter(_name, _config, _filter, _idx, _econfig) \
+{ \
+ if ((iommu_pmu->filter & _filter) && iommu_pmu_en_##_name(_econfig)) { \
+ dmar_writel(iommu_pmu->cfg_reg + _idx * IOMMU_PMU_CFG_OFFSET + \
+ IOMMU_PMU_CFG_SIZE + \
+ (ffs(_filter) - 1) * IOMMU_PMU_CFG_FILTERS_OFFSET, \
+ iommu_pmu_get_##_name(_config) | IOMMU_PMU_FILTER_EN);\
+ } \
+}
+
+#define iommu_pmu_clear_filter(_filter, _idx) \
+{ \
+ if (iommu_pmu->filter & _filter) { \
+ dmar_writel(iommu_pmu->cfg_reg + _idx * IOMMU_PMU_CFG_OFFSET + \
+ IOMMU_PMU_CFG_SIZE + \
+ (ffs(_filter) - 1) * IOMMU_PMU_CFG_FILTERS_OFFSET, \
+ 0); \
+ } \
+}
+
+/*
+ * Define the event attr related functions
+ * Input: _name: event attr name
+ * _string: string of the event in sysfs
+ * _g_idx: event group encoding
+ * _event: event encoding
+ */
+#define IOMMU_PMU_EVENT_ATTR(_name, _string, _g_idx, _event) \
+ PMU_EVENT_ATTR_STRING(_name, event_attr_##_name, _string) \
+ \
+static struct attribute *_name##_attr[] = { \
+ &event_attr_##_name.attr.attr, \
+ NULL \
+}; \
+ \
+static umode_t \
+_name##_is_visible(struct kobject *kobj, struct attribute *attr, int i) \
+{ \
+ struct device *dev = kobj_to_dev(kobj); \
+ struct iommu_pmu *iommu_pmu = dev_to_iommu_pmu(dev); \
+ \
+ if (!iommu_pmu) \
+ return 0; \
+ return (iommu_pmu->evcap[_g_idx] & _event) ? attr->mode : 0; \
+} \
+ \
+static struct attribute_group _name = { \
+ .name = "events", \
+ .attrs = _name##_attr, \
+ .is_visible = _name##_is_visible, \
+};
+
+IOMMU_PMU_EVENT_ATTR(iommu_clocks, "event_group=0x0,event=0x001", 0x0, 0x001)
+IOMMU_PMU_EVENT_ATTR(iommu_requests, "event_group=0x0,event=0x002", 0x0, 0x002)
+IOMMU_PMU_EVENT_ATTR(pw_occupancy, "event_group=0x0,event=0x004", 0x0, 0x004)
+IOMMU_PMU_EVENT_ATTR(ats_blocked, "event_group=0x0,event=0x008", 0x0, 0x008)
+IOMMU_PMU_EVENT_ATTR(iommu_mrds, "event_group=0x1,event=0x001", 0x1, 0x001)
+IOMMU_PMU_EVENT_ATTR(iommu_mem_blocked, "event_group=0x1,event=0x020", 0x1, 0x020)
+IOMMU_PMU_EVENT_ATTR(pg_req_posted, "event_group=0x1,event=0x040", 0x1, 0x040)
+IOMMU_PMU_EVENT_ATTR(ctxt_cache_lookup, "event_group=0x2,event=0x001", 0x2, 0x001)
+IOMMU_PMU_EVENT_ATTR(ctxt_cache_hit, "event_group=0x2,event=0x002", 0x2, 0x002)
+IOMMU_PMU_EVENT_ATTR(pasid_cache_lookup, "event_group=0x2,event=0x004", 0x2, 0x004)
+IOMMU_PMU_EVENT_ATTR(pasid_cache_hit, "event_group=0x2,event=0x008", 0x2, 0x008)
+IOMMU_PMU_EVENT_ATTR(ss_nonleaf_lookup, "event_group=0x2,event=0x010", 0x2, 0x010)
+IOMMU_PMU_EVENT_ATTR(ss_nonleaf_hit, "event_group=0x2,event=0x020", 0x2, 0x020)
+IOMMU_PMU_EVENT_ATTR(fs_nonleaf_lookup, "event_group=0x2,event=0x040", 0x2, 0x040)
+IOMMU_PMU_EVENT_ATTR(fs_nonleaf_hit, "event_group=0x2,event=0x080", 0x2, 0x080)
+IOMMU_PMU_EVENT_ATTR(hpt_nonleaf_lookup, "event_group=0x2,event=0x100", 0x2, 0x100)
+IOMMU_PMU_EVENT_ATTR(hpt_nonleaf_hit, "event_group=0x2,event=0x200", 0x2, 0x200)
+IOMMU_PMU_EVENT_ATTR(iotlb_lookup, "event_group=0x3,event=0x001", 0x3, 0x001)
+IOMMU_PMU_EVENT_ATTR(iotlb_hit, "event_group=0x3,event=0x002", 0x3, 0x002)
+IOMMU_PMU_EVENT_ATTR(hpt_leaf_lookup, "event_group=0x3,event=0x004", 0x3, 0x004)
+IOMMU_PMU_EVENT_ATTR(hpt_leaf_hit, "event_group=0x3,event=0x008", 0x3, 0x008)
+IOMMU_PMU_EVENT_ATTR(int_cache_lookup, "event_group=0x4,event=0x001", 0x4, 0x001)
+IOMMU_PMU_EVENT_ATTR(int_cache_hit_nonposted, "event_group=0x4,event=0x002", 0x4, 0x002)
+IOMMU_PMU_EVENT_ATTR(int_cache_hit_posted, "event_group=0x4,event=0x004", 0x4, 0x004)
+
+static const struct attribute_group *iommu_pmu_attr_update[] = {
+ &filter_requester_id_en,
+ &filter_domain_en,
+ &filter_pasid_en,
+ &filter_ats_en,
+ &filter_page_table_en,
+ &filter_requester_id,
+ &filter_domain,
+ &filter_pasid,
+ &filter_ats,
+ &filter_page_table,
+ &iommu_clocks,
+ &iommu_requests,
+ &pw_occupancy,
+ &ats_blocked,
+ &iommu_mrds,
+ &iommu_mem_blocked,
+ &pg_req_posted,
+ &ctxt_cache_lookup,
+ &ctxt_cache_hit,
+ &pasid_cache_lookup,
+ &pasid_cache_hit,
+ &ss_nonleaf_lookup,
+ &ss_nonleaf_hit,
+ &fs_nonleaf_lookup,
+ &fs_nonleaf_hit,
+ &hpt_nonleaf_lookup,
+ &hpt_nonleaf_hit,
+ &iotlb_lookup,
+ &iotlb_hit,
+ &hpt_leaf_lookup,
+ &hpt_leaf_hit,
+ &int_cache_lookup,
+ &int_cache_hit_nonposted,
+ &int_cache_hit_posted,
+ NULL
+};
+
+static inline void __iomem *
+iommu_event_base(struct iommu_pmu *iommu_pmu, int idx)
+{
+ return iommu_pmu->cntr_reg + idx * iommu_pmu->cntr_stride;
+}
+
+static inline void __iomem *
+iommu_config_base(struct iommu_pmu *iommu_pmu, int idx)
+{
+ return iommu_pmu->cfg_reg + idx * IOMMU_PMU_CFG_OFFSET;
+}
+
+static inline struct iommu_pmu *iommu_event_to_pmu(struct perf_event *event)
+{
+ return container_of(event->pmu, struct iommu_pmu, pmu);
+}
+
+static inline u64 iommu_event_config(struct perf_event *event)
+{
+ u64 config = event->attr.config;
+
+ return (iommu_event_select(config) << IOMMU_EVENT_CFG_ES_SHIFT) |
+ (iommu_event_group(config) << IOMMU_EVENT_CFG_EGI_SHIFT) |
+ IOMMU_EVENT_CFG_INT;
+}
+
+static inline bool is_iommu_pmu_event(struct iommu_pmu *iommu_pmu,
+ struct perf_event *event)
+{
+ return event->pmu == &iommu_pmu->pmu;
+}
+
+static int iommu_pmu_validate_event(struct perf_event *event)
+{
+ struct iommu_pmu *iommu_pmu = iommu_event_to_pmu(event);
+ u32 event_group = iommu_event_group(event->attr.config);
+
+ if (event_group >= iommu_pmu->num_eg)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int iommu_pmu_validate_group(struct perf_event *event)
+{
+ struct iommu_pmu *iommu_pmu = iommu_event_to_pmu(event);
+ struct perf_event *sibling;
+ int nr = 0;
+
+ /*
+ * All events in a group must be scheduled simultaneously.
+ * Check whether there is enough counters for all the events.
+ */
+ for_each_sibling_event(sibling, event->group_leader) {
+ if (!is_iommu_pmu_event(iommu_pmu, sibling) ||
+ sibling->state <= PERF_EVENT_STATE_OFF)
+ continue;
+
+ if (++nr > iommu_pmu->num_cntr)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int iommu_pmu_event_init(struct perf_event *event)
+{
+ struct hw_perf_event *hwc = &event->hw;
+
+ if (event->attr.type != event->pmu->type)
+ return -ENOENT;
+
+ /* sampling not supported */
+ if (event->attr.sample_period)
+ return -EINVAL;
+
+ if (event->cpu < 0)
+ return -EINVAL;
+
+ if (iommu_pmu_validate_event(event))
+ return -EINVAL;
+
+ hwc->config = iommu_event_config(event);
+
+ return iommu_pmu_validate_group(event);
+}
+
+static void iommu_pmu_event_update(struct perf_event *event)
+{
+ struct iommu_pmu *iommu_pmu = iommu_event_to_pmu(event);
+ struct hw_perf_event *hwc = &event->hw;
+ u64 prev_count, new_count, delta;
+ int shift = 64 - iommu_pmu->cntr_width;
+
+again:
+ prev_count = local64_read(&hwc->prev_count);
+ new_count = dmar_readq(iommu_event_base(iommu_pmu, hwc->idx));
+ if (local64_xchg(&hwc->prev_count, new_count) != prev_count)
+ goto again;
+
+ /*
+ * The counter width is enumerated. Always shift the counter
+ * before using it.
+ */
+ delta = (new_count << shift) - (prev_count << shift);
+ delta >>= shift;
+
+ local64_add(delta, &event->count);
+}
+
+static void iommu_pmu_start(struct perf_event *event, int flags)
+{
+ struct iommu_pmu *iommu_pmu = iommu_event_to_pmu(event);
+ struct intel_iommu *iommu = iommu_pmu->iommu;
+ struct hw_perf_event *hwc = &event->hw;
+ u64 count;
+
+ if (WARN_ON_ONCE(!(hwc->state & PERF_HES_STOPPED)))
+ return;
+
+ if (WARN_ON_ONCE(hwc->idx < 0 || hwc->idx >= IOMMU_PMU_IDX_MAX))
+ return;
+
+ if (flags & PERF_EF_RELOAD)
+ WARN_ON_ONCE(!(event->hw.state & PERF_HES_UPTODATE));
+
+ hwc->state = 0;
+
+ /* Always reprogram the period */
+ count = dmar_readq(iommu_event_base(iommu_pmu, hwc->idx));
+ local64_set((&hwc->prev_count), count);
+
+ /*
+ * The error of ecmd will be ignored.
+ * - The existing perf_event subsystem doesn't handle the error.
+ * Only IOMMU PMU returns runtime HW error. We don't want to
+ * change the existing generic interfaces for the specific case.
+ * - It's a corner case caused by HW, which is very unlikely to
+ * happen. There is nothing SW can do.
+ * - The worst case is that the user will get <not count> with
+ * perf command, which can give the user some hints.
+ */
+ ecmd_submit_sync(iommu, DMA_ECMD_ENABLE, hwc->idx, 0);
+
+ perf_event_update_userpage(event);
+}
+
+static void iommu_pmu_stop(struct perf_event *event, int flags)
+{
+ struct iommu_pmu *iommu_pmu = iommu_event_to_pmu(event);
+ struct intel_iommu *iommu = iommu_pmu->iommu;
+ struct hw_perf_event *hwc = &event->hw;
+
+ if (!(hwc->state & PERF_HES_STOPPED)) {
+ ecmd_submit_sync(iommu, DMA_ECMD_DISABLE, hwc->idx, 0);
+
+ iommu_pmu_event_update(event);
+
+ hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
+ }
+}
+
+static inline int
+iommu_pmu_validate_per_cntr_event(struct iommu_pmu *iommu_pmu,
+ int idx, struct perf_event *event)
+{
+ u32 event_group = iommu_event_group(event->attr.config);
+ u32 select = iommu_event_select(event->attr.config);
+
+ if (!(iommu_pmu->cntr_evcap[idx][event_group] & select))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int iommu_pmu_assign_event(struct iommu_pmu *iommu_pmu,
+ struct perf_event *event)
+{
+ struct hw_perf_event *hwc = &event->hw;
+ int idx;
+
+ /*
+ * The counters which support limited events are usually at the end.
+ * Schedule them first to accommodate more events.
+ */
+ for (idx = iommu_pmu->num_cntr - 1; idx >= 0; idx--) {
+ if (test_and_set_bit(idx, iommu_pmu->used_mask))
+ continue;
+ /* Check per-counter event capabilities */
+ if (!iommu_pmu_validate_per_cntr_event(iommu_pmu, idx, event))
+ break;
+ clear_bit(idx, iommu_pmu->used_mask);
+ }
+ if (idx < 0)
+ return -EINVAL;
+
+ iommu_pmu->event_list[idx] = event;
+ hwc->idx = idx;
+
+ /* config events */
+ dmar_writeq(iommu_config_base(iommu_pmu, idx), hwc->config);
+
+ iommu_pmu_set_filter(requester_id, event->attr.config1,
+ IOMMU_PMU_FILTER_REQUESTER_ID, idx,
+ event->attr.config1);
+ iommu_pmu_set_filter(domain, event->attr.config1,
+ IOMMU_PMU_FILTER_DOMAIN, idx,
+ event->attr.config1);
+ iommu_pmu_set_filter(pasid, event->attr.config1,
+ IOMMU_PMU_FILTER_PASID, idx,
+ event->attr.config1);
+ iommu_pmu_set_filter(ats, event->attr.config2,
+ IOMMU_PMU_FILTER_ATS, idx,
+ event->attr.config1);
+ iommu_pmu_set_filter(page_table, event->attr.config2,
+ IOMMU_PMU_FILTER_PAGE_TABLE, idx,
+ event->attr.config1);
+
+ return 0;
+}
+
+static int iommu_pmu_add(struct perf_event *event, int flags)
+{
+ struct iommu_pmu *iommu_pmu = iommu_event_to_pmu(event);
+ struct hw_perf_event *hwc = &event->hw;
+ int ret;
+
+ ret = iommu_pmu_assign_event(iommu_pmu, event);
+ if (ret < 0)
+ return ret;
+
+ hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+
+ if (flags & PERF_EF_START)
+ iommu_pmu_start(event, 0);
+
+ return 0;
+}
+
+static void iommu_pmu_del(struct perf_event *event, int flags)
+{
+ struct iommu_pmu *iommu_pmu = iommu_event_to_pmu(event);
+ int idx = event->hw.idx;
+
+ iommu_pmu_stop(event, PERF_EF_UPDATE);
+
+ iommu_pmu_clear_filter(IOMMU_PMU_FILTER_REQUESTER_ID, idx);
+ iommu_pmu_clear_filter(IOMMU_PMU_FILTER_DOMAIN, idx);
+ iommu_pmu_clear_filter(IOMMU_PMU_FILTER_PASID, idx);
+ iommu_pmu_clear_filter(IOMMU_PMU_FILTER_ATS, idx);
+ iommu_pmu_clear_filter(IOMMU_PMU_FILTER_PAGE_TABLE, idx);
+
+ iommu_pmu->event_list[idx] = NULL;
+ event->hw.idx = -1;
+ clear_bit(idx, iommu_pmu->used_mask);
+
+ perf_event_update_userpage(event);
+}
+
+static void iommu_pmu_enable(struct pmu *pmu)
+{
+ struct iommu_pmu *iommu_pmu = container_of(pmu, struct iommu_pmu, pmu);
+ struct intel_iommu *iommu = iommu_pmu->iommu;
+
+ ecmd_submit_sync(iommu, DMA_ECMD_UNFREEZE, 0, 0);
+}
+
+static void iommu_pmu_disable(struct pmu *pmu)
+{
+ struct iommu_pmu *iommu_pmu = container_of(pmu, struct iommu_pmu, pmu);
+ struct intel_iommu *iommu = iommu_pmu->iommu;
+
+ ecmd_submit_sync(iommu, DMA_ECMD_FREEZE, 0, 0);
+}
+
+static void iommu_pmu_counter_overflow(struct iommu_pmu *iommu_pmu)
+{
+ struct perf_event *event;
+ u64 status;
+ int i;
+
+ /*
+ * Two counters may be overflowed very close. Always check
+ * whether there are more to handle.
+ */
+ while ((status = dmar_readq(iommu_pmu->overflow))) {
+ for_each_set_bit(i, (unsigned long *)&status, iommu_pmu->num_cntr) {
+ /*
+ * Find the assigned event of the counter.
+ * Accumulate the value into the event->count.
+ */
+ event = iommu_pmu->event_list[i];
+ if (!event) {
+ pr_warn_once("Cannot find the assigned event for counter %d\n", i);
+ continue;
+ }
+ iommu_pmu_event_update(event);
+ }
+
+ dmar_writeq(iommu_pmu->overflow, status);
+ }
+}
+
+static irqreturn_t iommu_pmu_irq_handler(int irq, void *dev_id)
+{
+ struct intel_iommu *iommu = dev_id;
+
+ if (!dmar_readl(iommu->reg + DMAR_PERFINTRSTS_REG))
+ return IRQ_NONE;
+
+ iommu_pmu_counter_overflow(iommu->pmu);
+
+ /* Clear the status bit */
+ dmar_writel(iommu->reg + DMAR_PERFINTRSTS_REG, DMA_PERFINTRSTS_PIS);
+
+ return IRQ_HANDLED;
+}
+
+static int __iommu_pmu_register(struct intel_iommu *iommu)
+{
+ struct iommu_pmu *iommu_pmu = iommu->pmu;
+
+ iommu_pmu->pmu.name = iommu->name;
+ iommu_pmu->pmu.task_ctx_nr = perf_invalid_context;
+ iommu_pmu->pmu.event_init = iommu_pmu_event_init;
+ iommu_pmu->pmu.pmu_enable = iommu_pmu_enable;
+ iommu_pmu->pmu.pmu_disable = iommu_pmu_disable;
+ iommu_pmu->pmu.add = iommu_pmu_add;
+ iommu_pmu->pmu.del = iommu_pmu_del;
+ iommu_pmu->pmu.start = iommu_pmu_start;
+ iommu_pmu->pmu.stop = iommu_pmu_stop;
+ iommu_pmu->pmu.read = iommu_pmu_event_update;
+ iommu_pmu->pmu.attr_groups = iommu_pmu_attr_groups;
+ iommu_pmu->pmu.attr_update = iommu_pmu_attr_update;
+ iommu_pmu->pmu.capabilities = PERF_PMU_CAP_NO_EXCLUDE;
+ iommu_pmu->pmu.module = THIS_MODULE;
+
+ return perf_pmu_register(&iommu_pmu->pmu, iommu_pmu->pmu.name, -1);
+}
+
+static inline void __iomem *
+get_perf_reg_address(struct intel_iommu *iommu, u32 offset)
+{
+ u32 off = dmar_readl(iommu->reg + offset);
+
+ return iommu->reg + off;
+}
+
+int alloc_iommu_pmu(struct intel_iommu *iommu)
+{
+ struct iommu_pmu *iommu_pmu;
+ int i, j, ret;
+ u64 perfcap;
+ u32 cap;
+
+ if (!ecap_pms(iommu->ecap))
+ return 0;
+
+ /* The IOMMU PMU requires the ECMD support as well */
+ if (!cap_ecmds(iommu->cap))
+ return -ENODEV;
+
+ perfcap = dmar_readq(iommu->reg + DMAR_PERFCAP_REG);
+ /* The performance monitoring is not supported. */
+ if (!perfcap)
+ return -ENODEV;
+
+ /* Sanity check for the number of the counters and event groups */
+ if (!pcap_num_cntr(perfcap) || !pcap_num_event_group(perfcap))
+ return -ENODEV;
+
+ /* The interrupt on overflow is required */
+ if (!pcap_interrupt(perfcap))
+ return -ENODEV;
+
+ /* Check required Enhanced Command Capability */
+ if (!ecmd_has_pmu_essential(iommu))
+ return -ENODEV;
+
+ iommu_pmu = kzalloc(sizeof(*iommu_pmu), GFP_KERNEL);
+ if (!iommu_pmu)
+ return -ENOMEM;
+
+ iommu_pmu->num_cntr = pcap_num_cntr(perfcap);
+ if (iommu_pmu->num_cntr > IOMMU_PMU_IDX_MAX) {
+ pr_warn_once("The number of IOMMU counters %d > max(%d), clipping!",
+ iommu_pmu->num_cntr, IOMMU_PMU_IDX_MAX);
+ iommu_pmu->num_cntr = IOMMU_PMU_IDX_MAX;
+ }
+
+ iommu_pmu->cntr_width = pcap_cntr_width(perfcap);
+ iommu_pmu->filter = pcap_filters_mask(perfcap);
+ iommu_pmu->cntr_stride = pcap_cntr_stride(perfcap);
+ iommu_pmu->num_eg = pcap_num_event_group(perfcap);
+
+ iommu_pmu->evcap = kcalloc(iommu_pmu->num_eg, sizeof(u64), GFP_KERNEL);
+ if (!iommu_pmu->evcap) {
+ ret = -ENOMEM;
+ goto free_pmu;
+ }
+
+ /* Parse event group capabilities */
+ for (i = 0; i < iommu_pmu->num_eg; i++) {
+ u64 pcap;
+
+ pcap = dmar_readq(iommu->reg + DMAR_PERFEVNTCAP_REG +
+ i * IOMMU_PMU_CAP_REGS_STEP);
+ iommu_pmu->evcap[i] = pecap_es(pcap);
+ }
+
+ iommu_pmu->cntr_evcap = kcalloc(iommu_pmu->num_cntr, sizeof(u32 *), GFP_KERNEL);
+ if (!iommu_pmu->cntr_evcap) {
+ ret = -ENOMEM;
+ goto free_pmu_evcap;
+ }
+ for (i = 0; i < iommu_pmu->num_cntr; i++) {
+ iommu_pmu->cntr_evcap[i] = kcalloc(iommu_pmu->num_eg, sizeof(u32), GFP_KERNEL);
+ if (!iommu_pmu->cntr_evcap[i]) {
+ ret = -ENOMEM;
+ goto free_pmu_cntr_evcap;
+ }
+ /*
+ * Set to the global capabilities, will adjust according
+ * to per-counter capabilities later.
+ */
+ for (j = 0; j < iommu_pmu->num_eg; j++)
+ iommu_pmu->cntr_evcap[i][j] = (u32)iommu_pmu->evcap[j];
+ }
+
+ iommu_pmu->cfg_reg = get_perf_reg_address(iommu, DMAR_PERFCFGOFF_REG);
+ iommu_pmu->cntr_reg = get_perf_reg_address(iommu, DMAR_PERFCNTROFF_REG);
+ iommu_pmu->overflow = get_perf_reg_address(iommu, DMAR_PERFOVFOFF_REG);
+
+ /*
+ * Check per-counter capabilities. All counters should have the
+ * same capabilities on Interrupt on Overflow Support and Counter
+ * Width.
+ */
+ for (i = 0; i < iommu_pmu->num_cntr; i++) {
+ cap = dmar_readl(iommu_pmu->cfg_reg +
+ i * IOMMU_PMU_CFG_OFFSET +
+ IOMMU_PMU_CFG_CNTRCAP_OFFSET);
+ if (!iommu_cntrcap_pcc(cap))
+ continue;
+
+ /*
+ * It's possible that some counters have a different
+ * capability because of e.g., HW bug. Check the corner
+ * case here and simply drop those counters.
+ */
+ if ((iommu_cntrcap_cw(cap) != iommu_pmu->cntr_width) ||
+ !iommu_cntrcap_ios(cap)) {
+ iommu_pmu->num_cntr = i;
+ pr_warn("PMU counter capability inconsistent, counter number reduced to %d\n",
+ iommu_pmu->num_cntr);
+ }
+
+ /* Clear the pre-defined events group */
+ for (j = 0; j < iommu_pmu->num_eg; j++)
+ iommu_pmu->cntr_evcap[i][j] = 0;
+
+ /* Override with per-counter event capabilities */
+ for (j = 0; j < iommu_cntrcap_egcnt(cap); j++) {
+ cap = dmar_readl(iommu_pmu->cfg_reg + i * IOMMU_PMU_CFG_OFFSET +
+ IOMMU_PMU_CFG_CNTREVCAP_OFFSET +
+ (j * IOMMU_PMU_OFF_REGS_STEP));
+ iommu_pmu->cntr_evcap[i][iommu_event_group(cap)] = iommu_event_select(cap);
+ /*
+ * Some events may only be supported by a specific counter.
+ * Track them in the evcap as well.
+ */
+ iommu_pmu->evcap[iommu_event_group(cap)] |= iommu_event_select(cap);
+ }
+ }
+
+ iommu_pmu->iommu = iommu;
+ iommu->pmu = iommu_pmu;
+
+ return 0;
+
+free_pmu_cntr_evcap:
+ for (i = 0; i < iommu_pmu->num_cntr; i++)
+ kfree(iommu_pmu->cntr_evcap[i]);
+ kfree(iommu_pmu->cntr_evcap);
+free_pmu_evcap:
+ kfree(iommu_pmu->evcap);
+free_pmu:
+ kfree(iommu_pmu);
+
+ return ret;
+}
+
+void free_iommu_pmu(struct intel_iommu *iommu)
+{
+ struct iommu_pmu *iommu_pmu = iommu->pmu;
+
+ if (!iommu_pmu)
+ return;
+
+ if (iommu_pmu->evcap) {
+ int i;
+
+ for (i = 0; i < iommu_pmu->num_cntr; i++)
+ kfree(iommu_pmu->cntr_evcap[i]);
+ kfree(iommu_pmu->cntr_evcap);
+ }
+ kfree(iommu_pmu->evcap);
+ kfree(iommu_pmu);
+ iommu->pmu = NULL;
+}
+
+static int iommu_pmu_set_interrupt(struct intel_iommu *iommu)
+{
+ struct iommu_pmu *iommu_pmu = iommu->pmu;
+ int irq, ret;
+
+ irq = dmar_alloc_hwirq(IOMMU_IRQ_ID_OFFSET_PERF + iommu->seq_id, iommu->node, iommu);
+ if (irq <= 0)
+ return -EINVAL;
+
+ snprintf(iommu_pmu->irq_name, sizeof(iommu_pmu->irq_name), "dmar%d-perf", iommu->seq_id);
+
+ iommu->perf_irq = irq;
+ ret = request_threaded_irq(irq, NULL, iommu_pmu_irq_handler,
+ IRQF_ONESHOT, iommu_pmu->irq_name, iommu);
+ if (ret) {
+ dmar_free_hwirq(irq);
+ iommu->perf_irq = 0;
+ return ret;
+ }
+ return 0;
+}
+
+static void iommu_pmu_unset_interrupt(struct intel_iommu *iommu)
+{
+ if (!iommu->perf_irq)
+ return;
+
+ free_irq(iommu->perf_irq, iommu);
+ dmar_free_hwirq(iommu->perf_irq);
+ iommu->perf_irq = 0;
+}
+
+static int iommu_pmu_cpu_online(unsigned int cpu)
+{
+ if (cpumask_empty(&iommu_pmu_cpu_mask))
+ cpumask_set_cpu(cpu, &iommu_pmu_cpu_mask);
+
+ return 0;
+}
+
+static int iommu_pmu_cpu_offline(unsigned int cpu)
+{
+ struct dmar_drhd_unit *drhd;
+ struct intel_iommu *iommu;
+ int target;
+
+ if (!cpumask_test_and_clear_cpu(cpu, &iommu_pmu_cpu_mask))
+ return 0;
+
+ target = cpumask_any_but(cpu_online_mask, cpu);
+
+ if (target < nr_cpu_ids)
+ cpumask_set_cpu(target, &iommu_pmu_cpu_mask);
+ else
+ target = -1;
+
+ rcu_read_lock();
+
+ for_each_iommu(iommu, drhd) {
+ if (!iommu->pmu)
+ continue;
+ perf_pmu_migrate_context(&iommu->pmu->pmu, cpu, target);
+ }
+ rcu_read_unlock();
+
+ return 0;
+}
+
+static int nr_iommu_pmu;
+
+static int iommu_pmu_cpuhp_setup(struct iommu_pmu *iommu_pmu)
+{
+ int ret;
+
+ if (nr_iommu_pmu++)
+ return 0;
+
+ ret = cpuhp_setup_state(CPUHP_AP_PERF_X86_IOMMU_PERF_ONLINE,
+ "driver/iommu/intel/perfmon:online",
+ iommu_pmu_cpu_online,
+ iommu_pmu_cpu_offline);
+ if (ret)
+ nr_iommu_pmu = 0;
+
+ return ret;
+}
+
+static void iommu_pmu_cpuhp_free(struct iommu_pmu *iommu_pmu)
+{
+ if (--nr_iommu_pmu)
+ return;
+
+ cpuhp_remove_state(CPUHP_AP_PERF_X86_IOMMU_PERF_ONLINE);
+}
+
+void iommu_pmu_register(struct intel_iommu *iommu)
+{
+ struct iommu_pmu *iommu_pmu = iommu->pmu;
+
+ if (!iommu_pmu)
+ return;
+
+ if (__iommu_pmu_register(iommu))
+ goto err;
+
+ if (iommu_pmu_cpuhp_setup(iommu_pmu))
+ goto unregister;
+
+ /* Set interrupt for overflow */
+ if (iommu_pmu_set_interrupt(iommu))
+ goto cpuhp_free;
+
+ return;
+
+cpuhp_free:
+ iommu_pmu_cpuhp_free(iommu_pmu);
+unregister:
+ perf_pmu_unregister(&iommu_pmu->pmu);
+err:
+ pr_err("Failed to register PMU for iommu (seq_id = %d)\n", iommu->seq_id);
+ free_iommu_pmu(iommu);
+}
+
+void iommu_pmu_unregister(struct intel_iommu *iommu)
+{
+ struct iommu_pmu *iommu_pmu = iommu->pmu;
+
+ if (!iommu_pmu)
+ return;
+
+ iommu_pmu_unset_interrupt(iommu);
+ iommu_pmu_cpuhp_free(iommu_pmu);
+ perf_pmu_unregister(&iommu_pmu->pmu);
+}
diff --git a/drivers/iommu/intel/perfmon.h b/drivers/iommu/intel/perfmon.h
new file mode 100644
index 000000000000..58606af9a2b9
--- /dev/null
+++ b/drivers/iommu/intel/perfmon.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * PERFCFGOFF_REG, PERFFRZOFF_REG
+ * PERFOVFOFF_REG, PERFCNTROFF_REG
+ */
+#define IOMMU_PMU_NUM_OFF_REGS 4
+#define IOMMU_PMU_OFF_REGS_STEP 4
+
+#define IOMMU_PMU_FILTER_REQUESTER_ID 0x01
+#define IOMMU_PMU_FILTER_DOMAIN 0x02
+#define IOMMU_PMU_FILTER_PASID 0x04
+#define IOMMU_PMU_FILTER_ATS 0x08
+#define IOMMU_PMU_FILTER_PAGE_TABLE 0x10
+
+#define IOMMU_PMU_FILTER_EN BIT(31)
+
+#define IOMMU_PMU_CFG_OFFSET 0x100
+#define IOMMU_PMU_CFG_CNTRCAP_OFFSET 0x80
+#define IOMMU_PMU_CFG_CNTREVCAP_OFFSET 0x84
+#define IOMMU_PMU_CFG_SIZE 0x8
+#define IOMMU_PMU_CFG_FILTERS_OFFSET 0x4
+
+#define IOMMU_PMU_CAP_REGS_STEP 8
+
+#define iommu_cntrcap_pcc(p) ((p) & 0x1)
+#define iommu_cntrcap_cw(p) (((p) >> 8) & 0xff)
+#define iommu_cntrcap_ios(p) (((p) >> 16) & 0x1)
+#define iommu_cntrcap_egcnt(p) (((p) >> 28) & 0xf)
+
+#define IOMMU_EVENT_CFG_EGI_SHIFT 8
+#define IOMMU_EVENT_CFG_ES_SHIFT 32
+#define IOMMU_EVENT_CFG_INT BIT_ULL(1)
+
+#define iommu_event_select(p) ((p) & 0xfffffff)
+#define iommu_event_group(p) (((p) >> 28) & 0xf)
+
+#ifdef CONFIG_INTEL_IOMMU_PERF_EVENTS
+int alloc_iommu_pmu(struct intel_iommu *iommu);
+void free_iommu_pmu(struct intel_iommu *iommu);
+void iommu_pmu_register(struct intel_iommu *iommu);
+void iommu_pmu_unregister(struct intel_iommu *iommu);
+#else
+static inline int
+alloc_iommu_pmu(struct intel_iommu *iommu)
+{
+ return 0;
+}
+
+static inline void
+free_iommu_pmu(struct intel_iommu *iommu)
+{
+}
+
+static inline void
+iommu_pmu_register(struct intel_iommu *iommu)
+{
+}
+
+static inline void
+iommu_pmu_unregister(struct intel_iommu *iommu)
+{
+}
+#endif /* CONFIG_INTEL_IOMMU_PERF_EVENTS */
diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
index c76b66263467..7367f56c3bad 100644
--- a/drivers/iommu/intel/svm.c
+++ b/drivers/iommu/intel/svm.c
@@ -9,7 +9,6 @@
#include <linux/sched.h>
#include <linux/sched/mm.h>
#include <linux/slab.h>
-#include <linux/intel-svm.h>
#include <linux/rculist.h>
#include <linux/pci.h>
#include <linux/pci-ats.h>
@@ -79,7 +78,7 @@ int intel_svm_enable_prq(struct intel_iommu *iommu)
}
iommu->prq = page_address(pages);
- irq = dmar_alloc_hwirq(DMAR_UNITS_SUPPORTED + iommu->seq_id, iommu->node, iommu);
+ irq = dmar_alloc_hwirq(IOMMU_IRQ_ID_OFFSET_PRQ + iommu->seq_id, iommu->node, iommu);
if (irq <= 0) {
pr_err("IOMMU: %s: Failed to create IRQ vector for page request queue\n",
iommu->name);
@@ -299,9 +298,8 @@ out:
return 0;
}
-static struct iommu_sva *intel_svm_bind_mm(struct intel_iommu *iommu,
- struct device *dev,
- struct mm_struct *mm)
+static int intel_svm_bind_mm(struct intel_iommu *iommu, struct device *dev,
+ struct mm_struct *mm)
{
struct device_domain_info *info = dev_iommu_priv_get(dev);
struct intel_svm_dev *sdev;
@@ -313,7 +311,7 @@ static struct iommu_sva *intel_svm_bind_mm(struct intel_iommu *iommu,
if (!svm) {
svm = kzalloc(sizeof(*svm), GFP_KERNEL);
if (!svm)
- return ERR_PTR(-ENOMEM);
+ return -ENOMEM;
svm->pasid = mm->pasid;
svm->mm = mm;
@@ -323,24 +321,17 @@ static struct iommu_sva *intel_svm_bind_mm(struct intel_iommu *iommu,
ret = mmu_notifier_register(&svm->notifier, mm);
if (ret) {
kfree(svm);
- return ERR_PTR(ret);
+ return ret;
}
ret = pasid_private_add(svm->pasid, svm);
if (ret) {
mmu_notifier_unregister(&svm->notifier, mm);
kfree(svm);
- return ERR_PTR(ret);
+ return ret;
}
}
- /* Find the matching device in svm list */
- sdev = svm_lookup_device_by_dev(svm, dev);
- if (sdev) {
- sdev->users++;
- goto success;
- }
-
sdev = kzalloc(sizeof(*sdev), GFP_KERNEL);
if (!sdev) {
ret = -ENOMEM;
@@ -351,12 +342,8 @@ static struct iommu_sva *intel_svm_bind_mm(struct intel_iommu *iommu,
sdev->iommu = iommu;
sdev->did = FLPT_DEFAULT_DID;
sdev->sid = PCI_DEVID(info->bus, info->devfn);
- sdev->users = 1;
- sdev->pasid = svm->pasid;
- sdev->sva.dev = dev;
init_rcu_head(&sdev->rcu);
if (info->ats_enabled) {
- sdev->dev_iotlb = 1;
sdev->qdep = info->ats_qdep;
if (sdev->qdep >= QI_DEV_EIOTLB_MAX_INVS)
sdev->qdep = 0;
@@ -370,8 +357,8 @@ static struct iommu_sva *intel_svm_bind_mm(struct intel_iommu *iommu,
goto free_sdev;
list_add_rcu(&sdev->list, &svm->devs);
-success:
- return &sdev->sva;
+
+ return 0;
free_sdev:
kfree(sdev);
@@ -382,7 +369,7 @@ free_svm:
kfree(svm);
}
- return ERR_PTR(ret);
+ return ret;
}
/* Caller must hold pasid_mutex */
@@ -404,32 +391,32 @@ static int intel_svm_unbind_mm(struct device *dev, u32 pasid)
mm = svm->mm;
if (sdev) {
- sdev->users--;
- if (!sdev->users) {
- list_del_rcu(&sdev->list);
- /* Flush the PASID cache and IOTLB for this device.
- * Note that we do depend on the hardware *not* using
- * the PASID any more. Just as we depend on other
- * devices never using PASIDs that they have no right
- * to use. We have a *shared* PASID table, because it's
- * large and has to be physically contiguous. So it's
- * hard to be as defensive as we might like. */
- intel_pasid_tear_down_entry(iommu, dev,
- svm->pasid, false);
- intel_svm_drain_prq(dev, svm->pasid);
- kfree_rcu(sdev, rcu);
-
- if (list_empty(&svm->devs)) {
- if (svm->notifier.ops)
- mmu_notifier_unregister(&svm->notifier, mm);
- pasid_private_remove(svm->pasid);
- /* We mandate that no page faults may be outstanding
- * for the PASID when intel_svm_unbind_mm() is called.
- * If that is not obeyed, subtle errors will happen.
- * Let's make them less subtle... */
- memset(svm, 0x6b, sizeof(*svm));
- kfree(svm);
- }
+ list_del_rcu(&sdev->list);
+ /*
+ * Flush the PASID cache and IOTLB for this device.
+ * Note that we do depend on the hardware *not* using
+ * the PASID any more. Just as we depend on other
+ * devices never using PASIDs that they have no right
+ * to use. We have a *shared* PASID table, because it's
+ * large and has to be physically contiguous. So it's
+ * hard to be as defensive as we might like.
+ */
+ intel_pasid_tear_down_entry(iommu, dev, svm->pasid, false);
+ intel_svm_drain_prq(dev, svm->pasid);
+ kfree_rcu(sdev, rcu);
+
+ if (list_empty(&svm->devs)) {
+ if (svm->notifier.ops)
+ mmu_notifier_unregister(&svm->notifier, mm);
+ pasid_private_remove(svm->pasid);
+ /*
+ * We mandate that no page faults may be outstanding
+ * for the PASID when intel_svm_unbind_mm() is called.
+ * If that is not obeyed, subtle errors will happen.
+ * Let's make them less subtle...
+ */
+ memset(svm, 0x6b, sizeof(*svm));
+ kfree(svm);
}
}
out:
@@ -854,13 +841,10 @@ static int intel_svm_set_dev_pasid(struct iommu_domain *domain,
struct device_domain_info *info = dev_iommu_priv_get(dev);
struct intel_iommu *iommu = info->iommu;
struct mm_struct *mm = domain->mm;
- struct iommu_sva *sva;
- int ret = 0;
+ int ret;
mutex_lock(&pasid_mutex);
- sva = intel_svm_bind_mm(iommu, dev, mm);
- if (IS_ERR(sva))
- ret = PTR_ERR(sva);
+ ret = intel_svm_bind_mm(iommu, dev, mm);
mutex_unlock(&pasid_mutex);
return ret;
diff --git a/drivers/iommu/iommu-traces.c b/drivers/iommu/iommu-traces.c
index 1e9ca7789de1..23416bf76df9 100644
--- a/drivers/iommu/iommu-traces.c
+++ b/drivers/iommu/iommu-traces.c
@@ -18,7 +18,6 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(remove_device_from_group);
/* iommu_device_event */
EXPORT_TRACEPOINT_SYMBOL_GPL(attach_device_to_domain);
-EXPORT_TRACEPOINT_SYMBOL_GPL(detach_device_from_domain);
/* iommu_map_unmap */
EXPORT_TRACEPOINT_SYMBOL_GPL(map);
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 5f6a85aea501..10db680acaed 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -30,6 +30,7 @@
#include <linux/cc_platform.h>
#include <trace/events/iommu.h>
#include <linux/sched/mm.h>
+#include <linux/msi.h>
#include "dma-iommu.h"
@@ -371,6 +372,30 @@ err_unlock:
return ret;
}
+static bool iommu_is_attach_deferred(struct device *dev)
+{
+ const struct iommu_ops *ops = dev_iommu_ops(dev);
+
+ if (ops->is_attach_deferred)
+ return ops->is_attach_deferred(dev);
+
+ return false;
+}
+
+static int iommu_group_do_dma_first_attach(struct device *dev, void *data)
+{
+ struct iommu_domain *domain = data;
+
+ lockdep_assert_held(&dev->iommu_group->mutex);
+
+ if (iommu_is_attach_deferred(dev)) {
+ dev->iommu->attach_deferred = 1;
+ return 0;
+ }
+
+ return __iommu_attach_device(domain, dev);
+}
+
int iommu_probe_device(struct device *dev)
{
const struct iommu_ops *ops;
@@ -401,7 +426,7 @@ int iommu_probe_device(struct device *dev)
* attach the default domain.
*/
if (group->default_domain && !group->owner) {
- ret = __iommu_attach_device(group->default_domain, dev);
+ ret = iommu_group_do_dma_first_attach(dev, group->default_domain);
if (ret) {
mutex_unlock(&group->mutex);
iommu_group_put(group);
@@ -774,12 +799,16 @@ struct iommu_group *iommu_group_alloc(void)
ret = iommu_group_create_file(group,
&iommu_group_attr_reserved_regions);
- if (ret)
+ if (ret) {
+ kobject_put(group->devices_kobj);
return ERR_PTR(ret);
+ }
ret = iommu_group_create_file(group, &iommu_group_attr_type);
- if (ret)
+ if (ret) {
+ kobject_put(group->devices_kobj);
return ERR_PTR(ret);
+ }
pr_debug("Allocated group %d\n", group->id);
@@ -930,7 +959,7 @@ map_end:
if (map_size) {
ret = iommu_map(domain, addr - map_size,
addr - map_size, map_size,
- entry->prot);
+ entry->prot, GFP_KERNEL);
if (ret)
goto out;
map_size = 0;
@@ -947,16 +976,6 @@ out:
return ret;
}
-static bool iommu_is_attach_deferred(struct device *dev)
-{
- const struct iommu_ops *ops = dev_iommu_ops(dev);
-
- if (ops->is_attach_deferred)
- return ops->is_attach_deferred(dev);
-
- return false;
-}
-
/**
* iommu_group_add_device - add a device to an iommu group
* @group: the group into which to add the device (reference should be held)
@@ -1009,8 +1028,8 @@ rename:
mutex_lock(&group->mutex);
list_add_tail(&device->list, &group->devices);
- if (group->domain && !iommu_is_attach_deferred(dev))
- ret = __iommu_attach_device(group->domain, dev);
+ if (group->domain)
+ ret = iommu_group_do_dma_first_attach(dev, group->domain);
mutex_unlock(&group->mutex);
if (ret)
goto err_put_group;
@@ -1776,21 +1795,10 @@ static void probe_alloc_default_domain(struct bus_type *bus,
}
-static int iommu_group_do_dma_attach(struct device *dev, void *data)
-{
- struct iommu_domain *domain = data;
- int ret = 0;
-
- if (!iommu_is_attach_deferred(dev))
- ret = __iommu_attach_device(domain, dev);
-
- return ret;
-}
-
-static int __iommu_group_dma_attach(struct iommu_group *group)
+static int __iommu_group_dma_first_attach(struct iommu_group *group)
{
return __iommu_group_for_each_dev(group, group->default_domain,
- iommu_group_do_dma_attach);
+ iommu_group_do_dma_first_attach);
}
static int iommu_group_do_probe_finalize(struct device *dev, void *data)
@@ -1855,7 +1863,7 @@ int bus_iommu_probe(struct bus_type *bus)
iommu_group_create_direct_mappings(group);
- ret = __iommu_group_dma_attach(group);
+ ret = __iommu_group_dma_first_attach(group);
mutex_unlock(&group->mutex);
@@ -1898,6 +1906,29 @@ bool device_iommu_capable(struct device *dev, enum iommu_cap cap)
EXPORT_SYMBOL_GPL(device_iommu_capable);
/**
+ * iommu_group_has_isolated_msi() - Compute msi_device_has_isolated_msi()
+ * for a group
+ * @group: Group to query
+ *
+ * IOMMU groups should not have differing values of
+ * msi_device_has_isolated_msi() for devices in a group. However nothing
+ * directly prevents this, so ensure mistakes don't result in isolation failures
+ * by checking that all the devices are the same.
+ */
+bool iommu_group_has_isolated_msi(struct iommu_group *group)
+{
+ struct group_device *group_dev;
+ bool ret = true;
+
+ mutex_lock(&group->mutex);
+ list_for_each_entry(group_dev, &group->devices, list)
+ ret &= msi_device_has_isolated_msi(group_dev->dev);
+ mutex_unlock(&group->mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(iommu_group_has_isolated_msi);
+
+/**
* iommu_set_fault_handler() - set a fault handler for an iommu domain
* @domain: iommu domain
* @handler: fault handler
@@ -1987,9 +2018,11 @@ static int __iommu_attach_device(struct iommu_domain *domain,
return -ENODEV;
ret = domain->ops->attach_dev(domain, dev);
- if (!ret)
- trace_attach_device_to_domain(dev);
- return ret;
+ if (ret)
+ return ret;
+ dev->iommu->attach_deferred = 0;
+ trace_attach_device_to_domain(dev);
+ return 0;
}
/**
@@ -2034,22 +2067,12 @@ EXPORT_SYMBOL_GPL(iommu_attach_device);
int iommu_deferred_attach(struct device *dev, struct iommu_domain *domain)
{
- if (iommu_is_attach_deferred(dev))
+ if (dev->iommu && dev->iommu->attach_deferred)
return __iommu_attach_device(domain, dev);
return 0;
}
-static void __iommu_detach_device(struct iommu_domain *domain,
- struct device *dev)
-{
- if (iommu_is_attach_deferred(dev))
- return;
-
- domain->ops->detach_dev(domain, dev);
- trace_detach_device_from_domain(dev);
-}
-
void iommu_detach_device(struct iommu_domain *domain, struct device *dev)
{
struct iommu_group *group;
@@ -2124,8 +2147,22 @@ static int __iommu_attach_group(struct iommu_domain *domain,
ret = __iommu_group_for_each_dev(group, domain,
iommu_group_do_attach_device);
- if (ret == 0)
+ if (ret == 0) {
group->domain = domain;
+ } else {
+ /*
+ * To recover from the case when certain device within the
+ * group fails to attach to the new domain, we need force
+ * attaching all devices back to the old domain. The old
+ * domain is compatible for all devices in the group,
+ * hence the iommu driver should always return success.
+ */
+ struct iommu_domain *old_domain = group->domain;
+
+ group->domain = NULL;
+ WARN(__iommu_group_set_domain(group, old_domain),
+ "iommu driver failed to attach a compatible domain");
+ }
return ret;
}
@@ -2154,11 +2191,12 @@ int iommu_attach_group(struct iommu_domain *domain, struct iommu_group *group)
}
EXPORT_SYMBOL_GPL(iommu_attach_group);
-static int iommu_group_do_detach_device(struct device *dev, void *data)
+static int iommu_group_do_set_platform_dma(struct device *dev, void *data)
{
- struct iommu_domain *domain = data;
+ const struct iommu_ops *ops = dev_iommu_ops(dev);
- __iommu_detach_device(domain, dev);
+ if (!WARN_ON(!ops->set_platform_dma_ops))
+ ops->set_platform_dma_ops(dev);
return 0;
}
@@ -2172,15 +2210,13 @@ static int __iommu_group_set_domain(struct iommu_group *group,
return 0;
/*
- * New drivers should support default domains and so the detach_dev() op
- * will never be called. Otherwise the NULL domain represents some
+ * New drivers should support default domains, so set_platform_dma()
+ * op will never be called. Otherwise the NULL domain represents some
* platform specific behavior.
*/
if (!new_domain) {
- if (WARN_ON(!group->domain->ops->detach_dev))
- return -EINVAL;
- __iommu_group_for_each_dev(group, group->domain,
- iommu_group_do_detach_device);
+ __iommu_group_for_each_dev(group, NULL,
+ iommu_group_do_set_platform_dma);
group->domain = NULL;
return 0;
}
@@ -2360,34 +2396,27 @@ static int __iommu_map(struct iommu_domain *domain, unsigned long iova,
return ret;
}
-static int _iommu_map(struct iommu_domain *domain, unsigned long iova,
- phys_addr_t paddr, size_t size, int prot, gfp_t gfp)
+int iommu_map(struct iommu_domain *domain, unsigned long iova,
+ phys_addr_t paddr, size_t size, int prot, gfp_t gfp)
{
const struct iommu_domain_ops *ops = domain->ops;
int ret;
+ might_sleep_if(gfpflags_allow_blocking(gfp));
+
+ /* Discourage passing strange GFP flags */
+ if (WARN_ON_ONCE(gfp & (__GFP_COMP | __GFP_DMA | __GFP_DMA32 |
+ __GFP_HIGHMEM)))
+ return -EINVAL;
+
ret = __iommu_map(domain, iova, paddr, size, prot, gfp);
if (ret == 0 && ops->iotlb_sync_map)
ops->iotlb_sync_map(domain, iova, size);
return ret;
}
-
-int iommu_map(struct iommu_domain *domain, unsigned long iova,
- phys_addr_t paddr, size_t size, int prot)
-{
- might_sleep();
- return _iommu_map(domain, iova, paddr, size, prot, GFP_KERNEL);
-}
EXPORT_SYMBOL_GPL(iommu_map);
-int iommu_map_atomic(struct iommu_domain *domain, unsigned long iova,
- phys_addr_t paddr, size_t size, int prot)
-{
- return _iommu_map(domain, iova, paddr, size, prot, GFP_ATOMIC);
-}
-EXPORT_SYMBOL_GPL(iommu_map_atomic);
-
static size_t __iommu_unmap_pages(struct iommu_domain *domain,
unsigned long iova, size_t size,
struct iommu_iotlb_gather *iotlb_gather)
@@ -2477,9 +2506,9 @@ size_t iommu_unmap_fast(struct iommu_domain *domain,
}
EXPORT_SYMBOL_GPL(iommu_unmap_fast);
-static ssize_t __iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
- struct scatterlist *sg, unsigned int nents, int prot,
- gfp_t gfp)
+ssize_t iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
+ struct scatterlist *sg, unsigned int nents, int prot,
+ gfp_t gfp)
{
const struct iommu_domain_ops *ops = domain->ops;
size_t len = 0, mapped = 0;
@@ -2487,6 +2516,13 @@ static ssize_t __iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
unsigned int i = 0;
int ret;
+ might_sleep_if(gfpflags_allow_blocking(gfp));
+
+ /* Discourage passing strange GFP flags */
+ if (WARN_ON_ONCE(gfp & (__GFP_COMP | __GFP_DMA | __GFP_DMA32 |
+ __GFP_HIGHMEM)))
+ return -EINVAL;
+
while (i <= nents) {
phys_addr_t s_phys = sg_phys(sg);
@@ -2526,21 +2562,8 @@ out_err:
return ret;
}
-
-ssize_t iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
- struct scatterlist *sg, unsigned int nents, int prot)
-{
- might_sleep();
- return __iommu_map_sg(domain, iova, sg, nents, prot, GFP_KERNEL);
-}
EXPORT_SYMBOL_GPL(iommu_map_sg);
-ssize_t iommu_map_sg_atomic(struct iommu_domain *domain, unsigned long iova,
- struct scatterlist *sg, unsigned int nents, int prot)
-{
- return __iommu_map_sg(domain, iova, sg, nents, prot, GFP_ATOMIC);
-}
-
/**
* report_iommu_fault() - report about an IOMMU fault to the IOMMU framework
* @domain: the iommu domain where the fault has happened
diff --git a/drivers/iommu/iommufd/Kconfig b/drivers/iommu/iommufd/Kconfig
index 8306616b6d81..ada693ea51a7 100644
--- a/drivers/iommu/iommufd/Kconfig
+++ b/drivers/iommu/iommufd/Kconfig
@@ -23,7 +23,7 @@ config IOMMUFD_VFIO_CONTAINER
removed.
IOMMUFD VFIO container emulation is known to lack certain features
- of the native VFIO container, such as no-IOMMU support, peer-to-peer
+ of the native VFIO container, such as peer-to-peer
DMA mapping, PPC IOMMU support, as well as other potentially
undiscovered gaps. This option is currently intended for the
purpose of testing IOMMUFD with unmodified userspace supporting VFIO
diff --git a/drivers/iommu/iommufd/device.c b/drivers/iommu/iommufd/device.c
index d81f93a321af..a0c66f47a65a 100644
--- a/drivers/iommu/iommufd/device.c
+++ b/drivers/iommu/iommufd/device.c
@@ -4,7 +4,6 @@
#include <linux/iommufd.h>
#include <linux/slab.h>
#include <linux/iommu.h>
-#include <linux/irqdomain.h>
#include "io_pagetable.h"
#include "iommufd_private.h"
@@ -169,8 +168,7 @@ static int iommufd_device_setup_msi(struct iommufd_device *idev,
* operation from the device (eg a simple DMA) cannot trigger an
* interrupt outside this iommufd context.
*/
- if (!device_iommu_capable(idev->dev, IOMMU_CAP_INTR_REMAP) &&
- !irq_domain_check_msi_remap()) {
+ if (!iommu_group_has_isolated_msi(idev->group)) {
if (!allow_unsafe_interrupts)
return -EPERM;
@@ -346,10 +344,6 @@ int iommufd_device_attach(struct iommufd_device *idev, u32 *pt_id)
rc = iommufd_device_do_attach(idev, hwpt);
if (rc)
goto out_put_pt_obj;
-
- mutex_lock(&hwpt->ioas->mutex);
- list_add_tail(&hwpt->hwpt_item, &hwpt->ioas->hwpt_list);
- mutex_unlock(&hwpt->ioas->mutex);
break;
}
case IOMMUFD_OBJ_IOAS: {
diff --git a/drivers/iommu/iommufd/iommufd_private.h b/drivers/iommu/iommufd/iommufd_private.h
index 222e86591f8a..9d7f71510ca1 100644
--- a/drivers/iommu/iommufd/iommufd_private.h
+++ b/drivers/iommu/iommufd/iommufd_private.h
@@ -18,6 +18,8 @@ struct iommufd_ctx {
struct xarray objects;
u8 account_mode;
+ /* Compatibility with VFIO no iommu */
+ u8 no_iommu_mode;
struct iommufd_ioas *vfio_ioas;
};
diff --git a/drivers/iommu/iommufd/main.c b/drivers/iommu/iommufd/main.c
index 083e6fcbe10a..3fbe636c3d8a 100644
--- a/drivers/iommu/iommufd/main.c
+++ b/drivers/iommu/iommufd/main.c
@@ -252,9 +252,12 @@ union ucmd_buffer {
struct iommu_destroy destroy;
struct iommu_ioas_alloc alloc;
struct iommu_ioas_allow_iovas allow_iovas;
+ struct iommu_ioas_copy ioas_copy;
struct iommu_ioas_iova_ranges iova_ranges;
struct iommu_ioas_map map;
struct iommu_ioas_unmap unmap;
+ struct iommu_option option;
+ struct iommu_vfio_ioas vfio_ioas;
#ifdef CONFIG_IOMMUFD_TEST
struct iommu_test_cmd test;
#endif
diff --git a/drivers/iommu/iommufd/pages.c b/drivers/iommu/iommufd/pages.c
index 1e1d3509efae..f8d92c9bb65b 100644
--- a/drivers/iommu/iommufd/pages.c
+++ b/drivers/iommu/iommufd/pages.c
@@ -456,7 +456,8 @@ static int batch_iommu_map_small(struct iommu_domain *domain,
size % PAGE_SIZE);
while (size) {
- rc = iommu_map(domain, iova, paddr, PAGE_SIZE, prot);
+ rc = iommu_map(domain, iova, paddr, PAGE_SIZE, prot,
+ GFP_KERNEL_ACCOUNT);
if (rc)
goto err_unmap;
iova += PAGE_SIZE;
@@ -500,7 +501,8 @@ static int batch_to_domain(struct pfn_batch *batch, struct iommu_domain *domain,
else
rc = iommu_map(domain, iova,
PFN_PHYS(batch->pfns[cur]) + page_offset,
- next_iova - iova, area->iommu_prot);
+ next_iova - iova, area->iommu_prot,
+ GFP_KERNEL_ACCOUNT);
if (rc)
goto err_unmap;
iova = next_iova;
diff --git a/drivers/iommu/iommufd/vfio_compat.c b/drivers/iommu/iommufd/vfio_compat.c
index 3ceca0e8311c..514494a0025b 100644
--- a/drivers/iommu/iommufd/vfio_compat.c
+++ b/drivers/iommu/iommufd/vfio_compat.c
@@ -26,39 +26,84 @@ out_unlock:
}
/**
- * iommufd_vfio_compat_ioas_id - Return the IOAS ID that vfio should use
+ * iommufd_vfio_compat_ioas_get_id - Ensure a compat IOAS exists
+ * @ictx: Context to operate on
+ * @out_ioas_id: The IOAS ID of the compatibility IOAS
+ *
+ * Return the ID of the current compatibility IOAS. The ID can be passed into
+ * other functions that take an ioas_id.
+ */
+int iommufd_vfio_compat_ioas_get_id(struct iommufd_ctx *ictx, u32 *out_ioas_id)
+{
+ struct iommufd_ioas *ioas;
+
+ ioas = get_compat_ioas(ictx);
+ if (IS_ERR(ioas))
+ return PTR_ERR(ioas);
+ *out_ioas_id = ioas->obj.id;
+ iommufd_put_object(&ioas->obj);
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(iommufd_vfio_compat_ioas_get_id, IOMMUFD_VFIO);
+
+/**
+ * iommufd_vfio_compat_set_no_iommu - Called when a no-iommu device is attached
+ * @ictx: Context to operate on
+ *
+ * This allows selecting the VFIO_NOIOMMU_IOMMU and blocks normal types.
+ */
+int iommufd_vfio_compat_set_no_iommu(struct iommufd_ctx *ictx)
+{
+ int ret;
+
+ xa_lock(&ictx->objects);
+ if (!ictx->vfio_ioas) {
+ ictx->no_iommu_mode = 1;
+ ret = 0;
+ } else {
+ ret = -EINVAL;
+ }
+ xa_unlock(&ictx->objects);
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(iommufd_vfio_compat_set_no_iommu, IOMMUFD_VFIO);
+
+/**
+ * iommufd_vfio_compat_ioas_create - Ensure the compat IOAS is created
* @ictx: Context to operate on
- * @out_ioas_id: The ioas_id the caller should use
*
* The compatibility IOAS is the IOAS that the vfio compatibility ioctls operate
* on since they do not have an IOAS ID input in their ABI. Only attaching a
- * group should cause a default creation of the internal ioas, this returns the
- * existing ioas if it has already been assigned somehow.
+ * group should cause a default creation of the internal ioas, this does nothing
+ * if an existing ioas has already been assigned somehow.
*/
-int iommufd_vfio_compat_ioas_id(struct iommufd_ctx *ictx, u32 *out_ioas_id)
+int iommufd_vfio_compat_ioas_create(struct iommufd_ctx *ictx)
{
struct iommufd_ioas *ioas = NULL;
- struct iommufd_ioas *out_ioas;
+ int ret;
ioas = iommufd_ioas_alloc(ictx);
if (IS_ERR(ioas))
return PTR_ERR(ioas);
xa_lock(&ictx->objects);
- if (ictx->vfio_ioas && iommufd_lock_obj(&ictx->vfio_ioas->obj))
- out_ioas = ictx->vfio_ioas;
- else {
- out_ioas = ioas;
- ictx->vfio_ioas = ioas;
+ /*
+ * VFIO won't allow attaching a container to both iommu and no iommu
+ * operation
+ */
+ if (ictx->no_iommu_mode) {
+ ret = -EINVAL;
+ goto out_abort;
}
- xa_unlock(&ictx->objects);
- *out_ioas_id = out_ioas->obj.id;
- if (out_ioas != ioas) {
- iommufd_put_object(&out_ioas->obj);
- iommufd_object_abort(ictx, &ioas->obj);
- return 0;
+ if (ictx->vfio_ioas && iommufd_lock_obj(&ictx->vfio_ioas->obj)) {
+ ret = 0;
+ iommufd_put_object(&ictx->vfio_ioas->obj);
+ goto out_abort;
}
+ ictx->vfio_ioas = ioas;
+ xa_unlock(&ictx->objects);
+
/*
* An automatically created compat IOAS is treated as a userspace
* created object. Userspace can learn the ID via IOMMU_VFIO_IOAS_GET,
@@ -67,8 +112,13 @@ int iommufd_vfio_compat_ioas_id(struct iommufd_ctx *ictx, u32 *out_ioas_id)
*/
iommufd_object_finalize(ictx, &ioas->obj);
return 0;
+
+out_abort:
+ xa_unlock(&ictx->objects);
+ iommufd_object_abort(ictx, &ioas->obj);
+ return ret;
}
-EXPORT_SYMBOL_NS_GPL(iommufd_vfio_compat_ioas_id, IOMMUFD_VFIO);
+EXPORT_SYMBOL_NS_GPL(iommufd_vfio_compat_ioas_create, IOMMUFD_VFIO);
int iommufd_vfio_ioas(struct iommufd_ucmd *ucmd)
{
@@ -235,6 +285,9 @@ static int iommufd_vfio_check_extension(struct iommufd_ctx *ictx,
case VFIO_UNMAP_ALL:
return 1;
+ case VFIO_NOIOMMU_IOMMU:
+ return IS_ENABLED(CONFIG_VFIO_NOIOMMU);
+
case VFIO_DMA_CC_IOMMU:
return iommufd_vfio_cc_iommu(ictx);
@@ -261,10 +314,24 @@ static int iommufd_vfio_check_extension(struct iommufd_ctx *ictx,
static int iommufd_vfio_set_iommu(struct iommufd_ctx *ictx, unsigned long type)
{
+ bool no_iommu_mode = READ_ONCE(ictx->no_iommu_mode);
struct iommufd_ioas *ioas = NULL;
int rc = 0;
- if (type != VFIO_TYPE1_IOMMU && type != VFIO_TYPE1v2_IOMMU)
+ /*
+ * Emulation for NOIOMMU is imperfect in that VFIO blocks almost all
+ * other ioctls. We let them keep working but they mostly fail since no
+ * IOAS should exist.
+ */
+ if (IS_ENABLED(CONFIG_VFIO_NOIOMMU) && type == VFIO_NOIOMMU_IOMMU &&
+ no_iommu_mode) {
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+ return 0;
+ }
+
+ if ((type != VFIO_TYPE1_IOMMU && type != VFIO_TYPE1v2_IOMMU) ||
+ no_iommu_mode)
return -EINVAL;
/* VFIO fails the set_iommu if there is no group */
@@ -381,7 +448,7 @@ static int iommufd_vfio_iommu_get_info(struct iommufd_ctx *ictx,
};
size_t minsz = offsetofend(struct vfio_iommu_type1_info, iova_pgsizes);
struct vfio_info_cap_header __user *last_cap = NULL;
- struct vfio_iommu_type1_info info;
+ struct vfio_iommu_type1_info info = {};
struct iommufd_ioas *ioas;
size_t total_cap_size;
int rc;
diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c
index a003bd5fc65c..bdf1a4e5eae0 100644
--- a/drivers/iommu/ipmmu-vmsa.c
+++ b/drivers/iommu/ipmmu-vmsa.c
@@ -299,18 +299,6 @@ static void ipmmu_utlb_enable(struct ipmmu_vmsa_domain *domain,
mmu->utlb_ctx[utlb] = domain->context_id;
}
-/*
- * Disable MMU translation for the microTLB.
- */
-static void ipmmu_utlb_disable(struct ipmmu_vmsa_domain *domain,
- unsigned int utlb)
-{
- struct ipmmu_vmsa_device *mmu = domain->mmu;
-
- ipmmu_imuctr_write(mmu, utlb, 0);
- mmu->utlb_ctx[utlb] = IPMMU_CTX_INVALID;
-}
-
static void ipmmu_tlb_flush_all(void *cookie)
{
struct ipmmu_vmsa_domain *domain = cookie;
@@ -643,21 +631,6 @@ static int ipmmu_attach_device(struct iommu_domain *io_domain,
return 0;
}
-static void ipmmu_detach_device(struct iommu_domain *io_domain,
- struct device *dev)
-{
- struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
- struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain);
- unsigned int i;
-
- for (i = 0; i < fwspec->num_ids; ++i)
- ipmmu_utlb_disable(domain, fwspec->ids[i]);
-
- /*
- * TODO: Optimize by disabling the context when no device is attached.
- */
-}
-
static int ipmmu_map(struct iommu_domain *io_domain, unsigned long iova,
phys_addr_t paddr, size_t pgsize, size_t pgcount,
int prot, gfp_t gfp, size_t *mapped)
@@ -876,7 +849,6 @@ static const struct iommu_ops ipmmu_ops = {
.of_xlate = ipmmu_of_xlate,
.default_domain_ops = &(const struct iommu_domain_ops) {
.attach_dev = ipmmu_attach_device,
- .detach_dev = ipmmu_detach_device,
.map_pages = ipmmu_map,
.unmap_pages = ipmmu_unmap,
.flush_iotlb_all = ipmmu_flush_iotlb_all,
diff --git a/drivers/iommu/msm_iommu.c b/drivers/iommu/msm_iommu.c
index c60624910872..454f6331c889 100644
--- a/drivers/iommu/msm_iommu.c
+++ b/drivers/iommu/msm_iommu.c
@@ -443,9 +443,9 @@ fail:
return ret;
}
-static void msm_iommu_detach_dev(struct iommu_domain *domain,
- struct device *dev)
+static void msm_iommu_set_platform_dma(struct device *dev)
{
+ struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
struct msm_priv *priv = to_msm_priv(domain);
unsigned long flags;
struct msm_iommu_dev *iommu;
@@ -678,11 +678,11 @@ static struct iommu_ops msm_iommu_ops = {
.domain_alloc = msm_iommu_domain_alloc,
.probe_device = msm_iommu_probe_device,
.device_group = generic_device_group,
+ .set_platform_dma_ops = msm_iommu_set_platform_dma,
.pgsize_bitmap = MSM_IOMMU_PGSIZES,
.of_xlate = qcom_iommu_of_xlate,
.default_domain_ops = &(const struct iommu_domain_ops) {
.attach_dev = msm_iommu_attach_dev,
- .detach_dev = msm_iommu_detach_dev,
.map_pages = msm_iommu_map,
.unmap_pages = msm_iommu_unmap,
/*
diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index 2badd6acfb23..d5a4955910ff 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -710,14 +710,6 @@ err_unlock:
return ret;
}
-static void mtk_iommu_detach_device(struct iommu_domain *domain,
- struct device *dev)
-{
- struct mtk_iommu_data *data = dev_iommu_priv_get(dev);
-
- mtk_iommu_config(data, dev, false, 0);
-}
-
static int mtk_iommu_map(struct iommu_domain *domain, unsigned long iova,
phys_addr_t paddr, size_t pgsize, size_t pgcount,
int prot, gfp_t gfp, size_t *mapped)
@@ -946,7 +938,6 @@ static const struct iommu_ops mtk_iommu_ops = {
.owner = THIS_MODULE,
.default_domain_ops = &(const struct iommu_domain_ops) {
.attach_dev = mtk_iommu_attach_device,
- .detach_dev = mtk_iommu_detach_device,
.map_pages = mtk_iommu_map,
.unmap_pages = mtk_iommu_unmap,
.flush_iotlb_all = mtk_iommu_flush_iotlb_all,
diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c
index ca581ff1c769..43e4c8f89e23 100644
--- a/drivers/iommu/mtk_iommu_v1.c
+++ b/drivers/iommu/mtk_iommu_v1.c
@@ -319,7 +319,7 @@ static int mtk_iommu_v1_attach_device(struct iommu_domain *domain, struct device
return 0;
}
-static void mtk_iommu_v1_detach_device(struct iommu_domain *domain, struct device *dev)
+static void mtk_iommu_v1_set_platform_dma(struct device *dev)
{
struct mtk_iommu_v1_data *data = dev_iommu_priv_get(dev);
@@ -585,10 +585,10 @@ static const struct iommu_ops mtk_iommu_v1_ops = {
.def_domain_type = mtk_iommu_v1_def_domain_type,
.device_group = generic_device_group,
.pgsize_bitmap = MT2701_IOMMU_PAGE_SIZE,
+ .set_platform_dma_ops = mtk_iommu_v1_set_platform_dma,
.owner = THIS_MODULE,
.default_domain_ops = &(const struct iommu_domain_ops) {
.attach_dev = mtk_iommu_v1_attach_device,
- .detach_dev = mtk_iommu_v1_detach_device,
.map_pages = mtk_iommu_v1_map,
.unmap_pages = mtk_iommu_v1_unmap,
.iova_to_phys = mtk_iommu_v1_iova_to_phys,
diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
index 00d98f08732f..40f57d293a79 100644
--- a/drivers/iommu/of_iommu.c
+++ b/drivers/iommu/of_iommu.c
@@ -10,6 +10,7 @@
#include <linux/limits.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/of_iommu.h>
#include <linux/of_pci.h>
#include <linux/pci.h>
@@ -171,3 +172,98 @@ const struct iommu_ops *of_iommu_configure(struct device *dev,
return ops;
}
+
+static enum iommu_resv_type __maybe_unused
+iommu_resv_region_get_type(struct device *dev,
+ struct resource *phys,
+ phys_addr_t start, size_t length)
+{
+ phys_addr_t end = start + length - 1;
+
+ /*
+ * IOMMU regions without an associated physical region cannot be
+ * mapped and are simply reservations.
+ */
+ if (phys->start >= phys->end)
+ return IOMMU_RESV_RESERVED;
+
+ /* may be IOMMU_RESV_DIRECT_RELAXABLE for certain cases */
+ if (start == phys->start && end == phys->end)
+ return IOMMU_RESV_DIRECT;
+
+ dev_warn(dev, "treating non-direct mapping [%pr] -> [%pap-%pap] as reservation\n", &phys,
+ &start, &end);
+ return IOMMU_RESV_RESERVED;
+}
+
+/**
+ * of_iommu_get_resv_regions - reserved region driver helper for device tree
+ * @dev: device for which to get reserved regions
+ * @list: reserved region list
+ *
+ * IOMMU drivers can use this to implement their .get_resv_regions() callback
+ * for memory regions attached to a device tree node. See the reserved-memory
+ * device tree bindings on how to use these:
+ *
+ * Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt
+ */
+void of_iommu_get_resv_regions(struct device *dev, struct list_head *list)
+{
+#if IS_ENABLED(CONFIG_OF_ADDRESS)
+ struct of_phandle_iterator it;
+ int err;
+
+ of_for_each_phandle(&it, err, dev->of_node, "memory-region", NULL, 0) {
+ const __be32 *maps, *end;
+ struct resource phys;
+ int size;
+
+ memset(&phys, 0, sizeof(phys));
+
+ /*
+ * The "reg" property is optional and can be omitted by reserved-memory regions
+ * that represent reservations in the IOVA space, which are regions that should
+ * not be mapped.
+ */
+ if (of_find_property(it.node, "reg", NULL)) {
+ err = of_address_to_resource(it.node, 0, &phys);
+ if (err < 0) {
+ dev_err(dev, "failed to parse memory region %pOF: %d\n",
+ it.node, err);
+ continue;
+ }
+ }
+
+ maps = of_get_property(it.node, "iommu-addresses", &size);
+ if (!maps)
+ continue;
+
+ end = maps + size / sizeof(__be32);
+
+ while (maps < end) {
+ struct device_node *np;
+ u32 phandle;
+
+ phandle = be32_to_cpup(maps++);
+ np = of_find_node_by_phandle(phandle);
+
+ if (np == dev->of_node) {
+ int prot = IOMMU_READ | IOMMU_WRITE;
+ struct iommu_resv_region *region;
+ enum iommu_resv_type type;
+ phys_addr_t iova;
+ size_t length;
+
+ maps = of_translate_dma_region(np, maps, &iova, &length);
+ type = iommu_resv_region_get_type(dev, &phys, iova, length);
+
+ region = iommu_alloc_resv_region(iova, length, prot, type,
+ GFP_KERNEL);
+ if (region)
+ list_add_tail(&region->list, list);
+ }
+ }
+ }
+#endif
+}
+EXPORT_SYMBOL(of_iommu_get_resv_regions);
diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c
index 2fd7702c6709..3ab078112a7c 100644
--- a/drivers/iommu/omap-iommu.c
+++ b/drivers/iommu/omap-iommu.c
@@ -1556,9 +1556,9 @@ static void _omap_iommu_detach_dev(struct omap_iommu_domain *omap_domain,
omap_domain->dev = NULL;
}
-static void omap_iommu_detach_dev(struct iommu_domain *domain,
- struct device *dev)
+static void omap_iommu_set_platform_dma(struct device *dev)
{
+ struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
struct omap_iommu_domain *omap_domain = to_omap_domain(domain);
spin_lock(&omap_domain->lock);
@@ -1737,10 +1737,10 @@ static const struct iommu_ops omap_iommu_ops = {
.probe_device = omap_iommu_probe_device,
.release_device = omap_iommu_release_device,
.device_group = omap_iommu_device_group,
+ .set_platform_dma_ops = omap_iommu_set_platform_dma,
.pgsize_bitmap = OMAP_IOMMU_PGSIZES,
.default_domain_ops = &(const struct iommu_domain_ops) {
.attach_dev = omap_iommu_attach_dev,
- .detach_dev = omap_iommu_detach_dev,
.map = omap_iommu_map,
.unmap = omap_iommu_unmap,
.iova_to_phys = omap_iommu_iova_to_phys,
diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index a68eadd64f38..f30db22ea5d7 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -1192,7 +1192,6 @@ static const struct iommu_ops rk_iommu_ops = {
.of_xlate = rk_iommu_of_xlate,
.default_domain_ops = &(const struct iommu_domain_ops) {
.attach_dev = rk_iommu_attach_device,
- .detach_dev = rk_iommu_detach_device,
.map = rk_iommu_map,
.unmap = rk_iommu_unmap,
.iova_to_phys = rk_iommu_iova_to_phys,
diff --git a/drivers/iommu/s390-iommu.c b/drivers/iommu/s390-iommu.c
index ed33c6cce083..fbf59a8db29b 100644
--- a/drivers/iommu/s390-iommu.c
+++ b/drivers/iommu/s390-iommu.c
@@ -34,8 +34,6 @@ static bool s390_iommu_capable(struct device *dev, enum iommu_cap cap)
switch (cap) {
case IOMMU_CAP_CACHE_COHERENCY:
return true;
- case IOMMU_CAP_INTR_REMAP:
- return true;
default:
return false;
}
@@ -52,7 +50,7 @@ static struct iommu_domain *s390_domain_alloc(unsigned domain_type)
if (!s390_domain)
return NULL;
- s390_domain->dma_table = dma_alloc_cpu_table();
+ s390_domain->dma_table = dma_alloc_cpu_table(GFP_KERNEL);
if (!s390_domain->dma_table) {
kfree(s390_domain);
return NULL;
@@ -144,13 +142,10 @@ static int s390_iommu_attach_device(struct iommu_domain *domain,
return 0;
}
-static void s390_iommu_detach_device(struct iommu_domain *domain,
- struct device *dev)
+static void s390_iommu_set_platform_dma(struct device *dev)
{
struct zpci_dev *zdev = to_zpci_dev(dev);
- WARN_ON(zdev->s390_domain != to_s390_domain(domain));
-
__s390_iommu_detach_device(zdev);
zpci_dma_init_device(zdev);
}
@@ -260,7 +255,8 @@ static void s390_iommu_iotlb_sync_map(struct iommu_domain *domain,
static int s390_iommu_validate_trans(struct s390_domain *s390_domain,
phys_addr_t pa, dma_addr_t dma_addr,
- unsigned long nr_pages, int flags)
+ unsigned long nr_pages, int flags,
+ gfp_t gfp)
{
phys_addr_t page_addr = pa & PAGE_MASK;
unsigned long *entry;
@@ -268,7 +264,8 @@ static int s390_iommu_validate_trans(struct s390_domain *s390_domain,
int rc;
for (i = 0; i < nr_pages; i++) {
- entry = dma_walk_cpu_trans(s390_domain->dma_table, dma_addr);
+ entry = dma_walk_cpu_trans(s390_domain->dma_table, dma_addr,
+ gfp);
if (unlikely(!entry)) {
rc = -ENOMEM;
goto undo_cpu_trans;
@@ -284,7 +281,7 @@ undo_cpu_trans:
while (i-- > 0) {
dma_addr -= PAGE_SIZE;
entry = dma_walk_cpu_trans(s390_domain->dma_table,
- dma_addr);
+ dma_addr, gfp);
if (!entry)
break;
dma_update_cpu_trans(entry, 0, ZPCI_PTE_INVALID);
@@ -301,7 +298,8 @@ static int s390_iommu_invalidate_trans(struct s390_domain *s390_domain,
int rc = 0;
for (i = 0; i < nr_pages; i++) {
- entry = dma_walk_cpu_trans(s390_domain->dma_table, dma_addr);
+ entry = dma_walk_cpu_trans(s390_domain->dma_table, dma_addr,
+ GFP_ATOMIC);
if (unlikely(!entry)) {
rc = -EINVAL;
break;
@@ -339,7 +337,7 @@ static int s390_iommu_map_pages(struct iommu_domain *domain,
flags |= ZPCI_TABLE_PROTECTED;
rc = s390_iommu_validate_trans(s390_domain, paddr, iova,
- pgcount, flags);
+ pgcount, flags, gfp);
if (!rc)
*mapped = size;
@@ -435,11 +433,11 @@ static const struct iommu_ops s390_iommu_ops = {
.probe_device = s390_iommu_probe_device,
.release_device = s390_iommu_release_device,
.device_group = generic_device_group,
+ .set_platform_dma_ops = s390_iommu_set_platform_dma,
.pgsize_bitmap = SZ_4K,
.get_resv_regions = s390_iommu_get_resv_regions,
.default_domain_ops = &(const struct iommu_domain_ops) {
.attach_dev = s390_iommu_attach_device,
- .detach_dev = s390_iommu_detach_device,
.map_pages = s390_iommu_map_pages,
.unmap_pages = s390_iommu_unmap_pages,
.flush_iotlb_all = s390_iommu_flush_iotlb_all,
diff --git a/drivers/iommu/sprd-iommu.c b/drivers/iommu/sprd-iommu.c
index 219bfa11f7f4..ae94d74b73f4 100644
--- a/drivers/iommu/sprd-iommu.c
+++ b/drivers/iommu/sprd-iommu.c
@@ -255,21 +255,6 @@ static int sprd_iommu_attach_device(struct iommu_domain *domain,
return 0;
}
-static void sprd_iommu_detach_device(struct iommu_domain *domain,
- struct device *dev)
-{
- struct sprd_iommu_domain *dom = to_sprd_domain(domain);
- struct sprd_iommu_device *sdev = dom->sdev;
- size_t pgt_size = sprd_iommu_pgt_size(domain);
-
- if (!sdev)
- return;
-
- dma_free_coherent(sdev->dev, pgt_size, dom->pgt_va, dom->pgt_pa);
- sprd_iommu_hw_en(sdev, false);
- dom->sdev = NULL;
-}
-
static int sprd_iommu_map(struct iommu_domain *domain, unsigned long iova,
phys_addr_t paddr, size_t pgsize, size_t pgcount,
int prot, gfp_t gfp, size_t *mapped)
@@ -414,7 +399,6 @@ static const struct iommu_ops sprd_iommu_ops = {
.owner = THIS_MODULE,
.default_domain_ops = &(const struct iommu_domain_ops) {
.attach_dev = sprd_iommu_attach_device,
- .detach_dev = sprd_iommu_detach_device,
.map_pages = sprd_iommu_map,
.unmap_pages = sprd_iommu_unmap,
.iotlb_sync_map = sprd_iommu_sync_map,
diff --git a/drivers/iommu/sun50i-iommu.c b/drivers/iommu/sun50i-iommu.c
index 5b585eace3d4..2d993d0cea7d 100644
--- a/drivers/iommu/sun50i-iommu.c
+++ b/drivers/iommu/sun50i-iommu.c
@@ -834,7 +834,6 @@ static const struct iommu_ops sun50i_iommu_ops = {
.probe_device = sun50i_iommu_probe_device,
.default_domain_ops = &(const struct iommu_domain_ops) {
.attach_dev = sun50i_iommu_attach_device,
- .detach_dev = sun50i_iommu_detach_device,
.flush_iotlb_all = sun50i_iommu_flush_iotlb_all,
.iotlb_sync_map = sun50i_iommu_iotlb_sync_map,
.iotlb_sync = sun50i_iommu_iotlb_sync,
diff --git a/drivers/iommu/tegra-gart.c b/drivers/iommu/tegra-gart.c
index ed53279d1106..a482ff838b53 100644
--- a/drivers/iommu/tegra-gart.c
+++ b/drivers/iommu/tegra-gart.c
@@ -124,9 +124,9 @@ static int gart_iommu_attach_dev(struct iommu_domain *domain,
return ret;
}
-static void gart_iommu_detach_dev(struct iommu_domain *domain,
- struct device *dev)
+static void gart_iommu_set_platform_dma(struct device *dev)
{
+ struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
struct gart_device *gart = gart_handle;
spin_lock(&gart->dom_lock);
@@ -270,11 +270,11 @@ static const struct iommu_ops gart_iommu_ops = {
.domain_alloc = gart_iommu_domain_alloc,
.probe_device = gart_iommu_probe_device,
.device_group = generic_device_group,
+ .set_platform_dma_ops = gart_iommu_set_platform_dma,
.pgsize_bitmap = GART_IOMMU_PGSIZES,
.of_xlate = gart_iommu_of_xlate,
.default_domain_ops = &(const struct iommu_domain_ops) {
.attach_dev = gart_iommu_attach_dev,
- .detach_dev = gart_iommu_detach_dev,
.map = gart_iommu_map,
.unmap = gart_iommu_unmap,
.iova_to_phys = gart_iommu_iova_to_phys,
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index 5b1af40221ec..1cbf063ccf14 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -511,8 +511,9 @@ disable:
return err;
}
-static void tegra_smmu_detach_dev(struct iommu_domain *domain, struct device *dev)
+static void tegra_smmu_set_platform_dma(struct device *dev)
{
+ struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
struct tegra_smmu_as *as = to_smmu_as(domain);
struct tegra_smmu *smmu = as->smmu;
@@ -671,12 +672,12 @@ static struct page *as_get_pde_page(struct tegra_smmu_as *as,
* allocate page in a sleeping context if GFP flags permit. Hence
* spinlock needs to be unlocked and re-locked after allocation.
*/
- if (!(gfp & __GFP_ATOMIC))
+ if (gfpflags_allow_blocking(gfp))
spin_unlock_irqrestore(&as->lock, *flags);
page = alloc_page(gfp | __GFP_DMA | __GFP_ZERO);
- if (!(gfp & __GFP_ATOMIC))
+ if (gfpflags_allow_blocking(gfp))
spin_lock_irqsave(&as->lock, *flags);
/*
@@ -965,11 +966,11 @@ static const struct iommu_ops tegra_smmu_ops = {
.domain_alloc = tegra_smmu_domain_alloc,
.probe_device = tegra_smmu_probe_device,
.device_group = tegra_smmu_device_group,
+ .set_platform_dma_ops = tegra_smmu_set_platform_dma,
.of_xlate = tegra_smmu_of_xlate,
.pgsize_bitmap = SZ_4K,
.default_domain_ops = &(const struct iommu_domain_ops) {
.attach_dev = tegra_smmu_attach_dev,
- .detach_dev = tegra_smmu_detach_dev,
.map = tegra_smmu_map,
.unmap = tegra_smmu_unmap,
.iova_to_phys = tegra_smmu_iova_to_phys,
diff --git a/drivers/ipack/devices/ipoctal.c b/drivers/ipack/devices/ipoctal.c
index fc00274070b6..a01c15812b70 100644
--- a/drivers/ipack/devices/ipoctal.c
+++ b/drivers/ipack/devices/ipoctal.c
@@ -253,7 +253,7 @@ static void ipoctal_irq_channel(struct ipoctal_channel *channel)
static irqreturn_t ipoctal_irq_handler(void *arg)
{
unsigned int i;
- struct ipoctal *ipoctal = (struct ipoctal *) arg;
+ struct ipoctal *ipoctal = arg;
/* Clear the IPack device interrupt */
readw(ipoctal->int_space + ACK_INT_REQ0);
@@ -647,7 +647,7 @@ static void ipoctal_hangup(struct tty_struct *tty)
tty_port_hangup(&channel->tty_port);
ipoctal_reset_channel(channel);
- tty_port_set_initialized(&channel->tty_port, 0);
+ tty_port_set_initialized(&channel->tty_port, false);
wake_up_interruptible(&channel->tty_port.open_wait);
}
@@ -659,7 +659,7 @@ static void ipoctal_shutdown(struct tty_struct *tty)
return;
ipoctal_reset_channel(channel);
- tty_port_set_initialized(&channel->tty_port, 0);
+ tty_port_set_initialized(&channel->tty_port, false);
}
static void ipoctal_cleanup(struct tty_struct *tty)
diff --git a/drivers/ipack/ipack.c b/drivers/ipack/ipack.c
index 74d449858a61..cc1ecfd49928 100644
--- a/drivers/ipack/ipack.c
+++ b/drivers/ipack/ipack.c
@@ -76,9 +76,9 @@ static void ipack_bus_remove(struct device *device)
drv->ops->remove(dev);
}
-static int ipack_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int ipack_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct ipack_device *idev;
+ const struct ipack_device *idev;
if (!dev)
return -ENODEV;
diff --git a/drivers/irqchip/irq-apple-aic.c b/drivers/irqchip/irq-apple-aic.c
index eabb3b92965b..5c534d9fd2b0 100644
--- a/drivers/irqchip/irq-apple-aic.c
+++ b/drivers/irqchip/irq-apple-aic.c
@@ -210,7 +210,6 @@
FIELD_PREP(AIC_EVENT_NUM, x))
#define AIC_HWIRQ_IRQ(x) FIELD_GET(AIC_EVENT_NUM, x)
#define AIC_HWIRQ_DIE(x) FIELD_GET(AIC_EVENT_DIE, x)
-#define AIC_NR_FIQ 6
#define AIC_NR_SWIPI 32
/*
@@ -222,11 +221,18 @@
* running at EL2 (with VHE). When the kernel is running at EL1, the
* mapping differs and aic_irq_domain_translate() performs the remapping.
*/
-
-#define AIC_TMR_EL0_PHYS AIC_TMR_HV_PHYS
-#define AIC_TMR_EL0_VIRT AIC_TMR_HV_VIRT
-#define AIC_TMR_EL02_PHYS AIC_TMR_GUEST_PHYS
-#define AIC_TMR_EL02_VIRT AIC_TMR_GUEST_VIRT
+enum fiq_hwirq {
+ /* Must be ordered as in apple-aic.h */
+ AIC_TMR_EL0_PHYS = AIC_TMR_HV_PHYS,
+ AIC_TMR_EL0_VIRT = AIC_TMR_HV_VIRT,
+ AIC_TMR_EL02_PHYS = AIC_TMR_GUEST_PHYS,
+ AIC_TMR_EL02_VIRT = AIC_TMR_GUEST_VIRT,
+ AIC_CPU_PMU_Effi = AIC_CPU_PMU_E,
+ AIC_CPU_PMU_Perf = AIC_CPU_PMU_P,
+ /* No need for this to be discovered from DT */
+ AIC_VGIC_MI,
+ AIC_NR_FIQ
+};
static DEFINE_STATIC_KEY_TRUE(use_fast_ipi);
@@ -380,14 +386,20 @@ static void __exception_irq_entry aic_handle_irq(struct pt_regs *regs)
/*
* vGIC maintenance interrupts end up here too, so we need to check
- * for them separately. This should never trigger if KVM is working
- * properly, because it will have already taken care of clearing it
- * on guest exit before this handler runs.
+ * for them separately. It should however only trigger when NV is
+ * in use, and be cleared when coming back from the handler.
*/
- if (is_kernel_in_hyp_mode() && (read_sysreg_s(SYS_ICH_HCR_EL2) & ICH_HCR_EN) &&
- read_sysreg_s(SYS_ICH_MISR_EL2) != 0) {
- pr_err_ratelimited("vGIC IRQ fired and not handled by KVM, disabling.\n");
- sysreg_clear_set_s(SYS_ICH_HCR_EL2, ICH_HCR_EN, 0);
+ if (is_kernel_in_hyp_mode() &&
+ (read_sysreg_s(SYS_ICH_HCR_EL2) & ICH_HCR_EN) &&
+ read_sysreg_s(SYS_ICH_MISR_EL2) != 0) {
+ generic_handle_domain_irq(aic_irqc->hw_domain,
+ AIC_FIQ_HWIRQ(AIC_VGIC_MI));
+
+ if (unlikely((read_sysreg_s(SYS_ICH_HCR_EL2) & ICH_HCR_EN) &&
+ read_sysreg_s(SYS_ICH_MISR_EL2))) {
+ pr_err_ratelimited("vGIC IRQ fired and not handled by KVM, disabling.\n");
+ sysreg_clear_set_s(SYS_ICH_HCR_EL2, ICH_HCR_EN, 0);
+ }
}
}
@@ -1033,6 +1045,21 @@ static int __init aic_of_ic_init(struct device_node *node, struct device_node *p
"irqchip/apple-aic/ipi:starting",
aic_init_cpu, NULL);
+ if (is_kernel_in_hyp_mode()) {
+ struct irq_fwspec mi = {
+ .fwnode = of_node_to_fwnode(node),
+ .param_count = 3,
+ .param = {
+ [0] = AIC_FIQ, /* This is a lie */
+ [1] = AIC_VGIC_MI,
+ [2] = IRQ_TYPE_LEVEL_HIGH,
+ },
+ };
+
+ vgic_info.maint_irq = irq_create_fwspec_mapping(&mi);
+ WARN_ON(!vgic_info.maint_irq);
+ }
+
vgic_set_kvm_info(&vgic_info);
pr_info("Initialized with %d/%d IRQs * %d/%d die(s), %d FIQs, %d vIPIs",
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 5634d29b644d..586271b8aa39 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -4692,7 +4692,7 @@ static bool __maybe_unused its_enable_quirk_socionext_synquacer(void *data)
}
/* the pre-ITS breaks isolation, so disable MSI remapping */
- its->msi_domain_flags &= ~IRQ_DOMAIN_FLAG_MSI_REMAP;
+ its->msi_domain_flags &= ~IRQ_DOMAIN_FLAG_ISOLATED_MSI;
return true;
}
return false;
@@ -5075,7 +5075,7 @@ static int __init its_probe_one(struct resource *res,
its->cmd_write = its->cmd_base;
its->fwnode_handle = handle;
its->get_msi_base = its_irq_get_msi_base;
- its->msi_domain_flags = IRQ_DOMAIN_FLAG_MSI_REMAP;
+ its->msi_domain_flags = IRQ_DOMAIN_FLAG_ISOLATED_MSI;
its_enable_quirks(its);
diff --git a/drivers/irqchip/irq-imx-gpcv2.c b/drivers/irqchip/irq-imx-gpcv2.c
index b9c22f764b4d..8a0e82067924 100644
--- a/drivers/irqchip/irq-imx-gpcv2.c
+++ b/drivers/irqchip/irq-imx-gpcv2.c
@@ -283,6 +283,7 @@ static int __init imx_gpcv2_irqchip_init(struct device_node *node,
* later the GPC power domain driver will not be skipped.
*/
of_node_clear_flag(node, OF_POPULATED);
+ fwnode_dev_initialized(domain->fwnode, false);
return 0;
}
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index be2eeb3d6fd3..9dbce09eabac 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -623,17 +623,6 @@ config LEDS_NETXBIG
and 5Big Network v2 boards. The LEDs are wired to a CPLD and are
controlled through a GPIO extension bus.
-config LEDS_ASIC3
- bool "LED support for the HTC ASIC3"
- depends on LEDS_CLASS=y
- depends on MFD_ASIC3
- default y
- help
- This option enables support for the LEDs on the HTC ASIC3. The HTC
- ASIC3 LED GPIOs are inputs, not outputs, thus the leds-gpio driver
- cannot be used. This driver supports hardware blinking with an on+off
- period from 62ms to 125s. Say Y to enable LEDs on the HP iPAQ hx4700.
-
config LEDS_TCA6507
tristate "LED Support for TCA6507 I2C chip"
depends on LEDS_CLASS && I2C
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index a790c967fce9..d30395d11fd8 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -14,7 +14,6 @@ obj-$(CONFIG_LEDS_ADP5520) += leds-adp5520.o
obj-$(CONFIG_LEDS_AN30259A) += leds-an30259a.o
obj-$(CONFIG_LEDS_APU) += leds-apu.o
obj-$(CONFIG_LEDS_ARIEL) += leds-ariel.o
-obj-$(CONFIG_LEDS_ASIC3) += leds-asic3.o
obj-$(CONFIG_LEDS_AW2013) += leds-aw2013.o
obj-$(CONFIG_LEDS_BCM6328) += leds-bcm6328.o
obj-$(CONFIG_LEDS_BCM6358) += leds-bcm6358.o
diff --git a/drivers/leds/flash/leds-mt6360.c b/drivers/leds/flash/leds-mt6360.c
index e1066a52d2d2..1af6c5898343 100644
--- a/drivers/leds/flash/leds-mt6360.c
+++ b/drivers/leds/flash/leds-mt6360.c
@@ -71,10 +71,6 @@ enum {
#define MT6360_STRBTO_STEPUS 32000
#define MT6360_STRBTO_MAXUS 2432000
-#define STATE_OFF 0
-#define STATE_KEEP 1
-#define STATE_ON 2
-
struct mt6360_led {
union {
struct led_classdev isnk;
@@ -84,7 +80,7 @@ struct mt6360_led {
struct v4l2_flash *v4l2_flash;
struct mt6360_priv *priv;
u32 led_no;
- u32 default_state;
+ enum led_default_state default_state;
};
struct mt6360_priv {
@@ -405,10 +401,10 @@ static int mt6360_isnk_init_default_state(struct mt6360_led *led)
level = LED_OFF;
switch (led->default_state) {
- case STATE_ON:
+ case LEDS_DEFSTATE_ON:
led->isnk.brightness = led->isnk.max_brightness;
break;
- case STATE_KEEP:
+ case LEDS_DEFSTATE_KEEP:
led->isnk.brightness = min(level, led->isnk.max_brightness);
break;
default:
@@ -443,10 +439,10 @@ static int mt6360_flash_init_default_state(struct mt6360_led *led)
level = LED_OFF;
switch (led->default_state) {
- case STATE_ON:
+ case LEDS_DEFSTATE_ON:
flash->led_cdev.brightness = flash->led_cdev.max_brightness;
break;
- case STATE_KEEP:
+ case LEDS_DEFSTATE_KEEP:
flash->led_cdev.brightness =
min(level, flash->led_cdev.max_brightness);
break;
@@ -760,25 +756,6 @@ static int mt6360_init_flash_properties(struct mt6360_led *led,
return 0;
}
-static int mt6360_init_common_properties(struct mt6360_led *led,
- struct led_init_data *init_data)
-{
- const char *const states[] = { "off", "keep", "on" };
- const char *str;
- int ret;
-
- if (!fwnode_property_read_string(init_data->fwnode,
- "default-state", &str)) {
- ret = match_string(states, ARRAY_SIZE(states), str);
- if (ret < 0)
- ret = STATE_OFF;
-
- led->default_state = ret;
- }
-
- return 0;
-}
-
static void mt6360_v4l2_flash_release(struct mt6360_priv *priv)
{
int i;
@@ -852,10 +829,7 @@ static int mt6360_led_probe(struct platform_device *pdev)
led->led_no = reg;
led->priv = priv;
-
- ret = mt6360_init_common_properties(led, &init_data);
- if (ret)
- goto out_flash_release;
+ led->default_state = led_init_default_state_get(child);
if (reg == MT6360_VIRTUAL_MULTICOLOR ||
reg <= MT6360_LED_ISNKML)
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index 0c4b8d8d2b4f..a6b3adcd044a 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -253,6 +253,7 @@ struct led_classdev *of_led_get(struct device_node *np, int index)
led_dev = class_find_device_by_of_node(leds_class, led_node);
of_node_put(led_node);
+ put_device(led_dev);
return led_module_get(led_dev);
}
diff --git a/drivers/leds/leds-an30259a.c b/drivers/leds/leds-an30259a.c
index e072ee5409f7..89df267853a9 100644
--- a/drivers/leds/leds-an30259a.c
+++ b/drivers/leds/leds-an30259a.c
@@ -55,10 +55,6 @@
#define AN30259A_NAME "an30259a"
-#define STATE_OFF 0
-#define STATE_KEEP 1
-#define STATE_ON 2
-
struct an30259a;
struct an30259a_led {
@@ -66,7 +62,7 @@ struct an30259a_led {
struct fwnode_handle *fwnode;
struct led_classdev cdev;
u32 num;
- u32 default_state;
+ enum led_default_state default_state;
bool sloping;
};
@@ -205,7 +201,6 @@ static int an30259a_dt_init(struct i2c_client *client,
struct device_node *np = dev_of_node(&client->dev), *child;
int count, ret;
int i = 0;
- const char *str;
struct an30259a_led *led;
count = of_get_available_child_count(np);
@@ -228,15 +223,7 @@ static int an30259a_dt_init(struct i2c_client *client,
led->num = source;
led->chip = chip;
led->fwnode = of_fwnode_handle(child);
-
- if (!of_property_read_string(child, "default-state", &str)) {
- if (!strcmp(str, "on"))
- led->default_state = STATE_ON;
- else if (!strcmp(str, "keep"))
- led->default_state = STATE_KEEP;
- else
- led->default_state = STATE_OFF;
- }
+ led->default_state = led_init_default_state_get(led->fwnode);
i++;
}
@@ -261,10 +248,10 @@ static void an30259a_init_default_state(struct an30259a_led *led)
int led_on, err;
switch (led->default_state) {
- case STATE_ON:
+ case LEDS_DEFSTATE_ON:
led->cdev.brightness = LED_FULL;
break;
- case STATE_KEEP:
+ case LEDS_DEFSTATE_KEEP:
err = regmap_read(chip->regmap, AN30259A_REG_LED_ON, &led_on);
if (err)
break;
diff --git a/drivers/leds/leds-asic3.c b/drivers/leds/leds-asic3.c
deleted file mode 100644
index 8cbc1b8bafa5..000000000000
--- a/drivers/leds/leds-asic3.c
+++ /dev/null
@@ -1,177 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 2011 Paul Parsons <lost.distance@yahoo.com>
- */
-
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-#include <linux/leds.h>
-#include <linux/slab.h>
-
-#include <linux/mfd/asic3.h>
-#include <linux/mfd/core.h>
-#include <linux/module.h>
-
-/*
- * The HTC ASIC3 LED GPIOs are inputs, not outputs.
- * Hence we turn the LEDs on/off via the TimeBase register.
- */
-
-/*
- * When TimeBase is 4 the clock resolution is about 32Hz.
- * This driver supports hardware blinking with an on+off
- * period from 62ms (2 clocks) to 125s (4000 clocks).
- */
-#define MS_TO_CLK(ms) DIV_ROUND_CLOSEST(((ms)*1024), 32000)
-#define CLK_TO_MS(clk) (((clk)*32000)/1024)
-#define MAX_CLK 4000 /* Fits into 12-bit Time registers */
-#define MAX_MS CLK_TO_MS(MAX_CLK)
-
-static const unsigned int led_n_base[ASIC3_NUM_LEDS] = {
- [0] = ASIC3_LED_0_Base,
- [1] = ASIC3_LED_1_Base,
- [2] = ASIC3_LED_2_Base,
-};
-
-static void brightness_set(struct led_classdev *cdev,
- enum led_brightness value)
-{
- struct platform_device *pdev = to_platform_device(cdev->dev->parent);
- const struct mfd_cell *cell = mfd_get_cell(pdev);
- struct asic3 *asic = dev_get_drvdata(pdev->dev.parent);
- u32 timebase;
- unsigned int base;
-
- timebase = (value == LED_OFF) ? 0 : (LED_EN|0x4);
-
- base = led_n_base[cell->id];
- asic3_write_register(asic, (base + ASIC3_LED_PeriodTime), 32);
- asic3_write_register(asic, (base + ASIC3_LED_DutyTime), 32);
- asic3_write_register(asic, (base + ASIC3_LED_AutoStopCount), 0);
- asic3_write_register(asic, (base + ASIC3_LED_TimeBase), timebase);
-}
-
-static int blink_set(struct led_classdev *cdev,
- unsigned long *delay_on,
- unsigned long *delay_off)
-{
- struct platform_device *pdev = to_platform_device(cdev->dev->parent);
- const struct mfd_cell *cell = mfd_get_cell(pdev);
- struct asic3 *asic = dev_get_drvdata(pdev->dev.parent);
- u32 on;
- u32 off;
- unsigned int base;
-
- if (*delay_on > MAX_MS || *delay_off > MAX_MS)
- return -EINVAL;
-
- if (*delay_on == 0 && *delay_off == 0) {
- /* If both are zero then a sensible default should be chosen */
- on = MS_TO_CLK(500);
- off = MS_TO_CLK(500);
- } else {
- on = MS_TO_CLK(*delay_on);
- off = MS_TO_CLK(*delay_off);
- if ((on + off) > MAX_CLK)
- return -EINVAL;
- }
-
- base = led_n_base[cell->id];
- asic3_write_register(asic, (base + ASIC3_LED_PeriodTime), (on + off));
- asic3_write_register(asic, (base + ASIC3_LED_DutyTime), on);
- asic3_write_register(asic, (base + ASIC3_LED_AutoStopCount), 0);
- asic3_write_register(asic, (base + ASIC3_LED_TimeBase), (LED_EN|0x4));
-
- *delay_on = CLK_TO_MS(on);
- *delay_off = CLK_TO_MS(off);
-
- return 0;
-}
-
-static int asic3_led_probe(struct platform_device *pdev)
-{
- struct asic3_led *led = dev_get_platdata(&pdev->dev);
- int ret;
-
- ret = mfd_cell_enable(pdev);
- if (ret < 0)
- return ret;
-
- led->cdev = devm_kzalloc(&pdev->dev, sizeof(struct led_classdev),
- GFP_KERNEL);
- if (!led->cdev) {
- ret = -ENOMEM;
- goto out;
- }
-
- led->cdev->name = led->name;
- led->cdev->flags = LED_CORE_SUSPENDRESUME;
- led->cdev->brightness_set = brightness_set;
- led->cdev->blink_set = blink_set;
- led->cdev->default_trigger = led->default_trigger;
-
- ret = led_classdev_register(&pdev->dev, led->cdev);
- if (ret < 0)
- goto out;
-
- return 0;
-
-out:
- (void) mfd_cell_disable(pdev);
- return ret;
-}
-
-static int asic3_led_remove(struct platform_device *pdev)
-{
- struct asic3_led *led = dev_get_platdata(&pdev->dev);
-
- led_classdev_unregister(led->cdev);
-
- return mfd_cell_disable(pdev);
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int asic3_led_suspend(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- const struct mfd_cell *cell = mfd_get_cell(pdev);
- int ret;
-
- ret = 0;
- if (cell->suspend)
- ret = (*cell->suspend)(pdev);
-
- return ret;
-}
-
-static int asic3_led_resume(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- const struct mfd_cell *cell = mfd_get_cell(pdev);
- int ret;
-
- ret = 0;
- if (cell->resume)
- ret = (*cell->resume)(pdev);
-
- return ret;
-}
-#endif
-
-static SIMPLE_DEV_PM_OPS(asic3_led_pm_ops, asic3_led_suspend, asic3_led_resume);
-
-static struct platform_driver asic3_led_driver = {
- .probe = asic3_led_probe,
- .remove = asic3_led_remove,
- .driver = {
- .name = "leds-asic3",
- .pm = &asic3_led_pm_ops,
- },
-};
-
-module_platform_driver(asic3_led_driver);
-
-MODULE_AUTHOR("Paul Parsons <lost.distance@yahoo.com>");
-MODULE_DESCRIPTION("HTC ASIC3 LED driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:leds-asic3");
diff --git a/drivers/leds/leds-bcm6328.c b/drivers/leds/leds-bcm6328.c
index 2d4d87957a30..246f1296ab09 100644
--- a/drivers/leds/leds-bcm6328.c
+++ b/drivers/leds/leds-bcm6328.c
@@ -330,7 +330,9 @@ static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg,
{
struct led_init_data init_data = {};
struct bcm6328_led *led;
- const char *state;
+ enum led_default_state state;
+ unsigned long val, shift;
+ void __iomem *mode;
int rc;
led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
@@ -346,31 +348,29 @@ static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg,
if (of_property_read_bool(nc, "active-low"))
led->active_low = true;
- if (!of_property_read_string(nc, "default-state", &state)) {
- if (!strcmp(state, "on")) {
+ init_data.fwnode = of_fwnode_handle(nc);
+
+ state = led_init_default_state_get(init_data.fwnode);
+ switch (state) {
+ case LEDS_DEFSTATE_ON:
+ led->cdev.brightness = LED_FULL;
+ break;
+ case LEDS_DEFSTATE_KEEP:
+ shift = bcm6328_pin2shift(led->pin);
+ if (shift / 16)
+ mode = mem + BCM6328_REG_MODE_HI;
+ else
+ mode = mem + BCM6328_REG_MODE_LO;
+
+ val = bcm6328_led_read(mode) >> BCM6328_LED_SHIFT(shift % 16);
+ val &= BCM6328_LED_MODE_MASK;
+ if ((led->active_low && val == BCM6328_LED_MODE_OFF) ||
+ (!led->active_low && val == BCM6328_LED_MODE_ON))
led->cdev.brightness = LED_FULL;
- } else if (!strcmp(state, "keep")) {
- void __iomem *mode;
- unsigned long val, shift;
-
- shift = bcm6328_pin2shift(led->pin);
- if (shift / 16)
- mode = mem + BCM6328_REG_MODE_HI;
- else
- mode = mem + BCM6328_REG_MODE_LO;
-
- val = bcm6328_led_read(mode) >>
- BCM6328_LED_SHIFT(shift % 16);
- val &= BCM6328_LED_MODE_MASK;
- if ((led->active_low && val == BCM6328_LED_MODE_OFF) ||
- (!led->active_low && val == BCM6328_LED_MODE_ON))
- led->cdev.brightness = LED_FULL;
- else
- led->cdev.brightness = LED_OFF;
- } else {
+ else
led->cdev.brightness = LED_OFF;
- }
- } else {
+ break;
+ default:
led->cdev.brightness = LED_OFF;
}
@@ -378,7 +378,6 @@ static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg,
led->cdev.brightness_set = bcm6328_led_set;
led->cdev.blink_set = bcm6328_blink_set;
- init_data.fwnode = of_fwnode_handle(nc);
rc = devm_led_classdev_register_ext(dev, &led->cdev, &init_data);
if (rc < 0)
diff --git a/drivers/leds/leds-bcm6358.c b/drivers/leds/leds-bcm6358.c
index 9d2e487fa08a..86e51d44a5a7 100644
--- a/drivers/leds/leds-bcm6358.c
+++ b/drivers/leds/leds-bcm6358.c
@@ -96,7 +96,8 @@ static int bcm6358_led(struct device *dev, struct device_node *nc, u32 reg,
{
struct led_init_data init_data = {};
struct bcm6358_led *led;
- const char *state;
+ enum led_default_state state;
+ unsigned long val;
int rc;
led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
@@ -110,29 +111,28 @@ static int bcm6358_led(struct device *dev, struct device_node *nc, u32 reg,
if (of_property_read_bool(nc, "active-low"))
led->active_low = true;
- if (!of_property_read_string(nc, "default-state", &state)) {
- if (!strcmp(state, "on")) {
+ init_data.fwnode = of_fwnode_handle(nc);
+
+ state = led_init_default_state_get(init_data.fwnode);
+ switch (state) {
+ case LEDS_DEFSTATE_ON:
+ led->cdev.brightness = LED_FULL;
+ break;
+ case LEDS_DEFSTATE_KEEP:
+ val = bcm6358_led_read(led->mem + BCM6358_REG_MODE);
+ val &= BIT(led->pin);
+ if ((led->active_low && !val) || (!led->active_low && val))
led->cdev.brightness = LED_FULL;
- } else if (!strcmp(state, "keep")) {
- unsigned long val;
- val = bcm6358_led_read(led->mem + BCM6358_REG_MODE);
- val &= BIT(led->pin);
- if ((led->active_low && !val) ||
- (!led->active_low && val))
- led->cdev.brightness = LED_FULL;
- else
- led->cdev.brightness = LED_OFF;
- } else {
+ else
led->cdev.brightness = LED_OFF;
- }
- } else {
+ break;
+ default:
led->cdev.brightness = LED_OFF;
}
bcm6358_led_set(&led->cdev, led->cdev.brightness);
led->cdev.brightness_set = bcm6358_led_set;
- init_data.fwnode = of_fwnode_handle(nc);
rc = devm_led_classdev_register_ext(dev, &led->cdev, &init_data);
if (rc < 0)
diff --git a/drivers/leds/leds-bd2802.c b/drivers/leds/leds-bd2802.c
index 2b6678f6bd56..601185ddabcc 100644
--- a/drivers/leds/leds-bd2802.c
+++ b/drivers/leds/leds-bd2802.c
@@ -656,8 +656,7 @@ static void bd2802_unregister_led_classdev(struct bd2802_led *led)
led_classdev_unregister(&led->cdev_led1r);
}
-static int bd2802_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int bd2802_probe(struct i2c_client *client)
{
struct bd2802_led *led;
int ret, i;
@@ -787,7 +786,7 @@ static struct i2c_driver bd2802_i2c_driver = {
.name = "BD2802",
.pm = &bd2802_pm,
},
- .probe = bd2802_probe,
+ .probe_new = bd2802_probe,
.remove = bd2802_remove,
.id_table = bd2802_id,
};
diff --git a/drivers/leds/leds-blinkm.c b/drivers/leds/leds-blinkm.c
index e19cc8a7b7ca..37f2f32ae42d 100644
--- a/drivers/leds/leds-blinkm.c
+++ b/drivers/leds/leds-blinkm.c
@@ -565,8 +565,7 @@ static int blinkm_detect(struct i2c_client *client, struct i2c_board_info *info)
return 0;
}
-static int blinkm_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int blinkm_probe(struct i2c_client *client)
{
struct blinkm_data *data;
struct blinkm_led *led[3];
@@ -731,7 +730,7 @@ static struct i2c_driver blinkm_driver = {
.driver = {
.name = "blinkm",
},
- .probe = blinkm_probe,
+ .probe_new = blinkm_probe,
.remove = blinkm_remove,
.id_table = blinkm_id,
.detect = blinkm_detect,
diff --git a/drivers/leds/leds-is31fl319x.c b/drivers/leds/leds-is31fl319x.c
index b2f4c4ec7c56..7c908414ac7e 100644
--- a/drivers/leds/leds-is31fl319x.c
+++ b/drivers/leds/leds-is31fl319x.c
@@ -495,6 +495,11 @@ static inline int is31fl3196_db_to_gain(u32 dezibel)
return dezibel / IS31FL3196_AUDIO_GAIN_DB_STEP;
}
+static void is31f1319x_mutex_destroy(void *lock)
+{
+ mutex_destroy(lock);
+}
+
static int is31fl319x_probe(struct i2c_client *client)
{
struct is31fl319x_chip *is31;
@@ -511,7 +516,7 @@ static int is31fl319x_probe(struct i2c_client *client)
return -ENOMEM;
mutex_init(&is31->lock);
- err = devm_add_action(dev, (void (*)(void *))mutex_destroy, &is31->lock);
+ err = devm_add_action_or_reset(dev, is31f1319x_mutex_destroy, &is31->lock);
if (err)
return err;
diff --git a/drivers/leds/leds-is31fl32xx.c b/drivers/leds/leds-is31fl32xx.c
index 0d219c1ac3b5..799191859ce0 100644
--- a/drivers/leds/leds-is31fl32xx.c
+++ b/drivers/leds/leds-is31fl32xx.c
@@ -422,8 +422,7 @@ static const struct of_device_id of_is31fl32xx_match[] = {
MODULE_DEVICE_TABLE(of, of_is31fl32xx_match);
-static int is31fl32xx_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int is31fl32xx_probe(struct i2c_client *client)
{
const struct is31fl32xx_chipdef *cdef;
struct device *dev = &client->dev;
@@ -489,7 +488,7 @@ static struct i2c_driver is31fl32xx_driver = {
.name = "is31fl32xx",
.of_match_table = of_is31fl32xx_match,
},
- .probe = is31fl32xx_probe,
+ .probe_new = is31fl32xx_probe,
.remove = is31fl32xx_remove,
.id_table = is31fl32xx_id,
};
diff --git a/drivers/leds/leds-lm3530.c b/drivers/leds/leds-lm3530.c
index ba906c253c7f..a9a2018592ff 100644
--- a/drivers/leds/leds-lm3530.c
+++ b/drivers/leds/leds-lm3530.c
@@ -405,8 +405,7 @@ static struct attribute *lm3530_attrs[] = {
};
ATTRIBUTE_GROUPS(lm3530);
-static int lm3530_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int lm3530_probe(struct i2c_client *client)
{
struct lm3530_platform_data *pdata = dev_get_platdata(&client->dev);
struct lm3530_data *drvdata;
@@ -485,7 +484,7 @@ static const struct i2c_device_id lm3530_id[] = {
MODULE_DEVICE_TABLE(i2c, lm3530_id);
static struct i2c_driver lm3530_i2c_driver = {
- .probe = lm3530_probe,
+ .probe_new = lm3530_probe,
.remove = lm3530_remove,
.id_table = lm3530_id,
.driver = {
diff --git a/drivers/leds/leds-lm3532.c b/drivers/leds/leds-lm3532.c
index db64d44bcbbf..a08c09129a68 100644
--- a/drivers/leds/leds-lm3532.c
+++ b/drivers/leds/leds-lm3532.c
@@ -663,8 +663,7 @@ child_out:
return ret;
}
-static int lm3532_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int lm3532_probe(struct i2c_client *client)
{
struct lm3532_data *drvdata;
int ret = 0;
@@ -727,7 +726,7 @@ static const struct i2c_device_id lm3532_id[] = {
MODULE_DEVICE_TABLE(i2c, lm3532_id);
static struct i2c_driver lm3532_i2c_driver = {
- .probe = lm3532_probe,
+ .probe_new = lm3532_probe,
.remove = lm3532_remove,
.id_table = lm3532_id,
.driver = {
diff --git a/drivers/leds/leds-lm355x.c b/drivers/leds/leds-lm355x.c
index daa35927b301..612873070ca4 100644
--- a/drivers/leds/leds-lm355x.c
+++ b/drivers/leds/leds-lm355x.c
@@ -396,9 +396,9 @@ static const struct regmap_config lm355x_regmap = {
};
/* module initialize */
-static int lm355x_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int lm355x_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct lm355x_platform_data *pdata = dev_get_platdata(&client->dev);
struct lm355x_chip_data *chip;
@@ -516,7 +516,7 @@ static struct i2c_driver lm355x_i2c_driver = {
.name = LM355x_NAME,
.pm = NULL,
},
- .probe = lm355x_probe,
+ .probe_new = lm355x_probe,
.remove = lm355x_remove,
.id_table = lm355x_id,
};
diff --git a/drivers/leds/leds-lm3642.c b/drivers/leds/leds-lm3642.c
index 428a5d928150..b75ee3546c2e 100644
--- a/drivers/leds/leds-lm3642.c
+++ b/drivers/leds/leds-lm3642.c
@@ -289,8 +289,7 @@ static struct attribute *lm3642_torch_attrs[] = {
};
ATTRIBUTE_GROUPS(lm3642_torch);
-static int lm3642_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int lm3642_probe(struct i2c_client *client)
{
struct lm3642_platform_data *pdata = dev_get_platdata(&client->dev);
struct lm3642_chip_data *chip;
@@ -402,7 +401,7 @@ static struct i2c_driver lm3642_i2c_driver = {
.name = LM3642_NAME,
.pm = NULL,
},
- .probe = lm3642_probe,
+ .probe_new = lm3642_probe,
.remove = lm3642_remove,
.id_table = lm3642_id,
};
diff --git a/drivers/leds/leds-lm3692x.c b/drivers/leds/leds-lm3692x.c
index 54b4662bff41..66126d0666f5 100644
--- a/drivers/leds/leds-lm3692x.c
+++ b/drivers/leds/leds-lm3692x.c
@@ -456,9 +456,9 @@ static int lm3692x_probe_dt(struct lm3692x_led *led)
return ret;
}
-static int lm3692x_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int lm3692x_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct lm3692x_led *led;
int ret;
@@ -518,7 +518,7 @@ static struct i2c_driver lm3692x_driver = {
.name = "lm3692x",
.of_match_table = of_lm3692x_leds_match,
},
- .probe = lm3692x_probe,
+ .probe_new = lm3692x_probe,
.remove = lm3692x_remove,
.id_table = lm3692x_id,
};
diff --git a/drivers/leds/leds-lm3697.c b/drivers/leds/leds-lm3697.c
index 71231a60eebc..10e904bf40a0 100644
--- a/drivers/leds/leds-lm3697.c
+++ b/drivers/leds/leds-lm3697.c
@@ -299,8 +299,7 @@ child_out:
return ret;
}
-static int lm3697_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int lm3697_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct lm3697 *led;
@@ -377,7 +376,7 @@ static struct i2c_driver lm3697_driver = {
.name = "lm3697",
.of_match_table = of_lm3697_leds_match,
},
- .probe = lm3697_probe,
+ .probe_new = lm3697_probe,
.remove = lm3697_remove,
.id_table = lm3697_id,
};
diff --git a/drivers/leds/leds-lp3944.c b/drivers/leds/leds-lp3944.c
index 673ad8c04f41..be47c66b2e00 100644
--- a/drivers/leds/leds-lp3944.c
+++ b/drivers/leds/leds-lp3944.c
@@ -359,8 +359,7 @@ exit:
return err;
}
-static int lp3944_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int lp3944_probe(struct i2c_client *client)
{
struct lp3944_platform_data *lp3944_pdata =
dev_get_platdata(&client->dev);
@@ -428,7 +427,7 @@ static struct i2c_driver lp3944_driver = {
.driver = {
.name = "lp3944",
},
- .probe = lp3944_probe,
+ .probe_new = lp3944_probe,
.remove = lp3944_remove,
.id_table = lp3944_id,
};
diff --git a/drivers/leds/leds-lp3952.c b/drivers/leds/leds-lp3952.c
index bf0ad1b5ce24..24b2e0f9080d 100644
--- a/drivers/leds/leds-lp3952.c
+++ b/drivers/leds/leds-lp3952.c
@@ -207,8 +207,7 @@ static const struct regmap_config lp3952_regmap = {
.cache_type = REGCACHE_RBTREE,
};
-static int lp3952_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int lp3952_probe(struct i2c_client *client)
{
int status;
struct lp3952_led_array *priv;
@@ -274,7 +273,7 @@ static struct i2c_driver lp3952_i2c_driver = {
.driver = {
.name = LP3952_NAME,
},
- .probe = lp3952_probe,
+ .probe_new = lp3952_probe,
.remove = lp3952_remove,
.id_table = lp3952_id,
};
diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c
index 19478d9c19a7..a004af8e22c7 100644
--- a/drivers/leds/leds-lp5521.c
+++ b/drivers/leds/leds-lp5521.c
@@ -516,9 +516,9 @@ static struct lp55xx_device_config lp5521_cfg = {
.dev_attr_group = &lp5521_group,
};
-static int lp5521_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int lp5521_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
int ret;
struct lp55xx_chip *chip;
struct lp55xx_led *led;
@@ -608,7 +608,7 @@ static struct i2c_driver lp5521_driver = {
.name = "lp5521",
.of_match_table = of_match_ptr(of_lp5521_leds_match),
},
- .probe = lp5521_probe,
+ .probe_new = lp5521_probe,
.remove = lp5521_remove,
.id_table = lp5521_id,
};
diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c
index e08e3de1428d..55da914b8e5c 100644
--- a/drivers/leds/leds-lp5523.c
+++ b/drivers/leds/leds-lp5523.c
@@ -887,9 +887,9 @@ static struct lp55xx_device_config lp5523_cfg = {
.dev_attr_group = &lp5523_group,
};
-static int lp5523_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int lp5523_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
int ret;
struct lp55xx_chip *chip;
struct lp55xx_led *led;
@@ -983,7 +983,7 @@ static struct i2c_driver lp5523_driver = {
.name = "lp5523x",
.of_match_table = of_match_ptr(of_lp5523_leds_match),
},
- .probe = lp5523_probe,
+ .probe_new = lp5523_probe,
.remove = lp5523_remove,
.id_table = lp5523_id,
};
diff --git a/drivers/leds/leds-lp5562.c b/drivers/leds/leds-lp5562.c
index 0e490085ff35..b5d877faf6d7 100644
--- a/drivers/leds/leds-lp5562.c
+++ b/drivers/leds/leds-lp5562.c
@@ -511,8 +511,7 @@ static struct lp55xx_device_config lp5562_cfg = {
.dev_attr_group = &lp5562_group,
};
-static int lp5562_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int lp5562_probe(struct i2c_client *client)
{
int ret;
struct lp55xx_chip *chip;
@@ -604,7 +603,7 @@ static struct i2c_driver lp5562_driver = {
.name = "lp5562",
.of_match_table = of_match_ptr(of_lp5562_leds_match),
},
- .probe = lp5562_probe,
+ .probe_new = lp5562_probe,
.remove = lp5562_remove,
.id_table = lp5562_id,
};
diff --git a/drivers/leds/leds-lp8501.c b/drivers/leds/leds-lp8501.c
index ae11a02c0ab2..165d6423a928 100644
--- a/drivers/leds/leds-lp8501.c
+++ b/drivers/leds/leds-lp8501.c
@@ -299,9 +299,9 @@ static struct lp55xx_device_config lp8501_cfg = {
.run_engine = lp8501_run_engine,
};
-static int lp8501_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int lp8501_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
int ret;
struct lp55xx_chip *chip;
struct lp55xx_led *led;
@@ -392,7 +392,7 @@ static struct i2c_driver lp8501_driver = {
.name = "lp8501",
.of_match_table = of_match_ptr(of_lp8501_leds_match),
},
- .probe = lp8501_probe,
+ .probe_new = lp8501_probe,
.remove = lp8501_remove,
.id_table = lp8501_id,
};
diff --git a/drivers/leds/leds-lp8860.c b/drivers/leds/leds-lp8860.c
index e2b36d3187eb..b66ed5ac1aa5 100644
--- a/drivers/leds/leds-lp8860.c
+++ b/drivers/leds/leds-lp8860.c
@@ -375,8 +375,7 @@ static const struct regmap_config lp8860_eeprom_regmap_config = {
.cache_type = REGCACHE_NONE,
};
-static int lp8860_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int lp8860_probe(struct i2c_client *client)
{
int ret;
struct lp8860_led *led;
@@ -480,7 +479,7 @@ static struct i2c_driver lp8860_driver = {
.name = "lp8860",
.of_match_table = of_lp8860_leds_match,
},
- .probe = lp8860_probe,
+ .probe_new = lp8860_probe,
.remove = lp8860_remove,
.id_table = lp8860_id,
};
diff --git a/drivers/leds/leds-mt6323.c b/drivers/leds/leds-mt6323.c
index f59e0e8bda8b..17ee88043f52 100644
--- a/drivers/leds/leds-mt6323.c
+++ b/drivers/leds/leds-mt6323.c
@@ -339,23 +339,23 @@ static int mt6323_led_set_dt_default(struct led_classdev *cdev,
struct device_node *np)
{
struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
- const char *state;
+ enum led_default_state state;
int ret = 0;
- state = of_get_property(np, "default-state", NULL);
- if (state) {
- if (!strcmp(state, "keep")) {
- ret = mt6323_get_led_hw_brightness(cdev);
- if (ret < 0)
- return ret;
- led->current_brightness = ret;
- ret = 0;
- } else if (!strcmp(state, "on")) {
- ret =
- mt6323_led_set_brightness(cdev, cdev->max_brightness);
- } else {
- ret = mt6323_led_set_brightness(cdev, LED_OFF);
- }
+ state = led_init_default_state_get(of_fwnode_handle(np));
+ switch (state) {
+ case LEDS_DEFSTATE_ON:
+ ret = mt6323_led_set_brightness(cdev, cdev->max_brightness);
+ break;
+ case LEDS_DEFSTATE_KEEP:
+ ret = mt6323_get_led_hw_brightness(cdev);
+ if (ret < 0)
+ return ret;
+ led->current_brightness = ret;
+ ret = 0;
+ break;
+ default:
+ ret = mt6323_led_set_brightness(cdev, LED_OFF);
}
return ret;
diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c
index df83d97cb479..15b1acfa442e 100644
--- a/drivers/leds/leds-pca9532.c
+++ b/drivers/leds/leds-pca9532.c
@@ -50,8 +50,7 @@ struct pca9532_data {
u8 psc[2];
};
-static int pca9532_probe(struct i2c_client *client,
- const struct i2c_device_id *id);
+static int pca9532_probe(struct i2c_client *client);
static void pca9532_remove(struct i2c_client *client);
enum {
@@ -103,7 +102,7 @@ static struct i2c_driver pca9532_driver = {
.name = "leds-pca953x",
.of_match_table = of_match_ptr(of_pca9532_leds_match),
},
- .probe = pca9532_probe,
+ .probe_new = pca9532_probe,
.remove = pca9532_remove,
.id_table = pca9532_id,
};
@@ -504,9 +503,9 @@ pca9532_of_populate_pdata(struct device *dev, struct device_node *np)
return pdata;
}
-static int pca9532_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int pca9532_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
int devid;
struct pca9532_data *data = i2c_get_clientdata(client);
struct pca9532_platform_data *pca9532_pdata =
diff --git a/drivers/leds/leds-pca955x.c b/drivers/leds/leds-pca955x.c
index 33ec4543fb4f..1edd092e7894 100644
--- a/drivers/leds/leds-pca955x.c
+++ b/drivers/leds/leds-pca955x.c
@@ -130,7 +130,7 @@ struct pca955x_led {
struct led_classdev led_cdev;
int led_num; /* 0 .. 15 potentially */
u32 type;
- int default_state;
+ enum led_default_state default_state;
struct fwnode_handle *fwnode;
};
@@ -437,7 +437,6 @@ pca955x_get_pdata(struct i2c_client *client, struct pca955x_chipdef *chip)
return ERR_PTR(-ENOMEM);
device_for_each_child_node(&client->dev, child) {
- const char *state;
u32 reg;
int res;
@@ -448,19 +447,9 @@ pca955x_get_pdata(struct i2c_client *client, struct pca955x_chipdef *chip)
led = &pdata->leds[reg];
led->type = PCA955X_TYPE_LED;
led->fwnode = child;
- fwnode_property_read_u32(child, "type", &led->type);
+ led->default_state = led_init_default_state_get(child);
- if (!fwnode_property_read_string(child, "default-state",
- &state)) {
- if (!strcmp(state, "keep"))
- led->default_state = LEDS_GPIO_DEFSTATE_KEEP;
- else if (!strcmp(state, "on"))
- led->default_state = LEDS_GPIO_DEFSTATE_ON;
- else
- led->default_state = LEDS_GPIO_DEFSTATE_OFF;
- } else {
- led->default_state = LEDS_GPIO_DEFSTATE_OFF;
- }
+ fwnode_property_read_u32(child, "type", &led->type);
}
pdata->num_leds = chip->bits;
@@ -572,13 +561,11 @@ static int pca955x_probe(struct i2c_client *client)
led->brightness_set_blocking = pca955x_led_set;
led->brightness_get = pca955x_led_get;
- if (pdata->leds[i].default_state ==
- LEDS_GPIO_DEFSTATE_OFF) {
+ if (pdata->leds[i].default_state == LEDS_DEFSTATE_OFF) {
err = pca955x_led_set(led, LED_OFF);
if (err)
return err;
- } else if (pdata->leds[i].default_state ==
- LEDS_GPIO_DEFSTATE_ON) {
+ } else if (pdata->leds[i].default_state == LEDS_DEFSTATE_ON) {
err = pca955x_led_set(led, LED_FULL);
if (err)
return err;
@@ -617,8 +604,7 @@ static int pca955x_probe(struct i2c_client *client)
* brightness to see if it's using PWM1. If so, PWM1
* should not be written below.
*/
- if (pdata->leds[i].default_state ==
- LEDS_GPIO_DEFSTATE_KEEP) {
+ if (pdata->leds[i].default_state == LEDS_DEFSTATE_KEEP) {
if (led->brightness != LED_FULL &&
led->brightness != LED_OFF &&
led->brightness != LED_HALF)
diff --git a/drivers/leds/leds-pca963x.c b/drivers/leds/leds-pca963x.c
index a7e052c1db53..9cd476db601f 100644
--- a/drivers/leds/leds-pca963x.c
+++ b/drivers/leds/leds-pca963x.c
@@ -389,9 +389,9 @@ static const struct of_device_id of_pca963x_match[] = {
};
MODULE_DEVICE_TABLE(of, of_pca963x_match);
-static int pca963x_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int pca963x_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct device *dev = &client->dev;
struct pca963x_chipdef *chipdef;
struct pca963x *chip;
@@ -431,7 +431,7 @@ static struct i2c_driver pca963x_driver = {
.name = "leds-pca963x",
.of_match_table = of_pca963x_match,
},
- .probe = pca963x_probe,
+ .probe_new = pca963x_probe,
.id_table = pca963x_id,
};
diff --git a/drivers/leds/leds-pm8058.c b/drivers/leds/leds-pm8058.c
index fb2ab72c0c40..b9233f14b646 100644
--- a/drivers/leds/leds-pm8058.c
+++ b/drivers/leds/leds-pm8058.c
@@ -93,8 +93,8 @@ static int pm8058_led_probe(struct platform_device *pdev)
struct device_node *np;
int ret;
struct regmap *map;
- const char *state;
enum led_brightness maxbright;
+ enum led_default_state state;
led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
if (!led)
@@ -125,25 +125,26 @@ static int pm8058_led_probe(struct platform_device *pdev)
maxbright = 15; /* 4 bits */
led->cdev.max_brightness = maxbright;
- state = of_get_property(np, "default-state", NULL);
- if (state) {
- if (!strcmp(state, "keep")) {
- led->cdev.brightness = pm8058_led_get(&led->cdev);
- } else if (!strcmp(state, "on")) {
- led->cdev.brightness = maxbright;
- pm8058_led_set(&led->cdev, maxbright);
- } else {
- led->cdev.brightness = LED_OFF;
- pm8058_led_set(&led->cdev, LED_OFF);
- }
+ init_data.fwnode = of_fwnode_handle(np);
+
+ state = led_init_default_state_get(init_data.fwnode);
+ switch (state) {
+ case LEDS_DEFSTATE_ON:
+ led->cdev.brightness = maxbright;
+ pm8058_led_set(&led->cdev, maxbright);
+ break;
+ case LEDS_DEFSTATE_KEEP:
+ led->cdev.brightness = pm8058_led_get(&led->cdev);
+ break;
+ default:
+ led->cdev.brightness = LED_OFF;
+ pm8058_led_set(&led->cdev, LED_OFF);
}
if (led->ledtype == PM8058_LED_TYPE_KEYPAD ||
led->ledtype == PM8058_LED_TYPE_FLASH)
led->cdev.flags = LED_CORE_SUSPENDRESUME;
- init_data.fwnode = of_fwnode_handle(np);
-
ret = devm_led_classdev_register_ext(dev, &led->cdev, &init_data);
if (ret)
dev_err(dev, "Failed to register LED for %pOF\n", np);
diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c
index 6832180c1c54..29194cc382af 100644
--- a/drivers/leds/leds-pwm.c
+++ b/drivers/leds/leds-pwm.c
@@ -138,9 +138,9 @@ static int led_pwm_create_fwnode(struct device *dev, struct led_pwm_priv *priv)
struct led_pwm led;
int ret;
- memset(&led, 0, sizeof(led));
-
device_for_each_child_node(dev, fwnode) {
+ memset(&led, 0, sizeof(led));
+
ret = fwnode_property_read_string(fwnode, "label", &led.name);
if (ret && is_of_node(fwnode))
led.name = to_of_node(fwnode)->name;
diff --git a/drivers/leds/leds-syscon.c b/drivers/leds/leds-syscon.c
index 7eddb8ecb44e..e38abb5e60c1 100644
--- a/drivers/leds/leds-syscon.c
+++ b/drivers/leds/leds-syscon.c
@@ -61,7 +61,8 @@ static int syscon_led_probe(struct platform_device *pdev)
struct device *parent;
struct regmap *map;
struct syscon_led *sled;
- const char *state;
+ enum led_default_state state;
+ u32 value;
int ret;
parent = dev->parent;
@@ -86,34 +87,30 @@ static int syscon_led_probe(struct platform_device *pdev)
if (of_property_read_u32(np, "mask", &sled->mask))
return -EINVAL;
- state = of_get_property(np, "default-state", NULL);
- if (state) {
- if (!strcmp(state, "keep")) {
- u32 val;
-
- ret = regmap_read(map, sled->offset, &val);
- if (ret < 0)
- return ret;
- sled->state = !!(val & sled->mask);
- } else if (!strcmp(state, "on")) {
- sled->state = true;
- ret = regmap_update_bits(map, sled->offset,
- sled->mask,
- sled->mask);
- if (ret < 0)
- return ret;
- } else {
- sled->state = false;
- ret = regmap_update_bits(map, sled->offset,
- sled->mask, 0);
- if (ret < 0)
- return ret;
- }
+ init_data.fwnode = of_fwnode_handle(np);
+
+ state = led_init_default_state_get(init_data.fwnode);
+ switch (state) {
+ case LEDS_DEFSTATE_ON:
+ ret = regmap_update_bits(map, sled->offset, sled->mask, sled->mask);
+ if (ret < 0)
+ return ret;
+ sled->state = true;
+ break;
+ case LEDS_DEFSTATE_KEEP:
+ ret = regmap_read(map, sled->offset, &value);
+ if (ret < 0)
+ return ret;
+ sled->state = !!(value & sled->mask);
+ break;
+ default:
+ ret = regmap_update_bits(map, sled->offset, sled->mask, 0);
+ if (ret < 0)
+ return ret;
+ sled->state = false;
}
sled->cdev.brightness_set = syscon_led_set;
- init_data.fwnode = of_fwnode_handle(np);
-
ret = devm_led_classdev_register_ext(dev, &sled->cdev, &init_data);
if (ret < 0)
return ret;
diff --git a/drivers/leds/leds-tca6507.c b/drivers/leds/leds-tca6507.c
index 161bef65c6b7..07dd12686a69 100644
--- a/drivers/leds/leds-tca6507.c
+++ b/drivers/leds/leds-tca6507.c
@@ -695,8 +695,7 @@ tca6507_led_dt_init(struct device *dev)
&led.default_trigger);
led.flags = 0;
- if (fwnode_property_match_string(child, "compatible",
- "gpio") >= 0)
+ if (fwnode_device_is_compatible(child, "gpio"))
led.flags |= TCA6507_MAKE_GPIO;
ret = fwnode_property_read_u32(child, "reg", &reg);
@@ -728,8 +727,7 @@ static const struct of_device_id __maybe_unused of_tca6507_leds_match[] = {
};
MODULE_DEVICE_TABLE(of, of_tca6507_leds_match);
-static int tca6507_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int tca6507_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct i2c_adapter *adapter;
@@ -809,7 +807,7 @@ static struct i2c_driver tca6507_driver = {
.name = "leds-tca6507",
.of_match_table = of_match_ptr(of_tca6507_leds_match),
},
- .probe = tca6507_probe,
+ .probe_new = tca6507_probe,
.remove = tca6507_remove,
.id_table = tca6507_id,
};
diff --git a/drivers/leds/leds-tlc591xx.c b/drivers/leds/leds-tlc591xx.c
index cb7bd1353f9f..ec25e0c16bea 100644
--- a/drivers/leds/leds-tlc591xx.c
+++ b/drivers/leds/leds-tlc591xx.c
@@ -145,8 +145,7 @@ static const struct of_device_id of_tlc591xx_leds_match[] = {
MODULE_DEVICE_TABLE(of, of_tlc591xx_leds_match);
static int
-tlc591xx_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+tlc591xx_probe(struct i2c_client *client)
{
struct device_node *np, *child;
struct device *dev = &client->dev;
@@ -231,7 +230,7 @@ static struct i2c_driver tlc591xx_driver = {
.name = "tlc591xx",
.of_match_table = of_match_ptr(of_tlc591xx_leds_match),
},
- .probe = tlc591xx_probe,
+ .probe_new = tlc591xx_probe,
.id_table = tlc591xx_id,
};
diff --git a/drivers/leds/leds-turris-omnia.c b/drivers/leds/leds-turris-omnia.c
index c7c9851c894a..013f551b32b2 100644
--- a/drivers/leds/leds-turris-omnia.c
+++ b/drivers/leds/leds-turris-omnia.c
@@ -201,8 +201,7 @@ static struct attribute *omnia_led_controller_attrs[] = {
};
ATTRIBUTE_GROUPS(omnia_led_controller);
-static int omnia_leds_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int omnia_leds_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct device_node *np = dev_of_node(dev), *child;
@@ -272,7 +271,7 @@ static const struct i2c_device_id omnia_id[] = {
MODULE_DEVICE_TABLE(i2c, omnia_id);
static struct i2c_driver omnia_leds_driver = {
- .probe = omnia_leds_probe,
+ .probe_new = omnia_leds_probe,
.remove = omnia_leds_remove,
.id_table = omnia_id,
.driver = {
diff --git a/drivers/leds/leds.h b/drivers/leds/leds.h
index aa64757a4d89..345062ccabda 100644
--- a/drivers/leds/leds.h
+++ b/drivers/leds/leds.h
@@ -27,7 +27,6 @@ ssize_t led_trigger_read(struct file *filp, struct kobject *kobj,
ssize_t led_trigger_write(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr, char *buf,
loff_t pos, size_t count);
-enum led_default_state led_init_default_state_get(struct fwnode_handle *fwnode);
extern struct rw_semaphore leds_list_lock;
extern struct list_head leds_list;
diff --git a/drivers/leds/simple/simatic-ipc-leds-gpio.c b/drivers/leds/simple/simatic-ipc-leds-gpio.c
index 07f0d79d604d..e8d329b5a68c 100644
--- a/drivers/leds/simple/simatic-ipc-leds-gpio.c
+++ b/drivers/leds/simple/simatic-ipc-leds-gpio.c
@@ -77,6 +77,8 @@ static int simatic_ipc_leds_gpio_probe(struct platform_device *pdev)
switch (plat->devmode) {
case SIMATIC_IPC_DEVICE_127E:
+ if (!IS_ENABLED(CONFIG_PINCTRL_BROXTON))
+ return -ENODEV;
simatic_ipc_led_gpio_table = &simatic_ipc_led_gpio_table_127e;
break;
case SIMATIC_IPC_DEVICE_227G:
diff --git a/drivers/leds/trigger/ledtrig-disk.c b/drivers/leds/trigger/ledtrig-disk.c
index 0741910785bb..0b7dfbd04273 100644
--- a/drivers/leds/trigger/ledtrig-disk.c
+++ b/drivers/leds/trigger/ledtrig-disk.c
@@ -16,7 +16,6 @@
DEFINE_LED_TRIGGER(ledtrig_disk);
DEFINE_LED_TRIGGER(ledtrig_disk_read);
DEFINE_LED_TRIGGER(ledtrig_disk_write);
-DEFINE_LED_TRIGGER(ledtrig_ide);
void ledtrig_disk_activity(bool write)
{
@@ -24,8 +23,6 @@ void ledtrig_disk_activity(bool write)
led_trigger_blink_oneshot(ledtrig_disk,
&blink_delay, &blink_delay, 0);
- led_trigger_blink_oneshot(ledtrig_ide,
- &blink_delay, &blink_delay, 0);
if (write)
led_trigger_blink_oneshot(ledtrig_disk_write,
&blink_delay, &blink_delay, 0);
@@ -40,7 +37,6 @@ static int __init ledtrig_disk_init(void)
led_trigger_register_simple("disk-activity", &ledtrig_disk);
led_trigger_register_simple("disk-read", &ledtrig_disk_read);
led_trigger_register_simple("disk-write", &ledtrig_disk_write);
- led_trigger_register_simple("ide-disk", &ledtrig_ide);
return 0;
}
diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c
index 3bc1f374e657..211ed9aa9edc 100644
--- a/drivers/macintosh/macio_asic.c
+++ b/drivers/macintosh/macio_asic.c
@@ -128,12 +128,17 @@ static int macio_device_resume(struct device * dev)
return 0;
}
+static int macio_device_modalias(const struct device *dev, struct kobj_uevent_env *env)
+{
+ return of_device_uevent_modalias(dev, env);
+}
+
extern const struct attribute_group *macio_dev_groups[];
struct bus_type macio_bus_type = {
.name = "macio",
.match = macio_bus_match,
- .uevent = of_device_uevent_modalias,
+ .uevent = macio_device_modalias,
.probe = macio_device_probe,
.remove = macio_device_remove,
.shutdown = macio_device_shutdown,
diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c
index 24f0a444d312..9c6febce2376 100644
--- a/drivers/macintosh/windfarm_lm75_sensor.c
+++ b/drivers/macintosh/windfarm_lm75_sensor.c
@@ -33,8 +33,8 @@
#endif
struct wf_lm75_sensor {
- int ds1775 : 1;
- int inited : 1;
+ unsigned int ds1775 : 1;
+ unsigned int inited : 1;
struct i2c_client *i2c;
struct wf_sensor sens;
};
diff --git a/drivers/macintosh/windfarm_smu_sensors.c b/drivers/macintosh/windfarm_smu_sensors.c
index 00c6fe25fcba..2bdb73b34d29 100644
--- a/drivers/macintosh/windfarm_smu_sensors.c
+++ b/drivers/macintosh/windfarm_smu_sensors.c
@@ -274,8 +274,8 @@ struct smu_cpu_power_sensor {
struct list_head link;
struct wf_sensor *volts;
struct wf_sensor *amps;
- int fake_volts : 1;
- int quadratic : 1;
+ unsigned int fake_volts : 1;
+ unsigned int quadratic : 1;
struct wf_sensor sens;
};
#define to_smu_cpu_power(c) container_of(c, struct smu_cpu_power_sensor, sens)
diff --git a/drivers/mailbox/qcom-apcs-ipc-mailbox.c b/drivers/mailbox/qcom-apcs-ipc-mailbox.c
index 0e9f9cba8668..6bbf87c6d60b 100644
--- a/drivers/mailbox/qcom-apcs-ipc-mailbox.c
+++ b/drivers/mailbox/qcom-apcs-ipc-mailbox.c
@@ -42,7 +42,7 @@ static const struct qcom_apcs_ipc_data msm8994_apcs_data = {
};
static const struct qcom_apcs_ipc_data msm8996_apcs_data = {
- .offset = 16, .clk_name = NULL
+ .offset = 16, .clk_name = "qcom-apcs-msm8996-clk"
};
static const struct qcom_apcs_ipc_data apps_shared_apcs_data = {
@@ -141,6 +141,7 @@ static int qcom_apcs_ipc_remove(struct platform_device *pdev)
/* .data is the offset of the ipc register within the global block */
static const struct of_device_id qcom_apcs_ipc_of_match[] = {
+ { .compatible = "qcom,ipq5332-apcs-apps-global", .data = &ipq6018_apcs_data },
{ .compatible = "qcom,ipq6018-apcs-apps-global", .data = &ipq6018_apcs_data },
{ .compatible = "qcom,ipq8074-apcs-apps-global", .data = &ipq6018_apcs_data },
{ .compatible = "qcom,msm8916-apcs-kpss-global", .data = &msm8916_apcs_data },
diff --git a/drivers/mailbox/zynqmp-ipi-mailbox.c b/drivers/mailbox/zynqmp-ipi-mailbox.c
index 12e004ff1a14..a4c8d23c76e2 100644
--- a/drivers/mailbox/zynqmp-ipi-mailbox.c
+++ b/drivers/mailbox/zynqmp-ipi-mailbox.c
@@ -110,7 +110,7 @@ struct zynqmp_ipi_pdata {
unsigned int method;
u32 local_id;
int num_mboxes;
- struct zynqmp_ipi_mbox *ipi_mboxes;
+ struct zynqmp_ipi_mbox ipi_mboxes[];
};
static struct device_driver zynqmp_ipi_mbox_driver = {
@@ -635,7 +635,7 @@ static int zynqmp_ipi_probe(struct platform_device *pdev)
int num_mboxes, ret = -EINVAL;
num_mboxes = of_get_child_count(np);
- pdata = devm_kzalloc(dev, sizeof(*pdata) + (num_mboxes * sizeof(*mbox)),
+ pdata = devm_kzalloc(dev, struct_size(pdata, ipi_mboxes, num_mboxes),
GFP_KERNEL);
if (!pdata)
return -ENOMEM;
@@ -649,8 +649,6 @@ static int zynqmp_ipi_probe(struct platform_device *pdev)
}
pdata->num_mboxes = num_mboxes;
- pdata->ipi_mboxes = (struct zynqmp_ipi_mbox *)
- ((char *)pdata + sizeof(*pdata));
mbox = pdata->ipi_mboxes;
for_each_available_child_of_node(np, nc) {
diff --git a/drivers/mcb/mcb-core.c b/drivers/mcb/mcb-core.c
index b8ad4f16b4ac..978fdfc19a06 100644
--- a/drivers/mcb/mcb-core.c
+++ b/drivers/mcb/mcb-core.c
@@ -41,9 +41,9 @@ static int mcb_match(struct device *dev, struct device_driver *drv)
return 0;
}
-static int mcb_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int mcb_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct mcb_device *mdev = to_mcb_device(dev);
+ const struct mcb_device *mdev = to_mcb_device(dev);
int ret;
ret = add_uevent_var(env, "MODALIAS=mcb:16z%03d", mdev->id);
diff --git a/drivers/md/bcache/bcache_ondisk.h b/drivers/md/bcache/bcache_ondisk.h
index f96034e0ba4f..6620a7f8fffc 100644
--- a/drivers/md/bcache/bcache_ondisk.h
+++ b/drivers/md/bcache/bcache_ondisk.h
@@ -360,8 +360,8 @@ struct jset {
__u64 prio_bucket[MAX_CACHES_PER_SET];
union {
- struct bkey start[0];
- __u64 d[0];
+ DECLARE_FLEX_ARRAY(struct bkey, start);
+ DECLARE_FLEX_ARRAY(__u64, d);
};
};
@@ -425,8 +425,8 @@ struct bset {
__u32 keys;
union {
- struct bkey start[0];
- __u64 d[0];
+ DECLARE_FLEX_ARRAY(struct bkey, start);
+ DECLARE_FLEX_ARRAY(__u64, d);
};
};
diff --git a/drivers/md/dm-audit.c b/drivers/md/dm-audit.c
index 3049dfe67e50..2e979eeb1116 100644
--- a/drivers/md/dm-audit.c
+++ b/drivers/md/dm-audit.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Creating audit records for mapped devices.
*
diff --git a/drivers/md/dm-bio-prison-v1.c b/drivers/md/dm-bio-prison-v1.c
index 1f8f98efd97a..c4c05d5d8909 100644
--- a/drivers/md/dm-bio-prison-v1.c
+++ b/drivers/md/dm-bio-prison-v1.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Red Hat, Inc.
*
@@ -77,9 +78,9 @@ static void __setup_new_cell(struct dm_cell_key *key,
struct bio *holder,
struct dm_bio_prison_cell *cell)
{
- memcpy(&cell->key, key, sizeof(cell->key));
- cell->holder = holder;
- bio_list_init(&cell->bios);
+ memcpy(&cell->key, key, sizeof(cell->key));
+ cell->holder = holder;
+ bio_list_init(&cell->bios);
}
static int cmp_keys(struct dm_cell_key *lhs,
@@ -285,14 +286,14 @@ EXPORT_SYMBOL_GPL(dm_cell_promote_or_release);
struct dm_deferred_entry {
struct dm_deferred_set *ds;
- unsigned count;
+ unsigned int count;
struct list_head work_items;
};
struct dm_deferred_set {
spinlock_t lock;
- unsigned current_entry;
- unsigned sweeper;
+ unsigned int current_entry;
+ unsigned int sweeper;
struct dm_deferred_entry entries[DEFERRED_SET_SIZE];
};
@@ -338,7 +339,7 @@ struct dm_deferred_entry *dm_deferred_entry_inc(struct dm_deferred_set *ds)
}
EXPORT_SYMBOL_GPL(dm_deferred_entry_inc);
-static unsigned ds_next(unsigned index)
+static unsigned int ds_next(unsigned int index)
{
return (index + 1) % DEFERRED_SET_SIZE;
}
@@ -373,7 +374,7 @@ EXPORT_SYMBOL_GPL(dm_deferred_entry_dec);
int dm_deferred_set_add_work(struct dm_deferred_set *ds, struct list_head *work)
{
int r = 1;
- unsigned next_entry;
+ unsigned int next_entry;
spin_lock_irq(&ds->lock);
if ((ds->sweeper == ds->current_entry) &&
@@ -432,7 +433,7 @@ static int __init dm_bio_prison_init(void)
return 0;
- bad:
+bad:
while (i--)
_exits[i]();
diff --git a/drivers/md/dm-bio-prison-v1.h b/drivers/md/dm-bio-prison-v1.h
index cec52ac5e1ae..dfbf1e94cb75 100644
--- a/drivers/md/dm-bio-prison-v1.h
+++ b/drivers/md/dm-bio-prison-v1.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2011-2017 Red Hat, Inc.
*
diff --git a/drivers/md/dm-bio-prison-v2.c b/drivers/md/dm-bio-prison-v2.c
index 9dec3b61cf70..fd852981ef9c 100644
--- a/drivers/md/dm-bio-prison-v2.c
+++ b/drivers/md/dm-bio-prison-v2.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012-2017 Red Hat, Inc.
*
@@ -148,7 +149,7 @@ static bool __find_or_insert(struct dm_bio_prison_v2 *prison,
static bool __get(struct dm_bio_prison_v2 *prison,
struct dm_cell_key_v2 *key,
- unsigned lock_level,
+ unsigned int lock_level,
struct bio *inmate,
struct dm_bio_prison_cell_v2 *cell_prealloc,
struct dm_bio_prison_cell_v2 **cell)
@@ -171,7 +172,7 @@ static bool __get(struct dm_bio_prison_v2 *prison,
bool dm_cell_get_v2(struct dm_bio_prison_v2 *prison,
struct dm_cell_key_v2 *key,
- unsigned lock_level,
+ unsigned int lock_level,
struct bio *inmate,
struct dm_bio_prison_cell_v2 *cell_prealloc,
struct dm_bio_prison_cell_v2 **cell_result)
@@ -194,7 +195,7 @@ static bool __put(struct dm_bio_prison_v2 *prison,
// FIXME: shared locks granted above the lock level could starve this
if (!cell->shared_count) {
- if (cell->exclusive_lock){
+ if (cell->exclusive_lock) {
if (cell->quiesce_continuation) {
queue_work(prison->wq, cell->quiesce_continuation);
cell->quiesce_continuation = NULL;
@@ -224,7 +225,7 @@ EXPORT_SYMBOL_GPL(dm_cell_put_v2);
static int __lock(struct dm_bio_prison_v2 *prison,
struct dm_cell_key_v2 *key,
- unsigned lock_level,
+ unsigned int lock_level,
struct dm_bio_prison_cell_v2 *cell_prealloc,
struct dm_bio_prison_cell_v2 **cell_result)
{
@@ -255,7 +256,7 @@ static int __lock(struct dm_bio_prison_v2 *prison,
int dm_cell_lock_v2(struct dm_bio_prison_v2 *prison,
struct dm_cell_key_v2 *key,
- unsigned lock_level,
+ unsigned int lock_level,
struct dm_bio_prison_cell_v2 *cell_prealloc,
struct dm_bio_prison_cell_v2 **cell_result)
{
@@ -291,7 +292,7 @@ EXPORT_SYMBOL_GPL(dm_cell_quiesce_v2);
static int __promote(struct dm_bio_prison_v2 *prison,
struct dm_bio_prison_cell_v2 *cell,
- unsigned new_lock_level)
+ unsigned int new_lock_level)
{
if (!cell->exclusive_lock)
return -EINVAL;
@@ -302,7 +303,7 @@ static int __promote(struct dm_bio_prison_v2 *prison,
int dm_cell_lock_promote_v2(struct dm_bio_prison_v2 *prison,
struct dm_bio_prison_cell_v2 *cell,
- unsigned new_lock_level)
+ unsigned int new_lock_level)
{
int r;
diff --git a/drivers/md/dm-bio-prison-v2.h b/drivers/md/dm-bio-prison-v2.h
index 6e04234268db..ce2cca5ef2f5 100644
--- a/drivers/md/dm-bio-prison-v2.h
+++ b/drivers/md/dm-bio-prison-v2.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2011-2017 Red Hat, Inc.
*
@@ -44,8 +45,8 @@ struct dm_cell_key_v2 {
struct dm_bio_prison_cell_v2 {
// FIXME: pack these
bool exclusive_lock;
- unsigned exclusive_level;
- unsigned shared_count;
+ unsigned int exclusive_level;
+ unsigned int shared_count;
struct work_struct *quiesce_continuation;
struct rb_node node;
@@ -86,7 +87,7 @@ void dm_bio_prison_free_cell_v2(struct dm_bio_prison_v2 *prison,
*/
bool dm_cell_get_v2(struct dm_bio_prison_v2 *prison,
struct dm_cell_key_v2 *key,
- unsigned lock_level,
+ unsigned int lock_level,
struct bio *inmate,
struct dm_bio_prison_cell_v2 *cell_prealloc,
struct dm_bio_prison_cell_v2 **cell_result);
@@ -114,7 +115,7 @@ bool dm_cell_put_v2(struct dm_bio_prison_v2 *prison,
*/
int dm_cell_lock_v2(struct dm_bio_prison_v2 *prison,
struct dm_cell_key_v2 *key,
- unsigned lock_level,
+ unsigned int lock_level,
struct dm_bio_prison_cell_v2 *cell_prealloc,
struct dm_bio_prison_cell_v2 **cell_result);
@@ -132,7 +133,7 @@ void dm_cell_quiesce_v2(struct dm_bio_prison_v2 *prison,
*/
int dm_cell_lock_promote_v2(struct dm_bio_prison_v2 *prison,
struct dm_bio_prison_cell_v2 *cell,
- unsigned new_lock_level);
+ unsigned int new_lock_level);
/*
* Adds any held bios to the bio list.
diff --git a/drivers/md/dm-bio-record.h b/drivers/md/dm-bio-record.h
index 745e3ab4aa0a..04d2f0cda324 100644
--- a/drivers/md/dm-bio-record.h
+++ b/drivers/md/dm-bio-record.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
*
diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c
index bb786c39545e..cf077f9b30c3 100644
--- a/drivers/md/dm-bufio.c
+++ b/drivers/md/dm-bufio.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2009-2011 Red Hat, Inc.
*
@@ -89,18 +90,18 @@ struct dm_bufio_client {
unsigned long n_buffers[LIST_SIZE];
struct block_device *bdev;
- unsigned block_size;
+ unsigned int block_size;
s8 sectors_per_block_bits;
- void (*alloc_callback)(struct dm_buffer *);
- void (*write_callback)(struct dm_buffer *);
+ void (*alloc_callback)(struct dm_buffer *buf);
+ void (*write_callback)(struct dm_buffer *buf);
struct kmem_cache *slab_buffer;
struct kmem_cache *slab_cache;
struct dm_io_client *dm_io;
struct list_head reserved_buffers;
- unsigned need_reserved_buffers;
+ unsigned int need_reserved_buffers;
- unsigned minimum_buffers;
+ unsigned int minimum_buffers;
struct rb_root buffer_tree;
wait_queue_head_t free_buffer_wait;
@@ -145,17 +146,17 @@ struct dm_buffer {
unsigned char list_mode; /* LIST_* */
blk_status_t read_error;
blk_status_t write_error;
- unsigned accessed;
- unsigned hold_count;
+ unsigned int accessed;
+ unsigned int hold_count;
unsigned long state;
unsigned long last_accessed;
- unsigned dirty_start;
- unsigned dirty_end;
- unsigned write_start;
- unsigned write_end;
+ unsigned int dirty_start;
+ unsigned int dirty_end;
+ unsigned int write_start;
+ unsigned int write_end;
struct dm_bufio_client *c;
struct list_head write_list;
- void (*end_io)(struct dm_buffer *, blk_status_t);
+ void (*end_io)(struct dm_buffer *buf, blk_status_t stat);
#ifdef CONFIG_DM_DEBUG_BLOCK_STACK_TRACING
#define MAX_STACK 10
unsigned int stack_len;
@@ -215,12 +216,12 @@ static DEFINE_SPINLOCK(global_spinlock);
static LIST_HEAD(global_queue);
-static unsigned long global_num = 0;
+static unsigned long global_num;
/*
* Buffers are freed after this timeout
*/
-static unsigned dm_bufio_max_age = DM_BUFIO_DEFAULT_AGE_SECS;
+static unsigned int dm_bufio_max_age = DM_BUFIO_DEFAULT_AGE_SECS;
static unsigned long dm_bufio_retain_bytes = DM_BUFIO_DEFAULT_RETAIN_BYTES;
static unsigned long dm_bufio_peak_allocated;
@@ -258,9 +259,11 @@ static void buffer_record_stack(struct dm_buffer *b)
}
#endif
-/*----------------------------------------------------------------
+/*
+ *----------------------------------------------------------------
* A red/black tree acts as an index for all the buffers.
- *--------------------------------------------------------------*/
+ *----------------------------------------------------------------
+ */
static struct dm_buffer *__find(struct dm_bufio_client *c, sector_t block)
{
struct rb_node *n = c->buffer_tree.rb_node;
@@ -438,7 +441,7 @@ static void *alloc_buffer_data(struct dm_bufio_client *c, gfp_t gfp_mask,
* as if GFP_NOIO was specified.
*/
if (gfp_mask & __GFP_NORETRY) {
- unsigned noio_flag = memalloc_noio_save();
+ unsigned int noio_flag = memalloc_noio_save();
void *ptr = __vmalloc(c->block_size, gfp_mask);
memalloc_noio_restore(noio_flag);
@@ -561,7 +564,8 @@ static void __relink_lru(struct dm_buffer *b, int dirty)
b->last_accessed = jiffies;
}
-/*----------------------------------------------------------------
+/*
+ *--------------------------------------------------------------------------
* Submit I/O on the buffer.
*
* Bio interface is faster but it has some problems:
@@ -577,7 +581,8 @@ static void __relink_lru(struct dm_buffer *b, int dirty)
* rejects the bio because it is too large, use dm-io layer to do the I/O.
* The dm-io layer splits the I/O into multiple requests, avoiding the above
* shortcomings.
- *--------------------------------------------------------------*/
+ *--------------------------------------------------------------------------
+ */
/*
* dm-io completion routine. It just calls b->bio.bi_end_io, pretending
@@ -591,7 +596,7 @@ static void dmio_complete(unsigned long error, void *context)
}
static void use_dmio(struct dm_buffer *b, enum req_op op, sector_t sector,
- unsigned n_sectors, unsigned offset)
+ unsigned int n_sectors, unsigned int offset)
{
int r;
struct dm_io_request io_req = {
@@ -623,17 +628,18 @@ static void bio_complete(struct bio *bio)
{
struct dm_buffer *b = bio->bi_private;
blk_status_t status = bio->bi_status;
+
bio_uninit(bio);
kfree(bio);
b->end_io(b, status);
}
static void use_bio(struct dm_buffer *b, enum req_op op, sector_t sector,
- unsigned n_sectors, unsigned offset)
+ unsigned int n_sectors, unsigned int offset)
{
struct bio *bio;
char *ptr;
- unsigned vec_size, len;
+ unsigned int vec_size, len;
vec_size = b->c->block_size >> PAGE_SHIFT;
if (unlikely(b->c->sectors_per_block_bits < PAGE_SHIFT - SECTOR_SHIFT))
@@ -654,7 +660,8 @@ dmio:
len = n_sectors << SECTOR_SHIFT;
do {
- unsigned this_step = min((unsigned)(PAGE_SIZE - offset_in_page(ptr)), len);
+ unsigned int this_step = min((unsigned int)(PAGE_SIZE - offset_in_page(ptr)), len);
+
if (!bio_add_page(bio, virt_to_page(ptr), this_step,
offset_in_page(ptr))) {
bio_put(bio);
@@ -684,9 +691,9 @@ static inline sector_t block_to_sector(struct dm_bufio_client *c, sector_t block
static void submit_io(struct dm_buffer *b, enum req_op op,
void (*end_io)(struct dm_buffer *, blk_status_t))
{
- unsigned n_sectors;
+ unsigned int n_sectors;
sector_t sector;
- unsigned offset, end;
+ unsigned int offset, end;
b->end_io = end_io;
@@ -716,9 +723,11 @@ static void submit_io(struct dm_buffer *b, enum req_op op,
use_dmio(b, op, sector, n_sectors, offset);
}
-/*----------------------------------------------------------------
+/*
+ *--------------------------------------------------------------
* Writing dirty buffers
- *--------------------------------------------------------------*/
+ *--------------------------------------------------------------
+ */
/*
* The endio routine for write.
@@ -775,6 +784,7 @@ static void __write_dirty_buffer(struct dm_buffer *b,
static void __flush_write_list(struct list_head *write_list)
{
struct blk_plug plug;
+
blk_start_plug(&plug);
while (!list_empty(write_list)) {
struct dm_buffer *b =
@@ -998,9 +1008,11 @@ static void __check_watermark(struct dm_bufio_client *c,
__write_dirty_buffers_async(c, 1, write_list);
}
-/*----------------------------------------------------------------
+/*
+ *--------------------------------------------------------------
* Getting a buffer
- *--------------------------------------------------------------*/
+ *--------------------------------------------------------------
+ */
static struct dm_buffer *__bufio_new(struct dm_bufio_client *c, sector_t block,
enum new_flag nf, int *need_submit,
@@ -1156,7 +1168,7 @@ void *dm_bufio_new(struct dm_bufio_client *c, sector_t block,
EXPORT_SYMBOL_GPL(dm_bufio_new);
void dm_bufio_prefetch(struct dm_bufio_client *c,
- sector_t block, unsigned n_blocks)
+ sector_t block, unsigned int n_blocks)
{
struct blk_plug plug;
@@ -1170,6 +1182,7 @@ void dm_bufio_prefetch(struct dm_bufio_client *c,
for (; n_blocks--; block++) {
int need_submit;
struct dm_buffer *b;
+
b = __bufio_new(c, block, NF_PREFETCH, &need_submit,
&write_list);
if (unlikely(!list_empty(&write_list))) {
@@ -1232,7 +1245,7 @@ void dm_bufio_release(struct dm_buffer *b)
EXPORT_SYMBOL_GPL(dm_bufio_release);
void dm_bufio_mark_partial_buffer_dirty(struct dm_buffer *b,
- unsigned start, unsigned end)
+ unsigned int start, unsigned int end)
{
struct dm_bufio_client *c = b->c;
@@ -1454,6 +1467,7 @@ retry:
__link_buffer(b, new_block, LIST_DIRTY);
} else {
sector_t old_block;
+
wait_on_bit_lock_io(&b->state, B_WRITING,
TASK_UNINTERRUPTIBLE);
/*
@@ -1529,13 +1543,13 @@ void dm_bufio_forget_buffers(struct dm_bufio_client *c, sector_t block, sector_t
}
EXPORT_SYMBOL_GPL(dm_bufio_forget_buffers);
-void dm_bufio_set_minimum_buffers(struct dm_bufio_client *c, unsigned n)
+void dm_bufio_set_minimum_buffers(struct dm_bufio_client *c, unsigned int n)
{
c->minimum_buffers = n;
}
EXPORT_SYMBOL_GPL(dm_bufio_set_minimum_buffers);
-unsigned dm_bufio_get_block_size(struct dm_bufio_client *c)
+unsigned int dm_bufio_get_block_size(struct dm_bufio_client *c)
{
return c->block_size;
}
@@ -1544,6 +1558,7 @@ EXPORT_SYMBOL_GPL(dm_bufio_get_block_size);
sector_t dm_bufio_get_device_size(struct dm_bufio_client *c)
{
sector_t s = bdev_nr_sectors(c->bdev);
+
if (s >= c->start)
s -= c->start;
else
@@ -1659,10 +1674,12 @@ static bool __try_evict_buffer(struct dm_buffer *b, gfp_t gfp)
static unsigned long get_retain_buffers(struct dm_bufio_client *c)
{
unsigned long retain_bytes = READ_ONCE(dm_bufio_retain_bytes);
+
if (likely(c->sectors_per_block_bits >= 0))
retain_bytes >>= c->sectors_per_block_bits + SECTOR_SHIFT;
else
retain_bytes /= c->block_size;
+
return retain_bytes;
}
@@ -1734,15 +1751,15 @@ static unsigned long dm_bufio_shrink_count(struct shrinker *shrink, struct shrin
/*
* Create the buffering interface
*/
-struct dm_bufio_client *dm_bufio_client_create(struct block_device *bdev, unsigned block_size,
- unsigned reserved_buffers, unsigned aux_size,
+struct dm_bufio_client *dm_bufio_client_create(struct block_device *bdev, unsigned int block_size,
+ unsigned int reserved_buffers, unsigned int aux_size,
void (*alloc_callback)(struct dm_buffer *),
void (*write_callback)(struct dm_buffer *),
unsigned int flags)
{
int r;
struct dm_bufio_client *c;
- unsigned i;
+ unsigned int i;
char slab_name[27];
if (!block_size || block_size & ((1 << SECTOR_SHIFT) - 1)) {
@@ -1796,8 +1813,9 @@ struct dm_bufio_client *dm_bufio_client_create(struct block_device *bdev, unsign
if (block_size <= KMALLOC_MAX_SIZE &&
(block_size < PAGE_SIZE || !is_power_of_2(block_size))) {
- unsigned align = min(1U << __ffs(block_size), (unsigned)PAGE_SIZE);
- snprintf(slab_name, sizeof slab_name, "dm_bufio_cache-%u", block_size);
+ unsigned int align = min(1U << __ffs(block_size), (unsigned int)PAGE_SIZE);
+
+ snprintf(slab_name, sizeof(slab_name), "dm_bufio_cache-%u", block_size);
c->slab_cache = kmem_cache_create(slab_name, block_size, align,
SLAB_RECLAIM_ACCOUNT, NULL);
if (!c->slab_cache) {
@@ -1806,9 +1824,9 @@ struct dm_bufio_client *dm_bufio_client_create(struct block_device *bdev, unsign
}
}
if (aux_size)
- snprintf(slab_name, sizeof slab_name, "dm_bufio_buffer-%u", aux_size);
+ snprintf(slab_name, sizeof(slab_name), "dm_bufio_buffer-%u", aux_size);
else
- snprintf(slab_name, sizeof slab_name, "dm_bufio_buffer");
+ snprintf(slab_name, sizeof(slab_name), "dm_bufio_buffer");
c->slab_buffer = kmem_cache_create(slab_name, sizeof(struct dm_buffer) + aux_size,
0, SLAB_RECLAIM_ACCOUNT, NULL);
if (!c->slab_buffer) {
@@ -1833,7 +1851,7 @@ struct dm_bufio_client *dm_bufio_client_create(struct block_device *bdev, unsign
c->shrinker.scan_objects = dm_bufio_shrink_scan;
c->shrinker.seeks = 1;
c->shrinker.batch = 0;
- r = register_shrinker(&c->shrinker, "md-%s:(%u:%u)", slab_name,
+ r = register_shrinker(&c->shrinker, "dm-bufio:(%u:%u)",
MAJOR(bdev->bd_dev), MINOR(bdev->bd_dev));
if (r)
goto bad;
@@ -1872,7 +1890,7 @@ EXPORT_SYMBOL_GPL(dm_bufio_client_create);
*/
void dm_bufio_client_destroy(struct dm_bufio_client *c)
{
- unsigned i;
+ unsigned int i;
drop_buffers(c);
@@ -1920,9 +1938,9 @@ void dm_bufio_set_sector_offset(struct dm_bufio_client *c, sector_t start)
}
EXPORT_SYMBOL_GPL(dm_bufio_set_sector_offset);
-static unsigned get_max_age_hz(void)
+static unsigned int get_max_age_hz(void)
{
- unsigned max_age = READ_ONCE(dm_bufio_max_age);
+ unsigned int max_age = READ_ONCE(dm_bufio_max_age);
if (max_age > UINT_MAX / HZ)
max_age = UINT_MAX / HZ;
@@ -1973,7 +1991,7 @@ static void do_global_cleanup(struct work_struct *w)
struct dm_bufio_client *locked_client = NULL;
struct dm_bufio_client *current_client;
struct dm_buffer *b;
- unsigned spinlock_hold_count;
+ unsigned int spinlock_hold_count;
unsigned long threshold = dm_bufio_cache_size -
dm_bufio_cache_size / DM_BUFIO_LOW_WATERMARK_RATIO;
unsigned long loops = global_num * 2;
@@ -2059,9 +2077,11 @@ static void work_fn(struct work_struct *w)
DM_BUFIO_WORK_TIMER_SECS * HZ);
}
-/*----------------------------------------------------------------
+/*
+ *--------------------------------------------------------------
* Module setup
- *--------------------------------------------------------------*/
+ *--------------------------------------------------------------
+ */
/*
* This is called only once for the whole dm_bufio module.
@@ -2145,28 +2165,28 @@ static void __exit dm_bufio_exit(void)
module_init(dm_bufio_init)
module_exit(dm_bufio_exit)
-module_param_named(max_cache_size_bytes, dm_bufio_cache_size, ulong, S_IRUGO | S_IWUSR);
+module_param_named(max_cache_size_bytes, dm_bufio_cache_size, ulong, 0644);
MODULE_PARM_DESC(max_cache_size_bytes, "Size of metadata cache");
-module_param_named(max_age_seconds, dm_bufio_max_age, uint, S_IRUGO | S_IWUSR);
+module_param_named(max_age_seconds, dm_bufio_max_age, uint, 0644);
MODULE_PARM_DESC(max_age_seconds, "Max age of a buffer in seconds");
-module_param_named(retain_bytes, dm_bufio_retain_bytes, ulong, S_IRUGO | S_IWUSR);
+module_param_named(retain_bytes, dm_bufio_retain_bytes, ulong, 0644);
MODULE_PARM_DESC(retain_bytes, "Try to keep at least this many bytes cached in memory");
-module_param_named(peak_allocated_bytes, dm_bufio_peak_allocated, ulong, S_IRUGO | S_IWUSR);
+module_param_named(peak_allocated_bytes, dm_bufio_peak_allocated, ulong, 0644);
MODULE_PARM_DESC(peak_allocated_bytes, "Tracks the maximum allocated memory");
-module_param_named(allocated_kmem_cache_bytes, dm_bufio_allocated_kmem_cache, ulong, S_IRUGO);
+module_param_named(allocated_kmem_cache_bytes, dm_bufio_allocated_kmem_cache, ulong, 0444);
MODULE_PARM_DESC(allocated_kmem_cache_bytes, "Memory allocated with kmem_cache_alloc");
-module_param_named(allocated_get_free_pages_bytes, dm_bufio_allocated_get_free_pages, ulong, S_IRUGO);
+module_param_named(allocated_get_free_pages_bytes, dm_bufio_allocated_get_free_pages, ulong, 0444);
MODULE_PARM_DESC(allocated_get_free_pages_bytes, "Memory allocated with get_free_pages");
-module_param_named(allocated_vmalloc_bytes, dm_bufio_allocated_vmalloc, ulong, S_IRUGO);
+module_param_named(allocated_vmalloc_bytes, dm_bufio_allocated_vmalloc, ulong, 0444);
MODULE_PARM_DESC(allocated_vmalloc_bytes, "Memory allocated with vmalloc");
-module_param_named(current_allocated_bytes, dm_bufio_current_allocated, ulong, S_IRUGO);
+module_param_named(current_allocated_bytes, dm_bufio_current_allocated, ulong, 0444);
MODULE_PARM_DESC(current_allocated_bytes, "Memory currently used by the cache");
MODULE_AUTHOR("Mikulas Patocka <dm-devel@redhat.com>");
diff --git a/drivers/md/dm-builtin.c b/drivers/md/dm-builtin.c
index 8eb52e425141..e51076ea629e 100644
--- a/drivers/md/dm-builtin.c
+++ b/drivers/md/dm-builtin.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
#include "dm-core.h"
/*
@@ -45,5 +45,4 @@ void dm_kobject_release(struct kobject *kobj)
{
complete(dm_get_completion_from_kobject(kobj));
}
-
EXPORT_SYMBOL(dm_kobject_release);
diff --git a/drivers/md/dm-cache-background-tracker.c b/drivers/md/dm-cache-background-tracker.c
index 84814e819e4c..9c5308298cf1 100644
--- a/drivers/md/dm-cache-background-tracker.c
+++ b/drivers/md/dm-cache-background-tracker.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2017 Red Hat. All rights reserved.
*
@@ -17,7 +18,7 @@ struct bt_work {
};
struct background_tracker {
- unsigned max_work;
+ unsigned int max_work;
atomic_t pending_promotes;
atomic_t pending_writebacks;
atomic_t pending_demotes;
@@ -29,7 +30,7 @@ struct background_tracker {
struct kmem_cache *work_cache;
};
-struct background_tracker *btracker_create(unsigned max_work)
+struct background_tracker *btracker_create(unsigned int max_work)
{
struct background_tracker *b = kmalloc(sizeof(*b), GFP_KERNEL);
@@ -60,6 +61,14 @@ EXPORT_SYMBOL_GPL(btracker_create);
void btracker_destroy(struct background_tracker *b)
{
+ struct bt_work *w, *tmp;
+
+ BUG_ON(!list_empty(&b->issued));
+ list_for_each_entry_safe (w, tmp, &b->queued, list) {
+ list_del(&w->list);
+ kmem_cache_free(b->work_cache, w);
+ }
+
kmem_cache_destroy(b->work_cache);
kfree(b);
}
@@ -147,13 +156,13 @@ static void update_stats(struct background_tracker *b, struct policy_work *w, in
}
}
-unsigned btracker_nr_writebacks_queued(struct background_tracker *b)
+unsigned int btracker_nr_writebacks_queued(struct background_tracker *b)
{
return atomic_read(&b->pending_writebacks);
}
EXPORT_SYMBOL_GPL(btracker_nr_writebacks_queued);
-unsigned btracker_nr_demotions_queued(struct background_tracker *b)
+unsigned int btracker_nr_demotions_queued(struct background_tracker *b)
{
return atomic_read(&b->pending_demotes);
}
diff --git a/drivers/md/dm-cache-background-tracker.h b/drivers/md/dm-cache-background-tracker.h
index 27ab90dbc275..5b8f5c667b81 100644
--- a/drivers/md/dm-cache-background-tracker.h
+++ b/drivers/md/dm-cache-background-tracker.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2017 Red Hat. All rights reserved.
*
@@ -12,19 +13,44 @@
/*----------------------------------------------------------------*/
+/*
+ * The cache policy decides what background work should be performed,
+ * such as promotions, demotions and writebacks. The core cache target
+ * is in charge of performing the work, and does so when it sees fit.
+ *
+ * The background_tracker acts as a go between. Keeping track of future
+ * work that the policy has decided upon, and handing (issuing) it to
+ * the core target when requested.
+ *
+ * There is no locking in this, so calls will probably need to be
+ * protected with a spinlock.
+ */
+
struct background_work;
struct background_tracker;
/*
- * FIXME: discuss lack of locking in all methods.
+ * Create a new tracker, it will not be able to queue more than
+ * 'max_work' entries.
+ */
+struct background_tracker *btracker_create(unsigned int max_work);
+
+/*
+ * Destroy the tracker. No issued, but not complete, work should
+ * exist when this is called. It is fine to have queued but unissued
+ * work.
*/
-struct background_tracker *btracker_create(unsigned max_work);
void btracker_destroy(struct background_tracker *b);
-unsigned btracker_nr_writebacks_queued(struct background_tracker *b);
-unsigned btracker_nr_demotions_queued(struct background_tracker *b);
+unsigned int btracker_nr_writebacks_queued(struct background_tracker *b);
+unsigned int btracker_nr_demotions_queued(struct background_tracker *b);
/*
+ * Queue some work within the tracker. 'work' should point to the work
+ * to queue, this will be copied (ownership doesn't pass). If pwork
+ * is not NULL then it will be set to point to the tracker's internal
+ * copy of the work.
+ *
* returns -EINVAL iff the work is already queued. -ENOMEM if the work
* couldn't be queued for another reason.
*/
@@ -33,11 +59,20 @@ int btracker_queue(struct background_tracker *b,
struct policy_work **pwork);
/*
+ * Hands out the next piece of work to be performed.
* Returns -ENODATA if there's no work.
*/
int btracker_issue(struct background_tracker *b, struct policy_work **work);
-void btracker_complete(struct background_tracker *b,
- struct policy_work *op);
+
+/*
+ * Informs the tracker that the work has been completed and it may forget
+ * about it.
+ */
+void btracker_complete(struct background_tracker *b, struct policy_work *op);
+
+/*
+ * Predicate to see if an origin block is already scheduled for promotion.
+ */
bool btracker_promotion_already_present(struct background_tracker *b,
dm_oblock_t oblock);
diff --git a/drivers/md/dm-cache-block-types.h b/drivers/md/dm-cache-block-types.h
index 389c9e8ac785..57d2534c59ce 100644
--- a/drivers/md/dm-cache-block-types.h
+++ b/drivers/md/dm-cache-block-types.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2012 Red Hat, Inc.
*
diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c
index 83a5975bcc72..acffed750e3e 100644
--- a/drivers/md/dm-cache-metadata.c
+++ b/drivers/md/dm-cache-metadata.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Red Hat, Inc.
*
@@ -104,7 +105,7 @@ struct dm_cache_metadata {
refcount_t ref_count;
struct list_head list;
- unsigned version;
+ unsigned int version;
struct block_device *bdev;
struct dm_block_manager *bm;
struct dm_space_map *metadata_sm;
@@ -129,7 +130,7 @@ struct dm_cache_metadata {
bool clean_when_opened:1;
char policy_name[CACHE_POLICY_NAME_SIZE];
- unsigned policy_version[CACHE_POLICY_VERSION_SIZE];
+ unsigned int policy_version[CACHE_POLICY_VERSION_SIZE];
size_t policy_hint_size;
struct dm_cache_statistics stats;
@@ -162,10 +163,11 @@ struct dm_cache_metadata {
struct dm_bitset_cursor dirty_cursor;
};
-/*-------------------------------------------------------------------
+/*
+ *-----------------------------------------------------------------
* superblock validator
- *-----------------------------------------------------------------*/
-
+ *-----------------------------------------------------------------
+ */
#define SUPERBLOCK_CSUM_XOR 9031977
static void sb_prepare_for_write(struct dm_block_validator *v,
@@ -201,15 +203,15 @@ static int sb_check(struct dm_block_validator *v,
__le32 csum_le;
if (dm_block_location(b) != le64_to_cpu(disk_super->blocknr)) {
- DMERR("sb_check failed: blocknr %llu: wanted %llu",
- le64_to_cpu(disk_super->blocknr),
+ DMERR("%s failed: blocknr %llu: wanted %llu",
+ __func__, le64_to_cpu(disk_super->blocknr),
(unsigned long long)dm_block_location(b));
return -ENOTBLK;
}
if (le64_to_cpu(disk_super->magic) != CACHE_SUPERBLOCK_MAGIC) {
- DMERR("sb_check failed: magic %llu: wanted %llu",
- le64_to_cpu(disk_super->magic),
+ DMERR("%s failed: magic %llu: wanted %llu",
+ __func__, le64_to_cpu(disk_super->magic),
(unsigned long long)CACHE_SUPERBLOCK_MAGIC);
return -EILSEQ;
}
@@ -218,8 +220,8 @@ static int sb_check(struct dm_block_validator *v,
sb_block_size - sizeof(__le32),
SUPERBLOCK_CSUM_XOR));
if (csum_le != disk_super->csum) {
- DMERR("sb_check failed: csum %u: wanted %u",
- le32_to_cpu(csum_le), le32_to_cpu(disk_super->csum));
+ DMERR("%s failed: csum %u: wanted %u",
+ __func__, le32_to_cpu(csum_le), le32_to_cpu(disk_super->csum));
return -EILSEQ;
}
@@ -260,10 +262,10 @@ static int superblock_lock(struct dm_cache_metadata *cmd,
static int __superblock_all_zeroes(struct dm_block_manager *bm, bool *result)
{
int r;
- unsigned i;
+ unsigned int i;
struct dm_block *b;
__le64 *data_le, zero = cpu_to_le64(0);
- unsigned sb_block_size = dm_bm_block_size(bm) / sizeof(__le64);
+ unsigned int sb_block_size = dm_bm_block_size(bm) / sizeof(__le64);
/*
* We can't use a validator here - it may be all zeroes.
@@ -533,6 +535,7 @@ static int __create_persistent_data_objects(struct dm_cache_metadata *cmd,
bool may_format_device)
{
int r;
+
cmd->bm = dm_block_manager_create(cmd->bdev, DM_CACHE_METADATA_BLOCK_SIZE << SECTOR_SHIFT,
CACHE_MAX_CONCURRENT_LOCKS);
if (IS_ERR(cmd->bm)) {
@@ -566,6 +569,7 @@ static void update_flags(struct cache_disk_superblock *disk_super,
flags_mutator mutator)
{
uint32_t sb_flags = mutator(le32_to_cpu(disk_super->flags));
+
disk_super->flags = cpu_to_le32(sb_flags);
}
@@ -727,18 +731,20 @@ static int __commit_transaction(struct dm_cache_metadata *cmd,
*/
#define FLAGS_MASK ((1 << 16) - 1)
-static __le64 pack_value(dm_oblock_t block, unsigned flags)
+static __le64 pack_value(dm_oblock_t block, unsigned int flags)
{
uint64_t value = from_oblock(block);
+
value <<= 16;
value = value | (flags & FLAGS_MASK);
return cpu_to_le64(value);
}
-static void unpack_value(__le64 value_le, dm_oblock_t *block, unsigned *flags)
+static void unpack_value(__le64 value_le, dm_oblock_t *block, unsigned int *flags)
{
uint64_t value = le64_to_cpu(value_le);
uint64_t b = value >> 16;
+
*block = to_oblock(b);
*flags = value & FLAGS_MASK;
}
@@ -749,7 +755,7 @@ static struct dm_cache_metadata *metadata_open(struct block_device *bdev,
sector_t data_block_size,
bool may_format_device,
size_t policy_hint_size,
- unsigned metadata_version)
+ unsigned int metadata_version)
{
int r;
struct dm_cache_metadata *cmd;
@@ -810,7 +816,7 @@ static struct dm_cache_metadata *lookup_or_open(struct block_device *bdev,
sector_t data_block_size,
bool may_format_device,
size_t policy_hint_size,
- unsigned metadata_version)
+ unsigned int metadata_version)
{
struct dm_cache_metadata *cmd, *cmd2;
@@ -855,7 +861,7 @@ struct dm_cache_metadata *dm_cache_metadata_open(struct block_device *bdev,
sector_t data_block_size,
bool may_format_device,
size_t policy_hint_size,
- unsigned metadata_version)
+ unsigned int metadata_version)
{
struct dm_cache_metadata *cmd = lookup_or_open(bdev, data_block_size, may_format_device,
policy_hint_size, metadata_version);
@@ -890,7 +896,7 @@ static int block_clean_combined_dirty(struct dm_cache_metadata *cmd, dm_cblock_t
int r;
__le64 value;
dm_oblock_t ob;
- unsigned flags;
+ unsigned int flags;
r = dm_array_get_value(&cmd->info, cmd->root, from_cblock(b), &value);
if (r)
@@ -1009,13 +1015,13 @@ static bool cmd_write_lock(struct dm_cache_metadata *cmd)
do { \
if (!cmd_write_lock((cmd))) \
return -EINVAL; \
- } while(0)
+ } while (0)
#define WRITE_LOCK_VOID(cmd) \
do { \
if (!cmd_write_lock((cmd))) \
return; \
- } while(0)
+ } while (0)
#define WRITE_UNLOCK(cmd) \
up_write(&(cmd)->root_lock)
@@ -1034,13 +1040,13 @@ static bool cmd_read_lock(struct dm_cache_metadata *cmd)
do { \
if (!cmd_read_lock((cmd))) \
return -EINVAL; \
- } while(0)
+ } while (0)
#define READ_LOCK_VOID(cmd) \
do { \
if (!cmd_read_lock((cmd))) \
return; \
- } while(0)
+ } while (0)
#define READ_UNLOCK(cmd) \
up_read(&(cmd)->root_lock)
@@ -1252,6 +1258,7 @@ static int __insert(struct dm_cache_metadata *cmd,
{
int r;
__le64 value = pack_value(oblock, M_VALID);
+
__dm_bless_for_disk(&value);
r = dm_array_set_value(&cmd->info, cmd->root, from_cblock(cblock),
@@ -1288,7 +1295,7 @@ static bool policy_unchanged(struct dm_cache_metadata *cmd,
struct dm_cache_policy *policy)
{
const char *policy_name = dm_cache_policy_get_name(policy);
- const unsigned *policy_version = dm_cache_policy_get_version(policy);
+ const unsigned int *policy_version = dm_cache_policy_get_version(policy);
size_t policy_hint_size = dm_cache_policy_get_hint_size(policy);
/*
@@ -1339,7 +1346,7 @@ static int __load_mapping_v1(struct dm_cache_metadata *cmd,
__le32 *hint_value_le;
dm_oblock_t oblock;
- unsigned flags;
+ unsigned int flags;
bool dirty = true;
dm_array_cursor_get_value(mapping_cursor, (void **) &mapping_value_le);
@@ -1381,7 +1388,7 @@ static int __load_mapping_v2(struct dm_cache_metadata *cmd,
__le32 *hint_value_le;
dm_oblock_t oblock;
- unsigned flags;
+ unsigned int flags;
bool dirty = true;
dm_array_cursor_get_value(mapping_cursor, (void **) &mapping_value_le);
@@ -1513,7 +1520,7 @@ static int __dump_mapping(void *context, uint64_t cblock, void *leaf)
{
__le64 value;
dm_oblock_t oblock;
- unsigned flags;
+ unsigned int flags;
memcpy(&value, leaf, sizeof(value));
unpack_value(value, &oblock, &flags);
@@ -1547,7 +1554,7 @@ int dm_cache_changed_this_transaction(struct dm_cache_metadata *cmd)
static int __dirty(struct dm_cache_metadata *cmd, dm_cblock_t cblock, bool dirty)
{
int r;
- unsigned flags;
+ unsigned int flags;
dm_oblock_t oblock;
__le64 value;
@@ -1574,10 +1581,11 @@ static int __dirty(struct dm_cache_metadata *cmd, dm_cblock_t cblock, bool dirty
}
-static int __set_dirty_bits_v1(struct dm_cache_metadata *cmd, unsigned nr_bits, unsigned long *bits)
+static int __set_dirty_bits_v1(struct dm_cache_metadata *cmd, unsigned int nr_bits, unsigned long *bits)
{
int r;
- unsigned i;
+ unsigned int i;
+
for (i = 0; i < nr_bits; i++) {
r = __dirty(cmd, to_cblock(i), test_bit(i, bits));
if (r)
@@ -1594,7 +1602,7 @@ static int is_dirty_callback(uint32_t index, bool *value, void *context)
return 0;
}
-static int __set_dirty_bits_v2(struct dm_cache_metadata *cmd, unsigned nr_bits, unsigned long *bits)
+static int __set_dirty_bits_v2(struct dm_cache_metadata *cmd, unsigned int nr_bits, unsigned long *bits)
{
int r = 0;
@@ -1613,7 +1621,7 @@ static int __set_dirty_bits_v2(struct dm_cache_metadata *cmd, unsigned nr_bits,
}
int dm_cache_set_dirty_bits(struct dm_cache_metadata *cmd,
- unsigned nr_bits,
+ unsigned int nr_bits,
unsigned long *bits)
{
int r;
@@ -1712,7 +1720,7 @@ static int write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy *po
int r;
size_t hint_size;
const char *policy_name = dm_cache_policy_get_name(policy);
- const unsigned *policy_version = dm_cache_policy_get_version(policy);
+ const unsigned int *policy_version = dm_cache_policy_get_version(policy);
if (!policy_name[0] ||
(strlen(policy_name) > sizeof(cmd->policy_name) - 1))
diff --git a/drivers/md/dm-cache-metadata.h b/drivers/md/dm-cache-metadata.h
index 0905f2c1615e..57afc7047947 100644
--- a/drivers/md/dm-cache-metadata.h
+++ b/drivers/md/dm-cache-metadata.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2012 Red Hat, Inc.
*
@@ -60,7 +61,7 @@ struct dm_cache_metadata *dm_cache_metadata_open(struct block_device *bdev,
sector_t data_block_size,
bool may_format_device,
size_t policy_hint_size,
- unsigned metadata_version);
+ unsigned int metadata_version);
void dm_cache_metadata_close(struct dm_cache_metadata *cmd);
@@ -96,7 +97,7 @@ int dm_cache_load_mappings(struct dm_cache_metadata *cmd,
void *context);
int dm_cache_set_dirty_bits(struct dm_cache_metadata *cmd,
- unsigned nr_bits, unsigned long *bits);
+ unsigned int nr_bits, unsigned long *bits);
struct dm_cache_statistics {
uint32_t read_hits;
diff --git a/drivers/md/dm-cache-policy-internal.h b/drivers/md/dm-cache-policy-internal.h
index 56f0a23f698c..476a4f6794fc 100644
--- a/drivers/md/dm-cache-policy-internal.h
+++ b/drivers/md/dm-cache-policy-internal.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2012 Red Hat. All rights reserved.
*
@@ -85,9 +86,10 @@ static inline void policy_tick(struct dm_cache_policy *p, bool can_block)
}
static inline int policy_emit_config_values(struct dm_cache_policy *p, char *result,
- unsigned maxlen, ssize_t *sz_ptr)
+ unsigned int maxlen, ssize_t *sz_ptr)
{
ssize_t sz = *sz_ptr;
+
if (p->emit_config_values)
return p->emit_config_values(p, result, maxlen, sz_ptr);
@@ -112,20 +114,22 @@ static inline void policy_allow_migrations(struct dm_cache_policy *p, bool allow
/*
* Some utility functions commonly used by policies and the core target.
*/
-static inline size_t bitset_size_in_bytes(unsigned nr_entries)
+static inline size_t bitset_size_in_bytes(unsigned int nr_entries)
{
return sizeof(unsigned long) * dm_div_up(nr_entries, BITS_PER_LONG);
}
-static inline unsigned long *alloc_bitset(unsigned nr_entries)
+static inline unsigned long *alloc_bitset(unsigned int nr_entries)
{
size_t s = bitset_size_in_bytes(nr_entries);
+
return vzalloc(s);
}
-static inline void clear_bitset(void *bitset, unsigned nr_entries)
+static inline void clear_bitset(void *bitset, unsigned int nr_entries)
{
size_t s = bitset_size_in_bytes(nr_entries);
+
memset(bitset, 0, s);
}
@@ -154,7 +158,7 @@ void dm_cache_policy_destroy(struct dm_cache_policy *p);
*/
const char *dm_cache_policy_get_name(struct dm_cache_policy *p);
-const unsigned *dm_cache_policy_get_version(struct dm_cache_policy *p);
+const unsigned int *dm_cache_policy_get_version(struct dm_cache_policy *p);
size_t dm_cache_policy_get_hint_size(struct dm_cache_policy *p);
diff --git a/drivers/md/dm-cache-policy-smq.c b/drivers/md/dm-cache-policy-smq.c
index a3d281fc14c3..493a8715dc8f 100644
--- a/drivers/md/dm-cache-policy-smq.c
+++ b/drivers/md/dm-cache-policy-smq.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2015 Red Hat. All rights reserved.
*
@@ -23,12 +24,12 @@
/*
* Safe division functions that return zero on divide by zero.
*/
-static unsigned safe_div(unsigned n, unsigned d)
+static unsigned int safe_div(unsigned int n, unsigned int d)
{
return d ? n / d : 0u;
}
-static unsigned safe_mod(unsigned n, unsigned d)
+static unsigned int safe_mod(unsigned int n, unsigned int d)
{
return d ? n % d : 0u;
}
@@ -36,10 +37,10 @@ static unsigned safe_mod(unsigned n, unsigned d)
/*----------------------------------------------------------------*/
struct entry {
- unsigned hash_next:28;
- unsigned prev:28;
- unsigned next:28;
- unsigned level:6;
+ unsigned int hash_next:28;
+ unsigned int prev:28;
+ unsigned int next:28;
+ unsigned int level:6;
bool dirty:1;
bool allocated:1;
bool sentinel:1;
@@ -62,7 +63,7 @@ struct entry_space {
struct entry *end;
};
-static int space_init(struct entry_space *es, unsigned nr_entries)
+static int space_init(struct entry_space *es, unsigned int nr_entries)
{
if (!nr_entries) {
es->begin = es->end = NULL;
@@ -82,7 +83,7 @@ static void space_exit(struct entry_space *es)
vfree(es->begin);
}
-static struct entry *__get_entry(struct entry_space *es, unsigned block)
+static struct entry *__get_entry(struct entry_space *es, unsigned int block)
{
struct entry *e;
@@ -92,13 +93,13 @@ static struct entry *__get_entry(struct entry_space *es, unsigned block)
return e;
}
-static unsigned to_index(struct entry_space *es, struct entry *e)
+static unsigned int to_index(struct entry_space *es, struct entry *e)
{
BUG_ON(e < es->begin || e >= es->end);
return e - es->begin;
}
-static struct entry *to_entry(struct entry_space *es, unsigned block)
+static struct entry *to_entry(struct entry_space *es, unsigned int block)
{
if (block == INDEXER_NULL)
return NULL;
@@ -109,8 +110,8 @@ static struct entry *to_entry(struct entry_space *es, unsigned block)
/*----------------------------------------------------------------*/
struct ilist {
- unsigned nr_elts; /* excluding sentinel entries */
- unsigned head, tail;
+ unsigned int nr_elts; /* excluding sentinel entries */
+ unsigned int head, tail;
};
static void l_init(struct ilist *l)
@@ -252,23 +253,23 @@ static struct entry *l_pop_tail(struct entry_space *es, struct ilist *l)
struct queue {
struct entry_space *es;
- unsigned nr_elts;
- unsigned nr_levels;
+ unsigned int nr_elts;
+ unsigned int nr_levels;
struct ilist qs[MAX_LEVELS];
/*
* We maintain a count of the number of entries we would like in each
* level.
*/
- unsigned last_target_nr_elts;
- unsigned nr_top_levels;
- unsigned nr_in_top_levels;
- unsigned target_count[MAX_LEVELS];
+ unsigned int last_target_nr_elts;
+ unsigned int nr_top_levels;
+ unsigned int nr_in_top_levels;
+ unsigned int target_count[MAX_LEVELS];
};
-static void q_init(struct queue *q, struct entry_space *es, unsigned nr_levels)
+static void q_init(struct queue *q, struct entry_space *es, unsigned int nr_levels)
{
- unsigned i;
+ unsigned int i;
q->es = es;
q->nr_elts = 0;
@@ -284,7 +285,7 @@ static void q_init(struct queue *q, struct entry_space *es, unsigned nr_levels)
q->nr_in_top_levels = 0u;
}
-static unsigned q_size(struct queue *q)
+static unsigned int q_size(struct queue *q)
{
return q->nr_elts;
}
@@ -332,9 +333,9 @@ static void q_del(struct queue *q, struct entry *e)
/*
* Return the oldest entry of the lowest populated level.
*/
-static struct entry *q_peek(struct queue *q, unsigned max_level, bool can_cross_sentinel)
+static struct entry *q_peek(struct queue *q, unsigned int max_level, bool can_cross_sentinel)
{
- unsigned level;
+ unsigned int level;
struct entry *e;
max_level = min(max_level, q->nr_levels);
@@ -369,7 +370,7 @@ static struct entry *q_pop(struct queue *q)
* used by redistribute, so we know this is true. It also doesn't adjust
* the q->nr_elts count.
*/
-static struct entry *__redist_pop_from(struct queue *q, unsigned level)
+static struct entry *__redist_pop_from(struct queue *q, unsigned int level)
{
struct entry *e;
@@ -383,9 +384,10 @@ static struct entry *__redist_pop_from(struct queue *q, unsigned level)
return NULL;
}
-static void q_set_targets_subrange_(struct queue *q, unsigned nr_elts, unsigned lbegin, unsigned lend)
+static void q_set_targets_subrange_(struct queue *q, unsigned int nr_elts,
+ unsigned int lbegin, unsigned int lend)
{
- unsigned level, nr_levels, entries_per_level, remainder;
+ unsigned int level, nr_levels, entries_per_level, remainder;
BUG_ON(lbegin > lend);
BUG_ON(lend > q->nr_levels);
@@ -426,7 +428,7 @@ static void q_set_targets(struct queue *q)
static void q_redistribute(struct queue *q)
{
- unsigned target, level;
+ unsigned int target, level;
struct ilist *l, *l_above;
struct entry *e;
@@ -467,12 +469,12 @@ static void q_redistribute(struct queue *q)
}
}
-static void q_requeue(struct queue *q, struct entry *e, unsigned extra_levels,
+static void q_requeue(struct queue *q, struct entry *e, unsigned int extra_levels,
struct entry *s1, struct entry *s2)
{
struct entry *de;
- unsigned sentinels_passed = 0;
- unsigned new_level = min(q->nr_levels - 1u, e->level + extra_levels);
+ unsigned int sentinels_passed = 0;
+ unsigned int new_level = min(q->nr_levels - 1u, e->level + extra_levels);
/* try and find an entry to swap with */
if (extra_levels && (e->level < q->nr_levels - 1u)) {
@@ -512,9 +514,9 @@ static void q_requeue(struct queue *q, struct entry *e, unsigned extra_levels,
#define EIGHTH (1u << (FP_SHIFT - 3u))
struct stats {
- unsigned hit_threshold;
- unsigned hits;
- unsigned misses;
+ unsigned int hit_threshold;
+ unsigned int hits;
+ unsigned int misses;
};
enum performance {
@@ -523,7 +525,7 @@ enum performance {
Q_WELL
};
-static void stats_init(struct stats *s, unsigned nr_levels)
+static void stats_init(struct stats *s, unsigned int nr_levels)
{
s->hit_threshold = (nr_levels * 3u) / 4u;
s->hits = 0u;
@@ -535,7 +537,7 @@ static void stats_reset(struct stats *s)
s->hits = s->misses = 0u;
}
-static void stats_level_accessed(struct stats *s, unsigned level)
+static void stats_level_accessed(struct stats *s, unsigned int level)
{
if (level >= s->hit_threshold)
s->hits++;
@@ -556,7 +558,7 @@ static void stats_miss(struct stats *s)
*/
static enum performance stats_assess(struct stats *s)
{
- unsigned confidence = safe_div(s->hits << FP_SHIFT, s->hits + s->misses);
+ unsigned int confidence = safe_div(s->hits << FP_SHIFT, s->hits + s->misses);
if (confidence < SIXTEENTH)
return Q_POOR;
@@ -573,16 +575,16 @@ static enum performance stats_assess(struct stats *s)
struct smq_hash_table {
struct entry_space *es;
unsigned long long hash_bits;
- unsigned *buckets;
+ unsigned int *buckets;
};
/*
* All cache entries are stored in a chained hash table. To save space we
* use indexing again, and only store indexes to the next entry.
*/
-static int h_init(struct smq_hash_table *ht, struct entry_space *es, unsigned nr_entries)
+static int h_init(struct smq_hash_table *ht, struct entry_space *es, unsigned int nr_entries)
{
- unsigned i, nr_buckets;
+ unsigned int i, nr_buckets;
ht->es = es;
nr_buckets = roundup_pow_of_two(max(nr_entries / 4u, 16u));
@@ -603,7 +605,7 @@ static void h_exit(struct smq_hash_table *ht)
vfree(ht->buckets);
}
-static struct entry *h_head(struct smq_hash_table *ht, unsigned bucket)
+static struct entry *h_head(struct smq_hash_table *ht, unsigned int bucket)
{
return to_entry(ht->es, ht->buckets[bucket]);
}
@@ -613,7 +615,7 @@ static struct entry *h_next(struct smq_hash_table *ht, struct entry *e)
return to_entry(ht->es, e->hash_next);
}
-static void __h_insert(struct smq_hash_table *ht, unsigned bucket, struct entry *e)
+static void __h_insert(struct smq_hash_table *ht, unsigned int bucket, struct entry *e)
{
e->hash_next = ht->buckets[bucket];
ht->buckets[bucket] = to_index(ht->es, e);
@@ -621,11 +623,12 @@ static void __h_insert(struct smq_hash_table *ht, unsigned bucket, struct entry
static void h_insert(struct smq_hash_table *ht, struct entry *e)
{
- unsigned h = hash_64(from_oblock(e->oblock), ht->hash_bits);
+ unsigned int h = hash_64(from_oblock(e->oblock), ht->hash_bits);
+
__h_insert(ht, h, e);
}
-static struct entry *__h_lookup(struct smq_hash_table *ht, unsigned h, dm_oblock_t oblock,
+static struct entry *__h_lookup(struct smq_hash_table *ht, unsigned int h, dm_oblock_t oblock,
struct entry **prev)
{
struct entry *e;
@@ -641,7 +644,7 @@ static struct entry *__h_lookup(struct smq_hash_table *ht, unsigned h, dm_oblock
return NULL;
}
-static void __h_unlink(struct smq_hash_table *ht, unsigned h,
+static void __h_unlink(struct smq_hash_table *ht, unsigned int h,
struct entry *e, struct entry *prev)
{
if (prev)
@@ -656,7 +659,7 @@ static void __h_unlink(struct smq_hash_table *ht, unsigned h,
static struct entry *h_lookup(struct smq_hash_table *ht, dm_oblock_t oblock)
{
struct entry *e, *prev;
- unsigned h = hash_64(from_oblock(oblock), ht->hash_bits);
+ unsigned int h = hash_64(from_oblock(oblock), ht->hash_bits);
e = __h_lookup(ht, h, oblock, &prev);
if (e && prev) {
@@ -673,7 +676,7 @@ static struct entry *h_lookup(struct smq_hash_table *ht, dm_oblock_t oblock)
static void h_remove(struct smq_hash_table *ht, struct entry *e)
{
- unsigned h = hash_64(from_oblock(e->oblock), ht->hash_bits);
+ unsigned int h = hash_64(from_oblock(e->oblock), ht->hash_bits);
struct entry *prev;
/*
@@ -689,16 +692,16 @@ static void h_remove(struct smq_hash_table *ht, struct entry *e)
struct entry_alloc {
struct entry_space *es;
- unsigned begin;
+ unsigned int begin;
- unsigned nr_allocated;
+ unsigned int nr_allocated;
struct ilist free;
};
static void init_allocator(struct entry_alloc *ea, struct entry_space *es,
- unsigned begin, unsigned end)
+ unsigned int begin, unsigned int end)
{
- unsigned i;
+ unsigned int i;
ea->es = es;
ea->nr_allocated = 0u;
@@ -742,7 +745,7 @@ static struct entry *alloc_entry(struct entry_alloc *ea)
/*
* This assumes the cblock hasn't already been allocated.
*/
-static struct entry *alloc_particular_entry(struct entry_alloc *ea, unsigned i)
+static struct entry *alloc_particular_entry(struct entry_alloc *ea, unsigned int i)
{
struct entry *e = __get_entry(ea->es, ea->begin + i);
@@ -770,12 +773,12 @@ static bool allocator_empty(struct entry_alloc *ea)
return l_empty(&ea->free);
}
-static unsigned get_index(struct entry_alloc *ea, struct entry *e)
+static unsigned int get_index(struct entry_alloc *ea, struct entry *e)
{
return to_index(ea->es, e) - ea->begin;
}
-static struct entry *get_entry(struct entry_alloc *ea, unsigned index)
+static struct entry *get_entry(struct entry_alloc *ea, unsigned int index)
{
return __get_entry(ea->es, ea->begin + index);
}
@@ -800,9 +803,9 @@ struct smq_policy {
sector_t cache_block_size;
sector_t hotspot_block_size;
- unsigned nr_hotspot_blocks;
- unsigned cache_blocks_per_hotspot_block;
- unsigned hotspot_level_jump;
+ unsigned int nr_hotspot_blocks;
+ unsigned int cache_blocks_per_hotspot_block;
+ unsigned int hotspot_level_jump;
struct entry_space es;
struct entry_alloc writeback_sentinel_alloc;
@@ -831,7 +834,7 @@ struct smq_policy {
* Keeps track of time, incremented by the core. We use this to
* avoid attributing multiple hits within the same tick.
*/
- unsigned tick;
+ unsigned int tick;
/*
* The hash tables allows us to quickly find an entry by origin
@@ -846,8 +849,8 @@ struct smq_policy {
bool current_demote_sentinels;
unsigned long next_demote_period;
- unsigned write_promote_level;
- unsigned read_promote_level;
+ unsigned int write_promote_level;
+ unsigned int read_promote_level;
unsigned long next_hotspot_period;
unsigned long next_cache_period;
@@ -859,24 +862,24 @@ struct smq_policy {
/*----------------------------------------------------------------*/
-static struct entry *get_sentinel(struct entry_alloc *ea, unsigned level, bool which)
+static struct entry *get_sentinel(struct entry_alloc *ea, unsigned int level, bool which)
{
return get_entry(ea, which ? level : NR_CACHE_LEVELS + level);
}
-static struct entry *writeback_sentinel(struct smq_policy *mq, unsigned level)
+static struct entry *writeback_sentinel(struct smq_policy *mq, unsigned int level)
{
return get_sentinel(&mq->writeback_sentinel_alloc, level, mq->current_writeback_sentinels);
}
-static struct entry *demote_sentinel(struct smq_policy *mq, unsigned level)
+static struct entry *demote_sentinel(struct smq_policy *mq, unsigned int level)
{
return get_sentinel(&mq->demote_sentinel_alloc, level, mq->current_demote_sentinels);
}
static void __update_writeback_sentinels(struct smq_policy *mq)
{
- unsigned level;
+ unsigned int level;
struct queue *q = &mq->dirty;
struct entry *sentinel;
@@ -889,7 +892,7 @@ static void __update_writeback_sentinels(struct smq_policy *mq)
static void __update_demote_sentinels(struct smq_policy *mq)
{
- unsigned level;
+ unsigned int level;
struct queue *q = &mq->clean;
struct entry *sentinel;
@@ -917,7 +920,7 @@ static void update_sentinels(struct smq_policy *mq)
static void __sentinels_init(struct smq_policy *mq)
{
- unsigned level;
+ unsigned int level;
struct entry *sentinel;
for (level = 0; level < NR_CACHE_LEVELS; level++) {
@@ -1008,7 +1011,7 @@ static void requeue(struct smq_policy *mq, struct entry *e)
}
}
-static unsigned default_promote_level(struct smq_policy *mq)
+static unsigned int default_promote_level(struct smq_policy *mq)
{
/*
* The promote level depends on the current performance of the
@@ -1030,9 +1033,9 @@ static unsigned default_promote_level(struct smq_policy *mq)
1, 1, 1, 2, 4, 6, 7, 8, 7, 6, 4, 4, 3, 3, 2, 2, 1
};
- unsigned hits = mq->cache_stats.hits;
- unsigned misses = mq->cache_stats.misses;
- unsigned index = safe_div(hits << 4u, hits + misses);
+ unsigned int hits = mq->cache_stats.hits;
+ unsigned int misses = mq->cache_stats.misses;
+ unsigned int index = safe_div(hits << 4u, hits + misses);
return table[index];
}
@@ -1042,7 +1045,7 @@ static void update_promote_levels(struct smq_policy *mq)
* If there are unused cache entries then we want to be really
* eager to promote.
*/
- unsigned threshold_level = allocator_empty(&mq->cache_alloc) ?
+ unsigned int threshold_level = allocator_empty(&mq->cache_alloc) ?
default_promote_level(mq) : (NR_HOTSPOT_LEVELS / 2u);
threshold_level = max(threshold_level, NR_HOTSPOT_LEVELS);
@@ -1124,7 +1127,7 @@ static void end_cache_period(struct smq_policy *mq)
#define CLEAN_TARGET 25u
#define FREE_TARGET 25u
-static unsigned percent_to_target(struct smq_policy *mq, unsigned p)
+static unsigned int percent_to_target(struct smq_policy *mq, unsigned int p)
{
return from_cblock(mq->cache_size) * p / 100u;
}
@@ -1150,7 +1153,7 @@ static bool clean_target_met(struct smq_policy *mq, bool idle)
static bool free_target_met(struct smq_policy *mq)
{
- unsigned nr_free;
+ unsigned int nr_free;
nr_free = from_cblock(mq->cache_size) - mq->cache_alloc.nr_allocated;
return (nr_free + btracker_nr_demotions_queued(mq->bg_work)) >=
@@ -1300,7 +1303,7 @@ static dm_oblock_t to_hblock(struct smq_policy *mq, dm_oblock_t b)
static struct entry *update_hotspot_queue(struct smq_policy *mq, dm_oblock_t b)
{
- unsigned hi;
+ unsigned int hi;
dm_oblock_t hb = to_hblock(mq, b);
struct entry *e = h_lookup(&mq->hotspot_table, hb);
@@ -1549,7 +1552,7 @@ static void smq_clear_dirty(struct dm_cache_policy *p, dm_cblock_t cblock)
spin_unlock_irqrestore(&mq->lock, flags);
}
-static unsigned random_level(dm_cblock_t cblock)
+static unsigned int random_level(dm_cblock_t cblock)
{
return hash_32(from_cblock(cblock), 9) & (NR_CACHE_LEVELS - 1);
}
@@ -1631,6 +1634,7 @@ static void smq_tick(struct dm_cache_policy *p, bool can_block)
static void smq_allow_migrations(struct dm_cache_policy *p, bool allow)
{
struct smq_policy *mq = to_smq_policy(p);
+
mq->migrations_allowed = allow;
}
@@ -1660,7 +1664,7 @@ static int mq_set_config_value(struct dm_cache_policy *p,
}
static int mq_emit_config_values(struct dm_cache_policy *p, char *result,
- unsigned maxlen, ssize_t *sz_ptr)
+ unsigned int maxlen, ssize_t *sz_ptr)
{
ssize_t sz = *sz_ptr;
@@ -1699,16 +1703,16 @@ static void init_policy_functions(struct smq_policy *mq, bool mimic_mq)
static bool too_many_hotspot_blocks(sector_t origin_size,
sector_t hotspot_block_size,
- unsigned nr_hotspot_blocks)
+ unsigned int nr_hotspot_blocks)
{
return (hotspot_block_size * nr_hotspot_blocks) > origin_size;
}
static void calc_hotspot_params(sector_t origin_size,
sector_t cache_block_size,
- unsigned nr_cache_blocks,
+ unsigned int nr_cache_blocks,
sector_t *hotspot_block_size,
- unsigned *nr_hotspot_blocks)
+ unsigned int *nr_hotspot_blocks)
{
*hotspot_block_size = cache_block_size * 16u;
*nr_hotspot_blocks = max(nr_cache_blocks / 4u, 1024u);
@@ -1724,9 +1728,9 @@ static struct dm_cache_policy *__smq_create(dm_cblock_t cache_size,
bool mimic_mq,
bool migrations_allowed)
{
- unsigned i;
- unsigned nr_sentinels_per_queue = 2u * NR_CACHE_LEVELS;
- unsigned total_sentinels = 2u * nr_sentinels_per_queue;
+ unsigned int i;
+ unsigned int nr_sentinels_per_queue = 2u * NR_CACHE_LEVELS;
+ unsigned int total_sentinels = 2u * nr_sentinels_per_queue;
struct smq_policy *mq = kzalloc(sizeof(*mq), GFP_KERNEL);
if (!mq)
diff --git a/drivers/md/dm-cache-policy.c b/drivers/md/dm-cache-policy.c
index c1a3cee99b44..9330d5748895 100644
--- a/drivers/md/dm-cache-policy.c
+++ b/drivers/md/dm-cache-policy.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Red Hat. All rights reserved.
*
@@ -154,7 +155,7 @@ const char *dm_cache_policy_get_name(struct dm_cache_policy *p)
}
EXPORT_SYMBOL_GPL(dm_cache_policy_get_name);
-const unsigned *dm_cache_policy_get_version(struct dm_cache_policy *p)
+const unsigned int *dm_cache_policy_get_version(struct dm_cache_policy *p)
{
struct dm_cache_policy_type *t = p->private;
diff --git a/drivers/md/dm-cache-policy.h b/drivers/md/dm-cache-policy.h
index 06eb31af626f..a1eedcc42677 100644
--- a/drivers/md/dm-cache-policy.h
+++ b/drivers/md/dm-cache-policy.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2012 Red Hat. All rights reserved.
*
@@ -75,7 +76,7 @@ struct dm_cache_policy {
* background work.
*/
int (*get_background_work)(struct dm_cache_policy *p, bool idle,
- struct policy_work **result);
+ struct policy_work **result);
/*
* You must pass in the same work pointer that you were given, not
@@ -128,7 +129,7 @@ struct dm_cache_policy {
* Configuration.
*/
int (*emit_config_values)(struct dm_cache_policy *p, char *result,
- unsigned maxlen, ssize_t *sz_ptr);
+ unsigned int maxlen, ssize_t *sz_ptr);
int (*set_config_value)(struct dm_cache_policy *p,
const char *key, const char *value);
@@ -157,7 +158,7 @@ struct dm_cache_policy_type {
* what gets passed on the target line to select your policy.
*/
char name[CACHE_POLICY_NAME_SIZE];
- unsigned version[CACHE_POLICY_VERSION_SIZE];
+ unsigned int version[CACHE_POLICY_VERSION_SIZE];
/*
* For use by an alias dm_cache_policy_type to point to the
diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c
index 5e92fac90b67..dbbcfa580078 100644
--- a/drivers/md/dm-cache-target.c
+++ b/drivers/md/dm-cache-target.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Red Hat. All rights reserved.
*
@@ -180,15 +181,15 @@ static void continue_after_commit(struct batcher *b, struct continuation *k)
*/
static void issue_after_commit(struct batcher *b, struct bio *bio)
{
- bool commit_scheduled;
+ bool commit_scheduled;
- spin_lock_irq(&b->lock);
- commit_scheduled = b->commit_scheduled;
- bio_list_add(&b->bios, bio);
- spin_unlock_irq(&b->lock);
+ spin_lock_irq(&b->lock);
+ commit_scheduled = b->commit_scheduled;
+ bio_list_add(&b->bios, bio);
+ spin_unlock_irq(&b->lock);
- if (commit_scheduled)
- async_commit(b);
+ if (commit_scheduled)
+ async_commit(b);
}
/*
@@ -275,7 +276,7 @@ enum cache_io_mode {
struct cache_features {
enum cache_metadata_mode mode;
enum cache_io_mode io_mode;
- unsigned metadata_version;
+ unsigned int metadata_version;
bool discard_passdown:1;
};
@@ -362,7 +363,7 @@ struct cache {
* Rather than reconstructing the table line for the status we just
* save it and regurgitate.
*/
- unsigned nr_ctr_args;
+ unsigned int nr_ctr_args;
const char **ctr_args;
struct dm_kcopyd_client *copier;
@@ -378,7 +379,7 @@ struct cache {
unsigned long *dirty_bitset;
atomic_t nr_dirty;
- unsigned policy_nr_args;
+ unsigned int policy_nr_args;
struct dm_cache_policy *policy;
/*
@@ -409,7 +410,7 @@ struct cache {
struct per_bio_data {
bool tick:1;
- unsigned req_nr:2;
+ unsigned int req_nr:2;
struct dm_bio_prison_cell_v2 *cell;
struct dm_hook_info hook_info;
sector_t len;
@@ -517,20 +518,23 @@ static void build_key(dm_oblock_t begin, dm_oblock_t end, struct dm_cell_key_v2
#define WRITE_LOCK_LEVEL 0
#define READ_WRITE_LOCK_LEVEL 1
-static unsigned lock_level(struct bio *bio)
+static unsigned int lock_level(struct bio *bio)
{
return bio_data_dir(bio) == WRITE ?
WRITE_LOCK_LEVEL :
READ_WRITE_LOCK_LEVEL;
}
-/*----------------------------------------------------------------
+/*
+ *--------------------------------------------------------------
* Per bio data
- *--------------------------------------------------------------*/
+ *--------------------------------------------------------------
+ */
static struct per_bio_data *get_per_bio_data(struct bio *bio)
{
struct per_bio_data *pb = dm_per_bio_data(bio, sizeof(struct per_bio_data));
+
BUG_ON(!pb);
return pb;
}
@@ -687,6 +691,7 @@ static void clear_discard(struct cache *cache, dm_dblock_t b)
static bool is_discarded(struct cache *cache, dm_dblock_t b)
{
int r;
+
spin_lock_irq(&cache->lock);
r = test_bit(from_dblock(b), cache->discard_bitset);
spin_unlock_irq(&cache->lock);
@@ -697,6 +702,7 @@ static bool is_discarded(struct cache *cache, dm_dblock_t b)
static bool is_discarded_oblock(struct cache *cache, dm_oblock_t b)
{
int r;
+
spin_lock_irq(&cache->lock);
r = test_bit(from_dblock(oblock_to_dblock(cache, b)),
cache->discard_bitset);
@@ -705,9 +711,11 @@ static bool is_discarded_oblock(struct cache *cache, dm_oblock_t b)
return r;
}
-/*----------------------------------------------------------------
+/*
+ * -------------------------------------------------------------
* Remapping
- *--------------------------------------------------------------*/
+ *--------------------------------------------------------------
+ */
static void remap_to_origin(struct cache *cache, struct bio *bio)
{
bio_set_dev(bio, cache->origin_dev->bdev);
@@ -809,6 +817,7 @@ static void accounted_request(struct cache *cache, struct bio *bio)
static void issue_op(struct bio *bio, void *context)
{
struct cache *cache = context;
+
accounted_request(cache, bio);
}
@@ -833,9 +842,11 @@ static void remap_to_origin_and_cache(struct cache *cache, struct bio *bio,
remap_to_cache(cache, bio, cblock);
}
-/*----------------------------------------------------------------
+/*
+ *--------------------------------------------------------------
* Failure modes
- *--------------------------------------------------------------*/
+ *--------------------------------------------------------------
+ */
static enum cache_metadata_mode get_cache_mode(struct cache *cache)
{
return cache->features.mode;
@@ -848,7 +859,7 @@ static const char *cache_device_name(struct cache *cache)
static void notify_mode_switch(struct cache *cache, enum cache_metadata_mode mode)
{
- const char *descs[] = {
+ static const char *descs[] = {
"write",
"read-only",
"fail"
@@ -972,13 +983,14 @@ static void update_stats(struct cache_stats *stats, enum policy_operation op)
}
}
-/*----------------------------------------------------------------
+/*
+ *---------------------------------------------------------------------
* Migration processing
*
* Migration covers moving data from the origin device to the cache, or
* vice versa.
- *--------------------------------------------------------------*/
-
+ *---------------------------------------------------------------------
+ */
static void inc_io_migrations(struct cache *cache)
{
atomic_inc(&cache->nr_io_migrations);
@@ -1066,6 +1078,7 @@ static void quiesce(struct dm_cache_migration *mg,
static struct dm_cache_migration *ws_to_mg(struct work_struct *ws)
{
struct continuation *k = container_of(ws, struct continuation, ws);
+
return container_of(k, struct dm_cache_migration, k);
}
@@ -1217,6 +1230,7 @@ static void mg_complete(struct dm_cache_migration *mg, bool success)
static void mg_success(struct work_struct *ws)
{
struct dm_cache_migration *mg = ws_to_mg(ws);
+
mg_complete(mg, mg->k.input == 0);
}
@@ -1355,6 +1369,7 @@ static void mg_copy(struct work_struct *ws)
* Fallback to a real full copy after doing some tidying up.
*/
bool rb = bio_detain_shared(mg->cache, mg->op->oblock, mg->overwrite_bio);
+
BUG_ON(rb); /* An exclussive lock must _not_ be held for this block */
mg->overwrite_bio = NULL;
inc_io_migrations(mg->cache);
@@ -1430,9 +1445,11 @@ static int mg_start(struct cache *cache, struct policy_work *op, struct bio *bio
return mg_lock_writes(mg);
}
-/*----------------------------------------------------------------
+/*
+ *--------------------------------------------------------------
* invalidation processing
- *--------------------------------------------------------------*/
+ *--------------------------------------------------------------
+ */
static void invalidate_complete(struct dm_cache_migration *mg, bool success)
{
@@ -1455,12 +1472,15 @@ static void invalidate_complete(struct dm_cache_migration *mg, bool success)
static void invalidate_completed(struct work_struct *ws)
{
struct dm_cache_migration *mg = ws_to_mg(ws);
+
invalidate_complete(mg, !mg->k.input);
}
static int invalidate_cblock(struct cache *cache, dm_cblock_t cblock)
{
- int r = policy_invalidate_mapping(cache->policy, cblock);
+ int r;
+
+ r = policy_invalidate_mapping(cache->policy, cblock);
if (!r) {
r = dm_cache_remove_mapping(cache->cmd, cblock);
if (r) {
@@ -1553,9 +1573,11 @@ static int invalidate_start(struct cache *cache, dm_cblock_t cblock,
return invalidate_lock(mg);
}
-/*----------------------------------------------------------------
+/*
+ *--------------------------------------------------------------
* bio processing
- *--------------------------------------------------------------*/
+ *--------------------------------------------------------------
+ */
enum busy {
IDLE,
@@ -1763,9 +1785,11 @@ static bool process_discard_bio(struct cache *cache, struct bio *bio)
{
dm_dblock_t b, e;
- // FIXME: do we need to lock the region? Or can we just assume the
- // user wont be so foolish as to issue discard concurrently with
- // other IO?
+ /*
+ * FIXME: do we need to lock the region? Or can we just assume the
+ * user wont be so foolish as to issue discard concurrently with
+ * other IO?
+ */
calc_discard_block_range(cache, bio, &b, &e);
while (b != e) {
set_discard(cache, b);
@@ -1805,16 +1829,18 @@ static void process_deferred_bios(struct work_struct *ws)
else
commit_needed = process_bio(cache, bio) || commit_needed;
+ cond_resched();
}
if (commit_needed)
schedule_commit(&cache->committer);
}
-/*----------------------------------------------------------------
+/*
+ *--------------------------------------------------------------
* Main worker loop
- *--------------------------------------------------------------*/
-
+ *--------------------------------------------------------------
+ */
static void requeue_deferred_bios(struct cache *cache)
{
struct bio *bio;
@@ -1827,6 +1853,7 @@ static void requeue_deferred_bios(struct cache *cache)
while ((bio = bio_list_pop(&bios))) {
bio->bi_status = BLK_STS_DM_REQUEUE;
bio_endio(bio);
+ cond_resched();
}
}
@@ -1867,12 +1894,16 @@ static void check_migrations(struct work_struct *ws)
r = mg_start(cache, op, NULL);
if (r)
break;
+
+ cond_resched();
}
}
-/*----------------------------------------------------------------
+/*
+ *--------------------------------------------------------------
* Target methods
- *--------------------------------------------------------------*/
+ *--------------------------------------------------------------
+ */
/*
* This function gets called on the error paths of the constructor, so we
@@ -1880,7 +1911,7 @@ static void check_migrations(struct work_struct *ws)
*/
static void destroy(struct cache *cache)
{
- unsigned i;
+ unsigned int i;
mempool_exit(&cache->migration_pool);
@@ -2120,7 +2151,7 @@ static int parse_features(struct cache_args *ca, struct dm_arg_set *as,
};
int r, mode_ctr = 0;
- unsigned argc;
+ unsigned int argc;
const char *arg;
struct cache_features *cf = &ca->features;
@@ -2540,7 +2571,7 @@ bad:
static int copy_ctr_args(struct cache *cache, int argc, const char **argv)
{
- unsigned i;
+ unsigned int i;
const char **copy;
copy = kcalloc(argc, sizeof(*copy), GFP_KERNEL);
@@ -2562,7 +2593,7 @@ static int copy_ctr_args(struct cache *cache, int argc, const char **argv)
return 0;
}
-static int cache_ctr(struct dm_target *ti, unsigned argc, char **argv)
+static int cache_ctr(struct dm_target *ti, unsigned int argc, char **argv)
{
int r = -EINVAL;
struct cache_args *ca;
@@ -2665,7 +2696,7 @@ static int write_dirty_bitset(struct cache *cache)
static int write_discard_bitset(struct cache *cache)
{
- unsigned i, r;
+ unsigned int i, r;
if (get_cache_mode(cache) >= CM_READ_ONLY)
return -EINVAL;
@@ -2979,11 +3010,11 @@ static void cache_resume(struct dm_target *ti)
}
static void emit_flags(struct cache *cache, char *result,
- unsigned maxlen, ssize_t *sz_ptr)
+ unsigned int maxlen, ssize_t *sz_ptr)
{
ssize_t sz = *sz_ptr;
struct cache_features *cf = &cache->features;
- unsigned count = (cf->metadata_version == 2) + !cf->discard_passdown + 1;
+ unsigned int count = (cf->metadata_version == 2) + !cf->discard_passdown + 1;
DMEMIT("%u ", count);
@@ -3023,10 +3054,10 @@ static void emit_flags(struct cache *cache, char *result,
* <policy name> <#policy args> <policy args>* <cache metadata mode> <needs_check>
*/
static void cache_status(struct dm_target *ti, status_type_t type,
- unsigned status_flags, char *result, unsigned maxlen)
+ unsigned int status_flags, char *result, unsigned int maxlen)
{
int r = 0;
- unsigned i;
+ unsigned int i;
ssize_t sz = 0;
dm_block_t nr_free_blocks_metadata = 0;
dm_block_t nr_blocks_metadata = 0;
@@ -3063,18 +3094,18 @@ static void cache_status(struct dm_target *ti, status_type_t type,
residency = policy_residency(cache->policy);
DMEMIT("%u %llu/%llu %llu %llu/%llu %u %u %u %u %u %u %lu ",
- (unsigned)DM_CACHE_METADATA_BLOCK_SIZE,
+ (unsigned int)DM_CACHE_METADATA_BLOCK_SIZE,
(unsigned long long)(nr_blocks_metadata - nr_free_blocks_metadata),
(unsigned long long)nr_blocks_metadata,
(unsigned long long)cache->sectors_per_block,
(unsigned long long) from_cblock(residency),
(unsigned long long) from_cblock(cache->cache_size),
- (unsigned) atomic_read(&cache->stats.read_hit),
- (unsigned) atomic_read(&cache->stats.read_miss),
- (unsigned) atomic_read(&cache->stats.write_hit),
- (unsigned) atomic_read(&cache->stats.write_miss),
- (unsigned) atomic_read(&cache->stats.demotion),
- (unsigned) atomic_read(&cache->stats.promotion),
+ (unsigned int) atomic_read(&cache->stats.read_hit),
+ (unsigned int) atomic_read(&cache->stats.read_miss),
+ (unsigned int) atomic_read(&cache->stats.write_hit),
+ (unsigned int) atomic_read(&cache->stats.write_miss),
+ (unsigned int) atomic_read(&cache->stats.demotion),
+ (unsigned int) atomic_read(&cache->stats.promotion),
(unsigned long) atomic_read(&cache->nr_dirty));
emit_flags(cache, result, maxlen, &sz);
@@ -3253,11 +3284,11 @@ static int request_invalidation(struct cache *cache, struct cblock_range *range)
return r;
}
-static int process_invalidate_cblocks_message(struct cache *cache, unsigned count,
+static int process_invalidate_cblocks_message(struct cache *cache, unsigned int count,
const char **cblock_ranges)
{
int r = 0;
- unsigned i;
+ unsigned int i;
struct cblock_range range;
if (!passthrough_mode(cache)) {
@@ -3294,8 +3325,8 @@ static int process_invalidate_cblocks_message(struct cache *cache, unsigned coun
*
* The key migration_threshold is supported by the cache target core.
*/
-static int cache_message(struct dm_target *ti, unsigned argc, char **argv,
- char *result, unsigned maxlen)
+static int cache_message(struct dm_target *ti, unsigned int argc, char **argv,
+ char *result, unsigned int maxlen)
{
struct cache *cache = ti->private;
diff --git a/drivers/md/dm-clone-target.c b/drivers/md/dm-clone-target.c
index 29e0b85eeaf0..f38a27604c7a 100644
--- a/drivers/md/dm-clone-target.c
+++ b/drivers/md/dm-clone-target.c
@@ -580,7 +580,7 @@ static int hash_table_init(struct clone *clone)
sz = 1 << HASH_TABLE_BITS;
- clone->ht = kvmalloc(sz * sizeof(struct hash_table_bucket), GFP_KERNEL);
+ clone->ht = kvmalloc_array(sz, sizeof(struct hash_table_bucket), GFP_KERNEL);
if (!clone->ht)
return -ENOMEM;
diff --git a/drivers/md/dm-core.h b/drivers/md/dm-core.h
index 6c6bd24774f2..aecab0c0720f 100644
--- a/drivers/md/dm-core.h
+++ b/drivers/md/dm-core.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Internal header file _only_ for device mapper core
*
@@ -119,7 +120,7 @@ struct mapped_device {
struct dm_stats stats;
/* the number of internal suspends */
- unsigned internal_suspend_count;
+ unsigned int internal_suspend_count;
int swap_bios;
struct semaphore swap_bios_semaphore;
@@ -216,7 +217,7 @@ struct dm_table {
struct list_head devices;
/* events get handed up using this callback */
- void (*event_fn)(void *);
+ void (*event_fn)(void *data);
void *event_context;
struct dm_md_mempools *mempools;
@@ -326,9 +327,9 @@ static inline struct completion *dm_get_completion_from_kobject(struct kobject *
return &container_of(kobj, struct dm_kobject_holder, kobj)->completion;
}
-unsigned __dm_get_module_param(unsigned *module_param, unsigned def, unsigned max);
+unsigned int __dm_get_module_param(unsigned int *module_param, unsigned int def, unsigned int max);
-static inline bool dm_message_test_buffer_overflow(char *result, unsigned maxlen)
+static inline bool dm_message_test_buffer_overflow(char *result, unsigned int maxlen)
{
return !maxlen || strlen(result) + 1 >= maxlen;
}
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 3aeeb8f2802f..40cb1719ae4d 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2003 Jana Saout <jana@saout.de>
* Copyright (C) 2004 Clemens Fruhwirth <clemens@endorphin.org>
@@ -171,14 +172,14 @@ struct crypt_config {
} iv_gen_private;
u64 iv_offset;
unsigned int iv_size;
- unsigned short int sector_size;
+ unsigned short sector_size;
unsigned char sector_shift;
union {
struct crypto_skcipher **tfms;
struct crypto_aead **tfms_aead;
} cipher_tfm;
- unsigned tfms_count;
+ unsigned int tfms_count;
unsigned long cipher_flags;
/*
@@ -212,7 +213,7 @@ struct crypt_config {
* pool for per bio private data, crypto requests,
* encryption requeusts/buffer pages and integrity tags
*/
- unsigned tag_pool_max_sectors;
+ unsigned int tag_pool_max_sectors;
mempool_t tag_pool;
mempool_t req_pool;
mempool_t page_pool;
@@ -229,7 +230,7 @@ struct crypt_config {
#define POOL_ENTRY_SIZE 512
static DEFINE_SPINLOCK(dm_crypt_clients_lock);
-static unsigned dm_crypt_clients_n = 0;
+static unsigned int dm_crypt_clients_n;
static volatile unsigned long dm_crypt_pages_per_client;
#define DM_CRYPT_MEMORY_PERCENT 2
#define DM_CRYPT_MIN_PAGES_PER_CLIENT (BIO_MAX_VECS * 16)
@@ -354,7 +355,7 @@ static int crypt_iv_essiv_gen(struct crypt_config *cc, u8 *iv,
static int crypt_iv_benbi_ctr(struct crypt_config *cc, struct dm_target *ti,
const char *opts)
{
- unsigned bs;
+ unsigned int bs;
int log;
if (crypt_integrity_aead(cc))
@@ -363,9 +364,10 @@ static int crypt_iv_benbi_ctr(struct crypt_config *cc, struct dm_target *ti,
bs = crypto_skcipher_blocksize(any_tfm(cc));
log = ilog2(bs);
- /* we need to calculate how far we must shift the sector count
- * to get the cipher block count, we use this shift in _gen */
-
+ /*
+ * We need to calculate how far we must shift the sector count
+ * to get the cipher block count, we use this shift in _gen.
+ */
if (1 << log != bs) {
ti->error = "cypher blocksize is not a power of 2";
return -EINVAL;
@@ -531,9 +533,9 @@ static int crypt_iv_lmk_gen(struct crypt_config *cc, u8 *iv,
if (bio_data_dir(dmreq->ctx->bio_in) == WRITE) {
sg = crypt_get_sg_data(cc, dmreq->sg_in);
- src = kmap_atomic(sg_page(sg));
+ src = kmap_local_page(sg_page(sg));
r = crypt_iv_lmk_one(cc, iv, dmreq, src + sg->offset);
- kunmap_atomic(src);
+ kunmap_local(src);
} else
memset(iv, 0, cc->iv_size);
@@ -551,14 +553,14 @@ static int crypt_iv_lmk_post(struct crypt_config *cc, u8 *iv,
return 0;
sg = crypt_get_sg_data(cc, dmreq->sg_out);
- dst = kmap_atomic(sg_page(sg));
+ dst = kmap_local_page(sg_page(sg));
r = crypt_iv_lmk_one(cc, iv, dmreq, dst + sg->offset);
/* Tweak the first block of plaintext sector */
if (!r)
crypto_xor(dst + sg->offset, iv, cc->iv_size);
- kunmap_atomic(dst);
+ kunmap_local(dst);
return r;
}
@@ -681,9 +683,9 @@ static int crypt_iv_tcw_gen(struct crypt_config *cc, u8 *iv,
/* Remove whitening from ciphertext */
if (bio_data_dir(dmreq->ctx->bio_in) != WRITE) {
sg = crypt_get_sg_data(cc, dmreq->sg_in);
- src = kmap_atomic(sg_page(sg));
+ src = kmap_local_page(sg_page(sg));
r = crypt_iv_tcw_whitening(cc, dmreq, src + sg->offset);
- kunmap_atomic(src);
+ kunmap_local(src);
}
/* Calculate IV */
@@ -707,9 +709,9 @@ static int crypt_iv_tcw_post(struct crypt_config *cc, u8 *iv,
/* Apply whitening on ciphertext */
sg = crypt_get_sg_data(cc, dmreq->sg_out);
- dst = kmap_atomic(sg_page(sg));
+ dst = kmap_local_page(sg_page(sg));
r = crypt_iv_tcw_whitening(cc, dmreq, dst + sg->offset);
- kunmap_atomic(dst);
+ kunmap_local(dst);
return r;
}
@@ -731,8 +733,7 @@ static int crypt_iv_eboiv_ctr(struct crypt_config *cc, struct dm_target *ti,
}
if (crypto_skcipher_blocksize(any_tfm(cc)) != cc->iv_size) {
- ti->error = "Block size of EBOIV cipher does "
- "not match IV size of block cipher";
+ ti->error = "Block size of EBOIV cipher does not match IV size of block cipher";
return -EINVAL;
}
@@ -974,35 +975,35 @@ static int crypt_iv_elephant(struct crypt_config *cc, struct dm_crypt_request *d
goto out;
sg = crypt_get_sg_data(cc, dmreq->sg_out);
- data = kmap_atomic(sg_page(sg));
+ data = kmap_local_page(sg_page(sg));
data_offset = data + sg->offset;
/* Cannot modify original bio, copy to sg_out and apply Elephant to it */
if (bio_data_dir(dmreq->ctx->bio_in) == WRITE) {
sg2 = crypt_get_sg_data(cc, dmreq->sg_in);
- data2 = kmap_atomic(sg_page(sg2));
+ data2 = kmap_local_page(sg_page(sg2));
memcpy(data_offset, data2 + sg2->offset, cc->sector_size);
- kunmap_atomic(data2);
+ kunmap_local(data2);
}
if (bio_data_dir(dmreq->ctx->bio_in) != WRITE) {
- diffuser_disk_to_cpu((u32*)data_offset, cc->sector_size / sizeof(u32));
- diffuser_b_decrypt((u32*)data_offset, cc->sector_size / sizeof(u32));
- diffuser_a_decrypt((u32*)data_offset, cc->sector_size / sizeof(u32));
- diffuser_cpu_to_disk((__le32*)data_offset, cc->sector_size / sizeof(u32));
+ diffuser_disk_to_cpu((u32 *)data_offset, cc->sector_size / sizeof(u32));
+ diffuser_b_decrypt((u32 *)data_offset, cc->sector_size / sizeof(u32));
+ diffuser_a_decrypt((u32 *)data_offset, cc->sector_size / sizeof(u32));
+ diffuser_cpu_to_disk((__le32 *)data_offset, cc->sector_size / sizeof(u32));
}
for (i = 0; i < (cc->sector_size / 32); i++)
crypto_xor(data_offset + i * 32, ks, 32);
if (bio_data_dir(dmreq->ctx->bio_in) == WRITE) {
- diffuser_disk_to_cpu((u32*)data_offset, cc->sector_size / sizeof(u32));
- diffuser_a_encrypt((u32*)data_offset, cc->sector_size / sizeof(u32));
- diffuser_b_encrypt((u32*)data_offset, cc->sector_size / sizeof(u32));
- diffuser_cpu_to_disk((__le32*)data_offset, cc->sector_size / sizeof(u32));
+ diffuser_disk_to_cpu((u32 *)data_offset, cc->sector_size / sizeof(u32));
+ diffuser_a_encrypt((u32 *)data_offset, cc->sector_size / sizeof(u32));
+ diffuser_b_encrypt((u32 *)data_offset, cc->sector_size / sizeof(u32));
+ diffuser_cpu_to_disk((__le32 *)data_offset, cc->sector_size / sizeof(u32));
}
- kunmap_atomic(data);
+ kunmap_local(data);
out:
kfree_sensitive(ks);
kfree_sensitive(es);
@@ -1255,6 +1256,7 @@ static __le64 *org_sector_of_dmreq(struct crypt_config *cc,
struct dm_crypt_request *dmreq)
{
u8 *ptr = iv_of_dmreq(cc, dmreq) + cc->iv_size + cc->iv_size;
+
return (__le64 *) ptr;
}
@@ -1263,7 +1265,8 @@ static unsigned int *org_tag_of_dmreq(struct crypt_config *cc,
{
u8 *ptr = iv_of_dmreq(cc, dmreq) + cc->iv_size +
cc->iv_size + sizeof(uint64_t);
- return (unsigned int*)ptr;
+
+ return (unsigned int *)ptr;
}
static void *tag_from_dmreq(struct crypt_config *cc,
@@ -1463,7 +1466,7 @@ static void kcryptd_async_done(void *async_req, int error);
static int crypt_alloc_req_skcipher(struct crypt_config *cc,
struct convert_context *ctx)
{
- unsigned key_index = ctx->cc_sector & (cc->tfms_count - 1);
+ unsigned int key_index = ctx->cc_sector & (cc->tfms_count - 1);
if (!ctx->r.req) {
ctx->r.req = mempool_alloc(&cc->req_pool, in_interrupt() ? GFP_ATOMIC : GFP_NOIO);
@@ -1657,13 +1660,13 @@ static void crypt_free_buffer_pages(struct crypt_config *cc, struct bio *clone);
* non-blocking allocations without a mutex first but on failure we fallback
* to blocking allocations with a mutex.
*/
-static struct bio *crypt_alloc_buffer(struct dm_crypt_io *io, unsigned size)
+static struct bio *crypt_alloc_buffer(struct dm_crypt_io *io, unsigned int size)
{
struct crypt_config *cc = io->cc;
struct bio *clone;
unsigned int nr_iovecs = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
gfp_t gfp_mask = GFP_NOWAIT | __GFP_HIGHMEM;
- unsigned i, len, remaining_size;
+ unsigned int i, len, remaining_size;
struct page *page;
retry:
@@ -1738,6 +1741,7 @@ static void crypt_inc_pending(struct dm_crypt_io *io)
static void kcryptd_io_bio_endio(struct work_struct *work)
{
struct dm_crypt_io *io = container_of(work, struct dm_crypt_io, work);
+
bio_endio(io->base_bio);
}
@@ -1803,7 +1807,7 @@ static void crypt_endio(struct bio *clone)
{
struct dm_crypt_io *io = clone->bi_private;
struct crypt_config *cc = io->cc;
- unsigned rw = bio_data_dir(clone);
+ unsigned int rw = bio_data_dir(clone);
blk_status_t error;
/*
@@ -2255,7 +2259,7 @@ static void crypt_free_tfms_aead(struct crypt_config *cc)
static void crypt_free_tfms_skcipher(struct crypt_config *cc)
{
- unsigned i;
+ unsigned int i;
if (!cc->cipher_tfm.tfms)
return;
@@ -2280,7 +2284,7 @@ static void crypt_free_tfms(struct crypt_config *cc)
static int crypt_alloc_tfms_skcipher(struct crypt_config *cc, char *ciphermode)
{
- unsigned i;
+ unsigned int i;
int err;
cc->cipher_tfm.tfms = kcalloc(cc->tfms_count,
@@ -2338,12 +2342,12 @@ static int crypt_alloc_tfms(struct crypt_config *cc, char *ciphermode)
return crypt_alloc_tfms_skcipher(cc, ciphermode);
}
-static unsigned crypt_subkey_size(struct crypt_config *cc)
+static unsigned int crypt_subkey_size(struct crypt_config *cc)
{
return (cc->key_size - cc->key_extra_size) >> ilog2(cc->tfms_count);
}
-static unsigned crypt_authenckey_size(struct crypt_config *cc)
+static unsigned int crypt_authenckey_size(struct crypt_config *cc)
{
return crypt_subkey_size(cc) + RTA_SPACE(sizeof(struct crypto_authenc_key_param));
}
@@ -2354,7 +2358,7 @@ static unsigned crypt_authenckey_size(struct crypt_config *cc)
* This funcion converts cc->key to this special format.
*/
static void crypt_copy_authenckey(char *p, const void *key,
- unsigned enckeylen, unsigned authkeylen)
+ unsigned int enckeylen, unsigned int authkeylen)
{
struct crypto_authenc_key_param *param;
struct rtattr *rta;
@@ -2372,7 +2376,7 @@ static void crypt_copy_authenckey(char *p, const void *key,
static int crypt_setkey(struct crypt_config *cc)
{
- unsigned subkey_size;
+ unsigned int subkey_size;
int err = 0, i, r;
/* Ignore extra keys (which are used for IV etc) */
@@ -2485,7 +2489,7 @@ static int crypt_set_keyring_key(struct crypt_config *cc, const char *key_string
}
/* look for next ':' separating key_type from key_description */
- key_desc = strpbrk(key_string, ":");
+ key_desc = strchr(key_string, ':');
if (!key_desc || key_desc == key_string || !strlen(key_desc + 1))
return -EINVAL;
@@ -2500,7 +2504,7 @@ static int crypt_set_keyring_key(struct crypt_config *cc, const char *key_string
type = &key_type_encrypted;
set_key = set_key_encrypted;
} else if (IS_ENABLED(CONFIG_TRUSTED_KEYS) &&
- !strncmp(key_string, "trusted:", key_desc - key_string + 1)) {
+ !strncmp(key_string, "trusted:", key_desc - key_string + 1)) {
type = &key_type_trusted;
set_key = set_key_trusted;
} else {
@@ -3411,11 +3415,14 @@ static int crypt_map(struct dm_target *ti, struct bio *bio)
crypt_io_init(io, cc, bio, dm_target_offset(ti, bio->bi_iter.bi_sector));
if (cc->on_disk_tag_size) {
- unsigned tag_len = cc->on_disk_tag_size * (bio_sectors(bio) >> cc->sector_shift);
+ unsigned int tag_len = cc->on_disk_tag_size * (bio_sectors(bio) >> cc->sector_shift);
+
+ if (unlikely(tag_len > KMALLOC_MAX_SIZE))
+ io->integrity_metadata = NULL;
+ else
+ io->integrity_metadata = kmalloc(tag_len, GFP_NOIO | __GFP_NORETRY | __GFP_NOMEMALLOC | __GFP_NOWARN);
- if (unlikely(tag_len > KMALLOC_MAX_SIZE) ||
- unlikely(!(io->integrity_metadata = kmalloc(tag_len,
- GFP_NOIO | __GFP_NORETRY | __GFP_NOMEMALLOC | __GFP_NOWARN)))) {
+ if (unlikely(!io->integrity_metadata)) {
if (bio_sectors(bio) > cc->tag_pool_max_sectors)
dm_accept_partial_bio(bio, cc->tag_pool_max_sectors);
io->integrity_metadata = mempool_alloc(&cc->tag_pool, GFP_NOIO);
@@ -3439,14 +3446,14 @@ static int crypt_map(struct dm_target *ti, struct bio *bio)
static char hex2asc(unsigned char c)
{
- return c + '0' + ((unsigned)(9 - c) >> 4 & 0x27);
+ return c + '0' + ((unsigned int)(9 - c) >> 4 & 0x27);
}
static void crypt_status(struct dm_target *ti, status_type_t type,
- unsigned status_flags, char *result, unsigned maxlen)
+ unsigned int status_flags, char *result, unsigned int maxlen)
{
struct crypt_config *cc = ti->private;
- unsigned i, sz = 0;
+ unsigned int i, sz = 0;
int num_feature_args = 0;
switch (type) {
@@ -3562,8 +3569,8 @@ static void crypt_resume(struct dm_target *ti)
* key set <key>
* key wipe
*/
-static int crypt_message(struct dm_target *ti, unsigned argc, char **argv,
- char *result, unsigned maxlen)
+static int crypt_message(struct dm_target *ti, unsigned int argc, char **argv,
+ char *result, unsigned int maxlen)
{
struct crypt_config *cc = ti->private;
int key_size, ret = -EINVAL;
@@ -3624,10 +3631,10 @@ static void crypt_io_hints(struct dm_target *ti, struct queue_limits *limits)
limits->max_segment_size = PAGE_SIZE;
limits->logical_block_size =
- max_t(unsigned, limits->logical_block_size, cc->sector_size);
+ max_t(unsigned int, limits->logical_block_size, cc->sector_size);
limits->physical_block_size =
- max_t(unsigned, limits->physical_block_size, cc->sector_size);
- limits->io_min = max_t(unsigned, limits->io_min, cc->sector_size);
+ max_t(unsigned int, limits->physical_block_size, cc->sector_size);
+ limits->io_min = max_t(unsigned int, limits->io_min, cc->sector_size);
limits->dma_alignment = limits->logical_block_size - 1;
}
diff --git a/drivers/md/dm-delay.c b/drivers/md/dm-delay.c
index 869afef5654a..a425046f88c7 100644
--- a/drivers/md/dm-delay.c
+++ b/drivers/md/dm-delay.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2005-2007 Red Hat GmbH
*
@@ -20,8 +21,8 @@
struct delay_class {
struct dm_dev *dev;
sector_t start;
- unsigned delay;
- unsigned ops;
+ unsigned int delay;
+ unsigned int ops;
};
struct delay_c {
@@ -305,7 +306,7 @@ static int delay_map(struct dm_target *ti, struct bio *bio)
DMEMIT("%s %llu %u", (c)->dev->name, (unsigned long long)(c)->start, (c)->delay)
static void delay_status(struct dm_target *ti, status_type_t type,
- unsigned status_flags, char *result, unsigned maxlen)
+ unsigned int status_flags, char *result, unsigned int maxlen)
{
struct delay_c *dc = ti->private;
int sz = 0;
diff --git a/drivers/md/dm-dust.c b/drivers/md/dm-dust.c
index 03672204b0e3..7ae9936752de 100644
--- a/drivers/md/dm-dust.c
+++ b/drivers/md/dm-dust.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2018 Red Hat, Inc.
*
diff --git a/drivers/md/dm-ebs-target.c b/drivers/md/dm-ebs-target.c
index 512cc6cea095..b1068a68bc46 100644
--- a/drivers/md/dm-ebs-target.c
+++ b/drivers/md/dm-ebs-target.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2020 Red Hat GmbH
*
@@ -241,7 +242,7 @@ static void __ebs_process_bios(struct work_struct *ws)
* <offset>: offset in 512 bytes sectors into <dev_path>
* <ebs>: emulated block size in units of 512 bytes exposed to the upper layer
* [<ubs>]: underlying block size in units of 512 bytes imposed on the lower layer;
- * optional, if not supplied, retrieve logical block size from underlying device
+ * optional, if not supplied, retrieve logical block size from underlying device
*/
static int ebs_ctr(struct dm_target *ti, unsigned int argc, char **argv)
{
@@ -390,7 +391,7 @@ static int ebs_map(struct dm_target *ti, struct bio *bio)
}
static void ebs_status(struct dm_target *ti, status_type_t type,
- unsigned status_flags, char *result, unsigned maxlen)
+ unsigned int status_flags, char *result, unsigned int maxlen)
{
struct ebs_c *ec = ti->private;
diff --git a/drivers/md/dm-era-target.c b/drivers/md/dm-era-target.c
index e92c1afc3677..c2e7780cdd2d 100644
--- a/drivers/md/dm-era-target.c
+++ b/drivers/md/dm-era-target.c
@@ -22,9 +22,11 @@
#define INVALID_WRITESET_ROOT SUPERBLOCK_LOCATION
#define MIN_BLOCK_SIZE 8
-/*----------------------------------------------------------------
+/*
+ *--------------------------------------------------------------
* Writeset
- *--------------------------------------------------------------*/
+ *--------------------------------------------------------------
+ */
struct writeset_metadata {
uint32_t nr_bits;
dm_block_t root;
@@ -51,7 +53,7 @@ static void writeset_free(struct writeset *ws)
}
static int setup_on_disk_bitset(struct dm_disk_bitset *info,
- unsigned nr_bits, dm_block_t *root)
+ unsigned int nr_bits, dm_block_t *root)
{
int r;
@@ -62,7 +64,7 @@ static int setup_on_disk_bitset(struct dm_disk_bitset *info,
return dm_bitset_resize(info, *root, 0, nr_bits, false, root);
}
-static size_t bitset_size(unsigned nr_bits)
+static size_t bitset_size(unsigned int nr_bits)
{
return sizeof(unsigned long) * dm_div_up(nr_bits, BITS_PER_LONG);
}
@@ -110,13 +112,14 @@ static int writeset_marked_on_disk(struct dm_disk_bitset *info,
struct writeset_metadata *m, dm_block_t block,
bool *result)
{
+ int r;
dm_block_t old = m->root;
/*
* The bitset was flushed when it was archived, so we know there'll
* be no change to the root.
*/
- int r = dm_bitset_test_bit(info, m->root, block, &m->root, result);
+ r = dm_bitset_test_bit(info, m->root, block, &m->root, result);
if (r) {
DMERR("%s: dm_bitset_test_bit failed", __func__);
return r;
@@ -148,9 +151,11 @@ static int writeset_test_and_set(struct dm_disk_bitset *info,
return 1;
}
-/*----------------------------------------------------------------
+/*
+ *--------------------------------------------------------------
* On disk metadata layout
- *--------------------------------------------------------------*/
+ *--------------------------------------------------------------
+ */
#define SPACE_MAP_ROOT_SIZE 128
#define UUID_LEN 16
@@ -186,9 +191,11 @@ struct superblock_disk {
__le64 metadata_snap;
} __packed;
-/*----------------------------------------------------------------
+/*
+ *--------------------------------------------------------------
* Superblock validation
- *--------------------------------------------------------------*/
+ *--------------------------------------------------------------
+ */
static void sb_prepare_for_write(struct dm_block_validator *v,
struct dm_block *b,
size_t sb_block_size)
@@ -204,6 +211,7 @@ static void sb_prepare_for_write(struct dm_block_validator *v,
static int check_metadata_version(struct superblock_disk *disk)
{
uint32_t metadata_version = le32_to_cpu(disk->version);
+
if (metadata_version < MIN_ERA_VERSION || metadata_version > MAX_ERA_VERSION) {
DMERR("Era metadata version %u found, but only versions between %u and %u supported.",
metadata_version, MIN_ERA_VERSION, MAX_ERA_VERSION);
@@ -221,15 +229,15 @@ static int sb_check(struct dm_block_validator *v,
__le32 csum_le;
if (dm_block_location(b) != le64_to_cpu(disk->blocknr)) {
- DMERR("sb_check failed: blocknr %llu: wanted %llu",
- le64_to_cpu(disk->blocknr),
+ DMERR("%s failed: blocknr %llu: wanted %llu",
+ __func__, le64_to_cpu(disk->blocknr),
(unsigned long long)dm_block_location(b));
return -ENOTBLK;
}
if (le64_to_cpu(disk->magic) != SUPERBLOCK_MAGIC) {
- DMERR("sb_check failed: magic %llu: wanted %llu",
- le64_to_cpu(disk->magic),
+ DMERR("%s failed: magic %llu: wanted %llu",
+ __func__, le64_to_cpu(disk->magic),
(unsigned long long) SUPERBLOCK_MAGIC);
return -EILSEQ;
}
@@ -238,8 +246,8 @@ static int sb_check(struct dm_block_validator *v,
sb_block_size - sizeof(__le32),
SUPERBLOCK_CSUM_XOR));
if (csum_le != disk->csum) {
- DMERR("sb_check failed: csum %u: wanted %u",
- le32_to_cpu(csum_le), le32_to_cpu(disk->csum));
+ DMERR("%s failed: csum %u: wanted %u",
+ __func__, le32_to_cpu(csum_le), le32_to_cpu(disk->csum));
return -EILSEQ;
}
@@ -252,9 +260,11 @@ static struct dm_block_validator sb_validator = {
.check = sb_check
};
-/*----------------------------------------------------------------
+/*
+ *--------------------------------------------------------------
* Low level metadata handling
- *--------------------------------------------------------------*/
+ *--------------------------------------------------------------
+ */
#define DM_ERA_METADATA_BLOCK_SIZE 4096
#define ERA_MAX_CONCURRENT_LOCKS 5
@@ -323,10 +333,10 @@ static int superblock_lock(struct era_metadata *md,
static int superblock_all_zeroes(struct dm_block_manager *bm, bool *result)
{
int r;
- unsigned i;
+ unsigned int i;
struct dm_block *b;
__le64 *data_le, zero = cpu_to_le64(0);
- unsigned sb_block_size = dm_bm_block_size(bm) / sizeof(__le64);
+ unsigned int sb_block_size = dm_bm_block_size(bm) / sizeof(__le64);
/*
* We can't use a validator here - it may be all zeroes.
@@ -363,12 +373,12 @@ static void ws_unpack(const struct writeset_disk *disk, struct writeset_metadata
core->root = le64_to_cpu(disk->root);
}
-static void ws_inc(void *context, const void *value, unsigned count)
+static void ws_inc(void *context, const void *value, unsigned int count)
{
struct era_metadata *md = context;
struct writeset_disk ws_d;
dm_block_t b;
- unsigned i;
+ unsigned int i;
for (i = 0; i < count; i++) {
memcpy(&ws_d, value + (i * sizeof(ws_d)), sizeof(ws_d));
@@ -377,12 +387,12 @@ static void ws_inc(void *context, const void *value, unsigned count)
}
}
-static void ws_dec(void *context, const void *value, unsigned count)
+static void ws_dec(void *context, const void *value, unsigned int count)
{
struct era_metadata *md = context;
struct writeset_disk ws_d;
dm_block_t b;
- unsigned i;
+ unsigned int i;
for (i = 0; i < count; i++) {
memcpy(&ws_d, value + (i * sizeof(ws_d)), sizeof(ws_d));
@@ -401,6 +411,7 @@ static int ws_eq(void *context, const void *value1, const void *value2)
static void setup_writeset_tree_info(struct era_metadata *md)
{
struct dm_btree_value_type *vt = &md->writeset_tree_info.value_type;
+
md->writeset_tree_info.tm = md->tm;
md->writeset_tree_info.levels = 1;
vt->context = md;
@@ -411,9 +422,9 @@ static void setup_writeset_tree_info(struct era_metadata *md)
}
static void setup_era_array_info(struct era_metadata *md)
-
{
struct dm_btree_value_type vt;
+
vt.context = NULL;
vt.size = sizeof(__le32);
vt.inc = NULL;
@@ -658,21 +669,23 @@ static void swap_writeset(struct era_metadata *md, struct writeset *new_writeset
synchronize_rcu();
}
-/*----------------------------------------------------------------
+/*
+ *------------------------------------------------------------------------
* Writesets get 'digested' into the main era array.
*
* We're using a coroutine here so the worker thread can do the digestion,
* thus avoiding synchronisation of the metadata. Digesting a whole
* writeset in one go would cause too much latency.
- *--------------------------------------------------------------*/
+ *------------------------------------------------------------------------
+ */
struct digest {
uint32_t era;
- unsigned nr_bits, current_bit;
+ unsigned int nr_bits, current_bit;
struct writeset_metadata writeset;
__le32 value;
struct dm_disk_bitset info;
- int (*step)(struct era_metadata *, struct digest *);
+ int (*step)(struct era_metadata *md, struct digest *d);
};
static int metadata_digest_lookup_writeset(struct era_metadata *md,
@@ -702,7 +715,7 @@ static int metadata_digest_transcribe_writeset(struct era_metadata *md,
{
int r;
bool marked;
- unsigned b, e = min(d->current_bit + INSERTS_PER_STEP, d->nr_bits);
+ unsigned int b, e = min(d->current_bit + INSERTS_PER_STEP, d->nr_bits);
for (b = d->current_bit; b < e; b++) {
r = writeset_marked_on_disk(&d->info, &d->writeset, b, &marked);
@@ -784,10 +797,12 @@ static int metadata_digest_start(struct era_metadata *md, struct digest *d)
return 0;
}
-/*----------------------------------------------------------------
- * High level metadata interface. Target methods should use these, and not
- * the lower level ones.
- *--------------------------------------------------------------*/
+/*
+ *-----------------------------------------------------------------
+ * High level metadata interface. Target methods should use these,
+ * and not the lower level ones.
+ *-----------------------------------------------------------------
+ */
static struct era_metadata *metadata_open(struct block_device *bdev,
sector_t block_size,
bool may_format)
@@ -1181,17 +1196,19 @@ struct era {
struct rpc {
struct list_head list;
- int (*fn0)(struct era_metadata *);
- int (*fn1)(struct era_metadata *, void *);
+ int (*fn0)(struct era_metadata *md);
+ int (*fn1)(struct era_metadata *md, void *ref);
void *arg;
int result;
struct completion complete;
};
-/*----------------------------------------------------------------
+/*
+ *---------------------------------------------------------------
* Remapping.
- *---------------------------------------------------------------*/
+ *---------------------------------------------------------------
+ */
static bool block_size_is_power_of_two(struct era *era)
{
return era->sectors_per_block_shift >= 0;
@@ -1214,9 +1231,11 @@ static void remap_to_origin(struct era *era, struct bio *bio)
bio_set_dev(bio, era->origin_dev->bdev);
}
-/*----------------------------------------------------------------
+/*
+ *--------------------------------------------------------------
* Worker thread
- *--------------------------------------------------------------*/
+ *--------------------------------------------------------------
+ */
static void wake_worker(struct era *era)
{
if (!atomic_read(&era->suspended))
@@ -1372,9 +1391,10 @@ static int perform_rpc(struct era *era, struct rpc *rpc)
return rpc->result;
}
-static int in_worker0(struct era *era, int (*fn)(struct era_metadata *))
+static int in_worker0(struct era *era, int (*fn)(struct era_metadata *md))
{
struct rpc rpc;
+
rpc.fn0 = fn;
rpc.fn1 = NULL;
@@ -1382,9 +1402,10 @@ static int in_worker0(struct era *era, int (*fn)(struct era_metadata *))
}
static int in_worker1(struct era *era,
- int (*fn)(struct era_metadata *, void *), void *arg)
+ int (*fn)(struct era_metadata *md, void *ref), void *arg)
{
struct rpc rpc;
+
rpc.fn0 = NULL;
rpc.fn1 = fn;
rpc.arg = arg;
@@ -1403,9 +1424,11 @@ static void stop_worker(struct era *era)
drain_workqueue(era->wq);
}
-/*----------------------------------------------------------------
+/*
+ *--------------------------------------------------------------
* Target methods
- *--------------------------------------------------------------*/
+ *--------------------------------------------------------------
+ */
static void era_destroy(struct era *era)
{
if (era->md)
@@ -1439,7 +1462,7 @@ static bool valid_block_size(dm_block_t block_size)
/*
* <metadata dev> <data dev> <data block size (sectors)>
*/
-static int era_ctr(struct dm_target *ti, unsigned argc, char **argv)
+static int era_ctr(struct dm_target *ti, unsigned int argc, char **argv)
{
int r;
char dummy;
@@ -1618,7 +1641,7 @@ static int era_preresume(struct dm_target *ti)
* <current era> <held metadata root | '-'>
*/
static void era_status(struct dm_target *ti, status_type_t type,
- unsigned status_flags, char *result, unsigned maxlen)
+ unsigned int status_flags, char *result, unsigned int maxlen)
{
int r;
struct era *era = ti->private;
@@ -1633,10 +1656,10 @@ static void era_status(struct dm_target *ti, status_type_t type,
goto err;
DMEMIT("%u %llu/%llu %u",
- (unsigned) (DM_ERA_METADATA_BLOCK_SIZE >> SECTOR_SHIFT),
+ (unsigned int) (DM_ERA_METADATA_BLOCK_SIZE >> SECTOR_SHIFT),
(unsigned long long) stats.used,
(unsigned long long) stats.total,
- (unsigned) stats.era);
+ (unsigned int) stats.era);
if (stats.snap != SUPERBLOCK_LOCATION)
DMEMIT(" %llu", stats.snap);
@@ -1662,8 +1685,8 @@ err:
DMEMIT("Error");
}
-static int era_message(struct dm_target *ti, unsigned argc, char **argv,
- char *result, unsigned maxlen)
+static int era_message(struct dm_target *ti, unsigned int argc, char **argv,
+ char *result, unsigned int maxlen)
{
struct era *era = ti->private;
@@ -1694,6 +1717,7 @@ static int era_iterate_devices(struct dm_target *ti,
iterate_devices_callout_fn fn, void *data)
{
struct era *era = ti->private;
+
return fn(ti, era->origin_dev, 0, get_dev_size(era->origin_dev), data);
}
diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c
index 3997f34cfebc..c3799757bf4a 100644
--- a/drivers/md/dm-exception-store.c
+++ b/drivers/md/dm-exception-store.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2001-2002 Sistina Software (UK) Limited.
* Copyright (C) 2006-2008 Red Hat GmbH
@@ -142,7 +143,7 @@ EXPORT_SYMBOL(dm_exception_store_type_unregister);
static int set_chunk_size(struct dm_exception_store *store,
const char *chunk_size_arg, char **error)
{
- unsigned chunk_size;
+ unsigned int chunk_size;
if (kstrtouint(chunk_size_arg, 10, &chunk_size)) {
*error = "Invalid chunk size";
@@ -158,7 +159,7 @@ static int set_chunk_size(struct dm_exception_store *store,
}
int dm_exception_store_set_chunk_size(struct dm_exception_store *store,
- unsigned chunk_size,
+ unsigned int chunk_size,
char **error)
{
/* Check chunk_size is a power of 2 */
@@ -190,7 +191,7 @@ int dm_exception_store_set_chunk_size(struct dm_exception_store *store,
int dm_exception_store_create(struct dm_target *ti, int argc, char **argv,
struct dm_snapshot *snap,
- unsigned *args_used,
+ unsigned int *args_used,
struct dm_exception_store **store)
{
int r = 0;
diff --git a/drivers/md/dm-exception-store.h b/drivers/md/dm-exception-store.h
index b5f20eba3641..b67976637538 100644
--- a/drivers/md/dm-exception-store.h
+++ b/drivers/md/dm-exception-store.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2001-2002 Sistina Software (UK) Limited.
* Copyright (C) 2008 Red Hat, Inc. All rights reserved.
@@ -43,36 +44,36 @@ struct dm_exception_store_type {
const char *name;
struct module *module;
- int (*ctr) (struct dm_exception_store *store, char *options);
+ int (*ctr)(struct dm_exception_store *store, char *options);
/*
* Destroys this object when you've finished with it.
*/
- void (*dtr) (struct dm_exception_store *store);
+ void (*dtr)(struct dm_exception_store *store);
/*
* The target shouldn't read the COW device until this is
* called. As exceptions are read from the COW, they are
* reported back via the callback.
*/
- int (*read_metadata) (struct dm_exception_store *store,
- int (*callback)(void *callback_context,
- chunk_t old, chunk_t new),
- void *callback_context);
+ int (*read_metadata)(struct dm_exception_store *store,
+ int (*callback)(void *callback_context,
+ chunk_t old, chunk_t new),
+ void *callback_context);
/*
* Find somewhere to store the next exception.
*/
- int (*prepare_exception) (struct dm_exception_store *store,
- struct dm_exception *e);
+ int (*prepare_exception)(struct dm_exception_store *store,
+ struct dm_exception *e);
/*
* Update the metadata with this exception.
*/
- void (*commit_exception) (struct dm_exception_store *store,
- struct dm_exception *e, int valid,
- void (*callback) (void *, int success),
- void *callback_context);
+ void (*commit_exception)(struct dm_exception_store *store,
+ struct dm_exception *e, int valid,
+ void (*callback)(void *, int success),
+ void *callback_context);
/*
* Returns 0 if the exception store is empty.
@@ -82,30 +83,30 @@ struct dm_exception_store_type {
* still-to-be-merged chunk and returns the number of
* consecutive previous ones.
*/
- int (*prepare_merge) (struct dm_exception_store *store,
- chunk_t *last_old_chunk, chunk_t *last_new_chunk);
+ int (*prepare_merge)(struct dm_exception_store *store,
+ chunk_t *last_old_chunk, chunk_t *last_new_chunk);
/*
* Clear the last n exceptions.
* nr_merged must be <= the value returned by prepare_merge.
*/
- int (*commit_merge) (struct dm_exception_store *store, int nr_merged);
+ int (*commit_merge)(struct dm_exception_store *store, int nr_merged);
/*
* The snapshot is invalid, note this in the metadata.
*/
- void (*drop_snapshot) (struct dm_exception_store *store);
+ void (*drop_snapshot)(struct dm_exception_store *store);
- unsigned (*status) (struct dm_exception_store *store,
- status_type_t status, char *result,
- unsigned maxlen);
+ unsigned int (*status)(struct dm_exception_store *store,
+ status_type_t status, char *result,
+ unsigned int maxlen);
/*
* Return how full the snapshot is.
*/
- void (*usage) (struct dm_exception_store *store,
- sector_t *total_sectors, sector_t *sectors_allocated,
- sector_t *metadata_sectors);
+ void (*usage)(struct dm_exception_store *store,
+ sector_t *total_sectors, sector_t *sectors_allocated,
+ sector_t *metadata_sectors);
/* For internal device-mapper use only. */
struct list_head list;
@@ -118,9 +119,9 @@ struct dm_exception_store {
struct dm_snapshot *snap;
/* Size of data blocks saved - must be a power of 2 */
- unsigned chunk_size;
- unsigned chunk_mask;
- unsigned chunk_shift;
+ unsigned int chunk_size;
+ unsigned int chunk_mask;
+ unsigned int chunk_shift;
void *context;
@@ -144,7 +145,7 @@ static inline chunk_t dm_chunk_number(chunk_t chunk)
return chunk & (chunk_t)((1ULL << DM_CHUNK_NUMBER_BITS) - 1ULL);
}
-static inline unsigned dm_consecutive_chunk_count(struct dm_exception *e)
+static inline unsigned int dm_consecutive_chunk_count(struct dm_exception *e)
{
return e->new_chunk >> DM_CHUNK_NUMBER_BITS;
}
@@ -181,12 +182,12 @@ int dm_exception_store_type_register(struct dm_exception_store_type *type);
int dm_exception_store_type_unregister(struct dm_exception_store_type *type);
int dm_exception_store_set_chunk_size(struct dm_exception_store *store,
- unsigned chunk_size,
+ unsigned int chunk_size,
char **error);
int dm_exception_store_create(struct dm_target *ti, int argc, char **argv,
struct dm_snapshot *snap,
- unsigned *args_used,
+ unsigned int *args_used,
struct dm_exception_store **store);
void dm_exception_store_destroy(struct dm_exception_store *store);
diff --git a/drivers/md/dm-flakey.c b/drivers/md/dm-flakey.c
index 89fa7a68c6c4..5b7556d2a9d9 100644
--- a/drivers/md/dm-flakey.c
+++ b/drivers/md/dm-flakey.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2003 Sistina Software (UK) Limited.
* Copyright (C) 2004, 2010-2011 Red Hat, Inc. All rights reserved.
@@ -26,12 +27,12 @@ struct flakey_c {
struct dm_dev *dev;
unsigned long start_time;
sector_t start;
- unsigned up_interval;
- unsigned down_interval;
+ unsigned int up_interval;
+ unsigned int down_interval;
unsigned long flags;
- unsigned corrupt_bio_byte;
- unsigned corrupt_bio_rw;
- unsigned corrupt_bio_value;
+ unsigned int corrupt_bio_byte;
+ unsigned int corrupt_bio_rw;
+ unsigned int corrupt_bio_value;
blk_opf_t corrupt_bio_flags;
};
@@ -48,7 +49,7 @@ static int parse_features(struct dm_arg_set *as, struct flakey_c *fc,
struct dm_target *ti)
{
int r;
- unsigned argc;
+ unsigned int argc;
const char *arg_name;
static const struct dm_arg _args[] = {
@@ -148,7 +149,7 @@ static int parse_features(struct dm_arg_set *as, struct flakey_c *fc,
BUILD_BUG_ON(sizeof(fc->corrupt_bio_flags) !=
sizeof(unsigned int));
r = dm_read_arg(_args + 3, as,
- (__force unsigned *)&fc->corrupt_bio_flags,
+ (__force unsigned int *)&fc->corrupt_bio_flags,
&ti->error);
if (r)
return r;
@@ -303,9 +304,13 @@ static void corrupt_bio_data(struct bio *bio, struct flakey_c *fc)
*/
bio_for_each_segment(bvec, bio, iter) {
if (bio_iter_len(bio, iter) > corrupt_bio_byte) {
- char *segment = (page_address(bio_iter_page(bio, iter))
- + bio_iter_offset(bio, iter));
+ char *segment;
+ struct page *page = bio_iter_page(bio, iter);
+ if (unlikely(page == ZERO_PAGE(0)))
+ break;
+ segment = bvec_kmap_local(&bvec);
segment[corrupt_bio_byte] = fc->corrupt_bio_value;
+ kunmap_local(segment);
DMDEBUG("Corrupting data bio=%p by writing %u to byte %u "
"(rw=%c bi_opf=%u bi_sector=%llu size=%u)\n",
bio, fc->corrupt_bio_value, fc->corrupt_bio_byte,
@@ -320,8 +325,9 @@ static void corrupt_bio_data(struct bio *bio, struct flakey_c *fc)
static int flakey_map(struct dm_target *ti, struct bio *bio)
{
struct flakey_c *fc = ti->private;
- unsigned elapsed;
+ unsigned int elapsed;
struct per_bio_data *pb = dm_per_bio_data(bio, sizeof(struct per_bio_data));
+
pb->bio_submitted = false;
if (op_is_zone_mgmt(bio_op(bio)))
@@ -352,8 +358,7 @@ static int flakey_map(struct dm_target *ti, struct bio *bio)
if (test_bit(DROP_WRITES, &fc->flags)) {
bio_endio(bio);
return DM_MAPIO_SUBMITTED;
- }
- else if (test_bit(ERROR_WRITES, &fc->flags)) {
+ } else if (test_bit(ERROR_WRITES, &fc->flags)) {
bio_io_error(bio);
return DM_MAPIO_SUBMITTED;
}
@@ -361,9 +366,11 @@ static int flakey_map(struct dm_target *ti, struct bio *bio)
/*
* Corrupt matching writes.
*/
- if (fc->corrupt_bio_byte && (fc->corrupt_bio_rw == WRITE)) {
- if (all_corrupt_bio_flags_match(bio, fc))
- corrupt_bio_data(bio, fc);
+ if (fc->corrupt_bio_byte) {
+ if (fc->corrupt_bio_rw == WRITE) {
+ if (all_corrupt_bio_flags_match(bio, fc))
+ corrupt_bio_data(bio, fc);
+ }
goto map_bio;
}
@@ -389,13 +396,14 @@ static int flakey_end_io(struct dm_target *ti, struct bio *bio,
return DM_ENDIO_DONE;
if (!*error && pb->bio_submitted && (bio_data_dir(bio) == READ)) {
- if (fc->corrupt_bio_byte && (fc->corrupt_bio_rw == READ) &&
- all_corrupt_bio_flags_match(bio, fc)) {
- /*
- * Corrupt successful matching READs while in down state.
- */
- corrupt_bio_data(bio, fc);
-
+ if (fc->corrupt_bio_byte) {
+ if ((fc->corrupt_bio_rw == READ) &&
+ all_corrupt_bio_flags_match(bio, fc)) {
+ /*
+ * Corrupt successful matching READs while in down state.
+ */
+ corrupt_bio_data(bio, fc);
+ }
} else if (!test_bit(DROP_WRITES, &fc->flags) &&
!test_bit(ERROR_WRITES, &fc->flags)) {
/*
@@ -410,11 +418,11 @@ static int flakey_end_io(struct dm_target *ti, struct bio *bio,
}
static void flakey_status(struct dm_target *ti, status_type_t type,
- unsigned status_flags, char *result, unsigned maxlen)
+ unsigned int status_flags, char *result, unsigned int maxlen)
{
- unsigned sz = 0;
+ unsigned int sz = 0;
struct flakey_c *fc = ti->private;
- unsigned drop_writes, error_writes;
+ unsigned int drop_writes, error_writes;
switch (type) {
case STATUSTYPE_INFO:
diff --git a/drivers/md/dm-ima.c b/drivers/md/dm-ima.c
index a1bd7cd52b1b..b90f34259fbb 100644
--- a/drivers/md/dm-ima.c
+++ b/drivers/md/dm-ima.c
@@ -1,11 +1,10 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2021 Microsoft Corporation
*
* Author: Tushar Sugandhi <tusharsu@linux.microsoft.com>
*
- * File: dm-ima.c
- * Enables IMA measurements for DM targets
+ * Enables IMA measurements for DM targets
*/
#include "dm-core.h"
diff --git a/drivers/md/dm-ima.h b/drivers/md/dm-ima.h
index b8c3b614670b..568870a1a145 100644
--- a/drivers/md/dm-ima.h
+++ b/drivers/md/dm-ima.h
@@ -1,11 +1,10 @@
-/* SPDX-License-Identifier: GPL-2.0
- *
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
* Copyright (C) 2021 Microsoft Corporation
*
* Author: Tushar Sugandhi <tusharsu@linux.microsoft.com>
*
- * File: dm-ima.h
- * Header file for device mapper IMA measurements.
+ * Header file for device mapper IMA measurements.
*/
#ifndef DM_IMA_H
diff --git a/drivers/md/dm-init.c b/drivers/md/dm-init.c
index dc4381d68313..d369457dbed0 100644
--- a/drivers/md/dm-init.c
+++ b/drivers/md/dm-init.c
@@ -1,7 +1,6 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
/*
- * dm-init.c
* Copyright (C) 2017 The Chromium OS Authors <chromium-os-dev@chromium.org>
*
* This file is released under the GPLv2.
@@ -296,7 +295,7 @@ static int __init dm_init_init(void)
if (waitfor[i]) {
DMINFO("waiting for device %s ...", waitfor[i]);
while (!dm_get_dev_t(waitfor[i]))
- msleep(5);
+ fsleep(5000);
}
}
diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c
index c58156deb2b1..b0d5057fbdd9 100644
--- a/drivers/md/dm-integrity.c
+++ b/drivers/md/dm-integrity.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2016-2017 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016-2017 Milan Broz
@@ -112,9 +113,9 @@ struct journal_entry {
#endif
#define journal_entry_get_sector(je) le64_to_cpu((je)->u.sector)
#define journal_entry_is_unused(je) ((je)->u.s.sector_hi == cpu_to_le32(-1))
-#define journal_entry_set_unused(je) do { ((je)->u.s.sector_hi = cpu_to_le32(-1)); } while (0)
+#define journal_entry_set_unused(je) ((je)->u.s.sector_hi = cpu_to_le32(-1))
#define journal_entry_is_inprogress(je) ((je)->u.s.sector_hi == cpu_to_le32(-2))
-#define journal_entry_set_inprogress(je) do { ((je)->u.s.sector_hi = cpu_to_le32(-2)); } while (0)
+#define journal_entry_set_inprogress(je) ((je)->u.s.sector_hi = cpu_to_le32(-2))
#define JOURNAL_BLOCK_SECTORS 8
#define JOURNAL_SECTOR_DATA ((1 << SECTOR_SHIFT) - sizeof(commit_id_t))
@@ -157,13 +158,13 @@ struct alg_spec {
char *alg_string;
char *key_string;
__u8 *key;
- unsigned key_size;
+ unsigned int key_size;
};
struct dm_integrity_c {
struct dm_dev *dev;
struct dm_dev *meta_dev;
- unsigned tag_size;
+ unsigned int tag_size;
__s8 log2_tag_size;
sector_t start;
mempool_t journal_io_mempool;
@@ -171,8 +172,8 @@ struct dm_integrity_c {
struct dm_bufio_client *bufio;
struct workqueue_struct *metadata_wq;
struct superblock *sb;
- unsigned journal_pages;
- unsigned n_bitmap_blocks;
+ unsigned int journal_pages;
+ unsigned int n_bitmap_blocks;
struct page_list *journal;
struct page_list *journal_io;
@@ -180,7 +181,7 @@ struct dm_integrity_c {
struct page_list *recalc_bitmap;
struct page_list *may_write_bitmap;
struct bitmap_block_status *bbs;
- unsigned bitmap_flush_interval;
+ unsigned int bitmap_flush_interval;
int synchronous_mode;
struct bio_list synchronous_bios;
struct delayed_work bitmap_flush_work;
@@ -201,12 +202,12 @@ struct dm_integrity_c {
unsigned char journal_entries_per_sector;
unsigned char journal_section_entries;
unsigned short journal_section_sectors;
- unsigned journal_sections;
- unsigned journal_entries;
+ unsigned int journal_sections;
+ unsigned int journal_entries;
sector_t data_device_sectors;
sector_t meta_device_sectors;
- unsigned initial_sectors;
- unsigned metadata_run;
+ unsigned int initial_sectors;
+ unsigned int metadata_run;
__s8 log2_metadata_run;
__u8 log2_buffer_sectors;
__u8 sectors_per_block;
@@ -230,17 +231,17 @@ struct dm_integrity_c {
unsigned char commit_seq;
commit_id_t commit_ids[N_COMMIT_IDS];
- unsigned committed_section;
- unsigned n_committed_sections;
+ unsigned int committed_section;
+ unsigned int n_committed_sections;
- unsigned uncommitted_section;
- unsigned n_uncommitted_sections;
+ unsigned int uncommitted_section;
+ unsigned int n_uncommitted_sections;
- unsigned free_section;
+ unsigned int free_section;
unsigned char free_section_entry;
- unsigned free_sectors;
+ unsigned int free_sectors;
- unsigned free_sectors_threshold;
+ unsigned int free_sectors_threshold;
struct workqueue_struct *commit_wq;
struct work_struct commit_work;
@@ -257,7 +258,7 @@ struct dm_integrity_c {
unsigned long autocommit_jiffies;
struct timer_list autocommit_timer;
- unsigned autocommit_msec;
+ unsigned int autocommit_msec;
wait_queue_head_t copy_to_journal_wait;
@@ -305,7 +306,7 @@ struct dm_integrity_io {
struct dm_integrity_range range;
sector_t metadata_block;
- unsigned metadata_offset;
+ unsigned int metadata_offset;
atomic_t in_flight;
blk_status_t bi_status;
@@ -329,7 +330,7 @@ struct journal_io {
struct bitmap_block_status {
struct work_struct work;
struct dm_integrity_c *ic;
- unsigned idx;
+ unsigned int idx;
unsigned long *bitmap;
struct bio_list bio_queue;
spinlock_t bio_queue_lock;
@@ -345,6 +346,7 @@ static struct kmem_cache *journal_io_cache;
static void __DEBUG_bytes(__u8 *bytes, size_t len, const char *msg, ...)
{
va_list args;
+
va_start(args, msg);
vprintk(msg, args);
va_end(args);
@@ -410,8 +412,8 @@ static bool dm_integrity_disable_recalculate(struct dm_integrity_c *ic)
return false;
}
-static commit_id_t dm_integrity_commit_id(struct dm_integrity_c *ic, unsigned i,
- unsigned j, unsigned char seq)
+static commit_id_t dm_integrity_commit_id(struct dm_integrity_c *ic, unsigned int i,
+ unsigned int j, unsigned char seq)
{
/*
* Xor the number with section and sector, so that if a piece of
@@ -426,7 +428,7 @@ static void get_area_and_offset(struct dm_integrity_c *ic, sector_t data_sector,
if (!ic->meta_dev) {
__u8 log2_interleave_sectors = ic->sb->log2_interleave_sectors;
*area = data_sector >> log2_interleave_sectors;
- *offset = (unsigned)data_sector & ((1U << log2_interleave_sectors) - 1);
+ *offset = (unsigned int)data_sector & ((1U << log2_interleave_sectors) - 1);
} else {
*area = 0;
*offset = data_sector;
@@ -435,15 +437,15 @@ static void get_area_and_offset(struct dm_integrity_c *ic, sector_t data_sector,
#define sector_to_block(ic, n) \
do { \
- BUG_ON((n) & (unsigned)((ic)->sectors_per_block - 1)); \
+ BUG_ON((n) & (unsigned int)((ic)->sectors_per_block - 1)); \
(n) >>= (ic)->sb->log2_sectors_per_block; \
} while (0)
static __u64 get_metadata_sector_and_offset(struct dm_integrity_c *ic, sector_t area,
- sector_t offset, unsigned *metadata_offset)
+ sector_t offset, unsigned int *metadata_offset)
{
__u64 ms;
- unsigned mo;
+ unsigned int mo;
ms = area << ic->sb->log2_interleave_sectors;
if (likely(ic->log2_metadata_run >= 0))
@@ -484,7 +486,7 @@ static sector_t get_data_sector(struct dm_integrity_c *ic, sector_t area, sector
return result;
}
-static void wraparound_section(struct dm_integrity_c *ic, unsigned *sec_ptr)
+static void wraparound_section(struct dm_integrity_c *ic, unsigned int *sec_ptr)
{
if (unlikely(*sec_ptr >= ic->journal_sections))
*sec_ptr -= ic->journal_sections;
@@ -508,7 +510,7 @@ static int sb_mac(struct dm_integrity_c *ic, bool wr)
{
SHASH_DESC_ON_STACK(desc, ic->journal_mac);
int r;
- unsigned size = crypto_shash_digestsize(ic->journal_mac);
+ unsigned int size = crypto_shash_digestsize(ic->journal_mac);
if (sizeof(struct superblock) + size > 1 << SECTOR_SHIFT) {
dm_integrity_io_error(ic, "digest is too long", -EINVAL);
@@ -537,6 +539,7 @@ static int sb_mac(struct dm_integrity_c *ic, bool wr)
}
} else {
__u8 result[HASH_MAX_DIGESTSIZE];
+
r = crypto_shash_final(desc, result);
if (unlikely(r < 0)) {
dm_integrity_io_error(ic, "crypto_shash_final", r);
@@ -627,11 +630,10 @@ static bool block_bitmap_op(struct dm_integrity_c *ic, struct page_list *bitmap,
end_bit %= PAGE_SIZE * 8;
repeat:
- if (page < end_page) {
+ if (page < end_page)
this_end_bit = PAGE_SIZE * 8 - 1;
- } else {
+ else
this_end_bit = end_bit;
- }
data = lowmem_page_address(bitmap[page].page);
@@ -678,16 +680,18 @@ repeat:
} else if (mode == BITMAP_OP_CLEAR) {
if (!bit && this_end_bit == PAGE_SIZE * 8 - 1)
clear_page(data);
- else while (bit <= this_end_bit) {
- if (!(bit % BITS_PER_LONG) && this_end_bit >= bit + BITS_PER_LONG - 1) {
- do {
- data[bit / BITS_PER_LONG] = 0;
- bit += BITS_PER_LONG;
- } while (this_end_bit >= bit + BITS_PER_LONG - 1);
- continue;
+ else {
+ while (bit <= this_end_bit) {
+ if (!(bit % BITS_PER_LONG) && this_end_bit >= bit + BITS_PER_LONG - 1) {
+ do {
+ data[bit / BITS_PER_LONG] = 0;
+ bit += BITS_PER_LONG;
+ } while (this_end_bit >= bit + BITS_PER_LONG - 1);
+ continue;
+ }
+ __clear_bit(bit, data);
+ bit++;
}
- __clear_bit(bit, data);
- bit++;
}
} else {
BUG();
@@ -704,30 +708,31 @@ repeat:
static void block_bitmap_copy(struct dm_integrity_c *ic, struct page_list *dst, struct page_list *src)
{
- unsigned n_bitmap_pages = DIV_ROUND_UP(ic->n_bitmap_blocks, PAGE_SIZE / BITMAP_BLOCK_SIZE);
- unsigned i;
+ unsigned int n_bitmap_pages = DIV_ROUND_UP(ic->n_bitmap_blocks, PAGE_SIZE / BITMAP_BLOCK_SIZE);
+ unsigned int i;
for (i = 0; i < n_bitmap_pages; i++) {
unsigned long *dst_data = lowmem_page_address(dst[i].page);
unsigned long *src_data = lowmem_page_address(src[i].page);
+
copy_page(dst_data, src_data);
}
}
static struct bitmap_block_status *sector_to_bitmap_block(struct dm_integrity_c *ic, sector_t sector)
{
- unsigned bit = sector >> (ic->sb->log2_sectors_per_block + ic->log2_blocks_per_bitmap_bit);
- unsigned bitmap_block = bit / (BITMAP_BLOCK_SIZE * 8);
+ unsigned int bit = sector >> (ic->sb->log2_sectors_per_block + ic->log2_blocks_per_bitmap_bit);
+ unsigned int bitmap_block = bit / (BITMAP_BLOCK_SIZE * 8);
BUG_ON(bitmap_block >= ic->n_bitmap_blocks);
return &ic->bbs[bitmap_block];
}
-static void access_journal_check(struct dm_integrity_c *ic, unsigned section, unsigned offset,
+static void access_journal_check(struct dm_integrity_c *ic, unsigned int section, unsigned int offset,
bool e, const char *function)
{
#if defined(CONFIG_DM_DEBUG) || defined(INTERNAL_VERIFY)
- unsigned limit = e ? ic->journal_section_entries : ic->journal_section_sectors;
+ unsigned int limit = e ? ic->journal_section_entries : ic->journal_section_sectors;
if (unlikely(section >= ic->journal_sections) ||
unlikely(offset >= limit)) {
@@ -738,10 +743,10 @@ static void access_journal_check(struct dm_integrity_c *ic, unsigned section, un
#endif
}
-static void page_list_location(struct dm_integrity_c *ic, unsigned section, unsigned offset,
- unsigned *pl_index, unsigned *pl_offset)
+static void page_list_location(struct dm_integrity_c *ic, unsigned int section, unsigned int offset,
+ unsigned int *pl_index, unsigned int *pl_offset)
{
- unsigned sector;
+ unsigned int sector;
access_journal_check(ic, section, offset, false, "page_list_location");
@@ -752,9 +757,9 @@ static void page_list_location(struct dm_integrity_c *ic, unsigned section, unsi
}
static struct journal_sector *access_page_list(struct dm_integrity_c *ic, struct page_list *pl,
- unsigned section, unsigned offset, unsigned *n_sectors)
+ unsigned int section, unsigned int offset, unsigned int *n_sectors)
{
- unsigned pl_index, pl_offset;
+ unsigned int pl_index, pl_offset;
char *va;
page_list_location(ic, section, offset, &pl_index, &pl_offset);
@@ -767,14 +772,14 @@ static struct journal_sector *access_page_list(struct dm_integrity_c *ic, struct
return (struct journal_sector *)(va + pl_offset);
}
-static struct journal_sector *access_journal(struct dm_integrity_c *ic, unsigned section, unsigned offset)
+static struct journal_sector *access_journal(struct dm_integrity_c *ic, unsigned int section, unsigned int offset)
{
return access_page_list(ic, ic->journal, section, offset, NULL);
}
-static struct journal_entry *access_journal_entry(struct dm_integrity_c *ic, unsigned section, unsigned n)
+static struct journal_entry *access_journal_entry(struct dm_integrity_c *ic, unsigned int section, unsigned int n)
{
- unsigned rel_sector, offset;
+ unsigned int rel_sector, offset;
struct journal_sector *js;
access_journal_check(ic, section, n, true, "access_journal_entry");
@@ -786,7 +791,7 @@ static struct journal_entry *access_journal_entry(struct dm_integrity_c *ic, uns
return (struct journal_entry *)((char *)js + offset * ic->journal_entry_size);
}
-static struct journal_sector *access_journal_data(struct dm_integrity_c *ic, unsigned section, unsigned n)
+static struct journal_sector *access_journal_data(struct dm_integrity_c *ic, unsigned int section, unsigned int n)
{
n <<= ic->sb->log2_sectors_per_block;
@@ -797,11 +802,11 @@ static struct journal_sector *access_journal_data(struct dm_integrity_c *ic, uns
return access_journal(ic, section, n);
}
-static void section_mac(struct dm_integrity_c *ic, unsigned section, __u8 result[JOURNAL_MAC_SIZE])
+static void section_mac(struct dm_integrity_c *ic, unsigned int section, __u8 result[JOURNAL_MAC_SIZE])
{
SHASH_DESC_ON_STACK(desc, ic->journal_mac);
int r;
- unsigned j, size;
+ unsigned int j, size;
desc->tfm = ic->journal_mac;
@@ -821,7 +826,7 @@ static void section_mac(struct dm_integrity_c *ic, unsigned section, __u8 result
}
section_le = cpu_to_le64(section);
- r = crypto_shash_update(desc, (__u8 *)&section_le, sizeof section_le);
+ r = crypto_shash_update(desc, (__u8 *)&section_le, sizeof(section_le));
if (unlikely(r < 0)) {
dm_integrity_io_error(ic, "crypto_shash_update", r);
goto err;
@@ -830,7 +835,8 @@ static void section_mac(struct dm_integrity_c *ic, unsigned section, __u8 result
for (j = 0; j < ic->journal_section_entries; j++) {
struct journal_entry *je = access_journal_entry(ic, section, j);
- r = crypto_shash_update(desc, (__u8 *)&je->u.sector, sizeof je->u.sector);
+
+ r = crypto_shash_update(desc, (__u8 *)&je->u.sector, sizeof(je->u.sector));
if (unlikely(r < 0)) {
dm_integrity_io_error(ic, "crypto_shash_update", r);
goto err;
@@ -866,10 +872,10 @@ err:
memset(result, 0, JOURNAL_MAC_SIZE);
}
-static void rw_section_mac(struct dm_integrity_c *ic, unsigned section, bool wr)
+static void rw_section_mac(struct dm_integrity_c *ic, unsigned int section, bool wr)
{
__u8 result[JOURNAL_MAC_SIZE];
- unsigned j;
+ unsigned int j;
if (!ic->journal_mac)
return;
@@ -893,17 +899,18 @@ static void rw_section_mac(struct dm_integrity_c *ic, unsigned section, bool wr)
static void complete_journal_op(void *context)
{
struct journal_completion *comp = context;
+
BUG_ON(!atomic_read(&comp->in_flight));
if (likely(atomic_dec_and_test(&comp->in_flight)))
complete(&comp->comp);
}
-static void xor_journal(struct dm_integrity_c *ic, bool encrypt, unsigned section,
- unsigned n_sections, struct journal_completion *comp)
+static void xor_journal(struct dm_integrity_c *ic, bool encrypt, unsigned int section,
+ unsigned int n_sections, struct journal_completion *comp)
{
struct async_submit_ctl submit;
size_t n_bytes = (size_t)(n_sections * ic->journal_section_sectors) << SECTOR_SHIFT;
- unsigned pl_index, pl_offset, section_index;
+ unsigned int pl_index, pl_offset, section_index;
struct page_list *source_pl, *target_pl;
if (likely(encrypt)) {
@@ -928,7 +935,8 @@ static void xor_journal(struct dm_integrity_c *ic, bool encrypt, unsigned sectio
struct page *dst_page;
while (unlikely(pl_index == section_index)) {
- unsigned dummy;
+ unsigned int dummy;
+
if (likely(encrypt))
rw_section_mac(ic, section, true);
section++;
@@ -958,6 +966,7 @@ static void xor_journal(struct dm_integrity_c *ic, bool encrypt, unsigned sectio
static void complete_journal_encrypt(void *data, int err)
{
struct journal_completion *comp = data;
+
if (unlikely(err)) {
if (likely(err == -EINPROGRESS)) {
complete(&comp->ic->crypto_backoff);
@@ -971,6 +980,7 @@ static void complete_journal_encrypt(void *data, int err)
static bool do_crypt(bool encrypt, struct skcipher_request *req, struct journal_completion *comp)
{
int r;
+
skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
complete_journal_encrypt, comp);
if (likely(encrypt))
@@ -990,8 +1000,8 @@ static bool do_crypt(bool encrypt, struct skcipher_request *req, struct journal_
return false;
}
-static void crypt_journal(struct dm_integrity_c *ic, bool encrypt, unsigned section,
- unsigned n_sections, struct journal_completion *comp)
+static void crypt_journal(struct dm_integrity_c *ic, bool encrypt, unsigned int section,
+ unsigned int n_sections, struct journal_completion *comp)
{
struct scatterlist **source_sg;
struct scatterlist **target_sg;
@@ -1008,7 +1018,7 @@ static void crypt_journal(struct dm_integrity_c *ic, bool encrypt, unsigned sect
do {
struct skcipher_request *req;
- unsigned ivsize;
+ unsigned int ivsize;
char *iv;
if (likely(encrypt))
@@ -1034,8 +1044,8 @@ static void crypt_journal(struct dm_integrity_c *ic, bool encrypt, unsigned sect
complete_journal_op(comp);
}
-static void encrypt_journal(struct dm_integrity_c *ic, bool encrypt, unsigned section,
- unsigned n_sections, struct journal_completion *comp)
+static void encrypt_journal(struct dm_integrity_c *ic, bool encrypt, unsigned int section,
+ unsigned int n_sections, struct journal_completion *comp)
{
if (ic->journal_xor)
return xor_journal(ic, encrypt, section, n_sections, comp);
@@ -1046,18 +1056,19 @@ static void encrypt_journal(struct dm_integrity_c *ic, bool encrypt, unsigned se
static void complete_journal_io(unsigned long error, void *context)
{
struct journal_completion *comp = context;
+
if (unlikely(error != 0))
dm_integrity_io_error(comp->ic, "writing journal", -EIO);
complete_journal_op(comp);
}
static void rw_journal_sectors(struct dm_integrity_c *ic, blk_opf_t opf,
- unsigned sector, unsigned n_sectors,
+ unsigned int sector, unsigned int n_sectors,
struct journal_completion *comp)
{
struct dm_io_request io_req;
struct dm_io_region io_loc;
- unsigned pl_index, pl_offset;
+ unsigned int pl_index, pl_offset;
int r;
if (unlikely(dm_integrity_failed(ic))) {
@@ -1099,10 +1110,10 @@ static void rw_journal_sectors(struct dm_integrity_c *ic, blk_opf_t opf,
}
static void rw_journal(struct dm_integrity_c *ic, blk_opf_t opf,
- unsigned section, unsigned n_sections,
+ unsigned int section, unsigned int n_sections,
struct journal_completion *comp)
{
- unsigned sector, n_sectors;
+ unsigned int sector, n_sectors;
sector = section * ic->journal_section_sectors;
n_sectors = n_sections * ic->journal_section_sectors;
@@ -1110,12 +1121,12 @@ static void rw_journal(struct dm_integrity_c *ic, blk_opf_t opf,
rw_journal_sectors(ic, opf, sector, n_sectors, comp);
}
-static void write_journal(struct dm_integrity_c *ic, unsigned commit_start, unsigned commit_sections)
+static void write_journal(struct dm_integrity_c *ic, unsigned int commit_start, unsigned int commit_sections)
{
struct journal_completion io_comp;
struct journal_completion crypt_comp_1;
struct journal_completion crypt_comp_2;
- unsigned i;
+ unsigned int i;
io_comp.ic = ic;
init_completion(&io_comp.comp);
@@ -1135,7 +1146,8 @@ static void write_journal(struct dm_integrity_c *ic, unsigned commit_start, unsi
rw_journal(ic, REQ_OP_WRITE | REQ_FUA | REQ_SYNC, commit_start,
commit_sections, &io_comp);
} else {
- unsigned to_end;
+ unsigned int to_end;
+
io_comp.in_flight = (atomic_t)ATOMIC_INIT(2);
to_end = ic->journal_sections - commit_start;
if (ic->journal_io) {
@@ -1172,15 +1184,15 @@ static void write_journal(struct dm_integrity_c *ic, unsigned commit_start, unsi
wait_for_completion_io(&io_comp.comp);
}
-static void copy_from_journal(struct dm_integrity_c *ic, unsigned section, unsigned offset,
- unsigned n_sectors, sector_t target, io_notify_fn fn, void *data)
+static void copy_from_journal(struct dm_integrity_c *ic, unsigned int section, unsigned int offset,
+ unsigned int n_sectors, sector_t target, io_notify_fn fn, void *data)
{
struct dm_io_request io_req;
struct dm_io_region io_loc;
int r;
- unsigned sector, pl_index, pl_offset;
+ unsigned int sector, pl_index, pl_offset;
- BUG_ON((target | n_sectors | offset) & (unsigned)(ic->sectors_per_block - 1));
+ BUG_ON((target | n_sectors | offset) & (unsigned int)(ic->sectors_per_block - 1));
if (unlikely(dm_integrity_failed(ic))) {
fn(-1UL, data);
@@ -1221,10 +1233,11 @@ static bool add_new_range(struct dm_integrity_c *ic, struct dm_integrity_range *
struct rb_node **n = &ic->in_progress.rb_node;
struct rb_node *parent;
- BUG_ON((new_range->logical_sector | new_range->n_sectors) & (unsigned)(ic->sectors_per_block - 1));
+ BUG_ON((new_range->logical_sector | new_range->n_sectors) & (unsigned int)(ic->sectors_per_block - 1));
if (likely(check_waiting)) {
struct dm_integrity_range *range;
+
list_for_each_entry(range, &ic->wait_list, wait_entry) {
if (unlikely(ranges_overlap(range, new_range)))
return false;
@@ -1237,13 +1250,12 @@ static bool add_new_range(struct dm_integrity_c *ic, struct dm_integrity_range *
struct dm_integrity_range *range = container_of(*n, struct dm_integrity_range, node);
parent = *n;
- if (new_range->logical_sector + new_range->n_sectors <= range->logical_sector) {
+ if (new_range->logical_sector + new_range->n_sectors <= range->logical_sector)
n = &range->node.rb_left;
- } else if (new_range->logical_sector >= range->logical_sector + range->n_sectors) {
+ else if (new_range->logical_sector >= range->logical_sector + range->n_sectors)
n = &range->node.rb_right;
- } else {
+ else
return false;
- }
}
rb_link_node(&new_range->node, parent, n);
@@ -1259,6 +1271,7 @@ static void remove_range_unlocked(struct dm_integrity_c *ic, struct dm_integrity
struct dm_integrity_range *last_range =
list_first_entry(&ic->wait_list, struct dm_integrity_range, wait_entry);
struct task_struct *last_range_task;
+
last_range_task = last_range->task;
list_del(&last_range->wait_entry);
if (!add_new_range(ic, last_range, false)) {
@@ -1318,6 +1331,7 @@ static void add_journal_node(struct dm_integrity_c *ic, struct journal_node *nod
while (*link) {
struct journal_node *j;
+
parent = *link;
j = container_of(parent, struct journal_node, node);
if (sector < j->sector)
@@ -1339,28 +1353,29 @@ static void remove_journal_node(struct dm_integrity_c *ic, struct journal_node *
#define NOT_FOUND (-1U)
-static unsigned find_journal_node(struct dm_integrity_c *ic, sector_t sector, sector_t *next_sector)
+static unsigned int find_journal_node(struct dm_integrity_c *ic, sector_t sector, sector_t *next_sector)
{
struct rb_node *n = ic->journal_tree_root.rb_node;
- unsigned found = NOT_FOUND;
+ unsigned int found = NOT_FOUND;
+
*next_sector = (sector_t)-1;
while (n) {
struct journal_node *j = container_of(n, struct journal_node, node);
- if (sector == j->sector) {
+
+ if (sector == j->sector)
found = j - ic->journal_tree;
- }
+
if (sector < j->sector) {
*next_sector = j->sector;
n = j->node.rb_left;
- } else {
+ } else
n = j->node.rb_right;
- }
}
return found;
}
-static bool test_journal_node(struct dm_integrity_c *ic, unsigned pos, sector_t sector)
+static bool test_journal_node(struct dm_integrity_c *ic, unsigned int pos, sector_t sector)
{
struct journal_node *node, *next_node;
struct rb_node *next;
@@ -1385,7 +1400,7 @@ static bool find_newer_committed_node(struct dm_integrity_c *ic, struct journal_
{
struct rb_node *next;
struct journal_node *next_node;
- unsigned next_section;
+ unsigned int next_section;
BUG_ON(RB_EMPTY_NODE(&node->node));
@@ -1398,7 +1413,7 @@ static bool find_newer_committed_node(struct dm_integrity_c *ic, struct journal_
if (next_node->sector != node->sector)
return false;
- next_section = (unsigned)(next_node - ic->journal_tree) / ic->journal_section_entries;
+ next_section = (unsigned int)(next_node - ic->journal_tree) / ic->journal_section_entries;
if (next_section >= ic->committed_section &&
next_section < ic->committed_section + ic->n_committed_sections)
return true;
@@ -1413,17 +1428,17 @@ static bool find_newer_committed_node(struct dm_integrity_c *ic, struct journal_
#define TAG_CMP 2
static int dm_integrity_rw_tag(struct dm_integrity_c *ic, unsigned char *tag, sector_t *metadata_block,
- unsigned *metadata_offset, unsigned total_size, int op)
+ unsigned int *metadata_offset, unsigned int total_size, int op)
{
#define MAY_BE_FILLER 1
#define MAY_BE_HASH 2
- unsigned hash_offset = 0;
- unsigned may_be = MAY_BE_HASH | (ic->discard ? MAY_BE_FILLER : 0);
+ unsigned int hash_offset = 0;
+ unsigned int may_be = MAY_BE_HASH | (ic->discard ? MAY_BE_FILLER : 0);
do {
unsigned char *data, *dp;
struct dm_buffer *b;
- unsigned to_copy;
+ unsigned int to_copy;
int r;
r = dm_integrity_failed(ic);
@@ -1453,7 +1468,7 @@ static int dm_integrity_rw_tag(struct dm_integrity_c *ic, unsigned char *tag, se
goto thorough_test;
}
} else {
- unsigned i, ts;
+ unsigned int i, ts;
thorough_test:
ts = total_size;
@@ -1483,9 +1498,8 @@ thorough_test:
*metadata_offset = 0;
}
- if (unlikely(!is_power_of_2(ic->tag_size))) {
+ if (unlikely(!is_power_of_2(ic->tag_size)))
hash_offset = (hash_offset + to_copy) % ic->tag_size;
- }
total_size -= to_copy;
} while (unlikely(total_size));
@@ -1505,6 +1519,7 @@ struct flush_request {
static void flush_notify(unsigned long error, void *fr_)
{
struct flush_request *fr = fr_;
+
if (unlikely(error != 0))
dm_integrity_io_error(fr->ic, "flushing disk cache", -EIO);
complete(&fr->comp);
@@ -1513,7 +1528,6 @@ static void flush_notify(unsigned long error, void *fr_)
static void dm_integrity_flush_buffers(struct dm_integrity_c *ic, bool flush_data)
{
int r;
-
struct flush_request fr;
if (!ic->meta_dev)
@@ -1545,6 +1559,7 @@ static void dm_integrity_flush_buffers(struct dm_integrity_c *ic, bool flush_dat
static void sleep_on_endio_wait(struct dm_integrity_c *ic)
{
DECLARE_WAITQUEUE(wait, current);
+
__add_wait_queue(&ic->endio_wait, &wait);
__set_current_state(TASK_UNINTERRUPTIBLE);
spin_unlock_irq(&ic->endio_wait.lock);
@@ -1582,11 +1597,14 @@ static void submit_flush_bio(struct dm_integrity_c *ic, struct dm_integrity_io *
static void do_endio(struct dm_integrity_c *ic, struct bio *bio)
{
- int r = dm_integrity_failed(ic);
+ int r;
+
+ r = dm_integrity_failed(ic);
if (unlikely(r) && !bio->bi_status)
bio->bi_status = errno_to_blk_status(r);
if (unlikely(ic->synchronous_mode) && bio_op(bio) == REQ_OP_WRITE) {
unsigned long flags;
+
spin_lock_irqsave(&ic->endio_wait.lock, flags);
bio_list_add(&ic->synchronous_bios, bio);
queue_delayed_work(ic->commit_wq, &ic->bitmap_flush_work, 0);
@@ -1618,7 +1636,6 @@ static void dec_in_flight(struct dm_integrity_io *dio)
schedule_autocommit(ic);
bio = dm_bio_from_per_bio_data(dio, sizeof(struct dm_integrity_io));
-
if (unlikely(dio->bi_status) && !bio->bi_status)
bio->bi_status = dio->bi_status;
if (likely(!bio->bi_status) && unlikely(bio_sectors(bio) != dio->range.n_sectors)) {
@@ -1652,7 +1669,7 @@ static void integrity_sector_checksum(struct dm_integrity_c *ic, sector_t sector
__le64 sector_le = cpu_to_le64(sector);
SHASH_DESC_ON_STACK(req, ic->internal_hash);
int r;
- unsigned digest_size;
+ unsigned int digest_size;
req->tfm = ic->internal_hash;
@@ -1670,7 +1687,7 @@ static void integrity_sector_checksum(struct dm_integrity_c *ic, sector_t sector
}
}
- r = crypto_shash_update(req, (const __u8 *)&sector_le, sizeof sector_le);
+ r = crypto_shash_update(req, (const __u8 *)&sector_le, sizeof(sector_le));
if (unlikely(r < 0)) {
dm_integrity_io_error(ic, "crypto_shash_update", r);
goto failed;
@@ -1709,13 +1726,13 @@ static void integrity_metadata(struct work_struct *w)
if (ic->internal_hash) {
struct bvec_iter iter;
struct bio_vec bv;
- unsigned digest_size = crypto_shash_digestsize(ic->internal_hash);
+ unsigned int digest_size = crypto_shash_digestsize(ic->internal_hash);
struct bio *bio = dm_bio_from_per_bio_data(dio, sizeof(struct dm_integrity_io));
char *checksums;
- unsigned extra_space = unlikely(digest_size > ic->tag_size) ? digest_size - ic->tag_size : 0;
- char checksums_onstack[max((size_t)HASH_MAX_DIGESTSIZE, MAX_TAG_SIZE)];
+ unsigned int extra_space = unlikely(digest_size > ic->tag_size) ? digest_size - ic->tag_size : 0;
+ char checksums_onstack[max_t(size_t, HASH_MAX_DIGESTSIZE, MAX_TAG_SIZE)];
sector_t sector;
- unsigned sectors_to_process;
+ unsigned int sectors_to_process;
if (unlikely(ic->mode == 'R'))
goto skip_io;
@@ -1735,14 +1752,15 @@ static void integrity_metadata(struct work_struct *w)
}
if (unlikely(dio->op == REQ_OP_DISCARD)) {
- sector_t bi_sector = dio->bio_details.bi_iter.bi_sector;
- unsigned bi_size = dio->bio_details.bi_iter.bi_size;
- unsigned max_size = likely(checksums != checksums_onstack) ? PAGE_SIZE : HASH_MAX_DIGESTSIZE;
- unsigned max_blocks = max_size / ic->tag_size;
+ unsigned int bi_size = dio->bio_details.bi_iter.bi_size;
+ unsigned int max_size = likely(checksums != checksums_onstack) ? PAGE_SIZE : HASH_MAX_DIGESTSIZE;
+ unsigned int max_blocks = max_size / ic->tag_size;
+
memset(checksums, DISCARD_FILLER, max_size);
while (bi_size) {
- unsigned this_step_blocks = bi_size >> (SECTOR_SHIFT + ic->sb->log2_sectors_per_block);
+ unsigned int this_step_blocks = bi_size >> (SECTOR_SHIFT + ic->sb->log2_sectors_per_block);
+
this_step_blocks = min(this_step_blocks, max_blocks);
r = dm_integrity_rw_tag(ic, checksums, &dio->metadata_block, &dio->metadata_offset,
this_step_blocks * ic->tag_size, TAG_WRITE);
@@ -1752,13 +1770,7 @@ static void integrity_metadata(struct work_struct *w)
goto error;
}
- /*if (bi_size < this_step_blocks << (SECTOR_SHIFT + ic->sb->log2_sectors_per_block)) {
- printk("BUGG: bi_sector: %llx, bi_size: %u\n", bi_sector, bi_size);
- printk("BUGG: this_step_blocks: %u\n", this_step_blocks);
- BUG();
- }*/
bi_size -= this_step_blocks << (SECTOR_SHIFT + ic->sb->log2_sectors_per_block);
- bi_sector += this_step_blocks << ic->sb->log2_sectors_per_block;
}
if (likely(checksums != checksums_onstack))
@@ -1770,7 +1782,7 @@ static void integrity_metadata(struct work_struct *w)
sectors_to_process = dio->range.n_sectors;
__bio_for_each_segment(bv, bio, iter, dio->bio_details.bi_iter) {
- unsigned pos;
+ unsigned int pos;
char *mem, *checksums_ptr;
again:
@@ -1823,13 +1835,14 @@ again:
if (bip) {
struct bio_vec biv;
struct bvec_iter iter;
- unsigned data_to_process = dio->range.n_sectors;
+ unsigned int data_to_process = dio->range.n_sectors;
+
sector_to_block(ic, data_to_process);
data_to_process *= ic->tag_size;
bip_for_each_vec(biv, bip, iter) {
unsigned char *tag;
- unsigned this_len;
+ unsigned int this_len;
BUG_ON(PageHighMem(biv.bv_page));
tag = bvec_virt(&biv);
@@ -1867,11 +1880,13 @@ static int dm_integrity_map(struct dm_target *ti, struct bio *bio)
if (unlikely(dio->op == REQ_OP_DISCARD)) {
if (ti->max_io_len) {
sector_t sec = dm_target_offset(ti, bio->bi_iter.bi_sector);
- unsigned log2_max_io_len = __fls(ti->max_io_len);
+ unsigned int log2_max_io_len = __fls(ti->max_io_len);
sector_t start_boundary = sec >> log2_max_io_len;
sector_t end_boundary = (sec + bio_sectors(bio) - 1) >> log2_max_io_len;
+
if (start_boundary < end_boundary) {
sector_t len = ti->max_io_len - (sec & (ti->max_io_len - 1));
+
dm_accept_partial_bio(bio, len);
}
}
@@ -1897,7 +1912,7 @@ static int dm_integrity_map(struct dm_target *ti, struct bio *bio)
ic->provided_data_sectors);
return DM_MAPIO_KILL;
}
- if (unlikely((dio->range.logical_sector | bio_sectors(bio)) & (unsigned)(ic->sectors_per_block - 1))) {
+ if (unlikely((dio->range.logical_sector | bio_sectors(bio)) & (unsigned int)(ic->sectors_per_block - 1))) {
DMERR("Bio not aligned on %u sectors: 0x%llx, 0x%x",
ic->sectors_per_block,
dio->range.logical_sector, bio_sectors(bio));
@@ -1907,6 +1922,7 @@ static int dm_integrity_map(struct dm_target *ti, struct bio *bio)
if (ic->sectors_per_block > 1 && likely(dio->op != REQ_OP_DISCARD)) {
struct bvec_iter iter;
struct bio_vec bv;
+
bio_for_each_segment(bv, bio, iter) {
if (unlikely(bv.bv_len & ((ic->sectors_per_block << SECTOR_SHIFT) - 1))) {
DMERR("Bio vector (%u,%u) is not aligned on %u-sector boundary",
@@ -1919,7 +1935,8 @@ static int dm_integrity_map(struct dm_target *ti, struct bio *bio)
bip = bio_integrity(bio);
if (!ic->internal_hash) {
if (bip) {
- unsigned wanted_tag_size = bio_sectors(bio) >> ic->sb->log2_sectors_per_block;
+ unsigned int wanted_tag_size = bio_sectors(bio) >> ic->sb->log2_sectors_per_block;
+
if (ic->log2_tag_size >= 0)
wanted_tag_size <<= ic->log2_tag_size;
else
@@ -1949,11 +1966,11 @@ static int dm_integrity_map(struct dm_target *ti, struct bio *bio)
}
static bool __journal_read_write(struct dm_integrity_io *dio, struct bio *bio,
- unsigned journal_section, unsigned journal_entry)
+ unsigned int journal_section, unsigned int journal_entry)
{
struct dm_integrity_c *ic = dio->ic;
sector_t logical_sector;
- unsigned n_sectors;
+ unsigned int n_sectors;
logical_sector = dio->range.logical_sector;
n_sectors = dio->range.n_sectors;
@@ -1976,7 +1993,7 @@ retry_kmap:
if (unlikely(dio->op == REQ_OP_READ)) {
struct journal_sector *js;
char *mem_ptr;
- unsigned s;
+ unsigned int s;
if (unlikely(journal_entry_is_inprogress(je))) {
flush_dcache_page(bv.bv_page);
@@ -1998,7 +2015,7 @@ retry_kmap:
} while (++s < ic->sectors_per_block);
#ifdef INTERNAL_VERIFY
if (ic->internal_hash) {
- char checksums_onstack[max((size_t)HASH_MAX_DIGESTSIZE, MAX_TAG_SIZE)];
+ char checksums_onstack[max_t(size_t, HASH_MAX_DIGESTSIZE, MAX_TAG_SIZE)];
integrity_sector_checksum(ic, logical_sector, mem + bv.bv_offset, checksums_onstack);
if (unlikely(memcmp(checksums_onstack, journal_entry_tag(ic, je), ic->tag_size))) {
@@ -2013,31 +2030,32 @@ retry_kmap:
if (!ic->internal_hash) {
struct bio_integrity_payload *bip = bio_integrity(bio);
- unsigned tag_todo = ic->tag_size;
+ unsigned int tag_todo = ic->tag_size;
char *tag_ptr = journal_entry_tag(ic, je);
- if (bip) do {
- struct bio_vec biv = bvec_iter_bvec(bip->bip_vec, bip->bip_iter);
- unsigned tag_now = min(biv.bv_len, tag_todo);
- char *tag_addr;
- BUG_ON(PageHighMem(biv.bv_page));
- tag_addr = bvec_virt(&biv);
- if (likely(dio->op == REQ_OP_WRITE))
- memcpy(tag_ptr, tag_addr, tag_now);
- else
- memcpy(tag_addr, tag_ptr, tag_now);
- bvec_iter_advance(bip->bip_vec, &bip->bip_iter, tag_now);
- tag_ptr += tag_now;
- tag_todo -= tag_now;
- } while (unlikely(tag_todo)); else {
- if (likely(dio->op == REQ_OP_WRITE))
- memset(tag_ptr, 0, tag_todo);
- }
+ if (bip) {
+ do {
+ struct bio_vec biv = bvec_iter_bvec(bip->bip_vec, bip->bip_iter);
+ unsigned int tag_now = min(biv.bv_len, tag_todo);
+ char *tag_addr;
+
+ BUG_ON(PageHighMem(biv.bv_page));
+ tag_addr = bvec_virt(&biv);
+ if (likely(dio->op == REQ_OP_WRITE))
+ memcpy(tag_ptr, tag_addr, tag_now);
+ else
+ memcpy(tag_addr, tag_ptr, tag_now);
+ bvec_iter_advance(bip->bip_vec, &bip->bip_iter, tag_now);
+ tag_ptr += tag_now;
+ tag_todo -= tag_now;
+ } while (unlikely(tag_todo));
+ } else if (likely(dio->op == REQ_OP_WRITE))
+ memset(tag_ptr, 0, tag_todo);
}
if (likely(dio->op == REQ_OP_WRITE)) {
struct journal_sector *js;
- unsigned s;
+ unsigned int s;
js = access_journal_data(ic, journal_section, journal_entry);
memcpy(js, mem + bv.bv_offset, ic->sectors_per_block << SECTOR_SHIFT);
@@ -2048,9 +2066,11 @@ retry_kmap:
} while (++s < ic->sectors_per_block);
if (ic->internal_hash) {
- unsigned digest_size = crypto_shash_digestsize(ic->internal_hash);
+ unsigned int digest_size = crypto_shash_digestsize(ic->internal_hash);
+
if (unlikely(digest_size > ic->tag_size)) {
char checksums_onstack[HASH_MAX_DIGESTSIZE];
+
integrity_sector_checksum(ic, logical_sector, (char *)js, checksums_onstack);
memcpy(journal_entry_tag(ic, je), checksums_onstack, ic->tag_size);
} else
@@ -2080,14 +2100,12 @@ retry_kmap:
smp_mb();
if (unlikely(waitqueue_active(&ic->copy_to_journal_wait)))
wake_up(&ic->copy_to_journal_wait);
- if (READ_ONCE(ic->free_sectors) <= ic->free_sectors_threshold) {
+ if (READ_ONCE(ic->free_sectors) <= ic->free_sectors_threshold)
queue_work(ic->commit_wq, &ic->commit_work);
- } else {
+ else
schedule_autocommit(ic);
- }
- } else {
+ } else
remove_range(ic, &dio->range);
- }
if (unlikely(bio->bi_iter.bi_size)) {
sector_t area, offset;
@@ -2105,11 +2123,12 @@ static void dm_integrity_map_continue(struct dm_integrity_io *dio, bool from_map
{
struct dm_integrity_c *ic = dio->ic;
struct bio *bio = dm_bio_from_per_bio_data(dio, sizeof(struct dm_integrity_io));
- unsigned journal_section, journal_entry;
- unsigned journal_read_pos;
+ unsigned int journal_section, journal_entry;
+ unsigned int journal_read_pos;
struct completion read_comp;
bool discard_retried = false;
bool need_sync_io = ic->internal_hash && dio->op == REQ_OP_READ;
+
if (unlikely(dio->op == REQ_OP_DISCARD) && ic->mode != 'D')
need_sync_io = true;
@@ -2131,8 +2150,8 @@ retry:
journal_read_pos = NOT_FOUND;
if (ic->mode == 'J' && likely(dio->op != REQ_OP_DISCARD)) {
if (dio->op == REQ_OP_WRITE) {
- unsigned next_entry, i, pos;
- unsigned ws, we, range_sectors;
+ unsigned int next_entry, i, pos;
+ unsigned int ws, we, range_sectors;
dio->range.n_sectors = min(dio->range.n_sectors,
(sector_t)ic->free_sectors << ic->sb->log2_sectors_per_block);
@@ -2180,13 +2199,15 @@ retry:
goto journal_read_write;
} else {
sector_t next_sector;
+
journal_read_pos = find_journal_node(ic, dio->range.logical_sector, &next_sector);
if (likely(journal_read_pos == NOT_FOUND)) {
if (unlikely(dio->range.n_sectors > next_sector - dio->range.logical_sector))
dio->range.n_sectors = next_sector - dio->range.logical_sector;
} else {
- unsigned i;
- unsigned jp = journal_read_pos + 1;
+ unsigned int i;
+ unsigned int jp = journal_read_pos + 1;
+
for (i = ic->sectors_per_block; i < dio->range.n_sectors; i += ic->sectors_per_block, jp++) {
if (!test_journal_node(ic, jp, dio->range.logical_sector + i))
break;
@@ -2218,7 +2239,9 @@ offload_to_thread:
*/
if (journal_read_pos != NOT_FOUND) {
sector_t next_sector;
- unsigned new_pos = find_journal_node(ic, dio->range.logical_sector, &next_sector);
+ unsigned int new_pos;
+
+ new_pos = find_journal_node(ic, dio->range.logical_sector, &next_sector);
if (unlikely(new_pos != journal_read_pos)) {
remove_range_unlocked(ic, &dio->range);
goto retry;
@@ -2227,7 +2250,9 @@ offload_to_thread:
}
if (ic->mode == 'J' && likely(dio->op == REQ_OP_DISCARD) && !discard_retried) {
sector_t next_sector;
- unsigned new_pos = find_journal_node(ic, dio->range.logical_sector, &next_sector);
+ unsigned int new_pos;
+
+ new_pos = find_journal_node(ic, dio->range.logical_sector, &next_sector);
if (unlikely(new_pos != NOT_FOUND) ||
unlikely(next_sector < dio->range.logical_sector - dio->range.n_sectors)) {
remove_range_unlocked(ic, &dio->range);
@@ -2307,7 +2332,6 @@ offload_to_thread:
else
skip_check:
dec_in_flight(dio);
-
} else {
INIT_WORK(&dio->work, integrity_metadata);
queue_work(ic->metadata_wq, &dio->work);
@@ -2354,8 +2378,8 @@ static void pad_uncommitted(struct dm_integrity_c *ic)
static void integrity_commit(struct work_struct *w)
{
struct dm_integrity_c *ic = container_of(w, struct dm_integrity_c, commit_work);
- unsigned commit_start, commit_sections;
- unsigned i, j, n;
+ unsigned int commit_start, commit_sections;
+ unsigned int i, j, n;
struct bio *flushes;
del_timer(&ic->autocommit_timer);
@@ -2382,11 +2406,13 @@ static void integrity_commit(struct work_struct *w)
for (n = 0; n < commit_sections; n++) {
for (j = 0; j < ic->journal_section_entries; j++) {
struct journal_entry *je;
+
je = access_journal_entry(ic, i, j);
io_wait_event(ic->copy_to_journal_wait, !journal_entry_is_inprogress(je));
}
for (j = 0; j < ic->journal_section_sectors; j++) {
struct journal_sector *js;
+
js = access_journal(ic, i, j);
js->commit_id = dm_integrity_commit_id(ic, i, j, ic->commit_seq);
}
@@ -2412,6 +2438,7 @@ static void integrity_commit(struct work_struct *w)
release_flush_bios:
while (flushes) {
struct bio *next = flushes->bi_next;
+
flushes->bi_next = NULL;
do_endio(ic, flushes);
flushes = next;
@@ -2423,6 +2450,7 @@ static void complete_copy_from_journal(unsigned long error, void *context)
struct journal_io *io = context;
struct journal_completion *comp = io->comp;
struct dm_integrity_c *ic = comp->ic;
+
remove_range(ic, &io->range);
mempool_free(io, &ic->journal_io_mempool);
if (unlikely(error != 0))
@@ -2433,17 +2461,18 @@ static void complete_copy_from_journal(unsigned long error, void *context)
static void restore_last_bytes(struct dm_integrity_c *ic, struct journal_sector *js,
struct journal_entry *je)
{
- unsigned s = 0;
+ unsigned int s = 0;
+
do {
js->commit_id = je->last_bytes[s];
js++;
} while (++s < ic->sectors_per_block);
}
-static void do_journal_write(struct dm_integrity_c *ic, unsigned write_start,
- unsigned write_sections, bool from_replay)
+static void do_journal_write(struct dm_integrity_c *ic, unsigned int write_start,
+ unsigned int write_sections, bool from_replay)
{
- unsigned i, j, n;
+ unsigned int i, j, n;
struct journal_completion comp;
struct blk_plug plug;
@@ -2462,9 +2491,9 @@ static void do_journal_write(struct dm_integrity_c *ic, unsigned write_start,
for (j = 0; j < ic->journal_section_entries; j++) {
struct journal_entry *je = access_journal_entry(ic, i, j);
sector_t sec, area, offset;
- unsigned k, l, next_loop;
+ unsigned int k, l, next_loop;
sector_t metadata_block;
- unsigned metadata_offset;
+ unsigned int metadata_offset;
struct journal_io *io;
if (journal_entry_is_unused(je))
@@ -2472,7 +2501,7 @@ static void do_journal_write(struct dm_integrity_c *ic, unsigned write_start,
BUG_ON(unlikely(journal_entry_is_inprogress(je)) && !from_replay);
sec = journal_entry_get_sector(je);
if (unlikely(from_replay)) {
- if (unlikely(sec & (unsigned)(ic->sectors_per_block - 1))) {
+ if (unlikely(sec & (unsigned int)(ic->sectors_per_block - 1))) {
dm_integrity_io_error(ic, "invalid sector in journal", -EIO);
sec &= ~(sector_t)(ic->sectors_per_block - 1);
}
@@ -2486,6 +2515,7 @@ static void do_journal_write(struct dm_integrity_c *ic, unsigned write_start,
for (k = j + 1; k < ic->journal_section_entries; k++) {
struct journal_entry *je2 = access_journal_entry(ic, i, k);
sector_t sec2, area2, offset2;
+
if (journal_entry_is_unused(je2))
break;
BUG_ON(unlikely(journal_entry_is_inprogress(je2)) && !from_replay);
@@ -2533,9 +2563,8 @@ static void do_journal_write(struct dm_integrity_c *ic, unsigned write_start,
mempool_free(io, &ic->journal_io_mempool);
goto skip_io;
}
- for (l = j; l < k; l++) {
+ for (l = j; l < k; l++)
remove_journal_node(ic, &section_node[l]);
- }
}
spin_unlock_irq(&ic->endio_wait.lock);
@@ -2562,9 +2591,8 @@ static void do_journal_write(struct dm_integrity_c *ic, unsigned write_start,
journal_entry_set_unused(je2);
r = dm_integrity_rw_tag(ic, journal_entry_tag(ic, je2), &metadata_block, &metadata_offset,
ic->tag_size, TAG_WRITE);
- if (unlikely(r)) {
+ if (unlikely(r))
dm_integrity_io_error(ic, "reading tags", r);
- }
}
atomic_inc(&comp.in_flight);
@@ -2590,9 +2618,8 @@ skip_io:
static void integrity_writer(struct work_struct *w)
{
struct dm_integrity_c *ic = container_of(w, struct dm_integrity_c, writer_work);
- unsigned write_start, write_sections;
-
- unsigned prev_free_sectors;
+ unsigned int write_start, write_sections;
+ unsigned int prev_free_sectors;
spin_lock_irq(&ic->endio_wait.lock);
write_start = ic->committed_section;
@@ -2639,12 +2666,12 @@ static void integrity_recalc(struct work_struct *w)
struct dm_io_region io_loc;
sector_t area, offset;
sector_t metadata_block;
- unsigned metadata_offset;
+ unsigned int metadata_offset;
sector_t logical_sector, n_sectors;
__u8 *t;
- unsigned i;
+ unsigned int i;
int r;
- unsigned super_counter = 0;
+ unsigned int super_counter = 0;
DEBUG_print("start recalculation... (position %llx)\n", le64_to_cpu(ic->sb->recalc_sector));
@@ -2668,7 +2695,7 @@ next_chunk:
get_area_and_offset(ic, range.logical_sector, &area, &offset);
range.n_sectors = min((sector_t)RECALC_SECTORS, ic->provided_data_sectors - range.logical_sector);
if (!ic->meta_dev)
- range.n_sectors = min(range.n_sectors, ((sector_t)1U << ic->sb->log2_interleave_sectors) - (unsigned)offset);
+ range.n_sectors = min(range.n_sectors, ((sector_t)1U << ic->sb->log2_interleave_sectors) - (unsigned int)offset);
add_new_range_and_wait(ic, &range);
spin_unlock_irq(&ic->endio_wait.lock);
@@ -2676,9 +2703,9 @@ next_chunk:
n_sectors = range.n_sectors;
if (ic->mode == 'B') {
- if (block_bitmap_op(ic, ic->recalc_bitmap, logical_sector, n_sectors, BITMAP_OP_TEST_ALL_CLEAR)) {
+ if (block_bitmap_op(ic, ic->recalc_bitmap, logical_sector, n_sectors, BITMAP_OP_TEST_ALL_CLEAR))
goto advance_and_next;
- }
+
while (block_bitmap_op(ic, ic->recalc_bitmap, logical_sector,
ic->sectors_per_block, BITMAP_OP_TEST_ALL_CLEAR)) {
logical_sector += ic->sectors_per_block;
@@ -2697,9 +2724,9 @@ next_chunk:
if (unlikely(++super_counter == RECALC_WRITE_SUPER)) {
recalc_write_super(ic);
- if (ic->mode == 'B') {
+ if (ic->mode == 'B')
queue_delayed_work(ic->commit_wq, &ic->bitmap_flush_work, ic->bitmap_flush_interval);
- }
+
super_counter = 0;
}
@@ -2737,6 +2764,7 @@ next_chunk:
if (ic->mode == 'B') {
sector_t start, end;
+
start = (range.logical_sector >>
(ic->sb->log2_sectors_per_block + ic->log2_blocks_per_bitmap_bit)) <<
(ic->sb->log2_sectors_per_block + ic->log2_blocks_per_bitmap_bit);
@@ -2859,10 +2887,10 @@ static void bitmap_flush_work(struct work_struct *work)
}
-static void init_journal(struct dm_integrity_c *ic, unsigned start_section,
- unsigned n_sections, unsigned char commit_seq)
+static void init_journal(struct dm_integrity_c *ic, unsigned int start_section,
+ unsigned int n_sections, unsigned char commit_seq)
{
- unsigned i, j, n;
+ unsigned int i, j, n;
if (!n_sections)
return;
@@ -2872,12 +2900,14 @@ static void init_journal(struct dm_integrity_c *ic, unsigned start_section,
wraparound_section(ic, &i);
for (j = 0; j < ic->journal_section_sectors; j++) {
struct journal_sector *js = access_journal(ic, i, j);
+
BUILD_BUG_ON(sizeof(js->sectors) != JOURNAL_SECTOR_DATA);
memset(&js->sectors, 0, sizeof(js->sectors));
js->commit_id = dm_integrity_commit_id(ic, i, j, commit_seq);
}
for (j = 0; j < ic->journal_section_entries; j++) {
struct journal_entry *je = access_journal_entry(ic, i, j);
+
journal_entry_set_unused(je);
}
}
@@ -2885,9 +2915,10 @@ static void init_journal(struct dm_integrity_c *ic, unsigned start_section,
write_journal(ic, start_section, n_sections);
}
-static int find_commit_seq(struct dm_integrity_c *ic, unsigned i, unsigned j, commit_id_t id)
+static int find_commit_seq(struct dm_integrity_c *ic, unsigned int i, unsigned int j, commit_id_t id)
{
unsigned char k;
+
for (k = 0; k < N_COMMIT_IDS; k++) {
if (dm_integrity_commit_id(ic, i, j, k) == id)
return k;
@@ -2898,11 +2929,11 @@ static int find_commit_seq(struct dm_integrity_c *ic, unsigned i, unsigned j, co
static void replay_journal(struct dm_integrity_c *ic)
{
- unsigned i, j;
+ unsigned int i, j;
bool used_commit_ids[N_COMMIT_IDS];
- unsigned max_commit_id_sections[N_COMMIT_IDS];
- unsigned write_start, write_sections;
- unsigned continue_section;
+ unsigned int max_commit_id_sections[N_COMMIT_IDS];
+ unsigned int write_start, write_sections;
+ unsigned int continue_section;
bool journal_empty;
unsigned char unused, last_used, want_commit_seq;
@@ -2922,6 +2953,7 @@ static void replay_journal(struct dm_integrity_c *ic)
DEBUG_bytes(lowmem_page_address(ic->journal_io[0].page), 64, "read journal");
if (ic->journal_io) {
struct journal_completion crypt_comp;
+
crypt_comp.ic = ic;
init_completion(&crypt_comp.comp);
crypt_comp.in_flight = (atomic_t)ATOMIC_INIT(0);
@@ -2935,12 +2967,13 @@ static void replay_journal(struct dm_integrity_c *ic)
goto clear_journal;
journal_empty = true;
- memset(used_commit_ids, 0, sizeof used_commit_ids);
- memset(max_commit_id_sections, 0, sizeof max_commit_id_sections);
+ memset(used_commit_ids, 0, sizeof(used_commit_ids));
+ memset(max_commit_id_sections, 0, sizeof(max_commit_id_sections));
for (i = 0; i < ic->journal_sections; i++) {
for (j = 0; j < ic->journal_section_sectors; j++) {
int k;
struct journal_sector *js = access_journal(ic, i, j);
+
k = find_commit_seq(ic, i, j, js->commit_id);
if (k < 0)
goto clear_journal;
@@ -2950,6 +2983,7 @@ static void replay_journal(struct dm_integrity_c *ic)
if (journal_empty) {
for (j = 0; j < ic->journal_section_entries; j++) {
struct journal_entry *je = access_journal_entry(ic, i, j);
+
if (!journal_entry_is_unused(je)) {
journal_empty = false;
break;
@@ -3020,8 +3054,9 @@ brk:
ic->commit_seq = want_commit_seq;
DEBUG_print("continuing from section %u, commit seq %d\n", write_start, ic->commit_seq);
} else {
- unsigned s;
+ unsigned int s;
unsigned char erase_seq;
+
clear_journal:
DEBUG_print("clearing journal\n");
@@ -3058,7 +3093,7 @@ clear_journal:
static void dm_integrity_enter_synchronous_mode(struct dm_integrity_c *ic)
{
- DEBUG_print("dm_integrity_enter_synchronous_mode\n");
+ DEBUG_print("%s\n", __func__);
if (ic->mode == 'B') {
ic->bitmap_flush_interval = msecs_to_jiffies(10) + 1;
@@ -3074,7 +3109,7 @@ static int dm_integrity_reboot(struct notifier_block *n, unsigned long code, voi
{
struct dm_integrity_c *ic = container_of(n, struct dm_integrity_c, reboot_notifier);
- DEBUG_print("dm_integrity_reboot\n");
+ DEBUG_print("%s\n", __func__);
dm_integrity_enter_synchronous_mode(ic);
@@ -3231,6 +3266,7 @@ static void dm_integrity_resume(struct dm_target *ti)
DEBUG_print("testing recalc: %x\n", ic->sb->flags);
if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING)) {
__u64 recalc_pos = le64_to_cpu(ic->sb->recalc_sector);
+
DEBUG_print("recalc pos: %llx / %llx\n", recalc_pos, ic->provided_data_sectors);
if (recalc_pos < ic->provided_data_sectors) {
queue_work(ic->recalc_wq, &ic->recalc_work);
@@ -3252,10 +3288,10 @@ static void dm_integrity_resume(struct dm_target *ti)
}
static void dm_integrity_status(struct dm_target *ti, status_type_t type,
- unsigned status_flags, char *result, unsigned maxlen)
+ unsigned int status_flags, char *result, unsigned int maxlen)
{
struct dm_integrity_c *ic = (struct dm_integrity_c *)ti->private;
- unsigned arg_count;
+ unsigned int arg_count;
size_t sz = 0;
switch (type) {
@@ -3271,6 +3307,7 @@ static void dm_integrity_status(struct dm_target *ti, status_type_t type,
case STATUSTYPE_TABLE: {
__u64 watermark_percentage = (__u64)(ic->journal_entries - ic->free_sectors_threshold) * 100;
+
watermark_percentage += ic->journal_entries / 2;
do_div(watermark_percentage, ic->journal_entries);
arg_count = 3;
@@ -3305,7 +3342,7 @@ static void dm_integrity_status(struct dm_target *ti, status_type_t type,
DMEMIT(" interleave_sectors:%u", 1U << ic->sb->log2_interleave_sectors);
DMEMIT(" buffer_sectors:%u", 1U << ic->log2_buffer_sectors);
if (ic->mode == 'J') {
- DMEMIT(" journal_watermark:%u", (unsigned)watermark_percentage);
+ DMEMIT(" journal_watermark:%u", (unsigned int)watermark_percentage);
DMEMIT(" commit_time:%u", ic->autocommit_msec);
}
if (ic->mode == 'B') {
@@ -3384,7 +3421,7 @@ static void dm_integrity_io_hints(struct dm_target *ti, struct queue_limits *lim
static void calculate_journal_section_size(struct dm_integrity_c *ic)
{
- unsigned sector_space = JOURNAL_SECTOR_DATA;
+ unsigned int sector_space = JOURNAL_SECTOR_DATA;
ic->journal_sections = le32_to_cpu(ic->sb->journal_sections);
ic->journal_entry_size = roundup(offsetof(struct journal_entry, last_bytes[ic->sectors_per_block]) + ic->tag_size,
@@ -3430,6 +3467,7 @@ static int calculate_device_limits(struct dm_integrity_c *ic)
return -EINVAL;
} else {
__u64 meta_size = (ic->provided_data_sectors >> ic->sb->log2_sectors_per_block) * ic->tag_size;
+
meta_size = (meta_size + ((1U << (ic->log2_buffer_sectors + SECTOR_SHIFT)) - 1))
>> (ic->log2_buffer_sectors + SECTOR_SHIFT);
meta_size <<= ic->log2_buffer_sectors;
@@ -3447,6 +3485,7 @@ static void get_provided_data_sectors(struct dm_integrity_c *ic)
{
if (!ic->meta_dev) {
int test_bit;
+
ic->provided_data_sectors = 0;
for (test_bit = fls64(ic->meta_device_sectors) - 1; test_bit >= 3; test_bit--) {
__u64 prev_data_sectors = ic->provided_data_sectors;
@@ -3461,9 +3500,10 @@ static void get_provided_data_sectors(struct dm_integrity_c *ic)
}
}
-static int initialize_superblock(struct dm_integrity_c *ic, unsigned journal_sectors, unsigned interleave_sectors)
+static int initialize_superblock(struct dm_integrity_c *ic,
+ unsigned int journal_sectors, unsigned int interleave_sectors)
{
- unsigned journal_sections;
+ unsigned int journal_sections;
int test_bit;
memset(ic->sb, 0, SB_SECTORS << SECTOR_SHIFT);
@@ -3490,8 +3530,8 @@ static int initialize_superblock(struct dm_integrity_c *ic, unsigned journal_sec
if (!interleave_sectors)
interleave_sectors = DEFAULT_INTERLEAVE_SECTORS;
ic->sb->log2_interleave_sectors = __fls(interleave_sectors);
- ic->sb->log2_interleave_sectors = max((__u8)MIN_LOG2_INTERLEAVE_SECTORS, ic->sb->log2_interleave_sectors);
- ic->sb->log2_interleave_sectors = min((__u8)MAX_LOG2_INTERLEAVE_SECTORS, ic->sb->log2_interleave_sectors);
+ ic->sb->log2_interleave_sectors = max_t(__u8, MIN_LOG2_INTERLEAVE_SECTORS, ic->sb->log2_interleave_sectors);
+ ic->sb->log2_interleave_sectors = min_t(__u8, MAX_LOG2_INTERLEAVE_SECTORS, ic->sb->log2_interleave_sectors);
get_provided_data_sectors(ic);
if (!ic->provided_data_sectors)
@@ -3508,6 +3548,7 @@ try_smaller_buffer:
for (test_bit = fls(journal_sections) - 1; test_bit >= 0; test_bit--) {
__u32 prev_journal_sections = le32_to_cpu(ic->sb->journal_sections);
__u32 test_journal_sections = prev_journal_sections | (1U << test_bit);
+
if (test_journal_sections > journal_sections)
continue;
ic->sb->journal_sections = cpu_to_le32(test_journal_sections);
@@ -3548,7 +3589,7 @@ static void dm_integrity_set(struct dm_target *ti, struct dm_integrity_c *ic)
static void dm_integrity_free_page_list(struct page_list *pl)
{
- unsigned i;
+ unsigned int i;
if (!pl)
return;
@@ -3557,10 +3598,10 @@ static void dm_integrity_free_page_list(struct page_list *pl)
kvfree(pl);
}
-static struct page_list *dm_integrity_alloc_page_list(unsigned n_pages)
+static struct page_list *dm_integrity_alloc_page_list(unsigned int n_pages)
{
struct page_list *pl;
- unsigned i;
+ unsigned int i;
pl = kvmalloc_array(n_pages + 1, sizeof(struct page_list), GFP_KERNEL | __GFP_ZERO);
if (!pl)
@@ -3583,7 +3624,8 @@ static struct page_list *dm_integrity_alloc_page_list(unsigned n_pages)
static void dm_integrity_free_journal_scatterlist(struct dm_integrity_c *ic, struct scatterlist **sl)
{
- unsigned i;
+ unsigned int i;
+
for (i = 0; i < ic->journal_sections; i++)
kvfree(sl[i]);
kvfree(sl);
@@ -3593,7 +3635,7 @@ static struct scatterlist **dm_integrity_alloc_journal_scatterlist(struct dm_int
struct page_list *pl)
{
struct scatterlist **sl;
- unsigned i;
+ unsigned int i;
sl = kvmalloc_array(ic->journal_sections,
sizeof(struct scatterlist *),
@@ -3603,10 +3645,10 @@ static struct scatterlist **dm_integrity_alloc_journal_scatterlist(struct dm_int
for (i = 0; i < ic->journal_sections; i++) {
struct scatterlist *s;
- unsigned start_index, start_offset;
- unsigned end_index, end_offset;
- unsigned n_pages;
- unsigned idx;
+ unsigned int start_index, start_offset;
+ unsigned int end_index, end_offset;
+ unsigned int n_pages;
+ unsigned int idx;
page_list_location(ic, i, 0, &start_index, &start_offset);
page_list_location(ic, i, ic->journal_section_sectors - 1,
@@ -3624,7 +3666,8 @@ static struct scatterlist **dm_integrity_alloc_journal_scatterlist(struct dm_int
sg_init_table(s, n_pages);
for (idx = start_index; idx <= end_index; idx++) {
char *va = lowmem_page_address(pl[idx].page);
- unsigned start = 0, end = PAGE_SIZE;
+ unsigned int start = 0, end = PAGE_SIZE;
+
if (idx == start_index)
start = start_offset;
if (idx == end_index)
@@ -3642,7 +3685,7 @@ static void free_alg(struct alg_spec *a)
{
kfree_sensitive(a->alg_string);
kfree_sensitive(a->key);
- memset(a, 0, sizeof *a);
+ memset(a, 0, sizeof(*a));
}
static int get_alg_and_key(const char *arg, struct alg_spec *a, char **error, char *error_inval)
@@ -3711,7 +3754,7 @@ static int get_mac(struct crypto_shash **hash, struct alg_spec *a, char **error,
static int create_journal(struct dm_integrity_c *ic, char **error)
{
int r = 0;
- unsigned i;
+ unsigned int i;
__u64 journal_pages, journal_desc_size, journal_tree_size;
unsigned char *crypt_data = NULL, *crypt_iv = NULL;
struct skcipher_request *req = NULL;
@@ -3738,7 +3781,7 @@ static int create_journal(struct dm_integrity_c *ic, char **error)
goto bad;
}
if (ic->journal_crypt_alg.alg_string) {
- unsigned ivsize, blocksize;
+ unsigned int ivsize, blocksize;
struct journal_completion comp;
comp.ic = ic;
@@ -3805,13 +3848,14 @@ static int create_journal(struct dm_integrity_c *ic, char **error)
sg_init_table(sg, ic->journal_pages + 1);
for (i = 0; i < ic->journal_pages; i++) {
char *va = lowmem_page_address(ic->journal_xor[i].page);
+
clear_page(va);
sg_set_buf(&sg[i], va, PAGE_SIZE);
}
- sg_set_buf(&sg[i], &ic->commit_ids, sizeof ic->commit_ids);
+ sg_set_buf(&sg[i], &ic->commit_ids, sizeof(ic->commit_ids));
skcipher_request_set_crypt(req, sg, sg,
- PAGE_SIZE * ic->journal_pages + sizeof ic->commit_ids, crypt_iv);
+ PAGE_SIZE * ic->journal_pages + sizeof(ic->commit_ids), crypt_iv);
init_completion(&comp.comp);
comp.in_flight = (atomic_t)ATOMIC_INIT(1);
if (do_crypt(true, req, &comp))
@@ -3827,7 +3871,7 @@ static int create_journal(struct dm_integrity_c *ic, char **error)
crypto_free_skcipher(ic->journal_crypt);
ic->journal_crypt = NULL;
} else {
- unsigned crypt_len = roundup(ivsize, blocksize);
+ unsigned int crypt_len = roundup(ivsize, blocksize);
req = skcipher_request_alloc(ic->journal_crypt, GFP_KERNEL);
if (!req) {
@@ -3877,7 +3921,7 @@ static int create_journal(struct dm_integrity_c *ic, char **error)
memset(crypt_iv, 0x00, ivsize);
memset(crypt_data, 0x00, crypt_len);
- memcpy(crypt_data, &section_le, min((size_t)crypt_len, sizeof(section_le)));
+ memcpy(crypt_data, &section_le, min_t(size_t, crypt_len, sizeof(section_le)));
sg_init_one(&sg, crypt_data, crypt_len);
skcipher_request_set_crypt(req, &sg, &sg, crypt_len, crypt_iv);
@@ -3915,7 +3959,8 @@ static int create_journal(struct dm_integrity_c *ic, char **error)
}
for (i = 0; i < N_COMMIT_IDS; i++) {
- unsigned j;
+ unsigned int j;
+
retest_commit_id:
for (j = 0; j < i; j++) {
if (ic->commit_ids[j] == ic->commit_ids[i]) {
@@ -3969,17 +4014,17 @@ bad:
* journal_mac
* recalculate
*/
-static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
+static int dm_integrity_ctr(struct dm_target *ti, unsigned int argc, char **argv)
{
struct dm_integrity_c *ic;
char dummy;
int r;
- unsigned extra_args;
+ unsigned int extra_args;
struct dm_arg_set as;
static const struct dm_arg _args[] = {
{0, 18, "Invalid number of feature args"},
};
- unsigned journal_sectors, interleave_sectors, buffer_sectors, journal_watermark, sync_msec;
+ unsigned int journal_sectors, interleave_sectors, buffer_sectors, journal_watermark, sync_msec;
bool should_write_sb;
__u64 threshold;
unsigned long long start;
@@ -4058,8 +4103,9 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
while (extra_args--) {
const char *opt_string;
- unsigned val;
+ unsigned int val;
unsigned long long llval;
+
opt_string = dm_shift_arg(&as);
if (!opt_string) {
r = -EINVAL;
@@ -4090,7 +4136,7 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
} else if (sscanf(opt_string, "block_size:%u%c", &val, &dummy) == 1) {
if (val < 1 << SECTOR_SHIFT ||
val > MAX_SECTORS_PER_BLOCK << SECTOR_SHIFT ||
- (val & (val -1))) {
+ (val & (val - 1))) {
r = -EINVAL;
ti->error = "Invalid block_size argument";
goto bad;
@@ -4363,9 +4409,9 @@ try_smaller_buffer:
log2_blocks_per_bitmap_bit = log2_sectors_per_bitmap_bit - ic->sb->log2_sectors_per_block;
ic->log2_blocks_per_bitmap_bit = log2_blocks_per_bitmap_bit;
- if (should_write_sb) {
+ if (should_write_sb)
ic->sb->log2_blocks_per_bitmap_bit = log2_blocks_per_bitmap_bit;
- }
+
n_bitmap_bits = ((ic->provided_data_sectors >> ic->sb->log2_sectors_per_block)
+ (((sector_t)1 << log2_blocks_per_bitmap_bit) - 1)) >> log2_blocks_per_bitmap_bit;
ic->n_bitmap_blocks = DIV_ROUND_UP(n_bitmap_bits, BITMAP_BLOCK_SIZE * 8);
@@ -4391,7 +4437,7 @@ try_smaller_buffer:
DEBUG_print(" journal_entries_per_sector %u\n", ic->journal_entries_per_sector);
DEBUG_print(" journal_section_entries %u\n", ic->journal_section_entries);
DEBUG_print(" journal_section_sectors %u\n", ic->journal_section_sectors);
- DEBUG_print(" journal_sections %u\n", (unsigned)le32_to_cpu(ic->sb->journal_sections));
+ DEBUG_print(" journal_sections %u\n", (unsigned int)le32_to_cpu(ic->sb->journal_sections));
DEBUG_print(" journal_entries %u\n", ic->journal_entries);
DEBUG_print(" log2_interleave_sectors %d\n", ic->sb->log2_interleave_sectors);
DEBUG_print(" data_device_sectors 0x%llx\n", bdev_nr_sectors(ic->dev->bdev));
@@ -4409,8 +4455,9 @@ try_smaller_buffer:
if (ic->internal_hash) {
size_t recalc_tags_size;
+
ic->recalc_wq = alloc_workqueue("dm-integrity-recalc", WQ_MEM_RECLAIM, 1);
- if (!ic->recalc_wq ) {
+ if (!ic->recalc_wq) {
ti->error = "Cannot allocate workqueue";
r = -ENOMEM;
goto bad;
@@ -4465,8 +4512,8 @@ try_smaller_buffer:
}
if (ic->mode == 'B') {
- unsigned i;
- unsigned n_bitmap_pages = DIV_ROUND_UP(ic->n_bitmap_blocks, PAGE_SIZE / BITMAP_BLOCK_SIZE);
+ unsigned int i;
+ unsigned int n_bitmap_pages = DIV_ROUND_UP(ic->n_bitmap_blocks, PAGE_SIZE / BITMAP_BLOCK_SIZE);
ic->recalc_bitmap = dm_integrity_alloc_page_list(n_bitmap_pages);
if (!ic->recalc_bitmap) {
@@ -4486,7 +4533,7 @@ try_smaller_buffer:
INIT_DELAYED_WORK(&ic->bitmap_flush_work, bitmap_flush_work);
for (i = 0; i < ic->n_bitmap_blocks; i++) {
struct bitmap_block_status *bbs = &ic->bbs[i];
- unsigned sector, pl_index, pl_offset;
+ unsigned int sector, pl_index, pl_offset;
INIT_WORK(&bbs->work, bitmap_block_work);
bbs->ic = ic;
@@ -4523,7 +4570,9 @@ try_smaller_buffer:
goto bad;
}
if (ic->mode == 'B') {
- unsigned max_io_len = ((sector_t)ic->sectors_per_block << ic->log2_blocks_per_bitmap_bit) * (BITMAP_BLOCK_SIZE * 8);
+ unsigned int max_io_len;
+
+ max_io_len = ((sector_t)ic->sectors_per_block << ic->log2_blocks_per_bitmap_bit) * (BITMAP_BLOCK_SIZE * 8);
if (!max_io_len)
max_io_len = 1U << 31;
DEBUG_print("max_io_len: old %u, new %u\n", ti->max_io_len, max_io_len);
@@ -4594,10 +4643,12 @@ static void dm_integrity_dtr(struct dm_target *ti)
if (ic->journal_io_scatterlist)
dm_integrity_free_journal_scatterlist(ic, ic->journal_io_scatterlist);
if (ic->sk_requests) {
- unsigned i;
+ unsigned int i;
for (i = 0; i < ic->journal_sections; i++) {
- struct skcipher_request *req = ic->sk_requests[i];
+ struct skcipher_request *req;
+
+ req = ic->sk_requests[i];
if (req) {
kfree_sensitive(req->iv);
skcipher_request_free(req);
diff --git a/drivers/md/dm-io-rewind.c b/drivers/md/dm-io-rewind.c
index 0db53ccb94ba..6155b0117c9d 100644
--- a/drivers/md/dm-io-rewind.c
+++ b/drivers/md/dm-io-rewind.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2022 Red Hat, Inc.
*/
@@ -57,7 +57,7 @@ static void dm_bio_integrity_rewind(struct bio *bio, unsigned int bytes_done)
{
struct bio_integrity_payload *bip = bio_integrity(bio);
struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk);
- unsigned bytes = bio_integrity_bytes(bi, bytes_done >> 9);
+ unsigned int bytes = bio_integrity_bytes(bi, bytes_done >> 9);
bip->bip_iter.bi_sector -= bio_integrity_intervals(bi, bytes_done >> 9);
dm_bvec_iter_rewind(bip->bip_vec, &bip->bip_iter, bytes);
@@ -68,7 +68,6 @@ static void dm_bio_integrity_rewind(struct bio *bio, unsigned int bytes_done)
static inline void dm_bio_integrity_rewind(struct bio *bio,
unsigned int bytes_done)
{
- return;
}
#endif
@@ -104,7 +103,6 @@ static void dm_bio_crypt_rewind(struct bio *bio, unsigned int bytes)
static inline void dm_bio_crypt_rewind(struct bio *bio, unsigned int bytes)
{
- return;
}
#endif
@@ -131,7 +129,7 @@ static inline void dm_bio_rewind_iter(const struct bio *bio,
* rewinding from end of bio and restoring its original position.
* Caller is also responsibile for restoring bio's size.
*/
-static void dm_bio_rewind(struct bio *bio, unsigned bytes)
+static void dm_bio_rewind(struct bio *bio, unsigned int bytes)
{
if (bio_integrity(bio))
dm_bio_integrity_rewind(bio, bytes);
diff --git a/drivers/md/dm-io-tracker.h b/drivers/md/dm-io-tracker.h
index bdcc6273ebf0..bea1ca11855e 100644
--- a/drivers/md/dm-io-tracker.h
+++ b/drivers/md/dm-io-tracker.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2021 Red Hat, Inc. All rights reserved.
*
diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c
index 783564533459..dc2df76999b0 100644
--- a/drivers/md/dm-io.c
+++ b/drivers/md/dm-io.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2003 Sistina Software
* Copyright (C) 2006 Red Hat GmbH
@@ -38,7 +39,7 @@ struct io {
void *context;
void *vma_invalidate_address;
unsigned long vma_invalidate_size;
-} __attribute__((aligned(DM_IO_MAX_REGIONS)));
+} __aligned(DM_IO_MAX_REGIONS);
static struct kmem_cache *_dm_io_cache;
@@ -48,7 +49,7 @@ static struct kmem_cache *_dm_io_cache;
struct dm_io_client *dm_io_client_create(void)
{
struct dm_io_client *client;
- unsigned min_ios = dm_get_reserved_bio_based_ios();
+ unsigned int min_ios = dm_get_reserved_bio_based_ios();
int ret;
client = kzalloc(sizeof(*client), GFP_KERNEL);
@@ -65,7 +66,7 @@ struct dm_io_client *dm_io_client_create(void)
return client;
- bad:
+bad:
mempool_exit(&client->pool);
kfree(client);
return ERR_PTR(ret);
@@ -80,15 +81,17 @@ void dm_io_client_destroy(struct dm_io_client *client)
}
EXPORT_SYMBOL(dm_io_client_destroy);
-/*-----------------------------------------------------------------
+/*
+ *-------------------------------------------------------------------
* We need to keep track of which region a bio is doing io for.
* To avoid a memory allocation to store just 5 or 6 bits, we
* ensure the 'struct io' pointer is aligned so enough low bits are
* always zero and then combine it with the region number directly in
* bi_private.
- *---------------------------------------------------------------*/
+ *-------------------------------------------------------------------
+ */
static void store_io_and_region_in_bio(struct bio *bio, struct io *io,
- unsigned region)
+ unsigned int region)
{
if (unlikely(!IS_ALIGNED((unsigned long)io, DM_IO_MAX_REGIONS))) {
DMCRIT("Unaligned struct io pointer %p", io);
@@ -99,7 +102,7 @@ static void store_io_and_region_in_bio(struct bio *bio, struct io *io,
}
static void retrieve_io_and_region_from_bio(struct bio *bio, struct io **io,
- unsigned *region)
+ unsigned int *region)
{
unsigned long val = (unsigned long)bio->bi_private;
@@ -107,10 +110,12 @@ static void retrieve_io_and_region_from_bio(struct bio *bio, struct io **io,
*region = val & (DM_IO_MAX_REGIONS - 1);
}
-/*-----------------------------------------------------------------
+/*
+ *--------------------------------------------------------------
* We need an io object to keep track of the number of bios that
* have been dispatched for a particular io.
- *---------------------------------------------------------------*/
+ *--------------------------------------------------------------
+ */
static void complete_io(struct io *io)
{
unsigned long error_bits = io->error_bits;
@@ -137,7 +142,7 @@ static void dec_count(struct io *io, unsigned int region, blk_status_t error)
static void endio(struct bio *bio)
{
struct io *io;
- unsigned region;
+ unsigned int region;
blk_status_t error;
if (bio->bi_status && bio_data_dir(bio) == READ)
@@ -154,17 +159,19 @@ static void endio(struct bio *bio)
dec_count(io, region, error);
}
-/*-----------------------------------------------------------------
+/*
+ *--------------------------------------------------------------
* These little objects provide an abstraction for getting a new
* destination page for io.
- *---------------------------------------------------------------*/
+ *--------------------------------------------------------------
+ */
struct dpages {
void (*get_page)(struct dpages *dp,
- struct page **p, unsigned long *len, unsigned *offset);
+ struct page **p, unsigned long *len, unsigned int *offset);
void (*next_page)(struct dpages *dp);
union {
- unsigned context_u;
+ unsigned int context_u;
struct bvec_iter context_bi;
};
void *context_ptr;
@@ -177,9 +184,9 @@ struct dpages {
* Functions for getting the pages from a list.
*/
static void list_get_page(struct dpages *dp,
- struct page **p, unsigned long *len, unsigned *offset)
+ struct page **p, unsigned long *len, unsigned int *offset)
{
- unsigned o = dp->context_u;
+ unsigned int o = dp->context_u;
struct page_list *pl = (struct page_list *) dp->context_ptr;
*p = pl->page;
@@ -190,11 +197,12 @@ static void list_get_page(struct dpages *dp,
static void list_next_page(struct dpages *dp)
{
struct page_list *pl = (struct page_list *) dp->context_ptr;
+
dp->context_ptr = pl->next;
dp->context_u = 0;
}
-static void list_dp_init(struct dpages *dp, struct page_list *pl, unsigned offset)
+static void list_dp_init(struct dpages *dp, struct page_list *pl, unsigned int offset)
{
dp->get_page = list_get_page;
dp->next_page = list_next_page;
@@ -206,7 +214,7 @@ static void list_dp_init(struct dpages *dp, struct page_list *pl, unsigned offse
* Functions for getting the pages from a bvec.
*/
static void bio_get_page(struct dpages *dp, struct page **p,
- unsigned long *len, unsigned *offset)
+ unsigned long *len, unsigned int *offset)
{
struct bio_vec bvec = bvec_iter_bvec((struct bio_vec *)dp->context_ptr,
dp->context_bi);
@@ -244,7 +252,7 @@ static void bio_dp_init(struct dpages *dp, struct bio *bio)
* Functions for getting the pages from a VMA.
*/
static void vm_get_page(struct dpages *dp,
- struct page **p, unsigned long *len, unsigned *offset)
+ struct page **p, unsigned long *len, unsigned int *offset)
{
*p = vmalloc_to_page(dp->context_ptr);
*offset = dp->context_u;
@@ -269,7 +277,7 @@ static void vm_dp_init(struct dpages *dp, void *data)
* Functions for getting the pages from kernel memory.
*/
static void km_get_page(struct dpages *dp, struct page **p, unsigned long *len,
- unsigned *offset)
+ unsigned int *offset)
{
*p = virt_to_page(dp->context_ptr);
*offset = dp->context_u;
@@ -290,18 +298,20 @@ static void km_dp_init(struct dpages *dp, void *data)
dp->context_ptr = data;
}
-/*-----------------------------------------------------------------
+/*
+ *---------------------------------------------------------------
* IO routines that accept a list of pages.
- *---------------------------------------------------------------*/
-static void do_region(const blk_opf_t opf, unsigned region,
+ *---------------------------------------------------------------
+ */
+static void do_region(const blk_opf_t opf, unsigned int region,
struct dm_io_region *where, struct dpages *dp,
struct io *io)
{
struct bio *bio;
struct page *page;
unsigned long len;
- unsigned offset;
- unsigned num_bvecs;
+ unsigned int offset;
+ unsigned int num_bvecs;
sector_t remaining = where->count;
struct request_queue *q = bdev_get_queue(where->bdev);
sector_t num_sectors;
@@ -350,18 +360,20 @@ static void do_region(const blk_opf_t opf, unsigned region,
num_sectors = min_t(sector_t, special_cmd_max_sectors, remaining);
bio->bi_iter.bi_size = num_sectors << SECTOR_SHIFT;
remaining -= num_sectors;
- } else while (remaining) {
- /*
- * Try and add as many pages as possible.
- */
- dp->get_page(dp, &page, &len, &offset);
- len = min(len, to_bytes(remaining));
- if (!bio_add_page(bio, page, len, offset))
- break;
-
- offset = 0;
- remaining -= to_sector(len);
- dp->next_page(dp);
+ } else {
+ while (remaining) {
+ /*
+ * Try and add as many pages as possible.
+ */
+ dp->get_page(dp, &page, &len, &offset);
+ len = min(len, to_bytes(remaining));
+ if (!bio_add_page(bio, page, len, offset))
+ break;
+
+ offset = 0;
+ remaining -= to_sector(len);
+ dp->next_page(dp);
+ }
}
atomic_inc(&io->count);
@@ -508,7 +520,7 @@ static int dp_init(struct dm_io_request *io_req, struct dpages *dp,
return 0;
}
-int dm_io(struct dm_io_request *io_req, unsigned num_regions,
+int dm_io(struct dm_io_request *io_req, unsigned int num_regions,
struct dm_io_region *where, unsigned long *sync_error_bits)
{
int r;
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index 36fc6ae4737a..50a1259294d1 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2001, 2002 Sistina Software (UK) Limited.
* Copyright (C) 2004 - 2006 Red Hat, Inc. All rights reserved.
@@ -31,13 +32,15 @@ struct dm_file {
* poll will wait until the global event number is greater than
* this value.
*/
- volatile unsigned global_event_nr;
+ volatile unsigned int global_event_nr;
};
-/*-----------------------------------------------------------------
+/*
+ *---------------------------------------------------------------
* The ioctl interface needs to be able to look up devices by
* name or uuid.
- *---------------------------------------------------------------*/
+ *---------------------------------------------------------------
+ */
struct hash_cell {
struct rb_node name_node;
struct rb_node uuid_node;
@@ -51,10 +54,10 @@ struct hash_cell {
};
struct vers_iter {
- size_t param_size;
- struct dm_target_versions *vers, *old_vers;
- char *end;
- uint32_t flags;
+ size_t param_size;
+ struct dm_target_versions *vers, *old_vers;
+ char *end;
+ uint32_t flags;
};
@@ -78,16 +81,20 @@ static void dm_hash_exit(void)
dm_hash_remove_all(false, false, false);
}
-/*-----------------------------------------------------------------
+/*
+ *---------------------------------------------------------------
* Code for looking up a device by name
- *---------------------------------------------------------------*/
+ *---------------------------------------------------------------
+ */
static struct hash_cell *__get_name_cell(const char *str)
{
struct rb_node *n = name_rb_tree.rb_node;
while (n) {
struct hash_cell *hc = container_of(n, struct hash_cell, name_node);
- int c = strcmp(hc->name, str);
+ int c;
+
+ c = strcmp(hc->name, str);
if (!c) {
dm_get(hc->md);
return hc;
@@ -104,7 +111,9 @@ static struct hash_cell *__get_uuid_cell(const char *str)
while (n) {
struct hash_cell *hc = container_of(n, struct hash_cell, uuid_node);
- int c = strcmp(hc->uuid, str);
+ int c;
+
+ c = strcmp(hc->uuid, str);
if (!c) {
dm_get(hc->md);
return hc;
@@ -144,7 +153,9 @@ static void __link_name(struct hash_cell *new_hc)
while (*n) {
struct hash_cell *hc = container_of(*n, struct hash_cell, name_node);
- int c = strcmp(hc->name, new_hc->name);
+ int c;
+
+ c = strcmp(hc->name, new_hc->name);
BUG_ON(!c);
parent = *n;
n = c >= 0 ? &hc->name_node.rb_left : &hc->name_node.rb_right;
@@ -167,7 +178,9 @@ static void __link_uuid(struct hash_cell *new_hc)
while (*n) {
struct hash_cell *hc = container_of(*n, struct hash_cell, uuid_node);
- int c = strcmp(hc->uuid, new_hc->uuid);
+ int c;
+
+ c = strcmp(hc->uuid, new_hc->uuid);
BUG_ON(!c);
parent = *n;
n = c > 0 ? &hc->uuid_node.rb_left : &hc->uuid_node.rb_right;
@@ -195,9 +208,11 @@ static struct hash_cell *__get_dev_cell(uint64_t dev)
return hc;
}
-/*-----------------------------------------------------------------
+/*
+ *---------------------------------------------------------------
* Inserting, removing and renaming a device.
- *---------------------------------------------------------------*/
+ *---------------------------------------------------------------
+ */
static struct hash_cell *alloc_cell(const char *name, const char *uuid,
struct mapped_device *md)
{
@@ -295,6 +310,8 @@ static struct dm_table *__hash_remove(struct hash_cell *hc)
struct dm_table *table;
int srcu_idx;
+ lockdep_assert_held(&_hash_lock);
+
/* remove from the dev trees */
__unlink_name(hc);
__unlink_uuid(hc);
@@ -413,7 +430,7 @@ static struct mapped_device *dm_hash_rename(struct dm_ioctl *param,
struct hash_cell *hc;
struct dm_table *table;
struct mapped_device *md;
- unsigned change_uuid = (param->flags & DM_UUID_FLAG) ? 1 : 0;
+ unsigned int change_uuid = (param->flags & DM_UUID_FLAG) ? 1 : 0;
int srcu_idx;
/*
@@ -434,8 +451,7 @@ static struct mapped_device *dm_hash_rename(struct dm_ioctl *param,
hc = __get_name_cell(new);
if (hc) {
- DMERR("Unable to change %s on mapped device %s to one that "
- "already exists: %s",
+ DMERR("Unable to change %s on mapped device %s to one that already exists: %s",
change_uuid ? "uuid" : "name",
param->name, new);
dm_put(hc->md);
@@ -482,7 +498,7 @@ static struct mapped_device *dm_hash_rename(struct dm_ioctl *param,
dm_table_event(table);
dm_put_live_table(hc->md, srcu_idx);
- if (!dm_kobject_uevent(hc->md, KOBJ_CHANGE, param->event_nr))
+ if (!dm_kobject_uevent(hc->md, KOBJ_CHANGE, param->event_nr, false))
param->flags |= DM_UEVENT_GENERATED_FLAG;
md = hc->md;
@@ -500,9 +516,11 @@ void dm_deferred_remove(void)
dm_hash_remove_all(true, false, true);
}
-/*-----------------------------------------------------------------
+/*
+ *---------------------------------------------------------------
* Implementation of the ioctl commands
- *---------------------------------------------------------------*/
+ *---------------------------------------------------------------
+ */
/*
* All the ioctl commands get dispatched to functions with this
* prototype.
@@ -612,6 +630,7 @@ static int list_devices(struct file *filp, struct dm_ioctl *param, size_t param_
*/
for (n = rb_first(&name_rb_tree); n; n = rb_next(n)) {
void *uuid_ptr;
+
hc = container_of(n, struct hash_cell, name_node);
if (!filter_device(hc, param->name, param->uuid))
continue;
@@ -652,36 +671,34 @@ static int list_devices(struct file *filp, struct dm_ioctl *param, size_t param_
static void list_version_get_needed(struct target_type *tt, void *needed_param)
{
- size_t *needed = needed_param;
+ size_t *needed = needed_param;
- *needed += sizeof(struct dm_target_versions);
- *needed += strlen(tt->name) + 1;
- *needed += ALIGN_MASK;
+ *needed += sizeof(struct dm_target_versions);
+ *needed += strlen(tt->name) + 1;
+ *needed += ALIGN_MASK;
}
static void list_version_get_info(struct target_type *tt, void *param)
{
- struct vers_iter *info = param;
+ struct vers_iter *info = param;
- /* Check space - it might have changed since the first iteration */
- if ((char *)info->vers + sizeof(tt->version) + strlen(tt->name) + 1 >
- info->end) {
+ /* Check space - it might have changed since the first iteration */
+ if ((char *)info->vers + sizeof(tt->version) + strlen(tt->name) + 1 > info->end) {
+ info->flags = DM_BUFFER_FULL_FLAG;
+ return;
+ }
- info->flags = DM_BUFFER_FULL_FLAG;
- return;
- }
+ if (info->old_vers)
+ info->old_vers->next = (uint32_t) ((void *)info->vers - (void *)info->old_vers);
- if (info->old_vers)
- info->old_vers->next = (uint32_t) ((void *)info->vers -
- (void *)info->old_vers);
- info->vers->version[0] = tt->version[0];
- info->vers->version[1] = tt->version[1];
- info->vers->version[2] = tt->version[2];
- info->vers->next = 0;
- strcpy(info->vers->name, tt->name);
+ info->vers->version[0] = tt->version[0];
+ info->vers->version[1] = tt->version[1];
+ info->vers->version[2] = tt->version[2];
+ info->vers->next = 0;
+ strcpy(info->vers->name, tt->name);
- info->old_vers = info->vers;
- info->vers = align_ptr((void *)(info->vers + 1) + strlen(tt->name) + 1);
+ info->old_vers = info->vers;
+ info->vers = align_ptr((void *)(info->vers + 1) + strlen(tt->name) + 1);
}
static int __list_versions(struct dm_ioctl *param, size_t param_size, const char *name)
@@ -772,7 +789,7 @@ static struct dm_table *dm_get_inactive_table(struct mapped_device *md, int *src
down_read(&_hash_lock);
hc = dm_get_mdptr(md);
- if (!hc || hc->md != md) {
+ if (!hc) {
DMERR("device has been removed from the dev hash table.");
goto out;
}
@@ -841,6 +858,7 @@ static void __dev_status(struct mapped_device *md, struct dm_ioctl *param)
if (param->flags & DM_QUERY_INACTIVE_TABLE_FLAG) {
int srcu_idx;
+
table = dm_get_inactive_table(md, &srcu_idx);
if (table) {
if (!(dm_table_get_mode(table) & FMODE_WRITE))
@@ -921,9 +939,9 @@ static struct hash_cell *__find_device_hash_cell(struct dm_ioctl *param)
* Sneakily write in both the name and the uuid
* while we have the cell.
*/
- strlcpy(param->name, hc->name, sizeof(param->name));
+ strscpy(param->name, hc->name, sizeof(param->name));
if (hc->uuid)
- strlcpy(param->uuid, hc->uuid, sizeof(param->uuid));
+ strscpy(param->uuid, hc->uuid, sizeof(param->uuid));
else
param->uuid[0] = '\0';
@@ -995,7 +1013,7 @@ static int dev_remove(struct file *filp, struct dm_ioctl *param, size_t param_si
dm_ima_measure_on_device_remove(md, false);
- if (!dm_kobject_uevent(md, KOBJ_REMOVE, param->event_nr))
+ if (!dm_kobject_uevent(md, KOBJ_REMOVE, param->event_nr, false))
param->flags |= DM_UEVENT_GENERATED_FLAG;
dm_put(md);
@@ -1021,7 +1039,7 @@ static int dev_rename(struct file *filp, struct dm_ioctl *param, size_t param_si
int r;
char *new_data = (char *) param + param->data_start;
struct mapped_device *md;
- unsigned change_uuid = (param->flags & DM_UUID_FLAG) ? 1 : 0;
+ unsigned int change_uuid = (param->flags & DM_UUID_FLAG) ? 1 : 0;
if (new_data < param->data ||
invalid_str(new_data, (void *) param + param_size) || !*new_data ||
@@ -1073,8 +1091,7 @@ static int dev_set_geometry(struct file *filp, struct dm_ioctl *param, size_t pa
goto out;
}
- if (indata[0] > 65535 || indata[1] > 255 ||
- indata[2] > 255 || indata[3] > ULONG_MAX) {
+ if (indata[0] > 65535 || indata[1] > 255 || indata[2] > 255) {
DMERR("Geometry exceeds range limits.");
goto out;
}
@@ -1096,7 +1113,7 @@ out:
static int do_suspend(struct dm_ioctl *param)
{
int r = 0;
- unsigned suspend_flags = DM_SUSPEND_LOCKFS_FLAG;
+ unsigned int suspend_flags = DM_SUSPEND_LOCKFS_FLAG;
struct mapped_device *md;
md = find_device(param);
@@ -1125,10 +1142,11 @@ out:
static int do_resume(struct dm_ioctl *param)
{
int r = 0;
- unsigned suspend_flags = DM_SUSPEND_LOCKFS_FLAG;
+ unsigned int suspend_flags = DM_SUSPEND_LOCKFS_FLAG;
struct hash_cell *hc;
struct mapped_device *md;
struct dm_table *new_map, *old_map = NULL;
+ bool need_resize_uevent = false;
down_write(&_hash_lock);
@@ -1149,6 +1167,8 @@ static int do_resume(struct dm_ioctl *param)
/* Do we need to load a new map ? */
if (new_map) {
+ sector_t old_size, new_size;
+
/* Suspend if it isn't already suspended */
if (param->flags & DM_SKIP_LOCKFS_FLAG)
suspend_flags &= ~DM_SUSPEND_LOCKFS_FLAG;
@@ -1157,6 +1177,7 @@ static int do_resume(struct dm_ioctl *param)
if (!dm_suspended_md(md))
dm_suspend(md, suspend_flags);
+ old_size = dm_get_size(md);
old_map = dm_swap_table(md, new_map);
if (IS_ERR(old_map)) {
dm_sync_table(md);
@@ -1164,6 +1185,9 @@ static int do_resume(struct dm_ioctl *param)
dm_put(md);
return PTR_ERR(old_map);
}
+ new_size = dm_get_size(md);
+ if (old_size && new_size && old_size != new_size)
+ need_resize_uevent = true;
if (dm_table_get_mode(new_map) & FMODE_WRITE)
set_disk_ro(dm_disk(md), 0);
@@ -1176,7 +1200,7 @@ static int do_resume(struct dm_ioctl *param)
if (!r) {
dm_ima_measure_on_device_resume(md, new_map ? true : false);
- if (!dm_kobject_uevent(md, KOBJ_CHANGE, param->event_nr))
+ if (!dm_kobject_uevent(md, KOBJ_CHANGE, param->event_nr, need_resize_uevent))
param->flags |= DM_UEVENT_GENERATED_FLAG;
}
}
@@ -1236,7 +1260,7 @@ static void retrieve_status(struct dm_table *table,
char *outbuf, *outptr;
status_type_t type;
size_t remaining, len, used = 0;
- unsigned status_flags = 0;
+ unsigned int status_flags = 0;
outptr = outbuf = get_result_buffer(param, param_size, &len);
@@ -1387,7 +1411,7 @@ static int populate_table(struct dm_table *table,
char *target_params;
if (!param->target_count) {
- DMERR("populate_table: no targets specified");
+ DMERR("%s: no targets specified", __func__);
return -EINVAL;
}
@@ -1476,7 +1500,7 @@ static int table_load(struct file *filp, struct dm_ioctl *param, size_t param_si
/* stage inactive table */
down_write(&_hash_lock);
hc = dm_get_mdptr(md);
- if (!hc || hc->md != md) {
+ if (!hc) {
DMERR("device has been removed from the dev hash table.");
up_write(&_hash_lock);
r = -ENXIO;
@@ -1564,7 +1588,7 @@ static void retrieve_deps(struct dm_table *table,
/*
* Count the devices.
*/
- list_for_each (tmp, dm_table_get_devices(table))
+ list_for_each(tmp, dm_table_get_devices(table))
count++;
/*
@@ -1581,7 +1605,7 @@ static void retrieve_deps(struct dm_table *table,
*/
deps->count = count;
count = 0;
- list_for_each_entry (dd, dm_table_get_devices(table), list)
+ list_for_each_entry(dd, dm_table_get_devices(table), list)
deps->dev[count++] = huge_encode_dev(dd->dm_dev->bdev->bd_dev);
param->data_size = param->data_start + needed;
@@ -1641,8 +1665,8 @@ static int table_status(struct file *filp, struct dm_ioctl *param, size_t param_
* Returns a number <= 1 if message was processed by device mapper.
* Returns 2 if message should be delivered to the target.
*/
-static int message_for_md(struct mapped_device *md, unsigned argc, char **argv,
- char *result, unsigned maxlen)
+static int message_for_md(struct mapped_device *md, unsigned int argc, char **argv,
+ char *result, unsigned int maxlen)
{
int r;
@@ -1757,10 +1781,11 @@ static int target_message(struct file *filp, struct dm_ioctl *param, size_t para
#define IOCTL_FLAGS_NO_PARAMS 1
#define IOCTL_FLAGS_ISSUE_GLOBAL_EVENT 2
-/*-----------------------------------------------------------------
- * Implementation of open/close/ioctl on the special char
- * device.
- *---------------------------------------------------------------*/
+/*
+ *---------------------------------------------------------------
+ * Implementation of open/close/ioctl on the special char device.
+ *---------------------------------------------------------------
+ */
static ioctl_fn lookup_ioctl(unsigned int cmd, int *ioctl_flags)
{
static const struct {
@@ -1812,10 +1837,9 @@ static int check_version(unsigned int cmd, struct dm_ioctl __user *user)
if (copy_from_user(version, user->version, sizeof(version)))
return -EFAULT;
- if ((DM_VERSION_MAJOR != version[0]) ||
- (DM_VERSION_MINOR < version[1])) {
- DMERR("ioctl interface mismatch: "
- "kernel(%u.%u.%u), user(%u.%u.%u), cmd(%d)",
+ if ((version[0] != DM_VERSION_MAJOR) ||
+ (version[1] > DM_VERSION_MINOR)) {
+ DMERR("ioctl interface mismatch: kernel(%u.%u.%u), user(%u.%u.%u), cmd(%d)",
DM_VERSION_MAJOR, DM_VERSION_MINOR,
DM_VERSION_PATCHLEVEL,
version[0], version[1], version[2], cmd);
@@ -1852,7 +1876,7 @@ static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl *param_kern
struct dm_ioctl *dmi;
int secure_data;
const size_t minimum_data_size = offsetof(struct dm_ioctl, data);
- unsigned noio_flag;
+ unsigned int noio_flag;
if (copy_from_user(param_kernel, user, minimum_data_size))
return -EFAULT;
@@ -2079,9 +2103,9 @@ static const struct file_operations _ctl_fops = {
static struct miscdevice _dm_misc = {
.minor = MAPPER_CTRL_MINOR,
- .name = DM_NAME,
+ .name = DM_NAME,
.nodename = DM_DIR "/" DM_CONTROL_NODE,
- .fops = &_ctl_fops
+ .fops = &_ctl_fops
};
MODULE_ALIAS_MISCDEV(MAPPER_CTRL_MINOR);
@@ -2128,7 +2152,7 @@ int dm_copy_name_and_uuid(struct mapped_device *md, char *name, char *uuid)
mutex_lock(&dm_hash_cells_mutex);
hc = dm_get_mdptr(md);
- if (!hc || hc->md != md) {
+ if (!hc) {
r = -ENXIO;
goto out;
}
@@ -2241,7 +2265,9 @@ int __init dm_early_create(struct dm_ioctl *dmi,
err_destroy_table:
dm_table_destroy(t);
err_hash_remove:
+ down_write(&_hash_lock);
(void) __hash_remove(__get_name_cell(dmi->name));
+ up_write(&_hash_lock);
/* release reference from __get_name_cell */
dm_put(md);
err_destroy_dm:
diff --git a/drivers/md/dm-kcopyd.c b/drivers/md/dm-kcopyd.c
index 4d3bbbea2e9a..a158c6e5fbd7 100644
--- a/drivers/md/dm-kcopyd.c
+++ b/drivers/md/dm-kcopyd.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2002 Sistina Software (UK) Limited.
* Copyright (C) 2006 Red Hat GmbH
@@ -34,14 +35,14 @@
#define DEFAULT_SUB_JOB_SIZE_KB 512
#define MAX_SUB_JOB_SIZE_KB 1024
-static unsigned kcopyd_subjob_size_kb = DEFAULT_SUB_JOB_SIZE_KB;
+static unsigned int kcopyd_subjob_size_kb = DEFAULT_SUB_JOB_SIZE_KB;
-module_param(kcopyd_subjob_size_kb, uint, S_IRUGO | S_IWUSR);
+module_param(kcopyd_subjob_size_kb, uint, 0644);
MODULE_PARM_DESC(kcopyd_subjob_size_kb, "Sub-job size for dm-kcopyd clients");
-static unsigned dm_get_kcopyd_subjob_size(void)
+static unsigned int dm_get_kcopyd_subjob_size(void)
{
- unsigned sub_job_size_kb;
+ unsigned int sub_job_size_kb;
sub_job_size_kb = __dm_get_module_param(&kcopyd_subjob_size_kb,
DEFAULT_SUB_JOB_SIZE_KB,
@@ -50,15 +51,17 @@ static unsigned dm_get_kcopyd_subjob_size(void)
return sub_job_size_kb << 1;
}
-/*-----------------------------------------------------------------
+/*
+ *----------------------------------------------------------------
* Each kcopyd client has its own little pool of preallocated
* pages for kcopyd io.
- *---------------------------------------------------------------*/
+ *---------------------------------------------------------------
+ */
struct dm_kcopyd_client {
struct page_list *pages;
- unsigned nr_reserved_pages;
- unsigned nr_free_pages;
- unsigned sub_job_size;
+ unsigned int nr_reserved_pages;
+ unsigned int nr_free_pages;
+ unsigned int sub_job_size;
struct dm_io_client *io_client;
@@ -109,7 +112,7 @@ static DEFINE_SPINLOCK(throttle_spinlock);
* The reason for this is unknown but possibly due to jiffies rounding errors
* or read/write cache inside the disk.
*/
-#define SLEEP_MSEC 100
+#define SLEEP_USEC 100000
/*
* Maximum number of sleep events. There is a theoretical livelock if more
@@ -119,7 +122,7 @@ static DEFINE_SPINLOCK(throttle_spinlock);
static void io_job_start(struct dm_kcopyd_throttle *t)
{
- unsigned throttle, now, difference;
+ unsigned int throttle, now, difference;
int slept = 0, skew;
if (unlikely(!t))
@@ -148,6 +151,7 @@ try_again:
if (unlikely(t->total_period >= (1 << ACCOUNT_INTERVAL_SHIFT))) {
int shift = fls(t->total_period >> ACCOUNT_INTERVAL_SHIFT);
+
t->total_period >>= shift;
t->io_period >>= shift;
}
@@ -157,7 +161,7 @@ try_again:
if (unlikely(skew > 0) && slept < MAX_SLEEPS) {
slept++;
spin_unlock_irq(&throttle_spinlock);
- msleep(SLEEP_MSEC);
+ fsleep(SLEEP_USEC);
goto try_again;
}
@@ -182,7 +186,7 @@ static void io_job_finish(struct dm_kcopyd_throttle *t)
goto skip_limit;
if (!t->num_io_jobs) {
- unsigned now, difference;
+ unsigned int now, difference;
now = jiffies;
difference = now - t->last_jiffies;
@@ -303,9 +307,9 @@ static void drop_pages(struct page_list *pl)
/*
* Allocate and reserve nr_pages for the use of a specific client.
*/
-static int client_reserve_pages(struct dm_kcopyd_client *kc, unsigned nr_pages)
+static int client_reserve_pages(struct dm_kcopyd_client *kc, unsigned int nr_pages)
{
- unsigned i;
+ unsigned int i;
struct page_list *pl = NULL, *next;
for (i = 0; i < nr_pages; i++) {
@@ -333,15 +337,17 @@ static void client_free_pages(struct dm_kcopyd_client *kc)
kc->nr_free_pages = kc->nr_reserved_pages = 0;
}
-/*-----------------------------------------------------------------
+/*
+ *---------------------------------------------------------------
* kcopyd_jobs need to be allocated by the *clients* of kcopyd,
* for this reason we use a mempool to prevent the client from
* ever having to do io (which could cause a deadlock).
- *---------------------------------------------------------------*/
+ *---------------------------------------------------------------
+ */
struct kcopyd_job {
struct dm_kcopyd_client *kc;
struct list_head list;
- unsigned flags;
+ unsigned int flags;
/*
* Error state of the job.
@@ -582,7 +588,7 @@ static int run_io_job(struct kcopyd_job *job)
static int run_pages_job(struct kcopyd_job *job)
{
int r;
- unsigned nr_pages = dm_div_up(job->dests[0].count, PAGE_SIZE >> 9);
+ unsigned int nr_pages = dm_div_up(job->dests[0].count, PAGE_SIZE >> 9);
r = kcopyd_get_pages(job->kc, nr_pages, &job->pages);
if (!r) {
@@ -603,7 +609,7 @@ static int run_pages_job(struct kcopyd_job *job)
* of successful jobs.
*/
static int process_jobs(struct list_head *jobs, struct dm_kcopyd_client *kc,
- int (*fn) (struct kcopyd_job *))
+ int (*fn)(struct kcopyd_job *))
{
struct kcopyd_job *job;
int r, count = 0;
@@ -673,6 +679,7 @@ static void do_work(struct work_struct *work)
static void dispatch_job(struct kcopyd_job *job)
{
struct dm_kcopyd_client *kc = job->kc;
+
atomic_inc(&kc->nr_jobs);
if (unlikely(!job->source.count))
push(&kc->callback_jobs, job);
@@ -819,7 +826,7 @@ void dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from,
job->pages = NULL;
job->op = REQ_OP_READ;
} else {
- memset(&job->source, 0, sizeof job->source);
+ memset(&job->source, 0, sizeof(job->source));
job->source.count = job->dests[0].count;
job->pages = &zero_page_list;
@@ -849,8 +856,8 @@ void dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from,
EXPORT_SYMBOL(dm_kcopyd_copy);
void dm_kcopyd_zero(struct dm_kcopyd_client *kc,
- unsigned num_dests, struct dm_io_region *dests,
- unsigned flags, dm_kcopyd_notify_fn fn, void *context)
+ unsigned int num_dests, struct dm_io_region *dests,
+ unsigned int flags, dm_kcopyd_notify_fn fn, void *context)
{
dm_kcopyd_copy(kc, NULL, num_dests, dests, flags, fn, context);
}
@@ -900,13 +907,15 @@ int kcopyd_cancel(struct kcopyd_job *job, int block)
}
#endif /* 0 */
-/*-----------------------------------------------------------------
+/*
+ *---------------------------------------------------------------
* Client setup
- *---------------------------------------------------------------*/
+ *---------------------------------------------------------------
+ */
struct dm_kcopyd_client *dm_kcopyd_client_create(struct dm_kcopyd_throttle *throttle)
{
int r;
- unsigned reserve_pages;
+ unsigned int reserve_pages;
struct dm_kcopyd_client *kc;
kc = kzalloc(sizeof(*kc), GFP_KERNEL);
diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c
index 3212ef6aa81b..3e622dcc9dbd 100644
--- a/drivers/md/dm-linear.c
+++ b/drivers/md/dm-linear.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2001-2003 Sistina Software (UK) Limited.
*
@@ -64,7 +65,7 @@ static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv)
ti->private = lc;
return 0;
- bad:
+bad:
kfree(lc);
return ret;
}
@@ -95,7 +96,7 @@ static int linear_map(struct dm_target *ti, struct bio *bio)
}
static void linear_status(struct dm_target *ti, status_type_t type,
- unsigned status_flags, char *result, unsigned maxlen)
+ unsigned int status_flags, char *result, unsigned int maxlen)
{
struct linear_c *lc = (struct linear_c *) ti->private;
size_t sz = 0;
diff --git a/drivers/md/dm-log-userspace-base.c b/drivers/md/dm-log-userspace-base.c
index 9ab93ebea889..5aace6ee6d47 100644
--- a/drivers/md/dm-log-userspace-base.c
+++ b/drivers/md/dm-log-userspace-base.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2006-2009 Red Hat, Inc.
*
@@ -123,7 +124,7 @@ retry:
}
static int build_constructor_string(struct dm_target *ti,
- unsigned argc, char **argv,
+ unsigned int argc, char **argv,
char **ctr_str)
{
int i, str_size;
@@ -188,7 +189,7 @@ static void do_flush(struct work_struct *work)
* to the userspace ctr function.
*/
static int userspace_ctr(struct dm_dirty_log *log, struct dm_target *ti,
- unsigned argc, char **argv)
+ unsigned int argc, char **argv)
{
int r = 0;
int str_size;
@@ -345,8 +346,6 @@ static void userspace_dtr(struct dm_dirty_log *log)
kfree(lc->usr_argv_str);
kfree(lc);
-
- return;
}
static int userspace_presuspend(struct dm_dirty_log *log)
@@ -660,8 +659,6 @@ static void userspace_mark_region(struct dm_dirty_log *log, region_t region)
fe->region = region;
list_add(&fe->list, &lc->mark_list);
spin_unlock_irqrestore(&lc->flush_lock, flags);
-
- return;
}
/*
@@ -697,8 +694,6 @@ static void userspace_clear_region(struct dm_dirty_log *log, region_t region)
fe->region = region;
list_add(&fe->list, &lc->clear_list);
spin_unlock_irqrestore(&lc->flush_lock, flags);
-
- return;
}
/*
@@ -755,7 +750,6 @@ static void userspace_set_region_sync(struct dm_dirty_log *log,
* It would be nice to be able to report failures.
* However, it is easy enough to detect and resolve.
*/
- return;
}
/*
@@ -792,7 +786,7 @@ static region_t userspace_get_sync_count(struct dm_dirty_log *log)
* Returns: amount of space consumed
*/
static int userspace_status(struct dm_dirty_log *log, status_type_t status_type,
- char *result, unsigned maxlen)
+ char *result, unsigned int maxlen)
{
int r = 0;
char *table_args;
@@ -926,7 +920,6 @@ static void __exit userspace_dirty_log_exit(void)
kmem_cache_destroy(_flush_entry_cache);
DMINFO("version " DM_LOG_USERSPACE_VSN " unloaded");
- return;
}
module_init(userspace_dirty_log_init);
diff --git a/drivers/md/dm-log-userspace-transfer.c b/drivers/md/dm-log-userspace-transfer.c
index fdf8ec304f8d..f125b0f553fa 100644
--- a/drivers/md/dm-log-userspace-transfer.c
+++ b/drivers/md/dm-log-userspace-transfer.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2006-2009 Red Hat, Inc.
*
@@ -108,9 +109,8 @@ static int fill_pkg(struct cn_msg *msg, struct dm_ulog_request *tfr)
if (pkg->error != -EAGAIN)
*(pkg->data_size) = 0;
} else if (tfr->data_size > *(pkg->data_size)) {
- DMERR("Insufficient space to receive package [%u] "
- "(%u vs %zu)", tfr->request_type,
- tfr->data_size, *(pkg->data_size));
+ DMERR("Insufficient space to receive package [%u] (%u vs %zu)",
+ tfr->request_type, tfr->data_size, *(pkg->data_size));
*(pkg->data_size) = 0;
pkg->error = -ENOSPC;
@@ -142,7 +142,7 @@ static void cn_ulog_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
fill_pkg(msg, NULL);
else if (msg->len < sizeof(*tfr))
DMERR("Incomplete message received (expected %u, got %u): [%u]",
- (unsigned)sizeof(*tfr), msg->len, msg->seq);
+ (unsigned int)sizeof(*tfr), msg->len, msg->seq);
else
fill_pkg(NULL, tfr);
spin_unlock(&receiving_list_lock);
diff --git a/drivers/md/dm-log-userspace-transfer.h b/drivers/md/dm-log-userspace-transfer.h
index 04ee874f9153..f2f970af906f 100644
--- a/drivers/md/dm-log-userspace-transfer.h
+++ b/drivers/md/dm-log-userspace-transfer.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2006-2009 Red Hat, Inc.
*
diff --git a/drivers/md/dm-log-writes.c b/drivers/md/dm-log-writes.c
index 178e13a5b059..cbd0f81f4a35 100644
--- a/drivers/md/dm-log-writes.c
+++ b/drivers/md/dm-log-writes.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 Facebook. All rights reserved.
*
@@ -231,13 +232,13 @@ static int write_metadata(struct log_writes_c *lc, void *entry,
goto error;
}
- ptr = kmap_atomic(page);
+ ptr = kmap_local_page(page);
memcpy(ptr, entry, entrylen);
if (datalen)
memcpy(ptr + entrylen, data, datalen);
memset(ptr + entrylen + datalen, 0,
lc->sectorsize - entrylen - datalen);
- kunmap_atomic(ptr);
+ kunmap_local(ptr);
ret = bio_add_page(bio, page, lc->sectorsize, 0);
if (ret != lc->sectorsize) {
@@ -286,11 +287,11 @@ static int write_inline_data(struct log_writes_c *lc, void *entry,
goto error_bio;
}
- ptr = kmap_atomic(page);
+ ptr = kmap_local_page(page);
memcpy(ptr, data, pg_datalen);
if (pg_sectorlen > pg_datalen)
memset(ptr + pg_datalen, 0, pg_sectorlen - pg_datalen);
- kunmap_atomic(ptr);
+ kunmap_local(ptr);
ret = bio_add_page(bio, page, pg_sectorlen, 0);
if (ret != pg_sectorlen) {
@@ -742,9 +743,9 @@ static int log_writes_map(struct dm_target *ti, struct bio *bio)
return DM_MAPIO_KILL;
}
- dst = kmap_atomic(page);
+ dst = kmap_local_page(page);
memcpy_from_bvec(dst, &bv);
- kunmap_atomic(dst);
+ kunmap_local(dst);
block->vecs[i].bv_page = page;
block->vecs[i].bv_len = bv.bv_len;
block->vec_cnt++;
@@ -792,10 +793,10 @@ static int normal_end_io(struct dm_target *ti, struct bio *bio,
* INFO format: <logged entries> <highest allocated sector>
*/
static void log_writes_status(struct dm_target *ti, status_type_t type,
- unsigned status_flags, char *result,
- unsigned maxlen)
+ unsigned int status_flags, char *result,
+ unsigned int maxlen)
{
- unsigned sz = 0;
+ unsigned int sz = 0;
struct log_writes_c *lc = ti->private;
switch (type) {
@@ -844,8 +845,8 @@ static int log_writes_iterate_devices(struct dm_target *ti,
* Messages supported:
* mark <mark data> - specify the marked data.
*/
-static int log_writes_message(struct dm_target *ti, unsigned argc, char **argv,
- char *result, unsigned maxlen)
+static int log_writes_message(struct dm_target *ti, unsigned int argc, char **argv,
+ char *result, unsigned int maxlen)
{
int r = -EINVAL;
struct log_writes_c *lc = ti->private;
diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c
index cf10fa667797..afd94d2e7295 100644
--- a/drivers/md/dm-log.c
+++ b/drivers/md/dm-log.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2003 Sistina Software
* Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
@@ -182,10 +183,12 @@ void dm_dirty_log_destroy(struct dm_dirty_log *log)
}
EXPORT_SYMBOL(dm_dirty_log_destroy);
-/*-----------------------------------------------------------------
+/*
+ *---------------------------------------------------------------
* Persistent and core logs share a lot of their implementation.
* FIXME: need a reload method to be called from a resume
- *---------------------------------------------------------------*/
+ *---------------------------------------------------------------
+ */
/*
* Magic for persistent mirrors: "MiRr"
*/
@@ -223,7 +226,7 @@ struct log_c {
unsigned int region_count;
region_t sync_count;
- unsigned bitset_uint32_count;
+ unsigned int bitset_uint32_count;
uint32_t *clean_bits;
uint32_t *sync_bits;
uint32_t *recovering_bits; /* FIXME: this seems excessive */
@@ -255,28 +258,30 @@ struct log_c {
* The touched member needs to be updated every time we access
* one of the bitsets.
*/
-static inline int log_test_bit(uint32_t *bs, unsigned bit)
+static inline int log_test_bit(uint32_t *bs, unsigned int bit)
{
return test_bit_le(bit, bs) ? 1 : 0;
}
static inline void log_set_bit(struct log_c *l,
- uint32_t *bs, unsigned bit)
+ uint32_t *bs, unsigned int bit)
{
__set_bit_le(bit, bs);
l->touched_cleaned = 1;
}
static inline void log_clear_bit(struct log_c *l,
- uint32_t *bs, unsigned bit)
+ uint32_t *bs, unsigned int bit)
{
__clear_bit_le(bit, bs);
l->touched_dirtied = 1;
}
-/*----------------------------------------------------------------
+/*
+ *---------------------------------------------------------------
* Header IO
- *--------------------------------------------------------------*/
+ *--------------------------------------------------------------
+ */
static void header_to_disk(struct log_header_core *core, struct log_header_disk *disk)
{
disk->magic = cpu_to_le32(core->magic);
@@ -352,11 +357,13 @@ static int _check_region_size(struct dm_target *ti, uint32_t region_size)
return 1;
}
-/*----------------------------------------------------------------
+/*
+ *--------------------------------------------------------------
* core log constructor/destructor
*
* argv contains region_size followed optionally by [no]sync
- *--------------------------------------------------------------*/
+ *--------------------------------------------------------------
+ */
#define BYTE_SHIFT 3
static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti,
unsigned int argc, char **argv,
@@ -382,8 +389,7 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti,
else if (!strcmp(argv[1], "nosync"))
sync = NOSYNC;
else {
- DMWARN("unrecognised sync argument to "
- "dirty region log: %s", argv[1]);
+ DMWARN("unrecognised sync argument to dirty region log: %s", argv[1]);
return -EINVAL;
}
}
@@ -441,8 +447,7 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti,
*/
buf_size =
dm_round_up((LOG_OFFSET << SECTOR_SHIFT) + bitset_size,
- bdev_logical_block_size(lc->header_location.
- bdev));
+ bdev_logical_block_size(lc->header_location.bdev));
if (buf_size > bdev_nr_bytes(dev->bdev)) {
DMWARN("log device %s too small: need %llu bytes",
@@ -531,11 +536,13 @@ static void core_dtr(struct dm_dirty_log *log)
destroy_log_context(lc);
}
-/*----------------------------------------------------------------
+/*
+ *---------------------------------------------------------------------
* disk log constructor/destructor
*
* argv contains log_device region_size followed optionally by [no]sync
- *--------------------------------------------------------------*/
+ *---------------------------------------------------------------------
+ */
static int disk_ctr(struct dm_dirty_log *log, struct dm_target *ti,
unsigned int argc, char **argv)
{
@@ -582,7 +589,7 @@ static void fail_log_device(struct log_c *lc)
static int disk_resume(struct dm_dirty_log *log)
{
int r;
- unsigned i;
+ unsigned int i;
struct log_c *lc = (struct log_c *) log->context;
size_t size = lc->bitset_uint32_count * sizeof(uint32_t);
@@ -646,12 +653,14 @@ static int disk_resume(struct dm_dirty_log *log)
static uint32_t core_get_region_size(struct dm_dirty_log *log)
{
struct log_c *lc = (struct log_c *) log->context;
+
return lc->region_size;
}
static int core_resume(struct dm_dirty_log *log)
{
struct log_c *lc = (struct log_c *) log->context;
+
lc->sync_search = 0;
return 0;
}
@@ -659,12 +668,14 @@ static int core_resume(struct dm_dirty_log *log)
static int core_is_clean(struct dm_dirty_log *log, region_t region)
{
struct log_c *lc = (struct log_c *) log->context;
+
return log_test_bit(lc->clean_bits, region);
}
static int core_in_sync(struct dm_dirty_log *log, region_t region, int block)
{
struct log_c *lc = (struct log_c *) log->context;
+
return log_test_bit(lc->sync_bits, region);
}
@@ -717,12 +728,14 @@ static int disk_flush(struct dm_dirty_log *log)
static void core_mark_region(struct dm_dirty_log *log, region_t region)
{
struct log_c *lc = (struct log_c *) log->context;
+
log_clear_bit(lc, lc->clean_bits, region);
}
static void core_clear_region(struct dm_dirty_log *log, region_t region)
{
struct log_c *lc = (struct log_c *) log->context;
+
if (likely(!lc->flush_failed))
log_set_bit(lc, lc->clean_bits, region);
}
@@ -757,8 +770,8 @@ static void core_set_region_sync(struct dm_dirty_log *log, region_t region,
log_clear_bit(lc, lc->recovering_bits, region);
if (in_sync) {
log_set_bit(lc, lc->sync_bits, region);
- lc->sync_count++;
- } else if (log_test_bit(lc->sync_bits, region)) {
+ lc->sync_count++;
+ } else if (log_test_bit(lc->sync_bits, region)) {
lc->sync_count--;
log_clear_bit(lc, lc->sync_bits, region);
}
@@ -766,14 +779,16 @@ static void core_set_region_sync(struct dm_dirty_log *log, region_t region,
static region_t core_get_sync_count(struct dm_dirty_log *log)
{
- struct log_c *lc = (struct log_c *) log->context;
+ struct log_c *lc = (struct log_c *) log->context;
- return lc->sync_count;
+ return lc->sync_count;
}
#define DMEMIT_SYNC \
- if (lc->sync != DEFAULTSYNC) \
- DMEMIT("%ssync ", lc->sync == NOSYNC ? "no" : "")
+ do { \
+ if (lc->sync != DEFAULTSYNC) \
+ DMEMIT("%ssync ", lc->sync == NOSYNC ? "no" : ""); \
+ } while (0)
static int core_status(struct dm_dirty_log *log, status_type_t status,
char *result, unsigned int maxlen)
@@ -781,7 +796,7 @@ static int core_status(struct dm_dirty_log *log, status_type_t status,
int sz = 0;
struct log_c *lc = log->context;
- switch(status) {
+ switch (status) {
case STATUSTYPE_INFO:
DMEMIT("1 %s", log->type->name);
break;
@@ -806,7 +821,7 @@ static int disk_status(struct dm_dirty_log *log, status_type_t status,
int sz = 0;
struct log_c *lc = log->context;
- switch(status) {
+ switch (status) {
case STATUSTYPE_INFO:
DMEMIT("3 %s %s %c", log->type->name, lc->log_dev->name,
lc->log_dev_flush_failed ? 'F' :
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index 0e325469a252..61ab1a8d2c9c 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2003 Sistina Software Limited.
* Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
@@ -27,9 +28,11 @@
#include <linux/atomic.h>
#include <linux/blk-mq.h>
+static struct workqueue_struct *dm_mpath_wq;
+
#define DM_MSG_PREFIX "multipath"
#define DM_PG_INIT_DELAY_MSECS 2000
-#define DM_PG_INIT_DELAY_DEFAULT ((unsigned) -1)
+#define DM_PG_INIT_DELAY_DEFAULT ((unsigned int) -1)
#define QUEUE_IF_NO_PATH_TIMEOUT_DEFAULT 0
static unsigned long queue_if_no_path_timeout_secs = QUEUE_IF_NO_PATH_TIMEOUT_DEFAULT;
@@ -39,7 +42,7 @@ struct pgpath {
struct list_head list;
struct priority_group *pg; /* Owning PG */
- unsigned fail_count; /* Cumulative failure count */
+ unsigned int fail_count; /* Cumulative failure count */
struct dm_path path;
struct delayed_work activate_path;
@@ -59,8 +62,8 @@ struct priority_group {
struct multipath *m; /* Owning multipath instance */
struct path_selector ps;
- unsigned pg_num; /* Reference number */
- unsigned nr_pgpaths; /* Number of paths in PG */
+ unsigned int pg_num; /* Reference number */
+ unsigned int nr_pgpaths; /* Number of paths in PG */
struct list_head pgpaths;
bool bypassed:1; /* Temporarily bypass this PG? */
@@ -78,14 +81,14 @@ struct multipath {
struct priority_group *next_pg; /* Switch to this PG if set */
atomic_t nr_valid_paths; /* Total number of usable paths */
- unsigned nr_priority_groups;
+ unsigned int nr_priority_groups;
struct list_head priority_groups;
const char *hw_handler_name;
char *hw_handler_params;
wait_queue_head_t pg_init_wait; /* Wait for pg_init completion */
- unsigned pg_init_retries; /* Number of times to retry pg_init */
- unsigned pg_init_delay_msecs; /* Number of msecs before pg_init retry */
+ unsigned int pg_init_retries; /* Number of times to retry pg_init */
+ unsigned int pg_init_delay_msecs; /* Number of msecs before pg_init retry */
atomic_t pg_init_in_progress; /* Only one pg_init allowed at once */
atomic_t pg_init_count; /* Number of times pg_init called */
@@ -117,10 +120,11 @@ static void activate_path_work(struct work_struct *work);
static void process_queued_bios(struct work_struct *work);
static void queue_if_no_path_timeout_work(struct timer_list *t);
-/*-----------------------------------------------
+/*
+ *-----------------------------------------------
* Multipath state flags.
- *-----------------------------------------------*/
-
+ *-----------------------------------------------
+ */
#define MPATHF_QUEUE_IO 0 /* Must we queue all I/O? */
#define MPATHF_QUEUE_IF_NO_PATH 1 /* Queue I/O if last path fails? */
#define MPATHF_SAVED_QUEUE_IF_NO_PATH 2 /* Saved state during suspension */
@@ -135,6 +139,7 @@ static bool mpath_double_check_test_bit(int MPATHF_bit, struct multipath *m)
if (r) {
unsigned long flags;
+
spin_lock_irqsave(&m->lock, flags);
r = test_bit(MPATHF_bit, &m->flags);
spin_unlock_irqrestore(&m->lock, flags);
@@ -143,10 +148,11 @@ static bool mpath_double_check_test_bit(int MPATHF_bit, struct multipath *m)
return r;
}
-/*-----------------------------------------------
+/*
+ *-----------------------------------------------
* Allocation routines
- *-----------------------------------------------*/
-
+ *-----------------------------------------------
+ */
static struct pgpath *alloc_pgpath(void)
{
struct pgpath *pgpath = kzalloc(sizeof(*pgpath), GFP_KERNEL);
@@ -302,10 +308,11 @@ static void multipath_init_per_bio_data(struct bio *bio, struct dm_mpath_io **mp
dm_bio_record(bio_details, bio);
}
-/*-----------------------------------------------
+/*
+ *-----------------------------------------------
* Path selection
- *-----------------------------------------------*/
-
+ *-----------------------------------------------
+ */
static int __pg_init_all_paths(struct multipath *m)
{
struct pgpath *pgpath;
@@ -397,7 +404,7 @@ static struct pgpath *choose_pgpath(struct multipath *m, size_t nr_bytes)
unsigned long flags;
struct priority_group *pg;
struct pgpath *pgpath;
- unsigned bypassed = 1;
+ unsigned int bypassed = 1;
if (!atomic_read(&m->nr_valid_paths)) {
spin_lock_irqsave(&m->lock, flags);
@@ -467,13 +474,11 @@ failed:
* it has been invoked.
*/
#define dm_report_EIO(m) \
-do { \
DMDEBUG_LIMIT("%s: returning EIO; QIFNP = %d; SQIFNP = %d; DNFS = %d", \
dm_table_device_name((m)->ti->table), \
test_bit(MPATHF_QUEUE_IF_NO_PATH, &(m)->flags), \
test_bit(MPATHF_SAVED_QUEUE_IF_NO_PATH, &(m)->flags), \
- dm_noflush_suspending((m)->ti)); \
-} while (0)
+ dm_noflush_suspending((m)->ti))
/*
* Check whether bios must be queued in the device-mapper core rather
@@ -707,6 +712,7 @@ static void process_queued_bios(struct work_struct *work)
blk_start_plug(&plug);
while ((bio = bio_list_pop(&bios))) {
struct dm_mpath_io *mpio = get_mpio_from_bio(bio);
+
dm_bio_restore(get_bio_details_from_mpio(mpio), bio);
r = __multipath_map_bio(m, bio, mpio);
switch (r) {
@@ -733,15 +739,15 @@ static void process_queued_bios(struct work_struct *work)
/*
* If we run out of usable paths, should we queue I/O or error it?
*/
-static int queue_if_no_path(struct multipath *m, bool queue_if_no_path,
+static int queue_if_no_path(struct multipath *m, bool f_queue_if_no_path,
bool save_old_value, const char *caller)
{
unsigned long flags;
bool queue_if_no_path_bit, saved_queue_if_no_path_bit;
const char *dm_dev_name = dm_table_device_name(m->ti->table);
- DMDEBUG("%s: %s caller=%s queue_if_no_path=%d save_old_value=%d",
- dm_dev_name, __func__, caller, queue_if_no_path, save_old_value);
+ DMDEBUG("%s: %s caller=%s f_queue_if_no_path=%d save_old_value=%d",
+ dm_dev_name, __func__, caller, f_queue_if_no_path, save_old_value);
spin_lock_irqsave(&m->lock, flags);
@@ -754,11 +760,11 @@ static int queue_if_no_path(struct multipath *m, bool queue_if_no_path,
dm_dev_name);
} else
assign_bit(MPATHF_SAVED_QUEUE_IF_NO_PATH, &m->flags, queue_if_no_path_bit);
- } else if (!queue_if_no_path && saved_queue_if_no_path_bit) {
+ } else if (!f_queue_if_no_path && saved_queue_if_no_path_bit) {
/* due to "fail_if_no_path" message, need to honor it. */
clear_bit(MPATHF_SAVED_QUEUE_IF_NO_PATH, &m->flags);
}
- assign_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags, queue_if_no_path);
+ assign_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags, f_queue_if_no_path);
DMDEBUG("%s: after %s changes; QIFNP = %d; SQIFNP = %d; DNFS = %d",
dm_dev_name, __func__,
@@ -768,7 +774,7 @@ static int queue_if_no_path(struct multipath *m, bool queue_if_no_path,
spin_unlock_irqrestore(&m->lock, flags);
- if (!queue_if_no_path) {
+ if (!f_queue_if_no_path) {
dm_table_run_md_queue_async(m->ti->table);
process_queued_io_list(m);
}
@@ -825,7 +831,8 @@ static void trigger_event(struct work_struct *work)
dm_table_event(m->ti->table);
}
-/*-----------------------------------------------------------------
+/*
+ *---------------------------------------------------------------
* Constructor/argument parsing:
* <#multipath feature args> [<arg>]*
* <#hw_handler args> [hw_handler [<arg>]*]
@@ -834,13 +841,14 @@ static void trigger_event(struct work_struct *work)
* [<selector> <#selector args> [<arg>]*
* <#paths> <#per-path selector args>
* [<path> [<arg>]* ]+ ]+
- *---------------------------------------------------------------*/
+ *---------------------------------------------------------------
+ */
static int parse_path_selector(struct dm_arg_set *as, struct priority_group *pg,
struct dm_target *ti)
{
int r;
struct path_selector_type *pst;
- unsigned ps_argc;
+ unsigned int ps_argc;
static const struct dm_arg _args[] = {
{0, 1024, "invalid number of path selector args"},
@@ -983,7 +991,7 @@ static struct priority_group *parse_priority_group(struct dm_arg_set *as,
};
int r;
- unsigned i, nr_selector_args, nr_args;
+ unsigned int i, nr_selector_args, nr_args;
struct priority_group *pg;
struct dm_target *ti = m->ti;
@@ -1049,7 +1057,7 @@ static struct priority_group *parse_priority_group(struct dm_arg_set *as,
static int parse_hw_handler(struct dm_arg_set *as, struct multipath *m)
{
- unsigned hw_argc;
+ unsigned int hw_argc;
int ret;
struct dm_target *ti = m->ti;
@@ -1086,7 +1094,7 @@ static int parse_hw_handler(struct dm_arg_set *as, struct multipath *m)
goto fail;
}
j = sprintf(p, "%d", hw_argc - 1);
- for (i = 0, p+=j+1; i <= hw_argc - 2; i++, p+=j+1)
+ for (i = 0, p += j + 1; i <= hw_argc - 2; i++, p += j + 1)
j = sprintf(p, "%s", as->argv[i]);
}
dm_consume_args(as, hw_argc - 1);
@@ -1101,7 +1109,7 @@ fail:
static int parse_features(struct dm_arg_set *as, struct multipath *m)
{
int r;
- unsigned argc;
+ unsigned int argc;
struct dm_target *ti = m->ti;
const char *arg_name;
@@ -1170,7 +1178,7 @@ static int parse_features(struct dm_arg_set *as, struct multipath *m)
return r;
}
-static int multipath_ctr(struct dm_target *ti, unsigned argc, char **argv)
+static int multipath_ctr(struct dm_target *ti, unsigned int argc, char **argv)
{
/* target arguments */
static const struct dm_arg _args[] = {
@@ -1181,8 +1189,8 @@ static int multipath_ctr(struct dm_target *ti, unsigned argc, char **argv)
int r;
struct multipath *m;
struct dm_arg_set as;
- unsigned pg_count = 0;
- unsigned next_pg_num;
+ unsigned int pg_count = 0;
+ unsigned int next_pg_num;
unsigned long flags;
as.argc = argc;
@@ -1224,7 +1232,7 @@ static int multipath_ctr(struct dm_target *ti, unsigned argc, char **argv)
/* parse the priority groups */
while (as.argc) {
struct priority_group *pg;
- unsigned nr_valid_paths = atomic_read(&m->nr_valid_paths);
+ unsigned int nr_valid_paths = atomic_read(&m->nr_valid_paths);
pg = parse_priority_group(&as, m);
if (IS_ERR(pg)) {
@@ -1347,7 +1355,7 @@ static int fail_path(struct pgpath *pgpath)
dm_path_uevent(DM_UEVENT_PATH_FAILED, m->ti,
pgpath->path.dev->name, atomic_read(&m->nr_valid_paths));
- schedule_work(&m->trigger_event);
+ queue_work(dm_mpath_wq, &m->trigger_event);
enable_nopath_timeout(m);
@@ -1365,7 +1373,7 @@ static int reinstate_path(struct pgpath *pgpath)
int r = 0, run_queue = 0;
unsigned long flags;
struct multipath *m = pgpath->pg->m;
- unsigned nr_valid_paths;
+ unsigned int nr_valid_paths;
spin_lock_irqsave(&m->lock, flags);
@@ -1454,13 +1462,13 @@ static void bypass_pg(struct multipath *m, struct priority_group *pg,
static int switch_pg_num(struct multipath *m, const char *pgstr)
{
struct priority_group *pg;
- unsigned pgnum;
+ unsigned int pgnum;
unsigned long flags;
char dummy;
if (!pgstr || (sscanf(pgstr, "%u%c", &pgnum, &dummy) != 1) || !pgnum ||
!m->nr_priority_groups || (pgnum > m->nr_priority_groups)) {
- DMWARN("invalid PG number supplied to switch_pg_num");
+ DMWARN("invalid PG number supplied to %s", __func__);
return -EINVAL;
}
@@ -1487,7 +1495,7 @@ static int switch_pg_num(struct multipath *m, const char *pgstr)
static int bypass_pg_num(struct multipath *m, const char *pgstr, bool bypassed)
{
struct priority_group *pg;
- unsigned pgnum;
+ unsigned int pgnum;
char dummy;
if (!pgstr || (sscanf(pgstr, "%u%c", &pgnum, &dummy) != 1) || !pgnum ||
@@ -1789,14 +1797,14 @@ static void multipath_resume(struct dm_target *ti)
* num_paths num_selector_args [path_dev [selector_args]* ]+ ]+
*/
static void multipath_status(struct dm_target *ti, status_type_t type,
- unsigned status_flags, char *result, unsigned maxlen)
+ unsigned int status_flags, char *result, unsigned int maxlen)
{
int sz = 0, pg_counter, pgpath_counter;
unsigned long flags;
struct multipath *m = ti->private;
struct priority_group *pg;
struct pgpath *p;
- unsigned pg_num;
+ unsigned int pg_num;
char state;
spin_lock_irqsave(&m->lock, flags);
@@ -1821,7 +1829,7 @@ static void multipath_status(struct dm_target *ti, status_type_t type,
if (test_bit(MPATHF_RETAIN_ATTACHED_HW_HANDLER, &m->flags))
DMEMIT("retain_attached_hw_handler ");
if (m->queue_mode != DM_TYPE_REQUEST_BASED) {
- switch(m->queue_mode) {
+ switch (m->queue_mode) {
case DM_TYPE_BIO_BASED:
DMEMIT("queue_mode bio ");
break;
@@ -1948,8 +1956,8 @@ static void multipath_status(struct dm_target *ti, status_type_t type,
spin_unlock_irqrestore(&m->lock, flags);
}
-static int multipath_message(struct dm_target *ti, unsigned argc, char **argv,
- char *result, unsigned maxlen)
+static int multipath_message(struct dm_target *ti, unsigned int argc, char **argv,
+ char *result, unsigned int maxlen)
{
int r = -EINVAL;
struct dm_dev *dev;
@@ -2116,6 +2124,7 @@ static int multipath_busy(struct dm_target *ti)
/* no paths available, for blk-mq: rely on IO mapping to delay requeue */
if (!atomic_read(&m->nr_valid_paths)) {
unsigned long flags;
+
spin_lock_irqsave(&m->lock, flags);
if (test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags)) {
spin_unlock_irqrestore(&m->lock, flags);
@@ -2168,9 +2177,11 @@ static int multipath_busy(struct dm_target *ti)
return busy;
}
-/*-----------------------------------------------------------------
+/*
+ *---------------------------------------------------------------
* Module setup
- *---------------------------------------------------------------*/
+ *---------------------------------------------------------------
+ */
static struct target_type multipath_target = {
.name = "multipath",
.version = {1, 14, 0},
@@ -2196,12 +2207,11 @@ static struct target_type multipath_target = {
static int __init dm_multipath_init(void)
{
- int r;
+ int r = -ENOMEM;
kmultipathd = alloc_workqueue("kmpathd", WQ_MEM_RECLAIM, 0);
if (!kmultipathd) {
DMERR("failed to create workqueue kmpathd");
- r = -ENOMEM;
goto bad_alloc_kmultipathd;
}
@@ -2215,10 +2225,15 @@ static int __init dm_multipath_init(void)
WQ_MEM_RECLAIM);
if (!kmpath_handlerd) {
DMERR("failed to create workqueue kmpath_handlerd");
- r = -ENOMEM;
goto bad_alloc_kmpath_handlerd;
}
+ dm_mpath_wq = alloc_workqueue("dm_mpath_wq", 0, 0);
+ if (!dm_mpath_wq) {
+ DMERR("failed to create workqueue dm_mpath_wq");
+ goto bad_alloc_dm_mpath_wq;
+ }
+
r = dm_register_target(&multipath_target);
if (r < 0) {
DMERR("request-based register failed %d", r);
@@ -2229,6 +2244,8 @@ static int __init dm_multipath_init(void)
return 0;
bad_register_target:
+ destroy_workqueue(dm_mpath_wq);
+bad_alloc_dm_mpath_wq:
destroy_workqueue(kmpath_handlerd);
bad_alloc_kmpath_handlerd:
destroy_workqueue(kmultipathd);
@@ -2238,6 +2255,7 @@ bad_alloc_kmultipathd:
static void __exit dm_multipath_exit(void)
{
+ destroy_workqueue(dm_mpath_wq);
destroy_workqueue(kmpath_handlerd);
destroy_workqueue(kmultipathd);
@@ -2247,8 +2265,7 @@ static void __exit dm_multipath_exit(void)
module_init(dm_multipath_init);
module_exit(dm_multipath_exit);
-module_param_named(queue_if_no_path_timeout_secs,
- queue_if_no_path_timeout_secs, ulong, S_IRUGO | S_IWUSR);
+module_param_named(queue_if_no_path_timeout_secs, queue_if_no_path_timeout_secs, ulong, 0644);
MODULE_PARM_DESC(queue_if_no_path_timeout_secs, "No available paths queue IO timeout in seconds");
MODULE_DESCRIPTION(DM_NAME " multipath target");
diff --git a/drivers/md/dm-mpath.h b/drivers/md/dm-mpath.h
index e230f7196259..0e168e0c82dd 100644
--- a/drivers/md/dm-mpath.h
+++ b/drivers/md/dm-mpath.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
@@ -17,6 +18,6 @@ struct dm_path {
};
/* Callback for hwh_pg_init_fn to use when complete */
-void dm_pg_init_complete(struct dm_path *path, unsigned err_flags);
+void dm_pg_init_complete(struct dm_path *path, unsigned int err_flags);
#endif
diff --git a/drivers/md/dm-path-selector.c b/drivers/md/dm-path-selector.c
index fa0ccc585cb4..3e4cb81ce512 100644
--- a/drivers/md/dm-path-selector.c
+++ b/drivers/md/dm-path-selector.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2003 Sistina Software.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
@@ -114,6 +115,7 @@ int dm_register_path_selector(struct path_selector_type *pst)
return r;
}
+EXPORT_SYMBOL_GPL(dm_register_path_selector);
int dm_unregister_path_selector(struct path_selector_type *pst)
{
@@ -135,6 +137,4 @@ int dm_unregister_path_selector(struct path_selector_type *pst)
return 0;
}
-
-EXPORT_SYMBOL_GPL(dm_register_path_selector);
EXPORT_SYMBOL_GPL(dm_unregister_path_selector);
diff --git a/drivers/md/dm-path-selector.h b/drivers/md/dm-path-selector.h
index 83cac2b04b66..3861b2d8b963 100644
--- a/drivers/md/dm-path-selector.h
+++ b/drivers/md/dm-path-selector.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2003 Sistina Software.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
@@ -52,44 +53,43 @@ struct path_selector_type {
/*
* Constructs a path selector object, takes custom arguments
*/
- int (*create) (struct path_selector *ps, unsigned argc, char **argv);
- void (*destroy) (struct path_selector *ps);
+ int (*create)(struct path_selector *ps, unsigned int argc, char **argv);
+ void (*destroy)(struct path_selector *ps);
/*
* Add an opaque path object, along with some selector specific
* path args (eg, path priority).
*/
- int (*add_path) (struct path_selector *ps, struct dm_path *path,
- int argc, char **argv, char **error);
+ int (*add_path)(struct path_selector *ps, struct dm_path *path,
+ int argc, char **argv, char **error);
/*
* Chooses a path for this io, if no paths are available then
* NULL will be returned.
*/
- struct dm_path *(*select_path) (struct path_selector *ps,
- size_t nr_bytes);
+ struct dm_path *(*select_path)(struct path_selector *ps, size_t nr_bytes);
/*
* Notify the selector that a path has failed.
*/
- void (*fail_path) (struct path_selector *ps, struct dm_path *p);
+ void (*fail_path)(struct path_selector *ps, struct dm_path *p);
/*
* Ask selector to reinstate a path.
*/
- int (*reinstate_path) (struct path_selector *ps, struct dm_path *p);
+ int (*reinstate_path)(struct path_selector *ps, struct dm_path *p);
/*
* Table content based on parameters added in ps_add_path_fn
* or path selector status
*/
- int (*status) (struct path_selector *ps, struct dm_path *path,
- status_type_t type, char *result, unsigned int maxlen);
+ int (*status)(struct path_selector *ps, struct dm_path *path,
+ status_type_t type, char *result, unsigned int maxlen);
- int (*start_io) (struct path_selector *ps, struct dm_path *path,
- size_t nr_bytes);
- int (*end_io) (struct path_selector *ps, struct dm_path *path,
- size_t nr_bytes, u64 start_time);
+ int (*start_io)(struct path_selector *ps, struct dm_path *path,
+ size_t nr_bytes);
+ int (*end_io)(struct path_selector *ps, struct dm_path *path,
+ size_t nr_bytes, u64 start_time);
};
/* Register a path selector */
diff --git a/drivers/md/dm-ps-historical-service-time.c b/drivers/md/dm-ps-historical-service-time.c
index 1d82c95d323d..b49e10d76d03 100644
--- a/drivers/md/dm-ps-historical-service-time.c
+++ b/drivers/md/dm-ps-historical-service-time.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Historical Service Time
*
diff --git a/drivers/md/dm-ps-io-affinity.c b/drivers/md/dm-ps-io-affinity.c
index f74501e65a8e..461ee6b2044d 100644
--- a/drivers/md/dm-ps-io-affinity.c
+++ b/drivers/md/dm-ps-io-affinity.c
@@ -108,7 +108,7 @@ free_pi:
return ret;
}
-static int ioa_create(struct path_selector *ps, unsigned argc, char **argv)
+static int ioa_create(struct path_selector *ps, unsigned int argc, char **argv)
{
struct selector *s;
@@ -138,7 +138,7 @@ free_selector:
static void ioa_destroy(struct path_selector *ps)
{
struct selector *s = ps->context;
- unsigned cpu;
+ unsigned int cpu;
for_each_cpu(cpu, s->path_mask)
ioa_free_path(s, cpu);
@@ -162,7 +162,7 @@ static int ioa_status(struct path_selector *ps, struct dm_path *path,
return sz;
}
- switch(type) {
+ switch (type) {
case STATUSTYPE_INFO:
DMEMIT("%d ", atomic_read(&s->map_misses));
break;
diff --git a/drivers/md/dm-ps-queue-length.c b/drivers/md/dm-ps-queue-length.c
index cef70657bbbc..e305f05ad1e5 100644
--- a/drivers/md/dm-ps-queue-length.c
+++ b/drivers/md/dm-ps-queue-length.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2004-2005 IBM Corp. All Rights Reserved.
* Copyright (C) 2006-2009 NEC Corporation.
@@ -35,7 +36,7 @@ struct selector {
struct path_info {
struct list_head list;
struct dm_path *path;
- unsigned repeat_count;
+ unsigned int repeat_count;
atomic_t qlen; /* the number of in-flight I/Os */
};
@@ -52,7 +53,7 @@ static struct selector *alloc_selector(void)
return s;
}
-static int ql_create(struct path_selector *ps, unsigned argc, char **argv)
+static int ql_create(struct path_selector *ps, unsigned int argc, char **argv)
{
struct selector *s = alloc_selector();
@@ -84,9 +85,9 @@ static void ql_destroy(struct path_selector *ps)
}
static int ql_status(struct path_selector *ps, struct dm_path *path,
- status_type_t type, char *result, unsigned maxlen)
+ status_type_t type, char *result, unsigned int maxlen)
{
- unsigned sz = 0;
+ unsigned int sz = 0;
struct path_info *pi;
/* When called with NULL path, return selector status/args. */
@@ -116,14 +117,14 @@ static int ql_add_path(struct path_selector *ps, struct dm_path *path,
{
struct selector *s = ps->context;
struct path_info *pi;
- unsigned repeat_count = QL_MIN_IO;
+ unsigned int repeat_count = QL_MIN_IO;
char dummy;
unsigned long flags;
/*
* Arguments: [<repeat_count>]
- * <repeat_count>: The number of I/Os before switching path.
- * If not given, default (QL_MIN_IO) is used.
+ * <repeat_count>: The number of I/Os before switching path.
+ * If not given, default (QL_MIN_IO) is used.
*/
if (argc > 1) {
*error = "queue-length ps: incorrect number of arguments";
diff --git a/drivers/md/dm-ps-round-robin.c b/drivers/md/dm-ps-round-robin.c
index 27f44c5fa04e..0f04b673597a 100644
--- a/drivers/md/dm-ps-round-robin.c
+++ b/drivers/md/dm-ps-round-robin.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2003 Sistina Software.
* Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
@@ -20,13 +21,15 @@
#define RR_MIN_IO 1
#define RR_VERSION "1.2.0"
-/*-----------------------------------------------------------------
+/*
+ *---------------------------------------------------------------
* Path-handling code, paths are held in lists
- *---------------------------------------------------------------*/
+ *---------------------------------------------------------------
+ */
struct path_info {
struct list_head list;
struct dm_path *path;
- unsigned repeat_count;
+ unsigned int repeat_count;
};
static void free_paths(struct list_head *paths)
@@ -39,10 +42,11 @@ static void free_paths(struct list_head *paths)
}
}
-/*-----------------------------------------------------------------
+/*
+ *---------------------------------------------------------------
* Round-robin selector
- *---------------------------------------------------------------*/
-
+ *---------------------------------------------------------------
+ */
struct selector {
struct list_head valid_paths;
struct list_head invalid_paths;
@@ -62,7 +66,7 @@ static struct selector *alloc_selector(void)
return s;
}
-static int rr_create(struct path_selector *ps, unsigned argc, char **argv)
+static int rr_create(struct path_selector *ps, unsigned int argc, char **argv)
{
struct selector *s;
@@ -93,7 +97,7 @@ static int rr_status(struct path_selector *ps, struct dm_path *path,
if (!path)
DMEMIT("0 ");
else {
- switch(type) {
+ switch (type) {
case STATUSTYPE_INFO:
break;
case STATUSTYPE_TABLE:
@@ -119,7 +123,7 @@ static int rr_add_path(struct path_selector *ps, struct dm_path *path,
{
struct selector *s = ps->context;
struct path_info *pi;
- unsigned repeat_count = RR_MIN_IO;
+ unsigned int repeat_count = RR_MIN_IO;
char dummy;
unsigned long flags;
diff --git a/drivers/md/dm-ps-service-time.c b/drivers/md/dm-ps-service-time.c
index 3ec9c33265c5..969d31c40272 100644
--- a/drivers/md/dm-ps-service-time.c
+++ b/drivers/md/dm-ps-service-time.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2007-2009 NEC Corporation. All Rights Reserved.
*
@@ -30,8 +31,8 @@ struct selector {
struct path_info {
struct list_head list;
struct dm_path *path;
- unsigned repeat_count;
- unsigned relative_throughput;
+ unsigned int repeat_count;
+ unsigned int relative_throughput;
atomic_t in_flight_size; /* Total size of in-flight I/Os */
};
@@ -48,7 +49,7 @@ static struct selector *alloc_selector(void)
return s;
}
-static int st_create(struct path_selector *ps, unsigned argc, char **argv)
+static int st_create(struct path_selector *ps, unsigned int argc, char **argv)
{
struct selector *s = alloc_selector();
@@ -80,9 +81,9 @@ static void st_destroy(struct path_selector *ps)
}
static int st_status(struct path_selector *ps, struct dm_path *path,
- status_type_t type, char *result, unsigned maxlen)
+ status_type_t type, char *result, unsigned int maxlen)
{
- unsigned sz = 0;
+ unsigned int sz = 0;
struct path_info *pi;
if (!path)
@@ -113,22 +114,21 @@ static int st_add_path(struct path_selector *ps, struct dm_path *path,
{
struct selector *s = ps->context;
struct path_info *pi;
- unsigned repeat_count = ST_MIN_IO;
- unsigned relative_throughput = 1;
+ unsigned int repeat_count = ST_MIN_IO;
+ unsigned int relative_throughput = 1;
char dummy;
unsigned long flags;
/*
* Arguments: [<repeat_count> [<relative_throughput>]]
- * <repeat_count>: The number of I/Os before switching path.
- * If not given, default (ST_MIN_IO) is used.
- * <relative_throughput>: The relative throughput value of
+ * <repeat_count>: The number of I/Os before switching path.
+ * If not given, default (ST_MIN_IO) is used.
+ * <relative_throughput>: The relative throughput value of
* the path among all paths in the path-group.
- * The valid range: 0-<ST_MAX_RELATIVE_THROUGHPUT>
+ * The valid range: 0-<ST_MAX_RELATIVE_THROUGHPUT>
* If not given, minimum value '1' is used.
* If '0' is given, the path isn't selected while
- * other paths having a positive value are
- * available.
+ * other paths having a positive value are available.
*/
if (argc > 2) {
*error = "service-time ps: incorrect number of arguments";
diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c
index 54263679a7b1..60632b409b80 100644
--- a/drivers/md/dm-raid.c
+++ b/drivers/md/dm-raid.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2010-2011 Neil Brown
* Copyright (C) 2010-2018 Red Hat, Inc. All rights reserved.
@@ -29,10 +30,10 @@
*/
#define MIN_RAID456_JOURNAL_SPACE (4*2048)
-static bool devices_handle_discard_safely = false;
+static bool devices_handle_discard_safely;
/*
- * The following flags are used by dm-raid.c to set up the array state.
+ * The following flags are used by dm-raid to set up the array state.
* They must be cleared before md_run is called.
*/
#define FirstUse 10 /* rdev flag */
@@ -362,8 +363,8 @@ static struct {
const int mode;
const char *param;
} _raid456_journal_mode[] = {
- { R5C_JOURNAL_MODE_WRITE_THROUGH , "writethrough" },
- { R5C_JOURNAL_MODE_WRITE_BACK , "writeback" }
+ { R5C_JOURNAL_MODE_WRITE_THROUGH, "writethrough" },
+ { R5C_JOURNAL_MODE_WRITE_BACK, "writeback" }
};
/* Return MD raid4/5/6 journal mode for dm @journal_mode one */
@@ -1081,7 +1082,7 @@ static int validate_raid_redundancy(struct raid_set *rs)
if ((!rs->dev[i].rdev.sb_page ||
!test_bit(In_sync, &rs->dev[i].rdev.flags)) &&
(++rebuilds_per_group >= copies))
- goto too_many;
+ goto too_many;
}
break;
default:
@@ -1114,7 +1115,7 @@ too_many:
* [stripe_cache <sectors>] Stripe cache size for higher RAIDs
* [region_size <sectors>] Defines granularity of bitmap
* [journal_dev <dev>] raid4/5/6 journaling deviice
- * (i.e. write hole closing log)
+ * (i.e. write hole closing log)
*
* RAID10-only options:
* [raid10_copies <# copies>] Number of copies. (Default: 2)
@@ -1988,7 +1989,7 @@ struct dm_raid_superblock {
__le64 sectors; /* Used device size in sectors */
/*
- * Additonal Bit field of devices indicating failures to support
+ * Additional Bit field of devices indicating failures to support
* up to 256 devices with the 1.9.0 on-disk metadata format
*/
__le64 extended_failed_devices[DISKS_ARRAY_ELEMS - 1];
@@ -2855,7 +2856,7 @@ static int rs_setup_reshape(struct raid_set *rs)
*
* - in case of adding disk(s), array size has
* to grow after the disk adding reshape,
- * which'll hapen in the event handler;
+ * which'll happen in the event handler;
* reshape will happen forward, so space has to
* be available at the beginning of each disk
*
@@ -3148,7 +3149,7 @@ static int raid_ctr(struct dm_target *ti, unsigned int argc, char **argv)
* If a takeover is needed, userspace sets any additional
* devices to rebuild and we can check for a valid request here.
*
- * If acceptible, set the level to the new requested
+ * If acceptable, set the level to the new requested
* one, prohibit requesting recovery, allow the raid
* set to run and store superblocks during resume.
*/
@@ -3183,12 +3184,12 @@ static int raid_ctr(struct dm_target *ti, unsigned int argc, char **argv)
/* Out-of-place space has to be available to allow for a reshape unless raid1! */
if (reshape_sectors || rs_is_raid1(rs)) {
/*
- * We can only prepare for a reshape here, because the
- * raid set needs to run to provide the repective reshape
- * check functions via its MD personality instance.
- *
- * So do the reshape check after md_run() succeeded.
- */
+ * We can only prepare for a reshape here, because the
+ * raid set needs to run to provide the repective reshape
+ * check functions via its MD personality instance.
+ *
+ * So do the reshape check after md_run() succeeded.
+ */
r = rs_prepare_reshape(rs);
if (r)
goto bad;
@@ -3712,7 +3713,7 @@ static void raid_status(struct dm_target *ti, status_type_t type,
}
static int raid_message(struct dm_target *ti, unsigned int argc, char **argv,
- char *result, unsigned maxlen)
+ char *result, unsigned int maxlen)
{
struct raid_set *rs = ti->private;
struct mddev *mddev = &rs->md;
@@ -4001,7 +4002,7 @@ static int raid_preresume(struct dm_target *ti)
}
/* Resize bitmap to adjust to changed region size (aka MD bitmap chunksize) or grown device size */
- if (test_bit(RT_FLAG_RS_BITMAP_LOADED, &rs->runtime_flags) && mddev->bitmap &&
+ if (test_bit(RT_FLAG_RS_BITMAP_LOADED, &rs->runtime_flags) && mddev->bitmap &&
(test_bit(RT_FLAG_RS_GROW, &rs->runtime_flags) ||
(rs->requested_bitmap_chunk_sectors &&
mddev->bitmap_info.chunksize != to_bytes(rs->requested_bitmap_chunk_sectors)))) {
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index 06a38dc32025..bc417a5e5b89 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2003 Sistina Software Limited.
* Copyright (C) 2005-2008 Red Hat, Inc. All rights reserved.
@@ -19,6 +20,8 @@
#include <linux/dm-kcopyd.h>
#include <linux/dm-region-hash.h>
+static struct workqueue_struct *dm_raid1_wq;
+
#define DM_MSG_PREFIX "raid1"
#define MAX_RECOVERY 1 /* Maximum number of regions recovered in parallel. */
@@ -32,9 +35,11 @@
static DECLARE_WAIT_QUEUE_HEAD(_kmirrord_recovery_stopped);
-/*-----------------------------------------------------------------
+/*
+ *---------------------------------------------------------------
* Mirror set structures.
- *---------------------------------------------------------------*/
+ *---------------------------------------------------------------
+ */
enum dm_raid1_error {
DM_RAID1_WRITE_ERROR,
DM_RAID1_FLUSH_ERROR,
@@ -82,7 +87,7 @@ struct mirror_set {
struct work_struct trigger_event;
- unsigned nr_mirrors;
+ unsigned int nr_mirrors;
struct mirror mirror[];
};
@@ -236,8 +241,8 @@ static void fail_mirror(struct mirror *m, enum dm_raid1_error error_type)
* Better to issue requests to same failing device
* than to risk returning corrupt data.
*/
- DMERR("Primary mirror (%s) failed while out-of-sync: "
- "Reads may fail.", m->dev->name);
+ DMERR("Primary mirror (%s) failed while out-of-sync: Reads may fail.",
+ m->dev->name);
goto out;
}
@@ -248,7 +253,7 @@ static void fail_mirror(struct mirror *m, enum dm_raid1_error error_type)
DMWARN("All sides of mirror have failed.");
out:
- schedule_work(&ms->trigger_event);
+ queue_work(dm_raid1_wq, &ms->trigger_event);
}
static int mirror_flush(struct dm_target *ti)
@@ -285,13 +290,15 @@ static int mirror_flush(struct dm_target *ti)
return 0;
}
-/*-----------------------------------------------------------------
+/*
+ *---------------------------------------------------------------
* Recovery.
*
* When a mirror is first activated we may find that some regions
* are in the no-sync state. We have to recover these by
* recopying from the default mirror to all the others.
- *---------------------------------------------------------------*/
+ *---------------------------------------------------------------
+ */
static void recovery_complete(int read_err, unsigned long write_err,
void *context)
{
@@ -327,7 +334,7 @@ static void recovery_complete(int read_err, unsigned long write_err,
static void recover(struct mirror_set *ms, struct dm_region *reg)
{
- unsigned i;
+ unsigned int i;
struct dm_io_region from, to[DM_KCOPYD_MAX_REGIONS], *dest;
struct mirror *m;
unsigned long flags = 0;
@@ -408,9 +415,11 @@ static void do_recovery(struct mirror_set *ms)
}
}
-/*-----------------------------------------------------------------
+/*
+ *---------------------------------------------------------------
* Reads
- *---------------------------------------------------------------*/
+ *---------------------------------------------------------------
+ */
static struct mirror *choose_mirror(struct mirror_set *ms, sector_t sector)
{
struct mirror *m = get_default_mirror(ms);
@@ -498,9 +507,11 @@ static void hold_bio(struct mirror_set *ms, struct bio *bio)
spin_unlock_irq(&ms->lock);
}
-/*-----------------------------------------------------------------
+/*
+ *---------------------------------------------------------------
* Reads
- *---------------------------------------------------------------*/
+ *---------------------------------------------------------------
+ */
static void read_callback(unsigned long error, void *context)
{
struct bio *bio = context;
@@ -517,8 +528,7 @@ static void read_callback(unsigned long error, void *context)
fail_mirror(m, DM_RAID1_READ_ERROR);
if (likely(default_ok(m)) || mirror_available(m->ms, bio)) {
- DMWARN_LIMIT("Read failure on mirror device %s. "
- "Trying alternative device.",
+ DMWARN_LIMIT("Read failure on mirror device %s. Trying alternative device.",
m->dev->name);
queue_bio(m->ms, bio, bio_data_dir(bio));
return;
@@ -579,21 +589,21 @@ static void do_reads(struct mirror_set *ms, struct bio_list *reads)
}
}
-/*-----------------------------------------------------------------
+/*
+ *---------------------------------------------------------------------
* Writes.
*
* We do different things with the write io depending on the
* state of the region that it's in:
*
- * SYNC: increment pending, use kcopyd to write to *all* mirrors
+ * SYNC: increment pending, use kcopyd to write to *all* mirrors
* RECOVERING: delay the io until recovery completes
* NOSYNC: increment pending, just write to the default mirror
- *---------------------------------------------------------------*/
-
-
+ *---------------------------------------------------------------------
+ */
static void write_callback(unsigned long error, void *context)
{
- unsigned i;
+ unsigned int i;
struct bio *bio = (struct bio *) context;
struct mirror_set *ms;
int should_wake = 0;
@@ -842,9 +852,11 @@ static void trigger_event(struct work_struct *work)
dm_table_event(ms->ti->table);
}
-/*-----------------------------------------------------------------
+/*
+ *---------------------------------------------------------------
* kmirrord
- *---------------------------------------------------------------*/
+ *---------------------------------------------------------------
+ */
static void do_mirror(struct work_struct *work)
{
struct mirror_set *ms = container_of(work, struct mirror_set,
@@ -868,9 +880,11 @@ static void do_mirror(struct work_struct *work)
do_failures(ms, &failures);
}
-/*-----------------------------------------------------------------
+/*
+ *---------------------------------------------------------------
* Target functions
- *---------------------------------------------------------------*/
+ *---------------------------------------------------------------
+ */
static struct mirror_set *alloc_context(unsigned int nr_mirrors,
uint32_t region_size,
struct dm_target *ti,
@@ -903,7 +917,7 @@ static struct mirror_set *alloc_context(unsigned int nr_mirrors,
if (IS_ERR(ms->io_client)) {
ti->error = "Error creating dm_io client";
kfree(ms);
- return NULL;
+ return NULL;
}
ms->rh = dm_region_hash_create(ms, dispatch_bios, wakeup_mirrord,
@@ -963,10 +977,10 @@ static int get_mirror(struct mirror_set *ms, struct dm_target *ti,
* Create dirty log: log_type #log_params <log_params>
*/
static struct dm_dirty_log *create_dirty_log(struct dm_target *ti,
- unsigned argc, char **argv,
- unsigned *args_used)
+ unsigned int argc, char **argv,
+ unsigned int *args_used)
{
- unsigned param_count;
+ unsigned int param_count;
struct dm_dirty_log *dl;
char dummy;
@@ -997,10 +1011,10 @@ static struct dm_dirty_log *create_dirty_log(struct dm_target *ti,
return dl;
}
-static int parse_features(struct mirror_set *ms, unsigned argc, char **argv,
- unsigned *args_used)
+static int parse_features(struct mirror_set *ms, unsigned int argc, char **argv,
+ unsigned int *args_used)
{
- unsigned num_features;
+ unsigned int num_features;
struct dm_target *ti = ms->ti;
char dummy;
int i;
@@ -1389,7 +1403,7 @@ static char device_status_char(struct mirror *m)
static void mirror_status(struct dm_target *ti, status_type_t type,
- unsigned status_flags, char *result, unsigned maxlen)
+ unsigned int status_flags, char *result, unsigned int maxlen)
{
unsigned int m, sz = 0;
int num_feature_args = 0;
@@ -1458,7 +1472,7 @@ static int mirror_iterate_devices(struct dm_target *ti,
{
struct mirror_set *ms = ti->private;
int ret = 0;
- unsigned i;
+ unsigned int i;
for (i = 0; !ret && i < ms->nr_mirrors; i++)
ret = fn(ti, ms->mirror[i].dev,
@@ -1484,22 +1498,28 @@ static struct target_type mirror_target = {
static int __init dm_mirror_init(void)
{
- int r;
+ int r = -ENOMEM;
+
+ dm_raid1_wq = alloc_workqueue("dm_raid1_wq", 0, 0);
+ if (!dm_raid1_wq)
+ goto bad_target;
r = dm_register_target(&mirror_target);
if (r < 0) {
- DMERR("Failed to register mirror target");
+ destroy_workqueue(dm_raid1_wq);
goto bad_target;
}
return 0;
bad_target:
+ DMERR("Failed to register mirror target");
return r;
}
static void __exit dm_mirror_exit(void)
{
+ destroy_workqueue(dm_raid1_wq);
dm_unregister_target(&mirror_target);
}
diff --git a/drivers/md/dm-region-hash.c b/drivers/md/dm-region-hash.c
index 1f760451e6f4..852cfa37d48a 100644
--- a/drivers/md/dm-region-hash.c
+++ b/drivers/md/dm-region-hash.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2003 Sistina Software Limited.
* Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
@@ -18,7 +19,8 @@
#define DM_MSG_PREFIX "region hash"
-/*-----------------------------------------------------------------
+/*
+ *------------------------------------------------------------------
* Region hash
*
* The mirror splits itself up into discrete regions. Each
@@ -53,20 +55,21 @@
* lists in the region_hash, with the 'state', 'list' and
* 'delayed_bios' fields of the regions. This is used from irq
* context, so all other uses will have to suspend local irqs.
- *---------------------------------------------------------------*/
+ *------------------------------------------------------------------
+ */
struct dm_region_hash {
uint32_t region_size;
- unsigned region_shift;
+ unsigned int region_shift;
/* holds persistent region state */
struct dm_dirty_log *log;
/* hash table */
rwlock_t hash_lock;
- unsigned mask;
- unsigned nr_buckets;
- unsigned prime;
- unsigned shift;
+ unsigned int mask;
+ unsigned int nr_buckets;
+ unsigned int prime;
+ unsigned int shift;
struct list_head *buckets;
/*
@@ -74,7 +77,7 @@ struct dm_region_hash {
*/
int flush_failure;
- unsigned max_recovery; /* Max # of regions to recover in parallel */
+ unsigned int max_recovery; /* Max # of regions to recover in parallel */
spinlock_t region_lock;
atomic_t recovery_in_flight;
@@ -163,12 +166,12 @@ struct dm_region_hash *dm_region_hash_create(
struct bio_list *bios),
void (*wakeup_workers)(void *context),
void (*wakeup_all_recovery_waiters)(void *context),
- sector_t target_begin, unsigned max_recovery,
+ sector_t target_begin, unsigned int max_recovery,
struct dm_dirty_log *log, uint32_t region_size,
region_t nr_regions)
{
struct dm_region_hash *rh;
- unsigned nr_buckets, max_buckets;
+ unsigned int nr_buckets, max_buckets;
size_t i;
int ret;
@@ -236,7 +239,7 @@ EXPORT_SYMBOL_GPL(dm_region_hash_create);
void dm_region_hash_destroy(struct dm_region_hash *rh)
{
- unsigned h;
+ unsigned int h;
struct dm_region *reg, *nreg;
BUG_ON(!list_empty(&rh->quiesced_regions));
@@ -263,9 +266,9 @@ struct dm_dirty_log *dm_rh_dirty_log(struct dm_region_hash *rh)
}
EXPORT_SYMBOL_GPL(dm_rh_dirty_log);
-static unsigned rh_hash(struct dm_region_hash *rh, region_t region)
+static unsigned int rh_hash(struct dm_region_hash *rh, region_t region)
{
- return (unsigned) ((region * rh->prime) >> rh->shift) & rh->mask;
+ return (unsigned int) ((region * rh->prime) >> rh->shift) & rh->mask;
}
static struct dm_region *__rh_lookup(struct dm_region_hash *rh, region_t region)
diff --git a/drivers/md/dm-rq.c b/drivers/md/dm-rq.c
index a41209a43506..f7e9a3632eb3 100644
--- a/drivers/md/dm-rq.c
+++ b/drivers/md/dm-rq.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2016 Red Hat, Inc. All rights reserved.
*
@@ -23,33 +24,33 @@ struct dm_rq_target_io {
union map_info info;
struct dm_stats_aux stats_aux;
unsigned long duration_jiffies;
- unsigned n_sectors;
- unsigned completed;
+ unsigned int n_sectors;
+ unsigned int completed;
};
#define DM_MQ_NR_HW_QUEUES 1
#define DM_MQ_QUEUE_DEPTH 2048
-static unsigned dm_mq_nr_hw_queues = DM_MQ_NR_HW_QUEUES;
-static unsigned dm_mq_queue_depth = DM_MQ_QUEUE_DEPTH;
+static unsigned int dm_mq_nr_hw_queues = DM_MQ_NR_HW_QUEUES;
+static unsigned int dm_mq_queue_depth = DM_MQ_QUEUE_DEPTH;
/*
* Request-based DM's mempools' reserved IOs set by the user.
*/
#define RESERVED_REQUEST_BASED_IOS 256
-static unsigned reserved_rq_based_ios = RESERVED_REQUEST_BASED_IOS;
+static unsigned int reserved_rq_based_ios = RESERVED_REQUEST_BASED_IOS;
-unsigned dm_get_reserved_rq_based_ios(void)
+unsigned int dm_get_reserved_rq_based_ios(void)
{
return __dm_get_module_param(&reserved_rq_based_ios,
RESERVED_REQUEST_BASED_IOS, DM_RESERVED_MAX_IOS);
}
-static unsigned dm_get_blk_mq_nr_hw_queues(void)
+static unsigned int dm_get_blk_mq_nr_hw_queues(void)
{
return __dm_get_module_param(&dm_mq_nr_hw_queues, 1, 32);
}
-static unsigned dm_get_blk_mq_queue_depth(void)
+static unsigned int dm_get_blk_mq_queue_depth(void)
{
return __dm_get_module_param(&dm_mq_queue_depth,
DM_MQ_QUEUE_DEPTH, BLK_MQ_MAX_DEPTH);
@@ -127,6 +128,7 @@ static void rq_end_stats(struct mapped_device *md, struct request *orig)
{
if (unlikely(dm_stats_used(&md->stats))) {
struct dm_rq_target_io *tio = tio_from_request(orig);
+
tio->duration_jiffies = jiffies - tio->duration_jiffies;
dm_stats_account_io(&md->stats, rq_data_dir(orig),
blk_rq_pos(orig), tio->n_sectors, true,
@@ -434,6 +436,7 @@ static void dm_start_request(struct mapped_device *md, struct request *orig)
if (unlikely(dm_stats_used(&md->stats))) {
struct dm_rq_target_io *tio = tio_from_request(orig);
+
tio->duration_jiffies = jiffies;
tio->n_sectors = blk_rq_sectors(orig);
dm_stats_account_io(&md->stats, rq_data_dir(orig),
@@ -581,16 +584,16 @@ void dm_mq_cleanup_mapped_device(struct mapped_device *md)
}
}
-module_param(reserved_rq_based_ios, uint, S_IRUGO | S_IWUSR);
+module_param(reserved_rq_based_ios, uint, 0644);
MODULE_PARM_DESC(reserved_rq_based_ios, "Reserved IOs in request-based mempools");
/* Unused, but preserved for userspace compatibility */
static bool use_blk_mq = true;
-module_param(use_blk_mq, bool, S_IRUGO | S_IWUSR);
+module_param(use_blk_mq, bool, 0644);
MODULE_PARM_DESC(use_blk_mq, "Use block multiqueue for request-based DM devices");
-module_param(dm_mq_nr_hw_queues, uint, S_IRUGO | S_IWUSR);
+module_param(dm_mq_nr_hw_queues, uint, 0644);
MODULE_PARM_DESC(dm_mq_nr_hw_queues, "Number of hardware queues for request-based dm-mq devices");
-module_param(dm_mq_queue_depth, uint, S_IRUGO | S_IWUSR);
+module_param(dm_mq_queue_depth, uint, 0644);
MODULE_PARM_DESC(dm_mq_queue_depth, "Queue depth for request-based dm-mq devices");
diff --git a/drivers/md/dm-rq.h b/drivers/md/dm-rq.h
index 1eea0da641db..1f73e194e792 100644
--- a/drivers/md/dm-rq.h
+++ b/drivers/md/dm-rq.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Internal header file for device mapper
*
@@ -38,7 +39,7 @@ void dm_stop_queue(struct request_queue *q);
void dm_mq_kick_requeue_list(struct mapped_device *md);
-unsigned dm_get_reserved_rq_based_ios(void);
+unsigned int dm_get_reserved_rq_based_ios(void);
ssize_t dm_attr_rq_based_seq_io_merge_deadline_show(struct mapped_device *md, char *buf);
ssize_t dm_attr_rq_based_seq_io_merge_deadline_store(struct mapped_device *md,
diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c
index 680cc05ec654..f14e5df27874 100644
--- a/drivers/md/dm-snap-persistent.c
+++ b/drivers/md/dm-snap-persistent.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2001-2002 Sistina Software (UK) Limited.
* Copyright (C) 2006-2008 Red Hat GmbH
@@ -21,10 +22,12 @@
#define DM_PREFETCH_CHUNKS 12
-/*-----------------------------------------------------------------
+/*
+ *---------------------------------------------------------------
* Persistent snapshots, by persistent we mean that the snapshot
* will survive a reboot.
- *---------------------------------------------------------------*/
+ *---------------------------------------------------------------
+ */
/*
* We need to store a record of which parts of the origin have
@@ -92,7 +95,7 @@ struct core_exception {
};
struct commit_callback {
- void (*callback)(void *, int success);
+ void (*callback)(void *ref, int success);
void *context;
};
@@ -273,6 +276,7 @@ static void skip_metadata(struct pstore *ps)
{
uint32_t stride = ps->exceptions_per_area + 1;
chunk_t next_free = ps->next_free;
+
if (sector_div(next_free, stride) == NUM_SNAPSHOT_HDR_CHUNKS)
ps->next_free++;
}
@@ -303,7 +307,7 @@ static int read_header(struct pstore *ps, int *new_snapshot)
{
int r;
struct disk_header *dh;
- unsigned chunk_size;
+ unsigned int chunk_size;
int chunk_size_supplied = 1;
char *chunk_err;
@@ -354,8 +358,7 @@ static int read_header(struct pstore *ps, int *new_snapshot)
return 0;
if (chunk_size_supplied)
- DMWARN("chunk size %u in device metadata overrides "
- "table chunk size of %u.",
+ DMWARN("chunk size %u in device metadata overrides table chunk size of %u.",
chunk_size, ps->store->chunk_size);
/* We had a bogus chunk_size. Fix stuff up. */
@@ -515,15 +518,18 @@ static int read_exceptions(struct pstore *ps,
if (unlikely(prefetch_area < ps->current_area))
prefetch_area = ps->current_area;
- if (DM_PREFETCH_CHUNKS) do {
- chunk_t pf_chunk = area_location(ps, prefetch_area);
- if (unlikely(pf_chunk >= dm_bufio_get_device_size(client)))
- break;
- dm_bufio_prefetch(client, pf_chunk, 1);
- prefetch_area++;
- if (unlikely(!prefetch_area))
- break;
- } while (prefetch_area <= ps->current_area + DM_PREFETCH_CHUNKS);
+ if (DM_PREFETCH_CHUNKS) {
+ do {
+ chunk_t pf_chunk = area_location(ps, prefetch_area);
+
+ if (unlikely(pf_chunk >= dm_bufio_get_device_size(client)))
+ break;
+ dm_bufio_prefetch(client, pf_chunk, 1);
+ prefetch_area++;
+ if (unlikely(!prefetch_area))
+ break;
+ } while (prefetch_area <= ps->current_area + DM_PREFETCH_CHUNKS);
+ }
chunk = area_location(ps, ps->current_area);
@@ -690,7 +696,7 @@ static int persistent_prepare_exception(struct dm_exception_store *store,
static void persistent_commit_exception(struct dm_exception_store *store,
struct dm_exception *e, int valid,
- void (*callback) (void *, int success),
+ void (*callback)(void *, int success),
void *callback_context)
{
unsigned int i;
@@ -874,6 +880,7 @@ static int persistent_ctr(struct dm_exception_store *store, char *options)
if (options) {
char overflow = toupper(options[0]);
+
if (overflow == 'O')
store->userspace_supports_overflow = true;
else {
@@ -895,11 +902,11 @@ err_workqueue:
return r;
}
-static unsigned persistent_status(struct dm_exception_store *store,
+static unsigned int persistent_status(struct dm_exception_store *store,
status_type_t status, char *result,
- unsigned maxlen)
+ unsigned int maxlen)
{
- unsigned sz = 0;
+ unsigned int sz = 0;
switch (status) {
case STATUSTYPE_INFO:
@@ -958,8 +965,7 @@ int dm_persistent_snapshot_init(void)
r = dm_exception_store_type_register(&_persistent_compat_type);
if (r) {
- DMERR("Unable to register old-style persistent exception "
- "store type");
+ DMERR("Unable to register old-style persistent exception store type");
dm_exception_store_type_unregister(&_persistent_type);
return r;
}
diff --git a/drivers/md/dm-snap-transient.c b/drivers/md/dm-snap-transient.c
index 0e0ae4c36b37..1e07a745bedd 100644
--- a/drivers/md/dm-snap-transient.c
+++ b/drivers/md/dm-snap-transient.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2001-2002 Sistina Software (UK) Limited.
* Copyright (C) 2006-2008 Red Hat GmbH
@@ -16,9 +17,11 @@
#define DM_MSG_PREFIX "transient snapshot"
-/*-----------------------------------------------------------------
+/*
+ *---------------------------------------------------------------
* Implementation of the store for non-persistent snapshots.
- *---------------------------------------------------------------*/
+ *---------------------------------------------------------------
+ */
struct transient_c {
sector_t next_free;
};
@@ -53,7 +56,7 @@ static int transient_prepare_exception(struct dm_exception_store *store,
static void transient_commit_exception(struct dm_exception_store *store,
struct dm_exception *e, int valid,
- void (*callback) (void *, int success),
+ void (*callback)(void *, int success),
void *callback_context)
{
/* Just succeed */
@@ -84,11 +87,11 @@ static int transient_ctr(struct dm_exception_store *store, char *options)
return 0;
}
-static unsigned transient_status(struct dm_exception_store *store,
+static unsigned int transient_status(struct dm_exception_store *store,
status_type_t status, char *result,
- unsigned maxlen)
+ unsigned int maxlen)
{
- unsigned sz = 0;
+ unsigned int sz = 0;
switch (status) {
case STATUSTYPE_INFO:
@@ -140,8 +143,7 @@ int dm_transient_snapshot_init(void)
r = dm_exception_store_type_register(&_transient_compat_type);
if (r) {
- DMWARN("Unable to register old-style transient "
- "exception store type");
+ DMWARN("Unable to register old-style transient exception store type");
dm_exception_store_type_unregister(&_transient_type);
return r;
}
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index d1c2f84d27e3..f766c21408f1 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2001-2002 Sistina Software (UK) Limited.
*
@@ -41,7 +42,7 @@ static const char dm_snapshot_merge_target_name[] = "snapshot-merge";
struct dm_exception_table {
uint32_t hash_mask;
- unsigned hash_shift;
+ unsigned int hash_shift;
struct hlist_bl_head *table;
};
@@ -106,7 +107,7 @@ struct dm_snapshot {
/* The on disk metadata handler */
struct dm_exception_store *store;
- unsigned in_progress;
+ unsigned int in_progress;
struct wait_queue_head in_progress_wait;
struct dm_kcopyd_client *kcopyd_client;
@@ -122,11 +123,11 @@ struct dm_snapshot {
* The merge operation failed if this flag is set.
* Failure modes are handled as follows:
* - I/O error reading the header
- * => don't load the target; abort.
+ * => don't load the target; abort.
* - Header does not have "valid" flag set
- * => use the origin; forget about the snapshot.
+ * => use the origin; forget about the snapshot.
* - I/O error when reading exceptions
- * => don't load the target; abort.
+ * => don't load the target; abort.
* (We can't use the intermediate origin state.)
* - I/O error while merging
* => stop merging; set merge_failed; process I/O normally.
@@ -161,7 +162,7 @@ struct dm_snapshot {
*/
#define DEFAULT_COW_THRESHOLD 2048
-static unsigned cow_threshold = DEFAULT_COW_THRESHOLD;
+static unsigned int cow_threshold = DEFAULT_COW_THRESHOLD;
module_param_named(snapshot_cow_threshold, cow_threshold, uint, 0644);
MODULE_PARM_DESC(snapshot_cow_threshold, "Maximum number of chunks being copied on write");
@@ -244,12 +245,14 @@ struct dm_snap_tracked_chunk {
static void init_tracked_chunk(struct bio *bio)
{
struct dm_snap_tracked_chunk *c = dm_per_bio_data(bio, sizeof(struct dm_snap_tracked_chunk));
+
INIT_HLIST_NODE(&c->node);
}
static bool is_bio_tracked(struct bio *bio)
{
struct dm_snap_tracked_chunk *c = dm_per_bio_data(bio, sizeof(struct dm_snap_tracked_chunk));
+
return !hlist_unhashed(&c->node);
}
@@ -297,12 +300,12 @@ static int __chunk_is_tracked(struct dm_snapshot *s, chunk_t chunk)
/*
* This conflicting I/O is extremely improbable in the caller,
- * so msleep(1) is sufficient and there is no need for a wait queue.
+ * so fsleep(1000) is sufficient and there is no need for a wait queue.
*/
static void __check_for_conflicting_io(struct dm_snapshot *s, chunk_t chunk)
{
while (__chunk_is_tracked(s, chunk))
- msleep(1);
+ fsleep(1000);
}
/*
@@ -324,7 +327,7 @@ struct origin {
struct dm_origin {
struct dm_dev *dev;
struct dm_target *ti;
- unsigned split_boundary;
+ unsigned int split_boundary;
struct list_head hash_list;
};
@@ -377,7 +380,7 @@ static void exit_origin_hash(void)
kfree(_dm_origins);
}
-static unsigned origin_hash(struct block_device *bdev)
+static unsigned int origin_hash(struct block_device *bdev)
{
return bdev->bd_dev & ORIGIN_MASK;
}
@@ -388,7 +391,7 @@ static struct origin *__lookup_origin(struct block_device *origin)
struct origin *o;
ol = &_origins[origin_hash(origin)];
- list_for_each_entry (o, ol, hash_list)
+ list_for_each_entry(o, ol, hash_list)
if (bdev_equal(o->bdev, origin))
return o;
@@ -398,6 +401,7 @@ static struct origin *__lookup_origin(struct block_device *origin)
static void __insert_origin(struct origin *o)
{
struct list_head *sl = &_origins[origin_hash(o->bdev)];
+
list_add_tail(&o->hash_list, sl);
}
@@ -407,7 +411,7 @@ static struct dm_origin *__lookup_dm_origin(struct block_device *origin)
struct dm_origin *o;
ol = &_dm_origins[origin_hash(origin)];
- list_for_each_entry (o, ol, hash_list)
+ list_for_each_entry(o, ol, hash_list)
if (bdev_equal(o->dev->bdev, origin))
return o;
@@ -417,6 +421,7 @@ static struct dm_origin *__lookup_dm_origin(struct block_device *origin)
static void __insert_dm_origin(struct dm_origin *o)
{
struct list_head *sl = &_dm_origins[origin_hash(o->dev->bdev)];
+
list_add_tail(&o->hash_list, sl);
}
@@ -490,8 +495,7 @@ static int __validate_exception_handover(struct dm_snapshot *snap)
if ((__find_snapshots_sharing_cow(snap, &snap_src, &snap_dest,
&snap_merge) == 2) ||
snap_dest) {
- snap->ti->error = "Snapshot cow pairing for exception "
- "table handover failed";
+ snap->ti->error = "Snapshot cow pairing for exception table handover failed";
return -EINVAL;
}
@@ -518,8 +522,7 @@ static int __validate_exception_handover(struct dm_snapshot *snap)
if (!snap_src->store->type->prepare_merge ||
!snap_src->store->type->commit_merge) {
- snap->ti->error = "Snapshot exception store does not "
- "support snapshot-merge.";
+ snap->ti->error = "Snapshot exception store does not support snapshot-merge.";
return -EINVAL;
}
@@ -652,7 +655,7 @@ static void dm_exception_table_unlock(struct dm_exception_table_lock *lock)
}
static int dm_exception_table_init(struct dm_exception_table *et,
- uint32_t size, unsigned hash_shift)
+ uint32_t size, unsigned int hash_shift)
{
unsigned int i;
@@ -850,7 +853,7 @@ static int dm_add_exception(void *context, chunk_t old, chunk_t new)
static uint32_t __minimum_chunk_size(struct origin *o)
{
struct dm_snapshot *snap;
- unsigned chunk_size = rounddown_pow_of_two(UINT_MAX);
+ unsigned int chunk_size = rounddown_pow_of_two(UINT_MAX);
if (o)
list_for_each_entry(snap, &o->snapshots, list)
@@ -867,6 +870,7 @@ static int calc_max_buckets(void)
{
/* use a fixed size of 2MB */
unsigned long mem = 2 * 1024 * 1024;
+
mem /= sizeof(struct hlist_bl_head);
return mem;
@@ -937,8 +941,7 @@ static int __remove_single_exception_chunk(struct dm_snapshot *s,
e = dm_lookup_exception(&s->complete, old_chunk);
if (!e) {
- DMERR("Corruption detected: exception for block %llu is "
- "on disk but not in memory",
+ DMERR("Corruption detected: exception for block %llu is on disk but not in memory",
(unsigned long long)old_chunk);
return -EINVAL;
}
@@ -965,8 +968,7 @@ static int __remove_single_exception_chunk(struct dm_snapshot *s,
e->new_chunk++;
} else if (old_chunk != e->old_chunk +
dm_consecutive_chunk_count(e)) {
- DMERR("Attempt to merge block %llu from the "
- "middle of a chunk range [%llu - %llu]",
+ DMERR("Attempt to merge block %llu from the middle of a chunk range [%llu - %llu]",
(unsigned long long)old_chunk,
(unsigned long long)e->old_chunk,
(unsigned long long)
@@ -1010,7 +1012,7 @@ out:
}
static int origin_write_extent(struct dm_snapshot *merging_snap,
- sector_t sector, unsigned chunk_size);
+ sector_t sector, unsigned int chunk_size);
static void merge_callback(int read_err, unsigned long write_err,
void *context);
@@ -1059,8 +1061,7 @@ static void snapshot_merge_next_chunks(struct dm_snapshot *s)
&new_chunk);
if (linear_chunks <= 0) {
if (linear_chunks < 0) {
- DMERR("Read error in exception store: "
- "shutting down merge");
+ DMERR("Read error in exception store: shutting down merge");
down_write(&s->lock);
s->merge_failed = true;
up_write(&s->lock);
@@ -1183,7 +1184,7 @@ static int parse_snapshot_features(struct dm_arg_set *as, struct dm_snapshot *s,
struct dm_target *ti)
{
int r;
- unsigned argc;
+ unsigned int argc;
const char *arg_name;
static const struct dm_arg _args[] = {
@@ -1241,7 +1242,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
int r = -EINVAL;
char *origin_path, *cow_path;
dev_t origin_dev, cow_dev;
- unsigned args_used, num_flush_bios = 1;
+ unsigned int args_used, num_flush_bios = 1;
fmode_t origin_mode = FMODE_READ;
if (argc < 4) {
@@ -1493,7 +1494,7 @@ static void snapshot_dtr(struct dm_target *ti)
unregister_snapshot(s);
while (atomic_read(&s->pending_exceptions_count))
- msleep(1);
+ fsleep(1000);
/*
* Ensure instructions in mempool_exit aren't reordered
* before atomic_read.
@@ -1551,6 +1552,7 @@ static bool wait_for_in_progress(struct dm_snapshot *s, bool unlock_origins)
* throttling is unlikely to negatively impact performance.
*/
DECLARE_WAITQUEUE(wait, current);
+
__add_wait_queue(&s->in_progress_wait, &wait);
__set_current_state(TASK_UNINTERRUPTIBLE);
spin_unlock(&s->in_progress_wait.lock);
@@ -2208,12 +2210,10 @@ static int snapshot_preresume(struct dm_target *ti)
if (snap_src && snap_dest) {
down_read(&snap_src->lock);
if (s == snap_src) {
- DMERR("Unable to resume snapshot source until "
- "handover completes.");
+ DMERR("Unable to resume snapshot source until handover completes.");
r = -EINVAL;
} else if (!dm_suspended(snap_src->ti)) {
- DMERR("Unable to perform snapshot handover until "
- "source is suspended.");
+ DMERR("Unable to perform snapshot handover until source is suspended.");
r = -EINVAL;
}
up_read(&snap_src->lock);
@@ -2315,11 +2315,11 @@ static void snapshot_merge_resume(struct dm_target *ti)
}
static void snapshot_status(struct dm_target *ti, status_type_t type,
- unsigned status_flags, char *result, unsigned maxlen)
+ unsigned int status_flags, char *result, unsigned int maxlen)
{
- unsigned sz = 0;
+ unsigned int sz = 0;
struct dm_snapshot *snap = ti->private;
- unsigned num_features;
+ unsigned int num_features;
switch (type) {
case STATUSTYPE_INFO:
@@ -2344,8 +2344,7 @@ static void snapshot_status(struct dm_target *ti, status_type_t type,
(unsigned long long)sectors_allocated,
(unsigned long long)total_sectors,
(unsigned long long)metadata_sectors);
- }
- else
+ } else
DMEMIT("Unknown");
}
@@ -2419,10 +2418,11 @@ static void snapshot_io_hints(struct dm_target *ti, struct queue_limits *limits)
}
}
-/*-----------------------------------------------------------------
+/*
+ *---------------------------------------------------------------
* Origin methods
- *---------------------------------------------------------------*/
-
+ *---------------------------------------------------------------
+ */
/*
* If no exceptions need creating, DM_MAPIO_REMAPPED is returned and any
* supplied bio was ignored. The caller may submit it immediately.
@@ -2446,7 +2446,7 @@ static int __origin_write(struct list_head *snapshots, sector_t sector,
chunk_t chunk;
/* Do all the snapshots on this origin */
- list_for_each_entry (snap, snapshots, list) {
+ list_for_each_entry(snap, snapshots, list) {
/*
* Don't make new exceptions in a merging snapshot
* because it has effectively been deleted
@@ -2566,6 +2566,7 @@ again:
if (o) {
if (limit) {
struct dm_snapshot *s;
+
list_for_each_entry(s, &o->snapshots, list)
if (unlikely(!wait_for_in_progress(s, true)))
goto again;
@@ -2592,7 +2593,7 @@ again:
* size must be a multiple of merging_snap's chunk_size.
*/
static int origin_write_extent(struct dm_snapshot *merging_snap,
- sector_t sector, unsigned size)
+ sector_t sector, unsigned int size)
{
int must_wait = 0;
sector_t n;
@@ -2668,7 +2669,7 @@ static void origin_dtr(struct dm_target *ti)
static int origin_map(struct dm_target *ti, struct bio *bio)
{
struct dm_origin *o = ti->private;
- unsigned available_sectors;
+ unsigned int available_sectors;
bio_set_dev(bio, o->dev->bdev);
@@ -2679,7 +2680,7 @@ static int origin_map(struct dm_target *ti, struct bio *bio)
return DM_MAPIO_REMAPPED;
available_sectors = o->split_boundary -
- ((unsigned)bio->bi_iter.bi_sector & (o->split_boundary - 1));
+ ((unsigned int)bio->bi_iter.bi_sector & (o->split_boundary - 1));
if (bio_sectors(bio) > available_sectors)
dm_accept_partial_bio(bio, available_sectors);
@@ -2713,7 +2714,7 @@ static void origin_postsuspend(struct dm_target *ti)
}
static void origin_status(struct dm_target *ti, status_type_t type,
- unsigned status_flags, char *result, unsigned maxlen)
+ unsigned int status_flags, char *result, unsigned int maxlen)
{
struct dm_origin *o = ti->private;
diff --git a/drivers/md/dm-stats.c b/drivers/md/dm-stats.c
index f105a71915ab..c21a19ab73f7 100644
--- a/drivers/md/dm-stats.c
+++ b/drivers/md/dm-stats.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
#include <linux/errno.h>
#include <linux/numa.h>
#include <linux/slab.h>
@@ -42,12 +42,12 @@ struct dm_stat_shared {
struct dm_stat {
struct list_head list_entry;
int id;
- unsigned stat_flags;
+ unsigned int stat_flags;
size_t n_entries;
sector_t start;
sector_t end;
sector_t step;
- unsigned n_histogram_entries;
+ unsigned int n_histogram_entries;
unsigned long long *histogram_boundaries;
const char *program_id;
const char *aux_data;
@@ -63,7 +63,7 @@ struct dm_stat {
struct dm_stats_last_position {
sector_t last_sector;
- unsigned last_rw;
+ unsigned int last_rw;
};
/*
@@ -250,8 +250,8 @@ static void dm_stats_recalc_precise_timestamps(struct dm_stats *stats)
}
static int dm_stats_create(struct dm_stats *stats, sector_t start, sector_t end,
- sector_t step, unsigned stat_flags,
- unsigned n_histogram_entries,
+ sector_t step, unsigned int stat_flags,
+ unsigned int n_histogram_entries,
unsigned long long *histogram_boundaries,
const char *program_id, const char *aux_data,
void (*suspend_callback)(struct mapped_device *),
@@ -336,6 +336,7 @@ static int dm_stats_create(struct dm_stats *stats, sector_t start, sector_t end,
if (s->n_histogram_entries) {
unsigned long long *hi;
+
hi = dm_kvzalloc(s->histogram_alloc_size, NUMA_NO_NODE);
if (!hi) {
r = -ENOMEM;
@@ -357,6 +358,7 @@ static int dm_stats_create(struct dm_stats *stats, sector_t start, sector_t end,
s->stat_percpu[cpu] = p;
if (s->n_histogram_entries) {
unsigned long long *hi;
+
hi = dm_kvzalloc(s->histogram_alloc_size, cpu_to_node(cpu));
if (!hi) {
r = -ENOMEM;
@@ -470,11 +472,11 @@ do_sync_free:
}
static int dm_stats_list(struct dm_stats *stats, const char *program,
- char *result, unsigned maxlen)
+ char *result, unsigned int maxlen)
{
struct dm_stat *s;
sector_t len;
- unsigned sz = 0;
+ unsigned int sz = 0;
/*
* Output format:
@@ -494,7 +496,8 @@ static int dm_stats_list(struct dm_stats *stats, const char *program,
if (s->stat_flags & STAT_PRECISE_TIMESTAMPS)
DMEMIT(" precise_timestamps");
if (s->n_histogram_entries) {
- unsigned i;
+ unsigned int i;
+
DMEMIT(" histogram:");
for (i = 0; i < s->n_histogram_entries; i++) {
if (i)
@@ -518,7 +521,7 @@ static void dm_stat_round(struct dm_stat *s, struct dm_stat_shared *shared,
* This is racy, but so is part_round_stats_single.
*/
unsigned long long now, difference;
- unsigned in_flight_read, in_flight_write;
+ unsigned int in_flight_read, in_flight_write;
if (likely(!(s->stat_flags & STAT_PRECISE_TIMESTAMPS)))
now = jiffies;
@@ -529,8 +532,8 @@ static void dm_stat_round(struct dm_stat *s, struct dm_stat_shared *shared,
if (!difference)
return;
- in_flight_read = (unsigned)atomic_read(&shared->in_flight[READ]);
- in_flight_write = (unsigned)atomic_read(&shared->in_flight[WRITE]);
+ in_flight_read = (unsigned int)atomic_read(&shared->in_flight[READ]);
+ in_flight_write = (unsigned int)atomic_read(&shared->in_flight[WRITE]);
if (in_flight_read)
p->io_ticks[READ] += difference;
if (in_flight_write)
@@ -567,6 +570,7 @@ static void dm_stat_for_entry(struct dm_stat *s, size_t entry,
*/
#if BITS_PER_LONG == 32
unsigned long flags;
+
local_irq_save(flags);
#else
preempt_disable();
@@ -578,6 +582,7 @@ static void dm_stat_for_entry(struct dm_stat *s, size_t entry,
atomic_inc(&shared->in_flight[idx]);
} else {
unsigned long long duration;
+
dm_stat_round(s, shared, p);
atomic_dec(&shared->in_flight[idx]);
p->sectors[idx] += len;
@@ -591,15 +596,15 @@ static void dm_stat_for_entry(struct dm_stat *s, size_t entry,
duration = stats_aux->duration_ns;
}
if (s->n_histogram_entries) {
- unsigned lo = 0, hi = s->n_histogram_entries + 1;
+ unsigned int lo = 0, hi = s->n_histogram_entries + 1;
+
while (lo + 1 < hi) {
- unsigned mid = (lo + hi) / 2;
- if (s->histogram_boundaries[mid - 1] > duration) {
+ unsigned int mid = (lo + hi) / 2;
+
+ if (s->histogram_boundaries[mid - 1] > duration)
hi = mid;
- } else {
+ else
lo = mid;
- }
-
}
p->histogram[lo]++;
}
@@ -651,7 +656,7 @@ static void __dm_stat_bio(struct dm_stat *s, int bi_rw,
}
void dm_stats_account_io(struct dm_stats *stats, unsigned long bi_rw,
- sector_t bi_sector, unsigned bi_sectors, bool end,
+ sector_t bi_sector, unsigned int bi_sectors, bool end,
unsigned long start_time,
struct dm_stats_aux *stats_aux)
{
@@ -740,7 +745,8 @@ static void __dm_stat_init_temporary_percpu_totals(struct dm_stat_shared *shared
shared->tmp.io_ticks_total += READ_ONCE(p->io_ticks_total);
shared->tmp.time_in_queue += READ_ONCE(p->time_in_queue);
if (s->n_histogram_entries) {
- unsigned i;
+ unsigned int i;
+
for (i = 0; i < s->n_histogram_entries + 1; i++)
shared->tmp.histogram[i] += READ_ONCE(p->histogram[i]);
}
@@ -774,7 +780,8 @@ static void __dm_stat_clear(struct dm_stat *s, size_t idx_start, size_t idx_end,
p->time_in_queue -= shared->tmp.time_in_queue;
local_irq_enable();
if (s->n_histogram_entries) {
- unsigned i;
+ unsigned int i;
+
for (i = 0; i < s->n_histogram_entries + 1; i++) {
local_irq_disable();
p = &s->stat_percpu[smp_processor_id()][x];
@@ -811,7 +818,7 @@ static int dm_stats_clear(struct dm_stats *stats, int id)
static unsigned long long dm_jiffies_to_msec64(struct dm_stat *s, unsigned long long j)
{
unsigned long long result;
- unsigned mult;
+ unsigned int mult;
if (s->stat_flags & STAT_PRECISE_TIMESTAMPS)
return j;
@@ -831,9 +838,9 @@ static unsigned long long dm_jiffies_to_msec64(struct dm_stat *s, unsigned long
static int dm_stats_print(struct dm_stats *stats, int id,
size_t idx_start, size_t idx_len,
- bool clear, char *result, unsigned maxlen)
+ bool clear, char *result, unsigned int maxlen)
{
- unsigned sz = 0;
+ unsigned int sz = 0;
struct dm_stat *s;
size_t x;
sector_t start, end, step;
@@ -889,10 +896,10 @@ static int dm_stats_print(struct dm_stats *stats, int id,
dm_jiffies_to_msec64(s, shared->tmp.io_ticks[READ]),
dm_jiffies_to_msec64(s, shared->tmp.io_ticks[WRITE]));
if (s->n_histogram_entries) {
- unsigned i;
- for (i = 0; i < s->n_histogram_entries + 1; i++) {
+ unsigned int i;
+
+ for (i = 0; i < s->n_histogram_entries + 1; i++)
DMEMIT("%s%llu", !i ? " " : ":", shared->tmp.histogram[i]);
- }
}
DMEMIT("\n");
@@ -938,11 +945,11 @@ static int dm_stats_set_aux(struct dm_stats *stats, int id, const char *aux_data
return 0;
}
-static int parse_histogram(const char *h, unsigned *n_histogram_entries,
+static int parse_histogram(const char *h, unsigned int *n_histogram_entries,
unsigned long long **histogram_boundaries)
{
const char *q;
- unsigned n;
+ unsigned int n;
unsigned long long last;
*n_histogram_entries = 1;
@@ -962,6 +969,7 @@ static int parse_histogram(const char *h, unsigned *n_histogram_entries,
unsigned long long hi;
int s;
char ch;
+
s = sscanf(h, "%llu%c", &hi, &ch);
if (!s || (s == 2 && ch != ','))
return -EINVAL;
@@ -977,23 +985,21 @@ static int parse_histogram(const char *h, unsigned *n_histogram_entries,
}
static int message_stats_create(struct mapped_device *md,
- unsigned argc, char **argv,
- char *result, unsigned maxlen)
+ unsigned int argc, char **argv,
+ char *result, unsigned int maxlen)
{
int r;
int id;
char dummy;
unsigned long long start, end, len, step;
- unsigned divisor;
+ unsigned int divisor;
const char *program_id, *aux_data;
- unsigned stat_flags = 0;
-
- unsigned n_histogram_entries = 0;
+ unsigned int stat_flags = 0;
+ unsigned int n_histogram_entries = 0;
unsigned long long *histogram_boundaries = NULL;
-
struct dm_arg_set as, as_backup;
const char *a;
- unsigned feature_args;
+ unsigned int feature_args;
/*
* Input format:
@@ -1046,7 +1052,8 @@ static int message_stats_create(struct mapped_device *md,
else if (!strncasecmp(a, "histogram:", 10)) {
if (n_histogram_entries)
goto ret_einval;
- if ((r = parse_histogram(a + 10, &n_histogram_entries, &histogram_boundaries)))
+ r = parse_histogram(a + 10, &n_histogram_entries, &histogram_boundaries);
+ if (r)
goto ret;
} else
goto ret_einval;
@@ -1102,7 +1109,7 @@ ret:
}
static int message_stats_delete(struct mapped_device *md,
- unsigned argc, char **argv)
+ unsigned int argc, char **argv)
{
int id;
char dummy;
@@ -1117,7 +1124,7 @@ static int message_stats_delete(struct mapped_device *md,
}
static int message_stats_clear(struct mapped_device *md,
- unsigned argc, char **argv)
+ unsigned int argc, char **argv)
{
int id;
char dummy;
@@ -1132,8 +1139,8 @@ static int message_stats_clear(struct mapped_device *md,
}
static int message_stats_list(struct mapped_device *md,
- unsigned argc, char **argv,
- char *result, unsigned maxlen)
+ unsigned int argc, char **argv,
+ char *result, unsigned int maxlen)
{
int r;
const char *program = NULL;
@@ -1155,8 +1162,8 @@ static int message_stats_list(struct mapped_device *md,
}
static int message_stats_print(struct mapped_device *md,
- unsigned argc, char **argv, bool clear,
- char *result, unsigned maxlen)
+ unsigned int argc, char **argv, bool clear,
+ char *result, unsigned int maxlen)
{
int id;
char dummy;
@@ -1182,7 +1189,7 @@ static int message_stats_print(struct mapped_device *md,
}
static int message_stats_set_aux(struct mapped_device *md,
- unsigned argc, char **argv)
+ unsigned int argc, char **argv)
{
int id;
char dummy;
@@ -1196,8 +1203,8 @@ static int message_stats_set_aux(struct mapped_device *md,
return dm_stats_set_aux(dm_get_stats(md), id, argv[2]);
}
-int dm_stats_message(struct mapped_device *md, unsigned argc, char **argv,
- char *result, unsigned maxlen)
+int dm_stats_message(struct mapped_device *md, unsigned int argc, char **argv,
+ char *result, unsigned int maxlen)
{
int r;
@@ -1240,5 +1247,5 @@ void dm_statistics_exit(void)
DMCRIT("shared_memory_amount leaked: %lu", shared_memory_amount);
}
-module_param_named(stats_current_allocated_bytes, shared_memory_amount, ulong, S_IRUGO);
+module_param_named(stats_current_allocated_bytes, shared_memory_amount, ulong, 0444);
MODULE_PARM_DESC(stats_current_allocated_bytes, "Memory currently used by statistics");
diff --git a/drivers/md/dm-stats.h b/drivers/md/dm-stats.h
index 09c81a1ec057..0bc152c8e4f3 100644
--- a/drivers/md/dm-stats.h
+++ b/drivers/md/dm-stats.h
@@ -26,11 +26,11 @@ void dm_stats_cleanup(struct dm_stats *st);
struct mapped_device;
-int dm_stats_message(struct mapped_device *md, unsigned argc, char **argv,
- char *result, unsigned maxlen);
+int dm_stats_message(struct mapped_device *md, unsigned int argc, char **argv,
+ char *result, unsigned int maxlen);
void dm_stats_account_io(struct dm_stats *stats, unsigned long bi_rw,
- sector_t bi_sector, unsigned bi_sectors, bool end,
+ sector_t bi_sector, unsigned int bi_sectors, bool end,
unsigned long start_time,
struct dm_stats_aux *aux);
diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c
index baa085cc67bd..8d6951157106 100644
--- a/drivers/md/dm-stripe.c
+++ b/drivers/md/dm-stripe.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2001-2003 Sistina Software (UK) Limited.
*
@@ -15,6 +16,8 @@
#include <linux/slab.h>
#include <linux/log2.h>
+static struct workqueue_struct *dm_stripe_wq;
+
#define DM_MSG_PREFIX "striped"
#define DM_IO_ERROR_THRESHOLD 15
@@ -108,15 +111,13 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv)
width = ti->len;
if (sector_div(width, stripes)) {
- ti->error = "Target length not divisible by "
- "number of stripes";
+ ti->error = "Target length not divisible by number of stripes";
return -EINVAL;
}
tmp_len = width;
if (sector_div(tmp_len, chunk_size)) {
- ti->error = "Target length not divisible by "
- "chunk size";
+ ti->error = "Target length not divisible by chunk size";
return -EINVAL;
}
@@ -124,15 +125,13 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv)
* Do we have enough arguments for that many stripes ?
*/
if (argc != (2 + 2 * stripes)) {
- ti->error = "Not enough destinations "
- "specified";
+ ti->error = "Not enough destinations specified";
return -EINVAL;
}
sc = kmalloc(struct_size(sc, stripe, stripes), GFP_KERNEL);
if (!sc) {
- ti->error = "Memory allocation for striped context "
- "failed";
+ ti->error = "Memory allocation for striped context failed";
return -ENOMEM;
}
@@ -262,18 +261,18 @@ static int stripe_map_range(struct stripe_c *sc, struct bio *bio,
sc->stripe[target_stripe].physical_start;
bio->bi_iter.bi_size = to_bytes(end - begin);
return DM_MAPIO_REMAPPED;
- } else {
- /* The range doesn't map to the target stripe */
- bio_endio(bio);
- return DM_MAPIO_SUBMITTED;
}
+
+ /* The range doesn't map to the target stripe */
+ bio_endio(bio);
+ return DM_MAPIO_SUBMITTED;
}
static int stripe_map(struct dm_target *ti, struct bio *bio)
{
struct stripe_c *sc = ti->private;
uint32_t stripe;
- unsigned target_bio_nr;
+ unsigned int target_bio_nr;
if (bio->bi_opf & REQ_PREFLUSH) {
target_bio_nr = dm_bio_get_target_bio_nr(bio);
@@ -359,7 +358,7 @@ static size_t stripe_dax_recovery_write(struct dm_target *ti, pgoff_t pgoff,
*/
static void stripe_status(struct dm_target *ti, status_type_t type,
- unsigned status_flags, char *result, unsigned maxlen)
+ unsigned int status_flags, char *result, unsigned int maxlen)
{
struct stripe_c *sc = (struct stripe_c *) ti->private;
unsigned int sz = 0;
@@ -368,14 +367,12 @@ static void stripe_status(struct dm_target *ti, status_type_t type,
switch (type) {
case STATUSTYPE_INFO:
DMEMIT("%d ", sc->stripes);
- for (i = 0; i < sc->stripes; i++) {
+ for (i = 0; i < sc->stripes; i++)
DMEMIT("%s ", sc->stripe[i].dev->name);
- }
+
DMEMIT("1 ");
- for (i = 0; i < sc->stripes; i++) {
- DMEMIT("%c", atomic_read(&(sc->stripe[i].error_count)) ?
- 'D' : 'A');
- }
+ for (i = 0; i < sc->stripes; i++)
+ DMEMIT("%c", atomic_read(&(sc->stripe[i].error_count)) ? 'D' : 'A');
break;
case STATUSTYPE_TABLE:
@@ -406,7 +403,7 @@ static void stripe_status(struct dm_target *ti, status_type_t type,
static int stripe_end_io(struct dm_target *ti, struct bio *bio,
blk_status_t *error)
{
- unsigned i;
+ unsigned int i;
char major_minor[16];
struct stripe_c *sc = ti->private;
@@ -433,7 +430,7 @@ static int stripe_end_io(struct dm_target *ti, struct bio *bio,
atomic_inc(&(sc->stripe[i].error_count));
if (atomic_read(&(sc->stripe[i].error_count)) <
DM_IO_ERROR_THRESHOLD)
- schedule_work(&sc->trigger_event);
+ queue_work(dm_stripe_wq, &sc->trigger_event);
}
return DM_ENDIO_DONE;
@@ -444,7 +441,7 @@ static int stripe_iterate_devices(struct dm_target *ti,
{
struct stripe_c *sc = ti->private;
int ret = 0;
- unsigned i = 0;
+ unsigned int i = 0;
do {
ret = fn(ti, sc->stripe[i].dev,
@@ -459,7 +456,7 @@ static void stripe_io_hints(struct dm_target *ti,
struct queue_limits *limits)
{
struct stripe_c *sc = ti->private;
- unsigned chunk_size = sc->chunk_size << SECTOR_SHIFT;
+ unsigned int chunk_size = sc->chunk_size << SECTOR_SHIFT;
blk_limits_io_min(limits, chunk_size);
blk_limits_io_opt(limits, chunk_size * sc->stripes);
@@ -486,9 +483,14 @@ int __init dm_stripe_init(void)
{
int r;
+ dm_stripe_wq = alloc_workqueue("dm_stripe_wq", 0, 0);
+ if (!dm_stripe_wq)
+ return -ENOMEM;
r = dm_register_target(&stripe_target);
- if (r < 0)
+ if (r < 0) {
+ destroy_workqueue(dm_stripe_wq);
DMWARN("target registration failed");
+ }
return r;
}
@@ -496,4 +498,5 @@ int __init dm_stripe_init(void)
void dm_stripe_exit(void)
{
dm_unregister_target(&stripe_target);
+ destroy_workqueue(dm_stripe_wq);
}
diff --git a/drivers/md/dm-switch.c b/drivers/md/dm-switch.c
index 534dc2ca8bb0..ee2432927e90 100644
--- a/drivers/md/dm-switch.c
+++ b/drivers/md/dm-switch.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2010-2012 by Dell Inc. All rights reserved.
* Copyright (C) 2011-2013 Red Hat, Inc.
@@ -38,9 +39,9 @@ struct switch_path {
struct switch_ctx {
struct dm_target *ti;
- unsigned nr_paths; /* Number of paths in path_list. */
+ unsigned int nr_paths; /* Number of paths in path_list. */
- unsigned region_size; /* Region size in 512-byte sectors */
+ unsigned int region_size; /* Region size in 512-byte sectors */
unsigned long nr_regions; /* Number of regions making up the device */
signed char region_size_bits; /* log2 of region_size or -1 */
@@ -56,8 +57,8 @@ struct switch_ctx {
struct switch_path path_list[];
};
-static struct switch_ctx *alloc_switch_ctx(struct dm_target *ti, unsigned nr_paths,
- unsigned region_size)
+static struct switch_ctx *alloc_switch_ctx(struct dm_target *ti, unsigned int nr_paths,
+ unsigned int region_size)
{
struct switch_ctx *sctx;
@@ -73,7 +74,7 @@ static struct switch_ctx *alloc_switch_ctx(struct dm_target *ti, unsigned nr_pat
return sctx;
}
-static int alloc_region_table(struct dm_target *ti, unsigned nr_paths)
+static int alloc_region_table(struct dm_target *ti, unsigned int nr_paths)
{
struct switch_ctx *sctx = ti->private;
sector_t nr_regions = ti->len;
@@ -124,7 +125,7 @@ static int alloc_region_table(struct dm_target *ti, unsigned nr_paths)
}
static void switch_get_position(struct switch_ctx *sctx, unsigned long region_nr,
- unsigned long *region_index, unsigned *bit)
+ unsigned long *region_index, unsigned int *bit)
{
if (sctx->region_entries_per_slot_bits >= 0) {
*region_index = region_nr >> sctx->region_entries_per_slot_bits;
@@ -137,10 +138,10 @@ static void switch_get_position(struct switch_ctx *sctx, unsigned long region_nr
*bit *= sctx->region_table_entry_bits;
}
-static unsigned switch_region_table_read(struct switch_ctx *sctx, unsigned long region_nr)
+static unsigned int switch_region_table_read(struct switch_ctx *sctx, unsigned long region_nr)
{
unsigned long region_index;
- unsigned bit;
+ unsigned int bit;
switch_get_position(sctx, region_nr, &region_index, &bit);
@@ -151,9 +152,9 @@ static unsigned switch_region_table_read(struct switch_ctx *sctx, unsigned long
/*
* Find which path to use at given offset.
*/
-static unsigned switch_get_path_nr(struct switch_ctx *sctx, sector_t offset)
+static unsigned int switch_get_path_nr(struct switch_ctx *sctx, sector_t offset)
{
- unsigned path_nr;
+ unsigned int path_nr;
sector_t p;
p = offset;
@@ -172,10 +173,10 @@ static unsigned switch_get_path_nr(struct switch_ctx *sctx, sector_t offset)
}
static void switch_region_table_write(struct switch_ctx *sctx, unsigned long region_nr,
- unsigned value)
+ unsigned int value)
{
unsigned long region_index;
- unsigned bit;
+ unsigned int bit;
region_table_slot_t pte;
switch_get_position(sctx, region_nr, &region_index, &bit);
@@ -191,7 +192,7 @@ static void switch_region_table_write(struct switch_ctx *sctx, unsigned long reg
*/
static void initialise_region_table(struct switch_ctx *sctx)
{
- unsigned path_nr = 0;
+ unsigned int path_nr = 0;
unsigned long region_nr;
for (region_nr = 0; region_nr < sctx->nr_regions; region_nr++) {
@@ -249,7 +250,7 @@ static void switch_dtr(struct dm_target *ti)
* Optional args are to allow for future extension: currently this
* parameter must be 0.
*/
-static int switch_ctr(struct dm_target *ti, unsigned argc, char **argv)
+static int switch_ctr(struct dm_target *ti, unsigned int argc, char **argv)
{
static const struct dm_arg _args[] = {
{1, (KMALLOC_MAX_SIZE - sizeof(struct switch_ctx)) / sizeof(struct switch_path), "Invalid number of paths"},
@@ -259,7 +260,7 @@ static int switch_ctr(struct dm_target *ti, unsigned argc, char **argv)
struct switch_ctx *sctx;
struct dm_arg_set as;
- unsigned nr_paths, region_size, nr_optional_args;
+ unsigned int nr_paths, region_size, nr_optional_args;
int r;
as.argc = argc;
@@ -320,7 +321,7 @@ static int switch_map(struct dm_target *ti, struct bio *bio)
{
struct switch_ctx *sctx = ti->private;
sector_t offset = dm_target_offset(ti, bio->bi_iter.bi_sector);
- unsigned path_nr = switch_get_path_nr(sctx, offset);
+ unsigned int path_nr = switch_get_path_nr(sctx, offset);
bio_set_dev(bio, sctx->path_list[path_nr].dmdev->bdev);
bio->bi_iter.bi_sector = sctx->path_list[path_nr].start + offset;
@@ -371,9 +372,9 @@ static __always_inline unsigned long parse_hex(const char **string)
}
static int process_set_region_mappings(struct switch_ctx *sctx,
- unsigned argc, char **argv)
+ unsigned int argc, char **argv)
{
- unsigned i;
+ unsigned int i;
unsigned long region_index = 0;
for (i = 1; i < argc; i++) {
@@ -466,8 +467,8 @@ static int process_set_region_mappings(struct switch_ctx *sctx,
*
* Only set_region_mappings is supported.
*/
-static int switch_message(struct dm_target *ti, unsigned argc, char **argv,
- char *result, unsigned maxlen)
+static int switch_message(struct dm_target *ti, unsigned int argc, char **argv,
+ char *result, unsigned int maxlen)
{
static DEFINE_MUTEX(message_mutex);
@@ -487,10 +488,10 @@ static int switch_message(struct dm_target *ti, unsigned argc, char **argv,
}
static void switch_status(struct dm_target *ti, status_type_t type,
- unsigned status_flags, char *result, unsigned maxlen)
+ unsigned int status_flags, char *result, unsigned int maxlen)
{
struct switch_ctx *sctx = ti->private;
- unsigned sz = 0;
+ unsigned int sz = 0;
int path_nr;
switch (type) {
@@ -519,7 +520,7 @@ static void switch_status(struct dm_target *ti, status_type_t type,
static int switch_prepare_ioctl(struct dm_target *ti, struct block_device **bdev)
{
struct switch_ctx *sctx = ti->private;
- unsigned path_nr;
+ unsigned int path_nr;
path_nr = switch_get_path_nr(sctx, 0);
diff --git a/drivers/md/dm-sysfs.c b/drivers/md/dm-sysfs.c
index e28c92478536..bfaef27ca79f 100644
--- a/drivers/md/dm-sysfs.c
+++ b/drivers/md/dm-sysfs.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2008 Red Hat, Inc. All rights reserved.
*
@@ -11,13 +12,13 @@
struct dm_sysfs_attr {
struct attribute attr;
- ssize_t (*show)(struct mapped_device *, char *);
- ssize_t (*store)(struct mapped_device *, const char *, size_t count);
+ ssize_t (*show)(struct mapped_device *md, char *p);
+ ssize_t (*store)(struct mapped_device *md, const char *p, size_t count);
};
#define DM_ATTR_RO(_name) \
struct dm_sysfs_attr dm_attr_##_name = \
- __ATTR(_name, S_IRUGO, dm_attr_##_name##_show, NULL)
+ __ATTR(_name, 0444, dm_attr_##_name##_show, NULL)
static ssize_t dm_attr_show(struct kobject *kobj, struct attribute *attr,
char *page)
@@ -42,7 +43,7 @@ static ssize_t dm_attr_show(struct kobject *kobj, struct attribute *attr,
#define DM_ATTR_RW(_name) \
struct dm_sysfs_attr dm_attr_##_name = \
- __ATTR(_name, S_IRUGO | S_IWUSR, dm_attr_##_name##_show, dm_attr_##_name##_store)
+ __ATTR(_name, 0644, dm_attr_##_name##_show, dm_attr_##_name##_store)
static ssize_t dm_attr_store(struct kobject *kobj, struct attribute *attr,
const char *page, size_t count)
@@ -119,7 +120,7 @@ static const struct sysfs_ops dm_sysfs_ops = {
.store = dm_attr_store,
};
-static struct kobj_type dm_ktype = {
+static const struct kobj_type dm_ktype = {
.sysfs_ops = &dm_sysfs_ops,
.default_groups = dm_groups,
.release = dm_kobject_release,
@@ -142,6 +143,7 @@ int dm_sysfs_init(struct mapped_device *md)
void dm_sysfs_exit(struct mapped_device *md)
{
struct kobject *kobj = dm_kobject(md);
+
kobject_put(kobj);
wait_for_completion(dm_get_completion_from_kobject(kobj));
}
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 8541d5688f3a..2055a758541d 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
* Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
@@ -72,7 +73,7 @@ static sector_t high(struct dm_table *t, unsigned int l, unsigned int n)
n = get_child(n, CHILDREN_PER_NODE - 1);
if (n >= t->counts[l])
- return (sector_t) - 1;
+ return (sector_t) -1;
return get_node(t, l, n)[KEYS_PER_NODE - 1];
}
@@ -126,7 +127,7 @@ static int alloc_targets(struct dm_table *t, unsigned int num)
}
int dm_table_create(struct dm_table **result, fmode_t mode,
- unsigned num_targets, struct mapped_device *md)
+ unsigned int num_targets, struct mapped_device *md)
{
struct dm_table *t = kzalloc(sizeof(*t), GFP_KERNEL);
@@ -211,7 +212,7 @@ static struct dm_dev_internal *find_device(struct list_head *l, dev_t dev)
{
struct dm_dev_internal *dd;
- list_for_each_entry (dd, l, list)
+ list_for_each_entry(dd, l, list)
if (dd->dm_dev->bdev->bd_dev == dev)
return dd;
@@ -234,8 +235,7 @@ static int device_area_is_invalid(struct dm_target *ti, struct dm_dev *dev,
return 0;
if ((start >= dev_size) || (start + len > dev_size)) {
- DMERR("%s: %pg too small for target: "
- "start=%llu, len=%llu, dev_size=%llu",
+ DMERR("%s: %pg too small for target: start=%llu, len=%llu, dev_size=%llu",
dm_device_name(ti->table->md), bdev,
(unsigned long long)start,
(unsigned long long)len,
@@ -280,8 +280,7 @@ static int device_area_is_invalid(struct dm_target *ti, struct dm_dev *dev,
return 0;
if (start & (logical_block_size_sectors - 1)) {
- DMERR("%s: start=%llu not aligned to h/w "
- "logical block size %u of %pg",
+ DMERR("%s: start=%llu not aligned to h/w logical block size %u of %pg",
dm_device_name(ti->table->md),
(unsigned long long)start,
limits->logical_block_size, bdev);
@@ -289,8 +288,7 @@ static int device_area_is_invalid(struct dm_target *ti, struct dm_dev *dev,
}
if (len & (logical_block_size_sectors - 1)) {
- DMERR("%s: len=%llu not aligned to h/w "
- "logical block size %u of %pg",
+ DMERR("%s: len=%llu not aligned to h/w logical block size %u of %pg",
dm_device_name(ti->table->md),
(unsigned long long)len,
limits->logical_block_size, bdev);
@@ -364,6 +362,8 @@ int dm_get_device(struct dm_target *ti, const char *path, fmode_t mode,
if (!dev)
return -ENODEV;
}
+ if (dev == disk_devt(t->md->disk))
+ return -EINVAL;
dd = find_device(&t->devices, dev);
if (!dd) {
@@ -371,7 +371,8 @@ int dm_get_device(struct dm_target *ti, const char *path, fmode_t mode,
if (!dd)
return -ENOMEM;
- if ((r = dm_get_table_device(t->md, dev, mode, &dd->dm_dev))) {
+ r = dm_get_table_device(t->md, dev, mode, &dd->dm_dev);
+ if (r) {
kfree(dd);
return r;
}
@@ -470,10 +471,10 @@ static int adjoin(struct dm_table *t, struct dm_target *ti)
* On the other hand, dm-switch needs to process bulk data using messages and
* excessive use of GFP_NOIO could cause trouble.
*/
-static char **realloc_argv(unsigned *size, char **old_argv)
+static char **realloc_argv(unsigned int *size, char **old_argv)
{
char **argv;
- unsigned new_size;
+ unsigned int new_size;
gfp_t gfp;
if (*size) {
@@ -499,7 +500,7 @@ static char **realloc_argv(unsigned *size, char **old_argv)
int dm_split_args(int *argc, char ***argvp, char *input)
{
char *start, *end = input, *out, **argv = NULL;
- unsigned array_size = 0;
+ unsigned int array_size = 0;
*argc = 0;
@@ -732,9 +733,8 @@ int dm_table_add_target(struct dm_table *t, const char *type,
/*
* Target argument parsing helpers.
*/
-static int validate_next_arg(const struct dm_arg *arg,
- struct dm_arg_set *arg_set,
- unsigned *value, char **error, unsigned grouped)
+static int validate_next_arg(const struct dm_arg *arg, struct dm_arg_set *arg_set,
+ unsigned int *value, char **error, unsigned int grouped)
{
const char *arg_str = dm_shift_arg(arg_set);
char dummy;
@@ -752,14 +752,14 @@ static int validate_next_arg(const struct dm_arg *arg,
}
int dm_read_arg(const struct dm_arg *arg, struct dm_arg_set *arg_set,
- unsigned *value, char **error)
+ unsigned int *value, char **error)
{
return validate_next_arg(arg, arg_set, value, error, 0);
}
EXPORT_SYMBOL(dm_read_arg);
int dm_read_arg_group(const struct dm_arg *arg, struct dm_arg_set *arg_set,
- unsigned *value, char **error)
+ unsigned int *value, char **error)
{
return validate_next_arg(arg, arg_set, value, error, 1);
}
@@ -780,7 +780,7 @@ const char *dm_shift_arg(struct dm_arg_set *as)
}
EXPORT_SYMBOL(dm_shift_arg);
-void dm_consume_args(struct dm_arg_set *as, unsigned num_args)
+void dm_consume_args(struct dm_arg_set *as, unsigned int num_args)
{
BUG_ON(as->argc < num_args);
as->argc -= num_args;
@@ -856,7 +856,7 @@ static int device_is_rq_stackable(struct dm_target *ti, struct dm_dev *dev,
static int dm_table_determine_type(struct dm_table *t)
{
- unsigned bio_based = 0, request_based = 0, hybrid = 0;
+ unsigned int bio_based = 0, request_based = 0, hybrid = 0;
struct dm_target *ti;
struct list_head *devices = dm_table_get_devices(t);
enum dm_queue_mode live_md_type = dm_get_md_type(t->md);
@@ -881,8 +881,7 @@ static int dm_table_determine_type(struct dm_table *t)
bio_based = 1;
if (bio_based && request_based) {
- DMERR("Inconsistent table: different target types"
- " can't be mixed up");
+ DMERR("Inconsistent table: different target types can't be mixed up");
return -EINVAL;
}
}
@@ -1185,8 +1184,7 @@ static int dm_table_register_integrity(struct dm_table *t)
* profile the new profile should not conflict.
*/
if (blk_integrity_compare(dm_disk(md), template_disk) < 0) {
- DMERR("%s: conflict with existing integrity profile: "
- "%s profile mismatch",
+ DMERR("%s: conflict with existing integrity profile: %s profile mismatch",
dm_device_name(t->md),
template_disk->disk_name);
return 1;
@@ -1527,7 +1525,7 @@ static bool dm_table_any_dev_attr(struct dm_table *t,
if (ti->type->iterate_devices &&
ti->type->iterate_devices(ti, func, data))
return true;
- }
+ }
return false;
}
@@ -1535,7 +1533,7 @@ static bool dm_table_any_dev_attr(struct dm_table *t,
static int count_device(struct dm_target *ti, struct dm_dev *dev,
sector_t start, sector_t len, void *data)
{
- unsigned *num_devices = data;
+ unsigned int *num_devices = data;
(*num_devices)++;
@@ -1565,7 +1563,7 @@ bool dm_table_has_no_data_devices(struct dm_table *t)
{
for (unsigned int i = 0; i < t->num_targets; i++) {
struct dm_target *ti = dm_table_get_target(t, i);
- unsigned num_devices = 0;
+ unsigned int num_devices = 0;
if (!ti->type->iterate_devices)
return false;
@@ -1708,8 +1706,7 @@ combine_limits:
* for the table.
*/
if (blk_stack_limits(limits, &ti_limits, 0) < 0)
- DMWARN("%s: adding target device "
- "(start sect %llu len %llu) "
+ DMWARN("%s: adding target device (start sect %llu len %llu) "
"caused an alignment inconsistency",
dm_device_name(t->md),
(unsigned long long) ti->begin,
@@ -1971,8 +1968,7 @@ int dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
blk_queue_flag_set(QUEUE_FLAG_DAX, q);
if (dm_table_supports_dax(t, device_not_dax_synchronous_capable))
set_dax_synchronous(t->md->dax_dev);
- }
- else
+ } else
blk_queue_flag_clear(QUEUE_FLAG_DAX, q);
if (dm_table_any_dev_attr(t, device_dax_write_cache_enabled, NULL))
diff --git a/drivers/md/dm-target.c b/drivers/md/dm-target.c
index 8cd5184e62f0..26ea22b1a0d7 100644
--- a/drivers/md/dm-target.c
+++ b/drivers/md/dm-target.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2001 Sistina Software (UK) Limited
*
@@ -92,6 +93,7 @@ int dm_register_target(struct target_type *tt)
up_write(&_lock);
return rv;
}
+EXPORT_SYMBOL(dm_register_target);
void dm_unregister_target(struct target_type *tt)
{
@@ -105,6 +107,7 @@ void dm_unregister_target(struct target_type *tt)
up_write(&_lock);
}
+EXPORT_SYMBOL(dm_unregister_target);
/*
* io-err: always fails an io, useful for bringing
@@ -170,6 +173,3 @@ void dm_target_exit(void)
{
dm_unregister_target(&error_target);
}
-
-EXPORT_SYMBOL(dm_register_target);
-EXPORT_SYMBOL(dm_unregister_target);
diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c
index 6bcc4c4786d8..fd464fb024c3 100644
--- a/drivers/md/dm-thin-metadata.c
+++ b/drivers/md/dm-thin-metadata.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2011-2012 Red Hat, Inc.
*
@@ -14,7 +15,8 @@
#include <linux/device-mapper.h>
#include <linux/workqueue.h>
-/*--------------------------------------------------------------------------
+/*
+ *--------------------------------------------------------------------------
* As far as the metadata goes, there is:
*
* - A superblock in block zero, taking up fewer than 512 bytes for
@@ -70,7 +72,8 @@
*
* All metadata io is in THIN_METADATA_BLOCK_SIZE sized/aligned chunks
* from the block manager.
- *--------------------------------------------------------------------------*/
+ *--------------------------------------------------------------------------
+ */
#define DM_MSG_PREFIX "thin metadata"
@@ -239,10 +242,11 @@ struct dm_thin_device {
uint32_t snapshotted_time;
};
-/*----------------------------------------------------------------
+/*
+ *--------------------------------------------------------------
* superblock validator
- *--------------------------------------------------------------*/
-
+ *--------------------------------------------------------------
+ */
#define SUPERBLOCK_CSUM_XOR 160774
static void sb_prepare_for_write(struct dm_block_validator *v,
@@ -265,15 +269,15 @@ static int sb_check(struct dm_block_validator *v,
__le32 csum_le;
if (dm_block_location(b) != le64_to_cpu(disk_super->blocknr)) {
- DMERR("sb_check failed: blocknr %llu: "
- "wanted %llu", le64_to_cpu(disk_super->blocknr),
+ DMERR("%s failed: blocknr %llu: wanted %llu",
+ __func__, le64_to_cpu(disk_super->blocknr),
(unsigned long long)dm_block_location(b));
return -ENOTBLK;
}
if (le64_to_cpu(disk_super->magic) != THIN_SUPERBLOCK_MAGIC) {
- DMERR("sb_check failed: magic %llu: "
- "wanted %llu", le64_to_cpu(disk_super->magic),
+ DMERR("%s failed: magic %llu: wanted %llu",
+ __func__, le64_to_cpu(disk_super->magic),
(unsigned long long)THIN_SUPERBLOCK_MAGIC);
return -EILSEQ;
}
@@ -282,8 +286,8 @@ static int sb_check(struct dm_block_validator *v,
block_size - sizeof(__le32),
SUPERBLOCK_CSUM_XOR));
if (csum_le != disk_super->csum) {
- DMERR("sb_check failed: csum %u: wanted %u",
- le32_to_cpu(csum_le), le32_to_cpu(disk_super->csum));
+ DMERR("%s failed: csum %u: wanted %u",
+ __func__, le32_to_cpu(csum_le), le32_to_cpu(disk_super->csum));
return -EILSEQ;
}
@@ -296,10 +300,11 @@ static struct dm_block_validator sb_validator = {
.check = sb_check
};
-/*----------------------------------------------------------------
+/*
+ *--------------------------------------------------------------
* Methods for the btree value types
- *--------------------------------------------------------------*/
-
+ *--------------------------------------------------------------
+ */
static uint64_t pack_block_time(dm_block_t b, uint32_t t)
{
return (b << 24) | t;
@@ -318,12 +323,12 @@ static void unpack_block_time(uint64_t v, dm_block_t *b, uint32_t *t)
*/
typedef int (*run_fn)(struct dm_space_map *, dm_block_t, dm_block_t);
-static void with_runs(struct dm_space_map *sm, const __le64 *value_le, unsigned count, run_fn fn)
+static void with_runs(struct dm_space_map *sm, const __le64 *value_le, unsigned int count, run_fn fn)
{
uint64_t b, begin, end;
uint32_t t;
bool in_run = false;
- unsigned i;
+ unsigned int i;
for (i = 0; i < count; i++, value_le++) {
/* We know value_le is 8 byte aligned */
@@ -348,13 +353,13 @@ static void with_runs(struct dm_space_map *sm, const __le64 *value_le, unsigned
fn(sm, begin, end);
}
-static void data_block_inc(void *context, const void *value_le, unsigned count)
+static void data_block_inc(void *context, const void *value_le, unsigned int count)
{
with_runs((struct dm_space_map *) context,
(const __le64 *) value_le, count, dm_sm_inc_blocks);
}
-static void data_block_dec(void *context, const void *value_le, unsigned count)
+static void data_block_dec(void *context, const void *value_le, unsigned int count)
{
with_runs((struct dm_space_map *) context,
(const __le64 *) value_le, count, dm_sm_dec_blocks);
@@ -374,21 +379,21 @@ static int data_block_equal(void *context, const void *value1_le, const void *va
return b1 == b2;
}
-static void subtree_inc(void *context, const void *value, unsigned count)
+static void subtree_inc(void *context, const void *value, unsigned int count)
{
struct dm_btree_info *info = context;
const __le64 *root_le = value;
- unsigned i;
+ unsigned int i;
for (i = 0; i < count; i++, root_le++)
dm_tm_inc(info->tm, le64_to_cpu(*root_le));
}
-static void subtree_dec(void *context, const void *value, unsigned count)
+static void subtree_dec(void *context, const void *value, unsigned int count)
{
struct dm_btree_info *info = context;
const __le64 *root_le = value;
- unsigned i;
+ unsigned int i;
for (i = 0; i < count; i++, root_le++)
if (dm_btree_del(info, le64_to_cpu(*root_le)))
@@ -398,6 +403,7 @@ static void subtree_dec(void *context, const void *value, unsigned count)
static int subtree_equal(void *context, const void *value1_le, const void *value2_le)
{
__le64 v1_le, v2_le;
+
memcpy(&v1_le, value1_le, sizeof(v1_le));
memcpy(&v2_le, value2_le, sizeof(v2_le));
@@ -448,10 +454,10 @@ static int superblock_lock(struct dm_pool_metadata *pmd,
static int __superblock_all_zeroes(struct dm_block_manager *bm, int *result)
{
int r;
- unsigned i;
+ unsigned int i;
struct dm_block *b;
__le64 *data_le, zero = cpu_to_le64(0);
- unsigned block_size = dm_bm_block_size(bm) / sizeof(__le64);
+ unsigned int block_size = dm_bm_block_size(bm) / sizeof(__le64);
/*
* We can't use a validator here - it may be all zeroes.
@@ -971,7 +977,7 @@ struct dm_pool_metadata *dm_pool_metadata_open(struct block_device *bdev,
int dm_pool_metadata_close(struct dm_pool_metadata *pmd)
{
int r;
- unsigned open_devices = 0;
+ unsigned int open_devices = 0;
struct dm_thin_device *td, *tmp;
down_read(&pmd->root_lock);
@@ -1530,9 +1536,9 @@ static int __find_block(struct dm_thin_device *td, dm_block_t block,
dm_block_t keys[2] = { td->id, block };
struct dm_btree_info *info;
- if (can_issue_io) {
+ if (can_issue_io)
info = &pmd->info;
- } else
+ else
info = &pmd->nb_info;
r = dm_btree_lookup(info, pmd->root, keys, &value);
@@ -1606,8 +1612,8 @@ static int __find_mapped_range(struct dm_thin_device *td,
if (r) {
if (r == -ENODATA)
break;
- else
- return r;
+
+ return r;
}
if ((lookup.block != pool_end) ||
@@ -1679,7 +1685,7 @@ int dm_thin_insert_block(struct dm_thin_device *td, dm_block_t block,
static int __remove_range(struct dm_thin_device *td, dm_block_t begin, dm_block_t end)
{
int r;
- unsigned count, total_count = 0;
+ unsigned int count, total_count = 0;
struct dm_pool_metadata *pmd = td->pmd;
dm_block_t keys[1] = { td->id };
__le64 value;
diff --git a/drivers/md/dm-thin-metadata.h b/drivers/md/dm-thin-metadata.h
index 4d7a2caf21d9..2f64f48b5f19 100644
--- a/drivers/md/dm-thin-metadata.h
+++ b/drivers/md/dm-thin-metadata.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2010-2011 Red Hat, Inc.
*
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c
index 64cfcf46881d..6cd105c1cef3 100644
--- a/drivers/md/dm-thin.c
+++ b/drivers/md/dm-thin.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2011-2012 Red Hat UK.
*
@@ -32,7 +33,7 @@
#define COMMIT_PERIOD HZ
#define NO_SPACE_TIMEOUT_SECS 60
-static unsigned no_space_timeout_secs = NO_SPACE_TIMEOUT_SECS;
+static unsigned int no_space_timeout_secs = NO_SPACE_TIMEOUT_SECS;
DECLARE_DM_KCOPYD_THROTTLE_WITH_MODULE_PARM(snapshot_copy_throttle,
"A percentage of time allocated for copy on write");
@@ -254,7 +255,7 @@ struct pool {
struct delayed_work no_space_timeout;
unsigned long last_commit_jiffies;
- unsigned ref_count;
+ unsigned int ref_count;
spinlock_t lock;
struct bio_list deferred_flush_bios;
@@ -293,7 +294,7 @@ static enum pool_mode get_pool_mode(struct pool *pool)
static void notify_of_pool_mode_change(struct pool *pool)
{
- const char *descs[] = {
+ static const char *descs[] = {
"write",
"out-of-data-space",
"read-only",
@@ -1037,6 +1038,7 @@ out:
static void free_discard_mapping(struct dm_thin_new_mapping *m)
{
struct thin_c *tc = m->tc;
+
if (m->cell)
cell_defer_no_holder(tc, m->cell);
mempool_free(m, &tc->pool->mapping_pool);
@@ -1180,9 +1182,9 @@ static void process_prepared_discard_passdown_pt1(struct dm_thin_new_mapping *m)
discard_parent = bio_alloc(NULL, 1, 0, GFP_NOIO);
discard_parent->bi_end_io = passdown_endio;
discard_parent->bi_private = m;
- if (m->maybe_shared)
- passdown_double_checking_shared_status(m, discard_parent);
- else {
+ if (m->maybe_shared)
+ passdown_double_checking_shared_status(m, discard_parent);
+ else {
struct discard_op op;
begin_discard(&op, tc, discard_parent);
@@ -2159,7 +2161,7 @@ static void process_thin_deferred_bios(struct thin_c *tc)
struct bio *bio;
struct bio_list bios;
struct blk_plug plug;
- unsigned count = 0;
+ unsigned int count = 0;
if (tc->requeue_mode) {
error_thin_bio_list(tc, &tc->deferred_bio_list,
@@ -2207,6 +2209,7 @@ static void process_thin_deferred_bios(struct thin_c *tc)
throttle_work_update(&pool->throttle);
dm_pool_issue_prefetches(pool->pmd);
}
+ cond_resched();
}
blk_finish_plug(&plug);
}
@@ -2228,9 +2231,9 @@ static int cmp_cells(const void *lhs, const void *rhs)
return 0;
}
-static unsigned sort_cells(struct pool *pool, struct list_head *cells)
+static unsigned int sort_cells(struct pool *pool, struct list_head *cells)
{
- unsigned count = 0;
+ unsigned int count = 0;
struct dm_bio_prison_cell *cell, *tmp;
list_for_each_entry_safe(cell, tmp, cells, user_list) {
@@ -2251,7 +2254,7 @@ static void process_thin_deferred_cells(struct thin_c *tc)
struct pool *pool = tc->pool;
struct list_head cells;
struct dm_bio_prison_cell *cell;
- unsigned i, j, count;
+ unsigned int i, j, count;
INIT_LIST_HEAD(&cells);
@@ -2289,6 +2292,7 @@ static void process_thin_deferred_cells(struct thin_c *tc)
else
pool->process_cell(tc, cell);
}
+ cond_resched();
} while (!list_empty(&cells));
}
@@ -2411,6 +2415,7 @@ static void do_worker(struct work_struct *ws)
static void do_waker(struct work_struct *ws)
{
struct pool *pool = container_of(to_delayed_work(ws), struct pool, waker);
+
wake_worker(pool);
queue_delayed_work(pool->wq, &pool->waker, COMMIT_PERIOD);
}
@@ -2473,6 +2478,7 @@ static struct noflush_work *to_noflush(struct work_struct *ws)
static void do_noflush_start(struct work_struct *ws)
{
struct noflush_work *w = to_noflush(ws);
+
w->tc->requeue_mode = true;
requeue_io(w->tc);
pool_work_complete(&w->pw);
@@ -2481,6 +2487,7 @@ static void do_noflush_start(struct work_struct *ws)
static void do_noflush_stop(struct work_struct *ws)
{
struct noflush_work *w = to_noflush(ws);
+
w->tc->requeue_mode = false;
pool_work_complete(&w->pw);
}
@@ -2799,9 +2806,11 @@ static void requeue_bios(struct pool *pool)
rcu_read_unlock();
}
-/*----------------------------------------------------------------
+/*
+ *--------------------------------------------------------------
* Binding of control targets to a pool object
- *--------------------------------------------------------------*/
+ *--------------------------------------------------------------
+ */
static bool is_factor(sector_t block_size, uint32_t n)
{
return !sector_div(block_size, n);
@@ -2865,9 +2874,11 @@ static void unbind_control_target(struct pool *pool, struct dm_target *ti)
pool->ti = NULL;
}
-/*----------------------------------------------------------------
+/*
+ *--------------------------------------------------------------
* Pool creation
- *--------------------------------------------------------------*/
+ *--------------------------------------------------------------
+ */
/* Initialize pool features. */
static void pool_features_init(struct pool_features *pf)
{
@@ -3091,9 +3102,11 @@ static struct pool *__pool_find(struct mapped_device *pool_md,
return pool;
}
-/*----------------------------------------------------------------
+/*
+ *--------------------------------------------------------------
* Pool target methods
- *--------------------------------------------------------------*/
+ *--------------------------------------------------------------
+ */
static void pool_dtr(struct dm_target *ti)
{
struct pool_c *pt = ti->private;
@@ -3113,7 +3126,7 @@ static int parse_pool_features(struct dm_arg_set *as, struct pool_features *pf,
struct dm_target *ti)
{
int r;
- unsigned argc;
+ unsigned int argc;
const char *arg_name;
static const struct dm_arg _args[] = {
@@ -3234,6 +3247,7 @@ static dm_block_t calc_metadata_threshold(struct pool_c *pt)
* delete after you've grown the device).
*/
dm_block_t quarter = get_metadata_dev_size_in_blocks(pt->metadata_dev->bdev) / 4;
+
return min((dm_block_t)1024ULL /* 4M */, quarter);
}
@@ -3250,7 +3264,7 @@ static dm_block_t calc_metadata_threshold(struct pool_c *pt)
* read_only: Don't allow any changes to be made to the pool metadata.
* error_if_no_space: error IOs, instead of queueing, if no space.
*/
-static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
+static int pool_ctr(struct dm_target *ti, unsigned int argc, char **argv)
{
int r, pool_created = 0;
struct pool_c *pt;
@@ -3645,7 +3659,7 @@ static void pool_postsuspend(struct dm_target *ti)
(void) commit(pool);
}
-static int check_arg_count(unsigned argc, unsigned args_required)
+static int check_arg_count(unsigned int argc, unsigned int args_required)
{
if (argc != args_required) {
DMWARN("Message received with %u arguments instead of %u.",
@@ -3668,7 +3682,7 @@ static int read_dev_id(char *arg, dm_thin_id *dev_id, int warning)
return -EINVAL;
}
-static int process_create_thin_mesg(unsigned argc, char **argv, struct pool *pool)
+static int process_create_thin_mesg(unsigned int argc, char **argv, struct pool *pool)
{
dm_thin_id dev_id;
int r;
@@ -3691,7 +3705,7 @@ static int process_create_thin_mesg(unsigned argc, char **argv, struct pool *poo
return 0;
}
-static int process_create_snap_mesg(unsigned argc, char **argv, struct pool *pool)
+static int process_create_snap_mesg(unsigned int argc, char **argv, struct pool *pool)
{
dm_thin_id dev_id;
dm_thin_id origin_dev_id;
@@ -3719,7 +3733,7 @@ static int process_create_snap_mesg(unsigned argc, char **argv, struct pool *poo
return 0;
}
-static int process_delete_mesg(unsigned argc, char **argv, struct pool *pool)
+static int process_delete_mesg(unsigned int argc, char **argv, struct pool *pool)
{
dm_thin_id dev_id;
int r;
@@ -3739,7 +3753,7 @@ static int process_delete_mesg(unsigned argc, char **argv, struct pool *pool)
return r;
}
-static int process_set_transaction_id_mesg(unsigned argc, char **argv, struct pool *pool)
+static int process_set_transaction_id_mesg(unsigned int argc, char **argv, struct pool *pool)
{
dm_thin_id old_id, new_id;
int r;
@@ -3768,7 +3782,7 @@ static int process_set_transaction_id_mesg(unsigned argc, char **argv, struct po
return 0;
}
-static int process_reserve_metadata_snap_mesg(unsigned argc, char **argv, struct pool *pool)
+static int process_reserve_metadata_snap_mesg(unsigned int argc, char **argv, struct pool *pool)
{
int r;
@@ -3785,7 +3799,7 @@ static int process_reserve_metadata_snap_mesg(unsigned argc, char **argv, struct
return r;
}
-static int process_release_metadata_snap_mesg(unsigned argc, char **argv, struct pool *pool)
+static int process_release_metadata_snap_mesg(unsigned int argc, char **argv, struct pool *pool)
{
int r;
@@ -3809,8 +3823,8 @@ static int process_release_metadata_snap_mesg(unsigned argc, char **argv, struct
* reserve_metadata_snap
* release_metadata_snap
*/
-static int pool_message(struct dm_target *ti, unsigned argc, char **argv,
- char *result, unsigned maxlen)
+static int pool_message(struct dm_target *ti, unsigned int argc, char **argv,
+ char *result, unsigned int maxlen)
{
int r = -EINVAL;
struct pool_c *pt = ti->private;
@@ -3850,9 +3864,9 @@ static int pool_message(struct dm_target *ti, unsigned argc, char **argv,
}
static void emit_flags(struct pool_features *pf, char *result,
- unsigned sz, unsigned maxlen)
+ unsigned int sz, unsigned int maxlen)
{
- unsigned count = !pf->zero_new_blocks + !pf->discard_enabled +
+ unsigned int count = !pf->zero_new_blocks + !pf->discard_enabled +
!pf->discard_passdown + (pf->mode == PM_READ_ONLY) +
pf->error_if_no_space;
DMEMIT("%u ", count);
@@ -3880,10 +3894,10 @@ static void emit_flags(struct pool_features *pf, char *result,
* <pool mode> <discard config> <no space config> <needs_check>
*/
static void pool_status(struct dm_target *ti, status_type_t type,
- unsigned status_flags, char *result, unsigned maxlen)
+ unsigned int status_flags, char *result, unsigned int maxlen)
{
int r;
- unsigned sz = 0;
+ unsigned int sz = 0;
uint64_t transaction_id;
dm_block_t nr_free_blocks_data;
dm_block_t nr_free_blocks_metadata;
@@ -4095,9 +4109,11 @@ static struct target_type pool_target = {
.io_hints = pool_io_hints,
};
-/*----------------------------------------------------------------
+/*
+ *--------------------------------------------------------------
* Thin target methods
- *--------------------------------------------------------------*/
+ *--------------------------------------------------------------
+ */
static void thin_get(struct thin_c *tc)
{
refcount_inc(&tc->refcount);
@@ -4145,7 +4161,7 @@ static void thin_dtr(struct dm_target *ti)
* If the pool device has discards disabled, they get disabled for the thin
* device as well.
*/
-static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
+static int thin_ctr(struct dm_target *ti, unsigned int argc, char **argv)
{
int r;
struct thin_c *tc;
@@ -4367,7 +4383,7 @@ static int thin_preresume(struct dm_target *ti)
* <nr mapped sectors> <highest mapped sector>
*/
static void thin_status(struct dm_target *ti, status_type_t type,
- unsigned status_flags, char *result, unsigned maxlen)
+ unsigned int status_flags, char *result, unsigned int maxlen)
{
int r;
ssize_t sz = 0;
@@ -4518,7 +4534,7 @@ static void dm_thin_exit(void)
module_init(dm_thin_init);
module_exit(dm_thin_exit);
-module_param_named(no_space_timeout, no_space_timeout_secs, uint, S_IRUGO | S_IWUSR);
+module_param_named(no_space_timeout, no_space_timeout_secs, uint, 0644);
MODULE_PARM_DESC(no_space_timeout, "Out of data space queue IO timeout in seconds");
MODULE_DESCRIPTION(DM_NAME " thin provisioning target");
diff --git a/drivers/md/dm-uevent.c b/drivers/md/dm-uevent.c
index 8671267200d8..491738263292 100644
--- a/drivers/md/dm-uevent.c
+++ b/drivers/md/dm-uevent.c
@@ -3,7 +3,7 @@
* Device Mapper Uevent Support (dm-uevent)
*
* Copyright IBM Corporation, 2007
- * Author: Mike Anderson <andmike@linux.vnet.ibm.com>
+ * Author: Mike Anderson <andmike@linux.vnet.ibm.com>
*/
#include <linux/list.h>
#include <linux/slab.h>
@@ -60,7 +60,7 @@ static struct dm_uevent *dm_build_path_uevent(struct mapped_device *md,
enum kobject_action action,
const char *dm_action,
const char *path,
- unsigned nr_valid_paths)
+ unsigned int nr_valid_paths)
{
struct dm_uevent *event;
@@ -168,7 +168,7 @@ EXPORT_SYMBOL_GPL(dm_send_uevents);
*
*/
void dm_path_uevent(enum dm_uevent_type event_type, struct dm_target *ti,
- const char *path, unsigned nr_valid_paths)
+ const char *path, unsigned int nr_valid_paths)
{
struct mapped_device *md = dm_table_get_md(ti->table);
struct dm_uevent *event;
diff --git a/drivers/md/dm-uevent.h b/drivers/md/dm-uevent.h
index d30d226f2a18..12a5d4fb7d44 100644
--- a/drivers/md/dm-uevent.h
+++ b/drivers/md/dm-uevent.h
@@ -3,7 +3,7 @@
* Device Mapper Uevent Support
*
* Copyright IBM Corporation, 2007
- * Author: Mike Anderson <andmike@linux.vnet.ibm.com>
+ * Author: Mike Anderson <andmike@linux.vnet.ibm.com>
*/
#ifndef DM_UEVENT_H
#define DM_UEVENT_H
@@ -20,7 +20,7 @@ extern void dm_uevent_exit(void);
extern void dm_send_uevents(struct list_head *events, struct kobject *kobj);
extern void dm_path_uevent(enum dm_uevent_type event_type,
struct dm_target *ti, const char *path,
- unsigned nr_valid_paths);
+ unsigned int nr_valid_paths);
#else
@@ -37,7 +37,7 @@ static inline void dm_send_uevents(struct list_head *events,
}
static inline void dm_path_uevent(enum dm_uevent_type event_type,
struct dm_target *ti, const char *path,
- unsigned nr_valid_paths)
+ unsigned int nr_valid_paths)
{
}
diff --git a/drivers/md/dm-unstripe.c b/drivers/md/dm-unstripe.c
index fdc8921e5c19..e7b7d5983a16 100644
--- a/drivers/md/dm-unstripe.c
+++ b/drivers/md/dm-unstripe.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2017 Intel Corporation.
*
diff --git a/drivers/md/dm-verity-fec.c b/drivers/md/dm-verity-fec.c
index 23cffce56403..962fc32c947c 100644
--- a/drivers/md/dm-verity-fec.c
+++ b/drivers/md/dm-verity-fec.c
@@ -59,14 +59,14 @@ static int fec_decode_rs8(struct dm_verity *v, struct dm_verity_fec_io *fio,
* to the data block. Caller is responsible for releasing buf.
*/
static u8 *fec_read_parity(struct dm_verity *v, u64 rsb, int index,
- unsigned *offset, struct dm_buffer **buf)
+ unsigned int *offset, struct dm_buffer **buf)
{
u64 position, block, rem;
u8 *res;
position = (index + rsb) * v->fec->roots;
block = div64_u64_rem(position, v->fec->io_size, &rem);
- *offset = (unsigned)rem;
+ *offset = (unsigned int)rem;
res = dm_bufio_read(v->fec->bufio, block, buf);
if (IS_ERR(res)) {
@@ -102,7 +102,7 @@ static u8 *fec_read_parity(struct dm_verity *v, u64 rsb, int index,
*/
static inline u8 *fec_buffer_rs_block(struct dm_verity *v,
struct dm_verity_fec_io *fio,
- unsigned i, unsigned j)
+ unsigned int i, unsigned int j)
{
return &fio->bufs[i][j * v->fec->rsn];
}
@@ -111,7 +111,7 @@ static inline u8 *fec_buffer_rs_block(struct dm_verity *v,
* Return an index to the current RS block when called inside
* fec_for_each_buffer_rs_block.
*/
-static inline unsigned fec_buffer_rs_index(unsigned i, unsigned j)
+static inline unsigned int fec_buffer_rs_index(unsigned int i, unsigned int j)
{
return (i << DM_VERITY_FEC_BUF_RS_BITS) + j;
}
@@ -121,12 +121,12 @@ static inline unsigned fec_buffer_rs_index(unsigned i, unsigned j)
* starting from block_offset.
*/
static int fec_decode_bufs(struct dm_verity *v, struct dm_verity_fec_io *fio,
- u64 rsb, int byte_index, unsigned block_offset,
+ u64 rsb, int byte_index, unsigned int block_offset,
int neras)
{
int r, corrected = 0, res;
struct dm_buffer *buf;
- unsigned n, i, offset;
+ unsigned int n, i, offset;
u8 *par, *block;
par = fec_read_parity(v, rsb, block_offset, &offset, &buf);
@@ -197,7 +197,7 @@ static int fec_is_erasure(struct dm_verity *v, struct dm_verity_io *io,
* fits into buffers. Check for erasure locations if @neras is non-NULL.
*/
static int fec_read_bufs(struct dm_verity *v, struct dm_verity_io *io,
- u64 rsb, u64 target, unsigned block_offset,
+ u64 rsb, u64 target, unsigned int block_offset,
int *neras)
{
bool is_zero;
@@ -208,7 +208,7 @@ static int fec_read_bufs(struct dm_verity *v, struct dm_verity_io *io,
u64 block, ileaved;
u8 *bbuf, *rs_block;
u8 want_digest[HASH_MAX_DIGESTSIZE];
- unsigned n, k;
+ unsigned int n, k;
if (neras)
*neras = 0;
@@ -304,7 +304,7 @@ done:
*/
static int fec_alloc_bufs(struct dm_verity *v, struct dm_verity_fec_io *fio)
{
- unsigned n;
+ unsigned int n;
if (!fio->rs)
fio->rs = mempool_alloc(&v->fec->rs_pool, GFP_NOIO);
@@ -344,7 +344,7 @@ static int fec_alloc_bufs(struct dm_verity *v, struct dm_verity_fec_io *fio)
*/
static void fec_init_bufs(struct dm_verity *v, struct dm_verity_fec_io *fio)
{
- unsigned n;
+ unsigned int n;
fec_for_each_buffer(fio, n)
memset(fio->bufs[n], 0, v->fec->rsn << DM_VERITY_FEC_BUF_RS_BITS);
@@ -362,7 +362,7 @@ static int fec_decode_rsb(struct dm_verity *v, struct dm_verity_io *io,
bool use_erasures)
{
int r, neras = 0;
- unsigned pos;
+ unsigned int pos;
r = fec_alloc_bufs(v, fio);
if (unlikely(r < 0))
@@ -484,7 +484,7 @@ done:
*/
void verity_fec_finish_io(struct dm_verity_io *io)
{
- unsigned n;
+ unsigned int n;
struct dm_verity_fec *f = io->v->fec;
struct dm_verity_fec_io *fio = fec_io(io);
@@ -522,8 +522,8 @@ void verity_fec_init_io(struct dm_verity_io *io)
/*
* Append feature arguments and values to the status table.
*/
-unsigned verity_fec_status_table(struct dm_verity *v, unsigned sz,
- char *result, unsigned maxlen)
+unsigned int verity_fec_status_table(struct dm_verity *v, unsigned int sz,
+ char *result, unsigned int maxlen)
{
if (!verity_fec_is_enabled(v))
return sz;
@@ -589,7 +589,7 @@ bool verity_is_fec_opt_arg(const char *arg_name)
}
int verity_fec_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v,
- unsigned *argc, const char *arg_name)
+ unsigned int *argc, const char *arg_name)
{
int r;
struct dm_target *ti = v->ti;
diff --git a/drivers/md/dm-verity-fec.h b/drivers/md/dm-verity-fec.h
index 3c46c8d61883..8454070d2824 100644
--- a/drivers/md/dm-verity-fec.h
+++ b/drivers/md/dm-verity-fec.h
@@ -55,10 +55,10 @@ struct dm_verity_fec_io {
struct rs_control *rs; /* Reed-Solomon state */
int erasures[DM_VERITY_FEC_MAX_RSN]; /* erasures for decode_rs8 */
u8 *bufs[DM_VERITY_FEC_BUF_MAX]; /* bufs for deinterleaving */
- unsigned nbufs; /* number of buffers allocated */
+ unsigned int nbufs; /* number of buffers allocated */
u8 *output; /* buffer for corrected output */
size_t output_pos;
- unsigned level; /* recursion level */
+ unsigned int level; /* recursion level */
};
#ifdef CONFIG_DM_VERITY_FEC
@@ -72,15 +72,15 @@ extern int verity_fec_decode(struct dm_verity *v, struct dm_verity_io *io,
enum verity_block_type type, sector_t block,
u8 *dest, struct bvec_iter *iter);
-extern unsigned verity_fec_status_table(struct dm_verity *v, unsigned sz,
- char *result, unsigned maxlen);
+extern unsigned int verity_fec_status_table(struct dm_verity *v, unsigned int sz,
+ char *result, unsigned int maxlen);
extern void verity_fec_finish_io(struct dm_verity_io *io);
extern void verity_fec_init_io(struct dm_verity_io *io);
extern bool verity_is_fec_opt_arg(const char *arg_name);
extern int verity_fec_parse_opt_args(struct dm_arg_set *as,
- struct dm_verity *v, unsigned *argc,
+ struct dm_verity *v, unsigned int *argc,
const char *arg_name);
extern void verity_fec_dtr(struct dm_verity *v);
@@ -106,9 +106,9 @@ static inline int verity_fec_decode(struct dm_verity *v,
return -EOPNOTSUPP;
}
-static inline unsigned verity_fec_status_table(struct dm_verity *v,
- unsigned sz, char *result,
- unsigned maxlen)
+static inline unsigned int verity_fec_status_table(struct dm_verity *v,
+ unsigned int sz, char *result,
+ unsigned int maxlen)
{
return sz;
}
@@ -128,7 +128,7 @@ static inline bool verity_is_fec_opt_arg(const char *arg_name)
static inline int verity_fec_parse_opt_args(struct dm_arg_set *as,
struct dm_verity *v,
- unsigned *argc,
+ unsigned int *argc,
const char *arg_name)
{
return -EINVAL;
diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c
index ccf5b852fbf7..ade83ef3b439 100644
--- a/drivers/md/dm-verity-target.c
+++ b/drivers/md/dm-verity-target.c
@@ -41,9 +41,9 @@
#define DM_VERITY_OPTS_MAX (4 + DM_VERITY_OPTS_FEC + \
DM_VERITY_ROOT_HASH_VERIFICATION_OPTS)
-static unsigned dm_verity_prefetch_cluster = DM_VERITY_DEFAULT_PREFETCH_SIZE;
+static unsigned int dm_verity_prefetch_cluster = DM_VERITY_DEFAULT_PREFETCH_SIZE;
-module_param_named(prefetch_cluster, dm_verity_prefetch_cluster, uint, S_IRUGO | S_IWUSR);
+module_param_named(prefetch_cluster, dm_verity_prefetch_cluster, uint, 0644);
static DEFINE_STATIC_KEY_FALSE(use_tasklet_enabled);
@@ -51,7 +51,7 @@ struct dm_verity_prefetch_work {
struct work_struct work;
struct dm_verity *v;
sector_t block;
- unsigned n_blocks;
+ unsigned int n_blocks;
};
/*
@@ -110,22 +110,24 @@ static int verity_hash_update(struct dm_verity *v, struct ahash_request *req,
sg_init_one(&sg, data, len);
ahash_request_set_crypt(req, &sg, NULL, len);
return crypto_wait_req(crypto_ahash_update(req), wait);
- } else {
- do {
- int r;
- size_t this_step = min_t(size_t, len, PAGE_SIZE - offset_in_page(data));
- flush_kernel_vmap_range((void *)data, this_step);
- sg_init_table(&sg, 1);
- sg_set_page(&sg, vmalloc_to_page(data), this_step, offset_in_page(data));
- ahash_request_set_crypt(req, &sg, NULL, this_step);
- r = crypto_wait_req(crypto_ahash_update(req), wait);
- if (unlikely(r))
- return r;
- data += this_step;
- len -= this_step;
- } while (len);
- return 0;
}
+
+ do {
+ int r;
+ size_t this_step = min_t(size_t, len, PAGE_SIZE - offset_in_page(data));
+
+ flush_kernel_vmap_range((void *)data, this_step);
+ sg_init_table(&sg, 1);
+ sg_set_page(&sg, vmalloc_to_page(data), this_step, offset_in_page(data));
+ ahash_request_set_crypt(req, &sg, NULL, this_step);
+ r = crypto_wait_req(crypto_ahash_update(req), wait);
+ if (unlikely(r))
+ return r;
+ data += this_step;
+ len -= this_step;
+ } while (len);
+
+ return 0;
}
/*
@@ -164,7 +166,7 @@ static int verity_hash_final(struct dm_verity *v, struct ahash_request *req,
r = verity_hash_update(v, req, v->salt, v->salt_size, wait);
if (r < 0) {
- DMERR("verity_hash_final failed updating salt: %d", r);
+ DMERR("%s failed updating salt: %d", __func__, r);
goto out;
}
}
@@ -196,10 +198,10 @@ out:
}
static void verity_hash_at_level(struct dm_verity *v, sector_t block, int level,
- sector_t *hash_block, unsigned *offset)
+ sector_t *hash_block, unsigned int *offset)
{
sector_t position = verity_position_at_level(v, block, level);
- unsigned idx;
+ unsigned int idx;
*hash_block = v->hash_level_block[level] + (position >> v->hash_per_block_bits);
@@ -287,7 +289,7 @@ static int verity_verify_level(struct dm_verity *v, struct dm_verity_io *io,
u8 *data;
int r;
sector_t hash_block;
- unsigned offset;
+ unsigned int offset;
verity_hash_at_level(v, block, level, &hash_block, &offset);
@@ -332,10 +334,8 @@ static int verity_verify_level(struct dm_verity *v, struct dm_verity_io *io,
*/
r = -EAGAIN;
goto release_ret_r;
- }
- else if (verity_fec_decode(v, io,
- DM_VERITY_BLOCK_TYPE_METADATA,
- hash_block, data, NULL) == 0)
+ } else if (verity_fec_decode(v, io, DM_VERITY_BLOCK_TYPE_METADATA,
+ hash_block, data, NULL) == 0)
aux->hash_verified = 1;
else if (verity_handle_err(v,
DM_VERITY_BLOCK_TYPE_METADATA,
@@ -424,7 +424,7 @@ static int verity_for_io_block(struct dm_verity *v, struct dm_verity_io *io,
r = crypto_wait_req(crypto_ahash_update(req), wait);
if (unlikely(r < 0)) {
- DMERR("verity_for_io_block crypto op failed: %d", r);
+ DMERR("%s crypto op failed: %d", __func__, r);
return r;
}
@@ -445,13 +445,13 @@ int verity_for_bv_block(struct dm_verity *v, struct dm_verity_io *io,
struct dm_verity_io *io, u8 *data,
size_t len))
{
- unsigned todo = 1 << v->data_dev_block_bits;
+ unsigned int todo = 1 << v->data_dev_block_bits;
struct bio *bio = dm_bio_from_per_bio_data(io, v->ti->per_io_data_size);
do {
int r;
u8 *page;
- unsigned len;
+ unsigned int len;
struct bio_vec bv = bio_iter_iovec(bio, *iter);
page = bvec_kmap_local(&bv);
@@ -685,10 +685,12 @@ static void verity_prefetch_io(struct work_struct *work)
for (i = v->levels - 2; i >= 0; i--) {
sector_t hash_block_start;
sector_t hash_block_end;
+
verity_hash_at_level(v, pw->block, i, &hash_block_start, NULL);
verity_hash_at_level(v, pw->block + pw->n_blocks - 1, i, &hash_block_end, NULL);
+
if (!i) {
- unsigned cluster = READ_ONCE(dm_verity_prefetch_cluster);
+ unsigned int cluster = READ_ONCE(dm_verity_prefetch_cluster);
cluster >>= v->data_dev_block_bits;
if (unlikely(!cluster))
@@ -753,7 +755,7 @@ static int verity_map(struct dm_target *ti, struct bio *bio)
bio_set_dev(bio, v->data_dev->bdev);
bio->bi_iter.bi_sector = verity_map_sector(v, bio->bi_iter.bi_sector);
- if (((unsigned)bio->bi_iter.bi_sector | bio_sectors(bio)) &
+ if (((unsigned int)bio->bi_iter.bi_sector | bio_sectors(bio)) &
((1 << (v->data_dev_block_bits - SECTOR_SHIFT)) - 1)) {
DMERR_LIMIT("unaligned io");
return DM_MAPIO_KILL;
@@ -789,12 +791,12 @@ static int verity_map(struct dm_target *ti, struct bio *bio)
* Status: V (valid) or C (corruption found)
*/
static void verity_status(struct dm_target *ti, status_type_t type,
- unsigned status_flags, char *result, unsigned maxlen)
+ unsigned int status_flags, char *result, unsigned int maxlen)
{
struct dm_verity *v = ti->private;
- unsigned args = 0;
- unsigned sz = 0;
- unsigned x;
+ unsigned int args = 0;
+ unsigned int sz = 0;
+ unsigned int x;
switch (type) {
case STATUSTYPE_INFO:
@@ -1054,7 +1056,7 @@ static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v,
bool only_modifier_opts)
{
int r = 0;
- unsigned argc;
+ unsigned int argc;
struct dm_target *ti = v->ti;
const char *arg_name;
@@ -1156,13 +1158,12 @@ static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v,
* <digest>
* <salt> Hex string or "-" if no salt.
*/
-static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
+static int verity_ctr(struct dm_target *ti, unsigned int argc, char **argv)
{
struct dm_verity *v;
struct dm_verity_sig_opts verify_args = {0};
struct dm_arg_set as;
unsigned int num;
- unsigned int wq_flags;
unsigned long long num_ll;
int r;
int i;
@@ -1370,6 +1371,7 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
hash_position = v->hash_start;
for (i = v->levels - 1; i >= 0; i--) {
sector_t s;
+
v->hash_level_block[i] = hash_position;
s = (v->data_blocks + ((sector_t)1 << ((i + 1) * v->hash_per_block_bits)) - 1)
>> ((i + 1) * v->hash_per_block_bits);
@@ -1399,8 +1401,6 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
goto bad;
}
- /* WQ_UNBOUND greatly improves performance when running on ramdisk */
- wq_flags = WQ_MEM_RECLAIM | WQ_UNBOUND;
/*
* Using WQ_HIGHPRI improves throughput and completion latency by
* reducing wait times when reading from a dm-verity device.
@@ -1410,8 +1410,7 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
* will fall-back to using it for error handling (or if the bufio cache
* doesn't have required hashes).
*/
- wq_flags |= WQ_HIGHPRI;
- v->verify_wq = alloc_workqueue("kverityd", wq_flags, num_online_cpus());
+ v->verify_wq = alloc_workqueue("kverityd", WQ_MEM_RECLAIM | WQ_HIGHPRI, 0);
if (!v->verify_wq) {
ti->error = "Cannot allocate workqueue";
r = -ENOMEM;
diff --git a/drivers/md/dm-verity-verify-sig.c b/drivers/md/dm-verity-verify-sig.c
index db61a1f43ae9..4836508ea50c 100644
--- a/drivers/md/dm-verity-verify-sig.c
+++ b/drivers/md/dm-verity-verify-sig.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2019 Microsoft Corporation.
*
diff --git a/drivers/md/dm-verity-verify-sig.h b/drivers/md/dm-verity-verify-sig.h
index 3987c7141f79..f36ea92127bf 100644
--- a/drivers/md/dm-verity-verify-sig.h
+++ b/drivers/md/dm-verity-verify-sig.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2019 Microsoft Corporation.
*
diff --git a/drivers/md/dm-verity.h b/drivers/md/dm-verity.h
index 98f306ec6a33..2f555b420367 100644
--- a/drivers/md/dm-verity.h
+++ b/drivers/md/dm-verity.h
@@ -42,7 +42,7 @@ struct dm_verity {
u8 *root_digest; /* digest of the root block */
u8 *salt; /* salt: its size is salt_size */
u8 *zero_digest; /* digest for a zero block */
- unsigned salt_size;
+ unsigned int salt_size;
sector_t data_start; /* data offset in 512-byte sectors */
sector_t hash_start; /* hash start in blocks */
sector_t data_blocks; /* the number of data blocks */
@@ -54,10 +54,10 @@ struct dm_verity {
unsigned char version;
bool hash_failed:1; /* set if hash of any block failed */
bool use_tasklet:1; /* try to verify in tasklet before work-queue */
- unsigned digest_size; /* digest size for the current hash algorithm */
+ unsigned int digest_size; /* digest size for the current hash algorithm */
unsigned int ahash_reqsize;/* the size of temporary space for crypto */
enum verity_mode mode; /* mode for handling verification errors */
- unsigned corrupted_errs;/* Number of errors for corrupted blocks */
+ unsigned int corrupted_errs;/* Number of errors for corrupted blocks */
struct workqueue_struct *verify_wq;
@@ -77,7 +77,7 @@ struct dm_verity_io {
bio_end_io_t *orig_bi_end_io;
sector_t block;
- unsigned n_blocks;
+ unsigned int n_blocks;
bool in_tasklet;
struct bvec_iter iter;
diff --git a/drivers/md/dm-writecache.c b/drivers/md/dm-writecache.c
index 96a003eb7323..3aa5874f0aef 100644
--- a/drivers/md/dm-writecache.c
+++ b/drivers/md/dm-writecache.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2018 Red Hat. All rights reserved.
*
@@ -83,16 +83,13 @@ struct wc_entry {
struct rb_node rb_node;
struct list_head lru;
unsigned short wc_list_contiguous;
- bool write_in_progress
#if BITS_PER_LONG == 64
- :1
-#endif
- ;
- unsigned long index
-#if BITS_PER_LONG == 64
- :47
+ bool write_in_progress : 1;
+ unsigned long index : 47;
+#else
+ bool write_in_progress;
+ unsigned long index;
#endif
- ;
unsigned long age;
#ifdef DM_WRITECACHE_HANDLE_HARDWARE_ERRORS
uint64_t original_sector;
@@ -128,9 +125,9 @@ struct dm_writecache {
unsigned long max_age;
unsigned long pause;
- unsigned uncommitted_blocks;
- unsigned autocommit_blocks;
- unsigned max_writeback_jobs;
+ unsigned int uncommitted_blocks;
+ unsigned int autocommit_blocks;
+ unsigned int max_writeback_jobs;
int error;
@@ -155,7 +152,7 @@ struct dm_writecache {
sector_t data_device_sectors;
void *block_start;
struct wc_entry *entries;
- unsigned block_size;
+ unsigned int block_size;
unsigned char block_size_bits;
bool pmem_mode:1;
@@ -178,13 +175,13 @@ struct dm_writecache {
bool metadata_only:1;
bool pause_set:1;
- unsigned high_wm_percent_value;
- unsigned low_wm_percent_value;
- unsigned autocommit_time_value;
- unsigned max_age_value;
- unsigned pause_value;
+ unsigned int high_wm_percent_value;
+ unsigned int low_wm_percent_value;
+ unsigned int autocommit_time_value;
+ unsigned int max_age_value;
+ unsigned int pause_value;
- unsigned writeback_all;
+ unsigned int writeback_all;
struct workqueue_struct *writeback_wq;
struct work_struct writeback_work;
struct work_struct flush_work;
@@ -202,7 +199,7 @@ struct dm_writecache {
struct dm_kcopyd_client *dm_kcopyd;
unsigned long *dirty_bitmap;
- unsigned dirty_bitmap_size;
+ unsigned int dirty_bitmap_size;
struct bio_set bio_set;
mempool_t copy_pool;
@@ -227,7 +224,7 @@ struct writeback_struct {
struct list_head endio_entry;
struct dm_writecache *wc;
struct wc_entry **wc_list;
- unsigned wc_list_n;
+ unsigned int wc_list_n;
struct wc_entry *wc_list_inline[WB_LIST_INLINE];
struct bio bio;
};
@@ -236,7 +233,7 @@ struct copy_struct {
struct list_head endio_entry;
struct dm_writecache *wc;
struct wc_entry *e;
- unsigned n_entries;
+ unsigned int n_entries;
int error;
};
@@ -300,6 +297,7 @@ static int persistent_memory_claim(struct dm_writecache *wc)
}
if (da != p) {
long i;
+
wc->memory_map = NULL;
pages = kvmalloc_array(p, sizeof(struct page *), GFP_KERNEL);
if (!pages) {
@@ -309,6 +307,7 @@ static int persistent_memory_claim(struct dm_writecache *wc)
i = 0;
do {
long daa;
+
daa = dax_direct_access(wc->ssd_dev->dax_dev, offset + i,
p - i, DAX_ACCESS, NULL, &pfn);
if (daa <= 0) {
@@ -369,7 +368,7 @@ static struct page *persistent_memory_page(void *addr)
return virt_to_page(addr);
}
-static unsigned persistent_memory_page_offset(void *addr)
+static unsigned int persistent_memory_page_offset(void *addr)
{
return (unsigned long)addr & (PAGE_SIZE - 1);
}
@@ -502,11 +501,12 @@ static void ssd_commit_flushed(struct dm_writecache *wc, bool wait_for_ios)
COMPLETION_INITIALIZER_ONSTACK(endio.c),
ATOMIC_INIT(1),
};
- unsigned bitmap_bits = wc->dirty_bitmap_size * 8;
- unsigned i = 0;
+ unsigned int bitmap_bits = wc->dirty_bitmap_size * 8;
+ unsigned int i = 0;
while (1) {
- unsigned j;
+ unsigned int j;
+
i = find_next_bit(wc->dirty_bitmap, bitmap_bits, i);
if (unlikely(i == bitmap_bits))
break;
@@ -531,7 +531,7 @@ static void ssd_commit_flushed(struct dm_writecache *wc, bool wait_for_ios)
req.notify.context = &endio;
/* writing via async dm-io (implied by notify.fn above) won't return an error */
- (void) dm_io(&req, 1, &region, NULL);
+ (void) dm_io(&req, 1, &region, NULL);
i = j;
}
@@ -623,20 +623,21 @@ static struct wc_entry *writecache_find_entry(struct dm_writecache *wc,
if (unlikely(!node)) {
if (!(flags & WFE_RETURN_FOLLOWING))
return NULL;
- if (read_original_sector(wc, e) >= block) {
+ if (read_original_sector(wc, e) >= block)
return e;
- } else {
- node = rb_next(&e->rb_node);
- if (unlikely(!node))
- return NULL;
- e = container_of(node, struct wc_entry, rb_node);
- return e;
- }
+
+ node = rb_next(&e->rb_node);
+ if (unlikely(!node))
+ return NULL;
+
+ e = container_of(node, struct wc_entry, rb_node);
+ return e;
}
}
while (1) {
struct wc_entry *e2;
+
if (flags & WFE_LOWEST_SEQ)
node = rb_prev(&e->rb_node);
else
@@ -679,6 +680,7 @@ static void writecache_add_to_freelist(struct dm_writecache *wc, struct wc_entry
{
if (WC_MODE_SORT_FREELIST(wc)) {
struct rb_node **node = &wc->freetree.rb_node, *parent = NULL;
+
if (unlikely(!*node))
wc->current_free = e;
while (*node) {
@@ -718,6 +720,7 @@ static struct wc_entry *writecache_pop_from_freelist(struct dm_writecache *wc, s
if (WC_MODE_SORT_FREELIST(wc)) {
struct rb_node *next;
+
if (unlikely(!wc->current_free))
return NULL;
e = wc->current_free;
@@ -769,7 +772,7 @@ static void writecache_poison_lists(struct dm_writecache *wc)
/*
* Catch incorrect access to these values while the device is suspended.
*/
- memset(&wc->tree, -1, sizeof wc->tree);
+ memset(&wc->tree, -1, sizeof(wc->tree));
wc->lru.next = LIST_POISON1;
wc->lru.prev = LIST_POISON2;
wc->freelist.next = LIST_POISON1;
@@ -864,6 +867,7 @@ static void writecache_flush_work(struct work_struct *work)
static void writecache_autocommit_timer(struct timer_list *t)
{
struct dm_writecache *wc = from_timer(wc, t, autocommit_timer);
+
if (!writecache_has_error(wc))
queue_work(wc->writeback_wq, &wc->flush_work);
}
@@ -941,7 +945,8 @@ static void writecache_suspend(struct dm_target *ti)
wc_lock(wc);
if (flush_on_suspend)
wc->writeback_all--;
- while (writecache_wait_for_writeback(wc));
+ while (writecache_wait_for_writeback(wc))
+ ;
if (WC_MODE_PMEM(wc))
persistent_memory_flush_cache(wc->memory_map, wc->memory_map_size);
@@ -962,6 +967,7 @@ static int writecache_alloc_entries(struct dm_writecache *wc)
return -ENOMEM;
for (b = 0; b < wc->n_blocks; b++) {
struct wc_entry *e = &wc->entries[b];
+
e->index = b;
e->write_in_progress = false;
cond_resched();
@@ -1005,6 +1011,7 @@ static void writecache_resume(struct dm_target *ti)
r = writecache_read_metadata(wc, wc->metadata_sectors);
if (r) {
size_t sb_entries_offset;
+
writecache_error(wc, r, "unable to read metadata: %d", r);
sb_entries_offset = offsetof(struct wc_memory_superblock, entries);
memset((char *)wc->memory_map + sb_entries_offset, -1,
@@ -1034,6 +1041,7 @@ static void writecache_resume(struct dm_target *ti)
for (b = 0; b < wc->n_blocks; b++) {
struct wc_entry *e = &wc->entries[b];
struct wc_memory_entry wme;
+
if (writecache_has_error(wc)) {
e->original_sector = -1;
e->seq_count = -1;
@@ -1055,6 +1063,7 @@ static void writecache_resume(struct dm_target *ti)
#endif
for (b = 0; b < wc->n_blocks; b++) {
struct wc_entry *e = &wc->entries[b];
+
if (!writecache_entry_is_committed(wc, e)) {
if (read_seq_count(wc, e) != -1) {
erase_this:
@@ -1100,7 +1109,7 @@ erase_this:
wc_unlock(wc);
}
-static int process_flush_mesg(unsigned argc, char **argv, struct dm_writecache *wc)
+static int process_flush_mesg(unsigned int argc, char **argv, struct dm_writecache *wc)
{
if (argc != 1)
return -EINVAL;
@@ -1133,7 +1142,7 @@ static int process_flush_mesg(unsigned argc, char **argv, struct dm_writecache *
return 0;
}
-static int process_flush_on_suspend_mesg(unsigned argc, char **argv, struct dm_writecache *wc)
+static int process_flush_on_suspend_mesg(unsigned int argc, char **argv, struct dm_writecache *wc)
{
if (argc != 1)
return -EINVAL;
@@ -1153,7 +1162,7 @@ static void activate_cleaner(struct dm_writecache *wc)
wc->freelist_low_watermark = wc->n_blocks;
}
-static int process_cleaner_mesg(unsigned argc, char **argv, struct dm_writecache *wc)
+static int process_cleaner_mesg(unsigned int argc, char **argv, struct dm_writecache *wc)
{
if (argc != 1)
return -EINVAL;
@@ -1167,20 +1176,20 @@ static int process_cleaner_mesg(unsigned argc, char **argv, struct dm_writecache
return 0;
}
-static int process_clear_stats_mesg(unsigned argc, char **argv, struct dm_writecache *wc)
+static int process_clear_stats_mesg(unsigned int argc, char **argv, struct dm_writecache *wc)
{
if (argc != 1)
return -EINVAL;
wc_lock(wc);
- memset(&wc->stats, 0, sizeof wc->stats);
+ memset(&wc->stats, 0, sizeof(wc->stats));
wc_unlock(wc);
return 0;
}
-static int writecache_message(struct dm_target *ti, unsigned argc, char **argv,
- char *result, unsigned maxlen)
+static int writecache_message(struct dm_target *ti, unsigned int argc, char **argv,
+ char *result, unsigned int maxlen)
{
int r = -EINVAL;
struct dm_writecache *wc = ti->private;
@@ -1238,12 +1247,13 @@ static void memcpy_flushcache_optimized(void *dest, void *source, size_t size)
static void bio_copy_block(struct dm_writecache *wc, struct bio *bio, void *data)
{
void *buf;
- unsigned size;
+ unsigned int size;
int rw = bio_data_dir(bio);
- unsigned remaining_size = wc->block_size;
+ unsigned int remaining_size = wc->block_size;
do {
struct bio_vec bv = bio_iter_iovec(bio, bio->bi_iter);
+
buf = bvec_kmap_local(&bv);
size = bv.bv_len;
if (unlikely(size > remaining_size))
@@ -1251,6 +1261,7 @@ static void bio_copy_block(struct dm_writecache *wc, struct bio *bio, void *data
if (rw == READ) {
int r;
+
r = copy_mc_to_kernel(buf, data, size);
flush_dcache_page(bio_page(bio));
if (unlikely(r)) {
@@ -1371,13 +1382,14 @@ read_next_block:
static void writecache_bio_copy_ssd(struct dm_writecache *wc, struct bio *bio,
struct wc_entry *e, bool search_used)
{
- unsigned bio_size = wc->block_size;
+ unsigned int bio_size = wc->block_size;
sector_t start_cache_sec = cache_sector(wc, e);
sector_t current_cache_sec = start_cache_sec + (bio_size >> SECTOR_SHIFT);
while (bio_size < bio->bi_iter.bi_size) {
if (!search_used) {
struct wc_entry *f = writecache_pop_from_freelist(wc, current_cache_sec);
+
if (!f)
break;
write_original_sector_seq_count(wc, f, bio->bi_iter.bi_sector +
@@ -1387,6 +1399,7 @@ static void writecache_bio_copy_ssd(struct dm_writecache *wc, struct bio *bio,
} else {
struct wc_entry *f;
struct rb_node *next = rb_next(&e->rb_node);
+
if (!next)
break;
f = container_of(next, struct wc_entry, rb_node);
@@ -1427,6 +1440,7 @@ static enum wc_map_op writecache_map_write(struct dm_writecache *wc, struct bio
do {
bool found_entry = false;
bool search_used = false;
+
if (writecache_has_error(wc)) {
wc->stats.writes += bio->bi_iter.bi_size >> wc->block_size_bits;
return WC_MAP_ERROR;
@@ -1540,7 +1554,7 @@ static int writecache_map(struct dm_target *ti, struct bio *bio)
bio->bi_iter.bi_sector = dm_target_offset(ti, bio->bi_iter.bi_sector);
- if (unlikely((((unsigned)bio->bi_iter.bi_sector | bio_sectors(bio)) &
+ if (unlikely((((unsigned int)bio->bi_iter.bi_sector | bio_sectors(bio)) &
(wc->block_size / 512 - 1)) != 0)) {
DMERR("I/O is not aligned, sector %llu, size %u, block size %u",
(unsigned long long)bio->bi_iter.bi_sector,
@@ -1605,6 +1619,7 @@ static int writecache_end_io(struct dm_target *ti, struct bio *bio, blk_status_t
if (bio->bi_private == (void *)1) {
int dir = bio_data_dir(bio);
+
if (atomic_dec_and_test(&wc->bio_in_progress[dir]))
if (unlikely(waitqueue_active(&wc->bio_in_progress_wait[dir])))
wake_up(&wc->bio_in_progress_wait[dir]);
@@ -1666,7 +1681,7 @@ static void writecache_copy_endio(int read_err, unsigned long write_err, void *p
static void __writecache_endio_pmem(struct dm_writecache *wc, struct list_head *list)
{
- unsigned i;
+ unsigned int i;
struct writeback_struct *wb;
struct wc_entry *e;
unsigned long n_walked = 0;
@@ -1782,7 +1797,7 @@ pop_from_list:
static bool wc_add_block(struct writeback_struct *wb, struct wc_entry *e)
{
struct dm_writecache *wc = wb->wc;
- unsigned block_size = wc->block_size;
+ unsigned int block_size = wc->block_size;
void *address = memory_data(wc, e);
persistent_memory_flush_cache(address, block_size);
@@ -1817,7 +1832,7 @@ static void __writecache_writeback_pmem(struct dm_writecache *wc, struct writeba
struct wc_entry *e, *f;
struct bio *bio;
struct writeback_struct *wb;
- unsigned max_pages;
+ unsigned int max_pages;
while (wbl->size) {
wbl->size--;
@@ -1832,10 +1847,13 @@ static void __writecache_writeback_pmem(struct dm_writecache *wc, struct writeba
wb->wc = wc;
bio->bi_end_io = writecache_writeback_endio;
bio->bi_iter.bi_sector = read_original_sector(wc, e);
- if (max_pages <= WB_LIST_INLINE ||
- unlikely(!(wb->wc_list = kmalloc_array(max_pages, sizeof(struct wc_entry *),
- GFP_NOIO | __GFP_NORETRY |
- __GFP_NOMEMALLOC | __GFP_NOWARN)))) {
+
+ if (unlikely(max_pages > WB_LIST_INLINE))
+ wb->wc_list = kmalloc_array(max_pages, sizeof(struct wc_entry *),
+ GFP_NOIO | __GFP_NORETRY |
+ __GFP_NOMEMALLOC | __GFP_NOWARN);
+
+ if (likely(max_pages <= WB_LIST_INLINE) || unlikely(!wb->wc_list)) {
wb->wc_list = wb->wc_list_inline;
max_pages = WB_LIST_INLINE;
}
@@ -1880,7 +1898,7 @@ static void __writecache_writeback_ssd(struct dm_writecache *wc, struct writebac
struct copy_struct *c;
while (wbl->size) {
- unsigned n_sectors;
+ unsigned int n_sectors;
wbl->size--;
e = container_of(wbl->list.prev, struct wc_entry, lru);
@@ -1940,6 +1958,7 @@ static void writecache_writeback(struct work_struct *work)
if (likely(wc->pause != 0)) {
while (1) {
unsigned long idle;
+
if (unlikely(wc->cleaner) || unlikely(wc->writeback_all) ||
unlikely(dm_suspended(wc->ti)))
break;
@@ -1965,9 +1984,8 @@ restart:
goto restart;
}
- if (wc->overwrote_committed) {
+ if (wc->overwrote_committed)
writecache_wait_for_ios(wc, WRITE);
- }
n_walked = 0;
INIT_LIST_HEAD(&skipped);
@@ -1996,9 +2014,9 @@ restart:
} else
e = container_of(wc->lru.prev, struct wc_entry, lru);
BUG_ON(e->write_in_progress);
- if (unlikely(!writecache_entry_is_committed(wc, e))) {
+ if (unlikely(!writecache_entry_is_committed(wc, e)))
writecache_flush(wc);
- }
+
node = rb_prev(&e->rb_node);
if (node) {
f = container_of(node, struct wc_entry, rb_node);
@@ -2087,12 +2105,13 @@ restart:
if (unlikely(wc->writeback_all)) {
wc_lock(wc);
- while (writecache_wait_for_writeback(wc));
+ while (writecache_wait_for_writeback(wc))
+ ;
wc_unlock(wc);
}
}
-static int calculate_memory_size(uint64_t device_size, unsigned block_size,
+static int calculate_memory_size(uint64_t device_size, unsigned int block_size,
size_t *n_blocks_p, size_t *n_metadata_blocks_p)
{
uint64_t n_blocks, offset;
@@ -2155,7 +2174,7 @@ static int init_memory(struct dm_writecache *wc)
writecache_flush_all_metadata(wc);
writecache_commit_flushed(wc, false);
pmem_assign(sb(wc)->magic, cpu_to_le32(MEMORY_SUPERBLOCK_MAGIC));
- writecache_flush_region(wc, &sb(wc)->magic, sizeof sb(wc)->magic);
+ writecache_flush_region(wc, &sb(wc)->magic, sizeof(sb(wc)->magic));
writecache_commit_flushed(wc, false);
return 0;
@@ -2207,12 +2226,12 @@ static void writecache_dtr(struct dm_target *ti)
kfree(wc);
}
-static int writecache_ctr(struct dm_target *ti, unsigned argc, char **argv)
+static int writecache_ctr(struct dm_target *ti, unsigned int argc, char **argv)
{
struct dm_writecache *wc;
struct dm_arg_set as;
const char *string;
- unsigned opt_params;
+ unsigned int opt_params;
size_t offset, data_size;
int i, r;
char dummy;
@@ -2384,6 +2403,7 @@ static int writecache_ctr(struct dm_target *ti, unsigned argc, char **argv)
string = dm_shift_arg(&as), opt_params--;
if (!strcasecmp(string, "start_sector") && opt_params >= 1) {
unsigned long long start_sector;
+
string = dm_shift_arg(&as), opt_params--;
if (sscanf(string, "%llu%c", &start_sector, &dummy) != 1)
goto invalid_optional;
@@ -2419,7 +2439,8 @@ static int writecache_ctr(struct dm_target *ti, unsigned argc, char **argv)
goto invalid_optional;
wc->autocommit_blocks_set = true;
} else if (!strcasecmp(string, "autocommit_time") && opt_params >= 1) {
- unsigned autocommit_msecs;
+ unsigned int autocommit_msecs;
+
string = dm_shift_arg(&as), opt_params--;
if (sscanf(string, "%u%c", &autocommit_msecs, &dummy) != 1)
goto invalid_optional;
@@ -2429,7 +2450,8 @@ static int writecache_ctr(struct dm_target *ti, unsigned argc, char **argv)
wc->autocommit_time_value = autocommit_msecs;
wc->autocommit_time_set = true;
} else if (!strcasecmp(string, "max_age") && opt_params >= 1) {
- unsigned max_age_msecs;
+ unsigned int max_age_msecs;
+
string = dm_shift_arg(&as), opt_params--;
if (sscanf(string, "%u%c", &max_age_msecs, &dummy) != 1)
goto invalid_optional;
@@ -2445,16 +2467,19 @@ static int writecache_ctr(struct dm_target *ti, unsigned argc, char **argv)
if (WC_MODE_PMEM(wc)) {
wc->writeback_fua = true;
wc->writeback_fua_set = true;
- } else goto invalid_optional;
+ } else
+ goto invalid_optional;
} else if (!strcasecmp(string, "nofua")) {
if (WC_MODE_PMEM(wc)) {
wc->writeback_fua = false;
wc->writeback_fua_set = true;
- } else goto invalid_optional;
+ } else
+ goto invalid_optional;
} else if (!strcasecmp(string, "metadata_only")) {
wc->metadata_only = true;
} else if (!strcasecmp(string, "pause_writeback") && opt_params >= 1) {
- unsigned pause_msecs;
+ unsigned int pause_msecs;
+
if (WC_MODE_PMEM(wc))
goto invalid_optional;
string = dm_shift_arg(&as), opt_params--;
@@ -2653,11 +2678,11 @@ bad:
}
static void writecache_status(struct dm_target *ti, status_type_t type,
- unsigned status_flags, char *result, unsigned maxlen)
+ unsigned int status_flags, char *result, unsigned int maxlen)
{
struct dm_writecache *wc = ti->private;
- unsigned extra_args;
- unsigned sz = 0;
+ unsigned int extra_args;
+ unsigned int sz = 0;
switch (type) {
case STATUSTYPE_INFO:
diff --git a/drivers/md/dm-zero.c b/drivers/md/dm-zero.c
index faa1dbffc8b4..2601cd520384 100644
--- a/drivers/md/dm-zero.c
+++ b/drivers/md/dm-zero.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2003 Jana Saout <jana@saout.de>
*
diff --git a/drivers/md/dm-zone.c b/drivers/md/dm-zone.c
index 3dafc0e8b7a9..4b82b7798ce4 100644
--- a/drivers/md/dm-zone.c
+++ b/drivers/md/dm-zone.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2021 Western Digital Corporation or its affiliates.
*/
diff --git a/drivers/md/dm-zoned-metadata.c b/drivers/md/dm-zoned-metadata.c
index 0278482fac94..cf9402064aba 100644
--- a/drivers/md/dm-zoned-metadata.c
+++ b/drivers/md/dm-zoned-metadata.c
@@ -1013,11 +1013,9 @@ static int dmz_check_sb(struct dmz_metadata *zmd, struct dmz_sb *dsb,
}
sb_block = le64_to_cpu(sb->sb_block);
- if (sb_block != (u64)dsb->zone->id << zmd->zone_nr_blocks_shift ) {
- dmz_dev_err(dev, "Invalid superblock position "
- "(is %llu expected %llu)",
- sb_block,
- (u64)dsb->zone->id << zmd->zone_nr_blocks_shift);
+ if (sb_block != (u64)dsb->zone->id << zmd->zone_nr_blocks_shift) {
+ dmz_dev_err(dev, "Invalid superblock position (is %llu expected %llu)",
+ sb_block, (u64)dsb->zone->id << zmd->zone_nr_blocks_shift);
return -EINVAL;
}
if (zmd->sb_version > 1) {
@@ -1030,16 +1028,14 @@ static int dmz_check_sb(struct dmz_metadata *zmd, struct dmz_sb *dsb,
} else if (uuid_is_null(&zmd->uuid)) {
uuid_copy(&zmd->uuid, &sb_uuid);
} else if (!uuid_equal(&zmd->uuid, &sb_uuid)) {
- dmz_dev_err(dev, "mismatching DM-Zoned uuid, "
- "is %pUl expected %pUl",
+ dmz_dev_err(dev, "mismatching DM-Zoned uuid, is %pUl expected %pUl",
&sb_uuid, &zmd->uuid);
return -ENXIO;
}
if (!strlen(zmd->label))
memcpy(zmd->label, sb->dmz_label, BDEVNAME_SIZE);
else if (memcmp(zmd->label, sb->dmz_label, BDEVNAME_SIZE)) {
- dmz_dev_err(dev, "mismatching DM-Zoned label, "
- "is %s expected %s",
+ dmz_dev_err(dev, "mismatching DM-Zoned label, is %s expected %s",
sb->dmz_label, zmd->label);
return -ENXIO;
}
@@ -1346,7 +1342,7 @@ static int dmz_load_sb(struct dmz_metadata *zmd)
if (ret == -EINVAL)
goto out_kfree;
}
- out_kfree:
+out_kfree:
kfree(sb);
}
return ret;
@@ -1430,7 +1426,7 @@ static int dmz_emulate_zones(struct dmz_metadata *zmd, struct dmz_dev *dev)
int idx;
sector_t zone_offset = 0;
- for(idx = 0; idx < dev->nr_zones; idx++) {
+ for (idx = 0; idx < dev->nr_zones; idx++) {
struct dm_zone *zone;
zone = dmz_insert(zmd, idx, dev);
@@ -1457,7 +1453,7 @@ static void dmz_drop_zones(struct dmz_metadata *zmd)
{
int idx;
- for(idx = 0; idx < zmd->nr_zones; idx++) {
+ for (idx = 0; idx < zmd->nr_zones; idx++) {
struct dm_zone *zone = xa_load(&zmd->zones, idx);
kfree(zone);
@@ -2945,7 +2941,7 @@ int dmz_ctr_metadata(struct dmz_dev *dev, int num_dev,
zmd->mblk_shrinker.seeks = DEFAULT_SEEKS;
/* Metadata cache shrinker */
- ret = register_shrinker(&zmd->mblk_shrinker, "md-meta:(%u:%u)",
+ ret = register_shrinker(&zmd->mblk_shrinker, "dm-zoned-meta:(%u:%u)",
MAJOR(dev->bdev->bd_dev),
MINOR(dev->bdev->bd_dev));
if (ret) {
diff --git a/drivers/md/dm-zoned-target.c b/drivers/md/dm-zoned-target.c
index 95b132b52f33..ad4764dcd013 100644
--- a/drivers/md/dm-zoned-target.c
+++ b/drivers/md/dm-zoned-target.c
@@ -1119,7 +1119,6 @@ static void dmz_status(struct dm_target *ti, status_type_t type,
*result = '\0';
break;
}
- return;
}
static int dmz_message(struct dm_target *ti, unsigned int argc, char **argv,
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index b424a6ee27ba..eace45a18d45 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2001, 2002 Sistina Software (UK) Limited.
* Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
@@ -49,8 +50,8 @@
static const char *_name = DM_NAME;
-static unsigned int major = 0;
-static unsigned int _major = 0;
+static unsigned int major;
+static unsigned int _major;
static DEFINE_IDR(_minor_idr);
@@ -83,7 +84,7 @@ struct clone_info {
struct bio *bio;
struct dm_io *io;
sector_t sector;
- unsigned sector_count;
+ unsigned int sector_count;
bool is_abnormal_io:1;
bool submit_as_polled:1;
};
@@ -104,6 +105,7 @@ EXPORT_SYMBOL_GPL(dm_per_bio_data);
struct bio *dm_bio_from_per_bio_data(void *data, size_t data_size)
{
struct dm_io *io = (struct dm_io *)((char *)data + data_size);
+
if (io->magic == DM_IO_MAGIC)
return (struct bio *)((char *)io + DM_IO_BIO_OFFSET);
BUG_ON(io->magic != DM_TIO_MAGIC);
@@ -111,7 +113,7 @@ struct bio *dm_bio_from_per_bio_data(void *data, size_t data_size)
}
EXPORT_SYMBOL_GPL(dm_bio_from_per_bio_data);
-unsigned dm_bio_get_target_bio_nr(const struct bio *bio)
+unsigned int dm_bio_get_target_bio_nr(const struct bio *bio)
{
return container_of(bio, struct dm_target_io, clone)->target_bio_nr;
}
@@ -127,6 +129,7 @@ static int swap_bios = DEFAULT_SWAP_BIOS;
static int get_swap_bios(void)
{
int latch = READ_ONCE(swap_bios);
+
if (unlikely(latch <= 0))
latch = DEFAULT_SWAP_BIOS;
return latch;
@@ -142,7 +145,7 @@ struct table_device {
* Bio-based DM's mempools' reserved IOs set by the user.
*/
#define RESERVED_BIO_BASED_IOS 16
-static unsigned reserved_bio_based_ios = RESERVED_BIO_BASED_IOS;
+static unsigned int reserved_bio_based_ios = RESERVED_BIO_BASED_IOS;
static int __dm_get_module_param_int(int *module_param, int min, int max)
{
@@ -165,11 +168,10 @@ static int __dm_get_module_param_int(int *module_param, int min, int max)
return param;
}
-unsigned __dm_get_module_param(unsigned *module_param,
- unsigned def, unsigned max)
+unsigned int __dm_get_module_param(unsigned int *module_param, unsigned int def, unsigned int max)
{
- unsigned param = READ_ONCE(*module_param);
- unsigned modified_param = 0;
+ unsigned int param = READ_ONCE(*module_param);
+ unsigned int modified_param = 0;
if (!param)
modified_param = def;
@@ -184,14 +186,14 @@ unsigned __dm_get_module_param(unsigned *module_param,
return param;
}
-unsigned dm_get_reserved_bio_based_ios(void)
+unsigned int dm_get_reserved_bio_based_ios(void)
{
return __dm_get_module_param(&reserved_bio_based_ios,
RESERVED_BIO_BASED_IOS, DM_RESERVED_MAX_IOS);
}
EXPORT_SYMBOL_GPL(dm_get_reserved_bio_based_ios);
-static unsigned dm_get_numa_node(void)
+static unsigned int dm_get_numa_node(void)
{
return __dm_get_module_param_int(&dm_numa_node,
DM_NUMA_NODE, num_online_nodes() - 1);
@@ -231,7 +233,6 @@ out_uevent_exit:
static void local_exit(void)
{
- flush_scheduled_work();
destroy_workqueue(deferred_remove_workqueue);
unregister_blkdev(_major, _name);
@@ -435,7 +436,7 @@ retry:
r = ti->type->prepare_ioctl(ti, bdev);
if (r == -ENOTCONN && !fatal_signal_pending(current)) {
dm_put_live_table(md, *srcu_idx);
- msleep(10);
+ fsleep(10000);
goto retry;
}
@@ -604,7 +605,7 @@ static void free_io(struct dm_io *io)
}
static struct bio *alloc_tio(struct clone_info *ci, struct dm_target *ti,
- unsigned target_bio_nr, unsigned *len, gfp_t gfp_mask)
+ unsigned int target_bio_nr, unsigned int *len, gfp_t gfp_mask)
{
struct mapped_device *md = ci->io->md;
struct dm_target_io *tio;
@@ -1008,6 +1009,7 @@ static void dm_wq_requeue_work(struct work_struct *work)
io->next = NULL;
__dm_io_complete(io, false);
io = next;
+ cond_resched();
}
}
@@ -1115,6 +1117,7 @@ static void clone_endio(struct bio *bio)
if (endio) {
int r = endio(ti, bio, &error);
+
switch (r) {
case DM_ENDIO_REQUEUE:
if (static_branch_unlikely(&zoned_enabled)) {
@@ -1314,11 +1317,11 @@ out:
* the partially processed part (the sum of regions 1+2) must be the same for all
* copies of the bio.
*/
-void dm_accept_partial_bio(struct bio *bio, unsigned n_sectors)
+void dm_accept_partial_bio(struct bio *bio, unsigned int n_sectors)
{
struct dm_target_io *tio = clone_to_tio(bio);
struct dm_io *io = tio->io;
- unsigned bio_sectors = bio_sectors(bio);
+ unsigned int bio_sectors = bio_sectors(bio);
BUG_ON(dm_tio_flagged(tio, DM_TIO_IS_DUPLICATE_BIO));
BUG_ON(op_is_zone_mgmt(bio_op(bio)));
@@ -1403,6 +1406,7 @@ static void __map_bio(struct bio *clone)
if (static_branch_unlikely(&swap_bios_enabled) &&
unlikely(swap_bios_limit(ti, clone))) {
int latch = get_swap_bios();
+
if (unlikely(latch != md->swap_bios))
__set_swap_bios_limit(md, latch);
down(&md->swap_bios_semaphore);
@@ -1447,7 +1451,7 @@ static void __map_bio(struct bio *clone)
}
}
-static void setup_split_accounting(struct clone_info *ci, unsigned len)
+static void setup_split_accounting(struct clone_info *ci, unsigned int len)
{
struct dm_io *io = ci->io;
@@ -1463,7 +1467,7 @@ static void setup_split_accounting(struct clone_info *ci, unsigned len)
}
static void alloc_multiple_bios(struct bio_list *blist, struct clone_info *ci,
- struct dm_target *ti, unsigned num_bios)
+ struct dm_target *ti, unsigned int num_bios)
{
struct bio *bio;
int try;
@@ -1492,7 +1496,7 @@ static void alloc_multiple_bios(struct bio_list *blist, struct clone_info *ci,
}
static int __send_duplicate_bios(struct clone_info *ci, struct dm_target *ti,
- unsigned int num_bios, unsigned *len)
+ unsigned int num_bios, unsigned int *len)
{
struct bio_list blist = BIO_EMPTY_LIST;
struct bio *clone;
@@ -1558,10 +1562,9 @@ static void __send_empty_flush(struct clone_info *ci)
}
static void __send_changing_extent_only(struct clone_info *ci, struct dm_target *ti,
- unsigned num_bios)
+ unsigned int num_bios)
{
- unsigned len;
- unsigned int bios;
+ unsigned int len, bios;
len = min_t(sector_t, ci->sector_count,
max_io_len_target_boundary(ti, dm_target_offset(ti, ci->sector)));
@@ -1599,7 +1602,7 @@ static bool is_abnormal_io(struct bio *bio)
static blk_status_t __process_abnormal_io(struct clone_info *ci,
struct dm_target *ti)
{
- unsigned num_bios = 0;
+ unsigned int num_bios = 0;
switch (bio_op(ci->bio)) {
case REQ_OP_DISCARD:
@@ -1677,7 +1680,7 @@ static blk_status_t __split_and_process_bio(struct clone_info *ci)
{
struct bio *clone;
struct dm_target *ti;
- unsigned len;
+ unsigned int len;
ti = dm_table_find_target(ci->map, ci->sector);
if (unlikely(!ti))
@@ -1874,9 +1877,11 @@ static int dm_poll_bio(struct bio *bio, struct io_comp_batch *iob,
return 1;
}
-/*-----------------------------------------------------------------
+/*
+ *---------------------------------------------------------------
* An IDR is used to keep track of allocated minor numbers.
- *---------------------------------------------------------------*/
+ *---------------------------------------------------------------
+ */
static void free_minor(int minor)
{
spin_lock(&_minor_lock);
@@ -2139,7 +2144,7 @@ static void event_callback(void *context)
{
unsigned long flags;
LIST_HEAD(uevents);
- struct mapped_device *md = (struct mapped_device *) context;
+ struct mapped_device *md = context;
spin_lock_irqsave(&md->uevent_lock, flags);
list_splice_init(&md->uevent_list, &uevents);
@@ -2172,10 +2177,7 @@ static struct dm_table *__bind(struct mapped_device *md, struct dm_table *t,
if (size != dm_get_size(md))
memset(&md->geometry, 0, sizeof(md->geometry));
- if (!get_capacity(md->disk))
- set_capacity(md->disk, size);
- else
- set_capacity_and_notify(md->disk, size);
+ set_capacity(md->disk, size);
dm_table_event_callback(t, event_callback, md);
@@ -2375,7 +2377,7 @@ out_undo_holders:
struct mapped_device *dm_get_md(dev_t dev)
{
struct mapped_device *md;
- unsigned minor = MINOR(dev);
+ unsigned int minor = MINOR(dev);
if (MAJOR(dev) != _major || minor >= (1 << MINORBITS))
return NULL;
@@ -2457,7 +2459,7 @@ static void __dm_destroy(struct mapped_device *md, bool wait)
set_bit(DMF_POST_SUSPENDING, &md->flags);
dm_table_postsuspend_targets(map);
}
- /* dm_put_live_table must be before msleep, otherwise deadlock is possible */
+ /* dm_put_live_table must be before fsleep, otherwise deadlock is possible */
dm_put_live_table(md, srcu_idx);
mutex_unlock(&md->suspend_lock);
@@ -2469,7 +2471,7 @@ static void __dm_destroy(struct mapped_device *md, bool wait)
*/
if (wait)
while (atomic_read(&md->holders))
- msleep(1);
+ fsleep(1000);
else if (atomic_read(&md->holders))
DMWARN("%s: Forcibly removing mapped_device still in use! (%d users)",
dm_device_name(md), atomic_read(&md->holders));
@@ -2546,7 +2548,7 @@ static int dm_wait_for_completion(struct mapped_device *md, unsigned int task_st
break;
}
- msleep(5);
+ fsleep(5000);
}
return r;
@@ -2569,6 +2571,7 @@ static void dm_wq_work(struct work_struct *work)
break;
submit_bio_noacct(bio);
+ cond_resched();
}
}
@@ -2657,7 +2660,7 @@ static void unlock_fs(struct mapped_device *md)
* are being added to md->deferred list.
*/
static int __dm_suspend(struct mapped_device *md, struct dm_table *map,
- unsigned suspend_flags, unsigned int task_state,
+ unsigned int suspend_flags, unsigned int task_state,
int dmf_suspended_flag)
{
bool do_lockfs = suspend_flags & DM_SUSPEND_LOCKFS_FLAG;
@@ -2764,7 +2767,7 @@ static int __dm_suspend(struct mapped_device *md, struct dm_table *map,
*
* To abort suspend, start the request_queue.
*/
-int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
+int dm_suspend(struct mapped_device *md, unsigned int suspend_flags)
{
struct dm_table *map = NULL;
int r = 0;
@@ -2805,6 +2808,7 @@ static int __dm_resume(struct mapped_device *md, struct dm_table *map)
{
if (map) {
int r = dm_table_resume_targets(map);
+
if (r)
return r;
}
@@ -2866,7 +2870,7 @@ out:
* It may be used only from the kernel.
*/
-static void __dm_internal_suspend(struct mapped_device *md, unsigned suspend_flags)
+static void __dm_internal_suspend(struct mapped_device *md, unsigned int suspend_flags)
{
struct dm_table *map = NULL;
@@ -2964,27 +2968,31 @@ done:
}
EXPORT_SYMBOL_GPL(dm_internal_resume_fast);
-/*-----------------------------------------------------------------
+/*
+ *---------------------------------------------------------------
* Event notification.
- *---------------------------------------------------------------*/
+ *---------------------------------------------------------------
+ */
int dm_kobject_uevent(struct mapped_device *md, enum kobject_action action,
- unsigned cookie)
+ unsigned int cookie, bool need_resize_uevent)
{
int r;
- unsigned noio_flag;
+ unsigned int noio_flag;
char udev_cookie[DM_COOKIE_LENGTH];
- char *envp[] = { udev_cookie, NULL };
-
- noio_flag = memalloc_noio_save();
-
- if (!cookie)
- r = kobject_uevent(&disk_to_dev(md->disk)->kobj, action);
- else {
+ char *envp[3] = { NULL, NULL, NULL };
+ char **envpp = envp;
+ if (cookie) {
snprintf(udev_cookie, DM_COOKIE_LENGTH, "%s=%u",
DM_COOKIE_ENV_VAR_NAME, cookie);
- r = kobject_uevent_env(&disk_to_dev(md->disk)->kobj,
- action, envp);
+ *envpp++ = udev_cookie;
}
+ if (need_resize_uevent) {
+ *envpp++ = "RESIZE=1";
+ }
+
+ noio_flag = memalloc_noio_save();
+
+ r = kobject_uevent_env(&disk_to_dev(md->disk)->kobj, action, envp);
memalloc_noio_restore(noio_flag);
@@ -3382,13 +3390,13 @@ module_exit(dm_exit);
module_param(major, uint, 0);
MODULE_PARM_DESC(major, "The major number of the device mapper");
-module_param(reserved_bio_based_ios, uint, S_IRUGO | S_IWUSR);
+module_param(reserved_bio_based_ios, uint, 0644);
MODULE_PARM_DESC(reserved_bio_based_ios, "Reserved IOs in bio-based mempools");
-module_param(dm_numa_node, int, S_IRUGO | S_IWUSR);
+module_param(dm_numa_node, int, 0644);
MODULE_PARM_DESC(dm_numa_node, "NUMA node for DM device memory allocations");
-module_param(swap_bios, int, S_IRUGO | S_IWUSR);
+module_param(swap_bios, int, 0644);
MODULE_PARM_DESC(swap_bios, "Maximum allowed inflight swap IOs");
MODULE_DESCRIPTION(DM_NAME " driver");
diff --git a/drivers/md/dm.h b/drivers/md/dm.h
index 5201df03ce40..22eaed188907 100644
--- a/drivers/md/dm.h
+++ b/drivers/md/dm.h
@@ -48,9 +48,11 @@ struct dm_md_mempools;
struct dm_target_io;
struct dm_io;
-/*-----------------------------------------------------------------
+/*
+ *---------------------------------------------------------------
* Internal table functions.
- *---------------------------------------------------------------*/
+ *---------------------------------------------------------------
+ */
void dm_table_event_callback(struct dm_table *t,
void (*fn)(void *), void *context);
struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector);
@@ -119,9 +121,11 @@ static inline int dm_zone_map_bio(struct dm_target_io *tio)
}
#endif
-/*-----------------------------------------------------------------
+/*
+ *---------------------------------------------------------------
* A registry of target types.
- *---------------------------------------------------------------*/
+ *---------------------------------------------------------------
+ */
int dm_target_init(void);
void dm_target_exit(void);
struct target_type *dm_get_target_type(const char *name);
@@ -203,7 +207,7 @@ int dm_get_table_device(struct mapped_device *md, dev_t dev, fmode_t mode,
void dm_put_table_device(struct mapped_device *md, struct dm_dev *d);
int dm_kobject_uevent(struct mapped_device *md, enum kobject_action action,
- unsigned cookie);
+ unsigned int cookie, bool need_resize_uevent);
void dm_internal_suspend(struct mapped_device *md);
void dm_internal_resume(struct mapped_device *md);
@@ -222,6 +226,6 @@ void dm_free_md_mempools(struct dm_md_mempools *pools);
/*
* Various helpers
*/
-unsigned dm_get_reserved_bio_based_ios(void);
+unsigned int dm_get_reserved_bio_based_ios(void);
#endif
diff --git a/drivers/md/persistent-data/dm-array.c b/drivers/md/persistent-data/dm-array.c
index 3a963d783a86..798c9c53a343 100644
--- a/drivers/md/persistent-data/dm-array.c
+++ b/drivers/md/persistent-data/dm-array.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Red Hat, Inc.
*
@@ -57,7 +58,7 @@ static int array_block_check(struct dm_block_validator *v,
__le32 csum_disk;
if (dm_block_location(b) != le64_to_cpu(bh_le->blocknr)) {
- DMERR_LIMIT("array_block_check failed: blocknr %llu != wanted %llu",
+ DMERR_LIMIT("%s failed: blocknr %llu != wanted %llu", __func__,
(unsigned long long) le64_to_cpu(bh_le->blocknr),
(unsigned long long) dm_block_location(b));
return -ENOTBLK;
@@ -67,9 +68,9 @@ static int array_block_check(struct dm_block_validator *v,
size_of_block - sizeof(__le32),
CSUM_XOR));
if (csum_disk != bh_le->csum) {
- DMERR_LIMIT("array_block_check failed: csum %u != wanted %u",
- (unsigned) le32_to_cpu(csum_disk),
- (unsigned) le32_to_cpu(bh_le->csum));
+ DMERR_LIMIT("%s failed: csum %u != wanted %u", __func__,
+ (unsigned int) le32_to_cpu(csum_disk),
+ (unsigned int) le32_to_cpu(bh_le->csum));
return -EILSEQ;
}
@@ -94,7 +95,7 @@ static struct dm_block_validator array_validator = {
* index - The index into _this_ specific block.
*/
static void *element_at(struct dm_array_info *info, struct array_block *ab,
- unsigned index)
+ unsigned int index)
{
unsigned char *entry = (unsigned char *) (ab + 1);
@@ -108,9 +109,10 @@ static void *element_at(struct dm_array_info *info, struct array_block *ab,
* in an array block.
*/
static void on_entries(struct dm_array_info *info, struct array_block *ab,
- void (*fn)(void *, const void *, unsigned))
+ void (*fn)(void *, const void *, unsigned int))
{
- unsigned nr_entries = le32_to_cpu(ab->nr_entries);
+ unsigned int nr_entries = le32_to_cpu(ab->nr_entries);
+
fn(info->value_type.context, element_at(info, ab, 0), nr_entries);
}
@@ -171,7 +173,7 @@ static int alloc_ablock(struct dm_array_info *info, size_t size_of_block,
* the current number of entries.
*/
static void fill_ablock(struct dm_array_info *info, struct array_block *ab,
- const void *value, unsigned new_nr)
+ const void *value, unsigned int new_nr)
{
uint32_t nr_entries, delta, i;
struct dm_btree_value_type *vt = &info->value_type;
@@ -194,7 +196,7 @@ static void fill_ablock(struct dm_array_info *info, struct array_block *ab,
* entries.
*/
static void trim_ablock(struct dm_array_info *info, struct array_block *ab,
- unsigned new_nr)
+ unsigned int new_nr)
{
uint32_t nr_entries, delta;
struct dm_btree_value_type *vt = &info->value_type;
@@ -247,7 +249,7 @@ static void unlock_ablock(struct dm_array_info *info, struct dm_block *block)
* / max_entries).
*/
static int lookup_ablock(struct dm_array_info *info, dm_block_t root,
- unsigned index, struct dm_block **block,
+ unsigned int index, struct dm_block **block,
struct array_block **ab)
{
int r;
@@ -295,7 +297,7 @@ static int __shadow_ablock(struct dm_array_info *info, dm_block_t b,
* The shadow op will often be a noop. Only insert if it really
* copied data.
*/
-static int __reinsert_ablock(struct dm_array_info *info, unsigned index,
+static int __reinsert_ablock(struct dm_array_info *info, unsigned int index,
struct dm_block *block, dm_block_t b,
dm_block_t *root)
{
@@ -321,7 +323,7 @@ static int __reinsert_ablock(struct dm_array_info *info, unsigned index,
* for both the current root block, and the new one.
*/
static int shadow_ablock(struct dm_array_info *info, dm_block_t *root,
- unsigned index, struct dm_block **block,
+ unsigned int index, struct dm_block **block,
struct array_block **ab)
{
int r;
@@ -346,7 +348,7 @@ static int shadow_ablock(struct dm_array_info *info, dm_block_t *root,
*/
static int insert_new_ablock(struct dm_array_info *info, size_t size_of_block,
uint32_t max_entries,
- unsigned block_index, uint32_t nr,
+ unsigned int block_index, uint32_t nr,
const void *value, dm_block_t *root)
{
int r;
@@ -365,8 +367,8 @@ static int insert_new_ablock(struct dm_array_info *info, size_t size_of_block,
}
static int insert_full_ablocks(struct dm_array_info *info, size_t size_of_block,
- unsigned begin_block, unsigned end_block,
- unsigned max_entries, const void *value,
+ unsigned int begin_block, unsigned int end_block,
+ unsigned int max_entries, const void *value,
dm_block_t *root)
{
int r = 0;
@@ -402,20 +404,20 @@ struct resize {
/*
* Maximum nr entries in an array block.
*/
- unsigned max_entries;
+ unsigned int max_entries;
/*
* nr of completely full blocks in the array.
*
* 'old' refers to before the resize, 'new' after.
*/
- unsigned old_nr_full_blocks, new_nr_full_blocks;
+ unsigned int old_nr_full_blocks, new_nr_full_blocks;
/*
* Number of entries in the final block. 0 iff only full blocks in
* the array.
*/
- unsigned old_nr_entries_in_last_block, new_nr_entries_in_last_block;
+ unsigned int old_nr_entries_in_last_block, new_nr_entries_in_last_block;
/*
* The default value used when growing the array.
@@ -430,13 +432,14 @@ struct resize {
* begin_index - the index of the first array block to remove.
* end_index - the one-past-the-end value. ie. this block is not removed.
*/
-static int drop_blocks(struct resize *resize, unsigned begin_index,
- unsigned end_index)
+static int drop_blocks(struct resize *resize, unsigned int begin_index,
+ unsigned int end_index)
{
int r;
while (begin_index != end_index) {
uint64_t key = begin_index++;
+
r = dm_btree_remove(&resize->info->btree_info, resize->root,
&key, &resize->root);
if (r)
@@ -449,8 +452,8 @@ static int drop_blocks(struct resize *resize, unsigned begin_index,
/*
* Calculates how many blocks are needed for the array.
*/
-static unsigned total_nr_blocks_needed(unsigned nr_full_blocks,
- unsigned nr_entries_in_last_block)
+static unsigned int total_nr_blocks_needed(unsigned int nr_full_blocks,
+ unsigned int nr_entries_in_last_block)
{
return nr_full_blocks + (nr_entries_in_last_block ? 1 : 0);
}
@@ -461,7 +464,7 @@ static unsigned total_nr_blocks_needed(unsigned nr_full_blocks,
static int shrink(struct resize *resize)
{
int r;
- unsigned begin, end;
+ unsigned int begin, end;
struct dm_block *block;
struct array_block *ab;
@@ -527,7 +530,7 @@ static int grow_add_tail_block(struct resize *resize)
static int grow_needs_more_blocks(struct resize *resize)
{
int r;
- unsigned old_nr_blocks = resize->old_nr_full_blocks;
+ unsigned int old_nr_blocks = resize->old_nr_full_blocks;
if (resize->old_nr_entries_in_last_block > 0) {
old_nr_blocks++;
@@ -569,11 +572,11 @@ static int grow(struct resize *resize)
* These are the value_type functions for the btree elements, which point
* to array blocks.
*/
-static void block_inc(void *context, const void *value, unsigned count)
+static void block_inc(void *context, const void *value, unsigned int count)
{
const __le64 *block_le = value;
struct dm_array_info *info = context;
- unsigned i;
+ unsigned int i;
for (i = 0; i < count; i++, block_le++)
dm_tm_inc(info->btree_info.tm, le64_to_cpu(*block_le));
@@ -618,9 +621,10 @@ static void __block_dec(void *context, const void *value)
dm_tm_dec(info->btree_info.tm, b);
}
-static void block_dec(void *context, const void *value, unsigned count)
+static void block_dec(void *context, const void *value, unsigned int count)
{
- unsigned i;
+ unsigned int i;
+
for (i = 0; i < count; i++, value += sizeof(__le64))
__block_dec(context, value);
}
@@ -691,19 +695,21 @@ static int array_resize(struct dm_array_info *info, dm_block_t root,
int dm_array_resize(struct dm_array_info *info, dm_block_t root,
uint32_t old_size, uint32_t new_size,
const void *value, dm_block_t *new_root)
- __dm_written_to_disk(value)
+ __dm_written_to_disk(value)
{
int r = array_resize(info, root, old_size, new_size, value, new_root);
+
__dm_unbless_for_disk(value);
return r;
}
EXPORT_SYMBOL_GPL(dm_array_resize);
static int populate_ablock_with_values(struct dm_array_info *info, struct array_block *ab,
- value_fn fn, void *context, unsigned base, unsigned new_nr)
+ value_fn fn, void *context,
+ unsigned int base, unsigned int new_nr)
{
int r;
- unsigned i;
+ unsigned int i;
struct dm_btree_value_type *vt = &info->value_type;
BUG_ON(le32_to_cpu(ab->nr_entries));
@@ -728,7 +734,7 @@ int dm_array_new(struct dm_array_info *info, dm_block_t *root,
int r;
struct dm_block *block;
struct array_block *ab;
- unsigned block_index, end_block, size_of_block, max_entries;
+ unsigned int block_index, end_block, size_of_block, max_entries;
r = dm_array_empty(info, root);
if (r)
@@ -776,7 +782,7 @@ int dm_array_get_value(struct dm_array_info *info, dm_block_t root,
struct dm_block *block;
struct array_block *ab;
size_t size_of_block;
- unsigned entry, max_entries;
+ unsigned int entry, max_entries;
size_of_block = dm_bm_block_size(dm_tm_get_bm(info->btree_info.tm));
max_entries = calc_max_entries(info->value_type.size, size_of_block);
@@ -804,8 +810,8 @@ static int array_set_value(struct dm_array_info *info, dm_block_t root,
struct dm_block *block;
struct array_block *ab;
size_t size_of_block;
- unsigned max_entries;
- unsigned entry;
+ unsigned int max_entries;
+ unsigned int entry;
void *old_value;
struct dm_btree_value_type *vt = &info->value_type;
@@ -840,7 +846,7 @@ out:
int dm_array_set_value(struct dm_array_info *info, dm_block_t root,
uint32_t index, const void *value, dm_block_t *new_root)
- __dm_written_to_disk(value)
+ __dm_written_to_disk(value)
{
int r;
@@ -861,9 +867,9 @@ static int walk_ablock(void *context, uint64_t *keys, void *leaf)
struct walk_info *wi = context;
int r;
- unsigned i;
+ unsigned int i;
__le64 block_le;
- unsigned nr_entries, max_entries;
+ unsigned int nr_entries, max_entries;
struct dm_block *block;
struct array_block *ab;
diff --git a/drivers/md/persistent-data/dm-array.h b/drivers/md/persistent-data/dm-array.h
index d7d2d579c662..91d6165427b3 100644
--- a/drivers/md/persistent-data/dm-array.h
+++ b/drivers/md/persistent-data/dm-array.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2012 Red Hat, Inc.
*
@@ -198,7 +199,7 @@ struct dm_array_cursor {
struct dm_block *block;
struct array_block *ab;
- unsigned index;
+ unsigned int index;
};
int dm_array_cursor_begin(struct dm_array_info *info,
diff --git a/drivers/md/persistent-data/dm-bitset.c b/drivers/md/persistent-data/dm-bitset.c
index b7208d82e748..00c0a3f186b7 100644
--- a/drivers/md/persistent-data/dm-bitset.c
+++ b/drivers/md/persistent-data/dm-bitset.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Red Hat, Inc.
*
@@ -41,7 +42,7 @@ EXPORT_SYMBOL_GPL(dm_bitset_empty);
struct packer_context {
bit_value_fn fn;
- unsigned nr_bits;
+ unsigned int nr_bits;
void *context;
};
@@ -49,7 +50,7 @@ static int pack_bits(uint32_t index, void *value, void *context)
{
int r;
struct packer_context *p = context;
- unsigned bit, nr = min(64u, p->nr_bits - (index * 64));
+ unsigned int bit, nr = min(64u, p->nr_bits - (index * 64));
uint64_t word = 0;
bool bv;
@@ -73,6 +74,7 @@ int dm_bitset_new(struct dm_disk_bitset *info, dm_block_t *root,
uint32_t size, bit_value_fn fn, void *context)
{
struct packer_context p;
+
p.fn = fn;
p.nr_bits = size;
p.context = context;
@@ -147,7 +149,7 @@ static int get_array_entry(struct dm_disk_bitset *info, dm_block_t root,
uint32_t index, dm_block_t *new_root)
{
int r;
- unsigned array_index = index / BITS_PER_ARRAY_ENTRY;
+ unsigned int array_index = index / BITS_PER_ARRAY_ENTRY;
if (info->current_index_set) {
if (info->current_index == array_index)
@@ -165,7 +167,7 @@ int dm_bitset_set_bit(struct dm_disk_bitset *info, dm_block_t root,
uint32_t index, dm_block_t *new_root)
{
int r;
- unsigned b = index % BITS_PER_ARRAY_ENTRY;
+ unsigned int b = index % BITS_PER_ARRAY_ENTRY;
r = get_array_entry(info, root, index, new_root);
if (r)
@@ -182,7 +184,7 @@ int dm_bitset_clear_bit(struct dm_disk_bitset *info, dm_block_t root,
uint32_t index, dm_block_t *new_root)
{
int r;
- unsigned b = index % BITS_PER_ARRAY_ENTRY;
+ unsigned int b = index % BITS_PER_ARRAY_ENTRY;
r = get_array_entry(info, root, index, new_root);
if (r)
@@ -199,7 +201,7 @@ int dm_bitset_test_bit(struct dm_disk_bitset *info, dm_block_t root,
uint32_t index, dm_block_t *new_root, bool *result)
{
int r;
- unsigned b = index % BITS_PER_ARRAY_ENTRY;
+ unsigned int b = index % BITS_PER_ARRAY_ENTRY;
r = get_array_entry(info, root, index, new_root);
if (r)
diff --git a/drivers/md/persistent-data/dm-bitset.h b/drivers/md/persistent-data/dm-bitset.h
index df888da04ee1..a3392ece5fab 100644
--- a/drivers/md/persistent-data/dm-bitset.h
+++ b/drivers/md/persistent-data/dm-bitset.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2012 Red Hat, Inc.
*
diff --git a/drivers/md/persistent-data/dm-block-manager.c b/drivers/md/persistent-data/dm-block-manager.c
index 11935864f50f..7bdfc23f758a 100644
--- a/drivers/md/persistent-data/dm-block-manager.c
+++ b/drivers/md/persistent-data/dm-block-manager.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2011 Red Hat, Inc.
*
@@ -57,10 +58,10 @@ struct waiter {
int wants_write;
};
-static unsigned __find_holder(struct block_lock *lock,
+static unsigned int __find_holder(struct block_lock *lock,
struct task_struct *task)
{
- unsigned i;
+ unsigned int i;
for (i = 0; i < MAX_HOLDERS; i++)
if (lock->holders[i] == task)
@@ -73,7 +74,7 @@ static unsigned __find_holder(struct block_lock *lock,
/* call this *after* you increment lock->count */
static void __add_holder(struct block_lock *lock, struct task_struct *task)
{
- unsigned h = __find_holder(lock, NULL);
+ unsigned int h = __find_holder(lock, NULL);
#ifdef CONFIG_DM_DEBUG_BLOCK_STACK_TRACING
struct stack_store *t;
#endif
@@ -90,14 +91,15 @@ static void __add_holder(struct block_lock *lock, struct task_struct *task)
/* call this *before* you decrement lock->count */
static void __del_holder(struct block_lock *lock, struct task_struct *task)
{
- unsigned h = __find_holder(lock, task);
+ unsigned int h = __find_holder(lock, task);
+
lock->holders[h] = NULL;
put_task_struct(task);
}
static int __check_holder(struct block_lock *lock)
{
- unsigned i;
+ unsigned int i;
for (i = 0; i < MAX_HOLDERS; i++) {
if (lock->holders[i] == current) {
@@ -354,6 +356,7 @@ struct buffer_aux {
static void dm_block_manager_alloc_callback(struct dm_buffer *buf)
{
struct buffer_aux *aux = dm_bufio_get_aux_data(buf);
+
aux->validator = NULL;
bl_init(&aux->lock);
}
@@ -361,23 +364,26 @@ static void dm_block_manager_alloc_callback(struct dm_buffer *buf)
static void dm_block_manager_write_callback(struct dm_buffer *buf)
{
struct buffer_aux *aux = dm_bufio_get_aux_data(buf);
+
if (aux->validator) {
aux->validator->prepare_for_write(aux->validator, (struct dm_block *) buf,
dm_bufio_get_block_size(dm_bufio_get_client(buf)));
}
}
-/*----------------------------------------------------------------
+/*
+ * -------------------------------------------------------------
* Public interface
- *--------------------------------------------------------------*/
+ *--------------------------------------------------------------
+ */
struct dm_block_manager {
struct dm_bufio_client *bufio;
bool read_only:1;
};
struct dm_block_manager *dm_block_manager_create(struct block_device *bdev,
- unsigned block_size,
- unsigned max_held_per_thread)
+ unsigned int block_size,
+ unsigned int max_held_per_thread)
{
int r;
struct dm_block_manager *bm;
@@ -415,7 +421,7 @@ void dm_block_manager_destroy(struct dm_block_manager *bm)
}
EXPORT_SYMBOL_GPL(dm_block_manager_destroy);
-unsigned dm_bm_block_size(struct dm_block_manager *bm)
+unsigned int dm_bm_block_size(struct dm_block_manager *bm)
{
return dm_bufio_get_block_size(bm->bufio);
}
@@ -433,6 +439,7 @@ static int dm_bm_validate_buffer(struct dm_block_manager *bm,
{
if (unlikely(!aux->validator)) {
int r;
+
if (!v)
return 0;
r = v->check(v, (struct dm_block *) buf, dm_bufio_get_block_size(bm->bufio));
@@ -588,8 +595,7 @@ EXPORT_SYMBOL_GPL(dm_bm_write_lock_zero);
void dm_bm_unlock(struct dm_block *b)
{
- struct buffer_aux *aux;
- aux = dm_bufio_get_aux_data(to_buffer(b));
+ struct buffer_aux *aux = dm_bufio_get_aux_data(to_buffer(b));
if (aux->write_locked) {
dm_bufio_mark_buffer_dirty(to_buffer(b));
@@ -617,7 +623,7 @@ void dm_bm_prefetch(struct dm_block_manager *bm, dm_block_t b)
bool dm_bm_is_read_only(struct dm_block_manager *bm)
{
- return (bm ? bm->read_only : true);
+ return bm ? bm->read_only : true;
}
EXPORT_SYMBOL_GPL(dm_bm_is_read_only);
diff --git a/drivers/md/persistent-data/dm-block-manager.h b/drivers/md/persistent-data/dm-block-manager.h
index e728937f376a..5746b0f82a03 100644
--- a/drivers/md/persistent-data/dm-block-manager.h
+++ b/drivers/md/persistent-data/dm-block-manager.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2011 Red Hat, Inc.
*
@@ -32,11 +33,11 @@ void *dm_block_data(struct dm_block *b);
*/
struct dm_block_manager;
struct dm_block_manager *dm_block_manager_create(
- struct block_device *bdev, unsigned block_size,
- unsigned max_held_per_thread);
+ struct block_device *bdev, unsigned int block_size,
+ unsigned int max_held_per_thread);
void dm_block_manager_destroy(struct dm_block_manager *bm);
-unsigned dm_bm_block_size(struct dm_block_manager *bm);
+unsigned int dm_bm_block_size(struct dm_block_manager *bm);
dm_block_t dm_bm_nr_blocks(struct dm_block_manager *bm);
/*----------------------------------------------------------------*/
diff --git a/drivers/md/persistent-data/dm-btree-internal.h b/drivers/md/persistent-data/dm-btree-internal.h
index 893edb426dba..7ed2ce656fcc 100644
--- a/drivers/md/persistent-data/dm-btree-internal.h
+++ b/drivers/md/persistent-data/dm-btree-internal.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2011 Red Hat, Inc.
*
@@ -34,12 +35,12 @@ struct node_header {
__le32 max_entries;
__le32 value_size;
__le32 padding;
-} __attribute__((packed, aligned(8)));
+} __packed __aligned(8);
struct btree_node {
struct node_header header;
__le64 keys[];
-} __attribute__((packed, aligned(8)));
+} __packed __aligned(8);
/*
@@ -118,6 +119,7 @@ static inline void *value_base(struct btree_node *n)
static inline void *value_ptr(struct btree_node *n, uint32_t index)
{
uint32_t value_size = le32_to_cpu(n->header.value_size);
+
return value_base(n) + (value_size * index);
}
diff --git a/drivers/md/persistent-data/dm-btree-remove.c b/drivers/md/persistent-data/dm-btree-remove.c
index 4ead31e0d8ce..942cd47eb52d 100644
--- a/drivers/md/persistent-data/dm-btree-remove.c
+++ b/drivers/md/persistent-data/dm-btree-remove.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2011 Red Hat, Inc.
*
@@ -86,6 +87,7 @@ static int node_copy(struct btree_node *left, struct btree_node *right, int shif
{
uint32_t nr_left = le32_to_cpu(left->header.nr_entries);
uint32_t value_size = le32_to_cpu(left->header.value_size);
+
if (value_size != le32_to_cpu(right->header.value_size)) {
DMERR("mismatched value size");
return -EILSEQ;
@@ -124,11 +126,12 @@ static int node_copy(struct btree_node *left, struct btree_node *right, int shif
/*
* Delete a specific entry from a leaf node.
*/
-static void delete_at(struct btree_node *n, unsigned index)
+static void delete_at(struct btree_node *n, unsigned int index)
{
- unsigned nr_entries = le32_to_cpu(n->header.nr_entries);
- unsigned nr_to_copy = nr_entries - (index + 1);
+ unsigned int nr_entries = le32_to_cpu(n->header.nr_entries);
+ unsigned int nr_to_copy = nr_entries - (index + 1);
uint32_t value_size = le32_to_cpu(n->header.value_size);
+
BUG_ON(index >= nr_entries);
if (nr_to_copy) {
@@ -144,20 +147,20 @@ static void delete_at(struct btree_node *n, unsigned index)
n->header.nr_entries = cpu_to_le32(nr_entries - 1);
}
-static unsigned merge_threshold(struct btree_node *n)
+static unsigned int merge_threshold(struct btree_node *n)
{
return le32_to_cpu(n->header.max_entries) / 3;
}
struct child {
- unsigned index;
+ unsigned int index;
struct dm_block *block;
struct btree_node *n;
};
static int init_child(struct dm_btree_info *info, struct dm_btree_value_type *vt,
struct btree_node *parent,
- unsigned index, struct child *result)
+ unsigned int index, struct child *result)
{
int r, inc;
dm_block_t root;
@@ -263,7 +266,8 @@ static int __rebalance2(struct dm_btree_info *info, struct btree_node *parent,
/*
* Rebalance.
*/
- unsigned target_left = (nr_left + nr_right) / 2;
+ unsigned int target_left = (nr_left + nr_right) / 2;
+
ret = shift(left, right, nr_left - target_left);
if (ret)
return ret;
@@ -273,7 +277,7 @@ static int __rebalance2(struct dm_btree_info *info, struct btree_node *parent,
}
static int rebalance2(struct shadow_spine *s, struct dm_btree_info *info,
- struct dm_btree_value_type *vt, unsigned left_index)
+ struct dm_btree_value_type *vt, unsigned int left_index)
{
int r;
struct btree_node *parent;
@@ -310,7 +314,7 @@ static int delete_center_node(struct dm_btree_info *info, struct btree_node *par
uint32_t nr_left, uint32_t nr_center, uint32_t nr_right)
{
uint32_t max_entries = le32_to_cpu(left->header.max_entries);
- unsigned shift = min(max_entries - nr_left, nr_center);
+ unsigned int shift = min(max_entries - nr_left, nr_center);
if (nr_left + shift > max_entries) {
DMERR("node shift out of bounds");
@@ -351,10 +355,10 @@ static int redistribute3(struct dm_btree_info *info, struct btree_node *parent,
{
int s, ret;
uint32_t max_entries = le32_to_cpu(left->header.max_entries);
- unsigned total = nr_left + nr_center + nr_right;
- unsigned target_right = total / 3;
- unsigned remainder = (target_right * 3) != total;
- unsigned target_left = target_right + remainder;
+ unsigned int total = nr_left + nr_center + nr_right;
+ unsigned int target_right = total / 3;
+ unsigned int remainder = (target_right * 3) != total;
+ unsigned int target_left = target_right + remainder;
BUG_ON(target_left > max_entries);
BUG_ON(target_right > max_entries);
@@ -422,7 +426,7 @@ static int __rebalance3(struct dm_btree_info *info, struct btree_node *parent,
uint32_t nr_center = le32_to_cpu(center->header.nr_entries);
uint32_t nr_right = le32_to_cpu(right->header.nr_entries);
- unsigned threshold = merge_threshold(left) * 4 + 1;
+ unsigned int threshold = merge_threshold(left) * 4 + 1;
if ((left->header.max_entries != center->header.max_entries) ||
(center->header.max_entries != right->header.max_entries)) {
@@ -440,7 +444,7 @@ static int __rebalance3(struct dm_btree_info *info, struct btree_node *parent,
}
static int rebalance3(struct shadow_spine *s, struct dm_btree_info *info,
- struct dm_btree_value_type *vt, unsigned left_index)
+ struct dm_btree_value_type *vt, unsigned int left_index)
{
int r;
struct btree_node *parent = dm_block_data(shadow_current(s));
@@ -519,7 +523,7 @@ static int rebalance_children(struct shadow_spine *s,
return r;
}
-static int do_leaf(struct btree_node *n, uint64_t key, unsigned *index)
+static int do_leaf(struct btree_node *n, uint64_t key, unsigned int *index)
{
int i = lower_bound(n, key);
@@ -539,7 +543,7 @@ static int do_leaf(struct btree_node *n, uint64_t key, unsigned *index)
*/
static int remove_raw(struct shadow_spine *s, struct dm_btree_info *info,
struct dm_btree_value_type *vt, dm_block_t root,
- uint64_t key, unsigned *index)
+ uint64_t key, unsigned int *index)
{
int i = *index, r;
struct btree_node *n;
@@ -556,6 +560,7 @@ static int remove_raw(struct shadow_spine *s, struct dm_btree_info *info,
*/
if (shadow_has_parent(s)) {
__le64 location = cpu_to_le64(dm_block_location(shadow_current(s)));
+
memcpy(value_ptr(dm_block_data(shadow_parent(s)), i),
&location, sizeof(__le64));
}
@@ -589,7 +594,7 @@ static int remove_raw(struct shadow_spine *s, struct dm_btree_info *info,
int dm_btree_remove(struct dm_btree_info *info, dm_block_t root,
uint64_t *keys, dm_block_t *new_root)
{
- unsigned level, last_level = info->levels - 1;
+ unsigned int level, last_level = info->levels - 1;
int index = 0, r = 0;
struct shadow_spine spine;
struct btree_node *n;
@@ -601,7 +606,7 @@ int dm_btree_remove(struct dm_btree_info *info, dm_block_t root,
r = remove_raw(&spine, info,
(level == last_level ?
&info->value_type : &le64_vt),
- root, keys[level], (unsigned *)&index);
+ root, keys[level], (unsigned int *)&index);
if (r < 0)
break;
@@ -649,6 +654,7 @@ static int remove_nearest(struct shadow_spine *s, struct dm_btree_info *info,
*/
if (shadow_has_parent(s)) {
__le64 location = cpu_to_le64(dm_block_location(shadow_current(s)));
+
memcpy(value_ptr(dm_block_data(shadow_parent(s)), i),
&location, sizeof(__le64));
}
@@ -685,9 +691,9 @@ static int remove_nearest(struct shadow_spine *s, struct dm_btree_info *info,
static int remove_one(struct dm_btree_info *info, dm_block_t root,
uint64_t *keys, uint64_t end_key,
- dm_block_t *new_root, unsigned *nr_removed)
+ dm_block_t *new_root, unsigned int *nr_removed)
{
- unsigned level, last_level = info->levels - 1;
+ unsigned int level, last_level = info->levels - 1;
int index = 0, r = 0;
struct shadow_spine spine;
struct btree_node *n;
@@ -698,7 +704,7 @@ static int remove_one(struct dm_btree_info *info, dm_block_t root,
init_shadow_spine(&spine, info);
for (level = 0; level < last_level; level++) {
r = remove_raw(&spine, info, &le64_vt,
- root, keys[level], (unsigned *) &index);
+ root, keys[level], (unsigned int *) &index);
if (r < 0)
goto out;
@@ -742,7 +748,7 @@ out:
int dm_btree_remove_leaves(struct dm_btree_info *info, dm_block_t root,
uint64_t *first_key, uint64_t end_key,
- dm_block_t *new_root, unsigned *nr_removed)
+ dm_block_t *new_root, unsigned int *nr_removed)
{
int r;
diff --git a/drivers/md/persistent-data/dm-btree-spine.c b/drivers/md/persistent-data/dm-btree-spine.c
index e653458888a7..7540383b7cf3 100644
--- a/drivers/md/persistent-data/dm-btree-spine.c
+++ b/drivers/md/persistent-data/dm-btree-spine.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2011 Red Hat, Inc.
*
@@ -39,7 +40,7 @@ static int node_check(struct dm_block_validator *v,
uint32_t flags, nr_entries, max_entries;
if (dm_block_location(b) != le64_to_cpu(h->blocknr)) {
- DMERR_LIMIT("node_check failed: blocknr %llu != wanted %llu",
+ DMERR_LIMIT("%s failed: blocknr %llu != wanted %llu", __func__,
le64_to_cpu(h->blocknr), dm_block_location(b));
return -ENOTBLK;
}
@@ -48,7 +49,7 @@ static int node_check(struct dm_block_validator *v,
block_size - sizeof(__le32),
BTREE_CSUM_XOR));
if (csum_disk != h->csum) {
- DMERR_LIMIT("node_check failed: csum %u != wanted %u",
+ DMERR_LIMIT("%s failed: csum %u != wanted %u", __func__,
le32_to_cpu(csum_disk), le32_to_cpu(h->csum));
return -EILSEQ;
}
@@ -59,12 +60,12 @@ static int node_check(struct dm_block_validator *v,
if (sizeof(struct node_header) +
(sizeof(__le64) + value_size) * max_entries > block_size) {
- DMERR_LIMIT("node_check failed: max_entries too large");
+ DMERR_LIMIT("%s failed: max_entries too large", __func__);
return -EILSEQ;
}
if (nr_entries > max_entries) {
- DMERR_LIMIT("node_check failed: too many entries");
+ DMERR_LIMIT("%s failed: too many entries", __func__);
return -EILSEQ;
}
@@ -73,7 +74,7 @@ static int node_check(struct dm_block_validator *v,
*/
flags = le32_to_cpu(h->flags);
if (!(flags & INTERNAL_NODE) && !(flags & LEAF_NODE)) {
- DMERR_LIMIT("node_check failed: node is neither INTERNAL or LEAF");
+ DMERR_LIMIT("%s failed: node is neither INTERNAL or LEAF", __func__);
return -EILSEQ;
}
@@ -132,9 +133,8 @@ void exit_ro_spine(struct ro_spine *s)
{
int i;
- for (i = 0; i < s->count; i++) {
+ for (i = 0; i < s->count; i++)
unlock_block(s->info, s->nodes[i]);
- }
}
int ro_step(struct ro_spine *s, dm_block_t new_child)
@@ -183,9 +183,8 @@ void exit_shadow_spine(struct shadow_spine *s)
{
int i;
- for (i = 0; i < s->count; i++) {
+ for (i = 0; i < s->count; i++)
unlock_block(s->info, s->nodes[i]);
- }
}
int shadow_step(struct shadow_spine *s, dm_block_t b,
@@ -234,12 +233,12 @@ dm_block_t shadow_root(struct shadow_spine *s)
return s->root;
}
-static void le64_inc(void *context, const void *value_le, unsigned count)
+static void le64_inc(void *context, const void *value_le, unsigned int count)
{
dm_tm_with_runs(context, value_le, count, dm_tm_inc_range);
}
-static void le64_dec(void *context, const void *value_le, unsigned count)
+static void le64_dec(void *context, const void *value_le, unsigned int count)
{
dm_tm_with_runs(context, value_le, count, dm_tm_dec_range);
}
diff --git a/drivers/md/persistent-data/dm-btree.c b/drivers/md/persistent-data/dm-btree.c
index 5ce64e93aae7..0c7a2e8d1846 100644
--- a/drivers/md/persistent-data/dm-btree.c
+++ b/drivers/md/persistent-data/dm-btree.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2011 Red Hat, Inc.
*
@@ -13,9 +14,11 @@
#define DM_MSG_PREFIX "btree"
-/*----------------------------------------------------------------
+/*
+ *--------------------------------------------------------------
* Array manipulation
- *--------------------------------------------------------------*/
+ *--------------------------------------------------------------
+ */
static void memcpy_disk(void *dest, const void *src, size_t len)
__dm_written_to_disk(src)
{
@@ -23,8 +26,8 @@ static void memcpy_disk(void *dest, const void *src, size_t len)
__dm_unbless_for_disk(src);
}
-static void array_insert(void *base, size_t elt_size, unsigned nr_elts,
- unsigned index, void *elt)
+static void array_insert(void *base, size_t elt_size, unsigned int nr_elts,
+ unsigned int index, void *elt)
__dm_written_to_disk(elt)
{
if (index < nr_elts)
@@ -80,7 +83,7 @@ void inc_children(struct dm_transaction_manager *tm, struct btree_node *n,
vt->inc(vt->context, value_ptr(n, 0), nr_entries);
}
-static int insert_at(size_t value_size, struct btree_node *node, unsigned index,
+static int insert_at(size_t value_size, struct btree_node *node, unsigned int index,
uint64_t key, void *value)
__dm_written_to_disk(value)
{
@@ -162,9 +165,9 @@ EXPORT_SYMBOL_GPL(dm_btree_empty);
struct frame {
struct dm_block *b;
struct btree_node *n;
- unsigned level;
- unsigned nr_children;
- unsigned current_child;
+ unsigned int level;
+ unsigned int nr_children;
+ unsigned int current_child;
};
struct del_stack {
@@ -193,7 +196,7 @@ static int unprocessed_frames(struct del_stack *s)
static void prefetch_children(struct del_stack *s, struct frame *f)
{
- unsigned i;
+ unsigned int i;
struct dm_block_manager *bm = dm_tm_get_bm(s->tm);
for (i = 0; i < f->nr_children; i++)
@@ -205,7 +208,7 @@ static bool is_internal_level(struct dm_btree_info *info, struct frame *f)
return f->level < (info->levels - 1);
}
-static int push_frame(struct del_stack *s, dm_block_t b, unsigned level)
+static int push_frame(struct del_stack *s, dm_block_t b, unsigned int level)
{
int r;
uint32_t ref_count;
@@ -371,7 +374,7 @@ static int btree_lookup_raw(struct ro_spine *s, dm_block_t block, uint64_t key,
int dm_btree_lookup(struct dm_btree_info *info, dm_block_t root,
uint64_t *keys, void *value_le)
{
- unsigned level, last_level = info->levels - 1;
+ unsigned int level, last_level = info->levels - 1;
int r = -ENODATA;
uint64_t rkey;
__le64 internal_value_le;
@@ -467,7 +470,7 @@ out:
int dm_btree_lookup_next(struct dm_btree_info *info, dm_block_t root,
uint64_t *keys, uint64_t *rkey, void *value_le)
{
- unsigned level;
+ unsigned int level;
int r = -ENODATA;
__le64 internal_value_le;
struct ro_spine spine;
@@ -493,7 +496,6 @@ out:
exit_ro_spine(&spine);
return r;
}
-
EXPORT_SYMBOL_GPL(dm_btree_lookup_next);
/*----------------------------------------------------------------*/
@@ -502,11 +504,12 @@ EXPORT_SYMBOL_GPL(dm_btree_lookup_next);
* Copies entries from one region of a btree node to another. The regions
* must not overlap.
*/
-static void copy_entries(struct btree_node *dest, unsigned dest_offset,
- struct btree_node *src, unsigned src_offset,
- unsigned count)
+static void copy_entries(struct btree_node *dest, unsigned int dest_offset,
+ struct btree_node *src, unsigned int src_offset,
+ unsigned int count)
{
size_t value_size = le32_to_cpu(dest->header.value_size);
+
memcpy(dest->keys + dest_offset, src->keys + src_offset, count * sizeof(uint64_t));
memcpy(value_ptr(dest, dest_offset), value_ptr(src, src_offset), count * value_size);
}
@@ -515,11 +518,12 @@ static void copy_entries(struct btree_node *dest, unsigned dest_offset,
* Moves entries from one region fo a btree node to another. The regions
* may overlap.
*/
-static void move_entries(struct btree_node *dest, unsigned dest_offset,
- struct btree_node *src, unsigned src_offset,
- unsigned count)
+static void move_entries(struct btree_node *dest, unsigned int dest_offset,
+ struct btree_node *src, unsigned int src_offset,
+ unsigned int count)
{
size_t value_size = le32_to_cpu(dest->header.value_size);
+
memmove(dest->keys + dest_offset, src->keys + src_offset, count * sizeof(uint64_t));
memmove(value_ptr(dest, dest_offset), value_ptr(src, src_offset), count * value_size);
}
@@ -528,7 +532,7 @@ static void move_entries(struct btree_node *dest, unsigned dest_offset,
* Erases the first 'count' entries of a btree node, shifting following
* entries down into their place.
*/
-static void shift_down(struct btree_node *n, unsigned count)
+static void shift_down(struct btree_node *n, unsigned int count)
{
move_entries(n, 0, n, count, le32_to_cpu(n->header.nr_entries) - count);
}
@@ -537,7 +541,7 @@ static void shift_down(struct btree_node *n, unsigned count)
* Moves entries in a btree node up 'count' places, making space for
* new entries at the start of the node.
*/
-static void shift_up(struct btree_node *n, unsigned count)
+static void shift_up(struct btree_node *n, unsigned int count)
{
move_entries(n, count, n, 0, le32_to_cpu(n->header.nr_entries));
}
@@ -548,18 +552,20 @@ static void shift_up(struct btree_node *n, unsigned count)
*/
static void redistribute2(struct btree_node *left, struct btree_node *right)
{
- unsigned nr_left = le32_to_cpu(left->header.nr_entries);
- unsigned nr_right = le32_to_cpu(right->header.nr_entries);
- unsigned total = nr_left + nr_right;
- unsigned target_left = total / 2;
- unsigned target_right = total - target_left;
+ unsigned int nr_left = le32_to_cpu(left->header.nr_entries);
+ unsigned int nr_right = le32_to_cpu(right->header.nr_entries);
+ unsigned int total = nr_left + nr_right;
+ unsigned int target_left = total / 2;
+ unsigned int target_right = total - target_left;
if (nr_left < target_left) {
- unsigned delta = target_left - nr_left;
+ unsigned int delta = target_left - nr_left;
+
copy_entries(left, nr_left, right, 0, delta);
shift_down(right, delta);
} else if (nr_left > target_left) {
- unsigned delta = nr_left - target_left;
+ unsigned int delta = nr_left - target_left;
+
if (nr_right)
shift_up(right, delta);
copy_entries(right, 0, left, target_left, delta);
@@ -576,10 +582,10 @@ static void redistribute2(struct btree_node *left, struct btree_node *right)
static void redistribute3(struct btree_node *left, struct btree_node *center,
struct btree_node *right)
{
- unsigned nr_left = le32_to_cpu(left->header.nr_entries);
- unsigned nr_center = le32_to_cpu(center->header.nr_entries);
- unsigned nr_right = le32_to_cpu(right->header.nr_entries);
- unsigned total, target_left, target_center, target_right;
+ unsigned int nr_left = le32_to_cpu(left->header.nr_entries);
+ unsigned int nr_center = le32_to_cpu(center->header.nr_entries);
+ unsigned int nr_right = le32_to_cpu(right->header.nr_entries);
+ unsigned int total, target_left, target_center, target_right;
BUG_ON(nr_center);
@@ -589,19 +595,22 @@ static void redistribute3(struct btree_node *left, struct btree_node *center,
target_right = (total - target_left - target_center);
if (nr_left < target_left) {
- unsigned left_short = target_left - nr_left;
+ unsigned int left_short = target_left - nr_left;
+
copy_entries(left, nr_left, right, 0, left_short);
copy_entries(center, 0, right, left_short, target_center);
shift_down(right, nr_right - target_right);
} else if (nr_left < (target_left + target_center)) {
- unsigned left_to_center = nr_left - target_left;
+ unsigned int left_to_center = nr_left - target_left;
+
copy_entries(center, 0, left, target_left, left_to_center);
copy_entries(center, left_to_center, right, 0, target_center - left_to_center);
shift_down(right, nr_right - target_right);
} else {
- unsigned right_short = target_right - nr_right;
+ unsigned int right_short = target_right - nr_right;
+
shift_up(right, right_short);
copy_entries(right, 0, left, nr_left - right_short, right_short);
copy_entries(center, 0, left, target_left, nr_left - target_left);
@@ -642,7 +651,7 @@ static void redistribute3(struct btree_node *left, struct btree_node *center,
*
* Where A* is a shadow of A.
*/
-static int split_one_into_two(struct shadow_spine *s, unsigned parent_index,
+static int split_one_into_two(struct shadow_spine *s, unsigned int parent_index,
struct dm_btree_value_type *vt, uint64_t key)
{
int r;
@@ -696,7 +705,7 @@ static int split_one_into_two(struct shadow_spine *s, unsigned parent_index,
* to the new shadow.
*/
static int shadow_child(struct dm_btree_info *info, struct dm_btree_value_type *vt,
- struct btree_node *parent, unsigned index,
+ struct btree_node *parent, unsigned int index,
struct dm_block **result)
{
int r, inc;
@@ -725,11 +734,11 @@ static int shadow_child(struct dm_btree_info *info, struct dm_btree_value_type *
* Splits two nodes into three. This is more work, but results in fuller
* nodes, so saves metadata space.
*/
-static int split_two_into_three(struct shadow_spine *s, unsigned parent_index,
- struct dm_btree_value_type *vt, uint64_t key)
+static int split_two_into_three(struct shadow_spine *s, unsigned int parent_index,
+ struct dm_btree_value_type *vt, uint64_t key)
{
int r;
- unsigned middle_index;
+ unsigned int middle_index;
struct dm_block *left, *middle, *right, *parent;
struct btree_node *ln, *rn, *mn, *pn;
__le64 location;
@@ -781,7 +790,7 @@ static int split_two_into_three(struct shadow_spine *s, unsigned parent_index,
if (shadow_current(s) != right)
unlock_block(s->info, right);
- return r;
+ return r;
}
@@ -830,7 +839,7 @@ static int btree_split_beneath(struct shadow_spine *s, uint64_t key)
{
int r;
size_t size;
- unsigned nr_left, nr_right;
+ unsigned int nr_left, nr_right;
struct dm_block *left, *right, *new_parent;
struct btree_node *pn, *ln, *rn;
__le64 val;
@@ -904,7 +913,7 @@ static int btree_split_beneath(struct shadow_spine *s, uint64_t key)
* Redistributes a node's entries with its left sibling.
*/
static int rebalance_left(struct shadow_spine *s, struct dm_btree_value_type *vt,
- unsigned parent_index, uint64_t key)
+ unsigned int parent_index, uint64_t key)
{
int r;
struct dm_block *sib;
@@ -933,7 +942,7 @@ static int rebalance_left(struct shadow_spine *s, struct dm_btree_value_type *vt
* Redistributes a nodes entries with its right sibling.
*/
static int rebalance_right(struct shadow_spine *s, struct dm_btree_value_type *vt,
- unsigned parent_index, uint64_t key)
+ unsigned int parent_index, uint64_t key)
{
int r;
struct dm_block *sib;
@@ -961,10 +970,10 @@ static int rebalance_right(struct shadow_spine *s, struct dm_btree_value_type *v
/*
* Returns the number of spare entries in a node.
*/
-static int get_node_free_space(struct dm_btree_info *info, dm_block_t b, unsigned *space)
+static int get_node_free_space(struct dm_btree_info *info, dm_block_t b, unsigned int *space)
{
int r;
- unsigned nr_entries;
+ unsigned int nr_entries;
struct dm_block *block;
struct btree_node *node;
@@ -990,17 +999,18 @@ static int get_node_free_space(struct dm_btree_info *info, dm_block_t b, unsigne
*/
#define SPACE_THRESHOLD 8
static int rebalance_or_split(struct shadow_spine *s, struct dm_btree_value_type *vt,
- unsigned parent_index, uint64_t key)
+ unsigned int parent_index, uint64_t key)
{
int r;
struct btree_node *parent = dm_block_data(shadow_parent(s));
- unsigned nr_parent = le32_to_cpu(parent->header.nr_entries);
- unsigned free_space;
+ unsigned int nr_parent = le32_to_cpu(parent->header.nr_entries);
+ unsigned int free_space;
int left_shared = 0, right_shared = 0;
/* Should we move entries to the left sibling? */
if (parent_index > 0) {
dm_block_t left_b = value64(parent, parent_index - 1);
+
r = dm_tm_block_is_shared(s->info->tm, left_b, &left_shared);
if (r)
return r;
@@ -1018,6 +1028,7 @@ static int rebalance_or_split(struct shadow_spine *s, struct dm_btree_value_type
/* Should we move entries to the right sibling? */
if (parent_index < (nr_parent - 1)) {
dm_block_t right_b = value64(parent, parent_index + 1);
+
r = dm_tm_block_is_shared(s->info->tm, right_b, &right_shared);
if (r)
return r;
@@ -1080,7 +1091,7 @@ static bool has_space_for_insert(struct btree_node *node, uint64_t key)
static int btree_insert_raw(struct shadow_spine *s, dm_block_t root,
struct dm_btree_value_type *vt,
- uint64_t key, unsigned *index)
+ uint64_t key, unsigned int *index)
{
int r, i = *index, top = 1;
struct btree_node *node;
@@ -1214,9 +1225,9 @@ int btree_get_overwrite_leaf(struct dm_btree_info *info, dm_block_t root,
}
static bool need_insert(struct btree_node *node, uint64_t *keys,
- unsigned level, unsigned index)
+ unsigned int level, unsigned int index)
{
- return ((index >= le32_to_cpu(node->header.nr_entries)) ||
+ return ((index >= le32_to_cpu(node->header.nr_entries)) ||
(le64_to_cpu(node->keys[index]) != keys[level]));
}
@@ -1226,7 +1237,7 @@ static int insert(struct dm_btree_info *info, dm_block_t root,
__dm_written_to_disk(value)
{
int r;
- unsigned level, index = -1, last_level = info->levels - 1;
+ unsigned int level, index = -1, last_level = info->levels - 1;
dm_block_t block = root;
struct shadow_spine spine;
struct btree_node *n;
@@ -1309,7 +1320,7 @@ bad_unblessed:
int dm_btree_insert(struct dm_btree_info *info, dm_block_t root,
uint64_t *keys, void *value, dm_block_t *new_root)
- __dm_written_to_disk(value)
+ __dm_written_to_disk(value)
{
return insert(info, root, keys, value, new_root, NULL);
}
@@ -1318,7 +1329,7 @@ EXPORT_SYMBOL_GPL(dm_btree_insert);
int dm_btree_insert_notify(struct dm_btree_info *info, dm_block_t root,
uint64_t *keys, void *value, dm_block_t *new_root,
int *inserted)
- __dm_written_to_disk(value)
+ __dm_written_to_disk(value)
{
return insert(info, root, keys, value, new_root, inserted);
}
@@ -1341,8 +1352,8 @@ static int find_key(struct ro_spine *s, dm_block_t block, bool find_highest,
i = le32_to_cpu(ro_node(s)->header.nr_entries);
if (!i)
return -ENODATA;
- else
- i--;
+
+ i--;
if (find_highest)
*result_key = le64_to_cpu(ro_node(s)->keys[i]);
@@ -1412,7 +1423,7 @@ static int walk_node(struct dm_btree_info *info, dm_block_t block,
void *context)
{
int r;
- unsigned i, nr;
+ unsigned int i, nr;
struct dm_block *node;
struct btree_node *n;
uint64_t keys;
@@ -1455,7 +1466,7 @@ EXPORT_SYMBOL_GPL(dm_btree_walk);
static void prefetch_values(struct dm_btree_cursor *c)
{
- unsigned i, nr;
+ unsigned int i, nr;
__le64 value_le;
struct cursor_node *n = c->nodes + c->depth - 1;
struct btree_node *bn = dm_block_data(n->b);
@@ -1585,6 +1596,7 @@ EXPORT_SYMBOL_GPL(dm_btree_cursor_end);
int dm_btree_cursor_next(struct dm_btree_cursor *c)
{
int r = inc_or_backtrack(c);
+
if (!r) {
r = find_leaf(c);
if (r)
diff --git a/drivers/md/persistent-data/dm-btree.h b/drivers/md/persistent-data/dm-btree.h
index d2ae5aa4d00b..1b92acd7823d 100644
--- a/drivers/md/persistent-data/dm-btree.h
+++ b/drivers/md/persistent-data/dm-btree.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2011 Red Hat, Inc.
*
@@ -58,14 +59,14 @@ struct dm_btree_value_type {
* somewhere.) This method is _not_ called for insertion of a new
* value: It is assumed the ref count is already 1.
*/
- void (*inc)(void *context, const void *value, unsigned count);
+ void (*inc)(void *context, const void *value, unsigned int count);
/*
* These values are being deleted. The btree takes care of freeing
* the memory pointed to by @value. Often the del function just
* needs to decrement a reference counts somewhere.
*/
- void (*dec)(void *context, const void *value, unsigned count);
+ void (*dec)(void *context, const void *value, unsigned int count);
/*
* A test for equality between two values. When a value is
@@ -84,7 +85,7 @@ struct dm_btree_info {
/*
* Number of nested btrees. (Not the depth of a single tree.)
*/
- unsigned levels;
+ unsigned int levels;
struct dm_btree_value_type value_type;
};
@@ -121,7 +122,7 @@ int dm_btree_lookup_next(struct dm_btree_info *info, dm_block_t root,
*/
int dm_btree_insert(struct dm_btree_info *info, dm_block_t root,
uint64_t *keys, void *value, dm_block_t *new_root)
- __dm_written_to_disk(value);
+ __dm_written_to_disk(value);
/*
* A variant of insert that indicates whether it actually inserted or just
@@ -149,7 +150,7 @@ int dm_btree_remove(struct dm_btree_info *info, dm_block_t root,
*/
int dm_btree_remove_leaves(struct dm_btree_info *info, dm_block_t root,
uint64_t *keys, uint64_t end_key,
- dm_block_t *new_root, unsigned *nr_removed);
+ dm_block_t *new_root, unsigned int *nr_removed);
/*
* Returns < 0 on failure. Otherwise the number of key entries that have
@@ -188,7 +189,7 @@ int dm_btree_walk(struct dm_btree_info *info, dm_block_t root,
struct cursor_node {
struct dm_block *b;
- unsigned index;
+ unsigned int index;
};
struct dm_btree_cursor {
@@ -196,7 +197,7 @@ struct dm_btree_cursor {
dm_block_t root;
bool prefetch_leaves;
- unsigned depth;
+ unsigned int depth;
struct cursor_node nodes[DM_BTREE_CURSOR_MAX_DEPTH];
};
diff --git a/drivers/md/persistent-data/dm-persistent-data-internal.h b/drivers/md/persistent-data/dm-persistent-data-internal.h
index c49e26fff36c..c482434e566b 100644
--- a/drivers/md/persistent-data/dm-persistent-data-internal.h
+++ b/drivers/md/persistent-data/dm-persistent-data-internal.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2011 Red Hat, Inc.
*
@@ -9,11 +10,11 @@
#include "dm-block-manager.h"
-static inline unsigned dm_hash_block(dm_block_t b, unsigned hash_mask)
+static inline unsigned int dm_hash_block(dm_block_t b, unsigned int hash_mask)
{
- const unsigned BIG_PRIME = 4294967291UL;
+ const unsigned int BIG_PRIME = 4294967291UL;
- return (((unsigned) b) * BIG_PRIME) & hash_mask;
+ return (((unsigned int) b) * BIG_PRIME) & hash_mask;
}
#endif /* _PERSISTENT_DATA_INTERNAL_H */
diff --git a/drivers/md/persistent-data/dm-space-map-common.c b/drivers/md/persistent-data/dm-space-map-common.c
index bfbfa750e016..591d1a43d035 100644
--- a/drivers/md/persistent-data/dm-space-map-common.c
+++ b/drivers/md/persistent-data/dm-space-map-common.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2011 Red Hat, Inc.
*
@@ -41,7 +42,7 @@ static int index_check(struct dm_block_validator *v,
__le32 csum_disk;
if (dm_block_location(b) != le64_to_cpu(mi_le->blocknr)) {
- DMERR_LIMIT("index_check failed: blocknr %llu != wanted %llu",
+ DMERR_LIMIT("%s failed: blocknr %llu != wanted %llu", __func__,
le64_to_cpu(mi_le->blocknr), dm_block_location(b));
return -ENOTBLK;
}
@@ -50,7 +51,7 @@ static int index_check(struct dm_block_validator *v,
block_size - sizeof(__le32),
INDEX_CSUM_XOR));
if (csum_disk != mi_le->csum) {
- DMERR_LIMIT("index_check failed: csum %u != wanted %u",
+ DMERR_LIMIT("i%s failed: csum %u != wanted %u", __func__,
le32_to_cpu(csum_disk), le32_to_cpu(mi_le->csum));
return -EILSEQ;
}
@@ -126,7 +127,7 @@ static void *dm_bitmap_data(struct dm_block *b)
#define WORD_MASK_HIGH 0xAAAAAAAAAAAAAAAAULL
-static unsigned dm_bitmap_word_used(void *addr, unsigned b)
+static unsigned int dm_bitmap_word_used(void *addr, unsigned int b)
{
__le64 *words_le = addr;
__le64 *w_le = words_le + (b >> ENTRIES_SHIFT);
@@ -137,11 +138,11 @@ static unsigned dm_bitmap_word_used(void *addr, unsigned b)
return !(~bits & mask);
}
-static unsigned sm_lookup_bitmap(void *addr, unsigned b)
+static unsigned int sm_lookup_bitmap(void *addr, unsigned int b)
{
__le64 *words_le = addr;
__le64 *w_le = words_le + (b >> ENTRIES_SHIFT);
- unsigned hi, lo;
+ unsigned int hi, lo;
b = (b & (ENTRIES_PER_WORD - 1)) << 1;
hi = !!test_bit_le(b, (void *) w_le);
@@ -149,7 +150,7 @@ static unsigned sm_lookup_bitmap(void *addr, unsigned b)
return (hi << 1) | lo;
}
-static void sm_set_bitmap(void *addr, unsigned b, unsigned val)
+static void sm_set_bitmap(void *addr, unsigned int b, unsigned int val)
{
__le64 *words_le = addr;
__le64 *w_le = words_le + (b >> ENTRIES_SHIFT);
@@ -167,8 +168,8 @@ static void sm_set_bitmap(void *addr, unsigned b, unsigned val)
__clear_bit_le(b + 1, (void *) w_le);
}
-static int sm_find_free(void *addr, unsigned begin, unsigned end,
- unsigned *result)
+static int sm_find_free(void *addr, unsigned int begin, unsigned int end,
+ unsigned int *result)
{
while (begin < end) {
if (!(begin & (ENTRIES_PER_WORD - 1)) &&
@@ -237,7 +238,7 @@ int sm_ll_extend(struct ll_disk *ll, dm_block_t extra_blocks)
{
int r;
dm_block_t i, nr_blocks, nr_indexes;
- unsigned old_blocks, blocks;
+ unsigned int old_blocks, blocks;
nr_blocks = ll->nr_blocks + extra_blocks;
old_blocks = dm_sector_div_up(ll->nr_blocks, ll->entries_per_block);
@@ -351,7 +352,7 @@ int sm_ll_find_free_block(struct ll_disk *ll, dm_block_t begin,
for (i = index_begin; i < index_end; i++, begin = 0) {
struct dm_block *blk;
- unsigned position;
+ unsigned int position;
uint32_t bit_end;
r = ll->load_ie(ll, i, &ie_disk);
@@ -369,7 +370,7 @@ int sm_ll_find_free_block(struct ll_disk *ll, dm_block_t begin,
bit_end = (i == index_end - 1) ? end : ll->entries_per_block;
r = sm_find_free(dm_bitmap_data(blk),
- max_t(unsigned, begin, le32_to_cpu(ie_disk.none_free_before)),
+ max_t(unsigned int, begin, le32_to_cpu(ie_disk.none_free_before)),
bit_end, &position);
if (r == -ENOSPC) {
/*
@@ -390,7 +391,7 @@ int sm_ll_find_free_block(struct ll_disk *ll, dm_block_t begin,
}
int sm_ll_find_common_free_block(struct ll_disk *old_ll, struct ll_disk *new_ll,
- dm_block_t begin, dm_block_t end, dm_block_t *b)
+ dm_block_t begin, dm_block_t end, dm_block_t *b)
{
int r;
uint32_t count;
@@ -608,6 +609,7 @@ static int sm_ll_inc_overflow(struct ll_disk *ll, dm_block_t b, struct inc_conte
static inline int shadow_bitmap(struct ll_disk *ll, struct inc_context *ic)
{
int r, inc;
+
r = dm_tm_shadow_block(ll->tm, le64_to_cpu(ic->ie_disk.blocknr),
&dm_sm_bitmap_validator, &ic->bitmap_block, &inc);
if (r < 0) {
@@ -747,6 +749,7 @@ int sm_ll_inc(struct ll_disk *ll, dm_block_t b, dm_block_t e,
*nr_allocations = 0;
while (b != e) {
int r = __sm_ll_inc(ll, b, e, nr_allocations, &b);
+
if (r)
return r;
}
@@ -790,13 +793,12 @@ static int __sm_ll_dec_overflow(struct ll_disk *ll, dm_block_t b,
rc = le32_to_cpu(*v_ptr);
*old_rc = rc;
- if (rc == 3) {
+ if (rc == 3)
return __sm_ll_del_overflow(ll, b, ic);
- } else {
- rc--;
- *v_ptr = cpu_to_le32(rc);
- return 0;
- }
+
+ rc--;
+ *v_ptr = cpu_to_le32(rc);
+ return 0;
}
static int sm_ll_dec_overflow(struct ll_disk *ll, dm_block_t b,
@@ -929,6 +931,7 @@ int sm_ll_dec(struct ll_disk *ll, dm_block_t b, dm_block_t e,
*nr_allocations = 0;
while (b != e) {
int r = __sm_ll_dec(ll, b, e, nr_allocations, &b);
+
if (r)
return r;
}
@@ -1097,7 +1100,7 @@ static inline int ie_cache_writeback(struct ll_disk *ll, struct ie_cache *iec)
&iec->index, &iec->ie, &ll->bitmap_root);
}
-static inline unsigned hash_index(dm_block_t index)
+static inline unsigned int hash_index(dm_block_t index)
{
return dm_hash_block(index, IE_CACHE_MASK);
}
@@ -1106,7 +1109,7 @@ static int disk_ll_load_ie(struct ll_disk *ll, dm_block_t index,
struct disk_index_entry *ie)
{
int r;
- unsigned h = hash_index(index);
+ unsigned int h = hash_index(index);
struct ie_cache *iec = ll->ie_cache + h;
if (iec->valid) {
@@ -1137,7 +1140,7 @@ static int disk_ll_save_ie(struct ll_disk *ll, dm_block_t index,
struct disk_index_entry *ie)
{
int r;
- unsigned h = hash_index(index);
+ unsigned int h = hash_index(index);
struct ie_cache *iec = ll->ie_cache + h;
ll->bitmap_index_changed = true;
@@ -1164,9 +1167,11 @@ static int disk_ll_save_ie(struct ll_disk *ll, dm_block_t index,
static int disk_ll_init_index(struct ll_disk *ll)
{
- unsigned i;
+ unsigned int i;
+
for (i = 0; i < IE_CACHE_SIZE; i++) {
struct ie_cache *iec = ll->ie_cache + i;
+
iec->valid = false;
iec->dirty = false;
}
@@ -1186,10 +1191,11 @@ static dm_block_t disk_ll_max_entries(struct ll_disk *ll)
static int disk_ll_commit(struct ll_disk *ll)
{
int r = 0;
- unsigned i;
+ unsigned int i;
for (i = 0; i < IE_CACHE_SIZE; i++) {
struct ie_cache *iec = ll->ie_cache + i;
+
if (iec->valid && iec->dirty)
r = ie_cache_writeback(ll, iec);
}
diff --git a/drivers/md/persistent-data/dm-space-map-common.h b/drivers/md/persistent-data/dm-space-map-common.h
index 706ceb85d680..e83d1f225078 100644
--- a/drivers/md/persistent-data/dm-space-map-common.h
+++ b/drivers/md/persistent-data/dm-space-map-common.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2011 Red Hat, Inc.
*
@@ -33,7 +34,7 @@ struct disk_index_entry {
__le64 blocknr;
__le32 nr_free;
__le32 none_free_before;
-} __attribute__ ((packed, aligned(8)));
+} __packed __aligned(8);
#define MAX_METADATA_BITMAPS 255
@@ -43,7 +44,7 @@ struct disk_metadata_index {
__le64 blocknr;
struct disk_index_entry index[MAX_METADATA_BITMAPS];
-} __attribute__ ((packed, aligned(8)));
+} __packed __aligned(8);
struct ll_disk;
@@ -102,7 +103,7 @@ struct disk_sm_root {
__le64 nr_allocated;
__le64 bitmap_root;
__le64 ref_count_root;
-} __attribute__ ((packed, aligned(8)));
+} __packed __aligned(8);
#define ENTRIES_PER_BYTE 4
@@ -110,7 +111,7 @@ struct disk_bitmap_header {
__le32 csum;
__le32 not_used;
__le64 blocknr;
-} __attribute__ ((packed, aligned(8)));
+} __packed __aligned(8);
/*----------------------------------------------------------------*/
@@ -120,7 +121,7 @@ int sm_ll_lookup(struct ll_disk *ll, dm_block_t b, uint32_t *result);
int sm_ll_find_free_block(struct ll_disk *ll, dm_block_t begin,
dm_block_t end, dm_block_t *result);
int sm_ll_find_common_free_block(struct ll_disk *old_ll, struct ll_disk *new_ll,
- dm_block_t begin, dm_block_t end, dm_block_t *result);
+ dm_block_t begin, dm_block_t end, dm_block_t *result);
/*
* The next three functions return (via nr_allocations) the net number of
diff --git a/drivers/md/persistent-data/dm-space-map-disk.c b/drivers/md/persistent-data/dm-space-map-disk.c
index d0a8d5e73c28..f4241f54e20e 100644
--- a/drivers/md/persistent-data/dm-space-map-disk.c
+++ b/drivers/md/persistent-data/dm-space-map-disk.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2011 Red Hat, Inc.
*
@@ -48,6 +49,7 @@ static int sm_disk_extend(struct dm_space_map *sm, dm_block_t extra_blocks)
static int sm_disk_get_nr_blocks(struct dm_space_map *sm, dm_block_t *count)
{
struct sm_disk *smd = container_of(sm, struct sm_disk, sm);
+
*count = smd->old_ll.nr_blocks;
return 0;
@@ -56,6 +58,7 @@ static int sm_disk_get_nr_blocks(struct dm_space_map *sm, dm_block_t *count)
static int sm_disk_get_nr_free(struct dm_space_map *sm, dm_block_t *count)
{
struct sm_disk *smd = container_of(sm, struct sm_disk, sm);
+
*count = (smd->old_ll.nr_blocks - smd->old_ll.nr_allocated) - smd->nr_allocated_this_transaction;
return 0;
@@ -65,6 +68,7 @@ static int sm_disk_get_count(struct dm_space_map *sm, dm_block_t b,
uint32_t *result)
{
struct sm_disk *smd = container_of(sm, struct sm_disk, sm);
+
return sm_ll_lookup(&smd->ll, b, result);
}
@@ -91,9 +95,8 @@ static int sm_disk_set_count(struct dm_space_map *sm, dm_block_t b,
struct sm_disk *smd = container_of(sm, struct sm_disk, sm);
r = sm_ll_insert(&smd->ll, b, count, &nr_allocations);
- if (!r) {
+ if (!r)
smd->nr_allocated_this_transaction += nr_allocations;
- }
return r;
}
@@ -134,22 +137,20 @@ static int sm_disk_new_block(struct dm_space_map *sm, dm_block_t *b)
* Any block we allocate has to be free in both the old and current ll.
*/
r = sm_ll_find_common_free_block(&smd->old_ll, &smd->ll, smd->begin, smd->ll.nr_blocks, b);
- if (r == -ENOSPC) {
+ if (r == -ENOSPC)
/*
* There's no free block between smd->begin and the end of the metadata device.
* We search before smd->begin in case something has been freed.
*/
r = sm_ll_find_common_free_block(&smd->old_ll, &smd->ll, 0, smd->begin, b);
- }
if (r)
return r;
smd->begin = *b + 1;
r = sm_ll_inc(&smd->ll, *b, *b + 1, &nr_allocations);
- if (!r) {
+ if (!r)
smd->nr_allocated_this_transaction += nr_allocations;
- }
return r;
}
diff --git a/drivers/md/persistent-data/dm-space-map-disk.h b/drivers/md/persistent-data/dm-space-map-disk.h
index 447a0a9a2d9f..6f8665db94db 100644
--- a/drivers/md/persistent-data/dm-space-map-disk.h
+++ b/drivers/md/persistent-data/dm-space-map-disk.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2011 Red Hat, Inc.
*
diff --git a/drivers/md/persistent-data/dm-space-map-metadata.c b/drivers/md/persistent-data/dm-space-map-metadata.c
index 392ae26134a4..04698fd03e60 100644
--- a/drivers/md/persistent-data/dm-space-map-metadata.c
+++ b/drivers/md/persistent-data/dm-space-map-metadata.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2011 Red Hat, Inc.
*
@@ -94,8 +95,8 @@ struct block_op {
};
struct bop_ring_buffer {
- unsigned begin;
- unsigned end;
+ unsigned int begin;
+ unsigned int end;
struct block_op bops[MAX_RECURSIVE_ALLOCATIONS + 1];
};
@@ -110,9 +111,10 @@ static bool brb_empty(struct bop_ring_buffer *brb)
return brb->begin == brb->end;
}
-static unsigned brb_next(struct bop_ring_buffer *brb, unsigned old)
+static unsigned int brb_next(struct bop_ring_buffer *brb, unsigned int old)
{
- unsigned r = old + 1;
+ unsigned int r = old + 1;
+
return r >= ARRAY_SIZE(brb->bops) ? 0 : r;
}
@@ -120,7 +122,7 @@ static int brb_push(struct bop_ring_buffer *brb,
enum block_op_type type, dm_block_t b, dm_block_t e)
{
struct block_op *bop;
- unsigned next = brb_next(brb, brb->end);
+ unsigned int next = brb_next(brb, brb->end);
/*
* We don't allow the last bop to be filled, this way we can
@@ -171,8 +173,8 @@ struct sm_metadata {
dm_block_t begin;
- unsigned recursion_count;
- unsigned allocated_this_transaction;
+ unsigned int recursion_count;
+ unsigned int allocated_this_transaction;
struct bop_ring_buffer uncommitted;
struct threshold threshold;
@@ -181,6 +183,7 @@ struct sm_metadata {
static int add_bop(struct sm_metadata *smm, enum block_op_type type, dm_block_t b, dm_block_t e)
{
int r = brb_push(&smm->uncommitted, type, b, e);
+
if (r) {
DMERR("too many recursive allocations");
return -ENOMEM;
@@ -300,9 +303,9 @@ static int sm_metadata_get_count(struct dm_space_map *sm, dm_block_t b,
uint32_t *result)
{
int r;
- unsigned i;
+ unsigned int i;
struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
- unsigned adjustment = 0;
+ unsigned int adjustment = 0;
/*
* We may have some uncommitted adjustments to add. This list
@@ -340,7 +343,7 @@ static int sm_metadata_count_is_more_than_one(struct dm_space_map *sm,
dm_block_t b, int *result)
{
int r, adjustment = 0;
- unsigned i;
+ unsigned int i;
struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
uint32_t rc;
@@ -486,6 +489,7 @@ static int sm_metadata_new_block(struct dm_space_map *sm, dm_block_t *b)
struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
int r = sm_metadata_new_block_(sm, b);
+
if (r) {
DMERR_LIMIT("unable to allocate new metadata block");
return r;
diff --git a/drivers/md/persistent-data/dm-space-map-metadata.h b/drivers/md/persistent-data/dm-space-map-metadata.h
index 64df923974d8..ca5c3e532627 100644
--- a/drivers/md/persistent-data/dm-space-map-metadata.h
+++ b/drivers/md/persistent-data/dm-space-map-metadata.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2011 Red Hat, Inc.
*
diff --git a/drivers/md/persistent-data/dm-space-map.h b/drivers/md/persistent-data/dm-space-map.h
index a015cd11f6e9..dab490353781 100644
--- a/drivers/md/persistent-data/dm-space-map.h
+++ b/drivers/md/persistent-data/dm-space-map.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2011 Red Hat, Inc.
*
diff --git a/drivers/md/persistent-data/dm-transaction-manager.c b/drivers/md/persistent-data/dm-transaction-manager.c
index 16643fc974e8..6dc016248baf 100644
--- a/drivers/md/persistent-data/dm-transaction-manager.c
+++ b/drivers/md/persistent-data/dm-transaction-manager.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2011 Red Hat, Inc.
*
@@ -28,14 +29,15 @@ struct prefetch_set {
dm_block_t blocks[PREFETCH_SIZE];
};
-static unsigned prefetch_hash(dm_block_t b)
+static unsigned int prefetch_hash(dm_block_t b)
{
return hash_64(b, PREFETCH_BITS);
}
static void prefetch_wipe(struct prefetch_set *p)
{
- unsigned i;
+ unsigned int i;
+
for (i = 0; i < PREFETCH_SIZE; i++)
p->blocks[i] = PREFETCH_SENTINEL;
}
@@ -48,7 +50,7 @@ static void prefetch_init(struct prefetch_set *p)
static void prefetch_add(struct prefetch_set *p, dm_block_t b)
{
- unsigned h = prefetch_hash(b);
+ unsigned int h = prefetch_hash(b);
mutex_lock(&p->lock);
if (p->blocks[h] == PREFETCH_SENTINEL)
@@ -59,7 +61,7 @@ static void prefetch_add(struct prefetch_set *p, dm_block_t b)
static void prefetch_issue(struct prefetch_set *p, struct dm_block_manager *bm)
{
- unsigned i;
+ unsigned int i;
mutex_lock(&p->lock);
@@ -103,7 +105,7 @@ struct dm_transaction_manager {
static int is_shadow(struct dm_transaction_manager *tm, dm_block_t b)
{
int r = 0;
- unsigned bucket = dm_hash_block(b, DM_HASH_MASK);
+ unsigned int bucket = dm_hash_block(b, DM_HASH_MASK);
struct shadow_info *si;
spin_lock(&tm->lock);
@@ -123,7 +125,7 @@ static int is_shadow(struct dm_transaction_manager *tm, dm_block_t b)
*/
static void insert_shadow(struct dm_transaction_manager *tm, dm_block_t b)
{
- unsigned bucket;
+ unsigned int bucket;
struct shadow_info *si;
si = kmalloc(sizeof(*si), GFP_NOIO);
@@ -393,11 +395,11 @@ void dm_tm_dec_range(struct dm_transaction_manager *tm, dm_block_t b, dm_block_t
EXPORT_SYMBOL_GPL(dm_tm_dec_range);
void dm_tm_with_runs(struct dm_transaction_manager *tm,
- const __le64 *value_le, unsigned count, dm_tm_run_fn fn)
+ const __le64 *value_le, unsigned int count, dm_tm_run_fn fn)
{
uint64_t b, begin, end;
bool in_run = false;
- unsigned i;
+ unsigned int i;
for (i = 0; i < count; i++, value_le++) {
b = le64_to_cpu(*value_le);
diff --git a/drivers/md/persistent-data/dm-transaction-manager.h b/drivers/md/persistent-data/dm-transaction-manager.h
index 906c02ed0365..01f7e650118d 100644
--- a/drivers/md/persistent-data/dm-transaction-manager.h
+++ b/drivers/md/persistent-data/dm-transaction-manager.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2011 Red Hat, Inc.
*
@@ -111,7 +112,7 @@ void dm_tm_dec_range(struct dm_transaction_manager *tm, dm_block_t b, dm_block_t
*/
typedef void (*dm_tm_run_fn)(struct dm_transaction_manager *, dm_block_t, dm_block_t);
void dm_tm_with_runs(struct dm_transaction_manager *tm,
- const __le64 *value_le, unsigned count, dm_tm_run_fn fn);
+ const __le64 *value_le, unsigned int count, dm_tm_run_fn fn);
int dm_tm_ref(struct dm_transaction_manager *tm, dm_block_t b, uint32_t *result);
diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig
index 852b7d92fbdd..adcb6655385a 100644
--- a/drivers/media/common/Kconfig
+++ b/drivers/media/common/Kconfig
@@ -14,6 +14,9 @@ config TTPCI_EEPROM
tristate
depends on I2C
+config UVC_COMMON
+ tristate
+
config VIDEO_CX2341X
tristate
@@ -22,6 +25,7 @@ config VIDEO_TVEEPROM
depends on I2C
source "drivers/media/common/b2c2/Kconfig"
+source "drivers/media/common/saa7146/Kconfig"
source "drivers/media/common/siano/Kconfig"
source "drivers/media/common/v4l2-tpg/Kconfig"
source "drivers/media/common/videobuf2/Kconfig"
diff --git a/drivers/media/common/Makefile b/drivers/media/common/Makefile
index d78a0df15478..c5ab905e7c20 100644
--- a/drivers/media/common/Makefile
+++ b/drivers/media/common/Makefile
@@ -1,9 +1,10 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-y += b2c2/ siano/ v4l2-tpg/ videobuf2/
+obj-y += b2c2/ saa7146/ siano/ v4l2-tpg/ videobuf2/
# Please keep it alphabetically sorted by Kconfig name
# (e. g. LC_ALL=C sort Makefile)
obj-$(CONFIG_CYPRESS_FIRMWARE) += cypress_firmware.o
obj-$(CONFIG_TTPCI_EEPROM) += ttpci-eeprom.o
+obj-$(CONFIG_UVC_COMMON) += uvc.o
obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
diff --git a/drivers/staging/media/deprecated/saa7146/common/Kconfig b/drivers/media/common/saa7146/Kconfig
index a0aa155e5d85..a0aa155e5d85 100644
--- a/drivers/staging/media/deprecated/saa7146/common/Kconfig
+++ b/drivers/media/common/saa7146/Kconfig
diff --git a/drivers/staging/media/deprecated/saa7146/common/Makefile b/drivers/media/common/saa7146/Makefile
index 2a6337feaec8..2a6337feaec8 100644
--- a/drivers/staging/media/deprecated/saa7146/common/Makefile
+++ b/drivers/media/common/saa7146/Makefile
diff --git a/drivers/staging/media/deprecated/saa7146/common/saa7146_core.c b/drivers/media/common/saa7146/saa7146_core.c
index da21d346b870..e50fa0ff7c5d 100644
--- a/drivers/staging/media/deprecated/saa7146/common/saa7146_core.c
+++ b/drivers/media/common/saa7146/saa7146_core.c
@@ -8,8 +8,8 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <media/drv-intf/saa7146.h>
#include <linux/module.h>
-#include "saa7146.h"
static int saa7146_num;
diff --git a/drivers/staging/media/deprecated/saa7146/common/saa7146_fops.c b/drivers/media/common/saa7146/saa7146_fops.c
index aa14698a9c54..e9a15de6126e 100644
--- a/drivers/staging/media/deprecated/saa7146/common/saa7146_fops.c
+++ b/drivers/media/common/saa7146/saa7146_fops.c
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-only
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <media/drv-intf/saa7146_vv.h>
#include <linux/module.h>
-#include "saa7146_vv.h"
/****************************************************************************/
/* resource management functions, shamelessly stolen from saa7134 driver */
diff --git a/drivers/staging/media/deprecated/saa7146/common/saa7146_hlp.c b/drivers/media/common/saa7146/saa7146_hlp.c
index b1222a4cfa4a..6c9946a402ee 100644
--- a/drivers/staging/media/deprecated/saa7146/common/saa7146_hlp.c
+++ b/drivers/media/common/saa7146/saa7146_hlp.c
@@ -3,7 +3,7 @@
#include <linux/kernel.h>
#include <linux/export.h>
-#include "saa7146_vv.h"
+#include <media/drv-intf/saa7146_vv.h>
static void calculate_output_format_register(struct saa7146_dev* saa, u32 palette, u32* clip_format)
{
diff --git a/drivers/staging/media/deprecated/saa7146/common/saa7146_i2c.c b/drivers/media/common/saa7146/saa7146_i2c.c
index 7a33fe51775a..df9ebe2a168c 100644
--- a/drivers/staging/media/deprecated/saa7146/common/saa7146_i2c.c
+++ b/drivers/media/common/saa7146/saa7146_i2c.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#include "saa7146_vv.h"
+#include <media/drv-intf/saa7146_vv.h>
static u32 saa7146_i2c_func(struct i2c_adapter *adapter)
{
diff --git a/drivers/staging/media/deprecated/saa7146/common/saa7146_vbi.c b/drivers/media/common/saa7146/saa7146_vbi.c
index 2d4a05d7bc5b..bd442b984423 100644
--- a/drivers/staging/media/deprecated/saa7146/common/saa7146_vbi.c
+++ b/drivers/media/common/saa7146/saa7146_vbi.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
-#include "saa7146_vv.h"
+#include <media/drv-intf/saa7146_vv.h>
static int vbi_pixel_to_capture = 720 * 2;
diff --git a/drivers/staging/media/deprecated/saa7146/common/saa7146_video.c b/drivers/media/common/saa7146/saa7146_video.c
index 4598a44231fa..2296765079a4 100644
--- a/drivers/staging/media/deprecated/saa7146/common/saa7146_video.c
+++ b/drivers/media/common/saa7146/saa7146_video.c
@@ -1,10 +1,10 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <media/drv-intf/saa7146_vv.h>
#include <media/v4l2-event.h>
#include <media/v4l2-ctrls.h>
#include <linux/module.h>
#include <linux/kernel.h>
-#include "saa7146_vv.h"
static int max_memory = 32;
diff --git a/drivers/media/common/uvc.c b/drivers/media/common/uvc.c
new file mode 100644
index 000000000000..9c0ba7a6c185
--- /dev/null
+++ b/drivers/media/common/uvc.c
@@ -0,0 +1,183 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/usb/uvc.h>
+#include <linux/videodev2.h>
+
+/* ------------------------------------------------------------------------
+ * Video formats
+ */
+
+static const struct uvc_format_desc uvc_fmts[] = {
+ {
+ .guid = UVC_GUID_FORMAT_YUY2,
+ .fcc = V4L2_PIX_FMT_YUYV,
+ },
+ {
+ .guid = UVC_GUID_FORMAT_YUY2_ISIGHT,
+ .fcc = V4L2_PIX_FMT_YUYV,
+ },
+ {
+ .guid = UVC_GUID_FORMAT_NV12,
+ .fcc = V4L2_PIX_FMT_NV12,
+ },
+ {
+ .guid = UVC_GUID_FORMAT_MJPEG,
+ .fcc = V4L2_PIX_FMT_MJPEG,
+ },
+ {
+ .guid = UVC_GUID_FORMAT_YV12,
+ .fcc = V4L2_PIX_FMT_YVU420,
+ },
+ {
+ .guid = UVC_GUID_FORMAT_I420,
+ .fcc = V4L2_PIX_FMT_YUV420,
+ },
+ {
+ .guid = UVC_GUID_FORMAT_M420,
+ .fcc = V4L2_PIX_FMT_M420,
+ },
+ {
+ .guid = UVC_GUID_FORMAT_UYVY,
+ .fcc = V4L2_PIX_FMT_UYVY,
+ },
+ {
+ .guid = UVC_GUID_FORMAT_Y800,
+ .fcc = V4L2_PIX_FMT_GREY,
+ },
+ {
+ .guid = UVC_GUID_FORMAT_Y8,
+ .fcc = V4L2_PIX_FMT_GREY,
+ },
+ {
+ .guid = UVC_GUID_FORMAT_D3DFMT_L8,
+ .fcc = V4L2_PIX_FMT_GREY,
+ },
+ {
+ .guid = UVC_GUID_FORMAT_KSMEDIA_L8_IR,
+ .fcc = V4L2_PIX_FMT_GREY,
+ },
+ {
+ .guid = UVC_GUID_FORMAT_Y10,
+ .fcc = V4L2_PIX_FMT_Y10,
+ },
+ {
+ .guid = UVC_GUID_FORMAT_Y12,
+ .fcc = V4L2_PIX_FMT_Y12,
+ },
+ {
+ .guid = UVC_GUID_FORMAT_Y16,
+ .fcc = V4L2_PIX_FMT_Y16,
+ },
+ {
+ .guid = UVC_GUID_FORMAT_BY8,
+ .fcc = V4L2_PIX_FMT_SBGGR8,
+ },
+ {
+ .guid = UVC_GUID_FORMAT_BA81,
+ .fcc = V4L2_PIX_FMT_SBGGR8,
+ },
+ {
+ .guid = UVC_GUID_FORMAT_GBRG,
+ .fcc = V4L2_PIX_FMT_SGBRG8,
+ },
+ {
+ .guid = UVC_GUID_FORMAT_GRBG,
+ .fcc = V4L2_PIX_FMT_SGRBG8,
+ },
+ {
+ .guid = UVC_GUID_FORMAT_RGGB,
+ .fcc = V4L2_PIX_FMT_SRGGB8,
+ },
+ {
+ .guid = UVC_GUID_FORMAT_RGBP,
+ .fcc = V4L2_PIX_FMT_RGB565,
+ },
+ {
+ .guid = UVC_GUID_FORMAT_BGR3,
+ .fcc = V4L2_PIX_FMT_BGR24,
+ },
+ {
+ .guid = UVC_GUID_FORMAT_BGR4,
+ .fcc = V4L2_PIX_FMT_XBGR32,
+ },
+ {
+ .guid = UVC_GUID_FORMAT_H264,
+ .fcc = V4L2_PIX_FMT_H264,
+ },
+ {
+ .guid = UVC_GUID_FORMAT_H265,
+ .fcc = V4L2_PIX_FMT_HEVC,
+ },
+ {
+ .guid = UVC_GUID_FORMAT_Y8I,
+ .fcc = V4L2_PIX_FMT_Y8I,
+ },
+ {
+ .guid = UVC_GUID_FORMAT_Y12I,
+ .fcc = V4L2_PIX_FMT_Y12I,
+ },
+ {
+ .guid = UVC_GUID_FORMAT_Z16,
+ .fcc = V4L2_PIX_FMT_Z16,
+ },
+ {
+ .guid = UVC_GUID_FORMAT_RW10,
+ .fcc = V4L2_PIX_FMT_SRGGB10P,
+ },
+ {
+ .guid = UVC_GUID_FORMAT_BG16,
+ .fcc = V4L2_PIX_FMT_SBGGR16,
+ },
+ {
+ .guid = UVC_GUID_FORMAT_GB16,
+ .fcc = V4L2_PIX_FMT_SGBRG16,
+ },
+ {
+ .guid = UVC_GUID_FORMAT_RG16,
+ .fcc = V4L2_PIX_FMT_SRGGB16,
+ },
+ {
+ .guid = UVC_GUID_FORMAT_GR16,
+ .fcc = V4L2_PIX_FMT_SGRBG16,
+ },
+ {
+ .guid = UVC_GUID_FORMAT_INVZ,
+ .fcc = V4L2_PIX_FMT_Z16,
+ },
+ {
+ .guid = UVC_GUID_FORMAT_INVI,
+ .fcc = V4L2_PIX_FMT_Y10,
+ },
+ {
+ .guid = UVC_GUID_FORMAT_INZI,
+ .fcc = V4L2_PIX_FMT_INZI,
+ },
+ {
+ .guid = UVC_GUID_FORMAT_CNF4,
+ .fcc = V4L2_PIX_FMT_CNF4,
+ },
+ {
+ .guid = UVC_GUID_FORMAT_HEVC,
+ .fcc = V4L2_PIX_FMT_HEVC,
+ },
+};
+
+const struct uvc_format_desc *uvc_format_by_guid(const u8 guid[16])
+{
+ unsigned int len = ARRAY_SIZE(uvc_fmts);
+ unsigned int i;
+
+ for (i = 0; i < len; ++i) {
+ if (memcmp(guid, uvc_fmts[i].guid, 16) == 0)
+ return &uvc_fmts[i];
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(uvc_format_by_guid);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
index 53e495223ea0..cf6727d9c81f 100644
--- a/drivers/media/common/videobuf2/videobuf2-core.c
+++ b/drivers/media/common/videobuf2/videobuf2-core.c
@@ -502,27 +502,11 @@ static void __vb2_free_mem(struct vb2_queue *q, unsigned int buffers)
* related information, if no buffers are left return the queue to an
* uninitialized state. Might be called even if the queue has already been freed.
*/
-static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
+static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
{
unsigned int buffer;
- /*
- * Sanity check: when preparing a buffer the queue lock is released for
- * a short while (see __buf_prepare for the details), which would allow
- * a race with a reqbufs which can call this function. Removing the
- * buffers from underneath __buf_prepare is obviously a bad idea, so we
- * check if any of the buffers is in the state PREPARING, and if so we
- * just return -EAGAIN.
- */
- for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
- ++buffer) {
- if (q->bufs[buffer] == NULL)
- continue;
- if (q->bufs[buffer]->state == VB2_BUF_STATE_PREPARING) {
- dprintk(q, 1, "preparing buffers, cannot free\n");
- return -EAGAIN;
- }
- }
+ lockdep_assert_held(&q->mmap_lock);
/* Call driver-provided cleanup function for each buffer, if provided */
for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
@@ -616,7 +600,6 @@ static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
q->memory = VB2_MEMORY_UNKNOWN;
INIT_LIST_HEAD(&q->queued_list);
}
- return 0;
}
bool vb2_buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb)
@@ -798,10 +781,8 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
* queued without ever calling STREAMON.
*/
__vb2_queue_cancel(q);
- ret = __vb2_queue_free(q, q->num_buffers);
+ __vb2_queue_free(q, q->num_buffers);
mutex_unlock(&q->mmap_lock);
- if (ret)
- return ret;
/*
* In case of REQBUFS(0) return immediately without calling
diff --git a/drivers/media/common/videobuf2/videobuf2-dma-contig.c b/drivers/media/common/videobuf2/videobuf2-dma-contig.c
index 5f1175f8b349..205d3cac425c 100644
--- a/drivers/media/common/videobuf2/videobuf2-dma-contig.c
+++ b/drivers/media/common/videobuf2/videobuf2-dma-contig.c
@@ -293,7 +293,7 @@ static int vb2_dc_mmap(void *buf_priv, struct vm_area_struct *vma)
return ret;
}
- vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
+ vm_flags_set(vma, VM_DONTEXPAND | VM_DONTDUMP);
vma->vm_private_data = &buf->handler;
vma->vm_ops = &vb2_common_vm_ops;
diff --git a/drivers/media/common/videobuf2/videobuf2-vmalloc.c b/drivers/media/common/videobuf2/videobuf2-vmalloc.c
index 959b45beb1f3..a6c6d2fcaaa4 100644
--- a/drivers/media/common/videobuf2/videobuf2-vmalloc.c
+++ b/drivers/media/common/videobuf2/videobuf2-vmalloc.c
@@ -185,7 +185,7 @@ static int vb2_vmalloc_mmap(void *buf_priv, struct vm_area_struct *vma)
/*
* Make sure that vm_areas for 2 buffers won't be merged together
*/
- vma->vm_flags |= VM_DONTEXPAND;
+ vm_flags_set(vma, VM_DONTEXPAND);
/*
* Use common vm_area operations to track buffer refcount.
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c
index 4cf2d7cfd3f5..0a1f3899d72c 100644
--- a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c
@@ -2162,11 +2162,11 @@ int cxd2880_tnrdmd_check_internal_cpu_status(struct cxd2880_tnrdmd
else
*task_completed = 0;
- return ret;
+ return 0;
}
if (cpu_status != 0) {
*task_completed = 0;
- return ret;
+ return 0;
}
ret = cxd2880_tnrdmd_mon_internal_cpu_status_sub(tnr_dmd, &cpu_status);
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
index fe3c6f8b1b3e..c7e79da8c432 100644
--- a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
@@ -833,12 +833,12 @@ int cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd
else
*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
- return ret;
+ return 0;
}
if (sync_stat == 6) {
*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
- return ret;
+ return 0;
}
ret =
@@ -854,7 +854,7 @@ int cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd
else
*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
- return ret;
+ return 0;
}
int cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd
@@ -893,15 +893,15 @@ int cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd
else
*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
- return ret;
+ return 0;
}
if (ts_lock) {
*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
- return ret;
+ return 0;
} else if (!unlock_detected) {
*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
- return ret;
+ return 0;
}
ret =
@@ -915,5 +915,5 @@ int cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd
else
*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
- return ret;
+ return 0;
}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c
index dd32004a12d8..a9ab983348c8 100644
--- a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c
@@ -1024,12 +1024,12 @@ int cxd2880_tnrdmd_dvbt2_check_demod_lock(struct cxd2880_tnrdmd
else
*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
- return ret;
+ return 0;
}
if (sync_stat == 6) {
*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
- return ret;
+ return 0;
}
ret =
@@ -1045,7 +1045,7 @@ int cxd2880_tnrdmd_dvbt2_check_demod_lock(struct cxd2880_tnrdmd
else
*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
- return ret;
+ return 0;
}
int cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd
@@ -1084,15 +1084,15 @@ int cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd
else
*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
- return ret;
+ return 0;
}
if (ts_lock) {
*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
- return ret;
+ return 0;
} else if (!unlock_detected) {
*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
- return ret;
+ return 0;
}
ret =
@@ -1106,7 +1106,7 @@ int cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd
else
*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
- return ret;
+ return 0;
}
int cxd2880_tnrdmd_dvbt2_set_plp_cfg(struct cxd2880_tnrdmd
diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c
index 1dff59ca21a1..6bf6559b127f 100644
--- a/drivers/media/dvb-frontends/drx39xyj/drxj.c
+++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c
@@ -9539,7 +9539,8 @@ ctrl_get_qam_sig_quality(struct drx_demod_instance *demod)
qam_sl_sig_power = DRXJ_QAM_SL_SIG_POWER_QAM256 << 2;
break;
default:
- return -EIO;
+ rc = -EIO;
+ goto rw_error;
}
/* ------------------------------ */
@@ -10916,7 +10917,8 @@ ctrl_set_standard(struct drx_demod_instance *demod, enum drx_standard *standard)
break;
case DRX_STANDARD_AUTO:
default:
- return -EINVAL;
+ rc = -EINVAL;
+ goto rw_error;
}
/*
@@ -11463,7 +11465,8 @@ static int drxj_open(struct drx_demod_instance *demod)
if (DRX_ISPOWERDOWNMODE(demod->my_common_attr->current_power_mode)) {
pr_err("Should powerup before loading the firmware.");
- return -EINVAL;
+ rc = -EINVAL;
+ goto rw_error;
}
rc = drx_ctrl_u_code(demod, &ucode_info, UCODE_UPLOAD);
diff --git a/drivers/media/dvb-frontends/dvb-pll.c b/drivers/media/dvb-frontends/dvb-pll.c
index baf2a378e565..e35e00db7dbb 100644
--- a/drivers/media/dvb-frontends/dvb-pll.c
+++ b/drivers/media/dvb-frontends/dvb-pll.c
@@ -870,8 +870,9 @@ EXPORT_SYMBOL(dvb_pll_attach);
static int
-dvb_pll_probe(struct i2c_client *client, const struct i2c_device_id *id)
+dvb_pll_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct dvb_pll_config *cfg;
struct dvb_frontend *fe;
unsigned int desc_id;
@@ -941,7 +942,7 @@ static struct i2c_driver dvb_pll_driver = {
.driver = {
.name = "dvb_pll",
},
- .probe = dvb_pll_probe,
+ .probe_new = dvb_pll_probe,
.remove = dvb_pll_remove,
.id_table = dvb_pll_id,
};
diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c
index 4e844b2ef597..f26508b217ee 100644
--- a/drivers/media/dvb-frontends/m88ds3103.c
+++ b/drivers/media/dvb-frontends/m88ds3103.c
@@ -1760,9 +1760,9 @@ static struct i2c_adapter *m88ds3103_get_i2c_adapter(struct i2c_client *client)
return dev->muxc->adapter[0];
}
-static int m88ds3103_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int m88ds3103_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct m88ds3103_dev *dev;
struct m88ds3103_platform_data *pdata = client->dev.platform_data;
int ret;
@@ -1941,7 +1941,7 @@ static struct i2c_driver m88ds3103_driver = {
.name = "m88ds3103",
.suppress_bind_attrs = true,
},
- .probe = m88ds3103_probe,
+ .probe_new = m88ds3103_probe,
.remove = m88ds3103_remove,
.id_table = m88ds3103_id_table,
};
diff --git a/drivers/media/dvb-frontends/mb86a16.c b/drivers/media/dvb-frontends/mb86a16.c
index 2505f1e5794e..d3e29937cf4c 100644
--- a/drivers/media/dvb-frontends/mb86a16.c
+++ b/drivers/media/dvb-frontends/mb86a16.c
@@ -1498,6 +1498,7 @@ static int mb86a16_send_diseqc_msg(struct dvb_frontend *fe,
struct dvb_diseqc_master_cmd *cmd)
{
struct mb86a16_state *state = fe->demodulator_priv;
+ int ret = -EREMOTEIO;
int i;
u8 regs;
@@ -1510,8 +1511,10 @@ static int mb86a16_send_diseqc_msg(struct dvb_frontend *fe,
regs = 0x18;
- if (cmd->msg_len > 5 || cmd->msg_len < 4)
- return -EINVAL;
+ if (cmd->msg_len > 5 || cmd->msg_len < 4) {
+ ret = -EINVAL;
+ goto err;
+ }
for (i = 0; i < cmd->msg_len; i++) {
if (mb86a16_write(state, regs, cmd->msg[i]) < 0)
@@ -1532,7 +1535,7 @@ static int mb86a16_send_diseqc_msg(struct dvb_frontend *fe,
err:
dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
- return -EREMOTEIO;
+ return ret;
}
static int mb86a16_send_diseqc_burst(struct dvb_frontend *fe,
diff --git a/drivers/media/dvb-frontends/mn88443x.c b/drivers/media/dvb-frontends/mn88443x.c
index 452571b380b7..1f1753f2ab1a 100644
--- a/drivers/media/dvb-frontends/mn88443x.c
+++ b/drivers/media/dvb-frontends/mn88443x.c
@@ -673,9 +673,9 @@ static const struct regmap_config regmap_config = {
.cache_type = REGCACHE_NONE,
};
-static int mn88443x_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int mn88443x_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct mn88443x_config *conf = client->dev.platform_data;
struct mn88443x_priv *chip;
struct device *dev = &client->dev;
@@ -800,7 +800,7 @@ static struct i2c_driver mn88443x_driver = {
.name = "mn88443x",
.of_match_table = of_match_ptr(mn88443x_of_match),
},
- .probe = mn88443x_probe,
+ .probe_new = mn88443x_probe,
.remove = mn88443x_remove,
.id_table = mn88443x_i2c_id,
};
diff --git a/drivers/media/dvb-frontends/tc90522.c b/drivers/media/dvb-frontends/tc90522.c
index c22d2a2b2a45..77a991bf4713 100644
--- a/drivers/media/dvb-frontends/tc90522.c
+++ b/drivers/media/dvb-frontends/tc90522.c
@@ -779,9 +779,9 @@ static const struct dvb_frontend_ops tc90522_ops_ter = {
};
-static int tc90522_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int tc90522_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct tc90522_state *state;
struct tc90522_config *cfg;
const struct dvb_frontend_ops *ops;
@@ -840,7 +840,7 @@ static struct i2c_driver tc90522_driver = {
.driver = {
.name = "tc90522",
},
- .probe = tc90522_probe,
+ .probe_new = tc90522_probe,
.remove = tc90522_remove,
.id_table = tc90522_id,
};
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index 833241897d63..c3d5952ca27e 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -162,6 +162,19 @@ config VIDEO_IMX290
To compile this driver as a module, choose M here: the
module will be called imx290.
+config VIDEO_IMX296
+ tristate "Sony IMX296 sensor support"
+ depends on I2C && VIDEO_DEV
+ select MEDIA_CONTROLLER
+ select V4L2_FWNODE
+ select VIDEO_V4L2_SUBDEV_API
+ help
+ This is a Video4Linux2 sensor driver for the Sony
+ IMX296 camera.
+
+ To compile this driver as a module, choose M here: the
+ module will be called imx296.
+
config VIDEO_IMX319
tristate "Sony IMX319 sensor support"
depends on I2C && VIDEO_DEV
@@ -228,6 +241,20 @@ config VIDEO_IMX412
To compile this driver as a module, choose M here: the
module will be called imx412.
+config VIDEO_IMX415
+ tristate "Sony IMX415 sensor support"
+ depends on OF_GPIO
+ depends on I2C && VIDEO_DEV
+ select VIDEO_V4L2_SUBDEV_API
+ select MEDIA_CONTROLLER
+ select V4L2_FWNODE
+ help
+ This is a Video4Linux2 sensor driver for the Sony
+ IMX415 camera.
+
+ To compile this driver as a module, choose M here: the
+ module will be called imx415.
+
config VIDEO_MAX9271_LIB
tristate
@@ -645,6 +672,19 @@ config VIDEO_OV8856
To compile this driver as a module, choose M here: the
module will be called ov8856.
+config VIDEO_OV8858
+ tristate "OmniVision OV8858 sensor support"
+ depends on I2C && PM && VIDEO_DEV
+ select MEDIA_CONTROLLER
+ select VIDEO_V4L2_SUBDEV_API
+ select V4L2_FWNODE
+ help
+ This is a Video4Linux2 sensor driver for OmniVision
+ OV8858 camera sensor.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ov8858.
+
config VIDEO_OV8865
tristate "OmniVision OV8865 sensor support"
depends on I2C && PM && VIDEO_DEV
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index 4d6c052bb5a7..4f5e9d9cee85 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -43,11 +43,13 @@ obj-$(CONFIG_VIDEO_IMX219) += imx219.o
obj-$(CONFIG_VIDEO_IMX258) += imx258.o
obj-$(CONFIG_VIDEO_IMX274) += imx274.o
obj-$(CONFIG_VIDEO_IMX290) += imx290.o
+obj-$(CONFIG_VIDEO_IMX296) += imx296.o
obj-$(CONFIG_VIDEO_IMX319) += imx319.o
obj-$(CONFIG_VIDEO_IMX334) += imx334.o
obj-$(CONFIG_VIDEO_IMX335) += imx335.o
obj-$(CONFIG_VIDEO_IMX355) += imx355.o
obj-$(CONFIG_VIDEO_IMX412) += imx412.o
+obj-$(CONFIG_VIDEO_IMX415) += imx415.o
obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
obj-$(CONFIG_VIDEO_ISL7998X) += isl7998x.o
obj-$(CONFIG_VIDEO_KS0127) += ks0127.o
@@ -96,6 +98,7 @@ obj-$(CONFIG_VIDEO_OV7670) += ov7670.o
obj-$(CONFIG_VIDEO_OV772X) += ov772x.o
obj-$(CONFIG_VIDEO_OV7740) += ov7740.o
obj-$(CONFIG_VIDEO_OV8856) += ov8856.o
+obj-$(CONFIG_VIDEO_OV8858) += ov8858.o
obj-$(CONFIG_VIDEO_OV8865) += ov8865.o
obj-$(CONFIG_VIDEO_OV9282) += ov9282.o
obj-$(CONFIG_VIDEO_OV9640) += ov9640.o
diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index 216fe396973f..a22402b7acff 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -1393,9 +1393,9 @@ out_unlock:
return ret;
}
-static int adv7180_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int adv7180_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct device_node *np = client->dev.of_node;
struct adv7180_state *state;
struct v4l2_subdev *sd;
@@ -1610,7 +1610,7 @@ static struct i2c_driver adv7180_driver = {
.pm = ADV7180_PM_OPS,
.of_match_table = of_match_ptr(adv7180_of_id),
},
- .probe = adv7180_probe,
+ .probe_new = adv7180_probe,
.remove = adv7180_remove,
.id_table = adv7180_id,
};
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
index bda0c547ce44..9d218962d7c8 100644
--- a/drivers/media/i2c/adv7604.c
+++ b/drivers/media/i2c/adv7604.c
@@ -3401,9 +3401,9 @@ static void adv76xx_reset(struct adv76xx_state *state)
}
}
-static int adv76xx_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int adv76xx_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
static const struct v4l2_dv_timings cea640x480 =
V4L2_DV_BT_CEA_640X480P59_94;
struct adv76xx_state *state;
@@ -3686,7 +3686,7 @@ static struct i2c_driver adv76xx_driver = {
.name = "adv7604",
.of_match_table = of_match_ptr(adv76xx_of_id),
},
- .probe = adv76xx_probe,
+ .probe_new = adv76xx_probe,
.remove = adv76xx_remove,
.id_table = adv76xx_i2c_id,
};
diff --git a/drivers/media/i2c/ak7375.c b/drivers/media/i2c/ak7375.c
index 1af9f698eecf..e7cec45bc271 100644
--- a/drivers/media/i2c/ak7375.c
+++ b/drivers/media/i2c/ak7375.c
@@ -6,6 +6,7 @@
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
@@ -23,17 +24,29 @@
*/
#define AK7375_CTRL_STEPS 64
#define AK7375_CTRL_DELAY_US 1000
+/*
+ * The vcm may take up 10 ms (tDELAY) to power on and start taking
+ * I2C messages. Based on AK7371 datasheet.
+ */
+#define AK7375_POWER_DELAY_US 10000
#define AK7375_REG_POSITION 0x0
#define AK7375_REG_CONT 0x2
#define AK7375_MODE_ACTIVE 0x0
#define AK7375_MODE_STANDBY 0x40
+static const char * const ak7375_supply_names[] = {
+ "vdd",
+ "vio",
+};
+
/* ak7375 device structure */
struct ak7375_device {
struct v4l2_ctrl_handler ctrls_vcm;
struct v4l2_subdev sd;
struct v4l2_ctrl *focus;
+ struct regulator_bulk_data supplies[ARRAY_SIZE(ak7375_supply_names)];
+
/* active or standby mode */
bool active;
};
@@ -133,12 +146,24 @@ static int ak7375_probe(struct i2c_client *client)
{
struct ak7375_device *ak7375_dev;
int ret;
+ unsigned int i;
ak7375_dev = devm_kzalloc(&client->dev, sizeof(*ak7375_dev),
GFP_KERNEL);
if (!ak7375_dev)
return -ENOMEM;
+ for (i = 0; i < ARRAY_SIZE(ak7375_supply_names); i++)
+ ak7375_dev->supplies[i].supply = ak7375_supply_names[i];
+
+ ret = devm_regulator_bulk_get(&client->dev,
+ ARRAY_SIZE(ak7375_supply_names),
+ ak7375_dev->supplies);
+ if (ret) {
+ dev_err_probe(&client->dev, ret, "Failed to get regulators\n");
+ return ret;
+ }
+
v4l2_i2c_subdev_init(&ak7375_dev->sd, client, &ak7375_ops);
ak7375_dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
ak7375_dev->sd.internal_ops = &ak7375_int_ops;
@@ -208,6 +233,11 @@ static int __maybe_unused ak7375_vcm_suspend(struct device *dev)
if (ret)
dev_err(dev, "%s I2C failure: %d\n", __func__, ret);
+ ret = regulator_bulk_disable(ARRAY_SIZE(ak7375_supply_names),
+ ak7375_dev->supplies);
+ if (ret)
+ return ret;
+
ak7375_dev->active = false;
return 0;
@@ -228,6 +258,14 @@ static int __maybe_unused ak7375_vcm_resume(struct device *dev)
if (ak7375_dev->active)
return 0;
+ ret = regulator_bulk_enable(ARRAY_SIZE(ak7375_supply_names),
+ ak7375_dev->supplies);
+ if (ret)
+ return ret;
+
+ /* Wait for vcm to become ready */
+ usleep_range(AK7375_POWER_DELAY_US, AK7375_POWER_DELAY_US + 500);
+
ret = ak7375_i2c_write(ak7375_dev, AK7375_REG_CONT,
AK7375_MODE_ACTIVE, 1);
if (ret) {
diff --git a/drivers/media/i2c/cs53l32a.c b/drivers/media/i2c/cs53l32a.c
index 9461589aea30..670f89de32d4 100644
--- a/drivers/media/i2c/cs53l32a.c
+++ b/drivers/media/i2c/cs53l32a.c
@@ -128,9 +128,9 @@ static const struct v4l2_subdev_ops cs53l32a_ops = {
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
*/
-static int cs53l32a_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int cs53l32a_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct cs53l32a_state *state;
struct v4l2_subdev *sd;
int i;
@@ -209,7 +209,7 @@ static struct i2c_driver cs53l32a_driver = {
.driver = {
.name = "cs53l32a",
},
- .probe = cs53l32a_probe,
+ .probe_new = cs53l32a_probe,
.remove = cs53l32a_remove,
.id_table = cs53l32a_id,
};
diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c
index 77bd79a5954e..f9471c9e3a74 100644
--- a/drivers/media/i2c/imx219.c
+++ b/drivers/media/i2c/imx219.c
@@ -42,10 +42,16 @@
/* External clock frequency is 24.0M */
#define IMX219_XCLK_FREQ 24000000
-/* Pixel rate is fixed at 182.4M for all the modes */
+/* Pixel rate is fixed for all the modes */
#define IMX219_PIXEL_RATE 182400000
+#define IMX219_PIXEL_RATE_4LANE 280800000
#define IMX219_DEFAULT_LINK_FREQ 456000000
+#define IMX219_DEFAULT_LINK_FREQ_4LANE 363000000
+
+#define IMX219_REG_CSI_LANE_MODE 0x0114
+#define IMX219_CSI_2_LANE_MODE 0x01
+#define IMX219_CSI_4_LANE_MODE 0x03
/* V_TIMING internal */
#define IMX219_REG_VTS 0x0160
@@ -89,6 +95,12 @@
#define IMX219_REG_ORIENTATION 0x0172
+/* Binning Mode */
+#define IMX219_REG_BINNING_MODE 0x0174
+#define IMX219_BINNING_NONE 0x0000
+#define IMX219_BINNING_2X2 0x0101
+#define IMX219_BINNING_2X2_ANALOG 0x0303
+
/* Test Pattern Control */
#define IMX219_REG_TEST_PATTERN 0x0600
#define IMX219_TEST_PATTERN_DISABLE 0
@@ -143,25 +155,66 @@ struct imx219_mode {
/* Default register values */
struct imx219_reg_list reg_list;
+
+ /* 2x2 binning is used */
+ bool binning;
};
-/*
- * Register sets lifted off the i2C interface from the Raspberry Pi firmware
- * driver.
- * 3280x2464 = mode 2, 1920x1080 = mode 1, 1640x1232 = mode 4, 640x480 = mode 7.
- */
-static const struct imx219_reg mode_3280x2464_regs[] = {
- {0x0100, 0x00},
+static const struct imx219_reg imx219_common_regs[] = {
+ {0x0100, 0x00}, /* Mode Select */
+
+ /* To Access Addresses 3000-5fff, send the following commands */
{0x30eb, 0x0c},
{0x30eb, 0x05},
{0x300a, 0xff},
{0x300b, 0xff},
{0x30eb, 0x05},
{0x30eb, 0x09},
- {0x0114, 0x01},
- {0x0128, 0x00},
- {0x012a, 0x18},
+
+ /* PLL Clock Table */
+ {0x0301, 0x05}, /* VTPXCK_DIV */
+ {0x0303, 0x01}, /* VTSYSCK_DIV */
+ {0x0304, 0x03}, /* PREPLLCK_VT_DIV 0x03 = AUTO set */
+ {0x0305, 0x03}, /* PREPLLCK_OP_DIV 0x03 = AUTO set */
+ {0x0306, 0x00}, /* PLL_VT_MPY */
+ {0x0307, 0x39},
+ {0x030b, 0x01}, /* OP_SYS_CLK_DIV */
+ {0x030c, 0x00}, /* PLL_OP_MPY */
+ {0x030d, 0x72},
+
+ /* Undocumented registers */
+ {0x455e, 0x00},
+ {0x471e, 0x4b},
+ {0x4767, 0x0f},
+ {0x4750, 0x14},
+ {0x4540, 0x00},
+ {0x47b4, 0x14},
+ {0x4713, 0x30},
+ {0x478b, 0x10},
+ {0x478f, 0x10},
+ {0x4793, 0x10},
+ {0x4797, 0x0e},
+ {0x479b, 0x0e},
+
+ /* Frame Bank Register Group "A" */
+ {0x0162, 0x0d}, /* Line_Length_A */
+ {0x0163, 0x78},
+ {0x0170, 0x01}, /* X_ODD_INC_A */
+ {0x0171, 0x01}, /* Y_ODD_INC_A */
+
+ /* Output setup registers */
+ {0x0114, 0x01}, /* CSI 2-Lane Mode */
+ {0x0128, 0x00}, /* DPHY Auto Mode */
+ {0x012a, 0x18}, /* EXCK_Freq */
{0x012b, 0x00},
+};
+
+/*
+ * Register sets lifted off the i2C interface from the Raspberry Pi firmware
+ * driver.
+ * 3280x2464 = mode 2, 1920x1080 = mode 1, 1640x1232 = mode 4, 640x480 = mode 7.
+ */
+static const struct imx219_reg mode_3280x2464_regs[] = {
{0x0164, 0x00},
{0x0165, 0x00},
{0x0166, 0x0c},
@@ -174,53 +227,13 @@ static const struct imx219_reg mode_3280x2464_regs[] = {
{0x016d, 0xd0},
{0x016e, 0x09},
{0x016f, 0xa0},
- {0x0170, 0x01},
- {0x0171, 0x01},
- {0x0174, 0x00},
- {0x0175, 0x00},
- {0x0301, 0x05},
- {0x0303, 0x01},
- {0x0304, 0x03},
- {0x0305, 0x03},
- {0x0306, 0x00},
- {0x0307, 0x39},
- {0x030b, 0x01},
- {0x030c, 0x00},
- {0x030d, 0x72},
{0x0624, 0x0c},
{0x0625, 0xd0},
{0x0626, 0x09},
{0x0627, 0xa0},
- {0x455e, 0x00},
- {0x471e, 0x4b},
- {0x4767, 0x0f},
- {0x4750, 0x14},
- {0x4540, 0x00},
- {0x47b4, 0x14},
- {0x4713, 0x30},
- {0x478b, 0x10},
- {0x478f, 0x10},
- {0x4793, 0x10},
- {0x4797, 0x0e},
- {0x479b, 0x0e},
- {0x0162, 0x0d},
- {0x0163, 0x78},
};
static const struct imx219_reg mode_1920_1080_regs[] = {
- {0x0100, 0x00},
- {0x30eb, 0x05},
- {0x30eb, 0x0c},
- {0x300a, 0xff},
- {0x300b, 0xff},
- {0x30eb, 0x05},
- {0x30eb, 0x09},
- {0x0114, 0x01},
- {0x0128, 0x00},
- {0x012a, 0x18},
- {0x012b, 0x00},
- {0x0162, 0x0d},
- {0x0163, 0x78},
{0x0164, 0x02},
{0x0165, 0xa8},
{0x0166, 0x0a},
@@ -233,49 +246,13 @@ static const struct imx219_reg mode_1920_1080_regs[] = {
{0x016d, 0x80},
{0x016e, 0x04},
{0x016f, 0x38},
- {0x0170, 0x01},
- {0x0171, 0x01},
- {0x0174, 0x00},
- {0x0175, 0x00},
- {0x0301, 0x05},
- {0x0303, 0x01},
- {0x0304, 0x03},
- {0x0305, 0x03},
- {0x0306, 0x00},
- {0x0307, 0x39},
- {0x030b, 0x01},
- {0x030c, 0x00},
- {0x030d, 0x72},
{0x0624, 0x07},
{0x0625, 0x80},
{0x0626, 0x04},
{0x0627, 0x38},
- {0x455e, 0x00},
- {0x471e, 0x4b},
- {0x4767, 0x0f},
- {0x4750, 0x14},
- {0x4540, 0x00},
- {0x47b4, 0x14},
- {0x4713, 0x30},
- {0x478b, 0x10},
- {0x478f, 0x10},
- {0x4793, 0x10},
- {0x4797, 0x0e},
- {0x479b, 0x0e},
};
static const struct imx219_reg mode_1640_1232_regs[] = {
- {0x0100, 0x00},
- {0x30eb, 0x0c},
- {0x30eb, 0x05},
- {0x300a, 0xff},
- {0x300b, 0xff},
- {0x30eb, 0x05},
- {0x30eb, 0x09},
- {0x0114, 0x01},
- {0x0128, 0x00},
- {0x012a, 0x18},
- {0x012b, 0x00},
{0x0164, 0x00},
{0x0165, 0x00},
{0x0166, 0x0c},
@@ -288,53 +265,13 @@ static const struct imx219_reg mode_1640_1232_regs[] = {
{0x016d, 0x68},
{0x016e, 0x04},
{0x016f, 0xd0},
- {0x0170, 0x01},
- {0x0171, 0x01},
- {0x0174, 0x01},
- {0x0175, 0x01},
- {0x0301, 0x05},
- {0x0303, 0x01},
- {0x0304, 0x03},
- {0x0305, 0x03},
- {0x0306, 0x00},
- {0x0307, 0x39},
- {0x030b, 0x01},
- {0x030c, 0x00},
- {0x030d, 0x72},
{0x0624, 0x06},
{0x0625, 0x68},
{0x0626, 0x04},
{0x0627, 0xd0},
- {0x455e, 0x00},
- {0x471e, 0x4b},
- {0x4767, 0x0f},
- {0x4750, 0x14},
- {0x4540, 0x00},
- {0x47b4, 0x14},
- {0x4713, 0x30},
- {0x478b, 0x10},
- {0x478f, 0x10},
- {0x4793, 0x10},
- {0x4797, 0x0e},
- {0x479b, 0x0e},
- {0x0162, 0x0d},
- {0x0163, 0x78},
};
static const struct imx219_reg mode_640_480_regs[] = {
- {0x0100, 0x00},
- {0x30eb, 0x05},
- {0x30eb, 0x0c},
- {0x300a, 0xff},
- {0x300b, 0xff},
- {0x30eb, 0x05},
- {0x30eb, 0x09},
- {0x0114, 0x01},
- {0x0128, 0x00},
- {0x012a, 0x18},
- {0x012b, 0x00},
- {0x0162, 0x0d},
- {0x0163, 0x78},
{0x0164, 0x03},
{0x0165, 0xe8},
{0x0166, 0x08},
@@ -347,35 +284,10 @@ static const struct imx219_reg mode_640_480_regs[] = {
{0x016d, 0x80},
{0x016e, 0x01},
{0x016f, 0xe0},
- {0x0170, 0x01},
- {0x0171, 0x01},
- {0x0174, 0x03},
- {0x0175, 0x03},
- {0x0301, 0x05},
- {0x0303, 0x01},
- {0x0304, 0x03},
- {0x0305, 0x03},
- {0x0306, 0x00},
- {0x0307, 0x39},
- {0x030b, 0x01},
- {0x030c, 0x00},
- {0x030d, 0x72},
{0x0624, 0x06},
{0x0625, 0x68},
{0x0626, 0x04},
{0x0627, 0xd0},
- {0x455e, 0x00},
- {0x471e, 0x4b},
- {0x4767, 0x0f},
- {0x4750, 0x14},
- {0x4540, 0x00},
- {0x47b4, 0x14},
- {0x4713, 0x30},
- {0x478b, 0x10},
- {0x478f, 0x10},
- {0x4793, 0x10},
- {0x4797, 0x0e},
- {0x479b, 0x0e},
};
static const struct imx219_reg raw8_framefmt_regs[] = {
@@ -394,6 +306,10 @@ static const s64 imx219_link_freq_menu[] = {
IMX219_DEFAULT_LINK_FREQ,
};
+static const s64 imx219_link_freq_4lane_menu[] = {
+ IMX219_DEFAULT_LINK_FREQ_4LANE,
+};
+
static const char * const imx219_test_pattern_menu[] = {
"Disabled",
"Color Bars",
@@ -485,6 +401,7 @@ static const struct imx219_mode supported_modes[] = {
.num_of_regs = ARRAY_SIZE(mode_3280x2464_regs),
.regs = mode_3280x2464_regs,
},
+ .binning = false,
},
{
/* 1080P 30fps cropped */
@@ -501,6 +418,7 @@ static const struct imx219_mode supported_modes[] = {
.num_of_regs = ARRAY_SIZE(mode_1920_1080_regs),
.regs = mode_1920_1080_regs,
},
+ .binning = false,
},
{
/* 2x2 binned 30fps mode */
@@ -517,6 +435,7 @@ static const struct imx219_mode supported_modes[] = {
.num_of_regs = ARRAY_SIZE(mode_1640_1232_regs),
.regs = mode_1640_1232_regs,
},
+ .binning = true,
},
{
/* 640x480 30fps mode */
@@ -533,6 +452,7 @@ static const struct imx219_mode supported_modes[] = {
.num_of_regs = ARRAY_SIZE(mode_640_480_regs),
.regs = mode_640_480_regs,
},
+ .binning = true,
},
};
@@ -569,6 +489,9 @@ struct imx219 {
/* Streaming on/off */
bool streaming;
+
+ /* Two or Four lanes */
+ u8 lanes;
};
static inline struct imx219 *to_imx219(struct v4l2_subdev *_sd)
@@ -979,6 +902,35 @@ static int imx219_set_framefmt(struct imx219 *imx219)
return -EINVAL;
}
+static int imx219_set_binning(struct imx219 *imx219)
+{
+ if (!imx219->mode->binning) {
+ return imx219_write_reg(imx219, IMX219_REG_BINNING_MODE,
+ IMX219_REG_VALUE_16BIT,
+ IMX219_BINNING_NONE);
+ }
+
+ switch (imx219->fmt.code) {
+ case MEDIA_BUS_FMT_SRGGB8_1X8:
+ case MEDIA_BUS_FMT_SGRBG8_1X8:
+ case MEDIA_BUS_FMT_SGBRG8_1X8:
+ case MEDIA_BUS_FMT_SBGGR8_1X8:
+ return imx219_write_reg(imx219, IMX219_REG_BINNING_MODE,
+ IMX219_REG_VALUE_16BIT,
+ IMX219_BINNING_2X2_ANALOG);
+
+ case MEDIA_BUS_FMT_SRGGB10_1X10:
+ case MEDIA_BUS_FMT_SGRBG10_1X10:
+ case MEDIA_BUS_FMT_SGBRG10_1X10:
+ case MEDIA_BUS_FMT_SBGGR10_1X10:
+ return imx219_write_reg(imx219, IMX219_REG_BINNING_MODE,
+ IMX219_REG_VALUE_16BIT,
+ IMX219_BINNING_2X2);
+ }
+
+ return -EINVAL;
+}
+
static const struct v4l2_rect *
__imx219_get_pad_crop(struct imx219 *imx219,
struct v4l2_subdev_state *sd_state,
@@ -1031,6 +983,13 @@ static int imx219_get_selection(struct v4l2_subdev *sd,
return -EINVAL;
}
+static int imx219_configure_lanes(struct imx219 *imx219)
+{
+ return imx219_write_reg(imx219, IMX219_REG_CSI_LANE_MODE,
+ IMX219_REG_VALUE_08BIT, (imx219->lanes == 2) ?
+ IMX219_CSI_2_LANE_MODE : IMX219_CSI_4_LANE_MODE);
+};
+
static int imx219_start_streaming(struct imx219 *imx219)
{
struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
@@ -1041,6 +1000,20 @@ static int imx219_start_streaming(struct imx219 *imx219)
if (ret < 0)
return ret;
+ /* Send all registers that are common to all modes */
+ ret = imx219_write_regs(imx219, imx219_common_regs, ARRAY_SIZE(imx219_common_regs));
+ if (ret) {
+ dev_err(&client->dev, "%s failed to send mfg header\n", __func__);
+ goto err_rpm_put;
+ }
+
+ /* Configure two or four Lane mode */
+ ret = imx219_configure_lanes(imx219);
+ if (ret) {
+ dev_err(&client->dev, "%s failed to configure lanes\n", __func__);
+ goto err_rpm_put;
+ }
+
/* Apply default values of current mode */
reg_list = &imx219->mode->reg_list;
ret = imx219_write_regs(imx219, reg_list->regs, reg_list->num_of_regs);
@@ -1056,6 +1029,13 @@ static int imx219_start_streaming(struct imx219 *imx219)
goto err_rpm_put;
}
+ ret = imx219_set_binning(imx219);
+ if (ret) {
+ dev_err(&client->dev, "%s failed to set binning: %d\n",
+ __func__, ret);
+ goto err_rpm_put;
+ }
+
/* Apply customized values from user */
ret = __v4l2_ctrl_handler_setup(imx219->sd.ctrl_handler);
if (ret)
@@ -1272,6 +1252,11 @@ static const struct v4l2_subdev_internal_ops imx219_internal_ops = {
.open = imx219_open,
};
+static unsigned long imx219_get_pixel_rate(struct imx219 *imx219)
+{
+ return (imx219->lanes == 2) ? IMX219_PIXEL_RATE : IMX219_PIXEL_RATE_4LANE;
+}
+
/* Initialize control handlers */
static int imx219_init_controls(struct imx219 *imx219)
{
@@ -1293,15 +1278,16 @@ static int imx219_init_controls(struct imx219 *imx219)
/* By default, PIXEL_RATE is read only */
imx219->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
V4L2_CID_PIXEL_RATE,
- IMX219_PIXEL_RATE,
- IMX219_PIXEL_RATE, 1,
- IMX219_PIXEL_RATE);
+ imx219_get_pixel_rate(imx219),
+ imx219_get_pixel_rate(imx219), 1,
+ imx219_get_pixel_rate(imx219));
imx219->link_freq =
v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx219_ctrl_ops,
V4L2_CID_LINK_FREQ,
ARRAY_SIZE(imx219_link_freq_menu) - 1, 0,
- imx219_link_freq_menu);
+ (imx219->lanes == 2) ? imx219_link_freq_menu :
+ imx219_link_freq_4lane_menu);
if (imx219->link_freq)
imx219->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
@@ -1396,7 +1382,7 @@ static void imx219_free_controls(struct imx219 *imx219)
mutex_destroy(&imx219->mutex);
}
-static int imx219_check_hwcfg(struct device *dev)
+static int imx219_check_hwcfg(struct device *dev, struct imx219 *imx219)
{
struct fwnode_handle *endpoint;
struct v4l2_fwnode_endpoint ep_cfg = {
@@ -1416,10 +1402,12 @@ static int imx219_check_hwcfg(struct device *dev)
}
/* Check the number of MIPI CSI2 data lanes */
- if (ep_cfg.bus.mipi_csi2.num_data_lanes != 2) {
- dev_err(dev, "only 2 data lanes are currently supported\n");
+ if (ep_cfg.bus.mipi_csi2.num_data_lanes != 2 &&
+ ep_cfg.bus.mipi_csi2.num_data_lanes != 4) {
+ dev_err(dev, "only 2 or 4 data lanes are currently supported\n");
goto error_out;
}
+ imx219->lanes = ep_cfg.bus.mipi_csi2.num_data_lanes;
/* Check the link frequency set in device tree */
if (!ep_cfg.nr_of_link_frequencies) {
@@ -1428,7 +1416,8 @@ static int imx219_check_hwcfg(struct device *dev)
}
if (ep_cfg.nr_of_link_frequencies != 1 ||
- ep_cfg.link_frequencies[0] != IMX219_DEFAULT_LINK_FREQ) {
+ (ep_cfg.link_frequencies[0] != ((imx219->lanes == 2) ?
+ IMX219_DEFAULT_LINK_FREQ : IMX219_DEFAULT_LINK_FREQ_4LANE))) {
dev_err(dev, "Link frequency not supported: %lld\n",
ep_cfg.link_frequencies[0]);
goto error_out;
@@ -1456,7 +1445,7 @@ static int imx219_probe(struct i2c_client *client)
v4l2_i2c_subdev_init(&imx219->sd, client, &imx219_subdev_ops);
/* Check the hardware configuration in device tree */
- if (imx219_check_hwcfg(dev))
+ if (imx219_check_hwcfg(dev, imx219))
return -EINVAL;
/* Get system clock (xclk) */
diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c
index 218ded13fd80..49d6c8bdec41 100644
--- a/drivers/media/i2c/imx290.c
+++ b/drivers/media/i2c/imx290.c
@@ -152,13 +152,10 @@
#define IMX290_PIXEL_ARRAY_RECORDING_WIDTH 1920
#define IMX290_PIXEL_ARRAY_RECORDING_HEIGHT 1080
-static const char * const imx290_supply_name[] = {
- "vdda",
- "vddd",
- "vdddo",
-};
+/* Equivalent value for 16bpp */
+#define IMX290_BLACK_LEVEL_DEFAULT 3840
-#define IMX290_NUM_SUPPLIES ARRAY_SIZE(imx290_supply_name)
+#define IMX290_NUM_SUPPLIES 3
struct imx290_regval {
u32 reg;
@@ -180,11 +177,10 @@ struct imx290 {
struct clk *xclk;
struct regmap *regmap;
u8 nlanes;
- u8 bpp;
struct v4l2_subdev sd;
struct media_pad pad;
- struct v4l2_mbus_framefmt current_format;
+
const struct imx290_mode *current_mode;
struct regulator_bulk_data supplies[IMX290_NUM_SUPPLIES];
@@ -195,35 +191,16 @@ struct imx290 {
struct v4l2_ctrl *pixel_rate;
struct v4l2_ctrl *hblank;
struct v4l2_ctrl *vblank;
-
- struct mutex lock;
-};
-
-struct imx290_pixfmt {
- u32 code;
- u8 bpp;
-};
-
-static const struct imx290_pixfmt imx290_formats[] = {
- { MEDIA_BUS_FMT_SRGGB10_1X10, 10 },
- { MEDIA_BUS_FMT_SRGGB12_1X12, 12 },
};
-static const struct regmap_config imx290_regmap_config = {
- .reg_bits = 16,
- .val_bits = 8,
-};
+static inline struct imx290 *to_imx290(struct v4l2_subdev *_sd)
+{
+ return container_of(_sd, struct imx290, sd);
+}
-static const char * const imx290_test_pattern_menu[] = {
- "Disabled",
- "Sequence Pattern 1",
- "Horizontal Color-bar Chart",
- "Vertical Color-bar Chart",
- "Sequence Pattern 2",
- "Gradation Pattern 1",
- "Gradation Pattern 2",
- "000/555h Toggle Pattern",
-};
+/* -----------------------------------------------------------------------------
+ * Modes and formats
+ */
static const struct imx290_regval imx290_global_init_settings[] = {
{ IMX290_CTRL_07, IMX290_WINMODE_1080P },
@@ -338,7 +315,6 @@ static const struct imx290_regval imx290_10bit_settings[] = {
{ IMX290_ADBIT2, IMX290_ADBIT2_10BIT },
{ IMX290_ADBIT3, IMX290_ADBIT3_10BIT },
{ IMX290_CSI_DT_FMT, IMX290_CSI_DT_FMT_RAW10 },
- { IMX290_BLKLEVEL, 60 },
};
static const struct imx290_regval imx290_12bit_settings[] = {
@@ -348,7 +324,6 @@ static const struct imx290_regval imx290_12bit_settings[] = {
{ IMX290_ADBIT2, IMX290_ADBIT2_12BIT },
{ IMX290_ADBIT3, IMX290_ADBIT3_12BIT },
{ IMX290_CSI_DT_FMT, IMX290_CSI_DT_FMT_RAW12 },
- { IMX290_BLKLEVEL, 240 },
};
/* supported link frequencies */
@@ -438,11 +413,45 @@ static inline int imx290_modes_num(const struct imx290 *imx290)
return ARRAY_SIZE(imx290_modes_4lanes);
}
-static inline struct imx290 *to_imx290(struct v4l2_subdev *_sd)
+struct imx290_format_info {
+ u32 code;
+ u8 bpp;
+ const struct imx290_regval *regs;
+ unsigned int num_regs;
+};
+
+static const struct imx290_format_info imx290_formats[] = {
+ {
+ .code = MEDIA_BUS_FMT_SRGGB10_1X10,
+ .bpp = 10,
+ .regs = imx290_10bit_settings,
+ .num_regs = ARRAY_SIZE(imx290_10bit_settings),
+ }, {
+ .code = MEDIA_BUS_FMT_SRGGB12_1X12,
+ .bpp = 12,
+ .regs = imx290_12bit_settings,
+ .num_regs = ARRAY_SIZE(imx290_12bit_settings),
+ }
+};
+
+static const struct imx290_format_info *imx290_format_info(u32 code)
{
- return container_of(_sd, struct imx290, sd);
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(imx290_formats); ++i) {
+ const struct imx290_format_info *info = &imx290_formats[i];
+
+ if (info->code == code)
+ return info;
+ }
+
+ return NULL;
}
+/* -----------------------------------------------------------------------------
+ * Register access
+ */
+
static int __always_unused imx290_read(struct imx290 *imx290, u32 addr, u32 *value)
{
u8 data[3] = { 0, 0, 0 };
@@ -501,28 +510,82 @@ static int imx290_set_register_array(struct imx290 *imx290,
return 0;
}
-/* Stop streaming */
-static int imx290_stop_streaming(struct imx290 *imx290)
+static int imx290_set_data_lanes(struct imx290 *imx290)
{
int ret = 0;
+ u32 frsel;
- imx290_write(imx290, IMX290_STANDBY, 0x01, &ret);
+ switch (imx290->nlanes) {
+ case 2:
+ default:
+ frsel = 0x02;
+ break;
+ case 4:
+ frsel = 0x01;
+ break;
+ }
- msleep(30);
+ imx290_write(imx290, IMX290_PHY_LANE_NUM, imx290->nlanes - 1, &ret);
+ imx290_write(imx290, IMX290_CSI_LANE_MODE, imx290->nlanes - 1, &ret);
+ imx290_write(imx290, IMX290_FR_FDG_SEL, frsel, &ret);
- return imx290_write(imx290, IMX290_XMSTA, 0x01, &ret);
+ return ret;
+}
+
+static int imx290_set_black_level(struct imx290 *imx290,
+ const struct v4l2_mbus_framefmt *format,
+ unsigned int black_level, int *err)
+{
+ unsigned int bpp = imx290_format_info(format->code)->bpp;
+
+ return imx290_write(imx290, IMX290_BLKLEVEL,
+ black_level >> (16 - bpp), err);
+}
+
+static int imx290_setup_format(struct imx290 *imx290,
+ const struct v4l2_mbus_framefmt *format)
+{
+ const struct imx290_format_info *info;
+ int ret;
+
+ info = imx290_format_info(format->code);
+
+ ret = imx290_set_register_array(imx290, info->regs, info->num_regs);
+ if (ret < 0) {
+ dev_err(imx290->dev, "Could not set format registers\n");
+ return ret;
+ }
+
+ return imx290_set_black_level(imx290, format,
+ IMX290_BLACK_LEVEL_DEFAULT, &ret);
}
+/* ----------------------------------------------------------------------------
+ * Controls
+ */
+
static int imx290_set_ctrl(struct v4l2_ctrl *ctrl)
{
struct imx290 *imx290 = container_of(ctrl->handler,
struct imx290, ctrls);
+ const struct v4l2_mbus_framefmt *format;
+ struct v4l2_subdev_state *state;
int ret = 0;
+ /*
+ * Return immediately for controls that don't need to be applied to the
+ * device.
+ */
+ if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY)
+ return 0;
+
/* V4L2 controls values will be applied only when power is already up */
if (!pm_runtime_get_if_in_use(imx290->dev))
return 0;
+ state = v4l2_subdev_get_locked_active_state(&imx290->sd);
+ format = v4l2_subdev_get_pad_format(&imx290->sd, state, 0);
+
switch (ctrl->id) {
case V4L2_CID_ANALOGUE_GAIN:
ret = imx290_write(imx290, IMX290_GAIN, ctrl->val, NULL);
@@ -535,7 +598,7 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_TEST_PATTERN:
if (ctrl->val) {
- imx290_write(imx290, IMX290_BLKLEVEL, 0, &ret);
+ imx290_set_black_level(imx290, format, 0, &ret);
usleep_range(10000, 11000);
imx290_write(imx290, IMX290_PGCTRL,
(u8)(IMX290_PGCTRL_REGEN |
@@ -544,20 +607,18 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl)
} else {
imx290_write(imx290, IMX290_PGCTRL, 0x00, &ret);
usleep_range(10000, 11000);
- if (imx290->bpp == 10)
- imx290_write(imx290, IMX290_BLKLEVEL, 0x3c,
- &ret);
- else /* 12 bits per pixel */
- imx290_write(imx290, IMX290_BLKLEVEL, 0xf0,
- &ret);
+ imx290_set_black_level(imx290, format,
+ IMX290_BLACK_LEVEL_DEFAULT, &ret);
}
break;
+
default:
ret = -EINVAL;
break;
}
- pm_runtime_put(imx290->dev);
+ pm_runtime_mark_last_busy(imx290->dev);
+ pm_runtime_put_autosuspend(imx290->dev);
return ret;
}
@@ -566,14 +627,217 @@ static const struct v4l2_ctrl_ops imx290_ctrl_ops = {
.s_ctrl = imx290_set_ctrl,
};
-static struct v4l2_mbus_framefmt *
-imx290_get_pad_format(struct imx290 *imx290, struct v4l2_subdev_state *state,
- u32 which)
+static const char * const imx290_test_pattern_menu[] = {
+ "Disabled",
+ "Sequence Pattern 1",
+ "Horizontal Color-bar Chart",
+ "Vertical Color-bar Chart",
+ "Sequence Pattern 2",
+ "Gradation Pattern 1",
+ "Gradation Pattern 2",
+ "000/555h Toggle Pattern",
+};
+
+static void imx290_ctrl_update(struct imx290 *imx290,
+ const struct v4l2_mbus_framefmt *format,
+ const struct imx290_mode *mode)
{
- if (which == V4L2_SUBDEV_FORMAT_ACTIVE)
- return &imx290->current_format;
- else
- return v4l2_subdev_get_try_format(&imx290->sd, state, 0);
+ unsigned int hblank = mode->hmax - mode->width;
+ unsigned int vblank = IMX290_VMAX_DEFAULT - mode->height;
+ s64 link_freq = imx290_link_freqs_ptr(imx290)[mode->link_freq_index];
+ u64 pixel_rate;
+
+ /* pixel rate = link_freq * 2 * nr_of_lanes / bits_per_sample */
+ pixel_rate = link_freq * 2 * imx290->nlanes;
+ do_div(pixel_rate, imx290_format_info(format->code)->bpp);
+
+ __v4l2_ctrl_s_ctrl(imx290->link_freq, mode->link_freq_index);
+ __v4l2_ctrl_s_ctrl_int64(imx290->pixel_rate, pixel_rate);
+
+ __v4l2_ctrl_modify_range(imx290->hblank, hblank, hblank, 1, hblank);
+ __v4l2_ctrl_modify_range(imx290->vblank, vblank, vblank, 1, vblank);
+}
+
+static int imx290_ctrl_init(struct imx290 *imx290)
+{
+ struct v4l2_fwnode_device_properties props;
+ int ret;
+
+ ret = v4l2_fwnode_device_parse(imx290->dev, &props);
+ if (ret < 0)
+ return ret;
+
+ v4l2_ctrl_handler_init(&imx290->ctrls, 9);
+
+ /*
+ * The sensor has an analog gain and a digital gain, both controlled
+ * through a single gain value, expressed in 0.3dB increments. Values
+ * from 0.0dB (0) to 30.0dB (100) apply analog gain only, higher values
+ * up to 72.0dB (240) add further digital gain. Limit the range to
+ * analog gain only, support for digital gain can be added separately
+ * if needed.
+ *
+ * The IMX327 and IMX462 are largely compatible with the IMX290, but
+ * have an analog gain range of 0.0dB to 29.4dB and 42dB of digital
+ * gain. When support for those sensors gets added to the driver, the
+ * gain control should be adjusted accordingly.
+ */
+ v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
+ V4L2_CID_ANALOGUE_GAIN, 0, 100, 1, 0);
+
+ v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
+ V4L2_CID_EXPOSURE, 1, IMX290_VMAX_DEFAULT - 2, 1,
+ IMX290_VMAX_DEFAULT - 2);
+
+ /*
+ * Set the link frequency, pixel rate, horizontal blanking and vertical
+ * blanking to hardcoded values, they will be updated by
+ * imx290_ctrl_update().
+ */
+ imx290->link_freq =
+ v4l2_ctrl_new_int_menu(&imx290->ctrls, &imx290_ctrl_ops,
+ V4L2_CID_LINK_FREQ,
+ imx290_link_freqs_num(imx290) - 1, 0,
+ imx290_link_freqs_ptr(imx290));
+ if (imx290->link_freq)
+ imx290->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ imx290->pixel_rate = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
+ V4L2_CID_PIXEL_RATE,
+ 1, INT_MAX, 1, 1);
+
+ v4l2_ctrl_new_std_menu_items(&imx290->ctrls, &imx290_ctrl_ops,
+ V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(imx290_test_pattern_menu) - 1,
+ 0, 0, imx290_test_pattern_menu);
+
+ imx290->hblank = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
+ V4L2_CID_HBLANK, 1, 1, 1, 1);
+ if (imx290->hblank)
+ imx290->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ imx290->vblank = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
+ V4L2_CID_VBLANK, 1, 1, 1, 1);
+ if (imx290->vblank)
+ imx290->vblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ v4l2_ctrl_new_fwnode_properties(&imx290->ctrls, &imx290_ctrl_ops,
+ &props);
+
+ imx290->sd.ctrl_handler = &imx290->ctrls;
+
+ if (imx290->ctrls.error) {
+ ret = imx290->ctrls.error;
+ v4l2_ctrl_handler_free(&imx290->ctrls);
+ return ret;
+ }
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------------
+ * Subdev operations
+ */
+
+/* Start streaming */
+static int imx290_start_streaming(struct imx290 *imx290,
+ struct v4l2_subdev_state *state)
+{
+ const struct v4l2_mbus_framefmt *format;
+ int ret;
+
+ /* Set init register settings */
+ ret = imx290_set_register_array(imx290, imx290_global_init_settings,
+ ARRAY_SIZE(
+ imx290_global_init_settings));
+ if (ret < 0) {
+ dev_err(imx290->dev, "Could not set init registers\n");
+ return ret;
+ }
+
+ /* Set data lane count */
+ ret = imx290_set_data_lanes(imx290);
+ if (ret < 0) {
+ dev_err(imx290->dev, "Could not set data lanes\n");
+ return ret;
+ }
+
+ /* Apply the register values related to current frame format */
+ format = v4l2_subdev_get_pad_format(&imx290->sd, state, 0);
+ ret = imx290_setup_format(imx290, format);
+ if (ret < 0) {
+ dev_err(imx290->dev, "Could not set frame format\n");
+ return ret;
+ }
+
+ /* Apply default values of current mode */
+ ret = imx290_set_register_array(imx290, imx290->current_mode->data,
+ imx290->current_mode->data_size);
+ if (ret < 0) {
+ dev_err(imx290->dev, "Could not set current mode\n");
+ return ret;
+ }
+
+ ret = imx290_write(imx290, IMX290_HMAX, imx290->current_mode->hmax,
+ NULL);
+ if (ret)
+ return ret;
+
+ /* Apply customized values from user */
+ ret = __v4l2_ctrl_handler_setup(imx290->sd.ctrl_handler);
+ if (ret) {
+ dev_err(imx290->dev, "Could not sync v4l2 controls\n");
+ return ret;
+ }
+
+ imx290_write(imx290, IMX290_STANDBY, 0x00, &ret);
+
+ msleep(30);
+
+ /* Start streaming */
+ return imx290_write(imx290, IMX290_XMSTA, 0x00, &ret);
+}
+
+/* Stop streaming */
+static int imx290_stop_streaming(struct imx290 *imx290)
+{
+ int ret = 0;
+
+ imx290_write(imx290, IMX290_STANDBY, 0x01, &ret);
+
+ msleep(30);
+
+ return imx290_write(imx290, IMX290_XMSTA, 0x01, &ret);
+}
+
+static int imx290_set_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct imx290 *imx290 = to_imx290(sd);
+ struct v4l2_subdev_state *state;
+ int ret = 0;
+
+ state = v4l2_subdev_lock_and_get_active_state(sd);
+
+ if (enable) {
+ ret = pm_runtime_resume_and_get(imx290->dev);
+ if (ret < 0)
+ goto unlock;
+
+ ret = imx290_start_streaming(imx290, state);
+ if (ret) {
+ dev_err(imx290->dev, "Start stream failed\n");
+ pm_runtime_put_sync(imx290->dev);
+ goto unlock;
+ }
+ } else {
+ imx290_stop_streaming(imx290);
+ pm_runtime_mark_last_busy(imx290->dev);
+ pm_runtime_put_autosuspend(imx290->dev);
+ }
+
+unlock:
+ v4l2_subdev_unlock_state(state);
+ return ret;
}
static int imx290_enum_mbus_code(struct v4l2_subdev *sd,
@@ -595,8 +859,7 @@ static int imx290_enum_frame_size(struct v4l2_subdev *sd,
const struct imx290 *imx290 = to_imx290(sd);
const struct imx290_mode *imx290_modes = imx290_modes_ptr(imx290);
- if ((fse->code != imx290_formats[0].code) &&
- (fse->code != imx290_formats[1].code))
+ if (!imx290_format_info(fse->code))
return -EINVAL;
if (fse->index >= imx290_modes_num(imx290))
@@ -610,47 +873,6 @@ static int imx290_enum_frame_size(struct v4l2_subdev *sd,
return 0;
}
-static int imx290_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *fmt)
-{
- struct imx290 *imx290 = to_imx290(sd);
- struct v4l2_mbus_framefmt *framefmt;
-
- mutex_lock(&imx290->lock);
-
- framefmt = imx290_get_pad_format(imx290, sd_state, fmt->which);
- fmt->format = *framefmt;
-
- mutex_unlock(&imx290->lock);
-
- return 0;
-}
-
-static inline u8 imx290_get_link_freq_index(struct imx290 *imx290)
-{
- return imx290->current_mode->link_freq_index;
-}
-
-static s64 imx290_get_link_freq(struct imx290 *imx290)
-{
- u8 index = imx290_get_link_freq_index(imx290);
-
- return *(imx290_link_freqs_ptr(imx290) + index);
-}
-
-static u64 imx290_calc_pixel_rate(struct imx290 *imx290)
-{
- s64 link_freq = imx290_get_link_freq(imx290);
- u8 nlanes = imx290->nlanes;
- u64 pixel_rate;
-
- /* pixel rate = link_freq * 2 * nr_of_lanes / bits_per_sample */
- pixel_rate = link_freq * 2 * nlanes;
- do_div(pixel_rate, imx290->bpp);
- return pixel_rate;
-}
-
static int imx290_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
@@ -658,9 +880,6 @@ static int imx290_set_fmt(struct v4l2_subdev *sd,
struct imx290 *imx290 = to_imx290(sd);
const struct imx290_mode *mode;
struct v4l2_mbus_framefmt *format;
- unsigned int i;
-
- mutex_lock(&imx290->lock);
mode = v4l2_find_nearest_size(imx290_modes_ptr(imx290),
imx290_modes_num(imx290), width, height,
@@ -669,48 +888,21 @@ static int imx290_set_fmt(struct v4l2_subdev *sd,
fmt->format.width = mode->width;
fmt->format.height = mode->height;
- for (i = 0; i < ARRAY_SIZE(imx290_formats); i++)
- if (imx290_formats[i].code == fmt->format.code)
- break;
-
- if (i >= ARRAY_SIZE(imx290_formats))
- i = 0;
+ if (!imx290_format_info(fmt->format.code))
+ fmt->format.code = imx290_formats[0].code;
- fmt->format.code = imx290_formats[i].code;
fmt->format.field = V4L2_FIELD_NONE;
- format = imx290_get_pad_format(imx290, sd_state, fmt->which);
+ format = v4l2_subdev_get_pad_format(sd, sd_state, 0);
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
imx290->current_mode = mode;
- imx290->bpp = imx290_formats[i].bpp;
-
- if (imx290->link_freq)
- __v4l2_ctrl_s_ctrl(imx290->link_freq,
- imx290_get_link_freq_index(imx290));
- if (imx290->pixel_rate)
- __v4l2_ctrl_s_ctrl_int64(imx290->pixel_rate,
- imx290_calc_pixel_rate(imx290));
-
- if (imx290->hblank) {
- unsigned int hblank = mode->hmax - mode->width;
-
- __v4l2_ctrl_modify_range(imx290->hblank, hblank, hblank,
- 1, hblank);
- }
-
- if (imx290->vblank) {
- unsigned int vblank = IMX290_VMAX_DEFAULT - mode->height;
- __v4l2_ctrl_modify_range(imx290->vblank, vblank, vblank,
- 1, vblank);
- }
+ imx290_ctrl_update(imx290, &fmt->format, mode);
}
*format = fmt->format;
- mutex_unlock(&imx290->lock);
-
return 0;
}
@@ -718,14 +910,11 @@ static int imx290_get_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
- struct imx290 *imx290 = to_imx290(sd);
struct v4l2_mbus_framefmt *format;
switch (sel->target) {
case V4L2_SEL_TGT_CROP: {
- format = imx290_get_pad_format(imx290, sd_state, sel->which);
-
- mutex_lock(&imx290->lock);
+ format = v4l2_subdev_get_pad_format(sd, sd_state, 0);
sel->r.top = IMX920_PIXEL_ARRAY_MARGIN_TOP
+ (IMX290_PIXEL_ARRAY_RECORDING_HEIGHT - format->height) / 2;
@@ -734,7 +923,6 @@ static int imx290_get_selection(struct v4l2_subdev *sd,
sel->r.width = format->width;
sel->r.height = format->height;
- mutex_unlock(&imx290->lock);
return 0;
}
@@ -763,179 +951,116 @@ static int imx290_get_selection(struct v4l2_subdev *sd,
static int imx290_entity_init_cfg(struct v4l2_subdev *subdev,
struct v4l2_subdev_state *sd_state)
{
- struct v4l2_subdev_format fmt = { 0 };
-
- fmt.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
- fmt.format.width = 1920;
- fmt.format.height = 1080;
+ struct v4l2_subdev_format fmt = {
+ .which = V4L2_SUBDEV_FORMAT_TRY,
+ .format = {
+ .width = 1920,
+ .height = 1080,
+ },
+ };
imx290_set_fmt(subdev, sd_state, &fmt);
return 0;
}
-static int imx290_write_current_format(struct imx290 *imx290)
-{
- int ret;
+static const struct v4l2_subdev_video_ops imx290_video_ops = {
+ .s_stream = imx290_set_stream,
+};
- switch (imx290->current_format.code) {
- case MEDIA_BUS_FMT_SRGGB10_1X10:
- ret = imx290_set_register_array(imx290, imx290_10bit_settings,
- ARRAY_SIZE(
- imx290_10bit_settings));
- if (ret < 0) {
- dev_err(imx290->dev, "Could not set format registers\n");
- return ret;
- }
- break;
- case MEDIA_BUS_FMT_SRGGB12_1X12:
- ret = imx290_set_register_array(imx290, imx290_12bit_settings,
- ARRAY_SIZE(
- imx290_12bit_settings));
- if (ret < 0) {
- dev_err(imx290->dev, "Could not set format registers\n");
- return ret;
- }
- break;
- default:
- dev_err(imx290->dev, "Unknown pixel format\n");
- return -EINVAL;
- }
+static const struct v4l2_subdev_pad_ops imx290_pad_ops = {
+ .init_cfg = imx290_entity_init_cfg,
+ .enum_mbus_code = imx290_enum_mbus_code,
+ .enum_frame_size = imx290_enum_frame_size,
+ .get_fmt = v4l2_subdev_get_fmt,
+ .set_fmt = imx290_set_fmt,
+ .get_selection = imx290_get_selection,
+};
- return 0;
-}
+static const struct v4l2_subdev_ops imx290_subdev_ops = {
+ .video = &imx290_video_ops,
+ .pad = &imx290_pad_ops,
+};
-/* Start streaming */
-static int imx290_start_streaming(struct imx290 *imx290)
+static const struct media_entity_operations imx290_subdev_entity_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+static int imx290_subdev_init(struct imx290 *imx290)
{
+ struct i2c_client *client = to_i2c_client(imx290->dev);
+ const struct v4l2_mbus_framefmt *format;
+ struct v4l2_subdev_state *state;
int ret;
- /* Set init register settings */
- ret = imx290_set_register_array(imx290, imx290_global_init_settings,
- ARRAY_SIZE(
- imx290_global_init_settings));
- if (ret < 0) {
- dev_err(imx290->dev, "Could not set init registers\n");
- return ret;
- }
+ imx290->current_mode = &imx290_modes_ptr(imx290)[0];
- /* Apply the register values related to current frame format */
- ret = imx290_write_current_format(imx290);
+ v4l2_i2c_subdev_init(&imx290->sd, client, &imx290_subdev_ops);
+ imx290->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ imx290->sd.dev = imx290->dev;
+ imx290->sd.entity.ops = &imx290_subdev_entity_ops;
+ imx290->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+
+ imx290->pad.flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_pads_init(&imx290->sd.entity, 1, &imx290->pad);
if (ret < 0) {
- dev_err(imx290->dev, "Could not set frame format\n");
+ dev_err(imx290->dev, "Could not register media entity\n");
return ret;
}
- /* Apply default values of current mode */
- ret = imx290_set_register_array(imx290, imx290->current_mode->data,
- imx290->current_mode->data_size);
+ ret = imx290_ctrl_init(imx290);
if (ret < 0) {
- dev_err(imx290->dev, "Could not set current mode\n");
- return ret;
+ dev_err(imx290->dev, "Control initialization error %d\n", ret);
+ goto err_media;
}
- ret = imx290_write(imx290, IMX290_HMAX, imx290->current_mode->hmax,
- NULL);
- if (ret)
- return ret;
+ imx290->sd.state_lock = imx290->ctrls.lock;
- /* Apply customized values from user */
- ret = v4l2_ctrl_handler_setup(imx290->sd.ctrl_handler);
- if (ret) {
- dev_err(imx290->dev, "Could not sync v4l2 controls\n");
- return ret;
+ ret = v4l2_subdev_init_finalize(&imx290->sd);
+ if (ret < 0) {
+ dev_err(imx290->dev, "subdev initialization error %d\n", ret);
+ goto err_ctrls;
}
- imx290_write(imx290, IMX290_STANDBY, 0x00, &ret);
-
- msleep(30);
-
- /* Start streaming */
- return imx290_write(imx290, IMX290_XMSTA, 0x00, &ret);
-}
-
-static int imx290_set_stream(struct v4l2_subdev *sd, int enable)
-{
- struct imx290 *imx290 = to_imx290(sd);
- int ret = 0;
+ state = v4l2_subdev_lock_and_get_active_state(&imx290->sd);
+ format = v4l2_subdev_get_pad_format(&imx290->sd, state, 0);
+ imx290_ctrl_update(imx290, format, imx290->current_mode);
+ v4l2_subdev_unlock_state(state);
- if (enable) {
- ret = pm_runtime_resume_and_get(imx290->dev);
- if (ret < 0)
- goto unlock_and_return;
-
- ret = imx290_start_streaming(imx290);
- if (ret) {
- dev_err(imx290->dev, "Start stream failed\n");
- pm_runtime_put(imx290->dev);
- goto unlock_and_return;
- }
- } else {
- imx290_stop_streaming(imx290);
- pm_runtime_put(imx290->dev);
- }
-
-unlock_and_return:
+ return 0;
+err_ctrls:
+ v4l2_ctrl_handler_free(&imx290->ctrls);
+err_media:
+ media_entity_cleanup(&imx290->sd.entity);
return ret;
}
-static int imx290_get_regulators(struct device *dev, struct imx290 *imx290)
+static void imx290_subdev_cleanup(struct imx290 *imx290)
{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(imx290->supplies); i++)
- imx290->supplies[i].supply = imx290_supply_name[i];
-
- return devm_regulator_bulk_get(dev, ARRAY_SIZE(imx290->supplies),
- imx290->supplies);
+ v4l2_subdev_cleanup(&imx290->sd);
+ media_entity_cleanup(&imx290->sd.entity);
+ v4l2_ctrl_handler_free(&imx290->ctrls);
}
-static int imx290_set_data_lanes(struct imx290 *imx290)
-{
- int ret = 0, laneval, frsel;
-
- switch (imx290->nlanes) {
- case 2:
- laneval = 0x01;
- frsel = 0x02;
- break;
- case 4:
- laneval = 0x03;
- frsel = 0x01;
- break;
- default:
- /*
- * We should never hit this since the data lane count is
- * validated in probe itself
- */
- dev_err(imx290->dev, "Lane configuration not supported\n");
- return -EINVAL;
- }
-
- imx290_write(imx290, IMX290_PHY_LANE_NUM, laneval, &ret);
- imx290_write(imx290, IMX290_CSI_LANE_MODE, laneval, &ret);
- imx290_write(imx290, IMX290_FR_FDG_SEL, frsel, &ret);
-
- return ret;
-}
+/* ----------------------------------------------------------------------------
+ * Power management
+ */
-static int imx290_power_on(struct device *dev)
+static int imx290_power_on(struct imx290 *imx290)
{
- struct v4l2_subdev *sd = dev_get_drvdata(dev);
- struct imx290 *imx290 = to_imx290(sd);
int ret;
ret = clk_prepare_enable(imx290->xclk);
if (ret) {
- dev_err(dev, "Failed to enable clock\n");
+ dev_err(imx290->dev, "Failed to enable clock\n");
return ret;
}
ret = regulator_bulk_enable(ARRAY_SIZE(imx290->supplies),
imx290->supplies);
if (ret) {
- dev_err(dev, "Failed to enable regulators\n");
+ dev_err(imx290->dev, "Failed to enable regulators\n");
clk_disable_unprepare(imx290->xclk);
return ret;
}
@@ -944,123 +1069,86 @@ static int imx290_power_on(struct device *dev)
gpiod_set_value_cansleep(imx290->rst_gpio, 0);
usleep_range(30000, 31000);
- /* Set data lane count */
- imx290_set_data_lanes(imx290);
-
return 0;
}
-static int imx290_power_off(struct device *dev)
+static void imx290_power_off(struct imx290 *imx290)
{
- struct v4l2_subdev *sd = dev_get_drvdata(dev);
- struct imx290 *imx290 = to_imx290(sd);
-
clk_disable_unprepare(imx290->xclk);
gpiod_set_value_cansleep(imx290->rst_gpio, 1);
regulator_bulk_disable(ARRAY_SIZE(imx290->supplies), imx290->supplies);
+}
+
+static int imx290_runtime_resume(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct imx290 *imx290 = to_imx290(sd);
+
+ return imx290_power_on(imx290);
+}
+
+static int imx290_runtime_suspend(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct imx290 *imx290 = to_imx290(sd);
+
+ imx290_power_off(imx290);
return 0;
}
static const struct dev_pm_ops imx290_pm_ops = {
- SET_RUNTIME_PM_OPS(imx290_power_off, imx290_power_on, NULL)
-};
-
-static const struct v4l2_subdev_video_ops imx290_video_ops = {
- .s_stream = imx290_set_stream,
+ SET_RUNTIME_PM_OPS(imx290_runtime_suspend, imx290_runtime_resume, NULL)
};
-static const struct v4l2_subdev_pad_ops imx290_pad_ops = {
- .init_cfg = imx290_entity_init_cfg,
- .enum_mbus_code = imx290_enum_mbus_code,
- .enum_frame_size = imx290_enum_frame_size,
- .get_fmt = imx290_get_fmt,
- .set_fmt = imx290_set_fmt,
- .get_selection = imx290_get_selection,
-};
+/* ----------------------------------------------------------------------------
+ * Probe & remove
+ */
-static const struct v4l2_subdev_ops imx290_subdev_ops = {
- .video = &imx290_video_ops,
- .pad = &imx290_pad_ops,
+static const struct regmap_config imx290_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
};
-static const struct media_entity_operations imx290_subdev_entity_ops = {
- .link_validate = v4l2_subdev_link_validate,
+static const char * const imx290_supply_name[IMX290_NUM_SUPPLIES] = {
+ "vdda",
+ "vddd",
+ "vdddo",
};
-static int imx290_ctrl_init(struct imx290 *imx290)
+static int imx290_get_regulators(struct device *dev, struct imx290 *imx290)
{
- struct v4l2_fwnode_device_properties props;
- unsigned int blank;
- int ret;
-
- ret = v4l2_fwnode_device_parse(imx290->dev, &props);
- if (ret < 0)
- return ret;
-
- v4l2_ctrl_handler_init(&imx290->ctrls, 9);
- imx290->ctrls.lock = &imx290->lock;
-
- /*
- * The sensor has an analog gain and a digital gain, both controlled
- * through a single gain value, expressed in 0.3dB increments. Values
- * from 0.0dB (0) to 30.0dB (100) apply analog gain only, higher values
- * up to 72.0dB (240) add further digital gain. Limit the range to
- * analog gain only, support for digital gain can be added separately
- * if needed.
- *
- * The IMX327 and IMX462 are largely compatible with the IMX290, but
- * have an analog gain range of 0.0dB to 29.4dB and 42dB of digital
- * gain. When support for those sensors gets added to the driver, the
- * gain control should be adjusted accordingly.
- */
- v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
- V4L2_CID_ANALOGUE_GAIN, 0, 100, 1, 0);
-
- v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
- V4L2_CID_EXPOSURE, 1, IMX290_VMAX_DEFAULT - 2, 1,
- IMX290_VMAX_DEFAULT - 2);
-
- imx290->link_freq =
- v4l2_ctrl_new_int_menu(&imx290->ctrls, &imx290_ctrl_ops,
- V4L2_CID_LINK_FREQ,
- imx290_link_freqs_num(imx290) - 1, 0,
- imx290_link_freqs_ptr(imx290));
- if (imx290->link_freq)
- imx290->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
-
- imx290->pixel_rate = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
- V4L2_CID_PIXEL_RATE,
- 1, INT_MAX, 1,
- imx290_calc_pixel_rate(imx290));
+ unsigned int i;
- v4l2_ctrl_new_std_menu_items(&imx290->ctrls, &imx290_ctrl_ops,
- V4L2_CID_TEST_PATTERN,
- ARRAY_SIZE(imx290_test_pattern_menu) - 1,
- 0, 0, imx290_test_pattern_menu);
+ for (i = 0; i < ARRAY_SIZE(imx290->supplies); i++)
+ imx290->supplies[i].supply = imx290_supply_name[i];
- blank = imx290->current_mode->hmax - imx290->current_mode->width;
- imx290->hblank = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
- V4L2_CID_HBLANK, blank, blank, 1,
- blank);
- if (imx290->hblank)
- imx290->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ return devm_regulator_bulk_get(dev, ARRAY_SIZE(imx290->supplies),
+ imx290->supplies);
+}
- blank = IMX290_VMAX_DEFAULT - imx290->current_mode->height;
- imx290->vblank = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
- V4L2_CID_VBLANK, blank, blank, 1,
- blank);
- if (imx290->vblank)
- imx290->vblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+static int imx290_init_clk(struct imx290 *imx290)
+{
+ u32 xclk_freq;
+ int ret;
- v4l2_ctrl_new_fwnode_properties(&imx290->ctrls, &imx290_ctrl_ops,
- &props);
+ ret = fwnode_property_read_u32(dev_fwnode(imx290->dev),
+ "clock-frequency", &xclk_freq);
+ if (ret) {
+ dev_err(imx290->dev, "Could not get xclk frequency\n");
+ return ret;
+ }
- imx290->sd.ctrl_handler = &imx290->ctrls;
+ /* external clock must be 37.125 MHz */
+ if (xclk_freq != 37125000) {
+ dev_err(imx290->dev, "External clock frequency %u is not supported\n",
+ xclk_freq);
+ return -EINVAL;
+ }
- if (imx290->ctrls.error) {
- ret = imx290->ctrls.error;
- v4l2_ctrl_handler_free(&imx290->ctrls);
+ ret = clk_set_rate(imx290->xclk, xclk_freq);
+ if (ret) {
+ dev_err(imx290->dev, "Could not set xclk frequency\n");
return ret;
}
@@ -1089,171 +1177,159 @@ static s64 imx290_check_link_freqs(const struct imx290 *imx290,
return 0;
}
-static int imx290_probe(struct i2c_client *client)
+static int imx290_parse_dt(struct imx290 *imx290)
{
- struct device *dev = &client->dev;
- struct fwnode_handle *endpoint;
/* Only CSI2 is supported for now: */
struct v4l2_fwnode_endpoint ep = {
.bus_type = V4L2_MBUS_CSI2_DPHY
};
- struct imx290 *imx290;
- u32 xclk_freq;
- s64 fq;
+ struct fwnode_handle *endpoint;
int ret;
+ s64 fq;
- imx290 = devm_kzalloc(dev, sizeof(*imx290), GFP_KERNEL);
- if (!imx290)
- return -ENOMEM;
-
- imx290->dev = dev;
- imx290->regmap = devm_regmap_init_i2c(client, &imx290_regmap_config);
- if (IS_ERR(imx290->regmap)) {
- dev_err(dev, "Unable to initialize I2C\n");
- return -ENODEV;
- }
-
- endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL);
+ endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(imx290->dev), NULL);
if (!endpoint) {
- dev_err(dev, "Endpoint node not found\n");
+ dev_err(imx290->dev, "Endpoint node not found\n");
return -EINVAL;
}
ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep);
fwnode_handle_put(endpoint);
if (ret == -ENXIO) {
- dev_err(dev, "Unsupported bus type, should be CSI2\n");
- goto free_err;
+ dev_err(imx290->dev, "Unsupported bus type, should be CSI2\n");
+ goto done;
} else if (ret) {
- dev_err(dev, "Parsing endpoint node failed\n");
- goto free_err;
+ dev_err(imx290->dev, "Parsing endpoint node failed\n");
+ goto done;
}
/* Get number of data lanes */
imx290->nlanes = ep.bus.mipi_csi2.num_data_lanes;
if (imx290->nlanes != 2 && imx290->nlanes != 4) {
- dev_err(dev, "Invalid data lanes: %d\n", imx290->nlanes);
+ dev_err(imx290->dev, "Invalid data lanes: %d\n", imx290->nlanes);
ret = -EINVAL;
- goto free_err;
+ goto done;
}
- dev_dbg(dev, "Using %u data lanes\n", imx290->nlanes);
+ dev_dbg(imx290->dev, "Using %u data lanes\n", imx290->nlanes);
if (!ep.nr_of_link_frequencies) {
- dev_err(dev, "link-frequency property not found in DT\n");
+ dev_err(imx290->dev, "link-frequency property not found in DT\n");
ret = -EINVAL;
- goto free_err;
+ goto done;
}
/* Check that link frequences for all the modes are in device tree */
fq = imx290_check_link_freqs(imx290, &ep);
if (fq) {
- dev_err(dev, "Link frequency of %lld is not supported\n", fq);
+ dev_err(imx290->dev, "Link frequency of %lld is not supported\n",
+ fq);
ret = -EINVAL;
- goto free_err;
+ goto done;
}
- /* get system clock (xclk) */
- imx290->xclk = devm_clk_get(dev, "xclk");
- if (IS_ERR(imx290->xclk)) {
- dev_err(dev, "Could not get xclk");
- ret = PTR_ERR(imx290->xclk);
- goto free_err;
- }
+ ret = 0;
- ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency",
- &xclk_freq);
- if (ret) {
- dev_err(dev, "Could not get xclk frequency\n");
- goto free_err;
- }
+done:
+ v4l2_fwnode_endpoint_free(&ep);
+ return ret;
+}
- /* external clock must be 37.125 MHz */
- if (xclk_freq != 37125000) {
- dev_err(dev, "External clock frequency %u is not supported\n",
- xclk_freq);
- ret = -EINVAL;
- goto free_err;
- }
+static int imx290_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct imx290 *imx290;
+ int ret;
- ret = clk_set_rate(imx290->xclk, xclk_freq);
- if (ret) {
- dev_err(dev, "Could not set xclk frequency\n");
- goto free_err;
+ imx290 = devm_kzalloc(dev, sizeof(*imx290), GFP_KERNEL);
+ if (!imx290)
+ return -ENOMEM;
+
+ imx290->dev = dev;
+ imx290->regmap = devm_regmap_init_i2c(client, &imx290_regmap_config);
+ if (IS_ERR(imx290->regmap)) {
+ dev_err(dev, "Unable to initialize I2C\n");
+ return -ENODEV;
}
+ ret = imx290_parse_dt(imx290);
+ if (ret)
+ return ret;
+
+ /* Acquire resources. */
+ imx290->xclk = devm_clk_get(dev, "xclk");
+ if (IS_ERR(imx290->xclk))
+ return dev_err_probe(dev, PTR_ERR(imx290->xclk),
+ "Could not get xclk");
+
ret = imx290_get_regulators(dev, imx290);
- if (ret < 0) {
- dev_err(dev, "Cannot get regulators\n");
- goto free_err;
- }
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Cannot get regulators\n");
imx290->rst_gpio = devm_gpiod_get_optional(dev, "reset",
GPIOD_OUT_HIGH);
- if (IS_ERR(imx290->rst_gpio)) {
- dev_err(dev, "Cannot get reset gpio\n");
- ret = PTR_ERR(imx290->rst_gpio);
- goto free_err;
- }
+ if (IS_ERR(imx290->rst_gpio))
+ return dev_err_probe(dev, PTR_ERR(imx290->rst_gpio),
+ "Cannot get reset gpio\n");
- mutex_init(&imx290->lock);
+ /* Initialize external clock frequency. */
+ ret = imx290_init_clk(imx290);
+ if (ret)
+ return ret;
/*
- * Initialize the frame format. In particular, imx290->current_mode
- * and imx290->bpp are set to defaults: imx290_calc_pixel_rate() call
- * below relies on these fields.
+ * Enable power management. The driver supports runtime PM, but needs to
+ * work when runtime PM is disabled in the kernel. To that end, power
+ * the sensor on manually here.
*/
- imx290_entity_init_cfg(&imx290->sd, NULL);
-
- ret = imx290_ctrl_init(imx290);
+ ret = imx290_power_on(imx290);
if (ret < 0) {
- dev_err(dev, "Control initialization error %d\n", ret);
- goto free_mutex;
+ dev_err(dev, "Could not power on the device\n");
+ return ret;
}
- v4l2_i2c_subdev_init(&imx290->sd, client, &imx290_subdev_ops);
- imx290->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
- imx290->sd.dev = &client->dev;
- imx290->sd.entity.ops = &imx290_subdev_entity_ops;
- imx290->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+ /*
+ * Enable runtime PM with autosuspend. As the device has been powered
+ * manually, mark it as active, and increase the usage count without
+ * resuming the device.
+ */
+ pm_runtime_set_active(dev);
+ pm_runtime_get_noresume(dev);
+ pm_runtime_enable(dev);
+ pm_runtime_set_autosuspend_delay(dev, 1000);
+ pm_runtime_use_autosuspend(dev);
- imx290->pad.flags = MEDIA_PAD_FL_SOURCE;
- ret = media_entity_pads_init(&imx290->sd.entity, 1, &imx290->pad);
- if (ret < 0) {
- dev_err(dev, "Could not register media entity\n");
- goto free_ctrl;
- }
+ /* Initialize the V4L2 subdev. */
+ ret = imx290_subdev_init(imx290);
+ if (ret)
+ goto err_pm;
+ /*
+ * Finally, register the V4L2 subdev. This must be done after
+ * initializing everything as the subdev can be used immediately after
+ * being registered.
+ */
ret = v4l2_async_register_subdev(&imx290->sd);
if (ret < 0) {
dev_err(dev, "Could not register v4l2 device\n");
- goto free_entity;
- }
-
- /* Power on the device to match runtime PM state below */
- ret = imx290_power_on(dev);
- if (ret < 0) {
- dev_err(dev, "Could not power on the device\n");
- goto free_entity;
+ goto err_subdev;
}
- pm_runtime_set_active(dev);
- pm_runtime_enable(dev);
- pm_runtime_idle(dev);
-
- v4l2_fwnode_endpoint_free(&ep);
+ /*
+ * Decrease the PM usage count. The device will get suspended after the
+ * autosuspend delay, turning the power off.
+ */
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
return 0;
-free_entity:
- media_entity_cleanup(&imx290->sd.entity);
-free_ctrl:
- v4l2_ctrl_handler_free(&imx290->ctrls);
-free_mutex:
- mutex_destroy(&imx290->lock);
-free_err:
- v4l2_fwnode_endpoint_free(&ep);
-
+err_subdev:
+ imx290_subdev_cleanup(imx290);
+err_pm:
+ pm_runtime_disable(dev);
+ pm_runtime_put_noidle(dev);
+ imx290_power_off(imx290);
return ret;
}
@@ -1263,14 +1339,15 @@ static void imx290_remove(struct i2c_client *client)
struct imx290 *imx290 = to_imx290(sd);
v4l2_async_unregister_subdev(sd);
- media_entity_cleanup(&sd->entity);
- v4l2_ctrl_handler_free(sd->ctrl_handler);
-
- mutex_destroy(&imx290->lock);
+ imx290_subdev_cleanup(imx290);
+ /*
+ * Disable runtime PM. In case runtime PM is disabled in the kernel,
+ * make sure to turn power off manually.
+ */
pm_runtime_disable(imx290->dev);
if (!pm_runtime_status_suspended(imx290->dev))
- imx290_power_off(imx290->dev);
+ imx290_power_off(imx290);
pm_runtime_set_suspended(imx290->dev);
}
diff --git a/drivers/media/i2c/imx296.c b/drivers/media/i2c/imx296.c
new file mode 100644
index 000000000000..3c12b6edeac9
--- /dev/null
+++ b/drivers/media/i2c/imx296.c
@@ -0,0 +1,1172 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for IMX296 CMOS Image Sensor from Sony
+ *
+ * Copyright 2019 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-subdev.h>
+
+#define IMX296_PIXEL_ARRAY_WIDTH 1456
+#define IMX296_PIXEL_ARRAY_HEIGHT 1088
+
+#define IMX296_REG_8BIT(n) ((1 << 16) | (n))
+#define IMX296_REG_16BIT(n) ((2 << 16) | (n))
+#define IMX296_REG_24BIT(n) ((3 << 16) | (n))
+#define IMX296_REG_SIZE_SHIFT 16
+#define IMX296_REG_ADDR_MASK 0xffff
+
+#define IMX296_CTRL00 IMX296_REG_8BIT(0x3000)
+#define IMX296_CTRL00_STANDBY BIT(0)
+#define IMX296_CTRL08 IMX296_REG_8BIT(0x3008)
+#define IMX296_CTRL08_REGHOLD BIT(0)
+#define IMX296_CTRL0A IMX296_REG_8BIT(0x300a)
+#define IMX296_CTRL0A_XMSTA BIT(0)
+#define IMX296_CTRL0B IMX296_REG_8BIT(0x300b)
+#define IMX296_CTRL0B_TRIGEN BIT(0)
+#define IMX296_CTRL0D IMX296_REG_8BIT(0x300d)
+#define IMX296_CTRL0D_WINMODE_ALL (0 << 0)
+#define IMX296_CTRL0D_WINMODE_FD_BINNING (2 << 0)
+#define IMX296_CTRL0D_HADD_ON_BINNING BIT(5)
+#define IMX296_CTRL0D_SAT_CNT BIT(6)
+#define IMX296_CTRL0E IMX296_REG_8BIT(0x300e)
+#define IMX296_CTRL0E_VREVERSE BIT(0)
+#define IMX296_CTRL0E_HREVERSE BIT(1)
+#define IMX296_VMAX IMX296_REG_24BIT(0x3010)
+#define IMX296_HMAX IMX296_REG_16BIT(0x3014)
+#define IMX296_TMDCTRL IMX296_REG_8BIT(0x301d)
+#define IMX296_TMDCTRL_LATCH BIT(0)
+#define IMX296_TMDOUT IMX296_REG_16BIT(0x301e)
+#define IMX296_TMDOUT_MASK 0x3ff
+#define IMX296_WDSEL IMX296_REG_8BIT(0x3021)
+#define IMX296_WDSEL_NORMAL (0 << 0)
+#define IMX296_WDSEL_MULTI_2 (1 << 0)
+#define IMX296_WDSEL_MULTI_4 (3 << 0)
+#define IMX296_BLKLEVELAUTO IMX296_REG_8BIT(0x3022)
+#define IMX296_BLKLEVELAUTO_ON 0x01
+#define IMX296_BLKLEVELAUTO_OFF 0xf0
+#define IMX296_SST IMX296_REG_8BIT(0x3024)
+#define IMX296_SST_EN BIT(0)
+#define IMX296_CTRLTOUT IMX296_REG_8BIT(0x3026)
+#define IMX296_CTRLTOUT_TOUT1SEL_LOW (0 << 0)
+#define IMX296_CTRLTOUT_TOUT1SEL_PULSE (3 << 0)
+#define IMX296_CTRLTOUT_TOUT2SEL_LOW (0 << 2)
+#define IMX296_CTRLTOUT_TOUT2SEL_PULSE (3 << 2)
+#define IMX296_CTRLTRIG IMX296_REG_8BIT(0x3029)
+#define IMX296_CTRLTRIG_TOUT1_SEL_LOW (0 << 0)
+#define IMX296_CTRLTRIG_TOUT1_SEL_PULSE1 (1 << 0)
+#define IMX296_CTRLTRIG_TOUT2_SEL_LOW (0 << 4)
+#define IMX296_CTRLTRIG_TOUT2_SEL_PULSE2 (2 << 4)
+#define IMX296_SYNCSEL IMX296_REG_8BIT(0x3036)
+#define IMX296_SYNCSEL_NORMAL 0xc0
+#define IMX296_SYNCSEL_HIZ 0xf0
+#define IMX296_PULSE1 IMX296_REG_8BIT(0x306d)
+#define IMX296_PULSE1_EN_NOR BIT(0)
+#define IMX296_PULSE1_EN_TRIG BIT(1)
+#define IMX296_PULSE1_POL_HIGH (0 << 2)
+#define IMX296_PULSE1_POL_LOW (1 << 2)
+#define IMX296_PULSE1_UP IMX296_REG_24BIT(0x3070)
+#define IMX296_PULSE1_DN IMX296_REG_24BIT(0x3074)
+#define IMX296_PULSE2 IMX296_REG_8BIT(0x3079)
+#define IMX296_PULSE2_EN_NOR BIT(0)
+#define IMX296_PULSE2_EN_TRIG BIT(1)
+#define IMX296_PULSE2_POL_HIGH (0 << 2)
+#define IMX296_PULSE2_POL_LOW (1 << 2)
+#define IMX296_PULSE2_UP IMX296_REG_24BIT(0x307c)
+#define IMX296_PULSE2_DN IMX296_REG_24BIT(0x3080)
+#define IMX296_INCKSEL(n) IMX296_REG_8BIT(0x3089 + (n))
+#define IMX296_SHS1 IMX296_REG_24BIT(0x308d)
+#define IMX296_SHS2 IMX296_REG_24BIT(0x3090)
+#define IMX296_SHS3 IMX296_REG_24BIT(0x3094)
+#define IMX296_SHS4 IMX296_REG_24BIT(0x3098)
+#define IMX296_VBLANKLP IMX296_REG_8BIT(0x309c)
+#define IMX296_VBLANKLP_NORMAL 0x04
+#define IMX296_VBLANKLP_LOW_POWER 0x2c
+#define IMX296_EXP_CNT IMX296_REG_8BIT(0x30a3)
+#define IMX296_EXP_CNT_RESET BIT(0)
+#define IMX296_EXP_MAX IMX296_REG_16BIT(0x30a6)
+#define IMX296_VINT IMX296_REG_8BIT(0x30aa)
+#define IMX296_VINT_EN BIT(0)
+#define IMX296_LOWLAGTRG IMX296_REG_8BIT(0x30ae)
+#define IMX296_LOWLAGTRG_FAST BIT(0)
+#define IMX296_I2CCTRL IMX296_REG_8BIT(0x30ef)
+#define IMX296_I2CCTRL_I2CACKEN BIT(0)
+
+#define IMX296_SENSOR_INFO IMX296_REG_16BIT(0x3148)
+#define IMX296_SENSOR_INFO_MONO BIT(15)
+#define IMX296_SENSOR_INFO_IMX296LQ 0x4a00
+#define IMX296_SENSOR_INFO_IMX296LL 0xca00
+#define IMX296_S_SHSA IMX296_REG_16BIT(0x31ca)
+#define IMX296_S_SHSB IMX296_REG_16BIT(0x31d2)
+/*
+ * Registers 0x31c8 to 0x31cd, 0x31d0 to 0x31d5, 0x31e2, 0x31e3, 0x31ea and
+ * 0x31eb are related to exposure mode but otherwise not documented.
+ */
+
+#define IMX296_GAINCTRL IMX296_REG_8BIT(0x3200)
+#define IMX296_GAINCTRL_WD_GAIN_MODE_NORMAL 0x01
+#define IMX296_GAINCTRL_WD_GAIN_MODE_MULTI 0x41
+#define IMX296_GAIN IMX296_REG_16BIT(0x3204)
+#define IMX296_GAIN_MIN 0
+#define IMX296_GAIN_MAX 480
+#define IMX296_GAIN1 IMX296_REG_16BIT(0x3208)
+#define IMX296_GAIN2 IMX296_REG_16BIT(0x320c)
+#define IMX296_GAIN3 IMX296_REG_16BIT(0x3210)
+#define IMX296_GAINDLY IMX296_REG_8BIT(0x3212)
+#define IMX296_GAINDLY_NONE 0x08
+#define IMX296_GAINDLY_1FRAME 0x09
+#define IMX296_PGCTRL IMX296_REG_8BIT(0x3238)
+#define IMX296_PGCTRL_REGEN BIT(0)
+#define IMX296_PGCTRL_THRU BIT(1)
+#define IMX296_PGCTRL_CLKEN BIT(2)
+#define IMX296_PGCTRL_MODE(n) ((n) << 3)
+#define IMX296_PGHPOS IMX296_REG_16BIT(0x3239)
+#define IMX296_PGVPOS IMX296_REG_16BIT(0x323c)
+#define IMX296_PGHPSTEP IMX296_REG_8BIT(0x323e)
+#define IMX296_PGVPSTEP IMX296_REG_8BIT(0x323f)
+#define IMX296_PGHPNUM IMX296_REG_8BIT(0x3240)
+#define IMX296_PGVPNUM IMX296_REG_8BIT(0x3241)
+#define IMX296_PGDATA1 IMX296_REG_16BIT(0x3244)
+#define IMX296_PGDATA2 IMX296_REG_16BIT(0x3246)
+#define IMX296_PGHGSTEP IMX296_REG_8BIT(0x3249)
+#define IMX296_BLKLEVEL IMX296_REG_16BIT(0x3254)
+
+#define IMX296_FID0_ROI IMX296_REG_8BIT(0x3300)
+#define IMX296_FID0_ROIH1ON BIT(0)
+#define IMX296_FID0_ROIV1ON BIT(1)
+#define IMX296_FID0_ROIPH1 IMX296_REG_16BIT(0x3310)
+#define IMX296_FID0_ROIPV1 IMX296_REG_16BIT(0x3312)
+#define IMX296_FID0_ROIWH1 IMX296_REG_16BIT(0x3314)
+#define IMX296_FID0_ROIWH1_MIN 80
+#define IMX296_FID0_ROIWV1 IMX296_REG_16BIT(0x3316)
+#define IMX296_FID0_ROIWV1_MIN 4
+
+#define IMX296_CM_HSST_STARTTMG IMX296_REG_16BIT(0x4018)
+#define IMX296_CM_HSST_ENDTMG IMX296_REG_16BIT(0x401a)
+#define IMX296_DA_HSST_STARTTMG IMX296_REG_16BIT(0x404d)
+#define IMX296_DA_HSST_ENDTMG IMX296_REG_16BIT(0x4050)
+#define IMX296_LM_HSST_STARTTMG IMX296_REG_16BIT(0x4094)
+#define IMX296_LM_HSST_ENDTMG IMX296_REG_16BIT(0x4096)
+#define IMX296_SST_SIEASTA1_SET IMX296_REG_8BIT(0x40c9)
+#define IMX296_SST_SIEASTA1PRE_1U IMX296_REG_16BIT(0x40cc)
+#define IMX296_SST_SIEASTA1PRE_1D IMX296_REG_16BIT(0x40ce)
+#define IMX296_SST_SIEASTA1PRE_2U IMX296_REG_16BIT(0x40d0)
+#define IMX296_SST_SIEASTA1PRE_2D IMX296_REG_16BIT(0x40d2)
+#define IMX296_HSST IMX296_REG_8BIT(0x40dc)
+#define IMX296_HSST_EN BIT(2)
+
+#define IMX296_CKREQSEL IMX296_REG_8BIT(0x4101)
+#define IMX296_CKREQSEL_HS BIT(2)
+#define IMX296_GTTABLENUM IMX296_REG_8BIT(0x4114)
+#define IMX296_CTRL418C IMX296_REG_8BIT(0x418c)
+
+struct imx296_clk_params {
+ unsigned int freq;
+ u8 incksel[4];
+ u8 ctrl418c;
+};
+
+static const struct imx296_clk_params imx296_clk_params[] = {
+ { 37125000, { 0x80, 0x0b, 0x80, 0x08 }, 116 },
+ { 54000000, { 0xb0, 0x0f, 0xb0, 0x0c }, 168 },
+ { 74250000, { 0x80, 0x0f, 0x80, 0x0c }, 232 },
+};
+
+static const char * const imx296_supply_names[] = {
+ "dvdd",
+ "ovdd",
+ "avdd",
+};
+
+struct imx296 {
+ struct device *dev;
+ struct clk *clk;
+ struct regulator_bulk_data supplies[ARRAY_SIZE(imx296_supply_names)];
+ struct gpio_desc *reset;
+ struct regmap *regmap;
+
+ const struct imx296_clk_params *clk_params;
+ bool mono;
+
+ bool streaming;
+
+ struct v4l2_subdev subdev;
+ struct media_pad pad;
+
+ struct v4l2_ctrl_handler ctrls;
+ struct v4l2_ctrl *hblank;
+ struct v4l2_ctrl *vblank;
+};
+
+static inline struct imx296 *to_imx296(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct imx296, subdev);
+}
+
+static int imx296_read(struct imx296 *sensor, u32 addr)
+{
+ u8 data[3] = { 0, 0, 0 };
+ int ret;
+
+ ret = regmap_raw_read(sensor->regmap, addr & IMX296_REG_ADDR_MASK, data,
+ (addr >> IMX296_REG_SIZE_SHIFT) & 3);
+ if (ret < 0)
+ return ret;
+
+ return (data[2] << 16) | (data[1] << 8) | data[0];
+}
+
+static int imx296_write(struct imx296 *sensor, u32 addr, u32 value, int *err)
+{
+ u8 data[3] = { value & 0xff, (value >> 8) & 0xff, value >> 16 };
+ int ret;
+
+ if (err && *err)
+ return *err;
+
+ ret = regmap_raw_write(sensor->regmap, addr & IMX296_REG_ADDR_MASK,
+ data, (addr >> IMX296_REG_SIZE_SHIFT) & 3);
+ if (ret < 0) {
+ dev_err(sensor->dev, "%u-bit write to 0x%04x failed: %d\n",
+ ((addr >> IMX296_REG_SIZE_SHIFT) & 3) * 8,
+ addr & IMX296_REG_ADDR_MASK, ret);
+ if (err)
+ *err = ret;
+ }
+
+ return ret;
+}
+
+static int imx296_power_on(struct imx296 *sensor)
+{
+ int ret;
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(sensor->supplies),
+ sensor->supplies);
+ if (ret < 0)
+ return ret;
+
+ udelay(1);
+
+ ret = gpiod_direction_output(sensor->reset, 0);
+ if (ret < 0)
+ goto err_supply;
+
+ udelay(1);
+
+ ret = clk_prepare_enable(sensor->clk);
+ if (ret < 0)
+ goto err_reset;
+
+ /*
+ * The documentation doesn't explicitly say how much time is required
+ * after providing a clock and before starting I2C communication. It
+ * mentions a delay of 20µs in 4-wire mode, but tests showed that a
+ * delay of 100µs resulted in I2C communication failures, while 500µs
+ * seems to be enough. Be conservative.
+ */
+ usleep_range(1000, 2000);
+
+ return 0;
+
+err_reset:
+ gpiod_direction_output(sensor->reset, 1);
+err_supply:
+ regulator_bulk_disable(ARRAY_SIZE(sensor->supplies), sensor->supplies);
+ return ret;
+}
+
+static void imx296_power_off(struct imx296 *sensor)
+{
+ clk_disable_unprepare(sensor->clk);
+ gpiod_direction_output(sensor->reset, 1);
+ regulator_bulk_disable(ARRAY_SIZE(sensor->supplies), sensor->supplies);
+}
+
+/* -----------------------------------------------------------------------------
+ * Controls
+ */
+
+static const char * const imx296_test_pattern_menu[] = {
+ "Disabled",
+ "Multiple Pixels",
+ "Sequence 1",
+ "Sequence 2",
+ "Gradient",
+ "Row",
+ "Column",
+ "Cross",
+ "Stripe",
+ "Checks",
+};
+
+static int imx296_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct imx296 *sensor = container_of(ctrl->handler, struct imx296, ctrls);
+ const struct v4l2_mbus_framefmt *format;
+ struct v4l2_subdev_state *state;
+ unsigned int vmax;
+ int ret = 0;
+
+ if (!sensor->streaming)
+ return 0;
+
+ state = v4l2_subdev_get_locked_active_state(&sensor->subdev);
+ format = v4l2_subdev_get_pad_format(&sensor->subdev, state, 0);
+
+ switch (ctrl->id) {
+ case V4L2_CID_EXPOSURE:
+ /* Clamp the exposure value to VMAX. */
+ vmax = format->height + sensor->vblank->cur.val;
+ ctrl->val = min_t(int, ctrl->val, vmax);
+ imx296_write(sensor, IMX296_SHS1, vmax - ctrl->val, &ret);
+ break;
+
+ case V4L2_CID_ANALOGUE_GAIN:
+ imx296_write(sensor, IMX296_GAIN, ctrl->val, &ret);
+ break;
+
+ case V4L2_CID_VBLANK:
+ imx296_write(sensor, IMX296_VMAX, format->height + ctrl->val,
+ &ret);
+ break;
+
+ case V4L2_CID_TEST_PATTERN:
+ if (ctrl->val) {
+ imx296_write(sensor, IMX296_PGHPOS, 8, &ret);
+ imx296_write(sensor, IMX296_PGVPOS, 8, &ret);
+ imx296_write(sensor, IMX296_PGHPSTEP, 8, &ret);
+ imx296_write(sensor, IMX296_PGVPSTEP, 8, &ret);
+ imx296_write(sensor, IMX296_PGHPNUM, 100, &ret);
+ imx296_write(sensor, IMX296_PGVPNUM, 100, &ret);
+ imx296_write(sensor, IMX296_PGDATA1, 0x300, &ret);
+ imx296_write(sensor, IMX296_PGDATA2, 0x100, &ret);
+ imx296_write(sensor, IMX296_PGHGSTEP, 0, &ret);
+ imx296_write(sensor, IMX296_BLKLEVEL, 0, &ret);
+ imx296_write(sensor, IMX296_BLKLEVELAUTO,
+ IMX296_BLKLEVELAUTO_OFF, &ret);
+ imx296_write(sensor, IMX296_PGCTRL,
+ IMX296_PGCTRL_REGEN |
+ IMX296_PGCTRL_CLKEN |
+ IMX296_PGCTRL_MODE(ctrl->val - 1), &ret);
+ } else {
+ imx296_write(sensor, IMX296_PGCTRL,
+ IMX296_PGCTRL_CLKEN, &ret);
+ imx296_write(sensor, IMX296_BLKLEVEL, 0x3c, &ret);
+ imx296_write(sensor, IMX296_BLKLEVELAUTO,
+ IMX296_BLKLEVELAUTO_ON, &ret);
+ }
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops imx296_ctrl_ops = {
+ .s_ctrl = imx296_s_ctrl,
+};
+
+static int imx296_ctrls_init(struct imx296 *sensor)
+{
+ struct v4l2_fwnode_device_properties props;
+ unsigned int hblank;
+ int ret;
+
+ ret = v4l2_fwnode_device_parse(sensor->dev, &props);
+ if (ret < 0)
+ return ret;
+
+ v4l2_ctrl_handler_init(&sensor->ctrls, 9);
+
+ v4l2_ctrl_new_std(&sensor->ctrls, &imx296_ctrl_ops,
+ V4L2_CID_EXPOSURE, 1, 1048575, 1, 1104);
+ v4l2_ctrl_new_std(&sensor->ctrls, &imx296_ctrl_ops,
+ V4L2_CID_ANALOGUE_GAIN, IMX296_GAIN_MIN,
+ IMX296_GAIN_MAX, 1, IMX296_GAIN_MIN);
+
+ /*
+ * Horizontal blanking is controlled through the HMAX register, which
+ * contains a line length in INCK clock units. The INCK frequency is
+ * fixed to 74.25 MHz. The HMAX value is currently fixed to 1100,
+ * convert it to a number of pixels based on the nominal pixel rate.
+ */
+ hblank = 1100 * 1188000000ULL / 10 / 74250000
+ - IMX296_PIXEL_ARRAY_WIDTH;
+ sensor->hblank = v4l2_ctrl_new_std(&sensor->ctrls, &imx296_ctrl_ops,
+ V4L2_CID_HBLANK, hblank, hblank, 1,
+ hblank);
+ if (sensor->hblank)
+ sensor->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ sensor->vblank = v4l2_ctrl_new_std(&sensor->ctrls, &imx296_ctrl_ops,
+ V4L2_CID_VBLANK, 30,
+ 1048575 - IMX296_PIXEL_ARRAY_HEIGHT,
+ 1, 30);
+ /*
+ * The sensor calculates the MIPI timings internally to achieve a bit
+ * rate between 1122 and 1198 Mbps. The exact value is unfortunately not
+ * reported, at least according to the documentation. Report a nominal
+ * rate of 1188 Mbps as that is used by the datasheet in multiple
+ * examples.
+ */
+ v4l2_ctrl_new_std(&sensor->ctrls, NULL, V4L2_CID_PIXEL_RATE,
+ 1122000000 / 10, 1198000000 / 10, 1, 1188000000 / 10);
+ v4l2_ctrl_new_std_menu_items(&sensor->ctrls, &imx296_ctrl_ops,
+ V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(imx296_test_pattern_menu) - 1,
+ 0, 0, imx296_test_pattern_menu);
+
+ v4l2_ctrl_new_fwnode_properties(&sensor->ctrls, &imx296_ctrl_ops,
+ &props);
+
+ if (sensor->ctrls.error) {
+ dev_err(sensor->dev, "failed to add controls (%d)\n",
+ sensor->ctrls.error);
+ v4l2_ctrl_handler_free(&sensor->ctrls);
+ return sensor->ctrls.error;
+ }
+
+ sensor->subdev.ctrl_handler = &sensor->ctrls;
+
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 Subdev Operations
+ */
+
+/*
+ * This table is extracted from vendor data that is entirely undocumented. The
+ * first register write is required to activate the CSI-2 output. The other
+ * entries may or may not be optional?
+ */
+static const struct {
+ unsigned int reg;
+ unsigned int value;
+} imx296_init_table[] = {
+ { IMX296_REG_8BIT(0x3005), 0xf0 },
+ { IMX296_REG_8BIT(0x309e), 0x04 },
+ { IMX296_REG_8BIT(0x30a0), 0x04 },
+ { IMX296_REG_8BIT(0x30a1), 0x3c },
+ { IMX296_REG_8BIT(0x30a4), 0x5f },
+ { IMX296_REG_8BIT(0x30a8), 0x91 },
+ { IMX296_REG_8BIT(0x30ac), 0x28 },
+ { IMX296_REG_8BIT(0x30af), 0x09 },
+ { IMX296_REG_8BIT(0x30df), 0x00 },
+ { IMX296_REG_8BIT(0x3165), 0x00 },
+ { IMX296_REG_8BIT(0x3169), 0x10 },
+ { IMX296_REG_8BIT(0x316a), 0x02 },
+ { IMX296_REG_8BIT(0x31c8), 0xf3 }, /* Exposure-related */
+ { IMX296_REG_8BIT(0x31d0), 0xf4 }, /* Exposure-related */
+ { IMX296_REG_8BIT(0x321a), 0x00 },
+ { IMX296_REG_8BIT(0x3226), 0x02 },
+ { IMX296_REG_8BIT(0x3256), 0x01 },
+ { IMX296_REG_8BIT(0x3541), 0x72 },
+ { IMX296_REG_8BIT(0x3516), 0x77 },
+ { IMX296_REG_8BIT(0x350b), 0x7f },
+ { IMX296_REG_8BIT(0x3758), 0xa3 },
+ { IMX296_REG_8BIT(0x3759), 0x00 },
+ { IMX296_REG_8BIT(0x375a), 0x85 },
+ { IMX296_REG_8BIT(0x375b), 0x00 },
+ { IMX296_REG_8BIT(0x3832), 0xf5 },
+ { IMX296_REG_8BIT(0x3833), 0x00 },
+ { IMX296_REG_8BIT(0x38a2), 0xf6 },
+ { IMX296_REG_8BIT(0x38a3), 0x00 },
+ { IMX296_REG_8BIT(0x3a00), 0x80 },
+ { IMX296_REG_8BIT(0x3d48), 0xa3 },
+ { IMX296_REG_8BIT(0x3d49), 0x00 },
+ { IMX296_REG_8BIT(0x3d4a), 0x85 },
+ { IMX296_REG_8BIT(0x3d4b), 0x00 },
+ { IMX296_REG_8BIT(0x400e), 0x58 },
+ { IMX296_REG_8BIT(0x4014), 0x1c },
+ { IMX296_REG_8BIT(0x4041), 0x2a },
+ { IMX296_REG_8BIT(0x40a2), 0x06 },
+ { IMX296_REG_8BIT(0x40c1), 0xf6 },
+ { IMX296_REG_8BIT(0x40c7), 0x0f },
+ { IMX296_REG_8BIT(0x40c8), 0x00 },
+ { IMX296_REG_8BIT(0x4174), 0x00 },
+};
+
+static int imx296_setup(struct imx296 *sensor, struct v4l2_subdev_state *state)
+{
+ const struct v4l2_mbus_framefmt *format;
+ const struct v4l2_rect *crop;
+ unsigned int i;
+ int ret = 0;
+
+ format = v4l2_subdev_get_pad_format(&sensor->subdev, state, 0);
+ crop = v4l2_subdev_get_pad_crop(&sensor->subdev, state, 0);
+
+ for (i = 0; i < ARRAY_SIZE(imx296_init_table); ++i)
+ imx296_write(sensor, imx296_init_table[i].reg,
+ imx296_init_table[i].value, &ret);
+
+ if (crop->width != IMX296_PIXEL_ARRAY_WIDTH ||
+ crop->height != IMX296_PIXEL_ARRAY_HEIGHT) {
+ imx296_write(sensor, IMX296_FID0_ROI,
+ IMX296_FID0_ROIH1ON | IMX296_FID0_ROIV1ON, &ret);
+ imx296_write(sensor, IMX296_FID0_ROIPH1, crop->left, &ret);
+ imx296_write(sensor, IMX296_FID0_ROIPV1, crop->top, &ret);
+ imx296_write(sensor, IMX296_FID0_ROIWH1, crop->width, &ret);
+ imx296_write(sensor, IMX296_FID0_ROIWV1, crop->height, &ret);
+ } else {
+ imx296_write(sensor, IMX296_FID0_ROI, 0, &ret);
+ }
+
+ imx296_write(sensor, IMX296_CTRL0D,
+ (crop->width != format->width ?
+ IMX296_CTRL0D_HADD_ON_BINNING : 0) |
+ (crop->height != format->height ?
+ IMX296_CTRL0D_WINMODE_FD_BINNING : 0),
+ &ret);
+
+ /*
+ * HMAX and VMAX configure horizontal and vertical blanking by
+ * specifying the total line time and frame time respectively. The line
+ * time is specified in operational clock units (which appears to be the
+ * output of an internal PLL, fixed at 74.25 MHz regardless of the
+ * exernal clock frequency), while the frame time is specified as a
+ * number of lines.
+ *
+ * In the vertical direction the sensor outputs the following:
+ *
+ * - one line for the FS packet
+ * - two lines of embedded data (DT 0x12)
+ * - six null lines (DT 0x10)
+ * - four lines of vertical effective optical black (DT 0x37)
+ * - 8 to 1088 lines of active image data (RAW10, DT 0x2b)
+ * - one line for the FE packet
+ * - 16 or more lines of vertical blanking
+ */
+ imx296_write(sensor, IMX296_HMAX, 1100, &ret);
+ imx296_write(sensor, IMX296_VMAX,
+ format->height + sensor->vblank->cur.val, &ret);
+
+ for (i = 0; i < ARRAY_SIZE(sensor->clk_params->incksel); ++i)
+ imx296_write(sensor, IMX296_INCKSEL(i),
+ sensor->clk_params->incksel[i], &ret);
+ imx296_write(sensor, IMX296_GTTABLENUM, 0xc5, &ret);
+ imx296_write(sensor, IMX296_CTRL418C, sensor->clk_params->ctrl418c,
+ &ret);
+
+ imx296_write(sensor, IMX296_GAINDLY, IMX296_GAINDLY_NONE, &ret);
+ imx296_write(sensor, IMX296_BLKLEVEL, 0x03c, &ret);
+
+ return ret;
+}
+
+static int imx296_stream_on(struct imx296 *sensor)
+{
+ int ret = 0;
+
+ imx296_write(sensor, IMX296_CTRL00, 0, &ret);
+ usleep_range(2000, 5000);
+ imx296_write(sensor, IMX296_CTRL0A, 0, &ret);
+
+ return ret;
+}
+
+static int imx296_stream_off(struct imx296 *sensor)
+{
+ int ret = 0;
+
+ imx296_write(sensor, IMX296_CTRL0A, IMX296_CTRL0A_XMSTA, &ret);
+ imx296_write(sensor, IMX296_CTRL00, IMX296_CTRL00_STANDBY, &ret);
+
+ return ret;
+}
+
+static int imx296_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct imx296 *sensor = to_imx296(sd);
+ struct v4l2_subdev_state *state;
+ int ret;
+
+ state = v4l2_subdev_lock_and_get_active_state(sd);
+
+ if (!enable) {
+ ret = imx296_stream_off(sensor);
+
+ pm_runtime_mark_last_busy(sensor->dev);
+ pm_runtime_put_autosuspend(sensor->dev);
+
+ sensor->streaming = false;
+
+ goto unlock;
+ }
+
+ ret = pm_runtime_resume_and_get(sensor->dev);
+ if (ret < 0)
+ goto unlock;
+
+ ret = imx296_setup(sensor, state);
+ if (ret < 0)
+ goto err_pm;
+
+ /*
+ * Set streaming to true to ensure __v4l2_ctrl_handler_setup() will set
+ * the controls. The flag is reset to false further down if an error
+ * occurs.
+ */
+ sensor->streaming = true;
+
+ ret = __v4l2_ctrl_handler_setup(&sensor->ctrls);
+ if (ret < 0)
+ goto err_pm;
+
+ ret = imx296_stream_on(sensor);
+ if (ret)
+ goto err_pm;
+
+unlock:
+ v4l2_subdev_unlock_state(state);
+
+ return ret;
+
+err_pm:
+ /*
+ * In case of error, turn the power off synchronously as the device
+ * likely has no other chance to recover.
+ */
+ pm_runtime_put_sync(sensor->dev);
+ sensor->streaming = false;
+
+ goto unlock;
+}
+
+static int imx296_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ struct imx296 *sensor = to_imx296(sd);
+
+ if (code->index != 0)
+ return -EINVAL;
+
+ code->code = sensor->mono ? MEDIA_BUS_FMT_Y10_1X10
+ : MEDIA_BUS_FMT_SBGGR10_1X10;
+
+ return 0;
+}
+
+static int imx296_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ const struct v4l2_mbus_framefmt *format;
+
+ format = v4l2_subdev_get_pad_format(sd, state, fse->pad);
+
+ if (fse->index >= 2 || fse->code != format->code)
+ return -EINVAL;
+
+ fse->min_width = IMX296_PIXEL_ARRAY_WIDTH / (fse->index + 1);
+ fse->max_width = fse->min_width;
+ fse->min_height = IMX296_PIXEL_ARRAY_HEIGHT / (fse->index + 1);
+ fse->max_height = fse->min_height;
+
+ return 0;
+}
+
+static int imx296_get_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *fmt)
+{
+ fmt->format = *v4l2_subdev_get_pad_format(sd, state, fmt->pad);
+
+ return 0;
+}
+
+static int imx296_set_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *fmt)
+{
+ struct imx296 *sensor = to_imx296(sd);
+ struct v4l2_mbus_framefmt *format;
+ struct v4l2_rect *crop;
+
+ crop = v4l2_subdev_get_pad_crop(sd, state, fmt->pad);
+ format = v4l2_subdev_get_pad_format(sd, state, fmt->pad);
+
+ /*
+ * Binning is only allowed when cropping is disabled according to the
+ * documentation. This should be double-checked.
+ */
+ if (crop->width == IMX296_PIXEL_ARRAY_WIDTH &&
+ crop->height == IMX296_PIXEL_ARRAY_HEIGHT) {
+ unsigned int width;
+ unsigned int height;
+ unsigned int hratio;
+ unsigned int vratio;
+
+ /* Clamp the width and height to avoid dividing by zero. */
+ width = clamp_t(unsigned int, fmt->format.width,
+ crop->width / 2, crop->width);
+ height = clamp_t(unsigned int, fmt->format.height,
+ crop->height / 2, crop->height);
+
+ hratio = DIV_ROUND_CLOSEST(crop->width, width);
+ vratio = DIV_ROUND_CLOSEST(crop->height, height);
+
+ format->width = crop->width / hratio;
+ format->height = crop->height / vratio;
+ } else {
+ format->width = crop->width;
+ format->height = crop->height;
+ }
+
+ format->code = sensor->mono ? MEDIA_BUS_FMT_Y10_1X10
+ : MEDIA_BUS_FMT_SBGGR10_1X10;
+ format->field = V4L2_FIELD_NONE;
+ format->colorspace = V4L2_COLORSPACE_RAW;
+ format->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ format->quantization = V4L2_QUANTIZATION_FULL_RANGE;
+ format->xfer_func = V4L2_XFER_FUNC_NONE;
+
+ fmt->format = *format;
+
+ return 0;
+}
+
+static int imx296_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_selection *sel)
+{
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP:
+ sel->r = *v4l2_subdev_get_pad_crop(sd, state, sel->pad);
+ break;
+
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ case V4L2_SEL_TGT_NATIVE_SIZE:
+ sel->r.left = 0;
+ sel->r.top = 0;
+ sel->r.width = IMX296_PIXEL_ARRAY_WIDTH;
+ sel->r.height = IMX296_PIXEL_ARRAY_HEIGHT;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int imx296_set_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_selection *sel)
+{
+ struct v4l2_mbus_framefmt *format;
+ struct v4l2_rect *crop;
+ struct v4l2_rect rect;
+
+ if (sel->target != V4L2_SEL_TGT_CROP)
+ return -EINVAL;
+
+ /*
+ * Clamp the crop rectangle boundaries and align them to a multiple of 4
+ * pixels to satisfy hardware requirements.
+ */
+ rect.left = clamp(ALIGN(sel->r.left, 4), 0,
+ IMX296_PIXEL_ARRAY_WIDTH - IMX296_FID0_ROIWH1_MIN);
+ rect.top = clamp(ALIGN(sel->r.top, 4), 0,
+ IMX296_PIXEL_ARRAY_HEIGHT - IMX296_FID0_ROIWV1_MIN);
+ rect.width = clamp_t(unsigned int, ALIGN(sel->r.width, 4),
+ IMX296_FID0_ROIWH1_MIN, IMX296_PIXEL_ARRAY_WIDTH);
+ rect.height = clamp_t(unsigned int, ALIGN(sel->r.height, 4),
+ IMX296_FID0_ROIWV1_MIN, IMX296_PIXEL_ARRAY_HEIGHT);
+
+ rect.width = min_t(unsigned int, rect.width,
+ IMX296_PIXEL_ARRAY_WIDTH - rect.left);
+ rect.height = min_t(unsigned int, rect.height,
+ IMX296_PIXEL_ARRAY_HEIGHT - rect.top);
+
+ crop = v4l2_subdev_get_pad_crop(sd, state, sel->pad);
+
+ if (rect.width != crop->width || rect.height != crop->height) {
+ /*
+ * Reset the output image size if the crop rectangle size has
+ * been modified.
+ */
+ format = v4l2_subdev_get_pad_format(sd, state, sel->pad);
+ format->width = rect.width;
+ format->height = rect.height;
+ }
+
+ *crop = rect;
+ sel->r = rect;
+
+ return 0;
+}
+
+static int imx296_init_cfg(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ struct v4l2_subdev_selection sel = {
+ .target = V4L2_SEL_TGT_CROP,
+ .r.width = IMX296_PIXEL_ARRAY_WIDTH,
+ .r.height = IMX296_PIXEL_ARRAY_HEIGHT,
+ };
+ struct v4l2_subdev_format format = {
+ .format = {
+ .width = IMX296_PIXEL_ARRAY_WIDTH,
+ .height = IMX296_PIXEL_ARRAY_HEIGHT,
+ },
+ };
+
+ imx296_set_selection(sd, state, &sel);
+ imx296_set_format(sd, state, &format);
+
+ return 0;
+}
+
+static const struct v4l2_subdev_video_ops imx296_subdev_video_ops = {
+ .s_stream = imx296_s_stream,
+};
+
+static const struct v4l2_subdev_pad_ops imx296_subdev_pad_ops = {
+ .enum_mbus_code = imx296_enum_mbus_code,
+ .enum_frame_size = imx296_enum_frame_size,
+ .get_fmt = imx296_get_format,
+ .set_fmt = imx296_set_format,
+ .get_selection = imx296_get_selection,
+ .set_selection = imx296_set_selection,
+ .init_cfg = imx296_init_cfg,
+};
+
+static const struct v4l2_subdev_ops imx296_subdev_ops = {
+ .video = &imx296_subdev_video_ops,
+ .pad = &imx296_subdev_pad_ops,
+};
+
+static int imx296_subdev_init(struct imx296 *sensor)
+{
+ struct i2c_client *client = to_i2c_client(sensor->dev);
+ int ret;
+
+ v4l2_i2c_subdev_init(&sensor->subdev, client, &imx296_subdev_ops);
+
+ ret = imx296_ctrls_init(sensor);
+ if (ret < 0)
+ return ret;
+
+ sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
+ sensor->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+ ret = media_entity_pads_init(&sensor->subdev.entity, 1, &sensor->pad);
+ if (ret < 0) {
+ v4l2_ctrl_handler_free(&sensor->ctrls);
+ return ret;
+ }
+
+ sensor->subdev.state_lock = sensor->subdev.ctrl_handler->lock;
+
+ v4l2_subdev_init_finalize(&sensor->subdev);
+
+ return ret;
+}
+
+static void imx296_subdev_cleanup(struct imx296 *sensor)
+{
+ media_entity_cleanup(&sensor->subdev.entity);
+ v4l2_ctrl_handler_free(&sensor->ctrls);
+}
+
+/* -----------------------------------------------------------------------------
+ * Power management
+ */
+
+static int __maybe_unused imx296_runtime_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+ struct imx296 *sensor = to_imx296(subdev);
+
+ return imx296_power_on(sensor);
+}
+
+static int __maybe_unused imx296_runtime_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+ struct imx296 *sensor = to_imx296(subdev);
+
+ imx296_power_off(sensor);
+
+ return 0;
+}
+
+static const struct dev_pm_ops imx296_pm_ops = {
+ SET_RUNTIME_PM_OPS(imx296_runtime_suspend, imx296_runtime_resume, NULL)
+};
+
+/* -----------------------------------------------------------------------------
+ * Probe & Remove
+ */
+
+static int imx296_read_temperature(struct imx296 *sensor, int *temp)
+{
+ int tmdout;
+ int ret;
+
+ ret = imx296_write(sensor, IMX296_TMDCTRL, IMX296_TMDCTRL_LATCH, NULL);
+ if (ret < 0)
+ return ret;
+
+ tmdout = imx296_read(sensor, IMX296_TMDOUT) & IMX296_TMDOUT_MASK;
+ if (tmdout < 0)
+ return tmdout;
+
+ /* T(°C) = 246.312 - 0.304 * TMDOUT */;
+ *temp = 246312 - 304 * tmdout;
+
+ return imx296_write(sensor, IMX296_TMDCTRL, 0, NULL);
+}
+
+static int imx296_identify_model(struct imx296 *sensor)
+{
+ unsigned int model;
+ int temp = 0;
+ int ret;
+
+ model = (uintptr_t)of_device_get_match_data(sensor->dev);
+ if (model) {
+ dev_dbg(sensor->dev,
+ "sensor model auto-detection disabled, forcing 0x%04x\n",
+ model);
+ sensor->mono = model & IMX296_SENSOR_INFO_MONO;
+ return 0;
+ }
+
+ /*
+ * While most registers can be read when the sensor is in standby, this
+ * is not the case of the sensor info register :-(
+ */
+ ret = imx296_write(sensor, IMX296_CTRL00, 0, NULL);
+ if (ret < 0) {
+ dev_err(sensor->dev,
+ "failed to get sensor out of standby (%d)\n", ret);
+ return ret;
+ }
+
+ ret = imx296_read(sensor, IMX296_SENSOR_INFO);
+ if (ret < 0) {
+ dev_err(sensor->dev, "failed to read sensor information (%d)\n",
+ ret);
+ goto done;
+ }
+
+ model = (ret >> 6) & 0x1ff;
+
+ switch (model) {
+ case 296:
+ sensor->mono = ret & IMX296_SENSOR_INFO_MONO;
+ break;
+ /*
+ * The IMX297 seems to share features with the IMX296, it may be
+ * possible to support it in the same driver.
+ */
+ case 297:
+ default:
+ dev_err(sensor->dev, "invalid device model 0x%04x\n", ret);
+ ret = -ENODEV;
+ goto done;
+ }
+
+ ret = imx296_read_temperature(sensor, &temp);
+ if (ret < 0)
+ goto done;
+
+ dev_info(sensor->dev, "found IMX%u%s (%u.%uC)\n", model,
+ sensor->mono ? "LL" : "LQ", temp / 1000, (temp / 100) % 10);
+
+done:
+ imx296_write(sensor, IMX296_CTRL00, IMX296_CTRL00_STANDBY, NULL);
+ return ret;
+}
+
+static const struct regmap_config imx296_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+
+ .wr_table = &(const struct regmap_access_table) {
+ .no_ranges = (const struct regmap_range[]) {
+ {
+ .range_min = IMX296_SENSOR_INFO & 0xffff,
+ .range_max = (IMX296_SENSOR_INFO & 0xffff) + 1,
+ },
+ },
+ .n_no_ranges = 1,
+ },
+};
+
+static int imx296_probe(struct i2c_client *client)
+{
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ unsigned long clk_rate;
+ struct imx296 *sensor;
+ unsigned int i;
+ int ret;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+ dev_warn(&adapter->dev,
+ "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE\n");
+ return -EIO;
+ }
+
+ sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL);
+ if (!sensor)
+ return -ENOMEM;
+
+ sensor->dev = &client->dev;
+
+ /* Acquire resources. */
+ for (i = 0; i < ARRAY_SIZE(sensor->supplies); ++i)
+ sensor->supplies[i].supply = imx296_supply_names[i];
+
+ ret = devm_regulator_bulk_get(sensor->dev, ARRAY_SIZE(sensor->supplies),
+ sensor->supplies);
+ if (ret) {
+ dev_err_probe(sensor->dev, ret, "failed to get supplies\n");
+ return ret;
+ }
+
+ sensor->reset = devm_gpiod_get_optional(sensor->dev, "reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(sensor->reset))
+ return dev_err_probe(sensor->dev, PTR_ERR(sensor->reset),
+ "failed to get reset GPIO\n");
+
+ sensor->clk = devm_clk_get(sensor->dev, "inck");
+ if (IS_ERR(sensor->clk))
+ return dev_err_probe(sensor->dev, PTR_ERR(sensor->clk),
+ "failed to get clock\n");
+
+ clk_rate = clk_get_rate(sensor->clk);
+ for (i = 0; i < ARRAY_SIZE(imx296_clk_params); ++i) {
+ if (clk_rate == imx296_clk_params[i].freq) {
+ sensor->clk_params = &imx296_clk_params[i];
+ break;
+ }
+ }
+
+ if (!sensor->clk_params) {
+ dev_err(sensor->dev, "unsupported clock rate %lu\n", clk_rate);
+ return -EINVAL;
+ }
+
+ sensor->regmap = devm_regmap_init_i2c(client, &imx296_regmap_config);
+ if (IS_ERR(sensor->regmap))
+ return PTR_ERR(sensor->regmap);
+
+ /*
+ * Enable power management. The driver supports runtime PM, but needs to
+ * work when runtime PM is disabled in the kernel. To that end, power
+ * the sensor on manually here, identify it, and fully initialize it.
+ */
+ ret = imx296_power_on(sensor);
+ if (ret < 0)
+ return ret;
+
+ ret = imx296_identify_model(sensor);
+ if (ret < 0)
+ goto err_power;
+
+ /* Initialize the V4L2 subdev. */
+ ret = imx296_subdev_init(sensor);
+ if (ret < 0)
+ goto err_power;
+
+ /*
+ * Enable runtime PM. As the device has been powered manually, mark it
+ * as active, and increase the usage count without resuming the device.
+ */
+ pm_runtime_set_active(sensor->dev);
+ pm_runtime_get_noresume(sensor->dev);
+ pm_runtime_enable(sensor->dev);
+
+ /* Register the V4L2 subdev. */
+ ret = v4l2_async_register_subdev(&sensor->subdev);
+ if (ret < 0)
+ goto err_pm;
+
+ /*
+ * Finally, enable autosuspend and decrease the usage count. The device
+ * will get suspended after the autosuspend delay, turning the power
+ * off.
+ */
+ pm_runtime_set_autosuspend_delay(sensor->dev, 1000);
+ pm_runtime_use_autosuspend(sensor->dev);
+ pm_runtime_put_autosuspend(sensor->dev);
+
+ return 0;
+
+err_pm:
+ pm_runtime_disable(sensor->dev);
+ pm_runtime_put_noidle(sensor->dev);
+ imx296_subdev_cleanup(sensor);
+err_power:
+ imx296_power_off(sensor);
+ return ret;
+}
+
+static void imx296_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+ struct imx296 *sensor = to_imx296(subdev);
+
+ v4l2_async_unregister_subdev(subdev);
+
+ imx296_subdev_cleanup(sensor);
+
+ /*
+ * Disable runtime PM. In case runtime PM is disabled in the kernel,
+ * make sure to turn power off manually.
+ */
+ pm_runtime_disable(sensor->dev);
+ if (!pm_runtime_status_suspended(sensor->dev))
+ imx296_power_off(sensor);
+ pm_runtime_set_suspended(sensor->dev);
+}
+
+static const struct of_device_id imx296_of_match[] = {
+ { .compatible = "sony,imx296", .data = NULL },
+ { .compatible = "sony,imx296ll", .data = (void *)IMX296_SENSOR_INFO_IMX296LL },
+ { .compatible = "sony,imx296lq", .data = (void *)IMX296_SENSOR_INFO_IMX296LQ },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, imx296_of_match);
+
+static struct i2c_driver imx296_i2c_driver = {
+ .driver = {
+ .of_match_table = imx296_of_match,
+ .name = "imx296",
+ .pm = &imx296_pm_ops
+ },
+ .probe_new = imx296_probe,
+ .remove = imx296_remove,
+};
+
+module_i2c_driver(imx296_i2c_driver);
+
+MODULE_DESCRIPTION("Sony IMX296 Camera driver");
+MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/imx415.c b/drivers/media/i2c/imx415.c
new file mode 100644
index 000000000000..d90392df98c7
--- /dev/null
+++ b/drivers/media/i2c/imx415.c
@@ -0,0 +1,1300 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Driver for the Sony IMX415 CMOS Image Sensor.
+ *
+ * Copyright (C) 2023 WolfVision GmbH.
+ */
+
+#include <linux/clk.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-subdev.h>
+
+#define IMX415_PIXEL_ARRAY_TOP 0
+#define IMX415_PIXEL_ARRAY_LEFT 0
+#define IMX415_PIXEL_ARRAY_WIDTH 3864
+#define IMX415_PIXEL_ARRAY_HEIGHT 2192
+#define IMX415_PIXEL_ARRAY_VBLANK 58
+
+#define IMX415_NUM_CLK_PARAM_REGS 11
+
+#define IMX415_REG_8BIT(n) ((1 << 16) | (n))
+#define IMX415_REG_16BIT(n) ((2 << 16) | (n))
+#define IMX415_REG_24BIT(n) ((3 << 16) | (n))
+#define IMX415_REG_SIZE_SHIFT 16
+#define IMX415_REG_ADDR_MASK 0xffff
+
+#define IMX415_MODE IMX415_REG_8BIT(0x3000)
+#define IMX415_MODE_OPERATING (0)
+#define IMX415_MODE_STANDBY BIT(0)
+#define IMX415_REGHOLD IMX415_REG_8BIT(0x3001)
+#define IMX415_REGHOLD_INVALID (0)
+#define IMX415_REGHOLD_VALID BIT(0)
+#define IMX415_XMSTA IMX415_REG_8BIT(0x3002)
+#define IMX415_XMSTA_START (0)
+#define IMX415_XMSTA_STOP BIT(0)
+#define IMX415_BCWAIT_TIME IMX415_REG_16BIT(0x3008)
+#define IMX415_CPWAIT_TIME IMX415_REG_16BIT(0x300A)
+#define IMX415_WINMODE IMX415_REG_8BIT(0x301C)
+#define IMX415_ADDMODE IMX415_REG_8BIT(0x3022)
+#define IMX415_REVERSE IMX415_REG_8BIT(0x3030)
+#define IMX415_HREVERSE_SHIFT (0)
+#define IMX415_VREVERSE_SHIFT BIT(0)
+#define IMX415_ADBIT IMX415_REG_8BIT(0x3031)
+#define IMX415_MDBIT IMX415_REG_8BIT(0x3032)
+#define IMX415_SYS_MODE IMX415_REG_8BIT(0x3033)
+#define IMX415_OUTSEL IMX415_REG_8BIT(0x30C0)
+#define IMX415_DRV IMX415_REG_8BIT(0x30C1)
+#define IMX415_VMAX IMX415_REG_24BIT(0x3024)
+#define IMX415_HMAX IMX415_REG_16BIT(0x3028)
+#define IMX415_SHR0 IMX415_REG_24BIT(0x3050)
+#define IMX415_GAIN_PCG_0 IMX415_REG_16BIT(0x3090)
+#define IMX415_AGAIN_MIN 0
+#define IMX415_AGAIN_MAX 100
+#define IMX415_AGAIN_STEP 1
+#define IMX415_BLKLEVEL IMX415_REG_16BIT(0x30E2)
+#define IMX415_BLKLEVEL_DEFAULT 50
+#define IMX415_TPG_EN_DUOUT IMX415_REG_8BIT(0x30E4)
+#define IMX415_TPG_PATSEL_DUOUT IMX415_REG_8BIT(0x30E6)
+#define IMX415_TPG_COLORWIDTH IMX415_REG_8BIT(0x30E8)
+#define IMX415_TESTCLKEN_MIPI IMX415_REG_8BIT(0x3110)
+#define IMX415_INCKSEL1 IMX415_REG_8BIT(0x3115)
+#define IMX415_INCKSEL2 IMX415_REG_8BIT(0x3116)
+#define IMX415_INCKSEL3 IMX415_REG_16BIT(0x3118)
+#define IMX415_INCKSEL4 IMX415_REG_16BIT(0x311A)
+#define IMX415_INCKSEL5 IMX415_REG_8BIT(0x311E)
+#define IMX415_DIG_CLP_MODE IMX415_REG_8BIT(0x32C8)
+#define IMX415_WRJ_OPEN IMX415_REG_8BIT(0x3390)
+#define IMX415_SENSOR_INFO IMX415_REG_16BIT(0x3F12)
+#define IMX415_SENSOR_INFO_MASK 0xFFF
+#define IMX415_CHIP_ID 0x514
+#define IMX415_LANEMODE IMX415_REG_16BIT(0x4001)
+#define IMX415_LANEMODE_2 1
+#define IMX415_LANEMODE_4 3
+#define IMX415_TXCLKESC_FREQ IMX415_REG_16BIT(0x4004)
+#define IMX415_INCKSEL6 IMX415_REG_8BIT(0x400C)
+#define IMX415_TCLKPOST IMX415_REG_16BIT(0x4018)
+#define IMX415_TCLKPREPARE IMX415_REG_16BIT(0x401A)
+#define IMX415_TCLKTRAIL IMX415_REG_16BIT(0x401C)
+#define IMX415_TCLKZERO IMX415_REG_16BIT(0x401E)
+#define IMX415_THSPREPARE IMX415_REG_16BIT(0x4020)
+#define IMX415_THSZERO IMX415_REG_16BIT(0x4022)
+#define IMX415_THSTRAIL IMX415_REG_16BIT(0x4024)
+#define IMX415_THSEXIT IMX415_REG_16BIT(0x4026)
+#define IMX415_TLPX IMX415_REG_16BIT(0x4028)
+#define IMX415_INCKSEL7 IMX415_REG_8BIT(0x4074)
+
+struct imx415_reg {
+ u32 address;
+ u32 val;
+};
+
+static const char *const imx415_supply_names[] = {
+ "dvdd",
+ "ovdd",
+ "avdd",
+};
+
+/*
+ * The IMX415 data sheet uses lane rates but v4l2 uses link frequency to
+ * describe MIPI CSI-2 speed. This driver uses lane rates wherever possible
+ * and converts them to link frequencies by a factor of two when needed.
+ */
+static const s64 link_freq_menu_items[] = {
+ 594000000 / 2, 720000000 / 2, 891000000 / 2,
+ 1440000000 / 2, 1485000000 / 2,
+};
+
+struct imx415_clk_params {
+ u64 lane_rate;
+ u64 inck;
+ struct imx415_reg regs[IMX415_NUM_CLK_PARAM_REGS];
+};
+
+/* INCK Settings - includes all lane rate and INCK dependent registers */
+static const struct imx415_clk_params imx415_clk_params[] = {
+ {
+ .lane_rate = 594000000,
+ .inck = 27000000,
+ .regs[0] = { IMX415_BCWAIT_TIME, 0x05D },
+ .regs[1] = { IMX415_CPWAIT_TIME, 0x042 },
+ .regs[2] = { IMX415_SYS_MODE, 0x7 },
+ .regs[3] = { IMX415_INCKSEL1, 0x00 },
+ .regs[4] = { IMX415_INCKSEL2, 0x23 },
+ .regs[5] = { IMX415_INCKSEL3, 0x084 },
+ .regs[6] = { IMX415_INCKSEL4, 0x0E7 },
+ .regs[7] = { IMX415_INCKSEL5, 0x23 },
+ .regs[8] = { IMX415_INCKSEL6, 0x0 },
+ .regs[9] = { IMX415_INCKSEL7, 0x1 },
+ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x06C0 },
+ },
+ {
+ .lane_rate = 720000000,
+ .inck = 24000000,
+ .regs[0] = { IMX415_BCWAIT_TIME, 0x054 },
+ .regs[1] = { IMX415_CPWAIT_TIME, 0x03B },
+ .regs[2] = { IMX415_SYS_MODE, 0x9 },
+ .regs[3] = { IMX415_INCKSEL1, 0x00 },
+ .regs[4] = { IMX415_INCKSEL2, 0x23 },
+ .regs[5] = { IMX415_INCKSEL3, 0x0B4 },
+ .regs[6] = { IMX415_INCKSEL4, 0x0FC },
+ .regs[7] = { IMX415_INCKSEL5, 0x23 },
+ .regs[8] = { IMX415_INCKSEL6, 0x0 },
+ .regs[9] = { IMX415_INCKSEL7, 0x1 },
+ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x0600 },
+ },
+ {
+ .lane_rate = 891000000,
+ .inck = 27000000,
+ .regs[0] = { IMX415_BCWAIT_TIME, 0x05D },
+ .regs[1] = { IMX415_CPWAIT_TIME, 0x042 },
+ .regs[2] = { IMX415_SYS_MODE, 0x5 },
+ .regs[3] = { IMX415_INCKSEL1, 0x00 },
+ .regs[4] = { IMX415_INCKSEL2, 0x23 },
+ .regs[5] = { IMX415_INCKSEL3, 0x0C6 },
+ .regs[6] = { IMX415_INCKSEL4, 0x0E7 },
+ .regs[7] = { IMX415_INCKSEL5, 0x23 },
+ .regs[8] = { IMX415_INCKSEL6, 0x0 },
+ .regs[9] = { IMX415_INCKSEL7, 0x1 },
+ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x06C0 },
+ },
+ {
+ .lane_rate = 1440000000,
+ .inck = 24000000,
+ .regs[0] = { IMX415_BCWAIT_TIME, 0x054 },
+ .regs[1] = { IMX415_CPWAIT_TIME, 0x03B },
+ .regs[2] = { IMX415_SYS_MODE, 0x8 },
+ .regs[3] = { IMX415_INCKSEL1, 0x00 },
+ .regs[4] = { IMX415_INCKSEL2, 0x23 },
+ .regs[5] = { IMX415_INCKSEL3, 0x0B4 },
+ .regs[6] = { IMX415_INCKSEL4, 0x0FC },
+ .regs[7] = { IMX415_INCKSEL5, 0x23 },
+ .regs[8] = { IMX415_INCKSEL6, 0x1 },
+ .regs[9] = { IMX415_INCKSEL7, 0x0 },
+ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x0600 },
+ },
+ {
+ .lane_rate = 1485000000,
+ .inck = 27000000,
+ .regs[0] = { IMX415_BCWAIT_TIME, 0x05D },
+ .regs[1] = { IMX415_CPWAIT_TIME, 0x042 },
+ .regs[2] = { IMX415_SYS_MODE, 0x8 },
+ .regs[3] = { IMX415_INCKSEL1, 0x00 },
+ .regs[4] = { IMX415_INCKSEL2, 0x23 },
+ .regs[5] = { IMX415_INCKSEL3, 0x0A5 },
+ .regs[6] = { IMX415_INCKSEL4, 0x0E7 },
+ .regs[7] = { IMX415_INCKSEL5, 0x23 },
+ .regs[8] = { IMX415_INCKSEL6, 0x1 },
+ .regs[9] = { IMX415_INCKSEL7, 0x0 },
+ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x06C0 },
+ },
+};
+
+/* all-pixel 2-lane 720 Mbps 15.74 Hz mode */
+static const struct imx415_reg imx415_mode_2_720[] = {
+ { IMX415_VMAX, 0x08CA },
+ { IMX415_HMAX, 0x07F0 },
+ { IMX415_LANEMODE, IMX415_LANEMODE_2 },
+ { IMX415_TCLKPOST, 0x006F },
+ { IMX415_TCLKPREPARE, 0x002F },
+ { IMX415_TCLKTRAIL, 0x002F },
+ { IMX415_TCLKZERO, 0x00BF },
+ { IMX415_THSPREPARE, 0x002F },
+ { IMX415_THSZERO, 0x0057 },
+ { IMX415_THSTRAIL, 0x002F },
+ { IMX415_THSEXIT, 0x004F },
+ { IMX415_TLPX, 0x0027 },
+};
+
+/* all-pixel 2-lane 1440 Mbps 30.01 Hz mode */
+static const struct imx415_reg imx415_mode_2_1440[] = {
+ { IMX415_VMAX, 0x08CA },
+ { IMX415_HMAX, 0x042A },
+ { IMX415_LANEMODE, IMX415_LANEMODE_2 },
+ { IMX415_TCLKPOST, 0x009F },
+ { IMX415_TCLKPREPARE, 0x0057 },
+ { IMX415_TCLKTRAIL, 0x0057 },
+ { IMX415_TCLKZERO, 0x0187 },
+ { IMX415_THSPREPARE, 0x005F },
+ { IMX415_THSZERO, 0x00A7 },
+ { IMX415_THSTRAIL, 0x005F },
+ { IMX415_THSEXIT, 0x0097 },
+ { IMX415_TLPX, 0x004F },
+};
+
+/* all-pixel 4-lane 891 Mbps 30 Hz mode */
+static const struct imx415_reg imx415_mode_4_891[] = {
+ { IMX415_VMAX, 0x08CA },
+ { IMX415_HMAX, 0x044C },
+ { IMX415_LANEMODE, IMX415_LANEMODE_4 },
+ { IMX415_TCLKPOST, 0x007F },
+ { IMX415_TCLKPREPARE, 0x0037 },
+ { IMX415_TCLKTRAIL, 0x0037 },
+ { IMX415_TCLKZERO, 0x00F7 },
+ { IMX415_THSPREPARE, 0x003F },
+ { IMX415_THSZERO, 0x006F },
+ { IMX415_THSTRAIL, 0x003F },
+ { IMX415_THSEXIT, 0x005F },
+ { IMX415_TLPX, 0x002F },
+};
+
+struct imx415_mode_reg_list {
+ u32 num_of_regs;
+ const struct imx415_reg *regs;
+};
+
+/*
+ * Mode : number of lanes, lane rate and frame rate dependent settings
+ *
+ * pixel_rate and hmax_pix are needed to calculate hblank for the v4l2 ctrl
+ * interface. These values can not be found in the data sheet and should be
+ * treated as virtual values. Use following table when adding new modes.
+ *
+ * lane_rate lanes fps hmax_pix pixel_rate
+ *
+ * 594 2 10.000 4400 99000000
+ * 891 2 15.000 4400 148500000
+ * 720 2 15.748 4064 144000000
+ * 1782 2 30.000 4400 297000000
+ * 2079 2 30.000 4400 297000000
+ * 1440 2 30.019 4510 304615385
+ *
+ * 594 4 20.000 5500 247500000
+ * 594 4 25.000 4400 247500000
+ * 720 4 25.000 4400 247500000
+ * 720 4 30.019 4510 304615385
+ * 891 4 30.000 4400 297000000
+ * 1440 4 30.019 4510 304615385
+ * 1440 4 60.038 4510 609230769
+ * 1485 4 60.000 4400 594000000
+ * 1782 4 60.000 4400 594000000
+ * 2079 4 60.000 4400 594000000
+ * 2376 4 90.164 4392 891000000
+ */
+struct imx415_mode {
+ u64 lane_rate;
+ u32 lanes;
+ u32 hmax_pix;
+ u64 pixel_rate;
+ struct imx415_mode_reg_list reg_list;
+};
+
+/* mode configs */
+static const struct imx415_mode supported_modes[] = {
+ {
+ .lane_rate = 720000000,
+ .lanes = 2,
+ .hmax_pix = 4064,
+ .pixel_rate = 144000000,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(imx415_mode_2_720),
+ .regs = imx415_mode_2_720,
+ },
+ },
+ {
+ .lane_rate = 1440000000,
+ .lanes = 2,
+ .hmax_pix = 4510,
+ .pixel_rate = 304615385,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(imx415_mode_2_1440),
+ .regs = imx415_mode_2_1440,
+ },
+ },
+ {
+ .lane_rate = 891000000,
+ .lanes = 4,
+ .hmax_pix = 4400,
+ .pixel_rate = 297000000,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(imx415_mode_4_891),
+ .regs = imx415_mode_4_891,
+ },
+ },
+};
+
+static const struct regmap_config imx415_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+};
+
+static const char *const imx415_test_pattern_menu[] = {
+ "disabled",
+ "solid black",
+ "solid white",
+ "solid dark gray",
+ "solid light gray",
+ "stripes light/dark grey",
+ "stripes dark/light grey",
+ "stripes black/dark grey",
+ "stripes dark grey/black",
+ "stripes black/white",
+ "stripes white/black",
+ "horizontal color bar",
+ "vertical color bar",
+};
+
+struct imx415 {
+ struct device *dev;
+ struct clk *clk;
+ struct regulator_bulk_data supplies[ARRAY_SIZE(imx415_supply_names)];
+ struct gpio_desc *reset;
+ struct regmap *regmap;
+
+ const struct imx415_clk_params *clk_params;
+
+ bool streaming;
+
+ struct v4l2_subdev subdev;
+ struct media_pad pad;
+
+ struct v4l2_ctrl_handler ctrls;
+ struct v4l2_ctrl *vblank;
+ struct v4l2_ctrl *hflip;
+ struct v4l2_ctrl *vflip;
+
+ unsigned int cur_mode;
+ unsigned int num_data_lanes;
+};
+
+/*
+ * This table includes fixed register settings and a bunch of undocumented
+ * registers that have to be set to another value than default.
+ */
+static const struct imx415_reg imx415_init_table[] = {
+ /* use all-pixel readout mode, no flip */
+ { IMX415_WINMODE, 0x00 },
+ { IMX415_ADDMODE, 0x00 },
+ { IMX415_REVERSE, 0x00 },
+ /* use RAW 10-bit mode */
+ { IMX415_ADBIT, 0x00 },
+ { IMX415_MDBIT, 0x00 },
+ /* output VSYNC on XVS and low on XHS */
+ { IMX415_OUTSEL, 0x22 },
+ { IMX415_DRV, 0x00 },
+
+ /* SONY magic registers */
+ { IMX415_REG_8BIT(0x32D4), 0x21 },
+ { IMX415_REG_8BIT(0x32EC), 0xA1 },
+ { IMX415_REG_8BIT(0x3452), 0x7F },
+ { IMX415_REG_8BIT(0x3453), 0x03 },
+ { IMX415_REG_8BIT(0x358A), 0x04 },
+ { IMX415_REG_8BIT(0x35A1), 0x02 },
+ { IMX415_REG_8BIT(0x36BC), 0x0C },
+ { IMX415_REG_8BIT(0x36CC), 0x53 },
+ { IMX415_REG_8BIT(0x36CD), 0x00 },
+ { IMX415_REG_8BIT(0x36CE), 0x3C },
+ { IMX415_REG_8BIT(0x36D0), 0x8C },
+ { IMX415_REG_8BIT(0x36D1), 0x00 },
+ { IMX415_REG_8BIT(0x36D2), 0x71 },
+ { IMX415_REG_8BIT(0x36D4), 0x3C },
+ { IMX415_REG_8BIT(0x36D6), 0x53 },
+ { IMX415_REG_8BIT(0x36D7), 0x00 },
+ { IMX415_REG_8BIT(0x36D8), 0x71 },
+ { IMX415_REG_8BIT(0x36DA), 0x8C },
+ { IMX415_REG_8BIT(0x36DB), 0x00 },
+ { IMX415_REG_8BIT(0x3724), 0x02 },
+ { IMX415_REG_8BIT(0x3726), 0x02 },
+ { IMX415_REG_8BIT(0x3732), 0x02 },
+ { IMX415_REG_8BIT(0x3734), 0x03 },
+ { IMX415_REG_8BIT(0x3736), 0x03 },
+ { IMX415_REG_8BIT(0x3742), 0x03 },
+ { IMX415_REG_8BIT(0x3862), 0xE0 },
+ { IMX415_REG_8BIT(0x38CC), 0x30 },
+ { IMX415_REG_8BIT(0x38CD), 0x2F },
+ { IMX415_REG_8BIT(0x395C), 0x0C },
+ { IMX415_REG_8BIT(0x3A42), 0xD1 },
+ { IMX415_REG_8BIT(0x3A4C), 0x77 },
+ { IMX415_REG_8BIT(0x3AE0), 0x02 },
+ { IMX415_REG_8BIT(0x3AEC), 0x0C },
+ { IMX415_REG_8BIT(0x3B00), 0x2E },
+ { IMX415_REG_8BIT(0x3B06), 0x29 },
+ { IMX415_REG_8BIT(0x3B98), 0x25 },
+ { IMX415_REG_8BIT(0x3B99), 0x21 },
+ { IMX415_REG_8BIT(0x3B9B), 0x13 },
+ { IMX415_REG_8BIT(0x3B9C), 0x13 },
+ { IMX415_REG_8BIT(0x3B9D), 0x13 },
+ { IMX415_REG_8BIT(0x3B9E), 0x13 },
+ { IMX415_REG_8BIT(0x3BA1), 0x00 },
+ { IMX415_REG_8BIT(0x3BA2), 0x06 },
+ { IMX415_REG_8BIT(0x3BA3), 0x0B },
+ { IMX415_REG_8BIT(0x3BA4), 0x10 },
+ { IMX415_REG_8BIT(0x3BA5), 0x14 },
+ { IMX415_REG_8BIT(0x3BA6), 0x18 },
+ { IMX415_REG_8BIT(0x3BA7), 0x1A },
+ { IMX415_REG_8BIT(0x3BA8), 0x1A },
+ { IMX415_REG_8BIT(0x3BA9), 0x1A },
+ { IMX415_REG_8BIT(0x3BAC), 0xED },
+ { IMX415_REG_8BIT(0x3BAD), 0x01 },
+ { IMX415_REG_8BIT(0x3BAE), 0xF6 },
+ { IMX415_REG_8BIT(0x3BAF), 0x02 },
+ { IMX415_REG_8BIT(0x3BB0), 0xA2 },
+ { IMX415_REG_8BIT(0x3BB1), 0x03 },
+ { IMX415_REG_8BIT(0x3BB2), 0xE0 },
+ { IMX415_REG_8BIT(0x3BB3), 0x03 },
+ { IMX415_REG_8BIT(0x3BB4), 0xE0 },
+ { IMX415_REG_8BIT(0x3BB5), 0x03 },
+ { IMX415_REG_8BIT(0x3BB6), 0xE0 },
+ { IMX415_REG_8BIT(0x3BB7), 0x03 },
+ { IMX415_REG_8BIT(0x3BB8), 0xE0 },
+ { IMX415_REG_8BIT(0x3BBA), 0xE0 },
+ { IMX415_REG_8BIT(0x3BBC), 0xDA },
+ { IMX415_REG_8BIT(0x3BBE), 0x88 },
+ { IMX415_REG_8BIT(0x3BC0), 0x44 },
+ { IMX415_REG_8BIT(0x3BC2), 0x7B },
+ { IMX415_REG_8BIT(0x3BC4), 0xA2 },
+ { IMX415_REG_8BIT(0x3BC8), 0xBD },
+ { IMX415_REG_8BIT(0x3BCA), 0xBD },
+};
+
+static inline struct imx415 *to_imx415(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct imx415, subdev);
+}
+
+static int imx415_read(struct imx415 *sensor, u32 addr)
+{
+ u8 data[3] = { 0 };
+ int ret;
+
+ ret = regmap_raw_read(sensor->regmap, addr & IMX415_REG_ADDR_MASK, data,
+ (addr >> IMX415_REG_SIZE_SHIFT) & 3);
+ if (ret < 0)
+ return ret;
+
+ return (data[2] << 16) | (data[1] << 8) | data[0];
+}
+
+static int imx415_write(struct imx415 *sensor, u32 addr, u32 value)
+{
+ u8 data[3] = { value & 0xff, (value >> 8) & 0xff, value >> 16 };
+ int ret;
+
+ ret = regmap_raw_write(sensor->regmap, addr & IMX415_REG_ADDR_MASK,
+ data, (addr >> IMX415_REG_SIZE_SHIFT) & 3);
+ if (ret < 0)
+ dev_err_ratelimited(sensor->dev,
+ "%u-bit write to 0x%04x failed: %d\n",
+ ((addr >> IMX415_REG_SIZE_SHIFT) & 3) * 8,
+ addr & IMX415_REG_ADDR_MASK, ret);
+
+ return 0;
+}
+
+static int imx415_set_testpattern(struct imx415 *sensor, int val)
+{
+ int ret;
+
+ if (val) {
+ ret = imx415_write(sensor, IMX415_BLKLEVEL, 0x00);
+ if (ret)
+ return ret;
+ ret = imx415_write(sensor, IMX415_TPG_EN_DUOUT, 0x01);
+ if (ret)
+ return ret;
+ ret = imx415_write(sensor, IMX415_TPG_PATSEL_DUOUT, val - 1);
+ if (ret)
+ return ret;
+ ret = imx415_write(sensor, IMX415_TPG_COLORWIDTH, 0x01);
+ if (ret)
+ return ret;
+ ret = imx415_write(sensor, IMX415_TESTCLKEN_MIPI, 0x20);
+ if (ret)
+ return ret;
+ ret = imx415_write(sensor, IMX415_DIG_CLP_MODE, 0x00);
+ if (ret)
+ return ret;
+ ret = imx415_write(sensor, IMX415_WRJ_OPEN, 0x00);
+ } else {
+ ret = imx415_write(sensor, IMX415_BLKLEVEL,
+ IMX415_BLKLEVEL_DEFAULT);
+ if (ret)
+ return ret;
+ ret = imx415_write(sensor, IMX415_TPG_EN_DUOUT, 0x00);
+ if (ret)
+ return ret;
+ ret = imx415_write(sensor, IMX415_TESTCLKEN_MIPI, 0x00);
+ if (ret)
+ return ret;
+ ret = imx415_write(sensor, IMX415_DIG_CLP_MODE, 0x01);
+ if (ret)
+ return ret;
+ ret = imx415_write(sensor, IMX415_WRJ_OPEN, 0x01);
+ }
+ return 0;
+}
+
+static int imx415_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct imx415 *sensor = container_of(ctrl->handler, struct imx415,
+ ctrls);
+ const struct v4l2_mbus_framefmt *format;
+ struct v4l2_subdev_state *state;
+ unsigned int vmax;
+ unsigned int flip;
+
+ if (!sensor->streaming)
+ return 0;
+
+ state = v4l2_subdev_get_locked_active_state(&sensor->subdev);
+ format = v4l2_subdev_get_pad_format(&sensor->subdev, state, 0);
+
+ switch (ctrl->id) {
+ case V4L2_CID_EXPOSURE:
+ /* clamp the exposure value to VMAX. */
+ vmax = format->height + sensor->vblank->cur.val;
+ ctrl->val = min_t(int, ctrl->val, vmax);
+ return imx415_write(sensor, IMX415_SHR0, vmax - ctrl->val);
+
+ case V4L2_CID_ANALOGUE_GAIN:
+ /* analogue gain in 0.3 dB step size */
+ return imx415_write(sensor, IMX415_GAIN_PCG_0, ctrl->val);
+
+ case V4L2_CID_HFLIP:
+ case V4L2_CID_VFLIP:
+ flip = (sensor->hflip->val << IMX415_HREVERSE_SHIFT) |
+ (sensor->vflip->val << IMX415_VREVERSE_SHIFT);
+ return imx415_write(sensor, IMX415_REVERSE, flip);
+
+ case V4L2_CID_TEST_PATTERN:
+ return imx415_set_testpattern(sensor, ctrl->val);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct v4l2_ctrl_ops imx415_ctrl_ops = {
+ .s_ctrl = imx415_s_ctrl,
+};
+
+static int imx415_ctrls_init(struct imx415 *sensor)
+{
+ struct v4l2_fwnode_device_properties props;
+ struct v4l2_ctrl *ctrl;
+ u64 pixel_rate = supported_modes[sensor->cur_mode].pixel_rate;
+ u64 lane_rate = supported_modes[sensor->cur_mode].lane_rate;
+ u32 exposure_max = IMX415_PIXEL_ARRAY_HEIGHT +
+ IMX415_PIXEL_ARRAY_VBLANK - 8;
+ u32 hblank;
+ unsigned int i;
+ int ret;
+
+ ret = v4l2_fwnode_device_parse(sensor->dev, &props);
+ if (ret < 0)
+ return ret;
+
+ v4l2_ctrl_handler_init(&sensor->ctrls, 10);
+
+ for (i = 0; i < ARRAY_SIZE(link_freq_menu_items); ++i) {
+ if (lane_rate == link_freq_menu_items[i] * 2)
+ break;
+ }
+ if (i == ARRAY_SIZE(link_freq_menu_items)) {
+ return dev_err_probe(sensor->dev, -EINVAL,
+ "lane rate %llu not supported\n",
+ lane_rate);
+ }
+
+ ctrl = v4l2_ctrl_new_int_menu(&sensor->ctrls, &imx415_ctrl_ops,
+ V4L2_CID_LINK_FREQ,
+ ARRAY_SIZE(link_freq_menu_items) - 1, i,
+ link_freq_menu_items);
+
+ if (ctrl)
+ ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops, V4L2_CID_EXPOSURE,
+ 4, exposure_max, 1, exposure_max);
+
+ v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops,
+ V4L2_CID_ANALOGUE_GAIN, IMX415_AGAIN_MIN,
+ IMX415_AGAIN_MAX, IMX415_AGAIN_STEP,
+ IMX415_AGAIN_MIN);
+
+ hblank = supported_modes[sensor->cur_mode].hmax_pix -
+ IMX415_PIXEL_ARRAY_WIDTH;
+ ctrl = v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops,
+ V4L2_CID_HBLANK, hblank, hblank, 1, hblank);
+ if (ctrl)
+ ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ sensor->vblank = v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops,
+ V4L2_CID_VBLANK,
+ IMX415_PIXEL_ARRAY_VBLANK,
+ IMX415_PIXEL_ARRAY_VBLANK, 1,
+ IMX415_PIXEL_ARRAY_VBLANK);
+ if (sensor->vblank)
+ sensor->vblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ /*
+ * The pixel rate used here is a virtual value and can be used for
+ * calculating the frame rate together with hblank. It may not
+ * necessarily be the physically correct pixel clock.
+ */
+ v4l2_ctrl_new_std(&sensor->ctrls, NULL, V4L2_CID_PIXEL_RATE, pixel_rate,
+ pixel_rate, 1, pixel_rate);
+
+ sensor->hflip = v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ sensor->vflip = v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+ v4l2_ctrl_new_std_menu_items(&sensor->ctrls, &imx415_ctrl_ops,
+ V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(imx415_test_pattern_menu) - 1,
+ 0, 0, imx415_test_pattern_menu);
+
+ v4l2_ctrl_new_fwnode_properties(&sensor->ctrls, &imx415_ctrl_ops,
+ &props);
+
+ if (sensor->ctrls.error) {
+ dev_err_probe(sensor->dev, sensor->ctrls.error,
+ "failed to add controls\n");
+ v4l2_ctrl_handler_free(&sensor->ctrls);
+ return sensor->ctrls.error;
+ }
+ sensor->subdev.ctrl_handler = &sensor->ctrls;
+
+ return 0;
+}
+
+static int imx415_set_mode(struct imx415 *sensor, int mode)
+{
+ const struct imx415_reg *reg;
+ unsigned int i;
+ int ret = 0;
+
+ if (mode >= ARRAY_SIZE(supported_modes)) {
+ dev_err(sensor->dev, "Mode %d not supported\n", mode);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < supported_modes[mode].reg_list.num_of_regs; ++i) {
+ reg = &supported_modes[mode].reg_list.regs[i];
+ ret = imx415_write(sensor, reg->address, reg->val);
+ if (ret)
+ return ret;
+ }
+
+ for (i = 0; i < IMX415_NUM_CLK_PARAM_REGS; ++i) {
+ reg = &sensor->clk_params->regs[i];
+ ret = imx415_write(sensor, reg->address, reg->val);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int imx415_setup(struct imx415 *sensor, struct v4l2_subdev_state *state)
+{
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < ARRAY_SIZE(imx415_init_table); ++i) {
+ ret = imx415_write(sensor, imx415_init_table[i].address,
+ imx415_init_table[i].val);
+ if (ret)
+ return ret;
+ }
+
+ return imx415_set_mode(sensor, sensor->cur_mode);
+}
+
+static int imx415_wakeup(struct imx415 *sensor)
+{
+ int ret;
+
+ ret = imx415_write(sensor, IMX415_MODE, IMX415_MODE_OPERATING);
+ if (ret)
+ return ret;
+
+ /*
+ * According to the datasheet we have to wait at least 63 us after
+ * leaving standby mode. But this doesn't work even after 30 ms.
+ * So probably this should be 63 ms and therefore we wait for 80 ms.
+ */
+ msleep(80);
+
+ return 0;
+}
+
+static int imx415_stream_on(struct imx415 *sensor)
+{
+ int ret;
+
+ ret = imx415_wakeup(sensor);
+ if (ret)
+ return ret;
+
+ return imx415_write(sensor, IMX415_XMSTA, IMX415_XMSTA_START);
+}
+
+static int imx415_stream_off(struct imx415 *sensor)
+{
+ int ret;
+
+ ret = imx415_write(sensor, IMX415_XMSTA, IMX415_XMSTA_STOP);
+ if (ret)
+ return ret;
+
+ return imx415_write(sensor, IMX415_MODE, IMX415_MODE_STANDBY);
+}
+
+static int imx415_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct imx415 *sensor = to_imx415(sd);
+ struct v4l2_subdev_state *state;
+ int ret;
+
+ state = v4l2_subdev_lock_and_get_active_state(sd);
+
+ if (!enable) {
+ ret = imx415_stream_off(sensor);
+
+ pm_runtime_mark_last_busy(sensor->dev);
+ pm_runtime_put_autosuspend(sensor->dev);
+
+ sensor->streaming = false;
+
+ goto unlock;
+ }
+
+ ret = pm_runtime_resume_and_get(sensor->dev);
+ if (ret < 0)
+ goto unlock;
+
+ ret = imx415_setup(sensor, state);
+ if (ret)
+ goto err_pm;
+
+ /*
+ * Set streaming to true to ensure __v4l2_ctrl_handler_setup() will set
+ * the controls. The flag is reset to false further down if an error
+ * occurs.
+ */
+ sensor->streaming = true;
+
+ ret = __v4l2_ctrl_handler_setup(&sensor->ctrls);
+ if (ret < 0)
+ goto err_pm;
+
+ ret = imx415_stream_on(sensor);
+ if (ret)
+ goto err_pm;
+
+ ret = 0;
+
+unlock:
+ v4l2_subdev_unlock_state(state);
+
+ return ret;
+
+err_pm:
+ /*
+ * In case of error, turn the power off synchronously as the device
+ * likely has no other chance to recover.
+ */
+ pm_runtime_put_sync(sensor->dev);
+ sensor->streaming = false;
+
+ goto unlock;
+}
+
+static int imx415_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->index != 0)
+ return -EINVAL;
+
+ code->code = MEDIA_BUS_FMT_SGBRG10_1X10;
+
+ return 0;
+}
+
+static int imx415_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ const struct v4l2_mbus_framefmt *format;
+
+ format = v4l2_subdev_get_pad_format(sd, state, fse->pad);
+
+ if (fse->index > 0 || fse->code != format->code)
+ return -EINVAL;
+
+ fse->min_width = IMX415_PIXEL_ARRAY_WIDTH;
+ fse->max_width = fse->min_width;
+ fse->min_height = IMX415_PIXEL_ARRAY_HEIGHT;
+ fse->max_height = fse->min_height;
+ return 0;
+}
+
+static int imx415_get_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *fmt)
+{
+ fmt->format = *v4l2_subdev_get_pad_format(sd, state, fmt->pad);
+
+ return 0;
+}
+
+static int imx415_set_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *fmt)
+{
+ struct v4l2_mbus_framefmt *format;
+
+ format = v4l2_subdev_get_pad_format(sd, state, fmt->pad);
+
+ format->width = fmt->format.width;
+ format->height = fmt->format.height;
+ format->code = MEDIA_BUS_FMT_SGBRG10_1X10;
+ format->field = V4L2_FIELD_NONE;
+ format->colorspace = V4L2_COLORSPACE_RAW;
+ format->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ format->quantization = V4L2_QUANTIZATION_DEFAULT;
+ format->xfer_func = V4L2_XFER_FUNC_NONE;
+
+ fmt->format = *format;
+ return 0;
+}
+
+static int imx415_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_selection *sel)
+{
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP:
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ sel->r.top = IMX415_PIXEL_ARRAY_TOP;
+ sel->r.left = IMX415_PIXEL_ARRAY_LEFT;
+ sel->r.width = IMX415_PIXEL_ARRAY_WIDTH;
+ sel->r.height = IMX415_PIXEL_ARRAY_HEIGHT;
+
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int imx415_init_cfg(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ struct v4l2_subdev_format format = {
+ .format = {
+ .width = IMX415_PIXEL_ARRAY_WIDTH,
+ .height = IMX415_PIXEL_ARRAY_HEIGHT,
+ },
+ };
+
+ imx415_set_format(sd, state, &format);
+
+ return 0;
+}
+
+static const struct v4l2_subdev_video_ops imx415_subdev_video_ops = {
+ .s_stream = imx415_s_stream,
+};
+
+static const struct v4l2_subdev_pad_ops imx415_subdev_pad_ops = {
+ .enum_mbus_code = imx415_enum_mbus_code,
+ .enum_frame_size = imx415_enum_frame_size,
+ .get_fmt = imx415_get_format,
+ .set_fmt = imx415_set_format,
+ .get_selection = imx415_get_selection,
+ .init_cfg = imx415_init_cfg,
+};
+
+static const struct v4l2_subdev_ops imx415_subdev_ops = {
+ .video = &imx415_subdev_video_ops,
+ .pad = &imx415_subdev_pad_ops,
+};
+
+static int imx415_subdev_init(struct imx415 *sensor)
+{
+ struct i2c_client *client = to_i2c_client(sensor->dev);
+ int ret;
+
+ v4l2_i2c_subdev_init(&sensor->subdev, client, &imx415_subdev_ops);
+
+ ret = imx415_ctrls_init(sensor);
+ if (ret)
+ return ret;
+
+ sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
+ V4L2_SUBDEV_FL_HAS_EVENTS;
+ sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
+ sensor->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+ ret = media_entity_pads_init(&sensor->subdev.entity, 1, &sensor->pad);
+ if (ret < 0) {
+ v4l2_ctrl_handler_free(&sensor->ctrls);
+ return ret;
+ }
+
+ sensor->subdev.state_lock = sensor->subdev.ctrl_handler->lock;
+ v4l2_subdev_init_finalize(&sensor->subdev);
+
+ return 0;
+}
+
+static void imx415_subdev_cleanup(struct imx415 *sensor)
+{
+ media_entity_cleanup(&sensor->subdev.entity);
+ v4l2_ctrl_handler_free(&sensor->ctrls);
+}
+
+static int imx415_power_on(struct imx415 *sensor)
+{
+ int ret;
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(sensor->supplies),
+ sensor->supplies);
+ if (ret < 0)
+ return ret;
+
+ gpiod_set_value_cansleep(sensor->reset, 0);
+
+ udelay(1);
+
+ ret = clk_prepare_enable(sensor->clk);
+ if (ret < 0)
+ goto err_reset;
+
+ /*
+ * Data sheet states that 20 us are required before communication start,
+ * but this doesn't work in all cases. Use 100 us to be on the safe
+ * side.
+ */
+ usleep_range(100, 200);
+
+ return 0;
+
+err_reset:
+ gpiod_set_value_cansleep(sensor->reset, 1);
+ regulator_bulk_disable(ARRAY_SIZE(sensor->supplies), sensor->supplies);
+ return ret;
+}
+
+static void imx415_power_off(struct imx415 *sensor)
+{
+ clk_disable_unprepare(sensor->clk);
+ gpiod_set_value_cansleep(sensor->reset, 1);
+ regulator_bulk_disable(ARRAY_SIZE(sensor->supplies), sensor->supplies);
+}
+
+static int imx415_identify_model(struct imx415 *sensor)
+{
+ int model, ret;
+
+ /*
+ * While most registers can be read when the sensor is in standby, this
+ * is not the case of the sensor info register :-(
+ */
+ ret = imx415_wakeup(sensor);
+ if (ret)
+ return dev_err_probe(sensor->dev, ret,
+ "failed to get sensor out of standby\n");
+
+ ret = imx415_read(sensor, IMX415_SENSOR_INFO);
+ if (ret < 0) {
+ dev_err_probe(sensor->dev, ret,
+ "failed to read sensor information\n");
+ goto done;
+ }
+
+ model = ret & IMX415_SENSOR_INFO_MASK;
+
+ switch (model) {
+ case IMX415_CHIP_ID:
+ dev_info(sensor->dev, "Detected IMX415 image sensor\n");
+ break;
+ default:
+ ret = dev_err_probe(sensor->dev, -ENODEV,
+ "invalid device model 0x%04x\n", model);
+ goto done;
+ }
+
+ ret = 0;
+
+done:
+ imx415_write(sensor, IMX415_MODE, IMX415_MODE_STANDBY);
+ return ret;
+}
+
+static int imx415_check_inck(unsigned long inck, u64 link_frequency)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(imx415_clk_params); ++i) {
+ if ((imx415_clk_params[i].lane_rate == link_frequency * 2) &&
+ imx415_clk_params[i].inck == inck)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(imx415_clk_params))
+ return -EINVAL;
+ else
+ return 0;
+}
+
+static int imx415_parse_hw_config(struct imx415 *sensor)
+{
+ struct v4l2_fwnode_endpoint bus_cfg = {
+ .bus_type = V4L2_MBUS_CSI2_DPHY,
+ };
+ struct fwnode_handle *ep;
+ u64 lane_rate;
+ unsigned long inck;
+ unsigned int i, j;
+ int ret;
+
+ for (i = 0; i < ARRAY_SIZE(sensor->supplies); ++i)
+ sensor->supplies[i].supply = imx415_supply_names[i];
+
+ ret = devm_regulator_bulk_get(sensor->dev, ARRAY_SIZE(sensor->supplies),
+ sensor->supplies);
+ if (ret)
+ return dev_err_probe(sensor->dev, ret,
+ "failed to get supplies\n");
+
+ sensor->reset = devm_gpiod_get_optional(sensor->dev, "reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(sensor->reset))
+ return dev_err_probe(sensor->dev, PTR_ERR(sensor->reset),
+ "failed to get reset GPIO\n");
+
+ sensor->clk = devm_clk_get(sensor->dev, "inck");
+ if (IS_ERR(sensor->clk))
+ return dev_err_probe(sensor->dev, PTR_ERR(sensor->clk),
+ "failed to get clock\n");
+
+ ep = fwnode_graph_get_next_endpoint(dev_fwnode(sensor->dev), NULL);
+ if (!ep)
+ return -ENXIO;
+
+ ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);
+ fwnode_handle_put(ep);
+ if (ret)
+ return ret;
+
+ switch (bus_cfg.bus.mipi_csi2.num_data_lanes) {
+ case 2:
+ case 4:
+ sensor->num_data_lanes = bus_cfg.bus.mipi_csi2.num_data_lanes;
+ break;
+ default:
+ ret = dev_err_probe(sensor->dev, -EINVAL,
+ "invalid number of CSI2 data lanes %d\n",
+ bus_cfg.bus.mipi_csi2.num_data_lanes);
+ goto done_endpoint_free;
+ }
+
+ if (!bus_cfg.nr_of_link_frequencies) {
+ ret = dev_err_probe(sensor->dev, -EINVAL,
+ "no link frequencies defined");
+ goto done_endpoint_free;
+ }
+
+ /*
+ * Check if there exists a sensor mode defined for current INCK,
+ * number of lanes and given lane rates.
+ */
+ inck = clk_get_rate(sensor->clk);
+ for (i = 0; i < bus_cfg.nr_of_link_frequencies; ++i) {
+ if (imx415_check_inck(inck, bus_cfg.link_frequencies[i])) {
+ dev_dbg(sensor->dev,
+ "INCK %lu Hz not supported for this link freq",
+ inck);
+ continue;
+ }
+
+ for (j = 0; j < ARRAY_SIZE(supported_modes); ++j) {
+ if (sensor->num_data_lanes != supported_modes[j].lanes)
+ continue;
+ if (bus_cfg.link_frequencies[i] * 2 !=
+ supported_modes[j].lane_rate)
+ continue;
+ sensor->cur_mode = j;
+ break;
+ }
+ if (j < ARRAY_SIZE(supported_modes))
+ break;
+ }
+ if (i == bus_cfg.nr_of_link_frequencies) {
+ ret = dev_err_probe(sensor->dev, -EINVAL,
+ "no valid sensor mode defined\n");
+ goto done_endpoint_free;
+ }
+
+ lane_rate = supported_modes[sensor->cur_mode].lane_rate;
+ for (i = 0; i < ARRAY_SIZE(imx415_clk_params); ++i) {
+ if (lane_rate == imx415_clk_params[i].lane_rate &&
+ inck == imx415_clk_params[i].inck) {
+ sensor->clk_params = &imx415_clk_params[i];
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(imx415_clk_params)) {
+ ret = dev_err_probe(sensor->dev, -EINVAL,
+ "Mode %d not supported\n",
+ sensor->cur_mode);
+ goto done_endpoint_free;
+ }
+
+ ret = 0;
+ dev_dbg(sensor->dev, "clock: %lu Hz, lane_rate: %llu bps, lanes: %d\n",
+ inck, lane_rate, sensor->num_data_lanes);
+
+done_endpoint_free:
+ v4l2_fwnode_endpoint_free(&bus_cfg);
+
+ return ret;
+}
+
+static int imx415_probe(struct i2c_client *client)
+{
+ struct imx415 *sensor;
+ int ret;
+
+ sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL);
+ if (!sensor)
+ return -ENOMEM;
+
+ sensor->dev = &client->dev;
+
+ ret = imx415_parse_hw_config(sensor);
+ if (ret)
+ return ret;
+
+ sensor->regmap = devm_regmap_init_i2c(client, &imx415_regmap_config);
+ if (IS_ERR(sensor->regmap))
+ return PTR_ERR(sensor->regmap);
+
+ /*
+ * Enable power management. The driver supports runtime PM, but needs to
+ * work when runtime PM is disabled in the kernel. To that end, power
+ * the sensor on manually here, identify it, and fully initialize it.
+ */
+ ret = imx415_power_on(sensor);
+ if (ret)
+ return ret;
+
+ ret = imx415_identify_model(sensor);
+ if (ret)
+ goto err_power;
+
+ ret = imx415_subdev_init(sensor);
+ if (ret)
+ goto err_power;
+
+ /*
+ * Enable runtime PM. As the device has been powered manually, mark it
+ * as active, and increase the usage count without resuming the device.
+ */
+ pm_runtime_set_active(sensor->dev);
+ pm_runtime_get_noresume(sensor->dev);
+ pm_runtime_enable(sensor->dev);
+
+ ret = v4l2_async_register_subdev_sensor(&sensor->subdev);
+ if (ret < 0)
+ goto err_pm;
+
+ /*
+ * Finally, enable autosuspend and decrease the usage count. The device
+ * will get suspended after the autosuspend delay, turning the power
+ * off.
+ */
+ pm_runtime_set_autosuspend_delay(sensor->dev, 1000);
+ pm_runtime_use_autosuspend(sensor->dev);
+ pm_runtime_put_autosuspend(sensor->dev);
+
+ return 0;
+
+err_pm:
+ pm_runtime_disable(sensor->dev);
+ pm_runtime_put_noidle(sensor->dev);
+ imx415_subdev_cleanup(sensor);
+err_power:
+ imx415_power_off(sensor);
+ return ret;
+}
+
+static void imx415_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+ struct imx415 *sensor = to_imx415(subdev);
+
+ v4l2_async_unregister_subdev(subdev);
+
+ imx415_subdev_cleanup(sensor);
+
+ /*
+ * Disable runtime PM. In case runtime PM is disabled in the kernel,
+ * make sure to turn power off manually.
+ */
+ pm_runtime_disable(sensor->dev);
+ if (!pm_runtime_status_suspended(sensor->dev))
+ imx415_power_off(sensor);
+ pm_runtime_set_suspended(sensor->dev);
+}
+
+static int imx415_runtime_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+ struct imx415 *sensor = to_imx415(subdev);
+
+ return imx415_power_on(sensor);
+}
+
+static int imx415_runtime_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+ struct imx415 *sensor = to_imx415(subdev);
+
+ imx415_power_off(sensor);
+
+ return 0;
+}
+
+static DEFINE_RUNTIME_DEV_PM_OPS(imx415_pm_ops, imx415_runtime_suspend,
+ imx415_runtime_resume, NULL);
+
+static const struct of_device_id imx415_of_match[] = {
+ { .compatible = "sony,imx415" },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, imx415_of_match);
+
+static struct i2c_driver imx415_driver = {
+ .probe_new = imx415_probe,
+ .remove = imx415_remove,
+ .driver = {
+ .name = "imx415",
+ .of_match_table = imx415_of_match,
+ .pm = pm_ptr(&imx415_pm_ops),
+ },
+};
+
+module_i2c_driver(imx415_driver);
+
+MODULE_DESCRIPTION("Sony IMX415 image sensor driver");
+MODULE_AUTHOR("Gerald Loacker <gerald.loacker@wolfvision.net>");
+MODULE_AUTHOR("Michael Riesch <michael.riesch@wolfvision.net>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c
index 25bf1132dbff..51921068931d 100644
--- a/drivers/media/i2c/ir-kbd-i2c.c
+++ b/drivers/media/i2c/ir-kbd-i2c.c
@@ -757,8 +757,9 @@ static int zilog_tx_duty_cycle(struct rc_dev *dev, u32 duty_cycle)
return 0;
}
-static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
+static int ir_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
char *ir_codes = NULL;
const char *name = NULL;
u64 rc_proto = RC_PROTO_BIT_UNKNOWN;
@@ -987,7 +988,7 @@ static struct i2c_driver ir_kbd_driver = {
.driver = {
.name = "ir-kbd-i2c",
},
- .probe = ir_probe,
+ .probe_new = ir_probe,
.remove = ir_remove,
.id_table = ir_kbd_id,
};
diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c
index 9c083cf14231..701038d6d19b 100644
--- a/drivers/media/i2c/max9286.c
+++ b/drivers/media/i2c/max9286.c
@@ -72,7 +72,7 @@
#define MAX9286_DATATYPE_USER_YUV_12BIT (10 << 0)
#define MAX9286_DATATYPE_USER_24BIT (9 << 0)
#define MAX9286_DATATYPE_RAW14 (8 << 0)
-#define MAX9286_DATATYPE_RAW11 (7 << 0)
+#define MAX9286_DATATYPE_RAW12 (7 << 0)
#define MAX9286_DATATYPE_RAW10 (6 << 0)
#define MAX9286_DATATYPE_RAW8 (5 << 0)
#define MAX9286_DATATYPE_YUV422_10BIT (4 << 0)
@@ -81,13 +81,21 @@
#define MAX9286_DATATYPE_RGB565 (1 << 0)
#define MAX9286_DATATYPE_RGB888 (0 << 0)
/* Register 0x15 */
+#define MAX9286_CSI_IMAGE_TYP BIT(7)
#define MAX9286_VC(n) ((n) << 5)
#define MAX9286_VCTYPE BIT(4)
#define MAX9286_CSIOUTEN BIT(3)
-#define MAX9286_0X15_RESV (3 << 0)
+#define MAX9286_SWP_ENDIAN BIT(2)
+#define MAX9286_EN_CCBSYB_CLK_STR BIT(1)
+#define MAX9286_EN_GPI_CCBSYB BIT(0)
/* Register 0x1b */
#define MAX9286_SWITCHIN(n) (1 << ((n) + 4))
#define MAX9286_ENEQ(n) (1 << (n))
+/* Register 0x1c */
+#define MAX9286_HIGHIMM(n) BIT((n) + 4)
+#define MAX9286_I2CSEL BIT(2)
+#define MAX9286_HIBW BIT(1)
+#define MAX9286_BWS BIT(0)
/* Register 0x27 */
#define MAX9286_LOCKED BIT(7)
/* Register 0x31 */
@@ -136,9 +144,20 @@
#define MAX9286_N_PADS 5
#define MAX9286_SRC_PAD 4
+struct max9286_format_info {
+ u32 code;
+ u8 datatype;
+};
+
+struct max9286_i2c_speed {
+ u32 rate;
+ u8 mstbt;
+};
+
struct max9286_source {
struct v4l2_subdev *sd;
struct fwnode_handle *fwnode;
+ struct regulator *regulator;
};
struct max9286_asd {
@@ -168,13 +187,18 @@ struct max9286_priv {
/* The initial reverse control channel amplitude. */
u32 init_rev_chan_mv;
u32 rev_chan_mv;
+ u8 i2c_mstbt;
+ u32 bus_width;
+ bool use_gpio_poc;
u32 gpio_poc[2];
struct v4l2_ctrl_handler ctrls;
- struct v4l2_ctrl *pixelrate;
+ struct v4l2_ctrl *pixelrate_ctrl;
+ unsigned int pixelrate;
struct v4l2_mbus_framefmt fmt[MAX9286_N_SINKS];
+ struct v4l2_fract interval;
/* Protects controls and fmt structures */
struct mutex mutex;
@@ -214,6 +238,45 @@ static inline struct max9286_priv *sd_to_max9286(struct v4l2_subdev *sd)
return container_of(sd, struct max9286_priv, sd);
}
+static const struct max9286_format_info max9286_formats[] = {
+ {
+ .code = MEDIA_BUS_FMT_UYVY8_1X16,
+ .datatype = MAX9286_DATATYPE_YUV422_8BIT,
+ }, {
+ .code = MEDIA_BUS_FMT_VYUY8_1X16,
+ .datatype = MAX9286_DATATYPE_YUV422_8BIT,
+ }, {
+ .code = MEDIA_BUS_FMT_YUYV8_1X16,
+ .datatype = MAX9286_DATATYPE_YUV422_8BIT,
+ }, {
+ .code = MEDIA_BUS_FMT_YVYU8_1X16,
+ .datatype = MAX9286_DATATYPE_YUV422_8BIT,
+ }, {
+ .code = MEDIA_BUS_FMT_SBGGR12_1X12,
+ .datatype = MAX9286_DATATYPE_RAW12,
+ }, {
+ .code = MEDIA_BUS_FMT_SGBRG12_1X12,
+ .datatype = MAX9286_DATATYPE_RAW12,
+ }, {
+ .code = MEDIA_BUS_FMT_SGRBG12_1X12,
+ .datatype = MAX9286_DATATYPE_RAW12,
+ }, {
+ .code = MEDIA_BUS_FMT_SRGGB12_1X12,
+ .datatype = MAX9286_DATATYPE_RAW12,
+ },
+};
+
+static const struct max9286_i2c_speed max9286_i2c_speeds[] = {
+ { .rate = 8470, .mstbt = MAX9286_I2CMSTBT_8KBPS },
+ { .rate = 28300, .mstbt = MAX9286_I2CMSTBT_28KBPS },
+ { .rate = 84700, .mstbt = MAX9286_I2CMSTBT_84KBPS },
+ { .rate = 105000, .mstbt = MAX9286_I2CMSTBT_105KBPS },
+ { .rate = 173000, .mstbt = MAX9286_I2CMSTBT_173KBPS },
+ { .rate = 339000, .mstbt = MAX9286_I2CMSTBT_339KBPS },
+ { .rate = 533000, .mstbt = MAX9286_I2CMSTBT_533KBPS },
+ { .rate = 837000, .mstbt = MAX9286_I2CMSTBT_837KBPS },
+};
+
/* -----------------------------------------------------------------------------
* I2C IO
*/
@@ -334,7 +397,7 @@ error:
static void max9286_configure_i2c(struct max9286_priv *priv, bool localack)
{
u8 config = MAX9286_I2CSLVSH_469NS_234NS | MAX9286_I2CSLVTO_1024US |
- MAX9286_I2CMSTBT_105KBPS;
+ priv->i2c_mstbt;
if (localack)
config |= MAX9286_I2CLOCACK;
@@ -475,6 +538,77 @@ static int max9286_check_config_link(struct max9286_priv *priv,
return 0;
}
+static void max9286_set_video_format(struct max9286_priv *priv,
+ const struct v4l2_mbus_framefmt *format)
+{
+ const struct max9286_format_info *info = NULL;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(max9286_formats); ++i) {
+ if (max9286_formats[i].code == format->code) {
+ info = &max9286_formats[i];
+ break;
+ }
+ }
+
+ if (WARN_ON(!info))
+ return;
+
+ /*
+ * Video format setup: disable CSI output, set VC according to Link
+ * number, enable I2C clock stretching when CCBSY is low, enable CCBSY
+ * in external GPI-to-GPO mode.
+ */
+ max9286_write(priv, 0x15, MAX9286_VCTYPE | MAX9286_EN_CCBSYB_CLK_STR |
+ MAX9286_EN_GPI_CCBSYB);
+
+ /* Enable CSI-2 Lane D0-D3 only, DBL mode. */
+ max9286_write(priv, 0x12, MAX9286_CSIDBL | MAX9286_DBL |
+ MAX9286_CSILANECNT(priv->csi2_data_lanes) |
+ info->datatype);
+
+ /*
+ * Enable HS/VS encoding, use HS as line valid source, use D14/15 for
+ * HS/VS, invert VS.
+ */
+ max9286_write(priv, 0x0c, MAX9286_HVEN | MAX9286_DESEL |
+ MAX9286_INVVS | MAX9286_HVSRC_D14);
+}
+
+static void max9286_set_fsync_period(struct max9286_priv *priv)
+{
+ u32 fsync;
+
+ if (!priv->interval.numerator || !priv->interval.denominator) {
+ /*
+ * Special case, a null interval enables automatic FRAMESYNC
+ * mode. FRAMESYNC is taken from the slowest link.
+ */
+ max9286_write(priv, 0x01, MAX9286_FSYNCMODE_INT_HIZ |
+ MAX9286_FSYNCMETH_AUTO);
+ return;
+ }
+
+ /*
+ * Manual FRAMESYNC
+ *
+ * The FRAMESYNC generator is configured with a period expressed as a
+ * number of PCLK periods.
+ */
+ fsync = div_u64((u64)priv->pixelrate * priv->interval.numerator,
+ priv->interval.denominator);
+
+ dev_dbg(&priv->client->dev, "fsync period %u (pclk %u)\n", fsync,
+ priv->pixelrate);
+
+ max9286_write(priv, 0x01, MAX9286_FSYNCMODE_INT_OUT |
+ MAX9286_FSYNCMETH_MANUAL);
+
+ max9286_write(priv, 0x06, (fsync >> 0) & 0xff);
+ max9286_write(priv, 0x07, (fsync >> 8) & 0xff);
+ max9286_write(priv, 0x08, (fsync >> 16) & 0xff);
+}
+
/* -----------------------------------------------------------------------------
* V4L2 Subdev
*/
@@ -513,11 +647,13 @@ static int max9286_set_pixelrate(struct max9286_priv *priv)
return -EINVAL;
}
+ priv->pixelrate = pixelrate;
+
/*
* The CSI-2 transmitter pixel rate is the single source rate multiplied
* by the number of available sources.
*/
- return v4l2_ctrl_s_ctrl_int64(priv->pixelrate,
+ return v4l2_ctrl_s_ctrl_int64(priv->pixelrate_ctrl,
pixelrate * priv->nsources);
}
@@ -657,6 +793,17 @@ static int max9286_s_stream(struct v4l2_subdev *sd, int enable)
int ret;
if (enable) {
+ const struct v4l2_mbus_framefmt *format;
+
+ /*
+ * Get the format from the first used sink pad, as all sink
+ * formats must be identical.
+ */
+ format = &priv->fmt[__ffs(priv->bound_sources)];
+
+ max9286_set_video_format(priv, format);
+ max9286_set_fsync_period(priv);
+
/*
* The frame sync between cameras is transmitted across the
* reverse channel as GPIO. We must open all channels while
@@ -698,13 +845,17 @@ static int max9286_s_stream(struct v4l2_subdev *sd, int enable)
}
/*
- * Enable CSI output, VC set according to link number.
- * Bit 7 must be set (chip manual says it's 0 and reserved).
+ * Configure the CSI-2 output to line interleaved mode (W x (N
+ * x H), as opposed to the (N x W) x H mode that outputs the
+ * images stitched side-by-side) and enable it.
*/
- max9286_write(priv, 0x15, 0x80 | MAX9286_VCTYPE |
- MAX9286_CSIOUTEN | MAX9286_0X15_RESV);
+ max9286_write(priv, 0x15, MAX9286_CSI_IMAGE_TYP | MAX9286_VCTYPE |
+ MAX9286_CSIOUTEN | MAX9286_EN_CCBSYB_CLK_STR |
+ MAX9286_EN_GPI_CCBSYB);
} else {
- max9286_write(priv, 0x15, MAX9286_VCTYPE | MAX9286_0X15_RESV);
+ max9286_write(priv, 0x15, MAX9286_VCTYPE |
+ MAX9286_EN_CCBSYB_CLK_STR |
+ MAX9286_EN_GPI_CCBSYB);
/* Stop all cameras. */
for_each_source(priv, source)
@@ -716,6 +867,32 @@ static int max9286_s_stream(struct v4l2_subdev *sd, int enable)
return 0;
}
+static int max9286_g_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *interval)
+{
+ struct max9286_priv *priv = sd_to_max9286(sd);
+
+ if (interval->pad != MAX9286_SRC_PAD)
+ return -EINVAL;
+
+ interval->interval = priv->interval;
+
+ return 0;
+}
+
+static int max9286_s_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *interval)
+{
+ struct max9286_priv *priv = sd_to_max9286(sd);
+
+ if (interval->pad != MAX9286_SRC_PAD)
+ return -EINVAL;
+
+ priv->interval = interval->interval;
+
+ return 0;
+}
+
static int max9286_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
@@ -749,22 +926,20 @@ static int max9286_set_fmt(struct v4l2_subdev *sd,
{
struct max9286_priv *priv = sd_to_max9286(sd);
struct v4l2_mbus_framefmt *cfg_fmt;
+ unsigned int i;
if (format->pad == MAX9286_SRC_PAD)
return -EINVAL;
- /* Refuse non YUV422 formats as we hardcode DT to 8 bit YUV422 */
- switch (format->format.code) {
- case MEDIA_BUS_FMT_UYVY8_1X16:
- case MEDIA_BUS_FMT_VYUY8_1X16:
- case MEDIA_BUS_FMT_YUYV8_1X16:
- case MEDIA_BUS_FMT_YVYU8_1X16:
- break;
- default:
- format->format.code = MEDIA_BUS_FMT_UYVY8_1X16;
- break;
+ /* Validate the format. */
+ for (i = 0; i < ARRAY_SIZE(max9286_formats); ++i) {
+ if (max9286_formats[i].code == format->format.code)
+ break;
}
+ if (i == ARRAY_SIZE(max9286_formats))
+ format->format.code = max9286_formats[0].code;
+
cfg_fmt = max9286_get_pad_format(priv, sd_state, format->pad,
format->which);
if (!cfg_fmt)
@@ -807,6 +982,8 @@ static int max9286_get_fmt(struct v4l2_subdev *sd,
static const struct v4l2_subdev_video_ops max9286_video_ops = {
.s_stream = max9286_s_stream,
+ .g_frame_interval = max9286_g_frame_interval,
+ .s_frame_interval = max9286_s_frame_interval,
};
static const struct v4l2_subdev_pad_ops max9286_pad_ops = {
@@ -820,16 +997,20 @@ static const struct v4l2_subdev_ops max9286_subdev_ops = {
.pad = &max9286_pad_ops,
};
+static const struct v4l2_mbus_framefmt max9286_default_format = {
+ .width = 1280,
+ .height = 800,
+ .code = MEDIA_BUS_FMT_UYVY8_1X16,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .field = V4L2_FIELD_NONE,
+ .ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT,
+ .quantization = V4L2_QUANTIZATION_DEFAULT,
+ .xfer_func = V4L2_XFER_FUNC_DEFAULT,
+};
+
static void max9286_init_format(struct v4l2_mbus_framefmt *fmt)
{
- fmt->width = 1280;
- fmt->height = 800;
- fmt->code = MEDIA_BUS_FMT_UYVY8_1X16;
- fmt->colorspace = V4L2_COLORSPACE_SRGB;
- fmt->field = V4L2_FIELD_NONE;
- fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
- fmt->quantization = V4L2_QUANTIZATION_DEFAULT;
- fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+ *fmt = max9286_default_format;
}
static int max9286_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
@@ -891,10 +1072,10 @@ static int max9286_v4l2_register(struct max9286_priv *priv)
priv->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
v4l2_ctrl_handler_init(&priv->ctrls, 1);
- priv->pixelrate = v4l2_ctrl_new_std(&priv->ctrls,
- &max9286_ctrl_ops,
- V4L2_CID_PIXEL_RATE,
- 1, INT_MAX, 1, 50000000);
+ priv->pixelrate_ctrl = v4l2_ctrl_new_std(&priv->ctrls,
+ &max9286_ctrl_ops,
+ V4L2_CID_PIXEL_RATE,
+ 1, INT_MAX, 1, 50000000);
priv->sd.ctrl_handler = &priv->ctrls;
ret = priv->ctrls.error;
@@ -932,6 +1113,7 @@ static int max9286_v4l2_register(struct max9286_priv *priv)
err_put_node:
fwnode_handle_put(ep);
err_async:
+ v4l2_ctrl_handler_free(&priv->ctrls);
max9286_v4l2_notifier_unregister(priv);
return ret;
@@ -975,6 +1157,7 @@ static int max9286_setup(struct max9286_priv *priv)
(2 << 6) | (1 << 4) | (0 << 2) | (3 << 0), /* 210x */
(3 << 6) | (2 << 4) | (1 << 2) | (0 << 0), /* 3210 */
};
+ int cfg;
/*
* Set the I2C bus speed.
@@ -993,24 +1176,27 @@ static int max9286_setup(struct max9286_priv *priv)
max9286_write(priv, 0x0b, link_order[priv->route_mask]);
max9286_write(priv, 0x69, (0xf & ~priv->route_mask));
- /*
- * Video format setup:
- * Disable CSI output, VC is set according to Link number.
- */
- max9286_write(priv, 0x15, MAX9286_VCTYPE | MAX9286_0X15_RESV);
+ max9286_set_video_format(priv, &max9286_default_format);
+ max9286_set_fsync_period(priv);
- /* Enable CSI-2 Lane D0-D3 only, DBL mode, YUV422 8-bit. */
- max9286_write(priv, 0x12, MAX9286_CSIDBL | MAX9286_DBL |
- MAX9286_CSILANECNT(priv->csi2_data_lanes) |
- MAX9286_DATATYPE_YUV422_8BIT);
+ cfg = max9286_read(priv, 0x1c);
+ if (cfg < 0)
+ return cfg;
+
+ dev_dbg(&priv->client->dev, "power-up config: %s immunity, %u-bit bus\n",
+ cfg & MAX9286_HIGHIMM(0) ? "high" : "legacy",
+ cfg & MAX9286_BWS ? 32 : cfg & MAX9286_HIBW ? 27 : 24);
- /* Automatic: FRAMESYNC taken from the slowest Link. */
- max9286_write(priv, 0x01, MAX9286_FSYNCMODE_INT_HIZ |
- MAX9286_FSYNCMETH_AUTO);
+ if (priv->bus_width) {
+ cfg &= ~(MAX9286_HIBW | MAX9286_BWS);
- /* Enable HS/VS encoding, use D14/15 for HS/VS, invert VS. */
- max9286_write(priv, 0x0c, MAX9286_HVEN | MAX9286_INVVS |
- MAX9286_HVSRC_D14);
+ if (priv->bus_width == 27)
+ cfg |= MAX9286_HIBW;
+ else if (priv->bus_width == 32)
+ cfg |= MAX9286_BWS;
+
+ max9286_write(priv, 0x1c, cfg);
+ }
/*
* The overlap window seems to provide additional validation by tracking
@@ -1088,9 +1274,6 @@ static int max9286_parse_gpios(struct max9286_priv *priv)
struct device *dev = &priv->client->dev;
int ret;
- /* GPIO values default to high */
- priv->gpio_state = BIT(0) | BIT(1);
-
/*
* Parse the "gpio-poc" vendor property. If the property is not
* specified the camera power is controlled by a regulator.
@@ -1102,18 +1285,7 @@ static int max9286_parse_gpios(struct max9286_priv *priv)
* If gpio lines are not used for the camera power, register
* a gpio controller for consumers.
*/
- ret = max9286_register_gpio(priv);
- if (ret)
- return ret;
-
- priv->regulator = devm_regulator_get(dev, "poc");
- if (IS_ERR(priv->regulator)) {
- return dev_err_probe(dev, PTR_ERR(priv->regulator),
- "Unable to get PoC regulator (%ld)\n",
- PTR_ERR(priv->regulator));
- }
-
- return 0;
+ return max9286_register_gpio(priv);
}
/* If the property is specified make sure it is well formed. */
@@ -1124,21 +1296,75 @@ static int max9286_parse_gpios(struct max9286_priv *priv)
return -EINVAL;
}
+ priv->use_gpio_poc = true;
+ return 0;
+}
+
+static int max9286_poc_power_on(struct max9286_priv *priv)
+{
+ struct max9286_source *source;
+ unsigned int enabled = 0;
+ int ret;
+
+ /* Enable the global regulator if available. */
+ if (priv->regulator)
+ return regulator_enable(priv->regulator);
+
+ if (priv->use_gpio_poc)
+ return max9286_gpio_set(priv, priv->gpio_poc[0],
+ !priv->gpio_poc[1]);
+
+ /* Otherwise use the per-port regulators. */
+ for_each_source(priv, source) {
+ ret = regulator_enable(source->regulator);
+ if (ret < 0)
+ goto error;
+
+ enabled |= BIT(to_index(priv, source));
+ }
+
return 0;
+
+error:
+ for_each_source(priv, source) {
+ if (enabled & BIT(to_index(priv, source)))
+ regulator_disable(source->regulator);
+ }
+
+ return ret;
+}
+
+static int max9286_poc_power_off(struct max9286_priv *priv)
+{
+ struct max9286_source *source;
+ int ret = 0;
+
+ if (priv->regulator)
+ return regulator_disable(priv->regulator);
+
+ if (priv->use_gpio_poc)
+ return max9286_gpio_set(priv, priv->gpio_poc[0],
+ priv->gpio_poc[1]);
+
+ for_each_source(priv, source) {
+ int err;
+
+ err = regulator_disable(source->regulator);
+ if (!ret)
+ ret = err;
+ }
+
+ return ret;
}
static int max9286_poc_enable(struct max9286_priv *priv, bool enable)
{
int ret;
- /* If the regulator is not available, use gpio to control power. */
- if (!priv->regulator)
- ret = max9286_gpio_set(priv, priv->gpio_poc[0],
- enable ^ priv->gpio_poc[1]);
- else if (enable)
- ret = regulator_enable(priv->regulator);
+ if (enable)
+ ret = max9286_poc_power_on(priv);
else
- ret = regulator_disable(priv->regulator);
+ ret = max9286_poc_power_off(priv);
if (ret < 0)
dev_err(&priv->client->dev, "Unable to turn power %s\n",
@@ -1208,6 +1434,8 @@ static int max9286_parse_dt(struct max9286_priv *priv)
struct device_node *node = NULL;
unsigned int i2c_mux_mask = 0;
u32 reverse_channel_microvolt;
+ u32 i2c_clk_freq = 105000;
+ unsigned int i;
/* Balance the of_node_put() performed by of_find_node_by_name(). */
of_node_get(dev->of_node);
@@ -1298,6 +1526,40 @@ static int max9286_parse_dt(struct max9286_priv *priv)
}
of_node_put(node);
+ of_property_read_u32(dev->of_node, "maxim,bus-width", &priv->bus_width);
+ switch (priv->bus_width) {
+ case 0:
+ /*
+ * The property isn't specified in the device tree, the driver
+ * will keep the default value selected by the BWS pin.
+ */
+ case 24:
+ case 27:
+ case 32:
+ break;
+ default:
+ dev_err(dev, "Invalid %s value %u\n", "maxim,bus-width",
+ priv->bus_width);
+ return -EINVAL;
+ }
+
+ of_property_read_u32(dev->of_node, "maxim,i2c-remote-bus-hz",
+ &i2c_clk_freq);
+ for (i = 0; i < ARRAY_SIZE(max9286_i2c_speeds); ++i) {
+ const struct max9286_i2c_speed *speed = &max9286_i2c_speeds[i];
+
+ if (speed->rate == i2c_clk_freq) {
+ priv->i2c_mstbt = speed->mstbt;
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(max9286_i2c_speeds)) {
+ dev_err(dev, "Invalid %s value %u\n", "maxim,i2c-remote-bus-hz",
+ i2c_clk_freq);
+ return -EINVAL;
+ }
+
/*
* Parse the initial value of the reverse channel amplitude from
* the firmware interface and convert it to millivolts.
@@ -1317,6 +1579,44 @@ static int max9286_parse_dt(struct max9286_priv *priv)
return 0;
}
+static int max9286_get_poc_supplies(struct max9286_priv *priv)
+{
+ struct device *dev = &priv->client->dev;
+ struct max9286_source *source;
+ int ret;
+
+ /* Start by getting the global regulator. */
+ priv->regulator = devm_regulator_get_optional(dev, "poc");
+ if (!IS_ERR(priv->regulator))
+ return 0;
+
+ if (PTR_ERR(priv->regulator) != -ENODEV)
+ return dev_err_probe(dev, PTR_ERR(priv->regulator),
+ "Unable to get PoC regulator\n");
+
+ /* If there's no global regulator, get per-port regulators. */
+ dev_dbg(dev,
+ "No global PoC regulator, looking for per-port regulators\n");
+ priv->regulator = NULL;
+
+ for_each_source(priv, source) {
+ unsigned int index = to_index(priv, source);
+ char name[10];
+
+ snprintf(name, sizeof(name), "port%u-poc", index);
+ source->regulator = devm_regulator_get(dev, name);
+ if (IS_ERR(source->regulator)) {
+ ret = PTR_ERR(source->regulator);
+ dev_err_probe(dev, ret,
+ "Unable to get port %u PoC regulator\n",
+ index);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
static int max9286_probe(struct i2c_client *client)
{
struct max9286_priv *priv;
@@ -1330,10 +1630,19 @@ static int max9286_probe(struct i2c_client *client)
priv->client = client;
+ /* GPIO values default to high */
+ priv->gpio_state = BIT(0) | BIT(1);
+
+ ret = max9286_parse_dt(priv);
+ if (ret)
+ goto err_cleanup_dt;
+
priv->gpiod_pwdn = devm_gpiod_get_optional(&client->dev, "enable",
GPIOD_OUT_HIGH);
- if (IS_ERR(priv->gpiod_pwdn))
- return PTR_ERR(priv->gpiod_pwdn);
+ if (IS_ERR(priv->gpiod_pwdn)) {
+ ret = PTR_ERR(priv->gpiod_pwdn);
+ goto err_cleanup_dt;
+ }
gpiod_set_consumer_name(priv->gpiod_pwdn, "max9286-pwdn");
gpiod_set_value_cansleep(priv->gpiod_pwdn, 1);
@@ -1360,9 +1669,11 @@ static int max9286_probe(struct i2c_client *client)
if (ret)
goto err_powerdown;
- ret = max9286_parse_dt(priv);
- if (ret)
- goto err_powerdown;
+ if (!priv->use_gpio_poc) {
+ ret = max9286_get_poc_supplies(priv);
+ if (ret)
+ goto err_cleanup_dt;
+ }
ret = max9286_init(priv);
if (ret < 0)
@@ -1370,10 +1681,10 @@ static int max9286_probe(struct i2c_client *client)
return 0;
-err_cleanup_dt:
- max9286_cleanup_dt(priv);
err_powerdown:
gpiod_set_value_cansleep(priv->gpiod_pwdn, 0);
+err_cleanup_dt:
+ max9286_cleanup_dt(priv);
return ret;
}
diff --git a/drivers/media/i2c/msp3400-driver.c b/drivers/media/i2c/msp3400-driver.c
index 4ce7a15a9884..12032e28b428 100644
--- a/drivers/media/i2c/msp3400-driver.c
+++ b/drivers/media/i2c/msp3400-driver.c
@@ -663,8 +663,9 @@ static const char * const opmode_str[] = {
[OPMODE_AUTOSELECT] = "autodetect and autoselect",
};
-static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id)
+static int msp_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct msp_state *state;
struct v4l2_subdev *sd;
struct v4l2_ctrl_handler *hdl;
@@ -891,7 +892,7 @@ static struct i2c_driver msp_driver = {
.name = "msp3400",
.pm = &msp3400_pm_ops,
},
- .probe = msp_probe,
+ .probe_new = msp_probe,
.remove = msp_remove,
.id_table = msp_id,
};
diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c
index 4ffc2f6e7db4..9e023a4b9bd1 100644
--- a/drivers/media/i2c/mt9p031.c
+++ b/drivers/media/i2c/mt9p031.c
@@ -1102,9 +1102,9 @@ done:
return pdata;
}
-static int mt9p031_probe(struct i2c_client *client,
- const struct i2c_device_id *did)
+static int mt9p031_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *did = i2c_client_get_device_id(client);
struct mt9p031_platform_data *pdata = mt9p031_get_pdata(client);
struct i2c_adapter *adapter = client->adapter;
struct mt9p031 *mt9p031;
@@ -1248,7 +1248,7 @@ static struct i2c_driver mt9p031_i2c_driver = {
.of_match_table = of_match_ptr(mt9p031_of_match),
.name = "mt9p031",
},
- .probe = mt9p031_probe,
+ .probe_new = mt9p031_probe,
.remove = mt9p031_remove,
.id_table = mt9p031_id,
};
diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c
index bc4388ccc2a8..7cfd4ebdd2e6 100644
--- a/drivers/media/i2c/mt9v032.c
+++ b/drivers/media/i2c/mt9v032.c
@@ -1044,9 +1044,9 @@ done:
return pdata;
}
-static int mt9v032_probe(struct i2c_client *client,
- const struct i2c_device_id *did)
+static int mt9v032_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *did = i2c_client_get_device_id(client);
struct mt9v032_platform_data *pdata = mt9v032_get_pdata(client);
struct mt9v032 *mt9v032;
unsigned int i;
@@ -1296,7 +1296,7 @@ static struct i2c_driver mt9v032_driver = {
.name = "mt9v032",
.of_match_table = of_match_ptr(mt9v032_of_match),
},
- .probe = mt9v032_probe,
+ .probe_new = mt9v032_probe,
.remove = mt9v032_remove,
.id_table = mt9v032_id,
};
diff --git a/drivers/media/i2c/ov2740.c b/drivers/media/i2c/ov2740.c
index f3731f932a94..89d126240c34 100644
--- a/drivers/media/i2c/ov2740.c
+++ b/drivers/media/i2c/ov2740.c
@@ -629,8 +629,10 @@ static int ov2740_init_controls(struct ov2740 *ov2740)
V4L2_CID_TEST_PATTERN,
ARRAY_SIZE(ov2740_test_pattern_menu) - 1,
0, 0, ov2740_test_pattern_menu);
- if (ctrl_hdlr->error)
+ if (ctrl_hdlr->error) {
+ v4l2_ctrl_handler_free(ctrl_hdlr);
return ctrl_hdlr->error;
+ }
ov2740->sd.ctrl_handler = ctrl_hdlr;
diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c
index e0f908af581b..1536649b9e90 100644
--- a/drivers/media/i2c/ov5640.c
+++ b/drivers/media/i2c/ov5640.c
@@ -50,6 +50,7 @@
#define OV5640_REG_SYS_CTRL0 0x3008
#define OV5640_REG_SYS_CTRL0_SW_PWDN 0x42
#define OV5640_REG_SYS_CTRL0_SW_PWUP 0x02
+#define OV5640_REG_SYS_CTRL0_SW_RST 0x82
#define OV5640_REG_CHIP_ID 0x300a
#define OV5640_REG_IO_MIPI_CTRL00 0x300e
#define OV5640_REG_PAD_OUTPUT_ENABLE01 0x3017
@@ -520,7 +521,18 @@ static u32 ov5640_code_to_bpp(struct ov5640_dev *sensor, u32 code)
*/
/* YUV422 UYVY VGA@30fps */
-static const struct v4l2_mbus_framefmt ov5640_default_fmt = {
+static const struct v4l2_mbus_framefmt ov5640_csi2_default_fmt = {
+ .code = MEDIA_BUS_FMT_UYVY8_1X16,
+ .width = 640,
+ .height = 480,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(V4L2_COLORSPACE_SRGB),
+ .quantization = V4L2_QUANTIZATION_FULL_RANGE,
+ .xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(V4L2_COLORSPACE_SRGB),
+ .field = V4L2_FIELD_NONE,
+};
+
+static const struct v4l2_mbus_framefmt ov5640_dvp_default_fmt = {
.code = MEDIA_BUS_FMT_UYVY8_2X8,
.width = 640,
.height = 480,
@@ -532,7 +544,7 @@ static const struct v4l2_mbus_framefmt ov5640_default_fmt = {
};
static const struct reg_value ov5640_init_setting[] = {
- {0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0},
+ {0x3103, 0x11, 0, 0},
{0x3103, 0x03, 0, 0}, {0x3630, 0x36, 0, 0},
{0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0},
{0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0},
@@ -2424,24 +2436,48 @@ static void ov5640_power(struct ov5640_dev *sensor, bool enable)
gpiod_set_value_cansleep(sensor->pwdn_gpio, enable ? 0 : 1);
}
-static void ov5640_reset(struct ov5640_dev *sensor)
+/*
+ * From section 2.7 power up sequence:
+ * t0 + t1 + t2 >= 5ms Delay from DOVDD stable to PWDN pull down
+ * t3 >= 1ms Delay from PWDN pull down to RESETB pull up
+ * t4 >= 20ms Delay from RESETB pull up to SCCB (i2c) stable
+ *
+ * Some modules don't expose RESETB/PWDN pins directly, instead providing a
+ * "PWUP" GPIO which is wired through appropriate delays and inverters to the
+ * pins.
+ *
+ * In such cases, this gpio should be mapped to pwdn_gpio in the driver, and we
+ * should still toggle the pwdn_gpio below with the appropriate delays, while
+ * the calls to reset_gpio will be ignored.
+ */
+static void ov5640_powerup_sequence(struct ov5640_dev *sensor)
{
- if (!sensor->reset_gpio)
- return;
-
- gpiod_set_value_cansleep(sensor->reset_gpio, 0);
+ if (sensor->pwdn_gpio) {
+ gpiod_set_value_cansleep(sensor->reset_gpio, 0);
- /* camera power cycle */
- ov5640_power(sensor, false);
- usleep_range(5000, 10000);
- ov5640_power(sensor, true);
- usleep_range(5000, 10000);
+ /* camera power cycle */
+ ov5640_power(sensor, false);
+ usleep_range(5000, 10000);
+ ov5640_power(sensor, true);
+ usleep_range(5000, 10000);
- gpiod_set_value_cansleep(sensor->reset_gpio, 1);
- usleep_range(1000, 2000);
+ gpiod_set_value_cansleep(sensor->reset_gpio, 1);
+ usleep_range(1000, 2000);
- gpiod_set_value_cansleep(sensor->reset_gpio, 0);
+ gpiod_set_value_cansleep(sensor->reset_gpio, 0);
+ } else {
+ /* software reset */
+ ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0,
+ OV5640_REG_SYS_CTRL0_SW_RST);
+ }
usleep_range(20000, 25000);
+
+ /*
+ * software standby: allows registers programming;
+ * exit at restore_mode() for CSI, s_stream(1) for DVP
+ */
+ ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0,
+ OV5640_REG_SYS_CTRL0_SW_PWDN);
}
static int ov5640_set_power_on(struct ov5640_dev *sensor)
@@ -2464,8 +2500,7 @@ static int ov5640_set_power_on(struct ov5640_dev *sensor)
goto xclk_off;
}
- ov5640_reset(sensor);
- ov5640_power(sensor, true);
+ ov5640_powerup_sequence(sensor);
ret = ov5640_init_slave_id(sensor);
if (ret)
@@ -3316,6 +3351,7 @@ static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
break;
}
+ pm_runtime_mark_last_busy(&sensor->i2c_client->dev);
pm_runtime_put_autosuspend(&sensor->i2c_client->dev);
return 0;
@@ -3391,6 +3427,7 @@ static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl)
break;
}
+ pm_runtime_mark_last_busy(&sensor->i2c_client->dev);
pm_runtime_put_autosuspend(&sensor->i2c_client->dev);
return ret;
@@ -3458,7 +3495,7 @@ static int ov5640_init_controls(struct ov5640_dev *sensor)
/* Auto/manual gain */
ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTOGAIN,
0, 1, 1, 1);
- ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN,
+ ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_ANALOGUE_GAIN,
0, 1023, 1, 0);
ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION,
@@ -3710,8 +3747,10 @@ static int ov5640_s_stream(struct v4l2_subdev *sd, int enable)
out:
mutex_unlock(&sensor->lock);
- if (!enable || ret)
+ if (!enable || ret) {
+ pm_runtime_mark_last_busy(&sensor->i2c_client->dev);
pm_runtime_put_autosuspend(&sensor->i2c_client->dev);
+ }
return ret;
}
@@ -3719,11 +3758,13 @@ out:
static int ov5640_init_cfg(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state)
{
+ struct ov5640_dev *sensor = to_ov5640_dev(sd);
struct v4l2_mbus_framefmt *fmt =
v4l2_subdev_get_try_format(sd, state, 0);
struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, state, 0);
- *fmt = ov5640_default_fmt;
+ *fmt = ov5640_is_csi2(sensor) ? ov5640_csi2_default_fmt :
+ ov5640_dvp_default_fmt;
crop->left = OV5640_PIXEL_ARRAY_LEFT;
crop->top = OV5640_PIXEL_ARRAY_TOP;
@@ -3812,7 +3853,6 @@ static int ov5640_probe(struct i2c_client *client)
* default init sequence initialize sensor to
* YUV422 UYVY VGA@30fps
*/
- sensor->fmt = ov5640_default_fmt;
sensor->frame_interval.numerator = 1;
sensor->frame_interval.denominator = ov5640_framerates[OV5640_30_FPS];
sensor->current_fr = OV5640_30_FPS;
@@ -3845,6 +3885,9 @@ static int ov5640_probe(struct i2c_client *client)
return -EINVAL;
}
+ sensor->fmt = ov5640_is_csi2(sensor) ? ov5640_csi2_default_fmt :
+ ov5640_dvp_default_fmt;
+
/* get system clock (xclk) */
sensor->xclk = devm_clk_get(dev, "xclk");
if (IS_ERR(sensor->xclk)) {
@@ -3912,6 +3955,7 @@ static int ov5640_probe(struct i2c_client *client)
pm_runtime_set_autosuspend_delay(dev, 1000);
pm_runtime_use_autosuspend(dev);
+ pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0;
diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c
index bc9fc3bc90c2..f79d908f4531 100644
--- a/drivers/media/i2c/ov5670.c
+++ b/drivers/media/i2c/ov5670.c
@@ -1,15 +1,24 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2017 Intel Corporation.
+#include <asm/unaligned.h>
#include <linux/acpi.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-event.h>
#include <media/v4l2-fwnode.h>
+#define OV5670_XVCLK_FREQ 19200000
+
#define OV5670_REG_CHIP_ID 0x300a
#define OV5670_CHIP_ID 0x005670
@@ -65,6 +74,10 @@
#define OV5670_REG_VALUE_16BIT 2
#define OV5670_REG_VALUE_24BIT 3
+/* Pixel Array */
+#define OV5670_NATIVE_WIDTH 2624
+#define OV5670_NATIVE_HEIGHT 1980
+
/* Initial number of frames to skip to avoid possible garbage */
#define OV5670_NUM_OF_SKIP_FRAMES 2
@@ -83,6 +96,14 @@ struct ov5670_link_freq_config {
const struct ov5670_reg_list reg_list;
};
+static const char * const ov5670_supply_names[] = {
+ "avdd", /* Analog power */
+ "dvdd", /* Digital power */
+ "dovdd", /* Digital output power */
+};
+
+#define OV5670_NUM_SUPPLIES ARRAY_SIZE(ov5670_supply_names)
+
struct ov5670_mode {
/* Frame width in pixels */
u32 width;
@@ -99,10 +120,25 @@ struct ov5670_mode {
/* Link frequency needed for this resolution */
u32 link_freq_index;
+ /* Analog crop rectangle */
+ const struct v4l2_rect *analog_crop;
+
/* Sensor register settings for this resolution */
const struct ov5670_reg_list reg_list;
};
+/*
+ * All the modes supported by the driver are obtained by subsampling the
+ * full pixel array. The below values are reflected in registers from
+ * 0x3800-0x3807 in the modes register-value tables.
+ */
+static const struct v4l2_rect ov5670_analog_crop = {
+ .left = 12,
+ .top = 4,
+ .width = 2600,
+ .height = 1952,
+};
+
static const struct ov5670_reg mipi_data_rate_840mbps[] = {
{0x0300, 0x04},
{0x0301, 0x00},
@@ -1750,66 +1786,73 @@ static const struct ov5670_mode supported_modes[] = {
.height = 1944,
.vts_def = OV5670_VTS_30FPS,
.vts_min = OV5670_VTS_30FPS,
+ .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX,
+ .analog_crop = &ov5670_analog_crop,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_2592x1944_regs),
.regs = mode_2592x1944_regs,
},
- .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX,
},
{
.width = 1296,
.height = 972,
.vts_def = OV5670_VTS_30FPS,
.vts_min = 996,
+ .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX,
+ .analog_crop = &ov5670_analog_crop,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_1296x972_regs),
.regs = mode_1296x972_regs,
},
- .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX,
},
{
.width = 648,
.height = 486,
.vts_def = OV5670_VTS_30FPS,
.vts_min = 516,
+ .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX,
+ .analog_crop = &ov5670_analog_crop,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_648x486_regs),
.regs = mode_648x486_regs,
},
- .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX,
},
{
.width = 2560,
.height = 1440,
.vts_def = OV5670_VTS_30FPS,
.vts_min = OV5670_VTS_30FPS,
+ .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX,
+ .analog_crop = &ov5670_analog_crop,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_2560x1440_regs),
.regs = mode_2560x1440_regs,
},
- .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX,
},
{
.width = 1280,
.height = 720,
.vts_def = OV5670_VTS_30FPS,
.vts_min = 1020,
+
+ .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX,
+ .analog_crop = &ov5670_analog_crop,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_1280x720_regs),
.regs = mode_1280x720_regs,
},
- .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX,
},
{
.width = 640,
.height = 360,
.vts_def = OV5670_VTS_30FPS,
.vts_min = 510,
+ .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX,
+ .analog_crop = &ov5670_analog_crop,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_640x360_regs),
.regs = mode_640x360_regs,
},
- .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX,
}
};
@@ -1828,6 +1871,16 @@ struct ov5670 {
/* Current mode */
const struct ov5670_mode *cur_mode;
+ /* xvclk input clock */
+ struct clk *xvclk;
+
+ /* Regulators */
+ struct regulator_bulk_data supplies[OV5670_NUM_SUPPLIES];
+
+ /* Power-down and reset gpios. */
+ struct gpio_desc *pwdn_gpio; /* PWDNB pin. */
+ struct gpio_desc *reset_gpio; /* XSHUTDOWN pin. */
+
/* To serialize asynchronus callbacks */
struct mutex mutex;
@@ -1935,27 +1988,6 @@ static int ov5670_write_reg_list(struct ov5670 *ov5670,
return ov5670_write_regs(ov5670, r_list->regs, r_list->num_of_regs);
}
-/* Open sub-device */
-static int ov5670_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
-{
- struct ov5670 *ov5670 = to_ov5670(sd);
- struct v4l2_mbus_framefmt *try_fmt =
- v4l2_subdev_get_try_format(sd, fh->state, 0);
-
- mutex_lock(&ov5670->mutex);
-
- /* Initialize try_fmt */
- try_fmt->width = ov5670->cur_mode->width;
- try_fmt->height = ov5670->cur_mode->height;
- try_fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
- try_fmt->field = V4L2_FIELD_NONE;
-
- /* No crop or compose */
- mutex_unlock(&ov5670->mutex);
-
- return 0;
-}
-
static int ov5670_update_digital_gain(struct ov5670 *ov5670, u32 d_gain)
{
int ret;
@@ -2006,7 +2038,7 @@ static int ov5670_set_ctrl(struct v4l2_ctrl *ctrl)
struct ov5670, ctrl_handler);
struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd);
s64 max;
- int ret = 0;
+ int ret;
/* Propagate change of current control to all related controls */
switch (ctrl->id) {
@@ -2045,7 +2077,13 @@ static int ov5670_set_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_TEST_PATTERN:
ret = ov5670_enable_test_pattern(ov5670, ctrl->val);
break;
+ case V4L2_CID_HBLANK:
+ case V4L2_CID_LINK_FREQ:
+ case V4L2_CID_PIXEL_RATE:
+ ret = 0;
+ break;
default:
+ ret = -EINVAL;
dev_info(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n",
__func__, ctrl->id, ctrl->val);
break;
@@ -2155,6 +2193,28 @@ error:
return ret;
}
+static int ov5670_init_cfg(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ struct v4l2_mbus_framefmt *fmt =
+ v4l2_subdev_get_try_format(sd, state, 0);
+ const struct ov5670_mode *default_mode = &supported_modes[0];
+ struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, state, 0);
+
+ fmt->width = default_mode->width;
+ fmt->height = default_mode->height;
+ fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
+ fmt->field = V4L2_FIELD_NONE;
+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
+ fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(V4L2_COLORSPACE_SRGB);
+ fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
+ fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(V4L2_COLORSPACE_SRGB);
+
+ *crop = *default_mode->analog_crop;
+
+ return 0;
+}
+
static int ov5670_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
@@ -2404,6 +2464,49 @@ unlock_and_return:
return ret;
}
+static int __maybe_unused ov5670_runtime_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ov5670 *ov5670 = to_ov5670(sd);
+ unsigned long delay_us;
+ int ret;
+
+ ret = clk_prepare_enable(ov5670->xvclk);
+ if (ret)
+ return ret;
+
+ ret = regulator_bulk_enable(OV5670_NUM_SUPPLIES, ov5670->supplies);
+ if (ret) {
+ clk_disable_unprepare(ov5670->xvclk);
+ return ret;
+ }
+
+ gpiod_set_value_cansleep(ov5670->pwdn_gpio, 0);
+ gpiod_set_value_cansleep(ov5670->reset_gpio, 0);
+
+ /* 8192 * 2 clock pulses before the first SCCB transaction. */
+ delay_us = DIV_ROUND_UP(8192 * 2 * 1000,
+ DIV_ROUND_UP(OV5670_XVCLK_FREQ, 1000));
+ fsleep(delay_us);
+
+ return 0;
+}
+
+static int __maybe_unused ov5670_runtime_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ov5670 *ov5670 = to_ov5670(sd);
+
+ gpiod_set_value_cansleep(ov5670->reset_gpio, 1);
+ gpiod_set_value_cansleep(ov5670->pwdn_gpio, 1);
+ regulator_bulk_disable(OV5670_NUM_SUPPLIES, ov5670->supplies);
+ clk_disable_unprepare(ov5670->xvclk);
+
+ return 0;
+}
+
static int __maybe_unused ov5670_suspend(struct device *dev)
{
struct v4l2_subdev *sd = dev_get_drvdata(dev);
@@ -2438,15 +2541,64 @@ static const struct v4l2_subdev_core_ops ov5670_core_ops = {
.unsubscribe_event = v4l2_event_subdev_unsubscribe,
};
+static const struct v4l2_rect *
+__ov5670_get_pad_crop(struct ov5670 *sensor, struct v4l2_subdev_state *state,
+ unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+ const struct ov5670_mode *mode = sensor->cur_mode;
+
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_crop(&sensor->sd, state, pad);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return mode->analog_crop;
+ }
+
+ return NULL;
+}
+
+static int ov5670_get_selection(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_selection *sel)
+{
+ struct ov5670 *sensor = to_ov5670(subdev);
+
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP:
+ mutex_lock(&sensor->mutex);
+ sel->r = *__ov5670_get_pad_crop(sensor, state, sel->pad,
+ sel->which);
+ mutex_unlock(&sensor->mutex);
+ break;
+ case V4L2_SEL_TGT_NATIVE_SIZE:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ sel->r.top = 0;
+ sel->r.left = 0;
+ sel->r.width = OV5670_NATIVE_WIDTH;
+ sel->r.height = OV5670_NATIVE_HEIGHT;
+ break;
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ sel->r = ov5670_analog_crop;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static const struct v4l2_subdev_video_ops ov5670_video_ops = {
.s_stream = ov5670_set_stream,
};
static const struct v4l2_subdev_pad_ops ov5670_pad_ops = {
+ .init_cfg = ov5670_init_cfg,
.enum_mbus_code = ov5670_enum_mbus_code,
.get_fmt = ov5670_get_pad_format,
.set_fmt = ov5670_set_pad_format,
.enum_frame_size = ov5670_enum_frame_size,
+ .get_selection = ov5670_get_selection,
+ .set_selection = ov5670_get_selection,
};
static const struct v4l2_subdev_sensor_ops ov5670_sensor_ops = {
@@ -2464,9 +2616,34 @@ static const struct media_entity_operations ov5670_subdev_entity_ops = {
.link_validate = v4l2_subdev_link_validate,
};
-static const struct v4l2_subdev_internal_ops ov5670_internal_ops = {
- .open = ov5670_open,
-};
+static int ov5670_regulators_probe(struct ov5670 *ov5670)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd);
+ unsigned int i;
+
+ for (i = 0; i < OV5670_NUM_SUPPLIES; i++)
+ ov5670->supplies[i].supply = ov5670_supply_names[i];
+
+ return devm_regulator_bulk_get(&client->dev, OV5670_NUM_SUPPLIES,
+ ov5670->supplies);
+}
+
+static int ov5670_gpio_probe(struct ov5670 *ov5670)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd);
+
+ ov5670->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "powerdown",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(ov5670->pwdn_gpio))
+ return PTR_ERR(ov5670->pwdn_gpio);
+
+ ov5670->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(ov5670->reset_gpio))
+ return PTR_ERR(ov5670->reset_gpio);
+
+ return 0;
+}
static int ov5670_probe(struct i2c_client *client)
{
@@ -2476,10 +2653,6 @@ static int ov5670_probe(struct i2c_client *client)
bool full_power;
int ret;
- device_property_read_u32(&client->dev, "clock-frequency", &input_clk);
- if (input_clk != 19200000)
- return -EINVAL;
-
ov5670 = devm_kzalloc(&client->dev, sizeof(*ov5670), GFP_KERNEL);
if (!ov5670) {
ret = -ENOMEM;
@@ -2487,16 +2660,50 @@ static int ov5670_probe(struct i2c_client *client)
goto error_print;
}
+ ov5670->xvclk = devm_clk_get(&client->dev, NULL);
+ if (!IS_ERR_OR_NULL(ov5670->xvclk))
+ input_clk = clk_get_rate(ov5670->xvclk);
+ else if (PTR_ERR(ov5670->xvclk) == -ENOENT)
+ device_property_read_u32(&client->dev, "clock-frequency",
+ &input_clk);
+ else
+ return dev_err_probe(&client->dev, PTR_ERR(ov5670->xvclk),
+ "error getting clock\n");
+
+ if (input_clk != OV5670_XVCLK_FREQ) {
+ dev_err(&client->dev,
+ "Unsupported clock frequency %u\n", input_clk);
+ return -EINVAL;
+ }
+
/* Initialize subdev */
v4l2_i2c_subdev_init(&ov5670->sd, client, &ov5670_subdev_ops);
+ ret = ov5670_regulators_probe(ov5670);
+ if (ret) {
+ err_msg = "Regulators probe failed";
+ goto error_print;
+ }
+
+ ret = ov5670_gpio_probe(ov5670);
+ if (ret) {
+ err_msg = "GPIO probe failed";
+ goto error_print;
+ }
+
full_power = acpi_dev_state_d0(&client->dev);
if (full_power) {
+ ret = ov5670_runtime_resume(&client->dev);
+ if (ret) {
+ err_msg = "Power up failed";
+ goto error_print;
+ }
+
/* Check module identity */
ret = ov5670_identify_module(ov5670);
if (ret) {
err_msg = "ov5670_identify_module() error";
- goto error_print;
+ goto error_power_off;
}
}
@@ -2511,7 +2718,6 @@ static int ov5670_probe(struct i2c_client *client)
goto error_mutex_destroy;
}
- ov5670->sd.internal_ops = &ov5670_internal_ops;
ov5670->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
V4L2_SUBDEV_FL_HAS_EVENTS;
ov5670->sd.entity.ops = &ov5670_subdev_entity_ops;
@@ -2525,24 +2731,27 @@ static int ov5670_probe(struct i2c_client *client)
goto error_handler_free;
}
- /* Async register for subdev */
- ret = v4l2_async_register_subdev_sensor(&ov5670->sd);
- if (ret < 0) {
- err_msg = "v4l2_async_register_subdev() error";
- goto error_entity_cleanup;
- }
-
ov5670->streaming = false;
/* Set the device's state to active if it's in D0 state. */
if (full_power)
pm_runtime_set_active(&client->dev);
pm_runtime_enable(&client->dev);
+
+ /* Async register for subdev */
+ ret = v4l2_async_register_subdev_sensor(&ov5670->sd);
+ if (ret < 0) {
+ err_msg = "v4l2_async_register_subdev() error";
+ goto error_pm_disable;
+ }
+
pm_runtime_idle(&client->dev);
return 0;
-error_entity_cleanup:
+error_pm_disable:
+ pm_runtime_disable(&client->dev);
+
media_entity_cleanup(&ov5670->sd.entity);
error_handler_free:
@@ -2551,6 +2760,10 @@ error_handler_free:
error_mutex_destroy:
mutex_destroy(&ov5670->mutex);
+error_power_off:
+ if (full_power)
+ ov5670_runtime_suspend(&client->dev);
+
error_print:
dev_err(&client->dev, "%s: %s %d\n", __func__, err_msg, ret);
@@ -2568,10 +2781,12 @@ static void ov5670_remove(struct i2c_client *client)
mutex_destroy(&ov5670->mutex);
pm_runtime_disable(&client->dev);
+ ov5670_runtime_suspend(&client->dev);
}
static const struct dev_pm_ops ov5670_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(ov5670_suspend, ov5670_resume)
+ SET_RUNTIME_PM_OPS(ov5670_runtime_suspend, ov5670_runtime_resume, NULL)
};
#ifdef CONFIG_ACPI
@@ -2583,11 +2798,18 @@ static const struct acpi_device_id ov5670_acpi_ids[] = {
MODULE_DEVICE_TABLE(acpi, ov5670_acpi_ids);
#endif
+static const struct of_device_id ov5670_of_ids[] = {
+ { .compatible = "ovti,ov5670" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ov5670_of_ids);
+
static struct i2c_driver ov5670_i2c_driver = {
.driver = {
.name = "ov5670",
.pm = &ov5670_pm_ops,
.acpi_match_table = ACPI_PTR(ov5670_acpi_ids),
+ .of_match_table = ov5670_of_ids,
},
.probe_new = ov5670_probe,
.remove = ov5670_remove,
diff --git a/drivers/media/i2c/ov5675.c b/drivers/media/i2c/ov5675.c
index 94dc8cb7a7c0..d55180b3b7aa 100644
--- a/drivers/media/i2c/ov5675.c
+++ b/drivers/media/i2c/ov5675.c
@@ -3,10 +3,14 @@
#include <asm/unaligned.h>
#include <linux/acpi.h>
+#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-fwnode.h>
@@ -17,7 +21,7 @@
#define OV5675_LINK_FREQ_450MHZ 450000000ULL
#define OV5675_SCLK 90000000LL
-#define OV5675_MCLK 19200000
+#define OV5675_XVCLK_19_2 19200000
#define OV5675_DATA_LANES 2
#define OV5675_RGB_DEPTH 10
@@ -76,6 +80,14 @@
#define to_ov5675(_sd) container_of(_sd, struct ov5675, sd)
+static const char * const ov5675_supply_names[] = {
+ "avdd", /* Analog power */
+ "dovdd", /* Digital I/O power */
+ "dvdd", /* Digital core power */
+};
+
+#define OV5675_NUM_SUPPLIES ARRAY_SIZE(ov5675_supply_names)
+
enum {
OV5675_LINK_FREQ_900MBPS,
};
@@ -484,6 +496,9 @@ struct ov5675 {
struct v4l2_subdev sd;
struct media_pad pad;
struct v4l2_ctrl_handler ctrl_handler;
+ struct clk *xvclk;
+ struct gpio_desc *reset_gpio;
+ struct regulator_bulk_data supplies[OV5675_NUM_SUPPLIES];
/* V4L2 Controls */
struct v4l2_ctrl *link_freq;
@@ -764,12 +779,14 @@ static const struct v4l2_ctrl_ops ov5675_ctrl_ops = {
static int ov5675_init_controls(struct ov5675 *ov5675)
{
+ struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd);
+ struct v4l2_fwnode_device_properties props;
struct v4l2_ctrl_handler *ctrl_hdlr;
s64 exposure_max, h_blank;
int ret;
ctrl_hdlr = &ov5675->ctrl_handler;
- ret = v4l2_ctrl_handler_init(ctrl_hdlr, 8);
+ ret = v4l2_ctrl_handler_init(ctrl_hdlr, 10);
if (ret)
return ret;
@@ -820,12 +837,28 @@ static int ov5675_init_controls(struct ov5675 *ov5675)
v4l2_ctrl_new_std(ctrl_hdlr, &ov5675_ctrl_ops,
V4L2_CID_VFLIP, 0, 1, 1, 0);
- if (ctrl_hdlr->error)
+ if (ctrl_hdlr->error) {
+ v4l2_ctrl_handler_free(ctrl_hdlr);
return ctrl_hdlr->error;
+ }
+
+ ret = v4l2_fwnode_device_parse(&client->dev, &props);
+ if (ret)
+ goto error;
+
+ ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &ov5675_ctrl_ops,
+ &props);
+ if (ret)
+ goto error;
ov5675->sd.ctrl_handler = ctrl_hdlr;
return 0;
+
+error:
+ v4l2_ctrl_handler_free(ctrl_hdlr);
+
+ return ret;
}
static void ov5675_update_pad_format(const struct ov5675_mode *mode,
@@ -944,6 +977,56 @@ static int ov5675_set_stream(struct v4l2_subdev *sd, int enable)
return ret;
}
+static int ov5675_power_off(struct device *dev)
+{
+ /* 512 xvclk cycles after the last SCCB transation or MIPI frame end */
+ u32 delay_us = DIV_ROUND_UP(512, OV5675_XVCLK_19_2 / 1000 / 1000);
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct ov5675 *ov5675 = to_ov5675(sd);
+
+ usleep_range(delay_us, delay_us * 2);
+
+ clk_disable_unprepare(ov5675->xvclk);
+ gpiod_set_value_cansleep(ov5675->reset_gpio, 1);
+ regulator_bulk_disable(OV5675_NUM_SUPPLIES, ov5675->supplies);
+
+ return 0;
+}
+
+static int ov5675_power_on(struct device *dev)
+{
+ u32 delay_us = DIV_ROUND_UP(8192, OV5675_XVCLK_19_2 / 1000 / 1000);
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct ov5675 *ov5675 = to_ov5675(sd);
+ int ret;
+
+ ret = clk_prepare_enable(ov5675->xvclk);
+ if (ret < 0) {
+ dev_err(dev, "failed to enable xvclk: %d\n", ret);
+ return ret;
+ }
+
+ gpiod_set_value_cansleep(ov5675->reset_gpio, 1);
+
+ ret = regulator_bulk_enable(OV5675_NUM_SUPPLIES, ov5675->supplies);
+ if (ret) {
+ clk_disable_unprepare(ov5675->xvclk);
+ return ret;
+ }
+
+ /* Reset pulse should be at least 2ms and reset gpio released only once
+ * regulators are stable.
+ */
+ usleep_range(2000, 2200);
+
+ gpiod_set_value_cansleep(ov5675->reset_gpio, 0);
+
+ /* 8192 xvclk cycles prior to the first SCCB transation */
+ usleep_range(delay_us, delay_us * 2);
+
+ return 0;
+}
+
static int __maybe_unused ov5675_suspend(struct device *dev)
{
struct v4l2_subdev *sd = dev_get_drvdata(dev);
@@ -1040,6 +1123,31 @@ static int ov5675_get_format(struct v4l2_subdev *sd,
return 0;
}
+static int ov5675_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_selection *sel)
+{
+ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ sel->r.top = 0;
+ sel->r.left = 0;
+ sel->r.width = 2624;
+ sel->r.height = 2000;
+ return 0;
+ case V4L2_SEL_TGT_CROP:
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ sel->r.top = 16;
+ sel->r.left = 16;
+ sel->r.width = 2592;
+ sel->r.height = 1944;
+ return 0;
+ }
+ return -EINVAL;
+}
+
static int ov5675_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
@@ -1089,6 +1197,7 @@ static const struct v4l2_subdev_video_ops ov5675_video_ops = {
static const struct v4l2_subdev_pad_ops ov5675_pad_ops = {
.set_fmt = ov5675_set_format,
.get_fmt = ov5675_get_format,
+ .get_selection = ov5675_get_selection,
.enum_mbus_code = ov5675_enum_mbus_code,
.enum_frame_size = ov5675_enum_frame_size,
};
@@ -1106,32 +1215,60 @@ static const struct v4l2_subdev_internal_ops ov5675_internal_ops = {
.open = ov5675_open,
};
-static int ov5675_check_hwcfg(struct device *dev)
+static int ov5675_get_hwcfg(struct ov5675 *ov5675, struct device *dev)
{
struct fwnode_handle *ep;
struct fwnode_handle *fwnode = dev_fwnode(dev);
struct v4l2_fwnode_endpoint bus_cfg = {
.bus_type = V4L2_MBUS_CSI2_DPHY
};
- u32 mclk;
+ u32 xvclk_rate;
int ret;
unsigned int i, j;
if (!fwnode)
return -ENXIO;
- ret = fwnode_property_read_u32(fwnode, "clock-frequency", &mclk);
+ ov5675->xvclk = devm_clk_get_optional(dev, NULL);
+ if (IS_ERR(ov5675->xvclk))
+ return dev_err_probe(dev, PTR_ERR(ov5675->xvclk),
+ "failed to get xvclk: %ld\n",
+ PTR_ERR(ov5675->xvclk));
- if (ret) {
- dev_err(dev, "can't get clock frequency");
- return ret;
+ if (ov5675->xvclk) {
+ xvclk_rate = clk_get_rate(ov5675->xvclk);
+ } else {
+ ret = fwnode_property_read_u32(fwnode, "clock-frequency",
+ &xvclk_rate);
+
+ if (ret) {
+ dev_err(dev, "can't get clock frequency");
+ return ret;
+ }
}
- if (mclk != OV5675_MCLK) {
- dev_err(dev, "external clock %d is not supported", mclk);
+ if (xvclk_rate != OV5675_XVCLK_19_2) {
+ dev_err(dev, "external clock rate %u is unsupported",
+ xvclk_rate);
return -EINVAL;
}
+ ov5675->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(ov5675->reset_gpio)) {
+ ret = PTR_ERR(ov5675->reset_gpio);
+ dev_err(dev, "failed to get reset-gpios: %d\n", ret);
+ return ret;
+ }
+
+ for (i = 0; i < OV5675_NUM_SUPPLIES; i++)
+ ov5675->supplies[i].supply = ov5675_supply_names[i];
+
+ ret = devm_regulator_bulk_get(dev, OV5675_NUM_SUPPLIES,
+ ov5675->supplies);
+ if (ret)
+ return ret;
+
ep = fwnode_graph_get_next_endpoint(fwnode, NULL);
if (!ep)
return -ENXIO;
@@ -1185,6 +1322,10 @@ static void ov5675_remove(struct i2c_client *client)
v4l2_ctrl_handler_free(sd->ctrl_handler);
pm_runtime_disable(&client->dev);
mutex_destroy(&ov5675->mutex);
+
+ if (!pm_runtime_status_suspended(&client->dev))
+ ov5675_power_off(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
}
static int ov5675_probe(struct i2c_client *client)
@@ -1193,25 +1334,31 @@ static int ov5675_probe(struct i2c_client *client)
bool full_power;
int ret;
- ret = ov5675_check_hwcfg(&client->dev);
+ ov5675 = devm_kzalloc(&client->dev, sizeof(*ov5675), GFP_KERNEL);
+ if (!ov5675)
+ return -ENOMEM;
+
+ ret = ov5675_get_hwcfg(ov5675, &client->dev);
if (ret) {
- dev_err(&client->dev, "failed to check HW configuration: %d",
+ dev_err(&client->dev, "failed to get HW configuration: %d",
ret);
return ret;
}
- ov5675 = devm_kzalloc(&client->dev, sizeof(*ov5675), GFP_KERNEL);
- if (!ov5675)
- return -ENOMEM;
-
v4l2_i2c_subdev_init(&ov5675->sd, client, &ov5675_subdev_ops);
+ ret = ov5675_power_on(&client->dev);
+ if (ret) {
+ dev_err(&client->dev, "failed to power on: %d\n", ret);
+ return ret;
+ }
+
full_power = acpi_dev_state_d0(&client->dev);
if (full_power) {
ret = ov5675_identify_module(ov5675);
if (ret) {
dev_err(&client->dev, "failed to find sensor: %d", ret);
- return ret;
+ goto probe_power_off;
}
}
@@ -1241,11 +1388,6 @@ static int ov5675_probe(struct i2c_client *client)
goto probe_error_media_entity_cleanup;
}
- /*
- * Device is already turned on by i2c-core with ACPI domain PM.
- * Enable runtime PM and turn off the device.
- */
-
/* Set the device's state to active if it's in D0 state. */
if (full_power)
pm_runtime_set_active(&client->dev);
@@ -1260,12 +1402,15 @@ probe_error_media_entity_cleanup:
probe_error_v4l2_ctrl_handler_free:
v4l2_ctrl_handler_free(ov5675->sd.ctrl_handler);
mutex_destroy(&ov5675->mutex);
+probe_power_off:
+ ov5675_power_off(&client->dev);
return ret;
}
static const struct dev_pm_ops ov5675_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(ov5675_suspend, ov5675_resume)
+ SET_RUNTIME_PM_OPS(ov5675_power_off, ov5675_power_on, NULL)
};
#ifdef CONFIG_ACPI
@@ -1277,11 +1422,18 @@ static const struct acpi_device_id ov5675_acpi_ids[] = {
MODULE_DEVICE_TABLE(acpi, ov5675_acpi_ids);
#endif
+static const struct of_device_id ov5675_of_match[] = {
+ { .compatible = "ovti,ov5675", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, ov5675_of_match);
+
static struct i2c_driver ov5675_i2c_driver = {
.driver = {
.name = "ov5675",
.pm = &ov5675_pm_ops,
.acpi_match_table = ACPI_PTR(ov5675_acpi_ids),
+ .of_match_table = ov5675_of_match,
},
.probe_new = ov5675_probe,
.remove = ov5675_remove,
diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c
index 11d3bef65d43..b1bb0833571e 100644
--- a/drivers/media/i2c/ov7670.c
+++ b/drivers/media/i2c/ov7670.c
@@ -1840,16 +1840,16 @@ static int ov7670_parse_dt(struct device *dev,
if (bus_cfg.bus_type != V4L2_MBUS_PARALLEL) {
dev_err(dev, "Unsupported media bus type\n");
- return ret;
+ return -EINVAL;
}
info->mbus_config = bus_cfg.bus.parallel.flags;
return 0;
}
-static int ov7670_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ov7670_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct v4l2_fract tpf;
struct v4l2_subdev *sd;
struct ov7670_info *info;
@@ -2038,7 +2038,7 @@ static struct i2c_driver ov7670_driver = {
.name = "ov7670",
.of_match_table = of_match_ptr(ov7670_of_match),
},
- .probe = ov7670_probe,
+ .probe_new = ov7670_probe,
.remove = ov7670_remove,
.id_table = ov7670_id,
};
diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c
index 4189e3fc3d53..a238e63425f8 100644
--- a/drivers/media/i2c/ov772x.c
+++ b/drivers/media/i2c/ov772x.c
@@ -1462,7 +1462,7 @@ static int ov772x_probe(struct i2c_client *client)
priv->subdev.ctrl_handler = &priv->hdl;
if (priv->hdl.error) {
ret = priv->hdl.error;
- goto error_mutex_destroy;
+ goto error_ctrl_free;
}
priv->clk = clk_get(&client->dev, NULL);
@@ -1515,7 +1515,6 @@ error_clk_put:
clk_put(priv->clk);
error_ctrl_free:
v4l2_ctrl_handler_free(&priv->hdl);
-error_mutex_destroy:
mutex_destroy(&priv->lock);
return ret;
diff --git a/drivers/media/i2c/ov8858.c b/drivers/media/i2c/ov8858.c
new file mode 100644
index 000000000000..9ca8a17bfbb9
--- /dev/null
+++ b/drivers/media/i2c/ov8858.c
@@ -0,0 +1,2008 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Jacopo Mondi <jacopo.mondi@ideasonboard.com>
+ * Copyright (C) 2022 Nicholas Roth <nicholas@rothemail.net>
+ * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd.
+ */
+
+#include <asm/unaligned.h>
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pm_runtime.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+#include <media/media-entity.h>
+#include <media/v4l2-async.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-mediabus.h>
+#include <media/v4l2-subdev.h>
+
+#define OV8858_LINK_FREQ 360000000U
+#define OV8858_XVCLK_FREQ 24000000
+
+#define OV8858_REG_SIZE_SHIFT 16
+#define OV8858_REG_ADDR_MASK 0xffff
+#define OV8858_REG_8BIT(n) ((1U << OV8858_REG_SIZE_SHIFT) | (n))
+#define OV8858_REG_16BIT(n) ((2U << OV8858_REG_SIZE_SHIFT) | (n))
+#define OV8858_REG_24BIT(n) ((3U << OV8858_REG_SIZE_SHIFT) | (n))
+
+#define OV8858_REG_SC_CTRL0100 OV8858_REG_8BIT(0x0100)
+#define OV8858_MODE_SW_STANDBY 0x0
+#define OV8858_MODE_STREAMING 0x1
+
+#define OV8858_REG_CHIP_ID OV8858_REG_24BIT(0x300a)
+#define OV8858_CHIP_ID 0x008858
+
+#define OV8858_REG_SUB_ID OV8858_REG_8BIT(0x302a)
+#define OV8858_R1A 0xb0
+#define OV8858_R2A 0xb2
+
+#define OV8858_REG_LONG_EXPO OV8858_REG_24BIT(0x3500)
+#define OV8858_EXPOSURE_MIN 4
+#define OV8858_EXPOSURE_STEP 1
+#define OV8858_EXPOSURE_MARGIN 4
+
+#define OV8858_REG_LONG_GAIN OV8858_REG_16BIT(0x3508)
+#define OV8858_LONG_GAIN_MIN 0x0
+#define OV8858_LONG_GAIN_MAX 0x7ff
+#define OV8858_LONG_GAIN_STEP 1
+#define OV8858_LONG_GAIN_DEFAULT 0x80
+
+#define OV8858_REG_LONG_DIGIGAIN OV8858_REG_16BIT(0x350a)
+#define OV8858_LONG_DIGIGAIN_H_MASK 0x3fc0
+#define OV8858_LONG_DIGIGAIN_L_MASK 0x3f
+#define OV8858_LONG_DIGIGAIN_H_SHIFT 2
+#define OV8858_LONG_DIGIGAIN_MIN 0x0
+#define OV8858_LONG_DIGIGAIN_MAX 0x3fff
+#define OV8858_LONG_DIGIGAIN_STEP 1
+#define OV8858_LONG_DIGIGAIN_DEFAULT 0x200
+
+#define OV8858_REG_VTS OV8858_REG_16BIT(0x380e)
+#define OV8858_VTS_MAX 0x7fff
+
+#define OV8858_REG_TEST_PATTERN OV8858_REG_8BIT(0x5e00)
+#define OV8858_TEST_PATTERN_ENABLE 0x80
+#define OV8858_TEST_PATTERN_DISABLE 0x0
+
+#define REG_NULL 0xffff
+
+static const char * const ov8858_supply_names[] = {
+ "avdd", /* Analog power */
+ "dovdd", /* Digital I/O power */
+ "dvdd", /* Digital core power */
+};
+
+struct regval {
+ u16 addr;
+ u8 val;
+};
+
+struct regval_modes {
+ const struct regval *mode_2lanes;
+ const struct regval *mode_4lanes;
+};
+
+struct ov8858_mode {
+ u32 width;
+ u32 height;
+ u32 hts_def;
+ u32 vts_def;
+ u32 exp_def;
+ const struct regval_modes reg_modes;
+};
+
+struct ov8858 {
+ struct clk *xvclk;
+ struct gpio_desc *reset_gpio;
+ struct gpio_desc *pwdn_gpio;
+ struct regulator_bulk_data supplies[ARRAY_SIZE(ov8858_supply_names)];
+
+ struct v4l2_subdev subdev;
+ struct media_pad pad;
+
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct v4l2_ctrl *exposure;
+ struct v4l2_ctrl *hblank;
+ struct v4l2_ctrl *vblank;
+
+ const struct regval *global_regs;
+
+ unsigned int num_lanes;
+};
+
+static inline struct ov8858 *sd_to_ov8858(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct ov8858, subdev);
+}
+
+static const struct regval ov8858_global_regs_r1a[] = {
+ {0x0100, 0x00},
+ {0x0100, 0x00},
+ {0x0100, 0x00},
+ {0x0100, 0x00},
+ {0x0302, 0x1e},
+ {0x0303, 0x00},
+ {0x0304, 0x03},
+ {0x030e, 0x00},
+ {0x030f, 0x09},
+ {0x0312, 0x01},
+ {0x031e, 0x0c},
+ {0x3600, 0x00},
+ {0x3601, 0x00},
+ {0x3602, 0x00},
+ {0x3603, 0x00},
+ {0x3604, 0x22},
+ {0x3605, 0x30},
+ {0x3606, 0x00},
+ {0x3607, 0x20},
+ {0x3608, 0x11},
+ {0x3609, 0x28},
+ {0x360a, 0x00},
+ {0x360b, 0x06},
+ {0x360c, 0xdc},
+ {0x360d, 0x40},
+ {0x360e, 0x0c},
+ {0x360f, 0x20},
+ {0x3610, 0x07},
+ {0x3611, 0x20},
+ {0x3612, 0x88},
+ {0x3613, 0x80},
+ {0x3614, 0x58},
+ {0x3615, 0x00},
+ {0x3616, 0x4a},
+ {0x3617, 0xb0},
+ {0x3618, 0x56},
+ {0x3619, 0x70},
+ {0x361a, 0x99},
+ {0x361b, 0x00},
+ {0x361c, 0x07},
+ {0x361d, 0x00},
+ {0x361e, 0x00},
+ {0x361f, 0x00},
+ {0x3638, 0xff},
+ {0x3633, 0x0c},
+ {0x3634, 0x0c},
+ {0x3635, 0x0c},
+ {0x3636, 0x0c},
+ {0x3645, 0x13},
+ {0x3646, 0x83},
+ {0x364a, 0x07},
+ {0x3015, 0x01},
+ {0x3018, 0x32},
+ {0x3020, 0x93},
+ {0x3022, 0x01},
+ {0x3031, 0x0a},
+ {0x3034, 0x00},
+ {0x3106, 0x01},
+ {0x3305, 0xf1},
+ {0x3308, 0x00},
+ {0x3309, 0x28},
+ {0x330a, 0x00},
+ {0x330b, 0x20},
+ {0x330c, 0x00},
+ {0x330d, 0x00},
+ {0x330e, 0x00},
+ {0x330f, 0x40},
+ {0x3307, 0x04},
+ {0x3500, 0x00},
+ {0x3501, 0x4d},
+ {0x3502, 0x40},
+ {0x3503, 0x00},
+ {0x3505, 0x80},
+ {0x3508, 0x04},
+ {0x3509, 0x00},
+ {0x350c, 0x00},
+ {0x350d, 0x80},
+ {0x3510, 0x00},
+ {0x3511, 0x02},
+ {0x3512, 0x00},
+ {0x3700, 0x18},
+ {0x3701, 0x0c},
+ {0x3702, 0x28},
+ {0x3703, 0x19},
+ {0x3704, 0x14},
+ {0x3705, 0x00},
+ {0x3706, 0x35},
+ {0x3707, 0x04},
+ {0x3708, 0x24},
+ {0x3709, 0x33},
+ {0x370a, 0x00},
+ {0x370b, 0xb5},
+ {0x370c, 0x04},
+ {0x3718, 0x12},
+ {0x3719, 0x31},
+ {0x3712, 0x42},
+ {0x3714, 0x24},
+ {0x371e, 0x19},
+ {0x371f, 0x40},
+ {0x3720, 0x05},
+ {0x3721, 0x05},
+ {0x3724, 0x06},
+ {0x3725, 0x01},
+ {0x3726, 0x06},
+ {0x3728, 0x05},
+ {0x3729, 0x02},
+ {0x372a, 0x03},
+ {0x372b, 0x53},
+ {0x372c, 0xa3},
+ {0x372d, 0x53},
+ {0x372e, 0x06},
+ {0x372f, 0x10},
+ {0x3730, 0x01},
+ {0x3731, 0x06},
+ {0x3732, 0x14},
+ {0x3733, 0x10},
+ {0x3734, 0x40},
+ {0x3736, 0x20},
+ {0x373a, 0x05},
+ {0x373b, 0x06},
+ {0x373c, 0x0a},
+ {0x373e, 0x03},
+ {0x3755, 0x10},
+ {0x3758, 0x00},
+ {0x3759, 0x4c},
+ {0x375a, 0x06},
+ {0x375b, 0x13},
+ {0x375c, 0x20},
+ {0x375d, 0x02},
+ {0x375e, 0x00},
+ {0x375f, 0x14},
+ {0x3768, 0x22},
+ {0x3769, 0x44},
+ {0x376a, 0x44},
+ {0x3761, 0x00},
+ {0x3762, 0x00},
+ {0x3763, 0x00},
+ {0x3766, 0xff},
+ {0x376b, 0x00},
+ {0x3772, 0x23},
+ {0x3773, 0x02},
+ {0x3774, 0x16},
+ {0x3775, 0x12},
+ {0x3776, 0x04},
+ {0x3777, 0x00},
+ {0x3778, 0x1b},
+ {0x37a0, 0x44},
+ {0x37a1, 0x3d},
+ {0x37a2, 0x3d},
+ {0x37a3, 0x00},
+ {0x37a4, 0x00},
+ {0x37a5, 0x00},
+ {0x37a6, 0x00},
+ {0x37a7, 0x44},
+ {0x37a8, 0x4c},
+ {0x37a9, 0x4c},
+ {0x3760, 0x00},
+ {0x376f, 0x01},
+ {0x37aa, 0x44},
+ {0x37ab, 0x2e},
+ {0x37ac, 0x2e},
+ {0x37ad, 0x33},
+ {0x37ae, 0x0d},
+ {0x37af, 0x0d},
+ {0x37b0, 0x00},
+ {0x37b1, 0x00},
+ {0x37b2, 0x00},
+ {0x37b3, 0x42},
+ {0x37b4, 0x42},
+ {0x37b5, 0x33},
+ {0x37b6, 0x00},
+ {0x37b7, 0x00},
+ {0x37b8, 0x00},
+ {0x37b9, 0xff},
+ {0x3800, 0x00},
+ {0x3801, 0x0c},
+ {0x3802, 0x00},
+ {0x3803, 0x0c},
+ {0x3804, 0x0c},
+ {0x3805, 0xd3},
+ {0x3806, 0x09},
+ {0x3807, 0xa3},
+ {0x3808, 0x06},
+ {0x3809, 0x60},
+ {0x380a, 0x04},
+ {0x380b, 0xc8},
+ {0x380c, 0x07},
+ {0x380d, 0x88},
+ {0x380e, 0x04},
+ {0x380f, 0xdc},
+ {0x3810, 0x00},
+ {0x3811, 0x04},
+ {0x3813, 0x02},
+ {0x3814, 0x03},
+ {0x3815, 0x01},
+ {0x3820, 0x00},
+ {0x3821, 0x67},
+ {0x382a, 0x03},
+ {0x382b, 0x01},
+ {0x3830, 0x08},
+ {0x3836, 0x02},
+ {0x3837, 0x18},
+ {0x3841, 0xff},
+ {0x3846, 0x48},
+ {0x3d85, 0x14},
+ {0x3f08, 0x08},
+ {0x3f0a, 0x80},
+ {0x4000, 0xf1},
+ {0x4001, 0x10},
+ {0x4005, 0x10},
+ {0x4002, 0x27},
+ {0x4009, 0x81},
+ {0x400b, 0x0c},
+ {0x401b, 0x00},
+ {0x401d, 0x00},
+ {0x4020, 0x00},
+ {0x4021, 0x04},
+ {0x4022, 0x04},
+ {0x4023, 0xb9},
+ {0x4024, 0x05},
+ {0x4025, 0x2a},
+ {0x4026, 0x05},
+ {0x4027, 0x2b},
+ {0x4028, 0x00},
+ {0x4029, 0x02},
+ {0x402a, 0x04},
+ {0x402b, 0x04},
+ {0x402c, 0x02},
+ {0x402d, 0x02},
+ {0x402e, 0x08},
+ {0x402f, 0x02},
+ {0x401f, 0x00},
+ {0x4034, 0x3f},
+ {0x403d, 0x04},
+ {0x4300, 0xff},
+ {0x4301, 0x00},
+ {0x4302, 0x0f},
+ {0x4316, 0x00},
+ {0x4500, 0x38},
+ {0x4503, 0x18},
+ {0x4600, 0x00},
+ {0x4601, 0xcb},
+ {0x481f, 0x32},
+ {0x4837, 0x16},
+ {0x4850, 0x10},
+ {0x4851, 0x32},
+ {0x4b00, 0x2a},
+ {0x4b0d, 0x00},
+ {0x4d00, 0x04},
+ {0x4d01, 0x18},
+ {0x4d02, 0xc3},
+ {0x4d03, 0xff},
+ {0x4d04, 0xff},
+ {0x4d05, 0xff},
+ {0x5000, 0x7e},
+ {0x5001, 0x01},
+ {0x5002, 0x08},
+ {0x5003, 0x20},
+ {0x5046, 0x12},
+ {0x5901, 0x00},
+ {0x5e00, 0x00},
+ {0x5e01, 0x41},
+ {0x382d, 0x7f},
+ {0x4825, 0x3a},
+ {0x4826, 0x40},
+ {0x4808, 0x25},
+ {REG_NULL, 0x00},
+};
+
+static const struct regval ov8858_global_regs_r2a_2lane[] = {
+ /*
+ * MIPI=720Mbps, SysClk=144Mhz,Dac Clock=360Mhz.
+ * v00_01_00 (05/29/2014) : initial setting
+ * AM19 : 3617 <- 0xC0
+ * AM20 : change FWC_6K_EN to be default 0x3618=0x5a
+ */
+ {0x0103, 0x01}, /* software reset */
+ {0x0100, 0x00}, /* software standby */
+ {0x0302, 0x1e}, /* pll1_multi */
+ {0x0303, 0x00}, /* pll1_divm */
+ {0x0304, 0x03}, /* pll1_div_mipi */
+ {0x030e, 0x02}, /* pll2_rdiv */
+ {0x030f, 0x04}, /* pll2_divsp */
+ {0x0312, 0x03}, /* pll2_pre_div0, pll2_r_divdac */
+ {0x031e, 0x0c}, /* pll1_no_lat */
+ {0x3600, 0x00},
+ {0x3601, 0x00},
+ {0x3602, 0x00},
+ {0x3603, 0x00},
+ {0x3604, 0x22},
+ {0x3605, 0x20},
+ {0x3606, 0x00},
+ {0x3607, 0x20},
+ {0x3608, 0x11},
+ {0x3609, 0x28},
+ {0x360a, 0x00},
+ {0x360b, 0x05},
+ {0x360c, 0xd4},
+ {0x360d, 0x40},
+ {0x360e, 0x0c},
+ {0x360f, 0x20},
+ {0x3610, 0x07},
+ {0x3611, 0x20},
+ {0x3612, 0x88},
+ {0x3613, 0x80},
+ {0x3614, 0x58},
+ {0x3615, 0x00},
+ {0x3616, 0x4a},
+ {0x3617, 0x90},
+ {0x3618, 0x5a},
+ {0x3619, 0x70},
+ {0x361a, 0x99},
+ {0x361b, 0x0a},
+ {0x361c, 0x07},
+ {0x361d, 0x00},
+ {0x361e, 0x00},
+ {0x361f, 0x00},
+ {0x3638, 0xff},
+ {0x3633, 0x0f},
+ {0x3634, 0x0f},
+ {0x3635, 0x0f},
+ {0x3636, 0x12},
+ {0x3645, 0x13},
+ {0x3646, 0x83},
+ {0x364a, 0x07},
+ {0x3015, 0x00},
+ {0x3018, 0x32}, /* MIPI 2 lane */
+ {0x3020, 0x93}, /* Clock switch output normal, pclk_div =/1 */
+ {0x3022, 0x01}, /* pd_mipi enable when rst_sync */
+ {0x3031, 0x0a}, /* MIPI 10-bit mode */
+ {0x3034, 0x00},
+ {0x3106, 0x01}, /* sclk_div, sclk_pre_div */
+ {0x3305, 0xf1},
+ {0x3308, 0x00},
+ {0x3309, 0x28},
+ {0x330a, 0x00},
+ {0x330b, 0x20},
+ {0x330c, 0x00},
+ {0x330d, 0x00},
+ {0x330e, 0x00},
+ {0x330f, 0x40},
+ {0x3307, 0x04},
+ {0x3500, 0x00}, /* exposure H */
+ {0x3501, 0x4d}, /* exposure M */
+ {0x3502, 0x40}, /* exposure L */
+ {0x3503, 0x80}, /* gain delay ?, exposure delay 1 frame, real gain */
+ {0x3505, 0x80}, /* gain option */
+ {0x3508, 0x02}, /* gain H */
+ {0x3509, 0x00}, /* gain L */
+ {0x350c, 0x00}, /* short gain H */
+ {0x350d, 0x80}, /* short gain L */
+ {0x3510, 0x00}, /* short exposure H */
+ {0x3511, 0x02}, /* short exposure M */
+ {0x3512, 0x00}, /* short exposure L */
+ {0x3700, 0x18},
+ {0x3701, 0x0c},
+ {0x3702, 0x28},
+ {0x3703, 0x19},
+ {0x3704, 0x14},
+ {0x3705, 0x00},
+ {0x3706, 0x82},
+ {0x3707, 0x04},
+ {0x3708, 0x24},
+ {0x3709, 0x33},
+ {0x370a, 0x01},
+ {0x370b, 0x82},
+ {0x370c, 0x04},
+ {0x3718, 0x12},
+ {0x3719, 0x31},
+ {0x3712, 0x42},
+ {0x3714, 0x24},
+ {0x371e, 0x19},
+ {0x371f, 0x40},
+ {0x3720, 0x05},
+ {0x3721, 0x05},
+ {0x3724, 0x06},
+ {0x3725, 0x01},
+ {0x3726, 0x06},
+ {0x3728, 0x05},
+ {0x3729, 0x02},
+ {0x372a, 0x03},
+ {0x372b, 0x53},
+ {0x372c, 0xa3},
+ {0x372d, 0x53},
+ {0x372e, 0x06},
+ {0x372f, 0x10},
+ {0x3730, 0x01},
+ {0x3731, 0x06},
+ {0x3732, 0x14},
+ {0x3733, 0x10},
+ {0x3734, 0x40},
+ {0x3736, 0x20},
+ {0x373a, 0x05},
+ {0x373b, 0x06},
+ {0x373c, 0x0a},
+ {0x373e, 0x03},
+ {0x3750, 0x0a},
+ {0x3751, 0x0e},
+ {0x3755, 0x10},
+ {0x3758, 0x00},
+ {0x3759, 0x4c},
+ {0x375a, 0x06},
+ {0x375b, 0x13},
+ {0x375c, 0x20},
+ {0x375d, 0x02},
+ {0x375e, 0x00},
+ {0x375f, 0x14},
+ {0x3768, 0x22},
+ {0x3769, 0x44},
+ {0x376a, 0x44},
+ {0x3761, 0x00},
+ {0x3762, 0x00},
+ {0x3763, 0x00},
+ {0x3766, 0xff},
+ {0x376b, 0x00},
+ {0x3772, 0x23},
+ {0x3773, 0x02},
+ {0x3774, 0x16},
+ {0x3775, 0x12},
+ {0x3776, 0x04},
+ {0x3777, 0x00},
+ {0x3778, 0x17},
+ {0x37a0, 0x44},
+ {0x37a1, 0x3d},
+ {0x37a2, 0x3d},
+ {0x37a3, 0x00},
+ {0x37a4, 0x00},
+ {0x37a5, 0x00},
+ {0x37a6, 0x00},
+ {0x37a7, 0x44},
+ {0x37a8, 0x4c},
+ {0x37a9, 0x4c},
+ {0x3760, 0x00},
+ {0x376f, 0x01},
+ {0x37aa, 0x44},
+ {0x37ab, 0x2e},
+ {0x37ac, 0x2e},
+ {0x37ad, 0x33},
+ {0x37ae, 0x0d},
+ {0x37af, 0x0d},
+ {0x37b0, 0x00},
+ {0x37b1, 0x00},
+ {0x37b2, 0x00},
+ {0x37b3, 0x42},
+ {0x37b4, 0x42},
+ {0x37b5, 0x31},
+ {0x37b6, 0x00},
+ {0x37b7, 0x00},
+ {0x37b8, 0x00},
+ {0x37b9, 0xff},
+ {0x3800, 0x00}, /* x start H */
+ {0x3801, 0x0c}, /* x start L */
+ {0x3802, 0x00}, /* y start H */
+ {0x3803, 0x0c}, /* y start L */
+ {0x3804, 0x0c}, /* x end H */
+ {0x3805, 0xd3}, /* x end L */
+ {0x3806, 0x09}, /* y end H */
+ {0x3807, 0xa3}, /* y end L */
+ {0x3808, 0x06}, /* x output size H */
+ {0x3809, 0x60}, /* x output size L */
+ {0x380a, 0x04}, /* y output size H */
+ {0x380b, 0xc8}, /* y output size L */
+ {0x380c, 0x07}, /* HTS H */
+ {0x380d, 0x88}, /* HTS L */
+ {0x380e, 0x04}, /* VTS H */
+ {0x380f, 0xdc}, /* VTS L */
+ {0x3810, 0x00}, /* ISP x win H */
+ {0x3811, 0x04}, /* ISP x win L */
+ {0x3813, 0x02}, /* ISP y win L */
+ {0x3814, 0x03}, /* x odd inc */
+ {0x3815, 0x01}, /* x even inc */
+ {0x3820, 0x00}, /* vflip off */
+ {0x3821, 0x67}, /* mirror on, bin on */
+ {0x382a, 0x03}, /* y odd inc */
+ {0x382b, 0x01}, /* y even inc */
+ {0x3830, 0x08},
+ {0x3836, 0x02},
+ {0x3837, 0x18},
+ {0x3841, 0xff}, /* window auto size enable */
+ {0x3846, 0x48},
+ {0x3d85, 0x16}, /* OTP power up load data enable with BIST */
+ {0x3d8c, 0x73}, /* OTP setting start High */
+ {0x3d8d, 0xde}, /* OTP setting start Low */
+ {0x3f08, 0x08},
+ {0x3f0a, 0x00},
+ {0x4000, 0xf1}, /* out_range_trig, format_chg_trig */
+ {0x4001, 0x10}, /* total 128 black column */
+ {0x4005, 0x10}, /* BLC target L */
+ {0x4002, 0x27}, /* value used to limit BLC offset */
+ {0x4009, 0x81}, /* final BLC offset limitation enable */
+ {0x400b, 0x0c}, /* DCBLC on, DCBLC manual mode on */
+ {0x401b, 0x00}, /* zero line R coefficient */
+ {0x401d, 0x00}, /* zoro line T coefficient */
+ {0x4020, 0x00}, /* Anchor left start H */
+ {0x4021, 0x04}, /* Anchor left start L */
+ {0x4022, 0x06}, /* Anchor left end H */
+ {0x4023, 0x00}, /* Anchor left end L */
+ {0x4024, 0x0f}, /* Anchor right start H */
+ {0x4025, 0x2a}, /* Anchor right start L */
+ {0x4026, 0x0f}, /* Anchor right end H */
+ {0x4027, 0x2b}, /* Anchor right end L */
+ {0x4028, 0x00}, /* top zero line start */
+ {0x4029, 0x02}, /* top zero line number */
+ {0x402a, 0x04}, /* top black line start */
+ {0x402b, 0x04}, /* top black line number */
+ {0x402c, 0x00}, /* bottom zero line start */
+ {0x402d, 0x02}, /* bottom zoro line number */
+ {0x402e, 0x04}, /* bottom black line start */
+ {0x402f, 0x04}, /* bottom black line number */
+ {0x401f, 0x00}, /* interpolation x/y disable, Anchor one disable */
+ {0x4034, 0x3f},
+ {0x403d, 0x04}, /* md_precision_en */
+ {0x4300, 0xff}, /* clip max H */
+ {0x4301, 0x00}, /* clip min H */
+ {0x4302, 0x0f}, /* clip min L, clip max L */
+ {0x4316, 0x00},
+ {0x4500, 0x58},
+ {0x4503, 0x18},
+ {0x4600, 0x00},
+ {0x4601, 0xcb},
+ {0x481f, 0x32}, /* clk prepare min */
+ {0x4837, 0x16}, /* global timing */
+ {0x4850, 0x10}, /* lane 1 = 1, lane 0 = 0 */
+ {0x4851, 0x32}, /* lane 3 = 3, lane 2 = 2 */
+ {0x4b00, 0x2a},
+ {0x4b0d, 0x00},
+ {0x4d00, 0x04}, /* temperature sensor */
+ {0x4d01, 0x18},
+ {0x4d02, 0xc3},
+ {0x4d03, 0xff},
+ {0x4d04, 0xff},
+ {0x4d05, 0xff}, /* temperature sensor */
+ {0x5000, 0xfe}, /* lenc on, slave/master AWB gain/statistics enable */
+ {0x5001, 0x01}, /* BLC on */
+ {0x5002, 0x08}, /* H scale off, WBMATCH off, OTP_DPC */
+ {0x5003, 0x20}, /* DPC_DBC buffer control enable, WB */
+ {0x501e, 0x93}, /* enable digital gain */
+ {0x5046, 0x12},
+ {0x5780, 0x3e}, /* DPC */
+ {0x5781, 0x0f},
+ {0x5782, 0x44},
+ {0x5783, 0x02},
+ {0x5784, 0x01},
+ {0x5785, 0x00},
+ {0x5786, 0x00},
+ {0x5787, 0x04},
+ {0x5788, 0x02},
+ {0x5789, 0x0f},
+ {0x578a, 0xfd},
+ {0x578b, 0xf5},
+ {0x578c, 0xf5},
+ {0x578d, 0x03},
+ {0x578e, 0x08},
+ {0x578f, 0x0c},
+ {0x5790, 0x08},
+ {0x5791, 0x04},
+ {0x5792, 0x00},
+ {0x5793, 0x52},
+ {0x5794, 0xa3}, /* DPC */
+ {0x5871, 0x0d}, /* Lenc */
+ {0x5870, 0x18},
+ {0x586e, 0x10},
+ {0x586f, 0x08},
+ {0x58f7, 0x01},
+ {0x58f8, 0x3d}, /* Lenc */
+ {0x5901, 0x00}, /* H skip off, V skip off */
+ {0x5b00, 0x02}, /* OTP DPC start address */
+ {0x5b01, 0x10}, /* OTP DPC start address */
+ {0x5b02, 0x03}, /* OTP DPC end address */
+ {0x5b03, 0xcf}, /* OTP DPC end address */
+ {0x5b05, 0x6c}, /* recover method = 2b11, */
+ {0x5e00, 0x00}, /* use 0x3ff to test pattern off */
+ {0x5e01, 0x41}, /* window cut enable */
+ {0x382d, 0x7f},
+ {0x4825, 0x3a}, /* lpx_p_min */
+ {0x4826, 0x40}, /* hs_prepare_min */
+ {0x4808, 0x25}, /* wake up delay in 1/1024 s */
+ {0x3763, 0x18},
+ {0x3768, 0xcc},
+ {0x470b, 0x28},
+ {0x4202, 0x00},
+ {0x400d, 0x10}, /* BLC offset trigger L */
+ {0x4040, 0x04}, /* BLC gain th2 */
+ {0x403e, 0x04}, /* BLC gain th1 */
+ {0x4041, 0xc6}, /* BLC */
+ {0x3007, 0x80},
+ {0x400a, 0x01},
+ {REG_NULL, 0x00},
+};
+
+/*
+ * Xclk 24Mhz
+ * max_framerate 30fps
+ * mipi_datarate per lane 720Mbps
+ */
+static const struct regval ov8858_1632x1224_regs_2lane[] = {
+ /*
+ * MIPI=720Mbps, SysClk=144Mhz,Dac Clock=360Mhz.
+ * v00_01_00 (05/29/2014) : initial setting
+ * AM19 : 3617 <- 0xC0
+ * AM20 : change FWC_6K_EN to be default 0x3618=0x5a
+ */
+ {0x0100, 0x00},
+ {0x3501, 0x4d}, /* exposure M */
+ {0x3502, 0x40}, /* exposure L */
+ {0x3778, 0x17},
+ {0x3808, 0x06}, /* x output size H */
+ {0x3809, 0x60}, /* x output size L */
+ {0x380a, 0x04}, /* y output size H */
+ {0x380b, 0xc8}, /* y output size L */
+ {0x380c, 0x07}, /* HTS H */
+ {0x380d, 0x88}, /* HTS L */
+ {0x380e, 0x04}, /* VTS H */
+ {0x380f, 0xdc}, /* VTS L */
+ {0x3814, 0x03}, /* x odd inc */
+ {0x3821, 0x67}, /* mirror on, bin on */
+ {0x382a, 0x03}, /* y odd inc */
+ {0x3830, 0x08},
+ {0x3836, 0x02},
+ {0x3f0a, 0x00},
+ {0x4001, 0x10}, /* total 128 black column */
+ {0x4022, 0x06}, /* Anchor left end H */
+ {0x4023, 0x00}, /* Anchor left end L */
+ {0x4025, 0x2a}, /* Anchor right start L */
+ {0x4027, 0x2b}, /* Anchor right end L */
+ {0x402b, 0x04}, /* top black line number */
+ {0x402f, 0x04}, /* bottom black line number */
+ {0x4500, 0x58},
+ {0x4600, 0x00},
+ {0x4601, 0xcb},
+ {0x382d, 0x7f},
+ {0x0100, 0x01},
+ {REG_NULL, 0x00},
+};
+
+/*
+ * Xclk 24Mhz
+ * max_framerate 15fps
+ * mipi_datarate per lane 720Mbps
+ */
+static const struct regval ov8858_3264x2448_regs_2lane[] = {
+ {0x0100, 0x00},
+ {0x3501, 0x9a}, /* exposure M */
+ {0x3502, 0x20}, /* exposure L */
+ {0x3778, 0x1a},
+ {0x3808, 0x0c}, /* x output size H */
+ {0x3809, 0xc0}, /* x output size L */
+ {0x380a, 0x09}, /* y output size H */
+ {0x380b, 0x90}, /* y output size L */
+ {0x380c, 0x07}, /* HTS H */
+ {0x380d, 0x94}, /* HTS L */
+ {0x380e, 0x09}, /* VTS H */
+ {0x380f, 0xaa}, /* VTS L */
+ {0x3814, 0x01}, /* x odd inc */
+ {0x3821, 0x46}, /* mirror on, bin off */
+ {0x382a, 0x01}, /* y odd inc */
+ {0x3830, 0x06},
+ {0x3836, 0x01},
+ {0x3f0a, 0x00},
+ {0x4001, 0x00}, /* total 256 black column */
+ {0x4022, 0x0c}, /* Anchor left end H */
+ {0x4023, 0x60}, /* Anchor left end L */
+ {0x4025, 0x36}, /* Anchor right start L */
+ {0x4027, 0x37}, /* Anchor right end L */
+ {0x402b, 0x08}, /* top black line number */
+ {0x402f, 0x08}, /* bottom black line number */
+ {0x4500, 0x58},
+ {0x4600, 0x01},
+ {0x4601, 0x97},
+ {0x382d, 0xff},
+ {REG_NULL, 0x00},
+};
+
+static const struct regval ov8858_global_regs_r2a_4lane[] = {
+ /*
+ * MIPI=720Mbps, SysClk=144Mhz,Dac Clock=360Mhz.
+ * v00_01_00 (05/29/2014) : initial setting
+ * AM19 : 3617 <- 0xC0
+ * AM20 : change FWC_6K_EN to be default 0x3618=0x5a
+ */
+ {0x0103, 0x01}, /* software reset for OVTATool only */
+ {0x0103, 0x01}, /* software reset */
+ {0x0100, 0x00}, /* software standby */
+ {0x0302, 0x1e}, /* pll1_multi */
+ {0x0303, 0x00}, /* pll1_divm */
+ {0x0304, 0x03}, /* pll1_div_mipi */
+ {0x030e, 0x00}, /* pll2_rdiv */
+ {0x030f, 0x04}, /* pll2_divsp */
+ {0x0312, 0x01}, /* pll2_pre_div0, pll2_r_divdac */
+ {0x031e, 0x0c}, /* pll1_no_lat */
+ {0x3600, 0x00},
+ {0x3601, 0x00},
+ {0x3602, 0x00},
+ {0x3603, 0x00},
+ {0x3604, 0x22},
+ {0x3605, 0x20},
+ {0x3606, 0x00},
+ {0x3607, 0x20},
+ {0x3608, 0x11},
+ {0x3609, 0x28},
+ {0x360a, 0x00},
+ {0x360b, 0x05},
+ {0x360c, 0xd4},
+ {0x360d, 0x40},
+ {0x360e, 0x0c},
+ {0x360f, 0x20},
+ {0x3610, 0x07},
+ {0x3611, 0x20},
+ {0x3612, 0x88},
+ {0x3613, 0x80},
+ {0x3614, 0x58},
+ {0x3615, 0x00},
+ {0x3616, 0x4a},
+ {0x3617, 0x90},
+ {0x3618, 0x5a},
+ {0x3619, 0x70},
+ {0x361a, 0x99},
+ {0x361b, 0x0a},
+ {0x361c, 0x07},
+ {0x361d, 0x00},
+ {0x361e, 0x00},
+ {0x361f, 0x00},
+ {0x3638, 0xff},
+ {0x3633, 0x0f},
+ {0x3634, 0x0f},
+ {0x3635, 0x0f},
+ {0x3636, 0x12},
+ {0x3645, 0x13},
+ {0x3646, 0x83},
+ {0x364a, 0x07},
+ {0x3015, 0x01},
+ {0x3018, 0x72}, /* MIPI 4 lane */
+ {0x3020, 0x93}, /* Clock switch output normal, pclk_div =/1 */
+ {0x3022, 0x01}, /* pd_mipi enable when rst_sync */
+ {0x3031, 0x0a}, /* MIPI 10-bit mode */
+ {0x3034, 0x00},
+ {0x3106, 0x01}, /* sclk_div, sclk_pre_div */
+ {0x3305, 0xf1},
+ {0x3308, 0x00},
+ {0x3309, 0x28},
+ {0x330a, 0x00},
+ {0x330b, 0x20},
+ {0x330c, 0x00},
+ {0x330d, 0x00},
+ {0x330e, 0x00},
+ {0x330f, 0x40},
+ {0x3307, 0x04},
+ {0x3500, 0x00}, /* exposure H */
+ {0x3501, 0x4d}, /* exposure M */
+ {0x3502, 0x40}, /* exposure L */
+ {0x3503, 0x80}, /* gain delay ?, exposure delay 1 frame, real gain */
+ {0x3505, 0x80}, /* gain option */
+ {0x3508, 0x02}, /* gain H */
+ {0x3509, 0x00}, /* gain L */
+ {0x350c, 0x00}, /* short gain H */
+ {0x350d, 0x80}, /* short gain L */
+ {0x3510, 0x00}, /* short exposure H */
+ {0x3511, 0x02}, /* short exposure M */
+ {0x3512, 0x00}, /* short exposure L */
+ {0x3700, 0x30},
+ {0x3701, 0x18},
+ {0x3702, 0x50},
+ {0x3703, 0x32},
+ {0x3704, 0x28},
+ {0x3705, 0x00},
+ {0x3706, 0x82},
+ {0x3707, 0x08},
+ {0x3708, 0x48},
+ {0x3709, 0x66},
+ {0x370a, 0x01},
+ {0x370b, 0x82},
+ {0x370c, 0x07},
+ {0x3718, 0x14},
+ {0x3719, 0x31},
+ {0x3712, 0x44},
+ {0x3714, 0x24},
+ {0x371e, 0x31},
+ {0x371f, 0x7f},
+ {0x3720, 0x0a},
+ {0x3721, 0x0a},
+ {0x3724, 0x0c},
+ {0x3725, 0x02},
+ {0x3726, 0x0c},
+ {0x3728, 0x0a},
+ {0x3729, 0x03},
+ {0x372a, 0x06},
+ {0x372b, 0xa6},
+ {0x372c, 0xa6},
+ {0x372d, 0xa6},
+ {0x372e, 0x0c},
+ {0x372f, 0x20},
+ {0x3730, 0x02},
+ {0x3731, 0x0c},
+ {0x3732, 0x28},
+ {0x3733, 0x10},
+ {0x3734, 0x40},
+ {0x3736, 0x30},
+ {0x373a, 0x0a},
+ {0x373b, 0x0b},
+ {0x373c, 0x14},
+ {0x373e, 0x06},
+ {0x3750, 0x0a},
+ {0x3751, 0x0e},
+ {0x3755, 0x10},
+ {0x3758, 0x00},
+ {0x3759, 0x4c},
+ {0x375a, 0x0c},
+ {0x375b, 0x26},
+ {0x375c, 0x20},
+ {0x375d, 0x04},
+ {0x375e, 0x00},
+ {0x375f, 0x28},
+ {0x3768, 0x22},
+ {0x3769, 0x44},
+ {0x376a, 0x44},
+ {0x3761, 0x00},
+ {0x3762, 0x00},
+ {0x3763, 0x00},
+ {0x3766, 0xff},
+ {0x376b, 0x00},
+ {0x3772, 0x46},
+ {0x3773, 0x04},
+ {0x3774, 0x2c},
+ {0x3775, 0x13},
+ {0x3776, 0x08},
+ {0x3777, 0x00},
+ {0x3778, 0x17},
+ {0x37a0, 0x88},
+ {0x37a1, 0x7a},
+ {0x37a2, 0x7a},
+ {0x37a3, 0x00},
+ {0x37a4, 0x00},
+ {0x37a5, 0x00},
+ {0x37a6, 0x00},
+ {0x37a7, 0x88},
+ {0x37a8, 0x98},
+ {0x37a9, 0x98},
+ {0x3760, 0x00},
+ {0x376f, 0x01},
+ {0x37aa, 0x88},
+ {0x37ab, 0x5c},
+ {0x37ac, 0x5c},
+ {0x37ad, 0x55},
+ {0x37ae, 0x19},
+ {0x37af, 0x19},
+ {0x37b0, 0x00},
+ {0x37b1, 0x00},
+ {0x37b2, 0x00},
+ {0x37b3, 0x84},
+ {0x37b4, 0x84},
+ {0x37b5, 0x60},
+ {0x37b6, 0x00},
+ {0x37b7, 0x00},
+ {0x37b8, 0x00},
+ {0x37b9, 0xff},
+ {0x3800, 0x00}, /* x start H */
+ {0x3801, 0x0c}, /* x start L */
+ {0x3802, 0x00}, /* y start H */
+ {0x3803, 0x0c}, /* y start L */
+ {0x3804, 0x0c}, /* x end H */
+ {0x3805, 0xd3}, /* x end L */
+ {0x3806, 0x09}, /* y end H */
+ {0x3807, 0xa3}, /* y end L */
+ {0x3808, 0x06}, /* x output size H */
+ {0x3809, 0x60}, /* x output size L */
+ {0x380a, 0x04}, /* y output size H */
+ {0x380b, 0xc8}, /* y output size L */
+ {0x380c, 0x07}, /* HTS H */
+ {0x380d, 0x88}, /* HTS L */
+ {0x380e, 0x04}, /* VTS H */
+ {0x380f, 0xdc}, /* VTS L */
+ {0x3810, 0x00}, /* ISP x win H */
+ {0x3811, 0x04}, /* ISP x win L */
+ {0x3813, 0x02}, /* ISP y win L */
+ {0x3814, 0x03}, /* x odd inc */
+ {0x3815, 0x01}, /* x even inc */
+ {0x3820, 0x00}, /* vflip off */
+ {0x3821, 0x67}, /* mirror on, bin o */
+ {0x382a, 0x03}, /* y odd inc */
+ {0x382b, 0x01}, /* y even inc */
+ {0x3830, 0x08},
+ {0x3836, 0x02},
+ {0x3837, 0x18},
+ {0x3841, 0xff}, /* window auto size enable */
+ {0x3846, 0x48},
+ {0x3d85, 0x16}, /* OTP power up load data/setting enable */
+ {0x3d8c, 0x73}, /* OTP setting start High */
+ {0x3d8d, 0xde}, /* OTP setting start Low */
+ {0x3f08, 0x10},
+ {0x3f0a, 0x00},
+ {0x4000, 0xf1}, /* out_range/format_chg/gain/exp_chg trig enable */
+ {0x4001, 0x10}, /* total 128 black column */
+ {0x4005, 0x10}, /* BLC target L */
+ {0x4002, 0x27}, /* value used to limit BLC offset */
+ {0x4009, 0x81}, /* final BLC offset limitation enable */
+ {0x400b, 0x0c}, /* DCBLC on, DCBLC manual mode on */
+ {0x401b, 0x00}, /* zero line R coefficient */
+ {0x401d, 0x00}, /* zoro line T coefficient */
+ {0x4020, 0x00}, /* Anchor left start H */
+ {0x4021, 0x04}, /* Anchor left start L */
+ {0x4022, 0x06}, /* Anchor left end H */
+ {0x4023, 0x00}, /* Anchor left end L */
+ {0x4024, 0x0f}, /* Anchor right start H */
+ {0x4025, 0x2a}, /* Anchor right start L */
+ {0x4026, 0x0f}, /* Anchor right end H */
+ {0x4027, 0x2b}, /* Anchor right end L */
+ {0x4028, 0x00}, /* top zero line start */
+ {0x4029, 0x02}, /* top zero line number */
+ {0x402a, 0x04}, /* top black line start */
+ {0x402b, 0x04}, /* top black line number */
+ {0x402c, 0x00}, /* bottom zero line start */
+ {0x402d, 0x02}, /* bottom zoro line number */
+ {0x402e, 0x04}, /* bottom black line start */
+ {0x402f, 0x04}, /* bottom black line number */
+ {0x401f, 0x00}, /* interpolation x/y disable, Anchor one disable */
+ {0x4034, 0x3f},
+ {0x403d, 0x04}, /* md_precision_en */
+ {0x4300, 0xff}, /* clip max H */
+ {0x4301, 0x00}, /* clip min H */
+ {0x4302, 0x0f}, /* clip min L, clip max L */
+ {0x4316, 0x00},
+ {0x4500, 0x58},
+ {0x4503, 0x18},
+ {0x4600, 0x00},
+ {0x4601, 0xcb},
+ {0x481f, 0x32}, /* clk prepare min */
+ {0x4837, 0x16}, /* global timing */
+ {0x4850, 0x10}, /* lane 1 = 1, lane 0 = 0 */
+ {0x4851, 0x32}, /* lane 3 = 3, lane 2 = 2 */
+ {0x4b00, 0x2a},
+ {0x4b0d, 0x00},
+ {0x4d00, 0x04}, /* temperature sensor */
+ {0x4d01, 0x18},
+ {0x4d02, 0xc3},
+ {0x4d03, 0xff},
+ {0x4d04, 0xff},
+ {0x4d05, 0xff}, /* temperature sensor */
+ {0x5000, 0xfe}, /* lenc on, slave/master AWB gain/statistics enable */
+ {0x5001, 0x01}, /* BLC on */
+ {0x5002, 0x08}, /* WBMATCH sensor's gain, H scale/WBMATCH/OTP_DPC off */
+ {0x5003, 0x20}, /* DPC_DBC buffer control enable, WB */
+ {0x501e, 0x93}, /* enable digital gain */
+ {0x5046, 0x12},
+ {0x5780, 0x3e}, /* DPC */
+ {0x5781, 0x0f},
+ {0x5782, 0x44},
+ {0x5783, 0x02},
+ {0x5784, 0x01},
+ {0x5785, 0x00},
+ {0x5786, 0x00},
+ {0x5787, 0x04},
+ {0x5788, 0x02},
+ {0x5789, 0x0f},
+ {0x578a, 0xfd},
+ {0x578b, 0xf5},
+ {0x578c, 0xf5},
+ {0x578d, 0x03},
+ {0x578e, 0x08},
+ {0x578f, 0x0c},
+ {0x5790, 0x08},
+ {0x5791, 0x04},
+ {0x5792, 0x00},
+ {0x5793, 0x52},
+ {0x5794, 0xa3}, /* DPC */
+ {0x5871, 0x0d}, /* Lenc */
+ {0x5870, 0x18},
+ {0x586e, 0x10},
+ {0x586f, 0x08},
+ {0x58f7, 0x01},
+ {0x58f8, 0x3d}, /* Lenc */
+ {0x5901, 0x00}, /* H skip off, V skip off */
+ {0x5b00, 0x02}, /* OTP DPC start address */
+ {0x5b01, 0x10}, /* OTP DPC start address */
+ {0x5b02, 0x03}, /* OTP DPC end address */
+ {0x5b03, 0xcf}, /* OTP DPC end address */
+ {0x5b05, 0x6c}, /* recover method = 2b11 */
+ {0x5e00, 0x00}, /* use 0x3ff to test pattern off */
+ {0x5e01, 0x41}, /* window cut enable */
+ {0x382d, 0x7f},
+ {0x4825, 0x3a}, /* lpx_p_min */
+ {0x4826, 0x40}, /* hs_prepare_min */
+ {0x4808, 0x25}, /* wake up delay in 1/1024 s */
+ {0x3763, 0x18},
+ {0x3768, 0xcc},
+ {0x470b, 0x28},
+ {0x4202, 0x00},
+ {0x400d, 0x10}, /* BLC offset trigger L */
+ {0x4040, 0x04}, /* BLC gain th2 */
+ {0x403e, 0x04}, /* BLC gain th1 */
+ {0x4041, 0xc6}, /* BLC */
+ {0x3007, 0x80},
+ {0x400a, 0x01},
+ {REG_NULL, 0x00},
+};
+
+/*
+ * Xclk 24Mhz
+ * max_framerate 60fps
+ * mipi_datarate per lane 720Mbps
+ */
+static const struct regval ov8858_1632x1224_regs_4lane[] = {
+ {0x0100, 0x00},
+ {0x3501, 0x4d}, /* exposure M */
+ {0x3502, 0x40}, /* exposure L */
+ {0x3808, 0x06}, /* x output size H */
+ {0x3809, 0x60}, /* x output size L */
+ {0x380a, 0x04}, /* y output size H */
+ {0x380b, 0xc8}, /* y output size L */
+ {0x380c, 0x07}, /* HTS H */
+ {0x380d, 0x88}, /* HTS L */
+ {0x380e, 0x04}, /* VTS H */
+ {0x380f, 0xdc}, /* VTS L */
+ {0x3814, 0x03}, /* x odd inc */
+ {0x3821, 0x67}, /* mirror on, bin on */
+ {0x382a, 0x03}, /* y odd inc */
+ {0x3830, 0x08},
+ {0x3836, 0x02},
+ {0x3f0a, 0x00},
+ {0x4001, 0x10}, /* total 128 black column */
+ {0x4022, 0x06}, /* Anchor left end H */
+ {0x4023, 0x00}, /* Anchor left end L */
+ {0x4025, 0x2a}, /* Anchor right start L */
+ {0x4027, 0x2b}, /* Anchor right end L */
+ {0x402b, 0x04}, /* top black line number */
+ {0x402f, 0x04}, /* bottom black line number */
+ {0x4500, 0x58},
+ {0x4600, 0x00},
+ {0x4601, 0xcb},
+ {0x382d, 0x7f},
+ {0x0100, 0x01},
+ {REG_NULL, 0x00},
+};
+
+/*
+ * Xclk 24Mhz
+ * max_framerate 30fps
+ * mipi_datarate per lane 720Mbps
+ */
+static const struct regval ov8858_3264x2448_regs_4lane[] = {
+ {0x0100, 0x00},
+ {0x3501, 0x9a}, /* exposure M */
+ {0x3502, 0x20}, /* exposure L */
+ {0x3808, 0x0c}, /* x output size H */
+ {0x3809, 0xc0}, /* x output size L */
+ {0x380a, 0x09}, /* y output size H */
+ {0x380b, 0x90}, /* y output size L */
+ {0x380c, 0x07}, /* HTS H */
+ {0x380d, 0x94}, /* HTS L */
+ {0x380e, 0x09}, /* VTS H */
+ {0x380f, 0xaa}, /* VTS L */
+ {0x3814, 0x01}, /* x odd inc */
+ {0x3821, 0x46}, /* mirror on, bin off */
+ {0x382a, 0x01}, /* y odd inc */
+ {0x3830, 0x06},
+ {0x3836, 0x01},
+ {0x3f0a, 0x00},
+ {0x4001, 0x00}, /* total 256 black column */
+ {0x4022, 0x0c}, /* Anchor left end H */
+ {0x4023, 0x60}, /* Anchor left end L */
+ {0x4025, 0x36}, /* Anchor right start L */
+ {0x4027, 0x37}, /* Anchor right end L */
+ {0x402b, 0x08}, /* top black line number */
+ {0x402f, 0x08}, /* interpolation x/y disable, Anchor one disable */
+ {0x4500, 0x58},
+ {0x4600, 0x01},
+ {0x4601, 0x97},
+ {0x382d, 0xff},
+ {REG_NULL, 0x00},
+};
+
+static const struct ov8858_mode ov8858_modes[] = {
+ {
+ .width = 3264,
+ .height = 2448,
+ .exp_def = 2464,
+ .hts_def = 1940 * 2,
+ .vts_def = 2472,
+ .reg_modes = {
+ .mode_2lanes = ov8858_3264x2448_regs_2lane,
+ .mode_4lanes = ov8858_3264x2448_regs_4lane,
+ },
+ },
+ {
+ .width = 1632,
+ .height = 1224,
+ .exp_def = 1232,
+ .hts_def = 1928 * 2,
+ .vts_def = 1244,
+ .reg_modes = {
+ .mode_2lanes = ov8858_1632x1224_regs_2lane,
+ .mode_4lanes = ov8858_1632x1224_regs_4lane,
+ },
+ },
+};
+
+static const s64 link_freq_menu_items[] = {
+ OV8858_LINK_FREQ
+};
+
+static const char * const ov8858_test_pattern_menu[] = {
+ "Disabled",
+ "Vertical Color Bar Type 1",
+ "Vertical Color Bar Type 2",
+ "Vertical Color Bar Type 3",
+ "Vertical Color Bar Type 4"
+};
+
+/* ----------------------------------------------------------------------------
+ * HW access
+ */
+
+static int ov8858_write(struct ov8858 *ov8858, u32 reg, u32 val, int *err)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev);
+ unsigned int len = (reg >> OV8858_REG_SIZE_SHIFT) & 3;
+ u16 addr = reg & OV8858_REG_ADDR_MASK;
+ u8 buf[6];
+ int ret;
+
+ if (err && *err)
+ return *err;
+
+ put_unaligned_be16(addr, buf);
+ put_unaligned_be32(val << (8 * (4 - len)), buf + 2);
+
+ ret = i2c_master_send(client, buf, len + 2);
+ if (ret != len + 2) {
+ ret = ret < 0 ? ret : -EIO;
+ if (err)
+ *err = ret;
+
+ dev_err(&client->dev,
+ "Failed to write reg %u: %d\n", addr, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ov8858_write_array(struct ov8858 *ov8858, const struct regval *regs)
+{
+ unsigned int i;
+ int ret = 0;
+
+ for (i = 0; ret == 0 && regs[i].addr != REG_NULL; ++i) {
+ ov8858_write(ov8858, OV8858_REG_8BIT(regs[i].addr),
+ regs[i].val, &ret);
+ }
+
+ return ret;
+}
+
+static int ov8858_read(struct ov8858 *ov8858, u32 reg, u32 *val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev);
+ __be16 reg_addr_be = cpu_to_be16(reg & OV8858_REG_ADDR_MASK);
+ unsigned int len = (reg >> OV8858_REG_SIZE_SHIFT) & 3;
+ struct i2c_msg msgs[2];
+ __be32 data_be = 0;
+ u8 *data_be_p;
+ int ret;
+
+ data_be_p = (u8 *)&data_be;
+
+ /* Write register address */
+ msgs[0].addr = client->addr;
+ msgs[0].flags = 0;
+ msgs[0].len = 2;
+ msgs[0].buf = (u8 *)&reg_addr_be;
+
+ /* Read data from register */
+ msgs[1].addr = client->addr;
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].len = len;
+ msgs[1].buf = &data_be_p[4 - len];
+
+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (ret != ARRAY_SIZE(msgs)) {
+ ret = ret < 0 ? ret : -EIO;
+ dev_err(&client->dev,
+ "Failed to read reg %u: %d\n", reg, ret);
+ return ret;
+ }
+
+ *val = be32_to_cpu(data_be);
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------------
+ * Streaming
+ */
+
+static int ov8858_start_stream(struct ov8858 *ov8858,
+ struct v4l2_subdev_state *state)
+{
+ struct v4l2_mbus_framefmt *format;
+ const struct ov8858_mode *mode;
+ const struct regval *reg_list;
+ int ret;
+
+ ret = ov8858_write_array(ov8858, ov8858->global_regs);
+ if (ret)
+ return ret;
+
+ format = v4l2_subdev_get_pad_format(&ov8858->subdev, state, 0);
+ mode = v4l2_find_nearest_size(ov8858_modes, ARRAY_SIZE(ov8858_modes),
+ width, height, format->width,
+ format->height);
+
+ reg_list = ov8858->num_lanes == 4
+ ? mode->reg_modes.mode_4lanes
+ : mode->reg_modes.mode_2lanes;
+
+ ret = ov8858_write_array(ov8858, reg_list);
+ if (ret)
+ return ret;
+
+ /* 200 usec max to let PLL stabilize. */
+ fsleep(200);
+
+ ret = __v4l2_ctrl_handler_setup(&ov8858->ctrl_handler);
+ if (ret)
+ return ret;
+
+ ret = ov8858_write(ov8858, OV8858_REG_SC_CTRL0100,
+ OV8858_MODE_STREAMING, NULL);
+ if (ret)
+ return ret;
+
+ /* t5 (fixed) = 10msec before entering streaming state */
+ fsleep(10000);
+
+ return 0;
+}
+
+static int ov8858_stop_stream(struct ov8858 *ov8858)
+{
+ return ov8858_write(ov8858, OV8858_REG_SC_CTRL0100,
+ OV8858_MODE_SW_STANDBY, NULL);
+}
+
+static int ov8858_s_stream(struct v4l2_subdev *sd, int on)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov8858 *ov8858 = sd_to_ov8858(sd);
+ struct v4l2_subdev_state *state;
+ int ret = 0;
+
+ state = v4l2_subdev_lock_and_get_active_state(sd);
+
+ if (on) {
+ ret = pm_runtime_resume_and_get(&client->dev);
+ if (ret < 0)
+ goto unlock_and_return;
+
+ ret = ov8858_start_stream(ov8858, state);
+ if (ret) {
+ dev_err(&client->dev, "Failed to start streaming\n");
+ pm_runtime_put_sync(&client->dev);
+ goto unlock_and_return;
+ }
+ } else {
+ ov8858_stop_stream(ov8858);
+ pm_runtime_mark_last_busy(&client->dev);
+ pm_runtime_put_autosuspend(&client->dev);
+ }
+
+unlock_and_return:
+ v4l2_subdev_unlock_state(state);
+
+ return ret;
+}
+
+static const struct v4l2_subdev_video_ops ov8858_video_ops = {
+ .s_stream = ov8858_s_stream,
+};
+
+/* ----------------------------------------------------------------------------
+ * Pad ops
+ */
+
+static int ov8858_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *fmt)
+{
+ struct ov8858 *ov8858 = sd_to_ov8858(sd);
+ const struct ov8858_mode *mode;
+ s64 h_blank, vblank_def;
+
+ mode = v4l2_find_nearest_size(ov8858_modes, ARRAY_SIZE(ov8858_modes),
+ width, height, fmt->format.width,
+ fmt->format.height);
+
+ fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
+ fmt->format.width = mode->width;
+ fmt->format.height = mode->height;
+ fmt->format.field = V4L2_FIELD_NONE;
+
+ /* Store the format in the current subdev state. */
+ *v4l2_subdev_get_pad_format(sd, state, 0) = fmt->format;
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
+ return 0;
+
+ /* Adjust control limits when a new mode is applied. */
+ h_blank = mode->hts_def - mode->width;
+ __v4l2_ctrl_modify_range(ov8858->hblank, h_blank, h_blank, 1,
+ h_blank);
+
+ vblank_def = mode->vts_def - mode->height;
+ __v4l2_ctrl_modify_range(ov8858->vblank, vblank_def,
+ OV8858_VTS_MAX - mode->height, 1,
+ vblank_def);
+
+ return 0;
+}
+
+static int ov8858_enum_frame_sizes(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ if (fse->index >= ARRAY_SIZE(ov8858_modes))
+ return -EINVAL;
+
+ if (fse->code != MEDIA_BUS_FMT_SBGGR10_1X10)
+ return -EINVAL;
+
+ fse->min_width = ov8858_modes[fse->index].width;
+ fse->max_width = ov8858_modes[fse->index].width;
+ fse->max_height = ov8858_modes[fse->index].height;
+ fse->min_height = ov8858_modes[fse->index].height;
+
+ return 0;
+}
+
+static int ov8858_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->index != 0)
+ return -EINVAL;
+
+ code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
+
+ return 0;
+}
+
+static int ov8858_init_cfg(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
+{
+ const struct ov8858_mode *def_mode = &ov8858_modes[0];
+ struct v4l2_subdev_format fmt = {
+ .which = V4L2_SUBDEV_FORMAT_TRY,
+ .format = {
+ .width = def_mode->width,
+ .height = def_mode->height,
+ },
+ };
+
+ ov8858_set_fmt(sd, sd_state, &fmt);
+
+ return 0;
+}
+
+static const struct v4l2_subdev_pad_ops ov8858_pad_ops = {
+ .init_cfg = ov8858_init_cfg,
+ .enum_mbus_code = ov8858_enum_mbus_code,
+ .enum_frame_size = ov8858_enum_frame_sizes,
+ .get_fmt = v4l2_subdev_get_fmt,
+ .set_fmt = ov8858_set_fmt,
+};
+
+static const struct v4l2_subdev_core_ops ov8858_core_ops = {
+ .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+ .unsubscribe_event = v4l2_event_subdev_unsubscribe,
+};
+
+static const struct v4l2_subdev_ops ov8858_subdev_ops = {
+ .core = &ov8858_core_ops,
+ .video = &ov8858_video_ops,
+ .pad = &ov8858_pad_ops,
+};
+
+/* ----------------------------------------------------------------------------
+ * Controls handling
+ */
+
+static int ov8858_enable_test_pattern(struct ov8858 *ov8858, u32 pattern)
+{
+ u32 val;
+
+ if (pattern)
+ val = (pattern - 1) | OV8858_TEST_PATTERN_ENABLE;
+ else
+ val = OV8858_TEST_PATTERN_DISABLE;
+
+ return ov8858_write(ov8858, OV8858_REG_TEST_PATTERN, val, NULL);
+}
+
+static int ov8858_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct ov8858 *ov8858 = container_of(ctrl->handler,
+ struct ov8858, ctrl_handler);
+
+ struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev);
+ struct v4l2_mbus_framefmt *format;
+ struct v4l2_subdev_state *state;
+ u16 digi_gain;
+ s64 max_exp;
+ int ret;
+
+ /*
+ * The control handler and the subdev state use the same mutex and the
+ * mutex is guaranteed to be locked:
+ * - by the core when s_ctrl is called int the VIDIOC_S_CTRL call path
+ * - by the driver when s_ctrl is called in the s_stream(1) call path
+ */
+ state = v4l2_subdev_get_locked_active_state(&ov8858->subdev);
+ format = v4l2_subdev_get_pad_format(&ov8858->subdev, state, 0);
+
+ /* Propagate change of current control to all related controls */
+ switch (ctrl->id) {
+ case V4L2_CID_VBLANK:
+ /* Update max exposure while meeting expected vblanking */
+ max_exp = format->height + ctrl->val - OV8858_EXPOSURE_MARGIN;
+ __v4l2_ctrl_modify_range(ov8858->exposure,
+ ov8858->exposure->minimum, max_exp,
+ ov8858->exposure->step,
+ ov8858->exposure->default_value);
+ break;
+ }
+
+ if (!pm_runtime_get_if_in_use(&client->dev))
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_EXPOSURE:
+ /* 4 least significant bits of exposure are fractional part */
+ ret = ov8858_write(ov8858, OV8858_REG_LONG_EXPO,
+ ctrl->val << 4, NULL);
+ break;
+ case V4L2_CID_ANALOGUE_GAIN:
+ ret = ov8858_write(ov8858, OV8858_REG_LONG_GAIN,
+ ctrl->val, NULL);
+ break;
+ case V4L2_CID_DIGITAL_GAIN:
+ /*
+ * Digital gain is assembled as:
+ * 0x350a[7:0] = dgain[13:6]
+ * 0x350b[5:0] = dgain[5:0]
+ * Reassemble the control value to write it in one go.
+ */
+ digi_gain = (ctrl->val & OV8858_LONG_DIGIGAIN_L_MASK)
+ | ((ctrl->val & OV8858_LONG_DIGIGAIN_H_MASK) <<
+ OV8858_LONG_DIGIGAIN_H_SHIFT);
+ ret = ov8858_write(ov8858, OV8858_REG_LONG_DIGIGAIN,
+ digi_gain, NULL);
+ break;
+ case V4L2_CID_VBLANK:
+ ret = ov8858_write(ov8858, OV8858_REG_VTS,
+ ctrl->val + format->height, NULL);
+ break;
+ case V4L2_CID_TEST_PATTERN:
+ ret = ov8858_enable_test_pattern(ov8858, ctrl->val);
+ break;
+ default:
+ ret = -EINVAL;
+ dev_warn(&client->dev, "%s Unhandled id: 0x%x\n",
+ __func__, ctrl->id);
+ break;
+ }
+
+ pm_runtime_put(&client->dev);
+
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops ov8858_ctrl_ops = {
+ .s_ctrl = ov8858_set_ctrl,
+};
+
+/* ----------------------------------------------------------------------------
+ * Power Management
+ */
+
+static int ov8858_power_on(struct ov8858 *ov8858)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev);
+ struct device *dev = &client->dev;
+ unsigned long delay_us;
+ int ret;
+
+ if (clk_get_rate(ov8858->xvclk) != OV8858_XVCLK_FREQ)
+ dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
+
+ ret = clk_prepare_enable(ov8858->xvclk);
+ if (ret < 0) {
+ dev_err(dev, "Failed to enable xvclk\n");
+ return ret;
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(ov8858_supply_names),
+ ov8858->supplies);
+ if (ret < 0) {
+ dev_err(dev, "Failed to enable regulators\n");
+ goto disable_clk;
+ }
+
+ /*
+ * The chip manual only suggests 8192 cycles prior to first SCCB
+ * transaction, but a double sleep between the release of gpios
+ * helps with sporadic failures observed at probe time.
+ */
+ delay_us = DIV_ROUND_UP(8192, OV8858_XVCLK_FREQ / 1000 / 1000);
+
+ gpiod_set_value_cansleep(ov8858->reset_gpio, 0);
+ fsleep(delay_us);
+ gpiod_set_value_cansleep(ov8858->pwdn_gpio, 0);
+ fsleep(delay_us);
+
+ return 0;
+
+disable_clk:
+ clk_disable_unprepare(ov8858->xvclk);
+
+ return ret;
+}
+
+static void ov8858_power_off(struct ov8858 *ov8858)
+{
+ gpiod_set_value_cansleep(ov8858->pwdn_gpio, 1);
+ clk_disable_unprepare(ov8858->xvclk);
+ gpiod_set_value_cansleep(ov8858->reset_gpio, 1);
+
+ regulator_bulk_disable(ARRAY_SIZE(ov8858_supply_names),
+ ov8858->supplies);
+}
+
+static int ov8858_runtime_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ov8858 *ov8858 = sd_to_ov8858(sd);
+
+ return ov8858_power_on(ov8858);
+}
+
+static int ov8858_runtime_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ov8858 *ov8858 = sd_to_ov8858(sd);
+
+ ov8858_power_off(ov8858);
+
+ return 0;
+}
+
+static const struct dev_pm_ops ov8858_pm_ops = {
+ SET_RUNTIME_PM_OPS(ov8858_runtime_suspend,
+ ov8858_runtime_resume, NULL)
+};
+
+/* ----------------------------------------------------------------------------
+ * Probe and initialization
+ */
+
+static int ov8858_init_ctrls(struct ov8858 *ov8858)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev);
+ struct v4l2_ctrl_handler *handler = &ov8858->ctrl_handler;
+ const struct ov8858_mode *mode = &ov8858_modes[0];
+ struct v4l2_fwnode_device_properties props;
+ s64 exposure_max, vblank_def;
+ unsigned int pixel_rate;
+ struct v4l2_ctrl *ctrl;
+ u32 h_blank;
+ int ret;
+
+ ret = v4l2_ctrl_handler_init(handler, 10);
+ if (ret)
+ return ret;
+
+ ctrl = v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ,
+ 0, 0, link_freq_menu_items);
+ if (ctrl)
+ ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ /* pixel rate = link frequency * 2 * lanes / bpp */
+ pixel_rate = OV8858_LINK_FREQ * 2 * ov8858->num_lanes / 10;
+ v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE,
+ 0, pixel_rate, 1, pixel_rate);
+
+ h_blank = mode->hts_def - mode->width;
+ ov8858->hblank = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK,
+ h_blank, h_blank, 1, h_blank);
+ if (ov8858->hblank)
+ ov8858->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ vblank_def = mode->vts_def - mode->height;
+ ov8858->vblank = v4l2_ctrl_new_std(handler, &ov8858_ctrl_ops,
+ V4L2_CID_VBLANK, vblank_def,
+ OV8858_VTS_MAX - mode->height,
+ 1, vblank_def);
+
+ exposure_max = mode->vts_def - OV8858_EXPOSURE_MARGIN;
+ ov8858->exposure = v4l2_ctrl_new_std(handler, &ov8858_ctrl_ops,
+ V4L2_CID_EXPOSURE,
+ OV8858_EXPOSURE_MIN,
+ exposure_max, OV8858_EXPOSURE_STEP,
+ mode->exp_def);
+
+ v4l2_ctrl_new_std(handler, &ov8858_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
+ OV8858_LONG_GAIN_MIN, OV8858_LONG_GAIN_MAX,
+ OV8858_LONG_GAIN_STEP, OV8858_LONG_GAIN_DEFAULT);
+
+ v4l2_ctrl_new_std(handler, &ov8858_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
+ OV8858_LONG_DIGIGAIN_MIN, OV8858_LONG_DIGIGAIN_MAX,
+ OV8858_LONG_DIGIGAIN_STEP,
+ OV8858_LONG_DIGIGAIN_DEFAULT);
+
+ v4l2_ctrl_new_std_menu_items(handler, &ov8858_ctrl_ops,
+ V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(ov8858_test_pattern_menu) - 1,
+ 0, 0, ov8858_test_pattern_menu);
+
+ if (handler->error) {
+ ret = handler->error;
+ goto err_free_handler;
+ }
+
+ ret = v4l2_fwnode_device_parse(&client->dev, &props);
+ if (ret)
+ goto err_free_handler;
+
+ ret = v4l2_ctrl_new_fwnode_properties(handler, &ov8858_ctrl_ops,
+ &props);
+ if (ret)
+ goto err_free_handler;
+
+ ov8858->subdev.ctrl_handler = handler;
+
+ return 0;
+
+err_free_handler:
+ dev_err(&client->dev, "Failed to init controls: %d\n", ret);
+ v4l2_ctrl_handler_free(handler);
+
+ return ret;
+}
+
+static int ov8858_check_sensor_id(struct ov8858 *ov8858)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev);
+ u32 id = 0;
+ int ret;
+
+ ret = ov8858_read(ov8858, OV8858_REG_CHIP_ID, &id);
+ if (ret)
+ return ret;
+
+ if (id != OV8858_CHIP_ID) {
+ dev_err(&client->dev, "Unexpected sensor id 0x%x\n", id);
+ return -ENODEV;
+ }
+
+ ret = ov8858_read(ov8858, OV8858_REG_SUB_ID, &id);
+ if (ret)
+ return ret;
+
+ dev_info(&client->dev, "Detected OV8858 sensor, revision 0x%x\n", id);
+
+ if (id == OV8858_R2A) {
+ /* R2A supports 2 and 4 lanes modes. */
+ ov8858->global_regs = ov8858->num_lanes == 4
+ ? ov8858_global_regs_r2a_4lane
+ : ov8858_global_regs_r2a_2lane;
+ } else if (ov8858->num_lanes == 2) {
+ /*
+ * R1A only supports 2 lanes mode and it's only partially
+ * supported.
+ */
+ ov8858->global_regs = ov8858_global_regs_r1a;
+ dev_warn(&client->dev, "R1A may not work well!\n");
+ } else {
+ dev_err(&client->dev,
+ "Unsupported number of data lanes for R1A revision.\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ov8858_configure_regulators(struct ov8858 *ov8858)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev);
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(ov8858_supply_names); i++)
+ ov8858->supplies[i].supply = ov8858_supply_names[i];
+
+ return devm_regulator_bulk_get(&client->dev,
+ ARRAY_SIZE(ov8858_supply_names),
+ ov8858->supplies);
+}
+
+static int ov8858_parse_of(struct ov8858 *ov8858)
+{
+ struct v4l2_fwnode_endpoint vep = { .bus_type = V4L2_MBUS_CSI2_DPHY };
+ struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev);
+ struct device *dev = &client->dev;
+ struct fwnode_handle *endpoint;
+ int ret;
+
+ endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL);
+ if (!endpoint) {
+ dev_err(dev, "Failed to get endpoint\n");
+ return -EINVAL;
+ }
+
+ ret = v4l2_fwnode_endpoint_parse(endpoint, &vep);
+ if (ret) {
+ dev_err(dev, "Failed to parse endpoint: %d\n", ret);
+ fwnode_handle_put(endpoint);
+ return ret;
+ }
+
+ ov8858->num_lanes = vep.bus.mipi_csi2.num_data_lanes;
+ switch (ov8858->num_lanes) {
+ case 4:
+ case 2:
+ break;
+ default:
+ dev_err(dev, "Unsupported number of data lanes %u\n",
+ ov8858->num_lanes);
+ fwnode_handle_put(endpoint);
+ return -EINVAL;
+ }
+
+ ov8858->subdev.fwnode = endpoint;
+
+ return 0;
+}
+
+static int ov8858_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct v4l2_subdev *sd;
+ struct ov8858 *ov8858;
+ int ret;
+
+ ov8858 = devm_kzalloc(dev, sizeof(*ov8858), GFP_KERNEL);
+ if (!ov8858)
+ return -ENOMEM;
+
+ ov8858->xvclk = devm_clk_get(dev, "xvclk");
+ if (IS_ERR(ov8858->xvclk))
+ return dev_err_probe(dev, PTR_ERR(ov8858->xvclk),
+ "Failed to get xvclk\n");
+
+ ov8858->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(ov8858->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(ov8858->reset_gpio),
+ "Failed to get reset gpio\n");
+
+ ov8858->pwdn_gpio = devm_gpiod_get_optional(dev, "powerdown",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(ov8858->pwdn_gpio))
+ return dev_err_probe(dev, PTR_ERR(ov8858->pwdn_gpio),
+ "Failed to get powerdown gpio\n");
+
+ v4l2_i2c_subdev_init(&ov8858->subdev, client, &ov8858_subdev_ops);
+
+ ret = ov8858_configure_regulators(ov8858);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get regulators\n");
+
+ ret = ov8858_parse_of(ov8858);
+ if (ret)
+ return ret;
+
+ ret = ov8858_init_ctrls(ov8858);
+ if (ret)
+ goto err_put_fwnode;
+
+ sd = &ov8858->subdev;
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
+ ov8858->pad.flags = MEDIA_PAD_FL_SOURCE;
+ sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
+ ret = media_entity_pads_init(&sd->entity, 1, &ov8858->pad);
+ if (ret < 0)
+ goto err_free_handler;
+
+ sd->state_lock = ov8858->ctrl_handler.lock;
+ ret = v4l2_subdev_init_finalize(sd);
+ if (ret < 0) {
+ dev_err(&client->dev, "Subdev initialization error %d\n", ret);
+ goto err_clean_entity;
+ }
+
+ ret = ov8858_power_on(ov8858);
+ if (ret)
+ goto err_clean_entity;
+
+ pm_runtime_set_active(dev);
+ pm_runtime_get_noresume(dev);
+ pm_runtime_enable(dev);
+
+ ret = ov8858_check_sensor_id(ov8858);
+ if (ret)
+ goto err_power_off;
+
+ pm_runtime_set_autosuspend_delay(dev, 1000);
+ pm_runtime_use_autosuspend(dev);
+
+ ret = v4l2_async_register_subdev_sensor(sd);
+ if (ret) {
+ dev_err(dev, "v4l2 async register subdev failed\n");
+ goto err_power_off;
+ }
+
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+
+ return 0;
+
+err_power_off:
+ pm_runtime_disable(dev);
+ pm_runtime_put_noidle(dev);
+ ov8858_power_off(ov8858);
+err_clean_entity:
+ media_entity_cleanup(&sd->entity);
+err_free_handler:
+ v4l2_ctrl_handler_free(&ov8858->ctrl_handler);
+err_put_fwnode:
+ fwnode_handle_put(ov8858->subdev.fwnode);
+
+ return ret;
+}
+
+static void ov8858_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ov8858 *ov8858 = sd_to_ov8858(sd);
+
+ v4l2_async_unregister_subdev(sd);
+ media_entity_cleanup(&sd->entity);
+ v4l2_ctrl_handler_free(&ov8858->ctrl_handler);
+ fwnode_handle_put(ov8858->subdev.fwnode);
+
+ pm_runtime_disable(&client->dev);
+ if (!pm_runtime_status_suspended(&client->dev))
+ ov8858_power_off(ov8858);
+ pm_runtime_set_suspended(&client->dev);
+}
+
+static const struct of_device_id ov8858_of_match[] = {
+ { .compatible = "ovti,ov8858" },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, ov8858_of_match);
+
+static struct i2c_driver ov8858_i2c_driver = {
+ .driver = {
+ .name = "ov8858",
+ .pm = &ov8858_pm_ops,
+ .of_match_table = ov8858_of_match,
+ },
+ .probe_new = &ov8858_probe,
+ .remove = &ov8858_remove,
+};
+
+module_i2c_driver(ov8858_i2c_driver);
+
+MODULE_DESCRIPTION("OmniVision OV8858 sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/ov9282.c b/drivers/media/i2c/ov9282.c
index 37a55d53af56..7f46cac38aab 100644
--- a/drivers/media/i2c/ov9282.c
+++ b/drivers/media/i2c/ov9282.c
@@ -148,7 +148,6 @@ struct ov9282_mode {
/**
* struct ov9282 - ov9282 sensor device structure
* @dev: Pointer to generic device
- * @client: Pointer to i2c client
* @sd: V4L2 sub-device
* @pad: Media pad. Only one pad supported
* @reset_gpio: Sensor reset gpio
@@ -170,7 +169,6 @@ struct ov9282_mode {
*/
struct ov9282 {
struct device *dev;
- struct i2c_client *client;
struct v4l2_subdev sd;
struct media_pad pad;
struct gpio_desc *reset_gpio;
@@ -1144,10 +1142,9 @@ static int ov9282_parse_hw_config(struct ov9282 *ov9282)
}
ret = ov9282_configure_regulators(ov9282);
- if (ret) {
- dev_err(ov9282->dev, "Failed to get power regulators\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(ov9282->dev, ret,
+ "Failed to get power regulators\n");
rate = clk_get_rate(ov9282->inclk);
if (rate != OV9282_INCLK_RATE) {
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
index 59b03b0860d5..7938a3327d3e 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c
+++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
@@ -26,7 +26,6 @@
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-mediabus.h>
-#include <media/i2c/s5c73m3.h>
#include <media/v4l2-fwnode.h>
#include "s5c73m3.h"
@@ -436,7 +435,7 @@ static int __s5c73m3_s_stream(struct s5c73m3 *state, struct v4l2_subdev *sd,
state->streaming = !!on;
if (!on)
- return ret;
+ return 0;
if (state->apply_fiv) {
ret = s5c73m3_set_frame_rate(state);
@@ -1522,25 +1521,16 @@ static const struct v4l2_subdev_ops oif_subdev_ops = {
.video = &s5c73m3_oif_video_ops,
};
-static int s5c73m3_get_platform_data(struct s5c73m3 *state)
+static int s5c73m3_get_dt_data(struct s5c73m3 *state)
{
- struct i2c_client *c = state->i2c_client;
- struct device *dev = &c->dev;
- const struct s5c73m3_platform_data *pdata = dev->platform_data;
+ struct device *dev = &state->i2c_client->dev;
struct device_node *node = dev->of_node;
struct device_node *node_ep;
struct v4l2_fwnode_endpoint ep = { .bus_type = 0 };
int ret;
- if (!node) {
- if (!pdata) {
- dev_err(dev, "Platform data not specified\n");
- return -EINVAL;
- }
-
- state->mclk_frequency = pdata->mclk_frequency;
- return 0;
- }
+ if (!node)
+ return -EINVAL;
state->clock = devm_clk_get(dev, S5C73M3_CLK_NAME);
if (IS_ERR(state->clock))
@@ -1603,7 +1593,7 @@ static int s5c73m3_probe(struct i2c_client *client)
return -ENOMEM;
state->i2c_client = client;
- ret = s5c73m3_get_platform_data(state);
+ ret = s5c73m3_get_dt_data(state);
if (ret < 0)
return ret;
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c b/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c
index e3543ae384ed..1c8103670fa2 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c
+++ b/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c
@@ -23,7 +23,6 @@
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-mediabus.h>
-#include <media/i2c/s5c73m3.h>
#include "s5c73m3.h"
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3.h b/drivers/media/i2c/s5c73m3/s5c73m3.h
index 1fc7df41c5ee..627e80cf5b72 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3.h
+++ b/drivers/media/i2c/s5c73m3/s5c73m3.h
@@ -16,7 +16,6 @@
#include <media/v4l2-common.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-subdev.h>
-#include <media/i2c/s5c73m3.h>
#define DRIVER_NAME "S5C73M3"
diff --git a/drivers/media/i2c/saa7115.c b/drivers/media/i2c/saa7115.c
index 86e70a980218..efeda3956f81 100644
--- a/drivers/media/i2c/saa7115.c
+++ b/drivers/media/i2c/saa7115.c
@@ -1804,9 +1804,9 @@ static int saa711x_detect_chip(struct i2c_client *client,
return -ENODEV;
}
-static int saa711x_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int saa711x_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct saa711x_state *state;
struct v4l2_subdev *sd;
struct v4l2_ctrl_handler *hdl;
@@ -1951,7 +1951,7 @@ static struct i2c_driver saa711x_driver = {
.driver = {
.name = "saa7115",
},
- .probe = saa711x_probe,
+ .probe_new = saa711x_probe,
.remove = saa711x_remove,
.id_table = saa711x_id,
};
diff --git a/drivers/media/i2c/saa7127.c b/drivers/media/i2c/saa7127.c
index 78c9388c2ea1..f98f3a1c38a9 100644
--- a/drivers/media/i2c/saa7127.c
+++ b/drivers/media/i2c/saa7127.c
@@ -708,9 +708,9 @@ static const struct v4l2_subdev_ops saa7127_ops = {
/* ----------------------------------------------------------------------- */
-static int saa7127_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int saa7127_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct saa7127_state *state;
struct v4l2_subdev *sd;
struct v4l2_sliced_vbi_data vbi = { 0, 0, 0, 0 }; /* set to disabled */
@@ -810,7 +810,7 @@ static struct i2c_driver saa7127_driver = {
.driver = {
.name = "saa7127",
},
- .probe = saa7127_probe,
+ .probe_new = saa7127_probe,
.remove = saa7127_remove,
.id_table = saa7127_id,
};
diff --git a/drivers/media/i2c/st-vgxy61.c b/drivers/media/i2c/st-vgxy61.c
index 826baf4e064d..5dcabee6677d 100644
--- a/drivers/media/i2c/st-vgxy61.c
+++ b/drivers/media/i2c/st-vgxy61.c
@@ -5,7 +5,6 @@
* Copyright (C) 2022 STMicroelectronics SA
*/
-#include <asm-generic/unaligned.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
@@ -15,6 +14,9 @@
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/units.h>
+
+#include <asm/unaligned.h>
+
#include <media/mipi-csi2.h>
#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
diff --git a/drivers/media/i2c/tc358746.c b/drivers/media/i2c/tc358746.c
index d1f552bd81d4..4063754a6732 100644
--- a/drivers/media/i2c/tc358746.c
+++ b/drivers/media/i2c/tc358746.c
@@ -406,7 +406,7 @@ tc358746_apply_pll_config(struct tc358746 *tc358746)
val = PLL_FRS(ilog2(post)) | RESETB | PLL_EN;
mask = PLL_FRS_MASK | RESETB | PLL_EN;
- tc358746_update_bits(tc358746, PLLCTL1_REG, mask, val);
+ err = tc358746_update_bits(tc358746, PLLCTL1_REG, mask, val);
if (err)
return err;
@@ -988,6 +988,8 @@ static int __maybe_unused
tc358746_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
{
struct tc358746 *tc358746 = to_tc358746(sd);
+ u32 val;
+ int err;
/* 32-bit registers starting from CLW_DPHYCONTTX */
reg->size = reg->reg < CLW_DPHYCONTTX_REG ? 2 : 4;
@@ -995,12 +997,13 @@ tc358746_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
if (!pm_runtime_get_if_in_use(sd->dev))
return 0;
- tc358746_read(tc358746, reg->reg, (u32 *)&reg->val);
+ err = tc358746_read(tc358746, reg->reg, &val);
+ reg->val = val;
pm_runtime_mark_last_busy(sd->dev);
pm_runtime_put_sync_autosuspend(sd->dev);
- return 0;
+ return err;
}
static int __maybe_unused
diff --git a/drivers/media/i2c/tda1997x.c b/drivers/media/i2c/tda1997x.c
index 83931826cf6f..27f6393dc327 100644
--- a/drivers/media/i2c/tda1997x.c
+++ b/drivers/media/i2c/tda1997x.c
@@ -2519,9 +2519,9 @@ static struct snd_soc_component_driver tda1997x_codec_driver = {
.endianness = 1,
};
-static int tda1997x_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int tda1997x_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct tda1997x_state *state;
struct tda1997x_platform_data *pdata;
struct v4l2_subdev *sd;
@@ -2834,7 +2834,7 @@ static struct i2c_driver tda1997x_i2c_driver = {
.name = "tda1997x",
.of_match_table = of_match_ptr(tda1997x_of_id),
},
- .probe = tda1997x_probe,
+ .probe_new = tda1997x_probe,
.remove = tda1997x_remove,
.id_table = tda1997x_i2c_id,
};
diff --git a/drivers/media/i2c/tvaudio.c b/drivers/media/i2c/tvaudio.c
index 9f1ed078b661..a54c76d9e23b 100644
--- a/drivers/media/i2c/tvaudio.c
+++ b/drivers/media/i2c/tvaudio.c
@@ -1934,8 +1934,9 @@ static const struct v4l2_subdev_ops tvaudio_ops = {
/* i2c registration */
-static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id *id)
+static int tvaudio_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct CHIPSTATE *chip;
struct CHIPDESC *desc;
struct v4l2_subdev *sd;
@@ -2094,7 +2095,7 @@ static struct i2c_driver tvaudio_driver = {
.driver = {
.name = "tvaudio",
},
- .probe = tvaudio_probe,
+ .probe_new = tvaudio_probe,
.remove = tvaudio_remove,
.id_table = tvaudio_id,
};
diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c
index a746d96875f9..f294cae72b01 100644
--- a/drivers/media/i2c/tvp514x.c
+++ b/drivers/media/i2c/tvp514x.c
@@ -1017,14 +1017,14 @@ done:
/**
* tvp514x_probe() - decoder driver i2c probe handler
* @client: i2c driver client device structure
- * @id: i2c driver id table
*
* Register decoder as an i2c client device and V4L2
* device.
*/
static int
-tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id)
+tvp514x_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct tvp514x_platform_data *pdata = tvp514x_get_pdata(client);
struct tvp514x_decoder *decoder;
struct v4l2_subdev *sd;
@@ -1208,7 +1208,7 @@ static struct i2c_driver tvp514x_driver = {
.of_match_table = of_match_ptr(tvp514x_of_match),
.name = TVP514X_MODULE_NAME,
},
- .probe = tvp514x_probe,
+ .probe_new = tvp514x_probe,
.remove = tvp514x_remove,
.id_table = tvp514x_id,
};
diff --git a/drivers/media/i2c/video-i2c.c b/drivers/media/i2c/video-i2c.c
index f15ef2d13059..dddf9827b314 100644
--- a/drivers/media/i2c/video-i2c.c
+++ b/drivers/media/i2c/video-i2c.c
@@ -757,9 +757,9 @@ static void video_i2c_release(struct video_device *vdev)
kfree(data);
}
-static int video_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int video_i2c_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct video_i2c_data *data;
struct v4l2_device *v4l2_dev;
struct vb2_queue *queue;
@@ -959,7 +959,7 @@ static struct i2c_driver video_i2c_driver = {
.of_match_table = video_i2c_of_match,
.pm = &video_i2c_pm_ops,
},
- .probe = video_i2c_probe,
+ .probe_new = video_i2c_probe,
.remove = video_i2c_remove,
.id_table = video_i2c_id_table,
};
diff --git a/drivers/media/mc/mc-entity.c b/drivers/media/mc/mc-entity.c
index b8bcbc734eaf..e7216a985ba6 100644
--- a/drivers/media/mc/mc-entity.c
+++ b/drivers/media/mc/mc-entity.c
@@ -226,7 +226,13 @@ EXPORT_SYMBOL_GPL(media_entity_pads_init);
* Graph traversal
*/
-/*
+/**
+ * media_entity_has_pad_interdep - Check interdependency between two pads
+ *
+ * @entity: The entity
+ * @pad0: The first pad index
+ * @pad1: The second pad index
+ *
* This function checks the interdependency inside the entity between @pad0
* and @pad1. If two pads are interdependent they are part of the same pipeline
* and enabling one of the pads means that the other pad will become "locked"
@@ -236,6 +242,13 @@ EXPORT_SYMBOL_GPL(media_entity_pads_init);
* to check the dependency inside the entity between @pad0 and @pad1. If the
* has_pad_interdep operation is not implemented, all pads of the entity are
* considered to be interdependent.
+ *
+ * One of @pad0 and @pad1 must be a sink pad and the other one a source pad.
+ * The function returns false if both pads are sinks or sources.
+ *
+ * The caller must hold entity->graph_obj.mdev->mutex.
+ *
+ * Return: true if the pads are connected internally and false otherwise.
*/
static bool media_entity_has_pad_interdep(struct media_entity *entity,
unsigned int pad0, unsigned int pad1)
@@ -295,7 +308,7 @@ static struct media_entity *stack_pop(struct media_graph *graph)
*
* Reserve resources for graph walk in media device's current
* state. The memory must be released using
- * media_graph_walk_free().
+ * media_graph_walk_cleanup().
*
* Returns error on failure, zero on success.
*/
@@ -703,7 +716,7 @@ done:
__must_check int __media_pipeline_start(struct media_pad *pad,
struct media_pipeline *pipe)
{
- struct media_device *mdev = pad->entity->graph_obj.mdev;
+ struct media_device *mdev = pad->graph_obj.mdev;
struct media_pipeline_pad *err_ppad;
struct media_pipeline_pad *ppad;
int ret;
@@ -711,8 +724,8 @@ __must_check int __media_pipeline_start(struct media_pad *pad,
lockdep_assert_held(&mdev->graph_mutex);
/*
- * If the entity is already part of a pipeline, that pipeline must
- * be the same as the pipe given to media_pipeline_start().
+ * If the pad is already part of a pipeline, that pipeline must be the
+ * same as the pipe given to media_pipeline_start().
*/
if (WARN_ON(pad->pipe && pad->pipe != pipe))
return -EINVAL;
@@ -851,7 +864,7 @@ EXPORT_SYMBOL_GPL(__media_pipeline_start);
__must_check int media_pipeline_start(struct media_pad *pad,
struct media_pipeline *pipe)
{
- struct media_device *mdev = pad->entity->graph_obj.mdev;
+ struct media_device *mdev = pad->graph_obj.mdev;
int ret;
mutex_lock(&mdev->graph_mutex);
@@ -888,7 +901,7 @@ EXPORT_SYMBOL_GPL(__media_pipeline_stop);
void media_pipeline_stop(struct media_pad *pad)
{
- struct media_device *mdev = pad->entity->graph_obj.mdev;
+ struct media_device *mdev = pad->graph_obj.mdev;
mutex_lock(&mdev->graph_mutex);
__media_pipeline_stop(pad);
@@ -898,7 +911,7 @@ EXPORT_SYMBOL_GPL(media_pipeline_stop);
__must_check int media_pipeline_alloc_start(struct media_pad *pad)
{
- struct media_device *mdev = pad->entity->graph_obj.mdev;
+ struct media_device *mdev = pad->graph_obj.mdev;
struct media_pipeline *new_pipe = NULL;
struct media_pipeline *pipe;
int ret;
@@ -906,7 +919,7 @@ __must_check int media_pipeline_alloc_start(struct media_pad *pad)
mutex_lock(&mdev->graph_mutex);
/*
- * Is the entity already part of a pipeline? If not, we need to allocate
+ * Is the pad already part of a pipeline? If not, we need to allocate
* a pipe.
*/
pipe = media_pad_pipeline(pad);
@@ -932,6 +945,61 @@ out:
}
EXPORT_SYMBOL_GPL(media_pipeline_alloc_start);
+struct media_pad *
+__media_pipeline_pad_iter_next(struct media_pipeline *pipe,
+ struct media_pipeline_pad_iter *iter,
+ struct media_pad *pad)
+{
+ if (!pad)
+ iter->cursor = pipe->pads.next;
+
+ if (iter->cursor == &pipe->pads)
+ return NULL;
+
+ pad = list_entry(iter->cursor, struct media_pipeline_pad, list)->pad;
+ iter->cursor = iter->cursor->next;
+
+ return pad;
+}
+EXPORT_SYMBOL_GPL(__media_pipeline_pad_iter_next);
+
+int media_pipeline_entity_iter_init(struct media_pipeline *pipe,
+ struct media_pipeline_entity_iter *iter)
+{
+ return media_entity_enum_init(&iter->ent_enum, pipe->mdev);
+}
+EXPORT_SYMBOL_GPL(media_pipeline_entity_iter_init);
+
+void media_pipeline_entity_iter_cleanup(struct media_pipeline_entity_iter *iter)
+{
+ media_entity_enum_cleanup(&iter->ent_enum);
+}
+EXPORT_SYMBOL_GPL(media_pipeline_entity_iter_cleanup);
+
+struct media_entity *
+__media_pipeline_entity_iter_next(struct media_pipeline *pipe,
+ struct media_pipeline_entity_iter *iter,
+ struct media_entity *entity)
+{
+ if (!entity)
+ iter->cursor = pipe->pads.next;
+
+ while (iter->cursor != &pipe->pads) {
+ struct media_pipeline_pad *ppad;
+ struct media_entity *entity;
+
+ ppad = list_entry(iter->cursor, struct media_pipeline_pad, list);
+ entity = ppad->pad->entity;
+ iter->cursor = iter->cursor->next;
+
+ if (!media_entity_enum_test_and_set(&iter->ent_enum, entity))
+ return entity;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(__media_pipeline_entity_iter_next);
+
/* -----------------------------------------------------------------------------
* Links management
*/
diff --git a/drivers/media/pci/Kconfig b/drivers/media/pci/Kconfig
index dff0b450f387..480194543d05 100644
--- a/drivers/media/pci/Kconfig
+++ b/drivers/media/pci/Kconfig
@@ -27,6 +27,7 @@ if MEDIA_ANALOG_TV_SUPPORT
source "drivers/media/pci/dt3155/Kconfig"
source "drivers/media/pci/ivtv/Kconfig"
+source "drivers/media/pci/saa7146/Kconfig"
endif
@@ -57,6 +58,7 @@ source "drivers/media/pci/pluto2/Kconfig"
source "drivers/media/pci/pt1/Kconfig"
source "drivers/media/pci/pt3/Kconfig"
source "drivers/media/pci/smipcie/Kconfig"
+source "drivers/media/pci/ttpci/Kconfig"
endif
diff --git a/drivers/media/pci/Makefile b/drivers/media/pci/Makefile
index 8f887a8a7f17..8bed619b7130 100644
--- a/drivers/media/pci/Makefile
+++ b/drivers/media/pci/Makefile
@@ -5,7 +5,8 @@
# Please keep it alphabetically sorted by directory
# (e. g. LC_ALL=C sort Makefile)
-obj-y += b2c2/ \
+obj-y += ttpci/ \
+ b2c2/ \
pluto2/ \
dm1105/ \
pt1/ \
@@ -13,6 +14,7 @@ obj-y += b2c2/ \
mantis/ \
ngene/ \
ddbridge/ \
+ saa7146/ \
smipcie/ \
netup_unidvb/ \
intel/
diff --git a/drivers/media/pci/intel/ipu3/cio2-bridge.c b/drivers/media/pci/intel/ipu3/cio2-bridge.c
index df6c94da2f6a..dfefe0d8aa95 100644
--- a/drivers/media/pci/intel/ipu3/cio2-bridge.c
+++ b/drivers/media/pci/intel/ipu3/cio2-bridge.c
@@ -195,6 +195,19 @@ static void cio2_bridge_init_swnode_names(struct cio2_sensor *sensor)
SWNODE_GRAPH_ENDPOINT_NAME_FMT, 0); /* And endpoint 0 */
}
+static void cio2_bridge_init_swnode_group(struct cio2_sensor *sensor)
+{
+ struct software_node *nodes = sensor->swnodes;
+
+ sensor->group[SWNODE_SENSOR_HID] = &nodes[SWNODE_SENSOR_HID];
+ sensor->group[SWNODE_SENSOR_PORT] = &nodes[SWNODE_SENSOR_PORT];
+ sensor->group[SWNODE_SENSOR_ENDPOINT] = &nodes[SWNODE_SENSOR_ENDPOINT];
+ sensor->group[SWNODE_CIO2_PORT] = &nodes[SWNODE_CIO2_PORT];
+ sensor->group[SWNODE_CIO2_ENDPOINT] = &nodes[SWNODE_CIO2_ENDPOINT];
+ if (sensor->ssdb.vcmtype)
+ sensor->group[SWNODE_VCM] = &nodes[SWNODE_VCM];
+}
+
static void cio2_bridge_create_connection_swnodes(struct cio2_bridge *bridge,
struct cio2_sensor *sensor)
{
@@ -219,6 +232,8 @@ static void cio2_bridge_create_connection_swnodes(struct cio2_bridge *bridge,
if (sensor->ssdb.vcmtype)
nodes[SWNODE_VCM] =
NODE_VCM(cio2_vcm_types[sensor->ssdb.vcmtype - 1]);
+
+ cio2_bridge_init_swnode_group(sensor);
}
static void cio2_bridge_instantiate_vcm_i2c_client(struct cio2_sensor *sensor)
@@ -252,7 +267,7 @@ static void cio2_bridge_unregister_sensors(struct cio2_bridge *bridge)
for (i = 0; i < bridge->n_sensors; i++) {
sensor = &bridge->sensors[i];
- software_node_unregister_nodes(sensor->swnodes);
+ software_node_unregister_node_group(sensor->group);
ACPI_FREE(sensor->pld);
acpi_dev_put(sensor->adev);
i2c_unregister_device(sensor->vcm_i2c_client);
@@ -263,7 +278,7 @@ static int cio2_bridge_connect_sensor(const struct cio2_sensor_config *cfg,
struct cio2_bridge *bridge,
struct pci_dev *cio2)
{
- struct fwnode_handle *fwnode;
+ struct fwnode_handle *fwnode, *primary;
struct cio2_sensor *sensor;
struct acpi_device *adev;
acpi_status status;
@@ -310,7 +325,7 @@ static int cio2_bridge_connect_sensor(const struct cio2_sensor_config *cfg,
cio2_bridge_create_fwnode_properties(sensor, bridge, cfg);
cio2_bridge_create_connection_swnodes(bridge, sensor);
- ret = software_node_register_nodes(sensor->swnodes);
+ ret = software_node_register_node_group(sensor->group);
if (ret)
goto err_free_pld;
@@ -322,7 +337,9 @@ static int cio2_bridge_connect_sensor(const struct cio2_sensor_config *cfg,
}
sensor->adev = acpi_dev_get(adev);
- adev->fwnode.secondary = fwnode;
+
+ primary = acpi_fwnode_handle(adev);
+ primary->secondary = fwnode;
cio2_bridge_instantiate_vcm_i2c_client(sensor);
@@ -335,7 +352,7 @@ static int cio2_bridge_connect_sensor(const struct cio2_sensor_config *cfg,
return 0;
err_free_swnodes:
- software_node_unregister_nodes(sensor->swnodes);
+ software_node_unregister_node_group(sensor->group);
err_free_pld:
ACPI_FREE(sensor->pld);
err_put_adev:
diff --git a/drivers/media/pci/intel/ipu3/cio2-bridge.h b/drivers/media/pci/intel/ipu3/cio2-bridge.h
index 4418cbd08208..b93b749c65bd 100644
--- a/drivers/media/pci/intel/ipu3/cio2-bridge.h
+++ b/drivers/media/pci/intel/ipu3/cio2-bridge.h
@@ -117,8 +117,9 @@ struct cio2_sensor {
struct acpi_device *adev;
struct i2c_client *vcm_i2c_client;
- /* SWNODE_COUNT + 1 for terminating empty node */
- struct software_node swnodes[SWNODE_COUNT + 1];
+ /* SWNODE_COUNT + 1 for terminating NULL */
+ const struct software_node *group[SWNODE_COUNT + 1];
+ struct software_node swnodes[SWNODE_COUNT];
struct cio2_node_names node_names;
struct cio2_sensor_ssdb ssdb;
diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
index 390bd5ea3472..3b76a9d0383a 100644
--- a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
@@ -1843,6 +1843,9 @@ static void cio2_pci_remove(struct pci_dev *pci_dev)
v4l2_device_unregister(&cio2->v4l2_dev);
media_device_cleanup(&cio2->media_dev);
mutex_destroy(&cio2->lock);
+
+ pm_runtime_forbid(&pci_dev->dev);
+ pm_runtime_get_noresume(&pci_dev->dev);
}
static int __maybe_unused cio2_runtime_suspend(struct device *dev)
diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c
index 96328b0af164..cf2871306987 100644
--- a/drivers/media/pci/saa7134/saa7134-core.c
+++ b/drivers/media/pci/saa7134/saa7134-core.c
@@ -978,7 +978,7 @@ static void saa7134_unregister_video(struct saa7134_dev *dev)
}
if (dev->radio_dev) {
if (video_is_registered(dev->radio_dev))
- vb2_video_unregister_device(dev->radio_dev);
+ video_unregister_device(dev->radio_dev);
else
video_device_release(dev->radio_dev);
dev->radio_dev = NULL;
diff --git a/drivers/staging/media/deprecated/saa7146/saa7146/Kconfig b/drivers/media/pci/saa7146/Kconfig
index 228e8d3f8d2b..3bbb68a0ed7b 100644
--- a/drivers/staging/media/deprecated/saa7146/saa7146/Kconfig
+++ b/drivers/media/pci/saa7146/Kconfig
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
config VIDEO_HEXIUM_GEMINI
- tristate "Hexium Gemini frame grabber (DEPRECATED)"
+ tristate "Hexium Gemini frame grabber"
depends on PCI && VIDEO_DEV && I2C
select VIDEO_SAA7146_VV
help
@@ -8,28 +8,22 @@ config VIDEO_HEXIUM_GEMINI
grabber card by Hexium. Please note that the Gemini Dual
card is *not* fully supported.
- This driver is deprecated and is scheduled for removal by
- the beginning of 2023. See the TODO file for more information.
-
To compile this driver as a module, choose M here: the
module will be called hexium_gemini.
config VIDEO_HEXIUM_ORION
- tristate "Hexium HV-PCI6 and Orion frame grabber (DEPRECATED)"
+ tristate "Hexium HV-PCI6 and Orion frame grabber"
depends on PCI && VIDEO_DEV && I2C
select VIDEO_SAA7146_VV
help
This is a video4linux driver for the Hexium HV-PCI6 and
Orion frame grabber cards by Hexium.
- This driver is deprecated and is scheduled for removal by
- the beginning of 2023. See the TODO file for more information.
-
To compile this driver as a module, choose M here: the
module will be called hexium_orion.
config VIDEO_MXB
- tristate "Siemens-Nixdorf 'Multimedia eXtension Board' (DEPRECATED)"
+ tristate "Siemens-Nixdorf 'Multimedia eXtension Board'"
depends on PCI && VIDEO_DEV && I2C
select VIDEO_SAA7146_VV
select VIDEO_TUNER
@@ -41,8 +35,5 @@ config VIDEO_MXB
This is a video4linux driver for the 'Multimedia eXtension Board'
TV card by Siemens-Nixdorf.
- This driver is deprecated and is scheduled for removal by
- the beginning of 2023. See the TODO file for more information.
-
To compile this driver as a module, choose M here: the
module will be called mxb.
diff --git a/drivers/staging/media/deprecated/saa7146/saa7146/Makefile b/drivers/media/pci/saa7146/Makefile
index 37c9336f83d5..37c9336f83d5 100644
--- a/drivers/staging/media/deprecated/saa7146/saa7146/Makefile
+++ b/drivers/media/pci/saa7146/Makefile
diff --git a/drivers/staging/media/deprecated/saa7146/saa7146/hexium_gemini.c b/drivers/media/pci/saa7146/hexium_gemini.c
index 124e82bd4507..3947701cd6c7 100644
--- a/drivers/staging/media/deprecated/saa7146/saa7146/hexium_gemini.c
+++ b/drivers/media/pci/saa7146/hexium_gemini.c
@@ -13,9 +13,9 @@
#define DEBUG_VARIABLE debug
+#include <media/drv-intf/saa7146_vv.h>
#include <linux/module.h>
#include <linux/kernel.h>
-#include "../common/saa7146_vv.h"
static int debug;
module_param(debug, int, 0);
diff --git a/drivers/staging/media/deprecated/saa7146/saa7146/hexium_orion.c b/drivers/media/pci/saa7146/hexium_orion.c
index ebd63998ac79..2eb4bee16b71 100644
--- a/drivers/staging/media/deprecated/saa7146/saa7146/hexium_orion.c
+++ b/drivers/media/pci/saa7146/hexium_orion.c
@@ -13,9 +13,9 @@
#define DEBUG_VARIABLE debug
+#include <media/drv-intf/saa7146_vv.h>
#include <linux/module.h>
#include <linux/kernel.h>
-#include "../common/saa7146_vv.h"
static int debug;
module_param(debug, int, 0);
diff --git a/drivers/staging/media/deprecated/saa7146/saa7146/mxb.c b/drivers/media/pci/saa7146/mxb.c
index 3e568f952dae..7ded8f5b05cb 100644
--- a/drivers/staging/media/deprecated/saa7146/saa7146/mxb.c
+++ b/drivers/media/pci/saa7146/mxb.c
@@ -13,13 +13,13 @@
#define DEBUG_VARIABLE debug
+#include <media/drv-intf/saa7146_vv.h>
#include <media/tuner.h>
#include <media/v4l2-common.h>
#include <media/i2c/saa7115.h>
#include <linux/module.h>
#include <linux/kernel.h>
-#include "../common/saa7146_vv.h"
#include "tea6415c.h"
#include "tea6420.h"
diff --git a/drivers/staging/media/deprecated/saa7146/ttpci/Kconfig b/drivers/media/pci/ttpci/Kconfig
index 8c85ed58e938..65a6832a6b96 100644
--- a/drivers/staging/media/deprecated/saa7146/ttpci/Kconfig
+++ b/drivers/media/pci/ttpci/Kconfig
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
config DVB_BUDGET_CORE
- tristate "SAA7146 DVB cards (aka Budget, Nova-PCI) (DEPRECATED)"
+ tristate "SAA7146 DVB cards (aka Budget, Nova-PCI)"
depends on DVB_CORE && PCI && I2C
select VIDEO_SAA7146
select TTPCI_EEPROM
@@ -10,7 +10,7 @@ config DVB_BUDGET_CORE
MPEG2 decoder.
config DVB_BUDGET
- tristate "Budget cards (DEPRECATED)"
+ tristate "Budget cards"
depends on DVB_BUDGET_CORE && I2C
select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
select DVB_VES1X93 if MEDIA_SUBDRV_AUTOSELECT
@@ -30,16 +30,13 @@ config DVB_BUDGET
or Nova-PCI cards) without onboard MPEG2 decoder, and without
analog inputs or an onboard Common Interface connector.
- This driver is deprecated and is scheduled for removal by
- the beginning of 2023. See the TODO file for more information.
-
Say Y if you own such a card and want to use it.
To compile this driver as a module, choose M here: the
module will be called budget.
config DVB_BUDGET_CI
- tristate "Budget cards with onboard CI connector (DEPRECATED)"
+ tristate "Budget cards with onboard CI connector"
depends on DVB_BUDGET_CORE && I2C
select DVB_STV0297 if MEDIA_SUBDRV_AUTOSELECT
select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
@@ -60,16 +57,13 @@ config DVB_BUDGET_CI
Note: The Common Interface is not yet supported by this driver
due to lack of information from the vendor.
- This driver is deprecated and is scheduled for removal by
- the beginning of 2023. See the TODO file for more information.
-
Say Y if you own such a card and want to use it.
To compile this driver as a module, choose M here: the
module will be called budget-ci.
config DVB_BUDGET_AV
- tristate "Budget cards with analog video inputs (DEPRECATED)"
+ tristate "Budget cards with analog video inputs"
depends on DVB_BUDGET_CORE && I2C
select VIDEO_SAA7146_VV
depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV
@@ -86,9 +80,6 @@ config DVB_BUDGET_AV
(so called Budget- or Nova-PCI cards) without onboard
MPEG2 decoder, but with one or more analog video inputs.
- This driver is deprecated and is scheduled for removal by
- the beginning of 2023. See the TODO file for more information.
-
Say Y if you own such a card and want to use it.
To compile this driver as a module, choose M here: the
diff --git a/drivers/staging/media/deprecated/saa7146/ttpci/Makefile b/drivers/media/pci/ttpci/Makefile
index b0708f6e40cc..b0708f6e40cc 100644
--- a/drivers/staging/media/deprecated/saa7146/ttpci/Makefile
+++ b/drivers/media/pci/ttpci/Makefile
diff --git a/drivers/staging/media/deprecated/saa7146/ttpci/budget-av.c b/drivers/media/pci/ttpci/budget-av.c
index 0c61a2dec221..3cb83005cf09 100644
--- a/drivers/staging/media/deprecated/saa7146/ttpci/budget-av.c
+++ b/drivers/media/pci/ttpci/budget-av.c
@@ -29,7 +29,7 @@
#include "tda1004x.h"
#include "tua6100.h"
#include "dvb-pll.h"
-#include "../common/saa7146_vv.h"
+#include <media/drv-intf/saa7146_vv.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/slab.h>
diff --git a/drivers/staging/media/deprecated/saa7146/ttpci/budget-ci.c b/drivers/media/pci/ttpci/budget-ci.c
index d59d18647371..d59d18647371 100644
--- a/drivers/staging/media/deprecated/saa7146/ttpci/budget-ci.c
+++ b/drivers/media/pci/ttpci/budget-ci.c
diff --git a/drivers/staging/media/deprecated/saa7146/ttpci/budget-core.c b/drivers/media/pci/ttpci/budget-core.c
index 5d5796f24469..5d5796f24469 100644
--- a/drivers/staging/media/deprecated/saa7146/ttpci/budget-core.c
+++ b/drivers/media/pci/ttpci/budget-core.c
diff --git a/drivers/staging/media/deprecated/saa7146/ttpci/budget.c b/drivers/media/pci/ttpci/budget.c
index a88711a3ac7f..a88711a3ac7f 100644
--- a/drivers/staging/media/deprecated/saa7146/ttpci/budget.c
+++ b/drivers/media/pci/ttpci/budget.c
diff --git a/drivers/staging/media/deprecated/saa7146/ttpci/budget.h b/drivers/media/pci/ttpci/budget.h
index 82cc0df492b3..bd87432e6cde 100644
--- a/drivers/staging/media/deprecated/saa7146/ttpci/budget.h
+++ b/drivers/media/pci/ttpci/budget.h
@@ -13,7 +13,7 @@
#include <linux/module.h>
#include <linux/mutex.h>
-#include "../common/saa7146.h"
+#include <media/drv-intf/saa7146.h>
extern int budget_debug;
diff --git a/drivers/media/platform/amphion/venc.c b/drivers/media/platform/amphion/venc.c
index 3cbe8ce637e5..e6e8fe45fc7c 100644
--- a/drivers/media/platform/amphion/venc.c
+++ b/drivers/media/platform/amphion/venc.c
@@ -250,19 +250,10 @@ static int venc_s_fmt(struct file *file, void *fh, struct v4l2_format *f)
}
if (V4L2_TYPE_IS_OUTPUT(f->type)) {
- if (!vpu_color_check_primaries(pix_mp->colorspace)) {
- venc->params.color.primaries = pix_mp->colorspace;
- vpu_color_get_default(venc->params.color.primaries,
- &venc->params.color.transfer,
- &venc->params.color.matrix,
- &venc->params.color.full_range);
- }
- if (!vpu_color_check_transfers(pix_mp->xfer_func))
- venc->params.color.transfer = pix_mp->xfer_func;
- if (!vpu_color_check_matrix(pix_mp->ycbcr_enc))
- venc->params.color.matrix = pix_mp->ycbcr_enc;
- if (!vpu_color_check_full_range(pix_mp->quantization))
- venc->params.color.full_range = pix_mp->quantization;
+ venc->params.color.primaries = pix_mp->colorspace;
+ venc->params.color.transfer = pix_mp->xfer_func;
+ venc->params.color.matrix = pix_mp->ycbcr_enc;
+ venc->params.color.full_range = pix_mp->quantization;
}
pix_mp->colorspace = venc->params.color.primaries;
@@ -1281,7 +1272,6 @@ static void venc_init(struct file *file)
f.fmt.pix_mp.width = 1280;
f.fmt.pix_mp.height = 720;
f.fmt.pix_mp.field = V4L2_FIELD_NONE;
- f.fmt.pix_mp.colorspace = V4L2_COLORSPACE_REC709;
venc_s_fmt(file, &inst->fh, &f);
memset(&f, 0, sizeof(f));
diff --git a/drivers/media/platform/amphion/vpu_color.c b/drivers/media/platform/amphion/vpu_color.c
index 80b9a53fd1c1..4ae435cbc5cd 100644
--- a/drivers/media/platform/amphion/vpu_color.c
+++ b/drivers/media/platform/amphion/vpu_color.c
@@ -17,7 +17,7 @@
#include "vpu_helpers.h"
static const u8 colorprimaries[] = {
- 0,
+ V4L2_COLORSPACE_LAST,
V4L2_COLORSPACE_REC709, /*Rec. ITU-R BT.709-6*/
0,
0,
@@ -31,7 +31,7 @@ static const u8 colorprimaries[] = {
};
static const u8 colortransfers[] = {
- 0,
+ V4L2_XFER_FUNC_LAST,
V4L2_XFER_FUNC_709, /*Rec. ITU-R BT.709-6*/
0,
0,
@@ -53,7 +53,7 @@ static const u8 colortransfers[] = {
};
static const u8 colormatrixcoefs[] = {
- 0,
+ V4L2_YCBCR_ENC_LAST,
V4L2_YCBCR_ENC_709, /*Rec. ITU-R BT.709-6*/
0,
0,
diff --git a/drivers/media/platform/chips-media/imx-vdoa.c b/drivers/media/platform/chips-media/imx-vdoa.c
index c70871bae193..c3561fcecb98 100644
--- a/drivers/media/platform/chips-media/imx-vdoa.c
+++ b/drivers/media/platform/chips-media/imx-vdoa.c
@@ -324,11 +324,6 @@ static int vdoa_probe(struct platform_device *pdev)
return 0;
}
-static int vdoa_remove(struct platform_device *pdev)
-{
- return 0;
-}
-
static const struct of_device_id vdoa_dt_ids[] = {
{ .compatible = "fsl,imx6q-vdoa" },
{}
@@ -337,7 +332,6 @@ MODULE_DEVICE_TABLE(of, vdoa_dt_ids);
static struct platform_driver vdoa_driver = {
.probe = vdoa_probe,
- .remove = vdoa_remove,
.driver = {
.name = VDOA_NAME,
.of_match_table = vdoa_dt_ids,
diff --git a/drivers/media/platform/marvell/mmp-driver.c b/drivers/media/platform/marvell/mmp-driver.c
index df16899ab1cb..ef22bf8f276c 100644
--- a/drivers/media/platform/marvell/mmp-driver.c
+++ b/drivers/media/platform/marvell/mmp-driver.c
@@ -254,7 +254,7 @@ static int mmpcam_probe(struct platform_device *pdev)
*/
ret = mccic_register(mcam);
if (ret)
- return ret;
+ goto out;
/*
* Add OF clock provider.
diff --git a/drivers/media/platform/mediatek/mdp3/Kconfig b/drivers/media/platform/mediatek/mdp3/Kconfig
index 846e759a8f6a..602329c44750 100644
--- a/drivers/media/platform/mediatek/mdp3/Kconfig
+++ b/drivers/media/platform/mediatek/mdp3/Kconfig
@@ -3,14 +3,13 @@ config VIDEO_MEDIATEK_MDP3
tristate "MediaTek MDP v3 driver"
depends on MTK_IOMMU || COMPILE_TEST
depends on VIDEO_DEV
- depends on ARCH_MEDIATEK || COMPILE_TEST
depends on HAS_DMA
depends on REMOTEPROC
+ depends on MTK_MMSYS
+ depends on MTK_CMDQ
+ depends on MTK_SCP
select VIDEOBUF2_DMA_CONTIG
select V4L2_MEM2MEM_DEV
- select MTK_MMSYS
- select MTK_CMDQ
- select MTK_SCP
default n
help
It is a v4l2 driver and present in MediaTek MT8183 SoC.
diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c
index 7bc05f42a23c..091a68685590 100644
--- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c
+++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c
@@ -1002,7 +1002,8 @@ int mdp_comp_config(struct mdp_dev *mdp)
if (!pdev) {
dev_warn(dev, "can't find platform device of node:%s\n",
node->name);
- return -ENODEV;
+ ret = -ENODEV;
+ goto err_init_comps;
}
comp->comp_dev = &pdev->dev;
diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c
index 2d1f6ae9f080..97edcd9d1c81 100644
--- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c
+++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c
@@ -207,8 +207,8 @@ static int mdp_probe(struct platform_device *pdev)
}
for (i = 0; i < MDP_PIPE_MAX; i++) {
mdp->mdp_mutex[i] = mtk_mutex_get(&mm_pdev->dev);
- if (!mdp->mdp_mutex[i]) {
- ret = -ENODEV;
+ if (IS_ERR(mdp->mdp_mutex[i])) {
+ ret = PTR_ERR(mdp->mdp_mutex[i]);
goto err_free_mutex;
}
}
@@ -289,7 +289,8 @@ err_deinit_comp:
mdp_comp_destroy(mdp);
err_free_mutex:
for (i = 0; i < MDP_PIPE_MAX; i++)
- mtk_mutex_put(mdp->mdp_mutex[i]);
+ if (!IS_ERR_OR_NULL(mdp->mdp_mutex[i]))
+ mtk_mutex_put(mdp->mdp_mutex[i]);
err_destroy_device:
kfree(mdp);
err_return:
diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c
index 4305e4eb9900..777d445999e9 100644
--- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c
+++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c
@@ -72,9 +72,9 @@ static void mtk_vcodec_dec_pw_off(struct mtk_vcodec_pm *pm)
{
int ret;
- ret = pm_runtime_put_sync(pm->dev);
- if (ret)
- mtk_v4l2_err("pm_runtime_put_sync fail %d", ret);
+ ret = pm_runtime_put(pm->dev);
+ if (ret && ret != -EAGAIN)
+ mtk_v4l2_err("pm_runtime_put fail %d", ret);
}
static void mtk_vcodec_dec_clock_on(struct mtk_vcodec_pm *pm)
diff --git a/drivers/media/platform/mediatek/vcodec/venc/venc_h264_if.c b/drivers/media/platform/mediatek/vcodec/venc/venc_h264_if.c
index 13c4f860fa69..60fd165c0d94 100644
--- a/drivers/media/platform/mediatek/vcodec/venc/venc_h264_if.c
+++ b/drivers/media/platform/mediatek/vcodec/venc/venc_h264_if.c
@@ -565,7 +565,7 @@ static int h264_encode_frame(struct venc_h264_inst *inst,
*bs_size);
++inst->frm_cnt;
++inst->skip_frm_cnt;
- return ret;
+ return 0;
}
irq_status = h264_enc_wait_venc_done(inst);
@@ -580,7 +580,7 @@ static int h264_encode_frame(struct venc_h264_inst *inst,
mtk_vcodec_debug(inst, "frm %d bs_size %d key_frm %d <-",
inst->frm_cnt, *bs_size, inst->vpu_inst.is_key_frm);
- return ret;
+ return 0;
}
static void h264_encode_filler(struct venc_h264_inst *inst, void *buf,
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index e2994d48f10c..71758ee8474b 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -32,10 +32,6 @@
#include "microchip-isc-regs.h"
#include "microchip-isc.h"
-static unsigned int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "debug level (0-2)");
-
#define ISC_IS_FORMAT_RAW(mbus_code) \
(((mbus_code) & 0xf000) == 0x3000)
@@ -114,8 +110,8 @@ static int isc_buffer_prepare(struct vb2_buffer *vb)
unsigned long size = isc->fmt.fmt.pix.sizeimage;
if (vb2_plane_size(vb, 0) < size) {
- v4l2_err(&isc->v4l2_dev, "buffer too small (%lu < %lu)\n",
- vb2_plane_size(vb, 0), size);
+ dev_err(isc->dev, "buffer too small (%lu < %lu)\n",
+ vb2_plane_size(vb, 0), size);
return -EINVAL;
}
@@ -346,15 +342,14 @@ static int isc_start_streaming(struct vb2_queue *vq, unsigned int count)
/* Enable stream on the sub device */
ret = v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 1);
if (ret && ret != -ENOIOCTLCMD) {
- v4l2_err(&isc->v4l2_dev, "stream on failed in subdev %d\n",
- ret);
+ dev_err(isc->dev, "stream on failed in subdev %d\n", ret);
goto err_start_stream;
}
ret = pm_runtime_resume_and_get(isc->dev);
if (ret < 0) {
- v4l2_err(&isc->v4l2_dev, "RPM resume failed in subdev %d\n",
- ret);
+ dev_err(isc->dev, "RPM resume failed in subdev %d\n",
+ ret);
goto err_pm_get;
}
@@ -423,8 +418,7 @@ static void isc_stop_streaming(struct vb2_queue *vq)
/* Wait until the end of the current frame */
if (isc->cur_frm && !wait_for_completion_timeout(&isc->comp, 5 * HZ))
- v4l2_err(&isc->v4l2_dev,
- "Timeout waiting for end of the capture\n");
+ dev_err(isc->dev, "Timeout waiting for end of the capture\n");
mutex_unlock(&isc->awb_mutex);
@@ -436,7 +430,7 @@ static void isc_stop_streaming(struct vb2_queue *vq)
/* Disable stream on the sub device */
ret = v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 0);
if (ret && ret != -ENOIOCTLCMD)
- v4l2_err(&isc->v4l2_dev, "stream off failed in subdev\n");
+ dev_err(isc->dev, "stream off failed in subdev\n");
/* Release all active buffers */
spin_lock_irqsave(&isc->dma_queue_lock, flags);
@@ -620,28 +614,28 @@ static int isc_try_validate_formats(struct isc_device *isc)
break;
default:
/* any other different formats are not supported */
- v4l2_err(&isc->v4l2_dev, "Requested unsupported format.\n");
+ dev_err(isc->dev, "Requested unsupported format.\n");
ret = -EINVAL;
}
- v4l2_dbg(1, debug, &isc->v4l2_dev,
- "Format validation, requested rgb=%u, yuv=%u, grey=%u, bayer=%u\n",
- rgb, yuv, grey, bayer);
+ dev_dbg(isc->dev,
+ "Format validation, requested rgb=%u, yuv=%u, grey=%u, bayer=%u\n",
+ rgb, yuv, grey, bayer);
if (bayer &&
!ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
- v4l2_err(&isc->v4l2_dev, "Cannot output RAW if we do not receive RAW.\n");
+ dev_err(isc->dev, "Cannot output RAW if we do not receive RAW.\n");
return -EINVAL;
}
if (grey && !ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code) &&
!ISC_IS_FORMAT_GREY(isc->try_config.sd_format->mbus_code)) {
- v4l2_err(&isc->v4l2_dev, "Cannot output GREY if we do not receive RAW/GREY.\n");
+ dev_err(isc->dev, "Cannot output GREY if we do not receive RAW/GREY.\n");
return -EINVAL;
}
if ((rgb || bayer || yuv) &&
ISC_IS_FORMAT_GREY(isc->try_config.sd_format->mbus_code)) {
- v4l2_err(&isc->v4l2_dev, "Cannot convert GREY to another format.\n");
+ dev_err(isc->dev, "Cannot convert GREY to another format.\n");
return -EINVAL;
}
@@ -936,9 +930,9 @@ static int isc_set_fmt(struct isc_device *isc, struct v4l2_format *f)
isc->config = isc->try_config;
isc->fmt = isc->try_fmt;
- v4l2_dbg(1, debug, &isc->v4l2_dev, "ISC set_fmt to %.4s @%dx%d\n",
- (char *)&f->fmt.pix.pixelformat,
- f->fmt.pix.width, f->fmt.pix.height);
+ dev_dbg(isc->dev, "ISC set_fmt to %.4s @%dx%d\n",
+ (char *)&f->fmt.pix.pixelformat,
+ f->fmt.pix.width, f->fmt.pix.height);
return 0;
}
@@ -973,9 +967,9 @@ static int isc_validate(struct isc_device *isc)
/* Check if the format is not supported */
if (!sd_fmt) {
- v4l2_err(&isc->v4l2_dev,
- "Current subdevice is streaming a media bus code that is not supported 0x%x\n",
- format.format.code);
+ dev_err(isc->dev,
+ "Current subdevice is streaming a media bus code that is not supported 0x%x\n",
+ format.format.code);
return -EPIPE;
}
@@ -993,16 +987,16 @@ static int isc_validate(struct isc_device *isc)
/* Check if the frame size is the same. Otherwise we may overflow */
if (pixfmt->height != format.format.height ||
pixfmt->width != format.format.width) {
- v4l2_err(&isc->v4l2_dev,
- "ISC not configured with the proper frame size: %dx%d\n",
- format.format.width, format.format.height);
+ dev_err(isc->dev,
+ "ISC not configured with the proper frame size: %dx%d\n",
+ format.format.width, format.format.height);
return -EPIPE;
}
- v4l2_dbg(1, debug, &isc->v4l2_dev,
- "Identified subdev using format %.4s with %dx%d %d bpp\n",
- (char *)&sd_fmt->fourcc, pixfmt->width, pixfmt->height,
- isc->try_config.bpp);
+ dev_dbg(isc->dev,
+ "Identified subdev using format %.4s with %dx%d %d bpp\n",
+ (char *)&sd_fmt->fourcc, pixfmt->width, pixfmt->height,
+ isc->try_config.bpp);
/* Reset and restart AWB if the subdevice changed the format */
if (isc->try_config.sd_format && isc->config.sd_format &&
@@ -1027,7 +1021,7 @@ static int isc_validate(struct isc_device *isc)
isc->config = isc->try_config;
- v4l2_dbg(1, debug, &isc->v4l2_dev, "New ISC configuration in place\n");
+ dev_dbg(isc->dev, "New ISC configuration in place\n");
return 0;
}
@@ -1294,9 +1288,8 @@ static void isc_hist_count(struct isc_device *isc, u32 *min, u32 *max)
if (!*min)
*min = 1;
- v4l2_dbg(1, debug, &isc->v4l2_dev,
- "isc wb: hist_id %u, hist_count %u",
- ctrls->hist_id, *hist_count);
+ dev_dbg(isc->dev, "isc wb: hist_id %u, hist_count %u",
+ ctrls->hist_id, *hist_count);
}
static void isc_wb_update(struct isc_ctrls *ctrls)
@@ -1318,8 +1311,7 @@ static void isc_wb_update(struct isc_ctrls *ctrls)
(u64)hist_count[ISC_HIS_CFG_MODE_GB];
avg >>= 1;
- v4l2_dbg(1, debug, &isc->v4l2_dev,
- "isc wb: green components average %llu\n", avg);
+ dev_dbg(isc->dev, "isc wb: green components average %llu\n", avg);
/* Green histogram is null, nothing to do */
if (!avg)
@@ -1373,9 +1365,9 @@ static void isc_wb_update(struct isc_ctrls *ctrls)
else
gw_gain[c] = 1 << 9;
- v4l2_dbg(1, debug, &isc->v4l2_dev,
- "isc wb: component %d, s_gain %u, gw_gain %u\n",
- c, s_gain[c], gw_gain[c]);
+ dev_dbg(isc->dev,
+ "isc wb: component %d, s_gain %u, gw_gain %u\n",
+ c, s_gain[c], gw_gain[c]);
/* multiply both gains and adjust for decimals */
ctrls->gain[c] = s_gain[c] * gw_gain[c];
ctrls->gain[c] >>= 9;
@@ -1383,9 +1375,8 @@ static void isc_wb_update(struct isc_ctrls *ctrls)
/* make sure we are not out of range */
ctrls->gain[c] = clamp_val(ctrls->gain[c], 0, GENMASK(12, 0));
- v4l2_dbg(1, debug, &isc->v4l2_dev,
- "isc wb: component %d, final gain %u\n",
- c, ctrls->gain[c]);
+ dev_dbg(isc->dev, "isc wb: component %d, final gain %u\n",
+ c, ctrls->gain[c]);
}
}
@@ -1406,8 +1397,8 @@ static void isc_awb_work(struct work_struct *w)
isc_hist_count(isc, &min, &max);
- v4l2_dbg(1, debug, &isc->v4l2_dev,
- "isc wb mode %d: hist min %u , max %u\n", hist_id, min, max);
+ dev_dbg(isc->dev,
+ "isc wb mode %d: hist min %u , max %u\n", hist_id, min, max);
ctrls->hist_minmax[hist_id][HIST_MIN_INDEX] = min;
ctrls->hist_minmax[hist_id][HIST_MAX_INDEX] = max;
@@ -1446,8 +1437,8 @@ static void isc_awb_work(struct work_struct *w)
* we are basically done.
*/
if (ctrls->awb == ISC_WB_ONETIME) {
- v4l2_info(&isc->v4l2_dev,
- "Completed one time white-balance adjustment.\n");
+ dev_info(isc->dev,
+ "Completed one time white-balance adjustment.\n");
/* update the v4l2 controls values */
isc_update_v4l2_ctrls(isc);
ctrls->awb = ISC_WB_NONE;
@@ -1580,8 +1571,7 @@ static int isc_s_awb_ctrl(struct v4l2_ctrl *ctrl)
V4L2_CTRL_FLAG_INACTIVE)) {
ctrls->awb = ISC_WB_ONETIME;
isc_set_histogram(isc, true);
- v4l2_dbg(1, debug, &isc->v4l2_dev,
- "One time white-balance started.\n");
+ dev_dbg(isc->dev, "One time white-balance started.\n");
}
return 0;
}
@@ -1730,7 +1720,7 @@ static int isc_async_bound(struct v4l2_async_notifier *notifier,
int pad;
if (video_is_registered(&isc->video_dev)) {
- v4l2_err(&isc->v4l2_dev, "only supports one sub-device.\n");
+ dev_err(isc->dev, "only supports one sub-device.\n");
return -EBUSY;
}
@@ -1739,8 +1729,7 @@ static int isc_async_bound(struct v4l2_async_notifier *notifier,
pad = media_entity_get_fwnode_pad(&subdev->entity, asd->match.fwnode,
MEDIA_PAD_FL_SOURCE);
if (pad < 0) {
- v4l2_err(&isc->v4l2_dev, "failed to find pad for %s\n",
- subdev->name);
+ dev_err(isc->dev, "failed to find pad for %s\n", subdev->name);
return pad;
}
@@ -1813,7 +1802,7 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier)
ret = v4l2_device_register_subdev_nodes(&isc->v4l2_dev);
if (ret < 0) {
- v4l2_err(&isc->v4l2_dev, "Failed to register subdev nodes\n");
+ dev_err(isc->dev, "Failed to register subdev nodes\n");
return ret;
}
@@ -1838,8 +1827,7 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier)
ret = vb2_queue_init(q);
if (ret < 0) {
- v4l2_err(&isc->v4l2_dev,
- "vb2_queue_init() failed: %d\n", ret);
+ dev_err(isc->dev, "vb2_queue_init() failed: %d\n", ret);
goto isc_async_complete_err;
}
@@ -1850,13 +1838,13 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier)
ret = isc_set_default_fmt(isc);
if (ret) {
- v4l2_err(&isc->v4l2_dev, "Could not set default format\n");
+ dev_err(isc->dev, "Could not set default format\n");
goto isc_async_complete_err;
}
ret = isc_ctrl_init(isc);
if (ret) {
- v4l2_err(&isc->v4l2_dev, "Init isc ctrols failed: %d\n", ret);
+ dev_err(isc->dev, "Init isc ctrols failed: %d\n", ret);
goto isc_async_complete_err;
}
@@ -1876,8 +1864,7 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier)
ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
if (ret < 0) {
- v4l2_err(&isc->v4l2_dev,
- "video_register_device failed: %d\n", ret);
+ dev_err(isc->dev, "video_register_device failed: %d\n", ret);
goto isc_async_complete_err;
}
diff --git a/drivers/media/platform/nxp/dw100/dw100.c b/drivers/media/platform/nxp/dw100/dw100.c
index f6d48c36f386..189d60cd5ed1 100644
--- a/drivers/media/platform/nxp/dw100/dw100.c
+++ b/drivers/media/platform/nxp/dw100/dw100.c
@@ -1571,7 +1571,7 @@ static int dw100_probe(struct platform_device *pdev)
dev_name(&pdev->dev), dw_dev);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to request irq: %d\n", ret);
- return ret;
+ goto err_pm;
}
ret = v4l2_device_register(&pdev->dev, &dw_dev->v4l2_dev);
diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
index 6cd015a35f7c..f085f14d676a 100644
--- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
+++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
@@ -2472,19 +2472,12 @@ static int mxc_jpeg_probe(struct platform_device *pdev)
jpeg->mode = mode;
/* Get clocks */
- jpeg->clk_ipg = devm_clk_get(dev, "ipg");
- if (IS_ERR(jpeg->clk_ipg)) {
- dev_err(dev, "failed to get clock: ipg\n");
- ret = PTR_ERR(jpeg->clk_ipg);
- goto err_clk;
- }
-
- jpeg->clk_per = devm_clk_get(dev, "per");
- if (IS_ERR(jpeg->clk_per)) {
- dev_err(dev, "failed to get clock: per\n");
- ret = PTR_ERR(jpeg->clk_per);
+ ret = devm_clk_bulk_get_all(&pdev->dev, &jpeg->clks);
+ if (ret < 0) {
+ dev_err(dev, "failed to get clock\n");
goto err_clk;
}
+ jpeg->num_clks = ret;
ret = mxc_jpeg_attach_pm_domains(jpeg);
if (ret < 0) {
@@ -2581,32 +2574,20 @@ static int mxc_jpeg_runtime_resume(struct device *dev)
struct mxc_jpeg_dev *jpeg = dev_get_drvdata(dev);
int ret;
- ret = clk_prepare_enable(jpeg->clk_ipg);
- if (ret < 0) {
- dev_err(dev, "failed to enable clock: ipg\n");
- goto err_ipg;
- }
-
- ret = clk_prepare_enable(jpeg->clk_per);
+ ret = clk_bulk_prepare_enable(jpeg->num_clks, jpeg->clks);
if (ret < 0) {
- dev_err(dev, "failed to enable clock: per\n");
- goto err_per;
+ dev_err(dev, "failed to enable clock\n");
+ return ret;
}
return 0;
-
-err_per:
- clk_disable_unprepare(jpeg->clk_ipg);
-err_ipg:
- return ret;
}
static int mxc_jpeg_runtime_suspend(struct device *dev)
{
struct mxc_jpeg_dev *jpeg = dev_get_drvdata(dev);
- clk_disable_unprepare(jpeg->clk_ipg);
- clk_disable_unprepare(jpeg->clk_per);
+ clk_bulk_disable_unprepare(jpeg->num_clks, jpeg->clks);
return 0;
}
diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h
index 8fa8c0aec5a2..87157db78082 100644
--- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h
+++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h
@@ -120,8 +120,8 @@ struct mxc_jpeg_dev {
spinlock_t hw_lock; /* hardware access lock */
unsigned int mode;
struct mutex lock; /* v4l2 ioctls serialization */
- struct clk *clk_ipg;
- struct clk *clk_per;
+ struct clk_bulk_data *clks;
+ int num_clks;
struct platform_device *pdev;
struct device *dev;
void __iomem *base_reg;
diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c
index 905072871ed2..be2768a47995 100644
--- a/drivers/media/platform/nxp/imx-mipi-csis.c
+++ b/drivers/media/platform/nxp/imx-mipi-csis.c
@@ -327,10 +327,6 @@ struct mipi_csis_device {
u32 hs_settle;
u32 clk_settle;
- struct mutex lock; /* Protect csis_fmt and format_mbus */
- const struct csis_pix_format *csis_fmt;
- struct v4l2_mbus_framefmt format_mbus[CSIS_PADS_NUM];
-
spinlock_t slock; /* Protect events */
struct mipi_csis_event events[MIPI_CSIS_NUM_EVENTS];
struct dentry *debugfs_root;
@@ -559,10 +555,10 @@ static void mipi_csis_system_enable(struct mipi_csis_device *csis, int on)
mipi_csis_write(csis, MIPI_CSIS_DPHY_CMN_CTRL, val);
}
-/* Called with the csis.lock mutex held */
-static void __mipi_csis_set_format(struct mipi_csis_device *csis)
+static void __mipi_csis_set_format(struct mipi_csis_device *csis,
+ const struct v4l2_mbus_framefmt *format,
+ const struct csis_pix_format *csis_fmt)
{
- struct v4l2_mbus_framefmt *mf = &csis->format_mbus[CSIS_PAD_SINK];
u32 val;
/* Color format */
@@ -583,25 +579,26 @@ static void __mipi_csis_set_format(struct mipi_csis_device *csis)
*
* TODO: Verify which other formats require DUAL (or QUAD) modes.
*/
- if (csis->csis_fmt->data_type == MIPI_CSI2_DATA_TYPE_YUV422_8)
+ if (csis_fmt->data_type == MIPI_CSI2_DATA_TYPE_YUV422_8)
val |= MIPI_CSIS_ISPCFG_PIXEL_MODE_DUAL;
- val |= MIPI_CSIS_ISPCFG_FMT(csis->csis_fmt->data_type);
+ val |= MIPI_CSIS_ISPCFG_FMT(csis_fmt->data_type);
mipi_csis_write(csis, MIPI_CSIS_ISP_CONFIG_CH(0), val);
/* Pixel resolution */
- val = mf->width | (mf->height << 16);
+ val = format->width | (format->height << 16);
mipi_csis_write(csis, MIPI_CSIS_ISP_RESOL_CH(0), val);
}
-static int mipi_csis_calculate_params(struct mipi_csis_device *csis)
+static int mipi_csis_calculate_params(struct mipi_csis_device *csis,
+ const struct csis_pix_format *csis_fmt)
{
s64 link_freq;
u32 lane_rate;
/* Calculate the line rate from the pixel rate. */
link_freq = v4l2_get_link_freq(csis->src_sd->ctrl_handler,
- csis->csis_fmt->width,
+ csis_fmt->width,
csis->bus.num_data_lanes * 2);
if (link_freq < 0) {
dev_err(csis->dev, "Unable to obtain link frequency: %d\n",
@@ -643,7 +640,9 @@ static int mipi_csis_calculate_params(struct mipi_csis_device *csis)
return 0;
}
-static void mipi_csis_set_params(struct mipi_csis_device *csis)
+static void mipi_csis_set_params(struct mipi_csis_device *csis,
+ const struct v4l2_mbus_framefmt *format,
+ const struct csis_pix_format *csis_fmt)
{
int lanes = csis->bus.num_data_lanes;
u32 val;
@@ -655,7 +654,7 @@ static void mipi_csis_set_params(struct mipi_csis_device *csis)
val |= MIPI_CSIS_CMN_CTRL_INTER_MODE;
mipi_csis_write(csis, MIPI_CSIS_CMN_CTRL, val);
- __mipi_csis_set_format(csis);
+ __mipi_csis_set_format(csis, format, csis_fmt);
mipi_csis_write(csis, MIPI_CSIS_DPHY_CMN_CTRL,
MIPI_CSIS_DPHY_CMN_CTRL_HSSETTLE(csis->hs_settle) |
@@ -728,10 +727,12 @@ static int mipi_csis_clk_get(struct mipi_csis_device *csis)
return ret;
}
-static void mipi_csis_start_stream(struct mipi_csis_device *csis)
+static void mipi_csis_start_stream(struct mipi_csis_device *csis,
+ const struct v4l2_mbus_framefmt *format,
+ const struct csis_pix_format *csis_fmt)
{
mipi_csis_sw_reset(csis);
- mipi_csis_set_params(csis);
+ mipi_csis_set_params(csis, format, csis_fmt);
mipi_csis_system_enable(csis, true);
mipi_csis_enable_interrupts(csis, true);
}
@@ -935,120 +936,63 @@ static struct mipi_csis_device *sd_to_mipi_csis_device(struct v4l2_subdev *sdev)
static int mipi_csis_s_stream(struct v4l2_subdev *sd, int enable)
{
struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
+ const struct v4l2_mbus_framefmt *format;
+ const struct csis_pix_format *csis_fmt;
+ struct v4l2_subdev_state *state;
int ret;
if (!enable) {
- mutex_lock(&csis->lock);
-
v4l2_subdev_call(csis->src_sd, video, s_stream, 0);
mipi_csis_stop_stream(csis);
if (csis->debug.enable)
mipi_csis_log_counters(csis, true);
- mutex_unlock(&csis->lock);
-
pm_runtime_put(csis->dev);
return 0;
}
- ret = mipi_csis_calculate_params(csis);
+ state = v4l2_subdev_lock_and_get_active_state(sd);
+
+ format = v4l2_subdev_get_pad_format(sd, state, CSIS_PAD_SINK);
+ csis_fmt = find_csis_format(format->code);
+
+ ret = mipi_csis_calculate_params(csis, csis_fmt);
if (ret < 0)
- return ret;
+ goto err_unlock;
mipi_csis_clear_counters(csis);
ret = pm_runtime_resume_and_get(csis->dev);
if (ret < 0)
- return ret;
+ goto err_unlock;
- mutex_lock(&csis->lock);
+ mipi_csis_start_stream(csis, format, csis_fmt);
- mipi_csis_start_stream(csis);
ret = v4l2_subdev_call(csis->src_sd, video, s_stream, 1);
if (ret < 0)
- goto error;
+ goto err_stop;
mipi_csis_log_counters(csis, true);
- mutex_unlock(&csis->lock);
+ v4l2_subdev_unlock_state(state);
return 0;
-error:
+err_stop:
mipi_csis_stop_stream(csis);
- mutex_unlock(&csis->lock);
pm_runtime_put(csis->dev);
+err_unlock:
+ v4l2_subdev_unlock_state(state);
return ret;
}
-static struct v4l2_mbus_framefmt *
-mipi_csis_get_format(struct mipi_csis_device *csis,
- struct v4l2_subdev_state *sd_state,
- enum v4l2_subdev_format_whence which,
- unsigned int pad)
-{
- if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&csis->sd, sd_state, pad);
-
- return &csis->format_mbus[pad];
-}
-
-static int mipi_csis_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
-{
- struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
- struct v4l2_mbus_framefmt *fmt_sink;
- struct v4l2_mbus_framefmt *fmt_source;
- enum v4l2_subdev_format_whence which;
-
- which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
- fmt_sink = mipi_csis_get_format(csis, sd_state, which, CSIS_PAD_SINK);
-
- fmt_sink->code = MEDIA_BUS_FMT_UYVY8_1X16;
- fmt_sink->width = MIPI_CSIS_DEF_PIX_WIDTH;
- fmt_sink->height = MIPI_CSIS_DEF_PIX_HEIGHT;
- fmt_sink->field = V4L2_FIELD_NONE;
-
- fmt_sink->colorspace = V4L2_COLORSPACE_SMPTE170M;
- fmt_sink->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt_sink->colorspace);
- fmt_sink->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt_sink->colorspace);
- fmt_sink->quantization =
- V4L2_MAP_QUANTIZATION_DEFAULT(false, fmt_sink->colorspace,
- fmt_sink->ycbcr_enc);
-
- fmt_source = mipi_csis_get_format(csis, sd_state, which,
- CSIS_PAD_SOURCE);
- *fmt_source = *fmt_sink;
-
- return 0;
-}
-
-static int mipi_csis_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *sdformat)
-{
- struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
- struct v4l2_mbus_framefmt *fmt;
-
- fmt = mipi_csis_get_format(csis, sd_state, sdformat->which,
- sdformat->pad);
-
- mutex_lock(&csis->lock);
- sdformat->format = *fmt;
- mutex_unlock(&csis->lock);
-
- return 0;
-}
-
static int mipi_csis_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
- struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
-
/*
* The CSIS can't transcode in any way, the source format is identical
* to the sink format.
@@ -1059,8 +1003,7 @@ static int mipi_csis_enum_mbus_code(struct v4l2_subdev *sd,
if (code->index > 0)
return -EINVAL;
- fmt = mipi_csis_get_format(csis, sd_state, code->which,
- code->pad);
+ fmt = v4l2_subdev_get_pad_format(sd, sd_state, code->pad);
code->code = fmt->code;
return 0;
}
@@ -1080,7 +1023,6 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *sdformat)
{
- struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
struct csis_pix_format const *csis_fmt;
struct v4l2_mbus_framefmt *fmt;
unsigned int align;
@@ -1090,7 +1032,7 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd,
* modified.
*/
if (sdformat->pad == CSIS_PAD_SOURCE)
- return mipi_csis_get_fmt(sd, sd_state, sdformat);
+ return v4l2_subdev_get_fmt(sd, sd_state, sdformat);
if (sdformat->pad != CSIS_PAD_SINK)
return -EINVAL;
@@ -1128,14 +1070,12 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd,
&sdformat->format.height, 1,
CSIS_MAX_PIX_HEIGHT, 0, 0);
- fmt = mipi_csis_get_format(csis, sd_state, sdformat->which,
- sdformat->pad);
-
- mutex_lock(&csis->lock);
+ fmt = v4l2_subdev_get_pad_format(sd, sd_state, sdformat->pad);
fmt->code = csis_fmt->code;
fmt->width = sdformat->format.width;
fmt->height = sdformat->format.height;
+ fmt->field = V4L2_FIELD_NONE;
fmt->colorspace = sdformat->format.colorspace;
fmt->quantization = sdformat->format.quantization;
fmt->xfer_func = sdformat->format.xfer_func;
@@ -1144,48 +1084,68 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd,
sdformat->format = *fmt;
/* Propagate the format from sink to source. */
- fmt = mipi_csis_get_format(csis, sd_state, sdformat->which,
- CSIS_PAD_SOURCE);
+ fmt = v4l2_subdev_get_pad_format(sd, sd_state, CSIS_PAD_SOURCE);
*fmt = sdformat->format;
/* The format on the source pad might change due to unpacking. */
fmt->code = csis_fmt->output;
- /* Store the CSIS format descriptor for active formats. */
- if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
- csis->csis_fmt = csis_fmt;
-
- mutex_unlock(&csis->lock);
-
return 0;
}
static int mipi_csis_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
struct v4l2_mbus_frame_desc *fd)
{
- struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
struct v4l2_mbus_frame_desc_entry *entry = &fd->entry[0];
+ const struct csis_pix_format *csis_fmt;
+ const struct v4l2_mbus_framefmt *fmt;
+ struct v4l2_subdev_state *state;
if (pad != CSIS_PAD_SOURCE)
return -EINVAL;
+ state = v4l2_subdev_lock_and_get_active_state(sd);
+ fmt = v4l2_subdev_get_pad_format(sd, state, CSIS_PAD_SOURCE);
+ csis_fmt = find_csis_format(fmt->code);
+ v4l2_subdev_unlock_state(state);
+
+ if (!csis_fmt)
+ return -EPIPE;
+
fd->type = V4L2_MBUS_FRAME_DESC_TYPE_PARALLEL;
fd->num_entries = 1;
memset(entry, 0, sizeof(*entry));
- mutex_lock(&csis->lock);
-
entry->flags = 0;
- entry->pixelcode = csis->csis_fmt->code;
+ entry->pixelcode = csis_fmt->code;
entry->bus.csi2.vc = 0;
- entry->bus.csi2.dt = csis->csis_fmt->data_type;
-
- mutex_unlock(&csis->lock);
+ entry->bus.csi2.dt = csis_fmt->data_type;
return 0;
}
+static int mipi_csis_init_cfg(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
+{
+ struct v4l2_subdev_format fmt = {
+ .pad = CSIS_PAD_SINK,
+ };
+
+ fmt.format.code = mipi_csis_formats[0].code;
+ fmt.format.width = MIPI_CSIS_DEF_PIX_WIDTH;
+ fmt.format.height = MIPI_CSIS_DEF_PIX_HEIGHT;
+
+ fmt.format.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ fmt.format.xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt.format.colorspace);
+ fmt.format.ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt.format.colorspace);
+ fmt.format.quantization =
+ V4L2_MAP_QUANTIZATION_DEFAULT(false, fmt.format.colorspace,
+ fmt.format.ycbcr_enc);
+
+ return mipi_csis_set_fmt(sd, sd_state, &fmt);
+}
+
static int mipi_csis_log_status(struct v4l2_subdev *sd)
{
struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
@@ -1208,7 +1168,7 @@ static const struct v4l2_subdev_video_ops mipi_csis_video_ops = {
static const struct v4l2_subdev_pad_ops mipi_csis_pad_ops = {
.init_cfg = mipi_csis_init_cfg,
.enum_mbus_code = mipi_csis_enum_mbus_code,
- .get_fmt = mipi_csis_get_fmt,
+ .get_fmt = v4l2_subdev_get_fmt,
.set_fmt = mipi_csis_set_fmt,
.get_frame_desc = mipi_csis_get_frame_desc,
};
@@ -1348,40 +1308,34 @@ static int __maybe_unused mipi_csis_runtime_suspend(struct device *dev)
{
struct v4l2_subdev *sd = dev_get_drvdata(dev);
struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
- int ret = 0;
-
- mutex_lock(&csis->lock);
+ int ret;
ret = mipi_csis_phy_disable(csis);
if (ret)
- goto unlock;
+ return -EAGAIN;
mipi_csis_clk_disable(csis);
-unlock:
- mutex_unlock(&csis->lock);
-
- return ret ? -EAGAIN : 0;
+ return 0;
}
static int __maybe_unused mipi_csis_runtime_resume(struct device *dev)
{
struct v4l2_subdev *sd = dev_get_drvdata(dev);
struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
- int ret = 0;
-
- mutex_lock(&csis->lock);
+ int ret;
ret = mipi_csis_phy_enable(csis);
if (ret)
- goto unlock;
-
- mipi_csis_clk_enable(csis);
+ return -EAGAIN;
-unlock:
- mutex_unlock(&csis->lock);
+ ret = mipi_csis_clk_enable(csis);
+ if (ret) {
+ mipi_csis_phy_disable(csis);
+ return ret;
+ }
- return ret ? -EAGAIN : 0;
+ return 0;
}
static const struct dev_pm_ops mipi_csis_pm_ops = {
@@ -1396,6 +1350,7 @@ static const struct dev_pm_ops mipi_csis_pm_ops = {
static int mipi_csis_subdev_init(struct mipi_csis_device *csis)
{
struct v4l2_subdev *sd = &csis->sd;
+ int ret;
v4l2_subdev_init(sd, &mipi_csis_subdev_ops);
sd->owner = THIS_MODULE;
@@ -1417,15 +1372,21 @@ static int mipi_csis_subdev_init(struct mipi_csis_device *csis)
return -ENOENT;
}
- csis->csis_fmt = &mipi_csis_formats[0];
- mipi_csis_init_cfg(sd, NULL);
-
csis->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK
| MEDIA_PAD_FL_MUST_CONNECT;
csis->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE
| MEDIA_PAD_FL_MUST_CONNECT;
- return media_entity_pads_init(&sd->entity, CSIS_PADS_NUM,
- csis->pads);
+ ret = media_entity_pads_init(&sd->entity, CSIS_PADS_NUM, csis->pads);
+ if (ret)
+ return ret;
+
+ ret = v4l2_subdev_init_finalize(sd);
+ if (ret) {
+ media_entity_cleanup(&sd->entity);
+ return ret;
+ }
+
+ return 0;
}
static int mipi_csis_parse_dt(struct mipi_csis_device *csis)
@@ -1450,7 +1411,6 @@ static int mipi_csis_probe(struct platform_device *pdev)
if (!csis)
return -ENOMEM;
- mutex_init(&csis->lock);
spin_lock_init(&csis->slock);
csis->dev = dev;
@@ -1496,20 +1456,20 @@ static int mipi_csis_probe(struct platform_device *pdev)
dev_name(dev), csis);
if (ret) {
dev_err(dev, "Interrupt request failed\n");
- goto disable_clock;
+ goto err_disable_clock;
}
/* Initialize and register the subdev. */
ret = mipi_csis_subdev_init(csis);
if (ret < 0)
- goto disable_clock;
+ goto err_disable_clock;
platform_set_drvdata(pdev, &csis->sd);
ret = mipi_csis_async_register(csis);
if (ret < 0) {
dev_err(dev, "async register failed: %d\n", ret);
- goto cleanup;
+ goto err_cleanup;
}
/* Initialize debugfs. */
@@ -1520,7 +1480,7 @@ static int mipi_csis_probe(struct platform_device *pdev)
if (!pm_runtime_enabled(dev)) {
ret = mipi_csis_runtime_resume(dev);
if (ret < 0)
- goto unregister_all;
+ goto err_unregister_all;
}
dev_info(dev, "lanes: %d, freq: %u\n",
@@ -1528,17 +1488,17 @@ static int mipi_csis_probe(struct platform_device *pdev)
return 0;
-unregister_all:
+err_unregister_all:
mipi_csis_debugfs_exit(csis);
-cleanup:
+err_cleanup:
+ v4l2_subdev_cleanup(&csis->sd);
media_entity_cleanup(&csis->sd.entity);
v4l2_async_nf_unregister(&csis->notifier);
v4l2_async_nf_cleanup(&csis->notifier);
v4l2_async_unregister_subdev(&csis->sd);
-disable_clock:
+err_disable_clock:
mipi_csis_clk_disable(csis);
fwnode_handle_put(csis->sd.fwnode);
- mutex_destroy(&csis->lock);
return ret;
}
@@ -1556,9 +1516,9 @@ static int mipi_csis_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
mipi_csis_runtime_suspend(&pdev->dev);
mipi_csis_clk_disable(csis);
+ v4l2_subdev_cleanup(&csis->sd);
media_entity_cleanup(&csis->sd.entity);
fwnode_handle_put(csis->sd.fwnode);
- mutex_destroy(&csis->lock);
pm_runtime_set_suspended(&pdev->dev);
return 0;
diff --git a/drivers/media/platform/nxp/imx-pxp.c b/drivers/media/platform/nxp/imx-pxp.c
index 689ae5e6ac62..fde3c36e5e1d 100644
--- a/drivers/media/platform/nxp/imx-pxp.c
+++ b/drivers/media/platform/nxp/imx-pxp.c
@@ -10,6 +10,7 @@
* Pawel Osciak, <pawel@osciak.com>
* Marek Szyprowski, <m.szyprowski@samsung.com>
*/
+#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
@@ -18,15 +19,18 @@
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
#include <linux/sched.h>
#include <linux/slab.h>
-#include <linux/platform_device.h>
-#include <media/v4l2-mem2mem.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-ioctl.h>
+#include <media/media-device.h>
#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
#include <media/videobuf2-dma-contig.h>
#include "imx-pxp.h"
@@ -52,6 +56,11 @@ MODULE_PARM_DESC(debug, "activates debug info");
#define MEM2MEM_HFLIP (1 << 0)
#define MEM2MEM_VFLIP (1 << 1)
+#define PXP_VERSION_MAJOR(version) \
+ FIELD_GET(BM_PXP_VERSION_MAJOR, version)
+#define PXP_VERSION_MINOR(version) \
+ FIELD_GET(BM_PXP_VERSION_MINOR, version)
+
#define dprintk(dev, fmt, arg...) \
v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
@@ -168,14 +177,21 @@ enum {
V4L2_M2M_DST = 1,
};
-static struct pxp_fmt *find_format(struct v4l2_format *f)
+static const struct regmap_config pxp_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = HW_PXP_VERSION,
+};
+
+static struct pxp_fmt *find_format(unsigned int pixelformat)
{
struct pxp_fmt *fmt;
unsigned int k;
for (k = 0; k < NUM_FORMATS; k++) {
fmt = &formats[k];
- if (fmt->fourcc == f->fmt.pix.pixelformat)
+ if (fmt->fourcc == pixelformat)
break;
}
@@ -185,12 +201,23 @@ static struct pxp_fmt *find_format(struct v4l2_format *f)
return &formats[k];
}
+struct pxp_ctx;
+
+struct pxp_pdata {
+ u32 (*data_path_ctrl0)(struct pxp_ctx *ctx);
+};
+
struct pxp_dev {
struct v4l2_device v4l2_dev;
struct video_device vfd;
+#ifdef CONFIG_MEDIA_CONTROLLER
+ struct media_device mdev;
+#endif
struct clk *clk;
- void __iomem *mmio;
+ struct regmap *regmap;
+
+ const struct pxp_pdata *pdata;
atomic_t num_inst;
struct mutex dev_mutex;
@@ -234,6 +261,20 @@ static struct pxp_q_data *get_q_data(struct pxp_ctx *ctx,
return &ctx->q_data[V4L2_M2M_DST];
}
+static inline u32 pxp_read(struct pxp_dev *dev, u32 reg)
+{
+ u32 value;
+
+ regmap_read(dev->regmap, reg, &value);
+
+ return value;
+}
+
+static inline void pxp_write(struct pxp_dev *dev, u32 reg, u32 value)
+{
+ regmap_write(dev->regmap, reg, value);
+}
+
static u32 pxp_v4l2_pix_fmt_to_ps_format(u32 v4l2_pix_fmt)
{
switch (v4l2_pix_fmt) {
@@ -486,11 +527,11 @@ static void pxp_setup_csc(struct pxp_ctx *ctx)
csc1_coef = csc1_coef_smpte240m_lim;
}
- writel(csc1_coef[0], dev->mmio + HW_PXP_CSC1_COEF0);
- writel(csc1_coef[1], dev->mmio + HW_PXP_CSC1_COEF1);
- writel(csc1_coef[2], dev->mmio + HW_PXP_CSC1_COEF2);
+ pxp_write(dev, HW_PXP_CSC1_COEF0, csc1_coef[0]);
+ pxp_write(dev, HW_PXP_CSC1_COEF1, csc1_coef[1]);
+ pxp_write(dev, HW_PXP_CSC1_COEF2, csc1_coef[2]);
} else {
- writel(BM_PXP_CSC1_COEF0_BYPASS, dev->mmio + HW_PXP_CSC1_COEF0);
+ pxp_write(dev, HW_PXP_CSC1_COEF0, BM_PXP_CSC1_COEF0_BYPASS);
}
if (!pxp_v4l2_pix_fmt_is_yuv(ctx->q_data[V4L2_M2M_SRC].fmt->fourcc) &&
@@ -706,18 +747,95 @@ static void pxp_setup_csc(struct pxp_ctx *ctx)
BP_PXP_CSC2_CTRL_CSC_MODE;
}
- writel(csc2_ctrl, dev->mmio + HW_PXP_CSC2_CTRL);
- writel(csc2_coef[0], dev->mmio + HW_PXP_CSC2_COEF0);
- writel(csc2_coef[1], dev->mmio + HW_PXP_CSC2_COEF1);
- writel(csc2_coef[2], dev->mmio + HW_PXP_CSC2_COEF2);
- writel(csc2_coef[3], dev->mmio + HW_PXP_CSC2_COEF3);
- writel(csc2_coef[4], dev->mmio + HW_PXP_CSC2_COEF4);
- writel(csc2_coef[5], dev->mmio + HW_PXP_CSC2_COEF5);
+ pxp_write(dev, HW_PXP_CSC2_CTRL, csc2_ctrl);
+ pxp_write(dev, HW_PXP_CSC2_COEF0, csc2_coef[0]);
+ pxp_write(dev, HW_PXP_CSC2_COEF1, csc2_coef[1]);
+ pxp_write(dev, HW_PXP_CSC2_COEF2, csc2_coef[2]);
+ pxp_write(dev, HW_PXP_CSC2_COEF3, csc2_coef[3]);
+ pxp_write(dev, HW_PXP_CSC2_COEF4, csc2_coef[4]);
+ pxp_write(dev, HW_PXP_CSC2_COEF5, csc2_coef[5]);
} else {
- writel(BM_PXP_CSC2_CTRL_BYPASS, dev->mmio + HW_PXP_CSC2_CTRL);
+ pxp_write(dev, HW_PXP_CSC2_CTRL, BM_PXP_CSC2_CTRL_BYPASS);
}
}
+static u32 pxp_imx6ull_data_path_ctrl0(struct pxp_ctx *ctx)
+{
+ u32 ctrl0;
+
+ ctrl0 = 0;
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX15_SEL(3);
+ /* Bypass Dithering x3CH */
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX14_SEL(1);
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX13_SEL(3);
+ /* Select Rotation */
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX12_SEL(0);
+ /* Bypass LUT */
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX11_SEL(1);
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX10_SEL(3);
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX9_SEL(3);
+ /* Select CSC 2 */
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX8_SEL(0);
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX7_SEL(3);
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX6_SEL(3);
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX5_SEL(3);
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX4_SEL(3);
+ /* Bypass Rotation 2 */
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX3_SEL(0);
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX2_SEL(3);
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX1_SEL(3);
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX0_SEL(3);
+
+ return ctrl0;
+}
+
+static u32 pxp_imx7d_data_path_ctrl0(struct pxp_ctx *ctx)
+{
+ u32 ctrl0;
+
+ ctrl0 = 0;
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX15_SEL(3);
+ /* Select Rotation 0 */
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX14_SEL(0);
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX13_SEL(3);
+ /* Select MUX11 for Rotation 0 */
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX12_SEL(1);
+ /* Bypass LUT */
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX11_SEL(1);
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX10_SEL(3);
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX9_SEL(3);
+ /* Select CSC 2 */
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX8_SEL(0);
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX7_SEL(3);
+ /* Select Composite Alpha Blending/Color Key 0 for CSC 2 */
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX6_SEL(1);
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX5_SEL(3);
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX4_SEL(3);
+ /* Bypass Rotation 1 */
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX3_SEL(0);
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX2_SEL(3);
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX1_SEL(3);
+ ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX0_SEL(3);
+
+ return ctrl0;
+}
+
+static void pxp_set_data_path(struct pxp_ctx *ctx)
+{
+ struct pxp_dev *dev = ctx->dev;
+ u32 ctrl0;
+ u32 ctrl1;
+
+ ctrl0 = dev->pdata->data_path_ctrl0(ctx);
+
+ ctrl1 = 0;
+ ctrl1 |= BF_PXP_DATA_PATH_CTRL1_MUX17_SEL(3);
+ ctrl1 |= BF_PXP_DATA_PATH_CTRL1_MUX16_SEL(3);
+
+ pxp_write(dev, HW_PXP_DATA_PATH_CTRL0, ctrl0);
+ pxp_write(dev, HW_PXP_DATA_PATH_CTRL1, ctrl1);
+}
+
static int pxp_start(struct pxp_ctx *ctx, struct vb2_v4l2_buffer *in_vb,
struct vb2_v4l2_buffer *out_vb)
{
@@ -871,67 +989,48 @@ static int pxp_start(struct pxp_ctx *ctx, struct vb2_v4l2_buffer *in_vb,
BF_PXP_PS_SCALE_XSCALE(xscale);
ps_offset = BF_PXP_PS_OFFSET_YOFFSET(0) | BF_PXP_PS_OFFSET_XOFFSET(0);
- writel(ctrl, dev->mmio + HW_PXP_CTRL);
+ pxp_write(dev, HW_PXP_CTRL, ctrl);
/* skip STAT */
- writel(out_ctrl, dev->mmio + HW_PXP_OUT_CTRL);
- writel(out_buf, dev->mmio + HW_PXP_OUT_BUF);
- writel(out_buf2, dev->mmio + HW_PXP_OUT_BUF2);
- writel(out_pitch, dev->mmio + HW_PXP_OUT_PITCH);
- writel(out_lrc, dev->mmio + HW_PXP_OUT_LRC);
- writel(out_ps_ulc, dev->mmio + HW_PXP_OUT_PS_ULC);
- writel(out_ps_lrc, dev->mmio + HW_PXP_OUT_PS_LRC);
- writel(as_ulc, dev->mmio + HW_PXP_OUT_AS_ULC);
- writel(as_lrc, dev->mmio + HW_PXP_OUT_AS_LRC);
- writel(ps_ctrl, dev->mmio + HW_PXP_PS_CTRL);
- writel(ps_buf, dev->mmio + HW_PXP_PS_BUF);
- writel(ps_ubuf, dev->mmio + HW_PXP_PS_UBUF);
- writel(ps_vbuf, dev->mmio + HW_PXP_PS_VBUF);
- writel(ps_pitch, dev->mmio + HW_PXP_PS_PITCH);
- writel(0x00ffffff, dev->mmio + HW_PXP_PS_BACKGROUND_0);
- writel(ps_scale, dev->mmio + HW_PXP_PS_SCALE);
- writel(ps_offset, dev->mmio + HW_PXP_PS_OFFSET);
+ pxp_write(dev, HW_PXP_OUT_CTRL, out_ctrl);
+ pxp_write(dev, HW_PXP_OUT_BUF, out_buf);
+ pxp_write(dev, HW_PXP_OUT_BUF2, out_buf2);
+ pxp_write(dev, HW_PXP_OUT_PITCH, out_pitch);
+ pxp_write(dev, HW_PXP_OUT_LRC, out_lrc);
+ pxp_write(dev, HW_PXP_OUT_PS_ULC, out_ps_ulc);
+ pxp_write(dev, HW_PXP_OUT_PS_LRC, out_ps_lrc);
+ pxp_write(dev, HW_PXP_OUT_AS_ULC, as_ulc);
+ pxp_write(dev, HW_PXP_OUT_AS_LRC, as_lrc);
+ pxp_write(dev, HW_PXP_PS_CTRL, ps_ctrl);
+ pxp_write(dev, HW_PXP_PS_BUF, ps_buf);
+ pxp_write(dev, HW_PXP_PS_UBUF, ps_ubuf);
+ pxp_write(dev, HW_PXP_PS_VBUF, ps_vbuf);
+ pxp_write(dev, HW_PXP_PS_PITCH, ps_pitch);
+ pxp_write(dev, HW_PXP_PS_BACKGROUND_0, 0x00ffffff);
+ pxp_write(dev, HW_PXP_PS_SCALE, ps_scale);
+ pxp_write(dev, HW_PXP_PS_OFFSET, ps_offset);
/* disable processed surface color keying */
- writel(0x00ffffff, dev->mmio + HW_PXP_PS_CLRKEYLOW_0);
- writel(0x00000000, dev->mmio + HW_PXP_PS_CLRKEYHIGH_0);
+ pxp_write(dev, HW_PXP_PS_CLRKEYLOW_0, 0x00ffffff);
+ pxp_write(dev, HW_PXP_PS_CLRKEYHIGH_0, 0x00000000);
/* disable alpha surface color keying */
- writel(0x00ffffff, dev->mmio + HW_PXP_AS_CLRKEYLOW_0);
- writel(0x00000000, dev->mmio + HW_PXP_AS_CLRKEYHIGH_0);
+ pxp_write(dev, HW_PXP_AS_CLRKEYLOW_0, 0x00ffffff);
+ pxp_write(dev, HW_PXP_AS_CLRKEYHIGH_0, 0x00000000);
/* setup CSC */
pxp_setup_csc(ctx);
/* bypass LUT */
- writel(BM_PXP_LUT_CTRL_BYPASS, dev->mmio + HW_PXP_LUT_CTRL);
-
- writel(BF_PXP_DATA_PATH_CTRL0_MUX15_SEL(0)|
- BF_PXP_DATA_PATH_CTRL0_MUX14_SEL(1)|
- BF_PXP_DATA_PATH_CTRL0_MUX13_SEL(0)|
- BF_PXP_DATA_PATH_CTRL0_MUX12_SEL(0)|
- BF_PXP_DATA_PATH_CTRL0_MUX11_SEL(0)|
- BF_PXP_DATA_PATH_CTRL0_MUX10_SEL(0)|
- BF_PXP_DATA_PATH_CTRL0_MUX9_SEL(1)|
- BF_PXP_DATA_PATH_CTRL0_MUX8_SEL(0)|
- BF_PXP_DATA_PATH_CTRL0_MUX7_SEL(0)|
- BF_PXP_DATA_PATH_CTRL0_MUX6_SEL(0)|
- BF_PXP_DATA_PATH_CTRL0_MUX5_SEL(0)|
- BF_PXP_DATA_PATH_CTRL0_MUX4_SEL(0)|
- BF_PXP_DATA_PATH_CTRL0_MUX3_SEL(0)|
- BF_PXP_DATA_PATH_CTRL0_MUX2_SEL(0)|
- BF_PXP_DATA_PATH_CTRL0_MUX1_SEL(0)|
- BF_PXP_DATA_PATH_CTRL0_MUX0_SEL(0),
- dev->mmio + HW_PXP_DATA_PATH_CTRL0);
- writel(BF_PXP_DATA_PATH_CTRL1_MUX17_SEL(1) |
- BF_PXP_DATA_PATH_CTRL1_MUX16_SEL(1),
- dev->mmio + HW_PXP_DATA_PATH_CTRL1);
-
- writel(0xffff, dev->mmio + HW_PXP_IRQ_MASK);
+ pxp_write(dev, HW_PXP_LUT_CTRL, BM_PXP_LUT_CTRL_BYPASS);
+
+ pxp_set_data_path(ctx);
+
+ pxp_write(dev, HW_PXP_IRQ_MASK, 0xffff);
/* ungate, enable PS/AS/OUT and PXP operation */
- writel(BM_PXP_CTRL_IRQ_ENABLE, dev->mmio + HW_PXP_CTRL_SET);
- writel(BM_PXP_CTRL_ENABLE | BM_PXP_CTRL_ENABLE_CSC2 |
- BM_PXP_CTRL_ENABLE_LUT | BM_PXP_CTRL_ENABLE_ROTATE0 |
- BM_PXP_CTRL_ENABLE_PS_AS_OUT, dev->mmio + HW_PXP_CTRL_SET);
+ pxp_write(dev, HW_PXP_CTRL_SET, BM_PXP_CTRL_IRQ_ENABLE);
+ pxp_write(dev, HW_PXP_CTRL_SET,
+ BM_PXP_CTRL_ENABLE | BM_PXP_CTRL_ENABLE_CSC2 |
+ BM_PXP_CTRL_ENABLE_ROTATE0 | BM_PXP_CTRL_ENABLE_PS_AS_OUT);
return 0;
}
@@ -1004,23 +1103,23 @@ static irqreturn_t pxp_irq_handler(int irq, void *dev_id)
struct pxp_dev *dev = dev_id;
u32 stat;
- stat = readl(dev->mmio + HW_PXP_STAT);
+ stat = pxp_read(dev, HW_PXP_STAT);
if (stat & BM_PXP_STAT_IRQ0) {
/* we expect x = 0, y = height, irq0 = 1 */
if (stat & ~(BM_PXP_STAT_BLOCKX | BM_PXP_STAT_BLOCKY |
BM_PXP_STAT_IRQ0))
dprintk(dev, "%s: stat = 0x%08x\n", __func__, stat);
- writel(BM_PXP_STAT_IRQ0, dev->mmio + HW_PXP_STAT_CLR);
+ pxp_write(dev, HW_PXP_STAT_CLR, BM_PXP_STAT_IRQ0);
pxp_job_finish(dev);
} else {
- u32 irq = readl(dev->mmio + HW_PXP_IRQ);
+ u32 irq = pxp_read(dev, HW_PXP_IRQ);
dprintk(dev, "%s: stat = 0x%08x\n", __func__, stat);
dprintk(dev, "%s: irq = 0x%08x\n", __func__, irq);
- writel(irq, dev->mmio + HW_PXP_IRQ_CLR);
+ pxp_write(dev, HW_PXP_IRQ_CLR, irq);
}
return IRQ_HANDLED;
@@ -1034,8 +1133,6 @@ static int pxp_querycap(struct file *file, void *priv,
{
strscpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver));
strscpy(cap->card, MEM2MEM_NAME, sizeof(cap->card));
- snprintf(cap->bus_info, sizeof(cap->bus_info),
- "platform:%s", MEM2MEM_NAME);
return 0;
}
@@ -1181,10 +1278,10 @@ static int pxp_try_fmt_vid_cap(struct file *file, void *priv,
struct pxp_fmt *fmt;
struct pxp_ctx *ctx = file2ctx(file);
- fmt = find_format(f);
+ fmt = find_format(f->fmt.pix.pixelformat);
if (!fmt) {
f->fmt.pix.pixelformat = formats[0].fourcc;
- fmt = find_format(f);
+ fmt = find_format(f->fmt.pix.pixelformat);
}
if (!(fmt->types & MEM2MEM_CAPTURE)) {
v4l2_err(&ctx->dev->v4l2_dev,
@@ -1209,10 +1306,10 @@ static int pxp_try_fmt_vid_out(struct file *file, void *priv,
struct pxp_fmt *fmt;
struct pxp_ctx *ctx = file2ctx(file);
- fmt = find_format(f);
+ fmt = find_format(f->fmt.pix.pixelformat);
if (!fmt) {
f->fmt.pix.pixelformat = formats[0].fourcc;
- fmt = find_format(f);
+ fmt = find_format(f->fmt.pix.pixelformat);
}
if (!(fmt->types & MEM2MEM_OUTPUT)) {
v4l2_err(&ctx->dev->v4l2_dev,
@@ -1245,7 +1342,7 @@ static int pxp_s_fmt(struct pxp_ctx *ctx, struct v4l2_format *f)
return -EBUSY;
}
- q_data->fmt = find_format(f);
+ q_data->fmt = find_format(f->fmt.pix.pixelformat);
q_data->width = f->fmt.pix.width;
q_data->height = f->fmt.pix.height;
q_data->bytesperline = f->fmt.pix.bytesperline;
@@ -1304,6 +1401,26 @@ static int pxp_s_fmt_vid_out(struct file *file, void *priv,
return 0;
}
+static int pxp_enum_framesizes(struct file *file, void *fh,
+ struct v4l2_frmsizeenum *fsize)
+{
+ if (fsize->index > 0)
+ return -EINVAL;
+
+ if (!find_format(fsize->pixel_format))
+ return -EINVAL;
+
+ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+ fsize->stepwise.min_width = MIN_W;
+ fsize->stepwise.max_width = MAX_W;
+ fsize->stepwise.step_width = 1 << ALIGN_W;
+ fsize->stepwise.min_height = MIN_H;
+ fsize->stepwise.max_height = MAX_H;
+ fsize->stepwise.step_height = 1 << ALIGN_H;
+
+ return 0;
+}
+
static u8 pxp_degrees_to_rot_mode(u32 degrees)
{
switch (degrees) {
@@ -1372,6 +1489,8 @@ static const struct v4l2_ioctl_ops pxp_ioctl_ops = {
.vidioc_try_fmt_vid_out = pxp_try_fmt_vid_out,
.vidioc_s_fmt_vid_out = pxp_s_fmt_vid_out,
+ .vidioc_enum_framesizes = pxp_enum_framesizes,
+
.vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
.vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
.vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
@@ -1644,18 +1763,18 @@ static int pxp_soft_reset(struct pxp_dev *dev)
int ret;
u32 val;
- writel(BM_PXP_CTRL_SFTRST, dev->mmio + HW_PXP_CTRL_CLR);
- writel(BM_PXP_CTRL_CLKGATE, dev->mmio + HW_PXP_CTRL_CLR);
+ pxp_write(dev, HW_PXP_CTRL_CLR, BM_PXP_CTRL_SFTRST);
+ pxp_write(dev, HW_PXP_CTRL_CLR, BM_PXP_CTRL_CLKGATE);
- writel(BM_PXP_CTRL_SFTRST, dev->mmio + HW_PXP_CTRL_SET);
+ pxp_write(dev, HW_PXP_CTRL_SET, BM_PXP_CTRL_SFTRST);
- ret = readl_poll_timeout(dev->mmio + HW_PXP_CTRL, val,
- val & BM_PXP_CTRL_CLKGATE, 0, 100);
+ ret = regmap_read_poll_timeout(dev->regmap, HW_PXP_CTRL, val,
+ val & BM_PXP_CTRL_CLKGATE, 0, 100);
if (ret < 0)
return ret;
- writel(BM_PXP_CTRL_SFTRST, dev->mmio + HW_PXP_CTRL_CLR);
- writel(BM_PXP_CTRL_CLKGATE, dev->mmio + HW_PXP_CTRL_CLR);
+ pxp_write(dev, HW_PXP_CTRL_CLR, BM_PXP_CTRL_SFTRST);
+ pxp_write(dev, HW_PXP_CTRL_CLR, BM_PXP_CTRL_CLKGATE);
return 0;
}
@@ -1664,13 +1783,17 @@ static int pxp_probe(struct platform_device *pdev)
{
struct pxp_dev *dev;
struct video_device *vfd;
+ u32 hw_version;
int irq;
int ret;
+ void __iomem *mmio;
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
+ dev->pdata = of_device_get_match_data(&pdev->dev);
+
dev->clk = devm_clk_get(&pdev->dev, "axi");
if (IS_ERR(dev->clk)) {
ret = PTR_ERR(dev->clk);
@@ -1678,9 +1801,11 @@ static int pxp_probe(struct platform_device *pdev)
return ret;
}
- dev->mmio = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(dev->mmio))
- return PTR_ERR(dev->mmio);
+ mmio = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(mmio))
+ return PTR_ERR(mmio);
+ dev->regmap = devm_regmap_init_mmio(&pdev->dev, mmio,
+ &pxp_regmap_config);
irq = platform_get_irq(pdev, 0);
if (irq < 0)
@@ -1688,8 +1813,8 @@ static int pxp_probe(struct platform_device *pdev)
spin_lock_init(&dev->irqlock);
- ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, pxp_irq_handler,
- IRQF_ONESHOT, dev_name(&pdev->dev), dev);
+ ret = devm_request_irq(&pdev->dev, irq, pxp_irq_handler, 0,
+ dev_name(&pdev->dev), dev);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to request irq: %d\n", ret);
return ret;
@@ -1705,6 +1830,10 @@ static int pxp_probe(struct platform_device *pdev)
goto err_clk;
}
+ hw_version = pxp_read(dev, HW_PXP_VERSION);
+ dev_dbg(&pdev->dev, "PXP Version %u.%u\n",
+ PXP_VERSION_MAJOR(hw_version), PXP_VERSION_MINOR(hw_version));
+
ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
if (ret)
goto err_clk;
@@ -1737,8 +1866,34 @@ static int pxp_probe(struct platform_device *pdev)
goto err_m2m;
}
+#ifdef CONFIG_MEDIA_CONTROLLER
+ dev->mdev.dev = &pdev->dev;
+ strscpy(dev->mdev.model, MEM2MEM_NAME, sizeof(dev->mdev.model));
+ media_device_init(&dev->mdev);
+ dev->v4l2_dev.mdev = &dev->mdev;
+
+ ret = v4l2_m2m_register_media_controller(dev->m2m_dev, vfd,
+ MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to initialize media device\n");
+ goto err_vfd;
+ }
+
+ ret = media_device_register(&dev->mdev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register media device\n");
+ goto err_m2m_mc;
+ }
+#endif
+
return 0;
+#ifdef CONFIG_MEDIA_CONTROLLER
+err_m2m_mc:
+ v4l2_m2m_unregister_media_controller(dev->m2m_dev);
+err_vfd:
+ video_unregister_device(vfd);
+#endif
err_m2m:
v4l2_m2m_release(dev->m2m_dev);
err_v4l2:
@@ -1753,12 +1908,17 @@ static int pxp_remove(struct platform_device *pdev)
{
struct pxp_dev *dev = platform_get_drvdata(pdev);
- writel(BM_PXP_CTRL_CLKGATE, dev->mmio + HW_PXP_CTRL_SET);
- writel(BM_PXP_CTRL_SFTRST, dev->mmio + HW_PXP_CTRL_SET);
+ pxp_write(dev, HW_PXP_CTRL_SET, BM_PXP_CTRL_CLKGATE);
+ pxp_write(dev, HW_PXP_CTRL_SET, BM_PXP_CTRL_SFTRST);
clk_disable_unprepare(dev->clk);
v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME);
+
+#ifdef CONFIG_MEDIA_CONTROLLER
+ media_device_unregister(&dev->mdev);
+ v4l2_m2m_unregister_media_controller(dev->m2m_dev);
+#endif
video_unregister_device(&dev->vfd);
v4l2_m2m_release(dev->m2m_dev);
v4l2_device_unregister(&dev->v4l2_dev);
@@ -1766,8 +1926,17 @@ static int pxp_remove(struct platform_device *pdev)
return 0;
}
+static const struct pxp_pdata pxp_imx6ull_pdata = {
+ .data_path_ctrl0 = pxp_imx6ull_data_path_ctrl0,
+};
+
+static const struct pxp_pdata pxp_imx7d_pdata = {
+ .data_path_ctrl0 = pxp_imx7d_data_path_ctrl0,
+};
+
static const struct of_device_id pxp_dt_ids[] = {
- { .compatible = "fsl,imx6ull-pxp", .data = NULL },
+ { .compatible = "fsl,imx6ull-pxp", .data = &pxp_imx6ull_pdata },
+ { .compatible = "fsl,imx7d-pxp", .data = &pxp_imx7d_pdata },
{ },
};
MODULE_DEVICE_TABLE(of, pxp_dt_ids);
diff --git a/drivers/media/platform/nxp/imx7-media-csi.c b/drivers/media/platform/nxp/imx7-media-csi.c
index 886374d3a6ff..c22bf5c827e7 100644
--- a/drivers/media/platform/nxp/imx7-media-csi.c
+++ b/drivers/media/platform/nxp/imx7-media-csi.c
@@ -211,7 +211,6 @@ struct imx7_csi {
int irq;
struct clk *mclk;
- struct mutex lock; /* Protects is_streaming, format_mbus, cc */
spinlock_t irqlock; /* Protects last_eof */
/* Media and V4L2 device */
@@ -227,9 +226,6 @@ struct imx7_csi {
struct v4l2_subdev sd;
struct media_pad pad[IMX7_CSI_PADS_NUM];
- struct v4l2_mbus_framefmt format_mbus[IMX7_CSI_PADS_NUM];
- const struct imx7_csi_pixfmt *cc[IMX7_CSI_PADS_NUM];
-
/* Video device */
struct video_device *vdev; /* Video device */
struct media_pad vdev_pad; /* Video device pad */
@@ -510,7 +506,8 @@ static void imx7_csi_dma_stop(struct imx7_csi *csi)
imx7_csi_hw_disable_irq(csi);
}
-static void imx7_csi_configure(struct imx7_csi *csi)
+static void imx7_csi_configure(struct imx7_csi *csi,
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_pix_format *out_pix = &csi->vdev_fmt;
int width = out_pix->width;
@@ -541,12 +538,17 @@ static void imx7_csi_configure(struct imx7_csi *csi)
out_pix->pixelformat == V4L2_PIX_FMT_YUYV)
width *= 2;
} else {
+ const struct v4l2_mbus_framefmt *sink_fmt;
+
+ sink_fmt = v4l2_subdev_get_pad_format(&csi->sd, sd_state,
+ IMX7_CSI_PAD_SINK);
+
cr1 = BIT_SOF_POL | BIT_REDGE | BIT_HSYNC_POL | BIT_FCC
| BIT_MCLKDIV(1) | BIT_MCLKEN;
cr18 |= BIT_DATA_FROM_MIPI;
- switch (csi->format_mbus[IMX7_CSI_PAD_SINK].code) {
+ switch (sink_fmt->code) {
case MEDIA_BUS_FMT_Y8_1X8:
case MEDIA_BUS_FMT_SBGGR8_1X8:
case MEDIA_BUS_FMT_SGBRG8_1X8:
@@ -627,7 +629,8 @@ static void imx7_csi_configure(struct imx7_csi *csi)
imx7_csi_reg_write(csi, stride, CSI_CSIFBUF_PARA);
}
-static int imx7_csi_init(struct imx7_csi *csi)
+static int imx7_csi_init(struct imx7_csi *csi,
+ struct v4l2_subdev_state *sd_state)
{
int ret;
@@ -635,11 +638,13 @@ static int imx7_csi_init(struct imx7_csi *csi)
if (ret < 0)
return ret;
- imx7_csi_configure(csi);
+ imx7_csi_configure(csi, sd_state);
ret = imx7_csi_dma_setup(csi);
- if (ret < 0)
+ if (ret < 0) {
+ clk_disable_unprepare(csi->mclk);
return ret;
+ }
return 0;
}
@@ -1411,14 +1416,15 @@ static void imx7_csi_video_buf_queue(struct vb2_buffer *vb)
static int imx7_csi_video_validate_fmt(struct imx7_csi *csi)
{
- struct v4l2_subdev_format fmt_src;
+ struct v4l2_subdev_format fmt_src = {
+ .pad = IMX7_CSI_PAD_SRC,
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
const struct imx7_csi_pixfmt *cc;
int ret;
/* Retrieve the media bus format on the source subdev. */
- fmt_src.pad = IMX7_CSI_PAD_SRC;
- fmt_src.which = V4L2_SUBDEV_FORMAT_ACTIVE;
- ret = v4l2_subdev_call(&csi->sd, pad, get_fmt, NULL, &fmt_src);
+ ret = v4l2_subdev_call_state_active(&csi->sd, pad, get_fmt, &fmt_src);
if (ret)
return ret;
@@ -1599,17 +1605,15 @@ static struct imx7_csi_vb2_buffer *imx7_csi_video_next_buf(struct imx7_csi *csi)
static int imx7_csi_video_init_format(struct imx7_csi *csi)
{
- struct v4l2_subdev_format fmt_src = {
- .pad = IMX7_CSI_PAD_SRC,
- .which = V4L2_SUBDEV_FORMAT_ACTIVE,
- };
- fmt_src.format.code = IMX7_CSI_DEF_MBUS_CODE;
- fmt_src.format.width = IMX7_CSI_DEF_PIX_WIDTH;
- fmt_src.format.height = IMX7_CSI_DEF_PIX_HEIGHT;
+ struct v4l2_mbus_framefmt format = { };
+
+ format.code = IMX7_CSI_DEF_MBUS_CODE;
+ format.width = IMX7_CSI_DEF_PIX_WIDTH;
+ format.height = IMX7_CSI_DEF_PIX_HEIGHT;
- imx7_csi_mbus_fmt_to_pix_fmt(&csi->vdev_fmt, &fmt_src.format, NULL);
- csi->vdev_compose.width = fmt_src.format.width;
- csi->vdev_compose.height = fmt_src.format.height;
+ imx7_csi_mbus_fmt_to_pix_fmt(&csi->vdev_fmt, &format, NULL);
+ csi->vdev_compose.width = format.width;
+ csi->vdev_compose.height = format.height;
csi->vdev_cc = imx7_csi_find_pixel_format(csi->vdev_fmt.pixelformat);
@@ -1728,20 +1732,13 @@ static int imx7_csi_video_init(struct imx7_csi *csi)
static int imx7_csi_s_stream(struct v4l2_subdev *sd, int enable)
{
struct imx7_csi *csi = v4l2_get_subdevdata(sd);
+ struct v4l2_subdev_state *sd_state;
int ret = 0;
- mutex_lock(&csi->lock);
-
- if (!csi->src_sd) {
- ret = -EPIPE;
- goto out_unlock;
- }
-
- if (csi->is_streaming == !!enable)
- goto out_unlock;
+ sd_state = v4l2_subdev_lock_and_get_active_state(sd);
if (enable) {
- ret = imx7_csi_init(csi);
+ ret = imx7_csi_init(csi, sd_state);
if (ret < 0)
goto out_unlock;
@@ -1763,29 +1760,14 @@ static int imx7_csi_s_stream(struct v4l2_subdev *sd, int enable)
csi->is_streaming = !!enable;
out_unlock:
- mutex_unlock(&csi->lock);
+ v4l2_subdev_unlock_state(sd_state);
return ret;
}
-static struct v4l2_mbus_framefmt *
-imx7_csi_get_format(struct imx7_csi *csi,
- struct v4l2_subdev_state *sd_state,
- unsigned int pad,
- enum v4l2_subdev_format_whence which)
-{
- if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&csi->sd, sd_state, pad);
-
- return &csi->format_mbus[pad];
-}
-
static int imx7_csi_init_cfg(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state)
{
- const enum v4l2_subdev_format_whence which =
- sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
- struct imx7_csi *csi = v4l2_get_subdevdata(sd);
const struct imx7_csi_pixfmt *cc;
int i;
@@ -1793,7 +1775,7 @@ static int imx7_csi_init_cfg(struct v4l2_subdev *sd,
for (i = 0; i < IMX7_CSI_PADS_NUM; i++) {
struct v4l2_mbus_framefmt *mf =
- imx7_csi_get_format(csi, sd_state, i, which);
+ v4l2_subdev_get_pad_format(sd, sd_state, i);
mf->code = IMX7_CSI_DEF_MBUS_CODE;
mf->width = IMX7_CSI_DEF_PIX_WIDTH;
@@ -1805,8 +1787,6 @@ static int imx7_csi_init_cfg(struct v4l2_subdev *sd,
mf->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(mf->colorspace);
mf->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(!cc->yuv,
mf->colorspace, mf->ycbcr_enc);
-
- csi->cc[i] = cc;
}
return 0;
@@ -1816,59 +1796,30 @@ static int imx7_csi_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
- struct imx7_csi *csi = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *in_fmt;
int ret = 0;
- mutex_lock(&csi->lock);
-
- in_fmt = imx7_csi_get_format(csi, sd_state, IMX7_CSI_PAD_SINK,
- code->which);
+ in_fmt = v4l2_subdev_get_pad_format(sd, sd_state, IMX7_CSI_PAD_SINK);
switch (code->pad) {
case IMX7_CSI_PAD_SINK:
ret = imx7_csi_enum_mbus_formats(&code->code, code->index);
break;
+
case IMX7_CSI_PAD_SRC:
if (code->index != 0) {
ret = -EINVAL;
- goto out_unlock;
+ break;
}
code->code = in_fmt->code;
break;
- default:
- ret = -EINVAL;
- }
-
-out_unlock:
- mutex_unlock(&csi->lock);
-
- return ret;
-}
-static int imx7_csi_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *sdformat)
-{
- struct imx7_csi *csi = v4l2_get_subdevdata(sd);
- struct v4l2_mbus_framefmt *fmt;
- int ret = 0;
-
- mutex_lock(&csi->lock);
-
- fmt = imx7_csi_get_format(csi, sd_state, sdformat->pad,
- sdformat->which);
- if (!fmt) {
+ default:
ret = -EINVAL;
- goto out_unlock;
+ break;
}
- sdformat->format = *fmt;
-
-out_unlock:
- mutex_unlock(&csi->lock);
-
return ret;
}
@@ -1918,19 +1869,16 @@ static void imx7_csi_try_colorimetry(struct v4l2_mbus_framefmt *tryfmt)
tryfmt->ycbcr_enc);
}
-static int imx7_csi_try_fmt(struct imx7_csi *csi,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *sdformat,
- const struct imx7_csi_pixfmt **cc)
+static void imx7_csi_try_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *sdformat,
+ const struct imx7_csi_pixfmt **cc)
{
const struct imx7_csi_pixfmt *in_cc;
struct v4l2_mbus_framefmt *in_fmt;
u32 code;
- in_fmt = imx7_csi_get_format(csi, sd_state, IMX7_CSI_PAD_SINK,
- sdformat->which);
- if (!in_fmt)
- return -EINVAL;
+ in_fmt = v4l2_subdev_get_pad_format(sd, sd_state, IMX7_CSI_PAD_SINK);
switch (sdformat->pad) {
case IMX7_CSI_PAD_SRC:
@@ -1947,6 +1895,7 @@ static int imx7_csi_try_fmt(struct imx7_csi *csi,
sdformat->format.quantization = in_fmt->quantization;
sdformat->format.ycbcr_enc = in_fmt->ycbcr_enc;
break;
+
case IMX7_CSI_PAD_SINK:
*cc = imx7_csi_find_mbus_format(sdformat->format.code);
if (!*cc) {
@@ -1958,13 +1907,9 @@ static int imx7_csi_try_fmt(struct imx7_csi *csi,
if (sdformat->format.field != V4L2_FIELD_INTERLACED)
sdformat->format.field = V4L2_FIELD_NONE;
break;
- default:
- return -EINVAL;
}
imx7_csi_try_colorimetry(&sdformat->format);
-
- return 0;
}
static int imx7_csi_set_fmt(struct v4l2_subdev *sd,
@@ -1977,28 +1922,13 @@ static int imx7_csi_set_fmt(struct v4l2_subdev *sd,
const struct imx7_csi_pixfmt *cc;
struct v4l2_mbus_framefmt *fmt;
struct v4l2_subdev_format format;
- int ret = 0;
-
- if (sdformat->pad >= IMX7_CSI_PADS_NUM)
- return -EINVAL;
-
- mutex_lock(&csi->lock);
- if (csi->is_streaming) {
- ret = -EBUSY;
- goto out_unlock;
- }
+ if (csi->is_streaming)
+ return -EBUSY;
- ret = imx7_csi_try_fmt(csi, sd_state, sdformat, &cc);
- if (ret < 0)
- goto out_unlock;
+ imx7_csi_try_fmt(sd, sd_state, sdformat, &cc);
- fmt = imx7_csi_get_format(csi, sd_state, sdformat->pad,
- sdformat->which);
- if (!fmt) {
- ret = -EINVAL;
- goto out_unlock;
- }
+ fmt = v4l2_subdev_get_pad_format(sd, sd_state, sdformat->pad);
*fmt = sdformat->format;
@@ -2007,25 +1937,14 @@ static int imx7_csi_set_fmt(struct v4l2_subdev *sd,
format.pad = IMX7_CSI_PAD_SRC;
format.which = sdformat->which;
format.format = sdformat->format;
- if (imx7_csi_try_fmt(csi, sd_state, &format, &outcc)) {
- ret = -EINVAL;
- goto out_unlock;
- }
- outfmt = imx7_csi_get_format(csi, sd_state, IMX7_CSI_PAD_SRC,
- sdformat->which);
- *outfmt = format.format;
+ imx7_csi_try_fmt(sd, sd_state, &format, &outcc);
- if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
- csi->cc[IMX7_CSI_PAD_SRC] = outcc;
+ outfmt = v4l2_subdev_get_pad_format(sd, sd_state,
+ IMX7_CSI_PAD_SRC);
+ *outfmt = format.format;
}
- if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
- csi->cc[sdformat->pad] = cc;
-
-out_unlock:
- mutex_unlock(&csi->lock);
-
- return ret;
+ return 0;
}
static int imx7_csi_pad_link_validate(struct v4l2_subdev *sd,
@@ -2038,9 +1957,6 @@ static int imx7_csi_pad_link_validate(struct v4l2_subdev *sd,
unsigned int i;
int ret;
- if (!csi->src_sd)
- return -EPIPE;
-
/*
* Validate the source link, and record whether the source uses the
* parallel input or the CSI-2 receiver.
@@ -2128,7 +2044,7 @@ static const struct v4l2_subdev_video_ops imx7_csi_video_ops = {
static const struct v4l2_subdev_pad_ops imx7_csi_pad_ops = {
.init_cfg = imx7_csi_init_cfg,
.enum_mbus_code = imx7_csi_enum_mbus_code,
- .get_fmt = imx7_csi_get_fmt,
+ .get_fmt = v4l2_subdev_get_fmt,
.set_fmt = imx7_csi_set_fmt,
.link_validate = imx7_csi_pad_link_validate,
};
@@ -2201,7 +2117,7 @@ static int imx7_csi_async_register(struct imx7_csi *csi)
ret = PTR_ERR(asd);
/* OK if asd already exists */
if (ret != -EEXIST)
- return ret;
+ goto error;
}
}
@@ -2209,15 +2125,20 @@ static int imx7_csi_async_register(struct imx7_csi *csi)
ret = v4l2_async_nf_register(&csi->v4l2_dev, &csi->notifier);
if (ret)
- return ret;
+ goto error;
return 0;
+
+error:
+ v4l2_async_nf_cleanup(&csi->notifier);
+ return ret;
}
static void imx7_csi_media_cleanup(struct imx7_csi *csi)
{
v4l2_device_unregister(&csi->v4l2_dev);
media_device_unregister(&csi->mdev);
+ v4l2_subdev_cleanup(&csi->sd);
media_device_cleanup(&csi->mdev);
}
@@ -2285,6 +2206,10 @@ static int imx7_csi_media_init(struct imx7_csi *csi)
if (ret)
goto error;
+ ret = v4l2_subdev_init_finalize(&csi->sd);
+ if (ret)
+ goto error;
+
ret = v4l2_device_register_subdev(&csi->v4l2_dev, &csi->sd);
if (ret)
goto error;
@@ -2310,27 +2235,22 @@ static int imx7_csi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, csi);
spin_lock_init(&csi->irqlock);
- mutex_init(&csi->lock);
/* Acquire resources and install interrupt handler. */
csi->mclk = devm_clk_get(&pdev->dev, "mclk");
if (IS_ERR(csi->mclk)) {
ret = PTR_ERR(csi->mclk);
dev_err(dev, "Failed to get mclk: %d", ret);
- goto destroy_mutex;
+ return ret;
}
csi->irq = platform_get_irq(pdev, 0);
- if (csi->irq < 0) {
- ret = csi->irq;
- goto destroy_mutex;
- }
+ if (csi->irq < 0)
+ return csi->irq;
csi->regbase = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(csi->regbase)) {
- ret = PTR_ERR(csi->regbase);
- goto destroy_mutex;
- }
+ if (IS_ERR(csi->regbase))
+ return PTR_ERR(csi->regbase);
csi->model = (enum imx_csi_model)(uintptr_t)of_device_get_match_data(&pdev->dev);
@@ -2338,34 +2258,23 @@ static int imx7_csi_probe(struct platform_device *pdev)
(void *)csi);
if (ret < 0) {
dev_err(dev, "Request CSI IRQ failed.\n");
- goto destroy_mutex;
+ return ret;
}
/* Initialize all the media device infrastructure. */
ret = imx7_csi_media_init(csi);
if (ret)
- goto destroy_mutex;
-
- /* Set the default mbus formats. */
- ret = imx7_csi_init_cfg(&csi->sd, NULL);
- if (ret)
- goto media_cleanup;
+ return ret;
ret = imx7_csi_async_register(csi);
if (ret)
- goto subdev_notifier_cleanup;
+ goto err_media_cleanup;
return 0;
-subdev_notifier_cleanup:
- v4l2_async_nf_unregister(&csi->notifier);
- v4l2_async_nf_cleanup(&csi->notifier);
-media_cleanup:
+err_media_cleanup:
imx7_csi_media_cleanup(csi);
-destroy_mutex:
- mutex_destroy(&csi->lock);
-
return ret;
}
@@ -2379,8 +2288,6 @@ static int imx7_csi_remove(struct platform_device *pdev)
v4l2_async_nf_cleanup(&csi->notifier);
v4l2_async_unregister_subdev(&csi->sd);
- mutex_destroy(&csi->lock);
-
return 0;
}
diff --git a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c
index 451a4c9b3d30..04baa80494c6 100644
--- a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c
+++ b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c
@@ -429,7 +429,8 @@ static void csiphy_gen2_config_lanes(struct csiphy_device *csiphy,
array_size = ARRAY_SIZE(lane_regs_sm8250[0]);
break;
default:
- unreachable();
+ WARN(1, "unknown cspi version\n");
+ return;
}
for (l = 0; l < 5; l++) {
diff --git a/drivers/media/platform/qcom/venus/firmware.c b/drivers/media/platform/qcom/venus/firmware.c
index 142d4c74017c..61ff20a7e935 100644
--- a/drivers/media/platform/qcom/venus/firmware.c
+++ b/drivers/media/platform/qcom/venus/firmware.c
@@ -12,7 +12,7 @@
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/of_device.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/sizes.h>
#include <linux/soc/qcom/mdt_loader.h>
@@ -158,7 +158,7 @@ static int venus_boot_no_tz(struct venus_core *core, phys_addr_t mem_phys,
core->fw.mapped_mem_size = mem_size;
ret = iommu_map(iommu, VENUS_FW_START_ADDR, mem_phys, mem_size,
- IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV);
+ IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV, GFP_KERNEL);
if (ret) {
dev_err(dev, "could not map video firmware region\n");
return ret;
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
index 33e08efa3039..384fb54e219a 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
@@ -406,7 +406,7 @@ static void rzg2l_csi2_mipi_link_disable(struct rzg2l_csi2 *csi2)
if (!(rzg2l_csi2_read(csi2, CSI2nRTST) & CSI2nRTST_VSRSTS))
break;
usleep_range(100, 200);
- };
+ }
if (!timeout)
dev_err(csi2->dev, "Clearing CSI2nRTST.VSRSTS timed out\n");
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
index 91b57c7c2e56..e6eedd65b71d 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
@@ -404,7 +404,7 @@ void rzg2l_cru_stop_image_processing(struct rzg2l_cru_dev *cru)
break;
usleep_range(10, 20);
- };
+ }
/* Notify that AXI bus can not stop here */
if (!retries)
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_drv.c b/drivers/media/platform/renesas/vsp1/vsp1_drv.c
index c260d318d298..5710152d6511 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_drv.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_drv.c
@@ -818,9 +818,9 @@ static const struct vsp1_device_info vsp1_device_infos[] = {
.wpf_count = 2,
.num_bru_inputs = 5,
}, {
- .version = VI6_IP_VERSION_MODEL_VSPD_V3U,
+ .version = VI6_IP_VERSION_MODEL_VSPD_GEN4,
.model = "VSP2-D",
- .gen = 3,
+ .gen = 4,
.features = VSP1_HAS_BRU | VSP1_HAS_EXT_DL,
.lif_count = 1,
.rpf_count = 5,
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_hgo.c b/drivers/media/platform/renesas/vsp1/vsp1_hgo.c
index bf3f981f93a1..e6492deb0a64 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_hgo.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_hgo.c
@@ -196,10 +196,10 @@ struct vsp1_hgo *vsp1_hgo_create(struct vsp1_device *vsp1)
/* Initialize the control handler. */
v4l2_ctrl_handler_init(&hgo->ctrls.handler,
- vsp1->info->gen == 3 ? 2 : 1);
+ vsp1->info->gen >= 3 ? 2 : 1);
hgo->ctrls.max_rgb = v4l2_ctrl_new_custom(&hgo->ctrls.handler,
&hgo_max_rgb_control, NULL);
- if (vsp1->info->gen == 3)
+ if (vsp1->info->gen >= 3)
hgo->ctrls.num_bins =
v4l2_ctrl_new_custom(&hgo->ctrls.handler,
&hgo_num_bins_control, NULL);
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_lif.c b/drivers/media/platform/renesas/vsp1/vsp1_lif.c
index 186a5730e1e3..0ab2e0c70474 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_lif.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_lif.c
@@ -114,6 +114,7 @@ static void lif_configure_stream(struct vsp1_entity *entity,
break;
case VI6_IP_VERSION_MODEL_VSPD_GEN3:
+ case VI6_IP_VERSION_MODEL_VSPD_GEN4:
default:
hbth = 0;
obth = 3000;
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_pipe.c b/drivers/media/platform/renesas/vsp1/vsp1_pipe.c
index f72ac01c21ea..f8093ba9539e 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_pipe.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_pipe.c
@@ -146,6 +146,18 @@ static const struct vsp1_format_info vsp1_video_formats[] = {
VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
1, { 32, 0, 0 }, false, false, 1, 1, false },
+ { V4L2_PIX_FMT_RGBX1010102, MEDIA_BUS_FMT_ARGB8888_1X32,
+ VI6_FMT_RGB10_RGB10A2_A2RGB10,
+ VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS,
+ 1, { 32, 0, 0 }, false, false, 1, 1, false },
+ { V4L2_PIX_FMT_RGBA1010102, MEDIA_BUS_FMT_ARGB8888_1X32,
+ VI6_FMT_RGB10_RGB10A2_A2RGB10,
+ VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS,
+ 1, { 32, 0, 0 }, false, false, 1, 1, false },
+ { V4L2_PIX_FMT_ARGB2101010, MEDIA_BUS_FMT_ARGB8888_1X32,
+ VI6_FMT_RGB10_RGB10A2_A2RGB10,
+ VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS,
+ 1, { 32, 0, 0 }, false, false, 1, 1, false },
{ V4L2_PIX_FMT_UYVY, MEDIA_BUS_FMT_AYUV8_1X32,
VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
@@ -202,6 +214,12 @@ static const struct vsp1_format_info vsp1_video_formats[] = {
VI6_FMT_Y_U_V_444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
3, { 8, 8, 8 }, false, true, 1, 1, false },
+ { V4L2_PIX_FMT_Y210, MEDIA_BUS_FMT_AYUV8_1X32,
+ VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS,
+ 1, { 32, 0, 0 }, false, false, 2, 1, false },
+ { V4L2_PIX_FMT_Y212, MEDIA_BUS_FMT_AYUV8_1X32,
+ VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS,
+ 1, { 32, 0, 0 }, false, false, 2, 1, false },
};
/**
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_regs.h b/drivers/media/platform/renesas/vsp1/vsp1_regs.h
index 8928f4c6bb55..d94343ae57a1 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_regs.h
+++ b/drivers/media/platform/renesas/vsp1/vsp1_regs.h
@@ -228,6 +228,28 @@
#define VI6_RPF_MULT_ALPHA_RATIO_MASK (0xff << 0)
#define VI6_RPF_MULT_ALPHA_RATIO_SHIFT 0
+#define VI6_RPF_EXT_INFMT0 0x0370
+#define VI6_RPF_EXT_INFMT0_F2B BIT(12)
+#define VI6_RPF_EXT_INFMT0_IPBD_Y_8 (0 << 8)
+#define VI6_RPF_EXT_INFMT0_IPBD_Y_10 (1 << 8)
+#define VI6_RPF_EXT_INFMT0_IPBD_Y_12 (2 << 8)
+#define VI6_RPF_EXT_INFMT0_IPBD_C_8 (0 << 4)
+#define VI6_RPF_EXT_INFMT0_IPBD_C_10 (1 << 4)
+#define VI6_RPF_EXT_INFMT0_IPBD_C_12 (2 << 4)
+#define VI6_RPF_EXT_INFMT0_BYPP_M1_RGB10 (3 << 0)
+
+#define VI6_RPF_EXT_INFMT1 0x0374
+#define VI6_RPF_EXT_INFMT1_PACK_CPOS(a, b, c, d) \
+ (((a) << 24) | ((b) << 16) | ((c) << 8) | ((d) << 0))
+
+#define VI6_RPF_EXT_INFMT2 0x0378
+#define VI6_RPF_EXT_INFMT2_PACK_CLEN(a, b, c, d) \
+ (((a) << 24) | ((b) << 16) | ((c) << 8) | ((d) << 0))
+
+#define VI6_RPF_BRDITH_CTRL 0x03e0
+#define VI6_RPF_BRDITH_CTRL_ODE BIT(8)
+#define VI6_RPF_BRDITH_CTRL_CBRM BIT(0)
+
/* -----------------------------------------------------------------------------
* WPF Control Registers
*/
@@ -766,7 +788,7 @@
#define VI6_IP_VERSION_MODEL_VSPD_V3 (0x18 << 8)
#define VI6_IP_VERSION_MODEL_VSPDL_GEN3 (0x19 << 8)
#define VI6_IP_VERSION_MODEL_VSPBS_GEN3 (0x1a << 8)
-#define VI6_IP_VERSION_MODEL_VSPD_V3U (0x1c << 8)
+#define VI6_IP_VERSION_MODEL_VSPD_GEN4 (0x1c << 8)
/* RZ/G2L SoCs have no version register, So use 0x80 as the model version */
#define VI6_IP_VERSION_MODEL_VSPD_RZG2L (0x80 << 8)
@@ -782,6 +804,7 @@
#define VI6_IP_VERSION_SOC_M3N (0x04 << 0)
#define VI6_IP_VERSION_SOC_E3 (0x04 << 0)
#define VI6_IP_VERSION_SOC_V3U (0x05 << 0)
+#define VI6_IP_VERSION_SOC_V4H (0x06 << 0)
/* RZ/G2L SoCs have no version register, So use 0x80 for SoC Identification */
#define VI6_IP_VERSION_SOC_RZG2L (0x80 << 0)
@@ -845,6 +868,7 @@
#define VI6_FMT_XBXGXR_262626 0x21
#define VI6_FMT_ABGR_8888 0x22
#define VI6_FMT_XXRGB_88565 0x23
+#define VI6_FMT_RGB10_RGB10A2_A2RGB10 0x30
#define VI6_FMT_Y_UV_444 0x40
#define VI6_FMT_Y_UV_422 0x41
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_rpf.c b/drivers/media/platform/renesas/vsp1/vsp1_rpf.c
index 75083cb234fe..3b17f5fa4067 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_rpf.c
@@ -109,6 +109,58 @@ static void rpf_configure_stream(struct vsp1_entity *entity,
vsp1_rpf_write(rpf, dlb, VI6_RPF_INFMT, infmt);
vsp1_rpf_write(rpf, dlb, VI6_RPF_DSWAP, fmtinfo->swap);
+ if (entity->vsp1->info->gen == 4) {
+ u32 ext_infmt0;
+ u32 ext_infmt1;
+ u32 ext_infmt2;
+
+ switch (fmtinfo->fourcc) {
+ case V4L2_PIX_FMT_RGBX1010102:
+ ext_infmt0 = VI6_RPF_EXT_INFMT0_BYPP_M1_RGB10;
+ ext_infmt1 = VI6_RPF_EXT_INFMT1_PACK_CPOS(0, 10, 20, 0);
+ ext_infmt2 = VI6_RPF_EXT_INFMT2_PACK_CLEN(10, 10, 10, 0);
+ break;
+
+ case V4L2_PIX_FMT_RGBA1010102:
+ ext_infmt0 = VI6_RPF_EXT_INFMT0_BYPP_M1_RGB10;
+ ext_infmt1 = VI6_RPF_EXT_INFMT1_PACK_CPOS(0, 10, 20, 30);
+ ext_infmt2 = VI6_RPF_EXT_INFMT2_PACK_CLEN(10, 10, 10, 2);
+ break;
+
+ case V4L2_PIX_FMT_ARGB2101010:
+ ext_infmt0 = VI6_RPF_EXT_INFMT0_BYPP_M1_RGB10;
+ ext_infmt1 = VI6_RPF_EXT_INFMT1_PACK_CPOS(2, 12, 22, 0);
+ ext_infmt2 = VI6_RPF_EXT_INFMT2_PACK_CLEN(10, 10, 10, 2);
+ break;
+
+ case V4L2_PIX_FMT_Y210:
+ ext_infmt0 = VI6_RPF_EXT_INFMT0_F2B |
+ VI6_RPF_EXT_INFMT0_IPBD_Y_10 |
+ VI6_RPF_EXT_INFMT0_IPBD_C_10;
+ ext_infmt1 = 0x0;
+ ext_infmt2 = 0x0;
+ break;
+
+ case V4L2_PIX_FMT_Y212:
+ ext_infmt0 = VI6_RPF_EXT_INFMT0_F2B |
+ VI6_RPF_EXT_INFMT0_IPBD_Y_12 |
+ VI6_RPF_EXT_INFMT0_IPBD_C_12;
+ ext_infmt1 = 0x0;
+ ext_infmt2 = 0x0;
+ break;
+
+ default:
+ ext_infmt0 = 0;
+ ext_infmt1 = 0;
+ ext_infmt2 = 0;
+ break;
+ }
+
+ vsp1_rpf_write(rpf, dlb, VI6_RPF_EXT_INFMT0, ext_infmt0);
+ vsp1_rpf_write(rpf, dlb, VI6_RPF_EXT_INFMT1, ext_infmt1);
+ vsp1_rpf_write(rpf, dlb, VI6_RPF_EXT_INFMT2, ext_infmt2);
+ }
+
/* Output location. */
if (pipe->brx) {
const struct v4l2_rect *compose;
@@ -133,18 +185,18 @@ static void rpf_configure_stream(struct vsp1_entity *entity,
* a fixed alpha value set through the V4L2_CID_ALPHA_COMPONENT control
* otherwise.
*
- * The Gen3 RPF has extended alpha capability and can both multiply the
+ * The Gen3+ RPF has extended alpha capability and can both multiply the
* alpha channel by a fixed global alpha value, and multiply the pixel
* components to convert the input to premultiplied alpha.
*
* As alpha premultiplication is available in the BRx for both Gen2 and
- * Gen3 we handle it there and use the Gen3 alpha multiplier for global
+ * Gen3+ we handle it there and use the Gen3 alpha multiplier for global
* alpha multiplication only. This however prevents conversion to
* premultiplied alpha if no BRx is present in the pipeline. If that use
* case turns out to be useful we will revisit the implementation (for
* Gen3 only).
*
- * We enable alpha multiplication on Gen3 using the fixed alpha value
+ * We enable alpha multiplication on Gen3+ using the fixed alpha value
* set through the V4L2_CID_ALPHA_COMPONENT control when the input
* contains an alpha channel. On Gen2 the global alpha is ignored in
* that case.
@@ -155,7 +207,7 @@ static void rpf_configure_stream(struct vsp1_entity *entity,
(fmtinfo->alpha ? VI6_RPF_ALPH_SEL_ASEL_PACKED
: VI6_RPF_ALPH_SEL_ASEL_FIXED));
- if (entity->vsp1->info->gen == 3) {
+ if (entity->vsp1->info->gen >= 3) {
u32 mult;
if (fmtinfo->alpha) {
@@ -301,10 +353,10 @@ static void rpf_configure_partition(struct vsp1_entity *entity,
}
/*
- * On Gen3 hardware the SPUVS bit has no effect on 3-planar
+ * On Gen3+ hardware the SPUVS bit has no effect on 3-planar
* formats. Swap the U and V planes manually in that case.
*/
- if (vsp1->info->gen == 3 && format->num_planes == 3 &&
+ if (vsp1->info->gen >= 3 && format->num_planes == 3 &&
fmtinfo->swap_uv)
swap(mem.addr[1], mem.addr[2]);
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_video.c b/drivers/media/platform/renesas/vsp1/vsp1_video.c
index 9d24647c8f32..544012fd1fe9 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_video.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_video.c
@@ -267,10 +267,10 @@ static int vsp1_video_pipeline_setup_partitions(struct vsp1_pipeline *pipe)
div_size = format->width;
/*
- * Only Gen3 hardware requires image partitioning, Gen2 will operate
+ * Only Gen3+ hardware requires image partitioning, Gen2 will operate
* with a single partition that covers the whole output.
*/
- if (vsp1->info->gen == 3) {
+ if (vsp1->info->gen >= 3) {
list_for_each_entry(entity, &pipe->entities, list_pipe) {
unsigned int entity_max;
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_wpf.c b/drivers/media/platform/renesas/vsp1/vsp1_wpf.c
index 94e91d7bb56c..d0074ca00920 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_wpf.c
@@ -512,10 +512,10 @@ static void wpf_configure_partition(struct vsp1_entity *entity,
}
/*
- * On Gen3 hardware the SPUVS bit has no effect on 3-planar
+ * On Gen3+ hardware the SPUVS bit has no effect on 3-planar
* formats. Swap the U and V planes manually in that case.
*/
- if (vsp1->info->gen == 3 && format->num_planes == 3 &&
+ if (vsp1->info->gen >= 3 && format->num_planes == 3 &&
fmtinfo->swap_uv)
swap(mem.addr[1], mem.addr[2]);
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c
index d4540684ea9a..d1d1fdce03e3 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c
@@ -1131,10 +1131,12 @@ static void rkisp1_try_fmt(const struct rkisp1_capture *cap,
const struct rkisp1_capture_config *config = cap->config;
const struct rkisp1_capture_fmt_cfg *fmt;
const struct v4l2_format_info *info;
- const unsigned int max_widths[] = { RKISP1_RSZ_MP_SRC_MAX_WIDTH,
- RKISP1_RSZ_SP_SRC_MAX_WIDTH };
- const unsigned int max_heights[] = { RKISP1_RSZ_MP_SRC_MAX_HEIGHT,
- RKISP1_RSZ_SP_SRC_MAX_HEIGHT};
+ static const unsigned int max_widths[] = {
+ RKISP1_RSZ_MP_SRC_MAX_WIDTH, RKISP1_RSZ_SP_SRC_MAX_WIDTH
+ };
+ static const unsigned int max_heights[] = {
+ RKISP1_RSZ_MP_SRC_MAX_HEIGHT, RKISP1_RSZ_SP_SRC_MAX_HEIGHT
+ };
fmt = rkisp1_find_fmt_cfg(cap, pixm->pixelformat);
if (!fmt) {
@@ -1336,8 +1338,9 @@ void rkisp1_capture_devs_unregister(struct rkisp1_device *rkisp1)
static int rkisp1_register_capture(struct rkisp1_capture *cap)
{
- const char * const dev_names[] = {RKISP1_MP_DEV_NAME,
- RKISP1_SP_DEV_NAME};
+ static const char * const dev_names[] = {
+ RKISP1_MP_DEV_NAME, RKISP1_SP_DEV_NAME
+ };
struct v4l2_device *v4l2_dev = &cap->rkisp1->v4l2_dev;
struct video_device *vdev = &cap->vnode.vdev;
struct rkisp1_vdev_node *node;
diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-is.h b/drivers/media/platform/samsung/exynos4-is/fimc-is.h
index 06586e455b1d..c126b779aafc 100644
--- a/drivers/media/platform/samsung/exynos4-is/fimc-is.h
+++ b/drivers/media/platform/samsung/exynos4-is/fimc-is.h
@@ -14,7 +14,6 @@
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/kernel.h>
-#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/sizes.h>
#include <linux/spinlock.h>
@@ -231,7 +230,6 @@ struct chain_config {
/**
* struct fimc_is - fimc-is data structure
* @pdev: pointer to FIMC-IS platform device
- * @pctrl: pointer to pinctrl structure for this device
* @v4l2_dev: pointer to the top level v4l2_device
* @fw: data structure describing the FIMC-IS firmware binary
* @memory: memory region assigned for the FIMC-IS (firmware)
@@ -262,7 +260,6 @@ struct chain_config {
*/
struct fimc_is {
struct platform_device *pdev;
- struct pinctrl *pctrl;
struct v4l2_device *v4l2_dev;
struct fimc_is_firmware fw;
diff --git a/drivers/media/platform/samsung/exynos4-is/media-dev.h b/drivers/media/platform/samsung/exynos4-is/media-dev.h
index 62ad5d7e035a..079105d88bab 100644
--- a/drivers/media/platform/samsung/exynos4-is/media-dev.h
+++ b/drivers/media/platform/samsung/exynos4-is/media-dev.h
@@ -11,7 +11,6 @@
#include <linux/platform_device.h>
#include <linux/mutex.h>
#include <linux/of.h>
-#include <linux/pinctrl/consumer.h>
#include <media/media-device.h>
#include <media/media-entity.h>
#include <media/v4l2-device.h>
diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c
index f3e4cdac1ef3..9d2cce124a34 100644
--- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c
+++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c
@@ -1021,8 +1021,8 @@ static __poll_t s5p_mfc_poll(struct file *file,
* means either in driver already or waiting for driver to claim it
* and start processing.
*/
- if ((!src_q->streaming || list_empty(&src_q->queued_list))
- && (!dst_q->streaming || list_empty(&dst_q->queued_list))) {
+ if ((!vb2_is_streaming(src_q) || list_empty(&src_q->queued_list)) &&
+ (!vb2_is_streaming(dst_q) || list_empty(&dst_q->queued_list))) {
rc = EPOLLERR;
goto end;
}
diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c
index 18e6c65f4737..86c5235a0c7a 100644
--- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c
+++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c
@@ -264,6 +264,7 @@ static int sun4i_csi_remove(struct platform_device *pdev)
{
struct sun4i_csi *csi = platform_get_drvdata(pdev);
+ pm_runtime_disable(&pdev->dev);
v4l2_async_nf_unregister(&csi->notifier);
v4l2_async_nf_cleanup(&csi->notifier);
vb2_video_unregister_device(&csi->vdev);
diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c
index a3e826a755fc..95b5633b7914 100644
--- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c
+++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c
@@ -245,7 +245,7 @@ static int sun4i_csi_start_streaming(struct vb2_queue *vq, unsigned int count)
* We need a scratch buffer in case where we'll not have any
* more buffer queued so that we don't error out. One of those
* cases is when you end up at the last frame to capture, you
- * don't havea any buffer queued any more, and yet it doesn't
+ * don't have any buffer queued any more, and yet it doesn't
* really matter since you'll never reach the next buffer.
*
* Since we support the multi-planar API, we need to have a
@@ -311,7 +311,7 @@ static int sun4i_csi_start_streaming(struct vb2_queue *vq, unsigned int count)
writel(CSI_BUF_CTRL_DBE, csi->regs + CSI_BUF_CTRL_REG);
/* Clear the pending interrupts */
- writel(CSI_INT_FRM_DONE, csi->regs + 0x34);
+ writel(CSI_INT_FRM_DONE, csi->regs + CSI_INT_STA_REG);
/* Enable frame done interrupt */
writel(CSI_INT_FRM_DONE, csi->regs + CSI_INT_EN_REG);
diff --git a/drivers/media/platform/ti/cal/cal.c b/drivers/media/platform/ti/cal/cal.c
index 56b61c0583cf..1236215ec70e 100644
--- a/drivers/media/platform/ti/cal/cal.c
+++ b/drivers/media/platform/ti/cal/cal.c
@@ -1050,8 +1050,10 @@ static struct cal_ctx *cal_ctx_create(struct cal_dev *cal, int inst)
ctx->cport = inst;
ret = cal_ctx_v4l2_init(ctx);
- if (ret)
+ if (ret) {
+ kfree(ctx);
return NULL;
+ }
return ctx;
}
diff --git a/drivers/media/platform/ti/davinci/vpif.c b/drivers/media/platform/ti/davinci/vpif.c
index da27da4c165a..832489822706 100644
--- a/drivers/media/platform/ti/davinci/vpif.c
+++ b/drivers/media/platform/ti/davinci/vpif.c
@@ -480,7 +480,7 @@ static int vpif_probe(struct platform_device *pdev)
ret = irq;
goto err_put_rpm;
}
- res_irq = (struct resource)DEFINE_RES_IRQ_NAMED(irq, of_node_full_name(pdev->dev.of_node));
+ res_irq = DEFINE_RES_IRQ_NAMED(irq, of_node_full_name(pdev->dev.of_node));
res_irq.flags |= irq_get_trigger_type(irq);
pdev_capture = kzalloc(sizeof(*pdev_capture), GFP_KERNEL);
diff --git a/drivers/media/platform/ti/omap3isp/isp.c b/drivers/media/platform/ti/omap3isp/isp.c
index 1d40bb59ff81..e7327e38482d 100644
--- a/drivers/media/platform/ti/omap3isp/isp.c
+++ b/drivers/media/platform/ti/omap3isp/isp.c
@@ -2307,7 +2307,16 @@ static int isp_probe(struct platform_device *pdev)
/* Regulators */
isp->isp_csiphy1.vdd = devm_regulator_get(&pdev->dev, "vdd-csiphy1");
+ if (IS_ERR(isp->isp_csiphy1.vdd)) {
+ ret = PTR_ERR(isp->isp_csiphy1.vdd);
+ goto error;
+ }
+
isp->isp_csiphy2.vdd = devm_regulator_get(&pdev->dev, "vdd-csiphy2");
+ if (IS_ERR(isp->isp_csiphy2.vdd)) {
+ ret = PTR_ERR(isp->isp_csiphy2.vdd);
+ goto error;
+ }
/* Clocks
*
diff --git a/drivers/media/platform/ti/omap3isp/ispvideo.c b/drivers/media/platform/ti/omap3isp/ispvideo.c
index 3e5348c63773..ddc7d08d4f96 100644
--- a/drivers/media/platform/ti/omap3isp/ispvideo.c
+++ b/drivers/media/platform/ti/omap3isp/ispvideo.c
@@ -221,22 +221,16 @@ isp_video_remote_subdev(struct isp_video *video, u32 *pad)
static int isp_video_get_graph_data(struct isp_video *video,
struct isp_pipeline *pipe)
{
- struct media_graph graph;
- struct media_entity *entity = &video->video.entity;
- struct media_device *mdev = entity->graph_obj.mdev;
+ struct media_pipeline_entity_iter iter;
+ struct media_entity *entity;
struct isp_video *far_end = NULL;
int ret;
- mutex_lock(&mdev->graph_mutex);
- ret = media_graph_walk_init(&graph, mdev);
- if (ret) {
- mutex_unlock(&mdev->graph_mutex);
+ ret = media_pipeline_entity_iter_init(&pipe->pipe, &iter);
+ if (ret)
return ret;
- }
- media_graph_walk_start(&graph, entity);
-
- while ((entity = media_graph_walk_next(&graph))) {
+ media_pipeline_for_each_entity(&pipe->pipe, &iter, entity) {
struct isp_video *__video;
media_entity_enum_set(&pipe->ent_enum, entity);
@@ -255,9 +249,7 @@ static int isp_video_get_graph_data(struct isp_video *video,
far_end = __video;
}
- mutex_unlock(&mdev->graph_mutex);
-
- media_graph_walk_cleanup(&graph);
+ media_pipeline_entity_iter_cleanup(&iter);
if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
pipe->input = far_end;
diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c
index 8cb4a68c9119..b0aeedae7b65 100644
--- a/drivers/media/platform/verisilicon/hantro_drv.c
+++ b/drivers/media/platform/verisilicon/hantro_drv.c
@@ -1050,8 +1050,6 @@ static int hantro_probe(struct platform_device *pdev)
vpu->mdev.dev = vpu->dev;
strscpy(vpu->mdev.model, DRIVER_NAME, sizeof(vpu->mdev.model));
- strscpy(vpu->mdev.bus_info, "platform: " DRIVER_NAME,
- sizeof(vpu->mdev.bus_info));
media_device_init(&vpu->mdev);
vpu->mdev.ops = &hantro_m2m_media_ops;
vpu->v4l2_dev.mdev = &vpu->mdev;
diff --git a/drivers/media/platform/verisilicon/hantro_v4l2.c b/drivers/media/platform/verisilicon/hantro_v4l2.c
index 2c7a805289e7..c0d427956210 100644
--- a/drivers/media/platform/verisilicon/hantro_v4l2.c
+++ b/drivers/media/platform/verisilicon/hantro_v4l2.c
@@ -142,8 +142,6 @@ static int vidioc_querycap(struct file *file, void *priv,
strscpy(cap->driver, vpu->dev->driver->name, sizeof(cap->driver));
strscpy(cap->card, vdev->name, sizeof(cap->card));
- snprintf(cap->bus_info, sizeof(cap->bus_info), "platform: %s",
- vpu->dev->driver->name);
return 0;
}
@@ -161,8 +159,11 @@ static int vidioc_enum_framesizes(struct file *file, void *priv,
}
/* For non-coded formats check if postprocessing scaling is possible */
- if (fmt->codec_mode == HANTRO_MODE_NONE && hantro_needs_postproc(ctx, fmt)) {
- return hanto_postproc_enum_framesizes(ctx, fsize);
+ if (fmt->codec_mode == HANTRO_MODE_NONE) {
+ if (hantro_needs_postproc(ctx, fmt))
+ return hanto_postproc_enum_framesizes(ctx, fsize);
+ else
+ return -ENOTTY;
} else if (fsize->index != 0) {
vpu_debug(0, "invalid frame size index (expected 0, got %d)\n",
fsize->index);
diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c
index 0a7fd8642a65..fee02c8c85fd 100644
--- a/drivers/media/platform/xilinx/xilinx-dma.c
+++ b/drivers/media/platform/xilinx/xilinx-dma.c
@@ -173,31 +173,19 @@ done:
static int xvip_pipeline_validate(struct xvip_pipeline *pipe,
struct xvip_dma *start)
{
- struct media_graph graph;
- struct media_entity *entity = &start->video.entity;
- struct media_device *mdev = entity->graph_obj.mdev;
+ struct media_pipeline_pad_iter iter;
unsigned int num_inputs = 0;
unsigned int num_outputs = 0;
- int ret;
-
- mutex_lock(&mdev->graph_mutex);
-
- /* Walk the graph to locate the video nodes. */
- ret = media_graph_walk_init(&graph, mdev);
- if (ret) {
- mutex_unlock(&mdev->graph_mutex);
- return ret;
- }
-
- media_graph_walk_start(&graph, entity);
+ struct media_pad *pad;
- while ((entity = media_graph_walk_next(&graph))) {
+ /* Locate the video nodes in the pipeline. */
+ media_pipeline_for_each_pad(&pipe->pipe, &iter, pad) {
struct xvip_dma *dma;
- if (entity->function != MEDIA_ENT_F_IO_V4L)
+ if (pad->entity->function != MEDIA_ENT_F_IO_V4L)
continue;
- dma = to_xvip_dma(media_entity_to_video_device(entity));
+ dma = to_xvip_dma(media_entity_to_video_device(pad->entity));
if (dma->pad.flags & MEDIA_PAD_FL_SINK) {
pipe->output = dma;
@@ -207,10 +195,6 @@ static int xvip_pipeline_validate(struct xvip_pipeline *pipe,
}
}
- mutex_unlock(&mdev->graph_mutex);
-
- media_graph_walk_cleanup(&graph);
-
/* We need exactly one output and zero or one input. */
if (num_outputs != 1 || num_inputs > 1)
return -EPIPE;
diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c
index 8a316de70e6c..cbd49dff6d74 100644
--- a/drivers/media/radio/wl128x/fmdrv_common.c
+++ b/drivers/media/radio/wl128x/fmdrv_common.c
@@ -1442,7 +1442,7 @@ static long fm_st_receive(void *arg, struct sk_buff *skb)
{
struct fmdev *fmdev;
- fmdev = (struct fmdev *)arg;
+ fmdev = arg;
if (skb == NULL) {
fmerr("Invalid SKB received from ST\n");
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index f560fc38895f..ac4172feb6f9 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -314,7 +314,7 @@ config IR_PWM_TX
tristate "PWM IR transmitter"
depends on LIRC
depends on PWM
- depends on OF || COMPILE_TEST
+ depends on OF
help
Say Y if you want to use a PWM based IR transmitter. This is
more power efficient than the bit banging gpio driver.
@@ -361,7 +361,7 @@ config IR_SERIAL_TRANSMITTER
config IR_SPI
tristate "SPI connected IR LED"
depends on SPI && LIRC
- depends on OF || COMPILE_TEST
+ depends on OF
help
Say Y if you want to use an IR LED connected through SPI bus.
diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c
index e09270916fbc..11ee21a7db8f 100644
--- a/drivers/media/rc/ene_ir.c
+++ b/drivers/media/rc/ene_ir.c
@@ -1106,6 +1106,8 @@ static void ene_remove(struct pnp_dev *pnp_dev)
struct ene_device *dev = pnp_get_drvdata(pnp_dev);
unsigned long flags;
+ rc_unregister_device(dev->rdev);
+ del_timer_sync(&dev->tx_sim_timer);
spin_lock_irqsave(&dev->hw_lock, flags);
ene_rx_disable(dev);
ene_rx_restore_hw_buffer(dev);
@@ -1113,7 +1115,6 @@ static void ene_remove(struct pnp_dev *pnp_dev)
free_irq(dev->irq, dev);
release_region(dev->hw_io, ENE_IO_SIZE);
- rc_unregister_device(dev->rdev);
kfree(dev);
}
diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c
index 8f1fff7af6c9..8dbe780dae4e 100644
--- a/drivers/media/rc/gpio-ir-recv.c
+++ b/drivers/media/rc/gpio-ir-recv.c
@@ -126,6 +126,23 @@ static int gpio_ir_recv_probe(struct platform_device *pdev)
"gpio-ir-recv-irq", gpio_dev);
}
+static int gpio_ir_recv_remove(struct platform_device *pdev)
+{
+ struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);
+ struct device *pmdev = gpio_dev->pmdev;
+
+ if (pmdev) {
+ pm_runtime_get_sync(pmdev);
+ cpu_latency_qos_remove_request(&gpio_dev->qos);
+
+ pm_runtime_disable(pmdev);
+ pm_runtime_put_noidle(pmdev);
+ pm_runtime_set_suspended(pmdev);
+ }
+
+ return 0;
+}
+
#ifdef CONFIG_PM
static int gpio_ir_recv_suspend(struct device *dev)
{
@@ -185,6 +202,7 @@ MODULE_DEVICE_TABLE(of, gpio_ir_recv_of_match);
static struct platform_driver gpio_ir_recv_driver = {
.probe = gpio_ir_recv_probe,
+ .remove = gpio_ir_recv_remove,
.driver = {
.name = KBUILD_MODNAME,
.of_match_table = of_match_ptr(gpio_ir_recv_of_match),
diff --git a/drivers/media/rc/ir-rx51.c b/drivers/media/rc/ir-rx51.c
index 85080c3d2053..adbbe639a261 100644
--- a/drivers/media/rc/ir-rx51.c
+++ b/drivers/media/rc/ir-rx51.c
@@ -261,11 +261,6 @@ static int ir_rx51_probe(struct platform_device *dev)
return devm_rc_register_device(&dev->dev, ir_rx51.rcdev);
}
-static int ir_rx51_remove(struct platform_device *dev)
-{
- return 0;
-}
-
static const struct of_device_id ir_rx51_match[] = {
{
.compatible = "nokia,n900-ir",
@@ -276,7 +271,6 @@ MODULE_DEVICE_TABLE(of, ir_rx51_match);
static struct platform_driver ir_rx51_platform_driver = {
.probe = ir_rx51_probe,
- .remove = ir_rx51_remove,
.suspend = ir_rx51_suspend,
.resume = ir_rx51_resume,
.driver = {
diff --git a/drivers/media/rc/pwm-ir-tx.c b/drivers/media/rc/pwm-ir-tx.c
index 105a9c24f1e3..7732054c4621 100644
--- a/drivers/media/rc/pwm-ir-tx.c
+++ b/drivers/media/rc/pwm-ir-tx.c
@@ -120,7 +120,7 @@ static struct platform_driver pwm_ir_driver = {
.probe = pwm_ir_probe,
.driver = {
.name = DRIVER_NAME,
- .of_match_table = of_match_ptr(pwm_ir_of_match),
+ .of_match_table = pwm_ir_of_match,
},
};
module_platform_driver(pwm_ir_driver);
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 527d9324742b..6bdad6341844 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -1614,7 +1614,7 @@ static void rc_dev_release(struct device *device)
kfree(dev);
}
-static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env)
+static int rc_dev_uevent(const struct device *device, struct kobj_uevent_env *env)
{
struct rc_dev *dev = to_rc_dev(device);
int ret = 0;
diff --git a/drivers/media/test-drivers/vidtv/vidtv_psi.c b/drivers/media/test-drivers/vidtv/vidtv_psi.c
index a5875380ef40..ce0b7a6e92dc 100644
--- a/drivers/media/test-drivers/vidtv/vidtv_psi.c
+++ b/drivers/media/test-drivers/vidtv/vidtv_psi.c
@@ -1940,7 +1940,7 @@ u32 vidtv_psi_eit_write_into(struct vidtv_psi_eit_write_args *args)
struct vidtv_psi_table_eit_event
*vidtv_psi_eit_event_init(struct vidtv_psi_table_eit_event *head, u16 event_id)
{
- const u8 DURATION[] = {0x23, 0x59, 0x59}; /* BCD encoded */
+ static const u8 DURATION[] = {0x23, 0x59, 0x59}; /* BCD encoded */
struct vidtv_psi_table_eit_event *e;
struct timespec64 ts;
struct tm time;
diff --git a/drivers/media/test-drivers/visl/visl-video.c b/drivers/media/test-drivers/visl/visl-video.c
index b08664dfbe5f..7cac6a6456eb 100644
--- a/drivers/media/test-drivers/visl/visl-video.c
+++ b/drivers/media/test-drivers/visl/visl-video.c
@@ -687,7 +687,7 @@ static void visl_buf_request_complete(struct vb2_buffer *vb)
v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl);
}
-const struct vb2_ops visl_qops = {
+static const struct vb2_ops visl_qops = {
.queue_setup = visl_queue_setup,
.buf_out_validate = visl_buf_out_validate,
.buf_prepare = visl_buf_prepare,
diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c
index 476b32c04c20..3fa3dcda917a 100644
--- a/drivers/media/tuners/si2157.c
+++ b/drivers/media/tuners/si2157.c
@@ -875,9 +875,9 @@ err:
dev_dbg(&client->dev, "failed=%d\n", ret);
}
-static int si2157_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int si2157_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct si2157_config *cfg = client->dev.platform_data;
struct dvb_frontend *fe = cfg->fe;
struct si2157_dev *dev;
@@ -990,7 +990,7 @@ static struct i2c_driver si2157_driver = {
.name = "si2157",
.suppress_bind_attrs = true,
},
- .probe = si2157_probe,
+ .probe_new = si2157_probe,
.remove = si2157_remove,
.id_table = si2157_id_table,
};
diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c
index d33514acc2b5..4014f7d07330 100644
--- a/drivers/media/usb/dvb-usb-v2/af9015.c
+++ b/drivers/media/usb/dvb-usb-v2/af9015.c
@@ -1165,7 +1165,7 @@ static int af9015_rc_query(struct dvb_usb_device *d)
/* If any of these are non-zero, assume invalid data */
if (buf[1] || buf[2] || buf[3]) {
dev_dbg(&intf->dev, "invalid data\n");
- return ret;
+ return 0;
}
/* Check for repeat of previous code */
@@ -1174,7 +1174,7 @@ static int af9015_rc_query(struct dvb_usb_device *d)
dev_dbg(&intf->dev, "key repeated\n");
rc_repeat(d->rc_dev);
state->rc_repeat = buf[6];
- return ret;
+ return 0;
}
/* Only process key if canary killed */
diff --git a/drivers/media/usb/go7007/go7007-v4l2.c b/drivers/media/usb/go7007/go7007-v4l2.c
index b2edc4deaca3..13256565b034 100644
--- a/drivers/media/usb/go7007/go7007-v4l2.c
+++ b/drivers/media/usb/go7007/go7007-v4l2.c
@@ -404,16 +404,13 @@ static int go7007_start_streaming(struct vb2_queue *q, unsigned int count)
go->next_seq = 0;
go->active_buf = NULL;
go->modet_event_status = 0;
- q->streaming = 1;
if (go7007_start_encoder(go) < 0)
ret = -EIO;
else
ret = 0;
mutex_unlock(&go->hw_lock);
- if (ret) {
- q->streaming = 0;
+ if (ret)
return ret;
- }
call_all(&go->v4l2_dev, video, s_stream, 1);
v4l2_ctrl_grab(go->mpeg_video_gop_size, true);
v4l2_ctrl_grab(go->mpeg_video_gop_closure, true);
@@ -430,7 +427,6 @@ static void go7007_stop_streaming(struct vb2_queue *q)
struct go7007 *go = vb2_get_drv_priv(q);
unsigned long flags;
- q->streaming = 0;
go7007_stream_stop(go);
mutex_lock(&go->hw_lock);
go7007_reset_encoder(go);
diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c
index fe9c7b3a950e..6f443c542c6d 100644
--- a/drivers/media/usb/siano/smsusb.c
+++ b/drivers/media/usb/siano/smsusb.c
@@ -179,6 +179,7 @@ static void smsusb_stop_streaming(struct smsusb_device_t *dev)
for (i = 0; i < MAX_URBS; i++) {
usb_kill_urb(&dev->surbs[i].urb);
+ cancel_work_sync(&dev->surbs[i].wq);
if (dev->surbs[i].cb) {
smscore_putbuffer(dev->coredev, dev->surbs[i].cb);
diff --git a/drivers/media/usb/uvc/Kconfig b/drivers/media/usb/uvc/Kconfig
index ca51ee8e45f3..579532272fd6 100644
--- a/drivers/media/usb/uvc/Kconfig
+++ b/drivers/media/usb/uvc/Kconfig
@@ -3,6 +3,7 @@ config USB_VIDEO_CLASS
tristate "USB Video Class (UVC)"
depends on VIDEO_DEV
select VIDEOBUF2_VMALLOC
+ select UVC_COMMON
help
Support for the USB Video Class (UVC). Currently only video
input devices, such as webcams, are supported.
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index c95a2229f4fa..5e9d3da862dd 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -6,19 +6,21 @@
* Laurent Pinchart (laurent.pinchart@ideasonboard.com)
*/
+#include <asm/barrier.h>
+#include <linux/bitops.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/usb.h>
+#include <linux/usb/uvc.h>
#include <linux/videodev2.h>
#include <linux/vmalloc.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
#include <linux/atomic.h>
#include <media/v4l2-ctrls.h>
-#include <media/v4l2-uvc.h>
#include "uvcvideo.h"
@@ -363,19 +365,45 @@ static const u32 uvc_control_classes[] = {
V4L2_CID_USER_CLASS,
};
-static const struct uvc_menu_info power_line_frequency_controls[] = {
- { 0, "Disabled" },
- { 1, "50 Hz" },
- { 2, "60 Hz" },
- { 3, "Auto" },
-};
+static const int exposure_auto_mapping[] = { 2, 1, 4, 8 };
-static const struct uvc_menu_info exposure_auto_controls[] = {
- { 2, "Auto Mode" },
- { 1, "Manual Mode" },
- { 4, "Shutter Priority Mode" },
- { 8, "Aperture Priority Mode" },
-};
+/*
+ * This function translates the V4L2 menu index @idx, as exposed to userspace as
+ * the V4L2 control value, to the corresponding UVC control value used by the
+ * device. The custom menu_mapping in the control @mapping is used when
+ * available, otherwise the function assumes that the V4L2 and UVC values are
+ * identical.
+ *
+ * For controls of type UVC_CTRL_DATA_TYPE_BITMASK, the UVC control value is
+ * expressed as a bitmask and is thus guaranteed to have a single bit set.
+ *
+ * The function returns -EINVAL if the V4L2 menu index @idx isn't valid for the
+ * control, which includes all controls whose type isn't UVC_CTRL_DATA_TYPE_ENUM
+ * or UVC_CTRL_DATA_TYPE_BITMASK.
+ */
+static int uvc_mapping_get_menu_value(const struct uvc_control_mapping *mapping,
+ u32 idx)
+{
+ if (!test_bit(idx, &mapping->menu_mask))
+ return -EINVAL;
+
+ if (mapping->menu_mapping)
+ return mapping->menu_mapping[idx];
+
+ return idx;
+}
+
+static const char *
+uvc_mapping_get_menu_name(const struct uvc_control_mapping *mapping, u32 idx)
+{
+ if (!test_bit(idx, &mapping->menu_mask))
+ return NULL;
+
+ if (mapping->menu_names)
+ return mapping->menu_names[idx];
+
+ return v4l2_ctrl_get_menu(mapping->id)[idx];
+}
static s32 uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping,
u8 query, const u8 *data)
@@ -524,8 +552,9 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_MENU,
.data_type = UVC_CTRL_DATA_TYPE_BITMASK,
- .menu_info = exposure_auto_controls,
- .menu_count = ARRAY_SIZE(exposure_auto_controls),
+ .menu_mapping = exposure_auto_mapping,
+ .menu_mask = GENMASK(V4L2_EXPOSURE_APERTURE_PRIORITY,
+ V4L2_EXPOSURE_AUTO),
.slave_ids = { V4L2_CID_EXPOSURE_ABSOLUTE, },
},
{
@@ -721,32 +750,50 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
},
};
-static const struct uvc_control_mapping uvc_ctrl_mappings_uvc11[] = {
- {
- .id = V4L2_CID_POWER_LINE_FREQUENCY,
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
- .size = 2,
- .offset = 0,
- .v4l2_type = V4L2_CTRL_TYPE_MENU,
- .data_type = UVC_CTRL_DATA_TYPE_ENUM,
- .menu_info = power_line_frequency_controls,
- .menu_count = ARRAY_SIZE(power_line_frequency_controls) - 1,
- },
+const struct uvc_control_mapping uvc_ctrl_power_line_mapping_limited = {
+ .id = V4L2_CID_POWER_LINE_FREQUENCY,
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
+ .size = 2,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_MENU,
+ .data_type = UVC_CTRL_DATA_TYPE_ENUM,
+ .menu_mask = GENMASK(V4L2_CID_POWER_LINE_FREQUENCY_60HZ,
+ V4L2_CID_POWER_LINE_FREQUENCY_50HZ),
};
-static const struct uvc_control_mapping uvc_ctrl_mappings_uvc15[] = {
- {
- .id = V4L2_CID_POWER_LINE_FREQUENCY,
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
- .size = 2,
- .offset = 0,
- .v4l2_type = V4L2_CTRL_TYPE_MENU,
- .data_type = UVC_CTRL_DATA_TYPE_ENUM,
- .menu_info = power_line_frequency_controls,
- .menu_count = ARRAY_SIZE(power_line_frequency_controls),
- },
+const struct uvc_control_mapping uvc_ctrl_power_line_mapping_uvc11 = {
+ .id = V4L2_CID_POWER_LINE_FREQUENCY,
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
+ .size = 2,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_MENU,
+ .data_type = UVC_CTRL_DATA_TYPE_ENUM,
+ .menu_mask = GENMASK(V4L2_CID_POWER_LINE_FREQUENCY_60HZ,
+ V4L2_CID_POWER_LINE_FREQUENCY_DISABLED),
+};
+
+static const struct uvc_control_mapping *uvc_ctrl_mappings_uvc11[] = {
+ &uvc_ctrl_power_line_mapping_uvc11,
+ NULL, /* Sentinel */
+};
+
+static const struct uvc_control_mapping uvc_ctrl_power_line_mapping_uvc15 = {
+ .id = V4L2_CID_POWER_LINE_FREQUENCY,
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
+ .size = 2,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_MENU,
+ .data_type = UVC_CTRL_DATA_TYPE_ENUM,
+ .menu_mask = GENMASK(V4L2_CID_POWER_LINE_FREQUENCY_AUTO,
+ V4L2_CID_POWER_LINE_FREQUENCY_DISABLED),
+};
+
+static const struct uvc_control_mapping *uvc_ctrl_mappings_uvc15[] = {
+ &uvc_ctrl_power_line_mapping_uvc15,
+ NULL, /* Sentinel */
};
/* ------------------------------------------------------------------------
@@ -972,11 +1019,17 @@ static s32 __uvc_ctrl_get_value(struct uvc_control_mapping *mapping,
s32 value = mapping->get(mapping, UVC_GET_CUR, data);
if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) {
- const struct uvc_menu_info *menu = mapping->menu_info;
unsigned int i;
- for (i = 0; i < mapping->menu_count; ++i, ++menu) {
- if (menu->value == value) {
+ for (i = 0; BIT(i) <= mapping->menu_mask; ++i) {
+ u32 menu_value;
+
+ if (!test_bit(i, &mapping->menu_mask))
+ continue;
+
+ menu_value = uvc_mapping_get_menu_value(mapping, i);
+
+ if (menu_value == value) {
value = i;
break;
}
@@ -1085,11 +1138,28 @@ static int uvc_query_v4l2_class(struct uvc_video_chain *chain, u32 req_id,
return 0;
}
+/*
+ * Check if control @v4l2_id can be accessed by the given control @ioctl
+ * (VIDIOC_G_EXT_CTRLS, VIDIOC_TRY_EXT_CTRLS or VIDIOC_S_EXT_CTRLS).
+ *
+ * For set operations on slave controls, check if the master's value is set to
+ * manual, either in the others controls set in the same ioctl call, or from
+ * the master's current value. This catches VIDIOC_S_EXT_CTRLS calls that set
+ * both the master and slave control, such as for instance setting
+ * auto_exposure=1, exposure_time_absolute=251.
+ */
int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id,
- bool read)
+ const struct v4l2_ext_controls *ctrls,
+ unsigned long ioctl)
{
+ struct uvc_control_mapping *master_map = NULL;
+ struct uvc_control *master_ctrl = NULL;
struct uvc_control_mapping *mapping;
struct uvc_control *ctrl;
+ bool read = ioctl == VIDIOC_G_EXT_CTRLS;
+ s32 val;
+ int ret;
+ int i;
if (__uvc_query_v4l2_class(chain, v4l2_id, 0) >= 0)
return -EACCES;
@@ -1104,6 +1174,29 @@ int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id,
if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR) && !read)
return -EACCES;
+ if (ioctl != VIDIOC_S_EXT_CTRLS || !mapping->master_id)
+ return 0;
+
+ /*
+ * Iterate backwards in cases where the master control is accessed
+ * multiple times in the same ioctl. We want the last value.
+ */
+ for (i = ctrls->count - 1; i >= 0; i--) {
+ if (ctrls->controls[i].id == mapping->master_id)
+ return ctrls->controls[i].value ==
+ mapping->master_manual ? 0 : -EACCES;
+ }
+
+ __uvc_find_control(ctrl->entity, mapping->master_id, &master_map,
+ &master_ctrl, 0);
+
+ if (!master_ctrl || !(master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR))
+ return 0;
+
+ ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val);
+ if (ret >= 0 && val != mapping->master_manual)
+ return -EACCES;
+
return 0;
}
@@ -1121,6 +1214,25 @@ static const char *uvc_map_get_name(const struct uvc_control_mapping *map)
return "Unknown Control";
}
+static u32 uvc_get_ctrl_bitmap(struct uvc_control *ctrl,
+ struct uvc_control_mapping *mapping)
+{
+ /*
+ * Some controls, like CT_AE_MODE_CONTROL, use GET_RES to represent
+ * the number of bits supported. Those controls do not list GET_MAX
+ * as supported.
+ */
+ if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES)
+ return mapping->get(mapping, UVC_GET_RES,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
+
+ if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX)
+ return mapping->get(mapping, UVC_GET_MAX,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
+
+ return ~0;
+}
+
static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
struct uvc_control *ctrl,
struct uvc_control_mapping *mapping,
@@ -1128,7 +1240,6 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
{
struct uvc_control_mapping *master_map = NULL;
struct uvc_control *master_ctrl = NULL;
- const struct uvc_menu_info *menu;
unsigned int i;
memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl));
@@ -1169,13 +1280,19 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
switch (mapping->v4l2_type) {
case V4L2_CTRL_TYPE_MENU:
- v4l2_ctrl->minimum = 0;
- v4l2_ctrl->maximum = mapping->menu_count - 1;
+ v4l2_ctrl->minimum = ffs(mapping->menu_mask) - 1;
+ v4l2_ctrl->maximum = fls(mapping->menu_mask) - 1;
v4l2_ctrl->step = 1;
- menu = mapping->menu_info;
- for (i = 0; i < mapping->menu_count; ++i, ++menu) {
- if (menu->value == v4l2_ctrl->default_value) {
+ for (i = 0; BIT(i) <= mapping->menu_mask; ++i) {
+ u32 menu_value;
+
+ if (!test_bit(i, &mapping->menu_mask))
+ continue;
+
+ menu_value = uvc_mapping_get_menu_value(mapping, i);
+
+ if (menu_value == v4l2_ctrl->default_value) {
v4l2_ctrl->default_value = i;
break;
}
@@ -1195,6 +1312,12 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
v4l2_ctrl->step = 0;
return 0;
+ case V4L2_CTRL_TYPE_BITMASK:
+ v4l2_ctrl->minimum = 0;
+ v4l2_ctrl->maximum = uvc_get_ctrl_bitmap(ctrl, mapping);
+ v4l2_ctrl->step = 0;
+ return 0;
+
default:
break;
}
@@ -1268,11 +1391,11 @@ done:
int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
struct v4l2_querymenu *query_menu)
{
- const struct uvc_menu_info *menu_info;
struct uvc_control_mapping *mapping;
struct uvc_control *ctrl;
u32 index = query_menu->index;
u32 id = query_menu->id;
+ const char *name;
int ret;
memset(query_menu, 0, sizeof(*query_menu));
@@ -1289,16 +1412,13 @@ int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
goto done;
}
- if (query_menu->index >= mapping->menu_count) {
+ if (!test_bit(query_menu->index, &mapping->menu_mask)) {
ret = -EINVAL;
goto done;
}
- menu_info = &mapping->menu_info[query_menu->index];
-
- if (mapping->data_type == UVC_CTRL_DATA_TYPE_BITMASK &&
- (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES)) {
- s32 bitmap;
+ if (mapping->data_type == UVC_CTRL_DATA_TYPE_BITMASK) {
+ int mask;
if (!ctrl->cached) {
ret = uvc_ctrl_populate_cache(chain, ctrl);
@@ -1306,15 +1426,25 @@ int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
goto done;
}
- bitmap = mapping->get(mapping, UVC_GET_RES,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
- if (!(bitmap & menu_info->value)) {
+ mask = uvc_mapping_get_menu_value(mapping, query_menu->index);
+ if (mask < 0) {
+ ret = mask;
+ goto done;
+ }
+
+ if (!(uvc_get_ctrl_bitmap(ctrl, mapping) & mask)) {
ret = -EINVAL;
goto done;
}
}
- strscpy(query_menu->name, menu_info->name, sizeof(query_menu->name));
+ name = uvc_mapping_get_menu_name(mapping, query_menu->index);
+ if (!name) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ strscpy(query_menu->name, name, sizeof(query_menu->name));
done:
mutex_unlock(&chain->ctrl_mutex);
@@ -1442,6 +1572,10 @@ static void uvc_ctrl_status_event_work(struct work_struct *work)
uvc_ctrl_status_event(w->chain, w->ctrl, w->data);
+ /* The barrier is needed to synchronize with uvc_status_stop(). */
+ if (smp_load_acquire(&dev->flush_status))
+ return;
+
/* Resubmit the URB. */
w->urb->interval = dev->int_ep->desc.bInterval;
ret = usb_submit_urb(w->urb, GFP_KERNEL);
@@ -1791,31 +1925,44 @@ int uvc_ctrl_set(struct uvc_fh *handle,
value = xctrl->value;
break;
+ case V4L2_CTRL_TYPE_BITMASK:
+ if (!ctrl->cached) {
+ ret = uvc_ctrl_populate_cache(chain, ctrl);
+ if (ret < 0)
+ return ret;
+ }
+
+ xctrl->value &= uvc_get_ctrl_bitmap(ctrl, mapping);
+ value = xctrl->value;
+ break;
+
case V4L2_CTRL_TYPE_BOOLEAN:
xctrl->value = clamp(xctrl->value, 0, 1);
value = xctrl->value;
break;
case V4L2_CTRL_TYPE_MENU:
- if (xctrl->value < 0 || xctrl->value >= mapping->menu_count)
+ if (xctrl->value < (ffs(mapping->menu_mask) - 1) ||
+ xctrl->value > (fls(mapping->menu_mask) - 1))
return -ERANGE;
- value = mapping->menu_info[xctrl->value].value;
+
+ if (!test_bit(xctrl->value, &mapping->menu_mask))
+ return -EINVAL;
+
+ value = uvc_mapping_get_menu_value(mapping, xctrl->value);
/*
* Valid menu indices are reported by the GET_RES request for
* UVC controls that support it.
*/
- if (mapping->data_type == UVC_CTRL_DATA_TYPE_BITMASK &&
- (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES)) {
+ if (mapping->data_type == UVC_CTRL_DATA_TYPE_BITMASK) {
if (!ctrl->cached) {
ret = uvc_ctrl_populate_cache(chain, ctrl);
if (ret < 0)
return ret;
}
- step = mapping->get(mapping, UVC_GET_RES,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
- if (!(step & value))
+ if (!(uvc_get_ctrl_bitmap(ctrl, mapping) & value))
return -EINVAL;
}
@@ -2218,31 +2365,42 @@ static int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
unsigned int i;
/*
- * Most mappings come from static kernel data and need to be duplicated.
+ * Most mappings come from static kernel data, and need to be duplicated.
* Mappings that come from userspace will be unnecessarily duplicated,
* this could be optimized.
*/
map = kmemdup(mapping, sizeof(*mapping), GFP_KERNEL);
- if (map == NULL)
+ if (!map)
return -ENOMEM;
+ map->name = NULL;
+ map->menu_names = NULL;
+ map->menu_mapping = NULL;
+
/* For UVCIOC_CTRL_MAP custom control */
if (mapping->name) {
map->name = kstrdup(mapping->name, GFP_KERNEL);
- if (!map->name) {
- kfree(map);
- return -ENOMEM;
- }
+ if (!map->name)
+ goto err_nomem;
}
INIT_LIST_HEAD(&map->ev_subs);
- size = sizeof(*mapping->menu_info) * mapping->menu_count;
- map->menu_info = kmemdup(mapping->menu_info, size, GFP_KERNEL);
- if (map->menu_info == NULL) {
- kfree(map->name);
- kfree(map);
- return -ENOMEM;
+ if (mapping->menu_mapping && mapping->menu_mask) {
+ size = sizeof(mapping->menu_mapping[0])
+ * fls(mapping->menu_mask);
+ map->menu_mapping = kmemdup(mapping->menu_mapping, size,
+ GFP_KERNEL);
+ if (!map->menu_mapping)
+ goto err_nomem;
+ }
+ if (mapping->menu_names && mapping->menu_mask) {
+ size = sizeof(mapping->menu_names[0])
+ * fls(mapping->menu_mask);
+ map->menu_names = kmemdup(mapping->menu_names, size,
+ GFP_KERNEL);
+ if (!map->menu_names)
+ goto err_nomem;
}
if (map->get == NULL)
@@ -2264,6 +2422,13 @@ static int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
ctrl->info.selector);
return 0;
+
+err_nomem:
+ kfree(map->menu_names);
+ kfree(map->menu_mapping);
+ kfree(map->name);
+ kfree(map);
+ return -ENOMEM;
}
int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
@@ -2421,8 +2586,7 @@ static void uvc_ctrl_prune_entity(struct uvc_device *dev,
static void uvc_ctrl_init_ctrl(struct uvc_video_chain *chain,
struct uvc_control *ctrl)
{
- const struct uvc_control_mapping *mappings;
- unsigned int num_mappings;
+ const struct uvc_control_mapping **mappings;
unsigned int i;
/*
@@ -2489,16 +2653,11 @@ static void uvc_ctrl_init_ctrl(struct uvc_video_chain *chain,
}
/* Finally process version-specific mappings. */
- if (chain->dev->uvc_version < 0x0150) {
- mappings = uvc_ctrl_mappings_uvc11;
- num_mappings = ARRAY_SIZE(uvc_ctrl_mappings_uvc11);
- } else {
- mappings = uvc_ctrl_mappings_uvc15;
- num_mappings = ARRAY_SIZE(uvc_ctrl_mappings_uvc15);
- }
+ mappings = chain->dev->uvc_version < 0x0150
+ ? uvc_ctrl_mappings_uvc11 : uvc_ctrl_mappings_uvc15;
- for (i = 0; i < num_mappings; ++i) {
- const struct uvc_control_mapping *mapping = &mappings[i];
+ for (i = 0; mappings[i]; ++i) {
+ const struct uvc_control_mapping *mapping = mappings[i];
if (uvc_entity_match_guid(ctrl->entity, mapping->entity) &&
ctrl->info.selector == mapping->selector)
@@ -2591,7 +2750,8 @@ static void uvc_ctrl_cleanup_mappings(struct uvc_device *dev,
list_for_each_entry_safe(mapping, nm, &ctrl->info.mappings, list) {
list_del(&mapping->list);
- kfree(mapping->menu_info);
+ kfree(mapping->menu_names);
+ kfree(mapping->menu_mapping);
kfree(mapping->name);
kfree(mapping);
}
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index e4bcb5011360..7aefa76a42b3 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -7,12 +7,14 @@
*/
#include <linux/atomic.h>
+#include <linux/bits.h>
#include <linux/gpio/consumer.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/usb.h>
+#include <linux/usb/uvc.h>
#include <linux/videodev2.h>
#include <linux/vmalloc.h>
#include <linux/wait.h>
@@ -20,7 +22,6 @@
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
-#include <media/v4l2-uvc.h>
#include "uvcvideo.h"
@@ -224,7 +225,7 @@ static int uvc_parse_format(struct uvc_device *dev,
{
struct usb_interface *intf = streaming->intf;
struct usb_host_interface *alts = intf->cur_altsetting;
- struct uvc_format_desc *fmtdesc;
+ const struct uvc_format_desc *fmtdesc;
struct uvc_frame *frame;
const unsigned char *start = buffer;
unsigned int width_multiplier = 1;
@@ -251,14 +252,10 @@ static int uvc_parse_format(struct uvc_device *dev,
fmtdesc = uvc_format_by_guid(&buffer[5]);
if (fmtdesc != NULL) {
- strscpy(format->name, fmtdesc->name,
- sizeof(format->name));
format->fcc = fmtdesc->fcc;
} else {
dev_info(&streaming->intf->dev,
"Unknown video format %pUl\n", &buffer[5]);
- snprintf(format->name, sizeof(format->name), "%pUl\n",
- &buffer[5]);
format->fcc = 0;
}
@@ -270,8 +267,6 @@ static int uvc_parse_format(struct uvc_device *dev,
*/
if (dev->quirks & UVC_QUIRK_FORCE_Y8) {
if (format->fcc == V4L2_PIX_FMT_YUYV) {
- strscpy(format->name, "Greyscale 8-bit (Y8 )",
- sizeof(format->name));
format->fcc = V4L2_PIX_FMT_GREY;
format->bpp = 8;
width_multiplier = 2;
@@ -312,7 +307,6 @@ static int uvc_parse_format(struct uvc_device *dev,
return -EINVAL;
}
- strscpy(format->name, "MJPEG", sizeof(format->name));
format->fcc = V4L2_PIX_FMT_MJPEG;
format->flags = UVC_FMT_FLAG_COMPRESSED;
format->bpp = 0;
@@ -328,17 +322,7 @@ static int uvc_parse_format(struct uvc_device *dev,
return -EINVAL;
}
- switch (buffer[8] & 0x7f) {
- case 0:
- strscpy(format->name, "SD-DV", sizeof(format->name));
- break;
- case 1:
- strscpy(format->name, "SDL-DV", sizeof(format->name));
- break;
- case 2:
- strscpy(format->name, "HD-DV", sizeof(format->name));
- break;
- default:
+ if ((buffer[8] & 0x7f) > 2) {
uvc_dbg(dev, DESCR,
"device %d videostreaming interface %d: unknown DV format %u\n",
dev->udev->devnum,
@@ -346,9 +330,6 @@ static int uvc_parse_format(struct uvc_device *dev,
return -EINVAL;
}
- strlcat(format->name, buffer[8] & (1 << 7) ? " 60Hz" : " 50Hz",
- sizeof(format->name));
-
format->fcc = V4L2_PIX_FMT_DV;
format->flags = UVC_FMT_FLAG_COMPRESSED | UVC_FMT_FLAG_STREAM;
format->bpp = 0;
@@ -375,7 +356,7 @@ static int uvc_parse_format(struct uvc_device *dev,
return -EINVAL;
}
- uvc_dbg(dev, DESCR, "Found format %s\n", format->name);
+ uvc_dbg(dev, DESCR, "Found format %p4cc", &format->fcc);
buflen -= buffer[0];
buffer += buffer[0];
@@ -732,6 +713,7 @@ static int uvc_parse_streaming(struct uvc_device *dev,
/* Parse the alternate settings to find the maximum bandwidth. */
for (i = 0; i < intf->num_altsetting; ++i) {
struct usb_host_endpoint *ep;
+
alts = &intf->altsetting[i];
ep = uvc_find_endpoint(alts,
streaming->header.bEndpointAddress);
@@ -813,6 +795,27 @@ static struct uvc_entity *uvc_alloc_entity(u16 type, u16 id,
return entity;
}
+static void uvc_entity_set_name(struct uvc_device *dev, struct uvc_entity *entity,
+ const char *type_name, u8 string_id)
+{
+ int ret;
+
+ /*
+ * First attempt to read the entity name from the device. If the entity
+ * has no associated string, or if reading the string fails (most
+ * likely due to a buggy firmware), fall back to default names based on
+ * the entity type.
+ */
+ if (string_id) {
+ ret = usb_string(dev->udev, string_id, entity->name,
+ sizeof(entity->name));
+ if (!ret)
+ return;
+ }
+
+ sprintf(entity->name, "%s %u", type_name, entity->id);
+}
+
/* Parse vendor-specific extensions. */
static int uvc_parse_vendor_control(struct uvc_device *dev,
const unsigned char *buffer, int buflen)
@@ -879,11 +882,7 @@ static int uvc_parse_vendor_control(struct uvc_device *dev,
+ n;
memcpy(unit->extension.bmControls, &buffer[23+p], 2*n);
- if (buffer[24+p+2*n] != 0)
- usb_string(udev, buffer[24+p+2*n], unit->name,
- sizeof(unit->name));
- else
- sprintf(unit->name, "Extension %u", buffer[3]);
+ uvc_entity_set_name(dev, unit, "Extension", buffer[24+p+2*n]);
list_add_tail(&unit->list, &dev->entities);
handled = 1;
@@ -901,6 +900,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
struct usb_interface *intf;
struct usb_host_interface *alts = dev->intf->cur_altsetting;
unsigned int i, n, p, len;
+ const char *type_name;
u16 type;
switch (buffer[2]) {
@@ -1006,15 +1006,14 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
memcpy(term->media.bmTransportModes, &buffer[10+n], p);
}
- if (buffer[7] != 0)
- usb_string(udev, buffer[7], term->name,
- sizeof(term->name));
- else if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA)
- sprintf(term->name, "Camera %u", buffer[3]);
+ if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA)
+ type_name = "Camera";
else if (UVC_ENTITY_TYPE(term) == UVC_ITT_MEDIA_TRANSPORT_INPUT)
- sprintf(term->name, "Media %u", buffer[3]);
+ type_name = "Media";
else
- sprintf(term->name, "Input %u", buffer[3]);
+ type_name = "Input";
+
+ uvc_entity_set_name(dev, term, type_name, buffer[7]);
list_add_tail(&term->list, &dev->entities);
break;
@@ -1047,11 +1046,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
memcpy(term->baSourceID, &buffer[7], 1);
- if (buffer[8] != 0)
- usb_string(udev, buffer[8], term->name,
- sizeof(term->name));
- else
- sprintf(term->name, "Output %u", buffer[3]);
+ uvc_entity_set_name(dev, term, "Output", buffer[8]);
list_add_tail(&term->list, &dev->entities);
break;
@@ -1072,11 +1067,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
memcpy(unit->baSourceID, &buffer[5], p);
- if (buffer[5+p] != 0)
- usb_string(udev, buffer[5+p], unit->name,
- sizeof(unit->name));
- else
- sprintf(unit->name, "Selector %u", buffer[3]);
+ uvc_entity_set_name(dev, unit, "Selector", buffer[5+p]);
list_add_tail(&unit->list, &dev->entities);
break;
@@ -1105,11 +1096,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
if (dev->uvc_version >= 0x0110)
unit->processing.bmVideoStandards = buffer[9+n];
- if (buffer[8+n] != 0)
- usb_string(udev, buffer[8+n], unit->name,
- sizeof(unit->name));
- else
- sprintf(unit->name, "Processing %u", buffer[3]);
+ uvc_entity_set_name(dev, unit, "Processing", buffer[8+n]);
list_add_tail(&unit->list, &dev->entities);
break;
@@ -1136,11 +1123,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
unit->extension.bmControls = (u8 *)unit + sizeof(*unit);
memcpy(unit->extension.bmControls, &buffer[23+p], n);
- if (buffer[23+p+n] != 0)
- usb_string(udev, buffer[23+p+n], unit->name,
- sizeof(unit->name));
- else
- sprintf(unit->name, "Extension %u", buffer[3]);
+ uvc_entity_set_name(dev, unit, "Extension", buffer[23+p+n]);
list_add_tail(&unit->list, &dev->entities);
break;
@@ -1173,7 +1156,8 @@ static int uvc_parse_control(struct uvc_device *dev)
buffer[1] != USB_DT_CS_INTERFACE)
goto next_descriptor;
- if ((ret = uvc_parse_standard_control(dev, buffer, buflen)) < 0)
+ ret = uvc_parse_standard_control(dev, buffer, buflen);
+ if (ret < 0)
return ret;
next_descriptor:
@@ -1856,12 +1840,14 @@ static void uvc_delete(struct kref *kref)
list_for_each_safe(p, n, &dev->chains) {
struct uvc_video_chain *chain;
+
chain = list_entry(p, struct uvc_video_chain, list);
kfree(chain);
}
list_for_each_safe(p, n, &dev->entities) {
struct uvc_entity *entity;
+
entity = list_entry(p, struct uvc_entity, list);
#ifdef CONFIG_MEDIA_CONTROLLER
uvc_mc_cleanup_entity(entity);
@@ -1871,6 +1857,7 @@ static void uvc_delete(struct kref *kref)
list_for_each_safe(p, n, &dev->streams) {
struct uvc_streaming *streaming;
+
streaming = list_entry(p, struct uvc_streaming, list);
usb_driver_release_interface(&uvc_driver.driver,
streaming->intf);
@@ -2206,7 +2193,8 @@ static int uvc_probe(struct usb_interface *intf,
usb_set_intfdata(intf, dev);
/* Initialize the interrupt URB. */
- if ((ret = uvc_status_init(dev)) < 0) {
+ ret = uvc_status_init(dev);
+ if (ret < 0) {
dev_info(&dev->udev->dev,
"Unable to initialize the status endpoint (%d), status interrupt will not be supported.\n",
ret);
@@ -2353,40 +2341,23 @@ static int uvc_clock_param_set(const char *val, const struct kernel_param *kp)
}
module_param_call(clock, uvc_clock_param_set, uvc_clock_param_get,
- &uvc_clock_param, S_IRUGO|S_IWUSR);
+ &uvc_clock_param, 0644);
MODULE_PARM_DESC(clock, "Video buffers timestamp clock");
-module_param_named(hwtimestamps, uvc_hw_timestamps_param, uint, S_IRUGO|S_IWUSR);
+module_param_named(hwtimestamps, uvc_hw_timestamps_param, uint, 0644);
MODULE_PARM_DESC(hwtimestamps, "Use hardware timestamps");
-module_param_named(nodrop, uvc_no_drop_param, uint, S_IRUGO|S_IWUSR);
+module_param_named(nodrop, uvc_no_drop_param, uint, 0644);
MODULE_PARM_DESC(nodrop, "Don't drop incomplete frames");
-module_param_named(quirks, uvc_quirks_param, uint, S_IRUGO|S_IWUSR);
+module_param_named(quirks, uvc_quirks_param, uint, 0644);
MODULE_PARM_DESC(quirks, "Forced device quirks");
-module_param_named(trace, uvc_dbg_param, uint, S_IRUGO|S_IWUSR);
+module_param_named(trace, uvc_dbg_param, uint, 0644);
MODULE_PARM_DESC(trace, "Trace level bitmask");
-module_param_named(timeout, uvc_timeout_param, uint, S_IRUGO|S_IWUSR);
+module_param_named(timeout, uvc_timeout_param, uint, 0644);
MODULE_PARM_DESC(timeout, "Streaming control requests timeout");
/* ------------------------------------------------------------------------
* Driver initialization and cleanup
*/
-static const struct uvc_menu_info power_line_frequency_controls_limited[] = {
- { 1, "50 Hz" },
- { 2, "60 Hz" },
-};
-
-static const struct uvc_control_mapping uvc_ctrl_power_line_mapping_limited = {
- .id = V4L2_CID_POWER_LINE_FREQUENCY,
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
- .size = 2,
- .offset = 0,
- .v4l2_type = V4L2_CTRL_TYPE_MENU,
- .data_type = UVC_CTRL_DATA_TYPE_ENUM,
- .menu_info = power_line_frequency_controls_limited,
- .menu_count = ARRAY_SIZE(power_line_frequency_controls_limited),
-};
-
static const struct uvc_device_info uvc_ctrl_power_line_limited = {
.mappings = (const struct uvc_control_mapping *[]) {
&uvc_ctrl_power_line_mapping_limited,
@@ -2394,6 +2365,13 @@ static const struct uvc_device_info uvc_ctrl_power_line_limited = {
},
};
+static const struct uvc_device_info uvc_ctrl_power_line_uvc11 = {
+ .mappings = (const struct uvc_control_mapping *[]) {
+ &uvc_ctrl_power_line_mapping_uvc11,
+ NULL, /* Sentinel */
+ },
+};
+
static const struct uvc_device_info uvc_quirk_probe_minmax = {
.quirks = UVC_QUIRK_PROBE_MINMAX,
};
@@ -2496,6 +2474,24 @@ static const struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = (kernel_ulong_t)&uvc_quirk_probe_minmax },
+ /* Logitech, Webcam C910 */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x046d,
+ .idProduct = 0x0821,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_WAKE_AUTOSUSPEND)},
+ /* Logitech, Webcam B910 */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x046d,
+ .idProduct = 0x0823,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_WAKE_AUTOSUSPEND)},
/* Logitech Quickcam Fusion */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2973,6 +2969,15 @@ static const struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = UVC_INFO_QUIRK(UVC_QUIRK_FORCE_BPP) },
+ /* Lenovo Integrated Camera */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x30c9,
+ .idProduct = 0x0093,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = UVC_PC_PROTOCOL_15,
+ .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_uvc11 },
/* Sonix Technology USB 2.0 Camera */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2991,6 +2996,24 @@ static const struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited },
+ /* Acer EasyCamera */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x5986,
+ .idProduct = 0x1180,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited },
+ /* Acer EasyCamera */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x5986,
+ .idProduct = 0x1180,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited },
/* Intel RealSense D4M */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
diff --git a/drivers/media/usb/uvc/uvc_entity.c b/drivers/media/usb/uvc/uvc_entity.c
index 7c4d2f93d351..cc68dd24eb42 100644
--- a/drivers/media/usb/uvc/uvc_entity.c
+++ b/drivers/media/usb/uvc/uvc_entity.c
@@ -37,7 +37,7 @@ static int uvc_mc_create_links(struct uvc_video_chain *chain,
continue;
remote = uvc_entity_by_id(chain->dev, entity->baSourceID[i]);
- if (remote == NULL)
+ if (remote == NULL || remote->num_pads == 0)
return -EINVAL;
source = (UVC_ENTITY_TYPE(remote) == UVC_TT_STREAMING)
diff --git a/drivers/media/usb/uvc/uvc_status.c b/drivers/media/usb/uvc/uvc_status.c
index 7518ffce22ed..a78a88c710e2 100644
--- a/drivers/media/usb/uvc/uvc_status.c
+++ b/drivers/media/usb/uvc/uvc_status.c
@@ -6,6 +6,7 @@
* Laurent Pinchart (laurent.pinchart@ideasonboard.com)
*/
+#include <asm/barrier.h>
#include <linux/kernel.h>
#include <linux/input.h>
#include <linux/slab.h>
@@ -18,11 +19,34 @@
* Input device
*/
#ifdef CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV
+
+static bool uvc_input_has_button(struct uvc_device *dev)
+{
+ struct uvc_streaming *stream;
+
+ /*
+ * The device has button events if both bTriggerSupport and
+ * bTriggerUsage are one. Otherwise the camera button does not
+ * exist or is handled automatically by the camera without host
+ * driver or client application intervention.
+ */
+ list_for_each_entry(stream, &dev->streams, list) {
+ if (stream->header.bTriggerSupport == 1 &&
+ stream->header.bTriggerUsage == 1)
+ return true;
+ }
+
+ return false;
+}
+
static int uvc_input_init(struct uvc_device *dev)
{
struct input_dev *input;
int ret;
+ if (!uvc_input_has_button(dev))
+ return 0;
+
input = input_allocate_device();
if (input == NULL)
return -ENOMEM;
@@ -73,38 +97,23 @@ static void uvc_input_report_key(struct uvc_device *dev, unsigned int code,
/* --------------------------------------------------------------------------
* Status interrupt endpoint
*/
-struct uvc_streaming_status {
- u8 bStatusType;
- u8 bOriginator;
- u8 bEvent;
- u8 bValue[];
-} __packed;
-
-struct uvc_control_status {
- u8 bStatusType;
- u8 bOriginator;
- u8 bEvent;
- u8 bSelector;
- u8 bAttribute;
- u8 bValue[];
-} __packed;
-
static void uvc_event_streaming(struct uvc_device *dev,
- struct uvc_streaming_status *status, int len)
+ struct uvc_status *status, int len)
{
- if (len < 3) {
+ if (len <= offsetof(struct uvc_status, bEvent)) {
uvc_dbg(dev, STATUS,
"Invalid streaming status event received\n");
return;
}
if (status->bEvent == 0) {
- if (len < 4)
+ if (len <= offsetof(struct uvc_status, streaming))
return;
+
uvc_dbg(dev, STATUS, "Button (intf %u) %s len %d\n",
status->bOriginator,
- status->bValue[0] ? "pressed" : "released", len);
- uvc_input_report_key(dev, KEY_CAMERA, status->bValue[0]);
+ status->streaming.button ? "pressed" : "released", len);
+ uvc_input_report_key(dev, KEY_CAMERA, status->streaming.button);
} else {
uvc_dbg(dev, STATUS, "Stream %u error event %02x len %d\n",
status->bOriginator, status->bEvent, len);
@@ -131,7 +140,7 @@ static struct uvc_control *uvc_event_entity_find_ctrl(struct uvc_entity *entity,
}
static struct uvc_control *uvc_event_find_ctrl(struct uvc_device *dev,
- const struct uvc_control_status *status,
+ const struct uvc_status *status,
struct uvc_video_chain **chain)
{
list_for_each_entry((*chain), &dev->chains, list) {
@@ -143,7 +152,7 @@ static struct uvc_control *uvc_event_find_ctrl(struct uvc_device *dev,
continue;
ctrl = uvc_event_entity_find_ctrl(entity,
- status->bSelector);
+ status->control.bSelector);
if (ctrl)
return ctrl;
}
@@ -153,7 +162,7 @@ static struct uvc_control *uvc_event_find_ctrl(struct uvc_device *dev,
}
static bool uvc_event_control(struct urb *urb,
- const struct uvc_control_status *status, int len)
+ const struct uvc_status *status, int len)
{
static const char *attrs[] = { "value", "info", "failure", "min", "max" };
struct uvc_device *dev = urb->context;
@@ -161,24 +170,24 @@ static bool uvc_event_control(struct urb *urb,
struct uvc_control *ctrl;
if (len < 6 || status->bEvent != 0 ||
- status->bAttribute >= ARRAY_SIZE(attrs)) {
+ status->control.bAttribute >= ARRAY_SIZE(attrs)) {
uvc_dbg(dev, STATUS, "Invalid control status event received\n");
return false;
}
uvc_dbg(dev, STATUS, "Control %u/%u %s change len %d\n",
- status->bOriginator, status->bSelector,
- attrs[status->bAttribute], len);
+ status->bOriginator, status->control.bSelector,
+ attrs[status->control.bAttribute], len);
/* Find the control. */
ctrl = uvc_event_find_ctrl(dev, status, &chain);
if (!ctrl)
return false;
- switch (status->bAttribute) {
+ switch (status->control.bAttribute) {
case UVC_CTRL_VALUE_CHANGE:
return uvc_ctrl_status_event_async(urb, chain, ctrl,
- status->bValue);
+ status->control.bValue);
case UVC_CTRL_INFO_CHANGE:
case UVC_CTRL_FAILURE_CHANGE:
@@ -214,28 +223,22 @@ static void uvc_status_complete(struct urb *urb)
len = urb->actual_length;
if (len > 0) {
- switch (dev->status[0] & 0x0f) {
+ switch (dev->status->bStatusType & 0x0f) {
case UVC_STATUS_TYPE_CONTROL: {
- struct uvc_control_status *status =
- (struct uvc_control_status *)dev->status;
-
- if (uvc_event_control(urb, status, len))
+ if (uvc_event_control(urb, dev->status, len))
/* The URB will be resubmitted in work context. */
return;
break;
}
case UVC_STATUS_TYPE_STREAMING: {
- struct uvc_streaming_status *status =
- (struct uvc_streaming_status *)dev->status;
-
- uvc_event_streaming(dev, status, len);
+ uvc_event_streaming(dev, dev->status, len);
break;
}
default:
uvc_dbg(dev, STATUS, "Unknown status event type %u\n",
- dev->status[0]);
+ dev->status->bStatusType);
break;
}
}
@@ -259,12 +262,12 @@ int uvc_status_init(struct uvc_device *dev)
uvc_input_init(dev);
- dev->status = kzalloc(UVC_MAX_STATUS_SIZE, GFP_KERNEL);
- if (dev->status == NULL)
+ dev->status = kzalloc(sizeof(*dev->status), GFP_KERNEL);
+ if (!dev->status)
return -ENOMEM;
dev->int_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (dev->int_urb == NULL) {
+ if (!dev->int_urb) {
kfree(dev->status);
return -ENOMEM;
}
@@ -281,7 +284,7 @@ int uvc_status_init(struct uvc_device *dev)
interval = fls(interval) - 1;
usb_fill_int_urb(dev->int_urb, dev->udev, pipe,
- dev->status, UVC_MAX_STATUS_SIZE, uvc_status_complete,
+ dev->status, sizeof(*dev->status), uvc_status_complete,
dev, interval);
return 0;
@@ -309,5 +312,41 @@ int uvc_status_start(struct uvc_device *dev, gfp_t flags)
void uvc_status_stop(struct uvc_device *dev)
{
+ struct uvc_ctrl_work *w = &dev->async_ctrl;
+
+ /*
+ * Prevent the asynchronous control handler from requeing the URB. The
+ * barrier is needed so the flush_status change is visible to other
+ * CPUs running the asynchronous handler before usb_kill_urb() is
+ * called below.
+ */
+ smp_store_release(&dev->flush_status, true);
+
+ /*
+ * Cancel any pending asynchronous work. If any status event was queued,
+ * process it synchronously.
+ */
+ if (cancel_work_sync(&w->work))
+ uvc_ctrl_status_event(w->chain, w->ctrl, w->data);
+
+ /* Kill the urb. */
usb_kill_urb(dev->int_urb);
+
+ /*
+ * The URB completion handler may have queued asynchronous work. This
+ * won't resubmit the URB as flush_status is set, but it needs to be
+ * cancelled before returning or it could then race with a future
+ * uvc_status_start() call.
+ */
+ if (cancel_work_sync(&w->work))
+ uvc_ctrl_status_event(w->chain, w->ctrl, w->data);
+
+ /*
+ * From this point, there are no events on the queue and the status URB
+ * is dead. No events will be queued until uvc_status_start() is called.
+ * The barrier is needed to make sure that flush_status is visible to
+ * uvc_ctrl_status_event_work() when uvc_status_start() will be called
+ * again.
+ */
+ smp_store_release(&dev->flush_status, false);
}
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index f4d4c33b6dfb..35453f81c1d9 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -6,6 +6,7 @@
* Laurent Pinchart (laurent.pinchart@ideasonboard.com)
*/
+#include <linux/bits.h>
#include <linux/compat.h>
#include <linux/kernel.h>
#include <linux/list.h>
@@ -25,14 +26,84 @@
#include "uvcvideo.h"
+static int uvc_control_add_xu_mapping(struct uvc_video_chain *chain,
+ struct uvc_control_mapping *map,
+ const struct uvc_xu_control_mapping *xmap)
+{
+ unsigned int i;
+ size_t size;
+ int ret;
+
+ /*
+ * Prevent excessive memory consumption, as well as integer
+ * overflows.
+ */
+ if (xmap->menu_count == 0 ||
+ xmap->menu_count > UVC_MAX_CONTROL_MENU_ENTRIES)
+ return -EINVAL;
+
+ map->menu_names = NULL;
+ map->menu_mapping = NULL;
+
+ map->menu_mask = BIT_MASK(xmap->menu_count);
+
+ size = xmap->menu_count * sizeof(*map->menu_mapping);
+ map->menu_mapping = kzalloc(size, GFP_KERNEL);
+ if (!map->menu_mapping) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ for (i = 0; i < xmap->menu_count ; i++) {
+ if (copy_from_user((u32 *)&map->menu_mapping[i],
+ &xmap->menu_info[i].value,
+ sizeof(map->menu_mapping[i]))) {
+ ret = -EACCES;
+ goto done;
+ }
+ }
+
+ /*
+ * Always use the standard naming if available, otherwise copy the
+ * names supplied by userspace.
+ */
+ if (!v4l2_ctrl_get_menu(map->id)) {
+ size = xmap->menu_count * sizeof(map->menu_names[0]);
+ map->menu_names = kzalloc(size, GFP_KERNEL);
+ if (!map->menu_names) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ for (i = 0; i < xmap->menu_count ; i++) {
+ /* sizeof(names[i]) - 1: to take care of \0 */
+ if (copy_from_user((char *)map->menu_names[i],
+ xmap->menu_info[i].name,
+ sizeof(map->menu_names[i]) - 1)) {
+ ret = -EACCES;
+ goto done;
+ }
+ }
+ }
+
+ ret = uvc_ctrl_add_mapping(chain, map);
+
+done:
+ kfree(map->menu_names);
+ map->menu_names = NULL;
+ kfree(map->menu_mapping);
+ map->menu_mapping = NULL;
+
+ return ret;
+}
+
/* ------------------------------------------------------------------------
* UVC ioctls
*/
-static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain,
- struct uvc_xu_control_mapping *xmap)
+static int uvc_ioctl_xu_ctrl_map(struct uvc_video_chain *chain,
+ struct uvc_xu_control_mapping *xmap)
{
struct uvc_control_mapping *map;
- unsigned int size;
int ret;
map = kzalloc(sizeof(*map), GFP_KERNEL);
@@ -60,39 +131,20 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain,
case V4L2_CTRL_TYPE_INTEGER:
case V4L2_CTRL_TYPE_BOOLEAN:
case V4L2_CTRL_TYPE_BUTTON:
+ ret = uvc_ctrl_add_mapping(chain, map);
break;
case V4L2_CTRL_TYPE_MENU:
- /*
- * Prevent excessive memory consumption, as well as integer
- * overflows.
- */
- if (xmap->menu_count == 0 ||
- xmap->menu_count > UVC_MAX_CONTROL_MENU_ENTRIES) {
- ret = -EINVAL;
- goto free_map;
- }
-
- size = xmap->menu_count * sizeof(*map->menu_info);
- map->menu_info = memdup_user(xmap->menu_info, size);
- if (IS_ERR(map->menu_info)) {
- ret = PTR_ERR(map->menu_info);
- goto free_map;
- }
-
- map->menu_count = xmap->menu_count;
+ ret = uvc_control_add_xu_mapping(chain, map, xmap);
break;
default:
uvc_dbg(chain->dev, CONTROL,
"Unsupported V4L2 control type %u\n", xmap->v4l2_type);
ret = -ENOTTY;
- goto free_map;
+ break;
}
- ret = uvc_ctrl_add_mapping(chain, map);
-
- kfree(map->menu_info);
free_map:
kfree(map);
@@ -660,8 +712,6 @@ static int uvc_ioctl_enum_fmt(struct uvc_streaming *stream,
fmt->flags = 0;
if (format->flags & UVC_FMT_FLAG_COMPRESSED)
fmt->flags |= V4L2_FMT_FLAG_COMPRESSED;
- strscpy(fmt->description, format->name, sizeof(fmt->description));
- fmt->description[sizeof(fmt->description) - 1] = 0;
fmt->pixelformat = format->fcc;
return 0;
}
@@ -1020,8 +1070,7 @@ static int uvc_ctrl_check_access(struct uvc_video_chain *chain,
int ret = 0;
for (i = 0; i < ctrls->count; ++ctrl, ++i) {
- ret = uvc_ctrl_is_accessible(chain, ctrl->id,
- ioctl == VIDIOC_G_EXT_CTRLS);
+ ret = uvc_ctrl_is_accessible(chain, ctrl->id, ctrls, ioctl);
if (ret)
break;
}
@@ -1316,7 +1365,7 @@ static long uvc_ioctl_default(struct file *file, void *fh, bool valid_prio,
switch (cmd) {
/* Dynamic controls. */
case UVCIOC_CTRL_MAP:
- return uvc_ioctl_ctrl_map(chain, arg);
+ return uvc_ioctl_xu_ctrl_map(chain, arg);
case UVCIOC_CTRL_QUERY:
return uvc_xu_ctrl_query(chain, arg);
@@ -1429,7 +1478,7 @@ static long uvc_v4l2_compat_ioctl32(struct file *file,
ret = uvc_v4l2_get_xu_mapping(&karg.xmap, up);
if (ret)
return ret;
- ret = uvc_ioctl_ctrl_map(handle->chain, &karg.xmap);
+ ret = uvc_ioctl_xu_ctrl_map(handle->chain, &karg.xmap);
if (ret)
return ret;
ret = uvc_v4l2_put_xu_mapping(&karg.xmap, up);
diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c
index d2eb9066e4dc..d4b023d4de7c 100644
--- a/drivers/media/usb/uvc/uvc_video.c
+++ b/drivers/media/usb/uvc/uvc_video.c
@@ -79,13 +79,14 @@ int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit,
if (likely(ret == size))
return 0;
- dev_err(&dev->udev->dev,
- "Failed to query (%s) UVC control %u on unit %u: %d (exp. %u).\n",
- uvc_query_name(query), cs, unit, ret, size);
-
- if (ret != -EPIPE)
- return ret;
+ if (ret != -EPIPE) {
+ dev_err(&dev->udev->dev,
+ "Failed to query (%s) UVC control %u on unit %u: %d (exp. %u).\n",
+ uvc_query_name(query), cs, unit, ret, size);
+ return ret < 0 ? ret : -EPIPE;
+ }
+ /* Reuse data[0] to request the error code. */
tmp = *(u8 *)data;
ret = __uvc_query_ctrl(dev, UVC_GET_CUR, 0, intfnum,
@@ -107,7 +108,7 @@ int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit,
case 1: /* Not ready */
return -EBUSY;
case 2: /* Wrong state */
- return -EILSEQ;
+ return -EACCES;
case 3: /* Power */
return -EREMOTE;
case 4: /* Out of range */
@@ -129,12 +130,13 @@ int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit,
return -EPIPE;
}
+static const struct usb_device_id elgato_cam_link_4k = {
+ USB_DEVICE(0x0fd9, 0x0066)
+};
+
static void uvc_fixup_video_ctrl(struct uvc_streaming *stream,
struct uvc_streaming_control *ctrl)
{
- static const struct usb_device_id elgato_cam_link_4k = {
- USB_DEVICE(0x0fd9, 0x0066)
- };
struct uvc_format *format = NULL;
struct uvc_frame *frame = NULL;
unsigned int i;
@@ -297,7 +299,7 @@ static int uvc_get_video_ctrl(struct uvc_streaming *stream,
dev_err(&stream->intf->dev,
"Failed to query (%u) UVC %s control : %d (exp. %u).\n",
query, probe ? "probe" : "commit", ret, size);
- ret = -EIO;
+ ret = (ret == -EPROTO) ? -EPROTO : -EIO;
goto out;
}
@@ -516,7 +518,9 @@ uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf,
/*
* To limit the amount of data, drop SCRs with an SOF identical to the
- * previous one.
+ * previous one. This filtering is also needed to support UVC 1.5, where
+ * all the data packets of the same frame contains the same SOF. In that
+ * case only the first one will match the host_sof.
*/
dev_sof = get_unaligned_le16(&data[header_size - 2]);
if (dev_sof == stream->clock.last_sof)
@@ -1352,7 +1356,9 @@ static void uvc_video_decode_meta(struct uvc_streaming *stream,
if (has_scr)
memcpy(stream->clock.last_scr, scr, 6);
- memcpy(&meta->length, mem, length);
+ meta->length = mem[0];
+ meta->flags = mem[1];
+ memcpy(meta->buf, &mem[2], length - 2);
meta_buf->bytesused += length + sizeof(meta->ns) + sizeof(meta->sof);
uvc_dbg(stream->dev, FRAME,
@@ -1965,6 +1971,17 @@ static int uvc_video_start_transfer(struct uvc_streaming *stream,
"Selecting alternate setting %u (%u B/frame bandwidth)\n",
altsetting, best_psize);
+ /*
+ * Some devices, namely the Logitech C910 and B910, are unable
+ * to recover from a USB autosuspend, unless the alternate
+ * setting of the streaming interface is toggled.
+ */
+ if (stream->dev->quirks & UVC_QUIRK_WAKE_AUTOSUSPEND) {
+ usb_set_interface(stream->dev->udev, intfnum,
+ altsetting);
+ usb_set_interface(stream->dev->udev, intfnum, 0);
+ }
+
ret = usb_set_interface(stream->dev->udev, intfnum, altsetting);
if (ret < 0)
return ret;
@@ -2121,6 +2138,21 @@ int uvc_video_init(struct uvc_streaming *stream)
* request on the probe control, as required by the UVC specification.
*/
ret = uvc_get_video_ctrl(stream, probe, 1, UVC_GET_CUR);
+
+ /*
+ * Elgato Cam Link 4k can be in a stalled state if the resolution of
+ * the external source has changed while the firmware initializes.
+ * Once in this state, the device is useless until it receives a
+ * USB reset. It has even been observed that the stalled state will
+ * continue even after unplugging the device.
+ */
+ if (ret == -EPROTO &&
+ usb_match_one_id(stream->dev->intf, &elgato_cam_link_4k)) {
+ dev_err(&stream->intf->dev, "Elgato Cam Link 4K firmware crash detected\n");
+ dev_err(&stream->intf->dev, "Resetting the device, unplug and replug to recover\n");
+ usb_reset_device(stream->dev->udev);
+ }
+
if (ret < 0)
return ret;
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index df93db259312..9a596c8d894a 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -51,8 +51,6 @@
#define UVC_URBS 5
/* Maximum number of packets per URB. */
#define UVC_MAX_PACKETS 32
-/* Maximum status buffer size in bytes of interrupt URB. */
-#define UVC_MAX_STATUS_SIZE 16
#define UVC_CTRL_CONTROL_TIMEOUT 5000
#define UVC_CTRL_STREAMING_TIMEOUT 5000
@@ -74,6 +72,7 @@
#define UVC_QUIRK_RESTORE_CTRLS_ON_INIT 0x00000400
#define UVC_QUIRK_FORCE_Y8 0x00000800
#define UVC_QUIRK_FORCE_BPP 0x00001000
+#define UVC_QUIRK_WAKE_AUTOSUSPEND 0x00002000
/* Format flags */
#define UVC_FMT_FLAG_COMPRESSED 0x00000001
@@ -116,8 +115,9 @@ struct uvc_control_mapping {
enum v4l2_ctrl_type v4l2_type;
u32 data_type;
- const struct uvc_menu_info *menu_info;
- u32 menu_count;
+ const u32 *menu_mapping;
+ const char (*menu_names)[UVC_MENU_NAME_LEN];
+ unsigned long menu_mask;
u32 master_id;
s32 master_manual;
@@ -264,8 +264,6 @@ struct uvc_format {
u32 fcc;
u32 flags;
- char name[32];
-
unsigned int nframes;
struct uvc_frame *frame;
};
@@ -527,6 +525,26 @@ struct uvc_device_info {
const struct uvc_control_mapping **mappings;
};
+struct uvc_status_streaming {
+ u8 button;
+} __packed;
+
+struct uvc_status_control {
+ u8 bSelector;
+ u8 bAttribute;
+ u8 bValue[11];
+} __packed;
+
+struct uvc_status {
+ u8 bStatusType;
+ u8 bOriginator;
+ u8 bEvent;
+ union {
+ struct uvc_status_control control;
+ struct uvc_status_streaming streaming;
+ };
+} __packed;
+
struct uvc_device {
struct usb_device *udev;
struct usb_interface *intf;
@@ -559,7 +577,9 @@ struct uvc_device {
/* Status Interrupt Endpoint */
struct usb_host_endpoint *int_ep;
struct urb *int_urb;
- u8 *status;
+ struct uvc_status *status;
+ bool flush_status;
+
struct input_dev *input;
char input_phys[64];
@@ -728,6 +748,8 @@ int uvc_status_start(struct uvc_device *dev, gfp_t flags);
void uvc_status_stop(struct uvc_device *dev);
/* Controls */
+extern const struct uvc_control_mapping uvc_ctrl_power_line_mapping_limited;
+extern const struct uvc_control_mapping uvc_ctrl_power_line_mapping_uvc11;
extern const struct v4l2_subscribed_event_ops uvc_ctrl_sub_ev_ops;
int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
@@ -761,7 +783,8 @@ static inline int uvc_ctrl_rollback(struct uvc_fh *handle)
int uvc_ctrl_get(struct uvc_video_chain *chain, struct v4l2_ext_control *xctrl);
int uvc_ctrl_set(struct uvc_fh *handle, struct v4l2_ext_control *xctrl);
int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id,
- bool read);
+ const struct v4l2_ext_controls *ctrls,
+ unsigned long ioctl);
int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
struct uvc_xu_control_query *xqry);
diff --git a/drivers/media/v4l2-core/v4l2-h264.c b/drivers/media/v4l2-core/v4l2-h264.c
index 72bd64f65198..c00197d095e7 100644
--- a/drivers/media/v4l2-core/v4l2-h264.c
+++ b/drivers/media/v4l2-core/v4l2-h264.c
@@ -305,6 +305,8 @@ static const char *format_ref_list_p(const struct v4l2_h264_reflist_builder *bui
int n = 0, i;
*out_str = kmalloc(tmp_str_size, GFP_KERNEL);
+ if (!(*out_str))
+ return NULL;
n += snprintf(*out_str + n, tmp_str_size - n, "|");
@@ -343,6 +345,8 @@ static const char *format_ref_list_b(const struct v4l2_h264_reflist_builder *bui
int n = 0, i;
*out_str = kmalloc(tmp_str_size, GFP_KERNEL);
+ if (!(*out_str))
+ return NULL;
n += snprintf(*out_str + n, tmp_str_size - n, "|");
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 8e0a0ff62a70..87f163a89c80 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -16,6 +16,7 @@
#include <linux/kernel.h>
#include <linux/version.h>
+#include <linux/v4l2-subdev.h>
#include <linux/videodev2.h>
#include <media/media-device.h> /* for media_set_bus_info() */
@@ -1298,6 +1299,9 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_PIX_FMT_BGRX32: descr = "32-bit XBGR 8-8-8-8"; break;
case V4L2_PIX_FMT_RGBA32: descr = "32-bit RGBA 8-8-8-8"; break;
case V4L2_PIX_FMT_RGBX32: descr = "32-bit RGBX 8-8-8-8"; break;
+ case V4L2_PIX_FMT_RGBX1010102: descr = "32-bit RGBX 10-10-10-2"; break;
+ case V4L2_PIX_FMT_RGBA1010102: descr = "32-bit RGBA 10-10-10-2"; break;
+ case V4L2_PIX_FMT_ARGB2101010: descr = "32-bit ARGB 2-10-10-10"; break;
case V4L2_PIX_FMT_GREY: descr = "8-bit Greyscale"; break;
case V4L2_PIX_FMT_Y4: descr = "4-bit Greyscale"; break;
case V4L2_PIX_FMT_Y6: descr = "6-bit Greyscale"; break;
@@ -1442,6 +1446,9 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_PIX_FMT_NV12M_8L128: descr = "NV12M (8x128 Linear)"; break;
case V4L2_PIX_FMT_NV12_10BE_8L128: descr = "10-bit NV12 (8x128 Linear, BE)"; break;
case V4L2_PIX_FMT_NV12M_10BE_8L128: descr = "10-bit NV12M (8x128 Linear, BE)"; break;
+ case V4L2_PIX_FMT_Y210: descr = "10-bit YUYV Packed"; break;
+ case V4L2_PIX_FMT_Y212: descr = "12-bit YUYV Packed"; break;
+ case V4L2_PIX_FMT_Y216: descr = "16-bit YUYV Packed"; break;
default:
/* Compressed formats */
@@ -3148,6 +3155,21 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
ret = 1;
break;
}
+
+ case VIDIOC_SUBDEV_G_ROUTING:
+ case VIDIOC_SUBDEV_S_ROUTING: {
+ struct v4l2_subdev_routing *routing = parg;
+
+ if (routing->num_routes > 256)
+ return -E2BIG;
+
+ *user_ptr = u64_to_user_ptr(routing->routes);
+ *kernel_ptr = (void **)&routing->routes;
+ *array_size = sizeof(struct v4l2_subdev_route)
+ * routing->num_routes;
+ ret = 1;
+ break;
+ }
}
return ret;
@@ -3394,8 +3416,15 @@ video_usercopy(struct file *file, unsigned int orig_cmd, unsigned long arg,
/*
* Some ioctls can return an error, but still have valid
* results that must be returned.
+ *
+ * FIXME: subdev IOCTLS are partially handled here and partially in
+ * v4l2-subdev.c and the 'always_copy' flag can only be set for IOCTLS
+ * defined here as part of the 'v4l2_ioctls' array. As
+ * VIDIOC_SUBDEV_G_ROUTING needs to return results to applications even
+ * in case of failure, but it is not defined here as part of the
+ * 'v4l2_ioctls' array, insert an ad-hoc check to address that.
*/
- if (err < 0 && !always_copy)
+ if (err < 0 && !always_copy && cmd != VIDIOC_SUBDEV_G_ROUTING)
goto out;
if (has_array_args) {
diff --git a/drivers/media/v4l2-core/v4l2-jpeg.c b/drivers/media/v4l2-core/v4l2-jpeg.c
index c2513b775f6a..94435a7b6816 100644
--- a/drivers/media/v4l2-core/v4l2-jpeg.c
+++ b/drivers/media/v4l2-core/v4l2-jpeg.c
@@ -460,7 +460,7 @@ static int jpeg_parse_app14_data(struct jpeg_stream *stream,
/* Check for "Adobe\0" in Ap1..6 */
if (stream->curr + 6 > stream->end ||
strncmp(stream->curr, "Adobe\0", 6))
- return -EINVAL;
+ return jpeg_skip(stream, lp - 2);
/* get to Ap12 */
ret = jpeg_skip(stream, 11);
@@ -474,7 +474,7 @@ static int jpeg_parse_app14_data(struct jpeg_stream *stream,
*tf = ret;
/* skip the rest of the segment, this ensures at least it is complete */
- skip = lp - 2 - 11;
+ skip = lp - 2 - 11 - 1;
return jpeg_skip(stream, skip);
}
diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c
index be7fde1ed3ea..0cc30397fbad 100644
--- a/drivers/media/v4l2-core/v4l2-mem2mem.c
+++ b/drivers/media/v4l2-core/v4l2-mem2mem.c
@@ -922,9 +922,9 @@ static __poll_t v4l2_m2m_poll_for_data(struct file *file,
* means either in driver already or waiting for driver to claim it
* and start processing.
*/
- if ((!src_q->streaming || src_q->error ||
+ if ((!vb2_is_streaming(src_q) || src_q->error ||
list_empty(&src_q->queued_list)) &&
- (!dst_q->streaming || dst_q->error ||
+ (!vb2_is_streaming(dst_q) || dst_q->error ||
(list_empty(&dst_q->queued_list) && !dst_q->last_buffer_dequeued)))
return EPOLLERR;
diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index 6630fb30bc7d..b10045c02f43 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -8,21 +8,41 @@
* Sakari Ailus <sakari.ailus@iki.fi>
*/
+#include <linux/export.h>
#include <linux/ioctl.h>
#include <linux/leds.h>
#include <linux/mm.h>
#include <linux/module.h>
+#include <linux/overflow.h>
#include <linux/slab.h>
#include <linux/types.h>
-#include <linux/videodev2.h>
-#include <linux/export.h>
#include <linux/version.h>
+#include <linux/videodev2.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-fh.h>
#include <media/v4l2-event.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ioctl.h>
+
+#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
+/*
+ * The Streams API is an experimental feature. To use the Streams API, set
+ * 'v4l2_subdev_enable_streams_api' to 1 below.
+ */
+
+static bool v4l2_subdev_enable_streams_api;
+#endif
+
+/*
+ * Maximum stream ID is 63 for now, as we use u64 bitmask to represent a set
+ * of streams.
+ *
+ * Note that V4L2_FRAME_DESC_ENTRY_MAX is related: V4L2_FRAME_DESC_ENTRY_MAX
+ * restricts the total number of streams in a pad, although the stream ID is
+ * not restricted.
+ */
+#define V4L2_SUBDEV_MAX_STREAM_ID 63
#include "v4l2-subdev-priv.h"
@@ -151,8 +171,22 @@ static inline int check_pad(struct v4l2_subdev *sd, u32 pad)
return 0;
}
-static int check_state_pads(u32 which, struct v4l2_subdev_state *state)
+static int check_state(struct v4l2_subdev *sd, struct v4l2_subdev_state *state,
+ u32 which, u32 pad, u32 stream)
{
+ if (sd->flags & V4L2_SUBDEV_FL_STREAMS) {
+#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
+ if (!v4l2_subdev_state_get_stream_format(state, pad, stream))
+ return -EINVAL;
+ return 0;
+#else
+ return -EINVAL;
+#endif
+ }
+
+ if (stream != 0)
+ return -EINVAL;
+
if (which == V4L2_SUBDEV_FORMAT_TRY && (!state || !state->pads))
return -EINVAL;
@@ -166,8 +200,11 @@ static inline int check_format(struct v4l2_subdev *sd,
if (!format)
return -EINVAL;
+ if (!(sd->flags & V4L2_SUBDEV_FL_STREAMS))
+ format->stream = 0;
+
return check_which(format->which) ? : check_pad(sd, format->pad) ? :
- check_state_pads(format->which, state);
+ check_state(sd, state, format->which, format->pad, format->stream);
}
static int call_get_fmt(struct v4l2_subdev *sd,
@@ -193,8 +230,11 @@ static int call_enum_mbus_code(struct v4l2_subdev *sd,
if (!code)
return -EINVAL;
+ if (!(sd->flags & V4L2_SUBDEV_FL_STREAMS))
+ code->stream = 0;
+
return check_which(code->which) ? : check_pad(sd, code->pad) ? :
- check_state_pads(code->which, state) ? :
+ check_state(sd, state, code->which, code->pad, code->stream) ? :
sd->ops->pad->enum_mbus_code(sd, state, code);
}
@@ -205,8 +245,11 @@ static int call_enum_frame_size(struct v4l2_subdev *sd,
if (!fse)
return -EINVAL;
+ if (!(sd->flags & V4L2_SUBDEV_FL_STREAMS))
+ fse->stream = 0;
+
return check_which(fse->which) ? : check_pad(sd, fse->pad) ? :
- check_state_pads(fse->which, state) ? :
+ check_state(sd, state, fse->which, fse->pad, fse->stream) ? :
sd->ops->pad->enum_frame_size(sd, state, fse);
}
@@ -240,8 +283,11 @@ static int call_enum_frame_interval(struct v4l2_subdev *sd,
if (!fie)
return -EINVAL;
+ if (!(sd->flags & V4L2_SUBDEV_FL_STREAMS))
+ fie->stream = 0;
+
return check_which(fie->which) ? : check_pad(sd, fie->pad) ? :
- check_state_pads(fie->which, state) ? :
+ check_state(sd, state, fie->which, fie->pad, fie->stream) ? :
sd->ops->pad->enum_frame_interval(sd, state, fie);
}
@@ -252,8 +298,11 @@ static inline int check_selection(struct v4l2_subdev *sd,
if (!sel)
return -EINVAL;
+ if (!(sd->flags & V4L2_SUBDEV_FL_STREAMS))
+ sel->stream = 0;
+
return check_which(sel->which) ? : check_pad(sd, sel->pad) ? :
- check_state_pads(sel->which, state);
+ check_state(sd, state, sel->which, sel->pad, sel->stream);
}
static int call_get_selection(struct v4l2_subdev *sd,
@@ -444,6 +493,10 @@ subdev_ioctl_get_state(struct v4l2_subdev *sd, struct v4l2_subdev_fh *subdev_fh,
case VIDIOC_SUBDEV_S_SELECTION:
which = ((struct v4l2_subdev_selection *)arg)->which;
break;
+ case VIDIOC_SUBDEV_G_ROUTING:
+ case VIDIOC_SUBDEV_S_ROUTING:
+ which = ((struct v4l2_subdev_routing *)arg)->which;
+ break;
}
return which == V4L2_SUBDEV_FORMAT_TRY ?
@@ -458,6 +511,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg,
struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
struct v4l2_fh *vfh = file->private_data;
bool ro_subdev = test_bit(V4L2_FL_SUBDEV_RO_DEVNODE, &vdev->flags);
+ bool streams_subdev = sd->flags & V4L2_SUBDEV_FL_STREAMS;
int rval;
switch (cmd) {
@@ -466,7 +520,9 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg,
memset(cap->reserved, 0, sizeof(cap->reserved));
cap->version = LINUX_VERSION_CODE;
- cap->capabilities = ro_subdev ? V4L2_SUBDEV_CAP_RO_SUBDEV : 0;
+ cap->capabilities =
+ (ro_subdev ? V4L2_SUBDEV_CAP_RO_SUBDEV : 0) |
+ (streams_subdev ? V4L2_SUBDEV_CAP_STREAMS : 0);
return 0;
}
@@ -757,6 +813,81 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg,
case VIDIOC_SUBDEV_QUERYSTD:
return v4l2_subdev_call(sd, video, querystd, arg);
+ case VIDIOC_SUBDEV_G_ROUTING: {
+ struct v4l2_subdev_routing *routing = arg;
+ struct v4l2_subdev_krouting *krouting;
+
+ if (!v4l2_subdev_enable_streams_api)
+ return -ENOIOCTLCMD;
+
+ if (!(sd->flags & V4L2_SUBDEV_FL_STREAMS))
+ return -ENOIOCTLCMD;
+
+ memset(routing->reserved, 0, sizeof(routing->reserved));
+
+ krouting = &state->routing;
+
+ if (routing->num_routes < krouting->num_routes) {
+ routing->num_routes = krouting->num_routes;
+ return -ENOSPC;
+ }
+
+ memcpy((struct v4l2_subdev_route *)(uintptr_t)routing->routes,
+ krouting->routes,
+ krouting->num_routes * sizeof(*krouting->routes));
+ routing->num_routes = krouting->num_routes;
+
+ return 0;
+ }
+
+ case VIDIOC_SUBDEV_S_ROUTING: {
+ struct v4l2_subdev_routing *routing = arg;
+ struct v4l2_subdev_route *routes =
+ (struct v4l2_subdev_route *)(uintptr_t)routing->routes;
+ struct v4l2_subdev_krouting krouting = {};
+ unsigned int i;
+
+ if (!v4l2_subdev_enable_streams_api)
+ return -ENOIOCTLCMD;
+
+ if (!(sd->flags & V4L2_SUBDEV_FL_STREAMS))
+ return -ENOIOCTLCMD;
+
+ if (routing->which != V4L2_SUBDEV_FORMAT_TRY && ro_subdev)
+ return -EPERM;
+
+ memset(routing->reserved, 0, sizeof(routing->reserved));
+
+ for (i = 0; i < routing->num_routes; ++i) {
+ const struct v4l2_subdev_route *route = &routes[i];
+ const struct media_pad *pads = sd->entity.pads;
+
+ if (route->sink_stream > V4L2_SUBDEV_MAX_STREAM_ID ||
+ route->source_stream > V4L2_SUBDEV_MAX_STREAM_ID)
+ return -EINVAL;
+
+ if (route->sink_pad >= sd->entity.num_pads)
+ return -EINVAL;
+
+ if (!(pads[route->sink_pad].flags &
+ MEDIA_PAD_FL_SINK))
+ return -EINVAL;
+
+ if (route->source_pad >= sd->entity.num_pads)
+ return -EINVAL;
+
+ if (!(pads[route->source_pad].flags &
+ MEDIA_PAD_FL_SOURCE))
+ return -EINVAL;
+ }
+
+ krouting.num_routes = routing->num_routes;
+ krouting.routes = routes;
+
+ return v4l2_subdev_call(sd, pad, set_routing, state,
+ routing->which, &krouting);
+ }
+
default:
return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
}
@@ -937,7 +1068,7 @@ int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd,
EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate_default);
static int
-v4l2_subdev_link_validate_get_format(struct media_pad *pad,
+v4l2_subdev_link_validate_get_format(struct media_pad *pad, u32 stream,
struct v4l2_subdev_format *fmt)
{
if (is_media_entity_v4l2_subdev(pad->entity)) {
@@ -946,7 +1077,11 @@ v4l2_subdev_link_validate_get_format(struct media_pad *pad,
fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE;
fmt->pad = pad->index;
- return v4l2_subdev_call_state_active(sd, pad, get_fmt, fmt);
+ fmt->stream = stream;
+
+ return v4l2_subdev_call(sd, pad, get_fmt,
+ v4l2_subdev_get_locked_active_state(sd),
+ fmt);
}
WARN(pad->entity->function != MEDIA_ENT_F_IO_V4L,
@@ -956,34 +1091,206 @@ v4l2_subdev_link_validate_get_format(struct media_pad *pad,
return -EINVAL;
}
+#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
+
+static void __v4l2_link_validate_get_streams(struct media_pad *pad,
+ u64 *streams_mask)
+{
+ struct v4l2_subdev_route *route;
+ struct v4l2_subdev_state *state;
+ struct v4l2_subdev *subdev;
+
+ subdev = media_entity_to_v4l2_subdev(pad->entity);
+
+ *streams_mask = 0;
+
+ state = v4l2_subdev_get_locked_active_state(subdev);
+ if (WARN_ON(!state))
+ return;
+
+ for_each_active_route(&state->routing, route) {
+ u32 route_pad;
+ u32 route_stream;
+
+ if (pad->flags & MEDIA_PAD_FL_SOURCE) {
+ route_pad = route->source_pad;
+ route_stream = route->source_stream;
+ } else {
+ route_pad = route->sink_pad;
+ route_stream = route->sink_stream;
+ }
+
+ if (route_pad != pad->index)
+ continue;
+
+ *streams_mask |= BIT_ULL(route_stream);
+ }
+}
+
+#endif /* CONFIG_VIDEO_V4L2_SUBDEV_API */
+
+static void v4l2_link_validate_get_streams(struct media_pad *pad,
+ u64 *streams_mask)
+{
+ struct v4l2_subdev *subdev = media_entity_to_v4l2_subdev(pad->entity);
+
+ if (!(subdev->flags & V4L2_SUBDEV_FL_STREAMS)) {
+ /* Non-streams subdevs have an implicit stream 0 */
+ *streams_mask = BIT_ULL(0);
+ return;
+ }
+
+#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
+ __v4l2_link_validate_get_streams(pad, streams_mask);
+#else
+ /* This shouldn't happen */
+ *streams_mask = 0;
+#endif
+}
+
+static int v4l2_subdev_link_validate_locked(struct media_link *link)
+{
+ struct v4l2_subdev *sink_subdev =
+ media_entity_to_v4l2_subdev(link->sink->entity);
+ struct device *dev = sink_subdev->entity.graph_obj.mdev->dev;
+ u64 source_streams_mask;
+ u64 sink_streams_mask;
+ u64 dangling_sink_streams;
+ u32 stream;
+ int ret;
+
+ dev_dbg(dev, "validating link \"%s\":%u -> \"%s\":%u\n",
+ link->source->entity->name, link->source->index,
+ link->sink->entity->name, link->sink->index);
+
+ v4l2_link_validate_get_streams(link->source, &source_streams_mask);
+ v4l2_link_validate_get_streams(link->sink, &sink_streams_mask);
+
+ /*
+ * It is ok to have more source streams than sink streams as extra
+ * source streams can just be ignored by the receiver, but having extra
+ * sink streams is an error as streams must have a source.
+ */
+ dangling_sink_streams = (source_streams_mask ^ sink_streams_mask) &
+ sink_streams_mask;
+ if (dangling_sink_streams) {
+ dev_err(dev, "Dangling sink streams: mask %#llx\n",
+ dangling_sink_streams);
+ return -EINVAL;
+ }
+
+ /* Validate source and sink stream formats */
+
+ for (stream = 0; stream < sizeof(sink_streams_mask) * 8; ++stream) {
+ struct v4l2_subdev_format sink_fmt, source_fmt;
+
+ if (!(sink_streams_mask & BIT_ULL(stream)))
+ continue;
+
+ dev_dbg(dev, "validating stream \"%s\":%u:%u -> \"%s\":%u:%u\n",
+ link->source->entity->name, link->source->index, stream,
+ link->sink->entity->name, link->sink->index, stream);
+
+ ret = v4l2_subdev_link_validate_get_format(link->source, stream,
+ &source_fmt);
+ if (ret < 0) {
+ dev_dbg(dev,
+ "Failed to get format for \"%s\":%u:%u (but that's ok)\n",
+ link->source->entity->name, link->source->index,
+ stream);
+ continue;
+ }
+
+ ret = v4l2_subdev_link_validate_get_format(link->sink, stream,
+ &sink_fmt);
+ if (ret < 0) {
+ dev_dbg(dev,
+ "Failed to get format for \"%s\":%u:%u (but that's ok)\n",
+ link->sink->entity->name, link->sink->index,
+ stream);
+ continue;
+ }
+
+ /* TODO: add stream number to link_validate() */
+ ret = v4l2_subdev_call(sink_subdev, pad, link_validate, link,
+ &source_fmt, &sink_fmt);
+ if (!ret)
+ continue;
+
+ if (ret != -ENOIOCTLCMD)
+ return ret;
+
+ ret = v4l2_subdev_link_validate_default(sink_subdev, link,
+ &source_fmt, &sink_fmt);
+
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
int v4l2_subdev_link_validate(struct media_link *link)
{
- struct v4l2_subdev *sink;
- struct v4l2_subdev_format sink_fmt, source_fmt;
- int rval;
+ struct v4l2_subdev *source_sd, *sink_sd;
+ struct v4l2_subdev_state *source_state, *sink_state;
+ int ret;
- rval = v4l2_subdev_link_validate_get_format(
- link->source, &source_fmt);
- if (rval < 0)
- return 0;
+ sink_sd = media_entity_to_v4l2_subdev(link->sink->entity);
+ source_sd = media_entity_to_v4l2_subdev(link->source->entity);
- rval = v4l2_subdev_link_validate_get_format(
- link->sink, &sink_fmt);
- if (rval < 0)
- return 0;
+ sink_state = v4l2_subdev_get_unlocked_active_state(sink_sd);
+ source_state = v4l2_subdev_get_unlocked_active_state(source_sd);
- sink = media_entity_to_v4l2_subdev(link->sink->entity);
+ if (sink_state)
+ v4l2_subdev_lock_state(sink_state);
- rval = v4l2_subdev_call(sink, pad, link_validate, link,
- &source_fmt, &sink_fmt);
- if (rval != -ENOIOCTLCMD)
- return rval;
+ if (source_state)
+ v4l2_subdev_lock_state(source_state);
+
+ ret = v4l2_subdev_link_validate_locked(link);
- return v4l2_subdev_link_validate_default(
- sink, link, &source_fmt, &sink_fmt);
+ if (sink_state)
+ v4l2_subdev_unlock_state(sink_state);
+
+ if (source_state)
+ v4l2_subdev_unlock_state(source_state);
+
+ return ret;
}
EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate);
+bool v4l2_subdev_has_pad_interdep(struct media_entity *entity,
+ unsigned int pad0, unsigned int pad1)
+{
+ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+ struct v4l2_subdev_krouting *routing;
+ struct v4l2_subdev_state *state;
+ unsigned int i;
+
+ state = v4l2_subdev_lock_and_get_active_state(sd);
+
+ routing = &state->routing;
+
+ for (i = 0; i < routing->num_routes; ++i) {
+ struct v4l2_subdev_route *route = &routing->routes[i];
+
+ if (!(route->flags & V4L2_SUBDEV_ROUTE_FL_ACTIVE))
+ continue;
+
+ if ((route->sink_pad == pad0 && route->source_pad == pad1) ||
+ (route->source_pad == pad0 && route->sink_pad == pad1)) {
+ v4l2_subdev_unlock_state(state);
+ return true;
+ }
+ }
+
+ v4l2_subdev_unlock_state(state);
+
+ return false;
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_has_pad_interdep);
+
struct v4l2_subdev_state *
__v4l2_subdev_state_alloc(struct v4l2_subdev *sd, const char *lock_name,
struct lock_class_key *lock_key)
@@ -1001,7 +1308,8 @@ __v4l2_subdev_state_alloc(struct v4l2_subdev *sd, const char *lock_name,
else
state->lock = &state->_lock;
- if (sd->entity.num_pads) {
+ /* Drivers that support streams do not need the legacy pad config */
+ if (!(sd->flags & V4L2_SUBDEV_FL_STREAMS) && sd->entity.num_pads) {
state->pads = kvcalloc(sd->entity.num_pads,
sizeof(*state->pads), GFP_KERNEL);
if (!state->pads) {
@@ -1040,6 +1348,8 @@ void __v4l2_subdev_state_free(struct v4l2_subdev_state *state)
mutex_destroy(&state->_lock);
+ kfree(state->routing.routes);
+ kvfree(state->stream_configs.configs);
kvfree(state->pads);
kfree(state);
}
@@ -1069,15 +1379,68 @@ EXPORT_SYMBOL_GPL(v4l2_subdev_cleanup);
#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
+static int
+v4l2_subdev_init_stream_configs(struct v4l2_subdev_stream_configs *stream_configs,
+ const struct v4l2_subdev_krouting *routing)
+{
+ struct v4l2_subdev_stream_configs new_configs = { 0 };
+ struct v4l2_subdev_route *route;
+ u32 idx;
+
+ /* Count number of formats needed */
+ for_each_active_route(routing, route) {
+ /*
+ * Each route needs a format on both ends of the route.
+ */
+ new_configs.num_configs += 2;
+ }
+
+ if (new_configs.num_configs) {
+ new_configs.configs = kvcalloc(new_configs.num_configs,
+ sizeof(*new_configs.configs),
+ GFP_KERNEL);
+
+ if (!new_configs.configs)
+ return -ENOMEM;
+ }
+
+ /*
+ * Fill in the 'pad' and stream' value for each item in the array from
+ * the routing table
+ */
+ idx = 0;
+
+ for_each_active_route(routing, route) {
+ new_configs.configs[idx].pad = route->sink_pad;
+ new_configs.configs[idx].stream = route->sink_stream;
+
+ idx++;
+
+ new_configs.configs[idx].pad = route->source_pad;
+ new_configs.configs[idx].stream = route->source_stream;
+
+ idx++;
+ }
+
+ kvfree(stream_configs->configs);
+ *stream_configs = new_configs;
+
+ return 0;
+}
+
int v4l2_subdev_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *state,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *fmt;
- if (format->pad >= sd->entity.num_pads)
- return -EINVAL;
+ if (sd->flags & V4L2_SUBDEV_FL_STREAMS)
+ fmt = v4l2_subdev_state_get_stream_format(state, format->pad,
+ format->stream);
+ else if (format->pad < sd->entity.num_pads && format->stream == 0)
+ fmt = v4l2_subdev_get_pad_format(sd, state, format->pad);
+ else
+ fmt = NULL;
- fmt = v4l2_subdev_get_pad_format(sd, state, format->pad);
if (!fmt)
return -EINVAL;
@@ -1087,6 +1450,590 @@ int v4l2_subdev_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *state,
}
EXPORT_SYMBOL_GPL(v4l2_subdev_get_fmt);
+int v4l2_subdev_set_routing(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ const struct v4l2_subdev_krouting *routing)
+{
+ struct v4l2_subdev_krouting *dst = &state->routing;
+ const struct v4l2_subdev_krouting *src = routing;
+ struct v4l2_subdev_krouting new_routing = { 0 };
+ size_t bytes;
+ int r;
+
+ if (unlikely(check_mul_overflow((size_t)src->num_routes,
+ sizeof(*src->routes), &bytes)))
+ return -EOVERFLOW;
+
+ lockdep_assert_held(state->lock);
+
+ if (src->num_routes > 0) {
+ new_routing.routes = kmemdup(src->routes, bytes, GFP_KERNEL);
+ if (!new_routing.routes)
+ return -ENOMEM;
+ }
+
+ new_routing.num_routes = src->num_routes;
+
+ r = v4l2_subdev_init_stream_configs(&state->stream_configs,
+ &new_routing);
+ if (r) {
+ kfree(new_routing.routes);
+ return r;
+ }
+
+ kfree(dst->routes);
+ *dst = new_routing;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_set_routing);
+
+struct v4l2_subdev_route *
+__v4l2_subdev_next_active_route(const struct v4l2_subdev_krouting *routing,
+ struct v4l2_subdev_route *route)
+{
+ if (route)
+ ++route;
+ else
+ route = &routing->routes[0];
+
+ for (; route < routing->routes + routing->num_routes; ++route) {
+ if (!(route->flags & V4L2_SUBDEV_ROUTE_FL_ACTIVE))
+ continue;
+
+ return route;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(__v4l2_subdev_next_active_route);
+
+int v4l2_subdev_set_routing_with_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_krouting *routing,
+ const struct v4l2_mbus_framefmt *fmt)
+{
+ struct v4l2_subdev_stream_configs *stream_configs;
+ unsigned int i;
+ int ret;
+
+ ret = v4l2_subdev_set_routing(sd, state, routing);
+ if (ret)
+ return ret;
+
+ stream_configs = &state->stream_configs;
+
+ for (i = 0; i < stream_configs->num_configs; ++i)
+ stream_configs->configs[i].fmt = *fmt;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_set_routing_with_fmt);
+
+struct v4l2_mbus_framefmt *
+v4l2_subdev_state_get_stream_format(struct v4l2_subdev_state *state,
+ unsigned int pad, u32 stream)
+{
+ struct v4l2_subdev_stream_configs *stream_configs;
+ unsigned int i;
+
+ lockdep_assert_held(state->lock);
+
+ stream_configs = &state->stream_configs;
+
+ for (i = 0; i < stream_configs->num_configs; ++i) {
+ if (stream_configs->configs[i].pad == pad &&
+ stream_configs->configs[i].stream == stream)
+ return &stream_configs->configs[i].fmt;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_state_get_stream_format);
+
+struct v4l2_rect *
+v4l2_subdev_state_get_stream_crop(struct v4l2_subdev_state *state,
+ unsigned int pad, u32 stream)
+{
+ struct v4l2_subdev_stream_configs *stream_configs;
+ unsigned int i;
+
+ lockdep_assert_held(state->lock);
+
+ stream_configs = &state->stream_configs;
+
+ for (i = 0; i < stream_configs->num_configs; ++i) {
+ if (stream_configs->configs[i].pad == pad &&
+ stream_configs->configs[i].stream == stream)
+ return &stream_configs->configs[i].crop;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_state_get_stream_crop);
+
+struct v4l2_rect *
+v4l2_subdev_state_get_stream_compose(struct v4l2_subdev_state *state,
+ unsigned int pad, u32 stream)
+{
+ struct v4l2_subdev_stream_configs *stream_configs;
+ unsigned int i;
+
+ lockdep_assert_held(state->lock);
+
+ stream_configs = &state->stream_configs;
+
+ for (i = 0; i < stream_configs->num_configs; ++i) {
+ if (stream_configs->configs[i].pad == pad &&
+ stream_configs->configs[i].stream == stream)
+ return &stream_configs->configs[i].compose;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_state_get_stream_compose);
+
+int v4l2_subdev_routing_find_opposite_end(const struct v4l2_subdev_krouting *routing,
+ u32 pad, u32 stream, u32 *other_pad,
+ u32 *other_stream)
+{
+ unsigned int i;
+
+ for (i = 0; i < routing->num_routes; ++i) {
+ struct v4l2_subdev_route *route = &routing->routes[i];
+
+ if (route->source_pad == pad &&
+ route->source_stream == stream) {
+ if (other_pad)
+ *other_pad = route->sink_pad;
+ if (other_stream)
+ *other_stream = route->sink_stream;
+ return 0;
+ }
+
+ if (route->sink_pad == pad && route->sink_stream == stream) {
+ if (other_pad)
+ *other_pad = route->source_pad;
+ if (other_stream)
+ *other_stream = route->source_stream;
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_routing_find_opposite_end);
+
+struct v4l2_mbus_framefmt *
+v4l2_subdev_state_get_opposite_stream_format(struct v4l2_subdev_state *state,
+ u32 pad, u32 stream)
+{
+ u32 other_pad, other_stream;
+ int ret;
+
+ ret = v4l2_subdev_routing_find_opposite_end(&state->routing,
+ pad, stream,
+ &other_pad, &other_stream);
+ if (ret)
+ return NULL;
+
+ return v4l2_subdev_state_get_stream_format(state, other_pad,
+ other_stream);
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_state_get_opposite_stream_format);
+
+u64 v4l2_subdev_state_xlate_streams(const struct v4l2_subdev_state *state,
+ u32 pad0, u32 pad1, u64 *streams)
+{
+ const struct v4l2_subdev_krouting *routing = &state->routing;
+ struct v4l2_subdev_route *route;
+ u64 streams0 = 0;
+ u64 streams1 = 0;
+
+ for_each_active_route(routing, route) {
+ if (route->sink_pad == pad0 && route->source_pad == pad1 &&
+ (*streams & BIT_ULL(route->sink_stream))) {
+ streams0 |= BIT_ULL(route->sink_stream);
+ streams1 |= BIT_ULL(route->source_stream);
+ }
+ if (route->source_pad == pad0 && route->sink_pad == pad1 &&
+ (*streams & BIT_ULL(route->source_stream))) {
+ streams0 |= BIT_ULL(route->source_stream);
+ streams1 |= BIT_ULL(route->sink_stream);
+ }
+ }
+
+ *streams = streams0;
+ return streams1;
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_state_xlate_streams);
+
+int v4l2_subdev_routing_validate(struct v4l2_subdev *sd,
+ const struct v4l2_subdev_krouting *routing,
+ enum v4l2_subdev_routing_restriction disallow)
+{
+ u32 *remote_pads = NULL;
+ unsigned int i, j;
+ int ret = -EINVAL;
+
+ if (disallow & V4L2_SUBDEV_ROUTING_NO_STREAM_MIX) {
+ remote_pads = kcalloc(sd->entity.num_pads, sizeof(*remote_pads),
+ GFP_KERNEL);
+ if (!remote_pads)
+ return -ENOMEM;
+
+ for (i = 0; i < sd->entity.num_pads; ++i)
+ remote_pads[i] = U32_MAX;
+ }
+
+ for (i = 0; i < routing->num_routes; ++i) {
+ const struct v4l2_subdev_route *route = &routing->routes[i];
+
+ /* Validate the sink and source pad numbers. */
+ if (route->sink_pad >= sd->entity.num_pads ||
+ !(sd->entity.pads[route->sink_pad].flags & MEDIA_PAD_FL_SINK)) {
+ dev_dbg(sd->dev, "route %u sink (%u) is not a sink pad\n",
+ i, route->sink_pad);
+ goto out;
+ }
+
+ if (route->source_pad >= sd->entity.num_pads ||
+ !(sd->entity.pads[route->source_pad].flags & MEDIA_PAD_FL_SOURCE)) {
+ dev_dbg(sd->dev, "route %u source (%u) is not a source pad\n",
+ i, route->source_pad);
+ goto out;
+ }
+
+ /*
+ * V4L2_SUBDEV_ROUTING_NO_STREAM_MIX: Streams on the same pad
+ * may not be routed to streams on different pads.
+ */
+ if (disallow & V4L2_SUBDEV_ROUTING_NO_STREAM_MIX) {
+ if (remote_pads[route->sink_pad] != U32_MAX &&
+ remote_pads[route->sink_pad] != route->source_pad) {
+ dev_dbg(sd->dev,
+ "route %u attempts to mix %s streams\n",
+ i, "sink");
+ goto out;
+ }
+
+ if (remote_pads[route->source_pad] != U32_MAX &&
+ remote_pads[route->source_pad] != route->sink_pad) {
+ dev_dbg(sd->dev,
+ "route %u attempts to mix %s streams\n",
+ i, "source");
+ goto out;
+ }
+
+ remote_pads[route->sink_pad] = route->source_pad;
+ remote_pads[route->source_pad] = route->sink_pad;
+ }
+
+ for (j = i + 1; j < routing->num_routes; ++j) {
+ const struct v4l2_subdev_route *r = &routing->routes[j];
+
+ /*
+ * V4L2_SUBDEV_ROUTING_NO_1_TO_N: No two routes can
+ * originate from the same (sink) stream.
+ */
+ if ((disallow & V4L2_SUBDEV_ROUTING_NO_1_TO_N) &&
+ route->sink_pad == r->sink_pad &&
+ route->sink_stream == r->sink_stream) {
+ dev_dbg(sd->dev,
+ "routes %u and %u originate from same sink (%u/%u)\n",
+ i, j, route->sink_pad,
+ route->sink_stream);
+ goto out;
+ }
+
+ /*
+ * V4L2_SUBDEV_ROUTING_NO_N_TO_1: No two routes can end
+ * at the same (source) stream.
+ */
+ if ((disallow & V4L2_SUBDEV_ROUTING_NO_N_TO_1) &&
+ route->source_pad == r->source_pad &&
+ route->source_stream == r->source_stream) {
+ dev_dbg(sd->dev,
+ "routes %u and %u end at same source (%u/%u)\n",
+ i, j, route->source_pad,
+ route->source_stream);
+ goto out;
+ }
+ }
+ }
+
+ ret = 0;
+
+out:
+ kfree(remote_pads);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_routing_validate);
+
+static int v4l2_subdev_enable_streams_fallback(struct v4l2_subdev *sd, u32 pad,
+ u64 streams_mask)
+{
+ struct device *dev = sd->entity.graph_obj.mdev->dev;
+ unsigned int i;
+ int ret;
+
+ /*
+ * The subdev doesn't implement pad-based stream enable, fall back
+ * on the .s_stream() operation. This can only be done for subdevs that
+ * have a single source pad, as sd->enabled_streams is global to the
+ * subdev.
+ */
+ if (!(sd->entity.pads[pad].flags & MEDIA_PAD_FL_SOURCE))
+ return -EOPNOTSUPP;
+
+ for (i = 0; i < sd->entity.num_pads; ++i) {
+ if (i != pad && sd->entity.pads[i].flags & MEDIA_PAD_FL_SOURCE)
+ return -EOPNOTSUPP;
+ }
+
+ if (sd->enabled_streams & streams_mask) {
+ dev_dbg(dev, "set of streams %#llx already enabled on %s:%u\n",
+ streams_mask, sd->entity.name, pad);
+ return -EALREADY;
+ }
+
+ /* Start streaming when the first streams are enabled. */
+ if (!sd->enabled_streams) {
+ ret = v4l2_subdev_call(sd, video, s_stream, 1);
+ if (ret)
+ return ret;
+ }
+
+ sd->enabled_streams |= streams_mask;
+
+ return 0;
+}
+
+int v4l2_subdev_enable_streams(struct v4l2_subdev *sd, u32 pad,
+ u64 streams_mask)
+{
+ struct device *dev = sd->entity.graph_obj.mdev->dev;
+ struct v4l2_subdev_state *state;
+ u64 found_streams = 0;
+ unsigned int i;
+ int ret;
+
+ /* A few basic sanity checks first. */
+ if (pad >= sd->entity.num_pads)
+ return -EINVAL;
+
+ if (!streams_mask)
+ return 0;
+
+ /* Fallback on .s_stream() if .enable_streams() isn't available. */
+ if (!sd->ops->pad || !sd->ops->pad->enable_streams)
+ return v4l2_subdev_enable_streams_fallback(sd, pad,
+ streams_mask);
+
+ state = v4l2_subdev_lock_and_get_active_state(sd);
+
+ /*
+ * Verify that the requested streams exist and that they are not
+ * already enabled.
+ */
+ for (i = 0; i < state->stream_configs.num_configs; ++i) {
+ struct v4l2_subdev_stream_config *cfg =
+ &state->stream_configs.configs[i];
+
+ if (cfg->pad != pad || !(streams_mask & BIT_ULL(cfg->stream)))
+ continue;
+
+ found_streams |= BIT_ULL(cfg->stream);
+
+ if (cfg->enabled) {
+ dev_dbg(dev, "stream %u already enabled on %s:%u\n",
+ cfg->stream, sd->entity.name, pad);
+ ret = -EALREADY;
+ goto done;
+ }
+ }
+
+ if (found_streams != streams_mask) {
+ dev_dbg(dev, "streams 0x%llx not found on %s:%u\n",
+ streams_mask & ~found_streams, sd->entity.name, pad);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* Call the .enable_streams() operation. */
+ ret = v4l2_subdev_call(sd, pad, enable_streams, state, pad,
+ streams_mask);
+ if (ret)
+ goto done;
+
+ /* Mark the streams as enabled. */
+ for (i = 0; i < state->stream_configs.num_configs; ++i) {
+ struct v4l2_subdev_stream_config *cfg =
+ &state->stream_configs.configs[i];
+
+ if (cfg->pad == pad && (streams_mask & BIT_ULL(cfg->stream)))
+ cfg->enabled = true;
+ }
+
+done:
+ v4l2_subdev_unlock_state(state);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_enable_streams);
+
+static int v4l2_subdev_disable_streams_fallback(struct v4l2_subdev *sd, u32 pad,
+ u64 streams_mask)
+{
+ struct device *dev = sd->entity.graph_obj.mdev->dev;
+ unsigned int i;
+ int ret;
+
+ /*
+ * If the subdev doesn't implement pad-based stream enable, fall back
+ * on the .s_stream() operation. This can only be done for subdevs that
+ * have a single source pad, as sd->enabled_streams is global to the
+ * subdev.
+ */
+ if (!(sd->entity.pads[pad].flags & MEDIA_PAD_FL_SOURCE))
+ return -EOPNOTSUPP;
+
+ for (i = 0; i < sd->entity.num_pads; ++i) {
+ if (i != pad && sd->entity.pads[i].flags & MEDIA_PAD_FL_SOURCE)
+ return -EOPNOTSUPP;
+ }
+
+ if ((sd->enabled_streams & streams_mask) != streams_mask) {
+ dev_dbg(dev, "set of streams %#llx already disabled on %s:%u\n",
+ streams_mask, sd->entity.name, pad);
+ return -EALREADY;
+ }
+
+ /* Stop streaming when the last streams are disabled. */
+ if (!(sd->enabled_streams & ~streams_mask)) {
+ ret = v4l2_subdev_call(sd, video, s_stream, 0);
+ if (ret)
+ return ret;
+ }
+
+ sd->enabled_streams &= ~streams_mask;
+
+ return 0;
+}
+
+int v4l2_subdev_disable_streams(struct v4l2_subdev *sd, u32 pad,
+ u64 streams_mask)
+{
+ struct device *dev = sd->entity.graph_obj.mdev->dev;
+ struct v4l2_subdev_state *state;
+ u64 found_streams = 0;
+ unsigned int i;
+ int ret;
+
+ /* A few basic sanity checks first. */
+ if (pad >= sd->entity.num_pads)
+ return -EINVAL;
+
+ if (!streams_mask)
+ return 0;
+
+ /* Fallback on .s_stream() if .disable_streams() isn't available. */
+ if (!sd->ops->pad || !sd->ops->pad->disable_streams)
+ return v4l2_subdev_disable_streams_fallback(sd, pad,
+ streams_mask);
+
+ state = v4l2_subdev_lock_and_get_active_state(sd);
+
+ /*
+ * Verify that the requested streams exist and that they are not
+ * already disabled.
+ */
+ for (i = 0; i < state->stream_configs.num_configs; ++i) {
+ struct v4l2_subdev_stream_config *cfg =
+ &state->stream_configs.configs[i];
+
+ if (cfg->pad != pad || !(streams_mask & BIT_ULL(cfg->stream)))
+ continue;
+
+ found_streams |= BIT_ULL(cfg->stream);
+
+ if (!cfg->enabled) {
+ dev_dbg(dev, "stream %u already disabled on %s:%u\n",
+ cfg->stream, sd->entity.name, pad);
+ ret = -EALREADY;
+ goto done;
+ }
+ }
+
+ if (found_streams != streams_mask) {
+ dev_dbg(dev, "streams 0x%llx not found on %s:%u\n",
+ streams_mask & ~found_streams, sd->entity.name, pad);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* Call the .disable_streams() operation. */
+ ret = v4l2_subdev_call(sd, pad, disable_streams, state, pad,
+ streams_mask);
+ if (ret)
+ goto done;
+
+ /* Mark the streams as disabled. */
+ for (i = 0; i < state->stream_configs.num_configs; ++i) {
+ struct v4l2_subdev_stream_config *cfg =
+ &state->stream_configs.configs[i];
+
+ if (cfg->pad == pad && (streams_mask & BIT_ULL(cfg->stream)))
+ cfg->enabled = false;
+ }
+
+done:
+ v4l2_subdev_unlock_state(state);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_disable_streams);
+
+int v4l2_subdev_s_stream_helper(struct v4l2_subdev *sd, int enable)
+{
+ struct v4l2_subdev_state *state;
+ struct v4l2_subdev_route *route;
+ struct media_pad *pad;
+ u64 source_mask = 0;
+ int pad_index = -1;
+
+ /*
+ * Find the source pad. This helper is meant for subdevs that have a
+ * single source pad, so failures shouldn't happen, but catch them
+ * loudly nonetheless as they indicate a driver bug.
+ */
+ media_entity_for_each_pad(&sd->entity, pad) {
+ if (pad->flags & MEDIA_PAD_FL_SOURCE) {
+ pad_index = pad->index;
+ break;
+ }
+ }
+
+ if (WARN_ON(pad_index == -1))
+ return -EINVAL;
+
+ /*
+ * As there's a single source pad, just collect all the source streams.
+ */
+ state = v4l2_subdev_lock_and_get_active_state(sd);
+
+ for_each_active_route(&state->routing, route)
+ source_mask |= BIT_ULL(route->source_stream);
+
+ v4l2_subdev_unlock_state(state);
+
+ if (enable)
+ return v4l2_subdev_enable_streams(sd, pad_index, source_mask);
+ else
+ return v4l2_subdev_disable_streams(sd, pad_index, source_mask);
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_s_stream_helper);
+
#endif /* CONFIG_VIDEO_V4L2_SUBDEV_API */
#endif /* CONFIG_MEDIA_CONTROLLER */
diff --git a/drivers/media/v4l2-core/videobuf-dma-contig.c b/drivers/media/v4l2-core/videobuf-dma-contig.c
index f2c439359557..4c2ec7a0d804 100644
--- a/drivers/media/v4l2-core/videobuf-dma-contig.c
+++ b/drivers/media/v4l2-core/videobuf-dma-contig.c
@@ -314,7 +314,7 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
}
vma->vm_ops = &videobuf_vm_ops;
- vma->vm_flags |= VM_DONTEXPAND;
+ vm_flags_set(vma, VM_DONTEXPAND);
vma->vm_private_data = map;
dev_dbg(q->dev, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
diff --git a/drivers/media/v4l2-core/videobuf-dma-sg.c b/drivers/media/v4l2-core/videobuf-dma-sg.c
index 234e9f647c96..53001532e8e3 100644
--- a/drivers/media/v4l2-core/videobuf-dma-sg.c
+++ b/drivers/media/v4l2-core/videobuf-dma-sg.c
@@ -630,8 +630,8 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
map->count = 1;
map->q = q;
vma->vm_ops = &videobuf_vm_ops;
- vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
- vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */
+ /* using shared anonymous pages */
+ vm_flags_mod(vma, VM_DONTEXPAND | VM_DONTDUMP, VM_IO);
vma->vm_private_data = map;
dprintk(1, "mmap %p: q=%p %08lx-%08lx pgoff %08lx bufs %d-%d\n",
map, q, vma->vm_start, vma->vm_end, vma->vm_pgoff, first, last);
diff --git a/drivers/media/v4l2-core/videobuf-vmalloc.c b/drivers/media/v4l2-core/videobuf-vmalloc.c
index 9b2443720ab0..85c7090606d6 100644
--- a/drivers/media/v4l2-core/videobuf-vmalloc.c
+++ b/drivers/media/v4l2-core/videobuf-vmalloc.c
@@ -247,7 +247,7 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
}
vma->vm_ops = &videobuf_vm_ops;
- vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
+ vm_flags_set(vma, VM_DONTEXPAND | VM_DONTDUMP);
vma->vm_private_data = map;
dprintk(1, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
diff --git a/drivers/memory/renesas-rpc-if.c b/drivers/memory/renesas-rpc-if.c
index 09cd4318a83d..025bb628aaf3 100644
--- a/drivers/memory/renesas-rpc-if.c
+++ b/drivers/memory/renesas-rpc-if.c
@@ -163,14 +163,36 @@ static const struct regmap_access_table rpcif_volatile_table = {
.n_yes_ranges = ARRAY_SIZE(rpcif_volatile_ranges),
};
+struct rpcif_priv {
+ struct device *dev;
+ void __iomem *base;
+ void __iomem *dirmap;
+ struct regmap *regmap;
+ struct reset_control *rstc;
+ struct platform_device *vdev;
+ size_t size;
+ enum rpcif_type type;
+ enum rpcif_data_dir dir;
+ u8 bus_size;
+ u8 xfer_size;
+ void *buffer;
+ u32 xferlen;
+ u32 smcr;
+ u32 smadr;
+ u32 command; /* DRCMR or SMCMR */
+ u32 option; /* DROPR or SMOPR */
+ u32 enable; /* DRENR or SMENR */
+ u32 dummy; /* DRDMCR or SMDMCR */
+ u32 ddr; /* DRDRENR or SMDRENR */
+};
/*
* Custom accessor functions to ensure SM[RW]DR[01] are always accessed with
- * proper width. Requires rpcif.xfer_size to be correctly set before!
+ * proper width. Requires rpcif_priv.xfer_size to be correctly set before!
*/
static int rpcif_reg_read(void *context, unsigned int reg, unsigned int *val)
{
- struct rpcif *rpc = context;
+ struct rpcif_priv *rpc = context;
switch (reg) {
case RPCIF_SMRDR0:
@@ -206,7 +228,7 @@ static int rpcif_reg_read(void *context, unsigned int reg, unsigned int *val)
static int rpcif_reg_write(void *context, unsigned int reg, unsigned int val)
{
- struct rpcif *rpc = context;
+ struct rpcif_priv *rpc = context;
switch (reg) {
case RPCIF_SMWDR0:
@@ -253,39 +275,18 @@ static const struct regmap_config rpcif_regmap_config = {
.volatile_table = &rpcif_volatile_table,
};
-int rpcif_sw_init(struct rpcif *rpc, struct device *dev)
+int rpcif_sw_init(struct rpcif *rpcif, struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct resource *res;
+ struct rpcif_priv *rpc = dev_get_drvdata(dev);
- rpc->dev = dev;
-
- rpc->base = devm_platform_ioremap_resource_byname(pdev, "regs");
- if (IS_ERR(rpc->base))
- return PTR_ERR(rpc->base);
-
- rpc->regmap = devm_regmap_init(&pdev->dev, NULL, rpc, &rpcif_regmap_config);
- if (IS_ERR(rpc->regmap)) {
- dev_err(&pdev->dev,
- "failed to init regmap for rpcif, error %ld\n",
- PTR_ERR(rpc->regmap));
- return PTR_ERR(rpc->regmap);
- }
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dirmap");
- rpc->dirmap = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(rpc->dirmap))
- return PTR_ERR(rpc->dirmap);
- rpc->size = resource_size(res);
-
- rpc->type = (uintptr_t)of_device_get_match_data(dev);
- rpc->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
-
- return PTR_ERR_OR_ZERO(rpc->rstc);
+ rpcif->dev = dev;
+ rpcif->dirmap = rpc->dirmap;
+ rpcif->size = rpc->size;
+ return 0;
}
EXPORT_SYMBOL(rpcif_sw_init);
-static void rpcif_rzg2l_timing_adjust_sdr(struct rpcif *rpc)
+static void rpcif_rzg2l_timing_adjust_sdr(struct rpcif_priv *rpc)
{
regmap_write(rpc->regmap, RPCIF_PHYWR, 0xa5390000);
regmap_write(rpc->regmap, RPCIF_PHYADD, 0x80000000);
@@ -299,15 +300,17 @@ static void rpcif_rzg2l_timing_adjust_sdr(struct rpcif *rpc)
regmap_write(rpc->regmap, RPCIF_PHYADD, 0x80000032);
}
-int rpcif_hw_init(struct rpcif *rpc, bool hyperflash)
+int rpcif_hw_init(struct device *dev, bool hyperflash)
{
+ struct rpcif_priv *rpc = dev_get_drvdata(dev);
u32 dummy;
+ int ret;
- pm_runtime_get_sync(rpc->dev);
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret)
+ return ret;
if (rpc->type == RPCIF_RZ_G2L) {
- int ret;
-
ret = reset_control_reset(rpc->rstc);
if (ret)
return ret;
@@ -356,7 +359,7 @@ int rpcif_hw_init(struct rpcif *rpc, bool hyperflash)
regmap_write(rpc->regmap, RPCIF_SSLDR, RPCIF_SSLDR_SPNDL(7) |
RPCIF_SSLDR_SLNDL(7) | RPCIF_SSLDR_SCKDL(7));
- pm_runtime_put(rpc->dev);
+ pm_runtime_put(dev);
rpc->bus_size = hyperflash ? 2 : 1;
@@ -364,7 +367,7 @@ int rpcif_hw_init(struct rpcif *rpc, bool hyperflash)
}
EXPORT_SYMBOL(rpcif_hw_init);
-static int wait_msg_xfer_end(struct rpcif *rpc)
+static int wait_msg_xfer_end(struct rpcif_priv *rpc)
{
u32 sts;
@@ -373,7 +376,7 @@ static int wait_msg_xfer_end(struct rpcif *rpc)
USEC_PER_SEC);
}
-static u8 rpcif_bits_set(struct rpcif *rpc, u32 nbytes)
+static u8 rpcif_bits_set(struct rpcif_priv *rpc, u32 nbytes)
{
if (rpc->bus_size == 2)
nbytes /= 2;
@@ -386,9 +389,11 @@ static u8 rpcif_bit_size(u8 buswidth)
return buswidth > 4 ? 2 : ilog2(buswidth);
}
-void rpcif_prepare(struct rpcif *rpc, const struct rpcif_op *op, u64 *offs,
+void rpcif_prepare(struct device *dev, const struct rpcif_op *op, u64 *offs,
size_t *len)
{
+ struct rpcif_priv *rpc = dev_get_drvdata(dev);
+
rpc->smcr = 0;
rpc->smadr = 0;
rpc->enable = 0;
@@ -430,8 +435,7 @@ void rpcif_prepare(struct rpcif *rpc, const struct rpcif_op *op, u64 *offs,
if (op->dummy.buswidth) {
rpc->enable |= RPCIF_SMENR_DME;
- rpc->dummy = RPCIF_SMDMCR_DMCYC(op->dummy.ncycles /
- op->dummy.buswidth);
+ rpc->dummy = RPCIF_SMDMCR_DMCYC(op->dummy.ncycles);
}
if (op->option.buswidth) {
@@ -472,12 +476,15 @@ void rpcif_prepare(struct rpcif *rpc, const struct rpcif_op *op, u64 *offs,
}
EXPORT_SYMBOL(rpcif_prepare);
-int rpcif_manual_xfer(struct rpcif *rpc)
+int rpcif_manual_xfer(struct device *dev)
{
+ struct rpcif_priv *rpc = dev_get_drvdata(dev);
u32 smenr, smcr, pos = 0, max = rpc->bus_size == 2 ? 8 : 4;
int ret = 0;
- pm_runtime_get_sync(rpc->dev);
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
+ return ret;
regmap_update_bits(rpc->regmap, RPCIF_PHYCNT,
RPCIF_PHYCNT_CAL, RPCIF_PHYCNT_CAL);
@@ -587,13 +594,13 @@ int rpcif_manual_xfer(struct rpcif *rpc)
}
exit:
- pm_runtime_put(rpc->dev);
+ pm_runtime_put(dev);
return ret;
err_out:
if (reset_control_reset(rpc->rstc))
- dev_err(rpc->dev, "Failed to reset HW\n");
- rpcif_hw_init(rpc, rpc->bus_size == 2);
+ dev_err(dev, "Failed to reset HW\n");
+ rpcif_hw_init(dev, rpc->bus_size == 2);
goto exit;
}
EXPORT_SYMBOL(rpcif_manual_xfer);
@@ -640,15 +647,19 @@ static void memcpy_fromio_readw(void *to,
}
}
-ssize_t rpcif_dirmap_read(struct rpcif *rpc, u64 offs, size_t len, void *buf)
+ssize_t rpcif_dirmap_read(struct device *dev, u64 offs, size_t len, void *buf)
{
+ struct rpcif_priv *rpc = dev_get_drvdata(dev);
loff_t from = offs & (rpc->size - 1);
size_t size = rpc->size - from;
+ int ret;
if (len > size)
len = size;
- pm_runtime_get_sync(rpc->dev);
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
+ return ret;
regmap_update_bits(rpc->regmap, RPCIF_CMNCR, RPCIF_CMNCR_MD, 0);
regmap_write(rpc->regmap, RPCIF_DRCR, 0);
@@ -666,7 +677,7 @@ ssize_t rpcif_dirmap_read(struct rpcif *rpc, u64 offs, size_t len, void *buf)
else
memcpy_fromio(buf, rpc->dirmap + from, len);
- pm_runtime_put(rpc->dev);
+ pm_runtime_put(dev);
return len;
}
@@ -674,14 +685,17 @@ EXPORT_SYMBOL(rpcif_dirmap_read);
static int rpcif_probe(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
struct platform_device *vdev;
struct device_node *flash;
+ struct rpcif_priv *rpc;
+ struct resource *res;
const char *name;
int ret;
- flash = of_get_next_child(pdev->dev.of_node, NULL);
+ flash = of_get_next_child(dev->of_node, NULL);
if (!flash) {
- dev_warn(&pdev->dev, "no flash node found\n");
+ dev_warn(dev, "no flash node found\n");
return -ENODEV;
}
@@ -691,16 +705,45 @@ static int rpcif_probe(struct platform_device *pdev)
name = "rpc-if-hyperflash";
} else {
of_node_put(flash);
- dev_warn(&pdev->dev, "unknown flash type\n");
+ dev_warn(dev, "unknown flash type\n");
return -ENODEV;
}
of_node_put(flash);
+ rpc = devm_kzalloc(dev, sizeof(*rpc), GFP_KERNEL);
+ if (!rpc)
+ return -ENOMEM;
+
+ rpc->base = devm_platform_ioremap_resource_byname(pdev, "regs");
+ if (IS_ERR(rpc->base))
+ return PTR_ERR(rpc->base);
+
+ rpc->regmap = devm_regmap_init(dev, NULL, rpc, &rpcif_regmap_config);
+ if (IS_ERR(rpc->regmap)) {
+ dev_err(dev, "failed to init regmap for rpcif, error %ld\n",
+ PTR_ERR(rpc->regmap));
+ return PTR_ERR(rpc->regmap);
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dirmap");
+ rpc->dirmap = devm_ioremap_resource(dev, res);
+ if (IS_ERR(rpc->dirmap))
+ return PTR_ERR(rpc->dirmap);
+ rpc->size = resource_size(res);
+
+ rpc->type = (uintptr_t)of_device_get_match_data(dev);
+ rpc->rstc = devm_reset_control_get_exclusive(dev, NULL);
+ if (IS_ERR(rpc->rstc))
+ return PTR_ERR(rpc->rstc);
+
vdev = platform_device_alloc(name, pdev->id);
if (!vdev)
return -ENOMEM;
- vdev->dev.parent = &pdev->dev;
- platform_set_drvdata(pdev, vdev);
+ vdev->dev.parent = dev;
+
+ rpc->dev = dev;
+ rpc->vdev = vdev;
+ platform_set_drvdata(pdev, rpc);
ret = platform_device_add(vdev);
if (ret) {
@@ -713,9 +756,9 @@ static int rpcif_probe(struct platform_device *pdev)
static int rpcif_remove(struct platform_device *pdev)
{
- struct platform_device *vdev = platform_get_drvdata(pdev);
+ struct rpcif_priv *rpc = platform_get_drvdata(pdev);
- platform_device_unregister(vdev);
+ platform_device_unregister(rpc->vdev);
return 0;
}
diff --git a/drivers/memory/ti-emif-pm.c b/drivers/memory/ti-emif-pm.c
index 31d6266f008c..cef0d3beb63b 100644
--- a/drivers/memory/ti-emif-pm.c
+++ b/drivers/memory/ti-emif-pm.c
@@ -277,18 +277,13 @@ static int ti_emif_probe(struct platform_device *pdev)
int ret;
struct resource *res;
struct device *dev = &pdev->dev;
- const struct of_device_id *match;
struct ti_emif_data *emif_data;
emif_data = devm_kzalloc(dev, sizeof(*emif_data), GFP_KERNEL);
if (!emif_data)
return -ENOMEM;
- match = of_match_device(ti_emif_of_match, &pdev->dev);
- if (!match)
- return -ENODEV;
-
- emif_data->pm_data.ti_emif_sram_config = (unsigned long)match->data;
+ emif_data->pm_data.ti_emif_sram_config = (unsigned long) device_get_match_data(&pdev->dev);
emif_data->pm_data.ti_emif_base_addr_virt = devm_platform_get_and_ioremap_resource(pdev,
0,
diff --git a/drivers/memstick/core/Kconfig b/drivers/memstick/core/Kconfig
index 08192fd70eb4..50fa0711da9d 100644
--- a/drivers/memstick/core/Kconfig
+++ b/drivers/memstick/core/Kconfig
@@ -20,6 +20,7 @@ config MEMSTICK_UNSAFE_RESUME
config MSPRO_BLOCK
tristate "MemoryStick Pro block device driver"
depends on BLOCK
+ imply IOSCHED_BFQ
help
Say Y here to enable the MemoryStick Pro block device driver
support. This provides a block device driver, which you can use
@@ -29,6 +30,7 @@ config MSPRO_BLOCK
config MS_BLOCK
tristate "MemoryStick Standard device driver"
depends on BLOCK
+ imply IOSCHED_BFQ
help
Say Y here to enable the MemoryStick Standard device driver
support. This provides a block device driver, which you can use
diff --git a/drivers/memstick/core/memstick.c b/drivers/memstick/core/memstick.c
index 660df7d269fa..bf7667845459 100644
--- a/drivers/memstick/core/memstick.c
+++ b/drivers/memstick/core/memstick.c
@@ -57,10 +57,10 @@ static int memstick_bus_match(struct device *dev, struct device_driver *drv)
return 0;
}
-static int memstick_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int memstick_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct memstick_dev *card = container_of(dev, struct memstick_dev,
- dev);
+ const struct memstick_dev *card = container_of_const(dev, struct memstick_dev,
+ dev);
if (add_uevent_var(env, "MEMSTICK_TYPE=%02X", card->id.type))
return -ENOMEM;
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 5c24841e5699..fcc141e067b9 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -15,6 +15,7 @@ config MFD_CS5535
tristate "AMD CS5535 and CS5536 southbridge core functions"
select MFD_CORE
depends on PCI && (X86_32 || (X86 && COMPILE_TEST))
+ depends on !UML
help
This is the core driver for CS5535/CS5536 MFD functions. This is
necessary for using the board's GPIO and MFGPT functionality.
@@ -2166,14 +2167,32 @@ config SGI_MFD_IOC3
If you have an SGI Origin, Octane, or a PCI IOC3 card,
then say Y. Otherwise say N.
-config MFD_INTEL_M10_BMC
- tristate "Intel MAX 10 Board Management Controller"
- depends on SPI_MASTER
- select REGMAP_SPI_AVMM
- select MFD_CORE
+config MFD_INTEL_M10_BMC_CORE
+ tristate
+ select MFD_CORE
+ select REGMAP
+ default n
+
+config MFD_INTEL_M10_BMC_SPI
+ tristate "Intel MAX 10 Board Management Controller with SPI"
+ depends on SPI_MASTER
+ select MFD_INTEL_M10_BMC_CORE
+ select REGMAP_SPI_AVMM
+ help
+ Support for the Intel MAX 10 board management controller using the
+ SPI interface.
+
+ This driver provides common support for accessing the device,
+ additional drivers must be enabled in order to use the functionality
+ of the device.
+
+config MFD_INTEL_M10_BMC_PMCI
+ tristate "Intel MAX 10 Board Management Controller with PMCI"
+ depends on FPGA_DFL
+ select MFD_INTEL_M10_BMC_CORE
+ select REGMAP
help
- Support for the Intel MAX 10 board management controller using the
- SPI interface.
+ Support for the Intel MAX 10 board management controller via PMCI.
This driver provides common support for accessing the device,
additional drivers must be enabled in order to use the functionality
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 09712495f4f4..2f6c89d1e277 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -262,7 +262,10 @@ obj-$(CONFIG_MFD_QCOM_PM8008) += qcom-pm8008.o
obj-$(CONFIG_SGI_MFD_IOC3) += ioc3.o
obj-$(CONFIG_MFD_SIMPLE_MFD_I2C) += simple-mfd-i2c.o
obj-$(CONFIG_MFD_SMPRO) += smpro-core.o
-obj-$(CONFIG_MFD_INTEL_M10_BMC) += intel-m10-bmc.o
+
+obj-$(CONFIG_MFD_INTEL_M10_BMC_CORE) += intel-m10-bmc-core.o
+obj-$(CONFIG_MFD_INTEL_M10_BMC_SPI) += intel-m10-bmc-spi.o
+obj-$(CONFIG_MFD_INTEL_M10_BMC_PMCI) += intel-m10-bmc-pmci.o
obj-$(CONFIG_MFD_ATC260X) += atc260x-core.o
obj-$(CONFIG_MFD_ATC260X_I2C) += atc260x-i2c.o
diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c
index bd7ee3260d53..c166fcd331f1 100644
--- a/drivers/mfd/arizona-core.c
+++ b/drivers/mfd/arizona-core.c
@@ -45,7 +45,7 @@ int arizona_clk32k_enable(struct arizona *arizona)
if (arizona->clk32k_ref == 1) {
switch (arizona->pdata.clk32k_src) {
case ARIZONA_32KZ_MCLK1:
- ret = pm_runtime_get_sync(arizona->dev);
+ ret = pm_runtime_resume_and_get(arizona->dev);
if (ret != 0)
goto err_ref;
ret = clk_prepare_enable(arizona->mclk[ARIZONA_MCLK1]);
diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
index 47fd700f284f..01a6bbb6d266 100644
--- a/drivers/mfd/axp20x.c
+++ b/drivers/mfd/axp20x.c
@@ -23,7 +23,7 @@
#include <linux/mfd/core.h>
#include <linux/module.h>
#include <linux/of_device.h>
-#include <linux/pm_runtime.h>
+#include <linux/reboot.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
@@ -825,17 +825,16 @@ static const struct mfd_cell axp813_cells[] = {
},
};
-static struct axp20x_dev *axp20x_pm_power_off;
-static void axp20x_power_off(void)
+static int axp20x_power_off(struct sys_off_data *data)
{
- if (axp20x_pm_power_off->variant == AXP288_ID)
- return;
+ struct axp20x_dev *axp20x = data->cb_data;
- regmap_write(axp20x_pm_power_off->regmap, AXP20X_OFF_CTRL,
- AXP20X_OFF);
+ regmap_write(axp20x->regmap, AXP20X_OFF_CTRL, AXP20X_OFF);
/* Give capacitors etc. time to drain to avoid kernel panic msg. */
mdelay(500);
+
+ return NOTIFY_DONE;
}
int axp20x_match_device(struct axp20x_dev *axp20x)
@@ -1002,10 +1001,11 @@ int axp20x_device_probe(struct axp20x_dev *axp20x)
return ret;
}
- if (!pm_power_off) {
- axp20x_pm_power_off = axp20x;
- pm_power_off = axp20x_power_off;
- }
+ if (axp20x->variant != AXP288_ID)
+ devm_register_sys_off_handler(axp20x->dev,
+ SYS_OFF_MODE_POWER_OFF,
+ SYS_OFF_PRIO_DEFAULT,
+ axp20x_power_off, axp20x);
dev_info(axp20x->dev, "AXP20X driver loaded\n");
@@ -1015,11 +1015,6 @@ EXPORT_SYMBOL(axp20x_device_probe);
void axp20x_device_remove(struct axp20x_dev *axp20x)
{
- if (axp20x == axp20x_pm_power_off) {
- axp20x_pm_power_off = NULL;
- pm_power_off = NULL;
- }
-
mfd_remove_devices(axp20x->dev);
regmap_del_irq_chip(axp20x->irq, axp20x->regmap_irqc);
}
diff --git a/drivers/mfd/intel-m10-bmc-core.c b/drivers/mfd/intel-m10-bmc-core.c
new file mode 100644
index 000000000000..dac9cf7bcb4a
--- /dev/null
+++ b/drivers/mfd/intel-m10-bmc-core.c
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Intel MAX 10 Board Management Controller chip - common code
+ *
+ * Copyright (C) 2018-2020 Intel Corporation. All rights reserved.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/device.h>
+#include <linux/dev_printk.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/intel-m10-bmc.h>
+#include <linux/module.h>
+
+static ssize_t bmc_version_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct intel_m10bmc *ddata = dev_get_drvdata(dev);
+ unsigned int val;
+ int ret;
+
+ ret = m10bmc_sys_read(ddata, ddata->info->csr_map->build_version, &val);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "0x%x\n", val);
+}
+static DEVICE_ATTR_RO(bmc_version);
+
+static ssize_t bmcfw_version_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct intel_m10bmc *ddata = dev_get_drvdata(dev);
+ unsigned int val;
+ int ret;
+
+ ret = m10bmc_sys_read(ddata, ddata->info->csr_map->fw_version, &val);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "0x%x\n", val);
+}
+static DEVICE_ATTR_RO(bmcfw_version);
+
+static ssize_t mac_address_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct intel_m10bmc *ddata = dev_get_drvdata(dev);
+ unsigned int macaddr_low, macaddr_high;
+ int ret;
+
+ ret = m10bmc_sys_read(ddata, ddata->info->csr_map->mac_low, &macaddr_low);
+ if (ret)
+ return ret;
+
+ ret = m10bmc_sys_read(ddata, ddata->info->csr_map->mac_high, &macaddr_high);
+ if (ret)
+ return ret;
+
+ return sysfs_emit(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n",
+ (u8)FIELD_GET(M10BMC_N3000_MAC_BYTE1, macaddr_low),
+ (u8)FIELD_GET(M10BMC_N3000_MAC_BYTE2, macaddr_low),
+ (u8)FIELD_GET(M10BMC_N3000_MAC_BYTE3, macaddr_low),
+ (u8)FIELD_GET(M10BMC_N3000_MAC_BYTE4, macaddr_low),
+ (u8)FIELD_GET(M10BMC_N3000_MAC_BYTE5, macaddr_high),
+ (u8)FIELD_GET(M10BMC_N3000_MAC_BYTE6, macaddr_high));
+}
+static DEVICE_ATTR_RO(mac_address);
+
+static ssize_t mac_count_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct intel_m10bmc *ddata = dev_get_drvdata(dev);
+ unsigned int macaddr_high;
+ int ret;
+
+ ret = m10bmc_sys_read(ddata, ddata->info->csr_map->mac_high, &macaddr_high);
+ if (ret)
+ return ret;
+
+ return sysfs_emit(buf, "%u\n", (u8)FIELD_GET(M10BMC_N3000_MAC_COUNT, macaddr_high));
+}
+static DEVICE_ATTR_RO(mac_count);
+
+static struct attribute *m10bmc_attrs[] = {
+ &dev_attr_bmc_version.attr,
+ &dev_attr_bmcfw_version.attr,
+ &dev_attr_mac_address.attr,
+ &dev_attr_mac_count.attr,
+ NULL,
+};
+
+static const struct attribute_group m10bmc_group = {
+ .attrs = m10bmc_attrs,
+};
+
+const struct attribute_group *m10bmc_dev_groups[] = {
+ &m10bmc_group,
+ NULL,
+};
+EXPORT_SYMBOL_GPL(m10bmc_dev_groups);
+
+int m10bmc_dev_init(struct intel_m10bmc *m10bmc, const struct intel_m10bmc_platform_info *info)
+{
+ int ret;
+
+ m10bmc->info = info;
+ dev_set_drvdata(m10bmc->dev, m10bmc);
+
+ ret = devm_mfd_add_devices(m10bmc->dev, PLATFORM_DEVID_AUTO,
+ info->cells, info->n_cells,
+ NULL, 0, NULL);
+ if (ret)
+ dev_err(m10bmc->dev, "Failed to register sub-devices: %d\n", ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(m10bmc_dev_init);
+
+MODULE_DESCRIPTION("Intel MAX 10 BMC core driver");
+MODULE_AUTHOR("Intel Corporation");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/intel-m10-bmc-pmci.c b/drivers/mfd/intel-m10-bmc-pmci.c
new file mode 100644
index 000000000000..8821f1876dd6
--- /dev/null
+++ b/drivers/mfd/intel-m10-bmc-pmci.c
@@ -0,0 +1,455 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MAX10 BMC Platform Management Component Interface (PMCI) based
+ * interface.
+ *
+ * Copyright (C) 2020-2023 Intel Corporation.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/device.h>
+#include <linux/dfl.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/intel-m10-bmc.h>
+#include <linux/minmax.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+struct m10bmc_pmci_device {
+ void __iomem *base;
+ struct intel_m10bmc m10bmc;
+ struct mutex flash_mutex; /* protects flash_busy and serializes flash read/read */
+ bool flash_busy;
+};
+
+/*
+ * Intel FGPA indirect register access via hardware controller/bridge.
+ */
+#define INDIRECT_CMD_OFF 0
+#define INDIRECT_CMD_CLR 0
+#define INDIRECT_CMD_RD BIT(0)
+#define INDIRECT_CMD_WR BIT(1)
+#define INDIRECT_CMD_ACK BIT(2)
+
+#define INDIRECT_ADDR_OFF 0x4
+#define INDIRECT_RD_OFF 0x8
+#define INDIRECT_WR_OFF 0xc
+
+#define INDIRECT_INT_US 1
+#define INDIRECT_TIMEOUT_US 10000
+
+struct indirect_ctx {
+ void __iomem *base;
+ struct device *dev;
+};
+
+static int indirect_clear_cmd(struct indirect_ctx *ctx)
+{
+ unsigned int cmd;
+ int ret;
+
+ writel(INDIRECT_CMD_CLR, ctx->base + INDIRECT_CMD_OFF);
+
+ ret = readl_poll_timeout(ctx->base + INDIRECT_CMD_OFF, cmd,
+ cmd == INDIRECT_CMD_CLR,
+ INDIRECT_INT_US, INDIRECT_TIMEOUT_US);
+ if (ret)
+ dev_err(ctx->dev, "timed out waiting clear cmd (residual cmd=0x%x)\n", cmd);
+
+ return ret;
+}
+
+static int indirect_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+ struct indirect_ctx *ctx = context;
+ unsigned int cmd, ack, tmpval;
+ int ret, ret2;
+
+ cmd = readl(ctx->base + INDIRECT_CMD_OFF);
+ if (cmd != INDIRECT_CMD_CLR)
+ dev_warn(ctx->dev, "residual cmd 0x%x on read entry\n", cmd);
+
+ writel(reg, ctx->base + INDIRECT_ADDR_OFF);
+ writel(INDIRECT_CMD_RD, ctx->base + INDIRECT_CMD_OFF);
+
+ ret = readl_poll_timeout(ctx->base + INDIRECT_CMD_OFF, ack,
+ (ack & INDIRECT_CMD_ACK) == INDIRECT_CMD_ACK,
+ INDIRECT_INT_US, INDIRECT_TIMEOUT_US);
+ if (ret)
+ dev_err(ctx->dev, "read timed out on reg 0x%x ack 0x%x\n", reg, ack);
+ else
+ tmpval = readl(ctx->base + INDIRECT_RD_OFF);
+
+ ret2 = indirect_clear_cmd(ctx);
+
+ if (ret)
+ return ret;
+ if (ret2)
+ return ret2;
+
+ *val = tmpval;
+ return 0;
+}
+
+static int indirect_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+ struct indirect_ctx *ctx = context;
+ unsigned int cmd, ack;
+ int ret, ret2;
+
+ cmd = readl(ctx->base + INDIRECT_CMD_OFF);
+ if (cmd != INDIRECT_CMD_CLR)
+ dev_warn(ctx->dev, "residual cmd 0x%x on write entry\n", cmd);
+
+ writel(val, ctx->base + INDIRECT_WR_OFF);
+ writel(reg, ctx->base + INDIRECT_ADDR_OFF);
+ writel(INDIRECT_CMD_WR, ctx->base + INDIRECT_CMD_OFF);
+
+ ret = readl_poll_timeout(ctx->base + INDIRECT_CMD_OFF, ack,
+ (ack & INDIRECT_CMD_ACK) == INDIRECT_CMD_ACK,
+ INDIRECT_INT_US, INDIRECT_TIMEOUT_US);
+ if (ret)
+ dev_err(ctx->dev, "write timed out on reg 0x%x ack 0x%x\n", reg, ack);
+
+ ret2 = indirect_clear_cmd(ctx);
+
+ if (ret)
+ return ret;
+ return ret2;
+}
+
+static void pmci_write_fifo(void __iomem *base, const u32 *buf, size_t count)
+{
+ while (count--)
+ writel(*buf++, base);
+}
+
+static void pmci_read_fifo(void __iomem *base, u32 *buf, size_t count)
+{
+ while (count--)
+ *buf++ = readl(base);
+}
+
+static u32 pmci_get_write_space(struct m10bmc_pmci_device *pmci)
+{
+ u32 val;
+ int ret;
+
+ ret = read_poll_timeout(readl, val,
+ FIELD_GET(M10BMC_N6000_FLASH_FIFO_SPACE, val) ==
+ M10BMC_N6000_FIFO_MAX_WORDS,
+ M10BMC_FLASH_INT_US, M10BMC_FLASH_TIMEOUT_US,
+ false, pmci->base + M10BMC_N6000_FLASH_CTRL);
+ if (ret == -ETIMEDOUT)
+ return 0;
+
+ return FIELD_GET(M10BMC_N6000_FLASH_FIFO_SPACE, val) * M10BMC_N6000_FIFO_WORD_SIZE;
+}
+
+static int pmci_flash_bulk_write(struct intel_m10bmc *m10bmc, const u8 *buf, u32 size)
+{
+ struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc);
+ u32 blk_size, offset = 0, write_count;
+
+ while (size) {
+ blk_size = min(pmci_get_write_space(pmci), size);
+ if (blk_size == 0) {
+ dev_err(m10bmc->dev, "get FIFO available size fail\n");
+ return -EIO;
+ }
+
+ if (size < M10BMC_N6000_FIFO_WORD_SIZE)
+ break;
+
+ write_count = blk_size / M10BMC_N6000_FIFO_WORD_SIZE;
+ pmci_write_fifo(pmci->base + M10BMC_N6000_FLASH_FIFO,
+ (u32 *)(buf + offset), write_count);
+
+ size -= blk_size;
+ offset += blk_size;
+ }
+
+ /* Handle remainder (less than M10BMC_N6000_FIFO_WORD_SIZE bytes) */
+ if (size) {
+ u32 tmp = 0;
+
+ memcpy(&tmp, buf + offset, size);
+ pmci_write_fifo(pmci->base + M10BMC_N6000_FLASH_FIFO, &tmp, 1);
+ }
+
+ return 0;
+}
+
+static int pmci_flash_bulk_read(struct intel_m10bmc *m10bmc, u8 *buf, u32 addr, u32 size)
+{
+ struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc);
+ u32 blk_size, offset = 0, val, full_read_count, read_count;
+ int ret;
+
+ while (size) {
+ blk_size = min_t(u32, size, M10BMC_N6000_READ_BLOCK_SIZE);
+ full_read_count = blk_size / M10BMC_N6000_FIFO_WORD_SIZE;
+
+ read_count = full_read_count;
+ if (full_read_count * M10BMC_N6000_FIFO_WORD_SIZE < blk_size)
+ read_count++;
+
+ writel(addr + offset, pmci->base + M10BMC_N6000_FLASH_ADDR);
+ writel(FIELD_PREP(M10BMC_N6000_FLASH_READ_COUNT, read_count) |
+ M10BMC_N6000_FLASH_RD_MODE,
+ pmci->base + M10BMC_N6000_FLASH_CTRL);
+
+ ret = readl_poll_timeout((pmci->base + M10BMC_N6000_FLASH_CTRL), val,
+ !(val & M10BMC_N6000_FLASH_BUSY),
+ M10BMC_FLASH_INT_US, M10BMC_FLASH_TIMEOUT_US);
+ if (ret) {
+ dev_err(m10bmc->dev, "read timed out on reading flash 0x%xn", val);
+ return ret;
+ }
+
+ pmci_read_fifo(pmci->base + M10BMC_N6000_FLASH_FIFO,
+ (u32 *)(buf + offset), full_read_count);
+
+ size -= blk_size;
+ offset += blk_size;
+
+ if (full_read_count < read_count)
+ break;
+
+ writel(0, pmci->base + M10BMC_N6000_FLASH_CTRL);
+ }
+
+ /* Handle remainder (less than M10BMC_N6000_FIFO_WORD_SIZE bytes) */
+ if (size) {
+ u32 tmp;
+
+ pmci_read_fifo(pmci->base + M10BMC_N6000_FLASH_FIFO, &tmp, 1);
+ memcpy(buf + offset, &tmp, size);
+
+ writel(0, pmci->base + M10BMC_N6000_FLASH_CTRL);
+ }
+
+ return 0;
+}
+
+static int m10bmc_pmci_set_flash_host_mux(struct intel_m10bmc *m10bmc, bool request)
+{
+ u32 ctrl;
+ int ret;
+
+ ret = regmap_update_bits(m10bmc->regmap, M10BMC_N6000_FLASH_MUX_CTRL,
+ M10BMC_N6000_FLASH_HOST_REQUEST,
+ FIELD_PREP(M10BMC_N6000_FLASH_HOST_REQUEST, request));
+ if (ret)
+ return ret;
+
+ return regmap_read_poll_timeout(m10bmc->regmap,
+ M10BMC_N6000_FLASH_MUX_CTRL, ctrl,
+ request ?
+ (get_flash_mux(ctrl) == M10BMC_N6000_FLASH_MUX_HOST) :
+ (get_flash_mux(ctrl) != M10BMC_N6000_FLASH_MUX_HOST),
+ M10BMC_FLASH_INT_US, M10BMC_FLASH_TIMEOUT_US);
+}
+
+static int m10bmc_pmci_flash_read(struct intel_m10bmc *m10bmc, u8 *buf, u32 addr, u32 size)
+{
+ struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc);
+ int ret, ret2;
+
+ mutex_lock(&pmci->flash_mutex);
+ if (pmci->flash_busy) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ ret = m10bmc_pmci_set_flash_host_mux(m10bmc, true);
+ if (ret)
+ goto mux_fail;
+
+ ret = pmci_flash_bulk_read(m10bmc, buf, addr, size);
+
+mux_fail:
+ ret2 = m10bmc_pmci_set_flash_host_mux(m10bmc, false);
+
+unlock:
+ mutex_unlock(&pmci->flash_mutex);
+ if (ret)
+ return ret;
+ return ret2;
+}
+
+static int m10bmc_pmci_flash_write(struct intel_m10bmc *m10bmc, const u8 *buf, u32 offset, u32 size)
+{
+ struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc);
+ int ret;
+
+ mutex_lock(&pmci->flash_mutex);
+ WARN_ON_ONCE(!pmci->flash_busy);
+ /* On write, firmware manages flash MUX */
+ ret = pmci_flash_bulk_write(m10bmc, buf + offset, size);
+ mutex_unlock(&pmci->flash_mutex);
+
+ return ret;
+}
+
+static int m10bmc_pmci_flash_lock(struct intel_m10bmc *m10bmc)
+{
+ struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc);
+ int ret = 0;
+
+ mutex_lock(&pmci->flash_mutex);
+ if (pmci->flash_busy) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ pmci->flash_busy = true;
+
+unlock:
+ mutex_unlock(&pmci->flash_mutex);
+ return ret;
+}
+
+static void m10bmc_pmci_flash_unlock(struct intel_m10bmc *m10bmc)
+{
+ struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc);
+
+ mutex_lock(&pmci->flash_mutex);
+ WARN_ON_ONCE(!pmci->flash_busy);
+ pmci->flash_busy = false;
+ mutex_unlock(&pmci->flash_mutex);
+}
+
+static const struct intel_m10bmc_flash_bulk_ops m10bmc_pmci_flash_bulk_ops = {
+ .read = m10bmc_pmci_flash_read,
+ .write = m10bmc_pmci_flash_write,
+ .lock_write = m10bmc_pmci_flash_lock,
+ .unlock_write = m10bmc_pmci_flash_unlock,
+};
+
+static const struct regmap_range m10bmc_pmci_regmap_range[] = {
+ regmap_reg_range(M10BMC_N6000_SYS_BASE, M10BMC_N6000_SYS_END),
+};
+
+static const struct regmap_access_table m10bmc_pmci_access_table = {
+ .yes_ranges = m10bmc_pmci_regmap_range,
+ .n_yes_ranges = ARRAY_SIZE(m10bmc_pmci_regmap_range),
+};
+
+static struct regmap_config m10bmc_pmci_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .wr_table = &m10bmc_pmci_access_table,
+ .rd_table = &m10bmc_pmci_access_table,
+ .reg_read = &indirect_reg_read,
+ .reg_write = &indirect_reg_write,
+ .max_register = M10BMC_N6000_SYS_END,
+};
+
+static struct mfd_cell m10bmc_pmci_n6000_bmc_subdevs[] = {
+ { .name = "n6000bmc-hwmon" },
+ { .name = "n6000bmc-sec-update" },
+};
+
+static const struct m10bmc_csr_map m10bmc_n6000_csr_map = {
+ .base = M10BMC_N6000_SYS_BASE,
+ .build_version = M10BMC_N6000_BUILD_VER,
+ .fw_version = NIOS2_N6000_FW_VERSION,
+ .mac_low = M10BMC_N6000_MAC_LOW,
+ .mac_high = M10BMC_N6000_MAC_HIGH,
+ .doorbell = M10BMC_N6000_DOORBELL,
+ .auth_result = M10BMC_N6000_AUTH_RESULT,
+ .bmc_prog_addr = M10BMC_N6000_BMC_PROG_ADDR,
+ .bmc_reh_addr = M10BMC_N6000_BMC_REH_ADDR,
+ .bmc_magic = M10BMC_N6000_BMC_PROG_MAGIC,
+ .sr_prog_addr = M10BMC_N6000_SR_PROG_ADDR,
+ .sr_reh_addr = M10BMC_N6000_SR_REH_ADDR,
+ .sr_magic = M10BMC_N6000_SR_PROG_MAGIC,
+ .pr_prog_addr = M10BMC_N6000_PR_PROG_ADDR,
+ .pr_reh_addr = M10BMC_N6000_PR_REH_ADDR,
+ .pr_magic = M10BMC_N6000_PR_PROG_MAGIC,
+ .rsu_update_counter = M10BMC_N6000_STAGING_FLASH_COUNT,
+};
+
+static const struct intel_m10bmc_platform_info m10bmc_pmci_n6000 = {
+ .cells = m10bmc_pmci_n6000_bmc_subdevs,
+ .n_cells = ARRAY_SIZE(m10bmc_pmci_n6000_bmc_subdevs),
+ .csr_map = &m10bmc_n6000_csr_map,
+};
+
+static int m10bmc_pmci_probe(struct dfl_device *ddev)
+{
+ struct device *dev = &ddev->dev;
+ struct m10bmc_pmci_device *pmci;
+ struct indirect_ctx *ctx;
+ int ret;
+
+ pmci = devm_kzalloc(dev, sizeof(*pmci), GFP_KERNEL);
+ if (!pmci)
+ return -ENOMEM;
+
+ pmci->m10bmc.flash_bulk_ops = &m10bmc_pmci_flash_bulk_ops;
+ pmci->m10bmc.dev = dev;
+
+ pmci->base = devm_ioremap_resource(dev, &ddev->mmio_res);
+ if (IS_ERR(pmci->base))
+ return PTR_ERR(pmci->base);
+
+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ mutex_init(&pmci->flash_mutex);
+
+ ctx->base = pmci->base + M10BMC_N6000_INDIRECT_BASE;
+ ctx->dev = dev;
+ indirect_clear_cmd(ctx);
+ pmci->m10bmc.regmap = devm_regmap_init(dev, NULL, ctx, &m10bmc_pmci_regmap_config);
+
+ if (IS_ERR(pmci->m10bmc.regmap)) {
+ ret = PTR_ERR(pmci->m10bmc.regmap);
+ goto destroy_mutex;
+ }
+
+ ret = m10bmc_dev_init(&pmci->m10bmc, &m10bmc_pmci_n6000);
+ if (ret)
+ goto destroy_mutex;
+ return 0;
+
+destroy_mutex:
+ mutex_destroy(&pmci->flash_mutex);
+ return ret;
+}
+
+static void m10bmc_pmci_remove(struct dfl_device *ddev)
+{
+ struct intel_m10bmc *m10bmc = dev_get_drvdata(&ddev->dev);
+ struct m10bmc_pmci_device *pmci = container_of(m10bmc, struct m10bmc_pmci_device, m10bmc);
+
+ mutex_destroy(&pmci->flash_mutex);
+}
+
+#define FME_FEATURE_ID_M10BMC_PMCI 0x12
+
+static const struct dfl_device_id m10bmc_pmci_ids[] = {
+ { FME_ID, FME_FEATURE_ID_M10BMC_PMCI },
+ { }
+};
+MODULE_DEVICE_TABLE(dfl, m10bmc_pmci_ids);
+
+static struct dfl_driver m10bmc_pmci_driver = {
+ .drv = {
+ .name = "intel-m10-bmc",
+ .dev_groups = m10bmc_dev_groups,
+ },
+ .id_table = m10bmc_pmci_ids,
+ .probe = m10bmc_pmci_probe,
+ .remove = m10bmc_pmci_remove,
+};
+
+module_dfl_driver(m10bmc_pmci_driver);
+
+MODULE_DESCRIPTION("MAX10 BMC PMCI-based interface");
+MODULE_AUTHOR("Intel Corporation");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/intel-m10-bmc-spi.c b/drivers/mfd/intel-m10-bmc-spi.c
new file mode 100644
index 000000000000..957200e17fed
--- /dev/null
+++ b/drivers/mfd/intel-m10-bmc-spi.c
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Intel MAX 10 Board Management Controller chip
+ *
+ * Copyright (C) 2018-2020 Intel Corporation. All rights reserved.
+ */
+#include <linux/bitfield.h>
+#include <linux/dev_printk.h>
+#include <linux/init.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/intel-m10-bmc.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+
+static const struct regmap_range m10bmc_regmap_range[] = {
+ regmap_reg_range(M10BMC_N3000_LEGACY_BUILD_VER, M10BMC_N3000_LEGACY_BUILD_VER),
+ regmap_reg_range(M10BMC_N3000_SYS_BASE, M10BMC_N3000_SYS_END),
+ regmap_reg_range(M10BMC_N3000_FLASH_BASE, M10BMC_N3000_FLASH_END),
+};
+
+static const struct regmap_access_table m10bmc_access_table = {
+ .yes_ranges = m10bmc_regmap_range,
+ .n_yes_ranges = ARRAY_SIZE(m10bmc_regmap_range),
+};
+
+static struct regmap_config intel_m10bmc_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .wr_table = &m10bmc_access_table,
+ .rd_table = &m10bmc_access_table,
+ .max_register = M10BMC_N3000_MEM_END,
+};
+
+static int check_m10bmc_version(struct intel_m10bmc *ddata)
+{
+ unsigned int v;
+ int ret;
+
+ /*
+ * This check is to filter out the very old legacy BMC versions. In the
+ * old BMC chips, the BMC version info is stored in the old version
+ * register (M10BMC_N3000_LEGACY_BUILD_VER), so its read out value would have
+ * not been M10BMC_N3000_VER_LEGACY_INVALID (0xffffffff). But in new BMC
+ * chips that the driver supports, the value of this register should be
+ * M10BMC_N3000_VER_LEGACY_INVALID.
+ */
+ ret = m10bmc_raw_read(ddata, M10BMC_N3000_LEGACY_BUILD_VER, &v);
+ if (ret)
+ return -ENODEV;
+
+ if (v != M10BMC_N3000_VER_LEGACY_INVALID) {
+ dev_err(ddata->dev, "bad version M10BMC detected\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int intel_m10_bmc_spi_probe(struct spi_device *spi)
+{
+ const struct spi_device_id *id = spi_get_device_id(spi);
+ const struct intel_m10bmc_platform_info *info;
+ struct device *dev = &spi->dev;
+ struct intel_m10bmc *ddata;
+ int ret;
+
+ ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
+ if (!ddata)
+ return -ENOMEM;
+
+ info = (struct intel_m10bmc_platform_info *)id->driver_data;
+ ddata->dev = dev;
+
+ ddata->regmap = devm_regmap_init_spi_avmm(spi, &intel_m10bmc_regmap_config);
+ if (IS_ERR(ddata->regmap)) {
+ ret = PTR_ERR(ddata->regmap);
+ dev_err(dev, "Failed to allocate regmap: %d\n", ret);
+ return ret;
+ }
+
+ spi_set_drvdata(spi, ddata);
+
+ ret = check_m10bmc_version(ddata);
+ if (ret) {
+ dev_err(dev, "Failed to identify m10bmc hardware\n");
+ return ret;
+ }
+
+ return m10bmc_dev_init(ddata, info);
+}
+
+static const struct m10bmc_csr_map m10bmc_n3000_csr_map = {
+ .base = M10BMC_N3000_SYS_BASE,
+ .build_version = M10BMC_N3000_BUILD_VER,
+ .fw_version = NIOS2_N3000_FW_VERSION,
+ .mac_low = M10BMC_N3000_MAC_LOW,
+ .mac_high = M10BMC_N3000_MAC_HIGH,
+ .doorbell = M10BMC_N3000_DOORBELL,
+ .auth_result = M10BMC_N3000_AUTH_RESULT,
+ .bmc_prog_addr = M10BMC_N3000_BMC_PROG_ADDR,
+ .bmc_reh_addr = M10BMC_N3000_BMC_REH_ADDR,
+ .bmc_magic = M10BMC_N3000_BMC_PROG_MAGIC,
+ .sr_prog_addr = M10BMC_N3000_SR_PROG_ADDR,
+ .sr_reh_addr = M10BMC_N3000_SR_REH_ADDR,
+ .sr_magic = M10BMC_N3000_SR_PROG_MAGIC,
+ .pr_prog_addr = M10BMC_N3000_PR_PROG_ADDR,
+ .pr_reh_addr = M10BMC_N3000_PR_REH_ADDR,
+ .pr_magic = M10BMC_N3000_PR_PROG_MAGIC,
+ .rsu_update_counter = M10BMC_N3000_STAGING_FLASH_COUNT,
+};
+
+static struct mfd_cell m10bmc_d5005_subdevs[] = {
+ { .name = "d5005bmc-hwmon" },
+ { .name = "d5005bmc-sec-update" },
+};
+
+static struct mfd_cell m10bmc_pacn3000_subdevs[] = {
+ { .name = "n3000bmc-hwmon" },
+ { .name = "n3000bmc-retimer" },
+ { .name = "n3000bmc-sec-update" },
+};
+
+static struct mfd_cell m10bmc_n5010_subdevs[] = {
+ { .name = "n5010bmc-hwmon" },
+};
+
+static const struct intel_m10bmc_platform_info m10bmc_spi_n3000 = {
+ .cells = m10bmc_pacn3000_subdevs,
+ .n_cells = ARRAY_SIZE(m10bmc_pacn3000_subdevs),
+ .csr_map = &m10bmc_n3000_csr_map,
+};
+
+static const struct intel_m10bmc_platform_info m10bmc_spi_d5005 = {
+ .cells = m10bmc_d5005_subdevs,
+ .n_cells = ARRAY_SIZE(m10bmc_d5005_subdevs),
+ .csr_map = &m10bmc_n3000_csr_map,
+};
+
+static const struct intel_m10bmc_platform_info m10bmc_spi_n5010 = {
+ .cells = m10bmc_n5010_subdevs,
+ .n_cells = ARRAY_SIZE(m10bmc_n5010_subdevs),
+ .csr_map = &m10bmc_n3000_csr_map,
+};
+
+static const struct spi_device_id m10bmc_spi_id[] = {
+ { "m10-n3000", (kernel_ulong_t)&m10bmc_spi_n3000 },
+ { "m10-d5005", (kernel_ulong_t)&m10bmc_spi_d5005 },
+ { "m10-n5010", (kernel_ulong_t)&m10bmc_spi_n5010 },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, m10bmc_spi_id);
+
+static struct spi_driver intel_m10bmc_spi_driver = {
+ .driver = {
+ .name = "intel-m10-bmc",
+ .dev_groups = m10bmc_dev_groups,
+ },
+ .probe = intel_m10_bmc_spi_probe,
+ .id_table = m10bmc_spi_id,
+};
+module_spi_driver(intel_m10bmc_spi_driver);
+
+MODULE_DESCRIPTION("Intel MAX 10 BMC SPI bus interface");
+MODULE_AUTHOR("Intel Corporation");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("spi:intel-m10-bmc");
diff --git a/drivers/mfd/intel-m10-bmc.c b/drivers/mfd/intel-m10-bmc.c
deleted file mode 100644
index 7e3319e5b22f..000000000000
--- a/drivers/mfd/intel-m10-bmc.c
+++ /dev/null
@@ -1,238 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Intel MAX 10 Board Management Controller chip
- *
- * Copyright (C) 2018-2020 Intel Corporation. All rights reserved.
- */
-#include <linux/bitfield.h>
-#include <linux/init.h>
-#include <linux/mfd/core.h>
-#include <linux/mfd/intel-m10-bmc.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/regmap.h>
-#include <linux/spi/spi.h>
-
-enum m10bmc_type {
- M10_N3000,
- M10_D5005,
- M10_N5010,
-};
-
-static struct mfd_cell m10bmc_d5005_subdevs[] = {
- { .name = "d5005bmc-hwmon" },
- { .name = "d5005bmc-sec-update" }
-};
-
-static struct mfd_cell m10bmc_pacn3000_subdevs[] = {
- { .name = "n3000bmc-hwmon" },
- { .name = "n3000bmc-retimer" },
- { .name = "n3000bmc-sec-update" },
-};
-
-static struct mfd_cell m10bmc_n5010_subdevs[] = {
- { .name = "n5010bmc-hwmon" },
-};
-
-static const struct regmap_range m10bmc_regmap_range[] = {
- regmap_reg_range(M10BMC_LEGACY_BUILD_VER, M10BMC_LEGACY_BUILD_VER),
- regmap_reg_range(M10BMC_SYS_BASE, M10BMC_SYS_END),
- regmap_reg_range(M10BMC_FLASH_BASE, M10BMC_FLASH_END),
-};
-
-static const struct regmap_access_table m10bmc_access_table = {
- .yes_ranges = m10bmc_regmap_range,
- .n_yes_ranges = ARRAY_SIZE(m10bmc_regmap_range),
-};
-
-static struct regmap_config intel_m10bmc_regmap_config = {
- .reg_bits = 32,
- .val_bits = 32,
- .reg_stride = 4,
- .wr_table = &m10bmc_access_table,
- .rd_table = &m10bmc_access_table,
- .max_register = M10BMC_MEM_END,
-};
-
-static ssize_t bmc_version_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct intel_m10bmc *ddata = dev_get_drvdata(dev);
- unsigned int val;
- int ret;
-
- ret = m10bmc_sys_read(ddata, M10BMC_BUILD_VER, &val);
- if (ret)
- return ret;
-
- return sprintf(buf, "0x%x\n", val);
-}
-static DEVICE_ATTR_RO(bmc_version);
-
-static ssize_t bmcfw_version_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct intel_m10bmc *ddata = dev_get_drvdata(dev);
- unsigned int val;
- int ret;
-
- ret = m10bmc_sys_read(ddata, NIOS2_FW_VERSION, &val);
- if (ret)
- return ret;
-
- return sprintf(buf, "0x%x\n", val);
-}
-static DEVICE_ATTR_RO(bmcfw_version);
-
-static ssize_t mac_address_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct intel_m10bmc *max10 = dev_get_drvdata(dev);
- unsigned int macaddr_low, macaddr_high;
- int ret;
-
- ret = m10bmc_sys_read(max10, M10BMC_MAC_LOW, &macaddr_low);
- if (ret)
- return ret;
-
- ret = m10bmc_sys_read(max10, M10BMC_MAC_HIGH, &macaddr_high);
- if (ret)
- return ret;
-
- return sysfs_emit(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n",
- (u8)FIELD_GET(M10BMC_MAC_BYTE1, macaddr_low),
- (u8)FIELD_GET(M10BMC_MAC_BYTE2, macaddr_low),
- (u8)FIELD_GET(M10BMC_MAC_BYTE3, macaddr_low),
- (u8)FIELD_GET(M10BMC_MAC_BYTE4, macaddr_low),
- (u8)FIELD_GET(M10BMC_MAC_BYTE5, macaddr_high),
- (u8)FIELD_GET(M10BMC_MAC_BYTE6, macaddr_high));
-}
-static DEVICE_ATTR_RO(mac_address);
-
-static ssize_t mac_count_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct intel_m10bmc *max10 = dev_get_drvdata(dev);
- unsigned int macaddr_high;
- int ret;
-
- ret = m10bmc_sys_read(max10, M10BMC_MAC_HIGH, &macaddr_high);
- if (ret)
- return ret;
-
- return sysfs_emit(buf, "%u\n",
- (u8)FIELD_GET(M10BMC_MAC_COUNT, macaddr_high));
-}
-static DEVICE_ATTR_RO(mac_count);
-
-static struct attribute *m10bmc_attrs[] = {
- &dev_attr_bmc_version.attr,
- &dev_attr_bmcfw_version.attr,
- &dev_attr_mac_address.attr,
- &dev_attr_mac_count.attr,
- NULL,
-};
-ATTRIBUTE_GROUPS(m10bmc);
-
-static int check_m10bmc_version(struct intel_m10bmc *ddata)
-{
- unsigned int v;
- int ret;
-
- /*
- * This check is to filter out the very old legacy BMC versions. In the
- * old BMC chips, the BMC version info is stored in the old version
- * register (M10BMC_LEGACY_BUILD_VER), so its read out value would have
- * not been M10BMC_VER_LEGACY_INVALID (0xffffffff). But in new BMC
- * chips that the driver supports, the value of this register should be
- * M10BMC_VER_LEGACY_INVALID.
- */
- ret = m10bmc_raw_read(ddata, M10BMC_LEGACY_BUILD_VER, &v);
- if (ret)
- return -ENODEV;
-
- if (v != M10BMC_VER_LEGACY_INVALID) {
- dev_err(ddata->dev, "bad version M10BMC detected\n");
- return -ENODEV;
- }
-
- return 0;
-}
-
-static int intel_m10_bmc_spi_probe(struct spi_device *spi)
-{
- const struct spi_device_id *id = spi_get_device_id(spi);
- struct device *dev = &spi->dev;
- struct mfd_cell *cells;
- struct intel_m10bmc *ddata;
- int ret, n_cell;
-
- ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
- if (!ddata)
- return -ENOMEM;
-
- ddata->dev = dev;
-
- ddata->regmap =
- devm_regmap_init_spi_avmm(spi, &intel_m10bmc_regmap_config);
- if (IS_ERR(ddata->regmap)) {
- ret = PTR_ERR(ddata->regmap);
- dev_err(dev, "Failed to allocate regmap: %d\n", ret);
- return ret;
- }
-
- spi_set_drvdata(spi, ddata);
-
- ret = check_m10bmc_version(ddata);
- if (ret) {
- dev_err(dev, "Failed to identify m10bmc hardware\n");
- return ret;
- }
-
- switch (id->driver_data) {
- case M10_N3000:
- cells = m10bmc_pacn3000_subdevs;
- n_cell = ARRAY_SIZE(m10bmc_pacn3000_subdevs);
- break;
- case M10_D5005:
- cells = m10bmc_d5005_subdevs;
- n_cell = ARRAY_SIZE(m10bmc_d5005_subdevs);
- break;
- case M10_N5010:
- cells = m10bmc_n5010_subdevs;
- n_cell = ARRAY_SIZE(m10bmc_n5010_subdevs);
- break;
- default:
- return -ENODEV;
- }
-
- ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, cells, n_cell,
- NULL, 0, NULL);
- if (ret)
- dev_err(dev, "Failed to register sub-devices: %d\n", ret);
-
- return ret;
-}
-
-static const struct spi_device_id m10bmc_spi_id[] = {
- { "m10-n3000", M10_N3000 },
- { "m10-d5005", M10_D5005 },
- { "m10-n5010", M10_N5010 },
- { }
-};
-MODULE_DEVICE_TABLE(spi, m10bmc_spi_id);
-
-static struct spi_driver intel_m10bmc_spi_driver = {
- .driver = {
- .name = "intel-m10-bmc",
- .dev_groups = m10bmc_groups,
- },
- .probe = intel_m10_bmc_spi_probe,
- .id_table = m10bmc_spi_id,
-};
-module_spi_driver(intel_m10bmc_spi_driver);
-
-MODULE_DESCRIPTION("Intel MAX 10 BMC Device Driver");
-MODULE_AUTHOR("Intel Corporation");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("spi:intel-m10-bmc");
diff --git a/drivers/mfd/intel_soc_pmic_chtwc.c b/drivers/mfd/intel_soc_pmic_chtwc.c
index 9216f0d34206..d53dae255490 100644
--- a/drivers/mfd/intel_soc_pmic_chtwc.c
+++ b/drivers/mfd/intel_soc_pmic_chtwc.c
@@ -165,6 +165,14 @@ static const struct dmi_system_id cht_wc_model_dmi_ids[] = {
/* Non exact match to match all versions */
DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X9"),
},
+ }, {
+ /* Lenovo Yoga Tab 3 Pro YT3-X90F */
+ .driver_data = (void *)(long)INTEL_CHT_WC_LENOVO_YT3_X90,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "Blade3-10A-001"),
+ },
},
{ }
};
diff --git a/drivers/mfd/kempld-core.c b/drivers/mfd/kempld-core.c
index bb26241c73bd..33c6cfe9fe42 100644
--- a/drivers/mfd/kempld-core.c
+++ b/drivers/mfd/kempld-core.c
@@ -349,7 +349,7 @@ static ssize_t pld_version_show(struct device *dev,
{
struct kempld_device_data *pld = dev_get_drvdata(dev);
- return scnprintf(buf, PAGE_SIZE, "%s\n", pld->info.version);
+ return sysfs_emit(buf, "%s\n", pld->info.version);
}
static ssize_t pld_specification_show(struct device *dev,
@@ -357,8 +357,7 @@ static ssize_t pld_specification_show(struct device *dev,
{
struct kempld_device_data *pld = dev_get_drvdata(dev);
- return scnprintf(buf, PAGE_SIZE, "%d.%d\n", pld->info.spec_major,
- pld->info.spec_minor);
+ return sysfs_emit(buf, "%d.%d\n", pld->info.spec_major, pld->info.spec_minor);
}
static ssize_t pld_type_show(struct device *dev,
@@ -366,7 +365,7 @@ static ssize_t pld_type_show(struct device *dev,
{
struct kempld_device_data *pld = dev_get_drvdata(dev);
- return scnprintf(buf, PAGE_SIZE, "%s\n", kempld_get_type_string(pld));
+ return sysfs_emit(buf, "%s\n", kempld_get_type_string(pld));
}
static DEVICE_ATTR_RO(pld_version);
diff --git a/drivers/mfd/lm3533-core.c b/drivers/mfd/lm3533-core.c
index 74a553329416..946f94f3a3c3 100644
--- a/drivers/mfd/lm3533-core.c
+++ b/drivers/mfd/lm3533-core.c
@@ -286,7 +286,7 @@ static ssize_t show_output(struct device *dev,
val = (val & mask) >> shift;
- return scnprintf(buf, PAGE_SIZE, "%u\n", val);
+ return sysfs_emit(buf, "%u\n", val);
}
static ssize_t store_output(struct device *dev,
diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c
index eb3f061c8ee6..0246bbe80354 100644
--- a/drivers/mfd/max8925-core.c
+++ b/drivers/mfd/max8925-core.c
@@ -469,12 +469,6 @@ static struct max8925_irq_data max8925_irqs[] = {
},
};
-static inline struct max8925_irq_data *irq_to_max8925(struct max8925_chip *chip,
- int irq)
-{
- return &max8925_irqs[irq - chip->irq_base];
-}
-
static irqreturn_t max8925_irq(int irq, void *data)
{
struct max8925_chip *chip = data;
diff --git a/drivers/mfd/ntxec.c b/drivers/mfd/ntxec.c
index e16a7a82a929..b02785b10d48 100644
--- a/drivers/mfd/ntxec.c
+++ b/drivers/mfd/ntxec.c
@@ -175,6 +175,7 @@ static int ntxec_probe(struct i2c_client *client)
/* Bail out if we encounter an unknown firmware version */
switch (version) {
case NTXEC_VERSION_KOBO_AURA:
+ case NTXEC_VERSION_TOLINO_VISION:
subdevs = ntxec_subdev;
n_subdevs = ARRAY_SIZE(ntxec_subdev);
break;
diff --git a/drivers/mfd/ocelot-core.c b/drivers/mfd/ocelot-core.c
index b0ff05c1759f..e1772ff00cad 100644
--- a/drivers/mfd/ocelot-core.c
+++ b/drivers/mfd/ocelot-core.c
@@ -177,7 +177,7 @@ static const struct mfd_cell vsc7512_devs[] = {
.num_resources = ARRAY_SIZE(vsc7512_miim1_resources),
.resources = vsc7512_miim1_resources,
}, {
- .name = "ocelot-switch",
+ .name = "ocelot-ext-switch",
.of_compatible = "mscc,vsc7512-switch",
.num_resources = ARRAY_SIZE(vsc7512_switch_resources),
.resources = vsc7512_switch_resources,
diff --git a/drivers/mfd/pcf50633-adc.c b/drivers/mfd/pcf50633-adc.c
index 5cd653e61512..191b1bc6141c 100644
--- a/drivers/mfd/pcf50633-adc.c
+++ b/drivers/mfd/pcf50633-adc.c
@@ -136,6 +136,7 @@ int pcf50633_adc_async_read(struct pcf50633 *pcf, int mux, int avg,
void *callback_param)
{
struct pcf50633_adc_request *req;
+ int ret;
/* req is freed when the result is ready, in interrupt handler */
req = kmalloc(sizeof(*req), GFP_KERNEL);
@@ -147,7 +148,11 @@ int pcf50633_adc_async_read(struct pcf50633 *pcf, int mux, int avg,
req->callback = callback;
req->callback_param = callback_param;
- return adc_enqueue_request(pcf, req);
+ ret = adc_enqueue_request(pcf, req);
+ if (ret)
+ kfree(req);
+
+ return ret;
}
EXPORT_SYMBOL_GPL(pcf50633_adc_async_read);
diff --git a/drivers/mfd/qcom-pm8xxx.c b/drivers/mfd/qcom-pm8xxx.c
index 601106580e2e..9a948df8c28d 100644
--- a/drivers/mfd/qcom-pm8xxx.c
+++ b/drivers/mfd/qcom-pm8xxx.c
@@ -510,7 +510,6 @@ static int pm8xxx_probe(struct platform_device *pdev)
struct regmap *regmap;
int irq, rc;
unsigned int val;
- u32 rev;
struct pm_irq_chip *chip;
data = of_device_get_match_data(&pdev->dev);
@@ -535,7 +534,6 @@ static int pm8xxx_probe(struct platform_device *pdev)
return rc;
}
pr_info("PMIC revision 1: %02X\n", val);
- rev = val;
/* Read PMIC chip revision 2 */
rc = regmap_read(regmap, REG_HWREV_2, &val);
@@ -545,7 +543,6 @@ static int pm8xxx_probe(struct platform_device *pdev)
return rc;
}
pr_info("PMIC revision 2: %02X\n", val);
- rev |= val << BITS_PER_BYTE;
chip = devm_kzalloc(&pdev->dev,
struct_size(chip, config, data->num_irqs),
diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c
index f44fc3f080a8..0f22ef61e817 100644
--- a/drivers/mfd/rk808.c
+++ b/drivers/mfd/rk808.c
@@ -189,6 +189,7 @@ static const struct mfd_cell rk817s[] = {
};
static const struct mfd_cell rk818s[] = {
+ { .name = "rk808-clkout", .id = PLATFORM_DEVID_NONE, },
{ .name = "rk808-regulator", .id = PLATFORM_DEVID_NONE, },
{
.name = "rk808-rtc",
diff --git a/drivers/mfd/simple-mfd-i2c.c b/drivers/mfd/simple-mfd-i2c.c
index f4c8fc3ee463..e31f13fd6a79 100644
--- a/drivers/mfd/simple-mfd-i2c.c
+++ b/drivers/mfd/simple-mfd-i2c.c
@@ -48,7 +48,7 @@ static int simple_mfd_i2c_probe(struct i2c_client *i2c)
if (IS_ERR(regmap))
return PTR_ERR(regmap);
- /* If no MFD cells are spedified, use register the DT child nodes instead */
+ /* If no MFD cells are specified, register using the DT child nodes instead */
if (!simple_mfd_data || !simple_mfd_data->mfd_cell)
return devm_of_platform_populate(&i2c->dev);
diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c
index bdb2ce7ff03b..57b29c325131 100644
--- a/drivers/mfd/syscon.c
+++ b/drivers/mfd/syscon.c
@@ -20,6 +20,7 @@
#include <linux/platform_data/syscon.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
+#include <linux/reset.h>
#include <linux/mfd/syscon.h>
#include <linux/slab.h>
@@ -31,6 +32,7 @@ static LIST_HEAD(syscon_list);
struct syscon {
struct device_node *np;
struct regmap *regmap;
+ struct reset_control *reset;
struct list_head list;
};
@@ -40,7 +42,7 @@ static const struct regmap_config syscon_regmap_config = {
.reg_stride = 4,
};
-static struct syscon *of_syscon_register(struct device_node *np, bool check_clk)
+static struct syscon *of_syscon_register(struct device_node *np, bool check_res)
{
struct clk *clk;
struct syscon *syscon;
@@ -50,6 +52,7 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_clk)
int ret;
struct regmap_config syscon_config = syscon_regmap_config;
struct resource res;
+ struct reset_control *reset;
syscon = kzalloc(sizeof(*syscon), GFP_KERNEL);
if (!syscon)
@@ -114,7 +117,7 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_clk)
goto err_regmap;
}
- if (check_clk) {
+ if (check_res) {
clk = of_clk_get(np, 0);
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
@@ -124,8 +127,18 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_clk)
} else {
ret = regmap_mmio_attach_clk(regmap, clk);
if (ret)
- goto err_attach;
+ goto err_attach_clk;
}
+
+ reset = of_reset_control_get_optional_exclusive(np, NULL);
+ if (IS_ERR(reset)) {
+ ret = PTR_ERR(reset);
+ goto err_attach_clk;
+ }
+
+ ret = reset_control_deassert(reset);
+ if (ret)
+ goto err_reset;
}
syscon->regmap = regmap;
@@ -137,7 +150,9 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_clk)
return syscon;
-err_attach:
+err_reset:
+ reset_control_put(reset);
+err_attach_clk:
if (!IS_ERR(clk))
clk_put(clk);
err_clk:
@@ -150,7 +165,7 @@ err_map:
}
static struct regmap *device_node_get_regmap(struct device_node *np,
- bool check_clk)
+ bool check_res)
{
struct syscon *entry, *syscon = NULL;
@@ -165,7 +180,7 @@ static struct regmap *device_node_get_regmap(struct device_node *np,
spin_unlock(&syscon_list_slock);
if (!syscon)
- syscon = of_syscon_register(np, check_clk);
+ syscon = of_syscon_register(np, check_res);
if (IS_ERR(syscon))
return ERR_CAST(syscon);
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 62be2326c9b2..e2d9a93be43b 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -110,8 +110,8 @@
#define TWL6030_BASEADD_PWM 0x00BA
#define TWL6030_BASEADD_GASGAUGE 0x00C0
#define TWL6030_BASEADD_PIH 0x00D0
-#define TWL6030_BASEADD_CHARGER 0x00E0
#define TWL6032_BASEADD_CHARGER 0x00DA
+#define TWL6030_BASEADD_CHARGER 0x00E0
#define TWL6030_BASEADD_LED 0x00F4
/* subchip/slave 2 0x4A - DFT */
@@ -353,6 +353,9 @@ static struct twl_mapping twl6030_map[] = {
{ 2, TWL6030_BASEADD_ZERO },
{ 1, TWL6030_BASEADD_GPADC_CTRL },
{ 1, TWL6030_BASEADD_GASGAUGE },
+
+ /* TWL6032 specific charger registers */
+ { 1, TWL6032_BASEADD_CHARGER },
};
static const struct regmap_config twl6030_regmap_config[3] = {
@@ -803,10 +806,6 @@ twl_probe(struct i2c_client *client)
if ((id->driver_data) & TWL6030_CLASS) {
twl_priv->twl_id = TWL6030_CLASS_ID;
twl_priv->twl_map = &twl6030_map[0];
- /* The charger base address is different in twl6032 */
- if ((id->driver_data) & TWL6032_SUBCLASS)
- twl_priv->twl_map[TWL_MODULE_MAIN_CHARGE].base =
- TWL6032_BASEADD_CHARGER;
twl_regmap_config = twl6030_regmap_config;
} else {
twl_priv->twl_id = TWL4030_CLASS_ID;
diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c
index 6b36932263ba..e35b0f788c50 100644
--- a/drivers/mfd/twl4030-power.c
+++ b/drivers/mfd/twl4030-power.c
@@ -953,18 +953,12 @@ relock:
return err;
}
-static int twl4030_power_remove(struct platform_device *pdev)
-{
- return 0;
-}
-
static struct platform_driver twl4030_power_driver = {
.driver = {
.name = "twl4030_power",
.of_match_table = of_match_ptr(twl4030_power_of_match),
},
.probe = twl4030_power_probe,
- .remove = twl4030_power_remove,
};
module_platform_driver(twl4030_power_driver);
diff --git a/drivers/mfd/wm97xx-core.c b/drivers/mfd/wm97xx-core.c
index 9a2331eb1bfa..663acbb1854c 100644
--- a/drivers/mfd/wm97xx-core.c
+++ b/drivers/mfd/wm97xx-core.c
@@ -319,13 +319,11 @@ err_free_compat:
return ret;
}
-static int wm97xx_ac97_remove(struct ac97_codec_device *adev)
+static void wm97xx_ac97_remove(struct ac97_codec_device *adev)
{
struct wm97xx_priv *wm97xx = ac97_get_drvdata(adev);
snd_ac97_compat_release(wm97xx->ac97);
-
- return 0;
}
static const struct ac97_id wm97xx_ac97_ids[] = {
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 9947b7892bd5..433aa4197785 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -518,6 +518,26 @@ config VCPU_STALL_DETECTOR
If you do not intend to run this kernel as a guest, say N.
+config TMR_MANAGER
+ tristate "Select TMR Manager"
+ depends on MICROBLAZE && MB_MANAGER
+ help
+ This option enables the driver developed for TMR Manager.
+ The Triple Modular Redundancy(TMR) manager provides support for
+ fault detection.
+
+ Say N here unless you know what you are doing.
+
+config TMR_INJECT
+ tristate "Select TMR Inject"
+ depends on TMR_MANAGER && FAULT_INJECTION_DEBUG_FS
+ help
+ This option enables the driver developed for TMR Inject.
+ The Triple Modular Redundancy(TMR) Inject provides
+ fault injection.
+
+ Say N here unless you know what you are doing.
+
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"
@@ -532,7 +552,6 @@ source "drivers/misc/cxl/Kconfig"
source "drivers/misc/ocxl/Kconfig"
source "drivers/misc/bcm-vk/Kconfig"
source "drivers/misc/cardreader/Kconfig"
-source "drivers/misc/habanalabs/Kconfig"
source "drivers/misc/uacce/Kconfig"
source "drivers/misc/pvpanic/Kconfig"
source "drivers/misc/mchp_pci1xxxx/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 87b54a4a4422..56de43943cd5 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -56,7 +56,6 @@ obj-$(CONFIG_OCXL) += ocxl/
obj-$(CONFIG_BCM_VK) += bcm-vk/
obj-y += cardreader/
obj-$(CONFIG_PVPANIC) += pvpanic/
-obj-$(CONFIG_HABANA_AI) += habanalabs/
obj-$(CONFIG_UACCE) += uacce/
obj-$(CONFIG_XILINX_SDFEC) += xilinx_sdfec.o
obj-$(CONFIG_HISI_HIKEY_USB) += hisi_hikey_usb.o
@@ -64,3 +63,5 @@ obj-$(CONFIG_HI6421V600_IRQ) += hi6421v600-irq.o
obj-$(CONFIG_OPEN_DICE) += open-dice.o
obj-$(CONFIG_GP_PCI1XXXX) += mchp_pci1xxxx/
obj-$(CONFIG_VCPU_STALL_DETECTOR) += vcpu_stall_detector.o
+obj-$(CONFIG_TMR_MANAGER) += xilinx_tmr_manager.o
+obj-$(CONFIG_TMR_INJECT) += xilinx_tmr_inject.o
diff --git a/drivers/misc/cxl/context.c b/drivers/misc/cxl/context.c
index acaa44809c58..76b5ea66dfa1 100644
--- a/drivers/misc/cxl/context.c
+++ b/drivers/misc/cxl/context.c
@@ -220,7 +220,7 @@ int cxl_context_iomap(struct cxl_context *ctx, struct vm_area_struct *vma)
pr_devel("%s: mmio physical: %llx pe: %i master:%i\n", __func__,
ctx->psn_phys, ctx->pe , ctx->master);
- vma->vm_flags |= VM_IO | VM_PFNMAP;
+ vm_flags_set(vma, VM_IO | VM_PFNMAP);
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
vma->vm_ops = &cxl_mmap_vmops;
return 0;
diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c
index bdffc6543f6f..65d49a6de1a7 100644
--- a/drivers/misc/eeprom/at25.c
+++ b/drivers/misc/eeprom/at25.c
@@ -437,12 +437,6 @@ static int at25_probe(struct spi_device *spi)
struct spi_eeprom *pdata;
bool is_fram;
- err = device_property_match_string(&spi->dev, "compatible", "cypress,fm25");
- if (err >= 0)
- is_fram = true;
- else
- is_fram = false;
-
/*
* Ping the chip ... the status register is pretty portable,
* unlike probing manufacturer IDs. We do expect that system
@@ -462,6 +456,8 @@ static int at25_probe(struct spi_device *spi)
at25->spi = spi;
spi_set_drvdata(spi, at25);
+ is_fram = fwnode_device_is_compatible(dev_fwnode(&spi->dev), "cypress,fm25");
+
/* Chip description */
pdata = dev_get_platdata(&spi->dev);
if (pdata) {
diff --git a/drivers/misc/eeprom/idt_89hpesx.c b/drivers/misc/eeprom/idt_89hpesx.c
index 4e07ee9cb500..7075d0b37881 100644
--- a/drivers/misc/eeprom/idt_89hpesx.c
+++ b/drivers/misc/eeprom/idt_89hpesx.c
@@ -1566,12 +1566,20 @@ static struct i2c_driver idt_driver = {
*/
static int __init idt_init(void)
{
+ int ret;
+
/* Create Debugfs directory first */
if (debugfs_initialized())
csr_dbgdir = debugfs_create_dir("idt_csr", NULL);
/* Add new i2c-device driver */
- return i2c_add_driver(&idt_driver);
+ ret = i2c_add_driver(&idt_driver);
+ if (ret) {
+ debugfs_remove_recursive(csr_dbgdir);
+ return ret;
+ }
+
+ return 0;
}
module_init(idt_init);
diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c
index 1b010d9267c9..4ba966529458 100644
--- a/drivers/misc/enclosure.c
+++ b/drivers/misc/enclosure.c
@@ -32,7 +32,7 @@ static struct class enclosure_class;
* found. @start can be used as a starting point to obtain multiple
* enclosures per parent (should begin with NULL and then be set to
* each returned enclosure device). Obtains a reference to the
- * enclosure class device which must be released with device_put().
+ * enclosure class device which must be released with put_device().
* If @start is not NULL, a reference must be taken on it which is
* released before returning (this allows a loop through all
* enclosures to exit with only the reference on the enclosure of
diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index 5310606113fe..a701132638cf 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -18,7 +18,7 @@
#include <linux/rpmsg.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <uapi/misc/fastrpc.h>
#include <linux/of_reserved_mem.h>
@@ -2315,7 +2315,18 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
data->domain_id = domain_id;
data->rpdev = rpdev;
- return of_platform_populate(rdev->of_node, NULL, NULL, rdev);
+ err = of_platform_populate(rdev->of_node, NULL, NULL, rdev);
+ if (err)
+ goto populate_error;
+
+ return 0;
+
+populate_error:
+ if (data->fdevice)
+ misc_deregister(&data->fdevice->miscdev);
+ if (data->secure_fdevice)
+ misc_deregister(&data->secure_fdevice->miscdev);
+
fdev_error:
kfree(data);
return err;
diff --git a/drivers/misc/genwqe/card_utils.c b/drivers/misc/genwqe/card_utils.c
index 1167463f26fb..f778e11237a6 100644
--- a/drivers/misc/genwqe/card_utils.c
+++ b/drivers/misc/genwqe/card_utils.c
@@ -151,6 +151,9 @@ int genwqe_read_app_id(struct genwqe_dev *cd, char *app_name, int len)
return i;
}
+#define CRC32_POLYNOMIAL 0x20044009
+static u32 crc32_tab[256]; /* crc32 lookup table */
+
/**
* genwqe_init_crc32() - Prepare a lookup table for fast crc32 calculations
*
@@ -159,9 +162,6 @@ int genwqe_read_app_id(struct genwqe_dev *cd, char *app_name, int len)
*
* Genwqe's Polynomial = 0x20044009
*/
-#define CRC32_POLYNOMIAL 0x20044009
-static u32 crc32_tab[256]; /* crc32 lookup table */
-
void genwqe_init_crc32(void)
{
int i, j;
diff --git a/drivers/misc/habanalabs/include/gaudi2/arc/gaudi2_arc_common_packets.h b/drivers/misc/habanalabs/include/gaudi2/arc/gaudi2_arc_common_packets.h
deleted file mode 100644
index 2cf30c206ac6..000000000000
--- a/drivers/misc/habanalabs/include/gaudi2/arc/gaudi2_arc_common_packets.h
+++ /dev/null
@@ -1,213 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0
- *
- * Copyright (C) 2020 HabanaLabs Ltd.
- * All Rights Reserved.
- */
-
-#ifndef __GAUDI2_ARC_COMMON_PACKETS_H__
-#define __GAUDI2_ARC_COMMON_PACKETS_H__
-
-/*
- * CPU IDs for each ARC CPUs
- */
-
-#define CPU_ID_SCHED_ARC0 0 /* FARM_ARC0 */
-#define CPU_ID_SCHED_ARC1 1 /* FARM_ARC1 */
-#define CPU_ID_SCHED_ARC2 2 /* FARM_ARC2 */
-#define CPU_ID_SCHED_ARC3 3 /* FARM_ARC3 */
-/* Dcore1 MME Engine ARC instance used as scheduler */
-#define CPU_ID_SCHED_ARC4 4 /* DCORE1_MME0 */
-/* Dcore3 MME Engine ARC instance used as scheduler */
-#define CPU_ID_SCHED_ARC5 5 /* DCORE3_MME0 */
-
-#define CPU_ID_TPC_QMAN_ARC0 6 /* DCORE0_TPC0 */
-#define CPU_ID_TPC_QMAN_ARC1 7 /* DCORE0_TPC1 */
-#define CPU_ID_TPC_QMAN_ARC2 8 /* DCORE0_TPC2 */
-#define CPU_ID_TPC_QMAN_ARC3 9 /* DCORE0_TPC3 */
-#define CPU_ID_TPC_QMAN_ARC4 10 /* DCORE0_TPC4 */
-#define CPU_ID_TPC_QMAN_ARC5 11 /* DCORE0_TPC5 */
-#define CPU_ID_TPC_QMAN_ARC6 12 /* DCORE1_TPC0 */
-#define CPU_ID_TPC_QMAN_ARC7 13 /* DCORE1_TPC1 */
-#define CPU_ID_TPC_QMAN_ARC8 14 /* DCORE1_TPC2 */
-#define CPU_ID_TPC_QMAN_ARC9 15 /* DCORE1_TPC3 */
-#define CPU_ID_TPC_QMAN_ARC10 16 /* DCORE1_TPC4 */
-#define CPU_ID_TPC_QMAN_ARC11 17 /* DCORE1_TPC5 */
-#define CPU_ID_TPC_QMAN_ARC12 18 /* DCORE2_TPC0 */
-#define CPU_ID_TPC_QMAN_ARC13 19 /* DCORE2_TPC1 */
-#define CPU_ID_TPC_QMAN_ARC14 20 /* DCORE2_TPC2 */
-#define CPU_ID_TPC_QMAN_ARC15 21 /* DCORE2_TPC3 */
-#define CPU_ID_TPC_QMAN_ARC16 22 /* DCORE2_TPC4 */
-#define CPU_ID_TPC_QMAN_ARC17 23 /* DCORE2_TPC5 */
-#define CPU_ID_TPC_QMAN_ARC18 24 /* DCORE3_TPC0 */
-#define CPU_ID_TPC_QMAN_ARC19 25 /* DCORE3_TPC1 */
-#define CPU_ID_TPC_QMAN_ARC20 26 /* DCORE3_TPC2 */
-#define CPU_ID_TPC_QMAN_ARC21 27 /* DCORE3_TPC3 */
-#define CPU_ID_TPC_QMAN_ARC22 28 /* DCORE3_TPC4 */
-#define CPU_ID_TPC_QMAN_ARC23 29 /* DCORE3_TPC5 */
-#define CPU_ID_TPC_QMAN_ARC24 30 /* DCORE0_TPC6 - Never present */
-
-#define CPU_ID_MME_QMAN_ARC0 31 /* DCORE0_MME0 */
-#define CPU_ID_MME_QMAN_ARC1 32 /* DCORE2_MME0 */
-
-#define CPU_ID_EDMA_QMAN_ARC0 33 /* DCORE0_EDMA0 */
-#define CPU_ID_EDMA_QMAN_ARC1 34 /* DCORE0_EDMA1 */
-#define CPU_ID_EDMA_QMAN_ARC2 35 /* DCORE1_EDMA0 */
-#define CPU_ID_EDMA_QMAN_ARC3 36 /* DCORE1_EDMA1 */
-#define CPU_ID_EDMA_QMAN_ARC4 37 /* DCORE2_EDMA0 */
-#define CPU_ID_EDMA_QMAN_ARC5 38 /* DCORE2_EDMA1 */
-#define CPU_ID_EDMA_QMAN_ARC6 39 /* DCORE3_EDMA0 */
-#define CPU_ID_EDMA_QMAN_ARC7 40 /* DCORE3_EDMA1 */
-
-#define CPU_ID_PDMA_QMAN_ARC0 41 /* DCORE0_PDMA0 */
-#define CPU_ID_PDMA_QMAN_ARC1 42 /* DCORE0_PDMA1 */
-
-#define CPU_ID_ROT_QMAN_ARC0 43 /* ROT0 */
-#define CPU_ID_ROT_QMAN_ARC1 44 /* ROT1 */
-
-#define CPU_ID_NIC_QMAN_ARC0 45 /* NIC0_0 */
-#define CPU_ID_NIC_QMAN_ARC1 46 /* NIC0_1 */
-#define CPU_ID_NIC_QMAN_ARC2 47 /* NIC1_0 */
-#define CPU_ID_NIC_QMAN_ARC3 48 /* NIC1_1 */
-#define CPU_ID_NIC_QMAN_ARC4 49 /* NIC2_0 */
-#define CPU_ID_NIC_QMAN_ARC5 50 /* NIC2_1 */
-#define CPU_ID_NIC_QMAN_ARC6 51 /* NIC3_0 */
-#define CPU_ID_NIC_QMAN_ARC7 52 /* NIC3_1 */
-#define CPU_ID_NIC_QMAN_ARC8 53 /* NIC4_0 */
-#define CPU_ID_NIC_QMAN_ARC9 54 /* NIC4_1 */
-#define CPU_ID_NIC_QMAN_ARC10 55 /* NIC5_0 */
-#define CPU_ID_NIC_QMAN_ARC11 56 /* NIC5_1 */
-#define CPU_ID_NIC_QMAN_ARC12 57 /* NIC6_0 */
-#define CPU_ID_NIC_QMAN_ARC13 58 /* NIC6_1 */
-#define CPU_ID_NIC_QMAN_ARC14 59 /* NIC7_0 */
-#define CPU_ID_NIC_QMAN_ARC15 60 /* NIC7_1 */
-#define CPU_ID_NIC_QMAN_ARC16 61 /* NIC8_0 */
-#define CPU_ID_NIC_QMAN_ARC17 62 /* NIC8_1 */
-#define CPU_ID_NIC_QMAN_ARC18 63 /* NIC9_0 */
-#define CPU_ID_NIC_QMAN_ARC19 64 /* NIC9_1 */
-#define CPU_ID_NIC_QMAN_ARC20 65 /* NIC10_0 */
-#define CPU_ID_NIC_QMAN_ARC21 66 /* NIC10_1 */
-#define CPU_ID_NIC_QMAN_ARC22 67 /* NIC11_0 */
-#define CPU_ID_NIC_QMAN_ARC23 68 /* NIC11_1 */
-
-#define CPU_ID_MAX 69
-#define CPU_ID_SCHED_MAX 6
-
-#define CPU_ID_ALL 0xFE
-#define CPU_ID_INVALID 0xFF
-
-enum arc_regions_t {
- ARC_REGION0_UNSED = 0,
- /*
- * Extension registers
- * None
- */
- ARC_REGION1_SRAM = 1,
- /*
- * Extension registers
- * AUX_SRAM_LSB_ADDR
- * AUX_SRAM_MSB_ADDR
- * ARC Address: 0x1000_0000
- */
- ARC_REGION2_CFG = 2,
- /*
- * Extension registers
- * AUX_CFG_LSB_ADDR
- * AUX_CFG_MSB_ADDR
- * ARC Address: 0x2000_0000
- */
- ARC_REGION3_GENERAL = 3,
- /*
- * Extension registers
- * AUX_GENERAL_PURPOSE_LSB_ADDR_0
- * AUX_GENERAL_PURPOSE_MSB_ADDR_0
- * ARC Address: 0x3000_0000
- */
- ARC_REGION4_HBM0_FW = 4,
- /*
- * Extension registers
- * AUX_HBM0_LSB_ADDR
- * AUX_HBM0_MSB_ADDR
- * AUX_HBM0_OFFSET
- * ARC Address: 0x4000_0000
- */
- ARC_REGION5_HBM1_GC_DATA = 5,
- /*
- * Extension registers
- * AUX_HBM1_LSB_ADDR
- * AUX_HBM1_MSB_ADDR
- * AUX_HBM1_OFFSET
- * ARC Address: 0x5000_0000
- */
- ARC_REGION6_HBM2_GC_DATA = 6,
- /*
- * Extension registers
- * AUX_HBM2_LSB_ADDR
- * AUX_HBM2_MSB_ADDR
- * AUX_HBM2_OFFSET
- * ARC Address: 0x6000_0000
- */
- ARC_REGION7_HBM3_GC_DATA = 7,
- /*
- * Extension registers
- * AUX_HBM3_LSB_ADDR
- * AUX_HBM3_MSB_ADDR
- * AUX_HBM3_OFFSET
- * ARC Address: 0x7000_0000
- */
- ARC_REGION8_DCCM = 8,
- /*
- * Extension registers
- * None
- * ARC Address: 0x8000_0000
- */
- ARC_REGION9_PCIE = 9,
- /*
- * Extension registers
- * AUX_PCIE_LSB_ADDR
- * AUX_PCIE_MSB_ADDR
- * ARC Address: 0x9000_0000
- */
- ARC_REGION10_GENERAL = 10,
- /*
- * Extension registers
- * AUX_GENERAL_PURPOSE_LSB_ADDR_1
- * AUX_GENERAL_PURPOSE_MSB_ADDR_1
- * ARC Address: 0xA000_0000
- */
- ARC_REGION11_GENERAL = 11,
- /*
- * Extension registers
- * AUX_GENERAL_PURPOSE_LSB_ADDR_2
- * AUX_GENERAL_PURPOSE_MSB_ADDR_2
- * ARC Address: 0xB000_0000
- */
- ARC_REGION12_GENERAL = 12,
- /*
- * Extension registers
- * AUX_GENERAL_PURPOSE_LSB_ADDR_3
- * AUX_GENERAL_PURPOSE_MSB_ADDR_3
- * ARC Address: 0xC000_0000
- */
- ARC_REGION13_GENERAL = 13,
- /*
- * Extension registers
- * AUX_GENERAL_PURPOSE_LSB_ADDR_4
- * AUX_GENERAL_PURPOSE_MSB_ADDR_4
- * ARC Address: 0xD000_0000
- */
- ARC_REGION14_GENERAL = 14,
- /*
- * Extension registers
- * AUX_GENERAL_PURPOSE_LSB_ADDR_5
- * AUX_GENERAL_PURPOSE_MSB_ADDR_5
- * ARC Address: 0xE000_0000
- */
- ARC_REGION15_LBU = 15
- /*
- * Extension registers
- * None
- * ARC Address: 0xF000_0000
- */
-};
-
-#endif /* __GAUDI2_ARC_COMMON_PACKETS_H__ */
diff --git a/drivers/misc/isl29003.c b/drivers/misc/isl29003.c
index aeda2fa89e61..147b58f7968d 100644
--- a/drivers/misc/isl29003.c
+++ b/drivers/misc/isl29003.c
@@ -186,7 +186,7 @@ static ssize_t isl29003_show_range(struct device *dev,
{
struct i2c_client *client = to_i2c_client(dev);
- return sprintf(buf, "%i\n", isl29003_get_range(client));
+ return sysfs_emit(buf, "%i\n", isl29003_get_range(client));
}
static ssize_t isl29003_store_range(struct device *dev,
@@ -222,7 +222,7 @@ static ssize_t isl29003_show_resolution(struct device *dev,
{
struct i2c_client *client = to_i2c_client(dev);
- return sprintf(buf, "%d\n", isl29003_get_resolution(client));
+ return sysfs_emit(buf, "%d\n", isl29003_get_resolution(client));
}
static ssize_t isl29003_store_resolution(struct device *dev,
@@ -256,7 +256,7 @@ static ssize_t isl29003_show_mode(struct device *dev,
{
struct i2c_client *client = to_i2c_client(dev);
- return sprintf(buf, "%d\n", isl29003_get_mode(client));
+ return sysfs_emit(buf, "%d\n", isl29003_get_mode(client));
}
static ssize_t isl29003_store_mode(struct device *dev,
@@ -291,7 +291,7 @@ static ssize_t isl29003_show_power_state(struct device *dev,
{
struct i2c_client *client = to_i2c_client(dev);
- return sprintf(buf, "%d\n", isl29003_get_power_state(client));
+ return sysfs_emit(buf, "%d\n", isl29003_get_power_state(client));
}
static ssize_t isl29003_store_power_state(struct device *dev,
@@ -327,7 +327,7 @@ static ssize_t isl29003_show_lux(struct device *dev,
if (!isl29003_get_power_state(client))
return -EBUSY;
- return sprintf(buf, "%d\n", isl29003_get_adc_value(client));
+ return sysfs_emit(buf, "%d\n", isl29003_get_adc_value(client));
}
static DEVICE_ATTR(lux, S_IRUGO, isl29003_show_lux, NULL);
diff --git a/drivers/misc/mei/bus-fixup.c b/drivers/misc/mei/bus-fixup.c
index 6df7679d9739..211536109308 100644
--- a/drivers/misc/mei/bus-fixup.c
+++ b/drivers/misc/mei/bus-fixup.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * Copyright (c) 2013-2022, Intel Corporation. All rights reserved.
+ * Copyright (c) 2013-2023, Intel Corporation. All rights reserved.
* Intel Management Engine Interface (Intel MEI) Linux driver
*/
@@ -151,7 +151,7 @@ static int mei_fwver(struct mei_cl_device *cldev)
ret = __mei_cl_send(cldev->cl, (u8 *)&req, sizeof(req), 0,
MEI_CL_IO_TX_BLOCKING);
if (ret < 0) {
- dev_err(&cldev->dev, "Could not send ReqFWVersion cmd\n");
+ dev_info(&cldev->dev, "Could not send ReqFWVersion cmd ret = %d\n", ret);
return ret;
}
@@ -163,7 +163,7 @@ static int mei_fwver(struct mei_cl_device *cldev)
* Should be at least one version block,
* error out if nothing found
*/
- dev_err(&cldev->dev, "Could not read FW version\n");
+ dev_info(&cldev->dev, "Could not read FW version ret = %d\n", bytes_recv);
return -EIO;
}
@@ -220,15 +220,15 @@ static void mei_mkhi_fix(struct mei_cl_device *cldev)
if (cldev->bus->fw_f_fw_ver_supported) {
ret = mei_fwver(cldev);
if (ret < 0)
- dev_err(&cldev->dev, "FW version command failed %d\n",
- ret);
+ dev_info(&cldev->dev, "FW version command failed %d\n",
+ ret);
}
if (cldev->bus->hbm_f_os_supported) {
ret = mei_osver(cldev);
if (ret < 0)
- dev_err(&cldev->dev, "OS version command failed %d\n",
- ret);
+ dev_info(&cldev->dev, "OS version command failed %d\n",
+ ret);
}
mei_cldev_disable(cldev);
}
@@ -247,7 +247,7 @@ static void mei_gsc_mkhi_ver(struct mei_cl_device *cldev)
ret = mei_fwver(cldev);
if (ret < 0)
- dev_err(&cldev->dev, "FW version command failed %d\n", ret);
+ dev_info(&cldev->dev, "FW version command failed %d\n", ret);
mei_cldev_disable(cldev);
}
@@ -278,8 +278,8 @@ static void mei_gsc_mkhi_fix_ver(struct mei_cl_device *cldev)
ret = mei_fwver(cldev);
if (ret < 0)
- dev_err(&cldev->dev, "FW version command failed %d\n",
- ret);
+ dev_info(&cldev->dev, "FW version command failed %d\n",
+ ret);
out:
mei_cldev_disable(cldev);
}
@@ -380,7 +380,7 @@ static int mei_nfc_if_version(struct mei_cl *cl,
ret = __mei_cl_send(cl, (u8 *)&cmd, sizeof(cmd), 0,
MEI_CL_IO_TX_BLOCKING);
if (ret < 0) {
- dev_err(bus->dev, "Could not send IF version cmd\n");
+ dev_err(bus->dev, "Could not send IF version cmd ret = %d\n", ret);
return ret;
}
@@ -395,7 +395,7 @@ static int mei_nfc_if_version(struct mei_cl *cl,
bytes_recv = __mei_cl_recv(cl, (u8 *)reply, if_version_length, &vtag,
0, 0);
if (bytes_recv < 0 || (size_t)bytes_recv < if_version_length) {
- dev_err(bus->dev, "Could not read IF version\n");
+ dev_err(bus->dev, "Could not read IF version ret = %d\n", bytes_recv);
ret = -EIO;
goto err;
}
@@ -403,7 +403,7 @@ static int mei_nfc_if_version(struct mei_cl *cl,
memcpy(ver, reply->data, sizeof(*ver));
dev_info(bus->dev, "NFC MEI VERSION: IVN 0x%x Vendor ID 0x%x Type 0x%x\n",
- ver->fw_ivn, ver->vendor_id, ver->radio_type);
+ ver->fw_ivn, ver->vendor_id, ver->radio_type);
err:
kfree(reply);
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index a81b890c7ee6..5d7a68674d9b 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * Copyright (c) 2012-2019, Intel Corporation. All rights reserved.
+ * Copyright (c) 2012-2023, Intel Corporation. All rights reserved.
* Intel Management Engine Interface (Intel MEI) Linux driver
*/
@@ -1227,9 +1227,9 @@ ATTRIBUTE_GROUPS(mei_cldev);
*
* Return: 0 on success -ENOMEM on when add_uevent_var fails
*/
-static int mei_cl_device_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int mei_cl_device_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct mei_cl_device *cldev = to_mei_cl_device(dev);
+ const struct mei_cl_device *cldev = to_mei_cl_device(dev);
const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl);
u8 version = mei_me_cl_ver(cldev->me_cl);
@@ -1392,6 +1392,7 @@ static int mei_cl_bus_dev_add(struct mei_cl_device *cldev)
*/
static void mei_cl_bus_dev_stop(struct mei_cl_device *cldev)
{
+ cldev->do_match = 0;
if (cldev->is_added)
device_release_driver(&cldev->dev);
}
diff --git a/drivers/misc/mei/hdcp/mei_hdcp.c b/drivers/misc/mei/hdcp/mei_hdcp.c
index e889a8bd7ac8..e0dcd5c114db 100644
--- a/drivers/misc/mei/hdcp/mei_hdcp.c
+++ b/drivers/misc/mei/hdcp/mei_hdcp.c
@@ -859,8 +859,8 @@ static void mei_hdcp_remove(struct mei_cl_device *cldev)
dev_warn(&cldev->dev, "mei_cldev_disable() failed\n");
}
-#define MEI_UUID_HDCP GUID_INIT(0xB638AB7E, 0x94E2, 0x4EA2, 0xA5, \
- 0x52, 0xD1, 0xC5, 0x4B, 0x62, 0x7F, 0x04)
+#define MEI_UUID_HDCP UUID_LE(0xB638AB7E, 0x94E2, 0x4EA2, 0xA5, \
+ 0x52, 0xD1, 0xC5, 0x4B, 0x62, 0x7F, 0x04)
static const struct mei_cl_device_id mei_hdcp_tbl[] = {
{ .uuid = MEI_UUID_HDCP, .version = MEI_CL_VERSION_ANY },
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 996b70a988be..895011b7a0bf 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -13,6 +13,11 @@
#include <linux/mei.h>
#include <linux/mei_cl_bus.h>
+static inline int uuid_le_cmp(const uuid_le u1, const uuid_le u2)
+{
+ return memcmp(&u1, &u2, sizeof(uuid_le));
+}
+
#include "hw.h"
#include "hbm.h"
diff --git a/drivers/misc/mei/pxp/mei_pxp.c b/drivers/misc/mei/pxp/mei_pxp.c
index 8dd09b1722eb..7ee1fa7b1cb3 100644
--- a/drivers/misc/mei/pxp/mei_pxp.c
+++ b/drivers/misc/mei/pxp/mei_pxp.c
@@ -238,8 +238,8 @@ static void mei_pxp_remove(struct mei_cl_device *cldev)
}
/* fbf6fcf1-96cf-4e2e-a6a6-1bab8cbe36b1 : PAVP GUID*/
-#define MEI_GUID_PXP GUID_INIT(0xfbf6fcf1, 0x96cf, 0x4e2e, 0xA6, \
- 0xa6, 0x1b, 0xab, 0x8c, 0xbe, 0x36, 0xb1)
+#define MEI_GUID_PXP UUID_LE(0xfbf6fcf1, 0x96cf, 0x4e2e, 0xA6, \
+ 0xa6, 0x1b, 0xab, 0x8c, 0xbe, 0x36, 0xb1)
static struct mei_cl_device_id mei_pxp_tbl[] = {
{ .uuid = MEI_GUID_PXP, .version = MEI_CL_VERSION_ANY },
diff --git a/drivers/misc/ocxl/context.c b/drivers/misc/ocxl/context.c
index 9eb0d93b01c6..7f83116ae11a 100644
--- a/drivers/misc/ocxl/context.c
+++ b/drivers/misc/ocxl/context.c
@@ -180,7 +180,7 @@ static int check_mmap_afu_irq(struct ocxl_context *ctx,
if ((vma->vm_flags & VM_READ) || (vma->vm_flags & VM_EXEC) ||
!(vma->vm_flags & VM_WRITE))
return -EINVAL;
- vma->vm_flags &= ~(VM_MAYREAD | VM_MAYEXEC);
+ vm_flags_clear(vma, VM_MAYREAD | VM_MAYEXEC);
return 0;
}
@@ -204,7 +204,7 @@ int ocxl_context_mmap(struct ocxl_context *ctx, struct vm_area_struct *vma)
if (rc)
return rc;
- vma->vm_flags |= VM_IO | VM_PFNMAP;
+ vm_flags_set(vma, VM_IO | VM_PFNMAP);
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
vma->vm_ops = &ocxl_vmops;
return 0;
diff --git a/drivers/misc/ocxl/sysfs.c b/drivers/misc/ocxl/sysfs.c
index 25c78df8055d..405180d47d9b 100644
--- a/drivers/misc/ocxl/sysfs.c
+++ b/drivers/misc/ocxl/sysfs.c
@@ -134,7 +134,7 @@ static int global_mmio_mmap(struct file *filp, struct kobject *kobj,
(afu->config.global_mmio_size >> PAGE_SHIFT))
return -EINVAL;
- vma->vm_flags |= VM_IO | VM_PFNMAP;
+ vm_flags_set(vma, VM_IO | VM_PFNMAP);
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
vma->vm_ops = &global_mmio_vmops;
vma->vm_private_data = afu;
diff --git a/drivers/misc/open-dice.c b/drivers/misc/open-dice.c
index c61be3404c6f..8aea2d070a40 100644
--- a/drivers/misc/open-dice.c
+++ b/drivers/misc/open-dice.c
@@ -90,19 +90,17 @@ static int open_dice_mmap(struct file *filp, struct vm_area_struct *vma)
{
struct open_dice_drvdata *drvdata = to_open_dice_drvdata(filp);
- /* Do not allow userspace to modify the underlying data. */
- if ((vma->vm_flags & VM_WRITE) && (vma->vm_flags & VM_SHARED))
- return -EPERM;
-
- /* Ensure userspace cannot acquire VM_WRITE + VM_SHARED later. */
- if (vma->vm_flags & VM_WRITE)
- vma->vm_flags &= ~VM_MAYSHARE;
- else if (vma->vm_flags & VM_SHARED)
- vma->vm_flags &= ~VM_MAYWRITE;
+ if (vma->vm_flags & VM_MAYSHARE) {
+ /* Do not allow userspace to modify the underlying data. */
+ if (vma->vm_flags & VM_WRITE)
+ return -EPERM;
+ /* Ensure userspace cannot acquire VM_WRITE later. */
+ vm_flags_clear(vma, VM_MAYWRITE);
+ }
/* Create write-combine mapping so all clients observe a wipe. */
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
- vma->vm_flags |= VM_DONTCOPY | VM_DONTDUMP;
+ vm_flags_set(vma, VM_DONTCOPY | VM_DONTDUMP);
return vm_iomap_memory(vma, drvdata->rmem->base, drvdata->rmem->size);
}
diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
index 11530b4ec389..a7244de081ec 100644
--- a/drivers/misc/pci_endpoint_test.c
+++ b/drivers/misc/pci_endpoint_test.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/**
+/*
* Host side test driver to test endpoint functionality
*
* Copyright (C) 2017 Texas Instruments
@@ -72,6 +72,7 @@
#define PCI_DEVICE_ID_TI_J7200 0xb00f
#define PCI_DEVICE_ID_TI_AM64 0xb010
#define PCI_DEVICE_ID_LS1088A 0x80c0
+#define PCI_DEVICE_ID_IMX8 0x0808
#define is_am654_pci_dev(pdev) \
((pdev)->device == PCI_DEVICE_ID_TI_AM654)
@@ -980,6 +981,7 @@ static const struct pci_device_id pci_endpoint_test_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0x81c0),
.driver_data = (kernel_ulong_t)&default_data,
},
+ { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_IMX8),},
{ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_LS1088A),
.driver_data = (kernel_ulong_t)&default_data,
},
diff --git a/drivers/misc/sgi-gru/grufile.c b/drivers/misc/sgi-gru/grufile.c
index 7ffcfc0bb587..a3d659c11cc4 100644
--- a/drivers/misc/sgi-gru/grufile.c
+++ b/drivers/misc/sgi-gru/grufile.c
@@ -101,8 +101,8 @@ static int gru_file_mmap(struct file *file, struct vm_area_struct *vma)
vma->vm_end & (GRU_GSEG_PAGESIZE - 1))
return -EINVAL;
- vma->vm_flags |= VM_IO | VM_PFNMAP | VM_LOCKED |
- VM_DONTCOPY | VM_DONTEXPAND | VM_DONTDUMP;
+ vm_flags_set(vma, VM_IO | VM_PFNMAP | VM_LOCKED |
+ VM_DONTCOPY | VM_DONTEXPAND | VM_DONTDUMP);
vma->vm_page_prot = PAGE_SHARED;
vma->vm_ops = &gru_vm_ops;
diff --git a/drivers/misc/sgi-gru/grukservices.c b/drivers/misc/sgi-gru/grukservices.c
index fa1f5a632e7f..37e804bbb1f2 100644
--- a/drivers/misc/sgi-gru/grukservices.c
+++ b/drivers/misc/sgi-gru/grukservices.c
@@ -425,7 +425,7 @@ int gru_get_cb_exception_detail(void *cb,
static char *gru_get_cb_exception_detail_str(int ret, void *cb,
char *buf, int size)
{
- struct gru_control_block_status *gen = (void *)cb;
+ struct gru_control_block_status *gen = cb;
struct control_block_extended_exc_detail excdet;
if (ret > 0 && gen->istatus == CBS_EXCEPTION) {
@@ -452,7 +452,7 @@ static int gru_wait_idle_or_exception(struct gru_control_block_status *gen)
static int gru_retry_exception(void *cb)
{
- struct gru_control_block_status *gen = (void *)cb;
+ struct gru_control_block_status *gen = cb;
struct control_block_extended_exc_detail excdet;
int retry = EXCEPTION_RETRY_LIMIT;
@@ -475,7 +475,7 @@ static int gru_retry_exception(void *cb)
int gru_check_status_proc(void *cb)
{
- struct gru_control_block_status *gen = (void *)cb;
+ struct gru_control_block_status *gen = cb;
int ret;
ret = gen->istatus;
@@ -488,7 +488,7 @@ int gru_check_status_proc(void *cb)
int gru_wait_proc(void *cb)
{
- struct gru_control_block_status *gen = (void *)cb;
+ struct gru_control_block_status *gen = cb;
int ret;
ret = gru_wait_idle_or_exception(gen);
diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c
index 7f6976a9f508..01d2257deea4 100644
--- a/drivers/misc/ti-st/st_core.c
+++ b/drivers/misc/ti-st/st_core.c
@@ -338,7 +338,7 @@ void st_int_recv(void *disc_data,
ptr++;
count--;
continue;
- /* Unknow packet? */
+ /* Unknown packet? */
default:
type = *ptr;
diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c
index a3098fea3bf7..eee9b6581604 100644
--- a/drivers/misc/tifm_core.c
+++ b/drivers/misc/tifm_core.c
@@ -55,9 +55,9 @@ static int tifm_bus_match(struct device *dev, struct device_driver *drv)
return 0;
}
-static int tifm_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int tifm_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
+ const struct tifm_dev *sock = container_of_const(dev, struct tifm_dev, dev);
if (add_uevent_var(env, "TIFM_CARD_TYPE=%s", tifm_media_type_name(sock->type, 1)))
return -ENOMEM;
diff --git a/drivers/misc/uacce/uacce.c b/drivers/misc/uacce/uacce.c
index 905eff1f840e..07023397afc7 100644
--- a/drivers/misc/uacce/uacce.c
+++ b/drivers/misc/uacce/uacce.c
@@ -229,7 +229,7 @@ static int uacce_fops_mmap(struct file *filep, struct vm_area_struct *vma)
if (!qfr)
return -ENOMEM;
- vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND | VM_WIPEONFORK;
+ vm_flags_set(vma, VM_DONTCOPY | VM_DONTEXPAND | VM_WIPEONFORK);
vma->vm_ops = &uacce_vm_ops;
vma->vm_private_data = q;
qfr->type = type;
@@ -363,12 +363,52 @@ static ssize_t region_dus_size_show(struct device *dev,
uacce->qf_pg_num[UACCE_QFRT_DUS] << PAGE_SHIFT);
}
+static ssize_t isolate_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct uacce_device *uacce = to_uacce_device(dev);
+
+ return sysfs_emit(buf, "%d\n", uacce->ops->get_isolate_state(uacce));
+}
+
+static ssize_t isolate_strategy_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct uacce_device *uacce = to_uacce_device(dev);
+ u32 val;
+
+ val = uacce->ops->isolate_err_threshold_read(uacce);
+
+ return sysfs_emit(buf, "%u\n", val);
+}
+
+static ssize_t isolate_strategy_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct uacce_device *uacce = to_uacce_device(dev);
+ unsigned long val;
+ int ret;
+
+ if (kstrtoul(buf, 0, &val) < 0)
+ return -EINVAL;
+
+ if (val > UACCE_MAX_ERR_THRESHOLD)
+ return -EINVAL;
+
+ ret = uacce->ops->isolate_err_threshold_write(uacce, val);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
static DEVICE_ATTR_RO(api);
static DEVICE_ATTR_RO(flags);
static DEVICE_ATTR_RO(available_instances);
static DEVICE_ATTR_RO(algorithms);
static DEVICE_ATTR_RO(region_mmio_size);
static DEVICE_ATTR_RO(region_dus_size);
+static DEVICE_ATTR_RO(isolate);
+static DEVICE_ATTR_RW(isolate_strategy);
static struct attribute *uacce_dev_attrs[] = {
&dev_attr_api.attr,
@@ -377,6 +417,8 @@ static struct attribute *uacce_dev_attrs[] = {
&dev_attr_algorithms.attr,
&dev_attr_region_mmio_size.attr,
&dev_attr_region_dus_size.attr,
+ &dev_attr_isolate.attr,
+ &dev_attr_isolate_strategy.attr,
NULL,
};
@@ -392,6 +434,14 @@ static umode_t uacce_dev_is_visible(struct kobject *kobj,
(!uacce->qf_pg_num[UACCE_QFRT_DUS])))
return 0;
+ if (attr == &dev_attr_isolate_strategy.attr &&
+ (!uacce->ops->isolate_err_threshold_read &&
+ !uacce->ops->isolate_err_threshold_write))
+ return 0;
+
+ if (attr == &dev_attr_isolate.attr && !uacce->ops->get_isolate_state)
+ return 0;
+
return attr->mode;
}
diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c
index 61a2be712bf7..9ce9b9e0e9b6 100644
--- a/drivers/misc/vmw_balloon.c
+++ b/drivers/misc/vmw_balloon.c
@@ -1709,7 +1709,7 @@ static void __init vmballoon_debugfs_init(struct vmballoon *b)
static void __exit vmballoon_debugfs_exit(struct vmballoon *b)
{
static_key_disable(&balloon_stat_enabled.key);
- debugfs_remove(debugfs_lookup("vmmemctl", NULL));
+ debugfs_lookup_and_remove("vmmemctl", NULL);
kfree(b->stats);
b->stats = NULL;
}
diff --git a/drivers/misc/vmw_vmci/vmci_host.c b/drivers/misc/vmw_vmci/vmci_host.c
index da1e2a773823..857b9851402a 100644
--- a/drivers/misc/vmw_vmci/vmci_host.c
+++ b/drivers/misc/vmw_vmci/vmci_host.c
@@ -242,6 +242,8 @@ static int vmci_host_setup_notify(struct vmci_ctx *context,
context->notify_page = NULL;
return VMCI_ERROR_GENERIC;
}
+ if (context->notify_page == NULL)
+ return VMCI_ERROR_UNAVAILABLE;
/*
* Map the locked page and set up notify pointer.
diff --git a/drivers/misc/xilinx_tmr_inject.c b/drivers/misc/xilinx_tmr_inject.c
new file mode 100644
index 000000000000..d96f6d7cd109
--- /dev/null
+++ b/drivers/misc/xilinx_tmr_inject.c
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for Xilinx TMR Inject IP.
+ *
+ * Copyright (C) 2022 Advanced Micro Devices, Inc.
+ *
+ * Description:
+ * This driver is developed for TMR Inject IP,The Triple Modular Redundancy(TMR)
+ * Inject provides fault injection.
+ */
+
+#include <asm/xilinx_mb_manager.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/fault-inject.h>
+
+/* TMR Inject Register offsets */
+#define XTMR_INJECT_CR_OFFSET 0x0
+#define XTMR_INJECT_AIR_OFFSET 0x4
+#define XTMR_INJECT_IIR_OFFSET 0xC
+#define XTMR_INJECT_EAIR_OFFSET 0x10
+#define XTMR_INJECT_ERR_OFFSET 0x204
+
+/* Register Bitmasks/shifts */
+#define XTMR_INJECT_CR_CPUID_SHIFT 8
+#define XTMR_INJECT_CR_IE_SHIFT 10
+#define XTMR_INJECT_IIR_ADDR_MASK GENMASK(31, 16)
+
+#define XTMR_INJECT_MAGIC_MAX_VAL 255
+
+/**
+ * struct xtmr_inject_dev - Driver data for TMR Inject
+ * @regs: device physical base address
+ * @magic: Magic hardware configuration value
+ */
+struct xtmr_inject_dev {
+ void __iomem *regs;
+ u32 magic;
+};
+
+static DECLARE_FAULT_ATTR(inject_fault);
+static char *inject_request;
+module_param(inject_request, charp, 0);
+MODULE_PARM_DESC(inject_request, "default fault injection attributes");
+static struct dentry *dbgfs_root;
+
+/* IO accessors */
+static inline void xtmr_inject_write(struct xtmr_inject_dev *xtmr_inject,
+ u32 addr, u32 value)
+{
+ iowrite32(value, xtmr_inject->regs + addr);
+}
+
+static inline u32 xtmr_inject_read(struct xtmr_inject_dev *xtmr_inject,
+ u32 addr)
+{
+ return ioread32(xtmr_inject->regs + addr);
+}
+
+static int xtmr_inject_set(void *data, u64 val)
+{
+ if (val != 1)
+ return -EINVAL;
+
+ xmb_inject_err();
+ return 0;
+}
+DEFINE_DEBUGFS_ATTRIBUTE(xtmr_inject_fops, NULL, xtmr_inject_set, "%llu\n");
+
+static void xtmr_init_debugfs(struct xtmr_inject_dev *xtmr_inject)
+{
+ struct dentry *dir;
+
+ dbgfs_root = debugfs_create_dir("xtmr_inject", NULL);
+ dir = fault_create_debugfs_attr("inject_fault", dbgfs_root,
+ &inject_fault);
+ debugfs_create_file("inject_fault", 0200, dir, NULL,
+ &xtmr_inject_fops);
+}
+
+static void xtmr_inject_init(struct xtmr_inject_dev *xtmr_inject)
+{
+ u32 cr_val;
+
+ if (inject_request)
+ setup_fault_attr(&inject_fault, inject_request);
+ /* Allow fault injection */
+ cr_val = xtmr_inject->magic |
+ (1 << XTMR_INJECT_CR_IE_SHIFT) |
+ (1 << XTMR_INJECT_CR_CPUID_SHIFT);
+ xtmr_inject_write(xtmr_inject, XTMR_INJECT_CR_OFFSET,
+ cr_val);
+ /* Initialize the address inject and instruction inject registers */
+ xtmr_inject_write(xtmr_inject, XTMR_INJECT_AIR_OFFSET,
+ XMB_INJECT_ERR_OFFSET);
+ xtmr_inject_write(xtmr_inject, XTMR_INJECT_IIR_OFFSET,
+ XMB_INJECT_ERR_OFFSET & XTMR_INJECT_IIR_ADDR_MASK);
+}
+
+/**
+ * xtmr_inject_probe - Driver probe function
+ * @pdev: Pointer to the platform_device structure
+ *
+ * This is the driver probe routine. It does all the memory
+ * allocation for the device.
+ *
+ * Return: 0 on success and failure value on error
+ */
+static int xtmr_inject_probe(struct platform_device *pdev)
+{
+ struct xtmr_inject_dev *xtmr_inject;
+ int err;
+
+ xtmr_inject = devm_kzalloc(&pdev->dev, sizeof(*xtmr_inject),
+ GFP_KERNEL);
+ if (!xtmr_inject)
+ return -ENOMEM;
+
+ xtmr_inject->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(xtmr_inject->regs))
+ return PTR_ERR(xtmr_inject->regs);
+
+ err = of_property_read_u32(pdev->dev.of_node, "xlnx,magic",
+ &xtmr_inject->magic);
+ if (err < 0) {
+ dev_err(&pdev->dev, "unable to read xlnx,magic property");
+ return err;
+ }
+
+ if (xtmr_inject->magic > XTMR_INJECT_MAGIC_MAX_VAL) {
+ dev_err(&pdev->dev, "invalid xlnx,magic property value");
+ return -EINVAL;
+ }
+
+ /* Initialize TMR Inject */
+ xtmr_inject_init(xtmr_inject);
+
+ xtmr_init_debugfs(xtmr_inject);
+
+ platform_set_drvdata(pdev, xtmr_inject);
+
+ return 0;
+}
+
+static int xtmr_inject_remove(struct platform_device *pdev)
+{
+ debugfs_remove_recursive(dbgfs_root);
+ dbgfs_root = NULL;
+ return 0;
+}
+
+static const struct of_device_id xtmr_inject_of_match[] = {
+ {
+ .compatible = "xlnx,tmr-inject-1.0",
+ },
+ { /* end of table */ }
+};
+MODULE_DEVICE_TABLE(of, xtmr_inject_of_match);
+
+static struct platform_driver xtmr_inject_driver = {
+ .driver = {
+ .name = "xilinx-tmr_inject",
+ .of_match_table = xtmr_inject_of_match,
+ },
+ .probe = xtmr_inject_probe,
+ .remove = xtmr_inject_remove,
+};
+module_platform_driver(xtmr_inject_driver);
+MODULE_AUTHOR("Advanced Micro Devices, Inc");
+MODULE_DESCRIPTION("Xilinx TMR Inject Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/xilinx_tmr_manager.c b/drivers/misc/xilinx_tmr_manager.c
new file mode 100644
index 000000000000..0ef55e06d3a0
--- /dev/null
+++ b/drivers/misc/xilinx_tmr_manager.c
@@ -0,0 +1,220 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for Xilinx TMR Manager IP.
+ *
+ * Copyright (C) 2022 Advanced Micro Devices, Inc.
+ *
+ * Description:
+ * This driver is developed for TMR Manager,The Triple Modular Redundancy(TMR)
+ * Manager is responsible for handling the TMR subsystem state, including
+ * fault detection and error recovery. The core is triplicated in each of
+ * the sub-blocks in the TMR subsystem, and provides majority voting of
+ * its internal state provides soft error detection, correction and
+ * recovery.
+ */
+
+#include <asm/xilinx_mb_manager.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+
+/* TMR Manager Register offsets */
+#define XTMR_MANAGER_CR_OFFSET 0x0
+#define XTMR_MANAGER_FFR_OFFSET 0x4
+#define XTMR_MANAGER_CMR0_OFFSET 0x8
+#define XTMR_MANAGER_CMR1_OFFSET 0xC
+#define XTMR_MANAGER_BDIR_OFFSET 0x10
+#define XTMR_MANAGER_SEMIMR_OFFSET 0x1C
+
+/* Register Bitmasks/shifts */
+#define XTMR_MANAGER_CR_MAGIC1_MASK GENMASK(7, 0)
+#define XTMR_MANAGER_CR_MAGIC2_MASK GENMASK(15, 8)
+#define XTMR_MANAGER_CR_RIR_MASK BIT(16)
+#define XTMR_MANAGER_FFR_LM12_MASK BIT(0)
+#define XTMR_MANAGER_FFR_LM13_MASK BIT(1)
+#define XTMR_MANAGER_FFR_LM23_MASK BIT(2)
+
+#define XTMR_MANAGER_CR_MAGIC2_SHIFT 4
+#define XTMR_MANAGER_CR_RIR_SHIFT 16
+#define XTMR_MANAGER_CR_BB_SHIFT 18
+
+#define XTMR_MANAGER_MAGIC1_MAX_VAL 255
+
+/**
+ * struct xtmr_manager_dev - Driver data for TMR Manager
+ * @regs: device physical base address
+ * @cr_val: control register value
+ * @magic1: Magic 1 hardware configuration value
+ * @err_cnt: error statistics count
+ * @phys_baseaddr: Physical base address
+ */
+struct xtmr_manager_dev {
+ void __iomem *regs;
+ u32 cr_val;
+ u32 magic1;
+ u32 err_cnt;
+ resource_size_t phys_baseaddr;
+};
+
+/* IO accessors */
+static inline void xtmr_manager_write(struct xtmr_manager_dev *xtmr_manager,
+ u32 addr, u32 value)
+{
+ iowrite32(value, xtmr_manager->regs + addr);
+}
+
+static inline u32 xtmr_manager_read(struct xtmr_manager_dev *xtmr_manager,
+ u32 addr)
+{
+ return ioread32(xtmr_manager->regs + addr);
+}
+
+static void xmb_manager_reset_handler(struct xtmr_manager_dev *xtmr_manager)
+{
+ /* Clear the FFR Register contents as a part of recovery process. */
+ xtmr_manager_write(xtmr_manager, XTMR_MANAGER_FFR_OFFSET, 0);
+}
+
+static void xmb_manager_update_errcnt(struct xtmr_manager_dev *xtmr_manager)
+{
+ xtmr_manager->err_cnt++;
+}
+
+static ssize_t errcnt_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct xtmr_manager_dev *xtmr_manager = dev_get_drvdata(dev);
+
+ return sysfs_emit(buf, "%x\n", xtmr_manager->err_cnt);
+}
+static DEVICE_ATTR_RO(errcnt);
+
+static ssize_t dis_block_break_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct xtmr_manager_dev *xtmr_manager = dev_get_drvdata(dev);
+ int ret;
+ long value;
+
+ ret = kstrtoul(buf, 16, &value);
+ if (ret)
+ return ret;
+
+ /* unblock the break signal*/
+ xtmr_manager->cr_val &= ~(1 << XTMR_MANAGER_CR_BB_SHIFT);
+ xtmr_manager_write(xtmr_manager, XTMR_MANAGER_CR_OFFSET,
+ xtmr_manager->cr_val);
+ return size;
+}
+static DEVICE_ATTR_WO(dis_block_break);
+
+static struct attribute *xtmr_manager_dev_attrs[] = {
+ &dev_attr_dis_block_break.attr,
+ &dev_attr_errcnt.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(xtmr_manager_dev);
+
+static void xtmr_manager_init(struct xtmr_manager_dev *xtmr_manager)
+{
+ /* Clear the SEM interrupt mask register to disable the interrupt */
+ xtmr_manager_write(xtmr_manager, XTMR_MANAGER_SEMIMR_OFFSET, 0);
+
+ /* Allow recovery reset by default */
+ xtmr_manager->cr_val = (1 << XTMR_MANAGER_CR_RIR_SHIFT) |
+ xtmr_manager->magic1;
+ xtmr_manager_write(xtmr_manager, XTMR_MANAGER_CR_OFFSET,
+ xtmr_manager->cr_val);
+ /*
+ * Configure Break Delay Initialization Register to zero so that
+ * break occurs immediately
+ */
+ xtmr_manager_write(xtmr_manager, XTMR_MANAGER_BDIR_OFFSET, 0);
+
+ /*
+ * To come out of break handler need to block the break signal
+ * in the tmr manager, update the xtmr_manager cr_val for the same
+ */
+ xtmr_manager->cr_val |= (1 << XTMR_MANAGER_CR_BB_SHIFT);
+
+ /*
+ * When the break vector gets asserted because of error injection,
+ * the break signal must be blocked before exiting from the
+ * break handler, Below api updates the TMR manager address and
+ * control register and error counter callback arguments,
+ * which will be used by the break handler to block the
+ * break and call the callback function.
+ */
+ xmb_manager_register(xtmr_manager->phys_baseaddr, xtmr_manager->cr_val,
+ (void *)xmb_manager_update_errcnt,
+ xtmr_manager, (void *)xmb_manager_reset_handler);
+}
+
+/**
+ * xtmr_manager_probe - Driver probe function
+ * @pdev: Pointer to the platform_device structure
+ *
+ * This is the driver probe routine. It does all the memory
+ * allocation for the device.
+ *
+ * Return: 0 on success and failure value on error
+ */
+static int xtmr_manager_probe(struct platform_device *pdev)
+{
+ struct xtmr_manager_dev *xtmr_manager;
+ struct resource *res;
+ int err;
+
+ xtmr_manager = devm_kzalloc(&pdev->dev, sizeof(*xtmr_manager),
+ GFP_KERNEL);
+ if (!xtmr_manager)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ xtmr_manager->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(xtmr_manager->regs))
+ return PTR_ERR(xtmr_manager->regs);
+
+ xtmr_manager->phys_baseaddr = res->start;
+
+ err = of_property_read_u32(pdev->dev.of_node, "xlnx,magic1",
+ &xtmr_manager->magic1);
+ if (err < 0) {
+ dev_err(&pdev->dev, "unable to read xlnx,magic1 property");
+ return err;
+ }
+
+ if (xtmr_manager->magic1 > XTMR_MANAGER_MAGIC1_MAX_VAL) {
+ dev_err(&pdev->dev, "invalid xlnx,magic1 property value");
+ return -EINVAL;
+ }
+
+ /* Initialize TMR Manager */
+ xtmr_manager_init(xtmr_manager);
+
+ platform_set_drvdata(pdev, xtmr_manager);
+
+ return 0;
+}
+
+static const struct of_device_id xtmr_manager_of_match[] = {
+ {
+ .compatible = "xlnx,tmr-manager-1.0",
+ },
+ { /* end of table */ }
+};
+MODULE_DEVICE_TABLE(of, xtmr_manager_of_match);
+
+static struct platform_driver xtmr_manager_driver = {
+ .driver = {
+ .name = "xilinx-tmr_manager",
+ .of_match_table = xtmr_manager_of_match,
+ .dev_groups = xtmr_manager_dev_groups,
+ },
+ .probe = xtmr_manager_probe,
+};
+module_platform_driver(xtmr_manager_driver);
+
+MODULE_AUTHOR("Advanced Micro Devices, Inc");
+MODULE_DESCRIPTION("Xilinx TMR Manager Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig
index 6f25c34e4fec..bf4e29ef023c 100644
--- a/drivers/mmc/core/Kconfig
+++ b/drivers/mmc/core/Kconfig
@@ -15,7 +15,7 @@ config PWRSEQ_EMMC
config PWRSEQ_SD8787
tristate "HW reset support for SD8787 BT + Wifi module"
- depends on OF && (MWIFIEX || BT_MRVL_SDIO || LIBERTAS_SDIO || WILC1000_SDIO)
+ depends on OF && (MWIFIEX != n || BT_MRVL_SDIO != n || LIBERTAS_SDIO != n || WILC1000_SDIO != n)
help
This selects hardware reset support for the SD8787 BT + Wifi
module. By default this option is set to n.
@@ -37,6 +37,7 @@ config PWRSEQ_SIMPLE
config MMC_BLOCK
tristate "MMC block device driver"
depends on BLOCK
+ imply IOSCHED_BFQ
default y
help
Say Y here to enable the MMC block device driver support.
diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
index 20da7ed43e6d..672ab90c4b2d 100644
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -470,6 +470,8 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
struct mmc_data data = {};
struct mmc_request mrq = {};
struct scatterlist sg;
+ bool r1b_resp, use_r1b_resp = false;
+ unsigned int busy_timeout_ms;
int err;
unsigned int target_part;
@@ -545,6 +547,13 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
(cmd.opcode == MMC_SWITCH))
return mmc_sanitize(card, idata->ic.cmd_timeout_ms);
+ /* If it's an R1B response we need some more preparations. */
+ busy_timeout_ms = idata->ic.cmd_timeout_ms ? : MMC_BLK_TIMEOUT_MS;
+ r1b_resp = (cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B;
+ if (r1b_resp)
+ use_r1b_resp = mmc_prepare_busy_cmd(card->host, &cmd,
+ busy_timeout_ms);
+
mmc_wait_for_req(card->host, &mrq);
memcpy(&idata->ic.response, cmd.resp, sizeof(cmd.resp));
@@ -596,14 +605,14 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
if (idata->ic.postsleep_min_us)
usleep_range(idata->ic.postsleep_min_us, idata->ic.postsleep_max_us);
- if (idata->rpmb || (cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
- /*
- * Ensure RPMB/R1B command has completed by polling CMD13 "Send Status". Here we
- * allow to override the default timeout value if a custom timeout is specified.
- */
- err = mmc_poll_for_busy(card, idata->ic.cmd_timeout_ms ? : MMC_BLK_TIMEOUT_MS,
- false, MMC_BUSY_IO);
- }
+ /* No need to poll when using HW busy detection. */
+ if ((card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp)
+ return 0;
+
+ /* Ensure RPMB/R1B command has completed by polling with CMD13. */
+ if (idata->rpmb || r1b_resp)
+ err = mmc_poll_for_busy(card, busy_timeout_ms, false,
+ MMC_BUSY_IO);
return err;
}
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 36679f4e9acc..2c3074a605fc 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -55,9 +55,9 @@ static struct attribute *mmc_dev_attrs[] = {
ATTRIBUTE_GROUPS(mmc_dev);
static int
-mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
+mmc_bus_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct mmc_card *card = mmc_dev_to_card(dev);
+ const struct mmc_card *card = mmc_dev_to_card(dev);
const char *type;
unsigned int i;
int retval = 0;
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index d17eda753b7e..096093f7be00 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -588,6 +588,32 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
EXPORT_SYMBOL(mmc_alloc_host);
+static void devm_mmc_host_release(struct device *dev, void *res)
+{
+ mmc_free_host(*(struct mmc_host **)res);
+}
+
+struct mmc_host *devm_mmc_alloc_host(struct device *dev, int extra)
+{
+ struct mmc_host **dr, *host;
+
+ dr = devres_alloc(devm_mmc_host_release, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return NULL;
+
+ host = mmc_alloc_host(extra, dev);
+ if (!host) {
+ devres_free(dr);
+ return NULL;
+ }
+
+ *dr = host;
+ devres_add(dev, dr);
+
+ return host;
+}
+EXPORT_SYMBOL(devm_mmc_alloc_host);
+
static int mmc_validate_host_caps(struct mmc_host *host)
{
struct device *dev = host->parent;
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 81c55bfd6e0c..3b3adbddf664 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -575,6 +575,7 @@ bool mmc_prepare_busy_cmd(struct mmc_host *host, struct mmc_command *cmd,
cmd->busy_timeout = timeout_ms;
return true;
}
+EXPORT_SYMBOL_GPL(mmc_prepare_busy_cmd);
/**
* __mmc_switch - modify EXT_CSD register
diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c
index 988467fbb621..3bac1e71411b 100644
--- a/drivers/mmc/core/pwrseq_simple.c
+++ b/drivers/mmc/core/pwrseq_simple.c
@@ -119,14 +119,14 @@ static int mmc_pwrseq_simple_probe(struct platform_device *pdev)
pwrseq->ext_clk = devm_clk_get(dev, "ext_clock");
if (IS_ERR(pwrseq->ext_clk) && PTR_ERR(pwrseq->ext_clk) != -ENOENT)
- return PTR_ERR(pwrseq->ext_clk);
+ return dev_err_probe(dev, PTR_ERR(pwrseq->ext_clk), "external clock not ready\n");
pwrseq->reset_gpios = devm_gpiod_get_array(dev, "reset",
GPIOD_OUT_HIGH);
if (IS_ERR(pwrseq->reset_gpios) &&
PTR_ERR(pwrseq->reset_gpios) != -ENOENT &&
PTR_ERR(pwrseq->reset_gpios) != -ENOSYS) {
- return PTR_ERR(pwrseq->reset_gpios);
+ return dev_err_probe(dev, PTR_ERR(pwrseq->reset_gpios), "reset GPIOs not ready\n");
}
device_property_read_u32(dev, "post-power-on-delay-ms",
diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c
index f191a2a76f3b..47a48e902a24 100644
--- a/drivers/mmc/core/sdio_bus.c
+++ b/drivers/mmc/core/sdio_bus.c
@@ -120,9 +120,9 @@ static int sdio_bus_match(struct device *dev, struct device_driver *drv)
}
static int
-sdio_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
+sdio_bus_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct sdio_func *func = dev_to_sdio_func(dev);
+ const struct sdio_func *func = dev_to_sdio_func(dev);
unsigned int i;
if (add_uevent_var(env,
diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c
index 79dbf90216b5..b774bf51981d 100644
--- a/drivers/mmc/core/sdio_io.c
+++ b/drivers/mmc/core/sdio_io.c
@@ -766,7 +766,7 @@ EXPORT_SYMBOL_GPL(sdio_retune_crc_disable);
* sdio_retune_crc_enable - re-enable retuning on CRC errors
* @func: SDIO function attached to host
*
- * This is the compement to sdio_retune_crc_disable().
+ * This is the complement to sdio_retune_crc_disable().
*/
void sdio_retune_crc_enable(struct sdio_func *func)
{
diff --git a/drivers/mmc/core/sdio_uart.c b/drivers/mmc/core/sdio_uart.c
index ae7ef2e038be..50536fe59f1a 100644
--- a/drivers/mmc/core/sdio_uart.c
+++ b/drivers/mmc/core/sdio_uart.c
@@ -526,7 +526,7 @@ static void sdio_uart_irq(struct sdio_func *func)
port->in_sdio_uart_irq = NULL;
}
-static int uart_carrier_raised(struct tty_port *tport)
+static bool uart_carrier_raised(struct tty_port *tport)
{
struct sdio_uart_port *port =
container_of(tport, struct sdio_uart_port, port);
@@ -535,28 +535,27 @@ static int uart_carrier_raised(struct tty_port *tport)
return 1;
ret = sdio_uart_get_mctrl(port);
sdio_uart_release_func(port);
- if (ret & TIOCM_CAR)
- return 1;
- return 0;
+
+ return ret & TIOCM_CAR;
}
/**
* uart_dtr_rts - port helper to set uart signals
* @tport: tty port to be updated
- * @onoff: set to turn on DTR/RTS
+ * @active: set to turn on DTR/RTS
*
* Called by the tty port helpers when the modem signals need to be
* adjusted during an open, close and hangup.
*/
-static void uart_dtr_rts(struct tty_port *tport, int onoff)
+static void uart_dtr_rts(struct tty_port *tport, bool active)
{
struct sdio_uart_port *port =
container_of(tport, struct sdio_uart_port, port);
int ret = sdio_uart_claim_func(port);
if (ret)
return;
- if (onoff == 0)
+ if (!active)
sdio_uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
else
sdio_uart_set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c
index dd2a4b6ab6ad..2a2d949a9344 100644
--- a/drivers/mmc/core/slot-gpio.c
+++ b/drivers/mmc/core/slot-gpio.c
@@ -23,6 +23,7 @@ struct mmc_gpio {
char *ro_label;
char *cd_label;
u32 cd_debounce_delay_ms;
+ int cd_irq;
};
static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id)
@@ -53,12 +54,24 @@ int mmc_gpio_alloc(struct mmc_host *host)
ctx->ro_label = devm_kasprintf(host->parent, GFP_KERNEL, "%s ro", devname);
if (!ctx->ro_label)
return -ENOMEM;
+ ctx->cd_irq = -EINVAL;
host->slot.handler_priv = ctx;
host->slot.cd_irq = -EINVAL;
return 0;
}
+void mmc_gpio_set_cd_irq(struct mmc_host *host, int irq)
+{
+ struct mmc_gpio *ctx = host->slot.handler_priv;
+
+ if (!ctx || irq < 0)
+ return;
+
+ ctx->cd_irq = irq;
+}
+EXPORT_SYMBOL(mmc_gpio_set_cd_irq);
+
int mmc_gpio_get_ro(struct mmc_host *host)
{
struct mmc_gpio *ctx = host->slot.handler_priv;
@@ -98,7 +111,9 @@ void mmc_gpiod_request_cd_irq(struct mmc_host *host)
* Do not use IRQ if the platform prefers to poll, e.g., because that
* IRQ number is already used by another unit and cannot be shared.
*/
- if (!(host->caps & MMC_CAP_NEEDS_POLL))
+ if (ctx->cd_irq >= 0)
+ irq = ctx->cd_irq;
+ else if (!(host->caps & MMC_CAP_NEEDS_POLL))
irq = gpiod_to_irq(ctx->cd_gpio);
if (irq >= 0) {
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index e13b0b0b8ebb..4745fe217ade 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -348,6 +348,7 @@ config MMC_SDHCI_PXAV2
depends on MMC_SDHCI_PLTFM
depends on ARCH_MMP || COMPILE_TEST
default CPU_PXA910
+ select MMC_SDHCI_IO_ACCESSORS
help
This selects the Marvell(R) PXAV2 SD Host Controller.
If you have a PXA9XX platform with SD Host Controller
@@ -816,6 +817,16 @@ config MMC_DW_ROCKCHIP
Synopsys DesignWare Memory Card Interface driver. Select this option
for platforms based on RK3066, RK3188 and RK3288 SoC's.
+config MMC_DW_STARFIVE
+ tristate "StarFive specific extensions for Synopsys DW Memory Card Interface"
+ depends on SOC_STARFIVE
+ depends on MMC_DW
+ select MMC_DW_PLTFM
+ help
+ This selects support for StarFive JH7110 SoC specific extensions to the
+ Synopsys DesignWare Memory Card Interface driver. Select this option
+ for platforms based on StarFive JH7110 SoC.
+
config MMC_SH_MMCIF
tristate "SuperH Internal MMCIF support"
depends on SUPERH || ARCH_RENESAS || COMPILE_TEST
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index b498c17cd124..a693fa3d3f1c 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -54,6 +54,7 @@ obj-$(CONFIG_MMC_DW_HI3798CV200) += dw_mmc-hi3798cv200.o
obj-$(CONFIG_MMC_DW_K3) += dw_mmc-k3.o
obj-$(CONFIG_MMC_DW_PCI) += dw_mmc-pci.o
obj-$(CONFIG_MMC_DW_ROCKCHIP) += dw_mmc-rockchip.o
+obj-$(CONFIG_MMC_DW_STARFIVE) += dw_mmc-starfive.o
obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o
obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o
obj-$(CONFIG_MMC_VUB300) += vub300.o
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index bb9bbf1c927b..dd18440a90c5 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -1817,7 +1817,6 @@ static void atmci_tasklet_func(struct tasklet_struct *t)
atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
state = STATE_WAITING_NOTBUSY;
} else if (host->mrq->stop) {
- atmci_writel(host, ATMCI_IER, ATMCI_CMDRDY);
atmci_send_stop_cmd(host, data);
state = STATE_SENDING_STOP;
} else {
@@ -1850,8 +1849,6 @@ static void atmci_tasklet_func(struct tasklet_struct *t)
* command to send.
*/
if (host->mrq->stop) {
- atmci_writel(host, ATMCI_IER,
- ATMCI_CMDRDY);
atmci_send_stop_cmd(host, data);
state = STATE_SENDING_STOP;
} else {
diff --git a/drivers/mmc/host/dw_mmc-starfive.c b/drivers/mmc/host/dw_mmc-starfive.c
new file mode 100644
index 000000000000..40f5969b07a6
--- /dev/null
+++ b/drivers/mmc/host/dw_mmc-starfive.c
@@ -0,0 +1,186 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * StarFive Designware Mobile Storage Host Controller Driver
+ *
+ * Copyright (c) 2022 StarFive Technology Co., Ltd.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mmc/host.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include "dw_mmc.h"
+#include "dw_mmc-pltfm.h"
+
+#define ALL_INT_CLR 0x1ffff
+#define MAX_DELAY_CHAIN 32
+
+struct starfive_priv {
+ struct device *dev;
+ struct regmap *reg_syscon;
+ u32 syscon_offset;
+ u32 syscon_shift;
+ u32 syscon_mask;
+};
+
+static void dw_mci_starfive_set_ios(struct dw_mci *host, struct mmc_ios *ios)
+{
+ int ret;
+ unsigned int clock;
+
+ if (ios->timing == MMC_TIMING_MMC_DDR52 || ios->timing == MMC_TIMING_UHS_DDR50) {
+ clock = (ios->clock > 50000000 && ios->clock <= 52000000) ? 100000000 : ios->clock;
+ ret = clk_set_rate(host->ciu_clk, clock);
+ if (ret)
+ dev_dbg(host->dev, "Use an external frequency divider %uHz\n", ios->clock);
+ host->bus_hz = clk_get_rate(host->ciu_clk);
+ } else {
+ dev_dbg(host->dev, "Using the internal divider\n");
+ }
+}
+
+static int dw_mci_starfive_execute_tuning(struct dw_mci_slot *slot,
+ u32 opcode)
+{
+ static const int grade = MAX_DELAY_CHAIN;
+ struct dw_mci *host = slot->host;
+ struct starfive_priv *priv = host->priv;
+ int rise_point = -1, fall_point = -1;
+ int err, prev_err;
+ int i;
+ bool found = 0;
+ u32 regval;
+
+ /*
+ * Use grade as the max delay chain, and use the rise_point and
+ * fall_point to ensure the best sampling point of a data input
+ * signals.
+ */
+ for (i = 0; i < grade; i++) {
+ regval = i << priv->syscon_shift;
+ err = regmap_update_bits(priv->reg_syscon, priv->syscon_offset,
+ priv->syscon_mask, regval);
+ if (err)
+ return err;
+ mci_writel(host, RINTSTS, ALL_INT_CLR);
+
+ err = mmc_send_tuning(slot->mmc, opcode, NULL);
+ if (!err)
+ found = 1;
+
+ if (i > 0) {
+ if (err && !prev_err)
+ fall_point = i - 1;
+ if (!err && prev_err)
+ rise_point = i;
+ }
+
+ if (rise_point != -1 && fall_point != -1)
+ goto tuning_out;
+
+ prev_err = err;
+ err = 0;
+ }
+
+tuning_out:
+ if (found) {
+ if (rise_point == -1)
+ rise_point = 0;
+ if (fall_point == -1)
+ fall_point = grade - 1;
+ if (fall_point < rise_point) {
+ if ((rise_point + fall_point) >
+ (grade - 1))
+ i = fall_point / 2;
+ else
+ i = (rise_point + grade - 1) / 2;
+ } else {
+ i = (rise_point + fall_point) / 2;
+ }
+
+ regval = i << priv->syscon_shift;
+ err = regmap_update_bits(priv->reg_syscon, priv->syscon_offset,
+ priv->syscon_mask, regval);
+ if (err)
+ return err;
+ mci_writel(host, RINTSTS, ALL_INT_CLR);
+
+ dev_info(host->dev, "Found valid delay chain! use it [delay=%d]\n", i);
+ } else {
+ dev_err(host->dev, "No valid delay chain! use default\n");
+ err = -EINVAL;
+ }
+
+ mci_writel(host, RINTSTS, ALL_INT_CLR);
+ return err;
+}
+
+static int dw_mci_starfive_parse_dt(struct dw_mci *host)
+{
+ struct of_phandle_args args;
+ struct starfive_priv *priv;
+ int ret;
+
+ priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ ret = of_parse_phandle_with_fixed_args(host->dev->of_node,
+ "starfive,sysreg", 3, 0, &args);
+ if (ret) {
+ dev_err(host->dev, "Failed to parse starfive,sysreg\n");
+ return -EINVAL;
+ }
+
+ priv->reg_syscon = syscon_node_to_regmap(args.np);
+ of_node_put(args.np);
+ if (IS_ERR(priv->reg_syscon))
+ return PTR_ERR(priv->reg_syscon);
+
+ priv->syscon_offset = args.args[0];
+ priv->syscon_shift = args.args[1];
+ priv->syscon_mask = args.args[2];
+
+ host->priv = priv;
+
+ return 0;
+}
+
+static const struct dw_mci_drv_data starfive_data = {
+ .common_caps = MMC_CAP_CMD23,
+ .set_ios = dw_mci_starfive_set_ios,
+ .parse_dt = dw_mci_starfive_parse_dt,
+ .execute_tuning = dw_mci_starfive_execute_tuning,
+};
+
+static const struct of_device_id dw_mci_starfive_match[] = {
+ { .compatible = "starfive,jh7110-mmc",
+ .data = &starfive_data },
+ {},
+};
+MODULE_DEVICE_TABLE(of, dw_mci_starfive_match);
+
+static int dw_mci_starfive_probe(struct platform_device *pdev)
+{
+ return dw_mci_pltfm_register(pdev, &starfive_data);
+}
+
+static struct platform_driver dw_mci_starfive_driver = {
+ .probe = dw_mci_starfive_probe,
+ .remove = dw_mci_pltfm_remove,
+ .driver = {
+ .name = "dwmmc_starfive",
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ .of_match_table = dw_mci_starfive_match,
+ },
+};
+module_platform_driver(dw_mci_starfive_driver);
+
+MODULE_DESCRIPTION("StarFive JH7110 Specific DW-MSHC Driver Extension");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:dwmmc_starfive");
diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c
index eda1e2ddcaca..698450afa7bb 100644
--- a/drivers/mmc/host/jz4740_mmc.c
+++ b/drivers/mmc/host/jz4740_mmc.c
@@ -21,6 +21,7 @@
#include <linux/of_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
#include <linux/scatterlist.h>
#include <asm/cacheflush.h>
@@ -158,6 +159,8 @@ struct jz4740_mmc_host {
struct mmc_request *req;
struct mmc_command *cmd;
+ bool vqmmc_enabled;
+
unsigned long waiting;
uint32_t cmdat;
@@ -935,6 +938,8 @@ static void jz4740_mmc_request(struct mmc_host *mmc, struct mmc_request *req)
static void jz4740_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct jz4740_mmc_host *host = mmc_priv(mmc);
+ int ret;
+
if (ios->clock)
jz4740_mmc_set_clock_rate(host, ios->clock);
@@ -947,12 +952,25 @@ static void jz4740_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
clk_prepare_enable(host->clk);
break;
case MMC_POWER_ON:
+ if (!IS_ERR(mmc->supply.vqmmc) && !host->vqmmc_enabled) {
+ ret = regulator_enable(mmc->supply.vqmmc);
+ if (ret)
+ dev_err(&host->pdev->dev, "Failed to set vqmmc power!\n");
+ else
+ host->vqmmc_enabled = true;
+ }
break;
- default:
+ case MMC_POWER_OFF:
if (!IS_ERR(mmc->supply.vmmc))
mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
+ if (!IS_ERR(mmc->supply.vqmmc) && host->vqmmc_enabled) {
+ regulator_disable(mmc->supply.vqmmc);
+ host->vqmmc_enabled = false;
+ }
clk_disable_unprepare(host->clk);
break;
+ default:
+ break;
}
switch (ios->bus_width) {
@@ -978,6 +996,23 @@ static void jz4740_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_SDIO, enable);
}
+static int jz4740_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ int ret;
+
+ /* vqmmc regulator is available */
+ if (!IS_ERR(mmc->supply.vqmmc)) {
+ ret = mmc_regulator_set_vqmmc(mmc, ios);
+ return ret < 0 ? ret : 0;
+ }
+
+ /* no vqmmc regulator, assume fixed regulator at 3/3.3V */
+ if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330)
+ return 0;
+
+ return -EINVAL;
+}
+
static const struct mmc_host_ops jz4740_mmc_ops = {
.request = jz4740_mmc_request,
.pre_req = jz4740_mmc_pre_request,
@@ -986,6 +1021,7 @@ static const struct mmc_host_ops jz4740_mmc_ops = {
.get_ro = mmc_gpio_get_ro,
.get_cd = mmc_gpio_get_cd,
.enable_sdio_irq = jz4740_mmc_enable_sdio_irq,
+ .start_signal_voltage_switch = jz4740_voltage_switch,
};
static const struct of_device_id jz4740_mmc_of_match[] = {
diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c
index 5c94ad4661ce..2b963a81c2ad 100644
--- a/drivers/mmc/host/meson-gx-mmc.c
+++ b/drivers/mmc/host/meson-gx-mmc.c
@@ -150,12 +150,11 @@ struct sd_emmc_desc {
struct meson_host {
struct device *dev;
- struct meson_mmc_data *data;
+ const struct meson_mmc_data *data;
struct mmc_host *mmc;
struct mmc_command *cmd;
void __iomem *regs;
- struct clk *core_clk;
struct clk *mux_clk;
struct clk *mmc_clk;
unsigned long req_rate;
@@ -1083,20 +1082,6 @@ static irqreturn_t meson_mmc_irq_thread(int irq, void *dev_id)
return IRQ_HANDLED;
}
-/*
- * NOTE: we only need this until the GPIO/pinctrl driver can handle
- * interrupts. For now, the MMC core will use this for polling.
- */
-static int meson_mmc_get_cd(struct mmc_host *mmc)
-{
- int status = mmc_gpio_get_cd(mmc);
-
- if (status == -ENOSYS)
- return 1; /* assume present */
-
- return status;
-}
-
static void meson_mmc_cfg_init(struct meson_host *host)
{
u32 cfg = 0;
@@ -1165,7 +1150,7 @@ static void meson_mmc_ack_sdio_irq(struct mmc_host *mmc)
static const struct mmc_host_ops meson_mmc_ops = {
.request = meson_mmc_request,
.set_ios = meson_mmc_set_ios,
- .get_cd = meson_mmc_get_cd,
+ .get_cd = mmc_gpio_get_cd,
.pre_req = meson_mmc_pre_req,
.post_req = meson_mmc_post_req,
.execute_tuning = meson_mmc_resampling_tuning,
@@ -1180,9 +1165,10 @@ static int meson_mmc_probe(struct platform_device *pdev)
struct resource *res;
struct meson_host *host;
struct mmc_host *mmc;
- int ret;
+ struct clk *core_clk;
+ int cd_irq, ret;
- mmc = mmc_alloc_host(sizeof(struct meson_host), &pdev->dev);
+ mmc = devm_mmc_alloc_host(&pdev->dev, sizeof(struct meson_host));
if (!mmc)
return -ENOMEM;
host = mmc_priv(mmc);
@@ -1198,51 +1184,39 @@ static int meson_mmc_probe(struct platform_device *pdev)
host->vqmmc_enabled = false;
ret = mmc_regulator_get_supply(mmc);
if (ret)
- goto free_host;
+ return ret;
ret = mmc_of_parse(mmc);
- if (ret) {
- if (ret != -EPROBE_DEFER)
- dev_warn(&pdev->dev, "error parsing DT: %d\n", ret);
- goto free_host;
- }
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "error parsing DT\n");
mmc->caps |= MMC_CAP_CMD23;
if (mmc->caps & MMC_CAP_SDIO_IRQ)
mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
- host->data = (struct meson_mmc_data *)
- of_device_get_match_data(&pdev->dev);
- if (!host->data) {
- ret = -EINVAL;
- goto free_host;
- }
+ host->data = of_device_get_match_data(&pdev->dev);
+ if (!host->data)
+ return -EINVAL;
ret = device_reset_optional(&pdev->dev);
- if (ret) {
- dev_err_probe(&pdev->dev, ret, "device reset failed\n");
- goto free_host;
- }
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "device reset failed\n");
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- host->regs = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(host->regs)) {
- ret = PTR_ERR(host->regs);
- goto free_host;
- }
+ host->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+ if (IS_ERR(host->regs))
+ return PTR_ERR(host->regs);
host->irq = platform_get_irq(pdev, 0);
- if (host->irq <= 0) {
- ret = -EINVAL;
- goto free_host;
- }
+ if (host->irq <= 0)
+ return -EINVAL;
+
+ cd_irq = platform_get_irq_optional(pdev, 1);
+ mmc_gpio_set_cd_irq(mmc, cd_irq);
host->pinctrl = devm_pinctrl_get(&pdev->dev);
- if (IS_ERR(host->pinctrl)) {
- ret = PTR_ERR(host->pinctrl);
- goto free_host;
- }
+ if (IS_ERR(host->pinctrl))
+ return PTR_ERR(host->pinctrl);
host->pins_clk_gate = pinctrl_lookup_state(host->pinctrl,
"clk-gate");
@@ -1252,19 +1226,13 @@ static int meson_mmc_probe(struct platform_device *pdev)
host->pins_clk_gate = NULL;
}
- host->core_clk = devm_clk_get(&pdev->dev, "core");
- if (IS_ERR(host->core_clk)) {
- ret = PTR_ERR(host->core_clk);
- goto free_host;
- }
-
- ret = clk_prepare_enable(host->core_clk);
- if (ret)
- goto free_host;
+ core_clk = devm_clk_get_enabled(&pdev->dev, "core");
+ if (IS_ERR(core_clk))
+ return PTR_ERR(core_clk);
ret = meson_mmc_clk_init(host);
if (ret)
- goto err_core_clk;
+ return ret;
/* set config to sane default */
meson_mmc_cfg_init(host);
@@ -1348,10 +1316,6 @@ err_free_irq:
free_irq(host->irq, host);
err_init_clk:
clk_disable_unprepare(host->mmc_clk);
-err_core_clk:
- clk_disable_unprepare(host->core_clk);
-free_host:
- mmc_free_host(mmc);
return ret;
}
@@ -1366,9 +1330,7 @@ static int meson_mmc_remove(struct platform_device *pdev)
free_irq(host->irq, host);
clk_disable_unprepare(host->mmc_clk);
- clk_disable_unprepare(host->core_clk);
- mmc_free_host(host->mmc);
return 0;
}
diff --git a/drivers/mmc/host/moxart-mmc.c b/drivers/mmc/host/moxart-mmc.c
index 52ed30f2d9f4..2d002c81dcf3 100644
--- a/drivers/mmc/host/moxart-mmc.c
+++ b/drivers/mmc/host/moxart-mmc.c
@@ -611,6 +611,9 @@ static int moxart_probe(struct platform_device *pdev)
mmc->f_max = DIV_ROUND_CLOSEST(host->sysclk, 2);
mmc->f_min = DIV_ROUND_CLOSEST(host->sysclk, CLK_DIV_MASK * 2);
mmc->ocr_avail = 0xffff00; /* Support 2.0v - 3.6v power. */
+ mmc->max_blk_size = 2048; /* Max. block length in REG_DATA_CONTROL */
+ mmc->max_req_size = DATA_LEN_MASK; /* bits 0-23 in REG_DATA_LENGTH */
+ mmc->max_blk_count = mmc->max_req_size / 512;
if (IS_ERR(host->dma_chan_tx) || IS_ERR(host->dma_chan_rx)) {
if (PTR_ERR(host->dma_chan_tx) == -EPROBE_DEFER ||
@@ -628,6 +631,8 @@ static int moxart_probe(struct platform_device *pdev)
}
dev_dbg(dev, "PIO mode transfer enabled\n");
host->have_dma = false;
+
+ mmc->max_seg_size = mmc->max_req_size;
} else {
dev_dbg(dev, "DMA channels found (%p,%p)\n",
host->dma_chan_tx, host->dma_chan_rx);
@@ -646,6 +651,10 @@ static int moxart_probe(struct platform_device *pdev)
cfg.src_addr = host->reg_phys + REG_DATA_WINDOW;
cfg.dst_addr = 0;
dmaengine_slave_config(host->dma_chan_rx, &cfg);
+
+ mmc->max_seg_size = min3(mmc->max_req_size,
+ dma_get_max_seg_size(host->dma_chan_rx->device->dev),
+ dma_get_max_seg_size(host->dma_chan_tx->device->dev));
}
if (readl(host->base + REG_BUS_WIDTH) & BUS_WIDTH_4_SUPPORT)
diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c
index 29f562115c66..f38003f6b1ca 100644
--- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c
+++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c
@@ -210,6 +210,11 @@ static const struct renesas_sdhi_quirks sdhi_quirks_r8a77990 = {
.manual_tap_correction = true,
};
+static const struct renesas_sdhi_quirks sdhi_quirks_r9a09g011 = {
+ .fixed_addr_mode = true,
+ .hs400_disabled = true,
+};
+
/*
* Note for r8a7796 / r8a774a1: we can't distinguish ES1.1 and 1.2 as of now.
* So, we want to treat them equally and only have a match for ES1.2 to enforce
@@ -251,6 +256,11 @@ static const struct renesas_sdhi_of_data_with_quirks of_r8a77990_compatible = {
.quirks = &sdhi_quirks_r8a77990,
};
+static const struct renesas_sdhi_of_data_with_quirks of_r9a09g011_compatible = {
+ .of_data = &of_data_rcar_gen3,
+ .quirks = &sdhi_quirks_r9a09g011,
+};
+
static const struct renesas_sdhi_of_data_with_quirks of_rcar_gen3_compatible = {
.of_data = &of_data_rcar_gen3,
};
@@ -274,6 +284,7 @@ static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = {
{ .compatible = "renesas,sdhi-r8a77970", .data = &of_r8a77970_compatible, },
{ .compatible = "renesas,sdhi-r8a77990", .data = &of_r8a77990_compatible, },
{ .compatible = "renesas,sdhi-r8a77995", .data = &of_rcar_gen3_nohs400_compatible, },
+ { .compatible = "renesas,sdhi-r9a09g011", .data = &of_r9a09g011_compatible, },
{ .compatible = "renesas,rcar-gen3-sdhi", .data = &of_rcar_gen3_compatible, },
{ .compatible = "renesas,rcar-gen4-sdhi", .data = &of_rcar_gen3_compatible, },
{},
diff --git a/drivers/mmc/host/sdhci-brcmstb.c b/drivers/mmc/host/sdhci-brcmstb.c
index f2cf3d70db79..4c22337199cf 100644
--- a/drivers/mmc/host/sdhci-brcmstb.c
+++ b/drivers/mmc/host/sdhci-brcmstb.c
@@ -255,7 +255,6 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev)
struct sdhci_brcmstb_priv *priv;
u32 actual_clock_mhz;
struct sdhci_host *host;
- struct resource *iomem;
struct clk *clk;
struct clk *base_clk = NULL;
int res;
@@ -291,8 +290,7 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev)
}
/* Map in the non-standard CFG registers */
- iomem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- priv->cfg_regs = devm_ioremap_resource(&pdev->dev, iomem);
+ priv->cfg_regs = devm_platform_get_and_ioremap_resource(pdev, 1, NULL);
if (IS_ERR(priv->cfg_regs)) {
res = PTR_ERR(priv->cfg_regs);
goto err;
@@ -324,13 +322,11 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev)
* will allow these modes to be specified by device tree
* properties through mmc_of_parse().
*/
- host->caps = sdhci_readl(host, SDHCI_CAPABILITIES);
+ sdhci_read_caps(host);
if (match_priv->flags & BRCMSTB_MATCH_FLAGS_NO_64BIT)
host->caps &= ~SDHCI_CAN_64BIT;
- host->caps1 = sdhci_readl(host, SDHCI_CAPABILITIES_1);
host->caps1 &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_SDR104 |
SDHCI_SUPPORT_DDR50);
- host->quirks |= SDHCI_QUIRK_MISSING_CAPS;
if (match_priv->flags & BRCMSTB_MATCH_FLAGS_BROKEN_TIMEOUT)
host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 9e73c34b6401..58f042fdd4f4 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -338,6 +338,16 @@ struct pltfm_imx_data {
struct clk *clk_ahb;
struct clk *clk_per;
unsigned int actual_clock;
+
+ /*
+ * USDHC has one limition, require the SDIO device a different
+ * register setting. Driver has to recognize card type during
+ * the card init, but at this stage, mmc_host->card is not
+ * available. So involve this field to save the card type
+ * during card init through usdhc_init_card().
+ */
+ unsigned int init_card_type;
+
enum {
NO_CMD_PENDING, /* no multiblock command pending */
MULTIBLK_IN_PROCESS, /* exact multiblock cmd in process */
@@ -430,9 +440,12 @@ static inline void esdhc_wait_for_card_clock_gate_off(struct sdhci_host *host)
}
/* Enable the auto tuning circuit to check the CMD line and BUS line */
-static inline void usdhc_auto_tuning_mode_sel(struct sdhci_host *host)
+static inline void usdhc_auto_tuning_mode_sel_and_en(struct sdhci_host *host)
{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
u32 buswidth, auto_tune_buswidth;
+ u32 reg;
buswidth = USDHC_GET_BUSWIDTH(readl(host->ioaddr + SDHCI_HOST_CONTROL));
@@ -448,9 +461,27 @@ static inline void usdhc_auto_tuning_mode_sel(struct sdhci_host *host)
break;
}
+ /*
+ * For USDHC, auto tuning circuit can not handle the async sdio
+ * device interrupt correctly. When sdio device use 4 data lines,
+ * async sdio interrupt will use the shared DAT[1], if enable auto
+ * tuning circuit check these 4 data lines, include the DAT[1],
+ * this circuit will detect this interrupt, take this as a data on
+ * DAT[1], and adjust the delay cell wrongly.
+ * This is the hardware design limitation, to avoid this, for sdio
+ * device, config the auto tuning circuit only check DAT[0] and CMD
+ * line.
+ */
+ if (imx_data->init_card_type == MMC_TYPE_SDIO)
+ auto_tune_buswidth = ESDHC_VEND_SPEC2_AUTO_TUNE_1BIT_EN;
+
esdhc_clrset_le(host, ESDHC_VEND_SPEC2_AUTO_TUNE_MODE_MASK,
auto_tune_buswidth | ESDHC_VEND_SPEC2_AUTO_TUNE_CMD_EN,
ESDHC_VEND_SPEC2);
+
+ reg = readl(host->ioaddr + ESDHC_MIX_CTRL);
+ reg |= ESDHC_MIX_CTRL_AUTO_TUNE_EN;
+ writel(reg, host->ioaddr + ESDHC_MIX_CTRL);
}
static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
@@ -682,14 +713,11 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
} else {
v &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
m &= ~ESDHC_MIX_CTRL_FBCLK_SEL;
- m &= ~ESDHC_MIX_CTRL_AUTO_TUNE_EN;
}
if (val & SDHCI_CTRL_EXEC_TUNING) {
v |= ESDHC_MIX_CTRL_EXE_TUNE;
m |= ESDHC_MIX_CTRL_FBCLK_SEL;
- m |= ESDHC_MIX_CTRL_AUTO_TUNE_EN;
- usdhc_auto_tuning_mode_sel(host);
} else {
v &= ~ESDHC_MIX_CTRL_EXE_TUNE;
}
@@ -1023,13 +1051,15 @@ static void esdhc_reset_tuning(struct sdhci_host *host)
/* Reset the tuning circuit */
if (esdhc_is_usdhc(imx_data)) {
+ ctrl = readl(host->ioaddr + ESDHC_MIX_CTRL);
+ ctrl &= ~ESDHC_MIX_CTRL_AUTO_TUNE_EN;
if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) {
- ctrl = readl(host->ioaddr + ESDHC_MIX_CTRL);
ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
ctrl &= ~ESDHC_MIX_CTRL_FBCLK_SEL;
writel(ctrl, host->ioaddr + ESDHC_MIX_CTRL);
writel(0, host->ioaddr + ESDHC_TUNE_CTRL_STATUS);
} else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) {
+ writel(ctrl, host->ioaddr + ESDHC_MIX_CTRL);
ctrl = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS);
ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
ctrl &= ~ESDHC_MIX_CTRL_EXE_TUNE;
@@ -1052,9 +1082,19 @@ static void esdhc_reset_tuning(struct sdhci_host *host)
}
}
+static void usdhc_init_card(struct mmc_host *mmc, struct mmc_card *card)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
+
+ imx_data->init_card_type = card->type;
+}
+
static int usdhc_execute_tuning(struct mmc_host *mmc, u32 opcode)
{
struct sdhci_host *host = mmc_priv(mmc);
+ int err;
/*
* i.MX uSDHC internally already uses a fixed optimized timing for
@@ -1069,7 +1109,12 @@ static int usdhc_execute_tuning(struct mmc_host *mmc, u32 opcode)
* correct delay cell.
*/
esdhc_reset_tuning(host);
- return sdhci_execute_tuning(mmc, opcode);
+ err = sdhci_execute_tuning(mmc, opcode);
+ /* If tuning done, enable auto tuning */
+ if (!err && !host->tuning_err)
+ usdhc_auto_tuning_mode_sel_and_en(host);
+
+ return err;
}
static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val)
@@ -1103,11 +1148,8 @@ static void esdhc_post_tuning(struct sdhci_host *host)
{
u32 reg;
- usdhc_auto_tuning_mode_sel(host);
-
reg = readl(host->ioaddr + ESDHC_MIX_CTRL);
reg &= ~ESDHC_MIX_CTRL_EXE_TUNE;
- reg |= ESDHC_MIX_CTRL_AUTO_TUNE_EN;
writel(reg, host->ioaddr + ESDHC_MIX_CTRL);
}
@@ -1674,6 +1716,12 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
* to replace the standard one in sdhci_ops.
*/
host->mmc_host_ops.execute_tuning = usdhc_execute_tuning;
+
+ /*
+ * Link usdhc specific mmc_host_ops init card function,
+ * to distinguish the card type.
+ */
+ host->mmc_host_ops.init_card = usdhc_init_card;
}
err = sdhci_esdhc_imx_probe_dt(pdev, host, imx_data);
diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c
index 6db35b1b8557..86eb0045515e 100644
--- a/drivers/mmc/host/sdhci-iproc.c
+++ b/drivers/mmc/host/sdhci-iproc.c
@@ -18,6 +18,7 @@ struct sdhci_iproc_data {
u32 caps;
u32 caps1;
u32 mmc_caps;
+ bool missing_caps;
};
struct sdhci_iproc_host {
@@ -251,7 +252,6 @@ static const struct sdhci_iproc_data iproc_data = {
static const struct sdhci_pltfm_data sdhci_bcm2835_pltfm_data = {
.quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION |
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
- SDHCI_QUIRK_MISSING_CAPS |
SDHCI_QUIRK_NO_HISPD_BIT,
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
.ops = &sdhci_iproc_32only_ops,
@@ -266,6 +266,7 @@ static const struct sdhci_iproc_data bcm2835_data = {
.caps1 = SDHCI_DRIVER_TYPE_A |
SDHCI_DRIVER_TYPE_C,
.mmc_caps = 0x00000000,
+ .missing_caps = true,
};
static const struct sdhci_ops sdhci_iproc_bcm2711_ops = {
@@ -295,8 +296,7 @@ static const struct sdhci_iproc_data bcm2711_data = {
};
static const struct sdhci_pltfm_data sdhci_bcm7211a0_pltfm_data = {
- .quirks = SDHCI_QUIRK_MISSING_CAPS |
- SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
+ .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
SDHCI_QUIRK_BROKEN_DMA |
SDHCI_QUIRK_BROKEN_ADMA,
.ops = &sdhci_iproc_ops,
@@ -315,6 +315,7 @@ static const struct sdhci_iproc_data bcm7211a0_data = {
SDHCI_CAN_DO_HISPD,
.caps1 = SDHCI_DRIVER_TYPE_C |
SDHCI_DRIVER_TYPE_D,
+ .missing_caps = true,
};
static const struct of_device_id sdhci_iproc_of_match[] = {
@@ -397,9 +398,10 @@ static int sdhci_iproc_probe(struct platform_device *pdev)
}
}
- if (iproc_host->data->pdata->quirks & SDHCI_QUIRK_MISSING_CAPS) {
- host->caps = iproc_host->data->caps;
- host->caps1 = iproc_host->data->caps1;
+ if (iproc_host->data->missing_caps) {
+ __sdhci_read_caps(host, NULL,
+ &iproc_host->data->caps,
+ &iproc_host->data->caps1);
}
ret = sdhci_add_host(host);
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 4ac8651d0b29..8ac81d57a3df 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -13,7 +13,7 @@
#include <linux/pm_opp.h>
#include <linux/slab.h>
#include <linux/iopoll.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/regulator/consumer.h>
#include <linux/interconnect.h>
#include <linux/pinctrl/consumer.h>
diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c
index a7343d4bc50e..d1490469184b 100644
--- a/drivers/mmc/host/sdhci-of-dwcmshc.c
+++ b/drivers/mmc/host/sdhci-of-dwcmshc.c
@@ -48,6 +48,7 @@
#define DWCMSHC_EMMC_DLL_RXCLK_SRCSEL 29
#define DWCMSHC_EMMC_DLL_START_POINT 16
#define DWCMSHC_EMMC_DLL_INC 8
+#define DWCMSHC_EMMC_DLL_BYPASS BIT(24)
#define DWCMSHC_EMMC_DLL_DLYENA BIT(27)
#define DLL_TXCLK_TAPNUM_DEFAULT 0x10
#define DLL_TXCLK_TAPNUM_90_DEGREES 0xA
@@ -60,6 +61,7 @@
#define DLL_RXCLK_NO_INVERTER 1
#define DLL_RXCLK_INVERTER 0
#define DLL_CMDOUT_TAPNUM_90_DEGREES 0x8
+#define DLL_RXCLK_ORI_GATE BIT(31)
#define DLL_CMDOUT_TAPNUM_FROM_SW BIT(24)
#define DLL_CMDOUT_SRC_CLK_NEG BIT(28)
#define DLL_CMDOUT_EN_SRC_CLK_NEG BIT(29)
@@ -234,9 +236,12 @@ static void dwcmshc_rk3568_set_clock(struct sdhci_host *host, unsigned int clock
sdhci_writel(host, extra, reg);
if (clock <= 52000000) {
- /* Disable DLL and reset both of sample and drive clock */
- sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_CTRL);
- sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_RXCLK);
+ /*
+ * Disable DLL and reset both of sample and drive clock.
+ * The bypass bit and start bit need to be set if DLL is not locked.
+ */
+ sdhci_writel(host, DWCMSHC_EMMC_DLL_BYPASS | DWCMSHC_EMMC_DLL_START, DWCMSHC_EMMC_DLL_CTRL);
+ sdhci_writel(host, DLL_RXCLK_ORI_GATE, DWCMSHC_EMMC_DLL_RXCLK);
sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_TXCLK);
sdhci_writel(host, 0, DECMSHC_EMMC_DLL_CMDOUT);
/*
@@ -279,7 +284,7 @@ static void dwcmshc_rk3568_set_clock(struct sdhci_host *host, unsigned int clock
}
extra = 0x1 << 16 | /* tune clock stop en */
- 0x2 << 17 | /* pre-change delay */
+ 0x3 << 17 | /* pre-change delay */
0x3 << 19; /* post-change delay */
sdhci_writel(host, extra, dwc_priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL);
@@ -446,6 +451,7 @@ static const struct acpi_device_id sdhci_dwcmshc_acpi_ids[] = {
},
{}
};
+MODULE_DEVICE_TABLE(acpi, sdhci_dwcmshc_acpi_ids);
#endif
static int dwcmshc_probe(struct platform_device *pdev)
@@ -528,6 +534,11 @@ static int dwcmshc_probe(struct platform_device *pdev)
goto err_clk;
}
+#ifdef CONFIG_ACPI
+ if (pltfm_data == &sdhci_dwcmshc_bf3_pdata)
+ sdhci_enable_v4_mode(host);
+#endif
+
host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
err = sdhci_setup_host(host);
diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c
index c359f867df0a..01975d145200 100644
--- a/drivers/mmc/host/sdhci-pci-core.c
+++ b/drivers/mmc/host/sdhci-pci-core.c
@@ -251,13 +251,16 @@ static int ricoh_probe(struct sdhci_pci_chip *chip)
static int ricoh_mmc_probe_slot(struct sdhci_pci_slot *slot)
{
- slot->host->caps =
+ u32 caps =
FIELD_PREP(SDHCI_TIMEOUT_CLK_MASK, 0x21) |
FIELD_PREP(SDHCI_CLOCK_BASE_MASK, 0x21) |
SDHCI_TIMEOUT_CLK_UNIT |
SDHCI_CAN_VDD_330 |
SDHCI_CAN_DO_HISPD |
SDHCI_CAN_DO_SDMA;
+ u32 caps1 = 0;
+
+ __sdhci_read_caps(slot->host, NULL, &caps, &caps1);
return 0;
}
@@ -286,8 +289,7 @@ static const struct sdhci_pci_fixes sdhci_ricoh_mmc = {
#endif
.quirks = SDHCI_QUIRK_32BIT_DMA_ADDR |
SDHCI_QUIRK_CLOCK_BEFORE_RESET |
- SDHCI_QUIRK_NO_CARD_NO_RESET |
- SDHCI_QUIRK_MISSING_CAPS
+ SDHCI_QUIRK_NO_CARD_NO_RESET,
};
static void ene_714_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
diff --git a/drivers/mmc/host/sdhci-pxav2.c b/drivers/mmc/host/sdhci-pxav2.c
index f18906b5575f..fc306eb1f845 100644
--- a/drivers/mmc/host/sdhci-pxav2.c
+++ b/drivers/mmc/host/sdhci-pxav2.c
@@ -20,6 +20,9 @@
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/mmc.h>
+#include <linux/pinctrl/consumer.h>
#include "sdhci.h"
#include "sdhci-pltfm.h"
@@ -41,6 +44,13 @@
#define MMC_CARD 0x1000
#define MMC_WIDTH 0x0100
+struct sdhci_pxav2_host {
+ struct mmc_request *sdio_mrq;
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *pins_default;
+ struct pinctrl_state *pins_cmd_gpio;
+};
+
static void pxav2_reset(struct sdhci_host *host, u8 mask)
{
struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc));
@@ -80,6 +90,71 @@ static void pxav2_reset(struct sdhci_host *host, u8 mask)
}
}
+static u16 pxav1_readw(struct sdhci_host *host, int reg)
+{
+ /* Workaround for data abort exception on SDH2 and SDH4 on PXA168 */
+ if (reg == SDHCI_HOST_VERSION)
+ return readl(host->ioaddr + SDHCI_HOST_VERSION - 2) >> 16;
+
+ return readw(host->ioaddr + reg);
+}
+
+static u32 pxav1_irq(struct sdhci_host *host, u32 intmask)
+{
+ struct sdhci_pxav2_host *pxav2_host = sdhci_pltfm_priv(sdhci_priv(host));
+ struct mmc_request *sdio_mrq;
+
+ if (pxav2_host->sdio_mrq && (intmask & SDHCI_INT_CMD_MASK)) {
+ /* The dummy CMD0 for the SDIO workaround just completed */
+ sdhci_writel(host, intmask & SDHCI_INT_CMD_MASK, SDHCI_INT_STATUS);
+ intmask &= ~SDHCI_INT_CMD_MASK;
+
+ /* Restore MMC function to CMD pin */
+ if (pxav2_host->pinctrl && pxav2_host->pins_default)
+ pinctrl_select_state(pxav2_host->pinctrl, pxav2_host->pins_default);
+
+ sdio_mrq = pxav2_host->sdio_mrq;
+ pxav2_host->sdio_mrq = NULL;
+ mmc_request_done(host->mmc, sdio_mrq);
+ }
+
+ return intmask;
+}
+
+static void pxav1_request_done(struct sdhci_host *host, struct mmc_request *mrq)
+{
+ u16 tmp;
+ struct sdhci_pxav2_host *pxav2_host;
+
+ /* If this is an SDIO command, perform errata workaround for silicon bug */
+ if (mrq->cmd && !mrq->cmd->error &&
+ (mrq->cmd->opcode == SD_IO_RW_DIRECT ||
+ mrq->cmd->opcode == SD_IO_RW_EXTENDED)) {
+ /* Reset data port */
+ tmp = readw(host->ioaddr + SDHCI_TIMEOUT_CONTROL);
+ tmp |= 0x400;
+ writew(tmp, host->ioaddr + SDHCI_TIMEOUT_CONTROL);
+
+ /* Clock is now stopped, so restart it by sending a dummy CMD0 */
+ pxav2_host = sdhci_pltfm_priv(sdhci_priv(host));
+ pxav2_host->sdio_mrq = mrq;
+
+ /* Set CMD as high output rather than MMC function while we do CMD0 */
+ if (pxav2_host->pinctrl && pxav2_host->pins_cmd_gpio)
+ pinctrl_select_state(pxav2_host->pinctrl, pxav2_host->pins_cmd_gpio);
+
+ sdhci_writel(host, 0, SDHCI_ARGUMENT);
+ sdhci_writew(host, 0, SDHCI_TRANSFER_MODE);
+ sdhci_writew(host, SDHCI_MAKE_CMD(MMC_GO_IDLE_STATE, SDHCI_CMD_RESP_NONE),
+ SDHCI_COMMAND);
+
+ /* Don't finish this request until the dummy CMD0 finishes */
+ return;
+ }
+
+ mmc_request_done(host->mmc, mrq);
+}
+
static void pxav2_mmc_set_bus_width(struct sdhci_host *host, int width)
{
u8 ctrl;
@@ -101,6 +176,27 @@ static void pxav2_mmc_set_bus_width(struct sdhci_host *host, int width)
writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
}
+struct sdhci_pxa_variant {
+ const struct sdhci_ops *ops;
+ unsigned int extra_quirks;
+};
+
+static const struct sdhci_ops pxav1_sdhci_ops = {
+ .read_w = pxav1_readw,
+ .set_clock = sdhci_set_clock,
+ .irq = pxav1_irq,
+ .get_max_clock = sdhci_pltfm_clk_get_max_clock,
+ .set_bus_width = pxav2_mmc_set_bus_width,
+ .reset = pxav2_reset,
+ .set_uhs_signaling = sdhci_set_uhs_signaling,
+ .request_done = pxav1_request_done,
+};
+
+static const struct sdhci_pxa_variant __maybe_unused pxav1_variant = {
+ .ops = &pxav1_sdhci_ops,
+ .extra_quirks = SDHCI_QUIRK_NO_BUSY_IRQ | SDHCI_QUIRK_32BIT_DMA_SIZE,
+};
+
static const struct sdhci_ops pxav2_sdhci_ops = {
.set_clock = sdhci_set_clock,
.get_max_clock = sdhci_pltfm_clk_get_max_clock,
@@ -109,11 +205,14 @@ static const struct sdhci_ops pxav2_sdhci_ops = {
.set_uhs_signaling = sdhci_set_uhs_signaling,
};
+static const struct sdhci_pxa_variant pxav2_variant = {
+ .ops = &pxav2_sdhci_ops,
+};
+
#ifdef CONFIG_OF
static const struct of_device_id sdhci_pxav2_of_match[] = {
- {
- .compatible = "mrvl,pxav2-mmc",
- },
+ { .compatible = "mrvl,pxav1-mmc", .data = &pxav1_variant, },
+ { .compatible = "mrvl,pxav2-mmc", .data = &pxav2_variant, },
{},
};
MODULE_DEVICE_TABLE(of, sdhci_pxav2_of_match);
@@ -155,40 +254,53 @@ static int sdhci_pxav2_probe(struct platform_device *pdev)
{
struct sdhci_pltfm_host *pltfm_host;
struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data;
+ struct sdhci_pxav2_host *pxav2_host;
struct device *dev = &pdev->dev;
struct sdhci_host *host = NULL;
- const struct of_device_id *match;
+ const struct sdhci_pxa_variant *variant;
int ret;
- struct clk *clk;
+ struct clk *clk, *clk_core;
- host = sdhci_pltfm_init(pdev, NULL, 0);
+ host = sdhci_pltfm_init(pdev, NULL, sizeof(*pxav2_host));
if (IS_ERR(host))
return PTR_ERR(host);
pltfm_host = sdhci_priv(host);
+ pxav2_host = sdhci_pltfm_priv(pltfm_host);
- clk = devm_clk_get(dev, "PXA-SDHCLK");
+ clk = devm_clk_get(dev, "io");
+ if (IS_ERR(clk) && PTR_ERR(clk) != -EPROBE_DEFER)
+ clk = devm_clk_get(dev, NULL);
if (IS_ERR(clk)) {
- dev_err(dev, "failed to get io clock\n");
ret = PTR_ERR(clk);
+ dev_err_probe(dev, ret, "failed to get io clock\n");
goto free;
}
pltfm_host->clk = clk;
ret = clk_prepare_enable(clk);
if (ret) {
- dev_err(&pdev->dev, "failed to enable io clock\n");
+ dev_err(dev, "failed to enable io clock\n");
goto free;
}
+ clk_core = devm_clk_get_optional_enabled(dev, "core");
+ if (IS_ERR(clk_core)) {
+ ret = PTR_ERR(clk_core);
+ dev_err_probe(dev, ret, "failed to enable core clock\n");
+ goto disable_clk;
+ }
+
host->quirks = SDHCI_QUIRK_BROKEN_ADMA
| SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
| SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN;
- match = of_match_device(of_match_ptr(sdhci_pxav2_of_match), &pdev->dev);
- if (match) {
+ variant = of_device_get_match_data(dev);
+ if (variant)
pdata = pxav2_get_mmc_pdata(dev);
- }
+ else
+ variant = &pxav2_variant;
+
if (pdata) {
if (pdata->flags & PXA_FLAG_CARD_PERMANENT) {
/* on-chip device */
@@ -208,7 +320,23 @@ static int sdhci_pxav2_probe(struct platform_device *pdev)
host->mmc->pm_caps |= pdata->pm_caps;
}
- host->ops = &pxav2_sdhci_ops;
+ host->quirks |= variant->extra_quirks;
+ host->ops = variant->ops;
+
+ /* Set up optional pinctrl for PXA168 SDIO IRQ fix */
+ pxav2_host->pinctrl = devm_pinctrl_get(dev);
+ if (!IS_ERR(pxav2_host->pinctrl)) {
+ pxav2_host->pins_cmd_gpio = pinctrl_lookup_state(pxav2_host->pinctrl,
+ "state_cmd_gpio");
+ if (IS_ERR(pxav2_host->pins_cmd_gpio))
+ pxav2_host->pins_cmd_gpio = NULL;
+ pxav2_host->pins_default = pinctrl_lookup_state(pxav2_host->pinctrl,
+ "default");
+ if (IS_ERR(pxav2_host->pins_default))
+ pxav2_host->pins_default = NULL;
+ } else {
+ pxav2_host->pinctrl = NULL;
+ }
ret = sdhci_add_host(host);
if (ret)
diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c
index a6d89a3f1946..e39dcc998772 100644
--- a/drivers/mmc/host/sdhci-pxav3.c
+++ b/drivers/mmc/host/sdhci-pxav3.c
@@ -124,10 +124,8 @@ static int armada_38x_quirks(struct platform_device *pdev,
struct resource *res;
host->quirks &= ~SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN;
- host->quirks |= SDHCI_QUIRK_MISSING_CAPS;
- host->caps = sdhci_readl(host, SDHCI_CAPABILITIES);
- host->caps1 = sdhci_readl(host, SDHCI_CAPABILITIES_1);
+ sdhci_read_caps(host);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"conf-sdio3");
diff --git a/drivers/mmc/host/sdhci-sprd.c b/drivers/mmc/host/sdhci-sprd.c
index 525f979e2a97..7f4ee2e12735 100644
--- a/drivers/mmc/host/sdhci-sprd.c
+++ b/drivers/mmc/host/sdhci-sprd.c
@@ -553,8 +553,7 @@ static void sdhci_sprd_phy_param_parse(struct sdhci_sprd_host *sprd_host,
static const struct sdhci_pltfm_data sdhci_sprd_pdata = {
.quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION |
- SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
- SDHCI_QUIRK_MISSING_CAPS,
+ SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK,
.quirks2 = SDHCI_QUIRK2_BROKEN_HS200 |
SDHCI_QUIRK2_USE_32BIT_BLK_CNT |
SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
@@ -671,8 +670,7 @@ static int sdhci_sprd_probe(struct platform_device *pdev)
* will allow these modes to be specified only by device
* tree properties through mmc_of_parse().
*/
- host->caps = sdhci_readl(host, SDHCI_CAPABILITIES);
- host->caps1 = sdhci_readl(host, SDHCI_CAPABILITIES_1);
+ sdhci_read_caps(host);
host->caps1 &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_SDR104 |
SDHCI_SUPPORT_DDR50);
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index f3af1bd0f7b9..3241916141d7 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -4121,9 +4121,6 @@ void __sdhci_read_caps(struct sdhci_host *host, const u16 *ver,
v = ver ? *ver : sdhci_readw(host, SDHCI_HOST_VERSION);
host->version = (v & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT;
- if (host->quirks & SDHCI_QUIRK_MISSING_CAPS)
- return;
-
if (caps) {
host->caps = *caps;
} else {
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 605eaee805f7..f4f2085c274c 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -423,8 +423,6 @@ struct sdhci_host {
#define SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN (1<<25)
/* Controller cannot support End Attribute in NOP ADMA descriptor */
#define SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC (1<<26)
-/* Controller is missing device caps. Use caps provided by host */
-#define SDHCI_QUIRK_MISSING_CAPS (1<<27)
/* Controller uses Auto CMD12 command to stop the transfer */
#define SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12 (1<<28)
/* Controller doesn't have HISPD bit field in HI-SPEED SD card */
diff --git a/drivers/mmc/host/uniphier-sd.c b/drivers/mmc/host/uniphier-sd.c
index 3a8defdcca77..61acd69fac0e 100644
--- a/drivers/mmc/host/uniphier-sd.c
+++ b/drivers/mmc/host/uniphier-sd.c
@@ -8,6 +8,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
+#include <linux/mfd/syscon.h>
#include <linux/mfd/tmio.h>
#include <linux/mmc/host.h>
#include <linux/module.h>
@@ -15,6 +16,7 @@
#include <linux/of_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
+#include <linux/regmap.h>
#include <linux/reset.h>
#include "tmio_mmc.h"
@@ -48,6 +50,12 @@
#define UNIPHIER_SD_DMA_ADDR_L 0x440
#define UNIPHIER_SD_DMA_ADDR_H 0x444
+/* SD control */
+#define UNIPHIER_SDCTRL_CHOFFSET 0x200
+#define UNIPHIER_SDCTRL_MODE 0x30
+#define UNIPHIER_SDCTRL_MODE_UHS1MOD BIT(15)
+#define UNIPHIER_SDCTRL_MODE_SDRSEL BIT(14)
+
/*
* IP is extended to support various features: built-in DMA engine,
* 1/1024 divisor, etc.
@@ -66,6 +74,8 @@ struct uniphier_sd_priv {
struct reset_control *rst_hw;
struct dma_chan *chan;
enum dma_data_direction dma_dir;
+ struct regmap *sdctrl_regmap;
+ u32 sdctrl_ch;
unsigned long clk_rate;
unsigned long caps;
};
@@ -420,6 +430,42 @@ static void uniphier_sd_hw_reset(struct mmc_host *mmc)
usleep_range(300, 1000);
}
+static void uniphier_sd_speed_switch(struct tmio_mmc_host *host)
+{
+ struct uniphier_sd_priv *priv = uniphier_sd_priv(host);
+ unsigned int offset;
+ u32 val = 0;
+
+ if (!(host->mmc->caps & MMC_CAP_UHS))
+ return;
+
+ if (host->mmc->ios.timing == MMC_TIMING_UHS_SDR50 ||
+ host->mmc->ios.timing == MMC_TIMING_UHS_SDR104)
+ val = UNIPHIER_SDCTRL_MODE_SDRSEL;
+
+ offset = UNIPHIER_SDCTRL_CHOFFSET * priv->sdctrl_ch
+ + UNIPHIER_SDCTRL_MODE;
+ regmap_write_bits(priv->sdctrl_regmap, offset,
+ UNIPHIER_SDCTRL_MODE_SDRSEL, val);
+}
+
+static void uniphier_sd_uhs_enable(struct tmio_mmc_host *host, bool uhs_en)
+{
+ struct uniphier_sd_priv *priv = uniphier_sd_priv(host);
+ unsigned int offset;
+ u32 val;
+
+ if (!(host->mmc->caps & MMC_CAP_UHS))
+ return;
+
+ val = (uhs_en) ? UNIPHIER_SDCTRL_MODE_UHS1MOD : 0;
+
+ offset = UNIPHIER_SDCTRL_CHOFFSET * priv->sdctrl_ch
+ + UNIPHIER_SDCTRL_MODE;
+ regmap_write_bits(priv->sdctrl_regmap, offset,
+ UNIPHIER_SDCTRL_MODE_UHS1MOD, val);
+}
+
static void uniphier_sd_set_clock(struct tmio_mmc_host *host,
unsigned int clock)
{
@@ -433,6 +479,8 @@ static void uniphier_sd_set_clock(struct tmio_mmc_host *host,
tmp &= ~CLK_CTL_SCLKEN;
writel(tmp, host->ctl + (CTL_SD_CARD_CLK_CTL << 1));
+ uniphier_sd_speed_switch(host);
+
if (clock == 0)
return;
@@ -500,14 +548,17 @@ static int uniphier_sd_start_signal_voltage_switch(struct mmc_host *mmc,
struct uniphier_sd_priv *priv = uniphier_sd_priv(host);
struct pinctrl_state *pinstate = NULL;
u32 val, tmp;
+ bool uhs_en;
switch (ios->signal_voltage) {
case MMC_SIGNAL_VOLTAGE_330:
val = UNIPHIER_SD_VOLT_330;
+ uhs_en = false;
break;
case MMC_SIGNAL_VOLTAGE_180:
val = UNIPHIER_SD_VOLT_180;
pinstate = priv->pinstate_uhs;
+ uhs_en = true;
break;
default:
return -ENOTSUPP;
@@ -523,12 +574,19 @@ static int uniphier_sd_start_signal_voltage_switch(struct mmc_host *mmc,
else
pinctrl_select_default_state(mmc_dev(mmc));
+ uniphier_sd_uhs_enable(host, uhs_en);
+
return 0;
}
-static int uniphier_sd_uhs_init(struct tmio_mmc_host *host,
- struct uniphier_sd_priv *priv)
+static int uniphier_sd_uhs_init(struct tmio_mmc_host *host)
{
+ struct uniphier_sd_priv *priv = uniphier_sd_priv(host);
+ struct device *dev = &host->pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct of_phandle_args args;
+ int ret;
+
priv->pinctrl = devm_pinctrl_get(mmc_dev(host->mmc));
if (IS_ERR(priv->pinctrl))
return PTR_ERR(priv->pinctrl);
@@ -537,8 +595,20 @@ static int uniphier_sd_uhs_init(struct tmio_mmc_host *host,
if (IS_ERR(priv->pinstate_uhs))
return PTR_ERR(priv->pinstate_uhs);
- host->ops.start_signal_voltage_switch =
- uniphier_sd_start_signal_voltage_switch;
+ ret = of_parse_phandle_with_fixed_args(np,
+ "socionext,syscon-uhs-mode",
+ 1, 0, &args);
+ if (ret) {
+ dev_err(dev, "Can't get syscon-uhs-mode property\n");
+ return ret;
+ }
+ priv->sdctrl_regmap = syscon_node_to_regmap(args.np);
+ of_node_put(args.np);
+ if (IS_ERR(priv->sdctrl_regmap)) {
+ dev_err(dev, "Can't map syscon-uhs-mode\n");
+ return PTR_ERR(priv->sdctrl_regmap);
+ }
+ priv->sdctrl_ch = args.args[0];
return 0;
}
@@ -601,12 +671,15 @@ static int uniphier_sd_probe(struct platform_device *pdev)
}
if (host->mmc->caps & MMC_CAP_UHS) {
- ret = uniphier_sd_uhs_init(host, priv);
+ ret = uniphier_sd_uhs_init(host);
if (ret) {
dev_warn(dev,
"failed to setup UHS (error %d). Disabling UHS.",
ret);
host->mmc->caps &= ~MMC_CAP_UHS;
+ } else {
+ host->ops.start_signal_voltage_switch =
+ uniphier_sd_start_signal_voltage_switch;
}
}
diff --git a/drivers/most/Kconfig b/drivers/most/Kconfig
index 4b8145b9e7ad..69c9e728b7e6 100644
--- a/drivers/most/Kconfig
+++ b/drivers/most/Kconfig
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
menuconfig MOST
- tristate "MOST support"
+ tristate "MOST (Media Oriented Systems Transport) support"
depends on HAS_DMA && CONFIGFS_FS
default n
help
diff --git a/drivers/most/most_cdev.c b/drivers/most/most_cdev.c
index 3722f9abd7b9..4ee536980f71 100644
--- a/drivers/most/most_cdev.c
+++ b/drivers/most/most_cdev.c
@@ -297,7 +297,7 @@ static __poll_t comp_poll(struct file *filp, poll_table *wait)
return mask;
}
-/**
+/*
* Initialization of struct file_operations
*/
static const struct file_operations channel_fops = {
@@ -404,8 +404,9 @@ static int comp_tx_completion(struct most_interface *iface, int channel_id)
* @channel_id: channel index/ID
* @cfg: pointer to actual channel configuration
* @name: name of the device to be created
+ * @args: pointer to array of component parameters (from configfs)
*
- * This allocates achannel object and creates the device node in /dev
+ * This allocates a channel object and creates the device node in /dev
*
* Returns 0 on success or error code otherwise.
*/
diff --git a/drivers/most/most_snd.c b/drivers/most/most_snd.c
index c87f6a037874..45d762804c5e 100644
--- a/drivers/most/most_snd.c
+++ b/drivers/most/most_snd.c
@@ -27,6 +27,7 @@ static struct most_component comp;
/**
* struct channel - private structure to keep channel specific data
* @substream: stores the substream structure
+ * @pcm_hardware: low-level hardware description
* @iface: interface for which the channel belongs to
* @cfg: channel configuration
* @card: registered sound card
@@ -38,6 +39,7 @@ static struct most_component comp;
* @opened: set when the stream is opened
* @playback_task: playback thread
* @playback_waitq: waitq used by playback thread
+ * @copy_fn: copy function for PCM-specific format and width
*/
struct channel {
struct snd_pcm_substream *substream;
@@ -400,7 +402,7 @@ static snd_pcm_uframes_t pcm_pointer(struct snd_pcm_substream *substream)
return channel->buffer_pos;
}
-/**
+/*
* Initialization of struct snd_pcm_ops
*/
static const struct snd_pcm_ops pcm_ops = {
@@ -501,8 +503,8 @@ static void release_adapter(struct sound_adapter *adpt)
* @iface: pointer to interface instance
* @channel_id: channel index/ID
* @cfg: pointer to actual channel configuration
- * @arg_list: string that provides the name of the device to be created in /dev
- * plus the desired audio resolution
+ * @device_name: name of the device to be created in /dev
+ * @arg_list: string that provides the desired audio resolution
*
* Creates sound card, pcm device, sets pcm ops and registers sound card.
*
@@ -699,7 +701,7 @@ static int audio_tx_completion(struct most_interface *iface, int channel_id)
return 0;
}
-/**
+/*
* Initialization of the struct most_component
*/
static struct most_component comp = {
diff --git a/drivers/most/most_usb.c b/drivers/most/most_usb.c
index 73258b24fea7..485d5ca39951 100644
--- a/drivers/most/most_usb.c
+++ b/drivers/most/most_usb.c
@@ -660,7 +660,7 @@ static void hdm_request_netinfo(struct most_interface *iface, int channel,
/**
* link_stat_timer_handler - schedule work obtaining mac address and link status
- * @data: pointer to USB device instance
+ * @t: pointer to timer_list which holds a pointer to the USB device instance
*
* The handler runs in interrupt context. That's why we need to defer the
* tasks to a work queue.
@@ -763,14 +763,14 @@ static void wq_clear_halt(struct work_struct *wq_obj)
mutex_unlock(&mdev->io_mutex);
}
-/**
+/*
* hdm_usb_fops - file operation table for USB driver
*/
static const struct file_operations hdm_usb_fops = {
.owner = THIS_MODULE,
};
-/**
+/*
* usb_device_id - ID table for HCD device probing
*/
static const struct usb_device_id usbid[] = {
diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c
index 25bad4318305..3bbaa590c768 100644
--- a/drivers/mtd/devices/mtd_dataflash.c
+++ b/drivers/mtd/devices/mtd_dataflash.c
@@ -96,13 +96,6 @@ struct dataflash {
struct mtd_info mtd;
};
-static const struct spi_device_id dataflash_dev_ids[] = {
- { "at45" },
- { "dataflash" },
- { },
-};
-MODULE_DEVICE_TABLE(spi, dataflash_dev_ids);
-
#ifdef CONFIG_OF
static const struct of_device_id dataflash_dt_ids[] = {
{ .compatible = "atmel,at45", },
@@ -939,8 +932,6 @@ static struct spi_driver dataflash_driver = {
.name = "mtd_dataflash",
.of_match_table = of_match_ptr(dataflash_dt_ids),
},
- .id_table = dataflash_dev_ids,
-
.probe = dataflash_probe,
.remove = dataflash_remove,
.id_table = dataflash_spi_ids,
diff --git a/drivers/mtd/hyperbus/rpc-if.c b/drivers/mtd/hyperbus/rpc-if.c
index d00d30243403..ef32fca5f785 100644
--- a/drivers/mtd/hyperbus/rpc-if.c
+++ b/drivers/mtd/hyperbus/rpc-if.c
@@ -56,7 +56,7 @@ static void rpcif_hb_prepare_read(struct rpcif *rpc, void *to,
op.data.nbytes = len;
op.data.buf.in = to;
- rpcif_prepare(rpc, &op, NULL, NULL);
+ rpcif_prepare(rpc->dev, &op, NULL, NULL);
}
static void rpcif_hb_prepare_write(struct rpcif *rpc, unsigned long to,
@@ -70,7 +70,7 @@ static void rpcif_hb_prepare_write(struct rpcif *rpc, unsigned long to,
op.data.nbytes = len;
op.data.buf.out = from;
- rpcif_prepare(rpc, &op, NULL, NULL);
+ rpcif_prepare(rpc->dev, &op, NULL, NULL);
}
static u16 rpcif_hb_read16(struct hyperbus_device *hbdev, unsigned long addr)
@@ -81,7 +81,7 @@ static u16 rpcif_hb_read16(struct hyperbus_device *hbdev, unsigned long addr)
rpcif_hb_prepare_read(&hyperbus->rpc, &data, addr, 2);
- rpcif_manual_xfer(&hyperbus->rpc);
+ rpcif_manual_xfer(hyperbus->rpc.dev);
return data.x[0];
}
@@ -94,7 +94,7 @@ static void rpcif_hb_write16(struct hyperbus_device *hbdev, unsigned long addr,
rpcif_hb_prepare_write(&hyperbus->rpc, addr, &data, 2);
- rpcif_manual_xfer(&hyperbus->rpc);
+ rpcif_manual_xfer(hyperbus->rpc.dev);
}
static void rpcif_hb_copy_from(struct hyperbus_device *hbdev, void *to,
@@ -105,7 +105,7 @@ static void rpcif_hb_copy_from(struct hyperbus_device *hbdev, void *to,
rpcif_hb_prepare_read(&hyperbus->rpc, to, from, len);
- rpcif_dirmap_read(&hyperbus->rpc, from, len, to);
+ rpcif_dirmap_read(hyperbus->rpc.dev, from, len, to);
}
static const struct hyperbus_ops rpcif_hb_ops = {
@@ -130,9 +130,9 @@ static int rpcif_hb_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, hyperbus);
- rpcif_enable_rpm(&hyperbus->rpc);
+ pm_runtime_enable(hyperbus->rpc.dev);
- error = rpcif_hw_init(&hyperbus->rpc, true);
+ error = rpcif_hw_init(hyperbus->rpc.dev, true);
if (error)
goto out_disable_rpm;
@@ -150,7 +150,7 @@ static int rpcif_hb_probe(struct platform_device *pdev)
return 0;
out_disable_rpm:
- rpcif_disable_rpm(&hyperbus->rpc);
+ pm_runtime_disable(hyperbus->rpc.dev);
return error;
}
@@ -160,7 +160,7 @@ static int rpcif_hb_remove(struct platform_device *pdev)
hyperbus_unregister_device(&hyperbus->hbdev);
- rpcif_disable_rpm(&hyperbus->rpc);
+ pm_runtime_disable(hyperbus->rpc.dev);
return 0;
}
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index d442fa94c872..85f5ee6f06fc 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -577,6 +577,7 @@ static int mtd_part_of_parse(struct mtd_info *master,
{
struct mtd_part_parser *parser;
struct device_node *np;
+ struct device_node *child;
struct property *prop;
struct device *dev;
const char *compat;
@@ -594,6 +595,15 @@ static int mtd_part_of_parse(struct mtd_info *master,
else
np = of_get_child_by_name(np, "partitions");
+ /*
+ * Don't create devices that are added to a bus but will never get
+ * probed. That'll cause fw_devlink to block probing of consumers of
+ * this partition until the partition device is probed.
+ */
+ for_each_child_of_node(np, child)
+ if (of_device_is_compatible(child, "nvmem-cells"))
+ of_node_set_flag(child, OF_POPULATED);
+
of_property_for_each_string(np, "compatible", prop, compat) {
parser = mtd_part_get_compatible_parser(compat);
if (!parser)
diff --git a/drivers/mtd/nand/ecc-mtk.c b/drivers/mtd/nand/ecc-mtk.c
index 9f9b201fe706..c75bb8b80cc1 100644
--- a/drivers/mtd/nand/ecc-mtk.c
+++ b/drivers/mtd/nand/ecc-mtk.c
@@ -40,6 +40,10 @@
#define ECC_IDLE_REG(op) ((op) == ECC_ENCODE ? ECC_ENCIDLE : ECC_DECIDLE)
#define ECC_CTL_REG(op) ((op) == ECC_ENCODE ? ECC_ENCCON : ECC_DECCON)
+#define ECC_ERRMASK_MT7622 GENMASK(4, 0)
+#define ECC_ERRMASK_MT2701 GENMASK(5, 0)
+#define ECC_ERRMASK_MT2712 GENMASK(6, 0)
+
struct mtk_ecc_caps {
u32 err_mask;
u32 err_shift;
@@ -79,6 +83,10 @@ static const u8 ecc_strength_mt7622[] = {
4, 6, 8, 10, 12
};
+static const u8 ecc_strength_mt7986[] = {
+ 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24
+};
+
enum mtk_ecc_regs {
ECC_ENCPAR00,
ECC_ENCIRQ_EN,
@@ -451,7 +459,7 @@ unsigned int mtk_ecc_get_parity_bits(struct mtk_ecc *ecc)
EXPORT_SYMBOL(mtk_ecc_get_parity_bits);
static const struct mtk_ecc_caps mtk_ecc_caps_mt2701 = {
- .err_mask = 0x3f,
+ .err_mask = ECC_ERRMASK_MT2701,
.err_shift = 8,
.ecc_strength = ecc_strength_mt2701,
.ecc_regs = mt2701_ecc_regs,
@@ -462,7 +470,7 @@ static const struct mtk_ecc_caps mtk_ecc_caps_mt2701 = {
};
static const struct mtk_ecc_caps mtk_ecc_caps_mt2712 = {
- .err_mask = 0x7f,
+ .err_mask = ECC_ERRMASK_MT2712,
.err_shift = 8,
.ecc_strength = ecc_strength_mt2712,
.ecc_regs = mt2712_ecc_regs,
@@ -473,7 +481,7 @@ static const struct mtk_ecc_caps mtk_ecc_caps_mt2712 = {
};
static const struct mtk_ecc_caps mtk_ecc_caps_mt7622 = {
- .err_mask = 0x1f,
+ .err_mask = ECC_ERRMASK_MT7622,
.err_shift = 5,
.ecc_strength = ecc_strength_mt7622,
.ecc_regs = mt7622_ecc_regs,
@@ -483,6 +491,17 @@ static const struct mtk_ecc_caps mtk_ecc_caps_mt7622 = {
.pg_irq_sel = 0,
};
+static const struct mtk_ecc_caps mtk_ecc_caps_mt7986 = {
+ .err_mask = ECC_ERRMASK_MT7622,
+ .err_shift = 8,
+ .ecc_strength = ecc_strength_mt7986,
+ .ecc_regs = mt2712_ecc_regs,
+ .num_ecc_strength = 11,
+ .ecc_mode_shift = 5,
+ .parity_bits = 14,
+ .pg_irq_sel = 1,
+};
+
static const struct of_device_id mtk_ecc_dt_match[] = {
{
.compatible = "mediatek,mt2701-ecc",
@@ -493,6 +512,9 @@ static const struct of_device_id mtk_ecc_dt_match[] = {
}, {
.compatible = "mediatek,mt7622-ecc",
.data = &mtk_ecc_caps_mt7622,
+ }, {
+ .compatible = "mediatek,mt7986-ecc",
+ .data = &mtk_ecc_caps_mt7986,
},
{},
};
diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
index 048b1c8f08ee..170f1185ddc4 100644
--- a/drivers/mtd/nand/raw/Kconfig
+++ b/drivers/mtd/nand/raw/Kconfig
@@ -193,13 +193,6 @@ config MTD_NAND_PASEMI
Enables support for NAND Flash interface on PA Semi PWRficient
based boards
-config MTD_NAND_TMIO
- tristate "Toshiba Mobile IO NAND controller"
- depends on MFD_TMIO
- help
- Support for NAND flash connected to a Toshiba Mobile IO
- Controller in some PDAs, including the Sharp SL6000x.
-
source "drivers/mtd/nand/raw/brcmnand/Kconfig"
config MTD_NAND_BCM47XXNFLASH
diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile
index fa1d00120310..917cdfb815b9 100644
--- a/drivers/mtd/nand/raw/Makefile
+++ b/drivers/mtd/nand/raw/Makefile
@@ -23,7 +23,6 @@ omap2_nand-objs := omap2.o
obj-$(CONFIG_MTD_NAND_OMAP2) += omap2_nand.o
obj-$(CONFIG_MTD_NAND_OMAP_BCH_BUILD) += omap_elm.o
obj-$(CONFIG_MTD_NAND_MARVELL) += marvell_nand.o
-obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o
obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o
obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o
obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o
diff --git a/drivers/mtd/nand/raw/fsl_elbc_nand.c b/drivers/mtd/nand/raw/fsl_elbc_nand.c
index a18d121396aa..e25119e58b69 100644
--- a/drivers/mtd/nand/raw/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/raw/fsl_elbc_nand.c
@@ -725,6 +725,7 @@ static int fsl_elbc_attach_chip(struct nand_chip *chip)
struct fsl_lbc_ctrl *ctrl = priv->ctrl;
struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
unsigned int al;
+ u32 br;
/*
* if ECC was not chosen in DT, decide whether to use HW or SW ECC from
@@ -764,6 +765,13 @@ static int fsl_elbc_attach_chip(struct nand_chip *chip)
return -EINVAL;
}
+ /* enable/disable HW ECC checking and generating based on if HW ECC was chosen */
+ br = in_be32(&lbc->bank[priv->bank].br) & ~BR_DECC;
+ if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_ON_HOST)
+ out_be32(&lbc->bank[priv->bank].br, br | BR_DECC_CHK_GEN);
+ else
+ out_be32(&lbc->bank[priv->bank].br, br | BR_DECC_OFF);
+
/* calculate FMR Address Length field */
al = 0;
if (chip->pagemask & 0xffff0000)
diff --git a/drivers/mtd/nand/raw/marvell_nand.c b/drivers/mtd/nand/raw/marvell_nand.c
index 42c64dcea767..3034916d2e25 100644
--- a/drivers/mtd/nand/raw/marvell_nand.c
+++ b/drivers/mtd/nand/raw/marvell_nand.c
@@ -288,10 +288,17 @@ static const struct marvell_hw_ecc_layout marvell_nfc_layouts[] = {
MARVELL_LAYOUT( 2048, 512, 1, 1, 1, 2048, 40, 24, 0, 0, 0),
MARVELL_LAYOUT( 2048, 512, 4, 1, 1, 2048, 32, 30, 0, 0, 0),
MARVELL_LAYOUT( 2048, 512, 8, 2, 1, 1024, 0, 30,1024,32, 30),
+ MARVELL_LAYOUT( 2048, 512, 8, 2, 1, 1024, 0, 30,1024,64, 30),
+ MARVELL_LAYOUT( 2048, 512, 12, 3, 2, 704, 0, 30,640, 0, 30),
+ MARVELL_LAYOUT( 2048, 512, 16, 5, 4, 512, 0, 30, 0, 32, 30),
MARVELL_LAYOUT( 4096, 512, 4, 2, 2, 2048, 32, 30, 0, 0, 0),
MARVELL_LAYOUT( 4096, 512, 8, 5, 4, 1024, 0, 30, 0, 64, 30),
+ MARVELL_LAYOUT( 4096, 512, 12, 6, 5, 704, 0, 30,576, 32, 30),
+ MARVELL_LAYOUT( 4096, 512, 16, 9, 8, 512, 0, 30, 0, 32, 30),
MARVELL_LAYOUT( 8192, 512, 4, 4, 4, 2048, 0, 30, 0, 0, 0),
MARVELL_LAYOUT( 8192, 512, 8, 9, 8, 1024, 0, 30, 0, 160, 30),
+ MARVELL_LAYOUT( 8192, 512, 12, 12, 11, 704, 0, 30,448, 64, 30),
+ MARVELL_LAYOUT( 8192, 512, 16, 17, 16, 512, 0, 30, 0, 32, 30),
};
/**
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index c3cc66039925..a6af521832aa 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -1208,6 +1208,73 @@ static int nand_lp_exec_read_page_op(struct nand_chip *chip, unsigned int page,
return nand_exec_op(chip, &op);
}
+static int nand_lp_exec_cont_read_page_op(struct nand_chip *chip, unsigned int page,
+ unsigned int offset_in_page, void *buf,
+ unsigned int len, bool check_only)
+{
+ const struct nand_interface_config *conf =
+ nand_get_interface_config(chip);
+ u8 addrs[5];
+ struct nand_op_instr start_instrs[] = {
+ NAND_OP_CMD(NAND_CMD_READ0, 0),
+ NAND_OP_ADDR(4, addrs, 0),
+ NAND_OP_CMD(NAND_CMD_READSTART, NAND_COMMON_TIMING_NS(conf, tWB_max)),
+ NAND_OP_WAIT_RDY(NAND_COMMON_TIMING_MS(conf, tR_max), 0),
+ NAND_OP_CMD(NAND_CMD_READCACHESEQ, NAND_COMMON_TIMING_NS(conf, tWB_max)),
+ NAND_OP_WAIT_RDY(NAND_COMMON_TIMING_MS(conf, tR_max),
+ NAND_COMMON_TIMING_NS(conf, tRR_min)),
+ NAND_OP_DATA_IN(len, buf, 0),
+ };
+ struct nand_op_instr cont_instrs[] = {
+ NAND_OP_CMD(page == chip->cont_read.last_page ?
+ NAND_CMD_READCACHEEND : NAND_CMD_READCACHESEQ,
+ NAND_COMMON_TIMING_NS(conf, tWB_max)),
+ NAND_OP_WAIT_RDY(NAND_COMMON_TIMING_MS(conf, tR_max),
+ NAND_COMMON_TIMING_NS(conf, tRR_min)),
+ NAND_OP_DATA_IN(len, buf, 0),
+ };
+ struct nand_operation start_op = NAND_OPERATION(chip->cur_cs, start_instrs);
+ struct nand_operation cont_op = NAND_OPERATION(chip->cur_cs, cont_instrs);
+ int ret;
+
+ if (!len) {
+ start_op.ninstrs--;
+ cont_op.ninstrs--;
+ }
+
+ ret = nand_fill_column_cycles(chip, addrs, offset_in_page);
+ if (ret < 0)
+ return ret;
+
+ addrs[2] = page;
+ addrs[3] = page >> 8;
+
+ if (chip->options & NAND_ROW_ADDR_3) {
+ addrs[4] = page >> 16;
+ start_instrs[1].ctx.addr.naddrs++;
+ }
+
+ /* Check if cache reads are supported */
+ if (check_only) {
+ if (nand_check_op(chip, &start_op) || nand_check_op(chip, &cont_op))
+ return -EOPNOTSUPP;
+
+ return 0;
+ }
+
+ if (page == chip->cont_read.first_page)
+ return nand_exec_op(chip, &start_op);
+ else
+ return nand_exec_op(chip, &cont_op);
+}
+
+static bool rawnand_cont_read_ongoing(struct nand_chip *chip, unsigned int page)
+{
+ return chip->cont_read.ongoing &&
+ page >= chip->cont_read.first_page &&
+ page <= chip->cont_read.last_page;
+}
+
/**
* nand_read_page_op - Do a READ PAGE operation
* @chip: The NAND chip
@@ -1233,10 +1300,16 @@ int nand_read_page_op(struct nand_chip *chip, unsigned int page,
return -EINVAL;
if (nand_has_exec_op(chip)) {
- if (mtd->writesize > 512)
- return nand_lp_exec_read_page_op(chip, page,
- offset_in_page, buf,
- len);
+ if (mtd->writesize > 512) {
+ if (rawnand_cont_read_ongoing(chip, page))
+ return nand_lp_exec_cont_read_page_op(chip, page,
+ offset_in_page,
+ buf, len, false);
+ else
+ return nand_lp_exec_read_page_op(chip, page,
+ offset_in_page, buf,
+ len);
+ }
return nand_sp_exec_read_page_op(chip, page, offset_in_page,
buf, len);
@@ -3353,6 +3426,27 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
return NULL;
}
+static void rawnand_enable_cont_reads(struct nand_chip *chip, unsigned int page,
+ u32 readlen, int col)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
+ if (!chip->controller->supported_op.cont_read)
+ return;
+
+ if ((col && col + readlen < (3 * mtd->writesize)) ||
+ (!col && readlen < (2 * mtd->writesize))) {
+ chip->cont_read.ongoing = false;
+ return;
+ }
+
+ chip->cont_read.ongoing = true;
+ chip->cont_read.first_page = page;
+ if (col)
+ chip->cont_read.first_page++;
+ chip->cont_read.last_page = page + ((readlen >> chip->page_shift) & chip->pagemask);
+}
+
/**
* nand_setup_read_retry - [INTERN] Set the READ RETRY mode
* @chip: NAND chip object
@@ -3426,6 +3520,8 @@ static int nand_do_read_ops(struct nand_chip *chip, loff_t from,
oob = ops->oobbuf;
oob_required = oob ? 1 : 0;
+ rawnand_enable_cont_reads(chip, page, readlen, col);
+
while (1) {
struct mtd_ecc_stats ecc_stats = mtd->ecc_stats;
@@ -4991,6 +5087,47 @@ nand_manufacturer_name(const struct nand_manufacturer_desc *manufacturer_desc)
return manufacturer_desc ? manufacturer_desc->name : "Unknown";
}
+static void rawnand_check_data_only_read_support(struct nand_chip *chip)
+{
+ /* Use an arbitrary size for the check */
+ if (!nand_read_data_op(chip, NULL, SZ_512, true, true))
+ chip->controller->supported_op.data_only_read = 1;
+}
+
+static void rawnand_early_check_supported_ops(struct nand_chip *chip)
+{
+ /* The supported_op fields should not be set by individual drivers */
+ WARN_ON_ONCE(chip->controller->supported_op.data_only_read);
+
+ if (!nand_has_exec_op(chip))
+ return;
+
+ rawnand_check_data_only_read_support(chip);
+}
+
+static void rawnand_check_cont_read_support(struct nand_chip *chip)
+{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
+ if (chip->read_retries)
+ return;
+
+ if (!nand_lp_exec_cont_read_page_op(chip, 0, 0, NULL,
+ mtd->writesize, true))
+ chip->controller->supported_op.cont_read = 1;
+}
+
+static void rawnand_late_check_supported_ops(struct nand_chip *chip)
+{
+ /* The supported_op fields should not be set by individual drivers */
+ WARN_ON_ONCE(chip->controller->supported_op.cont_read);
+
+ if (!nand_has_exec_op(chip))
+ return;
+
+ rawnand_check_cont_read_support(chip);
+}
+
/*
* Get the flash and manufacturer id and lookup if the type is supported.
*/
@@ -5023,6 +5160,8 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
/* Select the device */
nand_select_target(chip, 0);
+ rawnand_early_check_supported_ops(chip);
+
/* Send the command for reading device ID */
ret = nand_readid_op(chip, 0, id_data, 2);
if (ret)
@@ -6325,6 +6464,8 @@ static int nand_scan_tail(struct nand_chip *chip)
goto err_free_interface_config;
}
+ rawnand_late_check_supported_ops(chip);
+
/*
* Look for secure regions in the NAND chip. These regions are supposed
* to be protected by a secure element like Trustzone. So the read/write
diff --git a/drivers/mtd/nand/raw/nand_jedec.c b/drivers/mtd/nand/raw/nand_jedec.c
index 85b6d9372d80..836757717660 100644
--- a/drivers/mtd/nand/raw/nand_jedec.c
+++ b/drivers/mtd/nand/raw/nand_jedec.c
@@ -46,8 +46,7 @@ int nand_jedec_detect(struct nand_chip *chip)
if (!p)
return -ENOMEM;
- if (!nand_has_exec_op(chip) ||
- !nand_read_data_op(chip, p, sizeof(*p), true, true))
+ if (!nand_has_exec_op(chip) || chip->controller->supported_op.data_only_read)
use_datain = true;
for (i = 0; i < JEDEC_PARAM_PAGES; i++) {
diff --git a/drivers/mtd/nand/raw/nand_onfi.c b/drivers/mtd/nand/raw/nand_onfi.c
index 7586befce7f9..f15ef90aec8c 100644
--- a/drivers/mtd/nand/raw/nand_onfi.c
+++ b/drivers/mtd/nand/raw/nand_onfi.c
@@ -166,8 +166,7 @@ int nand_onfi_detect(struct nand_chip *chip)
if (!pbuf)
return -ENOMEM;
- if (!nand_has_exec_op(chip) ||
- !nand_read_data_op(chip, &pbuf[0], sizeof(*pbuf), true, true))
+ if (!nand_has_exec_op(chip) || chip->controller->supported_op.data_only_read)
use_datain = true;
for (i = 0; i < ONFI_PARAM_PAGES; i++) {
diff --git a/drivers/mtd/nand/raw/pasemi_nand.c b/drivers/mtd/nand/raw/pasemi_nand.c
index c176036453ed..f7ef6ca06ca9 100644
--- a/drivers/mtd/nand/raw/pasemi_nand.c
+++ b/drivers/mtd/nand/raw/pasemi_nand.c
@@ -26,9 +26,12 @@
#define CLE_PIN_CTL 15
#define ALE_PIN_CTL 14
-static unsigned int lpcctl;
-static struct mtd_info *pasemi_nand_mtd;
-static struct nand_controller controller;
+struct pasemi_ddata {
+ struct nand_chip chip;
+ unsigned int lpcctl;
+ struct nand_controller controller;
+};
+
static const char driver_name[] = "pasemi-nand";
static void pasemi_read_buf(struct nand_chip *chip, u_char *buf, int len)
@@ -55,6 +58,8 @@ static void pasemi_write_buf(struct nand_chip *chip, const u_char *buf,
static void pasemi_hwcontrol(struct nand_chip *chip, int cmd,
unsigned int ctrl)
{
+ struct pasemi_ddata *ddata = container_of(chip, struct pasemi_ddata, chip);
+
if (cmd == NAND_CMD_NONE)
return;
@@ -65,12 +70,14 @@ static void pasemi_hwcontrol(struct nand_chip *chip, int cmd,
/* Push out posted writes */
eieio();
- inl(lpcctl);
+ inl(ddata->lpcctl);
}
static int pasemi_device_ready(struct nand_chip *chip)
{
- return !!(inl(lpcctl) & LBICTRL_LPCCTL_NR);
+ struct pasemi_ddata *ddata = container_of(chip, struct pasemi_ddata, chip);
+
+ return !!(inl(ddata->lpcctl) & LBICTRL_LPCCTL_NR);
}
static int pasemi_attach_chip(struct nand_chip *chip)
@@ -93,29 +100,31 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
struct device_node *np = dev->of_node;
struct resource res;
struct nand_chip *chip;
+ struct nand_controller *controller;
int err = 0;
+ struct pasemi_ddata *ddata;
+ struct mtd_info *pasemi_nand_mtd;
err = of_address_to_resource(np, 0, &res);
if (err)
return -EINVAL;
- /* We only support one device at the moment */
- if (pasemi_nand_mtd)
- return -ENODEV;
-
dev_dbg(dev, "pasemi_nand at %pR\n", &res);
/* Allocate memory for MTD device structure and private data */
- chip = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
- if (!chip) {
+ ddata = kzalloc(sizeof(*ddata), GFP_KERNEL);
+ if (!ddata) {
err = -ENOMEM;
goto out;
}
+ platform_set_drvdata(ofdev, ddata);
+ chip = &ddata->chip;
+ controller = &ddata->controller;
- controller.ops = &pasemi_ops;
- nand_controller_init(&controller);
- chip->controller = &controller;
+ controller->ops = &pasemi_ops;
+ nand_controller_init(controller);
+ chip->controller = controller;
pasemi_nand_mtd = nand_to_mtd(chip);
@@ -136,10 +145,10 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
goto out_ior;
}
- lpcctl = pci_resource_start(pdev, 0);
+ ddata->lpcctl = pci_resource_start(pdev, 0);
pci_dev_put(pdev);
- if (!request_region(lpcctl, 4, driver_name)) {
+ if (!request_region(ddata->lpcctl, 4, driver_name)) {
err = -EBUSY;
goto out_ior;
}
@@ -172,45 +181,43 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
}
dev_info(dev, "PA Semi NAND flash at %pR, control at I/O %x\n", &res,
- lpcctl);
+ ddata->lpcctl);
return 0;
out_cleanup_nand:
nand_cleanup(chip);
out_lpc:
- release_region(lpcctl, 4);
+ release_region(ddata->lpcctl, 4);
out_ior:
iounmap(chip->legacy.IO_ADDR_R);
out_mtd:
- kfree(chip);
+ kfree(ddata);
out:
return err;
}
static int pasemi_nand_remove(struct platform_device *ofdev)
{
- struct nand_chip *chip;
+ struct pasemi_ddata *ddata = platform_get_drvdata(ofdev);
+ struct mtd_info *pasemi_nand_mtd;
int ret;
+ struct nand_chip *chip;
- if (!pasemi_nand_mtd)
- return 0;
-
- chip = mtd_to_nand(pasemi_nand_mtd);
+ chip = &ddata->chip;
+ pasemi_nand_mtd = nand_to_mtd(chip);
/* Release resources, unregister device */
ret = mtd_device_unregister(pasemi_nand_mtd);
WARN_ON(ret);
nand_cleanup(chip);
- release_region(lpcctl, 4);
+ release_region(ddata->lpcctl, 4);
iounmap(chip->legacy.IO_ADDR_R);
/* Free the MTD device structure */
- kfree(chip);
-
- pasemi_nand_mtd = NULL;
+ kfree(ddata);
return 0;
}
diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c
index ea953e31933e..13e3e0198d15 100644
--- a/drivers/mtd/nand/raw/sunxi_nand.c
+++ b/drivers/mtd/nand/raw/sunxi_nand.c
@@ -172,10 +172,10 @@ struct sunxi_nand_chip_sel {
/**
* struct sunxi_nand_hw_ecc - stores information related to HW ECC support
*
- * @mode: the sunxi ECC mode field deduced from ECC requirements
+ * @ecc_ctl: ECC_CTL register value for this NAND chip
*/
struct sunxi_nand_hw_ecc {
- int mode;
+ u32 ecc_ctl;
};
/**
@@ -193,7 +193,7 @@ struct sunxi_nand_hw_ecc {
struct sunxi_nand_chip {
struct list_head node;
struct nand_chip nand;
- struct sunxi_nand_hw_ecc *ecc;
+ struct sunxi_nand_hw_ecc ecc;
unsigned long clk_rate;
u32 timing_cfg;
u32 timing_ctl;
@@ -421,7 +421,7 @@ static void sunxi_nfc_select_chip(struct nand_chip *nand, unsigned int cs)
struct sunxi_nand_chip_sel *sel;
u32 ctl;
- if (cs > 0 && cs >= sunxi_nand->nsels)
+ if (cs >= sunxi_nand->nsels)
return;
ctl = readl(nfc->regs + NFC_REG_CTL) &
@@ -689,26 +689,15 @@ static void sunxi_nfc_hw_ecc_enable(struct nand_chip *nand)
{
struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
- u32 ecc_ctl;
-
- ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL);
- ecc_ctl &= ~(NFC_ECC_MODE_MSK | NFC_ECC_PIPELINE |
- NFC_ECC_BLOCK_SIZE_MSK);
- ecc_ctl |= NFC_ECC_EN | NFC_ECC_MODE(sunxi_nand->ecc->mode) |
- NFC_ECC_EXCEPTION | NFC_ECC_PIPELINE;
-
- if (nand->ecc.size == 512)
- ecc_ctl |= NFC_ECC_BLOCK_512;
- writel(ecc_ctl, nfc->regs + NFC_REG_ECC_CTL);
+ writel(sunxi_nand->ecc.ecc_ctl, nfc->regs + NFC_REG_ECC_CTL);
}
static void sunxi_nfc_hw_ecc_disable(struct nand_chip *nand)
{
struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
- writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_ECC_EN,
- nfc->regs + NFC_REG_ECC_CTL);
+ writel(0, nfc->regs + NFC_REG_ECC_CTL);
}
static inline void sunxi_nfc_user_data_to_buf(u32 user_data, u8 *buf)
@@ -1604,12 +1593,19 @@ static int sunxi_nand_ooblayout_free(struct mtd_info *mtd, int section,
return 0;
}
+ /*
+ * The controller does not provide access to OOB bytes
+ * past the end of the ECC data.
+ */
+ if (section == ecc->steps && ecc->engine_type == NAND_ECC_ENGINE_TYPE_ON_HOST)
+ return -ERANGE;
+
oobregion->offset = section * (ecc->bytes + 4);
if (section < ecc->steps)
oobregion->length = 4;
else
- oobregion->offset = mtd->oobsize - oobregion->offset;
+ oobregion->length = mtd->oobsize - oobregion->offset;
return 0;
}
@@ -1619,11 +1615,6 @@ static const struct mtd_ooblayout_ops sunxi_nand_ooblayout_ops = {
.free = sunxi_nand_ooblayout_free,
};
-static void sunxi_nand_hw_ecc_ctrl_cleanup(struct sunxi_nand_chip *sunxi_nand)
-{
- kfree(sunxi_nand->ecc);
-}
-
static int sunxi_nand_hw_ecc_ctrl_init(struct nand_chip *nand,
struct nand_ecc_ctrl *ecc,
struct device_node *np)
@@ -1634,7 +1625,6 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct nand_chip *nand,
struct mtd_info *mtd = nand_to_mtd(nand);
struct nand_device *nanddev = mtd_to_nanddev(mtd);
int nsectors;
- int ret;
int i;
if (nanddev->ecc.user_conf.flags & NAND_ECC_MAXIMIZE_STRENGTH) {
@@ -1669,10 +1659,6 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct nand_chip *nand,
if (ecc->size != 512 && ecc->size != 1024)
return -EINVAL;
- sunxi_nand->ecc = kzalloc(sizeof(*sunxi_nand->ecc), GFP_KERNEL);
- if (!sunxi_nand->ecc)
- return -ENOMEM;
-
/* Prefer 1k ECC chunk over 512 ones */
if (ecc->size == 512 && mtd->writesize > 512) {
ecc->size = 1024;
@@ -1693,12 +1679,9 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct nand_chip *nand,
if (i >= ARRAY_SIZE(strengths)) {
dev_err(nfc->dev, "unsupported strength\n");
- ret = -ENOTSUPP;
- goto err;
+ return -ENOTSUPP;
}
- sunxi_nand->ecc->mode = i;
-
/* HW ECC always request ECC bytes for 1024 bytes blocks */
ecc->bytes = DIV_ROUND_UP(ecc->strength * fls(8 * 1024), 8);
@@ -1707,10 +1690,8 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct nand_chip *nand,
nsectors = mtd->writesize / ecc->size;
- if (mtd->oobsize < ((ecc->bytes + 4) * nsectors)) {
- ret = -EINVAL;
- goto err;
- }
+ if (mtd->oobsize < ((ecc->bytes + 4) * nsectors))
+ return -EINVAL;
ecc->read_oob = sunxi_nfc_hw_ecc_read_oob;
ecc->write_oob = sunxi_nfc_hw_ecc_write_oob;
@@ -1732,26 +1713,13 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct nand_chip *nand,
ecc->read_oob_raw = nand_read_oob_std;
ecc->write_oob_raw = nand_write_oob_std;
- return 0;
-
-err:
- kfree(sunxi_nand->ecc);
+ sunxi_nand->ecc.ecc_ctl = NFC_ECC_MODE(i) | NFC_ECC_EXCEPTION |
+ NFC_ECC_PIPELINE | NFC_ECC_EN;
- return ret;
-}
+ if (ecc->size == 512)
+ sunxi_nand->ecc.ecc_ctl |= NFC_ECC_BLOCK_512;
-static void sunxi_nand_ecc_cleanup(struct sunxi_nand_chip *sunxi_nand)
-{
- struct nand_ecc_ctrl *ecc = &sunxi_nand->nand.ecc;
-
- switch (ecc->engine_type) {
- case NAND_ECC_ENGINE_TYPE_ON_HOST:
- sunxi_nand_hw_ecc_ctrl_cleanup(sunxi_nand);
- break;
- case NAND_ECC_ENGINE_TYPE_NONE:
- default:
- break;
- }
+ return 0;
}
static int sunxi_nand_attach_chip(struct nand_chip *nand)
@@ -1950,6 +1918,24 @@ static const struct nand_controller_ops sunxi_nand_controller_ops = {
.exec_op = sunxi_nfc_exec_op,
};
+static void sunxi_nand_chips_cleanup(struct sunxi_nfc *nfc)
+{
+ struct sunxi_nand_chip *sunxi_nand;
+ struct nand_chip *chip;
+ int ret;
+
+ while (!list_empty(&nfc->chips)) {
+ sunxi_nand = list_first_entry(&nfc->chips,
+ struct sunxi_nand_chip,
+ node);
+ chip = &sunxi_nand->nand;
+ ret = mtd_device_unregister(nand_to_mtd(chip));
+ WARN_ON(ret);
+ nand_cleanup(chip);
+ list_del(&sunxi_nand->node);
+ }
+}
+
static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
struct device_node *np)
{
@@ -2041,18 +2027,13 @@ static int sunxi_nand_chips_init(struct device *dev, struct sunxi_nfc *nfc)
{
struct device_node *np = dev->of_node;
struct device_node *nand_np;
- int nchips = of_get_child_count(np);
int ret;
- if (nchips > 8) {
- dev_err(dev, "too many NAND chips: %d (max = 8)\n", nchips);
- return -EINVAL;
- }
-
for_each_child_of_node(np, nand_np) {
ret = sunxi_nand_chip_init(dev, nfc, nand_np);
if (ret) {
of_node_put(nand_np);
+ sunxi_nand_chips_cleanup(nfc);
return ret;
}
}
@@ -2060,25 +2041,6 @@ static int sunxi_nand_chips_init(struct device *dev, struct sunxi_nfc *nfc)
return 0;
}
-static void sunxi_nand_chips_cleanup(struct sunxi_nfc *nfc)
-{
- struct sunxi_nand_chip *sunxi_nand;
- struct nand_chip *chip;
- int ret;
-
- while (!list_empty(&nfc->chips)) {
- sunxi_nand = list_first_entry(&nfc->chips,
- struct sunxi_nand_chip,
- node);
- chip = &sunxi_nand->nand;
- ret = mtd_device_unregister(nand_to_mtd(chip));
- WARN_ON(ret);
- nand_cleanup(chip);
- sunxi_nand_ecc_cleanup(sunxi_nand);
- list_del(&sunxi_nand->node);
- }
-}
-
static int sunxi_nfc_dma_init(struct sunxi_nfc *nfc, struct resource *r)
{
int ret;
diff --git a/drivers/mtd/nand/raw/tmio_nand.c b/drivers/mtd/nand/raw/tmio_nand.c
deleted file mode 100644
index 8f1a42bf199c..000000000000
--- a/drivers/mtd/nand/raw/tmio_nand.c
+++ /dev/null
@@ -1,533 +0,0 @@
-/*
- * Toshiba TMIO NAND flash controller driver
- *
- * Slightly murky pre-git history of the driver:
- *
- * Copyright (c) Ian Molton 2004, 2005, 2008
- * Original work, independent of sharps code. Included hardware ECC support.
- * Hard ECC did not work for writes in the early revisions.
- * Copyright (c) Dirk Opfer 2005.
- * Modifications developed from sharps code but
- * NOT containing any, ported onto Ians base.
- * Copyright (c) Chris Humbert 2005
- * Copyright (c) Dmitry Baryshkov 2008
- * Minor fixes
- *
- * Parts copyright Sebastian Carlier
- *
- * This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- *
- */
-
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/mfd/core.h>
-#include <linux/mfd/tmio.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/partitions.h>
-#include <linux/slab.h>
-
-/*--------------------------------------------------------------------------*/
-
-/*
- * NAND Flash Host Controller Configuration Register
- */
-#define CCR_COMMAND 0x04 /* w Command */
-#define CCR_BASE 0x10 /* l NAND Flash Control Reg Base Addr */
-#define CCR_INTP 0x3d /* b Interrupt Pin */
-#define CCR_INTE 0x48 /* b Interrupt Enable */
-#define CCR_EC 0x4a /* b Event Control */
-#define CCR_ICC 0x4c /* b Internal Clock Control */
-#define CCR_ECCC 0x5b /* b ECC Control */
-#define CCR_NFTC 0x60 /* b NAND Flash Transaction Control */
-#define CCR_NFM 0x61 /* b NAND Flash Monitor */
-#define CCR_NFPSC 0x62 /* b NAND Flash Power Supply Control */
-#define CCR_NFDC 0x63 /* b NAND Flash Detect Control */
-
-/*
- * NAND Flash Control Register
- */
-#define FCR_DATA 0x00 /* bwl Data Register */
-#define FCR_MODE 0x04 /* b Mode Register */
-#define FCR_STATUS 0x05 /* b Status Register */
-#define FCR_ISR 0x06 /* b Interrupt Status Register */
-#define FCR_IMR 0x07 /* b Interrupt Mask Register */
-
-/* FCR_MODE Register Command List */
-#define FCR_MODE_DATA 0x94 /* Data Data_Mode */
-#define FCR_MODE_COMMAND 0x95 /* Data Command_Mode */
-#define FCR_MODE_ADDRESS 0x96 /* Data Address_Mode */
-
-#define FCR_MODE_HWECC_CALC 0xB4 /* HW-ECC Data */
-#define FCR_MODE_HWECC_RESULT 0xD4 /* HW-ECC Calc result Read_Mode */
-#define FCR_MODE_HWECC_RESET 0xF4 /* HW-ECC Reset */
-
-#define FCR_MODE_POWER_ON 0x0C /* Power Supply ON to SSFDC card */
-#define FCR_MODE_POWER_OFF 0x08 /* Power Supply OFF to SSFDC card */
-
-#define FCR_MODE_LED_OFF 0x00 /* LED OFF */
-#define FCR_MODE_LED_ON 0x04 /* LED ON */
-
-#define FCR_MODE_EJECT_ON 0x68 /* Ejection events active */
-#define FCR_MODE_EJECT_OFF 0x08 /* Ejection events ignored */
-
-#define FCR_MODE_LOCK 0x6C /* Lock_Mode. Eject Switch Invalid */
-#define FCR_MODE_UNLOCK 0x0C /* UnLock_Mode. Eject Switch is valid */
-
-#define FCR_MODE_CONTROLLER_ID 0x40 /* Controller ID Read */
-#define FCR_MODE_STANDBY 0x00 /* SSFDC card Changes Standby State */
-
-#define FCR_MODE_WE 0x80
-#define FCR_MODE_ECC1 0x40
-#define FCR_MODE_ECC0 0x20
-#define FCR_MODE_CE 0x10
-#define FCR_MODE_PCNT1 0x08
-#define FCR_MODE_PCNT0 0x04
-#define FCR_MODE_ALE 0x02
-#define FCR_MODE_CLE 0x01
-
-#define FCR_STATUS_BUSY 0x80
-
-/*--------------------------------------------------------------------------*/
-
-struct tmio_nand {
- struct nand_controller controller;
- struct nand_chip chip;
- struct completion comp;
-
- struct platform_device *dev;
-
- void __iomem *ccr;
- void __iomem *fcr;
- unsigned long fcr_base;
-
- unsigned int irq;
-
- /* for tmio_nand_read_byte */
- u8 read;
- unsigned read_good:1;
-};
-
-static inline struct tmio_nand *mtd_to_tmio(struct mtd_info *mtd)
-{
- return container_of(mtd_to_nand(mtd), struct tmio_nand, chip);
-}
-
-
-/*--------------------------------------------------------------------------*/
-
-static void tmio_nand_hwcontrol(struct nand_chip *chip, int cmd,
- unsigned int ctrl)
-{
- struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip));
-
- if (ctrl & NAND_CTRL_CHANGE) {
- u8 mode;
-
- if (ctrl & NAND_NCE) {
- mode = FCR_MODE_DATA;
-
- if (ctrl & NAND_CLE)
- mode |= FCR_MODE_CLE;
- else
- mode &= ~FCR_MODE_CLE;
-
- if (ctrl & NAND_ALE)
- mode |= FCR_MODE_ALE;
- else
- mode &= ~FCR_MODE_ALE;
- } else {
- mode = FCR_MODE_STANDBY;
- }
-
- tmio_iowrite8(mode, tmio->fcr + FCR_MODE);
- tmio->read_good = 0;
- }
-
- if (cmd != NAND_CMD_NONE)
- tmio_iowrite8(cmd, chip->legacy.IO_ADDR_W);
-}
-
-static int tmio_nand_dev_ready(struct nand_chip *chip)
-{
- struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip));
-
- return !(tmio_ioread8(tmio->fcr + FCR_STATUS) & FCR_STATUS_BUSY);
-}
-
-static irqreturn_t tmio_irq(int irq, void *__tmio)
-{
- struct tmio_nand *tmio = __tmio;
-
- /* disable RDYREQ interrupt */
- tmio_iowrite8(0x00, tmio->fcr + FCR_IMR);
- complete(&tmio->comp);
-
- return IRQ_HANDLED;
-}
-
-/*
- *The TMIO core has a RDYREQ interrupt on the posedge of #SMRB.
- *This interrupt is normally disabled, but for long operations like
- *erase and write, we enable it to wake us up. The irq handler
- *disables the interrupt.
- */
-static int tmio_nand_wait(struct nand_chip *nand_chip)
-{
- struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(nand_chip));
- long timeout;
- u8 status;
-
- /* enable RDYREQ interrupt */
-
- tmio_iowrite8(0x0f, tmio->fcr + FCR_ISR);
- reinit_completion(&tmio->comp);
- tmio_iowrite8(0x81, tmio->fcr + FCR_IMR);
-
- timeout = 400;
- timeout = wait_for_completion_timeout(&tmio->comp,
- msecs_to_jiffies(timeout));
-
- if (unlikely(!tmio_nand_dev_ready(nand_chip))) {
- tmio_iowrite8(0x00, tmio->fcr + FCR_IMR);
- dev_warn(&tmio->dev->dev, "still busy after 400 ms\n");
-
- } else if (unlikely(!timeout)) {
- tmio_iowrite8(0x00, tmio->fcr + FCR_IMR);
- dev_warn(&tmio->dev->dev, "timeout waiting for interrupt\n");
- }
-
- nand_status_op(nand_chip, &status);
- return status;
-}
-
-/*
- *The TMIO controller combines two 8-bit data bytes into one 16-bit
- *word. This function separates them so nand_base.c works as expected,
- *especially its NAND_CMD_READID routines.
- *
- *To prevent stale data from being read, tmio_nand_hwcontrol() clears
- *tmio->read_good.
- */
-static u_char tmio_nand_read_byte(struct nand_chip *chip)
-{
- struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip));
- unsigned int data;
-
- if (tmio->read_good--)
- return tmio->read;
-
- data = tmio_ioread16(tmio->fcr + FCR_DATA);
- tmio->read = data >> 8;
- return data;
-}
-
-/*
- *The TMIO controller converts an 8-bit NAND interface to a 16-bit
- *bus interface, so all data reads and writes must be 16-bit wide.
- *Thus, we implement 16-bit versions of the read, write, and verify
- *buffer functions.
- */
-static void
-tmio_nand_write_buf(struct nand_chip *chip, const u_char *buf, int len)
-{
- struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip));
-
- tmio_iowrite16_rep(tmio->fcr + FCR_DATA, buf, len >> 1);
-}
-
-static void tmio_nand_read_buf(struct nand_chip *chip, u_char *buf, int len)
-{
- struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip));
-
- tmio_ioread16_rep(tmio->fcr + FCR_DATA, buf, len >> 1);
-}
-
-static void tmio_nand_enable_hwecc(struct nand_chip *chip, int mode)
-{
- struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip));
-
- tmio_iowrite8(FCR_MODE_HWECC_RESET, tmio->fcr + FCR_MODE);
- tmio_ioread8(tmio->fcr + FCR_DATA); /* dummy read */
- tmio_iowrite8(FCR_MODE_HWECC_CALC, tmio->fcr + FCR_MODE);
-}
-
-static int tmio_nand_calculate_ecc(struct nand_chip *chip, const u_char *dat,
- u_char *ecc_code)
-{
- struct tmio_nand *tmio = mtd_to_tmio(nand_to_mtd(chip));
- unsigned int ecc;
-
- tmio_iowrite8(FCR_MODE_HWECC_RESULT, tmio->fcr + FCR_MODE);
-
- ecc = tmio_ioread16(tmio->fcr + FCR_DATA);
- ecc_code[1] = ecc; /* 000-255 LP7-0 */
- ecc_code[0] = ecc >> 8; /* 000-255 LP15-8 */
- ecc = tmio_ioread16(tmio->fcr + FCR_DATA);
- ecc_code[2] = ecc; /* 000-255 CP5-0,11b */
- ecc_code[4] = ecc >> 8; /* 256-511 LP7-0 */
- ecc = tmio_ioread16(tmio->fcr + FCR_DATA);
- ecc_code[3] = ecc; /* 256-511 LP15-8 */
- ecc_code[5] = ecc >> 8; /* 256-511 CP5-0,11b */
-
- tmio_iowrite8(FCR_MODE_DATA, tmio->fcr + FCR_MODE);
- return 0;
-}
-
-static int tmio_nand_correct_data(struct nand_chip *chip, unsigned char *buf,
- unsigned char *read_ecc,
- unsigned char *calc_ecc)
-{
- int r0, r1;
-
- /* assume ecc.size = 512 and ecc.bytes = 6 */
- r0 = rawnand_sw_hamming_correct(chip, buf, read_ecc, calc_ecc);
- if (r0 < 0)
- return r0;
- r1 = rawnand_sw_hamming_correct(chip, buf + 256, read_ecc + 3,
- calc_ecc + 3);
- if (r1 < 0)
- return r1;
- return r0 + r1;
-}
-
-static int tmio_hw_init(struct platform_device *dev, struct tmio_nand *tmio)
-{
- const struct mfd_cell *cell = mfd_get_cell(dev);
- int ret;
-
- if (cell->enable) {
- ret = cell->enable(dev);
- if (ret)
- return ret;
- }
-
- /* (4Ch) CLKRUN Enable 1st spcrunc */
- tmio_iowrite8(0x81, tmio->ccr + CCR_ICC);
-
- /* (10h)BaseAddress 0x1000 spba.spba2 */
- tmio_iowrite16(tmio->fcr_base, tmio->ccr + CCR_BASE);
- tmio_iowrite16(tmio->fcr_base >> 16, tmio->ccr + CCR_BASE + 2);
-
- /* (04h)Command Register I/O spcmd */
- tmio_iowrite8(0x02, tmio->ccr + CCR_COMMAND);
-
- /* (62h) Power Supply Control ssmpwc */
- /* HardPowerOFF - SuspendOFF - PowerSupplyWait_4MS */
- tmio_iowrite8(0x02, tmio->ccr + CCR_NFPSC);
-
- /* (63h) Detect Control ssmdtc */
- tmio_iowrite8(0x02, tmio->ccr + CCR_NFDC);
-
- /* Interrupt status register clear sintst */
- tmio_iowrite8(0x0f, tmio->fcr + FCR_ISR);
-
- /* After power supply, Media are reset smode */
- tmio_iowrite8(FCR_MODE_POWER_ON, tmio->fcr + FCR_MODE);
- tmio_iowrite8(FCR_MODE_COMMAND, tmio->fcr + FCR_MODE);
- tmio_iowrite8(NAND_CMD_RESET, tmio->fcr + FCR_DATA);
-
- /* Standby Mode smode */
- tmio_iowrite8(FCR_MODE_STANDBY, tmio->fcr + FCR_MODE);
-
- mdelay(5);
-
- return 0;
-}
-
-static void tmio_hw_stop(struct platform_device *dev, struct tmio_nand *tmio)
-{
- const struct mfd_cell *cell = mfd_get_cell(dev);
-
- tmio_iowrite8(FCR_MODE_POWER_OFF, tmio->fcr + FCR_MODE);
- if (cell->disable)
- cell->disable(dev);
-}
-
-static int tmio_attach_chip(struct nand_chip *chip)
-{
- if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST)
- return 0;
-
- chip->ecc.size = 512;
- chip->ecc.bytes = 6;
- chip->ecc.strength = 2;
- chip->ecc.hwctl = tmio_nand_enable_hwecc;
- chip->ecc.calculate = tmio_nand_calculate_ecc;
- chip->ecc.correct = tmio_nand_correct_data;
-
- return 0;
-}
-
-static const struct nand_controller_ops tmio_ops = {
- .attach_chip = tmio_attach_chip,
-};
-
-static int tmio_probe(struct platform_device *dev)
-{
- struct tmio_nand_data *data = dev_get_platdata(&dev->dev);
- struct resource *fcr = platform_get_resource(dev,
- IORESOURCE_MEM, 0);
- struct resource *ccr = platform_get_resource(dev,
- IORESOURCE_MEM, 1);
- int irq = platform_get_irq(dev, 0);
- struct tmio_nand *tmio;
- struct mtd_info *mtd;
- struct nand_chip *nand_chip;
- int retval;
-
- if (data == NULL)
- dev_warn(&dev->dev, "NULL platform data!\n");
-
- if (!ccr || !fcr)
- return -EINVAL;
-
- tmio = devm_kzalloc(&dev->dev, sizeof(*tmio), GFP_KERNEL);
- if (!tmio)
- return -ENOMEM;
-
- init_completion(&tmio->comp);
-
- tmio->dev = dev;
-
- platform_set_drvdata(dev, tmio);
- nand_chip = &tmio->chip;
- mtd = nand_to_mtd(nand_chip);
- mtd->name = "tmio-nand";
- mtd->dev.parent = &dev->dev;
-
- nand_controller_init(&tmio->controller);
- tmio->controller.ops = &tmio_ops;
- nand_chip->controller = &tmio->controller;
-
- tmio->ccr = devm_ioremap(&dev->dev, ccr->start, resource_size(ccr));
- if (!tmio->ccr)
- return -EIO;
-
- tmio->fcr_base = fcr->start & 0xfffff;
- tmio->fcr = devm_ioremap(&dev->dev, fcr->start, resource_size(fcr));
- if (!tmio->fcr)
- return -EIO;
-
- retval = tmio_hw_init(dev, tmio);
- if (retval)
- return retval;
-
- /* Set address of NAND IO lines */
- nand_chip->legacy.IO_ADDR_R = tmio->fcr;
- nand_chip->legacy.IO_ADDR_W = tmio->fcr;
-
- /* Set address of hardware control function */
- nand_chip->legacy.cmd_ctrl = tmio_nand_hwcontrol;
- nand_chip->legacy.dev_ready = tmio_nand_dev_ready;
- nand_chip->legacy.read_byte = tmio_nand_read_byte;
- nand_chip->legacy.write_buf = tmio_nand_write_buf;
- nand_chip->legacy.read_buf = tmio_nand_read_buf;
-
- if (data)
- nand_chip->badblock_pattern = data->badblock_pattern;
-
- /* 15 us command delay time */
- nand_chip->legacy.chip_delay = 15;
-
- retval = devm_request_irq(&dev->dev, irq, &tmio_irq, 0,
- dev_name(&dev->dev), tmio);
- if (retval) {
- dev_err(&dev->dev, "request_irq error %d\n", retval);
- goto err_irq;
- }
-
- tmio->irq = irq;
- nand_chip->legacy.waitfunc = tmio_nand_wait;
-
- /* Scan to find existence of the device */
- retval = nand_scan(nand_chip, 1);
- if (retval)
- goto err_irq;
-
- /* Register the partitions */
- retval = mtd_device_parse_register(mtd,
- data ? data->part_parsers : NULL,
- NULL,
- data ? data->partition : NULL,
- data ? data->num_partitions : 0);
- if (!retval)
- return retval;
-
- nand_cleanup(nand_chip);
-
-err_irq:
- tmio_hw_stop(dev, tmio);
- return retval;
-}
-
-static int tmio_remove(struct platform_device *dev)
-{
- struct tmio_nand *tmio = platform_get_drvdata(dev);
- struct nand_chip *chip = &tmio->chip;
- int ret;
-
- ret = mtd_device_unregister(nand_to_mtd(chip));
- WARN_ON(ret);
- nand_cleanup(chip);
- tmio_hw_stop(dev, tmio);
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int tmio_suspend(struct platform_device *dev, pm_message_t state)
-{
- const struct mfd_cell *cell = mfd_get_cell(dev);
-
- if (cell->suspend)
- cell->suspend(dev);
-
- tmio_hw_stop(dev, platform_get_drvdata(dev));
- return 0;
-}
-
-static int tmio_resume(struct platform_device *dev)
-{
- const struct mfd_cell *cell = mfd_get_cell(dev);
-
- /* FIXME - is this required or merely another attack of the broken
- * SHARP platform? Looks suspicious.
- */
- tmio_hw_init(dev, platform_get_drvdata(dev));
-
- if (cell->resume)
- cell->resume(dev);
-
- return 0;
-}
-#else
-#define tmio_suspend NULL
-#define tmio_resume NULL
-#endif
-
-static struct platform_driver tmio_driver = {
- .driver.name = "tmio-nand",
- .driver.owner = THIS_MODULE,
- .probe = tmio_probe,
- .remove = tmio_remove,
- .suspend = tmio_suspend,
- .resume = tmio_resume,
-};
-
-module_platform_driver(tmio_driver);
-
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Ian Molton, Dirk Opfer, Chris Humbert, Dmitry Baryshkov");
-MODULE_DESCRIPTION("NAND flash driver on Toshiba Mobile IO controller");
-MODULE_ALIAS("platform:tmio-nand");
diff --git a/drivers/mtd/nand/raw/vf610_nfc.c b/drivers/mtd/nand/raw/vf610_nfc.c
index a2b89b75073f..b643332ea1ff 100644
--- a/drivers/mtd/nand/raw/vf610_nfc.c
+++ b/drivers/mtd/nand/raw/vf610_nfc.c
@@ -206,7 +206,7 @@ static inline bool vf610_nfc_kernel_is_little_endian(void)
#endif
}
-/**
+/*
* Read accessor for internal SRAM buffer
* @dst: destination address in regular memory
* @src: source address in SRAM buffer
@@ -241,7 +241,7 @@ static inline void vf610_nfc_rd_from_sram(void *dst, const void __iomem *src,
}
}
-/**
+/*
* Write accessor for internal SRAM buffer
* @dst: destination address in SRAM buffer
* @src: source address in regular memory
diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile
index b520fe634041..4ec973b8b6bf 100644
--- a/drivers/mtd/nand/spi/Makefile
+++ b/drivers/mtd/nand/spi/Makefile
@@ -1,3 +1,3 @@
# SPDX-License-Identifier: GPL-2.0
-spinand-objs := core.o ato.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o
+spinand-objs := core.o alliancememory.o ato.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o
obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
diff --git a/drivers/mtd/nand/spi/alliancememory.c b/drivers/mtd/nand/spi/alliancememory.c
new file mode 100644
index 000000000000..7936ea546b03
--- /dev/null
+++ b/drivers/mtd/nand/spi/alliancememory.c
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Author: Mario Kicherer <dev@kicherer.org>
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/mtd/spinand.h>
+
+#define SPINAND_MFR_ALLIANCEMEMORY 0x52
+
+#define AM_STATUS_ECC_BITMASK (3 << 4)
+
+#define AM_STATUS_ECC_NONE_DETECTED (0 << 4)
+#define AM_STATUS_ECC_CORRECTED (1 << 4)
+#define AM_STATUS_ECC_ERRORED (2 << 4)
+#define AM_STATUS_ECC_MAX_CORRECTED (3 << 4)
+
+static SPINAND_OP_VARIANTS(read_cache_variants,
+ SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
+
+static SPINAND_OP_VARIANTS(write_cache_variants,
+ SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
+ SPINAND_PROG_LOAD(true, 0, NULL, 0));
+
+static SPINAND_OP_VARIANTS(update_cache_variants,
+ SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
+ SPINAND_PROG_LOAD(false, 0, NULL, 0));
+
+static int am_get_eccsize(struct mtd_info *mtd)
+{
+ if (mtd->oobsize == 64)
+ return 0x20;
+ else if (mtd->oobsize == 128)
+ return 0x38;
+ else if (mtd->oobsize == 256)
+ return 0x70;
+ else
+ return -EINVAL;
+}
+
+static int am_ooblayout_ecc(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ int ecc_bytes;
+
+ ecc_bytes = am_get_eccsize(mtd);
+ if (ecc_bytes < 0)
+ return ecc_bytes;
+
+ region->offset = mtd->oobsize - ecc_bytes;
+ region->length = ecc_bytes;
+
+ return 0;
+}
+
+static int am_ooblayout_free(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ int ecc_bytes;
+
+ if (section)
+ return -ERANGE;
+
+ ecc_bytes = am_get_eccsize(mtd);
+ if (ecc_bytes < 0)
+ return ecc_bytes;
+
+ /*
+ * It is unclear how many bytes are used for the bad block marker. We
+ * reserve the common two bytes here.
+ *
+ * The free area in this kind of flash is divided into chunks where the
+ * first 4 bytes of each chunk are unprotected. The number of chunks
+ * depends on the specific model. The models with 4096+256 bytes pages
+ * have 8 chunks, the others 4 chunks.
+ */
+
+ region->offset = 2;
+ region->length = mtd->oobsize - 2 - ecc_bytes;
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops am_ooblayout = {
+ .ecc = am_ooblayout_ecc,
+ .free = am_ooblayout_free,
+};
+
+static int am_ecc_get_status(struct spinand_device *spinand, u8 status)
+{
+ switch (status & AM_STATUS_ECC_BITMASK) {
+ case AM_STATUS_ECC_NONE_DETECTED:
+ return 0;
+
+ case AM_STATUS_ECC_CORRECTED:
+ /*
+ * use oobsize to determine the flash model and the maximum of
+ * correctable errors and return maximum - 1 by convention
+ */
+ if (spinand->base.mtd.oobsize == 64)
+ return 3;
+ else
+ return 7;
+
+ case AM_STATUS_ECC_ERRORED:
+ return -EBADMSG;
+
+ case AM_STATUS_ECC_MAX_CORRECTED:
+ /*
+ * use oobsize to determine the flash model and the maximum of
+ * correctable errors
+ */
+ if (spinand->base.mtd.oobsize == 64)
+ return 4;
+ else
+ return 8;
+
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static const struct spinand_info alliancememory_spinand_table[] = {
+ SPINAND_INFO("AS5F34G04SND",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x2f),
+ NAND_MEMORG(1, 2048, 128, 64, 4096, 80, 1, 1, 1),
+ NAND_ECCREQ(4, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&am_ooblayout,
+ am_ecc_get_status)),
+};
+
+static const struct spinand_manufacturer_ops alliancememory_spinand_manuf_ops = {
+};
+
+const struct spinand_manufacturer alliancememory_spinand_manufacturer = {
+ .id = SPINAND_MFR_ALLIANCEMEMORY,
+ .name = "AllianceMemory",
+ .chips = alliancememory_spinand_table,
+ .nchips = ARRAY_SIZE(alliancememory_spinand_table),
+ .ops = &alliancememory_spinand_manuf_ops,
+};
diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index dacd9c0e8b20..638391f77d8c 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -937,6 +937,7 @@ static const struct nand_ops spinand_ops = {
};
static const struct spinand_manufacturer *spinand_manufacturers[] = {
+ &alliancememory_spinand_manufacturer,
&ato_spinand_manufacturer,
&gigadevice_spinand_manufacturer,
&macronix_spinand_manufacturer,
diff --git a/drivers/mtd/nand/spi/macronix.c b/drivers/mtd/nand/spi/macronix.c
index dce835132a1e..722a9738ba37 100644
--- a/drivers/mtd/nand/spi/macronix.c
+++ b/drivers/mtd/nand/spi/macronix.c
@@ -83,9 +83,10 @@ static int mx35lf1ge4ab_ecc_get_status(struct spinand_device *spinand,
* in order to avoid forcing the wear-leveling layer to move
* data around if it's not necessary.
*/
- if (mx35lf1ge4ab_get_eccsr(spinand, &eccsr))
+ if (mx35lf1ge4ab_get_eccsr(spinand, spinand->scratchbuf))
return nanddev_get_ecc_conf(nand)->strength;
+ eccsr = *spinand->scratchbuf;
if (WARN_ON(eccsr > nanddev_get_ecc_conf(nand)->strength ||
!eccsr))
return nanddev_get_ecc_conf(nand)->strength;
diff --git a/drivers/mtd/parsers/ofpart_core.c b/drivers/mtd/parsers/ofpart_core.c
index 192190c42fc8..e7b8e9d0a910 100644
--- a/drivers/mtd/parsers/ofpart_core.c
+++ b/drivers/mtd/parsers/ofpart_core.c
@@ -122,6 +122,25 @@ static int parse_fixed_partitions(struct mtd_info *master,
a_cells = of_n_addr_cells(pp);
s_cells = of_n_size_cells(pp);
+ if (!dedicated && s_cells == 0) {
+ /*
+ * This is a ugly workaround to not create
+ * regression on devices that are still creating
+ * partitions as direct children of the nand controller.
+ * This can happen in case the nand controller node has
+ * #size-cells equal to 0 and the firmware (e.g.
+ * U-Boot) just add the partitions there assuming
+ * 32-bit addressing.
+ *
+ * If you get this warning your firmware and/or DTS
+ * should be really fixed.
+ *
+ * This is working only for devices smaller than 4GiB.
+ */
+ pr_warn("%s: ofpart partition %pOF (%pOF) #size-cells is wrongly set to <0>, assuming <1> for parsing partitions.\n",
+ master->name, pp, mtd_node);
+ s_cells = 1;
+ }
if (len / 4 != a_cells + s_cells) {
pr_debug("%s: ofpart partition %pOF (%pOF) error parsing reg property.\n",
master->name, pp,
diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
index d67c926bca8b..0a78045ca1d9 100644
--- a/drivers/mtd/spi-nor/core.c
+++ b/drivers/mtd/spi-nor/core.c
@@ -9,19 +9,18 @@
#include <linux/err.h>
#include <linux/errno.h>
-#include <linux/module.h>
#include <linux/delay.h>
#include <linux/device.h>
-#include <linux/mutex.h>
#include <linux/math64.h>
-#include <linux/sizes.h>
-#include <linux/slab.h>
-
+#include <linux/module.h>
#include <linux/mtd/mtd.h>
+#include <linux/mtd/spi-nor.h>
+#include <linux/mutex.h>
#include <linux/of_platform.h>
#include <linux/sched/task_stack.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
#include <linux/spi/flash.h>
-#include <linux/mtd/spi-nor.h>
#include "core.h"
@@ -2027,6 +2026,15 @@ void spi_nor_set_erase_type(struct spi_nor_erase_type *erase, u32 size,
}
/**
+ * spi_nor_mask_erase_type() - mask out a SPI NOR erase type
+ * @erase: pointer to a structure that describes a SPI NOR erase type
+ */
+void spi_nor_mask_erase_type(struct spi_nor_erase_type *erase)
+{
+ erase->size = 0;
+}
+
+/**
* spi_nor_init_uniform_erase_map() - Initialize uniform erase map
* @map: the erase map of the SPI NOR
* @erase_mask: bitmask encoding erase types that can erase the entire
diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h
index f03b55cf7e6f..25423225c29d 100644
--- a/drivers/mtd/spi-nor/core.h
+++ b/drivers/mtd/spi-nor/core.h
@@ -529,33 +529,30 @@ struct flash_info {
const struct spi_nor_fixups *fixups;
};
+#define SPI_NOR_ID_2ITEMS(_id) ((_id) >> 8) & 0xff, (_id) & 0xff
+#define SPI_NOR_ID_3ITEMS(_id) ((_id) >> 16) & 0xff, SPI_NOR_ID_2ITEMS(_id)
+
+#define SPI_NOR_ID(_jedec_id, _ext_id) \
+ .id = { SPI_NOR_ID_3ITEMS(_jedec_id), SPI_NOR_ID_2ITEMS(_ext_id) }, \
+ .id_len = !(_jedec_id) ? 0 : (3 + ((_ext_id) ? 2 : 0))
+
+#define SPI_NOR_ID6(_jedec_id, _ext_id) \
+ .id = { SPI_NOR_ID_3ITEMS(_jedec_id), SPI_NOR_ID_3ITEMS(_ext_id) }, \
+ .id_len = 6
+
+#define SPI_NOR_GEOMETRY(_sector_size, _n_sectors) \
+ .sector_size = (_sector_size), \
+ .n_sectors = (_n_sectors), \
+ .page_size = 256
+
/* Used when the "_ext_id" is two bytes at most */
#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors) \
- .id = { \
- ((_jedec_id) >> 16) & 0xff, \
- ((_jedec_id) >> 8) & 0xff, \
- (_jedec_id) & 0xff, \
- ((_ext_id) >> 8) & 0xff, \
- (_ext_id) & 0xff, \
- }, \
- .id_len = (!(_jedec_id) ? 0 : (3 + ((_ext_id) ? 2 : 0))), \
- .sector_size = (_sector_size), \
- .n_sectors = (_n_sectors), \
- .page_size = 256, \
+ SPI_NOR_ID((_jedec_id), (_ext_id)), \
+ SPI_NOR_GEOMETRY((_sector_size), (_n_sectors)),
#define INFO6(_jedec_id, _ext_id, _sector_size, _n_sectors) \
- .id = { \
- ((_jedec_id) >> 16) & 0xff, \
- ((_jedec_id) >> 8) & 0xff, \
- (_jedec_id) & 0xff, \
- ((_ext_id) >> 16) & 0xff, \
- ((_ext_id) >> 8) & 0xff, \
- (_ext_id) & 0xff, \
- }, \
- .id_len = 6, \
- .sector_size = (_sector_size), \
- .n_sectors = (_n_sectors), \
- .page_size = 256, \
+ SPI_NOR_ID6((_jedec_id), (_ext_id)), \
+ SPI_NOR_GEOMETRY((_sector_size), (_n_sectors)),
#define CAT25_INFO(_sector_size, _n_sectors, _page_size, _addr_nbytes) \
.sector_size = (_sector_size), \
@@ -684,6 +681,7 @@ void spi_nor_set_pp_settings(struct spi_nor_pp_command *pp, u8 opcode,
void spi_nor_set_erase_type(struct spi_nor_erase_type *erase, u32 size,
u8 opcode);
+void spi_nor_mask_erase_type(struct spi_nor_erase_type *erase);
struct spi_nor_erase_region *
spi_nor_region_next(struct spi_nor_erase_region *region);
void spi_nor_init_uniform_erase_map(struct spi_nor_erase_map *map,
diff --git a/drivers/mtd/spi-nor/debugfs.c b/drivers/mtd/spi-nor/debugfs.c
index ff895f6758ea..845b78c7ecc7 100644
--- a/drivers/mtd/spi-nor/debugfs.c
+++ b/drivers/mtd/spi-nor/debugfs.c
@@ -1,9 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
+#include <linux/debugfs.h>
#include <linux/mtd/spi-nor.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi-mem.h>
-#include <linux/debugfs.h>
#include "core.h"
diff --git a/drivers/mtd/spi-nor/issi.c b/drivers/mtd/spi-nor/issi.c
index a0ddad2afffc..400e2b42f45a 100644
--- a/drivers/mtd/spi-nor/issi.c
+++ b/drivers/mtd/spi-nor/issi.c
@@ -18,7 +18,7 @@ is25lp256_post_bfpt_fixups(struct spi_nor *nor,
* BFPT_DWORD1_ADDRESS_BYTES_3_ONLY.
* Overwrite the number of address bytes advertised by the BFPT.
*/
- if ((bfpt->dwords[BFPT_DWORD(1)] & BFPT_DWORD1_ADDRESS_BYTES_MASK) ==
+ if ((bfpt->dwords[SFDP_DWORD(1)] & BFPT_DWORD1_ADDRESS_BYTES_MASK) ==
BFPT_DWORD1_ADDRESS_BYTES_3_ONLY)
nor->params->addr_nbytes = 4;
diff --git a/drivers/mtd/spi-nor/macronix.c b/drivers/mtd/spi-nor/macronix.c
index d81a4cb2812b..6853ec9ae65d 100644
--- a/drivers/mtd/spi-nor/macronix.c
+++ b/drivers/mtd/spi-nor/macronix.c
@@ -22,7 +22,7 @@ mx25l25635_post_bfpt_fixups(struct spi_nor *nor,
* seems that the F version advertises support for Fast Read 4-4-4 in
* its BFPT table.
*/
- if (bfpt->dwords[BFPT_DWORD(5)] & BFPT_DWORD5_FAST_READ_4_4_4)
+ if (bfpt->dwords[SFDP_DWORD(5)] & BFPT_DWORD5_FAST_READ_4_4_4)
nor->flags |= SNOR_F_4B_OPCODES;
return 0;
diff --git a/drivers/mtd/spi-nor/sfdp.c b/drivers/mtd/spi-nor/sfdp.c
index 8434f654eca1..298ab5e53a8c 100644
--- a/drivers/mtd/spi-nor/sfdp.c
+++ b/drivers/mtd/spi-nor/sfdp.c
@@ -5,9 +5,9 @@
*/
#include <linux/bitfield.h>
+#include <linux/mtd/spi-nor.h>
#include <linux/slab.h>
#include <linux/sort.h>
-#include <linux/mtd/spi-nor.h>
#include "core.h"
@@ -242,64 +242,64 @@ static const struct sfdp_bfpt_read sfdp_bfpt_reads[] = {
/* Fast Read 1-1-2 */
{
SNOR_HWCAPS_READ_1_1_2,
- BFPT_DWORD(1), BIT(16), /* Supported bit */
- BFPT_DWORD(4), 0, /* Settings */
+ SFDP_DWORD(1), BIT(16), /* Supported bit */
+ SFDP_DWORD(4), 0, /* Settings */
SNOR_PROTO_1_1_2,
},
/* Fast Read 1-2-2 */
{
SNOR_HWCAPS_READ_1_2_2,
- BFPT_DWORD(1), BIT(20), /* Supported bit */
- BFPT_DWORD(4), 16, /* Settings */
+ SFDP_DWORD(1), BIT(20), /* Supported bit */
+ SFDP_DWORD(4), 16, /* Settings */
SNOR_PROTO_1_2_2,
},
/* Fast Read 2-2-2 */
{
SNOR_HWCAPS_READ_2_2_2,
- BFPT_DWORD(5), BIT(0), /* Supported bit */
- BFPT_DWORD(6), 16, /* Settings */
+ SFDP_DWORD(5), BIT(0), /* Supported bit */
+ SFDP_DWORD(6), 16, /* Settings */
SNOR_PROTO_2_2_2,
},
/* Fast Read 1-1-4 */
{
SNOR_HWCAPS_READ_1_1_4,
- BFPT_DWORD(1), BIT(22), /* Supported bit */
- BFPT_DWORD(3), 16, /* Settings */
+ SFDP_DWORD(1), BIT(22), /* Supported bit */
+ SFDP_DWORD(3), 16, /* Settings */
SNOR_PROTO_1_1_4,
},
/* Fast Read 1-4-4 */
{
SNOR_HWCAPS_READ_1_4_4,
- BFPT_DWORD(1), BIT(21), /* Supported bit */
- BFPT_DWORD(3), 0, /* Settings */
+ SFDP_DWORD(1), BIT(21), /* Supported bit */
+ SFDP_DWORD(3), 0, /* Settings */
SNOR_PROTO_1_4_4,
},
/* Fast Read 4-4-4 */
{
SNOR_HWCAPS_READ_4_4_4,
- BFPT_DWORD(5), BIT(4), /* Supported bit */
- BFPT_DWORD(7), 16, /* Settings */
+ SFDP_DWORD(5), BIT(4), /* Supported bit */
+ SFDP_DWORD(7), 16, /* Settings */
SNOR_PROTO_4_4_4,
},
};
static const struct sfdp_bfpt_erase sfdp_bfpt_erases[] = {
/* Erase Type 1 in DWORD8 bits[15:0] */
- {BFPT_DWORD(8), 0},
+ {SFDP_DWORD(8), 0},
/* Erase Type 2 in DWORD8 bits[31:16] */
- {BFPT_DWORD(8), 16},
+ {SFDP_DWORD(8), 16},
/* Erase Type 3 in DWORD9 bits[15:0] */
- {BFPT_DWORD(9), 0},
+ {SFDP_DWORD(9), 0},
/* Erase Type 4 in DWORD9 bits[31:16] */
- {BFPT_DWORD(9), 16},
+ {SFDP_DWORD(9), 16},
};
/**
@@ -458,7 +458,7 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
le32_to_cpu_array(bfpt.dwords, BFPT_DWORD_MAX);
/* Number of address bytes. */
- switch (bfpt.dwords[BFPT_DWORD(1)] & BFPT_DWORD1_ADDRESS_BYTES_MASK) {
+ switch (bfpt.dwords[SFDP_DWORD(1)] & BFPT_DWORD1_ADDRESS_BYTES_MASK) {
case BFPT_DWORD1_ADDRESS_BYTES_3_ONLY:
case BFPT_DWORD1_ADDRESS_BYTES_3_OR_4:
params->addr_nbytes = 3;
@@ -475,7 +475,7 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
}
/* Flash Memory Density (in bits). */
- val = bfpt.dwords[BFPT_DWORD(2)];
+ val = bfpt.dwords[SFDP_DWORD(2)];
if (val & BIT(31)) {
val &= ~BIT(31);
@@ -555,13 +555,13 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt);
/* Page size: this field specifies 'N' so the page size = 2^N bytes. */
- val = bfpt.dwords[BFPT_DWORD(11)];
+ val = bfpt.dwords[SFDP_DWORD(11)];
val &= BFPT_DWORD11_PAGE_SIZE_MASK;
val >>= BFPT_DWORD11_PAGE_SIZE_SHIFT;
params->page_size = 1U << val;
/* Quad Enable Requirements. */
- switch (bfpt.dwords[BFPT_DWORD(15)] & BFPT_DWORD15_QER_MASK) {
+ switch (bfpt.dwords[SFDP_DWORD(15)] & BFPT_DWORD15_QER_MASK) {
case BFPT_DWORD15_QER_NONE:
params->quad_enable = NULL;
break;
@@ -608,7 +608,7 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
}
/* Soft Reset support. */
- if (bfpt.dwords[BFPT_DWORD(16)] & BFPT_DWORD16_SWRST_EN_RST)
+ if (bfpt.dwords[SFDP_DWORD(16)] & BFPT_DWORD16_SWRST_EN_RST)
nor->flags |= SNOR_F_SOFT_RESET;
/* Stop here if not JESD216 rev C or later. */
@@ -616,7 +616,7 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt);
/* 8D-8D-8D command extension. */
- switch (bfpt.dwords[BFPT_DWORD(18)] & BFPT_DWORD18_CMD_EXT_MASK) {
+ switch (bfpt.dwords[SFDP_DWORD(18)] & BFPT_DWORD18_CMD_EXT_MASK) {
case BFPT_DWORD18_CMD_EXT_REP:
nor->cmd_ext_type = SPI_NOR_EXT_REPEAT;
break;
@@ -875,7 +875,7 @@ static int spi_nor_init_non_uniform_erase_map(struct spi_nor *nor,
*/
for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++)
if (!(regions_erase_type & BIT(erase[i].idx)))
- spi_nor_set_erase_type(&erase[i], 0, 0xFF);
+ spi_nor_mask_erase_type(&erase[i]);
return 0;
}
@@ -1004,7 +1004,7 @@ static int spi_nor_parse_4bait(struct spi_nor *nor,
discard_hwcaps |= read->hwcaps;
if ((params->hwcaps.mask & read->hwcaps) &&
- (dwords[0] & read->supported_bit))
+ (dwords[SFDP_DWORD(1)] & read->supported_bit))
read_hwcaps |= read->hwcaps;
}
@@ -1023,7 +1023,7 @@ static int spi_nor_parse_4bait(struct spi_nor *nor,
* authority for specifying Page Program support.
*/
discard_hwcaps |= program->hwcaps;
- if (dwords[0] & program->supported_bit)
+ if (dwords[SFDP_DWORD(1)] & program->supported_bit)
pp_hwcaps |= program->hwcaps;
}
@@ -1035,7 +1035,7 @@ static int spi_nor_parse_4bait(struct spi_nor *nor,
for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) {
const struct sfdp_4bait *erase = &erases[i];
- if (dwords[0] & erase->supported_bit)
+ if (dwords[SFDP_DWORD(1)] & erase->supported_bit)
erase_mask |= BIT(i);
}
@@ -1086,10 +1086,10 @@ static int spi_nor_parse_4bait(struct spi_nor *nor,
for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) {
if (erase_mask & BIT(i))
- erase_type[i].opcode = (dwords[1] >>
+ erase_type[i].opcode = (dwords[SFDP_DWORD(2)] >>
erase_type[i].idx * 8) & 0xFF;
else
- spi_nor_set_erase_type(&erase_type[i], 0u, 0xFF);
+ spi_nor_mask_erase_type(&erase_type[i]);
}
/*
@@ -1145,15 +1145,15 @@ static int spi_nor_parse_profile1(struct spi_nor *nor,
le32_to_cpu_array(dwords, profile1_header->length);
/* Get 8D-8D-8D fast read opcode and dummy cycles. */
- opcode = FIELD_GET(PROFILE1_DWORD1_RD_FAST_CMD, dwords[0]);
+ opcode = FIELD_GET(PROFILE1_DWORD1_RD_FAST_CMD, dwords[SFDP_DWORD(1)]);
/* Set the Read Status Register dummy cycles and dummy address bytes. */
- if (dwords[0] & PROFILE1_DWORD1_RDSR_DUMMY)
+ if (dwords[SFDP_DWORD(1)] & PROFILE1_DWORD1_RDSR_DUMMY)
nor->params->rdsr_dummy = 8;
else
nor->params->rdsr_dummy = 4;
- if (dwords[0] & PROFILE1_DWORD1_RDSR_ADDR_BYTES)
+ if (dwords[SFDP_DWORD(1)] & PROFILE1_DWORD1_RDSR_ADDR_BYTES)
nor->params->rdsr_addr_nbytes = 4;
else
nor->params->rdsr_addr_nbytes = 0;
@@ -1167,13 +1167,16 @@ static int spi_nor_parse_profile1(struct spi_nor *nor,
* Default to PROFILE1_DUMMY_DEFAULT if we don't find anything, and let
* flashes set the correct value if needed in their fixup hooks.
*/
- dummy = FIELD_GET(PROFILE1_DWORD4_DUMMY_200MHZ, dwords[3]);
+ dummy = FIELD_GET(PROFILE1_DWORD4_DUMMY_200MHZ, dwords[SFDP_DWORD(4)]);
if (!dummy)
- dummy = FIELD_GET(PROFILE1_DWORD5_DUMMY_166MHZ, dwords[4]);
+ dummy = FIELD_GET(PROFILE1_DWORD5_DUMMY_166MHZ,
+ dwords[SFDP_DWORD(5)]);
if (!dummy)
- dummy = FIELD_GET(PROFILE1_DWORD5_DUMMY_133MHZ, dwords[4]);
+ dummy = FIELD_GET(PROFILE1_DWORD5_DUMMY_133MHZ,
+ dwords[SFDP_DWORD(5)]);
if (!dummy)
- dummy = FIELD_GET(PROFILE1_DWORD5_DUMMY_100MHZ, dwords[4]);
+ dummy = FIELD_GET(PROFILE1_DWORD5_DUMMY_100MHZ,
+ dwords[SFDP_DWORD(5)]);
if (!dummy)
dev_dbg(nor->dev,
"Can't find dummy cycles from Profile 1.0 table\n");
@@ -1228,7 +1231,8 @@ static int spi_nor_parse_sccr(struct spi_nor *nor,
le32_to_cpu_array(dwords, sccr_header->length);
- if (FIELD_GET(SCCR_DWORD22_OCTAL_DTR_EN_VOLATILE, dwords[22]))
+ if (FIELD_GET(SCCR_DWORD22_OCTAL_DTR_EN_VOLATILE,
+ dwords[SFDP_DWORD(22)]))
nor->flags |= SNOR_F_IO_MODE_EN_VOLATILE;
out:
diff --git a/drivers/mtd/spi-nor/sfdp.h b/drivers/mtd/spi-nor/sfdp.h
index c1969f0a2f46..500659b35655 100644
--- a/drivers/mtd/spi-nor/sfdp.h
+++ b/drivers/mtd/spi-nor/sfdp.h
@@ -13,13 +13,12 @@
#define SFDP_JESD216A_MINOR 5
#define SFDP_JESD216B_MINOR 6
+/* SFDP DWORDS are indexed from 1 but C arrays are indexed from 0. */
+#define SFDP_DWORD(i) ((i) - 1)
+
/* Basic Flash Parameter Table */
-/*
- * JESD216 rev D defines a Basic Flash Parameter Table of 20 DWORDs.
- * They are indexed from 1 but C arrays are indexed from 0.
- */
-#define BFPT_DWORD(i) ((i) - 1)
+/* JESD216 rev D defines a Basic Flash Parameter Table of 20 DWORDs. */
#define BFPT_DWORD_MAX 20
struct sfdp_bfpt {
diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c
index b621cdfd506f..12a256c0ef4c 100644
--- a/drivers/mtd/spi-nor/spansion.c
+++ b/drivers/mtd/spi-nor/spansion.c
@@ -15,14 +15,19 @@
#define SPINOR_OP_RD_ANY_REG 0x65 /* Read any register */
#define SPINOR_OP_WR_ANY_REG 0x71 /* Write any register */
#define SPINOR_REG_CYPRESS_CFR1V 0x00800002
-#define SPINOR_REG_CYPRESS_CFR1V_QUAD_EN BIT(1) /* Quad Enable */
+#define SPINOR_REG_CYPRESS_CFR1_QUAD_EN BIT(1) /* Quad Enable */
#define SPINOR_REG_CYPRESS_CFR2V 0x00800003
-#define SPINOR_REG_CYPRESS_CFR2V_MEMLAT_11_24 0xb
+#define SPINOR_REG_CYPRESS_CFR2_MEMLAT_11_24 0xb
#define SPINOR_REG_CYPRESS_CFR3V 0x00800004
-#define SPINOR_REG_CYPRESS_CFR3V_PGSZ BIT(4) /* Page size. */
+#define SPINOR_REG_CYPRESS_CFR3_PGSZ BIT(4) /* Page size. */
#define SPINOR_REG_CYPRESS_CFR5V 0x00800006
-#define SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_EN 0x3
-#define SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_DS 0
+#define SPINOR_REG_CYPRESS_CFR5_BIT6 BIT(6)
+#define SPINOR_REG_CYPRESS_CFR5_DDR BIT(1)
+#define SPINOR_REG_CYPRESS_CFR5_OPI BIT(0)
+#define SPINOR_REG_CYPRESS_CFR5_OCT_DTR_EN \
+ (SPINOR_REG_CYPRESS_CFR5_BIT6 | SPINOR_REG_CYPRESS_CFR5_DDR | \
+ SPINOR_REG_CYPRESS_CFR5_OPI)
+#define SPINOR_REG_CYPRESS_CFR5_OCT_DTR_DS SPINOR_REG_CYPRESS_CFR5_BIT6
#define SPINOR_OP_CYPRESS_RD_FAST 0xee
/* Cypress SPI NOR flash operations. */
@@ -52,7 +57,7 @@ static int cypress_nor_octal_dtr_en(struct spi_nor *nor)
u8 addr_mode_nbytes = nor->params->addr_mode_nbytes;
/* Use 24 dummy cycles for memory array reads. */
- *buf = SPINOR_REG_CYPRESS_CFR2V_MEMLAT_11_24;
+ *buf = SPINOR_REG_CYPRESS_CFR2_MEMLAT_11_24;
op = (struct spi_mem_op)
CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes,
SPINOR_REG_CYPRESS_CFR2V, 1, buf);
@@ -64,7 +69,7 @@ static int cypress_nor_octal_dtr_en(struct spi_nor *nor)
nor->read_dummy = 24;
/* Set the octal and DTR enable bits. */
- buf[0] = SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_EN;
+ buf[0] = SPINOR_REG_CYPRESS_CFR5_OCT_DTR_EN;
op = (struct spi_mem_op)
CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes,
SPINOR_REG_CYPRESS_CFR5V, 1, buf);
@@ -98,7 +103,7 @@ static int cypress_nor_octal_dtr_dis(struct spi_nor *nor)
* in 8D-8D-8D mode. Since there is no register at the next location,
* just initialize the value to 0 and let the transaction go on.
*/
- buf[0] = SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_DS;
+ buf[0] = SPINOR_REG_CYPRESS_CFR5_OCT_DTR_DS;
buf[1] = 0;
op = (struct spi_mem_op)
CYPRESS_NOR_WR_ANY_REG_OP(nor->addr_nbytes,
@@ -150,11 +155,11 @@ static int cypress_nor_quad_enable_volatile(struct spi_nor *nor)
if (ret)
return ret;
- if (nor->bouncebuf[0] & SPINOR_REG_CYPRESS_CFR1V_QUAD_EN)
+ if (nor->bouncebuf[0] & SPINOR_REG_CYPRESS_CFR1_QUAD_EN)
return 0;
/* Update the Quad Enable bit. */
- nor->bouncebuf[0] |= SPINOR_REG_CYPRESS_CFR1V_QUAD_EN;
+ nor->bouncebuf[0] |= SPINOR_REG_CYPRESS_CFR1_QUAD_EN;
op = (struct spi_mem_op)
CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes,
SPINOR_REG_CYPRESS_CFR1V, 1,
@@ -205,7 +210,7 @@ static int cypress_nor_set_page_size(struct spi_nor *nor)
if (ret)
return ret;
- if (nor->bouncebuf[0] & SPINOR_REG_CYPRESS_CFR3V_PGSZ)
+ if (nor->bouncebuf[0] & SPINOR_REG_CYPRESS_CFR3_PGSZ)
nor->params->page_size = 512;
else
nor->params->page_size = 256;
diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c
index 75eaecc8639f..1de87062c67b 100644
--- a/drivers/mtd/ubi/block.c
+++ b/drivers/mtd/ubi/block.c
@@ -35,7 +35,6 @@
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/mtd/ubi.h>
-#include <linux/workqueue.h>
#include <linux/blkdev.h>
#include <linux/blk-mq.h>
#include <linux/hdreg.h>
@@ -62,7 +61,6 @@ struct ubiblock_param {
};
struct ubiblock_pdu {
- struct work_struct work;
struct ubi_sgl usgl;
};
@@ -82,8 +80,6 @@ struct ubiblock {
struct gendisk *gd;
struct request_queue *rq;
- struct workqueue_struct *wq;
-
struct mutex dev_mutex;
struct list_head list;
struct blk_mq_tag_set tag_set;
@@ -181,20 +177,29 @@ static struct ubiblock *find_dev_nolock(int ubi_num, int vol_id)
return NULL;
}
-static int ubiblock_read(struct ubiblock_pdu *pdu)
+static blk_status_t ubiblock_read(struct request *req)
{
- int ret, leb, offset, bytes_left, to_read;
- u64 pos;
- struct request *req = blk_mq_rq_from_pdu(pdu);
+ struct ubiblock_pdu *pdu = blk_mq_rq_to_pdu(req);
struct ubiblock *dev = req->q->queuedata;
+ u64 pos = blk_rq_pos(req) << 9;
+ int to_read = blk_rq_bytes(req);
+ int bytes_left = to_read;
+ /* Get LEB:offset address to read from */
+ int offset = do_div(pos, dev->leb_size);
+ int leb = pos;
+ struct req_iterator iter;
+ struct bio_vec bvec;
+ int ret;
- to_read = blk_rq_bytes(req);
- pos = blk_rq_pos(req) << 9;
+ blk_mq_start_request(req);
- /* Get LEB:offset address to read from */
- offset = do_div(pos, dev->leb_size);
- leb = pos;
- bytes_left = to_read;
+ /*
+ * It is safe to ignore the return value of blk_rq_map_sg() because
+ * the number of sg entries is limited to UBI_MAX_SG_COUNT
+ * and ubi_read_sg() will check that limit.
+ */
+ ubi_sgl_init(&pdu->usgl);
+ blk_rq_map_sg(req->q, req, pdu->usgl.sg);
while (bytes_left) {
/*
@@ -206,14 +211,17 @@ static int ubiblock_read(struct ubiblock_pdu *pdu)
ret = ubi_read_sg(dev->desc, leb, &pdu->usgl, offset, to_read);
if (ret < 0)
- return ret;
+ break;
bytes_left -= to_read;
to_read = bytes_left;
leb += 1;
offset = 0;
}
- return 0;
+
+ rq_for_each_segment(bvec, req, iter)
+ flush_dcache_page(bvec.bv_page);
+ return errno_to_blk_status(ret);
}
static int ubiblock_open(struct block_device *bdev, fmode_t mode)
@@ -289,47 +297,15 @@ static const struct block_device_operations ubiblock_ops = {
.getgeo = ubiblock_getgeo,
};
-static void ubiblock_do_work(struct work_struct *work)
-{
- int ret;
- struct ubiblock_pdu *pdu = container_of(work, struct ubiblock_pdu, work);
- struct request *req = blk_mq_rq_from_pdu(pdu);
- struct req_iterator iter;
- struct bio_vec bvec;
-
- blk_mq_start_request(req);
-
- /*
- * It is safe to ignore the return value of blk_rq_map_sg() because
- * the number of sg entries is limited to UBI_MAX_SG_COUNT
- * and ubi_read_sg() will check that limit.
- */
- blk_rq_map_sg(req->q, req, pdu->usgl.sg);
-
- ret = ubiblock_read(pdu);
-
- rq_for_each_segment(bvec, req, iter)
- flush_dcache_page(bvec.bv_page);
-
- blk_mq_end_request(req, errno_to_blk_status(ret));
-}
-
static blk_status_t ubiblock_queue_rq(struct blk_mq_hw_ctx *hctx,
const struct blk_mq_queue_data *bd)
{
- struct request *req = bd->rq;
- struct ubiblock *dev = hctx->queue->queuedata;
- struct ubiblock_pdu *pdu = blk_mq_rq_to_pdu(req);
-
- switch (req_op(req)) {
+ switch (req_op(bd->rq)) {
case REQ_OP_READ:
- ubi_sgl_init(&pdu->usgl);
- queue_work(dev->wq, &pdu->work);
- return BLK_STS_OK;
+ return ubiblock_read(bd->rq);
default:
return BLK_STS_IOERR;
}
-
}
static int ubiblock_init_request(struct blk_mq_tag_set *set,
@@ -339,8 +315,6 @@ static int ubiblock_init_request(struct blk_mq_tag_set *set,
struct ubiblock_pdu *pdu = blk_mq_rq_to_pdu(req);
sg_init_table(pdu->usgl.sg, UBI_MAX_SG_COUNT);
- INIT_WORK(&pdu->work, ubiblock_do_work);
-
return 0;
}
@@ -354,9 +328,12 @@ static int calc_disk_capacity(struct ubi_volume_info *vi, u64 *disk_capacity)
u64 size = vi->used_bytes >> 9;
if (vi->used_bytes % 512) {
- pr_warn("UBI: block: volume size is not a multiple of 512, "
- "last %llu bytes are ignored!\n",
- vi->used_bytes - (size << 9));
+ if (vi->vol_type == UBI_DYNAMIC_VOLUME)
+ pr_warn("UBI: block: volume size is not a multiple of 512, last %llu bytes are ignored!\n",
+ vi->used_bytes - (size << 9));
+ else
+ pr_info("UBI: block: volume size is not a multiple of 512, last %llu bytes are ignored!\n",
+ vi->used_bytes - (size << 9));
}
if ((sector_t)size != size)
@@ -401,7 +378,7 @@ int ubiblock_create(struct ubi_volume_info *vi)
dev->tag_set.ops = &ubiblock_mq_ops;
dev->tag_set.queue_depth = 64;
dev->tag_set.numa_node = NUMA_NO_NODE;
- dev->tag_set.flags = BLK_MQ_F_SHOULD_MERGE;
+ dev->tag_set.flags = BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_BLOCKING;
dev->tag_set.cmd_size = sizeof(struct ubiblock_pdu);
dev->tag_set.driver_data = dev;
dev->tag_set.nr_hw_queues = 1;
@@ -439,32 +416,20 @@ int ubiblock_create(struct ubi_volume_info *vi)
dev->rq = gd->queue;
blk_queue_max_segments(dev->rq, UBI_MAX_SG_COUNT);
- /*
- * Create one workqueue per volume (per registered block device).
- * Remember workqueues are cheap, they're not threads.
- */
- dev->wq = alloc_workqueue("%s", 0, 0, gd->disk_name);
- if (!dev->wq) {
- ret = -ENOMEM;
- goto out_remove_minor;
- }
-
list_add_tail(&dev->list, &ubiblock_devices);
/* Must be the last step: anyone can call file ops from now on */
- ret = add_disk(dev->gd);
+ ret = device_add_disk(vi->dev, dev->gd, NULL);
if (ret)
- goto out_destroy_wq;
+ goto out_remove_minor;
dev_info(disk_to_dev(dev->gd), "created from ubi%d:%d(%s)",
dev->ubi_num, dev->vol_id, vi->name);
mutex_unlock(&devices_mutex);
return 0;
-out_destroy_wq:
- list_del(&dev->list);
- destroy_workqueue(dev->wq);
out_remove_minor:
+ list_del(&dev->list);
idr_remove(&ubiblock_minor_idr, gd->first_minor);
out_cleanup_disk:
put_disk(dev->gd);
@@ -482,8 +447,6 @@ static void ubiblock_cleanup(struct ubiblock *dev)
{
/* Stop new requests to arrive */
del_gendisk(dev->gd);
- /* Flush pending work */
- destroy_workqueue(dev->wq);
/* Finally destroy the blk queue */
dev_info(disk_to_dev(dev->gd), "released");
put_disk(dev->gd);
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index a901f8edfa41..0904eb40c95f 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -35,7 +35,7 @@
#define MTD_PARAM_LEN_MAX 64
/* Maximum number of comma-separated items in the 'mtd=' parameter */
-#define MTD_PARAM_MAX_COUNT 4
+#define MTD_PARAM_MAX_COUNT 5
/* Maximum value for the number of bad PEBs per 1024 PEBs */
#define MAX_MTD_UBI_BEB_LIMIT 768
@@ -53,12 +53,14 @@
* @ubi_num: UBI number
* @vid_hdr_offs: VID header offset
* @max_beb_per1024: maximum expected number of bad PEBs per 1024 PEBs
+ * @enable_fm: enable fastmap when value is non-zero
*/
struct mtd_dev_param {
char name[MTD_PARAM_LEN_MAX];
int ubi_num;
int vid_hdr_offs;
int max_beb_per1024;
+ int enable_fm;
};
/* Numbers of elements set in the @mtd_dev_param array */
@@ -468,6 +470,7 @@ static int uif_init(struct ubi_device *ubi)
err = ubi_add_volume(ubi, ubi->volumes[i]);
if (err) {
ubi_err(ubi, "cannot add volume %d", i);
+ ubi->volumes[i] = NULL;
goto out_volumes;
}
}
@@ -663,6 +666,12 @@ static int io_init(struct ubi_device *ubi, int max_beb_per1024)
ubi->ec_hdr_alsize = ALIGN(UBI_EC_HDR_SIZE, ubi->hdrs_min_io_size);
ubi->vid_hdr_alsize = ALIGN(UBI_VID_HDR_SIZE, ubi->hdrs_min_io_size);
+ if (ubi->vid_hdr_offset && ((ubi->vid_hdr_offset + UBI_VID_HDR_SIZE) >
+ ubi->vid_hdr_alsize)) {
+ ubi_err(ubi, "VID header offset %d too large.", ubi->vid_hdr_offset);
+ return -EINVAL;
+ }
+
dbg_gen("min_io_size %d", ubi->min_io_size);
dbg_gen("max_write_size %d", ubi->max_write_size);
dbg_gen("hdrs_min_io_size %d", ubi->hdrs_min_io_size);
@@ -906,6 +915,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
ubi->dev.release = dev_release;
ubi->dev.class = &ubi_class;
ubi->dev.groups = ubi_dev_groups;
+ ubi->dev.parent = &mtd->dev;
ubi->mtd = mtd;
ubi->ubi_num = ubi_num;
@@ -1248,7 +1258,7 @@ static int __init ubi_init(void)
mutex_lock(&ubi_devices_mutex);
err = ubi_attach_mtd_dev(mtd, p->ubi_num,
p->vid_hdr_offs, p->max_beb_per1024,
- false);
+ p->enable_fm == 0 ? true : false);
mutex_unlock(&ubi_devices_mutex);
if (err < 0) {
pr_err("UBI error: cannot attach mtd%d\n",
@@ -1427,7 +1437,7 @@ static int ubi_mtd_param_parse(const char *val, const struct kernel_param *kp)
int err = kstrtoint(token, 10, &p->max_beb_per1024);
if (err) {
- pr_err("UBI error: bad value for max_beb_per1024 parameter: %s",
+ pr_err("UBI error: bad value for max_beb_per1024 parameter: %s\n",
token);
return -EINVAL;
}
@@ -1438,13 +1448,25 @@ static int ubi_mtd_param_parse(const char *val, const struct kernel_param *kp)
int err = kstrtoint(token, 10, &p->ubi_num);
if (err) {
- pr_err("UBI error: bad value for ubi_num parameter: %s",
+ pr_err("UBI error: bad value for ubi_num parameter: %s\n",
token);
return -EINVAL;
}
} else
p->ubi_num = UBI_DEV_NUM_AUTO;
+ token = tokens[4];
+ if (token) {
+ int err = kstrtoint(token, 10, &p->enable_fm);
+
+ if (err) {
+ pr_err("UBI error: bad value for enable_fm parameter: %s\n",
+ token);
+ return -EINVAL;
+ }
+ } else
+ p->enable_fm = 0;
+
mtd_devs += 1;
return 0;
}
@@ -1457,11 +1479,13 @@ MODULE_PARM_DESC(mtd, "MTD devices to attach. Parameter format: mtd=<name|num|pa
"Optional \"max_beb_per1024\" parameter specifies the maximum expected bad eraseblock per 1024 eraseblocks. (default value ("
__stringify(CONFIG_MTD_UBI_BEB_LIMIT) ") if 0)\n"
"Optional \"ubi_num\" parameter specifies UBI device number which have to be assigned to the newly created UBI device (assigned automatically by default)\n"
+ "Optional \"enable_fm\" parameter determines whether to enable fastmap during attach. If the value is non-zero, fastmap is enabled. Default value is 0.\n"
"\n"
"Example 1: mtd=/dev/mtd0 - attach MTD device /dev/mtd0.\n"
"Example 2: mtd=content,1984 mtd=4 - attach MTD device with name \"content\" using VID header offset 1984, and MTD device number 4 with default VID header offset.\n"
"Example 3: mtd=/dev/mtd1,0,25 - attach MTD device /dev/mtd1 using default VID header offset and reserve 25*nand_size_in_blocks/1024 erase blocks for bad block handling.\n"
"Example 4: mtd=/dev/mtd1,0,0,5 - attach MTD device /dev/mtd1 to UBI 5 and using default values for the other fields.\n"
+ "example 5: mtd=1,0,0,5 mtd=2,0,0,6,1 - attach MTD device /dev/mtd1 to UBI 5 and disable fastmap; attach MTD device /dev/mtd2 to UBI 6 and enable fastmap.(only works when fastmap is enabled and fm_autoconvert=Y).\n"
"\t(e.g. if the NAND *chipset* has 4096 PEB, 100 will be reserved for this UBI device).");
#ifdef CONFIG_MTD_UBI_FASTMAP
module_param(fm_autoconvert, bool, 0644);
diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c
index fcca6942dbdd..27168f511d6d 100644
--- a/drivers/mtd/ubi/debug.c
+++ b/drivers/mtd/ubi/debug.c
@@ -504,6 +504,7 @@ int ubi_debugfs_init_dev(struct ubi_device *ubi)
{
unsigned long ubi_num = ubi->ubi_num;
struct ubi_debug_info *d = &ubi->dbg;
+ umode_t mode = S_IRUSR | S_IWUSR;
int n;
if (!IS_ENABLED(CONFIG_DEBUG_FS))
@@ -518,41 +519,41 @@ int ubi_debugfs_init_dev(struct ubi_device *ubi)
d->dfs_dir = debugfs_create_dir(d->dfs_dir_name, dfs_rootdir);
- d->dfs_chk_gen = debugfs_create_file("chk_gen", S_IWUSR, d->dfs_dir,
+ d->dfs_chk_gen = debugfs_create_file("chk_gen", mode, d->dfs_dir,
(void *)ubi_num, &dfs_fops);
- d->dfs_chk_io = debugfs_create_file("chk_io", S_IWUSR, d->dfs_dir,
+ d->dfs_chk_io = debugfs_create_file("chk_io", mode, d->dfs_dir,
(void *)ubi_num, &dfs_fops);
- d->dfs_chk_fastmap = debugfs_create_file("chk_fastmap", S_IWUSR,
+ d->dfs_chk_fastmap = debugfs_create_file("chk_fastmap", mode,
d->dfs_dir, (void *)ubi_num,
&dfs_fops);
- d->dfs_disable_bgt = debugfs_create_file("tst_disable_bgt", S_IWUSR,
+ d->dfs_disable_bgt = debugfs_create_file("tst_disable_bgt", mode,
d->dfs_dir, (void *)ubi_num,
&dfs_fops);
d->dfs_emulate_bitflips = debugfs_create_file("tst_emulate_bitflips",
- S_IWUSR, d->dfs_dir,
+ mode, d->dfs_dir,
(void *)ubi_num,
&dfs_fops);
d->dfs_emulate_io_failures = debugfs_create_file("tst_emulate_io_failures",
- S_IWUSR, d->dfs_dir,
+ mode, d->dfs_dir,
(void *)ubi_num,
&dfs_fops);
d->dfs_emulate_power_cut = debugfs_create_file("tst_emulate_power_cut",
- S_IWUSR, d->dfs_dir,
+ mode, d->dfs_dir,
(void *)ubi_num,
&dfs_fops);
d->dfs_power_cut_min = debugfs_create_file("tst_emulate_power_cut_min",
- S_IWUSR, d->dfs_dir,
+ mode, d->dfs_dir,
(void *)ubi_num, &dfs_fops);
d->dfs_power_cut_max = debugfs_create_file("tst_emulate_power_cut_max",
- S_IWUSR, d->dfs_dir,
+ mode, d->dfs_dir,
(void *)ubi_num, &dfs_fops);
debugfs_create_file("detailed_erase_block_info", S_IRUSR, d->dfs_dir,
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
index 09c408c45a62..403b79d6efd5 100644
--- a/drivers/mtd/ubi/eba.c
+++ b/drivers/mtd/ubi/eba.c
@@ -61,7 +61,7 @@ struct ubi_eba_table {
};
/**
- * next_sqnum - get next sequence number.
+ * ubi_next_sqnum - get next sequence number.
* @ubi: UBI device description object
*
* This function returns next sequence number to use, which is just the current
diff --git a/drivers/mtd/ubi/fastmap-wl.c b/drivers/mtd/ubi/fastmap-wl.c
index 0ee452275578..863f571f1adb 100644
--- a/drivers/mtd/ubi/fastmap-wl.c
+++ b/drivers/mtd/ubi/fastmap-wl.c
@@ -146,13 +146,15 @@ void ubi_refill_pools(struct ubi_device *ubi)
if (ubi->fm_anchor) {
wl_tree_add(ubi->fm_anchor, &ubi->free);
ubi->free_count++;
+ ubi->fm_anchor = NULL;
}
- /*
- * All available PEBs are in ubi->free, now is the time to get
- * the best anchor PEBs.
- */
- ubi->fm_anchor = ubi_wl_get_fm_peb(ubi, 1);
+ if (!ubi->fm_disabled)
+ /*
+ * All available PEBs are in ubi->free, now is the time to get
+ * the best anchor PEBs.
+ */
+ ubi->fm_anchor = ubi_wl_get_fm_peb(ubi, 1);
for (;;) {
enough = 0;
diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c
index ca2d9efe62c3..28c8151a0725 100644
--- a/drivers/mtd/ubi/fastmap.c
+++ b/drivers/mtd/ubi/fastmap.c
@@ -93,7 +93,7 @@ size_t ubi_calc_fm_size(struct ubi_device *ubi)
/**
- * new_fm_vhdr - allocate a new volume header for fastmap usage.
+ * new_fm_vbuf() - allocate a new volume header for fastmap usage.
* @ubi: UBI device description object
* @vol_id: the VID of the new header
*
diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c
index 0fce99ff29b5..5db653eacbd4 100644
--- a/drivers/mtd/ubi/kapi.c
+++ b/drivers/mtd/ubi/kapi.c
@@ -79,6 +79,7 @@ void ubi_do_get_volume_info(struct ubi_device *ubi, struct ubi_volume *vol,
vi->name_len = vol->name_len;
vi->name = vol->name;
vi->cdev = vol->cdev.dev;
+ vi->dev = &vol->dev;
}
/**
diff --git a/drivers/mtd/ubi/misc.c b/drivers/mtd/ubi/misc.c
index 7b30c8ee3e82..1794d66b6eb7 100644
--- a/drivers/mtd/ubi/misc.c
+++ b/drivers/mtd/ubi/misc.c
@@ -10,7 +10,7 @@
#include "ubi.h"
/**
- * calc_data_len - calculate how much real data is stored in a buffer.
+ * ubi_calc_data_len - calculate how much real data is stored in a buffer.
* @ubi: UBI device description object
* @buf: a buffer with the contents of the physical eraseblock
* @length: the buffer length
diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c
index 8fcc0bdf0635..2c867d16f89f 100644
--- a/drivers/mtd/ubi/vmt.c
+++ b/drivers/mtd/ubi/vmt.c
@@ -464,7 +464,7 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
for (i = 0; i < -pebs; i++) {
err = ubi_eba_unmap_leb(ubi, vol, reserved_pebs + i);
if (err)
- goto out_acc;
+ goto out_free;
}
spin_lock(&ubi->volumes_lock);
ubi->rsvd_pebs += pebs;
@@ -512,8 +512,10 @@ out_acc:
ubi->avail_pebs += pebs;
spin_unlock(&ubi->volumes_lock);
}
+ return err;
+
out_free:
- kfree(new_eba_tbl);
+ ubi_eba_destroy_table(new_eba_tbl);
return err;
}
@@ -580,6 +582,7 @@ int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol)
if (err) {
ubi_err(ubi, "cannot add character device for volume %d, error %d",
vol_id, err);
+ vol_release(&vol->dev);
return err;
}
@@ -590,15 +593,14 @@ int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol)
vol->dev.groups = volume_dev_groups;
dev_set_name(&vol->dev, "%s_%d", ubi->ubi_name, vol->vol_id);
err = device_register(&vol->dev);
- if (err)
- goto out_cdev;
+ if (err) {
+ cdev_del(&vol->cdev);
+ put_device(&vol->dev);
+ return err;
+ }
self_check_volumes(ubi);
return err;
-
-out_cdev:
- cdev_del(&vol->cdev);
- return err;
}
/**
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index 68eb0f21b3fe..40f39e5d6dfc 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -165,7 +165,7 @@ static void wl_tree_add(struct ubi_wl_entry *e, struct rb_root *root)
}
/**
- * wl_tree_destroy - destroy a wear-leveling entry.
+ * wl_entry_destroy - destroy a wear-leveling entry.
* @ubi: UBI device description object
* @e: the wear-leveling entry to add
*
@@ -890,8 +890,11 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
err = do_sync_erase(ubi, e1, vol_id, lnum, 0);
if (err) {
- if (e2)
+ if (e2) {
+ spin_lock(&ubi->wl_lock);
wl_entry_destroy(ubi, e2);
+ spin_unlock(&ubi->wl_lock);
+ }
goto out_ro;
}
@@ -973,11 +976,11 @@ out_error:
spin_lock(&ubi->wl_lock);
ubi->move_from = ubi->move_to = NULL;
ubi->move_to_put = ubi->wl_scheduled = 0;
+ wl_entry_destroy(ubi, e1);
+ wl_entry_destroy(ubi, e2);
spin_unlock(&ubi->wl_lock);
ubi_free_vid_buf(vidb);
- wl_entry_destroy(ubi, e1);
- wl_entry_destroy(ubi, e2);
out_ro:
ubi_ro_mode(ubi);
@@ -1130,14 +1133,18 @@ static int __erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk)
/* Re-schedule the LEB for erasure */
err1 = schedule_erase(ubi, e, vol_id, lnum, 0, false);
if (err1) {
+ spin_lock(&ubi->wl_lock);
wl_entry_destroy(ubi, e);
+ spin_unlock(&ubi->wl_lock);
err = err1;
goto out_ro;
}
return err;
}
+ spin_lock(&ubi->wl_lock);
wl_entry_destroy(ubi, e);
+ spin_unlock(&ubi->wl_lock);
if (err != -EIO)
/*
* If this is not %-EIO, we have no idea what to do. Scheduling
@@ -1253,6 +1260,18 @@ int ubi_wl_put_peb(struct ubi_device *ubi, int vol_id, int lnum,
retry:
spin_lock(&ubi->wl_lock);
e = ubi->lookuptbl[pnum];
+ if (!e) {
+ /*
+ * This wl entry has been removed for some errors by other
+ * process (eg. wear leveling worker), corresponding process
+ * (except __erase_worker, which cannot concurrent with
+ * ubi_wl_put_peb) will set ubi ro_mode at the same time,
+ * just ignore this wl entry.
+ */
+ spin_unlock(&ubi->wl_lock);
+ up_read(&ubi->fm_protect);
+ return 0;
+ }
if (e == ubi->move_from) {
/*
* User is putting the physical eraseblock which was selected to
diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c
index 354aa3dbfde7..dddb28984bdf 100644
--- a/drivers/net/dsa/ocelot/felix_vsc9959.c
+++ b/drivers/net/dsa/ocelot/felix_vsc9959.c
@@ -554,7 +554,7 @@ static const char * const vsc9959_resource_names[TARGET_MAX] = {
* SGMII/QSGMII MAC PCS can be found.
*/
static const struct resource vsc9959_imdio_res =
- DEFINE_RES_MEM_NAMED(0x8030, 0x8040, "imdio");
+ DEFINE_RES_MEM_NAMED(0x8030, 0x10, "imdio");
static const struct reg_field vsc9959_regfields[REGFIELD_MAX] = {
[ANA_ADVLEARN_VLAN_CHK] = REG_FIELD(ANA_ADVLEARN, 6, 6),
diff --git a/drivers/net/dsa/ocelot/ocelot_ext.c b/drivers/net/dsa/ocelot/ocelot_ext.c
index 14efa6387bd7..063150659816 100644
--- a/drivers/net/dsa/ocelot/ocelot_ext.c
+++ b/drivers/net/dsa/ocelot/ocelot_ext.c
@@ -4,7 +4,6 @@
*/
#include <linux/mfd/ocelot.h>
-#include <linux/phylink.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <soc/mscc/ocelot.h>
@@ -149,7 +148,7 @@ MODULE_DEVICE_TABLE(of, ocelot_ext_switch_of_match);
static struct platform_driver ocelot_ext_switch_driver = {
.driver = {
- .name = "ocelot-switch",
+ .name = "ocelot-ext-switch",
.of_match_table = of_match_ptr(ocelot_ext_switch_of_match),
},
.probe = ocelot_ext_probe,
diff --git a/drivers/net/dsa/ocelot/seville_vsc9953.c b/drivers/net/dsa/ocelot/seville_vsc9953.c
index 287b64b788db..563ad338da25 100644
--- a/drivers/net/dsa/ocelot/seville_vsc9953.c
+++ b/drivers/net/dsa/ocelot/seville_vsc9953.c
@@ -893,8 +893,8 @@ static int vsc9953_mdio_bus_alloc(struct ocelot *ocelot)
rc = mscc_miim_setup(dev, &bus, "VSC9953 internal MDIO bus",
ocelot->targets[GCB],
- ocelot->map[GCB][GCB_MIIM_MII_STATUS & REG_MASK]);
-
+ ocelot->map[GCB][GCB_MIIM_MII_STATUS & REG_MASK],
+ true);
if (rc) {
dev_err(dev, "failed to setup MDIO bus\n");
return rc;
diff --git a/drivers/net/ethernet/freescale/fman/fman_memac.c b/drivers/net/ethernet/freescale/fman/fman_memac.c
index 587ad81a2dc3..625c79d5636f 100644
--- a/drivers/net/ethernet/freescale/fman/fman_memac.c
+++ b/drivers/net/ethernet/freescale/fman/fman_memac.c
@@ -1155,13 +1155,12 @@ int memac_initialization(struct mac_device *mac_dev,
else
memac->sgmii_pcs = pcs;
- memac->serdes = devm_of_phy_get(mac_dev->dev, mac_node, "serdes");
- err = PTR_ERR(memac->serdes);
- if (err == -ENODEV || err == -ENOSYS) {
+ memac->serdes = devm_of_phy_optional_get(mac_dev->dev, mac_node,
+ "serdes");
+ if (!memac->serdes) {
dev_dbg(mac_dev->dev, "could not get (optional) serdes\n");
- memac->serdes = NULL;
} else if (IS_ERR(memac->serdes)) {
- dev_err_probe(mac_dev->dev, err, "could not get serdes\n");
+ err = PTR_ERR(memac->serdes);
goto _return_fm_mac_free;
}
diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c
index 146ca1d8031b..c63d3ec9d328 100644
--- a/drivers/net/ethernet/ibm/ibmvnic.c
+++ b/drivers/net/ethernet/ibm/ibmvnic.c
@@ -296,10 +296,10 @@ static void ibmvnic_set_affinity(struct ibmvnic_adapter *adapter)
rc = __netif_set_xps_queue(adapter->netdev,
cpumask_bits(queue->affinity_mask),
- i, XPS_CPUS);
+ i_txqs - 1, XPS_CPUS);
if (rc)
netdev_warn(adapter->netdev, "%s: Set XPS on queue %d failed, rc = %d.\n",
- __func__, i, rc);
+ __func__, i_txqs - 1, rc);
}
out:
diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig
index a3c84bf05e44..c18c3b373846 100644
--- a/drivers/net/ethernet/intel/Kconfig
+++ b/drivers/net/ethernet/intel/Kconfig
@@ -296,6 +296,7 @@ config ICE
default n
depends on PCI_MSI
depends on PTP_1588_CLOCK_OPTIONAL
+ depends on GNSS || GNSS = n
select AUXILIARY_BUS
select DIMLIB
select NET_DEVLINK
@@ -337,9 +338,6 @@ config ICE_HWTS
the PTP clock driver precise cross-timestamp ioctl
(PTP_SYS_OFFSET_PRECISE).
-config ICE_GNSS
- def_bool GNSS = y || GNSS = ICE
-
config FM10K
tristate "Intel(R) FM10000 Ethernet Switch Host Interface Support"
default n
diff --git a/drivers/net/ethernet/intel/ice/Makefile b/drivers/net/ethernet/intel/ice/Makefile
index f269952d207d..5d89392f969b 100644
--- a/drivers/net/ethernet/intel/ice/Makefile
+++ b/drivers/net/ethernet/intel/ice/Makefile
@@ -47,4 +47,4 @@ ice-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
ice-$(CONFIG_RFS_ACCEL) += ice_arfs.o
ice-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
ice-$(CONFIG_ICE_SWITCHDEV) += ice_eswitch.o
-ice-$(CONFIG_ICE_GNSS) += ice_gnss.o
+ice-$(CONFIG_GNSS) += ice_gnss.o
diff --git a/drivers/net/ethernet/intel/ice/ice_gnss.h b/drivers/net/ethernet/intel/ice/ice_gnss.h
index 31db0701d13f..4d49e5b0b4b8 100644
--- a/drivers/net/ethernet/intel/ice/ice_gnss.h
+++ b/drivers/net/ethernet/intel/ice/ice_gnss.h
@@ -45,7 +45,7 @@ struct gnss_serial {
struct list_head queue;
};
-#if IS_ENABLED(CONFIG_ICE_GNSS)
+#if IS_ENABLED(CONFIG_GNSS)
void ice_gnss_init(struct ice_pf *pf);
void ice_gnss_exit(struct ice_pf *pf);
bool ice_gnss_is_gps_present(struct ice_hw *hw);
@@ -56,5 +56,5 @@ static inline bool ice_gnss_is_gps_present(struct ice_hw *hw)
{
return false;
}
-#endif /* IS_ENABLED(CONFIG_ICE_GNSS) */
+#endif /* IS_ENABLED(CONFIG_GNSS) */
#endif /* _ICE_GNSS_H_ */
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
index 684cb8ec9f21..10e11262d48a 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
@@ -793,7 +793,7 @@ static int otx2_prepare_ipv6_flow(struct ethtool_rx_flow_spec *fsp,
/* NPC profile doesn't extract AH/ESP header fields */
if ((ah_esp_mask->spi & ah_esp_hdr->spi) ||
- (ah_esp_mask->tclass & ah_esp_mask->tclass))
+ (ah_esp_mask->tclass & ah_esp_hdr->tclass))
return -EOPNOTSUPP;
if (flow_type == AH_V6_FLOW)
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c
index ef10aef3cda0..7045fedfd73a 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c
@@ -10,6 +10,7 @@
#include <net/tso.h>
#include <linux/bpf.h>
#include <linux/bpf_trace.h>
+#include <net/ip6_checksum.h>
#include "otx2_reg.h"
#include "otx2_common.h"
@@ -699,7 +700,7 @@ static void otx2_sqe_add_ext(struct otx2_nic *pfvf, struct otx2_snd_queue *sq,
static void otx2_sqe_add_mem(struct otx2_snd_queue *sq, int *offset,
int alg, u64 iova, int ptp_offset,
- u64 base_ns, int udp_csum)
+ u64 base_ns, bool udp_csum_crt)
{
struct nix_sqe_mem_s *mem;
@@ -711,7 +712,7 @@ static void otx2_sqe_add_mem(struct otx2_snd_queue *sq, int *offset,
if (ptp_offset) {
mem->start_offset = ptp_offset;
- mem->udp_csum_crt = udp_csum;
+ mem->udp_csum_crt = !!udp_csum_crt;
mem->base_ns = base_ns;
mem->step_type = 1;
}
@@ -986,10 +987,11 @@ static bool otx2_validate_network_transport(struct sk_buff *skb)
return false;
}
-static bool otx2_ptp_is_sync(struct sk_buff *skb, int *offset, int *udp_csum)
+static bool otx2_ptp_is_sync(struct sk_buff *skb, int *offset, bool *udp_csum_crt)
{
struct ethhdr *eth = (struct ethhdr *)(skb->data);
u16 nix_offload_hlen = 0, inner_vhlen = 0;
+ bool udp_hdr_present = false, is_sync;
u8 *data = skb->data, *msgtype;
__be16 proto = eth->h_proto;
int network_depth = 0;
@@ -1029,45 +1031,81 @@ static bool otx2_ptp_is_sync(struct sk_buff *skb, int *offset, int *udp_csum)
if (!otx2_validate_network_transport(skb))
return false;
- *udp_csum = 1;
*offset = nix_offload_hlen + skb_transport_offset(skb) +
sizeof(struct udphdr);
+ udp_hdr_present = true;
+
}
msgtype = data + *offset;
-
/* Check PTP messageId is SYNC or not */
- return (*msgtype & 0xf) == 0;
+ is_sync = !(*msgtype & 0xf);
+ if (is_sync)
+ *udp_csum_crt = udp_hdr_present;
+ else
+ *offset = 0;
+
+ return is_sync;
}
static void otx2_set_txtstamp(struct otx2_nic *pfvf, struct sk_buff *skb,
struct otx2_snd_queue *sq, int *offset)
{
+ struct ethhdr *eth = (struct ethhdr *)(skb->data);
struct ptpv2_tstamp *origin_tstamp;
- int ptp_offset = 0, udp_csum = 0;
+ bool udp_csum_crt = false;
+ unsigned int udphoff;
struct timespec64 ts;
+ int ptp_offset = 0;
+ __wsum skb_csum;
u64 iova;
if (unlikely(!skb_shinfo(skb)->gso_size &&
(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP))) {
- if (unlikely(pfvf->flags & OTX2_FLAG_PTP_ONESTEP_SYNC)) {
- if (otx2_ptp_is_sync(skb, &ptp_offset, &udp_csum)) {
- origin_tstamp = (struct ptpv2_tstamp *)
- ((u8 *)skb->data + ptp_offset +
- PTP_SYNC_SEC_OFFSET);
- ts = ns_to_timespec64(pfvf->ptp->tstamp);
- origin_tstamp->seconds_msb = htons((ts.tv_sec >> 32) & 0xffff);
- origin_tstamp->seconds_lsb = htonl(ts.tv_sec & 0xffffffff);
- origin_tstamp->nanoseconds = htonl(ts.tv_nsec);
- /* Point to correction field in PTP packet */
- ptp_offset += 8;
+ if (unlikely(pfvf->flags & OTX2_FLAG_PTP_ONESTEP_SYNC &&
+ otx2_ptp_is_sync(skb, &ptp_offset, &udp_csum_crt))) {
+ origin_tstamp = (struct ptpv2_tstamp *)
+ ((u8 *)skb->data + ptp_offset +
+ PTP_SYNC_SEC_OFFSET);
+ ts = ns_to_timespec64(pfvf->ptp->tstamp);
+ origin_tstamp->seconds_msb = htons((ts.tv_sec >> 32) & 0xffff);
+ origin_tstamp->seconds_lsb = htonl(ts.tv_sec & 0xffffffff);
+ origin_tstamp->nanoseconds = htonl(ts.tv_nsec);
+ /* Point to correction field in PTP packet */
+ ptp_offset += 8;
+
+ /* When user disables hw checksum, stack calculates the csum,
+ * but it does not cover ptp timestamp which is added later.
+ * Recalculate the checksum manually considering the timestamp.
+ */
+ if (udp_csum_crt) {
+ struct udphdr *uh = udp_hdr(skb);
+
+ if (skb->ip_summed != CHECKSUM_PARTIAL && uh->check != 0) {
+ udphoff = skb_transport_offset(skb);
+ uh->check = 0;
+ skb_csum = skb_checksum(skb, udphoff, skb->len - udphoff,
+ 0);
+ if (ntohs(eth->h_proto) == ETH_P_IPV6)
+ uh->check = csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+ &ipv6_hdr(skb)->daddr,
+ skb->len - udphoff,
+ ipv6_hdr(skb)->nexthdr,
+ skb_csum);
+ else
+ uh->check = csum_tcpudp_magic(ip_hdr(skb)->saddr,
+ ip_hdr(skb)->daddr,
+ skb->len - udphoff,
+ IPPROTO_UDP,
+ skb_csum);
+ }
}
} else {
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
}
iova = sq->timestamps->iova + (sq->head * sizeof(u64));
otx2_sqe_add_mem(sq, offset, NIX_SENDMEMALG_E_SETTSTMP, iova,
- ptp_offset, pfvf->ptp->base_ns, udp_csum);
+ ptp_offset, pfvf->ptp->base_ns, udp_csum_crt);
} else {
skb_tx_timestamp(skb);
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/qp.c b/drivers/net/ethernet/mellanox/mlx4/qp.c
index 48cfaa7eaf50..913ed255990f 100644
--- a/drivers/net/ethernet/mellanox/mlx4/qp.c
+++ b/drivers/net/ethernet/mellanox/mlx4/qp.c
@@ -46,6 +46,13 @@
#define MLX4_BF_QP_SKIP_MASK 0xc0
#define MLX4_MAX_BF_QP_RANGE 0x40
+void mlx4_put_qp(struct mlx4_qp *qp)
+{
+ if (refcount_dec_and_test(&qp->refcount))
+ complete(&qp->free);
+}
+EXPORT_SYMBOL_GPL(mlx4_put_qp);
+
void mlx4_qp_event(struct mlx4_dev *dev, u32 qpn, int event_type)
{
struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table;
@@ -64,10 +71,8 @@ void mlx4_qp_event(struct mlx4_dev *dev, u32 qpn, int event_type)
return;
}
+ /* Need to call mlx4_put_qp() in event handler */
qp->event(qp, event_type);
-
- if (refcount_dec_and_test(&qp->refcount))
- complete(&qp->free);
}
/* used for INIT/CLOSE port logic */
@@ -523,8 +528,7 @@ EXPORT_SYMBOL_GPL(mlx4_qp_remove);
void mlx4_qp_free(struct mlx4_dev *dev, struct mlx4_qp *qp)
{
- if (refcount_dec_and_test(&qp->refcount))
- complete(&qp->free);
+ mlx4_put_qp(qp);
wait_for_completion(&qp->free);
mlx4_qp_free_icm(dev, qp->qpn);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ecpf.c b/drivers/net/ethernet/mellanox/mlx5/core/ecpf.c
index 9a3878f9e582..7c9c4e40c019 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/ecpf.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/ecpf.c
@@ -98,4 +98,8 @@ void mlx5_ec_cleanup(struct mlx5_core_dev *dev)
err = mlx5_wait_for_pages(dev, &dev->priv.page_counters[MLX5_HOST_PF]);
if (err)
mlx5_core_warn(dev, "Timeout reclaiming external host PF pages err(%d)\n", err);
+
+ err = mlx5_wait_for_pages(dev, &dev->priv.page_counters[MLX5_VF]);
+ if (err)
+ mlx5_core_warn(dev, "Timeout reclaiming external host VFs pages err(%d)\n", err);
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c b/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c
index 9a1bc93b7dc6..eb5aeba3addf 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c
@@ -86,7 +86,19 @@ static bool mlx5e_ptp_ts_cqe_drop(struct mlx5e_ptpsq *ptpsq, u16 skb_cc, u16 skb
return (ptpsq->ts_cqe_ctr_mask && (skb_cc != skb_id));
}
-static void mlx5e_ptp_skb_fifo_ts_cqe_resync(struct mlx5e_ptpsq *ptpsq, u16 skb_cc, u16 skb_id)
+static bool mlx5e_ptp_ts_cqe_ooo(struct mlx5e_ptpsq *ptpsq, u16 skb_id)
+{
+ u16 skb_cc = PTP_WQE_CTR2IDX(ptpsq->skb_fifo_cc);
+ u16 skb_pc = PTP_WQE_CTR2IDX(ptpsq->skb_fifo_pc);
+
+ if (PTP_WQE_CTR2IDX(skb_id - skb_cc) >= PTP_WQE_CTR2IDX(skb_pc - skb_cc))
+ return true;
+
+ return false;
+}
+
+static void mlx5e_ptp_skb_fifo_ts_cqe_resync(struct mlx5e_ptpsq *ptpsq, u16 skb_cc,
+ u16 skb_id, int budget)
{
struct skb_shared_hwtstamps hwts = {};
struct sk_buff *skb;
@@ -98,6 +110,7 @@ static void mlx5e_ptp_skb_fifo_ts_cqe_resync(struct mlx5e_ptpsq *ptpsq, u16 skb_
hwts.hwtstamp = mlx5e_skb_cb_get_hwts(skb)->cqe_hwtstamp;
skb_tstamp_tx(skb, &hwts);
ptpsq->cq_stats->resync_cqe++;
+ napi_consume_skb(skb, budget);
skb_cc = PTP_WQE_CTR2IDX(ptpsq->skb_fifo_cc);
}
}
@@ -118,8 +131,14 @@ static void mlx5e_ptp_handle_ts_cqe(struct mlx5e_ptpsq *ptpsq,
goto out;
}
- if (mlx5e_ptp_ts_cqe_drop(ptpsq, skb_cc, skb_id))
- mlx5e_ptp_skb_fifo_ts_cqe_resync(ptpsq, skb_cc, skb_id);
+ if (mlx5e_ptp_ts_cqe_drop(ptpsq, skb_cc, skb_id)) {
+ if (mlx5e_ptp_ts_cqe_ooo(ptpsq, skb_id)) {
+ /* already handled by a previous resync */
+ ptpsq->cq_stats->ooo_cqe_drop++;
+ return;
+ }
+ mlx5e_ptp_skb_fifo_ts_cqe_resync(ptpsq, skb_cc, skb_id, budget);
+ }
skb = mlx5e_skb_fifo_pop(&ptpsq->skb_fifo);
hwtstamp = mlx5e_cqe_ts_to_ns(sq->ptp_cyc2time, sq->clock, get_cqe_ts(cqe));
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
index e24b46953542..8f7452dc00ee 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
@@ -710,8 +710,7 @@ forward:
else
napi_gro_receive(rq->cq.napi, skb);
- if (tc_priv.fwd_dev)
- dev_put(tc_priv.fwd_dev);
+ dev_put(tc_priv.fwd_dev);
return;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act_stats.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act_stats.c
index f71766dca660..626cb7470fa5 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act_stats.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act_stats.c
@@ -37,7 +37,7 @@ mlx5e_tc_act_stats_create(void)
int err;
handle = kvzalloc(sizeof(*handle), GFP_KERNEL);
- if (IS_ERR(handle))
+ if (!handle)
return ERR_PTR(-ENOMEM);
err = rhashtable_init(&handle->ht, &act_counters_ht_params);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h b/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h
index c067d2efab51..b9c2f67d3794 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h
@@ -86,7 +86,7 @@ void mlx5e_free_txqsq_descs(struct mlx5e_txqsq *sq);
static inline bool
mlx5e_skb_fifo_has_room(struct mlx5e_skb_fifo *fifo)
{
- return (*fifo->pc - *fifo->cc) < fifo->mask;
+ return (u16)(*fifo->pc - *fifo->cc) < fifo->mask;
}
static inline bool
@@ -302,6 +302,8 @@ void mlx5e_skb_fifo_push(struct mlx5e_skb_fifo *fifo, struct sk_buff *skb)
static inline
struct sk_buff *mlx5e_skb_fifo_pop(struct mlx5e_skb_fifo *fifo)
{
+ WARN_ON_ONCE(*fifo->pc == *fifo->cc);
+
return *mlx5e_skb_fifo_get(fifo, (*fifo->cc)++);
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index 53feb0529943..76a9c5194a70 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -668,6 +668,26 @@ static void mlx5e_rq_free_shampo(struct mlx5e_rq *rq)
mlx5e_rq_shampo_hd_free(rq);
}
+static __be32 mlx5e_get_terminate_scatter_list_mkey(struct mlx5_core_dev *dev)
+{
+ u32 out[MLX5_ST_SZ_DW(query_special_contexts_out)] = {};
+ u32 in[MLX5_ST_SZ_DW(query_special_contexts_in)] = {};
+ int res;
+
+ if (!MLX5_CAP_GEN(dev, terminate_scatter_list_mkey))
+ return MLX5_TERMINATE_SCATTER_LIST_LKEY;
+
+ MLX5_SET(query_special_contexts_in, in, opcode,
+ MLX5_CMD_OP_QUERY_SPECIAL_CONTEXTS);
+ res = mlx5_cmd_exec_inout(dev, query_special_contexts, in, out);
+ if (res)
+ return MLX5_TERMINATE_SCATTER_LIST_LKEY;
+
+ res = MLX5_GET(query_special_contexts_out, out,
+ terminate_scatter_list_mkey);
+ return cpu_to_be32(res);
+}
+
static int mlx5e_alloc_rq(struct mlx5e_params *params,
struct mlx5e_xsk_param *xsk,
struct mlx5e_rq_param *rqp,
@@ -832,7 +852,7 @@ static int mlx5e_alloc_rq(struct mlx5e_params *params,
/* check if num_frags is not a pow of two */
if (rq->wqe.info.num_frags < (1 << rq->wqe.info.log_num_frags)) {
wqe->data[f].byte_count = 0;
- wqe->data[f].lkey = cpu_to_be32(MLX5_INVALID_LKEY);
+ wqe->data[f].lkey = mlx5e_get_terminate_scatter_list_mkey(mdev);
wqe->data[f].addr = 0;
}
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
index 6687b8136e44..4478223c1720 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
@@ -2138,6 +2138,7 @@ static const struct counter_desc ptp_cq_stats_desc[] = {
{ MLX5E_DECLARE_PTP_CQ_STAT(struct mlx5e_ptp_cq_stats, abort_abs_diff_ns) },
{ MLX5E_DECLARE_PTP_CQ_STAT(struct mlx5e_ptp_cq_stats, resync_cqe) },
{ MLX5E_DECLARE_PTP_CQ_STAT(struct mlx5e_ptp_cq_stats, resync_event) },
+ { MLX5E_DECLARE_PTP_CQ_STAT(struct mlx5e_ptp_cq_stats, ooo_cqe_drop) },
};
static const struct counter_desc ptp_rq_stats_desc[] = {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h
index 375752d6546d..b77100b60b50 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h
@@ -461,6 +461,7 @@ struct mlx5e_ptp_cq_stats {
u64 abort_abs_diff_ns;
u64 resync_cqe;
u64 resync_event;
+ u64 ooo_cqe_drop;
};
struct mlx5e_rep_stats {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
index e34d9b5fb504..70b8d2dfa751 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
@@ -1048,61 +1048,6 @@ static int mlx5e_hairpin_get_prio(struct mlx5e_priv *priv,
return 0;
}
-static int debugfs_hairpin_queues_set(void *data, u64 val)
-{
- struct mlx5e_hairpin_params *hp = data;
-
- if (!val) {
- mlx5_core_err(hp->mdev,
- "Number of hairpin queues must be > 0\n");
- return -EINVAL;
- }
-
- hp->num_queues = val;
-
- return 0;
-}
-
-static int debugfs_hairpin_queues_get(void *data, u64 *val)
-{
- struct mlx5e_hairpin_params *hp = data;
-
- *val = hp->num_queues;
-
- return 0;
-}
-DEFINE_DEBUGFS_ATTRIBUTE(fops_hairpin_queues, debugfs_hairpin_queues_get,
- debugfs_hairpin_queues_set, "%llu\n");
-
-static int debugfs_hairpin_queue_size_set(void *data, u64 val)
-{
- struct mlx5e_hairpin_params *hp = data;
-
- if (val > BIT(MLX5_CAP_GEN(hp->mdev, log_max_hairpin_num_packets))) {
- mlx5_core_err(hp->mdev,
- "Invalid hairpin queue size, must be <= %lu\n",
- BIT(MLX5_CAP_GEN(hp->mdev,
- log_max_hairpin_num_packets)));
- return -EINVAL;
- }
-
- hp->queue_size = roundup_pow_of_two(val);
-
- return 0;
-}
-
-static int debugfs_hairpin_queue_size_get(void *data, u64 *val)
-{
- struct mlx5e_hairpin_params *hp = data;
-
- *val = hp->queue_size;
-
- return 0;
-}
-DEFINE_DEBUGFS_ATTRIBUTE(fops_hairpin_queue_size,
- debugfs_hairpin_queue_size_get,
- debugfs_hairpin_queue_size_set, "%llu\n");
-
static int debugfs_hairpin_num_active_get(void *data, u64 *val)
{
struct mlx5e_tc_table *tc = data;
@@ -1148,10 +1093,6 @@ static void mlx5e_tc_debugfs_init(struct mlx5e_tc_table *tc,
tc->dfs_root = debugfs_create_dir("tc", dfs_root);
- debugfs_create_file("hairpin_num_queues", 0644, tc->dfs_root,
- &tc->hairpin_params, &fops_hairpin_queues);
- debugfs_create_file("hairpin_queue_size", 0644, tc->dfs_root,
- &tc->hairpin_params, &fops_hairpin_queue_size);
debugfs_create_file("hairpin_num_active", 0444, tc->dfs_root, tc,
&fops_hairpin_num_active);
debugfs_create_file("hairpin_table_dump", 0444, tc->dfs_root, tc,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
index 2a98375a0abf..d766a64b1823 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
@@ -869,7 +869,8 @@ mlx5_eswitch_add_send_to_vport_rule(struct mlx5_eswitch *on_esw,
dest.vport.flags |= MLX5_FLOW_DEST_VPORT_VHCA_ID;
flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
- if (rep->vport == MLX5_VPORT_UPLINK)
+ if (MLX5_CAP_ESW_FLOWTABLE(on_esw->dev, flow_source) &&
+ rep->vport == MLX5_VPORT_UPLINK)
spec->flow_context.flow_source = MLX5_FLOW_CONTEXT_FLOW_SOURCE_LOCAL_VPORT;
flow_rule = mlx5_add_flow_rules(mlx5_eswitch_get_slow_fdb(on_esw),
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/geneve.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/geneve.c
index 23361a9ae4fa..6dc83e871cd7 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/geneve.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/geneve.c
@@ -105,6 +105,7 @@ int mlx5_geneve_tlv_option_add(struct mlx5_geneve *geneve, struct geneve_opt *op
geneve->opt_type = opt->type;
geneve->obj_id = res;
geneve->refcount++;
+ res = 0;
}
unlock:
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/ipsec_fs_roce.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/ipsec_fs_roce.c
index 2c53589b765d..6e3f178d6f84 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/ipsec_fs_roce.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/ipsec_fs_roce.c
@@ -162,7 +162,7 @@ int mlx5_ipsec_fs_roce_tx_create(struct mlx5_core_dev *mdev,
if (IS_ERR(ft)) {
err = PTR_ERR(ft);
mlx5_core_err(mdev, "Fail to create RoCE IPsec tx ft err=%d\n", err);
- return err;
+ goto free_in;
}
roce->ft = ft;
@@ -174,22 +174,25 @@ int mlx5_ipsec_fs_roce_tx_create(struct mlx5_core_dev *mdev,
if (IS_ERR(g)) {
err = PTR_ERR(g);
mlx5_core_err(mdev, "Fail to create RoCE IPsec tx group err=%d\n", err);
- goto fail;
+ goto destroy_table;
}
roce->g = g;
err = ipsec_fs_roce_tx_rule_setup(mdev, roce, pol_ft);
if (err) {
mlx5_core_err(mdev, "Fail to create RoCE IPsec tx rules err=%d\n", err);
- goto rule_fail;
+ goto destroy_group;
}
+ kvfree(in);
return 0;
-rule_fail:
+destroy_group:
mlx5_destroy_flow_group(roce->g);
-fail:
+destroy_table:
mlx5_destroy_flow_table(ft);
+free_in:
+ kvfree(in);
return err;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c
index 3008e9ce2bbf..20d7662c10fb 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c
@@ -147,6 +147,10 @@ mlx5_device_disable_sriov(struct mlx5_core_dev *dev, int num_vfs, bool clear_vf)
mlx5_eswitch_disable_sriov(dev->priv.eswitch, clear_vf);
+ /* For ECPFs, skip waiting for host VF pages until ECPF is destroyed */
+ if (mlx5_core_is_ecpf(dev))
+ return;
+
if (mlx5_wait_for_pages(dev, &dev->priv.page_counters[MLX5_VF]))
mlx5_core_warn(dev, "timeout reclaiming VFs pages\n");
}
diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c
index 8b89de0541ff..685e8cd7658c 100644
--- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c
@@ -1154,9 +1154,8 @@ static int lan966x_probe(struct platform_device *pdev)
lan966x->ports[p]->config.portmode = phy_mode;
lan966x->ports[p]->fwnode = fwnode_handle_get(portnp);
- serdes = devm_of_phy_get(lan966x->dev, to_of_node(portnp), NULL);
- if (PTR_ERR(serdes) == -ENODEV)
- serdes = NULL;
+ serdes = devm_of_phy_optional_get(lan966x->dev,
+ to_of_node(portnp), NULL);
if (IS_ERR(serdes)) {
err = PTR_ERR(serdes);
goto cleanup_ports;
diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c
index 4a3c3b5fb4a1..261f982ca40d 100644
--- a/drivers/net/ethernet/qlogic/qede/qede_main.c
+++ b/drivers/net/ethernet/qlogic/qede/qede_main.c
@@ -963,7 +963,6 @@ static int qede_alloc_fp_array(struct qede_dev *edev)
{
u8 fp_combined, fp_rx = edev->fp_num_rx;
struct qede_fastpath *fp;
- void *mem;
int i;
edev->fp_array = kcalloc(QEDE_QUEUE_CNT(edev),
@@ -974,20 +973,14 @@ static int qede_alloc_fp_array(struct qede_dev *edev)
}
if (!edev->coal_entry) {
- mem = kcalloc(QEDE_MAX_RSS_CNT(edev),
- sizeof(*edev->coal_entry), GFP_KERNEL);
- } else {
- mem = krealloc(edev->coal_entry,
- QEDE_QUEUE_CNT(edev) * sizeof(*edev->coal_entry),
- GFP_KERNEL);
- }
-
- if (!mem) {
- DP_ERR(edev, "coalesce entry allocation failed\n");
- kfree(edev->coal_entry);
- goto err;
+ edev->coal_entry = kcalloc(QEDE_MAX_RSS_CNT(edev),
+ sizeof(*edev->coal_entry),
+ GFP_KERNEL);
+ if (!edev->coal_entry) {
+ DP_ERR(edev, "coalesce entry allocation failed\n");
+ goto err;
+ }
}
- edev->coal_entry = mem;
fp_combined = QEDE_QUEUE_CNT(edev) - fp_rx - edev->fp_num_tx;
diff --git a/drivers/net/ethernet/sun/sunhme.c b/drivers/net/ethernet/sun/sunhme.c
index 1c16548415cd..b0c7ab74a82e 100644
--- a/drivers/net/ethernet/sun/sunhme.c
+++ b/drivers/net/ethernet/sun/sunhme.c
@@ -2894,8 +2894,10 @@ static int happy_meal_pci_probe(struct pci_dev *pdev,
goto err_out_clear_quattro;
}
- hpreg_res = devm_request_region(&pdev->dev, pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0), DRV_NAME);
+ hpreg_res = devm_request_mem_region(&pdev->dev,
+ pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0),
+ DRV_NAME);
if (!hpreg_res) {
err = -EBUSY;
dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting.\n");
diff --git a/drivers/net/ipa/ipa_main.c b/drivers/net/ipa/ipa_main.c
index 6cb7bf96a626..4cc8d8d6bc9b 100644
--- a/drivers/net/ipa/ipa_main.c
+++ b/drivers/net/ipa/ipa_main.c
@@ -16,7 +16,7 @@
#include <linux/of_device.h>
#include <linux/of_address.h>
#include <linux/pm_runtime.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/soc/qcom/mdt_loader.h>
#include "ipa.h"
diff --git a/drivers/net/ipa/ipa_mem.c b/drivers/net/ipa/ipa_mem.c
index 85096d1efe5b..db6ada2343af 100644
--- a/drivers/net/ipa/ipa_mem.c
+++ b/drivers/net/ipa/ipa_mem.c
@@ -472,7 +472,8 @@ static int ipa_imem_init(struct ipa *ipa, unsigned long addr, size_t size)
size = PAGE_ALIGN(size + addr - phys);
iova = phys; /* We just want a direct mapping */
- ret = iommu_map(domain, iova, phys, size, IOMMU_READ | IOMMU_WRITE);
+ ret = iommu_map(domain, iova, phys, size, IOMMU_READ | IOMMU_WRITE,
+ GFP_KERNEL);
if (ret)
return ret;
@@ -580,7 +581,8 @@ static int ipa_smem_init(struct ipa *ipa, u32 item, size_t size)
size = PAGE_ALIGN(size + addr - phys);
iova = phys; /* We just want a direct mapping */
- ret = iommu_map(domain, iova, phys, size, IOMMU_READ | IOMMU_WRITE);
+ ret = iommu_map(domain, iova, phys, size, IOMMU_READ | IOMMU_WRITE,
+ GFP_KERNEL);
if (ret)
return ret;
diff --git a/drivers/net/mdio/mdio-mscc-miim.c b/drivers/net/mdio/mdio-mscc-miim.c
index c87e991d1a17..1a1b95ae95fa 100644
--- a/drivers/net/mdio/mdio-mscc-miim.c
+++ b/drivers/net/mdio/mdio-mscc-miim.c
@@ -52,6 +52,7 @@ struct mscc_miim_info {
struct mscc_miim_dev {
struct regmap *regs;
int mii_status_offset;
+ bool ignore_read_errors;
struct regmap *phy_regs;
const struct mscc_miim_info *info;
struct clk *clk;
@@ -135,7 +136,7 @@ static int mscc_miim_read(struct mii_bus *bus, int mii_id, int regnum)
goto out;
}
- if (val & MSCC_MIIM_DATA_ERROR) {
+ if (!miim->ignore_read_errors && !!(val & MSCC_MIIM_DATA_ERROR)) {
ret = -EIO;
goto out;
}
@@ -212,7 +213,8 @@ static const struct regmap_config mscc_miim_phy_regmap_config = {
};
int mscc_miim_setup(struct device *dev, struct mii_bus **pbus, const char *name,
- struct regmap *mii_regmap, int status_offset)
+ struct regmap *mii_regmap, int status_offset,
+ bool ignore_read_errors)
{
struct mscc_miim_dev *miim;
struct mii_bus *bus;
@@ -234,6 +236,7 @@ int mscc_miim_setup(struct device *dev, struct mii_bus **pbus, const char *name,
miim->regs = mii_regmap;
miim->mii_status_offset = status_offset;
+ miim->ignore_read_errors = ignore_read_errors;
*pbus = bus;
@@ -285,7 +288,7 @@ static int mscc_miim_probe(struct platform_device *pdev)
return dev_err_probe(dev, PTR_ERR(phy_regmap),
"Unable to create phy register regmap\n");
- ret = mscc_miim_setup(dev, &bus, "mscc_miim", mii_regmap, 0);
+ ret = mscc_miim_setup(dev, &bus, "mscc_miim", mii_regmap, 0, false);
if (ret < 0) {
dev_err(dev, "Unable to setup the MDIO bus\n");
return ret;
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 00d5bcdf0e6f..389f33a12534 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -1330,7 +1330,7 @@ static int mdio_bus_match(struct device *dev, struct device_driver *drv)
return 0;
}
-static int mdio_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int mdio_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
int rc;
diff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c
index f9b128cecc3f..fee514b96ab1 100644
--- a/drivers/net/phy/phy-c45.c
+++ b/drivers/net/phy/phy-c45.c
@@ -262,7 +262,7 @@ int genphy_c45_an_config_aneg(struct phy_device *phydev)
linkmode_and(phydev->advertising, phydev->advertising,
phydev->supported);
- ret = genphy_c45_write_eee_adv(phydev, phydev->supported_eee);
+ ret = genphy_c45_an_config_eee_aneg(phydev);
if (ret < 0)
return ret;
else if (ret)
@@ -672,9 +672,9 @@ EXPORT_SYMBOL_GPL(genphy_c45_read_mdix);
*/
int genphy_c45_write_eee_adv(struct phy_device *phydev, unsigned long *adv)
{
- int val, changed;
+ int val, changed = 0;
- if (linkmode_intersects(phydev->supported, PHY_EEE_CAP1_FEATURES)) {
+ if (linkmode_intersects(phydev->supported_eee, PHY_EEE_CAP1_FEATURES)) {
val = linkmode_to_mii_eee_cap1_t(adv);
/* In eee_broken_modes are stored MDIO_AN_EEE_ADV specific raw
@@ -721,12 +721,11 @@ int genphy_c45_write_eee_adv(struct phy_device *phydev, unsigned long *adv)
* @phydev: target phy_device struct
* @adv: the linkmode advertisement status
*/
-static int genphy_c45_read_eee_adv(struct phy_device *phydev,
- unsigned long *adv)
+int genphy_c45_read_eee_adv(struct phy_device *phydev, unsigned long *adv)
{
int val;
- if (linkmode_intersects(phydev->supported, PHY_EEE_CAP1_FEATURES)) {
+ if (linkmode_intersects(phydev->supported_eee, PHY_EEE_CAP1_FEATURES)) {
/* IEEE 802.3-2018 45.2.7.13 EEE advertisement 1
* (Register 7.60)
*/
@@ -762,7 +761,7 @@ static int genphy_c45_read_eee_lpa(struct phy_device *phydev,
{
int val;
- if (linkmode_intersects(phydev->supported, PHY_EEE_CAP1_FEATURES)) {
+ if (linkmode_intersects(phydev->supported_eee, PHY_EEE_CAP1_FEATURES)) {
/* IEEE 802.3-2018 45.2.7.14 EEE link partner ability 1
* (Register 7.61)
*/
@@ -859,6 +858,21 @@ int genphy_c45_read_eee_abilities(struct phy_device *phydev)
EXPORT_SYMBOL_GPL(genphy_c45_read_eee_abilities);
/**
+ * genphy_c45_an_config_eee_aneg - configure EEE advertisement
+ * @phydev: target phy_device struct
+ */
+int genphy_c45_an_config_eee_aneg(struct phy_device *phydev)
+{
+ if (!phydev->eee_enabled) {
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(adv) = {};
+
+ return genphy_c45_write_eee_adv(phydev, adv);
+ }
+
+ return genphy_c45_write_eee_adv(phydev, phydev->advertising_eee);
+}
+
+/**
* genphy_c45_pma_read_abilities - read supported link modes from PMA
* @phydev: target phy_device struct
*
@@ -1421,17 +1435,33 @@ EXPORT_SYMBOL(genphy_c45_ethtool_get_eee);
int genphy_c45_ethtool_set_eee(struct phy_device *phydev,
struct ethtool_eee *data)
{
- __ETHTOOL_DECLARE_LINK_MODE_MASK(adv) = {};
int ret;
if (data->eee_enabled) {
- if (data->advertised)
- adv[0] = data->advertised;
- else
- linkmode_copy(adv, phydev->supported_eee);
+ if (data->advertised) {
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(adv);
+
+ ethtool_convert_legacy_u32_to_link_mode(adv,
+ data->advertised);
+ linkmode_andnot(adv, adv, phydev->supported_eee);
+ if (!linkmode_empty(adv)) {
+ phydev_warn(phydev, "At least some EEE link modes are not supported.\n");
+ return -EINVAL;
+ }
+
+ ethtool_convert_legacy_u32_to_link_mode(phydev->advertising_eee,
+ data->advertised);
+ } else {
+ linkmode_copy(phydev->advertising_eee,
+ phydev->supported_eee);
+ }
+
+ phydev->eee_enabled = true;
+ } else {
+ phydev->eee_enabled = false;
}
- ret = genphy_c45_write_eee_adv(phydev, adv);
+ ret = genphy_c45_an_config_eee_aneg(phydev);
if (ret < 0)
return ret;
if (ret > 0)
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 71becceb8764..3f8a64fb9d71 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -2231,7 +2231,7 @@ int __genphy_config_aneg(struct phy_device *phydev, bool changed)
{
int err;
- err = genphy_c45_write_eee_adv(phydev, phydev->supported_eee);
+ err = genphy_c45_an_config_eee_aneg(phydev);
if (err < 0)
return err;
else if (err)
@@ -3141,6 +3141,25 @@ static int phy_probe(struct device *dev)
of_set_phy_supported(phydev);
phy_advertise_supported(phydev);
+ /* Get PHY default EEE advertising modes and handle them as potentially
+ * safe initial configuration.
+ */
+ err = genphy_c45_read_eee_adv(phydev, phydev->advertising_eee);
+ if (err)
+ return err;
+
+ /* There is no "enabled" flag. If PHY is advertising, assume it is
+ * kind of enabled.
+ */
+ phydev->eee_enabled = !linkmode_empty(phydev->advertising_eee);
+
+ /* Some PHYs may advertise, by default, not support EEE modes. So,
+ * we need to clean them.
+ */
+ if (phydev->eee_enabled)
+ linkmode_and(phydev->advertising_eee, phydev->supported_eee,
+ phydev->advertising_eee);
+
/* Get the EEE modes we want to prohibit. We will ask
* the PHY stop advertising these mode later on
*/
diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c
index 3f94fbf83702..90f457b8e1fe 100644
--- a/drivers/net/wireless/ath/ath10k/qmi.c
+++ b/drivers/net/wireless/ath/ath10k/qmi.c
@@ -13,7 +13,7 @@
#include <linux/module.h>
#include <linux/net.h>
#include <linux/platform_device.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/soc/qcom/smem.h>
#include <linux/string.h>
#include <net/sock.h>
diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c
index cfcb759a87de..9a82f0336d95 100644
--- a/drivers/net/wireless/ath/ath10k/snoc.c
+++ b/drivers/net/wireless/ath/ath10k/snoc.c
@@ -1639,7 +1639,7 @@ static int ath10k_fw_init(struct ath10k *ar)
ret = iommu_map(iommu_dom, ar_snoc->fw.fw_start_addr,
ar->msa.paddr, ar->msa.mem_size,
- IOMMU_READ | IOMMU_WRITE);
+ IOMMU_READ | IOMMU_WRITE, GFP_KERNEL);
if (ret) {
ath10k_err(ar, "failed to map firmware region: %d\n", ret);
goto err_iommu_detach;
diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c
index cd48eca494ed..920abce9053a 100644
--- a/drivers/net/wireless/ath/ath11k/ahb.c
+++ b/drivers/net/wireless/ath/ath11k/ahb.c
@@ -1036,7 +1036,7 @@ static int ath11k_ahb_fw_resources_init(struct ath11k_base *ab)
ret = iommu_map(iommu_dom, ab_ahb->fw.msa_paddr,
ab_ahb->fw.msa_paddr, ab_ahb->fw.msa_size,
- IOMMU_READ | IOMMU_WRITE);
+ IOMMU_READ | IOMMU_WRITE, GFP_KERNEL);
if (ret) {
ath11k_err(ab, "failed to map firmware region: %d\n", ret);
goto err_iommu_detach;
@@ -1044,7 +1044,7 @@ static int ath11k_ahb_fw_resources_init(struct ath11k_base *ab)
ret = iommu_map(iommu_dom, ab_ahb->fw.ce_paddr,
ab_ahb->fw.ce_paddr, ab_ahb->fw.ce_size,
- IOMMU_READ | IOMMU_WRITE);
+ IOMMU_READ | IOMMU_WRITE, GFP_KERNEL);
if (ret) {
ath11k_err(ab, "failed to map firmware CE region: %d\n", ret);
goto err_iommu_unmap;
diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c
index 776362d151cb..0aeef2948ff5 100644
--- a/drivers/net/wireless/ath/ath11k/pci.c
+++ b/drivers/net/wireless/ath/ath11k/pci.c
@@ -981,7 +981,7 @@ static __maybe_unused int ath11k_pci_pm_suspend(struct device *dev)
if (ret)
ath11k_warn(ab, "failed to suspend core: %d\n", ret);
- return ret;
+ return 0;
}
static __maybe_unused int ath11k_pci_pm_resume(struct device *dev)
diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c
index b88959ef38aa..5e5c7bf51174 100644
--- a/drivers/net/wireless/mediatek/mt76/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/usb.c
@@ -706,6 +706,7 @@ mt76u_free_rx_queue(struct mt76_dev *dev, struct mt76_queue *q)
q->entry[i].urb = NULL;
}
page_pool_destroy(q->page_pool);
+ q->page_pool = NULL;
}
static void mt76u_free_rx(struct mt76_dev *dev)
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
index bf627af723bf..1b42676ca141 100644
--- a/drivers/net/xen-netback/netback.c
+++ b/drivers/net/xen-netback/netback.c
@@ -883,11 +883,9 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
struct xen_netif_tx_request txfrags[XEN_NETBK_LEGACY_SLOTS_MAX];
struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX-1];
unsigned int extra_count;
- u16 pending_idx;
RING_IDX idx;
int work_to_do;
unsigned int data_len;
- pending_ring_idx_t index;
if (queue->tx.sring->req_prod - queue->tx.req_cons >
XEN_NETIF_TX_RING_SIZE) {
@@ -983,9 +981,6 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
break;
}
- index = pending_index(queue->pending_cons);
- pending_idx = queue->pending_ring[index];
-
if (ret >= XEN_NETBK_LEGACY_SLOTS_MAX - 1 && data_len < txreq.size)
data_len = txreq.size;
diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c
index 001636901dda..a78a25b87240 100644
--- a/drivers/net/xen-netback/xenbus.c
+++ b/drivers/net/xen-netback/xenbus.c
@@ -200,7 +200,7 @@ static void xenvif_debugfs_delif(struct xenvif *vif)
* and vif variables to the environment, for the benefit of the vif-* hotplug
* scripts.
*/
-static int netback_uevent(struct xenbus_device *xdev,
+static int netback_uevent(const struct xenbus_device *xdev,
struct kobj_uevent_env *env)
{
struct backend_info *be = dev_get_drvdata(&xdev->dev);
diff --git a/drivers/nfc/st-nci/se.c b/drivers/nfc/st-nci/se.c
index ec87dd21e054..b2f1ced8e6dd 100644
--- a/drivers/nfc/st-nci/se.c
+++ b/drivers/nfc/st-nci/se.c
@@ -672,6 +672,12 @@ int st_nci_se_io(struct nci_dev *ndev, u32 se_idx,
ST_NCI_EVT_TRANSMIT_DATA, apdu,
apdu_length);
default:
+ /* Need to free cb_context here as at the moment we can't
+ * clearly indicate to the caller if the callback function
+ * would be called (and free it) or not. In both cases a
+ * negative value may be returned to the caller.
+ */
+ kfree(cb_context);
return -ENODEV;
}
}
diff --git a/drivers/nfc/st21nfca/se.c b/drivers/nfc/st21nfca/se.c
index df8d27cf2956..dae288bebcb5 100644
--- a/drivers/nfc/st21nfca/se.c
+++ b/drivers/nfc/st21nfca/se.c
@@ -236,6 +236,12 @@ int st21nfca_hci_se_io(struct nfc_hci_dev *hdev, u32 se_idx,
ST21NFCA_EVT_TRANSMIT_DATA,
apdu, apdu_length);
default:
+ /* Need to free cb_context here as at the moment we can't
+ * clearly indicate to the caller if the callback function
+ * would be called (and free it) or not. In both cases a
+ * negative value may be returned to the caller.
+ */
+ kfree(cb_context);
return -ENODEV;
}
}
diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c
index 0297b7882e33..d5593b0dc700 100644
--- a/drivers/nvdimm/btt.c
+++ b/drivers/nvdimm/btt.c
@@ -1482,20 +1482,6 @@ static void btt_submit_bio(struct bio *bio)
bio_endio(bio);
}
-static int btt_rw_page(struct block_device *bdev, sector_t sector,
- struct page *page, enum req_op op)
-{
- struct btt *btt = bdev->bd_disk->private_data;
- int rc;
-
- rc = btt_do_bvec(btt, NULL, page, thp_size(page), 0, op, sector);
- if (rc == 0)
- page_endio(page, op_is_write(op), 0);
-
- return rc;
-}
-
-
static int btt_getgeo(struct block_device *bd, struct hd_geometry *geo)
{
/* some standard values */
@@ -1508,7 +1494,6 @@ static int btt_getgeo(struct block_device *bd, struct hd_geometry *geo)
static const struct block_device_operations btt_fops = {
.owner = THIS_MODULE,
.submit_bio = btt_submit_bio,
- .rw_page = btt_rw_page,
.getgeo = btt_getgeo,
};
@@ -1530,6 +1515,7 @@ static int btt_blk_init(struct btt *btt)
blk_queue_logical_block_size(btt->btt_disk->queue, btt->sector_size);
blk_queue_max_hw_sectors(btt->btt_disk->queue, UINT_MAX);
blk_queue_flag_set(QUEUE_FLAG_NONROT, btt->btt_disk->queue);
+ blk_queue_flag_set(QUEUE_FLAG_SYNCHRONOUS, btt->btt_disk->queue);
if (btt_meta_size(btt)) {
rc = nd_integrity_init(btt->btt_disk, btt_meta_size(btt));
diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c
index b38d0355b0ac..4976a0069e9c 100644
--- a/drivers/nvdimm/bus.c
+++ b/drivers/nvdimm/bus.c
@@ -28,7 +28,7 @@ static int nvdimm_bus_major;
struct class *nd_class;
static DEFINE_IDA(nd_ida);
-static int to_nd_device_type(struct device *dev)
+static int to_nd_device_type(const struct device *dev)
{
if (is_nvdimm(dev))
return ND_DEVICE_DIMM;
@@ -42,7 +42,7 @@ static int to_nd_device_type(struct device *dev)
return 0;
}
-static int nvdimm_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int nvdimm_bus_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
return add_uevent_var(env, "MODALIAS=" ND_DEVICE_MODALIAS_FMT,
to_nd_device_type(dev));
@@ -508,7 +508,7 @@ static void nd_async_device_unregister(void *d, async_cookie_t cookie)
put_device(dev);
}
-void nd_device_register(struct device *dev)
+static void __nd_device_register(struct device *dev, bool sync)
{
if (!dev)
return;
@@ -531,11 +531,24 @@ void nd_device_register(struct device *dev)
}
get_device(dev);
- async_schedule_dev_domain(nd_async_device_register, dev,
- &nd_async_domain);
+ if (sync)
+ nd_async_device_register(dev, 0);
+ else
+ async_schedule_dev_domain(nd_async_device_register, dev,
+ &nd_async_domain);
+}
+
+void nd_device_register(struct device *dev)
+{
+ __nd_device_register(dev, false);
}
EXPORT_SYMBOL(nd_device_register);
+void nd_device_register_sync(struct device *dev)
+{
+ __nd_device_register(dev, true);
+}
+
void nd_device_unregister(struct device *dev, enum nd_async_mode mode)
{
bool killed;
diff --git a/drivers/nvdimm/dax_devs.c b/drivers/nvdimm/dax_devs.c
index 7f4a9d28b670..3bd61f245788 100644
--- a/drivers/nvdimm/dax_devs.c
+++ b/drivers/nvdimm/dax_devs.c
@@ -38,7 +38,7 @@ static const struct device_type nd_dax_device_type = {
.groups = nd_pfn_attribute_groups,
};
-bool is_nd_dax(struct device *dev)
+bool is_nd_dax(const struct device *dev)
{
return dev ? dev->type == &nd_dax_device_type : false;
}
diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c
index 1fc081dcf631..957f7c3d17ba 100644
--- a/drivers/nvdimm/dimm_devs.c
+++ b/drivers/nvdimm/dimm_devs.c
@@ -572,7 +572,7 @@ static const struct device_type nvdimm_device_type = {
.groups = nvdimm_attribute_groups,
};
-bool is_nvdimm(struct device *dev)
+bool is_nvdimm(const struct device *dev)
{
return dev->type == &nvdimm_device_type;
}
@@ -624,7 +624,10 @@ struct nvdimm *__nvdimm_create(struct nvdimm_bus *nvdimm_bus,
nvdimm->sec.ext_flags = nvdimm_security_flags(nvdimm, NVDIMM_MASTER);
device_initialize(dev);
lockdep_set_class(&dev->mutex, &nvdimm_key);
- nd_device_register(dev);
+ if (test_bit(NDD_REGISTER_SYNC, &flags))
+ nd_device_register_sync(dev);
+ else
+ nd_device_register(dev);
return nvdimm;
}
diff --git a/drivers/nvdimm/nd-core.h b/drivers/nvdimm/nd-core.h
index cc86ee09d7c0..86976a9e8a15 100644
--- a/drivers/nvdimm/nd-core.h
+++ b/drivers/nvdimm/nd-core.h
@@ -82,14 +82,14 @@ static inline void nvdimm_security_overwrite_query(struct work_struct *work)
}
#endif
-bool is_nvdimm(struct device *dev);
-bool is_nd_pmem(struct device *dev);
-bool is_nd_volatile(struct device *dev);
-static inline bool is_nd_region(struct device *dev)
+bool is_nvdimm(const struct device *dev);
+bool is_nd_pmem(const struct device *dev);
+bool is_nd_volatile(const struct device *dev);
+static inline bool is_nd_region(const struct device *dev)
{
return is_nd_pmem(dev) || is_nd_volatile(dev);
}
-static inline bool is_memory(struct device *dev)
+static inline bool is_memory(const struct device *dev)
{
return is_nd_pmem(dev) || is_nd_volatile(dev);
}
@@ -107,6 +107,7 @@ int nvdimm_bus_create_ndctl(struct nvdimm_bus *nvdimm_bus);
void nvdimm_bus_destroy_ndctl(struct nvdimm_bus *nvdimm_bus);
void nd_synchronize(void);
void nd_device_register(struct device *dev);
+void nd_device_register_sync(struct device *dev);
struct nd_label_id;
char *nd_label_gen_id(struct nd_label_id *label_id, const uuid_t *uuid,
u32 flags);
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
index ec5219680092..e8b9d27dbb3c 100644
--- a/drivers/nvdimm/nd.h
+++ b/drivers/nvdimm/nd.h
@@ -599,7 +599,7 @@ static inline int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig)
struct nd_dax *to_nd_dax(struct device *dev);
#if IS_ENABLED(CONFIG_NVDIMM_DAX)
int nd_dax_probe(struct device *dev, struct nd_namespace_common *ndns);
-bool is_nd_dax(struct device *dev);
+bool is_nd_dax(const struct device *dev);
struct device *nd_dax_create(struct nd_region *nd_region);
#else
static inline int nd_dax_probe(struct device *dev,
@@ -608,7 +608,7 @@ static inline int nd_dax_probe(struct device *dev,
return -ENODEV;
}
-static inline bool is_nd_dax(struct device *dev)
+static inline bool is_nd_dax(const struct device *dev)
{
return false;
}
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
index 96e6e9a5f235..ceea55f621cc 100644
--- a/drivers/nvdimm/pmem.c
+++ b/drivers/nvdimm/pmem.c
@@ -238,28 +238,6 @@ static void pmem_submit_bio(struct bio *bio)
bio_endio(bio);
}
-static int pmem_rw_page(struct block_device *bdev, sector_t sector,
- struct page *page, enum req_op op)
-{
- struct pmem_device *pmem = bdev->bd_disk->private_data;
- blk_status_t rc;
-
- if (op_is_write(op))
- rc = pmem_do_write(pmem, page, 0, sector, thp_size(page));
- else
- rc = pmem_do_read(pmem, page, 0, sector, thp_size(page));
- /*
- * The ->rw_page interface is subtle and tricky. The core
- * retries on any error, so we can only invoke page_endio() in
- * the successful completion case. Otherwise, we'll see crashes
- * caused by double completion.
- */
- if (rc == 0)
- page_endio(page, op_is_write(op), 0);
-
- return blk_status_to_errno(rc);
-}
-
/* see "strong" declaration in tools/testing/nvdimm/pmem-dax.c */
__weak long __pmem_direct_access(struct pmem_device *pmem, pgoff_t pgoff,
long nr_pages, enum dax_access_mode mode, void **kaddr,
@@ -310,7 +288,6 @@ __weak long __pmem_direct_access(struct pmem_device *pmem, pgoff_t pgoff,
static const struct block_device_operations pmem_fops = {
.owner = THIS_MODULE,
.submit_bio = pmem_submit_bio,
- .rw_page = pmem_rw_page,
};
static int pmem_dax_zero_page_range(struct dax_device *dax_dev, pgoff_t pgoff,
@@ -565,6 +542,7 @@ static int pmem_attach_disk(struct device *dev,
blk_queue_logical_block_size(q, pmem_sector_size(ndns));
blk_queue_max_hw_sectors(q, UINT_MAX);
blk_queue_flag_set(QUEUE_FLAG_NONROT, q);
+ blk_queue_flag_set(QUEUE_FLAG_SYNCHRONOUS, q);
if (pmem->pfn_flags & PFN_MAP)
blk_queue_flag_set(QUEUE_FLAG_DAX, q);
diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c
index 83dbf398ea84..8f134d63af13 100644
--- a/drivers/nvdimm/region_devs.c
+++ b/drivers/nvdimm/region_devs.c
@@ -839,12 +839,12 @@ static const struct device_type nd_volatile_device_type = {
.groups = nd_region_attribute_groups,
};
-bool is_nd_pmem(struct device *dev)
+bool is_nd_pmem(const struct device *dev)
{
return dev ? dev->type == &nd_pmem_device_type : false;
}
-bool is_nd_volatile(struct device *dev)
+bool is_nd_volatile(const struct device *dev)
{
return dev ? dev->type == &nd_volatile_device_type : false;
}
diff --git a/drivers/nvdimm/virtio_pmem.c b/drivers/nvdimm/virtio_pmem.c
index 20da455d2ef6..a92eb172f0e7 100644
--- a/drivers/nvdimm/virtio_pmem.c
+++ b/drivers/nvdimm/virtio_pmem.c
@@ -32,7 +32,6 @@ static int init_vq(struct virtio_pmem *vpmem)
static int virtio_pmem_probe(struct virtio_device *vdev)
{
struct nd_region_desc ndr_desc = {};
- int nid = dev_to_node(&vdev->dev);
struct nd_region *nd_region;
struct virtio_pmem *vpmem;
struct resource res;
@@ -79,7 +78,15 @@ static int virtio_pmem_probe(struct virtio_device *vdev)
dev_set_drvdata(&vdev->dev, vpmem->nvdimm_bus);
ndr_desc.res = &res;
- ndr_desc.numa_node = nid;
+
+ ndr_desc.numa_node = memory_add_physaddr_to_nid(res.start);
+ ndr_desc.target_node = phys_to_target_node(res.start);
+ if (ndr_desc.target_node == NUMA_NO_NODE) {
+ ndr_desc.target_node = ndr_desc.numa_node;
+ dev_dbg(&vdev->dev, "changing target node from %d to %d",
+ NUMA_NO_NODE, ndr_desc.target_node);
+ }
+
ndr_desc.flush = async_pmem_flush;
ndr_desc.provider_data = vdev;
set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags);
diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index 755f551426b5..6dec38805041 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -290,9 +290,19 @@ config NVMEM_SPRD_EFUSE
This driver can also be built as a module. If so, the module
will be called nvmem-sprd-efuse.
+config NVMEM_STM32_BSEC_OPTEE_TA
+ def_bool NVMEM_STM32_ROMEM && OPTEE
+ help
+ Say y here to enable the accesses to STM32MP SoC OTPs by the OP-TEE
+ trusted application STM32MP BSEC.
+
+ This library is a used by stm32-romem driver or included in the module
+ called nvmem-stm32-romem.
+
config NVMEM_STM32_ROMEM
tristate "STMicroelectronics STM32 factory-programmed memory support"
depends on ARCH_STM32 || COMPILE_TEST
+ depends on OPTEE || !OPTEE
help
Say y here to enable read-only access for STMicroelectronics STM32
factory-programmed memory area.
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
index fa80fe17e567..6a1efffa88f0 100644
--- a/drivers/nvmem/Makefile
+++ b/drivers/nvmem/Makefile
@@ -61,6 +61,7 @@ obj-$(CONFIG_NVMEM_SPRD_EFUSE) += nvmem_sprd_efuse.o
nvmem_sprd_efuse-y := sprd-efuse.o
obj-$(CONFIG_NVMEM_STM32_ROMEM) += nvmem_stm32_romem.o
nvmem_stm32_romem-y := stm32-romem.o
+nvmem_stm32_romem-$(CONFIG_NVMEM_STM32_BSEC_OPTEE_TA) += stm32-bsec-optee-ta.o
obj-$(CONFIG_NVMEM_SUNPLUS_OCOTP) += nvmem_sunplus_ocotp.o
nvmem_sunplus_ocotp-y := sunplus-ocotp.o
obj-$(CONFIG_NVMEM_SUNXI_SID) += nvmem_sunxi_sid.o
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index 34ee9d36ee7b..174ef3574e07 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -60,6 +60,7 @@ struct nvmem_cell_entry {
struct nvmem_cell {
struct nvmem_cell_entry *entry;
const char *id;
+ int index;
};
static DEFINE_MUTEX(nvmem_mutex);
@@ -501,6 +502,36 @@ static int nvmem_cell_info_to_nvmem_cell_entry(struct nvmem_device *nvmem,
}
/**
+ * nvmem_add_one_cell() - Add one cell information to an nvmem device
+ *
+ * @nvmem: nvmem device to add cells to.
+ * @info: nvmem cell info to add to the device
+ *
+ * Return: 0 or negative error code on failure.
+ */
+int nvmem_add_one_cell(struct nvmem_device *nvmem,
+ const struct nvmem_cell_info *info)
+{
+ struct nvmem_cell_entry *cell;
+ int rval;
+
+ cell = kzalloc(sizeof(*cell), GFP_KERNEL);
+ if (!cell)
+ return -ENOMEM;
+
+ rval = nvmem_cell_info_to_nvmem_cell_entry(nvmem, info, cell);
+ if (rval) {
+ kfree(cell);
+ return rval;
+ }
+
+ nvmem_cell_entry_add(cell);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(nvmem_add_one_cell);
+
+/**
* nvmem_add_cells() - Add cell information to an nvmem device
*
* @nvmem: nvmem device to add cells to.
@@ -513,40 +544,15 @@ static int nvmem_add_cells(struct nvmem_device *nvmem,
const struct nvmem_cell_info *info,
int ncells)
{
- struct nvmem_cell_entry **cells;
int i, rval;
- cells = kcalloc(ncells, sizeof(*cells), GFP_KERNEL);
- if (!cells)
- return -ENOMEM;
-
for (i = 0; i < ncells; i++) {
- cells[i] = kzalloc(sizeof(**cells), GFP_KERNEL);
- if (!cells[i]) {
- rval = -ENOMEM;
- goto err;
- }
-
- rval = nvmem_cell_info_to_nvmem_cell_entry(nvmem, &info[i], cells[i]);
- if (rval) {
- kfree(cells[i]);
- goto err;
- }
-
- nvmem_cell_entry_add(cells[i]);
+ rval = nvmem_add_one_cell(nvmem, &info[i]);
+ if (rval)
+ return rval;
}
- /* remove tmp array */
- kfree(cells);
-
return 0;
-err:
- while (i--)
- nvmem_cell_entry_drop(cells[i]);
-
- kfree(cells);
-
- return rval;
}
/**
@@ -682,15 +688,14 @@ static int nvmem_validate_keepouts(struct nvmem_device *nvmem)
static int nvmem_add_cells_from_of(struct nvmem_device *nvmem)
{
- struct device_node *parent, *child;
struct device *dev = &nvmem->dev;
- struct nvmem_cell_entry *cell;
+ struct device_node *child;
const __be32 *addr;
- int len;
+ int len, ret;
- parent = dev->of_node;
+ for_each_child_of_node(dev->of_node, child) {
+ struct nvmem_cell_info info = {0};
- for_each_child_of_node(parent, child) {
addr = of_get_property(child, "reg", &len);
if (!addr)
continue;
@@ -700,40 +705,24 @@ static int nvmem_add_cells_from_of(struct nvmem_device *nvmem)
return -EINVAL;
}
- cell = kzalloc(sizeof(*cell), GFP_KERNEL);
- if (!cell) {
- of_node_put(child);
- return -ENOMEM;
- }
-
- cell->nvmem = nvmem;
- cell->offset = be32_to_cpup(addr++);
- cell->bytes = be32_to_cpup(addr);
- cell->name = kasprintf(GFP_KERNEL, "%pOFn", child);
+ info.offset = be32_to_cpup(addr++);
+ info.bytes = be32_to_cpup(addr);
+ info.name = kasprintf(GFP_KERNEL, "%pOFn", child);
addr = of_get_property(child, "bits", &len);
if (addr && len == (2 * sizeof(u32))) {
- cell->bit_offset = be32_to_cpup(addr++);
- cell->nbits = be32_to_cpup(addr);
+ info.bit_offset = be32_to_cpup(addr++);
+ info.nbits = be32_to_cpup(addr);
}
- if (cell->nbits)
- cell->bytes = DIV_ROUND_UP(
- cell->nbits + cell->bit_offset,
- BITS_PER_BYTE);
+ info.np = of_node_get(child);
- if (!IS_ALIGNED(cell->offset, nvmem->stride)) {
- dev_err(dev, "cell %s unaligned to nvmem stride %d\n",
- cell->name, nvmem->stride);
- /* Cells already added will be freed later. */
- kfree_const(cell->name);
- kfree(cell);
+ ret = nvmem_add_one_cell(nvmem, &info);
+ kfree(info.name);
+ if (ret) {
of_node_put(child);
- return -EINVAL;
+ return ret;
}
-
- cell->np = of_node_get(child);
- nvmem_cell_entry_add(cell);
}
return 0;
@@ -764,7 +753,7 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
if (!nvmem)
return ERR_PTR(-ENOMEM);
- rval = ida_alloc(&nvmem_ida, GFP_KERNEL);
+ rval = ida_alloc(&nvmem_ida, GFP_KERNEL);
if (rval < 0) {
kfree(nvmem);
return ERR_PTR(rval);
@@ -1122,7 +1111,8 @@ struct nvmem_device *devm_nvmem_device_get(struct device *dev, const char *id)
}
EXPORT_SYMBOL_GPL(devm_nvmem_device_get);
-static struct nvmem_cell *nvmem_create_cell(struct nvmem_cell_entry *entry, const char *id)
+static struct nvmem_cell *nvmem_create_cell(struct nvmem_cell_entry *entry,
+ const char *id, int index)
{
struct nvmem_cell *cell;
const char *name = NULL;
@@ -1141,6 +1131,7 @@ static struct nvmem_cell *nvmem_create_cell(struct nvmem_cell_entry *entry, cons
cell->id = name;
cell->entry = entry;
+ cell->index = index;
return cell;
}
@@ -1179,7 +1170,7 @@ nvmem_cell_get_from_lookup(struct device *dev, const char *con_id)
__nvmem_device_put(nvmem);
cell = ERR_PTR(-ENOENT);
} else {
- cell = nvmem_create_cell(cell_entry, con_id);
+ cell = nvmem_create_cell(cell_entry, con_id, 0);
if (IS_ERR(cell))
__nvmem_device_put(nvmem);
}
@@ -1227,15 +1218,27 @@ struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *id)
struct nvmem_device *nvmem;
struct nvmem_cell_entry *cell_entry;
struct nvmem_cell *cell;
+ struct of_phandle_args cell_spec;
int index = 0;
+ int cell_index = 0;
+ int ret;
/* if cell name exists, find index to the name */
if (id)
index = of_property_match_string(np, "nvmem-cell-names", id);
- cell_np = of_parse_phandle(np, "nvmem-cells", index);
- if (!cell_np)
- return ERR_PTR(-ENOENT);
+ ret = of_parse_phandle_with_optional_args(np, "nvmem-cells",
+ "#nvmem-cell-cells",
+ index, &cell_spec);
+ if (ret)
+ return ERR_PTR(ret);
+
+ if (cell_spec.args_count > 1)
+ return ERR_PTR(-EINVAL);
+
+ cell_np = cell_spec.np;
+ if (cell_spec.args_count)
+ cell_index = cell_spec.args[0];
nvmem_np = of_get_parent(cell_np);
if (!nvmem_np) {
@@ -1257,7 +1260,7 @@ struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *id)
return ERR_PTR(-ENOENT);
}
- cell = nvmem_create_cell(cell_entry, id);
+ cell = nvmem_create_cell(cell_entry, id, cell_index);
if (IS_ERR(cell))
__nvmem_device_put(nvmem);
@@ -1410,8 +1413,8 @@ static void nvmem_shift_read_buffer_in_place(struct nvmem_cell_entry *cell, void
}
static int __nvmem_cell_read(struct nvmem_device *nvmem,
- struct nvmem_cell_entry *cell,
- void *buf, size_t *len, const char *id)
+ struct nvmem_cell_entry *cell,
+ void *buf, size_t *len, const char *id, int index)
{
int rc;
@@ -1425,7 +1428,7 @@ static int __nvmem_cell_read(struct nvmem_device *nvmem,
nvmem_shift_read_buffer_in_place(cell, buf);
if (nvmem->cell_post_process) {
- rc = nvmem->cell_post_process(nvmem->priv, id,
+ rc = nvmem->cell_post_process(nvmem->priv, id, index,
cell->offset, buf, cell->bytes);
if (rc)
return rc;
@@ -1460,7 +1463,7 @@ void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len)
if (!buf)
return ERR_PTR(-ENOMEM);
- rc = __nvmem_cell_read(nvmem, cell->entry, buf, len, cell->id);
+ rc = __nvmem_cell_read(nvmem, cell->entry, buf, len, cell->id, cell->index);
if (rc) {
kfree(buf);
return ERR_PTR(rc);
@@ -1773,7 +1776,7 @@ ssize_t nvmem_device_cell_read(struct nvmem_device *nvmem,
if (rc)
return rc;
- rc = __nvmem_cell_read(nvmem, &cell, buf, &len, NULL);
+ rc = __nvmem_cell_read(nvmem, &cell, buf, &len, NULL, 0);
if (rc)
return rc;
diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c
index 14284e866f26..e9b52ecb3f72 100644
--- a/drivers/nvmem/imx-ocotp.c
+++ b/drivers/nvmem/imx-ocotp.c
@@ -222,8 +222,8 @@ read_end:
return ret;
}
-static int imx_ocotp_cell_pp(void *context, const char *id, unsigned int offset,
- void *data, size_t bytes)
+static int imx_ocotp_cell_pp(void *context, const char *id, int index,
+ unsigned int offset, void *data, size_t bytes)
{
struct ocotp_priv *priv = context;
diff --git a/drivers/nvmem/qcom-spmi-sdam.c b/drivers/nvmem/qcom-spmi-sdam.c
index 8499892044b7..f822790db49e 100644
--- a/drivers/nvmem/qcom-spmi-sdam.c
+++ b/drivers/nvmem/qcom-spmi-sdam.c
@@ -175,18 +175,7 @@ static struct platform_driver sdam_driver = {
},
.probe = sdam_probe,
};
-
-static int __init sdam_init(void)
-{
- return platform_driver_register(&sdam_driver);
-}
-subsys_initcall(sdam_init);
-
-static void __exit sdam_exit(void)
-{
- return platform_driver_unregister(&sdam_driver);
-}
-module_exit(sdam_exit);
+module_platform_driver(sdam_driver);
MODULE_DESCRIPTION("QCOM SPMI SDAM driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/nvmem/rave-sp-eeprom.c b/drivers/nvmem/rave-sp-eeprom.c
index 66699d44f73d..c456011b75e8 100644
--- a/drivers/nvmem/rave-sp-eeprom.c
+++ b/drivers/nvmem/rave-sp-eeprom.c
@@ -45,7 +45,7 @@ enum rave_sp_eeprom_header_size {
* @type: Access type (see enum rave_sp_eeprom_access_type)
* @success: Success flag (Success = 1, Failure = 0)
* @data: Read data
-
+ *
* Note this structure corresponds to RSP_*_EEPROM payload from RAVE
* SP ICD
*/
diff --git a/drivers/nvmem/stm32-bsec-optee-ta.c b/drivers/nvmem/stm32-bsec-optee-ta.c
new file mode 100644
index 000000000000..f89ce791dd12
--- /dev/null
+++ b/drivers/nvmem/stm32-bsec-optee-ta.c
@@ -0,0 +1,298 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * OP-TEE STM32MP BSEC PTA interface, used by STM32 ROMEM driver
+ *
+ * Copyright (C) 2022, STMicroelectronics - All Rights Reserved
+ */
+
+#include <linux/tee_drv.h>
+
+#include "stm32-bsec-optee-ta.h"
+
+/*
+ * Read OTP memory
+ *
+ * [in] value[0].a OTP start offset in byte
+ * [in] value[0].b Access type (0:shadow, 1:fuse, 2:lock)
+ * [out] memref[1].buffer Output buffer to store read values
+ * [out] memref[1].size Size of OTP to be read
+ *
+ * Return codes:
+ * TEE_SUCCESS - Invoke command success
+ * TEE_ERROR_BAD_PARAMETERS - Incorrect input param
+ * TEE_ERROR_ACCESS_DENIED - OTP not accessible by caller
+ */
+#define PTA_BSEC_READ_MEM 0x0
+
+/*
+ * Write OTP memory
+ *
+ * [in] value[0].a OTP start offset in byte
+ * [in] value[0].b Access type (0:shadow, 1:fuse, 2:lock)
+ * [in] memref[1].buffer Input buffer to read values
+ * [in] memref[1].size Size of OTP to be written
+ *
+ * Return codes:
+ * TEE_SUCCESS - Invoke command success
+ * TEE_ERROR_BAD_PARAMETERS - Incorrect input param
+ * TEE_ERROR_ACCESS_DENIED - OTP not accessible by caller
+ */
+#define PTA_BSEC_WRITE_MEM 0x1
+
+/* value of PTA_BSEC access type = value[in] b */
+#define SHADOW_ACCESS 0
+#define FUSE_ACCESS 1
+#define LOCK_ACCESS 2
+
+/* Bitfield definition for LOCK status */
+#define LOCK_PERM BIT(30)
+
+/* OP-TEE STM32MP BSEC TA UUID */
+static const uuid_t stm32mp_bsec_ta_uuid =
+ UUID_INIT(0x94cf71ad, 0x80e6, 0x40b5,
+ 0xa7, 0xc6, 0x3d, 0xc5, 0x01, 0xeb, 0x28, 0x03);
+
+/*
+ * Check whether this driver supports the BSEC TA in the TEE instance
+ * represented by the params (ver/data) to this function.
+ */
+static int stm32_bsec_optee_ta_match(struct tee_ioctl_version_data *ver,
+ const void *data)
+{
+ /* Currently this driver only supports GP compliant, OP-TEE based TA */
+ if ((ver->impl_id == TEE_IMPL_ID_OPTEE) &&
+ (ver->gen_caps & TEE_GEN_CAP_GP))
+ return 1;
+ else
+ return 0;
+}
+
+/* Open a session to OP-TEE for STM32MP BSEC TA */
+static int stm32_bsec_ta_open_session(struct tee_context *ctx, u32 *id)
+{
+ struct tee_ioctl_open_session_arg sess_arg;
+ int rc;
+
+ memset(&sess_arg, 0, sizeof(sess_arg));
+ export_uuid(sess_arg.uuid, &stm32mp_bsec_ta_uuid);
+ sess_arg.clnt_login = TEE_IOCTL_LOGIN_REE_KERNEL;
+ sess_arg.num_params = 0;
+
+ rc = tee_client_open_session(ctx, &sess_arg, NULL);
+ if ((rc < 0) || (sess_arg.ret != 0)) {
+ pr_err("%s: tee_client_open_session failed err:%#x, ret:%#x\n",
+ __func__, sess_arg.ret, rc);
+ if (!rc)
+ rc = -EINVAL;
+ } else {
+ *id = sess_arg.session;
+ }
+
+ return rc;
+}
+
+/* close a session to OP-TEE for STM32MP BSEC TA */
+static void stm32_bsec_ta_close_session(void *ctx, u32 id)
+{
+ tee_client_close_session(ctx, id);
+}
+
+/* stm32_bsec_optee_ta_open() - initialize the STM32MP BSEC TA */
+int stm32_bsec_optee_ta_open(struct tee_context **ctx)
+{
+ struct tee_context *tee_ctx;
+ u32 session_id;
+ int rc;
+
+ /* Open context with TEE driver */
+ tee_ctx = tee_client_open_context(NULL, stm32_bsec_optee_ta_match, NULL, NULL);
+ if (IS_ERR(tee_ctx)) {
+ rc = PTR_ERR(tee_ctx);
+ if (rc == -ENOENT)
+ return -EPROBE_DEFER;
+ pr_err("%s: tee_client_open_context failed (%d)\n", __func__, rc);
+
+ return rc;
+ }
+
+ /* Check STM32MP BSEC TA presence */
+ rc = stm32_bsec_ta_open_session(tee_ctx, &session_id);
+ if (rc) {
+ tee_client_close_context(tee_ctx);
+ return rc;
+ }
+
+ stm32_bsec_ta_close_session(tee_ctx, session_id);
+
+ *ctx = tee_ctx;
+
+ return 0;
+}
+
+/* stm32_bsec_optee_ta_open() - release the PTA STM32MP BSEC TA */
+void stm32_bsec_optee_ta_close(void *ctx)
+{
+ tee_client_close_context(ctx);
+}
+
+/* stm32_bsec_optee_ta_read() - nvmem read access using PTA client driver */
+int stm32_bsec_optee_ta_read(struct tee_context *ctx, unsigned int offset,
+ void *buf, size_t bytes)
+{
+ struct tee_shm *shm;
+ struct tee_ioctl_invoke_arg arg;
+ struct tee_param param[2];
+ u8 *shm_buf;
+ u32 start, num_bytes;
+ int ret;
+ u32 session_id;
+
+ ret = stm32_bsec_ta_open_session(ctx, &session_id);
+ if (ret)
+ return ret;
+
+ memset(&arg, 0, sizeof(arg));
+ memset(&param, 0, sizeof(param));
+
+ arg.func = PTA_BSEC_READ_MEM;
+ arg.session = session_id;
+ arg.num_params = 2;
+
+ /* align access on 32bits */
+ start = ALIGN_DOWN(offset, 4);
+ num_bytes = round_up(offset + bytes - start, 4);
+ param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT;
+ param[0].u.value.a = start;
+ param[0].u.value.b = SHADOW_ACCESS;
+
+ shm = tee_shm_alloc_kernel_buf(ctx, num_bytes);
+ if (IS_ERR(shm)) {
+ ret = PTR_ERR(shm);
+ goto out_tee_session;
+ }
+
+ param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT;
+ param[1].u.memref.shm = shm;
+ param[1].u.memref.size = num_bytes;
+
+ ret = tee_client_invoke_func(ctx, &arg, param);
+ if (ret < 0 || arg.ret != 0) {
+ pr_err("TA_BSEC invoke failed TEE err:%#x, ret:%#x\n",
+ arg.ret, ret);
+ if (!ret)
+ ret = -EIO;
+ }
+ if (!ret) {
+ shm_buf = tee_shm_get_va(shm, 0);
+ if (IS_ERR(shm_buf)) {
+ ret = PTR_ERR(shm_buf);
+ pr_err("tee_shm_get_va failed for transmit (%d)\n", ret);
+ } else {
+ /* read data from 32 bits aligned buffer */
+ memcpy(buf, &shm_buf[offset % 4], bytes);
+ }
+ }
+
+ tee_shm_free(shm);
+
+out_tee_session:
+ stm32_bsec_ta_close_session(ctx, session_id);
+
+ return ret;
+}
+
+/* stm32_bsec_optee_ta_write() - nvmem write access using PTA client driver */
+int stm32_bsec_optee_ta_write(struct tee_context *ctx, unsigned int lower,
+ unsigned int offset, void *buf, size_t bytes)
+{ struct tee_shm *shm;
+ struct tee_ioctl_invoke_arg arg;
+ struct tee_param param[2];
+ u8 *shm_buf;
+ int ret;
+ u32 session_id;
+
+ ret = stm32_bsec_ta_open_session(ctx, &session_id);
+ if (ret)
+ return ret;
+
+ /* Allow only writing complete 32-bits aligned words */
+ if ((bytes % 4) || (offset % 4))
+ return -EINVAL;
+
+ memset(&arg, 0, sizeof(arg));
+ memset(&param, 0, sizeof(param));
+
+ arg.func = PTA_BSEC_WRITE_MEM;
+ arg.session = session_id;
+ arg.num_params = 2;
+
+ param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT;
+ param[0].u.value.a = offset;
+ param[0].u.value.b = FUSE_ACCESS;
+
+ shm = tee_shm_alloc_kernel_buf(ctx, bytes);
+ if (IS_ERR(shm)) {
+ ret = PTR_ERR(shm);
+ goto out_tee_session;
+ }
+
+ param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
+ param[1].u.memref.shm = shm;
+ param[1].u.memref.size = bytes;
+
+ shm_buf = tee_shm_get_va(shm, 0);
+ if (IS_ERR(shm_buf)) {
+ ret = PTR_ERR(shm_buf);
+ pr_err("tee_shm_get_va failed for transmit (%d)\n", ret);
+ tee_shm_free(shm);
+
+ goto out_tee_session;
+ }
+
+ memcpy(shm_buf, buf, bytes);
+
+ ret = tee_client_invoke_func(ctx, &arg, param);
+ if (ret < 0 || arg.ret != 0) {
+ pr_err("TA_BSEC invoke failed TEE err:%#x, ret:%#x\n", arg.ret, ret);
+ if (!ret)
+ ret = -EIO;
+ }
+ pr_debug("Write OTPs %d to %zu, ret=%d\n", offset / 4, (offset + bytes) / 4, ret);
+
+ /* Lock the upper OTPs with ECC protection, word programming only */
+ if (!ret && ((offset + bytes) >= (lower * 4))) {
+ u32 start, nb_lock;
+ u32 *lock = (u32 *)shm_buf;
+ int i;
+
+ /*
+ * don't lock the lower OTPs, no ECC protection and incremental
+ * bit programming, a second write is allowed
+ */
+ start = max_t(u32, offset, lower * 4);
+ nb_lock = (offset + bytes - start) / 4;
+
+ param[0].u.value.a = start;
+ param[0].u.value.b = LOCK_ACCESS;
+ param[1].u.memref.size = nb_lock * 4;
+
+ for (i = 0; i < nb_lock; i++)
+ lock[i] = LOCK_PERM;
+
+ ret = tee_client_invoke_func(ctx, &arg, param);
+ if (ret < 0 || arg.ret != 0) {
+ pr_err("TA_BSEC invoke failed TEE err:%#x, ret:%#x\n", arg.ret, ret);
+ if (!ret)
+ ret = -EIO;
+ }
+ pr_debug("Lock upper OTPs %d to %d, ret=%d\n",
+ start / 4, start / 4 + nb_lock, ret);
+ }
+
+ tee_shm_free(shm);
+
+out_tee_session:
+ stm32_bsec_ta_close_session(ctx, session_id);
+
+ return ret;
+}
diff --git a/drivers/nvmem/stm32-bsec-optee-ta.h b/drivers/nvmem/stm32-bsec-optee-ta.h
new file mode 100644
index 000000000000..3966a0535179
--- /dev/null
+++ b/drivers/nvmem/stm32-bsec-optee-ta.h
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * OP-TEE STM32MP BSEC PTA interface, used by STM32 ROMEM driver
+ *
+ * Copyright (C) 2022, STMicroelectronics - All Rights Reserved
+ */
+
+#if IS_ENABLED(CONFIG_NVMEM_STM32_BSEC_OPTEE_TA)
+/**
+ * stm32_bsec_optee_ta_open() - initialize the STM32 BSEC TA
+ * @ctx: the OP-TEE context on success
+ *
+ * Return:
+ * On success, 0. On failure, -errno.
+ */
+int stm32_bsec_optee_ta_open(struct tee_context **ctx);
+
+/**
+ * stm32_bsec_optee_ta_close() - release the STM32 BSEC TA
+ * @ctx: the OP-TEE context
+ *
+ * This function used to clean the OP-TEE resources initialized in
+ * stm32_bsec_optee_ta_open(); it can be used as callback to
+ * devm_add_action_or_reset()
+ */
+void stm32_bsec_optee_ta_close(void *ctx);
+
+/**
+ * stm32_bsec_optee_ta_read() - nvmem read access using TA client driver
+ * @ctx: the OP-TEE context provided by stm32_bsec_optee_ta_open
+ * @offset: nvmem offset
+ * @buf: buffer to fill with nvem values
+ * @bytes: number of bytes to read
+ *
+ * Return:
+ * On success, 0. On failure, -errno.
+ */
+int stm32_bsec_optee_ta_read(struct tee_context *ctx, unsigned int offset,
+ void *buf, size_t bytes);
+
+/**
+ * stm32_bsec_optee_ta_write() - nvmem write access using TA client driver
+ * @ctx: the OP-TEE context provided by stm32_bsec_optee_ta_open
+ * @lower: number of lower OTP, not protected by ECC
+ * @offset: nvmem offset
+ * @buf: buffer with nvem values
+ * @bytes: number of bytes to write
+ *
+ * Return:
+ * On success, 0. On failure, -errno.
+ */
+int stm32_bsec_optee_ta_write(struct tee_context *ctx, unsigned int lower,
+ unsigned int offset, void *buf, size_t bytes);
+
+#else
+
+static inline int stm32_bsec_optee_ta_open(struct tee_context **ctx)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline void stm32_bsec_optee_ta_close(void *ctx)
+{
+}
+
+static inline int stm32_bsec_optee_ta_read(struct tee_context *ctx,
+ unsigned int offset, void *buf,
+ size_t bytes)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int stm32_bsec_optee_ta_write(struct tee_context *ctx,
+ unsigned int lower,
+ unsigned int offset, void *buf,
+ size_t bytes)
+{
+ return -EOPNOTSUPP;
+}
+#endif /* CONFIG_NVMEM_STM32_BSEC_OPTEE_TA */
diff --git a/drivers/nvmem/stm32-romem.c b/drivers/nvmem/stm32-romem.c
index d1d03c2ad081..ba779e26937a 100644
--- a/drivers/nvmem/stm32-romem.c
+++ b/drivers/nvmem/stm32-romem.c
@@ -11,6 +11,9 @@
#include <linux/module.h>
#include <linux/nvmem-provider.h>
#include <linux/of_device.h>
+#include <linux/tee_drv.h>
+
+#include "stm32-bsec-optee-ta.h"
/* BSEC secure service access from non-secure */
#define STM32_SMC_BSEC 0x82001003
@@ -25,12 +28,14 @@
struct stm32_romem_cfg {
int size;
u8 lower;
+ bool ta;
};
struct stm32_romem_priv {
void __iomem *base;
struct nvmem_config cfg;
u8 lower;
+ struct tee_context *ctx;
};
static int stm32_romem_read(void *context, unsigned int offset, void *buf,
@@ -138,12 +143,54 @@ static int stm32_bsec_write(void *context, unsigned int offset, void *buf,
return 0;
}
+static int stm32_bsec_pta_read(void *context, unsigned int offset, void *buf,
+ size_t bytes)
+{
+ struct stm32_romem_priv *priv = context;
+
+ return stm32_bsec_optee_ta_read(priv->ctx, offset, buf, bytes);
+}
+
+static int stm32_bsec_pta_write(void *context, unsigned int offset, void *buf,
+ size_t bytes)
+{
+ struct stm32_romem_priv *priv = context;
+
+ return stm32_bsec_optee_ta_write(priv->ctx, priv->lower, offset, buf, bytes);
+}
+
+static bool stm32_bsec_smc_check(void)
+{
+ u32 val;
+ int ret;
+
+ /* check that the OP-TEE support the BSEC SMC (legacy mode) */
+ ret = stm32_bsec_smc(STM32_SMC_READ_SHADOW, 0, 0, &val);
+
+ return !ret;
+}
+
+static bool optee_presence_check(void)
+{
+ struct device_node *np;
+ bool tee_detected = false;
+
+ /* check that the OP-TEE node is present and available. */
+ np = of_find_compatible_node(NULL, NULL, "linaro,optee-tz");
+ if (np && of_device_is_available(np))
+ tee_detected = true;
+ of_node_put(np);
+
+ return tee_detected;
+}
+
static int stm32_romem_probe(struct platform_device *pdev)
{
const struct stm32_romem_cfg *cfg;
struct device *dev = &pdev->dev;
struct stm32_romem_priv *priv;
struct resource *res;
+ int rc;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -173,15 +220,36 @@ static int stm32_romem_probe(struct platform_device *pdev)
} else {
priv->cfg.size = cfg->size;
priv->lower = cfg->lower;
- priv->cfg.reg_read = stm32_bsec_read;
- priv->cfg.reg_write = stm32_bsec_write;
+ if (cfg->ta || optee_presence_check()) {
+ rc = stm32_bsec_optee_ta_open(&priv->ctx);
+ if (rc) {
+ /* wait for OP-TEE client driver to be up and ready */
+ if (rc == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ /* BSEC PTA is required or SMC not supported */
+ if (cfg->ta || !stm32_bsec_smc_check())
+ return rc;
+ }
+ }
+ if (priv->ctx) {
+ rc = devm_add_action_or_reset(dev, stm32_bsec_optee_ta_close, priv->ctx);
+ if (rc) {
+ dev_err(dev, "devm_add_action_or_reset() failed (%d)\n", rc);
+ return rc;
+ }
+ priv->cfg.reg_read = stm32_bsec_pta_read;
+ priv->cfg.reg_write = stm32_bsec_pta_write;
+ } else {
+ priv->cfg.reg_read = stm32_bsec_read;
+ priv->cfg.reg_write = stm32_bsec_write;
+ }
}
return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &priv->cfg));
}
/*
- * STM32MP15 BSEC OTP regions: 4096 OTP bits (with 3072 effective bits)
+ * STM32MP15/13 BSEC OTP regions: 4096 OTP bits (with 3072 effective bits)
* => 96 x 32-bits data words
* - Lower: 1K bits, 2:1 redundancy, incremental bit programming
* => 32 (x 32-bits) lower shadow registers = words 0 to 31
@@ -191,6 +259,13 @@ static int stm32_romem_probe(struct platform_device *pdev)
static const struct stm32_romem_cfg stm32mp15_bsec_cfg = {
.size = 384,
.lower = 32,
+ .ta = false,
+};
+
+static const struct stm32_romem_cfg stm32mp13_bsec_cfg = {
+ .size = 384,
+ .lower = 32,
+ .ta = true,
};
static const struct of_device_id stm32_romem_of_match[] = {
@@ -198,7 +273,10 @@ static const struct of_device_id stm32_romem_of_match[] = {
.compatible = "st,stm32mp15-bsec",
.data = (void *)&stm32mp15_bsec_cfg,
}, {
+ .compatible = "st,stm32mp13-bsec",
+ .data = (void *)&stm32mp13_bsec_cfg,
},
+ { /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, stm32_romem_of_match);
diff --git a/drivers/nvmem/sunxi_sid.c b/drivers/nvmem/sunxi_sid.c
index 92dfe4cb10e3..a970f1741cc6 100644
--- a/drivers/nvmem/sunxi_sid.c
+++ b/drivers/nvmem/sunxi_sid.c
@@ -197,15 +197,9 @@ static const struct sunxi_sid_cfg sun8i_h3_cfg = {
.need_register_readout = true,
};
-static const struct sunxi_sid_cfg sun20i_d1_cfg = {
- .value_offset = 0x200,
- .size = 0x100,
-};
-
static const struct sunxi_sid_cfg sun50i_a64_cfg = {
.value_offset = 0x200,
.size = 0x100,
- .need_register_readout = true,
};
static const struct sunxi_sid_cfg sun50i_h6_cfg = {
@@ -218,7 +212,7 @@ static const struct of_device_id sunxi_sid_of_match[] = {
{ .compatible = "allwinner,sun7i-a20-sid", .data = &sun7i_a20_cfg },
{ .compatible = "allwinner,sun8i-a83t-sid", .data = &sun50i_a64_cfg },
{ .compatible = "allwinner,sun8i-h3-sid", .data = &sun8i_h3_cfg },
- { .compatible = "allwinner,sun20i-d1-sid", .data = &sun20i_d1_cfg },
+ { .compatible = "allwinner,sun20i-d1-sid", .data = &sun50i_a64_cfg },
{ .compatible = "allwinner,sun50i-a64-sid", .data = &sun50i_a64_cfg },
{ .compatible = "allwinner,sun50i-h5-sid", .data = &sun50i_a64_cfg },
{ .compatible = "allwinner,sun50i-h6-sid", .data = &sun50i_h6_cfg },
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index 80b5fd44ab1c..644386833a7b 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -23,7 +23,19 @@ config OF_UNITTEST
that are executed once at boot time, and the results dumped to the
console.
- If unsure, say N here, but this option is safe to enable.
+ This option should only be enabled for a development kernel. The tests
+ will taint the kernel with TAINT_TEST. The tests will cause ERROR and
+ WARNING messages to print on the console. The tests will cause stack
+ traces to print on the console. It is possible that the tests will
+ leave the devicetree in a corrupted state.
+
+ The unittest output will be verbose. Copy the output to a file
+ via capturing the console output or via the dmesg command. Process
+ this file with scripts/dtc/of_unittest_expect to reduce the
+ verbosity, test whether expected output is present, and to
+ summarize the results.
+
+ If unsure, say N here. This option is not safe to enable.
config OF_ALL_DTBS
bool "Build all Device Tree Blobs"
diff --git a/drivers/of/address.c b/drivers/of/address.c
index 67763e5b8c0e..4c0b169ef9bf 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -626,6 +626,47 @@ u64 of_translate_dma_address(struct device_node *dev, const __be32 *in_addr)
}
EXPORT_SYMBOL(of_translate_dma_address);
+/**
+ * of_translate_dma_region - Translate device tree address and size tuple
+ * @dev: device tree node for which to translate
+ * @prop: pointer into array of cells
+ * @start: return value for the start of the DMA range
+ * @length: return value for the length of the DMA range
+ *
+ * Returns a pointer to the cell immediately following the translated DMA region.
+ */
+const __be32 *of_translate_dma_region(struct device_node *dev, const __be32 *prop,
+ phys_addr_t *start, size_t *length)
+{
+ struct device_node *parent;
+ u64 address, size;
+ int na, ns;
+
+ parent = __of_get_dma_parent(dev);
+ if (!parent)
+ return NULL;
+
+ na = of_bus_n_addr_cells(parent);
+ ns = of_bus_n_size_cells(parent);
+
+ of_node_put(parent);
+
+ address = of_translate_dma_address(dev, prop);
+ if (address == OF_BAD_ADDR)
+ return NULL;
+
+ size = of_read_number(prop + na, ns);
+
+ if (start)
+ *start = address;
+
+ if (length)
+ *length = size;
+
+ return prop + na + ns;
+}
+EXPORT_SYMBOL(of_translate_dma_region);
+
const __be32 *__of_get_address(struct device_node *dev, int index, int bar_no,
u64 *size, unsigned int *flags)
{
diff --git a/drivers/of/base.c b/drivers/of/base.c
index d5a5c35eba72..ac6fde53342f 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -1884,8 +1884,7 @@ static void of_alias_add(struct alias_prop *ap, struct device_node *np,
{
ap->np = np;
ap->id = id;
- strncpy(ap->stem, stem, stem_len);
- ap->stem[stem_len] = 0;
+ strscpy(ap->stem, stem, stem_len + 1);
list_add_tail(&ap->link, &aliases_lookup);
pr_debug("adding DT alias:%s: stem=%s id=%i node=%pOF\n",
ap->alias, ap->stem, ap->id, np);
diff --git a/drivers/of/device.c b/drivers/of/device.c
index c674a13c3055..955bfb3d1a83 100644
--- a/drivers/of/device.c
+++ b/drivers/of/device.c
@@ -248,7 +248,7 @@ const void *of_device_get_match_data(const struct device *dev)
}
EXPORT_SYMBOL(of_device_get_match_data);
-static ssize_t of_device_get_modalias(struct device *dev, char *str, ssize_t len)
+static ssize_t of_device_get_modalias(const struct device *dev, char *str, ssize_t len)
{
const char *compat;
char *c;
@@ -256,7 +256,7 @@ static ssize_t of_device_get_modalias(struct device *dev, char *str, ssize_t len
ssize_t csize;
ssize_t tsize;
- if ((!dev) || (!dev->of_node))
+ if ((!dev) || (!dev->of_node) || dev->of_node_reused)
return -ENODEV;
/* Name & Type */
@@ -372,11 +372,11 @@ void of_device_uevent(const struct device *dev, struct kobj_uevent_env *env)
mutex_unlock(&of_mutex);
}
-int of_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env)
+int of_device_uevent_modalias(const struct device *dev, struct kobj_uevent_env *env)
{
int sl;
- if ((!dev) || (!dev->of_node))
+ if ((!dev) || (!dev->of_node) || dev->of_node_reused)
return -ENODEV;
/* Devicetree modalias is tricky, we add it in 2 steps */
@@ -385,6 +385,8 @@ int of_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env)
sl = of_device_get_modalias(dev, &env->buf[env->buflen-1],
sizeof(env->buf) - env->buflen);
+ if (sl < 0)
+ return sl;
if (sl >= (sizeof(env->buf) - env->buflen))
return -ENOMEM;
env->buflen += sl;
diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c
index cd3821a6444f..07d93753b12f 100644
--- a/drivers/of/dynamic.c
+++ b/drivers/of/dynamic.c
@@ -329,10 +329,30 @@ void of_node_release(struct kobject *kobj)
{
struct device_node *node = kobj_to_device_node(kobj);
+ /*
+ * can not use '"%pOF", node' in pr_err() calls from this function
+ * because an of_node_get(node) when refcount is already zero
+ * will result in an error and a stack dump
+ */
+
/* We should never be releasing nodes that haven't been detached. */
if (!of_node_check_flag(node, OF_DETACHED)) {
- pr_err("ERROR: Bad of_node_put() on %pOF\n", node);
- dump_stack();
+
+ pr_err("ERROR: %s() detected bad of_node_put() on %pOF/%s\n",
+ __func__, node->parent, node->full_name);
+
+ /*
+ * of unittests will test this path. Do not print the stack
+ * trace when the error is caused by unittest so that we do
+ * not display what a normal developer might reasonably
+ * consider a real bug.
+ */
+ if (!IS_ENABLED(CONFIG_OF_UNITTEST) ||
+ strcmp(node->parent->full_name, "testcase-data")) {
+ dump_stack();
+ pr_err("ERROR: next of_node_put() on this node will result in a kobject warning 'refcount_t: underflow; use-after-free.'\n");
+ }
+
return;
}
if (!of_node_check_flag(node, OF_DYNAMIC))
@@ -357,6 +377,10 @@ void of_node_release(struct kobject *kobj)
__func__, node);
}
+ if (node->child)
+ pr_err("ERROR: %s() unexpected children for %pOF/%s\n",
+ __func__, node->parent, node->full_name);
+
property_list_free(node->properties);
property_list_free(node->deadprops);
fwnode_links_purge(of_fwnode_handle(node));
@@ -419,7 +443,8 @@ struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags)
* another node. The node data are dynamically allocated and all the node
* flags have the OF_DYNAMIC & OF_DETACHED bits set.
*
- * Return: The newly allocated node or NULL on out of memory error.
+ * Return: The newly allocated node or NULL on out of memory error. Use
+ * of_node_put() on it when done to free the memory allocated for it.
*/
struct device_node *__of_node_dup(const struct device_node *np,
const char *full_name)
diff --git a/drivers/of/irq.c b/drivers/of/irq.c
index e9bf5236ed89..174900072c18 100644
--- a/drivers/of/irq.c
+++ b/drivers/of/irq.c
@@ -438,10 +438,16 @@ int of_irq_get(struct device_node *dev, int index)
return rc;
domain = irq_find_host(oirq.np);
- if (!domain)
- return -EPROBE_DEFER;
+ if (!domain) {
+ rc = -EPROBE_DEFER;
+ goto out;
+ }
- return irq_create_of_mapping(&oirq);
+ rc = irq_create_of_mapping(&oirq);
+out:
+ of_node_put(oirq.np);
+
+ return rc;
}
EXPORT_SYMBOL_GPL(of_irq_get);
diff --git a/drivers/of/kobj.c b/drivers/of/kobj.c
index 7d3853a5a09a..3dbce1e6f184 100644
--- a/drivers/of/kobj.c
+++ b/drivers/of/kobj.c
@@ -24,7 +24,7 @@ static void of_node_release(struct kobject *kobj)
}
#endif /* CONFIG_OF_DYNAMIC */
-struct kobj_type of_node_ktype = {
+const struct kobj_type of_node_ktype = {
.release = of_node_release,
};
diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
index f90975e00446..948efa9f99e3 100644
--- a/drivers/of/of_reserved_mem.c
+++ b/drivers/of/of_reserved_mem.c
@@ -285,6 +285,16 @@ void __init fdt_init_reserved_mem(void)
else
memblock_phys_free(rmem->base,
rmem->size);
+ } else {
+ phys_addr_t end = rmem->base + rmem->size - 1;
+ bool reusable =
+ (of_get_flat_dt_prop(node, "reusable", NULL)) != NULL;
+
+ pr_info("%pa..%pa (%lu KiB) %s %s %s\n",
+ &rmem->base, &end, (unsigned long)(rmem->size / SZ_1K),
+ nomap ? "nomap" : "map",
+ reusable ? "reusable" : "non-reusable",
+ rmem->name ? rmem->name : "unknown");
}
}
}
diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
index ed4e6c144a68..2e01960f1aeb 100644
--- a/drivers/of/overlay.c
+++ b/drivers/of/overlay.c
@@ -1121,7 +1121,7 @@ static int node_overlaps_later_cs(struct overlay_changeset *remove_ovcs,
* The topmost check is done by exploiting this property. For each
* affected device node in the log list we check if this overlay is
* the one closest to the tail. If another overlay has affected this
- * device node and is closest to the tail, then removal is not permited.
+ * device node and is closest to the tail, then removal is not permitted.
*/
static int overlay_removal_is_ok(struct overlay_changeset *remove_ovcs)
{
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index b3878a98d27f..b2bd2e783445 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -222,7 +222,6 @@ static struct amba_device *of_amba_device_create(struct device_node *node,
struct device *parent)
{
struct amba_device *dev;
- const void *prop;
int ret;
pr_debug("Creating amba device %pOF\n", node);
@@ -250,9 +249,7 @@ static struct amba_device *of_amba_device_create(struct device_node *node,
of_device_make_bus_id(&dev->dev);
/* Allow the HW Peripheral ID to be overridden */
- prop = of_get_property(node, "arm,primecell-periphid", NULL);
- if (prop)
- dev->periphid = of_read_ulong(prop, 1);
+ of_property_read_u32(node, "arm,primecell-periphid", &dev->periphid);
ret = of_address_to_resource(node, 0, &dev->res);
if (ret) {
@@ -529,7 +526,7 @@ static int __init of_platform_default_populate_init(void)
int ret;
/* Check if we have a MacOS display without a node spec */
- if (of_get_property(of_chosen, "linux,bootx-noscreen", NULL)) {
+ if (of_property_present(of_chosen, "linux,bootx-noscreen")) {
/*
* The old code tried to work out which node was the MacOS
* display based on the address. I'm dropping that since the
diff --git a/drivers/of/property.c b/drivers/of/property.c
index 134cfc980b70..ddc75cd50825 100644
--- a/drivers/of/property.c
+++ b/drivers/of/property.c
@@ -1062,20 +1062,6 @@ of_fwnode_device_get_match_data(const struct fwnode_handle *fwnode,
return of_device_get_match_data(dev);
}
-static bool of_is_ancestor_of(struct device_node *test_ancestor,
- struct device_node *child)
-{
- of_node_get(child);
- while (child) {
- if (child == test_ancestor) {
- of_node_put(child);
- return true;
- }
- child = of_get_next_parent(child);
- }
- return false;
-}
-
static struct device_node *of_get_compat_node(struct device_node *np)
{
of_node_get(np);
@@ -1086,7 +1072,7 @@ static struct device_node *of_get_compat_node(struct device_node *np)
np = NULL;
}
- if (of_find_property(np, "compatible", NULL))
+ if (of_property_present(np, "compatible"))
break;
np = of_get_next_parent(np);
@@ -1106,71 +1092,27 @@ static struct device_node *of_get_compat_node_parent(struct device_node *np)
return node;
}
-/**
- * of_link_to_phandle - Add fwnode link to supplier from supplier phandle
- * @con_np: consumer device tree node
- * @sup_np: supplier device tree node
- *
- * Given a phandle to a supplier device tree node (@sup_np), this function
- * finds the device that owns the supplier device tree node and creates a
- * device link from @dev consumer device to the supplier device. This function
- * doesn't create device links for invalid scenarios such as trying to create a
- * link with a parent device as the consumer of its child device. In such
- * cases, it returns an error.
- *
- * Returns:
- * - 0 if fwnode link successfully created to supplier
- * - -EINVAL if the supplier link is invalid and should not be created
- * - -ENODEV if struct device will never be create for supplier
- */
-static int of_link_to_phandle(struct device_node *con_np,
+static void of_link_to_phandle(struct device_node *con_np,
struct device_node *sup_np)
{
- struct device *sup_dev;
- struct device_node *tmp_np = sup_np;
+ struct device_node *tmp_np = of_node_get(sup_np);
- /*
- * Find the device node that contains the supplier phandle. It may be
- * @sup_np or it may be an ancestor of @sup_np.
- */
- sup_np = of_get_compat_node(sup_np);
- if (!sup_np) {
- pr_debug("Not linking %pOFP to %pOFP - No device\n",
- con_np, tmp_np);
- return -ENODEV;
- }
+ /* Check that sup_np and its ancestors are available. */
+ while (tmp_np) {
+ if (of_fwnode_handle(tmp_np)->dev) {
+ of_node_put(tmp_np);
+ break;
+ }
- /*
- * Don't allow linking a device node as a consumer of one of its
- * descendant nodes. By definition, a child node can't be a functional
- * dependency for the parent node.
- */
- if (of_is_ancestor_of(con_np, sup_np)) {
- pr_debug("Not linking %pOFP to %pOFP - is descendant\n",
- con_np, sup_np);
- of_node_put(sup_np);
- return -EINVAL;
- }
+ if (!of_device_is_available(tmp_np)) {
+ of_node_put(tmp_np);
+ return;
+ }
- /*
- * Don't create links to "early devices" that won't have struct devices
- * created for them.
- */
- sup_dev = get_dev_from_fwnode(&sup_np->fwnode);
- if (!sup_dev &&
- (of_node_check_flag(sup_np, OF_POPULATED) ||
- sup_np->fwnode.flags & FWNODE_FLAG_NOT_DEVICE)) {
- pr_debug("Not linking %pOFP to %pOFP - No struct device\n",
- con_np, sup_np);
- of_node_put(sup_np);
- return -ENODEV;
+ tmp_np = of_get_next_parent(tmp_np);
}
- put_device(sup_dev);
fwnode_link_add(of_fwnode_handle(con_np), of_fwnode_handle(sup_np));
- of_node_put(sup_np);
-
- return 0;
}
/**
@@ -1202,8 +1144,8 @@ static struct device_node *parse_prop_cells(struct device_node *np,
if (strcmp(prop_name, list_name))
return NULL;
- if (of_parse_phandle_with_args(np, list_name, cells_name, index,
- &sup_args))
+ if (__of_parse_phandle_with_args(np, list_name, cells_name, 0, index,
+ &sup_args))
return NULL;
return sup_args.np;
@@ -1307,7 +1249,7 @@ DEFINE_SIMPLE_PROP(dmas, "dmas", "#dma-cells")
DEFINE_SIMPLE_PROP(power_domains, "power-domains", "#power-domain-cells")
DEFINE_SIMPLE_PROP(hwlocks, "hwlocks", "#hwlock-cells")
DEFINE_SIMPLE_PROP(extcon, "extcon", NULL)
-DEFINE_SIMPLE_PROP(nvmem_cells, "nvmem-cells", NULL)
+DEFINE_SIMPLE_PROP(nvmem_cells, "nvmem-cells", "#nvmem-cell-cells")
DEFINE_SIMPLE_PROP(phys, "phys", "#phy-cells")
DEFINE_SIMPLE_PROP(wakeup_parent, "wakeup-parent", NULL)
DEFINE_SIMPLE_PROP(pinctrl0, "pinctrl-0", NULL)
@@ -1358,7 +1300,7 @@ static struct device_node *parse_gpio_compat(struct device_node *np,
* Ignore node with gpio-hog property since its gpios are all provided
* by its parent.
*/
- if (of_find_property(np, "gpio-hog", NULL))
+ if (of_property_read_bool(np, "gpio-hog"))
return NULL;
if (of_parse_phandle_with_args(np, prop_name, "#gpio-cells", index,
diff --git a/drivers/of/unittest-data/testcases_common.dtsi b/drivers/of/unittest-data/testcases_common.dtsi
index 19292bbb4cbb..e7887f2301c1 100644
--- a/drivers/of/unittest-data/testcases_common.dtsi
+++ b/drivers/of/unittest-data/testcases_common.dtsi
@@ -17,3 +17,4 @@
#include "tests-address.dtsi"
#include "tests-platform.dtsi"
#include "tests-overlay.dtsi"
+#include "tests-lifecycle.dtsi"
diff --git a/drivers/of/unittest-data/tests-lifecycle.dtsi b/drivers/of/unittest-data/tests-lifecycle.dtsi
new file mode 100644
index 000000000000..28509a8783a7
--- /dev/null
+++ b/drivers/of/unittest-data/tests-lifecycle.dtsi
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/ {
+ testcase-data {
+ refcount-node {
+ };
+ };
+};
diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
index bc0f1e50a4be..b5a7a31d8bd2 100644
--- a/drivers/of/unittest.c
+++ b/drivers/of/unittest.c
@@ -54,8 +54,9 @@ static struct unittest_results {
* Print the expected message only if the current loglevel will allow
* the actual message to print.
*
- * Do not use EXPECT_BEGIN() or EXPECT_END() for messages generated by
- * pr_debug().
+ * Do not use EXPECT_BEGIN(), EXPECT_END(), EXPECT_NOT_BEGIN(), or
+ * EXPECT_NOT_END() to report messages expected to be reported or not
+ * reported by pr_debug().
*/
#define EXPECT_BEGIN(level, fmt, ...) \
printk(level pr_fmt("EXPECT \\ : ") fmt, ##__VA_ARGS__)
@@ -63,6 +64,12 @@ static struct unittest_results {
#define EXPECT_END(level, fmt, ...) \
printk(level pr_fmt("EXPECT / : ") fmt, ##__VA_ARGS__)
+#define EXPECT_NOT_BEGIN(level, fmt, ...) \
+ printk(level pr_fmt("EXPECT_NOT \\ : ") fmt, ##__VA_ARGS__)
+
+#define EXPECT_NOT_END(level, fmt, ...) \
+ printk(level pr_fmt("EXPECT_NOT / : ") fmt, ##__VA_ARGS__)
+
static void __init of_unittest_find_node_by_name(void)
{
struct device_node *np;
@@ -1488,6 +1495,7 @@ static int __init unittest_data_add(void)
struct device_node *next = np->sibling;
np->parent = of_root;
+ /* this will clear OF_DETACHED in np and children */
attach_node_and_children(np);
np = next;
}
@@ -2998,6 +3006,143 @@ out:
static inline void __init of_unittest_overlay(void) { }
#endif
+static void __init of_unittest_lifecycle(void)
+{
+#ifdef CONFIG_OF_DYNAMIC
+ unsigned int refcount;
+ int found_refcount_one = 0;
+ int put_count = 0;
+ struct device_node *np;
+ struct device_node *prev_sibling, *next_sibling;
+ const char *refcount_path = "/testcase-data/refcount-node";
+ const char *refcount_parent_path = "/testcase-data";
+
+ /*
+ * Node lifecycle tests, non-dynamic node:
+ *
+ * - Decrementing refcount to zero via of_node_put() should cause the
+ * attempt to free the node memory by of_node_release() to fail
+ * because the node is not a dynamic node.
+ *
+ * - Decrementing refcount past zero should result in additional
+ * errors reported.
+ */
+
+ np = of_find_node_by_path(refcount_path);
+ unittest(np, "find refcount_path \"%s\"\n", refcount_path);
+ if (np == NULL)
+ goto out_skip_tests;
+
+ while (!found_refcount_one) {
+
+ if (put_count++ > 10) {
+ unittest(0, "guardrail to avoid infinite loop\n");
+ goto out_skip_tests;
+ }
+
+ refcount = kref_read(&np->kobj.kref);
+ if (refcount == 1)
+ found_refcount_one = 1;
+ else
+ of_node_put(np);
+ }
+
+ EXPECT_BEGIN(KERN_INFO, "OF: ERROR: of_node_release() detected bad of_node_put() on /testcase-data/refcount-node");
+
+ /*
+ * refcount is now one, decrementing to zero will result in a call to
+ * of_node_release() to free the node's memory, which should result
+ * in an error
+ */
+ unittest(1, "/testcase-data/refcount-node is one");
+ of_node_put(np);
+
+ EXPECT_END(KERN_INFO, "OF: ERROR: of_node_release() detected bad of_node_put() on /testcase-data/refcount-node");
+
+
+ /*
+ * expect stack trace for subsequent of_node_put():
+ * __refcount_sub_and_test() calls:
+ * refcount_warn_saturate(r, REFCOUNT_SUB_UAF)
+ *
+ * Not capturing entire WARN_ONCE() trace with EXPECT_*(), just
+ * the first three lines, and the last line.
+ */
+ EXPECT_BEGIN(KERN_INFO, "------------[ cut here ]------------");
+ EXPECT_BEGIN(KERN_INFO, "WARNING: <<all>>");
+ EXPECT_BEGIN(KERN_INFO, "refcount_t: underflow; use-after-free.");
+ EXPECT_BEGIN(KERN_INFO, "---[ end trace <<int>> ]---");
+
+ /* refcount is now zero, this should fail */
+ unittest(1, "/testcase-data/refcount-node is zero");
+ of_node_put(np);
+
+ EXPECT_END(KERN_INFO, "---[ end trace <<int>> ]---");
+ EXPECT_END(KERN_INFO, "refcount_t: underflow; use-after-free.");
+ EXPECT_END(KERN_INFO, "WARNING: <<all>>");
+ EXPECT_END(KERN_INFO, "------------[ cut here ]------------");
+
+ /*
+ * Q. do we expect to get yet another warning?
+ * A. no, the WARNING is from WARN_ONCE()
+ */
+ EXPECT_NOT_BEGIN(KERN_INFO, "------------[ cut here ]------------");
+ EXPECT_NOT_BEGIN(KERN_INFO, "WARNING: <<all>>");
+ EXPECT_NOT_BEGIN(KERN_INFO, "refcount_t: underflow; use-after-free.");
+ EXPECT_NOT_BEGIN(KERN_INFO, "---[ end trace <<int>> ]---");
+
+ unittest(1, "/testcase-data/refcount-node is zero, second time");
+ of_node_put(np);
+
+ EXPECT_NOT_END(KERN_INFO, "---[ end trace <<int>> ]---");
+ EXPECT_NOT_END(KERN_INFO, "refcount_t: underflow; use-after-free.");
+ EXPECT_NOT_END(KERN_INFO, "WARNING: <<all>>");
+ EXPECT_NOT_END(KERN_INFO, "------------[ cut here ]------------");
+
+ /*
+ * refcount of zero will trigger stack traces from any further
+ * attempt to of_node_get() node "refcount-node". One example of
+ * this is where of_unittest_check_node_linkage() will recursively
+ * scan the tree, with 'for_each_child_of_node()' doing an
+ * of_node_get() of the children of a node.
+ *
+ * Prevent the stack trace by removing node "refcount-node" from
+ * its parent's child list.
+ *
+ * WARNING: EVIL, EVIL, EVIL:
+ *
+ * Directly manipulate the child list of node /testcase-data to
+ * remove child refcount-node. This is ignoring all proper methods
+ * of removing a child and will leak a small amount of memory.
+ */
+
+ np = of_find_node_by_path(refcount_parent_path);
+ unittest(np, "find refcount_parent_path \"%s\"\n", refcount_parent_path);
+ unittest(np, "ERROR: devicetree live tree left in a 'bad state' if test fail\n");
+ if (np == NULL)
+ return;
+
+ prev_sibling = np->child;
+ next_sibling = prev_sibling->sibling;
+ if (!strcmp(prev_sibling->full_name, "refcount-node")) {
+ np->child = next_sibling;
+ next_sibling = next_sibling->sibling;
+ }
+ while (next_sibling) {
+ if (!strcmp(next_sibling->full_name, "refcount-node"))
+ prev_sibling->sibling = next_sibling->sibling;
+ prev_sibling = next_sibling;
+ next_sibling = next_sibling->sibling;
+ }
+ of_node_put(np);
+
+ return;
+
+out_skip_tests:
+#endif
+ unittest(0, "One or more lifecycle tests skipped\n");
+}
+
#ifdef CONFIG_OF_OVERLAY
/*
@@ -3502,6 +3647,7 @@ static int __init of_unittest(void)
of_unittest_match_node();
of_unittest_platform_populate();
of_unittest_overlay();
+ of_unittest_lifecycle();
/* Double check linkage after removing testcase data */
of_unittest_check_tree_linkage();
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index 5784dc20fb38..88e125e36230 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -106,15 +106,22 @@ static int pnp_registered_parport;
static void frob_econtrol(struct parport *pb, unsigned char m,
unsigned char v)
{
+ const struct parport_pc_private *priv = pb->physport->private_data;
+ unsigned char ecr_writable = priv->ecr_writable;
unsigned char ectr = 0;
+ unsigned char new;
if (m != 0xff)
ectr = inb(ECONTROL(pb));
- pr_debug("frob_econtrol(%02x,%02x): %02x -> %02x\n",
- m, v, ectr, (ectr & ~m) ^ v);
+ new = (ectr & ~m) ^ v;
+ if (ecr_writable)
+ /* All known users of the ECR mask require bit 0 to be set. */
+ new = (new & ecr_writable) | 1;
- outb((ectr & ~m) ^ v, ECONTROL(pb));
+ pr_debug("frob_econtrol(%02x,%02x): %02x -> %02x\n", m, v, ectr, new);
+
+ outb(new, ECONTROL(pb));
}
static inline void frob_set_mode(struct parport *p, int mode)
@@ -1479,21 +1486,24 @@ static int parport_ECR_present(struct parport *pb)
struct parport_pc_private *priv = pb->private_data;
unsigned char r = 0xc;
- outb(r, CONTROL(pb));
- if ((inb(ECONTROL(pb)) & 0x3) == (r & 0x3)) {
- outb(r ^ 0x2, CONTROL(pb)); /* Toggle bit 1 */
+ if (!priv->ecr_writable) {
+ outb(r, CONTROL(pb));
+ if ((inb(ECONTROL(pb)) & 0x3) == (r & 0x3)) {
+ outb(r ^ 0x2, CONTROL(pb)); /* Toggle bit 1 */
- r = inb(CONTROL(pb));
- if ((inb(ECONTROL(pb)) & 0x2) == (r & 0x2))
- goto no_reg; /* Sure that no ECR register exists */
- }
+ r = inb(CONTROL(pb));
+ if ((inb(ECONTROL(pb)) & 0x2) == (r & 0x2))
+ /* Sure that no ECR register exists */
+ goto no_reg;
+ }
- if ((inb(ECONTROL(pb)) & 0x3) != 0x1)
- goto no_reg;
+ if ((inb(ECONTROL(pb)) & 0x3) != 0x1)
+ goto no_reg;
- ECR_WRITE(pb, 0x34);
- if (inb(ECONTROL(pb)) != 0x35)
- goto no_reg;
+ ECR_WRITE(pb, 0x34);
+ if (inb(ECONTROL(pb)) != 0x35)
+ goto no_reg;
+ }
priv->ecr = 1;
outb(0xc, CONTROL(pb));
@@ -2000,11 +2010,13 @@ static int parport_dma_probe(struct parport *p)
static LIST_HEAD(ports_list);
static DEFINE_SPINLOCK(ports_lock);
-struct parport *parport_pc_probe_port(unsigned long int base,
- unsigned long int base_hi,
- int irq, int dma,
- struct device *dev,
- int irqflags)
+static struct parport *__parport_pc_probe_port(unsigned long int base,
+ unsigned long int base_hi,
+ int irq, int dma,
+ struct device *dev,
+ int irqflags,
+ unsigned int mode_mask,
+ unsigned char ecr_writable)
{
struct parport_pc_private *priv;
struct parport_operations *ops;
@@ -2053,6 +2065,7 @@ struct parport *parport_pc_probe_port(unsigned long int base,
priv->ctr = 0xc;
priv->ctr_writable = ~0x10;
priv->ecr = 0;
+ priv->ecr_writable = ecr_writable;
priv->fifo_depth = 0;
priv->dma_buf = NULL;
priv->dma_handle = 0;
@@ -2116,20 +2129,28 @@ struct parport *parport_pc_probe_port(unsigned long int base,
p->dma != PARPORT_DMA_NOFIFO &&
priv->fifo_depth > 0 && p->irq != PARPORT_IRQ_NONE) {
p->modes |= PARPORT_MODE_ECP | PARPORT_MODE_COMPAT;
+ if (p->dma != PARPORT_DMA_NONE)
+ p->modes |= PARPORT_MODE_DMA;
+ } else
+ /* We can't use the DMA channel after all. */
+ p->dma = PARPORT_DMA_NONE;
+#endif /* Allowed to use FIFO/DMA */
+
+ p->modes &= ~mode_mask;
+
+#ifdef CONFIG_PARPORT_PC_FIFO
+ if ((p->modes & PARPORT_MODE_COMPAT) != 0)
p->ops->compat_write_data = parport_pc_compat_write_block_pio;
#ifdef CONFIG_PARPORT_1284
+ if ((p->modes & PARPORT_MODE_ECP) != 0)
p->ops->ecp_write_data = parport_pc_ecp_write_block_pio;
- /* currently broken, but working on it.. (FB) */
- /* p->ops->ecp_read_data = parport_pc_ecp_read_block_pio; */
-#endif /* IEEE 1284 support */
- if (p->dma != PARPORT_DMA_NONE) {
+#endif
+ if ((p->modes & (PARPORT_MODE_ECP | PARPORT_MODE_COMPAT)) != 0) {
+ if ((p->modes & PARPORT_MODE_DMA) != 0)
pr_cont(", dma %d", p->dma);
- p->modes |= PARPORT_MODE_DMA;
- } else
+ else
pr_cont(", using FIFO");
- } else
- /* We can't use the DMA channel after all. */
- p->dma = PARPORT_DMA_NONE;
+ }
#endif /* Allowed to use FIFO/DMA */
pr_cont(" [");
@@ -2239,6 +2260,16 @@ out1:
platform_device_unregister(pdev);
return NULL;
}
+
+struct parport *parport_pc_probe_port(unsigned long int base,
+ unsigned long int base_hi,
+ int irq, int dma,
+ struct device *dev,
+ int irqflags)
+{
+ return __parport_pc_probe_port(base, base_hi, irq, dma,
+ dev, irqflags, 0, 0);
+}
EXPORT_SYMBOL(parport_pc_probe_port);
void parport_pc_unregister_port(struct parport *p)
@@ -2626,7 +2657,14 @@ static struct parport_pc_pci {
int lo;
int hi;
/* -1 if not there, >6 for offset-method (max BAR is 6) */
- } addr[4];
+ } addr[2];
+
+ /* Bit field of parport modes to exclude. */
+ unsigned int mode_mask;
+
+ /* If non-zero, sets the bitmask of writable ECR bits. In that
+ * case additionally bit 0 will be forcibly set on writes. */
+ unsigned char ecr_writable;
/* If set, this is called immediately after pci_enable_device.
* If it returns non-zero, no probing will take place and the
@@ -2658,12 +2696,19 @@ static struct parport_pc_pci {
/* titan_010l */ { 1, { { 3, -1 }, } },
/* avlab_1p */ { 1, { { 0, 1}, } },
/* avlab_2p */ { 2, { { 0, 1}, { 2, 3 },} },
- /* The Oxford Semi cards are unusual: 954 doesn't support ECP,
- * and 840 locks up if you write 1 to bit 2! */
- /* oxsemi_952 */ { 1, { { 0, 1 }, } },
- /* oxsemi_954 */ { 1, { { 0, -1 }, } },
- /* oxsemi_840 */ { 1, { { 0, 1 }, } },
- /* oxsemi_pcie_pport */ { 1, { { 0, 1 }, } },
+ /* The Oxford Semi cards are unusual: older variants of 954 don't
+ * support ECP, and 840 locks up if you write 1 to bit 2! None
+ * implement nFault or service interrupts and all require 00001
+ * bit pattern to be used for bits 4:0 with ECR writes. */
+ /* oxsemi_952 */ { 1, { { 0, 1 }, },
+ PARPORT_MODE_COMPAT, ECR_MODE_MASK },
+ /* oxsemi_954 */ { 1, { { 0, 1 }, },
+ PARPORT_MODE_ECP |
+ PARPORT_MODE_COMPAT, ECR_MODE_MASK },
+ /* oxsemi_840 */ { 1, { { 0, 1 }, },
+ PARPORT_MODE_COMPAT, ECR_MODE_MASK },
+ /* oxsemi_pcie_pport */ { 1, { { 0, 1 }, },
+ PARPORT_MODE_COMPAT, ECR_MODE_MASK },
/* aks_0100 */ { 1, { { 0, -1 }, } },
/* mobility_pp */ { 1, { { 0, 1 }, } },
/* netmos_9900 */ { 1, { { 0, -1 }, } },
@@ -2831,9 +2876,11 @@ static int parport_pc_pci_probe(struct pci_dev *dev,
id->vendor, id->device, io_lo, io_hi, irq);
}
data->ports[count] =
- parport_pc_probe_port(io_lo, io_hi, irq,
- PARPORT_DMA_NONE, &dev->dev,
- IRQF_SHARED);
+ __parport_pc_probe_port(io_lo, io_hi, irq,
+ PARPORT_DMA_NONE, &dev->dev,
+ IRQF_SHARED,
+ cards[i].mode_mask,
+ cards[i].ecr_writable);
if (data->ports[count])
count++;
}
diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
index b09cdc59bfd0..42654035654a 100644
--- a/drivers/pci/controller/Kconfig
+++ b/drivers/pci/controller/Kconfig
@@ -9,6 +9,7 @@ config PCI_MVEBU
depends on MVEBU_MBUS
depends on ARM
depends on OF
+ depends on BROKEN
select PCI_BRIDGE_EMUL
help
Add support for Marvell EBU PCIe controller. This PCIe controller
@@ -285,7 +286,7 @@ config PCIE_BRCMSTB
config PCI_HYPERV_INTERFACE
tristate "Hyper-V PCI Interface"
- depends on ((X86 && X86_64) || ARM64) && HYPERV && PCI_MSI && PCI_MSI
+ depends on ((X86 && X86_64) || ARM64) && HYPERV && PCI_MSI
help
The Hyper-V PCI Interface is a helper driver allows other drivers to
have a common interface with the Hyper-V PCI frontend driver.
diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig
index 99ec91e2a5cf..434f6a4f4041 100644
--- a/drivers/pci/controller/dwc/Kconfig
+++ b/drivers/pci/controller/dwc/Kconfig
@@ -92,10 +92,31 @@ config PCI_EXYNOS
functions to implement the driver.
config PCI_IMX6
- bool "Freescale i.MX6/7/8 PCIe controller"
+ bool
+
+config PCI_IMX6_HOST
+ bool "Freescale i.MX6/7/8 PCIe controller host mode"
depends on ARCH_MXC || COMPILE_TEST
depends on PCI_MSI
select PCIE_DW_HOST
+ select PCI_IMX6
+ help
+ Enables support for the PCIe controller in the i.MX SoCs to
+ work in Root Complex mode. The PCI controller on i.MX is based
+ on DesignWare hardware and therefore the driver re-uses the
+ DesignWare core functions to implement the driver.
+
+config PCI_IMX6_EP
+ bool "Freescale i.MX6/7/8 PCIe controller endpoint mode"
+ depends on ARCH_MXC || COMPILE_TEST
+ depends on PCI_ENDPOINT
+ select PCIE_DW_EP
+ select PCI_IMX6
+ help
+ Enables support for the PCIe controller in the i.MX SoCs to
+ work in endpoint mode. The PCI controller on i.MX is based
+ on DesignWare hardware and therefore the driver re-uses the
+ DesignWare core functions to implement the driver.
config PCIE_SPEAR13XX
bool "STMicroelectronics SPEAr PCIe controller"
diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c
index 38462ed11d07..4ae807e7cf79 100644
--- a/drivers/pci/controller/dwc/pci-dra7xx.c
+++ b/drivers/pci/controller/dwc/pci-dra7xx.c
@@ -840,7 +840,7 @@ static int dra7xx_pcie_probe(struct platform_device *pdev)
}
dra7xx->mode = mode;
- ret = devm_request_irq(dev, irq, dra7xx_pcie_irq_handler,
+ ret = devm_request_threaded_irq(dev, irq, NULL, dra7xx_pcie_irq_handler,
IRQF_SHARED, "dra7xx-pcie-main", dra7xx);
if (ret) {
dev_err(dev, "failed to request irq\n");
diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c
index 1dde5c579edc..55a0405b921d 100644
--- a/drivers/pci/controller/dwc/pci-imx6.c
+++ b/drivers/pci/controller/dwc/pci-imx6.c
@@ -52,6 +52,9 @@ enum imx6_pcie_variants {
IMX8MQ,
IMX8MM,
IMX8MP,
+ IMX8MQ_EP,
+ IMX8MM_EP,
+ IMX8MP_EP,
};
#define IMX6_PCIE_FLAG_IMX6_PHY BIT(0)
@@ -60,6 +63,7 @@ enum imx6_pcie_variants {
struct imx6_pcie_drvdata {
enum imx6_pcie_variants variant;
+ enum dw_pcie_device_mode mode;
u32 flags;
int dbi_length;
const char *gpr;
@@ -152,24 +156,39 @@ struct imx6_pcie {
static unsigned int imx6_pcie_grp_offset(const struct imx6_pcie *imx6_pcie)
{
WARN_ON(imx6_pcie->drvdata->variant != IMX8MQ &&
+ imx6_pcie->drvdata->variant != IMX8MQ_EP &&
imx6_pcie->drvdata->variant != IMX8MM &&
- imx6_pcie->drvdata->variant != IMX8MP);
+ imx6_pcie->drvdata->variant != IMX8MM_EP &&
+ imx6_pcie->drvdata->variant != IMX8MP &&
+ imx6_pcie->drvdata->variant != IMX8MP_EP);
return imx6_pcie->controller_id == 1 ? IOMUXC_GPR16 : IOMUXC_GPR14;
}
static void imx6_pcie_configure_type(struct imx6_pcie *imx6_pcie)
{
- unsigned int mask, val;
+ unsigned int mask, val, mode;
- if (imx6_pcie->drvdata->variant == IMX8MQ &&
- imx6_pcie->controller_id == 1) {
- mask = IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE;
- val = FIELD_PREP(IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE,
- PCI_EXP_TYPE_ROOT_PORT);
- } else {
+ if (imx6_pcie->drvdata->mode == DW_PCIE_EP_TYPE)
+ mode = PCI_EXP_TYPE_ENDPOINT;
+ else
+ mode = PCI_EXP_TYPE_ROOT_PORT;
+
+ switch (imx6_pcie->drvdata->variant) {
+ case IMX8MQ:
+ case IMX8MQ_EP:
+ if (imx6_pcie->controller_id == 1) {
+ mask = IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE;
+ val = FIELD_PREP(IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE,
+ mode);
+ } else {
+ mask = IMX6Q_GPR12_DEVICE_TYPE;
+ val = FIELD_PREP(IMX6Q_GPR12_DEVICE_TYPE, mode);
+ }
+ break;
+ default:
mask = IMX6Q_GPR12_DEVICE_TYPE;
- val = FIELD_PREP(IMX6Q_GPR12_DEVICE_TYPE,
- PCI_EXP_TYPE_ROOT_PORT);
+ val = FIELD_PREP(IMX6Q_GPR12_DEVICE_TYPE, mode);
+ break;
}
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, mask, val);
@@ -304,13 +323,16 @@ static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie)
{
switch (imx6_pcie->drvdata->variant) {
case IMX8MM:
+ case IMX8MM_EP:
case IMX8MP:
+ case IMX8MP_EP:
/*
* The PHY initialization had been done in the PHY
* driver, break here directly.
*/
break;
case IMX8MQ:
+ case IMX8MQ_EP:
/*
* TODO: Currently this code assumes external
* oscillator is being used
@@ -561,8 +583,11 @@ static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie)
case IMX7D:
break;
case IMX8MM:
+ case IMX8MM_EP:
case IMX8MQ:
+ case IMX8MQ_EP:
case IMX8MP:
+ case IMX8MP_EP:
ret = clk_prepare_enable(imx6_pcie->pcie_aux);
if (ret) {
dev_err(dev, "unable to enable pcie_aux clock\n");
@@ -606,8 +631,11 @@ static void imx6_pcie_disable_ref_clk(struct imx6_pcie *imx6_pcie)
IMX7D_GPR12_PCIE_PHY_REFCLK_SEL);
break;
case IMX8MM:
+ case IMX8MM_EP:
case IMX8MQ:
+ case IMX8MQ_EP:
case IMX8MP:
+ case IMX8MP_EP:
clk_disable_unprepare(imx6_pcie->pcie_aux);
break;
default:
@@ -672,10 +700,13 @@ static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie)
switch (imx6_pcie->drvdata->variant) {
case IMX7D:
case IMX8MQ:
+ case IMX8MQ_EP:
reset_control_assert(imx6_pcie->pciephy_reset);
fallthrough;
case IMX8MM:
+ case IMX8MM_EP:
case IMX8MP:
+ case IMX8MP_EP:
reset_control_assert(imx6_pcie->apps_reset);
break;
case IMX6SX:
@@ -713,6 +744,7 @@ static int imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie)
switch (imx6_pcie->drvdata->variant) {
case IMX8MQ:
+ case IMX8MQ_EP:
reset_control_deassert(imx6_pcie->pciephy_reset);
break;
case IMX7D:
@@ -751,7 +783,9 @@ static int imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie)
break;
case IMX6Q: /* Nothing to do */
case IMX8MM:
+ case IMX8MM_EP:
case IMX8MP:
+ case IMX8MP_EP:
break;
}
@@ -800,8 +834,11 @@ static void imx6_pcie_ltssm_enable(struct device *dev)
break;
case IMX7D:
case IMX8MQ:
+ case IMX8MQ_EP:
case IMX8MM:
+ case IMX8MM_EP:
case IMX8MP:
+ case IMX8MP_EP:
reset_control_deassert(imx6_pcie->apps_reset);
break;
}
@@ -820,8 +857,11 @@ static void imx6_pcie_ltssm_disable(struct device *dev)
break;
case IMX7D:
case IMX8MQ:
+ case IMX8MQ_EP:
case IMX8MM:
+ case IMX8MM_EP:
case IMX8MP:
+ case IMX8MP_EP:
reset_control_assert(imx6_pcie->apps_reset);
break;
}
@@ -1003,8 +1043,104 @@ static const struct dw_pcie_host_ops imx6_pcie_host_ops = {
static const struct dw_pcie_ops dw_pcie_ops = {
.start_link = imx6_pcie_start_link,
+ .stop_link = imx6_pcie_stop_link,
+};
+
+static void imx6_pcie_ep_init(struct dw_pcie_ep *ep)
+{
+ enum pci_barno bar;
+ struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+
+ for (bar = BAR_0; bar <= BAR_5; bar++)
+ dw_pcie_ep_reset_bar(pci, bar);
+}
+
+static int imx6_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
+ enum pci_epc_irq_type type,
+ u16 interrupt_num)
+{
+ struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+
+ switch (type) {
+ case PCI_EPC_IRQ_LEGACY:
+ return dw_pcie_ep_raise_legacy_irq(ep, func_no);
+ case PCI_EPC_IRQ_MSI:
+ return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num);
+ case PCI_EPC_IRQ_MSIX:
+ return dw_pcie_ep_raise_msix_irq(ep, func_no, interrupt_num);
+ default:
+ dev_err(pci->dev, "UNKNOWN IRQ type\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct pci_epc_features imx8m_pcie_epc_features = {
+ .linkup_notifier = false,
+ .msi_capable = true,
+ .msix_capable = false,
+ .reserved_bar = 1 << BAR_1 | 1 << BAR_3,
+ .align = SZ_64K,
+};
+
+static const struct pci_epc_features*
+imx6_pcie_ep_get_features(struct dw_pcie_ep *ep)
+{
+ return &imx8m_pcie_epc_features;
+}
+
+static const struct dw_pcie_ep_ops pcie_ep_ops = {
+ .ep_init = imx6_pcie_ep_init,
+ .raise_irq = imx6_pcie_ep_raise_irq,
+ .get_features = imx6_pcie_ep_get_features,
};
+static int imx6_add_pcie_ep(struct imx6_pcie *imx6_pcie,
+ struct platform_device *pdev)
+{
+ int ret;
+ unsigned int pcie_dbi2_offset;
+ struct dw_pcie_ep *ep;
+ struct resource *res;
+ struct dw_pcie *pci = imx6_pcie->pci;
+ struct dw_pcie_rp *pp = &pci->pp;
+ struct device *dev = pci->dev;
+
+ imx6_pcie_host_init(pp);
+ ep = &pci->ep;
+ ep->ops = &pcie_ep_ops;
+
+ switch (imx6_pcie->drvdata->variant) {
+ case IMX8MQ_EP:
+ case IMX8MM_EP:
+ case IMX8MP_EP:
+ pcie_dbi2_offset = SZ_1M;
+ break;
+ default:
+ pcie_dbi2_offset = SZ_4K;
+ break;
+ }
+ pci->dbi_base2 = pci->dbi_base + pcie_dbi2_offset;
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
+ if (!res)
+ return -EINVAL;
+
+ ep->phys_base = res->start;
+ ep->addr_size = resource_size(res);
+ ep->page_size = SZ_64K;
+
+ ret = dw_pcie_ep_init(ep);
+ if (ret) {
+ dev_err(dev, "failed to initialize endpoint\n");
+ return ret;
+ }
+ /* Start LTSSM. */
+ imx6_pcie_ltssm_enable(dev);
+
+ return 0;
+}
+
static void imx6_pcie_pm_turnoff(struct imx6_pcie *imx6_pcie)
{
struct device *dev = imx6_pcie->pci->dev;
@@ -1166,6 +1302,7 @@ static int imx6_pcie_probe(struct platform_device *pdev)
"pcie_inbound_axi clock missing or invalid\n");
break;
case IMX8MQ:
+ case IMX8MQ_EP:
imx6_pcie->pcie_aux = devm_clk_get(dev, "pcie_aux");
if (IS_ERR(imx6_pcie->pcie_aux))
return dev_err_probe(dev, PTR_ERR(imx6_pcie->pcie_aux),
@@ -1190,7 +1327,9 @@ static int imx6_pcie_probe(struct platform_device *pdev)
}
break;
case IMX8MM:
+ case IMX8MM_EP:
case IMX8MP:
+ case IMX8MP_EP:
imx6_pcie->pcie_aux = devm_clk_get(dev, "pcie_aux");
if (IS_ERR(imx6_pcie->pcie_aux))
return dev_err_probe(dev, PTR_ERR(imx6_pcie->pcie_aux),
@@ -1279,15 +1418,22 @@ static int imx6_pcie_probe(struct platform_device *pdev)
if (ret)
return ret;
- ret = dw_pcie_host_init(&pci->pp);
- if (ret < 0)
- return ret;
+ if (imx6_pcie->drvdata->mode == DW_PCIE_EP_TYPE) {
+ ret = imx6_add_pcie_ep(imx6_pcie, pdev);
+ if (ret < 0)
+ return ret;
+ } else {
+ ret = dw_pcie_host_init(&pci->pp);
+ if (ret < 0)
+ return ret;
+
+ if (pci_msi_enabled()) {
+ u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_MSI);
- if (pci_msi_enabled()) {
- u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_MSI);
- val = dw_pcie_readw_dbi(pci, offset + PCI_MSI_FLAGS);
- val |= PCI_MSI_FLAGS_ENABLE;
- dw_pcie_writew_dbi(pci, offset + PCI_MSI_FLAGS, val);
+ val = dw_pcie_readw_dbi(pci, offset + PCI_MSI_FLAGS);
+ val |= PCI_MSI_FLAGS_ENABLE;
+ dw_pcie_writew_dbi(pci, offset + PCI_MSI_FLAGS, val);
+ }
}
return 0;
@@ -1343,6 +1489,21 @@ static const struct imx6_pcie_drvdata drvdata[] = {
.flags = IMX6_PCIE_FLAG_SUPPORTS_SUSPEND,
.gpr = "fsl,imx8mp-iomuxc-gpr",
},
+ [IMX8MQ_EP] = {
+ .variant = IMX8MQ_EP,
+ .mode = DW_PCIE_EP_TYPE,
+ .gpr = "fsl,imx8mq-iomuxc-gpr",
+ },
+ [IMX8MM_EP] = {
+ .variant = IMX8MM_EP,
+ .mode = DW_PCIE_EP_TYPE,
+ .gpr = "fsl,imx8mm-iomuxc-gpr",
+ },
+ [IMX8MP_EP] = {
+ .variant = IMX8MP_EP,
+ .mode = DW_PCIE_EP_TYPE,
+ .gpr = "fsl,imx8mp-iomuxc-gpr",
+ },
};
static const struct of_device_id imx6_pcie_of_match[] = {
@@ -1353,6 +1514,9 @@ static const struct of_device_id imx6_pcie_of_match[] = {
{ .compatible = "fsl,imx8mq-pcie", .data = &drvdata[IMX8MQ], },
{ .compatible = "fsl,imx8mm-pcie", .data = &drvdata[IMX8MM], },
{ .compatible = "fsl,imx8mp-pcie", .data = &drvdata[IMX8MP], },
+ { .compatible = "fsl,imx8mq-pcie-ep", .data = &drvdata[IMX8MQ_EP], },
+ { .compatible = "fsl,imx8mm-pcie-ep", .data = &drvdata[IMX8MM_EP], },
+ { .compatible = "fsl,imx8mp-pcie-ep", .data = &drvdata[IMX8MP_EP], },
{},
};
diff --git a/drivers/pci/controller/dwc/pcie-bt1.c b/drivers/pci/controller/dwc/pcie-bt1.c
index 3346770e6654..95a723a6fd46 100644
--- a/drivers/pci/controller/dwc/pcie-bt1.c
+++ b/drivers/pci/controller/dwc/pcie-bt1.c
@@ -583,6 +583,10 @@ static int bt1_pcie_add_port(struct bt1_pcie *btpci)
struct device *dev = &btpci->pdev->dev;
int ret;
+ ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
+ if (ret)
+ return ret;
+
btpci->dw.version = DW_PCIE_VER_460A;
btpci->dw.dev = dev;
btpci->dw.ops = &bt1_pcie_ops;
diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
index d06654895eba..f9182f8d552f 100644
--- a/drivers/pci/controller/dwc/pcie-designware-ep.c
+++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
@@ -612,8 +612,11 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
void dw_pcie_ep_exit(struct dw_pcie_ep *ep)
{
+ struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
struct pci_epc *epc = ep->epc;
+ dw_pcie_edma_remove(pci);
+
pci_epc_mem_free_addr(epc, ep->msi_mem_phys, ep->msi_mem,
epc->mem->window.page_size);
@@ -785,6 +788,10 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
goto err_exit_epc_mem;
}
+ ret = dw_pcie_edma_detect(pci);
+ if (ret)
+ goto err_free_epc_mem;
+
if (ep->ops->get_features) {
epc_features = ep->ops->get_features(ep);
if (epc_features->core_init_notifier)
@@ -793,10 +800,13 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
ret = dw_pcie_ep_init_complete(ep);
if (ret)
- goto err_free_epc_mem;
+ goto err_remove_edma;
return 0;
+err_remove_edma:
+ dw_pcie_edma_remove(pci);
+
err_free_epc_mem:
pci_epc_mem_free_addr(epc, ep->msi_mem_phys, ep->msi_mem,
epc->mem->window.page_size);
diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index 3ab6ae3712c4..9952057c8819 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -366,7 +366,17 @@ static int dw_pcie_msi_host_init(struct dw_pcie_rp *pp)
dw_chained_msi_isr, pp);
}
- ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
+ /*
+ * Even though the iMSI-RX Module supports 64-bit addresses some
+ * peripheral PCIe devices may lack 64-bit message support. In
+ * order not to miss MSI TLPs from those devices the MSI target
+ * address has to be within the lowest 4GB.
+ *
+ * Note until there is a better alternative found the reservation is
+ * done by allocating from the artificially limited DMA-coherent
+ * memory.
+ */
+ ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
if (ret)
dev_warn(dev, "Failed to set DMA mask to 32-bit. Devices with only 32-bit MSI support may not work properly\n");
@@ -467,14 +477,18 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp)
dw_pcie_iatu_detect(pci);
- ret = dw_pcie_setup_rc(pp);
+ ret = dw_pcie_edma_detect(pci);
if (ret)
goto err_free_msi;
+ ret = dw_pcie_setup_rc(pp);
+ if (ret)
+ goto err_remove_edma;
+
if (!dw_pcie_link_up(pci)) {
ret = dw_pcie_start_link(pci);
if (ret)
- goto err_free_msi;
+ goto err_remove_edma;
}
/* Ignore errors, the link may come up later */
@@ -491,6 +505,9 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp)
err_stop_link:
dw_pcie_stop_link(pci);
+err_remove_edma:
+ dw_pcie_edma_remove(pci);
+
err_free_msi:
if (pp->has_msi_ctrl)
dw_pcie_free_msi(pp);
@@ -512,6 +529,8 @@ void dw_pcie_host_deinit(struct dw_pcie_rp *pp)
dw_pcie_stop_link(pci);
+ dw_pcie_edma_remove(pci);
+
if (pp->has_msi_ctrl)
dw_pcie_free_msi(pp);
diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
index 6d5d619ab2e9..53a16b8b6ac2 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -12,6 +12,7 @@
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/dma/edma.h>
#include <linux/gpio/consumer.h>
#include <linux/ioport.h>
#include <linux/of.h>
@@ -142,6 +143,18 @@ int dw_pcie_get_resources(struct dw_pcie *pci)
if (!pci->atu_size)
pci->atu_size = SZ_4K;
+ /* eDMA region can be mapped to a custom base address */
+ if (!pci->edma.reg_base) {
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma");
+ if (res) {
+ pci->edma.reg_base = devm_ioremap_resource(pci->dev, res);
+ if (IS_ERR(pci->edma.reg_base))
+ return PTR_ERR(pci->edma.reg_base);
+ } else if (pci->atu_size >= 2 * DEFAULT_DBI_DMA_OFFSET) {
+ pci->edma.reg_base = pci->atu_base + DEFAULT_DBI_DMA_OFFSET;
+ }
+ }
+
/* LLDD is supposed to manually switch the clocks and resets state */
if (dw_pcie_cap_is(pci, REQ_RES)) {
ret = dw_pcie_get_clocks(pci);
@@ -782,6 +795,188 @@ void dw_pcie_iatu_detect(struct dw_pcie *pci)
pci->region_align / SZ_1K, (pci->region_limit + 1) / SZ_1G);
}
+static u32 dw_pcie_readl_dma(struct dw_pcie *pci, u32 reg)
+{
+ u32 val = 0;
+ int ret;
+
+ if (pci->ops && pci->ops->read_dbi)
+ return pci->ops->read_dbi(pci, pci->edma.reg_base, reg, 4);
+
+ ret = dw_pcie_read(pci->edma.reg_base + reg, 4, &val);
+ if (ret)
+ dev_err(pci->dev, "Read DMA address failed\n");
+
+ return val;
+}
+
+static int dw_pcie_edma_irq_vector(struct device *dev, unsigned int nr)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ char name[6];
+ int ret;
+
+ if (nr >= EDMA_MAX_WR_CH + EDMA_MAX_RD_CH)
+ return -EINVAL;
+
+ ret = platform_get_irq_byname_optional(pdev, "dma");
+ if (ret > 0)
+ return ret;
+
+ snprintf(name, sizeof(name), "dma%u", nr);
+
+ return platform_get_irq_byname_optional(pdev, name);
+}
+
+static struct dw_edma_core_ops dw_pcie_edma_ops = {
+ .irq_vector = dw_pcie_edma_irq_vector,
+};
+
+static int dw_pcie_edma_find_chip(struct dw_pcie *pci)
+{
+ u32 val;
+
+ /*
+ * Indirect eDMA CSRs access has been completely removed since v5.40a
+ * thus no space is now reserved for the eDMA channels viewport and
+ * former DMA CTRL register is no longer fixed to FFs.
+ */
+ if (dw_pcie_ver_is_ge(pci, 540A))
+ val = 0xFFFFFFFF;
+ else
+ val = dw_pcie_readl_dbi(pci, PCIE_DMA_VIEWPORT_BASE + PCIE_DMA_CTRL);
+
+ if (val == 0xFFFFFFFF && pci->edma.reg_base) {
+ pci->edma.mf = EDMA_MF_EDMA_UNROLL;
+
+ val = dw_pcie_readl_dma(pci, PCIE_DMA_CTRL);
+ } else if (val != 0xFFFFFFFF) {
+ pci->edma.mf = EDMA_MF_EDMA_LEGACY;
+
+ pci->edma.reg_base = pci->dbi_base + PCIE_DMA_VIEWPORT_BASE;
+ } else {
+ return -ENODEV;
+ }
+
+ pci->edma.dev = pci->dev;
+
+ if (!pci->edma.ops)
+ pci->edma.ops = &dw_pcie_edma_ops;
+
+ pci->edma.flags |= DW_EDMA_CHIP_LOCAL;
+
+ pci->edma.ll_wr_cnt = FIELD_GET(PCIE_DMA_NUM_WR_CHAN, val);
+ pci->edma.ll_rd_cnt = FIELD_GET(PCIE_DMA_NUM_RD_CHAN, val);
+
+ /* Sanity check the channels count if the mapping was incorrect */
+ if (!pci->edma.ll_wr_cnt || pci->edma.ll_wr_cnt > EDMA_MAX_WR_CH ||
+ !pci->edma.ll_rd_cnt || pci->edma.ll_rd_cnt > EDMA_MAX_RD_CH)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int dw_pcie_edma_irq_verify(struct dw_pcie *pci)
+{
+ struct platform_device *pdev = to_platform_device(pci->dev);
+ u16 ch_cnt = pci->edma.ll_wr_cnt + pci->edma.ll_rd_cnt;
+ char name[6];
+ int ret;
+
+ if (pci->edma.nr_irqs == 1)
+ return 0;
+ else if (pci->edma.nr_irqs > 1)
+ return pci->edma.nr_irqs != ch_cnt ? -EINVAL : 0;
+
+ ret = platform_get_irq_byname_optional(pdev, "dma");
+ if (ret > 0) {
+ pci->edma.nr_irqs = 1;
+ return 0;
+ }
+
+ for (; pci->edma.nr_irqs < ch_cnt; pci->edma.nr_irqs++) {
+ snprintf(name, sizeof(name), "dma%d", pci->edma.nr_irqs);
+
+ ret = platform_get_irq_byname_optional(pdev, name);
+ if (ret <= 0)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int dw_pcie_edma_ll_alloc(struct dw_pcie *pci)
+{
+ struct dw_edma_region *ll;
+ dma_addr_t paddr;
+ int i;
+
+ for (i = 0; i < pci->edma.ll_wr_cnt; i++) {
+ ll = &pci->edma.ll_region_wr[i];
+ ll->sz = DMA_LLP_MEM_SIZE;
+ ll->vaddr.mem = dmam_alloc_coherent(pci->dev, ll->sz,
+ &paddr, GFP_KERNEL);
+ if (!ll->vaddr.mem)
+ return -ENOMEM;
+
+ ll->paddr = paddr;
+ }
+
+ for (i = 0; i < pci->edma.ll_rd_cnt; i++) {
+ ll = &pci->edma.ll_region_rd[i];
+ ll->sz = DMA_LLP_MEM_SIZE;
+ ll->vaddr.mem = dmam_alloc_coherent(pci->dev, ll->sz,
+ &paddr, GFP_KERNEL);
+ if (!ll->vaddr.mem)
+ return -ENOMEM;
+
+ ll->paddr = paddr;
+ }
+
+ return 0;
+}
+
+int dw_pcie_edma_detect(struct dw_pcie *pci)
+{
+ int ret;
+
+ /* Don't fail if no eDMA was found (for the backward compatibility) */
+ ret = dw_pcie_edma_find_chip(pci);
+ if (ret)
+ return 0;
+
+ /* Don't fail on the IRQs verification (for the backward compatibility) */
+ ret = dw_pcie_edma_irq_verify(pci);
+ if (ret) {
+ dev_err(pci->dev, "Invalid eDMA IRQs found\n");
+ return 0;
+ }
+
+ ret = dw_pcie_edma_ll_alloc(pci);
+ if (ret) {
+ dev_err(pci->dev, "Couldn't allocate LLP memory\n");
+ return ret;
+ }
+
+ /* Don't fail if the DW eDMA driver can't find the device */
+ ret = dw_edma_probe(&pci->edma);
+ if (ret && ret != -ENODEV) {
+ dev_err(pci->dev, "Couldn't register eDMA device\n");
+ return ret;
+ }
+
+ dev_info(pci->dev, "eDMA: unroll %s, %hu wr, %hu rd\n",
+ pci->edma.mf == EDMA_MF_EDMA_UNROLL ? "T" : "F",
+ pci->edma.ll_wr_cnt, pci->edma.ll_rd_cnt);
+
+ return 0;
+}
+
+void dw_pcie_edma_remove(struct dw_pcie *pci)
+{
+ dw_edma_remove(&pci->edma);
+}
+
void dw_pcie_setup(struct dw_pcie *pci)
{
u32 val;
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index 393dfb931df6..79713ce075cc 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -15,6 +15,7 @@
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
+#include <linux/dma/edma.h>
#include <linux/gpio/consumer.h>
#include <linux/irq.h>
#include <linux/msi.h>
@@ -31,6 +32,7 @@
#define DW_PCIE_VER_480A 0x3438302a
#define DW_PCIE_VER_490A 0x3439302a
#define DW_PCIE_VER_520A 0x3532302a
+#define DW_PCIE_VER_540A 0x3534302a
#define __dw_pcie_ver_cmp(_pci, _ver, _op) \
((_pci)->version _op DW_PCIE_VER_ ## _ver)
@@ -167,6 +169,18 @@
#define PCIE_MSIX_DOORBELL 0x948
#define PCIE_MSIX_DOORBELL_PF_SHIFT 24
+/*
+ * eDMA CSRs. DW PCIe IP-core v4.70a and older had the eDMA registers accessible
+ * over the Port Logic registers space. Afterwards the unrolled mapping was
+ * introduced so eDMA and iATU could be accessed via a dedicated registers
+ * space.
+ */
+#define PCIE_DMA_VIEWPORT_BASE 0x970
+#define PCIE_DMA_UNROLL_BASE 0x80000
+#define PCIE_DMA_CTRL 0x008
+#define PCIE_DMA_NUM_WR_CHAN GENMASK(3, 0)
+#define PCIE_DMA_NUM_RD_CHAN GENMASK(19, 16)
+
#define PCIE_PL_CHK_REG_CONTROL_STATUS 0xB20
#define PCIE_PL_CHK_REG_CHK_REG_START BIT(0)
#define PCIE_PL_CHK_REG_CHK_REG_CONTINUOUS BIT(1)
@@ -215,6 +229,7 @@
* this offset, if atu_base not set.
*/
#define DEFAULT_DBI_ATU_OFFSET (0x3 << 20)
+#define DEFAULT_DBI_DMA_OFFSET PCIE_DMA_UNROLL_BASE
#define MAX_MSI_IRQS 256
#define MAX_MSI_IRQS_PER_CTRL 32
@@ -226,6 +241,9 @@
#define MAX_IATU_IN 256
#define MAX_IATU_OUT 256
+/* Default eDMA LLP memory size */
+#define DMA_LLP_MEM_SIZE PAGE_SIZE
+
struct dw_pcie;
struct dw_pcie_rp;
struct dw_pcie_ep;
@@ -369,6 +387,7 @@ struct dw_pcie {
int num_lanes;
int link_gen;
u8 n_fts[2];
+ struct dw_edma_chip edma;
struct clk_bulk_data app_clks[DW_PCIE_NUM_APP_CLKS];
struct clk_bulk_data core_clks[DW_PCIE_NUM_CORE_CLKS];
struct reset_control_bulk_data app_rsts[DW_PCIE_NUM_APP_RSTS];
@@ -408,6 +427,8 @@ int dw_pcie_prog_ep_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
void dw_pcie_disable_atu(struct dw_pcie *pci, u32 dir, int index);
void dw_pcie_setup(struct dw_pcie *pci);
void dw_pcie_iatu_detect(struct dw_pcie *pci);
+int dw_pcie_edma_detect(struct dw_pcie *pci);
+void dw_pcie_edma_remove(struct dw_pcie *pci);
static inline void dw_pcie_writel_dbi(struct dw_pcie *pci, u32 reg, u32 val)
{
diff --git a/drivers/pci/controller/dwc/pcie-histb.c b/drivers/pci/controller/dwc/pcie-histb.c
index 43c27812dd6d..927ae05dc920 100644
--- a/drivers/pci/controller/dwc/pcie-histb.c
+++ b/drivers/pci/controller/dwc/pcie-histb.c
@@ -450,4 +450,3 @@ static struct platform_driver histb_pcie_platform_driver = {
module_platform_driver(histb_pcie_platform_driver);
MODULE_DESCRIPTION("HiSilicon STB PCIe host controller driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
index 77e5dc7b88ad..a232b04af048 100644
--- a/drivers/pci/controller/dwc/pcie-qcom.c
+++ b/drivers/pci/controller/dwc/pcie-qcom.c
@@ -1534,8 +1534,19 @@ err_deinit:
return ret;
}
+static void qcom_pcie_host_deinit(struct dw_pcie_rp *pp)
+{
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct qcom_pcie *pcie = to_qcom_pcie(pci);
+
+ qcom_ep_reset_assert(pcie);
+ phy_power_off(pcie->phy);
+ pcie->cfg->ops->deinit(pcie);
+}
+
static const struct dw_pcie_host_ops qcom_pcie_dw_ops = {
- .host_init = qcom_pcie_host_init,
+ .host_init = qcom_pcie_host_init,
+ .host_deinit = qcom_pcie_host_deinit,
};
/* Qcom IP rev.: 2.1.0 Synopsys IP rev.: 4.01a */
@@ -1817,6 +1828,7 @@ static const struct of_device_id qcom_pcie_match[] = {
{ .compatible = "qcom,pcie-ipq8064", .data = &cfg_2_1_0 },
{ .compatible = "qcom,pcie-ipq8064-v2", .data = &cfg_2_1_0 },
{ .compatible = "qcom,pcie-ipq8074", .data = &cfg_2_3_3 },
+ { .compatible = "qcom,pcie-ipq8074-gen3", .data = &cfg_2_9_0 },
{ .compatible = "qcom,pcie-msm8996", .data = &cfg_2_3_2 },
{ .compatible = "qcom,pcie-qcs404", .data = &cfg_2_4_0 },
{ .compatible = "qcom,pcie-sa8540p", .data = &cfg_1_9_0 },
@@ -1826,6 +1838,7 @@ static const struct of_device_id qcom_pcie_match[] = {
{ .compatible = "qcom,pcie-sdm845", .data = &cfg_2_7_0 },
{ .compatible = "qcom,pcie-sm8150", .data = &cfg_1_9_0 },
{ .compatible = "qcom,pcie-sm8250", .data = &cfg_1_9_0 },
+ { .compatible = "qcom,pcie-sm8350", .data = &cfg_1_9_0 },
{ .compatible = "qcom,pcie-sm8450-pcie0", .data = &cfg_1_9_0 },
{ .compatible = "qcom,pcie-sm8450-pcie1", .data = &cfg_1_9_0 },
{ }
diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
index 02d78a12b6e7..09825b4a075e 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -286,6 +286,7 @@ struct tegra_pcie_dw {
struct gpio_desc *pex_refclk_sel_gpiod;
unsigned int pex_rst_irq;
int ep_state;
+ long link_status;
};
static inline struct tegra_pcie_dw *to_tegra_pcie(struct dw_pcie *pci)
@@ -449,9 +450,13 @@ static void pex_ep_event_hot_rst_done(struct tegra_pcie_dw *pcie)
static irqreturn_t tegra_pcie_ep_irq_thread(int irq, void *arg)
{
struct tegra_pcie_dw *pcie = arg;
+ struct dw_pcie_ep *ep = &pcie->pci.ep;
struct dw_pcie *pci = &pcie->pci;
u32 val, speed;
+ if (test_and_clear_bit(0, &pcie->link_status))
+ dw_pcie_ep_linkup(ep);
+
speed = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKSTA) &
PCI_EXP_LNKSTA_CLS;
clk_set_rate(pcie->core_clk, pcie_gen_freq[speed - 1]);
@@ -498,7 +503,6 @@ static irqreturn_t tegra_pcie_ep_irq_thread(int irq, void *arg)
static irqreturn_t tegra_pcie_ep_hard_irq(int irq, void *arg)
{
struct tegra_pcie_dw *pcie = arg;
- struct dw_pcie_ep *ep = &pcie->pci.ep;
int spurious = 1;
u32 status_l0, status_l1, link_status;
@@ -514,7 +518,8 @@ static irqreturn_t tegra_pcie_ep_hard_irq(int irq, void *arg)
link_status = appl_readl(pcie, APPL_LINK_STATUS);
if (link_status & APPL_LINK_STATUS_RDLH_LINK_UP) {
dev_dbg(pcie->dev, "Link is up with Host\n");
- dw_pcie_ep_linkup(ep);
+ set_bit(0, &pcie->link_status);
+ return IRQ_WAKE_THREAD;
}
}
diff --git a/drivers/pci/controller/mobiveil/pcie-mobiveil-plat.c b/drivers/pci/controller/mobiveil/pcie-mobiveil-plat.c
index f6fcd95c2bf5..c5bb87ff6d9a 100644
--- a/drivers/pci/controller/mobiveil/pcie-mobiveil-plat.c
+++ b/drivers/pci/controller/mobiveil/pcie-mobiveil-plat.c
@@ -56,6 +56,5 @@ static struct platform_driver mobiveil_pcie_driver = {
builtin_platform_driver(mobiveil_pcie_driver);
-MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Mobiveil PCIe host controller driver");
MODULE_AUTHOR("Subrahmanya Lingappa <l.subrahmanya@mobiveil.co.in>");
diff --git a/drivers/pci/controller/pci-loongson.c b/drivers/pci/controller/pci-loongson.c
index 05c50408f13b..fe0f732f6e43 100644
--- a/drivers/pci/controller/pci-loongson.c
+++ b/drivers/pci/controller/pci-loongson.c
@@ -15,9 +15,14 @@
#include "../pci.h"
/* Device IDs */
-#define DEV_PCIE_PORT_0 0x7a09
-#define DEV_PCIE_PORT_1 0x7a19
-#define DEV_PCIE_PORT_2 0x7a29
+#define DEV_LS2K_PCIE_PORT0 0x1a05
+#define DEV_LS7A_PCIE_PORT0 0x7a09
+#define DEV_LS7A_PCIE_PORT1 0x7a19
+#define DEV_LS7A_PCIE_PORT2 0x7a29
+#define DEV_LS7A_PCIE_PORT3 0x7a39
+#define DEV_LS7A_PCIE_PORT4 0x7a49
+#define DEV_LS7A_PCIE_PORT5 0x7a59
+#define DEV_LS7A_PCIE_PORT6 0x7a69
#define DEV_LS2K_APB 0x7a02
#define DEV_LS7A_GMAC 0x7a03
@@ -53,11 +58,11 @@ static void bridge_class_quirk(struct pci_dev *dev)
dev->class = PCI_CLASS_BRIDGE_PCI_NORMAL;
}
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
- DEV_PCIE_PORT_0, bridge_class_quirk);
+ DEV_LS7A_PCIE_PORT0, bridge_class_quirk);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
- DEV_PCIE_PORT_1, bridge_class_quirk);
+ DEV_LS7A_PCIE_PORT1, bridge_class_quirk);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
- DEV_PCIE_PORT_2, bridge_class_quirk);
+ DEV_LS7A_PCIE_PORT2, bridge_class_quirk);
static void system_bus_quirk(struct pci_dev *pdev)
{
@@ -75,37 +80,33 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
DEV_LS7A_LPC, system_bus_quirk);
-static void loongson_mrrs_quirk(struct pci_dev *dev)
+static void loongson_mrrs_quirk(struct pci_dev *pdev)
{
- struct pci_bus *bus = dev->bus;
- struct pci_dev *bridge;
- static const struct pci_device_id bridge_devids[] = {
- { PCI_VDEVICE(LOONGSON, DEV_PCIE_PORT_0) },
- { PCI_VDEVICE(LOONGSON, DEV_PCIE_PORT_1) },
- { PCI_VDEVICE(LOONGSON, DEV_PCIE_PORT_2) },
- { 0, },
- };
-
- /* look for the matching bridge */
- while (!pci_is_root_bus(bus)) {
- bridge = bus->self;
- bus = bus->parent;
- /*
- * Some Loongson PCIe ports have a h/w limitation of
- * 256 bytes maximum read request size. They can't handle
- * anything larger than this. So force this limit on
- * any devices attached under these ports.
- */
- if (pci_match_id(bridge_devids, bridge)) {
- if (pcie_get_readrq(dev) > 256) {
- pci_info(dev, "limiting MRRS to 256\n");
- pcie_set_readrq(dev, 256);
- }
- break;
- }
- }
+ /*
+ * Some Loongson PCIe ports have h/w limitations of maximum read
+ * request size. They can't handle anything larger than this. So
+ * force this limit on any devices attached under these ports.
+ */
+ struct pci_host_bridge *bridge = pci_find_host_bridge(pdev->bus);
+
+ bridge->no_inc_mrrs = 1;
}
-DECLARE_PCI_FIXUP_ENABLE(PCI_ANY_ID, PCI_ANY_ID, loongson_mrrs_quirk);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
+ DEV_LS2K_PCIE_PORT0, loongson_mrrs_quirk);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
+ DEV_LS7A_PCIE_PORT0, loongson_mrrs_quirk);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
+ DEV_LS7A_PCIE_PORT1, loongson_mrrs_quirk);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
+ DEV_LS7A_PCIE_PORT2, loongson_mrrs_quirk);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
+ DEV_LS7A_PCIE_PORT3, loongson_mrrs_quirk);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
+ DEV_LS7A_PCIE_PORT4, loongson_mrrs_quirk);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
+ DEV_LS7A_PCIE_PORT5, loongson_mrrs_quirk);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
+ DEV_LS7A_PCIE_PORT6, loongson_mrrs_quirk);
static void loongson_pci_pin_quirk(struct pci_dev *pdev)
{
diff --git a/drivers/pci/controller/pci-tegra.c b/drivers/pci/controller/pci-tegra.c
index 929f9363e94b..74c109f14ff0 100644
--- a/drivers/pci/controller/pci-tegra.c
+++ b/drivers/pci/controller/pci-tegra.c
@@ -1330,12 +1330,9 @@ static struct phy *devm_of_phy_optional_get_index(struct device *dev,
if (!name)
return ERR_PTR(-ENOMEM);
- phy = devm_of_phy_get(dev, np, name);
+ phy = devm_of_phy_optional_get(dev, np, name);
kfree(name);
- if (PTR_ERR(phy) == -ENODEV)
- phy = NULL;
-
return phy;
}
@@ -2814,4 +2811,3 @@ static struct platform_driver tegra_pcie_driver = {
.remove = tegra_pcie_remove,
};
module_platform_driver(tegra_pcie_driver);
-MODULE_LICENSE("GPL");
diff --git a/drivers/pci/controller/pci-versatile.c b/drivers/pci/controller/pci-versatile.c
index 7991d334e0f1..e9a6758fe2c1 100644
--- a/drivers/pci/controller/pci-versatile.c
+++ b/drivers/pci/controller/pci-versatile.c
@@ -169,4 +169,3 @@ static struct platform_driver versatile_pci_driver = {
module_platform_driver(versatile_pci_driver);
MODULE_DESCRIPTION("Versatile PCI driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/pci/controller/pcie-hisi-error.c b/drivers/pci/controller/pcie-hisi-error.c
index 7959c9c8d2bc..7d88eb696b06 100644
--- a/drivers/pci/controller/pcie-hisi-error.c
+++ b/drivers/pci/controller/pcie-hisi-error.c
@@ -324,4 +324,3 @@ static struct platform_driver hisi_pcie_error_handler_driver = {
module_platform_driver(hisi_pcie_error_handler_driver);
MODULE_DESCRIPTION("HiSilicon HIP PCIe controller error handling driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/pci/controller/pcie-microchip-host.c b/drivers/pci/controller/pcie-microchip-host.c
index 0ebf7015e9af..5e710e485464 100644
--- a/drivers/pci/controller/pcie-microchip-host.c
+++ b/drivers/pci/controller/pcie-microchip-host.c
@@ -1135,6 +1135,5 @@ static struct platform_driver mc_pcie_driver = {
};
builtin_platform_driver(mc_pcie_driver);
-MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Microchip PCIe host controller driver");
MODULE_AUTHOR("Daire McNamara <daire.mcnamara@microchip.com>");
diff --git a/drivers/pci/controller/pcie-mt7621.c b/drivers/pci/controller/pcie-mt7621.c
index ee7aad09d627..63a5f4463a9f 100644
--- a/drivers/pci/controller/pcie-mt7621.c
+++ b/drivers/pci/controller/pcie-mt7621.c
@@ -60,6 +60,7 @@
#define PCIE_PORT_LINKUP BIT(0)
#define PCIE_PORT_CNT 3
+#define INIT_PORTS_DELAY_MS 100
#define PERST_DELAY_MS 100
/**
@@ -369,6 +370,7 @@ static int mt7621_pcie_init_ports(struct mt7621_pcie *pcie)
}
}
+ msleep(INIT_PORTS_DELAY_MS);
mt7621_pcie_reset_ep_deassert(pcie);
tmp = NULL;
diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c
index 769eedeb8802..990630ec57c6 100644
--- a/drivers/pci/controller/vmd.c
+++ b/drivers/pci/controller/vmd.c
@@ -66,8 +66,23 @@ enum vmd_features {
* interrupt handling.
*/
VMD_FEAT_CAN_BYPASS_MSI_REMAP = (1 << 4),
+
+ /*
+ * Enable ASPM on the PCIE root ports and set the default LTR of the
+ * storage devices on platforms where these values are not configured by
+ * BIOS. This is needed for laptops, which require these settings for
+ * proper power management of the SoC.
+ */
+ VMD_FEAT_BIOS_PM_QUIRK = (1 << 5),
};
+#define VMD_BIOS_PM_QUIRK_LTR 0x1003 /* 3145728 ns */
+
+#define VMD_FEATS_CLIENT (VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP | \
+ VMD_FEAT_HAS_BUS_RESTRICTIONS | \
+ VMD_FEAT_OFFSET_FIRST_VECTOR | \
+ VMD_FEAT_BIOS_PM_QUIRK)
+
static DEFINE_IDA(vmd_instance_ida);
/*
@@ -709,6 +724,46 @@ static void vmd_copy_host_bridge_flags(struct pci_host_bridge *root_bridge,
vmd_bridge->native_dpc = root_bridge->native_dpc;
}
+/*
+ * Enable ASPM and LTR settings on devices that aren't configured by BIOS.
+ */
+static int vmd_pm_enable_quirk(struct pci_dev *pdev, void *userdata)
+{
+ unsigned long features = *(unsigned long *)userdata;
+ u16 ltr = VMD_BIOS_PM_QUIRK_LTR;
+ u32 ltr_reg;
+ int pos;
+
+ if (!(features & VMD_FEAT_BIOS_PM_QUIRK))
+ return 0;
+
+ pci_enable_link_state(pdev, PCIE_LINK_STATE_ALL);
+
+ pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_LTR);
+ if (!pos)
+ return 0;
+
+ /*
+ * Skip if the max snoop LTR is non-zero, indicating BIOS has set it
+ * so the LTR quirk is not needed.
+ */
+ pci_read_config_dword(pdev, pos + PCI_LTR_MAX_SNOOP_LAT, &ltr_reg);
+ if (!!(ltr_reg & (PCI_LTR_VALUE_MASK | PCI_LTR_SCALE_MASK)))
+ return 0;
+
+ /*
+ * Set the default values to the maximum required by the platform to
+ * allow the deepest power management savings. Write as a DWORD where
+ * the lower word is the max snoop latency and the upper word is the
+ * max non-snoop latency.
+ */
+ ltr_reg = (ltr << 16) | ltr;
+ pci_write_config_dword(pdev, pos + PCI_LTR_MAX_SNOOP_LAT, ltr_reg);
+ pci_info(pdev, "VMD: Default LTR value set by driver\n");
+
+ return 0;
+}
+
static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
{
struct pci_sysdata *sd = &vmd->sysdata;
@@ -881,6 +936,8 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
pci_assign_unassigned_bus_resources(vmd->bus);
+ pci_walk_bus(vmd->bus, vmd_pm_enable_quirk, &features);
+
/*
* VMD root buses are virtual and don't return true on pci_is_pcie()
* and will fail pcie_bus_configure_settings() early. It can instead be
@@ -1017,36 +1074,24 @@ static int vmd_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(vmd_dev_pm_ops, vmd_suspend, vmd_resume);
static const struct pci_device_id vmd_ids[] = {
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VMD_201D),
+ {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_VMD_201D),
.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP,},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VMD_28C0),
+ {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_VMD_28C0),
.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW |
VMD_FEAT_HAS_BUS_RESTRICTIONS |
VMD_FEAT_CAN_BYPASS_MSI_REMAP,},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x467f),
- .driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |
- VMD_FEAT_HAS_BUS_RESTRICTIONS |
- VMD_FEAT_OFFSET_FIRST_VECTOR,},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4c3d),
- .driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |
- VMD_FEAT_HAS_BUS_RESTRICTIONS |
- VMD_FEAT_OFFSET_FIRST_VECTOR,},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa77f),
- .driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |
- VMD_FEAT_HAS_BUS_RESTRICTIONS |
- VMD_FEAT_OFFSET_FIRST_VECTOR,},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7d0b),
- .driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |
- VMD_FEAT_HAS_BUS_RESTRICTIONS |
- VMD_FEAT_OFFSET_FIRST_VECTOR,},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xad0b),
- .driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |
- VMD_FEAT_HAS_BUS_RESTRICTIONS |
- VMD_FEAT_OFFSET_FIRST_VECTOR,},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VMD_9A0B),
- .driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |
- VMD_FEAT_HAS_BUS_RESTRICTIONS |
- VMD_FEAT_OFFSET_FIRST_VECTOR,},
+ {PCI_VDEVICE(INTEL, 0x467f),
+ .driver_data = VMD_FEATS_CLIENT,},
+ {PCI_VDEVICE(INTEL, 0x4c3d),
+ .driver_data = VMD_FEATS_CLIENT,},
+ {PCI_VDEVICE(INTEL, 0xa77f),
+ .driver_data = VMD_FEATS_CLIENT,},
+ {PCI_VDEVICE(INTEL, 0x7d0b),
+ .driver_data = VMD_FEATS_CLIENT,},
+ {PCI_VDEVICE(INTEL, 0xad0b),
+ .driver_data = VMD_FEATS_CLIENT,},
+ {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_VMD_9A0B),
+ .driver_data = VMD_FEATS_CLIENT,},
{0,}
};
MODULE_DEVICE_TABLE(pci, vmd_ids);
diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index 55283d2379a6..0f9d2ec822ac 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -826,33 +826,21 @@ static int pci_epf_test_core_init(struct pci_epf *epf)
return 0;
}
-static int pci_epf_test_notifier(struct notifier_block *nb, unsigned long val,
- void *data)
+static int pci_epf_test_link_up(struct pci_epf *epf)
{
- struct pci_epf *epf = container_of(nb, struct pci_epf, nb);
struct pci_epf_test *epf_test = epf_get_drvdata(epf);
- int ret;
-
- switch (val) {
- case CORE_INIT:
- ret = pci_epf_test_core_init(epf);
- if (ret)
- return NOTIFY_BAD;
- break;
- case LINK_UP:
- queue_delayed_work(kpcitest_workqueue, &epf_test->cmd_handler,
- msecs_to_jiffies(1));
- break;
-
- default:
- dev_err(&epf->dev, "Invalid EPF test notifier event\n");
- return NOTIFY_BAD;
- }
+ queue_delayed_work(kpcitest_workqueue, &epf_test->cmd_handler,
+ msecs_to_jiffies(1));
- return NOTIFY_OK;
+ return 0;
}
+static const struct pci_epc_event_ops pci_epf_test_event_ops = {
+ .core_init = pci_epf_test_core_init,
+ .link_up = pci_epf_test_link_up,
+};
+
static int pci_epf_test_alloc_space(struct pci_epf *epf)
{
struct pci_epf_test *epf_test = epf_get_drvdata(epf);
@@ -979,12 +967,8 @@ static int pci_epf_test_bind(struct pci_epf *epf)
if (ret)
epf_test->dma_supported = false;
- if (linkup_notifier || core_init_notifier) {
- epf->nb.notifier_call = pci_epf_test_notifier;
- pci_epc_register_notifier(epc, &epf->nb);
- } else {
+ if (!linkup_notifier && !core_init_notifier)
queue_work(kpcitest_workqueue, &epf_test->cmd_handler.work);
- }
return 0;
}
@@ -1010,6 +994,8 @@ static int pci_epf_test_probe(struct pci_epf *epf)
INIT_DELAYED_WORK(&epf_test->cmd_handler, pci_epf_test_cmd_handler);
+ epf->event_ops = &pci_epf_test_event_ops;
+
epf_set_drvdata(epf, epf_test);
return 0;
}
diff --git a/drivers/pci/endpoint/functions/pci-epf-vntb.c b/drivers/pci/endpoint/functions/pci-epf-vntb.c
index 04698e7995a5..b7c7a8af99f4 100644
--- a/drivers/pci/endpoint/functions/pci-epf-vntb.c
+++ b/drivers/pci/endpoint/functions/pci-epf-vntb.c
@@ -652,6 +652,7 @@ err_alloc_mem:
/**
* epf_ntb_mw_bar_clear() - Clear Memory window BARs
* @ntb: NTB device that facilitates communication between HOST and VHOST
+ * @num_mws: the number of Memory window BARs that to be cleared
*/
static void epf_ntb_mw_bar_clear(struct epf_ntb *ntb, int num_mws)
{
diff --git a/drivers/pci/endpoint/pci-ep-cfs.c b/drivers/pci/endpoint/pci-ep-cfs.c
index d4850bdd837f..4b8ac0ac84d5 100644
--- a/drivers/pci/endpoint/pci-ep-cfs.c
+++ b/drivers/pci/endpoint/pci-ep-cfs.c
@@ -728,4 +728,3 @@ module_exit(pci_ep_cfs_exit);
MODULE_DESCRIPTION("PCI EP CONFIGFS");
MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c
index 2542196e8c3d..9440d9811eea 100644
--- a/drivers/pci/endpoint/pci-epc-core.c
+++ b/drivers/pci/endpoint/pci-epc-core.c
@@ -613,7 +613,7 @@ int pci_epc_add_epf(struct pci_epc *epc, struct pci_epf *epf,
if (type == SECONDARY_INTERFACE && epf->sec_epc)
return -EBUSY;
- mutex_lock(&epc->lock);
+ mutex_lock(&epc->list_lock);
func_no = find_first_zero_bit(&epc->function_num_map,
BITS_PER_LONG);
if (func_no >= BITS_PER_LONG) {
@@ -640,7 +640,7 @@ int pci_epc_add_epf(struct pci_epc *epc, struct pci_epf *epf,
list_add_tail(list, &epc->pci_epf);
ret:
- mutex_unlock(&epc->lock);
+ mutex_unlock(&epc->list_lock);
return ret;
}
@@ -672,11 +672,11 @@ void pci_epc_remove_epf(struct pci_epc *epc, struct pci_epf *epf,
list = &epf->sec_epc_list;
}
- mutex_lock(&epc->lock);
+ mutex_lock(&epc->list_lock);
clear_bit(func_no, &epc->function_num_map);
list_del(list);
epf->epc = NULL;
- mutex_unlock(&epc->lock);
+ mutex_unlock(&epc->list_lock);
}
EXPORT_SYMBOL_GPL(pci_epc_remove_epf);
@@ -690,10 +690,19 @@ EXPORT_SYMBOL_GPL(pci_epc_remove_epf);
*/
void pci_epc_linkup(struct pci_epc *epc)
{
+ struct pci_epf *epf;
+
if (!epc || IS_ERR(epc))
return;
- atomic_notifier_call_chain(&epc->notifier, LINK_UP, NULL);
+ mutex_lock(&epc->list_lock);
+ list_for_each_entry(epf, &epc->pci_epf, list) {
+ mutex_lock(&epf->lock);
+ if (epf->event_ops && epf->event_ops->link_up)
+ epf->event_ops->link_up(epf);
+ mutex_unlock(&epf->lock);
+ }
+ mutex_unlock(&epc->list_lock);
}
EXPORT_SYMBOL_GPL(pci_epc_linkup);
@@ -707,10 +716,19 @@ EXPORT_SYMBOL_GPL(pci_epc_linkup);
*/
void pci_epc_init_notify(struct pci_epc *epc)
{
+ struct pci_epf *epf;
+
if (!epc || IS_ERR(epc))
return;
- atomic_notifier_call_chain(&epc->notifier, CORE_INIT, NULL);
+ mutex_lock(&epc->list_lock);
+ list_for_each_entry(epf, &epc->pci_epf, list) {
+ mutex_lock(&epf->lock);
+ if (epf->event_ops && epf->event_ops->core_init)
+ epf->event_ops->core_init(epf);
+ mutex_unlock(&epf->lock);
+ }
+ mutex_unlock(&epc->list_lock);
}
EXPORT_SYMBOL_GPL(pci_epc_init_notify);
@@ -777,8 +795,8 @@ __pci_epc_create(struct device *dev, const struct pci_epc_ops *ops,
}
mutex_init(&epc->lock);
+ mutex_init(&epc->list_lock);
INIT_LIST_HEAD(&epc->pci_epf);
- ATOMIC_INIT_NOTIFIER_HEAD(&epc->notifier);
device_initialize(&epc->dev);
epc->dev.class = pci_epc_class;
@@ -861,4 +879,3 @@ module_exit(pci_epc_exit);
MODULE_DESCRIPTION("PCI EPC Library");
MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/pci/endpoint/pci-epc-mem.c b/drivers/pci/endpoint/pci-epc-mem.c
index a97b56a6d2db..7dcf6f480b82 100644
--- a/drivers/pci/endpoint/pci-epc-mem.c
+++ b/drivers/pci/endpoint/pci-epc-mem.c
@@ -260,4 +260,3 @@ EXPORT_SYMBOL_GPL(pci_epc_mem_free_addr);
MODULE_DESCRIPTION("PCI EPC Address Space Management");
MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/pci/endpoint/pci-epf-core.c b/drivers/pci/endpoint/pci-epf-core.c
index 9ed556936f48..2036e38be093 100644
--- a/drivers/pci/endpoint/pci-epf-core.c
+++ b/drivers/pci/endpoint/pci-epf-core.c
@@ -568,4 +568,3 @@ module_exit(pci_epf_exit);
MODULE_DESCRIPTION("PCI EPF Library");
MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c
index 853e04ad272c..c02257f4b61c 100644
--- a/drivers/pci/hotplug/acpiphp_core.c
+++ b/drivers/pci/hotplug/acpiphp_core.c
@@ -45,7 +45,6 @@ static struct acpiphp_attention_info *attention_info;
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
MODULE_PARM_DESC(disable, "disable acpiphp driver");
module_param_named(disable, acpiphp_disabled, bool, 0444);
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index 10e9670eea0b..f8c70115b691 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -1088,6 +1088,8 @@ static void quirk_cmd_compl(struct pci_dev *pdev)
}
DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_INTEL, PCI_ANY_ID,
PCI_CLASS_BRIDGE_PCI, 8, quirk_cmd_compl);
+DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_QCOM, 0x010e,
+ PCI_CLASS_BRIDGE_PCI, 8, quirk_cmd_compl);
DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_QCOM, 0x0110,
PCI_CLASS_BRIDGE_PCI, 8, quirk_cmd_compl);
DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_QCOM, 0x0400,
diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c
index 53692b048301..56c7795ed890 100644
--- a/drivers/pci/hotplug/shpchp_core.c
+++ b/drivers/pci/hotplug/shpchp_core.c
@@ -32,7 +32,6 @@ int shpchp_poll_time;
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
module_param(shpchp_debug, bool, 0644);
module_param(shpchp_poll_mode, bool, 0644);
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
index 952217572113..b2e8322755c1 100644
--- a/drivers/pci/iov.c
+++ b/drivers/pci/iov.c
@@ -14,7 +14,7 @@
#include <linux/delay.h>
#include "pci.h"
-#define VIRTFN_ID_LEN 16
+#define VIRTFN_ID_LEN 17 /* "virtfn%u\0" for 2^32 - 1 */
int pci_iov_virtfn_bus(struct pci_dev *dev, int vf_id)
{
diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c
index 86812d2073ea..9e8205572830 100644
--- a/drivers/pci/p2pdma.c
+++ b/drivers/pci/p2pdma.c
@@ -194,11 +194,13 @@ static const struct attribute_group p2pmem_group = {
static void p2pdma_page_free(struct page *page)
{
struct pci_p2pdma_pagemap *pgmap = to_p2p_pgmap(page->pgmap);
+ /* safe to dereference while a reference is held to the percpu ref */
+ struct pci_p2pdma *p2pdma =
+ rcu_dereference_protected(pgmap->provider->p2pdma, 1);
struct percpu_ref *ref;
- gen_pool_free_owner(pgmap->provider->p2pdma->pool,
- (uintptr_t)page_to_virt(page), PAGE_SIZE,
- (void **)&ref);
+ gen_pool_free_owner(p2pdma->pool, (uintptr_t)page_to_virt(page),
+ PAGE_SIZE, (void **)&ref);
percpu_ref_put(ref);
}
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 068d6745bf98..052a611081ec 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -976,24 +976,41 @@ bool acpi_pci_power_manageable(struct pci_dev *dev)
bool acpi_pci_bridge_d3(struct pci_dev *dev)
{
struct pci_dev *rpdev;
- struct acpi_device *adev;
- acpi_status status;
- unsigned long long state;
+ struct acpi_device *adev, *rpadev;
const union acpi_object *obj;
if (acpi_pci_disabled || !dev->is_hotplug_bridge)
return false;
- /* Assume D3 support if the bridge is power-manageable by ACPI. */
- if (acpi_pci_power_manageable(dev))
- return true;
+ adev = ACPI_COMPANION(&dev->dev);
+ if (adev) {
+ /*
+ * If the bridge has _S0W, whether or not it can go into D3
+ * depends on what is returned by that object. In particular,
+ * if the power state returned by _S0W is D2 or shallower,
+ * entering D3 should not be allowed.
+ */
+ if (acpi_dev_power_state_for_wake(adev) <= ACPI_STATE_D2)
+ return false;
+
+ /*
+ * Otherwise, assume that the bridge can enter D3 so long as it
+ * is power-manageable via ACPI.
+ */
+ if (acpi_device_power_manageable(adev))
+ return true;
+ }
rpdev = pcie_find_root_port(dev);
if (!rpdev)
return false;
- adev = ACPI_COMPANION(&rpdev->dev);
- if (!adev)
+ if (rpdev == dev)
+ rpadev = adev;
+ else
+ rpadev = ACPI_COMPANION(&rpdev->dev);
+
+ if (!rpadev)
return false;
/*
@@ -1001,15 +1018,15 @@ bool acpi_pci_bridge_d3(struct pci_dev *dev)
* doesn't supply a wakeup GPE via _PRW, it cannot signal hotplug
* events from low-power states including D3hot and D3cold.
*/
- if (!adev->wakeup.flags.valid)
+ if (!rpadev->wakeup.flags.valid)
return false;
/*
- * If the Root Port cannot wake itself from D3hot or D3cold, we
- * can't use D3.
+ * In the bridge-below-a-Root-Port case, evaluate _S0W for the Root Port
+ * to verify whether or not it can signal wakeup from D3.
*/
- status = acpi_evaluate_integer(adev->handle, "_S0W", NULL, &state);
- if (ACPI_SUCCESS(status) && state < ACPI_STATE_D3_HOT)
+ if (rpadev != adev &&
+ acpi_dev_power_state_for_wake(rpadev) <= ACPI_STATE_D2)
return false;
/*
@@ -1018,7 +1035,7 @@ bool acpi_pci_bridge_d3(struct pci_dev *dev)
* bridges *below* that Root Port can also signal hotplug events
* while in D3.
*/
- if (!acpi_dev_get_property(adev, "HotPlugSupportInD3",
+ if (!acpi_dev_get_property(rpadev, "HotPlugSupportInD3",
ACPI_TYPE_INTEGER, &obj) &&
obj->integer.value == 1)
return true;
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index a2ceeacc33eb..57ddcc59af30 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -572,7 +572,7 @@ static void pci_pm_default_resume_early(struct pci_dev *pci_dev)
static void pci_pm_bridge_power_up_actions(struct pci_dev *pci_dev)
{
- pci_bridge_wait_for_secondary_bus(pci_dev);
+ pci_bridge_wait_for_secondary_bus(pci_dev, "resume", PCI_RESET_WAIT);
/*
* When powering on a bridge from D3cold, the whole hierarchy may be
* powered on into D0uninitialized state, resume them to give them a
@@ -1545,9 +1545,9 @@ void pci_dev_put(struct pci_dev *dev)
}
EXPORT_SYMBOL(pci_dev_put);
-static int pci_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int pci_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct pci_dev *pdev;
+ const struct pci_dev *pdev;
if (!dev)
return -ENODEV;
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 5641786bd020..7a67611dc5f4 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -167,9 +167,6 @@ static int __init pcie_port_pm_setup(char *str)
}
__setup("pcie_port_pm=", pcie_port_pm_setup);
-/* Time to wait after a reset for device to become responsive */
-#define PCIE_RESET_READY_POLL_MS 60000
-
/**
* pci_bus_max_busnr - returns maximum PCI bus number of given bus' children
* @bus: pointer to PCI bus structure to search
@@ -1174,7 +1171,7 @@ static int pci_dev_wait(struct pci_dev *dev, char *reset_type, int timeout)
return -ENOTTY;
}
- if (delay > 1000)
+ if (delay > PCI_RESET_WAIT)
pci_info(dev, "not ready %dms after %s; waiting\n",
delay - 1, reset_type);
@@ -1183,7 +1180,7 @@ static int pci_dev_wait(struct pci_dev *dev, char *reset_type, int timeout)
pci_read_config_dword(dev, PCI_COMMAND, &id);
}
- if (delay > 1000)
+ if (delay > PCI_RESET_WAIT)
pci_info(dev, "ready %dms after %s\n", delay - 1,
reset_type);
@@ -4941,24 +4938,31 @@ static int pci_bus_max_d3cold_delay(const struct pci_bus *bus)
/**
* pci_bridge_wait_for_secondary_bus - Wait for secondary bus to be accessible
* @dev: PCI bridge
+ * @reset_type: reset type in human-readable form
+ * @timeout: maximum time to wait for devices on secondary bus (milliseconds)
*
* Handle necessary delays before access to the devices on the secondary
- * side of the bridge are permitted after D3cold to D0 transition.
+ * side of the bridge are permitted after D3cold to D0 transition
+ * or Conventional Reset.
*
* For PCIe this means the delays in PCIe 5.0 section 6.6.1. For
* conventional PCI it means Tpvrh + Trhfa specified in PCI 3.0 section
* 4.3.2.
+ *
+ * Return 0 on success or -ENOTTY if the first device on the secondary bus
+ * failed to become accessible.
*/
-void pci_bridge_wait_for_secondary_bus(struct pci_dev *dev)
+int pci_bridge_wait_for_secondary_bus(struct pci_dev *dev, char *reset_type,
+ int timeout)
{
struct pci_dev *child;
int delay;
if (pci_dev_is_disconnected(dev))
- return;
+ return 0;
- if (!pci_is_bridge(dev) || !dev->bridge_d3)
- return;
+ if (!pci_is_bridge(dev))
+ return 0;
down_read(&pci_bus_sem);
@@ -4970,14 +4974,14 @@ void pci_bridge_wait_for_secondary_bus(struct pci_dev *dev)
*/
if (!dev->subordinate || list_empty(&dev->subordinate->devices)) {
up_read(&pci_bus_sem);
- return;
+ return 0;
}
/* Take d3cold_delay requirements into account */
delay = pci_bus_max_d3cold_delay(dev->subordinate);
if (!delay) {
up_read(&pci_bus_sem);
- return;
+ return 0;
}
child = list_first_entry(&dev->subordinate->devices, struct pci_dev,
@@ -4986,14 +4990,12 @@ void pci_bridge_wait_for_secondary_bus(struct pci_dev *dev)
/*
* Conventional PCI and PCI-X we need to wait Tpvrh + Trhfa before
- * accessing the device after reset (that is 1000 ms + 100 ms). In
- * practice this should not be needed because we don't do power
- * management for them (see pci_bridge_d3_possible()).
+ * accessing the device after reset (that is 1000 ms + 100 ms).
*/
if (!pci_is_pcie(dev)) {
pci_dbg(dev, "waiting %d ms for secondary bus\n", 1000 + delay);
msleep(1000 + delay);
- return;
+ return 0;
}
/*
@@ -5010,11 +5012,11 @@ void pci_bridge_wait_for_secondary_bus(struct pci_dev *dev)
* configuration requests if we only wait for 100 ms (see
* https://bugzilla.kernel.org/show_bug.cgi?id=203885).
*
- * Therefore we wait for 100 ms and check for the device presence.
- * If it is still not present give it an additional 100 ms.
+ * Therefore we wait for 100 ms and check for the device presence
+ * until the timeout expires.
*/
if (!pcie_downstream_port(dev))
- return;
+ return 0;
if (pcie_get_speed_cap(dev) <= PCIE_SPEED_5_0GT) {
pci_dbg(dev, "waiting %d ms for downstream link\n", delay);
@@ -5025,14 +5027,11 @@ void pci_bridge_wait_for_secondary_bus(struct pci_dev *dev)
if (!pcie_wait_for_link_delay(dev, true, delay)) {
/* Did not train, no need to wait any further */
pci_info(dev, "Data Link Layer Link Active not set in 1000 msec\n");
- return;
+ return -ENOTTY;
}
}
- if (!pci_device_is_present(child)) {
- pci_dbg(child, "waiting additional %d ms to become accessible\n", delay);
- msleep(delay);
- }
+ return pci_dev_wait(child, reset_type, timeout - delay);
}
void pci_reset_secondary_bus(struct pci_dev *dev)
@@ -5051,15 +5050,6 @@ void pci_reset_secondary_bus(struct pci_dev *dev)
ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET;
pci_write_config_word(dev, PCI_BRIDGE_CONTROL, ctrl);
-
- /*
- * Trhfa for conventional PCI is 2^25 clock cycles.
- * Assuming a minimum 33MHz clock this results in a 1s
- * delay before we can consider subordinate devices to
- * be re-initialized. PCIe has some ways to shorten this,
- * but we don't make use of them yet.
- */
- ssleep(1);
}
void __weak pcibios_reset_secondary_bus(struct pci_dev *dev)
@@ -5078,7 +5068,8 @@ int pci_bridge_secondary_bus_reset(struct pci_dev *dev)
{
pcibios_reset_secondary_bus(dev);
- return pci_dev_wait(dev, "bus reset", PCIE_RESET_READY_POLL_MS);
+ return pci_bridge_wait_for_secondary_bus(dev, "bus reset",
+ PCIE_RESET_READY_POLL_MS);
}
EXPORT_SYMBOL_GPL(pci_bridge_secondary_bus_reset);
@@ -6026,6 +6017,7 @@ int pcie_set_readrq(struct pci_dev *dev, int rq)
{
u16 v;
int ret;
+ struct pci_host_bridge *bridge = pci_find_host_bridge(dev->bus);
if (rq < 128 || rq > 4096 || !is_power_of_2(rq))
return -EINVAL;
@@ -6044,6 +6036,15 @@ int pcie_set_readrq(struct pci_dev *dev, int rq)
v = (ffs(rq) - 8) << 12;
+ if (bridge->no_inc_mrrs) {
+ int max_mrrs = pcie_get_readrq(dev);
+
+ if (rq > max_mrrs) {
+ pci_info(dev, "can't set Max_Read_Request_Size to %d; max is %d\n", rq, max_mrrs);
+ return -EINVAL;
+ }
+ }
+
ret = pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
PCI_EXP_DEVCTL_READRQ, v);
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 9049d07d3aae..d2c08670a20e 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -64,6 +64,19 @@ struct pci_cap_saved_state *pci_find_saved_ext_cap(struct pci_dev *dev,
#define PCI_PM_D3HOT_WAIT 10 /* msec */
#define PCI_PM_D3COLD_WAIT 100 /* msec */
+/*
+ * Following exit from Conventional Reset, devices must be ready within 1 sec
+ * (PCIe r6.0 sec 6.6.1). A D3cold to D0 transition implies a Conventional
+ * Reset (PCIe r6.0 sec 5.8).
+ */
+#define PCI_RESET_WAIT 1000 /* msec */
+/*
+ * Devices may extend the 1 sec period through Request Retry Status completions
+ * (PCIe r6.0 sec 2.3.1). The spec does not provide an upper limit, but 60 sec
+ * ought to be enough for any device to become responsive.
+ */
+#define PCIE_RESET_READY_POLL_MS 60000 /* msec */
+
void pci_update_current_state(struct pci_dev *dev, pci_power_t state);
void pci_refresh_power_state(struct pci_dev *dev);
int pci_power_up(struct pci_dev *dev);
@@ -86,8 +99,9 @@ void pci_msi_init(struct pci_dev *dev);
void pci_msix_init(struct pci_dev *dev);
bool pci_bridge_d3_possible(struct pci_dev *dev);
void pci_bridge_d3_update(struct pci_dev *dev);
-void pci_bridge_wait_for_secondary_bus(struct pci_dev *dev);
void pci_bridge_reconfigure_ltr(struct pci_dev *dev);
+int pci_bridge_wait_for_secondary_bus(struct pci_dev *dev, char *reset_type,
+ int timeout);
static inline void pci_wakeup_event(struct pci_dev *dev)
{
@@ -310,53 +324,36 @@ struct pci_sriov {
* @dev: PCI device to set new error_state
* @new: the state we want dev to be in
*
- * Must be called with device_lock held.
+ * If the device is experiencing perm_failure, it has to remain in that state.
+ * Any other transition is allowed.
*
* Returns true if state has been changed to the requested state.
*/
static inline bool pci_dev_set_io_state(struct pci_dev *dev,
pci_channel_state_t new)
{
- bool changed = false;
+ pci_channel_state_t old;
- device_lock_assert(&dev->dev);
switch (new) {
case pci_channel_io_perm_failure:
- switch (dev->error_state) {
- case pci_channel_io_frozen:
- case pci_channel_io_normal:
- case pci_channel_io_perm_failure:
- changed = true;
- break;
- }
- break;
+ xchg(&dev->error_state, pci_channel_io_perm_failure);
+ return true;
case pci_channel_io_frozen:
- switch (dev->error_state) {
- case pci_channel_io_frozen:
- case pci_channel_io_normal:
- changed = true;
- break;
- }
- break;
+ old = cmpxchg(&dev->error_state, pci_channel_io_normal,
+ pci_channel_io_frozen);
+ return old != pci_channel_io_perm_failure;
case pci_channel_io_normal:
- switch (dev->error_state) {
- case pci_channel_io_frozen:
- case pci_channel_io_normal:
- changed = true;
- break;
- }
- break;
+ old = cmpxchg(&dev->error_state, pci_channel_io_frozen,
+ pci_channel_io_normal);
+ return old != pci_channel_io_perm_failure;
+ default:
+ return false;
}
- if (changed)
- dev->error_state = new;
- return changed;
}
static inline int pci_dev_set_disconnected(struct pci_dev *dev, void *unused)
{
- device_lock(&dev->dev);
pci_dev_set_io_state(dev, pci_channel_io_perm_failure);
- device_unlock(&dev->dev);
return 0;
}
diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
index 625f7b2cafe4..f6c24ded134c 100644
--- a/drivers/pci/pcie/aer.c
+++ b/drivers/pci/pcie/aer.c
@@ -184,6 +184,9 @@ static int disable_ecrc_checking(struct pci_dev *dev)
*/
void pcie_set_ecrc_checking(struct pci_dev *dev)
{
+ if (!pcie_aer_is_native(dev))
+ return;
+
switch (ecrc_policy) {
case ECRC_POLICY_DEFAULT:
return;
@@ -1224,42 +1227,6 @@ static irqreturn_t aer_irq(int irq, void *context)
return IRQ_WAKE_THREAD;
}
-static int set_device_error_reporting(struct pci_dev *dev, void *data)
-{
- bool enable = *((bool *)data);
- int type = pci_pcie_type(dev);
-
- if ((type == PCI_EXP_TYPE_ROOT_PORT) ||
- (type == PCI_EXP_TYPE_RC_EC) ||
- (type == PCI_EXP_TYPE_UPSTREAM) ||
- (type == PCI_EXP_TYPE_DOWNSTREAM)) {
- if (enable)
- pci_enable_pcie_error_reporting(dev);
- else
- pci_disable_pcie_error_reporting(dev);
- }
-
- return 0;
-}
-
-/**
- * set_downstream_devices_error_reporting - enable/disable the error reporting bits on the root port and its downstream ports.
- * @dev: pointer to root port's pci_dev data structure
- * @enable: true = enable error reporting, false = disable error reporting.
- */
-static void set_downstream_devices_error_reporting(struct pci_dev *dev,
- bool enable)
-{
- set_device_error_reporting(dev, &enable);
-
- if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_EC)
- pcie_walk_rcec(dev, set_device_error_reporting, &enable);
- else if (dev->subordinate)
- pci_walk_bus(dev->subordinate, set_device_error_reporting,
- &enable);
-
-}
-
/**
* aer_enable_rootport - enable Root Port's interrupts when receiving messages
* @rpc: pointer to a Root Port data structure
@@ -1289,12 +1256,6 @@ static void aer_enable_rootport(struct aer_rpc *rpc)
pci_read_config_dword(pdev, aer + PCI_ERR_UNCOR_STATUS, &reg32);
pci_write_config_dword(pdev, aer + PCI_ERR_UNCOR_STATUS, reg32);
- /*
- * Enable error reporting for the root port device and downstream port
- * devices.
- */
- set_downstream_devices_error_reporting(pdev, true);
-
/* Enable Root Port's interrupt in response to error messages */
pci_read_config_dword(pdev, aer + PCI_ERR_ROOT_COMMAND, &reg32);
reg32 |= ROOT_PORT_INTR_ON_MESG_MASK;
@@ -1313,12 +1274,6 @@ static void aer_disable_rootport(struct aer_rpc *rpc)
int aer = pdev->aer_cap;
u32 reg32;
- /*
- * Disable error reporting for the root port device and downstream port
- * devices.
- */
- set_downstream_devices_error_reporting(pdev, false);
-
/* Disable Root's interrupt in response to error messages */
pci_read_config_dword(pdev, aer + PCI_ERR_ROOT_COMMAND, &reg32);
reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK;
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 4b4184563a92..66d7514ca111 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -1138,6 +1138,60 @@ int pci_disable_link_state(struct pci_dev *pdev, int state)
}
EXPORT_SYMBOL(pci_disable_link_state);
+/**
+ * pci_enable_link_state - Clear and set the default device link state so that
+ * the link may be allowed to enter the specified states. Note that if the
+ * BIOS didn't grant ASPM control to the OS, this does nothing because we can't
+ * touch the LNKCTL register. Also note that this does not enable states
+ * disabled by pci_disable_link_state(). Return 0 or a negative errno.
+ *
+ * @pdev: PCI device
+ * @state: Mask of ASPM link states to enable
+ */
+int pci_enable_link_state(struct pci_dev *pdev, int state)
+{
+ struct pcie_link_state *link = pcie_aspm_get_link(pdev);
+
+ if (!link)
+ return -EINVAL;
+ /*
+ * A driver requested that ASPM be enabled on this device, but
+ * if we don't have permission to manage ASPM (e.g., on ACPI
+ * systems we have to observe the FADT ACPI_FADT_NO_ASPM bit and
+ * the _OSC method), we can't honor that request.
+ */
+ if (aspm_disabled) {
+ pci_warn(pdev, "can't override BIOS ASPM; OS doesn't have ASPM control\n");
+ return -EPERM;
+ }
+
+ down_read(&pci_bus_sem);
+ mutex_lock(&aspm_lock);
+ link->aspm_default = 0;
+ if (state & PCIE_LINK_STATE_L0S)
+ link->aspm_default |= ASPM_STATE_L0S;
+ if (state & PCIE_LINK_STATE_L1)
+ /* L1 PM substates require L1 */
+ link->aspm_default |= ASPM_STATE_L1 | ASPM_STATE_L1SS;
+ if (state & PCIE_LINK_STATE_L1_1)
+ link->aspm_default |= ASPM_STATE_L1_1;
+ if (state & PCIE_LINK_STATE_L1_2)
+ link->aspm_default |= ASPM_STATE_L1_2;
+ if (state & PCIE_LINK_STATE_L1_1_PCIPM)
+ link->aspm_default |= ASPM_STATE_L1_1_PCIPM;
+ if (state & PCIE_LINK_STATE_L1_2_PCIPM)
+ link->aspm_default |= ASPM_STATE_L1_2_PCIPM;
+ pcie_config_aspm_link(link, policy_to_aspm_state(link));
+
+ link->clkpm_default = (state & PCIE_LINK_STATE_CLKPM) ? 1 : 0;
+ pcie_set_clkpm(link, policy_to_clkpm_state(link));
+ mutex_unlock(&aspm_lock);
+ up_read(&pci_bus_sem);
+
+ return 0;
+}
+EXPORT_SYMBOL(pci_enable_link_state);
+
static int pcie_aspm_set_policy(const char *val,
const struct kernel_param *kp)
{
diff --git a/drivers/pci/pcie/dpc.c b/drivers/pci/pcie/dpc.c
index f5ffea17c7f8..a5d7c69b764e 100644
--- a/drivers/pci/pcie/dpc.c
+++ b/drivers/pci/pcie/dpc.c
@@ -170,8 +170,8 @@ pci_ers_result_t dpc_reset_link(struct pci_dev *pdev)
pci_write_config_word(pdev, cap + PCI_EXP_DPC_STATUS,
PCI_EXP_DPC_STATUS_TRIGGER);
- if (!pcie_wait_for_link(pdev, true)) {
- pci_info(pdev, "Data Link Layer Link Active not set in 1000 msec\n");
+ if (pci_bridge_wait_for_secondary_bus(pdev, "DPC",
+ PCIE_RESET_READY_POLL_MS)) {
clear_bit(PCI_DPC_RECOVERED, &pdev->priv_flags);
ret = PCI_ERS_RESULT_DISCONNECT;
} else {
diff --git a/drivers/pci/pcie/portdrv.c b/drivers/pci/pcie/portdrv.c
index 2cc2e60bcb39..46fad0d813b2 100644
--- a/drivers/pci/pcie/portdrv.c
+++ b/drivers/pci/pcie/portdrv.c
@@ -501,7 +501,6 @@ static void pcie_port_device_remove(struct pci_dev *dev)
{
device_for_each_child(&dev->dev, NULL, remove_iter);
pci_free_irq_vectors(dev);
- pci_disable_device(dev);
}
/**
@@ -727,6 +726,19 @@ static void pcie_portdrv_remove(struct pci_dev *dev)
}
pcie_port_device_remove(dev);
+
+ pci_disable_device(dev);
+}
+
+static void pcie_portdrv_shutdown(struct pci_dev *dev)
+{
+ if (pci_bridge_d3_possible(dev)) {
+ pm_runtime_forbid(&dev->dev);
+ pm_runtime_get_noresume(&dev->dev);
+ pm_runtime_dont_use_autosuspend(&dev->dev);
+ }
+
+ pcie_port_device_remove(dev);
}
static pci_ers_result_t pcie_portdrv_error_detected(struct pci_dev *dev,
@@ -777,7 +789,7 @@ static struct pci_driver pcie_portdriver = {
.probe = pcie_portdrv_probe,
.remove = pcie_portdrv_remove,
- .shutdown = pcie_portdrv_remove,
+ .shutdown = pcie_portdrv_shutdown,
.err_handler = &pcie_portdrv_err_handler,
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 1779582fb500..a3f68b6ba6ac 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -596,6 +596,7 @@ static void pci_init_host_bridge(struct pci_host_bridge *bridge)
bridge->native_ltr = 1;
bridge->native_dpc = 1;
bridge->domain_nr = PCI_DOMAIN_NR_NOT_SET;
+ bridge->native_cxl_error = 1;
device_initialize(&bridge->dev);
}
@@ -996,7 +997,7 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge)
resource_list_for_each_entry_safe(window, n, &resources) {
offset = window->offset;
res = window->res;
- if (!res->end)
+ if (!res->flags && !res->start && !res->end)
continue;
list_move_tail(&window->node, &bridge->windows);
@@ -1841,6 +1842,8 @@ int pci_setup_device(struct pci_dev *dev)
pci_set_of_node(dev);
pci_set_acpi_fwnode(dev);
+ if (dev->dev.fwnode && !fwnode_device_is_available(dev->dev.fwnode))
+ return -ENODEV;
pci_dev_assign_slot(dev);
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 285acc4aaccc..44cab813bf95 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -4835,6 +4835,26 @@ static int pci_quirk_brcm_acs(struct pci_dev *dev, u16 acs_flags)
PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);
}
+/*
+ * Wangxun 10G/1G NICs have no ACS capability, and on multi-function
+ * devices, peer-to-peer transactions are not be used between the functions.
+ * So add an ACS quirk for below devices to isolate functions.
+ * SFxxx 1G NICs(em).
+ * RP1000/RP2000 10G NICs(sp).
+ */
+static int pci_quirk_wangxun_nic_acs(struct pci_dev *dev, u16 acs_flags)
+{
+ switch (dev->device) {
+ case 0x0100 ... 0x010F:
+ case 0x1001:
+ case 0x2001:
+ return pci_acs_ctrl_enabled(acs_flags,
+ PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);
+ }
+
+ return false;
+}
+
static const struct pci_dev_acs_enabled {
u16 vendor;
u16 device;
@@ -4980,6 +5000,8 @@ static const struct pci_dev_acs_enabled {
{ PCI_VENDOR_ID_NXP, 0x8d9b, pci_quirk_nxp_rp_acs },
/* Zhaoxin Root/Downstream Ports */
{ PCI_VENDOR_ID_ZHAOXIN, PCI_ANY_ID, pci_quirk_zhaoxin_pcie_ports_acs },
+ /* Wangxun nics */
+ { PCI_VENDOR_ID_WANGXUN, PCI_ANY_ID, pci_quirk_wangxun_nic_acs },
{ 0 }
};
@@ -5340,9 +5362,18 @@ static void quirk_no_flr(struct pci_dev *dev)
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x1487, quirk_no_flr);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x148c, quirk_no_flr);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x149c, quirk_no_flr);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x7901, quirk_no_flr);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x1502, quirk_no_flr);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x1503, quirk_no_flr);
+/* FLR may cause the SolidRun SNET DPU (rev 0x1) to hang */
+static void quirk_no_flr_snet(struct pci_dev *dev)
+{
+ if (dev->revision == 0x1)
+ quirk_no_flr(dev);
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SOLIDRUN, 0x1000, quirk_no_flr_snet);
+
static void quirk_no_ext_tags(struct pci_dev *pdev)
{
struct pci_host_bridge *bridge = pci_find_host_bridge(pdev->bus);
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index b4096598dbcb..c690572b10ce 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -1765,12 +1765,70 @@ static void adjust_bridge_window(struct pci_dev *bridge, struct resource *res,
add_size = size - new_size;
pci_dbg(bridge, "bridge window %pR shrunken by %pa\n", res,
&add_size);
+ } else {
+ return;
}
res->end = res->start + new_size - 1;
- remove_from_list(add_list, res);
+
+ /* If the resource is part of the add_list, remove it now */
+ if (add_list)
+ remove_from_list(add_list, res);
+}
+
+static void remove_dev_resource(struct resource *avail, struct pci_dev *dev,
+ struct resource *res)
+{
+ resource_size_t size, align, tmp;
+
+ size = resource_size(res);
+ if (!size)
+ return;
+
+ align = pci_resource_alignment(dev, res);
+ align = align ? ALIGN(avail->start, align) - avail->start : 0;
+ tmp = align + size;
+ avail->start = min(avail->start + tmp, avail->end + 1);
+}
+
+static void remove_dev_resources(struct pci_dev *dev, struct resource *io,
+ struct resource *mmio,
+ struct resource *mmio_pref)
+{
+ int i;
+
+ for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+ struct resource *res = &dev->resource[i];
+
+ if (resource_type(res) == IORESOURCE_IO) {
+ remove_dev_resource(io, dev, res);
+ } else if (resource_type(res) == IORESOURCE_MEM) {
+
+ /*
+ * Make sure prefetchable memory is reduced from
+ * the correct resource. Specifically we put 32-bit
+ * prefetchable memory in non-prefetchable window
+ * if there is an 64-bit pretchable window.
+ *
+ * See comments in __pci_bus_size_bridges() for
+ * more information.
+ */
+ if ((res->flags & IORESOURCE_PREFETCH) &&
+ ((res->flags & IORESOURCE_MEM_64) ==
+ (mmio_pref->flags & IORESOURCE_MEM_64)))
+ remove_dev_resource(mmio_pref, dev, res);
+ else
+ remove_dev_resource(mmio, dev, res);
+ }
+ }
}
+/*
+ * io, mmio and mmio_pref contain the total amount of bridge window space
+ * available. This includes the minimal space needed to cover all the
+ * existing devices on the bus and the possible extra space that can be
+ * shared with the bridges.
+ */
static void pci_bus_distribute_available_resources(struct pci_bus *bus,
struct list_head *add_list,
struct resource io,
@@ -1780,7 +1838,7 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus,
unsigned int normal_bridges = 0, hotplug_bridges = 0;
struct resource *io_res, *mmio_res, *mmio_pref_res;
struct pci_dev *dev, *bridge = bus->self;
- resource_size_t io_per_hp, mmio_per_hp, mmio_pref_per_hp, align;
+ resource_size_t io_per_b, mmio_per_b, mmio_pref_per_b, align;
io_res = &bridge->resource[PCI_BRIDGE_IO_WINDOW];
mmio_res = &bridge->resource[PCI_BRIDGE_MEM_WINDOW];
@@ -1824,94 +1882,88 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus,
normal_bridges++;
}
+ if (!(hotplug_bridges + normal_bridges))
+ return;
+
/*
- * There is only one bridge on the bus so it gets all available
- * resources which it can then distribute to the possible hotplug
- * bridges below.
+ * Calculate the amount of space we can forward from "bus" to any
+ * downstream buses, i.e., the space left over after assigning the
+ * BARs and windows on "bus".
*/
- if (hotplug_bridges + normal_bridges == 1) {
- dev = list_first_entry(&bus->devices, struct pci_dev, bus_list);
- if (dev->subordinate)
- pci_bus_distribute_available_resources(dev->subordinate,
- add_list, io, mmio, mmio_pref);
- return;
+ list_for_each_entry(dev, &bus->devices, bus_list) {
+ if (!dev->is_virtfn)
+ remove_dev_resources(dev, &io, &mmio, &mmio_pref);
}
- if (hotplug_bridges == 0)
- return;
-
/*
- * Calculate the total amount of extra resource space we can
- * pass to bridges below this one. This is basically the
- * extra space reduced by the minimal required space for the
- * non-hotplug bridges.
+ * If there is at least one hotplug bridge on this bus it gets all
+ * the extra resource space that was left after the reductions
+ * above.
+ *
+ * If there are no hotplug bridges the extra resource space is
+ * split between non-hotplug bridges. This is to allow possible
+ * hotplug bridges below them to get the extra space as well.
*/
+ if (hotplug_bridges) {
+ io_per_b = div64_ul(resource_size(&io), hotplug_bridges);
+ mmio_per_b = div64_ul(resource_size(&mmio), hotplug_bridges);
+ mmio_pref_per_b = div64_ul(resource_size(&mmio_pref),
+ hotplug_bridges);
+ } else {
+ io_per_b = div64_ul(resource_size(&io), normal_bridges);
+ mmio_per_b = div64_ul(resource_size(&mmio), normal_bridges);
+ mmio_pref_per_b = div64_ul(resource_size(&mmio_pref),
+ normal_bridges);
+ }
+
for_each_pci_bridge(dev, bus) {
- resource_size_t used_size;
struct resource *res;
+ struct pci_bus *b;
- if (dev->is_hotplug_bridge)
+ b = dev->subordinate;
+ if (!b)
+ continue;
+ if (hotplug_bridges && !dev->is_hotplug_bridge)
continue;
+ res = &dev->resource[PCI_BRIDGE_IO_WINDOW];
+
/*
- * Reduce the available resource space by what the
- * bridge and devices below it occupy.
+ * Make sure the split resource space is properly aligned
+ * for bridge windows (align it down to avoid going above
+ * what is available).
*/
- res = &dev->resource[PCI_BRIDGE_IO_WINDOW];
align = pci_resource_alignment(dev, res);
- align = align ? ALIGN(io.start, align) - io.start : 0;
- used_size = align + resource_size(res);
- if (!res->parent)
- io.start = min(io.start + used_size, io.end + 1);
+ io.end = align ? io.start + ALIGN_DOWN(io_per_b, align) - 1
+ : io.start + io_per_b - 1;
+
+ /*
+ * The x_per_b holds the extra resource space that can be
+ * added for each bridge but there is the minimal already
+ * reserved as well so adjust x.start down accordingly to
+ * cover the whole space.
+ */
+ io.start -= resource_size(res);
res = &dev->resource[PCI_BRIDGE_MEM_WINDOW];
align = pci_resource_alignment(dev, res);
- align = align ? ALIGN(mmio.start, align) - mmio.start : 0;
- used_size = align + resource_size(res);
- if (!res->parent)
- mmio.start = min(mmio.start + used_size, mmio.end + 1);
+ mmio.end = align ? mmio.start + ALIGN_DOWN(mmio_per_b, align) - 1
+ : mmio.start + mmio_per_b - 1;
+ mmio.start -= resource_size(res);
res = &dev->resource[PCI_BRIDGE_PREF_MEM_WINDOW];
align = pci_resource_alignment(dev, res);
- align = align ? ALIGN(mmio_pref.start, align) -
- mmio_pref.start : 0;
- used_size = align + resource_size(res);
- if (!res->parent)
- mmio_pref.start = min(mmio_pref.start + used_size,
- mmio_pref.end + 1);
- }
-
- io_per_hp = div64_ul(resource_size(&io), hotplug_bridges);
- mmio_per_hp = div64_ul(resource_size(&mmio), hotplug_bridges);
- mmio_pref_per_hp = div64_ul(resource_size(&mmio_pref),
- hotplug_bridges);
-
- /*
- * Go over devices on this bus and distribute the remaining
- * resource space between hotplug bridges.
- */
- for_each_pci_bridge(dev, bus) {
- struct pci_bus *b;
-
- b = dev->subordinate;
- if (!b || !dev->is_hotplug_bridge)
- continue;
-
- /*
- * Distribute available extra resources equally between
- * hotplug-capable downstream ports taking alignment into
- * account.
- */
- io.end = io.start + io_per_hp - 1;
- mmio.end = mmio.start + mmio_per_hp - 1;
- mmio_pref.end = mmio_pref.start + mmio_pref_per_hp - 1;
+ mmio_pref.end = align ? mmio_pref.start +
+ ALIGN_DOWN(mmio_pref_per_b, align) - 1
+ : mmio_pref.start + mmio_pref_per_b - 1;
+ mmio_pref.start -= resource_size(res);
pci_bus_distribute_available_resources(b, add_list, io, mmio,
mmio_pref);
- io.start += io_per_hp;
- mmio.start += mmio_per_hp;
- mmio_pref.start += mmio_pref_per_hp;
+ io.start += io.end + 1;
+ mmio.start += mmio.end + 1;
+ mmio_pref.start += mmio_pref.end + 1;
}
}
@@ -1923,6 +1975,8 @@ static void pci_bridge_distribute_available_resources(struct pci_dev *bridge,
if (!bridge->is_hotplug_bridge)
return;
+ pci_dbg(bridge, "distributing available resources\n");
+
/* Take the initial extra resources from the hotplug port */
available_io = bridge->resource[PCI_BRIDGE_IO_WINDOW];
available_mmio = bridge->resource[PCI_BRIDGE_MEM_WINDOW];
@@ -1934,6 +1988,54 @@ static void pci_bridge_distribute_available_resources(struct pci_dev *bridge,
available_mmio_pref);
}
+static bool pci_bridge_resources_not_assigned(struct pci_dev *dev)
+{
+ const struct resource *r;
+
+ /*
+ * If the child device's resources are not yet assigned it means we
+ * are configuring them (not the boot firmware), so we should be
+ * able to extend the upstream bridge resources in the same way we
+ * do with the normal hotplug case.
+ */
+ r = &dev->resource[PCI_BRIDGE_IO_WINDOW];
+ if (r->flags && !(r->flags & IORESOURCE_STARTALIGN))
+ return false;
+ r = &dev->resource[PCI_BRIDGE_MEM_WINDOW];
+ if (r->flags && !(r->flags & IORESOURCE_STARTALIGN))
+ return false;
+ r = &dev->resource[PCI_BRIDGE_PREF_MEM_WINDOW];
+ if (r->flags && !(r->flags & IORESOURCE_STARTALIGN))
+ return false;
+
+ return true;
+}
+
+static void
+pci_root_bus_distribute_available_resources(struct pci_bus *bus,
+ struct list_head *add_list)
+{
+ struct pci_dev *dev, *bridge = bus->self;
+
+ for_each_pci_bridge(dev, bus) {
+ struct pci_bus *b;
+
+ b = dev->subordinate;
+ if (!b)
+ continue;
+
+ /*
+ * Need to check "bridge" here too because it is NULL
+ * in case of root bus.
+ */
+ if (bridge && pci_bridge_resources_not_assigned(dev))
+ pci_bridge_distribute_available_resources(bridge,
+ add_list);
+ else
+ pci_root_bus_distribute_available_resources(b, add_list);
+ }
+}
+
/*
* First try will not touch PCI bridge res.
* Second and later try will clear small leaf bridge res.
@@ -1973,6 +2075,8 @@ again:
*/
__pci_bus_size_bridges(bus, add_list);
+ pci_root_bus_distribute_available_resources(bus, add_list);
+
/* Depth last, allocate resources and update the hardware. */
__pci_bus_assign_resources(bus, add_list, &fail_head);
if (add_list)
diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c
index a0c67191a8b9..0f87cade10f7 100644
--- a/drivers/pci/slot.c
+++ b/drivers/pci/slot.c
@@ -98,7 +98,7 @@ static struct attribute *pci_slot_default_attrs[] = {
};
ATTRIBUTE_GROUPS(pci_slot_default);
-static struct kobj_type pci_slot_ktype = {
+static const struct kobj_type pci_slot_ktype = {
.sysfs_ops = &pci_slot_sysfs_ops,
.release = &pci_slot_release,
.default_groups = pci_slot_default_groups,
diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c
index 75be4fe22509..3d6f17ff2429 100644
--- a/drivers/pci/switch/switchtec.c
+++ b/drivers/pci/switch/switchtec.c
@@ -606,21 +606,20 @@ static ssize_t switchtec_dev_read(struct file *filp, char __user *data,
rc = copy_to_user(data, &stuser->return_code,
sizeof(stuser->return_code));
if (rc) {
- rc = -EFAULT;
- goto out;
+ mutex_unlock(&stdev->mrpc_mutex);
+ return -EFAULT;
}
data += sizeof(stuser->return_code);
rc = copy_to_user(data, &stuser->data,
size - sizeof(stuser->return_code));
if (rc) {
- rc = -EFAULT;
- goto out;
+ mutex_unlock(&stdev->mrpc_mutex);
+ return -EFAULT;
}
stuser_set_state(stuser, MRPC_IDLE);
-out:
mutex_unlock(&stdev->mrpc_mutex);
if (stuser->status == SWITCHTEC_MRPC_STATUS_DONE ||
@@ -1480,15 +1479,13 @@ static irqreturn_t switchtec_event_isr(int irq, void *dev)
static irqreturn_t switchtec_dma_mrpc_isr(int irq, void *dev)
{
struct switchtec_dev *stdev = dev;
- irqreturn_t ret = IRQ_NONE;
iowrite32(SWITCHTEC_EVENT_CLEAR |
SWITCHTEC_EVENT_EN_IRQ,
&stdev->mmio_part_cfg->mrpc_comp_hdr);
schedule_work(&stdev->mrpc_work);
- ret = IRQ_HANDLED;
- return ret;
+ return IRQ_HANDLED;
}
static int switchtec_init_isr(struct switchtec_dev *stdev)
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index ace133b9f7d4..c8087efa5e4a 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -927,9 +927,9 @@ static int pcmcia_bus_match(struct device *dev, struct device_driver *drv)
return 0;
}
-static int pcmcia_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int pcmcia_bus_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct pcmcia_device *p_dev;
+ const struct pcmcia_device *p_dev;
int i;
u32 hash[4] = { 0, 0, 0, 0};
diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c
index 7b2288d4b1ec..70cb50fd41c2 100644
--- a/drivers/perf/riscv_pmu_sbi.c
+++ b/drivers/perf/riscv_pmu_sbi.c
@@ -44,7 +44,7 @@ static const struct attribute_group *riscv_pmu_attr_groups[] = {
};
/*
- * RISC-V doesn't have hetergenous harts yet. This need to be part of
+ * RISC-V doesn't have heterogeneous harts yet. This need to be part of
* per_cpu in case of harts with different pmu counters
*/
static union sbi_pmu_ctr_info *pmu_ctr_list;
@@ -52,6 +52,9 @@ static bool riscv_pmu_use_irq;
static unsigned int riscv_pmu_irq_num;
static unsigned int riscv_pmu_irq;
+/* Cache the available counters in a bitmask */
+static unsigned long cmask;
+
struct sbi_pmu_event_data {
union {
union {
@@ -267,6 +270,58 @@ static bool pmu_sbi_ctr_is_fw(int cidx)
return (info->type == SBI_PMU_CTR_TYPE_FW) ? true : false;
}
+/*
+ * Returns the counter width of a programmable counter and number of hardware
+ * counters. As we don't support heterogeneous CPUs yet, it is okay to just
+ * return the counter width of the first programmable counter.
+ */
+int riscv_pmu_get_hpm_info(u32 *hw_ctr_width, u32 *num_hw_ctr)
+{
+ int i;
+ union sbi_pmu_ctr_info *info;
+ u32 hpm_width = 0, hpm_count = 0;
+
+ if (!cmask)
+ return -EINVAL;
+
+ for_each_set_bit(i, &cmask, RISCV_MAX_COUNTERS) {
+ info = &pmu_ctr_list[i];
+ if (!info)
+ continue;
+ if (!hpm_width && info->csr != CSR_CYCLE && info->csr != CSR_INSTRET)
+ hpm_width = info->width;
+ if (info->type == SBI_PMU_CTR_TYPE_HW)
+ hpm_count++;
+ }
+
+ *hw_ctr_width = hpm_width;
+ *num_hw_ctr = hpm_count;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(riscv_pmu_get_hpm_info);
+
+static unsigned long pmu_sbi_get_filter_flags(struct perf_event *event)
+{
+ unsigned long cflags = 0;
+ bool guest_events = false;
+
+ if (event->attr.config1 & RISCV_PMU_CONFIG1_GUEST_EVENTS)
+ guest_events = true;
+ if (event->attr.exclude_kernel)
+ cflags |= guest_events ? SBI_PMU_CFG_FLAG_SET_VSINH : SBI_PMU_CFG_FLAG_SET_SINH;
+ if (event->attr.exclude_user)
+ cflags |= guest_events ? SBI_PMU_CFG_FLAG_SET_VUINH : SBI_PMU_CFG_FLAG_SET_UINH;
+ if (guest_events && event->attr.exclude_hv)
+ cflags |= SBI_PMU_CFG_FLAG_SET_SINH;
+ if (event->attr.exclude_host)
+ cflags |= SBI_PMU_CFG_FLAG_SET_UINH | SBI_PMU_CFG_FLAG_SET_SINH;
+ if (event->attr.exclude_guest)
+ cflags |= SBI_PMU_CFG_FLAG_SET_VSINH | SBI_PMU_CFG_FLAG_SET_VUINH;
+
+ return cflags;
+}
+
static int pmu_sbi_ctr_get_idx(struct perf_event *event)
{
struct hw_perf_event *hwc = &event->hw;
@@ -277,11 +332,7 @@ static int pmu_sbi_ctr_get_idx(struct perf_event *event)
uint64_t cbase = 0;
unsigned long cflags = 0;
- if (event->attr.exclude_kernel)
- cflags |= SBI_PMU_CFG_FLAG_SET_SINH;
- if (event->attr.exclude_user)
- cflags |= SBI_PMU_CFG_FLAG_SET_UINH;
-
+ cflags = pmu_sbi_get_filter_flags(event);
/* retrieve the available counter index */
#if defined(CONFIG_32BIT)
ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_CFG_MATCH, cbase,
@@ -385,11 +436,8 @@ static int pmu_sbi_event_map(struct perf_event *event, u64 *econfig)
bSoftware = config >> 63;
raw_config_val = config & RISCV_PMU_RAW_EVENT_MASK;
if (bSoftware) {
- if (raw_config_val < SBI_PMU_FW_MAX)
- ret = (raw_config_val & 0xFFFF) |
- (SBI_PMU_EVENT_TYPE_FW << 16);
- else
- return -EINVAL;
+ ret = (raw_config_val & 0xFFFF) |
+ (SBI_PMU_EVENT_TYPE_FW << 16);
} else {
ret = RISCV_PMU_RAW_EVENT_IDX;
*econfig = raw_config_val;
@@ -806,7 +854,6 @@ static void riscv_pmu_destroy(struct riscv_pmu *pmu)
static int pmu_sbi_device_probe(struct platform_device *pdev)
{
struct riscv_pmu *pmu = NULL;
- unsigned long cmask = 0;
int ret = -ENODEV;
int num_counters;
diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c
index 5472db9e87ef..fbcd7014ab43 100644
--- a/drivers/phy/allwinner/phy-sun4i-usb.c
+++ b/drivers/phy/allwinner/phy-sun4i-usb.c
@@ -99,28 +99,17 @@
#define DEBOUNCE_TIME msecs_to_jiffies(50)
#define POLL_TIME msecs_to_jiffies(250)
-enum sun4i_usb_phy_type {
- sun4i_a10_phy,
- sun6i_a31_phy,
- sun8i_a33_phy,
- sun8i_a83t_phy,
- sun8i_h3_phy,
- sun8i_r40_phy,
- sun8i_v3s_phy,
- sun50i_a64_phy,
- sun50i_h6_phy,
-};
-
struct sun4i_usb_phy_cfg {
int num_phys;
int hsic_index;
- enum sun4i_usb_phy_type type;
u32 disc_thresh;
u32 hci_phy_ctl_clear;
u8 phyctl_offset;
bool dedicated_clocks;
bool phy0_dual_route;
bool needs_phy2_siddq;
+ bool siddq_in_base;
+ bool poll_vbusen;
int missing_phys;
};
@@ -252,7 +241,8 @@ static void sun4i_usb_phy_passby(struct sun4i_usb_phy *phy, int enable)
SUNXI_AHB_INCRX_ALIGN_EN | SUNXI_ULPI_BYPASS_EN;
/* A83T USB2 is HSIC */
- if (phy_data->cfg->type == sun8i_a83t_phy && phy->index == 2)
+ if (phy_data->cfg->hsic_index &&
+ phy->index == phy_data->cfg->hsic_index)
bits |= SUNXI_EHCI_HS_FORCE | SUNXI_HSIC_CONNECT_INT |
SUNXI_HSIC;
@@ -340,8 +330,7 @@ static int sun4i_usb_phy_init(struct phy *_phy)
writel(val, phy->pmu + REG_HCI_PHY_CTL);
}
- if (data->cfg->type == sun8i_a83t_phy ||
- data->cfg->type == sun50i_h6_phy) {
+ if (data->cfg->siddq_in_base) {
if (phy->index == 0) {
val = readl(data->base + data->cfg->phyctl_offset);
val |= PHY_CTL_VBUSVLDEXT;
@@ -385,8 +374,7 @@ static int sun4i_usb_phy_exit(struct phy *_phy)
struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy);
if (phy->index == 0) {
- if (data->cfg->type == sun8i_a83t_phy ||
- data->cfg->type == sun50i_h6_phy) {
+ if (data->cfg->siddq_in_base) {
void __iomem *phyctl = data->base +
data->cfg->phyctl_offset;
@@ -466,9 +454,8 @@ static bool sun4i_usb_phy0_poll(struct sun4i_usb_phy_data *data)
* vbus using the N_VBUSEN pin on the pmic, so we must poll
* when using the pmic for vbus-det _and_ we're driving vbus.
*/
- if ((data->cfg->type == sun6i_a31_phy ||
- data->cfg->type == sun8i_a33_phy) &&
- data->vbus_power_supply && data->phys[0].regulator_on)
+ if (data->cfg->poll_vbusen && data->vbus_power_supply &&
+ data->phys[0].regulator_on)
return true;
return false;
@@ -918,9 +905,15 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
return 0;
}
+static const struct sun4i_usb_phy_cfg suniv_f1c100s_cfg = {
+ .num_phys = 1,
+ .disc_thresh = 3,
+ .phyctl_offset = REG_PHYCTL_A10,
+ .dedicated_clocks = true,
+};
+
static const struct sun4i_usb_phy_cfg sun4i_a10_cfg = {
.num_phys = 3,
- .type = sun4i_a10_phy,
.disc_thresh = 3,
.phyctl_offset = REG_PHYCTL_A10,
.dedicated_clocks = false,
@@ -928,7 +921,6 @@ static const struct sun4i_usb_phy_cfg sun4i_a10_cfg = {
static const struct sun4i_usb_phy_cfg sun5i_a13_cfg = {
.num_phys = 2,
- .type = sun4i_a10_phy,
.disc_thresh = 2,
.phyctl_offset = REG_PHYCTL_A10,
.dedicated_clocks = false,
@@ -936,15 +928,14 @@ static const struct sun4i_usb_phy_cfg sun5i_a13_cfg = {
static const struct sun4i_usb_phy_cfg sun6i_a31_cfg = {
.num_phys = 3,
- .type = sun6i_a31_phy,
.disc_thresh = 3,
.phyctl_offset = REG_PHYCTL_A10,
.dedicated_clocks = true,
+ .poll_vbusen = true,
};
static const struct sun4i_usb_phy_cfg sun7i_a20_cfg = {
.num_phys = 3,
- .type = sun4i_a10_phy,
.disc_thresh = 2,
.phyctl_offset = REG_PHYCTL_A10,
.dedicated_clocks = false,
@@ -952,31 +943,30 @@ static const struct sun4i_usb_phy_cfg sun7i_a20_cfg = {
static const struct sun4i_usb_phy_cfg sun8i_a23_cfg = {
.num_phys = 2,
- .type = sun6i_a31_phy,
.disc_thresh = 3,
.phyctl_offset = REG_PHYCTL_A10,
.dedicated_clocks = true,
+ .poll_vbusen = true,
};
static const struct sun4i_usb_phy_cfg sun8i_a33_cfg = {
.num_phys = 2,
- .type = sun8i_a33_phy,
.disc_thresh = 3,
.phyctl_offset = REG_PHYCTL_A33,
.dedicated_clocks = true,
+ .poll_vbusen = true,
};
static const struct sun4i_usb_phy_cfg sun8i_a83t_cfg = {
.num_phys = 3,
.hsic_index = 2,
- .type = sun8i_a83t_phy,
.phyctl_offset = REG_PHYCTL_A33,
.dedicated_clocks = true,
+ .siddq_in_base = true,
};
static const struct sun4i_usb_phy_cfg sun8i_h3_cfg = {
.num_phys = 4,
- .type = sun8i_h3_phy,
.disc_thresh = 3,
.phyctl_offset = REG_PHYCTL_A33,
.dedicated_clocks = true,
@@ -986,7 +976,6 @@ static const struct sun4i_usb_phy_cfg sun8i_h3_cfg = {
static const struct sun4i_usb_phy_cfg sun8i_r40_cfg = {
.num_phys = 3,
- .type = sun8i_r40_phy,
.disc_thresh = 3,
.phyctl_offset = REG_PHYCTL_A33,
.dedicated_clocks = true,
@@ -996,7 +985,6 @@ static const struct sun4i_usb_phy_cfg sun8i_r40_cfg = {
static const struct sun4i_usb_phy_cfg sun8i_v3s_cfg = {
.num_phys = 1,
- .type = sun8i_v3s_phy,
.disc_thresh = 3,
.phyctl_offset = REG_PHYCTL_A33,
.dedicated_clocks = true,
@@ -1006,16 +994,15 @@ static const struct sun4i_usb_phy_cfg sun8i_v3s_cfg = {
static const struct sun4i_usb_phy_cfg sun20i_d1_cfg = {
.num_phys = 2,
- .type = sun50i_h6_phy,
.phyctl_offset = REG_PHYCTL_A33,
.dedicated_clocks = true,
.hci_phy_ctl_clear = PHY_CTL_SIDDQ,
.phy0_dual_route = true,
+ .siddq_in_base = true,
};
static const struct sun4i_usb_phy_cfg sun50i_a64_cfg = {
.num_phys = 2,
- .type = sun50i_a64_phy,
.disc_thresh = 3,
.phyctl_offset = REG_PHYCTL_A33,
.dedicated_clocks = true,
@@ -1025,22 +1012,22 @@ static const struct sun4i_usb_phy_cfg sun50i_a64_cfg = {
static const struct sun4i_usb_phy_cfg sun50i_h6_cfg = {
.num_phys = 4,
- .type = sun50i_h6_phy,
.phyctl_offset = REG_PHYCTL_A33,
.dedicated_clocks = true,
.phy0_dual_route = true,
.missing_phys = BIT(1) | BIT(2),
+ .siddq_in_base = true,
};
static const struct sun4i_usb_phy_cfg sun50i_h616_cfg = {
.num_phys = 4,
- .type = sun50i_h6_phy,
.disc_thresh = 3,
.phyctl_offset = REG_PHYCTL_A33,
.dedicated_clocks = true,
.phy0_dual_route = true,
.hci_phy_ctl_clear = PHY_CTL_SIDDQ,
.needs_phy2_siddq = true,
+ .siddq_in_base = true,
};
static const struct of_device_id sun4i_usb_phy_of_match[] = {
@@ -1059,6 +1046,8 @@ static const struct of_device_id sun4i_usb_phy_of_match[] = {
.data = &sun50i_a64_cfg},
{ .compatible = "allwinner,sun50i-h6-usb-phy", .data = &sun50i_h6_cfg },
{ .compatible = "allwinner,sun50i-h616-usb-phy", .data = &sun50i_h616_cfg },
+ { .compatible = "allwinner,suniv-f1c100s-usb-phy",
+ .data = &suniv_f1c100s_cfg },
{ },
};
MODULE_DEVICE_TABLE(of, sun4i_usb_phy_of_match);
diff --git a/drivers/phy/mediatek/phy-mtk-io.h b/drivers/phy/mediatek/phy-mtk-io.h
index d20ad5e5be81..58f06db822cb 100644
--- a/drivers/phy/mediatek/phy-mtk-io.h
+++ b/drivers/phy/mediatek/phy-mtk-io.h
@@ -39,8 +39,8 @@ static inline void mtk_phy_update_bits(void __iomem *reg, u32 mask, u32 val)
/* field @mask shall be constant and continuous */
#define mtk_phy_update_field(reg, mask, val) \
({ \
- typeof(mask) mask_ = (mask); \
- mtk_phy_update_bits(reg, mask_, FIELD_PREP(mask_, val)); \
+ BUILD_BUG_ON_MSG(!__builtin_constant_p(mask), "mask is not constant"); \
+ mtk_phy_update_bits(reg, mask, FIELD_PREP(mask, val)); \
})
#endif
diff --git a/drivers/phy/phy-can-transceiver.c b/drivers/phy/phy-can-transceiver.c
index ce511ad5d369..5487b9dd1ead 100644
--- a/drivers/phy/phy-can-transceiver.c
+++ b/drivers/phy/phy-can-transceiver.c
@@ -84,6 +84,10 @@ static const struct of_device_id can_transceiver_phy_ids[] = {
.compatible = "ti,tcan1043",
.data = &tcan1043_drvdata
},
+ {
+ .compatible = "nxp,tjr1443",
+ .data = &tcan1043_drvdata
+ },
{ }
};
MODULE_DEVICE_TABLE(of, can_transceiver_phy_ids);
diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
index d93ddf1262c5..9951efc03eaa 100644
--- a/drivers/phy/phy-core.c
+++ b/drivers/phy/phy-core.c
@@ -767,27 +767,6 @@ struct phy *phy_get(struct device *dev, const char *string)
EXPORT_SYMBOL_GPL(phy_get);
/**
- * phy_optional_get() - lookup and obtain a reference to an optional phy.
- * @dev: device that requests this phy
- * @string: the phy name as given in the dt data or the name of the controller
- * port for non-dt case
- *
- * Returns the phy driver, after getting a refcount to it; or
- * NULL if there is no such phy. The caller is responsible for
- * calling phy_put() to release that count.
- */
-struct phy *phy_optional_get(struct device *dev, const char *string)
-{
- struct phy *phy = phy_get(dev, string);
-
- if (PTR_ERR(phy) == -ENODEV)
- phy = NULL;
-
- return phy;
-}
-EXPORT_SYMBOL_GPL(phy_optional_get);
-
-/**
* devm_phy_get() - lookup and obtain a reference to a phy.
* @dev: device that requests this phy
* @string: the phy name as given in the dt data or phy device name
@@ -880,6 +859,36 @@ struct phy *devm_of_phy_get(struct device *dev, struct device_node *np,
EXPORT_SYMBOL_GPL(devm_of_phy_get);
/**
+ * devm_of_phy_optional_get() - lookup and obtain a reference to an optional
+ * phy.
+ * @dev: device that requests this phy
+ * @np: node containing the phy
+ * @con_id: name of the phy from device's point of view
+ *
+ * Gets the phy using of_phy_get(), and associates a device with it using
+ * devres. On driver detach, release function is invoked on the devres data,
+ * then, devres data is freed. This differs to devm_of_phy_get() in
+ * that if the phy does not exist, it is not considered an error and
+ * -ENODEV will not be returned. Instead the NULL phy is returned,
+ * which can be passed to all other phy consumer calls.
+ */
+struct phy *devm_of_phy_optional_get(struct device *dev, struct device_node *np,
+ const char *con_id)
+{
+ struct phy *phy = devm_of_phy_get(dev, np, con_id);
+
+ if (PTR_ERR(phy) == -ENODEV)
+ phy = NULL;
+
+ if (IS_ERR(phy))
+ dev_err_probe(dev, PTR_ERR(phy), "failed to get PHY %pOF:%s",
+ np, con_id);
+
+ return phy;
+}
+EXPORT_SYMBOL_GPL(devm_of_phy_optional_get);
+
+/**
* devm_of_phy_get_by_index() - lookup and obtain a reference to a phy by index.
* @dev: device that requests this phy
* @np: node containing the phy
diff --git a/drivers/phy/qualcomm/Kconfig b/drivers/phy/qualcomm/Kconfig
index eb9ddc685b38..4850d48f31fa 100644
--- a/drivers/phy/qualcomm/Kconfig
+++ b/drivers/phy/qualcomm/Kconfig
@@ -50,14 +50,56 @@ config PHY_QCOM_PCIE2
Enable this to support the Qualcomm PCIe PHY, used with the Synopsys
based PCIe controller.
-config PHY_QCOM_QMP
- tristate "Qualcomm QMP PHY Driver"
+menuconfig PHY_QCOM_QMP
+ tristate "Qualcomm QMP PHY Drivers"
depends on OF && COMMON_CLK && (ARCH_QCOM || COMPILE_TEST)
+
+if PHY_QCOM_QMP
+
+config PHY_QCOM_QMP_COMBO
+ tristate "Qualcomm QMP Combo PHY Driver"
+ default PHY_QCOM_QMP
select GENERIC_PHY
select MFD_SYSCON
help
- Enable this to support the QMP PHY transceiver that is used
- with controllers such as PCIe, UFS, and USB on Qualcomm chips.
+ Enable this to support the QMP Combo PHY transceiver that is used
+ with USB3 and DisplayPort controllers on Qualcomm chips.
+
+config PHY_QCOM_QMP_PCIE
+ tristate "Qualcomm QMP PCIe PHY Driver"
+ depends on PCI || COMPILE_TEST
+ select GENERIC_PHY
+ default PHY_QCOM_QMP
+ help
+ Enable this to support the QMP PCIe PHY transceiver that is used
+ with PCIe controllers on Qualcomm chips.
+
+config PHY_QCOM_QMP_PCIE_8996
+ tristate "Qualcomm QMP PCIe 8996 PHY Driver"
+ depends on PCI || COMPILE_TEST
+ select GENERIC_PHY
+ default PHY_QCOM_QMP
+ help
+ Enable this to support the QMP PCIe PHY transceiver that is used
+ with PCIe controllers on Qualcomm msm8996 chips.
+
+config PHY_QCOM_QMP_UFS
+ tristate "Qualcomm QMP UFS PHY Driver"
+ select GENERIC_PHY
+ default PHY_QCOM_QMP
+ help
+ Enable this to support the QMP UFS PHY transceiver that is used
+ with UFS controllers on Qualcomm chips.
+
+config PHY_QCOM_QMP_USB
+ tristate "Qualcomm QMP USB PHY Driver"
+ select GENERIC_PHY
+ default PHY_QCOM_QMP
+ help
+ Enable this to support the QMP USB PHY transceiver that is used
+ with USB3 controllers on Qualcomm chips.
+
+endif # PHY_QCOM_QMP
config PHY_QCOM_QUSB2
tristate "Qualcomm QUSB2 PHY Driver"
@@ -70,6 +112,24 @@ config PHY_QCOM_QUSB2
PHY which is usually paired with either the ChipIdea or Synopsys DWC3
USB IPs on MSM SOCs.
+config PHY_QCOM_SNPS_EUSB2
+ tristate "Qualcomm SNPS eUSB2 PHY Driver"
+ depends on OF && (ARCH_QCOM || COMPILE_TEST)
+ select GENERIC_PHY
+ help
+ Enable support for the USB high-speed SNPS eUSB2 phy on Qualcomm
+ chipsets. The PHY is paired with a Synopsys DWC3 USB controller
+ on Qualcomm SOCs.
+
+config PHY_QCOM_EUSB2_REPEATER
+ tristate "Qualcomm SNPS eUSB2 Repeater Driver"
+ depends on OF && (ARCH_QCOM || COMPILE_TEST)
+ select GENERIC_PHY
+ help
+ Enable support for the USB high-speed SNPS eUSB2 repeater on Qualcomm
+ PMICs. The repeater is paired with a Synopsys eUSB2 Phy
+ on Qualcomm SOCs.
+
config PHY_QCOM_USB_HS
tristate "Qualcomm USB HS PHY module"
depends on USB_ULPI_BUS
diff --git a/drivers/phy/qualcomm/Makefile b/drivers/phy/qualcomm/Makefile
index 65f6c30a3e93..de3dc9ccf067 100644
--- a/drivers/phy/qualcomm/Makefile
+++ b/drivers/phy/qualcomm/Makefile
@@ -5,14 +5,16 @@ obj-$(CONFIG_PHY_QCOM_EDP) += phy-qcom-edp.o
obj-$(CONFIG_PHY_QCOM_IPQ4019_USB) += phy-qcom-ipq4019-usb.o
obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o
obj-$(CONFIG_PHY_QCOM_PCIE2) += phy-qcom-pcie2.o
-obj-$(CONFIG_PHY_QCOM_QMP) += \
- phy-qcom-qmp-combo.o \
- phy-qcom-qmp-pcie.o \
- phy-qcom-qmp-pcie-msm8996.o \
- phy-qcom-qmp-ufs.o \
- phy-qcom-qmp-usb.o
+
+obj-$(CONFIG_PHY_QCOM_QMP_COMBO) += phy-qcom-qmp-combo.o
+obj-$(CONFIG_PHY_QCOM_QMP_PCIE) += phy-qcom-qmp-pcie.o
+obj-$(CONFIG_PHY_QCOM_QMP_PCIE_8996) += phy-qcom-qmp-pcie-msm8996.o
+obj-$(CONFIG_PHY_QCOM_QMP_UFS) += phy-qcom-qmp-ufs.o
+obj-$(CONFIG_PHY_QCOM_QMP_USB) += phy-qcom-qmp-usb.o
obj-$(CONFIG_PHY_QCOM_QUSB2) += phy-qcom-qusb2.o
+obj-$(CONFIG_PHY_QCOM_SNPS_EUSB2) += phy-qcom-snps-eusb2.o
+obj-$(CONFIG_PHY_QCOM_EUSB2_REPEATER) += phy-qcom-eusb2-repeater.o
obj-$(CONFIG_PHY_QCOM_USB_HS) += phy-qcom-usb-hs.o
obj-$(CONFIG_PHY_QCOM_USB_HSIC) += phy-qcom-usb-hsic.o
obj-$(CONFIG_PHY_QCOM_USB_HS_28NM) += phy-qcom-usb-hs-28nm.o
diff --git a/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c b/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c
new file mode 100644
index 000000000000..3f265ac2df20
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c
@@ -0,0 +1,259 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2023, Linaro Limited
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regmap.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/phy/phy.h>
+
+/* eUSB2 status registers */
+#define EUSB2_RPTR_STATUS 0x08
+#define RPTR_OK BIT(7)
+
+/* eUSB2 control registers */
+#define EUSB2_EN_CTL1 0x46
+#define EUSB2_RPTR_EN BIT(7)
+
+#define EUSB2_FORCE_EN_5 0xe8
+#define F_CLK_19P2M_EN BIT(6)
+
+#define EUSB2_FORCE_VAL_5 0xeD
+#define V_CLK_19P2M_EN BIT(6)
+
+#define EUSB2_TUNE_IUSB2 0x51
+#define EUSB2_TUNE_SQUELCH_U 0x54
+#define EUSB2_TUNE_USB2_PREEM 0x57
+
+#define QCOM_EUSB2_REPEATER_INIT_CFG(o, v) \
+ { \
+ .offset = o, \
+ .val = v, \
+ }
+
+struct eusb2_repeater_init_tbl {
+ unsigned int offset;
+ unsigned int val;
+};
+
+struct eusb2_repeater_cfg {
+ const struct eusb2_repeater_init_tbl *init_tbl;
+ int init_tbl_num;
+ const char * const *vreg_list;
+ int num_vregs;
+};
+
+struct eusb2_repeater {
+ struct device *dev;
+ struct regmap *regmap;
+ struct phy *phy;
+ struct regulator_bulk_data *vregs;
+ const struct eusb2_repeater_cfg *cfg;
+ u16 base;
+ enum phy_mode mode;
+};
+
+static const char * const pm8550b_vreg_l[] = {
+ "vdd18", "vdd3",
+};
+
+static const struct eusb2_repeater_init_tbl pm8550b_init_tbl[] = {
+ QCOM_EUSB2_REPEATER_INIT_CFG(EUSB2_TUNE_IUSB2, 0x8),
+ QCOM_EUSB2_REPEATER_INIT_CFG(EUSB2_TUNE_SQUELCH_U, 0x3),
+ QCOM_EUSB2_REPEATER_INIT_CFG(EUSB2_TUNE_USB2_PREEM, 0x5),
+};
+
+static const struct eusb2_repeater_cfg pm8550b_eusb2_cfg = {
+ .init_tbl = pm8550b_init_tbl,
+ .init_tbl_num = ARRAY_SIZE(pm8550b_init_tbl),
+ .vreg_list = pm8550b_vreg_l,
+ .num_vregs = ARRAY_SIZE(pm8550b_vreg_l),
+};
+
+static int eusb2_repeater_init_vregs(struct eusb2_repeater *rptr)
+{
+ int num = rptr->cfg->num_vregs;
+ struct device *dev = rptr->dev;
+ int i;
+
+ rptr->vregs = devm_kcalloc(dev, num, sizeof(*rptr->vregs), GFP_KERNEL);
+ if (!rptr->vregs)
+ return -ENOMEM;
+
+ for (i = 0; i < num; i++)
+ rptr->vregs[i].supply = rptr->cfg->vreg_list[i];
+
+ return devm_regulator_bulk_get(dev, num, rptr->vregs);
+}
+
+static int eusb2_repeater_init(struct phy *phy)
+{
+ struct eusb2_repeater *rptr = phy_get_drvdata(phy);
+ const struct eusb2_repeater_init_tbl *init_tbl = rptr->cfg->init_tbl;
+ int num = rptr->cfg->init_tbl_num;
+ u32 val;
+ int ret;
+ int i;
+
+ ret = regulator_bulk_enable(rptr->cfg->num_vregs, rptr->vregs);
+ if (ret)
+ return ret;
+
+ regmap_update_bits(rptr->regmap, rptr->base + EUSB2_EN_CTL1,
+ EUSB2_RPTR_EN, EUSB2_RPTR_EN);
+
+ for (i = 0; i < num; i++)
+ regmap_update_bits(rptr->regmap,
+ rptr->base + init_tbl[i].offset,
+ init_tbl[i].val, init_tbl[i].val);
+
+ ret = regmap_read_poll_timeout(rptr->regmap,
+ rptr->base + EUSB2_RPTR_STATUS, val,
+ val & RPTR_OK, 10, 5);
+ if (ret)
+ dev_err(rptr->dev, "initialization timed-out\n");
+
+ return ret;
+}
+
+static int eusb2_repeater_set_mode(struct phy *phy,
+ enum phy_mode mode, int submode)
+{
+ struct eusb2_repeater *rptr = phy_get_drvdata(phy);
+
+ switch (mode) {
+ case PHY_MODE_USB_HOST:
+ /*
+ * CM.Lx is prohibited when repeater is already into Lx state as
+ * per eUSB 1.2 Spec. Below implement software workaround until
+ * PHY and controller is fixing seen observation.
+ */
+ regmap_update_bits(rptr->regmap, rptr->base + EUSB2_FORCE_EN_5,
+ F_CLK_19P2M_EN, F_CLK_19P2M_EN);
+ regmap_update_bits(rptr->regmap, rptr->base + EUSB2_FORCE_VAL_5,
+ V_CLK_19P2M_EN, V_CLK_19P2M_EN);
+ break;
+ case PHY_MODE_USB_DEVICE:
+ /*
+ * In device mode clear host mode related workaround as there
+ * is no repeater reset available, and enable/disable of
+ * repeater doesn't clear previous value due to shared
+ * regulators (say host <-> device mode switch).
+ */
+ regmap_update_bits(rptr->regmap, rptr->base + EUSB2_FORCE_EN_5,
+ F_CLK_19P2M_EN, 0);
+ regmap_update_bits(rptr->regmap, rptr->base + EUSB2_FORCE_VAL_5,
+ V_CLK_19P2M_EN, 0);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int eusb2_repeater_exit(struct phy *phy)
+{
+ struct eusb2_repeater *rptr = phy_get_drvdata(phy);
+
+ return regulator_bulk_disable(rptr->cfg->num_vregs, rptr->vregs);
+}
+
+static const struct phy_ops eusb2_repeater_ops = {
+ .init = eusb2_repeater_init,
+ .exit = eusb2_repeater_exit,
+ .set_mode = eusb2_repeater_set_mode,
+ .owner = THIS_MODULE,
+};
+
+static int eusb2_repeater_probe(struct platform_device *pdev)
+{
+ struct eusb2_repeater *rptr;
+ struct device *dev = &pdev->dev;
+ struct phy_provider *phy_provider;
+ struct device_node *np = dev->of_node;
+ u32 res;
+ int ret;
+
+ rptr = devm_kzalloc(dev, sizeof(*rptr), GFP_KERNEL);
+ if (!rptr)
+ return -ENOMEM;
+
+ rptr->dev = dev;
+ dev_set_drvdata(dev, rptr);
+
+ rptr->cfg = of_device_get_match_data(dev);
+ if (!rptr->cfg)
+ return -EINVAL;
+
+ rptr->regmap = dev_get_regmap(dev->parent, NULL);
+ if (!rptr->regmap)
+ return -ENODEV;
+
+ ret = of_property_read_u32(np, "reg", &res);
+ if (ret < 0)
+ return ret;
+
+ rptr->base = res;
+
+ ret = eusb2_repeater_init_vregs(rptr);
+ if (ret < 0) {
+ dev_err(dev, "unable to get supplies\n");
+ return ret;
+ }
+
+ rptr->phy = devm_phy_create(dev, np, &eusb2_repeater_ops);
+ if (IS_ERR(rptr->phy)) {
+ dev_err(dev, "failed to create PHY: %d\n", ret);
+ return PTR_ERR(rptr->phy);
+ }
+
+ phy_set_drvdata(rptr->phy, rptr);
+
+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+ if (IS_ERR(phy_provider))
+ return PTR_ERR(phy_provider);
+
+ dev_info(dev, "Registered Qcom-eUSB2 repeater\n");
+
+ return 0;
+}
+
+static int eusb2_repeater_remove(struct platform_device *pdev)
+{
+ struct eusb2_repeater *rptr = platform_get_drvdata(pdev);
+
+ if (!rptr)
+ return 0;
+
+ eusb2_repeater_exit(rptr->phy);
+
+ return 0;
+}
+
+static const struct of_device_id eusb2_repeater_of_match_table[] = {
+ {
+ .compatible = "qcom,pm8550b-eusb2-repeater",
+ .data = &pm8550b_eusb2_cfg,
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, eusb2_repeater_of_match_table);
+
+static struct platform_driver eusb2_repeater_driver = {
+ .probe = eusb2_repeater_probe,
+ .remove = eusb2_repeater_remove,
+ .driver = {
+ .name = "qcom-eusb2-repeater",
+ .of_match_table = eusb2_repeater_of_match_table,
+ },
+};
+
+module_platform_driver(eusb2_repeater_driver);
+
+MODULE_DESCRIPTION("Qualcomm PMIC eUSB2 Repeater driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/phy/qualcomm/phy-qcom-pcie2.c b/drivers/phy/qualcomm/phy-qcom-pcie2.c
index 5407e59bb185..11a2bb958681 100644
--- a/drivers/phy/qualcomm/phy-qcom-pcie2.c
+++ b/drivers/phy/qualcomm/phy-qcom-pcie2.c
@@ -243,7 +243,11 @@ static int phy_pipe_clksrc_register(struct qcom_phy *qphy)
fixed->fixed_rate = 250000000;
fixed->hw.init = &init;
- return devm_clk_hw_register(qphy->dev, &fixed->hw);
+ ret = devm_clk_hw_register(qphy->dev, &fixed->hw);
+ if (ret < 0)
+ return ret;
+
+ return devm_of_clk_add_hw_provider(qphy->dev, of_clk_hw_simple_get, &fixed->hw);
}
static int qcom_pcie2_phy_probe(struct platform_device *pdev)
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
index 77052c66cf70..c1483e157af4 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
@@ -23,6 +23,10 @@
#include <dt-bindings/phy/phy-qcom-qmp.h>
#include "phy-qcom-qmp.h"
+#include "phy-qcom-qmp-pcs-misc-v3.h"
+#include "phy-qcom-qmp-pcs-usb-v4.h"
+#include "phy-qcom-qmp-pcs-usb-v5.h"
+#include "phy-qcom-qmp-pcs-usb-v6.h"
/* QPHY_SW_RESET bit */
#define SW_RESET BIT(0)
@@ -56,9 +60,6 @@
/* QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR register bits */
#define IRQ_CLEAR BIT(0)
-/* QPHY_PCS_LFPS_RXTERM_IRQ_STATUS register bits */
-#define RCVR_DETECT BIT(0)
-
/* QPHY_V3_PCS_MISC_CLAMP_ENABLE register bits */
#define CLAMP_EN BIT(0) /* enables i/o clamp_n */
@@ -96,31 +97,29 @@ enum qphy_reg_layout {
QPHY_PCS_STATUS,
QPHY_PCS_AUTONOMOUS_MODE_CTRL,
QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR,
- QPHY_PCS_LFPS_RXTERM_IRQ_STATUS,
QPHY_PCS_POWER_DOWN_CONTROL,
/* Keep last to ensure regs_layout arrays are properly initialized */
QPHY_LAYOUT_SIZE
};
static const unsigned int qmp_v3_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = {
- [QPHY_SW_RESET] = 0x00,
- [QPHY_START_CTRL] = 0x08,
- [QPHY_PCS_STATUS] = 0x174,
- [QPHY_PCS_POWER_DOWN_CONTROL] = 0x04,
- [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = 0x0d8,
- [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = 0x0dc,
- [QPHY_PCS_LFPS_RXTERM_IRQ_STATUS] = 0x170,
+ [QPHY_SW_RESET] = QPHY_V3_PCS_SW_RESET,
+ [QPHY_START_CTRL] = QPHY_V3_PCS_START_CONTROL,
+ [QPHY_PCS_STATUS] = QPHY_V3_PCS_PCS_STATUS,
+ [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V3_PCS_POWER_DOWN_CONTROL,
+ [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = QPHY_V3_PCS_AUTONOMOUS_MODE_CTRL,
+ [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V3_PCS_LFPS_RXTERM_IRQ_CLEAR,
};
static const unsigned int qmp_v4_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = {
- [QPHY_SW_RESET] = 0x00,
- [QPHY_START_CTRL] = 0x44,
- [QPHY_PCS_STATUS] = 0x14,
- [QPHY_PCS_POWER_DOWN_CONTROL] = 0x40,
+ [QPHY_SW_RESET] = QPHY_V4_PCS_SW_RESET,
+ [QPHY_START_CTRL] = QPHY_V4_PCS_START_CONTROL,
+ [QPHY_PCS_STATUS] = QPHY_V4_PCS_PCS_STATUS1,
+ [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V4_PCS_POWER_DOWN_CONTROL,
/* In PCS_USB */
- [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = 0x008,
- [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = 0x014,
+ [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = QPHY_V4_PCS_USB3_AUTONOMOUS_MODE_CTRL,
+ [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V4_PCS_USB3_LFPS_RXTERM_IRQ_CLEAR,
};
static const struct qmp_phy_init_tbl qmp_v3_usb3_serdes_tbl[] = {
@@ -311,6 +310,70 @@ static const struct qmp_phy_init_tbl qmp_v3_usb3_pcs_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_RUN_TIME, 0x13),
};
+static const struct qmp_phy_init_tbl sm6350_usb3_rx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4e),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4, 0x18),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x77),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x03),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x75),
+};
+
+static const struct qmp_phy_init_tbl sm6350_usb3_pcs_tbl[] = {
+ /* FLL settings */
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL2, 0x83),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_L, 0x09),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_H_TOL, 0xa2),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_MAN_CODE, 0x40),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL1, 0x02),
+
+ /* Lock Det settings */
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG1, 0xd1),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG2, 0x1f),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG3, 0x47),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_POWER_STATE_CONFIG2, 0x1b),
+
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_LVL, 0xcc),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V0, 0x9f),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V1, 0x9f),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V2, 0xb7),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V3, 0x4e),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V4, 0x65),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_LS, 0x6b),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V0, 0x15),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V0, 0x0d),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V1, 0x15),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V1, 0x0d),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V2, 0x15),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V2, 0x0d),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V3, 0x15),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V3, 0x1d),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V4, 0x15),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V4, 0x0d),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_LS, 0x15),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_LS, 0x0d),
+
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_RATE_SLEW_CNTRL, 0x02),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_PWRUP_RESET_DLY_TIME_AUXCLK, 0x04),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TSYNC_RSYNC_TIME, 0x44),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_PWRUP_RESET_DLY_TIME_AUXCLK, 0x04),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_L, 0xe7),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_H, 0x03),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_L, 0x40),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_H, 0x00),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_WAIT_TIME, 0x75),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_LFPS_TX_ECSTART_EQTLOCK, 0x86),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_RUN_TIME, 0x13),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_LFPS_DET_HIGH_COUNT_VAL, 0x04),
+
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_REFGEN_REQ_CONFIG1, 0x21),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_REFGEN_REQ_CONFIG2, 0x60),
+};
+
static const struct qmp_phy_init_tbl sm8150_usb3_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_EN_CENTER, 0x01),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_PER1, 0x31),
@@ -494,6 +557,223 @@ static const struct qmp_phy_init_tbl sm8250_usb3_pcs_usb_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_V4_PCS_USB3_RXEQTRAINING_DFE_TIME_S2, 0x07),
};
+static const struct qmp_phy_init_tbl sm8350_usb3_tx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V5_TX_RES_CODE_LANE_TX, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V5_TX_RES_CODE_LANE_RX, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V5_TX_RES_CODE_LANE_OFFSET_TX, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V5_TX_RES_CODE_LANE_OFFSET_RX, 0x0e),
+ QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_1, 0x35),
+ QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_3, 0x3f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_4, 0x7f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_5, 0x3f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_TX_RCV_DETECT_LVL_2, 0x12),
+ QMP_PHY_INIT_CFG(QSERDES_V5_TX_PI_QEC_CTRL, 0x21),
+};
+
+static const struct qmp_phy_init_tbl sm8350_usb3_rx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_FO_GAIN, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SO_GAIN, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_FASTLOCK_FO_GAIN, 0x2f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x7f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_FASTLOCK_COUNT_LOW, 0xff),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_PI_CONTROLS, 0x99),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SB2_THRESH1, 0x08),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SB2_THRESH2, 0x08),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SB2_GAIN1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SB2_GAIN2, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_VGA_CAL_CNTRL1, 0x54),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_VGA_CAL_CNTRL2, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4a),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_IDAC_TSETTLE_LOW, 0xc0),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_IDAC_TSETTLE_HIGH, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x47),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_SIGDET_CNTRL, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_SIGDET_DEGLITCH_CNTRL, 0x0e),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_LOW, 0xbb),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH, 0x7b),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH2, 0xbb),
+ QMP_PHY_INIT_CFG_LANE(QSERDES_V5_RX_RX_MODE_00_HIGH3, 0x3d, 1),
+ QMP_PHY_INIT_CFG_LANE(QSERDES_V5_RX_RX_MODE_00_HIGH3, 0x3c, 2),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH4, 0xdb),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_LOW, 0x64),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH, 0x24),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH2, 0xd2),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH3, 0x13),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH4, 0xa9),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_DFE_EN_TIMER, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_DFE_CTLE_POST_CAL_OFFSET, 0x38),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_AUX_DATA_TCOARSE_TFINE, 0xa0),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_DCC_CTRL1, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_GM_CAL, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_VTH_CODE, 0x10),
+};
+
+static const struct qmp_phy_init_tbl sm8350_usb3_pcs_tbl[] = {
+ QMP_PHY_INIT_CFG(QPHY_V4_PCS_RCVR_DTCT_DLY_P1U2_L, 0xe7),
+ QMP_PHY_INIT_CFG(QPHY_V4_PCS_RCVR_DTCT_DLY_P1U2_H, 0x03),
+ QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG1, 0xd0),
+ QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG2, 0x07),
+ QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG3, 0x20),
+ QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG6, 0x13),
+ QMP_PHY_INIT_CFG(QPHY_V4_PCS_REFGEN_REQ_CONFIG1, 0x21),
+ QMP_PHY_INIT_CFG(QPHY_V4_PCS_RX_SIGDET_LVL, 0xaa),
+ QMP_PHY_INIT_CFG(QPHY_V4_PCS_CDR_RESET_TIME, 0x0a),
+ QMP_PHY_INIT_CFG(QPHY_V4_PCS_ALIGN_DETECT_CONFIG1, 0x88),
+ QMP_PHY_INIT_CFG(QPHY_V4_PCS_ALIGN_DETECT_CONFIG2, 0x13),
+ QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCS_TX_RX_CONFIG, 0x0c),
+ QMP_PHY_INIT_CFG(QPHY_V4_PCS_EQ_CONFIG1, 0x4b),
+ QMP_PHY_INIT_CFG(QPHY_V4_PCS_EQ_CONFIG5, 0x10),
+};
+
+static const struct qmp_phy_init_tbl sm8350_usb3_pcs_usb_tbl[] = {
+ QMP_PHY_INIT_CFG(QPHY_V5_PCS_USB3_RCVR_DTCT_DLY_U3_L, 0x40),
+ QMP_PHY_INIT_CFG(QPHY_V5_PCS_USB3_RCVR_DTCT_DLY_U3_H, 0x00),
+ QMP_PHY_INIT_CFG(QPHY_V5_PCS_USB3_LFPS_DET_HIGH_COUNT_VAL, 0xf8),
+ QMP_PHY_INIT_CFG(QPHY_V5_PCS_USB3_RXEQTRAINING_DFE_TIME_S2, 0x07),
+};
+
+static const struct qmp_phy_init_tbl sm8550_usb3_serdes_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE1_MODE1, 0xc0),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE2_MODE1, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE1, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE1, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE1, 0x36),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CORECLK_DIV_MODE1, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE1, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE1, 0x41),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE1, 0x41),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MSB_MODE1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START1_MODE1, 0x55),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START2_MODE1, 0x75),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START3_MODE1, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_SEL_1, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE1_MODE1, 0x25),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE2_MODE1, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE1_MODE1, 0x5c),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE2_MODE1, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0x5c),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE1_MODE0, 0xc0),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE2_MODE0, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE0, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE0, 0x36),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0x08),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x1a),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x41),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MSB_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START1_MODE0, 0x55),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START2_MODE0, 0x75),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START3_MODE0, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE1_MODE0, 0x25),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE2_MODE0, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_BG_TIMER, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_EN_CENTER, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_PER1, 0x62),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_PER2, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYSCLK_BUF_ENABLE, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYSCLK_EN_SEL, 0x1a),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_CFG, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CORE_CLK_EN, 0x20),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_CONFIG_1, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_AUTO_GAIN_ADJ_CTRL_1, 0xb6),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_AUTO_GAIN_ADJ_CTRL_2, 0x4b),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_AUTO_GAIN_ADJ_CTRL_3, 0x37),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_ADDITIONAL_MISC, 0x0c),
+};
+
+static const struct qmp_phy_init_tbl sm8550_usb3_tx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V6_TX_RES_CODE_LANE_TX, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V6_TX_RES_CODE_LANE_RX, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V6_TX_RES_CODE_LANE_OFFSET_TX, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_TX_RES_CODE_LANE_OFFSET_RX, 0x09),
+ QMP_PHY_INIT_CFG(QSERDES_V6_TX_LANE_MODE_1, 0xf5),
+ QMP_PHY_INIT_CFG(QSERDES_V6_TX_LANE_MODE_3, 0x3f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_TX_LANE_MODE_4, 0x3f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_TX_LANE_MODE_5, 0x5f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_TX_RCV_DETECT_LVL_2, 0x12),
+ QMP_PHY_INIT_CFG_LANE(QSERDES_V6_TX_PI_QEC_CTRL, 0x21, 1),
+ QMP_PHY_INIT_CFG_LANE(QSERDES_V6_TX_PI_QEC_CTRL, 0x05, 2),
+};
+
+static const struct qmp_phy_init_tbl sm8550_usb3_rx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_UCDR_FO_GAIN, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_UCDR_SO_GAIN, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_UCDR_FASTLOCK_FO_GAIN, 0x2f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x7f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_UCDR_FASTLOCK_COUNT_LOW, 0xff),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_UCDR_PI_CONTROLS, 0x99),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_UCDR_SB2_THRESH1, 0x08),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_UCDR_SB2_THRESH2, 0x08),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_UCDR_SB2_GAIN1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_UCDR_SB2_GAIN2, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_AUX_DATA_TCOARSE_TFINE, 0xa0),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_VGA_CAL_CNTRL1, 0x54),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_VGA_CAL_CNTRL2, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_GM_CAL, 0x13),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4a),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_IDAC_TSETTLE_LOW, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_IDAC_TSETTLE_HIGH, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x47),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_SIGDET_CNTRL, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_SIGDET_DEGLITCH_CNTRL, 0x0e),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_01_LOW, 0xdc),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_01_HIGH, 0x5c),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_01_HIGH2, 0x9c),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_01_HIGH3, 0x1d),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_01_HIGH4, 0x09),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_DFE_EN_TIMER, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_DFE_CTLE_POST_CAL_OFFSET, 0x38),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_DCC_CTRL1, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_VTH_CODE, 0x10),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_SIGDET_CAL_CTRL1, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_SIGDET_CAL_TRIM, 0x08),
+
+ QMP_PHY_INIT_CFG_LANE(QSERDES_V6_RX_RX_MODE_00_LOW, 0x3f, 1),
+ QMP_PHY_INIT_CFG_LANE(QSERDES_V6_RX_RX_MODE_00_HIGH, 0xbf, 1),
+ QMP_PHY_INIT_CFG_LANE(QSERDES_V6_RX_RX_MODE_00_HIGH2, 0xff, 1),
+ QMP_PHY_INIT_CFG_LANE(QSERDES_V6_RX_RX_MODE_00_HIGH3, 0xdf, 1),
+ QMP_PHY_INIT_CFG_LANE(QSERDES_V6_RX_RX_MODE_00_HIGH4, 0xed, 1),
+
+ QMP_PHY_INIT_CFG_LANE(QSERDES_V6_RX_RX_MODE_00_LOW, 0xbf, 2),
+ QMP_PHY_INIT_CFG_LANE(QSERDES_V6_RX_RX_MODE_00_HIGH, 0xbf, 2),
+ QMP_PHY_INIT_CFG_LANE(QSERDES_V6_RX_RX_MODE_00_HIGH2, 0xbf, 2),
+ QMP_PHY_INIT_CFG_LANE(QSERDES_V6_RX_RX_MODE_00_HIGH3, 0xdf, 2),
+ QMP_PHY_INIT_CFG_LANE(QSERDES_V6_RX_RX_MODE_00_HIGH4, 0xfd, 2),
+};
+
+static const struct qmp_phy_init_tbl sm8550_usb3_pcs_tbl[] = {
+ QMP_PHY_INIT_CFG(QPHY_USB_V6_PCS_LOCK_DETECT_CONFIG1, 0xc4),
+ QMP_PHY_INIT_CFG(QPHY_USB_V6_PCS_LOCK_DETECT_CONFIG2, 0x89),
+ QMP_PHY_INIT_CFG(QPHY_USB_V6_PCS_LOCK_DETECT_CONFIG3, 0x20),
+ QMP_PHY_INIT_CFG(QPHY_USB_V6_PCS_LOCK_DETECT_CONFIG6, 0x13),
+ QMP_PHY_INIT_CFG(QPHY_USB_V6_PCS_REFGEN_REQ_CONFIG1, 0x21),
+ QMP_PHY_INIT_CFG(QPHY_USB_V6_PCS_RX_SIGDET_LVL, 0x99),
+ QMP_PHY_INIT_CFG(QPHY_USB_V6_PCS_RCVR_DTCT_DLY_P1U2_L, 0xe7),
+ QMP_PHY_INIT_CFG(QPHY_USB_V6_PCS_RCVR_DTCT_DLY_P1U2_H, 0x03),
+ QMP_PHY_INIT_CFG(QPHY_USB_V6_PCS_CDR_RESET_TIME, 0x0a),
+ QMP_PHY_INIT_CFG(QPHY_USB_V6_PCS_ALIGN_DETECT_CONFIG1, 0x88),
+ QMP_PHY_INIT_CFG(QPHY_USB_V6_PCS_ALIGN_DETECT_CONFIG2, 0x13),
+ QMP_PHY_INIT_CFG(QPHY_USB_V6_PCS_PCS_TX_RX_CONFIG, 0x0c),
+ QMP_PHY_INIT_CFG(QPHY_USB_V6_PCS_EQ_CONFIG1, 0x4b),
+ QMP_PHY_INIT_CFG(QPHY_USB_V6_PCS_EQ_CONFIG5, 0x10),
+ QMP_PHY_INIT_CFG(QPHY_USB_V6_PCS_USB3_POWER_STATE_CONFIG1, 0x68),
+};
+
+static const struct qmp_phy_init_tbl sm8550_usb3_pcs_usb_tbl[] = {
+ QMP_PHY_INIT_CFG(QPHY_USB_V6_PCS_USB3_LFPS_DET_HIGH_COUNT_VAL, 0xf8),
+ QMP_PHY_INIT_CFG(QPHY_USB_V6_PCS_USB3_RXEQTRAINING_DFE_TIME_S2, 0x07),
+ QMP_PHY_INIT_CFG(QPHY_USB_V6_PCS_USB3_RCVR_DTCT_DLY_U3_L, 0x40),
+ QMP_PHY_INIT_CFG(QPHY_USB_V6_PCS_USB3_RCVR_DTCT_DLY_U3_H, 0x00),
+};
+
static const struct qmp_phy_init_tbl qmp_v4_dp_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V4_COM_SVS_MODE_CLK_SEL, 0x05),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_EN_SEL, 0x3b),
@@ -600,6 +880,20 @@ static const struct qmp_phy_init_tbl qmp_v5_dp_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V4_COM_CORE_CLK_EN, 0x1f),
};
+static const struct qmp_phy_init_tbl qmp_v5_dp_tx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V5_TX_VMODE_CTRL1, 0x40),
+ QMP_PHY_INIT_CFG(QSERDES_V5_TX_PRE_STALL_LDO_BOOST_EN, 0x30),
+ QMP_PHY_INIT_CFG(QSERDES_V5_TX_INTERFACE_SELECT, 0x3b),
+ QMP_PHY_INIT_CFG(QSERDES_V5_TX_CLKBUF_ENABLE, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_TX_RESET_TSYNC_EN, 0x03),
+ QMP_PHY_INIT_CFG(QSERDES_V5_TX_TRAN_DRVR_EMP_EN, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_TX_PARRATE_REC_DETECT_IDLE_EN, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V5_TX_TX_INTERFACE_MODE, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V5_TX_RES_CODE_LANE_OFFSET_TX, 0x11),
+ QMP_PHY_INIT_CFG(QSERDES_V5_TX_RES_CODE_LANE_OFFSET_RX, 0x11),
+ QMP_PHY_INIT_CFG(QSERDES_V5_TX_TX_BAND, 0x04),
+};
+
static const struct qmp_phy_init_tbl qmp_v5_5nm_dp_tx_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V5_5NM_TX_LANE_MODE_3, 0x51),
QMP_PHY_INIT_CFG(QSERDES_V5_5NM_TX_TRANSCEIVER_BIAS_EN, 0x1a),
@@ -615,6 +909,91 @@ static const struct qmp_phy_init_tbl qmp_v5_5nm_dp_tx_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V5_5NM_TX_TX_BAND, 0x01),
};
+static const struct qmp_phy_init_tbl qmp_v6_dp_serdes_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SVS_MODE_CLK_SEL, 0x15),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYSCLK_EN_SEL, 0x3b),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYS_CLK_CTRL, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CLK_ENABLE1, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYSCLK_BUF_ENABLE, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CLK_SELECT, 0x30),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE0, 0x36),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE0, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START1_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_CONFIG_1, 0x12),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_INTEGLOOP_GAIN0_MODE0, 0x3f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_INTEGLOOP_GAIN1_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_BG_TIMER, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CORE_CLK_DIV_MODE0, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_CTRL, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_BIAS_EN_CLK_BUFLR_EN, 0x17),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CORE_CLK_EN, 0x0f),
+};
+
+static const struct qmp_phy_init_tbl qmp_v6_dp_tx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V6_TX_VMODE_CTRL1, 0x40),
+ QMP_PHY_INIT_CFG(QSERDES_V6_TX_PRE_STALL_LDO_BOOST_EN, 0x30),
+ QMP_PHY_INIT_CFG(QSERDES_V6_TX_INTERFACE_SELECT, 0x3b),
+ QMP_PHY_INIT_CFG(QSERDES_V6_TX_CLKBUF_ENABLE, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_TX_RESET_TSYNC_EN, 0x03),
+ QMP_PHY_INIT_CFG(QSERDES_V6_TX_TRAN_DRVR_EMP_EN, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_TX_PARRATE_REC_DETECT_IDLE_EN, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V6_TX_TX_INTERFACE_MODE, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V6_TX_RES_CODE_LANE_OFFSET_TX, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_V6_TX_RES_CODE_LANE_OFFSET_RX, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_V6_TX_TX_BAND, 0x4),
+};
+
+static const struct qmp_phy_init_tbl qmp_v6_dp_serdes_tbl_rbr[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_SEL_1, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x34),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START2_MODE0, 0xc0),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START3_MODE0, 0x0b),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0x37),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_EN, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0x71),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x0c),
+};
+
+static const struct qmp_phy_init_tbl qmp_v6_dp_serdes_tbl_hbr[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_SEL_1, 0x03),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x34),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START2_MODE0, 0xc0),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START3_MODE0, 0x0b),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_EN, 0x08),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0x71),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x0c),
+};
+
+static const struct qmp_phy_init_tbl qmp_v6_dp_serdes_tbl_hbr2[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_SEL_1, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x46),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START2_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START3_MODE0, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x0e),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_EN, 0x08),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0x97),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x10),
+};
+
+static const struct qmp_phy_init_tbl qmp_v6_dp_serdes_tbl_hbr3[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_SEL_1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x34),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START2_MODE0, 0xc0),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START3_MODE0, 0x0b),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0x17),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x15),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_EN, 0x08),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0x71),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x0c),
+};
+
static const struct qmp_phy_init_tbl sc8280xp_usb43dp_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_EN_CENTER, 0x01),
QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_PER1, 0x31),
@@ -768,6 +1147,27 @@ static const u8 qmp_dp_v3_voltage_swing_hbr_rbr[4][4] = {
{ 0x1f, 0xff, 0xff, 0xff }
};
+static const u8 qmp_dp_v4_pre_emphasis_hbr3_hbr2[4][4] = {
+ { 0x00, 0x0c, 0x15, 0x1b },
+ { 0x02, 0x0e, 0x16, 0xff },
+ { 0x02, 0x11, 0xff, 0xff },
+ { 0x04, 0xff, 0xff, 0xff }
+};
+
+static const u8 qmp_dp_v4_pre_emphasis_hbr_rbr[4][4] = {
+ { 0x00, 0x0d, 0x14, 0x1a },
+ { 0x00, 0x0e, 0x15, 0xff },
+ { 0x00, 0x0d, 0xff, 0xff },
+ { 0x03, 0xff, 0xff, 0xff }
+};
+
+static const u8 qmp_dp_v4_voltage_swing_hbr_rbr[4][4] = {
+ { 0x08, 0x0f, 0x16, 0x1f },
+ { 0x11, 0x1e, 0x1f, 0xff },
+ { 0x16, 0x1f, 0xff, 0xff },
+ { 0x1f, 0xff, 0xff, 0xff }
+};
+
static const u8 qmp_dp_v5_pre_emphasis_hbr3_hbr2[4][4] = {
{ 0x20, 0x2c, 0x35, 0x3b },
{ 0x22, 0x2e, 0x36, 0xff },
@@ -796,6 +1196,13 @@ static const u8 qmp_dp_v5_voltage_swing_hbr_rbr[4][4] = {
{ 0x3f, 0xff, 0xff, 0xff }
};
+static const u8 qmp_dp_v6_pre_emphasis_hbr_rbr[4][4] = {
+ { 0x20, 0x2d, 0x34, 0x3a },
+ { 0x20, 0x2e, 0x35, 0xff },
+ { 0x20, 0x2e, 0xff, 0xff },
+ { 0x22, 0xff, 0xff, 0xff }
+};
+
struct qmp_combo;
struct qmp_combo_offsets {
@@ -809,6 +1216,8 @@ struct qmp_combo_offsets {
u16 usb3_pcs;
u16 usb3_pcs_usb;
u16 dp_serdes;
+ u16 dp_txa;
+ u16 dp_txb;
u16 dp_dp_phy;
};
@@ -928,6 +1337,9 @@ static int qmp_v4_calibrate_dp_phy(struct qmp_combo *qmp);
static int qmp_v5_configure_dp_phy(struct qmp_combo *qmp);
+static void qmp_v6_dp_aux_init(struct qmp_combo *qmp);
+static int qmp_v6_configure_dp_phy(struct qmp_combo *qmp);
+
static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val)
{
u32 reg;
@@ -975,6 +1387,21 @@ static const char * const sc7180_usb3phy_reset_l[] = {
"phy",
};
+static const struct qmp_combo_offsets qmp_combo_offsets_v3 = {
+ .com = 0x0000,
+ .txa = 0x1200,
+ .rxa = 0x1400,
+ .txb = 0x1600,
+ .rxb = 0x1800,
+ .usb3_serdes = 0x1000,
+ .usb3_pcs_misc = 0x1a00,
+ .usb3_pcs = 0x1c00,
+ .dp_serdes = 0x2000,
+ .dp_txa = 0x2200,
+ .dp_txb = 0x2600,
+ .dp_dp_phy = 0x2a00,
+};
+
static const struct qmp_combo_offsets qmp_combo_offsets_v5 = {
.com = 0x0000,
.txa = 0x0400,
@@ -989,6 +1416,22 @@ static const struct qmp_combo_offsets qmp_combo_offsets_v5 = {
.dp_dp_phy = 0x2200,
};
+static const struct qmp_combo_offsets qmp_combo_offsets_v6 = {
+ .com = 0x0000,
+ .txa = 0x1200,
+ .rxa = 0x1400,
+ .txb = 0x1600,
+ .rxb = 0x1800,
+ .usb3_serdes = 0x1000,
+ .usb3_pcs_misc = 0x1a00,
+ .usb3_pcs = 0x1c00,
+ .usb3_pcs_usb = 0x1f00,
+ .dp_serdes = 0x2000,
+ .dp_txa = 0x2200,
+ .dp_txb = 0x2600,
+ .dp_dp_phy = 0x2a00,
+};
+
static const struct qmp_phy_cfg sc7180_usb3dpphy_cfg = {
.serdes_tbl = qmp_v3_usb3_serdes_tbl,
.serdes_tbl_num = ARRAY_SIZE(qmp_v3_usb3_serdes_tbl),
@@ -1172,6 +1615,51 @@ static const struct qmp_phy_cfg sc8280xp_usb43dpphy_cfg = {
.regs = qmp_v4_usb3phy_regs_layout,
};
+static const struct qmp_phy_cfg sm6350_usb3dpphy_cfg = {
+ .offsets = &qmp_combo_offsets_v3,
+
+ .serdes_tbl = qmp_v3_usb3_serdes_tbl,
+ .serdes_tbl_num = ARRAY_SIZE(qmp_v3_usb3_serdes_tbl),
+ .tx_tbl = qmp_v3_usb3_tx_tbl,
+ .tx_tbl_num = ARRAY_SIZE(qmp_v3_usb3_tx_tbl),
+ .rx_tbl = sm6350_usb3_rx_tbl,
+ .rx_tbl_num = ARRAY_SIZE(sm6350_usb3_rx_tbl),
+ .pcs_tbl = sm6350_usb3_pcs_tbl,
+ .pcs_tbl_num = ARRAY_SIZE(sm6350_usb3_pcs_tbl),
+
+ .dp_serdes_tbl = qmp_v3_dp_serdes_tbl,
+ .dp_serdes_tbl_num = ARRAY_SIZE(qmp_v3_dp_serdes_tbl),
+ .dp_tx_tbl = qmp_v3_dp_tx_tbl,
+ .dp_tx_tbl_num = ARRAY_SIZE(qmp_v3_dp_tx_tbl),
+
+ .serdes_tbl_rbr = qmp_v3_dp_serdes_tbl_rbr,
+ .serdes_tbl_rbr_num = ARRAY_SIZE(qmp_v3_dp_serdes_tbl_rbr),
+ .serdes_tbl_hbr = qmp_v3_dp_serdes_tbl_hbr,
+ .serdes_tbl_hbr_num = ARRAY_SIZE(qmp_v3_dp_serdes_tbl_hbr),
+ .serdes_tbl_hbr2 = qmp_v3_dp_serdes_tbl_hbr2,
+ .serdes_tbl_hbr2_num = ARRAY_SIZE(qmp_v3_dp_serdes_tbl_hbr2),
+ .serdes_tbl_hbr3 = qmp_v3_dp_serdes_tbl_hbr3,
+ .serdes_tbl_hbr3_num = ARRAY_SIZE(qmp_v3_dp_serdes_tbl_hbr3),
+
+ .swing_hbr_rbr = &qmp_dp_v3_voltage_swing_hbr_rbr,
+ .pre_emphasis_hbr_rbr = &qmp_dp_v3_pre_emphasis_hbr_rbr,
+ .swing_hbr3_hbr2 = &qmp_dp_v3_voltage_swing_hbr3_hbr2,
+ .pre_emphasis_hbr3_hbr2 = &qmp_dp_v3_pre_emphasis_hbr3_hbr2,
+
+ .dp_aux_init = qmp_v3_dp_aux_init,
+ .configure_dp_tx = qmp_v3_configure_dp_tx,
+ .configure_dp_phy = qmp_v3_configure_dp_phy,
+ .calibrate_dp_phy = qmp_v3_calibrate_dp_phy,
+
+ .clk_list = qmp_v4_phy_clk_l,
+ .num_clks = ARRAY_SIZE(qmp_v4_phy_clk_l),
+ .reset_list = msm8996_usb3phy_reset_l,
+ .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l),
+ .vreg_list = qmp_phy_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
+ .regs = qmp_v3_usb3phy_regs_layout,
+};
+
static const struct qmp_phy_cfg sm8250_usb3dpphy_cfg = {
.serdes_tbl = sm8150_usb3_serdes_tbl,
.serdes_tbl_num = ARRAY_SIZE(sm8150_usb3_serdes_tbl),
@@ -1220,6 +1708,102 @@ static const struct qmp_phy_cfg sm8250_usb3dpphy_cfg = {
.has_pwrdn_delay = true,
};
+static const struct qmp_phy_cfg sm8350_usb3dpphy_cfg = {
+ .offsets = &qmp_combo_offsets_v3,
+
+ .serdes_tbl = sm8150_usb3_serdes_tbl,
+ .serdes_tbl_num = ARRAY_SIZE(sm8150_usb3_serdes_tbl),
+ .tx_tbl = sm8350_usb3_tx_tbl,
+ .tx_tbl_num = ARRAY_SIZE(sm8350_usb3_tx_tbl),
+ .rx_tbl = sm8350_usb3_rx_tbl,
+ .rx_tbl_num = ARRAY_SIZE(sm8350_usb3_rx_tbl),
+ .pcs_tbl = sm8350_usb3_pcs_tbl,
+ .pcs_tbl_num = ARRAY_SIZE(sm8350_usb3_pcs_tbl),
+ .pcs_usb_tbl = sm8350_usb3_pcs_usb_tbl,
+ .pcs_usb_tbl_num = ARRAY_SIZE(sm8350_usb3_pcs_usb_tbl),
+
+ .dp_serdes_tbl = qmp_v4_dp_serdes_tbl,
+ .dp_serdes_tbl_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl),
+ .dp_tx_tbl = qmp_v5_dp_tx_tbl,
+ .dp_tx_tbl_num = ARRAY_SIZE(qmp_v5_dp_tx_tbl),
+
+ .serdes_tbl_rbr = qmp_v4_dp_serdes_tbl_rbr,
+ .serdes_tbl_rbr_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl_rbr),
+ .serdes_tbl_hbr = qmp_v4_dp_serdes_tbl_hbr,
+ .serdes_tbl_hbr_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl_hbr),
+ .serdes_tbl_hbr2 = qmp_v4_dp_serdes_tbl_hbr2,
+ .serdes_tbl_hbr2_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl_hbr2),
+ .serdes_tbl_hbr3 = qmp_v4_dp_serdes_tbl_hbr3,
+ .serdes_tbl_hbr3_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl_hbr3),
+
+ .swing_hbr_rbr = &qmp_dp_v4_voltage_swing_hbr_rbr,
+ .pre_emphasis_hbr_rbr = &qmp_dp_v4_pre_emphasis_hbr_rbr,
+ .swing_hbr3_hbr2 = &qmp_dp_v3_voltage_swing_hbr3_hbr2,
+ .pre_emphasis_hbr3_hbr2 = &qmp_dp_v4_pre_emphasis_hbr3_hbr2,
+
+ .dp_aux_init = qmp_v4_dp_aux_init,
+ .configure_dp_tx = qmp_v4_configure_dp_tx,
+ .configure_dp_phy = qmp_v4_configure_dp_phy,
+ .calibrate_dp_phy = qmp_v4_calibrate_dp_phy,
+
+ .clk_list = qmp_v4_phy_clk_l,
+ .num_clks = ARRAY_SIZE(qmp_v4_phy_clk_l),
+ .reset_list = msm8996_usb3phy_reset_l,
+ .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l),
+ .vreg_list = qmp_phy_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
+ .regs = qmp_v4_usb3phy_regs_layout,
+
+ .has_pwrdn_delay = true,
+};
+
+static const struct qmp_phy_cfg sm8550_usb3dpphy_cfg = {
+ .offsets = &qmp_combo_offsets_v6,
+
+ .serdes_tbl = sm8550_usb3_serdes_tbl,
+ .serdes_tbl_num = ARRAY_SIZE(sm8550_usb3_serdes_tbl),
+ .tx_tbl = sm8550_usb3_tx_tbl,
+ .tx_tbl_num = ARRAY_SIZE(sm8550_usb3_tx_tbl),
+ .rx_tbl = sm8550_usb3_rx_tbl,
+ .rx_tbl_num = ARRAY_SIZE(sm8550_usb3_rx_tbl),
+ .pcs_tbl = sm8550_usb3_pcs_tbl,
+ .pcs_tbl_num = ARRAY_SIZE(sm8550_usb3_pcs_tbl),
+ .pcs_usb_tbl = sm8550_usb3_pcs_usb_tbl,
+ .pcs_usb_tbl_num = ARRAY_SIZE(sm8550_usb3_pcs_usb_tbl),
+
+ .dp_serdes_tbl = qmp_v6_dp_serdes_tbl,
+ .dp_serdes_tbl_num = ARRAY_SIZE(qmp_v6_dp_serdes_tbl),
+ .dp_tx_tbl = qmp_v6_dp_tx_tbl,
+ .dp_tx_tbl_num = ARRAY_SIZE(qmp_v6_dp_tx_tbl),
+
+ .serdes_tbl_rbr = qmp_v6_dp_serdes_tbl_rbr,
+ .serdes_tbl_rbr_num = ARRAY_SIZE(qmp_v6_dp_serdes_tbl_rbr),
+ .serdes_tbl_hbr = qmp_v6_dp_serdes_tbl_hbr,
+ .serdes_tbl_hbr_num = ARRAY_SIZE(qmp_v6_dp_serdes_tbl_hbr),
+ .serdes_tbl_hbr2 = qmp_v6_dp_serdes_tbl_hbr2,
+ .serdes_tbl_hbr2_num = ARRAY_SIZE(qmp_v6_dp_serdes_tbl_hbr2),
+ .serdes_tbl_hbr3 = qmp_v6_dp_serdes_tbl_hbr3,
+ .serdes_tbl_hbr3_num = ARRAY_SIZE(qmp_v6_dp_serdes_tbl_hbr3),
+
+ .swing_hbr_rbr = &qmp_dp_v5_voltage_swing_hbr_rbr,
+ .pre_emphasis_hbr_rbr = &qmp_dp_v6_pre_emphasis_hbr_rbr,
+ .swing_hbr3_hbr2 = &qmp_dp_v5_voltage_swing_hbr3_hbr2,
+ .pre_emphasis_hbr3_hbr2 = &qmp_dp_v5_pre_emphasis_hbr3_hbr2,
+
+ .dp_aux_init = qmp_v6_dp_aux_init,
+ .configure_dp_tx = qmp_v4_configure_dp_tx,
+ .configure_dp_phy = qmp_v6_configure_dp_phy,
+ .calibrate_dp_phy = qmp_v4_calibrate_dp_phy,
+
+ .regs = qmp_v4_usb3phy_regs_layout,
+ .clk_list = qmp_v4_phy_clk_l,
+ .num_clks = ARRAY_SIZE(qmp_v4_phy_clk_l),
+ .reset_list = msm8996_usb3phy_reset_l,
+ .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l),
+ .vreg_list = qmp_phy_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
+};
+
static void qmp_combo_configure_lane(void __iomem *base,
const struct qmp_phy_init_tbl tbl[],
int num,
@@ -1530,6 +2114,33 @@ static void qmp_v4_dp_aux_init(struct qmp_combo *qmp)
qmp->dp_dp_phy + QSERDES_V4_DP_PHY_AUX_INTERRUPT_MASK);
}
+static void qmp_v6_dp_aux_init(struct qmp_combo *qmp)
+{
+ writel(DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_PSR_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN |
+ DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN,
+ qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL);
+
+ /* Turn on BIAS current for PHY/PLL */
+ writel(0x17, qmp->dp_serdes + QSERDES_V6_COM_PLL_BIAS_EN_CLK_BUFLR_EN);
+
+ writel(0x00, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG0);
+ writel(0x13, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG1);
+ writel(0xa4, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG2);
+ writel(0x00, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG3);
+ writel(0x0a, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG4);
+ writel(0x26, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG5);
+ writel(0x0a, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG6);
+ writel(0x03, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG7);
+ writel(0xb7, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG8);
+ writel(0x03, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG9);
+ qmp->dp_aux_cfg = 0;
+
+ writel(PHY_AUX_STOP_ERR_MASK | PHY_AUX_DEC_ERR_MASK |
+ PHY_AUX_SYNC_ERR_MASK | PHY_AUX_ALIGN_ERR_MASK |
+ PHY_AUX_REQ_ERR_MASK,
+ qmp->dp_dp_phy + QSERDES_V4_DP_PHY_AUX_INTERRUPT_MASK);
+}
+
static void qmp_v4_configure_dp_tx(struct qmp_combo *qmp)
{
/* Program default values before writing proper values */
@@ -1543,7 +2154,10 @@ static void qmp_v4_configure_dp_tx(struct qmp_combo *qmp)
QSERDES_V4_TX_TX_EMP_POST1_LVL);
}
-static int qmp_v45_configure_dp_phy(struct qmp_combo *qmp)
+static int qmp_v456_configure_dp_phy(struct qmp_combo *qmp,
+ unsigned int com_resetm_ctrl_reg,
+ unsigned int com_c_ready_status_reg,
+ unsigned int dp_phy_status_reg)
{
const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts;
u32 phy_vco_div, status;
@@ -1590,9 +2204,9 @@ static int qmp_v45_configure_dp_phy(struct qmp_combo *qmp)
writel(0x01, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
writel(0x09, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
- writel(0x20, qmp->dp_serdes + QSERDES_V4_COM_RESETSM_CNTRL);
+ writel(0x20, qmp->dp_serdes + com_resetm_ctrl_reg);
- if (readl_poll_timeout(qmp->dp_serdes + QSERDES_V4_COM_C_READY_STATUS,
+ if (readl_poll_timeout(qmp->dp_serdes + com_c_ready_status_reg,
status,
((status & BIT(0)) > 0),
500,
@@ -1615,14 +2229,14 @@ static int qmp_v45_configure_dp_phy(struct qmp_combo *qmp)
writel(0x19, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
- if (readl_poll_timeout(qmp->dp_dp_phy + QSERDES_V4_DP_PHY_STATUS,
+ if (readl_poll_timeout(qmp->dp_dp_phy + dp_phy_status_reg,
status,
((status & BIT(0)) > 0),
500,
10000))
return -ETIMEDOUT;
- if (readl_poll_timeout(qmp->dp_dp_phy + QSERDES_V4_DP_PHY_STATUS,
+ if (readl_poll_timeout(qmp->dp_dp_phy + dp_phy_status_reg,
status,
((status & BIT(1)) > 0),
500,
@@ -1640,7 +2254,9 @@ static int qmp_v4_configure_dp_phy(struct qmp_combo *qmp)
u32 status;
int ret;
- ret = qmp_v45_configure_dp_phy(qmp);
+ ret = qmp_v456_configure_dp_phy(qmp, QSERDES_V4_COM_RESETSM_CNTRL,
+ QSERDES_V4_COM_C_READY_STATUS,
+ QSERDES_V4_DP_PHY_STATUS);
if (ret < 0)
return ret;
@@ -1702,7 +2318,9 @@ static int qmp_v5_configure_dp_phy(struct qmp_combo *qmp)
u32 status;
int ret;
- ret = qmp_v45_configure_dp_phy(qmp);
+ ret = qmp_v456_configure_dp_phy(qmp, QSERDES_V4_COM_RESETSM_CNTRL,
+ QSERDES_V4_COM_C_READY_STATUS,
+ QSERDES_V4_DP_PHY_STATUS);
if (ret < 0)
return ret;
@@ -1751,6 +2369,65 @@ static int qmp_v5_configure_dp_phy(struct qmp_combo *qmp)
return 0;
}
+static int qmp_v6_configure_dp_phy(struct qmp_combo *qmp)
+{
+ const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts;
+ u32 bias0_en, drvr0_en, bias1_en, drvr1_en;
+ bool reverse = false;
+ u32 status;
+ int ret;
+
+ ret = qmp_v456_configure_dp_phy(qmp, QSERDES_V6_COM_RESETSM_CNTRL,
+ QSERDES_V6_COM_C_READY_STATUS,
+ QSERDES_V6_DP_PHY_STATUS);
+ if (ret < 0)
+ return ret;
+
+ if (dp_opts->lanes == 1) {
+ bias0_en = reverse ? 0x3e : 0x1a;
+ drvr0_en = reverse ? 0x13 : 0x10;
+ bias1_en = reverse ? 0x15 : 0x3e;
+ drvr1_en = reverse ? 0x10 : 0x13;
+ } else if (dp_opts->lanes == 2) {
+ bias0_en = reverse ? 0x3f : 0x15;
+ drvr0_en = 0x10;
+ bias1_en = reverse ? 0x15 : 0x3f;
+ drvr1_en = 0x10;
+ } else {
+ bias0_en = 0x3f;
+ bias1_en = 0x3f;
+ drvr0_en = 0x10;
+ drvr1_en = 0x10;
+ }
+
+ writel(drvr0_en, qmp->dp_tx + QSERDES_V4_TX_HIGHZ_DRVR_EN);
+ writel(bias0_en, qmp->dp_tx + QSERDES_V4_TX_TRANSCEIVER_BIAS_EN);
+ writel(drvr1_en, qmp->dp_tx2 + QSERDES_V4_TX_HIGHZ_DRVR_EN);
+ writel(bias1_en, qmp->dp_tx2 + QSERDES_V4_TX_TRANSCEIVER_BIAS_EN);
+
+ writel(0x18, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
+ udelay(2000);
+ writel(0x19, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
+
+ if (readl_poll_timeout(qmp->dp_dp_phy + QSERDES_V6_DP_PHY_STATUS,
+ status,
+ ((status & BIT(1)) > 0),
+ 500,
+ 10000))
+ return -ETIMEDOUT;
+
+ writel(0x0a, qmp->dp_tx + QSERDES_V4_TX_TX_POL_INV);
+ writel(0x0a, qmp->dp_tx2 + QSERDES_V4_TX_TX_POL_INV);
+
+ writel(0x27, qmp->dp_tx + QSERDES_V4_TX_TX_DRV_LVL);
+ writel(0x27, qmp->dp_tx2 + QSERDES_V4_TX_TX_DRV_LVL);
+
+ writel(0x20, qmp->dp_tx + QSERDES_V4_TX_TX_EMP_POST1_LVL);
+ writel(0x20, qmp->dp_tx2 + QSERDES_V4_TX_TX_EMP_POST1_LVL);
+
+ return 0;
+}
+
/*
* We need to calibrate the aux setting here as many times
* as the caller tries
@@ -2641,8 +3318,13 @@ static int qmp_combo_parse_dt(struct qmp_combo *qmp)
qmp->pcs_usb = base + offs->usb3_pcs_usb;
qmp->dp_serdes = base + offs->dp_serdes;
- qmp->dp_tx = base + offs->txa;
- qmp->dp_tx2 = base + offs->txb;
+ if (offs->dp_txa) {
+ qmp->dp_tx = base + offs->dp_txa;
+ qmp->dp_tx2 = base + offs->dp_txb;
+ } else {
+ qmp->dp_tx = base + offs->txa;
+ qmp->dp_tx2 = base + offs->txb;
+ }
qmp->dp_dp_phy = base + offs->dp_dp_phy;
qmp->pipe_clk = devm_clk_get(dev, "usb3_pipe");
@@ -2790,9 +3472,25 @@ static const struct of_device_id qmp_combo_of_match_table[] = {
.data = &sdm845_usb3dpphy_cfg,
},
{
+ .compatible = "qcom,sm6350-qmp-usb3-dp-phy",
+ .data = &sm6350_usb3dpphy_cfg,
+ },
+ {
.compatible = "qcom,sm8250-qmp-usb3-dp-phy",
.data = &sm8250_usb3dpphy_cfg,
},
+ {
+ .compatible = "qcom,sm8350-qmp-usb3-dp-phy",
+ .data = &sm8350_usb3dpphy_cfg,
+ },
+ {
+ .compatible = "qcom,sm8450-qmp-usb3-dp-phy",
+ .data = &sm8350_usb3dpphy_cfg,
+ },
+ {
+ .compatible = "qcom,sm8550-qmp-usb3-dp-phy",
+ .data = &sm8550_usb3dpphy_cfg,
+ },
{ }
};
MODULE_DEVICE_TABLE(of, qmp_combo_of_match_table);
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c
index a088477e274f..09824be088c9 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c
@@ -84,9 +84,9 @@ static const unsigned int pciephy_regs_layout[QPHY_LAYOUT_SIZE] = {
[QPHY_COM_POWER_DOWN_CONTROL] = 0x404,
[QPHY_COM_START_CONTROL] = 0x408,
[QPHY_COM_PCS_READY_STATUS] = 0x448,
- [QPHY_SW_RESET] = 0x00,
- [QPHY_START_CTRL] = 0x08,
- [QPHY_PCS_STATUS] = 0x174,
+ [QPHY_SW_RESET] = QPHY_V2_PCS_SW_RESET,
+ [QPHY_START_CTRL] = QPHY_V2_PCS_START_CONTROL,
+ [QPHY_PCS_STATUS] = QPHY_V2_PCS_PCI_PCS_STATUS,
};
static const struct qmp_phy_init_tbl msm8996_pcie_serdes_tbl[] = {
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
index 1b136a87053f..5182aeac43ee 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
@@ -24,6 +24,14 @@
#include <linux/slab.h>
#include "phy-qcom-qmp.h"
+#include "phy-qcom-qmp-pcs-misc-v3.h"
+#include "phy-qcom-qmp-pcs-pcie-v4.h"
+#include "phy-qcom-qmp-pcs-pcie-v4_20.h"
+#include "phy-qcom-qmp-pcs-pcie-v5.h"
+#include "phy-qcom-qmp-pcs-pcie-v5_20.h"
+#include "phy-qcom-qmp-pcs-pcie-v6.h"
+#include "phy-qcom-qmp-pcs-pcie-v6_20.h"
+#include "phy-qcom-qmp-pcie-qhp.h"
/* QPHY_SW_RESET bit */
#define SW_RESET BIT(0)
@@ -74,25 +82,18 @@ enum qphy_reg_layout {
QPHY_LAYOUT_SIZE
};
-static const unsigned int ipq_pciephy_gen3_regs_layout[QPHY_LAYOUT_SIZE] = {
- [QPHY_SW_RESET] = 0x00,
- [QPHY_START_CTRL] = 0x44,
- [QPHY_PCS_STATUS] = 0x14,
- [QPHY_PCS_POWER_DOWN_CONTROL] = 0x40,
+static const unsigned int pciephy_v2_regs_layout[QPHY_LAYOUT_SIZE] = {
+ [QPHY_SW_RESET] = QPHY_V2_PCS_SW_RESET,
+ [QPHY_START_CTRL] = QPHY_V2_PCS_START_CONTROL,
+ [QPHY_PCS_STATUS] = QPHY_V2_PCS_PCI_PCS_STATUS,
+ [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V2_PCS_POWER_DOWN_CONTROL,
};
-static const unsigned int pciephy_regs_layout[QPHY_LAYOUT_SIZE] = {
- [QPHY_SW_RESET] = 0x00,
- [QPHY_START_CTRL] = 0x08,
- [QPHY_PCS_STATUS] = 0x174,
- [QPHY_PCS_POWER_DOWN_CONTROL] = 0x04,
-};
-
-static const unsigned int sdm845_qmp_pciephy_regs_layout[QPHY_LAYOUT_SIZE] = {
- [QPHY_SW_RESET] = 0x00,
- [QPHY_START_CTRL] = 0x08,
- [QPHY_PCS_STATUS] = 0x174,
- [QPHY_PCS_POWER_DOWN_CONTROL] = 0x04,
+static const unsigned int pciephy_v3_regs_layout[QPHY_LAYOUT_SIZE] = {
+ [QPHY_SW_RESET] = QPHY_V3_PCS_SW_RESET,
+ [QPHY_START_CTRL] = QPHY_V3_PCS_START_CONTROL,
+ [QPHY_PCS_STATUS] = QPHY_V3_PCS_PCS_STATUS,
+ [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V3_PCS_POWER_DOWN_CONTROL,
};
static const unsigned int sdm845_qhp_pciephy_regs_layout[QPHY_LAYOUT_SIZE] = {
@@ -102,11 +103,18 @@ static const unsigned int sdm845_qhp_pciephy_regs_layout[QPHY_LAYOUT_SIZE] = {
[QPHY_PCS_POWER_DOWN_CONTROL] = 0x04,
};
-static const unsigned int sm8250_pcie_regs_layout[QPHY_LAYOUT_SIZE] = {
- [QPHY_SW_RESET] = 0x00,
- [QPHY_START_CTRL] = 0x44,
- [QPHY_PCS_STATUS] = 0x14,
- [QPHY_PCS_POWER_DOWN_CONTROL] = 0x40,
+static const unsigned int pciephy_v4_regs_layout[QPHY_LAYOUT_SIZE] = {
+ [QPHY_SW_RESET] = QPHY_V4_PCS_SW_RESET,
+ [QPHY_START_CTRL] = QPHY_V4_PCS_START_CONTROL,
+ [QPHY_PCS_STATUS] = QPHY_V4_PCS_PCS_STATUS1,
+ [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V4_PCS_POWER_DOWN_CONTROL,
+};
+
+static const unsigned int pciephy_v5_regs_layout[QPHY_LAYOUT_SIZE] = {
+ [QPHY_SW_RESET] = QPHY_V5_PCS_SW_RESET,
+ [QPHY_START_CTRL] = QPHY_V5_PCS_START_CONTROL,
+ [QPHY_PCS_STATUS] = QPHY_V5_PCS_PCS_STATUS1,
+ [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V5_PCS_POWER_DOWN_CONTROL,
};
static const struct qmp_phy_init_tbl msm8998_pcie_serdes_tbl[] = {
@@ -1216,7 +1224,7 @@ static const struct qmp_phy_init_tbl sdx55_qmp_pcie_pcs_misc_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_V4_20_PCS_LANE1_INSIG_MX_CTRL2, 0x00),
};
-static const struct qmp_phy_init_tbl sm8450_qmp_gen3x1_pcie_serdes_tbl[] = {
+static const struct qmp_phy_init_tbl sm8450_qmp_gen3_pcie_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V5_COM_SYSCLK_EN_SEL, 0x08),
QMP_PHY_INIT_CFG(QSERDES_V5_COM_CLK_SELECT, 0x34),
QMP_PHY_INIT_CFG(QSERDES_V5_COM_CORECLK_DIV_MODE1, 0x08),
@@ -1250,7 +1258,6 @@ static const struct qmp_phy_init_tbl sm8450_qmp_gen3x1_pcie_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V5_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0xca),
QMP_PHY_INIT_CFG(QSERDES_V5_COM_BIN_VCOCAL_CMP_CODE2_MODE1, 0x18),
QMP_PHY_INIT_CFG(QSERDES_V5_COM_BIN_VCOCAL_CMP_CODE1_MODE1, 0xa2),
- QMP_PHY_INIT_CFG(QSERDES_V5_COM_SYSCLK_BUF_ENABLE, 0x07),
QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_EN_CENTER, 0x01),
QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_PER1, 0x31),
QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_PER2, 0x01),
@@ -1261,6 +1268,10 @@ static const struct qmp_phy_init_tbl sm8450_qmp_gen3x1_pcie_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V5_COM_CLK_ENABLE1, 0x90),
};
+static const struct qmp_phy_init_tbl sm8450_qmp_gen3x1_pcie_rc_serdes_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V5_COM_SYSCLK_BUF_ENABLE, 0x07),
+};
+
static const struct qmp_phy_init_tbl sm8450_qmp_gen3x1_pcie_tx_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V5_TX_PI_QEC_CTRL, 0x20),
QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_1, 0x75),
@@ -1269,11 +1280,9 @@ static const struct qmp_phy_init_tbl sm8450_qmp_gen3x1_pcie_tx_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V5_TX_RES_CODE_LANE_OFFSET_RX, 0x04),
};
-static const struct qmp_phy_init_tbl sm8450_qmp_gen3x1_pcie_rx_tbl[] = {
+static const struct qmp_phy_init_tbl sm8450_qmp_gen3_pcie_rx_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_LOW, 0x7f),
QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH, 0xff),
- QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH2, 0xbf),
- QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH3, 0x3f),
QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH4, 0xd8),
QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_LOW, 0xdc),
QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH, 0xdc),
@@ -1281,20 +1290,25 @@ static const struct qmp_phy_init_tbl sm8450_qmp_gen3x1_pcie_rx_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH3, 0x34),
QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH4, 0xa6),
QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_10_HIGH3, 0x34),
- QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_10_HIGH4, 0x38),
- QMP_PHY_INIT_CFG(QSERDES_V5_RX_VGA_CAL_CNTRL2, 0x07),
QMP_PHY_INIT_CFG(QSERDES_V5_RX_GM_CAL, 0x00),
QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SB2_THRESH1, 0x08),
QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SB2_THRESH2, 0x08),
- QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_PI_CONTROLS, 0xf0),
QMP_PHY_INIT_CFG(QSERDES_V5_RX_DFE_CTLE_POST_CAL_OFFSET, 0x38),
QMP_PHY_INIT_CFG(QSERDES_V5_RX_TX_ADAPT_POST_THRESH, 0xf0),
+};
+
+static const struct qmp_phy_init_tbl sm8450_qmp_gen3x1_pcie_rc_rx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH2, 0xbf),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH3, 0x3f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_10_HIGH4, 0x38),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_VGA_CAL_CNTRL2, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_PI_CONTROLS, 0xf0),
QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL4, 0x07),
QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_FO_GAIN, 0x09),
QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SO_GAIN, 0x05),
};
-static const struct qmp_phy_init_tbl sm8450_qmp_gen3x1_pcie_pcs_tbl[] = {
+static const struct qmp_phy_init_tbl sm8450_qmp_gen3_pcie_pcs_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_V5_PCS_RX_SIGDET_LVL, 0x77),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_RATE_SLEW_CNTRL1, 0x0b),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_REFGEN_REQ_CONFIG1, 0x05),
@@ -1307,6 +1321,40 @@ static const struct qmp_phy_init_tbl sm8450_qmp_gen3x1_pcie_pcs_misc_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_ENDPOINT_REFCLK_DRIVE, 0xc1),
};
+static const struct qmp_phy_init_tbl sm8350_qmp_gen3x1_pcie_tx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V5_TX_PI_QEC_CTRL, 0x20),
+ QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_1, 0x75),
+ QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_4, 0x3f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_TX_RES_CODE_LANE_OFFSET_TX, 0x1d),
+ QMP_PHY_INIT_CFG(QSERDES_V5_TX_RES_CODE_LANE_OFFSET_RX, 0x0c),
+};
+
+static const struct qmp_phy_init_tbl sm8350_qmp_gen3x1_pcie_rc_rx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH2, 0xbf),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH3, 0x3f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_VGA_CAL_CNTRL2, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_PI_CONTROLS, 0xf0),
+};
+
+static const struct qmp_phy_init_tbl sm8350_qmp_gen3x2_pcie_rc_rx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH2, 0x7f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH3, 0x34),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_VGA_CAL_CNTRL2, 0x0f),
+};
+
+static const struct qmp_phy_init_tbl sm8350_qmp_gen3x2_pcie_tx_tbl[] = {
+ QMP_PHY_INIT_CFG_LANE(QSERDES_V5_TX_PI_QEC_CTRL, 0x02, 1),
+ QMP_PHY_INIT_CFG_LANE(QSERDES_V5_TX_PI_QEC_CTRL, 0x04, 2),
+ QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_1, 0xd5),
+ QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_4, 0x3f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_TX_RES_CODE_LANE_OFFSET_TX, 0x1d),
+ QMP_PHY_INIT_CFG(QSERDES_V5_TX_RES_CODE_LANE_OFFSET_RX, 0x0c),
+};
+
+static const struct qmp_phy_init_tbl sm8350_qmp_gen3x2_pcie_rc_pcs_tbl[] = {
+ QMP_PHY_INIT_CFG(QPHY_V5_PCS_EQ_CONFIG2, 0x0f),
+};
+
static const struct qmp_phy_init_tbl sm8450_qmp_gen4x2_pcie_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V5_COM_BIAS_EN_CLKBUFLR_EN, 0x14),
QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_IVCO, 0x0f),
@@ -1458,6 +1506,234 @@ static const struct qmp_phy_init_tbl sm8450_qmp_gen4x2_pcie_ep_pcs_misc_tbl[] =
QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_PCIE_OSC_DTCT_MODE2_CONFIG5, 0x08),
};
+static const struct qmp_phy_init_tbl sm8550_qmp_gen3x2_pcie_serdes_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_EN_CENTER, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_PER1, 0x62),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_PER2, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE1_MODE0, 0xf8),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE2_MODE0, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE1_MODE1, 0x93),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE2_MODE1, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CLK_ENABLE1, 0x90),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYS_CLK_CTRL, 0x82),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE1, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE0, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE1, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE0, 0x36),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE1, 0x36),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYSCLK_EN_SEL, 0x08),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_BG_TIMER, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_EN, 0x42),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x0d),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE1, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE1, 0x1a),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x41),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE1, 0x34),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START1_MODE0, 0xab),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START2_MODE0, 0xaa),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START3_MODE0, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START1_MODE1, 0x55),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START2_MODE1, 0x55),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START3_MODE1, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CLK_SELECT, 0x34),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_SEL_1, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CORECLK_DIV_MODE1, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_CONFIG_1, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_ADDITIONAL_MISC_3, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CORE_CLK_EN, 0xa0),
+};
+
+static const struct qmp_phy_init_tbl sm8550_qmp_gen3x2_pcie_tx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V6_TX_LANE_MODE_1, 0x15),
+ QMP_PHY_INIT_CFG(QSERDES_V6_TX_LANE_MODE_4, 0x3f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_TX_PI_QEC_CTRL, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V6_TX_RES_CODE_LANE_OFFSET_RX, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V6_TX_RES_CODE_LANE_OFFSET_TX, 0x18),
+};
+
+static const struct qmp_phy_init_tbl sm8550_qmp_gen3x2_pcie_rx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_DFE_CTLE_POST_CAL_OFFSET, 0x38),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_GM_CAL, 0x11),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_00_HIGH, 0xbf),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_00_HIGH2, 0xbf),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_00_HIGH3, 0xb7),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_00_HIGH4, 0xea),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_00_LOW, 0x3f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_01_HIGH, 0x5c),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_01_HIGH2, 0x9c),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_01_HIGH3, 0x1a),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_01_HIGH4, 0x89),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_01_LOW, 0xdc),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_10_HIGH, 0x94),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_10_HIGH2, 0x5b),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_10_HIGH3, 0x1a),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_10_HIGH4, 0x89),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_TX_ADAPT_POST_THRESH, 0xf0),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_UCDR_FO_GAIN, 0x09),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_UCDR_SO_GAIN, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_UCDR_SB2_THRESH1, 0x08),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_UCDR_SB2_THRESH2, 0x08),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_VGA_CAL_CNTRL2, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_SIDGET_ENABLES, 0x1c),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_IDAC_TSETTLE_LOW, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_V6_RX_SIGDET_CAL_TRIM, 0x08),
+};
+
+static const struct qmp_phy_init_tbl sm8550_qmp_gen3x2_pcie_pcs_tbl[] = {
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_REFGEN_REQ_CONFIG1, 0x05),
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_RX_SIGDET_LVL, 0x77),
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_RATE_SLEW_CNTRL1, 0x0b),
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_EQ_CONFIG2, 0x0f),
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_PCS_TX_RX_CONFIG, 0x8c),
+};
+
+static const struct qmp_phy_init_tbl sm8550_qmp_gen3x2_pcie_pcs_misc_tbl[] = {
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V6_PCS_PCIE_POWER_STATE_CONFIG2, 0x1d),
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V6_PCS_PCIE_POWER_STATE_CONFIG4, 0x07),
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V6_PCS_PCIE_ENDPOINT_REFCLK_DRIVE, 0xc1),
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V6_PCS_PCIE_OSC_DTCT_ACTIONS, 0x00),
+};
+
+static const struct qmp_phy_init_tbl sm8550_qmp_gen4x2_pcie_serdes_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE1_MODE1, 0x26),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE2_MODE1, 0x03),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE1, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE1, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE1, 0x36),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CORECLK_DIV_MODE1, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE1, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE1, 0x1a),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE1, 0x68),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START1_MODE1, 0xab),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START2_MODE1, 0xaa),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START3_MODE1, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_SEL_1, 0x12),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE1_MODE0, 0xf8),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE2_MODE0, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE0, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE0, 0x36),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CORE_CLK_DIV_MODE0, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x0d),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x41),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START1_MODE0, 0xab),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START2_MODE0, 0xaa),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START3_MODE0, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_HS_SWITCH_SEL_1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_BG_TIMER, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_EN_CENTER, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_PER1, 0x62),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_PER2, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_POST_DIV_MUX, 0x40),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_BIAS_EN_CLK_BUFLR_EN, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CLK_ENABLE1, 0x90),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYS_CLK_CTRL, 0x82),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYSCLK_EN_SEL, 0x08),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_EN, 0x46),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_CFG, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CLK_SELECT, 0x34),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CORE_CLK_EN, 0xa0),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_CONFIG_1, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_MISC_1, 0x88),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_MODE, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_VCO_DC_LEVEL_CTRL, 0x0f),
+};
+
+static const struct qmp_phy_init_tbl sm8550_qmp_gen4x2_pcie_ln_shrd_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RXCLK_DIV2_CTRL, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_Q_EN_RATES, 0xe),
+ QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_DFE_DAC_ENABLE1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_TX_ADAPT_POST_THRESH1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_TX_ADAPT_POST_THRESH2, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B0, 0x12),
+ QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B1, 0x12),
+ QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B2, 0xdb),
+ QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B3, 0x9a),
+ QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B4, 0x38),
+ QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B5, 0xb6),
+ QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B6, 0x64),
+ QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH1_RATE210, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH1_RATE3, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH2_RATE210, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH2_RATE3, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH3_RATE210, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH3_RATE3, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH4_RATE3, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH5_RATE3, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH6_RATE3, 0x1f),
+};
+
+static const struct qmp_phy_init_tbl sm8550_qmp_gen4x2_pcie_tx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V6_20_TX_RES_CODE_LANE_OFFSET_TX, 0x1d),
+ QMP_PHY_INIT_CFG(QSERDES_V6_20_TX_RES_CODE_LANE_OFFSET_RX, 0x03),
+ QMP_PHY_INIT_CFG(QSERDES_V6_20_TX_LANE_MODE_1, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V6_20_TX_LANE_MODE_2, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V6_20_TX_LANE_MODE_3, 0x51),
+ QMP_PHY_INIT_CFG(QSERDES_V6_20_TX_TRAN_DRVR_EMP_EN, 0x34),
+};
+
+static const struct qmp_phy_init_tbl sm8550_qmp_gen4x2_pcie_rx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_UCDR_FO_GAIN_RATE_2, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_UCDR_FO_GAIN_RATE_3, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_UCDR_PI_CONTROLS, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_UCDR_SO_ACC_DEFAULT_VAL_RATE3, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_IVCM_CAL_CTRL2, 0x80),
+ QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_IVCM_POSTCAL_OFFSET, 0x7c),
+ QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_DFE_3, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_VGA_CAL_MAN_VAL, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_GM_CAL, 0x0d),
+ QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_EQU_ADAPTOR_CNTRL4, 0x0b),
+ QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_SIGDET_ENABLES, 0x1c),
+ QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_PHPRE_CTRL, 0x20),
+ QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_DFE_CTLE_POST_CAL_OFFSET, 0x30),
+ QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_Q_PI_INTRINSIC_BIAS_RATE32, 0x09),
+ QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE2_B0, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE2_B1, 0xb3),
+ QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE2_B2, 0x58),
+ QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE2_B3, 0x9a),
+ QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE2_B4, 0x26),
+ QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE2_B5, 0xb6),
+ QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE2_B6, 0xee),
+ QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B0, 0xdb),
+ QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B1, 0xdb),
+ QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B2, 0xa0),
+ QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B3, 0xdf),
+ QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B4, 0x78),
+ QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B5, 0x76),
+ QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B6, 0xff),
+};
+
+static const struct qmp_phy_init_tbl sm8550_qmp_gen4x2_pcie_pcs_tbl[] = {
+ QMP_PHY_INIT_CFG(QPHY_V6_20_PCS_G3S2_PRE_GAIN, 0x2e),
+ QMP_PHY_INIT_CFG(QPHY_V6_20_PCS_COM_ELECIDLE_DLY_SEL, 0x25),
+ QMP_PHY_INIT_CFG(QPHY_V6_20_PCS_EQ_CONFIG4, 0x00),
+ QMP_PHY_INIT_CFG(QPHY_V6_20_PCS_EQ_CONFIG5, 0x22),
+ QMP_PHY_INIT_CFG(QPHY_V6_20_PCS_TX_RX_CONFIG1, 0x04),
+ QMP_PHY_INIT_CFG(QPHY_V6_20_PCS_TX_RX_CONFIG2, 0x02),
+};
+
+static const struct qmp_phy_init_tbl sm8550_qmp_gen4x2_pcie_pcs_misc_tbl[] = {
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_ENDPOINT_REFCLK_DRIVE, 0xc1),
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_OSC_DTCT_ATCIONS, 0x00),
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_EQ_CONFIG1, 0x16),
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_EQ_CONFIG5, 0x02),
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_G4_PRE_GAIN, 0x2e),
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_RX_MARGINING_CONFIG1, 0x03),
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_RX_MARGINING_CONFIG3, 0x28),
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_TX_RX_CONFIG, 0xc0),
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_POWER_STATE_CONFIG2, 0x1d),
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_RX_MARGINING_CONFIG5, 0x0f),
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_G3_FOM_EQ_CONFIG5, 0xf2),
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_G4_FOM_EQ_CONFIG5, 0xf2),
+};
+
struct qmp_pcie_offsets {
u16 serdes;
u16 pcs;
@@ -1466,6 +1742,7 @@ struct qmp_pcie_offsets {
u16 rx;
u16 tx2;
u16 rx2;
+ u16 ln_shrd;
};
struct qmp_phy_cfg_tbls {
@@ -1479,6 +1756,8 @@ struct qmp_phy_cfg_tbls {
int pcs_num;
const struct qmp_phy_init_tbl *pcs_misc;
int pcs_misc_num;
+ const struct qmp_phy_init_tbl *ln_shrd;
+ int ln_shrd_num;
};
/* struct qmp_phy_cfg - per-PHY initialization config */
@@ -1521,6 +1800,8 @@ struct qmp_phy_cfg {
bool skip_start_delay;
+ bool has_nocsr_reset;
+
/* QMP PHY pipe clock interface rate */
unsigned long pipe_clock_rate;
};
@@ -1538,6 +1819,7 @@ struct qmp_pcie {
void __iomem *rx;
void __iomem *tx2;
void __iomem *rx2;
+ void __iomem *ln_shrd;
void __iomem *port_b;
@@ -1546,6 +1828,7 @@ struct qmp_pcie {
int num_pipe_clks;
struct reset_control_bulk_data *resets;
+ struct reset_control *nocsr_reset;
struct regulator_bulk_data *vregs;
struct phy *phy;
@@ -1600,6 +1883,10 @@ static const char * const qmp_phy_vreg_l[] = {
"vdda-phy", "vdda-pll",
};
+static const char * const sm8550_qmp_phy_vreg_l[] = {
+ "vdda-phy", "vdda-pll", "vdda-qref",
+};
+
/* list of resets */
static const char * const ipq8074_pciephy_reset_l[] = {
"phy", "common",
@@ -1619,6 +1906,17 @@ static const struct qmp_pcie_offsets qmp_pcie_offsets_v5 = {
.rx2 = 0x1800,
};
+static const struct qmp_pcie_offsets qmp_pcie_offsets_v6_20 = {
+ .serdes = 0x1000,
+ .pcs = 0x1200,
+ .pcs_misc = 0x1400,
+ .tx = 0x0000,
+ .rx = 0x0200,
+ .tx2 = 0x0800,
+ .rx2 = 0x0a00,
+ .ln_shrd = 0x0e00,
+};
+
static const struct qmp_phy_cfg ipq8074_pciephy_cfg = {
.lanes = 1,
@@ -1638,7 +1936,7 @@ static const struct qmp_phy_cfg ipq8074_pciephy_cfg = {
.num_resets = ARRAY_SIZE(ipq8074_pciephy_reset_l),
.vreg_list = NULL,
.num_vregs = 0,
- .regs = pciephy_regs_layout,
+ .regs = pciephy_v2_regs_layout,
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
.phy_status = PHYSTATUS,
@@ -1665,7 +1963,7 @@ static const struct qmp_phy_cfg ipq8074_pciephy_gen3_cfg = {
.num_resets = ARRAY_SIZE(ipq8074_pciephy_reset_l),
.vreg_list = NULL,
.num_vregs = 0,
- .regs = ipq_pciephy_gen3_regs_layout,
+ .regs = pciephy_v4_regs_layout,
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
.phy_status = PHYSTATUS,
@@ -1694,7 +1992,7 @@ static const struct qmp_phy_cfg ipq6018_pciephy_cfg = {
.num_resets = ARRAY_SIZE(ipq8074_pciephy_reset_l),
.vreg_list = NULL,
.num_vregs = 0,
- .regs = ipq_pciephy_gen3_regs_layout,
+ .regs = pciephy_v4_regs_layout,
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
.phy_status = PHYSTATUS,
@@ -1721,7 +2019,7 @@ static const struct qmp_phy_cfg sdm845_qmp_pciephy_cfg = {
.num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l),
.vreg_list = qmp_phy_vreg_l,
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
- .regs = sdm845_qmp_pciephy_regs_layout,
+ .regs = pciephy_v3_regs_layout,
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
.phy_status = PHYSTATUS,
@@ -1783,7 +2081,7 @@ static const struct qmp_phy_cfg sm8250_qmp_gen3x1_pciephy_cfg = {
.num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l),
.vreg_list = qmp_phy_vreg_l,
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
- .regs = sm8250_pcie_regs_layout,
+ .regs = pciephy_v4_regs_layout,
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
.phy_status = PHYSTATUS,
@@ -1820,7 +2118,7 @@ static const struct qmp_phy_cfg sm8250_qmp_gen3x2_pciephy_cfg = {
.num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l),
.vreg_list = qmp_phy_vreg_l,
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
- .regs = sm8250_pcie_regs_layout,
+ .regs = pciephy_v4_regs_layout,
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
.phy_status = PHYSTATUS,
@@ -1845,7 +2143,7 @@ static const struct qmp_phy_cfg msm8998_pciephy_cfg = {
.num_resets = ARRAY_SIZE(ipq8074_pciephy_reset_l),
.vreg_list = qmp_phy_vreg_l,
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
- .regs = pciephy_regs_layout,
+ .regs = pciephy_v3_regs_layout,
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
.phy_status = PHYSTATUS,
@@ -1874,7 +2172,7 @@ static const struct qmp_phy_cfg sc8180x_pciephy_cfg = {
.num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l),
.vreg_list = qmp_phy_vreg_l,
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
- .regs = sm8250_pcie_regs_layout,
+ .regs = pciephy_v4_regs_layout,
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
.phy_status = PHYSTATUS,
@@ -1909,7 +2207,7 @@ static const struct qmp_phy_cfg sc8280xp_qmp_gen3x1_pciephy_cfg = {
.num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l),
.vreg_list = qmp_phy_vreg_l,
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
- .regs = sm8250_pcie_regs_layout,
+ .regs = pciephy_v5_regs_layout,
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
.phy_status = PHYSTATUS,
@@ -1944,7 +2242,7 @@ static const struct qmp_phy_cfg sc8280xp_qmp_gen3x2_pciephy_cfg = {
.num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l),
.vreg_list = qmp_phy_vreg_l,
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
- .regs = sm8250_pcie_regs_layout,
+ .regs = pciephy_v5_regs_layout,
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
.phy_status = PHYSTATUS,
@@ -1982,7 +2280,7 @@ static const struct qmp_phy_cfg sc8280xp_qmp_gen3x4_pciephy_cfg = {
.num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l),
.vreg_list = qmp_phy_vreg_l,
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
- .regs = sm8250_pcie_regs_layout,
+ .regs = pciephy_v5_regs_layout,
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
.phy_status = PHYSTATUS,
@@ -2009,34 +2307,116 @@ static const struct qmp_phy_cfg sdx55_qmp_pciephy_cfg = {
.num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l),
.vreg_list = qmp_phy_vreg_l,
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
- .regs = sm8250_pcie_regs_layout,
+ .regs = pciephy_v4_regs_layout,
.pwrdn_ctrl = SW_PWRDN,
.phy_status = PHYSTATUS_4_20,
};
+static const struct qmp_phy_cfg sm8350_qmp_gen3x1_pciephy_cfg = {
+ .lanes = 1,
+
+ .offsets = &qmp_pcie_offsets_v5,
+
+ .tbls = {
+ .serdes = sm8450_qmp_gen3_pcie_serdes_tbl,
+ .serdes_num = ARRAY_SIZE(sm8450_qmp_gen3_pcie_serdes_tbl),
+ .tx = sm8350_qmp_gen3x1_pcie_tx_tbl,
+ .tx_num = ARRAY_SIZE(sm8350_qmp_gen3x1_pcie_tx_tbl),
+ .rx = sm8450_qmp_gen3_pcie_rx_tbl,
+ .rx_num = ARRAY_SIZE(sm8450_qmp_gen3_pcie_rx_tbl),
+ .pcs = sm8450_qmp_gen3_pcie_pcs_tbl,
+ .pcs_num = ARRAY_SIZE(sm8450_qmp_gen3_pcie_pcs_tbl),
+ .pcs_misc = sm8450_qmp_gen3x1_pcie_pcs_misc_tbl,
+ .pcs_misc_num = ARRAY_SIZE(sm8450_qmp_gen3x1_pcie_pcs_misc_tbl),
+ },
+
+ .tbls_rc = &(const struct qmp_phy_cfg_tbls) {
+ .serdes = sm8450_qmp_gen3x1_pcie_rc_serdes_tbl,
+ .serdes_num = ARRAY_SIZE(sm8450_qmp_gen3x1_pcie_rc_serdes_tbl),
+ .rx = sm8350_qmp_gen3x1_pcie_rc_rx_tbl,
+ .rx_num = ARRAY_SIZE(sm8350_qmp_gen3x1_pcie_rc_rx_tbl),
+ },
+
+ .clk_list = sc8280xp_pciephy_clk_l,
+ .num_clks = ARRAY_SIZE(sc8280xp_pciephy_clk_l),
+ .reset_list = sdm845_pciephy_reset_l,
+ .num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l),
+ .vreg_list = qmp_phy_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
+ .regs = pciephy_v5_regs_layout,
+
+ .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
+ .phy_status = PHYSTATUS,
+};
+
+static const struct qmp_phy_cfg sm8350_qmp_gen3x2_pciephy_cfg = {
+ .lanes = 2,
+
+ .offsets = &qmp_pcie_offsets_v5,
+
+ .tbls = {
+ .serdes = sm8450_qmp_gen3_pcie_serdes_tbl,
+ .serdes_num = ARRAY_SIZE(sm8450_qmp_gen3_pcie_serdes_tbl),
+ .tx = sm8350_qmp_gen3x2_pcie_tx_tbl,
+ .tx_num = ARRAY_SIZE(sm8350_qmp_gen3x2_pcie_tx_tbl),
+ .rx = sm8450_qmp_gen3_pcie_rx_tbl,
+ .rx_num = ARRAY_SIZE(sm8450_qmp_gen3_pcie_rx_tbl),
+ .pcs = sm8450_qmp_gen3_pcie_pcs_tbl,
+ .pcs_num = ARRAY_SIZE(sm8450_qmp_gen3_pcie_pcs_tbl),
+ .pcs_misc = sc8280xp_qmp_gen3x2_pcie_pcs_misc_tbl,
+ .pcs_misc_num = ARRAY_SIZE(sc8280xp_qmp_gen3x2_pcie_pcs_misc_tbl),
+ },
+
+ .tbls_rc = &(const struct qmp_phy_cfg_tbls) {
+ .rx = sm8350_qmp_gen3x2_pcie_rc_rx_tbl,
+ .rx_num = ARRAY_SIZE(sm8350_qmp_gen3x2_pcie_rc_rx_tbl),
+ .pcs = sm8350_qmp_gen3x2_pcie_rc_pcs_tbl,
+ .pcs_num = ARRAY_SIZE(sm8350_qmp_gen3x2_pcie_rc_pcs_tbl),
+ },
+
+ .clk_list = sc8280xp_pciephy_clk_l,
+ .num_clks = ARRAY_SIZE(sc8280xp_pciephy_clk_l),
+ .reset_list = sdm845_pciephy_reset_l,
+ .num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l),
+ .vreg_list = qmp_phy_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
+ .regs = pciephy_v5_regs_layout,
+
+ .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
+ .phy_status = PHYSTATUS,
+};
+
static const struct qmp_phy_cfg sm8450_qmp_gen3x1_pciephy_cfg = {
.lanes = 1,
.tbls = {
- .serdes = sm8450_qmp_gen3x1_pcie_serdes_tbl,
- .serdes_num = ARRAY_SIZE(sm8450_qmp_gen3x1_pcie_serdes_tbl),
+ .serdes = sm8450_qmp_gen3_pcie_serdes_tbl,
+ .serdes_num = ARRAY_SIZE(sm8450_qmp_gen3_pcie_serdes_tbl),
.tx = sm8450_qmp_gen3x1_pcie_tx_tbl,
.tx_num = ARRAY_SIZE(sm8450_qmp_gen3x1_pcie_tx_tbl),
- .rx = sm8450_qmp_gen3x1_pcie_rx_tbl,
- .rx_num = ARRAY_SIZE(sm8450_qmp_gen3x1_pcie_rx_tbl),
- .pcs = sm8450_qmp_gen3x1_pcie_pcs_tbl,
- .pcs_num = ARRAY_SIZE(sm8450_qmp_gen3x1_pcie_pcs_tbl),
+ .rx = sm8450_qmp_gen3_pcie_rx_tbl,
+ .rx_num = ARRAY_SIZE(sm8450_qmp_gen3_pcie_rx_tbl),
+ .pcs = sm8450_qmp_gen3_pcie_pcs_tbl,
+ .pcs_num = ARRAY_SIZE(sm8450_qmp_gen3_pcie_pcs_tbl),
.pcs_misc = sm8450_qmp_gen3x1_pcie_pcs_misc_tbl,
.pcs_misc_num = ARRAY_SIZE(sm8450_qmp_gen3x1_pcie_pcs_misc_tbl),
},
+
+ .tbls_rc = &(const struct qmp_phy_cfg_tbls) {
+ .serdes = sm8450_qmp_gen3x1_pcie_rc_serdes_tbl,
+ .serdes_num = ARRAY_SIZE(sm8450_qmp_gen3x1_pcie_rc_serdes_tbl),
+ .rx = sm8450_qmp_gen3x1_pcie_rc_rx_tbl,
+ .rx_num = ARRAY_SIZE(sm8450_qmp_gen3x1_pcie_rc_rx_tbl),
+ },
+
.clk_list = sdm845_pciephy_clk_l,
.num_clks = ARRAY_SIZE(sdm845_pciephy_clk_l),
.reset_list = sdm845_pciephy_reset_l,
.num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l),
.vreg_list = qmp_phy_vreg_l,
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
- .regs = sm8250_pcie_regs_layout,
+ .regs = pciephy_v5_regs_layout,
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
.phy_status = PHYSTATUS,
@@ -2078,12 +2458,73 @@ static const struct qmp_phy_cfg sm8450_qmp_gen4x2_pciephy_cfg = {
.num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l),
.vreg_list = qmp_phy_vreg_l,
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
- .regs = sm8250_pcie_regs_layout,
+ .regs = pciephy_v5_regs_layout,
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
.phy_status = PHYSTATUS_4_20,
};
+static const struct qmp_phy_cfg sm8550_qmp_gen3x2_pciephy_cfg = {
+ .lanes = 2,
+
+ .offsets = &qmp_pcie_offsets_v5,
+
+ .tbls = {
+ .serdes = sm8550_qmp_gen3x2_pcie_serdes_tbl,
+ .serdes_num = ARRAY_SIZE(sm8550_qmp_gen3x2_pcie_serdes_tbl),
+ .tx = sm8550_qmp_gen3x2_pcie_tx_tbl,
+ .tx_num = ARRAY_SIZE(sm8550_qmp_gen3x2_pcie_tx_tbl),
+ .rx = sm8550_qmp_gen3x2_pcie_rx_tbl,
+ .rx_num = ARRAY_SIZE(sm8550_qmp_gen3x2_pcie_rx_tbl),
+ .pcs = sm8550_qmp_gen3x2_pcie_pcs_tbl,
+ .pcs_num = ARRAY_SIZE(sm8550_qmp_gen3x2_pcie_pcs_tbl),
+ .pcs_misc = sm8550_qmp_gen3x2_pcie_pcs_misc_tbl,
+ .pcs_misc_num = ARRAY_SIZE(sm8550_qmp_gen3x2_pcie_pcs_misc_tbl),
+ },
+ .clk_list = sc8280xp_pciephy_clk_l,
+ .num_clks = ARRAY_SIZE(sc8280xp_pciephy_clk_l),
+ .reset_list = sdm845_pciephy_reset_l,
+ .num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l),
+ .vreg_list = qmp_phy_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
+ .regs = pciephy_v5_regs_layout,
+
+ .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
+ .phy_status = PHYSTATUS,
+};
+
+static const struct qmp_phy_cfg sm8550_qmp_gen4x2_pciephy_cfg = {
+ .lanes = 2,
+
+ .offsets = &qmp_pcie_offsets_v6_20,
+
+ .tbls = {
+ .serdes = sm8550_qmp_gen4x2_pcie_serdes_tbl,
+ .serdes_num = ARRAY_SIZE(sm8550_qmp_gen4x2_pcie_serdes_tbl),
+ .tx = sm8550_qmp_gen4x2_pcie_tx_tbl,
+ .tx_num = ARRAY_SIZE(sm8550_qmp_gen4x2_pcie_tx_tbl),
+ .rx = sm8550_qmp_gen4x2_pcie_rx_tbl,
+ .rx_num = ARRAY_SIZE(sm8550_qmp_gen4x2_pcie_rx_tbl),
+ .pcs = sm8550_qmp_gen4x2_pcie_pcs_tbl,
+ .pcs_num = ARRAY_SIZE(sm8550_qmp_gen4x2_pcie_pcs_tbl),
+ .pcs_misc = sm8550_qmp_gen4x2_pcie_pcs_misc_tbl,
+ .pcs_misc_num = ARRAY_SIZE(sm8550_qmp_gen4x2_pcie_pcs_misc_tbl),
+ .ln_shrd = sm8550_qmp_gen4x2_pcie_ln_shrd_tbl,
+ .ln_shrd_num = ARRAY_SIZE(sm8550_qmp_gen4x2_pcie_ln_shrd_tbl),
+ },
+ .clk_list = sc8280xp_pciephy_clk_l,
+ .num_clks = ARRAY_SIZE(sc8280xp_pciephy_clk_l),
+ .reset_list = sdm845_pciephy_reset_l,
+ .num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l),
+ .vreg_list = sm8550_qmp_phy_vreg_l,
+ .num_vregs = ARRAY_SIZE(sm8550_qmp_phy_vreg_l),
+ .regs = pciephy_v5_regs_layout,
+
+ .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
+ .phy_status = PHYSTATUS_4_20,
+ .has_nocsr_reset = true,
+};
+
static void qmp_pcie_configure_lane(void __iomem *base,
const struct qmp_phy_init_tbl tbl[],
int num,
@@ -2138,6 +2579,7 @@ static void qmp_pcie_init_registers(struct qmp_pcie *qmp, const struct qmp_phy_c
void __iomem *rx2 = qmp->rx2;
void __iomem *pcs = qmp->pcs;
void __iomem *pcs_misc = qmp->pcs_misc;
+ void __iomem *ln_shrd = qmp->ln_shrd;
if (!tbls)
return;
@@ -2159,6 +2601,8 @@ static void qmp_pcie_init_registers(struct qmp_pcie *qmp, const struct qmp_phy_c
qmp_pcie_configure(serdes, cfg->serdes_4ln_tbl, cfg->serdes_4ln_num);
qmp_pcie_init_port_b(qmp, tbls);
}
+
+ qmp_pcie_configure(ln_shrd, tbls->ln_shrd, tbls->ln_shrd_num);
}
static int qmp_pcie_init(struct phy *phy)
@@ -2179,12 +2623,18 @@ static int qmp_pcie_init(struct phy *phy)
goto err_disable_regulators;
}
+ ret = reset_control_assert(qmp->nocsr_reset);
+ if (ret) {
+ dev_err(qmp->dev, "no-csr reset assert failed\n");
+ goto err_assert_reset;
+ }
+
usleep_range(200, 300);
ret = reset_control_bulk_deassert(cfg->num_resets, qmp->resets);
if (ret) {
dev_err(qmp->dev, "reset deassert failed\n");
- goto err_disable_regulators;
+ goto err_assert_reset;
}
ret = clk_bulk_prepare_enable(cfg->num_clks, qmp->clks);
@@ -2240,6 +2690,12 @@ static int qmp_pcie_power_on(struct phy *phy)
if (ret)
return ret;
+ ret = reset_control_deassert(qmp->nocsr_reset);
+ if (ret) {
+ dev_err(qmp->dev, "no-csr reset deassert failed\n");
+ goto err_disable_pipe_clk;
+ }
+
/* Pull PHY out of reset state */
qphy_clrbits(pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
@@ -2373,6 +2829,13 @@ static int qmp_pcie_reset_init(struct qmp_pcie *qmp)
if (ret)
return dev_err_probe(dev, ret, "failed to get resets\n");
+ if (cfg->has_nocsr_reset) {
+ qmp->nocsr_reset = devm_reset_control_get_exclusive(dev, "phy_nocsr");
+ if (IS_ERR(qmp->nocsr_reset))
+ return dev_err_probe(dev, PTR_ERR(qmp->nocsr_reset),
+ "failed to get no-csr reset\n");
+ }
+
return 0;
}
@@ -2595,11 +3058,18 @@ static int qmp_pcie_parse_dt(struct qmp_pcie *qmp)
return PTR_ERR(qmp->port_b);
}
+ if (cfg->tbls.ln_shrd)
+ qmp->ln_shrd = base + offs->ln_shrd;
+
qmp->num_pipe_clks = 2;
qmp->pipe_clks[0].id = "pipe";
qmp->pipe_clks[1].id = "pipediv2";
- ret = devm_clk_bulk_get(dev, qmp->num_pipe_clks, qmp->pipe_clks);
+ ret = devm_clk_bulk_get(dev, 1, qmp->pipe_clks);
+ if (ret)
+ return ret;
+
+ ret = devm_clk_bulk_get_optional(dev, qmp->num_pipe_clks - 1, qmp->pipe_clks + 1);
if (ret)
return ret;
@@ -2720,11 +3190,23 @@ static const struct of_device_id qmp_pcie_of_match_table[] = {
.compatible = "qcom,sm8250-qmp-modem-pcie-phy",
.data = &sm8250_qmp_gen3x2_pciephy_cfg,
}, {
+ .compatible = "qcom,sm8350-qmp-gen3x1-pcie-phy",
+ .data = &sm8350_qmp_gen3x1_pciephy_cfg,
+ }, {
+ .compatible = "qcom,sm8350-qmp-gen3x2-pcie-phy",
+ .data = &sm8350_qmp_gen3x2_pciephy_cfg,
+ }, {
.compatible = "qcom,sm8450-qmp-gen3x1-pcie-phy",
.data = &sm8450_qmp_gen3x1_pciephy_cfg,
}, {
.compatible = "qcom,sm8450-qmp-gen4x2-pcie-phy",
.data = &sm8450_qmp_gen4x2_pciephy_cfg,
+ }, {
+ .compatible = "qcom,sm8550-qmp-gen3x2-pcie-phy",
+ .data = &sm8550_qmp_gen3x2_pciephy_cfg,
+ }, {
+ .compatible = "qcom,sm8550-qmp-gen4x2-pcie-phy",
+ .data = &sm8550_qmp_gen4x2_pciephy_cfg,
},
{ },
};
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6.h
new file mode 100644
index 000000000000..91e70002eb47
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2023, Linaro Limited
+ */
+
+#ifndef QCOM_PHY_QMP_PCS_PCIE_V6_H_
+#define QCOM_PHY_QMP_PCS_PCIE_V6_H_
+
+/* Only for QMP V6 PHY - PCIE have different offsets than V5 */
+#define QPHY_PCIE_V6_PCS_PCIE_POWER_STATE_CONFIG2 0x0c
+#define QPHY_PCIE_V6_PCS_PCIE_POWER_STATE_CONFIG4 0x14
+#define QPHY_PCIE_V6_PCS_PCIE_ENDPOINT_REFCLK_DRIVE 0x20
+#define QPHY_PCIE_V6_PCS_PCIE_OSC_DTCT_ACTIONS 0x94
+
+#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6_20.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6_20.h
new file mode 100644
index 000000000000..e3eb08776339
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6_20.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2023, Linaro Limited
+ */
+
+#ifndef QCOM_PHY_QMP_PCS_PCIE_V6_20_H_
+#define QCOM_PHY_QMP_PCS_PCIE_V6_20_H_
+
+/* Only for QMP V6_20 PHY - PCIE have different offsets than V5 */
+#define QPHY_PCIE_V6_20_PCS_POWER_STATE_CONFIG2 0x00c
+#define QPHY_PCIE_V6_20_PCS_TX_RX_CONFIG 0x018
+#define QPHY_PCIE_V6_20_PCS_ENDPOINT_REFCLK_DRIVE 0x01c
+#define QPHY_PCIE_V6_20_PCS_OSC_DTCT_ATCIONS 0x090
+#define QPHY_PCIE_V6_20_PCS_EQ_CONFIG1 0x0a0
+#define QPHY_PCIE_V6_20_PCS_EQ_CONFIG5 0x108
+#define QPHY_PCIE_V6_20_PCS_G4_PRE_GAIN 0x15c
+#define QPHY_PCIE_V6_20_PCS_RX_MARGINING_CONFIG1 0x17c
+#define QPHY_PCIE_V6_20_PCS_RX_MARGINING_CONFIG3 0x184
+#define QPHY_PCIE_V6_20_PCS_RX_MARGINING_CONFIG5 0x18c
+#define QPHY_PCIE_V6_20_PCS_G3_FOM_EQ_CONFIG5 0x1ac
+#define QPHY_PCIE_V6_20_PCS_G4_FOM_EQ_CONFIG5 0x1c0
+
+#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v2.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v2.h
new file mode 100644
index 000000000000..a0803a8783d2
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v2.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef QCOM_PHY_QMP_PCS_UFS_V2_H_
+#define QCOM_PHY_QMP_PCS_UFS_V2_H_
+
+#define QPHY_V2_PCS_UFS_PHY_START 0x000
+#define QPHY_V2_PCS_UFS_POWER_DOWN_CONTROL 0x004
+
+#define QPHY_V2_PCS_UFS_TX_LARGE_AMP_DRV_LVL 0x034
+#define QPHY_V2_PCS_UFS_TX_LARGE_AMP_POST_EMP_LVL 0x038
+#define QPHY_V2_PCS_UFS_TX_SMALL_AMP_DRV_LVL 0x03c
+#define QPHY_V2_PCS_UFS_TX_SMALL_AMP_POST_EMP_LVL 0x040
+
+#define QPHY_V2_PCS_UFS_RX_MIN_STALL_NOCONFIG_TIME_CAP 0x0cc
+#define QPHY_V2_PCS_UFS_RX_SYM_RESYNC_CTRL 0x13c
+#define QPHY_V2_PCS_UFS_RX_MIN_HIBERN8_TIME 0x140
+#define QPHY_V2_PCS_UFS_RX_SIGDET_CTRL2 0x148
+#define QPHY_V2_PCS_UFS_RX_PWM_GEAR_BAND 0x154
+
+#define QPHY_V2_PCS_UFS_READY_STATUS 0x168
+
+#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v3.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v3.h
index ba1ea29d2884..adea13c3a9e6 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v3.h
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v3.h
@@ -6,12 +6,15 @@
#ifndef QCOM_PHY_QMP_PCS_UFS_V3_H_
#define QCOM_PHY_QMP_PCS_UFS_V3_H_
+#define QPHY_V3_PCS_UFS_PHY_START 0x000
+#define QPHY_V3_PCS_UFS_POWER_DOWN_CONTROL 0x004
#define QPHY_V3_PCS_UFS_TX_LARGE_AMP_DRV_LVL 0x02c
#define QPHY_V3_PCS_UFS_TX_SMALL_AMP_DRV_LVL 0x034
#define QPHY_V3_PCS_UFS_RX_SYM_RESYNC_CTRL 0x134
#define QPHY_V3_PCS_UFS_RX_MIN_HIBERN8_TIME 0x138
#define QPHY_V3_PCS_UFS_RX_SIGDET_CTRL1 0x13c
#define QPHY_V3_PCS_UFS_RX_SIGDET_CTRL2 0x140
+#define QPHY_V3_PCS_UFS_READY_STATUS 0x160
#define QPHY_V3_PCS_UFS_TX_MID_TERM_CTRL1 0x1bc
#define QPHY_V3_PCS_UFS_MULTI_LANE_CTRL1 0x1c4
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v5.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v5.h
index bcca23493b7e..07959964fcf6 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v5.h
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v5.h
@@ -8,11 +8,15 @@
#define QCOM_PHY_QMP_PCS_UFS_V5_H_
/* Only for QMP V5 PHY - UFS PCS registers */
+#define QPHY_V5_PCS_UFS_PHY_START 0x000
+#define QPHY_V5_PCS_UFS_POWER_DOWN_CONTROL 0x004
+#define QPHY_V5_PCS_UFS_SW_RESET 0x008
#define QPHY_V5_PCS_UFS_TIMER_20US_CORECLK_STEPS_MSB 0x00c
#define QPHY_V5_PCS_UFS_TIMER_20US_CORECLK_STEPS_LSB 0x010
#define QPHY_V5_PCS_UFS_PLL_CNTL 0x02c
#define QPHY_V5_PCS_UFS_TX_LARGE_AMP_DRV_LVL 0x030
#define QPHY_V5_PCS_UFS_TX_SMALL_AMP_DRV_LVL 0x038
+#define QPHY_V5_PCS_UFS_BIST_FIXED_PAT_CTRL 0x060
#define QPHY_V5_PCS_UFS_TX_HSGEAR_CAPABILITY 0x074
#define QPHY_V5_PCS_UFS_RX_HSGEAR_CAPABILITY 0x0b4
#define QPHY_V5_PCS_UFS_DEBUG_BUS_CLKSEL 0x124
@@ -21,6 +25,7 @@
#define QPHY_V5_PCS_UFS_RX_SIGDET_CTRL2 0x158
#define QPHY_V5_PCS_UFS_TX_PWM_GEAR_BAND 0x160
#define QPHY_V5_PCS_UFS_TX_HS_GEAR_BAND 0x168
+#define QPHY_V5_PCS_UFS_READY_STATUS 0x180
#define QPHY_V5_PCS_UFS_TX_MID_TERM_CTRL1 0x1d8
#define QPHY_V5_PCS_UFS_MULTI_LANE_CTRL1 0x1e0
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h
new file mode 100644
index 000000000000..c23d5e41e25b
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2023, Linaro Limited
+ */
+
+#ifndef QCOM_PHY_QMP_PCS_UFS_V6_H_
+#define QCOM_PHY_QMP_PCS_UFS_V6_H_
+
+/* Only for QMP V6 PHY - UFS PCS registers */
+#define QPHY_V6_PCS_UFS_PHY_START 0x000
+#define QPHY_V6_PCS_UFS_POWER_DOWN_CONTROL 0x004
+#define QPHY_V6_PCS_UFS_SW_RESET 0x008
+#define QPHY_V6_PCS_UFS_TIMER_20US_CORECLK_STEPS_MSB 0x00c
+#define QPHY_V6_PCS_UFS_TIMER_20US_CORECLK_STEPS_LSB 0x010
+#define QPHY_V6_PCS_UFS_PLL_CNTL 0x02c
+#define QPHY_V6_PCS_UFS_TX_LARGE_AMP_DRV_LVL 0x030
+#define QPHY_V6_PCS_UFS_TX_SMALL_AMP_DRV_LVL 0x038
+#define QPHY_V6_PCS_UFS_BIST_FIXED_PAT_CTRL 0x060
+#define QPHY_V6_PCS_UFS_TX_HSGEAR_CAPABILITY 0x074
+#define QPHY_V6_PCS_UFS_RX_HSGEAR_CAPABILITY 0x0bc
+#define QPHY_V6_PCS_UFS_DEBUG_BUS_CLKSEL 0x158
+#define QPHY_V6_PCS_UFS_LINECFG_DISABLE 0x17c
+#define QPHY_V6_PCS_UFS_RX_MIN_HIBERN8_TIME 0x184
+#define QPHY_V6_PCS_UFS_RX_SIGDET_CTRL2 0x18c
+#define QPHY_V6_PCS_UFS_TX_PWM_GEAR_BAND 0x178
+#define QPHY_V6_PCS_UFS_TX_HS_GEAR_BAND 0x174
+#define QPHY_V6_PCS_UFS_READY_STATUS 0x1a8
+#define QPHY_V6_PCS_UFS_TX_MID_TERM_CTRL1 0x1f4
+#define QPHY_V6_PCS_UFS_MULTI_LANE_CTRL1 0x1fc
+
+#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-usb-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-usb-v6.h
new file mode 100644
index 000000000000..9510e63ba9d8
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-usb-v6.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2022, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef QCOM_PHY_QMP_PCS_USB_V6_H_
+#define QCOM_PHY_QMP_PCS_USB_V6_H_
+
+/* Only for QMP V6 PHY - USB3 have different offsets than V5 */
+#define QPHY_USB_V6_PCS_LOCK_DETECT_CONFIG1 0xc4
+#define QPHY_USB_V6_PCS_LOCK_DETECT_CONFIG2 0xc8
+#define QPHY_USB_V6_PCS_LOCK_DETECT_CONFIG3 0xcc
+#define QPHY_USB_V6_PCS_LOCK_DETECT_CONFIG6 0xd8
+#define QPHY_USB_V6_PCS_REFGEN_REQ_CONFIG1 0xdc
+#define QPHY_USB_V6_PCS_USB3_POWER_STATE_CONFIG1 0x90
+#define QPHY_USB_V6_PCS_RX_SIGDET_LVL 0x188
+#define QPHY_USB_V6_PCS_RCVR_DTCT_DLY_P1U2_L 0x190
+#define QPHY_USB_V6_PCS_RCVR_DTCT_DLY_P1U2_H 0x194
+#define QPHY_USB_V6_PCS_CDR_RESET_TIME 0x1b0
+#define QPHY_USB_V6_PCS_ALIGN_DETECT_CONFIG1 0x1c0
+#define QPHY_USB_V6_PCS_ALIGN_DETECT_CONFIG2 0x1c4
+#define QPHY_USB_V6_PCS_PCS_TX_RX_CONFIG 0x1d0
+#define QPHY_USB_V6_PCS_EQ_CONFIG1 0x1dc
+#define QPHY_USB_V6_PCS_EQ_CONFIG5 0x1ec
+
+#define QPHY_USB_V6_PCS_USB3_LFPS_DET_HIGH_COUNT_VAL 0x18
+#define QPHY_USB_V6_PCS_USB3_RXEQTRAINING_DFE_TIME_S2 0x3c
+#define QPHY_USB_V6_PCS_USB3_RCVR_DTCT_DLY_U3_L 0x40
+#define QPHY_USB_V6_PCS_USB3_RCVR_DTCT_DLY_U3_H 0x44
+
+#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v2.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v2.h
index c8515f506872..bf36399d0057 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v2.h
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v2.h
@@ -7,13 +7,11 @@
#define QCOM_PHY_QMP_PCS_V2_H_
/* Only for QMP V2 PHY - PCS registers */
+#define QPHY_V2_PCS_SW_RESET 0x000
#define QPHY_V2_PCS_POWER_DOWN_CONTROL 0x004
+#define QPHY_V2_PCS_START_CONTROL 0x008
#define QPHY_V2_PCS_TXDEEMPH_M6DB_V0 0x024
#define QPHY_V2_PCS_TXDEEMPH_M3P5DB_V0 0x028
-#define QPHY_V2_PCS_TX_LARGE_AMP_DRV_LVL 0x034
-#define QPHY_V2_PCS_TX_LARGE_AMP_POST_EMP_LVL 0x038
-#define QPHY_V2_PCS_TX_SMALL_AMP_DRV_LVL 0x03c
-#define QPHY_V2_PCS_TX_SMALL_AMP_POST_EMP_LVL 0x040
#define QPHY_V2_PCS_ENDPOINT_REFCLK_DRIVE 0x054
#define QPHY_V2_PCS_RX_IDLE_DTCT_CNTRL 0x058
#define QPHY_V2_PCS_POWER_STATE_CONFIG1 0x060
@@ -30,17 +28,16 @@
#define QPHY_V2_PCS_FLL_CNT_VAL_L 0x0c8
#define QPHY_V2_PCS_FLL_CNT_VAL_H_TOL 0x0cc
#define QPHY_V2_PCS_FLL_MAN_CODE 0x0d0
-
-/* UFS only ? */
-#define QPHY_V2_PCS_RX_MIN_STALL_NOCONFIG_TIME_CAP 0x0cc
-#define QPHY_V2_PCS_RX_SYM_RESYNC_CTRL 0x13c
-#define QPHY_V2_PCS_RX_MIN_HIBERN8_TIME 0x140
-#define QPHY_V2_PCS_RX_SIGDET_CTRL2 0x148
-#define QPHY_V2_PCS_RX_PWM_GEAR_BAND 0x154
+#define QPHY_V2_PCS_AUTONOMOUS_MODE_CTRL 0x0d4
+#define QPHY_V2_PCS_LFPS_RXTERM_IRQ_CLEAR 0x0d8
+#define QPHY_V2_PCS_LFPS_RXTERM_IRQ_STATUS 0x178
+#define QPHY_V2_PCS_USB_PCS_STATUS 0x17c /* USB */
#define QPHY_V2_PCS_PLL_LOCK_CHK_DLY_TIME_AUXCLK_LSB 0x1a8
#define QPHY_V2_PCS_OSC_DTCT_ACTIONS 0x1ac
#define QPHY_V2_PCS_RX_SIGDET_LVL 0x1d8
#define QPHY_V2_PCS_L1SS_WAKEUP_DLY_TIME_AUXCLK_LSB 0x1dc
#define QPHY_V2_PCS_L1SS_WAKEUP_DLY_TIME_AUXCLK_MSB 0x1e0
+#define QPHY_V2_PCS_PCI_PCS_STATUS 0x174 /* PCI */
+
#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v5.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v5.h
index 04f260711ea1..36cc80bb9059 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v5.h
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v5.h
@@ -7,6 +7,10 @@
#define QCOM_PHY_QMP_PCS_V5_H_
/* Only for QMP V5 PHY - USB/PCIe PCS registers */
+#define QPHY_V5_PCS_SW_RESET 0x000
+#define QPHY_V5_PCS_PCS_STATUS1 0x014
+#define QPHY_V5_PCS_POWER_DOWN_CONTROL 0x040
+#define QPHY_V5_PCS_START_CONTROL 0x044
#define QPHY_V5_PCS_LOCK_DETECT_CONFIG1 0x0c4
#define QPHY_V5_PCS_LOCK_DETECT_CONFIG2 0x0c8
#define QPHY_V5_PCS_LOCK_DETECT_CONFIG3 0x0cc
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v6.h
new file mode 100644
index 000000000000..18c4a3abe590
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v6.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2023, Linaro Limited
+ */
+
+#ifndef QCOM_PHY_QMP_PCS_V6_H_
+#define QCOM_PHY_QMP_PCS_V6_H_
+
+/* Only for QMP V6 PHY - USB/PCIe PCS registers */
+#define QPHY_V6_PCS_REFGEN_REQ_CONFIG1 0xdc
+#define QPHY_V6_PCS_RX_SIGDET_LVL 0x188
+#define QPHY_V6_PCS_RATE_SLEW_CNTRL1 0x198
+#define QPHY_V6_PCS_EQ_CONFIG2 0x1e0
+#define QPHY_V6_PCS_PCS_TX_RX_CONFIG 0x1d0
+
+#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v6_20.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v6_20.h
new file mode 100644
index 000000000000..9c3f1e4950e6
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v6_20.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2023, Linaro Limited
+ */
+
+#ifndef QCOM_PHY_QMP_PCS_V6_20_H_
+#define QCOM_PHY_QMP_PCS_V6_20_H_
+
+/* Only for QMP V6_20 PHY - USB/PCIe PCS registers */
+#define QPHY_V6_20_PCS_G3S2_PRE_GAIN 0x178
+#define QPHY_V6_20_PCS_RX_SIGDET_LVL 0x190
+#define QPHY_V6_20_PCS_COM_ELECIDLE_DLY_SEL 0x1b8
+#define QPHY_V6_20_PCS_TX_RX_CONFIG1 0x1dc
+#define QPHY_V6_20_PCS_TX_RX_CONFIG2 0x1e0
+#define QPHY_V6_20_PCS_EQ_CONFIG4 0x1f8
+#define QPHY_V6_20_PCS_EQ_CONFIG5 0x1fc
+
+#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h
new file mode 100644
index 000000000000..f420f8faf16a
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2023, Linaro Limited
+ */
+
+#ifndef QCOM_PHY_QMP_QSERDES_COM_V6_H_
+#define QCOM_PHY_QMP_QSERDES_COM_V6_H_
+
+/* Only for QMP V6 PHY - QSERDES COM registers */
+
+#define QSERDES_V6_COM_SSC_STEP_SIZE1_MODE1 0x00
+#define QSERDES_V6_COM_SSC_STEP_SIZE2_MODE1 0x04
+#define QSERDES_V6_COM_CP_CTRL_MODE1 0x10
+#define QSERDES_V6_COM_PLL_RCTRL_MODE1 0x14
+#define QSERDES_V6_COM_PLL_CCTRL_MODE1 0x18
+#define QSERDES_V6_COM_CORECLK_DIV_MODE1 0x1c
+#define QSERDES_V6_COM_LOCK_CMP1_MODE1 0x20
+#define QSERDES_V6_COM_LOCK_CMP2_MODE1 0x24
+#define QSERDES_V6_COM_DEC_START_MODE1 0x28
+#define QSERDES_V6_COM_DEC_START_MSB_MODE1 0x2c
+#define QSERDES_V6_COM_DIV_FRAC_START1_MODE1 0x30
+#define QSERDES_V6_COM_DIV_FRAC_START2_MODE1 0x34
+#define QSERDES_V6_COM_DIV_FRAC_START3_MODE1 0x38
+#define QSERDES_V6_COM_HSCLK_SEL_1 0x3c
+#define QSERDES_V6_COM_VCO_TUNE1_MODE1 0x48
+#define QSERDES_V6_COM_VCO_TUNE2_MODE1 0x4c
+#define QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE1_MODE1 0x50
+#define QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE2_MODE1 0x54
+#define QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE1_MODE0 0x58
+#define QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE2_MODE0 0x5c
+#define QSERDES_V6_COM_SSC_STEP_SIZE1_MODE0 0x60
+#define QSERDES_V6_COM_SSC_STEP_SIZE2_MODE0 0x64
+#define QSERDES_V6_COM_CP_CTRL_MODE0 0x70
+#define QSERDES_V6_COM_PLL_RCTRL_MODE0 0x74
+#define QSERDES_V6_COM_PLL_CCTRL_MODE0 0x78
+#define QSERDES_V6_COM_PLL_CORE_CLK_DIV_MODE0 0x7c
+#define QSERDES_V6_COM_LOCK_CMP1_MODE0 0x80
+#define QSERDES_V6_COM_LOCK_CMP2_MODE0 0x84
+#define QSERDES_V6_COM_DEC_START_MODE0 0x88
+#define QSERDES_V6_COM_DEC_START_MSB_MODE0 0x8c
+#define QSERDES_V6_COM_DIV_FRAC_START1_MODE0 0x90
+#define QSERDES_V6_COM_DIV_FRAC_START2_MODE0 0x94
+#define QSERDES_V6_COM_DIV_FRAC_START3_MODE0 0x98
+#define QSERDES_V6_COM_HSCLK_HS_SWITCH_SEL_1 0x9c
+#define QSERDES_V6_COM_INTEGLOOP_GAIN0_MODE0 0xa0
+#define QSERDES_V6_COM_INTEGLOOP_GAIN1_MODE0 0xa4
+#define QSERDES_V6_COM_VCO_TUNE1_MODE0 0xa8
+#define QSERDES_V6_COM_VCO_TUNE2_MODE0 0xac
+#define QSERDES_V6_COM_BG_TIMER 0xbc
+#define QSERDES_V6_COM_SSC_EN_CENTER 0xc0
+#define QSERDES_V6_COM_SSC_PER1 0xcc
+#define QSERDES_V6_COM_SSC_PER2 0xd0
+#define QSERDES_V6_COM_PLL_POST_DIV_MUX 0xd8
+#define QSERDES_V6_COM_PLL_BIAS_EN_CLK_BUFLR_EN 0xdc
+#define QSERDES_V6_COM_CLK_ENABLE1 0xe0
+#define QSERDES_V6_COM_SYS_CLK_CTRL 0xe4
+#define QSERDES_V6_COM_SYSCLK_BUF_ENABLE 0xe8
+#define QSERDES_V6_COM_PLL_IVCO 0xf4
+#define QSERDES_V6_COM_SYSCLK_EN_SEL 0x110
+#define QSERDES_V6_COM_RESETSM_CNTRL 0x118
+#define QSERDES_V6_COM_LOCK_CMP_EN 0x120
+#define QSERDES_V6_COM_LOCK_CMP_CFG 0x124
+#define QSERDES_V6_COM_VCO_TUNE_CTRL 0x13c
+#define QSERDES_V6_COM_VCO_TUNE_MAP 0x140
+#define QSERDES_V6_COM_VCO_TUNE_INITVAL2 0x148
+#define QSERDES_V6_COM_CLK_SELECT 0x164
+#define QSERDES_V6_COM_CORE_CLK_EN 0x170
+#define QSERDES_V6_COM_CMN_CONFIG_1 0x174
+#define QSERDES_V6_COM_SVS_MODE_CLK_SEL 0x17c
+#define QSERDES_V6_COM_CMN_MISC_1 0x184
+#define QSERDES_V6_COM_CMN_MODE 0x188
+#define QSERDES_V6_COM_PLL_VCO_DC_LEVEL_CTRL 0x198
+#define QSERDES_V6_COM_AUTO_GAIN_ADJ_CTRL_1 0x1a4
+#define QSERDES_V6_COM_AUTO_GAIN_ADJ_CTRL_2 0x1a8
+#define QSERDES_V6_COM_AUTO_GAIN_ADJ_CTRL_3 0x1ac
+#define QSERDES_V6_COM_ADDITIONAL_MISC 0x1b4
+#define QSERDES_V6_COM_ADDITIONAL_MISC_2 0x1b8
+#define QSERDES_V6_COM_ADDITIONAL_MISC_3 0x1bc
+#define QSERDES_V6_COM_CMN_STATUS 0x1d0
+#define QSERDES_V6_COM_C_READY_STATUS 0x1f8
+
+#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com.h
index fbaf6ef467f8..7fa5363feeb9 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com.h
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com.h
@@ -135,6 +135,6 @@
#define QSERDES_COM_CMN_MISC2 0x1b8
#define QSERDES_COM_CORECLK_DIV_MODE1 0x1bc
#define QSERDES_COM_CORECLK_DIV_MODE2 0x1c0
-#define QSERDES_COM_CMN_RSVD5 0x1c0
+#define QSERDES_COM_CMN_RSVD5 0x1c4
#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-ln-shrd-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-ln-shrd-v6.h
new file mode 100644
index 000000000000..86d7d796d5d7
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-ln-shrd-v6.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2023, Linaro Limited
+ */
+
+#ifndef QCOM_PHY_QMP_QSERDES_LN_SHRD_V6_H_
+#define QCOM_PHY_QMP_QSERDES_LN_SHRD_V6_H_
+
+#define QSERDES_V6_LN_SHRD_RXCLK_DIV2_CTRL 0xa0
+#define QSERDES_V6_LN_SHRD_RX_Q_EN_RATES 0xb0
+#define QSERDES_V6_LN_SHRD_DFE_DAC_ENABLE1 0xb4
+#define QSERDES_V6_LN_SHRD_TX_ADAPT_POST_THRESH1 0xc4
+#define QSERDES_V6_LN_SHRD_TX_ADAPT_POST_THRESH2 0xc8
+#define QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B0 0xd4
+#define QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B1 0xd8
+#define QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B2 0xdc
+#define QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B3 0xe0
+#define QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B4 0xe4
+#define QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B5 0xe8
+#define QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B6 0xec
+#define QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH1_RATE210 0xf0
+#define QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH1_RATE3 0xf4
+#define QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH2_RATE210 0xf8
+#define QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH2_RATE3 0xfc
+#define QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH3_RATE210 0x100
+#define QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH3_RATE3 0x104
+#define QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH4_RATE3 0x10c
+#define QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH5_RATE3 0x114
+#define QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH6_RATE3 0x11c
+#define QSERDES_V6_LN_SHRD_RX_SUMMER_CAL_SPD_MODE 0x128
+
+#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h
new file mode 100644
index 000000000000..15bcb4ba9139
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2023, Linaro Limited
+ */
+
+#ifndef QCOM_PHY_QMP_QSERDES_TXRX_UFS_V6_H_
+#define QCOM_PHY_QMP_QSERDES_TXRX_UFS_V6_H_
+
+#define QSERDES_UFS_V6_TX_RES_CODE_LANE_TX 0x28
+#define QSERDES_UFS_V6_TX_RES_CODE_LANE_RX 0x2c
+#define QSERDES_UFS_V6_TX_RES_CODE_LANE_OFFSET_TX 0x30
+#define QSERDES_UFS_V6_TX_RES_CODE_LANE_OFFSET_RX 0x34
+
+#define QSERDES_UFS_V6_RX_UCDR_FASTLOCK_FO_GAIN_RATE2 0x08
+#define QSERDES_UFS_V6_RX_UCDR_FASTLOCK_FO_GAIN_RATE4 0x10
+#define QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL 0x178
+#define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B0 0x208
+#define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B1 0x20c
+#define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B3 0x214
+#define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B6 0x220
+#define QSERDES_UFS_V6_RX_MODE_RATE2_B3 0x238
+#define QSERDES_UFS_V6_RX_MODE_RATE2_B6 0x244
+#define QSERDES_UFS_V6_RX_MODE_RATE3_B3 0x25c
+#define QSERDES_UFS_V6_RX_MODE_RATE3_B4 0x260
+#define QSERDES_UFS_V6_RX_MODE_RATE3_B5 0x264
+#define QSERDES_UFS_V6_RX_MODE_RATE3_B8 0x270
+#define QSERDES_UFS_V6_RX_MODE_RATE4_B3 0x280
+#define QSERDES_UFS_V6_RX_MODE_RATE4_B6 0x28c
+
+#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v5_5nm.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v5_5nm.h
index a1c088bd5158..a4a4e251348d 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v5_5nm.h
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v5_5nm.h
@@ -7,11 +7,6 @@
#define QCOM_PHY_QMP_QSERDES_TXRX_V5_5NM_H_
/* Only for QMP V5 5NM PHY - TX registers */
-#define QSERDES_V5_5NM_TX_RES_CODE_LANE_OFFSET_TX 0x30
-#define QSERDES_V5_5NM_TX_RES_CODE_LANE_OFFSET_RX 0x34
-#define QSERDES_V5_5NM_TX_LANE_MODE_1 0x78
-#define QSERDES_V5_5NM_TX_LANE_MODE_2 0x7c
-#define QSERDES_V5_5NM_TX_LANE_MODE_3 0x80
#define QSERDES_V5_5NM_TX_BIST_MODE_LANENO 0x00
#define QSERDES_V5_5NM_TX_BIST_INVERT 0x04
#define QSERDES_V5_5NM_TX_CLKBUF_ENABLE 0x08
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v6.h
new file mode 100644
index 000000000000..a69233e68f9a
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v6.h
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2023, Linaro Limited
+ */
+
+#ifndef QCOM_PHY_QMP_QSERDES_TXRX_USB_V6_H_
+#define QCOM_PHY_QMP_QSERDES_TXRX_USB_V6_H_
+
+#define QSERDES_V6_TX_CLKBUF_ENABLE 0x08
+#define QSERDES_V6_TX_RESET_TSYNC_EN 0x1c
+#define QSERDES_V6_TX_PRE_STALL_LDO_BOOST_EN 0x20
+#define QSERDES_V6_TX_TX_BAND 0x24
+#define QSERDES_V6_TX_INTERFACE_SELECT 0x2c
+#define QSERDES_V6_TX_RES_CODE_LANE_TX 0x34
+#define QSERDES_V6_TX_RES_CODE_LANE_RX 0x38
+#define QSERDES_V6_TX_RES_CODE_LANE_OFFSET_TX 0x3c
+#define QSERDES_V6_TX_RES_CODE_LANE_OFFSET_RX 0x40
+#define QSERDES_V6_TX_PARRATE_REC_DETECT_IDLE_EN 0x60
+#define QSERDES_V6_TX_BIST_PATTERN7 0x7c
+#define QSERDES_V6_TX_LANE_MODE_1 0x84
+#define QSERDES_V6_TX_LANE_MODE_3 0x8c
+#define QSERDES_V6_TX_LANE_MODE_4 0x90
+#define QSERDES_V6_TX_LANE_MODE_5 0x94
+#define QSERDES_V6_TX_RCV_DETECT_LVL_2 0xa4
+#define QSERDES_V6_TX_TRAN_DRVR_EMP_EN 0xc0
+#define QSERDES_V6_TX_TX_INTERFACE_MODE 0xc4
+#define QSERDES_V6_TX_VMODE_CTRL1 0xc8
+#define QSERDES_V6_TX_PI_QEC_CTRL 0xe4
+
+#define QSERDES_V6_RX_UCDR_FO_GAIN 0x08
+#define QSERDES_V6_RX_UCDR_SO_GAIN 0x14
+#define QSERDES_V6_RX_UCDR_FASTLOCK_FO_GAIN 0x30
+#define QSERDES_V6_RX_UCDR_SO_SATURATION_AND_ENABLE 0x34
+#define QSERDES_V6_RX_UCDR_FASTLOCK_COUNT_LOW 0x3c
+#define QSERDES_V6_RX_UCDR_FASTLOCK_COUNT_HIGH 0x40
+#define QSERDES_V6_RX_UCDR_PI_CONTROLS 0x44
+#define QSERDES_V6_RX_UCDR_SB2_THRESH1 0x4c
+#define QSERDES_V6_RX_UCDR_SB2_THRESH2 0x50
+#define QSERDES_V6_RX_UCDR_SB2_GAIN1 0x54
+#define QSERDES_V6_RX_UCDR_SB2_GAIN2 0x58
+#define QSERDES_V6_RX_AUX_DATA_TCOARSE_TFINE 0x60
+#define QSERDES_V6_RX_TX_ADAPT_POST_THRESH 0xcc
+#define QSERDES_V6_RX_VGA_CAL_CNTRL1 0xd4
+#define QSERDES_V6_RX_VGA_CAL_CNTRL2 0xd8
+#define QSERDES_V6_RX_GM_CAL 0xdc
+#define QSERDES_V6_RX_RX_EQU_ADAPTOR_CNTRL2 0xec
+#define QSERDES_V6_RX_RX_EQU_ADAPTOR_CNTRL3 0xf0
+#define QSERDES_V6_RX_RX_EQU_ADAPTOR_CNTRL4 0xf4
+#define QSERDES_V6_RX_RX_IDAC_TSETTLE_LOW 0xf8
+#define QSERDES_V6_RX_RX_IDAC_TSETTLE_HIGH 0xfc
+#define QSERDES_V6_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x110
+#define QSERDES_V6_RX_SIDGET_ENABLES 0x118
+#define QSERDES_V6_RX_SIGDET_CNTRL 0x11c
+#define QSERDES_V6_RX_SIGDET_DEGLITCH_CNTRL 0x124
+#define QSERDES_V6_RX_RX_MODE_00_LOW 0x15c
+#define QSERDES_V6_RX_RX_MODE_00_HIGH 0x160
+#define QSERDES_V6_RX_RX_MODE_00_HIGH2 0x164
+#define QSERDES_V6_RX_RX_MODE_00_HIGH3 0x168
+#define QSERDES_V6_RX_RX_MODE_00_HIGH4 0x16c
+#define QSERDES_V6_RX_RX_MODE_01_LOW 0x170
+#define QSERDES_V6_RX_RX_MODE_01_HIGH 0x174
+#define QSERDES_V6_RX_RX_MODE_01_HIGH2 0x178
+#define QSERDES_V6_RX_RX_MODE_01_HIGH3 0x17c
+#define QSERDES_V6_RX_RX_MODE_01_HIGH4 0x180
+#define QSERDES_V6_RX_RX_MODE_10_LOW 0x184
+#define QSERDES_V6_RX_RX_MODE_10_HIGH 0x188
+#define QSERDES_V6_RX_RX_MODE_10_HIGH2 0x18c
+#define QSERDES_V6_RX_RX_MODE_10_HIGH3 0x190
+#define QSERDES_V6_RX_RX_MODE_10_HIGH4 0x194
+#define QSERDES_V6_RX_DFE_EN_TIMER 0x1a0
+#define QSERDES_V6_RX_DFE_CTLE_POST_CAL_OFFSET 0x1a4
+#define QSERDES_V6_RX_DCC_CTRL1 0x1a8
+#define QSERDES_V6_RX_VTH_CODE 0x1b0
+#define QSERDES_V6_RX_SIGDET_CAL_CTRL1 0x1e4
+#define QSERDES_V6_RX_SIGDET_CAL_TRIM 0x1f8
+
+#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v6_20.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v6_20.h
new file mode 100644
index 000000000000..5385a8b60970
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v6_20.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2023, Linaro Limited
+ */
+
+#ifndef QCOM_PHY_QMP_QSERDES_TXRX_PCIE_V6_20_H_
+#define QCOM_PHY_QMP_QSERDES_TXRX_PCIE_V6_20_H_
+
+#define QSERDES_V6_20_TX_RES_CODE_LANE_OFFSET_TX 0x30
+#define QSERDES_V6_20_TX_RES_CODE_LANE_OFFSET_RX 0x34
+#define QSERDES_V6_20_TX_TRAN_DRVR_EMP_EN 0xac
+#define QSERDES_V6_20_TX_LANE_MODE_1 0x78
+#define QSERDES_V6_20_TX_LANE_MODE_2 0x7c
+#define QSERDES_V6_20_TX_LANE_MODE_3 0x80
+
+#define QSERDES_V6_20_RX_UCDR_FO_GAIN_RATE_2 0x08
+#define QSERDES_V6_20_RX_UCDR_FO_GAIN_RATE_3 0x0c
+#define QSERDES_V6_20_RX_UCDR_PI_CONTROLS 0x20
+#define QSERDES_V6_20_RX_UCDR_SO_ACC_DEFAULT_VAL_RATE3 0x34
+#define QSERDES_V6_20_RX_IVCM_CAL_CTRL2 0x9c
+#define QSERDES_V6_20_RX_IVCM_POSTCAL_OFFSET 0xa0
+#define QSERDES_V6_20_RX_DFE_3 0xb4
+#define QSERDES_V6_20_RX_VGA_CAL_MAN_VAL 0xe8
+#define QSERDES_V6_20_RX_GM_CAL 0x10c
+#define QSERDES_V6_20_RX_EQU_ADAPTOR_CNTRL4 0x120
+#define QSERDES_V6_20_RX_SIGDET_ENABLES 0x148
+#define QSERDES_V6_20_RX_PHPRE_CTRL 0x188
+#define QSERDES_V6_20_RX_DFE_CTLE_POST_CAL_OFFSET 0x194
+#define QSERDES_V6_20_RX_Q_PI_INTRINSIC_BIAS_RATE32 0x1dc
+#define QSERDES_V6_20_RX_MODE_RATE2_B0 0x1f4
+#define QSERDES_V6_20_RX_MODE_RATE2_B1 0x1f8
+#define QSERDES_V6_20_RX_MODE_RATE2_B2 0x1fc
+#define QSERDES_V6_20_RX_MODE_RATE2_B3 0x200
+#define QSERDES_V6_20_RX_MODE_RATE2_B4 0x204
+#define QSERDES_V6_20_RX_MODE_RATE2_B5 0x208
+#define QSERDES_V6_20_RX_MODE_RATE2_B6 0x20c
+#define QSERDES_V6_20_RX_MODE_RATE3_B0 0x210
+#define QSERDES_V6_20_RX_MODE_RATE3_B1 0x214
+#define QSERDES_V6_20_RX_MODE_RATE3_B2 0x218
+#define QSERDES_V6_20_RX_MODE_RATE3_B3 0x21c
+#define QSERDES_V6_20_RX_MODE_RATE3_B4 0x220
+#define QSERDES_V6_20_RX_MODE_RATE3_B5 0x224
+#define QSERDES_V6_20_RX_MODE_RATE3_B6 0x228
+
+#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
index 318eea35b972..994ddd5d4a81 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
@@ -20,7 +20,15 @@
#include <linux/reset.h>
#include <linux/slab.h>
+#include <ufs/unipro.h>
#include "phy-qcom-qmp.h"
+#include "phy-qcom-qmp-pcs-ufs-v2.h"
+#include "phy-qcom-qmp-pcs-ufs-v3.h"
+#include "phy-qcom-qmp-pcs-ufs-v4.h"
+#include "phy-qcom-qmp-pcs-ufs-v5.h"
+#include "phy-qcom-qmp-pcs-ufs-v6.h"
+
+#include "phy-qcom-qmp-qserdes-txrx-ufs-v6.h"
/* QPHY_SW_RESET bit */
#define SW_RESET BIT(0)
@@ -69,32 +77,40 @@ enum qphy_reg_layout {
QPHY_LAYOUT_SIZE
};
-static const unsigned int msm8996_ufsphy_regs_layout[QPHY_LAYOUT_SIZE] = {
- [QPHY_START_CTRL] = 0x00,
- [QPHY_PCS_READY_STATUS] = 0x168,
- [QPHY_PCS_POWER_DOWN_CONTROL] = 0x04,
-};
-
-static const unsigned int sdm845_ufsphy_regs_layout[QPHY_LAYOUT_SIZE] = {
- [QPHY_START_CTRL] = 0x00,
- [QPHY_PCS_READY_STATUS] = 0x160,
- [QPHY_PCS_POWER_DOWN_CONTROL] = 0x04,
+static const unsigned int ufsphy_v2_regs_layout[QPHY_LAYOUT_SIZE] = {
+ [QPHY_START_CTRL] = QPHY_V2_PCS_UFS_PHY_START,
+ [QPHY_PCS_READY_STATUS] = QPHY_V2_PCS_UFS_READY_STATUS,
+ [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V2_PCS_UFS_POWER_DOWN_CONTROL,
};
-static const unsigned int sm6115_ufsphy_regs_layout[QPHY_LAYOUT_SIZE] = {
- [QPHY_START_CTRL] = 0x00,
- [QPHY_PCS_READY_STATUS] = 0x168,
- [QPHY_PCS_POWER_DOWN_CONTROL] = 0x04,
+static const unsigned int ufsphy_v3_regs_layout[QPHY_LAYOUT_SIZE] = {
+ [QPHY_START_CTRL] = QPHY_V3_PCS_UFS_PHY_START,
+ [QPHY_PCS_READY_STATUS] = QPHY_V3_PCS_UFS_READY_STATUS,
+ [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V3_PCS_UFS_POWER_DOWN_CONTROL,
};
-static const unsigned int sm8150_ufsphy_regs_layout[QPHY_LAYOUT_SIZE] = {
+static const unsigned int ufsphy_v4_regs_layout[QPHY_LAYOUT_SIZE] = {
[QPHY_START_CTRL] = QPHY_V4_PCS_UFS_PHY_START,
[QPHY_PCS_READY_STATUS] = QPHY_V4_PCS_UFS_READY_STATUS,
[QPHY_SW_RESET] = QPHY_V4_PCS_UFS_SW_RESET,
[QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V4_PCS_UFS_POWER_DOWN_CONTROL,
};
-static const struct qmp_phy_init_tbl msm8996_ufs_serdes_tbl[] = {
+static const unsigned int ufsphy_v5_regs_layout[QPHY_LAYOUT_SIZE] = {
+ [QPHY_START_CTRL] = QPHY_V5_PCS_UFS_PHY_START,
+ [QPHY_PCS_READY_STATUS] = QPHY_V5_PCS_UFS_READY_STATUS,
+ [QPHY_SW_RESET] = QPHY_V5_PCS_UFS_SW_RESET,
+ [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V5_PCS_UFS_POWER_DOWN_CONTROL,
+};
+
+static const unsigned int ufsphy_v6_regs_layout[QPHY_LAYOUT_SIZE] = {
+ [QPHY_START_CTRL] = QPHY_V6_PCS_UFS_PHY_START,
+ [QPHY_PCS_READY_STATUS] = QPHY_V6_PCS_UFS_READY_STATUS,
+ [QPHY_SW_RESET] = QPHY_V6_PCS_UFS_SW_RESET,
+ [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V6_PCS_UFS_POWER_DOWN_CONTROL,
+};
+
+static const struct qmp_phy_init_tbl msm8996_ufsphy_serdes[] = {
QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x0e),
QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0xd7),
QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x30),
@@ -143,12 +159,12 @@ static const struct qmp_phy_init_tbl msm8996_ufs_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE1, 0x00),
};
-static const struct qmp_phy_init_tbl msm8996_ufs_tx_tbl[] = {
+static const struct qmp_phy_init_tbl msm8996_ufsphy_tx[] = {
QMP_PHY_INIT_CFG(QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, 0x45),
QMP_PHY_INIT_CFG(QSERDES_TX_LANE_MODE, 0x02),
};
-static const struct qmp_phy_init_tbl msm8996_ufs_rx_tbl[] = {
+static const struct qmp_phy_init_tbl msm8996_ufsphy_rx[] = {
QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_LVL, 0x24),
QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_CNTRL, 0x02),
QMP_PHY_INIT_CFG(QSERDES_RX_RX_INTERFACE_MODE, 0x00),
@@ -162,7 +178,7 @@ static const struct qmp_phy_init_tbl msm8996_ufs_rx_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0E),
};
-static const struct qmp_phy_init_tbl sm6115_ufsphy_serdes_tbl[] = {
+static const struct qmp_phy_init_tbl sm6115_ufsphy_serdes[] = {
QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x0e),
QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x14),
QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x30),
@@ -213,17 +229,18 @@ static const struct qmp_phy_init_tbl sm6115_ufsphy_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_COM_BG_TRIM, 0x0f),
QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_INITVAL1, 0xff),
QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_INITVAL2, 0x00),
+};
- /* Rate B */
+static const struct qmp_phy_init_tbl sm6115_ufsphy_hs_b_serdes[] = {
QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x44),
};
-static const struct qmp_phy_init_tbl sm6115_ufsphy_tx_tbl[] = {
+static const struct qmp_phy_init_tbl sm6115_ufsphy_tx[] = {
QMP_PHY_INIT_CFG(QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, 0x45),
QMP_PHY_INIT_CFG(QSERDES_TX_LANE_MODE, 0x06),
};
-static const struct qmp_phy_init_tbl sm6115_ufsphy_rx_tbl[] = {
+static const struct qmp_phy_init_tbl sm6115_ufsphy_rx[] = {
QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_LVL, 0x24),
QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_CNTRL, 0x0F),
QMP_PHY_INIT_CFG(QSERDES_RX_RX_INTERFACE_MODE, 0x40),
@@ -241,19 +258,19 @@ static const struct qmp_phy_init_tbl sm6115_ufsphy_rx_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x5B),
};
-static const struct qmp_phy_init_tbl sm6115_ufsphy_pcs_tbl[] = {
- QMP_PHY_INIT_CFG(QPHY_V2_PCS_RX_PWM_GEAR_BAND, 0x15),
- QMP_PHY_INIT_CFG(QPHY_V2_PCS_RX_SIGDET_CTRL2, 0x6d),
- QMP_PHY_INIT_CFG(QPHY_V2_PCS_TX_LARGE_AMP_DRV_LVL, 0x0f),
- QMP_PHY_INIT_CFG(QPHY_V2_PCS_TX_SMALL_AMP_DRV_LVL, 0x02),
- QMP_PHY_INIT_CFG(QPHY_V2_PCS_RX_MIN_STALL_NOCONFIG_TIME_CAP, 0x28),
- QMP_PHY_INIT_CFG(QPHY_V2_PCS_RX_SYM_RESYNC_CTRL, 0x03),
- QMP_PHY_INIT_CFG(QPHY_V2_PCS_TX_LARGE_AMP_POST_EMP_LVL, 0x12),
- QMP_PHY_INIT_CFG(QPHY_V2_PCS_TX_SMALL_AMP_POST_EMP_LVL, 0x0f),
- QMP_PHY_INIT_CFG(QPHY_V2_PCS_RX_MIN_HIBERN8_TIME, 0x9a), /* 8 us */
+static const struct qmp_phy_init_tbl sm6115_ufsphy_pcs[] = {
+ QMP_PHY_INIT_CFG(QPHY_V2_PCS_UFS_RX_PWM_GEAR_BAND, 0x15),
+ QMP_PHY_INIT_CFG(QPHY_V2_PCS_UFS_RX_SIGDET_CTRL2, 0x6d),
+ QMP_PHY_INIT_CFG(QPHY_V2_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0f),
+ QMP_PHY_INIT_CFG(QPHY_V2_PCS_UFS_TX_SMALL_AMP_DRV_LVL, 0x02),
+ QMP_PHY_INIT_CFG(QPHY_V2_PCS_UFS_RX_MIN_STALL_NOCONFIG_TIME_CAP, 0x28),
+ QMP_PHY_INIT_CFG(QPHY_V2_PCS_UFS_RX_SYM_RESYNC_CTRL, 0x03),
+ QMP_PHY_INIT_CFG(QPHY_V2_PCS_UFS_TX_LARGE_AMP_POST_EMP_LVL, 0x12),
+ QMP_PHY_INIT_CFG(QPHY_V2_PCS_UFS_TX_SMALL_AMP_POST_EMP_LVL, 0x0f),
+ QMP_PHY_INIT_CFG(QPHY_V2_PCS_UFS_RX_MIN_HIBERN8_TIME, 0x9a), /* 8 us */
};
-static const struct qmp_phy_init_tbl sdm845_ufsphy_serdes_tbl[] = {
+static const struct qmp_phy_init_tbl sdm845_ufsphy_serdes[] = {
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYS_CLK_CTRL, 0x02),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x04),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_BG_TIMER, 0x0a),
@@ -290,18 +307,19 @@ static const struct qmp_phy_init_tbl sdm845_ufsphy_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE2_MODE1, 0x00),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP1_MODE1, 0x32),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP2_MODE1, 0x0f),
+};
- /* Rate B */
+static const struct qmp_phy_init_tbl sdm845_ufsphy_hs_b_serdes[] = {
QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_MAP, 0x44),
};
-static const struct qmp_phy_init_tbl sdm845_ufsphy_tx_tbl[] = {
+static const struct qmp_phy_init_tbl sdm845_ufsphy_tx[] = {
QMP_PHY_INIT_CFG(QSERDES_V3_TX_LANE_MODE_1, 0x06),
QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX, 0x04),
QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_RX, 0x07),
};
-static const struct qmp_phy_init_tbl sdm845_ufsphy_rx_tbl[] = {
+static const struct qmp_phy_init_tbl sdm845_ufsphy_rx[] = {
QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_LVL, 0x24),
QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x0f),
QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x1e),
@@ -320,7 +338,7 @@ static const struct qmp_phy_init_tbl sdm845_ufsphy_rx_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x59),
};
-static const struct qmp_phy_init_tbl sdm845_ufsphy_pcs_tbl[] = {
+static const struct qmp_phy_init_tbl sdm845_ufsphy_pcs[] = {
QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_RX_SIGDET_CTRL2, 0x6e),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0a),
QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_TX_SMALL_AMP_DRV_LVL, 0x02),
@@ -331,7 +349,7 @@ static const struct qmp_phy_init_tbl sdm845_ufsphy_pcs_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_MULTI_LANE_CTRL1, 0x02),
};
-static const struct qmp_phy_init_tbl sm8150_ufsphy_serdes_tbl[] = {
+static const struct qmp_phy_init_tbl sm8150_ufsphy_serdes[] = {
QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_EN_SEL, 0xd9),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_SEL, 0x11),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_HS_SWITCH_SEL, 0x00),
@@ -356,12 +374,13 @@ static const struct qmp_phy_init_tbl sm8150_ufsphy_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP2_MODE1, 0x0f),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE1_MODE1, 0xdd),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE1, 0x23),
+};
- /* Rate B */
+static const struct qmp_phy_init_tbl sm8150_ufsphy_hs_b_serdes[] = {
QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE_MAP, 0x06),
};
-static const struct qmp_phy_init_tbl sm8150_ufsphy_tx_tbl[] = {
+static const struct qmp_phy_init_tbl sm8150_ufsphy_tx[] = {
QMP_PHY_INIT_CFG(QSERDES_V4_TX_PWM_GEAR_1_DIVIDER_BAND0_1, 0x06),
QMP_PHY_INIT_CFG(QSERDES_V4_TX_PWM_GEAR_2_DIVIDER_BAND0_1, 0x03),
QMP_PHY_INIT_CFG(QSERDES_V4_TX_PWM_GEAR_3_DIVIDER_BAND0_1, 0x01),
@@ -370,7 +389,11 @@ static const struct qmp_phy_init_tbl sm8150_ufsphy_tx_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V4_TX_TRAN_DRVR_EMP_EN, 0x0c),
};
-static const struct qmp_phy_init_tbl sm8150_ufsphy_rx_tbl[] = {
+static const struct qmp_phy_init_tbl sm8150_ufsphy_hs_g4_tx[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V4_TX_LANE_MODE_1, 0x75),
+};
+
+static const struct qmp_phy_init_tbl sm8150_ufsphy_rx[] = {
QMP_PHY_INIT_CFG(QSERDES_V4_RX_SIGDET_LVL, 0x24),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_SIGDET_CNTRL, 0x0f),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_SIGDET_DEGLITCH_CNTRL, 0x1e),
@@ -405,10 +428,28 @@ static const struct qmp_phy_init_tbl sm8150_ufsphy_rx_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_10_HIGH2, 0xc8),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_10_HIGH3, 0x3b),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_10_HIGH4, 0xb1),
+};
+static const struct qmp_phy_init_tbl sm8150_ufsphy_hs_g4_rx[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x5a),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_PI_CTRL2, 0x81),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_FO_GAIN, 0x0e),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_TERM_BW, 0x6f),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_IDAC_MEASURE_TIME, 0x20),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_IDAC_TSETTLE_LOW, 0x80),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_IDAC_TSETTLE_HIGH, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_LOW, 0x3f),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH, 0xff),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH2, 0xff),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH3, 0x7f),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH4, 0x6c),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_LOW, 0x6d),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH, 0x6d),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH2, 0xed),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH4, 0x3c),
};
-static const struct qmp_phy_init_tbl sm8150_ufsphy_pcs_tbl[] = {
+static const struct qmp_phy_init_tbl sm8150_ufsphy_pcs[] = {
QMP_PHY_INIT_CFG(QPHY_V4_PCS_UFS_RX_SIGDET_CTRL2, 0x6d),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0a),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_UFS_TX_SMALL_AMP_DRV_LVL, 0x02),
@@ -418,7 +459,40 @@ static const struct qmp_phy_init_tbl sm8150_ufsphy_pcs_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_V4_PCS_UFS_MULTI_LANE_CTRL1, 0x02),
};
-static const struct qmp_phy_init_tbl sm8350_ufsphy_serdes_tbl[] = {
+static const struct qmp_phy_init_tbl sm8150_ufsphy_hs_g4_pcs[] = {
+ QMP_PHY_INIT_CFG(QPHY_V4_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x10),
+ QMP_PHY_INIT_CFG(QPHY_V4_PCS_UFS_BIST_FIXED_PAT_CTRL, 0x0a),
+};
+
+static const struct qmp_phy_init_tbl sm8250_ufsphy_hs_g4_tx[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V4_TX_LANE_MODE_1, 0xe5),
+};
+
+static const struct qmp_phy_init_tbl sm8250_ufsphy_hs_g4_rx[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x5a),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_PI_CTRL2, 0x81),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_FO_GAIN, 0x0e),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_TERM_BW, 0x6f),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL1, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL2, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL3, 0x09),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL4, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x17),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_IDAC_MEASURE_TIME, 0x20),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_IDAC_TSETTLE_LOW, 0x80),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_IDAC_TSETTLE_HIGH, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_LOW, 0x3f),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH, 0xff),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH2, 0xff),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH3, 0x7f),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH4, 0x2c),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_LOW, 0x6d),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH, 0x6d),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH2, 0xed),
+ QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH4, 0x3c),
+};
+
+static const struct qmp_phy_init_tbl sm8350_ufsphy_serdes[] = {
QMP_PHY_INIT_CFG(QSERDES_V5_COM_SYSCLK_EN_SEL, 0xd9),
QMP_PHY_INIT_CFG(QSERDES_V5_COM_HSCLK_SEL, 0x11),
QMP_PHY_INIT_CFG(QSERDES_V5_COM_HSCLK_HS_SWITCH_SEL, 0x00),
@@ -443,12 +517,13 @@ static const struct qmp_phy_init_tbl sm8350_ufsphy_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP2_MODE1, 0x1e),
QMP_PHY_INIT_CFG(QSERDES_V5_COM_BIN_VCOCAL_CMP_CODE1_MODE1, 0xdd),
QMP_PHY_INIT_CFG(QSERDES_V5_COM_BIN_VCOCAL_CMP_CODE2_MODE1, 0x23),
+};
- /* Rate B */
+static const struct qmp_phy_init_tbl sm8350_ufsphy_hs_b_serdes[] = {
QMP_PHY_INIT_CFG(QSERDES_V5_COM_VCO_TUNE_MAP, 0x06),
};
-static const struct qmp_phy_init_tbl sm8350_ufsphy_tx_tbl[] = {
+static const struct qmp_phy_init_tbl sm8350_ufsphy_tx[] = {
QMP_PHY_INIT_CFG(QSERDES_V5_TX_PWM_GEAR_1_DIVIDER_BAND0_1, 0x06),
QMP_PHY_INIT_CFG(QSERDES_V5_TX_PWM_GEAR_2_DIVIDER_BAND0_1, 0x03),
QMP_PHY_INIT_CFG(QSERDES_V5_TX_PWM_GEAR_3_DIVIDER_BAND0_1, 0x01),
@@ -460,7 +535,7 @@ static const struct qmp_phy_init_tbl sm8350_ufsphy_tx_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V5_TX_TRAN_DRVR_EMP_EN, 0x0c),
};
-static const struct qmp_phy_init_tbl sm8350_ufsphy_rx_tbl[] = {
+static const struct qmp_phy_init_tbl sm8350_ufsphy_rx[] = {
QMP_PHY_INIT_CFG(QSERDES_V5_RX_SIGDET_LVL, 0x24),
QMP_PHY_INIT_CFG(QSERDES_V5_RX_SIGDET_CNTRL, 0x0f),
QMP_PHY_INIT_CFG(QSERDES_V5_RX_SIGDET_DEGLITCH_CNTRL, 0x1e),
@@ -500,24 +575,100 @@ static const struct qmp_phy_init_tbl sm8350_ufsphy_rx_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V5_RX_DCC_CTRL1, 0x0c),
};
-static const struct qmp_phy_init_tbl sm8350_ufsphy_pcs_tbl[] = {
+static const struct qmp_phy_init_tbl sm8350_ufsphy_pcs[] = {
QMP_PHY_INIT_CFG(QPHY_V5_PCS_UFS_RX_SIGDET_CTRL2, 0x6d),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0a),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_UFS_TX_SMALL_AMP_DRV_LVL, 0x02),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_UFS_TX_MID_TERM_CTRL1, 0x43),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_UFS_DEBUG_BUS_CLKSEL, 0x1f),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_UFS_RX_MIN_HIBERN8_TIME, 0xff),
- QMP_PHY_INIT_CFG(QPHY_V5_PCS_UFS_PLL_CNTL, 0x03),
- QMP_PHY_INIT_CFG(QPHY_V5_PCS_UFS_TIMER_20US_CORECLK_STEPS_MSB, 0x16),
- QMP_PHY_INIT_CFG(QPHY_V5_PCS_UFS_TIMER_20US_CORECLK_STEPS_LSB, 0xd8),
- QMP_PHY_INIT_CFG(QPHY_V5_PCS_UFS_TX_PWM_GEAR_BAND, 0xaa),
- QMP_PHY_INIT_CFG(QPHY_V5_PCS_UFS_TX_HS_GEAR_BAND, 0x06),
- QMP_PHY_INIT_CFG(QPHY_V5_PCS_UFS_TX_HSGEAR_CAPABILITY, 0x03),
- QMP_PHY_INIT_CFG(QPHY_V5_PCS_UFS_RX_HSGEAR_CAPABILITY, 0x03),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_UFS_RX_SIGDET_CTRL1, 0x0e),
QMP_PHY_INIT_CFG(QPHY_V5_PCS_UFS_MULTI_LANE_CTRL1, 0x02),
};
+static const struct qmp_phy_init_tbl sm8350_ufsphy_g4_tx[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_1, 0xe5),
+};
+
+static const struct qmp_phy_init_tbl sm8350_ufsphy_g4_rx[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_PI_CTRL2, 0x81),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_TERM_BW, 0x6f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL2, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4a),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_IDAC_MEASURE_TIME, 0x20),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_IDAC_TSETTLE_LOW, 0x80),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_IDAC_TSETTLE_HIGH, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_LOW, 0xbf),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH, 0xbf),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH2, 0x7f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH3, 0x7f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH4, 0x2d),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_LOW, 0x6d),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH, 0x6d),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH2, 0xed),
+ QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH4, 0x3c),
+};
+
+static const struct qmp_phy_init_tbl sm8350_ufsphy_g4_pcs[] = {
+ QMP_PHY_INIT_CFG(QPHY_V5_PCS_UFS_BIST_FIXED_PAT_CTRL, 0x0a),
+};
+
+static const struct qmp_phy_init_tbl sm8550_ufsphy_serdes[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYSCLK_EN_SEL, 0xd9),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_CONFIG_1, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_SEL_1, 0x11),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_HS_SWITCH_SEL_1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_EN, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_INITVAL2, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x41),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE0, 0x18),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE0, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0x7f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x4c),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE0, 0x18),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE0, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0x99),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x07),
+};
+
+static const struct qmp_phy_init_tbl sm8550_ufsphy_tx[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V6_TX_LANE_MODE_1, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_RES_CODE_LANE_OFFSET_TX, 0x07),
+};
+
+static const struct qmp_phy_init_tbl sm8550_ufsphy_rx[] = {
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FASTLOCK_FO_GAIN_RATE2, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FASTLOCK_FO_GAIN_RATE4, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL, 0x0e),
+
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B0, 0xc2),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B1, 0xc2),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B3, 0x1a),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B6, 0x60),
+
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE2_B3, 0x9e),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE2_B6, 0x60),
+
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE3_B3, 0x9e),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE3_B4, 0x0e),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE3_B5, 0x36),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE3_B8, 0x02),
+};
+
+static const struct qmp_phy_init_tbl sm8550_ufsphy_pcs[] = {
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_SIGDET_CTRL2, 0x69),
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0f),
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_MID_TERM_CTRL1, 0x43),
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x2b),
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_MULTI_LANE_CTRL1, 0x02),
+};
+
struct qmp_ufs_offsets {
u16 serdes;
u16 pcs;
@@ -527,21 +678,30 @@ struct qmp_ufs_offsets {
u16 rx2;
};
+struct qmp_phy_cfg_tbls {
+ /* Init sequence for PHY blocks - serdes, tx, rx, pcs */
+ const struct qmp_phy_init_tbl *serdes;
+ int serdes_num;
+ const struct qmp_phy_init_tbl *tx;
+ int tx_num;
+ const struct qmp_phy_init_tbl *rx;
+ int rx_num;
+ const struct qmp_phy_init_tbl *pcs;
+ int pcs_num;
+};
+
/* struct qmp_phy_cfg - per-PHY initialization config */
struct qmp_phy_cfg {
int lanes;
const struct qmp_ufs_offsets *offsets;
- /* Init sequence for PHY blocks - serdes, tx, rx, pcs */
- const struct qmp_phy_init_tbl *serdes_tbl;
- int serdes_tbl_num;
- const struct qmp_phy_init_tbl *tx_tbl;
- int tx_tbl_num;
- const struct qmp_phy_init_tbl *rx_tbl;
- int rx_tbl_num;
- const struct qmp_phy_init_tbl *pcs_tbl;
- int pcs_tbl_num;
+ /* Main init sequence for PHY blocks - serdes, tx, rx, pcs */
+ const struct qmp_phy_cfg_tbls tbls;
+ /* Additional sequence for HS Series B */
+ const struct qmp_phy_cfg_tbls tbls_hs_b;
+ /* Additional sequence for HS G4 */
+ const struct qmp_phy_cfg_tbls tbls_hs_g4;
/* clock ids to be requested */
const char * const *clk_list;
@@ -575,6 +735,8 @@ struct qmp_ufs {
struct reset_control *ufs_reset;
struct phy *phy;
+ u32 mode;
+ u32 submode;
};
static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val)
@@ -620,7 +782,7 @@ static const char * const qmp_phy_vreg_l[] = {
"vdda-phy", "vdda-pll",
};
-static const struct qmp_ufs_offsets qmp_ufs_offsets_v5 = {
+static const struct qmp_ufs_offsets qmp_ufs_offsets = {
.serdes = 0,
.pcs = 0xc00,
.tx = 0x400,
@@ -629,15 +791,26 @@ static const struct qmp_ufs_offsets qmp_ufs_offsets_v5 = {
.rx2 = 0xa00,
};
-static const struct qmp_phy_cfg msm8996_ufs_cfg = {
+static const struct qmp_ufs_offsets qmp_ufs_offsets_v6 = {
+ .serdes = 0,
+ .pcs = 0x0400,
+ .tx = 0x1000,
+ .rx = 0x1200,
+ .tx2 = 0x1800,
+ .rx2 = 0x1a00,
+};
+
+static const struct qmp_phy_cfg msm8996_ufsphy_cfg = {
.lanes = 1,
- .serdes_tbl = msm8996_ufs_serdes_tbl,
- .serdes_tbl_num = ARRAY_SIZE(msm8996_ufs_serdes_tbl),
- .tx_tbl = msm8996_ufs_tx_tbl,
- .tx_tbl_num = ARRAY_SIZE(msm8996_ufs_tx_tbl),
- .rx_tbl = msm8996_ufs_rx_tbl,
- .rx_tbl_num = ARRAY_SIZE(msm8996_ufs_rx_tbl),
+ .tbls = {
+ .serdes = msm8996_ufsphy_serdes,
+ .serdes_num = ARRAY_SIZE(msm8996_ufsphy_serdes),
+ .tx = msm8996_ufsphy_tx,
+ .tx_num = ARRAY_SIZE(msm8996_ufsphy_tx),
+ .rx = msm8996_ufsphy_rx,
+ .rx_num = ARRAY_SIZE(msm8996_ufsphy_rx),
+ },
.clk_list = msm8996_ufs_phy_clk_l,
.num_clks = ARRAY_SIZE(msm8996_ufs_phy_clk_l),
@@ -645,7 +818,7 @@ static const struct qmp_phy_cfg msm8996_ufs_cfg = {
.vreg_list = qmp_phy_vreg_l,
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
- .regs = msm8996_ufsphy_regs_layout,
+ .regs = ufsphy_v2_regs_layout,
.no_pcs_sw_reset = true,
};
@@ -653,39 +826,59 @@ static const struct qmp_phy_cfg msm8996_ufs_cfg = {
static const struct qmp_phy_cfg sc8280xp_ufsphy_cfg = {
.lanes = 2,
- .offsets = &qmp_ufs_offsets_v5,
-
- .serdes_tbl = sm8350_ufsphy_serdes_tbl,
- .serdes_tbl_num = ARRAY_SIZE(sm8350_ufsphy_serdes_tbl),
- .tx_tbl = sm8350_ufsphy_tx_tbl,
- .tx_tbl_num = ARRAY_SIZE(sm8350_ufsphy_tx_tbl),
- .rx_tbl = sm8350_ufsphy_rx_tbl,
- .rx_tbl_num = ARRAY_SIZE(sm8350_ufsphy_rx_tbl),
- .pcs_tbl = sm8350_ufsphy_pcs_tbl,
- .pcs_tbl_num = ARRAY_SIZE(sm8350_ufsphy_pcs_tbl),
+ .offsets = &qmp_ufs_offsets,
+
+ .tbls = {
+ .serdes = sm8350_ufsphy_serdes,
+ .serdes_num = ARRAY_SIZE(sm8350_ufsphy_serdes),
+ .tx = sm8350_ufsphy_tx,
+ .tx_num = ARRAY_SIZE(sm8350_ufsphy_tx),
+ .rx = sm8350_ufsphy_rx,
+ .rx_num = ARRAY_SIZE(sm8350_ufsphy_rx),
+ .pcs = sm8350_ufsphy_pcs,
+ .pcs_num = ARRAY_SIZE(sm8350_ufsphy_pcs),
+ },
+ .tbls_hs_b = {
+ .serdes = sm8350_ufsphy_hs_b_serdes,
+ .serdes_num = ARRAY_SIZE(sm8350_ufsphy_hs_b_serdes),
+ },
+ .tbls_hs_g4 = {
+ .tx = sm8350_ufsphy_g4_tx,
+ .tx_num = ARRAY_SIZE(sm8350_ufsphy_g4_tx),
+ .rx = sm8350_ufsphy_g4_rx,
+ .rx_num = ARRAY_SIZE(sm8350_ufsphy_g4_rx),
+ .pcs = sm8350_ufsphy_g4_pcs,
+ .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs),
+ },
.clk_list = sdm845_ufs_phy_clk_l,
.num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
.vreg_list = qmp_phy_vreg_l,
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
- .regs = sm8150_ufsphy_regs_layout,
+ .regs = ufsphy_v5_regs_layout,
};
static const struct qmp_phy_cfg sdm845_ufsphy_cfg = {
.lanes = 2,
- .serdes_tbl = sdm845_ufsphy_serdes_tbl,
- .serdes_tbl_num = ARRAY_SIZE(sdm845_ufsphy_serdes_tbl),
- .tx_tbl = sdm845_ufsphy_tx_tbl,
- .tx_tbl_num = ARRAY_SIZE(sdm845_ufsphy_tx_tbl),
- .rx_tbl = sdm845_ufsphy_rx_tbl,
- .rx_tbl_num = ARRAY_SIZE(sdm845_ufsphy_rx_tbl),
- .pcs_tbl = sdm845_ufsphy_pcs_tbl,
- .pcs_tbl_num = ARRAY_SIZE(sdm845_ufsphy_pcs_tbl),
+ .tbls = {
+ .serdes = sdm845_ufsphy_serdes,
+ .serdes_num = ARRAY_SIZE(sdm845_ufsphy_serdes),
+ .tx = sdm845_ufsphy_tx,
+ .tx_num = ARRAY_SIZE(sdm845_ufsphy_tx),
+ .rx = sdm845_ufsphy_rx,
+ .rx_num = ARRAY_SIZE(sdm845_ufsphy_rx),
+ .pcs = sdm845_ufsphy_pcs,
+ .pcs_num = ARRAY_SIZE(sdm845_ufsphy_pcs),
+ },
+ .tbls_hs_b = {
+ .serdes = sdm845_ufsphy_hs_b_serdes,
+ .serdes_num = ARRAY_SIZE(sdm845_ufsphy_hs_b_serdes),
+ },
.clk_list = sdm845_ufs_phy_clk_l,
.num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
.vreg_list = qmp_phy_vreg_l,
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
- .regs = sdm845_ufsphy_regs_layout,
+ .regs = ufsphy_v3_regs_layout,
.no_pcs_sw_reset = true,
};
@@ -693,19 +886,27 @@ static const struct qmp_phy_cfg sdm845_ufsphy_cfg = {
static const struct qmp_phy_cfg sm6115_ufsphy_cfg = {
.lanes = 1,
- .serdes_tbl = sm6115_ufsphy_serdes_tbl,
- .serdes_tbl_num = ARRAY_SIZE(sm6115_ufsphy_serdes_tbl),
- .tx_tbl = sm6115_ufsphy_tx_tbl,
- .tx_tbl_num = ARRAY_SIZE(sm6115_ufsphy_tx_tbl),
- .rx_tbl = sm6115_ufsphy_rx_tbl,
- .rx_tbl_num = ARRAY_SIZE(sm6115_ufsphy_rx_tbl),
- .pcs_tbl = sm6115_ufsphy_pcs_tbl,
- .pcs_tbl_num = ARRAY_SIZE(sm6115_ufsphy_pcs_tbl),
+ .offsets = &qmp_ufs_offsets,
+
+ .tbls = {
+ .serdes = sm6115_ufsphy_serdes,
+ .serdes_num = ARRAY_SIZE(sm6115_ufsphy_serdes),
+ .tx = sm6115_ufsphy_tx,
+ .tx_num = ARRAY_SIZE(sm6115_ufsphy_tx),
+ .rx = sm6115_ufsphy_rx,
+ .rx_num = ARRAY_SIZE(sm6115_ufsphy_rx),
+ .pcs = sm6115_ufsphy_pcs,
+ .pcs_num = ARRAY_SIZE(sm6115_ufsphy_pcs),
+ },
+ .tbls_hs_b = {
+ .serdes = sm6115_ufsphy_hs_b_serdes,
+ .serdes_num = ARRAY_SIZE(sm6115_ufsphy_hs_b_serdes),
+ },
.clk_list = sdm845_ufs_phy_clk_l,
.num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
.vreg_list = qmp_phy_vreg_l,
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
- .regs = sm6115_ufsphy_regs_layout,
+ .regs = ufsphy_v2_regs_layout,
.no_pcs_sw_reset = true,
};
@@ -713,55 +914,151 @@ static const struct qmp_phy_cfg sm6115_ufsphy_cfg = {
static const struct qmp_phy_cfg sm8150_ufsphy_cfg = {
.lanes = 2,
- .serdes_tbl = sm8150_ufsphy_serdes_tbl,
- .serdes_tbl_num = ARRAY_SIZE(sm8150_ufsphy_serdes_tbl),
- .tx_tbl = sm8150_ufsphy_tx_tbl,
- .tx_tbl_num = ARRAY_SIZE(sm8150_ufsphy_tx_tbl),
- .rx_tbl = sm8150_ufsphy_rx_tbl,
- .rx_tbl_num = ARRAY_SIZE(sm8150_ufsphy_rx_tbl),
- .pcs_tbl = sm8150_ufsphy_pcs_tbl,
- .pcs_tbl_num = ARRAY_SIZE(sm8150_ufsphy_pcs_tbl),
+ .tbls = {
+ .serdes = sm8150_ufsphy_serdes,
+ .serdes_num = ARRAY_SIZE(sm8150_ufsphy_serdes),
+ .tx = sm8150_ufsphy_tx,
+ .tx_num = ARRAY_SIZE(sm8150_ufsphy_tx),
+ .rx = sm8150_ufsphy_rx,
+ .rx_num = ARRAY_SIZE(sm8150_ufsphy_rx),
+ .pcs = sm8150_ufsphy_pcs,
+ .pcs_num = ARRAY_SIZE(sm8150_ufsphy_pcs),
+ },
+ .tbls_hs_b = {
+ .serdes = sm8150_ufsphy_hs_b_serdes,
+ .serdes_num = ARRAY_SIZE(sm8150_ufsphy_hs_b_serdes),
+ },
+ .tbls_hs_g4 = {
+ .tx = sm8150_ufsphy_hs_g4_tx,
+ .tx_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_tx),
+ .rx = sm8150_ufsphy_hs_g4_rx,
+ .rx_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_rx),
+ .pcs = sm8150_ufsphy_hs_g4_pcs,
+ .pcs_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_pcs),
+ },
+ .clk_list = sdm845_ufs_phy_clk_l,
+ .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
+ .vreg_list = qmp_phy_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
+ .regs = ufsphy_v4_regs_layout,
+};
+
+static const struct qmp_phy_cfg sm8250_ufsphy_cfg = {
+ .lanes = 2,
+
+ .tbls = {
+ .serdes = sm8150_ufsphy_serdes,
+ .serdes_num = ARRAY_SIZE(sm8150_ufsphy_serdes),
+ .tx = sm8150_ufsphy_tx,
+ .tx_num = ARRAY_SIZE(sm8150_ufsphy_tx),
+ .rx = sm8150_ufsphy_rx,
+ .rx_num = ARRAY_SIZE(sm8150_ufsphy_rx),
+ .pcs = sm8150_ufsphy_pcs,
+ .pcs_num = ARRAY_SIZE(sm8150_ufsphy_pcs),
+ },
+ .tbls_hs_b = {
+ .serdes = sm8150_ufsphy_hs_b_serdes,
+ .serdes_num = ARRAY_SIZE(sm8150_ufsphy_hs_b_serdes),
+ },
+ .tbls_hs_g4 = {
+ .tx = sm8250_ufsphy_hs_g4_tx,
+ .tx_num = ARRAY_SIZE(sm8250_ufsphy_hs_g4_tx),
+ .rx = sm8250_ufsphy_hs_g4_rx,
+ .rx_num = ARRAY_SIZE(sm8250_ufsphy_hs_g4_rx),
+ .pcs = sm8150_ufsphy_hs_g4_pcs,
+ .pcs_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_pcs),
+ },
.clk_list = sdm845_ufs_phy_clk_l,
.num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
.vreg_list = qmp_phy_vreg_l,
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
- .regs = sm8150_ufsphy_regs_layout,
+ .regs = ufsphy_v4_regs_layout,
};
static const struct qmp_phy_cfg sm8350_ufsphy_cfg = {
.lanes = 2,
- .serdes_tbl = sm8350_ufsphy_serdes_tbl,
- .serdes_tbl_num = ARRAY_SIZE(sm8350_ufsphy_serdes_tbl),
- .tx_tbl = sm8350_ufsphy_tx_tbl,
- .tx_tbl_num = ARRAY_SIZE(sm8350_ufsphy_tx_tbl),
- .rx_tbl = sm8350_ufsphy_rx_tbl,
- .rx_tbl_num = ARRAY_SIZE(sm8350_ufsphy_rx_tbl),
- .pcs_tbl = sm8350_ufsphy_pcs_tbl,
- .pcs_tbl_num = ARRAY_SIZE(sm8350_ufsphy_pcs_tbl),
+ .tbls = {
+ .serdes = sm8350_ufsphy_serdes,
+ .serdes_num = ARRAY_SIZE(sm8350_ufsphy_serdes),
+ .tx = sm8350_ufsphy_tx,
+ .tx_num = ARRAY_SIZE(sm8350_ufsphy_tx),
+ .rx = sm8350_ufsphy_rx,
+ .rx_num = ARRAY_SIZE(sm8350_ufsphy_rx),
+ .pcs = sm8350_ufsphy_pcs,
+ .pcs_num = ARRAY_SIZE(sm8350_ufsphy_pcs),
+ },
+ .tbls_hs_b = {
+ .serdes = sm8350_ufsphy_hs_b_serdes,
+ .serdes_num = ARRAY_SIZE(sm8350_ufsphy_hs_b_serdes),
+ },
+ .tbls_hs_g4 = {
+ .tx = sm8350_ufsphy_g4_tx,
+ .tx_num = ARRAY_SIZE(sm8350_ufsphy_g4_tx),
+ .rx = sm8350_ufsphy_g4_rx,
+ .rx_num = ARRAY_SIZE(sm8350_ufsphy_g4_rx),
+ .pcs = sm8350_ufsphy_g4_pcs,
+ .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs),
+ },
.clk_list = sdm845_ufs_phy_clk_l,
.num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
.vreg_list = qmp_phy_vreg_l,
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
- .regs = sm8150_ufsphy_regs_layout,
+ .regs = ufsphy_v5_regs_layout,
};
static const struct qmp_phy_cfg sm8450_ufsphy_cfg = {
.lanes = 2,
- .serdes_tbl = sm8350_ufsphy_serdes_tbl,
- .serdes_tbl_num = ARRAY_SIZE(sm8350_ufsphy_serdes_tbl),
- .tx_tbl = sm8350_ufsphy_tx_tbl,
- .tx_tbl_num = ARRAY_SIZE(sm8350_ufsphy_tx_tbl),
- .rx_tbl = sm8350_ufsphy_rx_tbl,
- .rx_tbl_num = ARRAY_SIZE(sm8350_ufsphy_rx_tbl),
- .pcs_tbl = sm8350_ufsphy_pcs_tbl,
- .pcs_tbl_num = ARRAY_SIZE(sm8350_ufsphy_pcs_tbl),
+ .tbls = {
+ .serdes = sm8350_ufsphy_serdes,
+ .serdes_num = ARRAY_SIZE(sm8350_ufsphy_serdes),
+ .tx = sm8350_ufsphy_tx,
+ .tx_num = ARRAY_SIZE(sm8350_ufsphy_tx),
+ .rx = sm8350_ufsphy_rx,
+ .rx_num = ARRAY_SIZE(sm8350_ufsphy_rx),
+ .pcs = sm8350_ufsphy_pcs,
+ .pcs_num = ARRAY_SIZE(sm8350_ufsphy_pcs),
+ },
+ .tbls_hs_b = {
+ .serdes = sm8350_ufsphy_hs_b_serdes,
+ .serdes_num = ARRAY_SIZE(sm8350_ufsphy_hs_b_serdes),
+ },
+ .tbls_hs_g4 = {
+ .tx = sm8350_ufsphy_g4_tx,
+ .tx_num = ARRAY_SIZE(sm8350_ufsphy_g4_tx),
+ .rx = sm8350_ufsphy_g4_rx,
+ .rx_num = ARRAY_SIZE(sm8350_ufsphy_g4_rx),
+ .pcs = sm8350_ufsphy_g4_pcs,
+ .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs),
+ },
.clk_list = sm8450_ufs_phy_clk_l,
.num_clks = ARRAY_SIZE(sm8450_ufs_phy_clk_l),
.vreg_list = qmp_phy_vreg_l,
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
- .regs = sm8150_ufsphy_regs_layout,
+ .regs = ufsphy_v5_regs_layout,
+};
+
+static const struct qmp_phy_cfg sm8550_ufsphy_cfg = {
+ .lanes = 2,
+
+ .offsets = &qmp_ufs_offsets_v6,
+
+ .tbls = {
+ .serdes = sm8550_ufsphy_serdes,
+ .serdes_num = ARRAY_SIZE(sm8550_ufsphy_serdes),
+ .tx = sm8550_ufsphy_tx,
+ .tx_num = ARRAY_SIZE(sm8550_ufsphy_tx),
+ .rx = sm8550_ufsphy_rx,
+ .rx_num = ARRAY_SIZE(sm8550_ufsphy_rx),
+ .pcs = sm8550_ufsphy_pcs,
+ .pcs_num = ARRAY_SIZE(sm8550_ufsphy_pcs),
+ },
+ .clk_list = sdm845_ufs_phy_clk_l,
+ .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
+ .vreg_list = qmp_phy_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
+ .regs = ufsphy_v6_regs_layout,
};
static void qmp_ufs_configure_lane(void __iomem *base,
@@ -790,16 +1087,46 @@ static void qmp_ufs_configure(void __iomem *base,
qmp_ufs_configure_lane(base, tbl, num, 0xff);
}
-static int qmp_ufs_serdes_init(struct qmp_ufs *qmp)
+static void qmp_ufs_serdes_init(struct qmp_ufs *qmp, const struct qmp_phy_cfg_tbls *tbls)
{
- const struct qmp_phy_cfg *cfg = qmp->cfg;
void __iomem *serdes = qmp->serdes;
- const struct qmp_phy_init_tbl *serdes_tbl = cfg->serdes_tbl;
- int serdes_tbl_num = cfg->serdes_tbl_num;
- qmp_ufs_configure(serdes, serdes_tbl, serdes_tbl_num);
+ qmp_ufs_configure(serdes, tbls->serdes, tbls->serdes_num);
+}
- return 0;
+static void qmp_ufs_lanes_init(struct qmp_ufs *qmp, const struct qmp_phy_cfg_tbls *tbls)
+{
+ const struct qmp_phy_cfg *cfg = qmp->cfg;
+ void __iomem *tx = qmp->tx;
+ void __iomem *rx = qmp->rx;
+
+ qmp_ufs_configure_lane(tx, tbls->tx, tbls->tx_num, 1);
+ qmp_ufs_configure_lane(rx, tbls->rx, tbls->rx_num, 1);
+
+ if (cfg->lanes >= 2) {
+ qmp_ufs_configure_lane(qmp->tx2, tbls->tx, tbls->tx_num, 2);
+ qmp_ufs_configure_lane(qmp->rx2, tbls->rx, tbls->rx_num, 2);
+ }
+}
+
+static void qmp_ufs_pcs_init(struct qmp_ufs *qmp, const struct qmp_phy_cfg_tbls *tbls)
+{
+ void __iomem *pcs = qmp->pcs;
+
+ qmp_ufs_configure(pcs, tbls->pcs, tbls->pcs_num);
+}
+
+static void qmp_ufs_init_registers(struct qmp_ufs *qmp, const struct qmp_phy_cfg *cfg)
+{
+ qmp_ufs_serdes_init(qmp, &cfg->tbls);
+ if (qmp->mode == PHY_MODE_UFS_HS_B)
+ qmp_ufs_serdes_init(qmp, &cfg->tbls_hs_b);
+ qmp_ufs_lanes_init(qmp, &cfg->tbls);
+ if (qmp->submode == UFS_HS_G4)
+ qmp_ufs_lanes_init(qmp, &cfg->tbls_hs_g4);
+ qmp_ufs_pcs_init(qmp, &cfg->tbls);
+ if (qmp->submode == UFS_HS_G4)
+ qmp_ufs_pcs_init(qmp, &cfg->tbls_hs_g4);
}
static int qmp_ufs_com_init(struct qmp_ufs *qmp)
@@ -886,25 +1213,12 @@ static int qmp_ufs_power_on(struct phy *phy)
{
struct qmp_ufs *qmp = phy_get_drvdata(phy);
const struct qmp_phy_cfg *cfg = qmp->cfg;
- void __iomem *tx = qmp->tx;
- void __iomem *rx = qmp->rx;
void __iomem *pcs = qmp->pcs;
void __iomem *status;
unsigned int val;
int ret;
- qmp_ufs_serdes_init(qmp);
-
- /* Tx, Rx, and PCS configurations */
- qmp_ufs_configure_lane(tx, cfg->tx_tbl, cfg->tx_tbl_num, 1);
- qmp_ufs_configure_lane(rx, cfg->rx_tbl, cfg->rx_tbl_num, 1);
-
- if (cfg->lanes >= 2) {
- qmp_ufs_configure_lane(qmp->tx2, cfg->tx_tbl, cfg->tx_tbl_num, 2);
- qmp_ufs_configure_lane(qmp->rx2, cfg->rx_tbl, cfg->rx_tbl_num, 2);
- }
-
- qmp_ufs_configure(pcs, cfg->pcs_tbl, cfg->pcs_tbl_num);
+ qmp_ufs_init_registers(qmp, cfg);
ret = reset_control_deassert(qmp->ufs_reset);
if (ret)
@@ -981,9 +1295,20 @@ static int qmp_ufs_disable(struct phy *phy)
return qmp_ufs_exit(phy);
}
+static int qmp_ufs_set_mode(struct phy *phy, enum phy_mode mode, int submode)
+{
+ struct qmp_ufs *qmp = phy_get_drvdata(phy);
+
+ qmp->mode = mode;
+ qmp->submode = submode;
+
+ return 0;
+}
+
static const struct phy_ops qcom_qmp_ufs_phy_ops = {
.power_on = qmp_ufs_enable,
.power_off = qmp_ufs_disable,
+ .set_mode = qmp_ufs_set_mode,
.owner = THIS_MODULE,
};
@@ -1021,6 +1346,59 @@ static int qmp_ufs_clk_init(struct qmp_ufs *qmp)
return devm_clk_bulk_get(dev, num, qmp->clks);
}
+static void qmp_ufs_clk_release_provider(void *res)
+{
+ of_clk_del_provider(res);
+}
+
+#define UFS_SYMBOL_CLOCKS 3
+
+static int qmp_ufs_register_clocks(struct qmp_ufs *qmp, struct device_node *np)
+{
+ struct clk_hw_onecell_data *clk_data;
+ struct clk_hw *hw;
+ char name[64];
+ int ret;
+
+ clk_data = devm_kzalloc(qmp->dev,
+ struct_size(clk_data, hws, UFS_SYMBOL_CLOCKS),
+ GFP_KERNEL);
+ if (!clk_data)
+ return -ENOMEM;
+
+ clk_data->num = UFS_SYMBOL_CLOCKS;
+
+ snprintf(name, sizeof(name), "%s::rx_symbol_0", dev_name(qmp->dev));
+ hw = devm_clk_hw_register_fixed_rate(qmp->dev, name, NULL, 0, 0);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+
+ clk_data->hws[0] = hw;
+
+ snprintf(name, sizeof(name), "%s::rx_symbol_1", dev_name(qmp->dev));
+ hw = devm_clk_hw_register_fixed_rate(qmp->dev, name, NULL, 0, 0);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+
+ clk_data->hws[1] = hw;
+
+ snprintf(name, sizeof(name), "%s::tx_symbol_0", dev_name(qmp->dev));
+ hw = devm_clk_hw_register_fixed_rate(qmp->dev, name, NULL, 0, 0);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+
+ clk_data->hws[2] = hw;
+
+ ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
+ if (ret)
+ return ret;
+
+ /*
+ * Roll a devm action because the clock provider can be a child node.
+ */
+ return devm_add_action_or_reset(qmp->dev, qmp_ufs_clk_release_provider, np);
+}
+
static int qmp_ufs_parse_dt_legacy(struct qmp_ufs *qmp, struct device_node *np)
{
struct platform_device *pdev = to_platform_device(qmp->dev);
@@ -1133,6 +1511,10 @@ static int qmp_ufs_probe(struct platform_device *pdev)
if (ret)
goto err_node_put;
+ ret = qmp_ufs_register_clocks(qmp, np);
+ if (ret)
+ goto err_node_put;
+
qmp->phy = devm_phy_create(dev, np, &qcom_qmp_ufs_phy_ops);
if (IS_ERR(qmp->phy)) {
ret = PTR_ERR(qmp->phy);
@@ -1156,7 +1538,7 @@ err_node_put:
static const struct of_device_id qmp_ufs_of_match_table[] = {
{
.compatible = "qcom,msm8996-qmp-ufs-phy",
- .data = &msm8996_ufs_cfg,
+ .data = &msm8996_ufsphy_cfg,
}, {
.compatible = "qcom,msm8998-qmp-ufs-phy",
.data = &sdm845_ufsphy_cfg,
@@ -1173,6 +1555,9 @@ static const struct of_device_id qmp_ufs_of_match_table[] = {
.compatible = "qcom,sm6115-qmp-ufs-phy",
.data = &sm6115_ufsphy_cfg,
}, {
+ .compatible = "qcom,sm6125-qmp-ufs-phy",
+ .data = &sm6115_ufsphy_cfg,
+ }, {
.compatible = "qcom,sm6350-qmp-ufs-phy",
.data = &sdm845_ufsphy_cfg,
}, {
@@ -1180,13 +1565,16 @@ static const struct of_device_id qmp_ufs_of_match_table[] = {
.data = &sm8150_ufsphy_cfg,
}, {
.compatible = "qcom,sm8250-qmp-ufs-phy",
- .data = &sm8150_ufsphy_cfg,
+ .data = &sm8250_ufsphy_cfg,
}, {
.compatible = "qcom,sm8350-qmp-ufs-phy",
.data = &sm8350_ufsphy_cfg,
}, {
.compatible = "qcom,sm8450-qmp-ufs-phy",
.data = &sm8450_ufsphy_cfg,
+ }, {
+ .compatible = "qcom,sm8550-qmp-ufs-phy",
+ .data = &sm8550_ufsphy_cfg,
},
{ },
};
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c
index 4aa338fc4643..a49711c5a63d 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c
@@ -21,6 +21,9 @@
#include <linux/slab.h>
#include "phy-qcom-qmp.h"
+#include "phy-qcom-qmp-pcs-misc-v3.h"
+#include "phy-qcom-qmp-pcs-usb-v4.h"
+#include "phy-qcom-qmp-pcs-usb-v5.h"
/* QPHY_SW_RESET bit */
#define SW_RESET BIT(0)
@@ -54,9 +57,6 @@
/* QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR register bits */
#define IRQ_CLEAR BIT(0)
-/* QPHY_PCS_LFPS_RXTERM_IRQ_STATUS register bits */
-#define RCVR_DETECT BIT(0)
-
/* QPHY_V3_PCS_MISC_CLAMP_ENABLE register bits */
#define CLAMP_EN BIT(0) /* enables i/o clamp_n */
@@ -94,53 +94,49 @@ enum qphy_reg_layout {
QPHY_PCS_STATUS,
QPHY_PCS_AUTONOMOUS_MODE_CTRL,
QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR,
- QPHY_PCS_LFPS_RXTERM_IRQ_STATUS,
QPHY_PCS_POWER_DOWN_CONTROL,
- /* PCS_MISC registers */
- QPHY_PCS_MISC_TYPEC_CTRL,
/* Keep last to ensure regs_layout arrays are properly initialized */
QPHY_LAYOUT_SIZE
};
-static const unsigned int usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = {
- [QPHY_SW_RESET] = 0x00,
- [QPHY_START_CTRL] = 0x08,
- [QPHY_PCS_STATUS] = 0x17c,
- [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = 0x0d4,
- [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = 0x0d8,
- [QPHY_PCS_LFPS_RXTERM_IRQ_STATUS] = 0x178,
- [QPHY_PCS_POWER_DOWN_CONTROL] = 0x04,
+static const unsigned int qmp_v2_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = {
+ [QPHY_SW_RESET] = QPHY_V2_PCS_SW_RESET,
+ [QPHY_START_CTRL] = QPHY_V2_PCS_START_CONTROL,
+ [QPHY_PCS_STATUS] = QPHY_V2_PCS_USB_PCS_STATUS,
+ [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = QPHY_V2_PCS_AUTONOMOUS_MODE_CTRL,
+ [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V2_PCS_LFPS_RXTERM_IRQ_CLEAR,
+ [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V2_PCS_POWER_DOWN_CONTROL,
};
static const unsigned int qmp_v3_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = {
- [QPHY_SW_RESET] = 0x00,
- [QPHY_START_CTRL] = 0x08,
- [QPHY_PCS_STATUS] = 0x174,
- [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = 0x0d8,
- [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = 0x0dc,
- [QPHY_PCS_LFPS_RXTERM_IRQ_STATUS] = 0x170,
- [QPHY_PCS_POWER_DOWN_CONTROL] = 0x04,
+ [QPHY_SW_RESET] = QPHY_V3_PCS_SW_RESET,
+ [QPHY_START_CTRL] = QPHY_V3_PCS_START_CONTROL,
+ [QPHY_PCS_STATUS] = QPHY_V3_PCS_PCS_STATUS,
+ [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = QPHY_V3_PCS_AUTONOMOUS_MODE_CTRL,
+ [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V3_PCS_LFPS_RXTERM_IRQ_CLEAR,
+ [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V3_PCS_POWER_DOWN_CONTROL,
};
static const unsigned int qmp_v4_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = {
- [QPHY_SW_RESET] = 0x00,
- [QPHY_START_CTRL] = 0x44,
- [QPHY_PCS_STATUS] = 0x14,
- [QPHY_PCS_POWER_DOWN_CONTROL] = 0x40,
+ [QPHY_SW_RESET] = QPHY_V4_PCS_SW_RESET,
+ [QPHY_START_CTRL] = QPHY_V4_PCS_START_CONTROL,
+ [QPHY_PCS_STATUS] = QPHY_V4_PCS_PCS_STATUS1,
+ [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V4_PCS_POWER_DOWN_CONTROL,
/* In PCS_USB */
- [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = 0x008,
- [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = 0x014,
+ [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = QPHY_V4_PCS_USB3_AUTONOMOUS_MODE_CTRL,
+ [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V4_PCS_USB3_LFPS_RXTERM_IRQ_CLEAR,
};
-static const unsigned int qcm2290_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = {
- [QPHY_SW_RESET] = 0x00,
- [QPHY_PCS_POWER_DOWN_CONTROL] = 0x04,
- [QPHY_START_CTRL] = 0x08,
- [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = 0xd8,
- [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = 0xdc,
- [QPHY_PCS_STATUS] = 0x174,
- [QPHY_PCS_MISC_TYPEC_CTRL] = 0x00,
+static const unsigned int qmp_v5_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = {
+ [QPHY_SW_RESET] = QPHY_V5_PCS_SW_RESET,
+ [QPHY_START_CTRL] = QPHY_V5_PCS_START_CONTROL,
+ [QPHY_PCS_STATUS] = QPHY_V5_PCS_PCS_STATUS1,
+ [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V5_PCS_POWER_DOWN_CONTROL,
+
+ /* In PCS_USB */
+ [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = QPHY_V5_PCS_USB3_AUTONOMOUS_MODE_CTRL,
+ [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V5_PCS_USB3_LFPS_RXTERM_IRQ_CLEAR,
};
static const struct qmp_phy_init_tbl ipq8074_usb3_serdes_tbl[] = {
@@ -1265,7 +1261,7 @@ static const struct qmp_phy_init_tbl qcm2290_usb3_tx_tbl[] = {
static const struct qmp_phy_init_tbl qcm2290_usb3_rx_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b),
- QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_PI_CONTROLS, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_PI_CONTROLS, 0x80),
QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW, 0x00),
QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x00),
QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FO_GAIN, 0x0a),
@@ -1607,7 +1603,7 @@ static const struct qmp_phy_cfg msm8996_usb3phy_cfg = {
.num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l),
.vreg_list = qmp_phy_vreg_l,
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
- .regs = usb3phy_regs_layout,
+ .regs = qmp_v2_usb3phy_regs_layout,
};
static const struct qmp_phy_cfg qmp_v3_usb3phy_cfg = {
@@ -1675,7 +1671,7 @@ static const struct qmp_phy_cfg sc8280xp_usb3_uniphy_cfg = {
.num_resets = ARRAY_SIZE(qcm2290_usb3phy_reset_l),
.vreg_list = qmp_phy_vreg_l,
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
- .regs = qmp_v4_usb3phy_regs_layout,
+ .regs = qmp_v5_usb3phy_regs_layout,
};
static const struct qmp_phy_cfg qmp_v3_usb3_uniphy_cfg = {
@@ -1866,7 +1862,7 @@ static const struct qmp_phy_cfg sdx65_usb3_uniphy_cfg = {
.num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l),
.vreg_list = qmp_phy_vreg_l,
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
- .regs = qmp_v4_usb3phy_regs_layout,
+ .regs = qmp_v5_usb3phy_regs_layout,
.pcs_usb_offset = 0x1000,
.has_pwrdn_delay = true,
@@ -1891,7 +1887,7 @@ static const struct qmp_phy_cfg sm8350_usb3phy_cfg = {
.num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l),
.vreg_list = qmp_phy_vreg_l,
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
- .regs = qmp_v4_usb3phy_regs_layout,
+ .regs = qmp_v5_usb3phy_regs_layout,
.pcs_usb_offset = 0x300,
.has_pwrdn_delay = true,
@@ -1917,7 +1913,7 @@ static const struct qmp_phy_cfg sm8350_usb3_uniphy_cfg = {
.num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l),
.vreg_list = qmp_phy_vreg_l,
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
- .regs = qmp_v4_usb3phy_regs_layout,
+ .regs = qmp_v5_usb3phy_regs_layout,
.pcs_usb_offset = 0x1000,
.has_pwrdn_delay = true,
@@ -1940,7 +1936,7 @@ static const struct qmp_phy_cfg qcm2290_usb3phy_cfg = {
.num_resets = ARRAY_SIZE(qcm2290_usb3phy_reset_l),
.vreg_list = qmp_phy_vreg_l,
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
- .regs = qcm2290_usb3phy_regs_layout,
+ .regs = qmp_v3_usb3phy_regs_layout,
};
static void qmp_usb_configure_lane(void __iomem *base,
@@ -2623,6 +2619,9 @@ static const struct of_device_id qmp_usb_of_match_table[] = {
.compatible = "qcom,sdx65-qmp-usb3-uni-phy",
.data = &sdx65_usb3_uniphy_cfg,
}, {
+ .compatible = "qcom,sm6115-qmp-usb3-phy",
+ .data = &qcm2290_usb3phy_cfg,
+ }, {
.compatible = "qcom,sm8150-qmp-usb3-phy",
.data = &sm8150_usb3phy_cfg,
}, {
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.h b/drivers/phy/qualcomm/phy-qcom-qmp.h
index 29a48f0436d2..7ee4b0e07d11 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.h
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.h
@@ -21,31 +21,28 @@
#include "phy-qcom-qmp-qserdes-txrx-v5_20.h"
#include "phy-qcom-qmp-qserdes-txrx-v5_5nm.h"
+#include "phy-qcom-qmp-qserdes-com-v6.h"
+#include "phy-qcom-qmp-qserdes-txrx-v6.h"
+#include "phy-qcom-qmp-qserdes-txrx-v6_20.h"
+#include "phy-qcom-qmp-qserdes-ln-shrd-v6.h"
+
#include "phy-qcom-qmp-qserdes-pll.h"
#include "phy-qcom-qmp-pcs-v2.h"
#include "phy-qcom-qmp-pcs-v3.h"
-#include "phy-qcom-qmp-pcs-misc-v3.h"
-#include "phy-qcom-qmp-pcs-ufs-v3.h"
#include "phy-qcom-qmp-pcs-v4.h"
-#include "phy-qcom-qmp-pcs-pcie-v4.h"
-#include "phy-qcom-qmp-pcs-usb-v4.h"
-#include "phy-qcom-qmp-pcs-ufs-v4.h"
#include "phy-qcom-qmp-pcs-v4_20.h"
-#include "phy-qcom-qmp-pcs-pcie-v4_20.h"
#include "phy-qcom-qmp-pcs-v5.h"
+
#include "phy-qcom-qmp-pcs-v5_20.h"
-#include "phy-qcom-qmp-pcs-pcie-v5.h"
-#include "phy-qcom-qmp-pcs-usb-v5.h"
-#include "phy-qcom-qmp-pcs-ufs-v5.h"
-#include "phy-qcom-qmp-pcs-pcie-v5_20.h"
+#include "phy-qcom-qmp-pcs-v6.h"
-#include "phy-qcom-qmp-pcie-qhp.h"
+#include "phy-qcom-qmp-pcs-v6_20.h"
/* Only for QMP V3 & V4 PHY - DP COM registers */
#define QPHY_V3_DP_COM_PHY_MODE_CTRL 0x00
@@ -137,4 +134,8 @@
#define QPHY_V4_PCS_MISC_TYPEC_STATUS 0x10
#define QPHY_V4_PCS_MISC_PLACEHOLDER_STATUS 0x14
+/* Only for QMP V6 PHY - DP PHY registers */
+#define QSERDES_V6_DP_PHY_AUX_INTERRUPT_STATUS 0x0e0
+#define QSERDES_V6_DP_PHY_STATUS 0x0e4
+
#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-snps-eusb2.c b/drivers/phy/qualcomm/phy-qcom-snps-eusb2.c
new file mode 100644
index 000000000000..eeaa1eb0e24b
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-snps-eusb2.c
@@ -0,0 +1,441 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2023, Linaro Limited
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/iopoll.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+
+#define USB_PHY_UTMI_CTRL0 (0x3c)
+#define SLEEPM BIT(0)
+#define OPMODE_MASK GENMASK(4, 3)
+#define OPMODE_NONDRIVING BIT(3)
+
+#define USB_PHY_UTMI_CTRL5 (0x50)
+#define POR BIT(1)
+
+#define USB_PHY_HS_PHY_CTRL_COMMON0 (0x54)
+#define PHY_ENABLE BIT(0)
+#define SIDDQ_SEL BIT(1)
+#define SIDDQ BIT(2)
+#define RETENABLEN BIT(3)
+#define FSEL_MASK GENMASK(6, 4)
+#define FSEL_19_2_MHZ_VAL (0x0)
+#define FSEL_38_4_MHZ_VAL (0x4)
+
+#define USB_PHY_CFG_CTRL_1 (0x58)
+#define PHY_CFG_PLL_CPBIAS_CNTRL_MASK GENMASK(7, 1)
+
+#define USB_PHY_CFG_CTRL_2 (0x5c)
+#define PHY_CFG_PLL_FB_DIV_7_0_MASK GENMASK(7, 0)
+#define DIV_7_0_19_2_MHZ_VAL (0x90)
+#define DIV_7_0_38_4_MHZ_VAL (0xc8)
+
+#define USB_PHY_CFG_CTRL_3 (0x60)
+#define PHY_CFG_PLL_FB_DIV_11_8_MASK GENMASK(3, 0)
+#define DIV_11_8_19_2_MHZ_VAL (0x1)
+#define DIV_11_8_38_4_MHZ_VAL (0x0)
+
+#define PHY_CFG_PLL_REF_DIV GENMASK(7, 4)
+#define PLL_REF_DIV_VAL (0x0)
+
+#define USB_PHY_HS_PHY_CTRL2 (0x64)
+#define VBUSVLDEXT0 BIT(0)
+#define USB2_SUSPEND_N BIT(2)
+#define USB2_SUSPEND_N_SEL BIT(3)
+#define VBUS_DET_EXT_SEL BIT(4)
+
+#define USB_PHY_CFG_CTRL_4 (0x68)
+#define PHY_CFG_PLL_GMP_CNTRL_MASK GENMASK(1, 0)
+#define PHY_CFG_PLL_INT_CNTRL_MASK GENMASK(7, 2)
+
+#define USB_PHY_CFG_CTRL_5 (0x6c)
+#define PHY_CFG_PLL_PROP_CNTRL_MASK GENMASK(4, 0)
+#define PHY_CFG_PLL_VREF_TUNE_MASK GENMASK(7, 6)
+
+#define USB_PHY_CFG_CTRL_6 (0x70)
+#define PHY_CFG_PLL_VCO_CNTRL_MASK GENMASK(2, 0)
+
+#define USB_PHY_CFG_CTRL_7 (0x74)
+
+#define USB_PHY_CFG_CTRL_8 (0x78)
+#define PHY_CFG_TX_FSLS_VREF_TUNE_MASK GENMASK(1, 0)
+#define PHY_CFG_TX_FSLS_VREG_BYPASS BIT(2)
+#define PHY_CFG_TX_HS_VREF_TUNE_MASK GENMASK(5, 3)
+#define PHY_CFG_TX_HS_XV_TUNE_MASK GENMASK(7, 6)
+
+#define USB_PHY_CFG_CTRL_9 (0x7c)
+#define PHY_CFG_TX_PREEMP_TUNE_MASK GENMASK(2, 0)
+#define PHY_CFG_TX_RES_TUNE_MASK GENMASK(4, 3)
+#define PHY_CFG_TX_RISE_TUNE_MASK GENMASK(6, 5)
+#define PHY_CFG_RCAL_BYPASS BIT(7)
+
+#define USB_PHY_CFG_CTRL_10 (0x80)
+
+#define USB_PHY_CFG0 (0x94)
+#define DATAPATH_CTRL_OVERRIDE_EN BIT(0)
+#define CMN_CTRL_OVERRIDE_EN BIT(1)
+
+#define UTMI_PHY_CMN_CTRL0 (0x98)
+#define TESTBURNIN BIT(6)
+
+#define USB_PHY_FSEL_SEL (0xb8)
+#define FSEL_SEL BIT(0)
+
+#define USB_PHY_APB_ACCESS_CMD (0x130)
+#define RW_ACCESS BIT(0)
+#define APB_START_CMD BIT(1)
+#define APB_LOGIC_RESET BIT(2)
+
+#define USB_PHY_APB_ACCESS_STATUS (0x134)
+#define ACCESS_DONE BIT(0)
+#define TIMED_OUT BIT(1)
+#define ACCESS_ERROR BIT(2)
+#define ACCESS_IN_PROGRESS BIT(3)
+
+#define USB_PHY_APB_ADDRESS (0x138)
+#define APB_REG_ADDR_MASK GENMASK(7, 0)
+
+#define USB_PHY_APB_WRDATA_LSB (0x13c)
+#define APB_REG_WRDATA_7_0_MASK GENMASK(3, 0)
+
+#define USB_PHY_APB_WRDATA_MSB (0x140)
+#define APB_REG_WRDATA_15_8_MASK GENMASK(7, 4)
+
+#define USB_PHY_APB_RDDATA_LSB (0x144)
+#define APB_REG_RDDATA_7_0_MASK GENMASK(3, 0)
+
+#define USB_PHY_APB_RDDATA_MSB (0x148)
+#define APB_REG_RDDATA_15_8_MASK GENMASK(7, 4)
+
+static const char * const eusb2_hsphy_vreg_names[] = {
+ "vdd", "vdda12",
+};
+
+#define EUSB2_NUM_VREGS ARRAY_SIZE(eusb2_hsphy_vreg_names)
+
+struct qcom_snps_eusb2_hsphy {
+ struct phy *phy;
+ void __iomem *base;
+
+ struct clk *ref_clk;
+ struct reset_control *phy_reset;
+
+ struct regulator_bulk_data vregs[EUSB2_NUM_VREGS];
+
+ enum phy_mode mode;
+
+ struct phy *repeater;
+};
+
+static int qcom_snps_eusb2_hsphy_set_mode(struct phy *p, enum phy_mode mode, int submode)
+{
+ struct qcom_snps_eusb2_hsphy *phy = phy_get_drvdata(p);
+
+ phy->mode = mode;
+
+ return phy_set_mode_ext(phy->repeater, mode, submode);
+}
+
+static void qcom_snps_eusb2_hsphy_write_mask(void __iomem *base, u32 offset,
+ u32 mask, u32 val)
+{
+ u32 reg;
+
+ reg = readl_relaxed(base + offset);
+ reg &= ~mask;
+ reg |= val & mask;
+ writel_relaxed(reg, base + offset);
+
+ /* Ensure above write is completed */
+ readl_relaxed(base + offset);
+}
+
+static void qcom_eusb2_default_parameters(struct qcom_snps_eusb2_hsphy *phy)
+{
+ /* default parameters: tx pre-emphasis */
+ qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_9,
+ PHY_CFG_TX_PREEMP_TUNE_MASK,
+ FIELD_PREP(PHY_CFG_TX_PREEMP_TUNE_MASK, 0));
+
+ /* tx rise/fall time */
+ qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_9,
+ PHY_CFG_TX_RISE_TUNE_MASK,
+ FIELD_PREP(PHY_CFG_TX_RISE_TUNE_MASK, 0x2));
+
+ /* source impedance adjustment */
+ qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_9,
+ PHY_CFG_TX_RES_TUNE_MASK,
+ FIELD_PREP(PHY_CFG_TX_RES_TUNE_MASK, 0x1));
+
+ /* dc voltage level adjustement */
+ qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_8,
+ PHY_CFG_TX_HS_VREF_TUNE_MASK,
+ FIELD_PREP(PHY_CFG_TX_HS_VREF_TUNE_MASK, 0x3));
+
+ /* transmitter HS crossover adjustement */
+ qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_8,
+ PHY_CFG_TX_HS_XV_TUNE_MASK,
+ FIELD_PREP(PHY_CFG_TX_HS_XV_TUNE_MASK, 0x0));
+}
+
+static int qcom_eusb2_ref_clk_init(struct qcom_snps_eusb2_hsphy *phy)
+{
+ unsigned long ref_clk_freq = clk_get_rate(phy->ref_clk);
+
+ switch (ref_clk_freq) {
+ case 19200000:
+ qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_HS_PHY_CTRL_COMMON0,
+ FSEL_MASK,
+ FIELD_PREP(FSEL_MASK, FSEL_19_2_MHZ_VAL));
+
+ qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_2,
+ PHY_CFG_PLL_FB_DIV_7_0_MASK,
+ DIV_7_0_19_2_MHZ_VAL);
+
+ qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_3,
+ PHY_CFG_PLL_FB_DIV_11_8_MASK,
+ DIV_11_8_19_2_MHZ_VAL);
+ break;
+
+ case 38400000:
+ qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_HS_PHY_CTRL_COMMON0,
+ FSEL_MASK,
+ FIELD_PREP(FSEL_MASK, FSEL_38_4_MHZ_VAL));
+
+ qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_2,
+ PHY_CFG_PLL_FB_DIV_7_0_MASK,
+ DIV_7_0_38_4_MHZ_VAL);
+
+ qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_3,
+ PHY_CFG_PLL_FB_DIV_11_8_MASK,
+ DIV_11_8_38_4_MHZ_VAL);
+ break;
+
+ default:
+ dev_err(&phy->phy->dev, "unsupported ref_clk_freq:%lu\n", ref_clk_freq);
+ return -EINVAL;
+ }
+
+ qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_3,
+ PHY_CFG_PLL_REF_DIV, PLL_REF_DIV_VAL);
+
+ return 0;
+}
+
+static int qcom_snps_eusb2_hsphy_init(struct phy *p)
+{
+ struct qcom_snps_eusb2_hsphy *phy = phy_get_drvdata(p);
+ int ret;
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(phy->vregs), phy->vregs);
+ if (ret)
+ return ret;
+
+ ret = phy_init(phy->repeater);
+ if (ret) {
+ dev_err(&p->dev, "repeater init failed. %d\n", ret);
+ goto disable_vreg;
+ }
+
+ ret = clk_prepare_enable(phy->ref_clk);
+ if (ret) {
+ dev_err(&p->dev, "failed to enable ref clock, %d\n", ret);
+ goto disable_vreg;
+ }
+
+ ret = reset_control_assert(phy->phy_reset);
+ if (ret) {
+ dev_err(&p->dev, "failed to assert phy_reset, %d\n", ret);
+ goto disable_ref_clk;
+ }
+
+ usleep_range(100, 150);
+
+ ret = reset_control_deassert(phy->phy_reset);
+ if (ret) {
+ dev_err(&p->dev, "failed to de-assert phy_reset, %d\n", ret);
+ goto disable_ref_clk;
+ }
+
+ qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG0,
+ CMN_CTRL_OVERRIDE_EN, CMN_CTRL_OVERRIDE_EN);
+
+ qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_UTMI_CTRL5, POR, POR);
+
+ qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_HS_PHY_CTRL_COMMON0,
+ PHY_ENABLE | RETENABLEN, PHY_ENABLE | RETENABLEN);
+
+ qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_APB_ACCESS_CMD,
+ APB_LOGIC_RESET, APB_LOGIC_RESET);
+
+ qcom_snps_eusb2_hsphy_write_mask(phy->base, UTMI_PHY_CMN_CTRL0, TESTBURNIN, 0);
+
+ qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_FSEL_SEL,
+ FSEL_SEL, FSEL_SEL);
+
+ /* update ref_clk related registers */
+ ret = qcom_eusb2_ref_clk_init(phy);
+ if (ret)
+ goto disable_ref_clk;
+
+ qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_1,
+ PHY_CFG_PLL_CPBIAS_CNTRL_MASK,
+ FIELD_PREP(PHY_CFG_PLL_CPBIAS_CNTRL_MASK, 0x1));
+
+ qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_4,
+ PHY_CFG_PLL_INT_CNTRL_MASK,
+ FIELD_PREP(PHY_CFG_PLL_INT_CNTRL_MASK, 0x8));
+
+ qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_4,
+ PHY_CFG_PLL_GMP_CNTRL_MASK,
+ FIELD_PREP(PHY_CFG_PLL_GMP_CNTRL_MASK, 0x1));
+
+ qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_5,
+ PHY_CFG_PLL_PROP_CNTRL_MASK,
+ FIELD_PREP(PHY_CFG_PLL_PROP_CNTRL_MASK, 0x10));
+
+ qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_6,
+ PHY_CFG_PLL_VCO_CNTRL_MASK,
+ FIELD_PREP(PHY_CFG_PLL_VCO_CNTRL_MASK, 0x0));
+
+ qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_5,
+ PHY_CFG_PLL_VREF_TUNE_MASK,
+ FIELD_PREP(PHY_CFG_PLL_VREF_TUNE_MASK, 0x1));
+
+ qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_HS_PHY_CTRL2,
+ VBUS_DET_EXT_SEL, VBUS_DET_EXT_SEL);
+
+ /* set default parameters */
+ qcom_eusb2_default_parameters(phy);
+
+ qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_HS_PHY_CTRL2,
+ USB2_SUSPEND_N_SEL | USB2_SUSPEND_N,
+ USB2_SUSPEND_N_SEL | USB2_SUSPEND_N);
+
+ qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_UTMI_CTRL0, SLEEPM, SLEEPM);
+
+ qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_HS_PHY_CTRL_COMMON0,
+ SIDDQ_SEL, SIDDQ_SEL);
+
+ qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_HS_PHY_CTRL_COMMON0,
+ SIDDQ, 0);
+
+ qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_UTMI_CTRL5, POR, 0);
+
+ qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_HS_PHY_CTRL2,
+ USB2_SUSPEND_N_SEL, 0);
+
+ return 0;
+
+disable_ref_clk:
+ clk_disable_unprepare(phy->ref_clk);
+
+disable_vreg:
+ regulator_bulk_disable(ARRAY_SIZE(phy->vregs), phy->vregs);
+
+ return ret;
+}
+
+static int qcom_snps_eusb2_hsphy_exit(struct phy *p)
+{
+ struct qcom_snps_eusb2_hsphy *phy = phy_get_drvdata(p);
+
+ clk_disable_unprepare(phy->ref_clk);
+
+ regulator_bulk_disable(ARRAY_SIZE(phy->vregs), phy->vregs);
+
+ phy_exit(phy->repeater);
+
+ return 0;
+}
+
+static const struct phy_ops qcom_snps_eusb2_hsphy_ops = {
+ .init = qcom_snps_eusb2_hsphy_init,
+ .exit = qcom_snps_eusb2_hsphy_exit,
+ .set_mode = qcom_snps_eusb2_hsphy_set_mode,
+ .owner = THIS_MODULE,
+};
+
+static int qcom_snps_eusb2_hsphy_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct qcom_snps_eusb2_hsphy *phy;
+ struct phy_provider *phy_provider;
+ struct phy *generic_phy;
+ int ret, i;
+ int num;
+
+ phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
+ if (!phy)
+ return -ENOMEM;
+
+ phy->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(phy->base))
+ return PTR_ERR(phy->base);
+
+ phy->phy_reset = devm_reset_control_get_exclusive(dev, NULL);
+ if (IS_ERR(phy->phy_reset))
+ return PTR_ERR(phy->phy_reset);
+
+ phy->ref_clk = devm_clk_get(dev, "ref");
+ if (IS_ERR(phy->ref_clk))
+ return dev_err_probe(dev, PTR_ERR(phy->ref_clk),
+ "failed to get ref clk\n");
+
+ num = ARRAY_SIZE(phy->vregs);
+ for (i = 0; i < num; i++)
+ phy->vregs[i].supply = eusb2_hsphy_vreg_names[i];
+
+ ret = devm_regulator_bulk_get(dev, num, phy->vregs);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to get regulator supplies\n");
+
+ phy->repeater = devm_of_phy_get_by_index(dev, np, 0);
+ if (IS_ERR(phy->repeater))
+ return dev_err_probe(dev, PTR_ERR(phy->repeater),
+ "failed to get repeater\n");
+
+ generic_phy = devm_phy_create(dev, NULL, &qcom_snps_eusb2_hsphy_ops);
+ if (IS_ERR(generic_phy)) {
+ dev_err(dev, "failed to create phy %d\n", ret);
+ return PTR_ERR(generic_phy);
+ }
+
+ dev_set_drvdata(dev, phy);
+ phy_set_drvdata(generic_phy, phy);
+
+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+ if (IS_ERR(phy_provider))
+ return PTR_ERR(phy_provider);
+
+ dev_info(dev, "Registered Qcom-eUSB2 phy\n");
+
+ return 0;
+}
+
+static const struct of_device_id qcom_snps_eusb2_hsphy_of_match_table[] = {
+ { .compatible = "qcom,sm8550-snps-eusb2-phy", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, qcom_snps_eusb2_hsphy_of_match_table);
+
+static struct platform_driver qcom_snps_eusb2_hsphy_driver = {
+ .probe = qcom_snps_eusb2_hsphy_probe,
+ .driver = {
+ .name = "qcom-snps-eusb2-hsphy",
+ .of_match_table = qcom_snps_eusb2_hsphy_of_match_table,
+ },
+};
+
+module_platform_driver(qcom_snps_eusb2_hsphy_driver);
+MODULE_DESCRIPTION("Qualcomm SNPS eUSB2 HS PHY driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/phy/renesas/r8a779f0-ether-serdes.c b/drivers/phy/renesas/r8a779f0-ether-serdes.c
index e7588a940d69..c5206ef9195b 100644
--- a/drivers/phy/renesas/r8a779f0-ether-serdes.c
+++ b/drivers/phy/renesas/r8a779f0-ether-serdes.c
@@ -18,7 +18,6 @@
#define R8A779F0_ETH_SERDES_BANK_SELECT 0x03fc
#define R8A779F0_ETH_SERDES_TIMEOUT_US 100000
#define R8A779F0_ETH_SERDES_NUM_RETRY_LINKUP 3
-#define R8A779F0_ETH_SERDES_NUM_RETRY_INIT 3
struct r8a779f0_eth_serdes_drv_data;
struct r8a779f0_eth_serdes_channel {
@@ -242,51 +241,46 @@ static int r8a779f0_eth_serdes_hw_init(struct r8a779f0_eth_serdes_channel *chann
if (ret)
return ret;
- ret = r8a779f0_eth_serdes_reg_wait(&dd->channel[0], 0x0000, 0x380, BIT(15), 0);
+ return r8a779f0_eth_serdes_reg_wait(&dd->channel[0], 0x0000, 0x380, BIT(15), 0);
+}
+
+static int r8a779f0_eth_serdes_init(struct phy *p)
+{
+ struct r8a779f0_eth_serdes_channel *channel = phy_get_drvdata(p);
+ int ret;
+
+ ret = r8a779f0_eth_serdes_hw_init(channel);
+ if (!ret)
+ channel->dd->initialized = true;
+
+ return ret;
+}
+
+static int r8a779f0_eth_serdes_hw_init_late(struct r8a779f0_eth_serdes_channel
+*channel)
+{
+ int ret;
+
+ ret = r8a779f0_eth_serdes_chan_setting(channel);
if (ret)
return ret;
- for (i = 0; i < R8A779F0_ETH_SERDES_NUM; i++) {
- ret = r8a779f0_eth_serdes_chan_setting(&dd->channel[i]);
- if (ret)
- return ret;
- }
-
- for (i = 0; i < R8A779F0_ETH_SERDES_NUM; i++) {
- ret = r8a779f0_eth_serdes_chan_speed(&dd->channel[i]);
- if (ret)
- return ret;
- }
+ ret = r8a779f0_eth_serdes_chan_speed(channel);
+ if (ret)
+ return ret;
- for (i = 0; i < R8A779F0_ETH_SERDES_NUM; i++)
- r8a779f0_eth_serdes_write32(dd->channel[i].addr, 0x03c0, 0x380, 0x0000);
- for (i = 0; i < R8A779F0_ETH_SERDES_NUM; i++)
- r8a779f0_eth_serdes_write32(dd->channel[i].addr, 0x03d0, 0x380, 0x0000);
+ r8a779f0_eth_serdes_write32(channel->addr, 0x03c0, 0x380, 0x0000);
- for (i = 0; i < R8A779F0_ETH_SERDES_NUM; i++) {
- ret = r8a779f0_eth_serdes_monitor_linkup(&dd->channel[i]);
- if (ret)
- return ret;
- }
+ r8a779f0_eth_serdes_write32(channel->addr, 0x03d0, 0x380, 0x0000);
- return 0;
+ return r8a779f0_eth_serdes_monitor_linkup(channel);
}
-static int r8a779f0_eth_serdes_init(struct phy *p)
+static int r8a779f0_eth_serdes_power_on(struct phy *p)
{
struct r8a779f0_eth_serdes_channel *channel = phy_get_drvdata(p);
- int i, ret;
- for (i = 0; i < R8A779F0_ETH_SERDES_NUM_RETRY_INIT; i++) {
- ret = r8a779f0_eth_serdes_hw_init(channel);
- if (!ret) {
- channel->dd->initialized = true;
- break;
- }
- usleep_range(1000, 2000);
- }
-
- return ret;
+ return r8a779f0_eth_serdes_hw_init_late(channel);
}
static int r8a779f0_eth_serdes_set_mode(struct phy *p, enum phy_mode mode,
@@ -319,6 +313,7 @@ static int r8a779f0_eth_serdes_set_speed(struct phy *p, int speed)
static const struct phy_ops r8a779f0_eth_serdes_ops = {
.init = r8a779f0_eth_serdes_init,
+ .power_on = r8a779f0_eth_serdes_power_on,
.set_mode = r8a779f0_eth_serdes_set_mode,
.set_speed = r8a779f0_eth_serdes_set_speed,
};
diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c
index d76440ae10ff..39db8acde61a 100644
--- a/drivers/phy/rockchip/phy-rockchip-typec.c
+++ b/drivers/phy/rockchip/phy-rockchip-typec.c
@@ -808,9 +808,8 @@ static int tcphy_get_mode(struct rockchip_typec_phy *tcphy)
struct extcon_dev *edev = tcphy->extcon;
union extcon_property_value property;
unsigned int id;
- bool ufp, dp;
u8 mode;
- int ret;
+ int ret, ufp, dp;
if (!edev)
return MODE_DFP_USB;
@@ -821,10 +820,10 @@ static int tcphy_get_mode(struct rockchip_typec_phy *tcphy)
mode = MODE_DFP_USB;
id = EXTCON_USB_HOST;
- if (ufp) {
+ if (ufp > 0) {
mode = MODE_UFP_USB;
id = EXTCON_USB;
- } else if (dp) {
+ } else if (dp > 0) {
mode = MODE_DFP_DP;
id = EXTCON_DISP_DP;
diff --git a/drivers/phy/samsung/phy-exynos-dp-video.c b/drivers/phy/samsung/phy-exynos-dp-video.c
index 2b670ef91deb..6069fedbd8f3 100644
--- a/drivers/phy/samsung/phy-exynos-dp-video.c
+++ b/drivers/phy/samsung/phy-exynos-dp-video.c
@@ -83,8 +83,11 @@ static int exynos_dp_video_phy_probe(struct platform_device *pdev)
if (!state)
return -ENOMEM;
- state->regs = syscon_regmap_lookup_by_phandle(dev->of_node,
- "samsung,pmu-syscon");
+ state->regs = syscon_node_to_regmap(dev->parent->of_node);
+ if (IS_ERR(state->regs))
+ /* Backwards compatible way */
+ state->regs = syscon_regmap_lookup_by_phandle(dev->of_node,
+ "samsung,pmu-syscon");
if (IS_ERR(state->regs)) {
dev_err(dev, "Failed to lookup PMU regmap\n");
return PTR_ERR(state->regs);
diff --git a/drivers/phy/samsung/phy-exynos-mipi-video.c b/drivers/phy/samsung/phy-exynos-mipi-video.c
index c1df1ef3ee3c..a7f67857e5b2 100644
--- a/drivers/phy/samsung/phy-exynos-mipi-video.c
+++ b/drivers/phy/samsung/phy-exynos-mipi-video.c
@@ -298,7 +298,7 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct phy_provider *phy_provider;
- unsigned int i;
+ unsigned int i = 0;
phy_dev = of_device_get_match_data(dev);
if (!phy_dev)
@@ -308,7 +308,10 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev)
if (!state)
return -ENOMEM;
- for (i = 0; i < phy_dev->num_regmaps; i++) {
+ state->regmaps[i] = syscon_node_to_regmap(dev->parent->of_node);
+ if (!IS_ERR(state->regmaps[i]))
+ i++;
+ for (; i < phy_dev->num_regmaps; i++) {
state->regmaps[i] = syscon_regmap_lookup_by_phandle(np,
phy_dev->regmap_names[i]);
if (IS_ERR(state->regmaps[i]))
diff --git a/drivers/phy/tegra/Makefile b/drivers/phy/tegra/Makefile
index 89b84067cb4c..eeeea72de117 100644
--- a/drivers/phy/tegra/Makefile
+++ b/drivers/phy/tegra/Makefile
@@ -7,4 +7,5 @@ phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_132_SOC) += xusb-tegra124.o
phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_210_SOC) += xusb-tegra210.o
phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_186_SOC) += xusb-tegra186.o
phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_194_SOC) += xusb-tegra186.o
+phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_234_SOC) += xusb-tegra186.o
obj-$(CONFIG_PHY_TEGRA194_P2U) += phy-tegra194-p2u.o
diff --git a/drivers/phy/tegra/xusb-tegra186.c b/drivers/phy/tegra/xusb-tegra186.c
index 6a8bd87cfdbd..1aae8535f452 100644
--- a/drivers/phy/tegra/xusb-tegra186.c
+++ b/drivers/phy/tegra/xusb-tegra186.c
@@ -89,6 +89,11 @@
#define USB2_TRK_START_TIMER(x) (((x) & 0x7f) << 12)
#define USB2_TRK_DONE_RESET_TIMER(x) (((x) & 0x7f) << 19)
#define USB2_PD_TRK BIT(26)
+#define USB2_TRK_COMPLETED BIT(31)
+
+#define XUSB_PADCTL_USB2_BIAS_PAD_CTL2 0x28c
+#define USB2_TRK_HW_MODE BIT(0)
+#define CYA_TRK_CODE_UPDATE_ON_IDLE BIT(31)
#define XUSB_PADCTL_HSIC_PADX_CTL0(x) (0x300 + (x) * 0x20)
#define HSIC_PD_TX_DATA0 BIT(1)
@@ -609,6 +614,32 @@ static void tegra186_utmi_bias_pad_power_on(struct tegra_xusb_padctl *padctl)
value &= ~USB2_PD_TRK;
padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
+ if (padctl->soc->poll_trk_completed) {
+ err = padctl_readl_poll(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1,
+ USB2_TRK_COMPLETED, USB2_TRK_COMPLETED, 100);
+ if (err) {
+ /* The failure with polling on trk complete will not
+ * cause the failure of powering on the bias pad.
+ */
+ dev_warn(dev, "failed to poll USB2 trk completed: %d\n", err);
+ }
+
+ value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
+ value |= USB2_TRK_COMPLETED;
+ padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
+ } else {
+ udelay(100);
+ }
+
+ if (padctl->soc->trk_hw_mode) {
+ value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL2);
+ value |= USB2_TRK_HW_MODE;
+ value &= ~CYA_TRK_CODE_UPDATE_ON_IDLE;
+ padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL2);
+ } else {
+ clk_disable_unprepare(priv->usb2_trk_clk);
+ }
+
mutex_unlock(&padctl->lock);
}
@@ -633,7 +664,12 @@ static void tegra186_utmi_bias_pad_power_off(struct tegra_xusb_padctl *padctl)
value |= USB2_PD_TRK;
padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
- clk_disable_unprepare(priv->usb2_trk_clk);
+ if (padctl->soc->trk_hw_mode) {
+ value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL2);
+ value &= ~USB2_TRK_HW_MODE;
+ padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL2);
+ clk_disable_unprepare(priv->usb2_trk_clk);
+ }
mutex_unlock(&padctl->lock);
}
@@ -1557,7 +1593,8 @@ const struct tegra_xusb_padctl_soc tegra186_xusb_padctl_soc = {
EXPORT_SYMBOL_GPL(tegra186_xusb_padctl_soc);
#endif
-#if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC)
+#if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \
+ IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC)
static const char * const tegra194_xusb_padctl_supply_names[] = {
"avdd-usb",
"vclamp-usb",
@@ -1613,8 +1650,31 @@ const struct tegra_xusb_padctl_soc tegra194_xusb_padctl_soc = {
.supply_names = tegra194_xusb_padctl_supply_names,
.num_supplies = ARRAY_SIZE(tegra194_xusb_padctl_supply_names),
.supports_gen2 = true,
+ .poll_trk_completed = true,
};
EXPORT_SYMBOL_GPL(tegra194_xusb_padctl_soc);
+
+const struct tegra_xusb_padctl_soc tegra234_xusb_padctl_soc = {
+ .num_pads = ARRAY_SIZE(tegra194_pads),
+ .pads = tegra194_pads,
+ .ports = {
+ .usb2 = {
+ .ops = &tegra186_usb2_port_ops,
+ .count = 4,
+ },
+ .usb3 = {
+ .ops = &tegra186_usb3_port_ops,
+ .count = 4,
+ },
+ },
+ .ops = &tegra186_xusb_padctl_ops,
+ .supply_names = tegra194_xusb_padctl_supply_names,
+ .num_supplies = ARRAY_SIZE(tegra194_xusb_padctl_supply_names),
+ .supports_gen2 = true,
+ .poll_trk_completed = true,
+ .trk_hw_mode = true,
+};
+EXPORT_SYMBOL_GPL(tegra234_xusb_padctl_soc);
#endif
MODULE_AUTHOR("JC Kuo <jckuo@nvidia.com>");
diff --git a/drivers/phy/tegra/xusb.c b/drivers/phy/tegra/xusb.c
index ff4b930879f3..78045bd6c214 100644
--- a/drivers/phy/tegra/xusb.c
+++ b/drivers/phy/tegra/xusb.c
@@ -72,6 +72,12 @@ static const struct of_device_id tegra_xusb_padctl_of_match[] = {
.data = &tegra194_xusb_padctl_soc,
},
#endif
+#if defined(CONFIG_ARCH_TEGRA_234_SOC)
+ {
+ .compatible = "nvidia,tegra234-xusb-padctl",
+ .data = &tegra234_xusb_padctl_soc,
+ },
+#endif
{ }
};
MODULE_DEVICE_TABLE(of, tegra_xusb_padctl_of_match);
@@ -712,6 +718,22 @@ static int tegra_xusb_setup_usb_role_switch(struct tegra_xusb_port *port)
return err;
}
+static void tegra_xusb_parse_usb_role_default_mode(struct tegra_xusb_port *port)
+{
+ enum usb_role role = USB_ROLE_NONE;
+ enum usb_dr_mode mode = usb_get_role_switch_default_mode(&port->dev);
+
+ if (mode == USB_DR_MODE_HOST)
+ role = USB_ROLE_HOST;
+ else if (mode == USB_DR_MODE_PERIPHERAL)
+ role = USB_ROLE_DEVICE;
+
+ if (role != USB_ROLE_NONE) {
+ usb_role_switch_set_role(port->usb_role_sw, role);
+ dev_dbg(&port->dev, "usb role default mode is %s", modes[mode]);
+ }
+}
+
static int tegra_xusb_usb2_port_parse_dt(struct tegra_xusb_usb2_port *usb2)
{
struct tegra_xusb_port *port = &usb2->base;
@@ -741,6 +763,7 @@ static int tegra_xusb_usb2_port_parse_dt(struct tegra_xusb_usb2_port *usb2)
err = tegra_xusb_setup_usb_role_switch(port);
if (err < 0)
return err;
+ tegra_xusb_parse_usb_role_default_mode(port);
} else {
dev_err(&port->dev, "usb-role-switch not found for %s mode",
modes[usb2->mode]);
diff --git a/drivers/phy/tegra/xusb.h b/drivers/phy/tegra/xusb.h
index c384734a61c2..8bd6cd281119 100644
--- a/drivers/phy/tegra/xusb.h
+++ b/drivers/phy/tegra/xusb.h
@@ -8,6 +8,7 @@
#define __PHY_TEGRA_XUSB_H
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/mutex.h>
#include <linux/workqueue.h>
@@ -431,6 +432,8 @@ struct tegra_xusb_padctl_soc {
unsigned int num_supplies;
bool supports_gen2;
bool need_fake_usb3_port;
+ bool poll_trk_completed;
+ bool trk_hw_mode;
};
struct tegra_xusb_padctl {
@@ -473,6 +476,23 @@ static inline u32 padctl_readl(struct tegra_xusb_padctl *padctl,
return value;
}
+static inline u32 padctl_readl_poll(struct tegra_xusb_padctl *padctl,
+ unsigned long offset, u32 val, u32 mask,
+ int us)
+{
+ u32 regval;
+ int err;
+
+ err = readl_poll_timeout(padctl->regs + offset, regval,
+ (regval & mask) == val, 1, us);
+ if (err) {
+ dev_err(padctl->dev, "%08lx poll timeout > %08x\n", offset,
+ regval);
+ }
+
+ return err;
+}
+
struct tegra_xusb_lane *tegra_xusb_find_lane(struct tegra_xusb_padctl *padctl,
const char *name,
unsigned int index);
@@ -489,5 +509,8 @@ extern const struct tegra_xusb_padctl_soc tegra186_xusb_padctl_soc;
#if defined(CONFIG_ARCH_TEGRA_194_SOC)
extern const struct tegra_xusb_padctl_soc tegra194_xusb_padctl_soc;
#endif
+#if defined(CONFIG_ARCH_TEGRA_234_SOC)
+extern const struct tegra_xusb_padctl_soc tegra234_xusb_padctl_soc;
+#endif
#endif /* __PHY_TEGRA_XUSB_H */
diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c
index ddce5ef7711c..1b83c98a78f0 100644
--- a/drivers/phy/ti/phy-j721e-wiz.c
+++ b/drivers/phy/ti/phy-j721e-wiz.c
@@ -58,6 +58,14 @@ enum wiz_lane_standard_mode {
LANE_MODE_GEN4,
};
+/*
+ * List of master lanes used for lane swapping
+ */
+enum wiz_typec_master_lane {
+ LANE0 = 0,
+ LANE2 = 2,
+};
+
enum wiz_refclk_mux_sel {
PLL0_REFCLK,
PLL1_REFCLK,
@@ -194,6 +202,9 @@ static const struct reg_field p_mac_div_sel1[WIZ_MAX_LANES] = {
static const struct reg_field typec_ln10_swap =
REG_FIELD(WIZ_SERDES_TYPEC, 30, 30);
+static const struct reg_field typec_ln23_swap =
+ REG_FIELD(WIZ_SERDES_TYPEC, 31, 31);
+
struct wiz_clk_mux {
struct clk_hw hw;
struct regmap_field *field;
@@ -367,6 +378,7 @@ struct wiz {
struct regmap_field *mux_sel_field[WIZ_MUX_NUM_CLOCKS];
struct regmap_field *div_sel_field[WIZ_DIV_NUM_CLOCKS_16G];
struct regmap_field *typec_ln10_swap;
+ struct regmap_field *typec_ln23_swap;
struct regmap_field *sup_legacy_clk_override;
struct device *dev;
@@ -376,6 +388,7 @@ struct wiz {
struct gpio_desc *gpio_typec_dir;
int typec_dir_delay;
u32 lane_phy_type[WIZ_MAX_LANES];
+ u32 master_lane_num[WIZ_MAX_LANES];
struct clk *input_clks[WIZ_MAX_INPUT_CLOCKS];
struct clk *output_clks[WIZ_MAX_OUTPUT_CLOCKS];
struct clk_onecell_data clk_data;
@@ -675,6 +688,13 @@ static int wiz_regfield_init(struct wiz *wiz)
return PTR_ERR(wiz->typec_ln10_swap);
}
+ wiz->typec_ln23_swap = devm_regmap_field_alloc(dev, regmap,
+ typec_ln23_swap);
+ if (IS_ERR(wiz->typec_ln23_swap)) {
+ dev_err(dev, "LN23_SWAP reg field init failed\n");
+ return PTR_ERR(wiz->typec_ln23_swap);
+ }
+
wiz->phy_en_refclk = devm_regmap_field_alloc(dev, regmap, phy_en_refclk);
if (IS_ERR(wiz->phy_en_refclk)) {
dev_err(dev, "PHY_EN_REFCLK reg field init failed\n");
@@ -1234,15 +1254,39 @@ static int wiz_phy_reset_deassert(struct reset_controller_dev *rcdev,
struct wiz *wiz = dev_get_drvdata(dev);
int ret;
- /* if typec-dir gpio was specified, set LN10 SWAP bit based on that */
- if (id == 0 && wiz->gpio_typec_dir) {
- if (wiz->typec_dir_delay)
- msleep_interruptible(wiz->typec_dir_delay);
-
- if (gpiod_get_value_cansleep(wiz->gpio_typec_dir))
- regmap_field_write(wiz->typec_ln10_swap, 1);
- else
- regmap_field_write(wiz->typec_ln10_swap, 0);
+ if (id == 0) {
+ /* if typec-dir gpio was specified, set LN10 SWAP bit based on that */
+ if (wiz->gpio_typec_dir) {
+ if (wiz->typec_dir_delay)
+ msleep_interruptible(wiz->typec_dir_delay);
+
+ if (gpiod_get_value_cansleep(wiz->gpio_typec_dir))
+ regmap_field_write(wiz->typec_ln10_swap, 1);
+ else
+ regmap_field_write(wiz->typec_ln10_swap, 0);
+ } else {
+ /* if no typec-dir gpio is specified and PHY type is USB3
+ * with master lane number is '0' or '2', then set LN10 or
+ * LN23 SWAP bit to '1' respectively.
+ */
+ u32 num_lanes = wiz->num_lanes;
+ int i;
+
+ for (i = 0; i < num_lanes; i++) {
+ if (wiz->lane_phy_type[i] == PHY_TYPE_USB3) {
+ switch (wiz->master_lane_num[i]) {
+ case LANE0:
+ regmap_field_write(wiz->typec_ln10_swap, 1);
+ break;
+ case LANE2:
+ regmap_field_write(wiz->typec_ln23_swap, 1);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
}
if (id == 0) {
@@ -1386,8 +1430,10 @@ static int wiz_get_lane_phy_types(struct device *dev, struct wiz *wiz)
dev_dbg(dev, "%s: Lanes %u-%u have phy-type %u\n", __func__,
reg, reg + num_lanes - 1, phy_type);
- for (i = reg; i < reg + num_lanes; i++)
+ for (i = reg; i < reg + num_lanes; i++) {
+ wiz->master_lane_num[i] = reg;
wiz->lane_phy_type[i] = phy_type;
+ }
}
return 0;
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 7d5f5458c72e..dcb53c4a9584 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -172,7 +172,7 @@ config PINCTRL_DA9062
config PINCTRL_DIGICOLOR
bool
- depends on OF && (ARCH_DIGICOLOR || COMPILE_TEST)
+ depends on ARCH_DIGICOLOR || COMPILE_TEST
select PINMUX
select GENERIC_PINCONF
diff --git a/drivers/pinctrl/bcm/pinctrl-bcm2835.c b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
index 7857e612a100..8e2551a08c37 100644
--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
@@ -358,13 +358,11 @@ static int bcm2835_gpio_direction_output(struct gpio_chip *chip,
return 0;
}
-static int bcm2835_of_gpio_ranges_fallback(struct gpio_chip *gc,
- struct device_node *np)
+static int bcm2835_add_pin_ranges_fallback(struct gpio_chip *gc)
{
+ struct device_node *np = dev_of_node(gc->parent);
struct pinctrl_dev *pctldev = of_pinctrl_get(np);
- of_node_put(np);
-
if (!pctldev)
return 0;
@@ -388,7 +386,7 @@ static const struct gpio_chip bcm2835_gpio_chip = {
.base = -1,
.ngpio = BCM2835_NUM_GPIOS,
.can_sleep = false,
- .of_gpio_ranges_fallback = bcm2835_of_gpio_ranges_fallback,
+ .add_pin_ranges = bcm2835_add_pin_ranges_fallback,
};
static const struct gpio_chip bcm2711_gpio_chip = {
@@ -405,7 +403,7 @@ static const struct gpio_chip bcm2711_gpio_chip = {
.base = -1,
.ngpio = BCM2711_NUM_GPIOS,
.can_sleep = false,
- .of_gpio_ranges_fallback = bcm2835_of_gpio_ranges_fallback,
+ .add_pin_ranges = bcm2835_add_pin_ranges_fallback,
};
static void bcm2835_gpio_irq_handle_bank(struct bcm2835_pinctrl *pc,
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
index 41fd84738707..d6e6c751255f 100644
--- a/drivers/pinctrl/core.c
+++ b/drivers/pinctrl/core.c
@@ -325,7 +325,12 @@ static bool pinctrl_ready_for_gpio_range(unsigned gpio)
{
struct pinctrl_dev *pctldev;
struct pinctrl_gpio_range *range = NULL;
- struct gpio_chip *chip = gpio_to_chip(gpio);
+ /*
+ * FIXME: "gpio" here is a number in the global GPIO numberspace.
+ * get rid of this from the ranges eventually and get the GPIO
+ * descriptor from the gpio_chip.
+ */
+ struct gpio_chip *chip = gpiod_to_chip(gpio_to_desc(gpio));
if (WARN(!chip, "no gpio_chip for gpio%i?", gpio))
return false;
@@ -1657,7 +1662,12 @@ static int pinctrl_pins_show(struct seq_file *s, void *what)
}
}
if (gpio_num >= 0)
- chip = gpio_to_chip(gpio_num);
+ /*
+ * FIXME: gpio_num comes from the global GPIO numberspace.
+ * we need to get rid of the range->base eventually and
+ * get the descriptor directly from the gpio_chip.
+ */
+ chip = gpiod_to_chip(gpio_to_desc(gpio_num));
else
chip = NULL;
if (chip)
diff --git a/drivers/pinctrl/freescale/pinctrl-mxs.c b/drivers/pinctrl/freescale/pinctrl-mxs.c
index 9f78c9b29ddd..cf3f4d2e0c16 100644
--- a/drivers/pinctrl/freescale/pinctrl-mxs.c
+++ b/drivers/pinctrl/freescale/pinctrl-mxs.c
@@ -269,9 +269,9 @@ static int mxs_pinconf_group_set(struct pinctrl_dev *pctldev,
for (n = 0; n < num_configs; n++) {
config = configs[n];
- ma = CONFIG_TO_MA(config);
- vol = CONFIG_TO_VOL(config);
- pull = CONFIG_TO_PULL(config);
+ ma = PIN_CONFIG_TO_MA(config);
+ vol = PIN_CONFIG_TO_VOL(config);
+ pull = PIN_CONFIG_TO_PULL(config);
for (i = 0; i < g->npins; i++) {
bank = PINID_TO_BANK(g->pins[i]);
diff --git a/drivers/pinctrl/freescale/pinctrl-mxs.h b/drivers/pinctrl/freescale/pinctrl-mxs.h
index ab9f834b03e6..5b26511d56aa 100644
--- a/drivers/pinctrl/freescale/pinctrl-mxs.h
+++ b/drivers/pinctrl/freescale/pinctrl-mxs.h
@@ -44,9 +44,9 @@
#define VOL_SHIFT 3
#define MA_PRESENT (1 << 2)
#define MA_SHIFT 0
-#define CONFIG_TO_PULL(c) ((c) >> PULL_SHIFT & 0x1)
-#define CONFIG_TO_VOL(c) ((c) >> VOL_SHIFT & 0x1)
-#define CONFIG_TO_MA(c) ((c) >> MA_SHIFT & 0x3)
+#define PIN_CONFIG_TO_PULL(c) ((c) >> PULL_SHIFT & 0x1)
+#define PIN_CONFIG_TO_VOL(c) ((c) >> VOL_SHIFT & 0x1)
+#define PIN_CONFIG_TO_MA(c) ((c) >> MA_SHIFT & 0x3)
struct mxs_function {
const char *name;
diff --git a/drivers/pinctrl/intel/pinctrl-alderlake.c b/drivers/pinctrl/intel/pinctrl-alderlake.c
index 427febe09b69..55bbfd647ba4 100644
--- a/drivers/pinctrl/intel/pinctrl-alderlake.c
+++ b/drivers/pinctrl/intel/pinctrl-alderlake.c
@@ -34,25 +34,11 @@
.gpio_base = (g), \
}
-#define ADL_COMMUNITY(b, s, e, g, v) \
- { \
- .barno = (b), \
- .padown_offset = ADL_##v##_PAD_OWN, \
- .padcfglock_offset = ADL_##v##_PADCFGLOCK, \
- .hostown_offset = ADL_##v##_HOSTSW_OWN, \
- .is_offset = ADL_##v##_GPI_IS, \
- .ie_offset = ADL_##v##_GPI_IE, \
- .pin_base = (s), \
- .npins = ((e) - (s) + 1), \
- .gpps = (g), \
- .ngpps = ARRAY_SIZE(g), \
- }
-
#define ADL_N_COMMUNITY(b, s, e, g) \
- ADL_COMMUNITY(b, s, e, g, N)
+ INTEL_COMMUNITY_GPPS(b, s, e, g, ADL_N)
#define ADL_S_COMMUNITY(b, s, e, g) \
- ADL_COMMUNITY(b, s, e, g, S)
+ INTEL_COMMUNITY_GPPS(b, s, e, g, ADL_S)
/* Alder Lake-N */
static const struct pinctrl_pin_desc adln_pins[] = {
diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c
index 67db79f38051..770a2723ef81 100644
--- a/drivers/pinctrl/intel/pinctrl-baytrail.c
+++ b/drivers/pinctrl/intel/pinctrl-baytrail.c
@@ -637,18 +637,18 @@ static const char *byt_get_function_name(struct pinctrl_dev *pctldev,
{
struct intel_pinctrl *vg = pinctrl_dev_get_drvdata(pctldev);
- return vg->soc->functions[selector].name;
+ return vg->soc->functions[selector].func.name;
}
static int byt_get_function_groups(struct pinctrl_dev *pctldev,
unsigned int selector,
const char * const **groups,
- unsigned int *num_groups)
+ unsigned int *ngroups)
{
struct intel_pinctrl *vg = pinctrl_dev_get_drvdata(pctldev);
- *groups = vg->soc->functions[selector].groups;
- *num_groups = vg->soc->functions[selector].ngroups;
+ *groups = vg->soc->functions[selector].func.groups;
+ *ngroups = vg->soc->functions[selector].func.ngroups;
return 0;
}
@@ -722,7 +722,7 @@ static int byt_set_mux(struct pinctrl_dev *pctldev, unsigned int func_selector,
if (group.modes)
byt_set_group_mixed_mux(vg, group, group.modes);
- else if (!strcmp(func.name, "gpio"))
+ else if (!strcmp(func.func.name, "gpio"))
byt_set_group_simple_mux(vg, group, BYT_DEFAULT_GPIO_MUX);
else
byt_set_group_simple_mux(vg, group, group.mode);
diff --git a/drivers/pinctrl/intel/pinctrl-broxton.c b/drivers/pinctrl/intel/pinctrl-broxton.c
index fb15cd10a32f..77e921b2178d 100644
--- a/drivers/pinctrl/intel/pinctrl-broxton.c
+++ b/drivers/pinctrl/intel/pinctrl-broxton.c
@@ -20,17 +20,8 @@
#define BXT_GPI_IS 0x100
#define BXT_GPI_IE 0x110
-#define BXT_COMMUNITY(s, e) \
- { \
- .padown_offset = BXT_PAD_OWN, \
- .padcfglock_offset = BXT_PADCFGLOCK, \
- .hostown_offset = BXT_HOSTSW_OWN, \
- .is_offset = BXT_GPI_IS, \
- .ie_offset = BXT_GPI_IE, \
- .gpp_size = 32, \
- .pin_base = (s), \
- .npins = ((e) - (s) + 1), \
- }
+#define BXT_COMMUNITY(b, s, e) \
+ INTEL_COMMUNITY_SIZE(b, s, e, 32, 4, BXT)
/* BXT */
static const struct pinctrl_pin_desc bxt_north_pins[] = {
@@ -172,7 +163,7 @@ static const struct intel_function bxt_north_functions[] = {
};
static const struct intel_community bxt_north_communities[] = {
- BXT_COMMUNITY(0, 82),
+ BXT_COMMUNITY(0, 0, 82),
};
static const struct intel_pinctrl_soc_data bxt_north_soc_data = {
@@ -289,7 +280,7 @@ static const struct intel_function bxt_northwest_functions[] = {
};
static const struct intel_community bxt_northwest_communities[] = {
- BXT_COMMUNITY(0, 71),
+ BXT_COMMUNITY(0, 0, 71),
};
static const struct intel_pinctrl_soc_data bxt_northwest_soc_data = {
@@ -396,7 +387,7 @@ static const struct intel_function bxt_west_functions[] = {
};
static const struct intel_community bxt_west_communities[] = {
- BXT_COMMUNITY(0, 41),
+ BXT_COMMUNITY(0, 0, 41),
};
static const struct intel_pinctrl_soc_data bxt_west_soc_data = {
@@ -472,7 +463,7 @@ static const struct intel_function bxt_southwest_functions[] = {
};
static const struct intel_community bxt_southwest_communities[] = {
- BXT_COMMUNITY(0, 30),
+ BXT_COMMUNITY(0, 0, 30),
};
static const struct intel_pinctrl_soc_data bxt_southwest_soc_data = {
@@ -511,7 +502,7 @@ static const struct pinctrl_pin_desc bxt_south_pins[] = {
};
static const struct intel_community bxt_south_communities[] = {
- BXT_COMMUNITY(0, 19),
+ BXT_COMMUNITY(0, 0, 19),
};
static const struct intel_pinctrl_soc_data bxt_south_soc_data = {
@@ -650,7 +641,7 @@ static const struct intel_function apl_north_functions[] = {
};
static const struct intel_community apl_north_communities[] = {
- BXT_COMMUNITY(0, 77),
+ BXT_COMMUNITY(0, 0, 77),
};
static const struct intel_pinctrl_soc_data apl_north_soc_data = {
@@ -770,7 +761,7 @@ static const struct intel_function apl_northwest_functions[] = {
};
static const struct intel_community apl_northwest_communities[] = {
- BXT_COMMUNITY(0, 76),
+ BXT_COMMUNITY(0, 0, 76),
};
static const struct intel_pinctrl_soc_data apl_northwest_soc_data = {
@@ -880,7 +871,7 @@ static const struct intel_function apl_west_functions[] = {
};
static const struct intel_community apl_west_communities[] = {
- BXT_COMMUNITY(0, 46),
+ BXT_COMMUNITY(0, 0, 46),
};
static const struct intel_pinctrl_soc_data apl_west_soc_data = {
@@ -972,7 +963,7 @@ static const struct intel_function apl_southwest_functions[] = {
};
static const struct intel_community apl_southwest_communities[] = {
- BXT_COMMUNITY(0, 42),
+ BXT_COMMUNITY(0, 0, 42),
};
static const struct intel_pinctrl_soc_data apl_southwest_soc_data = {
diff --git a/drivers/pinctrl/intel/pinctrl-cannonlake.c b/drivers/pinctrl/intel/pinctrl-cannonlake.c
index f8a8b9b14de9..88142ec57b25 100644
--- a/drivers/pinctrl/intel/pinctrl-cannonlake.c
+++ b/drivers/pinctrl/intel/pinctrl-cannonlake.c
@@ -15,12 +15,17 @@
#include "pinctrl-intel.h"
-#define CNL_PAD_OWN 0x020
-#define CNL_PADCFGLOCK 0x080
+#define CNL_LP_PAD_OWN 0x020
+#define CNL_LP_PADCFGLOCK 0x080
#define CNL_LP_HOSTSW_OWN 0x0b0
+#define CNL_LP_GPI_IS 0x100
+#define CNL_LP_GPI_IE 0x120
+
+#define CNL_H_PAD_OWN 0x020
+#define CNL_H_PADCFGLOCK 0x080
#define CNL_H_HOSTSW_OWN 0x0c0
-#define CNL_GPI_IS 0x100
-#define CNL_GPI_IE 0x120
+#define CNL_H_GPI_IS 0x100
+#define CNL_H_GPI_IE 0x120
#define CNL_GPP(r, s, e, g) \
{ \
@@ -30,25 +35,11 @@
.gpio_base = (g), \
}
-#define CNL_COMMUNITY(b, s, e, g, v) \
- { \
- .barno = (b), \
- .padown_offset = CNL_PAD_OWN, \
- .padcfglock_offset = CNL_PADCFGLOCK, \
- .hostown_offset = CNL_##v##_HOSTSW_OWN, \
- .is_offset = CNL_GPI_IS, \
- .ie_offset = CNL_GPI_IE, \
- .pin_base = (s), \
- .npins = ((e) - (s) + 1), \
- .gpps = (g), \
- .ngpps = ARRAY_SIZE(g), \
- }
-
#define CNL_LP_COMMUNITY(b, s, e, g) \
- CNL_COMMUNITY(b, s, e, g, LP)
+ INTEL_COMMUNITY_GPPS(b, s, e, g, CNL_LP)
#define CNL_H_COMMUNITY(b, s, e, g) \
- CNL_COMMUNITY(b, s, e, g, H)
+ INTEL_COMMUNITY_GPPS(b, s, e, g, CNL_H)
/* Cannon Lake-H */
static const struct pinctrl_pin_desc cnlh_pins[] = {
diff --git a/drivers/pinctrl/intel/pinctrl-cedarfork.c b/drivers/pinctrl/intel/pinctrl-cedarfork.c
index aa6f9040d3d8..2ab52b1fbc59 100644
--- a/drivers/pinctrl/intel/pinctrl-cedarfork.c
+++ b/drivers/pinctrl/intel/pinctrl-cedarfork.c
@@ -28,18 +28,7 @@
}
#define CDF_COMMUNITY(b, s, e, g) \
- { \
- .barno = (b), \
- .padown_offset = CDF_PAD_OWN, \
- .padcfglock_offset = CDF_PADCFGLOCK, \
- .hostown_offset = CDF_HOSTSW_OWN, \
- .is_offset = CDF_GPI_IS, \
- .ie_offset = CDF_GPI_IE, \
- .pin_base = (s), \
- .npins = ((e) - (s) + 1), \
- .gpps = (g), \
- .ngpps = ARRAY_SIZE(g), \
- }
+ INTEL_COMMUNITY_GPPS(b, s, e, g, CDF)
/* Cedar Fork PCH */
static const struct pinctrl_pin_desc cdf_pins[] = {
diff --git a/drivers/pinctrl/intel/pinctrl-cherryview.c b/drivers/pinctrl/intel/pinctrl-cherryview.c
index 11b81213922d..722990e27836 100644
--- a/drivers/pinctrl/intel/pinctrl-cherryview.c
+++ b/drivers/pinctrl/intel/pinctrl-cherryview.c
@@ -694,7 +694,7 @@ static const char *chv_get_function_name(struct pinctrl_dev *pctldev,
{
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
- return pctrl->soc->functions[function].name;
+ return pctrl->soc->functions[function].func.name;
}
static int chv_get_function_groups(struct pinctrl_dev *pctldev,
@@ -704,8 +704,8 @@ static int chv_get_function_groups(struct pinctrl_dev *pctldev,
{
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
- *groups = pctrl->soc->functions[function].groups;
- *ngroups = pctrl->soc->functions[function].ngroups;
+ *groups = pctrl->soc->functions[function].func.groups;
+ *ngroups = pctrl->soc->functions[function].func.ngroups;
return 0;
}
diff --git a/drivers/pinctrl/intel/pinctrl-denverton.c b/drivers/pinctrl/intel/pinctrl-denverton.c
index f26d030b9b41..c1a9db091c6e 100644
--- a/drivers/pinctrl/intel/pinctrl-denverton.c
+++ b/drivers/pinctrl/intel/pinctrl-denverton.c
@@ -28,18 +28,7 @@
}
#define DNV_COMMUNITY(b, s, e, g) \
- { \
- .barno = (b), \
- .padown_offset = DNV_PAD_OWN, \
- .padcfglock_offset = DNV_PADCFGLOCK, \
- .hostown_offset = DNV_HOSTSW_OWN, \
- .is_offset = DNV_GPI_IS, \
- .ie_offset = DNV_GPI_IE, \
- .pin_base = (s), \
- .npins = ((e) - (s) + 1), \
- .gpps = (g), \
- .ngpps = ARRAY_SIZE(g), \
- }
+ INTEL_COMMUNITY_GPPS(b, s, e, g, DNV)
/* Denverton */
static const struct pinctrl_pin_desc dnv_pins[] = {
diff --git a/drivers/pinctrl/intel/pinctrl-elkhartlake.c b/drivers/pinctrl/intel/pinctrl-elkhartlake.c
index 4702bdfa10e3..64b1997df0be 100644
--- a/drivers/pinctrl/intel/pinctrl-elkhartlake.c
+++ b/drivers/pinctrl/intel/pinctrl-elkhartlake.c
@@ -27,18 +27,8 @@
.size = ((e) - (s) + 1), \
}
-#define EHL_COMMUNITY(s, e, g) \
- { \
- .padown_offset = EHL_PAD_OWN, \
- .padcfglock_offset = EHL_PADCFGLOCK, \
- .hostown_offset = EHL_HOSTSW_OWN, \
- .is_offset = EHL_GPI_IS, \
- .ie_offset = EHL_GPI_IE, \
- .pin_base = (s), \
- .npins = ((e) - (s) + 1), \
- .gpps = (g), \
- .ngpps = ARRAY_SIZE(g), \
- }
+#define EHL_COMMUNITY(b, s, e, g) \
+ INTEL_COMMUNITY_GPPS(b, s, e, g, EHL)
/* Elkhart Lake */
static const struct pinctrl_pin_desc ehl_community0_pins[] = {
@@ -121,7 +111,7 @@ static const struct intel_padgroup ehl_community0_gpps[] = {
};
static const struct intel_community ehl_community0[] = {
- EHL_COMMUNITY(0, 66, ehl_community0_gpps),
+ EHL_COMMUNITY(0, 0, 66, ehl_community0_gpps),
};
static const struct intel_pinctrl_soc_data ehl_community0_soc_data = {
@@ -262,7 +252,7 @@ static const struct intel_padgroup ehl_community1_gpps[] = {
};
static const struct intel_community ehl_community1[] = {
- EHL_COMMUNITY(0, 112, ehl_community1_gpps),
+ EHL_COMMUNITY(0, 0, 112, ehl_community1_gpps),
};
static const struct intel_pinctrl_soc_data ehl_community1_soc_data = {
@@ -335,7 +325,7 @@ static const struct intel_padgroup ehl_community3_gpps[] = {
};
static const struct intel_community ehl_community3[] = {
- EHL_COMMUNITY(0, 46, ehl_community3_gpps),
+ EHL_COMMUNITY(0, 0, 46, ehl_community3_gpps),
};
static const struct intel_pinctrl_soc_data ehl_community3_soc_data = {
@@ -441,7 +431,7 @@ static const struct intel_padgroup ehl_community4_gpps[] = {
};
static const struct intel_community ehl_community4[] = {
- EHL_COMMUNITY(0, 79, ehl_community4_gpps),
+ EHL_COMMUNITY(0, 0, 79, ehl_community4_gpps),
};
static const struct intel_pinctrl_soc_data ehl_community4_soc_data = {
@@ -469,7 +459,7 @@ static const struct intel_padgroup ehl_community5_gpps[] = {
};
static const struct intel_community ehl_community5[] = {
- EHL_COMMUNITY(0, 7, ehl_community5_gpps),
+ EHL_COMMUNITY(0, 0, 7, ehl_community5_gpps),
};
static const struct intel_pinctrl_soc_data ehl_community5_soc_data = {
diff --git a/drivers/pinctrl/intel/pinctrl-emmitsburg.c b/drivers/pinctrl/intel/pinctrl-emmitsburg.c
index f6114dbf7520..cc8f0baabc91 100644
--- a/drivers/pinctrl/intel/pinctrl-emmitsburg.c
+++ b/drivers/pinctrl/intel/pinctrl-emmitsburg.c
@@ -28,18 +28,7 @@
}
#define EBG_COMMUNITY(b, s, e, g) \
- { \
- .barno = (b), \
- .padown_offset = EBG_PAD_OWN, \
- .padcfglock_offset = EBG_PADCFGLOCK, \
- .hostown_offset = EBG_HOSTSW_OWN, \
- .is_offset = EBG_GPI_IS, \
- .ie_offset = EBG_GPI_IE, \
- .pin_base = (s), \
- .npins = ((e) - (s) + 1), \
- .gpps = (g), \
- .ngpps = ARRAY_SIZE(g), \
- }
+ INTEL_COMMUNITY_GPPS(b, s, e, g, EBG)
/* Emmitsburg */
static const struct pinctrl_pin_desc ebg_pins[] = {
diff --git a/drivers/pinctrl/intel/pinctrl-geminilake.c b/drivers/pinctrl/intel/pinctrl-geminilake.c
index df02028b40f3..918cc9f261cf 100644
--- a/drivers/pinctrl/intel/pinctrl-geminilake.c
+++ b/drivers/pinctrl/intel/pinctrl-geminilake.c
@@ -20,17 +20,8 @@
#define GLK_GPI_IS 0x100
#define GLK_GPI_IE 0x110
-#define GLK_COMMUNITY(s, e) \
- { \
- .padown_offset = GLK_PAD_OWN, \
- .padcfglock_offset = GLK_PADCFGLOCK, \
- .hostown_offset = GLK_HOSTSW_OWN, \
- .is_offset = GLK_GPI_IS, \
- .ie_offset = GLK_GPI_IE, \
- .gpp_size = 32, \
- .pin_base = (s), \
- .npins = ((e) - (s) + 1), \
- }
+#define GLK_COMMUNITY(b, s, e) \
+ INTEL_COMMUNITY_SIZE(b, s, e, 32, 4, GLK)
/* GLK */
static const struct pinctrl_pin_desc glk_northwest_pins[] = {
@@ -173,7 +164,7 @@ static const struct intel_function glk_northwest_functions[] = {
};
static const struct intel_community glk_northwest_communities[] = {
- GLK_COMMUNITY(0, 79),
+ GLK_COMMUNITY(0, 0, 79),
};
static const struct intel_pinctrl_soc_data glk_northwest_soc_data = {
@@ -306,7 +297,7 @@ static const struct intel_function glk_north_functions[] = {
};
static const struct intel_community glk_north_communities[] = {
- GLK_COMMUNITY(0, 79),
+ GLK_COMMUNITY(0, 0, 79),
};
static const struct intel_pinctrl_soc_data glk_north_soc_data = {
@@ -345,7 +336,7 @@ static const struct pinctrl_pin_desc glk_audio_pins[] = {
};
static const struct intel_community glk_audio_communities[] = {
- GLK_COMMUNITY(0, 19),
+ GLK_COMMUNITY(0, 0, 19),
};
static const struct intel_pinctrl_soc_data glk_audio_soc_data = {
@@ -427,7 +418,7 @@ static const struct intel_function glk_scc_functions[] = {
};
static const struct intel_community glk_scc_communities[] = {
- GLK_COMMUNITY(0, 34),
+ GLK_COMMUNITY(0, 0, 34),
};
static const struct intel_pinctrl_soc_data glk_scc_soc_data = {
diff --git a/drivers/pinctrl/intel/pinctrl-icelake.c b/drivers/pinctrl/intel/pinctrl-icelake.c
index 84a56d9ae47e..1c64b4a1c491 100644
--- a/drivers/pinctrl/intel/pinctrl-icelake.c
+++ b/drivers/pinctrl/intel/pinctrl-icelake.c
@@ -15,12 +15,17 @@
#include "pinctrl-intel.h"
-#define ICL_PAD_OWN 0x020
-#define ICL_PADCFGLOCK 0x080
-#define ICL_HOSTSW_OWN 0x0b0
-#define ICL_GPI_IS 0x100
-#define ICL_LP_GPI_IE 0x110
-#define ICL_N_GPI_IE 0x120
+#define ICL_LP_PAD_OWN 0x020
+#define ICL_LP_PADCFGLOCK 0x080
+#define ICL_LP_HOSTSW_OWN 0x0b0
+#define ICL_LP_GPI_IS 0x100
+#define ICL_LP_GPI_IE 0x110
+
+#define ICL_N_PAD_OWN 0x020
+#define ICL_N_PADCFGLOCK 0x080
+#define ICL_N_HOSTSW_OWN 0x0b0
+#define ICL_N_GPI_IS 0x100
+#define ICL_N_GPI_IE 0x120
#define ICL_GPP(r, s, e, g) \
{ \
@@ -30,25 +35,11 @@
.gpio_base = (g), \
}
-#define ICL_COMMUNITY(b, s, e, g, v) \
- { \
- .barno = (b), \
- .padown_offset = ICL_PAD_OWN, \
- .padcfglock_offset = ICL_PADCFGLOCK, \
- .hostown_offset = ICL_HOSTSW_OWN, \
- .is_offset = ICL_GPI_IS, \
- .ie_offset = ICL_##v##_GPI_IE, \
- .pin_base = (s), \
- .npins = ((e) - (s) + 1), \
- .gpps = (g), \
- .ngpps = ARRAY_SIZE(g), \
- }
-
#define ICL_LP_COMMUNITY(b, s, e, g) \
- ICL_COMMUNITY(b, s, e, g, LP)
+ INTEL_COMMUNITY_GPPS(b, s, e, g, ICL_LP)
#define ICL_N_COMMUNITY(b, s, e, g) \
- ICL_COMMUNITY(b, s, e, g, N)
+ INTEL_COMMUNITY_GPPS(b, s, e, g, ICL_N)
/* Ice Lake-LP */
static const struct pinctrl_pin_desc icllp_pins[] = {
diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c
index e49f271de936..c7a71c49df0a 100644
--- a/drivers/pinctrl/intel/pinctrl-intel.c
+++ b/drivers/pinctrl/intel/pinctrl-intel.c
@@ -81,13 +81,16 @@
#define PADCFG1_TERM_MASK GENMASK(12, 10)
#define PADCFG1_TERM_20K BIT(2)
#define PADCFG1_TERM_5K BIT(1)
+#define PADCFG1_TERM_4K (BIT(2) | BIT(1))
#define PADCFG1_TERM_1K BIT(0)
+#define PADCFG1_TERM_952 (BIT(2) | BIT(0))
#define PADCFG1_TERM_833 (BIT(1) | BIT(0))
+#define PADCFG1_TERM_800 (BIT(2) | BIT(1) | BIT(0))
#define PADCFG2 0x008
-#define PADCFG2_DEBEN BIT(0)
#define PADCFG2_DEBOUNCE_SHIFT 1
#define PADCFG2_DEBOUNCE_MASK GENMASK(4, 1)
+#define PADCFG2_DEBEN BIT(0)
#define DEBOUNCE_PERIOD_NSEC 31250
@@ -369,7 +372,7 @@ static const char *intel_get_function_name(struct pinctrl_dev *pctldev,
{
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
- return pctrl->soc->functions[function].name;
+ return pctrl->soc->functions[function].func.name;
}
static int intel_get_function_groups(struct pinctrl_dev *pctldev,
@@ -379,8 +382,8 @@ static int intel_get_function_groups(struct pinctrl_dev *pctldev,
{
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
- *groups = pctrl->soc->functions[function].groups;
- *ngroups = pctrl->soc->functions[function].ngroups;
+ *groups = pctrl->soc->functions[function].func.groups;
+ *ngroups = pctrl->soc->functions[function].func.ngroups;
return 0;
}
@@ -574,6 +577,9 @@ static int intel_config_get_pull(struct intel_pinctrl *pctrl, unsigned int pin,
case PADCFG1_TERM_1K:
*arg = 1000;
break;
+ case PADCFG1_TERM_4K:
+ *arg = 4000;
+ break;
case PADCFG1_TERM_5K:
*arg = 5000;
break;
@@ -599,6 +605,9 @@ static int intel_config_get_pull(struct intel_pinctrl *pctrl, unsigned int pin,
return -EINVAL;
*arg = 1000;
break;
+ case PADCFG1_TERM_4K:
+ *arg = 4000;
+ break;
case PADCFG1_TERM_5K:
*arg = 5000;
break;
@@ -691,21 +700,17 @@ static int intel_config_set_pull(struct intel_pinctrl *pctrl, unsigned int pin,
raw_spin_lock_irqsave(&pctrl->lock, flags);
value = readl(padcfg1);
+ value &= ~(PADCFG1_TERM_MASK | PADCFG1_TERM_UP);
+
+ /* Set default strength value in case none is given */
+ if (arg == 1)
+ arg = 5000;
switch (param) {
case PIN_CONFIG_BIAS_DISABLE:
- value &= ~(PADCFG1_TERM_MASK | PADCFG1_TERM_UP);
break;
case PIN_CONFIG_BIAS_PULL_UP:
- value &= ~PADCFG1_TERM_MASK;
-
- value |= PADCFG1_TERM_UP;
-
- /* Set default strength value in case none is given */
- if (arg == 1)
- arg = 5000;
-
switch (arg) {
case 20000:
value |= PADCFG1_TERM_20K << PADCFG1_TERM_SHIFT;
@@ -713,6 +718,9 @@ static int intel_config_set_pull(struct intel_pinctrl *pctrl, unsigned int pin,
case 5000:
value |= PADCFG1_TERM_5K << PADCFG1_TERM_SHIFT;
break;
+ case 4000:
+ value |= PADCFG1_TERM_4K << PADCFG1_TERM_SHIFT;
+ break;
case 1000:
value |= PADCFG1_TERM_1K << PADCFG1_TERM_SHIFT;
break;
@@ -721,17 +729,13 @@ static int intel_config_set_pull(struct intel_pinctrl *pctrl, unsigned int pin,
break;
default:
ret = -EINVAL;
+ break;
}
+ value |= PADCFG1_TERM_UP;
break;
case PIN_CONFIG_BIAS_PULL_DOWN:
- value &= ~(PADCFG1_TERM_UP | PADCFG1_TERM_MASK);
-
- /* Set default strength value in case none is given */
- if (arg == 1)
- arg = 5000;
-
switch (arg) {
case 20000:
value |= PADCFG1_TERM_20K << PADCFG1_TERM_SHIFT;
@@ -739,6 +743,9 @@ static int intel_config_set_pull(struct intel_pinctrl *pctrl, unsigned int pin,
case 5000:
value |= PADCFG1_TERM_5K << PADCFG1_TERM_SHIFT;
break;
+ case 4000:
+ value |= PADCFG1_TERM_4K << PADCFG1_TERM_SHIFT;
+ break;
case 1000:
if (!(community->features & PINCTRL_FEATURE_1K_PD)) {
ret = -EINVAL;
@@ -755,9 +762,14 @@ static int intel_config_set_pull(struct intel_pinctrl *pctrl, unsigned int pin,
break;
default:
ret = -EINVAL;
+ break;
}
break;
+
+ default:
+ ret = -EINVAL;
+ break;
}
if (!ret)
@@ -1215,13 +1227,8 @@ static int intel_gpio_community_irq_handler(struct intel_pinctrl *pctrl,
/* Only interrupts that are enabled */
pending &= enabled;
- for_each_set_bit(gpp_offset, &pending, padgrp->size) {
- unsigned int irq;
-
- irq = irq_find_mapping(gc->irq.domain,
- padgrp->gpio_base + gpp_offset);
- generic_handle_irq(irq);
- }
+ for_each_set_bit(gpp_offset, &pending, padgrp->size)
+ generic_handle_domain_irq(gc->irq.domain, padgrp->gpio_base + gpp_offset);
ret += pending ? 1 : 0;
}
@@ -1399,7 +1406,7 @@ static int intel_pinctrl_add_padgroups_by_gpps(struct intel_pinctrl *pctrl,
for (i = 0; i < ngpps; i++) {
gpps[i] = community->gpps[i];
- if (gpps[i].size > 32)
+ if (gpps[i].size > INTEL_PINCTRL_MAX_GPP_SIZE)
return -EINVAL;
/* Special treatment for GPIO base */
@@ -1417,7 +1424,7 @@ static int intel_pinctrl_add_padgroups_by_gpps(struct intel_pinctrl *pctrl,
}
gpps[i].padown_num = padown_num;
- padown_num += DIV_ROUND_UP(gpps[i].size * 4, 32);
+ padown_num += DIV_ROUND_UP(gpps[i].size * 4, INTEL_PINCTRL_MAX_GPP_SIZE);
}
community->gpps = gpps;
@@ -1433,7 +1440,7 @@ static int intel_pinctrl_add_padgroups_by_size(struct intel_pinctrl *pctrl,
unsigned int padown_num = 0;
size_t i, ngpps = DIV_ROUND_UP(npins, community->gpp_size);
- if (community->gpp_size > 32)
+ if (community->gpp_size > INTEL_PINCTRL_MAX_GPP_SIZE)
return -EINVAL;
gpps = devm_kcalloc(pctrl->dev, ngpps, sizeof(*gpps), GFP_KERNEL);
@@ -1451,14 +1458,7 @@ static int intel_pinctrl_add_padgroups_by_size(struct intel_pinctrl *pctrl,
gpps[i].gpio_base = gpps[i].base;
gpps[i].padown_num = padown_num;
- /*
- * In older hardware the number of padown registers per
- * group is fixed regardless of the group size.
- */
- if (community->gpp_num_padown_regs)
- padown_num += community->gpp_num_padown_regs;
- else
- padown_num += DIV_ROUND_UP(gpps[i].size * 4, 32);
+ padown_num += community->gpp_num_padown_regs;
}
community->ngpps = ngpps;
diff --git a/drivers/pinctrl/intel/pinctrl-intel.h b/drivers/pinctrl/intel/pinctrl-intel.h
index 65628423bf63..1faf2ada480a 100644
--- a/drivers/pinctrl/intel/pinctrl-intel.h
+++ b/drivers/pinctrl/intel/pinctrl-intel.h
@@ -36,21 +36,19 @@ struct intel_pingroup {
/**
* struct intel_function - Description about a function
- * @name: Name of the function
- * @groups: An array of groups for this function
- * @ngroups: Number of groups in @groups
+ * @func: Generic data of the pin function (name and groups of pins)
*/
struct intel_function {
- const char *name;
- const char * const *groups;
- size_t ngroups;
+ struct pinfunction func;
};
+#define INTEL_PINCTRL_MAX_GPP_SIZE 32
+
/**
* struct intel_padgroup - Hardware pad group information
* @reg_num: GPI_IS register number
* @base: Starting pin of this group
- * @size: Size of this group (maximum is 32).
+ * @size: Size of this group (maximum is %INTEL_PINCTRL_MAX_GPP_SIZE).
* @gpio_base: Starting GPIO base of this group
* @padown_num: PAD_OWN register number (assigned by the core driver)
*
@@ -96,8 +94,7 @@ enum {
* @gpp_size: Maximum number of pads in each group, such as PADCFGLOCK,
* HOSTSW_OWN, GPI_IS, GPI_IE. Used when @gpps is %NULL.
* @gpp_num_padown_regs: Number of pad registers each pad group consumes at
- * minimum. Use %0 if the number of registers can be
- * determined by the size of the group.
+ * minimum. Used when @gpps is %NULL.
* @gpps: Pad groups if the controller has variable size pad groups
* @ngpps: Number of pad groups in this community
* @pad_map: Optional non-linear mapping of the pads
@@ -106,11 +103,13 @@ enum {
* @regs: Community specific common registers (reserved for core driver)
* @pad_regs: Community specific pad registers (reserved for core driver)
*
- * In some of Intel GPIO host controllers this driver supports each pad group
+ * In older Intel GPIO host controllers, this driver supports, each pad group
* is of equal size (except the last one). In that case the driver can just
- * fill in @gpp_size field and let the core driver to handle the rest. If
- * the controller has pad groups of variable size the client driver can
- * pass custom @gpps and @ngpps instead.
+ * fill in @gpp_size and @gpp_num_padown_regs fields and let the core driver
+ * to handle the rest.
+ *
+ * In newer Intel GPIO host controllers each pad group is of variable size,
+ * so the client driver can pass custom @gpps and @ngpps instead.
*/
struct intel_community {
unsigned int barno;
@@ -143,6 +142,28 @@ struct intel_community {
#define PINCTRL_FEATURE_BLINK BIT(4)
#define PINCTRL_FEATURE_EXP BIT(5)
+#define __INTEL_COMMUNITY(b, s, e, g, n, gs, gn, soc) \
+ { \
+ .barno = (b), \
+ .padown_offset = soc ## _PAD_OWN, \
+ .padcfglock_offset = soc ## _PADCFGLOCK, \
+ .hostown_offset = soc ## _HOSTSW_OWN, \
+ .is_offset = soc ## _GPI_IS, \
+ .ie_offset = soc ## _GPI_IE, \
+ .gpp_size = (gs), \
+ .gpp_num_padown_regs = (gn), \
+ .pin_base = (s), \
+ .npins = ((e) - (s) + 1), \
+ .gpps = (g), \
+ .ngpps = (n), \
+ }
+
+#define INTEL_COMMUNITY_GPPS(b, s, e, g, soc) \
+ __INTEL_COMMUNITY(b, s, e, g, ARRAY_SIZE(g), 0, 0, soc)
+
+#define INTEL_COMMUNITY_SIZE(b, s, e, gs, gn, soc) \
+ __INTEL_COMMUNITY(b, s, e, NULL, 0, gs, gn, soc)
+
/**
* PIN_GROUP - Declare a pin group
* @n: Name of the group
@@ -158,11 +179,9 @@ struct intel_community {
.modes = __builtin_choose_expr(__builtin_constant_p((m)), NULL, (m)), \
}
-#define FUNCTION(n, g) \
- { \
- .name = (n), \
- .groups = (g), \
- .ngroups = ARRAY_SIZE((g)), \
+#define FUNCTION(n, g) \
+ { \
+ .func = PINCTRL_PINFUNCTION((n), (g), ARRAY_SIZE(g)), \
}
/**
diff --git a/drivers/pinctrl/intel/pinctrl-jasperlake.c b/drivers/pinctrl/intel/pinctrl-jasperlake.c
index ec435b7ab392..086ab7fe08dd 100644
--- a/drivers/pinctrl/intel/pinctrl-jasperlake.c
+++ b/drivers/pinctrl/intel/pinctrl-jasperlake.c
@@ -29,18 +29,7 @@
}
#define JSL_COMMUNITY(b, s, e, g) \
- { \
- .barno = (b), \
- .padown_offset = JSL_PAD_OWN, \
- .padcfglock_offset = JSL_PADCFGLOCK, \
- .hostown_offset = JSL_HOSTSW_OWN, \
- .is_offset = JSL_GPI_IS, \
- .ie_offset = JSL_GPI_IE, \
- .pin_base = (s), \
- .npins = ((e) - (s) + 1), \
- .gpps = (g), \
- .ngpps = ARRAY_SIZE(g), \
- }
+ INTEL_COMMUNITY_GPPS(b, s, e, g, JSL)
/* Jasper Lake */
static const struct pinctrl_pin_desc jsl_pins[] = {
diff --git a/drivers/pinctrl/intel/pinctrl-lakefield.c b/drivers/pinctrl/intel/pinctrl-lakefield.c
index 3c6283c4827f..8dac2d6012b1 100644
--- a/drivers/pinctrl/intel/pinctrl-lakefield.c
+++ b/drivers/pinctrl/intel/pinctrl-lakefield.c
@@ -29,18 +29,7 @@
}
#define LKF_COMMUNITY(b, s, e, g) \
- { \
- .barno = (b), \
- .padown_offset = LKF_PAD_OWN, \
- .padcfglock_offset = LKF_PADCFGLOCK, \
- .hostown_offset = LKF_HOSTSW_OWN, \
- .is_offset = LKF_GPI_IS, \
- .ie_offset = LKF_GPI_IE, \
- .pin_base = (s), \
- .npins = ((e) - (s) + 1), \
- .gpps = (g), \
- .ngpps = ARRAY_SIZE(g), \
- }
+ INTEL_COMMUNITY_GPPS(b, s, e, g, LKF)
/* Lakefield */
static const struct pinctrl_pin_desc lkf_pins[] = {
diff --git a/drivers/pinctrl/intel/pinctrl-lewisburg.c b/drivers/pinctrl/intel/pinctrl-lewisburg.c
index ad4b446d588e..7aac1bbde2e9 100644
--- a/drivers/pinctrl/intel/pinctrl-lewisburg.c
+++ b/drivers/pinctrl/intel/pinctrl-lewisburg.c
@@ -21,17 +21,7 @@
#define LBG_GPI_IE 0x110
#define LBG_COMMUNITY(b, s, e) \
- { \
- .barno = (b), \
- .padown_offset = LBG_PAD_OWN, \
- .padcfglock_offset = LBG_PADCFGLOCK, \
- .hostown_offset = LBG_HOSTSW_OWN, \
- .is_offset = LBG_GPI_IS, \
- .ie_offset = LBG_GPI_IE, \
- .gpp_size = 24, \
- .pin_base = (s), \
- .npins = ((e) - (s) + 1), \
- }
+ INTEL_COMMUNITY_SIZE(b, s, e, 24, 3, LBG)
/* Lewisburg */
static const struct pinctrl_pin_desc lbg_pins[] = {
diff --git a/drivers/pinctrl/intel/pinctrl-lynxpoint.c b/drivers/pinctrl/intel/pinctrl-lynxpoint.c
index 8d05dad38556..cdace55aaeac 100644
--- a/drivers/pinctrl/intel/pinctrl-lynxpoint.c
+++ b/drivers/pinctrl/intel/pinctrl-lynxpoint.c
@@ -341,18 +341,18 @@ static const char *lp_get_function_name(struct pinctrl_dev *pctldev,
{
struct intel_pinctrl *lg = pinctrl_dev_get_drvdata(pctldev);
- return lg->soc->functions[selector].name;
+ return lg->soc->functions[selector].func.name;
}
static int lp_get_function_groups(struct pinctrl_dev *pctldev,
unsigned int selector,
const char * const **groups,
- unsigned int *num_groups)
+ unsigned int *ngroups)
{
struct intel_pinctrl *lg = pinctrl_dev_get_drvdata(pctldev);
- *groups = lg->soc->functions[selector].groups;
- *num_groups = lg->soc->functions[selector].ngroups;
+ *groups = lg->soc->functions[selector].func.groups;
+ *ngroups = lg->soc->functions[selector].func.ngroups;
return 0;
}
diff --git a/drivers/pinctrl/intel/pinctrl-merrifield.c b/drivers/pinctrl/intel/pinctrl-merrifield.c
index c0845bb1e9e3..365c391c97a3 100644
--- a/drivers/pinctrl/intel/pinctrl-merrifield.c
+++ b/drivers/pinctrl/intel/pinctrl-merrifield.c
@@ -576,7 +576,7 @@ static const char *mrfld_get_function_name(struct pinctrl_dev *pctldev,
{
struct mrfld_pinctrl *mp = pinctrl_dev_get_drvdata(pctldev);
- return mp->functions[function].name;
+ return mp->functions[function].func.name;
}
static int mrfld_get_function_groups(struct pinctrl_dev *pctldev,
@@ -586,8 +586,8 @@ static int mrfld_get_function_groups(struct pinctrl_dev *pctldev,
{
struct mrfld_pinctrl *mp = pinctrl_dev_get_drvdata(pctldev);
- *groups = mp->functions[function].groups;
- *ngroups = mp->functions[function].ngroups;
+ *groups = mp->functions[function].func.groups;
+ *ngroups = mp->functions[function].func.ngroups;
return 0;
}
diff --git a/drivers/pinctrl/intel/pinctrl-meteorlake.c b/drivers/pinctrl/intel/pinctrl-meteorlake.c
index 9576dcd1cb29..a82f6754c45b 100644
--- a/drivers/pinctrl/intel/pinctrl-meteorlake.c
+++ b/drivers/pinctrl/intel/pinctrl-meteorlake.c
@@ -14,11 +14,11 @@
#include "pinctrl-intel.h"
-#define MTL_PAD_OWN 0x0b0
-#define MTL_PADCFGLOCK 0x110
-#define MTL_HOSTSW_OWN 0x140
-#define MTL_GPI_IS 0x200
-#define MTL_GPI_IE 0x210
+#define MTL_P_PAD_OWN 0x0b0
+#define MTL_P_PADCFGLOCK 0x110
+#define MTL_P_HOSTSW_OWN 0x140
+#define MTL_P_GPI_IS 0x200
+#define MTL_P_GPI_IE 0x210
#define MTL_GPP(r, s, e, g) \
{ \
@@ -29,18 +29,7 @@
}
#define MTL_COMMUNITY(b, s, e, g) \
- { \
- .barno = (b), \
- .padown_offset = MTL_PAD_OWN, \
- .padcfglock_offset = MTL_PADCFGLOCK, \
- .hostown_offset = MTL_HOSTSW_OWN, \
- .is_offset = MTL_GPI_IS, \
- .ie_offset = MTL_GPI_IE, \
- .pin_base = (s), \
- .npins = ((e) - (s) + 1), \
- .gpps = (g), \
- .ngpps = ARRAY_SIZE(g), \
- }
+ INTEL_COMMUNITY_GPPS(b, s, e, g, MTL_P)
/* Meteor Lake-P */
static const struct pinctrl_pin_desc mtlp_pins[] = {
diff --git a/drivers/pinctrl/intel/pinctrl-moorefield.c b/drivers/pinctrl/intel/pinctrl-moorefield.c
index e3eec671e15d..3c9a8484b442 100644
--- a/drivers/pinctrl/intel/pinctrl-moorefield.c
+++ b/drivers/pinctrl/intel/pinctrl-moorefield.c
@@ -530,7 +530,7 @@ static const char *mofld_get_function_name(struct pinctrl_dev *pctldev, unsigned
{
struct mofld_pinctrl *mp = pinctrl_dev_get_drvdata(pctldev);
- return mp->functions[function].name;
+ return mp->functions[function].func.name;
}
static int mofld_get_function_groups(struct pinctrl_dev *pctldev, unsigned int function,
@@ -538,8 +538,8 @@ static int mofld_get_function_groups(struct pinctrl_dev *pctldev, unsigned int f
{
struct mofld_pinctrl *mp = pinctrl_dev_get_drvdata(pctldev);
- *groups = mp->functions[function].groups;
- *ngroups = mp->functions[function].ngroups;
+ *groups = mp->functions[function].func.groups;
+ *ngroups = mp->functions[function].func.ngroups;
return 0;
}
diff --git a/drivers/pinctrl/intel/pinctrl-sunrisepoint.c b/drivers/pinctrl/intel/pinctrl-sunrisepoint.c
index 292b660067e9..f91e27feb7c3 100644
--- a/drivers/pinctrl/intel/pinctrl-sunrisepoint.c
+++ b/drivers/pinctrl/intel/pinctrl-sunrisepoint.c
@@ -15,31 +15,17 @@
#include "pinctrl-intel.h"
-#define SPT_PAD_OWN 0x020
+#define SPT_H_PAD_OWN 0x020
#define SPT_H_PADCFGLOCK 0x090
-#define SPT_LP_PADCFGLOCK 0x0a0
-#define SPT_HOSTSW_OWN 0x0d0
-#define SPT_GPI_IS 0x100
-#define SPT_GPI_IE 0x120
-
-#define SPT_COMMUNITY(b, s, e, g, n, v, gs, gn) \
- { \
- .barno = (b), \
- .padown_offset = SPT_PAD_OWN, \
- .padcfglock_offset = SPT_##v##_PADCFGLOCK, \
- .hostown_offset = SPT_HOSTSW_OWN, \
- .is_offset = SPT_GPI_IS, \
- .ie_offset = SPT_GPI_IE, \
- .gpp_size = (gs), \
- .gpp_num_padown_regs = (gn), \
- .pin_base = (s), \
- .npins = ((e) - (s) + 1), \
- .gpps = (g), \
- .ngpps = (n), \
- }
+#define SPT_H_HOSTSW_OWN 0x0d0
+#define SPT_H_GPI_IS 0x100
+#define SPT_H_GPI_IE 0x120
-#define SPT_LP_COMMUNITY(b, s, e) \
- SPT_COMMUNITY(b, s, e, NULL, 0, LP, 24, 4)
+#define SPT_LP_PAD_OWN 0x020
+#define SPT_LP_PADCFGLOCK 0x0a0
+#define SPT_LP_HOSTSW_OWN 0x0d0
+#define SPT_LP_GPI_IS 0x100
+#define SPT_LP_GPI_IE 0x120
#define SPT_H_GPP(r, s, e, g) \
{ \
@@ -50,7 +36,10 @@
}
#define SPT_H_COMMUNITY(b, s, e, g) \
- SPT_COMMUNITY(b, s, e, g, ARRAY_SIZE(g), H, 0, 0)
+ INTEL_COMMUNITY_GPPS(b, s, e, g, SPT_H)
+
+#define SPT_LP_COMMUNITY(b, s, e) \
+ INTEL_COMMUNITY_SIZE(b, s, e, 24, 4, SPT_LP)
/* Sunrisepoint-LP */
static const struct pinctrl_pin_desc sptlp_pins[] = {
diff --git a/drivers/pinctrl/intel/pinctrl-tigerlake.c b/drivers/pinctrl/intel/pinctrl-tigerlake.c
index 431352fa2ab5..6e3a651d1241 100644
--- a/drivers/pinctrl/intel/pinctrl-tigerlake.c
+++ b/drivers/pinctrl/intel/pinctrl-tigerlake.c
@@ -15,13 +15,17 @@
#include "pinctrl-intel.h"
-#define TGL_PAD_OWN 0x020
+#define TGL_LP_PAD_OWN 0x020
#define TGL_LP_PADCFGLOCK 0x080
-#define TGL_H_PADCFGLOCK 0x090
#define TGL_LP_HOSTSW_OWN 0x0b0
+#define TGL_LP_GPI_IS 0x100
+#define TGL_LP_GPI_IE 0x120
+
+#define TGL_H_PAD_OWN 0x020
+#define TGL_H_PADCFGLOCK 0x090
#define TGL_H_HOSTSW_OWN 0x0c0
-#define TGL_GPI_IS 0x100
-#define TGL_GPI_IE 0x120
+#define TGL_H_GPI_IS 0x100
+#define TGL_H_GPI_IE 0x120
#define TGL_GPP(r, s, e, g) \
{ \
@@ -31,25 +35,11 @@
.gpio_base = (g), \
}
-#define TGL_COMMUNITY(b, s, e, g, v) \
- { \
- .barno = (b), \
- .padown_offset = TGL_PAD_OWN, \
- .padcfglock_offset = TGL_##v##_PADCFGLOCK, \
- .hostown_offset = TGL_##v##_HOSTSW_OWN, \
- .is_offset = TGL_GPI_IS, \
- .ie_offset = TGL_GPI_IE, \
- .pin_base = (s), \
- .npins = ((e) - (s) + 1), \
- .gpps = (g), \
- .ngpps = ARRAY_SIZE(g), \
- }
-
#define TGL_LP_COMMUNITY(b, s, e, g) \
- TGL_COMMUNITY(b, s, e, g, LP)
+ INTEL_COMMUNITY_GPPS(b, s, e, g, TGL_LP)
#define TGL_H_COMMUNITY(b, s, e, g) \
- TGL_COMMUNITY(b, s, e, g, H)
+ INTEL_COMMUNITY_GPPS(b, s, e, g, TGL_H)
/* Tiger Lake-LP */
static const struct pinctrl_pin_desc tgllp_pins[] = {
diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig
index fed02c6fea06..f20c28334bcb 100644
--- a/drivers/pinctrl/mediatek/Kconfig
+++ b/drivers/pinctrl/mediatek/Kconfig
@@ -127,6 +127,11 @@ config PINCTRL_MT7622
default ARM64 && ARCH_MEDIATEK
select PINCTRL_MTK_MOORE
+config PINCTRL_MT7981
+ bool "Mediatek MT7981 pin control"
+ depends on OF
+ select PINCTRL_MTK_MOORE
+
config PINCTRL_MT7986
bool "Mediatek MT7986 pin control"
depends on OF
diff --git a/drivers/pinctrl/mediatek/Makefile b/drivers/pinctrl/mediatek/Makefile
index 53265404a39d..44d197af516a 100644
--- a/drivers/pinctrl/mediatek/Makefile
+++ b/drivers/pinctrl/mediatek/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_PINCTRL_MT6797) += pinctrl-mt6797.o
obj-$(CONFIG_PINCTRL_MT7622) += pinctrl-mt7622.o
obj-$(CONFIG_PINCTRL_MT7623) += pinctrl-mt7623.o
obj-$(CONFIG_PINCTRL_MT7629) += pinctrl-mt7629.o
+obj-$(CONFIG_PINCTRL_MT7981) += pinctrl-mt7981.o
obj-$(CONFIG_PINCTRL_MT7986) += pinctrl-mt7986.o
obj-$(CONFIG_PINCTRL_MT8167) += pinctrl-mt8167.o
obj-$(CONFIG_PINCTRL_MT8173) += pinctrl-mt8173.o
diff --git a/drivers/pinctrl/mediatek/pinctrl-moore.c b/drivers/pinctrl/mediatek/pinctrl-moore.c
index 1ec0413959e1..007b98ce5631 100644
--- a/drivers/pinctrl/mediatek/pinctrl-moore.c
+++ b/drivers/pinctrl/mediatek/pinctrl-moore.c
@@ -574,7 +574,6 @@ static int mtk_build_gpiochip(struct mtk_pinctrl *hw)
chip->set_config = mtk_gpio_set_config;
chip->base = -1;
chip->ngpio = hw->soc->npins;
- chip->of_gpio_n_cells = 2;
ret = gpiochip_add_data(chip, hw);
if (ret < 0)
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7981.c b/drivers/pinctrl/mediatek/pinctrl-mt7981.c
new file mode 100644
index 000000000000..18abc5780011
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-mt7981.c
@@ -0,0 +1,1048 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * The MT7981 driver based on Linux generic pinctrl binding.
+ *
+ * Copyright (C) 2020 MediaTek Inc.
+ * Author: Sam Shih <sam.shih@mediatek.com>
+ */
+
+#include "pinctrl-moore.h"
+
+#define MT7981_PIN(_number, _name) \
+ MTK_PIN(_number, _name, 0, _number, DRV_GRP4)
+
+#define PIN_FIELD_BASE(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, _x_bits) \
+ PIN_FIELD_CALC(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, \
+ _x_bits, 32, 0)
+
+#define PINS_FIELD_BASE(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, _x_bits) \
+ PIN_FIELD_CALC(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, \
+ _x_bits, 32, 1)
+
+static const struct mtk_pin_field_calc mt7981_pin_mode_range[] = {
+ PIN_FIELD(0, 56, 0x300, 0x10, 0, 4),
+};
+
+static const struct mtk_pin_field_calc mt7981_pin_dir_range[] = {
+ PIN_FIELD(0, 56, 0x0, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7981_pin_di_range[] = {
+ PIN_FIELD(0, 56, 0x200, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7981_pin_do_range[] = {
+ PIN_FIELD(0, 56, 0x100, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7981_pin_ies_range[] = {
+ PIN_FIELD_BASE(0, 0, 1, 0x10, 0x10, 1, 1),
+ PIN_FIELD_BASE(1, 1, 1, 0x10, 0x10, 0, 1),
+ PIN_FIELD_BASE(2, 2, 5, 0x20, 0x10, 6, 1),
+ PIN_FIELD_BASE(3, 3, 4, 0x20, 0x10, 6, 1),
+ PIN_FIELD_BASE(4, 4, 4, 0x20, 0x10, 2, 1),
+ PIN_FIELD_BASE(5, 5, 4, 0x20, 0x10, 1, 1),
+ PIN_FIELD_BASE(6, 6, 4, 0x20, 0x10, 3, 1),
+ PIN_FIELD_BASE(7, 7, 4, 0x20, 0x10, 0, 1),
+ PIN_FIELD_BASE(8, 8, 4, 0x20, 0x10, 4, 1),
+
+ PIN_FIELD_BASE(9, 9, 5, 0x20, 0x10, 9, 1),
+ PIN_FIELD_BASE(10, 10, 5, 0x20, 0x10, 8, 1),
+ PIN_FIELD_BASE(11, 11, 5, 0x40, 0x10, 10, 1),
+ PIN_FIELD_BASE(12, 12, 5, 0x20, 0x10, 7, 1),
+ PIN_FIELD_BASE(13, 13, 5, 0x20, 0x10, 11, 1),
+
+ PIN_FIELD_BASE(14, 14, 4, 0x20, 0x10, 8, 1),
+
+ PIN_FIELD_BASE(15, 15, 2, 0x20, 0x10, 0, 1),
+ PIN_FIELD_BASE(16, 16, 2, 0x20, 0x10, 1, 1),
+ PIN_FIELD_BASE(17, 17, 2, 0x20, 0x10, 5, 1),
+ PIN_FIELD_BASE(18, 18, 2, 0x20, 0x10, 4, 1),
+ PIN_FIELD_BASE(19, 19, 2, 0x20, 0x10, 2, 1),
+ PIN_FIELD_BASE(20, 20, 2, 0x20, 0x10, 3, 1),
+ PIN_FIELD_BASE(21, 21, 2, 0x20, 0x10, 6, 1),
+ PIN_FIELD_BASE(22, 22, 2, 0x20, 0x10, 7, 1),
+ PIN_FIELD_BASE(23, 23, 2, 0x20, 0x10, 10, 1),
+ PIN_FIELD_BASE(24, 24, 2, 0x20, 0x10, 9, 1),
+ PIN_FIELD_BASE(25, 25, 2, 0x20, 0x10, 8, 1),
+
+ PIN_FIELD_BASE(26, 26, 5, 0x20, 0x10, 0, 1),
+ PIN_FIELD_BASE(27, 27, 5, 0x20, 0x10, 4, 1),
+ PIN_FIELD_BASE(28, 28, 5, 0x20, 0x10, 3, 1),
+ PIN_FIELD_BASE(29, 29, 5, 0x20, 0x10, 1, 1),
+ PIN_FIELD_BASE(30, 30, 5, 0x20, 0x10, 2, 1),
+ PIN_FIELD_BASE(31, 31, 5, 0x20, 0x10, 5, 1),
+
+ PIN_FIELD_BASE(32, 32, 1, 0x10, 0x10, 2, 1),
+ PIN_FIELD_BASE(33, 33, 1, 0x10, 0x10, 3, 1),
+
+ PIN_FIELD_BASE(34, 34, 4, 0x20, 0x10, 5, 1),
+ PIN_FIELD_BASE(35, 35, 4, 0x20, 0x10, 7, 1),
+
+ PIN_FIELD_BASE(36, 36, 3, 0x10, 0x10, 2, 1),
+ PIN_FIELD_BASE(37, 37, 3, 0x10, 0x10, 3, 1),
+ PIN_FIELD_BASE(38, 38, 3, 0x10, 0x10, 0, 1),
+ PIN_FIELD_BASE(39, 39, 3, 0x10, 0x10, 1, 1),
+
+ PIN_FIELD_BASE(40, 40, 7, 0x30, 0x10, 1, 1),
+ PIN_FIELD_BASE(41, 41, 7, 0x30, 0x10, 0, 1),
+ PIN_FIELD_BASE(42, 42, 7, 0x30, 0x10, 9, 1),
+ PIN_FIELD_BASE(43, 43, 7, 0x30, 0x10, 7, 1),
+ PIN_FIELD_BASE(44, 44, 7, 0x30, 0x10, 8, 1),
+ PIN_FIELD_BASE(45, 45, 7, 0x30, 0x10, 3, 1),
+ PIN_FIELD_BASE(46, 46, 7, 0x30, 0x10, 4, 1),
+ PIN_FIELD_BASE(47, 47, 7, 0x30, 0x10, 5, 1),
+ PIN_FIELD_BASE(48, 48, 7, 0x30, 0x10, 6, 1),
+ PIN_FIELD_BASE(49, 49, 7, 0x30, 0x10, 2, 1),
+
+ PIN_FIELD_BASE(50, 50, 6, 0x10, 0x10, 0, 1),
+ PIN_FIELD_BASE(51, 51, 6, 0x10, 0x10, 2, 1),
+ PIN_FIELD_BASE(52, 52, 6, 0x10, 0x10, 3, 1),
+ PIN_FIELD_BASE(53, 53, 6, 0x10, 0x10, 4, 1),
+ PIN_FIELD_BASE(54, 54, 6, 0x10, 0x10, 5, 1),
+ PIN_FIELD_BASE(55, 55, 6, 0x10, 0x10, 6, 1),
+ PIN_FIELD_BASE(56, 56, 6, 0x10, 0x10, 1, 1),
+};
+
+static const struct mtk_pin_field_calc mt7981_pin_smt_range[] = {
+ PIN_FIELD_BASE(0, 0, 1, 0x60, 0x10, 1, 1),
+ PIN_FIELD_BASE(1, 1, 1, 0x60, 0x10, 0, 1),
+ PIN_FIELD_BASE(2, 2, 5, 0x90, 0x10, 6, 1),
+ PIN_FIELD_BASE(3, 3, 4, 0x80, 0x10, 6, 1),
+ PIN_FIELD_BASE(4, 4, 4, 0x80, 0x10, 2, 1),
+ PIN_FIELD_BASE(5, 5, 4, 0x80, 0x10, 1, 1),
+ PIN_FIELD_BASE(6, 6, 4, 0x80, 0x10, 3, 1),
+ PIN_FIELD_BASE(7, 7, 4, 0x80, 0x10, 0, 1),
+ PIN_FIELD_BASE(8, 8, 4, 0x80, 0x10, 4, 1),
+
+ PIN_FIELD_BASE(9, 9, 5, 0x90, 0x10, 9, 1),
+ PIN_FIELD_BASE(10, 10, 5, 0x90, 0x10, 8, 1),
+ PIN_FIELD_BASE(11, 11, 5, 0x90, 0x10, 10, 1),
+ PIN_FIELD_BASE(12, 12, 5, 0x90, 0x10, 7, 1),
+ PIN_FIELD_BASE(13, 13, 5, 0x90, 0x10, 11, 1),
+
+ PIN_FIELD_BASE(14, 14, 4, 0x80, 0x10, 8, 1),
+
+ PIN_FIELD_BASE(15, 15, 2, 0x90, 0x10, 0, 1),
+ PIN_FIELD_BASE(16, 16, 2, 0x90, 0x10, 1, 1),
+ PIN_FIELD_BASE(17, 17, 2, 0x90, 0x10, 5, 1),
+ PIN_FIELD_BASE(18, 18, 2, 0x90, 0x10, 4, 1),
+ PIN_FIELD_BASE(19, 19, 2, 0x90, 0x10, 2, 1),
+ PIN_FIELD_BASE(20, 20, 2, 0x90, 0x10, 3, 1),
+ PIN_FIELD_BASE(21, 21, 2, 0x90, 0x10, 6, 1),
+ PIN_FIELD_BASE(22, 22, 2, 0x90, 0x10, 7, 1),
+ PIN_FIELD_BASE(23, 23, 2, 0x90, 0x10, 10, 1),
+ PIN_FIELD_BASE(24, 24, 2, 0x90, 0x10, 9, 1),
+ PIN_FIELD_BASE(25, 25, 2, 0x90, 0x10, 8, 1),
+
+ PIN_FIELD_BASE(26, 26, 5, 0x90, 0x10, 0, 1),
+ PIN_FIELD_BASE(27, 27, 5, 0x90, 0x10, 4, 1),
+ PIN_FIELD_BASE(28, 28, 5, 0x90, 0x10, 3, 1),
+ PIN_FIELD_BASE(29, 29, 5, 0x90, 0x10, 1, 1),
+ PIN_FIELD_BASE(30, 30, 5, 0x90, 0x10, 2, 1),
+ PIN_FIELD_BASE(31, 31, 5, 0x90, 0x10, 5, 1),
+
+ PIN_FIELD_BASE(32, 32, 1, 0x60, 0x10, 2, 1),
+ PIN_FIELD_BASE(33, 33, 1, 0x60, 0x10, 3, 1),
+
+ PIN_FIELD_BASE(34, 34, 4, 0x80, 0x10, 5, 1),
+ PIN_FIELD_BASE(35, 35, 4, 0x80, 0x10, 7, 1),
+
+ PIN_FIELD_BASE(36, 36, 3, 0x60, 0x10, 2, 1),
+ PIN_FIELD_BASE(37, 37, 3, 0x60, 0x10, 3, 1),
+ PIN_FIELD_BASE(38, 38, 3, 0x60, 0x10, 0, 1),
+ PIN_FIELD_BASE(39, 39, 3, 0x60, 0x10, 1, 1),
+
+ PIN_FIELD_BASE(40, 40, 7, 0x70, 0x10, 1, 1),
+ PIN_FIELD_BASE(41, 41, 7, 0x70, 0x10, 0, 1),
+ PIN_FIELD_BASE(42, 42, 7, 0x70, 0x10, 9, 1),
+ PIN_FIELD_BASE(43, 43, 7, 0x70, 0x10, 7, 1),
+ PIN_FIELD_BASE(44, 44, 7, 0x30, 0x10, 8, 1),
+ PIN_FIELD_BASE(45, 45, 7, 0x70, 0x10, 3, 1),
+ PIN_FIELD_BASE(46, 46, 7, 0x70, 0x10, 4, 1),
+ PIN_FIELD_BASE(47, 47, 7, 0x70, 0x10, 5, 1),
+ PIN_FIELD_BASE(48, 48, 7, 0x70, 0x10, 6, 1),
+ PIN_FIELD_BASE(49, 49, 7, 0x70, 0x10, 2, 1),
+
+ PIN_FIELD_BASE(50, 50, 6, 0x50, 0x10, 0, 1),
+ PIN_FIELD_BASE(51, 51, 6, 0x50, 0x10, 2, 1),
+ PIN_FIELD_BASE(52, 52, 6, 0x50, 0x10, 3, 1),
+ PIN_FIELD_BASE(53, 53, 6, 0x50, 0x10, 4, 1),
+ PIN_FIELD_BASE(54, 54, 6, 0x50, 0x10, 5, 1),
+ PIN_FIELD_BASE(55, 55, 6, 0x50, 0x10, 6, 1),
+ PIN_FIELD_BASE(56, 56, 6, 0x50, 0x10, 1, 1),
+};
+
+static const struct mtk_pin_field_calc mt7981_pin_pu_range[] = {
+ PIN_FIELD_BASE(40, 40, 7, 0x50, 0x10, 1, 1),
+ PIN_FIELD_BASE(41, 41, 7, 0x50, 0x10, 0, 1),
+ PIN_FIELD_BASE(42, 42, 7, 0x50, 0x10, 9, 1),
+ PIN_FIELD_BASE(43, 43, 7, 0x50, 0x10, 7, 1),
+ PIN_FIELD_BASE(44, 44, 7, 0x50, 0x10, 8, 1),
+ PIN_FIELD_BASE(45, 45, 7, 0x50, 0x10, 3, 1),
+ PIN_FIELD_BASE(46, 46, 7, 0x50, 0x10, 4, 1),
+ PIN_FIELD_BASE(47, 47, 7, 0x50, 0x10, 5, 1),
+ PIN_FIELD_BASE(48, 48, 7, 0x50, 0x10, 6, 1),
+ PIN_FIELD_BASE(49, 49, 7, 0x50, 0x10, 2, 1),
+
+ PIN_FIELD_BASE(50, 50, 6, 0x30, 0x10, 0, 1),
+ PIN_FIELD_BASE(51, 51, 6, 0x30, 0x10, 2, 1),
+ PIN_FIELD_BASE(52, 52, 6, 0x30, 0x10, 3, 1),
+ PIN_FIELD_BASE(53, 53, 6, 0x30, 0x10, 4, 1),
+ PIN_FIELD_BASE(54, 54, 6, 0x30, 0x10, 5, 1),
+ PIN_FIELD_BASE(55, 55, 6, 0x30, 0x10, 6, 1),
+ PIN_FIELD_BASE(56, 56, 6, 0x30, 0x10, 1, 1),
+};
+
+static const struct mtk_pin_field_calc mt7981_pin_pd_range[] = {
+ PIN_FIELD_BASE(40, 40, 7, 0x40, 0x10, 1, 1),
+ PIN_FIELD_BASE(41, 41, 7, 0x40, 0x10, 0, 1),
+ PIN_FIELD_BASE(42, 42, 7, 0x40, 0x10, 9, 1),
+ PIN_FIELD_BASE(43, 43, 7, 0x40, 0x10, 7, 1),
+ PIN_FIELD_BASE(44, 44, 7, 0x40, 0x10, 8, 1),
+ PIN_FIELD_BASE(45, 45, 7, 0x40, 0x10, 3, 1),
+ PIN_FIELD_BASE(46, 46, 7, 0x40, 0x10, 4, 1),
+ PIN_FIELD_BASE(47, 47, 7, 0x40, 0x10, 5, 1),
+ PIN_FIELD_BASE(48, 48, 7, 0x40, 0x10, 6, 1),
+ PIN_FIELD_BASE(49, 49, 7, 0x40, 0x10, 2, 1),
+
+ PIN_FIELD_BASE(50, 50, 6, 0x20, 0x10, 0, 1),
+ PIN_FIELD_BASE(51, 51, 6, 0x20, 0x10, 2, 1),
+ PIN_FIELD_BASE(52, 52, 6, 0x20, 0x10, 3, 1),
+ PIN_FIELD_BASE(53, 53, 6, 0x20, 0x10, 4, 1),
+ PIN_FIELD_BASE(54, 54, 6, 0x20, 0x10, 5, 1),
+ PIN_FIELD_BASE(55, 55, 6, 0x20, 0x10, 6, 1),
+ PIN_FIELD_BASE(56, 56, 6, 0x20, 0x10, 1, 1),
+};
+
+static const struct mtk_pin_field_calc mt7981_pin_drv_range[] = {
+ PIN_FIELD_BASE(0, 0, 1, 0x00, 0x10, 3, 3),
+ PIN_FIELD_BASE(1, 1, 1, 0x00, 0x10, 0, 3),
+
+ PIN_FIELD_BASE(2, 2, 5, 0x00, 0x10, 18, 3),
+
+ PIN_FIELD_BASE(3, 3, 4, 0x00, 0x10, 18, 1),
+ PIN_FIELD_BASE(4, 4, 4, 0x00, 0x10, 6, 1),
+ PIN_FIELD_BASE(5, 5, 4, 0x00, 0x10, 3, 3),
+ PIN_FIELD_BASE(6, 6, 4, 0x00, 0x10, 9, 3),
+ PIN_FIELD_BASE(7, 7, 4, 0x00, 0x10, 0, 3),
+ PIN_FIELD_BASE(8, 8, 4, 0x00, 0x10, 12, 3),
+
+ PIN_FIELD_BASE(9, 9, 5, 0x00, 0x10, 27, 3),
+ PIN_FIELD_BASE(10, 10, 5, 0x00, 0x10, 24, 3),
+ PIN_FIELD_BASE(11, 11, 5, 0x00, 0x10, 0, 3),
+ PIN_FIELD_BASE(12, 12, 5, 0x00, 0x10, 21, 3),
+ PIN_FIELD_BASE(13, 13, 5, 0x00, 0x10, 3, 3),
+
+ PIN_FIELD_BASE(14, 14, 4, 0x00, 0x10, 27, 3),
+
+ PIN_FIELD_BASE(15, 15, 2, 0x00, 0x10, 0, 3),
+ PIN_FIELD_BASE(16, 16, 2, 0x00, 0x10, 3, 3),
+ PIN_FIELD_BASE(17, 17, 2, 0x00, 0x10, 15, 3),
+ PIN_FIELD_BASE(18, 18, 2, 0x00, 0x10, 12, 3),
+ PIN_FIELD_BASE(19, 19, 2, 0x00, 0x10, 6, 3),
+ PIN_FIELD_BASE(20, 20, 2, 0x00, 0x10, 9, 3),
+ PIN_FIELD_BASE(21, 21, 2, 0x00, 0x10, 18, 3),
+ PIN_FIELD_BASE(22, 22, 2, 0x00, 0x10, 21, 3),
+ PIN_FIELD_BASE(23, 23, 2, 0x00, 0x10, 0, 3),
+ PIN_FIELD_BASE(24, 24, 2, 0x00, 0x10, 27, 3),
+ PIN_FIELD_BASE(25, 25, 2, 0x00, 0x10, 24, 3),
+
+ PIN_FIELD_BASE(26, 26, 5, 0x00, 0x10, 0, 3),
+ PIN_FIELD_BASE(27, 27, 5, 0x00, 0x10, 12, 3),
+ PIN_FIELD_BASE(28, 28, 5, 0x00, 0x10, 9, 3),
+ PIN_FIELD_BASE(29, 29, 5, 0x00, 0x10, 3, 3),
+ PIN_FIELD_BASE(30, 30, 5, 0x00, 0x10, 6, 3),
+ PIN_FIELD_BASE(31, 31, 5, 0x00, 0x10, 15, 3),
+
+ PIN_FIELD_BASE(32, 32, 1, 0x00, 0x10, 9, 3),
+ PIN_FIELD_BASE(33, 33, 1, 0x00, 0x10, 12, 3),
+
+ PIN_FIELD_BASE(34, 34, 4, 0x00, 0x10, 15, 3),
+ PIN_FIELD_BASE(35, 35, 4, 0x00, 0x10, 21, 3),
+
+ PIN_FIELD_BASE(36, 36, 3, 0x00, 0x10, 6, 3),
+ PIN_FIELD_BASE(37, 37, 3, 0x00, 0x10, 9, 3),
+ PIN_FIELD_BASE(38, 38, 3, 0x00, 0x10, 0, 3),
+ PIN_FIELD_BASE(39, 39, 3, 0x00, 0x10, 3, 3),
+
+ PIN_FIELD_BASE(40, 40, 7, 0x00, 0x10, 3, 3),
+ PIN_FIELD_BASE(41, 41, 7, 0x00, 0x10, 0, 3),
+ PIN_FIELD_BASE(42, 42, 7, 0x00, 0x10, 27, 3),
+ PIN_FIELD_BASE(43, 43, 7, 0x00, 0x10, 21, 3),
+ PIN_FIELD_BASE(44, 44, 7, 0x00, 0x10, 24, 3),
+ PIN_FIELD_BASE(45, 45, 7, 0x00, 0x10, 9, 3),
+ PIN_FIELD_BASE(46, 46, 7, 0x00, 0x10, 12, 3),
+ PIN_FIELD_BASE(47, 47, 7, 0x00, 0x10, 15, 3),
+ PIN_FIELD_BASE(48, 48, 7, 0x00, 0x10, 18, 3),
+ PIN_FIELD_BASE(49, 49, 7, 0x00, 0x10, 6, 3),
+
+ PIN_FIELD_BASE(50, 50, 6, 0x00, 0x10, 0, 3),
+ PIN_FIELD_BASE(51, 51, 6, 0x00, 0x10, 6, 3),
+ PIN_FIELD_BASE(52, 52, 6, 0x00, 0x10, 9, 3),
+ PIN_FIELD_BASE(53, 53, 6, 0x00, 0x10, 12, 3),
+ PIN_FIELD_BASE(54, 54, 6, 0x00, 0x10, 15, 3),
+ PIN_FIELD_BASE(55, 55, 6, 0x00, 0x10, 18, 3),
+ PIN_FIELD_BASE(56, 56, 6, 0x00, 0x10, 3, 3),
+};
+
+static const struct mtk_pin_field_calc mt7981_pin_pupd_range[] = {
+ PIN_FIELD_BASE(0, 0, 1, 0x20, 0x10, 1, 1),
+ PIN_FIELD_BASE(1, 1, 1, 0x20, 0x10, 0, 1),
+ PIN_FIELD_BASE(2, 2, 5, 0x30, 0x10, 6, 1),
+ PIN_FIELD_BASE(3, 3, 4, 0x30, 0x10, 6, 1),
+ PIN_FIELD_BASE(4, 4, 4, 0x30, 0x10, 2, 1),
+ PIN_FIELD_BASE(5, 5, 4, 0x30, 0x10, 1, 1),
+ PIN_FIELD_BASE(6, 6, 4, 0x30, 0x10, 3, 1),
+ PIN_FIELD_BASE(7, 7, 4, 0x30, 0x10, 0, 1),
+ PIN_FIELD_BASE(8, 8, 4, 0x30, 0x10, 4, 1),
+
+ PIN_FIELD_BASE(9, 9, 5, 0x30, 0x10, 9, 1),
+ PIN_FIELD_BASE(10, 10, 5, 0x30, 0x10, 8, 1),
+ PIN_FIELD_BASE(11, 11, 5, 0x30, 0x10, 10, 1),
+ PIN_FIELD_BASE(12, 12, 5, 0x30, 0x10, 7, 1),
+ PIN_FIELD_BASE(13, 13, 5, 0x30, 0x10, 11, 1),
+
+ PIN_FIELD_BASE(14, 14, 4, 0x30, 0x10, 8, 1),
+
+ PIN_FIELD_BASE(15, 15, 2, 0x30, 0x10, 0, 1),
+ PIN_FIELD_BASE(16, 16, 2, 0x30, 0x10, 1, 1),
+ PIN_FIELD_BASE(17, 17, 2, 0x30, 0x10, 5, 1),
+ PIN_FIELD_BASE(18, 18, 2, 0x30, 0x10, 4, 1),
+ PIN_FIELD_BASE(19, 19, 2, 0x30, 0x10, 2, 1),
+ PIN_FIELD_BASE(20, 20, 2, 0x90, 0x10, 3, 1),
+ PIN_FIELD_BASE(21, 21, 2, 0x30, 0x10, 6, 1),
+ PIN_FIELD_BASE(22, 22, 2, 0x30, 0x10, 7, 1),
+ PIN_FIELD_BASE(23, 23, 2, 0x30, 0x10, 10, 1),
+ PIN_FIELD_BASE(24, 24, 2, 0x30, 0x10, 9, 1),
+ PIN_FIELD_BASE(25, 25, 2, 0x30, 0x10, 8, 1),
+
+ PIN_FIELD_BASE(26, 26, 5, 0x30, 0x10, 0, 1),
+ PIN_FIELD_BASE(27, 27, 5, 0x30, 0x10, 4, 1),
+ PIN_FIELD_BASE(28, 28, 5, 0x30, 0x10, 3, 1),
+ PIN_FIELD_BASE(29, 29, 5, 0x30, 0x10, 1, 1),
+ PIN_FIELD_BASE(30, 30, 5, 0x30, 0x10, 2, 1),
+ PIN_FIELD_BASE(31, 31, 5, 0x30, 0x10, 5, 1),
+
+ PIN_FIELD_BASE(32, 32, 1, 0x20, 0x10, 2, 1),
+ PIN_FIELD_BASE(33, 33, 1, 0x20, 0x10, 3, 1),
+
+ PIN_FIELD_BASE(34, 34, 4, 0x30, 0x10, 5, 1),
+ PIN_FIELD_BASE(35, 35, 4, 0x30, 0x10, 7, 1),
+
+ PIN_FIELD_BASE(36, 36, 3, 0x20, 0x10, 2, 1),
+ PIN_FIELD_BASE(37, 37, 3, 0x20, 0x10, 3, 1),
+ PIN_FIELD_BASE(38, 38, 3, 0x20, 0x10, 0, 1),
+ PIN_FIELD_BASE(39, 39, 3, 0x20, 0x10, 1, 1),
+};
+
+static const struct mtk_pin_field_calc mt7981_pin_r0_range[] = {
+ PIN_FIELD_BASE(0, 0, 1, 0x30, 0x10, 1, 1),
+ PIN_FIELD_BASE(1, 1, 1, 0x30, 0x10, 0, 1),
+ PIN_FIELD_BASE(2, 2, 5, 0x40, 0x10, 6, 1),
+ PIN_FIELD_BASE(3, 3, 4, 0x40, 0x10, 6, 1),
+ PIN_FIELD_BASE(4, 4, 4, 0x40, 0x10, 2, 1),
+ PIN_FIELD_BASE(5, 5, 4, 0x40, 0x10, 1, 1),
+ PIN_FIELD_BASE(6, 6, 4, 0x40, 0x10, 3, 1),
+ PIN_FIELD_BASE(7, 7, 4, 0x40, 0x10, 0, 1),
+ PIN_FIELD_BASE(8, 8, 4, 0x40, 0x10, 4, 1),
+
+ PIN_FIELD_BASE(9, 9, 5, 0x40, 0x10, 9, 1),
+ PIN_FIELD_BASE(10, 10, 5, 0x40, 0x10, 8, 1),
+ PIN_FIELD_BASE(11, 11, 5, 0x40, 0x10, 10, 1),
+ PIN_FIELD_BASE(12, 12, 5, 0x40, 0x10, 7, 1),
+ PIN_FIELD_BASE(13, 13, 5, 0x40, 0x10, 11, 1),
+
+ PIN_FIELD_BASE(14, 14, 4, 0x40, 0x10, 8, 1),
+
+ PIN_FIELD_BASE(15, 15, 2, 0x40, 0x10, 0, 1),
+ PIN_FIELD_BASE(16, 16, 2, 0x40, 0x10, 1, 1),
+ PIN_FIELD_BASE(17, 17, 2, 0x40, 0x10, 5, 1),
+ PIN_FIELD_BASE(18, 18, 2, 0x40, 0x10, 4, 1),
+ PIN_FIELD_BASE(19, 19, 2, 0x40, 0x10, 2, 1),
+ PIN_FIELD_BASE(20, 20, 2, 0x40, 0x10, 3, 1),
+ PIN_FIELD_BASE(21, 21, 2, 0x40, 0x10, 6, 1),
+ PIN_FIELD_BASE(22, 22, 2, 0x40, 0x10, 7, 1),
+ PIN_FIELD_BASE(23, 23, 2, 0x40, 0x10, 10, 1),
+ PIN_FIELD_BASE(24, 24, 2, 0x40, 0x10, 9, 1),
+ PIN_FIELD_BASE(25, 25, 2, 0x40, 0x10, 8, 1),
+
+ PIN_FIELD_BASE(26, 26, 5, 0x40, 0x10, 0, 1),
+ PIN_FIELD_BASE(27, 27, 5, 0x40, 0x10, 4, 1),
+ PIN_FIELD_BASE(28, 28, 5, 0x40, 0x10, 3, 1),
+ PIN_FIELD_BASE(29, 29, 5, 0x40, 0x10, 1, 1),
+ PIN_FIELD_BASE(30, 30, 5, 0x40, 0x10, 2, 1),
+ PIN_FIELD_BASE(31, 31, 5, 0x40, 0x10, 5, 1),
+
+ PIN_FIELD_BASE(32, 32, 1, 0x30, 0x10, 2, 1),
+ PIN_FIELD_BASE(33, 33, 1, 0x30, 0x10, 3, 1),
+
+ PIN_FIELD_BASE(34, 34, 4, 0x40, 0x10, 5, 1),
+ PIN_FIELD_BASE(35, 35, 4, 0x40, 0x10, 7, 1),
+
+ PIN_FIELD_BASE(36, 36, 3, 0x30, 0x10, 2, 1),
+ PIN_FIELD_BASE(37, 37, 3, 0x30, 0x10, 3, 1),
+ PIN_FIELD_BASE(38, 38, 3, 0x30, 0x10, 0, 1),
+ PIN_FIELD_BASE(39, 39, 3, 0x30, 0x10, 1, 1),
+};
+
+static const struct mtk_pin_field_calc mt7981_pin_r1_range[] = {
+ PIN_FIELD_BASE(0, 0, 1, 0x40, 0x10, 1, 1),
+ PIN_FIELD_BASE(1, 1, 1, 0x40, 0x10, 0, 1),
+ PIN_FIELD_BASE(2, 2, 5, 0x50, 0x10, 6, 1),
+ PIN_FIELD_BASE(3, 3, 4, 0x50, 0x10, 6, 1),
+ PIN_FIELD_BASE(4, 4, 4, 0x50, 0x10, 2, 1),
+ PIN_FIELD_BASE(5, 5, 4, 0x50, 0x10, 1, 1),
+ PIN_FIELD_BASE(6, 6, 4, 0x50, 0x10, 3, 1),
+ PIN_FIELD_BASE(7, 7, 4, 0x50, 0x10, 0, 1),
+ PIN_FIELD_BASE(8, 8, 4, 0x50, 0x10, 4, 1),
+
+ PIN_FIELD_BASE(9, 9, 5, 0x50, 0x10, 9, 1),
+ PIN_FIELD_BASE(10, 10, 5, 0x50, 0x10, 8, 1),
+ PIN_FIELD_BASE(11, 11, 5, 0x50, 0x10, 10, 1),
+ PIN_FIELD_BASE(12, 12, 5, 0x50, 0x10, 7, 1),
+ PIN_FIELD_BASE(13, 13, 5, 0x50, 0x10, 11, 1),
+
+ PIN_FIELD_BASE(14, 14, 4, 0x50, 0x10, 8, 1),
+
+ PIN_FIELD_BASE(15, 15, 2, 0x50, 0x10, 0, 1),
+ PIN_FIELD_BASE(16, 16, 2, 0x50, 0x10, 1, 1),
+ PIN_FIELD_BASE(17, 17, 2, 0x50, 0x10, 5, 1),
+ PIN_FIELD_BASE(18, 18, 2, 0x50, 0x10, 4, 1),
+ PIN_FIELD_BASE(19, 19, 2, 0x50, 0x10, 2, 1),
+ PIN_FIELD_BASE(20, 20, 2, 0x50, 0x10, 3, 1),
+ PIN_FIELD_BASE(21, 21, 2, 0x50, 0x10, 6, 1),
+ PIN_FIELD_BASE(22, 22, 2, 0x50, 0x10, 7, 1),
+ PIN_FIELD_BASE(23, 23, 2, 0x50, 0x10, 10, 1),
+ PIN_FIELD_BASE(24, 24, 2, 0x50, 0x10, 9, 1),
+ PIN_FIELD_BASE(25, 25, 2, 0x50, 0x10, 8, 1),
+
+ PIN_FIELD_BASE(26, 26, 5, 0x50, 0x10, 0, 1),
+ PIN_FIELD_BASE(27, 27, 5, 0x50, 0x10, 4, 1),
+ PIN_FIELD_BASE(28, 28, 5, 0x50, 0x10, 3, 1),
+ PIN_FIELD_BASE(29, 29, 5, 0x50, 0x10, 1, 1),
+ PIN_FIELD_BASE(30, 30, 5, 0x50, 0x10, 2, 1),
+ PIN_FIELD_BASE(31, 31, 5, 0x50, 0x10, 5, 1),
+
+ PIN_FIELD_BASE(32, 32, 1, 0x40, 0x10, 2, 1),
+ PIN_FIELD_BASE(33, 33, 1, 0x40, 0x10, 3, 1),
+
+ PIN_FIELD_BASE(34, 34, 4, 0x50, 0x10, 5, 1),
+ PIN_FIELD_BASE(35, 35, 4, 0x50, 0x10, 7, 1),
+
+ PIN_FIELD_BASE(36, 36, 3, 0x40, 0x10, 2, 1),
+ PIN_FIELD_BASE(37, 37, 3, 0x40, 0x10, 3, 1),
+ PIN_FIELD_BASE(38, 38, 3, 0x40, 0x10, 0, 1),
+ PIN_FIELD_BASE(39, 39, 3, 0x40, 0x10, 1, 1),
+};
+
+static const unsigned int mt7981_pull_type[] = {
+ MTK_PULL_PUPD_R1R0_TYPE,/*0*/ MTK_PULL_PUPD_R1R0_TYPE,/*1*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*2*/ MTK_PULL_PUPD_R1R0_TYPE,/*3*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*4*/ MTK_PULL_PUPD_R1R0_TYPE,/*5*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*6*/ MTK_PULL_PUPD_R1R0_TYPE,/*7*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*8*/ MTK_PULL_PUPD_R1R0_TYPE,/*9*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*10*/ MTK_PULL_PUPD_R1R0_TYPE,/*11*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*12*/ MTK_PULL_PUPD_R1R0_TYPE,/*13*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*14*/ MTK_PULL_PUPD_R1R0_TYPE,/*15*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*16*/ MTK_PULL_PUPD_R1R0_TYPE,/*17*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*18*/ MTK_PULL_PUPD_R1R0_TYPE,/*19*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*20*/ MTK_PULL_PUPD_R1R0_TYPE,/*21*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*22*/ MTK_PULL_PUPD_R1R0_TYPE,/*23*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*24*/ MTK_PULL_PUPD_R1R0_TYPE,/*25*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*26*/ MTK_PULL_PUPD_R1R0_TYPE,/*27*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*28*/ MTK_PULL_PUPD_R1R0_TYPE,/*29*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*30*/ MTK_PULL_PUPD_R1R0_TYPE,/*31*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*32*/ MTK_PULL_PUPD_R1R0_TYPE,/*33*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*34*/ MTK_PULL_PUPD_R1R0_TYPE,/*35*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*36*/ MTK_PULL_PUPD_R1R0_TYPE,/*37*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*38*/ MTK_PULL_PUPD_R1R0_TYPE,/*39*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*40*/ MTK_PULL_PUPD_R1R0_TYPE,/*41*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*42*/ MTK_PULL_PUPD_R1R0_TYPE,/*43*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*44*/ MTK_PULL_PUPD_R1R0_TYPE,/*45*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*46*/ MTK_PULL_PUPD_R1R0_TYPE,/*47*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*48*/ MTK_PULL_PUPD_R1R0_TYPE,/*49*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*50*/ MTK_PULL_PUPD_R1R0_TYPE,/*51*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*52*/ MTK_PULL_PUPD_R1R0_TYPE,/*53*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*54*/ MTK_PULL_PUPD_R1R0_TYPE,/*55*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*56*/ MTK_PULL_PUPD_R1R0_TYPE,/*57*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*58*/ MTK_PULL_PUPD_R1R0_TYPE,/*59*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*60*/ MTK_PULL_PUPD_R1R0_TYPE,/*61*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*62*/ MTK_PULL_PUPD_R1R0_TYPE,/*63*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*64*/ MTK_PULL_PUPD_R1R0_TYPE,/*65*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*66*/ MTK_PULL_PUPD_R1R0_TYPE,/*67*/
+ MTK_PULL_PUPD_R1R0_TYPE,/*68*/ MTK_PULL_PU_PD_TYPE,/*69*/
+ MTK_PULL_PU_PD_TYPE,/*70*/ MTK_PULL_PU_PD_TYPE,/*71*/
+ MTK_PULL_PU_PD_TYPE,/*72*/ MTK_PULL_PU_PD_TYPE,/*73*/
+ MTK_PULL_PU_PD_TYPE,/*74*/ MTK_PULL_PU_PD_TYPE,/*75*/
+ MTK_PULL_PU_PD_TYPE,/*76*/ MTK_PULL_PU_PD_TYPE,/*77*/
+ MTK_PULL_PU_PD_TYPE,/*78*/ MTK_PULL_PU_PD_TYPE,/*79*/
+ MTK_PULL_PU_PD_TYPE,/*80*/ MTK_PULL_PU_PD_TYPE,/*81*/
+ MTK_PULL_PU_PD_TYPE,/*82*/ MTK_PULL_PU_PD_TYPE,/*83*/
+ MTK_PULL_PU_PD_TYPE,/*84*/ MTK_PULL_PU_PD_TYPE,/*85*/
+ MTK_PULL_PU_PD_TYPE,/*86*/ MTK_PULL_PU_PD_TYPE,/*87*/
+ MTK_PULL_PU_PD_TYPE,/*88*/ MTK_PULL_PU_PD_TYPE,/*89*/
+ MTK_PULL_PU_PD_TYPE,/*90*/ MTK_PULL_PU_PD_TYPE,/*91*/
+ MTK_PULL_PU_PD_TYPE,/*92*/ MTK_PULL_PU_PD_TYPE,/*93*/
+ MTK_PULL_PU_PD_TYPE,/*94*/ MTK_PULL_PU_PD_TYPE,/*95*/
+ MTK_PULL_PU_PD_TYPE,/*96*/ MTK_PULL_PU_PD_TYPE,/*97*/
+ MTK_PULL_PU_PD_TYPE,/*98*/ MTK_PULL_PU_PD_TYPE,/*99*/
+ MTK_PULL_PU_PD_TYPE,/*100*/
+};
+
+static const struct mtk_pin_reg_calc mt7981_reg_cals[] = {
+ [PINCTRL_PIN_REG_MODE] = MTK_RANGE(mt7981_pin_mode_range),
+ [PINCTRL_PIN_REG_DIR] = MTK_RANGE(mt7981_pin_dir_range),
+ [PINCTRL_PIN_REG_DI] = MTK_RANGE(mt7981_pin_di_range),
+ [PINCTRL_PIN_REG_DO] = MTK_RANGE(mt7981_pin_do_range),
+ [PINCTRL_PIN_REG_SMT] = MTK_RANGE(mt7981_pin_smt_range),
+ [PINCTRL_PIN_REG_IES] = MTK_RANGE(mt7981_pin_ies_range),
+ [PINCTRL_PIN_REG_PU] = MTK_RANGE(mt7981_pin_pu_range),
+ [PINCTRL_PIN_REG_PD] = MTK_RANGE(mt7981_pin_pd_range),
+ [PINCTRL_PIN_REG_DRV] = MTK_RANGE(mt7981_pin_drv_range),
+ [PINCTRL_PIN_REG_PUPD] = MTK_RANGE(mt7981_pin_pupd_range),
+ [PINCTRL_PIN_REG_R0] = MTK_RANGE(mt7981_pin_r0_range),
+ [PINCTRL_PIN_REG_R1] = MTK_RANGE(mt7981_pin_r1_range),
+};
+
+static const struct mtk_pin_desc mt7981_pins[] = {
+ MT7981_PIN(0, "GPIO_WPS"),
+ MT7981_PIN(1, "GPIO_RESET"),
+ MT7981_PIN(2, "SYS_WATCHDOG"),
+ MT7981_PIN(3, "PCIE_PERESET_N"),
+ MT7981_PIN(4, "JTAG_JTDO"),
+ MT7981_PIN(5, "JTAG_JTDI"),
+ MT7981_PIN(6, "JTAG_JTMS"),
+ MT7981_PIN(7, "JTAG_JTCLK"),
+ MT7981_PIN(8, "JTAG_JTRST_N"),
+ MT7981_PIN(9, "WO_JTAG_JTDO"),
+ MT7981_PIN(10, "WO_JTAG_JTDI"),
+ MT7981_PIN(11, "WO_JTAG_JTMS"),
+ MT7981_PIN(12, "WO_JTAG_JTCLK"),
+ MT7981_PIN(13, "WO_JTAG_JTRST_N"),
+ MT7981_PIN(14, "USB_VBUS"),
+ MT7981_PIN(15, "PWM0"),
+ MT7981_PIN(16, "SPI0_CLK"),
+ MT7981_PIN(17, "SPI0_MOSI"),
+ MT7981_PIN(18, "SPI0_MISO"),
+ MT7981_PIN(19, "SPI0_CS"),
+ MT7981_PIN(20, "SPI0_HOLD"),
+ MT7981_PIN(21, "SPI0_WP"),
+ MT7981_PIN(22, "SPI1_CLK"),
+ MT7981_PIN(23, "SPI1_MOSI"),
+ MT7981_PIN(24, "SPI1_MISO"),
+ MT7981_PIN(25, "SPI1_CS"),
+ MT7981_PIN(26, "SPI2_CLK"),
+ MT7981_PIN(27, "SPI2_MOSI"),
+ MT7981_PIN(28, "SPI2_MISO"),
+ MT7981_PIN(29, "SPI2_CS"),
+ MT7981_PIN(30, "SPI2_HOLD"),
+ MT7981_PIN(31, "SPI2_WP"),
+ MT7981_PIN(32, "UART0_RXD"),
+ MT7981_PIN(33, "UART0_TXD"),
+ MT7981_PIN(34, "PCIE_CLK_REQ"),
+ MT7981_PIN(35, "PCIE_WAKE_N"),
+ MT7981_PIN(36, "SMI_MDC"),
+ MT7981_PIN(37, "SMI_MDIO"),
+ MT7981_PIN(38, "GBE_INT"),
+ MT7981_PIN(39, "GBE_RESET"),
+ MT7981_PIN(40, "WF_DIG_RESETB"),
+ MT7981_PIN(41, "WF_CBA_RESETB"),
+ MT7981_PIN(42, "WF_XO_REQ"),
+ MT7981_PIN(43, "WF_TOP_CLK"),
+ MT7981_PIN(44, "WF_TOP_DATA"),
+ MT7981_PIN(45, "WF_HB1"),
+ MT7981_PIN(46, "WF_HB2"),
+ MT7981_PIN(47, "WF_HB3"),
+ MT7981_PIN(48, "WF_HB4"),
+ MT7981_PIN(49, "WF_HB0"),
+ MT7981_PIN(50, "WF_HB0_B"),
+ MT7981_PIN(51, "WF_HB5"),
+ MT7981_PIN(52, "WF_HB6"),
+ MT7981_PIN(53, "WF_HB7"),
+ MT7981_PIN(54, "WF_HB8"),
+ MT7981_PIN(55, "WF_HB9"),
+ MT7981_PIN(56, "WF_HB10"),
+};
+
+/* List all groups consisting of these pins dedicated to the enablement of
+ * certain hardware block and the corresponding mode for all of the pins.
+ * The hardware probably has multiple combinations of these pinouts.
+ */
+
+/* WA_AICE */
+static int mt7981_wa_aice1_pins[] = { 0, 1, };
+static int mt7981_wa_aice1_funcs[] = { 2, 2, };
+
+static int mt7981_wa_aice2_pins[] = { 0, 1, };
+static int mt7981_wa_aice2_funcs[] = { 3, 3, };
+
+static int mt7981_wa_aice3_pins[] = { 28, 29, };
+static int mt7981_wa_aice3_funcs[] = { 3, 3, };
+
+static int mt7981_wm_aice1_pins[] = { 9, 10, };
+static int mt7981_wm_aice1_funcs[] = { 2, 2, };
+
+static int mt7981_wm_aice2_pins[] = { 30, 31, };
+static int mt7981_wm_aice2_funcs[] = { 5, 5, };
+
+/* WM_UART */
+static int mt7981_wm_uart_0_pins[] = { 0, 1, };
+static int mt7981_wm_uart_0_funcs[] = { 5, 5, };
+
+static int mt7981_wm_uart_1_pins[] = { 20, 21, };
+static int mt7981_wm_uart_1_funcs[] = { 4, 4, };
+
+static int mt7981_wm_uart_2_pins[] = { 30, 31, };
+static int mt7981_wm_uart_2_funcs[] = { 3, 3, };
+
+/* DFD */
+static int mt7981_dfd_pins[] = { 0, 1, 4, 5, };
+static int mt7981_dfd_funcs[] = { 5, 5, 6, 6, };
+
+/* SYS_WATCHDOG */
+static int mt7981_watchdog_pins[] = { 2, };
+static int mt7981_watchdog_funcs[] = { 1, };
+
+static int mt7981_watchdog1_pins[] = { 13, };
+static int mt7981_watchdog1_funcs[] = { 5, };
+
+/* PCIE_PERESET_N */
+static int mt7981_pcie_pereset_pins[] = { 3, };
+static int mt7981_pcie_pereset_funcs[] = { 1, };
+
+/* JTAG */
+static int mt7981_jtag_pins[] = { 4, 5, 6, 7, 8, };
+static int mt7981_jtag_funcs[] = { 1, 1, 1, 1, 1, };
+
+/* WM_JTAG */
+static int mt7981_wm_jtag_0_pins[] = { 4, 5, 6, 7, 8, };
+static int mt7981_wm_jtag_0_funcs[] = { 2, 2, 2, 2, 2, };
+
+static int mt7981_wm_jtag_1_pins[] = { 20, 21, 22, 23, 24, };
+static int mt7981_wm_jtag_1_funcs[] = { 5, 5, 5, 5, 5, };
+
+/* WO0_JTAG */
+static int mt7981_wo0_jtag_0_pins[] = { 9, 10, 11, 12, 13, };
+static int mt7981_wo0_jtag_0_funcs[] = { 1, 1, 1, 1, 1, };
+
+static int mt7981_wo0_jtag_1_pins[] = { 25, 26, 27, 28, 29, };
+static int mt7981_wo0_jtag_1_funcs[] = { 5, 5, 5, 5, 5, };
+
+/* UART2 */
+static int mt7981_uart2_0_pins[] = { 4, 5, 6, 7, };
+static int mt7981_uart2_0_funcs[] = { 3, 3, 3, 3, };
+
+/* GBE_LED0 */
+static int mt7981_gbe_led0_pins[] = { 8, };
+static int mt7981_gbe_led0_funcs[] = { 3, };
+
+/* PTA_EXT */
+static int mt7981_pta_ext_0_pins[] = { 4, 5, 6, };
+static int mt7981_pta_ext_0_funcs[] = { 4, 4, 4, };
+
+static int mt7981_pta_ext_1_pins[] = { 22, 23, 24, };
+static int mt7981_pta_ext_1_funcs[] = { 4, 4, 4, };
+
+/* PWM2 */
+static int mt7981_pwm2_pins[] = { 7, };
+static int mt7981_pwm2_funcs[] = { 4, };
+
+/* NET_WO0_UART_TXD */
+static int mt7981_net_wo0_uart_txd_0_pins[] = { 8, };
+static int mt7981_net_wo0_uart_txd_0_funcs[] = { 4, };
+
+static int mt7981_net_wo0_uart_txd_1_pins[] = { 14, };
+static int mt7981_net_wo0_uart_txd_1_funcs[] = { 3, };
+
+static int mt7981_net_wo0_uart_txd_2_pins[] = { 15, };
+static int mt7981_net_wo0_uart_txd_2_funcs[] = { 4, };
+
+/* SPI1 */
+static int mt7981_spi1_0_pins[] = { 4, 5, 6, 7, };
+static int mt7981_spi1_0_funcs[] = { 5, 5, 5, 5, };
+
+/* I2C */
+static int mt7981_i2c0_0_pins[] = { 6, 7, };
+static int mt7981_i2c0_0_funcs[] = { 6, 6, };
+
+static int mt7981_i2c0_1_pins[] = { 30, 31, };
+static int mt7981_i2c0_1_funcs[] = { 4, 4, };
+
+static int mt7981_i2c0_2_pins[] = { 36, 37, };
+static int mt7981_i2c0_2_funcs[] = { 2, 2, };
+
+static int mt7981_u2_phy_i2c_pins[] = { 30, 31, };
+static int mt7981_u2_phy_i2c_funcs[] = { 6, 6, };
+
+static int mt7981_u3_phy_i2c_pins[] = { 32, 33, };
+static int mt7981_u3_phy_i2c_funcs[] = { 3, 3, };
+
+static int mt7981_sgmii1_phy_i2c_pins[] = { 32, 33, };
+static int mt7981_sgmii1_phy_i2c_funcs[] = { 2, 2, };
+
+static int mt7981_sgmii0_phy_i2c_pins[] = { 32, 33, };
+static int mt7981_sgmii0_phy_i2c_funcs[] = { 5, 5, };
+
+/* DFD_NTRST */
+static int mt7981_dfd_ntrst_pins[] = { 8, };
+static int mt7981_dfd_ntrst_funcs[] = { 6, };
+
+/* PWM0 */
+static int mt7981_pwm0_0_pins[] = { 13, };
+static int mt7981_pwm0_0_funcs[] = { 2, };
+
+static int mt7981_pwm0_1_pins[] = { 15, };
+static int mt7981_pwm0_1_funcs[] = { 1, };
+
+/* PWM1 */
+static int mt7981_pwm1_0_pins[] = { 14, };
+static int mt7981_pwm1_0_funcs[] = { 2, };
+
+static int mt7981_pwm1_1_pins[] = { 15, };
+static int mt7981_pwm1_1_funcs[] = { 3, };
+
+/* GBE_LED1 */
+static int mt7981_gbe_led1_pins[] = { 13, };
+static int mt7981_gbe_led1_funcs[] = { 3, };
+
+/* PCM */
+static int mt7981_pcm_pins[] = { 9, 10, 11, 12, 13, 25 };
+static int mt7981_pcm_funcs[] = { 4, 4, 4, 4, 4, 4, };
+
+/* UDI */
+static int mt7981_udi_pins[] = { 9, 10, 11, 12, 13, };
+static int mt7981_udi_funcs[] = { 6, 6, 6, 6, 6, };
+
+/* DRV_VBUS */
+static int mt7981_drv_vbus_pins[] = { 14, };
+static int mt7981_drv_vbus_funcs[] = { 1, };
+
+/* EMMC */
+static int mt7981_emmc_45_pins[] = { 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, };
+static int mt7981_emmc_45_funcs[] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, };
+
+/* SNFI */
+static int mt7981_snfi_pins[] = { 16, 17, 18, 19, 20, 21, };
+static int mt7981_snfi_funcs[] = { 3, 3, 3, 3, 3, 3, };
+
+/* SPI0 */
+static int mt7981_spi0_pins[] = { 16, 17, 18, 19, };
+static int mt7981_spi0_funcs[] = { 1, 1, 1, 1, };
+
+/* SPI0 */
+static int mt7981_spi0_wp_hold_pins[] = { 20, 21, };
+static int mt7981_spi0_wp_hold_funcs[] = { 1, 1, };
+
+/* SPI1 */
+static int mt7981_spi1_1_pins[] = { 22, 23, 24, 25, };
+static int mt7981_spi1_1_funcs[] = { 1, 1, 1, 1, };
+
+/* SPI2 */
+static int mt7981_spi2_pins[] = { 26, 27, 28, 29, };
+static int mt7981_spi2_funcs[] = { 1, 1, 1, 1, };
+
+/* SPI2 */
+static int mt7981_spi2_wp_hold_pins[] = { 30, 31, };
+static int mt7981_spi2_wp_hold_funcs[] = { 1, 1, };
+
+/* UART1 */
+static int mt7981_uart1_0_pins[] = { 16, 17, 18, 19, };
+static int mt7981_uart1_0_funcs[] = { 4, 4, 4, 4, };
+
+static int mt7981_uart1_1_pins[] = { 26, 27, 28, 29, };
+static int mt7981_uart1_1_funcs[] = { 2, 2, 2, 2, };
+
+/* UART2 */
+static int mt7981_uart2_1_pins[] = { 22, 23, 24, 25, };
+static int mt7981_uart2_1_funcs[] = { 3, 3, 3, 3, };
+
+/* UART0 */
+static int mt7981_uart0_pins[] = { 32, 33, };
+static int mt7981_uart0_funcs[] = { 1, 1, };
+
+/* PCIE_CLK_REQ */
+static int mt7981_pcie_clk_pins[] = { 34, };
+static int mt7981_pcie_clk_funcs[] = { 2, };
+
+/* PCIE_WAKE_N */
+static int mt7981_pcie_wake_pins[] = { 35, };
+static int mt7981_pcie_wake_funcs[] = { 2, };
+
+/* MDC_MDIO */
+static int mt7981_smi_mdc_mdio_pins[] = { 36, 37, };
+static int mt7981_smi_mdc_mdio_funcs[] = { 1, 1, };
+
+static int mt7981_gbe_ext_mdc_mdio_pins[] = { 36, 37, };
+static int mt7981_gbe_ext_mdc_mdio_funcs[] = { 3, 3, };
+
+/* WF0_MODE1 */
+static int mt7981_wf0_mode1_pins[] = { 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56 };
+static int mt7981_wf0_mode1_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+
+/* WF0_MODE3 */
+static int mt7981_wf0_mode3_pins[] = { 45, 46, 47, 48, 49, 51 };
+static int mt7981_wf0_mode3_funcs[] = { 2, 2, 2, 2, 2, 2 };
+
+/* WF2G_LED */
+static int mt7981_wf2g_led0_pins[] = { 30, };
+static int mt7981_wf2g_led0_funcs[] = { 2, };
+
+static int mt7981_wf2g_led1_pins[] = { 34, };
+static int mt7981_wf2g_led1_funcs[] = { 1, };
+
+/* WF5G_LED */
+static int mt7981_wf5g_led0_pins[] = { 31, };
+static int mt7981_wf5g_led0_funcs[] = { 2, };
+
+static int mt7981_wf5g_led1_pins[] = { 35, };
+static int mt7981_wf5g_led1_funcs[] = { 1, };
+
+/* MT7531_INT */
+static int mt7981_mt7531_int_pins[] = { 38, };
+static int mt7981_mt7531_int_funcs[] = { 1, };
+
+/* ANT_SEL */
+static int mt7981_ant_sel_pins[] = { 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 34, 35 };
+static int mt7981_ant_sel_funcs[] = { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 };
+
+static const struct group_desc mt7981_groups[] = {
+ /* @GPIO(0,1): WA_AICE(2) */
+ PINCTRL_PIN_GROUP("wa_aice1", mt7981_wa_aice1),
+ /* @GPIO(0,1): WA_AICE(3) */
+ PINCTRL_PIN_GROUP("wa_aice2", mt7981_wa_aice2),
+ /* @GPIO(0,1): WM_UART(5) */
+ PINCTRL_PIN_GROUP("wm_uart_0", mt7981_wm_uart_0),
+ /* @GPIO(0,1,4,5): DFD(6) */
+ PINCTRL_PIN_GROUP("dfd", mt7981_dfd),
+ /* @GPIO(2): SYS_WATCHDOG(1) */
+ PINCTRL_PIN_GROUP("watchdog", mt7981_watchdog),
+ /* @GPIO(3): PCIE_PERESET_N(1) */
+ PINCTRL_PIN_GROUP("pcie_pereset", mt7981_pcie_pereset),
+ /* @GPIO(4,8) JTAG(1) */
+ PINCTRL_PIN_GROUP("jtag", mt7981_jtag),
+ /* @GPIO(4,8) WM_JTAG(2) */
+ PINCTRL_PIN_GROUP("wm_jtag_0", mt7981_wm_jtag_0),
+ /* @GPIO(9,13) WO0_JTAG(1) */
+ PINCTRL_PIN_GROUP("wo0_jtag_0", mt7981_wo0_jtag_0),
+ /* @GPIO(4,7) WM_JTAG(3) */
+ PINCTRL_PIN_GROUP("uart2_0", mt7981_uart2_0),
+ /* @GPIO(8) GBE_LED0(3) */
+ PINCTRL_PIN_GROUP("gbe_led0", mt7981_gbe_led0),
+ /* @GPIO(4,6) PTA_EXT(4) */
+ PINCTRL_PIN_GROUP("pta_ext_0", mt7981_pta_ext_0),
+ /* @GPIO(7) PWM2(4) */
+ PINCTRL_PIN_GROUP("pwm2", mt7981_pwm2),
+ /* @GPIO(8) NET_WO0_UART_TXD(4) */
+ PINCTRL_PIN_GROUP("net_wo0_uart_txd_0", mt7981_net_wo0_uart_txd_0),
+ /* @GPIO(4,7) SPI1(5) */
+ PINCTRL_PIN_GROUP("spi1_0", mt7981_spi1_0),
+ /* @GPIO(6,7) I2C(5) */
+ PINCTRL_PIN_GROUP("i2c0_0", mt7981_i2c0_0),
+ /* @GPIO(0,1,4,5): DFD_NTRST(6) */
+ PINCTRL_PIN_GROUP("dfd_ntrst", mt7981_dfd_ntrst),
+ /* @GPIO(9,10): WM_AICE(2) */
+ PINCTRL_PIN_GROUP("wm_aice1", mt7981_wm_aice1),
+ /* @GPIO(13): PWM0(2) */
+ PINCTRL_PIN_GROUP("pwm0_0", mt7981_pwm0_0),
+ /* @GPIO(15): PWM0(1) */
+ PINCTRL_PIN_GROUP("pwm0_1", mt7981_pwm0_1),
+ /* @GPIO(14): PWM1(2) */
+ PINCTRL_PIN_GROUP("pwm1_0", mt7981_pwm1_0),
+ /* @GPIO(15): PWM1(3) */
+ PINCTRL_PIN_GROUP("pwm1_1", mt7981_pwm1_1),
+ /* @GPIO(14) NET_WO0_UART_TXD(3) */
+ PINCTRL_PIN_GROUP("net_wo0_uart_txd_1", mt7981_net_wo0_uart_txd_1),
+ /* @GPIO(15) NET_WO0_UART_TXD(4) */
+ PINCTRL_PIN_GROUP("net_wo0_uart_txd_2", mt7981_net_wo0_uart_txd_2),
+ /* @GPIO(13) GBE_LED0(3) */
+ PINCTRL_PIN_GROUP("gbe_led1", mt7981_gbe_led1),
+ /* @GPIO(9,13) PCM(4) */
+ PINCTRL_PIN_GROUP("pcm", mt7981_pcm),
+ /* @GPIO(13): SYS_WATCHDOG1(5) */
+ PINCTRL_PIN_GROUP("watchdog1", mt7981_watchdog1),
+ /* @GPIO(9,13) UDI(4) */
+ PINCTRL_PIN_GROUP("udi", mt7981_udi),
+ /* @GPIO(14) DRV_VBUS(1) */
+ PINCTRL_PIN_GROUP("drv_vbus", mt7981_drv_vbus),
+ /* @GPIO(15,25): EMMC(2) */
+ PINCTRL_PIN_GROUP("emmc_45", mt7981_emmc_45),
+ /* @GPIO(16,21): SNFI(3) */
+ PINCTRL_PIN_GROUP("snfi", mt7981_snfi),
+ /* @GPIO(16,19): SPI0(1) */
+ PINCTRL_PIN_GROUP("spi0", mt7981_spi0),
+ /* @GPIO(20,21): SPI0(1) */
+ PINCTRL_PIN_GROUP("spi0_wp_hold", mt7981_spi0_wp_hold),
+ /* @GPIO(22,25) SPI1(1) */
+ PINCTRL_PIN_GROUP("spi1_1", mt7981_spi1_1),
+ /* @GPIO(26,29): SPI2(1) */
+ PINCTRL_PIN_GROUP("spi2", mt7981_spi2),
+ /* @GPIO(30,31): SPI0(1) */
+ PINCTRL_PIN_GROUP("spi2_wp_hold", mt7981_spi2_wp_hold),
+ /* @GPIO(16,19): UART1(4) */
+ PINCTRL_PIN_GROUP("uart1_0", mt7981_uart1_0),
+ /* @GPIO(26,29): UART1(2) */
+ PINCTRL_PIN_GROUP("uart1_1", mt7981_uart1_1),
+ /* @GPIO(22,25): UART1(3) */
+ PINCTRL_PIN_GROUP("uart2_1", mt7981_uart2_1),
+ /* @GPIO(22,24) PTA_EXT(4) */
+ PINCTRL_PIN_GROUP("pta_ext_1", mt7981_pta_ext_1),
+ /* @GPIO(20,21): WM_UART(4) */
+ PINCTRL_PIN_GROUP("wm_aurt_1", mt7981_wm_uart_1),
+ /* @GPIO(30,31): WM_UART(3) */
+ PINCTRL_PIN_GROUP("wm_aurt_2", mt7981_wm_uart_2),
+ /* @GPIO(20,24) WM_JTAG(5) */
+ PINCTRL_PIN_GROUP("wm_jtag_1", mt7981_wm_jtag_1),
+ /* @GPIO(25,29) WO0_JTAG(5) */
+ PINCTRL_PIN_GROUP("wo0_jtag_1", mt7981_wo0_jtag_1),
+ /* @GPIO(28,29): WA_AICE(3) */
+ PINCTRL_PIN_GROUP("wa_aice3", mt7981_wa_aice3),
+ /* @GPIO(30,31): WM_AICE(5) */
+ PINCTRL_PIN_GROUP("wm_aice2", mt7981_wm_aice2),
+ /* @GPIO(30,31): I2C(4) */
+ PINCTRL_PIN_GROUP("i2c0_1", mt7981_i2c0_1),
+ /* @GPIO(30,31): I2C(6) */
+ PINCTRL_PIN_GROUP("u2_phy_i2c", mt7981_u2_phy_i2c),
+ /* @GPIO(32,33): I2C(1) */
+ PINCTRL_PIN_GROUP("uart0", mt7981_uart0),
+ /* @GPIO(32,33): I2C(2) */
+ PINCTRL_PIN_GROUP("sgmii1_phy_i2c", mt7981_sgmii1_phy_i2c),
+ /* @GPIO(32,33): I2C(3) */
+ PINCTRL_PIN_GROUP("u3_phy_i2c", mt7981_u3_phy_i2c),
+ /* @GPIO(32,33): I2C(5) */
+ PINCTRL_PIN_GROUP("sgmii0_phy_i2c", mt7981_sgmii0_phy_i2c),
+ /* @GPIO(34): PCIE_CLK_REQ(2) */
+ PINCTRL_PIN_GROUP("pcie_clk", mt7981_pcie_clk),
+ /* @GPIO(35): PCIE_WAKE_N(2) */
+ PINCTRL_PIN_GROUP("pcie_wake", mt7981_pcie_wake),
+ /* @GPIO(36,37): I2C(2) */
+ PINCTRL_PIN_GROUP("i2c0_2", mt7981_i2c0_2),
+ /* @GPIO(36,37): MDC_MDIO(1) */
+ PINCTRL_PIN_GROUP("smi_mdc_mdio", mt7981_smi_mdc_mdio),
+ /* @GPIO(36,37): MDC_MDIO(3) */
+ PINCTRL_PIN_GROUP("gbe_ext_mdc_mdio", mt7981_gbe_ext_mdc_mdio),
+ /* @GPIO(69,85): WF0_MODE1(1) */
+ PINCTRL_PIN_GROUP("wf0_mode1", mt7981_wf0_mode1),
+ /* @GPIO(74,80): WF0_MODE3(3) */
+ PINCTRL_PIN_GROUP("wf0_mode3", mt7981_wf0_mode3),
+ /* @GPIO(30): WF2G_LED(2) */
+ PINCTRL_PIN_GROUP("wf2g_led0", mt7981_wf2g_led0),
+ /* @GPIO(34): WF2G_LED(1) */
+ PINCTRL_PIN_GROUP("wf2g_led1", mt7981_wf2g_led1),
+ /* @GPIO(31): WF5G_LED(2) */
+ PINCTRL_PIN_GROUP("wf5g_led0", mt7981_wf5g_led0),
+ /* @GPIO(35): WF5G_LED(1) */
+ PINCTRL_PIN_GROUP("wf5g_led1", mt7981_wf5g_led1),
+ /* @GPIO(38): MT7531_INT(1) */
+ PINCTRL_PIN_GROUP("mt7531_int", mt7981_mt7531_int),
+ /* @GPIO(14,15,26,17,18,19,20,21,22,23,24,25,34,35): ANT_SEL(1) */
+ PINCTRL_PIN_GROUP("ant_sel", mt7981_ant_sel),
+};
+
+/* Joint those groups owning the same capability in user point of view which
+ * allows that people tend to use through the device tree.
+ */
+static const char *mt7981_wa_aice_groups[] = { "wa_aice1", "wa_aice2", "wm_aice1_1",
+ "wa_aice3", "wm_aice1_2", };
+static const char *mt7981_uart_groups[] = { "wm_uart_0", "uart2_0",
+ "net_wo0_uart_txd_0", "net_wo0_uart_txd_1", "net_wo0_uart_txd_2",
+ "uart1_0", "uart1_1", "uart2_1", "wm_aurt_1", "wm_aurt_2", "uart0", };
+static const char *mt7981_dfd_groups[] = { "dfd", "dfd_ntrst", };
+static const char *mt7981_wdt_groups[] = { "watchdog", "watchdog1", };
+static const char *mt7981_pcie_groups[] = { "pcie_pereset", "pcie_clk", "pcie_wake", };
+static const char *mt7981_jtag_groups[] = { "jtag", "wm_jtag_0", "wo0_jtag_0",
+ "wo0_jtag_1", "wm_jtag_1", };
+static const char *mt7981_led_groups[] = { "gbe_led0", "gbe_led1", "wf2g_led0",
+ "wf2g_led1", "wf5g_led0", "wf5g_led1", };
+static const char *mt7981_pta_groups[] = { "pta_ext_0", "pta_ext_1", };
+static const char *mt7981_pwm_groups[] = { "pwm2", "pwm0_0", "pwm0_1",
+ "pwm1_0", "pwm1_1", };
+static const char *mt7981_spi_groups[] = { "spi1_0", "spi0", "spi0_wp_hold", "spi1_1", "spi2",
+ "spi2_wp_hold", };
+static const char *mt7981_i2c_groups[] = { "i2c0_0", "i2c0_1", "u2_phy_i2c",
+ "sgmii1_phy_i2c", "u3_phy_i2c", "sgmii0_phy_i2c", "i2c0_2", };
+static const char *mt7981_pcm_groups[] = { "pcm", };
+static const char *mt7981_udi_groups[] = { "udi", };
+static const char *mt7981_usb_groups[] = { "drv_vbus", };
+static const char *mt7981_flash_groups[] = { "emmc_45", "snfi", };
+static const char *mt7981_ethernet_groups[] = { "smi_mdc_mdio", "gbe_ext_mdc_mdio",
+ "wf0_mode1", "wf0_mode3", "mt7531_int", };
+static const char *mt7981_ant_groups[] = { "ant_sel", };
+
+static const struct function_desc mt7981_functions[] = {
+ {"wa_aice", mt7981_wa_aice_groups, ARRAY_SIZE(mt7981_wa_aice_groups)},
+ {"dfd", mt7981_dfd_groups, ARRAY_SIZE(mt7981_dfd_groups)},
+ {"jtag", mt7981_jtag_groups, ARRAY_SIZE(mt7981_jtag_groups)},
+ {"pta", mt7981_pta_groups, ARRAY_SIZE(mt7981_pta_groups)},
+ {"pcm", mt7981_pcm_groups, ARRAY_SIZE(mt7981_pcm_groups)},
+ {"udi", mt7981_udi_groups, ARRAY_SIZE(mt7981_udi_groups)},
+ {"usb", mt7981_usb_groups, ARRAY_SIZE(mt7981_usb_groups)},
+ {"ant", mt7981_ant_groups, ARRAY_SIZE(mt7981_ant_groups)},
+ {"eth", mt7981_ethernet_groups, ARRAY_SIZE(mt7981_ethernet_groups)},
+ {"i2c", mt7981_i2c_groups, ARRAY_SIZE(mt7981_i2c_groups)},
+ {"led", mt7981_led_groups, ARRAY_SIZE(mt7981_led_groups)},
+ {"pwm", mt7981_pwm_groups, ARRAY_SIZE(mt7981_pwm_groups)},
+ {"spi", mt7981_spi_groups, ARRAY_SIZE(mt7981_spi_groups)},
+ {"uart", mt7981_uart_groups, ARRAY_SIZE(mt7981_uart_groups)},
+ {"watchdog", mt7981_wdt_groups, ARRAY_SIZE(mt7981_wdt_groups)},
+ {"flash", mt7981_flash_groups, ARRAY_SIZE(mt7981_flash_groups)},
+ {"pcie", mt7981_pcie_groups, ARRAY_SIZE(mt7981_pcie_groups)},
+};
+
+static const struct mtk_eint_hw mt7981_eint_hw = {
+ .port_mask = 7,
+ .ports = 7,
+ .ap_num = ARRAY_SIZE(mt7981_pins),
+ .db_cnt = 16,
+};
+
+static const char * const mt7981_pinctrl_register_base_names[] = {
+ "gpio", "iocfg_rt", "iocfg_rm", "iocfg_rb",
+ "iocfg_lb", "iocfg_bl", "iocfg_tm", "iocfg_tl",
+};
+
+static struct mtk_pin_soc mt7981_data = {
+ .reg_cal = mt7981_reg_cals,
+ .pins = mt7981_pins,
+ .npins = ARRAY_SIZE(mt7981_pins),
+ .grps = mt7981_groups,
+ .ngrps = ARRAY_SIZE(mt7981_groups),
+ .funcs = mt7981_functions,
+ .nfuncs = ARRAY_SIZE(mt7981_functions),
+ .eint_hw = &mt7981_eint_hw,
+ .gpio_m = 0,
+ .ies_present = false,
+ .base_names = mt7981_pinctrl_register_base_names,
+ .nbase_names = ARRAY_SIZE(mt7981_pinctrl_register_base_names),
+ .pull_type = mt7981_pull_type,
+ .bias_set_combo = mtk_pinconf_bias_set_combo,
+ .bias_get_combo = mtk_pinconf_bias_get_combo,
+ .drive_set = mtk_pinconf_drive_set_rev1,
+ .drive_get = mtk_pinconf_drive_get_rev1,
+ .adv_pull_get = mtk_pinconf_adv_pull_get,
+ .adv_pull_set = mtk_pinconf_adv_pull_set,
+};
+
+static const struct of_device_id mt7981_pinctrl_of_match[] = {
+ { .compatible = "mediatek,mt7981-pinctrl", },
+ {}
+};
+
+static int mt7981_pinctrl_probe(struct platform_device *pdev)
+{
+ return mtk_moore_pinctrl_probe(pdev, &mt7981_data);
+}
+
+static struct platform_driver mt7981_pinctrl_driver = {
+ .driver = {
+ .name = "mt7981-pinctrl",
+ .of_match_table = mt7981_pinctrl_of_match,
+ },
+ .probe = mt7981_pinctrl_probe,
+};
+
+static int __init mt7981_pinctrl_init(void)
+{
+ return platform_driver_register(&mt7981_pinctrl_driver);
+}
+arch_initcall(mt7981_pinctrl_init);
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
index 553d16703475..665dec419e7c 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
@@ -906,7 +906,6 @@ static const struct gpio_chip mtk_gpio_chip = {
.set = mtk_gpio_set,
.to_irq = mtk_gpio_to_irq,
.set_config = mtk_gpio_set_config,
- .of_gpio_n_cells = 2,
};
static int mtk_eint_suspend(struct device *device)
diff --git a/drivers/pinctrl/mediatek/pinctrl-paris.c b/drivers/pinctrl/mediatek/pinctrl-paris.c
index 475f4172d508..33d6c3fb7908 100644
--- a/drivers/pinctrl/mediatek/pinctrl-paris.c
+++ b/drivers/pinctrl/mediatek/pinctrl-paris.c
@@ -640,7 +640,7 @@ static int mtk_hw_get_value_wrap(struct mtk_pinctrl *hw, unsigned int gpio, int
ssize_t mtk_pctrl_show_one_pin(struct mtk_pinctrl *hw,
unsigned int gpio, char *buf, unsigned int buf_len)
{
- int pinmux, pullup, pullen, len = 0, r1 = -1, r0 = -1, rsel = -1;
+ int pinmux, pullup = 0, pullen = 0, len = 0, r1 = -1, r0 = -1, rsel = -1;
const struct mtk_pin_desc *desc;
u32 try_all_type = 0;
@@ -717,7 +717,7 @@ static void mtk_pctrl_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
unsigned int gpio)
{
struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev);
- char buf[PIN_DBG_BUF_SZ];
+ char buf[PIN_DBG_BUF_SZ] = { 0 };
(void)mtk_pctrl_show_one_pin(hw, gpio, buf, PIN_DBG_BUF_SZ);
@@ -987,7 +987,6 @@ static int mtk_build_gpiochip(struct mtk_pinctrl *hw)
chip->set_config = mtk_gpio_set_config;
chip->base = -1;
chip->ngpio = hw->soc->npins;
- chip->of_gpio_n_cells = 2;
ret = gpiochip_add_data(chip, hw);
if (ret < 0)
diff --git a/drivers/pinctrl/nomadik/pinctrl-abx500.c b/drivers/pinctrl/nomadik/pinctrl-abx500.c
index 28c3403df1b0..6b90051af206 100644
--- a/drivers/pinctrl/nomadik/pinctrl-abx500.c
+++ b/drivers/pinctrl/nomadik/pinctrl-abx500.c
@@ -446,8 +446,6 @@ out:
return ret;
}
-#include <linux/seq_file.h>
-
static void abx500_gpio_dbg_show_one(struct seq_file *s,
struct pinctrl_dev *pctldev,
struct gpio_chip *chip,
diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c
index 32c3edaf9038..9236a132c7ba 100644
--- a/drivers/pinctrl/pinctrl-amd.c
+++ b/drivers/pinctrl/pinctrl-amd.c
@@ -218,6 +218,7 @@ static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc)
char *orientation;
char debounce_value[40];
char *debounce_enable;
+ char *wake_cntrlz;
for (bank = 0; bank < gpio_dev->hwbank_num; bank++) {
unsigned int time = 0;
@@ -305,6 +306,12 @@ static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc)
wake_cntrl2 = " ∅";
seq_printf(s, "S4/S5 %s| ", wake_cntrl2);
+ if (pin_reg & BIT(WAKECNTRL_Z_OFF))
+ wake_cntrlz = "⏰";
+ else
+ wake_cntrlz = " ∅";
+ seq_printf(s, "Z %s| ", wake_cntrlz);
+
if (pin_reg & BIT(PULL_UP_ENABLE_OFF)) {
pull_up_enable = "+";
if (pin_reg & BIT(PULL_UP_SEL_OFF))
diff --git a/drivers/pinctrl/pinctrl-amd.h b/drivers/pinctrl/pinctrl-amd.h
index c8635998465d..81ae8319a1f0 100644
--- a/drivers/pinctrl/pinctrl-amd.h
+++ b/drivers/pinctrl/pinctrl-amd.h
@@ -42,6 +42,7 @@
#define OUTPUT_ENABLE_OFF 23
#define SW_CNTRL_IN_OFF 24
#define SW_CNTRL_EN_OFF 25
+#define WAKECNTRL_Z_OFF 27
#define INTERRUPT_STS_OFF 28
#define WAKE_STS_OFF 29
diff --git a/drivers/pinctrl/pinctrl-at91-pio4.c b/drivers/pinctrl/pinctrl-at91-pio4.c
index 39b233f73e13..373eed8bc4be 100644
--- a/drivers/pinctrl/pinctrl-at91-pio4.c
+++ b/drivers/pinctrl/pinctrl-at91-pio4.c
@@ -1149,8 +1149,8 @@ static int atmel_pinctrl_probe(struct platform_device *pdev)
pin_desc[i].number = i;
/* Pin naming convention: P(bank_name)(bank_pin_number). */
- pin_desc[i].name = kasprintf(GFP_KERNEL, "P%c%d",
- bank + 'A', line);
+ pin_desc[i].name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "P%c%d",
+ bank + 'A', line);
group->name = group_names[i] = pin_desc[i].name;
group->pin = pin_desc[i].number;
diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
index 1e1813d7c550..735c501e7a06 100644
--- a/drivers/pinctrl/pinctrl-at91.c
+++ b/drivers/pinctrl/pinctrl-at91.c
@@ -1294,7 +1294,7 @@ static int at91_pinctrl_probe_dt(struct platform_device *pdev,
struct at91_pinctrl *info)
{
int ret = 0;
- int i, j;
+ int i, j, ngpio_chips_enabled = 0;
uint32_t *tmp;
struct device_node *np = pdev->dev.of_node;
struct device_node *child;
@@ -1307,10 +1307,17 @@ static int at91_pinctrl_probe_dt(struct platform_device *pdev,
of_match_device(at91_pinctrl_of_match, &pdev->dev)->data;
at91_pinctrl_child_count(info, np);
- if (gpio_banks < 1) {
- dev_err(&pdev->dev, "you need to specify at least one gpio-controller\n");
- return -EINVAL;
- }
+ /*
+ * We need all the GPIO drivers to probe FIRST, or we will not be able
+ * to obtain references to the struct gpio_chip * for them, and we
+ * need this to proceed.
+ */
+ for (i = 0; i < MAX_GPIO_BANKS; i++)
+ if (gpio_chips[i])
+ ngpio_chips_enabled++;
+
+ if (ngpio_chips_enabled < info->nactive_banks)
+ return -EPROBE_DEFER;
ret = at91_pinctrl_mux_mask(info, np);
if (ret)
@@ -1366,7 +1373,7 @@ static int at91_pinctrl_probe(struct platform_device *pdev)
{
struct at91_pinctrl *info;
struct pinctrl_pin_desc *pdesc;
- int ret, i, j, k, ngpio_chips_enabled = 0;
+ int ret, i, j, k;
info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
if (!info)
@@ -1376,23 +1383,6 @@ static int at91_pinctrl_probe(struct platform_device *pdev)
if (ret)
return ret;
- /*
- * We need all the GPIO drivers to probe FIRST, or we will not be able
- * to obtain references to the struct gpio_chip * for them, and we
- * need this to proceed.
- */
- for (i = 0; i < gpio_banks; i++)
- if (gpio_chips[i])
- ngpio_chips_enabled++;
-
- if (ngpio_chips_enabled < info->nactive_banks) {
- dev_warn(&pdev->dev,
- "All GPIO chips are not registered yet (%d/%d)\n",
- ngpio_chips_enabled, info->nactive_banks);
- devm_kfree(&pdev->dev, info);
- return -EPROBE_DEFER;
- }
-
at91_pinctrl_desc.name = dev_name(&pdev->dev);
at91_pinctrl_desc.npins = gpio_banks * MAX_NB_GPIO_PER_BANK;
at91_pinctrl_desc.pins = pdesc =
@@ -1649,7 +1639,7 @@ static int gpio_irq_set_wake(struct irq_data *d, unsigned state)
return 0;
}
-static int at91_gpio_suspend(struct device *dev)
+static int __maybe_unused at91_gpio_suspend(struct device *dev)
{
struct at91_gpio_chip *at91_chip = dev_get_drvdata(dev);
void __iomem *pio = at91_chip->regbase;
@@ -1667,7 +1657,7 @@ static int at91_gpio_suspend(struct device *dev)
return 0;
}
-static int at91_gpio_resume(struct device *dev)
+static int __maybe_unused at91_gpio_resume(struct device *dev)
{
struct at91_gpio_chip *at91_chip = dev_get_drvdata(dev);
void __iomem *pio = at91_chip->regbase;
@@ -1885,7 +1875,7 @@ static int at91_gpio_probe(struct platform_device *pdev)
}
for (i = 0; i < chip->ngpio; i++)
- names[i] = kasprintf(GFP_KERNEL, "pio%c%d", alias_idx + 'A', i);
+ names[i] = devm_kasprintf(&pdev->dev, GFP_KERNEL, "pio%c%d", alias_idx + 'A', i);
chip->names = (const char *const *)names;
@@ -1923,7 +1913,7 @@ err:
}
static const struct dev_pm_ops at91_gpio_pm_ops = {
- SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(at91_gpio_suspend, at91_gpio_resume)
+ NOIRQ_SYSTEM_SLEEP_PM_OPS(at91_gpio_suspend, at91_gpio_resume)
};
static struct platform_driver at91_gpio_driver = {
diff --git a/drivers/pinctrl/pinctrl-da850-pupd.c b/drivers/pinctrl/pinctrl-da850-pupd.c
index 5a0a1f20c843..5eb248663e17 100644
--- a/drivers/pinctrl/pinctrl-da850-pupd.c
+++ b/drivers/pinctrl/pinctrl-da850-pupd.c
@@ -173,11 +173,6 @@ static int da850_pupd_probe(struct platform_device *pdev)
return 0;
}
-static int da850_pupd_remove(struct platform_device *pdev)
-{
- return 0;
-}
-
static const struct of_device_id da850_pupd_of_match[] = {
{ .compatible = "ti,da850-pupd" },
{ }
@@ -190,7 +185,6 @@ static struct platform_driver da850_pupd_driver = {
.of_match_table = da850_pupd_of_match,
},
.probe = da850_pupd_probe,
- .remove = da850_pupd_remove,
};
module_platform_driver(da850_pupd_driver);
diff --git a/drivers/pinctrl/pinctrl-digicolor.c b/drivers/pinctrl/pinctrl-digicolor.c
index cc3546fc4610..a0423172bdd6 100644
--- a/drivers/pinctrl/pinctrl-digicolor.c
+++ b/drivers/pinctrl/pinctrl-digicolor.c
@@ -11,18 +11,19 @@
* - Pin pad configuration (pull up/down, strength)
*/
+#include <linux/gpio/driver.h>
#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/io.h>
-#include <linux/gpio/driver.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
#include <linux/spinlock.h>
+
#include <linux/pinctrl/machine.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
+
#include "pinctrl-utils.h"
#define DRIVER_NAME "pinctrl-digicolor"
@@ -248,7 +249,6 @@ static int dc_gpiochip_add(struct dc_pinmap *pmap)
chip->set = dc_gpio_set;
chip->base = -1;
chip->ngpio = PINS_COUNT;
- chip->of_gpio_n_cells = 2;
spin_lock_init(&pmap->lock);
diff --git a/drivers/pinctrl/pinctrl-mcp23s08_i2c.c b/drivers/pinctrl/pinctrl-mcp23s08_i2c.c
index e0b001c8c08c..b635c5737e0c 100644
--- a/drivers/pinctrl/pinctrl-mcp23s08_i2c.c
+++ b/drivers/pinctrl/pinctrl-mcp23s08_i2c.c
@@ -8,8 +8,9 @@
#include "pinctrl-mcp23s08.h"
-static int mcp230xx_probe(struct i2c_client *client, const struct i2c_device_id *id)
+static int mcp230xx_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct device *dev = &client->dev;
unsigned int type = id->driver_data;
struct mcp23s08 *mcp;
@@ -100,7 +101,7 @@ static struct i2c_driver mcp230xx_driver = {
.name = "mcp230xx",
.of_match_table = mcp23s08_i2c_of_match,
},
- .probe = mcp230xx_probe,
+ .probe_new = mcp230xx_probe,
.id_table = mcp230xx_id,
};
diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
index 5eeac92f610a..0276b52f3716 100644
--- a/drivers/pinctrl/pinctrl-rockchip.c
+++ b/drivers/pinctrl/pinctrl-rockchip.c
@@ -3045,6 +3045,7 @@ static int rockchip_pinctrl_parse_groups(struct device_node *np,
np_config = of_find_node_by_phandle(be32_to_cpup(phandle));
ret = pinconf_generic_parse_dt_config(np_config, NULL,
&grp->data[j].configs, &grp->data[j].nconfigs);
+ of_node_put(np_config);
if (ret)
return ret;
}
diff --git a/drivers/pinctrl/pinctrl-sx150x.c b/drivers/pinctrl/pinctrl-sx150x.c
index a87ea3b95cf4..0b5ff99641e1 100644
--- a/drivers/pinctrl/pinctrl-sx150x.c
+++ b/drivers/pinctrl/pinctrl-sx150x.c
@@ -1094,9 +1094,9 @@ static const struct regmap_config sx150x_regmap_config = {
.volatile_reg = sx150x_reg_volatile,
};
-static int sx150x_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int sx150x_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
static const u32 i2c_funcs = I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WRITE_WORD_DATA;
struct device *dev = &client->dev;
@@ -1252,7 +1252,7 @@ static struct i2c_driver sx150x_driver = {
.name = "sx150x-pinctrl",
.of_match_table = of_match_ptr(sx150x_of_match),
},
- .probe = sx150x_probe,
+ .probe_new = sx150x_probe,
.id_table = sx150x_id,
};
diff --git a/drivers/pinctrl/pinctrl-thunderbay.c b/drivers/pinctrl/pinctrl-thunderbay.c
index 590bbbf619af..7a5ff955877c 100644
--- a/drivers/pinctrl/pinctrl-thunderbay.c
+++ b/drivers/pinctrl/pinctrl-thunderbay.c
@@ -1278,19 +1278,12 @@ static int thunderbay_pinctrl_probe(struct platform_device *pdev)
return 0;
}
-static int thunderbay_pinctrl_remove(struct platform_device *pdev)
-{
- /* thunderbay_pinctrl_remove function to clear the assigned memory */
- return 0;
-}
-
static struct platform_driver thunderbay_pinctrl_driver = {
.driver = {
.name = "thunderbay-pinctrl",
.of_match_table = thunderbay_pinctrl_match,
},
.probe = thunderbay_pinctrl_probe,
- .remove = thunderbay_pinctrl_remove,
};
builtin_platform_driver(thunderbay_pinctrl_driver);
diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c
index 6bd7ac37a0e0..021382632608 100644
--- a/drivers/pinctrl/pinmux.c
+++ b/drivers/pinctrl/pinmux.c
@@ -744,10 +744,8 @@ static ssize_t pinmux_select(struct file *file, const char __user *user_buf,
}
ret = pinctrl_get_group_selector(pctldev, gname);
- if (ret < 0) {
- dev_err(pctldev->dev, "failed to get group selector for %s", gname);
+ if (ret < 0)
goto exit_free_buf;
- }
gsel = ret;
ret = pmxops->set_mux(pctldev, fsel, gsel);
diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig
index 1378ddca084f..62d4810cfee1 100644
--- a/drivers/pinctrl/qcom/Kconfig
+++ b/drivers/pinctrl/qcom/Kconfig
@@ -48,6 +48,16 @@ config PINCTRL_IPQ8064
This is the pinctrl, pinmux, pinconf and gpiolib driver for the
Qualcomm TLMM block found in the Qualcomm IPQ8064 platform.
+config PINCTRL_IPQ5332
+ tristate "Qualcomm Technologies Inc IPQ5332 pin controller driver"
+ depends on OF
+ depends on ARM64 || COMPILE_TEST
+ depends on PINCTRL_MSM
+ help
+ This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+ Qualcomm Technologies Inc TLMM block found on the Qualcomm
+ Technologies Inc IPQ5332 platform.
+
config PINCTRL_IPQ8074
tristate "Qualcomm Technologies, Inc. IPQ8074 pin controller driver"
depends on OF
@@ -248,6 +258,25 @@ config PINCTRL_QCOM_SSBI_PMIC
which are using SSBI for communication with SoC. Example PMIC's
devices are pm8058 and pm8921.
+config PINCTRL_QDU1000
+ tristate "Qualcomm Tehcnologies Inc QDU1000/QRU1000 pin controller driver"
+ depends on GPIOLIB && OF
+ depends on ARM64 || COMPILE_TEST
+ depends on PINCTRL_MSM
+ help
+ This is the pinctrl, pinmux, pinconf, and gpiolib driver for the
+ Qualcomm Technologies Inc TLMM block found on the Qualcomm
+ Technologies Inc QDU1000 and QRU1000 platforms.
+
+config PINCTRL_SA8775P
+ tristate "Qualcomm Technologies Inc SA8775P pin controller driver"
+ depends on OF
+ depends on ARM64 || COMPILE_TEST
+ depends on PINCTRL_MSM
+ help
+ This is the pinctrl, pinmux and pinconf driver for the Qualcomm
+ TLMM block found on the Qualcomm SA8775P platforms.
+
config PINCTRL_SC7180
tristate "Qualcomm Technologies Inc SC7180 pin controller driver"
depends on OF
@@ -457,6 +486,27 @@ config PINCTRL_SC8280XP_LPASS_LPI
Qualcomm Technologies Inc LPASS (Low Power Audio SubSystem) LPI
(Low Power Island) found on the Qualcomm Technologies Inc SC8280XP platform.
+config PINCTRL_SM8550
+ tristate "Qualcomm Technologies Inc SM8550 pin controller driver"
+ depends on GPIOLIB
+ depends on ARM64 || COMPILE_TEST
+ depends on PINCTRL_MSM
+ help
+ This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+ Qualcomm Technologies Inc TLMM block found on the Qualcomm
+ Technologies Inc SM8550 platform.
+
+config PINCTRL_SM8550_LPASS_LPI
+ tristate "Qualcomm Technologies Inc SM8550 LPASS LPI pin controller driver"
+ depends on GPIOLIB
+ depends on ARM64 || COMPILE_TEST
+ depends on PINCTRL_LPASS_LPI
+ help
+ This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+ Qualcomm Technologies Inc LPASS (Low Power Audio SubSystem) LPI
+ (Low Power Island) found on the Qualcomm Technologies Inc SM8550
+ platform.
+
config PINCTRL_LPASS_LPI
tristate "Qualcomm Technologies Inc LPASS LPI pin controller driver"
select PINMUX
diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile
index a5c40f552e5c..bea53b52275b 100644
--- a/drivers/pinctrl/qcom/Makefile
+++ b/drivers/pinctrl/qcom/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_PINCTRL_APQ8064) += pinctrl-apq8064.o
obj-$(CONFIG_PINCTRL_APQ8084) += pinctrl-apq8084.o
obj-$(CONFIG_PINCTRL_IPQ4019) += pinctrl-ipq4019.o
obj-$(CONFIG_PINCTRL_IPQ8064) += pinctrl-ipq8064.o
+obj-$(CONFIG_PINCTRL_IPQ5332) += pinctrl-ipq5332.o
obj-$(CONFIG_PINCTRL_IPQ8074) += pinctrl-ipq8074.o
obj-$(CONFIG_PINCTRL_IPQ6018) += pinctrl-ipq6018.o
obj-$(CONFIG_PINCTRL_MSM8226) += pinctrl-msm8226.o
@@ -27,6 +28,8 @@ obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-gpio.o
obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-mpp.o
obj-$(CONFIG_PINCTRL_QCOM_SSBI_PMIC) += pinctrl-ssbi-gpio.o
obj-$(CONFIG_PINCTRL_QCOM_SSBI_PMIC) += pinctrl-ssbi-mpp.o
+obj-$(CONFIG_PINCTRL_QDU1000) += pinctrl-qdu1000.o
+obj-$(CONFIG_PINCTRL_SA8775P) += pinctrl-sa8775p.o
obj-$(CONFIG_PINCTRL_SC7180) += pinctrl-sc7180.o
obj-$(CONFIG_PINCTRL_SC7280) += pinctrl-sc7280.o
obj-$(CONFIG_PINCTRL_SC7280_LPASS_LPI) += pinctrl-sc7280-lpass-lpi.o
@@ -47,5 +50,7 @@ obj-$(CONFIG_PINCTRL_SM8250_LPASS_LPI) += pinctrl-sm8250-lpass-lpi.o
obj-$(CONFIG_PINCTRL_SM8350) += pinctrl-sm8350.o
obj-$(CONFIG_PINCTRL_SM8450) += pinctrl-sm8450.o
obj-$(CONFIG_PINCTRL_SM8450_LPASS_LPI) += pinctrl-sm8450-lpass-lpi.o
+obj-$(CONFIG_PINCTRL_SM8550) += pinctrl-sm8550.o
+obj-$(CONFIG_PINCTRL_SM8550_LPASS_LPI) += pinctrl-sm8550-lpass-lpi.o
obj-$(CONFIG_PINCTRL_SC8280XP_LPASS_LPI) += pinctrl-sc8280xp-lpass-lpi.o
obj-$(CONFIG_PINCTRL_LPASS_LPI) += pinctrl-lpass-lpi.o
diff --git a/drivers/pinctrl/qcom/pinctrl-ipq5332.c b/drivers/pinctrl/qcom/pinctrl-ipq5332.c
new file mode 100644
index 000000000000..e78d11292f42
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-ipq5332.c
@@ -0,0 +1,861 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/*
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-msm.h"
+
+#define FUNCTION(fname) \
+ [msm_mux_##fname] = { \
+ .name = #fname, \
+ .groups = fname##_groups, \
+ .ngroups = ARRAY_SIZE(fname##_groups), \
+ }
+
+#define REG_SIZE 0x1000
+#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9) \
+ { \
+ .name = "gpio" #id, \
+ .pins = gpio##id##_pins, \
+ .npins = (unsigned int)ARRAY_SIZE(gpio##id##_pins), \
+ .funcs = (int[]){ \
+ msm_mux_gpio, /* gpio mode */ \
+ msm_mux_##f1, \
+ msm_mux_##f2, \
+ msm_mux_##f3, \
+ msm_mux_##f4, \
+ msm_mux_##f5, \
+ msm_mux_##f6, \
+ msm_mux_##f7, \
+ msm_mux_##f8, \
+ msm_mux_##f9 \
+ }, \
+ .nfuncs = 10, \
+ .ctl_reg = REG_SIZE * id, \
+ .io_reg = 0x4 + REG_SIZE * id, \
+ .intr_cfg_reg = 0x8 + REG_SIZE * id, \
+ .intr_status_reg = 0xc + REG_SIZE * id, \
+ .intr_target_reg = 0x8 + REG_SIZE * id, \
+ .mux_bit = 2, \
+ .pull_bit = 0, \
+ .drv_bit = 6, \
+ .oe_bit = 9, \
+ .in_bit = 0, \
+ .out_bit = 1, \
+ .intr_enable_bit = 0, \
+ .intr_status_bit = 0, \
+ .intr_target_bit = 5, \
+ .intr_target_kpss_val = 3, \
+ .intr_raw_status_bit = 4, \
+ .intr_polarity_bit = 1, \
+ .intr_detection_bit = 2, \
+ .intr_detection_width = 2, \
+ }
+
+static const struct pinctrl_pin_desc ipq5332_pins[] = {
+ PINCTRL_PIN(0, "GPIO_0"),
+ PINCTRL_PIN(1, "GPIO_1"),
+ PINCTRL_PIN(2, "GPIO_2"),
+ PINCTRL_PIN(3, "GPIO_3"),
+ PINCTRL_PIN(4, "GPIO_4"),
+ PINCTRL_PIN(5, "GPIO_5"),
+ PINCTRL_PIN(6, "GPIO_6"),
+ PINCTRL_PIN(7, "GPIO_7"),
+ PINCTRL_PIN(8, "GPIO_8"),
+ PINCTRL_PIN(9, "GPIO_9"),
+ PINCTRL_PIN(10, "GPIO_10"),
+ PINCTRL_PIN(11, "GPIO_11"),
+ PINCTRL_PIN(12, "GPIO_12"),
+ PINCTRL_PIN(13, "GPIO_13"),
+ PINCTRL_PIN(14, "GPIO_14"),
+ PINCTRL_PIN(15, "GPIO_15"),
+ PINCTRL_PIN(16, "GPIO_16"),
+ PINCTRL_PIN(17, "GPIO_17"),
+ PINCTRL_PIN(18, "GPIO_18"),
+ PINCTRL_PIN(19, "GPIO_19"),
+ PINCTRL_PIN(20, "GPIO_20"),
+ PINCTRL_PIN(21, "GPIO_21"),
+ PINCTRL_PIN(22, "GPIO_22"),
+ PINCTRL_PIN(23, "GPIO_23"),
+ PINCTRL_PIN(24, "GPIO_24"),
+ PINCTRL_PIN(25, "GPIO_25"),
+ PINCTRL_PIN(26, "GPIO_26"),
+ PINCTRL_PIN(27, "GPIO_27"),
+ PINCTRL_PIN(28, "GPIO_28"),
+ PINCTRL_PIN(29, "GPIO_29"),
+ PINCTRL_PIN(30, "GPIO_30"),
+ PINCTRL_PIN(31, "GPIO_31"),
+ PINCTRL_PIN(32, "GPIO_32"),
+ PINCTRL_PIN(33, "GPIO_33"),
+ PINCTRL_PIN(34, "GPIO_34"),
+ PINCTRL_PIN(35, "GPIO_35"),
+ PINCTRL_PIN(36, "GPIO_36"),
+ PINCTRL_PIN(37, "GPIO_37"),
+ PINCTRL_PIN(38, "GPIO_38"),
+ PINCTRL_PIN(39, "GPIO_39"),
+ PINCTRL_PIN(40, "GPIO_40"),
+ PINCTRL_PIN(41, "GPIO_41"),
+ PINCTRL_PIN(42, "GPIO_42"),
+ PINCTRL_PIN(43, "GPIO_43"),
+ PINCTRL_PIN(44, "GPIO_44"),
+ PINCTRL_PIN(45, "GPIO_45"),
+ PINCTRL_PIN(46, "GPIO_46"),
+ PINCTRL_PIN(47, "GPIO_47"),
+ PINCTRL_PIN(48, "GPIO_48"),
+ PINCTRL_PIN(49, "GPIO_49"),
+ PINCTRL_PIN(50, "GPIO_50"),
+ PINCTRL_PIN(51, "GPIO_51"),
+ PINCTRL_PIN(52, "GPIO_52"),
+};
+
+#define DECLARE_MSM_GPIO_PINS(pin) \
+ static const unsigned int gpio##pin##_pins[] = { pin }
+DECLARE_MSM_GPIO_PINS(0);
+DECLARE_MSM_GPIO_PINS(1);
+DECLARE_MSM_GPIO_PINS(2);
+DECLARE_MSM_GPIO_PINS(3);
+DECLARE_MSM_GPIO_PINS(4);
+DECLARE_MSM_GPIO_PINS(5);
+DECLARE_MSM_GPIO_PINS(6);
+DECLARE_MSM_GPIO_PINS(7);
+DECLARE_MSM_GPIO_PINS(8);
+DECLARE_MSM_GPIO_PINS(9);
+DECLARE_MSM_GPIO_PINS(10);
+DECLARE_MSM_GPIO_PINS(11);
+DECLARE_MSM_GPIO_PINS(12);
+DECLARE_MSM_GPIO_PINS(13);
+DECLARE_MSM_GPIO_PINS(14);
+DECLARE_MSM_GPIO_PINS(15);
+DECLARE_MSM_GPIO_PINS(16);
+DECLARE_MSM_GPIO_PINS(17);
+DECLARE_MSM_GPIO_PINS(18);
+DECLARE_MSM_GPIO_PINS(19);
+DECLARE_MSM_GPIO_PINS(20);
+DECLARE_MSM_GPIO_PINS(21);
+DECLARE_MSM_GPIO_PINS(22);
+DECLARE_MSM_GPIO_PINS(23);
+DECLARE_MSM_GPIO_PINS(24);
+DECLARE_MSM_GPIO_PINS(25);
+DECLARE_MSM_GPIO_PINS(26);
+DECLARE_MSM_GPIO_PINS(27);
+DECLARE_MSM_GPIO_PINS(28);
+DECLARE_MSM_GPIO_PINS(29);
+DECLARE_MSM_GPIO_PINS(30);
+DECLARE_MSM_GPIO_PINS(31);
+DECLARE_MSM_GPIO_PINS(32);
+DECLARE_MSM_GPIO_PINS(33);
+DECLARE_MSM_GPIO_PINS(34);
+DECLARE_MSM_GPIO_PINS(35);
+DECLARE_MSM_GPIO_PINS(36);
+DECLARE_MSM_GPIO_PINS(37);
+DECLARE_MSM_GPIO_PINS(38);
+DECLARE_MSM_GPIO_PINS(39);
+DECLARE_MSM_GPIO_PINS(40);
+DECLARE_MSM_GPIO_PINS(41);
+DECLARE_MSM_GPIO_PINS(42);
+DECLARE_MSM_GPIO_PINS(43);
+DECLARE_MSM_GPIO_PINS(44);
+DECLARE_MSM_GPIO_PINS(45);
+DECLARE_MSM_GPIO_PINS(46);
+DECLARE_MSM_GPIO_PINS(47);
+DECLARE_MSM_GPIO_PINS(48);
+DECLARE_MSM_GPIO_PINS(49);
+DECLARE_MSM_GPIO_PINS(50);
+DECLARE_MSM_GPIO_PINS(51);
+DECLARE_MSM_GPIO_PINS(52);
+
+enum ipq5332_functions {
+ msm_mux_atest_char,
+ msm_mux_atest_char0,
+ msm_mux_atest_char1,
+ msm_mux_atest_char2,
+ msm_mux_atest_char3,
+ msm_mux_atest_tic,
+ msm_mux_audio_pri,
+ msm_mux_audio_pri0,
+ msm_mux_audio_pri1,
+ msm_mux_audio_sec,
+ msm_mux_audio_sec0,
+ msm_mux_audio_sec1,
+ msm_mux_blsp0_i2c,
+ msm_mux_blsp0_spi,
+ msm_mux_blsp0_uart0,
+ msm_mux_blsp0_uart1,
+ msm_mux_blsp1_i2c0,
+ msm_mux_blsp1_i2c1,
+ msm_mux_blsp1_spi0,
+ msm_mux_blsp1_spi1,
+ msm_mux_blsp1_uart0,
+ msm_mux_blsp1_uart1,
+ msm_mux_blsp1_uart2,
+ msm_mux_blsp2_i2c0,
+ msm_mux_blsp2_i2c1,
+ msm_mux_blsp2_spi,
+ msm_mux_blsp2_spi0,
+ msm_mux_blsp2_spi1,
+ msm_mux_core_voltage,
+ msm_mux_cri_trng0,
+ msm_mux_cri_trng1,
+ msm_mux_cri_trng2,
+ msm_mux_cri_trng3,
+ msm_mux_cxc_clk,
+ msm_mux_cxc_data,
+ msm_mux_dbg_out,
+ msm_mux_gcc_plltest,
+ msm_mux_gcc_tlmm,
+ msm_mux_gpio,
+ msm_mux_lock_det,
+ msm_mux_mac0,
+ msm_mux_mac1,
+ msm_mux_mdc0,
+ msm_mux_mdc1,
+ msm_mux_mdio0,
+ msm_mux_mdio1,
+ msm_mux_pc,
+ msm_mux_pcie0_clk,
+ msm_mux_pcie0_wake,
+ msm_mux_pcie1_clk,
+ msm_mux_pcie1_wake,
+ msm_mux_pcie2_clk,
+ msm_mux_pcie2_wake,
+ msm_mux_pll_test,
+ msm_mux_prng_rosc0,
+ msm_mux_prng_rosc1,
+ msm_mux_prng_rosc2,
+ msm_mux_prng_rosc3,
+ msm_mux_pta,
+ msm_mux_pwm0,
+ msm_mux_pwm1,
+ msm_mux_pwm2,
+ msm_mux_pwm3,
+ msm_mux_qdss_cti_trig_in_a0,
+ msm_mux_qdss_cti_trig_in_a1,
+ msm_mux_qdss_cti_trig_in_b0,
+ msm_mux_qdss_cti_trig_in_b1,
+ msm_mux_qdss_cti_trig_out_a0,
+ msm_mux_qdss_cti_trig_out_a1,
+ msm_mux_qdss_cti_trig_out_b0,
+ msm_mux_qdss_cti_trig_out_b1,
+ msm_mux_qdss_traceclk_a,
+ msm_mux_qdss_traceclk_b,
+ msm_mux_qdss_tracectl_a,
+ msm_mux_qdss_tracectl_b,
+ msm_mux_qdss_tracedata_a,
+ msm_mux_qdss_tracedata_b,
+ msm_mux_qspi_data,
+ msm_mux_qspi_clk,
+ msm_mux_qspi_cs,
+ msm_mux_resout,
+ msm_mux_rx0,
+ msm_mux_rx1,
+ msm_mux_sdc_data,
+ msm_mux_sdc_clk,
+ msm_mux_sdc_cmd,
+ msm_mux_tsens_max,
+ msm_mux_wci_txd,
+ msm_mux_wci_rxd,
+ msm_mux_wsi_clk,
+ msm_mux_wsi_clk3,
+ msm_mux_wsi_data,
+ msm_mux_wsi_data3,
+ msm_mux_wsis_reset,
+ msm_mux_xfem,
+ msm_mux__,
+};
+
+static const char * const gpio_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7",
+ "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14",
+ "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21",
+ "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28",
+ "gpio29", "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35",
+ "gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42",
+ "gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", "gpio49",
+ "gpio50", "gpio51", "gpio52",
+};
+
+static const char * const atest_char_groups[] = {
+ "gpio46",
+};
+
+static const char * const atest_char0_groups[] = {
+ "gpio0",
+};
+
+static const char * const atest_char1_groups[] = {
+ "gpio1",
+};
+
+static const char * const atest_char2_groups[] = {
+ "gpio2",
+};
+
+static const char * const atest_char3_groups[] = {
+ "gpio3",
+};
+
+static const char * const atest_tic_groups[] = {
+ "gpio9",
+};
+
+static const char * const audio_pri_groups[] = {
+ "gpio29", "gpio30", "gpio31", "gpio32",
+};
+
+static const char * const audio_pri0_groups[] = {
+ "gpio34", "gpio34",
+};
+
+static const char * const audio_pri1_groups[] = {
+ "gpio43", "gpio43",
+};
+
+static const char * const audio_sec_groups[] = {
+ "gpio33", "gpio34", "gpio35", "gpio36",
+};
+
+static const char * const audio_sec0_groups[] = {
+ "gpio30", "gpio30",
+};
+
+static const char * const audio_sec1_groups[] = {
+ "gpio45", "gpio45",
+};
+
+static const char * const blsp0_i2c_groups[] = {
+ "gpio16", "gpio17",
+};
+
+static const char * const blsp0_spi_groups[] = {
+ "gpio14", "gpio15", "gpio16", "gpio17",
+};
+
+static const char * const blsp0_uart0_groups[] = {
+ "gpio18", "gpio19",
+};
+
+static const char * const blsp0_uart1_groups[] = {
+ "gpio27", "gpio28",
+};
+
+static const char * const blsp1_i2c0_groups[] = {
+ "gpio29", "gpio30",
+};
+
+static const char * const blsp1_i2c1_groups[] = {
+ "gpio40", "gpio41",
+};
+
+static const char * const blsp1_spi0_groups[] = {
+ "gpio29", "gpio30", "gpio31", "gpio32",
+};
+
+static const char * const blsp1_spi1_groups[] = {
+ "gpio25", "gpio26", "gpio27", "gpio28",
+};
+
+static const char * const blsp1_uart0_groups[] = {
+ "gpio14", "gpio15", "gpio16", "gpio17",
+};
+
+static const char * const blsp1_uart1_groups[] = {
+ "gpio25", "gpio26", "gpio27", "gpio28",
+};
+
+static const char * const blsp1_uart2_groups[] = {
+ "gpio33", "gpio34", "gpio35", "gpio36",
+};
+
+static const char * const blsp2_i2c0_groups[] = {
+ "gpio43", "gpio45",
+};
+
+static const char * const blsp2_i2c1_groups[] = {
+ "gpio33", "gpio34",
+};
+
+static const char * const blsp2_spi_groups[] = {
+ "gpio37",
+};
+
+static const char * const blsp2_spi0_groups[] = {
+ "gpio33", "gpio34", "gpio35", "gpio36",
+};
+
+static const char * const blsp2_spi1_groups[] = {
+ "gpio40", "gpio41", "gpio42", "gpio52",
+};
+
+static const char * const core_voltage_groups[] = {
+ "gpio21", "gpio23",
+};
+
+static const char * const cri_trng0_groups[] = {
+ "gpio17",
+};
+
+static const char * const cri_trng1_groups[] = {
+ "gpio18",
+};
+
+static const char * const cri_trng2_groups[] = {
+ "gpio19",
+};
+
+static const char * const cri_trng3_groups[] = {
+ "gpio20",
+};
+
+static const char * const cxc_clk_groups[] = {
+ "gpio49",
+};
+
+static const char * const cxc_data_groups[] = {
+ "gpio50",
+};
+
+static const char * const dbg_out_groups[] = {
+ "gpio48",
+};
+
+static const char * const gcc_plltest_groups[] = {
+ "gpio43", "gpio45",
+};
+
+static const char * const gcc_tlmm_groups[] = {
+ "gpio44",
+};
+
+static const char * const lock_det_groups[] = {
+ "gpio51",
+};
+
+static const char * const mac0_groups[] = {
+ "gpio18",
+};
+
+static const char * const mac1_groups[] = {
+ "gpio19",
+};
+
+static const char * const mdc0_groups[] = {
+ "gpio25",
+};
+
+static const char * const mdc1_groups[] = {
+ "gpio27",
+};
+
+static const char * const mdio0_groups[] = {
+ "gpio26",
+};
+
+static const char * const mdio1_groups[] = {
+ "gpio28",
+};
+
+static const char * const pc_groups[] = {
+ "gpio35",
+};
+
+static const char * const pcie0_clk_groups[] = {
+ "gpio37",
+};
+
+static const char * const pcie0_wake_groups[] = {
+ "gpio39",
+};
+
+static const char * const pcie1_clk_groups[] = {
+ "gpio46",
+};
+
+static const char * const pcie1_wake_groups[] = {
+ "gpio48",
+};
+
+static const char * const pcie2_clk_groups[] = {
+ "gpio43",
+};
+
+static const char * const pcie2_wake_groups[] = {
+ "gpio45",
+};
+
+static const char * const pll_test_groups[] = {
+ "gpio49",
+};
+
+static const char * const prng_rosc0_groups[] = {
+ "gpio22",
+};
+
+static const char * const prng_rosc1_groups[] = {
+ "gpio24",
+};
+
+static const char * const prng_rosc2_groups[] = {
+ "gpio25",
+};
+
+static const char * const prng_rosc3_groups[] = {
+ "gpio26",
+};
+
+static const char * const pta_groups[] = {
+ "gpio49", "gpio50", "gpio51",
+};
+
+static const char * const pwm0_groups[] = {
+ "gpio43", "gpio44", "gpio45", "gpio46",
+};
+
+static const char * const pwm1_groups[] = {
+ "gpio29", "gpio30", "gpio31", "gpio32",
+};
+
+static const char * const pwm2_groups[] = {
+ "gpio25", "gpio26", "gpio27", "gpio28",
+};
+
+static const char * const pwm3_groups[] = {
+ "gpio8", "gpio9", "gpio10", "gpio11",
+};
+
+static const char * const qdss_cti_trig_in_a0_groups[] = {
+ "gpio5",
+};
+
+static const char * const qdss_cti_trig_in_a1_groups[] = {
+ "gpio7",
+};
+
+static const char * const qdss_cti_trig_in_b0_groups[] = {
+ "gpio47",
+};
+
+static const char * const qdss_cti_trig_in_b1_groups[] = {
+ "gpio49",
+};
+
+static const char * const qdss_cti_trig_out_a0_groups[] = {
+ "gpio4",
+};
+
+static const char * const qdss_cti_trig_out_a1_groups[] = {
+ "gpio6",
+};
+
+static const char * const qdss_cti_trig_out_b0_groups[] = {
+ "gpio46",
+};
+
+static const char * const qdss_cti_trig_out_b1_groups[] = {
+ "gpio48",
+};
+
+static const char * const qdss_traceclk_a_groups[] = {
+ "gpio8",
+};
+
+static const char * const qdss_traceclk_b_groups[] = {
+ "gpio45",
+};
+
+static const char * const qdss_tracectl_a_groups[] = {
+ "gpio9",
+};
+
+static const char * const qdss_tracectl_b_groups[] = {
+ "gpio44",
+};
+
+static const char * const qdss_tracedata_a_groups[] = {
+ "gpio10", "gpio11", "gpio12", "gpio13", "gpio14", "gpio15", "gpio16",
+ "gpio17", "gpio18", "gpio19", "gpio20", "gpio22", "gpio24", "gpio25",
+ "gpio26", "gpio27",
+};
+
+static const char * const qdss_tracedata_b_groups[] = {
+ "gpio29", "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35",
+ "gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42",
+ "gpio43", "gpio52",
+};
+
+static const char * const qspi_clk_groups[] = {
+ "gpio13",
+};
+
+static const char * const qspi_cs_groups[] = {
+ "gpio12",
+};
+
+static const char * const qspi_data_groups[] = {
+ "gpio8", "gpio9", "gpio10", "gpio11",
+};
+
+static const char * const resout_groups[] = {
+ "gpio20",
+};
+
+static const char * const rx0_groups[] = {
+ "gpio48",
+};
+
+static const char * const rx1_groups[] = {
+ "gpio45",
+};
+
+static const char * const sdc_clk_groups[] = {
+ "gpio13",
+};
+
+static const char * const sdc_cmd_groups[] = {
+ "gpio12",
+};
+
+static const char * const sdc_data_groups[] = {
+ "gpio8", "gpio9", "gpio10", "gpio11",
+};
+
+static const char * const tsens_max_groups[] = {
+ "gpio28",
+};
+
+static const char * const wci_txd_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7",
+ "gpio36", "gpio43", "gpio45",
+};
+
+static const char * const wci_rxd_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7",
+ "gpio35", "gpio36", "gpio43", "gpio45",
+};
+
+static const char * const wsi_clk_groups[] = {
+ "gpio40", "gpio42",
+};
+
+static const char * const wsi_clk3_groups[] = {
+ "gpio43",
+};
+
+static const char * const wsi_data_groups[] = {
+ "gpio41", "gpio52",
+};
+
+static const char * const wsi_data3_groups[] = {
+ "gpio44",
+};
+
+static const char * const wsis_reset_groups[] = {
+ "gpio41",
+};
+
+static const char * const xfem_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7",
+};
+
+static const struct msm_function ipq5332_functions[] = {
+ FUNCTION(atest_char),
+ FUNCTION(atest_char0),
+ FUNCTION(atest_char1),
+ FUNCTION(atest_char2),
+ FUNCTION(atest_char3),
+ FUNCTION(atest_tic),
+ FUNCTION(audio_pri),
+ FUNCTION(audio_pri0),
+ FUNCTION(audio_pri1),
+ FUNCTION(audio_sec),
+ FUNCTION(audio_sec0),
+ FUNCTION(audio_sec1),
+ FUNCTION(blsp0_i2c),
+ FUNCTION(blsp0_spi),
+ FUNCTION(blsp0_uart0),
+ FUNCTION(blsp0_uart1),
+ FUNCTION(blsp1_i2c0),
+ FUNCTION(blsp1_i2c1),
+ FUNCTION(blsp1_spi0),
+ FUNCTION(blsp1_spi1),
+ FUNCTION(blsp1_uart0),
+ FUNCTION(blsp1_uart1),
+ FUNCTION(blsp1_uart2),
+ FUNCTION(blsp2_i2c0),
+ FUNCTION(blsp2_i2c1),
+ FUNCTION(blsp2_spi),
+ FUNCTION(blsp2_spi0),
+ FUNCTION(blsp2_spi1),
+ FUNCTION(core_voltage),
+ FUNCTION(cri_trng0),
+ FUNCTION(cri_trng1),
+ FUNCTION(cri_trng2),
+ FUNCTION(cri_trng3),
+ FUNCTION(cxc_clk),
+ FUNCTION(cxc_data),
+ FUNCTION(dbg_out),
+ FUNCTION(gcc_plltest),
+ FUNCTION(gcc_tlmm),
+ FUNCTION(gpio),
+ FUNCTION(lock_det),
+ FUNCTION(mac0),
+ FUNCTION(mac1),
+ FUNCTION(mdc0),
+ FUNCTION(mdc1),
+ FUNCTION(mdio0),
+ FUNCTION(mdio1),
+ FUNCTION(pc),
+ FUNCTION(pcie0_clk),
+ FUNCTION(pcie0_wake),
+ FUNCTION(pcie1_clk),
+ FUNCTION(pcie1_wake),
+ FUNCTION(pcie2_clk),
+ FUNCTION(pcie2_wake),
+ FUNCTION(pll_test),
+ FUNCTION(prng_rosc0),
+ FUNCTION(prng_rosc1),
+ FUNCTION(prng_rosc2),
+ FUNCTION(prng_rosc3),
+ FUNCTION(pta),
+ FUNCTION(pwm0),
+ FUNCTION(pwm1),
+ FUNCTION(pwm2),
+ FUNCTION(pwm3),
+ FUNCTION(qdss_cti_trig_in_a0),
+ FUNCTION(qdss_cti_trig_in_a1),
+ FUNCTION(qdss_cti_trig_in_b0),
+ FUNCTION(qdss_cti_trig_in_b1),
+ FUNCTION(qdss_cti_trig_out_a0),
+ FUNCTION(qdss_cti_trig_out_a1),
+ FUNCTION(qdss_cti_trig_out_b0),
+ FUNCTION(qdss_cti_trig_out_b1),
+ FUNCTION(qdss_traceclk_a),
+ FUNCTION(qdss_traceclk_b),
+ FUNCTION(qdss_tracectl_a),
+ FUNCTION(qdss_tracectl_b),
+ FUNCTION(qdss_tracedata_a),
+ FUNCTION(qdss_tracedata_b),
+ FUNCTION(qspi_data),
+ FUNCTION(qspi_clk),
+ FUNCTION(qspi_cs),
+ FUNCTION(resout),
+ FUNCTION(rx0),
+ FUNCTION(rx1),
+ FUNCTION(sdc_data),
+ FUNCTION(sdc_clk),
+ FUNCTION(sdc_cmd),
+ FUNCTION(tsens_max),
+ FUNCTION(wci_txd),
+ FUNCTION(wci_rxd),
+ FUNCTION(wsi_clk),
+ FUNCTION(wsi_clk3),
+ FUNCTION(wsi_data),
+ FUNCTION(wsi_data3),
+ FUNCTION(wsis_reset),
+ FUNCTION(xfem),
+};
+
+static const struct msm_pingroup ipq5332_groups[] = {
+ PINGROUP(0, atest_char0, wci_txd, wci_rxd, xfem, _, _, _, _, _),
+ PINGROUP(1, atest_char1, wci_txd, wci_rxd, xfem, _, _, _, _, _),
+ PINGROUP(2, atest_char2, wci_txd, wci_rxd, xfem, _, _, _, _, _),
+ PINGROUP(3, atest_char3, wci_txd, wci_rxd, xfem, _, _, _, _, _),
+ PINGROUP(4, qdss_cti_trig_out_a0, wci_txd, wci_rxd, xfem, _, _, _, _, _),
+ PINGROUP(5, qdss_cti_trig_in_a0, wci_txd, wci_rxd, xfem, _, _, _, _, _),
+ PINGROUP(6, qdss_cti_trig_out_a1, wci_txd, wci_rxd, xfem, _, _, _, _, _),
+ PINGROUP(7, qdss_cti_trig_in_a1, wci_txd, wci_rxd, xfem, _, _, _, _, _),
+ PINGROUP(8, sdc_data, qspi_data, pwm3, qdss_traceclk_a, _, _, _, _, _),
+ PINGROUP(9, sdc_data, qspi_data, pwm3, qdss_tracectl_a, _, atest_tic, _, _, _),
+ PINGROUP(10, sdc_data, qspi_data, pwm3, qdss_tracedata_a, _, _, _, _, _),
+ PINGROUP(11, sdc_data, qspi_data, pwm3, qdss_tracedata_a, _, _, _, _, _),
+ PINGROUP(12, sdc_cmd, qspi_cs, qdss_tracedata_a, _, _, _, _, _, _),
+ PINGROUP(13, sdc_clk, qspi_clk, qdss_tracedata_a, _, _, _, _, _, _),
+ PINGROUP(14, blsp0_spi, blsp1_uart0, qdss_tracedata_a, _, _, _, _, _, _),
+ PINGROUP(15, blsp0_spi, blsp1_uart0, qdss_tracedata_a, _, _, _, _, _, _),
+ PINGROUP(16, blsp0_spi, blsp0_i2c, blsp1_uart0, _, qdss_tracedata_a, _, _, _, _),
+ PINGROUP(17, blsp0_spi, blsp0_i2c, blsp1_uart0, _, cri_trng0, qdss_tracedata_a, _, _, _),
+ PINGROUP(18, blsp0_uart0, mac0, _, cri_trng1, qdss_tracedata_a, _, _, _, _),
+ PINGROUP(19, blsp0_uart0, mac1, _, cri_trng2, qdss_tracedata_a, _, _, _, _),
+ PINGROUP(20, resout, _, cri_trng3, qdss_tracedata_a, _, _, _, _, _),
+ PINGROUP(21, core_voltage, _, _, _, _, _, _, _, _),
+ PINGROUP(22, _, prng_rosc0, qdss_tracedata_a, _, _, _, _, _, _),
+ PINGROUP(23, core_voltage, _, _, _, _, _, _, _, _),
+ PINGROUP(24, _, prng_rosc1, qdss_tracedata_a, _, _, _, _, _, _),
+ PINGROUP(25, mdc0, blsp1_uart1, blsp1_spi1, pwm2, _, _, prng_rosc2, qdss_tracedata_a, _),
+ PINGROUP(26, mdio0, blsp1_uart1, blsp1_spi1, pwm2, _, _, prng_rosc3, qdss_tracedata_a, _),
+ PINGROUP(27, mdc1, blsp0_uart1, blsp1_uart1, blsp1_spi1, pwm2, _, _, qdss_tracedata_a, _),
+ PINGROUP(28, mdio1, blsp0_uart1, blsp1_uart1, blsp1_spi1, pwm2, _, tsens_max, _, _),
+ PINGROUP(29, audio_pri, blsp1_spi0, blsp1_i2c0, pwm1, _, qdss_tracedata_b, _, _, _),
+ PINGROUP(30, audio_pri, blsp1_spi0, blsp1_i2c0, pwm1, audio_sec0, audio_sec0, _, qdss_tracedata_b, _),
+ PINGROUP(31, audio_pri, blsp1_spi0, pwm1, _, qdss_tracedata_b, _, _, _, _),
+ PINGROUP(32, audio_pri, blsp1_spi0, pwm1, _, qdss_tracedata_b, _, _, _, _),
+ PINGROUP(33, audio_sec, blsp1_uart2, blsp2_i2c1, blsp2_spi0, _, qdss_tracedata_b, _, _, _),
+ PINGROUP(34, audio_sec, blsp1_uart2, blsp2_i2c1, blsp2_spi0, audio_pri0, audio_pri0, _, qdss_tracedata_b, _),
+ PINGROUP(35, audio_sec, blsp1_uart2, pc, wci_rxd, blsp2_spi0, _, qdss_tracedata_b, _, _),
+ PINGROUP(36, audio_sec, blsp1_uart2, wci_txd, wci_rxd, blsp2_spi0, _, qdss_tracedata_b, _, _),
+ PINGROUP(37, pcie0_clk, blsp2_spi, _, qdss_tracedata_b, _, _, _, _, _),
+ PINGROUP(38, _, qdss_tracedata_b, _, _, _, _, _, _, _),
+ PINGROUP(39, pcie0_wake, _, qdss_tracedata_b, _, _, _, _, _, _),
+ PINGROUP(40, wsi_clk, blsp1_i2c1, blsp2_spi1, _, _, qdss_tracedata_b, _, _, _),
+ PINGROUP(41, wsi_data, blsp1_i2c1, blsp2_spi1, _, _, qdss_tracedata_b, _, wsis_reset, _),
+ PINGROUP(42, wsi_clk, blsp2_spi1, _, qdss_tracedata_b, _, _, _, _, _),
+ PINGROUP(43, pcie2_clk, wci_txd, wci_rxd, blsp2_i2c0, pwm0, audio_pri1, audio_pri1, _, gcc_plltest),
+ PINGROUP(44, pwm0, _, gcc_tlmm, qdss_tracectl_b, _, wsi_data3, _, _, _),
+ PINGROUP(45, pcie2_wake, wci_txd, wci_rxd, blsp2_i2c0, rx1, pwm0, audio_sec1, audio_sec1, _),
+ PINGROUP(46, pcie1_clk, atest_char, pwm0, _, qdss_cti_trig_out_b0, _, _, _, _),
+ PINGROUP(47, _, qdss_cti_trig_in_b0, _, _, _, _, _, _, _),
+ PINGROUP(48, pcie1_wake, rx0, dbg_out, qdss_cti_trig_out_b1, _, _, _, _, _),
+ PINGROUP(49, pta, cxc_clk, pll_test, _, qdss_cti_trig_in_b1, _, _, _, _),
+ PINGROUP(50, pta, cxc_data, _, _, _, _, _, _, _),
+ PINGROUP(51, pta, lock_det, _, _, _, _, _, _, _),
+ PINGROUP(52, wsi_data, blsp2_spi1, _, qdss_tracedata_b, _, _, _, _, _),
+};
+
+static const struct msm_pinctrl_soc_data ipq5332_pinctrl = {
+ .pins = ipq5332_pins,
+ .npins = ARRAY_SIZE(ipq5332_pins),
+ .functions = ipq5332_functions,
+ .nfunctions = ARRAY_SIZE(ipq5332_functions),
+ .groups = ipq5332_groups,
+ .ngroups = ARRAY_SIZE(ipq5332_groups),
+ .ngpios = 53,
+};
+
+static int ipq5332_pinctrl_probe(struct platform_device *pdev)
+{
+ return msm_pinctrl_probe(pdev, &ipq5332_pinctrl);
+}
+
+static const struct of_device_id ipq5332_pinctrl_of_match[] = {
+ { .compatible = "qcom,ipq5332-tlmm", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, ipq5332_pinctrl_of_match);
+
+static struct platform_driver ipq5332_pinctrl_driver = {
+ .driver = {
+ .name = "ipq5332-tlmm",
+ .of_match_table = ipq5332_pinctrl_of_match,
+ },
+ .probe = ipq5332_pinctrl_probe,
+ .remove = msm_pinctrl_remove,
+};
+
+static int __init ipq5332_pinctrl_init(void)
+{
+ return platform_driver_register(&ipq5332_pinctrl_driver);
+}
+arch_initcall(ipq5332_pinctrl_init);
+
+static void __exit ipq5332_pinctrl_exit(void)
+{
+ platform_driver_unregister(&ipq5332_pinctrl_driver);
+}
+module_exit(ipq5332_pinctrl_exit);
+
+MODULE_DESCRIPTION("QTI IPQ5332 TLMM driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c
index 3dc670faa59e..87920257bb73 100644
--- a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c
+++ b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c
@@ -430,7 +430,6 @@ int lpi_pinctrl_probe(struct platform_device *pdev)
pctrl->chip.base = -1;
pctrl->chip.ngpio = data->npins;
pctrl->chip.label = dev_name(dev);
- pctrl->chip.of_gpio_n_cells = 2;
pctrl->chip.can_sleep = false;
mutex_init(&pctrl->slew_access_lock);
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c
index 47e9a8b0d474..daeb79a9a602 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm.c
@@ -14,7 +14,7 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/reboot.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
@@ -310,6 +310,8 @@ static int msm_config_reg(struct msm_pinctrl *pctrl,
case PIN_CONFIG_BIAS_PULL_UP:
*bit = g->pull_bit;
*mask = 3;
+ if (g->i2c_pull_bit)
+ *mask |= BIT(g->i2c_pull_bit) >> *bit;
break;
case PIN_CONFIG_DRIVE_OPEN_DRAIN:
*bit = g->od_bit;
@@ -336,6 +338,7 @@ static int msm_config_reg(struct msm_pinctrl *pctrl,
#define MSM_KEEPER 2
#define MSM_PULL_UP_NO_KEEPER 2
#define MSM_PULL_UP 3
+#define MSM_I2C_STRONG_PULL_UP 2200
static unsigned msm_regval_to_drive(u32 val)
{
@@ -387,6 +390,8 @@ static int msm_config_group_get(struct pinctrl_dev *pctldev,
case PIN_CONFIG_BIAS_PULL_UP:
if (pctrl->soc->pull_no_keeper)
arg = arg == MSM_PULL_UP_NO_KEEPER;
+ else if (arg & BIT(g->i2c_pull_bit))
+ arg = MSM_I2C_STRONG_PULL_UP;
else
arg = arg == MSM_PULL_UP;
if (!arg)
@@ -467,6 +472,8 @@ static int msm_config_group_set(struct pinctrl_dev *pctldev,
case PIN_CONFIG_BIAS_PULL_UP:
if (pctrl->soc->pull_no_keeper)
arg = MSM_PULL_UP_NO_KEEPER;
+ else if (g->i2c_pull_bit && arg == MSM_I2C_STRONG_PULL_UP)
+ arg = BIT(g->i2c_pull_bit) | MSM_PULL_UP;
else
arg = MSM_PULL_UP;
break;
@@ -1350,7 +1357,7 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
girq = &chip->irq;
gpio_irq_chip_set_chip(girq, &msm_gpio_irq_chip);
girq->parent_handler = msm_gpio_irq_handler;
- girq->fwnode = pctrl->dev->fwnode;
+ girq->fwnode = dev_fwnode(pctrl->dev);
girq->num_parents = 1;
girq->parents = devm_kcalloc(pctrl->dev, 1, sizeof(*girq->parents),
GFP_KERNEL);
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.h b/drivers/pinctrl/qcom/pinctrl-msm.h
index 05a1209bf9ae..985eceda2517 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.h
+++ b/drivers/pinctrl/qcom/pinctrl-msm.h
@@ -80,6 +80,7 @@ struct msm_pingroup {
unsigned pull_bit:5;
unsigned drv_bit:5;
+ unsigned i2c_pull_bit:5;
unsigned od_bit:5;
unsigned egpio_enable:5;
diff --git a/drivers/pinctrl/qcom/pinctrl-msm8226.c b/drivers/pinctrl/qcom/pinctrl-msm8226.c
index fca0645e8008..0f05725e0a21 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm8226.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm8226.c
@@ -362,6 +362,8 @@ enum msm8226_functions {
MSM_MUX_cam_mclk0,
MSM_MUX_cam_mclk1,
MSM_MUX_cci_i2c0,
+ MSM_MUX_gp0_clk,
+ MSM_MUX_gp1_clk,
MSM_MUX_gpio,
MSM_MUX_sdc3,
MSM_MUX_wlan,
@@ -447,6 +449,9 @@ static const char * const cci_i2c0_groups[] = { "gpio29", "gpio30" };
static const char * const cam_mclk0_groups[] = { "gpio26" };
static const char * const cam_mclk1_groups[] = { "gpio27" };
+static const char * const gp0_clk_groups[] = { "gpio33" };
+static const char * const gp1_clk_groups[] = { "gpio34" };
+
static const char * const sdc3_groups[] = {
"gpio39", "gpio40", "gpio41", "gpio42", "gpio43", "gpio44"
};
@@ -480,6 +485,8 @@ static const struct msm_function msm8226_functions[] = {
FUNCTION(cam_mclk0),
FUNCTION(cam_mclk1),
FUNCTION(cci_i2c0),
+ FUNCTION(gp0_clk),
+ FUNCTION(gp1_clk),
FUNCTION(gpio),
FUNCTION(sdc3),
FUNCTION(wlan),
@@ -519,8 +526,8 @@ static const struct msm_pingroup msm8226_groups[] = {
PINGROUP(30, cci_i2c0, NA, NA, NA, NA, NA, NA),
PINGROUP(31, NA, NA, NA, NA, NA, NA, NA),
PINGROUP(32, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(33, NA, NA, NA, NA, NA, NA, NA),
- PINGROUP(34, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(33, NA, NA, gp0_clk, NA, NA, NA, NA),
+ PINGROUP(34, NA, NA, gp1_clk, NA, NA, NA, NA),
PINGROUP(35, NA, NA, NA, NA, NA, NA, NA),
PINGROUP(36, NA, NA, NA, NA, NA, NA, NA),
PINGROUP(37, NA, NA, NA, NA, NA, NA, NA),
diff --git a/drivers/pinctrl/qcom/pinctrl-msm8976.c b/drivers/pinctrl/qcom/pinctrl-msm8976.c
index ec43edf9b660..e11d84584719 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm8976.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm8976.c
@@ -733,7 +733,7 @@ static const char * const codec_int2_groups[] = {
"gpio74",
};
static const char * const wcss_bt_groups[] = {
- "gpio39", "gpio47", "gpio88",
+ "gpio39", "gpio47", "gpio48",
};
static const char * const sdc3_groups[] = {
"gpio39", "gpio40", "gpio41",
@@ -958,9 +958,9 @@ static const struct msm_pingroup msm8976_groups[] = {
PINGROUP(37, NA, NA, NA, qdss_tracedata_b, NA, NA, NA, NA, NA),
PINGROUP(38, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_b, NA),
PINGROUP(39, wcss_bt, sdc3, NA, qdss_tracedata_a, NA, NA, NA, NA, NA),
- PINGROUP(40, wcss_wlan, sdc3, NA, qdss_tracedata_a, NA, NA, NA, NA, NA),
- PINGROUP(41, wcss_wlan, sdc3, NA, qdss_tracedata_a, NA, NA, NA, NA, NA),
- PINGROUP(42, wcss_wlan, sdc3, NA, qdss_tracedata_a, NA, NA, NA, NA, NA),
+ PINGROUP(40, wcss_wlan2, sdc3, NA, qdss_tracedata_a, NA, NA, NA, NA, NA),
+ PINGROUP(41, wcss_wlan1, sdc3, NA, qdss_tracedata_a, NA, NA, NA, NA, NA),
+ PINGROUP(42, wcss_wlan0, sdc3, NA, qdss_tracedata_a, NA, NA, NA, NA, NA),
PINGROUP(43, wcss_wlan, sdc3, NA, NA, qdss_tracedata_a, NA, NA, NA, NA),
PINGROUP(44, wcss_wlan, sdc3, NA, NA, NA, NA, NA, NA, NA),
PINGROUP(45, wcss_fm, NA, qdss_tracectl_a, NA, NA, NA, NA, NA, NA),
diff --git a/drivers/pinctrl/qcom/pinctrl-qdu1000.c b/drivers/pinctrl/qcom/pinctrl-qdu1000.c
new file mode 100644
index 000000000000..b1d7674a2bec
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-qdu1000.c
@@ -0,0 +1,1274 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-msm.h"
+
+#define FUNCTION(fname) \
+ [msm_mux_##fname] = { \
+ .name = #fname, \
+ .groups = fname##_groups, \
+ .ngroups = ARRAY_SIZE(fname##_groups), \
+ }
+
+#define REG_BASE 0x100000
+#define REG_SIZE 0x1000
+#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9) \
+ { \
+ .name = "gpio" #id, \
+ .pins = gpio##id##_pins, \
+ .npins = (unsigned int)ARRAY_SIZE(gpio##id##_pins), \
+ .funcs = (int[]){ \
+ msm_mux_gpio, /* gpio mode */ \
+ msm_mux_##f1, \
+ msm_mux_##f2, \
+ msm_mux_##f3, \
+ msm_mux_##f4, \
+ msm_mux_##f5, \
+ msm_mux_##f6, \
+ msm_mux_##f7, \
+ msm_mux_##f8, \
+ msm_mux_##f9 \
+ }, \
+ .nfuncs = 10, \
+ .ctl_reg = REG_BASE + REG_SIZE * id, \
+ .io_reg = REG_BASE + 0x4 + REG_SIZE * id, \
+ .intr_cfg_reg = REG_BASE + 0x8 + REG_SIZE * id, \
+ .intr_status_reg = REG_BASE + 0xc + REG_SIZE * id, \
+ .intr_target_reg = REG_BASE + 0x8 + REG_SIZE * id, \
+ .mux_bit = 2, \
+ .pull_bit = 0, \
+ .drv_bit = 6, \
+ .oe_bit = 9, \
+ .in_bit = 0, \
+ .out_bit = 1, \
+ .intr_enable_bit = 0, \
+ .intr_status_bit = 0, \
+ .intr_target_bit = 5, \
+ .intr_target_kpss_val = 3, \
+ .intr_raw_status_bit = 4, \
+ .intr_polarity_bit = 1, \
+ .intr_detection_bit = 2, \
+ .intr_detection_width = 2, \
+ }
+
+#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \
+ { \
+ .name = #pg_name, \
+ .pins = pg_name##_pins, \
+ .npins = (unsigned int)ARRAY_SIZE(pg_name##_pins), \
+ .ctl_reg = REG_BASE + ctl, \
+ .io_reg = 0, \
+ .intr_cfg_reg = 0, \
+ .intr_status_reg = 0, \
+ .intr_target_reg = 0, \
+ .mux_bit = -1, \
+ .pull_bit = pull, \
+ .drv_bit = drv, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = -1, \
+ .intr_enable_bit = -1, \
+ .intr_status_bit = -1, \
+ .intr_target_bit = -1, \
+ .intr_raw_status_bit = -1, \
+ .intr_polarity_bit = -1, \
+ .intr_detection_bit = -1, \
+ .intr_detection_width = -1, \
+ }
+
+#define UFS_RESET(pg_name, offset) \
+ { \
+ .name = #pg_name, \
+ .pins = pg_name##_pins, \
+ .npins = (unsigned int)ARRAY_SIZE(pg_name##_pins), \
+ .ctl_reg = offset, \
+ .io_reg = offset + 0x4, \
+ .intr_cfg_reg = 0, \
+ .intr_status_reg = 0, \
+ .intr_target_reg = 0, \
+ .mux_bit = -1, \
+ .pull_bit = 3, \
+ .drv_bit = 0, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = 0, \
+ .intr_enable_bit = -1, \
+ .intr_status_bit = -1, \
+ .intr_target_bit = -1, \
+ .intr_raw_status_bit = -1, \
+ .intr_polarity_bit = -1, \
+ .intr_detection_bit = -1, \
+ .intr_detection_width = -1, \
+ }
+
+#define QUP_I3C(qup_mode, qup_offset) \
+ { \
+ .mode = qup_mode, \
+ .offset = qup_offset, \
+ }
+
+static const struct pinctrl_pin_desc qdu1000_pins[] = {
+ PINCTRL_PIN(0, "GPIO_0"),
+ PINCTRL_PIN(1, "GPIO_1"),
+ PINCTRL_PIN(2, "GPIO_2"),
+ PINCTRL_PIN(3, "GPIO_3"),
+ PINCTRL_PIN(4, "GPIO_4"),
+ PINCTRL_PIN(5, "GPIO_5"),
+ PINCTRL_PIN(6, "GPIO_6"),
+ PINCTRL_PIN(7, "GPIO_7"),
+ PINCTRL_PIN(8, "GPIO_8"),
+ PINCTRL_PIN(9, "GPIO_9"),
+ PINCTRL_PIN(10, "GPIO_10"),
+ PINCTRL_PIN(11, "GPIO_11"),
+ PINCTRL_PIN(12, "GPIO_12"),
+ PINCTRL_PIN(13, "GPIO_13"),
+ PINCTRL_PIN(14, "GPIO_14"),
+ PINCTRL_PIN(15, "GPIO_15"),
+ PINCTRL_PIN(16, "GPIO_16"),
+ PINCTRL_PIN(17, "GPIO_17"),
+ PINCTRL_PIN(18, "GPIO_18"),
+ PINCTRL_PIN(19, "GPIO_19"),
+ PINCTRL_PIN(20, "GPIO_20"),
+ PINCTRL_PIN(21, "GPIO_21"),
+ PINCTRL_PIN(22, "GPIO_22"),
+ PINCTRL_PIN(23, "GPIO_23"),
+ PINCTRL_PIN(24, "GPIO_24"),
+ PINCTRL_PIN(25, "GPIO_25"),
+ PINCTRL_PIN(26, "GPIO_26"),
+ PINCTRL_PIN(27, "GPIO_27"),
+ PINCTRL_PIN(28, "GPIO_28"),
+ PINCTRL_PIN(29, "GPIO_29"),
+ PINCTRL_PIN(30, "GPIO_30"),
+ PINCTRL_PIN(31, "GPIO_31"),
+ PINCTRL_PIN(32, "GPIO_32"),
+ PINCTRL_PIN(33, "GPIO_33"),
+ PINCTRL_PIN(34, "GPIO_34"),
+ PINCTRL_PIN(35, "GPIO_35"),
+ PINCTRL_PIN(36, "GPIO_36"),
+ PINCTRL_PIN(37, "GPIO_37"),
+ PINCTRL_PIN(38, "GPIO_38"),
+ PINCTRL_PIN(39, "GPIO_39"),
+ PINCTRL_PIN(40, "GPIO_40"),
+ PINCTRL_PIN(41, "GPIO_41"),
+ PINCTRL_PIN(42, "GPIO_42"),
+ PINCTRL_PIN(43, "GPIO_43"),
+ PINCTRL_PIN(44, "GPIO_44"),
+ PINCTRL_PIN(45, "GPIO_45"),
+ PINCTRL_PIN(46, "GPIO_46"),
+ PINCTRL_PIN(47, "GPIO_47"),
+ PINCTRL_PIN(48, "GPIO_48"),
+ PINCTRL_PIN(49, "GPIO_49"),
+ PINCTRL_PIN(50, "GPIO_50"),
+ PINCTRL_PIN(51, "GPIO_51"),
+ PINCTRL_PIN(52, "GPIO_52"),
+ PINCTRL_PIN(53, "GPIO_53"),
+ PINCTRL_PIN(54, "GPIO_54"),
+ PINCTRL_PIN(55, "GPIO_55"),
+ PINCTRL_PIN(56, "GPIO_56"),
+ PINCTRL_PIN(57, "GPIO_57"),
+ PINCTRL_PIN(58, "GPIO_58"),
+ PINCTRL_PIN(59, "GPIO_59"),
+ PINCTRL_PIN(60, "GPIO_60"),
+ PINCTRL_PIN(61, "GPIO_61"),
+ PINCTRL_PIN(62, "GPIO_62"),
+ PINCTRL_PIN(63, "GPIO_63"),
+ PINCTRL_PIN(64, "GPIO_64"),
+ PINCTRL_PIN(65, "GPIO_65"),
+ PINCTRL_PIN(66, "GPIO_66"),
+ PINCTRL_PIN(67, "GPIO_67"),
+ PINCTRL_PIN(68, "GPIO_68"),
+ PINCTRL_PIN(69, "GPIO_69"),
+ PINCTRL_PIN(70, "GPIO_70"),
+ PINCTRL_PIN(71, "GPIO_71"),
+ PINCTRL_PIN(72, "GPIO_72"),
+ PINCTRL_PIN(73, "GPIO_73"),
+ PINCTRL_PIN(74, "GPIO_74"),
+ PINCTRL_PIN(75, "GPIO_75"),
+ PINCTRL_PIN(76, "GPIO_76"),
+ PINCTRL_PIN(77, "GPIO_77"),
+ PINCTRL_PIN(78, "GPIO_78"),
+ PINCTRL_PIN(79, "GPIO_79"),
+ PINCTRL_PIN(80, "GPIO_80"),
+ PINCTRL_PIN(81, "GPIO_81"),
+ PINCTRL_PIN(82, "GPIO_82"),
+ PINCTRL_PIN(83, "GPIO_83"),
+ PINCTRL_PIN(84, "GPIO_84"),
+ PINCTRL_PIN(85, "GPIO_85"),
+ PINCTRL_PIN(86, "GPIO_86"),
+ PINCTRL_PIN(87, "GPIO_87"),
+ PINCTRL_PIN(88, "GPIO_88"),
+ PINCTRL_PIN(89, "GPIO_89"),
+ PINCTRL_PIN(90, "GPIO_90"),
+ PINCTRL_PIN(91, "GPIO_91"),
+ PINCTRL_PIN(92, "GPIO_92"),
+ PINCTRL_PIN(93, "GPIO_93"),
+ PINCTRL_PIN(94, "GPIO_94"),
+ PINCTRL_PIN(95, "GPIO_95"),
+ PINCTRL_PIN(96, "GPIO_96"),
+ PINCTRL_PIN(97, "GPIO_97"),
+ PINCTRL_PIN(98, "GPIO_98"),
+ PINCTRL_PIN(99, "GPIO_99"),
+ PINCTRL_PIN(100, "GPIO_100"),
+ PINCTRL_PIN(101, "GPIO_101"),
+ PINCTRL_PIN(102, "GPIO_102"),
+ PINCTRL_PIN(103, "GPIO_103"),
+ PINCTRL_PIN(104, "GPIO_104"),
+ PINCTRL_PIN(105, "GPIO_105"),
+ PINCTRL_PIN(106, "GPIO_106"),
+ PINCTRL_PIN(107, "GPIO_107"),
+ PINCTRL_PIN(108, "GPIO_108"),
+ PINCTRL_PIN(109, "GPIO_109"),
+ PINCTRL_PIN(110, "GPIO_110"),
+ PINCTRL_PIN(111, "GPIO_111"),
+ PINCTRL_PIN(112, "GPIO_112"),
+ PINCTRL_PIN(113, "GPIO_113"),
+ PINCTRL_PIN(114, "GPIO_114"),
+ PINCTRL_PIN(115, "GPIO_115"),
+ PINCTRL_PIN(116, "GPIO_116"),
+ PINCTRL_PIN(117, "GPIO_117"),
+ PINCTRL_PIN(118, "GPIO_118"),
+ PINCTRL_PIN(119, "GPIO_119"),
+ PINCTRL_PIN(120, "GPIO_120"),
+ PINCTRL_PIN(121, "GPIO_121"),
+ PINCTRL_PIN(122, "GPIO_122"),
+ PINCTRL_PIN(123, "GPIO_123"),
+ PINCTRL_PIN(124, "GPIO_124"),
+ PINCTRL_PIN(125, "GPIO_125"),
+ PINCTRL_PIN(126, "GPIO_126"),
+ PINCTRL_PIN(127, "GPIO_127"),
+ PINCTRL_PIN(128, "GPIO_128"),
+ PINCTRL_PIN(129, "GPIO_129"),
+ PINCTRL_PIN(130, "GPIO_130"),
+ PINCTRL_PIN(131, "GPIO_131"),
+ PINCTRL_PIN(132, "GPIO_132"),
+ PINCTRL_PIN(133, "GPIO_133"),
+ PINCTRL_PIN(134, "GPIO_134"),
+ PINCTRL_PIN(135, "GPIO_135"),
+ PINCTRL_PIN(136, "GPIO_136"),
+ PINCTRL_PIN(137, "GPIO_137"),
+ PINCTRL_PIN(138, "GPIO_138"),
+ PINCTRL_PIN(139, "GPIO_139"),
+ PINCTRL_PIN(140, "GPIO_140"),
+ PINCTRL_PIN(141, "GPIO_141"),
+ PINCTRL_PIN(142, "GPIO_142"),
+ PINCTRL_PIN(143, "GPIO_143"),
+ PINCTRL_PIN(144, "GPIO_144"),
+ PINCTRL_PIN(145, "GPIO_145"),
+ PINCTRL_PIN(146, "GPIO_146"),
+ PINCTRL_PIN(147, "GPIO_147"),
+ PINCTRL_PIN(148, "GPIO_148"),
+ PINCTRL_PIN(149, "GPIO_149"),
+ PINCTRL_PIN(150, "GPIO_150"),
+ PINCTRL_PIN(151, "SDC1_RCLK"),
+ PINCTRL_PIN(152, "SDC1_CLK"),
+ PINCTRL_PIN(153, "SDC1_CMD"),
+ PINCTRL_PIN(154, "SDC1_DATA"),
+};
+
+#define DECLARE_MSM_GPIO_PINS(pin) \
+ static const unsigned int gpio##pin##_pins[] = { pin }
+DECLARE_MSM_GPIO_PINS(0);
+DECLARE_MSM_GPIO_PINS(1);
+DECLARE_MSM_GPIO_PINS(2);
+DECLARE_MSM_GPIO_PINS(3);
+DECLARE_MSM_GPIO_PINS(4);
+DECLARE_MSM_GPIO_PINS(5);
+DECLARE_MSM_GPIO_PINS(6);
+DECLARE_MSM_GPIO_PINS(7);
+DECLARE_MSM_GPIO_PINS(8);
+DECLARE_MSM_GPIO_PINS(9);
+DECLARE_MSM_GPIO_PINS(10);
+DECLARE_MSM_GPIO_PINS(11);
+DECLARE_MSM_GPIO_PINS(12);
+DECLARE_MSM_GPIO_PINS(13);
+DECLARE_MSM_GPIO_PINS(14);
+DECLARE_MSM_GPIO_PINS(15);
+DECLARE_MSM_GPIO_PINS(16);
+DECLARE_MSM_GPIO_PINS(17);
+DECLARE_MSM_GPIO_PINS(18);
+DECLARE_MSM_GPIO_PINS(19);
+DECLARE_MSM_GPIO_PINS(20);
+DECLARE_MSM_GPIO_PINS(21);
+DECLARE_MSM_GPIO_PINS(22);
+DECLARE_MSM_GPIO_PINS(23);
+DECLARE_MSM_GPIO_PINS(24);
+DECLARE_MSM_GPIO_PINS(25);
+DECLARE_MSM_GPIO_PINS(26);
+DECLARE_MSM_GPIO_PINS(27);
+DECLARE_MSM_GPIO_PINS(28);
+DECLARE_MSM_GPIO_PINS(29);
+DECLARE_MSM_GPIO_PINS(30);
+DECLARE_MSM_GPIO_PINS(31);
+DECLARE_MSM_GPIO_PINS(32);
+DECLARE_MSM_GPIO_PINS(33);
+DECLARE_MSM_GPIO_PINS(34);
+DECLARE_MSM_GPIO_PINS(35);
+DECLARE_MSM_GPIO_PINS(36);
+DECLARE_MSM_GPIO_PINS(37);
+DECLARE_MSM_GPIO_PINS(38);
+DECLARE_MSM_GPIO_PINS(39);
+DECLARE_MSM_GPIO_PINS(40);
+DECLARE_MSM_GPIO_PINS(41);
+DECLARE_MSM_GPIO_PINS(42);
+DECLARE_MSM_GPIO_PINS(43);
+DECLARE_MSM_GPIO_PINS(44);
+DECLARE_MSM_GPIO_PINS(45);
+DECLARE_MSM_GPIO_PINS(46);
+DECLARE_MSM_GPIO_PINS(47);
+DECLARE_MSM_GPIO_PINS(48);
+DECLARE_MSM_GPIO_PINS(49);
+DECLARE_MSM_GPIO_PINS(50);
+DECLARE_MSM_GPIO_PINS(51);
+DECLARE_MSM_GPIO_PINS(52);
+DECLARE_MSM_GPIO_PINS(53);
+DECLARE_MSM_GPIO_PINS(54);
+DECLARE_MSM_GPIO_PINS(55);
+DECLARE_MSM_GPIO_PINS(56);
+DECLARE_MSM_GPIO_PINS(57);
+DECLARE_MSM_GPIO_PINS(58);
+DECLARE_MSM_GPIO_PINS(59);
+DECLARE_MSM_GPIO_PINS(60);
+DECLARE_MSM_GPIO_PINS(61);
+DECLARE_MSM_GPIO_PINS(62);
+DECLARE_MSM_GPIO_PINS(63);
+DECLARE_MSM_GPIO_PINS(64);
+DECLARE_MSM_GPIO_PINS(65);
+DECLARE_MSM_GPIO_PINS(66);
+DECLARE_MSM_GPIO_PINS(67);
+DECLARE_MSM_GPIO_PINS(68);
+DECLARE_MSM_GPIO_PINS(69);
+DECLARE_MSM_GPIO_PINS(70);
+DECLARE_MSM_GPIO_PINS(71);
+DECLARE_MSM_GPIO_PINS(72);
+DECLARE_MSM_GPIO_PINS(73);
+DECLARE_MSM_GPIO_PINS(74);
+DECLARE_MSM_GPIO_PINS(75);
+DECLARE_MSM_GPIO_PINS(76);
+DECLARE_MSM_GPIO_PINS(77);
+DECLARE_MSM_GPIO_PINS(78);
+DECLARE_MSM_GPIO_PINS(79);
+DECLARE_MSM_GPIO_PINS(80);
+DECLARE_MSM_GPIO_PINS(81);
+DECLARE_MSM_GPIO_PINS(82);
+DECLARE_MSM_GPIO_PINS(83);
+DECLARE_MSM_GPIO_PINS(84);
+DECLARE_MSM_GPIO_PINS(85);
+DECLARE_MSM_GPIO_PINS(86);
+DECLARE_MSM_GPIO_PINS(87);
+DECLARE_MSM_GPIO_PINS(88);
+DECLARE_MSM_GPIO_PINS(89);
+DECLARE_MSM_GPIO_PINS(90);
+DECLARE_MSM_GPIO_PINS(91);
+DECLARE_MSM_GPIO_PINS(92);
+DECLARE_MSM_GPIO_PINS(93);
+DECLARE_MSM_GPIO_PINS(94);
+DECLARE_MSM_GPIO_PINS(95);
+DECLARE_MSM_GPIO_PINS(96);
+DECLARE_MSM_GPIO_PINS(97);
+DECLARE_MSM_GPIO_PINS(98);
+DECLARE_MSM_GPIO_PINS(99);
+DECLARE_MSM_GPIO_PINS(100);
+DECLARE_MSM_GPIO_PINS(101);
+DECLARE_MSM_GPIO_PINS(102);
+DECLARE_MSM_GPIO_PINS(103);
+DECLARE_MSM_GPIO_PINS(104);
+DECLARE_MSM_GPIO_PINS(105);
+DECLARE_MSM_GPIO_PINS(106);
+DECLARE_MSM_GPIO_PINS(107);
+DECLARE_MSM_GPIO_PINS(108);
+DECLARE_MSM_GPIO_PINS(109);
+DECLARE_MSM_GPIO_PINS(110);
+DECLARE_MSM_GPIO_PINS(111);
+DECLARE_MSM_GPIO_PINS(112);
+DECLARE_MSM_GPIO_PINS(113);
+DECLARE_MSM_GPIO_PINS(114);
+DECLARE_MSM_GPIO_PINS(115);
+DECLARE_MSM_GPIO_PINS(116);
+DECLARE_MSM_GPIO_PINS(117);
+DECLARE_MSM_GPIO_PINS(118);
+DECLARE_MSM_GPIO_PINS(119);
+DECLARE_MSM_GPIO_PINS(120);
+DECLARE_MSM_GPIO_PINS(121);
+DECLARE_MSM_GPIO_PINS(122);
+DECLARE_MSM_GPIO_PINS(123);
+DECLARE_MSM_GPIO_PINS(124);
+DECLARE_MSM_GPIO_PINS(125);
+DECLARE_MSM_GPIO_PINS(126);
+DECLARE_MSM_GPIO_PINS(127);
+DECLARE_MSM_GPIO_PINS(128);
+DECLARE_MSM_GPIO_PINS(129);
+DECLARE_MSM_GPIO_PINS(130);
+DECLARE_MSM_GPIO_PINS(131);
+DECLARE_MSM_GPIO_PINS(132);
+DECLARE_MSM_GPIO_PINS(133);
+DECLARE_MSM_GPIO_PINS(134);
+DECLARE_MSM_GPIO_PINS(135);
+DECLARE_MSM_GPIO_PINS(136);
+DECLARE_MSM_GPIO_PINS(137);
+DECLARE_MSM_GPIO_PINS(138);
+DECLARE_MSM_GPIO_PINS(139);
+DECLARE_MSM_GPIO_PINS(140);
+DECLARE_MSM_GPIO_PINS(141);
+DECLARE_MSM_GPIO_PINS(142);
+DECLARE_MSM_GPIO_PINS(143);
+DECLARE_MSM_GPIO_PINS(144);
+DECLARE_MSM_GPIO_PINS(145);
+DECLARE_MSM_GPIO_PINS(146);
+DECLARE_MSM_GPIO_PINS(147);
+DECLARE_MSM_GPIO_PINS(148);
+DECLARE_MSM_GPIO_PINS(149);
+DECLARE_MSM_GPIO_PINS(150);
+
+static const unsigned int sdc1_rclk_pins[] = { 151 };
+static const unsigned int sdc1_clk_pins[] = { 152 };
+static const unsigned int sdc1_cmd_pins[] = { 153 };
+static const unsigned int sdc1_data_pins[] = { 154 };
+
+enum qdu1000_functions {
+ msm_mux_gpio,
+ msm_mux_cmo_pri,
+ msm_mux_si5518_int,
+ msm_mux_atest_char,
+ msm_mux_atest_usb,
+ msm_mux_char_exec,
+ msm_mux_cmu_rng,
+ msm_mux_dbg_out_clk,
+ msm_mux_ddr_bist,
+ msm_mux_ddr_pxi0,
+ msm_mux_ddr_pxi1,
+ msm_mux_ddr_pxi2,
+ msm_mux_ddr_pxi3,
+ msm_mux_ddr_pxi4,
+ msm_mux_ddr_pxi5,
+ msm_mux_ddr_pxi6,
+ msm_mux_ddr_pxi7,
+ msm_mux_eth012_int_n,
+ msm_mux_eth345_int_n,
+ msm_mux_eth6_int_n,
+ msm_mux_gcc_gp1,
+ msm_mux_gcc_gp2,
+ msm_mux_gcc_gp3,
+ msm_mux_gps_pps_in,
+ msm_mux_hardsync_pps_in,
+ msm_mux_intr_c,
+ msm_mux_jitter_bist_ref,
+ msm_mux_pcie_clkreqn,
+ msm_mux_phase_flag,
+ msm_mux_pll_bist,
+ msm_mux_pll_clk,
+ msm_mux_prng_rosc,
+ msm_mux_qdss_cti,
+ msm_mux_qdss_gpio,
+ msm_mux_qlink0_enable,
+ msm_mux_qlink0_request,
+ msm_mux_qlink0_wmss,
+ msm_mux_qlink1_enable,
+ msm_mux_qlink1_request,
+ msm_mux_qlink1_wmss,
+ msm_mux_qlink2_enable,
+ msm_mux_qlink2_request,
+ msm_mux_qlink2_wmss,
+ msm_mux_qlink3_enable,
+ msm_mux_qlink3_request,
+ msm_mux_qlink3_wmss,
+ msm_mux_qlink4_enable,
+ msm_mux_qlink4_request,
+ msm_mux_qlink4_wmss,
+ msm_mux_qlink5_enable,
+ msm_mux_qlink5_request,
+ msm_mux_qlink5_wmss,
+ msm_mux_qlink6_enable,
+ msm_mux_qlink6_request,
+ msm_mux_qlink6_wmss,
+ msm_mux_qlink7_enable,
+ msm_mux_qlink7_request,
+ msm_mux_qlink7_wmss,
+ msm_mux_qspi_clk,
+ msm_mux_qspi_cs,
+ msm_mux_qspi0,
+ msm_mux_qspi1,
+ msm_mux_qspi2,
+ msm_mux_qspi3,
+ msm_mux_qup00,
+ msm_mux_qup01,
+ msm_mux_qup02,
+ msm_mux_qup03,
+ msm_mux_qup04,
+ msm_mux_qup05,
+ msm_mux_qup06,
+ msm_mux_qup07,
+ msm_mux_qup08,
+ msm_mux_qup10,
+ msm_mux_qup11,
+ msm_mux_qup12,
+ msm_mux_qup13,
+ msm_mux_qup14,
+ msm_mux_qup15,
+ msm_mux_qup16,
+ msm_mux_qup17,
+ msm_mux_qup20,
+ msm_mux_qup21,
+ msm_mux_qup22,
+ msm_mux_smb_alert,
+ msm_mux_smb_clk,
+ msm_mux_smb_dat,
+ msm_mux_tb_trig,
+ msm_mux_tgu_ch0,
+ msm_mux_tgu_ch1,
+ msm_mux_tgu_ch2,
+ msm_mux_tgu_ch3,
+ msm_mux_tgu_ch4,
+ msm_mux_tgu_ch5,
+ msm_mux_tgu_ch6,
+ msm_mux_tgu_ch7,
+ msm_mux_tmess_prng0,
+ msm_mux_tmess_prng1,
+ msm_mux_tmess_prng2,
+ msm_mux_tmess_prng3,
+ msm_mux_tod_pps_in,
+ msm_mux_tsense_pwm1,
+ msm_mux_tsense_pwm2,
+ msm_mux_usb2phy_ac,
+ msm_mux_usb_con_det,
+ msm_mux_usb_dfp_en,
+ msm_mux_usb_phy,
+ msm_mux_vfr_0,
+ msm_mux_vfr_1,
+ msm_mux_vsense_trigger,
+ msm_mux__,
+};
+
+static const char * const gpio_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7",
+ "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14",
+ "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21",
+ "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28",
+ "gpio29", "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35",
+ "gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42",
+ "gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", "gpio49",
+ "gpio50", "gpio51", "gpio52", "gpio53", "gpio54", "gpio55", "gpio56",
+ "gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63",
+ "gpio64", "gpio65", "gpio66", "gpio67", "gpio68", "gpio69", "gpio70",
+ "gpio71", "gpio72", "gpio73", "gpio74", "gpio75", "gpio76", "gpio77",
+ "gpio78", "gpio79", "gpio80", "gpio81", "gpio82", "gpio83", "gpio84",
+ "gpio85", "gpio86", "gpio87", "gpio88", "gpio89", "gpio90", "gpio91",
+ "gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio97", "gpio98",
+ "gpio99", "gpio100", "gpio101", "gpio102", "gpio103", "gpio104",
+ "gpio105", "gpio106", "gpio107", "gpio108", "gpio109", "gpio110",
+ "gpio111", "gpio112", "gpio113", "gpio114", "gpio115", "gpio116",
+ "gpio117", "gpio118", "gpio119", "gpio120", "gpio121", "gpio122",
+ "gpio123", "gpio124", "gpio125", "gpio126", "gpio127", "gpio128",
+ "gpio129", "gpio130", "gpio131", "gpio132", "gpio133", "gpio134",
+ "gpio135", "gpio136", "gpio137", "gpio138", "gpio139", "gpio140",
+ "gpio141", "gpio142", "gpio143", "gpio144", "gpio145", "gpio146",
+ "gpio147", "gpio148", "gpio149", "gpio150",
+};
+static const char * const cmo_pri_groups[] = {
+ "gpio103",
+};
+static const char * const si5518_int_groups[] = {
+ "gpio44",
+};
+static const char * const atest_char_groups[] = {
+ "gpio89", "gpio90", "gpio91", "gpio92", "gpio95",
+};
+static const char * const atest_usb_groups[] = {
+ "gpio114", "gpio115", "gpio116", "gpio117", "gpio118",
+};
+static const char * const char_exec_groups[] = {
+ "gpio99", "gpio100",
+};
+static const char * const cmu_rng_groups[] = {
+ "gpio89", "gpio90", "gpio91", "gpio92",
+};
+static const char * const dbg_out_clk_groups[] = {
+ "gpio136",
+};
+static const char * const ddr_bist_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3",
+};
+static const char * const ddr_pxi0_groups[] = {
+ "gpio114", "gpio115",
+};
+static const char * const ddr_pxi1_groups[] = {
+ "gpio116", "gpio117",
+};
+static const char * const ddr_pxi2_groups[] = {
+ "gpio118", "gpio119",
+};
+static const char * const ddr_pxi3_groups[] = {
+ "gpio120", "gpio121",
+};
+static const char * const ddr_pxi4_groups[] = {
+ "gpio122", "gpio123",
+};
+static const char * const ddr_pxi5_groups[] = {
+ "gpio124", "gpio125",
+};
+static const char * const ddr_pxi6_groups[] = {
+ "gpio126", "gpio127",
+};
+static const char * const ddr_pxi7_groups[] = {
+ "gpio128", "gpio129",
+};
+static const char * const eth012_int_n_groups[] = {
+ "gpio86",
+};
+static const char * const eth345_int_n_groups[] = {
+ "gpio87",
+};
+static const char * const eth6_int_n_groups[] = {
+ "gpio88",
+};
+static const char * const gcc_gp1_groups[] = {
+ "gpio86", "gpio134",
+};
+static const char * const gcc_gp2_groups[] = {
+ "gpio87", "gpio135",
+};
+static const char * const gcc_gp3_groups[] = {
+ "gpio88", "gpio136",
+};
+static const char * const gps_pps_in_groups[] = {
+ "gpio49",
+};
+static const char * const hardsync_pps_in_groups[] = {
+ "gpio47",
+};
+static const char * const intr_c_groups[] = {
+ "gpio26", "gpio27", "gpio28", "gpio141", "gpio142", "gpio143",
+};
+static const char * const jitter_bist_ref_groups[] = {
+ "gpio130",
+};
+static const char * const pcie_clkreqn_groups[] = {
+ "gpio98", "gpio99", "gpio100",
+};
+static const char * const phase_flag_groups[] = {
+ "gpio6", "gpio7", "gpio8", "gpio9", "gpio16", "gpio17", "gpio18",
+ "gpio19", "gpio20", "gpio22", "gpio21", "gpio23", "gpio24", "gpio25",
+ "gpio26", "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", "gpio32",
+ "gpio33", "gpio42", "gpio43", "gpio89", "gpio90", "gpio91", "gpio92",
+ "gpio95", "gpio96", "gpio97", "gpio102",
+};
+static const char * const pll_bist_groups[] = {
+ "gpio20",
+};
+static const char * const pll_clk_groups[] = {
+ "gpio98",
+};
+static const char * const prng_rosc_groups[] = {
+ "gpio18", "gpio19", "gpio20", "gpio21",
+};
+static const char * const qdss_cti_groups[] = {
+ "gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio48",
+ "gpio49", "gpio86", "gpio87", "gpio93", "gpio94", "gpio130", "gpio131",
+ "gpio132", "gpio133", "gpio134", "gpio135", "gpio144", "gpio145",
+};
+static const char * const qdss_gpio_groups[] = {
+ "gpio6", "gpio7", "gpio8", "gpio9", "gpio16", "gpio17", "gpio18",
+ "gpio19", "gpio20", "gpio21", "gpio22", "gpio23", "gpio25", "gpio26",
+ "gpio27", "gpio28", "gpio24", "gpio29", "gpio30", "gpio31", "gpio32",
+ "gpio33", "gpio34", "gpio35", "gpio42", "gpio43", "gpio88", "gpio89",
+ "gpio90", "gpio91", "gpio92", "gpio95", "gpio96", "gpio97", "gpio102",
+ "gpio103",
+};
+static const char * const qlink0_enable_groups[] = {
+ "gpio67",
+};
+static const char * const qlink0_request_groups[] = {
+ "gpio66",
+};
+static const char * const qlink0_wmss_groups[] = {
+ "gpio82",
+};
+static const char * const qlink1_enable_groups[] = {
+ "gpio69",
+};
+static const char * const qlink1_request_groups[] = {
+ "gpio68",
+};
+static const char * const qlink1_wmss_groups[] = {
+ "gpio83",
+};
+static const char * const qlink2_enable_groups[] = {
+ "gpio71",
+};
+static const char * const qlink2_request_groups[] = {
+ "gpio70",
+};
+static const char * const qlink2_wmss_groups[] = {
+ "gpio138",
+};
+static const char * const qlink3_enable_groups[] = {
+ "gpio73",
+};
+static const char * const qlink3_request_groups[] = {
+ "gpio72",
+};
+static const char * const qlink3_wmss_groups[] = {
+ "gpio139",
+};
+static const char * const qlink4_enable_groups[] = {
+ "gpio75",
+};
+static const char * const qlink4_request_groups[] = {
+ "gpio74",
+};
+static const char * const qlink4_wmss_groups[] = {
+ "gpio84",
+};
+static const char * const qlink5_enable_groups[] = {
+ "gpio77",
+};
+static const char * const qlink5_request_groups[] = {
+ "gpio76",
+};
+static const char * const qlink5_wmss_groups[] = {
+ "gpio85",
+};
+static const char * const qlink6_enable_groups[] = {
+ "gpio79",
+};
+static const char * const qlink6_request_groups[] = {
+ "gpio78",
+};
+static const char * const qlink6_wmss_groups[] = {
+ "gpio56",
+};
+static const char * const qlink7_enable_groups[] = {
+ "gpio81",
+};
+static const char * const qlink7_request_groups[] = {
+ "gpio80",
+};
+static const char * const qlink7_wmss_groups[] = {
+ "gpio57",
+};
+static const char * const qspi0_groups[] = {
+ "gpio114",
+};
+static const char * const qspi1_groups[] = {
+ "gpio115",
+};
+static const char * const qspi2_groups[] = {
+ "gpio116",
+};
+static const char * const qspi3_groups[] = {
+ "gpio117",
+};
+static const char * const qspi_clk_groups[] = {
+ "gpio126",
+};
+static const char * const qspi_cs_groups[] = {
+ "gpio125",
+};
+static const char * const qup00_groups[] = {
+ "gpio6", "gpio7", "gpio8", "gpio9",
+};
+static const char * const qup01_groups[] = {
+ "gpio10", "gpio11", "gpio12", "gpio13",
+};
+static const char * const qup02_groups[] = {
+ "gpio10", "gpio11", "gpio12", "gpio13",
+};
+static const char * const qup03_groups[] = {
+ "gpio14", "gpio15", "gpio16", "gpio17",
+};
+static const char * const qup04_groups[] = {
+ "gpio14", "gpio15", "gpio16", "gpio17",
+};
+static const char * const qup05_groups[] = {
+ "gpio130", "gpio131", "gpio132", "gpio133",
+};
+static const char * const qup06_groups[] = {
+ "gpio130", "gpio131", "gpio132", "gpio133",
+};
+static const char * const qup07_groups[] = {
+ "gpio134", "gpio135",
+};
+static const char * const qup08_groups[] = {
+ "gpio134", "gpio135",
+};
+static const char * const qup10_groups[] = {
+ "gpio18", "gpio19", "gpio20", "gpio21",
+};
+static const char * const qup11_groups[] = {
+ "gpio22", "gpio23", "gpio24", "gpio25",
+};
+static const char * const qup12_groups[] = {
+ "gpio22", "gpio23", "gpio24", "gpio25",
+};
+static const char * const qup13_groups[] = {
+ "gpio26", "gpio27", "gpio28", "gpio29",
+};
+static const char * const qup14_groups[] = {
+ "gpio26", "gpio27", "gpio28", "gpio29",
+};
+static const char * const qup15_groups[] = {
+ "gpio30", "gpio31", "gpio32", "gpio33",
+};
+static const char * const qup16_groups[] = {
+ "gpio29", "gpio34", "gpio35", "gpio36", "gpio37", "gpio38", "gpio39",
+};
+static const char * const qup17_groups[] = {
+ "gpio12", "gpio13", "gpio14", "gpio30", "gpio31", "gpio40", "gpio41",
+};
+static const char * const qup20_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3",
+};
+static const char * const qup21_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3",
+};
+static const char * const qup22_groups[] = {
+ "gpio4", "gpio5", "gpio128", "gpio129",
+};
+static const char * const smb_alert_groups[] = {
+ "gpio88", "gpio101",
+};
+static const char * const smb_clk_groups[] = {
+ "gpio133",
+};
+static const char * const smb_dat_groups[] = {
+ "gpio132",
+};
+static const char * const tb_trig_groups[] = {
+ "gpio114",
+};
+static const char * const tgu_ch0_groups[] = {
+ "gpio6",
+};
+static const char * const tgu_ch1_groups[] = {
+ "gpio7",
+};
+static const char * const tgu_ch2_groups[] = {
+ "gpio8",
+};
+static const char * const tgu_ch3_groups[] = {
+ "gpio9",
+};
+static const char * const tgu_ch4_groups[] = {
+ "gpio44",
+};
+static const char * const tgu_ch5_groups[] = {
+ "gpio45",
+};
+static const char * const tgu_ch6_groups[] = {
+ "gpio46",
+};
+static const char * const tgu_ch7_groups[] = {
+ "gpio47",
+};
+static const char * const tmess_prng0_groups[] = {
+ "gpio33",
+};
+static const char * const tmess_prng1_groups[] = {
+ "gpio32",
+};
+static const char * const tmess_prng2_groups[] = {
+ "gpio31",
+};
+static const char * const tmess_prng3_groups[] = {
+ "gpio30",
+};
+static const char * const tod_pps_in_groups[] = {
+ "gpio48",
+};
+static const char * const tsense_pwm1_groups[] = {
+ "gpio2",
+};
+static const char * const tsense_pwm2_groups[] = {
+ "gpio3",
+};
+static const char * const usb2phy_ac_groups[] = {
+ "gpio90",
+};
+static const char * const usb_con_det_groups[] = {
+ "gpio42",
+};
+static const char * const usb_dfp_en_groups[] = {
+ "gpio43",
+};
+static const char * const usb_phy_groups[] = {
+ "gpio91",
+};
+static const char * const vfr_0_groups[] = {
+ "gpio93",
+};
+static const char * const vfr_1_groups[] = {
+ "gpio94",
+};
+static const char * const vsense_trigger_groups[] = {
+ "gpio135",
+};
+
+static const struct msm_function qdu1000_functions[] = {
+ FUNCTION(gpio),
+ FUNCTION(cmo_pri),
+ FUNCTION(si5518_int),
+ FUNCTION(atest_char),
+ FUNCTION(atest_usb),
+ FUNCTION(char_exec),
+ FUNCTION(cmu_rng),
+ FUNCTION(dbg_out_clk),
+ FUNCTION(ddr_bist),
+ FUNCTION(ddr_pxi0),
+ FUNCTION(ddr_pxi1),
+ FUNCTION(ddr_pxi2),
+ FUNCTION(ddr_pxi3),
+ FUNCTION(ddr_pxi4),
+ FUNCTION(ddr_pxi5),
+ FUNCTION(ddr_pxi6),
+ FUNCTION(ddr_pxi7),
+ FUNCTION(eth012_int_n),
+ FUNCTION(eth345_int_n),
+ FUNCTION(eth6_int_n),
+ FUNCTION(gcc_gp1),
+ FUNCTION(gcc_gp2),
+ FUNCTION(gcc_gp3),
+ FUNCTION(gps_pps_in),
+ FUNCTION(hardsync_pps_in),
+ FUNCTION(intr_c),
+ FUNCTION(jitter_bist_ref),
+ FUNCTION(pcie_clkreqn),
+ FUNCTION(phase_flag),
+ FUNCTION(pll_bist),
+ FUNCTION(pll_clk),
+ FUNCTION(prng_rosc),
+ FUNCTION(qdss_cti),
+ FUNCTION(qdss_gpio),
+ FUNCTION(qlink0_enable),
+ FUNCTION(qlink0_request),
+ FUNCTION(qlink0_wmss),
+ FUNCTION(qlink1_enable),
+ FUNCTION(qlink1_request),
+ FUNCTION(qlink1_wmss),
+ FUNCTION(qlink2_enable),
+ FUNCTION(qlink2_request),
+ FUNCTION(qlink2_wmss),
+ FUNCTION(qlink3_enable),
+ FUNCTION(qlink3_request),
+ FUNCTION(qlink3_wmss),
+ FUNCTION(qlink4_enable),
+ FUNCTION(qlink4_request),
+ FUNCTION(qlink4_wmss),
+ FUNCTION(qlink5_enable),
+ FUNCTION(qlink5_request),
+ FUNCTION(qlink5_wmss),
+ FUNCTION(qlink6_enable),
+ FUNCTION(qlink6_request),
+ FUNCTION(qlink6_wmss),
+ FUNCTION(qlink7_enable),
+ FUNCTION(qlink7_request),
+ FUNCTION(qlink7_wmss),
+ FUNCTION(qspi0),
+ FUNCTION(qspi1),
+ FUNCTION(qspi2),
+ FUNCTION(qspi3),
+ FUNCTION(qspi_clk),
+ FUNCTION(qspi_cs),
+ FUNCTION(qup00),
+ FUNCTION(qup01),
+ FUNCTION(qup02),
+ FUNCTION(qup03),
+ FUNCTION(qup04),
+ FUNCTION(qup05),
+ FUNCTION(qup06),
+ FUNCTION(qup07),
+ FUNCTION(qup08),
+ FUNCTION(qup10),
+ FUNCTION(qup11),
+ FUNCTION(qup12),
+ FUNCTION(qup13),
+ FUNCTION(qup14),
+ FUNCTION(qup15),
+ FUNCTION(qup16),
+ FUNCTION(qup17),
+ FUNCTION(qup20),
+ FUNCTION(qup21),
+ FUNCTION(qup22),
+ FUNCTION(smb_alert),
+ FUNCTION(smb_clk),
+ FUNCTION(smb_dat),
+ FUNCTION(tb_trig),
+ FUNCTION(tgu_ch0),
+ FUNCTION(tgu_ch1),
+ FUNCTION(tgu_ch2),
+ FUNCTION(tgu_ch3),
+ FUNCTION(tgu_ch4),
+ FUNCTION(tgu_ch5),
+ FUNCTION(tgu_ch6),
+ FUNCTION(tgu_ch7),
+ FUNCTION(tmess_prng0),
+ FUNCTION(tmess_prng1),
+ FUNCTION(tmess_prng2),
+ FUNCTION(tmess_prng3),
+ FUNCTION(tod_pps_in),
+ FUNCTION(tsense_pwm1),
+ FUNCTION(tsense_pwm2),
+ FUNCTION(usb2phy_ac),
+ FUNCTION(usb_con_det),
+ FUNCTION(usb_dfp_en),
+ FUNCTION(usb_phy),
+ FUNCTION(vfr_0),
+ FUNCTION(vfr_1),
+ FUNCTION(vsense_trigger),
+};
+
+/*
+ * Every pin is maintained as a single group, and missing or non-existing pin
+ * would be maintained as dummy group to synchronize pin group index with
+ * pin descriptor registered with pinctrl core.
+ * Clients would not be able to request these dummy pin groups.
+ */
+static const struct msm_pingroup qdu1000_groups[] = {
+ [0] = PINGROUP(0, qup20, qup21, ddr_bist, _, _, _, _, _, _),
+ [1] = PINGROUP(1, qup20, qup21, ddr_bist, _, _, _, _, _, _),
+ [2] = PINGROUP(2, qup21, qup20, ddr_bist, _,
+ tsense_pwm1, _, _, _, _),
+ [3] = PINGROUP(3, qup21, qup20, ddr_bist, _,
+ tsense_pwm2, _, _, _, _),
+ [4] = PINGROUP(4, qup22, _, _, _, _, _, _, _, _),
+ [5] = PINGROUP(5, qup22, _, _, _, _, _, _, _, _),
+ [6] = PINGROUP(6, qup00, tgu_ch0, phase_flag, _,
+ qdss_gpio, _, _, _, _),
+ [7] = PINGROUP(7, qup00, tgu_ch1, phase_flag, _,
+ qdss_gpio, _, _, _, _),
+ [8] = PINGROUP(8, qup00, tgu_ch2, phase_flag, _,
+ qdss_gpio, _, _, _, _),
+ [9] = PINGROUP(9, qup00, tgu_ch3, phase_flag, _,
+ qdss_gpio, _, _, _, _),
+ [10] = PINGROUP(10, qup01, qup02, _, _, _, _, _, _, _),
+ [11] = PINGROUP(11, qup01, qup02, _, _, _, _, _, _, _),
+ [12] = PINGROUP(12, qup02, qup01, qup17, _, _, _, _, _, _),
+ [13] = PINGROUP(13, qup02, qup01, qup17, _, _, _, _, _, _),
+ [14] = PINGROUP(14, qup03, qup04, qup17, _, _, _, _, _, _),
+ [15] = PINGROUP(15, qup03, qup04, _, _, _, _, _, _, _),
+ [16] = PINGROUP(16, qup04, qup03, phase_flag, _,
+ qdss_gpio, _, _, _, _),
+ [17] = PINGROUP(17, qup04, qup03, phase_flag, _,
+ qdss_gpio, _, _, _, _),
+ [18] = PINGROUP(18, qup10, prng_rosc, phase_flag,
+ _, qdss_gpio, _, _, _, _),
+ [19] = PINGROUP(19, qup10, prng_rosc, phase_flag,
+ _, qdss_gpio, _, _, _, _),
+ [20] = PINGROUP(20, qup10, prng_rosc, pll_bist,
+ phase_flag, _, qdss_gpio, _, _, _),
+ [21] = PINGROUP(21, qup10, prng_rosc, phase_flag,
+ _, qdss_gpio, _, _, _, _),
+ [22] = PINGROUP(22, qup11, qup12, phase_flag, _,
+ qdss_gpio, _, _, _, _),
+ [23] = PINGROUP(23, qup11, qup12, phase_flag, _,
+ qdss_gpio, _, _, _, _),
+ [24] = PINGROUP(24, qup12, qup11, phase_flag, _,
+ qdss_gpio, _, _, _, _),
+ [25] = PINGROUP(25, qup12, qup11, phase_flag, _,
+ qdss_gpio, _, _, _, _),
+ [26] = PINGROUP(26, qup13, qup14, intr_c,
+ phase_flag, _, qdss_gpio, _, _, _),
+ [27] = PINGROUP(27, qup13, qup14, intr_c,
+ phase_flag, _, qdss_gpio, _, _, _),
+ [28] = PINGROUP(28, qup14, qup13, intr_c,
+ phase_flag, _, qdss_gpio, _, _, _),
+ [29] = PINGROUP(29, qup14, qup13, qup16,
+ phase_flag, _, qdss_gpio, _, _, _),
+ [30] = PINGROUP(30, qup17, qup15, tmess_prng3,
+ phase_flag, _, qdss_gpio, _, _, _),
+ [31] = PINGROUP(31, qup17, qup15, tmess_prng2,
+ phase_flag, _, qdss_gpio, _, _, _),
+ [32] = PINGROUP(32, qup15, tmess_prng1, phase_flag,
+ _, qdss_gpio, _, _, _, _),
+ [33] = PINGROUP(33, qup15, tmess_prng0, phase_flag,
+ _, qdss_gpio, _, _, _, _),
+ [34] = PINGROUP(34, qup16, qdss_gpio, _, _, _, _, _, _, _),
+ [35] = PINGROUP(35, qup16, qdss_gpio, _, _, _, _, _, _, _),
+ [36] = PINGROUP(36, qup16, qdss_cti, _, _, _, _, _, _, _),
+ [37] = PINGROUP(37, qup16, qdss_cti, _, _, _, _, _, _, _),
+ [38] = PINGROUP(38, qup16, qdss_cti, _, _, _, _, _, _, _),
+ [39] = PINGROUP(39, qup16, qdss_cti, _, _, _, _, _, _, _),
+ [40] = PINGROUP(40, qup17, qdss_cti, _, _, _, _, _, _, _),
+ [41] = PINGROUP(41, qup17, qdss_cti, _, _, _, _, _, _, _),
+ [42] = PINGROUP(42, usb_con_det, phase_flag, _,
+ qdss_gpio, _, _, _, _, _),
+ [43] = PINGROUP(43, usb_dfp_en, phase_flag, _,
+ qdss_gpio, _, _, _, _, _),
+ [44] = PINGROUP(44, si5518_int, tgu_ch4, _, _, _, _, _, _, _),
+ [45] = PINGROUP(45, tgu_ch5, _, _, _, _, _, _, _, _),
+ [46] = PINGROUP(46, tgu_ch6, _, _, _, _, _, _, _, _),
+ [47] = PINGROUP(47, hardsync_pps_in, tgu_ch7, _, _, _, _, _, _, _),
+ [48] = PINGROUP(48, tod_pps_in, qdss_cti, _, _, _, _, _, _, _),
+ [49] = PINGROUP(49, gps_pps_in, qdss_cti, _, _, _, _, _, _, _),
+ [50] = PINGROUP(50, _, _, _, _, _, _, _, _, _),
+ [51] = PINGROUP(51, _, _, _, _, _, _, _, _, _),
+ [52] = PINGROUP(52, _, _, _, _, _, _, _, _, _),
+ [53] = PINGROUP(53, _, _, _, _, _, _, _, _, _),
+ [54] = PINGROUP(54, _, _, _, _, _, _, _, _, _),
+ [55] = PINGROUP(55, _, _, _, _, _, _, _, _, _),
+ [56] = PINGROUP(56, _, qlink6_wmss, _, _, _, _, _, _, _),
+ [57] = PINGROUP(57, _, qlink7_wmss, _, _, _, _, _, _, _),
+ [58] = PINGROUP(58, _, _, _, _, _, _, _, _, _),
+ [59] = PINGROUP(59, _, _, _, _, _, _, _, _, _),
+ [60] = PINGROUP(60, _, _, _, _, _, _, _, _, _),
+ [61] = PINGROUP(61, _, _, _, _, _, _, _, _, _),
+ [62] = PINGROUP(62, _, _, _, _, _, _, _, _, _),
+ [63] = PINGROUP(63, _, _, _, _, _, _, _, _, _),
+ [64] = PINGROUP(64, _, _, _, _, _, _, _, _, _),
+ [65] = PINGROUP(65, _, _, _, _, _, _, _, _, _),
+ [66] = PINGROUP(66, qlink0_request, _, _, _, _, _, _, _, _),
+ [67] = PINGROUP(67, qlink0_enable, _, _, _, _, _, _, _, _),
+ [68] = PINGROUP(68, qlink1_request, _, _, _, _, _, _, _, _),
+ [69] = PINGROUP(69, qlink1_enable, _, _, _, _, _, _, _, _),
+ [70] = PINGROUP(70, qlink2_request, _, _, _, _, _, _, _, _),
+ [71] = PINGROUP(71, qlink2_enable, _, _, _, _, _, _, _, _),
+ [72] = PINGROUP(72, qlink3_request, _, _, _, _, _, _, _, _),
+ [73] = PINGROUP(73, qlink3_enable, _, _, _, _, _, _, _, _),
+ [74] = PINGROUP(74, qlink4_request, _, _, _, _, _, _, _, _),
+ [75] = PINGROUP(75, qlink4_enable, _, _, _, _, _, _, _, _),
+ [76] = PINGROUP(76, qlink5_request, _, _, _, _, _, _, _, _),
+ [77] = PINGROUP(77, qlink5_enable, _, _, _, _, _, _, _, _),
+ [78] = PINGROUP(78, qlink6_request, _, _, _, _, _, _, _, _),
+ [79] = PINGROUP(79, qlink6_enable, _, _, _, _, _, _, _, _),
+ [80] = PINGROUP(80, qlink7_request, _, _, _, _, _, _, _, _),
+ [81] = PINGROUP(81, qlink7_enable, _, _, _, _, _, _, _, _),
+ [82] = PINGROUP(82, qlink0_wmss, _, _, _, _, _, _, _, _),
+ [83] = PINGROUP(83, qlink1_wmss, _, _, _, _, _, _, _, _),
+ [84] = PINGROUP(84, qlink4_wmss, _, _, _, _, _, _, _, _),
+ [85] = PINGROUP(85, qlink5_wmss, _, _, _, _, _, _, _, _),
+ [86] = PINGROUP(86, eth012_int_n, gcc_gp1, _, qdss_cti, _, _, _, _, _),
+ [87] = PINGROUP(87, eth345_int_n, gcc_gp2, _, qdss_cti, _, _, _, _, _),
+ [88] = PINGROUP(88, eth6_int_n, smb_alert, gcc_gp3, _,
+ qdss_gpio, _, _, _, _),
+ [89] = PINGROUP(89, phase_flag, cmu_rng, _,
+ qdss_gpio, atest_char, _, _, _, _),
+ [90] = PINGROUP(90, usb2phy_ac, phase_flag,
+ cmu_rng, _, qdss_gpio,
+ atest_char, _, _, _),
+ [91] = PINGROUP(91, usb_phy, phase_flag, cmu_rng,
+ _, qdss_gpio, atest_char, _, _, _),
+ [92] = PINGROUP(92, phase_flag, cmu_rng, _,
+ qdss_gpio, atest_char, _, _, _, _),
+ [93] = PINGROUP(93, vfr_0, qdss_cti, _, _, _, _, _, _, _),
+ [94] = PINGROUP(94, vfr_1, qdss_cti, _, _, _, _, _, _, _),
+ [95] = PINGROUP(95, phase_flag, _, qdss_gpio,
+ atest_char, _, _, _, _, _),
+ [96] = PINGROUP(96, phase_flag, _, qdss_gpio, _, _, _, _, _, _),
+ [97] = PINGROUP(97, phase_flag, _, qdss_gpio, _, _, _, _, _, _),
+ [98] = PINGROUP(98, pll_clk, _, _, _, _, _, _, _, _),
+ [99] = PINGROUP(99, pcie_clkreqn, char_exec, _, _, _, _, _, _, _),
+ [100] = PINGROUP(100, char_exec, _, _, _, _, _, _, _, _),
+ [101] = PINGROUP(101, smb_alert, _, _, _, _, _, _, _, _),
+ [102] = PINGROUP(102, phase_flag, _, qdss_gpio, _, _, _, _, _, _),
+ [103] = PINGROUP(103, cmo_pri, qdss_gpio, _, _, _, _, _, _, _),
+ [104] = PINGROUP(104, _, _, _, _, _, _, _, _, _),
+ [105] = PINGROUP(105, _, _, _, _, _, _, _, _, _),
+ [106] = PINGROUP(106, _, _, _, _, _, _, _, _, _),
+ [107] = PINGROUP(107, _, _, _, _, _, _, _, _, _),
+ [108] = PINGROUP(108, _, _, _, _, _, _, _, _, _),
+ [109] = PINGROUP(109, _, _, _, _, _, _, _, _, _),
+ [110] = PINGROUP(110, _, _, _, _, _, _, _, _, _),
+ [111] = PINGROUP(111, _, _, _, _, _, _, _, _, _),
+ [112] = PINGROUP(112, _, _, _, _, _, _, _, _, _),
+ [113] = PINGROUP(113, _, _, _, _, _, _, _, _, _),
+ [114] = PINGROUP(114, qspi0, tb_trig, _,
+ atest_usb, ddr_pxi0, _, _, _, _),
+ [115] = PINGROUP(115, qspi1, _, atest_usb,
+ ddr_pxi0, _, _, _, _, _),
+ [116] = PINGROUP(116, qspi2, _, atest_usb,
+ ddr_pxi1, _, _, _, _, _),
+ [117] = PINGROUP(117, qspi3, _, atest_usb,
+ ddr_pxi1, _, _, _, _, _),
+ [118] = PINGROUP(118, _, atest_usb, ddr_pxi2, _, _, _, _, _, _),
+ [119] = PINGROUP(119, _, _, ddr_pxi2, _, _, _, _, _, _),
+ [120] = PINGROUP(120, _, _, ddr_pxi3, _, _, _, _, _, _),
+ [121] = PINGROUP(121, _, ddr_pxi3, _, _, _, _, _, _, _),
+ [122] = PINGROUP(122, _, ddr_pxi4, _, _, _, _, _, _, _),
+ [123] = PINGROUP(123, _, ddr_pxi4, _, _, _, _, _, _, _),
+ [124] = PINGROUP(124, _, ddr_pxi5, _, _, _, _, _, _, _),
+ [125] = PINGROUP(125, qspi_cs, _, ddr_pxi5, _, _, _, _, _, _),
+ [126] = PINGROUP(126, qspi_clk, _, ddr_pxi6, _, _, _, _, _, _),
+ [127] = PINGROUP(127, _, ddr_pxi6, _, _, _, _, _, _, _),
+ [128] = PINGROUP(128, qup22, _, ddr_pxi7, _, _, _, _, _, _),
+ [129] = PINGROUP(129, qup22, ddr_pxi7, _, _, _, _, _, _, _),
+ [130] = PINGROUP(130, qup05, qup06, jitter_bist_ref,
+ qdss_cti, _, _, _, _, _),
+ [131] = PINGROUP(131, qup05, qup06, qdss_cti, _, _, _, _, _, _),
+ [132] = PINGROUP(132, qup06, qup05, smb_dat,
+ qdss_cti, _, _, _, _, _),
+ [133] = PINGROUP(133, qup06, qup05, smb_clk,
+ qdss_cti, _, _, _, _, _),
+ [134] = PINGROUP(134, qup08, qup07, gcc_gp1, _,
+ qdss_cti, _, _, _, _),
+ [135] = PINGROUP(135, qup08, qup07, gcc_gp2, _,
+ qdss_cti, vsense_trigger, _, _, _),
+ [136] = PINGROUP(136, gcc_gp3, dbg_out_clk, _, _, _, _, _, _, _),
+ [137] = PINGROUP(137, _, _, _, _, _, _, _, _, _),
+ [138] = PINGROUP(138, qlink2_wmss, _, _, _, _, _, _, _, _),
+ [139] = PINGROUP(139, qlink3_wmss, _, _, _, _, _, _, _, _),
+ [140] = PINGROUP(140, _, _, _, _, _, _, _, _, _),
+ [141] = PINGROUP(141, intr_c, _, _, _, _, _, _, _, _),
+ [142] = PINGROUP(142, intr_c, _, _, _, _, _, _, _, _),
+ [143] = PINGROUP(143, intr_c, _, _, _, _, _, _, _, _),
+ [144] = PINGROUP(144, qdss_cti, _, _, _, _, _, _, _, _),
+ [145] = PINGROUP(145, qdss_cti, _, _, _, _, _, _, _, _),
+ [146] = PINGROUP(146, _, _, _, _, _, _, _, _, _),
+ [147] = PINGROUP(147, _, _, _, _, _, _, _, _, _),
+ [148] = PINGROUP(148, _, _, _, _, _, _, _, _, _),
+ [149] = PINGROUP(149, _, _, _, _, _, _, _, _, _),
+ [150] = PINGROUP(150, _, _, _, _, _, _, _, _, _),
+ [151] = SDC_QDSD_PINGROUP(sdc1_rclk, 0x9e000, 0, 0),
+ [152] = SDC_QDSD_PINGROUP(sdc1_clk, 0x9d000, 13, 6),
+ [153] = SDC_QDSD_PINGROUP(sdc1_cmd, 0x9d000, 11, 3),
+ [154] = SDC_QDSD_PINGROUP(sdc1_data, 0x9d000, 9, 0),
+};
+static const struct msm_pinctrl_soc_data qdu1000_tlmm = {
+ .pins = qdu1000_pins,
+ .npins = ARRAY_SIZE(qdu1000_pins),
+ .functions = qdu1000_functions,
+ .nfunctions = ARRAY_SIZE(qdu1000_functions),
+ .groups = qdu1000_groups,
+ .ngroups = ARRAY_SIZE(qdu1000_groups),
+ .ngpios = 151,
+};
+
+static int qdu1000_tlmm_probe(struct platform_device *pdev)
+{
+ return msm_pinctrl_probe(pdev, &qdu1000_tlmm);
+}
+
+static const struct of_device_id qdu1000_tlmm_of_match[] = {
+ { .compatible = "qcom,qdu1000-tlmm", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, qdu1000_tlmm_of_match);
+
+static struct platform_driver qdu1000_tlmm_driver = {
+ .driver = {
+ .name = "qdu1000-tlmm",
+ .of_match_table = qdu1000_tlmm_of_match,
+ },
+ .probe = qdu1000_tlmm_probe,
+ .remove = msm_pinctrl_remove,
+};
+
+static int __init qdu1000_tlmm_init(void)
+{
+ return platform_driver_register(&qdu1000_tlmm_driver);
+}
+arch_initcall(qdu1000_tlmm_init);
+
+static void __exit qdu1000_tlmm_exit(void)
+{
+ platform_driver_unregister(&qdu1000_tlmm_driver);
+}
+module_exit(qdu1000_tlmm_exit);
+
+MODULE_DESCRIPTION("QTI QDU1000 TLMM driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/qcom/pinctrl-sa8775p.c b/drivers/pinctrl/qcom/pinctrl-sa8775p.c
new file mode 100644
index 000000000000..2ae7cdca65d3
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-sa8775p.c
@@ -0,0 +1,1537 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2023, Linaro Limited
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-msm.h"
+
+#define FUNCTION(fname) \
+ [msm_mux_##fname] = { \
+ .name = #fname, \
+ .groups = fname##_groups, \
+ .ngroups = ARRAY_SIZE(fname##_groups), \
+ }
+
+#define REG_BASE 0x100000
+#define REG_SIZE 0x1000
+#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9)\
+ { \
+ .name = "gpio" #id, \
+ .pins = gpio##id##_pins, \
+ .npins = (unsigned int)ARRAY_SIZE(gpio##id##_pins), \
+ .funcs = (int[]){ \
+ msm_mux_gpio, /* gpio mode */ \
+ msm_mux_##f1, \
+ msm_mux_##f2, \
+ msm_mux_##f3, \
+ msm_mux_##f4, \
+ msm_mux_##f5, \
+ msm_mux_##f6, \
+ msm_mux_##f7, \
+ msm_mux_##f8, \
+ msm_mux_##f9 \
+ }, \
+ .nfuncs = 10, \
+ .ctl_reg = REG_BASE + REG_SIZE * id, \
+ .io_reg = REG_BASE + 0x4 + REG_SIZE * id, \
+ .intr_cfg_reg = REG_BASE + 0x8 + REG_SIZE * id, \
+ .intr_status_reg = REG_BASE + 0xc + REG_SIZE * id, \
+ .intr_target_reg = REG_BASE + 0x8 + REG_SIZE * id, \
+ .mux_bit = 2, \
+ .pull_bit = 0, \
+ .drv_bit = 6, \
+ .egpio_enable = 12, \
+ .egpio_present = 11, \
+ .oe_bit = 9, \
+ .in_bit = 0, \
+ .out_bit = 1, \
+ .intr_enable_bit = 0, \
+ .intr_status_bit = 0, \
+ .intr_target_bit = 5, \
+ .intr_target_kpss_val = 3, \
+ .intr_raw_status_bit = 4, \
+ .intr_polarity_bit = 1, \
+ .intr_detection_bit = 2, \
+ .intr_detection_width = 2, \
+ }
+
+#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \
+ { \
+ .name = #pg_name, \
+ .pins = pg_name##_pins, \
+ .npins = (unsigned int)ARRAY_SIZE(pg_name##_pins), \
+ .ctl_reg = ctl, \
+ .io_reg = 0, \
+ .intr_cfg_reg = 0, \
+ .intr_status_reg = 0, \
+ .intr_target_reg = 0, \
+ .mux_bit = -1, \
+ .pull_bit = pull, \
+ .drv_bit = drv, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = -1, \
+ .intr_enable_bit = -1, \
+ .intr_status_bit = -1, \
+ .intr_target_bit = -1, \
+ .intr_raw_status_bit = -1, \
+ .intr_polarity_bit = -1, \
+ .intr_detection_bit = -1, \
+ .intr_detection_width = -1, \
+ }
+
+#define UFS_RESET(pg_name, offset) \
+ { \
+ .name = #pg_name, \
+ .pins = pg_name##_pins, \
+ .npins = (unsigned int)ARRAY_SIZE(pg_name##_pins), \
+ .ctl_reg = offset, \
+ .io_reg = offset + 0x4, \
+ .intr_cfg_reg = 0, \
+ .intr_status_reg = 0, \
+ .intr_target_reg = 0, \
+ .mux_bit = -1, \
+ .pull_bit = 3, \
+ .drv_bit = 0, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = 0, \
+ .intr_enable_bit = -1, \
+ .intr_status_bit = -1, \
+ .intr_target_bit = -1, \
+ .intr_raw_status_bit = -1, \
+ .intr_polarity_bit = -1, \
+ .intr_detection_bit = -1, \
+ .intr_detection_width = -1, \
+ }
+
+#define QUP_I3C(qup_mode, qup_offset) \
+ { \
+ .mode = qup_mode, \
+ .offset = qup_offset, \
+ }
+
+#define QUP_I3C_6_MODE_OFFSET 0xAF000
+#define QUP_I3C_7_MODE_OFFSET 0xB0000
+#define QUP_I3C_13_MODE_OFFSET 0xB1000
+#define QUP_I3C_14_MODE_OFFSET 0xB2000
+
+static const struct pinctrl_pin_desc sa8775p_pins[] = {
+ PINCTRL_PIN(0, "GPIO_0"),
+ PINCTRL_PIN(1, "GPIO_1"),
+ PINCTRL_PIN(2, "GPIO_2"),
+ PINCTRL_PIN(3, "GPIO_3"),
+ PINCTRL_PIN(4, "GPIO_4"),
+ PINCTRL_PIN(5, "GPIO_5"),
+ PINCTRL_PIN(6, "GPIO_6"),
+ PINCTRL_PIN(7, "GPIO_7"),
+ PINCTRL_PIN(8, "GPIO_8"),
+ PINCTRL_PIN(9, "GPIO_9"),
+ PINCTRL_PIN(10, "GPIO_10"),
+ PINCTRL_PIN(11, "GPIO_11"),
+ PINCTRL_PIN(12, "GPIO_12"),
+ PINCTRL_PIN(13, "GPIO_13"),
+ PINCTRL_PIN(14, "GPIO_14"),
+ PINCTRL_PIN(15, "GPIO_15"),
+ PINCTRL_PIN(16, "GPIO_16"),
+ PINCTRL_PIN(17, "GPIO_17"),
+ PINCTRL_PIN(18, "GPIO_18"),
+ PINCTRL_PIN(19, "GPIO_19"),
+ PINCTRL_PIN(20, "GPIO_20"),
+ PINCTRL_PIN(21, "GPIO_21"),
+ PINCTRL_PIN(22, "GPIO_22"),
+ PINCTRL_PIN(23, "GPIO_23"),
+ PINCTRL_PIN(24, "GPIO_24"),
+ PINCTRL_PIN(25, "GPIO_25"),
+ PINCTRL_PIN(26, "GPIO_26"),
+ PINCTRL_PIN(27, "GPIO_27"),
+ PINCTRL_PIN(28, "GPIO_28"),
+ PINCTRL_PIN(29, "GPIO_29"),
+ PINCTRL_PIN(30, "GPIO_30"),
+ PINCTRL_PIN(31, "GPIO_31"),
+ PINCTRL_PIN(32, "GPIO_32"),
+ PINCTRL_PIN(33, "GPIO_33"),
+ PINCTRL_PIN(34, "GPIO_34"),
+ PINCTRL_PIN(35, "GPIO_35"),
+ PINCTRL_PIN(36, "GPIO_36"),
+ PINCTRL_PIN(37, "GPIO_37"),
+ PINCTRL_PIN(38, "GPIO_38"),
+ PINCTRL_PIN(39, "GPIO_39"),
+ PINCTRL_PIN(40, "GPIO_40"),
+ PINCTRL_PIN(41, "GPIO_41"),
+ PINCTRL_PIN(42, "GPIO_42"),
+ PINCTRL_PIN(43, "GPIO_43"),
+ PINCTRL_PIN(44, "GPIO_44"),
+ PINCTRL_PIN(45, "GPIO_45"),
+ PINCTRL_PIN(46, "GPIO_46"),
+ PINCTRL_PIN(47, "GPIO_47"),
+ PINCTRL_PIN(48, "GPIO_48"),
+ PINCTRL_PIN(49, "GPIO_49"),
+ PINCTRL_PIN(50, "GPIO_50"),
+ PINCTRL_PIN(51, "GPIO_51"),
+ PINCTRL_PIN(52, "GPIO_52"),
+ PINCTRL_PIN(53, "GPIO_53"),
+ PINCTRL_PIN(54, "GPIO_54"),
+ PINCTRL_PIN(55, "GPIO_55"),
+ PINCTRL_PIN(56, "GPIO_56"),
+ PINCTRL_PIN(57, "GPIO_57"),
+ PINCTRL_PIN(58, "GPIO_58"),
+ PINCTRL_PIN(59, "GPIO_59"),
+ PINCTRL_PIN(60, "GPIO_60"),
+ PINCTRL_PIN(61, "GPIO_61"),
+ PINCTRL_PIN(62, "GPIO_62"),
+ PINCTRL_PIN(63, "GPIO_63"),
+ PINCTRL_PIN(64, "GPIO_64"),
+ PINCTRL_PIN(65, "GPIO_65"),
+ PINCTRL_PIN(66, "GPIO_66"),
+ PINCTRL_PIN(67, "GPIO_67"),
+ PINCTRL_PIN(68, "GPIO_68"),
+ PINCTRL_PIN(69, "GPIO_69"),
+ PINCTRL_PIN(70, "GPIO_70"),
+ PINCTRL_PIN(71, "GPIO_71"),
+ PINCTRL_PIN(72, "GPIO_72"),
+ PINCTRL_PIN(73, "GPIO_73"),
+ PINCTRL_PIN(74, "GPIO_74"),
+ PINCTRL_PIN(75, "GPIO_75"),
+ PINCTRL_PIN(76, "GPIO_76"),
+ PINCTRL_PIN(77, "GPIO_77"),
+ PINCTRL_PIN(78, "GPIO_78"),
+ PINCTRL_PIN(79, "GPIO_79"),
+ PINCTRL_PIN(80, "GPIO_80"),
+ PINCTRL_PIN(81, "GPIO_81"),
+ PINCTRL_PIN(82, "GPIO_82"),
+ PINCTRL_PIN(83, "GPIO_83"),
+ PINCTRL_PIN(84, "GPIO_84"),
+ PINCTRL_PIN(85, "GPIO_85"),
+ PINCTRL_PIN(86, "GPIO_86"),
+ PINCTRL_PIN(87, "GPIO_87"),
+ PINCTRL_PIN(88, "GPIO_88"),
+ PINCTRL_PIN(89, "GPIO_89"),
+ PINCTRL_PIN(90, "GPIO_90"),
+ PINCTRL_PIN(91, "GPIO_91"),
+ PINCTRL_PIN(92, "GPIO_92"),
+ PINCTRL_PIN(93, "GPIO_93"),
+ PINCTRL_PIN(94, "GPIO_94"),
+ PINCTRL_PIN(95, "GPIO_95"),
+ PINCTRL_PIN(96, "GPIO_96"),
+ PINCTRL_PIN(97, "GPIO_97"),
+ PINCTRL_PIN(98, "GPIO_98"),
+ PINCTRL_PIN(99, "GPIO_99"),
+ PINCTRL_PIN(100, "GPIO_100"),
+ PINCTRL_PIN(101, "GPIO_101"),
+ PINCTRL_PIN(102, "GPIO_102"),
+ PINCTRL_PIN(103, "GPIO_103"),
+ PINCTRL_PIN(104, "GPIO_104"),
+ PINCTRL_PIN(105, "GPIO_105"),
+ PINCTRL_PIN(106, "GPIO_106"),
+ PINCTRL_PIN(107, "GPIO_107"),
+ PINCTRL_PIN(108, "GPIO_108"),
+ PINCTRL_PIN(109, "GPIO_109"),
+ PINCTRL_PIN(110, "GPIO_110"),
+ PINCTRL_PIN(111, "GPIO_111"),
+ PINCTRL_PIN(112, "GPIO_112"),
+ PINCTRL_PIN(113, "GPIO_113"),
+ PINCTRL_PIN(114, "GPIO_114"),
+ PINCTRL_PIN(115, "GPIO_115"),
+ PINCTRL_PIN(116, "GPIO_116"),
+ PINCTRL_PIN(117, "GPIO_117"),
+ PINCTRL_PIN(118, "GPIO_118"),
+ PINCTRL_PIN(119, "GPIO_119"),
+ PINCTRL_PIN(120, "GPIO_120"),
+ PINCTRL_PIN(121, "GPIO_121"),
+ PINCTRL_PIN(122, "GPIO_122"),
+ PINCTRL_PIN(123, "GPIO_123"),
+ PINCTRL_PIN(124, "GPIO_124"),
+ PINCTRL_PIN(125, "GPIO_125"),
+ PINCTRL_PIN(126, "GPIO_126"),
+ PINCTRL_PIN(127, "GPIO_127"),
+ PINCTRL_PIN(128, "GPIO_128"),
+ PINCTRL_PIN(129, "GPIO_129"),
+ PINCTRL_PIN(130, "GPIO_130"),
+ PINCTRL_PIN(131, "GPIO_131"),
+ PINCTRL_PIN(132, "GPIO_132"),
+ PINCTRL_PIN(133, "GPIO_133"),
+ PINCTRL_PIN(134, "GPIO_134"),
+ PINCTRL_PIN(135, "GPIO_135"),
+ PINCTRL_PIN(136, "GPIO_136"),
+ PINCTRL_PIN(137, "GPIO_137"),
+ PINCTRL_PIN(138, "GPIO_138"),
+ PINCTRL_PIN(139, "GPIO_139"),
+ PINCTRL_PIN(140, "GPIO_140"),
+ PINCTRL_PIN(141, "GPIO_141"),
+ PINCTRL_PIN(142, "GPIO_142"),
+ PINCTRL_PIN(143, "GPIO_143"),
+ PINCTRL_PIN(144, "GPIO_144"),
+ PINCTRL_PIN(145, "GPIO_145"),
+ PINCTRL_PIN(146, "GPIO_146"),
+ PINCTRL_PIN(147, "GPIO_147"),
+ PINCTRL_PIN(148, "GPIO_148"),
+ PINCTRL_PIN(149, "UFS_RESET"),
+ PINCTRL_PIN(150, "SDC1_RCLK"),
+ PINCTRL_PIN(151, "SDC1_CLK"),
+ PINCTRL_PIN(152, "SDC1_CMD"),
+ PINCTRL_PIN(153, "SDC1_DATA"),
+};
+
+#define DECLARE_MSM_GPIO_PINS(pin) \
+ static const unsigned int gpio##pin##_pins[] = { pin }
+DECLARE_MSM_GPIO_PINS(0);
+DECLARE_MSM_GPIO_PINS(1);
+DECLARE_MSM_GPIO_PINS(2);
+DECLARE_MSM_GPIO_PINS(3);
+DECLARE_MSM_GPIO_PINS(4);
+DECLARE_MSM_GPIO_PINS(5);
+DECLARE_MSM_GPIO_PINS(6);
+DECLARE_MSM_GPIO_PINS(7);
+DECLARE_MSM_GPIO_PINS(8);
+DECLARE_MSM_GPIO_PINS(9);
+DECLARE_MSM_GPIO_PINS(10);
+DECLARE_MSM_GPIO_PINS(11);
+DECLARE_MSM_GPIO_PINS(12);
+DECLARE_MSM_GPIO_PINS(13);
+DECLARE_MSM_GPIO_PINS(14);
+DECLARE_MSM_GPIO_PINS(15);
+DECLARE_MSM_GPIO_PINS(16);
+DECLARE_MSM_GPIO_PINS(17);
+DECLARE_MSM_GPIO_PINS(18);
+DECLARE_MSM_GPIO_PINS(19);
+DECLARE_MSM_GPIO_PINS(20);
+DECLARE_MSM_GPIO_PINS(21);
+DECLARE_MSM_GPIO_PINS(22);
+DECLARE_MSM_GPIO_PINS(23);
+DECLARE_MSM_GPIO_PINS(24);
+DECLARE_MSM_GPIO_PINS(25);
+DECLARE_MSM_GPIO_PINS(26);
+DECLARE_MSM_GPIO_PINS(27);
+DECLARE_MSM_GPIO_PINS(28);
+DECLARE_MSM_GPIO_PINS(29);
+DECLARE_MSM_GPIO_PINS(30);
+DECLARE_MSM_GPIO_PINS(31);
+DECLARE_MSM_GPIO_PINS(32);
+DECLARE_MSM_GPIO_PINS(33);
+DECLARE_MSM_GPIO_PINS(34);
+DECLARE_MSM_GPIO_PINS(35);
+DECLARE_MSM_GPIO_PINS(36);
+DECLARE_MSM_GPIO_PINS(37);
+DECLARE_MSM_GPIO_PINS(38);
+DECLARE_MSM_GPIO_PINS(39);
+DECLARE_MSM_GPIO_PINS(40);
+DECLARE_MSM_GPIO_PINS(41);
+DECLARE_MSM_GPIO_PINS(42);
+DECLARE_MSM_GPIO_PINS(43);
+DECLARE_MSM_GPIO_PINS(44);
+DECLARE_MSM_GPIO_PINS(45);
+DECLARE_MSM_GPIO_PINS(46);
+DECLARE_MSM_GPIO_PINS(47);
+DECLARE_MSM_GPIO_PINS(48);
+DECLARE_MSM_GPIO_PINS(49);
+DECLARE_MSM_GPIO_PINS(50);
+DECLARE_MSM_GPIO_PINS(51);
+DECLARE_MSM_GPIO_PINS(52);
+DECLARE_MSM_GPIO_PINS(53);
+DECLARE_MSM_GPIO_PINS(54);
+DECLARE_MSM_GPIO_PINS(55);
+DECLARE_MSM_GPIO_PINS(56);
+DECLARE_MSM_GPIO_PINS(57);
+DECLARE_MSM_GPIO_PINS(58);
+DECLARE_MSM_GPIO_PINS(59);
+DECLARE_MSM_GPIO_PINS(60);
+DECLARE_MSM_GPIO_PINS(61);
+DECLARE_MSM_GPIO_PINS(62);
+DECLARE_MSM_GPIO_PINS(63);
+DECLARE_MSM_GPIO_PINS(64);
+DECLARE_MSM_GPIO_PINS(65);
+DECLARE_MSM_GPIO_PINS(66);
+DECLARE_MSM_GPIO_PINS(67);
+DECLARE_MSM_GPIO_PINS(68);
+DECLARE_MSM_GPIO_PINS(69);
+DECLARE_MSM_GPIO_PINS(70);
+DECLARE_MSM_GPIO_PINS(71);
+DECLARE_MSM_GPIO_PINS(72);
+DECLARE_MSM_GPIO_PINS(73);
+DECLARE_MSM_GPIO_PINS(74);
+DECLARE_MSM_GPIO_PINS(75);
+DECLARE_MSM_GPIO_PINS(76);
+DECLARE_MSM_GPIO_PINS(77);
+DECLARE_MSM_GPIO_PINS(78);
+DECLARE_MSM_GPIO_PINS(79);
+DECLARE_MSM_GPIO_PINS(80);
+DECLARE_MSM_GPIO_PINS(81);
+DECLARE_MSM_GPIO_PINS(82);
+DECLARE_MSM_GPIO_PINS(83);
+DECLARE_MSM_GPIO_PINS(84);
+DECLARE_MSM_GPIO_PINS(85);
+DECLARE_MSM_GPIO_PINS(86);
+DECLARE_MSM_GPIO_PINS(87);
+DECLARE_MSM_GPIO_PINS(88);
+DECLARE_MSM_GPIO_PINS(89);
+DECLARE_MSM_GPIO_PINS(90);
+DECLARE_MSM_GPIO_PINS(91);
+DECLARE_MSM_GPIO_PINS(92);
+DECLARE_MSM_GPIO_PINS(93);
+DECLARE_MSM_GPIO_PINS(94);
+DECLARE_MSM_GPIO_PINS(95);
+DECLARE_MSM_GPIO_PINS(96);
+DECLARE_MSM_GPIO_PINS(97);
+DECLARE_MSM_GPIO_PINS(98);
+DECLARE_MSM_GPIO_PINS(99);
+DECLARE_MSM_GPIO_PINS(100);
+DECLARE_MSM_GPIO_PINS(101);
+DECLARE_MSM_GPIO_PINS(102);
+DECLARE_MSM_GPIO_PINS(103);
+DECLARE_MSM_GPIO_PINS(104);
+DECLARE_MSM_GPIO_PINS(105);
+DECLARE_MSM_GPIO_PINS(106);
+DECLARE_MSM_GPIO_PINS(107);
+DECLARE_MSM_GPIO_PINS(108);
+DECLARE_MSM_GPIO_PINS(109);
+DECLARE_MSM_GPIO_PINS(110);
+DECLARE_MSM_GPIO_PINS(111);
+DECLARE_MSM_GPIO_PINS(112);
+DECLARE_MSM_GPIO_PINS(113);
+DECLARE_MSM_GPIO_PINS(114);
+DECLARE_MSM_GPIO_PINS(115);
+DECLARE_MSM_GPIO_PINS(116);
+DECLARE_MSM_GPIO_PINS(117);
+DECLARE_MSM_GPIO_PINS(118);
+DECLARE_MSM_GPIO_PINS(119);
+DECLARE_MSM_GPIO_PINS(120);
+DECLARE_MSM_GPIO_PINS(121);
+DECLARE_MSM_GPIO_PINS(122);
+DECLARE_MSM_GPIO_PINS(123);
+DECLARE_MSM_GPIO_PINS(124);
+DECLARE_MSM_GPIO_PINS(125);
+DECLARE_MSM_GPIO_PINS(126);
+DECLARE_MSM_GPIO_PINS(127);
+DECLARE_MSM_GPIO_PINS(128);
+DECLARE_MSM_GPIO_PINS(129);
+DECLARE_MSM_GPIO_PINS(130);
+DECLARE_MSM_GPIO_PINS(131);
+DECLARE_MSM_GPIO_PINS(132);
+DECLARE_MSM_GPIO_PINS(133);
+DECLARE_MSM_GPIO_PINS(134);
+DECLARE_MSM_GPIO_PINS(135);
+DECLARE_MSM_GPIO_PINS(136);
+DECLARE_MSM_GPIO_PINS(137);
+DECLARE_MSM_GPIO_PINS(138);
+DECLARE_MSM_GPIO_PINS(139);
+DECLARE_MSM_GPIO_PINS(140);
+DECLARE_MSM_GPIO_PINS(141);
+DECLARE_MSM_GPIO_PINS(142);
+DECLARE_MSM_GPIO_PINS(143);
+DECLARE_MSM_GPIO_PINS(144);
+DECLARE_MSM_GPIO_PINS(145);
+DECLARE_MSM_GPIO_PINS(146);
+DECLARE_MSM_GPIO_PINS(147);
+DECLARE_MSM_GPIO_PINS(148);
+
+static const unsigned int ufs_reset_pins[] = { 149 };
+static const unsigned int sdc1_rclk_pins[] = { 150 };
+static const unsigned int sdc1_clk_pins[] = { 151 };
+static const unsigned int sdc1_cmd_pins[] = { 152 };
+static const unsigned int sdc1_data_pins[] = { 153 };
+
+enum sa8775p_functions {
+ msm_mux_gpio,
+ msm_mux_atest_char,
+ msm_mux_atest_usb2,
+ msm_mux_audio_ref,
+ msm_mux_cam_mclk,
+ msm_mux_cci_async,
+ msm_mux_cci_i2c,
+ msm_mux_cci_timer0,
+ msm_mux_cci_timer1,
+ msm_mux_cci_timer2,
+ msm_mux_cci_timer3,
+ msm_mux_cci_timer4,
+ msm_mux_cci_timer5,
+ msm_mux_cci_timer6,
+ msm_mux_cci_timer7,
+ msm_mux_cci_timer8,
+ msm_mux_cci_timer9,
+ msm_mux_cri_trng,
+ msm_mux_cri_trng0,
+ msm_mux_cri_trng1,
+ msm_mux_dbg_out,
+ msm_mux_ddr_bist,
+ msm_mux_ddr_pxi0,
+ msm_mux_ddr_pxi1,
+ msm_mux_ddr_pxi2,
+ msm_mux_ddr_pxi3,
+ msm_mux_ddr_pxi4,
+ msm_mux_ddr_pxi5,
+ msm_mux_edp0_hot,
+ msm_mux_edp0_lcd,
+ msm_mux_edp1_hot,
+ msm_mux_edp1_lcd,
+ msm_mux_edp2_hot,
+ msm_mux_edp2_lcd,
+ msm_mux_edp3_hot,
+ msm_mux_edp3_lcd,
+ msm_mux_emac0_mcg0,
+ msm_mux_emac0_mcg1,
+ msm_mux_emac0_mcg2,
+ msm_mux_emac0_mcg3,
+ msm_mux_emac0_mdc,
+ msm_mux_emac0_mdio,
+ msm_mux_emac0_ptp_aux,
+ msm_mux_emac0_ptp_pps,
+ msm_mux_emac1_mcg0,
+ msm_mux_emac1_mcg1,
+ msm_mux_emac1_mcg2,
+ msm_mux_emac1_mcg3,
+ msm_mux_emac1_mdc,
+ msm_mux_emac1_mdio,
+ msm_mux_emac1_ptp_aux,
+ msm_mux_emac1_ptp_pps,
+ msm_mux_gcc_gp1,
+ msm_mux_gcc_gp2,
+ msm_mux_gcc_gp3,
+ msm_mux_gcc_gp4,
+ msm_mux_gcc_gp5,
+ msm_mux_hs0_mi2s,
+ msm_mux_hs1_mi2s,
+ msm_mux_hs2_mi2s,
+ msm_mux_ibi_i3c,
+ msm_mux_jitter_bist,
+ msm_mux_mdp0_vsync0,
+ msm_mux_mdp0_vsync1,
+ msm_mux_mdp0_vsync2,
+ msm_mux_mdp0_vsync3,
+ msm_mux_mdp0_vsync4,
+ msm_mux_mdp0_vsync5,
+ msm_mux_mdp0_vsync6,
+ msm_mux_mdp0_vsync7,
+ msm_mux_mdp0_vsync8,
+ msm_mux_mdp1_vsync0,
+ msm_mux_mdp1_vsync1,
+ msm_mux_mdp1_vsync2,
+ msm_mux_mdp1_vsync3,
+ msm_mux_mdp1_vsync4,
+ msm_mux_mdp1_vsync5,
+ msm_mux_mdp1_vsync6,
+ msm_mux_mdp1_vsync7,
+ msm_mux_mdp1_vsync8,
+ msm_mux_mdp_vsync,
+ msm_mux_mi2s1_data0,
+ msm_mux_mi2s1_data1,
+ msm_mux_mi2s1_sck,
+ msm_mux_mi2s1_ws,
+ msm_mux_mi2s2_data0,
+ msm_mux_mi2s2_data1,
+ msm_mux_mi2s2_sck,
+ msm_mux_mi2s2_ws,
+ msm_mux_mi2s_mclk0,
+ msm_mux_mi2s_mclk1,
+ msm_mux_pcie0_clkreq,
+ msm_mux_pcie1_clkreq,
+ msm_mux_phase_flag,
+ msm_mux_pll_bist,
+ msm_mux_pll_clk,
+ msm_mux_prng_rosc0,
+ msm_mux_prng_rosc1,
+ msm_mux_prng_rosc2,
+ msm_mux_prng_rosc3,
+ msm_mux_qdss_cti,
+ msm_mux_qdss_gpio,
+ msm_mux_qup0_se0,
+ msm_mux_qup0_se1,
+ msm_mux_qup0_se2,
+ msm_mux_qup0_se3,
+ msm_mux_qup0_se4,
+ msm_mux_qup0_se5,
+ msm_mux_qup1_se0,
+ msm_mux_qup1_se1,
+ msm_mux_qup1_se2,
+ msm_mux_qup1_se3,
+ msm_mux_qup1_se4,
+ msm_mux_qup1_se5,
+ msm_mux_qup1_se6,
+ msm_mux_qup2_se0,
+ msm_mux_qup2_se1,
+ msm_mux_qup2_se2,
+ msm_mux_qup2_se3,
+ msm_mux_qup2_se4,
+ msm_mux_qup2_se5,
+ msm_mux_qup2_se6,
+ msm_mux_qup3_se0,
+ msm_mux_sail_top,
+ msm_mux_sailss_emac0,
+ msm_mux_sailss_ospi,
+ msm_mux_sgmii_phy,
+ msm_mux_tb_trig,
+ msm_mux_tgu_ch0,
+ msm_mux_tgu_ch1,
+ msm_mux_tgu_ch2,
+ msm_mux_tgu_ch3,
+ msm_mux_tgu_ch4,
+ msm_mux_tgu_ch5,
+ msm_mux_tsense_pwm1,
+ msm_mux_tsense_pwm2,
+ msm_mux_tsense_pwm3,
+ msm_mux_tsense_pwm4,
+ msm_mux_usb2phy_ac,
+ msm_mux_vsense_trigger,
+ msm_mux__,
+};
+
+static const char * const gpio_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7",
+ "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14",
+ "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21",
+ "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28",
+ "gpio29", "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35",
+ "gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42",
+ "gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", "gpio49",
+ "gpio50", "gpio51", "gpio52", "gpio53", "gpio54", "gpio55", "gpio56",
+ "gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63",
+ "gpio64", "gpio65", "gpio66", "gpio67", "gpio68", "gpio69", "gpio70",
+ "gpio71", "gpio72", "gpio73", "gpio74", "gpio75", "gpio76", "gpio77",
+ "gpio78", "gpio79", "gpio80", "gpio81", "gpio82", "gpio83", "gpio84",
+ "gpio85", "gpio86", "gpio87", "gpio88", "gpio89", "gpio90", "gpio91",
+ "gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio97", "gpio98",
+ "gpio99", "gpio100", "gpio101", "gpio102", "gpio103", "gpio104",
+ "gpio105", "gpio106", "gpio107", "gpio108", "gpio109", "gpio110",
+ "gpio111", "gpio112", "gpio113", "gpio114", "gpio115", "gpio116",
+ "gpio117", "gpio118", "gpio119", "gpio120", "gpio121", "gpio122",
+ "gpio123", "gpio124", "gpio125", "gpio126", "gpio127", "gpio128",
+ "gpio129", "gpio130", "gpio131", "gpio132", "gpio133", "gpio134",
+ "gpio135", "gpio136", "gpio137", "gpio138", "gpio139", "gpio140",
+ "gpio141", "gpio142", "gpio143", "gpio144", "gpio145", "gpio146",
+ "gpio147", "gpio148",
+};
+
+static const char * const atest_char_groups[] = {
+ "gpio27", "gpio58", "gpio59", "gpio89", "gpio90",
+};
+
+static const char * const atest_usb2_groups[] = {
+ "gpio58", "gpio59", "gpio86", "gpio87", "gpio88", "gpio89", "gpio90",
+ "gpio91", "gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio97",
+ "gpio105",
+};
+
+static const char * const audio_ref_groups[] = {
+ "gpio113",
+};
+
+static const char * const cam_mclk_groups[] = {
+ "gpio72", "gpio73", "gpio74", "gpio75",
+};
+
+static const char * const cci_async_groups[] = {
+ "gpio50", "gpio66", "gpio68", "gpio69", "gpio70", "gpio71",
+};
+
+static const char * const cci_i2c_groups[] = {
+ "gpio52", "gpio53", "gpio54", "gpio55", "gpio56", "gpio57", "gpio58",
+ "gpio59", "gpio60", "gpio61", "gpio62", "gpio63", "gpio64", "gpio65",
+ "gpio66", "gpio67",
+};
+
+static const char * const cci_timer0_groups[] = {
+ "gpio68",
+};
+
+static const char * const cci_timer1_groups[] = {
+ "gpio69",
+};
+
+static const char * const cci_timer2_groups[] = {
+ "gpio70",
+};
+
+static const char * const cci_timer3_groups[] = {
+ "gpio71",
+};
+
+static const char * const cci_timer4_groups[] = {
+ "gpio52",
+};
+
+static const char * const cci_timer5_groups[] = {
+ "gpio53",
+};
+
+static const char * const cci_timer6_groups[] = {
+ "gpio54",
+};
+
+static const char * const cci_timer7_groups[] = {
+ "gpio55",
+};
+
+static const char * const cci_timer8_groups[] = {
+ "gpio56",
+};
+
+static const char * const cci_timer9_groups[] = {
+ "gpio57",
+};
+
+static const char * const cri_trng_groups[] = {
+ "gpio99",
+};
+
+static const char * const cri_trng0_groups[] = {
+ "gpio97",
+};
+
+static const char * const cri_trng1_groups[] = {
+ "gpio98",
+};
+
+static const char * const dbg_out_groups[] = {
+ "gpio144",
+};
+
+static const char * const ddr_bist_groups[] = {
+ "gpio56", "gpio57", "gpio58", "gpio59",
+};
+
+static const char * const ddr_pxi0_groups[] = {
+ "gpio33", "gpio34",
+};
+
+static const char * const ddr_pxi1_groups[] = {
+ "gpio52", "gpio53",
+};
+
+static const char * const ddr_pxi2_groups[] = {
+ "gpio55", "gpio86",
+};
+
+static const char * const ddr_pxi3_groups[] = {
+ "gpio87", "gpio88",
+};
+
+static const char * const ddr_pxi4_groups[] = {
+ "gpio89", "gpio90",
+};
+
+static const char * const ddr_pxi5_groups[] = {
+ "gpio118", "gpio119",
+};
+
+static const char * const edp0_hot_groups[] = {
+ "gpio101",
+};
+
+static const char * const edp0_lcd_groups[] = {
+ "gpio44",
+};
+
+static const char * const edp1_hot_groups[] = {
+ "gpio102",
+};
+
+static const char * const edp1_lcd_groups[] = {
+ "gpio45",
+};
+
+static const char * const edp2_hot_groups[] = {
+ "gpio104",
+};
+
+static const char * const edp2_lcd_groups[] = {
+ "gpio48",
+};
+
+static const char * const edp3_hot_groups[] = {
+ "gpio103",
+};
+
+static const char * const edp3_lcd_groups[] = {
+ "gpio49",
+};
+
+static const char * const emac0_mcg0_groups[] = {
+ "gpio12",
+};
+
+static const char * const emac0_mcg1_groups[] = {
+ "gpio13",
+};
+
+static const char * const emac0_mcg2_groups[] = {
+ "gpio14",
+};
+
+static const char * const emac0_mcg3_groups[] = {
+ "gpio15",
+};
+
+static const char * const emac0_mdc_groups[] = {
+ "gpio8",
+};
+
+static const char * const emac0_mdio_groups[] = {
+ "gpio9",
+};
+
+static const char * const emac0_ptp_aux_groups[] = {
+ "gpio6", "gpio10", "gpio11", "gpio12",
+};
+
+static const char * const emac0_ptp_pps_groups[] = {
+ "gpio6", "gpio10", "gpio11", "gpio12",
+};
+
+static const char * const emac1_mcg0_groups[] = {
+ "gpio16",
+
+};
+
+static const char * const emac1_mcg1_groups[] = {
+ "gpio17",
+};
+
+static const char * const emac1_mcg2_groups[] = {
+ "gpio18",
+};
+
+static const char * const emac1_mcg3_groups[] = {
+ "gpio19",
+};
+
+static const char * const emac1_mdc_groups[] = {
+ "gpio20",
+};
+
+static const char * const emac1_mdio_groups[] = {
+ "gpio21",
+};
+
+static const char * const emac1_ptp_aux_groups[] = {
+ "gpio6", "gpio10", "gpio11", "gpio12",
+};
+
+static const char * const emac1_ptp_pps_groups[] = {
+ "gpio6", "gpio10", "gpio11", "gpio12",
+};
+
+static const char * const gcc_gp1_groups[] = {
+ "gpio51", "gpio82",
+};
+
+static const char * const gcc_gp2_groups[] = {
+ "gpio52", "gpio83",
+};
+
+static const char * const gcc_gp3_groups[] = {
+ "gpio53", "gpio84",
+};
+
+static const char * const gcc_gp4_groups[] = {
+ "gpio33", "gpio55",
+};
+
+static const char * const gcc_gp5_groups[] = {
+ "gpio34", "gpio42",
+};
+
+static const char * const hs0_mi2s_groups[] = {
+ "gpio114", "gpio115", "gpio116", "gpio117",
+};
+
+static const char * const hs1_mi2s_groups[] = {
+ "gpio118", "gpio119", "gpio120", "gpio121",
+};
+
+static const char * const hs2_mi2s_groups[] = {
+ "gpio122", "gpio123", "gpio124", "gpio125",
+};
+
+static const char * const ibi_i3c_groups[] = {
+ "gpio40", "gpio41", "gpio42", "gpio43", "gpio80", "gpio81", "gpio84",
+ "gpio85",
+};
+
+static const char * const jitter_bist_groups[] = {
+ "gpio86",
+};
+
+static const char * const mdp0_vsync0_groups[] = {
+ "gpio57",
+};
+
+static const char * const mdp0_vsync1_groups[] = {
+ "gpio58",
+};
+
+static const char * const mdp0_vsync2_groups[] = {
+ "gpio59",
+};
+
+static const char * const mdp0_vsync3_groups[] = {
+ "gpio80",
+};
+
+static const char * const mdp0_vsync4_groups[] = {
+ "gpio81",
+};
+
+static const char * const mdp0_vsync5_groups[] = {
+ "gpio91",
+};
+
+static const char * const mdp0_vsync6_groups[] = {
+ "gpio92",
+};
+
+static const char * const mdp0_vsync7_groups[] = {
+ "gpio93",
+};
+
+static const char * const mdp0_vsync8_groups[] = {
+ "gpio94",
+};
+
+static const char * const mdp1_vsync0_groups[] = {
+ "gpio40",
+};
+
+static const char * const mdp1_vsync1_groups[] = {
+ "gpio41",
+};
+
+static const char * const mdp1_vsync2_groups[] = {
+ "gpio42",
+};
+
+static const char * const mdp1_vsync3_groups[] = {
+ "gpio43",
+};
+
+static const char * const mdp1_vsync4_groups[] = {
+ "gpio46",
+};
+
+static const char * const mdp1_vsync5_groups[] = {
+ "gpio47",
+};
+
+static const char * const mdp1_vsync6_groups[] = {
+ "gpio51",
+};
+
+static const char * const mdp1_vsync7_groups[] = {
+ "gpio52",
+};
+
+static const char * const mdp1_vsync8_groups[] = {
+ "gpio50",
+};
+
+static const char * const mdp_vsync_groups[] = {
+ "gpio82", "gpio83", "gpio84",
+};
+
+static const char * const mi2s1_data0_groups[] = {
+ "gpio108",
+};
+
+static const char * const mi2s1_data1_groups[] = {
+ "gpio109",
+};
+
+static const char * const mi2s1_sck_groups[] = {
+ "gpio106",
+};
+
+static const char * const mi2s1_ws_groups[] = {
+ "gpio107",
+};
+
+static const char * const mi2s2_data0_groups[] = {
+ "gpio112",
+};
+
+static const char * const mi2s2_data1_groups[] = {
+ "gpio113",
+};
+
+static const char * const mi2s2_sck_groups[] = {
+ "gpio110",
+};
+
+static const char * const mi2s2_ws_groups[] = {
+ "gpio111",
+};
+
+static const char * const mi2s_mclk0_groups[] = {
+ "gpio105",
+};
+
+static const char * const mi2s_mclk1_groups[] = {
+ "gpio117",
+};
+
+static const char * const pcie0_clkreq_groups[] = {
+ "gpio1",
+};
+
+static const char * const pcie1_clkreq_groups[] = {
+ "gpio3",
+};
+
+static const char * const phase_flag_groups[] = {
+ "gpio25", "gpio26", "gpio27", "gpio28", "gpio29", "gpio30", "gpio31",
+ "gpio32", "gpio35", "gpio36", "gpio37", "gpio38", "gpio39", "gpio56",
+ "gpio57", "gpio98", "gpio99", "gpio106", "gpio107", "gpio108",
+ "gpio109", "gpio110", "gpio111", "gpio112", "gpio113", "gpio114",
+ "gpio120", "gpio121", "gpio122", "gpio123", "gpio124", "gpio125",
+};
+
+static const char * const pll_bist_groups[] = {
+ "gpio114",
+};
+
+static const char * const pll_clk_groups[] = {
+ "gpio87",
+};
+
+static const char * const prng_rosc0_groups[] = {
+ "gpio101",
+};
+
+static const char * const prng_rosc1_groups[] = {
+ "gpio102",
+};
+
+static const char * const prng_rosc2_groups[] = {
+ "gpio103",
+};
+
+static const char * const prng_rosc3_groups[] = {
+ "gpio104",
+};
+
+static const char * const qdss_cti_groups[] = {
+ "gpio26", "gpio27", "gpio38", "gpio39", "gpio48", "gpio49", "gpio50",
+ "gpio51",
+};
+
+static const char * const qdss_gpio_groups[] = {
+ "gpio20", "gpio21", "gpio22", "gpio23", "gpio24", "gpio25", "gpio28",
+ "gpio29", "gpio30", "gpio31", "gpio60", "gpio61", "gpio62", "gpio63",
+ "gpio64", "gpio65", "gpio66", "gpio67", "gpio105", "gpio106", "gpio107",
+ "gpio108", "gpio109", "gpio110", "gpio111", "gpio112", "gpio113",
+ "gpio114", "gpio115", "gpio116", "gpio117", "gpio118", "gpio119",
+ "gpio120", "gpio121", "gpio122",
+};
+
+static const char * const qup0_se0_groups[] = {
+ "gpio20", "gpio21", "gpio22", "gpio23",
+};
+
+static const char * const qup0_se1_groups[] = {
+ "gpio24", "gpio25", "gpio26", "gpio27",
+};
+
+static const char * const qup0_se2_groups[] = {
+ "gpio36", "gpio37", "gpio38", "gpio39",
+};
+
+static const char * const qup0_se3_groups[] = {
+ "gpio28", "gpio29", "gpio30", "gpio31",
+};
+
+static const char * const qup0_se4_groups[] = {
+ "gpio32", "gpio33", "gpio34", "gpio35",
+};
+
+static const char * const qup0_se5_groups[] = {
+ "gpio36", "gpio37", "gpio38", "gpio39",
+};
+
+static const char * const qup1_se0_groups[] = {
+ "gpio40", "gpio41", "gpio42", "gpio43",
+};
+
+static const char * const qup1_se1_groups[] = {
+ "gpio40", "gpio41", "gpio42", "gpio43",
+};
+
+static const char * const qup1_se2_groups[] = {
+ "gpio44", "gpio45", "gpio46", "gpio47",
+};
+
+static const char * const qup1_se3_groups[] = {
+ "gpio44", "gpio45", "gpio46", "gpio47",
+};
+
+static const char * const qup1_se4_groups[] = {
+ "gpio48", "gpio49", "gpio50", "gpio51",
+};
+
+static const char * const qup1_se5_groups[] = {
+ "gpio52", "gpio53", "gpio54", "gpio55",
+};
+
+static const char * const qup1_se6_groups[] = {
+ "gpio56", "gpio56", "gpio57", "gpio57",
+};
+
+static const char * const qup2_se0_groups[] = {
+ "gpio80", "gpio81", "gpio82", "gpio83",
+};
+
+static const char * const qup2_se1_groups[] = {
+ "gpio84", "gpio85", "gpio99", "gpio100",
+};
+
+static const char * const qup2_se2_groups[] = {
+ "gpio86", "gpio87", "gpio88", "gpio89", "gpio90",
+};
+
+static const char * const qup2_se3_groups[] = {
+ "gpio91", "gpio92", "gpio93", "gpio94",
+};
+
+static const char * const qup2_se4_groups[] = {
+ "gpio95", "gpio96", "gpio97", "gpio98",
+};
+
+static const char * const qup2_se5_groups[] = {
+ "gpio84", "gpio85", "gpio99", "gpio100",
+};
+
+static const char * const qup2_se6_groups[] = {
+ "gpio95", "gpio96", "gpio97", "gpio98",
+};
+
+static const char * const qup3_se0_groups[] = {
+ "gpio13", "gpio14", "gpio15", "gpio16", "gpio17", "gpio18", "gpio19",
+};
+
+static const char * const sail_top_groups[] = {
+ "gpio13", "gpio14", "gpio15", "gpio16",
+};
+
+static const char * const sailss_emac0_groups[] = {
+ "gpio18", "gpio19",
+};
+
+static const char * const sailss_ospi_groups[] = {
+ "gpio18", "gpio19",
+};
+
+static const char * const sgmii_phy_groups[] = {
+ "gpio7", "gpio26",
+};
+
+static const char * const tb_trig_groups[] = {
+ "gpio17", "gpio17",
+};
+
+static const char * const tgu_ch0_groups[] = {
+ "gpio46",
+};
+
+static const char * const tgu_ch1_groups[] = {
+ "gpio47",
+};
+
+static const char * const tgu_ch2_groups[] = {
+ "gpio36",
+};
+
+static const char * const tgu_ch3_groups[] = {
+ "gpio37",
+};
+
+static const char * const tgu_ch4_groups[] = {
+ "gpio38",
+};
+
+static const char * const tgu_ch5_groups[] = {
+ "gpio39",
+};
+
+static const char * const tsense_pwm1_groups[] = {
+ "gpio104",
+};
+
+static const char * const tsense_pwm2_groups[] = {
+ "gpio103",
+};
+
+static const char * const tsense_pwm3_groups[] = {
+ "gpio102",
+};
+
+static const char * const tsense_pwm4_groups[] = {
+ "gpio101",
+};
+
+static const char * const usb2phy_ac_groups[] = {
+ "gpio10", "gpio11", "gpio12",
+};
+
+static const char * const vsense_trigger_groups[] = {
+ "gpio111",
+};
+
+static const struct msm_function sa8775p_functions[] = {
+ FUNCTION(gpio),
+ FUNCTION(atest_char),
+ FUNCTION(atest_usb2),
+ FUNCTION(audio_ref),
+ FUNCTION(cam_mclk),
+ FUNCTION(cci_async),
+ FUNCTION(cci_i2c),
+ FUNCTION(cci_timer0),
+ FUNCTION(cci_timer1),
+ FUNCTION(cci_timer2),
+ FUNCTION(cci_timer3),
+ FUNCTION(cci_timer4),
+ FUNCTION(cci_timer5),
+ FUNCTION(cci_timer6),
+ FUNCTION(cci_timer7),
+ FUNCTION(cci_timer8),
+ FUNCTION(cci_timer9),
+ FUNCTION(cri_trng),
+ FUNCTION(cri_trng0),
+ FUNCTION(cri_trng1),
+ FUNCTION(dbg_out),
+ FUNCTION(ddr_bist),
+ FUNCTION(ddr_pxi0),
+ FUNCTION(ddr_pxi1),
+ FUNCTION(ddr_pxi2),
+ FUNCTION(ddr_pxi3),
+ FUNCTION(ddr_pxi4),
+ FUNCTION(ddr_pxi5),
+ FUNCTION(edp0_hot),
+ FUNCTION(edp0_lcd),
+ FUNCTION(edp1_hot),
+ FUNCTION(edp1_lcd),
+ FUNCTION(edp2_hot),
+ FUNCTION(edp2_lcd),
+ FUNCTION(edp3_hot),
+ FUNCTION(edp3_lcd),
+ FUNCTION(emac0_mcg0),
+ FUNCTION(emac0_mcg1),
+ FUNCTION(emac0_mcg2),
+ FUNCTION(emac0_mcg3),
+ FUNCTION(emac0_mdc),
+ FUNCTION(emac0_mdio),
+ FUNCTION(emac0_ptp_aux),
+ FUNCTION(emac0_ptp_pps),
+ FUNCTION(emac1_mcg0),
+ FUNCTION(emac1_mcg1),
+ FUNCTION(emac1_mcg2),
+ FUNCTION(emac1_mcg3),
+ FUNCTION(emac1_mdc),
+ FUNCTION(emac1_mdio),
+ FUNCTION(emac1_ptp_aux),
+ FUNCTION(emac1_ptp_pps),
+ FUNCTION(gcc_gp1),
+ FUNCTION(gcc_gp2),
+ FUNCTION(gcc_gp3),
+ FUNCTION(gcc_gp4),
+ FUNCTION(gcc_gp5),
+ FUNCTION(hs0_mi2s),
+ FUNCTION(hs1_mi2s),
+ FUNCTION(hs2_mi2s),
+ FUNCTION(ibi_i3c),
+ FUNCTION(jitter_bist),
+ FUNCTION(mdp0_vsync0),
+ FUNCTION(mdp0_vsync1),
+ FUNCTION(mdp0_vsync2),
+ FUNCTION(mdp0_vsync3),
+ FUNCTION(mdp0_vsync4),
+ FUNCTION(mdp0_vsync5),
+ FUNCTION(mdp0_vsync6),
+ FUNCTION(mdp0_vsync7),
+ FUNCTION(mdp0_vsync8),
+ FUNCTION(mdp1_vsync0),
+ FUNCTION(mdp1_vsync1),
+ FUNCTION(mdp1_vsync2),
+ FUNCTION(mdp1_vsync3),
+ FUNCTION(mdp1_vsync4),
+ FUNCTION(mdp1_vsync5),
+ FUNCTION(mdp1_vsync6),
+ FUNCTION(mdp1_vsync7),
+ FUNCTION(mdp1_vsync8),
+ FUNCTION(mdp_vsync),
+ FUNCTION(mi2s1_data0),
+ FUNCTION(mi2s1_data1),
+ FUNCTION(mi2s1_sck),
+ FUNCTION(mi2s1_ws),
+ FUNCTION(mi2s2_data0),
+ FUNCTION(mi2s2_data1),
+ FUNCTION(mi2s2_sck),
+ FUNCTION(mi2s2_ws),
+ FUNCTION(mi2s_mclk0),
+ FUNCTION(mi2s_mclk1),
+ FUNCTION(pcie0_clkreq),
+ FUNCTION(pcie1_clkreq),
+ FUNCTION(phase_flag),
+ FUNCTION(pll_bist),
+ FUNCTION(pll_clk),
+ FUNCTION(prng_rosc0),
+ FUNCTION(prng_rosc1),
+ FUNCTION(prng_rosc2),
+ FUNCTION(prng_rosc3),
+ FUNCTION(qdss_cti),
+ FUNCTION(qdss_gpio),
+ FUNCTION(qup0_se0),
+ FUNCTION(qup0_se1),
+ FUNCTION(qup0_se2),
+ FUNCTION(qup0_se3),
+ FUNCTION(qup0_se4),
+ FUNCTION(qup0_se5),
+ FUNCTION(qup1_se0),
+ FUNCTION(qup1_se1),
+ FUNCTION(qup1_se2),
+ FUNCTION(qup1_se3),
+ FUNCTION(qup1_se4),
+ FUNCTION(qup1_se5),
+ FUNCTION(qup1_se6),
+ FUNCTION(qup2_se0),
+ FUNCTION(qup2_se1),
+ FUNCTION(qup2_se2),
+ FUNCTION(qup2_se3),
+ FUNCTION(qup2_se4),
+ FUNCTION(qup2_se5),
+ FUNCTION(qup2_se6),
+ FUNCTION(qup3_se0),
+ FUNCTION(sail_top),
+ FUNCTION(sailss_emac0),
+ FUNCTION(sailss_ospi),
+ FUNCTION(sgmii_phy),
+ FUNCTION(tb_trig),
+ FUNCTION(tgu_ch0),
+ FUNCTION(tgu_ch1),
+ FUNCTION(tgu_ch2),
+ FUNCTION(tgu_ch3),
+ FUNCTION(tgu_ch4),
+ FUNCTION(tgu_ch5),
+ FUNCTION(tsense_pwm1),
+ FUNCTION(tsense_pwm2),
+ FUNCTION(tsense_pwm3),
+ FUNCTION(tsense_pwm4),
+ FUNCTION(usb2phy_ac),
+ FUNCTION(vsense_trigger),
+};
+
+/*
+ * Every pin is maintained as a single group, and missing or non-existing pin
+ * would be maintained as dummy group to synchronize pin group index with
+ * pin descriptor registered with pinctrl core.
+ * Clients would not be able to request these dummy pin groups.
+ */
+static const struct msm_pingroup sa8775p_groups[] = {
+ [0] = PINGROUP(0, _, _, _, _, _, _, _, _, _),
+ [1] = PINGROUP(1, pcie0_clkreq, _, _, _, _, _, _, _, _),
+ [2] = PINGROUP(2, _, _, _, _, _, _, _, _, _),
+ [3] = PINGROUP(3, pcie1_clkreq, _, _, _, _, _, _, _, _),
+ [4] = PINGROUP(4, _, _, _, _, _, _, _, _, _),
+ [5] = PINGROUP(5, _, _, _, _, _, _, _, _, _),
+ [6] = PINGROUP(6, emac0_ptp_aux, emac0_ptp_pps, emac1_ptp_aux, emac1_ptp_pps,
+ _, _, _, _, _),
+ [7] = PINGROUP(7, sgmii_phy, _, _, _, _, _, _, _, _),
+ [8] = PINGROUP(8, emac0_mdc, _, _, _, _, _, _, _, _),
+ [9] = PINGROUP(9, emac0_mdio, _, _, _, _, _, _, _, _),
+ [10] = PINGROUP(10, usb2phy_ac, emac0_ptp_aux, emac0_ptp_pps, emac1_ptp_aux, emac1_ptp_pps,
+ _, _, _, _),
+ [11] = PINGROUP(11, usb2phy_ac, emac0_ptp_aux, emac0_ptp_pps, emac1_ptp_aux, emac1_ptp_pps,
+ _, _, _, _),
+ [12] = PINGROUP(12, usb2phy_ac, emac0_ptp_aux, emac0_ptp_pps, emac1_ptp_aux, emac1_ptp_pps,
+ emac0_mcg0, _, _, _),
+ [13] = PINGROUP(13, qup3_se0, emac0_mcg1, _, _, sail_top, _, _, _, _),
+ [14] = PINGROUP(14, qup3_se0, emac0_mcg2, _, _, sail_top, _, _, _, _),
+ [15] = PINGROUP(15, qup3_se0, emac0_mcg3, _, _, sail_top, _, _, _, _),
+ [16] = PINGROUP(16, qup3_se0, emac1_mcg0, _, _, sail_top, _, _, _, _),
+ [17] = PINGROUP(17, qup3_se0, tb_trig, tb_trig, emac1_mcg1, _, _, _, _, _),
+ [18] = PINGROUP(18, qup3_se0, emac1_mcg2, _, _, sailss_ospi, sailss_emac0, _, _, _),
+ [19] = PINGROUP(19, qup3_se0, emac1_mcg3, _, _, sailss_ospi, sailss_emac0, _, _, _),
+ [20] = PINGROUP(20, qup0_se0, emac1_mdc, qdss_gpio, _, _, _, _, _, _),
+ [21] = PINGROUP(21, qup0_se0, emac1_mdio, qdss_gpio, _, _, _, _, _, _),
+ [22] = PINGROUP(22, qup0_se0, qdss_gpio, _, _, _, _, _, _, _),
+ [23] = PINGROUP(23, qup0_se0, qdss_gpio, _, _, _, _, _, _, _),
+ [24] = PINGROUP(24, qup0_se1, qdss_gpio, _, _, _, _, _, _, _),
+ [25] = PINGROUP(25, qup0_se1, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [26] = PINGROUP(26, sgmii_phy, qup0_se1, qdss_cti, phase_flag, _, _, _, _, _),
+ [27] = PINGROUP(27, qup0_se1, qdss_cti, phase_flag, _, atest_char, _, _, _, _),
+ [28] = PINGROUP(28, qup0_se3, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [29] = PINGROUP(29, qup0_se3, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [30] = PINGROUP(30, qup0_se3, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [31] = PINGROUP(31, qup0_se3, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [32] = PINGROUP(32, qup0_se4, phase_flag, _, _, _, _, _, _, _),
+ [33] = PINGROUP(33, qup0_se4, gcc_gp4, _, ddr_pxi0, _, _, _, _, _),
+ [34] = PINGROUP(34, qup0_se4, gcc_gp5, _, ddr_pxi0, _, _, _, _, _),
+ [35] = PINGROUP(35, qup0_se4, phase_flag, _, _, _, _, _, _, _),
+ [36] = PINGROUP(36, qup0_se2, qup0_se5, phase_flag, tgu_ch2, _, _, _, _, _),
+ [37] = PINGROUP(37, qup0_se2, qup0_se5, phase_flag, tgu_ch3, _, _, _, _, _),
+ [38] = PINGROUP(38, qup0_se5, qup0_se2, qdss_cti, phase_flag, tgu_ch4, _, _, _, _),
+ [39] = PINGROUP(39, qup0_se5, qup0_se2, qdss_cti, phase_flag, tgu_ch5, _, _, _, _),
+ [40] = PINGROUP(40, qup1_se0, qup1_se1, ibi_i3c, mdp1_vsync0, _, _, _, _, _),
+ [41] = PINGROUP(41, qup1_se0, qup1_se1, ibi_i3c, mdp1_vsync1, _, _, _, _, _),
+ [42] = PINGROUP(42, qup1_se1, qup1_se0, ibi_i3c, mdp1_vsync2, gcc_gp5, _, _, _, _),
+ [43] = PINGROUP(43, qup1_se1, qup1_se0, ibi_i3c, mdp1_vsync3, _, _, _, _, _),
+ [44] = PINGROUP(44, qup1_se2, qup1_se3, edp0_lcd, _, _, _, _, _, _),
+ [45] = PINGROUP(45, qup1_se2, qup1_se3, edp1_lcd, _, _, _, _, _, _),
+ [46] = PINGROUP(46, qup1_se3, qup1_se2, mdp1_vsync4, tgu_ch0, _, _, _, _, _),
+ [47] = PINGROUP(47, qup1_se3, qup1_se2, mdp1_vsync5, tgu_ch1, _, _, _, _, _),
+ [48] = PINGROUP(48, qup1_se4, qdss_cti, edp2_lcd, _, _, _, _, _, _),
+ [49] = PINGROUP(49, qup1_se4, qdss_cti, edp3_lcd, _, _, _, _, _, _),
+ [50] = PINGROUP(50, qup1_se4, cci_async, qdss_cti, mdp1_vsync8, _, _, _, _, _),
+ [51] = PINGROUP(51, qup1_se4, qdss_cti, mdp1_vsync6, gcc_gp1, _, _, _, _, _),
+ [52] = PINGROUP(52, qup1_se5, cci_timer4, cci_i2c, mdp1_vsync7, gcc_gp2, _, ddr_pxi1, _, _),
+ [53] = PINGROUP(53, qup1_se5, cci_timer5, cci_i2c, gcc_gp3, _, ddr_pxi1, _, _, _),
+ [54] = PINGROUP(54, qup1_se5, cci_timer6, cci_i2c, _, _, _, _, _, _),
+ [55] = PINGROUP(55, qup1_se5, cci_timer7, cci_i2c, gcc_gp4, _, ddr_pxi2, _, _, _),
+ [56] = PINGROUP(56, qup1_se6, qup1_se6, cci_timer8, cci_i2c, phase_flag,
+ ddr_bist, _, _, _),
+ [57] = PINGROUP(57, qup1_se6, qup1_se6, cci_timer9, cci_i2c, mdp0_vsync0,
+ phase_flag, ddr_bist, _, _),
+ [58] = PINGROUP(58, cci_i2c, mdp0_vsync1, ddr_bist, _, atest_usb2, atest_char, _, _, _),
+ [59] = PINGROUP(59, cci_i2c, mdp0_vsync2, ddr_bist, _, atest_usb2, atest_char, _, _, _),
+ [60] = PINGROUP(60, cci_i2c, qdss_gpio, _, _, _, _, _, _, _),
+ [61] = PINGROUP(61, cci_i2c, qdss_gpio, _, _, _, _, _, _, _),
+ [62] = PINGROUP(62, cci_i2c, qdss_gpio, _, _, _, _, _, _, _),
+ [63] = PINGROUP(63, cci_i2c, qdss_gpio, _, _, _, _, _, _, _),
+ [64] = PINGROUP(64, cci_i2c, qdss_gpio, _, _, _, _, _, _, _),
+ [65] = PINGROUP(65, cci_i2c, qdss_gpio, _, _, _, _, _, _, _),
+ [66] = PINGROUP(66, cci_i2c, cci_async, qdss_gpio, _, _, _, _, _, _),
+ [67] = PINGROUP(67, cci_i2c, qdss_gpio, _, _, _, _, _, _, _),
+ [68] = PINGROUP(68, cci_timer0, cci_async, _, _, _, _, _, _, _),
+ [69] = PINGROUP(69, cci_timer1, cci_async, _, _, _, _, _, _, _),
+ [70] = PINGROUP(70, cci_timer2, cci_async, _, _, _, _, _, _, _),
+ [71] = PINGROUP(71, cci_timer3, cci_async, _, _, _, _, _, _, _),
+ [72] = PINGROUP(72, cam_mclk, _, _, _, _, _, _, _, _),
+ [73] = PINGROUP(73, cam_mclk, _, _, _, _, _, _, _, _),
+ [74] = PINGROUP(74, cam_mclk, _, _, _, _, _, _, _, _),
+ [75] = PINGROUP(75, cam_mclk, _, _, _, _, _, _, _, _),
+ [76] = PINGROUP(76, _, _, _, _, _, _, _, _, _),
+ [77] = PINGROUP(77, _, _, _, _, _, _, _, _, _),
+ [78] = PINGROUP(78, _, _, _, _, _, _, _, _, _),
+ [79] = PINGROUP(79, _, _, _, _, _, _, _, _, _),
+ [80] = PINGROUP(80, qup2_se0, ibi_i3c, mdp0_vsync3, _, _, _, _, _, _),
+ [81] = PINGROUP(81, qup2_se0, ibi_i3c, mdp0_vsync4, _, _, _, _, _, _),
+ [82] = PINGROUP(82, qup2_se0, mdp_vsync, gcc_gp1, _, _, _, _, _, _),
+ [83] = PINGROUP(83, qup2_se0, mdp_vsync, gcc_gp2, _, _, _, _, _, _),
+ [84] = PINGROUP(84, qup2_se1, qup2_se5, ibi_i3c, mdp_vsync, gcc_gp3, _, _, _, _),
+ [85] = PINGROUP(85, qup2_se1, qup2_se5, ibi_i3c, _, _, _, _, _, _),
+ [86] = PINGROUP(86, qup2_se2, jitter_bist, atest_usb2, ddr_pxi2, _, _, _, _, _),
+ [87] = PINGROUP(87, qup2_se2, pll_clk, atest_usb2, ddr_pxi3, _, _, _, _, _),
+ [88] = PINGROUP(88, qup2_se2, _, atest_usb2, ddr_pxi3, _, _, _, _, _),
+ [89] = PINGROUP(89, qup2_se2, _, atest_usb2, ddr_pxi4, atest_char, _, _, _, _),
+ [90] = PINGROUP(90, qup2_se2, _, atest_usb2, ddr_pxi4, atest_char, _, _, _, _),
+ [91] = PINGROUP(91, qup2_se3, mdp0_vsync5, _, atest_usb2, _, _, _, _, _),
+ [92] = PINGROUP(92, qup2_se3, mdp0_vsync6, _, atest_usb2, _, _, _, _, _),
+ [93] = PINGROUP(93, qup2_se3, mdp0_vsync7, _, atest_usb2, _, _, _, _, _),
+ [94] = PINGROUP(94, qup2_se3, mdp0_vsync8, _, atest_usb2, _, _, _, _, _),
+ [95] = PINGROUP(95, qup2_se4, qup2_se6, _, atest_usb2, _, _, _, _, _),
+ [96] = PINGROUP(96, qup2_se4, qup2_se6, _, atest_usb2, _, _, _, _, _),
+ [97] = PINGROUP(97, qup2_se6, qup2_se4, cri_trng0, _, atest_usb2, _, _, _, _),
+ [98] = PINGROUP(98, qup2_se6, qup2_se4, phase_flag, cri_trng1, _, _, _, _, _),
+ [99] = PINGROUP(99, qup2_se5, qup2_se1, phase_flag, cri_trng, _, _, _, _, _),
+ [100] = PINGROUP(100, qup2_se5, qup2_se1, _, _, _, _, _, _, _),
+ [101] = PINGROUP(101, edp0_hot, prng_rosc0, tsense_pwm4, _, _, _, _, _, _),
+ [102] = PINGROUP(102, edp1_hot, prng_rosc1, tsense_pwm3, _, _, _, _, _, _),
+ [103] = PINGROUP(103, edp3_hot, prng_rosc2, tsense_pwm2, _, _, _, _, _, _),
+ [104] = PINGROUP(104, edp2_hot, prng_rosc3, tsense_pwm1, _, _, _, _, _, _),
+ [105] = PINGROUP(105, mi2s_mclk0, _, qdss_gpio, atest_usb2, _, _, _, _, _),
+ [106] = PINGROUP(106, mi2s1_sck, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [107] = PINGROUP(107, mi2s1_ws, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [108] = PINGROUP(108, mi2s1_data0, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [109] = PINGROUP(109, mi2s1_data1, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [110] = PINGROUP(110, mi2s2_sck, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [111] = PINGROUP(111, mi2s2_ws, phase_flag, _, qdss_gpio, vsense_trigger, _, _, _, _),
+ [112] = PINGROUP(112, mi2s2_data0, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [113] = PINGROUP(113, mi2s2_data1, audio_ref, phase_flag, _, qdss_gpio, _, _, _, _),
+ [114] = PINGROUP(114, hs0_mi2s, pll_bist, phase_flag, _, qdss_gpio, _, _, _, _),
+ [115] = PINGROUP(115, hs0_mi2s, _, qdss_gpio, _, _, _, _, _, _),
+ [116] = PINGROUP(116, hs0_mi2s, _, qdss_gpio, _, _, _, _, _, _),
+ [117] = PINGROUP(117, hs0_mi2s, mi2s_mclk1, _, qdss_gpio, _, _, _, _, _),
+ [118] = PINGROUP(118, hs1_mi2s, _, qdss_gpio, ddr_pxi5, _, _, _, _, _),
+ [119] = PINGROUP(119, hs1_mi2s, _, qdss_gpio, ddr_pxi5, _, _, _, _, _),
+ [120] = PINGROUP(120, hs1_mi2s, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [121] = PINGROUP(121, hs1_mi2s, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [122] = PINGROUP(122, hs2_mi2s, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [123] = PINGROUP(123, hs2_mi2s, phase_flag, _, _, _, _, _, _, _),
+ [124] = PINGROUP(124, hs2_mi2s, phase_flag, _, _, _, _, _, _, _),
+ [125] = PINGROUP(125, hs2_mi2s, phase_flag, _, _, _, _, _, _, _),
+ [126] = PINGROUP(126, _, _, _, _, _, _, _, _, _),
+ [127] = PINGROUP(127, _, _, _, _, _, _, _, _, _),
+ [128] = PINGROUP(128, _, _, _, _, _, _, _, _, _),
+ [129] = PINGROUP(129, _, _, _, _, _, _, _, _, _),
+ [130] = PINGROUP(130, _, _, _, _, _, _, _, _, _),
+ [131] = PINGROUP(131, _, _, _, _, _, _, _, _, _),
+ [132] = PINGROUP(132, _, _, _, _, _, _, _, _, _),
+ [133] = PINGROUP(133, _, _, _, _, _, _, _, _, _),
+ [134] = PINGROUP(134, _, _, _, _, _, _, _, _, _),
+ [135] = PINGROUP(135, _, _, _, _, _, _, _, _, _),
+ [136] = PINGROUP(136, _, _, _, _, _, _, _, _, _),
+ [137] = PINGROUP(137, _, _, _, _, _, _, _, _, _),
+ [138] = PINGROUP(138, _, _, _, _, _, _, _, _, _),
+ [139] = PINGROUP(139, _, _, _, _, _, _, _, _, _),
+ [140] = PINGROUP(140, _, _, _, _, _, _, _, _, _),
+ [141] = PINGROUP(141, _, _, _, _, _, _, _, _, _),
+ [142] = PINGROUP(142, _, _, _, _, _, _, _, _, _),
+ [143] = PINGROUP(143, _, _, _, _, _, _, _, _, _),
+ [144] = PINGROUP(144, dbg_out, _, _, _, _, _, _, _, _),
+ [145] = PINGROUP(145, _, _, _, _, _, _, _, _, _),
+ [146] = PINGROUP(146, _, _, _, _, _, _, _, _, _),
+ [147] = PINGROUP(147, _, _, _, _, _, _, _, _, _),
+ [148] = PINGROUP(148, _, _, _, _, _, _, _, _, _),
+ [149] = UFS_RESET(ufs_reset, 0x1a2000),
+ [150] = SDC_QDSD_PINGROUP(sdc1_rclk, 0x199000, 15, 0),
+ [151] = SDC_QDSD_PINGROUP(sdc1_clk, 0x199000, 13, 6),
+ [152] = SDC_QDSD_PINGROUP(sdc1_cmd, 0x199000, 11, 3),
+ [153] = SDC_QDSD_PINGROUP(sdc1_data, 0x199000, 9, 0),
+};
+
+static const struct msm_pinctrl_soc_data sa8775p_pinctrl = {
+ .pins = sa8775p_pins,
+ .npins = ARRAY_SIZE(sa8775p_pins),
+ .functions = sa8775p_functions,
+ .nfunctions = ARRAY_SIZE(sa8775p_functions),
+ .groups = sa8775p_groups,
+ .ngroups = ARRAY_SIZE(sa8775p_groups),
+ .ngpios = 150,
+};
+
+static int sa8775p_pinctrl_probe(struct platform_device *pdev)
+{
+ return msm_pinctrl_probe(pdev, &sa8775p_pinctrl);
+}
+
+static const struct of_device_id sa8775p_pinctrl_of_match[] = {
+ { .compatible = "qcom,sa8775p-tlmm", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, sa8775p_pinctrl_of_match);
+
+static struct platform_driver sa8775p_pinctrl_driver = {
+ .driver = {
+ .name = "sa8775p-tlmm",
+ .of_match_table = sa8775p_pinctrl_of_match,
+ },
+ .probe = sa8775p_pinctrl_probe,
+ .remove = msm_pinctrl_remove,
+};
+
+static int __init sa8775p_pinctrl_init(void)
+{
+ return platform_driver_register(&sa8775p_pinctrl_driver);
+}
+arch_initcall(sa8775p_pinctrl_init);
+
+static void __exit sa8775p_pinctrl_exit(void)
+{
+ platform_driver_unregister(&sa8775p_pinctrl_driver);
+}
+module_exit(sa8775p_pinctrl_exit);
+
+MODULE_DESCRIPTION("QTI SA8775P pinctrl driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/qcom/pinctrl-sm8550-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sm8550-lpass-lpi.c
new file mode 100644
index 000000000000..c2bdd936d27f
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-sm8550-lpass-lpi.c
@@ -0,0 +1,240 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022-2023 Linaro Ltd.
+ */
+
+#include <linux/gpio/driver.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include "pinctrl-lpass-lpi.h"
+
+enum lpass_lpi_functions {
+ LPI_MUX_dmic1_clk,
+ LPI_MUX_dmic1_data,
+ LPI_MUX_dmic2_clk,
+ LPI_MUX_dmic2_data,
+ LPI_MUX_dmic3_clk,
+ LPI_MUX_dmic3_data,
+ LPI_MUX_dmic4_clk,
+ LPI_MUX_dmic4_data,
+ LPI_MUX_i2s0_clk,
+ LPI_MUX_i2s0_data,
+ LPI_MUX_i2s0_ws,
+ LPI_MUX_i2s1_clk,
+ LPI_MUX_i2s1_data,
+ LPI_MUX_i2s1_ws,
+ LPI_MUX_i2s2_clk,
+ LPI_MUX_i2s2_data,
+ LPI_MUX_i2s2_ws,
+ LPI_MUX_i2s3_clk,
+ LPI_MUX_i2s3_data,
+ LPI_MUX_i2s3_ws,
+ LPI_MUX_i2s4_clk,
+ LPI_MUX_i2s4_data,
+ LPI_MUX_i2s4_ws,
+ LPI_MUX_slimbus_clk,
+ LPI_MUX_slimbus_data,
+ LPI_MUX_swr_rx_clk,
+ LPI_MUX_swr_rx_data,
+ LPI_MUX_swr_tx_clk,
+ LPI_MUX_swr_tx_data,
+ LPI_MUX_wsa_swr_clk,
+ LPI_MUX_wsa_swr_data,
+ LPI_MUX_wsa2_swr_clk,
+ LPI_MUX_wsa2_swr_data,
+ LPI_MUX_ext_mclk1_a,
+ LPI_MUX_ext_mclk1_b,
+ LPI_MUX_ext_mclk1_c,
+ LPI_MUX_ext_mclk1_d,
+ LPI_MUX_ext_mclk1_e,
+ LPI_MUX_gpio,
+ LPI_MUX__,
+};
+
+static int gpio0_pins[] = { 0 };
+static int gpio1_pins[] = { 1 };
+static int gpio2_pins[] = { 2 };
+static int gpio3_pins[] = { 3 };
+static int gpio4_pins[] = { 4 };
+static int gpio5_pins[] = { 5 };
+static int gpio6_pins[] = { 6 };
+static int gpio7_pins[] = { 7 };
+static int gpio8_pins[] = { 8 };
+static int gpio9_pins[] = { 9 };
+static int gpio10_pins[] = { 10 };
+static int gpio11_pins[] = { 11 };
+static int gpio12_pins[] = { 12 };
+static int gpio13_pins[] = { 13 };
+static int gpio14_pins[] = { 14 };
+static int gpio15_pins[] = { 15 };
+static int gpio16_pins[] = { 16 };
+static int gpio17_pins[] = { 17 };
+static int gpio18_pins[] = { 18 };
+static int gpio19_pins[] = { 19 };
+static int gpio20_pins[] = { 20 };
+static int gpio21_pins[] = { 21 };
+static int gpio22_pins[] = { 22 };
+
+static const struct pinctrl_pin_desc sm8550_lpi_pins[] = {
+ PINCTRL_PIN(0, "gpio0"),
+ PINCTRL_PIN(1, "gpio1"),
+ PINCTRL_PIN(2, "gpio2"),
+ PINCTRL_PIN(3, "gpio3"),
+ PINCTRL_PIN(4, "gpio4"),
+ PINCTRL_PIN(5, "gpio5"),
+ PINCTRL_PIN(6, "gpio6"),
+ PINCTRL_PIN(7, "gpio7"),
+ PINCTRL_PIN(8, "gpio8"),
+ PINCTRL_PIN(9, "gpio9"),
+ PINCTRL_PIN(10, "gpio10"),
+ PINCTRL_PIN(11, "gpio11"),
+ PINCTRL_PIN(12, "gpio12"),
+ PINCTRL_PIN(13, "gpio13"),
+ PINCTRL_PIN(14, "gpio14"),
+ PINCTRL_PIN(15, "gpio15"),
+ PINCTRL_PIN(16, "gpio16"),
+ PINCTRL_PIN(17, "gpio17"),
+ PINCTRL_PIN(18, "gpio18"),
+ PINCTRL_PIN(19, "gpio19"),
+ PINCTRL_PIN(20, "gpio20"),
+ PINCTRL_PIN(21, "gpio21"),
+ PINCTRL_PIN(22, "gpio22"),
+};
+
+static const char * const dmic1_clk_groups[] = { "gpio6" };
+static const char * const dmic1_data_groups[] = { "gpio7" };
+static const char * const dmic2_clk_groups[] = { "gpio8" };
+static const char * const dmic2_data_groups[] = { "gpio9" };
+static const char * const dmic3_clk_groups[] = { "gpio12" };
+static const char * const dmic3_data_groups[] = { "gpio13" };
+static const char * const dmic4_clk_groups[] = { "gpio17" };
+static const char * const dmic4_data_groups[] = { "gpio18" };
+static const char * const i2s0_clk_groups[] = { "gpio0" };
+static const char * const i2s0_ws_groups[] = { "gpio1" };
+static const char * const i2s0_data_groups[] = { "gpio2", "gpio3", "gpio4", "gpio5" };
+static const char * const i2s1_clk_groups[] = { "gpio6" };
+static const char * const i2s1_ws_groups[] = { "gpio7" };
+static const char * const i2s1_data_groups[] = { "gpio8", "gpio9" };
+static const char * const i2s2_clk_groups[] = { "gpio10" };
+static const char * const i2s2_ws_groups[] = { "gpio11" };
+static const char * const i2s2_data_groups[] = { "gpio15", "gpio16" };
+static const char * const i2s3_clk_groups[] = { "gpio12" };
+static const char * const i2s3_ws_groups[] = { "gpio13" };
+static const char * const i2s3_data_groups[] = { "gpio17", "gpio18" };
+static const char * const i2s4_clk_groups[] = { "gpio19"};
+static const char * const i2s4_ws_groups[] = { "gpio20"};
+static const char * const i2s4_data_groups[] = { "gpio21", "gpio22"};
+static const char * const slimbus_clk_groups[] = { "gpio19"};
+static const char * const slimbus_data_groups[] = { "gpio20"};
+static const char * const swr_tx_clk_groups[] = { "gpio0" };
+static const char * const swr_tx_data_groups[] = { "gpio1", "gpio2", "gpio14" };
+static const char * const swr_rx_clk_groups[] = { "gpio3" };
+static const char * const swr_rx_data_groups[] = { "gpio4", "gpio5", "gpio15" };
+static const char * const wsa_swr_clk_groups[] = { "gpio10" };
+static const char * const wsa_swr_data_groups[] = { "gpio11" };
+static const char * const wsa2_swr_clk_groups[] = { "gpio15" };
+static const char * const wsa2_swr_data_groups[] = { "gpio16" };
+static const char * const ext_mclk1_c_groups[] = { "gpio5" };
+static const char * const ext_mclk1_b_groups[] = { "gpio9" };
+static const char * const ext_mclk1_a_groups[] = { "gpio13" };
+static const char * const ext_mclk1_d_groups[] = { "gpio14" };
+static const char * const ext_mclk1_e_groups[] = { "gpio22" };
+
+static const struct lpi_pingroup sm8550_groups[] = {
+ LPI_PINGROUP(0, 0, swr_tx_clk, i2s0_clk, _, _),
+ LPI_PINGROUP(1, 2, swr_tx_data, i2s0_ws, _, _),
+ LPI_PINGROUP(2, 4, swr_tx_data, i2s0_data, _, _),
+ LPI_PINGROUP(3, 8, swr_rx_clk, i2s0_data, _, _),
+ LPI_PINGROUP(4, 10, swr_rx_data, i2s0_data, _, _),
+ LPI_PINGROUP(5, 12, swr_rx_data, ext_mclk1_c, i2s0_data, _),
+ LPI_PINGROUP(6, LPI_NO_SLEW, dmic1_clk, i2s1_clk, _, _),
+ LPI_PINGROUP(7, LPI_NO_SLEW, dmic1_data, i2s1_ws, _, _),
+ LPI_PINGROUP(8, LPI_NO_SLEW, dmic2_clk, i2s1_data, _, _),
+ LPI_PINGROUP(9, LPI_NO_SLEW, dmic2_data, i2s1_data, ext_mclk1_b, _),
+ LPI_PINGROUP(10, 16, i2s2_clk, wsa_swr_clk, _, _),
+ LPI_PINGROUP(11, 18, i2s2_ws, wsa_swr_data, _, _),
+ LPI_PINGROUP(12, LPI_NO_SLEW, dmic3_clk, i2s3_clk, _, _),
+ LPI_PINGROUP(13, LPI_NO_SLEW, dmic3_data, i2s3_ws, ext_mclk1_a, _),
+ LPI_PINGROUP(14, 6, swr_tx_data, ext_mclk1_d, _, _),
+ LPI_PINGROUP(15, 20, i2s2_data, wsa2_swr_clk, _, _),
+ LPI_PINGROUP(16, 22, i2s2_data, wsa2_swr_data, _, _),
+ LPI_PINGROUP(17, LPI_NO_SLEW, dmic4_clk, i2s3_data, _, _),
+ LPI_PINGROUP(18, LPI_NO_SLEW, dmic4_data, i2s3_data, _, _),
+ LPI_PINGROUP(19, LPI_NO_SLEW, i2s4_clk, slimbus_clk, _, _),
+ LPI_PINGROUP(20, LPI_NO_SLEW, i2s4_ws, slimbus_data, _, _),
+ LPI_PINGROUP(21, LPI_NO_SLEW, i2s4_data, _, _, _),
+ LPI_PINGROUP(22, LPI_NO_SLEW, i2s4_data, ext_mclk1_e, _, _),
+};
+
+static const struct lpi_function sm8550_functions[] = {
+ LPI_FUNCTION(dmic1_clk),
+ LPI_FUNCTION(dmic1_data),
+ LPI_FUNCTION(dmic2_clk),
+ LPI_FUNCTION(dmic2_data),
+ LPI_FUNCTION(dmic3_clk),
+ LPI_FUNCTION(dmic3_data),
+ LPI_FUNCTION(dmic4_clk),
+ LPI_FUNCTION(dmic4_data),
+ LPI_FUNCTION(i2s0_clk),
+ LPI_FUNCTION(i2s0_data),
+ LPI_FUNCTION(i2s0_ws),
+ LPI_FUNCTION(i2s1_clk),
+ LPI_FUNCTION(i2s1_data),
+ LPI_FUNCTION(i2s1_ws),
+ LPI_FUNCTION(i2s2_clk),
+ LPI_FUNCTION(i2s2_data),
+ LPI_FUNCTION(i2s2_ws),
+ LPI_FUNCTION(i2s3_clk),
+ LPI_FUNCTION(i2s3_data),
+ LPI_FUNCTION(i2s3_ws),
+ LPI_FUNCTION(i2s4_clk),
+ LPI_FUNCTION(i2s4_data),
+ LPI_FUNCTION(i2s4_ws),
+ LPI_FUNCTION(slimbus_clk),
+ LPI_FUNCTION(slimbus_data),
+ LPI_FUNCTION(swr_rx_clk),
+ LPI_FUNCTION(swr_rx_data),
+ LPI_FUNCTION(swr_tx_clk),
+ LPI_FUNCTION(swr_tx_data),
+ LPI_FUNCTION(wsa_swr_clk),
+ LPI_FUNCTION(wsa_swr_data),
+ LPI_FUNCTION(wsa2_swr_clk),
+ LPI_FUNCTION(wsa2_swr_data),
+ LPI_FUNCTION(ext_mclk1_a),
+ LPI_FUNCTION(ext_mclk1_b),
+ LPI_FUNCTION(ext_mclk1_c),
+ LPI_FUNCTION(ext_mclk1_d),
+ LPI_FUNCTION(ext_mclk1_e),
+};
+
+static const struct lpi_pinctrl_variant_data sm8550_lpi_data = {
+ .pins = sm8550_lpi_pins,
+ .npins = ARRAY_SIZE(sm8550_lpi_pins),
+ .groups = sm8550_groups,
+ .ngroups = ARRAY_SIZE(sm8550_groups),
+ .functions = sm8550_functions,
+ .nfunctions = ARRAY_SIZE(sm8550_functions),
+};
+
+static const struct of_device_id lpi_pinctrl_of_match[] = {
+ {
+ .compatible = "qcom,sm8550-lpass-lpi-pinctrl",
+ .data = &sm8550_lpi_data,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, lpi_pinctrl_of_match);
+
+static struct platform_driver lpi_pinctrl_driver = {
+ .driver = {
+ .name = "qcom-sm8550-lpass-lpi-pinctrl",
+ .of_match_table = lpi_pinctrl_of_match,
+ },
+ .probe = lpi_pinctrl_probe,
+ .remove = lpi_pinctrl_remove,
+};
+
+module_platform_driver(lpi_pinctrl_driver);
+MODULE_DESCRIPTION("Qualcomm SM8550 LPI GPIO pin control driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/qcom/pinctrl-sm8550.c b/drivers/pinctrl/qcom/pinctrl-sm8550.c
new file mode 100644
index 000000000000..c9d038098f2c
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-sm8550.c
@@ -0,0 +1,1790 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022, Linaro Limited
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-msm.h"
+
+#define FUNCTION(fname) \
+ [msm_mux_##fname] = { \
+ .name = #fname, \
+ .groups = fname##_groups, \
+ .ngroups = ARRAY_SIZE(fname##_groups), \
+ }
+
+#define REG_SIZE 0x1000
+
+#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9) \
+ { \
+ .name = "gpio" #id, \
+ .pins = gpio##id##_pins, \
+ .npins = (unsigned int)ARRAY_SIZE(gpio##id##_pins), \
+ .funcs = (int[]){ \
+ msm_mux_gpio, /* gpio mode */ \
+ msm_mux_##f1, \
+ msm_mux_##f2, \
+ msm_mux_##f3, \
+ msm_mux_##f4, \
+ msm_mux_##f5, \
+ msm_mux_##f6, \
+ msm_mux_##f7, \
+ msm_mux_##f8, \
+ msm_mux_##f9 \
+ }, \
+ .nfuncs = 10, \
+ .ctl_reg = REG_SIZE * id, \
+ .io_reg = 0x4 + REG_SIZE * id, \
+ .intr_cfg_reg = 0x8 + REG_SIZE * id, \
+ .intr_status_reg = 0xc + REG_SIZE * id, \
+ .intr_target_reg = 0x8 + REG_SIZE * id, \
+ .mux_bit = 2, \
+ .pull_bit = 0, \
+ .drv_bit = 6, \
+ .i2c_pull_bit = 13, \
+ .egpio_enable = 12, \
+ .egpio_present = 11, \
+ .oe_bit = 9, \
+ .in_bit = 0, \
+ .out_bit = 1, \
+ .intr_enable_bit = 0, \
+ .intr_status_bit = 0, \
+ .intr_target_bit = 5, \
+ .intr_target_kpss_val = 3, \
+ .intr_raw_status_bit = 4, \
+ .intr_polarity_bit = 1, \
+ .intr_detection_bit = 2, \
+ .intr_detection_width = 2, \
+ }
+
+#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \
+ { \
+ .name = #pg_name, \
+ .pins = pg_name##_pins, \
+ .npins = (unsigned int)ARRAY_SIZE(pg_name##_pins), \
+ .ctl_reg = ctl, \
+ .io_reg = 0, \
+ .intr_cfg_reg = 0, \
+ .intr_status_reg = 0, \
+ .intr_target_reg = 0, \
+ .mux_bit = -1, \
+ .pull_bit = pull, \
+ .drv_bit = drv, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = -1, \
+ .intr_enable_bit = -1, \
+ .intr_status_bit = -1, \
+ .intr_target_bit = -1, \
+ .intr_raw_status_bit = -1, \
+ .intr_polarity_bit = -1, \
+ .intr_detection_bit = -1, \
+ .intr_detection_width = -1, \
+ }
+
+#define UFS_RESET(pg_name, offset) \
+ { \
+ .name = #pg_name, \
+ .pins = pg_name##_pins, \
+ .npins = (unsigned int)ARRAY_SIZE(pg_name##_pins), \
+ .ctl_reg = offset, \
+ .io_reg = offset + 0x4, \
+ .intr_cfg_reg = 0, \
+ .intr_status_reg = 0, \
+ .intr_target_reg = 0, \
+ .mux_bit = -1, \
+ .pull_bit = 3, \
+ .drv_bit = 0, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = 0, \
+ .intr_enable_bit = -1, \
+ .intr_status_bit = -1, \
+ .intr_target_bit = -1, \
+ .intr_raw_status_bit = -1, \
+ .intr_polarity_bit = -1, \
+ .intr_detection_bit = -1, \
+ .intr_detection_width = -1, \
+ }
+
+static const struct pinctrl_pin_desc sm8550_pins[] = {
+ PINCTRL_PIN(0, "GPIO_0"),
+ PINCTRL_PIN(1, "GPIO_1"),
+ PINCTRL_PIN(2, "GPIO_2"),
+ PINCTRL_PIN(3, "GPIO_3"),
+ PINCTRL_PIN(4, "GPIO_4"),
+ PINCTRL_PIN(5, "GPIO_5"),
+ PINCTRL_PIN(6, "GPIO_6"),
+ PINCTRL_PIN(7, "GPIO_7"),
+ PINCTRL_PIN(8, "GPIO_8"),
+ PINCTRL_PIN(9, "GPIO_9"),
+ PINCTRL_PIN(10, "GPIO_10"),
+ PINCTRL_PIN(11, "GPIO_11"),
+ PINCTRL_PIN(12, "GPIO_12"),
+ PINCTRL_PIN(13, "GPIO_13"),
+ PINCTRL_PIN(14, "GPIO_14"),
+ PINCTRL_PIN(15, "GPIO_15"),
+ PINCTRL_PIN(16, "GPIO_16"),
+ PINCTRL_PIN(17, "GPIO_17"),
+ PINCTRL_PIN(18, "GPIO_18"),
+ PINCTRL_PIN(19, "GPIO_19"),
+ PINCTRL_PIN(20, "GPIO_20"),
+ PINCTRL_PIN(21, "GPIO_21"),
+ PINCTRL_PIN(22, "GPIO_22"),
+ PINCTRL_PIN(23, "GPIO_23"),
+ PINCTRL_PIN(24, "GPIO_24"),
+ PINCTRL_PIN(25, "GPIO_25"),
+ PINCTRL_PIN(26, "GPIO_26"),
+ PINCTRL_PIN(27, "GPIO_27"),
+ PINCTRL_PIN(28, "GPIO_28"),
+ PINCTRL_PIN(29, "GPIO_29"),
+ PINCTRL_PIN(30, "GPIO_30"),
+ PINCTRL_PIN(31, "GPIO_31"),
+ PINCTRL_PIN(32, "GPIO_32"),
+ PINCTRL_PIN(33, "GPIO_33"),
+ PINCTRL_PIN(34, "GPIO_34"),
+ PINCTRL_PIN(35, "GPIO_35"),
+ PINCTRL_PIN(36, "GPIO_36"),
+ PINCTRL_PIN(37, "GPIO_37"),
+ PINCTRL_PIN(38, "GPIO_38"),
+ PINCTRL_PIN(39, "GPIO_39"),
+ PINCTRL_PIN(40, "GPIO_40"),
+ PINCTRL_PIN(41, "GPIO_41"),
+ PINCTRL_PIN(42, "GPIO_42"),
+ PINCTRL_PIN(43, "GPIO_43"),
+ PINCTRL_PIN(44, "GPIO_44"),
+ PINCTRL_PIN(45, "GPIO_45"),
+ PINCTRL_PIN(46, "GPIO_46"),
+ PINCTRL_PIN(47, "GPIO_47"),
+ PINCTRL_PIN(48, "GPIO_48"),
+ PINCTRL_PIN(49, "GPIO_49"),
+ PINCTRL_PIN(50, "GPIO_50"),
+ PINCTRL_PIN(51, "GPIO_51"),
+ PINCTRL_PIN(52, "GPIO_52"),
+ PINCTRL_PIN(53, "GPIO_53"),
+ PINCTRL_PIN(54, "GPIO_54"),
+ PINCTRL_PIN(55, "GPIO_55"),
+ PINCTRL_PIN(56, "GPIO_56"),
+ PINCTRL_PIN(57, "GPIO_57"),
+ PINCTRL_PIN(58, "GPIO_58"),
+ PINCTRL_PIN(59, "GPIO_59"),
+ PINCTRL_PIN(60, "GPIO_60"),
+ PINCTRL_PIN(61, "GPIO_61"),
+ PINCTRL_PIN(62, "GPIO_62"),
+ PINCTRL_PIN(63, "GPIO_63"),
+ PINCTRL_PIN(64, "GPIO_64"),
+ PINCTRL_PIN(65, "GPIO_65"),
+ PINCTRL_PIN(66, "GPIO_66"),
+ PINCTRL_PIN(67, "GPIO_67"),
+ PINCTRL_PIN(68, "GPIO_68"),
+ PINCTRL_PIN(69, "GPIO_69"),
+ PINCTRL_PIN(70, "GPIO_70"),
+ PINCTRL_PIN(71, "GPIO_71"),
+ PINCTRL_PIN(72, "GPIO_72"),
+ PINCTRL_PIN(73, "GPIO_73"),
+ PINCTRL_PIN(74, "GPIO_74"),
+ PINCTRL_PIN(75, "GPIO_75"),
+ PINCTRL_PIN(76, "GPIO_76"),
+ PINCTRL_PIN(77, "GPIO_77"),
+ PINCTRL_PIN(78, "GPIO_78"),
+ PINCTRL_PIN(79, "GPIO_79"),
+ PINCTRL_PIN(80, "GPIO_80"),
+ PINCTRL_PIN(81, "GPIO_81"),
+ PINCTRL_PIN(82, "GPIO_82"),
+ PINCTRL_PIN(83, "GPIO_83"),
+ PINCTRL_PIN(84, "GPIO_84"),
+ PINCTRL_PIN(85, "GPIO_85"),
+ PINCTRL_PIN(86, "GPIO_86"),
+ PINCTRL_PIN(87, "GPIO_87"),
+ PINCTRL_PIN(88, "GPIO_88"),
+ PINCTRL_PIN(89, "GPIO_89"),
+ PINCTRL_PIN(90, "GPIO_90"),
+ PINCTRL_PIN(91, "GPIO_91"),
+ PINCTRL_PIN(92, "GPIO_92"),
+ PINCTRL_PIN(93, "GPIO_93"),
+ PINCTRL_PIN(94, "GPIO_94"),
+ PINCTRL_PIN(95, "GPIO_95"),
+ PINCTRL_PIN(96, "GPIO_96"),
+ PINCTRL_PIN(97, "GPIO_97"),
+ PINCTRL_PIN(98, "GPIO_98"),
+ PINCTRL_PIN(99, "GPIO_99"),
+ PINCTRL_PIN(100, "GPIO_100"),
+ PINCTRL_PIN(101, "GPIO_101"),
+ PINCTRL_PIN(102, "GPIO_102"),
+ PINCTRL_PIN(103, "GPIO_103"),
+ PINCTRL_PIN(104, "GPIO_104"),
+ PINCTRL_PIN(105, "GPIO_105"),
+ PINCTRL_PIN(106, "GPIO_106"),
+ PINCTRL_PIN(107, "GPIO_107"),
+ PINCTRL_PIN(108, "GPIO_108"),
+ PINCTRL_PIN(109, "GPIO_109"),
+ PINCTRL_PIN(110, "GPIO_110"),
+ PINCTRL_PIN(111, "GPIO_111"),
+ PINCTRL_PIN(112, "GPIO_112"),
+ PINCTRL_PIN(113, "GPIO_113"),
+ PINCTRL_PIN(114, "GPIO_114"),
+ PINCTRL_PIN(115, "GPIO_115"),
+ PINCTRL_PIN(116, "GPIO_116"),
+ PINCTRL_PIN(117, "GPIO_117"),
+ PINCTRL_PIN(118, "GPIO_118"),
+ PINCTRL_PIN(119, "GPIO_119"),
+ PINCTRL_PIN(120, "GPIO_120"),
+ PINCTRL_PIN(121, "GPIO_121"),
+ PINCTRL_PIN(122, "GPIO_122"),
+ PINCTRL_PIN(123, "GPIO_123"),
+ PINCTRL_PIN(124, "GPIO_124"),
+ PINCTRL_PIN(125, "GPIO_125"),
+ PINCTRL_PIN(126, "GPIO_126"),
+ PINCTRL_PIN(127, "GPIO_127"),
+ PINCTRL_PIN(128, "GPIO_128"),
+ PINCTRL_PIN(129, "GPIO_129"),
+ PINCTRL_PIN(130, "GPIO_130"),
+ PINCTRL_PIN(131, "GPIO_131"),
+ PINCTRL_PIN(132, "GPIO_132"),
+ PINCTRL_PIN(133, "GPIO_133"),
+ PINCTRL_PIN(134, "GPIO_134"),
+ PINCTRL_PIN(135, "GPIO_135"),
+ PINCTRL_PIN(136, "GPIO_136"),
+ PINCTRL_PIN(137, "GPIO_137"),
+ PINCTRL_PIN(138, "GPIO_138"),
+ PINCTRL_PIN(139, "GPIO_139"),
+ PINCTRL_PIN(140, "GPIO_140"),
+ PINCTRL_PIN(141, "GPIO_141"),
+ PINCTRL_PIN(142, "GPIO_142"),
+ PINCTRL_PIN(143, "GPIO_143"),
+ PINCTRL_PIN(144, "GPIO_144"),
+ PINCTRL_PIN(145, "GPIO_145"),
+ PINCTRL_PIN(146, "GPIO_146"),
+ PINCTRL_PIN(147, "GPIO_147"),
+ PINCTRL_PIN(148, "GPIO_148"),
+ PINCTRL_PIN(149, "GPIO_149"),
+ PINCTRL_PIN(150, "GPIO_150"),
+ PINCTRL_PIN(151, "GPIO_151"),
+ PINCTRL_PIN(152, "GPIO_152"),
+ PINCTRL_PIN(153, "GPIO_153"),
+ PINCTRL_PIN(154, "GPIO_154"),
+ PINCTRL_PIN(155, "GPIO_155"),
+ PINCTRL_PIN(156, "GPIO_156"),
+ PINCTRL_PIN(157, "GPIO_157"),
+ PINCTRL_PIN(158, "GPIO_158"),
+ PINCTRL_PIN(159, "GPIO_159"),
+ PINCTRL_PIN(160, "GPIO_160"),
+ PINCTRL_PIN(161, "GPIO_161"),
+ PINCTRL_PIN(162, "GPIO_162"),
+ PINCTRL_PIN(163, "GPIO_163"),
+ PINCTRL_PIN(164, "GPIO_164"),
+ PINCTRL_PIN(165, "GPIO_165"),
+ PINCTRL_PIN(166, "GPIO_166"),
+ PINCTRL_PIN(167, "GPIO_167"),
+ PINCTRL_PIN(168, "GPIO_168"),
+ PINCTRL_PIN(169, "GPIO_169"),
+ PINCTRL_PIN(170, "GPIO_170"),
+ PINCTRL_PIN(171, "GPIO_171"),
+ PINCTRL_PIN(172, "GPIO_172"),
+ PINCTRL_PIN(173, "GPIO_173"),
+ PINCTRL_PIN(174, "GPIO_174"),
+ PINCTRL_PIN(175, "GPIO_175"),
+ PINCTRL_PIN(176, "GPIO_176"),
+ PINCTRL_PIN(177, "GPIO_177"),
+ PINCTRL_PIN(178, "GPIO_178"),
+ PINCTRL_PIN(179, "GPIO_179"),
+ PINCTRL_PIN(180, "GPIO_180"),
+ PINCTRL_PIN(181, "GPIO_181"),
+ PINCTRL_PIN(182, "GPIO_182"),
+ PINCTRL_PIN(183, "GPIO_183"),
+ PINCTRL_PIN(184, "GPIO_184"),
+ PINCTRL_PIN(185, "GPIO_185"),
+ PINCTRL_PIN(186, "GPIO_186"),
+ PINCTRL_PIN(187, "GPIO_187"),
+ PINCTRL_PIN(188, "GPIO_188"),
+ PINCTRL_PIN(189, "GPIO_189"),
+ PINCTRL_PIN(190, "GPIO_190"),
+ PINCTRL_PIN(191, "GPIO_191"),
+ PINCTRL_PIN(192, "GPIO_192"),
+ PINCTRL_PIN(193, "GPIO_193"),
+ PINCTRL_PIN(194, "GPIO_194"),
+ PINCTRL_PIN(195, "GPIO_195"),
+ PINCTRL_PIN(196, "GPIO_196"),
+ PINCTRL_PIN(197, "GPIO_197"),
+ PINCTRL_PIN(198, "GPIO_198"),
+ PINCTRL_PIN(199, "GPIO_199"),
+ PINCTRL_PIN(200, "GPIO_200"),
+ PINCTRL_PIN(201, "GPIO_201"),
+ PINCTRL_PIN(202, "GPIO_202"),
+ PINCTRL_PIN(203, "GPIO_203"),
+ PINCTRL_PIN(204, "GPIO_204"),
+ PINCTRL_PIN(205, "GPIO_205"),
+ PINCTRL_PIN(206, "GPIO_206"),
+ PINCTRL_PIN(207, "GPIO_207"),
+ PINCTRL_PIN(208, "GPIO_208"),
+ PINCTRL_PIN(209, "GPIO_209"),
+ PINCTRL_PIN(210, "UFS_RESET"),
+ PINCTRL_PIN(211, "SDC2_CLK"),
+ PINCTRL_PIN(212, "SDC2_CMD"),
+ PINCTRL_PIN(213, "SDC2_DATA"),
+};
+
+#define DECLARE_MSM_GPIO_PINS(pin) \
+ static const unsigned int gpio##pin##_pins[] = { pin }
+DECLARE_MSM_GPIO_PINS(0);
+DECLARE_MSM_GPIO_PINS(1);
+DECLARE_MSM_GPIO_PINS(2);
+DECLARE_MSM_GPIO_PINS(3);
+DECLARE_MSM_GPIO_PINS(4);
+DECLARE_MSM_GPIO_PINS(5);
+DECLARE_MSM_GPIO_PINS(6);
+DECLARE_MSM_GPIO_PINS(7);
+DECLARE_MSM_GPIO_PINS(8);
+DECLARE_MSM_GPIO_PINS(9);
+DECLARE_MSM_GPIO_PINS(10);
+DECLARE_MSM_GPIO_PINS(11);
+DECLARE_MSM_GPIO_PINS(12);
+DECLARE_MSM_GPIO_PINS(13);
+DECLARE_MSM_GPIO_PINS(14);
+DECLARE_MSM_GPIO_PINS(15);
+DECLARE_MSM_GPIO_PINS(16);
+DECLARE_MSM_GPIO_PINS(17);
+DECLARE_MSM_GPIO_PINS(18);
+DECLARE_MSM_GPIO_PINS(19);
+DECLARE_MSM_GPIO_PINS(20);
+DECLARE_MSM_GPIO_PINS(21);
+DECLARE_MSM_GPIO_PINS(22);
+DECLARE_MSM_GPIO_PINS(23);
+DECLARE_MSM_GPIO_PINS(24);
+DECLARE_MSM_GPIO_PINS(25);
+DECLARE_MSM_GPIO_PINS(26);
+DECLARE_MSM_GPIO_PINS(27);
+DECLARE_MSM_GPIO_PINS(28);
+DECLARE_MSM_GPIO_PINS(29);
+DECLARE_MSM_GPIO_PINS(30);
+DECLARE_MSM_GPIO_PINS(31);
+DECLARE_MSM_GPIO_PINS(32);
+DECLARE_MSM_GPIO_PINS(33);
+DECLARE_MSM_GPIO_PINS(34);
+DECLARE_MSM_GPIO_PINS(35);
+DECLARE_MSM_GPIO_PINS(36);
+DECLARE_MSM_GPIO_PINS(37);
+DECLARE_MSM_GPIO_PINS(38);
+DECLARE_MSM_GPIO_PINS(39);
+DECLARE_MSM_GPIO_PINS(40);
+DECLARE_MSM_GPIO_PINS(41);
+DECLARE_MSM_GPIO_PINS(42);
+DECLARE_MSM_GPIO_PINS(43);
+DECLARE_MSM_GPIO_PINS(44);
+DECLARE_MSM_GPIO_PINS(45);
+DECLARE_MSM_GPIO_PINS(46);
+DECLARE_MSM_GPIO_PINS(47);
+DECLARE_MSM_GPIO_PINS(48);
+DECLARE_MSM_GPIO_PINS(49);
+DECLARE_MSM_GPIO_PINS(50);
+DECLARE_MSM_GPIO_PINS(51);
+DECLARE_MSM_GPIO_PINS(52);
+DECLARE_MSM_GPIO_PINS(53);
+DECLARE_MSM_GPIO_PINS(54);
+DECLARE_MSM_GPIO_PINS(55);
+DECLARE_MSM_GPIO_PINS(56);
+DECLARE_MSM_GPIO_PINS(57);
+DECLARE_MSM_GPIO_PINS(58);
+DECLARE_MSM_GPIO_PINS(59);
+DECLARE_MSM_GPIO_PINS(60);
+DECLARE_MSM_GPIO_PINS(61);
+DECLARE_MSM_GPIO_PINS(62);
+DECLARE_MSM_GPIO_PINS(63);
+DECLARE_MSM_GPIO_PINS(64);
+DECLARE_MSM_GPIO_PINS(65);
+DECLARE_MSM_GPIO_PINS(66);
+DECLARE_MSM_GPIO_PINS(67);
+DECLARE_MSM_GPIO_PINS(68);
+DECLARE_MSM_GPIO_PINS(69);
+DECLARE_MSM_GPIO_PINS(70);
+DECLARE_MSM_GPIO_PINS(71);
+DECLARE_MSM_GPIO_PINS(72);
+DECLARE_MSM_GPIO_PINS(73);
+DECLARE_MSM_GPIO_PINS(74);
+DECLARE_MSM_GPIO_PINS(75);
+DECLARE_MSM_GPIO_PINS(76);
+DECLARE_MSM_GPIO_PINS(77);
+DECLARE_MSM_GPIO_PINS(78);
+DECLARE_MSM_GPIO_PINS(79);
+DECLARE_MSM_GPIO_PINS(80);
+DECLARE_MSM_GPIO_PINS(81);
+DECLARE_MSM_GPIO_PINS(82);
+DECLARE_MSM_GPIO_PINS(83);
+DECLARE_MSM_GPIO_PINS(84);
+DECLARE_MSM_GPIO_PINS(85);
+DECLARE_MSM_GPIO_PINS(86);
+DECLARE_MSM_GPIO_PINS(87);
+DECLARE_MSM_GPIO_PINS(88);
+DECLARE_MSM_GPIO_PINS(89);
+DECLARE_MSM_GPIO_PINS(90);
+DECLARE_MSM_GPIO_PINS(91);
+DECLARE_MSM_GPIO_PINS(92);
+DECLARE_MSM_GPIO_PINS(93);
+DECLARE_MSM_GPIO_PINS(94);
+DECLARE_MSM_GPIO_PINS(95);
+DECLARE_MSM_GPIO_PINS(96);
+DECLARE_MSM_GPIO_PINS(97);
+DECLARE_MSM_GPIO_PINS(98);
+DECLARE_MSM_GPIO_PINS(99);
+DECLARE_MSM_GPIO_PINS(100);
+DECLARE_MSM_GPIO_PINS(101);
+DECLARE_MSM_GPIO_PINS(102);
+DECLARE_MSM_GPIO_PINS(103);
+DECLARE_MSM_GPIO_PINS(104);
+DECLARE_MSM_GPIO_PINS(105);
+DECLARE_MSM_GPIO_PINS(106);
+DECLARE_MSM_GPIO_PINS(107);
+DECLARE_MSM_GPIO_PINS(108);
+DECLARE_MSM_GPIO_PINS(109);
+DECLARE_MSM_GPIO_PINS(110);
+DECLARE_MSM_GPIO_PINS(111);
+DECLARE_MSM_GPIO_PINS(112);
+DECLARE_MSM_GPIO_PINS(113);
+DECLARE_MSM_GPIO_PINS(114);
+DECLARE_MSM_GPIO_PINS(115);
+DECLARE_MSM_GPIO_PINS(116);
+DECLARE_MSM_GPIO_PINS(117);
+DECLARE_MSM_GPIO_PINS(118);
+DECLARE_MSM_GPIO_PINS(119);
+DECLARE_MSM_GPIO_PINS(120);
+DECLARE_MSM_GPIO_PINS(121);
+DECLARE_MSM_GPIO_PINS(122);
+DECLARE_MSM_GPIO_PINS(123);
+DECLARE_MSM_GPIO_PINS(124);
+DECLARE_MSM_GPIO_PINS(125);
+DECLARE_MSM_GPIO_PINS(126);
+DECLARE_MSM_GPIO_PINS(127);
+DECLARE_MSM_GPIO_PINS(128);
+DECLARE_MSM_GPIO_PINS(129);
+DECLARE_MSM_GPIO_PINS(130);
+DECLARE_MSM_GPIO_PINS(131);
+DECLARE_MSM_GPIO_PINS(132);
+DECLARE_MSM_GPIO_PINS(133);
+DECLARE_MSM_GPIO_PINS(134);
+DECLARE_MSM_GPIO_PINS(135);
+DECLARE_MSM_GPIO_PINS(136);
+DECLARE_MSM_GPIO_PINS(137);
+DECLARE_MSM_GPIO_PINS(138);
+DECLARE_MSM_GPIO_PINS(139);
+DECLARE_MSM_GPIO_PINS(140);
+DECLARE_MSM_GPIO_PINS(141);
+DECLARE_MSM_GPIO_PINS(142);
+DECLARE_MSM_GPIO_PINS(143);
+DECLARE_MSM_GPIO_PINS(144);
+DECLARE_MSM_GPIO_PINS(145);
+DECLARE_MSM_GPIO_PINS(146);
+DECLARE_MSM_GPIO_PINS(147);
+DECLARE_MSM_GPIO_PINS(148);
+DECLARE_MSM_GPIO_PINS(149);
+DECLARE_MSM_GPIO_PINS(150);
+DECLARE_MSM_GPIO_PINS(151);
+DECLARE_MSM_GPIO_PINS(152);
+DECLARE_MSM_GPIO_PINS(153);
+DECLARE_MSM_GPIO_PINS(154);
+DECLARE_MSM_GPIO_PINS(155);
+DECLARE_MSM_GPIO_PINS(156);
+DECLARE_MSM_GPIO_PINS(157);
+DECLARE_MSM_GPIO_PINS(158);
+DECLARE_MSM_GPIO_PINS(159);
+DECLARE_MSM_GPIO_PINS(160);
+DECLARE_MSM_GPIO_PINS(161);
+DECLARE_MSM_GPIO_PINS(162);
+DECLARE_MSM_GPIO_PINS(163);
+DECLARE_MSM_GPIO_PINS(164);
+DECLARE_MSM_GPIO_PINS(165);
+DECLARE_MSM_GPIO_PINS(166);
+DECLARE_MSM_GPIO_PINS(167);
+DECLARE_MSM_GPIO_PINS(168);
+DECLARE_MSM_GPIO_PINS(169);
+DECLARE_MSM_GPIO_PINS(170);
+DECLARE_MSM_GPIO_PINS(171);
+DECLARE_MSM_GPIO_PINS(172);
+DECLARE_MSM_GPIO_PINS(173);
+DECLARE_MSM_GPIO_PINS(174);
+DECLARE_MSM_GPIO_PINS(175);
+DECLARE_MSM_GPIO_PINS(176);
+DECLARE_MSM_GPIO_PINS(177);
+DECLARE_MSM_GPIO_PINS(178);
+DECLARE_MSM_GPIO_PINS(179);
+DECLARE_MSM_GPIO_PINS(180);
+DECLARE_MSM_GPIO_PINS(181);
+DECLARE_MSM_GPIO_PINS(182);
+DECLARE_MSM_GPIO_PINS(183);
+DECLARE_MSM_GPIO_PINS(184);
+DECLARE_MSM_GPIO_PINS(185);
+DECLARE_MSM_GPIO_PINS(186);
+DECLARE_MSM_GPIO_PINS(187);
+DECLARE_MSM_GPIO_PINS(188);
+DECLARE_MSM_GPIO_PINS(189);
+DECLARE_MSM_GPIO_PINS(190);
+DECLARE_MSM_GPIO_PINS(191);
+DECLARE_MSM_GPIO_PINS(192);
+DECLARE_MSM_GPIO_PINS(193);
+DECLARE_MSM_GPIO_PINS(194);
+DECLARE_MSM_GPIO_PINS(195);
+DECLARE_MSM_GPIO_PINS(196);
+DECLARE_MSM_GPIO_PINS(197);
+DECLARE_MSM_GPIO_PINS(198);
+DECLARE_MSM_GPIO_PINS(199);
+DECLARE_MSM_GPIO_PINS(200);
+DECLARE_MSM_GPIO_PINS(201);
+DECLARE_MSM_GPIO_PINS(202);
+DECLARE_MSM_GPIO_PINS(203);
+DECLARE_MSM_GPIO_PINS(204);
+DECLARE_MSM_GPIO_PINS(205);
+DECLARE_MSM_GPIO_PINS(206);
+DECLARE_MSM_GPIO_PINS(207);
+DECLARE_MSM_GPIO_PINS(208);
+DECLARE_MSM_GPIO_PINS(209);
+
+static const unsigned int ufs_reset_pins[] = { 210 };
+static const unsigned int sdc2_clk_pins[] = { 211 };
+static const unsigned int sdc2_cmd_pins[] = { 212 };
+static const unsigned int sdc2_data_pins[] = { 213 };
+
+enum sm8550_functions {
+ msm_mux_gpio,
+ msm_mux_aon_cci,
+ msm_mux_aoss_cti,
+ msm_mux_atest_char,
+ msm_mux_atest_usb,
+ msm_mux_audio_ext_mclk0,
+ msm_mux_audio_ext_mclk1,
+ msm_mux_audio_ref_clk,
+ msm_mux_cam_aon_mclk4,
+ msm_mux_cam_mclk,
+ msm_mux_cci_async_in,
+ msm_mux_cci_i2c_scl,
+ msm_mux_cci_i2c_sda,
+ msm_mux_cci_timer,
+ msm_mux_cmu_rng,
+ msm_mux_coex_uart1_rx,
+ msm_mux_coex_uart1_tx,
+ msm_mux_coex_uart2_rx,
+ msm_mux_coex_uart2_tx,
+ msm_mux_cri_trng,
+ msm_mux_dbg_out_clk,
+ msm_mux_ddr_bist_complete,
+ msm_mux_ddr_bist_fail,
+ msm_mux_ddr_bist_start,
+ msm_mux_ddr_bist_stop,
+ msm_mux_ddr_pxi0,
+ msm_mux_ddr_pxi1,
+ msm_mux_ddr_pxi2,
+ msm_mux_ddr_pxi3,
+ msm_mux_dp_hot,
+ msm_mux_gcc_gp1,
+ msm_mux_gcc_gp2,
+ msm_mux_gcc_gp3,
+ msm_mux_i2chub0_se0,
+ msm_mux_i2chub0_se1,
+ msm_mux_i2chub0_se2,
+ msm_mux_i2chub0_se3,
+ msm_mux_i2chub0_se4,
+ msm_mux_i2chub0_se5,
+ msm_mux_i2chub0_se6,
+ msm_mux_i2chub0_se7,
+ msm_mux_i2chub0_se8,
+ msm_mux_i2chub0_se9,
+ msm_mux_i2s0_data0,
+ msm_mux_i2s0_data1,
+ msm_mux_i2s0_sck,
+ msm_mux_i2s0_ws,
+ msm_mux_i2s1_data0,
+ msm_mux_i2s1_data1,
+ msm_mux_i2s1_sck,
+ msm_mux_i2s1_ws,
+ msm_mux_ibi_i3c,
+ msm_mux_jitter_bist,
+ msm_mux_mdp_vsync,
+ msm_mux_mdp_vsync0_out,
+ msm_mux_mdp_vsync1_out,
+ msm_mux_mdp_vsync2_out,
+ msm_mux_mdp_vsync3_out,
+ msm_mux_mdp_vsync_e,
+ msm_mux_nav_gpio0,
+ msm_mux_nav_gpio1,
+ msm_mux_nav_gpio2,
+ msm_mux_pcie0_clk_req_n,
+ msm_mux_pcie1_clk_req_n,
+ msm_mux_phase_flag,
+ msm_mux_pll_bist_sync,
+ msm_mux_pll_clk_aux,
+ msm_mux_prng_rosc0,
+ msm_mux_prng_rosc1,
+ msm_mux_prng_rosc2,
+ msm_mux_prng_rosc3,
+ msm_mux_qdss_cti,
+ msm_mux_qdss_gpio,
+ msm_mux_qlink0_enable,
+ msm_mux_qlink0_request,
+ msm_mux_qlink0_wmss,
+ msm_mux_qlink1_enable,
+ msm_mux_qlink1_request,
+ msm_mux_qlink1_wmss,
+ msm_mux_qlink2_enable,
+ msm_mux_qlink2_request,
+ msm_mux_qlink2_wmss,
+ msm_mux_qspi0,
+ msm_mux_qspi1,
+ msm_mux_qspi2,
+ msm_mux_qspi3,
+ msm_mux_qspi_clk,
+ msm_mux_qspi_cs,
+ msm_mux_qup1_se0,
+ msm_mux_qup1_se1,
+ msm_mux_qup1_se2,
+ msm_mux_qup1_se3,
+ msm_mux_qup1_se4,
+ msm_mux_qup1_se5,
+ msm_mux_qup1_se6,
+ msm_mux_qup1_se7,
+ msm_mux_qup2_se0,
+ msm_mux_qup2_se0_l0_mira,
+ msm_mux_qup2_se0_l0_mirb,
+ msm_mux_qup2_se0_l1_mira,
+ msm_mux_qup2_se0_l1_mirb,
+ msm_mux_qup2_se0_l2_mira,
+ msm_mux_qup2_se0_l2_mirb,
+ msm_mux_qup2_se0_l3_mira,
+ msm_mux_qup2_se0_l3_mirb,
+ msm_mux_qup2_se1,
+ msm_mux_qup2_se2,
+ msm_mux_qup2_se3,
+ msm_mux_qup2_se4,
+ msm_mux_qup2_se5,
+ msm_mux_qup2_se6,
+ msm_mux_qup2_se7,
+ msm_mux_resout_n,
+ msm_mux_sd_write_protect,
+ msm_mux_sdc40,
+ msm_mux_sdc41,
+ msm_mux_sdc42,
+ msm_mux_sdc43,
+ msm_mux_sdc4_clk,
+ msm_mux_sdc4_cmd,
+ msm_mux_tb_trig_sdc2,
+ msm_mux_tb_trig_sdc4,
+ msm_mux_tgu_ch0_trigout,
+ msm_mux_tgu_ch1_trigout,
+ msm_mux_tgu_ch2_trigout,
+ msm_mux_tgu_ch3_trigout,
+ msm_mux_tmess_prng0,
+ msm_mux_tmess_prng1,
+ msm_mux_tmess_prng2,
+ msm_mux_tmess_prng3,
+ msm_mux_tsense_pwm1,
+ msm_mux_tsense_pwm2,
+ msm_mux_tsense_pwm3,
+ msm_mux_uim0_clk,
+ msm_mux_uim0_data,
+ msm_mux_uim0_present,
+ msm_mux_uim0_reset,
+ msm_mux_uim1_clk,
+ msm_mux_uim1_data,
+ msm_mux_uim1_present,
+ msm_mux_uim1_reset,
+ msm_mux_usb1_hs,
+ msm_mux_usb_phy,
+ msm_mux_vfr_0,
+ msm_mux_vfr_1,
+ msm_mux_vsense_trigger_mirnat,
+ msm_mux__,
+};
+
+static const char * const gpio_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7",
+ "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14",
+ "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21",
+ "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28",
+ "gpio29", "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35",
+ "gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42",
+ "gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", "gpio49",
+ "gpio50", "gpio51", "gpio52", "gpio53", "gpio54", "gpio55", "gpio56",
+ "gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63",
+ "gpio64", "gpio65", "gpio66", "gpio67", "gpio68", "gpio69", "gpio70",
+ "gpio71", "gpio72", "gpio73", "gpio74", "gpio75", "gpio76", "gpio77",
+ "gpio78", "gpio79", "gpio80", "gpio81", "gpio82", "gpio83", "gpio84",
+ "gpio85", "gpio86", "gpio87", "gpio88", "gpio89", "gpio90", "gpio91",
+ "gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio97", "gpio98",
+ "gpio99", "gpio100", "gpio101", "gpio102", "gpio103", "gpio104",
+ "gpio105", "gpio106", "gpio107", "gpio108", "gpio109", "gpio110",
+ "gpio111", "gpio112", "gpio113", "gpio114", "gpio115", "gpio116",
+ "gpio117", "gpio118", "gpio119", "gpio120", "gpio121", "gpio122",
+ "gpio123", "gpio124", "gpio125", "gpio126", "gpio127", "gpio128",
+ "gpio129", "gpio130", "gpio131", "gpio132", "gpio133", "gpio134",
+ "gpio135", "gpio136", "gpio137", "gpio138", "gpio139", "gpio140",
+ "gpio141", "gpio142", "gpio143", "gpio144", "gpio145", "gpio146",
+ "gpio147", "gpio148", "gpio149", "gpio150", "gpio151", "gpio152",
+ "gpio153", "gpio154", "gpio155", "gpio156", "gpio157", "gpio158",
+ "gpio159", "gpio160", "gpio161", "gpio162", "gpio163", "gpio164",
+ "gpio165", "gpio166", "gpio167", "gpio168", "gpio169", "gpio170",
+ "gpio171", "gpio172", "gpio173", "gpio174", "gpio175", "gpio176",
+ "gpio177", "gpio178", "gpio179", "gpio180", "gpio181", "gpio182",
+ "gpio183", "gpio184", "gpio185", "gpio186", "gpio187", "gpio188",
+ "gpio189", "gpio190", "gpio191", "gpio192", "gpio193", "gpio194",
+ "gpio195", "gpio196", "gpio197", "gpio198", "gpio199", "gpio200",
+ "gpio201", "gpio202", "gpio203", "gpio204", "gpio205", "gpio206",
+ "gpio207", "gpio208", "gpio209",
+};
+
+static const char * const aon_cci_groups[] = {
+ "gpio208", "gpio209",
+};
+
+static const char * const aoss_cti_groups[] = {
+ "gpio44", "gpio45", "gpio46", "gpio47",
+};
+
+static const char *const atest_char_groups[] = {
+ "gpio130", "gpio132", "gpio133", "gpio134", "gpio135",
+};
+
+static const char *const atest_usb_groups[] = {
+ "gpio37", "gpio39", "gpio55", "gpio149", "gpio148",
+};
+
+static const char *const audio_ext_mclk0_groups[] = {
+ "gpio125",
+};
+
+static const char *const audio_ext_mclk1_groups[] = {
+ "gpio124",
+};
+
+static const char *const audio_ref_clk_groups[] = {
+ "gpio124",
+};
+
+static const char *const cam_aon_mclk4_groups[] = {
+ "gpio104",
+};
+
+static const char *const cam_mclk_groups[] = {
+ "gpio100", "gpio101", "gpio102", "gpio103",
+ "gpio105", "gpio106", "gpio107",
+};
+
+static const char *const cci_async_in_groups[] = {
+ "gpio71", "gpio72", "gpio109",
+};
+
+static const char *const cci_i2c_scl_groups[] = {
+ "gpio111", "gpio113", "gpio115", "gpio75", "gpio1",
+};
+
+static const char *const cci_i2c_sda_groups[] = {
+ "gpio110", "gpio112", "gpio114", "gpio74", "gpio0",
+};
+
+static const char *const cci_timer_groups[] = {
+ "gpio116", "gpio117", "gpio118", "gpio119", "gpio120",
+};
+
+static const char *const cmu_rng_groups[] = {
+ "gpio129", "gpio128", "gpio127", "gpio122",
+};
+
+static const char *const coex_uart1_rx_groups[] = {
+ "gpio148",
+};
+
+static const char *const coex_uart1_tx_groups[] = {
+ "gpio149",
+};
+
+static const char *const coex_uart2_rx_groups[] = {
+ "gpio150",
+};
+
+static const char *const coex_uart2_tx_groups[] = {
+ "gpio151",
+};
+
+static const char *const cri_trng_groups[] = {
+ "gpio187",
+};
+
+static const char *const dbg_out_clk_groups[] = {
+ "gpio89",
+};
+
+static const char *const ddr_bist_complete_groups[] = {
+ "gpio40",
+};
+
+static const char *const ddr_bist_fail_groups[] = {
+ "gpio36",
+};
+
+static const char *const ddr_bist_start_groups[] = {
+ "gpio37",
+};
+
+static const char *const ddr_bist_stop_groups[] = {
+ "gpio41",
+};
+
+static const char *const ddr_pxi0_groups[] = {
+ "gpio51",
+ "gpio52",
+};
+
+static const char *const ddr_pxi1_groups[] = {
+ "gpio40",
+ "gpio41",
+};
+
+static const char *const ddr_pxi2_groups[] = {
+ "gpio45",
+ "gpio47",
+};
+
+static const char *const ddr_pxi3_groups[] = {
+ "gpio43",
+ "gpio44",
+};
+
+static const char *const dp_hot_groups[] = {
+ "gpio47",
+};
+
+static const char *const gcc_gp1_groups[] = {
+ "gpio86",
+ "gpio134",
+};
+
+static const char *const gcc_gp2_groups[] = {
+ "gpio87",
+ "gpio135",
+};
+
+static const char *const gcc_gp3_groups[] = {
+ "gpio88",
+ "gpio136",
+};
+
+static const char *const i2chub0_se0_groups[] = {
+ "gpio16",
+ "gpio17",
+};
+
+static const char *const i2chub0_se1_groups[] = {
+ "gpio18",
+ "gpio19",
+};
+
+static const char *const i2chub0_se2_groups[] = {
+ "gpio20",
+ "gpio21",
+};
+
+static const char *const i2chub0_se3_groups[] = {
+ "gpio22",
+ "gpio23",
+};
+
+static const char *const i2chub0_se4_groups[] = {
+ "gpio4",
+ "gpio5",
+};
+
+static const char *const i2chub0_se5_groups[] = {
+ "gpio6",
+ "gpio7",
+};
+
+static const char *const i2chub0_se6_groups[] = {
+ "gpio8",
+ "gpio9",
+};
+
+static const char *const i2chub0_se7_groups[] = {
+ "gpio10",
+ "gpio11",
+};
+
+static const char *const i2chub0_se8_groups[] = {
+ "gpio206",
+ "gpio207",
+};
+
+static const char *const i2chub0_se9_groups[] = {
+ "gpio84",
+ "gpio85",
+};
+
+static const char *const i2s0_data0_groups[] = {
+ "gpio127",
+};
+
+static const char *const i2s0_data1_groups[] = {
+ "gpio128",
+};
+
+static const char *const i2s0_sck_groups[] = {
+ "gpio126",
+};
+
+static const char *const i2s0_ws_groups[] = {
+ "gpio129",
+};
+
+static const char *const i2s1_data0_groups[] = {
+ "gpio122",
+};
+
+static const char *const i2s1_data1_groups[] = {
+ "gpio124",
+};
+
+static const char *const i2s1_sck_groups[] = {
+ "gpio121",
+};
+
+static const char *const i2s1_ws_groups[] = {
+ "gpio123",
+};
+
+static const char *const ibi_i3c_groups[] = {
+ "gpio0", "gpio1", "gpio28", "gpio29", "gpio32",
+ "gpio33", "gpio56", "gpio57", "gpio60", "gpio61",
+};
+
+static const char *const jitter_bist_groups[] = {
+ "gpio43",
+};
+
+static const char *const mdp_vsync_groups[] = {
+ "gpio86",
+ "gpio87",
+ "gpio133",
+ "gpio137",
+};
+
+static const char *const mdp_vsync0_out_groups[] = {
+ "gpio86",
+};
+
+static const char *const mdp_vsync1_out_groups[] = {
+ "gpio86",
+};
+
+static const char *const mdp_vsync2_out_groups[] = {
+ "gpio87",
+};
+
+static const char *const mdp_vsync3_out_groups[] = {
+ "gpio87",
+};
+
+static const char *const mdp_vsync_e_groups[] = {
+ "gpio88",
+};
+
+static const char *const nav_gpio0_groups[] = {
+ "gpio154",
+};
+
+static const char *const nav_gpio1_groups[] = {
+ "gpio155",
+};
+
+static const char *const nav_gpio2_groups[] = {
+ "gpio153",
+};
+
+static const char *const pcie0_clk_req_n_groups[] = {
+ "gpio95",
+};
+
+static const char *const pcie1_clk_req_n_groups[] = {
+ "gpio98",
+};
+
+static const char *const phase_flag_groups[] = {
+ "gpio0", "gpio2", "gpio3", "gpio10", "gpio11", "gpio12", "gpio13", "gpio59",
+ "gpio63", "gpio64", "gpio65", "gpio67", "gpio68", "gpio69", "gpio75", "gpio76",
+ "gpio77", "gpio79", "gpio80", "gpio81", "gpio92", "gpio83", "gpio94", "gpio95",
+ "gpio96", "gpio97", "gpio98", "gpio99", "gpio116", "gpio117", "gpio119", "gpio120",
+};
+
+static const char *const pll_bist_sync_groups[] = {
+ "gpio20",
+};
+
+static const char *const pll_clk_aux_groups[] = {
+ "gpio107",
+};
+
+static const char *const prng_rosc0_groups[] = {
+ "gpio186",
+};
+
+static const char *const prng_rosc1_groups[] = {
+ "gpio183",
+};
+
+static const char *const prng_rosc2_groups[] = {
+ "gpio182",
+};
+
+static const char *const prng_rosc3_groups[] = {
+ "gpio181",
+};
+
+static const char *const qdss_cti_groups[] = {
+ "gpio10", "gpio11", "gpio75", "gpio79",
+ "gpio159", "gpio160", "gpio161", "gpio162",
+};
+
+static const char *const qdss_gpio_groups[] = {
+ "gpio59", "gpio64", "gpio73", "gpio100", "gpio101", "gpio102", "gpio103",
+ "gpio104", "gpio105", "gpio110", "gpio111", "gpio112", "gpio113", "gpio114",
+ "gpio115", "gpio116", "gpio117", "gpio120", "gpio138", "gpio139", "gpio140",
+ "gpio141", "gpio142", "gpio143", "gpio144", "gpio145", "gpio148", "gpio149",
+ "gpio150", "gpio151", "gpio152", "gpio153", "gpio154", "gpio155", "gpio156",
+ "gpio157",
+};
+
+static const char *const qlink0_enable_groups[] = {
+ "gpio157",
+};
+
+static const char *const qlink0_request_groups[] = {
+ "gpio156",
+};
+
+static const char *const qlink0_wmss_groups[] = {
+ "gpio158",
+};
+
+static const char *const qlink1_enable_groups[] = {
+ "gpio160",
+};
+
+static const char *const qlink1_request_groups[] = {
+ "gpio159",
+};
+
+static const char *const qlink1_wmss_groups[] = {
+ "gpio161",
+};
+
+static const char *const qlink2_enable_groups[] = {
+ "gpio163",
+};
+
+static const char *const qlink2_request_groups[] = {
+ "gpio162",
+};
+
+static const char *const qlink2_wmss_groups[] = {
+ "gpio164",
+};
+
+static const char *const qspi0_groups[] = {
+ "gpio89",
+};
+
+static const char *const qspi1_groups[] = {
+ "gpio90",
+};
+
+static const char *const qspi2_groups[] = {
+ "gpio48",
+};
+
+static const char *const qspi3_groups[] = {
+ "gpio49",
+};
+
+static const char *const qspi_clk_groups[] = {
+ "gpio50",
+};
+
+static const char *const qspi_cs_groups[] = {
+ "gpio51", "gpio91",
+};
+
+static const char *const qup1_se0_groups[] = {
+ "gpio28", "gpio29", "gpio30", "gpio31",
+};
+
+static const char *const qup1_se1_groups[] = {
+ "gpio32", "gpio33", "gpio34", "gpio35",
+};
+
+static const char *const qup1_se2_groups[] = {
+ "gpio40", "gpio41", "gpio42", "gpio36",
+ "gpio37", "gpio38", "gpio39",
+};
+
+static const char *const qup1_se3_groups[] = {
+ "gpio40", "gpio41", "gpio42", "gpio43",
+};
+
+static const char *const qup1_se4_groups[] = {
+ "gpio44", "gpio45", "gpio46", "gpio47",
+};
+
+static const char *const qup1_se5_groups[] = {
+ "gpio52", "gpio53", "gpio54", "gpio55",
+};
+
+static const char *const qup1_se6_groups[] = {
+ "gpio48", "gpio49", "gpio50", "gpio51",
+};
+
+static const char *const qup1_se7_groups[] = {
+ "gpio24", "gpio25", "gpio26", "gpio27",
+};
+
+static const char *const qup2_se0_groups[] = {
+ "gpio63", "gpio66", "gpio67",
+};
+
+static const char *const qup2_se0_l0_mira_groups[] = {
+ "gpio56",
+};
+
+static const char *const qup2_se0_l0_mirb_groups[] = {
+ "gpio0",
+};
+
+static const char *const qup2_se0_l1_mira_groups[] = {
+ "gpio57",
+};
+
+static const char *const qup2_se0_l1_mirb_groups[] = {
+ "gpio1",
+};
+
+static const char *const qup2_se0_l2_mira_groups[] = {
+ "gpio58",
+};
+
+static const char *const qup2_se0_l2_mirb_groups[] = {
+ "gpio109",
+};
+
+static const char *const qup2_se0_l3_mira_groups[] = {
+ "gpio59",
+};
+
+static const char *const qup2_se0_l3_mirb_groups[] = {
+ "gpio107",
+};
+
+static const char *const qup2_se1_groups[] = {
+ "gpio60", "gpio61", "gpio62", "gpio63",
+};
+
+static const char *const qup2_se2_groups[] = {
+ "gpio64", "gpio65", "gpio66", "gpio67",
+};
+
+static const char *const qup2_se3_groups[] = {
+ "gpio68", "gpio69", "gpio70", "gpio71",
+};
+
+static const char *const qup2_se4_groups[] = {
+ "gpio2", "gpio3", "gpio118", "gpio119",
+};
+
+static const char *const qup2_se5_groups[] = {
+ "gpio80", "gpio81", "gpio82", "gpio83",
+};
+
+static const char *const qup2_se6_groups[] = {
+ "gpio76", "gpio77", "gpio78", "gpio79",
+};
+
+static const char *const qup2_se7_groups[] = {
+ "gpio72", "gpio106", "gpio74", "gpio75",
+};
+
+static const char * const resout_n_groups[] = {
+ "gpio92",
+};
+
+static const char *const sd_write_protect_groups[] = {
+ "gpio93",
+};
+
+static const char *const sdc40_groups[] = {
+ "gpio89",
+};
+
+static const char *const sdc41_groups[] = {
+ "gpio90",
+};
+
+static const char *const sdc42_groups[] = {
+ "gpio48",
+};
+
+static const char *const sdc43_groups[] = {
+ "gpio49",
+};
+
+static const char *const sdc4_clk_groups[] = {
+ "gpio50",
+};
+
+static const char *const sdc4_cmd_groups[] = {
+ "gpio51",
+};
+
+static const char * const tb_trig_sdc2_groups[] = {
+ "gpio64",
+};
+
+static const char * const tb_trig_sdc4_groups[] = {
+ "gpio91",
+};
+
+static const char * const tgu_ch0_trigout_groups[] = {
+ "gpio64",
+};
+
+static const char * const tgu_ch1_trigout_groups[] = {
+ "gpio65",
+};
+
+static const char * const tgu_ch2_trigout_groups[] = {
+ "gpio66",
+};
+
+static const char * const tgu_ch3_trigout_groups[] = {
+ "gpio67",
+};
+
+static const char *const tmess_prng0_groups[] = {
+ "gpio92",
+};
+
+static const char *const tmess_prng1_groups[] = {
+ "gpio94",
+};
+
+static const char *const tmess_prng2_groups[] = {
+ "gpio95",
+};
+
+static const char *const tmess_prng3_groups[] = {
+ "gpio96",
+};
+
+static const char *const tsense_pwm1_groups[] = {
+ "gpio50",
+};
+
+static const char *const tsense_pwm2_groups[] = {
+ "gpio50",
+};
+
+static const char *const tsense_pwm3_groups[] = {
+ "gpio50",
+};
+
+static const char *const uim0_clk_groups[] = {
+ "gpio131",
+};
+
+static const char *const uim0_data_groups[] = {
+ "gpio130",
+};
+
+static const char *const uim0_present_groups[] = {
+ "gpio27",
+};
+
+static const char *const uim0_reset_groups[] = {
+ "gpio132",
+};
+
+static const char *const uim1_clk_groups[] = {
+ "gpio135",
+};
+
+static const char *const uim1_data_groups[] = {
+ "gpio134",
+};
+
+static const char *const uim1_present_groups[] = {
+ "gpio26",
+};
+
+static const char *const uim1_reset_groups[] = {
+ "gpio136",
+};
+
+static const char *const usb1_hs_groups[] = {
+ "gpio90",
+};
+
+static const char *const usb_phy_groups[] = {
+ "gpio11",
+ "gpio48",
+};
+
+static const char *const vfr_0_groups[] = {
+ "gpio150",
+};
+
+static const char *const vfr_1_groups[] = {
+ "gpio155",
+};
+
+static const char *const vsense_trigger_mirnat_groups[] = {
+ "gpio24",
+};
+
+static const struct msm_function sm8550_functions[] = {
+ FUNCTION(gpio),
+ FUNCTION(aon_cci),
+ FUNCTION(aoss_cti),
+ FUNCTION(atest_char),
+ FUNCTION(atest_usb),
+ FUNCTION(audio_ext_mclk0),
+ FUNCTION(audio_ext_mclk1),
+ FUNCTION(audio_ref_clk),
+ FUNCTION(cam_aon_mclk4),
+ FUNCTION(cam_mclk),
+ FUNCTION(cci_async_in),
+ FUNCTION(cci_i2c_scl),
+ FUNCTION(cci_i2c_sda),
+ FUNCTION(cci_timer),
+ FUNCTION(cmu_rng),
+ FUNCTION(coex_uart1_rx),
+ FUNCTION(coex_uart1_tx),
+ FUNCTION(coex_uart2_rx),
+ FUNCTION(coex_uart2_tx),
+ FUNCTION(cri_trng),
+ FUNCTION(dbg_out_clk),
+ FUNCTION(ddr_bist_complete),
+ FUNCTION(ddr_bist_fail),
+ FUNCTION(ddr_bist_start),
+ FUNCTION(ddr_bist_stop),
+ FUNCTION(ddr_pxi0),
+ FUNCTION(ddr_pxi1),
+ FUNCTION(ddr_pxi2),
+ FUNCTION(ddr_pxi3),
+ FUNCTION(dp_hot),
+ FUNCTION(gcc_gp1),
+ FUNCTION(gcc_gp2),
+ FUNCTION(gcc_gp3),
+ FUNCTION(i2chub0_se0),
+ FUNCTION(i2chub0_se1),
+ FUNCTION(i2chub0_se2),
+ FUNCTION(i2chub0_se3),
+ FUNCTION(i2chub0_se4),
+ FUNCTION(i2chub0_se5),
+ FUNCTION(i2chub0_se6),
+ FUNCTION(i2chub0_se7),
+ FUNCTION(i2chub0_se8),
+ FUNCTION(i2chub0_se9),
+ FUNCTION(i2s0_data0),
+ FUNCTION(i2s0_data1),
+ FUNCTION(i2s0_sck),
+ FUNCTION(i2s0_ws),
+ FUNCTION(i2s1_data0),
+ FUNCTION(i2s1_data1),
+ FUNCTION(i2s1_sck),
+ FUNCTION(i2s1_ws),
+ FUNCTION(ibi_i3c),
+ FUNCTION(jitter_bist),
+ FUNCTION(mdp_vsync),
+ FUNCTION(mdp_vsync0_out),
+ FUNCTION(mdp_vsync1_out),
+ FUNCTION(mdp_vsync2_out),
+ FUNCTION(mdp_vsync3_out),
+ FUNCTION(mdp_vsync_e),
+ FUNCTION(nav_gpio0),
+ FUNCTION(nav_gpio1),
+ FUNCTION(nav_gpio2),
+ FUNCTION(pcie0_clk_req_n),
+ FUNCTION(pcie1_clk_req_n),
+ FUNCTION(phase_flag),
+ FUNCTION(pll_bist_sync),
+ FUNCTION(pll_clk_aux),
+ FUNCTION(prng_rosc0),
+ FUNCTION(prng_rosc1),
+ FUNCTION(prng_rosc2),
+ FUNCTION(prng_rosc3),
+ FUNCTION(qdss_cti),
+ FUNCTION(qdss_gpio),
+ FUNCTION(qlink0_enable),
+ FUNCTION(qlink0_request),
+ FUNCTION(qlink0_wmss),
+ FUNCTION(qlink1_enable),
+ FUNCTION(qlink1_request),
+ FUNCTION(qlink1_wmss),
+ FUNCTION(qlink2_enable),
+ FUNCTION(qlink2_request),
+ FUNCTION(qlink2_wmss),
+ FUNCTION(qspi0),
+ FUNCTION(qspi1),
+ FUNCTION(qspi2),
+ FUNCTION(qspi3),
+ FUNCTION(qspi_clk),
+ FUNCTION(qspi_cs),
+ FUNCTION(qup1_se0),
+ FUNCTION(qup1_se1),
+ FUNCTION(qup1_se2),
+ FUNCTION(qup1_se3),
+ FUNCTION(qup1_se4),
+ FUNCTION(qup1_se5),
+ FUNCTION(qup1_se6),
+ FUNCTION(qup1_se7),
+ FUNCTION(qup2_se0),
+ FUNCTION(qup2_se0_l0_mira),
+ FUNCTION(qup2_se0_l0_mirb),
+ FUNCTION(qup2_se0_l1_mira),
+ FUNCTION(qup2_se0_l1_mirb),
+ FUNCTION(qup2_se0_l2_mira),
+ FUNCTION(qup2_se0_l2_mirb),
+ FUNCTION(qup2_se0_l3_mira),
+ FUNCTION(qup2_se0_l3_mirb),
+ FUNCTION(qup2_se1),
+ FUNCTION(qup2_se2),
+ FUNCTION(qup2_se3),
+ FUNCTION(qup2_se4),
+ FUNCTION(qup2_se5),
+ FUNCTION(qup2_se6),
+ FUNCTION(qup2_se7),
+ FUNCTION(resout_n),
+ FUNCTION(sd_write_protect),
+ FUNCTION(sdc40),
+ FUNCTION(sdc41),
+ FUNCTION(sdc42),
+ FUNCTION(sdc43),
+ FUNCTION(sdc4_clk),
+ FUNCTION(sdc4_cmd),
+ FUNCTION(tb_trig_sdc2),
+ FUNCTION(tb_trig_sdc4),
+ FUNCTION(tgu_ch0_trigout),
+ FUNCTION(tgu_ch1_trigout),
+ FUNCTION(tgu_ch2_trigout),
+ FUNCTION(tgu_ch3_trigout),
+ FUNCTION(tmess_prng0),
+ FUNCTION(tmess_prng1),
+ FUNCTION(tmess_prng2),
+ FUNCTION(tmess_prng3),
+ FUNCTION(tsense_pwm1),
+ FUNCTION(tsense_pwm2),
+ FUNCTION(tsense_pwm3),
+ FUNCTION(uim0_clk),
+ FUNCTION(uim0_data),
+ FUNCTION(uim0_present),
+ FUNCTION(uim0_reset),
+ FUNCTION(uim1_clk),
+ FUNCTION(uim1_data),
+ FUNCTION(uim1_present),
+ FUNCTION(uim1_reset),
+ FUNCTION(usb1_hs),
+ FUNCTION(usb_phy),
+ FUNCTION(vfr_0),
+ FUNCTION(vfr_1),
+ FUNCTION(vsense_trigger_mirnat),
+};
+
+/*
+ * Every pin is maintained as a single group, and missing or non-existing pin
+ * would be maintained as dummy group to synchronize pin group index with
+ * pin descriptor registered with pinctrl core.
+ * Clients would not be able to request these dummy pin groups.
+ */
+static const struct msm_pingroup sm8550_groups[] = {
+ [0] = PINGROUP(0, cci_i2c_sda, qup2_se0_l0_mirb, ibi_i3c, phase_flag, _, _, _, _, _),
+ [1] = PINGROUP(1, cci_i2c_scl, qup2_se0_l1_mirb, ibi_i3c, _, _, _, _, _, _),
+ [2] = PINGROUP(2, qup2_se4, phase_flag, _, _, _, _, _, _, _),
+ [3] = PINGROUP(3, qup2_se4, phase_flag, _, _, _, _, _, _, _),
+ [4] = PINGROUP(4, i2chub0_se4, _, _, _, _, _, _, _, _),
+ [5] = PINGROUP(5, i2chub0_se4, _, _, _, _, _, _, _, _),
+ [6] = PINGROUP(6, i2chub0_se5, _, _, _, _, _, _, _, _),
+ [7] = PINGROUP(7, i2chub0_se5, _, _, _, _, _, _, _, _),
+ [8] = PINGROUP(8, i2chub0_se6, _, _, _, _, _, _, _, _),
+ [9] = PINGROUP(9, i2chub0_se6, _, _, _, _, _, _, _, _),
+ [10] = PINGROUP(10, i2chub0_se7, qdss_cti, phase_flag, _, _, _, _, _, _),
+ [11] = PINGROUP(11, i2chub0_se7, usb_phy, qdss_cti, phase_flag, _, _, _, _, _),
+ [12] = PINGROUP(12, phase_flag, _, _, _, _, _, _, _, _),
+ [13] = PINGROUP(13, phase_flag, _, _, _, _, _, _, _, _),
+ [14] = PINGROUP(14, _, _, _, _, _, _, _, _, _),
+ [15] = PINGROUP(15, _, _, _, _, _, _, _, _, _),
+ [16] = PINGROUP(16, i2chub0_se0, _, _, _, _, _, _, _, _),
+ [17] = PINGROUP(17, i2chub0_se0, _, _, _, _, _, _, _, _),
+ [18] = PINGROUP(18, i2chub0_se1, _, _, _, _, _, _, _, _),
+ [19] = PINGROUP(19, i2chub0_se1, _, _, _, _, _, _, _, _),
+ [20] = PINGROUP(20, i2chub0_se2, pll_bist_sync, _, _, _, _, _, _, _),
+ [21] = PINGROUP(21, i2chub0_se2, _, _, _, _, _, _, _, _),
+ [22] = PINGROUP(22, i2chub0_se3, _, _, _, _, _, _, _, _),
+ [23] = PINGROUP(23, i2chub0_se3, _, _, _, _, _, _, _, _),
+ [24] = PINGROUP(24, qup1_se7, vsense_trigger_mirnat, _, _, _, _, _, _, _),
+ [25] = PINGROUP(25, qup1_se7, _, _, _, _, _, _, _, _),
+ [26] = PINGROUP(26, qup1_se7, uim1_present, _, _, _, _, _, _, _),
+ [27] = PINGROUP(27, qup1_se7, uim0_present, _, _, _, _, _, _, _),
+ [28] = PINGROUP(28, qup1_se0, ibi_i3c, _, _, _, _, _, _, _),
+ [29] = PINGROUP(29, qup1_se0, ibi_i3c, _, _, _, _, _, _, _),
+ [30] = PINGROUP(30, qup1_se0, _, _, _, _, _, _, _, _),
+ [31] = PINGROUP(31, qup1_se0, _, _, _, _, _, _, _, _),
+ [32] = PINGROUP(32, qup1_se1, ibi_i3c, _, _, _, _, _, _, _),
+ [33] = PINGROUP(33, qup1_se1, ibi_i3c, _, _, _, _, _, _, _),
+ [34] = PINGROUP(34, qup1_se1, _, _, _, _, _, _, _, _),
+ [35] = PINGROUP(35, qup1_se1, _, _, _, _, _, _, _, _),
+ [36] = PINGROUP(36, qup1_se2, ddr_bist_fail, _, _, _, _, _, _, _),
+ [37] = PINGROUP(37, qup1_se2, ddr_bist_start, _, atest_usb, _, _, _, _, _),
+ [38] = PINGROUP(38, qup1_se2, _, _, _, _, _, _, _, _),
+ [39] = PINGROUP(39, qup1_se2, _, atest_usb, _, _, _, _, _, _),
+ [40] = PINGROUP(40, qup1_se3, qup1_se2, ddr_bist_complete, _, ddr_pxi1, _, _, _, _),
+ [41] = PINGROUP(41, qup1_se3, qup1_se2, ddr_bist_stop, _, ddr_pxi1, _, _, _, _),
+ [42] = PINGROUP(42, qup1_se3, qup1_se2, _, _, _, _, _, _, _),
+ [43] = PINGROUP(43, qup1_se3, jitter_bist, ddr_pxi3, _, _, _, _, _, _),
+ [44] = PINGROUP(44, qup1_se4, aoss_cti, ddr_pxi3, _, _, _, _, _, _),
+ [45] = PINGROUP(45, qup1_se4, aoss_cti, ddr_pxi2, _, _, _, _, _, _),
+ [46] = PINGROUP(46, qup1_se4, aoss_cti, _, _, _, _, _, _, _),
+ [47] = PINGROUP(47, qup1_se4, aoss_cti, dp_hot, ddr_pxi2, _, _, _, _, _),
+ [48] = PINGROUP(48, usb_phy, qup1_se6, qspi2, sdc42, _, _, _, _, _),
+ [49] = PINGROUP(49, qup1_se6, qspi3, sdc43, _, _, _, _, _, _),
+ [50] = PINGROUP(50, qup1_se6, qspi_clk, sdc4_clk, tsense_pwm1, tsense_pwm2, tsense_pwm3, _, _, _),
+ [51] = PINGROUP(51, qup1_se6, qspi_cs, sdc4_cmd, ddr_pxi0, _, _, _, _, _),
+ [52] = PINGROUP(52, _, qup1_se5, ddr_pxi0, _, _, _, _, _, _),
+ [53] = PINGROUP(53, _, qup1_se5, _, _, _, _, _, _, _),
+ [54] = PINGROUP(54, _, qup1_se5, _, _, _, _, _, _, _),
+ [55] = PINGROUP(55, qup1_se5, atest_usb, _, _, _, _, _, _, _),
+ [56] = PINGROUP(56, qup2_se0_l0_mira, ibi_i3c, _, _, _, _, _, _, _),
+ [57] = PINGROUP(57, qup2_se0_l1_mira, ibi_i3c, _, _, _, _, _, _, _),
+ [58] = PINGROUP(58, qup2_se0_l2_mira, _, _, _, _, _, _, _, _),
+ [59] = PINGROUP(59, qup2_se0_l3_mira, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [60] = PINGROUP(60, qup2_se1, ibi_i3c, _, _, _, _, _, _, _),
+ [61] = PINGROUP(61, qup2_se1, ibi_i3c, _, _, _, _, _, _, _),
+ [62] = PINGROUP(62, qup2_se1, _, _, _, _, _, _, _, _),
+ [63] = PINGROUP(63, qup2_se1, qup2_se0, phase_flag, _, _, _, _, _, _),
+ [64] = PINGROUP(64, qup2_se2, tb_trig_sdc2, phase_flag, tgu_ch0_trigout, _, qdss_gpio, _, _, _),
+ [65] = PINGROUP(65, qup2_se2, phase_flag, tgu_ch1_trigout, _, _, _, _, _, _),
+ [66] = PINGROUP(66, qup2_se2, qup2_se0, tgu_ch2_trigout, _, _, _, _, _, _),
+ [67] = PINGROUP(67, qup2_se2, qup2_se0, phase_flag, tgu_ch3_trigout, _, _, _, _, _),
+ [68] = PINGROUP(68, qup2_se3, phase_flag, _, _, _, _, _, _, _),
+ [69] = PINGROUP(69, qup2_se3, phase_flag, _, _, _, _, _, _, _),
+ [70] = PINGROUP(70, qup2_se3, _, _, _, _, _, _, _, _),
+ [71] = PINGROUP(71, cci_async_in, qup2_se3, _, _, _, _, _, _, _),
+ [72] = PINGROUP(72, cci_async_in, qup2_se7, _, _, _, _, _, _, _),
+ [73] = PINGROUP(73, qdss_gpio, _, _, _, _, _, _, _, _),
+ [74] = PINGROUP(74, cci_i2c_sda, qup2_se7, _, _, _, _, _, _, _),
+ [75] = PINGROUP(75, cci_i2c_scl, qup2_se7, qdss_cti, phase_flag, _, _, _, _, _),
+ [76] = PINGROUP(76, qup2_se6, phase_flag, _, _, _, _, _, _, _),
+ [77] = PINGROUP(77, qup2_se6, phase_flag, _, _, _, _, _, _, _),
+ [78] = PINGROUP(78, qup2_se6, _, _, _, _, _, _, _, _),
+ [79] = PINGROUP(79, qup2_se6, qdss_cti, phase_flag, _, _, _, _, _, _),
+ [80] = PINGROUP(80, qup2_se5, phase_flag, _, _, _, _, _, _, _),
+ [81] = PINGROUP(81, qup2_se5, phase_flag, _, _, _, _, _, _, _),
+ [82] = PINGROUP(82, qup2_se5, _, _, _, _, _, _, _, _),
+ [83] = PINGROUP(83, qup2_se5, phase_flag, _, _, _, _, _, _, _),
+ [84] = PINGROUP(84, i2chub0_se9, _, _, _, _, _, _, _, _),
+ [85] = PINGROUP(85, i2chub0_se9, _, _, _, _, _, _, _, _),
+ [86] = PINGROUP(86, mdp_vsync, mdp_vsync0_out, mdp_vsync1_out, gcc_gp1, _, _, _, _, _),
+ [87] = PINGROUP(87, mdp_vsync, mdp_vsync2_out, mdp_vsync3_out, gcc_gp2, _, _, _, _, _),
+ [88] = PINGROUP(88, mdp_vsync_e, gcc_gp3, _, _, _, _, _, _, _),
+ [89] = PINGROUP(89, qspi0, sdc40, dbg_out_clk, _, _, _, _, _, _),
+ [90] = PINGROUP(90, usb1_hs, qspi1, sdc41, _, _, _, _, _, _),
+ [91] = PINGROUP(91, qspi_cs, tb_trig_sdc4, _, _, _, _, _, _, _),
+ [92] = PINGROUP(92, resout_n, phase_flag, tmess_prng0, _, _, _, _, _, _),
+ [93] = PINGROUP(93, sd_write_protect, _, _, _, _, _, _, _, _),
+ [94] = PINGROUP(94, phase_flag, tmess_prng1, _, _, _, _, _, _, _),
+ [95] = PINGROUP(95, pcie0_clk_req_n, phase_flag, tmess_prng2, _, _, _, _, _, _),
+ [96] = PINGROUP(96, phase_flag, tmess_prng3, _, _, _, _, _, _, _),
+ [97] = PINGROUP(97, phase_flag, _, _, _, _, _, _, _, _),
+ [98] = PINGROUP(98, pcie1_clk_req_n, phase_flag, _, _, _, _, _, _, _),
+ [99] = PINGROUP(99, phase_flag, _, _, _, _, _, _, _, _),
+ [100] = PINGROUP(100, cam_mclk, qdss_gpio, _, _, _, _, _, _, _),
+ [101] = PINGROUP(101, cam_mclk, qdss_gpio, _, _, _, _, _, _, _),
+ [102] = PINGROUP(102, cam_mclk, qdss_gpio, _, _, _, _, _, _, _),
+ [103] = PINGROUP(103, cam_mclk, qdss_gpio, _, _, _, _, _, _, _),
+ [104] = PINGROUP(104, cam_aon_mclk4, qdss_gpio, _, _, _, _, _, _, _),
+ [105] = PINGROUP(105, cam_mclk, qdss_gpio, _, _, _, _, _, _, _),
+ [106] = PINGROUP(106, cam_mclk, qup2_se7, _, _, _, _, _, _, _),
+ [107] = PINGROUP(107, cam_mclk, qup2_se0_l3_mirb, pll_clk_aux, _, _, _, _, _, _),
+ [108] = PINGROUP(108, _, _, _, _, _, _, _, _, _),
+ [109] = PINGROUP(109, cci_async_in, qup2_se0_l2_mirb, _, _, _, _, _, _, _),
+ [110] = PINGROUP(110, cci_i2c_sda, qdss_gpio, _, _, _, _, _, _, _),
+ [111] = PINGROUP(111, cci_i2c_scl, qdss_gpio, _, _, _, _, _, _, _),
+ [112] = PINGROUP(112, cci_i2c_sda, qdss_gpio, _, _, _, _, _, _, _),
+ [113] = PINGROUP(113, cci_i2c_scl, qdss_gpio, _, _, _, _, _, _, _),
+ [114] = PINGROUP(114, cci_i2c_sda, qdss_gpio, _, _, _, _, _, _, _),
+ [115] = PINGROUP(115, cci_i2c_scl, qdss_gpio, _, _, _, _, _, _, _),
+ [116] = PINGROUP(116, cci_timer, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [117] = PINGROUP(117, cci_timer, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [118] = PINGROUP(118, qup2_se4, cci_timer, _, _, _, _, _, _, _),
+ [119] = PINGROUP(119, qup2_se4, cci_timer, phase_flag, _, _, _, _, _, _),
+ [120] = PINGROUP(120, cci_timer, phase_flag, _, qdss_gpio, _, _, _, _, _),
+ [121] = PINGROUP(121, i2s1_sck, _, _, _, _, _, _, _, _),
+ [122] = PINGROUP(122, i2s1_data0, cmu_rng, _, _, _, _, _, _, _),
+ [123] = PINGROUP(123, i2s1_ws, _, _, _, _, _, _, _, _),
+ [124] = PINGROUP(124, i2s1_data1, audio_ext_mclk1, audio_ref_clk, _, _, _, _, _, _),
+ [125] = PINGROUP(125, audio_ext_mclk0, _, _, _, _, _, _, _, _),
+ [126] = PINGROUP(126, i2s0_sck, _, _, _, _, _, _, _, _),
+ [127] = PINGROUP(127, i2s0_data0, cmu_rng, _, _, _, _, _, _, _),
+ [128] = PINGROUP(128, i2s0_data1, cmu_rng, _, _, _, _, _, _, _),
+ [129] = PINGROUP(129, i2s0_ws, cmu_rng, _, _, _, _, _, _, _),
+ [130] = PINGROUP(130, uim0_data, atest_char, _, _, _, _, _, _, _),
+ [131] = PINGROUP(131, uim0_clk, _, _, _, _, _, _, _, _),
+ [132] = PINGROUP(132, uim0_reset, atest_char, _, _, _, _, _, _, _),
+ [133] = PINGROUP(133, mdp_vsync, atest_char, _, _, _, _, _, _, _),
+ [134] = PINGROUP(134, uim1_data, gcc_gp1, atest_char, _, _, _, _, _, _),
+ [135] = PINGROUP(135, uim1_clk, gcc_gp2, atest_char, _, _, _, _, _, _),
+ [136] = PINGROUP(136, uim1_reset, gcc_gp3, _, _, _, _, _, _, _),
+ [137] = PINGROUP(137, mdp_vsync, _, _, _, _, _, _, _, _),
+ [138] = PINGROUP(138, _, _, qdss_gpio, _, _, _, _, _, _),
+ [139] = PINGROUP(139, _, _, qdss_gpio, _, _, _, _, _, _),
+ [140] = PINGROUP(140, _, _, qdss_gpio, _, _, _, _, _, _),
+ [141] = PINGROUP(141, _, _, qdss_gpio, _, _, _, _, _, _),
+ [142] = PINGROUP(142, _, _, qdss_gpio, _, _, _, _, _, _),
+ [143] = PINGROUP(143, _, _, qdss_gpio, _, _, _, _, _, _),
+ [144] = PINGROUP(144, _, _, qdss_gpio, _, _, _, _, _, _),
+ [145] = PINGROUP(145, _, _, qdss_gpio, _, _, _, _, _, _),
+ [146] = PINGROUP(146, _, _, _, _, _, _, _, _, _),
+ [147] = PINGROUP(147, _, _, _, _, _, _, _, _, _),
+ [148] = PINGROUP(148, coex_uart1_rx, qdss_gpio, atest_usb, _, _, _, _, _, _),
+ [149] = PINGROUP(149, coex_uart1_tx, qdss_gpio, atest_usb, _, _, _, _, _, _),
+ [150] = PINGROUP(150, coex_uart2_rx, _, vfr_0, qdss_gpio, _, _, _, _, _),
+ [151] = PINGROUP(151, coex_uart2_tx, _, qdss_gpio, _, _, _, _, _, _),
+ [152] = PINGROUP(152, _, qdss_gpio, _, _, _, _, _, _, _),
+ [153] = PINGROUP(153, _, nav_gpio2, qdss_gpio, _, _, _, _, _, _),
+ [154] = PINGROUP(154, nav_gpio0, qdss_gpio, _, _, _, _, _, _, _),
+ [155] = PINGROUP(155, nav_gpio1, vfr_1, qdss_gpio, _, _, _, _, _, _),
+ [156] = PINGROUP(156, qlink0_request, qdss_gpio, _, _, _, _, _, _, _),
+ [157] = PINGROUP(157, qlink0_enable, qdss_gpio, _, _, _, _, _, _, _),
+ [158] = PINGROUP(158, qlink0_wmss, _, _, _, _, _, _, _, _),
+ [159] = PINGROUP(159, qlink1_request, qdss_cti, _, _, _, _, _, _, _),
+ [160] = PINGROUP(160, qlink1_enable, qdss_cti, _, _, _, _, _, _, _),
+ [161] = PINGROUP(161, qlink1_wmss, qdss_cti, _, _, _, _, _, _, _),
+ [162] = PINGROUP(162, qlink2_request, qdss_cti, _, _, _, _, _, _, _),
+ [163] = PINGROUP(163, qlink2_enable, _, _, _, _, _, _, _, _),
+ [164] = PINGROUP(164, qlink2_wmss, _, _, _, _, _, _, _, _),
+ [165] = PINGROUP(165, _, _, _, _, _, _, _, _, _),
+ [166] = PINGROUP(166, _, _, _, _, _, _, _, _, _),
+ [167] = PINGROUP(167, _, _, _, _, _, _, _, _, _),
+ [168] = PINGROUP(168, _, _, _, _, _, _, _, _, _),
+ [169] = PINGROUP(169, _, _, _, _, _, _, _, _, _),
+ [170] = PINGROUP(170, _, _, _, _, _, _, _, _, _),
+ [171] = PINGROUP(171, _, _, _, _, _, _, _, _, _),
+ [172] = PINGROUP(172, _, _, _, _, _, _, _, _, _),
+ [173] = PINGROUP(173, _, _, _, _, _, _, _, _, _),
+ [174] = PINGROUP(174, _, _, _, _, _, _, _, _, _),
+ [175] = PINGROUP(175, _, _, _, _, _, _, _, _, _),
+ [176] = PINGROUP(176, _, _, _, _, _, _, _, _, _),
+ [177] = PINGROUP(177, _, _, _, _, _, _, _, _, _),
+ [178] = PINGROUP(178, _, _, _, _, _, _, _, _, _),
+ [179] = PINGROUP(179, _, _, _, _, _, _, _, _, _),
+ [180] = PINGROUP(180, _, _, _, _, _, _, _, _, _),
+ [181] = PINGROUP(181, prng_rosc3, _, _, _, _, _, _, _, _),
+ [182] = PINGROUP(182, prng_rosc2, _, _, _, _, _, _, _, _),
+ [183] = PINGROUP(183, prng_rosc1, _, _, _, _, _, _, _, _),
+ [184] = PINGROUP(184, _, _, _, _, _, _, _, _, _),
+ [185] = PINGROUP(185, _, _, _, _, _, _, _, _, _),
+ [186] = PINGROUP(186, prng_rosc0, _, _, _, _, _, _, _, _),
+ [187] = PINGROUP(187, cri_trng, _, _, _, _, _, _, _, _),
+ [188] = PINGROUP(188, _, _, _, _, _, _, _, _, _),
+ [189] = PINGROUP(189, _, _, _, _, _, _, _, _, _),
+ [190] = PINGROUP(190, _, _, _, _, _, _, _, _, _),
+ [191] = PINGROUP(191, _, _, _, _, _, _, _, _, _),
+ [192] = PINGROUP(192, _, _, _, _, _, _, _, _, _),
+ [193] = PINGROUP(193, _, _, _, _, _, _, _, _, _),
+ [194] = PINGROUP(194, _, _, _, _, _, _, _, _, _),
+ [195] = PINGROUP(195, _, _, _, _, _, _, _, _, _),
+ [196] = PINGROUP(196, _, _, _, _, _, _, _, _, _),
+ [197] = PINGROUP(197, _, _, _, _, _, _, _, _, _),
+ [198] = PINGROUP(198, _, _, _, _, _, _, _, _, _),
+ [199] = PINGROUP(199, _, _, _, _, _, _, _, _, _),
+ [200] = PINGROUP(200, _, _, _, _, _, _, _, _, _),
+ [201] = PINGROUP(201, _, _, _, _, _, _, _, _, _),
+ [202] = PINGROUP(202, _, _, _, _, _, _, _, _, _),
+ [203] = PINGROUP(203, _, _, _, _, _, _, _, _, _),
+ [204] = PINGROUP(204, _, _, _, _, _, _, _, _, _),
+ [205] = PINGROUP(205, _, _, _, _, _, _, _, _, _),
+ [206] = PINGROUP(206, i2chub0_se8, _, _, _, _, _, _, _, _),
+ [207] = PINGROUP(207, i2chub0_se8, _, _, _, _, _, _, _, _),
+ [208] = PINGROUP(208, aon_cci, _, _, _, _, _, _, _, _),
+ [209] = PINGROUP(209, aon_cci, _, _, _, _, _, _, _, _),
+ [210] = UFS_RESET(ufs_reset, 0xde000),
+ [211] = SDC_QDSD_PINGROUP(sdc2_clk, 0xd6000, 14, 6),
+ [212] = SDC_QDSD_PINGROUP(sdc2_cmd, 0xd6000, 11, 3),
+ [213] = SDC_QDSD_PINGROUP(sdc2_data, 0xd6000, 9, 0),
+};
+
+static const struct msm_gpio_wakeirq_map sm8550_pdc_map[] = {
+ { 0, 118 }, { 2, 90 }, { 3, 101 }, { 8, 60 }, { 9, 67 },
+ { 11, 103 }, { 14, 136 }, { 15, 78 }, { 16, 138 }, { 17, 80 },
+ { 18, 71 }, { 19, 59 }, { 25, 57 }, { 26, 74 }, { 27, 76 },
+ { 28, 62 }, { 31, 88 }, { 32, 63 }, { 35, 124 }, { 39, 92 },
+ { 40, 77 }, { 41, 83 }, { 43, 86 }, { 44, 75 }, { 45, 93 },
+ { 46, 96 }, { 47, 64 }, { 48, 110 }, { 51, 89 }, { 55, 95 },
+ { 56, 68 }, { 59, 87 }, { 60, 65 }, { 62, 100 }, { 63, 81 },
+ { 67, 79 }, { 71, 102 }, { 73, 82 }, { 75, 72 }, { 79, 140 },
+ { 82, 105 }, { 83, 104 }, { 84, 126 }, { 85, 142 }, { 86, 106 },
+ { 87, 107 }, { 88, 61 }, { 89, 111 }, { 95, 108 }, { 96, 109 },
+ { 98, 97 }, { 99, 58 }, { 107, 139 }, { 119, 94 }, { 120, 135 },
+ { 133, 52 }, { 137, 84 }, { 148, 66 }, { 150, 73 }, { 153, 70 },
+ { 154, 53 }, { 155, 69 }, { 156, 54 }, { 159, 55 }, { 162, 56 },
+ { 166, 116 }, { 169, 119 }, { 171, 120 }, { 172, 85 }, { 174, 98 },
+ { 176, 112 }, { 177, 51 }, { 181, 114 }, { 182, 115 }, { 185, 117 },
+ { 187, 91 }, { 188, 123 }, { 190, 127 }, { 191, 113 }, { 192, 128 },
+ { 193, 129 }, { 196, 133 }, { 197, 134 }, { 198, 50 }, { 199, 99 },
+ { 200, 49 }, { 201, 48 }, { 203, 125 }, { 205, 141 }, { 206, 137 },
+ { 207, 47 }, { 208, 121 }, { 209, 122 },
+};
+
+static const struct msm_pinctrl_soc_data sm8550_tlmm = {
+ .pins = sm8550_pins,
+ .npins = ARRAY_SIZE(sm8550_pins),
+ .functions = sm8550_functions,
+ .nfunctions = ARRAY_SIZE(sm8550_functions),
+ .groups = sm8550_groups,
+ .ngroups = ARRAY_SIZE(sm8550_groups),
+ .ngpios = 211,
+ .wakeirq_map = sm8550_pdc_map,
+ .nwakeirq_map = ARRAY_SIZE(sm8550_pdc_map),
+ .egpio_func = 9,
+};
+
+static int sm8550_tlmm_probe(struct platform_device *pdev)
+{
+ return msm_pinctrl_probe(pdev, &sm8550_tlmm);
+}
+
+static const struct of_device_id sm8550_tlmm_of_match[] = {
+ { .compatible = "qcom,sm8550-tlmm", },
+ {},
+};
+
+static struct platform_driver sm8550_tlmm_driver = {
+ .driver = {
+ .name = "sm8550-tlmm",
+ .of_match_table = sm8550_tlmm_of_match,
+ },
+ .probe = sm8550_tlmm_probe,
+ .remove = msm_pinctrl_remove,
+};
+
+static int __init sm8550_tlmm_init(void)
+{
+ return platform_driver_register(&sm8550_tlmm_driver);
+}
+arch_initcall(sm8550_tlmm_init);
+
+static void __exit sm8550_tlmm_exit(void)
+{
+ platform_driver_unregister(&sm8550_tlmm_driver);
+}
+module_exit(sm8550_tlmm_exit);
+
+MODULE_DESCRIPTION("QTI SM8550 TLMM driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(of, sm8550_tlmm_of_match);
diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
index 89695b5a2ce7..ea3485344f06 100644
--- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
+++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
@@ -1146,7 +1146,7 @@ static int pmic_gpio_probe(struct platform_device *pdev)
gpio_irq_chip_set_chip(girq, &spmi_gpio_irq_chip);
girq->default_type = IRQ_TYPE_NONE;
girq->handler = handle_level_irq;
- girq->fwnode = of_node_to_fwnode(state->dev->of_node);
+ girq->fwnode = dev_fwnode(state->dev);
girq->parent_domain = parent_domain;
girq->child_to_parent_hwirq = pmic_gpio_child_to_parent_hwirq;
girq->populate_parent_alloc_arg = pmic_gpio_populate_parent_fwspec;
@@ -1221,6 +1221,10 @@ static const struct of_device_id pmic_gpio_of_match[] = {
{ .compatible = "qcom,pm8350b-gpio", .data = (void *) 8 },
{ .compatible = "qcom,pm8350c-gpio", .data = (void *) 9 },
{ .compatible = "qcom,pm8450-gpio", .data = (void *) 4 },
+ { .compatible = "qcom,pm8550-gpio", .data = (void *) 12 },
+ { .compatible = "qcom,pm8550b-gpio", .data = (void *) 12 },
+ { .compatible = "qcom,pm8550ve-gpio", .data = (void *) 8 },
+ { .compatible = "qcom,pm8550vs-gpio", .data = (void *) 6 },
{ .compatible = "qcom,pm8916-gpio", .data = (void *) 4 },
{ .compatible = "qcom,pm8941-gpio", .data = (void *) 36 },
/* pm8950 has 8 GPIOs with holes on 3 */
@@ -1232,11 +1236,13 @@ static const struct of_device_id pmic_gpio_of_match[] = {
{ .compatible = "qcom,pmi8994-gpio", .data = (void *) 10 },
{ .compatible = "qcom,pmi8998-gpio", .data = (void *) 14 },
{ .compatible = "qcom,pmk8350-gpio", .data = (void *) 4 },
+ { .compatible = "qcom,pmk8550-gpio", .data = (void *) 6 },
{ .compatible = "qcom,pmm8155au-gpio", .data = (void *) 10 },
/* pmp8074 has 12 GPIOs with holes on 1 and 12 */
{ .compatible = "qcom,pmp8074-gpio", .data = (void *) 12 },
{ .compatible = "qcom,pmr735a-gpio", .data = (void *) 4 },
{ .compatible = "qcom,pmr735b-gpio", .data = (void *) 4 },
+ { .compatible = "qcom,pmr735d-gpio", .data = (void *) 2 },
/* pms405 has 12 GPIOs with holes on 1, 9, and 10 */
{ .compatible = "qcom,pms405-gpio", .data = (void *) 12 },
/* pmx55 has 11 GPIOs with holes on 3, 7, 10, 11 */
diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c
index 063177b79927..644fb4a0e72a 100644
--- a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c
+++ b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c
@@ -927,7 +927,7 @@ static int pmic_mpp_probe(struct platform_device *pdev)
girq->chip = &state->irq;
girq->default_type = IRQ_TYPE_NONE;
girq->handler = handle_level_irq;
- girq->fwnode = of_node_to_fwnode(state->dev->of_node);
+ girq->fwnode = dev_fwnode(state->dev);
girq->parent_domain = parent_domain;
girq->child_to_parent_hwirq = pmic_mpp_child_to_parent_hwirq;
girq->populate_parent_alloc_arg = gpiochip_populate_parent_fwspec_fourcell;
diff --git a/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c b/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c
index 99314925bb13..e973001e5c88 100644
--- a/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c
+++ b/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c
@@ -791,7 +791,7 @@ static int pm8xxx_gpio_probe(struct platform_device *pdev)
girq->chip = &pm8xxx_irq_chip;
girq->default_type = IRQ_TYPE_NONE;
girq->handler = handle_level_irq;
- girq->fwnode = of_node_to_fwnode(pctrl->dev->of_node);
+ girq->fwnode = dev_fwnode(pctrl->dev);
girq->parent_domain = parent_domain;
girq->child_to_parent_hwirq = pm8xxx_child_to_parent_hwirq;
girq->populate_parent_alloc_arg = gpiochip_populate_parent_fwspec_twocell;
diff --git a/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c b/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c
index a46650db678a..86f66cb8bf30 100644
--- a/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c
+++ b/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c
@@ -881,7 +881,7 @@ static int pm8xxx_mpp_probe(struct platform_device *pdev)
girq->chip = &pctrl->irq;
girq->default_type = IRQ_TYPE_NONE;
girq->handler = handle_level_irq;
- girq->fwnode = of_node_to_fwnode(pctrl->dev->of_node);
+ girq->fwnode = dev_fwnode(pctrl->dev);
girq->parent_domain = parent_domain;
if (of_device_is_compatible(pdev->dev.of_node, "qcom,pm8821-mpp"))
girq->child_to_parent_hwirq = pm8821_mpp_child_to_parent_hwirq;
diff --git a/drivers/pinctrl/ralink/pinctrl-mt7620.c b/drivers/pinctrl/ralink/pinctrl-mt7620.c
index 22ff16eff02f..4e8d26bb3430 100644
--- a/drivers/pinctrl/ralink/pinctrl-mt7620.c
+++ b/drivers/pinctrl/ralink/pinctrl-mt7620.c
@@ -54,20 +54,20 @@
#define MT7620_GPIO_MODE_EPHY 15
#define MT7620_GPIO_MODE_PA 20
-static struct ralink_pmx_func i2c_func[] = { FUNC("i2c", 0, 1, 2) };
-static struct ralink_pmx_func spi_func[] = { FUNC("spi", 0, 3, 4) };
-static struct ralink_pmx_func uartlite_func[] = { FUNC("uartlite", 0, 15, 2) };
-static struct ralink_pmx_func mdio_func[] = {
+static struct ralink_pmx_func i2c_grp[] = { FUNC("i2c", 0, 1, 2) };
+static struct ralink_pmx_func spi_grp[] = { FUNC("spi", 0, 3, 4) };
+static struct ralink_pmx_func uartlite_grp[] = { FUNC("uartlite", 0, 15, 2) };
+static struct ralink_pmx_func mdio_grp[] = {
FUNC("mdio", MT7620_GPIO_MODE_MDIO, 22, 2),
FUNC("refclk", MT7620_GPIO_MODE_MDIO_REFCLK, 22, 2),
};
-static struct ralink_pmx_func rgmii1_func[] = { FUNC("rgmii1", 0, 24, 12) };
-static struct ralink_pmx_func refclk_func[] = { FUNC("spi refclk", 0, 37, 3) };
-static struct ralink_pmx_func ephy_func[] = { FUNC("ephy", 0, 40, 5) };
-static struct ralink_pmx_func rgmii2_func[] = { FUNC("rgmii2", 0, 60, 12) };
-static struct ralink_pmx_func wled_func[] = { FUNC("wled", 0, 72, 1) };
-static struct ralink_pmx_func pa_func[] = { FUNC("pa", 0, 18, 4) };
-static struct ralink_pmx_func uartf_func[] = {
+static struct ralink_pmx_func rgmii1_grp[] = { FUNC("rgmii1", 0, 24, 12) };
+static struct ralink_pmx_func refclk_grp[] = { FUNC("spi refclk", 0, 37, 3) };
+static struct ralink_pmx_func ephy_grp[] = { FUNC("ephy", 0, 40, 5) };
+static struct ralink_pmx_func rgmii2_grp[] = { FUNC("rgmii2", 0, 60, 12) };
+static struct ralink_pmx_func wled_grp[] = { FUNC("wled", 0, 72, 1) };
+static struct ralink_pmx_func pa_grp[] = { FUNC("pa", 0, 18, 4) };
+static struct ralink_pmx_func uartf_grp[] = {
FUNC("uartf", MT7620_GPIO_MODE_UARTF, 7, 8),
FUNC("pcm uartf", MT7620_GPIO_MODE_PCM_UARTF, 7, 8),
FUNC("pcm i2s", MT7620_GPIO_MODE_PCM_I2S, 7, 8),
@@ -76,202 +76,202 @@ static struct ralink_pmx_func uartf_func[] = {
FUNC("gpio uartf", MT7620_GPIO_MODE_GPIO_UARTF, 7, 4),
FUNC("gpio i2s", MT7620_GPIO_MODE_GPIO_I2S, 7, 4),
};
-static struct ralink_pmx_func wdt_func[] = {
+static struct ralink_pmx_func wdt_grp[] = {
FUNC("wdt rst", 0, 17, 1),
FUNC("wdt refclk", 0, 17, 1),
};
-static struct ralink_pmx_func pcie_rst_func[] = {
+static struct ralink_pmx_func pcie_rst_grp[] = {
FUNC("pcie rst", MT7620_GPIO_MODE_PCIE_RST, 36, 1),
FUNC("pcie refclk", MT7620_GPIO_MODE_PCIE_REF, 36, 1)
};
-static struct ralink_pmx_func nd_sd_func[] = {
+static struct ralink_pmx_func nd_sd_grp[] = {
FUNC("nand", MT7620_GPIO_MODE_NAND, 45, 15),
FUNC("sd", MT7620_GPIO_MODE_SD, 47, 13)
};
static struct ralink_pmx_group mt7620a_pinmux_data[] = {
- GRP("i2c", i2c_func, 1, MT7620_GPIO_MODE_I2C),
- GRP("uartf", uartf_func, MT7620_GPIO_MODE_UART0_MASK,
+ GRP("i2c", i2c_grp, 1, MT7620_GPIO_MODE_I2C),
+ GRP("uartf", uartf_grp, MT7620_GPIO_MODE_UART0_MASK,
MT7620_GPIO_MODE_UART0_SHIFT),
- GRP("spi", spi_func, 1, MT7620_GPIO_MODE_SPI),
- GRP("uartlite", uartlite_func, 1, MT7620_GPIO_MODE_UART1),
- GRP_G("wdt", wdt_func, MT7620_GPIO_MODE_WDT_MASK,
+ GRP("spi", spi_grp, 1, MT7620_GPIO_MODE_SPI),
+ GRP("uartlite", uartlite_grp, 1, MT7620_GPIO_MODE_UART1),
+ GRP_G("wdt", wdt_grp, MT7620_GPIO_MODE_WDT_MASK,
MT7620_GPIO_MODE_WDT_GPIO, MT7620_GPIO_MODE_WDT_SHIFT),
- GRP_G("mdio", mdio_func, MT7620_GPIO_MODE_MDIO_MASK,
+ GRP_G("mdio", mdio_grp, MT7620_GPIO_MODE_MDIO_MASK,
MT7620_GPIO_MODE_MDIO_GPIO, MT7620_GPIO_MODE_MDIO_SHIFT),
- GRP("rgmii1", rgmii1_func, 1, MT7620_GPIO_MODE_RGMII1),
- GRP("spi refclk", refclk_func, 1, MT7620_GPIO_MODE_SPI_REF_CLK),
- GRP_G("pcie", pcie_rst_func, MT7620_GPIO_MODE_PCIE_MASK,
+ GRP("rgmii1", rgmii1_grp, 1, MT7620_GPIO_MODE_RGMII1),
+ GRP("spi refclk", refclk_grp, 1, MT7620_GPIO_MODE_SPI_REF_CLK),
+ GRP_G("pcie", pcie_rst_grp, MT7620_GPIO_MODE_PCIE_MASK,
MT7620_GPIO_MODE_PCIE_GPIO, MT7620_GPIO_MODE_PCIE_SHIFT),
- GRP_G("nd_sd", nd_sd_func, MT7620_GPIO_MODE_ND_SD_MASK,
+ GRP_G("nd_sd", nd_sd_grp, MT7620_GPIO_MODE_ND_SD_MASK,
MT7620_GPIO_MODE_ND_SD_GPIO, MT7620_GPIO_MODE_ND_SD_SHIFT),
- GRP("rgmii2", rgmii2_func, 1, MT7620_GPIO_MODE_RGMII2),
- GRP("wled", wled_func, 1, MT7620_GPIO_MODE_WLED),
- GRP("ephy", ephy_func, 1, MT7620_GPIO_MODE_EPHY),
- GRP("pa", pa_func, 1, MT7620_GPIO_MODE_PA),
+ GRP("rgmii2", rgmii2_grp, 1, MT7620_GPIO_MODE_RGMII2),
+ GRP("wled", wled_grp, 1, MT7620_GPIO_MODE_WLED),
+ GRP("ephy", ephy_grp, 1, MT7620_GPIO_MODE_EPHY),
+ GRP("pa", pa_grp, 1, MT7620_GPIO_MODE_PA),
{ 0 }
};
-static struct ralink_pmx_func pwm1_func_mt76x8[] = {
+static struct ralink_pmx_func pwm1_grp_mt76x8[] = {
FUNC("sdxc d6", 3, 19, 1),
FUNC("utif", 2, 19, 1),
FUNC("gpio", 1, 19, 1),
FUNC("pwm1", 0, 19, 1),
};
-static struct ralink_pmx_func pwm0_func_mt76x8[] = {
+static struct ralink_pmx_func pwm0_grp_mt76x8[] = {
FUNC("sdxc d7", 3, 18, 1),
FUNC("utif", 2, 18, 1),
FUNC("gpio", 1, 18, 1),
FUNC("pwm0", 0, 18, 1),
};
-static struct ralink_pmx_func uart2_func_mt76x8[] = {
+static struct ralink_pmx_func uart2_grp_mt76x8[] = {
FUNC("sdxc d5 d4", 3, 20, 2),
FUNC("pwm", 2, 20, 2),
FUNC("gpio", 1, 20, 2),
FUNC("uart2", 0, 20, 2),
};
-static struct ralink_pmx_func uart1_func_mt76x8[] = {
+static struct ralink_pmx_func uart1_grp_mt76x8[] = {
FUNC("sw_r", 3, 45, 2),
FUNC("pwm", 2, 45, 2),
FUNC("gpio", 1, 45, 2),
FUNC("uart1", 0, 45, 2),
};
-static struct ralink_pmx_func i2c_func_mt76x8[] = {
+static struct ralink_pmx_func i2c_grp_mt76x8[] = {
FUNC("-", 3, 4, 2),
FUNC("debug", 2, 4, 2),
FUNC("gpio", 1, 4, 2),
FUNC("i2c", 0, 4, 2),
};
-static struct ralink_pmx_func refclk_func_mt76x8[] = { FUNC("refclk", 0, 37, 1) };
-static struct ralink_pmx_func perst_func_mt76x8[] = { FUNC("perst", 0, 36, 1) };
-static struct ralink_pmx_func wdt_func_mt76x8[] = { FUNC("wdt", 0, 38, 1) };
-static struct ralink_pmx_func spi_func_mt76x8[] = { FUNC("spi", 0, 7, 4) };
+static struct ralink_pmx_func refclk_grp_mt76x8[] = { FUNC("refclk", 0, 37, 1) };
+static struct ralink_pmx_func perst_grp_mt76x8[] = { FUNC("perst", 0, 36, 1) };
+static struct ralink_pmx_func wdt_grp_mt76x8[] = { FUNC("wdt", 0, 38, 1) };
+static struct ralink_pmx_func spi_grp_mt76x8[] = { FUNC("spi", 0, 7, 4) };
-static struct ralink_pmx_func sd_mode_func_mt76x8[] = {
+static struct ralink_pmx_func sd_mode_grp_mt76x8[] = {
FUNC("jtag", 3, 22, 8),
FUNC("utif", 2, 22, 8),
FUNC("gpio", 1, 22, 8),
FUNC("sdxc", 0, 22, 8),
};
-static struct ralink_pmx_func uart0_func_mt76x8[] = {
+static struct ralink_pmx_func uart0_grp_mt76x8[] = {
FUNC("-", 3, 12, 2),
FUNC("-", 2, 12, 2),
FUNC("gpio", 1, 12, 2),
FUNC("uart0", 0, 12, 2),
};
-static struct ralink_pmx_func i2s_func_mt76x8[] = {
+static struct ralink_pmx_func i2s_grp_mt76x8[] = {
FUNC("antenna", 3, 0, 4),
FUNC("pcm", 2, 0, 4),
FUNC("gpio", 1, 0, 4),
FUNC("i2s", 0, 0, 4),
};
-static struct ralink_pmx_func spi_cs1_func_mt76x8[] = {
+static struct ralink_pmx_func spi_cs1_grp_mt76x8[] = {
FUNC("-", 3, 6, 1),
FUNC("refclk", 2, 6, 1),
FUNC("gpio", 1, 6, 1),
FUNC("spi cs1", 0, 6, 1),
};
-static struct ralink_pmx_func spis_func_mt76x8[] = {
+static struct ralink_pmx_func spis_grp_mt76x8[] = {
FUNC("pwm_uart2", 3, 14, 4),
FUNC("utif", 2, 14, 4),
FUNC("gpio", 1, 14, 4),
FUNC("spis", 0, 14, 4),
};
-static struct ralink_pmx_func gpio_func_mt76x8[] = {
+static struct ralink_pmx_func gpio_grp_mt76x8[] = {
FUNC("pcie", 3, 11, 1),
FUNC("refclk", 2, 11, 1),
FUNC("gpio", 1, 11, 1),
FUNC("gpio", 0, 11, 1),
};
-static struct ralink_pmx_func p4led_kn_func_mt76x8[] = {
+static struct ralink_pmx_func p4led_kn_grp_mt76x8[] = {
FUNC("jtag", 3, 30, 1),
FUNC("utif", 2, 30, 1),
FUNC("gpio", 1, 30, 1),
FUNC("p4led_kn", 0, 30, 1),
};
-static struct ralink_pmx_func p3led_kn_func_mt76x8[] = {
+static struct ralink_pmx_func p3led_kn_grp_mt76x8[] = {
FUNC("jtag", 3, 31, 1),
FUNC("utif", 2, 31, 1),
FUNC("gpio", 1, 31, 1),
FUNC("p3led_kn", 0, 31, 1),
};
-static struct ralink_pmx_func p2led_kn_func_mt76x8[] = {
+static struct ralink_pmx_func p2led_kn_grp_mt76x8[] = {
FUNC("jtag", 3, 32, 1),
FUNC("utif", 2, 32, 1),
FUNC("gpio", 1, 32, 1),
FUNC("p2led_kn", 0, 32, 1),
};
-static struct ralink_pmx_func p1led_kn_func_mt76x8[] = {
+static struct ralink_pmx_func p1led_kn_grp_mt76x8[] = {
FUNC("jtag", 3, 33, 1),
FUNC("utif", 2, 33, 1),
FUNC("gpio", 1, 33, 1),
FUNC("p1led_kn", 0, 33, 1),
};
-static struct ralink_pmx_func p0led_kn_func_mt76x8[] = {
+static struct ralink_pmx_func p0led_kn_grp_mt76x8[] = {
FUNC("jtag", 3, 34, 1),
FUNC("rsvd", 2, 34, 1),
FUNC("gpio", 1, 34, 1),
FUNC("p0led_kn", 0, 34, 1),
};
-static struct ralink_pmx_func wled_kn_func_mt76x8[] = {
+static struct ralink_pmx_func wled_kn_grp_mt76x8[] = {
FUNC("rsvd", 3, 35, 1),
FUNC("rsvd", 2, 35, 1),
FUNC("gpio", 1, 35, 1),
FUNC("wled_kn", 0, 35, 1),
};
-static struct ralink_pmx_func p4led_an_func_mt76x8[] = {
+static struct ralink_pmx_func p4led_an_grp_mt76x8[] = {
FUNC("jtag", 3, 39, 1),
FUNC("utif", 2, 39, 1),
FUNC("gpio", 1, 39, 1),
FUNC("p4led_an", 0, 39, 1),
};
-static struct ralink_pmx_func p3led_an_func_mt76x8[] = {
+static struct ralink_pmx_func p3led_an_grp_mt76x8[] = {
FUNC("jtag", 3, 40, 1),
FUNC("utif", 2, 40, 1),
FUNC("gpio", 1, 40, 1),
FUNC("p3led_an", 0, 40, 1),
};
-static struct ralink_pmx_func p2led_an_func_mt76x8[] = {
+static struct ralink_pmx_func p2led_an_grp_mt76x8[] = {
FUNC("jtag", 3, 41, 1),
FUNC("utif", 2, 41, 1),
FUNC("gpio", 1, 41, 1),
FUNC("p2led_an", 0, 41, 1),
};
-static struct ralink_pmx_func p1led_an_func_mt76x8[] = {
+static struct ralink_pmx_func p1led_an_grp_mt76x8[] = {
FUNC("jtag", 3, 42, 1),
FUNC("utif", 2, 42, 1),
FUNC("gpio", 1, 42, 1),
FUNC("p1led_an", 0, 42, 1),
};
-static struct ralink_pmx_func p0led_an_func_mt76x8[] = {
+static struct ralink_pmx_func p0led_an_grp_mt76x8[] = {
FUNC("jtag", 3, 43, 1),
FUNC("rsvd", 2, 43, 1),
FUNC("gpio", 1, 43, 1),
FUNC("p0led_an", 0, 43, 1),
};
-static struct ralink_pmx_func wled_an_func_mt76x8[] = {
+static struct ralink_pmx_func wled_an_grp_mt76x8[] = {
FUNC("rsvd", 3, 44, 1),
FUNC("rsvd", 2, 44, 1),
FUNC("gpio", 1, 44, 1),
@@ -309,55 +309,55 @@ static struct ralink_pmx_func wled_an_func_mt76x8[] = {
#define MT76X8_GPIO_MODE_GPIO 0
static struct ralink_pmx_group mt76x8_pinmux_data[] = {
- GRP_G("pwm1", pwm1_func_mt76x8, MT76X8_GPIO_MODE_MASK,
+ GRP_G("pwm1", pwm1_grp_mt76x8, MT76X8_GPIO_MODE_MASK,
1, MT76X8_GPIO_MODE_PWM1),
- GRP_G("pwm0", pwm0_func_mt76x8, MT76X8_GPIO_MODE_MASK,
+ GRP_G("pwm0", pwm0_grp_mt76x8, MT76X8_GPIO_MODE_MASK,
1, MT76X8_GPIO_MODE_PWM0),
- GRP_G("uart2", uart2_func_mt76x8, MT76X8_GPIO_MODE_MASK,
+ GRP_G("uart2", uart2_grp_mt76x8, MT76X8_GPIO_MODE_MASK,
1, MT76X8_GPIO_MODE_UART2),
- GRP_G("uart1", uart1_func_mt76x8, MT76X8_GPIO_MODE_MASK,
+ GRP_G("uart1", uart1_grp_mt76x8, MT76X8_GPIO_MODE_MASK,
1, MT76X8_GPIO_MODE_UART1),
- GRP_G("i2c", i2c_func_mt76x8, MT76X8_GPIO_MODE_MASK,
+ GRP_G("i2c", i2c_grp_mt76x8, MT76X8_GPIO_MODE_MASK,
1, MT76X8_GPIO_MODE_I2C),
- GRP("refclk", refclk_func_mt76x8, 1, MT76X8_GPIO_MODE_REFCLK),
- GRP("perst", perst_func_mt76x8, 1, MT76X8_GPIO_MODE_PERST),
- GRP("wdt", wdt_func_mt76x8, 1, MT76X8_GPIO_MODE_WDT),
- GRP("spi", spi_func_mt76x8, 1, MT76X8_GPIO_MODE_SPI),
- GRP_G("sdmode", sd_mode_func_mt76x8, MT76X8_GPIO_MODE_MASK,
+ GRP("refclk", refclk_grp_mt76x8, 1, MT76X8_GPIO_MODE_REFCLK),
+ GRP("perst", perst_grp_mt76x8, 1, MT76X8_GPIO_MODE_PERST),
+ GRP("wdt", wdt_grp_mt76x8, 1, MT76X8_GPIO_MODE_WDT),
+ GRP("spi", spi_grp_mt76x8, 1, MT76X8_GPIO_MODE_SPI),
+ GRP_G("sdmode", sd_mode_grp_mt76x8, MT76X8_GPIO_MODE_MASK,
1, MT76X8_GPIO_MODE_SDMODE),
- GRP_G("uart0", uart0_func_mt76x8, MT76X8_GPIO_MODE_MASK,
+ GRP_G("uart0", uart0_grp_mt76x8, MT76X8_GPIO_MODE_MASK,
1, MT76X8_GPIO_MODE_UART0),
- GRP_G("i2s", i2s_func_mt76x8, MT76X8_GPIO_MODE_MASK,
+ GRP_G("i2s", i2s_grp_mt76x8, MT76X8_GPIO_MODE_MASK,
1, MT76X8_GPIO_MODE_I2S),
- GRP_G("spi cs1", spi_cs1_func_mt76x8, MT76X8_GPIO_MODE_MASK,
+ GRP_G("spi cs1", spi_cs1_grp_mt76x8, MT76X8_GPIO_MODE_MASK,
1, MT76X8_GPIO_MODE_CS1),
- GRP_G("spis", spis_func_mt76x8, MT76X8_GPIO_MODE_MASK,
+ GRP_G("spis", spis_grp_mt76x8, MT76X8_GPIO_MODE_MASK,
1, MT76X8_GPIO_MODE_SPIS),
- GRP_G("gpio", gpio_func_mt76x8, MT76X8_GPIO_MODE_MASK,
+ GRP_G("gpio", gpio_grp_mt76x8, MT76X8_GPIO_MODE_MASK,
1, MT76X8_GPIO_MODE_GPIO),
- GRP_G("wled_an", wled_an_func_mt76x8, MT76X8_GPIO_MODE_MASK,
+ GRP_G("wled_an", wled_an_grp_mt76x8, MT76X8_GPIO_MODE_MASK,
1, MT76X8_GPIO_MODE_WLED_AN),
- GRP_G("p0led_an", p0led_an_func_mt76x8, MT76X8_GPIO_MODE_MASK,
+ GRP_G("p0led_an", p0led_an_grp_mt76x8, MT76X8_GPIO_MODE_MASK,
1, MT76X8_GPIO_MODE_P0LED_AN),
- GRP_G("p1led_an", p1led_an_func_mt76x8, MT76X8_GPIO_MODE_MASK,
+ GRP_G("p1led_an", p1led_an_grp_mt76x8, MT76X8_GPIO_MODE_MASK,
1, MT76X8_GPIO_MODE_P1LED_AN),
- GRP_G("p2led_an", p2led_an_func_mt76x8, MT76X8_GPIO_MODE_MASK,
+ GRP_G("p2led_an", p2led_an_grp_mt76x8, MT76X8_GPIO_MODE_MASK,
1, MT76X8_GPIO_MODE_P2LED_AN),
- GRP_G("p3led_an", p3led_an_func_mt76x8, MT76X8_GPIO_MODE_MASK,
+ GRP_G("p3led_an", p3led_an_grp_mt76x8, MT76X8_GPIO_MODE_MASK,
1, MT76X8_GPIO_MODE_P3LED_AN),
- GRP_G("p4led_an", p4led_an_func_mt76x8, MT76X8_GPIO_MODE_MASK,
+ GRP_G("p4led_an", p4led_an_grp_mt76x8, MT76X8_GPIO_MODE_MASK,
1, MT76X8_GPIO_MODE_P4LED_AN),
- GRP_G("wled_kn", wled_kn_func_mt76x8, MT76X8_GPIO_MODE_MASK,
+ GRP_G("wled_kn", wled_kn_grp_mt76x8, MT76X8_GPIO_MODE_MASK,
1, MT76X8_GPIO_MODE_WLED_KN),
- GRP_G("p0led_kn", p0led_kn_func_mt76x8, MT76X8_GPIO_MODE_MASK,
+ GRP_G("p0led_kn", p0led_kn_grp_mt76x8, MT76X8_GPIO_MODE_MASK,
1, MT76X8_GPIO_MODE_P0LED_KN),
- GRP_G("p1led_kn", p1led_kn_func_mt76x8, MT76X8_GPIO_MODE_MASK,
+ GRP_G("p1led_kn", p1led_kn_grp_mt76x8, MT76X8_GPIO_MODE_MASK,
1, MT76X8_GPIO_MODE_P1LED_KN),
- GRP_G("p2led_kn", p2led_kn_func_mt76x8, MT76X8_GPIO_MODE_MASK,
+ GRP_G("p2led_kn", p2led_kn_grp_mt76x8, MT76X8_GPIO_MODE_MASK,
1, MT76X8_GPIO_MODE_P2LED_KN),
- GRP_G("p3led_kn", p3led_kn_func_mt76x8, MT76X8_GPIO_MODE_MASK,
+ GRP_G("p3led_kn", p3led_kn_grp_mt76x8, MT76X8_GPIO_MODE_MASK,
1, MT76X8_GPIO_MODE_P3LED_KN),
- GRP_G("p4led_kn", p4led_kn_func_mt76x8, MT76X8_GPIO_MODE_MASK,
+ GRP_G("p4led_kn", p4led_kn_grp_mt76x8, MT76X8_GPIO_MODE_MASK,
1, MT76X8_GPIO_MODE_P4LED_KN),
{ 0 }
};
diff --git a/drivers/pinctrl/ralink/pinctrl-mt7621.c b/drivers/pinctrl/ralink/pinctrl-mt7621.c
index b47968f40e0c..eddc0ba6d468 100644
--- a/drivers/pinctrl/ralink/pinctrl-mt7621.c
+++ b/drivers/pinctrl/ralink/pinctrl-mt7621.c
@@ -34,59 +34,59 @@
#define MT7621_GPIO_MODE_SDHCI_SHIFT 18
#define MT7621_GPIO_MODE_SDHCI_GPIO 1
-static struct ralink_pmx_func uart1_func[] = { FUNC("uart1", 0, 1, 2) };
-static struct ralink_pmx_func i2c_func[] = { FUNC("i2c", 0, 3, 2) };
-static struct ralink_pmx_func uart3_func[] = {
+static struct ralink_pmx_func uart1_grp[] = { FUNC("uart1", 0, 1, 2) };
+static struct ralink_pmx_func i2c_grp[] = { FUNC("i2c", 0, 3, 2) };
+static struct ralink_pmx_func uart3_grp[] = {
FUNC("uart3", 0, 5, 4),
FUNC("i2s", 2, 5, 4),
FUNC("spdif3", 3, 5, 4),
};
-static struct ralink_pmx_func uart2_func[] = {
+static struct ralink_pmx_func uart2_grp[] = {
FUNC("uart2", 0, 9, 4),
FUNC("pcm", 2, 9, 4),
FUNC("spdif2", 3, 9, 4),
};
-static struct ralink_pmx_func jtag_func[] = { FUNC("jtag", 0, 13, 5) };
-static struct ralink_pmx_func wdt_func[] = {
+static struct ralink_pmx_func jtag_grp[] = { FUNC("jtag", 0, 13, 5) };
+static struct ralink_pmx_func wdt_grp[] = {
FUNC("wdt rst", 0, 18, 1),
FUNC("wdt refclk", 2, 18, 1),
};
-static struct ralink_pmx_func pcie_rst_func[] = {
+static struct ralink_pmx_func pcie_rst_grp[] = {
FUNC("pcie rst", MT7621_GPIO_MODE_PCIE_RST, 19, 1),
FUNC("pcie refclk", MT7621_GPIO_MODE_PCIE_REF, 19, 1)
};
-static struct ralink_pmx_func mdio_func[] = { FUNC("mdio", 0, 20, 2) };
-static struct ralink_pmx_func rgmii2_func[] = { FUNC("rgmii2", 0, 22, 12) };
-static struct ralink_pmx_func spi_func[] = {
+static struct ralink_pmx_func mdio_grp[] = { FUNC("mdio", 0, 20, 2) };
+static struct ralink_pmx_func rgmii2_grp[] = { FUNC("rgmii2", 0, 22, 12) };
+static struct ralink_pmx_func spi_grp[] = {
FUNC("spi", 0, 34, 7),
FUNC("nand1", 2, 34, 7),
};
-static struct ralink_pmx_func sdhci_func[] = {
+static struct ralink_pmx_func sdhci_grp[] = {
FUNC("sdhci", 0, 41, 8),
FUNC("nand2", 2, 41, 8),
};
-static struct ralink_pmx_func rgmii1_func[] = { FUNC("rgmii1", 0, 49, 12) };
+static struct ralink_pmx_func rgmii1_grp[] = { FUNC("rgmii1", 0, 49, 12) };
static struct ralink_pmx_group mt7621_pinmux_data[] = {
- GRP("uart1", uart1_func, 1, MT7621_GPIO_MODE_UART1),
- GRP("i2c", i2c_func, 1, MT7621_GPIO_MODE_I2C),
- GRP_G("uart3", uart3_func, MT7621_GPIO_MODE_UART3_MASK,
+ GRP("uart1", uart1_grp, 1, MT7621_GPIO_MODE_UART1),
+ GRP("i2c", i2c_grp, 1, MT7621_GPIO_MODE_I2C),
+ GRP_G("uart3", uart3_grp, MT7621_GPIO_MODE_UART3_MASK,
MT7621_GPIO_MODE_UART3_GPIO, MT7621_GPIO_MODE_UART3_SHIFT),
- GRP_G("uart2", uart2_func, MT7621_GPIO_MODE_UART2_MASK,
+ GRP_G("uart2", uart2_grp, MT7621_GPIO_MODE_UART2_MASK,
MT7621_GPIO_MODE_UART2_GPIO, MT7621_GPIO_MODE_UART2_SHIFT),
- GRP("jtag", jtag_func, 1, MT7621_GPIO_MODE_JTAG),
- GRP_G("wdt", wdt_func, MT7621_GPIO_MODE_WDT_MASK,
+ GRP("jtag", jtag_grp, 1, MT7621_GPIO_MODE_JTAG),
+ GRP_G("wdt", wdt_grp, MT7621_GPIO_MODE_WDT_MASK,
MT7621_GPIO_MODE_WDT_GPIO, MT7621_GPIO_MODE_WDT_SHIFT),
- GRP_G("pcie", pcie_rst_func, MT7621_GPIO_MODE_PCIE_MASK,
+ GRP_G("pcie", pcie_rst_grp, MT7621_GPIO_MODE_PCIE_MASK,
MT7621_GPIO_MODE_PCIE_GPIO, MT7621_GPIO_MODE_PCIE_SHIFT),
- GRP_G("mdio", mdio_func, MT7621_GPIO_MODE_MDIO_MASK,
+ GRP_G("mdio", mdio_grp, MT7621_GPIO_MODE_MDIO_MASK,
MT7621_GPIO_MODE_MDIO_GPIO, MT7621_GPIO_MODE_MDIO_SHIFT),
- GRP("rgmii2", rgmii2_func, 1, MT7621_GPIO_MODE_RGMII2),
- GRP_G("spi", spi_func, MT7621_GPIO_MODE_SPI_MASK,
+ GRP("rgmii2", rgmii2_grp, 1, MT7621_GPIO_MODE_RGMII2),
+ GRP_G("spi", spi_grp, MT7621_GPIO_MODE_SPI_MASK,
MT7621_GPIO_MODE_SPI_GPIO, MT7621_GPIO_MODE_SPI_SHIFT),
- GRP_G("sdhci", sdhci_func, MT7621_GPIO_MODE_SDHCI_MASK,
+ GRP_G("sdhci", sdhci_grp, MT7621_GPIO_MODE_SDHCI_MASK,
MT7621_GPIO_MODE_SDHCI_GPIO, MT7621_GPIO_MODE_SDHCI_SHIFT),
- GRP("rgmii1", rgmii1_func, 1, MT7621_GPIO_MODE_RGMII1),
+ GRP("rgmii1", rgmii1_grp, 1, MT7621_GPIO_MODE_RGMII1),
{ 0 }
};
diff --git a/drivers/pinctrl/ralink/pinctrl-rt2880.c b/drivers/pinctrl/ralink/pinctrl-rt2880.c
index 811e12df1133..3e2f1aaaf095 100644
--- a/drivers/pinctrl/ralink/pinctrl-rt2880.c
+++ b/drivers/pinctrl/ralink/pinctrl-rt2880.c
@@ -15,22 +15,22 @@
#define RT2880_GPIO_MODE_SDRAM BIT(6)
#define RT2880_GPIO_MODE_PCI BIT(7)
-static struct ralink_pmx_func i2c_func[] = { FUNC("i2c", 0, 1, 2) };
-static struct ralink_pmx_func spi_func[] = { FUNC("spi", 0, 3, 4) };
-static struct ralink_pmx_func uartlite_func[] = { FUNC("uartlite", 0, 7, 8) };
-static struct ralink_pmx_func jtag_func[] = { FUNC("jtag", 0, 17, 5) };
-static struct ralink_pmx_func mdio_func[] = { FUNC("mdio", 0, 22, 2) };
-static struct ralink_pmx_func sdram_func[] = { FUNC("sdram", 0, 24, 16) };
-static struct ralink_pmx_func pci_func[] = { FUNC("pci", 0, 40, 32) };
+static struct ralink_pmx_func i2c_grp[] = { FUNC("i2c", 0, 1, 2) };
+static struct ralink_pmx_func spi_grp[] = { FUNC("spi", 0, 3, 4) };
+static struct ralink_pmx_func uartlite_grp[] = { FUNC("uartlite", 0, 7, 8) };
+static struct ralink_pmx_func jtag_grp[] = { FUNC("jtag", 0, 17, 5) };
+static struct ralink_pmx_func mdio_grp[] = { FUNC("mdio", 0, 22, 2) };
+static struct ralink_pmx_func sdram_grp[] = { FUNC("sdram", 0, 24, 16) };
+static struct ralink_pmx_func pci_grp[] = { FUNC("pci", 0, 40, 32) };
static struct ralink_pmx_group rt2880_pinmux_data_act[] = {
- GRP("i2c", i2c_func, 1, RT2880_GPIO_MODE_I2C),
- GRP("spi", spi_func, 1, RT2880_GPIO_MODE_SPI),
- GRP("uartlite", uartlite_func, 1, RT2880_GPIO_MODE_UART0),
- GRP("jtag", jtag_func, 1, RT2880_GPIO_MODE_JTAG),
- GRP("mdio", mdio_func, 1, RT2880_GPIO_MODE_MDIO),
- GRP("sdram", sdram_func, 1, RT2880_GPIO_MODE_SDRAM),
- GRP("pci", pci_func, 1, RT2880_GPIO_MODE_PCI),
+ GRP("i2c", i2c_grp, 1, RT2880_GPIO_MODE_I2C),
+ GRP("spi", spi_grp, 1, RT2880_GPIO_MODE_SPI),
+ GRP("uartlite", uartlite_grp, 1, RT2880_GPIO_MODE_UART0),
+ GRP("jtag", jtag_grp, 1, RT2880_GPIO_MODE_JTAG),
+ GRP("mdio", mdio_grp, 1, RT2880_GPIO_MODE_MDIO),
+ GRP("sdram", sdram_grp, 1, RT2880_GPIO_MODE_SDRAM),
+ GRP("pci", pci_grp, 1, RT2880_GPIO_MODE_PCI),
{ 0 }
};
diff --git a/drivers/pinctrl/ralink/pinctrl-rt305x.c b/drivers/pinctrl/ralink/pinctrl-rt305x.c
index 5b204b7ca1f3..bdaee5ce1ee0 100644
--- a/drivers/pinctrl/ralink/pinctrl-rt305x.c
+++ b/drivers/pinctrl/ralink/pinctrl-rt305x.c
@@ -31,9 +31,9 @@
#define RT3352_GPIO_MODE_LNA 18
#define RT3352_GPIO_MODE_PA 20
-static struct ralink_pmx_func i2c_func[] = { FUNC("i2c", 0, 1, 2) };
-static struct ralink_pmx_func spi_func[] = { FUNC("spi", 0, 3, 4) };
-static struct ralink_pmx_func uartf_func[] = {
+static struct ralink_pmx_func i2c_grp[] = { FUNC("i2c", 0, 1, 2) };
+static struct ralink_pmx_func spi_grp[] = { FUNC("spi", 0, 3, 4) };
+static struct ralink_pmx_func uartf_grp[] = {
FUNC("uartf", RT305X_GPIO_MODE_UARTF, 7, 8),
FUNC("pcm uartf", RT305X_GPIO_MODE_PCM_UARTF, 7, 8),
FUNC("pcm i2s", RT305X_GPIO_MODE_PCM_I2S, 7, 8),
@@ -42,65 +42,65 @@ static struct ralink_pmx_func uartf_func[] = {
FUNC("gpio uartf", RT305X_GPIO_MODE_GPIO_UARTF, 7, 4),
FUNC("gpio i2s", RT305X_GPIO_MODE_GPIO_I2S, 7, 4),
};
-static struct ralink_pmx_func uartlite_func[] = { FUNC("uartlite", 0, 15, 2) };
-static struct ralink_pmx_func jtag_func[] = { FUNC("jtag", 0, 17, 5) };
-static struct ralink_pmx_func mdio_func[] = { FUNC("mdio", 0, 22, 2) };
-static struct ralink_pmx_func rt5350_led_func[] = { FUNC("led", 0, 22, 5) };
-static struct ralink_pmx_func rt5350_cs1_func[] = {
+static struct ralink_pmx_func uartlite_grp[] = { FUNC("uartlite", 0, 15, 2) };
+static struct ralink_pmx_func jtag_grp[] = { FUNC("jtag", 0, 17, 5) };
+static struct ralink_pmx_func mdio_grp[] = { FUNC("mdio", 0, 22, 2) };
+static struct ralink_pmx_func rt5350_led_grp[] = { FUNC("led", 0, 22, 5) };
+static struct ralink_pmx_func rt5350_cs1_grp[] = {
FUNC("spi_cs1", 0, 27, 1),
FUNC("wdg_cs1", 1, 27, 1),
};
-static struct ralink_pmx_func sdram_func[] = { FUNC("sdram", 0, 24, 16) };
-static struct ralink_pmx_func rt3352_rgmii_func[] = {
+static struct ralink_pmx_func sdram_grp[] = { FUNC("sdram", 0, 24, 16) };
+static struct ralink_pmx_func rt3352_rgmii_grp[] = {
FUNC("rgmii", 0, 24, 12)
};
-static struct ralink_pmx_func rgmii_func[] = { FUNC("rgmii", 0, 40, 12) };
-static struct ralink_pmx_func rt3352_lna_func[] = { FUNC("lna", 0, 36, 2) };
-static struct ralink_pmx_func rt3352_pa_func[] = { FUNC("pa", 0, 38, 2) };
-static struct ralink_pmx_func rt3352_led_func[] = { FUNC("led", 0, 40, 5) };
-static struct ralink_pmx_func rt3352_cs1_func[] = {
+static struct ralink_pmx_func rgmii_grp[] = { FUNC("rgmii", 0, 40, 12) };
+static struct ralink_pmx_func rt3352_lna_grp[] = { FUNC("lna", 0, 36, 2) };
+static struct ralink_pmx_func rt3352_pa_grp[] = { FUNC("pa", 0, 38, 2) };
+static struct ralink_pmx_func rt3352_led_grp[] = { FUNC("led", 0, 40, 5) };
+static struct ralink_pmx_func rt3352_cs1_grp[] = {
FUNC("spi_cs1", 0, 45, 1),
FUNC("wdg_cs1", 1, 45, 1),
};
static struct ralink_pmx_group rt3050_pinmux_data[] = {
- GRP("i2c", i2c_func, 1, RT305X_GPIO_MODE_I2C),
- GRP("spi", spi_func, 1, RT305X_GPIO_MODE_SPI),
- GRP("uartf", uartf_func, RT305X_GPIO_MODE_UART0_MASK,
+ GRP("i2c", i2c_grp, 1, RT305X_GPIO_MODE_I2C),
+ GRP("spi", spi_grp, 1, RT305X_GPIO_MODE_SPI),
+ GRP("uartf", uartf_grp, RT305X_GPIO_MODE_UART0_MASK,
RT305X_GPIO_MODE_UART0_SHIFT),
- GRP("uartlite", uartlite_func, 1, RT305X_GPIO_MODE_UART1),
- GRP("jtag", jtag_func, 1, RT305X_GPIO_MODE_JTAG),
- GRP("mdio", mdio_func, 1, RT305X_GPIO_MODE_MDIO),
- GRP("rgmii", rgmii_func, 1, RT305X_GPIO_MODE_RGMII),
- GRP("sdram", sdram_func, 1, RT305X_GPIO_MODE_SDRAM),
+ GRP("uartlite", uartlite_grp, 1, RT305X_GPIO_MODE_UART1),
+ GRP("jtag", jtag_grp, 1, RT305X_GPIO_MODE_JTAG),
+ GRP("mdio", mdio_grp, 1, RT305X_GPIO_MODE_MDIO),
+ GRP("rgmii", rgmii_grp, 1, RT305X_GPIO_MODE_RGMII),
+ GRP("sdram", sdram_grp, 1, RT305X_GPIO_MODE_SDRAM),
{ 0 }
};
static struct ralink_pmx_group rt3352_pinmux_data[] = {
- GRP("i2c", i2c_func, 1, RT305X_GPIO_MODE_I2C),
- GRP("spi", spi_func, 1, RT305X_GPIO_MODE_SPI),
- GRP("uartf", uartf_func, RT305X_GPIO_MODE_UART0_MASK,
+ GRP("i2c", i2c_grp, 1, RT305X_GPIO_MODE_I2C),
+ GRP("spi", spi_grp, 1, RT305X_GPIO_MODE_SPI),
+ GRP("uartf", uartf_grp, RT305X_GPIO_MODE_UART0_MASK,
RT305X_GPIO_MODE_UART0_SHIFT),
- GRP("uartlite", uartlite_func, 1, RT305X_GPIO_MODE_UART1),
- GRP("jtag", jtag_func, 1, RT305X_GPIO_MODE_JTAG),
- GRP("mdio", mdio_func, 1, RT305X_GPIO_MODE_MDIO),
- GRP("rgmii", rt3352_rgmii_func, 1, RT305X_GPIO_MODE_RGMII),
- GRP("lna", rt3352_lna_func, 1, RT3352_GPIO_MODE_LNA),
- GRP("pa", rt3352_pa_func, 1, RT3352_GPIO_MODE_PA),
- GRP("led", rt3352_led_func, 1, RT5350_GPIO_MODE_PHY_LED),
- GRP("spi_cs1", rt3352_cs1_func, 2, RT5350_GPIO_MODE_SPI_CS1),
+ GRP("uartlite", uartlite_grp, 1, RT305X_GPIO_MODE_UART1),
+ GRP("jtag", jtag_grp, 1, RT305X_GPIO_MODE_JTAG),
+ GRP("mdio", mdio_grp, 1, RT305X_GPIO_MODE_MDIO),
+ GRP("rgmii", rt3352_rgmii_grp, 1, RT305X_GPIO_MODE_RGMII),
+ GRP("lna", rt3352_lna_grp, 1, RT3352_GPIO_MODE_LNA),
+ GRP("pa", rt3352_pa_grp, 1, RT3352_GPIO_MODE_PA),
+ GRP("led", rt3352_led_grp, 1, RT5350_GPIO_MODE_PHY_LED),
+ GRP("spi_cs1", rt3352_cs1_grp, 2, RT5350_GPIO_MODE_SPI_CS1),
{ 0 }
};
static struct ralink_pmx_group rt5350_pinmux_data[] = {
- GRP("i2c", i2c_func, 1, RT305X_GPIO_MODE_I2C),
- GRP("spi", spi_func, 1, RT305X_GPIO_MODE_SPI),
- GRP("uartf", uartf_func, RT305X_GPIO_MODE_UART0_MASK,
+ GRP("i2c", i2c_grp, 1, RT305X_GPIO_MODE_I2C),
+ GRP("spi", spi_grp, 1, RT305X_GPIO_MODE_SPI),
+ GRP("uartf", uartf_grp, RT305X_GPIO_MODE_UART0_MASK,
RT305X_GPIO_MODE_UART0_SHIFT),
- GRP("uartlite", uartlite_func, 1, RT305X_GPIO_MODE_UART1),
- GRP("jtag", jtag_func, 1, RT305X_GPIO_MODE_JTAG),
- GRP("led", rt5350_led_func, 1, RT5350_GPIO_MODE_PHY_LED),
- GRP("spi_cs1", rt5350_cs1_func, 2, RT5350_GPIO_MODE_SPI_CS1),
+ GRP("uartlite", uartlite_grp, 1, RT305X_GPIO_MODE_UART1),
+ GRP("jtag", jtag_grp, 1, RT305X_GPIO_MODE_JTAG),
+ GRP("led", rt5350_led_grp, 1, RT5350_GPIO_MODE_PHY_LED),
+ GRP("spi_cs1", rt5350_cs1_grp, 2, RT5350_GPIO_MODE_SPI_CS1),
{ 0 }
};
diff --git a/drivers/pinctrl/ralink/pinctrl-rt3883.c b/drivers/pinctrl/ralink/pinctrl-rt3883.c
index 44a66c3d2d2a..392208662355 100644
--- a/drivers/pinctrl/ralink/pinctrl-rt3883.c
+++ b/drivers/pinctrl/ralink/pinctrl-rt3883.c
@@ -39,9 +39,9 @@
#define RT3883_GPIO_MODE_LNA_G_GPIO 0x3
#define RT3883_GPIO_MODE_LNA_G _RT3883_GPIO_MODE_LNA_G(RT3883_GPIO_MODE_LNA_G_MASK)
-static struct ralink_pmx_func i2c_func[] = { FUNC("i2c", 0, 1, 2) };
-static struct ralink_pmx_func spi_func[] = { FUNC("spi", 0, 3, 4) };
-static struct ralink_pmx_func uartf_func[] = {
+static struct ralink_pmx_func i2c_grp[] = { FUNC("i2c", 0, 1, 2) };
+static struct ralink_pmx_func spi_grp[] = { FUNC("spi", 0, 3, 4) };
+static struct ralink_pmx_func uartf_grp[] = {
FUNC("uartf", RT3883_GPIO_MODE_UARTF, 7, 8),
FUNC("pcm uartf", RT3883_GPIO_MODE_PCM_UARTF, 7, 8),
FUNC("pcm i2s", RT3883_GPIO_MODE_PCM_I2S, 7, 8),
@@ -50,34 +50,34 @@ static struct ralink_pmx_func uartf_func[] = {
FUNC("gpio uartf", RT3883_GPIO_MODE_GPIO_UARTF, 7, 4),
FUNC("gpio i2s", RT3883_GPIO_MODE_GPIO_I2S, 7, 4),
};
-static struct ralink_pmx_func uartlite_func[] = { FUNC("uartlite", 0, 15, 2) };
-static struct ralink_pmx_func jtag_func[] = { FUNC("jtag", 0, 17, 5) };
-static struct ralink_pmx_func mdio_func[] = { FUNC("mdio", 0, 22, 2) };
-static struct ralink_pmx_func lna_a_func[] = { FUNC("lna a", 0, 32, 3) };
-static struct ralink_pmx_func lna_g_func[] = { FUNC("lna g", 0, 35, 3) };
-static struct ralink_pmx_func pci_func[] = {
+static struct ralink_pmx_func uartlite_grp[] = { FUNC("uartlite", 0, 15, 2) };
+static struct ralink_pmx_func jtag_grp[] = { FUNC("jtag", 0, 17, 5) };
+static struct ralink_pmx_func mdio_grp[] = { FUNC("mdio", 0, 22, 2) };
+static struct ralink_pmx_func lna_a_grp[] = { FUNC("lna a", 0, 32, 3) };
+static struct ralink_pmx_func lna_g_grp[] = { FUNC("lna g", 0, 35, 3) };
+static struct ralink_pmx_func pci_grp[] = {
FUNC("pci-dev", 0, 40, 32),
FUNC("pci-host2", 1, 40, 32),
FUNC("pci-host1", 2, 40, 32),
FUNC("pci-fnc", 3, 40, 32)
};
-static struct ralink_pmx_func ge1_func[] = { FUNC("ge1", 0, 72, 12) };
-static struct ralink_pmx_func ge2_func[] = { FUNC("ge2", 0, 84, 12) };
+static struct ralink_pmx_func ge1_grp[] = { FUNC("ge1", 0, 72, 12) };
+static struct ralink_pmx_func ge2_grp[] = { FUNC("ge2", 0, 84, 12) };
static struct ralink_pmx_group rt3883_pinmux_data[] = {
- GRP("i2c", i2c_func, 1, RT3883_GPIO_MODE_I2C),
- GRP("spi", spi_func, 1, RT3883_GPIO_MODE_SPI),
- GRP("uartf", uartf_func, RT3883_GPIO_MODE_UART0_MASK,
+ GRP("i2c", i2c_grp, 1, RT3883_GPIO_MODE_I2C),
+ GRP("spi", spi_grp, 1, RT3883_GPIO_MODE_SPI),
+ GRP("uartf", uartf_grp, RT3883_GPIO_MODE_UART0_MASK,
RT3883_GPIO_MODE_UART0_SHIFT),
- GRP("uartlite", uartlite_func, 1, RT3883_GPIO_MODE_UART1),
- GRP("jtag", jtag_func, 1, RT3883_GPIO_MODE_JTAG),
- GRP("mdio", mdio_func, 1, RT3883_GPIO_MODE_MDIO),
- GRP("lna a", lna_a_func, 1, RT3883_GPIO_MODE_LNA_A),
- GRP("lna g", lna_g_func, 1, RT3883_GPIO_MODE_LNA_G),
- GRP("pci", pci_func, RT3883_GPIO_MODE_PCI_MASK,
+ GRP("uartlite", uartlite_grp, 1, RT3883_GPIO_MODE_UART1),
+ GRP("jtag", jtag_grp, 1, RT3883_GPIO_MODE_JTAG),
+ GRP("mdio", mdio_grp, 1, RT3883_GPIO_MODE_MDIO),
+ GRP("lna a", lna_a_grp, 1, RT3883_GPIO_MODE_LNA_A),
+ GRP("lna g", lna_g_grp, 1, RT3883_GPIO_MODE_LNA_G),
+ GRP("pci", pci_grp, RT3883_GPIO_MODE_PCI_MASK,
RT3883_GPIO_MODE_PCI_SHIFT),
- GRP("ge1", ge1_func, 1, RT3883_GPIO_MODE_GE1),
- GRP("ge2", ge2_func, 1, RT3883_GPIO_MODE_GE2),
+ GRP("ge1", ge1_grp, 1, RT3883_GPIO_MODE_GE1),
+ GRP("ge2", ge2_grp, 1, RT3883_GPIO_MODE_GE2),
{ 0 }
};
diff --git a/drivers/pinctrl/renesas/pfc-r8a77950.c b/drivers/pinctrl/renesas/pfc-r8a77950.c
index 4c543ec3a863..cc66c6de045c 100644
--- a/drivers/pinctrl/renesas/pfc-r8a77950.c
+++ b/drivers/pinctrl/renesas/pfc-r8a77950.c
@@ -3820,6 +3820,186 @@ static const unsigned int usb31_mux[] = {
USB31_PWEN_MARK, USB31_OVC_MARK,
};
+/* - VIN4 ------------------------------------------------------------------- */
+static const unsigned int vin4_data18_a_pins[] = {
+ RCAR_GP_PIN(0, 10), RCAR_GP_PIN(0, 11),
+ RCAR_GP_PIN(0, 12), RCAR_GP_PIN(0, 13),
+ RCAR_GP_PIN(0, 14), RCAR_GP_PIN(0, 15),
+ RCAR_GP_PIN(1, 2), RCAR_GP_PIN(1, 3),
+ RCAR_GP_PIN(1, 4), RCAR_GP_PIN(1, 5),
+ RCAR_GP_PIN(1, 6), RCAR_GP_PIN(1, 7),
+ RCAR_GP_PIN(0, 2), RCAR_GP_PIN(0, 3),
+ RCAR_GP_PIN(0, 4), RCAR_GP_PIN(0, 5),
+ RCAR_GP_PIN(0, 6), RCAR_GP_PIN(0, 7),
+};
+static const unsigned int vin4_data18_a_mux[] = {
+ VI4_DATA2_A_MARK, VI4_DATA3_A_MARK,
+ VI4_DATA4_A_MARK, VI4_DATA5_A_MARK,
+ VI4_DATA6_A_MARK, VI4_DATA7_A_MARK,
+ VI4_DATA10_MARK, VI4_DATA11_MARK,
+ VI4_DATA12_MARK, VI4_DATA13_MARK,
+ VI4_DATA14_MARK, VI4_DATA15_MARK,
+ VI4_DATA18_MARK, VI4_DATA19_MARK,
+ VI4_DATA20_MARK, VI4_DATA21_MARK,
+ VI4_DATA22_MARK, VI4_DATA23_MARK,
+};
+static const unsigned int vin4_data18_b_pins[] = {
+ RCAR_GP_PIN(2, 2), RCAR_GP_PIN(2, 3),
+ RCAR_GP_PIN(2, 4), RCAR_GP_PIN(2, 5),
+ RCAR_GP_PIN(2, 6), RCAR_GP_PIN(2, 7),
+ RCAR_GP_PIN(1, 2), RCAR_GP_PIN(1, 3),
+ RCAR_GP_PIN(1, 4), RCAR_GP_PIN(1, 5),
+ RCAR_GP_PIN(1, 6), RCAR_GP_PIN(1, 7),
+ RCAR_GP_PIN(0, 2), RCAR_GP_PIN(0, 3),
+ RCAR_GP_PIN(0, 4), RCAR_GP_PIN(0, 5),
+ RCAR_GP_PIN(0, 6), RCAR_GP_PIN(0, 7),
+};
+static const unsigned int vin4_data18_b_mux[] = {
+ VI4_DATA2_B_MARK, VI4_DATA3_B_MARK,
+ VI4_DATA4_B_MARK, VI4_DATA5_B_MARK,
+ VI4_DATA6_B_MARK, VI4_DATA7_B_MARK,
+ VI4_DATA10_MARK, VI4_DATA11_MARK,
+ VI4_DATA12_MARK, VI4_DATA13_MARK,
+ VI4_DATA14_MARK, VI4_DATA15_MARK,
+ VI4_DATA18_MARK, VI4_DATA19_MARK,
+ VI4_DATA20_MARK, VI4_DATA21_MARK,
+ VI4_DATA22_MARK, VI4_DATA23_MARK,
+};
+static const unsigned int vin4_data_a_pins[] = {
+ RCAR_GP_PIN(0, 8), RCAR_GP_PIN(0, 9),
+ RCAR_GP_PIN(0, 10), RCAR_GP_PIN(0, 11),
+ RCAR_GP_PIN(0, 12), RCAR_GP_PIN(0, 13),
+ RCAR_GP_PIN(0, 14), RCAR_GP_PIN(0, 15),
+ RCAR_GP_PIN(1, 0), RCAR_GP_PIN(1, 1),
+ RCAR_GP_PIN(1, 2), RCAR_GP_PIN(1, 3),
+ RCAR_GP_PIN(1, 4), RCAR_GP_PIN(1, 5),
+ RCAR_GP_PIN(1, 6), RCAR_GP_PIN(1, 7),
+ RCAR_GP_PIN(0, 0), RCAR_GP_PIN(0, 1),
+ RCAR_GP_PIN(0, 2), RCAR_GP_PIN(0, 3),
+ RCAR_GP_PIN(0, 4), RCAR_GP_PIN(0, 5),
+ RCAR_GP_PIN(0, 6), RCAR_GP_PIN(0, 7),
+};
+static const unsigned int vin4_data_a_mux[] = {
+ VI4_DATA0_A_MARK, VI4_DATA1_A_MARK,
+ VI4_DATA2_A_MARK, VI4_DATA3_A_MARK,
+ VI4_DATA4_A_MARK, VI4_DATA5_A_MARK,
+ VI4_DATA6_A_MARK, VI4_DATA7_A_MARK,
+ VI4_DATA8_MARK, VI4_DATA9_MARK,
+ VI4_DATA10_MARK, VI4_DATA11_MARK,
+ VI4_DATA12_MARK, VI4_DATA13_MARK,
+ VI4_DATA14_MARK, VI4_DATA15_MARK,
+ VI4_DATA16_MARK, VI4_DATA17_MARK,
+ VI4_DATA18_MARK, VI4_DATA19_MARK,
+ VI4_DATA20_MARK, VI4_DATA21_MARK,
+ VI4_DATA22_MARK, VI4_DATA23_MARK,
+};
+static const unsigned int vin4_data_b_pins[] = {
+ RCAR_GP_PIN(2, 0), RCAR_GP_PIN(2, 1),
+ RCAR_GP_PIN(2, 2), RCAR_GP_PIN(2, 3),
+ RCAR_GP_PIN(2, 4), RCAR_GP_PIN(2, 5),
+ RCAR_GP_PIN(2, 6), RCAR_GP_PIN(2, 7),
+ RCAR_GP_PIN(1, 0), RCAR_GP_PIN(1, 1),
+ RCAR_GP_PIN(1, 2), RCAR_GP_PIN(1, 3),
+ RCAR_GP_PIN(1, 4), RCAR_GP_PIN(1, 5),
+ RCAR_GP_PIN(1, 6), RCAR_GP_PIN(1, 7),
+ RCAR_GP_PIN(0, 0), RCAR_GP_PIN(0, 1),
+ RCAR_GP_PIN(0, 2), RCAR_GP_PIN(0, 3),
+ RCAR_GP_PIN(0, 4), RCAR_GP_PIN(0, 5),
+ RCAR_GP_PIN(0, 6), RCAR_GP_PIN(0, 7),
+};
+static const unsigned int vin4_data_b_mux[] = {
+ VI4_DATA0_B_MARK, VI4_DATA1_B_MARK,
+ VI4_DATA2_B_MARK, VI4_DATA3_B_MARK,
+ VI4_DATA4_B_MARK, VI4_DATA5_B_MARK,
+ VI4_DATA6_B_MARK, VI4_DATA7_B_MARK,
+ VI4_DATA8_MARK, VI4_DATA9_MARK,
+ VI4_DATA10_MARK, VI4_DATA11_MARK,
+ VI4_DATA12_MARK, VI4_DATA13_MARK,
+ VI4_DATA14_MARK, VI4_DATA15_MARK,
+ VI4_DATA16_MARK, VI4_DATA17_MARK,
+ VI4_DATA18_MARK, VI4_DATA19_MARK,
+ VI4_DATA20_MARK, VI4_DATA21_MARK,
+ VI4_DATA22_MARK, VI4_DATA23_MARK,
+};
+static const unsigned int vin4_sync_pins[] = {
+ /* HSYNC#, VSYNC# */
+ RCAR_GP_PIN(1, 18), RCAR_GP_PIN(1, 17),
+};
+static const unsigned int vin4_sync_mux[] = {
+ VI4_HSYNC_N_MARK, VI4_VSYNC_N_MARK,
+};
+static const unsigned int vin4_field_pins[] = {
+ /* FIELD */
+ RCAR_GP_PIN(1, 16),
+};
+static const unsigned int vin4_field_mux[] = {
+ VI4_FIELD_MARK,
+};
+static const unsigned int vin4_clkenb_pins[] = {
+ /* CLKENB */
+ RCAR_GP_PIN(1, 19),
+};
+static const unsigned int vin4_clkenb_mux[] = {
+ VI4_CLKENB_MARK,
+};
+static const unsigned int vin4_clk_pins[] = {
+ /* CLK */
+ RCAR_GP_PIN(1, 27),
+};
+static const unsigned int vin4_clk_mux[] = {
+ VI4_CLK_MARK,
+};
+
+/* - VIN5 ------------------------------------------------------------------- */
+static const unsigned int vin5_data_pins[] = {
+ RCAR_GP_PIN(0, 0), RCAR_GP_PIN(0, 1),
+ RCAR_GP_PIN(0, 2), RCAR_GP_PIN(0, 3),
+ RCAR_GP_PIN(0, 4), RCAR_GP_PIN(0, 5),
+ RCAR_GP_PIN(0, 6), RCAR_GP_PIN(0, 7),
+ RCAR_GP_PIN(1, 12), RCAR_GP_PIN(1, 13),
+ RCAR_GP_PIN(1, 14), RCAR_GP_PIN(1, 15),
+ RCAR_GP_PIN(1, 4), RCAR_GP_PIN(1, 5),
+ RCAR_GP_PIN(1, 6), RCAR_GP_PIN(1, 7),
+};
+static const unsigned int vin5_data_mux[] = {
+ VI5_DATA0_MARK, VI5_DATA1_MARK,
+ VI5_DATA2_MARK, VI5_DATA3_MARK,
+ VI5_DATA4_MARK, VI5_DATA5_MARK,
+ VI5_DATA6_MARK, VI5_DATA7_MARK,
+ VI5_DATA8_MARK, VI5_DATA9_MARK,
+ VI5_DATA10_MARK, VI5_DATA11_MARK,
+ VI5_DATA12_MARK, VI5_DATA13_MARK,
+ VI5_DATA14_MARK, VI5_DATA15_MARK,
+};
+static const unsigned int vin5_sync_pins[] = {
+ /* HSYNC#, VSYNC# */
+ RCAR_GP_PIN(1, 10), RCAR_GP_PIN(1, 9),
+};
+static const unsigned int vin5_sync_mux[] = {
+ VI5_HSYNC_N_MARK, VI5_VSYNC_N_MARK,
+};
+static const unsigned int vin5_field_pins[] = {
+ RCAR_GP_PIN(1, 11),
+};
+static const unsigned int vin5_field_mux[] = {
+ /* FIELD */
+ VI5_FIELD_MARK,
+};
+static const unsigned int vin5_clkenb_pins[] = {
+ RCAR_GP_PIN(1, 20),
+};
+static const unsigned int vin5_clkenb_mux[] = {
+ /* CLKENB */
+ VI5_CLKENB_MARK,
+};
+static const unsigned int vin5_clk_pins[] = {
+ RCAR_GP_PIN(1, 21),
+};
+static const unsigned int vin5_clk_mux[] = {
+ /* CLK */
+ VI5_CLK_MARK,
+};
+
static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(audio_clk_a_a),
SH_PFC_PIN_GROUP(audio_clk_a_b),
@@ -4141,6 +4321,34 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(usb2),
SH_PFC_PIN_GROUP(usb30),
SH_PFC_PIN_GROUP(usb31),
+ BUS_DATA_PIN_GROUP(vin4_data, 8, _a),
+ BUS_DATA_PIN_GROUP(vin4_data, 10, _a),
+ BUS_DATA_PIN_GROUP(vin4_data, 12, _a),
+ BUS_DATA_PIN_GROUP(vin4_data, 16, _a),
+ SH_PFC_PIN_GROUP(vin4_data18_a),
+ BUS_DATA_PIN_GROUP(vin4_data, 20, _a),
+ BUS_DATA_PIN_GROUP(vin4_data, 24, _a),
+ BUS_DATA_PIN_GROUP(vin4_data, 8, _b),
+ BUS_DATA_PIN_GROUP(vin4_data, 10, _b),
+ BUS_DATA_PIN_GROUP(vin4_data, 12, _b),
+ BUS_DATA_PIN_GROUP(vin4_data, 16, _b),
+ SH_PFC_PIN_GROUP(vin4_data18_b),
+ BUS_DATA_PIN_GROUP(vin4_data, 20, _b),
+ BUS_DATA_PIN_GROUP(vin4_data, 24, _b),
+ SH_PFC_PIN_GROUP_SUBSET(vin4_g8, vin4_data_a, 8, 8),
+ SH_PFC_PIN_GROUP(vin4_sync),
+ SH_PFC_PIN_GROUP(vin4_field),
+ SH_PFC_PIN_GROUP(vin4_clkenb),
+ SH_PFC_PIN_GROUP(vin4_clk),
+ BUS_DATA_PIN_GROUP(vin5_data, 8),
+ BUS_DATA_PIN_GROUP(vin5_data, 10),
+ BUS_DATA_PIN_GROUP(vin5_data, 12),
+ BUS_DATA_PIN_GROUP(vin5_data, 16),
+ SH_PFC_PIN_GROUP_SUBSET(vin5_high8, vin5_data, 8, 8),
+ SH_PFC_PIN_GROUP(vin5_sync),
+ SH_PFC_PIN_GROUP(vin5_field),
+ SH_PFC_PIN_GROUP(vin5_clkenb),
+ SH_PFC_PIN_GROUP(vin5_clk),
};
static const char * const audio_clk_groups[] = {
@@ -4637,6 +4845,40 @@ static const char * const usb31_groups[] = {
"usb31",
};
+static const char * const vin4_groups[] = {
+ "vin4_data8_a",
+ "vin4_data10_a",
+ "vin4_data12_a",
+ "vin4_data16_a",
+ "vin4_data18_a",
+ "vin4_data20_a",
+ "vin4_data24_a",
+ "vin4_data8_b",
+ "vin4_data10_b",
+ "vin4_data12_b",
+ "vin4_data16_b",
+ "vin4_data18_b",
+ "vin4_data20_b",
+ "vin4_data24_b",
+ "vin4_g8",
+ "vin4_sync",
+ "vin4_field",
+ "vin4_clkenb",
+ "vin4_clk",
+};
+
+static const char * const vin5_groups[] = {
+ "vin5_data8",
+ "vin5_data10",
+ "vin5_data12",
+ "vin5_data16",
+ "vin5_high8",
+ "vin5_sync",
+ "vin5_field",
+ "vin5_clkenb",
+ "vin5_clk",
+};
+
static const struct sh_pfc_function pinmux_functions[] = {
SH_PFC_FUNCTION(audio_clk),
SH_PFC_FUNCTION(avb),
@@ -4696,6 +4938,8 @@ static const struct sh_pfc_function pinmux_functions[] = {
SH_PFC_FUNCTION(usb2),
SH_PFC_FUNCTION(usb30),
SH_PFC_FUNCTION(usb31),
+ SH_PFC_FUNCTION(vin4),
+ SH_PFC_FUNCTION(vin5),
};
static const struct pinmux_cfg_reg pinmux_config_regs[] = {
diff --git a/drivers/pinctrl/renesas/pfc-r8a779g0.c b/drivers/pinctrl/renesas/pfc-r8a779g0.c
index 5dd1c2c7708a..bf7fcce2d9c6 100644
--- a/drivers/pinctrl/renesas/pfc-r8a779g0.c
+++ b/drivers/pinctrl/renesas/pfc-r8a779g0.c
@@ -206,66 +206,66 @@
#define GPSR5_0 FM(AVB2_AVTP_PPS)
/* GPSR 6 */
-#define GPSR6_20 F_(AVB1_TXCREFCLK, IP2SR6_19_16)
-#define GPSR6_19 F_(AVB1_RD3, IP2SR6_15_12)
-#define GPSR6_18 F_(AVB1_TD3, IP2SR6_11_8)
-#define GPSR6_17 F_(AVB1_RD2, IP2SR6_7_4)
-#define GPSR6_16 F_(AVB1_TD2, IP2SR6_3_0)
-#define GPSR6_15 F_(AVB1_RD0, IP1SR6_31_28)
-#define GPSR6_14 F_(AVB1_RD1, IP1SR6_27_24)
-#define GPSR6_13 F_(AVB1_TD0, IP1SR6_23_20)
-#define GPSR6_12 F_(AVB1_TD1, IP1SR6_19_16)
-#define GPSR6_11 F_(AVB1_AVTP_CAPTURE, IP1SR6_15_12)
-#define GPSR6_10 F_(AVB1_AVTP_PPS, IP1SR6_11_8)
-#define GPSR6_9 F_(AVB1_RX_CTL, IP1SR6_7_4)
-#define GPSR6_8 F_(AVB1_RXC, IP1SR6_3_0)
-#define GPSR6_7 F_(AVB1_TX_CTL, IP0SR6_31_28)
-#define GPSR6_6 F_(AVB1_TXC, IP0SR6_27_24)
-#define GPSR6_5 F_(AVB1_AVTP_MATCH, IP0SR6_23_20)
-#define GPSR6_4 F_(AVB1_LINK, IP0SR6_19_16)
-#define GPSR6_3 F_(AVB1_PHY_INT, IP0SR6_15_12)
-#define GPSR6_2 F_(AVB1_MDC, IP0SR6_11_8)
-#define GPSR6_1 F_(AVB1_MAGIC, IP0SR6_7_4)
-#define GPSR6_0 F_(AVB1_MDIO, IP0SR6_3_0)
+#define GPSR6_20 F_(AVB1_TXCREFCLK, IP2SR6_19_16)
+#define GPSR6_19 F_(AVB1_RD3, IP2SR6_15_12)
+#define GPSR6_18 F_(AVB1_TD3, IP2SR6_11_8)
+#define GPSR6_17 F_(AVB1_RD2, IP2SR6_7_4)
+#define GPSR6_16 F_(AVB1_TD2, IP2SR6_3_0)
+#define GPSR6_15 F_(AVB1_RD0, IP1SR6_31_28)
+#define GPSR6_14 F_(AVB1_RD1, IP1SR6_27_24)
+#define GPSR6_13 F_(AVB1_TD0, IP1SR6_23_20)
+#define GPSR6_12 F_(AVB1_TD1, IP1SR6_19_16)
+#define GPSR6_11 F_(AVB1_AVTP_CAPTURE, IP1SR6_15_12)
+#define GPSR6_10 F_(AVB1_AVTP_PPS, IP1SR6_11_8)
+#define GPSR6_9 F_(AVB1_RX_CTL, IP1SR6_7_4)
+#define GPSR6_8 F_(AVB1_RXC, IP1SR6_3_0)
+#define GPSR6_7 F_(AVB1_TX_CTL, IP0SR6_31_28)
+#define GPSR6_6 F_(AVB1_TXC, IP0SR6_27_24)
+#define GPSR6_5 F_(AVB1_AVTP_MATCH, IP0SR6_23_20)
+#define GPSR6_4 F_(AVB1_LINK, IP0SR6_19_16)
+#define GPSR6_3 F_(AVB1_PHY_INT, IP0SR6_15_12)
+#define GPSR6_2 F_(AVB1_MDC, IP0SR6_11_8)
+#define GPSR6_1 F_(AVB1_MAGIC, IP0SR6_7_4)
+#define GPSR6_0 F_(AVB1_MDIO, IP0SR6_3_0)
/* GPSR7 */
-#define GPSR7_20 F_(AVB0_RX_CTL, IP2SR7_19_16)
-#define GPSR7_19 F_(AVB0_RXC, IP2SR7_15_12)
-#define GPSR7_18 F_(AVB0_RD0, IP2SR7_11_8)
-#define GPSR7_17 F_(AVB0_RD1, IP2SR7_7_4)
-#define GPSR7_16 F_(AVB0_TX_CTL, IP2SR7_3_0)
-#define GPSR7_15 F_(AVB0_TXC, IP1SR7_31_28)
-#define GPSR7_14 F_(AVB0_MDIO, IP1SR7_27_24)
-#define GPSR7_13 F_(AVB0_MDC, IP1SR7_23_20)
-#define GPSR7_12 F_(AVB0_RD2, IP1SR7_19_16)
-#define GPSR7_11 F_(AVB0_TD0, IP1SR7_15_12)
-#define GPSR7_10 F_(AVB0_MAGIC, IP1SR7_11_8)
-#define GPSR7_9 F_(AVB0_TXCREFCLK, IP1SR7_7_4)
-#define GPSR7_8 F_(AVB0_RD3, IP1SR7_3_0)
-#define GPSR7_7 F_(AVB0_TD1, IP0SR7_31_28)
-#define GPSR7_6 F_(AVB0_TD2, IP0SR7_27_24)
-#define GPSR7_5 F_(AVB0_PHY_INT, IP0SR7_23_20)
-#define GPSR7_4 F_(AVB0_LINK, IP0SR7_19_16)
-#define GPSR7_3 F_(AVB0_TD3, IP0SR7_15_12)
-#define GPSR7_2 F_(AVB0_AVTP_MATCH, IP0SR7_11_8)
-#define GPSR7_1 F_(AVB0_AVTP_CAPTURE, IP0SR7_7_4)
-#define GPSR7_0 F_(AVB0_AVTP_PPS, IP0SR7_3_0)
+#define GPSR7_20 F_(AVB0_RX_CTL, IP2SR7_19_16)
+#define GPSR7_19 F_(AVB0_RXC, IP2SR7_15_12)
+#define GPSR7_18 F_(AVB0_RD0, IP2SR7_11_8)
+#define GPSR7_17 F_(AVB0_RD1, IP2SR7_7_4)
+#define GPSR7_16 F_(AVB0_TX_CTL, IP2SR7_3_0)
+#define GPSR7_15 F_(AVB0_TXC, IP1SR7_31_28)
+#define GPSR7_14 F_(AVB0_MDIO, IP1SR7_27_24)
+#define GPSR7_13 F_(AVB0_MDC, IP1SR7_23_20)
+#define GPSR7_12 F_(AVB0_RD2, IP1SR7_19_16)
+#define GPSR7_11 F_(AVB0_TD0, IP1SR7_15_12)
+#define GPSR7_10 F_(AVB0_MAGIC, IP1SR7_11_8)
+#define GPSR7_9 F_(AVB0_TXCREFCLK, IP1SR7_7_4)
+#define GPSR7_8 F_(AVB0_RD3, IP1SR7_3_0)
+#define GPSR7_7 F_(AVB0_TD1, IP0SR7_31_28)
+#define GPSR7_6 F_(AVB0_TD2, IP0SR7_27_24)
+#define GPSR7_5 F_(AVB0_PHY_INT, IP0SR7_23_20)
+#define GPSR7_4 F_(AVB0_LINK, IP0SR7_19_16)
+#define GPSR7_3 F_(AVB0_TD3, IP0SR7_15_12)
+#define GPSR7_2 F_(AVB0_AVTP_MATCH, IP0SR7_11_8)
+#define GPSR7_1 F_(AVB0_AVTP_CAPTURE, IP0SR7_7_4)
+#define GPSR7_0 F_(AVB0_AVTP_PPS, IP0SR7_3_0)
/* GPSR8 */
-#define GPSR8_13 F_(GP8_13, IP1SR8_23_20)
-#define GPSR8_12 F_(GP8_12, IP1SR8_19_16)
-#define GPSR8_11 F_(SDA5, IP1SR8_15_12)
-#define GPSR8_10 F_(SCL5, IP1SR8_11_8)
-#define GPSR8_9 F_(SDA4, IP1SR8_7_4)
-#define GPSR8_8 F_(SCL4, IP1SR8_3_0)
-#define GPSR8_7 F_(SDA3, IP0SR8_31_28)
-#define GPSR8_6 F_(SCL3, IP0SR8_27_24)
-#define GPSR8_5 F_(SDA2, IP0SR8_23_20)
-#define GPSR8_4 F_(SCL2, IP0SR8_19_16)
-#define GPSR8_3 F_(SDA1, IP0SR8_15_12)
-#define GPSR8_2 F_(SCL1, IP0SR8_11_8)
-#define GPSR8_1 F_(SDA0, IP0SR8_7_4)
-#define GPSR8_0 F_(SCL0, IP0SR8_3_0)
+#define GPSR8_13 F_(GP8_13, IP1SR8_23_20)
+#define GPSR8_12 F_(GP8_12, IP1SR8_19_16)
+#define GPSR8_11 F_(SDA5, IP1SR8_15_12)
+#define GPSR8_10 F_(SCL5, IP1SR8_11_8)
+#define GPSR8_9 F_(SDA4, IP1SR8_7_4)
+#define GPSR8_8 F_(SCL4, IP1SR8_3_0)
+#define GPSR8_7 F_(SDA3, IP0SR8_31_28)
+#define GPSR8_6 F_(SCL3, IP0SR8_27_24)
+#define GPSR8_5 F_(SDA2, IP0SR8_23_20)
+#define GPSR8_4 F_(SCL2, IP0SR8_19_16)
+#define GPSR8_3 F_(SDA1, IP0SR8_15_12)
+#define GPSR8_2 F_(SCL1, IP0SR8_11_8)
+#define GPSR8_1 F_(SDA0, IP0SR8_7_4)
+#define GPSR8_0 F_(SCL0, IP0SR8_3_0)
/* SR0 */
/* IP0SR0 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */
diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c
index 5aa3836dbc22..04b31f0c6b34 100644
--- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c
+++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c
@@ -130,6 +130,7 @@ struct rzg2l_dedicated_configs {
struct rzg2l_pinctrl_data {
const char * const *port_pins;
const u32 *port_pin_configs;
+ unsigned int n_ports;
struct rzg2l_dedicated_configs *dedicated_pins;
unsigned int n_port_pins;
unsigned int n_dedicated_pins;
@@ -1124,7 +1125,7 @@ static struct {
}
};
-static int rzg2l_gpio_get_gpioint(unsigned int virq)
+static int rzg2l_gpio_get_gpioint(unsigned int virq, const struct rzg2l_pinctrl_data *data)
{
unsigned int gpioint;
unsigned int i;
@@ -1133,13 +1134,13 @@ static int rzg2l_gpio_get_gpioint(unsigned int virq)
port = virq / 8;
bit = virq % 8;
- if (port >= ARRAY_SIZE(rzg2l_gpio_configs) ||
- bit >= RZG2L_GPIO_PORT_GET_PINCNT(rzg2l_gpio_configs[port]))
+ if (port >= data->n_ports ||
+ bit >= RZG2L_GPIO_PORT_GET_PINCNT(data->port_pin_configs[port]))
return -EINVAL;
gpioint = bit;
for (i = 0; i < port; i++)
- gpioint += RZG2L_GPIO_PORT_GET_PINCNT(rzg2l_gpio_configs[i]);
+ gpioint += RZG2L_GPIO_PORT_GET_PINCNT(data->port_pin_configs[i]);
return gpioint;
}
@@ -1239,7 +1240,7 @@ static int rzg2l_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
unsigned long flags;
int gpioint, irq;
- gpioint = rzg2l_gpio_get_gpioint(child);
+ gpioint = rzg2l_gpio_get_gpioint(child, pctrl->data);
if (gpioint < 0)
return gpioint;
@@ -1313,8 +1314,8 @@ static void rzg2l_init_irq_valid_mask(struct gpio_chip *gc,
port = offset / 8;
bit = offset % 8;
- if (port >= ARRAY_SIZE(rzg2l_gpio_configs) ||
- bit >= RZG2L_GPIO_PORT_GET_PINCNT(rzg2l_gpio_configs[port]))
+ if (port >= pctrl->data->n_ports ||
+ bit >= RZG2L_GPIO_PORT_GET_PINCNT(pctrl->data->port_pin_configs[port]))
clear_bit(offset, valid_mask);
}
}
@@ -1467,6 +1468,12 @@ static int rzg2l_pinctrl_probe(struct platform_device *pdev)
struct rzg2l_pinctrl *pctrl;
int ret;
+ BUILD_BUG_ON(ARRAY_SIZE(rzg2l_gpio_configs) * RZG2L_PINS_PER_PORT >
+ ARRAY_SIZE(rzg2l_gpio_names));
+
+ BUILD_BUG_ON(ARRAY_SIZE(r9a07g043_gpio_configs) * RZG2L_PINS_PER_PORT >
+ ARRAY_SIZE(rzg2l_gpio_names));
+
pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL);
if (!pctrl)
return -ENOMEM;
@@ -1519,6 +1526,7 @@ static int rzg2l_pinctrl_probe(struct platform_device *pdev)
static struct rzg2l_pinctrl_data r9a07g043_data = {
.port_pins = rzg2l_gpio_names,
.port_pin_configs = r9a07g043_gpio_configs,
+ .n_ports = ARRAY_SIZE(r9a07g043_gpio_configs),
.dedicated_pins = rzg2l_dedicated_pins.common,
.n_port_pins = ARRAY_SIZE(r9a07g043_gpio_configs) * RZG2L_PINS_PER_PORT,
.n_dedicated_pins = ARRAY_SIZE(rzg2l_dedicated_pins.common),
@@ -1527,8 +1535,9 @@ static struct rzg2l_pinctrl_data r9a07g043_data = {
static struct rzg2l_pinctrl_data r9a07g044_data = {
.port_pins = rzg2l_gpio_names,
.port_pin_configs = rzg2l_gpio_configs,
+ .n_ports = ARRAY_SIZE(rzg2l_gpio_configs),
.dedicated_pins = rzg2l_dedicated_pins.common,
- .n_port_pins = ARRAY_SIZE(rzg2l_gpio_names),
+ .n_port_pins = ARRAY_SIZE(rzg2l_gpio_configs) * RZG2L_PINS_PER_PORT,
.n_dedicated_pins = ARRAY_SIZE(rzg2l_dedicated_pins.common) +
ARRAY_SIZE(rzg2l_dedicated_pins.rzg2l_pins),
};
diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c
index 514001e448b9..833e170e3d99 100644
--- a/drivers/pinctrl/samsung/pinctrl-samsung.c
+++ b/drivers/pinctrl/samsung/pinctrl-samsung.c
@@ -649,7 +649,7 @@ static int samsung_gpio_direction_output(struct gpio_chip *gc, unsigned offset,
}
/*
- * gpiolib gpio_to_irq callback function. Creates a mapping between a GPIO pin
+ * gpiod_to_irq() callback function. Creates a mapping between a GPIO pin
* and a virtual IRQ, if not already present.
*/
static int samsung_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
diff --git a/drivers/pinctrl/starfive/Kconfig b/drivers/pinctrl/starfive/Kconfig
index 55c514e622f9..8192ac2087fc 100644
--- a/drivers/pinctrl/starfive/Kconfig
+++ b/drivers/pinctrl/starfive/Kconfig
@@ -16,3 +16,36 @@ config PINCTRL_STARFIVE_JH7100
This also provides an interface to the GPIO pins not used by other
peripherals supporting inputs, outputs, configuring pull-up/pull-down
and interrupts on input changes.
+
+config PINCTRL_STARFIVE_JH7110
+ bool
+ select GENERIC_PINCTRL_GROUPS
+ select GENERIC_PINMUX_FUNCTIONS
+ select GENERIC_PINCONF
+ select GPIOLIB
+ select GPIOLIB_IRQCHIP
+ select OF_GPIO
+
+config PINCTRL_STARFIVE_JH7110_SYS
+ tristate "System pinctrl and GPIO driver for the StarFive JH7110 SoC"
+ depends on SOC_STARFIVE || COMPILE_TEST
+ depends on OF
+ select PINCTRL_STARFIVE_JH7110
+ default SOC_STARFIVE
+ help
+ Say yes here to support system pin control on the StarFive JH7110 SoC.
+ This also provides an interface to the GPIO pins not used by other
+ peripherals supporting inputs, outputs, configuring pull-up/pull-down
+ and interrupts on input changes.
+
+config PINCTRL_STARFIVE_JH7110_AON
+ tristate "Always-on pinctrl and GPIO driver for the StarFive JH7110 SoC"
+ depends on SOC_STARFIVE || COMPILE_TEST
+ depends on OF
+ select PINCTRL_STARFIVE_JH7110
+ default SOC_STARFIVE
+ help
+ Say yes here to support always-on pin control on the StarFive JH7110 SoC.
+ This also provides an interface to the GPIO pins not used by other
+ peripherals supporting inputs, outputs, configuring pull-up/pull-down
+ and interrupts on input changes.
diff --git a/drivers/pinctrl/starfive/Makefile b/drivers/pinctrl/starfive/Makefile
index 0293f26a0a99..ee0d32d085cb 100644
--- a/drivers/pinctrl/starfive/Makefile
+++ b/drivers/pinctrl/starfive/Makefile
@@ -1,3 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_PINCTRL_STARFIVE_JH7100) += pinctrl-starfive-jh7100.o
+
+obj-$(CONFIG_PINCTRL_STARFIVE_JH7110) += pinctrl-starfive-jh7110.o
+obj-$(CONFIG_PINCTRL_STARFIVE_JH7110_SYS) += pinctrl-starfive-jh7110-sys.o
+obj-$(CONFIG_PINCTRL_STARFIVE_JH7110_AON) += pinctrl-starfive-jh7110-aon.o
diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jh7110-aon.c b/drivers/pinctrl/starfive/pinctrl-starfive-jh7110-aon.c
new file mode 100644
index 000000000000..8cf28aaed254
--- /dev/null
+++ b/drivers/pinctrl/starfive/pinctrl-starfive-jh7110-aon.c
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Pinctrl / GPIO driver for StarFive JH7110 SoC aon controller
+ *
+ * Copyright (C) 2022 StarFive Technology Co., Ltd.
+ */
+
+#include <linux/err.h>
+#include <linux/gpio/driver.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include <dt-bindings/pinctrl/starfive,jh7110-pinctrl.h>
+
+#include "../core.h"
+#include "../pinconf.h"
+#include "../pinmux.h"
+#include "pinctrl-starfive-jh7110.h"
+
+#define JH7110_AON_NGPIO 4
+#define JH7110_AON_GC_BASE 64
+
+/* registers */
+#define JH7110_AON_DOEN 0x0
+#define JH7110_AON_DOUT 0x4
+#define JH7110_AON_GPI 0x8
+#define JH7110_AON_GPIOIN 0x2c
+
+#define JH7110_AON_GPIOEN 0xc
+#define JH7110_AON_GPIOIS 0x10
+#define JH7110_AON_GPIOIC 0x14
+#define JH7110_AON_GPIOIBE 0x18
+#define JH7110_AON_GPIOIEV 0x1c
+#define JH7110_AON_GPIOIE 0x20
+#define JH7110_AON_GPIORIS 0x28
+#define JH7110_AON_GPIOMIS 0x28
+
+#define JH7110_AON_GPO_PDA_0_5_CFG 0x30
+
+static const struct pinctrl_pin_desc jh7110_aon_pins[] = {
+ PINCTRL_PIN(PAD_TESTEN, "TESTEN"),
+ PINCTRL_PIN(PAD_RGPIO0, "RGPIO0"),
+ PINCTRL_PIN(PAD_RGPIO1, "RGPIO1"),
+ PINCTRL_PIN(PAD_RGPIO2, "RGPIO2"),
+ PINCTRL_PIN(PAD_RGPIO3, "RGPIO3"),
+ PINCTRL_PIN(PAD_RSTN, "RSTN"),
+ PINCTRL_PIN(PAD_GMAC0_MDC, "GMAC0_MDC"),
+ PINCTRL_PIN(PAD_GMAC0_MDIO, "GMAC0_MDIO"),
+ PINCTRL_PIN(PAD_GMAC0_RXD0, "GMAC0_RXD0"),
+ PINCTRL_PIN(PAD_GMAC0_RXD1, "GMAC0_RXD1"),
+ PINCTRL_PIN(PAD_GMAC0_RXD2, "GMAC0_RXD2"),
+ PINCTRL_PIN(PAD_GMAC0_RXD3, "GMAC0_RXD3"),
+ PINCTRL_PIN(PAD_GMAC0_RXDV, "GMAC0_RXDV"),
+ PINCTRL_PIN(PAD_GMAC0_RXC, "GMAC0_RXC"),
+ PINCTRL_PIN(PAD_GMAC0_TXD0, "GMAC0_TXD0"),
+ PINCTRL_PIN(PAD_GMAC0_TXD1, "GMAC0_TXD1"),
+ PINCTRL_PIN(PAD_GMAC0_TXD2, "GMAC0_TXD2"),
+ PINCTRL_PIN(PAD_GMAC0_TXD3, "GMAC0_TXD3"),
+ PINCTRL_PIN(PAD_GMAC0_TXEN, "GMAC0_TXEN"),
+ PINCTRL_PIN(PAD_GMAC0_TXC, "GMAC0_TXC"),
+};
+
+static int jh7110_aon_set_one_pin_mux(struct jh7110_pinctrl *sfp,
+ unsigned int pin,
+ unsigned int din, u32 dout,
+ u32 doen, u32 func)
+{
+ if (pin < sfp->gc.ngpio && func == 0)
+ jh7110_set_gpiomux(sfp, pin, din, dout, doen);
+
+ return 0;
+}
+
+static int jh7110_aon_get_padcfg_base(struct jh7110_pinctrl *sfp,
+ unsigned int pin)
+{
+ if (pin < PAD_GMAC0_MDC)
+ return JH7110_AON_GPO_PDA_0_5_CFG;
+
+ return -1;
+}
+
+static void jh7110_aon_irq_handler(struct irq_desc *desc)
+{
+ struct jh7110_pinctrl *sfp = jh7110_from_irq_desc(desc);
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ unsigned long mis;
+ unsigned int pin;
+
+ chained_irq_enter(chip, desc);
+
+ mis = readl_relaxed(sfp->base + JH7110_AON_GPIOMIS);
+ for_each_set_bit(pin, &mis, JH7110_AON_NGPIO)
+ generic_handle_domain_irq(sfp->gc.irq.domain, pin);
+
+ chained_irq_exit(chip, desc);
+}
+
+static int jh7110_aon_init_hw(struct gpio_chip *gc)
+{
+ struct jh7110_pinctrl *sfp = container_of(gc,
+ struct jh7110_pinctrl, gc);
+
+ /* mask all GPIO interrupts */
+ writel_relaxed(0, sfp->base + JH7110_AON_GPIOIE);
+ /* clear edge interrupt flags */
+ writel_relaxed(0, sfp->base + JH7110_AON_GPIOIC);
+ writel_relaxed(0x0f, sfp->base + JH7110_AON_GPIOIC);
+ /* enable GPIO interrupts */
+ writel_relaxed(1, sfp->base + JH7110_AON_GPIOEN);
+ return 0;
+}
+
+static const struct jh7110_gpio_irq_reg jh7110_aon_irq_reg = {
+ .is_reg_base = JH7110_AON_GPIOIS,
+ .ic_reg_base = JH7110_AON_GPIOIC,
+ .ibe_reg_base = JH7110_AON_GPIOIBE,
+ .iev_reg_base = JH7110_AON_GPIOIEV,
+ .ie_reg_base = JH7110_AON_GPIOIE,
+ .ris_reg_base = JH7110_AON_GPIORIS,
+ .mis_reg_base = JH7110_AON_GPIOMIS,
+};
+
+static const struct jh7110_pinctrl_soc_info jh7110_aon_pinctrl_info = {
+ .pins = jh7110_aon_pins,
+ .npins = ARRAY_SIZE(jh7110_aon_pins),
+ .ngpios = JH7110_AON_NGPIO,
+ .gc_base = JH7110_AON_GC_BASE,
+ .dout_reg_base = JH7110_AON_DOUT,
+ .dout_mask = GENMASK(3, 0),
+ .doen_reg_base = JH7110_AON_DOEN,
+ .doen_mask = GENMASK(2, 0),
+ .gpi_reg_base = JH7110_AON_GPI,
+ .gpi_mask = GENMASK(3, 0),
+ .gpioin_reg_base = JH7110_AON_GPIOIN,
+ .irq_reg = &jh7110_aon_irq_reg,
+ .jh7110_set_one_pin_mux = jh7110_aon_set_one_pin_mux,
+ .jh7110_get_padcfg_base = jh7110_aon_get_padcfg_base,
+ .jh7110_gpio_irq_handler = jh7110_aon_irq_handler,
+ .jh7110_gpio_init_hw = jh7110_aon_init_hw,
+};
+
+static const struct of_device_id jh7110_aon_pinctrl_of_match[] = {
+ {
+ .compatible = "starfive,jh7110-aon-pinctrl",
+ .data = &jh7110_aon_pinctrl_info,
+ },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, jh7110_aon_pinctrl_of_match);
+
+static struct platform_driver jh7110_aon_pinctrl_driver = {
+ .probe = jh7110_pinctrl_probe,
+ .driver = {
+ .name = "starfive-jh7110-aon-pinctrl",
+ .of_match_table = jh7110_aon_pinctrl_of_match,
+ },
+};
+module_platform_driver(jh7110_aon_pinctrl_driver);
+
+MODULE_DESCRIPTION("Pinctrl driver for the StarFive JH7110 SoC aon controller");
+MODULE_AUTHOR("Jianlong Huang <jianlong.huang@starfivetech.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jh7110-sys.c b/drivers/pinctrl/starfive/pinctrl-starfive-jh7110-sys.c
new file mode 100644
index 000000000000..bc279a39613f
--- /dev/null
+++ b/drivers/pinctrl/starfive/pinctrl-starfive-jh7110-sys.c
@@ -0,0 +1,449 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Pinctrl / GPIO driver for StarFive JH7110 SoC sys controller
+ *
+ * Copyright (C) 2022 Emil Renner Berthing <kernel@esmil.dk>
+ * Copyright (C) 2022 StarFive Technology Co., Ltd.
+ */
+
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/gpio/driver.h>
+#include <linux/io.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/spinlock.h>
+
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+
+#include <dt-bindings/pinctrl/starfive,jh7110-pinctrl.h>
+
+#include "../core.h"
+#include "../pinctrl-utils.h"
+#include "../pinmux.h"
+#include "../pinconf.h"
+#include "pinctrl-starfive-jh7110.h"
+
+#define JH7110_SYS_NGPIO 64
+#define JH7110_SYS_GC_BASE 0
+
+/* registers */
+#define JH7110_SYS_DOEN 0x000
+#define JH7110_SYS_DOUT 0x040
+#define JH7110_SYS_GPI 0x080
+#define JH7110_SYS_GPIOIN 0x118
+
+#define JH7110_SYS_GPIOEN 0x0dc
+#define JH7110_SYS_GPIOIS0 0x0e0
+#define JH7110_SYS_GPIOIS1 0x0e4
+#define JH7110_SYS_GPIOIC0 0x0e8
+#define JH7110_SYS_GPIOIC1 0x0ec
+#define JH7110_SYS_GPIOIBE0 0x0f0
+#define JH7110_SYS_GPIOIBE1 0x0f4
+#define JH7110_SYS_GPIOIEV0 0x0f8
+#define JH7110_SYS_GPIOIEV1 0x0fc
+#define JH7110_SYS_GPIOIE0 0x100
+#define JH7110_SYS_GPIOIE1 0x104
+#define JH7110_SYS_GPIORIS0 0x108
+#define JH7110_SYS_GPIORIS1 0x10c
+#define JH7110_SYS_GPIOMIS0 0x110
+#define JH7110_SYS_GPIOMIS1 0x114
+
+#define JH7110_SYS_GPO_PDA_0_74_CFG 0x120
+#define JH7110_SYS_GPO_PDA_89_94_CFG 0x284
+
+static const struct pinctrl_pin_desc jh7110_sys_pins[] = {
+ PINCTRL_PIN(PAD_GPIO0, "GPIO0"),
+ PINCTRL_PIN(PAD_GPIO1, "GPIO1"),
+ PINCTRL_PIN(PAD_GPIO2, "GPIO2"),
+ PINCTRL_PIN(PAD_GPIO3, "GPIO3"),
+ PINCTRL_PIN(PAD_GPIO4, "GPIO4"),
+ PINCTRL_PIN(PAD_GPIO5, "GPIO5"),
+ PINCTRL_PIN(PAD_GPIO6, "GPIO6"),
+ PINCTRL_PIN(PAD_GPIO7, "GPIO7"),
+ PINCTRL_PIN(PAD_GPIO8, "GPIO8"),
+ PINCTRL_PIN(PAD_GPIO9, "GPIO9"),
+ PINCTRL_PIN(PAD_GPIO10, "GPIO10"),
+ PINCTRL_PIN(PAD_GPIO11, "GPIO11"),
+ PINCTRL_PIN(PAD_GPIO12, "GPIO12"),
+ PINCTRL_PIN(PAD_GPIO13, "GPIO13"),
+ PINCTRL_PIN(PAD_GPIO14, "GPIO14"),
+ PINCTRL_PIN(PAD_GPIO15, "GPIO15"),
+ PINCTRL_PIN(PAD_GPIO16, "GPIO16"),
+ PINCTRL_PIN(PAD_GPIO17, "GPIO17"),
+ PINCTRL_PIN(PAD_GPIO18, "GPIO18"),
+ PINCTRL_PIN(PAD_GPIO19, "GPIO19"),
+ PINCTRL_PIN(PAD_GPIO20, "GPIO20"),
+ PINCTRL_PIN(PAD_GPIO21, "GPIO21"),
+ PINCTRL_PIN(PAD_GPIO22, "GPIO22"),
+ PINCTRL_PIN(PAD_GPIO23, "GPIO23"),
+ PINCTRL_PIN(PAD_GPIO24, "GPIO24"),
+ PINCTRL_PIN(PAD_GPIO25, "GPIO25"),
+ PINCTRL_PIN(PAD_GPIO26, "GPIO26"),
+ PINCTRL_PIN(PAD_GPIO27, "GPIO27"),
+ PINCTRL_PIN(PAD_GPIO28, "GPIO28"),
+ PINCTRL_PIN(PAD_GPIO29, "GPIO29"),
+ PINCTRL_PIN(PAD_GPIO30, "GPIO30"),
+ PINCTRL_PIN(PAD_GPIO31, "GPIO31"),
+ PINCTRL_PIN(PAD_GPIO32, "GPIO32"),
+ PINCTRL_PIN(PAD_GPIO33, "GPIO33"),
+ PINCTRL_PIN(PAD_GPIO34, "GPIO34"),
+ PINCTRL_PIN(PAD_GPIO35, "GPIO35"),
+ PINCTRL_PIN(PAD_GPIO36, "GPIO36"),
+ PINCTRL_PIN(PAD_GPIO37, "GPIO37"),
+ PINCTRL_PIN(PAD_GPIO38, "GPIO38"),
+ PINCTRL_PIN(PAD_GPIO39, "GPIO39"),
+ PINCTRL_PIN(PAD_GPIO40, "GPIO40"),
+ PINCTRL_PIN(PAD_GPIO41, "GPIO41"),
+ PINCTRL_PIN(PAD_GPIO42, "GPIO42"),
+ PINCTRL_PIN(PAD_GPIO43, "GPIO43"),
+ PINCTRL_PIN(PAD_GPIO44, "GPIO44"),
+ PINCTRL_PIN(PAD_GPIO45, "GPIO45"),
+ PINCTRL_PIN(PAD_GPIO46, "GPIO46"),
+ PINCTRL_PIN(PAD_GPIO47, "GPIO47"),
+ PINCTRL_PIN(PAD_GPIO48, "GPIO48"),
+ PINCTRL_PIN(PAD_GPIO49, "GPIO49"),
+ PINCTRL_PIN(PAD_GPIO50, "GPIO50"),
+ PINCTRL_PIN(PAD_GPIO51, "GPIO51"),
+ PINCTRL_PIN(PAD_GPIO52, "GPIO52"),
+ PINCTRL_PIN(PAD_GPIO53, "GPIO53"),
+ PINCTRL_PIN(PAD_GPIO54, "GPIO54"),
+ PINCTRL_PIN(PAD_GPIO55, "GPIO55"),
+ PINCTRL_PIN(PAD_GPIO56, "GPIO56"),
+ PINCTRL_PIN(PAD_GPIO57, "GPIO57"),
+ PINCTRL_PIN(PAD_GPIO58, "GPIO58"),
+ PINCTRL_PIN(PAD_GPIO59, "GPIO59"),
+ PINCTRL_PIN(PAD_GPIO60, "GPIO60"),
+ PINCTRL_PIN(PAD_GPIO61, "GPIO61"),
+ PINCTRL_PIN(PAD_GPIO62, "GPIO62"),
+ PINCTRL_PIN(PAD_GPIO63, "GPIO63"),
+ PINCTRL_PIN(PAD_SD0_CLK, "SD0_CLK"),
+ PINCTRL_PIN(PAD_SD0_CMD, "SD0_CMD"),
+ PINCTRL_PIN(PAD_SD0_DATA0, "SD0_DATA0"),
+ PINCTRL_PIN(PAD_SD0_DATA1, "SD0_DATA1"),
+ PINCTRL_PIN(PAD_SD0_DATA2, "SD0_DATA2"),
+ PINCTRL_PIN(PAD_SD0_DATA3, "SD0_DATA3"),
+ PINCTRL_PIN(PAD_SD0_DATA4, "SD0_DATA4"),
+ PINCTRL_PIN(PAD_SD0_DATA5, "SD0_DATA5"),
+ PINCTRL_PIN(PAD_SD0_DATA6, "SD0_DATA6"),
+ PINCTRL_PIN(PAD_SD0_DATA7, "SD0_DATA7"),
+ PINCTRL_PIN(PAD_SD0_STRB, "SD0_STRB"),
+ PINCTRL_PIN(PAD_GMAC1_MDC, "GMAC1_MDC"),
+ PINCTRL_PIN(PAD_GMAC1_MDIO, "GMAC1_MDIO"),
+ PINCTRL_PIN(PAD_GMAC1_RXD0, "GMAC1_RXD0"),
+ PINCTRL_PIN(PAD_GMAC1_RXD1, "GMAC1_RXD1"),
+ PINCTRL_PIN(PAD_GMAC1_RXD2, "GMAC1_RXD2"),
+ PINCTRL_PIN(PAD_GMAC1_RXD3, "GMAC1_RXD3"),
+ PINCTRL_PIN(PAD_GMAC1_RXDV, "GMAC1_RXDV"),
+ PINCTRL_PIN(PAD_GMAC1_RXC, "GMAC1_RXC"),
+ PINCTRL_PIN(PAD_GMAC1_TXD0, "GMAC1_TXD0"),
+ PINCTRL_PIN(PAD_GMAC1_TXD1, "GMAC1_TXD1"),
+ PINCTRL_PIN(PAD_GMAC1_TXD2, "GMAC1_TXD2"),
+ PINCTRL_PIN(PAD_GMAC1_TXD3, "GMAC1_TXD3"),
+ PINCTRL_PIN(PAD_GMAC1_TXEN, "GMAC1_TXEN"),
+ PINCTRL_PIN(PAD_GMAC1_TXC, "GMAC1_TXC"),
+ PINCTRL_PIN(PAD_QSPI_SCLK, "QSPI_SCLK"),
+ PINCTRL_PIN(PAD_QSPI_CS0, "QSPI_CS0"),
+ PINCTRL_PIN(PAD_QSPI_DATA0, "QSPI_DATA0"),
+ PINCTRL_PIN(PAD_QSPI_DATA1, "QSPI_DATA1"),
+ PINCTRL_PIN(PAD_QSPI_DATA2, "QSPI_DATA2"),
+ PINCTRL_PIN(PAD_QSPI_DATA3, "QSPI_DATA3"),
+};
+
+struct jh7110_func_sel {
+ u16 offset;
+ u8 shift;
+ u8 max;
+};
+
+static const struct jh7110_func_sel
+ jh7110_sys_func_sel[ARRAY_SIZE(jh7110_sys_pins)] = {
+ [PAD_GMAC1_RXC] = { 0x29c, 0, 1 },
+ [PAD_GPIO10] = { 0x29c, 2, 3 },
+ [PAD_GPIO11] = { 0x29c, 5, 3 },
+ [PAD_GPIO12] = { 0x29c, 8, 3 },
+ [PAD_GPIO13] = { 0x29c, 11, 3 },
+ [PAD_GPIO14] = { 0x29c, 14, 3 },
+ [PAD_GPIO15] = { 0x29c, 17, 3 },
+ [PAD_GPIO16] = { 0x29c, 20, 3 },
+ [PAD_GPIO17] = { 0x29c, 23, 3 },
+ [PAD_GPIO18] = { 0x29c, 26, 3 },
+ [PAD_GPIO19] = { 0x29c, 29, 3 },
+
+ [PAD_GPIO20] = { 0x2a0, 0, 3 },
+ [PAD_GPIO21] = { 0x2a0, 3, 3 },
+ [PAD_GPIO22] = { 0x2a0, 6, 3 },
+ [PAD_GPIO23] = { 0x2a0, 9, 3 },
+ [PAD_GPIO24] = { 0x2a0, 12, 3 },
+ [PAD_GPIO25] = { 0x2a0, 15, 3 },
+ [PAD_GPIO26] = { 0x2a0, 18, 3 },
+ [PAD_GPIO27] = { 0x2a0, 21, 3 },
+ [PAD_GPIO28] = { 0x2a0, 24, 3 },
+ [PAD_GPIO29] = { 0x2a0, 27, 3 },
+
+ [PAD_GPIO30] = { 0x2a4, 0, 3 },
+ [PAD_GPIO31] = { 0x2a4, 3, 3 },
+ [PAD_GPIO32] = { 0x2a4, 6, 3 },
+ [PAD_GPIO33] = { 0x2a4, 9, 3 },
+ [PAD_GPIO34] = { 0x2a4, 12, 3 },
+ [PAD_GPIO35] = { 0x2a4, 15, 3 },
+ [PAD_GPIO36] = { 0x2a4, 17, 3 },
+ [PAD_GPIO37] = { 0x2a4, 20, 3 },
+ [PAD_GPIO38] = { 0x2a4, 23, 3 },
+ [PAD_GPIO39] = { 0x2a4, 26, 3 },
+ [PAD_GPIO40] = { 0x2a4, 29, 3 },
+
+ [PAD_GPIO41] = { 0x2a8, 0, 3 },
+ [PAD_GPIO42] = { 0x2a8, 3, 3 },
+ [PAD_GPIO43] = { 0x2a8, 6, 3 },
+ [PAD_GPIO44] = { 0x2a8, 9, 3 },
+ [PAD_GPIO45] = { 0x2a8, 12, 3 },
+ [PAD_GPIO46] = { 0x2a8, 15, 3 },
+ [PAD_GPIO47] = { 0x2a8, 18, 3 },
+ [PAD_GPIO48] = { 0x2a8, 21, 3 },
+ [PAD_GPIO49] = { 0x2a8, 24, 3 },
+ [PAD_GPIO50] = { 0x2a8, 27, 3 },
+ [PAD_GPIO51] = { 0x2a8, 30, 3 },
+
+ [PAD_GPIO52] = { 0x2ac, 0, 3 },
+ [PAD_GPIO53] = { 0x2ac, 2, 3 },
+ [PAD_GPIO54] = { 0x2ac, 4, 3 },
+ [PAD_GPIO55] = { 0x2ac, 6, 3 },
+ [PAD_GPIO56] = { 0x2ac, 9, 3 },
+ [PAD_GPIO57] = { 0x2ac, 12, 3 },
+ [PAD_GPIO58] = { 0x2ac, 15, 3 },
+ [PAD_GPIO59] = { 0x2ac, 18, 3 },
+ [PAD_GPIO60] = { 0x2ac, 21, 3 },
+ [PAD_GPIO61] = { 0x2ac, 24, 3 },
+ [PAD_GPIO62] = { 0x2ac, 27, 3 },
+ [PAD_GPIO63] = { 0x2ac, 30, 3 },
+
+ [PAD_GPIO6] = { 0x2b0, 0, 3 },
+ [PAD_GPIO7] = { 0x2b0, 2, 3 },
+ [PAD_GPIO8] = { 0x2b0, 5, 3 },
+ [PAD_GPIO9] = { 0x2b0, 8, 3 },
+};
+
+struct jh7110_vin_group_sel {
+ u16 offset;
+ u8 shift;
+ u8 group;
+};
+
+static const struct jh7110_vin_group_sel
+ jh7110_sys_vin_group_sel[ARRAY_SIZE(jh7110_sys_pins)] = {
+ [PAD_GPIO6] = { 0x2b4, 21, 0 },
+ [PAD_GPIO7] = { 0x2b4, 18, 0 },
+ [PAD_GPIO8] = { 0x2b4, 15, 0 },
+ [PAD_GPIO9] = { 0x2b0, 11, 0 },
+ [PAD_GPIO10] = { 0x2b0, 20, 0 },
+ [PAD_GPIO11] = { 0x2b0, 23, 0 },
+ [PAD_GPIO12] = { 0x2b0, 26, 0 },
+ [PAD_GPIO13] = { 0x2b0, 29, 0 },
+ [PAD_GPIO14] = { 0x2b4, 0, 0 },
+ [PAD_GPIO15] = { 0x2b4, 3, 0 },
+ [PAD_GPIO16] = { 0x2b4, 6, 0 },
+ [PAD_GPIO17] = { 0x2b4, 9, 0 },
+ [PAD_GPIO18] = { 0x2b4, 12, 0 },
+ [PAD_GPIO19] = { 0x2b0, 14, 0 },
+ [PAD_GPIO20] = { 0x2b0, 17, 0 },
+
+ [PAD_GPIO21] = { 0x2b4, 21, 1 },
+ [PAD_GPIO22] = { 0x2b4, 18, 1 },
+ [PAD_GPIO23] = { 0x2b4, 15, 1 },
+ [PAD_GPIO24] = { 0x2b0, 11, 1 },
+ [PAD_GPIO25] = { 0x2b0, 20, 1 },
+ [PAD_GPIO26] = { 0x2b0, 23, 1 },
+ [PAD_GPIO27] = { 0x2b0, 26, 1 },
+ [PAD_GPIO28] = { 0x2b0, 29, 1 },
+ [PAD_GPIO29] = { 0x2b4, 0, 1 },
+ [PAD_GPIO30] = { 0x2b4, 3, 1 },
+ [PAD_GPIO31] = { 0x2b4, 6, 1 },
+ [PAD_GPIO32] = { 0x2b4, 9, 1 },
+ [PAD_GPIO33] = { 0x2b4, 12, 1 },
+ [PAD_GPIO34] = { 0x2b0, 14, 1 },
+ [PAD_GPIO35] = { 0x2b0, 17, 1 },
+
+ [PAD_GPIO36] = { 0x2b4, 21, 2 },
+ [PAD_GPIO37] = { 0x2b4, 18, 2 },
+ [PAD_GPIO38] = { 0x2b4, 15, 2 },
+ [PAD_GPIO39] = { 0x2b0, 11, 2 },
+ [PAD_GPIO40] = { 0x2b0, 20, 2 },
+ [PAD_GPIO41] = { 0x2b0, 23, 2 },
+ [PAD_GPIO42] = { 0x2b0, 26, 2 },
+ [PAD_GPIO43] = { 0x2b0, 29, 2 },
+ [PAD_GPIO44] = { 0x2b4, 0, 2 },
+ [PAD_GPIO45] = { 0x2b4, 3, 2 },
+ [PAD_GPIO46] = { 0x2b4, 6, 2 },
+ [PAD_GPIO47] = { 0x2b4, 9, 2 },
+ [PAD_GPIO48] = { 0x2b4, 12, 2 },
+ [PAD_GPIO49] = { 0x2b0, 14, 2 },
+ [PAD_GPIO50] = { 0x2b0, 17, 2 },
+};
+
+static void jh7110_set_function(struct jh7110_pinctrl *sfp,
+ unsigned int pin, u32 func)
+{
+ const struct jh7110_func_sel *fs = &jh7110_sys_func_sel[pin];
+ unsigned long flags;
+ void __iomem *reg;
+ u32 mask;
+
+ if (!fs->offset)
+ return;
+
+ if (func > fs->max)
+ return;
+
+ reg = sfp->base + fs->offset;
+ func = func << fs->shift;
+ mask = 0x3U << fs->shift;
+
+ raw_spin_lock_irqsave(&sfp->lock, flags);
+ func |= readl_relaxed(reg) & ~mask;
+ writel_relaxed(func, reg);
+ raw_spin_unlock_irqrestore(&sfp->lock, flags);
+}
+
+static void jh7110_set_vin_group(struct jh7110_pinctrl *sfp,
+ unsigned int pin)
+{
+ const struct jh7110_vin_group_sel *gs = &jh7110_sys_vin_group_sel[pin];
+ unsigned long flags;
+ void __iomem *reg;
+ u32 mask;
+ u32 grp;
+
+ if (!gs->offset)
+ return;
+
+ reg = sfp->base + gs->offset;
+ grp = gs->group << gs->shift;
+ mask = 0x3U << gs->shift;
+
+ raw_spin_lock_irqsave(&sfp->lock, flags);
+ grp |= readl_relaxed(reg) & ~mask;
+ writel_relaxed(grp, reg);
+ raw_spin_unlock_irqrestore(&sfp->lock, flags);
+}
+
+static int jh7110_sys_set_one_pin_mux(struct jh7110_pinctrl *sfp,
+ unsigned int pin,
+ unsigned int din, u32 dout,
+ u32 doen, u32 func)
+{
+ if (pin < sfp->gc.ngpio && func == 0)
+ jh7110_set_gpiomux(sfp, pin, din, dout, doen);
+
+ jh7110_set_function(sfp, pin, func);
+
+ if (pin < sfp->gc.ngpio && func == 2)
+ jh7110_set_vin_group(sfp, pin);
+
+ return 0;
+}
+
+static int jh7110_sys_get_padcfg_base(struct jh7110_pinctrl *sfp,
+ unsigned int pin)
+{
+ if (pin < PAD_GMAC1_MDC)
+ return JH7110_SYS_GPO_PDA_0_74_CFG;
+ else if (pin > PAD_GMAC1_TXC && pin <= PAD_QSPI_DATA3)
+ return JH7110_SYS_GPO_PDA_89_94_CFG;
+ else
+ return -1;
+}
+
+static void jh7110_sys_irq_handler(struct irq_desc *desc)
+{
+ struct jh7110_pinctrl *sfp = jh7110_from_irq_desc(desc);
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ unsigned long mis;
+ unsigned int pin;
+
+ chained_irq_enter(chip, desc);
+
+ mis = readl_relaxed(sfp->base + JH7110_SYS_GPIOMIS0);
+ for_each_set_bit(pin, &mis, 32)
+ generic_handle_domain_irq(sfp->gc.irq.domain, pin);
+
+ mis = readl_relaxed(sfp->base + JH7110_SYS_GPIOMIS1);
+ for_each_set_bit(pin, &mis, 32)
+ generic_handle_domain_irq(sfp->gc.irq.domain, pin + 32);
+
+ chained_irq_exit(chip, desc);
+}
+
+static int jh7110_sys_init_hw(struct gpio_chip *gc)
+{
+ struct jh7110_pinctrl *sfp = container_of(gc,
+ struct jh7110_pinctrl, gc);
+
+ /* mask all GPIO interrupts */
+ writel(0U, sfp->base + JH7110_SYS_GPIOIE0);
+ writel(0U, sfp->base + JH7110_SYS_GPIOIE1);
+ /* clear edge interrupt flags */
+ writel(~0U, sfp->base + JH7110_SYS_GPIOIC0);
+ writel(~0U, sfp->base + JH7110_SYS_GPIOIC1);
+ /* enable GPIO interrupts */
+ writel(1U, sfp->base + JH7110_SYS_GPIOEN);
+ return 0;
+}
+
+static const struct jh7110_gpio_irq_reg jh7110_sys_irq_reg = {
+ .is_reg_base = JH7110_SYS_GPIOIS0,
+ .ic_reg_base = JH7110_SYS_GPIOIC0,
+ .ibe_reg_base = JH7110_SYS_GPIOIBE0,
+ .iev_reg_base = JH7110_SYS_GPIOIEV0,
+ .ie_reg_base = JH7110_SYS_GPIOIE0,
+ .ris_reg_base = JH7110_SYS_GPIORIS0,
+ .mis_reg_base = JH7110_SYS_GPIOMIS0,
+};
+
+static const struct jh7110_pinctrl_soc_info jh7110_sys_pinctrl_info = {
+ .pins = jh7110_sys_pins,
+ .npins = ARRAY_SIZE(jh7110_sys_pins),
+ .ngpios = JH7110_SYS_NGPIO,
+ .gc_base = JH7110_SYS_GC_BASE,
+ .dout_reg_base = JH7110_SYS_DOUT,
+ .dout_mask = GENMASK(6, 0),
+ .doen_reg_base = JH7110_SYS_DOEN,
+ .doen_mask = GENMASK(5, 0),
+ .gpi_reg_base = JH7110_SYS_GPI,
+ .gpi_mask = GENMASK(6, 0),
+ .gpioin_reg_base = JH7110_SYS_GPIOIN,
+ .irq_reg = &jh7110_sys_irq_reg,
+ .jh7110_set_one_pin_mux = jh7110_sys_set_one_pin_mux,
+ .jh7110_get_padcfg_base = jh7110_sys_get_padcfg_base,
+ .jh7110_gpio_irq_handler = jh7110_sys_irq_handler,
+ .jh7110_gpio_init_hw = jh7110_sys_init_hw,
+};
+
+static const struct of_device_id jh7110_sys_pinctrl_of_match[] = {
+ {
+ .compatible = "starfive,jh7110-sys-pinctrl",
+ .data = &jh7110_sys_pinctrl_info,
+ },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, jh7110_sys_pinctrl_of_match);
+
+static struct platform_driver jh7110_sys_pinctrl_driver = {
+ .probe = jh7110_pinctrl_probe,
+ .driver = {
+ .name = "starfive-jh7110-sys-pinctrl",
+ .of_match_table = jh7110_sys_pinctrl_of_match,
+ },
+};
+module_platform_driver(jh7110_sys_pinctrl_driver);
+
+MODULE_DESCRIPTION("Pinctrl driver for the StarFive JH7110 SoC sys controller");
+MODULE_AUTHOR("Emil Renner Berthing <kernel@esmil.dk>");
+MODULE_AUTHOR("Jianlong Huang <jianlong.huang@starfivetech.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jh7110.c b/drivers/pinctrl/starfive/pinctrl-starfive-jh7110.c
new file mode 100644
index 000000000000..5fe729b4a03d
--- /dev/null
+++ b/drivers/pinctrl/starfive/pinctrl-starfive-jh7110.c
@@ -0,0 +1,982 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Pinctrl / GPIO driver for StarFive JH7110 SoC
+ *
+ * Copyright (C) 2022 Emil Renner Berthing <kernel@esmil.dk>
+ * Copyright (C) 2022 StarFive Technology Co., Ltd.
+ */
+
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/gpio/driver.h>
+#include <linux/io.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/seq_file.h>
+#include <linux/spinlock.h>
+
+#include <linux/pinctrl/consumer.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+
+#include <dt-bindings/pinctrl/starfive,jh7110-pinctrl.h>
+
+#include "../core.h"
+#include "../pinctrl-utils.h"
+#include "../pinmux.h"
+#include "../pinconf.h"
+#include "pinctrl-starfive-jh7110.h"
+
+/* pad control bits */
+#define JH7110_PADCFG_POS BIT(7)
+#define JH7110_PADCFG_SMT BIT(6)
+#define JH7110_PADCFG_SLEW BIT(5)
+#define JH7110_PADCFG_PD BIT(4)
+#define JH7110_PADCFG_PU BIT(3)
+#define JH7110_PADCFG_BIAS (JH7110_PADCFG_PD | JH7110_PADCFG_PU)
+#define JH7110_PADCFG_DS_MASK GENMASK(2, 1)
+#define JH7110_PADCFG_DS_2MA (0U << 1)
+#define JH7110_PADCFG_DS_4MA BIT(1)
+#define JH7110_PADCFG_DS_8MA (2U << 1)
+#define JH7110_PADCFG_DS_12MA (3U << 1)
+#define JH7110_PADCFG_IE BIT(0)
+
+/*
+ * The packed pinmux values from the device tree look like this:
+ *
+ * | 31 - 24 | 23 - 16 | 15 - 10 | 9 - 8 | 7 - 0 |
+ * | din | dout | doen | function | pin |
+ */
+static unsigned int jh7110_pinmux_din(u32 v)
+{
+ return (v & GENMASK(31, 24)) >> 24;
+}
+
+static u32 jh7110_pinmux_dout(u32 v)
+{
+ return (v & GENMASK(23, 16)) >> 16;
+}
+
+static u32 jh7110_pinmux_doen(u32 v)
+{
+ return (v & GENMASK(15, 10)) >> 10;
+}
+
+static u32 jh7110_pinmux_function(u32 v)
+{
+ return (v & GENMASK(9, 8)) >> 8;
+}
+
+static unsigned int jh7110_pinmux_pin(u32 v)
+{
+ return v & GENMASK(7, 0);
+}
+
+static struct jh7110_pinctrl *jh7110_from_irq_data(struct irq_data *d)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+
+ return container_of(gc, struct jh7110_pinctrl, gc);
+}
+
+struct jh7110_pinctrl *jh7110_from_irq_desc(struct irq_desc *desc)
+{
+ struct gpio_chip *gc = irq_desc_get_handler_data(desc);
+
+ return container_of(gc, struct jh7110_pinctrl, gc);
+}
+EXPORT_SYMBOL_GPL(jh7110_from_irq_desc);
+
+#ifdef CONFIG_DEBUG_FS
+static void jh7110_pin_dbg_show(struct pinctrl_dev *pctldev,
+ struct seq_file *s, unsigned int pin)
+{
+ struct jh7110_pinctrl *sfp = pinctrl_dev_get_drvdata(pctldev);
+ const struct jh7110_pinctrl_soc_info *info = sfp->info;
+
+ seq_printf(s, "%s", dev_name(pctldev->dev));
+
+ if (pin < sfp->gc.ngpio) {
+ unsigned int offset = 4 * (pin / 4);
+ unsigned int shift = 8 * (pin % 4);
+ u32 dout = readl_relaxed(sfp->base + info->dout_reg_base + offset);
+ u32 doen = readl_relaxed(sfp->base + info->doen_reg_base + offset);
+ u32 gpi = readl_relaxed(sfp->base + info->gpi_reg_base + offset);
+
+ dout = (dout >> shift) & info->dout_mask;
+ doen = (doen >> shift) & info->doen_mask;
+ gpi = ((gpi >> shift) - 2) & info->gpi_mask;
+
+ seq_printf(s, " dout=%u doen=%u din=%u", dout, doen, gpi);
+ }
+}
+#else
+#define jh7110_pin_dbg_show NULL
+#endif
+
+static int jh7110_dt_node_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *np,
+ struct pinctrl_map **maps,
+ unsigned int *num_maps)
+{
+ struct jh7110_pinctrl *sfp = pinctrl_dev_get_drvdata(pctldev);
+ struct device *dev = sfp->gc.parent;
+ struct device_node *child;
+ struct pinctrl_map *map;
+ const char **pgnames;
+ const char *grpname;
+ int ngroups;
+ int nmaps;
+ int ret;
+
+ ngroups = 0;
+ for_each_child_of_node(np, child)
+ ngroups += 1;
+ nmaps = 2 * ngroups;
+
+ pgnames = devm_kcalloc(dev, ngroups, sizeof(*pgnames), GFP_KERNEL);
+ if (!pgnames)
+ return -ENOMEM;
+
+ map = kcalloc(nmaps, sizeof(*map), GFP_KERNEL);
+ if (!map)
+ return -ENOMEM;
+
+ nmaps = 0;
+ ngroups = 0;
+ mutex_lock(&sfp->mutex);
+ for_each_child_of_node(np, child) {
+ int npins = of_property_count_u32_elems(child, "pinmux");
+ int *pins;
+ u32 *pinmux;
+ int i;
+
+ if (npins < 1) {
+ dev_err(dev,
+ "invalid pinctrl group %pOFn.%pOFn: pinmux not set\n",
+ np, child);
+ ret = -EINVAL;
+ goto put_child;
+ }
+
+ grpname = devm_kasprintf(dev, GFP_KERNEL, "%pOFn.%pOFn", np, child);
+ if (!grpname) {
+ ret = -ENOMEM;
+ goto put_child;
+ }
+
+ pgnames[ngroups++] = grpname;
+
+ pins = devm_kcalloc(dev, npins, sizeof(*pins), GFP_KERNEL);
+ if (!pins) {
+ ret = -ENOMEM;
+ goto put_child;
+ }
+
+ pinmux = devm_kcalloc(dev, npins, sizeof(*pinmux), GFP_KERNEL);
+ if (!pinmux) {
+ ret = -ENOMEM;
+ goto put_child;
+ }
+
+ ret = of_property_read_u32_array(child, "pinmux", pinmux, npins);
+ if (ret)
+ goto put_child;
+
+ for (i = 0; i < npins; i++)
+ pins[i] = jh7110_pinmux_pin(pinmux[i]);
+
+ map[nmaps].type = PIN_MAP_TYPE_MUX_GROUP;
+ map[nmaps].data.mux.function = np->name;
+ map[nmaps].data.mux.group = grpname;
+ nmaps += 1;
+
+ ret = pinctrl_generic_add_group(pctldev, grpname,
+ pins, npins, pinmux);
+ if (ret < 0) {
+ dev_err(dev, "error adding group %s: %d\n", grpname, ret);
+ goto put_child;
+ }
+
+ ret = pinconf_generic_parse_dt_config(child, pctldev,
+ &map[nmaps].data.configs.configs,
+ &map[nmaps].data.configs.num_configs);
+ if (ret) {
+ dev_err(dev, "error parsing pin config of group %s: %d\n",
+ grpname, ret);
+ goto put_child;
+ }
+
+ /* don't create a map if there are no pinconf settings */
+ if (map[nmaps].data.configs.num_configs == 0)
+ continue;
+
+ map[nmaps].type = PIN_MAP_TYPE_CONFIGS_GROUP;
+ map[nmaps].data.configs.group_or_pin = grpname;
+ nmaps += 1;
+ }
+
+ ret = pinmux_generic_add_function(pctldev, np->name,
+ pgnames, ngroups, NULL);
+ if (ret < 0) {
+ dev_err(dev, "error adding function %s: %d\n", np->name, ret);
+ goto free_map;
+ }
+ mutex_unlock(&sfp->mutex);
+
+ *maps = map;
+ *num_maps = nmaps;
+ return 0;
+
+put_child:
+ of_node_put(child);
+free_map:
+ pinctrl_utils_free_map(pctldev, map, nmaps);
+ mutex_unlock(&sfp->mutex);
+ return ret;
+}
+
+static const struct pinctrl_ops jh7110_pinctrl_ops = {
+ .get_groups_count = pinctrl_generic_get_group_count,
+ .get_group_name = pinctrl_generic_get_group_name,
+ .get_group_pins = pinctrl_generic_get_group_pins,
+ .pin_dbg_show = jh7110_pin_dbg_show,
+ .dt_node_to_map = jh7110_dt_node_to_map,
+ .dt_free_map = pinctrl_utils_free_map,
+};
+
+void jh7110_set_gpiomux(struct jh7110_pinctrl *sfp, unsigned int pin,
+ unsigned int din, u32 dout, u32 doen)
+{
+ const struct jh7110_pinctrl_soc_info *info = sfp->info;
+
+ unsigned int offset = 4 * (pin / 4);
+ unsigned int shift = 8 * (pin % 4);
+ u32 dout_mask = info->dout_mask << shift;
+ u32 done_mask = info->doen_mask << shift;
+ u32 ival, imask;
+ void __iomem *reg_dout;
+ void __iomem *reg_doen;
+ void __iomem *reg_din;
+ unsigned long flags;
+
+ reg_dout = sfp->base + info->dout_reg_base + offset;
+ reg_doen = sfp->base + info->doen_reg_base + offset;
+ dout <<= shift;
+ doen <<= shift;
+ if (din != GPI_NONE) {
+ unsigned int ioffset = 4 * (din / 4);
+ unsigned int ishift = 8 * (din % 4);
+
+ reg_din = sfp->base + info->gpi_reg_base + ioffset;
+ ival = (pin + 2) << ishift;
+ imask = info->gpi_mask << ishift;
+ } else {
+ reg_din = NULL;
+ }
+
+ raw_spin_lock_irqsave(&sfp->lock, flags);
+ dout |= readl_relaxed(reg_dout) & ~dout_mask;
+ writel_relaxed(dout, reg_dout);
+ doen |= readl_relaxed(reg_doen) & ~done_mask;
+ writel_relaxed(doen, reg_doen);
+ if (reg_din) {
+ ival |= readl_relaxed(reg_din) & ~imask;
+ writel_relaxed(ival, reg_din);
+ }
+ raw_spin_unlock_irqrestore(&sfp->lock, flags);
+}
+EXPORT_SYMBOL_GPL(jh7110_set_gpiomux);
+
+static int jh7110_set_mux(struct pinctrl_dev *pctldev,
+ unsigned int fsel, unsigned int gsel)
+{
+ struct jh7110_pinctrl *sfp = pinctrl_dev_get_drvdata(pctldev);
+ const struct jh7110_pinctrl_soc_info *info = sfp->info;
+ const struct group_desc *group;
+ const u32 *pinmux;
+ unsigned int i;
+
+ group = pinctrl_generic_get_group(pctldev, gsel);
+ if (!group)
+ return -EINVAL;
+
+ pinmux = group->data;
+ for (i = 0; i < group->num_pins; i++) {
+ u32 v = pinmux[i];
+
+ if (info->jh7110_set_one_pin_mux)
+ info->jh7110_set_one_pin_mux(sfp,
+ jh7110_pinmux_pin(v),
+ jh7110_pinmux_din(v),
+ jh7110_pinmux_dout(v),
+ jh7110_pinmux_doen(v),
+ jh7110_pinmux_function(v));
+ }
+
+ return 0;
+}
+
+static const struct pinmux_ops jh7110_pinmux_ops = {
+ .get_functions_count = pinmux_generic_get_function_count,
+ .get_function_name = pinmux_generic_get_function_name,
+ .get_function_groups = pinmux_generic_get_function_groups,
+ .set_mux = jh7110_set_mux,
+ .strict = true,
+};
+
+static const u8 jh7110_drive_strength_mA[4] = { 2, 4, 8, 12 };
+
+static u32 jh7110_padcfg_ds_to_mA(u32 padcfg)
+{
+ return jh7110_drive_strength_mA[(padcfg >> 1) & 3U];
+}
+
+static u32 jh7110_padcfg_ds_from_mA(u32 v)
+{
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ if (v <= jh7110_drive_strength_mA[i])
+ break;
+ }
+ return i << 1;
+}
+
+static void jh7110_padcfg_rmw(struct jh7110_pinctrl *sfp,
+ unsigned int pin, u32 mask, u32 value)
+{
+ const struct jh7110_pinctrl_soc_info *info = sfp->info;
+ void __iomem *reg;
+ unsigned long flags;
+ int padcfg_base;
+
+ if (!info->jh7110_get_padcfg_base)
+ return;
+
+ padcfg_base = info->jh7110_get_padcfg_base(sfp, pin);
+ if (padcfg_base < 0)
+ return;
+
+ reg = sfp->base + padcfg_base + 4 * pin;
+ value &= mask;
+
+ raw_spin_lock_irqsave(&sfp->lock, flags);
+ value |= readl_relaxed(reg) & ~mask;
+ writel_relaxed(value, reg);
+ raw_spin_unlock_irqrestore(&sfp->lock, flags);
+}
+
+static int jh7110_pinconf_get(struct pinctrl_dev *pctldev,
+ unsigned int pin, unsigned long *config)
+{
+ struct jh7110_pinctrl *sfp = pinctrl_dev_get_drvdata(pctldev);
+ const struct jh7110_pinctrl_soc_info *info = sfp->info;
+ int param = pinconf_to_config_param(*config);
+ u32 padcfg, arg;
+ bool enabled;
+ int padcfg_base;
+
+ if (!info->jh7110_get_padcfg_base)
+ return 0;
+
+ padcfg_base = info->jh7110_get_padcfg_base(sfp, pin);
+ if (padcfg_base < 0)
+ return 0;
+
+ padcfg = readl_relaxed(sfp->base + padcfg_base + 4 * pin);
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ enabled = !(padcfg & JH7110_PADCFG_BIAS);
+ arg = 0;
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ enabled = padcfg & JH7110_PADCFG_PD;
+ arg = 1;
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ enabled = padcfg & JH7110_PADCFG_PU;
+ arg = 1;
+ break;
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ enabled = true;
+ arg = jh7110_padcfg_ds_to_mA(padcfg);
+ break;
+ case PIN_CONFIG_INPUT_ENABLE:
+ enabled = padcfg & JH7110_PADCFG_IE;
+ arg = enabled;
+ break;
+ case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+ enabled = padcfg & JH7110_PADCFG_SMT;
+ arg = enabled;
+ break;
+ case PIN_CONFIG_SLEW_RATE:
+ enabled = true;
+ arg = !!(padcfg & JH7110_PADCFG_SLEW);
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+ *config = pinconf_to_config_packed(param, arg);
+ return enabled ? 0 : -EINVAL;
+}
+
+static int jh7110_pinconf_group_get(struct pinctrl_dev *pctldev,
+ unsigned int gsel,
+ unsigned long *config)
+{
+ const struct group_desc *group;
+
+ group = pinctrl_generic_get_group(pctldev, gsel);
+ if (!group)
+ return -EINVAL;
+
+ return jh7110_pinconf_get(pctldev, group->pins[0], config);
+}
+
+static int jh7110_pinconf_group_set(struct pinctrl_dev *pctldev,
+ unsigned int gsel,
+ unsigned long *configs,
+ unsigned int num_configs)
+{
+ struct jh7110_pinctrl *sfp = pinctrl_dev_get_drvdata(pctldev);
+ const struct group_desc *group;
+ u16 mask, value;
+ int i;
+
+ group = pinctrl_generic_get_group(pctldev, gsel);
+ if (!group)
+ return -EINVAL;
+
+ mask = 0;
+ value = 0;
+ for (i = 0; i < num_configs; i++) {
+ int param = pinconf_to_config_param(configs[i]);
+ u32 arg = pinconf_to_config_argument(configs[i]);
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ mask |= JH7110_PADCFG_BIAS;
+ value &= ~JH7110_PADCFG_BIAS;
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ if (arg == 0)
+ return -ENOTSUPP;
+ mask |= JH7110_PADCFG_BIAS;
+ value = (value & ~JH7110_PADCFG_BIAS) | JH7110_PADCFG_PD;
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ if (arg == 0)
+ return -ENOTSUPP;
+ mask |= JH7110_PADCFG_BIAS;
+ value = (value & ~JH7110_PADCFG_BIAS) | JH7110_PADCFG_PU;
+ break;
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ mask |= JH7110_PADCFG_DS_MASK;
+ value = (value & ~JH7110_PADCFG_DS_MASK) |
+ jh7110_padcfg_ds_from_mA(arg);
+ break;
+ case PIN_CONFIG_INPUT_ENABLE:
+ mask |= JH7110_PADCFG_IE;
+ if (arg)
+ value |= JH7110_PADCFG_IE;
+ else
+ value &= ~JH7110_PADCFG_IE;
+ break;
+ case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+ mask |= JH7110_PADCFG_SMT;
+ if (arg)
+ value |= JH7110_PADCFG_SMT;
+ else
+ value &= ~JH7110_PADCFG_SMT;
+ break;
+ case PIN_CONFIG_SLEW_RATE:
+ mask |= JH7110_PADCFG_SLEW;
+ if (arg)
+ value |= JH7110_PADCFG_SLEW;
+ else
+ value &= ~JH7110_PADCFG_SLEW;
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+ }
+
+ for (i = 0; i < group->num_pins; i++)
+ jh7110_padcfg_rmw(sfp, group->pins[i], mask, value);
+
+ return 0;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static void jh7110_pinconf_dbg_show(struct pinctrl_dev *pctldev,
+ struct seq_file *s, unsigned int pin)
+{
+ struct jh7110_pinctrl *sfp = pinctrl_dev_get_drvdata(pctldev);
+ const struct jh7110_pinctrl_soc_info *info = sfp->info;
+ u32 value;
+ int padcfg_base;
+
+ if (!info->jh7110_get_padcfg_base)
+ return;
+
+ padcfg_base = info->jh7110_get_padcfg_base(sfp, pin);
+ if (padcfg_base < 0)
+ return;
+
+ value = readl_relaxed(sfp->base + padcfg_base + 4 * pin);
+ seq_printf(s, " (0x%02x)", value);
+}
+#else
+#define jh7110_pinconf_dbg_show NULL
+#endif
+
+static const struct pinconf_ops jh7110_pinconf_ops = {
+ .pin_config_get = jh7110_pinconf_get,
+ .pin_config_group_get = jh7110_pinconf_group_get,
+ .pin_config_group_set = jh7110_pinconf_group_set,
+ .pin_config_dbg_show = jh7110_pinconf_dbg_show,
+ .is_generic = true,
+};
+
+static int jh7110_gpio_request(struct gpio_chip *gc, unsigned int gpio)
+{
+ return pinctrl_gpio_request(gc->base + gpio);
+}
+
+static void jh7110_gpio_free(struct gpio_chip *gc, unsigned int gpio)
+{
+ pinctrl_gpio_free(gc->base + gpio);
+}
+
+static int jh7110_gpio_get_direction(struct gpio_chip *gc,
+ unsigned int gpio)
+{
+ struct jh7110_pinctrl *sfp = container_of(gc,
+ struct jh7110_pinctrl, gc);
+ const struct jh7110_pinctrl_soc_info *info = sfp->info;
+ unsigned int offset = 4 * (gpio / 4);
+ unsigned int shift = 8 * (gpio % 4);
+ u32 doen = readl_relaxed(sfp->base + info->doen_reg_base + offset);
+
+ doen = (doen >> shift) & info->doen_mask;
+
+ return doen == GPOEN_ENABLE ?
+ GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN;
+}
+
+static int jh7110_gpio_direction_input(struct gpio_chip *gc,
+ unsigned int gpio)
+{
+ struct jh7110_pinctrl *sfp = container_of(gc,
+ struct jh7110_pinctrl, gc);
+ const struct jh7110_pinctrl_soc_info *info = sfp->info;
+
+ /* enable input and schmitt trigger */
+ jh7110_padcfg_rmw(sfp, gpio,
+ JH7110_PADCFG_IE | JH7110_PADCFG_SMT,
+ JH7110_PADCFG_IE | JH7110_PADCFG_SMT);
+
+ if (info->jh7110_set_one_pin_mux)
+ info->jh7110_set_one_pin_mux(sfp, gpio,
+ GPI_NONE, GPOUT_LOW, GPOEN_DISABLE, 0);
+
+ return 0;
+}
+
+static int jh7110_gpio_direction_output(struct gpio_chip *gc,
+ unsigned int gpio, int value)
+{
+ struct jh7110_pinctrl *sfp = container_of(gc,
+ struct jh7110_pinctrl, gc);
+ const struct jh7110_pinctrl_soc_info *info = sfp->info;
+
+ if (info->jh7110_set_one_pin_mux)
+ info->jh7110_set_one_pin_mux(sfp, gpio,
+ GPI_NONE, value ? GPOUT_HIGH : GPOUT_LOW,
+ GPOEN_ENABLE, 0);
+
+ /* disable input, schmitt trigger and bias */
+ jh7110_padcfg_rmw(sfp, gpio,
+ JH7110_PADCFG_IE | JH7110_PADCFG_SMT |
+ JH7110_PADCFG_BIAS, 0);
+ return 0;
+}
+
+static int jh7110_gpio_get(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct jh7110_pinctrl *sfp = container_of(gc,
+ struct jh7110_pinctrl, gc);
+ const struct jh7110_pinctrl_soc_info *info = sfp->info;
+ void __iomem *reg = sfp->base + info->gpioin_reg_base
+ + 4 * (gpio / 32);
+
+ return !!(readl_relaxed(reg) & BIT(gpio % 32));
+}
+
+static void jh7110_gpio_set(struct gpio_chip *gc,
+ unsigned int gpio, int value)
+{
+ struct jh7110_pinctrl *sfp = container_of(gc,
+ struct jh7110_pinctrl, gc);
+ const struct jh7110_pinctrl_soc_info *info = sfp->info;
+ unsigned int offset = 4 * (gpio / 4);
+ unsigned int shift = 8 * (gpio % 4);
+ void __iomem *reg_dout = sfp->base + info->dout_reg_base + offset;
+ u32 dout = (value ? GPOUT_HIGH : GPOUT_LOW) << shift;
+ u32 mask = info->dout_mask << shift;
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&sfp->lock, flags);
+ dout |= readl_relaxed(reg_dout) & ~mask;
+ writel_relaxed(dout, reg_dout);
+ raw_spin_unlock_irqrestore(&sfp->lock, flags);
+}
+
+static int jh7110_gpio_set_config(struct gpio_chip *gc,
+ unsigned int gpio, unsigned long config)
+{
+ struct jh7110_pinctrl *sfp = container_of(gc,
+ struct jh7110_pinctrl, gc);
+ u32 arg = pinconf_to_config_argument(config);
+ u32 value;
+ u32 mask;
+
+ switch (pinconf_to_config_param(config)) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ mask = JH7110_PADCFG_BIAS;
+ value = 0;
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ if (arg == 0)
+ return -ENOTSUPP;
+ mask = JH7110_PADCFG_BIAS;
+ value = JH7110_PADCFG_PD;
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ if (arg == 0)
+ return -ENOTSUPP;
+ mask = JH7110_PADCFG_BIAS;
+ value = JH7110_PADCFG_PU;
+ break;
+ case PIN_CONFIG_DRIVE_PUSH_PULL:
+ return 0;
+ case PIN_CONFIG_INPUT_ENABLE:
+ mask = JH7110_PADCFG_IE;
+ value = arg ? JH7110_PADCFG_IE : 0;
+ break;
+ case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+ mask = JH7110_PADCFG_SMT;
+ value = arg ? JH7110_PADCFG_SMT : 0;
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+ jh7110_padcfg_rmw(sfp, gpio, mask, value);
+ return 0;
+}
+
+static int jh7110_gpio_add_pin_ranges(struct gpio_chip *gc)
+{
+ struct jh7110_pinctrl *sfp = container_of(gc,
+ struct jh7110_pinctrl, gc);
+
+ sfp->gpios.name = sfp->gc.label;
+ sfp->gpios.base = sfp->gc.base;
+ sfp->gpios.pin_base = 0;
+ sfp->gpios.npins = sfp->gc.ngpio;
+ sfp->gpios.gc = &sfp->gc;
+ pinctrl_add_gpio_range(sfp->pctl, &sfp->gpios);
+ return 0;
+}
+
+static void jh7110_irq_ack(struct irq_data *d)
+{
+ struct jh7110_pinctrl *sfp = jh7110_from_irq_data(d);
+ const struct jh7110_gpio_irq_reg *irq_reg = sfp->info->irq_reg;
+ irq_hw_number_t gpio = irqd_to_hwirq(d);
+ void __iomem *ic = sfp->base + irq_reg->ic_reg_base
+ + 4 * (gpio / 32);
+ u32 mask = BIT(gpio % 32);
+ unsigned long flags;
+ u32 value;
+
+ raw_spin_lock_irqsave(&sfp->lock, flags);
+ value = readl_relaxed(ic) & ~mask;
+ writel_relaxed(value, ic);
+ writel_relaxed(value | mask, ic);
+ raw_spin_unlock_irqrestore(&sfp->lock, flags);
+}
+
+static void jh7110_irq_mask(struct irq_data *d)
+{
+ struct jh7110_pinctrl *sfp = jh7110_from_irq_data(d);
+ const struct jh7110_gpio_irq_reg *irq_reg = sfp->info->irq_reg;
+ irq_hw_number_t gpio = irqd_to_hwirq(d);
+ void __iomem *ie = sfp->base + irq_reg->ie_reg_base
+ + 4 * (gpio / 32);
+ u32 mask = BIT(gpio % 32);
+ unsigned long flags;
+ u32 value;
+
+ raw_spin_lock_irqsave(&sfp->lock, flags);
+ value = readl_relaxed(ie) & ~mask;
+ writel_relaxed(value, ie);
+ raw_spin_unlock_irqrestore(&sfp->lock, flags);
+
+ gpiochip_disable_irq(&sfp->gc, d->hwirq);
+}
+
+static void jh7110_irq_mask_ack(struct irq_data *d)
+{
+ struct jh7110_pinctrl *sfp = jh7110_from_irq_data(d);
+ const struct jh7110_gpio_irq_reg *irq_reg = sfp->info->irq_reg;
+ irq_hw_number_t gpio = irqd_to_hwirq(d);
+ void __iomem *ie = sfp->base + irq_reg->ie_reg_base
+ + 4 * (gpio / 32);
+ void __iomem *ic = sfp->base + irq_reg->ic_reg_base
+ + 4 * (gpio / 32);
+ u32 mask = BIT(gpio % 32);
+ unsigned long flags;
+ u32 value;
+
+ raw_spin_lock_irqsave(&sfp->lock, flags);
+ value = readl_relaxed(ie) & ~mask;
+ writel_relaxed(value, ie);
+
+ value = readl_relaxed(ic) & ~mask;
+ writel_relaxed(value, ic);
+ writel_relaxed(value | mask, ic);
+ raw_spin_unlock_irqrestore(&sfp->lock, flags);
+}
+
+static void jh7110_irq_unmask(struct irq_data *d)
+{
+ struct jh7110_pinctrl *sfp = jh7110_from_irq_data(d);
+ const struct jh7110_gpio_irq_reg *irq_reg = sfp->info->irq_reg;
+ irq_hw_number_t gpio = irqd_to_hwirq(d);
+ void __iomem *ie = sfp->base + irq_reg->ie_reg_base
+ + 4 * (gpio / 32);
+ u32 mask = BIT(gpio % 32);
+ unsigned long flags;
+ u32 value;
+
+ gpiochip_enable_irq(&sfp->gc, d->hwirq);
+
+ raw_spin_lock_irqsave(&sfp->lock, flags);
+ value = readl_relaxed(ie) | mask;
+ writel_relaxed(value, ie);
+ raw_spin_unlock_irqrestore(&sfp->lock, flags);
+}
+
+static int jh7110_irq_set_type(struct irq_data *d, unsigned int trigger)
+{
+ struct jh7110_pinctrl *sfp = jh7110_from_irq_data(d);
+ const struct jh7110_gpio_irq_reg *irq_reg = sfp->info->irq_reg;
+ irq_hw_number_t gpio = irqd_to_hwirq(d);
+ void __iomem *base = sfp->base + 4 * (gpio / 32);
+ u32 mask = BIT(gpio % 32);
+ u32 irq_type, edge_both, polarity;
+ unsigned long flags;
+
+ switch (trigger) {
+ case IRQ_TYPE_EDGE_RISING:
+ irq_type = mask; /* 1: edge triggered */
+ edge_both = 0; /* 0: single edge */
+ polarity = mask; /* 1: rising edge */
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ irq_type = mask; /* 1: edge triggered */
+ edge_both = 0; /* 0: single edge */
+ polarity = 0; /* 0: falling edge */
+ break;
+ case IRQ_TYPE_EDGE_BOTH:
+ irq_type = mask; /* 1: edge triggered */
+ edge_both = mask; /* 1: both edges */
+ polarity = 0; /* 0: ignored */
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ irq_type = 0; /* 0: level triggered */
+ edge_both = 0; /* 0: ignored */
+ polarity = mask; /* 1: high level */
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ irq_type = 0; /* 0: level triggered */
+ edge_both = 0; /* 0: ignored */
+ polarity = 0; /* 0: low level */
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (trigger & IRQ_TYPE_EDGE_BOTH)
+ irq_set_handler_locked(d, handle_edge_irq);
+ else
+ irq_set_handler_locked(d, handle_level_irq);
+
+ raw_spin_lock_irqsave(&sfp->lock, flags);
+ irq_type |= readl_relaxed(base + irq_reg->is_reg_base) & ~mask;
+ writel_relaxed(irq_type, base + irq_reg->is_reg_base);
+
+ edge_both |= readl_relaxed(base + irq_reg->ibe_reg_base) & ~mask;
+ writel_relaxed(edge_both, base + irq_reg->ibe_reg_base);
+
+ polarity |= readl_relaxed(base + irq_reg->iev_reg_base) & ~mask;
+ writel_relaxed(polarity, base + irq_reg->iev_reg_base);
+ raw_spin_unlock_irqrestore(&sfp->lock, flags);
+ return 0;
+}
+
+static struct irq_chip jh7110_irq_chip = {
+ .irq_ack = jh7110_irq_ack,
+ .irq_mask = jh7110_irq_mask,
+ .irq_mask_ack = jh7110_irq_mask_ack,
+ .irq_unmask = jh7110_irq_unmask,
+ .irq_set_type = jh7110_irq_set_type,
+ .flags = IRQCHIP_IMMUTABLE | IRQCHIP_SET_TYPE_MASKED,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
+
+static void jh7110_disable_clock(void *data)
+{
+ clk_disable_unprepare(data);
+}
+
+int jh7110_pinctrl_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ const struct jh7110_pinctrl_soc_info *info;
+ struct jh7110_pinctrl *sfp;
+ struct pinctrl_desc *jh7110_pinctrl_desc;
+ struct reset_control *rst;
+ struct clk *clk;
+ int ret;
+
+ info = of_device_get_match_data(&pdev->dev);
+ if (!info)
+ return -ENODEV;
+
+ if (!info->pins || !info->npins) {
+ dev_err(dev, "wrong pinctrl info\n");
+ return -EINVAL;
+ }
+
+ sfp = devm_kzalloc(dev, sizeof(*sfp), GFP_KERNEL);
+ if (!sfp)
+ return -ENOMEM;
+
+ sfp->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(sfp->base))
+ return PTR_ERR(sfp->base);
+
+ clk = devm_clk_get_optional(dev, NULL);
+ if (IS_ERR(clk))
+ return dev_err_probe(dev, PTR_ERR(clk), "could not get clock\n");
+
+ rst = devm_reset_control_get_exclusive(dev, NULL);
+ if (IS_ERR(rst))
+ return dev_err_probe(dev, PTR_ERR(rst), "could not get reset\n");
+
+ /*
+ * we don't want to assert reset and risk undoing pin muxing for the
+ * early boot serial console, but let's make sure the reset line is
+ * deasserted in case someone runs a really minimal bootloader.
+ */
+ ret = reset_control_deassert(rst);
+ if (ret)
+ return dev_err_probe(dev, ret, "could not deassert reset\n");
+
+ if (clk) {
+ ret = clk_prepare_enable(clk);
+ if (ret)
+ return dev_err_probe(dev, ret, "could not enable clock\n");
+
+ ret = devm_add_action_or_reset(dev, jh7110_disable_clock, clk);
+ if (ret)
+ return ret;
+ }
+
+ jh7110_pinctrl_desc = devm_kzalloc(&pdev->dev,
+ sizeof(*jh7110_pinctrl_desc),
+ GFP_KERNEL);
+ if (!jh7110_pinctrl_desc)
+ return -ENOMEM;
+
+ jh7110_pinctrl_desc->name = dev_name(dev);
+ jh7110_pinctrl_desc->pins = info->pins;
+ jh7110_pinctrl_desc->npins = info->npins;
+ jh7110_pinctrl_desc->pctlops = &jh7110_pinctrl_ops;
+ jh7110_pinctrl_desc->pmxops = &jh7110_pinmux_ops;
+ jh7110_pinctrl_desc->confops = &jh7110_pinconf_ops;
+ jh7110_pinctrl_desc->owner = THIS_MODULE;
+
+ sfp->info = info;
+ sfp->dev = dev;
+ platform_set_drvdata(pdev, sfp);
+ sfp->gc.parent = dev;
+ raw_spin_lock_init(&sfp->lock);
+ mutex_init(&sfp->mutex);
+
+ ret = devm_pinctrl_register_and_init(dev,
+ jh7110_pinctrl_desc,
+ sfp, &sfp->pctl);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "could not register pinctrl driver\n");
+
+ sfp->gc.label = dev_name(dev);
+ sfp->gc.owner = THIS_MODULE;
+ sfp->gc.request = jh7110_gpio_request;
+ sfp->gc.free = jh7110_gpio_free;
+ sfp->gc.get_direction = jh7110_gpio_get_direction;
+ sfp->gc.direction_input = jh7110_gpio_direction_input;
+ sfp->gc.direction_output = jh7110_gpio_direction_output;
+ sfp->gc.get = jh7110_gpio_get;
+ sfp->gc.set = jh7110_gpio_set;
+ sfp->gc.set_config = jh7110_gpio_set_config;
+ sfp->gc.add_pin_ranges = jh7110_gpio_add_pin_ranges;
+ sfp->gc.base = info->gc_base;
+ sfp->gc.ngpio = info->ngpios;
+
+ jh7110_irq_chip.name = sfp->gc.label;
+ gpio_irq_chip_set_chip(&sfp->gc.irq, &jh7110_irq_chip);
+ sfp->gc.irq.parent_handler = info->jh7110_gpio_irq_handler;
+ sfp->gc.irq.num_parents = 1;
+ sfp->gc.irq.parents = devm_kcalloc(dev, sfp->gc.irq.num_parents,
+ sizeof(*sfp->gc.irq.parents),
+ GFP_KERNEL);
+ if (!sfp->gc.irq.parents)
+ return -ENOMEM;
+ sfp->gc.irq.default_type = IRQ_TYPE_NONE;
+ sfp->gc.irq.handler = handle_bad_irq;
+ sfp->gc.irq.init_hw = info->jh7110_gpio_init_hw;
+
+ ret = platform_get_irq(pdev, 0);
+ if (ret < 0)
+ return ret;
+ sfp->gc.irq.parents[0] = ret;
+
+ ret = devm_gpiochip_add_data(dev, &sfp->gc, sfp);
+ if (ret)
+ return dev_err_probe(dev, ret, "could not register gpiochip\n");
+
+ irq_domain_set_pm_device(sfp->gc.irq.domain, dev);
+
+ dev_info(dev, "StarFive GPIO chip registered %d GPIOs\n", sfp->gc.ngpio);
+
+ return pinctrl_enable(sfp->pctl);
+}
+EXPORT_SYMBOL_GPL(jh7110_pinctrl_probe);
+
+MODULE_DESCRIPTION("Pinctrl driver for the StarFive JH7110 SoC");
+MODULE_AUTHOR("Emil Renner Berthing <kernel@esmil.dk>");
+MODULE_AUTHOR("Jianlong Huang <jianlong.huang@starfivetech.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jh7110.h b/drivers/pinctrl/starfive/pinctrl-starfive-jh7110.h
new file mode 100644
index 000000000000..3f20b7ff96dd
--- /dev/null
+++ b/drivers/pinctrl/starfive/pinctrl-starfive-jh7110.h
@@ -0,0 +1,70 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Pinctrl / GPIO driver for StarFive JH7110 SoC
+ *
+ * Copyright (C) 2022 StarFive Technology Co., Ltd.
+ */
+
+#ifndef __PINCTRL_STARFIVE_JH7110_H__
+#define __PINCTRL_STARFIVE_JH7110_H__
+
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinmux.h>
+
+struct jh7110_pinctrl {
+ struct device *dev;
+ struct gpio_chip gc;
+ struct pinctrl_gpio_range gpios;
+ raw_spinlock_t lock;
+ void __iomem *base;
+ struct pinctrl_dev *pctl;
+ /* register read/write mutex */
+ struct mutex mutex;
+ const struct jh7110_pinctrl_soc_info *info;
+};
+
+struct jh7110_gpio_irq_reg {
+ unsigned int is_reg_base;
+ unsigned int ic_reg_base;
+ unsigned int ibe_reg_base;
+ unsigned int iev_reg_base;
+ unsigned int ie_reg_base;
+ unsigned int ris_reg_base;
+ unsigned int mis_reg_base;
+};
+
+struct jh7110_pinctrl_soc_info {
+ const struct pinctrl_pin_desc *pins;
+ unsigned int npins;
+ unsigned int ngpios;
+ unsigned int gc_base;
+
+ /* gpio dout/doen/din/gpioinput register */
+ unsigned int dout_reg_base;
+ unsigned int dout_mask;
+ unsigned int doen_reg_base;
+ unsigned int doen_mask;
+ unsigned int gpi_reg_base;
+ unsigned int gpi_mask;
+ unsigned int gpioin_reg_base;
+
+ const struct jh7110_gpio_irq_reg *irq_reg;
+
+ /* generic pinmux */
+ int (*jh7110_set_one_pin_mux)(struct jh7110_pinctrl *sfp,
+ unsigned int pin,
+ unsigned int din, u32 dout,
+ u32 doen, u32 func);
+ /* gpio chip */
+ int (*jh7110_get_padcfg_base)(struct jh7110_pinctrl *sfp,
+ unsigned int pin);
+ void (*jh7110_gpio_irq_handler)(struct irq_desc *desc);
+ int (*jh7110_gpio_init_hw)(struct gpio_chip *gc);
+};
+
+void jh7110_set_gpiomux(struct jh7110_pinctrl *sfp, unsigned int pin,
+ unsigned int din, u32 dout, u32 doen);
+int jh7110_pinctrl_probe(struct platform_device *pdev);
+struct jh7110_pinctrl *jh7110_from_irq_desc(struct irq_desc *desc);
+
+#endif /* __PINCTRL_STARFIVE_JH7110_H__ */
diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.c b/drivers/pinctrl/stm32/pinctrl-stm32.c
index 1cddca506ad7..cb33a23ab0c1 100644
--- a/drivers/pinctrl/stm32/pinctrl-stm32.c
+++ b/drivers/pinctrl/stm32/pinctrl-stm32.c
@@ -1382,6 +1382,7 @@ static struct irq_domain *stm32_pctrl_get_irq_domain(struct platform_device *pde
return ERR_PTR(-ENXIO);
domain = irq_find_host(parent);
+ of_node_put(parent);
if (!domain)
/* domain not registered yet */
return ERR_PTR(-EPROBE_DEFER);
diff --git a/drivers/pinctrl/sunplus/sppctl.c b/drivers/pinctrl/sunplus/sppctl.c
index 25101293268f..6bbbab3a6fdf 100644
--- a/drivers/pinctrl/sunplus/sppctl.c
+++ b/drivers/pinctrl/sunplus/sppctl.c
@@ -553,7 +553,6 @@ static int sppctl_gpio_new(struct platform_device *pdev, struct sppctl_pdata *pc
gchip->base = -1;
gchip->ngpio = sppctl_gpio_list_sz;
gchip->names = sppctl_gpio_list_s;
- gchip->of_gpio_n_cells = 2;
pctl->pctl_grange.npins = gchip->ngpio;
pctl->pctl_grange.name = gchip->label;
diff --git a/drivers/platform/surface/aggregator/bus.c b/drivers/platform/surface/aggregator/bus.c
index 7004eb4a63a2..aaad41294200 100644
--- a/drivers/platform/surface/aggregator/bus.c
+++ b/drivers/platform/surface/aggregator/bus.c
@@ -35,9 +35,9 @@ static struct attribute *ssam_device_attrs[] = {
};
ATTRIBUTE_GROUPS(ssam_device);
-static int ssam_device_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int ssam_device_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct ssam_device *sdev = to_ssam_device(dev);
+ const struct ssam_device *sdev = to_ssam_device(dev);
return add_uevent_var(env, "MODALIAS=ssam:d%02Xc%02Xt%02Xi%02Xf%02X",
sdev->uid.domain, sdev->uid.category,
diff --git a/drivers/platform/x86/asus-tf103c-dock.c b/drivers/platform/x86/asus-tf103c-dock.c
index 62310e06282b..aeb1138464df 100644
--- a/drivers/platform/x86/asus-tf103c-dock.c
+++ b/drivers/platform/x86/asus-tf103c-dock.c
@@ -250,7 +250,7 @@ static int tf103c_dock_hid_raw_request(struct hid_device *hid, u8 reportnum,
return 0;
}
-static struct hid_ll_driver tf103c_dock_hid_ll_driver = {
+static const struct hid_ll_driver tf103c_dock_hid_ll_driver = {
.parse = tf103c_dock_hid_parse,
.start = tf103c_dock_hid_start,
.stop = tf103c_dock_hid_stop,
@@ -259,7 +259,7 @@ static struct hid_ll_driver tf103c_dock_hid_ll_driver = {
.raw_request = tf103c_dock_hid_raw_request,
};
-static int tf103c_dock_toprow_codes[13][2] = {
+static const int tf103c_dock_toprow_codes[13][2] = {
/* Normal, AltGr pressed */
{ KEY_POWER, KEY_F1 },
{ KEY_RFKILL, KEY_F2 },
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
index 5ffc00480aef..4fe7650dd014 100644
--- a/drivers/platform/x86/wmi.c
+++ b/drivers/platform/x86/wmi.c
@@ -693,15 +693,8 @@ char *wmi_get_acpi_device_uid(const char *guid_string)
}
EXPORT_SYMBOL_GPL(wmi_get_acpi_device_uid);
-static struct wmi_block *dev_to_wblock(struct device *dev)
-{
- return container_of(dev, struct wmi_block, dev.dev);
-}
-
-static struct wmi_device *dev_to_wdev(struct device *dev)
-{
- return container_of(dev, struct wmi_device, dev);
-}
+#define dev_to_wblock(__dev) container_of_const(__dev, struct wmi_block, dev.dev)
+#define dev_to_wdev(__dev) container_of_const(__dev, struct wmi_device, dev)
static inline struct wmi_driver *drv_to_wdrv(struct device_driver *drv)
{
@@ -804,9 +797,9 @@ static struct attribute *wmi_method_attrs[] = {
};
ATTRIBUTE_GROUPS(wmi_method);
-static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int wmi_dev_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct wmi_block *wblock = dev_to_wblock(dev);
+ const struct wmi_block *wblock = dev_to_wblock(dev);
if (add_uevent_var(env, "MODALIAS=wmi:%pUL", &wblock->gblock.guid))
return -ENOMEM;
diff --git a/drivers/platform/x86/x86-android-tablets.c b/drivers/platform/x86/x86-android-tablets.c
index 123a4618db55..111b007656fc 100644
--- a/drivers/platform/x86/x86-android-tablets.c
+++ b/drivers/platform/x86/x86-android-tablets.c
@@ -187,7 +187,7 @@ struct x86_dev_info {
/* Generic / shared charger / battery settings */
static const char * const tusb1211_chg_det_psy[] = { "tusb1211-charger-detect" };
static const char * const bq24190_psy[] = { "bq24190-charger" };
-static const char * const bq25890_psy[] = { "bq25890-charger" };
+static const char * const bq25890_psy[] = { "bq25890-charger-0" };
static const struct property_entry fg_bq24190_supply_props[] = {
PROPERTY_ENTRY_STRING_ARRAY("supplied-from", bq24190_psy),
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index a8c46ba5878f..8c87eeda0fec 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -141,6 +141,13 @@ config POWER_RESET_OCELOT_RESET
help
This driver supports restart for Microsemi Ocelot SoC and similar.
+config POWER_RESET_ODROID_GO_ULTRA_POWEROFF
+ bool "Odroid Go Ultra power-off driver"
+ depends on ARCH_MESON || COMPILE_TEST
+ depends on I2C=y && OF
+ help
+ This driver supports Power off for Odroid Go Ultra device.
+
config POWER_RESET_OXNAS
bool "OXNAS SoC restart driver"
depends on ARCH_OXNAS
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
index 0a39424fc558..d763e6735ee3 100644
--- a/drivers/power/reset/Makefile
+++ b/drivers/power/reset/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_POWER_RESET_MT6323) += mt6323-poweroff.o
obj-$(CONFIG_POWER_RESET_OXNAS) += oxnas-restart.o
obj-$(CONFIG_POWER_RESET_QCOM_PON) += qcom-pon.o
obj-$(CONFIG_POWER_RESET_OCELOT_RESET) += ocelot-reset.o
+obj-$(CONFIG_POWER_RESET_ODROID_GO_ULTRA_POWEROFF) += odroid-go-ultra-poweroff.o
obj-$(CONFIG_POWER_RESET_PIIX4_POWEROFF) += piix4-poweroff.o
obj-$(CONFIG_POWER_RESET_LTC2952) += ltc2952-poweroff.o
obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o
diff --git a/drivers/power/reset/odroid-go-ultra-poweroff.c b/drivers/power/reset/odroid-go-ultra-poweroff.c
new file mode 100644
index 000000000000..f46271da4e8e
--- /dev/null
+++ b/drivers/power/reset/odroid-go-ultra-poweroff.c
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2023 Neil Armstrong <neil.armstrong@linaro.org>
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/of_platform.h>
+#include <linux/mfd/rk808.h>
+#include <linux/regmap.h>
+#include <linux/module.h>
+#include <linux/reboot.h>
+#include <linux/i2c.h>
+
+/*
+ * The Odroid Go Ultra has 2 PMICs:
+ * - RK818 (manages the battery and USB-C power supply)
+ * - RK817
+ * Both PMICs feeds power to the S922X SoC, so they must be powered-off in sequence.
+ * Vendor does power-off the RK817 first, then the RK818 so here we follow this sequence.
+ */
+
+struct odroid_go_ultra_poweroff_data {
+ struct device *dev;
+ struct device *rk817;
+ struct device *rk818;
+};
+
+static int odroid_go_ultra_poweroff_prepare(struct sys_off_data *data)
+{
+ struct odroid_go_ultra_poweroff_data *poweroff_data = data->cb_data;
+ struct regmap *rk817, *rk818;
+ int ret;
+
+ /* RK817 Regmap */
+ rk817 = dev_get_regmap(poweroff_data->rk817, NULL);
+ if (!rk817) {
+ dev_err(poweroff_data->dev, "failed to get rk817 regmap\n");
+ return notifier_from_errno(-EINVAL);
+ }
+
+ /* RK818 Regmap */
+ rk818 = dev_get_regmap(poweroff_data->rk818, NULL);
+ if (!rk818) {
+ dev_err(poweroff_data->dev, "failed to get rk818 regmap\n");
+ return notifier_from_errno(-EINVAL);
+ }
+
+ dev_info(poweroff_data->dev, "Setting PMICs for power off");
+
+ /* RK817 */
+ ret = regmap_update_bits(rk817, RK817_SYS_CFG(3), DEV_OFF, DEV_OFF);
+ if (ret) {
+ dev_err(poweroff_data->dev, "failed to poweroff rk817\n");
+ return notifier_from_errno(ret);
+ }
+
+ /* RK818 */
+ ret = regmap_update_bits(rk818, RK818_DEVCTRL_REG, DEV_OFF, DEV_OFF);
+ if (ret) {
+ dev_err(poweroff_data->dev, "failed to poweroff rk818\n");
+ return notifier_from_errno(ret);
+ }
+
+ return NOTIFY_OK;
+}
+
+static void odroid_go_ultra_poweroff_put_pmic_device(void *data)
+{
+ struct device *dev = data;
+
+ put_device(dev);
+}
+
+static int odroid_go_ultra_poweroff_get_pmic_device(struct device *dev, const char *compatible,
+ struct device **pmic)
+{
+ struct device_node *pmic_node;
+ struct i2c_client *pmic_client;
+
+ pmic_node = of_find_compatible_node(NULL, NULL, compatible);
+ if (!pmic_node)
+ return -ENODEV;
+
+ pmic_client = of_find_i2c_device_by_node(pmic_node);
+ of_node_put(pmic_node);
+ if (!pmic_client)
+ return -EPROBE_DEFER;
+
+ *pmic = &pmic_client->dev;
+
+ return devm_add_action_or_reset(dev, odroid_go_ultra_poweroff_put_pmic_device, *pmic);
+}
+
+static int odroid_go_ultra_poweroff_probe(struct platform_device *pdev)
+{
+ struct odroid_go_ultra_poweroff_data *poweroff_data;
+ int ret;
+
+ poweroff_data = devm_kzalloc(&pdev->dev, sizeof(*poweroff_data), GFP_KERNEL);
+ if (!poweroff_data)
+ return -ENOMEM;
+
+ dev_set_drvdata(&pdev->dev, poweroff_data);
+
+ /* RK818 PMIC Device */
+ ret = odroid_go_ultra_poweroff_get_pmic_device(&pdev->dev, "rockchip,rk818",
+ &poweroff_data->rk818);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "failed to get rk818 mfd data\n");
+
+ /* RK817 PMIC Device */
+ ret = odroid_go_ultra_poweroff_get_pmic_device(&pdev->dev, "rockchip,rk817",
+ &poweroff_data->rk817);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "failed to get rk817 mfd data\n");
+
+ /* Register as SYS_OFF_MODE_POWER_OFF_PREPARE because regmap_update_bits may sleep */
+ ret = devm_register_sys_off_handler(&pdev->dev,
+ SYS_OFF_MODE_POWER_OFF_PREPARE,
+ SYS_OFF_PRIO_DEFAULT,
+ odroid_go_ultra_poweroff_prepare,
+ poweroff_data);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "failed to register sys-off handler\n");
+
+ dev_info(&pdev->dev, "Registered Power-Off handler\n");
+
+ return 0;
+}
+static struct platform_device *pdev;
+
+static struct platform_driver odroid_go_ultra_poweroff_driver = {
+ .driver = {
+ .name = "odroid-go-ultra-poweroff",
+ },
+ .probe = odroid_go_ultra_poweroff_probe,
+};
+
+static int __init odroid_go_ultra_poweroff_init(void)
+{
+ int ret;
+
+ /* Only create when running on the Odroid Go Ultra device */
+ if (!of_device_is_compatible(of_root, "hardkernel,odroid-go-ultra"))
+ return -ENODEV;
+
+ ret = platform_driver_register(&odroid_go_ultra_poweroff_driver);
+ if (ret)
+ return ret;
+
+ pdev = platform_device_register_resndata(NULL, "odroid-go-ultra-poweroff", -1,
+ NULL, 0, NULL, 0);
+
+ if (IS_ERR(pdev)) {
+ platform_driver_unregister(&odroid_go_ultra_poweroff_driver);
+ return PTR_ERR(pdev);
+ }
+
+ return 0;
+}
+
+static void __exit odroid_go_ultra_poweroff_exit(void)
+{
+ /* Only delete when running on the Odroid Go Ultra device */
+ if (!of_device_is_compatible(of_root, "hardkernel,odroid-go-ultra"))
+ return;
+
+ platform_device_unregister(pdev);
+ platform_driver_unregister(&odroid_go_ultra_poweroff_driver);
+}
+
+module_init(odroid_go_ultra_poweroff_init);
+module_exit(odroid_go_ultra_poweroff_exit);
+
+MODULE_AUTHOR("Neil Armstrong <neil.armstrong@linaro.org>");
+MODULE_DESCRIPTION("Odroid Go Ultra poweroff driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/power/reset/syscon-reboot.c b/drivers/power/reset/syscon-reboot.c
index 510e363381ca..45e34e6885f7 100644
--- a/drivers/power/reset/syscon-reboot.c
+++ b/drivers/power/reset/syscon-reboot.c
@@ -44,6 +44,7 @@ static int syscon_reboot_probe(struct platform_device *pdev)
struct syscon_reboot_context *ctx;
struct device *dev = &pdev->dev;
int mask_err, value_err;
+ int priority;
int err;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
@@ -57,6 +58,9 @@ static int syscon_reboot_probe(struct platform_device *pdev)
return PTR_ERR(ctx->map);
}
+ if (of_property_read_s32(pdev->dev.of_node, "priority", &priority))
+ priority = 192;
+
if (of_property_read_u32(pdev->dev.of_node, "offset", &ctx->offset))
return -EINVAL;
@@ -77,7 +81,7 @@ static int syscon_reboot_probe(struct platform_device *pdev)
}
ctx->restart_handler.notifier_call = syscon_restart_handle;
- ctx->restart_handler.priority = 192;
+ ctx->restart_handler.priority = priority;
err = register_restart_handler(&ctx->restart_handler);
if (err)
dev_err(dev, "can't register restart notifier (err=%d)\n", err);
diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index e2f8dfcdd2a9..c78be9f322e6 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -174,6 +174,15 @@ config BATTERY_PMU
Say Y here to expose battery information on Apple machines
through the generic battery class.
+config BATTERY_QCOM_BATTMGR
+ tristate "Qualcomm PMIC GLINK battery manager support"
+ depends on QCOM_PMIC_GLINK
+ select AUXILIARY_BUS
+ help
+ Say Y here to enable the Qualcomm PMIC GLINK power supply driver,
+ which is used on modern Qualcomm platforms to provide battery and
+ power supply information.
+
config BATTERY_OLPC
tristate "One Laptop Per Child battery"
depends on OLPC_EC
@@ -765,6 +774,41 @@ config CHARGER_RT9455
help
Say Y to enable support for Richtek RT9455 battery charger.
+config CHARGER_RT9467
+ tristate "Richtek RT9467 Battery Charger Driver"
+ depends on I2C && GPIOLIB && REGULATOR
+ select REGMAP_I2C
+ select REGMAP_IRQ
+ select LINEAR_RANGES
+ help
+ Say Y here to enable RT9467 Battery Charger.
+ RT9467 is a switch-mode single cell Li-Ion/Li-Polymer battery charger
+ for portable applications. It integrates a synchronous PWM controller,
+ power MOSFETs, input current sensing and regulation, high-accuracy
+ voltage regulation, and charge termination. The charge current is
+ regulated through integrated sensing resistors. It also features
+ USB On-The-Go (OTG) support and integrates D+/D- pin for USB
+ host/charging port detection.
+
+ This driver can also be built as a module. If so, the module
+ will be called "rt9467-charger".
+
+config CHARGER_RT9471
+ tristate "Richtek RT9471 battery charger driver"
+ depends on I2C && GPIOLIB && REGULATOR
+ select REGMAP_I2C
+ select REGMAP_IRQ
+ select LINEAR_RANGES
+ help
+ This adds support for Richtek RT9471 battery charger. RT9471 is
+ highly-integrated switch mode battery charger which is system power
+ patch manageable device for single cell Li-Ion and Li-polymer battery.
+ It can support BC12 detection on DPDM, and current and voltage
+ regulation on both charging and boost mode.
+
+ This driver can also be built as a module. If so, the module will be
+ called rt9471.
+
config CHARGER_CROS_USBPD
tristate "ChromeOS EC based USBPD charger"
depends on CROS_USBPD_NOTIFY
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index 8cb3c7f5c111..4adbfba02d05 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -33,6 +33,7 @@ obj-$(CONFIG_BATTERY_GAUGE_LTC2941) += ltc2941-battery-gauge.o
obj-$(CONFIG_BATTERY_GOLDFISH) += goldfish_battery.o
obj-$(CONFIG_BATTERY_LEGO_EV3) += lego_ev3_battery.o
obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o
+obj-$(CONFIG_BATTERY_QCOM_BATTMGR) += qcom_battmgr.o
obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o
obj-$(CONFIG_BATTERY_SAMSUNG_SDI) += samsung-sdi-battery.o
obj-$(CONFIG_BATTERY_COLLIE) += collie_battery.o
@@ -54,6 +55,8 @@ obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o
obj-$(CONFIG_BATTERY_MAX1721X) += max1721x_battery.o
obj-$(CONFIG_BATTERY_RT5033) += rt5033_battery.o
obj-$(CONFIG_CHARGER_RT9455) += rt9455_charger.o
+obj-$(CONFIG_CHARGER_RT9467) += rt9467-charger.o
+obj-$(CONFIG_CHARGER_RT9471) += rt9471.o
obj-$(CONFIG_BATTERY_TWL4030_MADC) += twl4030_madc_battery.o
obj-$(CONFIG_CHARGER_88PM860X) += 88pm860x_charger.o
obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c
index c6c9804280db..41a7bff9ac37 100644
--- a/drivers/power/supply/ab8500_fg.c
+++ b/drivers/power/supply/ab8500_fg.c
@@ -2453,7 +2453,7 @@ struct ab8500_fg_sysfs_entry {
static ssize_t charge_full_show(struct ab8500_fg *di, char *buf)
{
- return sprintf(buf, "%d\n", di->bat_cap.max_mah);
+ return sysfs_emit(buf, "%d\n", di->bat_cap.max_mah);
}
static ssize_t charge_full_store(struct ab8500_fg *di, const char *buf,
@@ -2472,7 +2472,7 @@ static ssize_t charge_full_store(struct ab8500_fg *di, const char *buf,
static ssize_t charge_now_show(struct ab8500_fg *di, char *buf)
{
- return sprintf(buf, "%d\n", di->bat_cap.prev_mah);
+ return sysfs_emit(buf, "%d\n", di->bat_cap.prev_mah);
}
static ssize_t charge_now_store(struct ab8500_fg *di, const char *buf,
@@ -2594,7 +2594,7 @@ static ssize_t ab8505_powercut_flagtime_read(struct device *dev,
goto fail;
}
- return scnprintf(buf, PAGE_SIZE, "%d\n", (reg_value & 0x7F));
+ return sysfs_emit(buf, "%d\n", (reg_value & 0x7F));
fail:
return ret;
@@ -2644,7 +2644,7 @@ static ssize_t ab8505_powercut_maxtime_read(struct device *dev,
goto fail;
}
- return scnprintf(buf, PAGE_SIZE, "%d\n", (reg_value & 0x7F));
+ return sysfs_emit(buf, "%d\n", (reg_value & 0x7F));
fail:
return ret;
@@ -2695,7 +2695,7 @@ static ssize_t ab8505_powercut_restart_read(struct device *dev,
goto fail;
}
- return scnprintf(buf, PAGE_SIZE, "%d\n", (reg_value & 0xF));
+ return sysfs_emit(buf, "%d\n", (reg_value & 0xF));
fail:
return ret;
@@ -2746,7 +2746,7 @@ static ssize_t ab8505_powercut_timer_read(struct device *dev,
goto fail;
}
- return scnprintf(buf, PAGE_SIZE, "%d\n", (reg_value & 0x7F));
+ return sysfs_emit(buf, "%d\n", (reg_value & 0x7F));
fail:
return ret;
@@ -2769,7 +2769,7 @@ static ssize_t ab8505_powercut_restart_counter_read(struct device *dev,
goto fail;
}
- return scnprintf(buf, PAGE_SIZE, "%d\n", (reg_value & 0xF0) >> 4);
+ return sysfs_emit(buf, "%d\n", (reg_value & 0xF0) >> 4);
fail:
return ret;
@@ -2790,7 +2790,7 @@ static ssize_t ab8505_powercut_read(struct device *dev,
if (ret < 0)
goto fail;
- return scnprintf(buf, PAGE_SIZE, "%d\n", (reg_value & 0x1));
+ return sysfs_emit(buf, "%d\n", (reg_value & 0x1));
fail:
return ret;
@@ -2841,7 +2841,7 @@ static ssize_t ab8505_powercut_flag_read(struct device *dev,
goto fail;
}
- return scnprintf(buf, PAGE_SIZE, "%d\n", ((reg_value & 0x10) >> 4));
+ return sysfs_emit(buf, "%d\n", ((reg_value & 0x10) >> 4));
fail:
return ret;
@@ -2864,7 +2864,7 @@ static ssize_t ab8505_powercut_debounce_read(struct device *dev,
goto fail;
}
- return scnprintf(buf, PAGE_SIZE, "%d\n", (reg_value & 0x7));
+ return sysfs_emit(buf, "%d\n", (reg_value & 0x7));
fail:
return ret;
@@ -2914,7 +2914,7 @@ static ssize_t ab8505_powercut_enable_status_read(struct device *dev,
goto fail;
}
- return scnprintf(buf, PAGE_SIZE, "%d\n", ((reg_value & 0x20) >> 5));
+ return sysfs_emit(buf, "%d\n", ((reg_value & 0x20) >> 5));
fail:
return ret;
diff --git a/drivers/power/supply/bq2415x_charger.c b/drivers/power/supply/bq2415x_charger.c
index d2cb7431dced..349b69d634e6 100644
--- a/drivers/power/supply/bq2415x_charger.c
+++ b/drivers/power/supply/bq2415x_charger.c
@@ -1059,7 +1059,7 @@ static ssize_t bq2415x_sysfs_show_status(struct device *dev,
ret = bq2415x_exec_command(bq, command);
if (ret < 0)
return ret;
- return sprintf(buf, "%d\n", ret);
+ return sysfs_emit(buf, "%d\n", ret);
}
/*
@@ -1098,11 +1098,11 @@ static ssize_t bq2415x_sysfs_show_timer(struct device *dev,
struct bq2415x_device *bq = power_supply_get_drvdata(psy);
if (bq->timer_error)
- return sprintf(buf, "%s\n", bq->timer_error);
+ return sysfs_emit(buf, "%s\n", bq->timer_error);
if (bq->autotimer)
- return sprintf(buf, "auto\n");
- return sprintf(buf, "off\n");
+ return sysfs_emit(buf, "auto\n");
+ return sysfs_emit(buf, "off\n");
}
/*
@@ -1175,30 +1175,30 @@ static ssize_t bq2415x_sysfs_show_mode(struct device *dev,
ssize_t ret = 0;
if (bq->automode > 0)
- ret += sprintf(buf+ret, "auto (");
+ ret += sysfs_emit_at(buf, ret, "auto (");
switch (bq->mode) {
case BQ2415X_MODE_OFF:
- ret += sprintf(buf+ret, "off");
+ ret += sysfs_emit_at(buf, ret, "off");
break;
case BQ2415X_MODE_NONE:
- ret += sprintf(buf+ret, "none");
+ ret += sysfs_emit_at(buf, ret, "none");
break;
case BQ2415X_MODE_HOST_CHARGER:
- ret += sprintf(buf+ret, "host");
+ ret += sysfs_emit_at(buf, ret, "host");
break;
case BQ2415X_MODE_DEDICATED_CHARGER:
- ret += sprintf(buf+ret, "dedicated");
+ ret += sysfs_emit_at(buf, ret, "dedicated");
break;
case BQ2415X_MODE_BOOST:
- ret += sprintf(buf+ret, "boost");
+ ret += sysfs_emit_at(buf, ret, "boost");
break;
}
if (bq->automode > 0)
- ret += sprintf(buf+ret, ")");
+ ret += sysfs_emit_at(buf, ret, ")");
- ret += sprintf(buf+ret, "\n");
+ ret += sysfs_emit_at(buf, ret, "\n");
return ret;
}
@@ -1215,15 +1215,15 @@ static ssize_t bq2415x_sysfs_show_reported_mode(struct device *dev,
switch (bq->reported_mode) {
case BQ2415X_MODE_OFF:
- return sprintf(buf, "off\n");
+ return sysfs_emit(buf, "off\n");
case BQ2415X_MODE_NONE:
- return sprintf(buf, "none\n");
+ return sysfs_emit(buf, "none\n");
case BQ2415X_MODE_HOST_CHARGER:
- return sprintf(buf, "host\n");
+ return sysfs_emit(buf, "host\n");
case BQ2415X_MODE_DEDICATED_CHARGER:
- return sprintf(buf, "dedicated\n");
+ return sysfs_emit(buf, "dedicated\n");
case BQ2415X_MODE_BOOST:
- return sprintf(buf, "boost\n");
+ return sysfs_emit(buf, "boost\n");
}
return -EINVAL;
@@ -1261,8 +1261,8 @@ static ssize_t bq2415x_sysfs_print_reg(struct bq2415x_device *bq,
int ret = bq2415x_i2c_read(bq, reg);
if (ret < 0)
- return sprintf(buf, "%#.2x=error %d\n", reg, ret);
- return sprintf(buf, "%#.2x=%#.2x\n", reg, ret);
+ return sysfs_emit(buf, "%#.2x=error %d\n", reg, ret);
+ return sysfs_emit(buf, "%#.2x=%#.2x\n", reg, ret);
}
/* show all raw values of chip register, format per line: 'register=value' */
@@ -1338,7 +1338,7 @@ static ssize_t bq2415x_sysfs_show_limit(struct device *dev,
if (ret < 0)
return ret;
- return sprintf(buf, "%d\n", ret);
+ return sysfs_emit(buf, "%d\n", ret);
}
/* set *_enable entries */
@@ -1401,7 +1401,7 @@ static ssize_t bq2415x_sysfs_show_enable(struct device *dev,
ret = bq2415x_exec_command(bq, command);
if (ret < 0)
return ret;
- return sprintf(buf, "%d\n", ret);
+ return sysfs_emit(buf, "%d\n", ret);
}
static DEVICE_ATTR(current_limit, S_IWUSR | S_IRUGO,
diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c
index 2b2c3a4391c1..be34b9848450 100644
--- a/drivers/power/supply/bq24190_charger.c
+++ b/drivers/power/supply/bq24190_charger.c
@@ -463,7 +463,7 @@ static ssize_t bq24190_sysfs_show(struct device *dev,
if (ret)
count = ret;
else
- count = scnprintf(buf, PAGE_SIZE, "%hhx\n", v);
+ count = sysfs_emit(buf, "%hhx\n", v);
pm_runtime_mark_last_busy(bdi->dev);
pm_runtime_put_autosuspend(bdi->dev);
diff --git a/drivers/power/supply/bq24257_charger.c b/drivers/power/supply/bq24257_charger.c
index ab4c49788c58..103ddc2b3def 100644
--- a/drivers/power/supply/bq24257_charger.c
+++ b/drivers/power/supply/bq24257_charger.c
@@ -767,8 +767,7 @@ static ssize_t bq24257_show_ovp_voltage(struct device *dev,
struct power_supply *psy = dev_get_drvdata(dev);
struct bq24257_device *bq = power_supply_get_drvdata(psy);
- return scnprintf(buf, PAGE_SIZE, "%u\n",
- bq24257_vovp_map[bq->init_data.vovp]);
+ return sysfs_emit(buf, "%u\n", bq24257_vovp_map[bq->init_data.vovp]);
}
static ssize_t bq24257_show_in_dpm_voltage(struct device *dev,
@@ -778,8 +777,7 @@ static ssize_t bq24257_show_in_dpm_voltage(struct device *dev,
struct power_supply *psy = dev_get_drvdata(dev);
struct bq24257_device *bq = power_supply_get_drvdata(psy);
- return scnprintf(buf, PAGE_SIZE, "%u\n",
- bq24257_vindpm_map[bq->init_data.vindpm]);
+ return sysfs_emit(buf, "%u\n", bq24257_vindpm_map[bq->init_data.vindpm]);
}
static ssize_t bq24257_sysfs_show_enable(struct device *dev,
@@ -800,7 +798,7 @@ static ssize_t bq24257_sysfs_show_enable(struct device *dev,
if (ret < 0)
return ret;
- return scnprintf(buf, PAGE_SIZE, "%d\n", ret);
+ return sysfs_emit(buf, "%d\n", ret);
}
static ssize_t bq24257_sysfs_set_enable(struct device *dev,
diff --git a/drivers/power/supply/bq256xx_charger.c b/drivers/power/supply/bq256xx_charger.c
index db13e288e439..9cf4936440c9 100644
--- a/drivers/power/supply/bq256xx_charger.c
+++ b/drivers/power/supply/bq256xx_charger.c
@@ -1563,7 +1563,7 @@ static int bq256xx_hw_init(struct bq256xx_device *bq)
return ret;
ret = bq->chip_info->bq256xx_set_ichg(bq,
- bat_info->constant_charge_current_max_ua);
+ bq->chip_info->bq256xx_def_ichg);
if (ret)
return ret;
@@ -1573,7 +1573,7 @@ static int bq256xx_hw_init(struct bq256xx_device *bq)
return ret;
ret = bq->chip_info->bq256xx_set_vbatreg(bq,
- bat_info->constant_charge_voltage_max_uv);
+ bq->chip_info->bq256xx_def_vbatreg);
if (ret)
return ret;
diff --git a/drivers/power/supply/bq25890_charger.c b/drivers/power/supply/bq25890_charger.c
index 2d731ea58323..bfe08d7bfaf3 100644
--- a/drivers/power/supply/bq25890_charger.c
+++ b/drivers/power/supply/bq25890_charger.c
@@ -95,6 +95,7 @@ struct bq25890_init_data {
struct bq25890_state {
u8 online;
+ u8 hiz;
u8 chrg_status;
u8 chrg_fault;
u8 vsys_status;
@@ -107,6 +108,10 @@ struct bq25890_device {
struct i2c_client *client;
struct device *dev;
struct power_supply *charger;
+ struct power_supply *secondary_chrg;
+ struct power_supply_desc desc;
+ char name[28]; /* "bq25890-charger-%d" */
+ int id;
struct usb_phy *usb_phy;
struct notifier_block usb_nb;
@@ -119,7 +124,9 @@ struct bq25890_device {
bool skip_reset;
bool read_back_init_data;
+ bool force_hiz;
u32 pump_express_vbus_max;
+ u32 iinlim_percentage;
enum bq25890_chip_version chip_version;
struct bq25890_init_data init_data;
struct bq25890_state state;
@@ -127,6 +134,9 @@ struct bq25890_device {
struct mutex lock; /* protect state data */
};
+static DEFINE_IDR(bq25890_id);
+static DEFINE_MUTEX(bq25890_id_mutex);
+
static const struct regmap_range bq25890_readonly_reg_ranges[] = {
regmap_reg_range(0x0b, 0x0c),
regmap_reg_range(0x0e, 0x13),
@@ -454,20 +464,18 @@ static int bq25890_get_vbus_voltage(struct bq25890_device *bq)
return bq25890_find_val(ret, TBL_VBUSV);
}
-static int bq25890_power_supply_get_property(struct power_supply *psy,
- enum power_supply_property psp,
- union power_supply_propval *val)
+static void bq25890_update_state(struct bq25890_device *bq,
+ enum power_supply_property psp,
+ struct bq25890_state *state)
{
- struct bq25890_device *bq = power_supply_get_drvdata(psy);
- struct bq25890_state state;
bool do_adc_conv;
int ret;
mutex_lock(&bq->lock);
/* update state in case we lost an interrupt */
__bq25890_handle_irq(bq);
- state = bq->state;
- do_adc_conv = !state.online && bq25890_is_adc_property(psp);
+ *state = bq->state;
+ do_adc_conv = (!state->online || state->hiz) && bq25890_is_adc_property(psp);
if (do_adc_conv)
bq25890_field_write(bq, F_CONV_START, 1);
mutex_unlock(&bq->lock);
@@ -475,10 +483,21 @@ static int bq25890_power_supply_get_property(struct power_supply *psy,
if (do_adc_conv)
regmap_field_read_poll_timeout(bq->rmap_fields[F_CONV_START],
ret, !ret, 25000, 1000000);
+}
+
+static int bq25890_power_supply_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct bq25890_device *bq = power_supply_get_drvdata(psy);
+ struct bq25890_state state;
+ int ret;
+
+ bq25890_update_state(bq, psp, &state);
switch (psp) {
case POWER_SUPPLY_PROP_STATUS:
- if (!state.online)
+ if (!state.online || state.hiz)
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
else if (state.chrg_status == STATUS_NOT_CHARGING)
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
@@ -493,7 +512,8 @@ static int bq25890_power_supply_get_property(struct power_supply *psy,
break;
case POWER_SUPPLY_PROP_CHARGE_TYPE:
- if (!state.online || state.chrg_status == STATUS_NOT_CHARGING ||
+ if (!state.online || state.hiz ||
+ state.chrg_status == STATUS_NOT_CHARGING ||
state.chrg_status == STATUS_TERMINATION_DONE)
val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
else if (state.chrg_status == STATUS_PRE_CHARGING)
@@ -513,7 +533,7 @@ static int bq25890_power_supply_get_property(struct power_supply *psy,
break;
case POWER_SUPPLY_PROP_ONLINE:
- val->intval = state.online;
+ val->intval = state.online && !state.hiz;
break;
case POWER_SUPPLY_PROP_HEALTH:
@@ -667,7 +687,8 @@ static int bq25890_power_supply_set_property(struct power_supply *psy,
const union power_supply_propval *val)
{
struct bq25890_device *bq = power_supply_get_drvdata(psy);
- int maxval;
+ struct bq25890_state state;
+ int maxval, ret;
u8 lval;
switch (psp) {
@@ -682,6 +703,12 @@ static int bq25890_power_supply_set_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
lval = bq25890_find_idx(val->intval, TBL_IINLIM);
return bq25890_field_write(bq, F_IINLIM, lval);
+ case POWER_SUPPLY_PROP_ONLINE:
+ ret = bq25890_field_write(bq, F_EN_HIZ, !val->intval);
+ if (!ret)
+ bq->force_hiz = !val->intval;
+ bq25890_update_state(bq, psp, &state);
+ return ret;
default:
return -EINVAL;
}
@@ -694,12 +721,25 @@ static int bq25890_power_supply_property_is_writeable(struct power_supply *psy,
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+ case POWER_SUPPLY_PROP_ONLINE:
return true;
default:
return false;
}
}
+/*
+ * If there are multiple chargers the maximum current the external power-supply
+ * can deliver needs to be divided over the chargers. This is done according
+ * to the bq->iinlim_percentage setting.
+ */
+static int bq25890_charger_get_scaled_iinlim_regval(struct bq25890_device *bq,
+ int iinlim_ua)
+{
+ iinlim_ua = iinlim_ua * bq->iinlim_percentage / 100;
+ return bq25890_find_idx(iinlim_ua, TBL_IINLIM);
+}
+
/* On the BQ25892 try to get charger-type info from our supplier */
static void bq25890_charger_external_power_changed(struct power_supply *psy)
{
@@ -718,7 +758,7 @@ static void bq25890_charger_external_power_changed(struct power_supply *psy)
switch (val.intval) {
case POWER_SUPPLY_USB_TYPE_DCP:
- input_current_limit = bq25890_find_idx(2000000, TBL_IINLIM);
+ input_current_limit = bq25890_charger_get_scaled_iinlim_regval(bq, 2000000);
if (bq->pump_express_vbus_max) {
queue_delayed_work(system_power_efficient_wq,
&bq->pump_express_work,
@@ -727,11 +767,11 @@ static void bq25890_charger_external_power_changed(struct power_supply *psy)
break;
case POWER_SUPPLY_USB_TYPE_CDP:
case POWER_SUPPLY_USB_TYPE_ACA:
- input_current_limit = bq25890_find_idx(1500000, TBL_IINLIM);
+ input_current_limit = bq25890_charger_get_scaled_iinlim_regval(bq, 1500000);
break;
case POWER_SUPPLY_USB_TYPE_SDP:
default:
- input_current_limit = bq25890_find_idx(500000, TBL_IINLIM);
+ input_current_limit = bq25890_charger_get_scaled_iinlim_regval(bq, 500000);
}
bq25890_field_write(bq, F_IINLIM, input_current_limit);
@@ -748,6 +788,7 @@ static int bq25890_get_chip_state(struct bq25890_device *bq,
} state_fields[] = {
{F_CHG_STAT, &state->chrg_status},
{F_PG_STAT, &state->online},
+ {F_EN_HIZ, &state->hiz},
{F_VSYS_STAT, &state->vsys_status},
{F_BOOST_FAULT, &state->boost_fault},
{F_BAT_FAULT, &state->bat_fault},
@@ -763,16 +804,18 @@ static int bq25890_get_chip_state(struct bq25890_device *bq,
*state_fields[i].data = ret;
}
- dev_dbg(bq->dev, "S:CHG/PG/VSYS=%d/%d/%d, F:CHG/BOOST/BAT/NTC=%d/%d/%d/%d\n",
- state->chrg_status, state->online, state->vsys_status,
- state->chrg_fault, state->boost_fault, state->bat_fault,
- state->ntc_fault);
+ dev_dbg(bq->dev, "S:CHG/PG/HIZ/VSYS=%d/%d/%d/%d, F:CHG/BOOST/BAT/NTC=%d/%d/%d/%d\n",
+ state->chrg_status, state->online,
+ state->hiz, state->vsys_status,
+ state->chrg_fault, state->boost_fault,
+ state->bat_fault, state->ntc_fault);
return 0;
}
static irqreturn_t __bq25890_handle_irq(struct bq25890_device *bq)
{
+ bool adc_conv_rate, new_adc_conv_rate;
struct bq25890_state new_state;
int ret;
@@ -783,14 +826,23 @@ static irqreturn_t __bq25890_handle_irq(struct bq25890_device *bq)
if (!memcmp(&bq->state, &new_state, sizeof(new_state)))
return IRQ_NONE;
- if (!new_state.online && bq->state.online) { /* power removed */
- /* disable ADC */
- ret = bq25890_field_write(bq, F_CONV_RATE, 0);
+ /*
+ * Restore HiZ bit in case it was set by user. The chip does not retain
+ * this bit on cable replug, hence the bit must be reset manually here.
+ */
+ if (new_state.online && !bq->state.online && bq->force_hiz) {
+ ret = bq25890_field_write(bq, F_EN_HIZ, bq->force_hiz);
if (ret < 0)
goto error;
- } else if (new_state.online && !bq->state.online) { /* power inserted */
- /* enable ADC, to have control of charge current/voltage */
- ret = bq25890_field_write(bq, F_CONV_RATE, 1);
+ new_state.hiz = 1;
+ }
+
+ /* Should period ADC sampling be enabled? */
+ adc_conv_rate = bq->state.online && !bq->state.hiz;
+ new_adc_conv_rate = new_state.online && !new_state.hiz;
+
+ if (new_adc_conv_rate != adc_conv_rate) {
+ ret = bq25890_field_write(bq, F_CONV_RATE, new_adc_conv_rate);
if (ret < 0)
goto error;
}
@@ -924,7 +976,7 @@ static int bq25890_hw_init(struct bq25890_device *bq)
}
/* Configure ADC for continuous conversions when charging */
- ret = bq25890_field_write(bq, F_CONV_RATE, !!bq->state.online);
+ ret = bq25890_field_write(bq, F_CONV_RATE, bq->state.online && !bq->state.hiz);
if (ret < 0) {
dev_dbg(bq->dev, "Config ADC failed %d\n", ret);
return ret;
@@ -957,7 +1009,6 @@ static char *bq25890_charger_supplied_to[] = {
};
static const struct power_supply_desc bq25890_power_supply_desc = {
- .name = "bq25890-charger",
.type = POWER_SUPPLY_TYPE_USB,
.properties = bq25890_power_supply_props,
.num_properties = ARRAY_SIZE(bq25890_power_supply_props),
@@ -971,12 +1022,21 @@ static int bq25890_power_supply_init(struct bq25890_device *bq)
{
struct power_supply_config psy_cfg = { .drv_data = bq, };
+ /* Get ID for the device */
+ mutex_lock(&bq25890_id_mutex);
+ bq->id = idr_alloc(&bq25890_id, bq, 0, 0, GFP_KERNEL);
+ mutex_unlock(&bq25890_id_mutex);
+ if (bq->id < 0)
+ return bq->id;
+
+ snprintf(bq->name, sizeof(bq->name), "bq25890-charger-%d", bq->id);
+ bq->desc = bq25890_power_supply_desc;
+ bq->desc.name = bq->name;
+
psy_cfg.supplied_to = bq25890_charger_supplied_to;
psy_cfg.num_supplicants = ARRAY_SIZE(bq25890_charger_supplied_to);
- bq->charger = devm_power_supply_register(bq->dev,
- &bq25890_power_supply_desc,
- &psy_cfg);
+ bq->charger = devm_power_supply_register(bq->dev, &bq->desc, &psy_cfg);
return PTR_ERR_OR_ZERO(bq->charger);
}
@@ -996,10 +1056,17 @@ static void bq25890_pump_express_work(struct work_struct *data)
{
struct bq25890_device *bq =
container_of(data, struct bq25890_device, pump_express_work.work);
+ union power_supply_propval value;
int voltage, i, ret;
dev_dbg(bq->dev, "Start to request input voltage increasing\n");
+ /* If there is a second charger put in Hi-Z mode */
+ if (bq->secondary_chrg) {
+ value.intval = 0;
+ power_supply_set_property(bq->secondary_chrg, POWER_SUPPLY_PROP_ONLINE, &value);
+ }
+
/* Enable current pulse voltage control protocol */
ret = bq25890_field_write(bq, F_PUMPX_EN, 1);
if (ret < 0)
@@ -1031,6 +1098,11 @@ static void bq25890_pump_express_work(struct work_struct *data)
bq25890_field_write(bq, F_PUMPX_EN, 0);
+ if (bq->secondary_chrg) {
+ value.intval = 1;
+ power_supply_set_property(bq->secondary_chrg, POWER_SUPPLY_PROP_ONLINE, &value);
+ }
+
dev_info(bq->dev, "Hi-voltage charging requested, input voltage is %d mV\n",
voltage);
@@ -1077,6 +1149,17 @@ static int bq25890_usb_notifier(struct notifier_block *nb, unsigned long val,
static int bq25890_vbus_enable(struct regulator_dev *rdev)
{
struct bq25890_device *bq = rdev_get_drvdata(rdev);
+ union power_supply_propval val = {
+ .intval = 0,
+ };
+
+ /*
+ * When enabling 5V boost / Vbus output, we need to put the secondary
+ * charger in Hi-Z mode to avoid it trying to charge the secondary
+ * battery from the 5V boost output.
+ */
+ if (bq->secondary_chrg)
+ power_supply_set_property(bq->secondary_chrg, POWER_SUPPLY_PROP_ONLINE, &val);
return bq25890_set_otg_cfg(bq, 1);
}
@@ -1084,8 +1167,19 @@ static int bq25890_vbus_enable(struct regulator_dev *rdev)
static int bq25890_vbus_disable(struct regulator_dev *rdev)
{
struct bq25890_device *bq = rdev_get_drvdata(rdev);
+ union power_supply_propval val = {
+ .intval = 1,
+ };
+ int ret;
+
+ ret = bq25890_set_otg_cfg(bq, 0);
+ if (ret)
+ return ret;
- return bq25890_set_otg_cfg(bq, 0);
+ if (bq->secondary_chrg)
+ power_supply_set_property(bq->secondary_chrg, POWER_SUPPLY_PROP_ONLINE, &val);
+
+ return 0;
}
static int bq25890_vbus_is_enabled(struct regulator_dev *rdev)
@@ -1296,11 +1390,31 @@ static int bq25890_fw_probe(struct bq25890_device *bq)
{
int ret;
struct bq25890_init_data *init = &bq->init_data;
+ const char *str;
+ u32 val;
+
+ ret = device_property_read_string(bq->dev, "linux,secondary-charger-name", &str);
+ if (ret == 0) {
+ bq->secondary_chrg = power_supply_get_by_name(str);
+ if (!bq->secondary_chrg)
+ return -EPROBE_DEFER;
+ }
/* Optional, left at 0 if property is not present */
device_property_read_u32(bq->dev, "linux,pump-express-vbus-max",
&bq->pump_express_vbus_max);
+ ret = device_property_read_u32(bq->dev, "linux,iinlim-percentage", &val);
+ if (ret == 0) {
+ if (val > 100) {
+ dev_err(bq->dev, "Error linux,iinlim-percentage %u > 100\n", val);
+ return -EINVAL;
+ }
+ bq->iinlim_percentage = val;
+ } else {
+ bq->iinlim_percentage = 100;
+ }
+
bq->skip_reset = device_property_read_bool(bq->dev, "linux,skip-reset");
bq->read_back_init_data = device_property_read_bool(bq->dev,
"linux,read-back-settings");
@@ -1322,6 +1436,12 @@ static void bq25890_non_devm_cleanup(void *data)
struct bq25890_device *bq = data;
cancel_delayed_work_sync(&bq->pump_express_work);
+
+ if (bq->id >= 0) {
+ mutex_lock(&bq25890_id_mutex);
+ idr_remove(&bq25890_id, bq->id);
+ mutex_unlock(&bq25890_id_mutex);
+ }
}
static int bq25890_probe(struct i2c_client *client)
@@ -1336,6 +1456,7 @@ static int bq25890_probe(struct i2c_client *client)
bq->client = client;
bq->dev = dev;
+ bq->id = -1;
mutex_init(&bq->lock);
INIT_DELAYED_WORK(&bq->pump_express_work, bq25890_pump_express_work);
diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
index 8bf048fbd36a..5ff6f44fd47b 100644
--- a/drivers/power/supply/bq27xxx_battery.c
+++ b/drivers/power/supply/bq27xxx_battery.c
@@ -1917,10 +1917,10 @@ static int bq27xxx_battery_capacity_level(struct bq27xxx_device_info *di,
if (di->opts & BQ27XXX_O_ZERO) {
if (di->cache.flags & BQ27000_FLAG_FC)
level = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
- else if (di->cache.flags & BQ27000_FLAG_EDV1)
- level = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
else if (di->cache.flags & BQ27000_FLAG_EDVF)
level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
+ else if (di->cache.flags & BQ27000_FLAG_EDV1)
+ level = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
else
level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
} else if (di->opts & BQ27Z561_O_BITS) {
@@ -1933,10 +1933,10 @@ static int bq27xxx_battery_capacity_level(struct bq27xxx_device_info *di,
} else {
if (di->cache.flags & BQ27XXX_FLAG_FC)
level = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
- else if (di->cache.flags & BQ27XXX_FLAG_SOC1)
- level = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
else if (di->cache.flags & BQ27XXX_FLAG_SOCF)
level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
+ else if (di->cache.flags & BQ27XXX_FLAG_SOC1)
+ level = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
else
level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
}
diff --git a/drivers/power/supply/charger-manager.c b/drivers/power/supply/charger-manager.c
index 92db79400a6a..c9e8450c646f 100644
--- a/drivers/power/supply/charger-manager.c
+++ b/drivers/power/supply/charger-manager.c
@@ -1075,7 +1075,7 @@ static ssize_t charger_name_show(struct device *dev,
struct charger_regulator *charger
= container_of(attr, struct charger_regulator, attr_name);
- return sprintf(buf, "%s\n", charger->regulator_name);
+ return sysfs_emit(buf, "%s\n", charger->regulator_name);
}
static ssize_t charger_state_show(struct device *dev,
@@ -1088,7 +1088,7 @@ static ssize_t charger_state_show(struct device *dev,
if (!charger->externally_control)
state = regulator_is_enabled(charger->consumer);
- return sprintf(buf, "%s\n", state ? "enabled" : "disabled");
+ return sysfs_emit(buf, "%s\n", state ? "enabled" : "disabled");
}
static ssize_t charger_externally_control_show(struct device *dev,
@@ -1097,7 +1097,7 @@ static ssize_t charger_externally_control_show(struct device *dev,
struct charger_regulator *charger = container_of(attr,
struct charger_regulator, attr_externally_control);
- return sprintf(buf, "%d\n", charger->externally_control);
+ return sysfs_emit(buf, "%d\n", charger->externally_control);
}
static ssize_t charger_externally_control_store(struct device *dev,
diff --git a/drivers/power/supply/collie_battery.c b/drivers/power/supply/collie_battery.c
index 7fb9b549f2de..68390bd1004f 100644
--- a/drivers/power/supply/collie_battery.c
+++ b/drivers/power/supply/collie_battery.c
@@ -404,7 +404,7 @@ static int collie_bat_probe(struct ucb1x00_dev *dev)
goto err_psy_reg_bu;
}
- ret = request_irq(gpio_to_irq(COLLIE_GPIO_CO),
+ ret = request_irq(gpiod_to_irq(collie_bat_main.gpio_full),
collie_bat_gpio_isr,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
"main full", &collie_bat_main);
@@ -440,7 +440,7 @@ err_put_gpio_full:
static void collie_bat_remove(struct ucb1x00_dev *dev)
{
- free_irq(gpio_to_irq(COLLIE_GPIO_CO), &collie_bat_main);
+ free_irq(gpiod_to_irq(collie_bat_main.gpio_full), &collie_bat_main);
power_supply_unregister(collie_bat_bu.psy);
power_supply_unregister(collie_bat_main.psy);
diff --git a/drivers/power/supply/da9150-charger.c b/drivers/power/supply/da9150-charger.c
index f9314cc0cd75..14da5c595dd9 100644
--- a/drivers/power/supply/da9150-charger.c
+++ b/drivers/power/supply/da9150-charger.c
@@ -466,10 +466,8 @@ static int da9150_charger_register_irq(struct platform_device *pdev,
int irq, ret;
irq = platform_get_irq_byname(pdev, irq_name);
- if (irq < 0) {
- dev_err(dev, "Failed to get IRQ CHG_STATUS: %d\n", irq);
+ if (irq < 0)
return irq;
- }
ret = request_threaded_irq(irq, NULL, handler, IRQF_ONESHOT, irq_name,
charger);
@@ -482,15 +480,12 @@ static int da9150_charger_register_irq(struct platform_device *pdev,
static void da9150_charger_unregister_irq(struct platform_device *pdev,
const char *irq_name)
{
- struct device *dev = &pdev->dev;
struct da9150_charger *charger = platform_get_drvdata(pdev);
int irq;
irq = platform_get_irq_byname(pdev, irq_name);
- if (irq < 0) {
- dev_err(dev, "Failed to get IRQ CHG_STATUS: %d\n", irq);
+ if (irq < 0)
return;
- }
free_irq(irq, charger);
}
diff --git a/drivers/power/supply/ds2780_battery.c b/drivers/power/supply/ds2780_battery.c
index 2b8c90d84325..1e7f297f6cb1 100644
--- a/drivers/power/supply/ds2780_battery.c
+++ b/drivers/power/supply/ds2780_battery.c
@@ -454,7 +454,7 @@ static ssize_t ds2780_get_pmod_enabled(struct device *dev,
if (ret < 0)
return ret;
- return sprintf(buf, "%d\n",
+ return sysfs_emit(buf, "%d\n",
!!(control_reg & DS2780_CONTROL_REG_PMOD));
}
@@ -507,7 +507,7 @@ static ssize_t ds2780_get_sense_resistor_value(struct device *dev,
if (ret < 0)
return ret;
- ret = sprintf(buf, "%d\n", sense_resistor);
+ ret = sysfs_emit(buf, "%d\n", sense_resistor);
return ret;
}
@@ -545,7 +545,7 @@ static ssize_t ds2780_get_rsgain_setting(struct device *dev,
if (ret < 0)
return ret;
- return sprintf(buf, "%d\n", rsgain);
+ return sysfs_emit(buf, "%d\n", rsgain);
}
static ssize_t ds2780_set_rsgain_setting(struct device *dev,
@@ -588,7 +588,7 @@ static ssize_t ds2780_get_pio_pin(struct device *dev,
if (ret < 0)
return ret;
- ret = sprintf(buf, "%d\n", sfr & DS2780_SFR_REG_PIOSC);
+ ret = sysfs_emit(buf, "%d\n", sfr & DS2780_SFR_REG_PIOSC);
return ret;
}
diff --git a/drivers/power/supply/ds2781_battery.c b/drivers/power/supply/ds2781_battery.c
index 05b859bf2dc0..c4f8ccc687f9 100644
--- a/drivers/power/supply/ds2781_battery.c
+++ b/drivers/power/supply/ds2781_battery.c
@@ -456,7 +456,7 @@ static ssize_t ds2781_get_pmod_enabled(struct device *dev,
if (ret < 0)
return ret;
- return sprintf(buf, "%d\n",
+ return sysfs_emit(buf, "%d\n",
!!(control_reg & DS2781_CONTROL_PMOD));
}
@@ -509,7 +509,7 @@ static ssize_t ds2781_get_sense_resistor_value(struct device *dev,
if (ret < 0)
return ret;
- ret = sprintf(buf, "%d\n", sense_resistor);
+ ret = sysfs_emit(buf, "%d\n", sense_resistor);
return ret;
}
@@ -547,7 +547,7 @@ static ssize_t ds2781_get_rsgain_setting(struct device *dev,
if (ret < 0)
return ret;
- return sprintf(buf, "%d\n", rsgain);
+ return sysfs_emit(buf, "%d\n", rsgain);
}
static ssize_t ds2781_set_rsgain_setting(struct device *dev,
@@ -590,7 +590,7 @@ static ssize_t ds2781_get_pio_pin(struct device *dev,
if (ret < 0)
return ret;
- ret = sprintf(buf, "%d\n", sfr & DS2781_SFR_PIOSC);
+ ret = sysfs_emit(buf, "%d\n", sfr & DS2781_SFR_PIOSC);
return ret;
}
diff --git a/drivers/power/supply/lp8788-charger.c b/drivers/power/supply/lp8788-charger.c
index f5f47a0aa1e3..755b6a4379b8 100644
--- a/drivers/power/supply/lp8788-charger.c
+++ b/drivers/power/supply/lp8788-charger.c
@@ -602,7 +602,7 @@ static ssize_t lp8788_show_charger_status(struct device *dev,
lp8788_read_byte(pchg->lp, LP8788_CHG_STATUS, &data);
state = (data & LP8788_CHG_STATE_M) >> LP8788_CHG_STATE_S;
- return scnprintf(buf, PAGE_SIZE, "%s\n", desc[state]);
+ return sysfs_emit(buf, "%s\n", desc[state]);
}
static ssize_t lp8788_show_eoc_time(struct device *dev,
@@ -618,8 +618,7 @@ static ssize_t lp8788_show_eoc_time(struct device *dev,
lp8788_read_byte(pchg->lp, LP8788_CHG_EOC, &val);
val = (val & LP8788_CHG_EOC_TIME_M) >> LP8788_CHG_EOC_TIME_S;
- return scnprintf(buf, PAGE_SIZE, "End Of Charge Time: %s\n",
- stime[val]);
+ return sysfs_emit(buf, "End Of Charge Time: %s\n", stime[val]);
}
static ssize_t lp8788_show_eoc_level(struct device *dev,
@@ -642,7 +641,7 @@ static ssize_t lp8788_show_eoc_level(struct device *dev,
val = (val & LP8788_CHG_EOC_LEVEL_M) >> LP8788_CHG_EOC_LEVEL_S;
level = mode ? abs_level[val] : relative_level[val];
- return scnprintf(buf, PAGE_SIZE, "End Of Charge Level: %s\n", level);
+ return sysfs_emit(buf, "End Of Charge Level: %s\n", level);
}
static DEVICE_ATTR(charger_status, S_IRUSR, lp8788_show_charger_status, NULL);
diff --git a/drivers/power/supply/ltc4162-l-charger.c b/drivers/power/supply/ltc4162-l-charger.c
index db2bb5233570..0e95c65369b8 100644
--- a/drivers/power/supply/ltc4162-l-charger.c
+++ b/drivers/power/supply/ltc4162-l-charger.c
@@ -525,7 +525,7 @@ static ssize_t charge_status_show(struct device *dev,
}
}
- return sprintf(buf, "%s\n", result);
+ return sysfs_emit(buf, "%s\n", result);
}
static DEVICE_ATTR_RO(charge_status);
@@ -541,7 +541,7 @@ static ssize_t vbat_show(struct device *dev,
if (ret)
return ret;
- return sprintf(buf, "%d\n", val.intval);
+ return sysfs_emit(buf, "%d\n", val.intval);
}
static DEVICE_ATTR_RO(vbat);
@@ -557,7 +557,7 @@ static ssize_t vbat_avg_show(struct device *dev,
if (ret)
return ret;
- return sprintf(buf, "%d\n", val.intval);
+ return sysfs_emit(buf, "%d\n", val.intval);
}
static DEVICE_ATTR_RO(vbat_avg);
@@ -573,7 +573,7 @@ static ssize_t ibat_show(struct device *dev,
if (ret)
return ret;
- return sprintf(buf, "%d\n", val.intval);
+ return sysfs_emit(buf, "%d\n", val.intval);
}
static DEVICE_ATTR_RO(ibat);
@@ -589,7 +589,7 @@ static ssize_t force_telemetry_show(struct device *dev,
if (ret)
return ret;
- return sprintf(buf, "%u\n", regval & BIT(2) ? 1 : 0);
+ return sysfs_emit(buf, "%u\n", regval & BIT(2) ? 1 : 0);
}
static ssize_t force_telemetry_store(struct device *dev,
@@ -628,7 +628,7 @@ static ssize_t arm_ship_mode_show(struct device *dev,
if (ret)
return ret;
- return sprintf(buf, "%u\n",
+ return sysfs_emit(buf, "%u\n",
regval == LTC4162L_ARM_SHIP_MODE_MAGIC ? 1 : 0);
}
diff --git a/drivers/power/supply/max14577_charger.c b/drivers/power/supply/max14577_charger.c
index f244cd902eb9..96f9de775043 100644
--- a/drivers/power/supply/max14577_charger.c
+++ b/drivers/power/supply/max14577_charger.c
@@ -532,7 +532,7 @@ static ssize_t show_fast_charge_timer(struct device *dev,
break;
}
- return scnprintf(buf, PAGE_SIZE, "%u\n", val);
+ return sysfs_emit(buf, "%u\n", val);
}
static ssize_t store_fast_charge_timer(struct device *dev,
diff --git a/drivers/power/supply/max1721x_battery.c b/drivers/power/supply/max1721x_battery.c
index d8d52e09da7b..bac43ab9e97c 100644
--- a/drivers/power/supply/max1721x_battery.c
+++ b/drivers/power/supply/max1721x_battery.c
@@ -384,7 +384,7 @@ static int devm_w1_max1721x_add_device(struct w1_slave *sl)
}
if (!info->ManufacturerName[0])
- strncpy(info->ManufacturerName, DEF_MFG_NAME,
+ strscpy(info->ManufacturerName, DEF_MFG_NAME,
2 * MAX1721X_REG_MFG_NUMB);
if (get_string(info, MAX1721X_REG_DEV_STR,
@@ -403,15 +403,15 @@ static int devm_w1_max1721x_add_device(struct w1_slave *sl)
switch (dev_name & MAX172XX_DEV_MASK) {
case MAX172X1_DEV:
- strncpy(info->DeviceName, DEF_DEV_NAME_MAX17211,
+ strscpy(info->DeviceName, DEF_DEV_NAME_MAX17211,
2 * MAX1721X_REG_DEV_NUMB);
break;
case MAX172X5_DEV:
- strncpy(info->DeviceName, DEF_DEV_NAME_MAX17215,
+ strscpy(info->DeviceName, DEF_DEV_NAME_MAX17215,
2 * MAX1721X_REG_DEV_NUMB);
break;
default:
- strncpy(info->DeviceName, DEF_DEV_NAME_UNKNOWN,
+ strscpy(info->DeviceName, DEF_DEV_NAME_UNKNOWN,
2 * MAX1721X_REG_DEV_NUMB);
}
}
diff --git a/drivers/power/supply/max77650-charger.c b/drivers/power/supply/max77650-charger.c
index d913428bedc0..e8c25da40ab2 100644
--- a/drivers/power/supply/max77650-charger.c
+++ b/drivers/power/supply/max77650-charger.c
@@ -141,7 +141,7 @@ static int max77650_charger_enable(struct max77650_charger_data *chg)
return rv;
}
-static int max77650_charger_disable(struct max77650_charger_data *chg)
+static void max77650_charger_disable(struct max77650_charger_data *chg)
{
int rv;
@@ -151,8 +151,6 @@ static int max77650_charger_disable(struct max77650_charger_data *chg)
MAX77650_CHARGER_DISABLED);
if (rv)
dev_err(chg->dev, "unable to disable the charger: %d\n", rv);
-
- return rv;
}
static irqreturn_t max77650_charger_check_status(int irq, void *data)
@@ -351,7 +349,9 @@ static int max77650_charger_remove(struct platform_device *pdev)
{
struct max77650_charger_data *chg = platform_get_drvdata(pdev);
- return max77650_charger_disable(chg);
+ max77650_charger_disable(chg);
+
+ return 0;
}
static const struct of_device_id max77650_charger_of_match[] = {
diff --git a/drivers/power/supply/max77693_charger.c b/drivers/power/supply/max77693_charger.c
index a2c5c9858639..794c8c054450 100644
--- a/drivers/power/supply/max77693_charger.c
+++ b/drivers/power/supply/max77693_charger.c
@@ -296,7 +296,7 @@ static ssize_t fast_charge_timer_show(struct device *dev,
break;
}
- return scnprintf(buf, PAGE_SIZE, "%u\n", val);
+ return sysfs_emit(buf, "%u\n", val);
}
static int max77693_set_fast_charge_timer(struct max77693_charger *chg,
@@ -357,7 +357,7 @@ static ssize_t top_off_threshold_current_show(struct device *dev,
else
val = data * 50000;
- return scnprintf(buf, PAGE_SIZE, "%u\n", val);
+ return sysfs_emit(buf, "%u\n", val);
}
static int max77693_set_top_off_threshold_current(struct max77693_charger *chg,
@@ -405,7 +405,7 @@ static ssize_t top_off_timer_show(struct device *dev,
val = data * 10;
- return scnprintf(buf, PAGE_SIZE, "%u\n", val);
+ return sysfs_emit(buf, "%u\n", val);
}
static int max77693_set_top_off_timer(struct max77693_charger *chg,
diff --git a/drivers/power/supply/mp2629_charger.c b/drivers/power/supply/mp2629_charger.c
index bf9c27b463a8..3a2a28fbba73 100644
--- a/drivers/power/supply/mp2629_charger.c
+++ b/drivers/power/supply/mp2629_charger.c
@@ -519,7 +519,7 @@ static ssize_t batt_impedance_compensation_show(struct device *dev,
return ret;
rval = (rval >> 4) * 10;
- return sprintf(buf, "%d mohm\n", rval);
+ return sysfs_emit(buf, "%d mohm\n", rval);
}
static ssize_t batt_impedance_compensation_store(struct device *dev,
diff --git a/drivers/power/supply/olpc_battery.c b/drivers/power/supply/olpc_battery.c
index a5da20ffd685..9f60094a5599 100644
--- a/drivers/power/supply/olpc_battery.c
+++ b/drivers/power/supply/olpc_battery.c
@@ -568,7 +568,7 @@ static ssize_t olpc_bat_error_read(struct device *dev,
if (ret < 0)
return ret;
- return sprintf(buf, "%d\n", ec_byte);
+ return sysfs_emit(buf, "%d\n", ec_byte);
}
static struct device_attribute olpc_bat_error = {
diff --git a/drivers/power/supply/pcf50633-charger.c b/drivers/power/supply/pcf50633-charger.c
index 8c5d892f6350..fd44cb8ac0e2 100644
--- a/drivers/power/supply/pcf50633-charger.c
+++ b/drivers/power/supply/pcf50633-charger.c
@@ -153,7 +153,7 @@ show_chgmode(struct device *dev, struct device_attribute *attr, char *buf)
u8 mbcs2 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCS2);
u8 chgmod = (mbcs2 & PCF50633_MBCS2_MBC_MASK);
- return sprintf(buf, "%d\n", chgmod);
+ return sysfs_emit(buf, "%d\n", chgmod);
}
static DEVICE_ATTR(chgmode, S_IRUGO, show_chgmode, NULL);
@@ -174,7 +174,7 @@ show_usblim(struct device *dev, struct device_attribute *attr, char *buf)
else
ma = 0;
- return sprintf(buf, "%u\n", ma);
+ return sysfs_emit(buf, "%u\n", ma);
}
static ssize_t set_usblim(struct device *dev,
@@ -207,7 +207,7 @@ show_chglim(struct device *dev, struct device_attribute *attr, char *buf)
ma = (mbc->pcf->pdata->charger_reference_current_ma * mbcc5) >> 8;
- return sprintf(buf, "%u\n", ma);
+ return sysfs_emit(buf, "%u\n", ma);
}
static ssize_t set_chglim(struct device *dev,
diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c
index 7c790c41e2fe..cc5b2e22b42a 100644
--- a/drivers/power/supply/power_supply_core.c
+++ b/drivers/power/supply/power_supply_core.c
@@ -1186,83 +1186,6 @@ static void psy_unregister_thermal(struct power_supply *psy)
thermal_zone_device_unregister(psy->tzd);
}
-/* thermal cooling device callbacks */
-static int ps_get_max_charge_cntl_limit(struct thermal_cooling_device *tcd,
- unsigned long *state)
-{
- struct power_supply *psy;
- union power_supply_propval val;
- int ret;
-
- psy = tcd->devdata;
- ret = power_supply_get_property(psy,
- POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX, &val);
- if (ret)
- return ret;
-
- *state = val.intval;
-
- return ret;
-}
-
-static int ps_get_cur_charge_cntl_limit(struct thermal_cooling_device *tcd,
- unsigned long *state)
-{
- struct power_supply *psy;
- union power_supply_propval val;
- int ret;
-
- psy = tcd->devdata;
- ret = power_supply_get_property(psy,
- POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT, &val);
- if (ret)
- return ret;
-
- *state = val.intval;
-
- return ret;
-}
-
-static int ps_set_cur_charge_cntl_limit(struct thermal_cooling_device *tcd,
- unsigned long state)
-{
- struct power_supply *psy;
- union power_supply_propval val;
- int ret;
-
- psy = tcd->devdata;
- val.intval = state;
- ret = psy->desc->set_property(psy,
- POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT, &val);
-
- return ret;
-}
-
-static const struct thermal_cooling_device_ops psy_tcd_ops = {
- .get_max_state = ps_get_max_charge_cntl_limit,
- .get_cur_state = ps_get_cur_charge_cntl_limit,
- .set_cur_state = ps_set_cur_charge_cntl_limit,
-};
-
-static int psy_register_cooler(struct power_supply *psy)
-{
- /* Register for cooling device if psy can control charging */
- if (psy_has_property(psy->desc, POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT)) {
- psy->tcd = thermal_cooling_device_register(
- (char *)psy->desc->name,
- psy, &psy_tcd_ops);
- return PTR_ERR_OR_ZERO(psy->tcd);
- }
-
- return 0;
-}
-
-static void psy_unregister_cooler(struct power_supply *psy)
-{
- if (IS_ERR_OR_NULL(psy->tcd))
- return;
- thermal_cooling_device_unregister(psy->tcd);
-}
#else
static int psy_register_thermal(struct power_supply *psy)
{
@@ -1272,15 +1195,6 @@ static int psy_register_thermal(struct power_supply *psy)
static void psy_unregister_thermal(struct power_supply *psy)
{
}
-
-static int psy_register_cooler(struct power_supply *psy)
-{
- return 0;
-}
-
-static void psy_unregister_cooler(struct power_supply *psy)
-{
-}
#endif
static struct power_supply *__must_check
@@ -1354,10 +1268,6 @@ __power_supply_register(struct device *parent,
if (rc)
goto register_thermal_failed;
- rc = psy_register_cooler(psy);
- if (rc)
- goto register_cooler_failed;
-
rc = power_supply_create_triggers(psy);
if (rc)
goto create_triggers_failed;
@@ -1387,8 +1297,6 @@ __power_supply_register(struct device *parent,
add_hwmon_sysfs_failed:
power_supply_remove_triggers(psy);
create_triggers_failed:
- psy_unregister_cooler(psy);
-register_cooler_failed:
psy_unregister_thermal(psy);
register_thermal_failed:
wakeup_init_failed:
@@ -1540,7 +1448,6 @@ void power_supply_unregister(struct power_supply *psy)
sysfs_remove_link(&psy->dev.kobj, "powers");
power_supply_remove_hwmon_sysfs(psy);
power_supply_remove_triggers(psy);
- psy_unregister_cooler(psy);
psy_unregister_thermal(psy);
device_init_wakeup(&psy->dev, false);
device_unregister(&psy->dev);
diff --git a/drivers/power/supply/power_supply_leds.c b/drivers/power/supply/power_supply_leds.c
index d69880cc3593..702bf83f6e6d 100644
--- a/drivers/power/supply/power_supply_leds.c
+++ b/drivers/power/supply/power_supply_leds.c
@@ -13,6 +13,7 @@
#include <linux/device.h>
#include <linux/power_supply.h>
#include <linux/slab.h>
+#include <linux/leds.h>
#include "power_supply.h"
diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
index 6ca7d3985a40..c228205e0953 100644
--- a/drivers/power/supply/power_supply_sysfs.c
+++ b/drivers/power/supply/power_supply_sysfs.c
@@ -249,11 +249,11 @@ static ssize_t power_supply_show_usb_type(struct device *dev,
usb_type = desc->usb_types[i];
if (value->intval == usb_type) {
- count += sprintf(buf + count, "[%s] ",
+ count += sysfs_emit_at(buf, count, "[%s] ",
POWER_SUPPLY_USB_TYPE_TEXT[usb_type]);
match = true;
} else {
- count += sprintf(buf + count, "%s ",
+ count += sysfs_emit_at(buf, count, "%s ",
POWER_SUPPLY_USB_TYPE_TEXT[usb_type]);
}
}
@@ -297,7 +297,7 @@ static ssize_t power_supply_show_property(struct device *dev,
if (ps_attr->text_values_len > 0 &&
value.intval < ps_attr->text_values_len && value.intval >= 0) {
- return sprintf(buf, "%s\n", ps_attr->text_values[value.intval]);
+ return sysfs_emit(buf, "%s\n", ps_attr->text_values[value.intval]);
}
switch (psp) {
@@ -306,10 +306,10 @@ static ssize_t power_supply_show_property(struct device *dev,
&value, buf);
break;
case POWER_SUPPLY_PROP_MODEL_NAME ... POWER_SUPPLY_PROP_SERIAL_NUMBER:
- ret = sprintf(buf, "%s\n", value.strval);
+ ret = sysfs_emit(buf, "%s\n", value.strval);
break;
default:
- ret = sprintf(buf, "%d\n", value.intval);
+ ret = sysfs_emit(buf, "%d\n", value.intval);
}
return ret;
diff --git a/drivers/power/supply/qcom_battmgr.c b/drivers/power/supply/qcom_battmgr.c
new file mode 100644
index 000000000000..de77df97b3a4
--- /dev/null
+++ b/drivers/power/supply/qcom_battmgr.c
@@ -0,0 +1,1410 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022, Linaro Ltd
+ */
+#include <linux/auxiliary_bus.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of_device.h>
+#include <linux/power_supply.h>
+#include <linux/soc/qcom/pdr.h>
+#include <linux/soc/qcom/pmic_glink.h>
+#include <linux/math.h>
+#include <linux/units.h>
+
+#define BATTMGR_CHEMISTRY_LEN 4
+#define BATTMGR_STRING_LEN 128
+
+enum qcom_battmgr_variant {
+ QCOM_BATTMGR_SM8350,
+ QCOM_BATTMGR_SC8280XP,
+};
+
+#define BATTMGR_BAT_STATUS 0x1
+
+#define BATTMGR_REQUEST_NOTIFICATION 0x4
+
+#define BATTMGR_NOTIFICATION 0x7
+#define NOTIF_BAT_PROPERTY 0x30
+#define NOTIF_USB_PROPERTY 0x32
+#define NOTIF_WLS_PROPERTY 0x34
+#define NOTIF_BAT_INFO 0x81
+#define NOTIF_BAT_STATUS 0x80
+
+#define BATTMGR_BAT_INFO 0x9
+
+#define BATTMGR_BAT_DISCHARGE_TIME 0xc
+
+#define BATTMGR_BAT_CHARGE_TIME 0xd
+
+#define BATTMGR_BAT_PROPERTY_GET 0x30
+#define BATTMGR_BAT_PROPERTY_SET 0x31
+#define BATT_STATUS 0
+#define BATT_HEALTH 1
+#define BATT_PRESENT 2
+#define BATT_CHG_TYPE 3
+#define BATT_CAPACITY 4
+#define BATT_SOH 5
+#define BATT_VOLT_OCV 6
+#define BATT_VOLT_NOW 7
+#define BATT_VOLT_MAX 8
+#define BATT_CURR_NOW 9
+#define BATT_CHG_CTRL_LIM 10
+#define BATT_CHG_CTRL_LIM_MAX 11
+#define BATT_TEMP 12
+#define BATT_TECHNOLOGY 13
+#define BATT_CHG_COUNTER 14
+#define BATT_CYCLE_COUNT 15
+#define BATT_CHG_FULL_DESIGN 16
+#define BATT_CHG_FULL 17
+#define BATT_MODEL_NAME 18
+#define BATT_TTF_AVG 19
+#define BATT_TTE_AVG 20
+#define BATT_RESISTANCE 21
+#define BATT_POWER_NOW 22
+#define BATT_POWER_AVG 23
+
+#define BATTMGR_USB_PROPERTY_GET 0x32
+#define BATTMGR_USB_PROPERTY_SET 0x33
+#define USB_ONLINE 0
+#define USB_VOLT_NOW 1
+#define USB_VOLT_MAX 2
+#define USB_CURR_NOW 3
+#define USB_CURR_MAX 4
+#define USB_INPUT_CURR_LIMIT 5
+#define USB_TYPE 6
+#define USB_ADAP_TYPE 7
+#define USB_MOISTURE_DET_EN 8
+#define USB_MOISTURE_DET_STS 9
+
+#define BATTMGR_WLS_PROPERTY_GET 0x34
+#define BATTMGR_WLS_PROPERTY_SET 0x35
+#define WLS_ONLINE 0
+#define WLS_VOLT_NOW 1
+#define WLS_VOLT_MAX 2
+#define WLS_CURR_NOW 3
+#define WLS_CURR_MAX 4
+#define WLS_TYPE 5
+#define WLS_BOOST_EN 6
+
+struct qcom_battmgr_enable_request {
+ struct pmic_glink_hdr hdr;
+ __le32 battery_id;
+ __le32 power_state;
+ __le32 low_capacity;
+ __le32 high_capacity;
+};
+
+struct qcom_battmgr_property_request {
+ struct pmic_glink_hdr hdr;
+ __le32 battery;
+ __le32 property;
+ __le32 value;
+};
+
+struct qcom_battmgr_update_request {
+ struct pmic_glink_hdr hdr;
+ u32 battery_id;
+};
+
+struct qcom_battmgr_charge_time_request {
+ struct pmic_glink_hdr hdr;
+ __le32 battery_id;
+ __le32 percent;
+ __le32 reserved;
+};
+
+struct qcom_battmgr_discharge_time_request {
+ struct pmic_glink_hdr hdr;
+ __le32 battery_id;
+ __le32 rate; /* 0 for current rate */
+ __le32 reserved;
+};
+
+struct qcom_battmgr_message {
+ struct pmic_glink_hdr hdr;
+ union {
+ struct {
+ __le32 property;
+ __le32 value;
+ __le32 result;
+ } intval;
+ struct {
+ __le32 property;
+ char model[BATTMGR_STRING_LEN];
+ } strval;
+ struct {
+ /*
+ * 0: mWh
+ * 1: mAh
+ */
+ __le32 power_unit;
+ __le32 design_capacity;
+ __le32 last_full_capacity;
+ /*
+ * 0 nonrechargable
+ * 1 rechargable
+ */
+ __le32 battery_tech;
+ __le32 design_voltage; /* mV */
+ __le32 capacity_low;
+ __le32 capacity_warning;
+ __le32 cycle_count;
+ /* thousandth of persent */
+ __le32 accuracy;
+ __le32 max_sample_time_ms;
+ __le32 min_sample_time_ms;
+ __le32 max_average_interval_ms;
+ __le32 min_average_interval_ms;
+ /* granularity between low and warning */
+ __le32 capacity_granularity1;
+ /* granularity between warning and full */
+ __le32 capacity_granularity2;
+ /*
+ * 0: no
+ * 1: cold
+ * 2: hot
+ */
+ __le32 swappable;
+ __le32 capabilities;
+ char model_number[BATTMGR_STRING_LEN];
+ char serial_number[BATTMGR_STRING_LEN];
+ char battery_type[BATTMGR_STRING_LEN];
+ char oem_info[BATTMGR_STRING_LEN];
+ char battery_chemistry[BATTMGR_CHEMISTRY_LEN];
+ char uid[BATTMGR_STRING_LEN];
+ __le32 critical_bias;
+ u8 day;
+ u8 month;
+ __le16 year;
+ __le32 battery_id;
+ } info;
+ struct {
+ /*
+ * BIT(0) discharging
+ * BIT(1) charging
+ * BIT(2) critical low
+ */
+ __le32 battery_state;
+ /* mWh or mAh, based on info->power_unit */
+ __le32 capacity;
+ __le32 rate;
+ /* mv */
+ __le32 battery_voltage;
+ /*
+ * BIT(0) power online
+ * BIT(1) discharging
+ * BIT(2) charging
+ * BIT(3) battery critical
+ */
+ __le32 power_state;
+ /*
+ * 1: AC
+ * 2: USB
+ * 3: Wireless
+ */
+ __le32 charging_source;
+ __le32 temperature;
+ } status;
+ __le32 time;
+ __le32 notification;
+ };
+};
+
+#define BATTMGR_CHARGING_SOURCE_AC 1
+#define BATTMGR_CHARGING_SOURCE_USB 2
+#define BATTMGR_CHARGING_SOURCE_WIRELESS 3
+
+enum qcom_battmgr_unit {
+ QCOM_BATTMGR_UNIT_mWh = 0,
+ QCOM_BATTMGR_UNIT_mAh = 1
+};
+
+struct qcom_battmgr_info {
+ bool valid;
+
+ bool present;
+ unsigned int charge_type;
+ unsigned int design_capacity;
+ unsigned int last_full_capacity;
+ unsigned int voltage_max_design;
+ unsigned int voltage_max;
+ unsigned int capacity_low;
+ unsigned int capacity_warning;
+ unsigned int cycle_count;
+ unsigned int charge_count;
+ char model_number[BATTMGR_STRING_LEN];
+ char serial_number[BATTMGR_STRING_LEN];
+ char oem_info[BATTMGR_STRING_LEN];
+ unsigned char technology;
+ unsigned char day;
+ unsigned char month;
+ unsigned short year;
+};
+
+struct qcom_battmgr_status {
+ unsigned int status;
+ unsigned int health;
+ unsigned int capacity;
+ unsigned int percent;
+ int current_now;
+ int power_now;
+ unsigned int voltage_now;
+ unsigned int voltage_ocv;
+ unsigned int temperature;
+
+ unsigned int discharge_time;
+ unsigned int charge_time;
+};
+
+struct qcom_battmgr_ac {
+ bool online;
+};
+
+struct qcom_battmgr_usb {
+ bool online;
+ unsigned int voltage_now;
+ unsigned int voltage_max;
+ unsigned int current_now;
+ unsigned int current_max;
+ unsigned int current_limit;
+ unsigned int usb_type;
+};
+
+struct qcom_battmgr_wireless {
+ bool online;
+ unsigned int voltage_now;
+ unsigned int voltage_max;
+ unsigned int current_now;
+ unsigned int current_max;
+};
+
+struct qcom_battmgr {
+ struct device *dev;
+ struct pmic_glink_client *client;
+
+ enum qcom_battmgr_variant variant;
+
+ struct power_supply *ac_psy;
+ struct power_supply *bat_psy;
+ struct power_supply *usb_psy;
+ struct power_supply *wls_psy;
+
+ enum qcom_battmgr_unit unit;
+
+ int error;
+ struct completion ack;
+
+ bool service_up;
+
+ struct qcom_battmgr_info info;
+ struct qcom_battmgr_status status;
+ struct qcom_battmgr_ac ac;
+ struct qcom_battmgr_usb usb;
+ struct qcom_battmgr_wireless wireless;
+
+ struct work_struct enable_work;
+
+ /*
+ * @lock is used to prevent concurrent power supply requests to the
+ * firmware, as it then stops responding.
+ */
+ struct mutex lock;
+};
+
+static int qcom_battmgr_request(struct qcom_battmgr *battmgr, void *data, size_t len)
+{
+ unsigned long left;
+ int ret;
+
+ reinit_completion(&battmgr->ack);
+
+ battmgr->error = 0;
+
+ ret = pmic_glink_send(battmgr->client, data, len);
+ if (ret < 0)
+ return ret;
+
+ left = wait_for_completion_timeout(&battmgr->ack, HZ);
+ if (!left)
+ return -ETIMEDOUT;
+
+ return battmgr->error;
+}
+
+static int qcom_battmgr_request_property(struct qcom_battmgr *battmgr, int opcode,
+ int property, u32 value)
+{
+ struct qcom_battmgr_property_request request = {
+ .hdr.owner = cpu_to_le32(PMIC_GLINK_OWNER_BATTMGR),
+ .hdr.type = cpu_to_le32(PMIC_GLINK_REQ_RESP),
+ .hdr.opcode = cpu_to_le32(opcode),
+ .battery = cpu_to_le32(0),
+ .property = cpu_to_le32(property),
+ .value = cpu_to_le32(value),
+ };
+
+ return qcom_battmgr_request(battmgr, &request, sizeof(request));
+}
+
+static int qcom_battmgr_update_status(struct qcom_battmgr *battmgr)
+{
+ struct qcom_battmgr_update_request request = {
+ .hdr.owner = cpu_to_le32(PMIC_GLINK_OWNER_BATTMGR),
+ .hdr.type = cpu_to_le32(PMIC_GLINK_REQ_RESP),
+ .hdr.opcode = cpu_to_le32(BATTMGR_BAT_STATUS),
+ .battery_id = cpu_to_le32(0),
+ };
+
+ return qcom_battmgr_request(battmgr, &request, sizeof(request));
+}
+
+static int qcom_battmgr_update_info(struct qcom_battmgr *battmgr)
+{
+ struct qcom_battmgr_update_request request = {
+ .hdr.owner = cpu_to_le32(PMIC_GLINK_OWNER_BATTMGR),
+ .hdr.type = cpu_to_le32(PMIC_GLINK_REQ_RESP),
+ .hdr.opcode = cpu_to_le32(BATTMGR_BAT_INFO),
+ .battery_id = cpu_to_le32(0),
+ };
+
+ return qcom_battmgr_request(battmgr, &request, sizeof(request));
+}
+
+static int qcom_battmgr_update_charge_time(struct qcom_battmgr *battmgr)
+{
+ struct qcom_battmgr_charge_time_request request = {
+ .hdr.owner = cpu_to_le32(PMIC_GLINK_OWNER_BATTMGR),
+ .hdr.type = cpu_to_le32(PMIC_GLINK_REQ_RESP),
+ .hdr.opcode = cpu_to_le32(BATTMGR_BAT_CHARGE_TIME),
+ .battery_id = cpu_to_le32(0),
+ .percent = cpu_to_le32(100),
+ };
+
+ return qcom_battmgr_request(battmgr, &request, sizeof(request));
+}
+
+static int qcom_battmgr_update_discharge_time(struct qcom_battmgr *battmgr)
+{
+ struct qcom_battmgr_discharge_time_request request = {
+ .hdr.owner = cpu_to_le32(PMIC_GLINK_OWNER_BATTMGR),
+ .hdr.type = cpu_to_le32(PMIC_GLINK_REQ_RESP),
+ .hdr.opcode = cpu_to_le32(BATTMGR_BAT_DISCHARGE_TIME),
+ .battery_id = cpu_to_le32(0),
+ .rate = cpu_to_le32(0),
+ };
+
+ return qcom_battmgr_request(battmgr, &request, sizeof(request));
+}
+
+static const u8 sm8350_bat_prop_map[] = {
+ [POWER_SUPPLY_PROP_STATUS] = BATT_STATUS,
+ [POWER_SUPPLY_PROP_HEALTH] = BATT_HEALTH,
+ [POWER_SUPPLY_PROP_PRESENT] = BATT_PRESENT,
+ [POWER_SUPPLY_PROP_CHARGE_TYPE] = BATT_CHG_TYPE,
+ [POWER_SUPPLY_PROP_CAPACITY] = BATT_CAPACITY,
+ [POWER_SUPPLY_PROP_VOLTAGE_OCV] = BATT_VOLT_OCV,
+ [POWER_SUPPLY_PROP_VOLTAGE_NOW] = BATT_VOLT_NOW,
+ [POWER_SUPPLY_PROP_VOLTAGE_MAX] = BATT_VOLT_MAX,
+ [POWER_SUPPLY_PROP_CURRENT_NOW] = BATT_CURR_NOW,
+ [POWER_SUPPLY_PROP_TEMP] = BATT_TEMP,
+ [POWER_SUPPLY_PROP_TECHNOLOGY] = BATT_TECHNOLOGY,
+ [POWER_SUPPLY_PROP_CHARGE_COUNTER] = BATT_CHG_COUNTER,
+ [POWER_SUPPLY_PROP_CYCLE_COUNT] = BATT_CYCLE_COUNT,
+ [POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN] = BATT_CHG_FULL_DESIGN,
+ [POWER_SUPPLY_PROP_CHARGE_FULL] = BATT_CHG_FULL,
+ [POWER_SUPPLY_PROP_MODEL_NAME] = BATT_MODEL_NAME,
+ [POWER_SUPPLY_PROP_TIME_TO_FULL_AVG] = BATT_TTF_AVG,
+ [POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG] = BATT_TTE_AVG,
+ [POWER_SUPPLY_PROP_POWER_NOW] = BATT_POWER_NOW,
+};
+
+static int qcom_battmgr_bat_sm8350_update(struct qcom_battmgr *battmgr,
+ enum power_supply_property psp)
+{
+ unsigned int prop;
+ int ret;
+
+ if (psp >= ARRAY_SIZE(sm8350_bat_prop_map))
+ return -EINVAL;
+
+ prop = sm8350_bat_prop_map[psp];
+
+ mutex_lock(&battmgr->lock);
+ ret = qcom_battmgr_request_property(battmgr, BATTMGR_BAT_PROPERTY_GET, prop, 0);
+ mutex_unlock(&battmgr->lock);
+
+ return ret;
+}
+
+static int qcom_battmgr_bat_sc8280xp_update(struct qcom_battmgr *battmgr,
+ enum power_supply_property psp)
+{
+ int ret;
+
+ mutex_lock(&battmgr->lock);
+
+ if (!battmgr->info.valid) {
+ ret = qcom_battmgr_update_info(battmgr);
+ if (ret < 0)
+ goto out_unlock;
+ battmgr->info.valid = true;
+ }
+
+ ret = qcom_battmgr_update_status(battmgr);
+ if (ret < 0)
+ goto out_unlock;
+
+ if (psp == POWER_SUPPLY_PROP_TIME_TO_FULL_AVG) {
+ ret = qcom_battmgr_update_charge_time(battmgr);
+ if (ret < 0) {
+ ret = -ENODATA;
+ goto out_unlock;
+ }
+ }
+
+ if (psp == POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG) {
+ ret = qcom_battmgr_update_discharge_time(battmgr);
+ if (ret < 0) {
+ ret = -ENODATA;
+ goto out_unlock;
+ }
+ }
+
+out_unlock:
+ mutex_unlock(&battmgr->lock);
+ return ret;
+}
+
+static int qcom_battmgr_bat_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct qcom_battmgr *battmgr = power_supply_get_drvdata(psy);
+ enum qcom_battmgr_unit unit = battmgr->unit;
+ int ret;
+
+ if (!battmgr->service_up)
+ return -ENODEV;
+
+ if (battmgr->variant == QCOM_BATTMGR_SC8280XP)
+ ret = qcom_battmgr_bat_sc8280xp_update(battmgr, psp);
+ else
+ ret = qcom_battmgr_bat_sm8350_update(battmgr, psp);
+ if (ret < 0)
+ return ret;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ val->intval = battmgr->status.status;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_TYPE:
+ val->intval = battmgr->info.charge_type;
+ break;
+ case POWER_SUPPLY_PROP_HEALTH:
+ val->intval = battmgr->status.health;
+ break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = battmgr->info.present;
+ break;
+ case POWER_SUPPLY_PROP_TECHNOLOGY:
+ val->intval = battmgr->info.technology;
+ break;
+ case POWER_SUPPLY_PROP_CYCLE_COUNT:
+ val->intval = battmgr->info.cycle_count;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+ val->intval = battmgr->info.voltage_max_design;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+ val->intval = battmgr->info.voltage_max;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ val->intval = battmgr->status.voltage_now;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_OCV:
+ val->intval = battmgr->status.voltage_ocv;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ val->intval = battmgr->status.current_now;
+ break;
+ case POWER_SUPPLY_PROP_POWER_NOW:
+ val->intval = battmgr->status.power_now;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+ if (unit != QCOM_BATTMGR_UNIT_mAh)
+ return -ENODATA;
+ val->intval = battmgr->info.design_capacity;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_FULL:
+ if (unit != QCOM_BATTMGR_UNIT_mAh)
+ return -ENODATA;
+ val->intval = battmgr->info.last_full_capacity;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_EMPTY:
+ if (unit != QCOM_BATTMGR_UNIT_mAh)
+ return -ENODATA;
+ val->intval = battmgr->info.capacity_low;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_NOW:
+ if (unit != QCOM_BATTMGR_UNIT_mAh)
+ return -ENODATA;
+ val->intval = battmgr->status.capacity;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_COUNTER:
+ val->intval = battmgr->info.charge_count;
+ break;
+ case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
+ if (unit != QCOM_BATTMGR_UNIT_mWh)
+ return -ENODATA;
+ val->intval = battmgr->info.design_capacity;
+ break;
+ case POWER_SUPPLY_PROP_ENERGY_FULL:
+ if (unit != QCOM_BATTMGR_UNIT_mWh)
+ return -ENODATA;
+ val->intval = battmgr->info.last_full_capacity;
+ break;
+ case POWER_SUPPLY_PROP_ENERGY_EMPTY:
+ if (unit != QCOM_BATTMGR_UNIT_mWh)
+ return -ENODATA;
+ val->intval = battmgr->info.capacity_low;
+ break;
+ case POWER_SUPPLY_PROP_ENERGY_NOW:
+ if (unit != QCOM_BATTMGR_UNIT_mWh)
+ return -ENODATA;
+ val->intval = battmgr->status.capacity;
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY:
+ val->intval = battmgr->status.percent;
+ break;
+ case POWER_SUPPLY_PROP_TEMP:
+ val->intval = battmgr->status.temperature;
+ break;
+ case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
+ val->intval = battmgr->status.discharge_time;
+ break;
+ case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
+ val->intval = battmgr->status.charge_time;
+ break;
+ case POWER_SUPPLY_PROP_MANUFACTURE_YEAR:
+ val->intval = battmgr->info.year;
+ break;
+ case POWER_SUPPLY_PROP_MANUFACTURE_MONTH:
+ val->intval = battmgr->info.month;
+ break;
+ case POWER_SUPPLY_PROP_MANUFACTURE_DAY:
+ val->intval = battmgr->info.day;
+ break;
+ case POWER_SUPPLY_PROP_MODEL_NAME:
+ val->strval = battmgr->info.model_number;
+ break;
+ case POWER_SUPPLY_PROP_MANUFACTURER:
+ val->strval = battmgr->info.oem_info;
+ break;
+ case POWER_SUPPLY_PROP_SERIAL_NUMBER:
+ val->strval = battmgr->info.serial_number;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const enum power_supply_property sc8280xp_bat_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_TECHNOLOGY,
+ POWER_SUPPLY_PROP_CYCLE_COUNT,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_POWER_NOW,
+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+ POWER_SUPPLY_PROP_CHARGE_FULL,
+ POWER_SUPPLY_PROP_CHARGE_EMPTY,
+ POWER_SUPPLY_PROP_CHARGE_NOW,
+ POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
+ POWER_SUPPLY_PROP_ENERGY_FULL,
+ POWER_SUPPLY_PROP_ENERGY_EMPTY,
+ POWER_SUPPLY_PROP_ENERGY_NOW,
+ POWER_SUPPLY_PROP_TEMP,
+ POWER_SUPPLY_PROP_MANUFACTURE_YEAR,
+ POWER_SUPPLY_PROP_MANUFACTURE_MONTH,
+ POWER_SUPPLY_PROP_MANUFACTURE_DAY,
+ POWER_SUPPLY_PROP_MODEL_NAME,
+ POWER_SUPPLY_PROP_MANUFACTURER,
+ POWER_SUPPLY_PROP_SERIAL_NUMBER,
+};
+
+static const struct power_supply_desc sc8280xp_bat_psy_desc = {
+ .name = "qcom-battmgr-bat",
+ .type = POWER_SUPPLY_TYPE_BATTERY,
+ .properties = sc8280xp_bat_props,
+ .num_properties = ARRAY_SIZE(sc8280xp_bat_props),
+ .get_property = qcom_battmgr_bat_get_property,
+};
+
+static const enum power_supply_property sm8350_bat_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_CHARGE_TYPE,
+ POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_VOLTAGE_OCV,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_TEMP,
+ POWER_SUPPLY_PROP_TECHNOLOGY,
+ POWER_SUPPLY_PROP_CHARGE_COUNTER,
+ POWER_SUPPLY_PROP_CYCLE_COUNT,
+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+ POWER_SUPPLY_PROP_CHARGE_FULL,
+ POWER_SUPPLY_PROP_MODEL_NAME,
+ POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
+ POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
+ POWER_SUPPLY_PROP_POWER_NOW,
+};
+
+static const struct power_supply_desc sm8350_bat_psy_desc = {
+ .name = "qcom-battmgr-bat",
+ .type = POWER_SUPPLY_TYPE_BATTERY,
+ .properties = sm8350_bat_props,
+ .num_properties = ARRAY_SIZE(sm8350_bat_props),
+ .get_property = qcom_battmgr_bat_get_property,
+};
+
+static int qcom_battmgr_ac_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct qcom_battmgr *battmgr = power_supply_get_drvdata(psy);
+ int ret;
+
+ if (!battmgr->service_up)
+ return -ENODEV;
+
+ ret = qcom_battmgr_bat_sc8280xp_update(battmgr, psp);
+ if (ret)
+ return ret;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = battmgr->ac.online;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const enum power_supply_property sc8280xp_ac_props[] = {
+ POWER_SUPPLY_PROP_ONLINE,
+};
+
+static const struct power_supply_desc sc8280xp_ac_psy_desc = {
+ .name = "qcom-battmgr-ac",
+ .type = POWER_SUPPLY_TYPE_MAINS,
+ .properties = sc8280xp_ac_props,
+ .num_properties = ARRAY_SIZE(sc8280xp_ac_props),
+ .get_property = qcom_battmgr_ac_get_property,
+};
+
+static const u8 sm8350_usb_prop_map[] = {
+ [POWER_SUPPLY_PROP_ONLINE] = USB_ONLINE,
+ [POWER_SUPPLY_PROP_VOLTAGE_NOW] = USB_VOLT_NOW,
+ [POWER_SUPPLY_PROP_VOLTAGE_MAX] = USB_VOLT_MAX,
+ [POWER_SUPPLY_PROP_CURRENT_NOW] = USB_CURR_NOW,
+ [POWER_SUPPLY_PROP_CURRENT_MAX] = USB_CURR_MAX,
+ [POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT] = USB_INPUT_CURR_LIMIT,
+ [POWER_SUPPLY_PROP_USB_TYPE] = USB_TYPE,
+};
+
+static int qcom_battmgr_usb_sm8350_update(struct qcom_battmgr *battmgr,
+ enum power_supply_property psp)
+{
+ unsigned int prop;
+ int ret;
+
+ if (psp >= ARRAY_SIZE(sm8350_usb_prop_map))
+ return -EINVAL;
+
+ prop = sm8350_usb_prop_map[psp];
+
+ mutex_lock(&battmgr->lock);
+ ret = qcom_battmgr_request_property(battmgr, BATTMGR_USB_PROPERTY_GET, prop, 0);
+ mutex_unlock(&battmgr->lock);
+
+ return ret;
+}
+
+static int qcom_battmgr_usb_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct qcom_battmgr *battmgr = power_supply_get_drvdata(psy);
+ int ret;
+
+ if (!battmgr->service_up)
+ return -ENODEV;
+
+ if (battmgr->variant == QCOM_BATTMGR_SC8280XP)
+ ret = qcom_battmgr_bat_sc8280xp_update(battmgr, psp);
+ else
+ ret = qcom_battmgr_usb_sm8350_update(battmgr, psp);
+ if (ret)
+ return ret;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = battmgr->usb.online;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ val->intval = battmgr->usb.voltage_now;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+ val->intval = battmgr->usb.voltage_max;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ val->intval = battmgr->usb.current_now;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ val->intval = battmgr->usb.current_max;
+ break;
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+ val->intval = battmgr->usb.current_limit;
+ break;
+ case POWER_SUPPLY_PROP_USB_TYPE:
+ val->intval = battmgr->usb.usb_type;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const enum power_supply_usb_type usb_psy_supported_types[] = {
+ POWER_SUPPLY_USB_TYPE_UNKNOWN,
+ POWER_SUPPLY_USB_TYPE_SDP,
+ POWER_SUPPLY_USB_TYPE_DCP,
+ POWER_SUPPLY_USB_TYPE_CDP,
+ POWER_SUPPLY_USB_TYPE_ACA,
+ POWER_SUPPLY_USB_TYPE_C,
+ POWER_SUPPLY_USB_TYPE_PD,
+ POWER_SUPPLY_USB_TYPE_PD_DRP,
+ POWER_SUPPLY_USB_TYPE_PD_PPS,
+ POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID,
+};
+
+static const enum power_supply_property sc8280xp_usb_props[] = {
+ POWER_SUPPLY_PROP_ONLINE,
+};
+
+static const struct power_supply_desc sc8280xp_usb_psy_desc = {
+ .name = "qcom-battmgr-usb",
+ .type = POWER_SUPPLY_TYPE_USB,
+ .properties = sc8280xp_usb_props,
+ .num_properties = ARRAY_SIZE(sc8280xp_usb_props),
+ .get_property = qcom_battmgr_usb_get_property,
+ .usb_types = usb_psy_supported_types,
+ .num_usb_types = ARRAY_SIZE(usb_psy_supported_types),
+};
+
+static const enum power_supply_property sm8350_usb_props[] = {
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CURRENT_MAX,
+ POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
+ POWER_SUPPLY_PROP_USB_TYPE,
+};
+
+static const struct power_supply_desc sm8350_usb_psy_desc = {
+ .name = "qcom-battmgr-usb",
+ .type = POWER_SUPPLY_TYPE_USB,
+ .properties = sm8350_usb_props,
+ .num_properties = ARRAY_SIZE(sm8350_usb_props),
+ .get_property = qcom_battmgr_usb_get_property,
+ .usb_types = usb_psy_supported_types,
+ .num_usb_types = ARRAY_SIZE(usb_psy_supported_types),
+};
+
+static const u8 sm8350_wls_prop_map[] = {
+ [POWER_SUPPLY_PROP_ONLINE] = WLS_ONLINE,
+ [POWER_SUPPLY_PROP_VOLTAGE_NOW] = WLS_VOLT_NOW,
+ [POWER_SUPPLY_PROP_VOLTAGE_MAX] = WLS_VOLT_MAX,
+ [POWER_SUPPLY_PROP_CURRENT_NOW] = WLS_CURR_NOW,
+ [POWER_SUPPLY_PROP_CURRENT_MAX] = WLS_CURR_MAX,
+};
+
+static int qcom_battmgr_wls_sm8350_update(struct qcom_battmgr *battmgr,
+ enum power_supply_property psp)
+{
+ unsigned int prop;
+ int ret;
+
+ if (psp >= ARRAY_SIZE(sm8350_wls_prop_map))
+ return -EINVAL;
+
+ prop = sm8350_wls_prop_map[psp];
+
+ mutex_lock(&battmgr->lock);
+ ret = qcom_battmgr_request_property(battmgr, BATTMGR_WLS_PROPERTY_GET, prop, 0);
+ mutex_unlock(&battmgr->lock);
+
+ return ret;
+}
+
+static int qcom_battmgr_wls_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct qcom_battmgr *battmgr = power_supply_get_drvdata(psy);
+ int ret;
+
+ if (!battmgr->service_up)
+ return -ENODEV;
+
+ if (battmgr->variant == QCOM_BATTMGR_SC8280XP)
+ ret = qcom_battmgr_bat_sc8280xp_update(battmgr, psp);
+ else
+ ret = qcom_battmgr_wls_sm8350_update(battmgr, psp);
+ if (ret < 0)
+ return ret;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = battmgr->wireless.online;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ val->intval = battmgr->wireless.voltage_now;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+ val->intval = battmgr->wireless.voltage_max;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ val->intval = battmgr->wireless.current_now;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ val->intval = battmgr->wireless.current_max;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const enum power_supply_property sc8280xp_wls_props[] = {
+ POWER_SUPPLY_PROP_ONLINE,
+};
+
+static const struct power_supply_desc sc8280xp_wls_psy_desc = {
+ .name = "qcom-battmgr-wls",
+ .type = POWER_SUPPLY_TYPE_WIRELESS,
+ .properties = sc8280xp_wls_props,
+ .num_properties = ARRAY_SIZE(sc8280xp_wls_props),
+ .get_property = qcom_battmgr_wls_get_property,
+};
+
+static const enum power_supply_property sm8350_wls_props[] = {
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CURRENT_MAX,
+};
+
+static const struct power_supply_desc sm8350_wls_psy_desc = {
+ .name = "qcom-battmgr-wls",
+ .type = POWER_SUPPLY_TYPE_WIRELESS,
+ .properties = sm8350_wls_props,
+ .num_properties = ARRAY_SIZE(sm8350_wls_props),
+ .get_property = qcom_battmgr_wls_get_property,
+};
+
+static void qcom_battmgr_notification(struct qcom_battmgr *battmgr,
+ const struct qcom_battmgr_message *msg,
+ int len)
+{
+ size_t payload_len = len - sizeof(struct pmic_glink_hdr);
+ unsigned int notification;
+
+ if (payload_len != sizeof(msg->notification)) {
+ dev_warn(battmgr->dev, "ignoring notification with invalid length\n");
+ return;
+ }
+
+ notification = le32_to_cpu(msg->notification);
+ switch (notification) {
+ case NOTIF_BAT_INFO:
+ battmgr->info.valid = false;
+ fallthrough;
+ case NOTIF_BAT_STATUS:
+ case NOTIF_BAT_PROPERTY:
+ power_supply_changed(battmgr->bat_psy);
+ break;
+ case NOTIF_USB_PROPERTY:
+ power_supply_changed(battmgr->usb_psy);
+ break;
+ case NOTIF_WLS_PROPERTY:
+ power_supply_changed(battmgr->wls_psy);
+ break;
+ default:
+ dev_err(battmgr->dev, "unknown notification: %#x\n", notification);
+ break;
+ }
+}
+
+static void qcom_battmgr_sc8280xp_strcpy(char *dest, const char *src)
+{
+ size_t len = src[0];
+
+ /* Some firmware versions return Pascal-style strings */
+ if (len < BATTMGR_STRING_LEN && len == strnlen(src + 1, BATTMGR_STRING_LEN - 1)) {
+ memcpy(dest, src + 1, len);
+ dest[len] = '\0';
+ } else {
+ memcpy(dest, src, BATTMGR_STRING_LEN);
+ }
+}
+
+static unsigned int qcom_battmgr_sc8280xp_parse_technology(const char *chemistry)
+{
+ if (!strncmp(chemistry, "LIO", BATTMGR_CHEMISTRY_LEN))
+ return POWER_SUPPLY_TECHNOLOGY_LION;
+
+ pr_err("Unknown battery technology '%s'\n", chemistry);
+ return POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
+}
+
+static unsigned int qcom_battmgr_sc8280xp_convert_temp(unsigned int temperature)
+{
+ return DIV_ROUND_CLOSEST(temperature, 10);
+}
+
+static void qcom_battmgr_sc8280xp_callback(struct qcom_battmgr *battmgr,
+ const struct qcom_battmgr_message *resp,
+ size_t len)
+{
+ unsigned int opcode = le32_to_cpu(resp->hdr.opcode);
+ unsigned int source;
+ unsigned int state;
+ size_t payload_len = len - sizeof(struct pmic_glink_hdr);
+
+ if (payload_len < sizeof(__le32)) {
+ dev_warn(battmgr->dev, "invalid payload length for %#x: %zd\n",
+ opcode, len);
+ return;
+ }
+
+ switch (opcode) {
+ case BATTMGR_REQUEST_NOTIFICATION:
+ battmgr->error = 0;
+ break;
+ case BATTMGR_BAT_INFO:
+ if (payload_len != sizeof(resp->info)) {
+ dev_warn(battmgr->dev,
+ "invalid payload length for battery information request: %zd\n",
+ payload_len);
+ battmgr->error = -ENODATA;
+ return;
+ }
+
+ battmgr->unit = le32_to_cpu(resp->info.power_unit);
+
+ battmgr->info.present = true;
+ battmgr->info.design_capacity = le32_to_cpu(resp->info.design_capacity) * 1000;
+ battmgr->info.last_full_capacity = le32_to_cpu(resp->info.last_full_capacity) * 1000;
+ battmgr->info.voltage_max_design = le32_to_cpu(resp->info.design_voltage) * 1000;
+ battmgr->info.capacity_low = le32_to_cpu(resp->info.capacity_low) * 1000;
+ battmgr->info.cycle_count = le32_to_cpu(resp->info.cycle_count);
+ qcom_battmgr_sc8280xp_strcpy(battmgr->info.model_number, resp->info.model_number);
+ qcom_battmgr_sc8280xp_strcpy(battmgr->info.serial_number, resp->info.serial_number);
+ battmgr->info.technology = qcom_battmgr_sc8280xp_parse_technology(resp->info.battery_chemistry);
+ qcom_battmgr_sc8280xp_strcpy(battmgr->info.oem_info, resp->info.oem_info);
+ battmgr->info.day = resp->info.day;
+ battmgr->info.month = resp->info.month;
+ battmgr->info.year = le16_to_cpu(resp->info.year);
+ break;
+ case BATTMGR_BAT_STATUS:
+ if (payload_len != sizeof(resp->status)) {
+ dev_warn(battmgr->dev,
+ "invalid payload length for battery status request: %zd\n",
+ payload_len);
+ battmgr->error = -ENODATA;
+ return;
+ }
+
+ state = le32_to_cpu(resp->status.battery_state);
+ if (state & BIT(0))
+ battmgr->status.status = POWER_SUPPLY_STATUS_DISCHARGING;
+ else if (state & BIT(1))
+ battmgr->status.status = POWER_SUPPLY_STATUS_CHARGING;
+ else
+ battmgr->status.status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+
+ battmgr->status.capacity = le32_to_cpu(resp->status.capacity) * 1000;
+ battmgr->status.power_now = le32_to_cpu(resp->status.rate) * 1000;
+ battmgr->status.voltage_now = le32_to_cpu(resp->status.battery_voltage) * 1000;
+ battmgr->status.temperature = qcom_battmgr_sc8280xp_convert_temp(le32_to_cpu(resp->status.temperature));
+
+ source = le32_to_cpu(resp->status.charging_source);
+ battmgr->ac.online = source == BATTMGR_CHARGING_SOURCE_AC;
+ battmgr->usb.online = source == BATTMGR_CHARGING_SOURCE_USB;
+ battmgr->wireless.online = source == BATTMGR_CHARGING_SOURCE_WIRELESS;
+ break;
+ case BATTMGR_BAT_DISCHARGE_TIME:
+ battmgr->status.discharge_time = le32_to_cpu(resp->time);
+ break;
+ case BATTMGR_BAT_CHARGE_TIME:
+ battmgr->status.charge_time = le32_to_cpu(resp->time);
+ break;
+ default:
+ dev_warn(battmgr->dev, "unknown message %#x\n", opcode);
+ break;
+ }
+
+ complete(&battmgr->ack);
+}
+
+static void qcom_battmgr_sm8350_callback(struct qcom_battmgr *battmgr,
+ const struct qcom_battmgr_message *resp,
+ size_t len)
+{
+ unsigned int property;
+ unsigned int opcode = le32_to_cpu(resp->hdr.opcode);
+ size_t payload_len = len - sizeof(struct pmic_glink_hdr);
+ unsigned int val;
+
+ if (payload_len < sizeof(__le32)) {
+ dev_warn(battmgr->dev, "invalid payload length for %#x: %zd\n",
+ opcode, len);
+ return;
+ }
+
+ switch (opcode) {
+ case BATTMGR_BAT_PROPERTY_GET:
+ property = le32_to_cpu(resp->intval.property);
+ if (property == BATT_MODEL_NAME) {
+ if (payload_len != sizeof(resp->strval)) {
+ dev_warn(battmgr->dev,
+ "invalid payload length for BATT_MODEL_NAME request: %zd\n",
+ payload_len);
+ battmgr->error = -ENODATA;
+ return;
+ }
+ } else {
+ if (payload_len != sizeof(resp->intval)) {
+ dev_warn(battmgr->dev,
+ "invalid payload length for %#x request: %zd\n",
+ property, payload_len);
+ battmgr->error = -ENODATA;
+ return;
+ }
+
+ battmgr->error = le32_to_cpu(resp->intval.result);
+ if (battmgr->error)
+ goto out_complete;
+ }
+
+ switch (property) {
+ case BATT_STATUS:
+ battmgr->status.status = le32_to_cpu(resp->intval.value);
+ break;
+ case BATT_HEALTH:
+ battmgr->status.health = le32_to_cpu(resp->intval.value);
+ break;
+ case BATT_PRESENT:
+ battmgr->info.present = le32_to_cpu(resp->intval.value);
+ break;
+ case BATT_CHG_TYPE:
+ battmgr->info.charge_type = le32_to_cpu(resp->intval.value);
+ break;
+ case BATT_CAPACITY:
+ battmgr->status.percent = le32_to_cpu(resp->intval.value) / 100;
+ break;
+ case BATT_VOLT_OCV:
+ battmgr->status.voltage_ocv = le32_to_cpu(resp->intval.value);
+ break;
+ case BATT_VOLT_NOW:
+ battmgr->status.voltage_now = le32_to_cpu(resp->intval.value);
+ break;
+ case BATT_VOLT_MAX:
+ battmgr->info.voltage_max = le32_to_cpu(resp->intval.value);
+ break;
+ case BATT_CURR_NOW:
+ battmgr->status.current_now = le32_to_cpu(resp->intval.value);
+ break;
+ case BATT_TEMP:
+ val = le32_to_cpu(resp->intval.value);
+ battmgr->status.temperature = DIV_ROUND_CLOSEST(val, 10);
+ break;
+ case BATT_TECHNOLOGY:
+ battmgr->info.technology = le32_to_cpu(resp->intval.value);
+ break;
+ case BATT_CHG_COUNTER:
+ battmgr->info.charge_count = le32_to_cpu(resp->intval.value);
+ break;
+ case BATT_CYCLE_COUNT:
+ battmgr->info.cycle_count = le32_to_cpu(resp->intval.value);
+ break;
+ case BATT_CHG_FULL_DESIGN:
+ battmgr->info.design_capacity = le32_to_cpu(resp->intval.value);
+ break;
+ case BATT_CHG_FULL:
+ battmgr->info.last_full_capacity = le32_to_cpu(resp->intval.value);
+ break;
+ case BATT_MODEL_NAME:
+ strscpy(battmgr->info.model_number, resp->strval.model, BATTMGR_STRING_LEN);
+ break;
+ case BATT_TTF_AVG:
+ battmgr->status.charge_time = le32_to_cpu(resp->intval.value);
+ break;
+ case BATT_TTE_AVG:
+ battmgr->status.discharge_time = le32_to_cpu(resp->intval.value);
+ break;
+ case BATT_POWER_NOW:
+ battmgr->status.power_now = le32_to_cpu(resp->intval.value);
+ break;
+ default:
+ dev_warn(battmgr->dev, "unknown property %#x\n", property);
+ break;
+ }
+ break;
+ case BATTMGR_USB_PROPERTY_GET:
+ property = le32_to_cpu(resp->intval.property);
+ if (payload_len != sizeof(resp->intval)) {
+ dev_warn(battmgr->dev,
+ "invalid payload length for %#x request: %zd\n",
+ property, payload_len);
+ battmgr->error = -ENODATA;
+ return;
+ }
+
+ battmgr->error = le32_to_cpu(resp->intval.result);
+ if (battmgr->error)
+ goto out_complete;
+
+ switch (property) {
+ case USB_ONLINE:
+ battmgr->usb.online = le32_to_cpu(resp->intval.value);
+ break;
+ case USB_VOLT_NOW:
+ battmgr->usb.voltage_now = le32_to_cpu(resp->intval.value);
+ break;
+ case USB_VOLT_MAX:
+ battmgr->usb.voltage_max = le32_to_cpu(resp->intval.value);
+ break;
+ case USB_CURR_NOW:
+ battmgr->usb.current_now = le32_to_cpu(resp->intval.value);
+ break;
+ case USB_CURR_MAX:
+ battmgr->usb.current_max = le32_to_cpu(resp->intval.value);
+ break;
+ case USB_INPUT_CURR_LIMIT:
+ battmgr->usb.current_limit = le32_to_cpu(resp->intval.value);
+ break;
+ case USB_TYPE:
+ battmgr->usb.usb_type = le32_to_cpu(resp->intval.value);
+ break;
+ default:
+ dev_warn(battmgr->dev, "unknown property %#x\n", property);
+ break;
+ }
+ break;
+ case BATTMGR_WLS_PROPERTY_GET:
+ property = le32_to_cpu(resp->intval.property);
+ if (payload_len != sizeof(resp->intval)) {
+ dev_warn(battmgr->dev,
+ "invalid payload length for %#x request: %zd\n",
+ property, payload_len);
+ battmgr->error = -ENODATA;
+ return;
+ }
+
+ battmgr->error = le32_to_cpu(resp->intval.result);
+ if (battmgr->error)
+ goto out_complete;
+
+ switch (property) {
+ case WLS_ONLINE:
+ battmgr->wireless.online = le32_to_cpu(resp->intval.value);
+ break;
+ case WLS_VOLT_NOW:
+ battmgr->wireless.voltage_now = le32_to_cpu(resp->intval.value);
+ break;
+ case WLS_VOLT_MAX:
+ battmgr->wireless.voltage_max = le32_to_cpu(resp->intval.value);
+ break;
+ case WLS_CURR_NOW:
+ battmgr->wireless.current_now = le32_to_cpu(resp->intval.value);
+ break;
+ case WLS_CURR_MAX:
+ battmgr->wireless.current_max = le32_to_cpu(resp->intval.value);
+ break;
+ default:
+ dev_warn(battmgr->dev, "unknown property %#x\n", property);
+ break;
+ }
+ break;
+ case BATTMGR_REQUEST_NOTIFICATION:
+ battmgr->error = 0;
+ break;
+ default:
+ dev_warn(battmgr->dev, "unknown message %#x\n", opcode);
+ break;
+ }
+
+out_complete:
+ complete(&battmgr->ack);
+}
+
+static void qcom_battmgr_callback(const void *data, size_t len, void *priv)
+{
+ const struct pmic_glink_hdr *hdr = data;
+ struct qcom_battmgr *battmgr = priv;
+ unsigned int opcode = le32_to_cpu(hdr->opcode);
+
+ if (opcode == BATTMGR_NOTIFICATION)
+ qcom_battmgr_notification(battmgr, data, len);
+ else if (battmgr->variant == QCOM_BATTMGR_SC8280XP)
+ qcom_battmgr_sc8280xp_callback(battmgr, data, len);
+ else
+ qcom_battmgr_sm8350_callback(battmgr, data, len);
+}
+
+static void qcom_battmgr_enable_worker(struct work_struct *work)
+{
+ struct qcom_battmgr *battmgr = container_of(work, struct qcom_battmgr, enable_work);
+ struct qcom_battmgr_enable_request req = {
+ .hdr.owner = PMIC_GLINK_OWNER_BATTMGR,
+ .hdr.type = PMIC_GLINK_NOTIFY,
+ .hdr.opcode = BATTMGR_REQUEST_NOTIFICATION,
+ };
+ int ret;
+
+ ret = qcom_battmgr_request(battmgr, &req, sizeof(req));
+ if (ret)
+ dev_err(battmgr->dev, "failed to request power notifications\n");
+}
+
+static void qcom_battmgr_pdr_notify(void *priv, int state)
+{
+ struct qcom_battmgr *battmgr = priv;
+
+ if (state == SERVREG_SERVICE_STATE_UP) {
+ battmgr->service_up = true;
+ schedule_work(&battmgr->enable_work);
+ } else {
+ battmgr->service_up = false;
+ }
+}
+
+static const struct of_device_id qcom_battmgr_of_variants[] = {
+ { .compatible = "qcom,sc8180x-pmic-glink", .data = (void *)QCOM_BATTMGR_SC8280XP },
+ { .compatible = "qcom,sc8280xp-pmic-glink", .data = (void *)QCOM_BATTMGR_SC8280XP },
+ /* Unmatched devices falls back to QCOM_BATTMGR_SM8350 */
+ {}
+};
+
+static char *qcom_battmgr_battery[] = { "battery" };
+
+static int qcom_battmgr_probe(struct auxiliary_device *adev,
+ const struct auxiliary_device_id *id)
+{
+ struct power_supply_config psy_cfg_supply = {};
+ struct power_supply_config psy_cfg = {};
+ const struct of_device_id *match;
+ struct qcom_battmgr *battmgr;
+ struct device *dev = &adev->dev;
+
+ battmgr = devm_kzalloc(dev, sizeof(*battmgr), GFP_KERNEL);
+ if (!battmgr)
+ return -ENOMEM;
+
+ battmgr->dev = dev;
+
+ psy_cfg.drv_data = battmgr;
+ psy_cfg.of_node = adev->dev.of_node;
+
+ psy_cfg_supply.drv_data = battmgr;
+ psy_cfg_supply.of_node = adev->dev.of_node;
+ psy_cfg_supply.supplied_to = qcom_battmgr_battery;
+ psy_cfg_supply.num_supplicants = 1;
+
+ INIT_WORK(&battmgr->enable_work, qcom_battmgr_enable_worker);
+ mutex_init(&battmgr->lock);
+ init_completion(&battmgr->ack);
+
+ match = of_match_device(qcom_battmgr_of_variants, dev->parent);
+ if (match)
+ battmgr->variant = (unsigned long)match->data;
+ else
+ battmgr->variant = QCOM_BATTMGR_SM8350;
+
+ if (battmgr->variant == QCOM_BATTMGR_SC8280XP) {
+ battmgr->bat_psy = devm_power_supply_register(dev, &sc8280xp_bat_psy_desc, &psy_cfg);
+ if (IS_ERR(battmgr->bat_psy))
+ return dev_err_probe(dev, PTR_ERR(battmgr->bat_psy),
+ "failed to register battery power supply\n");
+
+ battmgr->ac_psy = devm_power_supply_register(dev, &sc8280xp_ac_psy_desc, &psy_cfg_supply);
+ if (IS_ERR(battmgr->ac_psy))
+ return dev_err_probe(dev, PTR_ERR(battmgr->ac_psy),
+ "failed to register AC power supply\n");
+
+ battmgr->usb_psy = devm_power_supply_register(dev, &sc8280xp_usb_psy_desc, &psy_cfg_supply);
+ if (IS_ERR(battmgr->usb_psy))
+ return dev_err_probe(dev, PTR_ERR(battmgr->usb_psy),
+ "failed to register USB power supply\n");
+
+ battmgr->wls_psy = devm_power_supply_register(dev, &sc8280xp_wls_psy_desc, &psy_cfg_supply);
+ if (IS_ERR(battmgr->wls_psy))
+ return dev_err_probe(dev, PTR_ERR(battmgr->wls_psy),
+ "failed to register wireless charing power supply\n");
+ } else {
+ battmgr->bat_psy = devm_power_supply_register(dev, &sm8350_bat_psy_desc, &psy_cfg);
+ if (IS_ERR(battmgr->bat_psy))
+ return dev_err_probe(dev, PTR_ERR(battmgr->bat_psy),
+ "failed to register battery power supply\n");
+
+ battmgr->usb_psy = devm_power_supply_register(dev, &sm8350_usb_psy_desc, &psy_cfg_supply);
+ if (IS_ERR(battmgr->usb_psy))
+ return dev_err_probe(dev, PTR_ERR(battmgr->usb_psy),
+ "failed to register USB power supply\n");
+
+ battmgr->wls_psy = devm_power_supply_register(dev, &sm8350_wls_psy_desc, &psy_cfg_supply);
+ if (IS_ERR(battmgr->wls_psy))
+ return dev_err_probe(dev, PTR_ERR(battmgr->wls_psy),
+ "failed to register wireless charing power supply\n");
+ }
+
+ battmgr->client = devm_pmic_glink_register_client(dev,
+ PMIC_GLINK_OWNER_BATTMGR,
+ qcom_battmgr_callback,
+ qcom_battmgr_pdr_notify,
+ battmgr);
+ return PTR_ERR_OR_ZERO(battmgr->client);
+}
+
+static const struct auxiliary_device_id qcom_battmgr_id_table[] = {
+ { .name = "pmic_glink.power-supply", },
+ {},
+};
+MODULE_DEVICE_TABLE(auxiliary, qcom_battmgr_id_table);
+
+static struct auxiliary_driver qcom_battmgr_driver = {
+ .name = "pmic_glink_power_supply",
+ .probe = qcom_battmgr_probe,
+ .id_table = qcom_battmgr_id_table,
+};
+
+module_auxiliary_driver(qcom_battmgr_driver);
+
+MODULE_DESCRIPTION("Qualcomm PMIC GLINK battery manager driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/power/supply/rt9467-charger.c b/drivers/power/supply/rt9467-charger.c
new file mode 100644
index 000000000000..73f744a3155d
--- /dev/null
+++ b/drivers/power/supply/rt9467-charger.c
@@ -0,0 +1,1282 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 Richtek Technology Corp.
+ *
+ * Author: ChiYuan Huang <cy_huang@richtek.com>
+ * ChiaEn Wu <chiaen_wu@richtek.com>
+ */
+
+#include <linux/bits.h>
+#include <linux/bitfield.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/kstrtox.h>
+#include <linux/linear_range.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/power_supply.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/units.h>
+#include <linux/sysfs.h>
+
+#define RT9467_REG_CORE_CTRL0 0x00
+#define RT9467_REG_CHG_CTRL1 0x01
+#define RT9467_REG_CHG_CTRL2 0x02
+#define RT9467_REG_CHG_CTRL3 0x03
+#define RT9467_REG_CHG_CTRL4 0x04
+#define RT9467_REG_CHG_CTRL5 0x05
+#define RT9467_REG_CHG_CTRL6 0x06
+#define RT9467_REG_CHG_CTRL7 0x07
+#define RT9467_REG_CHG_CTRL8 0x08
+#define RT9467_REG_CHG_CTRL9 0x09
+#define RT9467_REG_CHG_CTRL10 0x0A
+#define RT9467_REG_CHG_CTRL12 0x0C
+#define RT9467_REG_CHG_CTRL13 0x0D
+#define RT9467_REG_CHG_CTRL14 0x0E
+#define RT9467_REG_CHG_ADC 0x11
+#define RT9467_REG_CHG_DPDM1 0x12
+#define RT9467_REG_CHG_DPDM2 0x13
+#define RT9467_REG_DEVICE_ID 0x40
+#define RT9467_REG_CHG_STAT 0x42
+#define RT9467_REG_ADC_DATA_H 0x44
+#define RT9467_REG_CHG_STATC 0x50
+#define RT9467_REG_CHG_IRQ1 0x53
+#define RT9467_REG_CHG_STATC_CTRL 0x60
+#define RT9467_REG_CHG_IRQ1_CTRL 0x63
+
+#define RT9467_MASK_PWR_RDY BIT(7)
+#define RT9467_MASK_MIVR_STAT BIT(6)
+#define RT9467_MASK_OTG_CSEL GENMASK(2, 0)
+#define RT9467_MASK_OTG_VSEL GENMASK(7, 2)
+#define RT9467_MASK_OTG_EN BIT(0)
+#define RT9467_MASK_ADC_IN_SEL GENMASK(7, 4)
+#define RT9467_MASK_ADC_START BIT(0)
+
+#define RT9467_NUM_IRQ_REGS 4
+#define RT9467_ICHG_MIN_uA 100000
+#define RT9467_ICHG_MAX_uA 5000000
+#define RT9467_CV_MAX_uV 4710000
+#define RT9467_OTG_MIN_uV 4425000
+#define RT9467_OTG_MAX_uV 5825000
+#define RT9467_OTG_STEP_uV 25000
+#define RT9467_NUM_VOTG (RT9467_OTG_MAX_uV - RT9467_OTG_MIN_uV + 1)
+#define RT9467_AICLVTH_GAP_uV 200000
+#define RT9467_ADCCONV_TIME_MS 35
+
+#define RT9466_VID 0x8
+#define RT9467_VID 0x9
+
+/* IRQ number */
+#define RT9467_IRQ_TS_STATC 0
+#define RT9467_IRQ_CHG_FAULT 1
+#define RT9467_IRQ_CHG_STATC 2
+#define RT9467_IRQ_CHG_TMR 3
+#define RT9467_IRQ_CHG_BATABS 4
+#define RT9467_IRQ_CHG_ADPBAD 5
+#define RT9467_IRQ_CHG_RVP 6
+#define RT9467_IRQ_OTP 7
+
+#define RT9467_IRQ_CHG_AICLM 8
+#define RT9467_IRQ_CHG_ICHGM 9
+#define RT9467_IRQ_WDTMR 11
+#define RT9467_IRQ_SSFINISH 12
+#define RT9467_IRQ_CHG_RECHG 13
+#define RT9467_IRQ_CHG_TERM 14
+#define RT9467_IRQ_CHG_IEOC 15
+
+#define RT9467_IRQ_ADC_DONE 16
+#define RT9467_IRQ_PUMPX_DONE 17
+#define RT9467_IRQ_BST_BATUV 21
+#define RT9467_IRQ_BST_MIDOV 22
+#define RT9467_IRQ_BST_OLP 23
+
+#define RT9467_IRQ_ATTACH 24
+#define RT9467_IRQ_DETACH 25
+#define RT9467_IRQ_HVDCP_DET 29
+#define RT9467_IRQ_CHGDET 30
+#define RT9467_IRQ_DCDT 31
+
+enum rt9467_fields {
+ /* RT9467_REG_CORE_CTRL0 */
+ F_RST = 0,
+ /* RT9467_REG_CHG_CTRL1 */
+ F_HZ, F_OTG_PIN_EN, F_OPA_MODE,
+ /* RT9467_REG_CHG_CTRL2 */
+ F_SHIP_MODE, F_TE, F_IINLMTSEL, F_CFO_EN, F_CHG_EN,
+ /* RT9467_REG_CHG_CTRL3 */
+ F_IAICR, F_ILIM_EN,
+ /* RT9467_REG_CHG_CTRL4 */
+ F_VOREG,
+ /* RT9467_REG_CHG_CTRL6 */
+ F_VMIVR,
+ /* RT9467_REG_CHG_CTRL7 */
+ F_ICHG,
+ /* RT9467_REG_CHG_CTRL8 */
+ F_IPREC,
+ /* RT9467_REG_CHG_CTRL9 */
+ F_IEOC,
+ /* RT9467_REG_CHG_CTRL12 */
+ F_WT_FC,
+ /* RT9467_REG_CHG_CTRL13 */
+ F_OCP,
+ /* RT9467_REG_CHG_CTRL14 */
+ F_AICL_MEAS, F_AICL_VTH,
+ /* RT9467_REG_CHG_DPDM1 */
+ F_USBCHGEN,
+ /* RT9467_REG_CHG_DPDM2 */
+ F_USB_STATUS,
+ /* RT9467_REG_DEVICE_ID */
+ F_VENDOR,
+ /* RT9467_REG_CHG_STAT */
+ F_CHG_STAT,
+ /* RT9467_REG_CHG_STATC */
+ F_PWR_RDY, F_CHG_MIVR,
+ F_MAX_FIELDS
+};
+
+static const struct regmap_irq rt9467_irqs[] = {
+ REGMAP_IRQ_REG_LINE(RT9467_IRQ_TS_STATC, 8),
+ REGMAP_IRQ_REG_LINE(RT9467_IRQ_CHG_FAULT, 8),
+ REGMAP_IRQ_REG_LINE(RT9467_IRQ_CHG_STATC, 8),
+ REGMAP_IRQ_REG_LINE(RT9467_IRQ_CHG_TMR, 8),
+ REGMAP_IRQ_REG_LINE(RT9467_IRQ_CHG_BATABS, 8),
+ REGMAP_IRQ_REG_LINE(RT9467_IRQ_CHG_ADPBAD, 8),
+ REGMAP_IRQ_REG_LINE(RT9467_IRQ_CHG_RVP, 8),
+ REGMAP_IRQ_REG_LINE(RT9467_IRQ_OTP, 8),
+ REGMAP_IRQ_REG_LINE(RT9467_IRQ_CHG_AICLM, 8),
+ REGMAP_IRQ_REG_LINE(RT9467_IRQ_CHG_ICHGM, 8),
+ REGMAP_IRQ_REG_LINE(RT9467_IRQ_WDTMR, 8),
+ REGMAP_IRQ_REG_LINE(RT9467_IRQ_SSFINISH, 8),
+ REGMAP_IRQ_REG_LINE(RT9467_IRQ_CHG_RECHG, 8),
+ REGMAP_IRQ_REG_LINE(RT9467_IRQ_CHG_TERM, 8),
+ REGMAP_IRQ_REG_LINE(RT9467_IRQ_CHG_IEOC, 8),
+ REGMAP_IRQ_REG_LINE(RT9467_IRQ_ADC_DONE, 8),
+ REGMAP_IRQ_REG_LINE(RT9467_IRQ_PUMPX_DONE, 8),
+ REGMAP_IRQ_REG_LINE(RT9467_IRQ_BST_BATUV, 8),
+ REGMAP_IRQ_REG_LINE(RT9467_IRQ_BST_MIDOV, 8),
+ REGMAP_IRQ_REG_LINE(RT9467_IRQ_BST_OLP, 8),
+ REGMAP_IRQ_REG_LINE(RT9467_IRQ_ATTACH, 8),
+ REGMAP_IRQ_REG_LINE(RT9467_IRQ_DETACH, 8),
+ REGMAP_IRQ_REG_LINE(RT9467_IRQ_HVDCP_DET, 8),
+ REGMAP_IRQ_REG_LINE(RT9467_IRQ_CHGDET, 8),
+ REGMAP_IRQ_REG_LINE(RT9467_IRQ_DCDT, 8)
+};
+
+static const struct regmap_irq_chip rt9467_irq_chip = {
+ .name = "rt9467-irqs",
+ .status_base = RT9467_REG_CHG_IRQ1,
+ .mask_base = RT9467_REG_CHG_IRQ1_CTRL,
+ .num_regs = RT9467_NUM_IRQ_REGS,
+ .irqs = rt9467_irqs,
+ .num_irqs = ARRAY_SIZE(rt9467_irqs),
+};
+
+enum rt9467_ranges {
+ RT9467_RANGE_IAICR = 0,
+ RT9467_RANGE_VOREG,
+ RT9467_RANGE_VMIVR,
+ RT9467_RANGE_ICHG,
+ RT9467_RANGE_IPREC,
+ RT9467_RANGE_IEOC,
+ RT9467_RANGE_AICL_VTH,
+ RT9467_RANGES_MAX
+};
+
+static const struct linear_range rt9467_ranges[RT9467_RANGES_MAX] = {
+ LINEAR_RANGE_IDX(RT9467_RANGE_IAICR, 100000, 0x0, 0x3F, 50000),
+ LINEAR_RANGE_IDX(RT9467_RANGE_VOREG, 3900000, 0x0, 0x51, 10000),
+ LINEAR_RANGE_IDX(RT9467_RANGE_VMIVR, 3900000, 0x0, 0x5F, 100000),
+ LINEAR_RANGE_IDX(RT9467_RANGE_ICHG, 900000, 0x08, 0x31, 100000),
+ LINEAR_RANGE_IDX(RT9467_RANGE_IPREC, 100000, 0x0, 0x0F, 50000),
+ LINEAR_RANGE_IDX(RT9467_RANGE_IEOC, 100000, 0x0, 0x0F, 50000),
+ LINEAR_RANGE_IDX(RT9467_RANGE_AICL_VTH, 4100000, 0x0, 0x7, 100000),
+};
+
+static const struct reg_field rt9467_chg_fields[] = {
+ [F_RST] = REG_FIELD(RT9467_REG_CORE_CTRL0, 7, 7),
+ [F_HZ] = REG_FIELD(RT9467_REG_CHG_CTRL1, 2, 2),
+ [F_OTG_PIN_EN] = REG_FIELD(RT9467_REG_CHG_CTRL1, 1, 1),
+ [F_OPA_MODE] = REG_FIELD(RT9467_REG_CHG_CTRL1, 0, 0),
+ [F_SHIP_MODE] = REG_FIELD(RT9467_REG_CHG_CTRL2, 7, 7),
+ [F_TE] = REG_FIELD(RT9467_REG_CHG_CTRL2, 4, 4),
+ [F_IINLMTSEL] = REG_FIELD(RT9467_REG_CHG_CTRL2, 2, 3),
+ [F_CFO_EN] = REG_FIELD(RT9467_REG_CHG_CTRL2, 1, 1),
+ [F_CHG_EN] = REG_FIELD(RT9467_REG_CHG_CTRL2, 0, 0),
+ [F_IAICR] = REG_FIELD(RT9467_REG_CHG_CTRL3, 2, 7),
+ [F_ILIM_EN] = REG_FIELD(RT9467_REG_CHG_CTRL3, 0, 0),
+ [F_VOREG] = REG_FIELD(RT9467_REG_CHG_CTRL4, 1, 7),
+ [F_VMIVR] = REG_FIELD(RT9467_REG_CHG_CTRL6, 1, 7),
+ [F_ICHG] = REG_FIELD(RT9467_REG_CHG_CTRL7, 2, 7),
+ [F_IPREC] = REG_FIELD(RT9467_REG_CHG_CTRL8, 0, 3),
+ [F_IEOC] = REG_FIELD(RT9467_REG_CHG_CTRL9, 4, 7),
+ [F_WT_FC] = REG_FIELD(RT9467_REG_CHG_CTRL12, 5, 7),
+ [F_OCP] = REG_FIELD(RT9467_REG_CHG_CTRL13, 2, 2),
+ [F_AICL_MEAS] = REG_FIELD(RT9467_REG_CHG_CTRL14, 7, 7),
+ [F_AICL_VTH] = REG_FIELD(RT9467_REG_CHG_CTRL14, 0, 2),
+ [F_USBCHGEN] = REG_FIELD(RT9467_REG_CHG_DPDM1, 7, 7),
+ [F_USB_STATUS] = REG_FIELD(RT9467_REG_CHG_DPDM2, 0, 2),
+ [F_VENDOR] = REG_FIELD(RT9467_REG_DEVICE_ID, 4, 7),
+ [F_CHG_STAT] = REG_FIELD(RT9467_REG_CHG_STAT, 6, 7),
+ [F_PWR_RDY] = REG_FIELD(RT9467_REG_CHG_STATC, 7, 7),
+ [F_CHG_MIVR] = REG_FIELD(RT9467_REG_CHG_STATC, 6, 6),
+};
+
+enum {
+ RT9467_STAT_READY = 0,
+ RT9467_STAT_PROGRESS,
+ RT9467_STAT_CHARGE_DONE,
+ RT9467_STAT_FAULT
+};
+
+enum rt9467_adc_chan {
+ RT9467_ADC_VBUS_DIV5 = 0,
+ RT9467_ADC_VBUS_DIV2,
+ RT9467_ADC_VSYS,
+ RT9467_ADC_VBAT,
+ RT9467_ADC_TS_BAT,
+ RT9467_ADC_IBUS,
+ RT9467_ADC_IBAT,
+ RT9467_ADC_REGN,
+ RT9467_ADC_TEMP_JC
+};
+
+enum rt9467_chg_type {
+ RT9467_CHG_TYPE_NOVBUS = 0,
+ RT9467_CHG_TYPE_UNDER_GOING,
+ RT9467_CHG_TYPE_SDP,
+ RT9467_CHG_TYPE_SDPNSTD,
+ RT9467_CHG_TYPE_DCP,
+ RT9467_CHG_TYPE_CDP,
+ RT9467_CHG_TYPE_MAX
+};
+
+enum rt9467_iin_limit_sel {
+ RT9467_IINLMTSEL_3_2A = 0,
+ RT9467_IINLMTSEL_CHG_TYP,
+ RT9467_IINLMTSEL_AICR,
+ RT9467_IINLMTSEL_LOWER_LEVEL, /* lower of above three */
+};
+
+struct rt9467_chg_data {
+ struct device *dev;
+ struct regmap *regmap;
+ struct regmap_field *rm_field[F_MAX_FIELDS];
+ struct regmap_irq_chip_data *irq_chip_data;
+ struct power_supply *psy;
+ struct mutex adc_lock;
+ struct mutex attach_lock;
+ struct mutex ichg_ieoc_lock;
+ struct regulator_dev *rdev;
+ struct completion aicl_done;
+ enum power_supply_usb_type psy_usb_type;
+ unsigned int old_stat;
+ unsigned int vid;
+ int ichg_ua;
+ int ieoc_ua;
+};
+
+static int rt9467_otg_of_parse_cb(struct device_node *of,
+ const struct regulator_desc *desc,
+ struct regulator_config *cfg)
+{
+ struct rt9467_chg_data *data = cfg->driver_data;
+
+ cfg->ena_gpiod = fwnode_gpiod_get_index(of_fwnode_handle(of),
+ "enable", 0, GPIOD_OUT_LOW |
+ GPIOD_FLAGS_BIT_NONEXCLUSIVE,
+ desc->name);
+ if (IS_ERR(cfg->ena_gpiod)) {
+ cfg->ena_gpiod = NULL;
+ return 0;
+ }
+
+ return regmap_field_write(data->rm_field[F_OTG_PIN_EN], 1);
+}
+
+static const struct regulator_ops rt9467_otg_regulator_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_current_limit = regulator_set_current_limit_regmap,
+ .get_current_limit = regulator_get_current_limit_regmap,
+};
+
+static const u32 rt9467_otg_microamp[] = {
+ 500000, 700000, 1100000, 1300000, 1800000, 2100000, 2400000, 3000000
+};
+
+static const struct regulator_desc rt9467_otg_desc = {
+ .name = "rt9476-usb-otg-vbus",
+ .of_match = "usb-otg-vbus-regulator",
+ .of_parse_cb = rt9467_otg_of_parse_cb,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .min_uV = RT9467_OTG_MIN_uV,
+ .uV_step = RT9467_OTG_STEP_uV,
+ .n_voltages = RT9467_NUM_VOTG,
+ .curr_table = rt9467_otg_microamp,
+ .n_current_limits = ARRAY_SIZE(rt9467_otg_microamp),
+ .csel_reg = RT9467_REG_CHG_CTRL10,
+ .csel_mask = RT9467_MASK_OTG_CSEL,
+ .vsel_reg = RT9467_REG_CHG_CTRL5,
+ .vsel_mask = RT9467_MASK_OTG_VSEL,
+ .enable_reg = RT9467_REG_CHG_CTRL1,
+ .enable_mask = RT9467_MASK_OTG_EN,
+ .ops = &rt9467_otg_regulator_ops,
+};
+
+static int rt9467_register_otg_regulator(struct rt9467_chg_data *data)
+{
+ struct regulator_config cfg = {
+ .dev = data->dev,
+ .regmap = data->regmap,
+ .driver_data = data,
+ };
+
+ data->rdev = devm_regulator_register(data->dev, &rt9467_otg_desc, &cfg);
+ return PTR_ERR_OR_ZERO(data->rdev);
+}
+
+static int rt9467_get_value_from_ranges(struct rt9467_chg_data *data,
+ enum rt9467_fields field,
+ enum rt9467_ranges rsel,
+ int *value)
+{
+ const struct linear_range *range = rt9467_ranges + rsel;
+ unsigned int sel;
+ int ret;
+
+ ret = regmap_field_read(data->rm_field[field], &sel);
+ if (ret)
+ return ret;
+
+ return linear_range_get_value(range, sel, value);
+}
+
+static int rt9467_set_value_from_ranges(struct rt9467_chg_data *data,
+ enum rt9467_fields field,
+ enum rt9467_ranges rsel,
+ int value)
+{
+ const struct linear_range *range = rt9467_ranges + rsel;
+ unsigned int sel;
+ bool found;
+ int ret;
+
+ if (rsel == RT9467_RANGE_VMIVR) {
+ ret = linear_range_get_selector_high(range, value, &sel, &found);
+ if (ret)
+ value = range->max_sel;
+ } else {
+ linear_range_get_selector_within(range, value, &sel);
+ }
+
+ return regmap_field_write(data->rm_field[field], sel);
+}
+
+static int rt9467_get_adc_sel(enum rt9467_adc_chan chan, int *sel)
+{
+ switch (chan) {
+ case RT9467_ADC_VBUS_DIV5:
+ case RT9467_ADC_VBUS_DIV2:
+ case RT9467_ADC_VSYS:
+ case RT9467_ADC_VBAT:
+ *sel = chan + 1;
+ return 0;
+ case RT9467_ADC_TS_BAT:
+ *sel = chan + 2;
+ return 0;
+ case RT9467_ADC_IBUS:
+ case RT9467_ADC_IBAT:
+ *sel = chan + 3;
+ return 0;
+ case RT9467_ADC_REGN:
+ case RT9467_ADC_TEMP_JC:
+ *sel = chan + 4;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int rt9467_get_adc_raw_data(struct rt9467_chg_data *data,
+ enum rt9467_adc_chan chan, int *val)
+{
+ unsigned int adc_stat, reg_val, adc_sel;
+ __be16 chan_raw_data;
+ int ret;
+
+ mutex_lock(&data->adc_lock);
+
+ ret = rt9467_get_adc_sel(chan, &adc_sel);
+ if (ret)
+ goto adc_unlock;
+
+ ret = regmap_write(data->regmap, RT9467_REG_CHG_ADC, 0);
+ if (ret) {
+ dev_err(data->dev, "Failed to clear ADC enable\n");
+ goto adc_unlock;
+ }
+
+ reg_val = RT9467_MASK_ADC_START | FIELD_PREP(RT9467_MASK_ADC_IN_SEL, adc_sel);
+ ret = regmap_write(data->regmap, RT9467_REG_CHG_ADC, reg_val);
+ if (ret)
+ goto adc_unlock;
+
+ /* Minimum wait time for one channel processing */
+ msleep(RT9467_ADCCONV_TIME_MS);
+
+ ret = regmap_read_poll_timeout(data->regmap, RT9467_REG_CHG_ADC,
+ adc_stat,
+ !(adc_stat & RT9467_MASK_ADC_START),
+ MILLI, RT9467_ADCCONV_TIME_MS * MILLI);
+ if (ret) {
+ dev_err(data->dev, "Failed to wait ADC conversion, chan = %d\n", chan);
+ goto adc_unlock;
+ }
+
+ ret = regmap_raw_read(data->regmap, RT9467_REG_ADC_DATA_H,
+ &chan_raw_data, sizeof(chan_raw_data));
+ if (ret)
+ goto adc_unlock;
+
+ *val = be16_to_cpu(chan_raw_data);
+
+adc_unlock:
+ mutex_unlock(&data->adc_lock);
+ return ret;
+}
+
+static int rt9467_get_adc(struct rt9467_chg_data *data,
+ enum rt9467_adc_chan chan, int *val)
+{
+ unsigned int aicr_ua, ichg_ua;
+ int ret;
+
+ ret = rt9467_get_adc_raw_data(data, chan, val);
+ if (ret)
+ return ret;
+
+ switch (chan) {
+ case RT9467_ADC_VBUS_DIV5:
+ *val *= 25000;
+ return 0;
+ case RT9467_ADC_VBUS_DIV2:
+ *val *= 10000;
+ return 0;
+ case RT9467_ADC_VBAT:
+ case RT9467_ADC_VSYS:
+ case RT9467_ADC_REGN:
+ *val *= 5000;
+ return 0;
+ case RT9467_ADC_TS_BAT:
+ *val /= 400;
+ return 0;
+ case RT9467_ADC_IBUS:
+ /* UUG MOS turn-on ratio will affect the IBUS adc scale */
+ ret = rt9467_get_value_from_ranges(data, F_IAICR,
+ RT9467_RANGE_IAICR, &aicr_ua);
+ if (ret)
+ return ret;
+
+ *val *= aicr_ua < 400000 ? 29480 : 50000;
+ return 0;
+ case RT9467_ADC_IBAT:
+ /* PP MOS turn-on ratio will affect the ICHG adc scale */
+ ret = rt9467_get_value_from_ranges(data, F_ICHG,
+ RT9467_RANGE_ICHG, &ichg_ua);
+ if (ret)
+ return ret;
+
+ *val *= ichg_ua <= 400000 ? 28500 :
+ ichg_ua <= 800000 ? 31500 : 500000;
+ return 0;
+ case RT9467_ADC_TEMP_JC:
+ *val = ((*val * 2) - 40) * 10;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int rt9467_psy_get_status(struct rt9467_chg_data *data, int *state)
+{
+ unsigned int status;
+ int ret;
+
+ ret = regmap_field_read(data->rm_field[F_CHG_STAT], &status);
+ if (ret)
+ return ret;
+
+ switch (status) {
+ case RT9467_STAT_READY:
+ *state = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ return 0;
+ case RT9467_STAT_PROGRESS:
+ *state = POWER_SUPPLY_STATUS_CHARGING;
+ return 0;
+ case RT9467_STAT_CHARGE_DONE:
+ *state = POWER_SUPPLY_STATUS_FULL;
+ return 0;
+ default:
+ *state = POWER_SUPPLY_STATUS_UNKNOWN;
+ return 0;
+ }
+}
+
+static int rt9467_psy_set_ichg(struct rt9467_chg_data *data, int microamp)
+{
+ int ret;
+
+ mutex_lock(&data->ichg_ieoc_lock);
+
+ if (microamp < 500000) {
+ dev_err(data->dev, "Minimum value must be 500mA\n");
+ microamp = 500000;
+ }
+
+ ret = rt9467_set_value_from_ranges(data, F_ICHG, RT9467_RANGE_ICHG, microamp);
+ if (ret)
+ goto out;
+
+ ret = rt9467_get_value_from_ranges(data, F_ICHG, RT9467_RANGE_ICHG,
+ &data->ichg_ua);
+ if (ret)
+ goto out;
+
+out:
+ mutex_unlock(&data->ichg_ieoc_lock);
+ return ret;
+}
+
+static int rt9467_run_aicl(struct rt9467_chg_data *data)
+{
+ unsigned int statc, aicl_vth;
+ int mivr_vth, aicr_get;
+ int ret = 0;
+
+
+ ret = regmap_read(data->regmap, RT9467_REG_CHG_STATC, &statc);
+ if (ret) {
+ dev_err(data->dev, "Failed to read status\n");
+ return ret;
+ }
+
+ if (!(statc & RT9467_MASK_PWR_RDY) || !(statc & RT9467_MASK_MIVR_STAT)) {
+ dev_info(data->dev, "Condition not matched %d\n", statc);
+ return 0;
+ }
+
+ ret = rt9467_get_value_from_ranges(data, F_VMIVR, RT9467_RANGE_VMIVR,
+ &mivr_vth);
+ if (ret) {
+ dev_err(data->dev, "Failed to get mivr\n");
+ return ret;
+ }
+
+ /* AICL_VTH = MIVR_VTH + 200mV */
+ aicl_vth = mivr_vth + RT9467_AICLVTH_GAP_uV;
+ ret = rt9467_set_value_from_ranges(data, F_AICL_VTH,
+ RT9467_RANGE_AICL_VTH, aicl_vth);
+
+ /* Trigger AICL function */
+ ret = regmap_field_write(data->rm_field[F_AICL_MEAS], 1);
+ if (ret) {
+ dev_err(data->dev, "Failed to set aicl measurement\n");
+ return ret;
+ }
+
+ reinit_completion(&data->aicl_done);
+ ret = wait_for_completion_timeout(&data->aicl_done, msecs_to_jiffies(3500));
+ if (ret)
+ return ret;
+
+ ret = rt9467_get_value_from_ranges(data, F_IAICR, RT9467_RANGE_IAICR, &aicr_get);
+ if (ret) {
+ dev_err(data->dev, "Failed to get aicr\n");
+ return ret;
+ }
+
+ dev_info(data->dev, "aicr get = %d uA\n", aicr_get);
+ return 0;
+}
+
+static int rt9467_psy_set_ieoc(struct rt9467_chg_data *data, int microamp)
+{
+ int ret;
+
+ mutex_lock(&data->ichg_ieoc_lock);
+
+ ret = rt9467_set_value_from_ranges(data, F_IEOC, RT9467_RANGE_IEOC, microamp);
+ if (ret)
+ goto out;
+
+ ret = rt9467_get_value_from_ranges(data, F_IEOC, RT9467_RANGE_IEOC, &data->ieoc_ua);
+ if (ret)
+ goto out;
+
+out:
+ mutex_unlock(&data->ichg_ieoc_lock);
+ return ret;
+}
+
+static const enum power_supply_usb_type rt9467_chg_usb_types[] = {
+ POWER_SUPPLY_USB_TYPE_UNKNOWN,
+ POWER_SUPPLY_USB_TYPE_SDP,
+ POWER_SUPPLY_USB_TYPE_DCP,
+ POWER_SUPPLY_USB_TYPE_CDP,
+};
+
+static const enum power_supply_property rt9467_chg_properties[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_CURRENT_MAX,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
+ POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
+ POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT,
+ POWER_SUPPLY_PROP_USB_TYPE,
+ POWER_SUPPLY_PROP_PRECHARGE_CURRENT,
+ POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
+};
+
+static int rt9467_psy_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct rt9467_chg_data *data = power_supply_get_drvdata(psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ return rt9467_psy_get_status(data, &val->intval);
+ case POWER_SUPPLY_PROP_ONLINE:
+ return regmap_field_read(data->rm_field[F_PWR_RDY], &val->intval);
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ mutex_lock(&data->attach_lock);
+ if (data->psy_usb_type == POWER_SUPPLY_USB_TYPE_UNKNOWN ||
+ data->psy_usb_type == POWER_SUPPLY_USB_TYPE_SDP)
+ val->intval = 500000;
+ else
+ val->intval = 1500000;
+ mutex_unlock(&data->attach_lock);
+ return 0;
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+ mutex_lock(&data->ichg_ieoc_lock);
+ val->intval = data->ichg_ua;
+ mutex_unlock(&data->ichg_ieoc_lock);
+ return 0;
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
+ val->intval = RT9467_ICHG_MAX_uA;
+ return 0;
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+ return rt9467_get_value_from_ranges(data, F_VOREG,
+ RT9467_RANGE_VOREG,
+ &val->intval);
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
+ val->intval = RT9467_CV_MAX_uV;
+ return 0;
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+ return rt9467_get_value_from_ranges(data, F_IAICR,
+ RT9467_RANGE_IAICR,
+ &val->intval);
+ case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
+ return rt9467_get_value_from_ranges(data, F_VMIVR,
+ RT9467_RANGE_VMIVR,
+ &val->intval);
+ case POWER_SUPPLY_PROP_USB_TYPE:
+ mutex_lock(&data->attach_lock);
+ val->intval = data->psy_usb_type;
+ mutex_unlock(&data->attach_lock);
+ return 0;
+ case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
+ return rt9467_get_value_from_ranges(data, F_IPREC,
+ RT9467_RANGE_IPREC,
+ &val->intval);
+ case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
+ mutex_lock(&data->ichg_ieoc_lock);
+ val->intval = data->ieoc_ua;
+ mutex_unlock(&data->ichg_ieoc_lock);
+ return 0;
+ default:
+ return -ENODATA;
+ }
+}
+
+static int rt9467_psy_set_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ struct rt9467_chg_data *data = power_supply_get_drvdata(psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ return regmap_field_write(data->rm_field[F_CHG_EN], val->intval);
+ case POWER_SUPPLY_PROP_ONLINE:
+ return regmap_field_write(data->rm_field[F_HZ], val->intval);
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+ return rt9467_psy_set_ichg(data, val->intval);
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+ return rt9467_set_value_from_ranges(data, F_VOREG,
+ RT9467_RANGE_VOREG, val->intval);
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+ if (val->intval == -1)
+ return rt9467_run_aicl(data);
+ else
+ return rt9467_set_value_from_ranges(data, F_IAICR,
+ RT9467_RANGE_IAICR,
+ val->intval);
+ case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
+ return rt9467_set_value_from_ranges(data, F_VMIVR,
+ RT9467_RANGE_VMIVR, val->intval);
+ case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
+ return rt9467_set_value_from_ranges(data, F_IPREC,
+ RT9467_RANGE_IPREC, val->intval);
+ case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
+ return rt9467_psy_set_ieoc(data, val->intval);
+ case POWER_SUPPLY_PROP_USB_TYPE:
+ return regmap_field_write(data->rm_field[F_USBCHGEN], val->intval);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int rt9467_chg_prop_is_writeable(struct power_supply *psy,
+ enum power_supply_property psp)
+{
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ case POWER_SUPPLY_PROP_ONLINE:
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+ case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
+ case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
+ case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
+ case POWER_SUPPLY_PROP_USB_TYPE:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static const struct power_supply_desc rt9467_chg_psy_desc = {
+ .name = "rt9467-charger",
+ .type = POWER_SUPPLY_TYPE_USB,
+ .usb_types = rt9467_chg_usb_types,
+ .num_usb_types = ARRAY_SIZE(rt9467_chg_usb_types),
+ .properties = rt9467_chg_properties,
+ .num_properties = ARRAY_SIZE(rt9467_chg_properties),
+ .property_is_writeable = rt9467_chg_prop_is_writeable,
+ .get_property = rt9467_psy_get_property,
+ .set_property = rt9467_psy_set_property,
+};
+
+static inline struct rt9467_chg_data *psy_device_to_chip(struct device *dev)
+{
+ return power_supply_get_drvdata(to_power_supply(dev));
+}
+
+static ssize_t sysoff_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct rt9467_chg_data *data = psy_device_to_chip(dev);
+ unsigned int sysoff_enable;
+ int ret;
+
+ ret = regmap_field_read(data->rm_field[F_SHIP_MODE], &sysoff_enable);
+ if (ret)
+ return ret;
+
+ return sysfs_emit(buf, "%d\n", sysoff_enable);
+}
+
+static ssize_t sysoff_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct rt9467_chg_data *data = psy_device_to_chip(dev);
+ unsigned int tmp;
+ int ret;
+
+ ret = kstrtouint(buf, 10, &tmp);
+ if (ret)
+ return ret;
+
+ ret = regmap_field_write(data->rm_field[F_SHIP_MODE], !!tmp);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static DEVICE_ATTR_RW(sysoff_enable);
+
+static struct attribute *rt9467_sysfs_attrs[] = {
+ &dev_attr_sysoff_enable.attr,
+ NULL
+};
+
+ATTRIBUTE_GROUPS(rt9467_sysfs);
+
+static int rt9467_register_psy(struct rt9467_chg_data *data)
+{
+ struct power_supply_config cfg = {
+ .drv_data = data,
+ .of_node = dev_of_node(data->dev),
+ .attr_grp = rt9467_sysfs_groups,
+ };
+
+ data->psy = devm_power_supply_register(data->dev, &rt9467_chg_psy_desc,
+ &cfg);
+ return PTR_ERR_OR_ZERO(data->psy);
+}
+
+static int rt9467_mivr_handler(struct rt9467_chg_data *data)
+{
+ unsigned int mivr_act;
+ int ret, ibus_ma;
+
+ /*
+ * back-boost workaround
+ * If (mivr_active & ibus < 100mA), toggle cfo bit
+ */
+ ret = regmap_field_read(data->rm_field[F_CHG_MIVR], &mivr_act);
+ if (ret) {
+ dev_err(data->dev, "Failed to read MIVR stat\n");
+ return ret;
+ }
+
+ if (!mivr_act)
+ return 0;
+
+ ret = rt9467_get_adc(data, RT9467_ADC_IBUS, &ibus_ma);
+ if (ret) {
+ dev_err(data->dev, "Failed to get IBUS\n");
+ return ret;
+ }
+
+ if (ibus_ma < 100000) {
+ ret = regmap_field_write(data->rm_field[F_CFO_EN], 0);
+ ret |= regmap_field_write(data->rm_field[F_CFO_EN], 1);
+ if (ret)
+ dev_err(data->dev, "Failed to toggle cfo\n");
+ }
+
+ return ret;
+}
+
+static irqreturn_t rt9467_statc_handler(int irq, void *priv)
+{
+ struct rt9467_chg_data *data = priv;
+ unsigned int new_stat, evts = 0;
+ int ret;
+
+ ret = regmap_read(data->regmap, RT9467_REG_CHG_STATC, &new_stat);
+ if (ret) {
+ dev_err(data->dev, "Failed to read chg_statc\n");
+ return IRQ_NONE;
+ }
+
+ evts = data->old_stat ^ new_stat;
+ data->old_stat = new_stat;
+
+ if ((evts & new_stat) & RT9467_MASK_MIVR_STAT) {
+ ret = rt9467_mivr_handler(data);
+ if (ret)
+ dev_err(data->dev, "Failed to handle mivr stat\n");
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t rt9467_wdt_handler(int irq, void *priv)
+{
+ struct rt9467_chg_data *data = priv;
+ unsigned int dev_id;
+ int ret;
+
+ /* Any i2c communication can kick watchdog timer */
+ ret = regmap_read(data->regmap, RT9467_REG_DEVICE_ID, &dev_id);
+ if (ret) {
+ dev_err(data->dev, "Failed to kick wdt (%d)\n", ret);
+ return IRQ_NONE;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int rt9467_report_usb_state(struct rt9467_chg_data *data)
+{
+ unsigned int usb_stat, power_ready;
+ bool psy_changed = true;
+ int ret;
+
+ ret = regmap_field_read(data->rm_field[F_USB_STATUS], &usb_stat);
+ ret |= regmap_field_read(data->rm_field[F_PWR_RDY], &power_ready);
+ if (ret)
+ return ret;
+
+ if (!power_ready)
+ usb_stat = RT9467_CHG_TYPE_NOVBUS;
+
+ mutex_lock(&data->attach_lock);
+
+ switch (usb_stat) {
+ case RT9467_CHG_TYPE_NOVBUS:
+ data->psy_usb_type = POWER_SUPPLY_USB_TYPE_UNKNOWN;
+ break;
+ case RT9467_CHG_TYPE_SDP:
+ data->psy_usb_type = POWER_SUPPLY_USB_TYPE_SDP;
+ break;
+ case RT9467_CHG_TYPE_SDPNSTD:
+ data->psy_usb_type = POWER_SUPPLY_USB_TYPE_DCP;
+ break;
+ case RT9467_CHG_TYPE_DCP:
+ data->psy_usb_type = POWER_SUPPLY_USB_TYPE_DCP;
+ break;
+ case RT9467_CHG_TYPE_CDP:
+ data->psy_usb_type = POWER_SUPPLY_USB_TYPE_CDP;
+ break;
+ case RT9467_CHG_TYPE_UNDER_GOING:
+ default:
+ psy_changed = false;
+ break;
+ }
+
+ mutex_unlock(&data->attach_lock);
+
+ if (psy_changed)
+ power_supply_changed(data->psy);
+
+ return 0;
+}
+
+static irqreturn_t rt9467_usb_state_handler(int irq, void *priv)
+{
+ struct rt9467_chg_data *data = priv;
+ int ret;
+
+ ret = rt9467_report_usb_state(data);
+ if (ret) {
+ dev_err(data->dev, "Failed to report attach type (%d)\n", ret);
+ return IRQ_NONE;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t rt9467_aiclmeas_handler(int irq, void *priv)
+{
+ struct rt9467_chg_data *data = priv;
+
+ complete(&data->aicl_done);
+ return IRQ_HANDLED;
+}
+
+#define RT9467_IRQ_DESC(_name, _handler_func, _hwirq) \
+{ \
+ .name = #_name, \
+ .handler = rt9467_##_handler_func##_handler, \
+ .hwirq = _hwirq, \
+}
+
+static int rt9467_request_interrupt(struct rt9467_chg_data *data)
+{
+ struct device *dev = data->dev;
+ static const struct {
+ const char *name;
+ int hwirq;
+ irq_handler_t handler;
+ } rt9467_exclusive_irqs[] = {
+ RT9467_IRQ_DESC(statc, statc, RT9467_IRQ_TS_STATC),
+ RT9467_IRQ_DESC(wdt, wdt, RT9467_IRQ_WDTMR),
+ RT9467_IRQ_DESC(attach, usb_state, RT9467_IRQ_ATTACH),
+ RT9467_IRQ_DESC(detach, usb_state, RT9467_IRQ_DETACH),
+ RT9467_IRQ_DESC(aiclmeas, aiclmeas, RT9467_IRQ_CHG_AICLM),
+ }, rt9466_exclusive_irqs[] = {
+ RT9467_IRQ_DESC(statc, statc, RT9467_IRQ_TS_STATC),
+ RT9467_IRQ_DESC(wdt, wdt, RT9467_IRQ_WDTMR),
+ RT9467_IRQ_DESC(aiclmeas, aiclmeas, RT9467_IRQ_CHG_AICLM),
+ }, *chg_irqs;
+ int num_chg_irqs, i, virq, ret;
+
+ if (data->vid == RT9466_VID) {
+ chg_irqs = rt9466_exclusive_irqs;
+ num_chg_irqs = ARRAY_SIZE(rt9466_exclusive_irqs);
+ } else {
+ chg_irqs = rt9467_exclusive_irqs;
+ num_chg_irqs = ARRAY_SIZE(rt9467_exclusive_irqs);
+ }
+
+ for (i = 0; i < num_chg_irqs; i++) {
+ virq = regmap_irq_get_virq(data->irq_chip_data, chg_irqs[i].hwirq);
+ if (virq <= 0)
+ return dev_err_probe(dev, virq, "Failed to get (%s) irq\n",
+ chg_irqs[i].name);
+
+ ret = devm_request_threaded_irq(dev, virq, NULL, chg_irqs[i].handler,
+ IRQF_ONESHOT, chg_irqs[i].name, data);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to request (%s) irq\n",
+ chg_irqs[i].name);
+ }
+
+ return 0;
+}
+
+static int rt9467_do_charger_init(struct rt9467_chg_data *data)
+{
+ struct device *dev = data->dev;
+ int ret;
+
+ ret = regmap_write(data->regmap, RT9467_REG_CHG_ADC, 0);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to reset ADC\n");
+
+ ret = rt9467_get_value_from_ranges(data, F_ICHG, RT9467_RANGE_ICHG,
+ &data->ichg_ua);
+ ret |= rt9467_get_value_from_ranges(data, F_IEOC, RT9467_RANGE_IEOC,
+ &data->ieoc_ua);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to init ichg/ieoc value\n");
+
+ ret = regmap_update_bits(data->regmap, RT9467_REG_CHG_STATC_CTRL,
+ RT9467_MASK_PWR_RDY | RT9467_MASK_MIVR_STAT, 0);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to make statc unmask\n");
+
+ /* Select IINLMTSEL to use AICR */
+ ret = regmap_field_write(data->rm_field[F_IINLMTSEL],
+ RT9467_IINLMTSEL_AICR);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to set iinlmtsel to AICR\n");
+
+ /* Wait for AICR Rampping */
+ msleep(150);
+
+ /* Disable hardware ILIM */
+ ret = regmap_field_write(data->rm_field[F_ILIM_EN], 0);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to disable hardware ILIM\n");
+
+ /* Set inductor OCP to high level */
+ ret = regmap_field_write(data->rm_field[F_OCP], 1);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to set higher inductor OCP level\n");
+
+ /* Set charge termination default enable */
+ ret = regmap_field_write(data->rm_field[F_TE], 1);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to set TE=1\n");
+
+ /* Set 12hrs fast charger timer */
+ ret = regmap_field_write(data->rm_field[F_WT_FC], 4);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to set WT_FC\n");
+
+ /* Toggle BC12 function */
+ ret = regmap_field_write(data->rm_field[F_USBCHGEN], 0);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to disable BC12\n");
+
+ return regmap_field_write(data->rm_field[F_USBCHGEN], 1);
+}
+
+static bool rt9467_is_accessible_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x00 ... 0x1A:
+ case 0x20 ... 0x38:
+ case 0x40 ... 0x49:
+ case 0x50 ... 0x57:
+ case 0x60 ... 0x67:
+ case 0x70 ... 0x79:
+ case 0x82 ... 0x85:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config rt9467_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x85,
+ .writeable_reg = rt9467_is_accessible_reg,
+ .readable_reg = rt9467_is_accessible_reg,
+};
+
+static int rt9467_check_vendor_info(struct rt9467_chg_data *data)
+{
+ unsigned int vid;
+ int ret;
+
+ ret = regmap_field_read(data->rm_field[F_VENDOR], &vid);
+ if (ret) {
+ dev_err(data->dev, "Failed to get vid\n");
+ return ret;
+ }
+
+ if ((vid != RT9466_VID) && (vid != RT9467_VID))
+ return dev_err_probe(data->dev, -ENODEV,
+ "VID not correct [0x%02X]\n", vid);
+
+ data->vid = vid;
+ return 0;
+}
+
+static int rt9467_reset_chip(struct rt9467_chg_data *data)
+{
+ int ret;
+
+ /* Disable HZ before reset chip */
+ ret = regmap_field_write(data->rm_field[F_HZ], 0);
+ if (ret)
+ return ret;
+
+ return regmap_field_write(data->rm_field[F_RST], 1);
+}
+
+static void rt9467_chg_destroy_adc_lock(void *data)
+{
+ struct mutex *adc_lock = data;
+
+ mutex_destroy(adc_lock);
+}
+
+static void rt9467_chg_destroy_attach_lock(void *data)
+{
+ struct mutex *attach_lock = data;
+
+ mutex_destroy(attach_lock);
+}
+
+static void rt9467_chg_destroy_ichg_ieoc_lock(void *data)
+{
+ struct mutex *ichg_ieoc_lock = data;
+
+ mutex_destroy(ichg_ieoc_lock);
+}
+
+static void rt9467_chg_complete_aicl_done(void *data)
+{
+ struct completion *aicl_done = data;
+
+ complete(aicl_done);
+}
+
+static int rt9467_charger_probe(struct i2c_client *i2c)
+{
+ struct device *dev = &i2c->dev;
+ struct rt9467_chg_data *data;
+ struct gpio_desc *ceb_gpio;
+ int ret;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->dev = &i2c->dev;
+ i2c_set_clientdata(i2c, data);
+
+ /* Default pull charge enable gpio to make 'CHG_EN' by SW control only */
+ ceb_gpio = devm_gpiod_get_optional(dev, "charge-enable", GPIOD_OUT_LOW);
+ if (IS_ERR(ceb_gpio))
+ return dev_err_probe(dev, PTR_ERR(ceb_gpio),
+ "Failed to config charge enable gpio\n");
+
+ data->regmap = devm_regmap_init_i2c(i2c, &rt9467_regmap_config);
+ if (IS_ERR(data->regmap))
+ return dev_err_probe(dev, PTR_ERR(data->regmap),
+ "Failed to init regmap\n");
+
+ ret = devm_regmap_field_bulk_alloc(dev, data->regmap,
+ data->rm_field, rt9467_chg_fields,
+ ARRAY_SIZE(rt9467_chg_fields));
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to alloc regmap fields\n");
+
+ ret = rt9467_check_vendor_info(data);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to check vendor info");
+
+ ret = rt9467_reset_chip(data);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to reset chip\n");
+
+ ret = devm_regmap_add_irq_chip(dev, data->regmap, i2c->irq,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT, 0,
+ &rt9467_irq_chip, &data->irq_chip_data);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to add irq chip\n");
+
+ mutex_init(&data->adc_lock);
+ ret = devm_add_action_or_reset(dev, rt9467_chg_destroy_adc_lock,
+ &data->adc_lock);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to init ADC lock\n");
+
+ mutex_init(&data->attach_lock);
+ ret = devm_add_action_or_reset(dev, rt9467_chg_destroy_attach_lock,
+ &data->attach_lock);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to init attach lock\n");
+
+ mutex_init(&data->ichg_ieoc_lock);
+ ret = devm_add_action_or_reset(dev, rt9467_chg_destroy_ichg_ieoc_lock,
+ &data->ichg_ieoc_lock);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to init ICHG/IEOC lock\n");
+
+ init_completion(&data->aicl_done);
+ ret = devm_add_action_or_reset(dev, rt9467_chg_complete_aicl_done,
+ &data->aicl_done);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to init AICL done completion\n");
+
+ ret = rt9467_do_charger_init(data);
+ if (ret)
+ return ret;
+
+ ret = rt9467_register_otg_regulator(data);
+ if (ret)
+ return ret;
+
+ ret = rt9467_register_psy(data);
+ if (ret)
+ return ret;
+
+ return rt9467_request_interrupt(data);
+}
+
+static const struct of_device_id rt9467_charger_of_match_table[] = {
+ { .compatible = "richtek,rt9467", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, rt9467_charger_of_match_table);
+
+static struct i2c_driver rt9467_charger_driver = {
+ .driver = {
+ .name = "rt9467-charger",
+ .of_match_table = rt9467_charger_of_match_table,
+ },
+ .probe_new = rt9467_charger_probe,
+};
+module_i2c_driver(rt9467_charger_driver);
+
+MODULE_DESCRIPTION("Richtek RT9467 Charger Driver");
+MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
+MODULE_AUTHOR("ChiaEn Wu <chiaen_wu@richtek.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/power/supply/rt9471.c b/drivers/power/supply/rt9471.c
new file mode 100644
index 000000000000..1ea40876494b
--- /dev/null
+++ b/drivers/power/supply/rt9471.c
@@ -0,0 +1,930 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 Richtek Technology Corp.
+ *
+ * Authors: Alina Yu <alina_yu@richtek.com>
+ * ChiYuan Huang <cy_huang@richtek.com>
+ */
+
+#include <linux/bits.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kstrtox.h>
+#include <linux/linear_range.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/power_supply.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/sysfs.h>
+
+#define RT9471_REG_OTGCFG 0x00
+#define RT9471_REG_TOP 0x01
+#define RT9471_REG_FUNC 0x02
+#define RT9471_REG_IBUS 0x03
+#define RT9471_REG_VBUS 0x04
+#define RT9471_REG_PRECHG 0x05
+#define RT9471_REG_VCHG 0x07
+#define RT9471_REG_ICHG 0x08
+#define RT9471_REG_CHGTMR 0x09
+#define RT9471_REG_EOC 0x0A
+#define RT9471_REG_INFO 0x0B
+#define RT9471_REG_JEITA 0x0C
+#define RT9471_REG_PUMP_EXP 0x0D
+#define RT9471_REG_DPDMDET 0x0E
+#define RT9471_REG_ICSTAT 0x0F
+#define RT9471_REG_STAT0 0x10
+#define RT9471_REG_STAT1 0x11
+#define RT9471_REG_STAT2 0x12
+#define RT9471_REG_IRQ0 0x20
+#define RT9471_REG_MASK0 0x30
+
+#define RT9471_OTGCV_MASK GENMASK(7, 6)
+#define RT9471_OTGCC_MASK BIT(0)
+#define RT9471_OTGEN_MASK BIT(1)
+#define RT9471_CHGFAULT_MASK GENMASK(4, 1)
+
+#define RT9471_NUM_IRQ_REGS 4
+#define RT9471_OTGCV_MINUV 4850000
+#define RT9471_OTGCV_STEPUV 150000
+#define RT9471_NUM_VOTG 4
+#define RT9471_VCHG_MAXUV 4700000
+#define RT9471_ICHG_MAXUA 3150000
+
+/* Device ID */
+#define RT9470_DEVID 0x09
+#define RT9470D_DEVID 0x0A
+#define RT9471_DEVID 0x0D
+#define RT9471D_DEVID 0x0E
+
+/* IRQ number */
+#define RT9471_IRQ_BC12_DONE 0
+#define RT9471_IRQ_DETACH 1
+#define RT9471_IRQ_RECHG 2
+#define RT9471_IRQ_CHG_DONE 3
+#define RT9471_IRQ_BG_CHG 4
+#define RT9471_IRQ_IE0C 5
+#define RT9471_IRQ_CHG_RDY 6
+#define RT9471_IRQ_VBUS_GD 7
+#define RT9471_IRQ_CHG_BATOV 9
+#define RT9471_IRQ_CHG_SYSOV 10
+#define RT9471_IRQ_CHG_TOUT 11
+#define RT9471_IRQ_CHG_BUSUV 12
+#define RT9471_IRQ_CHG_THREG 13
+#define RT9471_IRQ_CHG_AICR 14
+#define RT9471_IRQ_CHG_MIVR 15
+#define RT9471_IRQ_SYS_SHORT 16
+#define RT9471_IRQ_SYS_MIN 17
+#define RT9471_IRQ_AICC_DONE 18
+#define RT9471_IRQ_PE_DONE 19
+#define RT9471_IRQ_JEITA_COLD 20
+#define RT9471_IRQ_JEITA_COOL 21
+#define RT9471_IRQ_JEITA_WARM 22
+#define RT9471_IRQ_JEITA_HOT 23
+#define RT9471_IRQ_OTG_FAULT 24
+#define RT9471_IRQ_OTG_LBP 25
+#define RT9471_IRQ_OTG_CC 26
+#define RT9471_IRQ_WDT 29
+#define RT9471_IRQ_VAC_OV 30
+#define RT9471_IRQ_OTP 31
+
+enum rt9471_fields {
+ F_WDT = 0,
+ F_WDT_RST,
+ F_CHG_EN,
+ F_HZ,
+ F_BATFET_DIS,
+ F_AICR,
+ F_AICC_EN,
+ F_MIVR,
+ F_IPRE_CHG,
+ F_VPRE_CHG,
+ F_VBAT_REG,
+ F_ICHG_REG,
+ F_EOC_RST,
+ F_TE,
+ F_IEOC_CHG,
+ F_DEVICE_ID,
+ F_REG_RST,
+ F_BC12_EN,
+ F_IC_STAT,
+ F_PORT_STAT,
+ F_ST_CHG_DONE,
+ F_ST_CHG_RDY,
+ F_ST_VBUS_GD,
+ F_MAX_FIELDS
+};
+
+enum rt9471_ranges {
+ RT9471_RANGE_AICR = 0,
+ RT9471_RANGE_MIVR,
+ RT9471_RANGE_IPRE,
+ RT9471_RANGE_VCHG,
+ RT9471_RANGE_ICHG,
+ RT9471_RANGE_IEOC,
+ RT9471_MAX_RANGES
+};
+
+enum {
+ RT9471_PORTSTAT_APPLE_10W = 8,
+ RT9471_PORTSTAT_SAMSUNG_10W,
+ RT9471_PORTSTAT_APPLE_5W,
+ RT9471_PORTSTAT_APPLE_12W,
+ RT9471_PORTSTAT_NSTD,
+ RT9471_PORTSTAT_SDP,
+ RT9471_PORTSTAT_CDP,
+ RT9471_PORTSTAT_DCP,
+};
+
+struct rt9471_chip {
+ struct device *dev;
+ struct regmap *regmap;
+ struct regmap_field *rm_fields[F_MAX_FIELDS];
+ struct regmap_irq_chip_data *irq_chip_data;
+ struct regulator_dev *otg_rdev;
+ struct power_supply *psy;
+ struct power_supply_desc psy_desc;
+ struct mutex var_lock;
+ enum power_supply_usb_type psy_usb_type;
+ int psy_usb_curr;
+};
+
+static const struct reg_field rt9471_reg_fields[F_MAX_FIELDS] = {
+ [F_WDT] = REG_FIELD(RT9471_REG_TOP, 0, 0),
+ [F_WDT_RST] = REG_FIELD(RT9471_REG_TOP, 1, 1),
+ [F_CHG_EN] = REG_FIELD(RT9471_REG_FUNC, 0, 0),
+ [F_HZ] = REG_FIELD(RT9471_REG_FUNC, 5, 5),
+ [F_BATFET_DIS] = REG_FIELD(RT9471_REG_FUNC, 7, 7),
+ [F_AICR] = REG_FIELD(RT9471_REG_IBUS, 0, 5),
+ [F_AICC_EN] = REG_FIELD(RT9471_REG_IBUS, 7, 7),
+ [F_MIVR] = REG_FIELD(RT9471_REG_VBUS, 0, 3),
+ [F_IPRE_CHG] = REG_FIELD(RT9471_REG_PRECHG, 0, 3),
+ [F_VPRE_CHG] = REG_FIELD(RT9471_REG_PRECHG, 4, 6),
+ [F_VBAT_REG] = REG_FIELD(RT9471_REG_VCHG, 0, 6),
+ [F_ICHG_REG] = REG_FIELD(RT9471_REG_ICHG, 0, 5),
+ [F_EOC_RST] = REG_FIELD(RT9471_REG_EOC, 0, 0),
+ [F_TE] = REG_FIELD(RT9471_REG_EOC, 1, 1),
+ [F_IEOC_CHG] = REG_FIELD(RT9471_REG_EOC, 4, 7),
+ [F_DEVICE_ID] = REG_FIELD(RT9471_REG_INFO, 3, 6),
+ [F_REG_RST] = REG_FIELD(RT9471_REG_INFO, 7, 7),
+ [F_BC12_EN] = REG_FIELD(RT9471_REG_DPDMDET, 7, 7),
+ [F_IC_STAT] = REG_FIELD(RT9471_REG_ICSTAT, 0, 3),
+ [F_PORT_STAT] = REG_FIELD(RT9471_REG_ICSTAT, 4, 7),
+ [F_ST_CHG_DONE] = REG_FIELD(RT9471_REG_STAT0, 3, 3),
+ [F_ST_CHG_RDY] = REG_FIELD(RT9471_REG_STAT0, 6, 6),
+ [F_ST_VBUS_GD] = REG_FIELD(RT9471_REG_STAT0, 7, 7),
+};
+
+static const struct linear_range rt9471_chg_ranges[RT9471_MAX_RANGES] = {
+ [RT9471_RANGE_AICR] = { .min = 50000, .min_sel = 1, .max_sel = 63, .step = 50000 },
+ [RT9471_RANGE_MIVR] = { .min = 3900000, .min_sel = 0, .max_sel = 15, .step = 100000 },
+ [RT9471_RANGE_IPRE] = { .min = 50000, .min_sel = 0, .max_sel = 15, .step = 50000 },
+ [RT9471_RANGE_VCHG] = { .min = 3900000, .min_sel = 0, .max_sel = 80, .step = 10000 },
+ [RT9471_RANGE_ICHG] = { .min = 0, .min_sel = 0, .max_sel = 63, .step = 50000 },
+ [RT9471_RANGE_IEOC] = { .min = 50000, .min_sel = 0, .max_sel = 15, .step = 50000 },
+};
+
+static int rt9471_set_value_by_field_range(struct rt9471_chip *chip,
+ enum rt9471_fields field,
+ enum rt9471_ranges range, int val)
+{
+ unsigned int sel;
+
+ if (val < 0)
+ return -EINVAL;
+
+ linear_range_get_selector_within(rt9471_chg_ranges + range, val, &sel);
+
+ return regmap_field_write(chip->rm_fields[field], sel);
+}
+
+
+static int rt9471_get_value_by_field_range(struct rt9471_chip *chip,
+ enum rt9471_fields field,
+ enum rt9471_ranges range, int *val)
+{
+ unsigned int sel, rvalue;
+ int ret;
+
+ ret = regmap_field_read(chip->rm_fields[field], &sel);
+ if (ret)
+ return ret;
+
+ ret = linear_range_get_value(rt9471_chg_ranges + range, sel, &rvalue);
+ if (ret)
+ return ret;
+
+ *val = rvalue;
+ return 0;
+}
+
+static int rt9471_set_ieoc(struct rt9471_chip *chip, int microamp)
+{
+ int ret;
+
+ if (microamp == 0)
+ return regmap_field_write(chip->rm_fields[F_TE], 0);
+
+ ret = rt9471_set_value_by_field_range(chip, F_IEOC_CHG, RT9471_RANGE_IEOC, microamp);
+ if (ret)
+ return ret;
+
+ /* After applying the new IEOC value, enable charge termination */
+ return regmap_field_write(chip->rm_fields[F_TE], 1);
+}
+
+static int rt9471_get_ieoc(struct rt9471_chip *chip, int *microamp)
+{
+ unsigned int chg_term_enable;
+ int ret;
+
+ ret = regmap_field_read(chip->rm_fields[F_TE], &chg_term_enable);
+ if (ret)
+ return ret;
+
+ if (!chg_term_enable) {
+ *microamp = 0;
+ return 0;
+ }
+
+ return rt9471_get_value_by_field_range(chip, F_IEOC_CHG, RT9471_RANGE_IEOC, microamp);
+}
+
+static int rt9471_get_status(struct rt9471_chip *chip, int *status)
+{
+ unsigned int chg_ready, chg_done, fault_stat;
+ int ret;
+
+ ret = regmap_field_read(chip->rm_fields[F_ST_CHG_RDY], &chg_ready);
+ if (ret)
+ return ret;
+
+ ret = regmap_field_read(chip->rm_fields[F_ST_CHG_DONE], &chg_done);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(chip->regmap, RT9471_REG_STAT1, &fault_stat);
+ if (ret)
+ return ret;
+
+ fault_stat &= RT9471_CHGFAULT_MASK;
+
+ if (chg_ready && chg_done)
+ *status = POWER_SUPPLY_STATUS_FULL;
+ else if (chg_ready && fault_stat)
+ *status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ else if (chg_ready && !fault_stat)
+ *status = POWER_SUPPLY_STATUS_CHARGING;
+ else
+ *status = POWER_SUPPLY_STATUS_DISCHARGING;
+
+ return 0;
+}
+
+static int rt9471_get_vbus_good(struct rt9471_chip *chip, int *stat)
+{
+ unsigned int vbus_gd;
+ int ret;
+
+ ret = regmap_field_read(chip->rm_fields[F_ST_VBUS_GD], &vbus_gd);
+ if (ret)
+ return ret;
+
+ *stat = vbus_gd;
+ return 0;
+}
+
+static int rt9471_get_usb_type(struct rt9471_chip *chip, int *usb_type)
+{
+ mutex_lock(&chip->var_lock);
+ *usb_type = chip->psy_usb_type;
+ mutex_unlock(&chip->var_lock);
+
+ return 0;
+}
+
+static int rt9471_get_usb_type_current(struct rt9471_chip *chip,
+ int *microamp)
+{
+ mutex_lock(&chip->var_lock);
+ *microamp = chip->psy_usb_curr;
+ mutex_unlock(&chip->var_lock);
+
+ return 0;
+}
+
+static enum power_supply_property rt9471_charger_properties[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_CURRENT_MAX,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
+ POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
+ POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT,
+ POWER_SUPPLY_PROP_USB_TYPE,
+ POWER_SUPPLY_PROP_PRECHARGE_CURRENT,
+ POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
+ POWER_SUPPLY_PROP_MODEL_NAME,
+ POWER_SUPPLY_PROP_MANUFACTURER,
+};
+
+static enum power_supply_usb_type rt9471_charger_usb_types[] = {
+ POWER_SUPPLY_USB_TYPE_UNKNOWN,
+ POWER_SUPPLY_USB_TYPE_SDP,
+ POWER_SUPPLY_USB_TYPE_DCP,
+ POWER_SUPPLY_USB_TYPE_CDP,
+ POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID,
+};
+
+static int rt9471_charger_property_is_writeable(struct power_supply *psy,
+ enum power_supply_property psp)
+{
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ case POWER_SUPPLY_PROP_ONLINE:
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+ case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
+ case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
+ case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static int rt9471_charger_set_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ struct rt9471_chip *chip = power_supply_get_drvdata(psy);
+ int value = val->intval;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ return regmap_field_write(chip->rm_fields[F_CHG_EN], !!value);
+ case POWER_SUPPLY_PROP_ONLINE:
+ return regmap_field_write(chip->rm_fields[F_HZ], !value);
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+ return rt9471_set_value_by_field_range(chip, F_ICHG_REG, RT9471_RANGE_ICHG, value);
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+ return rt9471_set_value_by_field_range(chip, F_VBAT_REG, RT9471_RANGE_VCHG, value);
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+ return rt9471_set_value_by_field_range(chip, F_AICR, RT9471_RANGE_AICR, value);
+ case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
+ return rt9471_set_value_by_field_range(chip, F_MIVR, RT9471_RANGE_MIVR, value);
+ case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
+ return rt9471_set_value_by_field_range(chip, F_IPRE_CHG, RT9471_RANGE_IPRE, value);
+ case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
+ return rt9471_set_ieoc(chip, val->intval);
+ default:
+ return -EINVAL;
+ }
+}
+
+static const char * const rt9471_manufacturer = "Richtek Technology Corp.";
+static const char * const rt9471_model = "RT9471";
+
+static int rt9471_charger_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct rt9471_chip *chip = power_supply_get_drvdata(psy);
+ int *pvalue = &val->intval;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ return rt9471_get_status(chip, pvalue);
+ case POWER_SUPPLY_PROP_ONLINE:
+ return rt9471_get_vbus_good(chip, pvalue);
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ return rt9471_get_usb_type_current(chip, pvalue);
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+ return rt9471_get_value_by_field_range(chip, F_ICHG_REG, RT9471_RANGE_ICHG, pvalue);
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
+ *pvalue = RT9471_ICHG_MAXUA;
+ return 0;
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+ return rt9471_get_value_by_field_range(chip, F_VBAT_REG, RT9471_RANGE_VCHG, pvalue);
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
+ val->intval = RT9471_VCHG_MAXUV;
+ return 0;
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+ return rt9471_get_value_by_field_range(chip, F_AICR, RT9471_RANGE_AICR, pvalue);
+ case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
+ return rt9471_get_value_by_field_range(chip, F_MIVR, RT9471_RANGE_MIVR, pvalue);
+ case POWER_SUPPLY_PROP_USB_TYPE:
+ return rt9471_get_usb_type(chip, pvalue);
+ case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
+ return rt9471_get_value_by_field_range(chip, F_IPRE_CHG, RT9471_RANGE_IPRE, pvalue);
+ case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
+ return rt9471_get_ieoc(chip, pvalue);
+ case POWER_SUPPLY_PROP_MODEL_NAME:
+ val->strval = rt9471_model;
+ return 0;
+ case POWER_SUPPLY_PROP_MANUFACTURER:
+ val->strval = rt9471_manufacturer;
+ return 0;
+ default:
+ return -ENODATA;
+ }
+}
+
+static irqreturn_t rt9471_vbus_gd_handler(int irqno, void *devid)
+{
+ struct rt9471_chip *chip = devid;
+
+ power_supply_changed(chip->psy);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t rt9471_detach_handler(int irqno, void *devid)
+{
+ struct rt9471_chip *chip = devid;
+ unsigned int vbus_gd;
+ int ret;
+
+ ret = regmap_field_read(chip->rm_fields[F_ST_VBUS_GD], &vbus_gd);
+ if (ret)
+ return IRQ_NONE;
+
+ /* Only focus on really detached */
+ if (vbus_gd)
+ return IRQ_HANDLED;
+
+ mutex_lock(&chip->var_lock);
+ chip->psy_usb_type = POWER_SUPPLY_USB_TYPE_UNKNOWN;
+ chip->psy_usb_curr = 0;
+ mutex_unlock(&chip->var_lock);
+
+ power_supply_changed(chip->psy);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t rt9471_bc12_done_handler(int irqno, void *devid)
+{
+ struct rt9471_chip *chip = devid;
+ enum power_supply_usb_type usb_type;
+ unsigned int port_stat;
+ int usb_curr, ret;
+
+ ret = regmap_field_read(chip->rm_fields[F_PORT_STAT], &port_stat);
+ if (ret)
+ return IRQ_NONE;
+
+ switch (port_stat) {
+ case RT9471_PORTSTAT_APPLE_10W:
+ usb_type = POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID;
+ usb_curr = 2000000;
+ break;
+ case RT9471_PORTSTAT_APPLE_5W:
+ usb_type = POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID;
+ usb_curr = 1000000;
+ break;
+ case RT9471_PORTSTAT_APPLE_12W:
+ usb_type = POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID;
+ usb_curr = 2400000;
+ break;
+ case RT9471_PORTSTAT_SAMSUNG_10W:
+ usb_type = POWER_SUPPLY_USB_TYPE_DCP;
+ usb_curr = 2000000;
+ break;
+ case RT9471_PORTSTAT_DCP:
+ usb_type = POWER_SUPPLY_USB_TYPE_DCP;
+ usb_curr = 1500000;
+ break;
+ case RT9471_PORTSTAT_NSTD:
+ case RT9471_PORTSTAT_SDP:
+ usb_type = POWER_SUPPLY_USB_TYPE_SDP;
+ usb_curr = 500000;
+ break;
+ case RT9471_PORTSTAT_CDP:
+ usb_type = POWER_SUPPLY_USB_TYPE_CDP;
+ usb_curr = 1500000;
+ break;
+ default:
+ usb_type = POWER_SUPPLY_USB_TYPE_UNKNOWN;
+ usb_curr = 0;
+ break;
+ }
+
+ mutex_lock(&chip->var_lock);
+ chip->psy_usb_type = usb_type;
+ chip->psy_usb_curr = usb_curr;
+ mutex_unlock(&chip->var_lock);
+
+ power_supply_changed(chip->psy);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t rt9471_wdt_handler(int irqno, void *devid)
+{
+ struct rt9471_chip *chip = devid;
+ int ret;
+
+ ret = regmap_field_write(chip->rm_fields[F_WDT_RST], 1);
+
+ return ret ? IRQ_NONE : IRQ_HANDLED;
+}
+
+static irqreturn_t rt9471_otg_fault_handler(int irqno, void *devid)
+{
+ struct rt9471_chip *chip = devid;
+
+ regulator_notifier_call_chain(chip->otg_rdev, REGULATOR_EVENT_FAIL, NULL);
+
+ return IRQ_HANDLED;
+}
+
+#define RT9471_IRQ_DESC(_name, _hwirq) \
+{ \
+ .name = #_name, \
+ .hwirq = _hwirq, \
+ .handler = rt9471_##_name##_handler, \
+}
+
+static int rt9471_register_interrupts(struct rt9471_chip *chip)
+{
+ struct device *dev = chip->dev;
+ static const struct {
+ char *name;
+ int hwirq;
+ irq_handler_t handler;
+ } chg_irqs[] = {
+ RT9471_IRQ_DESC(vbus_gd, RT9471_IRQ_VBUS_GD),
+ RT9471_IRQ_DESC(detach, RT9471_IRQ_DETACH),
+ RT9471_IRQ_DESC(bc12_done, RT9471_IRQ_BC12_DONE),
+ RT9471_IRQ_DESC(wdt, RT9471_IRQ_WDT),
+ RT9471_IRQ_DESC(otg_fault, RT9471_IRQ_OTG_FAULT),
+ }, *curr;
+ int i, virq, ret;
+
+ for (i = 0; i < ARRAY_SIZE(chg_irqs); i++) {
+ curr = chg_irqs + i;
+
+ virq = regmap_irq_get_virq(chip->irq_chip_data, curr->hwirq);
+ if (virq <= 0)
+ return virq;
+
+ ret = devm_request_threaded_irq(dev, virq, NULL, curr->handler,
+ IRQF_ONESHOT, curr->name, chip);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to register IRQ (%s)\n",
+ curr->name);
+ }
+
+ return 0;
+}
+
+static const struct regulator_ops rt9471_otg_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .set_current_limit = regulator_set_current_limit_regmap,
+ .get_current_limit = regulator_get_current_limit_regmap,
+};
+
+static const unsigned int rt9471_otg_microamp[] = { 500000, 1200000, };
+
+static const struct regulator_desc rt9471_otg_rdesc = {
+ .of_match = of_match_ptr("usb-otg-vbus-regulator"),
+ .name = "rt9471-otg-vbus",
+ .owner = THIS_MODULE,
+ .type = REGULATOR_VOLTAGE,
+ .ops = &rt9471_otg_ops,
+ .min_uV = RT9471_OTGCV_MINUV,
+ .uV_step = RT9471_OTGCV_STEPUV,
+ .n_voltages = RT9471_NUM_VOTG,
+ .curr_table = rt9471_otg_microamp,
+ .n_current_limits = ARRAY_SIZE(rt9471_otg_microamp),
+ .enable_mask = RT9471_OTGEN_MASK,
+ .enable_reg = RT9471_REG_FUNC,
+ .vsel_reg = RT9471_REG_OTGCFG,
+ .vsel_mask = RT9471_OTGCV_MASK,
+ .csel_reg = RT9471_REG_OTGCFG,
+ .csel_mask = RT9471_OTGCC_MASK,
+};
+
+static int rt9471_register_otg_regulator(struct rt9471_chip *chip)
+{
+ struct device *dev = chip->dev;
+ struct regulator_config cfg = { .dev = dev, .driver_data = chip };
+
+ chip->otg_rdev = devm_regulator_register(dev, &rt9471_otg_rdesc, &cfg);
+
+ return PTR_ERR_OR_ZERO(chip->otg_rdev);
+}
+
+static inline struct rt9471_chip *psy_device_to_chip(struct device *dev)
+{
+ return power_supply_get_drvdata(to_power_supply(dev));
+}
+
+static ssize_t sysoff_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct rt9471_chip *chip = psy_device_to_chip(dev);
+ unsigned int sysoff_enable;
+ int ret;
+
+ ret = regmap_field_read(chip->rm_fields[F_BATFET_DIS], &sysoff_enable);
+ if (ret)
+ return ret;
+
+ return sysfs_emit(buf, "%d\n", sysoff_enable);
+}
+
+static ssize_t sysoff_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct rt9471_chip *chip = psy_device_to_chip(dev);
+ unsigned int tmp;
+ int ret;
+
+ ret = kstrtouint(buf, 10, &tmp);
+ if (ret)
+ return ret;
+
+ ret = regmap_field_write(chip->rm_fields[F_BATFET_DIS], !!tmp);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static ssize_t port_detect_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct rt9471_chip *chip = psy_device_to_chip(dev);
+ unsigned int bc12_enable;
+ int ret;
+
+ ret = regmap_field_read(chip->rm_fields[F_BC12_EN], &bc12_enable);
+ if (ret)
+ return ret;
+
+ return sysfs_emit(buf, "%d\n", bc12_enable);
+}
+
+static ssize_t port_detect_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct rt9471_chip *chip = psy_device_to_chip(dev);
+ unsigned int tmp;
+ int ret;
+
+ ret = kstrtouint(buf, 10, &tmp);
+ if (ret)
+ return ret;
+
+ ret = regmap_field_write(chip->rm_fields[F_BC12_EN], !!tmp);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static DEVICE_ATTR_RW(sysoff_enable);
+static DEVICE_ATTR_RW(port_detect_enable);
+
+static struct attribute *rt9471_sysfs_attrs[] = {
+ &dev_attr_sysoff_enable.attr,
+ &dev_attr_port_detect_enable.attr,
+ NULL
+};
+
+ATTRIBUTE_GROUPS(rt9471_sysfs);
+
+static int rt9471_register_psy(struct rt9471_chip *chip)
+{
+ struct device *dev = chip->dev;
+ struct power_supply_desc *desc = &chip->psy_desc;
+ struct power_supply_config cfg = {};
+ char *psy_name;
+
+ cfg.drv_data = chip;
+ cfg.of_node = dev->of_node;
+ cfg.attr_grp = rt9471_sysfs_groups;
+
+ psy_name = devm_kasprintf(dev, GFP_KERNEL, "rt9471-%s", dev_name(dev));
+ if (!psy_name)
+ return -ENOMEM;
+
+ desc->name = psy_name;
+ desc->type = POWER_SUPPLY_TYPE_USB;
+ desc->usb_types = rt9471_charger_usb_types;
+ desc->num_usb_types = ARRAY_SIZE(rt9471_charger_usb_types);
+ desc->properties = rt9471_charger_properties;
+ desc->num_properties = ARRAY_SIZE(rt9471_charger_properties);
+ desc->get_property = rt9471_charger_get_property;
+ desc->set_property = rt9471_charger_set_property;
+ desc->property_is_writeable = rt9471_charger_property_is_writeable;
+
+ chip->psy = devm_power_supply_register(dev, desc, &cfg);
+
+ return PTR_ERR_OR_ZERO(chip->psy);
+}
+
+static const struct regmap_irq rt9471_regmap_irqs[] = {
+ REGMAP_IRQ_REG_LINE(RT9471_IRQ_BC12_DONE, 8),
+ REGMAP_IRQ_REG_LINE(RT9471_IRQ_DETACH, 8),
+ REGMAP_IRQ_REG_LINE(RT9471_IRQ_RECHG, 8),
+ REGMAP_IRQ_REG_LINE(RT9471_IRQ_CHG_DONE, 8),
+ REGMAP_IRQ_REG_LINE(RT9471_IRQ_BG_CHG, 8),
+ REGMAP_IRQ_REG_LINE(RT9471_IRQ_IE0C, 8),
+ REGMAP_IRQ_REG_LINE(RT9471_IRQ_CHG_RDY, 8),
+ REGMAP_IRQ_REG_LINE(RT9471_IRQ_VBUS_GD, 8),
+ REGMAP_IRQ_REG_LINE(RT9471_IRQ_CHG_BATOV, 8),
+ REGMAP_IRQ_REG_LINE(RT9471_IRQ_CHG_SYSOV, 8),
+ REGMAP_IRQ_REG_LINE(RT9471_IRQ_CHG_TOUT, 8),
+ REGMAP_IRQ_REG_LINE(RT9471_IRQ_CHG_BUSUV, 8),
+ REGMAP_IRQ_REG_LINE(RT9471_IRQ_CHG_THREG, 8),
+ REGMAP_IRQ_REG_LINE(RT9471_IRQ_CHG_AICR, 8),
+ REGMAP_IRQ_REG_LINE(RT9471_IRQ_CHG_MIVR, 8),
+ REGMAP_IRQ_REG_LINE(RT9471_IRQ_SYS_SHORT, 8),
+ REGMAP_IRQ_REG_LINE(RT9471_IRQ_SYS_MIN, 8),
+ REGMAP_IRQ_REG_LINE(RT9471_IRQ_AICC_DONE, 8),
+ REGMAP_IRQ_REG_LINE(RT9471_IRQ_PE_DONE, 8),
+ REGMAP_IRQ_REG_LINE(RT9471_IRQ_JEITA_COLD, 8),
+ REGMAP_IRQ_REG_LINE(RT9471_IRQ_JEITA_COOL, 8),
+ REGMAP_IRQ_REG_LINE(RT9471_IRQ_JEITA_WARM, 8),
+ REGMAP_IRQ_REG_LINE(RT9471_IRQ_JEITA_HOT, 8),
+ REGMAP_IRQ_REG_LINE(RT9471_IRQ_OTG_FAULT, 8),
+ REGMAP_IRQ_REG_LINE(RT9471_IRQ_OTG_LBP, 8),
+ REGMAP_IRQ_REG_LINE(RT9471_IRQ_OTG_CC, 8),
+ REGMAP_IRQ_REG_LINE(RT9471_IRQ_WDT, 8),
+ REGMAP_IRQ_REG_LINE(RT9471_IRQ_VAC_OV, 8),
+ REGMAP_IRQ_REG_LINE(RT9471_IRQ_OTP, 8),
+};
+
+static const struct regmap_irq_chip rt9471_irq_chip = {
+ .name = "rt9471-irqs",
+ .status_base = RT9471_REG_IRQ0,
+ .mask_base = RT9471_REG_MASK0,
+ .num_regs = RT9471_NUM_IRQ_REGS,
+ .irqs = rt9471_regmap_irqs,
+ .num_irqs = ARRAY_SIZE(rt9471_regmap_irqs),
+};
+
+static const struct reg_sequence rt9471_init_regs[] = {
+ REG_SEQ0(RT9471_REG_INFO, 0x80), /* REG_RST */
+ REG_SEQ0(RT9471_REG_TOP, 0xC0), /* WDT = 0 */
+ REG_SEQ0(RT9471_REG_FUNC, 0x01), /* BATFET_DIS_DLY = 0 */
+ REG_SEQ0(RT9471_REG_IBUS, 0x0A), /* AUTO_AICR = 0 */
+ REG_SEQ0(RT9471_REG_VBUS, 0xC6), /* VAC_OVP = 14V */
+ REG_SEQ0(RT9471_REG_JEITA, 0x38), /* JEITA = 0 */
+ REG_SEQ0(RT9471_REG_DPDMDET, 0x31), /* BC12_EN = 0, DCP_DP_OPT = 1 */
+};
+
+static int rt9471_check_devinfo(struct rt9471_chip *chip)
+{
+ struct device *dev = chip->dev;
+ unsigned int dev_id;
+ int ret;
+
+ ret = regmap_field_read(chip->rm_fields[F_DEVICE_ID], &dev_id);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to read device_id\n");
+
+ switch (dev_id) {
+ case RT9470_DEVID:
+ case RT9470D_DEVID:
+ case RT9471_DEVID:
+ case RT9471D_DEVID:
+ return 0;
+ default:
+ return dev_err_probe(dev, -ENODEV, "Incorrect device id\n");
+ }
+}
+
+static bool rt9471_accessible_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x00 ... 0x0F:
+ case 0x10 ... 0x13:
+ case 0x20 ... 0x33:
+ case 0x40 ... 0xA1:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config rt9471_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0xA1,
+ .writeable_reg = rt9471_accessible_reg,
+ .readable_reg = rt9471_accessible_reg,
+};
+
+static int rt9471_probe(struct i2c_client *i2c)
+{
+ struct device *dev = &i2c->dev;
+ struct rt9471_chip *chip;
+ struct gpio_desc *ce_gpio;
+ struct regmap *regmap;
+ int ret;
+
+ chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->dev = dev;
+ mutex_init(&chip->var_lock);
+ i2c_set_clientdata(i2c, chip);
+
+ /* Default pull charge enable gpio to make 'CHG_EN' by SW control only */
+ ce_gpio = devm_gpiod_get_optional(dev, "charge-enable", GPIOD_OUT_HIGH);
+ if (IS_ERR(ce_gpio))
+ return dev_err_probe(dev, PTR_ERR(ce_gpio),
+ "Failed to config charge enable gpio\n");
+
+ regmap = devm_regmap_init_i2c(i2c, &rt9471_regmap_config);
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap), "Failed to init regmap\n");
+
+ chip->regmap = regmap;
+
+ ret = devm_regmap_field_bulk_alloc(dev, regmap, chip->rm_fields,
+ rt9471_reg_fields,
+ ARRAY_SIZE(rt9471_reg_fields));
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to alloc regmap field\n");
+
+ ret = rt9471_check_devinfo(chip);
+ if (ret)
+ return ret;
+
+ ret = regmap_register_patch(regmap, rt9471_init_regs,
+ ARRAY_SIZE(rt9471_init_regs));
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to init registers\n");
+
+ ret = devm_regmap_add_irq_chip(dev, regmap, i2c->irq,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 0,
+ &rt9471_irq_chip, &chip->irq_chip_data);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to add IRQ chip\n");
+
+ ret = rt9471_register_psy(chip);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to register psy\n");
+
+ ret = rt9471_register_otg_regulator(chip);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to register otg\n");
+
+ ret = rt9471_register_interrupts(chip);
+ if (ret)
+ return ret;
+
+ /* After IRQs are all initialized, enable port detection by default */
+ return regmap_field_write(chip->rm_fields[F_BC12_EN], 1);
+}
+
+static void rt9471_shutdown(struct i2c_client *i2c)
+{
+ struct rt9471_chip *chip = i2c_get_clientdata(i2c);
+
+ /*
+ * There's no external reset pin. Do register reset to guarantee charger
+ * function is normal after shutdown
+ */
+ regmap_field_write(chip->rm_fields[F_REG_RST], 1);
+}
+
+static const struct of_device_id rt9471_of_device_id[] = {
+ { .compatible = "richtek,rt9471" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, rt9471_of_device_id);
+
+static struct i2c_driver rt9471_driver = {
+ .driver = {
+ .name = "rt9471",
+ .of_match_table = rt9471_of_device_id,
+ },
+ .probe_new = rt9471_probe,
+ .shutdown = rt9471_shutdown,
+};
+module_i2c_driver(rt9471_driver);
+
+MODULE_DESCRIPTION("Richtek RT9471 charger driver");
+MODULE_AUTHOR("Alina Yu <alina_yu@richtek.com>");
+MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/power/supply/test_power.c b/drivers/power/supply/test_power.c
index 5f510ddc946d..0d0a77584c5d 100644
--- a/drivers/power/supply/test_power.c
+++ b/drivers/power/supply/test_power.c
@@ -306,8 +306,7 @@ static int map_get_value(struct battery_property_map *map, const char *key,
char buf[MAX_KEYLENGTH];
int cr;
- strncpy(buf, key, MAX_KEYLENGTH);
- buf[MAX_KEYLENGTH-1] = '\0';
+ strscpy(buf, key, MAX_KEYLENGTH);
cr = strnlen(buf, MAX_KEYLENGTH) - 1;
if (cr < 0)
diff --git a/drivers/power/supply/twl4030_charger.c b/drivers/power/supply/twl4030_charger.c
index 1bc49b2e12e8..53a0ea5a61da 100644
--- a/drivers/power/supply/twl4030_charger.c
+++ b/drivers/power/supply/twl4030_charger.c
@@ -726,11 +726,9 @@ twl4030_bci_mode_show(struct device *dev,
for (i = 0; i < ARRAY_SIZE(modes); i++)
if (mode == i)
- len += scnprintf(buf+len, PAGE_SIZE-len,
- "[%s] ", modes[i]);
+ len += sysfs_emit_at(buf, len, "[%s] ", modes[i]);
else
- len += scnprintf(buf+len, PAGE_SIZE-len,
- "%s ", modes[i]);
+ len += sysfs_emit_at(buf, len, "%s ", modes[i]);
buf[len-1] = '\n';
return len;
}
diff --git a/drivers/power/supply/wm8350_power.c b/drivers/power/supply/wm8350_power.c
index 908cfd45d262..f2786761299c 100644
--- a/drivers/power/supply/wm8350_power.c
+++ b/drivers/power/supply/wm8350_power.c
@@ -176,7 +176,7 @@ static ssize_t charger_state_show(struct device *dev,
return 0;
}
- return sprintf(buf, "%s\n", charge);
+ return sysfs_emit(buf, "%s\n", charge);
}
static DEVICE_ATTR_RO(charger_state);
diff --git a/drivers/pps/clients/pps-ldisc.c b/drivers/pps/clients/pps-ldisc.c
index d73c4c2ed4e1..443d6bae19d1 100644
--- a/drivers/pps/clients/pps-ldisc.c
+++ b/drivers/pps/clients/pps-ldisc.c
@@ -13,7 +13,7 @@
#include <linux/pps_kernel.h>
#include <linux/bug.h>
-static void pps_tty_dcd_change(struct tty_struct *tty, unsigned int status)
+static void pps_tty_dcd_change(struct tty_struct *tty, bool active)
{
struct pps_device *pps;
struct pps_event_time ts;
@@ -29,11 +29,11 @@ static void pps_tty_dcd_change(struct tty_struct *tty, unsigned int status)
return;
/* Now do the PPS event report */
- pps_event(pps, &ts, status ? PPS_CAPTUREASSERT :
+ pps_event(pps, &ts, active ? PPS_CAPTUREASSERT :
PPS_CAPTURECLEAR, NULL);
dev_dbg(pps->dev, "PPS %s at %lu\n",
- status ? "assert" : "clear", jiffies);
+ active ? "assert" : "clear", jiffies);
}
static int (*alias_n_tty_open)(struct tty_struct *tty);
diff --git a/drivers/ptp/ptp_private.h b/drivers/ptp/ptp_private.h
index 77918a2c6701..75f58fc468a7 100644
--- a/drivers/ptp/ptp_private.h
+++ b/drivers/ptp/ptp_private.h
@@ -66,7 +66,7 @@ struct ptp_vclock {
struct hlist_node vclock_hash_node;
struct cyclecounter cc;
struct timecounter tc;
- spinlock_t lock; /* protects tc/cc */
+ struct mutex lock; /* protects tc/cc */
};
/*
diff --git a/drivers/ptp/ptp_vclock.c b/drivers/ptp/ptp_vclock.c
index 1c0ed4805c0a..dcf752c9e045 100644
--- a/drivers/ptp/ptp_vclock.c
+++ b/drivers/ptp/ptp_vclock.c
@@ -43,16 +43,16 @@ static void ptp_vclock_hash_del(struct ptp_vclock *vclock)
static int ptp_vclock_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
{
struct ptp_vclock *vclock = info_to_vclock(ptp);
- unsigned long flags;
s64 adj;
adj = (s64)scaled_ppm << PTP_VCLOCK_FADJ_SHIFT;
adj = div_s64(adj, PTP_VCLOCK_FADJ_DENOMINATOR);
- spin_lock_irqsave(&vclock->lock, flags);
+ if (mutex_lock_interruptible(&vclock->lock))
+ return -EINTR;
timecounter_read(&vclock->tc);
vclock->cc.mult = PTP_VCLOCK_CC_MULT + adj;
- spin_unlock_irqrestore(&vclock->lock, flags);
+ mutex_unlock(&vclock->lock);
return 0;
}
@@ -60,11 +60,11 @@ static int ptp_vclock_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
static int ptp_vclock_adjtime(struct ptp_clock_info *ptp, s64 delta)
{
struct ptp_vclock *vclock = info_to_vclock(ptp);
- unsigned long flags;
- spin_lock_irqsave(&vclock->lock, flags);
+ if (mutex_lock_interruptible(&vclock->lock))
+ return -EINTR;
timecounter_adjtime(&vclock->tc, delta);
- spin_unlock_irqrestore(&vclock->lock, flags);
+ mutex_unlock(&vclock->lock);
return 0;
}
@@ -73,12 +73,12 @@ static int ptp_vclock_gettime(struct ptp_clock_info *ptp,
struct timespec64 *ts)
{
struct ptp_vclock *vclock = info_to_vclock(ptp);
- unsigned long flags;
u64 ns;
- spin_lock_irqsave(&vclock->lock, flags);
+ if (mutex_lock_interruptible(&vclock->lock))
+ return -EINTR;
ns = timecounter_read(&vclock->tc);
- spin_unlock_irqrestore(&vclock->lock, flags);
+ mutex_unlock(&vclock->lock);
*ts = ns_to_timespec64(ns);
return 0;
@@ -91,7 +91,6 @@ static int ptp_vclock_gettimex(struct ptp_clock_info *ptp,
struct ptp_vclock *vclock = info_to_vclock(ptp);
struct ptp_clock *pptp = vclock->pclock;
struct timespec64 pts;
- unsigned long flags;
int err;
u64 ns;
@@ -99,9 +98,10 @@ static int ptp_vclock_gettimex(struct ptp_clock_info *ptp,
if (err)
return err;
- spin_lock_irqsave(&vclock->lock, flags);
+ if (mutex_lock_interruptible(&vclock->lock))
+ return -EINTR;
ns = timecounter_cyc2time(&vclock->tc, timespec64_to_ns(&pts));
- spin_unlock_irqrestore(&vclock->lock, flags);
+ mutex_unlock(&vclock->lock);
*ts = ns_to_timespec64(ns);
@@ -113,11 +113,11 @@ static int ptp_vclock_settime(struct ptp_clock_info *ptp,
{
struct ptp_vclock *vclock = info_to_vclock(ptp);
u64 ns = timespec64_to_ns(ts);
- unsigned long flags;
- spin_lock_irqsave(&vclock->lock, flags);
+ if (mutex_lock_interruptible(&vclock->lock))
+ return -EINTR;
timecounter_init(&vclock->tc, &vclock->cc, ns);
- spin_unlock_irqrestore(&vclock->lock, flags);
+ mutex_unlock(&vclock->lock);
return 0;
}
@@ -127,7 +127,6 @@ static int ptp_vclock_getcrosststamp(struct ptp_clock_info *ptp,
{
struct ptp_vclock *vclock = info_to_vclock(ptp);
struct ptp_clock *pptp = vclock->pclock;
- unsigned long flags;
int err;
u64 ns;
@@ -135,9 +134,10 @@ static int ptp_vclock_getcrosststamp(struct ptp_clock_info *ptp,
if (err)
return err;
- spin_lock_irqsave(&vclock->lock, flags);
+ if (mutex_lock_interruptible(&vclock->lock))
+ return -EINTR;
ns = timecounter_cyc2time(&vclock->tc, ktime_to_ns(xtstamp->device));
- spin_unlock_irqrestore(&vclock->lock, flags);
+ mutex_unlock(&vclock->lock);
xtstamp->device = ns_to_ktime(ns);
@@ -205,7 +205,7 @@ struct ptp_vclock *ptp_vclock_register(struct ptp_clock *pclock)
INIT_HLIST_NODE(&vclock->vclock_hash_node);
- spin_lock_init(&vclock->lock);
+ mutex_init(&vclock->lock);
vclock->clock = ptp_clock_register(&vclock->info, &pclock->dev);
if (IS_ERR_OR_NULL(vclock->clock)) {
@@ -269,7 +269,6 @@ ktime_t ptp_convert_timestamp(const ktime_t *hwtstamp, int vclock_index)
{
unsigned int hash = vclock_index % HASH_SIZE(vclock_hash);
struct ptp_vclock *vclock;
- unsigned long flags;
u64 ns;
u64 vclock_ns = 0;
@@ -281,9 +280,10 @@ ktime_t ptp_convert_timestamp(const ktime_t *hwtstamp, int vclock_index)
if (vclock->clock->index != vclock_index)
continue;
- spin_lock_irqsave(&vclock->lock, flags);
+ if (mutex_lock_interruptible(&vclock->lock))
+ break;
vclock_ns = timecounter_cyc2time(&vclock->tc, ns);
- spin_unlock_irqrestore(&vclock->lock, flags);
+ mutex_unlock(&vclock->lock);
break;
}
diff --git a/drivers/pwm/pwm-ab8500.c b/drivers/pwm/pwm-ab8500.c
index ad37bc46f272..507ff0d5f7bd 100644
--- a/drivers/pwm/pwm-ab8500.c
+++ b/drivers/pwm/pwm-ab8500.c
@@ -3,6 +3,7 @@
* Copyright (C) ST-Ericsson SA 2010
*
* Author: Arun R Murthy <arun.murthy@stericsson.com>
+ * Datasheet: https://web.archive.org/web/20130614115108/http://www.stericsson.com/developers/CD00291561_UM1031_AB8500_user_manual-rev5_CTDS_public.pdf
*/
#include <linux/err.h>
#include <linux/platform_device.h>
@@ -20,6 +21,8 @@
#define AB8500_PWM_OUT_CTRL2_REG 0x61
#define AB8500_PWM_OUT_CTRL7_REG 0x66
+#define AB8500_PWM_CLKRATE 9600000
+
struct ab8500_pwm_chip {
struct pwm_chip chip;
unsigned int hwid;
@@ -35,13 +38,60 @@ static int ab8500_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
{
int ret;
u8 reg;
- unsigned int higher_val, lower_val;
+ u8 higher_val, lower_val;
+ unsigned int duty_steps, div;
struct ab8500_pwm_chip *ab8500 = ab8500_pwm_from_chip(chip);
if (state->polarity != PWM_POLARITY_NORMAL)
return -EINVAL;
- if (!state->enabled) {
+ if (state->enabled) {
+ /*
+ * A time quantum is
+ * q = (32 - FreqPWMOutx[3:0]) / AB8500_PWM_CLKRATE
+ * The period is always 1024 q, duty_cycle is between 1q and 1024q.
+ *
+ * FreqPWMOutx[3:0] | output frequency | output frequency | 1024q = period
+ * | (from manual) | (1 / 1024q) | = 1 / freq
+ * -----------------+------------------+------------------+--------------
+ * b0000 | 293 Hz | 292.968750 Hz | 3413333.33 ns
+ * b0001 | 302 Hz | 302.419355 Hz | 3306666.66 ns
+ * b0010 | 312 Hz | 312.500000 Hz | 3200000 ns
+ * b0011 | 323 Hz | 323.275862 Hz | 3093333.33 ns
+ * b0100 | 334 Hz | 334.821429 Hz | 2986666.66 ns
+ * b0101 | 347 Hz | 347.222222 Hz | 2880000 ns
+ * b0110 | 360 Hz | 360.576923 Hz | 2773333.33 ns
+ * b0111 | 375 Hz | 375.000000 Hz | 2666666.66 ns
+ * b1000 | 390 Hz | 390.625000 Hz | 2560000 ns
+ * b1001 | 407 Hz | 407.608696 Hz | 2453333.33 ns
+ * b1010 | 426 Hz | 426.136364 Hz | 2346666.66 ns
+ * b1011 | 446 Hz | 446.428571 Hz | 2240000 ns
+ * b1100 | 468 Hz | 468.750000 Hz | 2133333.33 ns
+ * b1101 | 493 Hz | 493.421053 Hz | 2026666.66 ns
+ * b1110 | 520 Hz | 520.833333 Hz | 1920000 ns
+ * b1111 | 551 Hz | 551.470588 Hz | 1813333.33 ns
+ *
+ *
+ * AB8500_PWM_CLKRATE is a multiple of 1024, so the division by
+ * 1024 can be done in this factor without loss of precision.
+ */
+ div = min_t(u64, mul_u64_u64_div_u64(state->period,
+ AB8500_PWM_CLKRATE >> 10,
+ NSEC_PER_SEC), 32); /* 32 - FreqPWMOutx[3:0] */
+ if (div <= 16)
+ /* requested period < 3413333.33 */
+ return -EINVAL;
+
+ duty_steps = max_t(u64, mul_u64_u64_div_u64(state->duty_cycle,
+ AB8500_PWM_CLKRATE,
+ (u64)NSEC_PER_SEC * div), 1024);
+ }
+
+ /*
+ * The hardware doesn't support duty_steps = 0 explicitly, but emits low
+ * when disabled.
+ */
+ if (!state->enabled || duty_steps == 0) {
ret = abx500_mask_and_set_register_interruptible(chip->dev,
AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG,
1 << ab8500->hwid, 0);
@@ -53,28 +103,29 @@ static int ab8500_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
}
/*
- * get the first 8 bits that are be written to
+ * The lower 8 bits of duty_steps is written to ...
* AB8500_PWM_OUT_CTRL1_REG[0:7]
*/
- lower_val = state->duty_cycle & 0x00FF;
+ lower_val = (duty_steps - 1) & 0x00ff;
/*
- * get bits [9:10] that are to be written to
- * AB8500_PWM_OUT_CTRL2_REG[0:1]
+ * The two remaining high bits to
+ * AB8500_PWM_OUT_CTRL2_REG[0:1]; together with FreqPWMOutx.
*/
- higher_val = ((state->duty_cycle & 0x0300) >> 8);
+ higher_val = ((duty_steps - 1) & 0x0300) >> 8 | (32 - div) << 4;
reg = AB8500_PWM_OUT_CTRL1_REG + (ab8500->hwid * 2);
ret = abx500_set_register_interruptible(chip->dev, AB8500_MISC,
- reg, (u8)lower_val);
+ reg, lower_val);
if (ret < 0)
return ret;
ret = abx500_set_register_interruptible(chip->dev, AB8500_MISC,
- (reg + 1), (u8)higher_val);
+ (reg + 1), higher_val);
if (ret < 0)
return ret;
+ /* enable */
ret = abx500_mask_and_set_register_interruptible(chip->dev,
AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG,
1 << ab8500->hwid, 1 << ab8500->hwid);
@@ -85,8 +136,51 @@ static int ab8500_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return ret;
}
+static int ab8500_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
+ struct pwm_state *state)
+{
+ u8 ctrl7, lower_val, higher_val;
+ int ret;
+ struct ab8500_pwm_chip *ab8500 = ab8500_pwm_from_chip(chip);
+ unsigned int div, duty_steps;
+
+ ret = abx500_get_register_interruptible(chip->dev, AB8500_MISC,
+ AB8500_PWM_OUT_CTRL7_REG,
+ &ctrl7);
+ if (ret)
+ return ret;
+
+ state->polarity = PWM_POLARITY_NORMAL;
+
+ if (!(ctrl7 & 1 << ab8500->hwid)) {
+ state->enabled = false;
+ return 0;
+ }
+
+ ret = abx500_get_register_interruptible(chip->dev, AB8500_MISC,
+ AB8500_PWM_OUT_CTRL1_REG + (ab8500->hwid * 2),
+ &lower_val);
+ if (ret)
+ return ret;
+
+ ret = abx500_get_register_interruptible(chip->dev, AB8500_MISC,
+ AB8500_PWM_OUT_CTRL2_REG + (ab8500->hwid * 2),
+ &higher_val);
+ if (ret)
+ return ret;
+
+ div = 32 - ((higher_val & 0xf0) >> 4);
+ duty_steps = ((higher_val & 3) << 8 | lower_val) + 1;
+
+ state->period = DIV64_U64_ROUND_UP((u64)div << 10, AB8500_PWM_CLKRATE);
+ state->duty_cycle = DIV64_U64_ROUND_UP((u64)div * duty_steps, AB8500_PWM_CLKRATE);
+
+ return 0;
+}
+
static const struct pwm_ops ab8500_pwm_ops = {
.apply = ab8500_pwm_apply,
+ .get_state = ab8500_pwm_get_state,
.owner = THIS_MODULE,
};
diff --git a/drivers/pwm/pwm-dwc.c b/drivers/pwm/pwm-dwc.c
index bd2308812096..3bbb26c862c3 100644
--- a/drivers/pwm/pwm-dwc.c
+++ b/drivers/pwm/pwm-dwc.c
@@ -198,20 +198,35 @@ static const struct pwm_ops dwc_pwm_ops = {
.owner = THIS_MODULE,
};
+static struct dwc_pwm *dwc_pwm_alloc(struct device *dev)
+{
+ struct dwc_pwm *dwc;
+
+ dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL);
+ if (!dwc)
+ return NULL;
+
+ dwc->chip.dev = dev;
+ dwc->chip.ops = &dwc_pwm_ops;
+ dwc->chip.npwm = DWC_TIMERS_TOTAL;
+
+ dev_set_drvdata(dev, dwc);
+ return dwc;
+}
+
static int dwc_pwm_probe(struct pci_dev *pci, const struct pci_device_id *id)
{
struct device *dev = &pci->dev;
struct dwc_pwm *dwc;
int ret;
- dwc = devm_kzalloc(&pci->dev, sizeof(*dwc), GFP_KERNEL);
+ dwc = dwc_pwm_alloc(dev);
if (!dwc)
return -ENOMEM;
ret = pcim_enable_device(pci);
if (ret) {
- dev_err(&pci->dev,
- "Failed to enable device (%pe)\n", ERR_PTR(ret));
+ dev_err(dev, "Failed to enable device (%pe)\n", ERR_PTR(ret));
return ret;
}
@@ -219,24 +234,17 @@ static int dwc_pwm_probe(struct pci_dev *pci, const struct pci_device_id *id)
ret = pcim_iomap_regions(pci, BIT(0), pci_name(pci));
if (ret) {
- dev_err(&pci->dev,
- "Failed to iomap PCI BAR (%pe)\n", ERR_PTR(ret));
+ dev_err(dev, "Failed to iomap PCI BAR (%pe)\n", ERR_PTR(ret));
return ret;
}
dwc->base = pcim_iomap_table(pci)[0];
if (!dwc->base) {
- dev_err(&pci->dev, "Base address missing\n");
+ dev_err(dev, "Base address missing\n");
return -ENOMEM;
}
- pci_set_drvdata(pci, dwc);
-
- dwc->chip.dev = dev;
- dwc->chip.ops = &dwc_pwm_ops;
- dwc->chip.npwm = DWC_TIMERS_TOTAL;
-
- ret = pwmchip_add(&dwc->chip);
+ ret = devm_pwmchip_add(dev, &dwc->chip);
if (ret)
return ret;
@@ -248,12 +256,8 @@ static int dwc_pwm_probe(struct pci_dev *pci, const struct pci_device_id *id)
static void dwc_pwm_remove(struct pci_dev *pci)
{
- struct dwc_pwm *dwc = pci_get_drvdata(pci);
-
pm_runtime_forbid(&pci->dev);
pm_runtime_get_noresume(&pci->dev);
-
- pwmchip_remove(&dwc->chip);
}
#ifdef CONFIG_PM_SLEEP
diff --git a/drivers/pwm/pwm-iqs620a.c b/drivers/pwm/pwm-iqs620a.c
index 4987ca940b64..8362b4870c66 100644
--- a/drivers/pwm/pwm-iqs620a.c
+++ b/drivers/pwm/pwm-iqs620a.c
@@ -55,8 +55,8 @@ static int iqs620_pwm_init(struct iqs620_pwm_private *iqs620_pwm,
if (ret)
return ret;
- return regmap_update_bits(iqs62x->regmap, IQS620_PWR_SETTINGS,
- IQS620_PWR_SETTINGS_PWM_OUT, 0xff);
+ return regmap_set_bits(iqs62x->regmap, IQS620_PWR_SETTINGS,
+ IQS620_PWR_SETTINGS_PWM_OUT);
}
static int iqs620_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
diff --git a/drivers/pwm/pwm-lp3943.c b/drivers/pwm/pwm-lp3943.c
index 215ef9069114..35675e4058c6 100644
--- a/drivers/pwm/pwm-lp3943.c
+++ b/drivers/pwm/pwm-lp3943.c
@@ -8,7 +8,6 @@
*/
#include <linux/err.h>
-#include <linux/i2c.h>
#include <linux/mfd/lp3943.h>
#include <linux/module.h>
#include <linux/platform_device.h>
diff --git a/drivers/pwm/pwm-sifive.c b/drivers/pwm/pwm-sifive.c
index 62b6acc6373d..393a4b97fc19 100644
--- a/drivers/pwm/pwm-sifive.c
+++ b/drivers/pwm/pwm-sifive.c
@@ -161,7 +161,13 @@ static int pwm_sifive_apply(struct pwm_chip *chip, struct pwm_device *pwm,
mutex_lock(&ddata->lock);
if (state->period != ddata->approx_period) {
- if (ddata->user_count != 1) {
+ /*
+ * Don't let a 2nd user change the period underneath the 1st user.
+ * However if ddate->approx_period == 0 this is the first time we set
+ * any period, so let whoever gets here first set the period so other
+ * users who agree on the period won't fail.
+ */
+ if (ddata->user_count != 1 && ddata->approx_period) {
mutex_unlock(&ddata->lock);
return -EBUSY;
}
diff --git a/drivers/pwm/pwm-stm32-lp.c b/drivers/pwm/pwm-stm32-lp.c
index 514ff58a4471..f315fa106be8 100644
--- a/drivers/pwm/pwm-stm32-lp.c
+++ b/drivers/pwm/pwm-stm32-lp.c
@@ -127,7 +127,7 @@ static int stm32_pwm_lp_apply(struct pwm_chip *chip, struct pwm_device *pwm,
/* ensure CMP & ARR registers are properly written */
ret = regmap_read_poll_timeout(priv->regmap, STM32_LPTIM_ISR, val,
- (val & STM32_LPTIM_CMPOK_ARROK),
+ (val & STM32_LPTIM_CMPOK_ARROK) == STM32_LPTIM_CMPOK_ARROK,
100, 1000);
if (ret) {
dev_err(priv->chip.dev, "ARR/CMP registers write issue\n");
diff --git a/drivers/rapidio/rio-driver.c b/drivers/rapidio/rio-driver.c
index a72bb0a40fcf..e60e49769bed 100644
--- a/drivers/rapidio/rio-driver.c
+++ b/drivers/rapidio/rio-driver.c
@@ -204,9 +204,9 @@ static int rio_match_bus(struct device *dev, struct device_driver *drv)
out:return 0;
}
-static int rio_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int rio_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct rio_dev *rdev;
+ const struct rio_dev *rdev;
if (!dev)
return -ENODEV;
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 820c9a0788e5..aae28d0a489c 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -655,6 +655,14 @@ config REGULATOR_MAX20086
protectorvia I2C bus. The regulator has 2 or 4 outputs depending on
the device model. This driver is only capable to turn on/off them.
+config REGULATOR_MAX20411
+ tristate "Maxim MAX20411 High-Efficiency Single Step-Down Converter"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ This driver controls the Maxim MAX20411 family of high-efficiency,
+ syncrhonous step-down converters.
+
config REGULATOR_MAX77686
tristate "Maxim 77686 regulator"
depends on MFD_MAX77686 || COMPILE_TEST
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index b9f5eb35bf5f..ee383d8fc835 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -80,6 +80,7 @@ obj-$(CONFIG_REGULATOR_MAX8973) += max8973-regulator.o
obj-$(CONFIG_REGULATOR_MAX8997) += max8997-regulator.o
obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o
obj-$(CONFIG_REGULATOR_MAX20086) += max20086-regulator.o
+obj-$(CONFIG_REGULATOR_MAX20411) += max20411-regulator.o
obj-$(CONFIG_REGULATOR_MAX77686) += max77686-regulator.o
obj-$(CONFIG_REGULATOR_MAX77693) += max77693-regulator.o
obj-$(CONFIG_REGULATOR_MAX77802) += max77802-regulator.o
diff --git a/drivers/regulator/act8945a-regulator.c b/drivers/regulator/act8945a-regulator.c
index 6a62f946ccae..1db1c6423779 100644
--- a/drivers/regulator/act8945a-regulator.c
+++ b/drivers/regulator/act8945a-regulator.c
@@ -15,7 +15,7 @@
#include <linux/regulator/machine.h>
#include <dt-bindings/regulator/active-semi,8945a-regulator.h>
-/**
+/*
* ACT8945A Global Register Map.
*/
#define ACT8945A_SYS_MODE 0x00
@@ -46,13 +46,13 @@
#define ACT8945A_LDO4_CTRL 0x65
#define ACT8945A_LDO4_SUS 0x66
-/**
+/*
* Field Definitions.
*/
#define ACT8945A_ENA 0x80 /* ON - [7] */
#define ACT8945A_VSEL_MASK 0x3F /* VSET - [5:0] */
-/**
+/*
* ACT8945A Voltage Number
*/
#define ACT8945A_VOLTAGE_NUM 64
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index ae69e493913d..4fcd36055b02 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1584,7 +1584,7 @@ static int set_machine_constraints(struct regulator_dev *rdev)
}
if (rdev->desc->off_on_delay)
- rdev->last_off = ktime_get();
+ rdev->last_off = ktime_get_boottime();
/* If the constraints say the regulator should be on at this point
* and we have control then make sure it is enabled.
@@ -2673,7 +2673,7 @@ static int _regulator_do_enable(struct regulator_dev *rdev)
* this regulator was disabled.
*/
ktime_t end = ktime_add_us(rdev->last_off, rdev->desc->off_on_delay);
- s64 remaining = ktime_us_delta(end, ktime_get());
+ s64 remaining = ktime_us_delta(end, ktime_get_boottime());
if (remaining > 0)
_regulator_delay_helper(remaining);
@@ -2912,7 +2912,7 @@ static int _regulator_do_disable(struct regulator_dev *rdev)
}
if (rdev->desc->off_on_delay)
- rdev->last_off = ktime_get();
+ rdev->last_off = ktime_get_boottime();
trace_regulator_disable_complete(rdev_get_name(rdev));
diff --git a/drivers/regulator/fixed-helper.c b/drivers/regulator/fixed-helper.c
index 2c6098e6f4bc..0eb2442456f0 100644
--- a/drivers/regulator/fixed-helper.c
+++ b/drivers/regulator/fixed-helper.c
@@ -20,7 +20,7 @@ static void regulator_fixed_release(struct device *dev)
}
/**
- * regulator_register_fixed_name - register a no-op fixed regulator
+ * regulator_register_always_on - register an always-on regulator with a fixed name
* @id: platform device id
* @name: name to be used for the regulator
* @supplies: consumers for this regulator
diff --git a/drivers/regulator/max20411-regulator.c b/drivers/regulator/max20411-regulator.c
new file mode 100644
index 000000000000..83dacb4ff173
--- /dev/null
+++ b/drivers/regulator/max20411-regulator.c
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022, Linaro Ltd.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+
+#define MAX20411_UV_STEP 6250
+#define MAX20411_BASE_UV 243750
+#define MAX20411_MIN_SEL 41 /* 0.5V */
+#define MAX20411_MAX_SEL 165 /* 1.275V */
+#define MAX20411_VID_OFFSET 0x7
+#define MAX20411_VID_MASK 0xff
+#define MAX20411_SLEW_OFFSET 0x6
+#define MAX20411_SLEW_DVS_MASK 0xc
+#define MAX20411_SLEW_SR_MASK 0x3
+
+struct max20411 {
+ struct device *dev;
+ struct device_node *of_node;
+ struct regulator_desc desc;
+ struct regulator_dev *rdev;
+ struct regmap *regmap;
+};
+
+static const unsigned int max20411_slew_rates[] = { 13100, 6600, 3300, 1600 };
+
+static int max20411_enable_time(struct regulator_dev *rdev)
+{
+ int voltage, rate, ret;
+ unsigned int val;
+
+ /* get voltage */
+ ret = regmap_read(rdev->regmap, rdev->desc->vsel_reg, &val);
+ if (ret)
+ return ret;
+
+ val &= rdev->desc->vsel_mask;
+ voltage = regulator_list_voltage_linear(rdev, val);
+
+ /* get rate */
+ ret = regmap_read(rdev->regmap, MAX20411_SLEW_OFFSET, &val);
+ if (ret)
+ return ret;
+
+ val = FIELD_GET(MAX20411_SLEW_SR_MASK, val);
+ rate = max20411_slew_rates[val];
+
+ return DIV_ROUND_UP(voltage, rate);
+}
+
+static const struct regmap_config max20411_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0xe,
+};
+
+static const struct regulator_ops max20411_ops = {
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ .enable_time = max20411_enable_time,
+};
+
+static const struct regulator_desc max20411_desc = {
+ .ops = &max20411_ops,
+ .owner = THIS_MODULE,
+ .type = REGULATOR_VOLTAGE,
+ .supply_name = "vin",
+ .name = "max20411",
+
+ /*
+ * voltage = 0.24375V + selector * 6.25mV
+ * with valid selector between 41 to 165 (0.5V to 1.275V)
+ */
+ .min_uV = MAX20411_BASE_UV,
+ .uV_step = MAX20411_UV_STEP,
+ .linear_min_sel = MAX20411_MIN_SEL,
+ .n_voltages = MAX20411_MAX_SEL + 1,
+
+ .vsel_reg = MAX20411_VID_OFFSET,
+ .vsel_mask = MAX20411_VID_MASK,
+
+ .ramp_reg = MAX20411_SLEW_OFFSET,
+ .ramp_mask = MAX20411_SLEW_DVS_MASK,
+ .ramp_delay_table = max20411_slew_rates,
+ .n_ramp_values = ARRAY_SIZE(max20411_slew_rates),
+};
+
+static int max20411_probe(struct i2c_client *client)
+{
+ struct regulator_init_data *init_data;
+ struct device *dev = &client->dev;
+ struct regulator_config cfg = {};
+ struct max20411 *max20411;
+
+ max20411 = devm_kzalloc(dev, sizeof(*max20411), GFP_KERNEL);
+ if (!max20411)
+ return -ENOMEM;
+
+ max20411->regmap = devm_regmap_init_i2c(client, &max20411_regmap_config);
+ if (IS_ERR(max20411->regmap)) {
+ dev_err(dev, "Failed to allocate regmap!\n");
+ return PTR_ERR(max20411->regmap);
+ }
+
+ max20411->dev = dev;
+ max20411->of_node = dev->of_node;
+
+ max20411->desc = max20411_desc;
+ init_data = of_get_regulator_init_data(max20411->dev, max20411->of_node, &max20411->desc);
+ if (!init_data)
+ return -ENODATA;
+
+ cfg.dev = max20411->dev;
+ cfg.init_data = init_data;
+ cfg.of_node = max20411->of_node;
+ cfg.driver_data = max20411;
+
+ cfg.ena_gpiod = gpiod_get(max20411->dev, "enable", GPIOD_ASIS);
+ if (IS_ERR(cfg.ena_gpiod))
+ return dev_err_probe(dev, PTR_ERR(cfg.ena_gpiod),
+ "unable to acquire enable gpio\n");
+
+ max20411->rdev = devm_regulator_register(max20411->dev, &max20411->desc, &cfg);
+ if (IS_ERR(max20411->rdev))
+ dev_err(max20411->dev, "Failed to register regulator\n");
+
+ return PTR_ERR_OR_ZERO(max20411->rdev);
+}
+
+static const struct of_device_id of_max20411_match_tbl[] = {
+ { .compatible = "maxim,max20411", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, of_max20411_match_tbl);
+
+static const struct i2c_device_id max20411_id[] = {
+ { "max20411", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, max20411_id);
+
+static struct i2c_driver max20411_i2c_driver = {
+ .driver = {
+ .name = "max20411",
+ .of_match_table = of_max20411_match_tbl,
+ },
+ .probe_new = max20411_probe,
+ .id_table = max20411_id,
+};
+module_i2c_driver(max20411_i2c_driver);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/max597x-regulator.c b/drivers/regulator/max597x-regulator.c
index 39f803ff0a90..648e3641885a 100644
--- a/drivers/regulator/max597x-regulator.c
+++ b/drivers/regulator/max597x-regulator.c
@@ -193,7 +193,7 @@ static int max597x_get_status(struct regulator_dev *rdev)
ret = regmap_read(rdev->regmap, MAX5970_REG_STATUS3, &val);
if (ret)
- return REGULATOR_FAILED_RETRY;
+ return ret;
if (val & MAX5970_STATUS3_ALERT)
return REGULATOR_STATUS_ERROR;
@@ -357,12 +357,6 @@ static int max597x_irq_handler(int irq, struct regulator_irq_data *rid,
return 0;
}
-static const struct regmap_config max597x_regmap_config = {
- .reg_bits = 8,
- .val_bits = 8,
- .max_register = MAX_REGISTERS,
-};
-
static int max597x_adc_range(struct regmap *regmap, const int ch,
u32 *irng, u32 *mon_rng)
{
@@ -431,41 +425,59 @@ static int max597x_setup_irq(struct device *dev,
static int max597x_regulator_probe(struct platform_device *pdev)
{
-
-
- struct max597x_data *max597x = dev_get_drvdata(pdev->dev.parent);
+ struct max597x_data *max597x;
+ struct regmap *regmap = dev_get_regmap(pdev->dev.parent, NULL);
struct max597x_regulator *data;
-
+ struct i2c_client *i2c = to_i2c_client(pdev->dev.parent);
struct regulator_config config = { };
struct regulator_dev *rdev;
struct regulator_dev *rdevs[MAX5970_NUM_SWITCHES];
- int num_switches = max597x->num_switches;
+ int num_switches;
int ret, i;
+ if (!regmap)
+ return -EPROBE_DEFER;
+
+ max597x = devm_kzalloc(&i2c->dev, sizeof(struct max597x_data), GFP_KERNEL);
+ if (!max597x)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, max597x);
+
+ if (of_device_is_compatible(i2c->dev.of_node, "maxim,max5978"))
+ max597x->num_switches = MAX597x_TYPE_MAX5978;
+ else if (of_device_is_compatible(i2c->dev.of_node, "maxim,max5970"))
+ max597x->num_switches = MAX597x_TYPE_MAX5970;
+ else
+ return -ENODEV;
+
+ i2c_set_clientdata(i2c, max597x);
+ num_switches = max597x->num_switches;
+
for (i = 0; i < num_switches; i++) {
data =
- devm_kzalloc(max597x->dev, sizeof(struct max597x_regulator),
+ devm_kzalloc(&i2c->dev, sizeof(struct max597x_regulator),
GFP_KERNEL);
if (!data)
return -ENOMEM;
data->num_switches = num_switches;
- data->regmap = max597x->regmap;
+ data->regmap = regmap;
- ret = max597x_adc_range(data->regmap, i, &max597x->irng[i], &max597x->mon_rng[i]);
+ ret = max597x_adc_range(regmap, i, &max597x->irng[i], &max597x->mon_rng[i]);
if (ret < 0)
return ret;
data->irng = max597x->irng[i];
data->mon_rng = max597x->mon_rng[i];
- config.dev = max597x->dev;
+ config.dev = &i2c->dev;
config.driver_data = (void *)data;
config.regmap = data->regmap;
- rdev = devm_regulator_register(max597x->dev,
+ rdev = devm_regulator_register(&i2c->dev,
&regulators[i], &config);
if (IS_ERR(rdev)) {
- dev_err(max597x->dev, "failed to register regulator %s\n",
+ dev_err(&i2c->dev, "failed to register regulator %s\n",
regulators[i].name);
return PTR_ERR(rdev);
}
@@ -473,12 +485,12 @@ static int max597x_regulator_probe(struct platform_device *pdev)
max597x->shunt_micro_ohms[i] = data->shunt_micro_ohms;
}
- if (max597x->irq) {
+ if (i2c->irq) {
ret =
- max597x_setup_irq(max597x->dev, max597x->irq, rdevs, num_switches,
+ max597x_setup_irq(&i2c->dev, i2c->irq, rdevs, num_switches,
data);
if (ret) {
- dev_err(max597x->dev, "IRQ setup failed");
+ dev_err(&i2c->dev, "IRQ setup failed");
return ret;
}
}
diff --git a/drivers/regulator/max77802-regulator.c b/drivers/regulator/max77802-regulator.c
index 21e0eb0f43f9..befe5f319819 100644
--- a/drivers/regulator/max77802-regulator.c
+++ b/drivers/regulator/max77802-regulator.c
@@ -94,9 +94,11 @@ static int max77802_set_suspend_disable(struct regulator_dev *rdev)
{
unsigned int val = MAX77802_OFF_PWRREQ;
struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev);
- int id = rdev_get_id(rdev);
+ unsigned int id = rdev_get_id(rdev);
int shift = max77802_get_opmode_shift(id);
+ if (WARN_ON_ONCE(id >= ARRAY_SIZE(max77802->opmode)))
+ return -EINVAL;
max77802->opmode[id] = val;
return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
rdev->desc->enable_mask, val << shift);
@@ -110,7 +112,7 @@ static int max77802_set_suspend_disable(struct regulator_dev *rdev)
static int max77802_set_mode(struct regulator_dev *rdev, unsigned int mode)
{
struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev);
- int id = rdev_get_id(rdev);
+ unsigned int id = rdev_get_id(rdev);
unsigned int val;
int shift = max77802_get_opmode_shift(id);
@@ -127,6 +129,9 @@ static int max77802_set_mode(struct regulator_dev *rdev, unsigned int mode)
return -EINVAL;
}
+ if (WARN_ON_ONCE(id >= ARRAY_SIZE(max77802->opmode)))
+ return -EINVAL;
+
max77802->opmode[id] = val;
return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
rdev->desc->enable_mask, val << shift);
@@ -135,8 +140,10 @@ static int max77802_set_mode(struct regulator_dev *rdev, unsigned int mode)
static unsigned max77802_get_mode(struct regulator_dev *rdev)
{
struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev);
- int id = rdev_get_id(rdev);
+ unsigned int id = rdev_get_id(rdev);
+ if (WARN_ON_ONCE(id >= ARRAY_SIZE(max77802->opmode)))
+ return -EINVAL;
return max77802_map_mode(max77802->opmode[id]);
}
@@ -160,10 +167,13 @@ static int max77802_set_suspend_mode(struct regulator_dev *rdev,
unsigned int mode)
{
struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev);
- int id = rdev_get_id(rdev);
+ unsigned int id = rdev_get_id(rdev);
unsigned int val;
int shift = max77802_get_opmode_shift(id);
+ if (WARN_ON_ONCE(id >= ARRAY_SIZE(max77802->opmode)))
+ return -EINVAL;
+
/*
* If the regulator has been disabled for suspend
* then is invalid to try setting a suspend mode.
@@ -209,9 +219,11 @@ static int max77802_set_suspend_mode(struct regulator_dev *rdev,
static int max77802_enable(struct regulator_dev *rdev)
{
struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev);
- int id = rdev_get_id(rdev);
+ unsigned int id = rdev_get_id(rdev);
int shift = max77802_get_opmode_shift(id);
+ if (WARN_ON_ONCE(id >= ARRAY_SIZE(max77802->opmode)))
+ return -EINVAL;
if (max77802->opmode[id] == MAX77802_OFF_PWRREQ)
max77802->opmode[id] = MAX77802_OPMODE_NORMAL;
@@ -495,7 +507,7 @@ static int max77802_pmic_probe(struct platform_device *pdev)
for (i = 0; i < MAX77802_REG_MAX; i++) {
struct regulator_dev *rdev;
- int id = regulators[i].id;
+ unsigned int id = regulators[i].id;
int shift = max77802_get_opmode_shift(id);
int ret;
@@ -513,10 +525,12 @@ static int max77802_pmic_probe(struct platform_device *pdev)
* the hardware reports OFF as the regulator operating mode.
* Default to operating mode NORMAL in that case.
*/
- if (val == MAX77802_STATUS_OFF)
- max77802->opmode[id] = MAX77802_OPMODE_NORMAL;
- else
- max77802->opmode[id] = val;
+ if (id < ARRAY_SIZE(max77802->opmode)) {
+ if (val == MAX77802_STATUS_OFF)
+ max77802->opmode[id] = MAX77802_OPMODE_NORMAL;
+ else
+ max77802->opmode[id] = val;
+ }
rdev = devm_regulator_register(&pdev->dev,
&regulators[i], &config);
diff --git a/drivers/regulator/mcp16502.c b/drivers/regulator/mcp16502.c
index 042668385678..abee1b09008d 100644
--- a/drivers/regulator/mcp16502.c
+++ b/drivers/regulator/mcp16502.c
@@ -77,6 +77,7 @@
* @MCP16502_REG_A: active state register
* @MCP16502_REG_LPM: low power mode state register
* @MCP16502_REG_HIB: hibernate state register
+ * @MCP16502_REG_HPM: high-performance mode register
* @MCP16502_REG_SEQ: startup sequence register
* @MCP16502_REG_CFG: configuration register
*/
diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c
index 35269f998210..754c6fcc6e64 100644
--- a/drivers/regulator/s5m8767.c
+++ b/drivers/regulator/s5m8767.c
@@ -923,10 +923,14 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
for (i = 0; i < pdata->num_regulators; i++) {
const struct sec_voltage_desc *desc;
- int id = pdata->regulators[i].id;
+ unsigned int id = pdata->regulators[i].id;
int enable_reg, enable_val;
struct regulator_dev *rdev;
+ BUILD_BUG_ON(ARRAY_SIZE(regulators) != ARRAY_SIZE(reg_voltage_map));
+ if (WARN_ON_ONCE(id >= ARRAY_SIZE(regulators)))
+ continue;
+
desc = reg_voltage_map[id];
if (desc) {
regulators[id].n_voltages =
diff --git a/drivers/regulator/scmi-regulator.c b/drivers/regulator/scmi-regulator.c
index b9918f4fd241..29ab217297d6 100644
--- a/drivers/regulator/scmi-regulator.c
+++ b/drivers/regulator/scmi-regulator.c
@@ -311,16 +311,12 @@ static int scmi_regulator_probe(struct scmi_device *sdev)
return PTR_ERR(voltage_ops);
num_doms = voltage_ops->num_domains_get(ph);
- if (num_doms <= 0) {
- if (!num_doms) {
- dev_err(&sdev->dev,
- "number of voltage domains invalid\n");
- num_doms = -EINVAL;
- } else {
- dev_err(&sdev->dev,
- "failed to get voltage domains - err:%d\n",
- num_doms);
- }
+ if (!num_doms)
+ return 0;
+
+ if (num_doms < 0) {
+ dev_err(&sdev->dev, "failed to get voltage domains - err:%d\n",
+ num_doms);
return num_doms;
}
diff --git a/drivers/regulator/tps65219-regulator.c b/drivers/regulator/tps65219-regulator.c
index c484c943e467..4b5acaa45049 100644
--- a/drivers/regulator/tps65219-regulator.c
+++ b/drivers/regulator/tps65219-regulator.c
@@ -173,24 +173,6 @@ static unsigned int tps65219_get_mode(struct regulator_dev *dev)
return REGULATOR_MODE_NORMAL;
}
-/*
- * generic regulator_set_bypass_regmap does not fully match requirements
- * TPS65219 Requires explicitly that regulator is disabled before switch
- */
-static int tps65219_set_bypass(struct regulator_dev *dev, bool enable)
-{
- struct tps65219 *tps = rdev_get_drvdata(dev);
- unsigned int rid = rdev_get_id(dev);
-
- if (dev->desc->ops->is_enabled(dev)) {
- dev_err(tps->dev,
- "%s LDO%d enabled, must be shut down to set bypass ",
- __func__, rid);
- return -EBUSY;
- }
- return regulator_set_bypass_regmap(dev, enable);
-}
-
/* Operations permitted on BUCK1/2/3 */
static const struct regulator_ops tps65219_bucks_ops = {
.is_enabled = regulator_is_enabled_regmap,
@@ -217,7 +199,7 @@ static const struct regulator_ops tps65219_ldos_1_2_ops = {
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.list_voltage = regulator_list_voltage_linear_range,
.map_voltage = regulator_map_voltage_linear_range,
- .set_bypass = tps65219_set_bypass,
+ .set_bypass = regulator_set_bypass_regmap,
.get_bypass = regulator_get_bypass_regmap,
};
@@ -342,7 +324,7 @@ static int tps65219_regulator_probe(struct platform_device *pdev)
&config);
if (IS_ERR(rdev)) {
dev_err(tps->dev, "failed to register %s regulator\n",
- pdev->name);
+ regulators[i].name);
return PTR_ERR(rdev);
}
rdevtbl[i] = rdev;
@@ -367,7 +349,7 @@ static int tps65219_regulator_probe(struct platform_device *pdev)
irq_data[i].type = irq_type;
tps65219_get_rdev_by_name(irq_type->regulator_name, rdevtbl, rdev);
- if (rdev < 0) {
+ if (IS_ERR(rdev)) {
dev_err(tps->dev, "Failed to get rdev for %s\n",
irq_type->regulator_name);
return -EINVAL;
diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c
index d421a2ccaa1e..0861b76f185f 100644
--- a/drivers/remoteproc/mtk_scp.c
+++ b/drivers/remoteproc/mtk_scp.c
@@ -649,6 +649,7 @@ static const struct rproc_ops scp_ops = {
.load = scp_load,
.da_to_va = scp_da_to_va,
.parse_fw = scp_parse_fw,
+ .sanity_check = rproc_elf_sanity_check,
};
/**
diff --git a/drivers/remoteproc/mtk_scp_ipi.c b/drivers/remoteproc/mtk_scp_ipi.c
index 00f041ebcde6..fc55df649b40 100644
--- a/drivers/remoteproc/mtk_scp_ipi.c
+++ b/drivers/remoteproc/mtk_scp_ipi.c
@@ -6,13 +6,17 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/time64.h>
#include <linux/remoteproc/mtk_scp.h>
#include "mtk_common.h"
+#define SCP_TIMEOUT_US (2000 * USEC_PER_MSEC)
+
/**
* scp_ipi_register() - register an ipi function
*
@@ -156,7 +160,7 @@ int scp_ipi_send(struct mtk_scp *scp, u32 id, void *buf, unsigned int len,
unsigned int wait)
{
struct mtk_share_obj __iomem *send_obj = scp->send_buf;
- unsigned long timeout;
+ u32 val;
int ret;
if (WARN_ON(id <= SCP_IPI_INIT) || WARN_ON(id >= SCP_IPI_MAX) ||
@@ -164,23 +168,21 @@ int scp_ipi_send(struct mtk_scp *scp, u32 id, void *buf, unsigned int len,
WARN_ON(len > sizeof(send_obj->share_buf)) || WARN_ON(!buf))
return -EINVAL;
- mutex_lock(&scp->send_lock);
-
ret = clk_prepare_enable(scp->clk);
if (ret) {
dev_err(scp->dev, "failed to enable clock\n");
- goto unlock_mutex;
+ return ret;
}
+ mutex_lock(&scp->send_lock);
+
/* Wait until SCP receives the last command */
- timeout = jiffies + msecs_to_jiffies(2000);
- do {
- if (time_after(jiffies, timeout)) {
- dev_err(scp->dev, "%s: IPI timeout!\n", __func__);
- ret = -ETIMEDOUT;
- goto clock_disable;
- }
- } while (readl(scp->reg_base + scp->data->host_to_scp_reg));
+ ret = readl_poll_timeout_atomic(scp->reg_base + scp->data->host_to_scp_reg,
+ val, !val, 0, SCP_TIMEOUT_US);
+ if (ret) {
+ dev_err(scp->dev, "%s: IPI timeout!\n", __func__);
+ goto unlock_mutex;
+ }
scp_memcpy_aligned(send_obj->share_buf, buf, len);
@@ -194,10 +196,9 @@ int scp_ipi_send(struct mtk_scp *scp, u32 id, void *buf, unsigned int len,
if (wait) {
/* wait for SCP's ACK */
- timeout = msecs_to_jiffies(wait);
ret = wait_event_timeout(scp->ack_wq,
scp->ipi_id_ack[id],
- timeout);
+ msecs_to_jiffies(wait));
scp->ipi_id_ack[id] = false;
if (WARN(!ret, "scp ipi %d ack time out !", id))
ret = -EIO;
@@ -205,10 +206,9 @@ int scp_ipi_send(struct mtk_scp *scp, u32 id, void *buf, unsigned int len,
ret = 0;
}
-clock_disable:
- clk_disable_unprepare(scp->clk);
unlock_mutex:
mutex_unlock(&scp->send_lock);
+ clk_disable_unprepare(scp->clk);
return ret;
}
diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c
index 128bf9912f2c..b76db7fa693d 100644
--- a/drivers/remoteproc/pru_rproc.c
+++ b/drivers/remoteproc/pru_rproc.c
@@ -2,12 +2,14 @@
/*
* PRU-ICSS remoteproc driver for various TI SoCs
*
- * Copyright (C) 2014-2020 Texas Instruments Incorporated - https://www.ti.com/
+ * Copyright (C) 2014-2022 Texas Instruments Incorporated - https://www.ti.com/
*
* Author(s):
* Suman Anna <s-anna@ti.com>
* Andrew F. Davis <afd@ti.com>
* Grzegorz Jaszczyk <grzegorz.jaszczyk@linaro.org> for Texas Instruments
+ * Puranjay Mohan <p-mohan@ti.com>
+ * Md Danish Anwar <danishanwar@ti.com>
*/
#include <linux/bitops.h>
@@ -16,6 +18,7 @@
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
+#include <linux/remoteproc/pruss.h>
#include <linux/pruss_driver.h>
#include <linux/remoteproc.h>
@@ -111,10 +114,13 @@ struct pru_private_data {
* @rproc: remoteproc pointer for this PRU core
* @data: PRU core specific data
* @mem_regions: data for each of the PRU memory regions
+ * @client_np: client device node
+ * @lock: mutex to protect client usage
* @fw_name: name of firmware image used during loading
* @mapped_irq: virtual interrupt numbers of created fw specific mapping
* @pru_interrupt_map: pointer to interrupt mapping description (firmware)
* @pru_interrupt_map_sz: pru_interrupt_map size
+ * @rmw_lock: lock for read, modify, write operations on registers
* @dbg_single_step: debug state variable to set PRU into single step mode
* @dbg_continuous: debug state variable to restore PRU execution mode
* @evt_count: number of mapped events
@@ -126,10 +132,13 @@ struct pru_rproc {
struct rproc *rproc;
const struct pru_private_data *data;
struct pruss_mem_region mem_regions[PRU_IOMEM_MAX];
+ struct device_node *client_np;
+ struct mutex lock;
const char *fw_name;
unsigned int *mapped_irq;
struct pru_irq_rsc *pru_interrupt_map;
size_t pru_interrupt_map_sz;
+ spinlock_t rmw_lock;
u32 dbg_single_step;
u32 dbg_continuous;
u8 evt_count;
@@ -146,6 +155,212 @@ void pru_control_write_reg(struct pru_rproc *pru, unsigned int reg, u32 val)
writel_relaxed(val, pru->mem_regions[PRU_IOMEM_CTRL].va + reg);
}
+static inline
+void pru_control_set_reg(struct pru_rproc *pru, unsigned int reg,
+ u32 mask, u32 set)
+{
+ u32 val;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pru->rmw_lock, flags);
+
+ val = pru_control_read_reg(pru, reg);
+ val &= ~mask;
+ val |= (set & mask);
+ pru_control_write_reg(pru, reg, val);
+
+ spin_unlock_irqrestore(&pru->rmw_lock, flags);
+}
+
+/**
+ * pru_rproc_set_firmware() - set firmware for a PRU core
+ * @rproc: the rproc instance of the PRU
+ * @fw_name: the new firmware name, or NULL if default is desired
+ *
+ * Return: 0 on success, or errno in error case.
+ */
+static int pru_rproc_set_firmware(struct rproc *rproc, const char *fw_name)
+{
+ struct pru_rproc *pru = rproc->priv;
+
+ if (!fw_name)
+ fw_name = pru->fw_name;
+
+ return rproc_set_firmware(rproc, fw_name);
+}
+
+static struct rproc *__pru_rproc_get(struct device_node *np, int index)
+{
+ struct rproc *rproc;
+ phandle rproc_phandle;
+ int ret;
+
+ ret = of_property_read_u32_index(np, "ti,prus", index, &rproc_phandle);
+ if (ret)
+ return ERR_PTR(ret);
+
+ rproc = rproc_get_by_phandle(rproc_phandle);
+ if (!rproc) {
+ ret = -EPROBE_DEFER;
+ return ERR_PTR(ret);
+ }
+
+ /* make sure it is PRU rproc */
+ if (!is_pru_rproc(rproc->dev.parent)) {
+ rproc_put(rproc);
+ return ERR_PTR(-ENODEV);
+ }
+
+ return rproc;
+}
+
+/**
+ * pru_rproc_get() - get the PRU rproc instance from a device node
+ * @np: the user/client device node
+ * @index: index to use for the ti,prus property
+ * @pru_id: optional pointer to return the PRU remoteproc processor id
+ *
+ * This function looks through a client device node's "ti,prus" property at
+ * index @index and returns the rproc handle for a valid PRU remote processor if
+ * found. The function allows only one user to own the PRU rproc resource at a
+ * time. Caller must call pru_rproc_put() when done with using the rproc, not
+ * required if the function returns a failure.
+ *
+ * When optional @pru_id pointer is passed the PRU remoteproc processor id is
+ * returned.
+ *
+ * Return: rproc handle on success, and an ERR_PTR on failure using one
+ * of the following error values
+ * -ENODEV if device is not found
+ * -EBUSY if PRU is already acquired by anyone
+ * -EPROBE_DEFER is PRU device is not probed yet
+ */
+struct rproc *pru_rproc_get(struct device_node *np, int index,
+ enum pruss_pru_id *pru_id)
+{
+ struct rproc *rproc;
+ struct pru_rproc *pru;
+ struct device *dev;
+ const char *fw_name;
+ int ret;
+
+ rproc = __pru_rproc_get(np, index);
+ if (IS_ERR(rproc))
+ return rproc;
+
+ pru = rproc->priv;
+ dev = &rproc->dev;
+
+ mutex_lock(&pru->lock);
+
+ if (pru->client_np) {
+ mutex_unlock(&pru->lock);
+ ret = -EBUSY;
+ goto err_no_rproc_handle;
+ }
+
+ pru->client_np = np;
+ rproc->sysfs_read_only = true;
+
+ mutex_unlock(&pru->lock);
+
+ if (pru_id)
+ *pru_id = pru->id;
+
+ ret = of_property_read_string_index(np, "firmware-name", index,
+ &fw_name);
+ if (!ret) {
+ ret = pru_rproc_set_firmware(rproc, fw_name);
+ if (ret) {
+ dev_err(dev, "failed to set firmware: %d\n", ret);
+ goto err;
+ }
+ }
+
+ return rproc;
+
+err_no_rproc_handle:
+ rproc_put(rproc);
+ return ERR_PTR(ret);
+
+err:
+ pru_rproc_put(rproc);
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(pru_rproc_get);
+
+/**
+ * pru_rproc_put() - release the PRU rproc resource
+ * @rproc: the rproc resource to release
+ *
+ * Releases the PRU rproc resource and makes it available to other
+ * users.
+ */
+void pru_rproc_put(struct rproc *rproc)
+{
+ struct pru_rproc *pru;
+
+ if (IS_ERR_OR_NULL(rproc) || !is_pru_rproc(rproc->dev.parent))
+ return;
+
+ pru = rproc->priv;
+
+ pru_rproc_set_firmware(rproc, NULL);
+
+ mutex_lock(&pru->lock);
+
+ if (!pru->client_np) {
+ mutex_unlock(&pru->lock);
+ return;
+ }
+
+ pru->client_np = NULL;
+ rproc->sysfs_read_only = false;
+ mutex_unlock(&pru->lock);
+
+ rproc_put(rproc);
+}
+EXPORT_SYMBOL_GPL(pru_rproc_put);
+
+/**
+ * pru_rproc_set_ctable() - set the constant table index for the PRU
+ * @rproc: the rproc instance of the PRU
+ * @c: constant table index to set
+ * @addr: physical address to set it to
+ *
+ * Return: 0 on success, or errno in error case.
+ */
+int pru_rproc_set_ctable(struct rproc *rproc, enum pru_ctable_idx c, u32 addr)
+{
+ struct pru_rproc *pru = rproc->priv;
+ unsigned int reg;
+ u32 mask, set;
+ u16 idx;
+ u16 idx_mask;
+
+ if (IS_ERR_OR_NULL(rproc))
+ return -EINVAL;
+
+ if (!rproc->dev.parent || !is_pru_rproc(rproc->dev.parent))
+ return -ENODEV;
+
+ /* pointer is 16 bit and index is 8-bit so mask out the rest */
+ idx_mask = (c >= PRU_C28) ? 0xFFFF : 0xFF;
+
+ /* ctable uses bit 8 and upwards only */
+ idx = (addr >> 8) & idx_mask;
+
+ /* configurable ctable (i.e. C24) starts at PRU_CTRL_CTBIR0 */
+ reg = PRU_CTRL_CTBIR0 + 4 * (c >> 1);
+ mask = idx_mask << (16 * (c & 1));
+ set = idx << (16 * (c & 1));
+
+ pru_control_set_reg(pru, reg, mask, set);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pru_rproc_set_ctable);
+
static inline u32 pru_debug_read_reg(struct pru_rproc *pru, unsigned int reg)
{
return readl_relaxed(pru->mem_regions[PRU_IOMEM_DEBUG].va + reg);
@@ -438,7 +653,7 @@ static void *pru_d_da_to_va(struct pru_rproc *pru, u32 da, size_t len)
dram0 = pruss->mem_regions[PRUSS_MEM_DRAM0];
dram1 = pruss->mem_regions[PRUSS_MEM_DRAM1];
/* PRU1 has its local RAM addresses reversed */
- if (pru->id == 1)
+ if (pru->id == PRUSS_PRU1)
swap(dram0, dram1);
shrd_ram = pruss->mem_regions[PRUSS_MEM_SHRD_RAM2];
@@ -747,14 +962,14 @@ static int pru_rproc_set_id(struct pru_rproc *pru)
case RTU0_IRAM_ADDR_MASK:
fallthrough;
case PRU0_IRAM_ADDR_MASK:
- pru->id = 0;
+ pru->id = PRUSS_PRU0;
break;
case TX_PRU1_IRAM_ADDR_MASK:
fallthrough;
case RTU1_IRAM_ADDR_MASK:
fallthrough;
case PRU1_IRAM_ADDR_MASK:
- pru->id = 1;
+ pru->id = PRUSS_PRU1;
break;
default:
ret = -EINVAL;
@@ -816,6 +1031,9 @@ static int pru_rproc_probe(struct platform_device *pdev)
pru->pruss = platform_get_drvdata(ppdev);
pru->rproc = rproc;
pru->fw_name = fw_name;
+ pru->client_np = NULL;
+ spin_lock_init(&pru->rmw_lock);
+ mutex_init(&pru->lock);
for (i = 0; i < ARRAY_SIZE(mem_names); i++) {
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
@@ -904,7 +1122,7 @@ MODULE_DEVICE_TABLE(of, pru_rproc_match);
static struct platform_driver pru_rproc_driver = {
.driver = {
- .name = "pru-rproc",
+ .name = PRU_RPROC_DRVNAME,
.of_match_table = pru_rproc_match,
.suppress_bind_attrs = true,
},
@@ -916,5 +1134,7 @@ module_platform_driver(pru_rproc_driver);
MODULE_AUTHOR("Suman Anna <s-anna@ti.com>");
MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
MODULE_AUTHOR("Grzegorz Jaszczyk <grzegorz.jaszczyk@linaro.org>");
+MODULE_AUTHOR("Puranjay Mohan <p-mohan@ti.com>");
+MODULE_AUTHOR("Md Danish Anwar <danishanwar@ti.com>");
MODULE_DESCRIPTION("PRU-ICSS Remote Processor Driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/remoteproc/qcom_common.c b/drivers/remoteproc/qcom_common.c
index 020349f8979d..a0d4238492e9 100644
--- a/drivers/remoteproc/qcom_common.c
+++ b/drivers/remoteproc/qcom_common.c
@@ -101,7 +101,9 @@ static void qcom_minidump_cleanup(struct rproc *rproc)
}
}
-static int qcom_add_minidump_segments(struct rproc *rproc, struct minidump_subsystem *subsystem)
+static int qcom_add_minidump_segments(struct rproc *rproc, struct minidump_subsystem *subsystem,
+ void (*rproc_dumpfn_t)(struct rproc *rproc, struct rproc_dump_segment *segment,
+ void *dest, size_t offset, size_t size))
{
struct minidump_region __iomem *ptr;
struct minidump_region region;
@@ -123,15 +125,15 @@ static int qcom_add_minidump_segments(struct rproc *rproc, struct minidump_subsy
for (i = 0; i < seg_cnt; i++) {
memcpy_fromio(&region, ptr + i, sizeof(region));
- if (region.valid == MD_REGION_VALID) {
- name = kstrdup(region.name, GFP_KERNEL);
+ if (le32_to_cpu(region.valid) == MD_REGION_VALID) {
+ name = kstrndup(region.name, MAX_REGION_NAME_LENGTH - 1, GFP_KERNEL);
if (!name) {
iounmap(ptr);
return -ENOMEM;
}
da = le64_to_cpu(region.address);
- size = le32_to_cpu(region.size);
- rproc_coredump_add_custom_segment(rproc, da, size, NULL, name);
+ size = le64_to_cpu(region.size);
+ rproc_coredump_add_custom_segment(rproc, da, size, rproc_dumpfn_t, name);
}
}
@@ -139,7 +141,10 @@ static int qcom_add_minidump_segments(struct rproc *rproc, struct minidump_subsy
return 0;
}
-void qcom_minidump(struct rproc *rproc, unsigned int minidump_id)
+void qcom_minidump(struct rproc *rproc, unsigned int minidump_id,
+ void (*rproc_dumpfn_t)(struct rproc *rproc,
+ struct rproc_dump_segment *segment, void *dest, size_t offset,
+ size_t size))
{
int ret;
struct minidump_subsystem *subsystem;
@@ -169,7 +174,7 @@ void qcom_minidump(struct rproc *rproc, unsigned int minidump_id)
return;
}
- ret = qcom_add_minidump_segments(rproc, subsystem);
+ ret = qcom_add_minidump_segments(rproc, subsystem, rproc_dumpfn_t);
if (ret) {
dev_err(&rproc->dev, "Failed with error: %d while adding minidump entries\n", ret);
goto clean_minidump;
diff --git a/drivers/remoteproc/qcom_common.h b/drivers/remoteproc/qcom_common.h
index c35adf730be0..9ef4449052a9 100644
--- a/drivers/remoteproc/qcom_common.h
+++ b/drivers/remoteproc/qcom_common.h
@@ -6,6 +6,7 @@
#include "remoteproc_internal.h"
#include <linux/soc/qcom/qmi.h>
+struct qcom_glink_smem;
struct qcom_sysmon;
struct qcom_rproc_glink {
@@ -15,7 +16,7 @@ struct qcom_rproc_glink {
struct device *dev;
struct device_node *node;
- struct qcom_glink *edge;
+ struct qcom_glink_smem *edge;
};
struct qcom_rproc_subdev {
@@ -33,7 +34,10 @@ struct qcom_rproc_ssr {
struct qcom_ssr_subsystem *info;
};
-void qcom_minidump(struct rproc *rproc, unsigned int minidump_id);
+void qcom_minidump(struct rproc *rproc, unsigned int minidump_id,
+ void (*rproc_dumpfn_t)(struct rproc *rproc,
+ struct rproc_dump_segment *segment, void *dest, size_t offset,
+ size_t size));
void qcom_add_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glink,
const char *ssr_name);
diff --git a/drivers/remoteproc/qcom_q6v5.c b/drivers/remoteproc/qcom_q6v5.c
index 497acfb33f8f..192c7aa0e39e 100644
--- a/drivers/remoteproc/qcom_q6v5.c
+++ b/drivers/remoteproc/qcom_q6v5.c
@@ -205,8 +205,8 @@ int qcom_q6v5_request_stop(struct qcom_q6v5 *q6v5, struct qcom_sysmon *sysmon)
q6v5->running = false;
- /* Don't perform SMP2P dance if sysmon already shut down the remote */
- if (qcom_sysmon_shutdown_acked(sysmon))
+ /* Don't perform SMP2P dance if remote isn't running */
+ if (q6v5->rproc->state != RPROC_RUNNING || qcom_sysmon_shutdown_acked(sysmon))
return 0;
qcom_smem_state_update_bits(q6v5->state,
diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c
index 4c9a1b99cd51..08d8dad22ca7 100644
--- a/drivers/remoteproc/qcom_q6v5_adsp.c
+++ b/drivers/remoteproc/qcom_q6v5_adsp.c
@@ -9,6 +9,7 @@
#include <linux/firmware.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/iommu.h>
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/mfd/syscon.h>
@@ -48,12 +49,18 @@
#define LPASS_PWR_ON_REG 0x10
#define LPASS_HALTREQ_REG 0x0
+#define SID_MASK_DEFAULT 0xF
+
#define QDSP6SS_XO_CBCR 0x38
#define QDSP6SS_CORE_CBCR 0x20
#define QDSP6SS_SLEEP_CBCR 0x3c
#define QCOM_Q6V5_RPROC_PROXY_PD_MAX 3
+#define LPASS_BOOT_CORE_START BIT(0)
+#define LPASS_BOOT_CMD_START BIT(0)
+#define LPASS_EFUSE_Q6SS_EVB_SEL 0x0
+
struct adsp_pil_data {
int crash_reason_smem;
const char *firmware_name;
@@ -62,6 +69,7 @@ struct adsp_pil_data {
const char *sysmon_name;
int ssctl_id;
bool is_wpss;
+ bool has_iommu;
bool auto_boot;
const char **clk_ids;
@@ -82,6 +90,7 @@ struct qcom_adsp {
struct clk_bulk_data *clks;
void __iomem *qdsp6ss_base;
+ void __iomem *lpass_efuse;
struct reset_control *pdc_sync_reset;
struct reset_control *restart;
@@ -99,6 +108,7 @@ struct qcom_adsp {
phys_addr_t mem_reloc;
void *mem_region;
size_t mem_size;
+ bool has_iommu;
struct device *proxy_pds[QCOM_Q6V5_RPROC_PROXY_PD_MAX];
size_t proxy_pd_count;
@@ -325,6 +335,48 @@ static int adsp_load(struct rproc *rproc, const struct firmware *fw)
return 0;
}
+static void adsp_unmap_carveout(struct rproc *rproc)
+{
+ struct qcom_adsp *adsp = rproc->priv;
+
+ if (adsp->has_iommu)
+ iommu_unmap(rproc->domain, adsp->mem_phys, adsp->mem_size);
+}
+
+static int adsp_map_carveout(struct rproc *rproc)
+{
+ struct qcom_adsp *adsp = rproc->priv;
+ struct of_phandle_args args;
+ long long sid;
+ unsigned long iova;
+ int ret;
+
+ if (!adsp->has_iommu)
+ return 0;
+
+ if (!rproc->domain)
+ return -EINVAL;
+
+ ret = of_parse_phandle_with_args(adsp->dev->of_node, "iommus", "#iommu-cells", 0, &args);
+ if (ret < 0)
+ return ret;
+
+ sid = args.args[0] & SID_MASK_DEFAULT;
+
+ /* Add SID configuration for ADSP Firmware to SMMU */
+ iova = adsp->mem_phys | (sid << 32);
+
+ ret = iommu_map(rproc->domain, iova, adsp->mem_phys,
+ adsp->mem_size, IOMMU_READ | IOMMU_WRITE,
+ GFP_KERNEL);
+ if (ret) {
+ dev_err(adsp->dev, "Unable to map ADSP Physical Memory\n");
+ return ret;
+ }
+
+ return 0;
+}
+
static int adsp_start(struct rproc *rproc)
{
struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
@@ -335,9 +387,15 @@ static int adsp_start(struct rproc *rproc)
if (ret)
return ret;
+ ret = adsp_map_carveout(rproc);
+ if (ret) {
+ dev_err(adsp->dev, "ADSP smmu mapping failed\n");
+ goto disable_irqs;
+ }
+
ret = clk_prepare_enable(adsp->xo);
if (ret)
- goto disable_irqs;
+ goto adsp_smmu_unmap;
ret = qcom_rproc_pds_enable(adsp, adsp->proxy_pds,
adsp->proxy_pd_count);
@@ -362,11 +420,14 @@ static int adsp_start(struct rproc *rproc)
/* Program boot address */
writel(adsp->mem_phys >> 4, adsp->qdsp6ss_base + RST_EVB_REG);
+ if (adsp->lpass_efuse)
+ writel(LPASS_EFUSE_Q6SS_EVB_SEL, adsp->lpass_efuse);
+
/* De-assert QDSP6 stop core. QDSP6 will execute after out of reset */
- writel(0x1, adsp->qdsp6ss_base + CORE_START_REG);
+ writel(LPASS_BOOT_CORE_START, adsp->qdsp6ss_base + CORE_START_REG);
/* Trigger boot FSM to start QDSP6 */
- writel(0x1, adsp->qdsp6ss_base + BOOT_CMD_REG);
+ writel(LPASS_BOOT_CMD_START, adsp->qdsp6ss_base + BOOT_CMD_REG);
/* Wait for core to come out of reset */
ret = readl_poll_timeout(adsp->qdsp6ss_base + BOOT_STATUS_REG,
@@ -390,6 +451,8 @@ disable_power_domain:
qcom_rproc_pds_disable(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
disable_xo_clk:
clk_disable_unprepare(adsp->xo);
+adsp_smmu_unmap:
+ adsp_unmap_carveout(rproc);
disable_irqs:
qcom_q6v5_unprepare(&adsp->q6v5);
@@ -418,6 +481,8 @@ static int adsp_stop(struct rproc *rproc)
if (ret)
dev_err(adsp->dev, "failed to shutdown: %d\n", ret);
+ adsp_unmap_carveout(rproc);
+
handover = qcom_q6v5_unprepare(&adsp->q6v5);
if (handover)
qcom_adsp_pil_handover(&adsp->q6v5);
@@ -437,6 +502,27 @@ static void *adsp_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iom
return adsp->mem_region + offset;
}
+static int adsp_parse_firmware(struct rproc *rproc, const struct firmware *fw)
+{
+ struct qcom_adsp *adsp = rproc->priv;
+ int ret;
+
+ ret = qcom_register_dump_segments(rproc, fw);
+ if (ret) {
+ dev_err(&rproc->dev, "Error in registering dump segments\n");
+ return ret;
+ }
+
+ if (adsp->has_iommu) {
+ ret = rproc_elf_load_rsc_table(rproc, fw);
+ if (ret) {
+ dev_err(&rproc->dev, "Error in loading resource table\n");
+ return ret;
+ }
+ }
+ return 0;
+}
+
static unsigned long adsp_panic(struct rproc *rproc)
{
struct qcom_adsp *adsp = rproc->priv;
@@ -448,7 +534,7 @@ static const struct rproc_ops adsp_ops = {
.start = adsp_start,
.stop = adsp_stop,
.da_to_va = adsp_da_to_va,
- .parse_fw = qcom_register_dump_segments,
+ .parse_fw = adsp_parse_firmware,
.load = adsp_load,
.panic = adsp_panic,
};
@@ -507,6 +593,7 @@ static int adsp_init_reset(struct qcom_adsp *adsp)
static int adsp_init_mmio(struct qcom_adsp *adsp,
struct platform_device *pdev)
{
+ struct resource *efuse_region;
struct device_node *syscon;
int ret;
@@ -516,6 +603,17 @@ static int adsp_init_mmio(struct qcom_adsp *adsp,
return PTR_ERR(adsp->qdsp6ss_base);
}
+ efuse_region = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!efuse_region) {
+ adsp->lpass_efuse = NULL;
+ dev_dbg(adsp->dev, "failed to get efuse memory region\n");
+ } else {
+ adsp->lpass_efuse = devm_ioremap_resource(&pdev->dev, efuse_region);
+ if (IS_ERR(adsp->lpass_efuse)) {
+ dev_err(adsp->dev, "failed to map efuse registers\n");
+ return PTR_ERR(adsp->lpass_efuse);
+ }
+ }
syscon = of_parse_phandle(pdev->dev.of_node, "qcom,halt-regs", 0);
if (!syscon) {
dev_err(&pdev->dev, "failed to parse qcom,halt-regs\n");
@@ -595,12 +693,15 @@ static int adsp_probe(struct platform_device *pdev)
}
rproc->auto_boot = desc->auto_boot;
+ rproc->has_iommu = desc->has_iommu;
rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE);
adsp = (struct qcom_adsp *)rproc->priv;
adsp->dev = &pdev->dev;
adsp->rproc = rproc;
adsp->info_name = desc->sysmon_name;
+ adsp->has_iommu = desc->has_iommu;
+
platform_set_drvdata(pdev, adsp);
if (desc->is_wpss)
@@ -696,6 +797,21 @@ static const struct adsp_pil_data adsp_resource_init = {
},
};
+static const struct adsp_pil_data adsp_sc7280_resource_init = {
+ .crash_reason_smem = 423,
+ .firmware_name = "adsp.pbn",
+ .load_state = "adsp",
+ .ssr_name = "lpass",
+ .sysmon_name = "adsp",
+ .ssctl_id = 0x14,
+ .has_iommu = true,
+ .auto_boot = true,
+ .clk_ids = (const char*[]) {
+ "gcc_cfg_noc_lpass", NULL
+ },
+ .num_clks = 1,
+};
+
static const struct adsp_pil_data cdsp_resource_init = {
.crash_reason_smem = 601,
.firmware_name = "cdsp.mdt",
@@ -734,6 +850,7 @@ static const struct adsp_pil_data wpss_resource_init = {
static const struct of_device_id adsp_of_match[] = {
{ .compatible = "qcom,qcs404-cdsp-pil", .data = &cdsp_resource_init },
+ { .compatible = "qcom,sc7280-adsp-pil", .data = &adsp_sc7280_resource_init },
{ .compatible = "qcom,sc7280-wpss-pil", .data = &wpss_resource_init },
{ .compatible = "qcom,sdm845-adsp-pil", .data = &adsp_resource_init },
{ },
diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c
index fddb63cffee0..ab053084f7a2 100644
--- a/drivers/remoteproc/qcom_q6v5_mss.c
+++ b/drivers/remoteproc/qcom_q6v5_mss.c
@@ -10,7 +10,6 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/devcoredump.h>
-#include <linux/dma-map-ops.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
@@ -18,6 +17,7 @@
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
+#include <linux/of_reserved_mem.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
@@ -34,12 +34,14 @@
#include "qcom_pil_info.h"
#include "qcom_q6v5.h"
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#define MPSS_CRASH_REASON_SMEM 421
#define MBA_LOG_SIZE SZ_4K
+#define MPSS_PAS_ID 5
+
/* RMB Status Register Values */
#define RMB_PBL_SUCCESS 0x1
@@ -111,6 +113,9 @@
#define QDSS_BHS_ON BIT(21)
#define QDSS_LDO_BYP BIT(22)
+/* QDSP6v55 parameters */
+#define QDSP6V55_MEM_BITS GENMASK(16, 8)
+
/* QDSP6v56 parameters */
#define QDSP6v56_LDO_BYP BIT(25)
#define QDSP6v56_BHS_ON BIT(24)
@@ -211,6 +216,9 @@ struct q6v5 {
size_t mba_size;
size_t dp_size;
+ phys_addr_t mdata_phys;
+ size_t mdata_size;
+
phys_addr_t mpss_phys;
phys_addr_t mpss_reloc;
size_t mpss_size;
@@ -234,7 +242,9 @@ struct q6v5 {
};
enum {
+ MSS_MSM8909,
MSS_MSM8916,
+ MSS_MSM8953,
MSS_MSM8974,
MSS_MSM8996,
MSS_MSM8998,
@@ -687,13 +697,16 @@ static int q6v5proc_reset(struct q6v5 *qproc)
return ret;
}
goto pbl_wait;
- } else if (qproc->version == MSS_MSM8996 ||
+ } else if (qproc->version == MSS_MSM8909 ||
+ qproc->version == MSS_MSM8953 ||
+ qproc->version == MSS_MSM8996 ||
qproc->version == MSS_MSM8998) {
- int mem_pwr_ctl;
- /* Override the ACC value if required */
- writel(QDSP6SS_ACC_OVERRIDE_VAL,
- qproc->reg_base + QDSP6SS_STRAP_ACC);
+ if (qproc->version != MSS_MSM8909 &&
+ qproc->version != MSS_MSM8953)
+ /* Override the ACC value if required */
+ writel(QDSP6SS_ACC_OVERRIDE_VAL,
+ qproc->reg_base + QDSP6SS_STRAP_ACC);
/* Assert resets, stop core */
val = readl(qproc->reg_base + QDSP6SS_RESET_REG);
@@ -725,36 +738,54 @@ static int q6v5proc_reset(struct q6v5 *qproc)
val |= QDSP6v56_LDO_BYP;
writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
- /* Deassert QDSP6 compiler memory clamp */
- val = readl(qproc->reg_base + QDSP6SS_PWR_CTL_REG);
- val &= ~QDSP6v56_CLAMP_QMC_MEM;
- writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
-
- /* Deassert memory peripheral sleep and L2 memory standby */
- val |= Q6SS_L2DATA_STBY_N | Q6SS_SLP_RET_N;
- writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
-
- /* Turn on L1, L2, ETB and JU memories 1 at a time */
- if (qproc->version == MSS_MSM8996) {
- mem_pwr_ctl = QDSP6SS_MEM_PWR_CTL;
- i = 19;
+ if (qproc->version != MSS_MSM8909) {
+ int mem_pwr_ctl;
+
+ /* Deassert QDSP6 compiler memory clamp */
+ val = readl(qproc->reg_base + QDSP6SS_PWR_CTL_REG);
+ val &= ~QDSP6v56_CLAMP_QMC_MEM;
+ writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
+
+ /* Deassert memory peripheral sleep and L2 memory standby */
+ val |= Q6SS_L2DATA_STBY_N | Q6SS_SLP_RET_N;
+ writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
+
+ /* Turn on L1, L2, ETB and JU memories 1 at a time */
+ if (qproc->version == MSS_MSM8953 ||
+ qproc->version == MSS_MSM8996) {
+ mem_pwr_ctl = QDSP6SS_MEM_PWR_CTL;
+ i = 19;
+ } else {
+ /* MSS_MSM8998 */
+ mem_pwr_ctl = QDSP6V6SS_MEM_PWR_CTL;
+ i = 28;
+ }
+ val = readl(qproc->reg_base + mem_pwr_ctl);
+ for (; i >= 0; i--) {
+ val |= BIT(i);
+ writel(val, qproc->reg_base + mem_pwr_ctl);
+ /*
+ * Read back value to ensure the write is done then
+ * wait for 1us for both memory peripheral and data
+ * array to turn on.
+ */
+ val |= readl(qproc->reg_base + mem_pwr_ctl);
+ udelay(1);
+ }
} else {
- /* MSS_MSM8998 */
- mem_pwr_ctl = QDSP6V6SS_MEM_PWR_CTL;
- i = 28;
- }
- val = readl(qproc->reg_base + mem_pwr_ctl);
- for (; i >= 0; i--) {
- val |= BIT(i);
- writel(val, qproc->reg_base + mem_pwr_ctl);
- /*
- * Read back value to ensure the write is done then
- * wait for 1us for both memory peripheral and data
- * array to turn on.
- */
- val |= readl(qproc->reg_base + mem_pwr_ctl);
- udelay(1);
+ /* Turn on memories */
+ val = readl(qproc->reg_base + QDSP6SS_PWR_CTL_REG);
+ val |= Q6SS_SLP_RET_N | Q6SS_L2DATA_STBY_N |
+ Q6SS_ETB_SLP_NRET_N | QDSP6V55_MEM_BITS;
+ writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
+
+ /* Turn on L2 banks 1 at a time */
+ for (i = 0; i <= 7; i++) {
+ val |= BIT(i);
+ writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
+ }
}
+
/* Remove word line clamp */
val = readl(qproc->reg_base + QDSP6SS_PWR_CTL_REG);
val &= ~QDSP6v56_CLAMP_WL;
@@ -933,52 +964,47 @@ static void q6v5proc_halt_axi_port(struct q6v5 *qproc,
static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw,
const char *fw_name)
{
- unsigned long dma_attrs = DMA_ATTR_FORCE_CONTIGUOUS | DMA_ATTR_NO_KERNEL_MAPPING;
- unsigned long flags = VM_DMA_COHERENT | VM_FLUSH_RESET_PERMS;
- struct page **pages;
- struct page *page;
+ unsigned long dma_attrs = DMA_ATTR_FORCE_CONTIGUOUS;
dma_addr_t phys;
void *metadata;
int mdata_perm;
int xferop_ret;
size_t size;
- void *vaddr;
- int count;
+ void *ptr;
int ret;
- int i;
metadata = qcom_mdt_read_metadata(fw, &size, fw_name, qproc->dev);
if (IS_ERR(metadata))
return PTR_ERR(metadata);
- page = dma_alloc_attrs(qproc->dev, size, &phys, GFP_KERNEL, dma_attrs);
- if (!page) {
- kfree(metadata);
- dev_err(qproc->dev, "failed to allocate mdt buffer\n");
- return -ENOMEM;
- }
-
- count = PAGE_ALIGN(size) >> PAGE_SHIFT;
- pages = kmalloc_array(count, sizeof(struct page *), GFP_KERNEL);
- if (!pages) {
- ret = -ENOMEM;
- goto free_dma_attrs;
- }
-
- for (i = 0; i < count; i++)
- pages[i] = nth_page(page, i);
+ if (qproc->mdata_phys) {
+ if (size > qproc->mdata_size) {
+ ret = -EINVAL;
+ dev_err(qproc->dev, "metadata size outside memory range\n");
+ goto free_metadata;
+ }
- vaddr = vmap(pages, count, flags, pgprot_dmacoherent(PAGE_KERNEL));
- kfree(pages);
- if (!vaddr) {
- dev_err(qproc->dev, "unable to map memory region: %pa+%zx\n", &phys, size);
- ret = -EBUSY;
- goto free_dma_attrs;
+ phys = qproc->mdata_phys;
+ ptr = memremap(qproc->mdata_phys, size, MEMREMAP_WC);
+ if (!ptr) {
+ ret = -EBUSY;
+ dev_err(qproc->dev, "unable to map memory region: %pa+%zx\n",
+ &qproc->mdata_phys, size);
+ goto free_metadata;
+ }
+ } else {
+ ptr = dma_alloc_attrs(qproc->dev, size, &phys, GFP_KERNEL, dma_attrs);
+ if (!ptr) {
+ ret = -ENOMEM;
+ dev_err(qproc->dev, "failed to allocate mdt buffer\n");
+ goto free_metadata;
+ }
}
- memcpy(vaddr, metadata, size);
+ memcpy(ptr, metadata, size);
- vunmap(vaddr);
+ if (qproc->mdata_phys)
+ memunmap(ptr);
/* Hypervisor mapping to access metadata by modem */
mdata_perm = BIT(QCOM_SCM_VMID_HLOS);
@@ -1008,7 +1034,9 @@ static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw,
"mdt buffer not reclaimed system may become unstable\n");
free_dma_attrs:
- dma_free_attrs(qproc->dev, size, page, phys, dma_attrs);
+ if (!qproc->mdata_phys)
+ dma_free_attrs(qproc->dev, size, ptr, phys, dma_attrs);
+free_metadata:
kfree(metadata);
return ret < 0 ? ret : 0;
@@ -1343,6 +1371,15 @@ static int q6v5_mpss_load(struct q6v5 *qproc)
max_addr = ALIGN(phdr->p_paddr + phdr->p_memsz, SZ_4K);
}
+ if (qproc->version == MSS_MSM8953) {
+ ret = qcom_scm_pas_mem_setup(MPSS_PAS_ID, qproc->mpss_phys, qproc->mpss_size);
+ if (ret) {
+ dev_err(qproc->dev,
+ "setting up mpss memory failed: %d\n", ret);
+ goto release_firmware;
+ }
+ }
+
/*
* In case of a modem subsystem restart on secure devices, the modem
* memory can be reclaimed only after MBA is loaded.
@@ -1836,6 +1873,7 @@ static int q6v5_init_reset(struct q6v5 *qproc)
static int q6v5_alloc_memory_region(struct q6v5 *qproc)
{
struct device_node *child;
+ struct reserved_mem *rmem;
struct device_node *node;
struct resource r;
int ret;
@@ -1882,6 +1920,26 @@ static int q6v5_alloc_memory_region(struct q6v5 *qproc)
qproc->mpss_phys = qproc->mpss_reloc = r.start;
qproc->mpss_size = resource_size(&r);
+ if (!child) {
+ node = of_parse_phandle(qproc->dev->of_node, "memory-region", 2);
+ } else {
+ child = of_get_child_by_name(qproc->dev->of_node, "metadata");
+ node = of_parse_phandle(child, "memory-region", 0);
+ of_node_put(child);
+ }
+
+ if (!node)
+ return 0;
+
+ rmem = of_reserved_mem_lookup(node);
+ if (!rmem) {
+ dev_err(qproc->dev, "unable to resolve metadata region\n");
+ return -EINVAL;
+ }
+
+ qproc->mdata_phys = rmem->base;
+ qproc->mdata_size = rmem->size;
+
return 0;
}
@@ -2240,6 +2298,40 @@ static const struct rproc_hexagon_res msm8996_mss = {
.version = MSS_MSM8996,
};
+static const struct rproc_hexagon_res msm8909_mss = {
+ .hexagon_mba_image = "mba.mbn",
+ .proxy_supply = (struct qcom_mss_reg_res[]) {
+ {
+ .supply = "pll",
+ .uA = 100000,
+ },
+ {}
+ },
+ .proxy_clk_names = (char*[]){
+ "xo",
+ NULL
+ },
+ .active_clk_names = (char*[]){
+ "iface",
+ "bus",
+ "mem",
+ NULL
+ },
+ .proxy_pd_names = (char*[]){
+ "mx",
+ "cx",
+ NULL
+ },
+ .need_mem_protection = false,
+ .has_alt_reset = false,
+ .has_mba_logs = false,
+ .has_spare_reg = false,
+ .has_qaccept_regs = false,
+ .has_ext_cntl_regs = false,
+ .has_vq6 = false,
+ .version = MSS_MSM8909,
+};
+
static const struct rproc_hexagon_res msm8916_mss = {
.hexagon_mba_image = "mba.mbn",
.proxy_supply = (struct qcom_mss_reg_res[]) {
@@ -2285,6 +2377,41 @@ static const struct rproc_hexagon_res msm8916_mss = {
.version = MSS_MSM8916,
};
+static const struct rproc_hexagon_res msm8953_mss = {
+ .hexagon_mba_image = "mba.mbn",
+ .proxy_supply = (struct qcom_mss_reg_res[]) {
+ {
+ .supply = "pll",
+ .uA = 100000,
+ },
+ {}
+ },
+ .proxy_clk_names = (char*[]){
+ "xo",
+ NULL
+ },
+ .active_clk_names = (char*[]){
+ "iface",
+ "bus",
+ "mem",
+ NULL
+ },
+ .proxy_pd_names = (char*[]) {
+ "cx",
+ "mx",
+ "mss",
+ NULL
+ },
+ .need_mem_protection = false,
+ .has_alt_reset = false,
+ .has_mba_logs = false,
+ .has_spare_reg = false,
+ .has_qaccept_regs = false,
+ .has_ext_cntl_regs = false,
+ .has_vq6 = false,
+ .version = MSS_MSM8953,
+};
+
static const struct rproc_hexagon_res msm8974_mss = {
.hexagon_mba_image = "mba.b00",
.proxy_supply = (struct qcom_mss_reg_res[]) {
@@ -2340,7 +2467,9 @@ static const struct rproc_hexagon_res msm8974_mss = {
static const struct of_device_id q6v5_of_match[] = {
{ .compatible = "qcom,q6v5-pil", .data = &msm8916_mss},
+ { .compatible = "qcom,msm8909-mss-pil", .data = &msm8909_mss},
{ .compatible = "qcom,msm8916-mss-pil", .data = &msm8916_mss},
+ { .compatible = "qcom,msm8953-mss-pil", .data = &msm8953_mss},
{ .compatible = "qcom,msm8974-mss-pil", .data = &msm8974_mss},
{ .compatible = "qcom,msm8996-mss-pil", .data = &msm8996_mss},
{ .compatible = "qcom,msm8998-mss-pil", .data = &msm8998_mss},
diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c
index dc6f07ca8341..0871108fb4dc 100644
--- a/drivers/remoteproc/qcom_q6v5_pas.c
+++ b/drivers/remoteproc/qcom_q6v5_pas.c
@@ -18,7 +18,7 @@
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/regulator/consumer.h>
#include <linux/remoteproc.h>
#include <linux/soc/qcom/mdt_loader.h>
@@ -35,9 +35,10 @@
struct adsp_data {
int crash_reason_smem;
const char *firmware_name;
+ const char *dtb_firmware_name;
int pas_id;
+ int dtb_pas_id;
unsigned int minidump_id;
- bool has_aggre2_clk;
bool auto_boot;
bool decrypt_shutdown;
@@ -47,6 +48,8 @@ struct adsp_data {
const char *ssr_name;
const char *sysmon_name;
int ssctl_id;
+
+ int region_assign_idx;
};
struct qcom_adsp {
@@ -65,20 +68,33 @@ struct qcom_adsp {
int proxy_pd_count;
+ const char *dtb_firmware_name;
int pas_id;
+ int dtb_pas_id;
unsigned int minidump_id;
int crash_reason_smem;
- bool has_aggre2_clk;
bool decrypt_shutdown;
const char *info_name;
+ const struct firmware *firmware;
+ const struct firmware *dtb_firmware;
+
struct completion start_done;
struct completion stop_done;
phys_addr_t mem_phys;
+ phys_addr_t dtb_mem_phys;
phys_addr_t mem_reloc;
+ phys_addr_t dtb_mem_reloc;
+ phys_addr_t region_assign_phys;
void *mem_region;
+ void *dtb_mem_region;
size_t mem_size;
+ size_t dtb_mem_size;
+ size_t region_assign_size;
+
+ int region_assign_idx;
+ int region_assign_perms;
struct qcom_rproc_glink glink_subdev;
struct qcom_rproc_subdev smd_subdev;
@@ -86,8 +102,27 @@ struct qcom_adsp {
struct qcom_sysmon *sysmon;
struct qcom_scm_pas_metadata pas_metadata;
+ struct qcom_scm_pas_metadata dtb_pas_metadata;
};
+void adsp_segment_dump(struct rproc *rproc, struct rproc_dump_segment *segment,
+ void *dest, size_t offset, size_t size)
+{
+ struct qcom_adsp *adsp = rproc->priv;
+ int total_offset;
+
+ total_offset = segment->da + segment->offset + offset - adsp->mem_phys;
+ if (total_offset < 0 || total_offset + size > adsp->mem_size) {
+ dev_err(adsp->dev,
+ "invalid copy request for segment %pad with offset %zu and size %zu)\n",
+ &segment->da, offset, size);
+ memset(dest, 0xff, size);
+ return;
+ }
+
+ memcpy_fromio(dest, adsp->mem_region + total_offset, size);
+}
+
static void adsp_minidump(struct rproc *rproc)
{
struct qcom_adsp *adsp = rproc->priv;
@@ -95,7 +130,7 @@ static void adsp_minidump(struct rproc *rproc)
if (rproc->dump_conf == RPROC_COREDUMP_DISABLED)
return;
- qcom_minidump(rproc, adsp->minidump_id);
+ qcom_minidump(rproc, adsp->minidump_id, adsp_segment_dump);
}
static int adsp_pds_enable(struct qcom_adsp *adsp, struct device **pds,
@@ -160,6 +195,8 @@ static int adsp_unprepare(struct rproc *rproc)
* here.
*/
qcom_scm_pas_metadata_release(&adsp->pas_metadata);
+ if (adsp->dtb_pas_id)
+ qcom_scm_pas_metadata_release(&adsp->dtb_pas_metadata);
return 0;
}
@@ -169,20 +206,40 @@ static int adsp_load(struct rproc *rproc, const struct firmware *fw)
struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
int ret;
- ret = qcom_mdt_pas_init(adsp->dev, fw, rproc->firmware, adsp->pas_id,
- adsp->mem_phys, &adsp->pas_metadata);
- if (ret)
- return ret;
+ /* Store firmware handle to be used in adsp_start() */
+ adsp->firmware = fw;
- ret = qcom_mdt_load_no_init(adsp->dev, fw, rproc->firmware, adsp->pas_id,
- adsp->mem_region, adsp->mem_phys, adsp->mem_size,
- &adsp->mem_reloc);
- if (ret)
- return ret;
+ if (adsp->dtb_pas_id) {
+ ret = request_firmware(&adsp->dtb_firmware, adsp->dtb_firmware_name, adsp->dev);
+ if (ret) {
+ dev_err(adsp->dev, "request_firmware failed for %s: %d\n",
+ adsp->dtb_firmware_name, ret);
+ return ret;
+ }
- qcom_pil_info_store(adsp->info_name, adsp->mem_phys, adsp->mem_size);
+ ret = qcom_mdt_pas_init(adsp->dev, adsp->dtb_firmware, adsp->dtb_firmware_name,
+ adsp->dtb_pas_id, adsp->dtb_mem_phys,
+ &adsp->dtb_pas_metadata);
+ if (ret)
+ goto release_dtb_firmware;
+
+ ret = qcom_mdt_load_no_init(adsp->dev, adsp->dtb_firmware, adsp->dtb_firmware_name,
+ adsp->dtb_pas_id, adsp->dtb_mem_region,
+ adsp->dtb_mem_phys, adsp->dtb_mem_size,
+ &adsp->dtb_mem_reloc);
+ if (ret)
+ goto release_dtb_metadata;
+ }
return 0;
+
+release_dtb_metadata:
+ qcom_scm_pas_metadata_release(&adsp->dtb_pas_metadata);
+
+release_dtb_firmware:
+ release_firmware(adsp->dtb_firmware);
+
+ return ret;
}
static int adsp_start(struct rproc *rproc)
@@ -218,24 +275,55 @@ static int adsp_start(struct rproc *rproc)
goto disable_cx_supply;
}
+ if (adsp->dtb_pas_id) {
+ ret = qcom_scm_pas_auth_and_reset(adsp->dtb_pas_id);
+ if (ret) {
+ dev_err(adsp->dev,
+ "failed to authenticate dtb image and release reset\n");
+ goto disable_px_supply;
+ }
+ }
+
+ ret = qcom_mdt_pas_init(adsp->dev, adsp->firmware, rproc->firmware, adsp->pas_id,
+ adsp->mem_phys, &adsp->pas_metadata);
+ if (ret)
+ goto disable_px_supply;
+
+ ret = qcom_mdt_load_no_init(adsp->dev, adsp->firmware, rproc->firmware, adsp->pas_id,
+ adsp->mem_region, adsp->mem_phys, adsp->mem_size,
+ &adsp->mem_reloc);
+ if (ret)
+ goto release_pas_metadata;
+
+ qcom_pil_info_store(adsp->info_name, adsp->mem_phys, adsp->mem_size);
+
ret = qcom_scm_pas_auth_and_reset(adsp->pas_id);
if (ret) {
dev_err(adsp->dev,
"failed to authenticate image and release reset\n");
- goto disable_px_supply;
+ goto release_pas_metadata;
}
ret = qcom_q6v5_wait_for_start(&adsp->q6v5, msecs_to_jiffies(5000));
if (ret == -ETIMEDOUT) {
dev_err(adsp->dev, "start timed out\n");
qcom_scm_pas_shutdown(adsp->pas_id);
- goto disable_px_supply;
+ goto release_pas_metadata;
}
qcom_scm_pas_metadata_release(&adsp->pas_metadata);
+ if (adsp->dtb_pas_id)
+ qcom_scm_pas_metadata_release(&adsp->dtb_pas_metadata);
+
+ /* Remove pointer to the loaded firmware, only valid in adsp_load() & adsp_start() */
+ adsp->firmware = NULL;
return 0;
+release_pas_metadata:
+ qcom_scm_pas_metadata_release(&adsp->pas_metadata);
+ if (adsp->dtb_pas_id)
+ qcom_scm_pas_metadata_release(&adsp->dtb_pas_metadata);
disable_px_supply:
if (adsp->px_supply)
regulator_disable(adsp->px_supply);
@@ -251,6 +339,9 @@ disable_proxy_pds:
disable_irqs:
qcom_q6v5_unprepare(&adsp->q6v5);
+ /* Remove pointer to the loaded firmware, only valid in adsp_load() & adsp_start() */
+ adsp->firmware = NULL;
+
return ret;
}
@@ -284,6 +375,12 @@ static int adsp_stop(struct rproc *rproc)
if (ret)
dev_err(adsp->dev, "failed to shutdown: %d\n", ret);
+ if (adsp->dtb_pas_id) {
+ ret = qcom_scm_pas_shutdown(adsp->dtb_pas_id);
+ if (ret)
+ dev_err(adsp->dev, "failed to shutdown dtb: %d\n", ret);
+ }
+
handover = qcom_q6v5_unprepare(&adsp->q6v5);
if (handover)
qcom_pas_handover(&adsp->q6v5);
@@ -345,15 +442,13 @@ static int adsp_init_clock(struct qcom_adsp *adsp)
return ret;
}
- if (adsp->has_aggre2_clk) {
- adsp->aggre2_clk = devm_clk_get(adsp->dev, "aggre2");
- if (IS_ERR(adsp->aggre2_clk)) {
- ret = PTR_ERR(adsp->aggre2_clk);
- if (ret != -EPROBE_DEFER)
- dev_err(adsp->dev,
- "failed to get aggre2 clock");
- return ret;
- }
+ adsp->aggre2_clk = devm_clk_get_optional(adsp->dev, "aggre2");
+ if (IS_ERR(adsp->aggre2_clk)) {
+ ret = PTR_ERR(adsp->aggre2_clk);
+ if (ret != -EPROBE_DEFER)
+ dev_err(adsp->dev,
+ "failed to get aggre2 clock");
+ return ret;
}
return 0;
@@ -462,15 +557,95 @@ static int adsp_alloc_memory_region(struct qcom_adsp *adsp)
return -EBUSY;
}
+ if (!adsp->dtb_pas_id)
+ return 0;
+
+ node = of_parse_phandle(adsp->dev->of_node, "memory-region", 1);
+ if (!node) {
+ dev_err(adsp->dev, "no dtb memory-region specified\n");
+ return -EINVAL;
+ }
+
+ ret = of_address_to_resource(node, 0, &r);
+ if (ret)
+ return ret;
+
+ adsp->dtb_mem_phys = adsp->dtb_mem_reloc = r.start;
+ adsp->dtb_mem_size = resource_size(&r);
+ adsp->dtb_mem_region = devm_ioremap_wc(adsp->dev, adsp->dtb_mem_phys, adsp->dtb_mem_size);
+ if (!adsp->dtb_mem_region) {
+ dev_err(adsp->dev, "unable to map dtb memory region: %pa+%zx\n",
+ &r.start, adsp->dtb_mem_size);
+ return -EBUSY;
+ }
+
return 0;
}
+static int adsp_assign_memory_region(struct qcom_adsp *adsp)
+{
+ struct qcom_scm_vmperm perm;
+ struct device_node *node;
+ struct resource r;
+ int ret;
+
+ if (!adsp->region_assign_idx)
+ return 0;
+
+ node = of_parse_phandle(adsp->dev->of_node, "memory-region", adsp->region_assign_idx);
+ if (!node) {
+ dev_err(adsp->dev, "missing shareable memory-region\n");
+ return -EINVAL;
+ }
+
+ ret = of_address_to_resource(node, 0, &r);
+ if (ret)
+ return ret;
+
+ perm.vmid = QCOM_SCM_VMID_MSS_MSA;
+ perm.perm = QCOM_SCM_PERM_RW;
+
+ adsp->region_assign_phys = r.start;
+ adsp->region_assign_size = resource_size(&r);
+ adsp->region_assign_perms = BIT(QCOM_SCM_VMID_HLOS);
+
+ ret = qcom_scm_assign_mem(adsp->region_assign_phys,
+ adsp->region_assign_size,
+ &adsp->region_assign_perms,
+ &perm, 1);
+ if (ret < 0) {
+ dev_err(adsp->dev, "assign memory failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void adsp_unassign_memory_region(struct qcom_adsp *adsp)
+{
+ struct qcom_scm_vmperm perm;
+ int ret;
+
+ if (!adsp->region_assign_idx)
+ return;
+
+ perm.vmid = QCOM_SCM_VMID_HLOS;
+ perm.perm = QCOM_SCM_PERM_RW;
+
+ ret = qcom_scm_assign_mem(adsp->region_assign_phys,
+ adsp->region_assign_size,
+ &adsp->region_assign_perms,
+ &perm, 1);
+ if (ret < 0)
+ dev_err(adsp->dev, "unassign memory failed\n");
+}
+
static int adsp_probe(struct platform_device *pdev)
{
const struct adsp_data *desc;
struct qcom_adsp *adsp;
struct rproc *rproc;
- const char *fw_name;
+ const char *fw_name, *dtb_fw_name = NULL;
const struct rproc_ops *ops = &adsp_ops;
int ret;
@@ -487,6 +662,14 @@ static int adsp_probe(struct platform_device *pdev)
if (ret < 0 && ret != -EINVAL)
return ret;
+ if (desc->dtb_firmware_name) {
+ dtb_fw_name = desc->dtb_firmware_name;
+ ret = of_property_read_string_index(pdev->dev.of_node, "firmware-name", 1,
+ &dtb_fw_name);
+ if (ret < 0 && ret != -EINVAL)
+ return ret;
+ }
+
if (desc->minidump_id)
ops = &adsp_minidump_ops;
@@ -505,9 +688,13 @@ static int adsp_probe(struct platform_device *pdev)
adsp->rproc = rproc;
adsp->minidump_id = desc->minidump_id;
adsp->pas_id = desc->pas_id;
- adsp->has_aggre2_clk = desc->has_aggre2_clk;
adsp->info_name = desc->sysmon_name;
adsp->decrypt_shutdown = desc->decrypt_shutdown;
+ adsp->region_assign_idx = desc->region_assign_idx;
+ if (dtb_fw_name) {
+ adsp->dtb_firmware_name = dtb_fw_name;
+ adsp->dtb_pas_id = desc->dtb_pas_id;
+ }
platform_set_drvdata(pdev, adsp);
ret = device_init_wakeup(adsp->dev, true);
@@ -518,6 +705,10 @@ static int adsp_probe(struct platform_device *pdev)
if (ret)
goto free_rproc;
+ ret = adsp_assign_memory_region(adsp);
+ if (ret)
+ goto free_rproc;
+
ret = adsp_init_clock(adsp);
if (ret)
goto free_rproc;
@@ -539,7 +730,6 @@ static int adsp_probe(struct platform_device *pdev)
qcom_add_glink_subdev(rproc, &adsp->glink_subdev, desc->ssr_name);
qcom_add_smd_subdev(rproc, &adsp->smd_subdev);
- qcom_add_ssr_subdev(rproc, &adsp->ssr_subdev, desc->ssr_name);
adsp->sysmon = qcom_add_sysmon_subdev(rproc,
desc->sysmon_name,
desc->ssctl_id);
@@ -548,6 +738,7 @@ static int adsp_probe(struct platform_device *pdev)
goto detach_proxy_pds;
}
+ qcom_add_ssr_subdev(rproc, &adsp->ssr_subdev, desc->ssr_name);
ret = rproc_add(rproc);
if (ret)
goto detach_proxy_pds;
@@ -570,6 +761,7 @@ static int adsp_remove(struct platform_device *pdev)
rproc_del(adsp->rproc);
qcom_q6v5_deinit(&adsp->q6v5);
+ adsp_unassign_memory_region(adsp);
qcom_remove_glink_subdev(adsp->rproc, &adsp->glink_subdev);
qcom_remove_sysmon_subdev(adsp->sysmon);
qcom_remove_smd_subdev(adsp->rproc, &adsp->smd_subdev);
@@ -585,7 +777,6 @@ static const struct adsp_data adsp_resource_init = {
.crash_reason_smem = 423,
.firmware_name = "adsp.mdt",
.pas_id = 1,
- .has_aggre2_clk = false,
.auto_boot = true,
.ssr_name = "lpass",
.sysmon_name = "adsp",
@@ -596,7 +787,6 @@ static const struct adsp_data sdm845_adsp_resource_init = {
.crash_reason_smem = 423,
.firmware_name = "adsp.mdt",
.pas_id = 1,
- .has_aggre2_clk = false,
.auto_boot = true,
.load_state = "adsp",
.ssr_name = "lpass",
@@ -608,7 +798,6 @@ static const struct adsp_data sm6350_adsp_resource = {
.crash_reason_smem = 423,
.firmware_name = "adsp.mdt",
.pas_id = 1,
- .has_aggre2_clk = false,
.auto_boot = true,
.proxy_pd_names = (char*[]){
"lcx",
@@ -625,7 +814,6 @@ static const struct adsp_data sm8150_adsp_resource = {
.crash_reason_smem = 423,
.firmware_name = "adsp.mdt",
.pas_id = 1,
- .has_aggre2_clk = false,
.auto_boot = true,
.proxy_pd_names = (char*[]){
"cx",
@@ -641,7 +829,6 @@ static const struct adsp_data sm8250_adsp_resource = {
.crash_reason_smem = 423,
.firmware_name = "adsp.mdt",
.pas_id = 1,
- .has_aggre2_clk = false,
.auto_boot = true,
.proxy_pd_names = (char*[]){
"lcx",
@@ -658,7 +845,6 @@ static const struct adsp_data sm8350_adsp_resource = {
.crash_reason_smem = 423,
.firmware_name = "adsp.mdt",
.pas_id = 1,
- .has_aggre2_clk = false,
.auto_boot = true,
.proxy_pd_names = (char*[]){
"lcx",
@@ -675,7 +861,6 @@ static const struct adsp_data msm8996_adsp_resource = {
.crash_reason_smem = 423,
.firmware_name = "adsp.mdt",
.pas_id = 1,
- .has_aggre2_clk = false,
.auto_boot = true,
.proxy_pd_names = (char*[]){
"cx",
@@ -690,7 +875,6 @@ static const struct adsp_data cdsp_resource_init = {
.crash_reason_smem = 601,
.firmware_name = "cdsp.mdt",
.pas_id = 18,
- .has_aggre2_clk = false,
.auto_boot = true,
.ssr_name = "cdsp",
.sysmon_name = "cdsp",
@@ -701,7 +885,6 @@ static const struct adsp_data sdm845_cdsp_resource_init = {
.crash_reason_smem = 601,
.firmware_name = "cdsp.mdt",
.pas_id = 18,
- .has_aggre2_clk = false,
.auto_boot = true,
.load_state = "cdsp",
.ssr_name = "cdsp",
@@ -713,7 +896,6 @@ static const struct adsp_data sm6350_cdsp_resource = {
.crash_reason_smem = 601,
.firmware_name = "cdsp.mdt",
.pas_id = 18,
- .has_aggre2_clk = false,
.auto_boot = true,
.proxy_pd_names = (char*[]){
"cx",
@@ -730,7 +912,6 @@ static const struct adsp_data sm8150_cdsp_resource = {
.crash_reason_smem = 601,
.firmware_name = "cdsp.mdt",
.pas_id = 18,
- .has_aggre2_clk = false,
.auto_boot = true,
.proxy_pd_names = (char*[]){
"cx",
@@ -746,7 +927,6 @@ static const struct adsp_data sm8250_cdsp_resource = {
.crash_reason_smem = 601,
.firmware_name = "cdsp.mdt",
.pas_id = 18,
- .has_aggre2_clk = false,
.auto_boot = true,
.proxy_pd_names = (char*[]){
"cx",
@@ -762,7 +942,6 @@ static const struct adsp_data sc8280xp_nsp0_resource = {
.crash_reason_smem = 601,
.firmware_name = "cdsp.mdt",
.pas_id = 18,
- .has_aggre2_clk = false,
.auto_boot = true,
.proxy_pd_names = (char*[]){
"nsp",
@@ -777,7 +956,6 @@ static const struct adsp_data sc8280xp_nsp1_resource = {
.crash_reason_smem = 633,
.firmware_name = "cdsp.mdt",
.pas_id = 30,
- .has_aggre2_clk = false,
.auto_boot = true,
.proxy_pd_names = (char*[]){
"nsp",
@@ -792,7 +970,6 @@ static const struct adsp_data sm8350_cdsp_resource = {
.crash_reason_smem = 601,
.firmware_name = "cdsp.mdt",
.pas_id = 18,
- .has_aggre2_clk = false,
.auto_boot = true,
.proxy_pd_names = (char*[]){
"cx",
@@ -810,7 +987,6 @@ static const struct adsp_data mpss_resource_init = {
.firmware_name = "modem.mdt",
.pas_id = 4,
.minidump_id = 3,
- .has_aggre2_clk = false,
.auto_boot = false,
.proxy_pd_names = (char*[]){
"cx",
@@ -827,7 +1003,6 @@ static const struct adsp_data sc8180x_mpss_resource = {
.crash_reason_smem = 421,
.firmware_name = "modem.mdt",
.pas_id = 4,
- .has_aggre2_clk = false,
.auto_boot = false,
.proxy_pd_names = (char*[]){
"cx",
@@ -843,7 +1018,6 @@ static const struct adsp_data slpi_resource_init = {
.crash_reason_smem = 424,
.firmware_name = "slpi.mdt",
.pas_id = 12,
- .has_aggre2_clk = true,
.auto_boot = true,
.proxy_pd_names = (char*[]){
"ssc_cx",
@@ -858,7 +1032,6 @@ static const struct adsp_data sm8150_slpi_resource = {
.crash_reason_smem = 424,
.firmware_name = "slpi.mdt",
.pas_id = 12,
- .has_aggre2_clk = false,
.auto_boot = true,
.proxy_pd_names = (char*[]){
"lcx",
@@ -875,7 +1048,6 @@ static const struct adsp_data sm8250_slpi_resource = {
.crash_reason_smem = 424,
.firmware_name = "slpi.mdt",
.pas_id = 12,
- .has_aggre2_clk = false,
.auto_boot = true,
.proxy_pd_names = (char*[]){
"lcx",
@@ -892,7 +1064,6 @@ static const struct adsp_data sm8350_slpi_resource = {
.crash_reason_smem = 424,
.firmware_name = "slpi.mdt",
.pas_id = 12,
- .has_aggre2_clk = false,
.auto_boot = true,
.proxy_pd_names = (char*[]){
"lcx",
@@ -919,7 +1090,6 @@ static const struct adsp_data sdx55_mpss_resource = {
.crash_reason_smem = 421,
.firmware_name = "modem.mdt",
.pas_id = 4,
- .has_aggre2_clk = false,
.auto_boot = true,
.proxy_pd_names = (char*[]){
"cx",
@@ -936,7 +1106,6 @@ static const struct adsp_data sm8450_mpss_resource = {
.firmware_name = "modem.mdt",
.pas_id = 4,
.minidump_id = 3,
- .has_aggre2_clk = false,
.auto_boot = false,
.decrypt_shutdown = true,
.proxy_pd_names = (char*[]){
@@ -950,8 +1119,69 @@ static const struct adsp_data sm8450_mpss_resource = {
.ssctl_id = 0x12,
};
+static const struct adsp_data sm8550_adsp_resource = {
+ .crash_reason_smem = 423,
+ .firmware_name = "adsp.mdt",
+ .dtb_firmware_name = "adsp_dtb.mdt",
+ .pas_id = 1,
+ .dtb_pas_id = 0x24,
+ .minidump_id = 5,
+ .auto_boot = true,
+ .proxy_pd_names = (char*[]){
+ "lcx",
+ "lmx",
+ NULL
+ },
+ .load_state = "adsp",
+ .ssr_name = "lpass",
+ .sysmon_name = "adsp",
+ .ssctl_id = 0x14,
+};
+
+static const struct adsp_data sm8550_cdsp_resource = {
+ .crash_reason_smem = 601,
+ .firmware_name = "cdsp.mdt",
+ .dtb_firmware_name = "cdsp_dtb.mdt",
+ .pas_id = 18,
+ .dtb_pas_id = 0x25,
+ .minidump_id = 7,
+ .auto_boot = true,
+ .proxy_pd_names = (char*[]){
+ "cx",
+ "mxc",
+ "nsp",
+ NULL
+ },
+ .load_state = "cdsp",
+ .ssr_name = "cdsp",
+ .sysmon_name = "cdsp",
+ .ssctl_id = 0x17,
+};
+
+static const struct adsp_data sm8550_mpss_resource = {
+ .crash_reason_smem = 421,
+ .firmware_name = "modem.mdt",
+ .dtb_firmware_name = "modem_dtb.mdt",
+ .pas_id = 4,
+ .dtb_pas_id = 0x26,
+ .minidump_id = 3,
+ .auto_boot = false,
+ .decrypt_shutdown = true,
+ .proxy_pd_names = (char*[]){
+ "cx",
+ "mss",
+ NULL
+ },
+ .load_state = "modem",
+ .ssr_name = "mpss",
+ .sysmon_name = "modem",
+ .ssctl_id = 0x12,
+ .region_assign_idx = 2,
+};
+
static const struct of_device_id adsp_of_match[] = {
{ .compatible = "qcom,msm8226-adsp-pil", .data = &adsp_resource_init},
+ { .compatible = "qcom,msm8953-adsp-pil", .data = &msm8996_adsp_resource},
{ .compatible = "qcom,msm8974-adsp-pil", .data = &adsp_resource_init},
{ .compatible = "qcom,msm8996-adsp-pil", .data = &msm8996_adsp_resource},
{ .compatible = "qcom,msm8996-slpi-pil", .data = &slpi_resource_init},
@@ -972,6 +1202,9 @@ static const struct of_device_id adsp_of_match[] = {
{ .compatible = "qcom,sdm845-adsp-pas", .data = &sdm845_adsp_resource_init},
{ .compatible = "qcom,sdm845-cdsp-pas", .data = &sdm845_cdsp_resource_init},
{ .compatible = "qcom,sdx55-mpss-pas", .data = &sdx55_mpss_resource},
+ { .compatible = "qcom,sm6115-adsp-pas", .data = &adsp_resource_init},
+ { .compatible = "qcom,sm6115-cdsp-pas", .data = &cdsp_resource_init},
+ { .compatible = "qcom,sm6115-mpss-pas", .data = &sc8180x_mpss_resource},
{ .compatible = "qcom,sm6350-adsp-pas", .data = &sm6350_adsp_resource},
{ .compatible = "qcom,sm6350-cdsp-pas", .data = &sm6350_cdsp_resource},
{ .compatible = "qcom,sm6350-mpss-pas", .data = &mpss_resource_init},
@@ -990,6 +1223,9 @@ static const struct of_device_id adsp_of_match[] = {
{ .compatible = "qcom,sm8450-cdsp-pas", .data = &sm8350_cdsp_resource},
{ .compatible = "qcom,sm8450-slpi-pas", .data = &sm8350_slpi_resource},
{ .compatible = "qcom,sm8450-mpss-pas", .data = &sm8450_mpss_resource},
+ { .compatible = "qcom,sm8550-adsp-pas", .data = &sm8550_adsp_resource},
+ { .compatible = "qcom,sm8550-cdsp-pas", .data = &sm8550_cdsp_resource},
+ { .compatible = "qcom,sm8550-mpss-pas", .data = &sm8550_mpss_resource},
{ },
};
MODULE_DEVICE_TABLE(of, adsp_of_match);
diff --git a/drivers/remoteproc/qcom_sysmon.c b/drivers/remoteproc/qcom_sysmon.c
index 85393d5eb005..746f56b4bafb 100644
--- a/drivers/remoteproc/qcom_sysmon.c
+++ b/drivers/remoteproc/qcom_sysmon.c
@@ -388,7 +388,7 @@ static void ssctl_send_event(struct qcom_sysmon *sysmon,
}
memset(&req, 0, sizeof(req));
- strlcpy(req.subsys_name, event->subsys_name, sizeof(req.subsys_name));
+ strscpy(req.subsys_name, event->subsys_name, sizeof(req.subsys_name));
req.subsys_name_len = strlen(req.subsys_name);
req.event = event->ssr_event;
req.evt_driven_valid = true;
diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
index 68f37296b151..9d4d04fff8c6 100644
--- a/drivers/remoteproc/qcom_wcnss.c
+++ b/drivers/remoteproc/qcom_wcnss.c
@@ -19,7 +19,7 @@
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/regulator/consumer.h>
#include <linux/remoteproc.h>
#include <linux/soc/qcom/mdt_loader.h>
@@ -141,6 +141,17 @@ static const struct wcnss_data pronto_v2_data = {
.num_vregs = 1,
};
+static const struct wcnss_data pronto_v3_data = {
+ .pmu_offset = 0x1004,
+ .spare_offset = 0x1088,
+
+ .pd_names = { "mx", "cx" },
+ .vregs = (struct wcnss_vreg_info[]) {
+ { "vddpx", 1800000, 1800000, 0 },
+ },
+ .num_vregs = 1,
+};
+
static int wcnss_load(struct rproc *rproc, const struct firmware *fw)
{
struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
@@ -675,6 +686,7 @@ static const struct of_device_id wcnss_of_match[] = {
{ .compatible = "qcom,riva-pil", &riva_data },
{ .compatible = "qcom,pronto-v1-pil", &pronto_v1_data },
{ .compatible = "qcom,pronto-v2-pil", &pronto_v2_data },
+ { .compatible = "qcom,pronto-v3-pil", &pronto_v3_data },
{ },
};
MODULE_DEVICE_TABLE(of, wcnss_of_match);
diff --git a/drivers/remoteproc/qcom_wcnss.h b/drivers/remoteproc/qcom_wcnss.h
index 6d01ee6afa7f..cb4ce543e68f 100644
--- a/drivers/remoteproc/qcom_wcnss.h
+++ b/drivers/remoteproc/qcom_wcnss.h
@@ -5,8 +5,6 @@
struct qcom_iris;
struct qcom_wcnss;
-extern struct platform_driver qcom_iris_driver;
-
struct wcnss_vreg_info {
const char * const name;
int min_voltage;
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 1cd4815a6dd1..80072b6b6283 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -643,7 +643,8 @@ static int rproc_handle_devmem(struct rproc *rproc, void *ptr,
if (!mapping)
return -ENOMEM;
- ret = iommu_map(rproc->domain, rsc->da, rsc->pa, rsc->len, rsc->flags);
+ ret = iommu_map(rproc->domain, rsc->da, rsc->pa, rsc->len, rsc->flags,
+ GFP_KERNEL);
if (ret) {
dev_err(dev, "failed to map devmem: %d\n", ret);
goto out;
@@ -737,7 +738,7 @@ static int rproc_alloc_carveout(struct rproc *rproc,
}
ret = iommu_map(rproc->domain, mem->da, dma, mem->len,
- mem->flags);
+ mem->flags, GFP_KERNEL);
if (ret) {
dev_err(dev, "iommu_map failed: %d\n", ret);
goto free_mapping;
diff --git a/drivers/remoteproc/ti_k3_dsp_remoteproc.c b/drivers/remoteproc/ti_k3_dsp_remoteproc.c
index eb9c64f7b9b4..ec626a37fef6 100644
--- a/drivers/remoteproc/ti_k3_dsp_remoteproc.c
+++ b/drivers/remoteproc/ti_k3_dsp_remoteproc.c
@@ -870,6 +870,10 @@ static const struct k3_dsp_mem_data c71_mems[] = {
{ .name = "l1dram", .dev_addr = 0xe00000 },
};
+static const struct k3_dsp_mem_data c7xv_mems[] = {
+ { .name = "l2sram", .dev_addr = 0x800000 },
+};
+
static const struct k3_dsp_dev_data c66_data = {
.mems = c66_mems,
.num_mems = ARRAY_SIZE(c66_mems),
@@ -884,10 +888,18 @@ static const struct k3_dsp_dev_data c71_data = {
.uses_lreset = false,
};
+static const struct k3_dsp_dev_data c7xv_data = {
+ .mems = c7xv_mems,
+ .num_mems = ARRAY_SIZE(c7xv_mems),
+ .boot_align_addr = SZ_2M,
+ .uses_lreset = false,
+};
+
static const struct of_device_id k3_dsp_of_match[] = {
{ .compatible = "ti,j721e-c66-dsp", .data = &c66_data, },
{ .compatible = "ti,j721e-c71-dsp", .data = &c71_data, },
{ .compatible = "ti,j721s2-c71-dsp", .data = &c71_data, },
+ { .compatible = "ti,am62a-c7xv-dsp", .data = &c7xv_data, },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, k3_dsp_of_match);
diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
index 115c0a1eddb1..01d2805fe30f 100644
--- a/drivers/rpmsg/qcom_glink_native.c
+++ b/drivers/rpmsg/qcom_glink_native.c
@@ -11,7 +11,6 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/rpmsg.h>
@@ -78,11 +77,8 @@ struct glink_core_rx_intent {
/**
* struct qcom_glink - driver context, relates to one remote subsystem
* @dev: reference to the associated struct device
- * @mbox_client: mailbox client
- * @mbox_chan: mailbox channel
* @rx_pipe: pipe object for receive FIFO
* @tx_pipe: pipe object for transmit FIFO
- * @irq: IRQ for signaling incoming events
* @rx_work: worker for handling received control messages
* @rx_lock: protects the @rx_queue
* @rx_queue: queue of received control messages to be processed in @rx_work
@@ -94,18 +90,14 @@ struct glink_core_rx_intent {
* @intentless: flag to indicate that there is no intent
* @tx_avail_notify: Waitqueue for pending tx tasks
* @sent_read_notify: flag to check cmd sent or not
+ * @abort_tx: flag indicating that all tx attempts should fail
*/
struct qcom_glink {
struct device *dev;
- struct mbox_client mbox_client;
- struct mbox_chan *mbox_chan;
-
struct qcom_glink_pipe *rx_pipe;
struct qcom_glink_pipe *tx_pipe;
- int irq;
-
struct work_struct rx_work;
spinlock_t rx_lock;
struct list_head rx_queue;
@@ -120,6 +112,8 @@ struct qcom_glink {
bool intentless;
wait_queue_head_t tx_avail_notify;
bool sent_read_notify;
+
+ bool abort_tx;
};
enum {
@@ -189,20 +183,20 @@ struct glink_channel {
static const struct rpmsg_endpoint_ops glink_endpoint_ops;
-#define RPM_CMD_VERSION 0
-#define RPM_CMD_VERSION_ACK 1
-#define RPM_CMD_OPEN 2
-#define RPM_CMD_CLOSE 3
-#define RPM_CMD_OPEN_ACK 4
-#define RPM_CMD_INTENT 5
-#define RPM_CMD_RX_DONE 6
-#define RPM_CMD_RX_INTENT_REQ 7
-#define RPM_CMD_RX_INTENT_REQ_ACK 8
-#define RPM_CMD_TX_DATA 9
-#define RPM_CMD_CLOSE_ACK 11
-#define RPM_CMD_TX_DATA_CONT 12
-#define RPM_CMD_READ_NOTIF 13
-#define RPM_CMD_RX_DONE_W_REUSE 14
+#define GLINK_CMD_VERSION 0
+#define GLINK_CMD_VERSION_ACK 1
+#define GLINK_CMD_OPEN 2
+#define GLINK_CMD_CLOSE 3
+#define GLINK_CMD_OPEN_ACK 4
+#define GLINK_CMD_INTENT 5
+#define GLINK_CMD_RX_DONE 6
+#define GLINK_CMD_RX_INTENT_REQ 7
+#define GLINK_CMD_RX_INTENT_REQ_ACK 8
+#define GLINK_CMD_TX_DATA 9
+#define GLINK_CMD_CLOSE_ACK 11
+#define GLINK_CMD_TX_DATA_CONT 12
+#define GLINK_CMD_READ_NOTIF 13
+#define GLINK_CMD_RX_DONE_W_REUSE 14
#define GLINK_FEATURE_INTENTLESS BIT(1)
@@ -280,10 +274,10 @@ static size_t qcom_glink_rx_avail(struct qcom_glink *glink)
return glink->rx_pipe->avail(glink->rx_pipe);
}
-static void qcom_glink_rx_peak(struct qcom_glink *glink,
+static void qcom_glink_rx_peek(struct qcom_glink *glink,
void *data, unsigned int offset, size_t count)
{
- glink->rx_pipe->peak(glink->rx_pipe, data, offset, count);
+ glink->rx_pipe->peek(glink->rx_pipe, data, offset, count);
}
static void qcom_glink_rx_advance(struct qcom_glink *glink, size_t count)
@@ -303,18 +297,22 @@ static void qcom_glink_tx_write(struct qcom_glink *glink,
glink->tx_pipe->write(glink->tx_pipe, hdr, hlen, data, dlen);
}
+static void qcom_glink_tx_kick(struct qcom_glink *glink)
+{
+ glink->tx_pipe->kick(glink->tx_pipe);
+}
+
static void qcom_glink_send_read_notify(struct qcom_glink *glink)
{
struct glink_msg msg;
- msg.cmd = cpu_to_le16(RPM_CMD_READ_NOTIF);
+ msg.cmd = cpu_to_le16(GLINK_CMD_READ_NOTIF);
msg.param1 = 0;
msg.param2 = 0;
qcom_glink_tx_write(glink, &msg, sizeof(msg), NULL, 0);
- mbox_send_message(glink->mbox_chan, NULL);
- mbox_client_txdone(glink->mbox_chan, 0);
+ qcom_glink_tx_kick(glink);
}
static int qcom_glink_tx(struct qcom_glink *glink,
@@ -331,12 +329,22 @@ static int qcom_glink_tx(struct qcom_glink *glink,
spin_lock_irqsave(&glink->tx_lock, flags);
+ if (glink->abort_tx) {
+ ret = -EIO;
+ goto out;
+ }
+
while (qcom_glink_tx_avail(glink) < tlen) {
if (!wait) {
ret = -EAGAIN;
goto out;
}
+ if (glink->abort_tx) {
+ ret = -EIO;
+ goto out;
+ }
+
if (!glink->sent_read_notify) {
glink->sent_read_notify = true;
qcom_glink_send_read_notify(glink);
@@ -355,9 +363,7 @@ static int qcom_glink_tx(struct qcom_glink *glink,
}
qcom_glink_tx_write(glink, hdr, hlen, data, dlen);
-
- mbox_send_message(glink->mbox_chan, NULL);
- mbox_client_txdone(glink->mbox_chan, 0);
+ qcom_glink_tx_kick(glink);
out:
spin_unlock_irqrestore(&glink->tx_lock, flags);
@@ -369,7 +375,7 @@ static int qcom_glink_send_version(struct qcom_glink *glink)
{
struct glink_msg msg;
- msg.cmd = cpu_to_le16(RPM_CMD_VERSION);
+ msg.cmd = cpu_to_le16(GLINK_CMD_VERSION);
msg.param1 = cpu_to_le16(GLINK_VERSION_1);
msg.param2 = cpu_to_le32(glink->features);
@@ -380,7 +386,7 @@ static void qcom_glink_send_version_ack(struct qcom_glink *glink)
{
struct glink_msg msg;
- msg.cmd = cpu_to_le16(RPM_CMD_VERSION_ACK);
+ msg.cmd = cpu_to_le16(GLINK_CMD_VERSION_ACK);
msg.param1 = cpu_to_le16(GLINK_VERSION_1);
msg.param2 = cpu_to_le32(glink->features);
@@ -392,7 +398,7 @@ static void qcom_glink_send_open_ack(struct qcom_glink *glink,
{
struct glink_msg msg;
- msg.cmd = cpu_to_le16(RPM_CMD_OPEN_ACK);
+ msg.cmd = cpu_to_le16(GLINK_CMD_OPEN_ACK);
msg.param1 = cpu_to_le16(channel->rcid);
msg.param2 = cpu_to_le32(0);
@@ -417,12 +423,18 @@ static void qcom_glink_handle_intent_req_ack(struct qcom_glink *glink,
complete(&channel->intent_req_comp);
}
+static void qcom_glink_intent_req_abort(struct glink_channel *channel)
+{
+ channel->intent_req_result = 0;
+ complete(&channel->intent_req_comp);
+}
+
/**
- * qcom_glink_send_open_req() - send a RPM_CMD_OPEN request to the remote
+ * qcom_glink_send_open_req() - send a GLINK_CMD_OPEN request to the remote
* @glink: Ptr to the glink edge
* @channel: Ptr to the channel that the open req is sent
*
- * Allocates a local channel id and sends a RPM_CMD_OPEN message to the remote.
+ * Allocates a local channel id and sends a GLINK_CMD_OPEN message to the remote.
* Will return with refcount held, regardless of outcome.
*
* Return: 0 on success, negative errno otherwise.
@@ -451,7 +463,7 @@ static int qcom_glink_send_open_req(struct qcom_glink *glink,
channel->lcid = ret;
- req.msg.cmd = cpu_to_le16(RPM_CMD_OPEN);
+ req.msg.cmd = cpu_to_le16(GLINK_CMD_OPEN);
req.msg.param1 = cpu_to_le16(channel->lcid);
req.msg.param2 = cpu_to_le32(name_len);
strcpy(req.name, channel->name);
@@ -476,7 +488,7 @@ static void qcom_glink_send_close_req(struct qcom_glink *glink,
{
struct glink_msg req;
- req.cmd = cpu_to_le16(RPM_CMD_CLOSE);
+ req.cmd = cpu_to_le16(GLINK_CMD_CLOSE);
req.param1 = cpu_to_le16(channel->lcid);
req.param2 = 0;
@@ -488,7 +500,7 @@ static void qcom_glink_send_close_ack(struct qcom_glink *glink,
{
struct glink_msg req;
- req.cmd = cpu_to_le16(RPM_CMD_CLOSE_ACK);
+ req.cmd = cpu_to_le16(GLINK_CMD_CLOSE_ACK);
req.param1 = cpu_to_le16(rcid);
req.param2 = 0;
@@ -519,7 +531,7 @@ static void qcom_glink_rx_done_work(struct work_struct *work)
iid = intent->id;
reuse = intent->reuse;
- cmd.id = reuse ? RPM_CMD_RX_DONE_W_REUSE : RPM_CMD_RX_DONE;
+ cmd.id = reuse ? GLINK_CMD_RX_DONE_W_REUSE : GLINK_CMD_RX_DONE;
cmd.lcid = cid;
cmd.liid = iid;
@@ -631,7 +643,7 @@ static int qcom_glink_send_intent_req_ack(struct qcom_glink *glink,
{
struct glink_msg msg;
- msg.cmd = cpu_to_le16(RPM_CMD_RX_INTENT_REQ_ACK);
+ msg.cmd = cpu_to_le16(GLINK_CMD_RX_INTENT_REQ_ACK);
msg.param1 = cpu_to_le16(channel->lcid);
msg.param2 = cpu_to_le32(granted);
@@ -662,7 +674,7 @@ static int qcom_glink_advertise_intent(struct qcom_glink *glink,
} __packed;
struct command cmd;
- cmd.id = cpu_to_le16(RPM_CMD_INTENT);
+ cmd.id = cpu_to_le16(GLINK_CMD_INTENT);
cmd.lcid = cpu_to_le16(channel->lcid);
cmd.count = cpu_to_le32(1);
cmd.size = cpu_to_le32(intent->size);
@@ -796,7 +808,7 @@ static int qcom_glink_rx_defer(struct qcom_glink *glink, size_t extra)
INIT_LIST_HEAD(&dcmd->node);
- qcom_glink_rx_peak(glink, &dcmd->msg, 0, sizeof(dcmd->msg) + extra);
+ qcom_glink_rx_peek(glink, &dcmd->msg, 0, sizeof(dcmd->msg) + extra);
spin_lock(&glink->rx_lock);
list_add_tail(&dcmd->node, &glink->rx_queue);
@@ -829,7 +841,7 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
return -EAGAIN;
}
- qcom_glink_rx_peak(glink, &hdr, 0, sizeof(hdr));
+ qcom_glink_rx_peek(glink, &hdr, 0, sizeof(hdr));
chunk_size = le32_to_cpu(hdr.chunk_size);
left_size = le32_to_cpu(hdr.left_size);
@@ -894,7 +906,7 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
goto advance_rx;
}
- qcom_glink_rx_peak(glink, intent->data + intent->offset,
+ qcom_glink_rx_peek(glink, intent->data + intent->offset,
sizeof(hdr), chunk_size);
intent->offset += chunk_size;
@@ -954,6 +966,7 @@ static void qcom_glink_handle_intent(struct qcom_glink *glink,
spin_unlock_irqrestore(&glink->idr_lock, flags);
if (!channel) {
dev_err(glink->dev, "intents for non-existing channel\n");
+ qcom_glink_rx_advance(glink, ALIGN(msglen, 8));
return;
}
@@ -961,7 +974,7 @@ static void qcom_glink_handle_intent(struct qcom_glink *glink,
if (!msg)
return;
- qcom_glink_rx_peak(glink, msg, 0, msglen);
+ qcom_glink_rx_peek(glink, msg, 0, msglen);
for (i = 0; i < count; ++i) {
intent = kzalloc(sizeof(*intent), GFP_ATOMIC);
@@ -1001,9 +1014,8 @@ static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid)
return 0;
}
-static irqreturn_t qcom_glink_native_intr(int irq, void *data)
+void qcom_glink_native_rx(struct qcom_glink *glink)
{
- struct qcom_glink *glink = data;
struct glink_msg msg;
unsigned int param1;
unsigned int param2;
@@ -1019,49 +1031,47 @@ static irqreturn_t qcom_glink_native_intr(int irq, void *data)
if (avail < sizeof(msg))
break;
- qcom_glink_rx_peak(glink, &msg, 0, sizeof(msg));
+ qcom_glink_rx_peek(glink, &msg, 0, sizeof(msg));
cmd = le16_to_cpu(msg.cmd);
param1 = le16_to_cpu(msg.param1);
param2 = le32_to_cpu(msg.param2);
switch (cmd) {
- case RPM_CMD_VERSION:
- case RPM_CMD_VERSION_ACK:
- case RPM_CMD_CLOSE:
- case RPM_CMD_CLOSE_ACK:
- case RPM_CMD_RX_INTENT_REQ:
+ case GLINK_CMD_VERSION:
+ case GLINK_CMD_VERSION_ACK:
+ case GLINK_CMD_CLOSE:
+ case GLINK_CMD_CLOSE_ACK:
+ case GLINK_CMD_RX_INTENT_REQ:
ret = qcom_glink_rx_defer(glink, 0);
break;
- case RPM_CMD_OPEN_ACK:
+ case GLINK_CMD_OPEN_ACK:
ret = qcom_glink_rx_open_ack(glink, param1);
qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
break;
- case RPM_CMD_OPEN:
+ case GLINK_CMD_OPEN:
ret = qcom_glink_rx_defer(glink, param2);
break;
- case RPM_CMD_TX_DATA:
- case RPM_CMD_TX_DATA_CONT:
+ case GLINK_CMD_TX_DATA:
+ case GLINK_CMD_TX_DATA_CONT:
ret = qcom_glink_rx_data(glink, avail);
break;
- case RPM_CMD_READ_NOTIF:
+ case GLINK_CMD_READ_NOTIF:
qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
-
- mbox_send_message(glink->mbox_chan, NULL);
- mbox_client_txdone(glink->mbox_chan, 0);
+ qcom_glink_tx_kick(glink);
break;
- case RPM_CMD_INTENT:
+ case GLINK_CMD_INTENT:
qcom_glink_handle_intent(glink, param1, param2, avail);
break;
- case RPM_CMD_RX_DONE:
+ case GLINK_CMD_RX_DONE:
qcom_glink_handle_rx_done(glink, param1, param2, false);
qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
break;
- case RPM_CMD_RX_DONE_W_REUSE:
+ case GLINK_CMD_RX_DONE_W_REUSE:
qcom_glink_handle_rx_done(glink, param1, param2, true);
qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
break;
- case RPM_CMD_RX_INTENT_REQ_ACK:
+ case GLINK_CMD_RX_INTENT_REQ_ACK:
qcom_glink_handle_intent_req_ack(glink, param1, param2);
qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
break;
@@ -1074,9 +1084,8 @@ static irqreturn_t qcom_glink_native_intr(int irq, void *data)
if (ret)
break;
}
-
- return IRQ_HANDLED;
}
+EXPORT_SYMBOL(qcom_glink_native_rx);
/* Locally initiated rpmsg_create_ept */
static struct glink_channel *qcom_glink_create_local(struct qcom_glink *glink,
@@ -1264,7 +1273,7 @@ static int qcom_glink_request_intent(struct qcom_glink *glink,
reinit_completion(&channel->intent_req_comp);
- cmd.id = RPM_CMD_RX_INTENT_REQ;
+ cmd.id = GLINK_CMD_RX_INTENT_REQ;
cmd.cid = channel->lcid;
cmd.size = size;
@@ -1338,7 +1347,7 @@ static int __qcom_glink_send(struct glink_channel *channel,
chunk_size = SZ_8K;
left_size = len - chunk_size;
}
- req.msg.cmd = cpu_to_le16(RPM_CMD_TX_DATA);
+ req.msg.cmd = cpu_to_le16(GLINK_CMD_TX_DATA);
req.msg.param1 = cpu_to_le16(channel->lcid);
req.msg.param2 = cpu_to_le32(iid);
req.chunk_size = cpu_to_le32(chunk_size);
@@ -1359,7 +1368,7 @@ static int __qcom_glink_send(struct glink_channel *channel,
chunk_size = SZ_8K;
left_size -= chunk_size;
- req.msg.cmd = cpu_to_le16(RPM_CMD_TX_DATA_CONT);
+ req.msg.cmd = cpu_to_le16(GLINK_CMD_TX_DATA_CONT);
req.msg.param1 = cpu_to_le16(channel->lcid);
req.msg.param2 = cpu_to_le32(iid);
req.chunk_size = cpu_to_le32(chunk_size);
@@ -1446,6 +1455,7 @@ static void qcom_glink_rpdev_release(struct device *dev)
{
struct rpmsg_device *rpdev = to_rpmsg_device(dev);
+ kfree(rpdev->driver_override);
kfree(rpdev);
}
@@ -1623,22 +1633,22 @@ static void qcom_glink_work(struct work_struct *work)
param2 = le32_to_cpu(msg->param2);
switch (cmd) {
- case RPM_CMD_VERSION:
+ case GLINK_CMD_VERSION:
qcom_glink_receive_version(glink, param1, param2);
break;
- case RPM_CMD_VERSION_ACK:
+ case GLINK_CMD_VERSION_ACK:
qcom_glink_receive_version_ack(glink, param1, param2);
break;
- case RPM_CMD_OPEN:
+ case GLINK_CMD_OPEN:
qcom_glink_rx_open(glink, param1, msg->data);
break;
- case RPM_CMD_CLOSE:
+ case GLINK_CMD_CLOSE:
qcom_glink_rx_close(glink, param1);
break;
- case RPM_CMD_CLOSE_ACK:
+ case GLINK_CMD_CLOSE_ACK:
qcom_glink_rx_close_ack(glink, param1);
break;
- case RPM_CMD_RX_INTENT_REQ:
+ case GLINK_CMD_RX_INTENT_REQ:
qcom_glink_handle_intent_req(glink, param1, param2);
break;
default:
@@ -1689,6 +1699,7 @@ static void qcom_glink_device_release(struct device *dev)
/* Release qcom_glink_alloc_channel() reference */
kref_put(&channel->refcount, qcom_glink_channel_release);
+ kfree(rpdev->driver_override);
kfree(rpdev);
}
@@ -1722,7 +1733,6 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev,
struct qcom_glink_pipe *tx,
bool intentless)
{
- int irq;
int ret;
struct qcom_glink *glink;
@@ -1753,27 +1763,6 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev,
if (ret)
dev_err(dev, "failed to add groups\n");
- glink->mbox_client.dev = dev;
- glink->mbox_client.knows_txdone = true;
- glink->mbox_chan = mbox_request_channel(&glink->mbox_client, 0);
- if (IS_ERR(glink->mbox_chan)) {
- if (PTR_ERR(glink->mbox_chan) != -EPROBE_DEFER)
- dev_err(dev, "failed to acquire IPC channel\n");
- return ERR_CAST(glink->mbox_chan);
- }
-
- irq = of_irq_get(dev->of_node, 0);
- ret = devm_request_irq(dev, irq,
- qcom_glink_native_intr,
- IRQF_NO_SUSPEND | IRQF_SHARED,
- "glink-native", glink);
- if (ret) {
- dev_err(dev, "failed to request IRQ\n");
- return ERR_PTR(ret);
- }
-
- glink->irq = irq;
-
ret = qcom_glink_send_version(glink);
if (ret)
return ERR_PTR(ret);
@@ -1796,12 +1785,24 @@ static int qcom_glink_remove_device(struct device *dev, void *data)
void qcom_glink_native_remove(struct qcom_glink *glink)
{
struct glink_channel *channel;
+ unsigned long flags;
int cid;
int ret;
- disable_irq(glink->irq);
qcom_glink_cancel_rx_work(glink);
+ /* Fail all attempts at sending messages */
+ spin_lock_irqsave(&glink->tx_lock, flags);
+ glink->abort_tx = true;
+ wake_up_all(&glink->tx_avail_notify);
+ spin_unlock_irqrestore(&glink->tx_lock, flags);
+
+ /* Abort any senders waiting for intent requests */
+ spin_lock_irqsave(&glink->idr_lock, flags);
+ idr_for_each_entry(&glink->lcids, channel, cid)
+ qcom_glink_intent_req_abort(channel);
+ spin_unlock_irqrestore(&glink->idr_lock, flags);
+
ret = device_for_each_child(glink->dev, NULL, qcom_glink_remove_device);
if (ret)
dev_warn(glink->dev, "Can't remove GLINK devices: %d\n", ret);
@@ -1816,15 +1817,8 @@ void qcom_glink_native_remove(struct qcom_glink *glink)
idr_destroy(&glink->lcids);
idr_destroy(&glink->rcids);
- mbox_free_channel(glink->mbox_chan);
}
EXPORT_SYMBOL_GPL(qcom_glink_native_remove);
-void qcom_glink_native_unregister(struct qcom_glink *glink)
-{
- device_unregister(glink->dev);
-}
-EXPORT_SYMBOL_GPL(qcom_glink_native_unregister);
-
MODULE_DESCRIPTION("Qualcomm GLINK driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/rpmsg/qcom_glink_native.h b/drivers/rpmsg/qcom_glink_native.h
index 624184fc458e..8dbec24de23e 100644
--- a/drivers/rpmsg/qcom_glink_native.h
+++ b/drivers/rpmsg/qcom_glink_native.h
@@ -6,6 +6,8 @@
#ifndef __QCOM_GLINK_NATIVE_H__
#define __QCOM_GLINK_NATIVE_H__
+#include <linux/types.h>
+
#define GLINK_FEATURE_INTENT_REUSE BIT(0)
#define GLINK_FEATURE_MIGRATION BIT(1)
#define GLINK_FEATURE_TRACER_PKT BIT(2)
@@ -15,15 +17,17 @@ struct qcom_glink_pipe {
size_t (*avail)(struct qcom_glink_pipe *glink_pipe);
- void (*peak)(struct qcom_glink_pipe *glink_pipe, void *data,
+ void (*peek)(struct qcom_glink_pipe *glink_pipe, void *data,
unsigned int offset, size_t count);
void (*advance)(struct qcom_glink_pipe *glink_pipe, size_t count);
void (*write)(struct qcom_glink_pipe *glink_pipe,
const void *hdr, size_t hlen,
const void *data, size_t dlen);
+ void (*kick)(struct qcom_glink_pipe *glink_pipe);
};
+struct device;
struct qcom_glink;
struct qcom_glink *qcom_glink_native_probe(struct device *dev,
@@ -32,6 +36,6 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev,
struct qcom_glink_pipe *tx,
bool intentless);
void qcom_glink_native_remove(struct qcom_glink *glink);
+void qcom_glink_native_rx(struct qcom_glink *glink);
-void qcom_glink_native_unregister(struct qcom_glink *glink);
#endif
diff --git a/drivers/rpmsg/qcom_glink_rpm.c b/drivers/rpmsg/qcom_glink_rpm.c
index f64f45d1a735..f94bb7d4f1ec 100644
--- a/drivers/rpmsg/qcom_glink_rpm.c
+++ b/drivers/rpmsg/qcom_glink_rpm.c
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/rpmsg.h>
@@ -53,6 +54,18 @@ struct glink_rpm_pipe {
void __iomem *fifo;
};
+struct glink_rpm {
+ struct qcom_glink *glink;
+
+ int irq;
+
+ struct mbox_client mbox_client;
+ struct mbox_chan *mbox_chan;
+
+ struct glink_rpm_pipe rx_pipe;
+ struct glink_rpm_pipe tx_pipe;
+};
+
static size_t glink_rpm_rx_avail(struct qcom_glink_pipe *glink_pipe)
{
struct glink_rpm_pipe *pipe = to_rpm_pipe(glink_pipe);
@@ -68,7 +81,7 @@ static size_t glink_rpm_rx_avail(struct qcom_glink_pipe *glink_pipe)
return head - tail;
}
-static void glink_rpm_rx_peak(struct qcom_glink_pipe *glink_pipe,
+static void glink_rpm_rx_peek(struct qcom_glink_pipe *glink_pipe,
void *data, unsigned int offset, size_t count)
{
struct glink_rpm_pipe *pipe = to_rpm_pipe(glink_pipe);
@@ -179,6 +192,24 @@ static void glink_rpm_tx_write(struct qcom_glink_pipe *glink_pipe,
writel(head, pipe->head);
}
+static void glink_rpm_tx_kick(struct qcom_glink_pipe *glink_pipe)
+{
+ struct glink_rpm_pipe *pipe = to_rpm_pipe(glink_pipe);
+ struct glink_rpm *rpm = container_of(pipe, struct glink_rpm, tx_pipe);
+
+ mbox_send_message(rpm->mbox_chan, NULL);
+ mbox_client_txdone(rpm->mbox_chan, 0);
+}
+
+static irqreturn_t qcom_glink_rpm_intr(int irq, void *data)
+{
+ struct glink_rpm *rpm = data;
+
+ qcom_glink_native_rx(rpm->glink);
+
+ return IRQ_HANDLED;
+}
+
static int glink_rpm_parse_toc(struct device *dev,
void __iomem *msg_ram,
size_t msg_ram_size,
@@ -257,8 +288,7 @@ err_inval:
static int glink_rpm_probe(struct platform_device *pdev)
{
struct qcom_glink *glink;
- struct glink_rpm_pipe *rx_pipe;
- struct glink_rpm_pipe *tx_pipe;
+ struct glink_rpm *rpm;
struct device_node *np;
void __iomem *msg_ram;
size_t msg_ram_size;
@@ -266,9 +296,8 @@ static int glink_rpm_probe(struct platform_device *pdev)
struct resource r;
int ret;
- rx_pipe = devm_kzalloc(&pdev->dev, sizeof(*rx_pipe), GFP_KERNEL);
- tx_pipe = devm_kzalloc(&pdev->dev, sizeof(*tx_pipe), GFP_KERNEL);
- if (!rx_pipe || !tx_pipe)
+ rpm = devm_kzalloc(&pdev->dev, sizeof(*rpm), GFP_KERNEL);
+ if (!rpm)
return -ENOMEM;
np = of_parse_phandle(dev->of_node, "qcom,rpm-msg-ram", 0);
@@ -283,39 +312,66 @@ static int glink_rpm_probe(struct platform_device *pdev)
return -ENOMEM;
ret = glink_rpm_parse_toc(dev, msg_ram, msg_ram_size,
- rx_pipe, tx_pipe);
+ &rpm->rx_pipe, &rpm->tx_pipe);
if (ret)
return ret;
+ rpm->irq = of_irq_get(dev->of_node, 0);
+ ret = devm_request_irq(dev, rpm->irq, qcom_glink_rpm_intr,
+ IRQF_NO_SUSPEND | IRQF_NO_AUTOEN,
+ "glink-rpm", rpm);
+ if (ret) {
+ dev_err(dev, "failed to request IRQ\n");
+ return ret;
+ }
+
+ rpm->mbox_client.dev = dev;
+ rpm->mbox_client.knows_txdone = true;
+ rpm->mbox_chan = mbox_request_channel(&rpm->mbox_client, 0);
+ if (IS_ERR(rpm->mbox_chan))
+ return dev_err_probe(dev, PTR_ERR(rpm->mbox_chan), "failed to acquire IPC channel\n");
+
/* Pipe specific accessors */
- rx_pipe->native.avail = glink_rpm_rx_avail;
- rx_pipe->native.peak = glink_rpm_rx_peak;
- rx_pipe->native.advance = glink_rpm_rx_advance;
- tx_pipe->native.avail = glink_rpm_tx_avail;
- tx_pipe->native.write = glink_rpm_tx_write;
+ rpm->rx_pipe.native.avail = glink_rpm_rx_avail;
+ rpm->rx_pipe.native.peek = glink_rpm_rx_peek;
+ rpm->rx_pipe.native.advance = glink_rpm_rx_advance;
+ rpm->tx_pipe.native.avail = glink_rpm_tx_avail;
+ rpm->tx_pipe.native.write = glink_rpm_tx_write;
+ rpm->tx_pipe.native.kick = glink_rpm_tx_kick;
- writel(0, tx_pipe->head);
- writel(0, rx_pipe->tail);
+ writel(0, rpm->tx_pipe.head);
+ writel(0, rpm->rx_pipe.tail);
- glink = qcom_glink_native_probe(&pdev->dev,
+ glink = qcom_glink_native_probe(dev,
0,
- &rx_pipe->native,
- &tx_pipe->native,
+ &rpm->rx_pipe.native,
+ &rpm->tx_pipe.native,
true);
- if (IS_ERR(glink))
+ if (IS_ERR(glink)) {
+ mbox_free_channel(rpm->mbox_chan);
return PTR_ERR(glink);
+ }
+
+ rpm->glink = glink;
- platform_set_drvdata(pdev, glink);
+ platform_set_drvdata(pdev, rpm);
+
+ enable_irq(rpm->irq);
return 0;
}
static int glink_rpm_remove(struct platform_device *pdev)
{
- struct qcom_glink *glink = platform_get_drvdata(pdev);
+ struct glink_rpm *rpm = platform_get_drvdata(pdev);
+ struct qcom_glink *glink = rpm->glink;
+
+ disable_irq(rpm->irq);
qcom_glink_native_remove(glink);
+ mbox_free_channel(rpm->mbox_chan);
+
return 0;
}
diff --git a/drivers/rpmsg/qcom_glink_smem.c b/drivers/rpmsg/qcom_glink_smem.c
index 579bc4443f6d..7a982c60a8dd 100644
--- a/drivers/rpmsg/qcom_glink_smem.c
+++ b/drivers/rpmsg/qcom_glink_smem.c
@@ -7,8 +7,10 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
+#include <linux/mailbox_client.h>
#include <linux/mfd/syscon.h>
#include <linux/slab.h>
#include <linux/rpmsg.h>
@@ -33,6 +35,18 @@
#define SMEM_GLINK_NATIVE_XPRT_FIFO_0 479
#define SMEM_GLINK_NATIVE_XPRT_FIFO_1 480
+struct qcom_glink_smem {
+ struct device dev;
+
+ int irq;
+ struct qcom_glink *glink;
+
+ struct mbox_client mbox_client;
+ struct mbox_chan *mbox_chan;
+
+ u32 remote_pid;
+};
+
struct glink_smem_pipe {
struct qcom_glink_pipe native;
@@ -41,7 +55,7 @@ struct glink_smem_pipe {
void *fifo;
- int remote_pid;
+ struct qcom_glink_smem *smem;
};
#define to_smem_pipe(p) container_of(p, struct glink_smem_pipe, native)
@@ -49,13 +63,14 @@ struct glink_smem_pipe {
static size_t glink_smem_rx_avail(struct qcom_glink_pipe *np)
{
struct glink_smem_pipe *pipe = to_smem_pipe(np);
+ struct qcom_glink_smem *smem = pipe->smem;
size_t len;
void *fifo;
u32 head;
u32 tail;
if (!pipe->fifo) {
- fifo = qcom_smem_get(pipe->remote_pid,
+ fifo = qcom_smem_get(smem->remote_pid,
SMEM_GLINK_NATIVE_XPRT_FIFO_1, &len);
if (IS_ERR(fifo)) {
pr_err("failed to acquire RX fifo handle: %ld\n",
@@ -76,7 +91,7 @@ static size_t glink_smem_rx_avail(struct qcom_glink_pipe *np)
return head - tail;
}
-static void glink_smem_rx_peak(struct qcom_glink_pipe *np,
+static void glink_smem_rx_peek(struct qcom_glink_pipe *np,
void *data, unsigned int offset, size_t count)
{
struct glink_smem_pipe *pipe = to_smem_pipe(np);
@@ -177,16 +192,37 @@ static void glink_smem_tx_write(struct qcom_glink_pipe *glink_pipe,
*pipe->head = cpu_to_le32(head);
}
+static void glink_smem_tx_kick(struct qcom_glink_pipe *glink_pipe)
+{
+ struct glink_smem_pipe *pipe = to_smem_pipe(glink_pipe);
+ struct qcom_glink_smem *smem = pipe->smem;
+
+ mbox_send_message(smem->mbox_chan, NULL);
+ mbox_client_txdone(smem->mbox_chan, 0);
+}
+
+static irqreturn_t qcom_glink_smem_intr(int irq, void *data)
+{
+ struct qcom_glink_smem *smem = data;
+
+ qcom_glink_native_rx(smem->glink);
+
+ return IRQ_HANDLED;
+}
+
static void qcom_glink_smem_release(struct device *dev)
{
- kfree(dev);
+ struct qcom_glink_smem *smem = container_of(dev, struct qcom_glink_smem, dev);
+
+ kfree(smem);
}
-struct qcom_glink *qcom_glink_smem_register(struct device *parent,
- struct device_node *node)
+struct qcom_glink_smem *qcom_glink_smem_register(struct device *parent,
+ struct device_node *node)
{
struct glink_smem_pipe *rx_pipe;
struct glink_smem_pipe *tx_pipe;
+ struct qcom_glink_smem *smem;
struct qcom_glink *glink;
struct device *dev;
u32 remote_pid;
@@ -194,10 +230,12 @@ struct qcom_glink *qcom_glink_smem_register(struct device *parent,
size_t size;
int ret;
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (!dev)
+ smem = kzalloc(sizeof(*smem), GFP_KERNEL);
+ if (!smem)
return ERR_PTR(-ENOMEM);
+ dev = &smem->dev;
+
dev->parent = parent;
dev->of_node = node;
dev->release = qcom_glink_smem_release;
@@ -216,6 +254,8 @@ struct qcom_glink *qcom_glink_smem_register(struct device *parent,
goto err_put_dev;
}
+ smem->remote_pid = remote_pid;
+
rx_pipe = devm_kzalloc(dev, sizeof(*rx_pipe), GFP_KERNEL);
tx_pipe = devm_kzalloc(dev, sizeof(*tx_pipe), GFP_KERNEL);
if (!rx_pipe || !tx_pipe) {
@@ -264,14 +304,33 @@ struct qcom_glink *qcom_glink_smem_register(struct device *parent,
goto err_put_dev;
}
+ smem->irq = of_irq_get(smem->dev.of_node, 0);
+ ret = devm_request_irq(&smem->dev, smem->irq, qcom_glink_smem_intr,
+ IRQF_NO_SUSPEND | IRQF_NO_AUTOEN,
+ "glink-smem", smem);
+ if (ret) {
+ dev_err(&smem->dev, "failed to request IRQ\n");
+ goto err_put_dev;
+ }
+
+ smem->mbox_client.dev = &smem->dev;
+ smem->mbox_client.knows_txdone = true;
+ smem->mbox_chan = mbox_request_channel(&smem->mbox_client, 0);
+ if (IS_ERR(smem->mbox_chan)) {
+ ret = dev_err_probe(&smem->dev, PTR_ERR(smem->mbox_chan),
+ "failed to acquire IPC channel\n");
+ goto err_put_dev;
+ }
+
+ rx_pipe->smem = smem;
rx_pipe->native.avail = glink_smem_rx_avail;
- rx_pipe->native.peak = glink_smem_rx_peak;
+ rx_pipe->native.peek = glink_smem_rx_peek;
rx_pipe->native.advance = glink_smem_rx_advance;
- rx_pipe->remote_pid = remote_pid;
+ tx_pipe->smem = smem;
tx_pipe->native.avail = glink_smem_tx_avail;
tx_pipe->native.write = glink_smem_tx_write;
- tx_pipe->remote_pid = remote_pid;
+ tx_pipe->native.kick = glink_smem_tx_kick;
*rx_pipe->tail = 0;
*tx_pipe->head = 0;
@@ -282,10 +341,17 @@ struct qcom_glink *qcom_glink_smem_register(struct device *parent,
false);
if (IS_ERR(glink)) {
ret = PTR_ERR(glink);
- goto err_put_dev;
+ goto err_free_mbox;
}
- return glink;
+ smem->glink = glink;
+
+ enable_irq(smem->irq);
+
+ return smem;
+
+err_free_mbox:
+ mbox_free_channel(smem->mbox_chan);
err_put_dev:
device_unregister(dev);
@@ -294,10 +360,16 @@ err_put_dev:
}
EXPORT_SYMBOL_GPL(qcom_glink_smem_register);
-void qcom_glink_smem_unregister(struct qcom_glink *glink)
+void qcom_glink_smem_unregister(struct qcom_glink_smem *smem)
{
+ struct qcom_glink *glink = smem->glink;
+
+ disable_irq(smem->irq);
+
qcom_glink_native_remove(glink);
- qcom_glink_native_unregister(glink);
+
+ mbox_free_channel(smem->mbox_chan);
+ device_unregister(&smem->dev);
}
EXPORT_SYMBOL_GPL(qcom_glink_smem_unregister);
diff --git a/drivers/rpmsg/qcom_glink_ssr.c b/drivers/rpmsg/qcom_glink_ssr.c
index 776d64446879..39ffa384c9b1 100644
--- a/drivers/rpmsg/qcom_glink_ssr.c
+++ b/drivers/rpmsg/qcom_glink_ssr.c
@@ -111,7 +111,7 @@ static int qcom_glink_ssr_notifier_call(struct notifier_block *nb,
msg.command = cpu_to_le32(GLINK_SSR_DO_CLEANUP);
msg.seq_num = cpu_to_le32(ssr->seq_num);
msg.name_len = cpu_to_le32(strlen(ssr_name));
- strlcpy(msg.name, ssr_name, sizeof(msg.name));
+ strscpy(msg.name, ssr_name, sizeof(msg.name));
ret = rpmsg_send(ssr->ept, &msg, sizeof(msg));
if (ret < 0)
diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
index 3e0b8f3496ed..a271fceb16f4 100644
--- a/drivers/rpmsg/rpmsg_char.c
+++ b/drivers/rpmsg/rpmsg_char.c
@@ -75,6 +75,7 @@ int rpmsg_chrdev_eptdev_destroy(struct device *dev, void *data)
struct rpmsg_eptdev *eptdev = dev_to_eptdev(dev);
mutex_lock(&eptdev->ept_lock);
+ eptdev->rpdev = NULL;
if (eptdev->ept) {
/* The default endpoint is released by the rpmsg core */
if (!eptdev->default_ept)
@@ -128,6 +129,11 @@ static int rpmsg_eptdev_open(struct inode *inode, struct file *filp)
return -EBUSY;
}
+ if (!eptdev->rpdev) {
+ mutex_unlock(&eptdev->ept_lock);
+ return -ENETRESET;
+ }
+
get_device(dev);
/*
@@ -279,7 +285,9 @@ static __poll_t rpmsg_eptdev_poll(struct file *filp, poll_table *wait)
if (!skb_queue_empty(&eptdev->queue))
mask |= EPOLLIN | EPOLLRDNORM;
+ mutex_lock(&eptdev->ept_lock);
mask |= rpmsg_poll(eptdev->ept, filp, wait);
+ mutex_unlock(&eptdev->ept_lock);
return mask;
}
diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c
index d6dde00efdae..a2207c0cf432 100644
--- a/drivers/rpmsg/rpmsg_core.c
+++ b/drivers/rpmsg/rpmsg_core.c
@@ -492,9 +492,9 @@ static int rpmsg_dev_match(struct device *dev, struct device_driver *drv)
return of_driver_match_device(dev, drv);
}
-static int rpmsg_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int rpmsg_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct rpmsg_device *rpdev = to_rpmsg_device(dev);
+ const struct rpmsg_device *rpdev = to_rpmsg_device(dev);
int ret;
ret = of_device_uevent_modalias(dev, env);
diff --git a/drivers/rpmsg/rpmsg_ctrl.c b/drivers/rpmsg/rpmsg_ctrl.c
index 107da70fdbaa..433253835690 100644
--- a/drivers/rpmsg/rpmsg_ctrl.c
+++ b/drivers/rpmsg/rpmsg_ctrl.c
@@ -194,10 +194,12 @@ static void rpmsg_ctrldev_remove(struct rpmsg_device *rpdev)
struct rpmsg_ctrldev *ctrldev = dev_get_drvdata(&rpdev->dev);
int ret;
+ mutex_lock(&ctrldev->ctrl_lock);
/* Destroy all endpoints */
ret = device_for_each_child(&ctrldev->dev, NULL, rpmsg_chrdev_eptdev_destroy);
if (ret)
dev_warn(&rpdev->dev, "failed to nuke endpoints: %d\n", ret);
+ mutex_unlock(&ctrldev->ctrl_lock);
cdev_device_del(&ctrldev->cdev, &ctrldev->dev);
put_device(&ctrldev->dev);
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 2ba72de0fa47..5a71579af0a1 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1677,7 +1677,7 @@ config RTC_DRV_MPC5121
config RTC_DRV_JZ4740
tristate "Ingenic JZ4740 SoC"
depends on MIPS || COMPILE_TEST
- depends on OF
+ depends on OF && COMMON_CLK
help
If you say yes here you get support for the Ingenic JZ47xx SoCs RTC
controllers.
@@ -1773,6 +1773,18 @@ config RTC_DRV_SNVS
This driver can also be built as a module, if so, the module
will be called "rtc-snvs".
+config RTC_DRV_BBNSM
+ tristate "NXP BBNSM RTC support"
+ select REGMAP_MMIO
+ depends on ARCH_MXC || COMPILE_TEST
+ depends on HAS_IOMEM
+ depends on OF
+ help
+ If you say yes here you get support for the NXP BBNSM RTC module.
+
+ This driver can also be built as a module, if so, the module
+ will be called "rtc-bbnsm".
+
config RTC_DRV_IMX_SC
depends on IMX_SCU
depends on HAVE_ARM_SMCCC
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 59eb30289335..ea445d1ebb17 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -33,6 +33,7 @@ obj-$(CONFIG_RTC_DRV_ASPEED) += rtc-aspeed.o
obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o
obj-$(CONFIG_RTC_DRV_AU1XXX) += rtc-au1xxx.o
+obj-$(CONFIG_RTC_DRV_BBNSM) += rtc-nxp-bbnsm.o
obj-$(CONFIG_RTC_DRV_BD70528) += rtc-bd70528.o
obj-$(CONFIG_RTC_DRV_BQ32K) += rtc-bq32k.o
obj-$(CONFIG_RTC_DRV_BQ4802) += rtc-bq4802.o
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index 7c30cb3c764d..499d89150afc 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -392,7 +392,7 @@ int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
return err;
if (!rtc->ops) {
err = -ENODEV;
- } else if (!test_bit(RTC_FEATURE_ALARM, rtc->features) || !rtc->ops->read_alarm) {
+ } else if (!test_bit(RTC_FEATURE_ALARM, rtc->features)) {
err = -EINVAL;
} else {
memset(alarm, 0, sizeof(struct rtc_wkalrm));
diff --git a/drivers/rtc/rtc-ab-eoz9.c b/drivers/rtc/rtc-ab-eoz9.c
index 2f8deb8c4cd3..34611f6dedcb 100644
--- a/drivers/rtc/rtc-ab-eoz9.c
+++ b/drivers/rtc/rtc-ab-eoz9.c
@@ -536,9 +536,14 @@ static int abeoz9_probe(struct i2c_client *client)
clear_bit(RTC_FEATURE_ALARM, data->rtc->features);
if (client->irq > 0) {
+ unsigned long irqflags = IRQF_TRIGGER_LOW;
+
+ if (dev_fwnode(&client->dev))
+ irqflags = 0;
+
ret = devm_request_threaded_irq(dev, client->irq, NULL,
abeoz9_rtc_irq,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ irqflags | IRQF_ONESHOT,
dev_name(dev), dev);
if (ret) {
dev_err(dev, "failed to request alarm irq\n");
diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c
index 2e0e6432901b..f34a2e59cac7 100644
--- a/drivers/rtc/rtc-abx80x.c
+++ b/drivers/rtc/rtc-abx80x.c
@@ -11,6 +11,7 @@
*/
#include <linux/bcd.h>
+#include <linux/bitfield.h>
#include <linux/i2c.h>
#include <linux/kstrtox.h>
#include <linux/module.h>
@@ -88,6 +89,16 @@
#define ABX8XX_TRICKLE_STANDARD_DIODE 0x8
#define ABX8XX_TRICKLE_SCHOTTKY_DIODE 0x4
+#define ABX8XX_REG_EXTRAM 0x3f
+#define ABX8XX_EXTRAM_XADS GENMASK(1, 0)
+
+#define ABX8XX_SRAM_BASE 0x40
+#define ABX8XX_SRAM_WIN_SIZE 0x40
+#define ABX8XX_RAM_SIZE 256
+
+#define NVMEM_ADDR_LOWER GENMASK(5, 0)
+#define NVMEM_ADDR_UPPER GENMASK(7, 6)
+
static u8 trickle_resistors[] = {0, 3, 6, 11};
enum abx80x_chip {AB0801, AB0803, AB0804, AB0805,
@@ -674,6 +685,68 @@ static int abx80x_setup_watchdog(struct abx80x_priv *priv)
}
#endif
+static int abx80x_nvmem_xfer(struct abx80x_priv *priv, unsigned int offset,
+ void *val, size_t bytes, bool write)
+{
+ int ret;
+
+ while (bytes) {
+ u8 extram, reg, len, lower, upper;
+
+ lower = FIELD_GET(NVMEM_ADDR_LOWER, offset);
+ upper = FIELD_GET(NVMEM_ADDR_UPPER, offset);
+ extram = FIELD_PREP(ABX8XX_EXTRAM_XADS, upper);
+ reg = ABX8XX_SRAM_BASE + lower;
+ len = min(lower + bytes, (size_t)ABX8XX_SRAM_WIN_SIZE) - lower;
+ len = min_t(u8, len, I2C_SMBUS_BLOCK_MAX);
+
+ ret = i2c_smbus_write_byte_data(priv->client, ABX8XX_REG_EXTRAM,
+ extram);
+ if (ret)
+ return ret;
+
+ if (write)
+ ret = i2c_smbus_write_i2c_block_data(priv->client, reg,
+ len, val);
+ else
+ ret = i2c_smbus_read_i2c_block_data(priv->client, reg,
+ len, val);
+ if (ret)
+ return ret;
+
+ offset += len;
+ val += len;
+ bytes -= len;
+ }
+
+ return 0;
+}
+
+static int abx80x_nvmem_read(void *priv, unsigned int offset, void *val,
+ size_t bytes)
+{
+ return abx80x_nvmem_xfer(priv, offset, val, bytes, false);
+}
+
+static int abx80x_nvmem_write(void *priv, unsigned int offset, void *val,
+ size_t bytes)
+{
+ return abx80x_nvmem_xfer(priv, offset, val, bytes, true);
+}
+
+static int abx80x_setup_nvmem(struct abx80x_priv *priv)
+{
+ struct nvmem_config config = {
+ .type = NVMEM_TYPE_BATTERY_BACKED,
+ .reg_read = abx80x_nvmem_read,
+ .reg_write = abx80x_nvmem_write,
+ .size = ABX8XX_RAM_SIZE,
+ .priv = priv,
+ };
+
+ return devm_rtc_nvmem_register(priv->rtc, &config);
+}
+
static const struct i2c_device_id abx80x_id[] = {
{ "abx80x", ABX80X },
{ "ab0801", AB0801 },
@@ -840,6 +913,10 @@ static int abx80x_probe(struct i2c_client *client)
return err;
}
+ err = abx80x_setup_nvmem(priv);
+ if (err)
+ return err;
+
if (client->irq > 0) {
dev_info(&client->dev, "IRQ %d supplied\n", client->irq);
err = devm_request_threaded_irq(&client->dev, client->irq, NULL,
diff --git a/drivers/rtc/rtc-brcmstb-waketimer.c b/drivers/rtc/rtc-brcmstb-waketimer.c
index c74130e8f496..1efa81cecc27 100644
--- a/drivers/rtc/rtc-brcmstb-waketimer.c
+++ b/drivers/rtc/rtc-brcmstb-waketimer.c
@@ -27,13 +27,17 @@ struct brcmstb_waketmr {
struct rtc_device *rtc;
struct device *dev;
void __iomem *base;
- int irq;
+ unsigned int wake_irq;
+ unsigned int alarm_irq;
struct notifier_block reboot_notifier;
struct clk *clk;
u32 rate;
+ unsigned long rtc_alarm;
+ bool alarm_en;
};
#define BRCMSTB_WKTMR_EVENT 0x00
+#define WKTMR_ALARM_EVENT BIT(0)
#define BRCMSTB_WKTMR_COUNTER 0x04
#define BRCMSTB_WKTMR_ALARM 0x08
#define BRCMSTB_WKTMR_PRESCALER 0x0C
@@ -41,28 +45,71 @@ struct brcmstb_waketmr {
#define BRCMSTB_WKTMR_DEFAULT_FREQ 27000000
+static inline bool brcmstb_waketmr_is_pending(struct brcmstb_waketmr *timer)
+{
+ u32 reg;
+
+ reg = readl_relaxed(timer->base + BRCMSTB_WKTMR_EVENT);
+ return !!(reg & WKTMR_ALARM_EVENT);
+}
+
static inline void brcmstb_waketmr_clear_alarm(struct brcmstb_waketmr *timer)
{
- writel_relaxed(1, timer->base + BRCMSTB_WKTMR_EVENT);
+ u32 reg;
+
+ if (timer->alarm_en && timer->alarm_irq)
+ disable_irq(timer->alarm_irq);
+ timer->alarm_en = false;
+ reg = readl_relaxed(timer->base + BRCMSTB_WKTMR_COUNTER);
+ writel_relaxed(reg - 1, timer->base + BRCMSTB_WKTMR_ALARM);
+ writel_relaxed(WKTMR_ALARM_EVENT, timer->base + BRCMSTB_WKTMR_EVENT);
(void)readl_relaxed(timer->base + BRCMSTB_WKTMR_EVENT);
}
static void brcmstb_waketmr_set_alarm(struct brcmstb_waketmr *timer,
unsigned int secs)
{
+ unsigned int now;
+
brcmstb_waketmr_clear_alarm(timer);
/* Make sure we are actually counting in seconds */
writel_relaxed(timer->rate, timer->base + BRCMSTB_WKTMR_PRESCALER);
- writel_relaxed(secs + 1, timer->base + BRCMSTB_WKTMR_ALARM);
+ writel_relaxed(secs, timer->base + BRCMSTB_WKTMR_ALARM);
+ now = readl_relaxed(timer->base + BRCMSTB_WKTMR_COUNTER);
+
+ while ((int)(secs - now) <= 0 &&
+ !brcmstb_waketmr_is_pending(timer)) {
+ secs = now + 1;
+ writel_relaxed(secs, timer->base + BRCMSTB_WKTMR_ALARM);
+ now = readl_relaxed(timer->base + BRCMSTB_WKTMR_COUNTER);
+ }
}
static irqreturn_t brcmstb_waketmr_irq(int irq, void *data)
{
struct brcmstb_waketmr *timer = data;
- pm_wakeup_event(timer->dev, 0);
+ if (!timer->alarm_irq)
+ pm_wakeup_event(timer->dev, 0);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t brcmstb_alarm_irq(int irq, void *data)
+{
+ struct brcmstb_waketmr *timer = data;
+
+ /* Ignore spurious interrupts */
+ if (!brcmstb_waketmr_is_pending(timer))
+ return IRQ_HANDLED;
+
+ if (timer->alarm_en) {
+ if (!device_may_wakeup(timer->dev))
+ writel_relaxed(WKTMR_ALARM_EVENT,
+ timer->base + BRCMSTB_WKTMR_EVENT);
+ rtc_update_irq(timer->rtc, 1, RTC_IRQF | RTC_AF);
+ }
return IRQ_HANDLED;
}
@@ -88,17 +135,25 @@ static void wktmr_read(struct brcmstb_waketmr *timer,
static int brcmstb_waketmr_prepare_suspend(struct brcmstb_waketmr *timer)
{
struct device *dev = timer->dev;
- int ret = 0;
+ int ret;
if (device_may_wakeup(dev)) {
- ret = enable_irq_wake(timer->irq);
+ ret = enable_irq_wake(timer->wake_irq);
if (ret) {
dev_err(dev, "failed to enable wake-up interrupt\n");
return ret;
}
+ if (timer->alarm_en && timer->alarm_irq) {
+ ret = enable_irq_wake(timer->alarm_irq);
+ if (ret) {
+ dev_err(dev, "failed to enable rtc interrupt\n");
+ disable_irq_wake(timer->wake_irq);
+ return ret;
+ }
+ }
}
- return ret;
+ return 0;
}
/* If enabled as a wakeup-source, arm the timer when powering off */
@@ -146,46 +201,47 @@ static int brcmstb_waketmr_getalarm(struct device *dev,
struct rtc_wkalrm *alarm)
{
struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
- time64_t sec;
- u32 reg;
- sec = readl_relaxed(timer->base + BRCMSTB_WKTMR_ALARM);
- if (sec != 0) {
- /* Alarm is enabled */
- alarm->enabled = 1;
- rtc_time64_to_tm(sec, &alarm->time);
- }
+ alarm->enabled = timer->alarm_en;
+ rtc_time64_to_tm(timer->rtc_alarm, &alarm->time);
- reg = readl_relaxed(timer->base + BRCMSTB_WKTMR_EVENT);
- alarm->pending = !!(reg & 1);
+ alarm->pending = brcmstb_waketmr_is_pending(timer);
return 0;
}
-static int brcmstb_waketmr_setalarm(struct device *dev,
- struct rtc_wkalrm *alarm)
+static int brcmstb_waketmr_alarm_enable(struct device *dev,
+ unsigned int enabled)
{
struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
- time64_t sec;
-
- if (alarm->enabled)
- sec = rtc_tm_to_time64(&alarm->time);
- else
- sec = 0;
- brcmstb_waketmr_set_alarm(timer, sec);
+ if (enabled && !timer->alarm_en) {
+ if ((int)(readl_relaxed(timer->base + BRCMSTB_WKTMR_COUNTER) -
+ readl_relaxed(timer->base + BRCMSTB_WKTMR_ALARM)) >= 0 &&
+ !brcmstb_waketmr_is_pending(timer))
+ return -EINVAL;
+ timer->alarm_en = true;
+ if (timer->alarm_irq)
+ enable_irq(timer->alarm_irq);
+ } else if (!enabled && timer->alarm_en) {
+ if (timer->alarm_irq)
+ disable_irq(timer->alarm_irq);
+ timer->alarm_en = false;
+ }
return 0;
}
-/*
- * Does not do much but keep the RTC class happy. We always support
- * alarms.
- */
-static int brcmstb_waketmr_alarm_enable(struct device *dev,
- unsigned int enabled)
+static int brcmstb_waketmr_setalarm(struct device *dev,
+ struct rtc_wkalrm *alarm)
{
- return 0;
+ struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
+
+ timer->rtc_alarm = rtc_tm_to_time64(&alarm->time);
+
+ brcmstb_waketmr_set_alarm(timer, timer->rtc_alarm);
+
+ return brcmstb_waketmr_alarm_enable(dev, alarm->enabled);
}
static const struct rtc_class_ops brcmstb_waketmr_ops = {
@@ -221,12 +277,12 @@ static int brcmstb_waketmr_probe(struct platform_device *pdev)
* Set wakeup capability before requesting wakeup interrupt, so we can
* process boot-time "wakeups" (e.g., from S5 soft-off)
*/
- device_set_wakeup_capable(dev, true);
- device_wakeup_enable(dev);
+ device_init_wakeup(dev, true);
- timer->irq = platform_get_irq(pdev, 0);
- if (timer->irq < 0)
+ ret = platform_get_irq(pdev, 0);
+ if (ret < 0)
return -ENODEV;
+ timer->wake_irq = (unsigned int)ret;
timer->clk = devm_clk_get(dev, NULL);
if (!IS_ERR(timer->clk)) {
@@ -241,11 +297,24 @@ static int brcmstb_waketmr_probe(struct platform_device *pdev)
timer->clk = NULL;
}
- ret = devm_request_irq(dev, timer->irq, brcmstb_waketmr_irq, 0,
+ ret = devm_request_irq(dev, timer->wake_irq, brcmstb_waketmr_irq, 0,
"brcmstb-waketimer", timer);
if (ret < 0)
goto err_clk;
+ brcmstb_waketmr_clear_alarm(timer);
+
+ /* Attempt to initialize non-wake irq */
+ ret = platform_get_irq(pdev, 1);
+ if (ret > 0) {
+ timer->alarm_irq = (unsigned int)ret;
+ ret = devm_request_irq(dev, timer->alarm_irq, brcmstb_alarm_irq,
+ IRQF_NO_AUTOEN, "brcmstb-waketimer-rtc",
+ timer);
+ if (ret < 0)
+ timer->alarm_irq = 0;
+ }
+
timer->reboot_notifier.notifier_call = brcmstb_waketmr_reboot;
register_reboot_notifier(&timer->reboot_notifier);
@@ -256,8 +325,6 @@ static int brcmstb_waketmr_probe(struct platform_device *pdev)
if (ret)
goto err_notifier;
- dev_info(dev, "registered, with irq %d\n", timer->irq);
-
return 0;
err_notifier:
@@ -295,7 +362,9 @@ static int brcmstb_waketmr_resume(struct device *dev)
if (!device_may_wakeup(dev))
return 0;
- ret = disable_irq_wake(timer->irq);
+ ret = disable_irq_wake(timer->wake_irq);
+ if (timer->alarm_en && timer->alarm_irq)
+ disable_irq_wake(timer->alarm_irq);
brcmstb_waketmr_clear_alarm(timer);
@@ -325,4 +394,5 @@ module_platform_driver(brcmstb_waketmr_driver);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Brian Norris");
MODULE_AUTHOR("Markus Mayer");
+MODULE_AUTHOR("Doug Berger");
MODULE_DESCRIPTION("Wake-up timer driver for STB chips");
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index def9b7f9d957..e86ba84df6cb 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -1712,9 +1712,9 @@ static const struct regmap_config regmap_config = {
.val_bits = 8,
};
-static int ds1307_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ds1307_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct ds1307 *ds1307;
const void *match;
int err = -ENODEV;
@@ -2011,7 +2011,7 @@ static struct i2c_driver ds1307_driver = {
.name = "rtc-ds1307",
.of_match_table = ds1307_of_match,
},
- .probe = ds1307_probe,
+ .probe_new = ds1307_probe,
.id_table = ds1307_id,
};
diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c
index 1e8bc6cc1e12..dc6b0f4a54e2 100644
--- a/drivers/rtc/rtc-efi.c
+++ b/drivers/rtc/rtc-efi.c
@@ -164,7 +164,7 @@ static int efi_read_time(struct device *dev, struct rtc_time *tm)
if (status != EFI_SUCCESS) {
/* should never happen */
- dev_err(dev, "can't read time\n");
+ dev_err_once(dev, "can't read time\n");
return -EINVAL;
}
diff --git a/drivers/rtc/rtc-hym8563.c b/drivers/rtc/rtc-hym8563.c
index cc710d682121..7d5a298a9a3b 100644
--- a/drivers/rtc/rtc-hym8563.c
+++ b/drivers/rtc/rtc-hym8563.c
@@ -518,9 +518,14 @@ static int hym8563_probe(struct i2c_client *client)
}
if (client->irq > 0) {
+ unsigned long irqflags = IRQF_TRIGGER_LOW;
+
+ if (dev_fwnode(&client->dev))
+ irqflags = 0;
+
ret = devm_request_threaded_irq(&client->dev, client->irq,
NULL, hym8563_irq,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ irqflags | IRQF_ONESHOT,
client->name, hym8563);
if (ret < 0) {
dev_err(&client->dev, "irq %d request failed, %d\n",
diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c
index a3b0de3393f5..e68a79b5e00e 100644
--- a/drivers/rtc/rtc-isl12022.c
+++ b/drivers/rtc/rtc-isl12022.c
@@ -8,16 +8,16 @@
* by Alessandro Zummo <a.zummo@towertech.it>.
*/
-#include <linux/i2c.h>
#include <linux/bcd.h>
-#include <linux/rtc.h>
-#include <linux/slab.h>
-#include <linux/module.h>
#include <linux/err.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/regmap.h>
#include <linux/hwmon.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/rtc.h>
+#include <linux/slab.h>
+
+#include <asm/byteorder.h>
/* ISL register offsets */
#define ISL12022_REG_SC 0x00
@@ -44,13 +44,6 @@
#define ISL12022_BETA_TSE (1 << 7)
-static struct i2c_driver isl12022_driver;
-
-struct isl12022 {
- struct rtc_device *rtc;
- struct regmap *regmap;
-};
-
static umode_t isl12022_hwmon_is_visible(const void *data,
enum hwmon_sensor_types type,
u32 attr, int channel)
@@ -67,19 +60,17 @@ static umode_t isl12022_hwmon_is_visible(const void *data,
*/
static int isl12022_hwmon_read_temp(struct device *dev, long *mC)
{
- struct isl12022 *isl12022 = dev_get_drvdata(dev);
- struct regmap *regmap = isl12022->regmap;
- u8 temp_buf[2];
+ struct regmap *regmap = dev_get_drvdata(dev);
int temp, ret;
+ __le16 buf;
- ret = regmap_bulk_read(regmap, ISL12022_REG_TEMP_L,
- temp_buf, sizeof(temp_buf));
+ ret = regmap_bulk_read(regmap, ISL12022_REG_TEMP_L, &buf, sizeof(buf));
if (ret)
return ret;
/*
* Temperature is represented as a 10-bit number, unit half-Kelvins.
*/
- temp = (temp_buf[1] << 8) | temp_buf[0];
+ temp = le16_to_cpu(buf);
temp *= 500;
temp -= 273000;
@@ -115,23 +106,21 @@ static const struct hwmon_chip_info isl12022_hwmon_chip_info = {
static void isl12022_hwmon_register(struct device *dev)
{
- struct isl12022 *isl12022;
+ struct regmap *regmap = dev_get_drvdata(dev);
struct device *hwmon;
int ret;
if (!IS_REACHABLE(CONFIG_HWMON))
return;
- isl12022 = dev_get_drvdata(dev);
-
- ret = regmap_update_bits(isl12022->regmap, ISL12022_REG_BETA,
+ ret = regmap_update_bits(regmap, ISL12022_REG_BETA,
ISL12022_BETA_TSE, ISL12022_BETA_TSE);
if (ret) {
dev_warn(dev, "unable to enable temperature sensor\n");
return;
}
- hwmon = devm_hwmon_device_register_with_info(dev, "isl12022", isl12022,
+ hwmon = devm_hwmon_device_register_with_info(dev, "isl12022", regmap,
&isl12022_hwmon_chip_info,
NULL);
if (IS_ERR(hwmon))
@@ -144,8 +133,7 @@ static void isl12022_hwmon_register(struct device *dev)
*/
static int isl12022_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
- struct isl12022 *isl12022 = dev_get_drvdata(dev);
- struct regmap *regmap = isl12022->regmap;
+ struct regmap *regmap = dev_get_drvdata(dev);
uint8_t buf[ISL12022_REG_INT + 1];
int ret;
@@ -155,16 +143,12 @@ static int isl12022_rtc_read_time(struct device *dev, struct rtc_time *tm)
if (buf[ISL12022_REG_SR] & (ISL12022_SR_LBAT85 | ISL12022_SR_LBAT75)) {
dev_warn(dev,
- "voltage dropped below %u%%, "
- "date and time is not reliable.\n",
+ "voltage dropped below %u%%, date and time is not reliable.\n",
buf[ISL12022_REG_SR] & ISL12022_SR_LBAT85 ? 85 : 75);
}
dev_dbg(dev,
- "%s: raw data is sec=%02x, min=%02x, hr=%02x, "
- "mday=%02x, mon=%02x, year=%02x, wday=%02x, "
- "sr=%02x, int=%02x",
- __func__,
+ "raw data is sec=%02x, min=%02x, hr=%02x, mday=%02x, mon=%02x, year=%02x, wday=%02x, sr=%02x, int=%02x",
buf[ISL12022_REG_SC],
buf[ISL12022_REG_MN],
buf[ISL12022_REG_HR],
@@ -190,8 +174,7 @@ static int isl12022_rtc_read_time(struct device *dev, struct rtc_time *tm)
static int isl12022_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
- struct isl12022 *isl12022 = dev_get_drvdata(dev);
- struct regmap *regmap = isl12022->regmap;
+ struct regmap *regmap = dev_get_drvdata(dev);
int ret;
uint8_t buf[ISL12022_REG_DW + 1];
@@ -218,8 +201,7 @@ static int isl12022_rtc_set_time(struct device *dev, struct rtc_time *tm)
buf[ISL12022_REG_DW] = tm->tm_wday & 0x07;
- return regmap_bulk_write(isl12022->regmap, ISL12022_REG_SC,
- buf, sizeof(buf));
+ return regmap_bulk_write(regmap, ISL12022_REG_SC, buf, sizeof(buf));
}
static const struct rtc_class_ops isl12022_rtc_ops = {
@@ -235,44 +217,39 @@ static const struct regmap_config regmap_config = {
static int isl12022_probe(struct i2c_client *client)
{
- struct isl12022 *isl12022;
+ struct rtc_device *rtc;
+ struct regmap *regmap;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -ENODEV;
- isl12022 = devm_kzalloc(&client->dev, sizeof(struct isl12022),
- GFP_KERNEL);
- if (!isl12022)
- return -ENOMEM;
- dev_set_drvdata(&client->dev, isl12022);
-
- isl12022->regmap = devm_regmap_init_i2c(client, &regmap_config);
- if (IS_ERR(isl12022->regmap)) {
+ regmap = devm_regmap_init_i2c(client, &regmap_config);
+ if (IS_ERR(regmap)) {
dev_err(&client->dev, "regmap allocation failed\n");
- return PTR_ERR(isl12022->regmap);
+ return PTR_ERR(regmap);
}
+ dev_set_drvdata(&client->dev, regmap);
+
isl12022_hwmon_register(&client->dev);
- isl12022->rtc = devm_rtc_allocate_device(&client->dev);
- if (IS_ERR(isl12022->rtc))
- return PTR_ERR(isl12022->rtc);
+ rtc = devm_rtc_allocate_device(&client->dev);
+ if (IS_ERR(rtc))
+ return PTR_ERR(rtc);
- isl12022->rtc->ops = &isl12022_rtc_ops;
- isl12022->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
- isl12022->rtc->range_max = RTC_TIMESTAMP_END_2099;
+ rtc->ops = &isl12022_rtc_ops;
+ rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
+ rtc->range_max = RTC_TIMESTAMP_END_2099;
- return devm_rtc_register_device(isl12022->rtc);
+ return devm_rtc_register_device(rtc);
}
-#ifdef CONFIG_OF
static const struct of_device_id isl12022_dt_match[] = {
{ .compatible = "isl,isl12022" }, /* for backward compat., don't use */
{ .compatible = "isil,isl12022" },
{ },
};
MODULE_DEVICE_TABLE(of, isl12022_dt_match);
-#endif
static const struct i2c_device_id isl12022_id[] = {
{ "isl12022", 0 },
@@ -283,9 +260,7 @@ MODULE_DEVICE_TABLE(i2c, isl12022_id);
static struct i2c_driver isl12022_driver = {
.driver = {
.name = "rtc-isl12022",
-#ifdef CONFIG_OF
- .of_match_table = of_match_ptr(isl12022_dt_match),
-#endif
+ .of_match_table = isl12022_dt_match,
},
.probe_new = isl12022_probe,
.id_table = isl12022_id,
diff --git a/drivers/rtc/rtc-jz4740.c b/drivers/rtc/rtc-jz4740.c
index c383719292c7..59d279e3e6f5 100644
--- a/drivers/rtc/rtc-jz4740.c
+++ b/drivers/rtc/rtc-jz4740.c
@@ -6,12 +6,15 @@
*/
#include <linux/clk.h>
+#include <linux/clk-provider.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_wakeirq.h>
+#include <linux/property.h>
#include <linux/reboot.h>
#include <linux/rtc.h>
#include <linux/slab.h>
@@ -25,6 +28,7 @@
#define JZ_REG_RTC_WAKEUP_FILTER 0x24
#define JZ_REG_RTC_RESET_COUNTER 0x28
#define JZ_REG_RTC_SCRATCHPAD 0x34
+#define JZ_REG_RTC_CKPCR 0x40
/* The following are present on the jz4780 */
#define JZ_REG_RTC_WENR 0x3C
@@ -44,6 +48,9 @@
#define JZ_RTC_WAKEUP_FILTER_MASK 0x0000FFE0
#define JZ_RTC_RESET_COUNTER_MASK 0x00000FE0
+#define JZ_RTC_CKPCR_CK32PULL_DIS BIT(4)
+#define JZ_RTC_CKPCR_CK32CTL_EN (BIT(2) | BIT(1))
+
enum jz4740_rtc_type {
ID_JZ4740,
ID_JZ4760,
@@ -56,6 +63,8 @@ struct jz4740_rtc {
struct rtc_device *rtc;
+ struct clk_hw clk32k;
+
spinlock_t lock;
};
@@ -69,19 +78,15 @@ static inline uint32_t jz4740_rtc_reg_read(struct jz4740_rtc *rtc, size_t reg)
static int jz4740_rtc_wait_write_ready(struct jz4740_rtc *rtc)
{
uint32_t ctrl;
- int timeout = 10000;
- do {
- ctrl = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_CTRL);
- } while (!(ctrl & JZ_RTC_CTRL_WRDY) && --timeout);
-
- return timeout ? 0 : -EIO;
+ return readl_poll_timeout(rtc->base + JZ_REG_RTC_CTRL, ctrl,
+ ctrl & JZ_RTC_CTRL_WRDY, 0, 1000);
}
static inline int jz4780_rtc_enable_write(struct jz4740_rtc *rtc)
{
uint32_t ctrl;
- int ret, timeout = 10000;
+ int ret;
ret = jz4740_rtc_wait_write_ready(rtc);
if (ret != 0)
@@ -89,11 +94,8 @@ static inline int jz4780_rtc_enable_write(struct jz4740_rtc *rtc)
writel(JZ_RTC_WENR_MAGIC, rtc->base + JZ_REG_RTC_WENR);
- do {
- ctrl = readl(rtc->base + JZ_REG_RTC_WENR);
- } while (!(ctrl & JZ_RTC_WENR_WEN) && --timeout);
-
- return timeout ? 0 : -EIO;
+ return readl_poll_timeout(rtc->base + JZ_REG_RTC_WENR, ctrl,
+ ctrl & JZ_RTC_WENR_WEN, 0, 1000);
}
static inline int jz4740_rtc_reg_write(struct jz4740_rtc *rtc, size_t reg,
@@ -260,6 +262,7 @@ static void jz4740_rtc_power_off(void)
static const struct of_device_id jz4740_rtc_of_match[] = {
{ .compatible = "ingenic,jz4740-rtc", .data = (void *)ID_JZ4740 },
{ .compatible = "ingenic,jz4760-rtc", .data = (void *)ID_JZ4760 },
+ { .compatible = "ingenic,jz4770-rtc", .data = (void *)ID_JZ4780 },
{ .compatible = "ingenic,jz4780-rtc", .data = (void *)ID_JZ4780 },
{},
};
@@ -301,6 +304,38 @@ static void jz4740_rtc_set_wakeup_params(struct jz4740_rtc *rtc,
jz4740_rtc_reg_write(rtc, JZ_REG_RTC_RESET_COUNTER, reset_ticks);
}
+static int jz4740_rtc_clk32k_enable(struct clk_hw *hw)
+{
+ struct jz4740_rtc *rtc = container_of(hw, struct jz4740_rtc, clk32k);
+
+ return jz4740_rtc_reg_write(rtc, JZ_REG_RTC_CKPCR,
+ JZ_RTC_CKPCR_CK32PULL_DIS |
+ JZ_RTC_CKPCR_CK32CTL_EN);
+}
+
+static void jz4740_rtc_clk32k_disable(struct clk_hw *hw)
+{
+ struct jz4740_rtc *rtc = container_of(hw, struct jz4740_rtc, clk32k);
+
+ jz4740_rtc_reg_write(rtc, JZ_REG_RTC_CKPCR, 0);
+}
+
+static int jz4740_rtc_clk32k_is_enabled(struct clk_hw *hw)
+{
+ struct jz4740_rtc *rtc = container_of(hw, struct jz4740_rtc, clk32k);
+ u32 ckpcr;
+
+ ckpcr = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_CKPCR);
+
+ return !!(ckpcr & JZ_RTC_CKPCR_CK32CTL_EN);
+}
+
+static const struct clk_ops jz4740_rtc_clk32k_ops = {
+ .enable = jz4740_rtc_clk32k_enable,
+ .disable = jz4740_rtc_clk32k_disable,
+ .is_enabled = jz4740_rtc_clk32k_is_enabled,
+};
+
static int jz4740_rtc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -335,17 +370,13 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
device_init_wakeup(dev, 1);
ret = dev_pm_set_wake_irq(dev, irq);
- if (ret) {
- dev_err(dev, "Failed to set wake irq: %d\n", ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to set wake irq\n");
rtc->rtc = devm_rtc_allocate_device(dev);
- if (IS_ERR(rtc->rtc)) {
- ret = PTR_ERR(rtc->rtc);
- dev_err(dev, "Failed to allocate rtc device: %d\n", ret);
- return ret;
- }
+ if (IS_ERR(rtc->rtc))
+ return dev_err_probe(dev, PTR_ERR(rtc->rtc),
+ "Failed to allocate rtc device\n");
rtc->rtc->ops = &jz4740_rtc_ops;
rtc->rtc->range_max = U32_MAX;
@@ -362,10 +393,8 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
ret = devm_request_irq(dev, irq, jz4740_rtc_irq, 0,
pdev->name, rtc);
- if (ret) {
- dev_err(dev, "Failed to request rtc irq: %d\n", ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to request rtc irq\n");
if (of_device_is_system_power_controller(np)) {
dev_for_power_off = dev;
@@ -376,6 +405,21 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
dev_warn(dev, "Poweroff handler already present!\n");
}
+ if (device_property_present(dev, "#clock-cells")) {
+ rtc->clk32k.init = CLK_HW_INIT_HW("clk32k", __clk_get_hw(clk),
+ &jz4740_rtc_clk32k_ops, 0);
+
+ ret = devm_clk_hw_register(dev, &rtc->clk32k);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Unable to register clk32k clock\n");
+
+ ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, &rtc->clk32k);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Unable to register clk32k clock provider\n");
+ }
+
return 0;
}
diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c
index 494052dbd39f..c1963f7c424d 100644
--- a/drivers/rtc/rtc-m41t80.c
+++ b/drivers/rtc/rtc-m41t80.c
@@ -914,9 +914,14 @@ static int m41t80_probe(struct i2c_client *client)
"wakeup-source");
#endif
if (client->irq > 0) {
+ unsigned long irqflags = IRQF_TRIGGER_LOW;
+
+ if (dev_fwnode(&client->dev))
+ irqflags = 0;
+
rc = devm_request_threaded_irq(&client->dev, client->irq,
NULL, m41t80_handle_irq,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ irqflags | IRQF_ONESHOT,
"m41t80", client);
if (rc) {
dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n");
diff --git a/drivers/rtc/rtc-max8907.c b/drivers/rtc/rtc-max8907.c
index db3495d10274..af97140dd00a 100644
--- a/drivers/rtc/rtc-max8907.c
+++ b/drivers/rtc/rtc-max8907.c
@@ -9,7 +9,6 @@
*/
#include <linux/bcd.h>
-#include <linux/i2c.h>
#include <linux/mfd/max8907.h>
#include <linux/module.h>
#include <linux/platform_device.h>
diff --git a/drivers/rtc/rtc-moxart.c b/drivers/rtc/rtc-moxart.c
index 6b24ac9e1cfa..2247dd39ee4b 100644
--- a/drivers/rtc/rtc-moxart.c
+++ b/drivers/rtc/rtc-moxart.c
@@ -10,14 +10,15 @@
* Moxa Technology Co., Ltd. <www.moxa.com>
*/
+#include <linux/err.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/rtc.h>
#include <linux/platform_device.h>
#include <linux/module.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
+#include <linux/mod_devicetable.h>
+#include <linux/gpio/consumer.h>
#define GPIO_RTC_RESERVED 0x0C
#define GPIO_RTC_DATA_SET 0x10
@@ -55,7 +56,9 @@
struct moxart_rtc {
struct rtc_device *rtc;
spinlock_t rtc_lock;
- int gpio_data, gpio_sclk, gpio_reset;
+ struct gpio_desc *gpio_data;
+ struct gpio_desc *gpio_sclk;
+ struct gpio_desc *gpio_reset;
};
static int day_of_year[12] = { 0, 31, 59, 90, 120, 151, 181,
@@ -67,10 +70,10 @@ static void moxart_rtc_write_byte(struct device *dev, u8 data)
int i;
for (i = 0; i < 8; i++, data >>= 1) {
- gpio_set_value(moxart_rtc->gpio_sclk, 0);
- gpio_set_value(moxart_rtc->gpio_data, ((data & 1) == 1));
+ gpiod_set_value(moxart_rtc->gpio_sclk, 0);
+ gpiod_set_value(moxart_rtc->gpio_data, ((data & 1) == 1));
udelay(GPIO_RTC_DELAY_TIME);
- gpio_set_value(moxart_rtc->gpio_sclk, 1);
+ gpiod_set_value(moxart_rtc->gpio_sclk, 1);
udelay(GPIO_RTC_DELAY_TIME);
}
}
@@ -82,11 +85,11 @@ static u8 moxart_rtc_read_byte(struct device *dev)
u8 data = 0;
for (i = 0; i < 8; i++) {
- gpio_set_value(moxart_rtc->gpio_sclk, 0);
+ gpiod_set_value(moxart_rtc->gpio_sclk, 0);
udelay(GPIO_RTC_DELAY_TIME);
- gpio_set_value(moxart_rtc->gpio_sclk, 1);
+ gpiod_set_value(moxart_rtc->gpio_sclk, 1);
udelay(GPIO_RTC_DELAY_TIME);
- if (gpio_get_value(moxart_rtc->gpio_data))
+ if (gpiod_get_value(moxart_rtc->gpio_data))
data |= (1 << i);
udelay(GPIO_RTC_DELAY_TIME);
}
@@ -101,15 +104,15 @@ static u8 moxart_rtc_read_register(struct device *dev, u8 cmd)
local_irq_save(flags);
- gpio_direction_output(moxart_rtc->gpio_data, 0);
- gpio_set_value(moxart_rtc->gpio_reset, 1);
+ gpiod_direction_output(moxart_rtc->gpio_data, 0);
+ gpiod_set_value(moxart_rtc->gpio_reset, 1);
udelay(GPIO_RTC_DELAY_TIME);
moxart_rtc_write_byte(dev, cmd);
- gpio_direction_input(moxart_rtc->gpio_data);
+ gpiod_direction_input(moxart_rtc->gpio_data);
udelay(GPIO_RTC_DELAY_TIME);
data = moxart_rtc_read_byte(dev);
- gpio_set_value(moxart_rtc->gpio_sclk, 0);
- gpio_set_value(moxart_rtc->gpio_reset, 0);
+ gpiod_set_value(moxart_rtc->gpio_sclk, 0);
+ gpiod_set_value(moxart_rtc->gpio_reset, 0);
udelay(GPIO_RTC_DELAY_TIME);
local_irq_restore(flags);
@@ -124,13 +127,13 @@ static void moxart_rtc_write_register(struct device *dev, u8 cmd, u8 data)
local_irq_save(flags);
- gpio_direction_output(moxart_rtc->gpio_data, 0);
- gpio_set_value(moxart_rtc->gpio_reset, 1);
+ gpiod_direction_output(moxart_rtc->gpio_data, 0);
+ gpiod_set_value(moxart_rtc->gpio_reset, 1);
udelay(GPIO_RTC_DELAY_TIME);
moxart_rtc_write_byte(dev, cmd);
moxart_rtc_write_byte(dev, data);
- gpio_set_value(moxart_rtc->gpio_sclk, 0);
- gpio_set_value(moxart_rtc->gpio_reset, 0);
+ gpiod_set_value(moxart_rtc->gpio_sclk, 0);
+ gpiod_set_value(moxart_rtc->gpio_reset, 0);
udelay(GPIO_RTC_DELAY_TIME);
local_irq_restore(flags);
@@ -247,53 +250,33 @@ static int moxart_rtc_probe(struct platform_device *pdev)
if (!moxart_rtc)
return -ENOMEM;
- moxart_rtc->gpio_data = of_get_named_gpio(pdev->dev.of_node,
- "gpio-rtc-data", 0);
- if (!gpio_is_valid(moxart_rtc->gpio_data)) {
- dev_err(&pdev->dev, "invalid gpio (data): %d\n",
- moxart_rtc->gpio_data);
- return moxart_rtc->gpio_data;
- }
-
- moxart_rtc->gpio_sclk = of_get_named_gpio(pdev->dev.of_node,
- "gpio-rtc-sclk", 0);
- if (!gpio_is_valid(moxart_rtc->gpio_sclk)) {
- dev_err(&pdev->dev, "invalid gpio (sclk): %d\n",
- moxart_rtc->gpio_sclk);
- return moxart_rtc->gpio_sclk;
- }
-
- moxart_rtc->gpio_reset = of_get_named_gpio(pdev->dev.of_node,
- "gpio-rtc-reset", 0);
- if (!gpio_is_valid(moxart_rtc->gpio_reset)) {
- dev_err(&pdev->dev, "invalid gpio (reset): %d\n",
- moxart_rtc->gpio_reset);
- return moxart_rtc->gpio_reset;
- }
-
- spin_lock_init(&moxart_rtc->rtc_lock);
- platform_set_drvdata(pdev, moxart_rtc);
-
- ret = devm_gpio_request(&pdev->dev, moxart_rtc->gpio_data, "rtc_data");
+ moxart_rtc->gpio_data = devm_gpiod_get(&pdev->dev, "rtc-data",
+ GPIOD_IN);
+ ret = PTR_ERR_OR_ZERO(moxart_rtc->gpio_data);
if (ret) {
- dev_err(&pdev->dev, "can't get rtc_data gpio\n");
+ dev_err(&pdev->dev, "can't get rtc data gpio: %d\n", ret);
return ret;
}
- ret = devm_gpio_request_one(&pdev->dev, moxart_rtc->gpio_sclk,
- GPIOF_DIR_OUT, "rtc_sclk");
+ moxart_rtc->gpio_sclk = devm_gpiod_get(&pdev->dev, "rtc-sclk",
+ GPIOD_ASIS);
+ ret = PTR_ERR_OR_ZERO(moxart_rtc->gpio_sclk);
if (ret) {
- dev_err(&pdev->dev, "can't get rtc_sclk gpio\n");
+ dev_err(&pdev->dev, "can't get rtc sclk gpio: %d\n", ret);
return ret;
}
- ret = devm_gpio_request_one(&pdev->dev, moxart_rtc->gpio_reset,
- GPIOF_DIR_OUT, "rtc_reset");
+ moxart_rtc->gpio_reset = devm_gpiod_get(&pdev->dev, "rtc-reset",
+ GPIOD_ASIS);
+ ret = PTR_ERR_OR_ZERO(moxart_rtc->gpio_reset);
if (ret) {
- dev_err(&pdev->dev, "can't get rtc_reset gpio\n");
+ dev_err(&pdev->dev, "can't get rtc reset gpio: %d\n", ret);
return ret;
}
+ spin_lock_init(&moxart_rtc->rtc_lock);
+ platform_set_drvdata(pdev, moxart_rtc);
+
moxart_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&moxart_rtc_ops,
THIS_MODULE);
diff --git a/drivers/rtc/rtc-nxp-bbnsm.c b/drivers/rtc/rtc-nxp-bbnsm.c
new file mode 100644
index 000000000000..acbfbeb8b070
--- /dev/null
+++ b/drivers/rtc/rtc-nxp-bbnsm.c
@@ -0,0 +1,226 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Copyright 2022 NXP.
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_wakeirq.h>
+#include <linux/regmap.h>
+#include <linux/rtc.h>
+
+#define BBNSM_CTRL 0x8
+#define BBNSM_INT_EN 0x10
+#define BBNSM_EVENTS 0x14
+#define BBNSM_RTC_LS 0x40
+#define BBNSM_RTC_MS 0x44
+#define BBNSM_TA 0x50
+
+#define RTC_EN 0x2
+#define RTC_EN_MSK 0x3
+#define TA_EN (0x2 << 2)
+#define TA_DIS (0x1 << 2)
+#define TA_EN_MSK (0x3 << 2)
+#define RTC_INT_EN 0x2
+#define TA_INT_EN (0x2 << 2)
+
+#define BBNSM_EVENT_TA (0x2 << 2)
+
+#define CNTR_TO_SECS_SH 15
+
+struct bbnsm_rtc {
+ struct rtc_device *rtc;
+ struct regmap *regmap;
+ int irq;
+ struct clk *clk;
+};
+
+static u32 bbnsm_read_counter(struct bbnsm_rtc *bbnsm)
+{
+ u32 rtc_msb, rtc_lsb;
+ unsigned int timeout = 100;
+ u32 time;
+ u32 tmp = 0;
+
+ do {
+ time = tmp;
+ /* read the msb */
+ regmap_read(bbnsm->regmap, BBNSM_RTC_MS, &rtc_msb);
+ /* read the lsb */
+ regmap_read(bbnsm->regmap, BBNSM_RTC_LS, &rtc_lsb);
+ /* convert to seconds */
+ tmp = (rtc_msb << 17) | (rtc_lsb >> 15);
+ } while (tmp != time && --timeout);
+
+ return time;
+}
+
+static int bbnsm_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct bbnsm_rtc *bbnsm = dev_get_drvdata(dev);
+ unsigned long time;
+ u32 val;
+
+ regmap_read(bbnsm->regmap, BBNSM_CTRL, &val);
+ if ((val & RTC_EN_MSK) != RTC_EN)
+ return -EINVAL;
+
+ time = bbnsm_read_counter(bbnsm);
+ rtc_time64_to_tm(time, tm);
+
+ return 0;
+}
+
+static int bbnsm_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct bbnsm_rtc *bbnsm = dev_get_drvdata(dev);
+ unsigned long time = rtc_tm_to_time64(tm);
+
+ /* disable the RTC first */
+ regmap_update_bits(bbnsm->regmap, BBNSM_CTRL, RTC_EN_MSK, 0);
+
+ /* write the 32bit sec time to 47 bit timer counter, leaving 15 LSBs blank */
+ regmap_write(bbnsm->regmap, BBNSM_RTC_LS, time << CNTR_TO_SECS_SH);
+ regmap_write(bbnsm->regmap, BBNSM_RTC_MS, time >> (32 - CNTR_TO_SECS_SH));
+
+ /* Enable the RTC again */
+ regmap_update_bits(bbnsm->regmap, BBNSM_CTRL, RTC_EN_MSK, RTC_EN);
+
+ return 0;
+}
+
+static int bbnsm_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct bbnsm_rtc *bbnsm = dev_get_drvdata(dev);
+ u32 bbnsm_events, bbnsm_ta;
+
+ regmap_read(bbnsm->regmap, BBNSM_TA, &bbnsm_ta);
+ rtc_time64_to_tm(bbnsm_ta, &alrm->time);
+
+ regmap_read(bbnsm->regmap, BBNSM_EVENTS, &bbnsm_events);
+ alrm->pending = (bbnsm_events & BBNSM_EVENT_TA) ? 1 : 0;
+
+ return 0;
+}
+
+static int bbnsm_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
+{
+ struct bbnsm_rtc *bbnsm = dev_get_drvdata(dev);
+
+ /* enable the alarm event */
+ regmap_update_bits(bbnsm->regmap, BBNSM_CTRL, TA_EN_MSK, enable ? TA_EN : TA_DIS);
+ /* enable the alarm interrupt */
+ regmap_update_bits(bbnsm->regmap, BBNSM_INT_EN, TA_EN_MSK, enable ? TA_EN : TA_DIS);
+
+ return 0;
+}
+
+static int bbnsm_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct bbnsm_rtc *bbnsm = dev_get_drvdata(dev);
+ unsigned long time = rtc_tm_to_time64(&alrm->time);
+
+ /* disable the alarm */
+ regmap_update_bits(bbnsm->regmap, BBNSM_CTRL, TA_EN, TA_EN);
+
+ /* write the seconds to TA */
+ regmap_write(bbnsm->regmap, BBNSM_TA, time);
+
+ return bbnsm_rtc_alarm_irq_enable(dev, alrm->enabled);
+}
+
+static const struct rtc_class_ops bbnsm_rtc_ops = {
+ .read_time = bbnsm_rtc_read_time,
+ .set_time = bbnsm_rtc_set_time,
+ .read_alarm = bbnsm_rtc_read_alarm,
+ .set_alarm = bbnsm_rtc_set_alarm,
+ .alarm_irq_enable = bbnsm_rtc_alarm_irq_enable,
+};
+
+static irqreturn_t bbnsm_rtc_irq_handler(int irq, void *dev_id)
+{
+ struct device *dev = dev_id;
+ struct bbnsm_rtc *bbnsm = dev_get_drvdata(dev);
+ u32 val;
+
+ regmap_read(bbnsm->regmap, BBNSM_EVENTS, &val);
+ if (val & BBNSM_EVENT_TA) {
+ bbnsm_rtc_alarm_irq_enable(dev, false);
+ /* clear the alarm event */
+ regmap_write_bits(bbnsm->regmap, BBNSM_EVENTS, TA_EN_MSK, BBNSM_EVENT_TA);
+ rtc_update_irq(bbnsm->rtc, 1, RTC_AF | RTC_IRQF);
+
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static int bbnsm_rtc_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct bbnsm_rtc *bbnsm;
+ int ret;
+
+ bbnsm = devm_kzalloc(&pdev->dev, sizeof(*bbnsm), GFP_KERNEL);
+ if (!bbnsm)
+ return -ENOMEM;
+
+ bbnsm->rtc = devm_rtc_allocate_device(&pdev->dev);
+ if (IS_ERR(bbnsm->rtc))
+ return PTR_ERR(bbnsm->rtc);
+
+ bbnsm->regmap = syscon_node_to_regmap(np->parent);
+ if (IS_ERR(bbnsm->regmap)) {
+ dev_dbg(&pdev->dev, "bbnsm get regmap failed\n");
+ return PTR_ERR(bbnsm->regmap);
+ }
+
+ bbnsm->irq = platform_get_irq(pdev, 0);
+ if (bbnsm->irq < 0)
+ return bbnsm->irq;
+
+ platform_set_drvdata(pdev, bbnsm);
+
+ /* clear all the pending events */
+ regmap_write(bbnsm->regmap, BBNSM_EVENTS, 0x7A);
+
+ device_init_wakeup(&pdev->dev, true);
+ dev_pm_set_wake_irq(&pdev->dev, bbnsm->irq);
+
+ ret = devm_request_irq(&pdev->dev, bbnsm->irq, bbnsm_rtc_irq_handler,
+ IRQF_SHARED, "rtc alarm", &pdev->dev);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request irq %d: %d\n",
+ bbnsm->irq, ret);
+ return ret;
+ }
+
+ bbnsm->rtc->ops = &bbnsm_rtc_ops;
+ bbnsm->rtc->range_max = U32_MAX;
+
+ return devm_rtc_register_device(bbnsm->rtc);
+}
+
+static const struct of_device_id bbnsm_dt_ids[] = {
+ { .compatible = "nxp,imx93-bbnsm-rtc" },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, bbnsm_dt_ids);
+
+static struct platform_driver bbnsm_rtc_driver = {
+ .driver = {
+ .name = "bbnsm_rtc",
+ .of_match_table = bbnsm_dt_ids,
+ },
+ .probe = bbnsm_rtc_probe,
+};
+module_platform_driver(bbnsm_rtc_driver);
+
+MODULE_AUTHOR("Jacky Bai <ping.bai@nxp.com>");
+MODULE_DESCRIPTION("NXP BBNSM RTC Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c
index e13b5e695d06..e714661e61a9 100644
--- a/drivers/rtc/rtc-pcf2123.c
+++ b/drivers/rtc/rtc-pcf2123.c
@@ -413,9 +413,14 @@ static int pcf2123_probe(struct spi_device *spi)
/* Register alarm irq */
if (spi->irq > 0) {
+ unsigned long irqflags = IRQF_TRIGGER_LOW;
+
+ if (dev_fwnode(&spi->dev))
+ irqflags = 0;
+
ret = devm_request_threaded_irq(&spi->dev, spi->irq, NULL,
pcf2123_rtc_irq,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ irqflags | IRQF_ONESHOT,
pcf2123_driver.driver.name, &spi->dev);
if (!ret)
device_init_wakeup(&spi->dev, true);
diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c
index 754e03984f98..71a456355981 100644
--- a/drivers/rtc/rtc-pcf85063.c
+++ b/drivers/rtc/rtc-pcf85063.c
@@ -621,9 +621,14 @@ static int pcf85063_probe(struct i2c_client *client)
clear_bit(RTC_FEATURE_ALARM, pcf85063->rtc->features);
if (config->has_alarms && client->irq > 0) {
+ unsigned long irqflags = IRQF_TRIGGER_LOW;
+
+ if (dev_fwnode(&client->dev))
+ irqflags = 0;
+
err = devm_request_threaded_irq(&client->dev, client->irq,
NULL, pcf85063_rtc_handle_irq,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ irqflags | IRQF_ONESHOT,
"pcf85063", pcf85063);
if (err) {
dev_warn(&pcf85063->rtc->dev,
diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c
index 92de99f11a7a..2e111cdb94f7 100644
--- a/drivers/rtc/rtc-pcf8523.c
+++ b/drivers/rtc/rtc-pcf8523.c
@@ -445,13 +445,18 @@ static int pcf8523_probe(struct i2c_client *client)
clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features);
if (client->irq > 0) {
+ unsigned long irqflags = IRQF_TRIGGER_LOW;
+
+ if (dev_fwnode(&client->dev))
+ irqflags = 0;
+
err = regmap_write(pcf8523->regmap, PCF8523_TMR_CLKOUT_CTRL, 0x38);
if (err < 0)
return err;
err = devm_request_threaded_irq(&client->dev, client->irq,
NULL, pcf8523_irq,
- IRQF_SHARED | IRQF_ONESHOT | IRQF_TRIGGER_LOW,
+ IRQF_SHARED | IRQF_ONESHOT | irqflags,
dev_name(&rtc->dev), pcf8523);
if (err)
return err;
diff --git a/drivers/rtc/rtc-pcf85363.c b/drivers/rtc/rtc-pcf85363.c
index c05b722f0060..8958eadf1c3e 100644
--- a/drivers/rtc/rtc-pcf85363.c
+++ b/drivers/rtc/rtc-pcf85363.c
@@ -101,6 +101,10 @@
#define PIN_IO_INTA_OUT 2
#define PIN_IO_INTA_HIZ 3
+#define OSC_CAP_SEL GENMASK(1, 0)
+#define OSC_CAP_6000 0x01
+#define OSC_CAP_12500 0x02
+
#define STOP_EN_STOP BIT(0)
#define RESET_CPR 0xa4
@@ -117,6 +121,32 @@ struct pcf85x63_config {
unsigned int num_nvram;
};
+static int pcf85363_load_capacitance(struct pcf85363 *pcf85363, struct device_node *node)
+{
+ u32 load = 7000;
+ u8 value = 0;
+
+ of_property_read_u32(node, "quartz-load-femtofarads", &load);
+
+ switch (load) {
+ default:
+ dev_warn(&pcf85363->rtc->dev, "Unknown quartz-load-femtofarads value: %d. Assuming 7000",
+ load);
+ fallthrough;
+ case 7000:
+ break;
+ case 6000:
+ value = OSC_CAP_6000;
+ break;
+ case 12500:
+ value = OSC_CAP_12500;
+ break;
+ }
+
+ return regmap_update_bits(pcf85363->regmap, CTRL_OSCILLATOR,
+ OSC_CAP_SEL, value);
+}
+
static int pcf85363_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct pcf85363 *pcf85363 = dev_get_drvdata(dev);
@@ -372,7 +402,7 @@ static int pcf85363_probe(struct i2c_client *client)
.reg_write = pcf85363_nvram_write,
},
};
- int ret, i;
+ int ret, i, err;
if (data)
config = data;
@@ -394,18 +424,28 @@ static int pcf85363_probe(struct i2c_client *client)
if (IS_ERR(pcf85363->rtc))
return PTR_ERR(pcf85363->rtc);
+ err = pcf85363_load_capacitance(pcf85363, client->dev.of_node);
+ if (err < 0)
+ dev_warn(&client->dev, "failed to set xtal load capacitance: %d",
+ err);
+
pcf85363->rtc->ops = &rtc_ops;
pcf85363->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
pcf85363->rtc->range_max = RTC_TIMESTAMP_END_2099;
clear_bit(RTC_FEATURE_ALARM, pcf85363->rtc->features);
if (client->irq > 0) {
+ unsigned long irqflags = IRQF_TRIGGER_LOW;
+
+ if (dev_fwnode(&client->dev))
+ irqflags = 0;
+
regmap_write(pcf85363->regmap, CTRL_FLAGS, 0);
regmap_update_bits(pcf85363->regmap, CTRL_PIN_IO,
PIN_IO_INTA_OUT, PIN_IO_INTAPM);
ret = devm_request_threaded_irq(&client->dev, client->irq,
NULL, pcf85363_rtc_handle_irq,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ irqflags | IRQF_ONESHOT,
"pcf85363", client);
if (ret)
dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n");
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
index 0a7fd9478465..7e720472213c 100644
--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -558,9 +558,14 @@ static int pcf8563_probe(struct i2c_client *client)
pcf8563->rtc->set_start_time = true;
if (client->irq > 0) {
+ unsigned long irqflags = IRQF_TRIGGER_LOW;
+
+ if (dev_fwnode(&client->dev))
+ irqflags = 0;
+
err = devm_request_threaded_irq(&client->dev, client->irq,
NULL, pcf8563_irq,
- IRQF_SHARED | IRQF_ONESHOT | IRQF_TRIGGER_LOW,
+ IRQF_SHARED | IRQF_ONESHOT | irqflags,
pcf8563_driver.driver.name, client);
if (err) {
dev_err(&client->dev, "unable to request IRQ %d\n",
diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c
index 716e5d9ad74d..372494e82f40 100644
--- a/drivers/rtc/rtc-pm8xxx.c
+++ b/drivers/rtc/rtc-pm8xxx.c
@@ -1,8 +1,13 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/*
+ * pm8xxx RTC driver
+ *
+ * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2023, Linaro Limited
*/
#include <linux/of.h>
#include <linux/module.h>
+#include <linux/nvmem-consumer.h>
#include <linux/init.h>
#include <linux/rtc.h>
#include <linux/platform_device.h>
@@ -12,11 +17,7 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
-/* RTC Register offsets from RTC CTRL REG */
-#define PM8XXX_ALARM_CTRL_OFFSET 0x01
-#define PM8XXX_RTC_WRITE_OFFSET 0x02
-#define PM8XXX_RTC_READ_OFFSET 0x06
-#define PM8XXX_ALARM_RW_OFFSET 0x0A
+#include <asm/unaligned.h>
/* RTC_CTRL register bit fields */
#define PM8xxx_RTC_ENABLE BIT(7)
@@ -27,13 +28,13 @@
/**
* struct pm8xxx_rtc_regs - describe RTC registers per PMIC versions
- * @ctrl: base address of control register
- * @write: base address of write register
- * @read: base address of read register
- * @alarm_ctrl: base address of alarm control register
- * @alarm_ctrl2: base address of alarm control2 register
- * @alarm_rw: base address of alarm read-write register
- * @alarm_en: alarm enable mask
+ * @ctrl: address of control register
+ * @write: base address of write registers
+ * @read: base address of read registers
+ * @alarm_ctrl: address of alarm control register
+ * @alarm_ctrl2: address of alarm control2 register
+ * @alarm_rw: base address of alarm read-write registers
+ * @alarm_en: alarm enable mask
*/
struct pm8xxx_rtc_regs {
unsigned int ctrl;
@@ -46,25 +47,135 @@ struct pm8xxx_rtc_regs {
};
/**
- * struct pm8xxx_rtc - rtc driver internal structure
- * @rtc: rtc device for this driver.
- * @regmap: regmap used to access RTC registers
- * @allow_set_time: indicates whether writing to the RTC is allowed
- * @rtc_alarm_irq: rtc alarm irq number.
- * @regs: rtc registers description.
- * @rtc_dev: device structure.
- * @ctrl_reg_lock: spinlock protecting access to ctrl_reg.
+ * struct pm8xxx_rtc - RTC driver internal structure
+ * @rtc: RTC device
+ * @regmap: regmap used to access registers
+ * @allow_set_time: whether the time can be set
+ * @alarm_irq: alarm irq number
+ * @regs: register description
+ * @dev: device structure
+ * @nvmem_cell: nvmem cell for offset
+ * @offset: offset from epoch in seconds
*/
struct pm8xxx_rtc {
struct rtc_device *rtc;
struct regmap *regmap;
bool allow_set_time;
- int rtc_alarm_irq;
+ int alarm_irq;
const struct pm8xxx_rtc_regs *regs;
- struct device *rtc_dev;
- spinlock_t ctrl_reg_lock;
+ struct device *dev;
+ struct nvmem_cell *nvmem_cell;
+ u32 offset;
};
+static int pm8xxx_rtc_read_nvmem_offset(struct pm8xxx_rtc *rtc_dd)
+{
+ size_t len;
+ void *buf;
+ int rc;
+
+ buf = nvmem_cell_read(rtc_dd->nvmem_cell, &len);
+ if (IS_ERR(buf)) {
+ rc = PTR_ERR(buf);
+ dev_dbg(rtc_dd->dev, "failed to read nvmem offset: %d\n", rc);
+ return rc;
+ }
+
+ if (len != sizeof(u32)) {
+ dev_dbg(rtc_dd->dev, "unexpected nvmem cell size %zu\n", len);
+ kfree(buf);
+ return -EINVAL;
+ }
+
+ rtc_dd->offset = get_unaligned_le32(buf);
+
+ kfree(buf);
+
+ return 0;
+}
+
+static int pm8xxx_rtc_write_nvmem_offset(struct pm8xxx_rtc *rtc_dd, u32 offset)
+{
+ u8 buf[sizeof(u32)];
+ int rc;
+
+ put_unaligned_le32(offset, buf);
+
+ rc = nvmem_cell_write(rtc_dd->nvmem_cell, buf, sizeof(buf));
+ if (rc < 0) {
+ dev_dbg(rtc_dd->dev, "failed to write nvmem offset: %d\n", rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int pm8xxx_rtc_read_offset(struct pm8xxx_rtc *rtc_dd)
+{
+ if (!rtc_dd->nvmem_cell)
+ return 0;
+
+ return pm8xxx_rtc_read_nvmem_offset(rtc_dd);
+}
+
+static int pm8xxx_rtc_read_raw(struct pm8xxx_rtc *rtc_dd, u32 *secs)
+{
+ const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
+ u8 value[NUM_8_BIT_RTC_REGS];
+ unsigned int reg;
+ int rc;
+
+ rc = regmap_bulk_read(rtc_dd->regmap, regs->read, value, sizeof(value));
+ if (rc)
+ return rc;
+
+ /*
+ * Read the LSB again and check if there has been a carry over.
+ * If there has, redo the read operation.
+ */
+ rc = regmap_read(rtc_dd->regmap, regs->read, &reg);
+ if (rc < 0)
+ return rc;
+
+ if (reg < value[0]) {
+ rc = regmap_bulk_read(rtc_dd->regmap, regs->read, value,
+ sizeof(value));
+ if (rc)
+ return rc;
+ }
+
+ *secs = get_unaligned_le32(value);
+
+ return 0;
+}
+
+static int pm8xxx_rtc_update_offset(struct pm8xxx_rtc *rtc_dd, u32 secs)
+{
+ u32 raw_secs;
+ u32 offset;
+ int rc;
+
+ if (!rtc_dd->nvmem_cell)
+ return -ENODEV;
+
+ rc = pm8xxx_rtc_read_raw(rtc_dd, &raw_secs);
+ if (rc)
+ return rc;
+
+ offset = secs - raw_secs;
+
+ if (offset == rtc_dd->offset)
+ return 0;
+
+ rc = pm8xxx_rtc_write_nvmem_offset(rtc_dd, offset);
+ if (rc)
+ return rc;
+
+ rtc_dd->offset = offset;
+
+ return 0;
+}
+
/*
* Steps to write the RTC registers.
* 1. Disable alarm if enabled.
@@ -74,269 +185,186 @@ struct pm8xxx_rtc {
* 5. Enable rtc if disabled in step 2.
* 6. Enable alarm if disabled in step 1.
*/
-static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm)
+static int __pm8xxx_rtc_set_time(struct pm8xxx_rtc *rtc_dd, u32 secs)
{
- int rc, i;
- unsigned long secs, irq_flags;
- u8 value[NUM_8_BIT_RTC_REGS], alarm_enabled = 0, rtc_disabled = 0;
- unsigned int ctrl_reg, rtc_ctrl_reg;
- struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
+ u8 value[NUM_8_BIT_RTC_REGS];
+ bool alarm_enabled;
+ int rc;
- if (!rtc_dd->allow_set_time)
- return -ENODEV;
-
- secs = rtc_tm_to_time64(tm);
-
- dev_dbg(dev, "Seconds value to be written to RTC = %lu\n", secs);
-
- for (i = 0; i < NUM_8_BIT_RTC_REGS; i++) {
- value[i] = secs & 0xFF;
- secs >>= 8;
- }
-
- spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags);
+ put_unaligned_le32(secs, value);
- rc = regmap_read(rtc_dd->regmap, regs->alarm_ctrl, &ctrl_reg);
+ rc = regmap_update_bits_check(rtc_dd->regmap, regs->alarm_ctrl,
+ regs->alarm_en, 0, &alarm_enabled);
if (rc)
- goto rtc_rw_fail;
-
- if (ctrl_reg & regs->alarm_en) {
- alarm_enabled = 1;
- ctrl_reg &= ~regs->alarm_en;
- rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl, ctrl_reg);
- if (rc) {
- dev_err(dev, "Write to RTC Alarm control register failed\n");
- goto rtc_rw_fail;
- }
- }
+ return rc;
- /* Disable RTC H/w before writing on RTC register */
- rc = regmap_read(rtc_dd->regmap, regs->ctrl, &rtc_ctrl_reg);
+ /* Disable RTC */
+ rc = regmap_update_bits(rtc_dd->regmap, regs->ctrl, PM8xxx_RTC_ENABLE, 0);
if (rc)
- goto rtc_rw_fail;
-
- if (rtc_ctrl_reg & PM8xxx_RTC_ENABLE) {
- rtc_disabled = 1;
- rtc_ctrl_reg &= ~PM8xxx_RTC_ENABLE;
- rc = regmap_write(rtc_dd->regmap, regs->ctrl, rtc_ctrl_reg);
- if (rc) {
- dev_err(dev, "Write to RTC control register failed\n");
- goto rtc_rw_fail;
- }
- }
+ return rc;
/* Write 0 to Byte[0] */
rc = regmap_write(rtc_dd->regmap, regs->write, 0);
- if (rc) {
- dev_err(dev, "Write to RTC write data register failed\n");
- goto rtc_rw_fail;
- }
+ if (rc)
+ return rc;
/* Write Byte[1], Byte[2], Byte[3] */
rc = regmap_bulk_write(rtc_dd->regmap, regs->write + 1,
&value[1], sizeof(value) - 1);
- if (rc) {
- dev_err(dev, "Write to RTC write data register failed\n");
- goto rtc_rw_fail;
- }
+ if (rc)
+ return rc;
/* Write Byte[0] */
rc = regmap_write(rtc_dd->regmap, regs->write, value[0]);
- if (rc) {
- dev_err(dev, "Write to RTC write data register failed\n");
- goto rtc_rw_fail;
- }
+ if (rc)
+ return rc;
- /* Enable RTC H/w after writing on RTC register */
- if (rtc_disabled) {
- rtc_ctrl_reg |= PM8xxx_RTC_ENABLE;
- rc = regmap_write(rtc_dd->regmap, regs->ctrl, rtc_ctrl_reg);
- if (rc) {
- dev_err(dev, "Write to RTC control register failed\n");
- goto rtc_rw_fail;
- }
- }
+ /* Enable RTC */
+ rc = regmap_update_bits(rtc_dd->regmap, regs->ctrl, PM8xxx_RTC_ENABLE,
+ PM8xxx_RTC_ENABLE);
+ if (rc)
+ return rc;
if (alarm_enabled) {
- ctrl_reg |= regs->alarm_en;
- rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl, ctrl_reg);
- if (rc) {
- dev_err(dev, "Write to RTC Alarm control register failed\n");
- goto rtc_rw_fail;
- }
+ rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl,
+ regs->alarm_en, regs->alarm_en);
+ if (rc)
+ return rc;
}
-rtc_rw_fail:
- spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
-
- return rc;
+ return 0;
}
-static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm)
+static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
- int rc;
- u8 value[NUM_8_BIT_RTC_REGS];
- unsigned long secs;
- unsigned int reg;
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
- const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
+ u32 secs;
+ int rc;
- rc = regmap_bulk_read(rtc_dd->regmap, regs->read, value, sizeof(value));
- if (rc) {
- dev_err(dev, "RTC read data register failed\n");
- return rc;
- }
+ secs = rtc_tm_to_time64(tm);
- /*
- * Read the LSB again and check if there has been a carry over.
- * If there is, redo the read operation.
- */
- rc = regmap_read(rtc_dd->regmap, regs->read, &reg);
- if (rc < 0) {
- dev_err(dev, "RTC read data register failed\n");
+ if (rtc_dd->allow_set_time)
+ rc = __pm8xxx_rtc_set_time(rtc_dd, secs);
+ else
+ rc = pm8xxx_rtc_update_offset(rtc_dd, secs);
+
+ if (rc)
return rc;
- }
- if (unlikely(reg < value[0])) {
- rc = regmap_bulk_read(rtc_dd->regmap, regs->read,
- value, sizeof(value));
- if (rc) {
- dev_err(dev, "RTC read data register failed\n");
- return rc;
- }
- }
+ dev_dbg(dev, "set time: %ptRd %ptRt (%u + %u)\n", tm, tm,
+ secs - rtc_dd->offset, rtc_dd->offset);
+ return 0;
+}
- secs = value[0] | (value[1] << 8) | (value[2] << 16) |
- ((unsigned long)value[3] << 24);
+static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
+ u32 secs;
+ int rc;
- rtc_time64_to_tm(secs, tm);
+ rc = pm8xxx_rtc_read_raw(rtc_dd, &secs);
+ if (rc)
+ return rc;
- dev_dbg(dev, "secs = %lu, h:m:s == %ptRt, y-m-d = %ptRdr\n", secs, tm, tm);
+ secs += rtc_dd->offset;
+ rtc_time64_to_tm(secs, tm);
+ dev_dbg(dev, "read time: %ptRd %ptRt (%u + %u)\n", tm, tm,
+ secs - rtc_dd->offset, rtc_dd->offset);
return 0;
}
static int pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
- int rc, i;
- u8 value[NUM_8_BIT_RTC_REGS];
- unsigned int ctrl_reg;
- unsigned long secs, irq_flags;
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
+ u8 value[NUM_8_BIT_RTC_REGS];
+ u32 secs;
+ int rc;
secs = rtc_tm_to_time64(&alarm->time);
+ secs -= rtc_dd->offset;
+ put_unaligned_le32(secs, value);
- for (i = 0; i < NUM_8_BIT_RTC_REGS; i++) {
- value[i] = secs & 0xFF;
- secs >>= 8;
- }
-
- spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags);
+ rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl,
+ regs->alarm_en, 0);
+ if (rc)
+ return rc;
rc = regmap_bulk_write(rtc_dd->regmap, regs->alarm_rw, value,
sizeof(value));
- if (rc) {
- dev_err(dev, "Write to RTC ALARM register failed\n");
- goto rtc_rw_fail;
- }
-
- rc = regmap_read(rtc_dd->regmap, regs->alarm_ctrl, &ctrl_reg);
if (rc)
- goto rtc_rw_fail;
-
- if (alarm->enabled)
- ctrl_reg |= regs->alarm_en;
- else
- ctrl_reg &= ~regs->alarm_en;
+ return rc;
- rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl, ctrl_reg);
- if (rc) {
- dev_err(dev, "Write to RTC alarm control register failed\n");
- goto rtc_rw_fail;
+ if (alarm->enabled) {
+ rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl,
+ regs->alarm_en, regs->alarm_en);
+ if (rc)
+ return rc;
}
- dev_dbg(dev, "Alarm Set for h:m:s=%ptRt, y-m-d=%ptRdr\n",
- &alarm->time, &alarm->time);
-rtc_rw_fail:
- spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
- return rc;
+ dev_dbg(dev, "set alarm: %ptRd %ptRt\n", &alarm->time, &alarm->time);
+
+ return 0;
}
static int pm8xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
- int rc;
- unsigned int ctrl_reg;
- u8 value[NUM_8_BIT_RTC_REGS];
- unsigned long secs;
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
+ u8 value[NUM_8_BIT_RTC_REGS];
+ unsigned int ctrl_reg;
+ u32 secs;
+ int rc;
rc = regmap_bulk_read(rtc_dd->regmap, regs->alarm_rw, value,
sizeof(value));
- if (rc) {
- dev_err(dev, "RTC alarm time read failed\n");
+ if (rc)
return rc;
- }
-
- secs = value[0] | (value[1] << 8) | (value[2] << 16) |
- ((unsigned long)value[3] << 24);
+ secs = get_unaligned_le32(value);
+ secs += rtc_dd->offset;
rtc_time64_to_tm(secs, &alarm->time);
rc = regmap_read(rtc_dd->regmap, regs->alarm_ctrl, &ctrl_reg);
- if (rc) {
- dev_err(dev, "Read from RTC alarm control register failed\n");
+ if (rc)
return rc;
- }
+
alarm->enabled = !!(ctrl_reg & PM8xxx_RTC_ALARM_ENABLE);
- dev_dbg(dev, "Alarm set for - h:m:s=%ptRt, y-m-d=%ptRdr\n",
- &alarm->time, &alarm->time);
+ dev_dbg(dev, "read alarm: %ptRd %ptRt\n", &alarm->time, &alarm->time);
return 0;
}
static int pm8xxx_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
{
- int rc;
- unsigned long irq_flags;
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
- unsigned int ctrl_reg;
u8 value[NUM_8_BIT_RTC_REGS] = {0};
-
- spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags);
-
- rc = regmap_read(rtc_dd->regmap, regs->alarm_ctrl, &ctrl_reg);
- if (rc)
- goto rtc_rw_fail;
+ unsigned int val;
+ int rc;
if (enable)
- ctrl_reg |= regs->alarm_en;
+ val = regs->alarm_en;
else
- ctrl_reg &= ~regs->alarm_en;
+ val = 0;
- rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl, ctrl_reg);
- if (rc) {
- dev_err(dev, "Write to RTC control register failed\n");
- goto rtc_rw_fail;
- }
+ rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl,
+ regs->alarm_en, val);
+ if (rc)
+ return rc;
- /* Clear Alarm register */
+ /* Clear alarm register */
if (!enable) {
rc = regmap_bulk_write(rtc_dd->regmap, regs->alarm_rw, value,
sizeof(value));
- if (rc) {
- dev_err(dev, "Clear RTC ALARM register failed\n");
- goto rtc_rw_fail;
- }
+ if (rc)
+ return rc;
}
-rtc_rw_fail:
- spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
- return rc;
+ return 0;
}
static const struct rtc_class_ops pm8xxx_rtc_ops = {
@@ -351,69 +379,31 @@ static irqreturn_t pm8xxx_alarm_trigger(int irq, void *dev_id)
{
struct pm8xxx_rtc *rtc_dd = dev_id;
const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
- unsigned int ctrl_reg;
int rc;
rtc_update_irq(rtc_dd->rtc, 1, RTC_IRQF | RTC_AF);
- spin_lock(&rtc_dd->ctrl_reg_lock);
-
- /* Clear the alarm enable bit */
- rc = regmap_read(rtc_dd->regmap, regs->alarm_ctrl, &ctrl_reg);
- if (rc) {
- spin_unlock(&rtc_dd->ctrl_reg_lock);
- goto rtc_alarm_handled;
- }
-
- ctrl_reg &= ~regs->alarm_en;
-
- rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl, ctrl_reg);
- if (rc) {
- spin_unlock(&rtc_dd->ctrl_reg_lock);
- dev_err(rtc_dd->rtc_dev,
- "Write to alarm control register failed\n");
- goto rtc_alarm_handled;
- }
-
- spin_unlock(&rtc_dd->ctrl_reg_lock);
-
- /* Clear RTC alarm register */
- rc = regmap_read(rtc_dd->regmap, regs->alarm_ctrl2, &ctrl_reg);
- if (rc) {
- dev_err(rtc_dd->rtc_dev,
- "RTC Alarm control2 register read failed\n");
- goto rtc_alarm_handled;
- }
+ /* Disable alarm */
+ rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl,
+ regs->alarm_en, 0);
+ if (rc)
+ return IRQ_NONE;
- ctrl_reg |= PM8xxx_RTC_ALARM_CLEAR;
- rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl2, ctrl_reg);
+ /* Clear alarm status */
+ rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl2,
+ PM8xxx_RTC_ALARM_CLEAR, 0);
if (rc)
- dev_err(rtc_dd->rtc_dev,
- "Write to RTC Alarm control2 register failed\n");
+ return IRQ_NONE;
-rtc_alarm_handled:
return IRQ_HANDLED;
}
static int pm8xxx_rtc_enable(struct pm8xxx_rtc *rtc_dd)
{
const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
- unsigned int ctrl_reg;
- int rc;
-
- /* Check if the RTC is on, else turn it on */
- rc = regmap_read(rtc_dd->regmap, regs->ctrl, &ctrl_reg);
- if (rc)
- return rc;
- if (!(ctrl_reg & PM8xxx_RTC_ENABLE)) {
- ctrl_reg |= PM8xxx_RTC_ENABLE;
- rc = regmap_write(rtc_dd->regmap, regs->ctrl, ctrl_reg);
- if (rc)
- return rc;
- }
-
- return 0;
+ return regmap_update_bits(rtc_dd->regmap, regs->ctrl, PM8xxx_RTC_ENABLE,
+ PM8xxx_RTC_ENABLE);
}
static const struct pm8xxx_rtc_regs pm8921_regs = {
@@ -456,9 +446,6 @@ static const struct pm8xxx_rtc_regs pmk8350_regs = {
.alarm_en = BIT(7),
};
-/*
- * Hardcoded RTC bases until IORESOURCE_REG mapping is figured out
- */
static const struct of_device_id pm8xxx_id_table[] = {
{ .compatible = "qcom,pm8921-rtc", .data = &pm8921_regs },
{ .compatible = "qcom,pm8058-rtc", .data = &pm8058_regs },
@@ -470,9 +457,9 @@ MODULE_DEVICE_TABLE(of, pm8xxx_id_table);
static int pm8xxx_rtc_probe(struct platform_device *pdev)
{
- int rc;
- struct pm8xxx_rtc *rtc_dd;
const struct of_device_id *match;
+ struct pm8xxx_rtc *rtc_dd;
+ int rc;
match = of_match_node(pm8xxx_id_table, pdev->dev.of_node);
if (!match)
@@ -482,24 +469,33 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev)
if (rtc_dd == NULL)
return -ENOMEM;
- /* Initialise spinlock to protect RTC control register */
- spin_lock_init(&rtc_dd->ctrl_reg_lock);
-
rtc_dd->regmap = dev_get_regmap(pdev->dev.parent, NULL);
- if (!rtc_dd->regmap) {
- dev_err(&pdev->dev, "Parent regmap unavailable.\n");
+ if (!rtc_dd->regmap)
return -ENXIO;
- }
- rtc_dd->rtc_alarm_irq = platform_get_irq(pdev, 0);
- if (rtc_dd->rtc_alarm_irq < 0)
+ rtc_dd->alarm_irq = platform_get_irq(pdev, 0);
+ if (rtc_dd->alarm_irq < 0)
return -ENXIO;
rtc_dd->allow_set_time = of_property_read_bool(pdev->dev.of_node,
"allow-set-time");
+ rtc_dd->nvmem_cell = devm_nvmem_cell_get(&pdev->dev, "offset");
+ if (IS_ERR(rtc_dd->nvmem_cell)) {
+ rc = PTR_ERR(rtc_dd->nvmem_cell);
+ if (rc != -ENOENT)
+ return rc;
+ rtc_dd->nvmem_cell = NULL;
+ }
+
rtc_dd->regs = match->data;
- rtc_dd->rtc_dev = &pdev->dev;
+ rtc_dd->dev = &pdev->dev;
+
+ if (!rtc_dd->allow_set_time) {
+ rc = pm8xxx_rtc_read_offset(rtc_dd);
+ if (rc)
+ return rc;
+ }
rc = pm8xxx_rtc_enable(rtc_dd);
if (rc)
@@ -509,7 +505,6 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 1);
- /* Register the RTC device */
rtc_dd->rtc = devm_rtc_allocate_device(&pdev->dev);
if (IS_ERR(rtc_dd->rtc))
return PTR_ERR(rtc_dd->rtc);
@@ -517,21 +512,18 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev)
rtc_dd->rtc->ops = &pm8xxx_rtc_ops;
rtc_dd->rtc->range_max = U32_MAX;
- /* Request the alarm IRQ */
- rc = devm_request_any_context_irq(&pdev->dev, rtc_dd->rtc_alarm_irq,
+ rc = devm_request_any_context_irq(&pdev->dev, rtc_dd->alarm_irq,
pm8xxx_alarm_trigger,
IRQF_TRIGGER_RISING,
"pm8xxx_rtc_alarm", rtc_dd);
- if (rc < 0) {
- dev_err(&pdev->dev, "Request IRQ failed (%d)\n", rc);
+ if (rc < 0)
return rc;
- }
rc = devm_rtc_register_device(rtc_dd->rtc);
if (rc)
return rc;
- rc = dev_pm_set_wake_irq(&pdev->dev, rtc_dd->rtc_alarm_irq);
+ rc = dev_pm_set_wake_irq(&pdev->dev, rtc_dd->alarm_irq);
if (rc)
return rc;
@@ -559,3 +551,4 @@ MODULE_ALIAS("platform:rtc-pm8xxx");
MODULE_DESCRIPTION("PMIC8xxx RTC driver");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Anirudh Ghayal <aghayal@codeaurora.org>");
+MODULE_AUTHOR("Johan Hovold <johan@kernel.org>");
diff --git a/drivers/rtc/rtc-rv3028.c b/drivers/rtc/rtc-rv3028.c
index b0099e26e3b0..ec5d7a614e2d 100644
--- a/drivers/rtc/rtc-rv3028.c
+++ b/drivers/rtc/rtc-rv3028.c
@@ -982,6 +982,12 @@ static int rv3028_probe(struct i2c_client *client)
return 0;
}
+static const struct acpi_device_id rv3028_i2c_acpi_match[] = {
+ { "MCRY3028" },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, rv3028_i2c_acpi_match);
+
static const __maybe_unused struct of_device_id rv3028_of_match[] = {
{ .compatible = "microcrystal,rv3028", },
{ }
@@ -991,6 +997,7 @@ MODULE_DEVICE_TABLE(of, rv3028_of_match);
static struct i2c_driver rv3028_driver = {
.driver = {
.name = "rtc-rv3028",
+ .acpi_match_table = rv3028_i2c_acpi_match,
.of_match_table = of_match_ptr(rv3028_of_match),
},
.probe_new = rv3028_probe,
diff --git a/drivers/rtc/rtc-rv3029c2.c b/drivers/rtc/rtc-rv3029c2.c
index e4fdd47ae066..0852f6709a85 100644
--- a/drivers/rtc/rtc-rv3029c2.c
+++ b/drivers/rtc/rtc-rv3029c2.c
@@ -735,9 +735,14 @@ static int rv3029_probe(struct device *dev, struct regmap *regmap, int irq,
return PTR_ERR(rv3029->rtc);
if (rv3029->irq > 0) {
+ unsigned long irqflags = IRQF_TRIGGER_LOW;
+
+ if (dev_fwnode(dev))
+ irqflags = 0;
+
rc = devm_request_threaded_irq(dev, rv3029->irq,
NULL, rv3029_handle_irq,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ irqflags | IRQF_ONESHOT,
"rv3029", dev);
if (rc) {
dev_warn(dev, "unable to request IRQ, alarms disabled\n");
diff --git a/drivers/rtc/rtc-rv3032.c b/drivers/rtc/rtc-rv3032.c
index c3bee305eacc..1ff4f2e6fa77 100644
--- a/drivers/rtc/rtc-rv3032.c
+++ b/drivers/rtc/rtc-rv3032.c
@@ -930,9 +930,14 @@ static int rv3032_probe(struct i2c_client *client)
return PTR_ERR(rv3032->rtc);
if (client->irq > 0) {
+ unsigned long irqflags = IRQF_TRIGGER_LOW;
+
+ if (dev_fwnode(&client->dev))
+ irqflags = 0;
+
ret = devm_request_threaded_irq(&client->dev, client->irq,
NULL, rv3032_handle_irq,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ irqflags | IRQF_ONESHOT,
"rv3032", rv3032);
if (ret) {
dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n");
@@ -975,6 +980,12 @@ static int rv3032_probe(struct i2c_client *client)
return 0;
}
+static const struct acpi_device_id rv3032_i2c_acpi_match[] = {
+ { "MCRY3032" },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, rv3032_i2c_acpi_match);
+
static const __maybe_unused struct of_device_id rv3032_of_match[] = {
{ .compatible = "microcrystal,rv3032", },
{ }
@@ -984,6 +995,7 @@ MODULE_DEVICE_TABLE(of, rv3032_of_match);
static struct i2c_driver rv3032_driver = {
.driver = {
.name = "rtc-rv3032",
+ .acpi_match_table = rv3032_i2c_acpi_match,
.of_match_table = of_match_ptr(rv3032_of_match),
},
.probe_new = rv3032_probe,
diff --git a/drivers/rtc/rtc-rv8803.c b/drivers/rtc/rtc-rv8803.c
index b581b6d5ad73..25c3b9e4f515 100644
--- a/drivers/rtc/rtc-rv8803.c
+++ b/drivers/rtc/rtc-rv8803.c
@@ -70,6 +70,7 @@ struct rv8803_data {
struct mutex flags_lock;
u8 ctrl;
u8 backup;
+ u8 alarm_invalid:1;
enum rv8803_type type;
};
@@ -165,13 +166,13 @@ static int rv8803_regs_init(struct rv8803_data *rv8803)
static int rv8803_regs_configure(struct rv8803_data *rv8803);
-static int rv8803_regs_reset(struct rv8803_data *rv8803)
+static int rv8803_regs_reset(struct rv8803_data *rv8803, bool full)
{
/*
* The RV-8803 resets all registers to POR defaults after voltage-loss,
* the Epson RTCs don't, so we manually reset the remainder here.
*/
- if (rv8803->type == rx_8803 || rv8803->type == rx_8900) {
+ if (full || rv8803->type == rx_8803 || rv8803->type == rx_8900) {
int ret = rv8803_regs_init(rv8803);
if (ret)
return ret;
@@ -238,6 +239,11 @@ static int rv8803_get_time(struct device *dev, struct rtc_time *tm)
u8 *date = date1;
int ret, flags;
+ if (rv8803->alarm_invalid) {
+ dev_warn(dev, "Corruption detected, data may be invalid.\n");
+ return -EINVAL;
+ }
+
flags = rv8803_read_reg(rv8803->client, RV8803_FLAG);
if (flags < 0)
return flags;
@@ -313,12 +319,19 @@ static int rv8803_set_time(struct device *dev, struct rtc_time *tm)
return flags;
}
- if (flags & RV8803_FLAG_V2F) {
- ret = rv8803_regs_reset(rv8803);
+ if ((flags & RV8803_FLAG_V2F) || rv8803->alarm_invalid) {
+ /*
+ * If we sense corruption in the alarm registers, but see no
+ * voltage loss flag, we can't rely on other registers having
+ * sensible values. Reset them fully.
+ */
+ ret = rv8803_regs_reset(rv8803, rv8803->alarm_invalid);
if (ret) {
mutex_unlock(&rv8803->flags_lock);
return ret;
}
+
+ rv8803->alarm_invalid = false;
}
ret = rv8803_write_reg(rv8803->client, RV8803_FLAG,
@@ -344,15 +357,33 @@ static int rv8803_get_alarm(struct device *dev, struct rtc_wkalrm *alrm)
if (flags < 0)
return flags;
+ alarmvals[0] &= 0x7f;
+ alarmvals[1] &= 0x3f;
+ alarmvals[2] &= 0x3f;
+
+ if (!bcd_is_valid(alarmvals[0]) ||
+ !bcd_is_valid(alarmvals[1]) ||
+ !bcd_is_valid(alarmvals[2]))
+ goto err_invalid;
+
alrm->time.tm_sec = 0;
- alrm->time.tm_min = bcd2bin(alarmvals[0] & 0x7f);
- alrm->time.tm_hour = bcd2bin(alarmvals[1] & 0x3f);
- alrm->time.tm_mday = bcd2bin(alarmvals[2] & 0x3f);
+ alrm->time.tm_min = bcd2bin(alarmvals[0]);
+ alrm->time.tm_hour = bcd2bin(alarmvals[1]);
+ alrm->time.tm_mday = bcd2bin(alarmvals[2]);
alrm->enabled = !!(rv8803->ctrl & RV8803_CTRL_AIE);
alrm->pending = (flags & RV8803_FLAG_AF) && alrm->enabled;
+ if ((unsigned int)alrm->time.tm_mday > 31 ||
+ (unsigned int)alrm->time.tm_hour >= 24 ||
+ (unsigned int)alrm->time.tm_min >= 60)
+ goto err_invalid;
+
return 0;
+
+err_invalid:
+ rv8803->alarm_invalid = true;
+ return -EINVAL;
}
static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
@@ -641,9 +672,14 @@ static int rv8803_probe(struct i2c_client *client)
return PTR_ERR(rv8803->rtc);
if (client->irq > 0) {
+ unsigned long irqflags = IRQF_TRIGGER_LOW;
+
+ if (dev_fwnode(&client->dev))
+ irqflags = 0;
+
err = devm_request_threaded_irq(&client->dev, client->irq,
NULL, rv8803_handle_irq,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ irqflags | IRQF_ONESHOT,
"rv8803", client);
if (err) {
dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n");
diff --git a/drivers/rtc/rtc-rx6110.c b/drivers/rtc/rtc-rx6110.c
index 76a49838014b..37608883a796 100644
--- a/drivers/rtc/rtc-rx6110.c
+++ b/drivers/rtc/rtc-rx6110.c
@@ -10,7 +10,6 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_gpio.h>
#include <linux/regmap.h>
#include <linux/rtc.h>
#include <linux/of.h>
diff --git a/drivers/rtc/rtc-rx8010.c b/drivers/rtc/rtc-rx8010.c
index d09056570739..b9c8dad26208 100644
--- a/drivers/rtc/rtc-rx8010.c
+++ b/drivers/rtc/rtc-rx8010.c
@@ -394,10 +394,14 @@ static int rx8010_probe(struct i2c_client *client)
return PTR_ERR(rx8010->rtc);
if (client->irq > 0) {
- dev_info(dev, "IRQ %d supplied\n", client->irq);
+ unsigned long irqflags = IRQF_TRIGGER_LOW;
+
+ if (dev_fwnode(&client->dev))
+ irqflags = 0;
+
err = devm_request_threaded_irq(dev, client->irq, NULL,
rx8010_irq_1_handler,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ irqflags | IRQF_ONESHOT,
"rx8010", client);
if (err) {
dev_err(dev, "unable to request IRQ\n");
diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c
index ed5516089e9a..7038f47d77ff 100644
--- a/drivers/rtc/rtc-sun6i.c
+++ b/drivers/rtc/rtc-sun6i.c
@@ -136,7 +136,6 @@ struct sun6i_rtc_clk_data {
unsigned int fixed_prescaler : 16;
unsigned int has_prescaler : 1;
unsigned int has_out_clk : 1;
- unsigned int export_iosc : 1;
unsigned int has_losc_en : 1;
unsigned int has_auto_swt : 1;
};
@@ -271,10 +270,8 @@ static void __init sun6i_rtc_clk_init(struct device_node *node,
/* Yes, I know, this is ugly. */
sun6i_rtc = rtc;
- /* Only read IOSC name from device tree if it is exported */
- if (rtc->data->export_iosc)
- of_property_read_string_index(node, "clock-output-names", 2,
- &iosc_name);
+ of_property_read_string_index(node, "clock-output-names", 2,
+ &iosc_name);
rtc->int_osc = clk_hw_register_fixed_rate_with_accuracy(NULL,
iosc_name,
@@ -315,13 +312,10 @@ static void __init sun6i_rtc_clk_init(struct device_node *node,
goto err_register;
}
- clk_data->num = 2;
+ clk_data->num = 3;
clk_data->hws[0] = &rtc->hw;
clk_data->hws[1] = __clk_get_hw(rtc->ext_losc);
- if (rtc->data->export_iosc) {
- clk_data->hws[2] = rtc->int_osc;
- clk_data->num = 3;
- }
+ clk_data->hws[2] = rtc->int_osc;
of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
return;
@@ -361,7 +355,6 @@ static const struct sun6i_rtc_clk_data sun8i_h3_rtc_data = {
.fixed_prescaler = 32,
.has_prescaler = 1,
.has_out_clk = 1,
- .export_iosc = 1,
};
static void __init sun8i_h3_rtc_clk_init(struct device_node *node)
@@ -379,7 +372,6 @@ static const struct sun6i_rtc_clk_data sun50i_h6_rtc_data = {
.fixed_prescaler = 32,
.has_prescaler = 1,
.has_out_clk = 1,
- .export_iosc = 1,
.has_losc_en = 1,
.has_auto_swt = 1,
};
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index 72ba83c1bc79..0b05cd76b7d0 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -629,7 +629,7 @@ static int raw3215_startup(struct raw3215_info *raw)
if (tty_port_initialized(&raw->port))
return 0;
raw->line_pos = 0;
- tty_port_set_initialized(&raw->port, 1);
+ tty_port_set_initialized(&raw->port, true);
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
raw3215_try_io(raw);
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
@@ -659,7 +659,7 @@ static void raw3215_shutdown(struct raw3215_info *raw)
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
remove_wait_queue(&raw->empty_wait, &wait);
set_current_state(TASK_RUNNING);
- tty_port_set_initialized(&raw->port, 1);
+ tty_port_set_initialized(&raw->port, true);
}
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
}
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index dfbb998db86f..3ef636935a54 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -1411,9 +1411,9 @@ static void css_shutdown(struct device *dev)
sch->driver->shutdown(sch);
}
-static int css_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int css_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct subchannel *sch = to_subchannel(dev);
+ const struct subchannel *sch = to_subchannel(dev);
int ret;
ret = add_uevent_var(env, "ST=%01X", sch->st);
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 5418e60dbfc3..8eb089b99cde 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -80,7 +80,7 @@ ccw_bus_match (struct device * dev, struct device_driver * drv)
* specified size. Return length of resulting string (excluding trailing '\0')
* even if string doesn't fit buffer (snprintf semantics). */
static int snprint_alias(char *buf, size_t size,
- struct ccw_device_id *id, const char *suffix)
+ const struct ccw_device_id *id, const char *suffix)
{
int len;
@@ -101,10 +101,10 @@ static int snprint_alias(char *buf, size_t size,
/* Set up environment variables for ccw device uevent. Return 0 on success,
* non-zero otherwise. */
-static int ccw_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int ccw_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct ccw_device *cdev = to_ccwdev(dev);
- struct ccw_device_id *id = &(cdev->id);
+ const struct ccw_device *cdev = to_ccwdev(dev);
+ const struct ccw_device_id *id = &(cdev->id);
int ret;
char modalias_buf[30];
diff --git a/drivers/s390/cio/scm.c b/drivers/s390/cio/scm.c
index b6b4589c70bd..6b21ba68c1fe 100644
--- a/drivers/s390/cio/scm.c
+++ b/drivers/s390/cio/scm.c
@@ -37,7 +37,7 @@ static void scmdev_remove(struct device *dev)
scmdrv->remove(scmdev);
}
-static int scmdev_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int scmdev_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
return add_uevent_var(env, "MODALIAS=scm:scmdev");
}
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index b02c631f3b71..f4cc1720156f 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -613,10 +613,10 @@ static int ap_bus_match(struct device *dev, struct device_driver *drv)
* It sets up a single environment variable DEV_TYPE which contains the
* hardware device type.
*/
-static int ap_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int ap_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
int rc = 0;
- struct ap_device *ap_dev = to_ap_dev(dev);
+ const struct ap_device *ap_dev = to_ap_dev(dev);
/* Uevents from ap bus core don't need extensions to the env */
if (dev == ap_root_device)
diff --git a/drivers/s390/virtio/virtio_ccw.c b/drivers/s390/virtio/virtio_ccw.c
index a10dbe632ef9..954fc31b4bc7 100644
--- a/drivers/s390/virtio/virtio_ccw.c
+++ b/drivers/s390/virtio/virtio_ccw.c
@@ -363,7 +363,7 @@ static void virtio_ccw_drop_indicator(struct virtio_ccw_device *vcdev,
thinint_area->isc = VIRTIO_AIRQ_ISC;
ccw->cmd_code = CCW_CMD_SET_IND_ADAPTER;
ccw->count = sizeof(*thinint_area);
- ccw->cda = (__u32)(unsigned long) thinint_area;
+ ccw->cda = (__u32)virt_to_phys(thinint_area);
} else {
/* payload is the address of the indicators */
indicatorp = ccw_device_dma_zalloc(vcdev->cdev,
@@ -373,7 +373,7 @@ static void virtio_ccw_drop_indicator(struct virtio_ccw_device *vcdev,
*indicatorp = 0;
ccw->cmd_code = CCW_CMD_SET_IND;
ccw->count = sizeof(indicators(vcdev));
- ccw->cda = (__u32)(unsigned long) indicatorp;
+ ccw->cda = (__u32)virt_to_phys(indicatorp);
}
/* Deregister indicators from host. */
*indicators(vcdev) = 0;
@@ -417,7 +417,7 @@ static int virtio_ccw_read_vq_conf(struct virtio_ccw_device *vcdev,
ccw->cmd_code = CCW_CMD_READ_VQ_CONF;
ccw->flags = 0;
ccw->count = sizeof(struct vq_config_block);
- ccw->cda = (__u32)(unsigned long)(&vcdev->dma_area->config_block);
+ ccw->cda = (__u32)virt_to_phys(&vcdev->dma_area->config_block);
ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_VQ_CONF);
if (ret)
return ret;
@@ -454,7 +454,7 @@ static void virtio_ccw_del_vq(struct virtqueue *vq, struct ccw1 *ccw)
}
ccw->cmd_code = CCW_CMD_SET_VQ;
ccw->flags = 0;
- ccw->cda = (__u32)(unsigned long)(info->info_block);
+ ccw->cda = (__u32)virt_to_phys(info->info_block);
ret = ccw_io_helper(vcdev, ccw,
VIRTIO_CCW_DOING_SET_VQ | index);
/*
@@ -556,7 +556,7 @@ static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev,
}
ccw->cmd_code = CCW_CMD_SET_VQ;
ccw->flags = 0;
- ccw->cda = (__u32)(unsigned long)(info->info_block);
+ ccw->cda = (__u32)virt_to_phys(info->info_block);
err = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_VQ | i);
if (err) {
dev_warn(&vcdev->cdev->dev, "SET_VQ failed\n");
@@ -590,6 +590,7 @@ static int virtio_ccw_register_adapter_ind(struct virtio_ccw_device *vcdev,
{
int ret;
struct virtio_thinint_area *thinint_area = NULL;
+ unsigned long indicator_addr;
struct airq_info *info;
thinint_area = ccw_device_dma_zalloc(vcdev->cdev,
@@ -599,21 +600,22 @@ static int virtio_ccw_register_adapter_ind(struct virtio_ccw_device *vcdev,
goto out;
}
/* Try to get an indicator. */
- thinint_area->indicator = get_airq_indicator(vqs, nvqs,
- &thinint_area->bit_nr,
- &vcdev->airq_info);
- if (!thinint_area->indicator) {
+ indicator_addr = get_airq_indicator(vqs, nvqs,
+ &thinint_area->bit_nr,
+ &vcdev->airq_info);
+ if (!indicator_addr) {
ret = -ENOSPC;
goto out;
}
+ thinint_area->indicator = virt_to_phys((void *)indicator_addr);
info = vcdev->airq_info;
thinint_area->summary_indicator =
- (unsigned long) get_summary_indicator(info);
+ virt_to_phys(get_summary_indicator(info));
thinint_area->isc = VIRTIO_AIRQ_ISC;
ccw->cmd_code = CCW_CMD_SET_IND_ADAPTER;
ccw->flags = CCW_FLAG_SLI;
ccw->count = sizeof(*thinint_area);
- ccw->cda = (__u32)(unsigned long)thinint_area;
+ ccw->cda = (__u32)virt_to_phys(thinint_area);
ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_IND_ADAPTER);
if (ret) {
if (ret == -EOPNOTSUPP) {
@@ -686,7 +688,7 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs,
ccw->cmd_code = CCW_CMD_SET_IND;
ccw->flags = 0;
ccw->count = sizeof(indicators(vcdev));
- ccw->cda = (__u32)(unsigned long) indicatorp;
+ ccw->cda = (__u32)virt_to_phys(indicatorp);
ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_IND);
if (ret)
goto out;
@@ -697,7 +699,7 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs,
ccw->cmd_code = CCW_CMD_SET_CONF_IND;
ccw->flags = 0;
ccw->count = sizeof(indicators2(vcdev));
- ccw->cda = (__u32)(unsigned long) indicatorp;
+ ccw->cda = (__u32)virt_to_phys(indicatorp);
ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_CONF_IND);
if (ret)
goto out;
@@ -759,7 +761,7 @@ static u64 virtio_ccw_get_features(struct virtio_device *vdev)
ccw->cmd_code = CCW_CMD_READ_FEAT;
ccw->flags = 0;
ccw->count = sizeof(*features);
- ccw->cda = (__u32)(unsigned long)features;
+ ccw->cda = (__u32)virt_to_phys(features);
ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_FEAT);
if (ret) {
rc = 0;
@@ -776,7 +778,7 @@ static u64 virtio_ccw_get_features(struct virtio_device *vdev)
ccw->cmd_code = CCW_CMD_READ_FEAT;
ccw->flags = 0;
ccw->count = sizeof(*features);
- ccw->cda = (__u32)(unsigned long)features;
+ ccw->cda = (__u32)virt_to_phys(features);
ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_FEAT);
if (ret == 0)
rc |= (u64)le32_to_cpu(features->features) << 32;
@@ -829,7 +831,7 @@ static int virtio_ccw_finalize_features(struct virtio_device *vdev)
ccw->cmd_code = CCW_CMD_WRITE_FEAT;
ccw->flags = 0;
ccw->count = sizeof(*features);
- ccw->cda = (__u32)(unsigned long)features;
+ ccw->cda = (__u32)virt_to_phys(features);
ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_FEAT);
if (ret)
goto out_free;
@@ -843,7 +845,7 @@ static int virtio_ccw_finalize_features(struct virtio_device *vdev)
ccw->cmd_code = CCW_CMD_WRITE_FEAT;
ccw->flags = 0;
ccw->count = sizeof(*features);
- ccw->cda = (__u32)(unsigned long)features;
+ ccw->cda = (__u32)virt_to_phys(features);
ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_FEAT);
out_free:
@@ -875,7 +877,7 @@ static void virtio_ccw_get_config(struct virtio_device *vdev,
ccw->cmd_code = CCW_CMD_READ_CONF;
ccw->flags = 0;
ccw->count = offset + len;
- ccw->cda = (__u32)(unsigned long)config_area;
+ ccw->cda = (__u32)virt_to_phys(config_area);
ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_CONFIG);
if (ret)
goto out_free;
@@ -922,7 +924,7 @@ static void virtio_ccw_set_config(struct virtio_device *vdev,
ccw->cmd_code = CCW_CMD_WRITE_CONF;
ccw->flags = 0;
ccw->count = offset + len;
- ccw->cda = (__u32)(unsigned long)config_area;
+ ccw->cda = (__u32)virt_to_phys(config_area);
ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_CONFIG);
out_free:
@@ -946,7 +948,7 @@ static u8 virtio_ccw_get_status(struct virtio_device *vdev)
ccw->cmd_code = CCW_CMD_READ_STATUS;
ccw->flags = 0;
ccw->count = sizeof(vcdev->dma_area->status);
- ccw->cda = (__u32)(unsigned long)&vcdev->dma_area->status;
+ ccw->cda = (__u32)virt_to_phys(&vcdev->dma_area->status);
ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_STATUS);
/*
* If the channel program failed (should only happen if the device
@@ -975,7 +977,7 @@ static void virtio_ccw_set_status(struct virtio_device *vdev, u8 status)
ccw->cmd_code = CCW_CMD_WRITE_STATUS;
ccw->flags = 0;
ccw->count = sizeof(status);
- ccw->cda = (__u32)(unsigned long)&vcdev->dma_area->status;
+ ccw->cda = (__u32)virt_to_phys(&vcdev->dma_area->status);
/* We use ssch for setting the status which is a serializing
* instruction that guarantees the memory writes have
* completed before ssch.
@@ -1274,7 +1276,7 @@ static int virtio_ccw_set_transport_rev(struct virtio_ccw_device *vcdev)
ccw->cmd_code = CCW_CMD_SET_VIRTIO_REV;
ccw->flags = 0;
ccw->count = sizeof(*rev);
- ccw->cda = (__u32)(unsigned long)rev;
+ ccw->cda = (__u32)virt_to_phys(rev);
vcdev->revision = VIRTIO_CCW_REV_MAX;
do {
diff --git a/drivers/sbus/char/oradax.c b/drivers/sbus/char/oradax.c
index 21b7cb6e7e70..e300cf26bc2a 100644
--- a/drivers/sbus/char/oradax.c
+++ b/drivers/sbus/char/oradax.c
@@ -389,7 +389,7 @@ static int dax_devmap(struct file *f, struct vm_area_struct *vma)
/* completion area is mapped read-only for user */
if (vma->vm_flags & VM_WRITE)
return -EPERM;
- vma->vm_flags &= ~VM_MAYWRITE;
+ vm_flags_clear(vma, VM_MAYWRITE);
if (remap_pfn_range(vma, vma->vm_start, ctx->ca_buf_ra >> PAGE_SHIFT,
len, vma->vm_page_prot))
diff --git a/drivers/scsi/3w-sas.c b/drivers/scsi/3w-sas.c
index 3ebe66151dcb..f41c93454f0c 100644
--- a/drivers/scsi/3w-sas.c
+++ b/drivers/scsi/3w-sas.c
@@ -690,7 +690,7 @@ static void twl_load_sgl(TW_Device_Extension *tw_dev, TW_Command_Full *full_comm
newcommand->request_id__lunl =
cpu_to_le16(TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->request_id__lunl), request_id));
if (length) {
- newcommand->sg_list[0].address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1);
+ newcommand->sg_list[0].address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache));
newcommand->sg_list[0].length = TW_CPU_TO_SGL(length);
}
newcommand->sgl_entries__lunh =
@@ -702,7 +702,7 @@ static void twl_load_sgl(TW_Device_Extension *tw_dev, TW_Command_Full *full_comm
if (TW_SGL_OUT(oldcommand->opcode__sgloffset)) {
/* Load the sg list */
sgl = (TW_SG_Entry_ISO *)((u32 *)oldcommand+oldcommand->size - (sizeof(TW_SG_Entry_ISO)/4) + pae + (sizeof(dma_addr_t) > 4 ? 1 : 0));
- sgl->address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1);
+ sgl->address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache));
sgl->length = TW_CPU_TO_SGL(length);
oldcommand->size += pae;
oldcommand->size += sizeof(dma_addr_t) > 4 ? 1 : 0;
@@ -748,7 +748,7 @@ static long twl_chrdev_ioctl(struct file *file, unsigned int cmd, unsigned long
data_buffer_length_adjusted = (driver_command.buffer_length + 511) & ~511;
/* Now allocate ioctl buf memory */
- cpu_addr = dma_alloc_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, &dma_handle, GFP_KERNEL);
+ cpu_addr = dma_alloc_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted + sizeof(TW_Ioctl_Buf_Apache), &dma_handle, GFP_KERNEL);
if (!cpu_addr) {
retval = -ENOMEM;
goto out2;
@@ -757,7 +757,7 @@ static long twl_chrdev_ioctl(struct file *file, unsigned int cmd, unsigned long
tw_ioctl = (TW_Ioctl_Buf_Apache *)cpu_addr;
/* Now copy down the entire ioctl */
- if (copy_from_user(tw_ioctl, argp, driver_command.buffer_length + sizeof(TW_Ioctl_Buf_Apache) - 1))
+ if (copy_from_user(tw_ioctl, argp, driver_command.buffer_length + sizeof(TW_Ioctl_Buf_Apache)))
goto out3;
/* See which ioctl we are doing */
@@ -815,11 +815,11 @@ static long twl_chrdev_ioctl(struct file *file, unsigned int cmd, unsigned long
}
/* Now copy the entire response to userspace */
- if (copy_to_user(argp, tw_ioctl, sizeof(TW_Ioctl_Buf_Apache) + driver_command.buffer_length - 1) == 0)
+ if (copy_to_user(argp, tw_ioctl, sizeof(TW_Ioctl_Buf_Apache) + driver_command.buffer_length) == 0)
retval = 0;
out3:
/* Now free ioctl buf memory */
- dma_free_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, cpu_addr, dma_handle);
+ dma_free_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted + sizeof(TW_Ioctl_Buf_Apache), cpu_addr, dma_handle);
out2:
mutex_unlock(&tw_dev->ioctl_lock);
out:
diff --git a/drivers/scsi/3w-sas.h b/drivers/scsi/3w-sas.h
index b0508039a280..096dec29e2ac 100644
--- a/drivers/scsi/3w-sas.h
+++ b/drivers/scsi/3w-sas.h
@@ -335,7 +335,7 @@ typedef struct TAG_TW_Ioctl_Apache {
TW_Ioctl_Driver_Command driver_command;
char padding[488];
TW_Command_Full firmware_command;
- char data_buffer[1];
+ char data_buffer[];
} TW_Ioctl_Buf_Apache;
/* GetParam descriptor */
@@ -344,7 +344,7 @@ typedef struct {
unsigned short parameter_id;
unsigned short parameter_size_bytes;
unsigned short actual_parameter_size_bytes;
- unsigned char data[1];
+ unsigned char data[];
} TW_Param_Apache;
/* Compatibility information structure */
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index 4d4cb47b3846..24c049eff157 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -818,8 +818,8 @@ static void aac_probe_container_scsi_done(struct scsi_cmnd *scsi_cmnd)
int aac_probe_container(struct aac_dev *dev, int cid)
{
- struct scsi_cmnd *scsicmd = kzalloc(sizeof(*scsicmd), GFP_KERNEL);
- struct aac_cmd_priv *cmd_priv = aac_priv(scsicmd);
+ struct aac_cmd_priv *cmd_priv;
+ struct scsi_cmnd *scsicmd = kzalloc(sizeof(*scsicmd) + sizeof(*cmd_priv), GFP_KERNEL);
struct scsi_device *scsidev = kzalloc(sizeof(*scsidev), GFP_KERNEL);
int status;
@@ -838,6 +838,7 @@ int aac_probe_container(struct aac_dev *dev, int cid)
while (scsicmd->device == scsidev)
schedule();
kfree(scsidev);
+ cmd_priv = aac_priv(scsicmd);
status = cmd_priv->status;
kfree(scsicmd);
return status;
diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c
index ed119a3f6f2e..7f0208300110 100644
--- a/drivers/scsi/aic94xx/aic94xx_task.c
+++ b/drivers/scsi/aic94xx/aic94xx_task.c
@@ -50,6 +50,9 @@ static int asd_map_scatterlist(struct sas_task *task,
dma_addr_t dma = dma_map_single(&asd_ha->pcidev->dev, p,
task->total_xfer_len,
task->data_dir);
+ if (dma_mapping_error(&asd_ha->pcidev->dev, dma))
+ return -ENOMEM;
+
sg_arr[0].bus_addr = cpu_to_le64((u64)dma);
sg_arr[0].size = cpu_to_le32(task->total_xfer_len);
sg_arr[0].flags |= ASD_SG_EL_LIST_EOL;
diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c
index 7ab29eaec6f3..72fe6df78bc5 100644
--- a/drivers/scsi/ch.c
+++ b/drivers/scsi/ch.c
@@ -184,20 +184,21 @@ static int ch_find_errno(struct scsi_sense_hdr *sshdr)
static int
ch_do_scsi(scsi_changer *ch, unsigned char *cmd, int cmd_len,
- void *buffer, unsigned buflength,
- enum dma_data_direction direction)
+ void *buffer, unsigned int buflength, enum req_op op)
{
int errno, retries = 0, timeout, result;
struct scsi_sense_hdr sshdr;
+ const struct scsi_exec_args exec_args = {
+ .sshdr = &sshdr,
+ };
timeout = (cmd[0] == INITIALIZE_ELEMENT_STATUS)
? timeout_init : timeout_move;
retry:
errno = 0;
- result = scsi_execute_req(ch->device, cmd, direction, buffer,
- buflength, &sshdr, timeout * HZ,
- MAX_RETRIES, NULL);
+ result = scsi_execute_cmd(ch->device, cmd, op, buffer, buflength,
+ timeout * HZ, MAX_RETRIES, &exec_args);
if (result < 0)
return result;
if (scsi_sense_valid(&sshdr)) {
@@ -254,7 +255,7 @@ ch_read_element_status(scsi_changer *ch, u_int elem, char *data)
cmd[5] = 1;
cmd[9] = 255;
if (0 == (result = ch_do_scsi(ch, cmd, 12,
- buffer, 256, DMA_FROM_DEVICE))) {
+ buffer, 256, REQ_OP_DRV_IN))) {
if (((buffer[16] << 8) | buffer[17]) != elem) {
DPRINTK("asked for element 0x%02x, got 0x%02x\n",
elem,(buffer[16] << 8) | buffer[17]);
@@ -284,7 +285,7 @@ ch_init_elem(scsi_changer *ch)
memset(cmd,0,sizeof(cmd));
cmd[0] = INITIALIZE_ELEMENT_STATUS;
cmd[1] = (ch->device->lun & 0x7) << 5;
- err = ch_do_scsi(ch, cmd, 6, NULL, 0, DMA_NONE);
+ err = ch_do_scsi(ch, cmd, 6, NULL, 0, REQ_OP_DRV_IN);
VPRINTK(KERN_INFO, "... finished\n");
return err;
}
@@ -306,10 +307,10 @@ ch_readconfig(scsi_changer *ch)
cmd[1] = (ch->device->lun & 0x7) << 5;
cmd[2] = 0x1d;
cmd[4] = 255;
- result = ch_do_scsi(ch, cmd, 10, buffer, 255, DMA_FROM_DEVICE);
+ result = ch_do_scsi(ch, cmd, 10, buffer, 255, REQ_OP_DRV_IN);
if (0 != result) {
cmd[1] |= (1<<3);
- result = ch_do_scsi(ch, cmd, 10, buffer, 255, DMA_FROM_DEVICE);
+ result = ch_do_scsi(ch, cmd, 10, buffer, 255, REQ_OP_DRV_IN);
}
if (0 == result) {
ch->firsts[CHET_MT] =
@@ -434,7 +435,7 @@ ch_position(scsi_changer *ch, u_int trans, u_int elem, int rotate)
cmd[4] = (elem >> 8) & 0xff;
cmd[5] = elem & 0xff;
cmd[8] = rotate ? 1 : 0;
- return ch_do_scsi(ch, cmd, 10, NULL, 0, DMA_NONE);
+ return ch_do_scsi(ch, cmd, 10, NULL, 0, REQ_OP_DRV_IN);
}
static int
@@ -455,7 +456,7 @@ ch_move(scsi_changer *ch, u_int trans, u_int src, u_int dest, int rotate)
cmd[6] = (dest >> 8) & 0xff;
cmd[7] = dest & 0xff;
cmd[10] = rotate ? 1 : 0;
- return ch_do_scsi(ch, cmd, 12, NULL,0, DMA_NONE);
+ return ch_do_scsi(ch, cmd, 12, NULL, 0, REQ_OP_DRV_IN);
}
static int
@@ -481,7 +482,7 @@ ch_exchange(scsi_changer *ch, u_int trans, u_int src,
cmd[9] = dest2 & 0xff;
cmd[10] = (rotate1 ? 1 : 0) | (rotate2 ? 2 : 0);
- return ch_do_scsi(ch, cmd, 12, NULL, 0, DMA_NONE);
+ return ch_do_scsi(ch, cmd, 12, NULL, 0, REQ_OP_DRV_IN);
}
static void
@@ -531,7 +532,7 @@ ch_set_voltag(scsi_changer *ch, u_int elem,
memcpy(buffer,tag,32);
ch_check_voltag(buffer);
- result = ch_do_scsi(ch, cmd, 12, buffer, 256, DMA_TO_DEVICE);
+ result = ch_do_scsi(ch, cmd, 12, buffer, 256, REQ_OP_DRV_OUT);
kfree(buffer);
return result;
}
@@ -799,8 +800,7 @@ static long ch_ioctl(struct file *file,
ch_cmd[5] = 1;
ch_cmd[9] = 255;
- result = ch_do_scsi(ch, ch_cmd, 12,
- buffer, 256, DMA_FROM_DEVICE);
+ result = ch_do_scsi(ch, ch_cmd, 12, buffer, 256, REQ_OP_DRV_IN);
if (!result) {
cge.cge_status = buffer[18];
cge.cge_flags = 0;
diff --git a/drivers/scsi/cxlflash/ocxl_hw.c b/drivers/scsi/cxlflash/ocxl_hw.c
index 631eda2d467e..6542818e595a 100644
--- a/drivers/scsi/cxlflash/ocxl_hw.c
+++ b/drivers/scsi/cxlflash/ocxl_hw.c
@@ -1167,7 +1167,7 @@ static int afu_mmap(struct file *file, struct vm_area_struct *vma)
(ctx->psn_size >> PAGE_SHIFT))
return -EINVAL;
- vma->vm_flags |= VM_IO | VM_PFNMAP;
+ vm_flags_set(vma, VM_IO | VM_PFNMAP);
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
vma->vm_ops = &ocxlflash_vmops;
return 0;
diff --git a/drivers/scsi/cxlflash/superpipe.c b/drivers/scsi/cxlflash/superpipe.c
index df0ebabbf387..22cfc2e1dfb9 100644
--- a/drivers/scsi/cxlflash/superpipe.c
+++ b/drivers/scsi/cxlflash/superpipe.c
@@ -308,19 +308,19 @@ out:
* @lli: LUN destined for capacity request.
*
* The READ_CAP16 can take quite a while to complete. Should an EEH occur while
- * in scsi_execute(), the EEH handler will attempt to recover. As part of the
- * recovery, the handler drains all currently running ioctls, waiting until they
- * have completed before proceeding with a reset. As this routine is used on the
- * ioctl path, this can create a condition where the EEH handler becomes stuck,
- * infinitely waiting for this ioctl thread. To avoid this behavior, temporarily
- * unmark this thread as an ioctl thread by releasing the ioctl read semaphore.
- * This will allow the EEH handler to proceed with a recovery while this thread
- * is still running. Once the scsi_execute() returns, reacquire the ioctl read
- * semaphore and check the adapter state in case it changed while inside of
- * scsi_execute(). The state check will wait if the adapter is still being
- * recovered or return a failure if the recovery failed. In the event that the
- * adapter reset failed, simply return the failure as the ioctl would be unable
- * to continue.
+ * in scsi_execute_cmd(), the EEH handler will attempt to recover. As part of
+ * the recovery, the handler drains all currently running ioctls, waiting until
+ * they have completed before proceeding with a reset. As this routine is used
+ * on the ioctl path, this can create a condition where the EEH handler becomes
+ * stuck, infinitely waiting for this ioctl thread. To avoid this behavior,
+ * temporarily unmark this thread as an ioctl thread by releasing the ioctl
+ * read semaphore. This will allow the EEH handler to proceed with a recovery
+ * while this thread is still running. Once the scsi_execute_cmd() returns,
+ * reacquire the ioctl read semaphore and check the adapter state in case it
+ * changed while inside of scsi_execute_cmd(). The state check will wait if the
+ * adapter is still being recovered or return a failure if the recovery failed.
+ * In the event that the adapter reset failed, simply return the failure as the
+ * ioctl would be unable to continue.
*
* Note that the above puts a requirement on this routine to only be called on
* an ioctl thread.
@@ -333,6 +333,9 @@ static int read_cap16(struct scsi_device *sdev, struct llun_info *lli)
struct device *dev = &cfg->dev->dev;
struct glun_info *gli = lli->parent;
struct scsi_sense_hdr sshdr;
+ const struct scsi_exec_args exec_args = {
+ .sshdr = &sshdr,
+ };
u8 *cmd_buf = NULL;
u8 *scsi_cmd = NULL;
int rc = 0;
@@ -357,9 +360,8 @@ retry:
/* Drop the ioctl read semahpore across lengthy call */
up_read(&cfg->ioctl_rwsem);
- result = scsi_execute(sdev, scsi_cmd, DMA_FROM_DEVICE, cmd_buf,
- CMD_BUFSIZE, NULL, &sshdr, to, CMD_RETRIES,
- 0, 0, NULL);
+ result = scsi_execute_cmd(sdev, scsi_cmd, REQ_OP_DRV_IN, cmd_buf,
+ CMD_BUFSIZE, to, CMD_RETRIES, &exec_args);
down_read(&cfg->ioctl_rwsem);
rc = check_state(cfg);
if (rc) {
diff --git a/drivers/scsi/cxlflash/vlun.c b/drivers/scsi/cxlflash/vlun.c
index 5c74dc7c2288..9caabf550436 100644
--- a/drivers/scsi/cxlflash/vlun.c
+++ b/drivers/scsi/cxlflash/vlun.c
@@ -397,19 +397,19 @@ static int init_vlun(struct llun_info *lli)
* @nblks: Number of logical blocks to write same.
*
* The SCSI WRITE_SAME16 can take quite a while to complete. Should an EEH occur
- * while in scsi_execute(), the EEH handler will attempt to recover. As part of
- * the recovery, the handler drains all currently running ioctls, waiting until
- * they have completed before proceeding with a reset. As this routine is used
- * on the ioctl path, this can create a condition where the EEH handler becomes
- * stuck, infinitely waiting for this ioctl thread. To avoid this behavior,
- * temporarily unmark this thread as an ioctl thread by releasing the ioctl read
- * semaphore. This will allow the EEH handler to proceed with a recovery while
- * this thread is still running. Once the scsi_execute() returns, reacquire the
- * ioctl read semaphore and check the adapter state in case it changed while
- * inside of scsi_execute(). The state check will wait if the adapter is still
- * being recovered or return a failure if the recovery failed. In the event that
- * the adapter reset failed, simply return the failure as the ioctl would be
- * unable to continue.
+ * while in scsi_execute_cmd(), the EEH handler will attempt to recover. As
+ * part of the recovery, the handler drains all currently running ioctls,
+ * waiting until they have completed before proceeding with a reset. As this
+ * routine is used on the ioctl path, this can create a condition where the
+ * EEH handler becomes stuck, infinitely waiting for this ioctl thread. To
+ * avoid this behavior, temporarily unmark this thread as an ioctl thread by
+ * releasing the ioctl read semaphore. This will allow the EEH handler to
+ * proceed with a recovery while this thread is still running. Once the
+ * scsi_execute_cmd() returns, reacquire the ioctl read semaphore and check the
+ * adapter state in case it changed while inside of scsi_execute_cmd(). The
+ * state check will wait if the adapter is still being recovered or return a
+ * failure if the recovery failed. In the event that the adapter reset failed,
+ * simply return the failure as the ioctl would be unable to continue.
*
* Note that the above puts a requirement on this routine to only be called on
* an ioctl thread.
@@ -450,9 +450,9 @@ static int write_same16(struct scsi_device *sdev,
/* Drop the ioctl read semahpore across lengthy call */
up_read(&cfg->ioctl_rwsem);
- result = scsi_execute(sdev, scsi_cmd, DMA_TO_DEVICE, cmd_buf,
- CMD_BUFSIZE, NULL, NULL, to,
- CMD_RETRIES, 0, 0, NULL);
+ result = scsi_execute_cmd(sdev, scsi_cmd, REQ_OP_DRV_OUT,
+ cmd_buf, CMD_BUFSIZE, to,
+ CMD_RETRIES, NULL);
down_read(&cfg->ioctl_rwsem);
rc = check_state(cfg);
if (rc) {
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 29a2865b8e2e..362fa631f39b 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -127,8 +127,11 @@ static int submit_rtpg(struct scsi_device *sdev, unsigned char *buff,
int bufflen, struct scsi_sense_hdr *sshdr, int flags)
{
u8 cdb[MAX_COMMAND_SIZE];
- blk_opf_t req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
- REQ_FAILFAST_DRIVER;
+ blk_opf_t opf = REQ_OP_DRV_IN | REQ_FAILFAST_DEV |
+ REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER;
+ const struct scsi_exec_args exec_args = {
+ .sshdr = sshdr,
+ };
/* Prepare the command. */
memset(cdb, 0x0, MAX_COMMAND_SIZE);
@@ -139,9 +142,9 @@ static int submit_rtpg(struct scsi_device *sdev, unsigned char *buff,
cdb[1] = MI_REPORT_TARGET_PGS;
put_unaligned_be32(bufflen, &cdb[6]);
- return scsi_execute(sdev, cdb, DMA_FROM_DEVICE, buff, bufflen, NULL,
- sshdr, ALUA_FAILOVER_TIMEOUT * HZ,
- ALUA_FAILOVER_RETRIES, req_flags, 0, NULL);
+ return scsi_execute_cmd(sdev, cdb, opf, buff, bufflen,
+ ALUA_FAILOVER_TIMEOUT * HZ,
+ ALUA_FAILOVER_RETRIES, &exec_args);
}
/*
@@ -157,8 +160,11 @@ static int submit_stpg(struct scsi_device *sdev, int group_id,
u8 cdb[MAX_COMMAND_SIZE];
unsigned char stpg_data[8];
int stpg_len = 8;
- blk_opf_t req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
- REQ_FAILFAST_DRIVER;
+ blk_opf_t opf = REQ_OP_DRV_OUT | REQ_FAILFAST_DEV |
+ REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER;
+ const struct scsi_exec_args exec_args = {
+ .sshdr = sshdr,
+ };
/* Prepare the data buffer */
memset(stpg_data, 0, stpg_len);
@@ -171,9 +177,9 @@ static int submit_stpg(struct scsi_device *sdev, int group_id,
cdb[1] = MO_SET_TARGET_PGS;
put_unaligned_be32(stpg_len, &cdb[6]);
- return scsi_execute(sdev, cdb, DMA_TO_DEVICE, stpg_data, stpg_len, NULL,
- sshdr, ALUA_FAILOVER_TIMEOUT * HZ,
- ALUA_FAILOVER_RETRIES, req_flags, 0, NULL);
+ return scsi_execute_cmd(sdev, cdb, opf, stpg_data,
+ stpg_len, ALUA_FAILOVER_TIMEOUT * HZ,
+ ALUA_FAILOVER_RETRIES, &exec_args);
}
static struct alua_port_group *alua_find_get_pg(char *id_str, size_t id_size,
diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c
index 2e21ab447873..3cf88db2d5b2 100644
--- a/drivers/scsi/device_handler/scsi_dh_emc.c
+++ b/drivers/scsi/device_handler/scsi_dh_emc.c
@@ -239,8 +239,11 @@ static int send_trespass_cmd(struct scsi_device *sdev,
unsigned char cdb[MAX_COMMAND_SIZE];
int err, res = SCSI_DH_OK, len;
struct scsi_sense_hdr sshdr;
- blk_opf_t req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
- REQ_FAILFAST_DRIVER;
+ blk_opf_t opf = REQ_OP_DRV_OUT | REQ_FAILFAST_DEV |
+ REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER;
+ const struct scsi_exec_args exec_args = {
+ .sshdr = &sshdr,
+ };
if (csdev->flags & CLARIION_SHORT_TRESPASS) {
page22 = short_trespass;
@@ -263,9 +266,9 @@ static int send_trespass_cmd(struct scsi_device *sdev,
BUG_ON((len > CLARIION_BUFFER_SIZE));
memcpy(csdev->buffer, page22, len);
- err = scsi_execute(sdev, cdb, DMA_TO_DEVICE, csdev->buffer, len, NULL,
- &sshdr, CLARIION_TIMEOUT * HZ, CLARIION_RETRIES,
- req_flags, 0, NULL);
+ err = scsi_execute_cmd(sdev, cdb, opf, csdev->buffer, len,
+ CLARIION_TIMEOUT * HZ, CLARIION_RETRIES,
+ &exec_args);
if (err) {
if (scsi_sense_valid(&sshdr))
res = trespass_endio(sdev, &sshdr);
diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
index 0d2cfa60aa06..5f2f943d926c 100644
--- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c
+++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
@@ -83,12 +83,15 @@ static int hp_sw_tur(struct scsi_device *sdev, struct hp_sw_dh_data *h)
unsigned char cmd[6] = { TEST_UNIT_READY };
struct scsi_sense_hdr sshdr;
int ret = SCSI_DH_OK, res;
- blk_opf_t req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
- REQ_FAILFAST_DRIVER;
+ blk_opf_t opf = REQ_OP_DRV_IN | REQ_FAILFAST_DEV |
+ REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER;
+ const struct scsi_exec_args exec_args = {
+ .sshdr = &sshdr,
+ };
retry:
- res = scsi_execute(sdev, cmd, DMA_NONE, NULL, 0, NULL, &sshdr,
- HP_SW_TIMEOUT, HP_SW_RETRIES, req_flags, 0, NULL);
+ res = scsi_execute_cmd(sdev, cmd, opf, NULL, 0, HP_SW_TIMEOUT,
+ HP_SW_RETRIES, &exec_args);
if (res) {
if (scsi_sense_valid(&sshdr))
ret = tur_done(sdev, h, &sshdr);
@@ -121,12 +124,15 @@ static int hp_sw_start_stop(struct hp_sw_dh_data *h)
struct scsi_device *sdev = h->sdev;
int res, rc = SCSI_DH_OK;
int retry_cnt = HP_SW_RETRIES;
- blk_opf_t req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
- REQ_FAILFAST_DRIVER;
+ blk_opf_t opf = REQ_OP_DRV_IN | REQ_FAILFAST_DEV |
+ REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER;
+ const struct scsi_exec_args exec_args = {
+ .sshdr = &sshdr,
+ };
retry:
- res = scsi_execute(sdev, cmd, DMA_NONE, NULL, 0, NULL, &sshdr,
- HP_SW_TIMEOUT, HP_SW_RETRIES, req_flags, 0, NULL);
+ res = scsi_execute_cmd(sdev, cmd, opf, NULL, 0, HP_SW_TIMEOUT,
+ HP_SW_RETRIES, &exec_args);
if (res) {
if (!scsi_sense_valid(&sshdr)) {
sdev_printk(KERN_WARNING, sdev,
diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c
index bf8754741f85..c5538645057a 100644
--- a/drivers/scsi/device_handler/scsi_dh_rdac.c
+++ b/drivers/scsi/device_handler/scsi_dh_rdac.c
@@ -536,8 +536,11 @@ static void send_mode_select(struct work_struct *work)
unsigned char cdb[MAX_COMMAND_SIZE];
struct scsi_sense_hdr sshdr;
unsigned int data_size;
- blk_opf_t req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
- REQ_FAILFAST_DRIVER;
+ blk_opf_t opf = REQ_OP_DRV_OUT | REQ_FAILFAST_DEV |
+ REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER;
+ const struct scsi_exec_args exec_args = {
+ .sshdr = &sshdr,
+ };
spin_lock(&ctlr->ms_lock);
list_splice_init(&ctlr->ms_head, &list);
@@ -555,9 +558,8 @@ static void send_mode_select(struct work_struct *work)
(char *) h->ctlr->array_name, h->ctlr->index,
(retry_cnt == RDAC_RETRY_COUNT) ? "queueing" : "retrying");
- if (scsi_execute(sdev, cdb, DMA_TO_DEVICE, &h->ctlr->mode_select,
- data_size, NULL, &sshdr, RDAC_TIMEOUT * HZ,
- RDAC_RETRIES, req_flags, 0, NULL)) {
+ if (scsi_execute_cmd(sdev, cdb, opf, &h->ctlr->mode_select, data_size,
+ RDAC_TIMEOUT * HZ, RDAC_RETRIES, &exec_args)) {
err = mode_select_handle_sense(sdev, &sshdr);
if (err == SCSI_DH_RETRY && retry_cnt--)
goto retry;
diff --git a/drivers/scsi/elx/libefc_sli/sli4.c b/drivers/scsi/elx/libefc_sli/sli4.c
index b8c048cdb17f..8f96049f62dd 100644
--- a/drivers/scsi/elx/libefc_sli/sli4.c
+++ b/drivers/scsi/elx/libefc_sli/sli4.c
@@ -4,7 +4,7 @@
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
*/
-/**
+/*
* All common (i.e. transport-independent) SLI-4 functions are implemented
* in this file.
*/
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 2022ffb45041..198d3f20d682 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -3912,7 +3912,6 @@ static int ipr_copy_ucode_buffer(struct ipr_sglist *sglist,
{
int bsize_elem, i, result = 0;
struct scatterlist *sg;
- void *kaddr;
/* Determine the actual number of bytes per element */
bsize_elem = PAGE_SIZE * (1 << sglist->order);
@@ -3923,9 +3922,7 @@ static int ipr_copy_ucode_buffer(struct ipr_sglist *sglist,
buffer += bsize_elem) {
struct page *page = sg_page(sg);
- kaddr = kmap(page);
- memcpy(kaddr, buffer, bsize_elem);
- kunmap(page);
+ memcpy_to_page(page, 0, buffer, bsize_elem);
sg->length = bsize_elem;
@@ -3938,9 +3935,7 @@ static int ipr_copy_ucode_buffer(struct ipr_sglist *sglist,
if (len % bsize_elem) {
struct page *page = sg_page(sg);
- kaddr = kmap(page);
- memcpy(kaddr, buffer, len % bsize_elem);
- kunmap(page);
+ memcpy_to_page(page, 0, buffer, len % bsize_elem);
sg->length = len % bsize_elem;
}
@@ -5370,9 +5365,9 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd *scsi_cmd)
continue;
ipr_cmd->done = ipr_sata_eh_done;
- if (!(ipr_cmd->qc->flags & ATA_QCFLAG_FAILED)) {
+ if (!(ipr_cmd->qc->flags & ATA_QCFLAG_EH)) {
ipr_cmd->qc->err_mask |= AC_ERR_TIMEOUT;
- ipr_cmd->qc->flags |= ATA_QCFLAG_FAILED;
+ ipr_cmd->qc->flags |= ATA_QCFLAG_EH;
}
}
}
@@ -7142,11 +7137,8 @@ static unsigned int ipr_qc_issue(struct ata_queued_cmd *qc)
/**
* ipr_qc_fill_rtf - Read result TF
* @qc: ATA queued command
- *
- * Return value:
- * true
**/
-static bool ipr_qc_fill_rtf(struct ata_queued_cmd *qc)
+static void ipr_qc_fill_rtf(struct ata_queued_cmd *qc)
{
struct ipr_sata_port *sata_port = qc->ap->private_data;
struct ipr_ioasa_gata *g = &sata_port->ioasa;
@@ -7163,8 +7155,6 @@ static bool ipr_qc_fill_rtf(struct ata_queued_cmd *qc)
tf->hob_lbal = g->hob_lbal;
tf->hob_lbam = g->hob_lbam;
tf->hob_lbah = g->hob_lbah;
-
- return true;
}
static struct ata_port_operations ipr_sata_ops = {
diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
index 16419aeec02d..bb206509265e 100644
--- a/drivers/scsi/ips.c
+++ b/drivers/scsi/ips.c
@@ -1499,17 +1499,16 @@ static int ips_is_passthru(struct scsi_cmnd *SC)
struct scatterlist *sg = scsi_sglist(SC);
char *buffer;
- /* kmap_atomic() ensures addressability of the user buffer.*/
/* local_irq_save() protects the KM_IRQ0 address slot. */
local_irq_save(flags);
- buffer = kmap_atomic(sg_page(sg)) + sg->offset;
- if (buffer && buffer[0] == 'C' && buffer[1] == 'O' &&
- buffer[2] == 'P' && buffer[3] == 'P') {
- kunmap_atomic(buffer - sg->offset);
+ buffer = kmap_local_page(sg_page(sg)) + sg->offset;
+ if (buffer && buffer[0] == 'C' && buffer[1] == 'O' &&
+ buffer[2] == 'P' && buffer[3] == 'P') {
+ kunmap_local(buffer);
local_irq_restore(flags);
return 1;
}
- kunmap_atomic(buffer - sg->offset);
+ kunmap_local(buffer);
local_irq_restore(flags);
}
return 0;
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index 5e80225b5308..77714a495cbb 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -125,7 +125,7 @@ static void sas_ata_task_done(struct sas_task *task)
} else {
link->eh_info.err_mask |= ac_err_mask(dev->sata_dev.fis[2]);
if (unlikely(link->eh_info.err_mask))
- qc->flags |= ATA_QCFLAG_FAILED;
+ qc->flags |= ATA_QCFLAG_EH;
}
} else {
ac = sas_to_ata_err(stat);
@@ -136,7 +136,7 @@ static void sas_ata_task_done(struct sas_task *task)
qc->err_mask = ac;
} else {
link->eh_info.err_mask |= AC_ERR_DEV;
- qc->flags |= ATA_QCFLAG_FAILED;
+ qc->flags |= ATA_QCFLAG_EH;
}
dev->sata_dev.fis[2] = ATA_ERR | ATA_DRDY; /* tf status */
@@ -226,12 +226,11 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
return ret;
}
-static bool sas_ata_qc_fill_rtf(struct ata_queued_cmd *qc)
+static void sas_ata_qc_fill_rtf(struct ata_queued_cmd *qc)
{
struct domain_device *dev = qc->ap->private_data;
ata_tf_from_fis(dev->sata_dev.fis, &qc->result_tf);
- return true;
}
static struct sas_internal *dev_to_sas_internal(struct domain_device *dev)
@@ -239,7 +238,17 @@ static struct sas_internal *dev_to_sas_internal(struct domain_device *dev)
return to_sas_internal(dev->port->ha->core.shost->transportt);
}
-static int sas_get_ata_command_set(struct domain_device *dev);
+static int sas_get_ata_command_set(struct domain_device *dev)
+{
+ struct ata_taskfile tf;
+
+ if (dev->dev_type == SAS_SATA_PENDING)
+ return ATA_DEV_UNKNOWN;
+
+ ata_tf_from_fis(dev->frame_rcvd, &tf);
+
+ return ata_dev_classify(&tf);
+}
int sas_get_ata_info(struct domain_device *dev, struct ex_phy *phy)
{
@@ -476,7 +485,7 @@ static void sas_ata_internal_abort(struct sas_task *task)
static void sas_ata_post_internal(struct ata_queued_cmd *qc)
{
- if (qc->flags & ATA_QCFLAG_FAILED)
+ if (qc->flags & ATA_QCFLAG_EH)
qc->err_mask |= AC_ERR_OTHER;
if (qc->err_mask) {
@@ -631,26 +640,12 @@ void sas_ata_task_abort(struct sas_task *task)
/* Internal command, fake a timeout and complete. */
qc->flags &= ~ATA_QCFLAG_ACTIVE;
- qc->flags |= ATA_QCFLAG_FAILED;
+ qc->flags |= ATA_QCFLAG_EH;
qc->err_mask |= AC_ERR_TIMEOUT;
waiting = qc->private_data;
complete(waiting);
}
-static int sas_get_ata_command_set(struct domain_device *dev)
-{
- struct dev_to_host_fis *fis =
- (struct dev_to_host_fis *) dev->frame_rcvd;
- struct ata_taskfile tf;
-
- if (dev->dev_type == SAS_SATA_PENDING)
- return ATA_DEV_UNKNOWN;
-
- ata_tf_from_fis((const u8 *)fis, &tf);
-
- return ata_dev_classify(&tf);
-}
-
void sas_probe_sata(struct asd_sas_port *port)
{
struct domain_device *dev, *n;
@@ -679,6 +674,68 @@ void sas_probe_sata(struct asd_sas_port *port)
}
+int sas_ata_add_dev(struct domain_device *parent, struct ex_phy *phy,
+ struct domain_device *child, int phy_id)
+{
+ struct sas_rphy *rphy;
+ int ret;
+
+ if (child->linkrate > parent->min_linkrate) {
+ struct sas_phy *cphy = child->phy;
+ enum sas_linkrate min_prate = cphy->minimum_linkrate,
+ parent_min_lrate = parent->min_linkrate,
+ min_linkrate = (min_prate > parent_min_lrate) ?
+ parent_min_lrate : 0;
+ struct sas_phy_linkrates rates = {
+ .maximum_linkrate = parent->min_linkrate,
+ .minimum_linkrate = min_linkrate,
+ };
+
+ pr_notice("ex %016llx phy%02d SATA device linkrate > min pathway connection rate, attempting to lower device linkrate\n",
+ SAS_ADDR(child->sas_addr), phy_id);
+ ret = sas_smp_phy_control(parent, phy_id,
+ PHY_FUNC_LINK_RESET, &rates);
+ if (ret) {
+ pr_err("ex %016llx phy%02d SATA device could not set linkrate (%d)\n",
+ SAS_ADDR(child->sas_addr), phy_id, ret);
+ return ret;
+ }
+ pr_notice("ex %016llx phy%02d SATA device set linkrate successfully\n",
+ SAS_ADDR(child->sas_addr), phy_id);
+ child->linkrate = child->min_linkrate;
+ }
+ ret = sas_get_ata_info(child, phy);
+ if (ret)
+ return ret;
+
+ sas_init_dev(child);
+ ret = sas_ata_init(child);
+ if (ret)
+ return ret;
+
+ rphy = sas_end_device_alloc(phy->port);
+ if (!rphy)
+ return -ENOMEM;
+
+ rphy->identify.phy_identifier = phy_id;
+ child->rphy = rphy;
+ get_device(&rphy->dev);
+
+ list_add_tail(&child->disco_list_node, &parent->port->disco_list);
+
+ ret = sas_discover_sata(child);
+ if (ret) {
+ pr_notice("sas_discover_sata() for device %16llx at %016llx:%02d returned 0x%x\n",
+ SAS_ADDR(child->sas_addr),
+ SAS_ADDR(parent->sas_addr), phy_id, ret);
+ sas_rphy_free(child->rphy);
+ list_del(&child->disco_list_node);
+ return ret;
+ }
+
+ return 0;
+}
+
static void sas_ata_flush_pm_eh(struct asd_sas_port *port, const char *func)
{
struct domain_device *dev, *n;
diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c
index d5bc1314c341..72fdb2e5d047 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -455,14 +455,8 @@ static void sas_discover_domain(struct work_struct *work)
break;
case SAS_SATA_DEV:
case SAS_SATA_PM:
-#ifdef CONFIG_SCSI_SAS_ATA
error = sas_discover_sata(dev);
break;
-#else
- pr_notice("ATA device seen but CONFIG_SCSI_SAS_ATA=N so cannot attach\n");
- fallthrough;
-#endif
- /* Fall through - only for the #else condition above. */
default:
error = -ENXIO;
pr_err("unhandled device %d\n", dev->dev_type);
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index a04cad620e93..dc670304f181 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -751,13 +751,46 @@ static void sas_ex_get_linkrate(struct domain_device *parent,
child->pathways = min(child->pathways, parent->pathways);
}
+static int sas_ex_add_dev(struct domain_device *parent, struct ex_phy *phy,
+ struct domain_device *child, int phy_id)
+{
+ struct sas_rphy *rphy;
+ int res;
+
+ child->dev_type = SAS_END_DEVICE;
+ rphy = sas_end_device_alloc(phy->port);
+ if (!rphy)
+ return -ENOMEM;
+
+ child->tproto = phy->attached_tproto;
+ sas_init_dev(child);
+
+ child->rphy = rphy;
+ get_device(&rphy->dev);
+ rphy->identify.phy_identifier = phy_id;
+ sas_fill_in_rphy(child, rphy);
+
+ list_add_tail(&child->disco_list_node, &parent->port->disco_list);
+
+ res = sas_notify_lldd_dev_found(child);
+ if (res) {
+ pr_notice("notify lldd for device %016llx at %016llx:%02d returned 0x%x\n",
+ SAS_ADDR(child->sas_addr),
+ SAS_ADDR(parent->sas_addr), phy_id, res);
+ sas_rphy_free(child->rphy);
+ list_del(&child->disco_list_node);
+ return res;
+ }
+
+ return 0;
+}
+
static struct domain_device *sas_ex_discover_end_dev(
struct domain_device *parent, int phy_id)
{
struct expander_device *parent_ex = &parent->ex_dev;
struct ex_phy *phy = &parent_ex->ex_phy[phy_id];
struct domain_device *child = NULL;
- struct sas_rphy *rphy;
int res;
if (phy->attached_sata_host || phy->attached_sata_ps)
@@ -785,99 +818,23 @@ static struct domain_device *sas_ex_discover_end_dev(
sas_ex_get_linkrate(parent, child, phy);
sas_device_set_phy(child, phy->port);
-#ifdef CONFIG_SCSI_SAS_ATA
if ((phy->attached_tproto & SAS_PROTOCOL_STP) || phy->attached_sata_dev) {
- if (child->linkrate > parent->min_linkrate) {
- struct sas_phy *cphy = child->phy;
- enum sas_linkrate min_prate = cphy->minimum_linkrate,
- parent_min_lrate = parent->min_linkrate,
- min_linkrate = (min_prate > parent_min_lrate) ?
- parent_min_lrate : 0;
- struct sas_phy_linkrates rates = {
- .maximum_linkrate = parent->min_linkrate,
- .minimum_linkrate = min_linkrate,
- };
- int ret;
-
- pr_notice("ex %016llx phy%02d SATA device linkrate > min pathway connection rate, attempting to lower device linkrate\n",
- SAS_ADDR(child->sas_addr), phy_id);
- ret = sas_smp_phy_control(parent, phy_id,
- PHY_FUNC_LINK_RESET, &rates);
- if (ret) {
- pr_err("ex %016llx phy%02d SATA device could not set linkrate (%d)\n",
- SAS_ADDR(child->sas_addr), phy_id, ret);
- goto out_free;
- }
- pr_notice("ex %016llx phy%02d SATA device set linkrate successfully\n",
- SAS_ADDR(child->sas_addr), phy_id);
- child->linkrate = child->min_linkrate;
- }
- res = sas_get_ata_info(child, phy);
- if (res)
- goto out_free;
-
- sas_init_dev(child);
- res = sas_ata_init(child);
- if (res)
- goto out_free;
- rphy = sas_end_device_alloc(phy->port);
- if (!rphy)
- goto out_free;
- rphy->identify.phy_identifier = phy_id;
-
- child->rphy = rphy;
- get_device(&rphy->dev);
-
- list_add_tail(&child->disco_list_node, &parent->port->disco_list);
-
- res = sas_discover_sata(child);
- if (res) {
- pr_notice("sas_discover_sata() for device %16llx at %016llx:%02d returned 0x%x\n",
- SAS_ADDR(child->sas_addr),
- SAS_ADDR(parent->sas_addr), phy_id, res);
- goto out_list_del;
- }
- } else
-#endif
- if (phy->attached_tproto & SAS_PROTOCOL_SSP) {
- child->dev_type = SAS_END_DEVICE;
- rphy = sas_end_device_alloc(phy->port);
- /* FIXME: error handling */
- if (unlikely(!rphy))
- goto out_free;
- child->tproto = phy->attached_tproto;
- sas_init_dev(child);
-
- child->rphy = rphy;
- get_device(&rphy->dev);
- rphy->identify.phy_identifier = phy_id;
- sas_fill_in_rphy(child, rphy);
-
- list_add_tail(&child->disco_list_node, &parent->port->disco_list);
-
- res = sas_discover_end_dev(child);
- if (res) {
- pr_notice("sas_discover_end_dev() for device %016llx at %016llx:%02d returned 0x%x\n",
- SAS_ADDR(child->sas_addr),
- SAS_ADDR(parent->sas_addr), phy_id, res);
- goto out_list_del;
- }
+ res = sas_ata_add_dev(parent, phy, child, phy_id);
+ } else if (phy->attached_tproto & SAS_PROTOCOL_SSP) {
+ res = sas_ex_add_dev(parent, phy, child, phy_id);
} else {
pr_notice("target proto 0x%x at %016llx:0x%x not handled\n",
phy->attached_tproto, SAS_ADDR(parent->sas_addr),
phy_id);
- goto out_free;
+ res = -ENODEV;
}
+ if (res)
+ goto out_free;
+
list_add_tail(&child->siblings, &parent_ex->children);
return child;
- out_list_del:
- sas_rphy_free(child->rphy);
- list_del(&child->disco_list_node);
- spin_lock_irq(&parent->port->dev_list_lock);
- list_del(&child->dev_list_node);
- spin_unlock_irq(&parent->port->dev_list_lock);
out_free:
sas_port_delete(phy->port);
out_err:
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index 9ad233b40a9e..cf55f8e3bd9f 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -1592,8 +1592,6 @@ struct lpfc_hba {
struct timer_list cpuhp_poll_timer;
struct list_head poll_list; /* slowpath eq polling list */
#define LPFC_POLL_HB 1 /* slowpath heartbeat */
-#define LPFC_POLL_FASTPATH 0 /* called from fastpath */
-#define LPFC_POLL_SLOWPATH 1 /* called from slowpath */
char os_host_name[MAXHOSTNAMELEN];
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index 77e1b2911cb4..76c3434f8976 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -1905,8 +1905,7 @@ lpfc_xcvr_data_show(struct device *dev, struct device_attribute *attr,
goto out_free_rdp;
}
- strncpy(chbuf, &rdp_context->page_a0[SSF_VENDOR_NAME], 16);
- chbuf[16] = 0;
+ strscpy(chbuf, &rdp_context->page_a0[SSF_VENDOR_NAME], 16);
len = scnprintf(buf, PAGE_SIZE - len, "VendorName:\t%s\n", chbuf);
len += scnprintf(buf + len, PAGE_SIZE - len,
@@ -1914,17 +1913,13 @@ lpfc_xcvr_data_show(struct device *dev, struct device_attribute *attr,
(uint8_t)rdp_context->page_a0[SSF_VENDOR_OUI],
(uint8_t)rdp_context->page_a0[SSF_VENDOR_OUI + 1],
(uint8_t)rdp_context->page_a0[SSF_VENDOR_OUI + 2]);
- strncpy(chbuf, &rdp_context->page_a0[SSF_VENDOR_PN], 16);
- chbuf[16] = 0;
+ strscpy(chbuf, &rdp_context->page_a0[SSF_VENDOR_PN], 16);
len += scnprintf(buf + len, PAGE_SIZE - len, "VendorPN:\t%s\n", chbuf);
- strncpy(chbuf, &rdp_context->page_a0[SSF_VENDOR_SN], 16);
- chbuf[16] = 0;
+ strscpy(chbuf, &rdp_context->page_a0[SSF_VENDOR_SN], 16);
len += scnprintf(buf + len, PAGE_SIZE - len, "VendorSN:\t%s\n", chbuf);
- strncpy(chbuf, &rdp_context->page_a0[SSF_VENDOR_REV], 4);
- chbuf[4] = 0;
+ strscpy(chbuf, &rdp_context->page_a0[SSF_VENDOR_REV], 4);
len += scnprintf(buf + len, PAGE_SIZE - len, "VendorRev:\t%s\n", chbuf);
- strncpy(chbuf, &rdp_context->page_a0[SSF_DATE_CODE], 8);
- chbuf[8] = 0;
+ strscpy(chbuf, &rdp_context->page_a0[SSF_DATE_CODE], 8);
len += scnprintf(buf + len, PAGE_SIZE - len, "DateCode:\t%s\n", chbuf);
len += scnprintf(buf + len, PAGE_SIZE - len, "Identifier:\t%xh\n",
(uint8_t)rdp_context->page_a0[SSF_IDENTIFIER]);
@@ -1941,33 +1936,25 @@ lpfc_xcvr_data_show(struct device *dev, struct device_attribute *attr,
&rdp_context->page_a0[SSF_TRANSCEIVER_CODE_B7];
len += scnprintf(buf + len, PAGE_SIZE - len, "Speeds: \t");
- if (*(uint8_t *)trasn_code_byte7 == 0) {
- len += scnprintf(buf + len, PAGE_SIZE - len,
- "Unknown\n");
- } else {
- if (trasn_code_byte7->fc_sp_100MB)
- len += scnprintf(buf + len, PAGE_SIZE - len,
- "1 ");
- if (trasn_code_byte7->fc_sp_200mb)
- len += scnprintf(buf + len, PAGE_SIZE - len,
- "2 ");
- if (trasn_code_byte7->fc_sp_400MB)
- len += scnprintf(buf + len, PAGE_SIZE - len,
- "4 ");
- if (trasn_code_byte7->fc_sp_800MB)
- len += scnprintf(buf + len, PAGE_SIZE - len,
- "8 ");
- if (trasn_code_byte7->fc_sp_1600MB)
- len += scnprintf(buf + len, PAGE_SIZE - len,
- "16 ");
- if (trasn_code_byte7->fc_sp_3200MB)
- len += scnprintf(buf + len, PAGE_SIZE - len,
- "32 ");
- if (trasn_code_byte7->speed_chk_ecc)
- len += scnprintf(buf + len, PAGE_SIZE - len,
- "64 ");
- len += scnprintf(buf + len, PAGE_SIZE - len, "GB\n");
- }
+ if (*(uint8_t *)trasn_code_byte7 == 0) {
+ len += scnprintf(buf + len, PAGE_SIZE - len, "Unknown\n");
+ } else {
+ if (trasn_code_byte7->fc_sp_100MB)
+ len += scnprintf(buf + len, PAGE_SIZE - len, "1 ");
+ if (trasn_code_byte7->fc_sp_200mb)
+ len += scnprintf(buf + len, PAGE_SIZE - len, "2 ");
+ if (trasn_code_byte7->fc_sp_400MB)
+ len += scnprintf(buf + len, PAGE_SIZE - len, "4 ");
+ if (trasn_code_byte7->fc_sp_800MB)
+ len += scnprintf(buf + len, PAGE_SIZE - len, "8 ");
+ if (trasn_code_byte7->fc_sp_1600MB)
+ len += scnprintf(buf + len, PAGE_SIZE - len, "16 ");
+ if (trasn_code_byte7->fc_sp_3200MB)
+ len += scnprintf(buf + len, PAGE_SIZE - len, "32 ");
+ if (trasn_code_byte7->speed_chk_ecc)
+ len += scnprintf(buf + len, PAGE_SIZE - len, "64 ");
+ len += scnprintf(buf + len, PAGE_SIZE - len, "GB\n");
+ }
temperature = (rdp_context->page_a2[SFF_TEMPERATURE_B1] << 8 |
rdp_context->page_a2[SFF_TEMPERATURE_B0]);
vcc = (rdp_context->page_a2[SFF_VCC_B1] << 8 |
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index 8928f016d09e..976fd5ee7f7e 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -253,7 +253,6 @@ int lpfc_read_object(struct lpfc_hba *phba, char *s, uint32_t *datap,
uint32_t len);
void lpfc_sli4_cleanup_poll_list(struct lpfc_hba *phba);
-int lpfc_sli4_poll_eq(struct lpfc_queue *q, uint8_t path);
void lpfc_sli4_poll_hbtimer(struct timer_list *t);
void lpfc_sli4_start_polling(struct lpfc_queue *q);
void lpfc_sli4_stop_polling(struct lpfc_queue *q);
@@ -684,6 +683,7 @@ int lpfc_vmid_get_appid(struct lpfc_vport *vport, char *uuid,
union lpfc_vmid_io_tag *tag);
void lpfc_vmid_vport_cleanup(struct lpfc_vport *vport);
int lpfc_issue_els_qfpa(struct lpfc_vport *vport);
+void lpfc_reinit_vmid(struct lpfc_vport *vport);
void lpfc_sli_rpi_release(struct lpfc_vport *vport,
struct lpfc_nodelist *ndlp);
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 919741bbe267..569639dc8b2c 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -1123,6 +1123,9 @@ stop_rr_fcf_flogi:
if (sp->cmn.priority_tagging)
vport->phba->pport->vmid_flag |= (LPFC_VMID_ISSUE_QFPA |
LPFC_VMID_TYPE_PRIO);
+ /* reinitialize the VMID datastructure before returning */
+ if (lpfc_is_vmid_enabled(phba))
+ lpfc_reinit_vmid(vport);
/*
* Address a timing race with dev_loss. If dev_loss is active on
@@ -2373,15 +2376,30 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
/* PRLI failed */
lpfc_printf_vlog(vport, mode, loglevel,
"2754 PRLI failure DID:%06X Status:x%x/x%x, "
- "data: x%x\n",
+ "data: x%x x%x\n",
ndlp->nlp_DID, ulp_status,
- ulp_word4, ndlp->fc4_prli_sent);
+ ulp_word4, ndlp->nlp_state,
+ ndlp->fc4_prli_sent);
/* Do not call DSM for lpfc_els_abort'ed ELS cmds */
if (!lpfc_error_lost_link(ulp_status, ulp_word4))
lpfc_disc_state_machine(vport, ndlp, cmdiocb,
NLP_EVT_CMPL_PRLI);
+ /* The following condition catches an inflight transition
+ * mismatch typically caused by an RSCN. Skip any
+ * processing to allow recovery.
+ */
+ if (ndlp->nlp_state >= NLP_STE_PLOGI_ISSUE &&
+ ndlp->nlp_state <= NLP_STE_REG_LOGIN_ISSUE) {
+ lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE,
+ "2784 PRLI cmpl: state mismatch "
+ "DID x%06x nstate x%x nflag x%x\n",
+ ndlp->nlp_DID, ndlp->nlp_state,
+ ndlp->nlp_flag);
+ goto out;
+ }
+
/*
* For P2P topology, retain the node so that PLOGI can be
* attempted on it again.
@@ -4673,6 +4691,15 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
/* the nameserver fails */
maxretry = 0;
delay = 100;
+ } else if (cmd == ELS_CMD_PRLI &&
+ ndlp->nlp_state != NLP_STE_PRLI_ISSUE) {
+ /* State-command disagreement. The PRLI was
+ * failed with an invalid rpi meaning there
+ * some unexpected state change. Don't retry.
+ */
+ maxretry = 0;
+ retry = 0;
+ break;
}
retry = 1;
break;
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index 80375d73b732..a6df0a5b4006 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -1129,21 +1129,6 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove)
struct lpfc_nodelist *ndlp, *next_ndlp;
list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
- if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) {
- /* It's possible the FLOGI to the fabric node never
- * successfully completed and never registered with the
- * transport. In this case there is no way to clean up
- * the node.
- */
- if (ndlp->nlp_DID == Fabric_DID) {
- if (ndlp->nlp_prev_state ==
- NLP_STE_UNUSED_NODE &&
- !ndlp->fc4_xpt_flags)
- lpfc_nlp_put(ndlp);
- }
- continue;
- }
-
if ((phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) ||
((vport->port_type == LPFC_NPIV_PORT) &&
((ndlp->nlp_DID == NameServer_DID) ||
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h
index fb3504dbb899..58fa39c403a0 100644
--- a/drivers/scsi/lpfc/lpfc_hw4.h
+++ b/drivers/scsi/lpfc/lpfc_hw4.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. *
* Copyright (C) 2009-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -4201,6 +4201,8 @@ struct lpfc_acqe_fc_la {
#define LPFC_FC_LA_TYPE_MDS_LOOPBACK 0x5
#define LPFC_FC_LA_TYPE_UNEXP_WWPN 0x6
#define LPFC_FC_LA_TYPE_TRUNKING_EVENT 0x7
+#define LPFC_FC_LA_TYPE_ACTIVATE_FAIL 0x8
+#define LPFC_FC_LA_TYPE_LINK_RESET_PRTCL_EVT 0x9
#define lpfc_acqe_fc_la_port_type_SHIFT 6
#define lpfc_acqe_fc_la_port_type_MASK 0x00000003
#define lpfc_acqe_fc_la_port_type_WORD word0
@@ -4242,6 +4244,9 @@ struct lpfc_acqe_fc_la {
#define lpfc_acqe_fc_la_fault_SHIFT 0
#define lpfc_acqe_fc_la_fault_MASK 0x000000FF
#define lpfc_acqe_fc_la_fault_WORD word1
+#define lpfc_acqe_fc_la_link_status_SHIFT 8
+#define lpfc_acqe_fc_la_link_status_MASK 0x0000007F
+#define lpfc_acqe_fc_la_link_status_WORD word1
#define lpfc_acqe_fc_la_trunk_fault_SHIFT 0
#define lpfc_acqe_fc_la_trunk_fault_MASK 0x0000000F
#define lpfc_acqe_fc_la_trunk_fault_WORD word1
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 389a35308be3..6eb4085a3a22 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -5190,16 +5190,25 @@ static void
lpfc_sli4_parse_latt_fault(struct lpfc_hba *phba,
struct lpfc_acqe_link *acqe_link)
{
- switch (bf_get(lpfc_acqe_link_fault, acqe_link)) {
- case LPFC_ASYNC_LINK_FAULT_NONE:
- case LPFC_ASYNC_LINK_FAULT_LOCAL:
- case LPFC_ASYNC_LINK_FAULT_REMOTE:
- case LPFC_ASYNC_LINK_FAULT_LR_LRR:
+ switch (bf_get(lpfc_acqe_fc_la_att_type, acqe_link)) {
+ case LPFC_FC_LA_TYPE_LINK_DOWN:
+ case LPFC_FC_LA_TYPE_TRUNKING_EVENT:
+ case LPFC_FC_LA_TYPE_ACTIVATE_FAIL:
+ case LPFC_FC_LA_TYPE_LINK_RESET_PRTCL_EVT:
break;
default:
- lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
- "0398 Unknown link fault code: x%x\n",
- bf_get(lpfc_acqe_link_fault, acqe_link));
+ switch (bf_get(lpfc_acqe_link_fault, acqe_link)) {
+ case LPFC_ASYNC_LINK_FAULT_NONE:
+ case LPFC_ASYNC_LINK_FAULT_LOCAL:
+ case LPFC_ASYNC_LINK_FAULT_REMOTE:
+ case LPFC_ASYNC_LINK_FAULT_LR_LRR:
+ break;
+ default:
+ lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
+ "0398 Unknown link fault code: x%x\n",
+ bf_get(lpfc_acqe_link_fault, acqe_link));
+ break;
+ }
break;
}
}
@@ -6282,6 +6291,7 @@ lpfc_sli4_async_fc_evt(struct lpfc_hba *phba, struct lpfc_acqe_fc_la *acqe_fc)
LPFC_MBOXQ_t *pmb;
MAILBOX_t *mb;
struct lpfc_mbx_read_top *la;
+ char *log_level;
int rc;
if (bf_get(lpfc_trailer_type, acqe_fc) !=
@@ -6313,25 +6323,70 @@ lpfc_sli4_async_fc_evt(struct lpfc_hba *phba, struct lpfc_acqe_fc_la *acqe_fc)
bf_get(lpfc_acqe_fc_la_port_number, acqe_fc);
phba->sli4_hba.link_state.fault =
bf_get(lpfc_acqe_link_fault, acqe_fc);
+ phba->sli4_hba.link_state.link_status =
+ bf_get(lpfc_acqe_fc_la_link_status, acqe_fc);
- if (bf_get(lpfc_acqe_fc_la_att_type, acqe_fc) ==
- LPFC_FC_LA_TYPE_LINK_DOWN)
- phba->sli4_hba.link_state.logical_speed = 0;
- else if (!phba->sli4_hba.conf_trunk)
- phba->sli4_hba.link_state.logical_speed =
+ /*
+ * Only select attention types need logical speed modification to what
+ * was previously set.
+ */
+ if (phba->sli4_hba.link_state.status >= LPFC_FC_LA_TYPE_LINK_UP &&
+ phba->sli4_hba.link_state.status < LPFC_FC_LA_TYPE_ACTIVATE_FAIL) {
+ if (bf_get(lpfc_acqe_fc_la_att_type, acqe_fc) ==
+ LPFC_FC_LA_TYPE_LINK_DOWN)
+ phba->sli4_hba.link_state.logical_speed = 0;
+ else if (!phba->sli4_hba.conf_trunk)
+ phba->sli4_hba.link_state.logical_speed =
bf_get(lpfc_acqe_fc_la_llink_spd, acqe_fc) * 10;
+ }
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
"2896 Async FC event - Speed:%dGBaud Topology:x%x "
"LA Type:x%x Port Type:%d Port Number:%d Logical speed:"
- "%dMbps Fault:%d\n",
+ "%dMbps Fault:x%x Link Status:x%x\n",
phba->sli4_hba.link_state.speed,
phba->sli4_hba.link_state.topology,
phba->sli4_hba.link_state.status,
phba->sli4_hba.link_state.type,
phba->sli4_hba.link_state.number,
phba->sli4_hba.link_state.logical_speed,
- phba->sli4_hba.link_state.fault);
+ phba->sli4_hba.link_state.fault,
+ phba->sli4_hba.link_state.link_status);
+
+ /*
+ * The following attention types are informational only, providing
+ * further details about link status. Overwrite the value of
+ * link_state.status appropriately. No further action is required.
+ */
+ if (phba->sli4_hba.link_state.status >= LPFC_FC_LA_TYPE_ACTIVATE_FAIL) {
+ switch (phba->sli4_hba.link_state.status) {
+ case LPFC_FC_LA_TYPE_ACTIVATE_FAIL:
+ log_level = KERN_WARNING;
+ phba->sli4_hba.link_state.status =
+ LPFC_FC_LA_TYPE_LINK_DOWN;
+ break;
+ case LPFC_FC_LA_TYPE_LINK_RESET_PRTCL_EVT:
+ /*
+ * During bb credit recovery establishment, receiving
+ * this attention type is normal. Link Up attention
+ * type is expected to occur before this informational
+ * attention type so keep the Link Up status.
+ */
+ log_level = KERN_INFO;
+ phba->sli4_hba.link_state.status =
+ LPFC_FC_LA_TYPE_LINK_UP;
+ break;
+ default:
+ log_level = KERN_INFO;
+ break;
+ }
+ lpfc_log_msg(phba, log_level, LOG_SLI,
+ "2992 Async FC event - Informational Link "
+ "Attention Type x%x\n",
+ bf_get(lpfc_acqe_fc_la_att_type, acqe_fc));
+ return;
+ }
+
pmb = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!pmb) {
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
@@ -13918,6 +13973,13 @@ fcponly:
if (sli4_params->sge_supp_len > LPFC_MAX_SGE_SIZE)
sli4_params->sge_supp_len = LPFC_MAX_SGE_SIZE;
+ rc = dma_set_max_seg_size(&phba->pcidev->dev, sli4_params->sge_supp_len);
+ if (unlikely(rc)) {
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+ "6400 Can't set dma maximum segment size\n");
+ return rc;
+ }
+
/*
* Check whether the adapter supports an embedded copy of the
* FCP CMD IU within the WQE for FCP_Ixxx commands. In order
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 7a1563564df7..e989f130434e 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -1689,7 +1689,7 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
struct lpfc_pde6 *pde6 = NULL;
struct lpfc_pde7 *pde7 = NULL;
dma_addr_t dataphysaddr, protphysaddr;
- unsigned short curr_data = 0, curr_prot = 0;
+ unsigned short curr_prot = 0;
unsigned int split_offset;
unsigned int protgroup_len, protgroup_offset = 0, protgroup_remainder;
unsigned int protgrp_blks, protgrp_bytes;
@@ -1858,7 +1858,6 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
bpl->tus.w = le32_to_cpu(bpl->tus.w);
num_bde++;
- curr_data++;
if (split_offset)
break;
@@ -2119,7 +2118,7 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
struct scatterlist *sgpe = NULL; /* s/g prot entry */
struct sli4_sge_diseed *diseed = NULL;
dma_addr_t dataphysaddr, protphysaddr;
- unsigned short curr_data = 0, curr_prot = 0;
+ unsigned short curr_prot = 0;
unsigned int split_offset;
unsigned int protgroup_len, protgroup_offset = 0, protgroup_remainder;
unsigned int protgrp_blks, protgrp_bytes;
@@ -2364,7 +2363,6 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
dma_offset += dma_len;
num_sge++;
- curr_data++;
if (split_offset) {
sgl++;
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 182aaae60386..edbd81c3b643 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -11270,6 +11270,30 @@ lpfc_sli4_calc_ring(struct lpfc_hba *phba, struct lpfc_iocbq *piocb)
}
}
+inline void lpfc_sli4_poll_eq(struct lpfc_queue *eq)
+{
+ struct lpfc_hba *phba = eq->phba;
+
+ /*
+ * Unlocking an irq is one of the entry point to check
+ * for re-schedule, but we are good for io submission
+ * path as midlayer does a get_cpu to glue us in. Flush
+ * out the invalidate queue so we can see the updated
+ * value for flag.
+ */
+ smp_rmb();
+
+ if (READ_ONCE(eq->mode) == LPFC_EQ_POLL)
+ /* We will not likely get the completion for the caller
+ * during this iteration but i guess that's fine.
+ * Future io's coming on this eq should be able to
+ * pick it up. As for the case of single io's, they
+ * will be handled through a sched from polling timer
+ * function which is currently triggered every 1msec.
+ */
+ lpfc_sli4_process_eq(phba, eq, LPFC_QUEUE_NOARM);
+}
+
/**
* lpfc_sli_issue_iocb - Wrapper function for __lpfc_sli_issue_iocb
* @phba: Pointer to HBA context object.
@@ -11309,7 +11333,7 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number,
rc = __lpfc_sli_issue_iocb(phba, ring_number, piocb, flag);
spin_unlock_irqrestore(&pring->ring_lock, iflags);
- lpfc_sli4_poll_eq(eq, LPFC_POLL_FASTPATH);
+ lpfc_sli4_poll_eq(eq);
} else {
/* For now, SLI2/3 will still use hbalock */
spin_lock_irqsave(&phba->hbalock, iflags);
@@ -15625,12 +15649,11 @@ void lpfc_sli4_poll_hbtimer(struct timer_list *t)
{
struct lpfc_hba *phba = from_timer(phba, t, cpuhp_poll_timer);
struct lpfc_queue *eq;
- int i = 0;
rcu_read_lock();
list_for_each_entry_rcu(eq, &phba->poll_list, _poll_list)
- i += lpfc_sli4_poll_eq(eq, LPFC_POLL_SLOWPATH);
+ lpfc_sli4_poll_eq(eq);
if (!list_empty(&phba->poll_list))
mod_timer(&phba->cpuhp_poll_timer,
jiffies + msecs_to_jiffies(LPFC_POLL_HB));
@@ -15638,33 +15661,6 @@ void lpfc_sli4_poll_hbtimer(struct timer_list *t)
rcu_read_unlock();
}
-inline int lpfc_sli4_poll_eq(struct lpfc_queue *eq, uint8_t path)
-{
- struct lpfc_hba *phba = eq->phba;
- int i = 0;
-
- /*
- * Unlocking an irq is one of the entry point to check
- * for re-schedule, but we are good for io submission
- * path as midlayer does a get_cpu to glue us in. Flush
- * out the invalidate queue so we can see the updated
- * value for flag.
- */
- smp_rmb();
-
- if (READ_ONCE(eq->mode) == LPFC_EQ_POLL)
- /* We will not likely get the completion for the caller
- * during this iteration but i guess that's fine.
- * Future io's coming on this eq should be able to
- * pick it up. As for the case of single io's, they
- * will be handled through a sched from polling timer
- * function which is currently triggered every 1msec.
- */
- i = lpfc_sli4_process_eq(phba, eq, LPFC_QUEUE_NOARM);
-
- return i;
-}
-
static inline void lpfc_sli4_add_to_poll_list(struct lpfc_queue *eq)
{
struct lpfc_hba *phba = eq->phba;
@@ -20819,6 +20815,7 @@ lpfc_wr_object(struct lpfc_hba *phba, struct list_head *dmabuf_list,
struct lpfc_mbx_wr_object *wr_object;
LPFC_MBOXQ_t *mbox;
int rc = 0, i = 0;
+ int mbox_status = 0;
uint32_t shdr_status, shdr_add_status, shdr_add_status_2;
uint32_t shdr_change_status = 0, shdr_csf = 0;
uint32_t mbox_tmo;
@@ -20864,11 +20861,15 @@ lpfc_wr_object(struct lpfc_hba *phba, struct list_head *dmabuf_list,
wr_object->u.request.bde_count = i;
bf_set(lpfc_wr_object_write_length, &wr_object->u.request, written);
if (!phba->sli4_hba.intr_enable)
- rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
+ mbox_status = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
else {
mbox_tmo = lpfc_mbox_tmo_val(phba, mbox);
- rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo);
+ mbox_status = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo);
}
+
+ /* The mbox status needs to be maintained to detect MBOX_TIMEOUT. */
+ rc = mbox_status;
+
/* The IOCTL status is embedded in the mailbox subheader. */
shdr_status = bf_get(lpfc_mbox_hdr_status,
&wr_object->header.cfg_shdr.response);
@@ -20883,10 +20884,6 @@ lpfc_wr_object(struct lpfc_hba *phba, struct list_head *dmabuf_list,
&wr_object->u.response);
}
- if (!phba->sli4_hba.intr_enable)
- mempool_free(mbox, phba->mbox_mem_pool);
- else if (rc != MBX_TIMEOUT)
- mempool_free(mbox, phba->mbox_mem_pool);
if (shdr_status || shdr_add_status || shdr_add_status_2 || rc) {
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
"3025 Write Object mailbox failed with "
@@ -20904,6 +20901,12 @@ lpfc_wr_object(struct lpfc_hba *phba, struct list_head *dmabuf_list,
lpfc_log_fw_write_cmpl(phba, shdr_status, shdr_add_status,
shdr_add_status_2, shdr_change_status,
shdr_csf);
+
+ if (!phba->sli4_hba.intr_enable)
+ mempool_free(mbox, phba->mbox_mem_pool);
+ else if (mbox_status != MBX_TIMEOUT)
+ mempool_free(mbox, phba->mbox_mem_pool);
+
return rc;
}
@@ -21276,7 +21279,7 @@ lpfc_sli4_issue_wqe(struct lpfc_hba *phba, struct lpfc_sli4_hdw_queue *qp,
lpfc_sli_ringtxcmpl_put(phba, pring, pwqe);
spin_unlock_irqrestore(&pring->ring_lock, iflags);
- lpfc_sli4_poll_eq(qp->hba_eq, LPFC_POLL_FASTPATH);
+ lpfc_sli4_poll_eq(qp->hba_eq);
return 0;
}
@@ -21298,7 +21301,7 @@ lpfc_sli4_issue_wqe(struct lpfc_hba *phba, struct lpfc_sli4_hdw_queue *qp,
lpfc_sli_ringtxcmpl_put(phba, pring, pwqe);
spin_unlock_irqrestore(&pring->ring_lock, iflags);
- lpfc_sli4_poll_eq(qp->hba_eq, LPFC_POLL_FASTPATH);
+ lpfc_sli4_poll_eq(qp->hba_eq);
return 0;
}
@@ -21328,7 +21331,7 @@ lpfc_sli4_issue_wqe(struct lpfc_hba *phba, struct lpfc_sli4_hdw_queue *qp,
lpfc_sli_ringtxcmpl_put(phba, pring, pwqe);
spin_unlock_irqrestore(&pring->ring_lock, iflags);
- lpfc_sli4_poll_eq(qp->hba_eq, LPFC_POLL_FASTPATH);
+ lpfc_sli4_poll_eq(qp->hba_eq);
return 0;
}
return WQE_ERROR;
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h
index f927c2a25d54..3b62c4032c31 100644
--- a/drivers/scsi/lpfc/lpfc_sli4.h
+++ b/drivers/scsi/lpfc/lpfc_sli4.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. *
* Copyright (C) 2009-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -291,8 +291,9 @@ struct lpfc_sli4_link {
uint8_t type;
uint8_t number;
uint8_t fault;
- uint32_t logical_speed;
+ uint8_t link_status;
uint16_t topology;
+ uint32_t logical_speed;
};
struct lpfc_fcf_rec {
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index 41a1128f8651..0238208cdd11 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -20,7 +20,7 @@
* included with this package. *
*******************************************************************/
-#define LPFC_DRIVER_VERSION "14.2.0.9"
+#define LPFC_DRIVER_VERSION "14.2.0.10"
#define LPFC_DRIVER_NAME "lpfc"
/* Used for SLI 2/3 */
@@ -32,6 +32,6 @@
#define LPFC_MODULE_DESC "Emulex LightPulse Fibre Channel SCSI driver " \
LPFC_DRIVER_VERSION
-#define LPFC_COPYRIGHT "Copyright (C) 2017-2022 Broadcom. All Rights " \
+#define LPFC_COPYRIGHT "Copyright (C) 2017-2023 Broadcom. All Rights " \
"Reserved. The term \"Broadcom\" refers to Broadcom Inc. " \
"and/or its subsidiaries."
diff --git a/drivers/scsi/lpfc/lpfc_vmid.c b/drivers/scsi/lpfc/lpfc_vmid.c
index ed1d7f7b88a3..cf8ba840d0ea 100644
--- a/drivers/scsi/lpfc/lpfc_vmid.c
+++ b/drivers/scsi/lpfc/lpfc_vmid.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -284,3 +284,42 @@ int lpfc_vmid_get_appid(struct lpfc_vport *vport, char *uuid,
}
return rc;
}
+
+/*
+ * lpfc_reinit_vmid - reinitializes the vmid data structure
+ * @vport: pointer to vport data structure
+ *
+ * This routine reinitializes the vmid post flogi completion
+ *
+ * Return codes
+ * None
+ */
+void
+lpfc_reinit_vmid(struct lpfc_vport *vport)
+{
+ u32 bucket, i, cpu;
+ struct lpfc_vmid *cur;
+ struct lpfc_vmid *vmp = NULL;
+ struct hlist_node *tmp;
+
+ write_lock(&vport->vmid_lock);
+ vport->cur_vmid_cnt = 0;
+
+ for (i = 0; i < vport->max_vmid; i++) {
+ vmp = &vport->vmid[i];
+ vmp->flag = LPFC_VMID_SLOT_FREE;
+ memset(vmp->host_vmid, 0, sizeof(vmp->host_vmid));
+ vmp->io_rd_cnt = 0;
+ vmp->io_wr_cnt = 0;
+
+ if (vmp->last_io_time)
+ for_each_possible_cpu(cpu)
+ *per_cpu_ptr(vmp->last_io_time, cpu) = 0;
+ }
+
+ /* for all elements in the hash table */
+ if (!hash_empty(vport->hash_table))
+ hash_for_each_safe(vport->hash_table, bucket, tmp, cur, hnode)
+ hash_del(&cur->hnode);
+ write_unlock(&vport->vmid_lock);
+}
diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c
index 4d171f5c213f..6c7559cf1a4b 100644
--- a/drivers/scsi/lpfc/lpfc_vport.c
+++ b/drivers/scsi/lpfc/lpfc_vport.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -534,7 +534,7 @@ disable_vport(struct fc_vport *fc_vport)
{
struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data;
struct lpfc_hba *phba = vport->phba;
- struct lpfc_nodelist *ndlp = NULL, *next_ndlp = NULL;
+ struct lpfc_nodelist *ndlp = NULL;
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
/* Can't disable during an outstanding delete. */
@@ -546,17 +546,7 @@ disable_vport(struct fc_vport *fc_vport)
(void)lpfc_send_npiv_logo(vport, ndlp);
lpfc_sli_host_down(vport);
-
- /* Mark all nodes for discovery so we can remove them by
- * calling lpfc_cleanup_rpis(vport, 1)
- */
- list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
- if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
- continue;
- lpfc_disc_state_machine(vport, ndlp, NULL,
- NLP_EVT_DEVICE_RECOVERY);
- }
- lpfc_cleanup_rpis(vport, 1);
+ lpfc_cleanup_rpis(vport, 0);
lpfc_stop_vport_timers(vport);
lpfc_unreg_all_rpis(vport);
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
index fe70f8f11435..6597e118c805 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
@@ -3323,7 +3323,7 @@ static void megasas_prepare_secondRaid1_IO(struct megasas_instance *instance,
/* copy the io request frame as well as 8 SGEs data for r1 command*/
memcpy(r1_cmd->io_request, cmd->io_request,
(sizeof(struct MPI2_RAID_SCSI_IO_REQUEST)));
- memcpy(&r1_cmd->io_request->SGL, &cmd->io_request->SGL,
+ memcpy(r1_cmd->io_request->SGLs, cmd->io_request->SGLs,
(fusion->max_sge_in_main_msg * sizeof(union MPI2_SGE_IO_UNION)));
/*sense buffer is different for r1 command*/
r1_cmd->io_request->SenseBufferLowAddress =
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h
index 49e9a9048ee7..b677d80e5874 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.h
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h
@@ -526,7 +526,10 @@ struct MPI2_RAID_SCSI_IO_REQUEST {
__le32 Control; /* 0x3C */
union MPI2_SCSI_IO_CDB_UNION CDB; /* 0x40 */
union RAID_CONTEXT_UNION RaidContext; /* 0x60 */
- union MPI2_SGE_IO_UNION SGL; /* 0x80 */
+ union {
+ union MPI2_SGE_IO_UNION SGL; /* 0x80 */
+ DECLARE_FLEX_ARRAY(union MPI2_SGE_IO_UNION, SGLs);
+ };
};
/*
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c
index 69061545d9d2..2ee9ea57554d 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.c
@@ -5849,6 +5849,9 @@ _base_release_memory_pools(struct MPT3SAS_ADAPTER *ioc)
}
dma_pool_destroy(ioc->pcie_sgl_dma_pool);
}
+ kfree(ioc->pcie_sg_lookup);
+ ioc->pcie_sg_lookup = NULL;
+
if (ioc->config_page) {
dexitprintk(ioc,
ioc_info(ioc, "config_page(0x%p): free\n",
diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c
index 0d8b1e942ded..efdb8178db32 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c
@@ -1884,7 +1884,7 @@ mpt3sas_enable_diag_buffer(struct MPT3SAS_ADAPTER *ioc, u8 bits_to_register)
diag_register.requested_buffer_size>>10);
else if (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE]
& MPT3_DIAG_BUFFER_IS_REGISTERED) {
- ioc_err(ioc, "Trace buffer memory %d KB allocated\n",
+ ioc_info(ioc, "Trace buffer memory %d KB allocated\n",
diag_register.requested_buffer_size>>10);
if (ioc->hba_mpi_version_belonged != MPI2_VERSION)
ioc->diag_buffer_status[
diff --git a/drivers/scsi/mvumi.c b/drivers/scsi/mvumi.c
index b3dcb8918618..60c65586f30e 100644
--- a/drivers/scsi/mvumi.c
+++ b/drivers/scsi/mvumi.c
@@ -1841,7 +1841,7 @@ static enum mvumi_qc_result mvumi_send_command(struct mvumi_hba *mhba,
cmd->frame->request_id = mhba->io_seq++;
cmd->request_id = cmd->frame->request_id;
mhba->tag_cmd[cmd->frame->tag] = cmd;
- frame_len = sizeof(*ib_frame) - 4 +
+ frame_len = sizeof(*ib_frame) +
ib_frame->sg_counts * sizeof(struct mvumi_sgl);
if (mhba->hba_capability & HS_CAPABILITY_SUPPORT_DYN_SRC) {
struct mvumi_dyn_list_entry *dle;
@@ -2387,7 +2387,7 @@ static int mvumi_io_attach(struct mvumi_hba *mhba)
struct Scsi_Host *host = mhba->shost;
struct scsi_device *sdev = NULL;
int ret;
- unsigned int max_sg = (mhba->ib_max_size + 4 -
+ unsigned int max_sg = (mhba->ib_max_size -
sizeof(struct mvumi_msg_frame)) / sizeof(struct mvumi_sgl);
host->irq = mhba->pdev->irq;
diff --git a/drivers/scsi/mvumi.h b/drivers/scsi/mvumi.h
index a88c58787b68..1306a4abf19a 100644
--- a/drivers/scsi/mvumi.h
+++ b/drivers/scsi/mvumi.h
@@ -279,7 +279,7 @@ struct mvumi_msg_frame {
u16 request_id;
u16 reserved1;
u8 cdb[MAX_COMMAND_SIZE];
- u32 payload[1];
+ u32 payload[];
};
/*
@@ -294,7 +294,7 @@ struct mvumi_rsp_frame {
u8 req_status;
u8 rsp_flag; /* Indicates the type of Data_Payload.*/
u16 request_id;
- u32 payload[1];
+ u32 payload[];
};
struct mvumi_ob_data {
@@ -380,7 +380,7 @@ struct mvumi_hs_header {
u8 page_code;
u8 checksum;
u16 frame_length;
- u32 frame_content[1];
+ u32 frame_content[];
};
/*
diff --git a/drivers/scsi/pm8001/pm8001_ctl.c b/drivers/scsi/pm8001/pm8001_ctl.c
index 73f036bed128..5c26a13ffbd2 100644
--- a/drivers/scsi/pm8001/pm8001_ctl.c
+++ b/drivers/scsi/pm8001/pm8001_ctl.c
@@ -61,10 +61,10 @@ static ssize_t pm8001_ctl_mpi_interface_rev_show(struct device *cdev,
struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
if (pm8001_ha->chip_id == chip_8001) {
- return snprintf(buf, PAGE_SIZE, "%d\n",
+ return sysfs_emit(buf, "%d\n",
pm8001_ha->main_cfg_tbl.pm8001_tbl.interface_rev);
} else {
- return snprintf(buf, PAGE_SIZE, "%d\n",
+ return sysfs_emit(buf, "%d\n",
pm8001_ha->main_cfg_tbl.pm80xx_tbl.interface_rev);
}
}
@@ -86,7 +86,7 @@ static ssize_t controller_fatal_error_show(struct device *cdev,
struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
- return snprintf(buf, PAGE_SIZE, "%d\n",
+ return sysfs_emit(buf, "%d\n",
pm8001_ha->controller_fatal_error);
}
static DEVICE_ATTR_RO(controller_fatal_error);
@@ -107,13 +107,13 @@ static ssize_t pm8001_ctl_fw_version_show(struct device *cdev,
struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
if (pm8001_ha->chip_id == chip_8001) {
- return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
+ return sysfs_emit(buf, "%02x.%02x.%02x.%02x\n",
(u8)(pm8001_ha->main_cfg_tbl.pm8001_tbl.firmware_rev >> 24),
(u8)(pm8001_ha->main_cfg_tbl.pm8001_tbl.firmware_rev >> 16),
(u8)(pm8001_ha->main_cfg_tbl.pm8001_tbl.firmware_rev >> 8),
(u8)(pm8001_ha->main_cfg_tbl.pm8001_tbl.firmware_rev));
} else {
- return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
+ return sysfs_emit(buf, "%02x.%02x.%02x.%02x\n",
(u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.firmware_rev >> 24),
(u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.firmware_rev >> 16),
(u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.firmware_rev >> 8),
@@ -138,7 +138,7 @@ static ssize_t pm8001_ctl_ila_version_show(struct device *cdev,
struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
if (pm8001_ha->chip_id != chip_8001) {
- return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
+ return sysfs_emit(buf, "%02x.%02x.%02x.%02x\n",
(u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.ila_version >> 24),
(u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.ila_version >> 16),
(u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.ila_version >> 8),
@@ -164,7 +164,7 @@ static ssize_t pm8001_ctl_inactive_fw_version_show(struct device *cdev,
struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
if (pm8001_ha->chip_id != chip_8001) {
- return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
+ return sysfs_emit(buf, "%02x.%02x.%02x.%02x\n",
(u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.inc_fw_version >> 24),
(u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.inc_fw_version >> 16),
(u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.inc_fw_version >> 8),
@@ -191,10 +191,10 @@ static ssize_t pm8001_ctl_max_out_io_show(struct device *cdev,
struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
if (pm8001_ha->chip_id == chip_8001) {
- return snprintf(buf, PAGE_SIZE, "%d\n",
+ return sysfs_emit(buf, "%d\n",
pm8001_ha->main_cfg_tbl.pm8001_tbl.max_out_io);
} else {
- return snprintf(buf, PAGE_SIZE, "%d\n",
+ return sysfs_emit(buf, "%d\n",
pm8001_ha->main_cfg_tbl.pm80xx_tbl.max_out_io);
}
}
@@ -215,13 +215,11 @@ static ssize_t pm8001_ctl_max_devices_show(struct device *cdev,
struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
if (pm8001_ha->chip_id == chip_8001) {
- return snprintf(buf, PAGE_SIZE, "%04d\n",
- (u16)(pm8001_ha->main_cfg_tbl.pm8001_tbl.max_sgl >> 16)
- );
+ return sysfs_emit(buf, "%04d\n",
+ (u16)(pm8001_ha->main_cfg_tbl.pm8001_tbl.max_sgl >> 16));
} else {
- return snprintf(buf, PAGE_SIZE, "%04d\n",
- (u16)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.max_sgl >> 16)
- );
+ return sysfs_emit(buf, "%04d\n",
+ (u16)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.max_sgl >> 16));
}
}
static DEVICE_ATTR(max_devices, S_IRUGO, pm8001_ctl_max_devices_show, NULL);
@@ -242,13 +240,11 @@ static ssize_t pm8001_ctl_max_sg_list_show(struct device *cdev,
struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
if (pm8001_ha->chip_id == chip_8001) {
- return snprintf(buf, PAGE_SIZE, "%04d\n",
- pm8001_ha->main_cfg_tbl.pm8001_tbl.max_sgl & 0x0000FFFF
- );
+ return sysfs_emit(buf, "%04d\n",
+ pm8001_ha->main_cfg_tbl.pm8001_tbl.max_sgl & 0x0000FFFF);
} else {
- return snprintf(buf, PAGE_SIZE, "%04d\n",
- pm8001_ha->main_cfg_tbl.pm80xx_tbl.max_sgl & 0x0000FFFF
- );
+ return sysfs_emit(buf, "%04d\n",
+ pm8001_ha->main_cfg_tbl.pm80xx_tbl.max_sgl & 0x0000FFFF);
}
}
static DEVICE_ATTR(max_sg_list, S_IRUGO, pm8001_ctl_max_sg_list_show, NULL);
@@ -315,7 +311,7 @@ static ssize_t pm8001_ctl_host_sas_address_show(struct device *cdev,
struct Scsi_Host *shost = class_to_shost(cdev);
struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
- return snprintf(buf, PAGE_SIZE, "0x%016llx\n",
+ return sysfs_emit(buf, "0x%016llx\n",
be64_to_cpu(*(__be64 *)pm8001_ha->sas_addr));
}
static DEVICE_ATTR(host_sas_address, S_IRUGO,
@@ -336,7 +332,7 @@ static ssize_t pm8001_ctl_logging_level_show(struct device *cdev,
struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
- return snprintf(buf, PAGE_SIZE, "%08xh\n", pm8001_ha->logging_level);
+ return sysfs_emit(buf, "%08xh\n", pm8001_ha->logging_level);
}
static ssize_t pm8001_ctl_logging_level_store(struct device *cdev,
@@ -517,7 +513,7 @@ static ssize_t event_log_size_show(struct device *cdev,
struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
- return snprintf(buf, PAGE_SIZE, "%d\n",
+ return sysfs_emit(buf, "%d\n",
pm8001_ha->main_cfg_tbl.pm80xx_tbl.event_log_size);
}
static DEVICE_ATTR_RO(event_log_size);
@@ -604,7 +600,7 @@ static ssize_t non_fatal_count_show(struct device *cdev,
struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
- return snprintf(buf, PAGE_SIZE, "%08x",
+ return sysfs_emit(buf, "%08x\n",
pm8001_ha->non_fatal_count);
}
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index b67ad30d56e6..70cfc94c3d43 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -2732,7 +2732,7 @@ qla2x00_dev_loss_tmo_callbk(struct fc_rport *rport)
spin_lock_irqsave(host->host_lock, flags);
/* Confirm port has not reappeared before clearing pointers. */
if (rport->port_state != FC_PORTSTATE_ONLINE) {
- fcport->rport = fcport->drport = NULL;
+ fcport->rport = NULL;
*((fc_port_t **)rport->dd_data) = NULL;
}
spin_unlock_irqrestore(host->host_lock, flags);
@@ -3171,8 +3171,7 @@ qla24xx_vport_delete(struct fc_vport *fc_vport)
set_bit(VPORT_DELETE, &vha->dpc_flags);
- while (test_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags) ||
- test_bit(FCPORT_UPDATE_NEEDED, &vha->dpc_flags))
+ while (test_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags))
msleep(1000);
diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
index cd75b179410d..dba7bba788d7 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.c
+++ b/drivers/scsi/qla2xxx/qla_bsg.c
@@ -278,8 +278,8 @@ qla2x00_process_els(struct bsg_job *bsg_job)
const char *type;
int req_sg_cnt, rsp_sg_cnt;
int rval = (DID_ERROR << 16);
- uint16_t nextlid = 0;
uint32_t els_cmd = 0;
+ int qla_port_allocated = 0;
if (bsg_request->msgcode == FC_BSG_RPT_ELS) {
rport = fc_bsg_to_rport(bsg_job);
@@ -329,9 +329,9 @@ qla2x00_process_els(struct bsg_job *bsg_job)
/* make sure the rport is logged in,
* if not perform fabric login
*/
- if (qla2x00_fabric_login(vha, fcport, &nextlid)) {
+ if (atomic_read(&fcport->state) != FCS_ONLINE) {
ql_dbg(ql_dbg_user, vha, 0x7003,
- "Failed to login port %06X for ELS passthru.\n",
+ "Port %06X is not online for ELS passthru.\n",
fcport->d_id.b24);
rval = -EIO;
goto done;
@@ -348,6 +348,7 @@ qla2x00_process_els(struct bsg_job *bsg_job)
goto done;
}
+ qla_port_allocated = 1;
/* Initialize all required fields of fcport */
fcport->vha = vha;
fcport->d_id.b.al_pa =
@@ -432,7 +433,7 @@ done_unmap_sg:
goto done_free_fcport;
done_free_fcport:
- if (bsg_request->msgcode != FC_BSG_RPT_ELS)
+ if (qla_port_allocated)
qla2x00_free_fcport(fcport);
done:
return rval;
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index a26a373be9da..ec0e987b71fa 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -384,6 +384,13 @@ struct els_reject {
struct req_que;
struct qla_tgt_sess;
+struct qla_buf_dsc {
+ u16 tag;
+#define TAG_FREED 0xffff
+ void *buf;
+ dma_addr_t buf_dma;
+};
+
/*
* SCSI Request Block
*/
@@ -392,14 +399,16 @@ struct srb_cmd {
uint32_t request_sense_length;
uint32_t fw_sense_length;
uint8_t *request_sense_ptr;
- struct ct6_dsd *ct6_ctx;
struct crc_context *crc_ctx;
+ struct ct6_dsd ct6_ctx;
+ struct qla_buf_dsc buf_dsc;
};
/*
* SRB flag definitions
*/
#define SRB_DMA_VALID BIT_0 /* Command sent to ISP */
+#define SRB_GOT_BUF BIT_1
#define SRB_FCP_CMND_DMA_VALID BIT_12 /* DIF: DSD List valid */
#define SRB_CRC_CTX_DMA_VALID BIT_2 /* DIF: context DMA valid */
#define SRB_CRC_PROT_DMA_VALID BIT_4 /* DIF: prot DMA valid */
@@ -660,7 +669,7 @@ enum {
struct iocb_resource {
u8 res_type;
- u8 pad;
+ u8 exch_cnt;
u16 iocb_cnt;
};
@@ -2485,7 +2494,6 @@ struct ct_sns_desc {
enum discovery_state {
DSC_DELETED,
- DSC_GNN_ID,
DSC_GNL,
DSC_LOGIN_PEND,
DSC_LOGIN_FAILED,
@@ -2596,7 +2604,7 @@ typedef struct fc_port {
int login_retry;
- struct fc_rport *rport, *drport;
+ struct fc_rport *rport;
u32 supported_classes;
uint8_t fc4_type;
@@ -2699,7 +2707,6 @@ extern const char *const port_state_str[5];
static const char *const port_dstate_str[] = {
[DSC_DELETED] = "DELETED",
- [DSC_GNN_ID] = "GNN_ID",
[DSC_GNL] = "GNL",
[DSC_LOGIN_PEND] = "LOGIN_PEND",
[DSC_LOGIN_FAILED] = "LOGIN_FAILED",
@@ -3462,6 +3469,7 @@ struct qla_msix_entry {
int have_irq;
int in_use;
uint32_t vector;
+ uint32_t vector_base0;
uint16_t entry;
char name[30];
void *handle;
@@ -3479,7 +3487,6 @@ enum qla_work_type {
QLA_EVT_ASYNC_ADISC,
QLA_EVT_UEVENT,
QLA_EVT_AENFX,
- QLA_EVT_GPNID,
QLA_EVT_UNMAP,
QLA_EVT_NEW_SESS,
QLA_EVT_GPDB,
@@ -3493,7 +3500,6 @@ enum qla_work_type {
QLA_EVT_GPNFT,
QLA_EVT_GPNFT_DONE,
QLA_EVT_GNNFT_DONE,
- QLA_EVT_GNNID,
QLA_EVT_GFPNID,
QLA_EVT_SP_RETRY,
QLA_EVT_IIDMA,
@@ -3536,15 +3542,12 @@ struct qla_work_evt {
} iosb;
struct {
port_id_t id;
- } gpnid;
- struct {
- port_id_t id;
u8 port_name[8];
u8 node_name[8];
void *pla;
u8 fc4_type;
} new_sess;
- struct { /*Get PDB, Get Speed, update fcport, gnl, gidpn */
+ struct { /*Get PDB, Get Speed, update fcport, gnl */
fc_port_t *fcport;
u8 opt;
} fcport;
@@ -3721,10 +3724,27 @@ struct qla_fw_resources {
u16 iocbs_limit;
u16 iocbs_qp_limit;
u16 iocbs_used;
+ u16 exch_total;
+ u16 exch_limit;
+ u16 exch_used;
+ u16 pad;
};
#define QLA_IOCB_PCT_LIMIT 95
+struct qla_buf_pool {
+ u16 num_bufs;
+ u16 num_active;
+ u16 max_used;
+ u16 num_alloc;
+ u16 prev_max;
+ u16 pad;
+ uint32_t take_snapshot:1;
+ unsigned long *buf_map;
+ void **buf_array;
+ dma_addr_t *dma_array;
+};
+
/*Queue pair data structure */
struct qla_qpair {
spinlock_t qp_lock;
@@ -3778,6 +3798,7 @@ struct qla_qpair {
struct qla_tgt_counters tgt_counters;
uint16_t cpuid;
struct qla_fw_resources fwres ____cacheline_aligned;
+ struct qla_buf_pool buf_pool;
u32 cmd_cnt;
u32 cmd_completion_cnt;
u32 prev_completion_cnt;
@@ -3938,7 +3959,6 @@ struct qlt_hw_data {
__le32 __iomem *atio_q_out;
const struct qla_tgt_func_tmpl *tgt_ops;
- struct qla_tgt_vp_map *tgt_vp_map;
int saved_set;
__le16 saved_exchange_count;
@@ -4106,6 +4126,7 @@ struct qla_hw_data {
struct req_que **req_q_map;
struct rsp_que **rsp_q_map;
struct qla_qpair **queue_pair_map;
+ struct qla_qpair **qp_cpu_map;
unsigned long req_qid_map[(QLA_MAX_QUEUES / 8) / sizeof(unsigned long)];
unsigned long rsp_qid_map[(QLA_MAX_QUEUES / 8) / sizeof(unsigned long)];
unsigned long qpair_qid_map[(QLA_MAX_QUEUES / 8)
@@ -4762,6 +4783,7 @@ struct qla_hw_data {
spinlock_t sadb_lock; /* protects list */
struct els_reject elsrej;
u8 edif_post_stop_cnt_down;
+ struct qla_vp_map *vp_map;
};
#define RX_ELS_SIZE (roundup(sizeof(struct enode) + ELS_MAX_PAYLOAD, SMP_CACHE_BYTES))
@@ -4857,6 +4879,7 @@ typedef struct scsi_qla_host {
#define LOOP_READY 5
#define LOOP_DEAD 6
+ unsigned long buf_expired;
unsigned long relogin_jif;
unsigned long dpc_flags;
#define RESET_MARKER_NEEDED 0 /* Send marker to ISP. */
@@ -4872,7 +4895,6 @@ typedef struct scsi_qla_host {
#define ISP_ABORT_RETRY 10 /* ISP aborted. */
#define BEACON_BLINK_NEEDED 11
#define REGISTER_FDMI_NEEDED 12
-#define FCPORT_UPDATE_NEEDED 13
#define VP_DPC_NEEDED 14 /* wake up for VP dpc handling */
#define UNLOADING 15
#define NPIV_CONFIG_NEEDED 16
@@ -5022,7 +5044,6 @@ typedef struct scsi_qla_host {
uint8_t n2n_port_name[WWN_SIZE];
uint16_t n2n_id;
__le16 dport_data[4];
- struct list_head gpnid_list;
struct fab_scan scan;
uint8_t scm_fabric_connection_flags;
@@ -5064,7 +5085,7 @@ struct qla27xx_image_status {
#define SET_AL_PA 2
#define RESET_VP_IDX 3
#define RESET_AL_PA 4
-struct qla_tgt_vp_map {
+struct qla_vp_map {
uint8_t idx;
scsi_qla_host_t *vha;
};
diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c
index 777808af5634..1925cc6897b6 100644
--- a/drivers/scsi/qla2xxx/qla_dfs.c
+++ b/drivers/scsi/qla2xxx/qla_dfs.c
@@ -235,7 +235,7 @@ qla_dfs_fw_resource_cnt_show(struct seq_file *s, void *unused)
uint16_t mb[MAX_IOCB_MB_REG];
int rc;
struct qla_hw_data *ha = vha->hw;
- u16 iocbs_used, i;
+ u16 iocbs_used, i, exch_used;
rc = qla24xx_res_count_wait(vha, mb, SIZEOF_IOCB_MB_REG);
if (rc != QLA_SUCCESS) {
@@ -263,13 +263,19 @@ qla_dfs_fw_resource_cnt_show(struct seq_file *s, void *unused)
if (ql2xenforce_iocb_limit) {
/* lock is not require. It's an estimate. */
iocbs_used = ha->base_qpair->fwres.iocbs_used;
+ exch_used = ha->base_qpair->fwres.exch_used;
for (i = 0; i < ha->max_qpairs; i++) {
- if (ha->queue_pair_map[i])
+ if (ha->queue_pair_map[i]) {
iocbs_used += ha->queue_pair_map[i]->fwres.iocbs_used;
+ exch_used += ha->queue_pair_map[i]->fwres.exch_used;
+ }
}
seq_printf(s, "Driver: estimate iocb used [%d] high water limit [%d]\n",
iocbs_used, ha->base_qpair->fwres.iocbs_limit);
+
+ seq_printf(s, "estimate exchange used[%d] high water limit [%d] n",
+ exch_used, ha->base_qpair->fwres.exch_limit);
}
return 0;
diff --git a/drivers/scsi/qla2xxx/qla_edif.c b/drivers/scsi/qla2xxx/qla_edif.c
index e4240aae5f9e..ec0e20255bd3 100644
--- a/drivers/scsi/qla2xxx/qla_edif.c
+++ b/drivers/scsi/qla2xxx/qla_edif.c
@@ -480,6 +480,49 @@ void qla2x00_release_all_sadb(struct scsi_qla_host *vha, struct fc_port *fcport)
}
/**
+ * qla_delete_n2n_sess_and_wait: search for N2N session, tear it down and
+ * wait for tear down to complete. In N2N topology, there is only one
+ * session being active in tracking the remote device.
+ * @vha: host adapter pointer
+ * return code: 0 - found the session and completed the tear down.
+ * 1 - timeout occurred. Caller to use link bounce to reset.
+ */
+static int qla_delete_n2n_sess_and_wait(scsi_qla_host_t *vha)
+{
+ struct fc_port *fcport;
+ int rc = -EIO;
+ ulong expire = jiffies + 23 * HZ;
+
+ if (!N2N_TOPO(vha->hw))
+ return 0;
+
+ fcport = NULL;
+ list_for_each_entry(fcport, &vha->vp_fcports, list) {
+ if (!fcport->n2n_flag)
+ continue;
+
+ ql_dbg(ql_dbg_disc, fcport->vha, 0x2016,
+ "%s reset sess at app start \n", __func__);
+
+ qla_edif_sa_ctl_init(vha, fcport);
+ qlt_schedule_sess_for_deletion(fcport);
+
+ while (time_before_eq(jiffies, expire)) {
+ if (fcport->disc_state != DSC_DELETE_PEND) {
+ rc = 0;
+ break;
+ }
+ msleep(1);
+ }
+
+ set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
+ break;
+ }
+
+ return rc;
+}
+
+/**
* qla_edif_app_start: application has announce its present
* @vha: host adapter pointer
* @bsg_job: user request
@@ -518,18 +561,17 @@ qla_edif_app_start(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
fcport->n2n_link_reset_cnt = 0;
if (vha->hw->flags.n2n_fw_acc_sec) {
- list_for_each_entry_safe(fcport, tf, &vha->vp_fcports, list)
- qla_edif_sa_ctl_init(vha, fcport);
-
+ bool link_bounce = false;
/*
* While authentication app was not running, remote device
* could still try to login with this local port. Let's
- * clear the state and try again.
+ * reset the session, reconnect and re-authenticate.
*/
- qla2x00_wait_for_sess_deletion(vha);
+ if (qla_delete_n2n_sess_and_wait(vha))
+ link_bounce = true;
- /* bounce the link to get the other guy to relogin */
- if (!vha->hw->flags.n2n_bigger) {
+ /* bounce the link to start login */
+ if (!vha->hw->flags.n2n_bigger || link_bounce) {
set_bit(N2N_LINK_RESET, &vha->dpc_flags);
qla2xxx_wake_dpc(vha);
}
@@ -925,7 +967,9 @@ qla_edif_app_getfcinfo(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
if (!(fcport->flags & FCF_FCSP_DEVICE))
continue;
- tdid = app_req.remote_pid;
+ tdid.b.domain = app_req.remote_pid.domain;
+ tdid.b.area = app_req.remote_pid.area;
+ tdid.b.al_pa = app_req.remote_pid.al_pa;
ql_dbg(ql_dbg_edif, vha, 0x2058,
"APP request entry - portid=%06x.\n", tdid.b24);
@@ -2989,9 +3033,10 @@ qla28xx_start_scsi_edif(srb_t *sp)
tot_dsds = nseg;
req_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
- sp->iores.res_type = RESOURCE_INI;
+ sp->iores.res_type = RESOURCE_IOCB | RESOURCE_EXCH;
+ sp->iores.exch_cnt = 1;
sp->iores.iocb_cnt = req_cnt;
- if (qla_get_iocbs(sp->qpair, &sp->iores))
+ if (qla_get_fw_resources(sp->qpair, &sp->iores))
goto queuing_error;
if (req->cnt < (req_cnt + 2)) {
@@ -3006,26 +3051,16 @@ qla28xx_start_scsi_edif(srb_t *sp)
goto queuing_error;
}
- ctx = sp->u.scmd.ct6_ctx =
- mempool_alloc(ha->ctx_mempool, GFP_ATOMIC);
- if (!ctx) {
- ql_log(ql_log_fatal, vha, 0x3010,
- "Failed to allocate ctx for cmd=%p.\n", cmd);
- goto queuing_error;
- }
-
- memset(ctx, 0, sizeof(struct ct6_dsd));
- ctx->fcp_cmnd = dma_pool_zalloc(ha->fcp_cmnd_dma_pool,
- GFP_ATOMIC, &ctx->fcp_cmnd_dma);
- if (!ctx->fcp_cmnd) {
+ if (qla_get_buf(vha, sp->qpair, &sp->u.scmd.buf_dsc)) {
ql_log(ql_log_fatal, vha, 0x3011,
- "Failed to allocate fcp_cmnd for cmd=%p.\n", cmd);
+ "Failed to allocate buf for fcp_cmnd for cmd=%p.\n", cmd);
goto queuing_error;
}
- /* Initialize the DSD list and dma handle */
- INIT_LIST_HEAD(&ctx->dsd_list);
- ctx->dsd_use_cnt = 0;
+ sp->flags |= SRB_GOT_BUF;
+ ctx = &sp->u.scmd.ct6_ctx;
+ ctx->fcp_cmnd = sp->u.scmd.buf_dsc.buf;
+ ctx->fcp_cmnd_dma = sp->u.scmd.buf_dsc.buf_dma;
if (cmd->cmd_len > 16) {
additional_cdb_len = cmd->cmd_len - 16;
@@ -3144,7 +3179,6 @@ no_dsds:
cmd_pkt->fcp_cmnd_dseg_len = cpu_to_le16(ctx->fcp_cmnd_len);
put_unaligned_le64(ctx->fcp_cmnd_dma, &cmd_pkt->fcp_cmnd_dseg_address);
- sp->flags |= SRB_FCP_CMND_DMA_VALID;
cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd));
/* Set total data segment count. */
cmd_pkt->entry_count = (uint8_t)req_cnt;
@@ -3176,16 +3210,12 @@ no_dsds:
return QLA_SUCCESS;
queuing_error_fcp_cmnd:
- dma_pool_free(ha->fcp_cmnd_dma_pool, ctx->fcp_cmnd, ctx->fcp_cmnd_dma);
queuing_error:
if (tot_dsds)
scsi_dma_unmap(cmd);
- if (sp->u.scmd.ct6_ctx) {
- mempool_free(sp->u.scmd.ct6_ctx, ha->ctx_mempool);
- sp->u.scmd.ct6_ctx = NULL;
- }
- qla_put_iocbs(sp->qpair, &sp->iores);
+ qla_put_buf(sp->qpair, &sp->u.scmd.buf_dsc);
+ qla_put_fw_resources(sp->qpair, &sp->iores);
spin_unlock_irqrestore(lock, flags);
return QLA_FUNCTION_FAILED;
diff --git a/drivers/scsi/qla2xxx/qla_edif.h b/drivers/scsi/qla2xxx/qla_edif.h
index 7cdb89ccdc6e..aa566cdb77e5 100644
--- a/drivers/scsi/qla2xxx/qla_edif.h
+++ b/drivers/scsi/qla2xxx/qla_edif.h
@@ -145,4 +145,6 @@ struct enode {
(qla_ini_mode_enabled(_s->vha) && (_s->disc_state == DSC_DELETE_PEND || \
_s->disc_state == DSC_DELETED))
+#define EDIF_CAP(_ha) (ql2xsecenable && IS_QLA28XX(_ha))
+
#endif /* __QLA_EDIF_H */
diff --git a/drivers/scsi/qla2xxx/qla_edif_bsg.h b/drivers/scsi/qla2xxx/qla_edif_bsg.h
index 0931f4e4e127..514c265ba86e 100644
--- a/drivers/scsi/qla2xxx/qla_edif_bsg.h
+++ b/drivers/scsi/qla2xxx/qla_edif_bsg.h
@@ -89,7 +89,20 @@ struct app_plogi_reply {
struct app_pinfo_req {
struct app_id app_info;
uint8_t num_ports;
- port_id_t remote_pid;
+ struct {
+#ifdef __BIG_ENDIAN
+ uint8_t domain;
+ uint8_t area;
+ uint8_t al_pa;
+#elif defined(__LITTLE_ENDIAN)
+ uint8_t al_pa;
+ uint8_t area;
+ uint8_t domain;
+#else
+#error "__BIG_ENDIAN or __LITTLE_ENDIAN must be defined!"
+#endif
+ uint8_t rsvd_1;
+ } remote_pid;
uint8_t version;
uint8_t pad[VND_CMD_PAD_SIZE];
uint8_t reserved[VND_CMD_APP_RESERVED_SIZE];
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index e3256e721be1..9142df876c73 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -257,6 +257,7 @@ struct edif_sa_ctl *qla_edif_find_sa_ctl_by_index(fc_port_t *fcport,
/*
* Global Functions in qla_mid.c source file.
*/
+extern void qla_update_vp_map(struct scsi_qla_host *, int);
extern struct scsi_host_template qla2xxx_driver_template;
extern struct scsi_transport_template *qla2xxx_transport_vport_template;
extern void qla2x00_timer(struct timer_list *);
@@ -292,6 +293,7 @@ extern void qla2x00_alert_all_vps(struct rsp_que *, uint16_t *);
extern void qla2x00_async_event(scsi_qla_host_t *, struct rsp_que *,
uint16_t *);
extern int qla2x00_vp_abort_isp(scsi_qla_host_t *);
+void qla_adjust_buf(struct scsi_qla_host *);
/*
* Global Function Prototypes in qla_iocb.c source file.
@@ -721,10 +723,6 @@ extern int qla2x00_chk_ms_status(scsi_qla_host_t *, ms_iocb_entry_t *,
struct ct_sns_rsp *, const char *);
extern void qla2x00_async_iocb_timeout(void *data);
-extern int qla24xx_post_gpnid_work(struct scsi_qla_host *, port_id_t *);
-extern int qla24xx_async_gpnid(scsi_qla_host_t *, port_id_t *);
-void qla24xx_handle_gpnid_event(scsi_qla_host_t *, struct event_arg *);
-
int qla24xx_post_gpsc_work(struct scsi_qla_host *, fc_port_t *);
int qla24xx_async_gpsc(scsi_qla_host_t *, fc_port_t *);
void qla24xx_handle_gpsc_event(scsi_qla_host_t *, struct event_arg *);
@@ -734,9 +732,6 @@ int qla24xx_async_gffid(scsi_qla_host_t *vha, fc_port_t *fcport, bool);
int qla24xx_async_gpnft(scsi_qla_host_t *, u8, srb_t *);
void qla24xx_async_gpnft_done(scsi_qla_host_t *, srb_t *);
void qla24xx_async_gnnft_done(scsi_qla_host_t *, srb_t *);
-int qla24xx_async_gnnid(scsi_qla_host_t *, fc_port_t *);
-void qla24xx_handle_gnnid_event(scsi_qla_host_t *, struct event_arg *);
-int qla24xx_post_gnnid_work(struct scsi_qla_host *, fc_port_t *);
int qla24xx_post_gfpnid_work(struct scsi_qla_host *, fc_port_t *);
int qla24xx_async_gfpnid(scsi_qla_host_t *, fc_port_t *);
void qla24xx_handle_gfpnid_event(scsi_qla_host_t *, struct event_arg *);
@@ -962,7 +957,7 @@ extern struct fc_port *qlt_find_sess_invalidate_other(scsi_qla_host_t *,
uint64_t wwn, port_id_t port_id, uint16_t loop_id, struct fc_port **);
void qla24xx_delete_sess_fn(struct work_struct *);
void qlt_unknown_atio_work_fn(struct work_struct *);
-void qlt_update_host_map(struct scsi_qla_host *, port_id_t);
+void qla_update_host_map(struct scsi_qla_host *, port_id_t);
void qla_remove_hostmap(struct qla_hw_data *ha);
void qlt_clr_qp_table(struct scsi_qla_host *vha);
void qlt_set_mode(struct scsi_qla_host *);
@@ -975,6 +970,8 @@ extern void qla_nvme_abort_set_option
(struct abort_entry_24xx *abt, srb_t *sp);
extern void qla_nvme_abort_process_comp_status
(struct abort_entry_24xx *abt, srb_t *sp);
+struct scsi_qla_host *qla_find_host_by_vp_idx(struct scsi_qla_host *vha,
+ uint16_t vp_idx);
/* nvme.c */
void qla_nvme_unregister_remote_port(struct fc_port *fcport);
@@ -1019,5 +1016,8 @@ int qla2xxx_enable_port(struct Scsi_Host *shost);
uint64_t qla2x00_get_num_tgts(scsi_qla_host_t *vha);
uint64_t qla2x00_count_set_bits(u32 num);
-
+int qla_create_buf_pool(struct scsi_qla_host *, struct qla_qpair *);
+void qla_free_buf_pool(struct qla_qpair *);
+int qla_get_buf(struct scsi_qla_host *, struct qla_qpair *, struct qla_buf_dsc *);
+void qla_put_buf(struct qla_qpair *, struct qla_buf_dsc *);
#endif /* _QLA_GBL_H */
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index 64ab070b8716..4738f8935f7f 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -2949,22 +2949,6 @@ done:
return rval;
}
-int qla24xx_post_gpnid_work(struct scsi_qla_host *vha, port_id_t *id)
-{
- struct qla_work_evt *e;
-
- if (test_bit(UNLOADING, &vha->dpc_flags) ||
- (vha->vp_idx && test_bit(VPORT_DELETE, &vha->dpc_flags)))
- return 0;
-
- e = qla2x00_alloc_work(vha, QLA_EVT_GPNID);
- if (!e)
- return QLA_FUNCTION_FAILED;
-
- e->u.gpnid.id = *id;
- return qla2x00_post_work(vha, e);
-}
-
void qla24xx_sp_unmap(scsi_qla_host_t *vha, srb_t *sp)
{
struct srb_iocb *c = &sp->u.iocb_cmd;
@@ -2997,287 +2981,6 @@ void qla24xx_sp_unmap(scsi_qla_host_t *vha, srb_t *sp)
kref_put(&sp->cmd_kref, qla2x00_sp_release);
}
-void qla24xx_handle_gpnid_event(scsi_qla_host_t *vha, struct event_arg *ea)
-{
- fc_port_t *fcport, *conflict, *t;
- u16 data[2];
-
- ql_dbg(ql_dbg_disc, vha, 0xffff,
- "%s %d port_id: %06x\n",
- __func__, __LINE__, ea->id.b24);
-
- if (ea->rc) {
- /* cable is disconnected */
- list_for_each_entry_safe(fcport, t, &vha->vp_fcports, list) {
- if (fcport->d_id.b24 == ea->id.b24)
- fcport->scan_state = QLA_FCPORT_SCAN;
-
- qlt_schedule_sess_for_deletion(fcport);
- }
- } else {
- /* cable is connected */
- fcport = qla2x00_find_fcport_by_wwpn(vha, ea->port_name, 1);
- if (fcport) {
- list_for_each_entry_safe(conflict, t, &vha->vp_fcports,
- list) {
- if ((conflict->d_id.b24 == ea->id.b24) &&
- (fcport != conflict))
- /*
- * 2 fcports with conflict Nport ID or
- * an existing fcport is having nport ID
- * conflict with new fcport.
- */
-
- conflict->scan_state = QLA_FCPORT_SCAN;
-
- qlt_schedule_sess_for_deletion(conflict);
- }
-
- fcport->scan_needed = 0;
- fcport->rscn_gen++;
- fcport->scan_state = QLA_FCPORT_FOUND;
- fcport->flags |= FCF_FABRIC_DEVICE;
- if (fcport->login_retry == 0) {
- fcport->login_retry =
- vha->hw->login_retry_count;
- ql_dbg(ql_dbg_disc, vha, 0xffff,
- "Port login retry %8phN, lid 0x%04x cnt=%d.\n",
- fcport->port_name, fcport->loop_id,
- fcport->login_retry);
- }
- switch (fcport->disc_state) {
- case DSC_LOGIN_COMPLETE:
- /* recheck session is still intact. */
- ql_dbg(ql_dbg_disc, vha, 0x210d,
- "%s %d %8phC revalidate session with ADISC\n",
- __func__, __LINE__, fcport->port_name);
- data[0] = data[1] = 0;
- qla2x00_post_async_adisc_work(vha, fcport,
- data);
- break;
- case DSC_DELETED:
- ql_dbg(ql_dbg_disc, vha, 0x210d,
- "%s %d %8phC login\n", __func__, __LINE__,
- fcport->port_name);
- fcport->d_id = ea->id;
- qla24xx_fcport_handle_login(vha, fcport);
- break;
- case DSC_DELETE_PEND:
- fcport->d_id = ea->id;
- break;
- default:
- fcport->d_id = ea->id;
- break;
- }
- } else {
- list_for_each_entry_safe(conflict, t, &vha->vp_fcports,
- list) {
- if (conflict->d_id.b24 == ea->id.b24) {
- /* 2 fcports with conflict Nport ID or
- * an existing fcport is having nport ID
- * conflict with new fcport.
- */
- ql_dbg(ql_dbg_disc, vha, 0xffff,
- "%s %d %8phC DS %d\n",
- __func__, __LINE__,
- conflict->port_name,
- conflict->disc_state);
-
- conflict->scan_state = QLA_FCPORT_SCAN;
- qlt_schedule_sess_for_deletion(conflict);
- }
- }
-
- /* create new fcport */
- ql_dbg(ql_dbg_disc, vha, 0x2065,
- "%s %d %8phC post new sess\n",
- __func__, __LINE__, ea->port_name);
- qla24xx_post_newsess_work(vha, &ea->id,
- ea->port_name, NULL, NULL, 0);
- }
- }
-}
-
-static void qla2x00_async_gpnid_sp_done(srb_t *sp, int res)
-{
- struct scsi_qla_host *vha = sp->vha;
- struct ct_sns_req *ct_req =
- (struct ct_sns_req *)sp->u.iocb_cmd.u.ctarg.req;
- struct ct_sns_rsp *ct_rsp =
- (struct ct_sns_rsp *)sp->u.iocb_cmd.u.ctarg.rsp;
- struct event_arg ea;
- struct qla_work_evt *e;
- unsigned long flags;
-
- if (res)
- ql_dbg(ql_dbg_disc, vha, 0x2066,
- "Async done-%s fail res %x rscn gen %d ID %3phC. %8phC\n",
- sp->name, res, sp->gen1, &ct_req->req.port_id.port_id,
- ct_rsp->rsp.gpn_id.port_name);
- else
- ql_dbg(ql_dbg_disc, vha, 0x2066,
- "Async done-%s good rscn gen %d ID %3phC. %8phC\n",
- sp->name, sp->gen1, &ct_req->req.port_id.port_id,
- ct_rsp->rsp.gpn_id.port_name);
-
- memset(&ea, 0, sizeof(ea));
- memcpy(ea.port_name, ct_rsp->rsp.gpn_id.port_name, WWN_SIZE);
- ea.sp = sp;
- ea.id = be_to_port_id(ct_req->req.port_id.port_id);
- ea.rc = res;
-
- spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
- list_del(&sp->elem);
- spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
-
- if (res) {
- if (res == QLA_FUNCTION_TIMEOUT) {
- qla24xx_post_gpnid_work(sp->vha, &ea.id);
- /* ref: INIT */
- kref_put(&sp->cmd_kref, qla2x00_sp_release);
- return;
- }
- } else if (sp->gen1) {
- /* There was another RSCN for this Nport ID */
- qla24xx_post_gpnid_work(sp->vha, &ea.id);
- /* ref: INIT */
- kref_put(&sp->cmd_kref, qla2x00_sp_release);
- return;
- }
-
- qla24xx_handle_gpnid_event(vha, &ea);
-
- e = qla2x00_alloc_work(vha, QLA_EVT_UNMAP);
- if (!e) {
- /* please ignore kernel warning. otherwise, we have mem leak. */
- dma_free_coherent(&vha->hw->pdev->dev,
- sp->u.iocb_cmd.u.ctarg.req_allocated_size,
- sp->u.iocb_cmd.u.ctarg.req,
- sp->u.iocb_cmd.u.ctarg.req_dma);
- sp->u.iocb_cmd.u.ctarg.req = NULL;
-
- dma_free_coherent(&vha->hw->pdev->dev,
- sp->u.iocb_cmd.u.ctarg.rsp_allocated_size,
- sp->u.iocb_cmd.u.ctarg.rsp,
- sp->u.iocb_cmd.u.ctarg.rsp_dma);
- sp->u.iocb_cmd.u.ctarg.rsp = NULL;
-
- /* ref: INIT */
- kref_put(&sp->cmd_kref, qla2x00_sp_release);
- return;
- }
-
- e->u.iosb.sp = sp;
- qla2x00_post_work(vha, e);
-}
-
-/* Get WWPN with Nport ID. */
-int qla24xx_async_gpnid(scsi_qla_host_t *vha, port_id_t *id)
-{
- int rval = QLA_FUNCTION_FAILED;
- struct ct_sns_req *ct_req;
- srb_t *sp, *tsp;
- struct ct_sns_pkt *ct_sns;
- unsigned long flags;
-
- if (!vha->flags.online)
- goto done;
-
- /* ref: INIT */
- sp = qla2x00_get_sp(vha, NULL, GFP_KERNEL);
- if (!sp)
- goto done;
-
- sp->type = SRB_CT_PTHRU_CMD;
- sp->name = "gpnid";
- sp->u.iocb_cmd.u.ctarg.id = *id;
- sp->gen1 = 0;
- qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2,
- qla2x00_async_gpnid_sp_done);
-
- spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
- list_for_each_entry(tsp, &vha->gpnid_list, elem) {
- if (tsp->u.iocb_cmd.u.ctarg.id.b24 == id->b24) {
- tsp->gen1++;
- spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
- /* ref: INIT */
- kref_put(&sp->cmd_kref, qla2x00_sp_release);
- goto done;
- }
- }
- list_add_tail(&sp->elem, &vha->gpnid_list);
- spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
-
- sp->u.iocb_cmd.u.ctarg.req = dma_alloc_coherent(&vha->hw->pdev->dev,
- sizeof(struct ct_sns_pkt), &sp->u.iocb_cmd.u.ctarg.req_dma,
- GFP_KERNEL);
- sp->u.iocb_cmd.u.ctarg.req_allocated_size = sizeof(struct ct_sns_pkt);
- if (!sp->u.iocb_cmd.u.ctarg.req) {
- ql_log(ql_log_warn, vha, 0xd041,
- "Failed to allocate ct_sns request.\n");
- goto done_free_sp;
- }
-
- sp->u.iocb_cmd.u.ctarg.rsp = dma_alloc_coherent(&vha->hw->pdev->dev,
- sizeof(struct ct_sns_pkt), &sp->u.iocb_cmd.u.ctarg.rsp_dma,
- GFP_KERNEL);
- sp->u.iocb_cmd.u.ctarg.rsp_allocated_size = sizeof(struct ct_sns_pkt);
- if (!sp->u.iocb_cmd.u.ctarg.rsp) {
- ql_log(ql_log_warn, vha, 0xd042,
- "Failed to allocate ct_sns request.\n");
- goto done_free_sp;
- }
-
- ct_sns = (struct ct_sns_pkt *)sp->u.iocb_cmd.u.ctarg.rsp;
- memset(ct_sns, 0, sizeof(*ct_sns));
-
- ct_sns = (struct ct_sns_pkt *)sp->u.iocb_cmd.u.ctarg.req;
- /* CT_IU preamble */
- ct_req = qla2x00_prep_ct_req(ct_sns, GPN_ID_CMD, GPN_ID_RSP_SIZE);
-
- /* GPN_ID req */
- ct_req->req.port_id.port_id = port_id_to_be_id(*id);
-
- sp->u.iocb_cmd.u.ctarg.req_size = GPN_ID_REQ_SIZE;
- sp->u.iocb_cmd.u.ctarg.rsp_size = GPN_ID_RSP_SIZE;
- sp->u.iocb_cmd.u.ctarg.nport_handle = NPH_SNS;
-
- ql_dbg(ql_dbg_disc, vha, 0x2067,
- "Async-%s hdl=%x ID %3phC.\n", sp->name,
- sp->handle, &ct_req->req.port_id.port_id);
-
- rval = qla2x00_start_sp(sp);
- if (rval != QLA_SUCCESS)
- goto done_free_sp;
-
- return rval;
-
-done_free_sp:
- spin_lock_irqsave(&vha->hw->vport_slock, flags);
- list_del(&sp->elem);
- spin_unlock_irqrestore(&vha->hw->vport_slock, flags);
-
- if (sp->u.iocb_cmd.u.ctarg.req) {
- dma_free_coherent(&vha->hw->pdev->dev,
- sizeof(struct ct_sns_pkt),
- sp->u.iocb_cmd.u.ctarg.req,
- sp->u.iocb_cmd.u.ctarg.req_dma);
- sp->u.iocb_cmd.u.ctarg.req = NULL;
- }
- if (sp->u.iocb_cmd.u.ctarg.rsp) {
- dma_free_coherent(&vha->hw->pdev->dev,
- sizeof(struct ct_sns_pkt),
- sp->u.iocb_cmd.u.ctarg.rsp,
- sp->u.iocb_cmd.u.ctarg.rsp_dma);
- sp->u.iocb_cmd.u.ctarg.rsp = NULL;
- }
- /* ref: INIT */
- kref_put(&sp->cmd_kref, qla2x00_sp_release);
-done:
- return rval;
-}
-
-
void qla24xx_async_gffid_sp_done(srb_t *sp, int res)
{
struct scsi_qla_host *vha = sp->vha;
@@ -4190,116 +3893,6 @@ void qla_scan_work_fn(struct work_struct *work)
spin_unlock_irqrestore(&vha->work_lock, flags);
}
-/* GNN_ID */
-void qla24xx_handle_gnnid_event(scsi_qla_host_t *vha, struct event_arg *ea)
-{
- qla24xx_post_gnl_work(vha, ea->fcport);
-}
-
-static void qla2x00_async_gnnid_sp_done(srb_t *sp, int res)
-{
- struct scsi_qla_host *vha = sp->vha;
- fc_port_t *fcport = sp->fcport;
- u8 *node_name = fcport->ct_desc.ct_sns->p.rsp.rsp.gnn_id.node_name;
- struct event_arg ea;
- u64 wwnn;
-
- fcport->flags &= ~FCF_ASYNC_SENT;
- wwnn = wwn_to_u64(node_name);
- if (wwnn)
- memcpy(fcport->node_name, node_name, WWN_SIZE);
-
- memset(&ea, 0, sizeof(ea));
- ea.fcport = fcport;
- ea.sp = sp;
- ea.rc = res;
-
- ql_dbg(ql_dbg_disc, vha, 0x204f,
- "Async done-%s res %x, WWPN %8phC %8phC\n",
- sp->name, res, fcport->port_name, fcport->node_name);
-
- qla24xx_handle_gnnid_event(vha, &ea);
-
- /* ref: INIT */
- kref_put(&sp->cmd_kref, qla2x00_sp_release);
-}
-
-int qla24xx_async_gnnid(scsi_qla_host_t *vha, fc_port_t *fcport)
-{
- int rval = QLA_FUNCTION_FAILED;
- struct ct_sns_req *ct_req;
- srb_t *sp;
-
- if (!vha->flags.online || (fcport->flags & FCF_ASYNC_SENT))
- return rval;
-
- qla2x00_set_fcport_disc_state(fcport, DSC_GNN_ID);
- /* ref: INIT */
- sp = qla2x00_get_sp(vha, fcport, GFP_ATOMIC);
- if (!sp)
- goto done;
-
- fcport->flags |= FCF_ASYNC_SENT;
- sp->type = SRB_CT_PTHRU_CMD;
- sp->name = "gnnid";
- sp->gen1 = fcport->rscn_gen;
- sp->gen2 = fcport->login_gen;
- qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2,
- qla2x00_async_gnnid_sp_done);
-
- /* CT_IU preamble */
- ct_req = qla2x00_prep_ct_req(fcport->ct_desc.ct_sns, GNN_ID_CMD,
- GNN_ID_RSP_SIZE);
-
- /* GNN_ID req */
- ct_req->req.port_id.port_id = port_id_to_be_id(fcport->d_id);
-
-
- /* req & rsp use the same buffer */
- sp->u.iocb_cmd.u.ctarg.req = fcport->ct_desc.ct_sns;
- sp->u.iocb_cmd.u.ctarg.req_dma = fcport->ct_desc.ct_sns_dma;
- sp->u.iocb_cmd.u.ctarg.rsp = fcport->ct_desc.ct_sns;
- sp->u.iocb_cmd.u.ctarg.rsp_dma = fcport->ct_desc.ct_sns_dma;
- sp->u.iocb_cmd.u.ctarg.req_size = GNN_ID_REQ_SIZE;
- sp->u.iocb_cmd.u.ctarg.rsp_size = GNN_ID_RSP_SIZE;
- sp->u.iocb_cmd.u.ctarg.nport_handle = NPH_SNS;
-
- ql_dbg(ql_dbg_disc, vha, 0xffff,
- "Async-%s - %8phC hdl=%x loopid=%x portid %06x.\n",
- sp->name, fcport->port_name,
- sp->handle, fcport->loop_id, fcport->d_id.b24);
-
- rval = qla2x00_start_sp(sp);
- if (rval != QLA_SUCCESS)
- goto done_free_sp;
- return rval;
-
-done_free_sp:
- /* ref: INIT */
- kref_put(&sp->cmd_kref, qla2x00_sp_release);
- fcport->flags &= ~FCF_ASYNC_SENT;
-done:
- return rval;
-}
-
-int qla24xx_post_gnnid_work(struct scsi_qla_host *vha, fc_port_t *fcport)
-{
- struct qla_work_evt *e;
- int ls;
-
- ls = atomic_read(&vha->loop_state);
- if (((ls != LOOP_READY) && (ls != LOOP_UP)) ||
- test_bit(UNLOADING, &vha->dpc_flags))
- return 0;
-
- e = qla2x00_alloc_work(vha, QLA_EVT_GNNID);
- if (!e)
- return QLA_FUNCTION_FAILED;
-
- e->u.fcport.fcport = fcport;
- return qla2x00_post_work(vha, e);
-}
-
/* GPFN_ID */
void qla24xx_handle_gfpnid_event(scsi_qla_host_t *vha, struct event_arg *ea)
{
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 8d9ecabb1aac..1dbc1496ebed 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -128,12 +128,14 @@ static void qla24xx_abort_iocb_timeout(void *data)
sp->cmd_sp)) {
qpair->req->outstanding_cmds[handle] = NULL;
cmdsp_found = 1;
+ qla_put_fw_resources(qpair, &sp->cmd_sp->iores);
}
/* removing the abort */
if (qpair->req->outstanding_cmds[handle] == sp) {
qpair->req->outstanding_cmds[handle] = NULL;
sp_found = 1;
+ qla_put_fw_resources(qpair, &sp->iores);
break;
}
}
@@ -388,6 +390,12 @@ done_free_sp:
fcport->flags &= ~FCF_ASYNC_SENT;
done:
fcport->flags &= ~FCF_ASYNC_ACTIVE;
+
+ /*
+ * async login failed. Could be due to iocb/exchange resource
+ * being low. Set state DELETED for re-login process to start again.
+ */
+ qla2x00_set_fcport_disc_state(fcport, DSC_DELETED);
return rval;
}
@@ -1646,7 +1654,6 @@ static void qla_chk_n2n_b4_login(struct scsi_qla_host *vha, fc_port_t *fcport)
int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport)
{
u16 data[2];
- u64 wwn;
u16 sec;
ql_dbg(ql_dbg_disc, vha, 0x20d8,
@@ -1686,7 +1693,6 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport)
switch (fcport->disc_state) {
case DSC_DELETED:
- wwn = wwn_to_u64(fcport->node_name);
switch (vha->hw->current_topology) {
case ISP_CFG_N:
if (fcport_is_smaller(fcport)) {
@@ -1710,12 +1716,7 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport)
}
break;
default:
- if (wwn == 0) {
- ql_dbg(ql_dbg_disc, vha, 0xffff,
- "%s %d %8phC post GNNID\n",
- __func__, __LINE__, fcport->port_name);
- qla24xx_post_gnnid_work(vha, fcport);
- } else if (fcport->loop_id == FC_NO_LOOP_ID) {
+ if (fcport->loop_id == FC_NO_LOOP_ID) {
ql_dbg(ql_dbg_disc, vha, 0x20bd,
"%s %d %8phC post gnl\n",
__func__, __LINE__, fcport->port_name);
@@ -2000,6 +2001,7 @@ qla2x00_tmf_iocb_timeout(void *data)
for (h = 1; h < sp->qpair->req->num_outstanding_cmds; h++) {
if (sp->qpair->req->outstanding_cmds[h] == sp) {
sp->qpair->req->outstanding_cmds[h] = NULL;
+ qla_put_fw_resources(sp->qpair, &sp->iores);
break;
}
}
@@ -2073,7 +2075,6 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun,
done_free_sp:
/* ref: INIT */
kref_put(&sp->cmd_kref, qla2x00_sp_release);
- fcport->flags &= ~FCF_ASYNC_SENT;
done:
return rval;
}
@@ -2315,7 +2316,7 @@ qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea)
ea->fcport->login_pause = 1;
ql_dbg(ql_dbg_disc, vha, 0x20ed,
- "%s %d %8phC NPortId %06x inuse with loopid 0x%x. post gidpn\n",
+ "%s %d %8phC NPortId %06x inuse with loopid 0x%x.\n",
__func__, __LINE__, ea->fcport->port_name,
ea->fcport->d_id.b24, lid);
} else {
@@ -3943,6 +3944,12 @@ void qla_init_iocb_limit(scsi_qla_host_t *vha)
ha->base_qpair->fwres.iocbs_limit = limit;
ha->base_qpair->fwres.iocbs_qp_limit = limit / num_qps;
ha->base_qpair->fwres.iocbs_used = 0;
+
+ ha->base_qpair->fwres.exch_total = ha->orig_fw_xcb_count;
+ ha->base_qpair->fwres.exch_limit = (ha->orig_fw_xcb_count *
+ QLA_IOCB_PCT_LIMIT) / 100;
+ ha->base_qpair->fwres.exch_used = 0;
+
for (i = 0; i < ha->max_qpairs; i++) {
if (ha->queue_pair_map[i]) {
ha->queue_pair_map[i]->fwres.iocbs_total =
@@ -3951,6 +3958,10 @@ void qla_init_iocb_limit(scsi_qla_host_t *vha)
ha->queue_pair_map[i]->fwres.iocbs_qp_limit =
limit / num_qps;
ha->queue_pair_map[i]->fwres.iocbs_used = 0;
+ ha->queue_pair_map[i]->fwres.exch_total = ha->orig_fw_xcb_count;
+ ha->queue_pair_map[i]->fwres.exch_limit =
+ (ha->orig_fw_xcb_count * QLA_IOCB_PCT_LIMIT) / 100;
+ ha->queue_pair_map[i]->fwres.exch_used = 0;
}
}
}
@@ -4809,9 +4820,9 @@ qla2x00_configure_hba(scsi_qla_host_t *vha)
spin_lock_irqsave(&ha->hardware_lock, flags);
if (vha->hw->flags.edif_enabled) {
if (topo != 2)
- qlt_update_host_map(vha, id);
+ qla_update_host_map(vha, id);
} else if (!(topo == 2 && ha->flags.n2n_bigger))
- qlt_update_host_map(vha, id);
+ qla_update_host_map(vha, id);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
if (!vha->flags.init_done)
@@ -5206,27 +5217,6 @@ qla2x00_nvram_config(scsi_qla_host_t *vha)
return (rval);
}
-static void
-qla2x00_rport_del(void *data)
-{
- fc_port_t *fcport = data;
- struct fc_rport *rport;
- unsigned long flags;
-
- spin_lock_irqsave(fcport->vha->host->host_lock, flags);
- rport = fcport->drport ? fcport->drport : fcport->rport;
- fcport->drport = NULL;
- spin_unlock_irqrestore(fcport->vha->host->host_lock, flags);
- if (rport) {
- ql_dbg(ql_dbg_disc, fcport->vha, 0x210b,
- "%s %8phN. rport %p roles %x\n",
- __func__, fcport->port_name, rport,
- rport->roles);
-
- fc_remote_port_delete(rport);
- }
-}
-
void qla2x00_set_fcport_state(fc_port_t *fcport, int state)
{
int old_state;
@@ -6743,33 +6733,6 @@ int qla2x00_perform_loop_resync(scsi_qla_host_t *ha)
return rval;
}
-void
-qla2x00_update_fcports(scsi_qla_host_t *base_vha)
-{
- fc_port_t *fcport;
- struct scsi_qla_host *vha, *tvp;
- struct qla_hw_data *ha = base_vha->hw;
- unsigned long flags;
-
- spin_lock_irqsave(&ha->vport_slock, flags);
- /* Go with deferred removal of rport references. */
- list_for_each_entry_safe(vha, tvp, &base_vha->hw->vp_list, list) {
- atomic_inc(&vha->vref_count);
- list_for_each_entry(fcport, &vha->vp_fcports, list) {
- if (fcport->drport &&
- atomic_read(&fcport->state) != FCS_UNCONFIGURED) {
- spin_unlock_irqrestore(&ha->vport_slock, flags);
- qla2x00_rport_del(fcport);
-
- spin_lock_irqsave(&ha->vport_slock, flags);
- }
- }
- atomic_dec(&vha->vref_count);
- wake_up(&vha->vref_waitq);
- }
- spin_unlock_irqrestore(&ha->vport_slock, flags);
-}
-
/* Assumes idc_lock always held on entry */
void
qla83xx_reset_ownership(scsi_qla_host_t *vha)
@@ -9461,8 +9424,6 @@ struct qla_qpair *qla2xxx_create_qpair(struct scsi_qla_host *vha, int qos,
qpair->req = ha->req_q_map[req_id];
qpair->rsp->req = qpair->req;
qpair->rsp->qpair = qpair;
- /* init qpair to this cpu. Will adjust at run time. */
- qla_cpu_update(qpair, raw_smp_processor_id());
if (IS_T10_PI_CAPABLE(ha) && ql2xenabledif) {
if (ha->fw_attributes & BIT_4)
@@ -9477,6 +9438,13 @@ struct qla_qpair *qla2xxx_create_qpair(struct scsi_qla_host *vha, int qos,
goto fail_mempool;
}
+ if (qla_create_buf_pool(vha, qpair)) {
+ ql_log(ql_log_warn, vha, 0xd036,
+ "Failed to initialize buf pool for qpair %d\n",
+ qpair->id);
+ goto fail_bufpool;
+ }
+
/* Mark as online */
qpair->online = 1;
@@ -9492,7 +9460,10 @@ struct qla_qpair *qla2xxx_create_qpair(struct scsi_qla_host *vha, int qos,
}
return qpair;
+fail_bufpool:
+ mempool_destroy(qpair->srb_mempool);
fail_mempool:
+ qla25xx_delete_req_que(vha, qpair->req);
fail_req:
qla25xx_delete_rsp_que(vha, qpair->rsp);
fail_rsp:
@@ -9518,6 +9489,8 @@ int qla2xxx_delete_qpair(struct scsi_qla_host *vha, struct qla_qpair *qpair)
qpair->delete_in_progress = 1;
+ qla_free_buf_pool(qpair);
+
ret = qla25xx_delete_req_que(vha, qpair->req);
if (ret != QLA_SUCCESS)
goto fail;
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
index 5185dc5daf80..cce6e425c121 100644
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -380,24 +380,26 @@ qla2xxx_get_fc4_priority(struct scsi_qla_host *vha)
enum {
RESOURCE_NONE,
- RESOURCE_INI,
+ RESOURCE_IOCB = BIT_0,
+ RESOURCE_EXCH = BIT_1, /* exchange */
+ RESOURCE_FORCE = BIT_2,
};
static inline int
-qla_get_iocbs(struct qla_qpair *qp, struct iocb_resource *iores)
+qla_get_fw_resources(struct qla_qpair *qp, struct iocb_resource *iores)
{
u16 iocbs_used, i;
+ u16 exch_used;
struct qla_hw_data *ha = qp->vha->hw;
if (!ql2xenforce_iocb_limit) {
iores->res_type = RESOURCE_NONE;
return 0;
}
+ if (iores->res_type & RESOURCE_FORCE)
+ goto force;
- if ((iores->iocb_cnt + qp->fwres.iocbs_used) < qp->fwres.iocbs_qp_limit) {
- qp->fwres.iocbs_used += iores->iocb_cnt;
- return 0;
- } else {
+ if ((iores->iocb_cnt + qp->fwres.iocbs_used) >= qp->fwres.iocbs_qp_limit) {
/* no need to acquire qpair lock. It's just rough calculation */
iocbs_used = ha->base_qpair->fwres.iocbs_used;
for (i = 0; i < ha->max_qpairs; i++) {
@@ -405,30 +407,49 @@ qla_get_iocbs(struct qla_qpair *qp, struct iocb_resource *iores)
iocbs_used += ha->queue_pair_map[i]->fwres.iocbs_used;
}
- if ((iores->iocb_cnt + iocbs_used) < qp->fwres.iocbs_limit) {
- qp->fwres.iocbs_used += iores->iocb_cnt;
- return 0;
- } else {
+ if ((iores->iocb_cnt + iocbs_used) >= qp->fwres.iocbs_limit) {
+ iores->res_type = RESOURCE_NONE;
+ return -ENOSPC;
+ }
+ }
+
+ if (iores->res_type & RESOURCE_EXCH) {
+ exch_used = ha->base_qpair->fwres.exch_used;
+ for (i = 0; i < ha->max_qpairs; i++) {
+ if (ha->queue_pair_map[i])
+ exch_used += ha->queue_pair_map[i]->fwres.exch_used;
+ }
+
+ if ((exch_used + iores->exch_cnt) >= qp->fwres.exch_limit) {
iores->res_type = RESOURCE_NONE;
return -ENOSPC;
}
}
+force:
+ qp->fwres.iocbs_used += iores->iocb_cnt;
+ qp->fwres.exch_used += iores->exch_cnt;
+ return 0;
}
static inline void
-qla_put_iocbs(struct qla_qpair *qp, struct iocb_resource *iores)
+qla_put_fw_resources(struct qla_qpair *qp, struct iocb_resource *iores)
{
- switch (iores->res_type) {
- case RESOURCE_NONE:
- break;
- default:
+ if (iores->res_type & RESOURCE_IOCB) {
if (qp->fwres.iocbs_used >= iores->iocb_cnt) {
qp->fwres.iocbs_used -= iores->iocb_cnt;
} else {
- // should not happen
+ /* should not happen */
qp->fwres.iocbs_used = 0;
}
- break;
+ }
+
+ if (iores->res_type & RESOURCE_EXCH) {
+ if (qp->fwres.exch_used >= iores->exch_cnt) {
+ qp->fwres.exch_used -= iores->exch_cnt;
+ } else {
+ /* should not happen */
+ qp->fwres.exch_used = 0;
+ }
}
iores->res_type = RESOURCE_NONE;
}
@@ -494,3 +515,58 @@ fcport_is_bigger(fc_port_t *fcport)
{
return !fcport_is_smaller(fcport);
}
+
+static inline struct qla_qpair *
+qla_mapq_nvme_select_qpair(struct qla_hw_data *ha, struct qla_qpair *qpair)
+{
+ int cpuid = smp_processor_id();
+
+ if (qpair->cpuid != cpuid &&
+ ha->qp_cpu_map[cpuid]) {
+ qpair = ha->qp_cpu_map[cpuid];
+ }
+ return qpair;
+}
+
+static inline void
+qla_mapq_init_qp_cpu_map(struct qla_hw_data *ha,
+ struct qla_msix_entry *msix,
+ struct qla_qpair *qpair)
+{
+ const struct cpumask *mask;
+ unsigned int cpu;
+
+ if (!ha->qp_cpu_map)
+ return;
+ mask = pci_irq_get_affinity(ha->pdev, msix->vector_base0);
+ qpair->cpuid = cpumask_first(mask);
+ for_each_cpu(cpu, mask) {
+ ha->qp_cpu_map[cpu] = qpair;
+ }
+ msix->cpuid = qpair->cpuid;
+}
+
+static inline void
+qla_mapq_free_qp_cpu_map(struct qla_hw_data *ha)
+{
+ if (ha->qp_cpu_map) {
+ kfree(ha->qp_cpu_map);
+ ha->qp_cpu_map = NULL;
+ }
+}
+
+static inline int qla_mapq_alloc_qp_cpu_map(struct qla_hw_data *ha)
+{
+ scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
+
+ if (!ha->qp_cpu_map) {
+ ha->qp_cpu_map = kcalloc(NR_CPUS, sizeof(struct qla_qpair *),
+ GFP_KERNEL);
+ if (!ha->qp_cpu_map) {
+ ql_log(ql_log_fatal, vha, 0x0180,
+ "Unable to allocate memory for qp_cpu_map ptrs.\n");
+ return -1;
+ }
+ }
+ return 0;
+}
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index 42ce4e1fe744..b9b3e6f80ea9 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -623,7 +623,7 @@ qla24xx_build_scsi_type_6_iocbs(srb_t *sp, struct cmd_type_6 *cmd_pkt,
}
cur_seg = scsi_sglist(cmd);
- ctx = sp->u.scmd.ct6_ctx;
+ ctx = &sp->u.scmd.ct6_ctx;
while (tot_dsds) {
avail_dsds = (tot_dsds > QLA_DSDS_PER_IOCB) ?
@@ -1589,9 +1589,10 @@ qla24xx_start_scsi(srb_t *sp)
tot_dsds = nseg;
req_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
- sp->iores.res_type = RESOURCE_INI;
+ sp->iores.res_type = RESOURCE_IOCB | RESOURCE_EXCH;
+ sp->iores.exch_cnt = 1;
sp->iores.iocb_cnt = req_cnt;
- if (qla_get_iocbs(sp->qpair, &sp->iores))
+ if (qla_get_fw_resources(sp->qpair, &sp->iores))
goto queuing_error;
if (req->cnt < (req_cnt + 2)) {
@@ -1678,7 +1679,7 @@ queuing_error:
if (tot_dsds)
scsi_dma_unmap(cmd);
- qla_put_iocbs(sp->qpair, &sp->iores);
+ qla_put_fw_resources(sp->qpair, &sp->iores);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return QLA_FUNCTION_FAILED;
@@ -1793,9 +1794,10 @@ qla24xx_dif_start_scsi(srb_t *sp)
tot_prot_dsds = nseg;
tot_dsds += nseg;
- sp->iores.res_type = RESOURCE_INI;
+ sp->iores.res_type = RESOURCE_IOCB | RESOURCE_EXCH;
+ sp->iores.exch_cnt = 1;
sp->iores.iocb_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
- if (qla_get_iocbs(sp->qpair, &sp->iores))
+ if (qla_get_fw_resources(sp->qpair, &sp->iores))
goto queuing_error;
if (req->cnt < (req_cnt + 2)) {
@@ -1883,7 +1885,7 @@ queuing_error:
}
/* Cleanup will be performed by the caller (queuecommand) */
- qla_put_iocbs(sp->qpair, &sp->iores);
+ qla_put_fw_resources(sp->qpair, &sp->iores);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return QLA_FUNCTION_FAILED;
@@ -1952,9 +1954,10 @@ qla2xxx_start_scsi_mq(srb_t *sp)
tot_dsds = nseg;
req_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
- sp->iores.res_type = RESOURCE_INI;
+ sp->iores.res_type = RESOURCE_IOCB | RESOURCE_EXCH;
+ sp->iores.exch_cnt = 1;
sp->iores.iocb_cnt = req_cnt;
- if (qla_get_iocbs(sp->qpair, &sp->iores))
+ if (qla_get_fw_resources(sp->qpair, &sp->iores))
goto queuing_error;
if (req->cnt < (req_cnt + 2)) {
@@ -2041,7 +2044,7 @@ queuing_error:
if (tot_dsds)
scsi_dma_unmap(cmd);
- qla_put_iocbs(sp->qpair, &sp->iores);
+ qla_put_fw_resources(sp->qpair, &sp->iores);
spin_unlock_irqrestore(&qpair->qp_lock, flags);
return QLA_FUNCTION_FAILED;
@@ -2171,9 +2174,10 @@ qla2xxx_dif_start_scsi_mq(srb_t *sp)
tot_prot_dsds = nseg;
tot_dsds += nseg;
- sp->iores.res_type = RESOURCE_INI;
+ sp->iores.res_type = RESOURCE_IOCB | RESOURCE_EXCH;
+ sp->iores.exch_cnt = 1;
sp->iores.iocb_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
- if (qla_get_iocbs(sp->qpair, &sp->iores))
+ if (qla_get_fw_resources(sp->qpair, &sp->iores))
goto queuing_error;
if (req->cnt < (req_cnt + 2)) {
@@ -2260,7 +2264,7 @@ queuing_error:
}
/* Cleanup will be performed by the caller (queuecommand) */
- qla_put_iocbs(sp->qpair, &sp->iores);
+ qla_put_fw_resources(sp->qpair, &sp->iores);
spin_unlock_irqrestore(&qpair->qp_lock, flags);
return QLA_FUNCTION_FAILED;
@@ -2916,7 +2920,7 @@ static void qla2x00_els_dcmd2_sp_done(srb_t *sp, int res)
conflict_fcport->conflict = fcport;
fcport->login_pause = 1;
ql_dbg(ql_dbg_disc, vha, 0x20ed,
- "%s %d %8phC pid %06x inuse with lid %#x post gidpn\n",
+ "%s %d %8phC pid %06x inuse with lid %#x.\n",
__func__, __LINE__,
fcport->port_name,
fcport->d_id.b24, lid);
@@ -3455,13 +3459,7 @@ sufficient_dsds:
goto queuing_error;
}
- ctx = sp->u.scmd.ct6_ctx =
- mempool_alloc(ha->ctx_mempool, GFP_ATOMIC);
- if (!ctx) {
- ql_log(ql_log_fatal, vha, 0x3010,
- "Failed to allocate ctx for cmd=%p.\n", cmd);
- goto queuing_error;
- }
+ ctx = &sp->u.scmd.ct6_ctx;
memset(ctx, 0, sizeof(struct ct6_dsd));
ctx->fcp_cmnd = dma_pool_zalloc(ha->fcp_cmnd_dma_pool,
@@ -3813,6 +3811,65 @@ qla24xx_prlo_iocb(srb_t *sp, struct logio_entry_24xx *logio)
logio->vp_index = sp->fcport->vha->vp_idx;
}
+static int qla_get_iocbs_resource(struct srb *sp)
+{
+ bool get_exch;
+ bool push_it_through = false;
+
+ if (!ql2xenforce_iocb_limit) {
+ sp->iores.res_type = RESOURCE_NONE;
+ return 0;
+ }
+ sp->iores.res_type = RESOURCE_NONE;
+
+ switch (sp->type) {
+ case SRB_TM_CMD:
+ case SRB_PRLI_CMD:
+ case SRB_ADISC_CMD:
+ push_it_through = true;
+ fallthrough;
+ case SRB_LOGIN_CMD:
+ case SRB_ELS_CMD_RPT:
+ case SRB_ELS_CMD_HST:
+ case SRB_ELS_CMD_HST_NOLOGIN:
+ case SRB_CT_CMD:
+ case SRB_NVME_LS:
+ case SRB_ELS_DCMD:
+ get_exch = true;
+ break;
+
+ case SRB_FXIOCB_DCMD:
+ case SRB_FXIOCB_BCMD:
+ sp->iores.res_type = RESOURCE_NONE;
+ return 0;
+
+ case SRB_SA_UPDATE:
+ case SRB_SA_REPLACE:
+ case SRB_MB_IOCB:
+ case SRB_ABT_CMD:
+ case SRB_NACK_PLOGI:
+ case SRB_NACK_PRLI:
+ case SRB_NACK_LOGO:
+ case SRB_LOGOUT_CMD:
+ case SRB_CTRL_VP:
+ push_it_through = true;
+ fallthrough;
+ default:
+ get_exch = false;
+ }
+
+ sp->iores.res_type |= RESOURCE_IOCB;
+ sp->iores.iocb_cnt = 1;
+ if (get_exch) {
+ sp->iores.res_type |= RESOURCE_EXCH;
+ sp->iores.exch_cnt = 1;
+ }
+ if (push_it_through)
+ sp->iores.res_type |= RESOURCE_FORCE;
+
+ return qla_get_fw_resources(sp->qpair, &sp->iores);
+}
+
int
qla2x00_start_sp(srb_t *sp)
{
@@ -3827,6 +3884,12 @@ qla2x00_start_sp(srb_t *sp)
return -EIO;
spin_lock_irqsave(qp->qp_lock_ptr, flags);
+ rval = qla_get_iocbs_resource(sp);
+ if (rval) {
+ spin_unlock_irqrestore(qp->qp_lock_ptr, flags);
+ return -EAGAIN;
+ }
+
pkt = __qla2x00_alloc_iocbs(sp->qpair, sp);
if (!pkt) {
rval = EAGAIN;
@@ -3927,6 +3990,8 @@ qla2x00_start_sp(srb_t *sp)
wmb();
qla2x00_start_iocbs(vha, qp->req);
done:
+ if (rval)
+ qla_put_fw_resources(sp->qpair, &sp->iores);
spin_unlock_irqrestore(qp->qp_lock_ptr, flags);
return rval;
}
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index e19fde304e5c..46e8b38603f0 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -3112,6 +3112,7 @@ qla25xx_process_bidir_status_iocb(scsi_qla_host_t *vha, void *pkt,
}
bsg_reply->reply_payload_rcv_len = 0;
+ qla_put_fw_resources(sp->qpair, &sp->iores);
done:
/* Return the vendor specific reply to API */
bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = rval;
@@ -3197,7 +3198,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
}
return;
}
- qla_put_iocbs(sp->qpair, &sp->iores);
+ qla_put_fw_resources(sp->qpair, &sp->iores);
if (sp->cmd_type != TYPE_SRB) {
req->outstanding_cmds[handle] = NULL;
@@ -3362,8 +3363,6 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
"Dropped frame(s) detected (0x%x of 0x%x bytes).\n",
resid, scsi_bufflen(cp));
- vha->interface_err_cnt++;
-
res = DID_ERROR << 16 | lscsi_status;
goto check_scsi_status;
}
@@ -3618,7 +3617,6 @@ qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt)
default:
sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
if (sp) {
- qla_put_iocbs(sp->qpair, &sp->iores);
sp->done(sp, res);
return 0;
}
@@ -3771,7 +3769,6 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
if (rsp->qpair->cpuid != smp_processor_id() || !rsp->qpair->rcv_intr) {
rsp->qpair->rcv_intr = 1;
- qla_cpu_update(rsp->qpair, smp_processor_id());
}
#define __update_rsp_in(_is_shadow_hba, _rsp, _rsp_in) \
@@ -4379,6 +4376,7 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
for (i = 0; i < ha->msix_count; i++) {
qentry = &ha->msix_entries[i];
qentry->vector = pci_irq_vector(ha->pdev, i);
+ qentry->vector_base0 = i;
qentry->entry = i;
qentry->have_irq = 0;
qentry->in_use = 0;
@@ -4606,5 +4604,6 @@ int qla25xx_request_irq(struct qla_hw_data *ha, struct qla_qpair *qpair,
}
msix->have_irq = 1;
msix->handle = qpair;
+ qla_mapq_init_qp_cpu_map(ha, msix, qpair);
return ret;
}
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 359595a64664..254fd4c64262 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -4010,7 +4010,7 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
rptid_entry->port_id[2], rptid_entry->port_id[1],
rptid_entry->port_id[0]);
ha->current_topology = ISP_CFG_NL;
- qlt_update_host_map(vha, id);
+ qla_update_host_map(vha, id);
} else if (rptid_entry->format == 1) {
/* fabric */
@@ -4126,7 +4126,7 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
WWN_SIZE);
}
- qlt_update_host_map(vha, id);
+ qla_update_host_map(vha, id);
}
set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags);
@@ -4153,7 +4153,7 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
if (!found)
return;
- qlt_update_host_map(vp, id);
+ qla_update_host_map(vp, id);
/*
* Cannot configure here as we are still sitting on the
@@ -4184,7 +4184,7 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
ha->flags.n2n_ae = 1;
spin_lock_irqsave(&ha->vport_slock, flags);
- qlt_update_vp_map(vha, SET_AL_PA);
+ qla_update_vp_map(vha, SET_AL_PA);
spin_unlock_irqrestore(&ha->vport_slock, flags);
list_for_each_entry(fcport, &vha->vp_fcports, list) {
diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
index 16a9f22bb860..78661b658dcd 100644
--- a/drivers/scsi/qla2xxx/qla_mid.c
+++ b/drivers/scsi/qla2xxx/qla_mid.c
@@ -52,7 +52,7 @@ qla24xx_allocate_vp_id(scsi_qla_host_t *vha)
spin_unlock_irqrestore(&ha->vport_slock, flags);
spin_lock_irqsave(&ha->hardware_lock, flags);
- qlt_update_vp_map(vha, SET_VP_IDX);
+ qla_update_vp_map(vha, SET_VP_IDX);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
mutex_unlock(&ha->vport_lock);
@@ -80,7 +80,7 @@ qla24xx_deallocate_vp_id(scsi_qla_host_t *vha)
spin_lock_irqsave(&ha->vport_slock, flags);
if (atomic_read(&vha->vref_count) == 0) {
list_del(&vha->list);
- qlt_update_vp_map(vha, RESET_VP_IDX);
+ qla_update_vp_map(vha, RESET_VP_IDX);
bailout = 1;
}
spin_unlock_irqrestore(&ha->vport_slock, flags);
@@ -95,7 +95,7 @@ qla24xx_deallocate_vp_id(scsi_qla_host_t *vha)
"vha->vref_count=%u timeout\n", vha->vref_count.counter);
spin_lock_irqsave(&ha->vport_slock, flags);
list_del(&vha->list);
- qlt_update_vp_map(vha, RESET_VP_IDX);
+ qla_update_vp_map(vha, RESET_VP_IDX);
spin_unlock_irqrestore(&ha->vport_slock, flags);
}
@@ -187,7 +187,7 @@ qla24xx_disable_vp(scsi_qla_host_t *vha)
/* Remove port id from vp target map */
spin_lock_irqsave(&vha->hw->hardware_lock, flags);
- qlt_update_vp_map(vha, RESET_AL_PA);
+ qla_update_vp_map(vha, RESET_AL_PA);
spin_unlock_irqrestore(&vha->hw->hardware_lock, flags);
qla2x00_mark_vp_devices_dead(vha);
@@ -384,15 +384,6 @@ qla2x00_do_dpc_vp(scsi_qla_host_t *vha)
}
}
- if (test_bit(FCPORT_UPDATE_NEEDED, &vha->dpc_flags)) {
- ql_dbg(ql_dbg_dpc, vha, 0x4016,
- "FCPort update scheduled.\n");
- qla2x00_update_fcports(vha);
- clear_bit(FCPORT_UPDATE_NEEDED, &vha->dpc_flags);
- ql_dbg(ql_dbg_dpc, vha, 0x4017,
- "FCPort update end.\n");
- }
-
if (test_bit(RELOGIN_NEEDED, &vha->dpc_flags) &&
!test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags) &&
atomic_read(&vha->loop_state) != LOOP_DOWN) {
@@ -1014,3 +1005,288 @@ done:
kref_put(&sp->cmd_kref, qla2x00_sp_release);
return rval;
}
+
+struct scsi_qla_host *qla_find_host_by_vp_idx(struct scsi_qla_host *vha, uint16_t vp_idx)
+{
+ struct qla_hw_data *ha = vha->hw;
+
+ if (vha->vp_idx == vp_idx)
+ return vha;
+
+ BUG_ON(ha->vp_map == NULL);
+ if (likely(test_bit(vp_idx, ha->vp_idx_map)))
+ return ha->vp_map[vp_idx].vha;
+
+ return NULL;
+}
+
+/* vport_slock to be held by the caller */
+void
+qla_update_vp_map(struct scsi_qla_host *vha, int cmd)
+{
+ void *slot;
+ u32 key;
+ int rc;
+
+ if (!vha->hw->vp_map)
+ return;
+
+ key = vha->d_id.b24;
+
+ switch (cmd) {
+ case SET_VP_IDX:
+ vha->hw->vp_map[vha->vp_idx].vha = vha;
+ break;
+ case SET_AL_PA:
+ slot = btree_lookup32(&vha->hw->host_map, key);
+ if (!slot) {
+ ql_dbg(ql_dbg_disc, vha, 0xf018,
+ "Save vha in host_map %p %06x\n", vha, key);
+ rc = btree_insert32(&vha->hw->host_map,
+ key, vha, GFP_ATOMIC);
+ if (rc)
+ ql_log(ql_log_info, vha, 0xd03e,
+ "Unable to insert s_id into host_map: %06x\n",
+ key);
+ return;
+ }
+ ql_dbg(ql_dbg_disc, vha, 0xf019,
+ "replace existing vha in host_map %p %06x\n", vha, key);
+ btree_update32(&vha->hw->host_map, key, vha);
+ break;
+ case RESET_VP_IDX:
+ vha->hw->vp_map[vha->vp_idx].vha = NULL;
+ break;
+ case RESET_AL_PA:
+ ql_dbg(ql_dbg_disc, vha, 0xf01a,
+ "clear vha in host_map %p %06x\n", vha, key);
+ slot = btree_lookup32(&vha->hw->host_map, key);
+ if (slot)
+ btree_remove32(&vha->hw->host_map, key);
+ vha->d_id.b24 = 0;
+ break;
+ }
+}
+
+void qla_update_host_map(struct scsi_qla_host *vha, port_id_t id)
+{
+
+ if (!vha->d_id.b24) {
+ vha->d_id = id;
+ qla_update_vp_map(vha, SET_AL_PA);
+ } else if (vha->d_id.b24 != id.b24) {
+ qla_update_vp_map(vha, RESET_AL_PA);
+ vha->d_id = id;
+ qla_update_vp_map(vha, SET_AL_PA);
+ }
+}
+
+int qla_create_buf_pool(struct scsi_qla_host *vha, struct qla_qpair *qp)
+{
+ int sz;
+
+ qp->buf_pool.num_bufs = qp->req->length;
+
+ sz = BITS_TO_LONGS(qp->req->length);
+ qp->buf_pool.buf_map = kcalloc(sz, sizeof(long), GFP_KERNEL);
+ if (!qp->buf_pool.buf_map) {
+ ql_log(ql_log_warn, vha, 0x0186,
+ "Failed to allocate buf_map(%zd).\n", sz * sizeof(unsigned long));
+ return -ENOMEM;
+ }
+ sz = qp->req->length * sizeof(void *);
+ qp->buf_pool.buf_array = kcalloc(qp->req->length, sizeof(void *), GFP_KERNEL);
+ if (!qp->buf_pool.buf_array) {
+ ql_log(ql_log_warn, vha, 0x0186,
+ "Failed to allocate buf_array(%d).\n", sz);
+ kfree(qp->buf_pool.buf_map);
+ return -ENOMEM;
+ }
+ sz = qp->req->length * sizeof(dma_addr_t);
+ qp->buf_pool.dma_array = kcalloc(qp->req->length, sizeof(dma_addr_t), GFP_KERNEL);
+ if (!qp->buf_pool.dma_array) {
+ ql_log(ql_log_warn, vha, 0x0186,
+ "Failed to allocate dma_array(%d).\n", sz);
+ kfree(qp->buf_pool.buf_map);
+ kfree(qp->buf_pool.buf_array);
+ return -ENOMEM;
+ }
+ set_bit(0, qp->buf_pool.buf_map);
+ return 0;
+}
+
+void qla_free_buf_pool(struct qla_qpair *qp)
+{
+ int i;
+ struct qla_hw_data *ha = qp->vha->hw;
+
+ for (i = 0; i < qp->buf_pool.num_bufs; i++) {
+ if (qp->buf_pool.buf_array[i] && qp->buf_pool.dma_array[i])
+ dma_pool_free(ha->fcp_cmnd_dma_pool, qp->buf_pool.buf_array[i],
+ qp->buf_pool.dma_array[i]);
+ qp->buf_pool.buf_array[i] = NULL;
+ qp->buf_pool.dma_array[i] = 0;
+ }
+
+ kfree(qp->buf_pool.dma_array);
+ kfree(qp->buf_pool.buf_array);
+ kfree(qp->buf_pool.buf_map);
+}
+
+/* it is assume qp->qp_lock is held at this point */
+int qla_get_buf(struct scsi_qla_host *vha, struct qla_qpair *qp, struct qla_buf_dsc *dsc)
+{
+ u16 tag, i = 0;
+ void *buf;
+ dma_addr_t buf_dma;
+ struct qla_hw_data *ha = vha->hw;
+
+ dsc->tag = TAG_FREED;
+again:
+ tag = find_first_zero_bit(qp->buf_pool.buf_map, qp->buf_pool.num_bufs);
+ if (tag >= qp->buf_pool.num_bufs) {
+ ql_dbg(ql_dbg_io, vha, 0x00e2,
+ "qp(%d) ran out of buf resource.\n", qp->id);
+ return -EIO;
+ }
+ if (tag == 0) {
+ set_bit(0, qp->buf_pool.buf_map);
+ i++;
+ if (i == 5) {
+ ql_dbg(ql_dbg_io, vha, 0x00e3,
+ "qp(%d) unable to get tag.\n", qp->id);
+ return -EIO;
+ }
+ goto again;
+ }
+
+ if (!qp->buf_pool.buf_array[tag]) {
+ buf = dma_pool_zalloc(ha->fcp_cmnd_dma_pool, GFP_ATOMIC, &buf_dma);
+ if (!buf) {
+ ql_log(ql_log_fatal, vha, 0x13b1,
+ "Failed to allocate buf.\n");
+ return -ENOMEM;
+ }
+
+ dsc->buf = qp->buf_pool.buf_array[tag] = buf;
+ dsc->buf_dma = qp->buf_pool.dma_array[tag] = buf_dma;
+ qp->buf_pool.num_alloc++;
+ } else {
+ dsc->buf = qp->buf_pool.buf_array[tag];
+ dsc->buf_dma = qp->buf_pool.dma_array[tag];
+ memset(dsc->buf, 0, FCP_CMND_DMA_POOL_SIZE);
+ }
+
+ qp->buf_pool.num_active++;
+ if (qp->buf_pool.num_active > qp->buf_pool.max_used)
+ qp->buf_pool.max_used = qp->buf_pool.num_active;
+
+ dsc->tag = tag;
+ set_bit(tag, qp->buf_pool.buf_map);
+ return 0;
+}
+
+static void qla_trim_buf(struct qla_qpair *qp, u16 trim)
+{
+ int i, j;
+ struct qla_hw_data *ha = qp->vha->hw;
+
+ if (!trim)
+ return;
+
+ for (i = 0; i < trim; i++) {
+ j = qp->buf_pool.num_alloc - 1;
+ if (test_bit(j, qp->buf_pool.buf_map)) {
+ ql_dbg(ql_dbg_io + ql_dbg_verbose, qp->vha, 0x300b,
+ "QP id(%d): trim active buf[%d]. Remain %d bufs\n",
+ qp->id, j, qp->buf_pool.num_alloc);
+ return;
+ }
+
+ if (qp->buf_pool.buf_array[j]) {
+ dma_pool_free(ha->fcp_cmnd_dma_pool, qp->buf_pool.buf_array[j],
+ qp->buf_pool.dma_array[j]);
+ qp->buf_pool.buf_array[j] = NULL;
+ qp->buf_pool.dma_array[j] = 0;
+ }
+ qp->buf_pool.num_alloc--;
+ if (!qp->buf_pool.num_alloc)
+ break;
+ }
+ ql_dbg(ql_dbg_io + ql_dbg_verbose, qp->vha, 0x3010,
+ "QP id(%d): trimmed %d bufs. Remain %d bufs\n",
+ qp->id, trim, qp->buf_pool.num_alloc);
+}
+
+static void __qla_adjust_buf(struct qla_qpair *qp)
+{
+ u32 trim;
+
+ qp->buf_pool.take_snapshot = 0;
+ qp->buf_pool.prev_max = qp->buf_pool.max_used;
+ qp->buf_pool.max_used = qp->buf_pool.num_active;
+
+ if (qp->buf_pool.prev_max > qp->buf_pool.max_used &&
+ qp->buf_pool.num_alloc > qp->buf_pool.max_used) {
+ /* down trend */
+ trim = qp->buf_pool.num_alloc - qp->buf_pool.max_used;
+ trim = (trim * 10) / 100;
+ trim = trim ? trim : 1;
+ qla_trim_buf(qp, trim);
+ } else if (!qp->buf_pool.prev_max && !qp->buf_pool.max_used) {
+ /* 2 periods of no io */
+ qla_trim_buf(qp, qp->buf_pool.num_alloc);
+ }
+}
+
+/* it is assume qp->qp_lock is held at this point */
+void qla_put_buf(struct qla_qpair *qp, struct qla_buf_dsc *dsc)
+{
+ if (dsc->tag == TAG_FREED)
+ return;
+ lockdep_assert_held(qp->qp_lock_ptr);
+
+ clear_bit(dsc->tag, qp->buf_pool.buf_map);
+ qp->buf_pool.num_active--;
+ dsc->tag = TAG_FREED;
+
+ if (qp->buf_pool.take_snapshot)
+ __qla_adjust_buf(qp);
+}
+
+#define EXPIRE (60 * HZ)
+void qla_adjust_buf(struct scsi_qla_host *vha)
+{
+ unsigned long flags;
+ int i;
+ struct qla_qpair *qp;
+
+ if (vha->vp_idx)
+ return;
+
+ if (!vha->buf_expired) {
+ vha->buf_expired = jiffies + EXPIRE;
+ return;
+ }
+ if (time_before(jiffies, vha->buf_expired))
+ return;
+
+ vha->buf_expired = jiffies + EXPIRE;
+
+ for (i = 0; i < vha->hw->num_qpairs; i++) {
+ qp = vha->hw->queue_pair_map[i];
+ if (!qp)
+ continue;
+ if (!qp->buf_pool.num_alloc)
+ continue;
+
+ if (qp->buf_pool.take_snapshot) {
+ /* no io has gone through in the last EXPIRE period */
+ spin_lock_irqsave(qp->qp_lock_ptr, flags);
+ __qla_adjust_buf(qp);
+ spin_unlock_irqrestore(qp->qp_lock_ptr, flags);
+ } else {
+ qp->buf_pool.take_snapshot = 1;
+ }
+ }
+}
diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c
index 02fdeb0d31ec..648e8f798606 100644
--- a/drivers/scsi/qla2xxx/qla_nvme.c
+++ b/drivers/scsi/qla2xxx/qla_nvme.c
@@ -170,18 +170,6 @@ out:
qla2xxx_rel_qpair_sp(sp->qpair, sp);
}
-static void qla_nvme_ls_unmap(struct srb *sp, struct nvmefc_ls_req *fd)
-{
- if (sp->flags & SRB_DMA_VALID) {
- struct srb_iocb *nvme = &sp->u.iocb_cmd;
- struct qla_hw_data *ha = sp->fcport->vha->hw;
-
- dma_unmap_single(&ha->pdev->dev, nvme->u.nvme.cmd_dma,
- fd->rqstlen, DMA_TO_DEVICE);
- sp->flags &= ~SRB_DMA_VALID;
- }
-}
-
static void qla_nvme_release_ls_cmd_kref(struct kref *kref)
{
struct srb *sp = container_of(kref, struct srb, cmd_kref);
@@ -199,7 +187,6 @@ static void qla_nvme_release_ls_cmd_kref(struct kref *kref)
fd = priv->fd;
- qla_nvme_ls_unmap(sp, fd);
fd->done(fd, priv->comp_status);
out:
qla2x00_rel_sp(sp);
@@ -365,13 +352,10 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *lport,
nvme->u.nvme.rsp_len = fd->rsplen;
nvme->u.nvme.rsp_dma = fd->rspdma;
nvme->u.nvme.timeout_sec = fd->timeout;
- nvme->u.nvme.cmd_dma = dma_map_single(&ha->pdev->dev, fd->rqstaddr,
- fd->rqstlen, DMA_TO_DEVICE);
+ nvme->u.nvme.cmd_dma = fd->rqstdma;
dma_sync_single_for_device(&ha->pdev->dev, nvme->u.nvme.cmd_dma,
fd->rqstlen, DMA_TO_DEVICE);
- sp->flags |= SRB_DMA_VALID;
-
rval = qla2x00_start_sp(sp);
if (rval != QLA_SUCCESS) {
ql_log(ql_log_warn, vha, 0x700e,
@@ -379,7 +363,6 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *lport,
wake_up(&sp->nvme_ls_waitq);
sp->priv = NULL;
priv->sp = NULL;
- qla_nvme_ls_unmap(sp, fd);
qla2x00_rel_sp(sp);
return rval;
}
@@ -445,13 +428,24 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp)
goto queuing_error;
}
req_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
+
+ sp->iores.res_type = RESOURCE_IOCB | RESOURCE_EXCH;
+ sp->iores.exch_cnt = 1;
+ sp->iores.iocb_cnt = req_cnt;
+ if (qla_get_fw_resources(sp->qpair, &sp->iores)) {
+ rval = -EBUSY;
+ goto queuing_error;
+ }
+
if (req->cnt < (req_cnt + 2)) {
if (IS_SHADOW_REG_CAPABLE(ha)) {
cnt = *req->out_ptr;
} else {
cnt = rd_reg_dword_relaxed(req->req_q_out);
- if (qla2x00_check_reg16_for_disconnect(vha, cnt))
+ if (qla2x00_check_reg16_for_disconnect(vha, cnt)) {
+ rval = -EBUSY;
goto queuing_error;
+ }
}
if (req->ring_index < cnt)
@@ -600,6 +594,8 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp)
qla24xx_process_response_queue(vha, rsp);
queuing_error:
+ if (rval)
+ qla_put_fw_resources(sp->qpair, &sp->iores);
spin_unlock_irqrestore(&qpair->qp_lock, flags);
return rval;
@@ -613,6 +609,7 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport,
fc_port_t *fcport;
struct srb_iocb *nvme;
struct scsi_qla_host *vha;
+ struct qla_hw_data *ha;
int rval;
srb_t *sp;
struct qla_qpair *qpair = hw_queue_handle;
@@ -633,6 +630,7 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport,
return -ENODEV;
vha = fcport->vha;
+ ha = vha->hw;
if (test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags))
return -EBUSY;
@@ -647,6 +645,8 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport,
if (fcport->nvme_flag & NVME_FLAG_RESETTING)
return -EBUSY;
+ qpair = qla_mapq_nvme_select_qpair(ha, qpair);
+
/* Alloc SRB structure */
sp = qla2xxx_get_qpair_sp(vha, qpair, fcport, GFP_ATOMIC);
if (!sp)
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 7fb28c207ee5..545167627e48 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -472,6 +472,11 @@ static int qla2x00_alloc_queues(struct qla_hw_data *ha, struct req_que *req,
"Unable to allocate memory for queue pair ptrs.\n");
goto fail_qpair_map;
}
+ if (qla_mapq_alloc_qp_cpu_map(ha) != 0) {
+ kfree(ha->queue_pair_map);
+ ha->queue_pair_map = NULL;
+ goto fail_qpair_map;
+ }
}
/*
@@ -546,6 +551,7 @@ static void qla2x00_free_queues(struct qla_hw_data *ha)
ha->base_qpair = NULL;
}
+ qla_mapq_free_qp_cpu_map(ha);
spin_lock_irqsave(&ha->hardware_lock, flags);
for (cnt = 0; cnt < ha->max_req_queues; cnt++) {
if (!test_bit(cnt, ha->req_qid_map))
@@ -733,15 +739,17 @@ void qla2x00_sp_free_dma(srb_t *sp)
}
if (sp->flags & SRB_FCP_CMND_DMA_VALID) {
- struct ct6_dsd *ctx1 = sp->u.scmd.ct6_ctx;
+ struct ct6_dsd *ctx1 = &sp->u.scmd.ct6_ctx;
dma_pool_free(ha->fcp_cmnd_dma_pool, ctx1->fcp_cmnd,
ctx1->fcp_cmnd_dma);
list_splice(&ctx1->dsd_list, &ha->gbl_dsd_list);
ha->gbl_dsd_inuse -= ctx1->dsd_use_cnt;
ha->gbl_dsd_avail += ctx1->dsd_use_cnt;
- mempool_free(ctx1, ha->ctx_mempool);
}
+
+ if (sp->flags & SRB_GOT_BUF)
+ qla_put_buf(sp->qpair, &sp->u.scmd.buf_dsc);
}
void qla2x00_sp_compl(srb_t *sp, int res)
@@ -817,14 +825,13 @@ void qla2xxx_qpair_sp_free_dma(srb_t *sp)
}
if (sp->flags & SRB_FCP_CMND_DMA_VALID) {
- struct ct6_dsd *ctx1 = sp->u.scmd.ct6_ctx;
+ struct ct6_dsd *ctx1 = &sp->u.scmd.ct6_ctx;
dma_pool_free(ha->fcp_cmnd_dma_pool, ctx1->fcp_cmnd,
ctx1->fcp_cmnd_dma);
list_splice(&ctx1->dsd_list, &ha->gbl_dsd_list);
ha->gbl_dsd_inuse -= ctx1->dsd_use_cnt;
ha->gbl_dsd_avail += ctx1->dsd_use_cnt;
- mempool_free(ctx1, ha->ctx_mempool);
sp->flags &= ~SRB_FCP_CMND_DMA_VALID;
}
@@ -834,6 +841,9 @@ void qla2xxx_qpair_sp_free_dma(srb_t *sp)
dma_pool_free(ha->dl_dma_pool, ctx0, ctx0->crc_ctx_dma);
sp->flags &= ~SRB_CRC_CTX_DMA_VALID;
}
+
+ if (sp->flags & SRB_GOT_BUF)
+ qla_put_buf(sp->qpair, &sp->u.scmd.buf_dsc);
}
void qla2xxx_qpair_sp_compl(srb_t *sp, int res)
@@ -4118,10 +4128,16 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
char name[16];
int rc;
+ if (QLA_TGT_MODE_ENABLED() || EDIF_CAP(ha)) {
+ ha->vp_map = kcalloc(MAX_MULTI_ID_FABRIC, sizeof(struct qla_vp_map), GFP_KERNEL);
+ if (!ha->vp_map)
+ goto fail;
+ }
+
ha->init_cb = dma_alloc_coherent(&ha->pdev->dev, ha->init_cb_size,
&ha->init_cb_dma, GFP_KERNEL);
if (!ha->init_cb)
- goto fail;
+ goto fail_free_vp_map;
rc = btree_init32(&ha->host_map);
if (rc)
@@ -4540,6 +4556,8 @@ fail_free_init_cb:
ha->init_cb_dma);
ha->init_cb = NULL;
ha->init_cb_dma = 0;
+fail_free_vp_map:
+ kfree(ha->vp_map);
fail:
ql_log(ql_log_fatal, NULL, 0x0030,
"Memory allocation failure.\n");
@@ -4981,6 +4999,9 @@ qla2x00_mem_free(struct qla_hw_data *ha)
ha->sf_init_cb = NULL;
ha->sf_init_cb_dma = 0;
ha->loop_id_map = NULL;
+
+ kfree(ha->vp_map);
+ ha->vp_map = NULL;
}
struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht,
@@ -5016,7 +5037,6 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht,
INIT_LIST_HEAD(&vha->plogi_ack_list);
INIT_LIST_HEAD(&vha->qp_list);
INIT_LIST_HEAD(&vha->gnl.fcports);
- INIT_LIST_HEAD(&vha->gpnid_list);
INIT_WORK(&vha->iocb_work, qla2x00_iocb_work_fn);
INIT_LIST_HEAD(&vha->purex_list.head);
@@ -5461,9 +5481,6 @@ qla2x00_do_work(struct scsi_qla_host *vha)
case QLA_EVT_AENFX:
qlafx00_process_aen(vha, e);
break;
- case QLA_EVT_GPNID:
- qla24xx_async_gpnid(vha, &e->u.gpnid.id);
- break;
case QLA_EVT_UNMAP:
qla24xx_sp_unmap(vha, e->u.iosb.sp);
break;
@@ -5506,9 +5523,6 @@ qla2x00_do_work(struct scsi_qla_host *vha)
case QLA_EVT_GNNFT_DONE:
qla24xx_async_gnnft_done(vha, e->u.iosb.sp);
break;
- case QLA_EVT_GNNID:
- qla24xx_async_gnnid(vha, e->u.fcport.fcport);
- break;
case QLA_EVT_GFPNID:
qla24xx_async_gfpnid(vha, e->u.fcport.fcport);
break;
@@ -7025,11 +7039,6 @@ qla2x00_do_dpc(void *data)
}
}
- if (test_and_clear_bit(FCPORT_UPDATE_NEEDED,
- &base_vha->dpc_flags)) {
- qla2x00_update_fcports(base_vha);
- }
-
if (IS_QLAFX00(ha))
goto loop_resync_check;
@@ -7094,9 +7103,12 @@ qla2x00_do_dpc(void *data)
}
}
loop_resync_check:
- if (test_and_clear_bit(LOOP_RESYNC_NEEDED,
+ if (!qla2x00_reset_active(base_vha) &&
+ test_and_clear_bit(LOOP_RESYNC_NEEDED,
&base_vha->dpc_flags)) {
-
+ /*
+ * Allow abort_isp to complete before moving on to scanning.
+ */
ql_dbg(ql_dbg_dpc, base_vha, 0x400f,
"Loop resync scheduled.\n");
@@ -7447,7 +7459,7 @@ qla2x00_timer(struct timer_list *t)
/* if the loop has been down for 4 minutes, reinit adapter */
if (atomic_dec_and_test(&vha->loop_down_timer) != 0) {
- if (!(vha->device_flags & DFLG_NO_CABLE)) {
+ if (!(vha->device_flags & DFLG_NO_CABLE) && !vha->vp_idx) {
ql_log(ql_log_warn, vha, 0x6009,
"Loop down - aborting ISP.\n");
@@ -7516,13 +7528,13 @@ qla2x00_timer(struct timer_list *t)
set_bit(SET_ZIO_THRESHOLD_NEEDED, &vha->dpc_flags);
start_dpc++;
}
+ qla_adjust_buf(vha);
/* borrowing w to signify dpc will run */
w = 0;
/* Schedule the DPC routine if needed */
if ((test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) ||
test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags) ||
- test_bit(FCPORT_UPDATE_NEEDED, &vha->dpc_flags) ||
start_dpc ||
test_bit(RESET_MARKER_NEEDED, &vha->dpc_flags) ||
test_bit(BEACON_BLINK_NEEDED, &vha->dpc_flags) ||
@@ -7533,13 +7545,10 @@ qla2x00_timer(struct timer_list *t)
test_bit(PROCESS_PUREX_IOCB, &vha->dpc_flags))) {
ql_dbg(ql_dbg_timer, vha, 0x600b,
"isp_abort_needed=%d loop_resync_needed=%d "
- "fcport_update_needed=%d start_dpc=%d "
- "reset_marker_needed=%d",
+ "start_dpc=%d reset_marker_needed=%d",
test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags),
test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags),
- test_bit(FCPORT_UPDATE_NEEDED, &vha->dpc_flags),
- start_dpc,
- test_bit(RESET_MARKER_NEEDED, &vha->dpc_flags));
+ start_dpc, test_bit(RESET_MARKER_NEEDED, &vha->dpc_flags));
ql_dbg(ql_dbg_timer, vha, 0x600c,
"beacon_blink_needed=%d isp_unrecoverable=%d "
"fcoe_ctx_reset_needed=%d vp_dpc_needed=%d "
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index 548f22705ddc..aa0cf5ca6c1c 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -198,22 +198,6 @@ struct scsi_qla_host *qla_find_host_by_d_id(struct scsi_qla_host *vha,
return host;
}
-static inline
-struct scsi_qla_host *qlt_find_host_by_vp_idx(struct scsi_qla_host *vha,
- uint16_t vp_idx)
-{
- struct qla_hw_data *ha = vha->hw;
-
- if (vha->vp_idx == vp_idx)
- return vha;
-
- BUG_ON(ha->tgt.tgt_vp_map == NULL);
- if (likely(test_bit(vp_idx, ha->vp_idx_map)))
- return ha->tgt.tgt_vp_map[vp_idx].vha;
-
- return NULL;
-}
-
static inline void qlt_incr_num_pend_cmds(struct scsi_qla_host *vha)
{
unsigned long flags;
@@ -371,7 +355,7 @@ static bool qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *vha,
if ((entry->u.isp24.vp_index != 0xFF) &&
(entry->u.isp24.nport_handle != cpu_to_le16(0xFFFF))) {
- host = qlt_find_host_by_vp_idx(vha,
+ host = qla_find_host_by_vp_idx(vha,
entry->u.isp24.vp_index);
if (unlikely(!host)) {
ql_dbg(ql_dbg_tgt, vha, 0xe03f,
@@ -395,7 +379,7 @@ static bool qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *vha,
{
struct abts_recv_from_24xx *entry =
(struct abts_recv_from_24xx *)atio;
- struct scsi_qla_host *host = qlt_find_host_by_vp_idx(vha,
+ struct scsi_qla_host *host = qla_find_host_by_vp_idx(vha,
entry->vp_index);
unsigned long flags;
@@ -438,7 +422,7 @@ void qlt_response_pkt_all_vps(struct scsi_qla_host *vha,
case CTIO_TYPE7:
{
struct ctio7_from_24xx *entry = (struct ctio7_from_24xx *)pkt;
- struct scsi_qla_host *host = qlt_find_host_by_vp_idx(vha,
+ struct scsi_qla_host *host = qla_find_host_by_vp_idx(vha,
entry->vp_index);
if (unlikely(!host)) {
ql_dbg(ql_dbg_tgt, vha, 0xe041,
@@ -457,7 +441,7 @@ void qlt_response_pkt_all_vps(struct scsi_qla_host *vha,
struct imm_ntfy_from_isp *entry =
(struct imm_ntfy_from_isp *)pkt;
- host = qlt_find_host_by_vp_idx(vha, entry->u.isp24.vp_index);
+ host = qla_find_host_by_vp_idx(vha, entry->u.isp24.vp_index);
if (unlikely(!host)) {
ql_dbg(ql_dbg_tgt, vha, 0xe042,
"qla_target(%d): Response pkt (IMMED_NOTIFY_TYPE) "
@@ -475,7 +459,7 @@ void qlt_response_pkt_all_vps(struct scsi_qla_host *vha,
struct nack_to_isp *entry = (struct nack_to_isp *)pkt;
if (0xFF != entry->u.isp24.vp_index) {
- host = qlt_find_host_by_vp_idx(vha,
+ host = qla_find_host_by_vp_idx(vha,
entry->u.isp24.vp_index);
if (unlikely(!host)) {
ql_dbg(ql_dbg_tgt, vha, 0xe043,
@@ -495,7 +479,7 @@ void qlt_response_pkt_all_vps(struct scsi_qla_host *vha,
{
struct abts_recv_from_24xx *entry =
(struct abts_recv_from_24xx *)pkt;
- struct scsi_qla_host *host = qlt_find_host_by_vp_idx(vha,
+ struct scsi_qla_host *host = qla_find_host_by_vp_idx(vha,
entry->vp_index);
if (unlikely(!host)) {
ql_dbg(ql_dbg_tgt, vha, 0xe044,
@@ -512,7 +496,7 @@ void qlt_response_pkt_all_vps(struct scsi_qla_host *vha,
{
struct abts_resp_to_24xx *entry =
(struct abts_resp_to_24xx *)pkt;
- struct scsi_qla_host *host = qlt_find_host_by_vp_idx(vha,
+ struct scsi_qla_host *host = qla_find_host_by_vp_idx(vha,
entry->vp_index);
if (unlikely(!host)) {
ql_dbg(ql_dbg_tgt, vha, 0xe045,
@@ -1028,8 +1012,7 @@ void qlt_free_session_done(struct work_struct *work)
}
if (ha->flags.edif_enabled &&
- (!own || (own &&
- own->iocb.u.isp24.status_subcode == ELS_PLOGI))) {
+ (!own || own->iocb.u.isp24.status_subcode == ELS_PLOGI)) {
sess->edif.authok = 0;
if (!ha->flags.host_shutting_down) {
ql_dbg(ql_dbg_edif, vha, 0x911e,
@@ -7145,7 +7128,7 @@ qlt_probe_one_stage1(struct scsi_qla_host *base_vha, struct qla_hw_data *ha)
qlt_clear_mode(base_vha);
- qlt_update_vp_map(base_vha, SET_VP_IDX);
+ qla_update_vp_map(base_vha, SET_VP_IDX);
}
irqreturn_t
@@ -7224,17 +7207,10 @@ qlt_mem_alloc(struct qla_hw_data *ha)
if (!QLA_TGT_MODE_ENABLED())
return 0;
- ha->tgt.tgt_vp_map = kcalloc(MAX_MULTI_ID_FABRIC,
- sizeof(struct qla_tgt_vp_map),
- GFP_KERNEL);
- if (!ha->tgt.tgt_vp_map)
- return -ENOMEM;
-
ha->tgt.atio_ring = dma_alloc_coherent(&ha->pdev->dev,
(ha->tgt.atio_q_length + 1) * sizeof(struct atio_from_isp),
&ha->tgt.atio_dma, GFP_KERNEL);
if (!ha->tgt.atio_ring) {
- kfree(ha->tgt.tgt_vp_map);
return -ENOMEM;
}
return 0;
@@ -7253,70 +7229,6 @@ qlt_mem_free(struct qla_hw_data *ha)
}
ha->tgt.atio_ring = NULL;
ha->tgt.atio_dma = 0;
- kfree(ha->tgt.tgt_vp_map);
- ha->tgt.tgt_vp_map = NULL;
-}
-
-/* vport_slock to be held by the caller */
-void
-qlt_update_vp_map(struct scsi_qla_host *vha, int cmd)
-{
- void *slot;
- u32 key;
- int rc;
-
- key = vha->d_id.b24;
-
- switch (cmd) {
- case SET_VP_IDX:
- if (!QLA_TGT_MODE_ENABLED())
- return;
- vha->hw->tgt.tgt_vp_map[vha->vp_idx].vha = vha;
- break;
- case SET_AL_PA:
- slot = btree_lookup32(&vha->hw->host_map, key);
- if (!slot) {
- ql_dbg(ql_dbg_tgt_mgt, vha, 0xf018,
- "Save vha in host_map %p %06x\n", vha, key);
- rc = btree_insert32(&vha->hw->host_map,
- key, vha, GFP_ATOMIC);
- if (rc)
- ql_log(ql_log_info, vha, 0xd03e,
- "Unable to insert s_id into host_map: %06x\n",
- key);
- return;
- }
- ql_dbg(ql_dbg_tgt_mgt, vha, 0xf019,
- "replace existing vha in host_map %p %06x\n", vha, key);
- btree_update32(&vha->hw->host_map, key, vha);
- break;
- case RESET_VP_IDX:
- if (!QLA_TGT_MODE_ENABLED())
- return;
- vha->hw->tgt.tgt_vp_map[vha->vp_idx].vha = NULL;
- break;
- case RESET_AL_PA:
- ql_dbg(ql_dbg_tgt_mgt, vha, 0xf01a,
- "clear vha in host_map %p %06x\n", vha, key);
- slot = btree_lookup32(&vha->hw->host_map, key);
- if (slot)
- btree_remove32(&vha->hw->host_map, key);
- vha->d_id.b24 = 0;
- break;
- }
-}
-
-void qlt_update_host_map(struct scsi_qla_host *vha, port_id_t id)
-{
-
- if (!vha->d_id.b24) {
- vha->d_id = id;
- qlt_update_vp_map(vha, SET_AL_PA);
- } else if (vha->d_id.b24 != id.b24) {
- qlt_update_vp_map(vha, RESET_AL_PA);
- vha->d_id = id;
- qlt_update_vp_map(vha, SET_AL_PA);
- }
}
static int __init qlt_parse_ini_mode(void)
diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h
index 7df86578214f..354fca2e7feb 100644
--- a/drivers/scsi/qla2xxx/qla_target.h
+++ b/drivers/scsi/qla2xxx/qla_target.h
@@ -1017,7 +1017,6 @@ extern void qlt_fc_port_added(struct scsi_qla_host *, fc_port_t *);
extern void qlt_fc_port_deleted(struct scsi_qla_host *, fc_port_t *, int);
extern int __init qlt_init(void);
extern void qlt_exit(void);
-extern void qlt_update_vp_map(struct scsi_qla_host *, int);
extern void qlt_free_session_done(struct work_struct *);
/*
* This macro is used during early initializations when host->active_mode
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index 03f3e2cd62b5..42d69d89834f 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -6,9 +6,9 @@
/*
* Driver version
*/
-#define QLA2XXX_VERSION "10.02.07.900-k"
+#define QLA2XXX_VERSION "10.02.08.200-k"
#define QLA_DRIVER_MAJOR_VER 10
#define QLA_DRIVER_MINOR_VER 2
-#define QLA_DRIVER_PATCH_VER 7
-#define QLA_DRIVER_BETA_VER 900
+#define QLA_DRIVER_PATCH_VER 8
+#define QLA_DRIVER_BETA_VER 200
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
index 8fa0056b56dd..8024322c9c5a 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
@@ -1552,6 +1552,7 @@ static const struct qla_tgt_func_tmpl tcm_qla2xxx_template = {
static int tcm_qla2xxx_init_lport(struct tcm_qla2xxx_lport *lport)
{
int rc;
+ size_t map_sz;
rc = btree_init32(&lport->lport_fcport_map);
if (rc) {
@@ -1559,17 +1560,15 @@ static int tcm_qla2xxx_init_lport(struct tcm_qla2xxx_lport *lport)
return rc;
}
- lport->lport_loopid_map =
- vzalloc(array_size(65536,
- sizeof(struct tcm_qla2xxx_fc_loopid)));
+ map_sz = array_size(65536, sizeof(struct tcm_qla2xxx_fc_loopid));
+
+ lport->lport_loopid_map = vzalloc(map_sz);
if (!lport->lport_loopid_map) {
- pr_err("Unable to allocate lport->lport_loopid_map of %zu bytes\n",
- sizeof(struct tcm_qla2xxx_fc_loopid) * 65536);
+ pr_err("Unable to allocate lport->lport_loopid_map of %zu bytes\n", map_sz);
btree_destroy32(&lport->lport_fcport_map);
return -ENOMEM;
}
- pr_debug("qla2xxx: Allocated lport_loopid_map of %zu bytes\n",
- sizeof(struct tcm_qla2xxx_fc_loopid) * 65536);
+ pr_debug("qla2xxx: Allocated lport_loopid_map of %zu bytes\n", map_sz);
return 0;
}
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 9feb0323bc44..7d2210a006f0 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -309,8 +309,8 @@ static int scsi_vpd_inquiry(struct scsi_device *sdev, unsigned char *buffer,
* I'm not convinced we need to try quite this hard to get VPD, but
* all the existing users tried this hard.
*/
- result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer,
- len, NULL, 30 * HZ, 3, NULL);
+ result = scsi_execute_cmd(sdev, cmd, REQ_OP_DRV_IN, buffer, len,
+ 30 * HZ, 3, NULL);
if (result)
return -EIO;
@@ -510,6 +510,9 @@ int scsi_report_opcode(struct scsi_device *sdev, unsigned char *buffer,
unsigned char cmd[16];
struct scsi_sense_hdr sshdr;
int result, request_len;
+ const struct scsi_exec_args exec_args = {
+ .sshdr = &sshdr,
+ };
if (sdev->no_report_opcodes || sdev->scsi_level < SCSI_SPC_3)
return -EINVAL;
@@ -531,9 +534,8 @@ int scsi_report_opcode(struct scsi_device *sdev, unsigned char *buffer,
put_unaligned_be32(request_len, &cmd[6]);
memset(buffer, 0, len);
- result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer,
- request_len, &sshdr, 30 * HZ, 3, NULL);
-
+ result = scsi_execute_cmd(sdev, cmd, REQ_OP_DRV_IN, buffer,
+ request_len, 30 * HZ, 3, &exec_args);
if (result < 0)
return result;
if (result && scsi_sense_valid(&sshdr) &&
diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c
index 1126a265d5ee..e3b31d32b6a9 100644
--- a/drivers/scsi/scsi_ioctl.c
+++ b/drivers/scsi/scsi_ioctl.c
@@ -69,12 +69,15 @@ static int ioctl_internal_command(struct scsi_device *sdev, char *cmd,
{
int result;
struct scsi_sense_hdr sshdr;
+ const struct scsi_exec_args exec_args = {
+ .sshdr = &sshdr,
+ };
SCSI_LOG_IOCTL(1, sdev_printk(KERN_INFO, sdev,
"Trying ioctl with scsi command %d\n", *cmd));
- result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0,
- &sshdr, timeout, retries, NULL);
+ result = scsi_execute_cmd(sdev, cmd, REQ_OP_DRV_IN, NULL, 0, timeout,
+ retries, &exec_args);
SCSI_LOG_IOCTL(2, sdev_printk(KERN_INFO, sdev,
"Ioctl returned 0x%x\n", result));
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 9ed1ebcb7443..abe93ec8b7d0 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -185,39 +185,37 @@ void scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
__scsi_queue_insert(cmd, reason, true);
}
-
/**
- * __scsi_execute - insert request and wait for the result
- * @sdev: scsi device
+ * scsi_execute_cmd - insert request and wait for the result
+ * @sdev: scsi_device
* @cmd: scsi command
- * @data_direction: data direction
+ * @opf: block layer request cmd_flags
* @buffer: data buffer
* @bufflen: len of buffer
- * @sense: optional sense buffer
- * @sshdr: optional decoded sense header
* @timeout: request timeout in HZ
* @retries: number of times to retry request
- * @flags: flags for ->cmd_flags
- * @rq_flags: flags for ->rq_flags
- * @resid: optional residual length
+ * @args: Optional args. See struct definition for field descriptions
*
* Returns the scsi_cmnd result field if a command was executed, or a negative
* Linux error code if we didn't get that far.
*/
-int __scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
- int data_direction, void *buffer, unsigned bufflen,
- unsigned char *sense, struct scsi_sense_hdr *sshdr,
- int timeout, int retries, blk_opf_t flags,
- req_flags_t rq_flags, int *resid)
+int scsi_execute_cmd(struct scsi_device *sdev, const unsigned char *cmd,
+ blk_opf_t opf, void *buffer, unsigned int bufflen,
+ int timeout, int retries,
+ const struct scsi_exec_args *args)
{
+ static const struct scsi_exec_args default_args;
struct request *req;
struct scsi_cmnd *scmd;
int ret;
- req = scsi_alloc_request(sdev->request_queue,
- data_direction == DMA_TO_DEVICE ?
- REQ_OP_DRV_OUT : REQ_OP_DRV_IN,
- rq_flags & RQF_PM ? BLK_MQ_REQ_PM : 0);
+ if (!args)
+ args = &default_args;
+ else if (WARN_ON_ONCE(args->sense &&
+ args->sense_len != SCSI_SENSE_BUFFERSIZE))
+ return -EINVAL;
+
+ req = scsi_alloc_request(sdev->request_queue, opf, args->req_flags);
if (IS_ERR(req))
return PTR_ERR(req);
@@ -232,8 +230,7 @@ int __scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
memcpy(scmd->cmnd, cmd, scmd->cmd_len);
scmd->allowed = retries;
req->timeout = timeout;
- req->cmd_flags |= flags;
- req->rq_flags |= rq_flags | RQF_QUIET;
+ req->rq_flags |= RQF_QUIET;
/*
* head injection *required* here otherwise quiesce won't work
@@ -249,20 +246,21 @@ int __scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
if (unlikely(scmd->resid_len > 0 && scmd->resid_len <= bufflen))
memset(buffer + bufflen - scmd->resid_len, 0, scmd->resid_len);
- if (resid)
- *resid = scmd->resid_len;
- if (sense && scmd->sense_len)
- memcpy(sense, scmd->sense_buffer, SCSI_SENSE_BUFFERSIZE);
- if (sshdr)
+ if (args->resid)
+ *args->resid = scmd->resid_len;
+ if (args->sense)
+ memcpy(args->sense, scmd->sense_buffer, SCSI_SENSE_BUFFERSIZE);
+ if (args->sshdr)
scsi_normalize_sense(scmd->sense_buffer, scmd->sense_len,
- sshdr);
+ args->sshdr);
+
ret = scmd->result;
out:
blk_mq_free_request(req);
return ret;
}
-EXPORT_SYMBOL(__scsi_execute);
+EXPORT_SYMBOL(scsi_execute_cmd);
/*
* Wake up the error handler if necessary. Avoid as follows that the error
@@ -2086,6 +2084,9 @@ int scsi_mode_select(struct scsi_device *sdev, int pf, int sp,
{
unsigned char cmd[10];
unsigned char *real_buffer;
+ const struct scsi_exec_args exec_args = {
+ .sshdr = sshdr,
+ };
int ret;
memset(cmd, 0, sizeof(cmd));
@@ -2135,8 +2136,8 @@ int scsi_mode_select(struct scsi_device *sdev, int pf, int sp,
cmd[4] = len;
}
- ret = scsi_execute_req(sdev, cmd, DMA_TO_DEVICE, real_buffer, len,
- sshdr, timeout, retries, NULL);
+ ret = scsi_execute_cmd(sdev, cmd, REQ_OP_DRV_OUT, real_buffer, len,
+ timeout, retries, &exec_args);
kfree(real_buffer);
return ret;
}
@@ -2167,6 +2168,10 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
int header_length;
int result, retry_count = retries;
struct scsi_sense_hdr my_sshdr;
+ const struct scsi_exec_args exec_args = {
+ /* caller might not be interested in sense, but we need it */
+ .sshdr = sshdr ? : &my_sshdr,
+ };
memset(data, 0, sizeof(*data));
memset(&cmd[0], 0, 12);
@@ -2175,9 +2180,7 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
cmd[1] = dbd & 0x18; /* allows DBD and LLBA bits */
cmd[2] = modepage;
- /* caller might not be interested in sense, but we need it */
- if (!sshdr)
- sshdr = &my_sshdr;
+ sshdr = exec_args.sshdr;
retry:
use_10_for_ms = sdev->use_10_for_ms || len > 255;
@@ -2200,8 +2203,8 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
memset(buffer, 0, len);
- result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer, len,
- sshdr, timeout, retries, NULL);
+ result = scsi_execute_cmd(sdev, cmd, REQ_OP_DRV_IN, buffer, len,
+ timeout, retries, &exec_args);
if (result < 0)
return result;
@@ -2281,12 +2284,15 @@ scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries,
char cmd[] = {
TEST_UNIT_READY, 0, 0, 0, 0, 0,
};
+ const struct scsi_exec_args exec_args = {
+ .sshdr = sshdr,
+ };
int result;
/* try to eat the UNIT_ATTENTION if there are enough retries */
do {
- result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, sshdr,
- timeout, 1, NULL);
+ result = scsi_execute_cmd(sdev, cmd, REQ_OP_DRV_IN, NULL, 0,
+ timeout, 1, &exec_args);
if (sdev->removable && scsi_sense_valid(sshdr) &&
sshdr->sense_key == UNIT_ATTENTION)
sdev->changed = 1;
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index f9b18fdc7b3c..4e842d79de31 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -210,7 +210,7 @@ static void scsi_unlock_floptical(struct scsi_device *sdev,
scsi_cmd[3] = 0;
scsi_cmd[4] = 0x2a; /* size */
scsi_cmd[5] = 0;
- scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE, result, 0x2a, NULL,
+ scsi_execute_cmd(sdev, scsi_cmd, REQ_OP_DRV_IN, result, 0x2a,
SCSI_TIMEOUT, 3, NULL);
}
@@ -646,8 +646,12 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result,
unsigned char scsi_cmd[MAX_COMMAND_SIZE];
int first_inquiry_len, try_inquiry_len, next_inquiry_len;
int response_len = 0;
- int pass, count, result;
+ int pass, count, result, resid;
struct scsi_sense_hdr sshdr;
+ const struct scsi_exec_args exec_args = {
+ .sshdr = &sshdr,
+ .resid = &resid,
+ };
*bflags = 0;
@@ -665,18 +669,16 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result,
/* Each pass gets up to three chances to ignore Unit Attention */
for (count = 0; count < 3; ++count) {
- int resid;
-
memset(scsi_cmd, 0, 6);
scsi_cmd[0] = INQUIRY;
scsi_cmd[4] = (unsigned char) try_inquiry_len;
memset(inq_result, 0, try_inquiry_len);
- result = scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE,
- inq_result, try_inquiry_len, &sshdr,
+ result = scsi_execute_cmd(sdev, scsi_cmd, REQ_OP_DRV_IN,
+ inq_result, try_inquiry_len,
HZ / 2 + HZ * scsi_inq_timeout, 3,
- &resid);
+ &exec_args);
SCSI_LOG_SCAN_BUS(3, sdev_printk(KERN_INFO, sdev,
"scsi scan: INQUIRY %s with code 0x%x\n",
@@ -1401,6 +1403,9 @@ static int scsi_report_lun_scan(struct scsi_target *starget, blist_flags_t bflag
struct scsi_sense_hdr sshdr;
struct scsi_device *sdev;
struct Scsi_Host *shost = dev_to_shost(&starget->dev);
+ const struct scsi_exec_args exec_args = {
+ .sshdr = &sshdr,
+ };
int ret = 0;
/*
@@ -1475,9 +1480,10 @@ retry:
"scsi scan: Sending REPORT LUNS to (try %d)\n",
retries));
- result = scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE,
- lun_data, length, &sshdr,
- SCSI_REPORT_LUNS_TIMEOUT, 3, NULL);
+ result = scsi_execute_cmd(sdev, scsi_cmd, REQ_OP_DRV_IN,
+ lun_data, length,
+ SCSI_REPORT_LUNS_TIMEOUT, 3,
+ &exec_args);
SCSI_LOG_SCAN_BUS(3, sdev_printk (KERN_INFO, sdev,
"scsi scan: REPORT LUNS"
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 8ef9a5494340..ee28f73af4d4 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -536,9 +536,9 @@ static int scsi_bus_match(struct device *dev, struct device_driver *gendrv)
return (sdp->inq_periph_qual == SCSI_INQ_PQ_CON)? 1: 0;
}
-static int scsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int scsi_bus_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct scsi_device *sdev;
+ const struct scsi_device *sdev;
if (dev->type != &scsi_dev_type)
return 0;
diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c
index f569cf0095c2..2442d4d2e3f3 100644
--- a/drivers/scsi/scsi_transport_spi.c
+++ b/drivers/scsi/scsi_transport_spi.c
@@ -105,28 +105,27 @@ static int sprint_frac(char *dest, int value, int denom)
}
static int spi_execute(struct scsi_device *sdev, const void *cmd,
- enum dma_data_direction dir,
- void *buffer, unsigned bufflen,
+ enum req_op op, void *buffer, unsigned int bufflen,
struct scsi_sense_hdr *sshdr)
{
int i, result;
- unsigned char sense[SCSI_SENSE_BUFFERSIZE];
struct scsi_sense_hdr sshdr_tmp;
+ blk_opf_t opf = op | REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
+ REQ_FAILFAST_DRIVER;
+ const struct scsi_exec_args exec_args = {
+ .req_flags = BLK_MQ_REQ_PM,
+ .sshdr = sshdr ? : &sshdr_tmp,
+ };
- if (!sshdr)
- sshdr = &sshdr_tmp;
+ sshdr = exec_args.sshdr;
for(i = 0; i < DV_RETRIES; i++) {
/*
* The purpose of the RQF_PM flag below is to bypass the
* SDEV_QUIESCE state.
*/
- result = scsi_execute(sdev, cmd, dir, buffer, bufflen, sense,
- sshdr, DV_TIMEOUT, /* retries */ 1,
- REQ_FAILFAST_DEV |
- REQ_FAILFAST_TRANSPORT |
- REQ_FAILFAST_DRIVER,
- RQF_PM, NULL);
+ result = scsi_execute_cmd(sdev, cmd, opf, buffer, bufflen,
+ DV_TIMEOUT, 1, &exec_args);
if (result < 0 || !scsi_sense_valid(sshdr) ||
sshdr->sense_key != UNIT_ATTENTION)
break;
@@ -675,7 +674,7 @@ spi_dv_device_echo_buffer(struct scsi_device *sdev, u8 *buffer,
}
for (r = 0; r < retries; r++) {
- result = spi_execute(sdev, spi_write_buffer, DMA_TO_DEVICE,
+ result = spi_execute(sdev, spi_write_buffer, REQ_OP_DRV_OUT,
buffer, len, &sshdr);
if(result || !scsi_device_online(sdev)) {
@@ -697,7 +696,7 @@ spi_dv_device_echo_buffer(struct scsi_device *sdev, u8 *buffer,
}
memset(ptr, 0, len);
- spi_execute(sdev, spi_read_buffer, DMA_FROM_DEVICE,
+ spi_execute(sdev, spi_read_buffer, REQ_OP_DRV_IN,
ptr, len, NULL);
scsi_device_set_state(sdev, SDEV_QUIESCE);
@@ -722,7 +721,7 @@ spi_dv_device_compare_inquiry(struct scsi_device *sdev, u8 *buffer,
for (r = 0; r < retries; r++) {
memset(ptr, 0, len);
- result = spi_execute(sdev, spi_inquiry, DMA_FROM_DEVICE,
+ result = spi_execute(sdev, spi_inquiry, REQ_OP_DRV_IN,
ptr, len, NULL);
if(result || !scsi_device_online(sdev)) {
@@ -828,7 +827,7 @@ spi_dv_device_get_echo_buffer(struct scsi_device *sdev, u8 *buffer)
* (reservation conflict, device not ready, etc) just
* skip the write tests */
for (l = 0; ; l++) {
- result = spi_execute(sdev, spi_test_unit_ready, DMA_NONE,
+ result = spi_execute(sdev, spi_test_unit_ready, REQ_OP_DRV_IN,
NULL, 0, NULL);
if(result) {
@@ -841,7 +840,7 @@ spi_dv_device_get_echo_buffer(struct scsi_device *sdev, u8 *buffer)
}
result = spi_execute(sdev, spi_read_buffer_descriptor,
- DMA_FROM_DEVICE, buffer, 4, NULL);
+ REQ_OP_DRV_IN, buffer, 4, NULL);
if (result)
/* Device has no echo buffer */
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 277960decc10..a38c71511bc9 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -664,6 +664,9 @@ static int sd_sec_submit(void *data, u16 spsp, u8 secp, void *buffer,
struct scsi_disk *sdkp = data;
struct scsi_device *sdev = sdkp->device;
u8 cdb[12] = { 0, };
+ const struct scsi_exec_args exec_args = {
+ .req_flags = BLK_MQ_REQ_PM,
+ };
int ret;
cdb[0] = send ? SECURITY_PROTOCOL_OUT : SECURITY_PROTOCOL_IN;
@@ -671,9 +674,9 @@ static int sd_sec_submit(void *data, u16 spsp, u8 secp, void *buffer,
put_unaligned_be16(spsp, &cdb[2]);
put_unaligned_be32(len, &cdb[6]);
- ret = scsi_execute(sdev, cdb, send ? DMA_TO_DEVICE : DMA_FROM_DEVICE,
- buffer, len, NULL, NULL, SD_TIMEOUT, sdkp->max_retries, 0,
- RQF_PM, NULL);
+ ret = scsi_execute_cmd(sdev, cdb, send ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN,
+ buffer, len, SD_TIMEOUT, sdkp->max_retries,
+ &exec_args);
return ret <= 0 ? ret : -EIO;
}
#endif /* CONFIG_BLK_SED_OPAL */
@@ -1581,13 +1584,16 @@ static int sd_sync_cache(struct scsi_disk *sdkp, struct scsi_sense_hdr *sshdr)
const int timeout = sdp->request_queue->rq_timeout
* SD_FLUSH_TIMEOUT_MULTIPLIER;
struct scsi_sense_hdr my_sshdr;
+ const struct scsi_exec_args exec_args = {
+ .req_flags = BLK_MQ_REQ_PM,
+ /* caller might not be interested in sense, but we need it */
+ .sshdr = sshdr ? : &my_sshdr,
+ };
if (!scsi_device_online(sdp))
return -ENODEV;
- /* caller might not be interested in sense, but we need it */
- if (!sshdr)
- sshdr = &my_sshdr;
+ sshdr = exec_args.sshdr;
for (retries = 3; retries > 0; --retries) {
unsigned char cmd[16] = { 0 };
@@ -1600,8 +1606,8 @@ static int sd_sync_cache(struct scsi_disk *sdkp, struct scsi_sense_hdr *sshdr)
* Leave the rest of the command zero to indicate
* flush everything.
*/
- res = scsi_execute(sdp, cmd, DMA_NONE, NULL, 0, NULL, sshdr,
- timeout, sdkp->max_retries, 0, RQF_PM, NULL);
+ res = scsi_execute_cmd(sdp, cmd, REQ_OP_DRV_IN, NULL, 0,
+ timeout, sdkp->max_retries, &exec_args);
if (res == 0)
break;
}
@@ -1743,6 +1749,9 @@ static int sd_pr_command(struct block_device *bdev, u8 sa,
struct scsi_disk *sdkp = scsi_disk(bdev->bd_disk);
struct scsi_device *sdev = sdkp->device;
struct scsi_sense_hdr sshdr;
+ const struct scsi_exec_args exec_args = {
+ .sshdr = &sshdr,
+ };
int result;
u8 cmd[16] = { 0, };
u8 data[24] = { 0, };
@@ -1756,8 +1765,9 @@ static int sd_pr_command(struct block_device *bdev, u8 sa,
put_unaligned_be64(sa_key, &data[8]);
data[20] = flags;
- result = scsi_execute_req(sdev, cmd, DMA_TO_DEVICE, &data, sizeof(data),
- &sshdr, SD_TIMEOUT, sdkp->max_retries, NULL);
+ result = scsi_execute_cmd(sdev, cmd, REQ_OP_DRV_OUT, &data,
+ sizeof(data), SD_TIMEOUT, sdkp->max_retries,
+ &exec_args);
if (scsi_status_is_check_condition(result) &&
scsi_sense_valid(&sshdr)) {
@@ -2086,6 +2096,9 @@ sd_spinup_disk(struct scsi_disk *sdkp)
int retries, spintime;
unsigned int the_result;
struct scsi_sense_hdr sshdr;
+ const struct scsi_exec_args exec_args = {
+ .sshdr = &sshdr,
+ };
int sense_valid = 0;
spintime = 0;
@@ -2101,10 +2114,11 @@ sd_spinup_disk(struct scsi_disk *sdkp)
cmd[0] = TEST_UNIT_READY;
memset((void *) &cmd[1], 0, 9);
- the_result = scsi_execute_req(sdkp->device, cmd,
- DMA_NONE, NULL, 0,
- &sshdr, SD_TIMEOUT,
- sdkp->max_retries, NULL);
+ the_result = scsi_execute_cmd(sdkp->device, cmd,
+ REQ_OP_DRV_IN, NULL, 0,
+ SD_TIMEOUT,
+ sdkp->max_retries,
+ &exec_args);
/*
* If the drive has indicated to us that it
@@ -2161,10 +2175,10 @@ sd_spinup_disk(struct scsi_disk *sdkp)
cmd[4] = 1; /* Start spin cycle */
if (sdkp->device->start_stop_pwr_cond)
cmd[4] |= 1 << 4;
- scsi_execute_req(sdkp->device, cmd, DMA_NONE,
- NULL, 0, &sshdr,
+ scsi_execute_cmd(sdkp->device, cmd,
+ REQ_OP_DRV_IN, NULL, 0,
SD_TIMEOUT, sdkp->max_retries,
- NULL);
+ &exec_args);
spintime_expire = jiffies + 100 * HZ;
spintime = 1;
}
@@ -2294,6 +2308,9 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,
{
unsigned char cmd[16];
struct scsi_sense_hdr sshdr;
+ const struct scsi_exec_args exec_args = {
+ .sshdr = &sshdr,
+ };
int sense_valid = 0;
int the_result;
int retries = 3, reset_retries = READ_CAPACITY_RETRIES_ON_RESET;
@@ -2311,9 +2328,9 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,
cmd[13] = RC16_LEN;
memset(buffer, 0, RC16_LEN);
- the_result = scsi_execute_req(sdp, cmd, DMA_FROM_DEVICE,
- buffer, RC16_LEN, &sshdr,
- SD_TIMEOUT, sdkp->max_retries, NULL);
+ the_result = scsi_execute_cmd(sdp, cmd, REQ_OP_DRV_IN,
+ buffer, RC16_LEN, SD_TIMEOUT,
+ sdkp->max_retries, &exec_args);
if (media_not_present(sdkp, &sshdr))
return -ENODEV;
@@ -2385,6 +2402,9 @@ static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp,
{
unsigned char cmd[16];
struct scsi_sense_hdr sshdr;
+ const struct scsi_exec_args exec_args = {
+ .sshdr = &sshdr,
+ };
int sense_valid = 0;
int the_result;
int retries = 3, reset_retries = READ_CAPACITY_RETRIES_ON_RESET;
@@ -2396,9 +2416,9 @@ static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp,
memset(&cmd[1], 0, 9);
memset(buffer, 0, 8);
- the_result = scsi_execute_req(sdp, cmd, DMA_FROM_DEVICE,
- buffer, 8, &sshdr,
- SD_TIMEOUT, sdkp->max_retries, NULL);
+ the_result = scsi_execute_cmd(sdp, cmd, REQ_OP_DRV_IN, buffer,
+ 8, SD_TIMEOUT, sdkp->max_retries,
+ &exec_args);
if (media_not_present(sdkp, &sshdr))
return -ENODEV;
@@ -3635,6 +3655,10 @@ static int sd_start_stop_device(struct scsi_disk *sdkp, int start)
{
unsigned char cmd[6] = { START_STOP }; /* START_VALID */
struct scsi_sense_hdr sshdr;
+ const struct scsi_exec_args exec_args = {
+ .sshdr = &sshdr,
+ .req_flags = BLK_MQ_REQ_PM,
+ };
struct scsi_device *sdp = sdkp->device;
int res;
@@ -3647,8 +3671,8 @@ static int sd_start_stop_device(struct scsi_disk *sdkp, int start)
if (!scsi_device_online(sdp))
return -ENODEV;
- res = scsi_execute(sdp, cmd, DMA_NONE, NULL, 0, NULL, &sshdr,
- SD_TIMEOUT, sdkp->max_retries, 0, RQF_PM, NULL);
+ res = scsi_execute_cmd(sdp, cmd, REQ_OP_DRV_IN, NULL, 0, SD_TIMEOUT,
+ sdkp->max_retries, &exec_args);
if (res) {
sd_print_result(sdkp, "Start/Stop Unit failed", res);
if (res > 0 && scsi_sense_valid(&sshdr)) {
@@ -3788,10 +3812,13 @@ static int sd_resume_runtime(struct device *dev)
if (sdp->ignore_media_change) {
/* clear the device's sense data */
static const u8 cmd[10] = { REQUEST_SENSE };
+ const struct scsi_exec_args exec_args = {
+ .req_flags = BLK_MQ_REQ_PM,
+ };
- if (scsi_execute(sdp, cmd, DMA_NONE, NULL, 0, NULL,
- NULL, sdp->request_queue->rq_timeout, 1, 0,
- RQF_PM, NULL))
+ if (scsi_execute_cmd(sdp, cmd, REQ_OP_DRV_IN, NULL, 0,
+ sdp->request_queue->rq_timeout, 1,
+ &exec_args))
sd_printk(KERN_NOTICE, sdkp,
"Failed to clear sense data\n");
}
diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c
index 62abebbaf2e7..6b3a02d4406c 100644
--- a/drivers/scsi/sd_zbc.c
+++ b/drivers/scsi/sd_zbc.c
@@ -148,6 +148,9 @@ static int sd_zbc_do_report_zones(struct scsi_disk *sdkp, unsigned char *buf,
struct scsi_device *sdp = sdkp->device;
const int timeout = sdp->request_queue->rq_timeout;
struct scsi_sense_hdr sshdr;
+ const struct scsi_exec_args exec_args = {
+ .sshdr = &sshdr,
+ };
unsigned char cmd[16];
unsigned int rep_len;
int result;
@@ -160,9 +163,8 @@ static int sd_zbc_do_report_zones(struct scsi_disk *sdkp, unsigned char *buf,
if (partial)
cmd[14] = ZBC_REPORT_ZONE_PARTIAL;
- result = scsi_execute_req(sdp, cmd, DMA_FROM_DEVICE,
- buf, buflen, &sshdr,
- timeout, SD_MAX_RETRIES, NULL);
+ result = scsi_execute_cmd(sdp, cmd, REQ_OP_DRV_IN, buf, buflen,
+ timeout, SD_MAX_RETRIES, &exec_args);
if (result) {
sd_printk(KERN_ERR, sdkp,
"REPORT ZONES start lba %llu failed\n", lba);
diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c
index 0a1734f34587..869ca9c7f23f 100644
--- a/drivers/scsi/ses.c
+++ b/drivers/scsi/ses.c
@@ -89,10 +89,13 @@ static int ses_recv_diag(struct scsi_device *sdev, int page_code,
unsigned char recv_page_code;
unsigned int retries = SES_RETRIES;
struct scsi_sense_hdr sshdr;
+ const struct scsi_exec_args exec_args = {
+ .sshdr = &sshdr,
+ };
do {
- ret = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, bufflen,
- &sshdr, SES_TIMEOUT, 1, NULL);
+ ret = scsi_execute_cmd(sdev, cmd, REQ_OP_DRV_IN, buf, bufflen,
+ SES_TIMEOUT, 1, &exec_args);
} while (ret > 0 && --retries && scsi_sense_valid(&sshdr) &&
(sshdr.sense_key == NOT_READY ||
(sshdr.sense_key == UNIT_ATTENTION && sshdr.asc == 0x29)));
@@ -130,10 +133,13 @@ static int ses_send_diag(struct scsi_device *sdev, int page_code,
};
struct scsi_sense_hdr sshdr;
unsigned int retries = SES_RETRIES;
+ const struct scsi_exec_args exec_args = {
+ .sshdr = &sshdr,
+ };
do {
- result = scsi_execute_req(sdev, cmd, DMA_TO_DEVICE, buf, bufflen,
- &sshdr, SES_TIMEOUT, 1, NULL);
+ result = scsi_execute_cmd(sdev, cmd, REQ_OP_DRV_OUT, buf,
+ bufflen, SES_TIMEOUT, 1, &exec_args);
} while (result > 0 && --retries && scsi_sense_valid(&sshdr) &&
(sshdr.sense_key == NOT_READY ||
(sshdr.sense_key == UNIT_ATTENTION && sshdr.asc == 0x29)));
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index ff9854f59964..a91049213203 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -1288,7 +1288,7 @@ sg_mmap(struct file *filp, struct vm_area_struct *vma)
}
sfp->mmap_called = 1;
- vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
+ vm_flags_set(vma, VM_IO | VM_DONTEXPAND | VM_DONTDUMP);
vma->vm_private_data = sfp;
vma->vm_ops = &sg_mmap_vm_ops;
out:
diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h
index af27bb0f3133..228838eb3686 100644
--- a/drivers/scsi/smartpqi/smartpqi.h
+++ b/drivers/scsi/smartpqi/smartpqi.h
@@ -954,7 +954,7 @@ struct report_log_lun {
struct report_log_lun_list {
struct report_lun_header header;
- struct report_log_lun lun_entries[1];
+ struct report_log_lun lun_entries[];
};
struct report_phys_lun_8byte_wwid {
diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c
index d0446d4d4465..49a8f91810b6 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -1259,7 +1259,8 @@ static int pqi_get_device_lists(struct pqi_ctrl_info *ctrl_info,
"report logical LUNs failed\n");
/*
- * Tack the controller itself onto the end of the logical device list.
+ * Tack the controller itself onto the end of the logical device list
+ * by adding a list entry that is all zeros.
*/
logdev_data = *logdev_list;
diff --git a/drivers/scsi/snic/snic_debugfs.c b/drivers/scsi/snic/snic_debugfs.c
index 57bdc3ba49d9..9dd975b36b5b 100644
--- a/drivers/scsi/snic/snic_debugfs.c
+++ b/drivers/scsi/snic/snic_debugfs.c
@@ -437,6 +437,6 @@ void snic_trc_debugfs_init(void)
void
snic_trc_debugfs_term(void)
{
- debugfs_remove(debugfs_lookup(TRC_FILE, snic_glob->trc_root));
- debugfs_remove(debugfs_lookup(TRC_ENABLE_FILE, snic_glob->trc_root));
+ debugfs_lookup_and_remove(TRC_FILE, snic_glob->trc_root);
+ debugfs_lookup_and_remove(TRC_ENABLE_FILE, snic_glob->trc_root);
}
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index a278b739d0c5..9e51dcd30bfd 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -170,10 +170,13 @@ static unsigned int sr_get_events(struct scsi_device *sdev)
struct event_header *eh = (void *)buf;
struct media_event_desc *med = (void *)(buf + 4);
struct scsi_sense_hdr sshdr;
+ const struct scsi_exec_args exec_args = {
+ .sshdr = &sshdr,
+ };
int result;
- result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, sizeof(buf),
- &sshdr, SR_TIMEOUT, MAX_RETRIES, NULL);
+ result = scsi_execute_cmd(sdev, cmd, REQ_OP_DRV_IN, buf, sizeof(buf),
+ SR_TIMEOUT, MAX_RETRIES, &exec_args);
if (scsi_sense_valid(&sshdr) && sshdr.sense_key == UNIT_ATTENTION)
return DISK_EVENT_MEDIA_CHANGE;
@@ -730,8 +733,8 @@ static void get_sectorsize(struct scsi_cd *cd)
memset(buffer, 0, sizeof(buffer));
/* Do the command and wait.. */
- the_result = scsi_execute_req(cd->device, cmd, DMA_FROM_DEVICE,
- buffer, sizeof(buffer), NULL,
+ the_result = scsi_execute_cmd(cd->device, cmd, REQ_OP_DRV_IN,
+ buffer, sizeof(buffer),
SR_TIMEOUT, MAX_RETRIES, NULL);
retries--;
diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c
index fbdb5124d7f7..5b0b35e60e61 100644
--- a/drivers/scsi/sr_ioctl.c
+++ b/drivers/scsi/sr_ioctl.c
@@ -188,13 +188,15 @@ static int sr_play_trkind(struct cdrom_device_info *cdi,
int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc)
{
struct scsi_device *SDev;
- struct scsi_sense_hdr local_sshdr, *sshdr = &local_sshdr;
+ struct scsi_sense_hdr local_sshdr, *sshdr;
int result, err = 0, retries = 0;
+ const struct scsi_exec_args exec_args = {
+ .sshdr = cgc->sshdr ? : &local_sshdr,
+ };
SDev = cd->device;
- if (cgc->sshdr)
- sshdr = cgc->sshdr;
+ sshdr = exec_args.sshdr;
retry:
if (!scsi_block_when_processing_errors(SDev)) {
@@ -202,10 +204,11 @@ int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc)
goto out;
}
- result = scsi_execute(SDev, cgc->cmd, cgc->data_direction,
- cgc->buffer, cgc->buflen, NULL, sshdr,
- cgc->timeout, IOCTL_RETRIES, 0, 0, NULL);
-
+ result = scsi_execute_cmd(SDev, cgc->cmd,
+ cgc->data_direction == DMA_TO_DEVICE ?
+ REQ_OP_DRV_OUT : REQ_OP_DRV_IN, cgc->buffer,
+ cgc->buflen, cgc->timeout, IOCTL_RETRIES,
+ &exec_args);
/* Minimal error checking. Ignore cases we know about, and report the rest. */
if (result < 0) {
err = result;
diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c
index d07d24c06b54..c5558c45ab3a 100644
--- a/drivers/scsi/virtio_scsi.c
+++ b/drivers/scsi/virtio_scsi.c
@@ -330,7 +330,7 @@ static void virtscsi_handle_param_change(struct virtio_scsi *vscsi,
scsi_device_put(sdev);
}
-static void virtscsi_rescan_hotunplug(struct virtio_scsi *vscsi)
+static int virtscsi_rescan_hotunplug(struct virtio_scsi *vscsi)
{
struct scsi_device *sdev;
struct Scsi_Host *shost = virtio_scsi_host(vscsi->vdev);
@@ -338,6 +338,11 @@ static void virtscsi_rescan_hotunplug(struct virtio_scsi *vscsi)
int result, inquiry_len, inq_result_len = 256;
char *inq_result = kmalloc(inq_result_len, GFP_KERNEL);
+ if (!inq_result) {
+ kfree(inq_result);
+ return -ENOMEM;
+ }
+
shost_for_each_device(sdev, shost) {
inquiry_len = sdev->inquiry_len ? sdev->inquiry_len : 36;
@@ -347,8 +352,8 @@ static void virtscsi_rescan_hotunplug(struct virtio_scsi *vscsi)
memset(inq_result, 0, inq_result_len);
- result = scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE,
- inq_result, inquiry_len, NULL,
+ result = scsi_execute_cmd(sdev, scsi_cmd, REQ_OP_DRV_IN,
+ inq_result, inquiry_len,
SD_TIMEOUT, SD_MAX_RETRIES, NULL);
if (result == 0 && inq_result[0] >> 5) {
@@ -366,6 +371,7 @@ static void virtscsi_rescan_hotunplug(struct virtio_scsi *vscsi)
}
kfree(inq_result);
+ return 0;
}
static void virtscsi_handle_event(struct work_struct *work)
@@ -377,9 +383,13 @@ static void virtscsi_handle_event(struct work_struct *work)
if (event->event &
cpu_to_virtio32(vscsi->vdev, VIRTIO_SCSI_T_EVENTS_MISSED)) {
+ int ret;
+
event->event &= ~cpu_to_virtio32(vscsi->vdev,
VIRTIO_SCSI_T_EVENTS_MISSED);
- virtscsi_rescan_hotunplug(vscsi);
+ ret = virtscsi_rescan_hotunplug(vscsi);
+ if (ret)
+ return;
scsi_scan_host(virtio_scsi_host(vscsi->vdev));
}
diff --git a/drivers/sh/clk/core.c b/drivers/sh/clk/core.c
index d996782a7106..7a73f5e4a1fc 100644
--- a/drivers/sh/clk/core.c
+++ b/drivers/sh/clk/core.c
@@ -295,7 +295,7 @@ int clk_enable(struct clk *clk)
int ret;
if (!clk)
- return -EINVAL;
+ return 0;
spin_lock_irqsave(&clock_lock, flags);
ret = __clk_enable(clk);
diff --git a/drivers/sh/maple/maple.c b/drivers/sh/maple/maple.c
index e24e220e56ee..e05473c5c267 100644
--- a/drivers/sh/maple/maple.c
+++ b/drivers/sh/maple/maple.c
@@ -760,12 +760,6 @@ static int maple_match_bus_driver(struct device *devptr,
return 0;
}
-static int maple_bus_uevent(struct device *dev,
- struct kobj_uevent_env *env)
-{
- return 0;
-}
-
static void maple_bus_release(struct device *dev)
{
}
@@ -782,7 +776,6 @@ static struct maple_driver maple_unsupported_device = {
struct bus_type maple_bus_type = {
.name = "maple",
.match = maple_match_bus_driver,
- .uevent = maple_bus_uevent,
};
EXPORT_SYMBOL_GPL(maple_bus_type);
diff --git a/drivers/slimbus/core.c b/drivers/slimbus/core.c
index 219483b79c09..d43873bb5fe6 100644
--- a/drivers/slimbus/core.c
+++ b/drivers/slimbus/core.c
@@ -93,9 +93,9 @@ static void slim_device_remove(struct device *dev)
}
}
-static int slim_device_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int slim_device_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct slim_device *sbdev = to_slim_device(dev);
+ const struct slim_device *sbdev = to_slim_device(dev);
return add_uevent_var(env, "MODALIAS=slim:%s", dev_name(&sbdev->dev));
}
diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
index 5dbb09f843f7..4e176280113a 100644
--- a/drivers/soc/Kconfig
+++ b/drivers/soc/Kconfig
@@ -16,12 +16,14 @@ source "drivers/soc/litex/Kconfig"
source "drivers/soc/loongson/Kconfig"
source "drivers/soc/mediatek/Kconfig"
source "drivers/soc/microchip/Kconfig"
+source "drivers/soc/nuvoton/Kconfig"
source "drivers/soc/pxa/Kconfig"
source "drivers/soc/qcom/Kconfig"
source "drivers/soc/renesas/Kconfig"
source "drivers/soc/rockchip/Kconfig"
source "drivers/soc/samsung/Kconfig"
source "drivers/soc/sifive/Kconfig"
+source "drivers/soc/starfive/Kconfig"
source "drivers/soc/sunxi/Kconfig"
source "drivers/soc/tegra/Kconfig"
source "drivers/soc/ti/Kconfig"
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
index fff513bd522d..3b0f9fb3b5c8 100644
--- a/drivers/soc/Makefile
+++ b/drivers/soc/Makefile
@@ -21,13 +21,15 @@ obj-$(CONFIG_LITEX_SOC_CONTROLLER) += litex/
obj-y += loongson/
obj-y += mediatek/
obj-y += microchip/
+obj-y += nuvoton/
obj-y += pxa/
obj-y += amlogic/
obj-y += qcom/
obj-y += renesas/
obj-y += rockchip/
obj-$(CONFIG_SOC_SAMSUNG) += samsung/
-obj-$(CONFIG_SOC_SIFIVE) += sifive/
+obj-y += sifive/
+obj-$(CONFIG_SOC_STARFIVE) += starfive/
obj-y += sunxi/
obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-y += ti/
diff --git a/drivers/soc/amlogic/meson-ee-pwrc.c b/drivers/soc/amlogic/meson-ee-pwrc.c
index dd5f2a13ceb5..f54acffc83f9 100644
--- a/drivers/soc/amlogic/meson-ee-pwrc.c
+++ b/drivers/soc/amlogic/meson-ee-pwrc.c
@@ -46,6 +46,9 @@
#define HHI_NANOQ_MEM_PD_REG1 (0x47 << 2)
#define HHI_VPU_MEM_PD_REG2 (0x4d << 2)
+#define G12A_HHI_NANOQ_MEM_PD_REG0 (0x43 << 2)
+#define G12A_HHI_NANOQ_MEM_PD_REG1 (0x44 << 2)
+
struct meson_ee_pwrc;
struct meson_ee_pwrc_domain;
@@ -106,6 +109,13 @@ static struct meson_ee_pwrc_top_domain sm1_pwrc_usb = SM1_EE_PD(17);
static struct meson_ee_pwrc_top_domain sm1_pwrc_pci = SM1_EE_PD(18);
static struct meson_ee_pwrc_top_domain sm1_pwrc_ge2d = SM1_EE_PD(19);
+static struct meson_ee_pwrc_top_domain g12a_pwrc_nna = {
+ .sleep_reg = GX_AO_RTI_GEN_PWR_SLEEP0,
+ .sleep_mask = BIT(16) | BIT(17),
+ .iso_reg = GX_AO_RTI_GEN_PWR_ISO0,
+ .iso_mask = BIT(16) | BIT(17),
+};
+
/* Memory PD Domains */
#define VPU_MEMPD(__reg) \
@@ -217,6 +227,11 @@ static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_audio[] = {
{ HHI_AUDIO_MEM_PD_REG0, GENMASK(27, 26) },
};
+static struct meson_ee_pwrc_mem_domain g12a_pwrc_mem_nna[] = {
+ { G12A_HHI_NANOQ_MEM_PD_REG0, GENMASK(31, 0) },
+ { G12A_HHI_NANOQ_MEM_PD_REG1, GENMASK(23, 0) },
+};
+
#define VPU_PD(__name, __top_pd, __mem, __is_pwr_off, __resets, __clks) \
{ \
.name = __name, \
@@ -253,6 +268,8 @@ static struct meson_ee_pwrc_domain_desc g12a_pwrc_domains[] = {
[PWRC_G12A_VPU_ID] = VPU_PD("VPU", &gx_pwrc_vpu, g12a_pwrc_mem_vpu,
pwrc_ee_is_powered_off, 11, 2),
[PWRC_G12A_ETH_ID] = MEM_PD("ETH", meson_pwrc_mem_eth),
+ [PWRC_G12A_NNA_ID] = TOP_PD("NNA", &g12a_pwrc_nna, g12a_pwrc_mem_nna,
+ pwrc_ee_is_powered_off),
};
static struct meson_ee_pwrc_domain_desc gxbb_pwrc_domains[] = {
diff --git a/drivers/soc/apple/apple-pmgr-pwrstate.c b/drivers/soc/apple/apple-pmgr-pwrstate.c
index e1122288409a..a3e2bc1d2686 100644
--- a/drivers/soc/apple/apple-pmgr-pwrstate.c
+++ b/drivers/soc/apple/apple-pmgr-pwrstate.c
@@ -116,8 +116,9 @@ static int apple_pmgr_ps_power_off(struct generic_pm_domain *genpd)
static int apple_pmgr_reset_assert(struct reset_controller_dev *rcdev, unsigned long id)
{
struct apple_pmgr_ps *ps = rcdev_to_apple_pmgr_ps(rcdev);
+ unsigned long flags;
- mutex_lock(&ps->genpd.mlock);
+ spin_lock_irqsave(&ps->genpd.slock, flags);
if (ps->genpd.status == GENPD_STATE_OFF)
dev_err(ps->dev, "PS 0x%x: asserting RESET while powered down\n", ps->offset);
@@ -129,7 +130,7 @@ static int apple_pmgr_reset_assert(struct reset_controller_dev *rcdev, unsigned
regmap_update_bits(ps->regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_RESET,
APPLE_PMGR_RESET);
- mutex_unlock(&ps->genpd.mlock);
+ spin_unlock_irqrestore(&ps->genpd.slock, flags);
return 0;
}
@@ -137,8 +138,9 @@ static int apple_pmgr_reset_assert(struct reset_controller_dev *rcdev, unsigned
static int apple_pmgr_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id)
{
struct apple_pmgr_ps *ps = rcdev_to_apple_pmgr_ps(rcdev);
+ unsigned long flags;
- mutex_lock(&ps->genpd.mlock);
+ spin_lock_irqsave(&ps->genpd.slock, flags);
dev_dbg(ps->dev, "PS 0x%x: deassert reset\n", ps->offset);
regmap_update_bits(ps->regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_RESET, 0);
@@ -147,7 +149,7 @@ static int apple_pmgr_reset_deassert(struct reset_controller_dev *rcdev, unsigne
if (ps->genpd.status == GENPD_STATE_OFF)
dev_err(ps->dev, "PS 0x%x: RESET was deasserted while powered down\n", ps->offset);
- mutex_unlock(&ps->genpd.mlock);
+ spin_unlock_irqrestore(&ps->genpd.slock, flags);
return 0;
}
@@ -222,6 +224,7 @@ static int apple_pmgr_ps_probe(struct platform_device *pdev)
return ret;
}
+ ps->genpd.flags |= GENPD_FLAG_IRQ_SAFE;
ps->genpd.name = name;
ps->genpd.power_on = apple_pmgr_ps_power_on;
ps->genpd.power_off = apple_pmgr_ps_power_off;
diff --git a/drivers/soc/apple/rtkit-crashlog.c b/drivers/soc/apple/rtkit-crashlog.c
index 732deed64660..8319e365110b 100644
--- a/drivers/soc/apple/rtkit-crashlog.c
+++ b/drivers/soc/apple/rtkit-crashlog.c
@@ -13,6 +13,17 @@
#define APPLE_RTKIT_CRASHLOG_VERSION FOURCC('C', 'v', 'e', 'r')
#define APPLE_RTKIT_CRASHLOG_MBOX FOURCC('C', 'm', 'b', 'x')
#define APPLE_RTKIT_CRASHLOG_TIME FOURCC('C', 't', 'i', 'm')
+#define APPLE_RTKIT_CRASHLOG_REGS FOURCC('C', 'r', 'g', '8')
+
+/* For COMPILE_TEST on non-ARM64 architectures */
+#ifndef PSR_MODE_EL0t
+#define PSR_MODE_EL0t 0x00000000
+#define PSR_MODE_EL1t 0x00000004
+#define PSR_MODE_EL1h 0x00000005
+#define PSR_MODE_EL2t 0x00000008
+#define PSR_MODE_EL2h 0x00000009
+#define PSR_MODE_MASK 0x0000000f
+#endif
struct apple_rtkit_crashlog_header {
u32 fourcc;
@@ -31,6 +42,24 @@ struct apple_rtkit_crashlog_mbox_entry {
};
static_assert(sizeof(struct apple_rtkit_crashlog_mbox_entry) == 0x18);
+struct apple_rtkit_crashlog_regs {
+ u32 unk_0;
+ u32 unk_4;
+ u64 regs[31];
+ u64 sp;
+ u64 pc;
+ u64 psr;
+ u64 cpacr;
+ u64 fpsr;
+ u64 fpcr;
+ u64 unk[64];
+ u64 far;
+ u64 unk_X;
+ u64 esr;
+ u64 unk_Z;
+} __packed;
+static_assert(sizeof(struct apple_rtkit_crashlog_regs) == 0x350);
+
static void apple_rtkit_crashlog_dump_str(struct apple_rtkit *rtk, u8 *bfr,
size_t size)
{
@@ -94,6 +123,66 @@ static void apple_rtkit_crashlog_dump_mailbox(struct apple_rtkit *rtk, u8 *bfr,
}
}
+static void apple_rtkit_crashlog_dump_regs(struct apple_rtkit *rtk, u8 *bfr,
+ size_t size)
+{
+ struct apple_rtkit_crashlog_regs *regs;
+ const char *el;
+ int i;
+
+ if (size < sizeof(*regs)) {
+ dev_warn(rtk->dev, "RTKit: Regs section too small: 0x%zx", size);
+ return;
+ }
+
+ regs = (struct apple_rtkit_crashlog_regs *)bfr;
+
+ switch (regs->psr & PSR_MODE_MASK) {
+ case PSR_MODE_EL0t:
+ el = "EL0t";
+ break;
+ case PSR_MODE_EL1t:
+ el = "EL1t";
+ break;
+ case PSR_MODE_EL1h:
+ el = "EL1h";
+ break;
+ case PSR_MODE_EL2t:
+ el = "EL2t";
+ break;
+ case PSR_MODE_EL2h:
+ el = "EL2h";
+ break;
+ default:
+ el = "unknown";
+ break;
+ }
+
+ dev_warn(rtk->dev, "RTKit: Exception dump:");
+ dev_warn(rtk->dev, " == Exception taken from %s ==", el);
+ dev_warn(rtk->dev, " PSR = 0x%llx", regs->psr);
+ dev_warn(rtk->dev, " PC = 0x%llx\n", regs->pc);
+ dev_warn(rtk->dev, " ESR = 0x%llx\n", regs->esr);
+ dev_warn(rtk->dev, " FAR = 0x%llx\n", regs->far);
+ dev_warn(rtk->dev, " SP = 0x%llx\n", regs->sp);
+ dev_warn(rtk->dev, "\n");
+
+ for (i = 0; i < 31; i += 4) {
+ if (i < 28)
+ dev_warn(rtk->dev,
+ " x%02d-x%02d = %016llx %016llx %016llx %016llx\n",
+ i, i + 3,
+ regs->regs[i], regs->regs[i + 1],
+ regs->regs[i + 2], regs->regs[i + 3]);
+ else
+ dev_warn(rtk->dev,
+ " x%02d-x%02d = %016llx %016llx %016llx\n", i, i + 3,
+ regs->regs[i], regs->regs[i + 1], regs->regs[i + 2]);
+ }
+
+ dev_warn(rtk->dev, "\n");
+}
+
void apple_rtkit_crashlog_dump(struct apple_rtkit *rtk, u8 *bfr, size_t size)
{
size_t offset;
@@ -140,6 +229,10 @@ void apple_rtkit_crashlog_dump(struct apple_rtkit *rtk, u8 *bfr, size_t size)
apple_rtkit_crashlog_dump_time(rtk, bfr + offset + 16,
section_size);
break;
+ case APPLE_RTKIT_CRASHLOG_REGS:
+ apple_rtkit_crashlog_dump_regs(rtk, bfr + offset + 16,
+ section_size);
+ break;
default:
dev_warn(rtk->dev,
"RTKit: Unknown crashlog section: %x",
diff --git a/drivers/soc/apple/rtkit.c b/drivers/soc/apple/rtkit.c
index 8ec74d7539eb..35ec35aa500d 100644
--- a/drivers/soc/apple/rtkit.c
+++ b/drivers/soc/apple/rtkit.c
@@ -9,6 +9,7 @@
enum {
APPLE_RTKIT_PWR_STATE_OFF = 0x00, /* power off, cannot be restarted */
APPLE_RTKIT_PWR_STATE_SLEEP = 0x01, /* sleeping, can be restarted */
+ APPLE_RTKIT_PWR_STATE_IDLE = 0x201, /* sleeping, retain state */
APPLE_RTKIT_PWR_STATE_QUIESCED = 0x10, /* running but no communication */
APPLE_RTKIT_PWR_STATE_ON = 0x20, /* normal operating state */
};
@@ -698,7 +699,7 @@ static int apple_rtkit_request_mbox_chan(struct apple_rtkit *rtk)
return 0;
}
-static struct apple_rtkit *apple_rtkit_init(struct device *dev, void *cookie,
+struct apple_rtkit *apple_rtkit_init(struct device *dev, void *cookie,
const char *mbox_name, int mbox_idx,
const struct apple_rtkit_ops *ops)
{
@@ -750,6 +751,7 @@ free_rtk:
kfree(rtk);
return ERR_PTR(ret);
}
+EXPORT_SYMBOL_GPL(apple_rtkit_init);
static int apple_rtkit_wait_for_completion(struct completion *c)
{
@@ -881,6 +883,26 @@ int apple_rtkit_shutdown(struct apple_rtkit *rtk)
}
EXPORT_SYMBOL_GPL(apple_rtkit_shutdown);
+int apple_rtkit_idle(struct apple_rtkit *rtk)
+{
+ int ret;
+
+ /* if OFF is used here the co-processor will not wake up again */
+ ret = apple_rtkit_set_ap_power_state(rtk,
+ APPLE_RTKIT_PWR_STATE_IDLE);
+ if (ret)
+ return ret;
+
+ ret = apple_rtkit_set_iop_power_state(rtk, APPLE_RTKIT_PWR_STATE_IDLE);
+ if (ret)
+ return ret;
+
+ rtk->iop_power_state = APPLE_RTKIT_PWR_STATE_IDLE;
+ rtk->ap_power_state = APPLE_RTKIT_PWR_STATE_IDLE;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(apple_rtkit_idle);
+
int apple_rtkit_quiesce(struct apple_rtkit *rtk)
{
int ret;
@@ -926,10 +948,8 @@ int apple_rtkit_wake(struct apple_rtkit *rtk)
}
EXPORT_SYMBOL_GPL(apple_rtkit_wake);
-static void apple_rtkit_free(void *data)
+void apple_rtkit_free(struct apple_rtkit *rtk)
{
- struct apple_rtkit *rtk = data;
-
mbox_free_channel(rtk->mbox_chan);
destroy_workqueue(rtk->wq);
@@ -940,6 +960,12 @@ static void apple_rtkit_free(void *data)
kfree(rtk->syslog_msg_buffer);
kfree(rtk);
}
+EXPORT_SYMBOL_GPL(apple_rtkit_free);
+
+static void apple_rtkit_free_wrapper(void *data)
+{
+ apple_rtkit_free(data);
+}
struct apple_rtkit *devm_apple_rtkit_init(struct device *dev, void *cookie,
const char *mbox_name, int mbox_idx,
@@ -952,7 +978,7 @@ struct apple_rtkit *devm_apple_rtkit_init(struct device *dev, void *cookie,
if (IS_ERR(rtk))
return rtk;
- ret = devm_add_action_or_reset(dev, apple_rtkit_free, rtk);
+ ret = devm_add_action_or_reset(dev, apple_rtkit_free_wrapper, rtk);
if (ret)
return ERR_PTR(ret);
diff --git a/drivers/soc/bcm/bcm2835-power.c b/drivers/soc/bcm/bcm2835-power.c
index 5bcd047768b6..bf51f03f77d6 100644
--- a/drivers/soc/bcm/bcm2835-power.c
+++ b/drivers/soc/bcm/bcm2835-power.c
@@ -701,14 +701,8 @@ fail:
return ret;
}
-static int bcm2835_power_remove(struct platform_device *pdev)
-{
- return 0;
-}
-
static struct platform_driver bcm2835_power_driver = {
.probe = bcm2835_power_probe,
- .remove = bcm2835_power_remove,
.driver = {
.name = "bcm2835-power",
},
diff --git a/drivers/soc/imx/Kconfig b/drivers/soc/imx/Kconfig
index 4b906791d6c7..a8742fc58f01 100644
--- a/drivers/soc/imx/Kconfig
+++ b/drivers/soc/imx/Kconfig
@@ -28,4 +28,15 @@ config SOC_IMX9
help
If you say yes here, you get support for the NXP i.MX9 family
+config IMX8M_BLK_CTRL
+ bool
+ default SOC_IMX8M && IMX_GPCV2_PM_DOMAINS
+ depends on PM_GENERIC_DOMAINS
+ depends on COMMON_CLK
+
+config IMX9_BLK_CTRL
+ bool
+ default SOC_IMX9 && IMX_GPCV2_PM_DOMAINS
+ depends on PM_GENERIC_DOMAINS
+
endmenu
diff --git a/drivers/soc/imx/Makefile b/drivers/soc/imx/Makefile
index 7b4099ceafd6..a28c44a1f16a 100644
--- a/drivers/soc/imx/Makefile
+++ b/drivers/soc/imx/Makefile
@@ -5,7 +5,7 @@ endif
obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o
obj-$(CONFIG_IMX_GPCV2_PM_DOMAINS) += gpcv2.o
obj-$(CONFIG_SOC_IMX8M) += soc-imx8m.o
-obj-$(CONFIG_SOC_IMX8M) += imx8m-blk-ctrl.o
-obj-$(CONFIG_SOC_IMX8M) += imx8mp-blk-ctrl.o
+obj-$(CONFIG_IMX8M_BLK_CTRL) += imx8m-blk-ctrl.o
+obj-$(CONFIG_IMX8M_BLK_CTRL) += imx8mp-blk-ctrl.o
obj-$(CONFIG_SOC_IMX9) += imx93-src.o imx93-pd.o
-obj-$(CONFIG_SOC_IMX9) += imx93-blk-ctrl.o
+obj-$(CONFIG_IMX9_BLK_CTRL) += imx93-blk-ctrl.o
diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c
index 7a47d14fde44..4b3300b090a8 100644
--- a/drivers/soc/imx/gpcv2.c
+++ b/drivers/soc/imx/gpcv2.c
@@ -1518,7 +1518,7 @@ static int imx_gpcv2_probe(struct platform_device *pdev)
domain->genpd.power_off = imx_pgc_power_down;
pd_pdev->dev.parent = dev;
- pd_pdev->dev.of_node = np;
+ device_set_node(&pd_pdev->dev, of_fwnode_handle(np));
ret = platform_device_add(pd_pdev);
if (ret) {
diff --git a/drivers/soc/imx/imx8m-blk-ctrl.c b/drivers/soc/imx/imx8m-blk-ctrl.c
index ddcf6be3d8b4..399cb85105a1 100644
--- a/drivers/soc/imx/imx8m-blk-ctrl.c
+++ b/drivers/soc/imx/imx8m-blk-ctrl.c
@@ -4,6 +4,7 @@
* Copyright 2021 Pengutronix, Lucas Stach <kernel@pengutronix.de>
*/
+#include <linux/bitfield.h>
#include <linux/device.h>
#include <linux/interconnect.h>
#include <linux/module.h>
@@ -654,6 +655,10 @@ static const struct imx8m_blk_ctrl_data imx8mn_disp_blk_ctl_dev_data = {
.num_domains = ARRAY_SIZE(imx8mn_disp_blk_ctl_domain_data),
};
+#define LCDIF_ARCACHE_CTRL 0x4c
+#define LCDIF_1_RD_HURRY GENMASK(15, 13)
+#define LCDIF_0_RD_HURRY GENMASK(12, 10)
+
static int imx8mp_media_power_notifier(struct notifier_block *nb,
unsigned long action, void *data)
{
@@ -667,14 +672,24 @@ static int imx8mp_media_power_notifier(struct notifier_block *nb,
regmap_set_bits(bc->regmap, BLK_CLK_EN, BIT(8));
regmap_set_bits(bc->regmap, BLK_SFT_RSTN, BIT(8));
- /*
- * On power up we have no software backchannel to the GPC to
- * wait for the ADB handshake to happen, so we just delay for a
- * bit. On power down the GPC driver waits for the handshake.
- */
- if (action == GENPD_NOTIFY_ON)
+ if (action == GENPD_NOTIFY_ON) {
+ /*
+ * On power up we have no software backchannel to the GPC to
+ * wait for the ADB handshake to happen, so we just delay for a
+ * bit. On power down the GPC driver waits for the handshake.
+ */
udelay(5);
+ /*
+ * Set panic read hurry level for both LCDIF interfaces to
+ * maximum priority to minimize chances of display FIFO
+ * underflow.
+ */
+ regmap_set_bits(bc->regmap, LCDIF_ARCACHE_CTRL,
+ FIELD_PREP(LCDIF_1_RD_HURRY, 7) |
+ FIELD_PREP(LCDIF_0_RD_HURRY, 7));
+ }
+
return NOTIFY_OK;
}
diff --git a/drivers/soc/imx/imx8mp-blk-ctrl.c b/drivers/soc/imx/imx8mp-blk-ctrl.c
index 0f13853901df..a0592db8fa86 100644
--- a/drivers/soc/imx/imx8mp-blk-ctrl.c
+++ b/drivers/soc/imx/imx8mp-blk-ctrl.c
@@ -4,7 +4,9 @@
* Copyright 2022 Pengutronix, Lucas Stach <kernel@pengutronix.de>
*/
+#include <linux/bitfield.h>
#include <linux/clk.h>
+#include <linux/clk-provider.h>
#include <linux/device.h>
#include <linux/interconnect.h>
#include <linux/module.h>
@@ -21,6 +23,15 @@
#define USB_CLOCK_MODULE_EN BIT(1)
#define PCIE_PHY_APB_RST BIT(4)
#define PCIE_PHY_INIT_RST BIT(5)
+#define GPR_REG1 0x4
+#define PLL_LOCK BIT(13)
+#define GPR_REG2 0x8
+#define P_PLL_MASK GENMASK(5, 0)
+#define M_PLL_MASK GENMASK(15, 6)
+#define S_PLL_MASK GENMASK(18, 16)
+#define GPR_REG3 0xc
+#define PLL_CKE BIT(17)
+#define PLL_RST BIT(31)
struct imx8mp_blk_ctrl_domain;
@@ -60,6 +71,7 @@ struct imx8mp_blk_ctrl_domain {
struct imx8mp_blk_ctrl_data {
int max_reg;
+ int (*probe) (struct imx8mp_blk_ctrl *bc);
notifier_fn_t power_notifier_fn;
void (*power_off) (struct imx8mp_blk_ctrl *bc, struct imx8mp_blk_ctrl_domain *domain);
void (*power_on) (struct imx8mp_blk_ctrl *bc, struct imx8mp_blk_ctrl_domain *domain);
@@ -73,6 +85,92 @@ to_imx8mp_blk_ctrl_domain(struct generic_pm_domain *genpd)
return container_of(genpd, struct imx8mp_blk_ctrl_domain, genpd);
}
+struct clk_hsio_pll {
+ struct clk_hw hw;
+ struct regmap *regmap;
+};
+
+static inline struct clk_hsio_pll *to_clk_hsio_pll(struct clk_hw *hw)
+{
+ return container_of(hw, struct clk_hsio_pll, hw);
+}
+
+static int clk_hsio_pll_prepare(struct clk_hw *hw)
+{
+ struct clk_hsio_pll *clk = to_clk_hsio_pll(hw);
+ u32 val;
+
+ /* set the PLL configuration */
+ regmap_update_bits(clk->regmap, GPR_REG2,
+ P_PLL_MASK | M_PLL_MASK | S_PLL_MASK,
+ FIELD_PREP(P_PLL_MASK, 12) |
+ FIELD_PREP(M_PLL_MASK, 800) |
+ FIELD_PREP(S_PLL_MASK, 4));
+
+ /* de-assert PLL reset */
+ regmap_update_bits(clk->regmap, GPR_REG3, PLL_RST, PLL_RST);
+
+ /* enable PLL */
+ regmap_update_bits(clk->regmap, GPR_REG3, PLL_CKE, PLL_CKE);
+
+ return regmap_read_poll_timeout(clk->regmap, GPR_REG1, val,
+ val & PLL_LOCK, 10, 100);
+}
+
+static void clk_hsio_pll_unprepare(struct clk_hw *hw)
+{
+ struct clk_hsio_pll *clk = to_clk_hsio_pll(hw);
+
+ regmap_update_bits(clk->regmap, GPR_REG3, PLL_RST | PLL_CKE, 0);
+}
+
+static int clk_hsio_pll_is_prepared(struct clk_hw *hw)
+{
+ struct clk_hsio_pll *clk = to_clk_hsio_pll(hw);
+
+ return regmap_test_bits(clk->regmap, GPR_REG1, PLL_LOCK);
+}
+
+static unsigned long clk_hsio_pll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ return 100000000;
+}
+
+static const struct clk_ops clk_hsio_pll_ops = {
+ .prepare = clk_hsio_pll_prepare,
+ .unprepare = clk_hsio_pll_unprepare,
+ .is_prepared = clk_hsio_pll_is_prepared,
+ .recalc_rate = clk_hsio_pll_recalc_rate,
+};
+
+static int imx8mp_hsio_blk_ctrl_probe(struct imx8mp_blk_ctrl *bc)
+{
+ struct clk_hsio_pll *clk_hsio_pll;
+ struct clk_hw *hw;
+ struct clk_init_data init = {};
+ int ret;
+
+ clk_hsio_pll = devm_kzalloc(bc->dev, sizeof(*clk_hsio_pll), GFP_KERNEL);
+ if (!clk_hsio_pll)
+ return -ENOMEM;
+
+ init.name = "hsio_pll";
+ init.ops = &clk_hsio_pll_ops;
+ init.parent_names = (const char *[]){"osc_24m"};
+ init.num_parents = 1;
+
+ clk_hsio_pll->regmap = bc->regmap;
+ clk_hsio_pll->hw.init = &init;
+
+ hw = &clk_hsio_pll->hw;
+ ret = devm_clk_hw_register(bc->dev, hw);
+ if (ret)
+ return ret;
+
+ return devm_of_clk_add_hw_provider(bc->dev, of_clk_hw_simple_get, hw);
+}
+
static void imx8mp_hsio_blk_ctrl_power_on(struct imx8mp_blk_ctrl *bc,
struct imx8mp_blk_ctrl_domain *domain)
{
@@ -187,6 +285,7 @@ static const struct imx8mp_blk_ctrl_domain_data imx8mp_hsio_domain_data[] = {
static const struct imx8mp_blk_ctrl_data imx8mp_hsio_blk_ctl_dev_data = {
.max_reg = 0x24,
+ .probe = imx8mp_hsio_blk_ctrl_probe,
.power_on = imx8mp_hsio_blk_ctrl_power_on,
.power_off = imx8mp_hsio_blk_ctrl_power_off,
.power_notifier_fn = imx8mp_hsio_power_notifier,
@@ -201,6 +300,7 @@ static const struct imx8mp_blk_ctrl_data imx8mp_hsio_blk_ctl_dev_data = {
#define HDMI_RTX_CLK_CTL3 0x70
#define HDMI_RTX_CLK_CTL4 0x80
#define HDMI_TX_CONTROL0 0x200
+#define HDMI_LCDIF_NOC_HURRY_MASK GENMASK(14, 12)
static void imx8mp_hdmi_blk_ctrl_power_on(struct imx8mp_blk_ctrl *bc,
struct imx8mp_blk_ctrl_domain *domain)
@@ -217,6 +317,8 @@ static void imx8mp_hdmi_blk_ctrl_power_on(struct imx8mp_blk_ctrl *bc,
regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(11));
regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0,
BIT(4) | BIT(5) | BIT(6));
+ regmap_set_bits(bc->regmap, HDMI_TX_CONTROL0,
+ FIELD_PREP(HDMI_LCDIF_NOC_HURRY_MASK, 7));
break;
case IMX8MP_HDMIBLK_PD_PAI:
regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(17));
@@ -635,6 +737,12 @@ static int imx8mp_blk_ctrl_probe(struct platform_device *pdev)
goto cleanup_provider;
}
+ if (bc_data->probe) {
+ ret = bc_data->probe(bc);
+ if (ret)
+ goto cleanup_provider;
+ }
+
dev_set_drvdata(dev, bc);
return 0;
diff --git a/drivers/soc/imx/imx93-pd.c b/drivers/soc/imx/imx93-pd.c
index 4d235c8c4924..832deeed8fd6 100644
--- a/drivers/soc/imx/imx93-pd.c
+++ b/drivers/soc/imx/imx93-pd.c
@@ -164,7 +164,6 @@ MODULE_DEVICE_TABLE(of, imx93_pd_ids);
static struct platform_driver imx93_power_domain_driver = {
.driver = {
.name = "imx93_power_domain",
- .owner = THIS_MODULE,
.of_match_table = imx93_pd_ids,
},
.probe = imx93_pd_probe,
diff --git a/drivers/soc/imx/imx93-src.c b/drivers/soc/imx/imx93-src.c
index 4d74921cae0f..f1c2e22d5cbd 100644
--- a/drivers/soc/imx/imx93-src.c
+++ b/drivers/soc/imx/imx93-src.c
@@ -21,7 +21,6 @@ MODULE_DEVICE_TABLE(of, imx93_src_ids);
static struct platform_driver imx93_src_driver = {
.driver = {
.name = "imx93_src",
- .owner = THIS_MODULE,
.of_match_table = imx93_src_ids,
},
.probe = imx93_src_probe,
diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig
index 40d0cc600cae..d6b83a5508ca 100644
--- a/drivers/soc/mediatek/Kconfig
+++ b/drivers/soc/mediatek/Kconfig
@@ -44,6 +44,11 @@ config MTK_PMIC_WRAP
on different MediaTek SoCs. The PMIC wrapper is a proprietary
hardware to connect the PMIC.
+config MTK_REGULATOR_COUPLER
+ bool "MediaTek SoC Regulator Coupler" if COMPILE_TEST
+ default ARCH_MEDIATEK
+ depends on REGULATOR
+
config MTK_SCPSYS
bool "MediaTek SCPSYS Support"
default ARCH_MEDIATEK
@@ -68,7 +73,7 @@ config MTK_SCPSYS_PM_DOMAINS
tasks in the system.
config MTK_MMSYS
- bool "MediaTek MMSYS Support"
+ tristate "MediaTek MMSYS Support"
default ARCH_MEDIATEK
depends on HAS_IOMEM
help
diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile
index 0e9e703c931a..8c0ddacbcde8 100644
--- a/drivers/soc/mediatek/Makefile
+++ b/drivers/soc/mediatek/Makefile
@@ -3,6 +3,7 @@ obj-$(CONFIG_MTK_CMDQ) += mtk-cmdq-helper.o
obj-$(CONFIG_MTK_DEVAPC) += mtk-devapc.o
obj-$(CONFIG_MTK_INFRACFG) += mtk-infracfg.o
obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o
+obj-$(CONFIG_MTK_REGULATOR_COUPLER) += mtk-regulator-coupler.o
obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o
obj-$(CONFIG_MTK_SCPSYS_PM_DOMAINS) += mtk-pm-domains.o
obj-$(CONFIG_MTK_MMSYS) += mtk-mmsys.o
diff --git a/drivers/soc/mediatek/mt8186-pm-domains.h b/drivers/soc/mediatek/mt8186-pm-domains.h
index 108af61854a3..fce86f79c505 100644
--- a/drivers/soc/mediatek/mt8186-pm-domains.h
+++ b/drivers/soc/mediatek/mt8186-pm-domains.h
@@ -304,7 +304,6 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8186[] = {
.ctl_offs = 0x9FC,
.pwr_sta_offs = 0x16C,
.pwr_sta2nd_offs = 0x170,
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
},
[MT8186_POWER_DOMAIN_ADSP_INFRA] = {
.name = "adsp_infra",
@@ -312,7 +311,6 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8186[] = {
.ctl_offs = 0x9F8,
.pwr_sta_offs = 0x16C,
.pwr_sta2nd_offs = 0x170,
- .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
},
[MT8186_POWER_DOMAIN_ADSP_TOP] = {
.name = "adsp_top",
@@ -332,7 +330,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8186[] = {
MT8186_TOP_AXI_PROT_EN_3_CLR,
MT8186_TOP_AXI_PROT_EN_3_STA),
},
- .caps = MTK_SCPD_SRAM_ISO | MTK_SCPD_KEEP_DEFAULT_OFF | MTK_SCPD_ACTIVE_WAKEUP,
+ .caps = MTK_SCPD_SRAM_ISO | MTK_SCPD_ACTIVE_WAKEUP,
},
};
diff --git a/drivers/soc/mediatek/mt8188-mmsys.h b/drivers/soc/mediatek/mt8188-mmsys.h
new file mode 100644
index 000000000000..448cc3761b43
--- /dev/null
+++ b/drivers/soc/mediatek/mt8188-mmsys.h
@@ -0,0 +1,149 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __SOC_MEDIATEK_MT8188_MMSYS_H
+#define __SOC_MEDIATEK_MT8188_MMSYS_H
+
+#define MT8188_VDO0_OVL_MOUT_EN 0xf14
+#define MT8188_MOUT_DISP_OVL0_TO_DISP_RDMA0 BIT(0)
+#define MT8188_MOUT_DISP_OVL0_TO_DISP_WDMA0 BIT(1)
+#define MT8188_MOUT_DISP_OVL0_TO_DISP_OVL1 BIT(2)
+#define MT8188_MOUT_DISP_OVL1_TO_DISP_RDMA1 BIT(4)
+#define MT8188_MOUT_DISP_OVL1_TO_DISP_WDMA1 BIT(5)
+#define MT8188_MOUT_DISP_OVL1_TO_DISP_OVL0 BIT(6)
+
+#define MT8188_VDO0_SEL_IN 0xf34
+#define MT8188_VDO0_SEL_OUT 0xf38
+
+#define MT8188_VDO0_DISP_RDMA_SEL 0xf40
+#define MT8188_SOUT_DISP_RDMA0_TO_MASK GENMASK(2, 0)
+#define MT8188_SOUT_DISP_RDMA0_TO_DISP_COLOR0 (0 << 0)
+#define MT8188_SOUT_DISP_RDMA0_TO_DISP_DSI0 (1 << 0)
+#define MT8188_SOUT_DISP_RDMA0_TO_DISP_DP_INTF0 (5 << 0)
+#define MT8188_SEL_IN_DISP_RDMA0_FROM_MASK GENMASK(8, 8)
+#define MT8188_SEL_IN_DISP_RDMA0_FROM_DISP_OVL0 (0 << 8)
+#define MT8188_SEL_IN_DISP_RDMA0_FROM_DISP_RSZ0 (1 << 8)
+
+
+#define MT8188_VDO0_DSI0_SEL_IN 0xf44
+#define MT8188_SEL_IN_DSI0_FROM_MASK BIT(0)
+#define MT8188_SEL_IN_DSI0_FROM_DSC_WRAP0_OUT (0 << 0)
+#define MT8188_SEL_IN_DSI0_FROM_DISP_DITHER0 (1 << 0)
+
+#define MT8188_VDO0_DP_INTF0_SEL_IN 0xf4C
+#define MT8188_SEL_IN_DP_INTF0_FROM_MASK GENMASK(2, 0)
+#define MT8188_SEL_IN_DP_INTF0_FROM_DSC_WRAP0C1_OUT (0 << 0)
+#define MT8188_SEL_IN_DP_INTF0_FROM_VPP_MERGE (1 << 0)
+#define MT8188_SEL_IN_DP_INTF0_FROM_DISP_DITHER0 (3 << 0)
+
+#define MT8188_VDO0_DISP_DITHER0_SEL_OUT 0xf58
+#define MT8188_SOUT_DISP_DITHER0_TO_MASK GENMASK(2, 0)
+#define MT8188_SOUT_DISP_DITHER0_TO_DSC_WRAP0_IN (0 << 0)
+#define MT8188_SOUT_DISP_DITHER0_TO_DSI0 (1 << 0)
+#define MT8188_SOUT_DISP_DITHER0_TO_VPP_MERGE0 (6 << 0)
+#define MT8188_SOUT_DISP_DITHER0_TO_DP_INTF0 (7 << 0)
+
+#define MT8188_VDO0_VPP_MERGE_SEL 0xf60
+#define MT8188_SEL_IN_VPP_MERGE_FROM_MASK GENMASK(1, 0)
+#define MT8188_SEL_IN_VPP_MERGE_FROM_DSC_WRAP0_OUT (0 << 0)
+#define MT8188_SEL_IN_VPP_MERGE_FROM_DITHER0_OUT (3 << 0)
+
+#define MT8188_SOUT_VPP_MERGE_TO_MASK GENMASK(6, 4)
+#define MT8188_SOUT_VPP_MERGE_TO_DSI1 (0 << 4)
+#define MT8188_SOUT_VPP_MERGE_TO_DP_INTF0 (1 << 4)
+#define MT8188_SOUT_VPP_MERGE_TO_SINA_VIRTUAL0 (2 << 4)
+#define MT8188_SOUT_VPP_MERGE_TO_DISP_WDMA1 (3 << 4)
+#define MT8188_SOUT_VPP_MERGE_TO_DSC_WRAP0_IN (4 << 4)
+#define MT8188_SOUT_VPP_MERGE_TO_DISP_WDMA0 (5 << 4)
+#define MT8188_SOUT_VPP_MERGE_TO_DSC_WRAP1_IN_MASK GENMASK(11, 11)
+#define MT8188_SOUT_VPP_MERGE_TO_DSC_WRAP1_IN (0 << 11)
+
+#define MT8188_VDO0_DSC_WARP_SEL 0xf64
+#define MT8188_SEL_IN_DSC_WRAP0C0_IN_FROM_MASK GENMASK(0, 0)
+#define MT8188_SEL_IN_DSC_WRAP0C0_IN_FROM_DISP_DITHER0 (0 << 0)
+#define MT8188_SEL_IN_DSC_WRAP0C0_IN_FROM_VPP_MERGE (1 << 0)
+#define MT8188_SOUT_DSC_WRAP0_OUT_TO_MASK GENMASK(19, 16)
+#define MT8188_SOUT_DSC_WRAP0_OUT_TO_DSI0 BIT(16)
+#define MT8188_SOUT_DSC_WRAP0_OUT_TO_SINB_VIRTUAL0 BIT(17)
+#define MT8188_SOUT_DSC_WRAP0_OUT_TO_VPP_MERGE BIT(18)
+#define MT8188_SOUT_DSC_WRAP0_OUT_TO_DISP_WDMA0 BIT(19)
+
+static const struct mtk_mmsys_routes mmsys_mt8188_routing_table[] = {
+ {
+ DDP_COMPONENT_OVL0, DDP_COMPONENT_RDMA0,
+ MT8188_VDO0_OVL_MOUT_EN, MT8188_MOUT_DISP_OVL0_TO_DISP_RDMA0,
+ MT8188_MOUT_DISP_OVL0_TO_DISP_RDMA0
+ }, {
+ DDP_COMPONENT_OVL0, DDP_COMPONENT_WDMA0,
+ MT8188_VDO0_OVL_MOUT_EN, MT8188_MOUT_DISP_OVL0_TO_DISP_WDMA0,
+ MT8188_MOUT_DISP_OVL0_TO_DISP_WDMA0
+ }, {
+ DDP_COMPONENT_OVL0, DDP_COMPONENT_RDMA0,
+ MT8188_VDO0_DISP_RDMA_SEL, MT8188_SEL_IN_DISP_RDMA0_FROM_MASK,
+ MT8188_SEL_IN_DISP_RDMA0_FROM_DISP_OVL0
+ }, {
+ DDP_COMPONENT_DITHER0, DDP_COMPONENT_DSI0,
+ MT8188_VDO0_DSI0_SEL_IN, MT8188_SEL_IN_DSI0_FROM_MASK,
+ MT8188_SEL_IN_DSI0_FROM_DISP_DITHER0
+ }, {
+ DDP_COMPONENT_DITHER0, DDP_COMPONENT_MERGE0,
+ MT8188_VDO0_VPP_MERGE_SEL, MT8188_SEL_IN_VPP_MERGE_FROM_MASK,
+ MT8188_SEL_IN_VPP_MERGE_FROM_DITHER0_OUT
+ }, {
+ DDP_COMPONENT_DITHER0, DDP_COMPONENT_DSC0,
+ MT8188_VDO0_DSC_WARP_SEL,
+ MT8188_SEL_IN_DSC_WRAP0C0_IN_FROM_MASK,
+ MT8188_SEL_IN_DSC_WRAP0C0_IN_FROM_DISP_DITHER0
+ }, {
+ DDP_COMPONENT_DITHER0, DDP_COMPONENT_DP_INTF0,
+ MT8188_VDO0_DP_INTF0_SEL_IN, MT8188_SEL_IN_DP_INTF0_FROM_MASK,
+ MT8188_SEL_IN_DP_INTF0_FROM_DISP_DITHER0
+ }, {
+ DDP_COMPONENT_DSC0, DDP_COMPONENT_MERGE0,
+ MT8188_VDO0_VPP_MERGE_SEL, MT8188_SEL_IN_VPP_MERGE_FROM_MASK,
+ MT8188_SEL_IN_VPP_MERGE_FROM_DSC_WRAP0_OUT
+ }, {
+ DDP_COMPONENT_DSC0, DDP_COMPONENT_DSI0,
+ MT8188_VDO0_DSI0_SEL_IN, MT8188_SEL_IN_DSI0_FROM_MASK,
+ MT8188_SEL_IN_DSI0_FROM_DSC_WRAP0_OUT
+ }, {
+ DDP_COMPONENT_RDMA0, DDP_COMPONENT_COLOR0,
+ MT8188_VDO0_DISP_RDMA_SEL, MT8188_SOUT_DISP_RDMA0_TO_MASK,
+ MT8188_SOUT_DISP_RDMA0_TO_DISP_COLOR0
+ }, {
+ DDP_COMPONENT_DITHER0, DDP_COMPONENT_DSI0,
+ MT8188_VDO0_DISP_DITHER0_SEL_OUT,
+ MT8188_SOUT_DISP_DITHER0_TO_MASK,
+ MT8188_SOUT_DISP_DITHER0_TO_DSI0
+ }, {
+ DDP_COMPONENT_DITHER0, DDP_COMPONENT_DP_INTF0,
+ MT8188_VDO0_DISP_DITHER0_SEL_OUT,
+ MT8188_SOUT_DISP_DITHER0_TO_MASK,
+ MT8188_SOUT_DISP_DITHER0_TO_DP_INTF0
+ }, {
+ DDP_COMPONENT_MERGE0, DDP_COMPONENT_DP_INTF0,
+ MT8188_VDO0_VPP_MERGE_SEL, MT8188_SOUT_VPP_MERGE_TO_MASK,
+ MT8188_SOUT_VPP_MERGE_TO_DP_INTF0
+ }, {
+ DDP_COMPONENT_MERGE0, DDP_COMPONENT_DPI0,
+ MT8188_VDO0_VPP_MERGE_SEL, MT8188_SOUT_VPP_MERGE_TO_MASK,
+ MT8188_SOUT_VPP_MERGE_TO_SINA_VIRTUAL0
+ }, {
+ DDP_COMPONENT_MERGE0, DDP_COMPONENT_WDMA0,
+ MT8188_VDO0_VPP_MERGE_SEL, MT8188_SOUT_VPP_MERGE_TO_MASK,
+ MT8188_SOUT_VPP_MERGE_TO_DISP_WDMA0
+ }, {
+ DDP_COMPONENT_MERGE0, DDP_COMPONENT_DSC0,
+ MT8188_VDO0_VPP_MERGE_SEL, MT8188_SOUT_VPP_MERGE_TO_MASK,
+ MT8188_SOUT_VPP_MERGE_TO_DSC_WRAP0_IN
+ }, {
+ DDP_COMPONENT_DSC0, DDP_COMPONENT_DSI0,
+ MT8188_VDO0_DSC_WARP_SEL, MT8188_SOUT_DSC_WRAP0_OUT_TO_MASK,
+ MT8188_SOUT_DSC_WRAP0_OUT_TO_DSI0
+ }, {
+ DDP_COMPONENT_DSC0, DDP_COMPONENT_MERGE0,
+ MT8188_VDO0_DSC_WARP_SEL, MT8188_SOUT_DSC_WRAP0_OUT_TO_MASK,
+ MT8188_SOUT_DSC_WRAP0_OUT_TO_VPP_MERGE
+ },
+};
+
+#endif /* __SOC_MEDIATEK_MT8188_MMSYS_H */
diff --git a/drivers/soc/mediatek/mt8188-pm-domains.h b/drivers/soc/mediatek/mt8188-pm-domains.h
new file mode 100644
index 000000000000..0692cb444ed0
--- /dev/null
+++ b/drivers/soc/mediatek/mt8188-pm-domains.h
@@ -0,0 +1,623 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Garmin Chang <garmin.chang@mediatek.com>
+ */
+
+#ifndef __SOC_MEDIATEK_MT8188_PM_DOMAINS_H
+#define __SOC_MEDIATEK_MT8188_PM_DOMAINS_H
+
+#include "mtk-pm-domains.h"
+#include <dt-bindings/power/mediatek,mt8188-power.h>
+
+/*
+ * MT8188 power domain support
+ */
+
+static const struct scpsys_domain_data scpsys_domain_data_mt8188[] = {
+ [MT8188_POWER_DOMAIN_MFG0] = {
+ .name = "mfg0",
+ .sta_mask = BIT(1),
+ .ctl_offs = 0x300,
+ .pwr_sta_offs = 0x174,
+ .pwr_sta2nd_offs = 0x178,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF | MTK_SCPD_DOMAIN_SUPPLY,
+ },
+ [MT8188_POWER_DOMAIN_MFG1] = {
+ .name = "mfg1",
+ .sta_mask = BIT(2),
+ .ctl_offs = 0x304,
+ .pwr_sta_offs = 0x174,
+ .pwr_sta2nd_offs = 0x178,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MFG1_STEP1,
+ MT8188_TOP_AXI_PROT_EN_SET,
+ MT8188_TOP_AXI_PROT_EN_CLR,
+ MT8188_TOP_AXI_PROT_EN_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_2_MFG1_STEP2,
+ MT8188_TOP_AXI_PROT_EN_2_SET,
+ MT8188_TOP_AXI_PROT_EN_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_2_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_1_MFG1_STEP3,
+ MT8188_TOP_AXI_PROT_EN_1_SET,
+ MT8188_TOP_AXI_PROT_EN_1_CLR,
+ MT8188_TOP_AXI_PROT_EN_1_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_2_MFG1_STEP4,
+ MT8188_TOP_AXI_PROT_EN_2_SET,
+ MT8188_TOP_AXI_PROT_EN_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_2_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MFG1_STEP5,
+ MT8188_TOP_AXI_PROT_EN_SET,
+ MT8188_TOP_AXI_PROT_EN_CLR,
+ MT8188_TOP_AXI_PROT_EN_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_MFG1_STEP6,
+ MT8188_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_SET,
+ MT8188_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_CLR,
+ MT8188_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_STA),
+ },
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF | MTK_SCPD_DOMAIN_SUPPLY,
+ },
+ [MT8188_POWER_DOMAIN_MFG2] = {
+ .name = "mfg2",
+ .sta_mask = BIT(3),
+ .ctl_offs = 0x308,
+ .pwr_sta_offs = 0x174,
+ .pwr_sta2nd_offs = 0x178,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8188_POWER_DOMAIN_MFG3] = {
+ .name = "mfg3",
+ .sta_mask = BIT(4),
+ .ctl_offs = 0x30C,
+ .pwr_sta_offs = 0x174,
+ .pwr_sta2nd_offs = 0x178,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8188_POWER_DOMAIN_MFG4] = {
+ .name = "mfg4",
+ .sta_mask = BIT(5),
+ .ctl_offs = 0x310,
+ .pwr_sta_offs = 0x174,
+ .pwr_sta2nd_offs = 0x178,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8188_POWER_DOMAIN_PEXTP_MAC_P0] = {
+ .name = "pextp_mac_p0",
+ .sta_mask = BIT(10),
+ .ctl_offs = 0x324,
+ .pwr_sta_offs = 0x174,
+ .pwr_sta2nd_offs = 0x178,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_PEXTP_MAC_P0_STEP1,
+ MT8188_TOP_AXI_PROT_EN_SET,
+ MT8188_TOP_AXI_PROT_EN_CLR,
+ MT8188_TOP_AXI_PROT_EN_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_PEXTP_MAC_P0_STEP2,
+ MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_SET,
+ MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_CLR,
+ MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_STA),
+ },
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8188_POWER_DOMAIN_PEXTP_PHY_TOP] = {
+ .name = "pextp_phy_top",
+ .sta_mask = BIT(12),
+ .ctl_offs = 0x328,
+ .pwr_sta_offs = 0x174,
+ .pwr_sta2nd_offs = 0x178,
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8188_POWER_DOMAIN_CSIRX_TOP] = {
+ .name = "pextp_csirx_top",
+ .sta_mask = BIT(17),
+ .ctl_offs = 0x3C4,
+ .pwr_sta_offs = 0x174,
+ .pwr_sta2nd_offs = 0x178,
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8188_POWER_DOMAIN_ETHER] = {
+ .name = "ether",
+ .sta_mask = BIT(1),
+ .ctl_offs = 0x338,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_ETHER_STEP1,
+ MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_SET,
+ MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_CLR,
+ MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_STA),
+ },
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF | MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT8188_POWER_DOMAIN_HDMI_TX] = {
+ .name = "hdmi_tx",
+ .sta_mask = BIT(18),
+ .ctl_offs = 0x37C,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_HDMI_TX_STEP1,
+ MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_SET,
+ MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_CLR,
+ MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_STA),
+ },
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF | MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT8188_POWER_DOMAIN_ADSP_AO] = {
+ .name = "adsp_ao",
+ .sta_mask = BIT(10),
+ .ctl_offs = 0x35C,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_2_ADSP_AO_STEP1,
+ MT8188_TOP_AXI_PROT_EN_2_SET,
+ MT8188_TOP_AXI_PROT_EN_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_2_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_2_ADSP_AO_STEP2,
+ MT8188_TOP_AXI_PROT_EN_2_SET,
+ MT8188_TOP_AXI_PROT_EN_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_2_STA),
+ },
+ .caps = MTK_SCPD_ALWAYS_ON,
+ },
+ [MT8188_POWER_DOMAIN_ADSP_INFRA] = {
+ .name = "adsp_infra",
+ .sta_mask = BIT(9),
+ .ctl_offs = 0x358,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_2_ADSP_INFRA_STEP1,
+ MT8188_TOP_AXI_PROT_EN_2_SET,
+ MT8188_TOP_AXI_PROT_EN_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_2_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_2_ADSP_INFRA_STEP2,
+ MT8188_TOP_AXI_PROT_EN_2_SET,
+ MT8188_TOP_AXI_PROT_EN_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_2_STA),
+ },
+ .caps = MTK_SCPD_SRAM_ISO | MTK_SCPD_ALWAYS_ON,
+ },
+ [MT8188_POWER_DOMAIN_ADSP] = {
+ .name = "adsp",
+ .sta_mask = BIT(8),
+ .ctl_offs = 0x354,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_2_ADSP_STEP1,
+ MT8188_TOP_AXI_PROT_EN_2_SET,
+ MT8188_TOP_AXI_PROT_EN_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_2_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_2_ADSP_STEP2,
+ MT8188_TOP_AXI_PROT_EN_2_SET,
+ MT8188_TOP_AXI_PROT_EN_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_2_STA),
+ },
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF | MTK_SCPD_SRAM_ISO | MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT8188_POWER_DOMAIN_AUDIO] = {
+ .name = "audio",
+ .sta_mask = BIT(6),
+ .ctl_offs = 0x34C,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_2_AUDIO_STEP1,
+ MT8188_TOP_AXI_PROT_EN_2_SET,
+ MT8188_TOP_AXI_PROT_EN_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_2_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_2_AUDIO_STEP2,
+ MT8188_TOP_AXI_PROT_EN_2_SET,
+ MT8188_TOP_AXI_PROT_EN_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_2_STA),
+ },
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF | MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT8188_POWER_DOMAIN_AUDIO_ASRC] = {
+ .name = "audio_asrc",
+ .sta_mask = BIT(7),
+ .ctl_offs = 0x350,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_2_AUDIO_ASRC_STEP1,
+ MT8188_TOP_AXI_PROT_EN_2_SET,
+ MT8188_TOP_AXI_PROT_EN_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_2_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_2_AUDIO_ASRC_STEP2,
+ MT8188_TOP_AXI_PROT_EN_2_SET,
+ MT8188_TOP_AXI_PROT_EN_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_2_STA),
+ },
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8188_POWER_DOMAIN_VPPSYS0] = {
+ .name = "vppsys0",
+ .sta_mask = BIT(11),
+ .ctl_offs = 0x360,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_VPPSYS0_STEP1,
+ MT8188_TOP_AXI_PROT_EN_SET,
+ MT8188_TOP_AXI_PROT_EN_CLR,
+ MT8188_TOP_AXI_PROT_EN_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_2_VPPSYS0_STEP2,
+ MT8188_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_2_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_VPPSYS0_STEP3,
+ MT8188_TOP_AXI_PROT_EN_SET,
+ MT8188_TOP_AXI_PROT_EN_CLR,
+ MT8188_TOP_AXI_PROT_EN_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_2_VPPSYS0_STEP4,
+ MT8188_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_2_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_VPPSYS0_STEP5,
+ MT8188_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_SET,
+ MT8188_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_CLR,
+ MT8188_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_STA),
+ },
+ },
+ [MT8188_POWER_DOMAIN_VDOSYS0] = {
+ .name = "vdosys0",
+ .sta_mask = BIT(13),
+ .ctl_offs = 0x368,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_VDOSYS0_STEP1,
+ MT8188_TOP_AXI_PROT_EN_MM_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_VDOSYS0_STEP2,
+ MT8188_TOP_AXI_PROT_EN_SET,
+ MT8188_TOP_AXI_PROT_EN_CLR,
+ MT8188_TOP_AXI_PROT_EN_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_VDOSYS0_STEP3,
+ MT8188_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_SET,
+ MT8188_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_CLR,
+ MT8188_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_STA),
+ },
+ },
+ [MT8188_POWER_DOMAIN_VDOSYS1] = {
+ .name = "vdosys1",
+ .sta_mask = BIT(14),
+ .ctl_offs = 0x36C,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_VDOSYS1_STEP1,
+ MT8188_TOP_AXI_PROT_EN_MM_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_VDOSYS1_STEP2,
+ MT8188_TOP_AXI_PROT_EN_MM_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_2_VDOSYS1_STEP3,
+ MT8188_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_2_STA),
+ },
+ },
+ [MT8188_POWER_DOMAIN_DP_TX] = {
+ .name = "dp_tx",
+ .sta_mask = BIT(16),
+ .ctl_offs = 0x374,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_DP_TX_STEP1,
+ MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_SET,
+ MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_CLR,
+ MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_STA),
+ },
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8188_POWER_DOMAIN_EDP_TX] = {
+ .name = "edp_tx",
+ .sta_mask = BIT(17),
+ .ctl_offs = 0x378,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_EDP_TX_STEP1,
+ MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_SET,
+ MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_CLR,
+ MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_STA),
+ },
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8188_POWER_DOMAIN_VPPSYS1] = {
+ .name = "vppsys1",
+ .sta_mask = BIT(12),
+ .ctl_offs = 0x364,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_VPPSYS1_STEP1,
+ MT8188_TOP_AXI_PROT_EN_MM_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_VPPSYS1_STEP2,
+ MT8188_TOP_AXI_PROT_EN_MM_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_2_VPPSYS1_STEP3,
+ MT8188_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_2_STA),
+ },
+ },
+ [MT8188_POWER_DOMAIN_WPE] = {
+ .name = "wpe",
+ .sta_mask = BIT(15),
+ .ctl_offs = 0x370,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_2_WPE_STEP1,
+ MT8188_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_2_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_2_WPE_STEP2,
+ MT8188_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_2_STA),
+ },
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8188_POWER_DOMAIN_VDEC0] = {
+ .name = "vdec0",
+ .sta_mask = BIT(19),
+ .ctl_offs = 0x380,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_VDEC0_STEP1,
+ MT8188_TOP_AXI_PROT_EN_MM_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_2_VDEC0_STEP2,
+ MT8188_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_2_STA),
+ },
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8188_POWER_DOMAIN_VDEC1] = {
+ .name = "vdec1",
+ .sta_mask = BIT(20),
+ .ctl_offs = 0x384,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_VDEC1_STEP1,
+ MT8188_TOP_AXI_PROT_EN_MM_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_VDEC1_STEP2,
+ MT8188_TOP_AXI_PROT_EN_MM_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_STA),
+ },
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8188_POWER_DOMAIN_VENC] = {
+ .name = "venc",
+ .sta_mask = BIT(22),
+ .ctl_offs = 0x38C,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_VENC_STEP1,
+ MT8188_TOP_AXI_PROT_EN_MM_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_VENC_STEP2,
+ MT8188_TOP_AXI_PROT_EN_MM_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_2_VENC_STEP3,
+ MT8188_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_2_STA),
+ },
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8188_POWER_DOMAIN_IMG_VCORE] = {
+ .name = "vcore",
+ .sta_mask = BIT(28),
+ .ctl_offs = 0x3A4,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_IMG_VCORE_STEP1,
+ MT8188_TOP_AXI_PROT_EN_MM_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_IMG_VCORE_STEP2,
+ MT8188_TOP_AXI_PROT_EN_MM_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_2_IMG_VCORE_STEP3,
+ MT8188_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_2_STA),
+ },
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF | MTK_SCPD_DOMAIN_SUPPLY,
+ },
+ [MT8188_POWER_DOMAIN_IMG_MAIN] = {
+ .name = "img_main",
+ .sta_mask = BIT(29),
+ .ctl_offs = 0x3A8,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_2_IMG_MAIN_STEP1,
+ MT8188_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_2_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_2_IMG_MAIN_STEP2,
+ MT8188_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_2_STA),
+ },
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8188_POWER_DOMAIN_DIP] = {
+ .name = "dip",
+ .sta_mask = BIT(30),
+ .ctl_offs = 0x3AC,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8188_POWER_DOMAIN_IPE] = {
+ .name = "ipe",
+ .sta_mask = BIT(31),
+ .ctl_offs = 0x3B0,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8188_POWER_DOMAIN_CAM_VCORE] = {
+ .name = "cam_vcore",
+ .sta_mask = BIT(27),
+ .ctl_offs = 0x3A0,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_CAM_VCORE_STEP1,
+ MT8188_TOP_AXI_PROT_EN_MM_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_2_CAM_VCORE_STEP2,
+ MT8188_TOP_AXI_PROT_EN_2_SET,
+ MT8188_TOP_AXI_PROT_EN_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_2_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_1_CAM_VCORE_STEP3,
+ MT8188_TOP_AXI_PROT_EN_1_SET,
+ MT8188_TOP_AXI_PROT_EN_1_CLR,
+ MT8188_TOP_AXI_PROT_EN_1_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_CAM_VCORE_STEP4,
+ MT8188_TOP_AXI_PROT_EN_MM_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_2_CAM_VCORE_STEP5,
+ MT8188_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_2_STA),
+ },
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF | MTK_SCPD_DOMAIN_SUPPLY,
+ },
+ [MT8188_POWER_DOMAIN_CAM_MAIN] = {
+ .name = "cam_main",
+ .sta_mask = BIT(24),
+ .ctl_offs = 0x394,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_2_CAM_MAIN_STEP1,
+ MT8188_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_2_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_2_CAM_MAIN_STEP2,
+ MT8188_TOP_AXI_PROT_EN_2_SET,
+ MT8188_TOP_AXI_PROT_EN_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_2_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_2_CAM_MAIN_STEP3,
+ MT8188_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_2_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_2_CAM_MAIN_STEP4,
+ MT8188_TOP_AXI_PROT_EN_2_SET,
+ MT8188_TOP_AXI_PROT_EN_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_2_STA),
+ },
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8188_POWER_DOMAIN_CAM_SUBA] = {
+ .name = "cam_suba",
+ .sta_mask = BIT(25),
+ .ctl_offs = 0x398,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8188_POWER_DOMAIN_CAM_SUBB] = {
+ .name = "cam_subb",
+ .sta_mask = BIT(26),
+ .ctl_offs = 0x39C,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+};
+
+static const struct scpsys_soc_data mt8188_scpsys_data = {
+ .domains_data = scpsys_domain_data_mt8188,
+ .num_domains = ARRAY_SIZE(scpsys_domain_data_mt8188),
+};
+
+#endif /* __SOC_MEDIATEK_MT8188_PM_DOMAINS_H */
diff --git a/drivers/soc/mediatek/mt8195-mmsys.h b/drivers/soc/mediatek/mt8195-mmsys.h
index abfe94a30248..a6652ae63431 100644
--- a/drivers/soc/mediatek/mt8195-mmsys.h
+++ b/drivers/soc/mediatek/mt8195-mmsys.h
@@ -75,6 +75,77 @@
#define MT8195_SOUT_DSC_WRAP1_OUT_TO_SINA_VIRTUAL0 (2 << 16)
#define MT8195_SOUT_DSC_WRAP1_OUT_TO_VPP_MERGE (3 << 16)
+#define MT8195_VDO1_SW0_RST_B 0x1d0
+#define MT8195_VDO1_MERGE0_ASYNC_CFG_WD 0xe30
+#define MT8195_VDO1_HDRBE_ASYNC_CFG_WD 0xe70
+#define MT8195_VDO1_HDR_TOP_CFG 0xd00
+#define MT8195_VDO1_MIXER_IN1_ALPHA 0xd30
+#define MT8195_VDO1_MIXER_IN1_PAD 0xd40
+
+#define MT8195_VDO1_VPP_MERGE0_P0_SEL_IN 0xf04
+#define MT8195_VPP_MERGE0_P0_SEL_IN_FROM_MDP_RDMA0 1
+
+#define MT8195_VDO1_VPP_MERGE0_P1_SEL_IN 0xf08
+#define MT8195_VPP_MERGE0_P1_SEL_IN_FROM_MDP_RDMA1 1
+
+#define MT8195_VDO1_DISP_DPI1_SEL_IN 0xf10
+#define MT8195_DISP_DPI1_SEL_IN_FROM_VPP_MERGE4_MOUT 0
+
+#define MT8195_VDO1_DISP_DP_INTF0_SEL_IN 0xf14
+#define MT8195_DISP_DP_INTF0_SEL_IN_FROM_VPP_MERGE4_MOUT 0
+
+#define MT8195_VDO1_MERGE4_SOUT_SEL 0xf18
+#define MT8195_MERGE4_SOUT_TO_DPI1_SEL 2
+#define MT8195_MERGE4_SOUT_TO_DP_INTF0_SEL 3
+
+#define MT8195_VDO1_MIXER_IN1_SEL_IN 0xf24
+#define MT8195_MIXER_IN1_SEL_IN_FROM_MERGE0_ASYNC_SOUT 1
+
+#define MT8195_VDO1_MIXER_IN2_SEL_IN 0xf28
+#define MT8195_MIXER_IN2_SEL_IN_FROM_MERGE1_ASYNC_SOUT 1
+
+#define MT8195_VDO1_MIXER_IN3_SEL_IN 0xf2c
+#define MT8195_MIXER_IN3_SEL_IN_FROM_MERGE2_ASYNC_SOUT 1
+
+#define MT8195_VDO1_MIXER_IN4_SEL_IN 0xf30
+#define MT8195_MIXER_IN4_SEL_IN_FROM_MERGE3_ASYNC_SOUT 1
+
+#define MT8195_VDO1_MIXER_OUT_SOUT_SEL 0xf34
+#define MT8195_MIXER_SOUT_TO_MERGE4_ASYNC_SEL 1
+
+#define MT8195_VDO1_VPP_MERGE1_P0_SEL_IN 0xf3c
+#define MT8195_VPP_MERGE1_P0_SEL_IN_FROM_MDP_RDMA2 1
+
+#define MT8195_VDO1_MERGE0_ASYNC_SOUT_SEL 0xf40
+#define MT8195_SOUT_TO_MIXER_IN1_SEL 1
+
+#define MT8195_VDO1_MERGE1_ASYNC_SOUT_SEL 0xf44
+#define MT8195_SOUT_TO_MIXER_IN2_SEL 1
+
+#define MT8195_VDO1_MERGE2_ASYNC_SOUT_SEL 0xf48
+#define MT8195_SOUT_TO_MIXER_IN3_SEL 1
+
+#define MT8195_VDO1_MERGE3_ASYNC_SOUT_SEL 0xf4c
+#define MT8195_SOUT_TO_MIXER_IN4_SEL 1
+
+#define MT8195_VDO1_MERGE4_ASYNC_SEL_IN 0xf50
+#define MT8195_MERGE4_ASYNC_SEL_IN_FROM_MIXER_OUT_SOUT 1
+
+#define MT8195_VDO1_MIXER_IN1_SOUT_SEL 0xf58
+#define MT8195_MIXER_IN1_SOUT_TO_DISP_MIXER 0
+
+#define MT8195_VDO1_MIXER_IN2_SOUT_SEL 0xf5c
+#define MT8195_MIXER_IN2_SOUT_TO_DISP_MIXER 0
+
+#define MT8195_VDO1_MIXER_IN3_SOUT_SEL 0xf60
+#define MT8195_MIXER_IN3_SOUT_TO_DISP_MIXER 0
+
+#define MT8195_VDO1_MIXER_IN4_SOUT_SEL 0xf64
+#define MT8195_MIXER_IN4_SOUT_TO_DISP_MIXER 0
+
+#define MT8195_VDO1_MIXER_SOUT_SEL_IN 0xf68
+#define MT8195_MIXER_SOUT_SEL_IN_FROM_DISP_MIXER 0
+
static const struct mtk_mmsys_routes mmsys_mt8195_routing_table[] = {
{
DDP_COMPONENT_OVL0, DDP_COMPONENT_RDMA0,
@@ -367,4 +438,79 @@ static const struct mtk_mmsys_routes mmsys_mt8195_routing_table[] = {
}
};
+static const struct mtk_mmsys_routes mmsys_mt8195_vdo1_routing_table[] = {
+ {
+ DDP_COMPONENT_MDP_RDMA0, DDP_COMPONENT_MERGE1,
+ MT8195_VDO1_VPP_MERGE0_P0_SEL_IN, GENMASK(0, 0),
+ MT8195_VPP_MERGE0_P0_SEL_IN_FROM_MDP_RDMA0
+ }, {
+ DDP_COMPONENT_MDP_RDMA1, DDP_COMPONENT_MERGE1,
+ MT8195_VDO1_VPP_MERGE0_P1_SEL_IN, GENMASK(0, 0),
+ MT8195_VPP_MERGE0_P1_SEL_IN_FROM_MDP_RDMA1
+ }, {
+ DDP_COMPONENT_MDP_RDMA2, DDP_COMPONENT_MERGE2,
+ MT8195_VDO1_VPP_MERGE1_P0_SEL_IN, GENMASK(0, 0),
+ MT8195_VPP_MERGE1_P0_SEL_IN_FROM_MDP_RDMA2
+ }, {
+ DDP_COMPONENT_MERGE1, DDP_COMPONENT_ETHDR_MIXER,
+ MT8195_VDO1_MERGE0_ASYNC_SOUT_SEL, GENMASK(1, 0),
+ MT8195_SOUT_TO_MIXER_IN1_SEL
+ }, {
+ DDP_COMPONENT_MERGE2, DDP_COMPONENT_ETHDR_MIXER,
+ MT8195_VDO1_MERGE1_ASYNC_SOUT_SEL, GENMASK(1, 0),
+ MT8195_SOUT_TO_MIXER_IN2_SEL
+ }, {
+ DDP_COMPONENT_MERGE3, DDP_COMPONENT_ETHDR_MIXER,
+ MT8195_VDO1_MERGE2_ASYNC_SOUT_SEL, GENMASK(1, 0),
+ MT8195_SOUT_TO_MIXER_IN3_SEL
+ }, {
+ DDP_COMPONENT_MERGE4, DDP_COMPONENT_ETHDR_MIXER,
+ MT8195_VDO1_MERGE3_ASYNC_SOUT_SEL, GENMASK(1, 0),
+ MT8195_SOUT_TO_MIXER_IN4_SEL
+ }, {
+ DDP_COMPONENT_ETHDR_MIXER, DDP_COMPONENT_MERGE5,
+ MT8195_VDO1_MIXER_OUT_SOUT_SEL, GENMASK(0, 0),
+ MT8195_MIXER_SOUT_TO_MERGE4_ASYNC_SEL
+ }, {
+ DDP_COMPONENT_MERGE1, DDP_COMPONENT_ETHDR_MIXER,
+ MT8195_VDO1_MIXER_IN1_SEL_IN, GENMASK(0, 0),
+ MT8195_MIXER_IN1_SEL_IN_FROM_MERGE0_ASYNC_SOUT
+ }, {
+ DDP_COMPONENT_MERGE2, DDP_COMPONENT_ETHDR_MIXER,
+ MT8195_VDO1_MIXER_IN2_SEL_IN, GENMASK(0, 0),
+ MT8195_MIXER_IN2_SEL_IN_FROM_MERGE1_ASYNC_SOUT
+ }, {
+ DDP_COMPONENT_MERGE3, DDP_COMPONENT_ETHDR_MIXER,
+ MT8195_VDO1_MIXER_IN3_SEL_IN, GENMASK(0, 0),
+ MT8195_MIXER_IN3_SEL_IN_FROM_MERGE2_ASYNC_SOUT
+ }, {
+ DDP_COMPONENT_MERGE4, DDP_COMPONENT_ETHDR_MIXER,
+ MT8195_VDO1_MIXER_IN4_SEL_IN, GENMASK(0, 0),
+ MT8195_MIXER_IN4_SEL_IN_FROM_MERGE3_ASYNC_SOUT
+ }, {
+ DDP_COMPONENT_ETHDR_MIXER, DDP_COMPONENT_MERGE5,
+ MT8195_VDO1_MIXER_SOUT_SEL_IN, GENMASK(2, 0),
+ MT8195_MIXER_SOUT_SEL_IN_FROM_DISP_MIXER
+ }, {
+ DDP_COMPONENT_ETHDR_MIXER, DDP_COMPONENT_MERGE5,
+ MT8195_VDO1_MERGE4_ASYNC_SEL_IN, GENMASK(2, 0),
+ MT8195_MERGE4_ASYNC_SEL_IN_FROM_MIXER_OUT_SOUT
+ }, {
+ DDP_COMPONENT_MERGE5, DDP_COMPONENT_DPI1,
+ MT8195_VDO1_DISP_DPI1_SEL_IN, GENMASK(1, 0),
+ MT8195_DISP_DPI1_SEL_IN_FROM_VPP_MERGE4_MOUT
+ }, {
+ DDP_COMPONENT_MERGE5, DDP_COMPONENT_DPI1,
+ MT8195_VDO1_MERGE4_SOUT_SEL, GENMASK(1, 0),
+ MT8195_MERGE4_SOUT_TO_DPI1_SEL
+ }, {
+ DDP_COMPONENT_MERGE5, DDP_COMPONENT_DP_INTF1,
+ MT8195_VDO1_DISP_DP_INTF0_SEL_IN, GENMASK(1, 0),
+ MT8195_DISP_DP_INTF0_SEL_IN_FROM_VPP_MERGE4_MOUT
+ }, {
+ DDP_COMPONENT_MERGE5, DDP_COMPONENT_DP_INTF1,
+ MT8195_VDO1_MERGE4_SOUT_SEL, GENMASK(1, 0),
+ MT8195_MERGE4_SOUT_TO_DP_INTF0_SEL
+ }
+};
#endif /* __SOC_MEDIATEK_MT8195_MMSYS_H */
diff --git a/drivers/soc/mediatek/mtk-devapc.c b/drivers/soc/mediatek/mtk-devapc.c
index fc13334db1b1..bad139cb117e 100644
--- a/drivers/soc/mediatek/mtk-devapc.c
+++ b/drivers/soc/mediatek/mtk-devapc.c
@@ -276,19 +276,14 @@ static int mtk_devapc_probe(struct platform_device *pdev)
if (!devapc_irq)
return -EINVAL;
- ctx->infra_clk = devm_clk_get(&pdev->dev, "devapc-infra-clock");
+ ctx->infra_clk = devm_clk_get_enabled(&pdev->dev, "devapc-infra-clock");
if (IS_ERR(ctx->infra_clk))
return -EINVAL;
- if (clk_prepare_enable(ctx->infra_clk))
- return -EINVAL;
-
ret = devm_request_irq(&pdev->dev, devapc_irq, devapc_violation_irq,
IRQF_TRIGGER_NONE, "devapc", ctx);
- if (ret) {
- clk_disable_unprepare(ctx->infra_clk);
+ if (ret)
return ret;
- }
platform_set_drvdata(pdev, ctx);
@@ -303,8 +298,6 @@ static int mtk_devapc_remove(struct platform_device *pdev)
stop_devapc(ctx);
- clk_disable_unprepare(ctx->infra_clk);
-
return 0;
}
diff --git a/drivers/soc/mediatek/mtk-mmsys.c b/drivers/soc/mediatek/mtk-mmsys.c
index f3431448e843..eb4c7e57896c 100644
--- a/drivers/soc/mediatek/mtk-mmsys.c
+++ b/drivers/soc/mediatek/mtk-mmsys.c
@@ -7,6 +7,7 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/io.h>
+#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/reset-controller.h>
@@ -16,10 +17,13 @@
#include "mt8167-mmsys.h"
#include "mt8183-mmsys.h"
#include "mt8186-mmsys.h"
+#include "mt8188-mmsys.h"
#include "mt8192-mmsys.h"
#include "mt8195-mmsys.h"
#include "mt8365-mmsys.h"
+#define MMSYS_SW_RESET_PER_REG 32
+
static const struct mtk_mmsys_driver_data mt2701_mmsys_driver_data = {
.clk_driver = "clk-mt2701-mm",
.routes = mmsys_default_routing_table,
@@ -51,6 +55,7 @@ static const struct mtk_mmsys_driver_data mt8173_mmsys_driver_data = {
.routes = mmsys_default_routing_table,
.num_routes = ARRAY_SIZE(mmsys_default_routing_table),
.sw0_rst_offset = MT8183_MMSYS_SW0_RST_B,
+ .num_resets = 32,
};
static const struct mtk_mmsys_driver_data mt8183_mmsys_driver_data = {
@@ -58,6 +63,7 @@ static const struct mtk_mmsys_driver_data mt8183_mmsys_driver_data = {
.routes = mmsys_mt8183_routing_table,
.num_routes = ARRAY_SIZE(mmsys_mt8183_routing_table),
.sw0_rst_offset = MT8183_MMSYS_SW0_RST_B,
+ .num_resets = 32,
};
static const struct mtk_mmsys_driver_data mt8186_mmsys_driver_data = {
@@ -65,6 +71,13 @@ static const struct mtk_mmsys_driver_data mt8186_mmsys_driver_data = {
.routes = mmsys_mt8186_routing_table,
.num_routes = ARRAY_SIZE(mmsys_mt8186_routing_table),
.sw0_rst_offset = MT8186_MMSYS_SW0_RST_B,
+ .num_resets = 32,
+};
+
+static const struct mtk_mmsys_driver_data mt8188_vdosys0_driver_data = {
+ .clk_driver = "clk-mt8188-vdo0",
+ .routes = mmsys_mt8188_routing_table,
+ .num_routes = ARRAY_SIZE(mmsys_mt8188_routing_table),
};
static const struct mtk_mmsys_driver_data mt8192_mmsys_driver_data = {
@@ -72,6 +85,7 @@ static const struct mtk_mmsys_driver_data mt8192_mmsys_driver_data = {
.routes = mmsys_mt8192_routing_table,
.num_routes = ARRAY_SIZE(mmsys_mt8192_routing_table),
.sw0_rst_offset = MT8186_MMSYS_SW0_RST_B,
+ .num_resets = 32,
};
static const struct mtk_mmsys_driver_data mt8195_vdosys0_driver_data = {
@@ -80,6 +94,24 @@ static const struct mtk_mmsys_driver_data mt8195_vdosys0_driver_data = {
.num_routes = ARRAY_SIZE(mmsys_mt8195_routing_table),
};
+static const struct mtk_mmsys_driver_data mt8195_vdosys1_driver_data = {
+ .clk_driver = "clk-mt8195-vdo1",
+ .routes = mmsys_mt8195_vdo1_routing_table,
+ .num_routes = ARRAY_SIZE(mmsys_mt8195_vdo1_routing_table),
+ .sw0_rst_offset = MT8195_VDO1_SW0_RST_B,
+ .num_resets = 64,
+};
+
+static const struct mtk_mmsys_driver_data mt8195_vppsys0_driver_data = {
+ .clk_driver = "clk-mt8195-vpp0",
+ .is_vppsys = true,
+};
+
+static const struct mtk_mmsys_driver_data mt8195_vppsys1_driver_data = {
+ .clk_driver = "clk-mt8195-vpp1",
+ .is_vppsys = true,
+};
+
static const struct mtk_mmsys_driver_data mt8365_mmsys_driver_data = {
.clk_driver = "clk-mt8365-mm",
.routes = mt8365_mmsys_routing_table,
@@ -91,24 +123,44 @@ struct mtk_mmsys {
const struct mtk_mmsys_driver_data *data;
spinlock_t lock; /* protects mmsys_sw_rst_b reg */
struct reset_controller_dev rcdev;
+ struct cmdq_client_reg cmdq_base;
};
+static void mtk_mmsys_update_bits(struct mtk_mmsys *mmsys, u32 offset, u32 mask, u32 val,
+ struct cmdq_pkt *cmdq_pkt)
+{
+ u32 tmp;
+
+#if IS_REACHABLE(CONFIG_MTK_CMDQ)
+ if (cmdq_pkt) {
+ if (mmsys->cmdq_base.size == 0) {
+ pr_err("mmsys lose gce property, failed to update mmsys bits with cmdq");
+ return;
+ }
+ cmdq_pkt_write_mask(cmdq_pkt, mmsys->cmdq_base.subsys,
+ mmsys->cmdq_base.offset + offset, val,
+ mask);
+ return;
+ }
+#endif
+
+ tmp = readl_relaxed(mmsys->regs + offset);
+ tmp = (tmp & ~mask) | (val & mask);
+ writel_relaxed(tmp, mmsys->regs + offset);
+}
+
void mtk_mmsys_ddp_connect(struct device *dev,
enum mtk_ddp_comp_id cur,
enum mtk_ddp_comp_id next)
{
struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
const struct mtk_mmsys_routes *routes = mmsys->data->routes;
- u32 reg;
int i;
for (i = 0; i < mmsys->data->num_routes; i++)
- if (cur == routes[i].from_comp && next == routes[i].to_comp) {
- reg = readl_relaxed(mmsys->regs + routes[i].addr);
- reg &= ~routes[i].mask;
- reg |= routes[i].val;
- writel_relaxed(reg, mmsys->regs + routes[i].addr);
- }
+ if (cur == routes[i].from_comp && next == routes[i].to_comp)
+ mtk_mmsys_update_bits(mmsys, routes[i].addr, routes[i].mask,
+ routes[i].val, NULL);
}
EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_connect);
@@ -118,26 +170,51 @@ void mtk_mmsys_ddp_disconnect(struct device *dev,
{
struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
const struct mtk_mmsys_routes *routes = mmsys->data->routes;
- u32 reg;
int i;
for (i = 0; i < mmsys->data->num_routes; i++)
- if (cur == routes[i].from_comp && next == routes[i].to_comp) {
- reg = readl_relaxed(mmsys->regs + routes[i].addr);
- reg &= ~routes[i].mask;
- writel_relaxed(reg, mmsys->regs + routes[i].addr);
- }
+ if (cur == routes[i].from_comp && next == routes[i].to_comp)
+ mtk_mmsys_update_bits(mmsys, routes[i].addr, routes[i].mask, 0, NULL);
}
EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_disconnect);
-static void mtk_mmsys_update_bits(struct mtk_mmsys *mmsys, u32 offset, u32 mask, u32 val)
+void mtk_mmsys_merge_async_config(struct device *dev, int idx, int width, int height,
+ struct cmdq_pkt *cmdq_pkt)
{
- u32 tmp;
+ mtk_mmsys_update_bits(dev_get_drvdata(dev), MT8195_VDO1_MERGE0_ASYNC_CFG_WD + 0x10 * idx,
+ ~0, height << 16 | width, cmdq_pkt);
+}
+EXPORT_SYMBOL_GPL(mtk_mmsys_merge_async_config);
- tmp = readl_relaxed(mmsys->regs + offset);
- tmp = (tmp & ~mask) | val;
- writel_relaxed(tmp, mmsys->regs + offset);
+void mtk_mmsys_hdr_config(struct device *dev, int be_width, int be_height,
+ struct cmdq_pkt *cmdq_pkt)
+{
+ mtk_mmsys_update_bits(dev_get_drvdata(dev), MT8195_VDO1_HDRBE_ASYNC_CFG_WD, ~0,
+ be_height << 16 | be_width, cmdq_pkt);
}
+EXPORT_SYMBOL_GPL(mtk_mmsys_hdr_config);
+
+void mtk_mmsys_mixer_in_config(struct device *dev, int idx, bool alpha_sel, u16 alpha,
+ u8 mode, u32 biwidth, struct cmdq_pkt *cmdq_pkt)
+{
+ struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
+
+ mtk_mmsys_update_bits(mmsys, MT8195_VDO1_MIXER_IN1_ALPHA + (idx - 1) * 4, ~0,
+ alpha << 16 | alpha, cmdq_pkt);
+ mtk_mmsys_update_bits(mmsys, MT8195_VDO1_HDR_TOP_CFG, BIT(19 + idx),
+ alpha_sel << (19 + idx), cmdq_pkt);
+ mtk_mmsys_update_bits(mmsys, MT8195_VDO1_MIXER_IN1_PAD + (idx - 1) * 4,
+ GENMASK(31, 16) | GENMASK(1, 0), biwidth << 16 | mode, cmdq_pkt);
+}
+EXPORT_SYMBOL_GPL(mtk_mmsys_mixer_in_config);
+
+void mtk_mmsys_mixer_in_channel_swap(struct device *dev, int idx, bool channel_swap,
+ struct cmdq_pkt *cmdq_pkt)
+{
+ mtk_mmsys_update_bits(dev_get_drvdata(dev), MT8195_VDO1_MIXER_IN1_PAD + (idx - 1) * 4,
+ BIT(4), channel_swap << 4, cmdq_pkt);
+}
+EXPORT_SYMBOL_GPL(mtk_mmsys_mixer_in_channel_swap);
void mtk_mmsys_ddp_dpi_fmt_config(struct device *dev, u32 val)
{
@@ -146,20 +223,20 @@ void mtk_mmsys_ddp_dpi_fmt_config(struct device *dev, u32 val)
switch (val) {
case MTK_DPI_RGB888_SDR_CON:
mtk_mmsys_update_bits(mmsys, MT8186_MMSYS_DPI_OUTPUT_FORMAT,
- MT8186_DPI_FORMAT_MASK, MT8186_DPI_RGB888_SDR_CON);
+ MT8186_DPI_FORMAT_MASK, MT8186_DPI_RGB888_SDR_CON, NULL);
break;
case MTK_DPI_RGB565_SDR_CON:
mtk_mmsys_update_bits(mmsys, MT8186_MMSYS_DPI_OUTPUT_FORMAT,
- MT8186_DPI_FORMAT_MASK, MT8186_DPI_RGB565_SDR_CON);
+ MT8186_DPI_FORMAT_MASK, MT8186_DPI_RGB565_SDR_CON, NULL);
break;
case MTK_DPI_RGB565_DDR_CON:
mtk_mmsys_update_bits(mmsys, MT8186_MMSYS_DPI_OUTPUT_FORMAT,
- MT8186_DPI_FORMAT_MASK, MT8186_DPI_RGB565_DDR_CON);
+ MT8186_DPI_FORMAT_MASK, MT8186_DPI_RGB565_DDR_CON, NULL);
break;
case MTK_DPI_RGB888_DDR_CON:
default:
mtk_mmsys_update_bits(mmsys, MT8186_MMSYS_DPI_OUTPUT_FORMAT,
- MT8186_DPI_FORMAT_MASK, MT8186_DPI_RGB888_DDR_CON);
+ MT8186_DPI_FORMAT_MASK, MT8186_DPI_RGB888_DDR_CON, NULL);
break;
}
}
@@ -170,18 +247,19 @@ static int mtk_mmsys_reset_update(struct reset_controller_dev *rcdev, unsigned l
{
struct mtk_mmsys *mmsys = container_of(rcdev, struct mtk_mmsys, rcdev);
unsigned long flags;
+ u32 offset;
u32 reg;
- spin_lock_irqsave(&mmsys->lock, flags);
+ offset = (id / MMSYS_SW_RESET_PER_REG) * sizeof(u32);
+ id = id % MMSYS_SW_RESET_PER_REG;
+ reg = mmsys->data->sw0_rst_offset + offset;
- reg = readl_relaxed(mmsys->regs + mmsys->data->sw0_rst_offset);
+ spin_lock_irqsave(&mmsys->lock, flags);
if (assert)
- reg &= ~BIT(id);
+ mtk_mmsys_update_bits(mmsys, reg, BIT(id), 0, NULL);
else
- reg |= BIT(id);
-
- writel_relaxed(reg, mmsys->regs + mmsys->data->sw0_rst_offset);
+ mtk_mmsys_update_bits(mmsys, reg, BIT(id), BIT(id), NULL);
spin_unlock_irqrestore(&mmsys->lock, flags);
@@ -236,19 +314,28 @@ static int mtk_mmsys_probe(struct platform_device *pdev)
return ret;
}
- spin_lock_init(&mmsys->lock);
+ mmsys->data = of_device_get_match_data(&pdev->dev);
- mmsys->rcdev.owner = THIS_MODULE;
- mmsys->rcdev.nr_resets = 32;
- mmsys->rcdev.ops = &mtk_mmsys_reset_ops;
- mmsys->rcdev.of_node = pdev->dev.of_node;
- ret = devm_reset_controller_register(&pdev->dev, &mmsys->rcdev);
- if (ret) {
- dev_err(&pdev->dev, "Couldn't register mmsys reset controller: %d\n", ret);
- return ret;
+ if (mmsys->data->num_resets > 0) {
+ spin_lock_init(&mmsys->lock);
+
+ mmsys->rcdev.owner = THIS_MODULE;
+ mmsys->rcdev.nr_resets = mmsys->data->num_resets;
+ mmsys->rcdev.ops = &mtk_mmsys_reset_ops;
+ mmsys->rcdev.of_node = pdev->dev.of_node;
+ ret = devm_reset_controller_register(&pdev->dev, &mmsys->rcdev);
+ if (ret) {
+ dev_err(&pdev->dev, "Couldn't register mmsys reset controller: %d\n", ret);
+ return ret;
+ }
}
- mmsys->data = of_device_get_match_data(&pdev->dev);
+#if IS_REACHABLE(CONFIG_MTK_CMDQ)
+ ret = cmdq_dev_get_client_reg(dev, &mmsys->cmdq_base, 0);
+ if (ret)
+ dev_dbg(dev, "No mediatek,gce-client-reg!\n");
+#endif
+
platform_set_drvdata(pdev, mmsys);
clks = platform_device_register_data(&pdev->dev, mmsys->data->clk_driver,
@@ -256,6 +343,9 @@ static int mtk_mmsys_probe(struct platform_device *pdev)
if (IS_ERR(clks))
return PTR_ERR(clks);
+ if (mmsys->data->is_vppsys)
+ goto out_probe_done;
+
drm = platform_device_register_data(&pdev->dev, "mediatek-drm",
PLATFORM_DEVID_AUTO, NULL, 0);
if (IS_ERR(drm)) {
@@ -263,6 +353,7 @@ static int mtk_mmsys_probe(struct platform_device *pdev)
return PTR_ERR(drm);
}
+out_probe_done:
return 0;
}
@@ -300,6 +391,10 @@ static const struct of_device_id of_match_mtk_mmsys[] = {
.data = &mt8186_mmsys_driver_data,
},
{
+ .compatible = "mediatek,mt8188-vdosys0",
+ .data = &mt8188_vdosys0_driver_data,
+ },
+ {
.compatible = "mediatek,mt8192-mmsys",
.data = &mt8192_mmsys_driver_data,
},
@@ -312,6 +407,18 @@ static const struct of_device_id of_match_mtk_mmsys[] = {
.data = &mt8195_vdosys0_driver_data,
},
{
+ .compatible = "mediatek,mt8195-vdosys1",
+ .data = &mt8195_vdosys1_driver_data,
+ },
+ {
+ .compatible = "mediatek,mt8195-vppsys0",
+ .data = &mt8195_vppsys0_driver_data,
+ },
+ {
+ .compatible = "mediatek,mt8195-vppsys1",
+ .data = &mt8195_vppsys1_driver_data,
+ },
+ {
.compatible = "mediatek,mt8365-mmsys",
.data = &mt8365_mmsys_driver_data,
},
@@ -326,4 +433,19 @@ static struct platform_driver mtk_mmsys_drv = {
.probe = mtk_mmsys_probe,
};
-builtin_platform_driver(mtk_mmsys_drv);
+static int __init mtk_mmsys_init(void)
+{
+ return platform_driver_register(&mtk_mmsys_drv);
+}
+
+static void __exit mtk_mmsys_exit(void)
+{
+ platform_driver_unregister(&mtk_mmsys_drv);
+}
+
+module_init(mtk_mmsys_init);
+module_exit(mtk_mmsys_exit);
+
+MODULE_AUTHOR("Yongqiang Niu <yongqiang.niu@mediatek.com>");
+MODULE_DESCRIPTION("MediaTek SoC MMSYS driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/mediatek/mtk-mmsys.h b/drivers/soc/mediatek/mtk-mmsys.h
index 77f37f8c715b..56f8cc3a97b7 100644
--- a/drivers/soc/mediatek/mtk-mmsys.h
+++ b/drivers/soc/mediatek/mtk-mmsys.h
@@ -91,6 +91,8 @@ struct mtk_mmsys_driver_data {
const struct mtk_mmsys_routes *routes;
const unsigned int num_routes;
const u16 sw0_rst_offset;
+ const u32 num_resets;
+ const bool is_vppsys;
};
/*
diff --git a/drivers/soc/mediatek/mtk-mutex.c b/drivers/soc/mediatek/mtk-mutex.c
index c1a33d52038e..c5b1b42303ac 100644
--- a/drivers/soc/mediatek/mtk-mutex.c
+++ b/drivers/soc/mediatek/mtk-mutex.c
@@ -116,6 +116,21 @@
#define MT8173_MUTEX_MOD_DISP_PWM1 24
#define MT8173_MUTEX_MOD_DISP_OD 25
+#define MT8188_MUTEX_MOD_DISP_OVL0 0
+#define MT8188_MUTEX_MOD_DISP_WDMA0 1
+#define MT8188_MUTEX_MOD_DISP_RDMA0 2
+#define MT8188_MUTEX_MOD_DISP_COLOR0 3
+#define MT8188_MUTEX_MOD_DISP_CCORR0 4
+#define MT8188_MUTEX_MOD_DISP_AAL0 5
+#define MT8188_MUTEX_MOD_DISP_GAMMA0 6
+#define MT8188_MUTEX_MOD_DISP_DITHER0 7
+#define MT8188_MUTEX_MOD_DISP_DSI0 8
+#define MT8188_MUTEX_MOD_DISP_DSC_WRAP0_CORE0 9
+#define MT8188_MUTEX_MOD_DISP_VPP_MERGE 20
+#define MT8188_MUTEX_MOD_DISP_DP_INTF0 21
+#define MT8188_MUTEX_MOD_DISP_POSTMASK0 24
+#define MT8188_MUTEX_MOD2_DISP_PWM0 33
+
#define MT8195_MUTEX_MOD_DISP_OVL0 0
#define MT8195_MUTEX_MOD_DISP_WDMA0 1
#define MT8195_MUTEX_MOD_DISP_RDMA0 2
@@ -130,6 +145,24 @@
#define MT8195_MUTEX_MOD_DISP_DP_INTF0 21
#define MT8195_MUTEX_MOD_DISP_PWM0 27
+#define MT8195_MUTEX_MOD_DISP1_MDP_RDMA0 0
+#define MT8195_MUTEX_MOD_DISP1_MDP_RDMA1 1
+#define MT8195_MUTEX_MOD_DISP1_MDP_RDMA2 2
+#define MT8195_MUTEX_MOD_DISP1_MDP_RDMA3 3
+#define MT8195_MUTEX_MOD_DISP1_MDP_RDMA4 4
+#define MT8195_MUTEX_MOD_DISP1_MDP_RDMA5 5
+#define MT8195_MUTEX_MOD_DISP1_MDP_RDMA6 6
+#define MT8195_MUTEX_MOD_DISP1_MDP_RDMA7 7
+#define MT8195_MUTEX_MOD_DISP1_VPP_MERGE0 8
+#define MT8195_MUTEX_MOD_DISP1_VPP_MERGE1 9
+#define MT8195_MUTEX_MOD_DISP1_VPP_MERGE2 10
+#define MT8195_MUTEX_MOD_DISP1_VPP_MERGE3 11
+#define MT8195_MUTEX_MOD_DISP1_VPP_MERGE4 12
+#define MT8195_MUTEX_MOD_DISP1_DISP_MIXER 18
+#define MT8195_MUTEX_MOD_DISP1_DPI0 25
+#define MT8195_MUTEX_MOD_DISP1_DPI1 26
+#define MT8195_MUTEX_MOD_DISP1_DP_INTF0 27
+
#define MT8365_MUTEX_MOD_DISP_OVL0 7
#define MT8365_MUTEX_MOD_DISP_OVL0_2L 8
#define MT8365_MUTEX_MOD_DISP_RDMA0 9
@@ -180,6 +213,8 @@
#define MT8167_MUTEX_SOF_DPI1 3
#define MT8183_MUTEX_SOF_DSI0 1
#define MT8183_MUTEX_SOF_DPI0 2
+#define MT8188_MUTEX_SOF_DSI0 1
+#define MT8188_MUTEX_SOF_DP_INTF0 3
#define MT8195_MUTEX_SOF_DSI0 1
#define MT8195_MUTEX_SOF_DSI1 2
#define MT8195_MUTEX_SOF_DP_INTF0 3
@@ -189,6 +224,8 @@
#define MT8183_MUTEX_EOF_DSI0 (MT8183_MUTEX_SOF_DSI0 << 6)
#define MT8183_MUTEX_EOF_DPI0 (MT8183_MUTEX_SOF_DPI0 << 6)
+#define MT8188_MUTEX_EOF_DSI0 (MT8188_MUTEX_SOF_DSI0 << 7)
+#define MT8188_MUTEX_EOF_DP_INTF0 (MT8188_MUTEX_SOF_DP_INTF0 << 7)
#define MT8195_MUTEX_EOF_DSI0 (MT8195_MUTEX_SOF_DSI0 << 7)
#define MT8195_MUTEX_EOF_DSI1 (MT8195_MUTEX_SOF_DSI1 << 7)
#define MT8195_MUTEX_EOF_DP_INTF0 (MT8195_MUTEX_SOF_DP_INTF0 << 7)
@@ -344,6 +381,23 @@ static const unsigned int mt8186_mdp_mutex_table_mod[MUTEX_MOD_IDX_MAX] = {
[MUTEX_MOD_IDX_MDP_COLOR0] = MT8186_MUTEX_MOD_MDP_COLOR0,
};
+static const unsigned int mt8188_mutex_mod[DDP_COMPONENT_ID_MAX] = {
+ [DDP_COMPONENT_OVL0] = MT8188_MUTEX_MOD_DISP_OVL0,
+ [DDP_COMPONENT_WDMA0] = MT8188_MUTEX_MOD_DISP_WDMA0,
+ [DDP_COMPONENT_RDMA0] = MT8188_MUTEX_MOD_DISP_RDMA0,
+ [DDP_COMPONENT_COLOR0] = MT8188_MUTEX_MOD_DISP_COLOR0,
+ [DDP_COMPONENT_CCORR] = MT8188_MUTEX_MOD_DISP_CCORR0,
+ [DDP_COMPONENT_AAL0] = MT8188_MUTEX_MOD_DISP_AAL0,
+ [DDP_COMPONENT_GAMMA] = MT8188_MUTEX_MOD_DISP_GAMMA0,
+ [DDP_COMPONENT_POSTMASK0] = MT8188_MUTEX_MOD_DISP_POSTMASK0,
+ [DDP_COMPONENT_DITHER0] = MT8188_MUTEX_MOD_DISP_DITHER0,
+ [DDP_COMPONENT_MERGE0] = MT8188_MUTEX_MOD_DISP_VPP_MERGE,
+ [DDP_COMPONENT_DSC0] = MT8188_MUTEX_MOD_DISP_DSC_WRAP0_CORE0,
+ [DDP_COMPONENT_DSI0] = MT8188_MUTEX_MOD_DISP_DSI0,
+ [DDP_COMPONENT_PWM0] = MT8188_MUTEX_MOD2_DISP_PWM0,
+ [DDP_COMPONENT_DP_INTF0] = MT8188_MUTEX_MOD_DISP_DP_INTF0,
+};
+
static const unsigned int mt8192_mutex_mod[DDP_COMPONENT_ID_MAX] = {
[DDP_COMPONENT_AAL0] = MT8192_MUTEX_MOD_DISP_AAL0,
[DDP_COMPONENT_CCORR] = MT8192_MUTEX_MOD_DISP_CCORR0,
@@ -372,6 +426,21 @@ static const unsigned int mt8195_mutex_mod[DDP_COMPONENT_ID_MAX] = {
[DDP_COMPONENT_DSI0] = MT8195_MUTEX_MOD_DISP_DSI0,
[DDP_COMPONENT_PWM0] = MT8195_MUTEX_MOD_DISP_PWM0,
[DDP_COMPONENT_DP_INTF0] = MT8195_MUTEX_MOD_DISP_DP_INTF0,
+ [DDP_COMPONENT_MDP_RDMA0] = MT8195_MUTEX_MOD_DISP1_MDP_RDMA0,
+ [DDP_COMPONENT_MDP_RDMA1] = MT8195_MUTEX_MOD_DISP1_MDP_RDMA1,
+ [DDP_COMPONENT_MDP_RDMA2] = MT8195_MUTEX_MOD_DISP1_MDP_RDMA2,
+ [DDP_COMPONENT_MDP_RDMA3] = MT8195_MUTEX_MOD_DISP1_MDP_RDMA3,
+ [DDP_COMPONENT_MDP_RDMA4] = MT8195_MUTEX_MOD_DISP1_MDP_RDMA4,
+ [DDP_COMPONENT_MDP_RDMA5] = MT8195_MUTEX_MOD_DISP1_MDP_RDMA5,
+ [DDP_COMPONENT_MDP_RDMA6] = MT8195_MUTEX_MOD_DISP1_MDP_RDMA6,
+ [DDP_COMPONENT_MDP_RDMA7] = MT8195_MUTEX_MOD_DISP1_MDP_RDMA7,
+ [DDP_COMPONENT_MERGE1] = MT8195_MUTEX_MOD_DISP1_VPP_MERGE0,
+ [DDP_COMPONENT_MERGE2] = MT8195_MUTEX_MOD_DISP1_VPP_MERGE1,
+ [DDP_COMPONENT_MERGE3] = MT8195_MUTEX_MOD_DISP1_VPP_MERGE2,
+ [DDP_COMPONENT_MERGE4] = MT8195_MUTEX_MOD_DISP1_VPP_MERGE3,
+ [DDP_COMPONENT_ETHDR_MIXER] = MT8195_MUTEX_MOD_DISP1_DISP_MIXER,
+ [DDP_COMPONENT_MERGE5] = MT8195_MUTEX_MOD_DISP1_VPP_MERGE4,
+ [DDP_COMPONENT_DP_INTF1] = MT8195_MUTEX_MOD_DISP1_DP_INTF0,
};
static const unsigned int mt8365_mutex_mod[DDP_COMPONENT_ID_MAX] = {
@@ -435,6 +504,14 @@ static const unsigned int mt8186_mutex_sof[MUTEX_SOF_DSI3 + 1] = {
* but also detect the error at end of frame(EAEOF) when EOF signal
* arrives.
*/
+static const unsigned int mt8188_mutex_sof[DDP_MUTEX_SOF_MAX] = {
+ [MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE,
+ [MUTEX_SOF_DSI0] =
+ MT8188_MUTEX_SOF_DSI0 | MT8188_MUTEX_EOF_DSI0,
+ [MUTEX_SOF_DP_INTF0] =
+ MT8188_MUTEX_SOF_DP_INTF0 | MT8188_MUTEX_EOF_DP_INTF0,
+};
+
static const unsigned int mt8195_mutex_sof[DDP_MUTEX_SOF_MAX] = {
[MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE,
[MUTEX_SOF_DSI0] = MT8195_MUTEX_SOF_DSI0 | MT8195_MUTEX_EOF_DSI0,
@@ -505,6 +582,13 @@ static const struct mtk_mutex_data mt8186_mutex_driver_data = {
.mutex_sof_reg = MT8183_MUTEX0_SOF0,
};
+static const struct mtk_mutex_data mt8188_mutex_driver_data = {
+ .mutex_mod = mt8188_mutex_mod,
+ .mutex_sof = mt8188_mutex_sof,
+ .mutex_mod_reg = MT8183_MUTEX0_MOD0,
+ .mutex_sof_reg = MT8183_MUTEX0_SOF0,
+};
+
static const struct mtk_mutex_data mt8192_mutex_driver_data = {
.mutex_mod = mt8192_mutex_mod,
.mutex_sof = mt8183_mutex_sof,
@@ -602,6 +686,9 @@ void mtk_mutex_add_comp(struct mtk_mutex *mutex,
case DDP_COMPONENT_DP_INTF0:
sof_id = MUTEX_SOF_DP_INTF0;
break;
+ case DDP_COMPONENT_DP_INTF1:
+ sof_id = MUTEX_SOF_DP_INTF1;
+ break;
default:
if (mtx->data->mutex_mod[id] < 32) {
offset = DISP_REG_MUTEX_MOD(mtx->data->mutex_mod_reg,
@@ -642,6 +729,7 @@ void mtk_mutex_remove_comp(struct mtk_mutex *mutex,
case DDP_COMPONENT_DPI0:
case DDP_COMPONENT_DPI1:
case DDP_COMPONENT_DP_INTF0:
+ case DDP_COMPONENT_DP_INTF1:
writel_relaxed(MUTEX_SOF_SINGLE_MODE,
mtx->regs +
DISP_REG_MUTEX_SOF(mtx->data->mutex_sof_reg,
@@ -832,11 +920,6 @@ static int mtk_mutex_probe(struct platform_device *pdev)
return 0;
}
-static int mtk_mutex_remove(struct platform_device *pdev)
-{
- return 0;
-}
-
static const struct of_device_id mutex_driver_dt_match[] = {
{ .compatible = "mediatek,mt2701-disp-mutex",
.data = &mt2701_mutex_driver_data},
@@ -854,6 +937,8 @@ static const struct of_device_id mutex_driver_dt_match[] = {
.data = &mt8186_mutex_driver_data},
{ .compatible = "mediatek,mt8186-mdp3-mutex",
.data = &mt8186_mdp_mutex_driver_data},
+ { .compatible = "mediatek,mt8188-disp-mutex",
+ .data = &mt8188_mutex_driver_data},
{ .compatible = "mediatek,mt8192-disp-mutex",
.data = &mt8192_mutex_driver_data},
{ .compatible = "mediatek,mt8195-disp-mutex",
@@ -866,7 +951,6 @@ MODULE_DEVICE_TABLE(of, mutex_driver_dt_match);
static struct platform_driver mtk_mutex_driver = {
.probe = mtk_mutex_probe,
- .remove = mtk_mutex_remove,
.driver = {
.name = "mediatek-mutex",
.owner = THIS_MODULE,
@@ -874,4 +958,19 @@ static struct platform_driver mtk_mutex_driver = {
},
};
-builtin_platform_driver(mtk_mutex_driver);
+static int __init mtk_mutex_init(void)
+{
+ return platform_driver_register(&mtk_mutex_driver);
+}
+
+static void __exit mtk_mutex_exit(void)
+{
+ platform_driver_unregister(&mtk_mutex_driver);
+}
+
+module_init(mtk_mutex_init);
+module_exit(mtk_mutex_exit);
+
+MODULE_AUTHOR("Yongqiang Niu <yongqiang.niu@mediatek.com>");
+MODULE_DESCRIPTION("MediaTek SoC MUTEX driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/mediatek/mtk-pm-domains.c b/drivers/soc/mediatek/mtk-pm-domains.c
index 474b272f9b02..354249cc1b12 100644
--- a/drivers/soc/mediatek/mtk-pm-domains.c
+++ b/drivers/soc/mediatek/mtk-pm-domains.c
@@ -21,6 +21,7 @@
#include "mt8173-pm-domains.h"
#include "mt8183-pm-domains.h"
#include "mt8186-pm-domains.h"
+#include "mt8188-pm-domains.h"
#include "mt8192-pm-domains.h"
#include "mt8195-pm-domains.h"
@@ -218,6 +219,10 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
if (ret)
goto err_reg;
+ if (pd->data->ext_buck_iso_offs && MTK_SCPD_CAPS(pd, MTK_SCPD_EXT_BUCK_ISO))
+ regmap_clear_bits(scpsys->base, pd->data->ext_buck_iso_offs,
+ pd->data->ext_buck_iso_mask);
+
/* subsys power on */
regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_BIT);
regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_2ND_BIT);
@@ -272,6 +277,10 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
if (ret < 0)
return ret;
+ if (pd->data->ext_buck_iso_offs && MTK_SCPD_CAPS(pd, MTK_SCPD_EXT_BUCK_ISO))
+ regmap_set_bits(scpsys->base, pd->data->ext_buck_iso_offs,
+ pd->data->ext_buck_iso_mask);
+
clk_bulk_disable_unprepare(pd->num_subsys_clks, pd->subsys_clks);
/* subsys power off */
@@ -580,6 +589,10 @@ static const struct of_device_id scpsys_of_match[] = {
.data = &mt8186_scpsys_data,
},
{
+ .compatible = "mediatek,mt8188-power-controller",
+ .data = &mt8188_scpsys_data,
+ },
+ {
.compatible = "mediatek,mt8192-power-controller",
.data = &mt8192_scpsys_data,
},
diff --git a/drivers/soc/mediatek/mtk-pm-domains.h b/drivers/soc/mediatek/mtk-pm-domains.h
index 7d3c0c36316c..5ec53ee073c4 100644
--- a/drivers/soc/mediatek/mtk-pm-domains.h
+++ b/drivers/soc/mediatek/mtk-pm-domains.h
@@ -10,6 +10,7 @@
#define MTK_SCPD_DOMAIN_SUPPLY BIT(4)
/* can't set MTK_SCPD_KEEP_DEFAULT_OFF at the same time */
#define MTK_SCPD_ALWAYS_ON BIT(5)
+#define MTK_SCPD_EXT_BUCK_ISO BIT(6)
#define MTK_SCPD_CAPS(_scpd, _x) ((_scpd)->data->caps & (_x))
#define SPM_VDE_PWR_CON 0x0210
@@ -81,6 +82,8 @@ struct scpsys_bus_prot_data {
* @ctl_offs: The offset for main power control register.
* @sram_pdn_bits: The mask for sram power control bits.
* @sram_pdn_ack_bits: The mask for sram power control acked bits.
+ * @ext_buck_iso_offs: The offset for external buck isolation
+ * @ext_buck_iso_mask: The mask for external buck isolation
* @caps: The flag for active wake-up action.
* @bp_infracfg: bus protection for infracfg subsystem
* @bp_smi: bus protection for smi subsystem
@@ -91,6 +94,8 @@ struct scpsys_domain_data {
int ctl_offs;
u32 sram_pdn_bits;
u32 sram_pdn_ack_bits;
+ int ext_buck_iso_offs;
+ u32 ext_buck_iso_mask;
u8 caps;
const struct scpsys_bus_prot_data bp_infracfg[SPM_MAX_BUS_PROT_DATA];
const struct scpsys_bus_prot_data bp_smi[SPM_MAX_BUS_PROT_DATA];
diff --git a/drivers/soc/mediatek/mtk-regulator-coupler.c b/drivers/soc/mediatek/mtk-regulator-coupler.c
new file mode 100644
index 000000000000..ad2ed42aa697
--- /dev/null
+++ b/drivers/soc/mediatek/mtk-regulator-coupler.c
@@ -0,0 +1,159 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Voltage regulators coupler for MediaTek SoCs
+ *
+ * Copyright (C) 2022 Collabora, Ltd.
+ * Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/regulator/coupler.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/suspend.h>
+
+#define to_mediatek_coupler(x) container_of(x, struct mediatek_regulator_coupler, coupler)
+
+struct mediatek_regulator_coupler {
+ struct regulator_coupler coupler;
+ struct regulator_dev *vsram_rdev;
+};
+
+/*
+ * We currently support only couples of not more than two vregs and
+ * modify the vsram voltage only when changing voltage of vgpu.
+ *
+ * This function is limited to the GPU<->SRAM voltages relationships.
+ */
+static int mediatek_regulator_balance_voltage(struct regulator_coupler *coupler,
+ struct regulator_dev *rdev,
+ suspend_state_t state)
+{
+ struct mediatek_regulator_coupler *mrc = to_mediatek_coupler(coupler);
+ int max_spread = rdev->constraints->max_spread[0];
+ int vsram_min_uV = mrc->vsram_rdev->constraints->min_uV;
+ int vsram_max_uV = mrc->vsram_rdev->constraints->max_uV;
+ int vsram_target_min_uV, vsram_target_max_uV;
+ int min_uV = 0;
+ int max_uV = INT_MAX;
+ int ret;
+
+ /*
+ * If the target device is on, setting the SRAM voltage directly
+ * is not supported as it scales through its coupled supply voltage.
+ *
+ * An exception is made in case the use_count is zero: this means
+ * that this is the first time we power up the SRAM regulator, which
+ * implies that the target device has yet to perform initialization
+ * and setting a voltage at that time is harmless.
+ */
+ if (rdev == mrc->vsram_rdev) {
+ if (rdev->use_count == 0)
+ return regulator_do_balance_voltage(rdev, state, true);
+
+ return -EPERM;
+ }
+
+ ret = regulator_check_consumers(rdev, &min_uV, &max_uV, state);
+ if (ret < 0)
+ return ret;
+
+ if (min_uV == 0) {
+ ret = regulator_get_voltage_rdev(rdev);
+ if (ret < 0)
+ return ret;
+ min_uV = ret;
+ }
+
+ ret = regulator_check_voltage(rdev, &min_uV, &max_uV);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * If we're asked to set a voltage less than VSRAM min_uV, set
+ * the minimum allowed voltage on VSRAM, as in this case it is
+ * safe to ignore the max_spread parameter.
+ */
+ vsram_target_min_uV = max(vsram_min_uV, min_uV + max_spread);
+ vsram_target_max_uV = min(vsram_max_uV, vsram_target_min_uV + max_spread);
+
+ /* Make sure we're not out of range */
+ vsram_target_min_uV = min(vsram_target_min_uV, vsram_max_uV);
+
+ pr_debug("Setting voltage %d-%duV on %s (minuV %d)\n",
+ vsram_target_min_uV, vsram_target_max_uV,
+ rdev_get_name(mrc->vsram_rdev), min_uV);
+
+ ret = regulator_set_voltage_rdev(mrc->vsram_rdev, vsram_target_min_uV,
+ vsram_target_max_uV, state);
+ if (ret)
+ return ret;
+
+ /* The sram voltage is now balanced: update the target vreg voltage */
+ return regulator_do_balance_voltage(rdev, state, true);
+}
+
+static int mediatek_regulator_attach(struct regulator_coupler *coupler,
+ struct regulator_dev *rdev)
+{
+ struct mediatek_regulator_coupler *mrc = to_mediatek_coupler(coupler);
+ const char *rdev_name = rdev_get_name(rdev);
+
+ /*
+ * If we're getting a coupling of more than two regulators here and
+ * this means that this is surely not a GPU<->SRAM couple: in that
+ * case, we may want to use another coupler implementation, if any,
+ * or the generic one: the regulator core will keep walking through
+ * the list of couplers when any .attach_regulator() cb returns 1.
+ */
+ if (rdev->coupling_desc.n_coupled > 2)
+ return 1;
+
+ if (strstr(rdev_name, "sram")) {
+ if (mrc->vsram_rdev)
+ return -EINVAL;
+ mrc->vsram_rdev = rdev;
+ } else if (!strstr(rdev_name, "vgpu") && !strstr(rdev_name, "Vgpu")) {
+ return 1;
+ }
+
+ return 0;
+}
+
+static int mediatek_regulator_detach(struct regulator_coupler *coupler,
+ struct regulator_dev *rdev)
+{
+ struct mediatek_regulator_coupler *mrc = to_mediatek_coupler(coupler);
+
+ if (rdev == mrc->vsram_rdev)
+ mrc->vsram_rdev = NULL;
+
+ return 0;
+}
+
+static struct mediatek_regulator_coupler mediatek_coupler = {
+ .coupler = {
+ .attach_regulator = mediatek_regulator_attach,
+ .detach_regulator = mediatek_regulator_detach,
+ .balance_voltage = mediatek_regulator_balance_voltage,
+ },
+};
+
+static int mediatek_regulator_coupler_init(void)
+{
+ if (!of_machine_is_compatible("mediatek,mt8183") &&
+ !of_machine_is_compatible("mediatek,mt8186") &&
+ !of_machine_is_compatible("mediatek,mt8192"))
+ return 0;
+
+ return regulator_coupler_register(&mediatek_coupler.coupler);
+}
+arch_initcall(mediatek_regulator_coupler_init);
+
+MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>");
+MODULE_DESCRIPTION("MediaTek Regulator Coupler driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/mediatek/mtk-svs.c b/drivers/soc/mediatek/mtk-svs.c
index 0469c9dfeb04..f26eb2f637d5 100644
--- a/drivers/soc/mediatek/mtk-svs.c
+++ b/drivers/soc/mediatek/mtk-svs.c
@@ -138,6 +138,7 @@
static DEFINE_SPINLOCK(svs_lock);
+#ifdef CONFIG_DEBUG_FS
#define debug_fops_ro(name) \
static int svs_##name##_debug_open(struct inode *inode, \
struct file *filp) \
@@ -170,6 +171,7 @@ static DEFINE_SPINLOCK(svs_lock);
}
#define svs_dentry_data(name) {__stringify(name), &svs_##name##_debug_fops}
+#endif
/**
* enum svsb_phase - svs bank phase enumeration
@@ -311,15 +313,12 @@ static const u32 svs_regs_v2[] = {
/**
* struct svs_platform - svs platform control
- * @name: svs platform name
* @base: svs platform register base
* @dev: svs platform device
* @main_clk: main clock for svs bank
* @pbank: svs bank pointer needing to be protected by spin_lock section
* @banks: svs banks that svs platform supports
* @rst: svs platform reset control
- * @efuse_parsing: svs platform efuse parsing function pointer
- * @probe: svs platform probe function pointer
* @efuse_max: total number of svs efuse
* @tefuse_max: total number of thermal efuse
* @regs: svs platform registers map
@@ -328,15 +327,12 @@ static const u32 svs_regs_v2[] = {
* @tefuse: thermal efuse data received from NVMEM framework
*/
struct svs_platform {
- char *name;
void __iomem *base;
struct device *dev;
struct clk *main_clk;
struct svs_bank *pbank;
struct svs_bank *banks;
struct reset_control *rst;
- bool (*efuse_parsing)(struct svs_platform *svsp);
- int (*probe)(struct svs_platform *svsp);
size_t efuse_max;
size_t tefuse_max;
const u32 *regs;
@@ -628,6 +624,7 @@ unlock_mutex:
return ret;
}
+#ifdef CONFIG_DEBUG_FS
static int svs_dump_debug_show(struct seq_file *m, void *p)
{
struct svs_platform *svsp = (struct svs_platform *)m->private;
@@ -843,6 +840,7 @@ static int svs_create_debug_cmds(struct svs_platform *svsp)
return 0;
}
+#endif /* CONFIG_DEBUG_FS */
static u32 interpolate(u32 f0, u32 f1, u32 v0, u32 v1, u32 fx)
{
@@ -1324,7 +1322,7 @@ static int svs_init01(struct svs_platform *svsp)
svsb->pm_runtime_enabled_count++;
}
- ret = pm_runtime_get_sync(svsb->opp_dev);
+ ret = pm_runtime_resume_and_get(svsb->opp_dev);
if (ret < 0) {
dev_err(svsb->dev, "mtcmos on fail: %d\n", ret);
goto svs_init01_resume_cpuidle;
@@ -1461,6 +1459,7 @@ static int svs_init02(struct svs_platform *svsp)
{
struct svs_bank *svsb;
unsigned long flags, time_left;
+ int ret;
u32 idx;
for (idx = 0; idx < svsp->bank_max; idx++) {
@@ -1479,7 +1478,8 @@ static int svs_init02(struct svs_platform *svsp)
msecs_to_jiffies(5000));
if (!time_left) {
dev_err(svsb->dev, "init02 completion timeout\n");
- return -EBUSY;
+ ret = -EBUSY;
+ goto out_of_init02;
}
}
@@ -1497,12 +1497,30 @@ static int svs_init02(struct svs_platform *svsp)
if (svsb->type == SVSB_HIGH || svsb->type == SVSB_LOW) {
if (svs_sync_bank_volts_from_opp(svsb)) {
dev_err(svsb->dev, "sync volt fail\n");
- return -EPERM;
+ ret = -EPERM;
+ goto out_of_init02;
}
}
}
return 0;
+
+out_of_init02:
+ for (idx = 0; idx < svsp->bank_max; idx++) {
+ svsb = &svsp->banks[idx];
+
+ spin_lock_irqsave(&svs_lock, flags);
+ svsp->pbank = svsb;
+ svs_switch_bank(svsp);
+ svs_writel_relaxed(svsp, SVSB_PTPEN_OFF, SVSEN);
+ svs_writel_relaxed(svsp, SVSB_INTSTS_VAL_CLEAN, INTSTS);
+ spin_unlock_irqrestore(&svs_lock, flags);
+
+ svsb->phase = SVSB_PHASE_ERROR;
+ svs_adjust_pm_opp_volts(svsb);
+ }
+
+ return ret;
}
static void svs_mon_mode(struct svs_platform *svsp)
@@ -1594,12 +1612,16 @@ static int svs_resume(struct device *dev)
ret = svs_init02(svsp);
if (ret)
- goto out_of_resume;
+ goto svs_resume_reset_assert;
svs_mon_mode(svsp);
return 0;
+svs_resume_reset_assert:
+ dev_err(svsp->dev, "assert reset: %d\n",
+ reset_control_assert(svsp->rst));
+
out_of_resume:
clk_disable_unprepare(svsp->main_clk);
return ret;
@@ -1899,26 +1921,27 @@ static bool svs_mt8183_efuse_parsing(struct svs_platform *svsp)
o_slope_sign = (svsp->tefuse[0] >> 7) & BIT(0);
ts_id = (svsp->tefuse[1] >> 9) & BIT(0);
- o_slope = (svsp->tefuse[0] >> 26) & GENMASK(5, 0);
-
- if (adc_cali_en_t == 1) {
- if (!ts_id)
- o_slope = 0;
-
- if (adc_ge_t < 265 || adc_ge_t > 758 ||
- adc_oe_t < 265 || adc_oe_t > 758 ||
- o_vtsmcu[0] < -8 || o_vtsmcu[0] > 484 ||
- o_vtsmcu[1] < -8 || o_vtsmcu[1] > 484 ||
- o_vtsmcu[2] < -8 || o_vtsmcu[2] > 484 ||
- o_vtsmcu[3] < -8 || o_vtsmcu[3] > 484 ||
- o_vtsmcu[4] < -8 || o_vtsmcu[4] > 484 ||
- o_vtsabb < -8 || o_vtsabb > 484 ||
- degc_cali < 1 || degc_cali > 63) {
- dev_err(svsp->dev, "bad thermal efuse, no mon mode\n");
- goto remove_mt8183_svsb_mon_mode;
- }
+ if (!ts_id) {
+ o_slope = 1534;
} else {
- dev_err(svsp->dev, "no thermal efuse, no mon mode\n");
+ o_slope = (svsp->tefuse[0] >> 26) & GENMASK(5, 0);
+ if (!o_slope_sign)
+ o_slope = 1534 + o_slope * 10;
+ else
+ o_slope = 1534 - o_slope * 10;
+ }
+
+ if (adc_cali_en_t == 0 ||
+ adc_ge_t < 265 || adc_ge_t > 758 ||
+ adc_oe_t < 265 || adc_oe_t > 758 ||
+ o_vtsmcu[0] < -8 || o_vtsmcu[0] > 484 ||
+ o_vtsmcu[1] < -8 || o_vtsmcu[1] > 484 ||
+ o_vtsmcu[2] < -8 || o_vtsmcu[2] > 484 ||
+ o_vtsmcu[3] < -8 || o_vtsmcu[3] > 484 ||
+ o_vtsmcu[4] < -8 || o_vtsmcu[4] > 484 ||
+ o_vtsabb < -8 || o_vtsabb > 484 ||
+ degc_cali < 1 || degc_cali > 63) {
+ dev_err(svsp->dev, "bad thermal efuse, no mon mode\n");
goto remove_mt8183_svsb_mon_mode;
}
@@ -1937,11 +1960,7 @@ static bool svs_mt8183_efuse_parsing(struct svs_platform *svsp)
x_roomt[i] = (((format[i] * 10000) / 4096) * 10000) / gain;
temp0 = (10000 * 100000 / gain) * 15 / 18;
-
- if (!o_slope_sign)
- mts = (temp0 * 10) / (1534 + o_slope * 10);
- else
- mts = (temp0 * 10) / (1534 - o_slope * 10);
+ mts = (temp0 * 10) / o_slope;
for (idx = 0; idx < svsp->bank_max; idx++) {
svsb = &svsp->banks[idx];
@@ -1968,11 +1987,7 @@ static bool svs_mt8183_efuse_parsing(struct svs_platform *svsp)
temp0 = (degc_cali * 10 / 2);
temp1 = ((10000 * 100000 / 4096 / gain) *
oe + tb_roomt * 10) * 15 / 18;
-
- if (!o_slope_sign)
- temp2 = temp1 * 100 / (1534 + o_slope * 10);
- else
- temp2 = temp1 * 100 / (1534 - o_slope * 10);
+ temp2 = temp1 * 100 / o_slope;
svsb->bts = (temp0 + temp2 - 250) * 4 / 10;
}
@@ -2011,7 +2026,7 @@ static bool svs_is_efuse_data_correct(struct svs_platform *svsp)
svsp->efuse_max /= sizeof(u32);
nvmem_cell_put(cell);
- return svsp->efuse_parsing(svsp);
+ return true;
}
static struct device *svs_get_subsys_device(struct svs_platform *svsp,
@@ -2326,50 +2341,38 @@ static const struct of_device_id svs_of_match[] = {
/* Sentinel */
},
};
+MODULE_DEVICE_TABLE(of, svs_of_match);
-static struct svs_platform *svs_platform_probe(struct platform_device *pdev)
+static int svs_probe(struct platform_device *pdev)
{
struct svs_platform *svsp;
const struct svs_platform_data *svsp_data;
- int ret;
+ int ret, svsp_irq;
svsp_data = of_device_get_match_data(&pdev->dev);
- if (!svsp_data) {
- dev_err(&pdev->dev, "no svs platform data?\n");
- return ERR_PTR(-EPERM);
- }
svsp = devm_kzalloc(&pdev->dev, sizeof(*svsp), GFP_KERNEL);
if (!svsp)
- return ERR_PTR(-ENOMEM);
+ return -ENOMEM;
svsp->dev = &pdev->dev;
- svsp->name = svsp_data->name;
svsp->banks = svsp_data->banks;
- svsp->efuse_parsing = svsp_data->efuse_parsing;
- svsp->probe = svsp_data->probe;
svsp->regs = svsp_data->regs;
svsp->bank_max = svsp_data->bank_max;
- ret = svsp->probe(svsp);
+ ret = svsp_data->probe(svsp);
if (ret)
- return ERR_PTR(ret);
-
- return svsp;
-}
-
-static int svs_probe(struct platform_device *pdev)
-{
- struct svs_platform *svsp;
- int svsp_irq, ret;
-
- svsp = svs_platform_probe(pdev);
- if (IS_ERR(svsp))
- return PTR_ERR(svsp);
+ return ret;
if (!svs_is_efuse_data_correct(svsp)) {
dev_notice(svsp->dev, "efuse data isn't correct\n");
ret = -EPERM;
+ goto svs_probe_free_efuse;
+ }
+
+ if (!svsp_data->efuse_parsing(svsp)) {
+ dev_err(svsp->dev, "efuse data parsing failed\n");
+ ret = -EPERM;
goto svs_probe_free_resource;
}
@@ -2385,14 +2388,6 @@ static int svs_probe(struct platform_device *pdev)
goto svs_probe_free_resource;
}
- ret = devm_request_threaded_irq(svsp->dev, svsp_irq, NULL, svs_isr,
- IRQF_ONESHOT, svsp->name, svsp);
- if (ret) {
- dev_err(svsp->dev, "register irq(%d) failed: %d\n",
- svsp_irq, ret);
- goto svs_probe_free_resource;
- }
-
svsp->main_clk = devm_clk_get(svsp->dev, "main");
if (IS_ERR(svsp->main_clk)) {
dev_err(svsp->dev, "failed to get clock: %ld\n",
@@ -2414,17 +2409,27 @@ static int svs_probe(struct platform_device *pdev)
goto svs_probe_clk_disable;
}
+ ret = devm_request_threaded_irq(svsp->dev, svsp_irq, NULL, svs_isr,
+ IRQF_ONESHOT, svsp_data->name, svsp);
+ if (ret) {
+ dev_err(svsp->dev, "register irq(%d) failed: %d\n",
+ svsp_irq, ret);
+ goto svs_probe_iounmap;
+ }
+
ret = svs_start(svsp);
if (ret) {
dev_err(svsp->dev, "svs start fail: %d\n", ret);
goto svs_probe_iounmap;
}
+#ifdef CONFIG_DEBUG_FS
ret = svs_create_debug_cmds(svsp);
if (ret) {
dev_err(svsp->dev, "svs create debug cmds fail: %d\n", ret);
goto svs_probe_iounmap;
}
+#endif
return 0;
@@ -2435,11 +2440,13 @@ svs_probe_clk_disable:
clk_disable_unprepare(svsp->main_clk);
svs_probe_free_resource:
- if (!IS_ERR_OR_NULL(svsp->efuse))
- kfree(svsp->efuse);
if (!IS_ERR_OR_NULL(svsp->tefuse))
kfree(svsp->tefuse);
+svs_probe_free_efuse:
+ if (!IS_ERR_OR_NULL(svsp->efuse))
+ kfree(svsp->efuse);
+
return ret;
}
diff --git a/drivers/soc/nuvoton/Kconfig b/drivers/soc/nuvoton/Kconfig
new file mode 100644
index 000000000000..df46182088ec
--- /dev/null
+++ b/drivers/soc/nuvoton/Kconfig
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0
+menuconfig WPCM450_SOC
+ tristate "Nuvoton WPCM450 SoC driver"
+ default y if ARCH_WPCM450
+ select SOC_BUS
+ help
+ Say Y here to compile the SoC information driver for Nuvoton
+ WPCM450 SoCs.
+
+ This driver provides information such as the SoC model and
+ revision.
diff --git a/drivers/soc/nuvoton/Makefile b/drivers/soc/nuvoton/Makefile
new file mode 100644
index 000000000000..e30317b4e829
--- /dev/null
+++ b/drivers/soc/nuvoton/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_WPCM450_SOC) += wpcm450-soc.o
diff --git a/drivers/soc/nuvoton/wpcm450-soc.c b/drivers/soc/nuvoton/wpcm450-soc.c
new file mode 100644
index 000000000000..c5e0d11c383b
--- /dev/null
+++ b/drivers/soc/nuvoton/wpcm450-soc.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Nuvoton WPCM450 SoC Identification
+ *
+ * Copyright (C) 2022 Jonathan Neuschäfer
+ */
+
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/sys_soc.h>
+
+#define GCR_PDID 0
+#define PDID_CHIP(x) ((x) & 0x00ffffff)
+#define CHIP_WPCM450 0x926450
+#define PDID_REV(x) ((x) >> 24)
+
+struct revision {
+ u8 number;
+ const char *name;
+};
+
+static const struct revision revisions[] __initconst = {
+ { 0x00, "Z1" },
+ { 0x03, "Z2" },
+ { 0x04, "Z21" },
+ { 0x08, "A1" },
+ { 0x09, "A2" },
+ { 0x0a, "A3" },
+ {}
+};
+
+static const char * __init get_revision(unsigned int rev)
+{
+ int i;
+
+ for (i = 0; revisions[i].name; i++)
+ if (revisions[i].number == rev)
+ return revisions[i].name;
+ return NULL;
+}
+
+static struct soc_device_attribute *wpcm450_attr;
+static struct soc_device *wpcm450_soc;
+
+static int __init wpcm450_soc_init(void)
+{
+ struct soc_device_attribute *attr;
+ struct soc_device *soc;
+ const char *revision;
+ struct regmap *gcr;
+ u32 pdid;
+ int ret;
+
+ if (!of_machine_is_compatible("nuvoton,wpcm450"))
+ return 0;
+
+ gcr = syscon_regmap_lookup_by_compatible("nuvoton,wpcm450-gcr");
+ if (IS_ERR(gcr))
+ return PTR_ERR(gcr);
+ ret = regmap_read(gcr, GCR_PDID, &pdid);
+ if (ret)
+ return ret;
+
+ if (PDID_CHIP(pdid) != CHIP_WPCM450) {
+ pr_warn("Unknown chip ID in GCR.PDID: 0x%06x\n", PDID_CHIP(pdid));
+ return -ENODEV;
+ }
+
+ revision = get_revision(PDID_REV(pdid));
+ if (!revision) {
+ pr_warn("Unknown chip revision in GCR.PDID: 0x%02x\n", PDID_REV(pdid));
+ return -ENODEV;
+ }
+
+ attr = kzalloc(sizeof(*attr), GFP_KERNEL);
+ if (!attr)
+ return -ENOMEM;
+
+ attr->family = "Nuvoton NPCM";
+ attr->soc_id = "WPCM450";
+ attr->revision = revision;
+ soc = soc_device_register(attr);
+ if (IS_ERR(soc)) {
+ kfree(attr);
+ pr_warn("Could not register SoC device\n");
+ return PTR_ERR(soc);
+ }
+
+ wpcm450_soc = soc;
+ wpcm450_attr = attr;
+ return 0;
+}
+module_init(wpcm450_soc_init);
+
+static void __exit wpcm450_soc_exit(void)
+{
+ if (wpcm450_soc) {
+ soc_device_unregister(wpcm450_soc);
+ wpcm450_soc = NULL;
+ kfree(wpcm450_attr);
+ }
+}
+module_exit(wpcm450_soc_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jonathan Neuschäfer");
+MODULE_DESCRIPTION("Nuvoton WPCM450 SoC Identification driver");
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index ae504c43d9e7..a8f283086a21 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -91,11 +91,38 @@ config QCOM_OCMEM
config QCOM_PDR_HELPERS
tristate
select QCOM_QMI_HELPERS
+ depends on NET
+
+config QCOM_PMIC_GLINK
+ tristate "Qualcomm PMIC GLINK driver"
+ depends on RPMSG
+ depends on TYPEC
+ depends on DRM
+ depends on NET
+ depends on OF
+ select AUXILIARY_BUS
+ select QCOM_PDR_HELPERS
+ help
+ The Qualcomm PMIC GLINK driver provides access, over GLINK, to the
+ USB and battery firmware running on one of the coprocessors in
+ several modern Qualcomm platforms.
+
+ Say yes here to support USB-C and battery status on modern Qualcomm
+ platforms.
config QCOM_QMI_HELPERS
tristate
depends on NET
+config QCOM_RAMP_CTRL
+ tristate "Qualcomm Ramp Controller driver"
+ depends on ARCH_QCOM || COMPILE_TEST
+ help
+ The Ramp Controller is used to program the sequence ID for pulse
+ swallowing, enable sequence and link sequence IDs for the CPU
+ cores on some Qualcomm SoCs.
+ Say y here to enable support for the ramp controller.
+
config QCOM_RMTFS_MEM
tristate "Qualcomm Remote Filesystem memory driver"
depends on ARCH_QCOM
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index d66604aff2b0..6e88da899f60 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -8,8 +8,11 @@ obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o
obj-$(CONFIG_QCOM_MDT_LOADER) += mdt_loader.o
obj-$(CONFIG_QCOM_OCMEM) += ocmem.o
obj-$(CONFIG_QCOM_PDR_HELPERS) += pdr_interface.o
+obj-$(CONFIG_QCOM_PMIC_GLINK) += pmic_glink.o
+obj-$(CONFIG_QCOM_PMIC_GLINK) += pmic_glink_altmode.o
obj-$(CONFIG_QCOM_QMI_HELPERS) += qmi_helpers.o
qmi_helpers-y += qmi_encdec.o qmi_interface.o
+obj-$(CONFIG_QCOM_RAMP_CTRL) += ramp_controller.o
obj-$(CONFIG_QCOM_RMTFS_MEM) += rmtfs_mem.o
obj-$(CONFIG_QCOM_RPMH) += qcom_rpmh.o
qcom_rpmh-y += rpmh-rsc.o
diff --git a/drivers/soc/qcom/apr.c b/drivers/soc/qcom/apr.c
index d51abb462ae5..30f81d6d9d9d 100644
--- a/drivers/soc/qcom/apr.c
+++ b/drivers/soc/qcom/apr.c
@@ -387,9 +387,9 @@ static void apr_device_remove(struct device *dev)
spin_unlock(&apr->svcs_lock);
}
-static int apr_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int apr_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct apr_device *adev = to_apr_device(dev);
+ const struct apr_device *adev = to_apr_device(dev);
int ret;
ret = of_device_uevent_modalias(dev, env);
diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c
index 3f11554df2f3..33dd8c315eb7 100644
--- a/drivers/soc/qcom/mdt_loader.c
+++ b/drivers/soc/qcom/mdt_loader.c
@@ -12,7 +12,7 @@
#include <linux/firmware.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/soc/qcom/mdt_loader.h>
diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c
index c92d26b73e6f..199fe9872035 100644
--- a/drivers/soc/qcom/ocmem.c
+++ b/drivers/soc/qcom/ocmem.c
@@ -16,7 +16,7 @@
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/types.h>
diff --git a/drivers/soc/qcom/pmic_glink.c b/drivers/soc/qcom/pmic_glink.c
new file mode 100644
index 000000000000..bb3fb57abcc6
--- /dev/null
+++ b/drivers/soc/qcom/pmic_glink.c
@@ -0,0 +1,336 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022, Linaro Ltd
+ */
+#include <linux/auxiliary_bus.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/rpmsg.h>
+#include <linux/slab.h>
+#include <linux/soc/qcom/pdr.h>
+#include <linux/soc/qcom/pmic_glink.h>
+
+struct pmic_glink {
+ struct device *dev;
+ struct pdr_handle *pdr;
+
+ struct rpmsg_endpoint *ept;
+
+ struct auxiliary_device altmode_aux;
+ struct auxiliary_device ps_aux;
+ struct auxiliary_device ucsi_aux;
+
+ /* serializing client_state and pdr_state updates */
+ struct mutex state_lock;
+ unsigned int client_state;
+ unsigned int pdr_state;
+
+ /* serializing clients list updates */
+ struct mutex client_lock;
+ struct list_head clients;
+};
+
+static struct pmic_glink *__pmic_glink;
+static DEFINE_MUTEX(__pmic_glink_lock);
+
+struct pmic_glink_client {
+ struct list_head node;
+
+ struct pmic_glink *pg;
+ unsigned int id;
+
+ void (*cb)(const void *data, size_t len, void *priv);
+ void (*pdr_notify)(void *priv, int state);
+ void *priv;
+};
+
+static void _devm_pmic_glink_release_client(struct device *dev, void *res)
+{
+ struct pmic_glink_client *client = (struct pmic_glink_client *)res;
+ struct pmic_glink *pg = client->pg;
+
+ mutex_lock(&pg->client_lock);
+ list_del(&client->node);
+ mutex_unlock(&pg->client_lock);
+}
+
+struct pmic_glink_client *devm_pmic_glink_register_client(struct device *dev,
+ unsigned int id,
+ void (*cb)(const void *, size_t, void *),
+ void (*pdr)(void *, int),
+ void *priv)
+{
+ struct pmic_glink_client *client;
+ struct pmic_glink *pg = dev_get_drvdata(dev->parent);
+
+ client = devres_alloc(_devm_pmic_glink_release_client, sizeof(*client), GFP_KERNEL);
+ if (!client)
+ return ERR_PTR(-ENOMEM);
+
+ client->pg = pg;
+ client->id = id;
+ client->cb = cb;
+ client->pdr_notify = pdr;
+ client->priv = priv;
+
+ mutex_lock(&pg->client_lock);
+ list_add(&client->node, &pg->clients);
+ mutex_unlock(&pg->client_lock);
+
+ devres_add(dev, client);
+
+ return client;
+}
+EXPORT_SYMBOL_GPL(devm_pmic_glink_register_client);
+
+int pmic_glink_send(struct pmic_glink_client *client, void *data, size_t len)
+{
+ struct pmic_glink *pg = client->pg;
+
+ return rpmsg_send(pg->ept, data, len);
+}
+EXPORT_SYMBOL_GPL(pmic_glink_send);
+
+static int pmic_glink_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
+ int len, void *priv, u32 addr)
+{
+ struct pmic_glink_client *client;
+ struct pmic_glink_hdr *hdr;
+ struct pmic_glink *pg = dev_get_drvdata(&rpdev->dev);
+
+ if (len < sizeof(*hdr)) {
+ dev_warn(pg->dev, "ignoring truncated message\n");
+ return 0;
+ }
+
+ hdr = data;
+
+ list_for_each_entry(client, &pg->clients, node) {
+ if (client->id == le32_to_cpu(hdr->owner))
+ client->cb(data, len, client->priv);
+ }
+
+ return 0;
+}
+
+static void pmic_glink_aux_release(struct device *dev) {}
+
+static int pmic_glink_add_aux_device(struct pmic_glink *pg,
+ struct auxiliary_device *aux,
+ const char *name)
+{
+ struct device *parent = pg->dev;
+ int ret;
+
+ aux->name = name;
+ aux->dev.parent = parent;
+ aux->dev.release = pmic_glink_aux_release;
+ device_set_of_node_from_dev(&aux->dev, parent);
+ ret = auxiliary_device_init(aux);
+ if (ret)
+ return ret;
+
+ ret = auxiliary_device_add(aux);
+ if (ret)
+ auxiliary_device_uninit(aux);
+
+ return ret;
+}
+
+static void pmic_glink_del_aux_device(struct pmic_glink *pg,
+ struct auxiliary_device *aux)
+{
+ auxiliary_device_delete(aux);
+ auxiliary_device_uninit(aux);
+}
+
+static void pmic_glink_state_notify_clients(struct pmic_glink *pg)
+{
+ struct pmic_glink_client *client;
+ unsigned int new_state = pg->client_state;
+
+ if (pg->client_state != SERVREG_SERVICE_STATE_UP) {
+ if (pg->pdr_state == SERVREG_SERVICE_STATE_UP && pg->ept)
+ new_state = SERVREG_SERVICE_STATE_UP;
+ } else {
+ if (pg->pdr_state == SERVREG_SERVICE_STATE_UP && pg->ept)
+ new_state = SERVREG_SERVICE_STATE_DOWN;
+ }
+
+ if (new_state != pg->client_state) {
+ list_for_each_entry(client, &pg->clients, node)
+ client->pdr_notify(client->priv, new_state);
+ pg->client_state = new_state;
+ }
+}
+
+static void pmic_glink_pdr_callback(int state, char *svc_path, void *priv)
+{
+ struct pmic_glink *pg = priv;
+
+ mutex_lock(&pg->state_lock);
+ pg->pdr_state = state;
+
+ pmic_glink_state_notify_clients(pg);
+ mutex_unlock(&pg->state_lock);
+}
+
+static int pmic_glink_rpmsg_probe(struct rpmsg_device *rpdev)
+{
+ struct pmic_glink *pg = __pmic_glink;
+ int ret = 0;
+
+ mutex_lock(&__pmic_glink_lock);
+ if (!pg) {
+ ret = dev_err_probe(&rpdev->dev, -ENODEV, "no pmic_glink device to attach to\n");
+ goto out_unlock;
+ }
+
+ dev_set_drvdata(&rpdev->dev, pg);
+
+ mutex_lock(&pg->state_lock);
+ pg->ept = rpdev->ept;
+ pmic_glink_state_notify_clients(pg);
+ mutex_unlock(&pg->state_lock);
+
+out_unlock:
+ mutex_unlock(&__pmic_glink_lock);
+ return ret;
+}
+
+static void pmic_glink_rpmsg_remove(struct rpmsg_device *rpdev)
+{
+ struct pmic_glink *pg;
+
+ mutex_lock(&__pmic_glink_lock);
+ pg = __pmic_glink;
+ if (!pg)
+ goto out_unlock;
+
+ mutex_lock(&pg->state_lock);
+ pg->ept = NULL;
+ pmic_glink_state_notify_clients(pg);
+ mutex_unlock(&pg->state_lock);
+out_unlock:
+ mutex_unlock(&__pmic_glink_lock);
+}
+
+static const struct rpmsg_device_id pmic_glink_rpmsg_id_match[] = {
+ { "PMIC_RTR_ADSP_APPS" },
+ {}
+};
+
+static struct rpmsg_driver pmic_glink_rpmsg_driver = {
+ .probe = pmic_glink_rpmsg_probe,
+ .remove = pmic_glink_rpmsg_remove,
+ .callback = pmic_glink_rpmsg_callback,
+ .id_table = pmic_glink_rpmsg_id_match,
+ .drv = {
+ .name = "qcom_pmic_glink_rpmsg",
+ },
+};
+
+static int pmic_glink_probe(struct platform_device *pdev)
+{
+ struct pdr_service *service;
+ struct pmic_glink *pg;
+ int ret;
+
+ pg = devm_kzalloc(&pdev->dev, sizeof(*pg), GFP_KERNEL);
+ if (!pg)
+ return -ENOMEM;
+
+ dev_set_drvdata(&pdev->dev, pg);
+
+ pg->dev = &pdev->dev;
+
+ INIT_LIST_HEAD(&pg->clients);
+ mutex_init(&pg->client_lock);
+ mutex_init(&pg->state_lock);
+
+ ret = pmic_glink_add_aux_device(pg, &pg->altmode_aux, "altmode");
+ if (ret)
+ return ret;
+ ret = pmic_glink_add_aux_device(pg, &pg->ps_aux, "power-supply");
+ if (ret)
+ goto out_release_altmode_aux;
+
+ pg->pdr = pdr_handle_alloc(pmic_glink_pdr_callback, pg);
+ if (IS_ERR(pg->pdr)) {
+ ret = dev_err_probe(&pdev->dev, PTR_ERR(pg->pdr), "failed to initialize pdr\n");
+ goto out_release_aux_devices;
+ }
+
+ service = pdr_add_lookup(pg->pdr, "tms/servreg", "msm/adsp/charger_pd");
+ if (IS_ERR(service)) {
+ ret = dev_err_probe(&pdev->dev, PTR_ERR(service),
+ "failed adding pdr lookup for charger_pd\n");
+ goto out_release_pdr_handle;
+ }
+
+ mutex_lock(&__pmic_glink_lock);
+ __pmic_glink = pg;
+ mutex_unlock(&__pmic_glink_lock);
+
+ return 0;
+
+out_release_pdr_handle:
+ pdr_handle_release(pg->pdr);
+out_release_aux_devices:
+ pmic_glink_del_aux_device(pg, &pg->ps_aux);
+out_release_altmode_aux:
+ pmic_glink_del_aux_device(pg, &pg->altmode_aux);
+
+ return ret;
+}
+
+static int pmic_glink_remove(struct platform_device *pdev)
+{
+ struct pmic_glink *pg = dev_get_drvdata(&pdev->dev);
+
+ pdr_handle_release(pg->pdr);
+
+ pmic_glink_del_aux_device(pg, &pg->ps_aux);
+ pmic_glink_del_aux_device(pg, &pg->altmode_aux);
+
+ mutex_lock(&__pmic_glink_lock);
+ __pmic_glink = NULL;
+ mutex_unlock(&__pmic_glink_lock);
+
+ return 0;
+}
+
+static const struct of_device_id pmic_glink_of_match[] = {
+ { .compatible = "qcom,pmic-glink", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, pmic_glink_of_match);
+
+static struct platform_driver pmic_glink_driver = {
+ .probe = pmic_glink_probe,
+ .remove = pmic_glink_remove,
+ .driver = {
+ .name = "qcom_pmic_glink",
+ .of_match_table = pmic_glink_of_match,
+ },
+};
+
+static int pmic_glink_init(void)
+{
+ platform_driver_register(&pmic_glink_driver);
+ register_rpmsg_driver(&pmic_glink_rpmsg_driver);
+
+ return 0;
+};
+module_init(pmic_glink_init);
+
+static void pmic_glink_exit(void)
+{
+ unregister_rpmsg_driver(&pmic_glink_rpmsg_driver);
+ platform_driver_unregister(&pmic_glink_driver);
+};
+module_exit(pmic_glink_exit);
+
+MODULE_DESCRIPTION("Qualcomm PMIC GLINK driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/qcom/pmic_glink_altmode.c b/drivers/soc/qcom/pmic_glink_altmode.c
new file mode 100644
index 000000000000..4d7895bdeaf2
--- /dev/null
+++ b/drivers/soc/qcom/pmic_glink_altmode.c
@@ -0,0 +1,478 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022, Linaro Ltd
+ */
+#include <linux/auxiliary_bus.h>
+#include <linux/bitfield.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/mutex.h>
+#include <linux/property.h>
+#include <linux/soc/qcom/pdr.h>
+#include <drm/drm_bridge.h>
+
+#include <linux/usb/typec_altmode.h>
+#include <linux/usb/typec_dp.h>
+#include <linux/usb/typec_mux.h>
+
+#include <linux/soc/qcom/pmic_glink.h>
+
+#define PMIC_GLINK_MAX_PORTS 2
+
+#define USBC_SC8180X_NOTIFY_IND 0x13
+#define USBC_CMD_WRITE_REQ 0x15
+#define USBC_NOTIFY_IND 0x16
+
+#define ALTMODE_PAN_EN 0x10
+#define ALTMODE_PAN_ACK 0x11
+
+struct usbc_write_req {
+ struct pmic_glink_hdr hdr;
+ __le32 cmd;
+ __le32 arg;
+ __le32 reserved;
+};
+
+#define NOTIFY_PAYLOAD_SIZE 16
+struct usbc_notify {
+ struct pmic_glink_hdr hdr;
+ char payload[NOTIFY_PAYLOAD_SIZE];
+ u32 reserved;
+};
+
+struct usbc_sc8180x_notify {
+ struct pmic_glink_hdr hdr;
+ __le32 notification;
+ __le32 reserved[2];
+};
+
+enum pmic_glink_altmode_pin_assignment {
+ DPAM_HPD_OUT,
+ DPAM_HPD_A,
+ DPAM_HPD_B,
+ DPAM_HPD_C,
+ DPAM_HPD_D,
+ DPAM_HPD_E,
+ DPAM_HPD_F,
+};
+
+struct pmic_glink_altmode;
+
+#define work_to_altmode_port(w) container_of((w), struct pmic_glink_altmode_port, work)
+
+struct pmic_glink_altmode_port {
+ struct pmic_glink_altmode *altmode;
+ unsigned int index;
+
+ struct typec_switch *typec_switch;
+ struct typec_mux *typec_mux;
+ struct typec_mux_state state;
+ struct typec_altmode dp_alt;
+
+ struct work_struct work;
+
+ struct drm_bridge bridge;
+
+ enum typec_orientation orientation;
+ u16 svid;
+ u8 dp_data;
+ u8 mode;
+ u8 hpd_state;
+ u8 hpd_irq;
+};
+
+#define work_to_altmode(w) container_of((w), struct pmic_glink_altmode, enable_work)
+
+struct pmic_glink_altmode {
+ struct device *dev;
+
+ unsigned int owner_id;
+
+ /* To synchronize WRITE_REQ acks */
+ struct mutex lock;
+
+ struct completion pan_ack;
+ struct pmic_glink_client *client;
+
+ struct work_struct enable_work;
+
+ struct pmic_glink_altmode_port ports[PMIC_GLINK_MAX_PORTS];
+};
+
+static int pmic_glink_altmode_request(struct pmic_glink_altmode *altmode, u32 cmd, u32 arg)
+{
+ struct usbc_write_req req = {};
+ unsigned long left;
+ int ret;
+
+ /*
+ * The USBC_CMD_WRITE_REQ ack doesn't identify the request, so wait for
+ * one ack at a time.
+ */
+ mutex_lock(&altmode->lock);
+
+ req.hdr.owner = cpu_to_le32(altmode->owner_id);
+ req.hdr.type = cpu_to_le32(PMIC_GLINK_REQ_RESP);
+ req.hdr.opcode = cpu_to_le32(USBC_CMD_WRITE_REQ);
+ req.cmd = cpu_to_le32(cmd);
+ req.arg = cpu_to_le32(arg);
+
+ ret = pmic_glink_send(altmode->client, &req, sizeof(req));
+ if (ret) {
+ dev_err(altmode->dev, "failed to send altmode request: %#x (%d)\n", cmd, ret);
+ goto out_unlock;
+ }
+
+ left = wait_for_completion_timeout(&altmode->pan_ack, 5 * HZ);
+ if (!left) {
+ dev_err(altmode->dev, "timeout waiting for altmode request ack for: %#x\n", cmd);
+ ret = -ETIMEDOUT;
+ }
+
+out_unlock:
+ mutex_unlock(&altmode->lock);
+ return ret;
+}
+
+static void pmic_glink_altmode_enable_dp(struct pmic_glink_altmode *altmode,
+ struct pmic_glink_altmode_port *port,
+ u8 mode, bool hpd_state,
+ bool hpd_irq)
+{
+ struct typec_displayport_data dp_data = {};
+ int ret;
+
+ dp_data.status = DP_STATUS_ENABLED;
+ if (hpd_state)
+ dp_data.status |= DP_STATUS_HPD_STATE;
+ if (hpd_irq)
+ dp_data.status |= DP_STATUS_IRQ_HPD;
+ dp_data.conf = DP_CONF_SET_PIN_ASSIGN(mode);
+
+ port->state.alt = &port->dp_alt;
+ port->state.data = &dp_data;
+ port->state.mode = TYPEC_MODAL_STATE(mode);
+
+ ret = typec_mux_set(port->typec_mux, &port->state);
+ if (ret)
+ dev_err(altmode->dev, "failed to switch mux to DP\n");
+}
+
+static void pmic_glink_altmode_enable_usb(struct pmic_glink_altmode *altmode,
+ struct pmic_glink_altmode_port *port)
+{
+ int ret;
+
+ port->state.alt = NULL;
+ port->state.data = NULL;
+ port->state.mode = TYPEC_STATE_USB;
+
+ ret = typec_mux_set(port->typec_mux, &port->state);
+ if (ret)
+ dev_err(altmode->dev, "failed to switch mux to USB\n");
+}
+
+static void pmic_glink_altmode_worker(struct work_struct *work)
+{
+ struct pmic_glink_altmode_port *alt_port = work_to_altmode_port(work);
+ struct pmic_glink_altmode *altmode = alt_port->altmode;
+
+ typec_switch_set(alt_port->typec_switch, alt_port->orientation);
+
+ if (alt_port->svid == USB_TYPEC_DP_SID)
+ pmic_glink_altmode_enable_dp(altmode, alt_port, alt_port->mode,
+ alt_port->hpd_state, alt_port->hpd_irq);
+ else
+ pmic_glink_altmode_enable_usb(altmode, alt_port);
+
+ if (alt_port->hpd_state)
+ drm_bridge_hpd_notify(&alt_port->bridge, connector_status_connected);
+ else
+ drm_bridge_hpd_notify(&alt_port->bridge, connector_status_disconnected);
+
+ pmic_glink_altmode_request(altmode, ALTMODE_PAN_ACK, alt_port->index);
+};
+
+static enum typec_orientation pmic_glink_altmode_orientation(unsigned int orientation)
+{
+ if (orientation == 0)
+ return TYPEC_ORIENTATION_NORMAL;
+ else if (orientation == 1)
+ return TYPEC_ORIENTATION_REVERSE;
+ else
+ return TYPEC_ORIENTATION_NONE;
+}
+
+#define SC8180X_PORT_MASK 0x000000ff
+#define SC8180X_ORIENTATION_MASK 0x0000ff00
+#define SC8180X_MUX_MASK 0x00ff0000
+#define SC8180X_MODE_MASK 0x3f000000
+#define SC8180X_HPD_STATE_MASK 0x40000000
+#define SC8180X_HPD_IRQ_MASK 0x80000000
+
+static void pmic_glink_altmode_sc8180xp_notify(struct pmic_glink_altmode *altmode,
+ const void *data, size_t len)
+{
+ struct pmic_glink_altmode_port *alt_port;
+ const struct usbc_sc8180x_notify *msg;
+ u32 notification;
+ u8 orientation;
+ u8 hpd_state;
+ u8 hpd_irq;
+ u16 svid;
+ u8 port;
+ u8 mode;
+ u8 mux;
+
+ if (len != sizeof(*msg)) {
+ dev_warn(altmode->dev, "invalid length of USBC_NOTIFY indication: %zd\n", len);
+ return;
+ }
+
+ msg = data;
+ notification = le32_to_cpu(msg->notification);
+ port = FIELD_GET(SC8180X_PORT_MASK, notification);
+ orientation = FIELD_GET(SC8180X_ORIENTATION_MASK, notification);
+ mux = FIELD_GET(SC8180X_MUX_MASK, notification);
+ mode = FIELD_GET(SC8180X_MODE_MASK, notification);
+ hpd_state = FIELD_GET(SC8180X_HPD_STATE_MASK, notification);
+ hpd_irq = FIELD_GET(SC8180X_HPD_IRQ_MASK, notification);
+
+ svid = mux == 2 ? USB_TYPEC_DP_SID : 0;
+
+ if (!altmode->ports[port].altmode) {
+ dev_dbg(altmode->dev, "notification on undefined port %d\n", port);
+ return;
+ }
+
+ alt_port = &altmode->ports[port];
+ alt_port->orientation = pmic_glink_altmode_orientation(orientation);
+ alt_port->svid = svid;
+ alt_port->mode = mode;
+ alt_port->hpd_state = hpd_state;
+ alt_port->hpd_irq = hpd_irq;
+ schedule_work(&alt_port->work);
+}
+
+#define SC8280XP_DPAM_MASK 0x3f
+#define SC8280XP_HPD_STATE_MASK BIT(6)
+#define SC8280XP_HPD_IRQ_MASK BIT(7)
+
+static void pmic_glink_altmode_sc8280xp_notify(struct pmic_glink_altmode *altmode,
+ u16 svid, const void *data, size_t len)
+{
+ struct pmic_glink_altmode_port *alt_port;
+ const struct usbc_notify *notify;
+ u8 orientation;
+ u8 hpd_state;
+ u8 hpd_irq;
+ u8 mode;
+ u8 port;
+
+ if (len != sizeof(*notify)) {
+ dev_warn(altmode->dev, "invalid length USBC_NOTIFY_IND: %zd\n",
+ len);
+ return;
+ }
+
+ notify = data;
+
+ port = notify->payload[0];
+ orientation = notify->payload[1];
+ mode = FIELD_GET(SC8280XP_DPAM_MASK, notify->payload[8]) - DPAM_HPD_A;
+ hpd_state = FIELD_GET(SC8280XP_HPD_STATE_MASK, notify->payload[8]);
+ hpd_irq = FIELD_GET(SC8280XP_HPD_IRQ_MASK, notify->payload[8]);
+
+ if (!altmode->ports[port].altmode) {
+ dev_dbg(altmode->dev, "notification on undefined port %d\n", port);
+ return;
+ }
+
+ alt_port = &altmode->ports[port];
+ alt_port->orientation = pmic_glink_altmode_orientation(orientation);
+ alt_port->svid = svid;
+ alt_port->mode = mode;
+ alt_port->hpd_state = hpd_state;
+ alt_port->hpd_irq = hpd_irq;
+ schedule_work(&alt_port->work);
+}
+
+static void pmic_glink_altmode_callback(const void *data, size_t len, void *priv)
+{
+ struct pmic_glink_altmode *altmode = priv;
+ const struct pmic_glink_hdr *hdr = data;
+ u16 opcode;
+ u16 svid;
+
+ opcode = le32_to_cpu(hdr->opcode) & 0xff;
+ svid = le32_to_cpu(hdr->opcode) >> 16;
+
+ switch (opcode) {
+ case USBC_CMD_WRITE_REQ:
+ complete(&altmode->pan_ack);
+ break;
+ case USBC_NOTIFY_IND:
+ pmic_glink_altmode_sc8280xp_notify(altmode, svid, data, len);
+ break;
+ case USBC_SC8180X_NOTIFY_IND:
+ pmic_glink_altmode_sc8180xp_notify(altmode, data, len);
+ break;
+ }
+}
+
+static int pmic_glink_altmode_attach(struct drm_bridge *bridge,
+ enum drm_bridge_attach_flags flags)
+{
+ return flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR ? 0 : -EINVAL;
+}
+
+static const struct drm_bridge_funcs pmic_glink_altmode_bridge_funcs = {
+ .attach = pmic_glink_altmode_attach,
+};
+
+static void pmic_glink_altmode_put_mux(void *data)
+{
+ typec_mux_put(data);
+}
+
+static void pmic_glink_altmode_put_switch(void *data)
+{
+ typec_switch_put(data);
+}
+
+static void pmic_glink_altmode_enable_worker(struct work_struct *work)
+{
+ struct pmic_glink_altmode *altmode = work_to_altmode(work);
+ int ret;
+
+ ret = pmic_glink_altmode_request(altmode, ALTMODE_PAN_EN, 0);
+ if (ret)
+ dev_err(altmode->dev, "failed to request altmode notifications\n");
+}
+
+static void pmic_glink_altmode_pdr_notify(void *priv, int state)
+{
+ struct pmic_glink_altmode *altmode = priv;
+
+ if (state == SERVREG_SERVICE_STATE_UP)
+ schedule_work(&altmode->enable_work);
+}
+
+static const struct of_device_id pmic_glink_altmode_of_quirks[] = {
+ { .compatible = "qcom,sc8180x-pmic-glink", .data = (void *)PMIC_GLINK_OWNER_USBC },
+ {}
+};
+
+static int pmic_glink_altmode_probe(struct auxiliary_device *adev,
+ const struct auxiliary_device_id *id)
+{
+ struct pmic_glink_altmode_port *alt_port;
+ struct pmic_glink_altmode *altmode;
+ struct typec_altmode_desc mux_desc = {};
+ const struct of_device_id *match;
+ struct fwnode_handle *fwnode;
+ struct device *dev = &adev->dev;
+ u32 port;
+ int ret;
+
+ altmode = devm_kzalloc(dev, sizeof(*altmode), GFP_KERNEL);
+ if (!altmode)
+ return -ENOMEM;
+
+ altmode->dev = dev;
+
+ match = of_match_device(pmic_glink_altmode_of_quirks, dev->parent);
+ if (match)
+ altmode->owner_id = (unsigned long)match->data;
+ else
+ altmode->owner_id = PMIC_GLINK_OWNER_USBC_PAN;
+
+ INIT_WORK(&altmode->enable_work, pmic_glink_altmode_enable_worker);
+ init_completion(&altmode->pan_ack);
+ mutex_init(&altmode->lock);
+
+ device_for_each_child_node(dev, fwnode) {
+ ret = fwnode_property_read_u32(fwnode, "reg", &port);
+ if (ret < 0) {
+ dev_err(dev, "missing reg property of %pOFn\n", fwnode);
+ return ret;
+ }
+
+ if (port >= ARRAY_SIZE(altmode->ports)) {
+ dev_warn(dev, "invalid connector number, ignoring\n");
+ continue;
+ }
+
+ if (altmode->ports[port].altmode) {
+ dev_err(dev, "multiple connector definition for port %u\n", port);
+ return -EINVAL;
+ }
+
+ alt_port = &altmode->ports[port];
+ alt_port->altmode = altmode;
+ alt_port->index = port;
+ INIT_WORK(&alt_port->work, pmic_glink_altmode_worker);
+
+ alt_port->bridge.funcs = &pmic_glink_altmode_bridge_funcs;
+ alt_port->bridge.of_node = to_of_node(fwnode);
+ alt_port->bridge.ops = DRM_BRIDGE_OP_HPD;
+ alt_port->bridge.type = DRM_MODE_CONNECTOR_USB;
+
+ ret = devm_drm_bridge_add(dev, &alt_port->bridge);
+ if (ret)
+ return ret;
+
+ alt_port->dp_alt.svid = USB_TYPEC_DP_SID;
+ alt_port->dp_alt.mode = USB_TYPEC_DP_MODE;
+ alt_port->dp_alt.active = 1;
+
+ mux_desc.svid = USB_TYPEC_DP_SID;
+ mux_desc.mode = USB_TYPEC_DP_MODE;
+ alt_port->typec_mux = fwnode_typec_mux_get(fwnode, &mux_desc);
+ if (IS_ERR(alt_port->typec_mux))
+ return dev_err_probe(dev, PTR_ERR(alt_port->typec_mux),
+ "failed to acquire mode-switch for port: %d\n",
+ port);
+
+ ret = devm_add_action_or_reset(dev, pmic_glink_altmode_put_mux,
+ alt_port->typec_mux);
+ if (ret)
+ return ret;
+
+ alt_port->typec_switch = fwnode_typec_switch_get(fwnode);
+ if (IS_ERR(alt_port->typec_switch))
+ return dev_err_probe(dev, PTR_ERR(alt_port->typec_switch),
+ "failed to acquire orientation-switch for port: %d\n",
+ port);
+
+ ret = devm_add_action_or_reset(dev, pmic_glink_altmode_put_switch,
+ alt_port->typec_switch);
+ if (ret)
+ return ret;
+ }
+
+ altmode->client = devm_pmic_glink_register_client(dev,
+ altmode->owner_id,
+ pmic_glink_altmode_callback,
+ pmic_glink_altmode_pdr_notify,
+ altmode);
+ return PTR_ERR_OR_ZERO(altmode->client);
+}
+
+static const struct auxiliary_device_id pmic_glink_altmode_id_table[] = {
+ { .name = "pmic_glink.altmode", },
+ {},
+};
+MODULE_DEVICE_TABLE(auxiliary, pmic_glink_altmode_id_table);
+
+static struct auxiliary_driver pmic_glink_altmode_driver = {
+ .name = "pmic_glink_altmode",
+ .probe = pmic_glink_altmode_probe,
+ .id_table = pmic_glink_altmode_id_table,
+};
+
+module_auxiliary_driver(pmic_glink_altmode_driver);
+
+MODULE_DESCRIPTION("Qualcomm PMIC GLINK Altmode driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c
index f0475b93ca73..795a2e1d59b3 100644
--- a/drivers/soc/qcom/qcom-geni-se.c
+++ b/drivers/soc/qcom/qcom-geni-se.c
@@ -14,7 +14,7 @@
#include <linux/of_platform.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
-#include <linux/qcom-geni-se.h>
+#include <linux/soc/qcom/geni-se.h>
/**
* DOC: Overview
diff --git a/drivers/soc/qcom/qcom_stats.c b/drivers/soc/qcom/qcom_stats.c
index 6228af057120..c207bb96c523 100644
--- a/drivers/soc/qcom/qcom_stats.c
+++ b/drivers/soc/qcom/qcom_stats.c
@@ -92,7 +92,7 @@ static int qcom_subsystem_sleep_stats_show(struct seq_file *s, void *unused)
/* Items are allocated lazily, so lookup pointer each time */
stat = qcom_smem_get(subsystem->pid, subsystem->smem_item, NULL);
if (IS_ERR(stat))
- return -EIO;
+ return 0;
qcom_print_stats(s, stat);
@@ -170,20 +170,14 @@ static void qcom_create_soc_sleep_stat_files(struct dentry *root, void __iomem *
static void qcom_create_subsystem_stat_files(struct dentry *root,
const struct stats_config *config)
{
- const struct sleep_stats *stat;
int i;
if (!config->subsystem_stats_in_smem)
return;
- for (i = 0; i < ARRAY_SIZE(subsystems); i++) {
- stat = qcom_smem_get(subsystems[i].pid, subsystems[i].smem_item, NULL);
- if (IS_ERR(stat))
- continue;
-
+ for (i = 0; i < ARRAY_SIZE(subsystems); i++)
debugfs_create_file(subsystems[i].name, 0400, root, (void *)&subsystems[i],
&qcom_subsystem_sleep_stats_fops);
- }
}
static int qcom_stats_probe(struct platform_device *pdev)
diff --git a/drivers/soc/qcom/ramp_controller.c b/drivers/soc/qcom/ramp_controller.c
new file mode 100644
index 000000000000..dc74d2a19de2
--- /dev/null
+++ b/drivers/soc/qcom/ramp_controller.c
@@ -0,0 +1,343 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Qualcomm Ramp Controller driver
+ * Copyright (c) 2022, AngeloGioacchino Del Regno
+ * <angelogioacchino.delregno@collabora.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+
+#define RC_UPDATE_EN BIT(0)
+#define RC_ROOT_EN BIT(1)
+
+#define RC_REG_CFG_UPDATE 0x60
+#define RC_CFG_UPDATE_EN BIT(8)
+#define RC_CFG_ACK GENMASK(31, 16)
+
+#define RC_DCVS_CFG_SID 2
+#define RC_LINK_SID 3
+#define RC_LMH_SID 6
+#define RC_DFS_SID 14
+
+#define RC_UPDATE_TIMEOUT_US 500
+
+/**
+ * struct qcom_ramp_controller_desc - SoC specific parameters
+ * @cfg_dfs_sid: Dynamic Frequency Scaling SID configuration
+ * @cfg_link_sid: Link SID configuration
+ * @cfg_lmh_sid: Limits Management hardware SID configuration
+ * @cfg_ramp_en: Ramp Controller enable sequence
+ * @cfg_ramp_dis: Ramp Controller disable sequence
+ * @cmd_reg: Command register offset
+ * @num_dfs_sids: Number of DFS SIDs (max 8)
+ * @num_link_sids: Number of Link SIDs (max 3)
+ * @num_lmh_sids: Number of LMh SIDs (max 8)
+ * @num_ramp_en: Number of entries in enable sequence
+ * @num_ramp_dis: Number of entries in disable sequence
+ */
+struct qcom_ramp_controller_desc {
+ const struct reg_sequence *cfg_dfs_sid;
+ const struct reg_sequence *cfg_link_sid;
+ const struct reg_sequence *cfg_lmh_sid;
+ const struct reg_sequence *cfg_ramp_en;
+ const struct reg_sequence *cfg_ramp_dis;
+ u8 cmd_reg;
+ u8 num_dfs_sids;
+ u8 num_link_sids;
+ u8 num_lmh_sids;
+ u8 num_ramp_en;
+ u8 num_ramp_dis;
+};
+
+/**
+ * struct qcom_ramp_controller - Main driver structure
+ * @regmap: Regmap handle
+ * @desc: SoC specific parameters
+ */
+struct qcom_ramp_controller {
+ struct regmap *regmap;
+ const struct qcom_ramp_controller_desc *desc;
+};
+
+/**
+ * rc_wait_for_update() - Wait for Ramp Controller root update
+ * @qrc: Main driver structure
+ *
+ * Return: Zero for success or negative number for failure
+ */
+static int rc_wait_for_update(struct qcom_ramp_controller *qrc)
+{
+ const struct qcom_ramp_controller_desc *d = qrc->desc;
+ struct regmap *r = qrc->regmap;
+ u32 val;
+ int ret;
+
+ ret = regmap_set_bits(r, d->cmd_reg, RC_ROOT_EN);
+ if (ret)
+ return ret;
+
+ return regmap_read_poll_timeout(r, d->cmd_reg, val, !(val & RC_UPDATE_EN),
+ 1, RC_UPDATE_TIMEOUT_US);
+}
+
+/**
+ * rc_set_cfg_update() - Ramp Controller configuration update
+ * @qrc: Main driver structure
+ * @ce: Configuration entry to update
+ *
+ * Return: Zero for success or negative number for failure
+ */
+static int rc_set_cfg_update(struct qcom_ramp_controller *qrc, u8 ce)
+{
+ const struct qcom_ramp_controller_desc *d = qrc->desc;
+ struct regmap *r = qrc->regmap;
+ u32 ack, val;
+ int ret;
+
+ /* The ack bit is between bits 16-31 of RC_REG_CFG_UPDATE */
+ ack = FIELD_PREP(RC_CFG_ACK, BIT(ce));
+
+ /* Write the configuration type first... */
+ ret = regmap_set_bits(r, d->cmd_reg + RC_REG_CFG_UPDATE, ce);
+ if (ret)
+ return ret;
+
+ /* ...and after that, enable the update bit to sync the changes */
+ ret = regmap_set_bits(r, d->cmd_reg + RC_REG_CFG_UPDATE, RC_CFG_UPDATE_EN);
+ if (ret)
+ return ret;
+
+ /* Wait for the changes to go through */
+ ret = regmap_read_poll_timeout(r, d->cmd_reg + RC_REG_CFG_UPDATE, val,
+ val & ack, 1, RC_UPDATE_TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ /*
+ * Configuration update success! The CFG_UPDATE register will not be
+ * cleared automatically upon applying the configuration, so we have
+ * to do that manually in order to leave the ramp controller in a
+ * predictable and clean state.
+ */
+ ret = regmap_write(r, d->cmd_reg + RC_REG_CFG_UPDATE, 0);
+ if (ret)
+ return ret;
+
+ /* Wait for the update bit cleared ack */
+ return regmap_read_poll_timeout(r, d->cmd_reg + RC_REG_CFG_UPDATE,
+ val, !(val & RC_CFG_ACK), 1,
+ RC_UPDATE_TIMEOUT_US);
+}
+
+/**
+ * rc_write_cfg - Send configuration sequence
+ * @qrc: Main driver structure
+ * @seq: Register sequence to send before asking for update
+ * @ce: Configuration SID
+ * @nsids: Total number of SIDs
+ *
+ * Returns: Zero for success or negative number for error
+ */
+static int rc_write_cfg(struct qcom_ramp_controller *qrc,
+ const struct reg_sequence *seq,
+ u16 ce, u8 nsids)
+{
+ int ret;
+ u8 i;
+
+ /* Check if, and wait until the ramp controller is ready */
+ ret = rc_wait_for_update(qrc);
+ if (ret)
+ return ret;
+
+ /* Write the sequence */
+ ret = regmap_multi_reg_write(qrc->regmap, seq, nsids);
+ if (ret)
+ return ret;
+
+ /* Pull the trigger: do config update starting from the last sid */
+ for (i = 0; i < nsids; i++) {
+ ret = rc_set_cfg_update(qrc, (u8)ce - i);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * rc_ramp_ctrl_enable() - Enable Ramp up/down Control
+ * @qrc: Main driver structure
+ *
+ * Return: Zero for success or negative number for error
+ */
+static int rc_ramp_ctrl_enable(struct qcom_ramp_controller *qrc)
+{
+ const struct qcom_ramp_controller_desc *d = qrc->desc;
+ int i, ret;
+
+ for (i = 0; i < d->num_ramp_en; i++) {
+ ret = rc_write_cfg(qrc, &d->cfg_ramp_en[i], RC_DCVS_CFG_SID, 1);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * qcom_ramp_controller_start() - Initialize and start the ramp controller
+ * @qrc: Main driver structure
+ *
+ * The Ramp Controller needs to be initialized by programming the relevant
+ * registers with SoC-specific configuration: once programming is done,
+ * the hardware will take care of the rest (no further handling required).
+ *
+ * Return: Zero for success or negative number for error
+ */
+static int qcom_ramp_controller_start(struct qcom_ramp_controller *qrc)
+{
+ const struct qcom_ramp_controller_desc *d = qrc->desc;
+ int ret;
+
+ /* Program LMH, DFS, Link SIDs */
+ ret = rc_write_cfg(qrc, d->cfg_lmh_sid, RC_LMH_SID, d->num_lmh_sids);
+ if (ret)
+ return ret;
+
+ ret = rc_write_cfg(qrc, d->cfg_dfs_sid, RC_DFS_SID, d->num_dfs_sids);
+ if (ret)
+ return ret;
+
+ ret = rc_write_cfg(qrc, d->cfg_link_sid, RC_LINK_SID, d->num_link_sids);
+ if (ret)
+ return ret;
+
+ /* Everything is ready! Enable the ramp up/down control */
+ return rc_ramp_ctrl_enable(qrc);
+}
+
+static const struct regmap_config qrc_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x68,
+ .fast_io = true,
+};
+
+static const struct reg_sequence msm8976_cfg_dfs_sid[] = {
+ { 0x10, 0xfefebff7 },
+ { 0x14, 0xfdff7fef },
+ { 0x18, 0xfbffdefb },
+ { 0x1c, 0xb69b5555 },
+ { 0x20, 0x24929249 },
+ { 0x24, 0x49241112 },
+ { 0x28, 0x11112111 },
+ { 0x2c, 0x8102 }
+};
+
+static const struct reg_sequence msm8976_cfg_link_sid[] = {
+ { 0x40, 0xfc987 }
+};
+
+static const struct reg_sequence msm8976_cfg_lmh_sid[] = {
+ { 0x30, 0x77706db },
+ { 0x34, 0x5550249 },
+ { 0x38, 0x111 }
+};
+
+static const struct reg_sequence msm8976_cfg_ramp_en[] = {
+ { 0x50, 0x800 }, /* pre_en */
+ { 0x50, 0xc00 }, /* en */
+ { 0x50, 0x400 } /* post_en */
+};
+
+static const struct reg_sequence msm8976_cfg_ramp_dis[] = {
+ { 0x50, 0x0 }
+};
+
+static const struct qcom_ramp_controller_desc msm8976_rc_cfg = {
+ .cfg_dfs_sid = msm8976_cfg_dfs_sid,
+ .num_dfs_sids = ARRAY_SIZE(msm8976_cfg_dfs_sid),
+
+ .cfg_link_sid = msm8976_cfg_link_sid,
+ .num_link_sids = ARRAY_SIZE(msm8976_cfg_link_sid),
+
+ .cfg_lmh_sid = msm8976_cfg_lmh_sid,
+ .num_lmh_sids = ARRAY_SIZE(msm8976_cfg_lmh_sid),
+
+ .cfg_ramp_en = msm8976_cfg_ramp_en,
+ .num_ramp_en = ARRAY_SIZE(msm8976_cfg_ramp_en),
+
+ .cfg_ramp_dis = msm8976_cfg_ramp_dis,
+ .num_ramp_dis = ARRAY_SIZE(msm8976_cfg_ramp_dis),
+
+ .cmd_reg = 0x0,
+};
+
+static int qcom_ramp_controller_probe(struct platform_device *pdev)
+{
+ struct qcom_ramp_controller *qrc;
+ void __iomem *base;
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ qrc = devm_kmalloc(&pdev->dev, sizeof(*qrc), GFP_KERNEL);
+ if (!qrc)
+ return -ENOMEM;
+
+ qrc->desc = device_get_match_data(&pdev->dev);
+ if (!qrc)
+ return -EINVAL;
+
+ qrc->regmap = devm_regmap_init_mmio(&pdev->dev, base, &qrc_regmap_config);
+ if (IS_ERR(qrc->regmap))
+ return PTR_ERR(qrc->regmap);
+
+ platform_set_drvdata(pdev, qrc);
+
+ return qcom_ramp_controller_start(qrc);
+}
+
+static int qcom_ramp_controller_remove(struct platform_device *pdev)
+{
+ struct qcom_ramp_controller *qrc = platform_get_drvdata(pdev);
+
+ return rc_write_cfg(qrc, qrc->desc->cfg_ramp_dis,
+ RC_DCVS_CFG_SID, qrc->desc->num_ramp_dis);
+}
+
+static const struct of_device_id qcom_ramp_controller_match_table[] = {
+ { .compatible = "qcom,msm8976-ramp-controller", .data = &msm8976_rc_cfg },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, qcom_ramp_controller_match_table);
+
+static struct platform_driver qcom_ramp_controller_driver = {
+ .driver = {
+ .name = "qcom-ramp-controller",
+ .of_match_table = qcom_ramp_controller_match_table,
+ .suppress_bind_attrs = true,
+ },
+ .probe = qcom_ramp_controller_probe,
+ .remove = qcom_ramp_controller_remove,
+};
+
+static int __init qcom_ramp_controller_init(void)
+{
+ return platform_driver_register(&qcom_ramp_controller_driver);
+}
+arch_initcall(qcom_ramp_controller_init);
+
+MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>");
+MODULE_DESCRIPTION("Qualcomm Ramp Controller driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/qcom/rmtfs_mem.c b/drivers/soc/qcom/rmtfs_mem.c
index 0feaae357821..2d3ee22b9249 100644
--- a/drivers/soc/qcom/rmtfs_mem.c
+++ b/drivers/soc/qcom/rmtfs_mem.c
@@ -14,9 +14,10 @@
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/io.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#define QCOM_RMTFS_MEM_DEV_MAX (MINORMASK + 1)
+#define NUM_MAX_VMIDS 2
static dev_t qcom_rmtfs_mem_major;
@@ -171,12 +172,12 @@ static void qcom_rmtfs_mem_release_device(struct device *dev)
static int qcom_rmtfs_mem_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
- struct qcom_scm_vmperm perms[2];
+ struct qcom_scm_vmperm perms[NUM_MAX_VMIDS + 1];
struct reserved_mem *rmem;
struct qcom_rmtfs_mem *rmtfs_mem;
u32 client_id;
- u32 vmid;
- int ret;
+ u32 num_vmids, vmid[NUM_MAX_VMIDS];
+ int ret, i;
rmem = of_reserved_mem_lookup(node);
if (!rmem) {
@@ -226,7 +227,18 @@ static int qcom_rmtfs_mem_probe(struct platform_device *pdev)
goto put_device;
}
- ret = of_property_read_u32(node, "qcom,vmid", &vmid);
+ num_vmids = of_property_count_u32_elems(node, "qcom,vmid");
+ if (num_vmids < 0) {
+ dev_err(&pdev->dev, "failed to count qcom,vmid elements: %d\n", ret);
+ goto remove_cdev;
+ } else if (num_vmids > NUM_MAX_VMIDS) {
+ dev_warn(&pdev->dev,
+ "too many VMIDs (%d) specified! Only mapping first %d entries\n",
+ num_vmids, NUM_MAX_VMIDS);
+ num_vmids = NUM_MAX_VMIDS;
+ }
+
+ ret = of_property_read_u32_array(node, "qcom,vmid", vmid, num_vmids);
if (ret < 0 && ret != -EINVAL) {
dev_err(&pdev->dev, "failed to parse qcom,vmid\n");
goto remove_cdev;
@@ -238,12 +250,15 @@ static int qcom_rmtfs_mem_probe(struct platform_device *pdev)
perms[0].vmid = QCOM_SCM_VMID_HLOS;
perms[0].perm = QCOM_SCM_PERM_RW;
- perms[1].vmid = vmid;
- perms[1].perm = QCOM_SCM_PERM_RW;
+
+ for (i = 0; i < num_vmids; i++) {
+ perms[i + 1].vmid = vmid[i];
+ perms[i + 1].perm = QCOM_SCM_PERM_RW;
+ }
rmtfs_mem->perms = BIT(QCOM_SCM_VMID_HLOS);
ret = qcom_scm_assign_mem(rmtfs_mem->addr, rmtfs_mem->size,
- &rmtfs_mem->perms, perms, 2);
+ &rmtfs_mem->perms, perms, num_vmids + 1);
if (ret < 0) {
dev_err(&pdev->dev, "assign memory failed\n");
goto remove_cdev;
diff --git a/drivers/soc/qcom/rpmhpd.c b/drivers/soc/qcom/rpmhpd.c
index 4c2d2c296790..f20e2a49a669 100644
--- a/drivers/soc/qcom/rpmhpd.c
+++ b/drivers/soc/qcom/rpmhpd.c
@@ -187,6 +187,16 @@ static struct rpmhpd nsp = {
.res_name = "nsp.lvl",
};
+static struct rpmhpd nsp0 = {
+ .pd = { .name = "nsp0", },
+ .res_name = "nsp0.lvl",
+};
+
+static struct rpmhpd nsp1 = {
+ .pd = { .name = "nsp1", },
+ .res_name = "nsp1.lvl",
+};
+
static struct rpmhpd qphy = {
.pd = { .name = "qphy", },
.res_name = "qphy.lvl",
@@ -212,6 +222,29 @@ static const struct rpmhpd_desc sa8540p_desc = {
.num_pds = ARRAY_SIZE(sa8540p_rpmhpds),
};
+/* SA8775P RPMH power domains */
+static struct rpmhpd *sa8775p_rpmhpds[] = {
+ [SA8775P_CX] = &cx,
+ [SA8775P_CX_AO] = &cx_ao,
+ [SA8775P_EBI] = &ebi,
+ [SA8775P_GFX] = &gfx,
+ [SA8775P_LCX] = &lcx,
+ [SA8775P_LMX] = &lmx,
+ [SA8775P_MMCX] = &mmcx,
+ [SA8775P_MMCX_AO] = &mmcx_ao,
+ [SA8775P_MXC] = &mxc,
+ [SA8775P_MXC_AO] = &mxc_ao,
+ [SA8775P_MX] = &mx,
+ [SA8775P_MX_AO] = &mx_ao,
+ [SA8775P_NSP0] = &nsp0,
+ [SA8775P_NSP1] = &nsp1,
+};
+
+static const struct rpmhpd_desc sa8775p_desc = {
+ .rpmhpds = sa8775p_rpmhpds,
+ .num_pds = ARRAY_SIZE(sa8775p_rpmhpds),
+};
+
/* SDM670 RPMH powerdomains */
static struct rpmhpd *sdm670_rpmhpds[] = {
[SDM670_CX] = &cx_w_mx_parent,
@@ -487,6 +520,7 @@ static const struct rpmhpd_desc sc8280xp_desc = {
static const struct of_device_id rpmhpd_match_table[] = {
{ .compatible = "qcom,qdu1000-rpmhpd", .data = &qdu1000_desc },
{ .compatible = "qcom,sa8540p-rpmhpd", .data = &sa8540p_desc },
+ { .compatible = "qcom,sa8775p-rpmhpd", .data = &sa8775p_desc },
{ .compatible = "qcom,sc7180-rpmhpd", .data = &sc7180_desc },
{ .compatible = "qcom,sc7280-rpmhpd", .data = &sc7280_desc },
{ .compatible = "qcom,sc8180x-rpmhpd", .data = &sc8180x_desc },
diff --git a/drivers/soc/qcom/rpmpd.c b/drivers/soc/qcom/rpmpd.c
index f0db6a10cf4e..337b1ad1cd3b 100644
--- a/drivers/soc/qcom/rpmpd.c
+++ b/drivers/soc/qcom/rpmpd.c
@@ -471,23 +471,6 @@ static const struct rpmpd_desc qcm2290_desc = {
.max_state = RPM_SMD_LEVEL_TURBO_NO_CPR,
};
-static struct rpmpd *sm4250_rpmpds[] = {
- [SM4250_VDDCX] = &sm6115_vddcx,
- [SM4250_VDDCX_AO] = &sm6115_vddcx_ao,
- [SM4250_VDDCX_VFL] = &sm6115_vddcx_vfl,
- [SM4250_VDDMX] = &sm6115_vddmx,
- [SM4250_VDDMX_AO] = &sm6115_vddmx_ao,
- [SM4250_VDDMX_VFL] = &sm6115_vddmx_vfl,
- [SM4250_VDD_LPI_CX] = &sm6115_vdd_lpi_cx,
- [SM4250_VDD_LPI_MX] = &sm6115_vdd_lpi_mx,
-};
-
-static const struct rpmpd_desc sm4250_desc = {
- .rpmpds = sm4250_rpmpds,
- .num_pds = ARRAY_SIZE(sm4250_rpmpds),
- .max_state = RPM_SMD_LEVEL_TURBO_NO_CPR,
-};
-
static const struct of_device_id rpmpd_match_table[] = {
{ .compatible = "qcom,mdm9607-rpmpd", .data = &mdm9607_desc },
{ .compatible = "qcom,msm8226-rpmpd", .data = &msm8226_desc },
@@ -502,7 +485,6 @@ static const struct of_device_id rpmpd_match_table[] = {
{ .compatible = "qcom,qcm2290-rpmpd", .data = &qcm2290_desc },
{ .compatible = "qcom,qcs404-rpmpd", .data = &qcs404_desc },
{ .compatible = "qcom,sdm660-rpmpd", .data = &sdm660_desc },
- { .compatible = "qcom,sm4250-rpmpd", .data = &sm4250_desc },
{ .compatible = "qcom,sm6115-rpmpd", .data = &sm6115_desc },
{ .compatible = "qcom,sm6125-rpmpd", .data = &sm6125_desc },
{ .compatible = "qcom,sm6375-rpmpd", .data = &sm6375_desc },
diff --git a/drivers/soc/qcom/smd-rpm.c b/drivers/soc/qcom/smd-rpm.c
index 7e3b6a7ea34c..523627d5d398 100644
--- a/drivers/soc/qcom/smd-rpm.c
+++ b/drivers/soc/qcom/smd-rpm.c
@@ -233,6 +233,7 @@ static void qcom_smd_rpm_remove(struct rpmsg_device *rpdev)
static const struct of_device_id qcom_smd_rpm_of_match[] = {
{ .compatible = "qcom,rpm-apq8084" },
{ .compatible = "qcom,rpm-ipq6018" },
+ { .compatible = "qcom,rpm-ipq9574" },
{ .compatible = "qcom,rpm-msm8226" },
{ .compatible = "qcom,rpm-msm8909" },
{ .compatible = "qcom,rpm-msm8916" },
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
index ebcbf9b9c18b..e9012ca1a87b 100644
--- a/drivers/soc/qcom/socinfo.c
+++ b/drivers/soc/qcom/socinfo.c
@@ -169,6 +169,13 @@ struct socinfo {
__le32 ndefective_parts_array_offset;
/* Version 15 */
__le32 nmodem_supported;
+ /* Version 16 */
+ __le32 feature_code;
+ __le32 pcode;
+ __le32 npartnamemap_offset;
+ __le32 nnum_partname_mapping;
+ /* Version 17 */
+ __le32 oem_variant;
};
#ifdef CONFIG_DEBUG_FS
@@ -189,6 +196,9 @@ struct socinfo_params {
u32 num_defective_parts;
u32 ndefective_parts_array_offset;
u32 nmodem_supported;
+ u32 feature_code;
+ u32 pcode;
+ u32 oem_variant;
};
struct smem_image_version {
@@ -214,44 +224,72 @@ struct soc_id {
};
static const struct soc_id soc_id[] = {
+ { qcom_board_id(MSM8260) },
+ { qcom_board_id(MSM8660) },
+ { qcom_board_id(APQ8060) },
{ qcom_board_id(MSM8960) },
{ qcom_board_id(APQ8064) },
+ { qcom_board_id(MSM8930) },
+ { qcom_board_id(MSM8630) },
+ { qcom_board_id(MSM8230) },
+ { qcom_board_id(APQ8030) },
+ { qcom_board_id(MSM8627) },
+ { qcom_board_id(MSM8227) },
{ qcom_board_id(MSM8660A) },
{ qcom_board_id(MSM8260A) },
{ qcom_board_id(APQ8060A) },
{ qcom_board_id(MSM8974) },
+ { qcom_board_id(MSM8225) },
+ { qcom_board_id(MSM8625) },
{ qcom_board_id(MPQ8064) },
{ qcom_board_id(MSM8960AB) },
{ qcom_board_id(APQ8060AB) },
{ qcom_board_id(MSM8260AB) },
{ qcom_board_id(MSM8660AB) },
+ { qcom_board_id(MSM8930AA) },
+ { qcom_board_id(MSM8630AA) },
+ { qcom_board_id(MSM8230AA) },
{ qcom_board_id(MSM8626) },
{ qcom_board_id(MSM8610) },
{ qcom_board_id(APQ8064AB) },
+ { qcom_board_id(MSM8930AB) },
+ { qcom_board_id(MSM8630AB) },
+ { qcom_board_id(MSM8230AB) },
+ { qcom_board_id(APQ8030AB) },
{ qcom_board_id(MSM8226) },
{ qcom_board_id(MSM8526) },
+ { qcom_board_id(APQ8030AA) },
{ qcom_board_id(MSM8110) },
{ qcom_board_id(MSM8210) },
{ qcom_board_id(MSM8810) },
{ qcom_board_id(MSM8212) },
{ qcom_board_id(MSM8612) },
{ qcom_board_id(MSM8112) },
+ { qcom_board_id(MSM8125) },
{ qcom_board_id(MSM8225Q) },
{ qcom_board_id(MSM8625Q) },
{ qcom_board_id(MSM8125Q) },
{ qcom_board_id(APQ8064AA) },
{ qcom_board_id(APQ8084) },
+ { qcom_board_id(MSM8130) },
+ { qcom_board_id(MSM8130AA) },
+ { qcom_board_id(MSM8130AB) },
+ { qcom_board_id(MSM8627AA) },
+ { qcom_board_id(MSM8227AA) },
{ qcom_board_id(APQ8074) },
{ qcom_board_id(MSM8274) },
{ qcom_board_id(MSM8674) },
+ { qcom_board_id(MDM9635) },
{ qcom_board_id_named(MSM8974PRO_AC, "MSM8974PRO-AC") },
{ qcom_board_id(MSM8126) },
{ qcom_board_id(APQ8026) },
{ qcom_board_id(MSM8926) },
+ { qcom_board_id(IPQ8062) },
+ { qcom_board_id(IPQ8064) },
+ { qcom_board_id(IPQ8066) },
+ { qcom_board_id(IPQ8068) },
{ qcom_board_id(MSM8326) },
{ qcom_board_id(MSM8916) },
- { qcom_board_id(MSM8956) },
- { qcom_board_id(MSM8976) },
{ qcom_board_id(MSM8994) },
{ qcom_board_id_named(APQ8074PRO_AA, "APQ8074PRO-AA") },
{ qcom_board_id_named(APQ8074PRO_AB, "APQ8074PRO-AB") },
@@ -273,32 +311,74 @@ static const struct soc_id soc_id[] = {
{ qcom_board_id(MSM8510) },
{ qcom_board_id(MSM8512) },
{ qcom_board_id(MSM8936) },
+ { qcom_board_id(MDM9640) },
{ qcom_board_id(MSM8939) },
{ qcom_board_id(APQ8036) },
{ qcom_board_id(APQ8039) },
+ { qcom_board_id(MSM8236) },
+ { qcom_board_id(MSM8636) },
+ { qcom_board_id(MSM8909) },
{ qcom_board_id(MSM8996) },
{ qcom_board_id(APQ8016) },
{ qcom_board_id(MSM8216) },
{ qcom_board_id(MSM8116) },
{ qcom_board_id(MSM8616) },
{ qcom_board_id(MSM8992) },
+ { qcom_board_id(APQ8092) },
{ qcom_board_id(APQ8094) },
+ { qcom_board_id(MSM8209) },
+ { qcom_board_id(MSM8208) },
+ { qcom_board_id(MDM9209) },
+ { qcom_board_id(MDM9309) },
+ { qcom_board_id(MDM9609) },
+ { qcom_board_id(MSM8239) },
+ { qcom_board_id(MSM8952) },
+ { qcom_board_id(APQ8009) },
+ { qcom_board_id(MSM8956) },
+ { qcom_board_id(MSM8929) },
+ { qcom_board_id(MSM8629) },
+ { qcom_board_id(MSM8229) },
+ { qcom_board_id(APQ8029) },
+ { qcom_board_id(APQ8056) },
+ { qcom_board_id(MSM8609) },
+ { qcom_board_id(APQ8076) },
+ { qcom_board_id(MSM8976) },
+ { qcom_board_id(IPQ8065) },
+ { qcom_board_id(IPQ8069) },
+ { qcom_board_id(MDM9650) },
+ { qcom_board_id(MDM9655) },
+ { qcom_board_id(MDM9250) },
+ { qcom_board_id(MDM9255) },
+ { qcom_board_id(MDM9350) },
+ { qcom_board_id(APQ8052) },
{ qcom_board_id(MDM9607) },
{ qcom_board_id(APQ8096) },
{ qcom_board_id(MSM8998) },
{ qcom_board_id(MSM8953) },
+ { qcom_board_id(MSM8937) },
+ { qcom_board_id(APQ8037) },
{ qcom_board_id(MDM8207) },
{ qcom_board_id(MDM9207) },
{ qcom_board_id(MDM9307) },
{ qcom_board_id(MDM9628) },
+ { qcom_board_id(MSM8909W) },
+ { qcom_board_id(APQ8009W) },
+ { qcom_board_id(MSM8996L) },
+ { qcom_board_id(MSM8917) },
{ qcom_board_id(APQ8053) },
{ qcom_board_id(MSM8996SG) },
+ { qcom_board_id(APQ8017) },
+ { qcom_board_id(MSM8217) },
+ { qcom_board_id(MSM8617) },
{ qcom_board_id(MSM8996AU) },
{ qcom_board_id(APQ8096AU) },
{ qcom_board_id(APQ8096SG) },
+ { qcom_board_id(MSM8940) },
+ { qcom_board_id(SDX201) },
{ qcom_board_id(SDM660) },
{ qcom_board_id(SDM630) },
{ qcom_board_id(APQ8098) },
+ { qcom_board_id(MSM8920) },
{ qcom_board_id(SDM845) },
{ qcom_board_id(MDM9206) },
{ qcom_board_id(IPQ8074) },
@@ -306,6 +386,8 @@ static const struct soc_id soc_id[] = {
{ qcom_board_id(SDM658) },
{ qcom_board_id(SDA658) },
{ qcom_board_id(SDA630) },
+ { qcom_board_id(MSM8905) },
+ { qcom_board_id(SDX202) },
{ qcom_board_id(SDM450) },
{ qcom_board_id(SM8150) },
{ qcom_board_id(SDA845) },
@@ -317,10 +399,15 @@ static const struct soc_id soc_id[] = {
{ qcom_board_id(SDM632) },
{ qcom_board_id(SDA632) },
{ qcom_board_id(SDA450) },
+ { qcom_board_id(SDM439) },
+ { qcom_board_id(SDM429) },
{ qcom_board_id(SM8250) },
{ qcom_board_id(SA8155) },
+ { qcom_board_id(SDA439) },
+ { qcom_board_id(SDA429) },
{ qcom_board_id(IPQ8070) },
{ qcom_board_id(IPQ8071) },
+ { qcom_board_id(QM215) },
{ qcom_board_id(IPQ8072A) },
{ qcom_board_id(IPQ8074A) },
{ qcom_board_id(IPQ8076A) },
@@ -330,18 +417,20 @@ static const struct soc_id soc_id[] = {
{ qcom_board_id(IPQ8071A) },
{ qcom_board_id(IPQ6018) },
{ qcom_board_id(IPQ6028) },
+ { qcom_board_id(SDM429W) },
{ qcom_board_id(SM4250) },
{ qcom_board_id(IPQ6000) },
{ qcom_board_id(IPQ6010) },
{ qcom_board_id(SC7180) },
{ qcom_board_id(SM6350) },
+ { qcom_board_id(QCM2150) },
+ { qcom_board_id(SDA429W) },
{ qcom_board_id(SM8350) },
{ qcom_board_id(SM6115) },
{ qcom_board_id(SC8280XP) },
{ qcom_board_id(IPQ6005) },
{ qcom_board_id(QRB5165) },
{ qcom_board_id(SM8450) },
- { qcom_board_id(SM8550) },
{ qcom_board_id(SM7225) },
{ qcom_board_id(SA8295P) },
{ qcom_board_id(SA8540P) },
@@ -352,12 +441,15 @@ static const struct soc_id soc_id[] = {
{ qcom_board_id(SC7280) },
{ qcom_board_id(SC7180P) },
{ qcom_board_id(SM6375) },
+ { qcom_board_id(SM8550) },
{ qcom_board_id(QRU1000) },
{ qcom_board_id(QDU1000) },
{ qcom_board_id(QDU1010) },
{ qcom_board_id(QRU1032) },
{ qcom_board_id(QRU1052) },
{ qcom_board_id(QRU1062) },
+ { qcom_board_id(IPQ5332) },
+ { qcom_board_id(IPQ5322) },
};
static const char *socinfo_machine(struct device *dev, unsigned int id)
@@ -512,6 +604,20 @@ static void socinfo_debugfs_init(struct qcom_socinfo *qcom_socinfo,
&qcom_socinfo->info.fmt);
switch (qcom_socinfo->info.fmt) {
+ case SOCINFO_VERSION(0, 17):
+ qcom_socinfo->info.oem_variant = __le32_to_cpu(info->oem_variant);
+ debugfs_create_u32("oem_variant", 0444, qcom_socinfo->dbg_root,
+ &qcom_socinfo->info.oem_variant);
+ fallthrough;
+ case SOCINFO_VERSION(0, 16):
+ qcom_socinfo->info.feature_code = __le32_to_cpu(info->feature_code);
+ qcom_socinfo->info.pcode = __le32_to_cpu(info->pcode);
+
+ debugfs_create_u32("feature_code", 0444, qcom_socinfo->dbg_root,
+ &qcom_socinfo->info.feature_code);
+ debugfs_create_u32("pcode", 0444, qcom_socinfo->dbg_root,
+ &qcom_socinfo->info.pcode);
+ fallthrough;
case SOCINFO_VERSION(0, 15):
qcom_socinfo->info.nmodem_supported = __le32_to_cpu(info->nmodem_supported);
diff --git a/drivers/soc/renesas/Kconfig b/drivers/soc/renesas/Kconfig
index 660498252ec5..4e8b51ba2266 100644
--- a/drivers/soc/renesas/Kconfig
+++ b/drivers/soc/renesas/Kconfig
@@ -330,6 +330,7 @@ config ARCH_R9A09G011
bool "ARM64 Platform support for RZ/V2M"
select PM
select PM_GENERIC_DOMAINS
+ select PWC_RZV2M
help
This enables support for the Renesas RZ/V2M SoC.
@@ -345,6 +346,9 @@ config ARCH_R9A07G043
endif # RISCV
+config PWC_RZV2M
+ bool "Renesas RZ/V2M PWC support" if COMPILE_TEST
+
config RST_RCAR
bool "Reset Controller support for R-Car" if COMPILE_TEST
diff --git a/drivers/soc/renesas/Makefile b/drivers/soc/renesas/Makefile
index 535868c9c7e4..6e4e77b0afff 100644
--- a/drivers/soc/renesas/Makefile
+++ b/drivers/soc/renesas/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_ARCH_R9A06G032) += r9a06g032-smp.o
endif
# Family
+obj-$(CONFIG_PWC_RZV2M) += pwc-rzv2m.o
obj-$(CONFIG_RST_RCAR) += rcar-rst.o
obj-$(CONFIG_SYSC_RCAR) += rcar-sysc.o
obj-$(CONFIG_SYSC_RCAR_GEN4) += rcar-gen4-sysc.o
diff --git a/drivers/soc/renesas/pwc-rzv2m.c b/drivers/soc/renesas/pwc-rzv2m.c
new file mode 100644
index 000000000000..c83bdbdabb64
--- /dev/null
+++ b/drivers/soc/renesas/pwc-rzv2m.c
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2023 Renesas Electronics Corporation
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio/driver.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+
+#define PWC_PWCRST 0x00
+#define PWC_PWCCKEN 0x04
+#define PWC_PWCCTL 0x50
+#define PWC_GPIO 0x80
+
+#define PWC_PWCRST_RSTSOFTAX 0x1
+#define PWC_PWCCKEN_ENGCKMAIN 0x1
+#define PWC_PWCCTL_PWOFF 0x1
+
+struct rzv2m_pwc_priv {
+ void __iomem *base;
+ struct device *dev;
+ struct gpio_chip gp;
+ DECLARE_BITMAP(ch_en_bits, 2);
+};
+
+static void rzv2m_pwc_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
+{
+ struct rzv2m_pwc_priv *priv = gpiochip_get_data(chip);
+ u32 reg;
+
+ /* BIT 16 enables write to BIT 0, and BIT 17 enables write to BIT 1 */
+ reg = BIT(offset + 16);
+ if (value)
+ reg |= BIT(offset);
+
+ writel(reg, priv->base + PWC_GPIO);
+
+ assign_bit(offset, priv->ch_en_bits, value);
+}
+
+static int rzv2m_pwc_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+ struct rzv2m_pwc_priv *priv = gpiochip_get_data(chip);
+
+ return test_bit(offset, priv->ch_en_bits);
+}
+
+static int rzv2m_pwc_gpio_direction_output(struct gpio_chip *gc,
+ unsigned int nr, int value)
+{
+ if (nr > 1)
+ return -EINVAL;
+
+ rzv2m_pwc_gpio_set(gc, nr, value);
+
+ return 0;
+}
+
+static const struct gpio_chip rzv2m_pwc_gc = {
+ .label = "gpio_rzv2m_pwc",
+ .owner = THIS_MODULE,
+ .get = rzv2m_pwc_gpio_get,
+ .set = rzv2m_pwc_gpio_set,
+ .direction_output = rzv2m_pwc_gpio_direction_output,
+ .can_sleep = false,
+ .ngpio = 2,
+ .base = -1,
+};
+
+static int rzv2m_pwc_poweroff(struct sys_off_data *data)
+{
+ struct rzv2m_pwc_priv *priv = data->cb_data;
+
+ writel(PWC_PWCRST_RSTSOFTAX, priv->base + PWC_PWCRST);
+ writel(PWC_PWCCKEN_ENGCKMAIN, priv->base + PWC_PWCCKEN);
+ writel(PWC_PWCCTL_PWOFF, priv->base + PWC_PWCCTL);
+
+ mdelay(150);
+
+ dev_err(priv->dev, "Failed to power off the system");
+
+ return NOTIFY_DONE;
+}
+
+static int rzv2m_pwc_probe(struct platform_device *pdev)
+{
+ struct rzv2m_pwc_priv *priv;
+ int ret;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ /*
+ * The register used by this driver cannot be read, therefore set the
+ * outputs to their default values and initialize priv->ch_en_bits
+ * accordingly. BIT 16 enables write to BIT 0, BIT 17 enables write to
+ * BIT 1, and the default value of both BIT 0 and BIT 1 is 0.
+ */
+ writel(BIT(17) | BIT(16), priv->base + PWC_GPIO);
+ bitmap_zero(priv->ch_en_bits, 2);
+
+ priv->gp = rzv2m_pwc_gc;
+ priv->gp.parent = pdev->dev.parent;
+ priv->gp.fwnode = dev_fwnode(&pdev->dev);
+
+ ret = devm_gpiochip_add_data(&pdev->dev, &priv->gp, priv);
+ if (ret)
+ return ret;
+
+ if (device_property_read_bool(&pdev->dev, "renesas,rzv2m-pwc-power"))
+ ret = devm_register_power_off_handler(&pdev->dev,
+ rzv2m_pwc_poweroff, priv);
+
+ return ret;
+}
+
+static const struct of_device_id rzv2m_pwc_of_match[] = {
+ { .compatible = "renesas,rzv2m-pwc" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, rzv2m_pwc_of_match);
+
+static struct platform_driver rzv2m_pwc_driver = {
+ .probe = rzv2m_pwc_probe,
+ .driver = {
+ .name = "rzv2m_pwc",
+ .of_match_table = of_match_ptr(rzv2m_pwc_of_match),
+ },
+};
+module_platform_driver(rzv2m_pwc_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Fabrizio Castro <castro.fabrizio.jz@renesas.com>");
+MODULE_DESCRIPTION("Renesas RZ/V2M PWC driver");
diff --git a/drivers/soc/renesas/r8a779g0-sysc.c b/drivers/soc/renesas/r8a779g0-sysc.c
index a452709f066d..b932eba1b804 100644
--- a/drivers/soc/renesas/r8a779g0-sysc.c
+++ b/drivers/soc/renesas/r8a779g0-sysc.c
@@ -37,6 +37,7 @@ static struct rcar_gen4_sysc_area r8a779g0_areas[] __initdata = {
{ "a3vip0", R8A779G0_PD_A3VIP0, R8A779G0_PD_ALWAYS_ON },
{ "a3vip1", R8A779G0_PD_A3VIP1, R8A779G0_PD_ALWAYS_ON },
{ "a3vip2", R8A779G0_PD_A3VIP2, R8A779G0_PD_ALWAYS_ON },
+ { "a3dul", R8A779G0_PD_A3DUL, R8A779G0_PD_ALWAYS_ON },
{ "a3isp0", R8A779G0_PD_A3ISP0, R8A779G0_PD_ALWAYS_ON },
{ "a3isp1", R8A779G0_PD_A3ISP1, R8A779G0_PD_ALWAYS_ON },
{ "a3ir", R8A779G0_PD_A3IR, R8A779G0_PD_ALWAYS_ON },
diff --git a/drivers/soc/renesas/rcar-sysc.c b/drivers/soc/renesas/rcar-sysc.c
index b0a80de34c98..eed47696e825 100644
--- a/drivers/soc/renesas/rcar-sysc.c
+++ b/drivers/soc/renesas/rcar-sysc.c
@@ -437,7 +437,7 @@ static int __init rcar_sysc_pd_init(void)
error = of_genpd_add_provider_onecell(np, &domains->onecell_data);
if (!error)
- of_node_set_flag(np, OF_POPULATED);
+ fwnode_dev_initialized(of_fwnode_handle(np), true);
out_put:
of_node_put(np);
diff --git a/drivers/soc/sifive/Kconfig b/drivers/soc/sifive/Kconfig
index ed4c571f8771..e86870be34c9 100644
--- a/drivers/soc/sifive/Kconfig
+++ b/drivers/soc/sifive/Kconfig
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
-if SOC_SIFIVE
+if SOC_SIFIVE || SOC_STARFIVE
config SIFIVE_CCACHE
bool "Sifive Composable Cache controller"
diff --git a/drivers/soc/starfive/Kconfig b/drivers/soc/starfive/Kconfig
new file mode 100644
index 000000000000..bdb96dc4c989
--- /dev/null
+++ b/drivers/soc/starfive/Kconfig
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0
+
+config JH71XX_PMU
+ bool "Support PMU for StarFive JH71XX Soc"
+ depends on PM
+ depends on SOC_STARFIVE || COMPILE_TEST
+ default SOC_STARFIVE
+ select PM_GENERIC_DOMAINS
+ help
+ Say 'y' here to enable support power domain support.
+ In order to meet low power requirements, a Power Management Unit (PMU)
+ is designed for controlling power resources in StarFive JH71XX SoCs.
diff --git a/drivers/soc/starfive/Makefile b/drivers/soc/starfive/Makefile
new file mode 100644
index 000000000000..13b589d6b5f3
--- /dev/null
+++ b/drivers/soc/starfive/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_JH71XX_PMU) += jh71xx_pmu.o
diff --git a/drivers/soc/starfive/jh71xx_pmu.c b/drivers/soc/starfive/jh71xx_pmu.c
new file mode 100644
index 000000000000..7d5f50d71c0d
--- /dev/null
+++ b/drivers/soc/starfive/jh71xx_pmu.c
@@ -0,0 +1,383 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * StarFive JH71XX PMU (Power Management Unit) Controller Driver
+ *
+ * Copyright (C) 2022 StarFive Technology Co., Ltd.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <dt-bindings/power/starfive,jh7110-pmu.h>
+
+/* register offset */
+#define JH71XX_PMU_SW_TURN_ON_POWER 0x0C
+#define JH71XX_PMU_SW_TURN_OFF_POWER 0x10
+#define JH71XX_PMU_SW_ENCOURAGE 0x44
+#define JH71XX_PMU_TIMER_INT_MASK 0x48
+#define JH71XX_PMU_CURR_POWER_MODE 0x80
+#define JH71XX_PMU_EVENT_STATUS 0x88
+#define JH71XX_PMU_INT_STATUS 0x8C
+
+/* sw encourage cfg */
+#define JH71XX_PMU_SW_ENCOURAGE_EN_LO 0x05
+#define JH71XX_PMU_SW_ENCOURAGE_EN_HI 0x50
+#define JH71XX_PMU_SW_ENCOURAGE_DIS_LO 0x0A
+#define JH71XX_PMU_SW_ENCOURAGE_DIS_HI 0xA0
+#define JH71XX_PMU_SW_ENCOURAGE_ON 0xFF
+
+/* pmu int status */
+#define JH71XX_PMU_INT_SEQ_DONE BIT(0)
+#define JH71XX_PMU_INT_HW_REQ BIT(1)
+#define JH71XX_PMU_INT_SW_FAIL GENMASK(3, 2)
+#define JH71XX_PMU_INT_HW_FAIL GENMASK(5, 4)
+#define JH71XX_PMU_INT_PCH_FAIL GENMASK(8, 6)
+#define JH71XX_PMU_INT_ALL_MASK GENMASK(8, 0)
+
+/*
+ * The time required for switching power status is based on the time
+ * to turn on the largest domain's power, which is at microsecond level
+ */
+#define JH71XX_PMU_TIMEOUT_US 100
+
+struct jh71xx_domain_info {
+ const char * const name;
+ unsigned int flags;
+ u8 bit;
+};
+
+struct jh71xx_pmu_match_data {
+ const struct jh71xx_domain_info *domain_info;
+ int num_domains;
+};
+
+struct jh71xx_pmu {
+ struct device *dev;
+ const struct jh71xx_pmu_match_data *match_data;
+ void __iomem *base;
+ struct generic_pm_domain **genpd;
+ struct genpd_onecell_data genpd_data;
+ int irq;
+ spinlock_t lock; /* protects pmu reg */
+};
+
+struct jh71xx_pmu_dev {
+ const struct jh71xx_domain_info *domain_info;
+ struct jh71xx_pmu *pmu;
+ struct generic_pm_domain genpd;
+};
+
+static int jh71xx_pmu_get_state(struct jh71xx_pmu_dev *pmd, u32 mask, bool *is_on)
+{
+ struct jh71xx_pmu *pmu = pmd->pmu;
+
+ if (!mask)
+ return -EINVAL;
+
+ *is_on = readl(pmu->base + JH71XX_PMU_CURR_POWER_MODE) & mask;
+
+ return 0;
+}
+
+static int jh71xx_pmu_set_state(struct jh71xx_pmu_dev *pmd, u32 mask, bool on)
+{
+ struct jh71xx_pmu *pmu = pmd->pmu;
+ unsigned long flags;
+ u32 val;
+ u32 mode;
+ u32 encourage_lo;
+ u32 encourage_hi;
+ bool is_on;
+ int ret;
+
+ ret = jh71xx_pmu_get_state(pmd, mask, &is_on);
+ if (ret) {
+ dev_dbg(pmu->dev, "unable to get current state for %s\n",
+ pmd->genpd.name);
+ return ret;
+ }
+
+ if (is_on == on) {
+ dev_dbg(pmu->dev, "pm domain [%s] is already %sable status.\n",
+ pmd->genpd.name, on ? "en" : "dis");
+ return 0;
+ }
+
+ spin_lock_irqsave(&pmu->lock, flags);
+
+ /*
+ * The PMU accepts software encourage to switch power mode in the following 2 steps:
+ *
+ * 1.Configure the register SW_TURN_ON_POWER (offset 0x0c) by writing 1 to
+ * the bit corresponding to the power domain that will be turned on
+ * and writing 0 to the others.
+ * Likewise, configure the register SW_TURN_OFF_POWER (offset 0x10) by
+ * writing 1 to the bit corresponding to the power domain that will be
+ * turned off and writing 0 to the others.
+ */
+ if (on) {
+ mode = JH71XX_PMU_SW_TURN_ON_POWER;
+ encourage_lo = JH71XX_PMU_SW_ENCOURAGE_EN_LO;
+ encourage_hi = JH71XX_PMU_SW_ENCOURAGE_EN_HI;
+ } else {
+ mode = JH71XX_PMU_SW_TURN_OFF_POWER;
+ encourage_lo = JH71XX_PMU_SW_ENCOURAGE_DIS_LO;
+ encourage_hi = JH71XX_PMU_SW_ENCOURAGE_DIS_HI;
+ }
+
+ writel(mask, pmu->base + mode);
+
+ /*
+ * 2.Write SW encourage command sequence to the Software Encourage Reg (offset 0x44)
+ * First write SW_MODE_ENCOURAGE_ON to JH71XX_PMU_SW_ENCOURAGE. This will reset
+ * the state machine which parses the command sequence. This register must be
+ * written every time software wants to power on/off a domain.
+ * Then write the lower bits of the command sequence, followed by the upper
+ * bits. The sequence differs between powering on & off a domain.
+ */
+ writel(JH71XX_PMU_SW_ENCOURAGE_ON, pmu->base + JH71XX_PMU_SW_ENCOURAGE);
+ writel(encourage_lo, pmu->base + JH71XX_PMU_SW_ENCOURAGE);
+ writel(encourage_hi, pmu->base + JH71XX_PMU_SW_ENCOURAGE);
+
+ spin_unlock_irqrestore(&pmu->lock, flags);
+
+ /* Wait for the power domain bit to be enabled / disabled */
+ if (on) {
+ ret = readl_poll_timeout_atomic(pmu->base + JH71XX_PMU_CURR_POWER_MODE,
+ val, val & mask,
+ 1, JH71XX_PMU_TIMEOUT_US);
+ } else {
+ ret = readl_poll_timeout_atomic(pmu->base + JH71XX_PMU_CURR_POWER_MODE,
+ val, !(val & mask),
+ 1, JH71XX_PMU_TIMEOUT_US);
+ }
+
+ if (ret) {
+ dev_err(pmu->dev, "%s: failed to power %s\n",
+ pmd->genpd.name, on ? "on" : "off");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int jh71xx_pmu_on(struct generic_pm_domain *genpd)
+{
+ struct jh71xx_pmu_dev *pmd = container_of(genpd,
+ struct jh71xx_pmu_dev, genpd);
+ u32 pwr_mask = BIT(pmd->domain_info->bit);
+
+ return jh71xx_pmu_set_state(pmd, pwr_mask, true);
+}
+
+static int jh71xx_pmu_off(struct generic_pm_domain *genpd)
+{
+ struct jh71xx_pmu_dev *pmd = container_of(genpd,
+ struct jh71xx_pmu_dev, genpd);
+ u32 pwr_mask = BIT(pmd->domain_info->bit);
+
+ return jh71xx_pmu_set_state(pmd, pwr_mask, false);
+}
+
+static void jh71xx_pmu_int_enable(struct jh71xx_pmu *pmu, u32 mask, bool enable)
+{
+ u32 val;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pmu->lock, flags);
+ val = readl(pmu->base + JH71XX_PMU_TIMER_INT_MASK);
+
+ if (enable)
+ val &= ~mask;
+ else
+ val |= mask;
+
+ writel(val, pmu->base + JH71XX_PMU_TIMER_INT_MASK);
+ spin_unlock_irqrestore(&pmu->lock, flags);
+}
+
+static irqreturn_t jh71xx_pmu_interrupt(int irq, void *data)
+{
+ struct jh71xx_pmu *pmu = data;
+ u32 val;
+
+ val = readl(pmu->base + JH71XX_PMU_INT_STATUS);
+
+ if (val & JH71XX_PMU_INT_SEQ_DONE)
+ dev_dbg(pmu->dev, "sequence done.\n");
+ if (val & JH71XX_PMU_INT_HW_REQ)
+ dev_dbg(pmu->dev, "hardware encourage requestion.\n");
+ if (val & JH71XX_PMU_INT_SW_FAIL)
+ dev_err(pmu->dev, "software encourage fail.\n");
+ if (val & JH71XX_PMU_INT_HW_FAIL)
+ dev_err(pmu->dev, "hardware encourage fail.\n");
+ if (val & JH71XX_PMU_INT_PCH_FAIL)
+ dev_err(pmu->dev, "p-channel fail event.\n");
+
+ /* clear interrupts */
+ writel(val, pmu->base + JH71XX_PMU_INT_STATUS);
+ writel(val, pmu->base + JH71XX_PMU_EVENT_STATUS);
+
+ return IRQ_HANDLED;
+}
+
+static int jh71xx_pmu_init_domain(struct jh71xx_pmu *pmu, int index)
+{
+ struct jh71xx_pmu_dev *pmd;
+ u32 pwr_mask;
+ int ret;
+ bool is_on = false;
+
+ pmd = devm_kzalloc(pmu->dev, sizeof(*pmd), GFP_KERNEL);
+ if (!pmd)
+ return -ENOMEM;
+
+ pmd->domain_info = &pmu->match_data->domain_info[index];
+ pmd->pmu = pmu;
+ pwr_mask = BIT(pmd->domain_info->bit);
+
+ pmd->genpd.name = pmd->domain_info->name;
+ pmd->genpd.flags = pmd->domain_info->flags;
+
+ ret = jh71xx_pmu_get_state(pmd, pwr_mask, &is_on);
+ if (ret)
+ dev_warn(pmu->dev, "unable to get current state for %s\n",
+ pmd->genpd.name);
+
+ pmd->genpd.power_on = jh71xx_pmu_on;
+ pmd->genpd.power_off = jh71xx_pmu_off;
+ pm_genpd_init(&pmd->genpd, NULL, !is_on);
+
+ pmu->genpd_data.domains[index] = &pmd->genpd;
+
+ return 0;
+}
+
+static int jh71xx_pmu_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ const struct jh71xx_pmu_match_data *match_data;
+ struct jh71xx_pmu *pmu;
+ unsigned int i;
+ int ret;
+
+ pmu = devm_kzalloc(dev, sizeof(*pmu), GFP_KERNEL);
+ if (!pmu)
+ return -ENOMEM;
+
+ pmu->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(pmu->base))
+ return PTR_ERR(pmu->base);
+
+ pmu->irq = platform_get_irq(pdev, 0);
+ if (pmu->irq < 0)
+ return pmu->irq;
+
+ ret = devm_request_irq(dev, pmu->irq, jh71xx_pmu_interrupt,
+ 0, pdev->name, pmu);
+ if (ret)
+ dev_err(dev, "failed to request irq\n");
+
+ match_data = of_device_get_match_data(dev);
+ if (!match_data)
+ return -EINVAL;
+
+ pmu->genpd = devm_kcalloc(dev, match_data->num_domains,
+ sizeof(struct generic_pm_domain *),
+ GFP_KERNEL);
+ if (!pmu->genpd)
+ return -ENOMEM;
+
+ pmu->dev = dev;
+ pmu->match_data = match_data;
+ pmu->genpd_data.domains = pmu->genpd;
+ pmu->genpd_data.num_domains = match_data->num_domains;
+
+ for (i = 0; i < match_data->num_domains; i++) {
+ ret = jh71xx_pmu_init_domain(pmu, i);
+ if (ret) {
+ dev_err(dev, "failed to initialize power domain\n");
+ return ret;
+ }
+ }
+
+ spin_lock_init(&pmu->lock);
+ jh71xx_pmu_int_enable(pmu, JH71XX_PMU_INT_ALL_MASK & ~JH71XX_PMU_INT_PCH_FAIL, true);
+
+ ret = of_genpd_add_provider_onecell(np, &pmu->genpd_data);
+ if (ret) {
+ dev_err(dev, "failed to register genpd driver: %d\n", ret);
+ return ret;
+ }
+
+ dev_dbg(dev, "registered %u power domains\n", i);
+
+ return 0;
+}
+
+static const struct jh71xx_domain_info jh7110_power_domains[] = {
+ [JH7110_PD_SYSTOP] = {
+ .name = "SYSTOP",
+ .bit = 0,
+ .flags = GENPD_FLAG_ALWAYS_ON,
+ },
+ [JH7110_PD_CPU] = {
+ .name = "CPU",
+ .bit = 1,
+ .flags = GENPD_FLAG_ALWAYS_ON,
+ },
+ [JH7110_PD_GPUA] = {
+ .name = "GPUA",
+ .bit = 2,
+ },
+ [JH7110_PD_VDEC] = {
+ .name = "VDEC",
+ .bit = 3,
+ },
+ [JH7110_PD_VOUT] = {
+ .name = "VOUT",
+ .bit = 4,
+ },
+ [JH7110_PD_ISP] = {
+ .name = "ISP",
+ .bit = 5,
+ },
+ [JH7110_PD_VENC] = {
+ .name = "VENC",
+ .bit = 6,
+ },
+};
+
+static const struct jh71xx_pmu_match_data jh7110_pmu = {
+ .num_domains = ARRAY_SIZE(jh7110_power_domains),
+ .domain_info = jh7110_power_domains,
+};
+
+static const struct of_device_id jh71xx_pmu_of_match[] = {
+ {
+ .compatible = "starfive,jh7110-pmu",
+ .data = (void *)&jh7110_pmu,
+ }, {
+ /* sentinel */
+ }
+};
+
+static struct platform_driver jh71xx_pmu_driver = {
+ .probe = jh71xx_pmu_probe,
+ .driver = {
+ .name = "jh71xx-pmu",
+ .of_match_table = jh71xx_pmu_of_match,
+ .suppress_bind_attrs = true,
+ },
+};
+builtin_platform_driver(jh71xx_pmu_driver);
+
+MODULE_AUTHOR("Walker Chen <walker.chen@starfivetech.com>");
+MODULE_DESCRIPTION("StarFive JH71XX PMU Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/sunxi/Kconfig b/drivers/soc/sunxi/Kconfig
index 8aecbc9b1976..c5070914fc6a 100644
--- a/drivers/soc/sunxi/Kconfig
+++ b/drivers/soc/sunxi/Kconfig
@@ -19,3 +19,12 @@ config SUNXI_SRAM
Say y here to enable the SRAM controller support. This
device is responsible on mapping the SRAM in the sunXi SoCs
whether to the CPU/DMA, or to the devices.
+
+config SUN20I_PPU
+ bool "Allwinner D1 PPU power domain driver"
+ depends on ARCH_SUNXI || COMPILE_TEST
+ depends on PM
+ select PM_GENERIC_DOMAINS
+ help
+ Say y to enable the PPU power domain driver. This saves power
+ when certain peripherals, such as the video engine, are idle.
diff --git a/drivers/soc/sunxi/Makefile b/drivers/soc/sunxi/Makefile
index 549159571d4f..90ff2ebe7655 100644
--- a/drivers/soc/sunxi/Makefile
+++ b/drivers/soc/sunxi/Makefile
@@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_SUNXI_MBUS) += sunxi_mbus.o
obj-$(CONFIG_SUNXI_SRAM) += sunxi_sram.o
+obj-$(CONFIG_SUN20I_PPU) += sun20i-ppu.o
diff --git a/drivers/soc/sunxi/sun20i-ppu.c b/drivers/soc/sunxi/sun20i-ppu.c
new file mode 100644
index 000000000000..98cb41d36560
--- /dev/null
+++ b/drivers/soc/sunxi/sun20i-ppu.c
@@ -0,0 +1,207 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/reset.h>
+
+#define PD_STATE_ON 1
+#define PD_STATE_OFF 2
+
+#define PD_RSTN_REG 0x00
+#define PD_CLK_GATE_REG 0x04
+#define PD_PWROFF_GATE_REG 0x08
+#define PD_PSW_ON_REG 0x0c
+#define PD_PSW_OFF_REG 0x10
+#define PD_PSW_DELAY_REG 0x14
+#define PD_OFF_DELAY_REG 0x18
+#define PD_ON_DELAY_REG 0x1c
+#define PD_COMMAND_REG 0x20
+#define PD_STATUS_REG 0x24
+#define PD_STATUS_COMPLETE BIT(1)
+#define PD_STATUS_BUSY BIT(3)
+#define PD_STATUS_STATE GENMASK(17, 16)
+#define PD_ACTIVE_CTRL_REG 0x2c
+#define PD_GATE_STATUS_REG 0x30
+#define PD_RSTN_STATUS BIT(0)
+#define PD_CLK_GATE_STATUS BIT(1)
+#define PD_PWROFF_GATE_STATUS BIT(2)
+#define PD_PSW_STATUS_REG 0x34
+
+#define PD_REGS_SIZE 0x80
+
+struct sun20i_ppu_desc {
+ const char *const *names;
+ unsigned int num_domains;
+};
+
+struct sun20i_ppu_pd {
+ struct generic_pm_domain genpd;
+ void __iomem *base;
+};
+
+#define to_sun20i_ppu_pd(_genpd) \
+ container_of(_genpd, struct sun20i_ppu_pd, genpd)
+
+static bool sun20i_ppu_pd_is_on(const struct sun20i_ppu_pd *pd)
+{
+ u32 status = readl(pd->base + PD_STATUS_REG);
+
+ return FIELD_GET(PD_STATUS_STATE, status) == PD_STATE_ON;
+}
+
+static int sun20i_ppu_pd_set_power(const struct sun20i_ppu_pd *pd, bool power_on)
+{
+ u32 state, status;
+ int ret;
+
+ if (sun20i_ppu_pd_is_on(pd) == power_on)
+ return 0;
+
+ /* Wait for the power controller to be idle. */
+ ret = readl_poll_timeout(pd->base + PD_STATUS_REG, status,
+ !(status & PD_STATUS_BUSY), 100, 1000);
+ if (ret)
+ return ret;
+
+ state = power_on ? PD_STATE_ON : PD_STATE_OFF;
+ writel(state, pd->base + PD_COMMAND_REG);
+
+ /* Wait for the state transition to complete. */
+ ret = readl_poll_timeout(pd->base + PD_STATUS_REG, status,
+ FIELD_GET(PD_STATUS_STATE, status) == state &&
+ (status & PD_STATUS_COMPLETE), 100, 1000);
+ if (ret)
+ return ret;
+
+ /* Clear the completion flag. */
+ writel(status, pd->base + PD_STATUS_REG);
+
+ return 0;
+}
+
+static int sun20i_ppu_pd_power_on(struct generic_pm_domain *genpd)
+{
+ const struct sun20i_ppu_pd *pd = to_sun20i_ppu_pd(genpd);
+
+ return sun20i_ppu_pd_set_power(pd, true);
+}
+
+static int sun20i_ppu_pd_power_off(struct generic_pm_domain *genpd)
+{
+ const struct sun20i_ppu_pd *pd = to_sun20i_ppu_pd(genpd);
+
+ return sun20i_ppu_pd_set_power(pd, false);
+}
+
+static int sun20i_ppu_probe(struct platform_device *pdev)
+{
+ const struct sun20i_ppu_desc *desc;
+ struct device *dev = &pdev->dev;
+ struct genpd_onecell_data *ppu;
+ struct sun20i_ppu_pd *pds;
+ struct reset_control *rst;
+ void __iomem *base;
+ struct clk *clk;
+ int ret;
+
+ desc = of_device_get_match_data(dev);
+ if (!desc)
+ return -EINVAL;
+
+ pds = devm_kcalloc(dev, desc->num_domains, sizeof(*pds), GFP_KERNEL);
+ if (!pds)
+ return -ENOMEM;
+
+ ppu = devm_kzalloc(dev, sizeof(*ppu), GFP_KERNEL);
+ if (!ppu)
+ return -ENOMEM;
+
+ ppu->domains = devm_kcalloc(dev, desc->num_domains,
+ sizeof(*ppu->domains), GFP_KERNEL);
+ if (!ppu->domains)
+ return -ENOMEM;
+
+ ppu->num_domains = desc->num_domains;
+ platform_set_drvdata(pdev, ppu);
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ rst = devm_reset_control_get_exclusive(dev, NULL);
+ if (IS_ERR(rst))
+ return PTR_ERR(rst);
+
+ ret = reset_control_deassert(rst);
+ if (ret)
+ return ret;
+
+ for (unsigned int i = 0; i < ppu->num_domains; ++i) {
+ struct sun20i_ppu_pd *pd = &pds[i];
+
+ pd->genpd.name = desc->names[i];
+ pd->genpd.power_off = sun20i_ppu_pd_power_off;
+ pd->genpd.power_on = sun20i_ppu_pd_power_on;
+ pd->base = base + PD_REGS_SIZE * i;
+
+ ret = pm_genpd_init(&pd->genpd, NULL, sun20i_ppu_pd_is_on(pd));
+ if (ret) {
+ dev_warn(dev, "Failed to add '%s' domain: %d\n",
+ pd->genpd.name, ret);
+ continue;
+ }
+
+ ppu->domains[i] = &pd->genpd;
+ }
+
+ ret = of_genpd_add_provider_onecell(dev->of_node, ppu);
+ if (ret)
+ dev_warn(dev, "Failed to add provider: %d\n", ret);
+
+ return 0;
+}
+
+static const char *const sun20i_d1_ppu_pd_names[] = {
+ "CPU",
+ "VE",
+ "DSP",
+};
+
+static const struct sun20i_ppu_desc sun20i_d1_ppu_desc = {
+ .names = sun20i_d1_ppu_pd_names,
+ .num_domains = ARRAY_SIZE(sun20i_d1_ppu_pd_names),
+};
+
+static const struct of_device_id sun20i_ppu_of_match[] = {
+ {
+ .compatible = "allwinner,sun20i-d1-ppu",
+ .data = &sun20i_d1_ppu_desc,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, sun20i_ppu_of_match);
+
+static struct platform_driver sun20i_ppu_driver = {
+ .probe = sun20i_ppu_probe,
+ .driver = {
+ .name = "sun20i-ppu",
+ .of_match_table = sun20i_ppu_of_match,
+ /* Power domains cannot be removed while they are in use. */
+ .suppress_bind_attrs = true,
+ },
+};
+module_platform_driver(sun20i_ppu_driver);
+
+MODULE_AUTHOR("Samuel Holland <samuel@sholland.org>");
+MODULE_DESCRIPTION("Allwinner D1 PPU power domain driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c
index 92f9186c1c42..f09918c59042 100644
--- a/drivers/soc/sunxi/sunxi_sram.c
+++ b/drivers/soc/sunxi/sunxi_sram.c
@@ -120,6 +120,9 @@ static int sunxi_sram_show(struct seq_file *s, void *data)
seq_puts(s, "--------------------\n\n");
for_each_child_of_node(sram_dev->of_node, sram_node) {
+ if (!of_device_is_compatible(sram_node, "mmio-sram"))
+ continue;
+
sram_addr_p = of_get_address(sram_node, 0, NULL, NULL);
seq_printf(s, "sram@%08x\n",
diff --git a/drivers/soc/xilinx/xlnx_event_manager.c b/drivers/soc/xilinx/xlnx_event_manager.c
index 2de082765bef..c76381899ef4 100644
--- a/drivers/soc/xilinx/xlnx_event_manager.c
+++ b/drivers/soc/xilinx/xlnx_event_manager.c
@@ -116,8 +116,10 @@ static int xlnx_add_cb_for_notify_event(const u32 node_id, const u32 event, cons
INIT_LIST_HEAD(&eve_data->cb_list_head);
cb_data = kmalloc(sizeof(*cb_data), GFP_KERNEL);
- if (!cb_data)
+ if (!cb_data) {
+ kfree(eve_data);
return -ENOMEM;
+ }
cb_data->eve_cb = cb_fun;
cb_data->agent_data = data;
diff --git a/drivers/soc/xilinx/zynqmp_pm_domains.c b/drivers/soc/xilinx/zynqmp_pm_domains.c
index fcce2433bd6d..69d03ad4cf1e 100644
--- a/drivers/soc/xilinx/zynqmp_pm_domains.c
+++ b/drivers/soc/xilinx/zynqmp_pm_domains.c
@@ -227,7 +227,7 @@ static struct generic_pm_domain *zynqmp_gpd_xlate
goto done;
}
- /**
+ /*
* Add index in empty node_id of power domain list as no existing
* power domain found for current index.
*/
diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
index 76515c33e639..b6aca59c3130 100644
--- a/drivers/soundwire/bus.c
+++ b/drivers/soundwire/bus.c
@@ -225,9 +225,9 @@ static inline int do_transfer(struct sdw_bus *bus, struct sdw_msg *msg)
}
static inline int do_transfer_defer(struct sdw_bus *bus,
- struct sdw_msg *msg,
- struct sdw_defer *defer)
+ struct sdw_msg *msg)
{
+ struct sdw_defer *defer = &bus->defer_msg;
int retry = bus->prop.err_threshold;
enum sdw_command_response resp;
int ret = 0, i;
@@ -237,24 +237,7 @@ static inline int do_transfer_defer(struct sdw_bus *bus,
init_completion(&defer->complete);
for (i = 0; i <= retry; i++) {
- resp = bus->ops->xfer_msg_defer(bus, msg, defer);
- ret = find_response_code(resp);
- /* if cmd is ok or ignored return */
- if (ret == 0 || ret == -ENODATA)
- return ret;
- }
-
- return ret;
-}
-
-static int sdw_reset_page(struct sdw_bus *bus, u16 dev_num)
-{
- int retry = bus->prop.err_threshold;
- enum sdw_command_response resp;
- int ret = 0, i;
-
- for (i = 0; i <= retry; i++) {
- resp = bus->ops->reset_page_addr(bus, dev_num);
+ resp = bus->ops->xfer_msg_defer(bus);
ret = find_response_code(resp);
/* if cmd is ok or ignored return */
if (ret == 0 || ret == -ENODATA)
@@ -275,9 +258,6 @@ static int sdw_transfer_unlocked(struct sdw_bus *bus, struct sdw_msg *msg)
(msg->flags & SDW_MSG_FLAG_WRITE) ? "write" : "read",
msg->addr, msg->len);
- if (msg->page)
- sdw_reset_page(bus, msg->dev_num);
-
return ret;
}
@@ -335,26 +315,21 @@ EXPORT_SYMBOL(sdw_show_ping_status);
* sdw_transfer_defer() - Asynchronously transfer message to a SDW Slave device
* @bus: SDW bus
* @msg: SDW message to be xfered
- * @defer: Defer block for signal completion
*
* Caller needs to hold the msg_lock lock while calling this
*/
-int sdw_transfer_defer(struct sdw_bus *bus, struct sdw_msg *msg,
- struct sdw_defer *defer)
+int sdw_transfer_defer(struct sdw_bus *bus, struct sdw_msg *msg)
{
int ret;
if (!bus->ops->xfer_msg_defer)
return -ENOTSUPP;
- ret = do_transfer_defer(bus, msg, defer);
+ ret = do_transfer_defer(bus, msg);
if (ret != 0 && ret != -ENODATA)
dev_err(bus->dev, "Defer trf on Slave %d failed:%d\n",
msg->dev_num, ret);
- if (msg->page)
- sdw_reset_page(bus, msg->dev_num);
-
return ret;
}
@@ -414,8 +389,7 @@ int sdw_fill_msg(struct sdw_msg *msg, struct sdw_slave *slave,
* all clients need to use the pm versions
*/
-static int
-sdw_nread_no_pm(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
+int sdw_nread_no_pm(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
{
struct sdw_msg msg;
int ret;
@@ -430,9 +404,9 @@ sdw_nread_no_pm(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
ret = 0;
return ret;
}
+EXPORT_SYMBOL(sdw_nread_no_pm);
-static int
-sdw_nwrite_no_pm(struct sdw_slave *slave, u32 addr, size_t count, const u8 *val)
+int sdw_nwrite_no_pm(struct sdw_slave *slave, u32 addr, size_t count, const u8 *val)
{
struct sdw_msg msg;
int ret;
@@ -447,6 +421,7 @@ sdw_nwrite_no_pm(struct sdw_slave *slave, u32 addr, size_t count, const u8 *val)
ret = 0;
return ret;
}
+EXPORT_SYMBOL(sdw_nwrite_no_pm);
int sdw_write_no_pm(struct sdw_slave *slave, u32 addr, u8 value)
{
@@ -1214,7 +1189,7 @@ int sdw_configure_dpn_intr(struct sdw_slave *slave,
val &= ~SDW_DPN_INT_PORT_READY;
}
- ret = sdw_update(slave, addr, (mask | SDW_DPN_INT_PORT_READY), val);
+ ret = sdw_update_no_pm(slave, addr, (mask | SDW_DPN_INT_PORT_READY), val);
if (ret < 0)
dev_err(&slave->dev,
"SDW_DPN_INTMASK write failed:%d\n", val);
@@ -1233,10 +1208,11 @@ static int sdw_slave_set_frequency(struct sdw_slave *slave)
/*
* frequency base and scale registers are required for SDCA
- * devices. They may also be used for 1.2+/non-SDCA devices,
- * but we will need a DisCo property to cover this case
+ * devices. They may also be used for 1.2+/non-SDCA devices.
+ * Driver can set the property, we will need a DisCo property
+ * to discover this case from platform firmware.
*/
- if (!slave->id.class_id)
+ if (!slave->id.class_id && !slave->prop.clock_reg_supported)
return 0;
if (!mclk_freq) {
@@ -1587,7 +1563,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
goto io_err;
}
- if (slave->prop.is_sdca) {
+ if (slave->id.class_id) {
ret = sdw_read_no_pm(slave, SDW_DP0_INT);
if (ret < 0) {
dev_err(&slave->dev,
@@ -1724,7 +1700,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
goto io_err;
}
- if (slave->prop.is_sdca) {
+ if (slave->id.class_id) {
ret = sdw_read_no_pm(slave, SDW_DP0_INT);
if (ret < 0) {
dev_err(&slave->dev,
diff --git a/drivers/soundwire/bus.h b/drivers/soundwire/bus.h
index 7631ef5e71fb..96927a143796 100644
--- a/drivers/soundwire/bus.h
+++ b/drivers/soundwire/bus.h
@@ -151,8 +151,7 @@ int sdw_configure_dpn_intr(struct sdw_slave *slave, int port,
bool enable, int mask);
int sdw_transfer(struct sdw_bus *bus, struct sdw_msg *msg);
-int sdw_transfer_defer(struct sdw_bus *bus, struct sdw_msg *msg,
- struct sdw_defer *defer);
+int sdw_transfer_defer(struct sdw_bus *bus, struct sdw_msg *msg);
#define SDW_READ_INTR_CLEAR_RETRY 10
diff --git a/drivers/soundwire/bus_type.c b/drivers/soundwire/bus_type.c
index 04b3529f8929..1f43ee848eac 100644
--- a/drivers/soundwire/bus_type.c
+++ b/drivers/soundwire/bus_type.c
@@ -58,9 +58,9 @@ int sdw_slave_modalias(const struct sdw_slave *slave, char *buf, size_t size)
slave->id.sdw_version, slave->id.class_id);
}
-int sdw_slave_uevent(struct device *dev, struct kobj_uevent_env *env)
+int sdw_slave_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct sdw_slave *slave = dev_to_sdw_dev(dev);
+ const struct sdw_slave *slave = dev_to_sdw_dev(dev);
char modalias[32];
sdw_slave_modalias(slave, modalias, sizeof(modalias));
@@ -105,20 +105,19 @@ static int sdw_drv_probe(struct device *dev)
if (ret)
return ret;
- mutex_lock(&slave->sdw_dev_lock);
-
ret = drv->probe(slave, id);
if (ret) {
name = drv->name;
if (!name)
name = drv->driver.name;
- mutex_unlock(&slave->sdw_dev_lock);
dev_err(dev, "Probe of %s failed: %d\n", name, ret);
dev_pm_domain_detach(dev, false);
return ret;
}
+ mutex_lock(&slave->sdw_dev_lock);
+
/* device is probed so let's read the properties now */
if (drv->ops && drv->ops->read_prop)
drv->ops->read_prop(slave);
@@ -167,14 +166,12 @@ static int sdw_drv_remove(struct device *dev)
int ret = 0;
mutex_lock(&slave->sdw_dev_lock);
-
slave->probed = false;
+ mutex_unlock(&slave->sdw_dev_lock);
if (drv->remove)
ret = drv->remove(slave);
- mutex_unlock(&slave->sdw_dev_lock);
-
dev_pm_domain_detach(dev, false);
return ret;
diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
index a1de363eba3f..e835dabb516c 100644
--- a/drivers/soundwire/cadence_master.c
+++ b/drivers/soundwire/cadence_master.c
@@ -127,7 +127,8 @@ MODULE_PARM_DESC(cdns_mcp_int_mask, "Cadence MCP IntMask");
#define CDNS_MCP_CMD_BASE 0x80
#define CDNS_MCP_RESP_BASE 0x80
-#define CDNS_MCP_CMD_LEN 0x20
+/* FIFO can hold 8 commands */
+#define CDNS_MCP_CMD_LEN 8
#define CDNS_MCP_CMD_WORD_LEN 0x4
#define CDNS_MCP_CMD_SSP_TAG BIT(31)
@@ -554,6 +555,29 @@ cdns_fill_msg_resp(struct sdw_cdns *cdns,
return SDW_CMD_OK;
}
+static void cdns_read_response(struct sdw_cdns *cdns)
+{
+ u32 num_resp, cmd_base;
+ int i;
+
+ /* RX_FIFO_AVAIL can be 2 entries more than the FIFO size */
+ BUILD_BUG_ON(ARRAY_SIZE(cdns->response_buf) < CDNS_MCP_CMD_LEN + 2);
+
+ num_resp = cdns_readl(cdns, CDNS_MCP_FIFOSTAT);
+ num_resp &= CDNS_MCP_RX_FIFO_AVAIL;
+ if (num_resp > ARRAY_SIZE(cdns->response_buf)) {
+ dev_warn(cdns->dev, "RX AVAIL %d too long\n", num_resp);
+ num_resp = ARRAY_SIZE(cdns->response_buf);
+ }
+
+ cmd_base = CDNS_MCP_CMD_BASE;
+
+ for (i = 0; i < num_resp; i++) {
+ cdns->response_buf[i] = cdns_readl(cdns, cmd_base);
+ cmd_base += CDNS_MCP_CMD_WORD_LEN;
+ }
+}
+
static enum sdw_command_response
_cdns_xfer_msg(struct sdw_cdns *cdns, struct sdw_msg *msg, int cmd,
int offset, int count, bool defer)
@@ -595,6 +619,10 @@ _cdns_xfer_msg(struct sdw_cdns *cdns, struct sdw_msg *msg, int cmd,
dev_err(cdns->dev, "IO transfer timed out, cmd %d device %d addr %x len %d\n",
cmd, msg->dev_num, msg->addr, msg->len);
msg->len = 0;
+
+ /* Drain anything in the RX_FIFO */
+ cdns_read_response(cdns);
+
return SDW_CMD_TIMEOUT;
}
@@ -721,10 +749,11 @@ cdns_xfer_msg(struct sdw_bus *bus, struct sdw_msg *msg)
EXPORT_SYMBOL(cdns_xfer_msg);
enum sdw_command_response
-cdns_xfer_msg_defer(struct sdw_bus *bus,
- struct sdw_msg *msg, struct sdw_defer *defer)
+cdns_xfer_msg_defer(struct sdw_bus *bus)
{
struct sdw_cdns *cdns = bus_to_cdns(bus);
+ struct sdw_defer *defer = &bus->defer_msg;
+ struct sdw_msg *msg = defer->msg;
int cmd = 0, ret;
/* for defer only 1 message is supported */
@@ -735,27 +764,10 @@ cdns_xfer_msg_defer(struct sdw_bus *bus,
if (ret)
return SDW_CMD_FAIL_OTHER;
- cdns->defer = defer;
- cdns->defer->length = msg->len;
-
return _cdns_xfer_msg(cdns, msg, cmd, 0, msg->len, true);
}
EXPORT_SYMBOL(cdns_xfer_msg_defer);
-enum sdw_command_response
-cdns_reset_page_addr(struct sdw_bus *bus, unsigned int dev_num)
-{
- struct sdw_cdns *cdns = bus_to_cdns(bus);
- struct sdw_msg msg;
-
- /* Create dummy message with valid device number */
- memset(&msg, 0, sizeof(msg));
- msg.dev_num = dev_num;
-
- return cdns_program_scp_addr(cdns, &msg);
-}
-EXPORT_SYMBOL(cdns_reset_page_addr);
-
u32 cdns_read_ping_status(struct sdw_bus *bus)
{
struct sdw_cdns *cdns = bus_to_cdns(bus);
@@ -768,22 +780,6 @@ EXPORT_SYMBOL(cdns_read_ping_status);
* IRQ handling
*/
-static void cdns_read_response(struct sdw_cdns *cdns)
-{
- u32 num_resp, cmd_base;
- int i;
-
- num_resp = cdns_readl(cdns, CDNS_MCP_FIFOSTAT);
- num_resp &= CDNS_MCP_RX_FIFO_AVAIL;
-
- cmd_base = CDNS_MCP_CMD_BASE;
-
- for (i = 0; i < num_resp; i++) {
- cdns->response_buf[i] = cdns_readl(cdns, cmd_base);
- cmd_base += CDNS_MCP_CMD_WORD_LEN;
- }
-}
-
static int cdns_update_slave_status(struct sdw_cdns *cdns,
u64 slave_intstat)
{
@@ -881,13 +877,15 @@ irqreturn_t sdw_cdns_irq(int irq, void *dev_id)
return IRQ_NONE;
if (int_status & CDNS_MCP_INT_RX_WL) {
+ struct sdw_bus *bus = &cdns->bus;
+ struct sdw_defer *defer = &bus->defer_msg;
+
cdns_read_response(cdns);
- if (cdns->defer) {
- cdns_fill_msg_resp(cdns, cdns->defer->msg,
- cdns->defer->length, 0);
- complete(&cdns->defer->complete);
- cdns->defer = NULL;
+ if (defer && defer->msg) {
+ cdns_fill_msg_resp(cdns, defer->msg,
+ defer->length, 0);
+ complete(&defer->complete);
} else {
complete(&cdns->tx_complete);
}
diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h
index 0434d70d4b1f..dec0b4f993c1 100644
--- a/drivers/soundwire/cadence_master.h
+++ b/drivers/soundwire/cadence_master.h
@@ -8,6 +8,12 @@
#define SDW_CADENCE_GSYNC_KHZ 4 /* 4 kHz */
#define SDW_CADENCE_GSYNC_HZ (SDW_CADENCE_GSYNC_KHZ * 1000)
+/*
+ * The Cadence IP supports up to 32 entries in the FIFO, though implementations
+ * can configure the IP to have a smaller FIFO.
+ */
+#define CDNS_MCP_IP_MAX_CMD_LEN 32
+
/**
* struct sdw_cdns_pdi: PDI (Physical Data Interface) instance
*
@@ -103,7 +109,6 @@ struct sdw_cdns_dai_runtime {
* @instance: instance number
* @response_buf: SoundWire response buffer
* @tx_complete: Tx completion
- * @defer: Defer pointer
* @ports: Data ports
* @num_ports: Total number of data ports
* @pcm: PCM streams
@@ -117,9 +122,13 @@ struct sdw_cdns {
struct sdw_bus bus;
unsigned int instance;
- u32 response_buf[0x80];
+ /*
+ * The datasheet says the RX FIFO AVAIL can be 2 entries more
+ * than the FIFO capacity, so allow for this.
+ */
+ u32 response_buf[CDNS_MCP_IP_MAX_CMD_LEN + 2];
+
struct completion tx_complete;
- struct sdw_defer *defer;
struct sdw_cdns_port *ports;
int num_ports;
@@ -147,7 +156,6 @@ struct sdw_cdns {
/* Exported symbols */
int sdw_cdns_probe(struct sdw_cdns *cdns);
-extern struct sdw_master_ops sdw_cdns_master_ops;
irqreturn_t sdw_cdns_irq(int irq, void *dev_id);
irqreturn_t sdw_cdns_thread(int irq, void *dev_id);
@@ -173,14 +181,10 @@ void sdw_cdns_config_stream(struct sdw_cdns *cdns,
u32 ch, u32 dir, struct sdw_cdns_pdi *pdi);
enum sdw_command_response
-cdns_reset_page_addr(struct sdw_bus *bus, unsigned int dev_num);
-
-enum sdw_command_response
cdns_xfer_msg(struct sdw_bus *bus, struct sdw_msg *msg);
enum sdw_command_response
-cdns_xfer_msg_defer(struct sdw_bus *bus,
- struct sdw_msg *msg, struct sdw_defer *defer);
+cdns_xfer_msg_defer(struct sdw_bus *bus);
u32 cdns_read_ping_status(struct sdw_bus *bus);
diff --git a/drivers/soundwire/debugfs.c b/drivers/soundwire/debugfs.c
index 49900cd207bc..dea782e0edc4 100644
--- a/drivers/soundwire/debugfs.c
+++ b/drivers/soundwire/debugfs.c
@@ -4,6 +4,7 @@
#include <linux/device.h>
#include <linux/debugfs.h>
#include <linux/mod_devicetable.h>
+#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/soundwire/sdw.h>
#include <linux/soundwire/sdw_registers.h>
@@ -35,7 +36,7 @@ static ssize_t sdw_sprintf(struct sdw_slave *slave,
{
int value;
- value = sdw_read(slave, reg);
+ value = sdw_read_no_pm(slave, reg);
if (value < 0)
return scnprintf(buf + pos, RD_BUF - pos, "%3x\tXX\n", reg);
@@ -55,6 +56,12 @@ static int sdw_slave_reg_show(struct seq_file *s_file, void *data)
if (!buf)
return -ENOMEM;
+ ret = pm_runtime_resume_and_get(&slave->dev);
+ if (ret < 0 && ret != -EACCES) {
+ kfree(buf);
+ return ret;
+ }
+
ret = scnprintf(buf, RD_BUF, "Register Value\n");
/* DP0 non-banked registers */
@@ -112,6 +119,10 @@ static int sdw_slave_reg_show(struct seq_file *s_file, void *data)
}
seq_printf(s_file, "%s", buf);
+
+ pm_runtime_mark_last_busy(&slave->dev);
+ pm_runtime_put(&slave->dev);
+
kfree(buf);
return 0;
diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
index bc9c50bacc49..2651767272c7 100644
--- a/drivers/soundwire/intel.c
+++ b/drivers/soundwire/intel.c
@@ -778,22 +778,6 @@ unlock:
* DAI routines
*/
-static int intel_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
- int ret;
-
- ret = pm_runtime_resume_and_get(cdns->dev);
- if (ret < 0 && ret != -EACCES) {
- dev_err_ratelimited(cdns->dev,
- "pm_runtime_resume_and_get failed in %s, ret %d\n",
- __func__, ret);
- return ret;
- }
- return 0;
-}
-
static int intel_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
@@ -954,15 +938,6 @@ intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
return 0;
}
-static void intel_shutdown(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
-
- pm_runtime_mark_last_busy(cdns->dev);
- pm_runtime_put_autosuspend(cdns->dev);
-}
-
static int intel_pcm_set_sdw_stream(struct snd_soc_dai *dai,
void *stream, int direction)
{
@@ -1088,12 +1063,10 @@ static int intel_component_dais_suspend(struct snd_soc_component *component)
}
static const struct snd_soc_dai_ops intel_pcm_dai_ops = {
- .startup = intel_startup,
.hw_params = intel_hw_params,
.prepare = intel_prepare,
.hw_free = intel_hw_free,
.trigger = intel_trigger,
- .shutdown = intel_shutdown,
.set_stream = intel_pcm_set_sdw_stream,
.get_stream = intel_get_sdw_stream,
};
diff --git a/drivers/soundwire/intel_auxdevice.c b/drivers/soundwire/intel_auxdevice.c
index 96c6b2112feb..5021be0f4158 100644
--- a/drivers/soundwire/intel_auxdevice.c
+++ b/drivers/soundwire/intel_auxdevice.c
@@ -113,7 +113,6 @@ static struct sdw_master_ops sdw_intel_ops = {
.override_adr = sdw_dmi_override_adr,
.xfer_msg = cdns_xfer_msg,
.xfer_msg_defer = cdns_xfer_msg_defer,
- .reset_page_addr = cdns_reset_page_addr,
.set_bus_conf = cdns_bus_conf,
.pre_bank_switch = generic_pre_bank_switch,
.post_bank_switch = generic_post_bank_switch,
diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c
index bd502368339e..8c6da1739e3d 100644
--- a/drivers/soundwire/stream.c
+++ b/drivers/soundwire/stream.c
@@ -81,14 +81,14 @@ static int _sdw_program_slave_port_params(struct sdw_bus *bus,
}
/* Program DPN_OffsetCtrl2 registers */
- ret = sdw_write(slave, addr1, t_params->offset2);
+ ret = sdw_write_no_pm(slave, addr1, t_params->offset2);
if (ret < 0) {
dev_err(bus->dev, "DPN_OffsetCtrl2 register write failed\n");
return ret;
}
/* Program DPN_BlockCtrl3 register */
- ret = sdw_write(slave, addr2, t_params->blk_pkg_mode);
+ ret = sdw_write_no_pm(slave, addr2, t_params->blk_pkg_mode);
if (ret < 0) {
dev_err(bus->dev, "DPN_BlockCtrl3 register write failed\n");
return ret;
@@ -105,7 +105,7 @@ static int _sdw_program_slave_port_params(struct sdw_bus *bus,
/* Program DPN_SampleCtrl2 register */
wbuf = FIELD_GET(SDW_DPN_SAMPLECTRL_HIGH, t_params->sample_interval - 1);
- ret = sdw_write(slave, addr3, wbuf);
+ ret = sdw_write_no_pm(slave, addr3, wbuf);
if (ret < 0) {
dev_err(bus->dev, "DPN_SampleCtrl2 register write failed\n");
return ret;
@@ -115,7 +115,7 @@ static int _sdw_program_slave_port_params(struct sdw_bus *bus,
wbuf = FIELD_PREP(SDW_DPN_HCTRL_HSTART, t_params->hstart);
wbuf |= FIELD_PREP(SDW_DPN_HCTRL_HSTOP, t_params->hstop);
- ret = sdw_write(slave, addr4, wbuf);
+ ret = sdw_write_no_pm(slave, addr4, wbuf);
if (ret < 0)
dev_err(bus->dev, "DPN_HCtrl register write failed\n");
@@ -163,7 +163,7 @@ static int sdw_program_slave_port_params(struct sdw_bus *bus,
wbuf = FIELD_PREP(SDW_DPN_PORTCTRL_DATAMODE, p_params->data_mode);
wbuf |= FIELD_PREP(SDW_DPN_PORTCTRL_FLOWMODE, p_params->flow_mode);
- ret = sdw_update(s_rt->slave, addr1, 0xF, wbuf);
+ ret = sdw_update_no_pm(s_rt->slave, addr1, 0xF, wbuf);
if (ret < 0) {
dev_err(&s_rt->slave->dev,
"DPN_PortCtrl register write failed for port %d\n",
@@ -173,7 +173,7 @@ static int sdw_program_slave_port_params(struct sdw_bus *bus,
if (!dpn_prop->read_only_wordlength) {
/* Program DPN_BlockCtrl1 register */
- ret = sdw_write(s_rt->slave, addr2, (p_params->bps - 1));
+ ret = sdw_write_no_pm(s_rt->slave, addr2, (p_params->bps - 1));
if (ret < 0) {
dev_err(&s_rt->slave->dev,
"DPN_BlockCtrl1 register write failed for port %d\n",
@@ -184,7 +184,7 @@ static int sdw_program_slave_port_params(struct sdw_bus *bus,
/* Program DPN_SampleCtrl1 register */
wbuf = (t_params->sample_interval - 1) & SDW_DPN_SAMPLECTRL_LOW;
- ret = sdw_write(s_rt->slave, addr3, wbuf);
+ ret = sdw_write_no_pm(s_rt->slave, addr3, wbuf);
if (ret < 0) {
dev_err(&s_rt->slave->dev,
"DPN_SampleCtrl1 register write failed for port %d\n",
@@ -193,7 +193,7 @@ static int sdw_program_slave_port_params(struct sdw_bus *bus,
}
/* Program DPN_OffsetCtrl1 registers */
- ret = sdw_write(s_rt->slave, addr4, t_params->offset1);
+ ret = sdw_write_no_pm(s_rt->slave, addr4, t_params->offset1);
if (ret < 0) {
dev_err(&s_rt->slave->dev,
"DPN_OffsetCtrl1 register write failed for port %d\n",
@@ -203,7 +203,7 @@ static int sdw_program_slave_port_params(struct sdw_bus *bus,
/* Program DPN_BlockCtrl2 register*/
if (t_params->blk_grp_ctrl_valid) {
- ret = sdw_write(s_rt->slave, addr5, t_params->blk_grp_ctrl);
+ ret = sdw_write_no_pm(s_rt->slave, addr5, t_params->blk_grp_ctrl);
if (ret < 0) {
dev_err(&s_rt->slave->dev,
"DPN_BlockCtrl2 reg write failed for port %d\n",
@@ -214,7 +214,7 @@ static int sdw_program_slave_port_params(struct sdw_bus *bus,
/* program DPN_LaneCtrl register */
if (slave_prop->lane_control_support) {
- ret = sdw_write(s_rt->slave, addr6, t_params->lane_ctrl);
+ ret = sdw_write_no_pm(s_rt->slave, addr6, t_params->lane_ctrl);
if (ret < 0) {
dev_err(&s_rt->slave->dev,
"DPN_LaneCtrl register write failed for port %d\n",
@@ -319,9 +319,9 @@ static int sdw_enable_disable_slave_ports(struct sdw_bus *bus,
* it is safe to reset this register
*/
if (en)
- ret = sdw_write(s_rt->slave, addr, p_rt->ch_mask);
+ ret = sdw_write_no_pm(s_rt->slave, addr, p_rt->ch_mask);
else
- ret = sdw_write(s_rt->slave, addr, 0x0);
+ ret = sdw_write_no_pm(s_rt->slave, addr, 0x0);
if (ret < 0)
dev_err(&s_rt->slave->dev,
@@ -469,16 +469,16 @@ static int sdw_prep_deprep_slave_ports(struct sdw_bus *bus,
}
/* Inform slave about the impending port prepare */
- sdw_do_port_prep(s_rt, prep_ch, SDW_OPS_PORT_PRE_PREP);
+ sdw_do_port_prep(s_rt, prep_ch, prep ? SDW_OPS_PORT_PRE_PREP : SDW_OPS_PORT_PRE_DEPREP);
/* Prepare Slave port implementing CP_SM */
if (!dpn_prop->simple_ch_prep_sm) {
addr = SDW_DPN_PREPARECTRL(p_rt->num);
if (prep)
- ret = sdw_write(s_rt->slave, addr, p_rt->ch_mask);
+ ret = sdw_write_no_pm(s_rt->slave, addr, p_rt->ch_mask);
else
- ret = sdw_write(s_rt->slave, addr, 0x0);
+ ret = sdw_write_no_pm(s_rt->slave, addr, 0x0);
if (ret < 0) {
dev_err(&s_rt->slave->dev,
@@ -491,7 +491,7 @@ static int sdw_prep_deprep_slave_ports(struct sdw_bus *bus,
wait_for_completion_timeout(port_ready,
msecs_to_jiffies(dpn_prop->ch_prep_timeout));
- val = sdw_read(s_rt->slave, SDW_DPN_PREPARESTATUS(p_rt->num));
+ val = sdw_read_no_pm(s_rt->slave, SDW_DPN_PREPARESTATUS(p_rt->num));
if ((val < 0) || (val & p_rt->ch_mask)) {
ret = (val < 0) ? val : -ETIMEDOUT;
dev_err(&s_rt->slave->dev,
@@ -501,7 +501,7 @@ static int sdw_prep_deprep_slave_ports(struct sdw_bus *bus,
}
/* Inform slaves about ports prepared */
- sdw_do_port_prep(s_rt, prep_ch, SDW_OPS_PORT_POST_PREP);
+ sdw_do_port_prep(s_rt, prep_ch, prep ? SDW_OPS_PORT_POST_PREP : SDW_OPS_PORT_POST_DEPREP);
/* Disable interrupt after Port de-prepare */
if (!prep && intr)
@@ -684,8 +684,6 @@ static int sdw_bank_switch(struct sdw_bus *bus, int m_rt_count)
if (!wr_msg)
return -ENOMEM;
- bus->defer_msg.msg = wr_msg;
-
wbuf = kzalloc(sizeof(*wbuf), GFP_KERNEL);
if (!wbuf) {
ret = -ENOMEM;
@@ -713,7 +711,7 @@ static int sdw_bank_switch(struct sdw_bus *bus, int m_rt_count)
multi_link = bus->multi_link && (m_rt_count >= bus->hw_sync_min_links);
if (multi_link)
- ret = sdw_transfer_defer(bus, wr_msg, &bus->defer_msg);
+ ret = sdw_transfer_defer(bus, wr_msg);
else
ret = sdw_transfer(bus, wr_msg);
@@ -723,8 +721,8 @@ static int sdw_bank_switch(struct sdw_bus *bus, int m_rt_count)
}
if (!multi_link) {
- kfree(wr_msg);
kfree(wbuf);
+ kfree(wr_msg);
bus->defer_msg.msg = NULL;
bus->params.curr_bank = !bus->params.curr_bank;
bus->params.next_bank = !bus->params.next_bank;
@@ -769,6 +767,7 @@ static int sdw_ml_sync_bank_switch(struct sdw_bus *bus)
if (bus->defer_msg.msg) {
kfree(bus->defer_msg.msg->buf);
kfree(bus->defer_msg.msg);
+ bus->defer_msg.msg = NULL;
}
return 0;
@@ -867,6 +866,7 @@ error:
if (bus->defer_msg.msg) {
kfree(bus->defer_msg.msg->buf);
kfree(bus->defer_msg.msg);
+ bus->defer_msg.msg = NULL;
}
}
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 2aba88a57a77..47bbba04fe3a 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -199,6 +199,15 @@ config SPI_BCM_QSPI
based platforms. This driver works for both SPI master for SPI NOR
flash device as well as MSPI device.
+config SPI_BCMBCA_HSSPI
+ tristate "Broadcom BCMBCA HS SPI controller driver"
+ depends on ARCH_BCMBCA || COMPILE_TEST
+ help
+ This enables support for the High Speed SPI controller present on
+ newer Broadcom BCMBCA SoCs. These SoCs include an updated SPI controller
+ that adds the capability to allow the driver to control chip select
+ explicitly.
+
config SPI_BITBANG
tristate "Utilities for Bitbanging SPI masters"
help
@@ -247,7 +256,7 @@ config SPI_CADENCE_XSPI
Enable support for the Cadence XSPI Flash controller.
Cadence XSPI is a specialized controller for connecting an SPI
- Flash over upto 8bit wide bus. Enable this option if you have a
+ Flash over up to 8-bit wide bus. Enable this option if you have a
device with a Cadence XSPI controller and want to access the
Flash as an MTD device.
@@ -295,7 +304,6 @@ config SPI_DW_BT1
tristate "Baikal-T1 SPI driver for DW SPI core"
depends on MIPS_BAIKAL_T1 || COMPILE_TEST
select MULTIPLEXER
- select MUX_MMIO
help
Baikal-T1 SoC is equipped with three DW APB SSI-based MMIO SPI
controllers. Two of them are pretty much normal: with IRQ, DMA,
@@ -448,19 +456,19 @@ config SPI_INTEL
tristate
config SPI_INTEL_PCI
- tristate "Intel PCH/PCU SPI flash PCI driver (DANGEROUS)"
+ tristate "Intel PCH/PCU SPI flash PCI driver"
depends on PCI
depends on X86 || COMPILE_TEST
depends on SPI_MEM
select SPI_INTEL
help
This enables PCI support for the Intel PCH/PCU SPI controller in
- master mode. This controller is present in modern Intel hardware
- and is used to hold BIOS and other persistent settings. Using
- this driver it is possible to upgrade BIOS directly from Linux.
-
- Say N here unless you know what you are doing. Overwriting the
- SPI flash may render the system unbootable.
+ master mode. This controller is used to hold BIOS and other
+ persistent settings. Controllers present in modern Intel hardware
+ only work in hardware sequencing mode, this means that the
+ controller exposes a subset of operations that makes it safer to
+ use. Using this driver it is possible to upgrade BIOS directly
+ from Linux.
To compile this driver as a module, choose M here: the module
will be called spi-intel-pci.
@@ -472,10 +480,11 @@ config SPI_INTEL_PLATFORM
select SPI_INTEL
help
This enables platform support for the Intel PCH/PCU SPI
- controller in master mode. This controller is present in modern
- Intel hardware and is used to hold BIOS and other persistent
- settings. Using this driver it is possible to upgrade BIOS
- directly from Linux.
+ controller in master mode that is used to hold BIOS and other
+ persistent settings. Most of these controllers work in
+ software sequencing mode, which means that the controller
+ exposes the low level SPI-NOR opcodes to the software. Using
+ this driver it is possible to upgrade BIOS directly from Linux.
Say N here unless you know what you are doing. Overwriting the
SPI flash may render the system unbootable.
@@ -1142,9 +1151,6 @@ config SPI_SPIDEV
help
This supports user mode SPI protocol drivers.
- Note that this application programming interface is EXPERIMENTAL
- and hence SUBJECT TO CHANGE WITHOUT NOTICE while it stabilizes.
-
config SPI_LOOPBACK_TEST
tristate "spi loopback test framework support"
depends on m
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 12648f75a919..d87cf75bee6a 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_SPI_BCM2835) += spi-bcm2835.o
obj-$(CONFIG_SPI_BCM2835AUX) += spi-bcm2835aux.o
obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63xx.o
obj-$(CONFIG_SPI_BCM63XX_HSSPI) += spi-bcm63xx-hsspi.o
+obj-$(CONFIG_SPI_BCMBCA_HSSPI) += spi-bcmbca-hsspi.o
obj-$(CONFIG_SPI_BCM_QSPI) += spi-iproc-qspi.o spi-brcmstb-qspi.o spi-bcm-qspi.o
obj-$(CONFIG_SPI_BITBANG) += spi-bitbang.o
obj-$(CONFIG_SPI_BUTTERFLY) += spi-butterfly.o
diff --git a/drivers/spi/atmel-quadspi.c b/drivers/spi/atmel-quadspi.c
index 70637e46290a..f4632cb07495 100644
--- a/drivers/spi/atmel-quadspi.c
+++ b/drivers/spi/atmel-quadspi.c
@@ -406,7 +406,7 @@ static int atmel_qspi_set_cfg(struct atmel_qspi *aq,
static int atmel_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
- struct atmel_qspi *aq = spi_controller_get_devdata(mem->spi->master);
+ struct atmel_qspi *aq = spi_controller_get_devdata(mem->spi->controller);
u32 sr, offset;
int err;
@@ -476,7 +476,7 @@ static const struct spi_controller_mem_ops atmel_qspi_mem_ops = {
static int atmel_qspi_setup(struct spi_device *spi)
{
- struct spi_controller *ctrl = spi->master;
+ struct spi_controller *ctrl = spi->controller;
struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
unsigned long src_rate;
u32 scbr;
@@ -512,7 +512,7 @@ static int atmel_qspi_setup(struct spi_device *spi)
static int atmel_qspi_set_cs_timing(struct spi_device *spi)
{
- struct spi_controller *ctrl = spi->master;
+ struct spi_controller *ctrl = spi->controller;
struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
unsigned long clk_rate;
u32 cs_setup;
@@ -582,7 +582,7 @@ static int atmel_qspi_probe(struct platform_device *pdev)
struct resource *res;
int irq, err = 0;
- ctrl = devm_spi_alloc_master(&pdev->dev, sizeof(*aq));
+ ctrl = devm_spi_alloc_host(&pdev->dev, sizeof(*aq));
if (!ctrl)
return -ENOMEM;
diff --git a/drivers/spi/spi-altera-core.c b/drivers/spi/spi-altera-core.c
index de4d31c530d9..94fe6bf1b9a6 100644
--- a/drivers/spi/spi-altera-core.c
+++ b/drivers/spi/spi-altera-core.c
@@ -24,7 +24,7 @@
#define ALTERA_SPI_TXDATA 4
#define ALTERA_SPI_STATUS 8
#define ALTERA_SPI_CONTROL 12
-#define ALTERA_SPI_SLAVE_SEL 20
+#define ALTERA_SPI_TARGET_SEL 20
#define ALTERA_SPI_STATUS_ROE_MSK 0x8
#define ALTERA_SPI_STATUS_TOE_MSK 0x10
@@ -67,7 +67,7 @@ static int altr_spi_readl(struct altera_spi *hw, unsigned int reg,
static inline struct altera_spi *altera_spi_to_hw(struct spi_device *sdev)
{
- return spi_master_get_devdata(sdev->master);
+ return spi_controller_get_devdata(sdev->controller);
}
static void altera_spi_set_cs(struct spi_device *spi, bool is_high)
@@ -77,9 +77,9 @@ static void altera_spi_set_cs(struct spi_device *spi, bool is_high)
if (is_high) {
hw->imr &= ~ALTERA_SPI_CONTROL_SSO_MSK;
altr_spi_writel(hw, ALTERA_SPI_CONTROL, hw->imr);
- altr_spi_writel(hw, ALTERA_SPI_SLAVE_SEL, 0);
+ altr_spi_writel(hw, ALTERA_SPI_TARGET_SEL, 0);
} else {
- altr_spi_writel(hw, ALTERA_SPI_SLAVE_SEL,
+ altr_spi_writel(hw, ALTERA_SPI_TARGET_SEL,
BIT(spi->chip_select));
hw->imr |= ALTERA_SPI_CONTROL_SSO_MSK;
altr_spi_writel(hw, ALTERA_SPI_CONTROL, hw->imr);
@@ -139,10 +139,10 @@ static void altera_spi_rx_word(struct altera_spi *hw)
hw->count++;
}
-static int altera_spi_txrx(struct spi_master *master,
+static int altera_spi_txrx(struct spi_controller *host,
struct spi_device *spi, struct spi_transfer *t)
{
- struct altera_spi *hw = spi_master_get_devdata(master);
+ struct altera_spi *hw = spi_controller_get_devdata(host);
u32 val;
hw->tx = t->tx_buf;
@@ -175,15 +175,15 @@ static int altera_spi_txrx(struct spi_master *master,
altera_spi_rx_word(hw);
}
- spi_finalize_current_transfer(master);
+ spi_finalize_current_transfer(host);
return 0;
}
irqreturn_t altera_spi_irq(int irq, void *dev)
{
- struct spi_master *master = dev;
- struct altera_spi *hw = spi_master_get_devdata(master);
+ struct spi_controller *host = dev;
+ struct altera_spi *hw = spi_controller_get_devdata(host);
altera_spi_rx_word(hw);
@@ -194,20 +194,20 @@ irqreturn_t altera_spi_irq(int irq, void *dev)
hw->imr &= ~ALTERA_SPI_CONTROL_IRRDY_MSK;
altr_spi_writel(hw, ALTERA_SPI_CONTROL, hw->imr);
- spi_finalize_current_transfer(master);
+ spi_finalize_current_transfer(host);
}
return IRQ_HANDLED;
}
EXPORT_SYMBOL_GPL(altera_spi_irq);
-void altera_spi_init_master(struct spi_master *master)
+void altera_spi_init_host(struct spi_controller *host)
{
- struct altera_spi *hw = spi_master_get_devdata(master);
+ struct altera_spi *hw = spi_controller_get_devdata(host);
u32 val;
- master->transfer_one = altera_spi_txrx;
- master->set_cs = altera_spi_set_cs;
+ host->transfer_one = altera_spi_txrx;
+ host->set_cs = altera_spi_set_cs;
/* program defaults into the registers */
hw->imr = 0; /* disable spi interrupts */
@@ -217,6 +217,6 @@ void altera_spi_init_master(struct spi_master *master)
if (val & ALTERA_SPI_STATUS_RRDY_MSK)
altr_spi_readl(hw, ALTERA_SPI_RXDATA, &val); /* flush rxdata */
}
-EXPORT_SYMBOL_GPL(altera_spi_init_master);
+EXPORT_SYMBOL_GPL(altera_spi_init_host);
MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-altera-dfl.c b/drivers/spi/spi-altera-dfl.c
index 596e181ae136..5d6e08c12dff 100644
--- a/drivers/spi/spi-altera-dfl.c
+++ b/drivers/spi/spi-altera-dfl.c
@@ -104,20 +104,20 @@ static const struct regmap_config indirect_regbus_cfg = {
.reg_read = indirect_bus_reg_read,
};
-static void config_spi_master(void __iomem *base, struct spi_master *master)
+static void config_spi_host(void __iomem *base, struct spi_controller *host)
{
u64 v;
v = readq(base + SPI_CORE_PARAMETER);
- master->mode_bits = SPI_CS_HIGH;
+ host->mode_bits = SPI_CS_HIGH;
if (FIELD_GET(CLK_POLARITY, v))
- master->mode_bits |= SPI_CPOL;
+ host->mode_bits |= SPI_CPOL;
if (FIELD_GET(CLK_PHASE, v))
- master->mode_bits |= SPI_CPHA;
+ host->mode_bits |= SPI_CPHA;
- master->num_chipselect = FIELD_GET(NUM_CHIPSELECT, v);
- master->bits_per_word_mask =
+ host->num_chipselect = FIELD_GET(NUM_CHIPSELECT, v);
+ host->bits_per_word_mask =
SPI_BPW_RANGE_MASK(1, FIELD_GET(DATA_WIDTH, v));
}
@@ -125,18 +125,18 @@ static int dfl_spi_altera_probe(struct dfl_device *dfl_dev)
{
struct spi_board_info board_info = { 0 };
struct device *dev = &dfl_dev->dev;
- struct spi_master *master;
+ struct spi_controller *host;
struct altera_spi *hw;
void __iomem *base;
int err;
- master = devm_spi_alloc_master(dev, sizeof(struct altera_spi));
- if (!master)
+ host = devm_spi_alloc_host(dev, sizeof(struct altera_spi));
+ if (!host)
return -ENOMEM;
- master->bus_num = -1;
+ host->bus_num = -1;
- hw = spi_master_get_devdata(master);
+ hw = spi_controller_get_devdata(host);
hw->dev = dev;
@@ -145,10 +145,10 @@ static int dfl_spi_altera_probe(struct dfl_device *dfl_dev)
if (IS_ERR(base))
return PTR_ERR(base);
- config_spi_master(base, master);
+ config_spi_host(base, host);
dev_dbg(dev, "%s cs %u bpm 0x%x mode 0x%x\n", __func__,
- master->num_chipselect, master->bits_per_word_mask,
- master->mode_bits);
+ host->num_chipselect, host->bits_per_word_mask,
+ host->mode_bits);
hw->regmap = devm_regmap_init(dev, NULL, base, &indirect_regbus_cfg);
if (IS_ERR(hw->regmap))
@@ -156,11 +156,11 @@ static int dfl_spi_altera_probe(struct dfl_device *dfl_dev)
hw->irq = -EINVAL;
- altera_spi_init_master(master);
+ altera_spi_init_host(host);
- err = devm_spi_register_master(dev, master);
+ err = devm_spi_register_controller(dev, host);
if (err)
- return dev_err_probe(dev, err, "%s failed to register spi master\n",
+ return dev_err_probe(dev, err, "%s failed to register spi host\n",
__func__);
if (dfl_dev->revision == FME_FEATURE_REV_MAX10_SPI_N5010)
@@ -172,7 +172,7 @@ static int dfl_spi_altera_probe(struct dfl_device *dfl_dev)
board_info.bus_num = 0;
board_info.chip_select = 0;
- if (!spi_new_device(master, &board_info)) {
+ if (!spi_new_device(host, &board_info)) {
dev_err(dev, "%s failed to create SPI device: %s\n",
__func__, board_info.modalias);
}
diff --git a/drivers/spi/spi-altera-platform.c b/drivers/spi/spi-altera-platform.c
index 65147aae82a1..72e7a0f21793 100644
--- a/drivers/spi/spi-altera-platform.c
+++ b/drivers/spi/spi-altera-platform.c
@@ -39,16 +39,16 @@ static int altera_spi_probe(struct platform_device *pdev)
struct altera_spi_platform_data *pdata = dev_get_platdata(&pdev->dev);
enum altera_spi_type type = ALTERA_SPI_TYPE_UNKNOWN;
struct altera_spi *hw;
- struct spi_master *master;
+ struct spi_controller *host;
int err = -ENODEV;
u16 i;
- master = spi_alloc_master(&pdev->dev, sizeof(struct altera_spi));
- if (!master)
+ host = spi_alloc_host(&pdev->dev, sizeof(struct altera_spi));
+ if (!host)
return err;
- /* setup the master state. */
- master->bus_num = -1;
+ /* setup the host state. */
+ host->bus_num = -1;
if (pdata) {
if (pdata->num_chipselect > ALTERA_SPI_MAX_CS) {
@@ -59,18 +59,18 @@ static int altera_spi_probe(struct platform_device *pdev)
goto exit;
}
- master->num_chipselect = pdata->num_chipselect;
- master->mode_bits = pdata->mode_bits;
- master->bits_per_word_mask = pdata->bits_per_word_mask;
+ host->num_chipselect = pdata->num_chipselect;
+ host->mode_bits = pdata->mode_bits;
+ host->bits_per_word_mask = pdata->bits_per_word_mask;
} else {
- master->num_chipselect = 16;
- master->mode_bits = SPI_CS_HIGH;
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16);
+ host->num_chipselect = 16;
+ host->mode_bits = SPI_CS_HIGH;
+ host->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16);
}
- master->dev.of_node = pdev->dev.of_node;
+ host->dev.of_node = pdev->dev.of_node;
- hw = spi_master_get_devdata(master);
+ hw = spi_controller_get_devdata(host);
hw->dev = &pdev->dev;
if (platid)
@@ -107,24 +107,24 @@ static int altera_spi_probe(struct platform_device *pdev)
}
}
- altera_spi_init_master(master);
+ altera_spi_init_host(host);
/* irq is optional */
hw->irq = platform_get_irq(pdev, 0);
if (hw->irq >= 0) {
err = devm_request_irq(&pdev->dev, hw->irq, altera_spi_irq, 0,
- pdev->name, master);
+ pdev->name, host);
if (err)
goto exit;
}
- err = devm_spi_register_master(&pdev->dev, master);
+ err = devm_spi_register_controller(&pdev->dev, host);
if (err)
goto exit;
if (pdata) {
for (i = 0; i < pdata->num_devices; i++) {
- if (!spi_new_device(master, pdata->devices + i))
+ if (!spi_new_device(host, pdata->devices + i))
dev_warn(&pdev->dev,
"unable to create SPI device: %s\n",
pdata->devices[i].modalias);
@@ -135,7 +135,7 @@ static int altera_spi_probe(struct platform_device *pdev)
return 0;
exit:
- spi_master_put(master);
+ spi_controller_put(host);
return err;
}
diff --git a/drivers/spi/spi-ar934x.c b/drivers/spi/spi-ar934x.c
index ec7250c4c810..4a6ecaa0a9c9 100644
--- a/drivers/spi/spi-ar934x.c
+++ b/drivers/spi/spi-ar934x.c
@@ -61,7 +61,7 @@ static inline int ar934x_spi_clk_div(struct ar934x_spi *sp, unsigned int freq)
static int ar934x_spi_setup(struct spi_device *spi)
{
- struct ar934x_spi *sp = spi_controller_get_devdata(spi->master);
+ struct ar934x_spi *sp = spi_controller_get_devdata(spi->controller);
if ((spi->max_speed_hz == 0) ||
(spi->max_speed_hz > (sp->clk_freq / 2))) {
@@ -74,10 +74,10 @@ static int ar934x_spi_setup(struct spi_device *spi)
return 0;
}
-static int ar934x_spi_transfer_one_message(struct spi_controller *master,
+static int ar934x_spi_transfer_one_message(struct spi_controller *ctlr,
struct spi_message *m)
{
- struct ar934x_spi *sp = spi_controller_get_devdata(master);
+ struct ar934x_spi *sp = spi_controller_get_devdata(ctlr);
struct spi_transfer *t = NULL;
struct spi_device *spi = m->spi;
unsigned long trx_done, trx_cur;
@@ -150,7 +150,7 @@ static int ar934x_spi_transfer_one_message(struct spi_controller *master,
msg_done:
m->status = stat;
- spi_finalize_current_message(master);
+ spi_finalize_current_message(ctlr);
return 0;
}
@@ -183,7 +183,7 @@ static int ar934x_spi_probe(struct platform_device *pdev)
if (ret)
return ret;
- ctlr = devm_spi_alloc_master(&pdev->dev, sizeof(*sp));
+ ctlr = devm_spi_alloc_host(&pdev->dev, sizeof(*sp));
if (!ctlr) {
dev_info(&pdev->dev, "failed to allocate spi controller\n");
ret = -ENOMEM;
diff --git a/drivers/spi/spi-armada-3700.c b/drivers/spi/spi-armada-3700.c
index 9df9fc40b783..4d554b948d71 100644
--- a/drivers/spi/spi-armada-3700.c
+++ b/drivers/spi/spi-armada-3700.c
@@ -100,7 +100,7 @@
#define A3700_SPI_CLK_CAPT_EDGE BIT(7)
struct a3700_spi {
- struct spi_master *master;
+ struct spi_controller *host;
void __iomem *base;
struct clk *clk;
unsigned int irq;
@@ -174,7 +174,7 @@ static int a3700_spi_pin_mode_set(struct a3700_spi *a3700_spi,
val |= A3700_SPI_ADDR_PIN;
break;
default:
- dev_err(&a3700_spi->master->dev, "wrong pin mode %u", pin_mode);
+ dev_err(&a3700_spi->host->dev, "wrong pin mode %u", pin_mode);
return -EINVAL;
}
@@ -278,7 +278,7 @@ static int a3700_spi_fifo_flush(struct a3700_spi *a3700_spi)
static void a3700_spi_init(struct a3700_spi *a3700_spi)
{
- struct spi_master *master = a3700_spi->master;
+ struct spi_controller *host = a3700_spi->host;
u32 val;
int i;
@@ -295,14 +295,14 @@ static void a3700_spi_init(struct a3700_spi *a3700_spi)
/* Disable AUTO_CS and deactivate all chip-selects */
a3700_spi_auto_cs_unset(a3700_spi);
- for (i = 0; i < master->num_chipselect; i++)
+ for (i = 0; i < host->num_chipselect; i++)
a3700_spi_deactivate_cs(a3700_spi, i);
/* Enable FIFO mode */
a3700_spi_fifo_mode_set(a3700_spi, true);
/* Set SPI mode */
- a3700_spi_mode_set(a3700_spi, master->mode_bits);
+ a3700_spi_mode_set(a3700_spi, host->mode_bits);
/* Reset counters */
spireg_write(a3700_spi, A3700_SPI_IF_HDR_CNT_REG, 0);
@@ -315,11 +315,11 @@ static void a3700_spi_init(struct a3700_spi *a3700_spi)
static irqreturn_t a3700_spi_interrupt(int irq, void *dev_id)
{
- struct spi_master *master = dev_id;
+ struct spi_controller *host = dev_id;
struct a3700_spi *a3700_spi;
u32 cause;
- a3700_spi = spi_master_get_devdata(master);
+ a3700_spi = spi_controller_get_devdata(host);
/* Get interrupt causes */
cause = spireg_read(a3700_spi, A3700_SPI_INT_STAT_REG);
@@ -344,7 +344,7 @@ static bool a3700_spi_wait_completion(struct spi_device *spi)
unsigned int ctrl_reg;
unsigned long timeout_jiffies;
- a3700_spi = spi_master_get_devdata(spi->master);
+ a3700_spi = spi_controller_get_devdata(spi->controller);
/* SPI interrupt is edge-triggered, which means an interrupt will
* be generated only when detecting a specific status bit changed
@@ -393,7 +393,7 @@ static bool a3700_spi_transfer_wait(struct spi_device *spi,
{
struct a3700_spi *a3700_spi;
- a3700_spi = spi_master_get_devdata(spi->master);
+ a3700_spi = spi_controller_get_devdata(spi->controller);
a3700_spi->wait_mask = bit_mask;
return a3700_spi_wait_completion(spi);
@@ -417,7 +417,7 @@ static void a3700_spi_transfer_setup(struct spi_device *spi,
{
struct a3700_spi *a3700_spi;
- a3700_spi = spi_master_get_devdata(spi->master);
+ a3700_spi = spi_controller_get_devdata(spi->controller);
a3700_spi_clock_set(a3700_spi, xfer->speed_hz);
@@ -434,7 +434,7 @@ static void a3700_spi_transfer_setup(struct spi_device *spi,
static void a3700_spi_set_cs(struct spi_device *spi, bool enable)
{
- struct a3700_spi *a3700_spi = spi_master_get_devdata(spi->master);
+ struct a3700_spi *a3700_spi = spi_controller_get_devdata(spi->controller);
if (!enable)
a3700_spi_activate_cs(a3700_spi, spi->chip_select);
@@ -565,10 +565,10 @@ static void a3700_spi_transfer_abort_fifo(struct a3700_spi *a3700_spi)
spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
}
-static int a3700_spi_prepare_message(struct spi_master *master,
+static int a3700_spi_prepare_message(struct spi_controller *host,
struct spi_message *message)
{
- struct a3700_spi *a3700_spi = spi_master_get_devdata(master);
+ struct a3700_spi *a3700_spi = spi_controller_get_devdata(host);
struct spi_device *spi = message->spi;
int ret;
@@ -588,11 +588,11 @@ static int a3700_spi_prepare_message(struct spi_master *master,
return 0;
}
-static int a3700_spi_transfer_one_fifo(struct spi_master *master,
+static int a3700_spi_transfer_one_fifo(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct a3700_spi *a3700_spi = spi_master_get_devdata(master);
+ struct a3700_spi *a3700_spi = spi_controller_get_devdata(host);
int ret = 0, timeout = A3700_SPI_TIMEOUT;
unsigned int nbits = 0, byte_len;
u32 val;
@@ -732,16 +732,16 @@ static int a3700_spi_transfer_one_fifo(struct spi_master *master,
error:
a3700_spi_transfer_abort_fifo(a3700_spi);
out:
- spi_finalize_current_transfer(master);
+ spi_finalize_current_transfer(host);
return ret;
}
-static int a3700_spi_transfer_one_full_duplex(struct spi_master *master,
+static int a3700_spi_transfer_one_full_duplex(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct a3700_spi *a3700_spi = spi_master_get_devdata(master);
+ struct a3700_spi *a3700_spi = spi_controller_get_devdata(host);
u32 val;
/* Disable FIFO mode */
@@ -777,27 +777,27 @@ static int a3700_spi_transfer_one_full_duplex(struct spi_master *master,
}
- spi_finalize_current_transfer(master);
+ spi_finalize_current_transfer(host);
return 0;
}
-static int a3700_spi_transfer_one(struct spi_master *master,
+static int a3700_spi_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
a3700_spi_transfer_setup(spi, xfer);
if (xfer->tx_buf && xfer->rx_buf)
- return a3700_spi_transfer_one_full_duplex(master, spi, xfer);
+ return a3700_spi_transfer_one_full_duplex(host, spi, xfer);
- return a3700_spi_transfer_one_fifo(master, spi, xfer);
+ return a3700_spi_transfer_one_fifo(host, spi, xfer);
}
-static int a3700_spi_unprepare_message(struct spi_master *master,
+static int a3700_spi_unprepare_message(struct spi_controller *host,
struct spi_message *message)
{
- struct a3700_spi *a3700_spi = spi_master_get_devdata(master);
+ struct a3700_spi *a3700_spi = spi_controller_get_devdata(host);
clk_disable(a3700_spi->clk);
@@ -815,14 +815,14 @@ static int a3700_spi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *of_node = dev->of_node;
- struct spi_master *master;
+ struct spi_controller *host;
struct a3700_spi *spi;
u32 num_cs = 0;
int irq, ret = 0;
- master = spi_alloc_master(dev, sizeof(*spi));
- if (!master) {
- dev_err(dev, "master allocation failed\n");
+ host = spi_alloc_host(dev, sizeof(*spi));
+ if (!host) {
+ dev_err(dev, "host allocation failed\n");
ret = -ENOMEM;
goto out;
}
@@ -833,23 +833,23 @@ static int a3700_spi_probe(struct platform_device *pdev)
goto error;
}
- master->bus_num = pdev->id;
- master->dev.of_node = of_node;
- master->mode_bits = SPI_MODE_3;
- master->num_chipselect = num_cs;
- master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(32);
- master->prepare_message = a3700_spi_prepare_message;
- master->transfer_one = a3700_spi_transfer_one;
- master->unprepare_message = a3700_spi_unprepare_message;
- master->set_cs = a3700_spi_set_cs;
- master->mode_bits |= (SPI_RX_DUAL | SPI_TX_DUAL |
+ host->bus_num = pdev->id;
+ host->dev.of_node = of_node;
+ host->mode_bits = SPI_MODE_3;
+ host->num_chipselect = num_cs;
+ host->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(32);
+ host->prepare_message = a3700_spi_prepare_message;
+ host->transfer_one = a3700_spi_transfer_one;
+ host->unprepare_message = a3700_spi_unprepare_message;
+ host->set_cs = a3700_spi_set_cs;
+ host->mode_bits |= (SPI_RX_DUAL | SPI_TX_DUAL |
SPI_RX_QUAD | SPI_TX_QUAD);
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
- spi = spi_master_get_devdata(master);
+ spi = spi_controller_get_devdata(host);
- spi->master = master;
+ spi->host = host;
spi->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(spi->base)) {
@@ -878,23 +878,23 @@ static int a3700_spi_probe(struct platform_device *pdev)
goto error;
}
- master->max_speed_hz = min_t(unsigned long, A3700_SPI_MAX_SPEED_HZ,
+ host->max_speed_hz = min_t(unsigned long, A3700_SPI_MAX_SPEED_HZ,
clk_get_rate(spi->clk));
- master->min_speed_hz = DIV_ROUND_UP(clk_get_rate(spi->clk),
+ host->min_speed_hz = DIV_ROUND_UP(clk_get_rate(spi->clk),
A3700_SPI_MAX_PRESCALE);
a3700_spi_init(spi);
ret = devm_request_irq(dev, spi->irq, a3700_spi_interrupt, 0,
- dev_name(dev), master);
+ dev_name(dev), host);
if (ret) {
dev_err(dev, "could not request IRQ: %d\n", ret);
goto error_clk;
}
- ret = devm_spi_register_master(dev, master);
+ ret = devm_spi_register_controller(dev, host);
if (ret) {
- dev_err(dev, "Failed to register master\n");
+ dev_err(dev, "Failed to register host\n");
goto error_clk;
}
@@ -903,15 +903,15 @@ static int a3700_spi_probe(struct platform_device *pdev)
error_clk:
clk_unprepare(spi->clk);
error:
- spi_master_put(master);
+ spi_controller_put(host);
out:
return ret;
}
static int a3700_spi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct a3700_spi *spi = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct a3700_spi *spi = spi_controller_get_devdata(host);
clk_unprepare(spi->clk);
diff --git a/drivers/spi/spi-at91-usart.c b/drivers/spi/spi-at91-usart.c
index 9cd738682aab..fab9d223e24a 100644
--- a/drivers/spi/spi-at91-usart.c
+++ b/drivers/spi/spi-at91-usart.c
@@ -38,7 +38,7 @@
#define US_CR_TXEN BIT(6)
#define US_CR_TXDIS BIT(7)
-#define US_MR_SPI_MASTER 0x0E
+#define US_MR_SPI_HOST 0x0E
#define US_MR_CHRL GENMASK(7, 6)
#define US_MR_CPHA BIT(8)
#define US_MR_CPOL BIT(16)
@@ -61,7 +61,7 @@
#define US_OVRE_RXRDY_IRQS (US_IR_OVRE | US_IR_RXRDY)
#define US_INIT \
- (US_MR_SPI_MASTER | US_MR_CHRL | US_MR_CLKO | US_MR_WRDBT)
+ (US_MR_SPI_HOST | US_MR_CHRL | US_MR_CLKO | US_MR_WRDBT)
#define US_DMA_MIN_BYTES 16
#define US_DMA_TIMEOUT (msecs_to_jiffies(1000))
@@ -104,7 +104,7 @@ struct at91_usart_spi {
static void dma_callback(void *data)
{
struct spi_controller *ctlr = data;
- struct at91_usart_spi *aus = spi_master_get_devdata(ctlr);
+ struct at91_usart_spi *aus = spi_controller_get_devdata(ctlr);
at91_usart_spi_writel(aus, IER, US_IR_RXRDY);
aus->current_rx_remaining_bytes = 0;
@@ -115,7 +115,7 @@ static bool at91_usart_spi_can_dma(struct spi_controller *ctrl,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct at91_usart_spi *aus = spi_master_get_devdata(ctrl);
+ struct at91_usart_spi *aus = spi_controller_get_devdata(ctrl);
return aus->use_dma && xfer->len >= US_DMA_MIN_BYTES;
}
@@ -216,7 +216,7 @@ static void at91_usart_spi_stop_dma(struct spi_controller *ctlr)
static int at91_usart_spi_dma_transfer(struct spi_controller *ctlr,
struct spi_transfer *xfer)
{
- struct at91_usart_spi *aus = spi_master_get_devdata(ctlr);
+ struct at91_usart_spi *aus = spi_controller_get_devdata(ctlr);
struct dma_chan *rxchan = ctlr->dma_rx;
struct dma_chan *txchan = ctlr->dma_tx;
struct dma_async_tx_descriptor *rxdesc;
@@ -334,7 +334,7 @@ at91_usart_spi_set_xfer_speed(struct at91_usart_spi *aus,
static irqreturn_t at91_usart_spi_interrupt(int irq, void *dev_id)
{
struct spi_controller *controller = dev_id;
- struct at91_usart_spi *aus = spi_master_get_devdata(controller);
+ struct at91_usart_spi *aus = spi_controller_get_devdata(controller);
spin_lock(&aus->lock);
at91_usart_spi_read_status(aus);
@@ -359,7 +359,7 @@ static irqreturn_t at91_usart_spi_interrupt(int irq, void *dev_id)
static int at91_usart_spi_setup(struct spi_device *spi)
{
- struct at91_usart_spi *aus = spi_master_get_devdata(spi->controller);
+ struct at91_usart_spi *aus = spi_controller_get_devdata(spi->controller);
u32 *ausd = spi->controller_state;
unsigned int mr = at91_usart_spi_readl(aus, MR);
@@ -399,7 +399,7 @@ static int at91_usart_spi_transfer_one(struct spi_controller *ctlr,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct at91_usart_spi *aus = spi_master_get_devdata(ctlr);
+ struct at91_usart_spi *aus = spi_controller_get_devdata(ctlr);
unsigned long dma_timeout = 0;
int ret = 0;
@@ -444,7 +444,7 @@ static int at91_usart_spi_transfer_one(struct spi_controller *ctlr,
static int at91_usart_spi_prepare_message(struct spi_controller *ctlr,
struct spi_message *message)
{
- struct at91_usart_spi *aus = spi_master_get_devdata(ctlr);
+ struct at91_usart_spi *aus = spi_controller_get_devdata(ctlr);
struct spi_device *spi = message->spi;
u32 *ausd = spi->controller_state;
@@ -458,7 +458,7 @@ static int at91_usart_spi_prepare_message(struct spi_controller *ctlr,
static int at91_usart_spi_unprepare_message(struct spi_controller *ctlr,
struct spi_message *message)
{
- struct at91_usart_spi *aus = spi_master_get_devdata(ctlr);
+ struct at91_usart_spi *aus = spi_controller_get_devdata(ctlr);
at91_usart_spi_writel(aus, CR, US_RESET | US_DISABLE);
at91_usart_spi_writel(aus, IDR, US_OVRE_RXRDY_IRQS);
@@ -515,7 +515,7 @@ static int at91_usart_spi_probe(struct platform_device *pdev)
return PTR_ERR(clk);
ret = -ENOMEM;
- controller = spi_alloc_master(&pdev->dev, sizeof(*aus));
+ controller = spi_alloc_host(&pdev->dev, sizeof(*aus));
if (!controller)
goto at91_usart_spi_probe_fail;
@@ -539,7 +539,7 @@ static int at91_usart_spi_probe(struct platform_device *pdev)
US_MAX_CLK_DIV);
platform_set_drvdata(pdev, controller);
- aus = spi_master_get_devdata(controller);
+ aus = spi_controller_get_devdata(controller);
aus->dev = &pdev->dev;
aus->regs = devm_ioremap_resource(&pdev->dev, regs);
@@ -574,9 +574,9 @@ static int at91_usart_spi_probe(struct platform_device *pdev)
spin_lock_init(&aus->lock);
init_completion(&aus->xfer_completion);
- ret = devm_spi_register_master(&pdev->dev, controller);
+ ret = devm_spi_register_controller(&pdev->dev, controller);
if (ret)
- goto at91_usart_fail_register_master;
+ goto at91_usart_fail_register_controller;
dev_info(&pdev->dev,
"AT91 USART SPI Controller version 0x%x at %pa (irq %d)\n",
@@ -585,19 +585,19 @@ static int at91_usart_spi_probe(struct platform_device *pdev)
return 0;
-at91_usart_fail_register_master:
+at91_usart_fail_register_controller:
at91_usart_spi_release_dma(controller);
at91_usart_fail_dma:
clk_disable_unprepare(clk);
at91_usart_spi_probe_fail:
- spi_master_put(controller);
+ spi_controller_put(controller);
return ret;
}
__maybe_unused static int at91_usart_spi_runtime_suspend(struct device *dev)
{
struct spi_controller *ctlr = dev_get_drvdata(dev);
- struct at91_usart_spi *aus = spi_master_get_devdata(ctlr);
+ struct at91_usart_spi *aus = spi_controller_get_devdata(ctlr);
clk_disable_unprepare(aus->clk);
pinctrl_pm_select_sleep_state(dev);
@@ -608,7 +608,7 @@ __maybe_unused static int at91_usart_spi_runtime_suspend(struct device *dev)
__maybe_unused static int at91_usart_spi_runtime_resume(struct device *dev)
{
struct spi_controller *ctrl = dev_get_drvdata(dev);
- struct at91_usart_spi *aus = spi_master_get_devdata(ctrl);
+ struct at91_usart_spi *aus = spi_controller_get_devdata(ctrl);
pinctrl_pm_select_default_state(dev);
@@ -633,7 +633,7 @@ __maybe_unused static int at91_usart_spi_suspend(struct device *dev)
__maybe_unused static int at91_usart_spi_resume(struct device *dev)
{
struct spi_controller *ctrl = dev_get_drvdata(dev);
- struct at91_usart_spi *aus = spi_master_get_devdata(ctrl);
+ struct at91_usart_spi *aus = spi_controller_get_devdata(ctrl);
int ret;
if (!pm_runtime_suspended(dev)) {
@@ -650,7 +650,7 @@ __maybe_unused static int at91_usart_spi_resume(struct device *dev)
static int at91_usart_spi_remove(struct platform_device *pdev)
{
struct spi_controller *ctlr = platform_get_drvdata(pdev);
- struct at91_usart_spi *aus = spi_master_get_devdata(ctlr);
+ struct at91_usart_spi *aus = spi_controller_get_devdata(ctlr);
at91_usart_spi_release_dma(ctlr);
clk_disable_unprepare(aus->clk);
diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c
index 607e7a49fb89..795e88dbef1b 100644
--- a/drivers/spi/spi-ath79.c
+++ b/drivers/spi/spi-ath79.c
@@ -58,7 +58,7 @@ static inline void ath79_spi_wr(struct ath79_spi *sp, unsigned int reg, u32 val)
static inline struct ath79_spi *ath79_spidev_to_sp(struct spi_device *spi)
{
- return spi_master_get_devdata(spi->master);
+ return spi_controller_get_devdata(spi->controller);
}
static inline void ath79_spi_delay(struct ath79_spi *sp, unsigned int nsecs)
@@ -120,7 +120,7 @@ static u32 ath79_spi_txrx_mode0(struct spi_device *spi, unsigned int nsecs,
else
out = ioc & ~AR71XX_SPI_IOC_DO;
- /* setup MSB (to slave) on trailing edge */
+ /* setup MSB (to target) on trailing edge */
ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, out);
ath79_spi_delay(sp, nsecs);
ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, out | AR71XX_SPI_IOC_CLK);
@@ -168,28 +168,28 @@ static const struct spi_controller_mem_ops ath79_mem_ops = {
static int ath79_spi_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct ath79_spi *sp;
unsigned long rate;
int ret;
- master = spi_alloc_master(&pdev->dev, sizeof(*sp));
- if (master == NULL) {
- dev_err(&pdev->dev, "failed to allocate spi master\n");
+ host = spi_alloc_host(&pdev->dev, sizeof(*sp));
+ if (host == NULL) {
+ dev_err(&pdev->dev, "failed to allocate spi host\n");
return -ENOMEM;
}
- sp = spi_master_get_devdata(master);
- master->dev.of_node = pdev->dev.of_node;
+ sp = spi_controller_get_devdata(host);
+ host->dev.of_node = pdev->dev.of_node;
platform_set_drvdata(pdev, sp);
- master->use_gpio_descriptors = true;
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
- master->flags = SPI_MASTER_GPIO_SS;
- master->num_chipselect = 3;
- master->mem_ops = &ath79_mem_ops;
+ host->use_gpio_descriptors = true;
+ host->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
+ host->flags = SPI_MASTER_GPIO_SS;
+ host->num_chipselect = 3;
+ host->mem_ops = &ath79_mem_ops;
- sp->bitbang.master = master;
+ sp->bitbang.master = host;
sp->bitbang.chipselect = ath79_spi_chipselect;
sp->bitbang.txrx_word[SPI_MODE_0] = ath79_spi_txrx_mode0;
sp->bitbang.flags = SPI_CS_HIGH;
@@ -197,18 +197,18 @@ static int ath79_spi_probe(struct platform_device *pdev)
sp->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(sp->base)) {
ret = PTR_ERR(sp->base);
- goto err_put_master;
+ goto err_put_host;
}
sp->clk = devm_clk_get(&pdev->dev, "ahb");
if (IS_ERR(sp->clk)) {
ret = PTR_ERR(sp->clk);
- goto err_put_master;
+ goto err_put_host;
}
ret = clk_prepare_enable(sp->clk);
if (ret)
- goto err_put_master;
+ goto err_put_host;
rate = DIV_ROUND_UP(clk_get_rate(sp->clk), MHZ);
if (!rate) {
@@ -231,8 +231,8 @@ err_disable:
ath79_spi_disable(sp);
err_clk_disable:
clk_disable_unprepare(sp->clk);
-err_put_master:
- spi_master_put(sp->bitbang.master);
+err_put_host:
+ spi_controller_put(host);
return ret;
}
@@ -244,7 +244,7 @@ static int ath79_spi_remove(struct platform_device *pdev)
spi_bitbang_stop(&sp->bitbang);
ath79_spi_disable(sp);
clk_disable_unprepare(sp->clk);
- spi_master_put(sp->bitbang.master);
+ spi_controller_put(sp->bitbang.master);
return 0;
}
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index c4f22d50dba5..5c5678f065f3 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -358,7 +358,7 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi)
u32 csr;
/* Make sure clock polarity is correct */
- for (i = 0; i < spi->master->num_chipselect; i++) {
+ for (i = 0; i < spi->controller->num_chipselect; i++) {
csr = spi_readl(as, CSR0 + 4 * i);
if ((csr ^ cpol) & SPI_BIT(CPOL))
spi_writel(as, CSR0 + 4 * i,
@@ -419,11 +419,11 @@ static inline bool atmel_spi_use_dma(struct atmel_spi *as,
return as->use_dma && xfer->len >= DMA_MIN_BYTES;
}
-static bool atmel_spi_can_dma(struct spi_master *master,
+static bool atmel_spi_can_dma(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct atmel_spi *as = spi_master_get_devdata(master);
+ struct atmel_spi *as = spi_controller_get_devdata(host);
if (IS_ENABLED(CONFIG_SOC_SAM_V4_V5))
return atmel_spi_use_dma(as, xfer) &&
@@ -435,7 +435,7 @@ static bool atmel_spi_can_dma(struct spi_master *master,
static int atmel_spi_dma_slave_config(struct atmel_spi *as, u8 bits_per_word)
{
- struct spi_master *master = platform_get_drvdata(as->pdev);
+ struct spi_controller *host = platform_get_drvdata(as->pdev);
struct dma_slave_config slave_config;
int err = 0;
@@ -467,21 +467,21 @@ static int atmel_spi_dma_slave_config(struct atmel_spi *as, u8 bits_per_word)
* So we'd rather write only one data at the time. Hence the transmit
* path works the same whether FIFOs are available (and enabled) or not.
*/
- if (dmaengine_slave_config(master->dma_tx, &slave_config)) {
+ if (dmaengine_slave_config(host->dma_tx, &slave_config)) {
dev_err(&as->pdev->dev,
"failed to configure tx dma channel\n");
err = -EINVAL;
}
/*
- * This driver configures the spi controller for master mode (MSTR bit
+ * This driver configures the spi controller for host mode (MSTR bit
* set to '1' in the Mode Register).
* So according to the datasheet, when FIFOs are available (and
* enabled), the Receive FIFO operates in Single Data Mode.
* So the receive path works the same whether FIFOs are available (and
* enabled) or not.
*/
- if (dmaengine_slave_config(master->dma_rx, &slave_config)) {
+ if (dmaengine_slave_config(host->dma_rx, &slave_config)) {
dev_err(&as->pdev->dev,
"failed to configure rx dma channel\n");
err = -EINVAL;
@@ -490,22 +490,22 @@ static int atmel_spi_dma_slave_config(struct atmel_spi *as, u8 bits_per_word)
return err;
}
-static int atmel_spi_configure_dma(struct spi_master *master,
+static int atmel_spi_configure_dma(struct spi_controller *host,
struct atmel_spi *as)
{
struct device *dev = &as->pdev->dev;
int err;
- master->dma_tx = dma_request_chan(dev, "tx");
- if (IS_ERR(master->dma_tx)) {
- err = PTR_ERR(master->dma_tx);
+ host->dma_tx = dma_request_chan(dev, "tx");
+ if (IS_ERR(host->dma_tx)) {
+ err = PTR_ERR(host->dma_tx);
dev_dbg(dev, "No TX DMA channel, DMA is disabled\n");
goto error_clear;
}
- master->dma_rx = dma_request_chan(dev, "rx");
- if (IS_ERR(master->dma_rx)) {
- err = PTR_ERR(master->dma_rx);
+ host->dma_rx = dma_request_chan(dev, "rx");
+ if (IS_ERR(host->dma_rx)) {
+ err = PTR_ERR(host->dma_rx);
/*
* No reason to check EPROBE_DEFER here since we have already
* requested tx channel.
@@ -520,45 +520,45 @@ static int atmel_spi_configure_dma(struct spi_master *master,
dev_info(&as->pdev->dev,
"Using %s (tx) and %s (rx) for DMA transfers\n",
- dma_chan_name(master->dma_tx),
- dma_chan_name(master->dma_rx));
+ dma_chan_name(host->dma_tx),
+ dma_chan_name(host->dma_rx));
return 0;
error:
- if (!IS_ERR(master->dma_rx))
- dma_release_channel(master->dma_rx);
- if (!IS_ERR(master->dma_tx))
- dma_release_channel(master->dma_tx);
+ if (!IS_ERR(host->dma_rx))
+ dma_release_channel(host->dma_rx);
+ if (!IS_ERR(host->dma_tx))
+ dma_release_channel(host->dma_tx);
error_clear:
- master->dma_tx = master->dma_rx = NULL;
+ host->dma_tx = host->dma_rx = NULL;
return err;
}
-static void atmel_spi_stop_dma(struct spi_master *master)
+static void atmel_spi_stop_dma(struct spi_controller *host)
{
- if (master->dma_rx)
- dmaengine_terminate_all(master->dma_rx);
- if (master->dma_tx)
- dmaengine_terminate_all(master->dma_tx);
+ if (host->dma_rx)
+ dmaengine_terminate_all(host->dma_rx);
+ if (host->dma_tx)
+ dmaengine_terminate_all(host->dma_tx);
}
-static void atmel_spi_release_dma(struct spi_master *master)
+static void atmel_spi_release_dma(struct spi_controller *host)
{
- if (master->dma_rx) {
- dma_release_channel(master->dma_rx);
- master->dma_rx = NULL;
+ if (host->dma_rx) {
+ dma_release_channel(host->dma_rx);
+ host->dma_rx = NULL;
}
- if (master->dma_tx) {
- dma_release_channel(master->dma_tx);
- master->dma_tx = NULL;
+ if (host->dma_tx) {
+ dma_release_channel(host->dma_tx);
+ host->dma_tx = NULL;
}
}
/* This function is called by the DMA driver from tasklet context */
static void dma_callback(void *data)
{
- struct spi_master *master = data;
- struct atmel_spi *as = spi_master_get_devdata(master);
+ struct spi_controller *host = data;
+ struct atmel_spi *as = spi_controller_get_devdata(host);
if (is_vmalloc_addr(as->current_transfer->rx_buf) &&
IS_ENABLED(CONFIG_SOC_SAM_V4_V5)) {
@@ -571,13 +571,13 @@ static void dma_callback(void *data)
/*
* Next transfer using PIO without FIFO.
*/
-static void atmel_spi_next_xfer_single(struct spi_master *master,
+static void atmel_spi_next_xfer_single(struct spi_controller *host,
struct spi_transfer *xfer)
{
- struct atmel_spi *as = spi_master_get_devdata(master);
+ struct atmel_spi *as = spi_controller_get_devdata(host);
unsigned long xfer_pos = xfer->len - as->current_remaining_bytes;
- dev_vdbg(master->dev.parent, "atmel_spi_next_xfer_pio\n");
+ dev_vdbg(host->dev.parent, "atmel_spi_next_xfer_pio\n");
/* Make sure data is not remaining in RDR */
spi_readl(as, RDR);
@@ -591,7 +591,7 @@ static void atmel_spi_next_xfer_single(struct spi_master *master,
else
spi_writel(as, TDR, *(u8 *)(xfer->tx_buf + xfer_pos));
- dev_dbg(master->dev.parent,
+ dev_dbg(host->dev.parent,
" start pio xfer %p: len %u tx %p rx %p bitpw %d\n",
xfer, xfer->len, xfer->tx_buf, xfer->rx_buf,
xfer->bits_per_word);
@@ -603,10 +603,10 @@ static void atmel_spi_next_xfer_single(struct spi_master *master,
/*
* Next transfer using PIO with FIFO.
*/
-static void atmel_spi_next_xfer_fifo(struct spi_master *master,
+static void atmel_spi_next_xfer_fifo(struct spi_controller *host,
struct spi_transfer *xfer)
{
- struct atmel_spi *as = spi_master_get_devdata(master);
+ struct atmel_spi *as = spi_controller_get_devdata(host);
u32 current_remaining_data, num_data;
u32 offset = xfer->len - as->current_remaining_bytes;
const u16 *words = (const u16 *)((u8 *)xfer->tx_buf + offset);
@@ -614,7 +614,7 @@ static void atmel_spi_next_xfer_fifo(struct spi_master *master,
u16 td0, td1;
u32 fifomr;
- dev_vdbg(master->dev.parent, "atmel_spi_next_xfer_fifo\n");
+ dev_vdbg(host->dev.parent, "atmel_spi_next_xfer_fifo\n");
/* Compute the number of data to transfer in the current iteration */
current_remaining_data = ((xfer->bits_per_word > 8) ?
@@ -658,7 +658,7 @@ static void atmel_spi_next_xfer_fifo(struct spi_master *master,
num_data--;
}
- dev_dbg(master->dev.parent,
+ dev_dbg(host->dev.parent,
" start fifo xfer %p: len %u tx %p rx %p bitpw %d\n",
xfer, xfer->len, xfer->tx_buf, xfer->rx_buf,
xfer->bits_per_word);
@@ -673,32 +673,32 @@ static void atmel_spi_next_xfer_fifo(struct spi_master *master,
/*
* Next transfer using PIO.
*/
-static void atmel_spi_next_xfer_pio(struct spi_master *master,
+static void atmel_spi_next_xfer_pio(struct spi_controller *host,
struct spi_transfer *xfer)
{
- struct atmel_spi *as = spi_master_get_devdata(master);
+ struct atmel_spi *as = spi_controller_get_devdata(host);
if (as->fifo_size)
- atmel_spi_next_xfer_fifo(master, xfer);
+ atmel_spi_next_xfer_fifo(host, xfer);
else
- atmel_spi_next_xfer_single(master, xfer);
+ atmel_spi_next_xfer_single(host, xfer);
}
/*
* Submit next transfer for DMA.
*/
-static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
+static int atmel_spi_next_xfer_dma_submit(struct spi_controller *host,
struct spi_transfer *xfer,
u32 *plen)
{
- struct atmel_spi *as = spi_master_get_devdata(master);
- struct dma_chan *rxchan = master->dma_rx;
- struct dma_chan *txchan = master->dma_tx;
+ struct atmel_spi *as = spi_controller_get_devdata(host);
+ struct dma_chan *rxchan = host->dma_rx;
+ struct dma_chan *txchan = host->dma_tx;
struct dma_async_tx_descriptor *rxdesc;
struct dma_async_tx_descriptor *txdesc;
dma_cookie_t cookie;
- dev_vdbg(master->dev.parent, "atmel_spi_next_xfer_dma_submit\n");
+ dev_vdbg(host->dev.parent, "atmel_spi_next_xfer_dma_submit\n");
/* Check that the channels are available */
if (!rxchan || !txchan)
@@ -749,7 +749,7 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
if (!txdesc)
goto err_dma;
- dev_dbg(master->dev.parent,
+ dev_dbg(host->dev.parent,
" start dma xfer %p: len %u tx %p/%08llx rx %p/%08llx\n",
xfer, xfer->len, xfer->tx_buf, (unsigned long long)xfer->tx_dma,
xfer->rx_buf, (unsigned long long)xfer->rx_dma);
@@ -759,7 +759,7 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
/* Put the callback on the RX transfer only, that should finish last */
rxdesc->callback = dma_callback;
- rxdesc->callback_param = master;
+ rxdesc->callback_param = host;
/* Submit and fire RX and TX with TX last so we're ready to read! */
cookie = rxdesc->tx_submit(rxdesc);
@@ -775,12 +775,12 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
err_dma:
spi_writel(as, IDR, SPI_BIT(OVRES));
- atmel_spi_stop_dma(master);
+ atmel_spi_stop_dma(host);
err_exit:
return -ENOMEM;
}
-static void atmel_spi_next_xfer_data(struct spi_master *master,
+static void atmel_spi_next_xfer_data(struct spi_controller *host,
struct spi_transfer *xfer,
dma_addr_t *tx_dma,
dma_addr_t *rx_dma,
@@ -788,8 +788,8 @@ static void atmel_spi_next_xfer_data(struct spi_master *master,
{
*rx_dma = xfer->rx_dma + xfer->len - *plen;
*tx_dma = xfer->tx_dma + xfer->len - *plen;
- if (*plen > master->max_dma_len)
- *plen = master->max_dma_len;
+ if (*plen > host->max_dma_len)
+ *plen = host->max_dma_len;
}
static int atmel_spi_set_xfer_speed(struct atmel_spi *as,
@@ -844,17 +844,17 @@ static int atmel_spi_set_xfer_speed(struct atmel_spi *as,
* Submit next transfer for PDC.
* lock is held, spi irq is blocked
*/
-static void atmel_spi_pdc_next_xfer(struct spi_master *master,
+static void atmel_spi_pdc_next_xfer(struct spi_controller *host,
struct spi_transfer *xfer)
{
- struct atmel_spi *as = spi_master_get_devdata(master);
+ struct atmel_spi *as = spi_controller_get_devdata(host);
u32 len;
dma_addr_t tx_dma, rx_dma;
spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
len = as->current_remaining_bytes;
- atmel_spi_next_xfer_data(master, xfer, &tx_dma, &rx_dma, &len);
+ atmel_spi_next_xfer_data(host, xfer, &tx_dma, &rx_dma, &len);
as->current_remaining_bytes -= len;
spi_writel(as, RPR, rx_dma);
@@ -865,7 +865,7 @@ static void atmel_spi_pdc_next_xfer(struct spi_master *master,
spi_writel(as, RCR, len);
spi_writel(as, TCR, len);
- dev_dbg(&master->dev,
+ dev_dbg(&host->dev,
" start xfer %p: len %u tx %p/%08llx rx %p/%08llx\n",
xfer, xfer->len, xfer->tx_buf,
(unsigned long long)xfer->tx_dma, xfer->rx_buf,
@@ -873,7 +873,7 @@ static void atmel_spi_pdc_next_xfer(struct spi_master *master,
if (as->current_remaining_bytes) {
len = as->current_remaining_bytes;
- atmel_spi_next_xfer_data(master, xfer, &tx_dma, &rx_dma, &len);
+ atmel_spi_next_xfer_data(host, xfer, &tx_dma, &rx_dma, &len);
as->current_remaining_bytes -= len;
spi_writel(as, RNPR, rx_dma);
@@ -884,7 +884,7 @@ static void atmel_spi_pdc_next_xfer(struct spi_master *master,
spi_writel(as, RNCR, len);
spi_writel(as, TNCR, len);
- dev_dbg(&master->dev,
+ dev_dbg(&host->dev,
" next xfer %p: len %u tx %p/%08llx rx %p/%08llx\n",
xfer, xfer->len, xfer->tx_buf,
(unsigned long long)xfer->tx_dma, xfer->rx_buf,
@@ -944,14 +944,14 @@ atmel_spi_dma_map_xfer(struct atmel_spi *as, struct spi_transfer *xfer)
return 0;
}
-static void atmel_spi_dma_unmap_xfer(struct spi_master *master,
+static void atmel_spi_dma_unmap_xfer(struct spi_controller *host,
struct spi_transfer *xfer)
{
if (xfer->tx_dma != INVALID_DMA_ADDRESS)
- dma_unmap_single(master->dev.parent, xfer->tx_dma,
+ dma_unmap_single(host->dev.parent, xfer->tx_dma,
xfer->len, DMA_TO_DEVICE);
if (xfer->rx_dma != INVALID_DMA_ADDRESS)
- dma_unmap_single(master->dev.parent, xfer->rx_dma,
+ dma_unmap_single(host->dev.parent, xfer->rx_dma,
xfer->len, DMA_FROM_DEVICE);
}
@@ -1039,8 +1039,8 @@ atmel_spi_pump_pio_data(struct atmel_spi *as, struct spi_transfer *xfer)
static irqreturn_t
atmel_spi_pio_interrupt(int irq, void *dev_id)
{
- struct spi_master *master = dev_id;
- struct atmel_spi *as = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_id;
+ struct atmel_spi *as = spi_controller_get_devdata(host);
u32 status, pending, imr;
struct spi_transfer *xfer;
int ret = IRQ_NONE;
@@ -1052,7 +1052,7 @@ atmel_spi_pio_interrupt(int irq, void *dev_id)
if (pending & SPI_BIT(OVRES)) {
ret = IRQ_HANDLED;
spi_writel(as, IDR, SPI_BIT(OVRES));
- dev_warn(master->dev.parent, "overrun\n");
+ dev_warn(host->dev.parent, "overrun\n");
/*
* When we get an overrun, we disregard the current
@@ -1097,8 +1097,8 @@ atmel_spi_pio_interrupt(int irq, void *dev_id)
static irqreturn_t
atmel_spi_pdc_interrupt(int irq, void *dev_id)
{
- struct spi_master *master = dev_id;
- struct atmel_spi *as = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_id;
+ struct atmel_spi *as = spi_controller_get_devdata(host);
u32 status, pending, imr;
int ret = IRQ_NONE;
@@ -1152,12 +1152,12 @@ static int atmel_word_delay_csr(struct spi_device *spi, struct atmel_spi *as)
static void initialize_native_cs_for_gpio(struct atmel_spi *as)
{
int i;
- struct spi_master *master = platform_get_drvdata(as->pdev);
+ struct spi_controller *host = platform_get_drvdata(as->pdev);
if (!as->native_cs_free)
return; /* already initialized */
- if (!master->cs_gpiods)
+ if (!host->cs_gpiods)
return; /* No CS GPIO */
/*
@@ -1170,7 +1170,7 @@ static void initialize_native_cs_for_gpio(struct atmel_spi *as)
i = 1;
for (; i < 4; i++)
- if (master->cs_gpiods[i])
+ if (host->cs_gpiods[i])
as->native_cs_free |= BIT(i);
if (as->native_cs_free)
@@ -1186,7 +1186,7 @@ static int atmel_spi_setup(struct spi_device *spi)
int chip_select;
int word_delay_csr;
- as = spi_master_get_devdata(spi->master);
+ as = spi_controller_get_devdata(spi->controller);
/* see notes above re chipselect */
if (!spi->cs_gpiod && (spi->mode & SPI_CS_HIGH)) {
@@ -1254,7 +1254,7 @@ static int atmel_spi_setup(struct spi_device *spi)
static void atmel_spi_set_cs(struct spi_device *spi, bool enable)
{
- struct atmel_spi *as = spi_master_get_devdata(spi->master);
+ struct atmel_spi *as = spi_controller_get_devdata(spi->controller);
/* the core doesn't really pass us enable/disable, but CS HIGH vs CS LOW
* since we already have routines for activate/deactivate translate
* high/low to active/inactive
@@ -1269,7 +1269,7 @@ static void atmel_spi_set_cs(struct spi_device *spi, bool enable)
}
-static int atmel_spi_one_transfer(struct spi_master *master,
+static int atmel_spi_one_transfer(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
@@ -1281,7 +1281,7 @@ static int atmel_spi_one_transfer(struct spi_master *master,
int ret;
unsigned long dma_timeout;
- as = spi_master_get_devdata(master);
+ as = spi_controller_get_devdata(host);
asd = spi->controller_state;
bits = (asd->csr >> 4) & 0xf;
@@ -1295,7 +1295,7 @@ static int atmel_spi_one_transfer(struct spi_master *master,
* DMA map early, for performance (empties dcache ASAP) and
* better fault reporting.
*/
- if ((!master->cur_msg->is_dma_mapped)
+ if ((!host->cur_msg->is_dma_mapped)
&& as->use_pdc) {
if (atmel_spi_dma_map_xfer(as, xfer) < 0)
return -ENOMEM;
@@ -1311,11 +1311,11 @@ static int atmel_spi_one_transfer(struct spi_master *master,
if (as->use_pdc) {
atmel_spi_lock(as);
- atmel_spi_pdc_next_xfer(master, xfer);
+ atmel_spi_pdc_next_xfer(host, xfer);
atmel_spi_unlock(as);
} else if (atmel_spi_use_dma(as, xfer)) {
len = as->current_remaining_bytes;
- ret = atmel_spi_next_xfer_dma_submit(master,
+ ret = atmel_spi_next_xfer_dma_submit(host,
xfer, &len);
if (ret) {
dev_err(&spi->dev,
@@ -1329,7 +1329,7 @@ static int atmel_spi_one_transfer(struct spi_master *master,
}
} else {
atmel_spi_lock(as);
- atmel_spi_next_xfer_pio(master, xfer);
+ atmel_spi_next_xfer_pio(host, xfer);
atmel_spi_unlock(as);
}
@@ -1346,7 +1346,7 @@ static int atmel_spi_one_transfer(struct spi_master *master,
if (as->done_status) {
if (as->use_pdc) {
- dev_warn(master->dev.parent,
+ dev_warn(host->dev.parent,
"overrun (%u/%u remaining)\n",
spi_readl(as, TCR), spi_readl(as, RCR));
@@ -1362,7 +1362,7 @@ static int atmel_spi_one_transfer(struct spi_master *master,
if (spi_readl(as, SR) & SPI_BIT(TXEMPTY))
break;
if (!timeout)
- dev_warn(master->dev.parent,
+ dev_warn(host->dev.parent,
"timeout waiting for TXEMPTY");
while (spi_readl(as, SR) & SPI_BIT(RDRF))
spi_readl(as, RDR);
@@ -1371,13 +1371,13 @@ static int atmel_spi_one_transfer(struct spi_master *master,
spi_readl(as, SR);
} else if (atmel_spi_use_dma(as, xfer)) {
- atmel_spi_stop_dma(master);
+ atmel_spi_stop_dma(host);
}
}
- if (!master->cur_msg->is_dma_mapped
+ if (!host->cur_msg->is_dma_mapped
&& as->use_pdc)
- atmel_spi_dma_unmap_xfer(master, xfer);
+ atmel_spi_dma_unmap_xfer(host, xfer);
if (as->use_pdc)
atmel_spi_disable_pdc_transfer(as);
@@ -1440,7 +1440,7 @@ static int atmel_spi_probe(struct platform_device *pdev)
int irq;
struct clk *clk;
int ret;
- struct spi_master *master;
+ struct spi_controller *host;
struct atmel_spi *as;
/* Select default pin state */
@@ -1459,29 +1459,29 @@ static int atmel_spi_probe(struct platform_device *pdev)
return PTR_ERR(clk);
/* setup spi core then atmel-specific driver state */
- master = spi_alloc_master(&pdev->dev, sizeof(*as));
- if (!master)
+ host = spi_alloc_host(&pdev->dev, sizeof(*as));
+ if (!host)
return -ENOMEM;
/* the spi->mode bits understood by this driver: */
- master->use_gpio_descriptors = true;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 16);
- master->dev.of_node = pdev->dev.of_node;
- master->bus_num = pdev->id;
- master->num_chipselect = 4;
- master->setup = atmel_spi_setup;
- master->flags = (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX |
+ host->use_gpio_descriptors = true;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+ host->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 16);
+ host->dev.of_node = pdev->dev.of_node;
+ host->bus_num = pdev->id;
+ host->num_chipselect = 4;
+ host->setup = atmel_spi_setup;
+ host->flags = (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX |
SPI_MASTER_GPIO_SS);
- master->transfer_one = atmel_spi_one_transfer;
- master->set_cs = atmel_spi_set_cs;
- master->cleanup = atmel_spi_cleanup;
- master->auto_runtime_pm = true;
- master->max_dma_len = SPI_MAX_DMA_XFER;
- master->can_dma = atmel_spi_can_dma;
- platform_set_drvdata(pdev, master);
+ host->transfer_one = atmel_spi_one_transfer;
+ host->set_cs = atmel_spi_set_cs;
+ host->cleanup = atmel_spi_cleanup;
+ host->auto_runtime_pm = true;
+ host->max_dma_len = SPI_MAX_DMA_XFER;
+ host->can_dma = atmel_spi_can_dma;
+ platform_set_drvdata(pdev, host);
- as = spi_master_get_devdata(master);
+ as = spi_controller_get_devdata(host);
spin_lock_init(&as->lock);
@@ -1502,7 +1502,7 @@ static int atmel_spi_probe(struct platform_device *pdev)
as->use_dma = false;
as->use_pdc = false;
if (as->caps.has_dma_support) {
- ret = atmel_spi_configure_dma(master, as);
+ ret = atmel_spi_configure_dma(host, as);
if (ret == 0) {
as->use_dma = true;
} else if (ret == -EPROBE_DEFER) {
@@ -1532,7 +1532,7 @@ static int atmel_spi_probe(struct platform_device *pdev)
}
}
if (!as->use_dma)
- dev_info(master->dev.parent,
+ dev_info(host->dev.parent,
" can not allocate dma coherent memory\n");
}
@@ -1541,10 +1541,10 @@ static int atmel_spi_probe(struct platform_device *pdev)
if (as->use_pdc) {
ret = devm_request_irq(&pdev->dev, irq, atmel_spi_pdc_interrupt,
- 0, dev_name(&pdev->dev), master);
+ 0, dev_name(&pdev->dev), host);
} else {
ret = devm_request_irq(&pdev->dev, irq, atmel_spi_pio_interrupt,
- 0, dev_name(&pdev->dev), master);
+ 0, dev_name(&pdev->dev), host);
}
if (ret)
goto out_unmap_regs;
@@ -1569,7 +1569,7 @@ static int atmel_spi_probe(struct platform_device *pdev)
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
- ret = devm_spi_register_master(&pdev->dev, master);
+ ret = devm_spi_register_controller(&pdev->dev, host);
if (ret)
goto out_free_dma;
@@ -1585,28 +1585,28 @@ out_free_dma:
pm_runtime_set_suspended(&pdev->dev);
if (as->use_dma)
- atmel_spi_release_dma(master);
+ atmel_spi_release_dma(host);
spi_writel(as, CR, SPI_BIT(SWRST));
spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
clk_disable_unprepare(clk);
out_free_irq:
out_unmap_regs:
- spi_master_put(master);
+ spi_controller_put(host);
return ret;
}
static int atmel_spi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct atmel_spi *as = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct atmel_spi *as = spi_controller_get_devdata(host);
pm_runtime_get_sync(&pdev->dev);
/* reset the hardware and block queue progress */
if (as->use_dma) {
- atmel_spi_stop_dma(master);
- atmel_spi_release_dma(master);
+ atmel_spi_stop_dma(host);
+ atmel_spi_release_dma(host);
if (IS_ENABLED(CONFIG_SOC_SAM_V4_V5)) {
dma_free_coherent(&pdev->dev, SPI_MAX_DMA_XFER,
as->addr_tx_bbuf,
@@ -1633,8 +1633,8 @@ static int atmel_spi_remove(struct platform_device *pdev)
static int atmel_spi_runtime_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct atmel_spi *as = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct atmel_spi *as = spi_controller_get_devdata(host);
clk_disable_unprepare(as->clk);
pinctrl_pm_select_sleep_state(dev);
@@ -1644,8 +1644,8 @@ static int atmel_spi_runtime_suspend(struct device *dev)
static int atmel_spi_runtime_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct atmel_spi *as = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct atmel_spi *as = spi_controller_get_devdata(host);
pinctrl_pm_select_default_state(dev);
@@ -1654,11 +1654,11 @@ static int atmel_spi_runtime_resume(struct device *dev)
static int atmel_spi_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
+ struct spi_controller *host = dev_get_drvdata(dev);
int ret;
/* Stop the queue running */
- ret = spi_master_suspend(master);
+ ret = spi_controller_suspend(host);
if (ret)
return ret;
@@ -1670,8 +1670,8 @@ static int atmel_spi_suspend(struct device *dev)
static int atmel_spi_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct atmel_spi *as = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct atmel_spi *as = spi_controller_get_devdata(host);
int ret;
ret = clk_prepare_enable(as->clk);
@@ -1689,7 +1689,7 @@ static int atmel_spi_resume(struct device *dev)
}
/* Start the queue running */
- return spi_master_resume(master);
+ return spi_controller_resume(host);
}
static const struct dev_pm_ops atmel_spi_pm_ops = {
diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c
index b871fd810d80..cd0a6478f5e7 100644
--- a/drivers/spi/spi-bcm63xx-hsspi.c
+++ b/drivers/spi/spi-bcm63xx-hsspi.c
@@ -20,6 +20,8 @@
#include <linux/spi/spi.h>
#include <linux/mutex.h>
#include <linux/of.h>
+#include <linux/spi/spi-mem.h>
+#include <linux/mtd/spi-nor.h>
#include <linux/reset.h>
#include <linux/pm_runtime.h>
@@ -57,6 +59,7 @@
#define PINGPONG_CMD_SS_SHIFT 12
#define HSSPI_PINGPONG_STATUS_REG(x) (0x84 + (x) * 0x40)
+#define HSSPI_PINGPONG_STATUS_SRC_BUSY BIT(1)
#define HSSPI_PROFILE_CLK_CTRL_REG(x) (0x100 + (x) * 0x20)
#define CLK_CTRL_FREQ_CTRL_MASK 0x0000ffff
@@ -92,15 +95,42 @@
#define HSSPI_MAX_PREPEND_LEN 15
-#define HSSPI_MAX_SYNC_CLOCK 30000000
+/*
+ * Some chip require 30MHz but other require 25MHz. Use smaller value to cover
+ * both cases.
+ */
+#define HSSPI_MAX_SYNC_CLOCK 25000000
#define HSSPI_SPI_MAX_CS 8
#define HSSPI_BUS_NUM 1 /* 0 is legacy SPI */
+#define HSSPI_POLL_STATUS_TIMEOUT_MS 100
+
+#define HSSPI_WAIT_MODE_POLLING 0
+#define HSSPI_WAIT_MODE_INTR 1
+#define HSSPI_WAIT_MODE_MAX HSSPI_WAIT_MODE_INTR
+
+/*
+ * Default transfer mode is auto. If the msg is prependable, use the prepend
+ * mode. If not, falls back to use the dummy cs workaround mode but limit the
+ * clock to 25MHz to make sure it works in all board design.
+ */
+#define HSSPI_XFER_MODE_AUTO 0
+#define HSSPI_XFER_MODE_PREPEND 1
+#define HSSPI_XFER_MODE_DUMMYCS 2
+#define HSSPI_XFER_MODE_MAX HSSPI_XFER_MODE_DUMMYCS
+
+#define bcm63xx_prepend_printk_on_checkfail(bs, fmt, ...) \
+do { \
+ if (bs->xfer_mode == HSSPI_XFER_MODE_AUTO) \
+ dev_dbg(&bs->pdev->dev, fmt, ##__VA_ARGS__); \
+ else if (bs->xfer_mode == HSSPI_XFER_MODE_PREPEND) \
+ dev_err(&bs->pdev->dev, fmt, ##__VA_ARGS__); \
+} while (0)
struct bcm63xx_hsspi {
struct completion done;
struct mutex bus_mutex;
-
+ struct mutex msg_mutex;
struct platform_device *pdev;
struct clk *clk;
struct clk *pll_clk;
@@ -109,8 +139,289 @@ struct bcm63xx_hsspi {
u32 speed_hz;
u8 cs_polarity;
+ u32 wait_mode;
+ u32 xfer_mode;
+ u32 prepend_cnt;
+ u8 *prepend_buf;
+};
+
+static ssize_t wait_mode_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct spi_controller *ctrl = dev_get_drvdata(dev);
+ struct bcm63xx_hsspi *bs = spi_master_get_devdata(ctrl);
+
+ return sprintf(buf, "%d\n", bs->wait_mode);
+}
+
+static ssize_t wait_mode_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct spi_controller *ctrl = dev_get_drvdata(dev);
+ struct bcm63xx_hsspi *bs = spi_master_get_devdata(ctrl);
+ u32 val;
+
+ if (kstrtou32(buf, 10, &val))
+ return -EINVAL;
+
+ if (val > HSSPI_WAIT_MODE_MAX) {
+ dev_warn(dev, "invalid wait mode %u\n", val);
+ return -EINVAL;
+ }
+
+ mutex_lock(&bs->msg_mutex);
+ bs->wait_mode = val;
+ /* clear interrupt status to avoid spurious int on next transfer */
+ if (val == HSSPI_WAIT_MODE_INTR)
+ __raw_writel(HSSPI_INT_CLEAR_ALL, bs->regs + HSSPI_INT_STATUS_REG);
+ mutex_unlock(&bs->msg_mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR_RW(wait_mode);
+
+static ssize_t xfer_mode_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct spi_controller *ctrl = dev_get_drvdata(dev);
+ struct bcm63xx_hsspi *bs = spi_master_get_devdata(ctrl);
+
+ return sprintf(buf, "%d\n", bs->xfer_mode);
+}
+
+static ssize_t xfer_mode_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct spi_controller *ctrl = dev_get_drvdata(dev);
+ struct bcm63xx_hsspi *bs = spi_master_get_devdata(ctrl);
+ u32 val;
+
+ if (kstrtou32(buf, 10, &val))
+ return -EINVAL;
+
+ if (val > HSSPI_XFER_MODE_MAX) {
+ dev_warn(dev, "invalid xfer mode %u\n", val);
+ return -EINVAL;
+ }
+
+ mutex_lock(&bs->msg_mutex);
+ bs->xfer_mode = val;
+ mutex_unlock(&bs->msg_mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR_RW(xfer_mode);
+
+static struct attribute *bcm63xx_hsspi_attrs[] = {
+ &dev_attr_wait_mode.attr,
+ &dev_attr_xfer_mode.attr,
+ NULL,
+};
+
+static const struct attribute_group bcm63xx_hsspi_group = {
+ .attrs = bcm63xx_hsspi_attrs,
};
+static void bcm63xx_hsspi_set_clk(struct bcm63xx_hsspi *bs,
+ struct spi_device *spi, int hz);
+
+static size_t bcm63xx_hsspi_max_message_size(struct spi_device *spi)
+{
+ return HSSPI_BUFFER_LEN - HSSPI_OPCODE_LEN;
+}
+
+static int bcm63xx_hsspi_wait_cmd(struct bcm63xx_hsspi *bs)
+{
+ unsigned long limit;
+ u32 reg = 0;
+ int rc = 0;
+
+ if (bs->wait_mode == HSSPI_WAIT_MODE_INTR) {
+ if (wait_for_completion_timeout(&bs->done, HZ) == 0)
+ rc = 1;
+ } else {
+ /* polling mode checks for status busy bit */
+ limit = jiffies + msecs_to_jiffies(HSSPI_POLL_STATUS_TIMEOUT_MS);
+
+ while (!time_after(jiffies, limit)) {
+ reg = __raw_readl(bs->regs + HSSPI_PINGPONG_STATUS_REG(0));
+ if (reg & HSSPI_PINGPONG_STATUS_SRC_BUSY)
+ cpu_relax();
+ else
+ break;
+ }
+ if (reg & HSSPI_PINGPONG_STATUS_SRC_BUSY)
+ rc = 1;
+ }
+
+ if (rc)
+ dev_err(&bs->pdev->dev, "transfer timed out!\n");
+
+ return rc;
+}
+
+static bool bcm63xx_prepare_prepend_transfer(struct spi_master *master,
+ struct spi_message *msg,
+ struct spi_transfer *t_prepend)
+{
+
+ struct bcm63xx_hsspi *bs = spi_master_get_devdata(master);
+ bool tx_only = false;
+ struct spi_transfer *t;
+
+ /*
+ * Multiple transfers within a message may be combined into one transfer
+ * to the controller using its prepend feature. A SPI message is prependable
+ * only if the following are all true:
+ * 1. One or more half duplex write transfer in single bit mode
+ * 2. Optional full duplex read/write at the end
+ * 3. No delay and cs_change between transfers
+ */
+ bs->prepend_cnt = 0;
+ list_for_each_entry(t, &msg->transfers, transfer_list) {
+ if ((spi_delay_to_ns(&t->delay, t) > 0) || t->cs_change) {
+ bcm63xx_prepend_printk_on_checkfail(bs,
+ "Delay or cs change not supported in prepend mode!\n");
+ return false;
+ }
+
+ tx_only = false;
+ if (t->tx_buf && !t->rx_buf) {
+ tx_only = true;
+ if (bs->prepend_cnt + t->len >
+ (HSSPI_BUFFER_LEN - HSSPI_OPCODE_LEN)) {
+ bcm63xx_prepend_printk_on_checkfail(bs,
+ "exceed max buf len, abort prepending transfers!\n");
+ return false;
+ }
+
+ if (t->tx_nbits > SPI_NBITS_SINGLE &&
+ !list_is_last(&t->transfer_list, &msg->transfers)) {
+ bcm63xx_prepend_printk_on_checkfail(bs,
+ "multi-bit prepend buf not supported!\n");
+ return false;
+ }
+
+ if (t->tx_nbits == SPI_NBITS_SINGLE) {
+ memcpy(bs->prepend_buf + bs->prepend_cnt, t->tx_buf, t->len);
+ bs->prepend_cnt += t->len;
+ }
+ } else {
+ if (!list_is_last(&t->transfer_list, &msg->transfers)) {
+ bcm63xx_prepend_printk_on_checkfail(bs,
+ "rx/tx_rx transfer not supported when it is not last one!\n");
+ return false;
+ }
+ }
+
+ if (list_is_last(&t->transfer_list, &msg->transfers)) {
+ memcpy(t_prepend, t, sizeof(struct spi_transfer));
+
+ if (tx_only && t->tx_nbits == SPI_NBITS_SINGLE) {
+ /*
+ * if the last one is also a single bit tx only transfer, merge
+ * all of them into one single tx transfer
+ */
+ t_prepend->len = bs->prepend_cnt;
+ t_prepend->tx_buf = bs->prepend_buf;
+ bs->prepend_cnt = 0;
+ } else {
+ /*
+ * if the last one is not a tx only transfer or dual tx xfer, all
+ * the previous transfers are sent through prepend bytes and
+ * make sure it does not exceed the max prepend len
+ */
+ if (bs->prepend_cnt > HSSPI_MAX_PREPEND_LEN) {
+ bcm63xx_prepend_printk_on_checkfail(bs,
+ "exceed max prepend len, abort prepending transfers!\n");
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+static int bcm63xx_hsspi_do_prepend_txrx(struct spi_device *spi,
+ struct spi_transfer *t)
+{
+ struct bcm63xx_hsspi *bs = spi_master_get_devdata(spi->master);
+ unsigned int chip_select = spi->chip_select;
+ u16 opcode = 0, val;
+ const u8 *tx = t->tx_buf;
+ u8 *rx = t->rx_buf;
+ u32 reg = 0;
+
+ /*
+ * shouldn't happen as we set the max_message_size in the probe.
+ * but check it again in case some driver does not honor the max size
+ */
+ if (t->len + bs->prepend_cnt > (HSSPI_BUFFER_LEN - HSSPI_OPCODE_LEN)) {
+ dev_warn(&bs->pdev->dev,
+ "Prepend message large than fifo size len %d prepend %d\n",
+ t->len, bs->prepend_cnt);
+ return -EINVAL;
+ }
+
+ bcm63xx_hsspi_set_clk(bs, spi, t->speed_hz);
+
+ if (tx && rx)
+ opcode = HSSPI_OP_READ_WRITE;
+ else if (tx)
+ opcode = HSSPI_OP_WRITE;
+ else if (rx)
+ opcode = HSSPI_OP_READ;
+
+ if ((opcode == HSSPI_OP_READ && t->rx_nbits == SPI_NBITS_DUAL) ||
+ (opcode == HSSPI_OP_WRITE && t->tx_nbits == SPI_NBITS_DUAL)) {
+ opcode |= HSSPI_OP_MULTIBIT;
+
+ if (t->rx_nbits == SPI_NBITS_DUAL) {
+ reg |= 1 << MODE_CTRL_MULTIDATA_RD_SIZE_SHIFT;
+ reg |= bs->prepend_cnt << MODE_CTRL_MULTIDATA_RD_STRT_SHIFT;
+ }
+ if (t->tx_nbits == SPI_NBITS_DUAL) {
+ reg |= 1 << MODE_CTRL_MULTIDATA_WR_SIZE_SHIFT;
+ reg |= bs->prepend_cnt << MODE_CTRL_MULTIDATA_WR_STRT_SHIFT;
+ }
+ }
+
+ reg |= bs->prepend_cnt << MODE_CTRL_PREPENDBYTE_CNT_SHIFT;
+ __raw_writel(reg | 0xff,
+ bs->regs + HSSPI_PROFILE_MODE_CTRL_REG(chip_select));
+
+ reinit_completion(&bs->done);
+ if (bs->prepend_cnt)
+ memcpy_toio(bs->fifo + HSSPI_OPCODE_LEN, bs->prepend_buf,
+ bs->prepend_cnt);
+ if (tx)
+ memcpy_toio(bs->fifo + HSSPI_OPCODE_LEN + bs->prepend_cnt, tx,
+ t->len);
+
+ *(__be16 *)(&val) = cpu_to_be16(opcode | t->len);
+ __raw_writew(val, bs->fifo);
+ /* enable interrupt */
+ if (bs->wait_mode == HSSPI_WAIT_MODE_INTR)
+ __raw_writel(HSSPI_PINGx_CMD_DONE(0), bs->regs + HSSPI_INT_MASK_REG);
+
+ /* start the transfer */
+ reg = chip_select << PINGPONG_CMD_SS_SHIFT |
+ chip_select << PINGPONG_CMD_PROFILE_SHIFT |
+ PINGPONG_COMMAND_START_NOW;
+ __raw_writel(reg, bs->regs + HSSPI_PINGPONG_COMMAND_REG(0));
+
+ if (bcm63xx_hsspi_wait_cmd(bs))
+ return -ETIMEDOUT;
+
+ if (rx)
+ memcpy_fromio(rx, bs->fifo, t->len);
+
+ return 0;
+}
+
static void bcm63xx_hsspi_set_cs(struct bcm63xx_hsspi *bs, unsigned int cs,
bool active)
{
@@ -158,14 +469,16 @@ static int bcm63xx_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t)
{
struct bcm63xx_hsspi *bs = spi_master_get_devdata(spi->master);
unsigned int chip_select = spi->chip_select;
- u16 opcode = 0;
+ u16 opcode = 0, val;
int pending = t->len;
int step_size = HSSPI_BUFFER_LEN;
const u8 *tx = t->tx_buf;
u8 *rx = t->rx_buf;
+ u32 reg = 0;
bcm63xx_hsspi_set_clk(bs, spi, t->speed_hz);
- bcm63xx_hsspi_set_cs(bs, spi->chip_select, true);
+ if (!t->cs_off)
+ bcm63xx_hsspi_set_cs(bs, spi->chip_select, true);
if (tx && rx)
opcode = HSSPI_OP_READ_WRITE;
@@ -178,11 +491,16 @@ static int bcm63xx_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t)
step_size -= HSSPI_OPCODE_LEN;
if ((opcode == HSSPI_OP_READ && t->rx_nbits == SPI_NBITS_DUAL) ||
- (opcode == HSSPI_OP_WRITE && t->tx_nbits == SPI_NBITS_DUAL))
+ (opcode == HSSPI_OP_WRITE && t->tx_nbits == SPI_NBITS_DUAL)) {
opcode |= HSSPI_OP_MULTIBIT;
- __raw_writel(1 << MODE_CTRL_MULTIDATA_WR_SIZE_SHIFT |
- 1 << MODE_CTRL_MULTIDATA_RD_SIZE_SHIFT | 0xff,
+ if (t->rx_nbits == SPI_NBITS_DUAL)
+ reg |= 1 << MODE_CTRL_MULTIDATA_RD_SIZE_SHIFT;
+ if (t->tx_nbits == SPI_NBITS_DUAL)
+ reg |= 1 << MODE_CTRL_MULTIDATA_WR_SIZE_SHIFT;
+ }
+
+ __raw_writel(reg | 0xff,
bs->regs + HSSPI_PROFILE_MODE_CTRL_REG(chip_select));
while (pending > 0) {
@@ -194,22 +512,21 @@ static int bcm63xx_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t)
tx += curr_step;
}
- __raw_writew(opcode | curr_step, bs->fifo);
+ *(__be16 *)(&val) = cpu_to_be16(opcode | curr_step);
+ __raw_writew(val, bs->fifo);
/* enable interrupt */
- __raw_writel(HSSPI_PINGx_CMD_DONE(0),
- bs->regs + HSSPI_INT_MASK_REG);
+ if (bs->wait_mode == HSSPI_WAIT_MODE_INTR)
+ __raw_writel(HSSPI_PINGx_CMD_DONE(0),
+ bs->regs + HSSPI_INT_MASK_REG);
- /* start the transfer */
- __raw_writel(!chip_select << PINGPONG_CMD_SS_SHIFT |
- chip_select << PINGPONG_CMD_PROFILE_SHIFT |
- PINGPONG_COMMAND_START_NOW,
- bs->regs + HSSPI_PINGPONG_COMMAND_REG(0));
+ reg = !chip_select << PINGPONG_CMD_SS_SHIFT |
+ chip_select << PINGPONG_CMD_PROFILE_SHIFT |
+ PINGPONG_COMMAND_START_NOW;
+ __raw_writel(reg, bs->regs + HSSPI_PINGPONG_COMMAND_REG(0));
- if (wait_for_completion_timeout(&bs->done, HZ) == 0) {
- dev_err(&bs->pdev->dev, "transfer timed out!\n");
+ if (bcm63xx_hsspi_wait_cmd(bs))
return -ETIMEDOUT;
- }
if (rx) {
memcpy_fromio(rx, bs->fifo, curr_step);
@@ -259,17 +576,17 @@ static int bcm63xx_hsspi_setup(struct spi_device *spi)
return 0;
}
-static int bcm63xx_hsspi_transfer_one(struct spi_master *master,
+static int bcm63xx_hsspi_do_dummy_cs_txrx(struct spi_device *spi,
struct spi_message *msg)
{
- struct bcm63xx_hsspi *bs = spi_master_get_devdata(master);
- struct spi_transfer *t;
- struct spi_device *spi = msg->spi;
+ struct bcm63xx_hsspi *bs = spi_master_get_devdata(spi->master);
int status = -EINVAL;
int dummy_cs;
- u32 reg;
+ bool keep_cs = false;
+ struct spi_transfer *t;
- /* This controller does not support keeping CS active during idle.
+ /*
+ * This controller does not support keeping CS active during idle.
* To work around this, we use the following ugly hack:
*
* a. Invert the target chip select's polarity so it will be active.
@@ -287,6 +604,21 @@ static int bcm63xx_hsspi_transfer_one(struct spi_master *master,
bcm63xx_hsspi_set_cs(bs, dummy_cs, true);
list_for_each_entry(t, &msg->transfers, transfer_list) {
+ /*
+ * We are here because one of reasons below:
+ * a. Message is not prependable and in default auto xfer mode. This mean
+ * we fallback to dummy cs mode at maximum 25MHz safe clock rate.
+ * b. User set to use the dummy cs mode.
+ */
+ if (bs->xfer_mode == HSSPI_XFER_MODE_AUTO) {
+ if (t->speed_hz > HSSPI_MAX_SYNC_CLOCK) {
+ t->speed_hz = HSSPI_MAX_SYNC_CLOCK;
+ dev_warn_once(&bs->pdev->dev,
+ "Force to dummy cs mode. Reduce the speed to %dHz",
+ t->speed_hz);
+ }
+ }
+
status = bcm63xx_hsspi_do_txrx(spi, t);
if (status)
break;
@@ -295,23 +627,85 @@ static int bcm63xx_hsspi_transfer_one(struct spi_master *master,
spi_transfer_delay_exec(t);
- if (t->cs_change)
- bcm63xx_hsspi_set_cs(bs, spi->chip_select, false);
+ /* use existing cs change logic from spi_transfer_one_message */
+ if (t->cs_change) {
+ if (list_is_last(&t->transfer_list, &msg->transfers)) {
+ keep_cs = true;
+ } else {
+ if (!t->cs_off)
+ bcm63xx_hsspi_set_cs(bs, spi->chip_select, false);
+
+ spi_transfer_cs_change_delay_exec(msg, t);
+
+ if (!list_next_entry(t, transfer_list)->cs_off)
+ bcm63xx_hsspi_set_cs(bs, spi->chip_select, true);
+ }
+ } else if (!list_is_last(&t->transfer_list, &msg->transfers) &&
+ t->cs_off != list_next_entry(t, transfer_list)->cs_off) {
+ bcm63xx_hsspi_set_cs(bs, spi->chip_select, t->cs_off);
+ }
}
- mutex_lock(&bs->bus_mutex);
- reg = __raw_readl(bs->regs + HSSPI_GLOBAL_CTRL_REG);
- reg &= ~GLOBAL_CTRL_CS_POLARITY_MASK;
- reg |= bs->cs_polarity;
- __raw_writel(reg, bs->regs + HSSPI_GLOBAL_CTRL_REG);
- mutex_unlock(&bs->bus_mutex);
+ bcm63xx_hsspi_set_cs(bs, dummy_cs, false);
+ if (status || !keep_cs)
+ bcm63xx_hsspi_set_cs(bs, spi->chip_select, false);
+
+ return status;
+}
+static int bcm63xx_hsspi_transfer_one(struct spi_master *master,
+ struct spi_message *msg)
+{
+ struct bcm63xx_hsspi *bs = spi_master_get_devdata(master);
+ struct spi_device *spi = msg->spi;
+ int status = -EINVAL;
+ bool prependable = false;
+ struct spi_transfer t_prepend;
+
+ mutex_lock(&bs->msg_mutex);
+
+ if (bs->xfer_mode != HSSPI_XFER_MODE_DUMMYCS)
+ prependable = bcm63xx_prepare_prepend_transfer(master, msg, &t_prepend);
+
+ if (prependable) {
+ status = bcm63xx_hsspi_do_prepend_txrx(spi, &t_prepend);
+ msg->actual_length = (t_prepend.len + bs->prepend_cnt);
+ } else {
+ if (bs->xfer_mode == HSSPI_XFER_MODE_PREPEND) {
+ dev_err(&bs->pdev->dev,
+ "User sets prepend mode but msg not prependable! Abort transfer\n");
+ status = -EINVAL;
+ } else
+ status = bcm63xx_hsspi_do_dummy_cs_txrx(spi, msg);
+ }
+
+ mutex_unlock(&bs->msg_mutex);
msg->status = status;
spi_finalize_current_message(master);
return 0;
}
+static bool bcm63xx_hsspi_mem_supports_op(struct spi_mem *mem,
+ const struct spi_mem_op *op)
+{
+ if (!spi_mem_default_supports_op(mem, op))
+ return false;
+
+ /* Controller doesn't support spi mem dual io mode */
+ if ((op->cmd.opcode == SPINOR_OP_READ_1_2_2) ||
+ (op->cmd.opcode == SPINOR_OP_READ_1_2_2_4B) ||
+ (op->cmd.opcode == SPINOR_OP_READ_1_2_2_DTR) ||
+ (op->cmd.opcode == SPINOR_OP_READ_1_2_2_DTR_4B))
+ return false;
+
+ return true;
+}
+
+static const struct spi_controller_mem_ops bcm63xx_hsspi_mem_ops = {
+ .supports_op = bcm63xx_hsspi_mem_supports_op,
+};
+
static irqreturn_t bcm63xx_hsspi_interrupt(int irq, void *dev_id)
{
struct bcm63xx_hsspi *bs = (struct bcm63xx_hsspi *)dev_id;
@@ -398,10 +792,18 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
bs->regs = regs;
bs->speed_hz = rate;
bs->fifo = (u8 __iomem *)(bs->regs + HSSPI_FIFO_REG(0));
+ bs->wait_mode = HSSPI_WAIT_MODE_POLLING;
+ bs->prepend_buf = devm_kzalloc(dev, HSSPI_BUFFER_LEN, GFP_KERNEL);
+ if (!bs->prepend_buf) {
+ ret = -ENOMEM;
+ goto out_put_master;
+ }
mutex_init(&bs->bus_mutex);
+ mutex_init(&bs->msg_mutex);
init_completion(&bs->done);
+ master->mem_ops = &bcm63xx_hsspi_mem_ops;
master->dev.of_node = dev->of_node;
if (!dev->of_node)
master->bus_num = HSSPI_BUS_NUM;
@@ -415,6 +817,9 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
master->num_chipselect = num_cs;
master->setup = bcm63xx_hsspi_setup;
master->transfer_one_message = bcm63xx_hsspi_transfer_one;
+ master->max_transfer_size = bcm63xx_hsspi_max_message_size;
+ master->max_message_size = bcm63xx_hsspi_max_message_size;
+
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH |
SPI_RX_DUAL | SPI_TX_DUAL;
master->bits_per_word_mask = SPI_BPW_MASK(8);
@@ -434,21 +839,33 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
__raw_writel(reg | GLOBAL_CTRL_CLK_GATE_SSOFF,
bs->regs + HSSPI_GLOBAL_CTRL_REG);
- ret = devm_request_irq(dev, irq, bcm63xx_hsspi_interrupt, IRQF_SHARED,
- pdev->name, bs);
+ if (irq > 0) {
+ ret = devm_request_irq(dev, irq, bcm63xx_hsspi_interrupt, IRQF_SHARED,
+ pdev->name, bs);
- if (ret)
- goto out_put_master;
+ if (ret)
+ goto out_put_master;
+ }
pm_runtime_enable(&pdev->dev);
+ ret = sysfs_create_group(&pdev->dev.kobj, &bcm63xx_hsspi_group);
+ if (ret) {
+ dev_err(&pdev->dev, "couldn't register sysfs group\n");
+ goto out_pm_disable;
+ }
+
/* register and we are done */
ret = devm_spi_register_master(dev, master);
if (ret)
- goto out_pm_disable;
+ goto out_sysgroup_disable;
+
+ dev_info(dev, "Broadcom 63XX High Speed SPI Controller driver");
return 0;
+out_sysgroup_disable:
+ sysfs_remove_group(&pdev->dev.kobj, &bcm63xx_hsspi_group);
out_pm_disable:
pm_runtime_disable(&pdev->dev);
out_put_master:
@@ -470,6 +887,7 @@ static int bcm63xx_hsspi_remove(struct platform_device *pdev)
__raw_writel(0, bs->regs + HSSPI_INT_MASK_REG);
clk_disable_unprepare(bs->pll_clk);
clk_disable_unprepare(bs->clk);
+ sysfs_remove_group(&pdev->dev.kobj, &bcm63xx_hsspi_group);
return 0;
}
@@ -516,6 +934,7 @@ static SIMPLE_DEV_PM_OPS(bcm63xx_hsspi_pm_ops, bcm63xx_hsspi_suspend,
static const struct of_device_id bcm63xx_hsspi_of_match[] = {
{ .compatible = "brcm,bcm6328-hsspi", },
+ { .compatible = "brcm,bcmbca-hsspi-v1.0", },
{ },
};
MODULE_DEVICE_TABLE(of, bcm63xx_hsspi_of_match);
diff --git a/drivers/spi/spi-bcmbca-hsspi.c b/drivers/spi/spi-bcmbca-hsspi.c
new file mode 100644
index 000000000000..3f9e6131ad86
--- /dev/null
+++ b/drivers/spi/spi-bcmbca-hsspi.c
@@ -0,0 +1,654 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Broadcom BCMBCA High Speed SPI Controller driver
+ *
+ * Copyright 2000-2010 Broadcom Corporation
+ * Copyright 2012-2013 Jonas Gorski <jogo@openwrt.org>
+ * Copyright 2019-2022 Broadcom Ltd
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/spi/spi.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/spi/spi-mem.h>
+#include <linux/pm_runtime.h>
+
+#define HSSPI_GLOBAL_CTRL_REG 0x0
+#define GLOBAL_CTRL_CS_POLARITY_SHIFT 0
+#define GLOBAL_CTRL_CS_POLARITY_MASK 0x000000ff
+#define GLOBAL_CTRL_PLL_CLK_CTRL_SHIFT 8
+#define GLOBAL_CTRL_PLL_CLK_CTRL_MASK 0x0000ff00
+#define GLOBAL_CTRL_CLK_GATE_SSOFF BIT(16)
+#define GLOBAL_CTRL_CLK_POLARITY BIT(17)
+#define GLOBAL_CTRL_MOSI_IDLE BIT(18)
+
+#define HSSPI_GLOBAL_EXT_TRIGGER_REG 0x4
+
+#define HSSPI_INT_STATUS_REG 0x8
+#define HSSPI_INT_STATUS_MASKED_REG 0xc
+#define HSSPI_INT_MASK_REG 0x10
+
+#define HSSPI_PINGx_CMD_DONE(i) BIT((i * 8) + 0)
+#define HSSPI_PINGx_RX_OVER(i) BIT((i * 8) + 1)
+#define HSSPI_PINGx_TX_UNDER(i) BIT((i * 8) + 2)
+#define HSSPI_PINGx_POLL_TIMEOUT(i) BIT((i * 8) + 3)
+#define HSSPI_PINGx_CTRL_INVAL(i) BIT((i * 8) + 4)
+
+#define HSSPI_INT_CLEAR_ALL 0xff001f1f
+
+#define HSSPI_PINGPONG_COMMAND_REG(x) (0x80 + (x) * 0x40)
+#define PINGPONG_CMD_COMMAND_MASK 0xf
+#define PINGPONG_COMMAND_NOOP 0
+#define PINGPONG_COMMAND_START_NOW 1
+#define PINGPONG_COMMAND_START_TRIGGER 2
+#define PINGPONG_COMMAND_HALT 3
+#define PINGPONG_COMMAND_FLUSH 4
+#define PINGPONG_CMD_PROFILE_SHIFT 8
+#define PINGPONG_CMD_SS_SHIFT 12
+
+#define HSSPI_PINGPONG_STATUS_REG(x) (0x84 + (x) * 0x40)
+#define HSSPI_PINGPONG_STATUS_SRC_BUSY BIT(1)
+
+#define HSSPI_PROFILE_CLK_CTRL_REG(x) (0x100 + (x) * 0x20)
+#define CLK_CTRL_FREQ_CTRL_MASK 0x0000ffff
+#define CLK_CTRL_SPI_CLK_2X_SEL BIT(14)
+#define CLK_CTRL_ACCUM_RST_ON_LOOP BIT(15)
+#define CLK_CTRL_CLK_POLARITY BIT(16)
+
+#define HSSPI_PROFILE_SIGNAL_CTRL_REG(x) (0x104 + (x) * 0x20)
+#define SIGNAL_CTRL_LATCH_RISING BIT(12)
+#define SIGNAL_CTRL_LAUNCH_RISING BIT(13)
+#define SIGNAL_CTRL_ASYNC_INPUT_PATH BIT(16)
+
+#define HSSPI_PROFILE_MODE_CTRL_REG(x) (0x108 + (x) * 0x20)
+#define MODE_CTRL_MULTIDATA_RD_STRT_SHIFT 8
+#define MODE_CTRL_MULTIDATA_WR_STRT_SHIFT 12
+#define MODE_CTRL_MULTIDATA_RD_SIZE_SHIFT 16
+#define MODE_CTRL_MULTIDATA_WR_SIZE_SHIFT 18
+#define MODE_CTRL_MODE_3WIRE BIT(20)
+#define MODE_CTRL_PREPENDBYTE_CNT_SHIFT 24
+
+#define HSSPI_FIFO_REG(x) (0x200 + (x) * 0x200)
+
+#define HSSPI_OP_MULTIBIT BIT(11)
+#define HSSPI_OP_CODE_SHIFT 13
+#define HSSPI_OP_SLEEP (0 << HSSPI_OP_CODE_SHIFT)
+#define HSSPI_OP_READ_WRITE (1 << HSSPI_OP_CODE_SHIFT)
+#define HSSPI_OP_WRITE (2 << HSSPI_OP_CODE_SHIFT)
+#define HSSPI_OP_READ (3 << HSSPI_OP_CODE_SHIFT)
+#define HSSPI_OP_SETIRQ (4 << HSSPI_OP_CODE_SHIFT)
+
+#define HSSPI_BUFFER_LEN 512
+#define HSSPI_OPCODE_LEN 2
+
+#define HSSPI_MAX_PREPEND_LEN 15
+
+#define HSSPI_MAX_SYNC_CLOCK 30000000
+
+#define HSSPI_SPI_MAX_CS 8
+#define HSSPI_BUS_NUM 1 /* 0 is legacy SPI */
+#define HSSPI_POLL_STATUS_TIMEOUT_MS 100
+
+#define HSSPI_WAIT_MODE_POLLING 0
+#define HSSPI_WAIT_MODE_INTR 1
+#define HSSPI_WAIT_MODE_MAX HSSPI_WAIT_MODE_INTR
+
+#define SPIM_CTRL_CS_OVERRIDE_SEL_SHIFT 0
+#define SPIM_CTRL_CS_OVERRIDE_SEL_MASK 0xff
+#define SPIM_CTRL_CS_OVERRIDE_VAL_SHIFT 8
+#define SPIM_CTRL_CS_OVERRIDE_VAL_MASK 0xff
+
+struct bcmbca_hsspi {
+ struct completion done;
+ struct mutex bus_mutex;
+ struct mutex msg_mutex;
+ struct platform_device *pdev;
+ struct clk *clk;
+ struct clk *pll_clk;
+ void __iomem *regs;
+ void __iomem *spim_ctrl;
+ u8 __iomem *fifo;
+ u32 speed_hz;
+ u8 cs_polarity;
+ u32 wait_mode;
+};
+
+static ssize_t wait_mode_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct spi_controller *ctrl = dev_get_drvdata(dev);
+ struct bcmbca_hsspi *bs = spi_master_get_devdata(ctrl);
+
+ return sprintf(buf, "%d\n", bs->wait_mode);
+}
+
+static ssize_t wait_mode_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct spi_controller *ctrl = dev_get_drvdata(dev);
+ struct bcmbca_hsspi *bs = spi_master_get_devdata(ctrl);
+ u32 val;
+
+ if (kstrtou32(buf, 10, &val))
+ return -EINVAL;
+
+ if (val > HSSPI_WAIT_MODE_MAX) {
+ dev_warn(dev, "invalid wait mode %u\n", val);
+ return -EINVAL;
+ }
+
+ mutex_lock(&bs->msg_mutex);
+ bs->wait_mode = val;
+ /* clear interrupt status to avoid spurious int on next transfer */
+ if (val == HSSPI_WAIT_MODE_INTR)
+ __raw_writel(HSSPI_INT_CLEAR_ALL, bs->regs + HSSPI_INT_STATUS_REG);
+ mutex_unlock(&bs->msg_mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR_RW(wait_mode);
+
+static struct attribute *bcmbca_hsspi_attrs[] = {
+ &dev_attr_wait_mode.attr,
+ NULL,
+};
+
+static const struct attribute_group bcmbca_hsspi_group = {
+ .attrs = bcmbca_hsspi_attrs,
+};
+
+static void bcmbca_hsspi_set_cs(struct bcmbca_hsspi *bs, unsigned int cs,
+ bool active)
+{
+ u32 reg;
+
+ /* No cs orerriden needed for SS7 internal cs on pcm based voice dev */
+ if (cs == 7)
+ return;
+
+ mutex_lock(&bs->bus_mutex);
+
+ reg = __raw_readl(bs->spim_ctrl);
+ if (active)
+ reg |= BIT(cs + SPIM_CTRL_CS_OVERRIDE_SEL_SHIFT);
+ else
+ reg &= ~BIT(cs + SPIM_CTRL_CS_OVERRIDE_SEL_SHIFT);
+
+ __raw_writel(reg, bs->spim_ctrl);
+
+ mutex_unlock(&bs->bus_mutex);
+}
+
+static void bcmbca_hsspi_set_clk(struct bcmbca_hsspi *bs,
+ struct spi_device *spi, int hz)
+{
+ unsigned int profile = spi->chip_select;
+ u32 reg;
+
+ reg = DIV_ROUND_UP(2048, DIV_ROUND_UP(bs->speed_hz, hz));
+ __raw_writel(CLK_CTRL_ACCUM_RST_ON_LOOP | reg,
+ bs->regs + HSSPI_PROFILE_CLK_CTRL_REG(profile));
+
+ reg = __raw_readl(bs->regs + HSSPI_PROFILE_SIGNAL_CTRL_REG(profile));
+ if (hz > HSSPI_MAX_SYNC_CLOCK)
+ reg |= SIGNAL_CTRL_ASYNC_INPUT_PATH;
+ else
+ reg &= ~SIGNAL_CTRL_ASYNC_INPUT_PATH;
+ __raw_writel(reg, bs->regs + HSSPI_PROFILE_SIGNAL_CTRL_REG(profile));
+
+ mutex_lock(&bs->bus_mutex);
+ /* setup clock polarity */
+ reg = __raw_readl(bs->regs + HSSPI_GLOBAL_CTRL_REG);
+ reg &= ~GLOBAL_CTRL_CLK_POLARITY;
+ if (spi->mode & SPI_CPOL)
+ reg |= GLOBAL_CTRL_CLK_POLARITY;
+ __raw_writel(reg, bs->regs + HSSPI_GLOBAL_CTRL_REG);
+
+ mutex_unlock(&bs->bus_mutex);
+}
+
+static int bcmbca_hsspi_wait_cmd(struct bcmbca_hsspi *bs, unsigned int cs)
+{
+ unsigned long limit;
+ u32 reg = 0;
+ int rc = 0;
+
+ if (bs->wait_mode == HSSPI_WAIT_MODE_INTR) {
+ if (wait_for_completion_timeout(&bs->done, HZ) == 0)
+ rc = 1;
+ } else {
+ limit = jiffies + msecs_to_jiffies(HSSPI_POLL_STATUS_TIMEOUT_MS);
+
+ while (!time_after(jiffies, limit)) {
+ reg = __raw_readl(bs->regs + HSSPI_PINGPONG_STATUS_REG(0));
+ if (reg & HSSPI_PINGPONG_STATUS_SRC_BUSY)
+ cpu_relax();
+ else
+ break;
+ }
+ if (reg & HSSPI_PINGPONG_STATUS_SRC_BUSY)
+ rc = 1;
+ }
+
+ if (rc)
+ dev_err(&bs->pdev->dev, "transfer timed out!\n");
+
+ return rc;
+}
+
+static int bcmbca_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t,
+ struct spi_message *msg)
+{
+ struct bcmbca_hsspi *bs = spi_master_get_devdata(spi->master);
+ unsigned int chip_select = spi->chip_select;
+ u16 opcode = 0, val;
+ int pending = t->len;
+ int step_size = HSSPI_BUFFER_LEN;
+ const u8 *tx = t->tx_buf;
+ u8 *rx = t->rx_buf;
+ u32 reg = 0, cs_act = 0;
+
+ bcmbca_hsspi_set_clk(bs, spi, t->speed_hz);
+
+ if (tx && rx)
+ opcode = HSSPI_OP_READ_WRITE;
+ else if (tx)
+ opcode = HSSPI_OP_WRITE;
+ else if (rx)
+ opcode = HSSPI_OP_READ;
+
+ if (opcode != HSSPI_OP_READ)
+ step_size -= HSSPI_OPCODE_LEN;
+
+ if ((opcode == HSSPI_OP_READ && t->rx_nbits == SPI_NBITS_DUAL) ||
+ (opcode == HSSPI_OP_WRITE && t->tx_nbits == SPI_NBITS_DUAL)) {
+ opcode |= HSSPI_OP_MULTIBIT;
+
+ if (t->rx_nbits == SPI_NBITS_DUAL)
+ reg |= 1 << MODE_CTRL_MULTIDATA_RD_SIZE_SHIFT;
+ if (t->tx_nbits == SPI_NBITS_DUAL)
+ reg |= 1 << MODE_CTRL_MULTIDATA_WR_SIZE_SHIFT;
+ }
+
+ __raw_writel(reg | 0xff,
+ bs->regs + HSSPI_PROFILE_MODE_CTRL_REG(chip_select));
+
+ while (pending > 0) {
+ int curr_step = min_t(int, step_size, pending);
+
+ reinit_completion(&bs->done);
+ if (tx) {
+ memcpy_toio(bs->fifo + HSSPI_OPCODE_LEN, tx, curr_step);
+ tx += curr_step;
+ }
+
+ *(__be16 *)(&val) = cpu_to_be16(opcode | curr_step);
+ __raw_writew(val, bs->fifo);
+
+ /* enable interrupt */
+ if (bs->wait_mode == HSSPI_WAIT_MODE_INTR)
+ __raw_writel(HSSPI_PINGx_CMD_DONE(0),
+ bs->regs + HSSPI_INT_MASK_REG);
+
+ if (!cs_act) {
+ /* must apply cs signal as close as the cmd starts */
+ bcmbca_hsspi_set_cs(bs, chip_select, true);
+ cs_act = 1;
+ }
+
+ reg = chip_select << PINGPONG_CMD_SS_SHIFT |
+ chip_select << PINGPONG_CMD_PROFILE_SHIFT |
+ PINGPONG_COMMAND_START_NOW;
+ __raw_writel(reg, bs->regs + HSSPI_PINGPONG_COMMAND_REG(0));
+
+ if (bcmbca_hsspi_wait_cmd(bs, spi->chip_select))
+ return -ETIMEDOUT;
+
+ pending -= curr_step;
+
+ if (rx) {
+ memcpy_fromio(rx, bs->fifo, curr_step);
+ rx += curr_step;
+ }
+ }
+
+ return 0;
+}
+
+static int bcmbca_hsspi_setup(struct spi_device *spi)
+{
+ struct bcmbca_hsspi *bs = spi_master_get_devdata(spi->master);
+ u32 reg;
+
+ reg = __raw_readl(bs->regs +
+ HSSPI_PROFILE_SIGNAL_CTRL_REG(spi->chip_select));
+ reg &= ~(SIGNAL_CTRL_LAUNCH_RISING | SIGNAL_CTRL_LATCH_RISING);
+ if (spi->mode & SPI_CPHA)
+ reg |= SIGNAL_CTRL_LAUNCH_RISING;
+ else
+ reg |= SIGNAL_CTRL_LATCH_RISING;
+ __raw_writel(reg, bs->regs +
+ HSSPI_PROFILE_SIGNAL_CTRL_REG(spi->chip_select));
+
+ mutex_lock(&bs->bus_mutex);
+ reg = __raw_readl(bs->regs + HSSPI_GLOBAL_CTRL_REG);
+
+ if (spi->mode & SPI_CS_HIGH)
+ reg |= BIT(spi->chip_select);
+ else
+ reg &= ~BIT(spi->chip_select);
+ __raw_writel(reg, bs->regs + HSSPI_GLOBAL_CTRL_REG);
+
+ if (spi->mode & SPI_CS_HIGH)
+ bs->cs_polarity |= BIT(spi->chip_select);
+ else
+ bs->cs_polarity &= ~BIT(spi->chip_select);
+
+ reg = __raw_readl(bs->spim_ctrl);
+ reg &= ~BIT(spi->chip_select + SPIM_CTRL_CS_OVERRIDE_VAL_SHIFT);
+ if (spi->mode & SPI_CS_HIGH)
+ reg |= BIT(spi->chip_select + SPIM_CTRL_CS_OVERRIDE_VAL_SHIFT);
+ __raw_writel(reg, bs->spim_ctrl);
+
+ mutex_unlock(&bs->bus_mutex);
+
+ return 0;
+}
+
+static int bcmbca_hsspi_transfer_one(struct spi_master *master,
+ struct spi_message *msg)
+{
+ struct bcmbca_hsspi *bs = spi_master_get_devdata(master);
+ struct spi_transfer *t;
+ struct spi_device *spi = msg->spi;
+ int status = -EINVAL;
+ bool keep_cs = false;
+
+ mutex_lock(&bs->msg_mutex);
+ list_for_each_entry(t, &msg->transfers, transfer_list) {
+ status = bcmbca_hsspi_do_txrx(spi, t, msg);
+ if (status)
+ break;
+
+ spi_transfer_delay_exec(t);
+
+ if (t->cs_change) {
+ if (list_is_last(&t->transfer_list, &msg->transfers)) {
+ keep_cs = true;
+ } else {
+ if (!t->cs_off)
+ bcmbca_hsspi_set_cs(bs, spi->chip_select, false);
+
+ spi_transfer_cs_change_delay_exec(msg, t);
+
+ if (!list_next_entry(t, transfer_list)->cs_off)
+ bcmbca_hsspi_set_cs(bs, spi->chip_select, true);
+ }
+ } else if (!list_is_last(&t->transfer_list, &msg->transfers) &&
+ t->cs_off != list_next_entry(t, transfer_list)->cs_off) {
+ bcmbca_hsspi_set_cs(bs, spi->chip_select, t->cs_off);
+ }
+
+ msg->actual_length += t->len;
+ }
+
+ mutex_unlock(&bs->msg_mutex);
+
+ if (status || !keep_cs)
+ bcmbca_hsspi_set_cs(bs, spi->chip_select, false);
+
+ msg->status = status;
+ spi_finalize_current_message(master);
+
+ return 0;
+}
+
+static irqreturn_t bcmbca_hsspi_interrupt(int irq, void *dev_id)
+{
+ struct bcmbca_hsspi *bs = (struct bcmbca_hsspi *)dev_id;
+
+ if (__raw_readl(bs->regs + HSSPI_INT_STATUS_MASKED_REG) == 0)
+ return IRQ_NONE;
+
+ __raw_writel(HSSPI_INT_CLEAR_ALL, bs->regs + HSSPI_INT_STATUS_REG);
+ __raw_writel(0, bs->regs + HSSPI_INT_MASK_REG);
+
+ complete(&bs->done);
+
+ return IRQ_HANDLED;
+}
+
+static int bcmbca_hsspi_probe(struct platform_device *pdev)
+{
+ struct spi_master *master;
+ struct bcmbca_hsspi *bs;
+ struct resource *res_mem;
+ void __iomem *spim_ctrl;
+ void __iomem *regs;
+ struct device *dev = &pdev->dev;
+ struct clk *clk, *pll_clk = NULL;
+ int irq, ret;
+ u32 reg, rate, num_cs = HSSPI_SPI_MAX_CS;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ res_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hsspi");
+ if (!res_mem)
+ return -EINVAL;
+ regs = devm_ioremap_resource(dev, res_mem);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+
+ res_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "spim-ctrl");
+ if (!res_mem)
+ return -EINVAL;
+ spim_ctrl = devm_ioremap_resource(dev, res_mem);
+ if (IS_ERR(spim_ctrl))
+ return PTR_ERR(spim_ctrl);
+
+ clk = devm_clk_get(dev, "hsspi");
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ ret = clk_prepare_enable(clk);
+ if (ret)
+ return ret;
+
+ rate = clk_get_rate(clk);
+ if (!rate) {
+ pll_clk = devm_clk_get(dev, "pll");
+
+ if (IS_ERR(pll_clk)) {
+ ret = PTR_ERR(pll_clk);
+ goto out_disable_clk;
+ }
+
+ ret = clk_prepare_enable(pll_clk);
+ if (ret)
+ goto out_disable_clk;
+
+ rate = clk_get_rate(pll_clk);
+ if (!rate) {
+ ret = -EINVAL;
+ goto out_disable_pll_clk;
+ }
+ }
+
+ master = spi_alloc_master(&pdev->dev, sizeof(*bs));
+ if (!master) {
+ ret = -ENOMEM;
+ goto out_disable_pll_clk;
+ }
+
+ bs = spi_master_get_devdata(master);
+ bs->pdev = pdev;
+ bs->clk = clk;
+ bs->pll_clk = pll_clk;
+ bs->regs = regs;
+ bs->spim_ctrl = spim_ctrl;
+ bs->speed_hz = rate;
+ bs->fifo = (u8 __iomem *) (bs->regs + HSSPI_FIFO_REG(0));
+ bs->wait_mode = HSSPI_WAIT_MODE_POLLING;
+
+ mutex_init(&bs->bus_mutex);
+ mutex_init(&bs->msg_mutex);
+ init_completion(&bs->done);
+
+ master->dev.of_node = dev->of_node;
+ if (!dev->of_node)
+ master->bus_num = HSSPI_BUS_NUM;
+
+ of_property_read_u32(dev->of_node, "num-cs", &num_cs);
+ if (num_cs > 8) {
+ dev_warn(dev, "unsupported number of cs (%i), reducing to 8\n",
+ num_cs);
+ num_cs = HSSPI_SPI_MAX_CS;
+ }
+ master->num_chipselect = num_cs;
+ master->setup = bcmbca_hsspi_setup;
+ master->transfer_one_message = bcmbca_hsspi_transfer_one;
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH |
+ SPI_RX_DUAL | SPI_TX_DUAL;
+ master->bits_per_word_mask = SPI_BPW_MASK(8);
+ master->auto_runtime_pm = true;
+
+ platform_set_drvdata(pdev, master);
+
+ /* Initialize the hardware */
+ __raw_writel(0, bs->regs + HSSPI_INT_MASK_REG);
+
+ /* clean up any pending interrupts */
+ __raw_writel(HSSPI_INT_CLEAR_ALL, bs->regs + HSSPI_INT_STATUS_REG);
+
+ /* read out default CS polarities */
+ reg = __raw_readl(bs->regs + HSSPI_GLOBAL_CTRL_REG);
+ bs->cs_polarity = reg & GLOBAL_CTRL_CS_POLARITY_MASK;
+ __raw_writel(reg | GLOBAL_CTRL_CLK_GATE_SSOFF,
+ bs->regs + HSSPI_GLOBAL_CTRL_REG);
+
+ if (irq > 0) {
+ ret = devm_request_irq(dev, irq, bcmbca_hsspi_interrupt, IRQF_SHARED,
+ pdev->name, bs);
+ if (ret)
+ goto out_put_master;
+ }
+
+ pm_runtime_enable(&pdev->dev);
+
+ ret = sysfs_create_group(&pdev->dev.kobj, &bcmbca_hsspi_group);
+ if (ret) {
+ dev_err(&pdev->dev, "couldn't register sysfs group\n");
+ goto out_pm_disable;
+ }
+
+ /* register and we are done */
+ ret = devm_spi_register_master(dev, master);
+ if (ret)
+ goto out_sysgroup_disable;
+
+ dev_info(dev, "Broadcom BCMBCA High Speed SPI Controller driver");
+
+ return 0;
+
+out_sysgroup_disable:
+ sysfs_remove_group(&pdev->dev.kobj, &bcmbca_hsspi_group);
+out_pm_disable:
+ pm_runtime_disable(&pdev->dev);
+out_put_master:
+ spi_master_put(master);
+out_disable_pll_clk:
+ clk_disable_unprepare(pll_clk);
+out_disable_clk:
+ clk_disable_unprepare(clk);
+ return ret;
+}
+
+static int bcmbca_hsspi_remove(struct platform_device *pdev)
+{
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct bcmbca_hsspi *bs = spi_master_get_devdata(master);
+
+ /* reset the hardware and block queue progress */
+ __raw_writel(0, bs->regs + HSSPI_INT_MASK_REG);
+ clk_disable_unprepare(bs->pll_clk);
+ clk_disable_unprepare(bs->clk);
+ sysfs_remove_group(&pdev->dev.kobj, &bcmbca_hsspi_group);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int bcmbca_hsspi_suspend(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct bcmbca_hsspi *bs = spi_master_get_devdata(master);
+
+ spi_master_suspend(master);
+ clk_disable_unprepare(bs->pll_clk);
+ clk_disable_unprepare(bs->clk);
+
+ return 0;
+}
+
+static int bcmbca_hsspi_resume(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct bcmbca_hsspi *bs = spi_master_get_devdata(master);
+ int ret;
+
+ ret = clk_prepare_enable(bs->clk);
+ if (ret)
+ return ret;
+
+ if (bs->pll_clk) {
+ ret = clk_prepare_enable(bs->pll_clk);
+ if (ret) {
+ clk_disable_unprepare(bs->clk);
+ return ret;
+ }
+ }
+
+ spi_master_resume(master);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(bcmbca_hsspi_pm_ops, bcmbca_hsspi_suspend,
+ bcmbca_hsspi_resume);
+
+static const struct of_device_id bcmbca_hsspi_of_match[] = {
+ { .compatible = "brcm,bcmbca-hsspi-v1.1", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, bcmbca_hsspi_of_match);
+
+static struct platform_driver bcmbca_hsspi_driver = {
+ .driver = {
+ .name = "bcmbca-hsspi",
+ .pm = &bcmbca_hsspi_pm_ops,
+ .of_match_table = bcmbca_hsspi_of_match,
+ },
+ .probe = bcmbca_hsspi_probe,
+ .remove = bcmbca_hsspi_remove,
+};
+
+module_platform_driver(bcmbca_hsspi_driver);
+
+MODULE_ALIAS("platform:bcmbca_hsspi");
+MODULE_DESCRIPTION("Broadcom BCMBCA High Speed SPI Controller driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c
index 676313e1bdad..64b6a460d739 100644
--- a/drivers/spi/spi-cadence-quadspi.c
+++ b/drivers/spi/spi-cadence-quadspi.c
@@ -84,6 +84,7 @@ struct cqspi_st {
u32 trigger_address;
u32 wr_delay;
bool use_direct_mode;
+ bool use_direct_mode_wr;
struct cqspi_flash_pdata f_pdata[CQSPI_MAX_CHIPSELECT];
bool use_dma_read;
u32 pd_dev_id;
@@ -531,6 +532,17 @@ static int cqspi_command_read(struct cqspi_flash_pdata *f_pdata,
/* 0 means 1 byte. */
reg |= (((n_rx - 1) & CQSPI_REG_CMDCTRL_RD_BYTES_MASK)
<< CQSPI_REG_CMDCTRL_RD_BYTES_LSB);
+
+ /* setup ADDR BIT field */
+ if (op->addr.nbytes) {
+ reg |= (0x1 << CQSPI_REG_CMDCTRL_ADDR_EN_LSB);
+ reg |= ((op->addr.nbytes - 1) &
+ CQSPI_REG_CMDCTRL_ADD_BYTES_MASK)
+ << CQSPI_REG_CMDCTRL_ADD_BYTES_LSB;
+
+ writel(op->addr.val, reg_base + CQSPI_REG_CMDADDRESS);
+ }
+
status = cqspi_exec_flash_cmd(cqspi, reg);
if (status)
return status;
@@ -549,6 +561,9 @@ static int cqspi_command_read(struct cqspi_flash_pdata *f_pdata,
memcpy(rxbuf, &reg, read_len);
}
+ /* Reset CMD_CTRL Reg once command read completes */
+ writel(0, reg_base + CQSPI_REG_CMDCTRL);
+
return 0;
}
@@ -613,7 +628,12 @@ static int cqspi_command_write(struct cqspi_flash_pdata *f_pdata,
}
}
- return cqspi_exec_flash_cmd(cqspi, reg);
+ ret = cqspi_exec_flash_cmd(cqspi, reg);
+
+ /* Reset CMD_CTRL Reg once command write completes */
+ writel(0, reg_base + CQSPI_REG_CMDCTRL);
+
+ return ret;
}
static int cqspi_read_setup(struct cqspi_flash_pdata *f_pdata,
@@ -766,7 +786,7 @@ failrd:
writel(0, reg_base + CQSPI_REG_IRQMASK);
/* Cancel the indirect read */
- writel(CQSPI_REG_INDIRECTWR_CANCEL_MASK,
+ writel(CQSPI_REG_INDIRECTRD_CANCEL_MASK,
reg_base + CQSPI_REG_INDIRECTRD);
return ret;
}
@@ -937,6 +957,12 @@ static int cqspi_write_setup(struct cqspi_flash_pdata *f_pdata,
reg = readl(reg_base + CQSPI_REG_WR_COMPLETION_CTRL);
reg |= CQSPI_REG_WR_DISABLE_AUTO_POLL;
writel(reg, reg_base + CQSPI_REG_WR_COMPLETION_CTRL);
+ /*
+ * DAC mode require auto polling as flash needs to be polled
+ * for write completion in case of bubble in SPI transaction
+ * due to slow CPU/DMA master.
+ */
+ cqspi->use_direct_mode_wr = false;
}
reg = readl(reg_base + CQSPI_REG_SIZE);
@@ -1222,7 +1248,7 @@ static ssize_t cqspi_write(struct cqspi_flash_pdata *f_pdata,
* data.
*/
if (!op->cmd.dtr && cqspi->use_direct_mode &&
- ((to + len) <= cqspi->ahb_size)) {
+ cqspi->use_direct_mode_wr && ((to + len) <= cqspi->ahb_size)) {
memcpy_toio(cqspi->ahb_base + to, buf, len);
return cqspi_wait_idle(cqspi);
}
@@ -1333,7 +1359,13 @@ static int cqspi_mem_process(struct spi_mem *mem, const struct spi_mem_op *op)
cqspi_configure(f_pdata, mem->spi->max_speed_hz);
if (op->data.dir == SPI_MEM_DATA_IN && op->data.buf.in) {
- if (!op->addr.nbytes)
+ /*
+ * Performing reads in DAC mode forces to read minimum 4 bytes
+ * which is unsupported on some flash devices during register
+ * reads, prefer STIG mode for such small reads.
+ */
+ if (!op->addr.nbytes ||
+ op->data.nbytes <= CQSPI_STIG_DATA_LEN_MAX)
return cqspi_command_read(f_pdata, op);
return cqspi_read(f_pdata, op);
@@ -1692,8 +1724,10 @@ static int cqspi_probe(struct platform_device *pdev)
cqspi->master_ref_clk_hz);
if (ddata->hwcaps_mask & CQSPI_SUPPORTS_OCTAL)
master->mode_bits |= SPI_RX_OCTAL | SPI_TX_OCTAL;
- if (!(ddata->quirks & CQSPI_DISABLE_DAC_MODE))
+ if (!(ddata->quirks & CQSPI_DISABLE_DAC_MODE)) {
cqspi->use_direct_mode = true;
+ cqspi->use_direct_mode_wr = true;
+ }
if (ddata->quirks & CQSPI_SUPPORT_EXTERNAL_DMA)
cqspi->use_dma_read = true;
if (ddata->quirks & CQSPI_NO_SUPPORT_WR_COMPLETION)
diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
index 4e83cc5b445d..babb039bcb43 100644
--- a/drivers/spi/spi-geni-qcom.c
+++ b/drivers/spi/spi-geni-qcom.c
@@ -12,7 +12,7 @@
#include <linux/platform_device.h>
#include <linux/pm_opp.h>
#include <linux/pm_runtime.h>
-#include <linux/qcom-geni-se.h>
+#include <linux/soc/qcom/geni-se.h>
#include <linux/spi/spi.h>
#include <linux/spinlock.h>
@@ -87,6 +87,8 @@ struct spi_geni_master {
struct completion cs_done;
struct completion cancel_done;
struct completion abort_done;
+ struct completion tx_reset_done;
+ struct completion rx_reset_done;
unsigned int oversampling;
spinlock_t lock;
int irq;
@@ -95,6 +97,8 @@ struct spi_geni_master {
struct dma_chan *tx;
struct dma_chan *rx;
int cur_xfer_mode;
+ dma_addr_t tx_se_dma;
+ dma_addr_t rx_se_dma;
};
static int get_spi_clk_cfg(unsigned int speed_hz,
@@ -129,23 +133,27 @@ static int get_spi_clk_cfg(unsigned int speed_hz,
return ret;
}
-static void handle_fifo_timeout(struct spi_master *spi,
+static void handle_se_timeout(struct spi_master *spi,
struct spi_message *msg)
{
struct spi_geni_master *mas = spi_master_get_devdata(spi);
unsigned long time_left;
struct geni_se *se = &mas->se;
+ const struct spi_transfer *xfer;
spin_lock_irq(&mas->lock);
reinit_completion(&mas->cancel_done);
- writel(0, se->base + SE_GENI_TX_WATERMARK_REG);
+ if (mas->cur_xfer_mode == GENI_SE_FIFO)
+ writel(0, se->base + SE_GENI_TX_WATERMARK_REG);
+
+ xfer = mas->cur_xfer;
mas->cur_xfer = NULL;
geni_se_cancel_m_cmd(se);
spin_unlock_irq(&mas->lock);
time_left = wait_for_completion_timeout(&mas->cancel_done, HZ);
if (time_left)
- return;
+ goto unmap_if_dma;
spin_lock_irq(&mas->lock);
reinit_completion(&mas->abort_done);
@@ -162,6 +170,39 @@ static void handle_fifo_timeout(struct spi_master *spi,
*/
mas->abort_failed = true;
}
+
+unmap_if_dma:
+ if (mas->cur_xfer_mode == GENI_SE_DMA) {
+ if (xfer) {
+ if (xfer->tx_buf && mas->tx_se_dma) {
+ spin_lock_irq(&mas->lock);
+ reinit_completion(&mas->tx_reset_done);
+ writel(1, se->base + SE_DMA_TX_FSM_RST);
+ spin_unlock_irq(&mas->lock);
+ time_left = wait_for_completion_timeout(&mas->tx_reset_done, HZ);
+ if (!time_left)
+ dev_err(mas->dev, "DMA TX RESET failed\n");
+ geni_se_tx_dma_unprep(se, mas->tx_se_dma, xfer->len);
+ }
+ if (xfer->rx_buf && mas->rx_se_dma) {
+ spin_lock_irq(&mas->lock);
+ reinit_completion(&mas->rx_reset_done);
+ writel(1, se->base + SE_DMA_RX_FSM_RST);
+ spin_unlock_irq(&mas->lock);
+ time_left = wait_for_completion_timeout(&mas->rx_reset_done, HZ);
+ if (!time_left)
+ dev_err(mas->dev, "DMA RX RESET failed\n");
+ geni_se_rx_dma_unprep(se, mas->rx_se_dma, xfer->len);
+ }
+ } else {
+ /*
+ * This can happen if a timeout happened and we had to wait
+ * for lock in this function because isr was holding the lock
+ * and handling transfer completion at that time.
+ */
+ dev_warn(mas->dev, "Cancel/Abort on completed SPI transfer\n");
+ }
+ }
}
static void handle_gpi_timeout(struct spi_master *spi, struct spi_message *msg)
@@ -178,7 +219,8 @@ static void spi_geni_handle_err(struct spi_master *spi, struct spi_message *msg)
switch (mas->cur_xfer_mode) {
case GENI_SE_FIFO:
- handle_fifo_timeout(spi, msg);
+ case GENI_SE_DMA:
+ handle_se_timeout(spi, msg);
break;
case GENI_GPI_DMA:
handle_gpi_timeout(spi, msg);
@@ -250,6 +292,8 @@ static void spi_geni_set_cs(struct spi_device *slv, bool set_flag)
}
mas->cs_flag = set_flag;
+ /* set xfer_mode to FIFO to complete cs_done in isr */
+ mas->cur_xfer_mode = GENI_SE_FIFO;
reinit_completion(&mas->cs_done);
if (set_flag)
geni_se_setup_m_cmd(se, SPI_CS_ASSERT, 0);
@@ -260,7 +304,7 @@ static void spi_geni_set_cs(struct spi_device *slv, bool set_flag)
time_left = wait_for_completion_timeout(&mas->cs_done, HZ);
if (!time_left) {
dev_warn(mas->dev, "Timeout setting chip select\n");
- handle_fifo_timeout(spi, NULL);
+ handle_se_timeout(spi, NULL);
}
exit:
@@ -482,8 +526,12 @@ static bool geni_can_dma(struct spi_controller *ctlr,
{
struct spi_geni_master *mas = spi_master_get_devdata(slv->master);
- /* check if dma is supported */
- return mas->cur_xfer_mode != GENI_SE_FIFO;
+ /*
+ * Return true if transfer needs to be mapped prior to
+ * calling transfer_one which is the case only for GPI_DMA.
+ * For SE_DMA mode, map/unmap is done in geni_se_*x_dma_prep.
+ */
+ return mas->cur_xfer_mode == GENI_GPI_DMA;
}
static int spi_geni_prepare_message(struct spi_master *spi,
@@ -494,6 +542,7 @@ static int spi_geni_prepare_message(struct spi_master *spi,
switch (mas->cur_xfer_mode) {
case GENI_SE_FIFO:
+ case GENI_SE_DMA:
if (spi_geni_is_abort_still_pending(mas))
return -EBUSY;
ret = setup_fifo_params(spi_msg->spi, spi);
@@ -597,7 +646,7 @@ static int spi_geni_init(struct spi_geni_master *mas)
break;
}
/*
- * in case of failure to get dma channel, we can still do the
+ * in case of failure to get gpi dma channel, we can still do the
* FIFO mode, so fallthrough
*/
dev_warn(mas->dev, "FIFO mode disabled, but couldn't get DMA, fall back to FIFO mode\n");
@@ -716,12 +765,12 @@ static void geni_spi_handle_rx(struct spi_geni_master *mas)
mas->rx_rem_bytes -= rx_bytes;
}
-static void setup_fifo_xfer(struct spi_transfer *xfer,
+static int setup_se_xfer(struct spi_transfer *xfer,
struct spi_geni_master *mas,
u16 mode, struct spi_master *spi)
{
u32 m_cmd = 0;
- u32 len;
+ u32 len, fifo_size;
struct geni_se *se = &mas->se;
int ret;
@@ -748,7 +797,7 @@ static void setup_fifo_xfer(struct spi_transfer *xfer,
/* Speed and bits per word can be overridden per transfer */
ret = geni_spi_set_clock_and_bw(mas, xfer->speed_hz);
if (ret)
- return;
+ return ret;
mas->tx_rem_bytes = 0;
mas->rx_rem_bytes = 0;
@@ -772,17 +821,50 @@ static void setup_fifo_xfer(struct spi_transfer *xfer,
mas->rx_rem_bytes = xfer->len;
}
+ /* Select transfer mode based on transfer length */
+ fifo_size = mas->tx_fifo_depth * mas->fifo_width_bits / mas->cur_bits_per_word;
+ mas->cur_xfer_mode = (len <= fifo_size) ? GENI_SE_FIFO : GENI_SE_DMA;
+ geni_se_select_mode(se, mas->cur_xfer_mode);
+
/*
* Lock around right before we start the transfer since our
* interrupt could come in at any time now.
*/
spin_lock_irq(&mas->lock);
geni_se_setup_m_cmd(se, m_cmd, FRAGMENTATION);
- if (m_cmd & SPI_TX_ONLY) {
+
+ if (mas->cur_xfer_mode == GENI_SE_DMA) {
+ if (m_cmd & SPI_RX_ONLY) {
+ ret = geni_se_rx_dma_prep(se, xfer->rx_buf,
+ xfer->len, &mas->rx_se_dma);
+ if (ret) {
+ dev_err(mas->dev, "Failed to setup Rx dma %d\n", ret);
+ mas->rx_se_dma = 0;
+ goto unlock_and_return;
+ }
+ }
+ if (m_cmd & SPI_TX_ONLY) {
+ ret = geni_se_tx_dma_prep(se, (void *)xfer->tx_buf,
+ xfer->len, &mas->tx_se_dma);
+ if (ret) {
+ dev_err(mas->dev, "Failed to setup Tx dma %d\n", ret);
+ mas->tx_se_dma = 0;
+ if (m_cmd & SPI_RX_ONLY) {
+ /* Unmap rx buffer if duplex transfer */
+ geni_se_rx_dma_unprep(se, mas->rx_se_dma, xfer->len);
+ mas->rx_se_dma = 0;
+ }
+ goto unlock_and_return;
+ }
+ }
+ } else if (m_cmd & SPI_TX_ONLY) {
if (geni_spi_handle_tx(mas))
writel(mas->tx_wm, se->base + SE_GENI_TX_WATERMARK_REG);
}
+
+unlock_and_return:
spin_unlock_irq(&mas->lock);
+ return ret;
}
static int spi_geni_transfer_one(struct spi_master *spi,
@@ -790,6 +872,7 @@ static int spi_geni_transfer_one(struct spi_master *spi,
struct spi_transfer *xfer)
{
struct spi_geni_master *mas = spi_master_get_devdata(spi);
+ int ret;
if (spi_geni_is_abort_still_pending(mas))
return -EBUSY;
@@ -798,9 +881,12 @@ static int spi_geni_transfer_one(struct spi_master *spi,
if (!xfer->len)
return 0;
- if (mas->cur_xfer_mode == GENI_SE_FIFO) {
- setup_fifo_xfer(xfer, mas, slv->mode, spi);
- return 1;
+ if (mas->cur_xfer_mode == GENI_SE_FIFO || mas->cur_xfer_mode == GENI_SE_DMA) {
+ ret = setup_se_xfer(xfer, mas, slv->mode, spi);
+ /* SPI framework expects +ve ret code to wait for transfer complete */
+ if (!ret)
+ ret = 1;
+ return ret;
}
return setup_gsi_xfer(xfer, mas, slv, spi);
}
@@ -823,39 +909,70 @@ static irqreturn_t geni_spi_isr(int irq, void *data)
spin_lock(&mas->lock);
- if ((m_irq & M_RX_FIFO_WATERMARK_EN) || (m_irq & M_RX_FIFO_LAST_EN))
- geni_spi_handle_rx(mas);
-
- if (m_irq & M_TX_FIFO_WATERMARK_EN)
- geni_spi_handle_tx(mas);
-
- if (m_irq & M_CMD_DONE_EN) {
- if (mas->cur_xfer) {
+ if (mas->cur_xfer_mode == GENI_SE_FIFO) {
+ if ((m_irq & M_RX_FIFO_WATERMARK_EN) || (m_irq & M_RX_FIFO_LAST_EN))
+ geni_spi_handle_rx(mas);
+
+ if (m_irq & M_TX_FIFO_WATERMARK_EN)
+ geni_spi_handle_tx(mas);
+
+ if (m_irq & M_CMD_DONE_EN) {
+ if (mas->cur_xfer) {
+ spi_finalize_current_transfer(spi);
+ mas->cur_xfer = NULL;
+ /*
+ * If this happens, then a CMD_DONE came before all the
+ * Tx buffer bytes were sent out. This is unusual, log
+ * this condition and disable the WM interrupt to
+ * prevent the system from stalling due an interrupt
+ * storm.
+ *
+ * If this happens when all Rx bytes haven't been
+ * received, log the condition. The only known time
+ * this can happen is if bits_per_word != 8 and some
+ * registers that expect xfer lengths in num spi_words
+ * weren't written correctly.
+ */
+ if (mas->tx_rem_bytes) {
+ writel(0, se->base + SE_GENI_TX_WATERMARK_REG);
+ dev_err(mas->dev, "Premature done. tx_rem = %d bpw%d\n",
+ mas->tx_rem_bytes, mas->cur_bits_per_word);
+ }
+ if (mas->rx_rem_bytes)
+ dev_err(mas->dev, "Premature done. rx_rem = %d bpw%d\n",
+ mas->rx_rem_bytes, mas->cur_bits_per_word);
+ } else {
+ complete(&mas->cs_done);
+ }
+ }
+ } else if (mas->cur_xfer_mode == GENI_SE_DMA) {
+ const struct spi_transfer *xfer = mas->cur_xfer;
+ u32 dma_tx_status = readl_relaxed(se->base + SE_DMA_TX_IRQ_STAT);
+ u32 dma_rx_status = readl_relaxed(se->base + SE_DMA_RX_IRQ_STAT);
+
+ if (dma_tx_status)
+ writel(dma_tx_status, se->base + SE_DMA_TX_IRQ_CLR);
+ if (dma_rx_status)
+ writel(dma_rx_status, se->base + SE_DMA_RX_IRQ_CLR);
+ if (dma_tx_status & TX_DMA_DONE)
+ mas->tx_rem_bytes = 0;
+ if (dma_rx_status & RX_DMA_DONE)
+ mas->rx_rem_bytes = 0;
+ if (dma_tx_status & TX_RESET_DONE)
+ complete(&mas->tx_reset_done);
+ if (dma_rx_status & RX_RESET_DONE)
+ complete(&mas->rx_reset_done);
+ if (!mas->tx_rem_bytes && !mas->rx_rem_bytes && xfer) {
+ if (xfer->tx_buf && mas->tx_se_dma) {
+ geni_se_tx_dma_unprep(se, mas->tx_se_dma, xfer->len);
+ mas->tx_se_dma = 0;
+ }
+ if (xfer->rx_buf && mas->rx_se_dma) {
+ geni_se_rx_dma_unprep(se, mas->rx_se_dma, xfer->len);
+ mas->rx_se_dma = 0;
+ }
spi_finalize_current_transfer(spi);
mas->cur_xfer = NULL;
- /*
- * If this happens, then a CMD_DONE came before all the
- * Tx buffer bytes were sent out. This is unusual, log
- * this condition and disable the WM interrupt to
- * prevent the system from stalling due an interrupt
- * storm.
- *
- * If this happens when all Rx bytes haven't been
- * received, log the condition. The only known time
- * this can happen is if bits_per_word != 8 and some
- * registers that expect xfer lengths in num spi_words
- * weren't written correctly.
- */
- if (mas->tx_rem_bytes) {
- writel(0, se->base + SE_GENI_TX_WATERMARK_REG);
- dev_err(mas->dev, "Premature done. tx_rem = %d bpw%d\n",
- mas->tx_rem_bytes, mas->cur_bits_per_word);
- }
- if (mas->rx_rem_bytes)
- dev_err(mas->dev, "Premature done. rx_rem = %d bpw%d\n",
- mas->rx_rem_bytes, mas->cur_bits_per_word);
- } else {
- complete(&mas->cs_done);
}
}
@@ -949,6 +1066,8 @@ static int spi_geni_probe(struct platform_device *pdev)
init_completion(&mas->cs_done);
init_completion(&mas->cancel_done);
init_completion(&mas->abort_done);
+ init_completion(&mas->tx_reset_done);
+ init_completion(&mas->rx_reset_done);
spin_lock_init(&mas->lock);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, 250);
diff --git a/drivers/spi/spi-intel-pci.c b/drivers/spi/spi-intel-pci.c
index f0d532ea40e8..4d69e320d018 100644
--- a/drivers/spi/spi-intel-pci.c
+++ b/drivers/spi/spi-intel-pci.c
@@ -60,12 +60,12 @@ static int intel_spi_pci_probe(struct pci_dev *pdev,
}
static const struct pci_device_id intel_spi_pci_ids[] = {
- { PCI_VDEVICE(INTEL, 0x02a4), (unsigned long)&bxt_info },
- { PCI_VDEVICE(INTEL, 0x06a4), (unsigned long)&bxt_info },
+ { PCI_VDEVICE(INTEL, 0x02a4), (unsigned long)&cnl_info },
+ { PCI_VDEVICE(INTEL, 0x06a4), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0x18e0), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x19e0), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x1bca), (unsigned long)&bxt_info },
- { PCI_VDEVICE(INTEL, 0x34a4), (unsigned long)&bxt_info },
+ { PCI_VDEVICE(INTEL, 0x34a4), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0x38a4), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x43a4), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0x4b24), (unsigned long)&bxt_info },
@@ -75,11 +75,14 @@ static const struct pci_device_id intel_spi_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x7a24), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0x7aa4), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0x7e23), (unsigned long)&cnl_info },
- { PCI_VDEVICE(INTEL, 0xa0a4), (unsigned long)&bxt_info },
+ { PCI_VDEVICE(INTEL, 0x9d24), (unsigned long)&cnl_info },
+ { PCI_VDEVICE(INTEL, 0x9da4), (unsigned long)&cnl_info },
+ { PCI_VDEVICE(INTEL, 0xa0a4), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0xa1a4), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0xa224), (unsigned long)&bxt_info },
+ { PCI_VDEVICE(INTEL, 0xa2a4), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0xa324), (unsigned long)&cnl_info },
- { PCI_VDEVICE(INTEL, 0xa3a4), (unsigned long)&bxt_info },
+ { PCI_VDEVICE(INTEL, 0xa3a4), (unsigned long)&cnl_info },
{ },
};
MODULE_DEVICE_TABLE(pci, intel_spi_pci_ids);
diff --git a/drivers/spi/spi-intel.c b/drivers/spi/spi-intel.c
index f619212b0d5c..f4679868c49f 100644
--- a/drivers/spi/spi-intel.c
+++ b/drivers/spi/spi-intel.c
@@ -104,7 +104,7 @@
#define BXT_PR 0x84
#define BXT_SSFSTS_CTL 0xa0
#define BXT_FREG_NUM 12
-#define BXT_PR_NUM 6
+#define BXT_PR_NUM 5
#define CNL_PR 0x84
#define CNL_FREG_NUM 6
@@ -1368,14 +1368,14 @@ static int intel_spi_populate_chip(struct intel_spi *ispi)
if (!spi_new_device(ispi->master, &chip))
return -ENODEV;
- /* Add the second chip if present */
- if (ispi->master->num_chipselect < 2)
- return 0;
-
ret = intel_spi_read_desc(ispi);
if (ret)
return ret;
+ /* Add the second chip if present */
+ if (ispi->master->num_chipselect < 2)
+ return 0;
+
chip.platform_data = NULL;
chip.chip_select = 1;
diff --git a/drivers/spi/spi-loopback-test.c b/drivers/spi/spi-loopback-test.c
index dd7de8fa37d0..313106eb8d40 100644
--- a/drivers/spi/spi-loopback-test.c
+++ b/drivers/spi/spi-loopback-test.c
@@ -71,6 +71,11 @@ module_param(check_ranges, int, 0644);
MODULE_PARM_DESC(check_ranges,
"checks rx_buffer pattern are valid");
+static unsigned int delay_ms = 100;
+module_param(delay_ms, uint, 0644);
+MODULE_PARM_DESC(delay_ms,
+ "delay between tests, in milliseconds (default: 100)");
+
/* the actual tests to execute */
static struct spi_test spi_tests[] = {
{
@@ -1098,7 +1103,8 @@ int spi_test_run_tests(struct spi_device *spi,
* detect the individual tests when using a logic analyzer
* we also add scheduling to avoid potential spi_timeouts...
*/
- mdelay(100);
+ if (delay_ms)
+ mdelay(delay_ms);
schedule();
}
diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
index 0c79193d9697..701838b6f0c4 100644
--- a/drivers/spi/spi-mem.c
+++ b/drivers/spi/spi-mem.c
@@ -325,7 +325,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
if (!spi_mem_internal_supports_op(mem, op))
return -ENOTSUPP;
- if (ctlr->mem_ops && !mem->spi->cs_gpiod) {
+ if (ctlr->mem_ops && ctlr->mem_ops->exec_op && !mem->spi->cs_gpiod) {
ret = spi_mem_access_start(mem);
if (ret)
return ret;
diff --git a/drivers/spi/spi-mtk-snfi.c b/drivers/spi/spi-mtk-snfi.c
index fa8412ba20e2..f3f95eb37365 100644
--- a/drivers/spi/spi-mtk-snfi.c
+++ b/drivers/spi/spi-mtk-snfi.c
@@ -195,6 +195,8 @@
#define DATA_READ_MODE_X4 2
#define DATA_READ_MODE_DUAL 5
#define DATA_READ_MODE_QUAD 6
+#define DATA_READ_LATCH_LAT GENMASK(9, 8)
+#define DATA_READ_LATCH_LAT_S 8
#define PG_LOAD_CUSTOM_EN BIT(7)
#define DATARD_CUSTOM_EN BIT(6)
#define CS_DESELECT_CYC_S 0
@@ -205,6 +207,9 @@
#define SNF_DLY_CTL3 0x548
#define SFCK_SAM_DLY_S 0
+#define SFCK_SAM_DLY GENMASK(5, 0)
+#define SFCK_SAM_DLY_TOTAL 9
+#define SFCK_SAM_DLY_RANGE 47
#define SNF_STA_CTL1 0x550
#define CUS_PG_DONE BIT(28)
@@ -297,6 +302,7 @@ struct mtk_snand {
struct device *dev;
struct clk *nfi_clk;
struct clk *pad_clk;
+ struct clk *nfi_hclk;
void __iomem *nfi_base;
int irq;
struct completion op_done;
@@ -1339,7 +1345,16 @@ static int mtk_snand_enable_clk(struct mtk_snand *ms)
dev_err(ms->dev, "unable to enable pad clk\n");
goto err1;
}
+ ret = clk_prepare_enable(ms->nfi_hclk);
+ if (ret) {
+ dev_err(ms->dev, "unable to enable nfi hclk\n");
+ goto err2;
+ }
+
return 0;
+
+err2:
+ clk_disable_unprepare(ms->pad_clk);
err1:
clk_disable_unprepare(ms->nfi_clk);
return ret;
@@ -1347,6 +1362,7 @@ err1:
static void mtk_snand_disable_clk(struct mtk_snand *ms)
{
+ clk_disable_unprepare(ms->nfi_hclk);
clk_disable_unprepare(ms->pad_clk);
clk_disable_unprepare(ms->nfi_clk);
}
@@ -1357,6 +1373,8 @@ static int mtk_snand_probe(struct platform_device *pdev)
const struct of_device_id *dev_id;
struct spi_controller *ctlr;
struct mtk_snand *ms;
+ unsigned long spi_freq;
+ u32 val = 0;
int ret;
dev_id = of_match_node(mtk_snand_ids, np);
@@ -1401,6 +1419,13 @@ static int mtk_snand_probe(struct platform_device *pdev)
goto release_ecc;
}
+ ms->nfi_hclk = devm_clk_get_optional(&pdev->dev, "nfi_hclk");
+ if (IS_ERR(ms->nfi_hclk)) {
+ ret = PTR_ERR(ms->nfi_hclk);
+ dev_err(&pdev->dev, "unable to get nfi_hclk, err = %d\n", ret);
+ goto release_ecc;
+ }
+
ret = mtk_snand_enable_clk(ms);
if (ret)
goto release_ecc;
@@ -1428,10 +1453,22 @@ static int mtk_snand_probe(struct platform_device *pdev)
// switch to SNFI mode
nfi_write32(ms, SNF_CFG, SPI_MODE);
+ ret = of_property_read_u32(np, "rx-sample-delay-ns", &val);
+ if (!ret)
+ nfi_rmw32(ms, SNF_DLY_CTL3, SFCK_SAM_DLY,
+ val * SFCK_SAM_DLY_RANGE / SFCK_SAM_DLY_TOTAL);
+
+ ret = of_property_read_u32(np, "mediatek,rx-latch-latency-ns", &val);
+ if (!ret) {
+ spi_freq = clk_get_rate(ms->pad_clk);
+ val = DIV_ROUND_CLOSEST(val, NSEC_PER_SEC / spi_freq);
+ nfi_rmw32(ms, SNF_MISC_CTL, DATA_READ_LATCH_LAT,
+ val << DATA_READ_LATCH_LAT_S);
+ }
+
// setup an initial page format for ops matching page_cache_op template
// before ECC is called.
- ret = mtk_snand_setup_pagefmt(ms, ms->caps->sector_size,
- ms->caps->spare_sizes[0]);
+ ret = mtk_snand_setup_pagefmt(ms, SZ_2K, SZ_64);
if (ret) {
dev_err(ms->dev, "failed to set initial page format\n");
goto disable_clk;
diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c
index e4484ace584e..a17ff839117f 100644
--- a/drivers/spi/spi-pl022.c
+++ b/drivers/spi/spi-pl022.c
@@ -2091,7 +2091,6 @@ pl022_platform_data_dt_get(struct device *dev)
return NULL;
pd->bus_id = -1;
- pd->enable_dma = 1;
of_property_read_u32(np, "pl022,autosuspend-delay",
&pd->autosuspend_delay);
pd->rt = of_property_read_bool(np, "pl022,rt");
diff --git a/drivers/spi/spi-rpc-if.c b/drivers/spi/spi-rpc-if.c
index 24ec1c83f379..ec0904faf3a1 100644
--- a/drivers/spi/spi-rpc-if.c
+++ b/drivers/spi/spi-rpc-if.c
@@ -58,7 +58,7 @@ static void rpcif_spi_mem_prepare(struct spi_device *spi_dev,
rpc_op.data.dir = RPCIF_NO_DATA;
}
- rpcif_prepare(rpc, &rpc_op, offs, len);
+ rpcif_prepare(rpc->dev, &rpc_op, offs, len);
}
static bool rpcif_spi_mem_supports_op(struct spi_mem *mem,
@@ -86,7 +86,7 @@ static ssize_t rpcif_spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc,
rpcif_spi_mem_prepare(desc->mem->spi, &desc->info.op_tmpl, &offs, &len);
- return rpcif_dirmap_read(rpc, offs, len, buf);
+ return rpcif_dirmap_read(rpc->dev, offs, len, buf);
}
static int rpcif_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc)
@@ -117,7 +117,7 @@ static int rpcif_spi_mem_exec_op(struct spi_mem *mem,
rpcif_spi_mem_prepare(mem->spi, op, NULL, NULL);
- return rpcif_manual_xfer(rpc);
+ return rpcif_manual_xfer(rpc->dev);
}
static const struct spi_controller_mem_ops rpcif_spi_mem_ops = {
@@ -147,7 +147,7 @@ static int rpcif_spi_probe(struct platform_device *pdev)
ctlr->dev.of_node = parent->of_node;
- rpcif_enable_rpm(rpc);
+ pm_runtime_enable(rpc->dev);
ctlr->num_chipselect = 1;
ctlr->mem_ops = &rpcif_spi_mem_ops;
@@ -156,7 +156,7 @@ static int rpcif_spi_probe(struct platform_device *pdev)
ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_QUAD | SPI_RX_QUAD;
ctlr->flags = SPI_CONTROLLER_HALF_DUPLEX;
- error = rpcif_hw_init(rpc, false);
+ error = rpcif_hw_init(rpc->dev, false);
if (error)
goto out_disable_rpm;
@@ -169,7 +169,7 @@ static int rpcif_spi_probe(struct platform_device *pdev)
return 0;
out_disable_rpm:
- rpcif_disable_rpm(rpc);
+ pm_runtime_disable(rpc->dev);
return error;
}
@@ -179,7 +179,7 @@ static int rpcif_spi_remove(struct platform_device *pdev)
struct rpcif *rpc = spi_controller_get_devdata(ctlr);
spi_unregister_controller(ctlr);
- rpcif_disable_rpm(rpc);
+ pm_runtime_disable(rpc->dev);
return 0;
}
diff --git a/drivers/spi/spi-sn-f-ospi.c b/drivers/spi/spi-sn-f-ospi.c
index 348c6e1edd38..333b22dfd8db 100644
--- a/drivers/spi/spi-sn-f-ospi.c
+++ b/drivers/spi/spi-sn-f-ospi.c
@@ -611,7 +611,7 @@ static int f_ospi_probe(struct platform_device *pdev)
return -ENOMEM;
ctlr->mode_bits = SPI_TX_DUAL | SPI_TX_QUAD | SPI_TX_OCTAL
- | SPI_RX_DUAL | SPI_RX_QUAD | SPI_TX_OCTAL
+ | SPI_RX_DUAL | SPI_RX_QUAD | SPI_RX_OCTAL
| SPI_MODE_0 | SPI_MODE_1 | SPI_LSB_FIRST;
ctlr->mem_ops = &f_ospi_mem_ops;
ctlr->bus_num = -1;
diff --git a/drivers/spi/spi-synquacer.c b/drivers/spi/spi-synquacer.c
index 47cbe73137c2..dc188f9202c9 100644
--- a/drivers/spi/spi-synquacer.c
+++ b/drivers/spi/spi-synquacer.c
@@ -472,10 +472,9 @@ static int synquacer_spi_transfer_one(struct spi_master *master,
read_fifo(sspi);
}
- if (status < 0) {
- dev_err(sspi->dev, "failed to transfer. status: 0x%x\n",
- status);
- return status;
+ if (status == 0) {
+ dev_err(sspi->dev, "failed to transfer. Timeout.\n");
+ return -ETIMEDOUT;
}
return 0;
diff --git a/drivers/spi/spi-tegra210-quad.c b/drivers/spi/spi-tegra210-quad.c
index 9f356612ba7e..0b9bc3b7f53a 100644
--- a/drivers/spi/spi-tegra210-quad.c
+++ b/drivers/spi/spi-tegra210-quad.c
@@ -1156,6 +1156,10 @@ static int tegra_qspi_combined_seq_xfer(struct tegra_qspi *tqspi,
ret = -EIO;
goto exit;
}
+ if (!xfer->cs_change) {
+ tegra_qspi_transfer_end(spi);
+ spi_transfer_delay_exec(xfer);
+ }
break;
default:
ret = -EINVAL;
@@ -1164,14 +1168,14 @@ static int tegra_qspi_combined_seq_xfer(struct tegra_qspi *tqspi,
msg->actual_length += xfer->len;
transfer_phase++;
}
- if (!xfer->cs_change) {
- tegra_qspi_transfer_end(spi);
- spi_transfer_delay_exec(xfer);
- }
ret = 0;
exit:
msg->status = ret;
+ if (ret < 0) {
+ tegra_qspi_transfer_end(spi);
+ spi_transfer_delay_exec(xfer);
+ }
return ret;
}
@@ -1297,7 +1301,7 @@ static bool tegra_qspi_validate_cmb_seq(struct tegra_qspi *tqspi,
if (xfer->len > 4 || xfer->len < 3)
return false;
xfer = list_next_entry(xfer, transfer_list);
- if (!tqspi->soc_data->has_dma || xfer->len > (QSPI_FIFO_DEPTH << 2))
+ if (!tqspi->soc_data->has_dma && xfer->len > (QSPI_FIFO_DEPTH << 2))
return false;
return true;
@@ -1532,6 +1536,7 @@ static int tegra_qspi_probe(struct platform_device *pdev)
master->mode_bits = SPI_MODE_0 | SPI_MODE_3 | SPI_CS_HIGH |
SPI_TX_DUAL | SPI_RX_DUAL | SPI_TX_QUAD | SPI_RX_QUAD;
master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) | SPI_BPW_MASK(8);
+ master->flags = SPI_CONTROLLER_HALF_DUPLEX;
master->setup = tegra_qspi_setup;
master->transfer_one_message = tegra_qspi_transfer_one_message;
master->num_chipselect = 1;
diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c
index 7377d3b81302..1411548f4255 100644
--- a/drivers/spi/spi-xilinx.c
+++ b/drivers/spi/spi-xilinx.c
@@ -83,7 +83,7 @@ struct xilinx_spi {
void __iomem *regs; /* virt. address of the control registers */
int irq;
-
+ bool force_irq; /* force irq to setup master inhibit */
u8 *rx_ptr; /* pointer in the Tx buffer */
const u8 *tx_ptr; /* pointer in the Rx buffer */
u8 bytes_per_word;
@@ -248,7 +248,8 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
xspi->rx_ptr = t->rx_buf;
remaining_words = t->len / xspi->bytes_per_word;
- if (xspi->irq >= 0 && remaining_words > xspi->buffer_size) {
+ if (xspi->irq >= 0 &&
+ (xspi->force_irq || remaining_words > xspi->buffer_size)) {
u32 isr;
use_irq = true;
/* Inhibit irq to avoid spurious irqs on tx_empty*/
@@ -393,6 +394,7 @@ static int xilinx_spi_probe(struct platform_device *pdev)
struct resource *res;
int ret, num_cs = 0, bits_per_word;
struct spi_master *master;
+ bool force_irq = false;
u32 tmp;
u8 i;
@@ -400,6 +402,7 @@ static int xilinx_spi_probe(struct platform_device *pdev)
if (pdata) {
num_cs = pdata->num_chipselect;
bits_per_word = pdata->bits_per_word;
+ force_irq = pdata->force_irq;
} else {
of_property_read_u32(pdev->dev.of_node, "xlnx,num-ss-bits",
&num_cs);
@@ -477,6 +480,8 @@ static int xilinx_spi_probe(struct platform_device *pdev)
dev_name(&pdev->dev), xspi);
if (ret)
return ret;
+
+ xspi->force_irq = force_irq;
}
/* SPI controller initializations */
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 3f33934f5429..44b85a8d47f1 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -395,7 +395,7 @@ static int spi_match_device(struct device *dev, struct device_driver *drv)
return strcmp(spi->modalias, drv->name) == 0;
}
-static int spi_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int spi_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
const struct spi_device *spi = to_spi_device(dev);
int rc;
@@ -604,7 +604,7 @@ static void spi_dev_set_name(struct spi_device *spi)
}
dev_set_name(&spi->dev, "%s.%u", dev_name(&spi->controller->dev),
- spi->chip_select);
+ spi_get_chipselect(spi, 0));
}
static int spi_dev_check(struct device *dev, void *data)
@@ -613,7 +613,7 @@ static int spi_dev_check(struct device *dev, void *data)
struct spi_device *new_spi = data;
if (spi->controller == new_spi->controller &&
- spi->chip_select == new_spi->chip_select)
+ spi_get_chipselect(spi, 0) == spi_get_chipselect(new_spi, 0))
return -EBUSY;
return 0;
}
@@ -638,7 +638,7 @@ static int __spi_add_device(struct spi_device *spi)
status = bus_for_each_dev(&spi_bus_type, NULL, spi, spi_dev_check);
if (status) {
dev_err(dev, "chipselect %d already in use\n",
- spi->chip_select);
+ spi_get_chipselect(spi, 0));
return status;
}
@@ -649,7 +649,7 @@ static int __spi_add_device(struct spi_device *spi)
}
if (ctlr->cs_gpiods)
- spi->cs_gpiod = ctlr->cs_gpiods[spi->chip_select];
+ spi_set_csgpiod(spi, 0, ctlr->cs_gpiods[spi_get_chipselect(spi, 0)]);
/*
* Drivers may modify this initial i/o setup, but will
@@ -692,8 +692,8 @@ int spi_add_device(struct spi_device *spi)
int status;
/* Chipselects are numbered 0..max; validate. */
- if (spi->chip_select >= ctlr->num_chipselect) {
- dev_err(dev, "cs%d >= max %d\n", spi->chip_select,
+ if (spi_get_chipselect(spi, 0) >= ctlr->num_chipselect) {
+ dev_err(dev, "cs%d >= max %d\n", spi_get_chipselect(spi, 0),
ctlr->num_chipselect);
return -EINVAL;
}
@@ -714,8 +714,8 @@ static int spi_add_device_locked(struct spi_device *spi)
struct device *dev = ctlr->dev.parent;
/* Chipselects are numbered 0..max; validate. */
- if (spi->chip_select >= ctlr->num_chipselect) {
- dev_err(dev, "cs%d >= max %d\n", spi->chip_select,
+ if (spi_get_chipselect(spi, 0) >= ctlr->num_chipselect) {
+ dev_err(dev, "cs%d >= max %d\n", spi_get_chipselect(spi, 0),
ctlr->num_chipselect);
return -EINVAL;
}
@@ -761,7 +761,7 @@ struct spi_device *spi_new_device(struct spi_controller *ctlr,
WARN_ON(strlen(chip->modalias) >= sizeof(proxy->modalias));
- proxy->chip_select = chip->chip_select;
+ spi_set_chipselect(proxy, 0, chip->chip_select);
proxy->max_speed_hz = chip->max_speed_hz;
proxy->mode = chip->mode;
proxy->irq = chip->irq;
@@ -970,24 +970,23 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force)
* Avoid calling into the driver (or doing delays) if the chip select
* isn't actually changing from the last time this was called.
*/
- if (!force && ((enable && spi->controller->last_cs == spi->chip_select) ||
- (!enable && spi->controller->last_cs != spi->chip_select)) &&
+ if (!force && ((enable && spi->controller->last_cs == spi_get_chipselect(spi, 0)) ||
+ (!enable && spi->controller->last_cs != spi_get_chipselect(spi, 0))) &&
(spi->controller->last_cs_mode_high == (spi->mode & SPI_CS_HIGH)))
return;
trace_spi_set_cs(spi, activate);
- spi->controller->last_cs = enable ? spi->chip_select : -1;
+ spi->controller->last_cs = enable ? spi_get_chipselect(spi, 0) : -1;
spi->controller->last_cs_mode_high = spi->mode & SPI_CS_HIGH;
- if ((spi->cs_gpiod || !spi->controller->set_cs_timing) && !activate) {
+ if ((spi_get_csgpiod(spi, 0) || !spi->controller->set_cs_timing) && !activate)
spi_delay_exec(&spi->cs_hold, NULL);
- }
if (spi->mode & SPI_CS_HIGH)
enable = !enable;
- if (spi->cs_gpiod) {
+ if (spi_get_csgpiod(spi, 0)) {
if (!(spi->mode & SPI_NO_CS)) {
/*
* Historically ACPI has no means of the GPIO polarity and
@@ -1000,10 +999,10 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force)
* into account.
*/
if (has_acpi_companion(&spi->dev))
- gpiod_set_value_cansleep(spi->cs_gpiod, !enable);
+ gpiod_set_value_cansleep(spi_get_csgpiod(spi, 0), !enable);
else
/* Polarity handled by GPIO library */
- gpiod_set_value_cansleep(spi->cs_gpiod, activate);
+ gpiod_set_value_cansleep(spi_get_csgpiod(spi, 0), activate);
}
/* Some SPI masters need both GPIO CS & slave_select */
if ((spi->controller->flags & SPI_MASTER_GPIO_SS) &&
@@ -1013,7 +1012,7 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force)
spi->controller->set_cs(spi, !enable);
}
- if (spi->cs_gpiod || !spi->controller->set_cs_timing) {
+ if (spi_get_csgpiod(spi, 0) || !spi->controller->set_cs_timing) {
if (activate)
spi_delay_exec(&spi->cs_setup, NULL);
else
@@ -1484,6 +1483,13 @@ static void _spi_transfer_cs_change_delay(struct spi_message *msg,
}
}
+void spi_transfer_cs_change_delay_exec(struct spi_message *msg,
+ struct spi_transfer *xfer)
+{
+ _spi_transfer_cs_change_delay(msg, xfer);
+}
+EXPORT_SYMBOL_GPL(spi_transfer_cs_change_delay_exec);
+
/*
* spi_transfer_one_message - Default implementation of transfer_one_message()
*
@@ -1921,7 +1927,7 @@ void spi_take_timestamp_post(struct spi_controller *ctlr,
/* Capture the resolution of the timestamp */
xfer->ptp_sts_word_post = progress;
- xfer->timestamped = true;
+ xfer->timestamped = 1;
}
EXPORT_SYMBOL_GPL(spi_take_timestamp_post);
@@ -2319,7 +2325,7 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
nc, rc);
return rc;
}
- spi->chip_select = value;
+ spi_set_chipselect(spi, 0, value);
/* Device speed */
if (!of_property_read_u32(nc, "spi-max-frequency", &value))
@@ -2327,6 +2333,8 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
/* Device CS delays */
of_spi_parse_dt_cs_delay(nc, &spi->cs_setup, "spi-cs-setup-delay-ns");
+ of_spi_parse_dt_cs_delay(nc, &spi->cs_hold, "spi-cs-hold-delay-ns");
+ of_spi_parse_dt_cs_delay(nc, &spi->cs_inactive, "spi-cs-inactive-delay-ns");
return 0;
}
@@ -2436,7 +2444,7 @@ struct spi_device *spi_new_ancillary_device(struct spi_device *spi,
strscpy(ancillary->modalias, "dummy", sizeof(ancillary->modalias));
/* Use provided chip-select for ancillary device */
- ancillary->chip_select = chip_select;
+ spi_set_chipselect(ancillary, 0, chip_select);
/* Take over SPI mode/speed from SPI main device */
ancillary->max_speed_hz = spi->max_speed_hz;
@@ -2683,7 +2691,7 @@ struct spi_device *acpi_spi_device_alloc(struct spi_controller *ctlr,
spi->mode |= lookup.mode;
spi->irq = lookup.irq;
spi->bits_per_word = lookup.bits_per_word;
- spi->chip_select = lookup.chip_select;
+ spi_set_chipselect(spi, 0, lookup.chip_select);
return spi;
}
@@ -3064,15 +3072,14 @@ static int spi_controller_check_ops(struct spi_controller *ctlr)
* The controller may implement only the high-level SPI-memory like
* operations if it does not support regular SPI transfers, and this is
* valid use case.
- * If ->mem_ops is NULL, we request that at least one of the
- * ->transfer_xxx() method be implemented.
+ * If ->mem_ops or ->mem_ops->exec_op is NULL, we request that at least
+ * one of the ->transfer_xxx() method be implemented.
*/
- if (ctlr->mem_ops) {
- if (!ctlr->mem_ops->exec_op)
- return -EINVAL;
- } else if (!ctlr->transfer && !ctlr->transfer_one &&
+ if (!ctlr->mem_ops || (ctlr->mem_ops && !ctlr->mem_ops->exec_op)) {
+ if (!ctlr->transfer && !ctlr->transfer_one &&
!ctlr->transfer_one_message) {
- return -EINVAL;
+ return -EINVAL;
+ }
}
return 0;
@@ -3645,7 +3652,7 @@ static int spi_set_cs_timing(struct spi_device *spi)
struct device *parent = spi->controller->dev.parent;
int status = 0;
- if (spi->controller->set_cs_timing && !spi->cs_gpiod) {
+ if (spi->controller->set_cs_timing && !spi_get_csgpiod(spi, 0)) {
if (spi->controller->auto_runtime_pm) {
status = pm_runtime_get_sync(parent);
if (status < 0) {
@@ -3850,7 +3857,7 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
* cs_change is set for each transfer.
*/
if ((spi->mode & SPI_CS_WORD) && (!(ctlr->mode_bits & SPI_CS_WORD) ||
- spi->cs_gpiod)) {
+ spi_get_csgpiod(spi, 0))) {
size_t maxsize;
int ret;
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index a1ea093795cf..5a038c667401 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -116,7 +116,6 @@ spidev_sync(struct spidev_data *spidev, struct spi_message *message)
status = spidev_sync_unlocked(spi, message);
mutex_unlock(&spidev->spi_lock);
-
return status;
}
@@ -712,6 +711,8 @@ static const struct spi_device_id spidev_spi_ids[] = {
{ .name = "m53cpld" },
{ .name = "spi-petra" },
{ .name = "spi-authenta" },
+ { .name = "em3581" },
+ { .name = "si3210" },
{},
};
MODULE_DEVICE_TABLE(spi, spidev_spi_ids);
@@ -730,14 +731,16 @@ static int spidev_of_check(struct device *dev)
}
static const struct of_device_id spidev_dt_ids[] = {
- { .compatible = "rohm,dh2228fv", .data = &spidev_of_check },
+ { .compatible = "cisco,spi-petra", .data = &spidev_of_check },
+ { .compatible = "dh,dhcom-board", .data = &spidev_of_check },
{ .compatible = "lineartechnology,ltc2488", .data = &spidev_of_check },
- { .compatible = "semtech,sx1301", .data = &spidev_of_check },
{ .compatible = "lwn,bk4", .data = &spidev_of_check },
- { .compatible = "dh,dhcom-board", .data = &spidev_of_check },
{ .compatible = "menlo,m53cpld", .data = &spidev_of_check },
- { .compatible = "cisco,spi-petra", .data = &spidev_of_check },
{ .compatible = "micron,spi-authenta", .data = &spidev_of_check },
+ { .compatible = "rohm,dh2228fv", .data = &spidev_of_check },
+ { .compatible = "semtech,sx1301", .data = &spidev_of_check },
+ { .compatible = "silabs,em3581", .data = &spidev_of_check },
+ { .compatible = "silabs,si3210", .data = &spidev_of_check },
{},
};
MODULE_DEVICE_TABLE(of, spidev_dt_ids);
diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c
index 55381592bb5a..73551531ed43 100644
--- a/drivers/spmi/spmi.c
+++ b/drivers/spmi/spmi.c
@@ -366,7 +366,7 @@ static void spmi_drv_shutdown(struct device *dev)
sdrv->shutdown(to_spmi_device(dev));
}
-static int spmi_drv_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int spmi_drv_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
int ret;
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
index 8a93c83cb6f8..ab080cf26c9f 100644
--- a/drivers/ssb/main.c
+++ b/drivers/ssb/main.c
@@ -339,9 +339,9 @@ static int ssb_bus_match(struct device *dev, struct device_driver *drv)
return 0;
}
-static int ssb_device_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int ssb_device_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
+ const struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
if (!dev)
return -ENODEV;
diff --git a/drivers/staging/emxx_udc/emxx_udc.c b/drivers/staging/emxx_udc/emxx_udc.c
index b4e19174bef2..f9765841c4aa 100644
--- a/drivers/staging/emxx_udc/emxx_udc.c
+++ b/drivers/staging/emxx_udc/emxx_udc.c
@@ -2587,10 +2587,15 @@ static int nbu2ss_ep_queue(struct usb_ep *_ep,
req->unaligned = false;
if (req->unaligned) {
- if (!ep->virt_buf)
+ if (!ep->virt_buf) {
ep->virt_buf = dma_alloc_coherent(udc->dev, PAGE_SIZE,
&ep->phys_buf,
GFP_ATOMIC | GFP_DMA);
+ if (!ep->virt_buf) {
+ spin_unlock_irqrestore(&udc->lock, flags);
+ return -ENOMEM;
+ }
+ }
if (ep->epnum > 0) {
if (ep->direct == USB_DIR_IN)
memcpy(ep->virt_buf, req->req.buf,
diff --git a/drivers/staging/greybus/audio_codec.c b/drivers/staging/greybus/audio_codec.c
index 0ad8aeabccbf..72ace74ea605 100644
--- a/drivers/staging/greybus/audio_codec.c
+++ b/drivers/staging/greybus/audio_codec.c
@@ -1075,11 +1075,6 @@ static int gbaudio_codec_probe(struct platform_device *pdev)
gbaudio_dai, ARRAY_SIZE(gbaudio_dai));
}
-static int gbaudio_codec_remove(struct platform_device *pdev)
-{
- return 0;
-}
-
static const struct of_device_id greybus_asoc_machine_of_match[] = {
{ .compatible = "toshiba,apb-dummy-codec", },
{},
@@ -1094,7 +1089,6 @@ static struct platform_driver gbaudio_codec_driver = {
.of_match_table = greybus_asoc_machine_of_match,
},
.probe = gbaudio_codec_probe,
- .remove = gbaudio_codec_remove,
};
module_platform_driver(gbaudio_codec_driver);
diff --git a/drivers/staging/greybus/gbphy.c b/drivers/staging/greybus/gbphy.c
index 5a5c17a4519b..6a7d8cf2a1eb 100644
--- a/drivers/staging/greybus/gbphy.c
+++ b/drivers/staging/greybus/gbphy.c
@@ -71,14 +71,14 @@ static const struct device_type greybus_gbphy_dev_type = {
.pm = &gb_gbphy_pm_ops,
};
-static int gbphy_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int gbphy_dev_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct gbphy_device *gbphy_dev = to_gbphy_dev(dev);
- struct greybus_descriptor_cport *cport_desc = gbphy_dev->cport_desc;
- struct gb_bundle *bundle = gbphy_dev->bundle;
- struct gb_interface *intf = bundle->intf;
- struct gb_module *module = intf->module;
- struct gb_host_device *hd = intf->hd;
+ const struct gbphy_device *gbphy_dev = to_gbphy_dev(dev);
+ const struct greybus_descriptor_cport *cport_desc = gbphy_dev->cport_desc;
+ const struct gb_bundle *bundle = gbphy_dev->bundle;
+ const struct gb_interface *intf = bundle->intf;
+ const struct gb_module *module = intf->module;
+ const struct gb_host_device *hd = intf->hd;
if (add_uevent_var(env, "BUS=%u", hd->bus_id))
return -ENOMEM;
diff --git a/drivers/staging/greybus/gpio.c b/drivers/staging/greybus/gpio.c
index 8a7cf1d0e968..d729b922a750 100644
--- a/drivers/staging/greybus/gpio.c
+++ b/drivers/staging/greybus/gpio.c
@@ -43,7 +43,11 @@ struct gb_gpio_controller {
};
#define gpio_chip_to_gb_gpio_controller(chip) \
container_of(chip, struct gb_gpio_controller, chip)
-#define irq_data_to_gpio_chip(d) (d->domain->host_data)
+
+static struct gpio_chip *irq_data_to_gpio_chip(struct irq_data *d)
+{
+ return d->domain->host_data;
+}
static int gb_gpio_line_count_operation(struct gb_gpio_controller *ggc)
{
diff --git a/drivers/staging/greybus/hid.c b/drivers/staging/greybus/hid.c
index adb91286803a..15335c38cb26 100644
--- a/drivers/staging/greybus/hid.c
+++ b/drivers/staging/greybus/hid.c
@@ -381,7 +381,7 @@ static int gb_hid_power(struct hid_device *hid, int lvl)
}
/* HID structure to pass callbacks */
-static struct hid_ll_driver gb_hid_ll_driver = {
+static const struct hid_ll_driver gb_hid_ll_driver = {
.parse = gb_hid_parse,
.start = gb_hid_start,
.stop = gb_hid_stop,
diff --git a/drivers/staging/greybus/uart.c b/drivers/staging/greybus/uart.c
index 90ff07f2cbf7..20a34599859f 100644
--- a/drivers/staging/greybus/uart.c
+++ b/drivers/staging/greybus/uart.c
@@ -701,7 +701,7 @@ static int gb_tty_ioctl(struct tty_struct *tty, unsigned int cmd,
return -ENOIOCTLCMD;
}
-static void gb_tty_dtr_rts(struct tty_port *port, int on)
+static void gb_tty_dtr_rts(struct tty_port *port, bool active)
{
struct gb_tty *gb_tty;
u8 newctrl;
@@ -709,7 +709,7 @@ static void gb_tty_dtr_rts(struct tty_port *port, int on)
gb_tty = container_of(port, struct gb_tty, port);
newctrl = gb_tty->ctrlout;
- if (on)
+ if (active)
newctrl |= (GB_UART_CTRL_DTR | GB_UART_CTRL_RTS);
else
newctrl &= ~(GB_UART_CTRL_DTR | GB_UART_CTRL_RTS);
diff --git a/drivers/staging/greybus/usb.c b/drivers/staging/greybus/usb.c
index 8e9d9d59a357..b7badf87a3f0 100644
--- a/drivers/staging/greybus/usb.c
+++ b/drivers/staging/greybus/usb.c
@@ -27,7 +27,7 @@ struct gb_usb_hub_control_request {
};
struct gb_usb_hub_control_response {
- u8 buf[0];
+ DECLARE_FLEX_ARRAY(u8, buf);
};
struct gb_usb_device {
diff --git a/drivers/staging/ks7010/ks_wlan_net.c b/drivers/staging/ks7010/ks_wlan_net.c
index 044c807ca022..e03c87f0bfe7 100644
--- a/drivers/staging/ks7010/ks_wlan_net.c
+++ b/drivers/staging/ks7010/ks_wlan_net.c
@@ -382,8 +382,7 @@ static int ks_wlan_get_nick(struct net_device *dev,
return -EPERM;
/* for SLEEP MODE */
- strncpy(extra, priv->nick, 16);
- extra[16] = '\0';
+ strscpy(extra, priv->nick, 17);
dwrq->data.length = strlen(extra) + 1;
return 0;
diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig
index 617012e09a37..bc6c7b248f86 100644
--- a/drivers/staging/media/Kconfig
+++ b/drivers/staging/media/Kconfig
@@ -22,6 +22,8 @@ if STAGING_MEDIA && MEDIA_SUPPORT
# Please keep them in alphabetic order
source "drivers/staging/media/atomisp/Kconfig"
+source "drivers/staging/media/av7110/Kconfig"
+
source "drivers/staging/media/imx/Kconfig"
source "drivers/staging/media/ipu3/Kconfig"
@@ -52,13 +54,6 @@ menuconfig STAGING_MEDIA_DEPRECATED
if STAGING_MEDIA_DEPRECATED
source "drivers/staging/media/deprecated/atmel/Kconfig"
-source "drivers/staging/media/deprecated/cpia2/Kconfig"
-source "drivers/staging/media/deprecated/fsl-viu/Kconfig"
-source "drivers/staging/media/deprecated/meye/Kconfig"
-source "drivers/staging/media/deprecated/saa7146/Kconfig"
-source "drivers/staging/media/deprecated/stkwebcam/Kconfig"
-source "drivers/staging/media/deprecated/tm6000/Kconfig"
-source "drivers/staging/media/deprecated/zr364xx/Kconfig"
endif
endif
diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile
index 1e14edc2d44c..1a4c3a062e3d 100644
--- a/drivers/staging/media/Makefile
+++ b/drivers/staging/media/Makefile
@@ -1,18 +1,12 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_VIDEO_ATMEL_ISC_BASE) += deprecated/atmel/
obj-$(CONFIG_INTEL_ATOMISP) += atomisp/
-obj-$(CONFIG_VIDEO_CPIA2) += deprecated/cpia2/
obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx/
obj-$(CONFIG_VIDEO_MAX96712) += max96712/
obj-$(CONFIG_VIDEO_MESON_VDEC) += meson/vdec/
-obj-$(CONFIG_VIDEO_MEYE) += deprecated/meye/
obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/
obj-$(CONFIG_VIDEO_ROCKCHIP_VDEC) += rkvdec/
-obj-$(CONFIG_VIDEO_STKWEBCAM) += deprecated/stkwebcam/
obj-$(CONFIG_VIDEO_SUNXI) += sunxi/
obj-$(CONFIG_VIDEO_TEGRA) += tegra-video/
obj-$(CONFIG_VIDEO_IPU3_IMGU) += ipu3/
-obj-$(CONFIG_VIDEO_TM6000) += deprecated/tm6000/
-obj-$(CONFIG_VIDEO_VIU) += deprecated/fsl-viu/
-obj-$(CONFIG_USB_ZR364XX) += deprecated/zr364xx/
-obj-y += deprecated/saa7146/
+obj-$(CONFIG_DVB_AV7110) += av7110/
diff --git a/drivers/staging/media/atomisp/Kconfig b/drivers/staging/media/atomisp/Kconfig
index 2c8d7fdcc5f7..c9bff98e5309 100644
--- a/drivers/staging/media/atomisp/Kconfig
+++ b/drivers/staging/media/atomisp/Kconfig
@@ -14,7 +14,7 @@ config VIDEO_ATOMISP
depends on VIDEO_DEV && INTEL_ATOMISP
depends on PMIC_OPREGION
select IOSF_MBI
- select VIDEOBUF_VMALLOC
+ select VIDEOBUF2_VMALLOC
select VIDEO_V4L2_SUBDEV_API
help
Say Y here if your platform supports Intel Atom SoC
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c
index 87a634bf9ff5..0d90683ed227 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c
@@ -241,179 +241,6 @@ static int gc0310_write_reg_array(struct i2c_client *client,
return __gc0310_flush_reg_array(client, &ctrl);
}
-static int gc0310_g_focal(struct v4l2_subdev *sd, s32 *val)
-{
- *val = (GC0310_FOCAL_LENGTH_NUM << 16) | GC0310_FOCAL_LENGTH_DEM;
- return 0;
-}
-
-static int gc0310_g_fnumber(struct v4l2_subdev *sd, s32 *val)
-{
- /*const f number for imx*/
- *val = (GC0310_F_NUMBER_DEFAULT_NUM << 16) | GC0310_F_NUMBER_DEM;
- return 0;
-}
-
-static int gc0310_g_fnumber_range(struct v4l2_subdev *sd, s32 *val)
-{
- *val = (GC0310_F_NUMBER_DEFAULT_NUM << 24) |
- (GC0310_F_NUMBER_DEM << 16) |
- (GC0310_F_NUMBER_DEFAULT_NUM << 8) | GC0310_F_NUMBER_DEM;
- return 0;
-}
-
-static int gc0310_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val)
-{
- struct gc0310_device *dev = to_gc0310_sensor(sd);
-
- *val = dev->res->bin_factor_x;
-
- return 0;
-}
-
-static int gc0310_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val)
-{
- struct gc0310_device *dev = to_gc0310_sensor(sd);
-
- *val = dev->res->bin_factor_y;
-
- return 0;
-}
-
-static int gc0310_get_intg_factor(struct i2c_client *client,
- struct camera_mipi_info *info,
- const struct gc0310_resolution *res)
-{
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct gc0310_device *dev = to_gc0310_sensor(sd);
- struct atomisp_sensor_mode_data *buf = &info->data;
- u16 val;
- u8 reg_val;
- int ret;
- unsigned int hori_blanking;
- unsigned int vert_blanking;
- unsigned int sh_delay;
-
- if (!info)
- return -EINVAL;
-
- /* pixel clock calculattion */
- dev->vt_pix_clk_freq_mhz = 14400000; // 16.8MHz
- buf->vt_pix_clk_freq_mhz = dev->vt_pix_clk_freq_mhz;
- dev_dbg(&client->dev, "vt_pix_clk_freq_mhz=%d\n", buf->vt_pix_clk_freq_mhz);
-
- /* get integration time */
- buf->coarse_integration_time_min = GC0310_COARSE_INTG_TIME_MIN;
- buf->coarse_integration_time_max_margin =
- GC0310_COARSE_INTG_TIME_MAX_MARGIN;
-
- buf->fine_integration_time_min = GC0310_FINE_INTG_TIME_MIN;
- buf->fine_integration_time_max_margin =
- GC0310_FINE_INTG_TIME_MAX_MARGIN;
-
- buf->fine_integration_time_def = GC0310_FINE_INTG_TIME_MIN;
- buf->read_mode = res->bin_mode;
-
- /* get the cropping and output resolution to ISP for this mode. */
- /* Getting crop_horizontal_start */
- ret = gc0310_read_reg(client, GC0310_8BIT,
- GC0310_H_CROP_START_H, &reg_val);
- if (ret)
- return ret;
- val = (reg_val & 0xFF) << 8;
- ret = gc0310_read_reg(client, GC0310_8BIT,
- GC0310_H_CROP_START_L, &reg_val);
- if (ret)
- return ret;
- buf->crop_horizontal_start = val | (reg_val & 0xFF);
- dev_dbg(&client->dev, "crop_horizontal_start=%d\n", buf->crop_horizontal_start);
-
- /* Getting crop_vertical_start */
- ret = gc0310_read_reg(client, GC0310_8BIT,
- GC0310_V_CROP_START_H, &reg_val);
- if (ret)
- return ret;
- val = (reg_val & 0xFF) << 8;
- ret = gc0310_read_reg(client, GC0310_8BIT,
- GC0310_V_CROP_START_L, &reg_val);
- if (ret)
- return ret;
- buf->crop_vertical_start = val | (reg_val & 0xFF);
- dev_dbg(&client->dev, "crop_vertical_start=%d\n", buf->crop_vertical_start);
-
- /* Getting output_width */
- ret = gc0310_read_reg(client, GC0310_8BIT,
- GC0310_H_OUTSIZE_H, &reg_val);
- if (ret)
- return ret;
- val = (reg_val & 0xFF) << 8;
- ret = gc0310_read_reg(client, GC0310_8BIT,
- GC0310_H_OUTSIZE_L, &reg_val);
- if (ret)
- return ret;
- buf->output_width = val | (reg_val & 0xFF);
- dev_dbg(&client->dev, "output_width=%d\n", buf->output_width);
-
- /* Getting output_height */
- ret = gc0310_read_reg(client, GC0310_8BIT,
- GC0310_V_OUTSIZE_H, &reg_val);
- if (ret)
- return ret;
- val = (reg_val & 0xFF) << 8;
- ret = gc0310_read_reg(client, GC0310_8BIT,
- GC0310_V_OUTSIZE_L, &reg_val);
- if (ret)
- return ret;
- buf->output_height = val | (reg_val & 0xFF);
- dev_dbg(&client->dev, "output_height=%d\n", buf->output_height);
-
- buf->crop_horizontal_end = buf->crop_horizontal_start + buf->output_width - 1;
- buf->crop_vertical_end = buf->crop_vertical_start + buf->output_height - 1;
- dev_dbg(&client->dev, "crop_horizontal_end=%d\n", buf->crop_horizontal_end);
- dev_dbg(&client->dev, "crop_vertical_end=%d\n", buf->crop_vertical_end);
-
- /* Getting line_length_pck */
- ret = gc0310_read_reg(client, GC0310_8BIT,
- GC0310_H_BLANKING_H, &reg_val);
- if (ret)
- return ret;
- val = (reg_val & 0xFF) << 8;
- ret = gc0310_read_reg(client, GC0310_8BIT,
- GC0310_H_BLANKING_L, &reg_val);
- if (ret)
- return ret;
- hori_blanking = val | (reg_val & 0xFF);
- ret = gc0310_read_reg(client, GC0310_8BIT,
- GC0310_SH_DELAY, &reg_val);
- if (ret)
- return ret;
- sh_delay = reg_val;
- buf->line_length_pck = buf->output_width + hori_blanking + sh_delay + 4;
- dev_dbg(&client->dev, "hori_blanking=%d sh_delay=%d line_length_pck=%d\n", hori_blanking,
- sh_delay, buf->line_length_pck);
-
- /* Getting frame_length_lines */
- ret = gc0310_read_reg(client, GC0310_8BIT,
- GC0310_V_BLANKING_H, &reg_val);
- if (ret)
- return ret;
- val = (reg_val & 0xFF) << 8;
- ret = gc0310_read_reg(client, GC0310_8BIT,
- GC0310_V_BLANKING_L, &reg_val);
- if (ret)
- return ret;
- vert_blanking = val | (reg_val & 0xFF);
- buf->frame_length_lines = buf->output_height + vert_blanking;
- dev_dbg(&client->dev, "vert_blanking=%d frame_length_lines=%d\n", vert_blanking,
- buf->frame_length_lines);
-
- buf->binning_factor_x = res->bin_factor_x ?
- res->bin_factor_x : 1;
- buf->binning_factor_y = res->bin_factor_y ?
- res->bin_factor_y : 1;
- return 0;
-}
-
static int gc0310_set_gain(struct v4l2_subdev *sd, int gain)
{
@@ -596,21 +423,6 @@ static int gc0310_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_EXPOSURE_ABSOLUTE:
ret = gc0310_q_exposure(&dev->sd, &ctrl->val);
break;
- case V4L2_CID_FOCAL_ABSOLUTE:
- ret = gc0310_g_focal(&dev->sd, &ctrl->val);
- break;
- case V4L2_CID_FNUMBER_ABSOLUTE:
- ret = gc0310_g_fnumber(&dev->sd, &ctrl->val);
- break;
- case V4L2_CID_FNUMBER_RANGE:
- ret = gc0310_g_fnumber_range(&dev->sd, &ctrl->val);
- break;
- case V4L2_CID_BIN_FACTOR_HORZ:
- ret = gc0310_g_bin_factor_x(&dev->sd, &ctrl->val);
- break;
- case V4L2_CID_BIN_FACTOR_VERT:
- ret = gc0310_g_bin_factor_y(&dev->sd, &ctrl->val);
- break;
default:
ret = -EINVAL;
}
@@ -655,61 +467,6 @@ static const struct v4l2_ctrl_config gc0310_controls[] = {
.step = 1,
.def = 0,
},
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_FOCAL_ABSOLUTE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "focal length",
- .min = GC0310_FOCAL_LENGTH_DEFAULT,
- .max = GC0310_FOCAL_LENGTH_DEFAULT,
- .step = 0x01,
- .def = GC0310_FOCAL_LENGTH_DEFAULT,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_FNUMBER_ABSOLUTE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "f-number",
- .min = GC0310_F_NUMBER_DEFAULT,
- .max = GC0310_F_NUMBER_DEFAULT,
- .step = 0x01,
- .def = GC0310_F_NUMBER_DEFAULT,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_FNUMBER_RANGE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "f-number range",
- .min = GC0310_F_NUMBER_RANGE,
- .max = GC0310_F_NUMBER_RANGE,
- .step = 0x01,
- .def = GC0310_F_NUMBER_RANGE,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_BIN_FACTOR_HORZ,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "horizontal binning factor",
- .min = 0,
- .max = GC0310_BIN_FACTOR_MAX,
- .step = 1,
- .def = 0,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_BIN_FACTOR_VERT,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "vertical binning factor",
- .min = 0,
- .max = GC0310_BIN_FACTOR_MAX,
- .step = 1,
- .def = 0,
- .flags = 0,
- },
};
static int gc0310_init(struct v4l2_subdev *sd)
@@ -952,12 +709,6 @@ static int gc0310_set_fmt(struct v4l2_subdev *sd,
goto err;
}
- ret = gc0310_get_intg_factor(client, gc0310_info, dev->res);
- if (ret) {
- dev_err(&client->dev, "failed to get integration_factor\n");
- goto err;
- }
-
err:
mutex_unlock(&dev->input_lock);
return ret;
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c
index 4d5a7e335f85..cb4c79b483ca 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c
@@ -220,135 +220,6 @@ static int gc2235_write_reg_array(struct i2c_client *client,
return __gc2235_flush_reg_array(client, &ctrl);
}
-static int gc2235_g_focal(struct v4l2_subdev *sd, s32 *val)
-{
- *val = (GC2235_FOCAL_LENGTH_NUM << 16) | GC2235_FOCAL_LENGTH_DEM;
- return 0;
-}
-
-static int gc2235_g_fnumber(struct v4l2_subdev *sd, s32 *val)
-{
- /* const f number for imx */
- *val = (GC2235_F_NUMBER_DEFAULT_NUM << 16) | GC2235_F_NUMBER_DEM;
- return 0;
-}
-
-static int gc2235_g_fnumber_range(struct v4l2_subdev *sd, s32 *val)
-{
- *val = (GC2235_F_NUMBER_DEFAULT_NUM << 24) |
- (GC2235_F_NUMBER_DEM << 16) |
- (GC2235_F_NUMBER_DEFAULT_NUM << 8) | GC2235_F_NUMBER_DEM;
- return 0;
-}
-
-static int gc2235_get_intg_factor(struct i2c_client *client,
- struct camera_mipi_info *info,
- const struct gc2235_resolution *res)
-{
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct gc2235_device *dev = to_gc2235_sensor(sd);
- struct atomisp_sensor_mode_data *buf = &info->data;
- u16 reg_val, reg_val_h;
- int ret;
-
- if (!info)
- return -EINVAL;
-
- /* pixel clock calculattion */
- buf->vt_pix_clk_freq_mhz = dev->vt_pix_clk_freq_mhz = 30000000;
-
- /* get integration time */
- buf->coarse_integration_time_min = GC2235_COARSE_INTG_TIME_MIN;
- buf->coarse_integration_time_max_margin =
- GC2235_COARSE_INTG_TIME_MAX_MARGIN;
-
- buf->fine_integration_time_min = GC2235_FINE_INTG_TIME_MIN;
- buf->fine_integration_time_max_margin =
- GC2235_FINE_INTG_TIME_MAX_MARGIN;
-
- buf->fine_integration_time_def = GC2235_FINE_INTG_TIME_MIN;
- buf->frame_length_lines = res->lines_per_frame;
- buf->line_length_pck = res->pixels_per_line;
- buf->read_mode = res->bin_mode;
-
- /* get the cropping and output resolution to ISP for this mode. */
- ret = gc2235_read_reg(client, GC2235_8BIT,
- GC2235_H_CROP_START_H, &reg_val_h);
- ret = gc2235_read_reg(client, GC2235_8BIT,
- GC2235_H_CROP_START_L, &reg_val);
- if (ret)
- return ret;
-
- buf->crop_horizontal_start = (reg_val_h << 8) | reg_val;
-
- ret = gc2235_read_reg(client, GC2235_8BIT,
- GC2235_V_CROP_START_H, &reg_val_h);
- ret = gc2235_read_reg(client, GC2235_8BIT,
- GC2235_V_CROP_START_L, &reg_val);
- if (ret)
- return ret;
-
- buf->crop_vertical_start = (reg_val_h << 8) | reg_val;
-
- ret = gc2235_read_reg(client, GC2235_8BIT,
- GC2235_H_OUTSIZE_H, &reg_val_h);
- ret = gc2235_read_reg(client, GC2235_8BIT,
- GC2235_H_OUTSIZE_L, &reg_val);
- if (ret)
- return ret;
- buf->output_width = (reg_val_h << 8) | reg_val;
-
- ret = gc2235_read_reg(client, GC2235_8BIT,
- GC2235_V_OUTSIZE_H, &reg_val_h);
- ret = gc2235_read_reg(client, GC2235_8BIT,
- GC2235_V_OUTSIZE_L, &reg_val);
- if (ret)
- return ret;
- buf->output_height = (reg_val_h << 8) | reg_val;
-
- buf->crop_horizontal_end = buf->crop_horizontal_start +
- buf->output_width - 1;
- buf->crop_vertical_end = buf->crop_vertical_start +
- buf->output_height - 1;
-
- ret = gc2235_read_reg(client, GC2235_8BIT,
- GC2235_HB_H, &reg_val_h);
- ret = gc2235_read_reg(client, GC2235_8BIT,
- GC2235_HB_L, &reg_val);
- if (ret)
- return ret;
-
-#if 0
- u16 dummy = (reg_val_h << 8) | reg_val;
-#endif
-
- ret = gc2235_read_reg(client, GC2235_8BIT,
- GC2235_SH_DELAY_H, &reg_val_h);
- ret = gc2235_read_reg(client, GC2235_8BIT,
- GC2235_SH_DELAY_L, &reg_val);
-
-#if 0
- buf->line_length_pck = buf->output_width + 16 + dummy +
- (((u16)reg_val_h << 8) | (u16)reg_val) + 4;
-#endif
- ret = gc2235_read_reg(client, GC2235_8BIT,
- GC2235_VB_H, &reg_val_h);
- ret = gc2235_read_reg(client, GC2235_8BIT,
- GC2235_VB_L, &reg_val);
- if (ret)
- return ret;
-
-#if 0
- buf->frame_length_lines = buf->output_height + 32 +
- (((u16)reg_val_h << 8) | (u16)reg_val);
-#endif
- buf->binning_factor_x = res->bin_factor_x ?
- res->bin_factor_x : 1;
- buf->binning_factor_y = res->bin_factor_y ?
- res->bin_factor_y : 1;
- return 0;
-}
-
static long __gc2235_set_exposure(struct v4l2_subdev *sd, int coarse_itg,
int gain, int digitgain)
@@ -467,15 +338,6 @@ static int gc2235_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_EXPOSURE_ABSOLUTE:
ret = gc2235_q_exposure(&dev->sd, &ctrl->val);
break;
- case V4L2_CID_FOCAL_ABSOLUTE:
- ret = gc2235_g_focal(&dev->sd, &ctrl->val);
- break;
- case V4L2_CID_FNUMBER_ABSOLUTE:
- ret = gc2235_g_fnumber(&dev->sd, &ctrl->val);
- break;
- case V4L2_CID_FNUMBER_RANGE:
- ret = gc2235_g_fnumber_range(&dev->sd, &ctrl->val);
- break;
default:
ret = -EINVAL;
}
@@ -499,39 +361,6 @@ static struct v4l2_ctrl_config gc2235_controls[] = {
.def = 0x00,
.flags = 0,
},
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_FOCAL_ABSOLUTE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "focal length",
- .min = GC2235_FOCAL_LENGTH_DEFAULT,
- .max = GC2235_FOCAL_LENGTH_DEFAULT,
- .step = 0x01,
- .def = GC2235_FOCAL_LENGTH_DEFAULT,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_FNUMBER_ABSOLUTE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "f-number",
- .min = GC2235_F_NUMBER_DEFAULT,
- .max = GC2235_F_NUMBER_DEFAULT,
- .step = 0x01,
- .def = GC2235_F_NUMBER_DEFAULT,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_FNUMBER_RANGE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "f-number range",
- .min = GC2235_F_NUMBER_RANGE,
- .max = GC2235_F_NUMBER_RANGE,
- .step = 0x01,
- .def = GC2235_F_NUMBER_RANGE,
- .flags = 0,
- },
};
static int __gc2235_init(struct v4l2_subdev *sd)
@@ -743,11 +572,6 @@ static int gc2235_set_fmt(struct v4l2_subdev *sd,
goto err;
}
- ret = gc2235_get_intg_factor(client, gc2235_info,
- dev->res);
- if (ret)
- dev_err(&client->dev, "failed to get integration_factor\n");
-
err:
mutex_unlock(&dev->input_lock);
return ret;
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c
index a0e8e94b2412..0e5a981dd331 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c
@@ -612,96 +612,6 @@ static int mt9m114_res2size(struct v4l2_subdev *sd, int *h_size, int *v_size)
return 0;
}
-static int mt9m114_get_intg_factor(struct i2c_client *client,
- struct camera_mipi_info *info,
- const struct mt9m114_res_struct *res)
-{
- struct atomisp_sensor_mode_data *buf;
- u32 reg_val;
- int ret;
-
- if (!info)
- return -EINVAL;
-
- buf = &info->data;
-
- ret = mt9m114_read_reg(client, MISENSOR_32BIT,
- REG_PIXEL_CLK, &reg_val);
- if (ret)
- return ret;
- buf->vt_pix_clk_freq_mhz = reg_val;
-
- /* get integration time */
- buf->coarse_integration_time_min = MT9M114_COARSE_INTG_TIME_MIN;
- buf->coarse_integration_time_max_margin =
- MT9M114_COARSE_INTG_TIME_MAX_MARGIN;
-
- buf->fine_integration_time_min = MT9M114_FINE_INTG_TIME_MIN;
- buf->fine_integration_time_max_margin =
- MT9M114_FINE_INTG_TIME_MAX_MARGIN;
-
- buf->fine_integration_time_def = MT9M114_FINE_INTG_TIME_MIN;
-
- buf->frame_length_lines = res->lines_per_frame;
- buf->line_length_pck = res->pixels_per_line;
- buf->read_mode = res->bin_mode;
-
- /* get the cropping and output resolution to ISP for this mode. */
- ret = mt9m114_read_reg(client, MISENSOR_16BIT,
- REG_H_START, &reg_val);
- if (ret)
- return ret;
- buf->crop_horizontal_start = reg_val;
-
- ret = mt9m114_read_reg(client, MISENSOR_16BIT,
- REG_V_START, &reg_val);
- if (ret)
- return ret;
- buf->crop_vertical_start = reg_val;
-
- ret = mt9m114_read_reg(client, MISENSOR_16BIT,
- REG_H_END, &reg_val);
- if (ret)
- return ret;
- buf->crop_horizontal_end = reg_val;
-
- ret = mt9m114_read_reg(client, MISENSOR_16BIT,
- REG_V_END, &reg_val);
- if (ret)
- return ret;
- buf->crop_vertical_end = reg_val;
-
- ret = mt9m114_read_reg(client, MISENSOR_16BIT,
- REG_WIDTH, &reg_val);
- if (ret)
- return ret;
- buf->output_width = reg_val;
-
- ret = mt9m114_read_reg(client, MISENSOR_16BIT,
- REG_HEIGHT, &reg_val);
- if (ret)
- return ret;
- buf->output_height = reg_val;
-
- ret = mt9m114_read_reg(client, MISENSOR_16BIT,
- REG_TIMING_HTS, &reg_val);
- if (ret)
- return ret;
- buf->line_length_pck = reg_val;
-
- ret = mt9m114_read_reg(client, MISENSOR_16BIT,
- REG_TIMING_VTS, &reg_val);
- if (ret)
- return ret;
- buf->frame_length_lines = reg_val;
-
- buf->binning_factor_x = res->bin_factor_x ?
- res->bin_factor_x : 1;
- buf->binning_factor_y = res->bin_factor_y ?
- res->bin_factor_y : 1;
- return 0;
-}
-
static int mt9m114_get_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
@@ -823,12 +733,6 @@ static int mt9m114_set_fmt(struct v4l2_subdev *sd,
mt9m114_res[index].used = false;
}
}
- ret = mt9m114_get_intg_factor(c, mt9m114_info,
- &mt9m114_res[res->res]);
- if (ret) {
- dev_err(&c->dev, "failed to get integration_factor\n");
- return -EINVAL;
- }
/*
* mt9m114 - we don't poll for context switch
* because it does not happen with streaming disabled.
@@ -841,28 +745,6 @@ static int mt9m114_set_fmt(struct v4l2_subdev *sd,
return 0;
}
-/* TODO: Update to SOC functions, remove exposure and gain */
-static int mt9m114_g_focal(struct v4l2_subdev *sd, s32 *val)
-{
- *val = (MT9M114_FOCAL_LENGTH_NUM << 16) | MT9M114_FOCAL_LENGTH_DEM;
- return 0;
-}
-
-static int mt9m114_g_fnumber(struct v4l2_subdev *sd, s32 *val)
-{
- /* const f number for mt9m114 */
- *val = (MT9M114_F_NUMBER_DEFAULT_NUM << 16) | MT9M114_F_NUMBER_DEM;
- return 0;
-}
-
-static int mt9m114_g_fnumber_range(struct v4l2_subdev *sd, s32 *val)
-{
- *val = (MT9M114_F_NUMBER_DEFAULT_NUM << 24) |
- (MT9M114_F_NUMBER_DEM << 16) |
- (MT9M114_F_NUMBER_DEFAULT_NUM << 8) | MT9M114_F_NUMBER_DEM;
- return 0;
-}
-
/* Horizontal flip the image. */
static int mt9m114_g_hflip(struct v4l2_subdev *sd, s32 *val)
{
@@ -1134,24 +1016,6 @@ static int mt9m114_s_exposure_selection(struct v4l2_subdev *sd,
return 0;
}
-static int mt9m114_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val)
-{
- struct mt9m114_device *dev = to_mt9m114_sensor(sd);
-
- *val = mt9m114_res[dev->res].bin_factor_x;
-
- return 0;
-}
-
-static int mt9m114_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val)
-{
- struct mt9m114_device *dev = to_mt9m114_sensor(sd);
-
- *val = mt9m114_res[dev->res].bin_factor_y;
-
- return 0;
-}
-
static int mt9m114_s_ev(struct v4l2_subdev *sd, s32 val)
{
struct i2c_client *c = v4l2_get_subdevdata(sd);
@@ -1271,27 +1135,12 @@ static int mt9m114_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_HFLIP:
ret = mt9m114_g_hflip(&dev->sd, &ctrl->val);
break;
- case V4L2_CID_FOCAL_ABSOLUTE:
- ret = mt9m114_g_focal(&dev->sd, &ctrl->val);
- break;
- case V4L2_CID_FNUMBER_ABSOLUTE:
- ret = mt9m114_g_fnumber(&dev->sd, &ctrl->val);
- break;
- case V4L2_CID_FNUMBER_RANGE:
- ret = mt9m114_g_fnumber_range(&dev->sd, &ctrl->val);
- break;
case V4L2_CID_EXPOSURE_ABSOLUTE:
ret = mt9m114_g_exposure(&dev->sd, &ctrl->val);
break;
case V4L2_CID_EXPOSURE_ZONE_NUM:
ret = mt9m114_g_exposure_zone_num(&dev->sd, &ctrl->val);
break;
- case V4L2_CID_BIN_FACTOR_HORZ:
- ret = mt9m114_g_bin_factor_x(&dev->sd, &ctrl->val);
- break;
- case V4L2_CID_BIN_FACTOR_VERT:
- ret = mt9m114_g_bin_factor_y(&dev->sd, &ctrl->val);
- break;
case V4L2_CID_EXPOSURE:
ret = mt9m114_g_ev(&dev->sd, &ctrl->val);
break;
@@ -1333,39 +1182,6 @@ static struct v4l2_ctrl_config mt9m114_controls[] = {
},
{
.ops = &ctrl_ops,
- .id = V4L2_CID_FOCAL_ABSOLUTE,
- .name = "focal length",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .min = MT9M114_FOCAL_LENGTH_DEFAULT,
- .max = MT9M114_FOCAL_LENGTH_DEFAULT,
- .step = 1,
- .def = MT9M114_FOCAL_LENGTH_DEFAULT,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_FNUMBER_ABSOLUTE,
- .name = "f-number",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .min = MT9M114_F_NUMBER_DEFAULT,
- .max = MT9M114_F_NUMBER_DEFAULT,
- .step = 1,
- .def = MT9M114_F_NUMBER_DEFAULT,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_FNUMBER_RANGE,
- .name = "f-number range",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .min = MT9M114_F_NUMBER_RANGE,
- .max = MT9M114_F_NUMBER_RANGE,
- .step = 1,
- .def = MT9M114_F_NUMBER_RANGE,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
.id = V4L2_CID_EXPOSURE_ABSOLUTE,
.name = "exposure",
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -1399,28 +1215,6 @@ static struct v4l2_ctrl_config mt9m114_controls[] = {
},
{
.ops = &ctrl_ops,
- .id = V4L2_CID_BIN_FACTOR_HORZ,
- .name = "horizontal binning factor",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .min = 0,
- .max = MT9M114_BIN_FACTOR_MAX,
- .step = 1,
- .def = 0,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_BIN_FACTOR_VERT,
- .name = "vertical binning factor",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .min = 0,
- .max = MT9M114_BIN_FACTOR_MAX,
- .step = 1,
- .def = 0,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
.id = V4L2_CID_EXPOSURE,
.name = "exposure biasx",
.type = V4L2_CTRL_TYPE_INTEGER,
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c
index fa1de45b7a2d..aeb38599fe13 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c
@@ -15,30 +15,22 @@
*
*/
-#include <asm/unaligned.h>
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/kmod.h>
+#include <linux/acpi.h>
#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/machine.h>
#include <linux/i2c.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/types.h>
+
+#include <media/ov_16bit_addr_reg_helpers.h>
#include <media/v4l2-device.h>
-#include <linux/io.h>
-#include <linux/acpi.h>
+
#include "../include/linux/atomisp_gmin_platform.h"
#include "ov2680.h"
-static int h_flag;
-static int v_flag;
static enum atomisp_bayer_order ov2680_bayer_order_mapping[] = {
atomisp_bayer_order_bggr,
atomisp_bayer_order_grbg,
@@ -46,64 +38,6 @@ static enum atomisp_bayer_order ov2680_bayer_order_mapping[] = {
atomisp_bayer_order_rggb,
};
-/* i2c read/write stuff */
-static int ov2680_read_reg(struct i2c_client *client,
- int len, u16 reg, u32 *val)
-{
- struct i2c_msg msgs[2];
- u8 addr_buf[2] = { reg >> 8, reg & 0xff };
- u8 data_buf[4] = { 0, };
- int ret;
-
- if (len > 4)
- return -EINVAL;
-
- msgs[0].addr = client->addr;
- msgs[0].flags = 0;
- msgs[0].len = ARRAY_SIZE(addr_buf);
- msgs[0].buf = addr_buf;
-
- msgs[1].addr = client->addr;
- msgs[1].flags = I2C_M_RD;
- msgs[1].len = len;
- msgs[1].buf = &data_buf[4 - len];
-
- ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
- if (ret != ARRAY_SIZE(msgs)) {
- dev_err(&client->dev, "read error: reg=0x%4x: %d\n", reg, ret);
- return -EIO;
- }
-
- *val = get_unaligned_be32(data_buf);
-
- return 0;
-}
-
-static int ov2680_write_reg(struct i2c_client *client, unsigned int len,
- u16 reg, u16 val)
-{
- u8 buf[6];
- int ret;
-
- if (len == 2)
- put_unaligned_be16(val, buf + 2);
- else if (len == 1)
- buf[2] = val;
- else
- return -EINVAL;
-
- put_unaligned_be16(reg, buf);
-
- ret = i2c_master_send(client, buf, len + 2);
- if (ret != len + 2) {
- dev_err(&client->dev, "write error %d reg 0x%04x, val 0x%02x: buf sent: %*ph\n",
- ret, reg, val, len + 2, &buf);
- return -EIO;
- }
-
- return 0;
-}
-
static int ov2680_write_reg_array(struct i2c_client *client,
const struct ov2680_reg *reglist)
{
@@ -111,7 +45,7 @@ static int ov2680_write_reg_array(struct i2c_client *client,
int ret;
for (; next->reg != 0; next++) {
- ret = ov2680_write_reg(client, 1, next->reg, next->val);
+ ret = ov_write_reg8(client, next->reg, next->val);
if (ret)
return ret;
}
@@ -119,518 +53,127 @@ static int ov2680_write_reg_array(struct i2c_client *client,
return 0;
}
-static int ov2680_g_focal(struct v4l2_subdev *sd, s32 *val)
-{
- *val = (OV2680_FOCAL_LENGTH_NUM << 16) | OV2680_FOCAL_LENGTH_DEM;
- return 0;
-}
-
-static int ov2680_g_fnumber(struct v4l2_subdev *sd, s32 *val)
+static void ov2680_set_bayer_order(struct ov2680_device *sensor, struct v4l2_mbus_framefmt *fmt)
{
- /* const f number for ov2680 */
-
- *val = (OV2680_F_NUMBER_DEFAULT_NUM << 16) | OV2680_F_NUMBER_DEM;
- return 0;
-}
+ static const int ov2680_hv_flip_bayer_order[] = {
+ MEDIA_BUS_FMT_SBGGR10_1X10,
+ MEDIA_BUS_FMT_SGRBG10_1X10,
+ MEDIA_BUS_FMT_SGBRG10_1X10,
+ MEDIA_BUS_FMT_SRGGB10_1X10,
+ };
+ struct camera_mipi_info *ov2680_info;
+ int hv_flip = 0;
-static int ov2680_g_fnumber_range(struct v4l2_subdev *sd, s32 *val)
-{
- *val = (OV2680_F_NUMBER_DEFAULT_NUM << 24) |
- (OV2680_F_NUMBER_DEM << 16) |
- (OV2680_F_NUMBER_DEFAULT_NUM << 8) | OV2680_F_NUMBER_DEM;
- return 0;
-}
+ if (sensor->ctrls.vflip->val)
+ hv_flip += 1;
-static int ov2680_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val)
-{
- struct ov2680_device *dev = to_ov2680_sensor(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
+ if (sensor->ctrls.hflip->val)
+ hv_flip += 2;
- dev_dbg(&client->dev, "++++ov2680_g_bin_factor_x\n");
- *val = dev->res->bin_factor_x;
+ fmt->code = ov2680_hv_flip_bayer_order[hv_flip];
- return 0;
+ /* TODO atomisp specific custom API, should be removed */
+ ov2680_info = v4l2_get_subdev_hostdata(&sensor->sd);
+ if (ov2680_info)
+ ov2680_info->raw_bayer_order = ov2680_bayer_order_mapping[hv_flip];
}
-static int ov2680_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val)
+static int ov2680_set_vflip(struct ov2680_device *sensor, s32 val)
{
- struct ov2680_device *dev = to_ov2680_sensor(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- *val = dev->res->bin_factor_y;
- dev_dbg(&client->dev, "++++ov2680_g_bin_factor_y\n");
- return 0;
-}
-
-static int ov2680_get_intg_factor(struct i2c_client *client,
- struct camera_mipi_info *info,
- const struct ov2680_resolution *res)
-{
- struct atomisp_sensor_mode_data *buf = &info->data;
- unsigned int pix_clk_freq_hz;
- u32 reg_val;
int ret;
- dev_dbg(&client->dev, "++++ov2680_get_intg_factor\n");
- if (!info)
- return -EINVAL;
-
- /* pixel clock */
- pix_clk_freq_hz = res->pix_clk_freq * 1000000;
-
- buf->vt_pix_clk_freq_mhz = pix_clk_freq_hz;
-
- /* get integration time */
- buf->coarse_integration_time_min = OV2680_COARSE_INTG_TIME_MIN;
- buf->coarse_integration_time_max_margin =
- OV2680_COARSE_INTG_TIME_MAX_MARGIN;
-
- buf->fine_integration_time_min = OV2680_FINE_INTG_TIME_MIN;
- buf->fine_integration_time_max_margin =
- OV2680_FINE_INTG_TIME_MAX_MARGIN;
-
- buf->fine_integration_time_def = OV2680_FINE_INTG_TIME_MIN;
- buf->frame_length_lines = res->lines_per_frame;
- buf->line_length_pck = res->pixels_per_line;
- buf->read_mode = res->bin_mode;
-
- /* get the cropping and output resolution to ISP for this mode. */
- ret = ov2680_read_reg(client, 2,
- OV2680_HORIZONTAL_START_H, &reg_val);
- if (ret)
- return ret;
- buf->crop_horizontal_start = reg_val;
-
- ret = ov2680_read_reg(client, 2,
- OV2680_VERTICAL_START_H, &reg_val);
- if (ret)
- return ret;
- buf->crop_vertical_start = reg_val;
-
- ret = ov2680_read_reg(client, 2,
- OV2680_HORIZONTAL_END_H, &reg_val);
- if (ret)
- return ret;
- buf->crop_horizontal_end = reg_val;
-
- ret = ov2680_read_reg(client, 2,
- OV2680_VERTICAL_END_H, &reg_val);
- if (ret)
- return ret;
- buf->crop_vertical_end = reg_val;
+ if (sensor->is_streaming)
+ return -EBUSY;
- ret = ov2680_read_reg(client, 2,
- OV2680_HORIZONTAL_OUTPUT_SIZE_H, &reg_val);
- if (ret)
+ ret = ov_update_reg(sensor->client, OV2680_REG_FORMAT1, BIT(2), val ? BIT(2) : 0);
+ if (ret < 0)
return ret;
- buf->output_width = reg_val;
- ret = ov2680_read_reg(client, 2,
- OV2680_VERTICAL_OUTPUT_SIZE_H, &reg_val);
- if (ret)
- return ret;
- buf->output_height = reg_val;
-
- buf->binning_factor_x = res->bin_factor_x ?
- (res->bin_factor_x * 2) : 1;
- buf->binning_factor_y = res->bin_factor_y ?
- (res->bin_factor_y * 2) : 1;
+ ov2680_set_bayer_order(sensor, &sensor->mode.fmt);
return 0;
}
-static long __ov2680_set_exposure(struct v4l2_subdev *sd, int coarse_itg,
- int gain, int digitgain)
-
+static int ov2680_set_hflip(struct ov2680_device *sensor, s32 val)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov2680_device *dev = to_ov2680_sensor(sd);
- u16 vts;
- int ret, exp_val;
-
- dev_dbg(&client->dev,
- "+++++++__ov2680_set_exposure coarse_itg %d, gain %d, digitgain %d++\n",
- coarse_itg, gain, digitgain);
-
- vts = dev->res->lines_per_frame;
-
- /* group hold */
- ret = ov2680_write_reg(client, 1,
- OV2680_GROUP_ACCESS, 0x00);
- if (ret) {
- dev_err(&client->dev, "%s: write 0x%02x: error, aborted\n",
- __func__, OV2680_GROUP_ACCESS);
- return ret;
- }
-
- /* Increase the VTS to match exposure + MARGIN */
- if (coarse_itg > vts - OV2680_INTEGRATION_TIME_MARGIN)
- vts = (u16)coarse_itg + OV2680_INTEGRATION_TIME_MARGIN;
-
- ret = ov2680_write_reg(client, 2, OV2680_TIMING_VTS_H, vts);
- if (ret) {
- dev_err(&client->dev, "%s: write 0x%02x: error, aborted\n",
- __func__, OV2680_TIMING_VTS_H);
- return ret;
- }
-
- /* set exposure */
-
- /* Lower four bit should be 0*/
- exp_val = coarse_itg << 4;
- ret = ov2680_write_reg(client, 1,
- OV2680_EXPOSURE_L, exp_val & 0xFF);
- if (ret) {
- dev_err(&client->dev, "%s: write 0x%02x: error, aborted\n",
- __func__, OV2680_EXPOSURE_L);
- return ret;
- }
-
- ret = ov2680_write_reg(client, 1,
- OV2680_EXPOSURE_M, (exp_val >> 8) & 0xFF);
- if (ret) {
- dev_err(&client->dev, "%s: write 0x%02x: error, aborted\n",
- __func__, OV2680_EXPOSURE_M);
- return ret;
- }
-
- ret = ov2680_write_reg(client, 1,
- OV2680_EXPOSURE_H, (exp_val >> 16) & 0x0F);
- if (ret) {
- dev_err(&client->dev, "%s: write 0x%02x: error, aborted\n",
- __func__, OV2680_EXPOSURE_H);
- return ret;
- }
-
- /* Analog gain */
- ret = ov2680_write_reg(client, 2, OV2680_AGC_H, gain);
- if (ret) {
- dev_err(&client->dev, "%s: write 0x%02x: error, aborted\n",
- __func__, OV2680_AGC_H);
- return ret;
- }
- /* Digital gain */
- if (digitgain) {
- ret = ov2680_write_reg(client, 2,
- OV2680_MWB_RED_GAIN_H, digitgain);
- if (ret) {
- dev_err(&client->dev,
- "%s: write 0x%02x: error, aborted\n",
- __func__, OV2680_MWB_RED_GAIN_H);
- return ret;
- }
-
- ret = ov2680_write_reg(client, 2,
- OV2680_MWB_GREEN_GAIN_H, digitgain);
- if (ret) {
- dev_err(&client->dev,
- "%s: write 0x%02x: error, aborted\n",
- __func__, OV2680_MWB_RED_GAIN_H);
- return ret;
- }
-
- ret = ov2680_write_reg(client, 2,
- OV2680_MWB_BLUE_GAIN_H, digitgain);
- if (ret) {
- dev_err(&client->dev,
- "%s: write 0x%02x: error, aborted\n",
- __func__, OV2680_MWB_RED_GAIN_H);
- return ret;
- }
- }
+ int ret;
- /* End group */
- ret = ov2680_write_reg(client, 1,
- OV2680_GROUP_ACCESS, 0x10);
- if (ret)
- return ret;
+ if (sensor->is_streaming)
+ return -EBUSY;
- /* Delay launch group */
- ret = ov2680_write_reg(client, 1,
- OV2680_GROUP_ACCESS, 0xa0);
- if (ret)
+ ret = ov_update_reg(sensor->client, OV2680_REG_FORMAT2, BIT(2), val ? BIT(2) : 0);
+ if (ret < 0)
return ret;
- return ret;
-}
-
-static int ov2680_set_exposure(struct v4l2_subdev *sd, int exposure,
- int gain, int digitgain)
-{
- struct ov2680_device *dev = to_ov2680_sensor(sd);
- int ret = 0;
-
- mutex_lock(&dev->input_lock);
-
- dev->exposure = exposure;
- dev->gain = gain;
- dev->digitgain = digitgain;
- if (dev->power_on)
- ret = __ov2680_set_exposure(sd, exposure, gain, digitgain);
-
- mutex_unlock(&dev->input_lock);
-
- return ret;
+ ov2680_set_bayer_order(sensor, &sensor->mode.fmt);
+ return 0;
}
-static long ov2680_s_exposure(struct v4l2_subdev *sd,
- struct atomisp_exposure *exposure)
+static int ov2680_exposure_set(struct ov2680_device *sensor, u32 exp)
{
- u16 coarse_itg = exposure->integration_time[0];
- u16 analog_gain = exposure->gain[0];
- u16 digital_gain = exposure->gain[1];
-
- /* we should not accept the invalid value below */
- if (analog_gain == 0) {
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- v4l2_err(client, "%s: invalid value\n", __func__);
- return -EINVAL;
- }
-
- return ov2680_set_exposure(sd, coarse_itg, analog_gain, digital_gain);
+ return ov_write_reg24(sensor->client, OV2680_REG_EXPOSURE_PK_HIGH, exp << 4);
}
-static long ov2680_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+static int ov2680_gain_set(struct ov2680_device *sensor, u32 gain)
{
- switch (cmd) {
- case ATOMISP_IOC_S_EXPOSURE:
- return ov2680_s_exposure(sd, arg);
-
- default:
- return -EINVAL;
- }
- return 0;
+ return ov_write_reg16(sensor->client, OV2680_REG_GAIN_PK, gain);
}
-/*
- * This returns the exposure time being used. This should only be used
- * for filling in EXIF data, not for actual image processing.
- */
-static int ov2680_q_exposure(struct v4l2_subdev *sd, s32 *value)
+static int ov2680_test_pattern_set(struct ov2680_device *sensor, int value)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- u32 reg_val;
int ret;
- /* get exposure */
- ret = ov2680_read_reg(client, 3, OV2680_EXPOSURE_H, &reg_val);
- if (ret)
- return ret;
-
- /* Lower four bits are not part of the exposure val (always 0) */
- *value = reg_val >> 4;
- return 0;
-}
+ if (!value)
+ return ov_update_reg(sensor->client, OV2680_REG_ISP_CTRL00, BIT(7), 0);
-static int ov2680_v_flip(struct v4l2_subdev *sd, s32 value)
-{
- struct camera_mipi_info *ov2680_info = NULL;
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret;
- u32 val;
- u8 index;
-
- dev_dbg(&client->dev, "@%s: value:%d\n", __func__, value);
- ret = ov2680_read_reg(client, 1, OV2680_FLIP_REG, &val);
- if (ret)
+ ret = ov_update_reg(sensor->client, OV2680_REG_ISP_CTRL00, 0x03, value - 1);
+ if (ret < 0)
return ret;
- if (value)
- val |= OV2680_FLIP_MIRROR_BIT_ENABLE;
- else
- val &= ~OV2680_FLIP_MIRROR_BIT_ENABLE;
- ret = ov2680_write_reg(client, 1,
- OV2680_FLIP_REG, val);
- if (ret)
+ ret = ov_update_reg(sensor->client, OV2680_REG_ISP_CTRL00, BIT(7), BIT(7));
+ if (ret < 0)
return ret;
- index = (v_flag > 0 ? OV2680_FLIP_BIT : 0) | (h_flag > 0 ? OV2680_MIRROR_BIT :
- 0);
- ov2680_info = v4l2_get_subdev_hostdata(sd);
- if (ov2680_info) {
- ov2680_info->raw_bayer_order = ov2680_bayer_order_mapping[index];
- }
- return ret;
+
+ return 0;
}
-static int ov2680_h_flip(struct v4l2_subdev *sd, s32 value)
+static int ov2680_s_ctrl(struct v4l2_ctrl *ctrl)
{
- struct camera_mipi_info *ov2680_info = NULL;
- struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
+ struct ov2680_device *sensor = to_ov2680_sensor(sd);
int ret;
- u32 val;
- u8 index;
-
- dev_dbg(&client->dev, "@%s: value:%d\n", __func__, value);
-
- ret = ov2680_read_reg(client, 1, OV2680_MIRROR_REG, &val);
- if (ret)
- return ret;
- if (value)
- val |= OV2680_FLIP_MIRROR_BIT_ENABLE;
- else
- val &= ~OV2680_FLIP_MIRROR_BIT_ENABLE;
- ret = ov2680_write_reg(client, 1,
- OV2680_MIRROR_REG, val);
- if (ret)
- return ret;
- index = (v_flag > 0 ? OV2680_FLIP_BIT : 0) | (h_flag > 0 ? OV2680_MIRROR_BIT :
- 0);
- ov2680_info = v4l2_get_subdev_hostdata(sd);
- if (ov2680_info) {
- ov2680_info->raw_bayer_order = ov2680_bayer_order_mapping[index];
+ /* Only apply changes to the controls if the device is powered up */
+ if (!pm_runtime_get_if_in_use(sensor->sd.dev)) {
+ ov2680_set_bayer_order(sensor, &sensor->mode.fmt);
+ return 0;
}
- return ret;
-}
-
-static int ov2680_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct ov2680_device *dev =
- container_of(ctrl->handler, struct ov2680_device, ctrl_handler);
- struct i2c_client *client = v4l2_get_subdevdata(&dev->sd);
- int ret = 0;
switch (ctrl->id) {
case V4L2_CID_VFLIP:
- dev_dbg(&client->dev, "%s: CID_VFLIP:%d.\n",
- __func__, ctrl->val);
- ret = ov2680_v_flip(&dev->sd, ctrl->val);
+ ret = ov2680_set_vflip(sensor, ctrl->val);
break;
case V4L2_CID_HFLIP:
- dev_dbg(&client->dev, "%s: CID_HFLIP:%d.\n",
- __func__, ctrl->val);
- ret = ov2680_h_flip(&dev->sd, ctrl->val);
+ ret = ov2680_set_hflip(sensor, ctrl->val);
break;
- default:
- ret = -EINVAL;
- }
- return ret;
-}
-
-static int ov2680_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct ov2680_device *dev =
- container_of(ctrl->handler, struct ov2680_device, ctrl_handler);
- int ret = 0;
-
- switch (ctrl->id) {
- case V4L2_CID_EXPOSURE_ABSOLUTE:
- ret = ov2680_q_exposure(&dev->sd, &ctrl->val);
- break;
- case V4L2_CID_FOCAL_ABSOLUTE:
- ret = ov2680_g_focal(&dev->sd, &ctrl->val);
- break;
- case V4L2_CID_FNUMBER_ABSOLUTE:
- ret = ov2680_g_fnumber(&dev->sd, &ctrl->val);
- break;
- case V4L2_CID_FNUMBER_RANGE:
- ret = ov2680_g_fnumber_range(&dev->sd, &ctrl->val);
+ case V4L2_CID_EXPOSURE:
+ ret = ov2680_exposure_set(sensor, ctrl->val);
break;
- case V4L2_CID_BIN_FACTOR_HORZ:
- ret = ov2680_g_bin_factor_x(&dev->sd, &ctrl->val);
+ case V4L2_CID_GAIN:
+ ret = ov2680_gain_set(sensor, ctrl->val);
break;
- case V4L2_CID_BIN_FACTOR_VERT:
- ret = ov2680_g_bin_factor_y(&dev->sd, &ctrl->val);
+ case V4L2_CID_TEST_PATTERN:
+ ret = ov2680_test_pattern_set(sensor, ctrl->val);
break;
default:
ret = -EINVAL;
}
+ pm_runtime_put(sensor->sd.dev);
return ret;
}
-static const struct v4l2_ctrl_ops ctrl_ops = {
+static const struct v4l2_ctrl_ops ov2680_ctrl_ops = {
.s_ctrl = ov2680_s_ctrl,
- .g_volatile_ctrl = ov2680_g_volatile_ctrl
-};
-
-static const struct v4l2_ctrl_config ov2680_controls[] = {
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_EXPOSURE_ABSOLUTE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "exposure",
- .min = 0x0,
- .max = 0xffff,
- .step = 0x01,
- .def = 0x00,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_FOCAL_ABSOLUTE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "focal length",
- .min = OV2680_FOCAL_LENGTH_DEFAULT,
- .max = OV2680_FOCAL_LENGTH_DEFAULT,
- .step = 0x01,
- .def = OV2680_FOCAL_LENGTH_DEFAULT,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_FNUMBER_ABSOLUTE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "f-number",
- .min = OV2680_F_NUMBER_DEFAULT,
- .max = OV2680_F_NUMBER_DEFAULT,
- .step = 0x01,
- .def = OV2680_F_NUMBER_DEFAULT,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_FNUMBER_RANGE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "f-number range",
- .min = OV2680_F_NUMBER_RANGE,
- .max = OV2680_F_NUMBER_RANGE,
- .step = 0x01,
- .def = OV2680_F_NUMBER_RANGE,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_BIN_FACTOR_HORZ,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "horizontal binning factor",
- .min = 0,
- .max = OV2680_BIN_FACTOR_MAX,
- .step = 1,
- .def = 0,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_BIN_FACTOR_VERT,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "vertical binning factor",
- .min = 0,
- .max = OV2680_BIN_FACTOR_MAX,
- .step = 1,
- .def = 0,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Flip",
- .min = 0,
- .max = 1,
- .step = 1,
- .def = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Mirror",
- .min = 0,
- .max = 1,
- .step = 1,
- .def = 0,
- },
};
static int ov2680_init_registers(struct v4l2_subdev *sd)
@@ -638,288 +181,191 @@ static int ov2680_init_registers(struct v4l2_subdev *sd)
struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret;
- ret = ov2680_write_reg(client, 1, OV2680_SW_RESET, 0x01);
+ ret = ov_write_reg8(client, OV2680_SW_RESET, 0x01);
ret |= ov2680_write_reg_array(client, ov2680_global_setting);
return ret;
}
-static int power_ctrl(struct v4l2_subdev *sd, bool flag)
+static struct v4l2_mbus_framefmt *
+__ov2680_get_pad_format(struct ov2680_device *sensor,
+ struct v4l2_subdev_state *state,
+ unsigned int pad, enum v4l2_subdev_format_whence which)
{
- int ret = 0;
- struct ov2680_device *dev = to_ov2680_sensor(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (!dev || !dev->platform_data)
- return -ENODEV;
-
- dev_dbg(&client->dev, "%s: %s", __func__, flag ? "on" : "off");
-
- if (flag) {
- ret |= dev->platform_data->v1p8_ctrl(sd, 1);
- ret |= dev->platform_data->v2p8_ctrl(sd, 1);
- usleep_range(10000, 15000);
- }
+ if (which == V4L2_SUBDEV_FORMAT_TRY)
+ return v4l2_subdev_get_try_format(&sensor->sd, state, pad);
- if (!flag || ret) {
- ret |= dev->platform_data->v1p8_ctrl(sd, 0);
- ret |= dev->platform_data->v2p8_ctrl(sd, 0);
- }
- return ret;
+ return &sensor->mode.fmt;
}
-static int gpio_ctrl(struct v4l2_subdev *sd, bool flag)
+static void ov2680_fill_format(struct ov2680_device *sensor,
+ struct v4l2_mbus_framefmt *fmt,
+ unsigned int width, unsigned int height)
{
- int ret;
- struct ov2680_device *dev = to_ov2680_sensor(sd);
+ memset(fmt, 0, sizeof(*fmt));
+ fmt->width = width;
+ fmt->height = height;
+ fmt->field = V4L2_FIELD_NONE;
+ ov2680_set_bayer_order(sensor, fmt);
+}
- if (!dev || !dev->platform_data)
- return -ENODEV;
+static void ov2680_calc_mode(struct ov2680_device *sensor, int width, int height)
+{
+ int orig_width = width;
+ int orig_height = height;
- /*
- * The OV2680 documents only one GPIO input (#XSHUTDN), but
- * existing integrations often wire two (reset/power_down)
- * because that is the way other sensors work. There is no
- * way to tell how it is wired internally, so existing
- * firmwares expose both and we drive them symmetrically.
- */
- if (flag) {
- ret = dev->platform_data->gpio0_ctrl(sd, 1);
- usleep_range(10000, 15000);
- /* Ignore return from second gpio, it may not be there */
- dev->platform_data->gpio1_ctrl(sd, 1);
- usleep_range(10000, 15000);
+ if (width <= (OV2680_NATIVE_WIDTH / 2) &&
+ height <= (OV2680_NATIVE_HEIGHT / 2)) {
+ sensor->mode.binning = true;
+ width *= 2;
+ height *= 2;
} else {
- dev->platform_data->gpio1_ctrl(sd, 0);
- ret = dev->platform_data->gpio0_ctrl(sd, 0);
+ sensor->mode.binning = false;
}
- return ret;
+
+ sensor->mode.h_start = ((OV2680_NATIVE_WIDTH - width) / 2) & ~1;
+ sensor->mode.v_start = ((OV2680_NATIVE_HEIGHT - height) / 2) & ~1;
+ sensor->mode.h_end = min(sensor->mode.h_start + width + OV2680_END_MARGIN - 1,
+ OV2680_NATIVE_WIDTH - 1);
+ sensor->mode.v_end = min(sensor->mode.v_start + height + OV2680_END_MARGIN - 1,
+ OV2680_NATIVE_HEIGHT - 1);
+ sensor->mode.h_output_size = orig_width;
+ sensor->mode.v_output_size = orig_height;
+ sensor->mode.hts = OV2680_PIXELS_PER_LINE;
+ sensor->mode.vts = OV2680_LINES_PER_FRAME;
}
-static int power_up(struct v4l2_subdev *sd)
+static int ov2680_set_mode(struct ov2680_device *sensor)
{
- struct ov2680_device *dev = to_ov2680_sensor(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct i2c_client *client = sensor->client;
+ u8 pll_div, unknown, inc, fmt1, fmt2;
int ret;
- if (!dev->platform_data) {
- dev_err(&client->dev,
- "no camera_sensor_platform_data");
- return -ENODEV;
+ if (sensor->mode.binning) {
+ pll_div = 1;
+ unknown = 0x23;
+ inc = 0x31;
+ fmt1 = 0xc2;
+ fmt2 = 0x01;
+ } else {
+ pll_div = 0;
+ unknown = 0x21;
+ inc = 0x11;
+ fmt1 = 0xc0;
+ fmt2 = 0x00;
}
- if (dev->power_on)
- return 0; /* Already on */
-
- /* power control */
- ret = power_ctrl(sd, 1);
+ ret = ov_write_reg8(client, 0x3086, pll_div);
if (ret)
- goto fail_power;
-
- /* according to DS, at least 5ms is needed between DOVDD and PWDN */
- usleep_range(5000, 6000);
-
- /* gpio ctrl */
- ret = gpio_ctrl(sd, 1);
- if (ret) {
- ret = gpio_ctrl(sd, 1);
- if (ret)
- goto fail_power;
- }
+ return ret;
- /* flis clock control */
- ret = dev->platform_data->flisclk_ctrl(sd, 1);
+ ret = ov_write_reg8(client, 0x370a, unknown);
if (ret)
- goto fail_clk;
-
- /* according to DS, 20ms is needed between PWDN and i2c access */
- msleep(20);
+ return ret;
- ret = ov2680_init_registers(sd);
+ ret = ov_write_reg16(client, OV2680_HORIZONTAL_START_H, sensor->mode.h_start);
if (ret)
- goto fail_init_registers;
+ return ret;
- ret = __ov2680_set_exposure(sd, dev->exposure, dev->gain, dev->digitgain);
+ ret = ov_write_reg16(client, OV2680_VERTICAL_START_H, sensor->mode.v_start);
if (ret)
- goto fail_init_registers;
+ return ret;
- dev->power_on = true;
- return 0;
+ ret = ov_write_reg16(client, OV2680_HORIZONTAL_END_H, sensor->mode.h_end);
+ if (ret)
+ return ret;
-fail_init_registers:
- dev->platform_data->flisclk_ctrl(sd, 0);
-fail_clk:
- gpio_ctrl(sd, 0);
-fail_power:
- power_ctrl(sd, 0);
- dev_err(&client->dev, "sensor power-up failed\n");
+ ret = ov_write_reg16(client, OV2680_VERTICAL_END_H, sensor->mode.v_end);
+ if (ret)
+ return ret;
- return ret;
-}
+ ret = ov_write_reg16(client, OV2680_HORIZONTAL_OUTPUT_SIZE_H,
+ sensor->mode.h_output_size);
+ if (ret)
+ return ret;
-static int power_down(struct v4l2_subdev *sd)
-{
- struct ov2680_device *dev = to_ov2680_sensor(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret = 0;
+ ret = ov_write_reg16(client, OV2680_VERTICAL_OUTPUT_SIZE_H,
+ sensor->mode.v_output_size);
+ if (ret)
+ return ret;
- h_flag = 0;
- v_flag = 0;
- if (!dev->platform_data) {
- dev_err(&client->dev,
- "no camera_sensor_platform_data");
- return -ENODEV;
- }
+ ret = ov_write_reg16(client, OV2680_HTS, sensor->mode.hts);
+ if (ret)
+ return ret;
- if (!dev->power_on)
- return 0; /* Already off */
+ ret = ov_write_reg16(client, OV2680_VTS, sensor->mode.vts);
+ if (ret)
+ return ret;
- ret = dev->platform_data->flisclk_ctrl(sd, 0);
+ ret = ov_write_reg16(client, OV2680_ISP_X_WIN, 0);
if (ret)
- dev_err(&client->dev, "flisclk failed\n");
+ return ret;
- /* gpio ctrl */
- ret = gpio_ctrl(sd, 0);
- if (ret) {
- ret = gpio_ctrl(sd, 0);
- if (ret)
- dev_err(&client->dev, "gpio failed 2\n");
- }
+ ret = ov_write_reg16(client, OV2680_ISP_Y_WIN, 0);
+ if (ret)
+ return ret;
- /* power control */
- ret = power_ctrl(sd, 0);
- if (ret) {
- dev_err(&client->dev, "vprog failed.\n");
+ ret = ov_write_reg8(client, OV2680_X_INC, inc);
+ if (ret)
return ret;
- }
- dev->power_on = false;
- return 0;
-}
+ ret = ov_write_reg8(client, OV2680_Y_INC, inc);
+ if (ret)
+ return ret;
-static int ov2680_s_power(struct v4l2_subdev *sd, int on)
-{
- struct ov2680_device *dev = to_ov2680_sensor(sd);
- int ret;
+ ret = ov_write_reg16(client, OV2680_X_WIN, sensor->mode.h_output_size);
+ if (ret)
+ return ret;
- mutex_lock(&dev->input_lock);
+ ret = ov_write_reg16(client, OV2680_Y_WIN, sensor->mode.v_output_size);
+ if (ret)
+ return ret;
- if (on == 0) {
- ret = power_down(sd);
- } else {
- ret = power_up(sd);
- }
+ ret = ov_write_reg8(client, OV2680_REG_FORMAT1, fmt1);
+ if (ret)
+ return ret;
- mutex_unlock(&dev->input_lock);
+ ret = ov_write_reg8(client, OV2680_REG_FORMAT2, fmt2);
+ if (ret)
+ return ret;
- return ret;
+ return 0;
}
static int ov2680_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
- struct v4l2_mbus_framefmt *fmt = &format->format;
- struct ov2680_device *dev = to_ov2680_sensor(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct camera_mipi_info *ov2680_info = NULL;
- struct ov2680_resolution *res;
- int vts, ret = 0;
-
- dev_dbg(&client->dev, "%s: %s: pad: %d, fmt: %p\n",
- __func__,
- (format->which == V4L2_SUBDEV_FORMAT_TRY) ? "try" : "set",
- format->pad, fmt);
-
- if (format->pad)
- return -EINVAL;
+ struct ov2680_device *sensor = to_ov2680_sensor(sd);
+ struct v4l2_mbus_framefmt *fmt;
+ unsigned int width, height;
- if (!fmt)
- return -EINVAL;
+ width = min_t(unsigned int, ALIGN(format->format.width, 2), OV2680_NATIVE_WIDTH);
+ height = min_t(unsigned int, ALIGN(format->format.height, 2), OV2680_NATIVE_HEIGHT);
- ov2680_info = v4l2_get_subdev_hostdata(sd);
- if (!ov2680_info)
- return -EINVAL;
+ fmt = __ov2680_get_pad_format(sensor, sd_state, format->pad, format->which);
+ ov2680_fill_format(sensor, fmt, width, height);
- res = v4l2_find_nearest_size(ov2680_res_preview,
- ARRAY_SIZE(ov2680_res_preview), width,
- height, fmt->width, fmt->height);
- if (!res)
- res = &ov2680_res_preview[N_RES_PREVIEW - 1];
+ format->format = *fmt;
- fmt->width = res->width;
- fmt->height = res->height;
-
- fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
- if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- sd_state->pads->try_fmt = *fmt;
+ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
return 0;
- }
-
- dev_dbg(&client->dev, "%s: %dx%d\n",
- __func__, fmt->width, fmt->height);
- mutex_lock(&dev->input_lock);
-
- /* s_power has not been called yet for std v4l2 clients (camorama) */
- power_up(sd);
- ret = ov2680_write_reg_array(client, dev->res->regs);
- if (ret) {
- dev_err(&client->dev,
- "ov2680 write resolution register err: %d\n", ret);
- goto err;
- }
-
- vts = dev->res->lines_per_frame;
-
- /* If necessary increase the VTS to match exposure + MARGIN */
- if (dev->exposure > vts - OV2680_INTEGRATION_TIME_MARGIN)
- vts = dev->exposure + OV2680_INTEGRATION_TIME_MARGIN;
-
- ret = ov2680_write_reg(client, 2, OV2680_TIMING_VTS_H, vts);
- if (ret) {
- dev_err(&client->dev, "ov2680 write vts err: %d\n", ret);
- goto err;
- }
-
- ret = ov2680_get_intg_factor(client, ov2680_info, res);
- if (ret) {
- dev_err(&client->dev, "failed to get integration factor\n");
- goto err;
- }
-
- /*
- * recall flip functions to avoid flip registers
- * were overridden by default setting
- */
- if (h_flag)
- ov2680_h_flip(sd, h_flag);
- if (v_flag)
- ov2680_v_flip(sd, v_flag);
-
- dev->res = res;
-err:
- mutex_unlock(&dev->input_lock);
- return ret;
+ mutex_lock(&sensor->input_lock);
+ ov2680_calc_mode(sensor, fmt->width, fmt->height);
+ mutex_unlock(&sensor->input_lock);
+ return 0;
}
static int ov2680_get_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
- struct v4l2_mbus_framefmt *fmt = &format->format;
- struct ov2680_device *dev = to_ov2680_sensor(sd);
-
- if (format->pad)
- return -EINVAL;
-
- if (!fmt)
- return -EINVAL;
-
- fmt->width = dev->res->width;
- fmt->height = dev->res->height;
- fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
+ struct ov2680_device *sensor = to_ov2680_sensor(sd);
+ struct v4l2_mbus_framefmt *fmt;
+ fmt = __ov2680_get_pad_format(sensor, sd_state, format->pad, format->which);
+ format->format = *fmt;
return 0;
}
@@ -934,14 +380,12 @@ static int ov2680_detect(struct i2c_client *client)
if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
return -ENODEV;
- ret = ov2680_read_reg(client, 1,
- OV2680_SC_CMMN_CHIP_ID_H, &high);
+ ret = ov_read_reg8(client, OV2680_SC_CMMN_CHIP_ID_H, &high);
if (ret) {
dev_err(&client->dev, "sensor_id_high = 0x%x\n", high);
return -ENODEV;
}
- ret = ov2680_read_reg(client, 1,
- OV2680_SC_CMMN_CHIP_ID_L, &low);
+ ret = ov_read_reg8(client, OV2680_SC_CMMN_CHIP_ID_L, &low);
id = ((((u16)high) << 8) | (u16)low);
if (id != OV2680_ID) {
@@ -949,8 +393,7 @@ static int ov2680_detect(struct i2c_client *client)
return -ENODEV;
}
- ret = ov2680_read_reg(client, 1,
- OV2680_SC_CMMN_SUB_ID, &high);
+ ret = ov_read_reg8(client, OV2680_SC_CMMN_SUB_ID, &high);
revision = (u8)high & 0x0f;
dev_info(&client->dev, "sensor_revision id = 0x%x, rev= %d\n",
@@ -961,88 +404,79 @@ static int ov2680_detect(struct i2c_client *client)
static int ov2680_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct ov2680_device *dev = to_ov2680_sensor(sd);
+ struct ov2680_device *sensor = to_ov2680_sensor(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret;
+ int ret = 0;
+
+ mutex_lock(&sensor->input_lock);
+
+ if (sensor->is_streaming == enable) {
+ dev_warn(&client->dev, "stream already %s\n", enable ? "started" : "stopped");
+ goto error_unlock;
+ }
+
+ if (enable) {
+ ret = pm_runtime_get_sync(sensor->sd.dev);
+ if (ret < 0)
+ goto error_unlock;
+
+ ret = ov2680_set_mode(sensor);
+ if (ret)
+ goto error_power_down;
- mutex_lock(&dev->input_lock);
- if (enable)
- dev_dbg(&client->dev, "ov2680_s_stream one\n");
- else
- dev_dbg(&client->dev, "ov2680_s_stream off\n");
+ /* Restore value of all ctrls */
+ ret = __v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
+ if (ret)
+ goto error_power_down;
- ret = ov2680_write_reg(client, 1, OV2680_SW_STREAM,
- enable ? OV2680_START_STREAMING :
- OV2680_STOP_STREAMING);
+ ret = ov_write_reg8(client, OV2680_SW_STREAM, OV2680_START_STREAMING);
+ if (ret)
+ goto error_power_down;
+ } else {
+ ov_write_reg8(client, OV2680_SW_STREAM, OV2680_STOP_STREAMING);
+ pm_runtime_put(sensor->sd.dev);
+ }
- //otp valid at stream on state
- //if(!dev->otp_data)
- // dev->otp_data = ov2680_otp_read(sd);
+ sensor->is_streaming = enable;
+ v4l2_ctrl_activate(sensor->ctrls.vflip, !enable);
+ v4l2_ctrl_activate(sensor->ctrls.hflip, !enable);
- mutex_unlock(&dev->input_lock);
+ mutex_unlock(&sensor->input_lock);
+ return 0;
+error_power_down:
+ pm_runtime_put(sensor->sd.dev);
+error_unlock:
+ mutex_unlock(&sensor->input_lock);
return ret;
}
-static int ov2680_s_config(struct v4l2_subdev *sd,
- int irq, void *platform_data)
+static int ov2680_s_config(struct v4l2_subdev *sd)
{
- struct ov2680_device *dev = to_ov2680_sensor(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret = 0;
-
- if (!platform_data)
- return -ENODEV;
-
- dev->platform_data =
- (struct camera_sensor_platform_data *)platform_data;
-
- mutex_lock(&dev->input_lock);
+ int ret;
- ret = power_up(sd);
- if (ret) {
+ ret = pm_runtime_get_sync(&client->dev);
+ if (ret < 0) {
dev_err(&client->dev, "ov2680 power-up err.\n");
goto fail_power_on;
}
- ret = dev->platform_data->csi_cfg(sd, 1);
- if (ret)
- goto fail_csi_cfg;
-
/* config & detect sensor */
ret = ov2680_detect(client);
- if (ret) {
+ if (ret)
dev_err(&client->dev, "ov2680_detect err s_config.\n");
- goto fail_csi_cfg;
- }
- /* turn off sensor, after probed */
- ret = power_down(sd);
- if (ret) {
- dev_err(&client->dev, "ov2680 power-off err.\n");
- goto fail_csi_cfg;
- }
- mutex_unlock(&dev->input_lock);
-
- return 0;
-
-fail_csi_cfg:
- dev->platform_data->csi_cfg(sd, 0);
fail_power_on:
- power_down(sd);
- dev_err(&client->dev, "sensor power-gating failed\n");
- mutex_unlock(&dev->input_lock);
+ pm_runtime_put(&client->dev);
return ret;
}
static int ov2680_g_frame_interval(struct v4l2_subdev *sd,
struct v4l2_subdev_frame_interval *interval)
{
- struct ov2680_device *dev = to_ov2680_sensor(sd);
-
interval->interval.numerator = 1;
- interval->interval.denominator = dev->res->fps;
-
+ interval->interval.denominator = OV2680_FPS;
return 0;
}
@@ -1050,7 +484,8 @@ static int ov2680_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
- if (code->index >= MAX_FMTS)
+ /* We support only a single format */
+ if (code->index)
return -EINVAL;
code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
@@ -1061,15 +496,25 @@ static int ov2680_enum_frame_size(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
+ static const struct v4l2_frmsize_discrete ov2680_frame_sizes[] = {
+ { 1616, 1216 },
+ { 1616, 1096 },
+ { 1616, 916 },
+ { 1456, 1096 },
+ { 1296, 976 },
+ { 1296, 736 },
+ { 784, 592 },
+ { 656, 496 },
+ };
int index = fse->index;
- if (index >= N_RES_PREVIEW)
+ if (index >= ARRAY_SIZE(ov2680_frame_sizes))
return -EINVAL;
- fse->min_width = ov2680_res_preview[index].width;
- fse->min_height = ov2680_res_preview[index].height;
- fse->max_width = ov2680_res_preview[index].width;
- fse->max_height = ov2680_res_preview[index].height;
+ fse->min_width = ov2680_frame_sizes[index].width;
+ fse->min_height = ov2680_frame_sizes[index].height;
+ fse->max_width = ov2680_frame_sizes[index].width;
+ fse->max_height = ov2680_frame_sizes[index].height;
return 0;
}
@@ -1078,30 +523,18 @@ static int ov2680_enum_frame_interval(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_interval_enum *fie)
{
- struct v4l2_fract fract;
-
- if (fie->index >= N_RES_PREVIEW ||
- fie->width > ov2680_res_preview[0].width ||
- fie->height > ov2680_res_preview[0].height ||
- fie->which > V4L2_SUBDEV_FORMAT_ACTIVE)
+ /* Only 1 framerate */
+ if (fie->index)
return -EINVAL;
- fract.denominator = ov2680_res_preview[fie->index].fps;
- fract.numerator = 1;
-
- fie->interval = fract;
-
+ fie->interval.numerator = 1;
+ fie->interval.denominator = OV2680_FPS;
return 0;
}
static int ov2680_g_skip_frames(struct v4l2_subdev *sd, u32 *frames)
{
- struct ov2680_device *dev = to_ov2680_sensor(sd);
-
- mutex_lock(&dev->input_lock);
- *frames = dev->res->skip_frames;
- mutex_unlock(&dev->input_lock);
-
+ *frames = OV2680_SKIP_FRAMES;
return 0;
}
@@ -1114,11 +547,6 @@ static const struct v4l2_subdev_sensor_ops ov2680_sensor_ops = {
.g_skip_frames = ov2680_g_skip_frames,
};
-static const struct v4l2_subdev_core_ops ov2680_core_ops = {
- .s_power = ov2680_s_power,
- .ioctl = ov2680_ioctl,
-};
-
static const struct v4l2_subdev_pad_ops ov2680_pad_ops = {
.enum_mbus_code = ov2680_enum_mbus_code,
.enum_frame_size = ov2680_enum_frame_size,
@@ -1128,98 +556,173 @@ static const struct v4l2_subdev_pad_ops ov2680_pad_ops = {
};
static const struct v4l2_subdev_ops ov2680_ops = {
- .core = &ov2680_core_ops,
.video = &ov2680_video_ops,
.pad = &ov2680_pad_ops,
.sensor = &ov2680_sensor_ops,
};
+static int ov2680_init_controls(struct ov2680_device *sensor)
+{
+ static const char * const test_pattern_menu[] = {
+ "Disabled",
+ "Color Bars",
+ "Random Data",
+ "Square",
+ "Black Image",
+ };
+ const struct v4l2_ctrl_ops *ops = &ov2680_ctrl_ops;
+ struct ov2680_ctrls *ctrls = &sensor->ctrls;
+ struct v4l2_ctrl_handler *hdl = &ctrls->handler;
+ int exp_max = OV2680_LINES_PER_FRAME - OV2680_INTEGRATION_TIME_MARGIN;
+
+ v4l2_ctrl_handler_init(hdl, 4);
+
+ hdl->lock = &sensor->input_lock;
+
+ ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
+ ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
+ ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,
+ 0, exp_max, 1, exp_max);
+ ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN, 0, 1023, 1, 250);
+ ctrls->test_pattern =
+ v4l2_ctrl_new_std_menu_items(hdl,
+ &ov2680_ctrl_ops, V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(test_pattern_menu) - 1,
+ 0, 0, test_pattern_menu);
+
+ ctrls->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
+ ctrls->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
+
+ if (hdl->error)
+ return hdl->error;
+
+ sensor->sd.ctrl_handler = hdl;
+ return 0;
+}
+
static void ov2680_remove(struct i2c_client *client)
{
struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct ov2680_device *dev = to_ov2680_sensor(sd);
+ struct ov2680_device *sensor = to_ov2680_sensor(sd);
dev_dbg(&client->dev, "ov2680_remove...\n");
- dev->platform_data->csi_cfg(sd, 0);
-
+ atomisp_unregister_subdev(sd);
v4l2_device_unregister_subdev(sd);
- media_entity_cleanup(&dev->sd.entity);
- v4l2_ctrl_handler_free(&dev->ctrl_handler);
- kfree(dev);
+ media_entity_cleanup(&sensor->sd.entity);
+ v4l2_ctrl_handler_free(&sensor->ctrls.handler);
+ pm_runtime_disable(&client->dev);
}
+/*
+ * Unlike other sensors which have both a rest and powerdown input pins,
+ * the OV2680 only has a powerdown input. But some ACPI tables still list
+ * 2 GPIOs for the OV2680 and it is unclear which to use. So try to get
+ * up to 2 GPIOs (1 mandatory, 1 optional) and control them in sync.
+ */
+static const struct acpi_gpio_params ov2680_first_gpio = { 0, 0, true };
+static const struct acpi_gpio_params ov2680_second_gpio = { 1, 0, true };
+
+static const struct acpi_gpio_mapping ov2680_gpio_mapping[] = {
+ { "powerdown-gpios", &ov2680_first_gpio, 1 },
+ { "powerdown-alt-gpios", &ov2680_second_gpio, 1 },
+ { },
+};
+
static int ov2680_probe(struct i2c_client *client)
{
- struct ov2680_device *dev;
+ struct device *dev = &client->dev;
+ struct ov2680_device *sensor;
int ret;
- void *pdata;
- unsigned int i;
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (!dev)
+ sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
+ if (!sensor)
return -ENOMEM;
- mutex_init(&dev->input_lock);
+ mutex_init(&sensor->input_lock);
- dev->res = &ov2680_res_preview[0];
- dev->exposure = dev->res->lines_per_frame - OV2680_INTEGRATION_TIME_MARGIN;
- dev->gain = 250; /* 0-2047 */
- v4l2_i2c_subdev_init(&dev->sd, client, &ov2680_ops);
+ sensor->client = client;
+ v4l2_i2c_subdev_init(&sensor->sd, client, &ov2680_ops);
- pdata = gmin_camera_platform_data(&dev->sd,
- ATOMISP_INPUT_FORMAT_RAW_10,
- atomisp_bayer_order_bggr);
- if (!pdata) {
- ret = -EINVAL;
- goto out_free;
- }
-
- ret = ov2680_s_config(&dev->sd, client->irq, pdata);
+ ret = devm_acpi_dev_add_driver_gpios(&client->dev, ov2680_gpio_mapping);
if (ret)
- goto out_free;
+ return ret;
+
+ sensor->powerdown = devm_gpiod_get(dev, "powerdown", GPIOD_OUT_HIGH);
+ if (IS_ERR(sensor->powerdown))
+ return dev_err_probe(dev, PTR_ERR(sensor->powerdown), "getting powerdown GPIO\n");
+
+ sensor->powerdown_alt = devm_gpiod_get_optional(dev, "powerdown-alt", GPIOD_OUT_HIGH);
+ if (IS_ERR(sensor->powerdown_alt))
+ return dev_err_probe(dev, PTR_ERR(sensor->powerdown_alt), "getting powerdown-alt GPIO\n");
- ret = atomisp_register_i2c_module(&dev->sd, pdata, RAW_CAMERA);
+ pm_runtime_set_suspended(dev);
+ pm_runtime_enable(dev);
+ pm_runtime_set_autosuspend_delay(dev, 1000);
+ pm_runtime_use_autosuspend(dev);
+
+ ret = ov2680_s_config(&sensor->sd);
if (ret)
- goto out_free;
-
- dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
- dev->pad.flags = MEDIA_PAD_FL_SOURCE;
- dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
- ret =
- v4l2_ctrl_handler_init(&dev->ctrl_handler,
- ARRAY_SIZE(ov2680_controls));
+ return ret;
+
+ sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
+ sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+
+ ret = ov2680_init_controls(sensor);
if (ret) {
ov2680_remove(client);
return ret;
}
- for (i = 0; i < ARRAY_SIZE(ov2680_controls); i++)
- v4l2_ctrl_new_custom(&dev->ctrl_handler, &ov2680_controls[i],
- NULL);
-
- if (dev->ctrl_handler.error) {
+ ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
+ if (ret) {
ov2680_remove(client);
- return dev->ctrl_handler.error;
+ return ret;
}
- /* Use same lock for controls as for everything else. */
- dev->ctrl_handler.lock = &dev->input_lock;
- dev->sd.ctrl_handler = &dev->ctrl_handler;
+ ov2680_fill_format(sensor, &sensor->mode.fmt, OV2680_NATIVE_WIDTH, OV2680_NATIVE_HEIGHT);
- ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad);
+ ret = atomisp_register_sensor_no_gmin(&sensor->sd, 1, ATOMISP_INPUT_FORMAT_RAW_10,
+ atomisp_bayer_order_bggr);
if (ret) {
ov2680_remove(client);
- dev_dbg(&client->dev, "+++ remove ov2680\n");
+ return ret;
}
- return ret;
-out_free:
- dev_dbg(&client->dev, "+++ out free\n");
- v4l2_device_unregister_subdev(&dev->sd);
- kfree(dev);
- return ret;
+
+ return 0;
}
+static int ov2680_suspend(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct ov2680_device *sensor = to_ov2680_sensor(sd);
+
+ gpiod_set_value_cansleep(sensor->powerdown, 1);
+ gpiod_set_value_cansleep(sensor->powerdown_alt, 1);
+ return 0;
+}
+
+static int ov2680_resume(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct ov2680_device *sensor = to_ov2680_sensor(sd);
+
+ /* according to DS, at least 5ms is needed after DOVDD (enabled by ACPI) */
+ usleep_range(5000, 6000);
+
+ gpiod_set_value_cansleep(sensor->powerdown, 0);
+ gpiod_set_value_cansleep(sensor->powerdown_alt, 0);
+
+ /* according to DS, 20ms is needed between PWDN and i2c access */
+ msleep(20);
+
+ ov2680_init_registers(sd);
+ return 0;
+}
+
+static DEFINE_RUNTIME_DEV_PM_OPS(ov2680_pm_ops, ov2680_suspend, ov2680_resume, NULL);
+
static const struct acpi_device_id ov2680_acpi_match[] = {
{"XXOV2680"},
{"OVTI2680"},
@@ -1230,6 +733,7 @@ MODULE_DEVICE_TABLE(acpi, ov2680_acpi_match);
static struct i2c_driver ov2680_driver = {
.driver = {
.name = "ov2680",
+ .pm = pm_sleep_ptr(&ov2680_pm_ops),
.acpi_match_table = ov2680_acpi_match,
},
.probe_new = ov2680_probe,
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c
index 887b6f99f6ca..5d2e6e2e72f0 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c
@@ -261,134 +261,6 @@ static int ov2722_write_reg_array(struct i2c_client *client,
return __ov2722_flush_reg_array(client, &ctrl);
}
-static int ov2722_g_focal(struct v4l2_subdev *sd, s32 *val)
-{
- *val = (OV2722_FOCAL_LENGTH_NUM << 16) | OV2722_FOCAL_LENGTH_DEM;
- return 0;
-}
-
-static int ov2722_g_fnumber(struct v4l2_subdev *sd, s32 *val)
-{
- /*const f number for imx*/
- *val = (OV2722_F_NUMBER_DEFAULT_NUM << 16) | OV2722_F_NUMBER_DEM;
- return 0;
-}
-
-static int ov2722_g_fnumber_range(struct v4l2_subdev *sd, s32 *val)
-{
- *val = (OV2722_F_NUMBER_DEFAULT_NUM << 24) |
- (OV2722_F_NUMBER_DEM << 16) |
- (OV2722_F_NUMBER_DEFAULT_NUM << 8) | OV2722_F_NUMBER_DEM;
- return 0;
-}
-
-static int ov2722_get_intg_factor(struct i2c_client *client,
- struct camera_mipi_info *info,
- const struct ov2722_resolution *res)
-{
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct ov2722_device *dev = NULL;
- struct atomisp_sensor_mode_data *buf = &info->data;
- const unsigned int ext_clk_freq_hz = 19200000;
- const unsigned int pll_invariant_div = 10;
- unsigned int pix_clk_freq_hz;
- u16 pre_pll_clk_div;
- u16 pll_multiplier;
- u16 op_pix_clk_div;
- u16 reg_val;
- int ret;
-
- if (!info)
- return -EINVAL;
-
- dev = to_ov2722_sensor(sd);
-
- /* pixel clock calculattion */
- ret = ov2722_read_reg(client, OV2722_8BIT,
- OV2722_SC_CMMN_PLL_CTRL3, &pre_pll_clk_div);
- if (ret)
- return ret;
-
- ret = ov2722_read_reg(client, OV2722_8BIT,
- OV2722_SC_CMMN_PLL_MULTIPLIER, &pll_multiplier);
- if (ret)
- return ret;
-
- ret = ov2722_read_reg(client, OV2722_8BIT,
- OV2722_SC_CMMN_PLL_DEBUG_OPT, &op_pix_clk_div);
- if (ret)
- return ret;
-
- pre_pll_clk_div = (pre_pll_clk_div & 0x70) >> 4;
- if (!pre_pll_clk_div)
- return -EINVAL;
-
- pll_multiplier = pll_multiplier & 0x7f;
- op_pix_clk_div = op_pix_clk_div & 0x03;
- pix_clk_freq_hz = ext_clk_freq_hz / pre_pll_clk_div * pll_multiplier
- * op_pix_clk_div / pll_invariant_div;
-
- dev->vt_pix_clk_freq_mhz = pix_clk_freq_hz;
- buf->vt_pix_clk_freq_mhz = pix_clk_freq_hz;
-
- /* get integration time */
- buf->coarse_integration_time_min = OV2722_COARSE_INTG_TIME_MIN;
- buf->coarse_integration_time_max_margin =
- OV2722_COARSE_INTG_TIME_MAX_MARGIN;
-
- buf->fine_integration_time_min = OV2722_FINE_INTG_TIME_MIN;
- buf->fine_integration_time_max_margin =
- OV2722_FINE_INTG_TIME_MAX_MARGIN;
-
- buf->fine_integration_time_def = OV2722_FINE_INTG_TIME_MIN;
- buf->frame_length_lines = res->lines_per_frame;
- buf->line_length_pck = res->pixels_per_line;
- buf->read_mode = res->bin_mode;
-
- /* get the cropping and output resolution to ISP for this mode. */
- ret = ov2722_read_reg(client, OV2722_16BIT,
- OV2722_H_CROP_START_H, &reg_val);
- if (ret)
- return ret;
- buf->crop_horizontal_start = reg_val;
-
- ret = ov2722_read_reg(client, OV2722_16BIT,
- OV2722_V_CROP_START_H, &reg_val);
- if (ret)
- return ret;
- buf->crop_vertical_start = reg_val;
-
- ret = ov2722_read_reg(client, OV2722_16BIT,
- OV2722_H_CROP_END_H, &reg_val);
- if (ret)
- return ret;
- buf->crop_horizontal_end = reg_val;
-
- ret = ov2722_read_reg(client, OV2722_16BIT,
- OV2722_V_CROP_END_H, &reg_val);
- if (ret)
- return ret;
- buf->crop_vertical_end = reg_val;
-
- ret = ov2722_read_reg(client, OV2722_16BIT,
- OV2722_H_OUTSIZE_H, &reg_val);
- if (ret)
- return ret;
- buf->output_width = reg_val;
-
- ret = ov2722_read_reg(client, OV2722_16BIT,
- OV2722_V_OUTSIZE_H, &reg_val);
- if (ret)
- return ret;
- buf->output_height = reg_val;
-
- buf->binning_factor_x = res->bin_factor_x ?
- res->bin_factor_x : 1;
- buf->binning_factor_y = res->bin_factor_y ?
- res->bin_factor_y : 1;
- return 0;
-}
-
static long __ov2722_set_exposure(struct v4l2_subdev *sd, int coarse_itg,
int gain, int digitgain)
@@ -547,15 +419,6 @@ static int ov2722_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_EXPOSURE_ABSOLUTE:
ret = ov2722_q_exposure(&dev->sd, &ctrl->val);
break;
- case V4L2_CID_FOCAL_ABSOLUTE:
- ret = ov2722_g_focal(&dev->sd, &ctrl->val);
- break;
- case V4L2_CID_FNUMBER_ABSOLUTE:
- ret = ov2722_g_fnumber(&dev->sd, &ctrl->val);
- break;
- case V4L2_CID_FNUMBER_RANGE:
- ret = ov2722_g_fnumber_range(&dev->sd, &ctrl->val);
- break;
case V4L2_CID_LINK_FREQ:
val = dev->res->mipi_freq;
if (val == 0)
@@ -588,39 +451,6 @@ static const struct v4l2_ctrl_config ov2722_controls[] = {
},
{
.ops = &ctrl_ops,
- .id = V4L2_CID_FOCAL_ABSOLUTE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "focal length",
- .min = OV2722_FOCAL_LENGTH_DEFAULT,
- .max = OV2722_FOCAL_LENGTH_DEFAULT,
- .step = 0x01,
- .def = OV2722_FOCAL_LENGTH_DEFAULT,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_FNUMBER_ABSOLUTE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "f-number",
- .min = OV2722_F_NUMBER_DEFAULT,
- .max = OV2722_F_NUMBER_DEFAULT,
- .step = 0x01,
- .def = OV2722_F_NUMBER_DEFAULT,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_FNUMBER_RANGE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "f-number range",
- .min = OV2722_F_NUMBER_RANGE,
- .max = OV2722_F_NUMBER_RANGE,
- .step = 0x01,
- .def = OV2722_F_NUMBER_RANGE,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
.id = V4L2_CID_LINK_FREQ,
.name = "Link Frequency",
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -682,10 +512,7 @@ static int gpio_ctrl(struct v4l2_subdev *sd, bool flag)
* before PWDN# when turning it on or off.
*/
ret = dev->platform_data->gpio0_ctrl(sd, flag);
- /*
- *ov2722 PWDN# active high when pull down,opposite to the convention
- */
- ret |= dev->platform_data->gpio1_ctrl(sd, !flag);
+ ret |= dev->platform_data->gpio1_ctrl(sd, flag);
return ret;
}
@@ -701,6 +528,9 @@ static int power_up(struct v4l2_subdev *sd)
return -ENODEV;
}
+ if (dev->power_on == 1)
+ return 0; /* Already on */
+
/* power control */
ret = power_ctrl(sd, 1);
if (ret)
@@ -725,6 +555,7 @@ static int power_up(struct v4l2_subdev *sd)
/* according to DS, 20ms is needed between PWDN and i2c access */
msleep(20);
+ dev->power_on = 1;
return 0;
fail_clk:
@@ -748,6 +579,9 @@ static int power_down(struct v4l2_subdev *sd)
return -ENODEV;
}
+ if (dev->power_on == 0)
+ return 0; /* Already off */
+
ret = dev->platform_data->flisclk_ctrl(sd, 0);
if (ret)
dev_err(&client->dev, "flisclk failed\n");
@@ -765,6 +599,7 @@ static int power_down(struct v4l2_subdev *sd)
if (ret)
dev_err(&client->dev, "vprog failed.\n");
+ dev->power_on = 0;
return ret;
}
@@ -824,7 +659,6 @@ static int ov2722_set_fmt(struct v4l2_subdev *sd,
if (!ov2722_info)
return -EINVAL;
- mutex_lock(&dev->input_lock);
res = v4l2_find_nearest_size(ov2722_res_preview,
ARRAY_SIZE(ov2722_res_preview), width,
height, fmt->width, fmt->height);
@@ -838,10 +672,13 @@ static int ov2722_set_fmt(struct v4l2_subdev *sd,
fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
sd_state->pads->try_fmt = *fmt;
- mutex_unlock(&dev->input_lock);
return 0;
}
+ mutex_lock(&dev->input_lock);
+
+ /* s_power has not been called yet for std v4l2 clients (camorama) */
+ power_up(sd);
dev->pixels_per_line = dev->res->pixels_per_line;
dev->lines_per_frame = dev->res->lines_per_frame;
@@ -875,10 +712,6 @@ static int ov2722_set_fmt(struct v4l2_subdev *sd,
}
}
- ret = ov2722_get_intg_factor(client, ov2722_info, dev->res);
- if (ret)
- dev_err(&client->dev, "failed to get integration_factor\n");
-
err:
mutex_unlock(&dev->input_lock);
return ret;
@@ -1137,6 +970,7 @@ static int ov2722_probe(struct i2c_client *client)
return -ENOMEM;
mutex_init(&dev->input_lock);
+ dev->power_on = -1;
dev->res = &ov2722_res_preview[0];
v4l2_i2c_subdev_init(&dev->sd, client, &ov2722_ops);
@@ -1168,6 +1002,7 @@ out_ctrl_handler_free:
v4l2_ctrl_handler_free(&dev->ctrl_handler);
out_free:
+ atomisp_gmin_remove_subdev(&dev->sd);
v4l2_device_unregister_subdev(&dev->sd);
kfree(dev);
return ret;
diff --git a/drivers/staging/media/atomisp/i2c/gc0310.h b/drivers/staging/media/atomisp/i2c/gc0310.h
index 4b9ce681bd93..cae480ae6fba 100644
--- a/drivers/staging/media/atomisp/i2c/gc0310.h
+++ b/drivers/staging/media/atomisp/i2c/gc0310.h
@@ -38,9 +38,6 @@
#define I2C_RETRY_COUNT 5
#define GC0310_FOCAL_LENGTH_NUM 278 /*2.78mm*/
-#define GC0310_FOCAL_LENGTH_DEM 100
-#define GC0310_F_NUMBER_DEFAULT_NUM 26
-#define GC0310_F_NUMBER_DEM 10
#define MAX_FMTS 1
@@ -126,9 +123,6 @@ struct gc0310_resolution {
u32 skip_frames;
u16 pixels_per_line;
u16 lines_per_frame;
- u8 bin_factor_x;
- u8 bin_factor_y;
- u8 bin_mode;
bool used;
};
@@ -149,7 +143,6 @@ struct gc0310_device {
struct v4l2_ctrl_handler ctrl_handler;
struct camera_sensor_platform_data *platform_data;
- int vt_pix_clk_freq_mhz;
struct gc0310_resolution *res;
u8 type;
bool power_on;
@@ -390,9 +383,6 @@ static struct gc0310_resolution gc0310_res_preview[] = {
.pixels_per_line = 0x0314,
.lines_per_frame = 0x0213,
#endif
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.skip_frames = 2,
.regs = gc0310_VGA_30fps,
},
diff --git a/drivers/staging/media/atomisp/i2c/gc2235.h b/drivers/staging/media/atomisp/i2c/gc2235.h
index 806be5dff7a5..55ea422291ba 100644
--- a/drivers/staging/media/atomisp/i2c/gc2235.h
+++ b/drivers/staging/media/atomisp/i2c/gc2235.h
@@ -44,9 +44,6 @@
#define I2C_RETRY_COUNT 5
#define GC2235_FOCAL_LENGTH_NUM 278 /*2.78mm*/
-#define GC2235_FOCAL_LENGTH_DEM 100
-#define GC2235_F_NUMBER_DEFAULT_NUM 26
-#define GC2235_F_NUMBER_DEM 10
#define MAX_FMTS 1
@@ -137,9 +134,6 @@ struct gc2235_resolution {
u32 skip_frames;
u16 pixels_per_line;
u16 lines_per_frame;
- u8 bin_factor_x;
- u8 bin_factor_y;
- u8 bin_mode;
bool used;
};
@@ -161,7 +155,6 @@ struct gc2235_device {
struct gc2235_resolution *res;
struct camera_sensor_platform_data *platform_data;
- int vt_pix_clk_freq_mhz;
u8 type;
};
@@ -540,9 +533,6 @@ static struct gc2235_resolution gc2235_res_preview[] = {
.used = 0,
.pixels_per_line = 2132,
.lines_per_frame = 1068,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
.skip_frames = 3,
.regs = gc2235_1600_900_30fps,
},
@@ -556,9 +546,6 @@ static struct gc2235_resolution gc2235_res_preview[] = {
.used = 0,
.pixels_per_line = 2132,
.lines_per_frame = 1368,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
.skip_frames = 3,
.regs = gc2235_1616_1082_30fps,
},
@@ -571,9 +558,6 @@ static struct gc2235_resolution gc2235_res_preview[] = {
.used = 0,
.pixels_per_line = 2132,
.lines_per_frame = 1368,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
.skip_frames = 3,
.regs = gc2235_1616_1216_30fps,
},
@@ -597,9 +581,6 @@ static struct gc2235_resolution gc2235_res_still[] = {
.used = 0,
.pixels_per_line = 2132,
.lines_per_frame = 1068,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
.skip_frames = 3,
.regs = gc2235_1600_900_30fps,
},
@@ -612,9 +593,6 @@ static struct gc2235_resolution gc2235_res_still[] = {
.used = 0,
.pixels_per_line = 2132,
.lines_per_frame = 1368,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
.skip_frames = 3,
.regs = gc2235_1616_1082_30fps,
},
@@ -627,9 +605,6 @@ static struct gc2235_resolution gc2235_res_still[] = {
.used = 0,
.pixels_per_line = 2132,
.lines_per_frame = 1368,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
.skip_frames = 3,
.regs = gc2235_1616_1216_30fps,
},
@@ -648,9 +623,6 @@ static struct gc2235_resolution gc2235_res_video[] = {
.used = 0,
.pixels_per_line = 1828,
.lines_per_frame = 888,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
.skip_frames = 3,
.regs = gc2235_1296_736_30fps,
},
@@ -663,9 +635,6 @@ static struct gc2235_resolution gc2235_res_video[] = {
.used = 0,
.pixels_per_line = 1492,
.lines_per_frame = 792,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
.skip_frames = 3,
.regs = gc2235_960_640_30fps,
},
diff --git a/drivers/staging/media/atomisp/i2c/mt9m114.h b/drivers/staging/media/atomisp/i2c/mt9m114.h
index bcce18b65fa6..b0cd1b724394 100644
--- a/drivers/staging/media/atomisp/i2c/mt9m114.h
+++ b/drivers/staging/media/atomisp/i2c/mt9m114.h
@@ -136,9 +136,6 @@
#define MT9M114_BPAT_BGBGGRGR BIT(3)
#define MT9M114_FOCAL_LENGTH_NUM 208 /*2.08mm*/
-#define MT9M114_FOCAL_LENGTH_DEM 100
-#define MT9M114_F_NUMBER_DEFAULT_NUM 24
-#define MT9M114_F_NUMBER_DEM 10
#define MT9M114_WAIT_STAT_TIMEOUT 100
#define MT9M114_FLICKER_MODE_50HZ 1
#define MT9M114_FLICKER_MODE_60HZ 2
@@ -319,9 +316,6 @@ struct mt9m114_res_struct {
struct regval_list *regs;
u16 pixels_per_line;
u16 lines_per_frame;
- u8 bin_factor_x;
- u8 bin_factor_y;
- u8 bin_mode;
};
/* 2 bytes used for address: 256 bytes total */
@@ -353,9 +347,6 @@ static struct mt9m114_res_struct mt9m114_res[] = {
.pixels_per_line = 0x0640,
.lines_per_frame = 0x0307,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
},
{
.desc = "848P",
@@ -369,9 +360,6 @@ static struct mt9m114_res_struct mt9m114_res[] = {
.pixels_per_line = 0x0640,
.lines_per_frame = 0x03E8,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
},
{
.desc = "960P",
@@ -385,9 +373,6 @@ static struct mt9m114_res_struct mt9m114_res[] = {
.pixels_per_line = 0x0644, /* consistent with regs arrays */
.lines_per_frame = 0x03E5, /* consistent with regs arrays */
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
},
};
diff --git a/drivers/staging/media/atomisp/i2c/ov2680.h b/drivers/staging/media/atomisp/i2c/ov2680.h
index 7ab337b859ad..a37af0a74a53 100644
--- a/drivers/staging/media/atomisp/i2c/ov2680.h
+++ b/drivers/staging/media/atomisp/i2c/ov2680.h
@@ -32,53 +32,22 @@
#include "../include/linux/atomisp_platform.h"
-/* Defines for register writes and register array processing */
-#define I2C_MSG_LENGTH 0x2
-#define I2C_RETRY_COUNT 5
+#define OV2680_NATIVE_WIDTH 1616
+#define OV2680_NATIVE_HEIGHT 1216
-#define OV2680_FOCAL_LENGTH_NUM 334 /*3.34mm*/
-#define OV2680_FOCAL_LENGTH_DEM 100
-#define OV2680_F_NUMBER_DEFAULT_NUM 24
-#define OV2680_F_NUMBER_DEM 10
+/* 1704 * 1294 * 30fps = 66MHz pixel clock */
+#define OV2680_PIXELS_PER_LINE 1704
+#define OV2680_LINES_PER_FRAME 1294
+#define OV2680_FPS 30
+#define OV2680_SKIP_FRAMES 3
-#define OV2680_BIN_FACTOR_MAX 4
+/* If possible send 16 extra rows / lines to the ISP as padding */
+#define OV2680_END_MARGIN 16
-#define MAX_FMTS 1
+#define OV2680_FOCAL_LENGTH_NUM 334 /*3.34mm*/
-/* sensor_mode_data read_mode adaptation */
-#define OV2680_READ_MODE_BINNING_ON 0x0400
-#define OV2680_READ_MODE_BINNING_OFF 0x00
-#define OV2680_INTEGRATION_TIME_MARGIN 8
-
-#define OV2680_MAX_EXPOSURE_VALUE 0xFFF1
-#define OV2680_MAX_GAIN_VALUE 0xFF
-
-/*
- * focal length bits definition:
- * bits 31-16: numerator, bits 15-0: denominator
- */
-#define OV2680_FOCAL_LENGTH_DEFAULT 0x1B70064
-
-/*
- * current f-number bits definition:
- * bits 31-16: numerator, bits 15-0: denominator
- */
-#define OV2680_F_NUMBER_DEFAULT 0x18000a
-
-/*
- * f-number range bits definition:
- * bits 31-24: max f-number numerator
- * bits 23-16: max f-number denominator
- * bits 15-8: min f-number numerator
- * bits 7-0: min f-number denominator
- */
-#define OV2680_F_NUMBER_RANGE 0x180a180a
-#define OV2680_ID 0x2680
-
-#define OV2680_FINE_INTG_TIME_MIN 0
-#define OV2680_FINE_INTG_TIME_MAX_MARGIN 0
-#define OV2680_COARSE_INTG_TIME_MIN 1
-#define OV2680_COARSE_INTG_TIME_MAX_MARGIN 6
+#define OV2680_INTEGRATION_TIME_MARGIN 8
+#define OV2680_ID 0x2680
/*
* OV2680 System control registers
@@ -92,74 +61,49 @@
#define OV2680_SC_CMMN_SCCB_ID 0x302B /* 0x300C*/
#define OV2680_SC_CMMN_SUB_ID 0x302A /* process, version*/
-#define OV2680_GROUP_ACCESS 0x3208 /*Bit[7:4] Group control, Bit[3:0] Group ID*/
-
-#define OV2680_EXPOSURE_H 0x3500 /*Bit[3:0] Bit[19:16] of exposure, remaining 16 bits lies in Reg0x3501&Reg0x3502*/
-#define OV2680_EXPOSURE_M 0x3501
-#define OV2680_EXPOSURE_L 0x3502
-#define OV2680_AGC_H 0x350A /*Bit[1:0] means Bit[9:8] of gain*/
-#define OV2680_AGC_L 0x350B /*Bit[7:0] of gain*/
-
-#define OV2680_HORIZONTAL_START_H 0x3800 /*Bit[11:8]*/
-#define OV2680_HORIZONTAL_START_L 0x3801 /*Bit[7:0]*/
-#define OV2680_VERTICAL_START_H 0x3802 /*Bit[11:8]*/
-#define OV2680_VERTICAL_START_L 0x3803 /*Bit[7:0]*/
-#define OV2680_HORIZONTAL_END_H 0x3804 /*Bit[11:8]*/
-#define OV2680_HORIZONTAL_END_L 0x3805 /*Bit[7:0]*/
-#define OV2680_VERTICAL_END_H 0x3806 /*Bit[11:8]*/
-#define OV2680_VERTICAL_END_L 0x3807 /*Bit[7:0]*/
-#define OV2680_HORIZONTAL_OUTPUT_SIZE_H 0x3808 /*Bit[3:0]*/
-#define OV2680_HORIZONTAL_OUTPUT_SIZE_L 0x3809 /*Bit[7:0]*/
-#define OV2680_VERTICAL_OUTPUT_SIZE_H 0x380a /*Bit[3:0]*/
-#define OV2680_VERTICAL_OUTPUT_SIZE_L 0x380b /*Bit[7:0]*/
-#define OV2680_TIMING_HTS_H 0x380C /*High 8-bit, and low 8-bit HTS address is 0x380d*/
-#define OV2680_TIMING_HTS_L 0x380D /*High 8-bit, and low 8-bit HTS address is 0x380d*/
-#define OV2680_TIMING_VTS_H 0x380e /*High 8-bit, and low 8-bit HTS address is 0x380f*/
-#define OV2680_TIMING_VTS_L 0x380f /*High 8-bit, and low 8-bit HTS address is 0x380f*/
-#define OV2680_FRAME_OFF_NUM 0x4202
+#define OV2680_GROUP_ACCESS 0x3208 /*Bit[7:4] Group control, Bit[3:0] Group ID*/
+
+#define OV2680_REG_EXPOSURE_PK_HIGH 0x3500
+#define OV2680_REG_GAIN_PK 0x350a
+
+#define OV2680_HORIZONTAL_START_H 0x3800 /* Bit[11:8] */
+#define OV2680_HORIZONTAL_START_L 0x3801 /* Bit[7:0] */
+#define OV2680_VERTICAL_START_H 0x3802 /* Bit[11:8] */
+#define OV2680_VERTICAL_START_L 0x3803 /* Bit[7:0] */
+#define OV2680_HORIZONTAL_END_H 0x3804 /* Bit[11:8] */
+#define OV2680_HORIZONTAL_END_L 0x3805 /* Bit[7:0] */
+#define OV2680_VERTICAL_END_H 0x3806 /* Bit[11:8] */
+#define OV2680_VERTICAL_END_L 0x3807 /* Bit[7:0] */
+#define OV2680_HORIZONTAL_OUTPUT_SIZE_H 0x3808 /* Bit[11:8] */
+#define OV2680_HORIZONTAL_OUTPUT_SIZE_L 0x3809 /* Bit[7:0] */
+#define OV2680_VERTICAL_OUTPUT_SIZE_H 0x380a /* Bit[11:8] */
+#define OV2680_VERTICAL_OUTPUT_SIZE_L 0x380b /* Bit[7:0] */
+#define OV2680_HTS 0x380c
+#define OV2680_VTS 0x380e
+#define OV2680_ISP_X_WIN 0x3810
+#define OV2680_ISP_Y_WIN 0x3812
+#define OV2680_X_INC 0x3814
+#define OV2680_Y_INC 0x3815
+
+#define OV2680_FRAME_OFF_NUM 0x4202
/*Flip/Mirror*/
-#define OV2680_FLIP_REG 0x3820
-#define OV2680_MIRROR_REG 0x3821
-#define OV2680_FLIP_BIT 1
-#define OV2680_MIRROR_BIT 2
-#define OV2680_FLIP_MIRROR_BIT_ENABLE 4
+#define OV2680_REG_FORMAT1 0x3820
+#define OV2680_REG_FORMAT2 0x3821
#define OV2680_MWB_RED_GAIN_H 0x5004/*0x3400*/
#define OV2680_MWB_GREEN_GAIN_H 0x5006/*0x3402*/
#define OV2680_MWB_BLUE_GAIN_H 0x5008/*0x3404*/
-#define OV2680_MWB_GAIN_MAX 0x0fff
-
-#define OV2680_START_STREAMING 0x01
-#define OV2680_STOP_STREAMING 0x00
-
-#define OV2680_INVALID_CONFIG 0xffffffff
+#define OV2680_MWB_GAIN_MAX 0x0fff
-struct regval_list {
- u16 reg_num;
- u8 value;
-};
+#define OV2680_REG_ISP_CTRL00 0x5080
-struct ov2680_resolution {
- const struct ov2680_reg *regs;
- int res;
- int width;
- int height;
- int fps;
- int pix_clk_freq;
- u32 skip_frames;
- u16 pixels_per_line;
- u16 lines_per_frame;
- u8 bin_factor_x;
- u8 bin_factor_y;
- u8 bin_mode;
-};
+#define OV2680_X_WIN 0x5704
+#define OV2680_Y_WIN 0x5706
+#define OV2680_WIN_CONTROL 0x5708
-struct ov2680_format {
- u8 *desc;
- u32 pixelformat;
- struct ov2680_reg *regs;
-};
+#define OV2680_START_STREAMING 0x01
+#define OV2680_STOP_STREAMING 0x00
/*
* ov2680 device structure.
@@ -168,13 +112,32 @@ struct ov2680_device {
struct v4l2_subdev sd;
struct media_pad pad;
struct mutex input_lock;
- struct v4l2_ctrl_handler ctrl_handler;
- struct ov2680_resolution *res;
- struct camera_sensor_platform_data *platform_data;
- bool power_on;
- u16 exposure;
- u16 gain;
- u16 digitgain;
+ struct i2c_client *client;
+ struct gpio_desc *powerdown;
+ struct gpio_desc *powerdown_alt;
+ bool is_streaming;
+
+ struct ov2680_mode {
+ struct v4l2_mbus_framefmt fmt;
+ bool binning;
+ u16 h_start;
+ u16 v_start;
+ u16 h_end;
+ u16 v_end;
+ u16 h_output_size;
+ u16 v_output_size;
+ u16 hts;
+ u16 vts;
+ } mode;
+
+ struct ov2680_ctrls {
+ struct v4l2_ctrl_handler handler;
+ struct v4l2_ctrl *hflip;
+ struct v4l2_ctrl *vflip;
+ struct v4l2_ctrl *exposure;
+ struct v4l2_ctrl *gain;
+ struct v4l2_ctrl *test_pattern;
+ } ctrls;
};
/**
@@ -192,17 +155,13 @@ struct ov2680_reg {
#define to_ov2680_sensor(x) container_of(x, struct ov2680_device, sd)
-#define OV2680_MAX_WRITE_BUF_SIZE 30
+static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
+{
+ struct ov2680_device *sensor =
+ container_of(ctrl->handler, struct ov2680_device, ctrls.handler);
-struct ov2680_write_buffer {
- u16 addr;
- u8 data[OV2680_MAX_WRITE_BUF_SIZE];
-};
-
-struct ov2680_write_ctrl {
- int index;
- struct ov2680_write_buffer buffer;
-};
+ return &sensor->sd;
+}
static struct ov2680_reg const ov2680_global_setting[] = {
{0x0103, 0x01},
@@ -240,6 +199,8 @@ static struct ov2680_reg const ov2680_global_setting[] = {
{0x3819, 0x04},
{0x4000, 0x81},
{0x4001, 0x40},
+ {0x4008, 0x00},
+ {0x4009, 0x03},
{0x4602, 0x02},
{0x481f, 0x36},
{0x4825, 0x36},
@@ -252,6 +213,8 @@ static struct ov2680_reg const ov2680_global_setting[] = {
{0x5008, 0x04},
{0x5009, 0x00},
{0x5080, 0x00},
+ {0x5081, 0x41},
+ {0x5708, 0x01}, /* add for full size flip off and mirror off 2014/09/11 */
{0x3701, 0x64}, //add on 14/05/13
{0x3784, 0x0c}, //based OV2680_R1A_AM10.ovt add on 14/06/13
{0x5780, 0x3e}, //based OV2680_R1A_AM10.ovt,Adjust DPC setting (57xx) on 14/06/13
@@ -276,642 +239,7 @@ static struct ov2680_reg const ov2680_global_setting[] = {
{0x5793, 0x00},
{0x5794, 0x03}, //based OV2680_R1A_AM10.ovt,Adjust DPC setting (57xx) on 14/06/13
{0x0100, 0x00}, //stream off
-
- {}
-};
-
-/*
- * 176x144 30fps VBlanking 1lane 10Bit (binning)
- */
-static struct ov2680_reg const ov2680_QCIF_30fps[] = {
- {0x3086, 0x01},
- {0x370a, 0x23},
- {0x3801, 0xa0},
- {0x3802, 0x00},
- {0x3803, 0x78},
- {0x3804, 0x05},
- {0x3805, 0xaf},
- {0x3806, 0x04},
- {0x3807, 0x47},
- {0x3808, 0x00},
- {0x3809, 0xC0},
- {0x380a, 0x00},
- {0x380b, 0xa0},
- {0x380c, 0x06},
- {0x380d, 0xb0},
- {0x3810, 0x00},
- {0x3811, 0x04},
- {0x3812, 0x00},
- {0x3813, 0x04},
- {0x3814, 0x31},
- {0x3815, 0x31},
- {0x4000, 0x81},
- {0x4001, 0x40},
- {0x4008, 0x00},
- {0x4009, 0x03},
- {0x5081, 0x41},
- {0x5708, 0x00}, //add for full size flip off and mirror off 2014/09/11
- {0x5704, 0x10},
- {0x5705, 0xa0},
- {0x5706, 0x0c},
- {0x5707, 0x78},
- {0x3820, 0xc2},
- {0x3821, 0x01},
- // {0x5090, 0x0c},
- {}
-};
-
-/*
- * 352x288 30fps VBlanking 1lane 10Bit (binning)
- */
-static struct ov2680_reg const ov2680_CIF_30fps[] = {
- {0x3086, 0x01},
- {0x370a, 0x23},
- {0x3801, 0xa0},
- {0x3802, 0x00},
- {0x3803, 0x78},
- {0x3804, 0x03},
- {0x3805, 0x8f},
- {0x3806, 0x02},
- {0x3807, 0xe7},
- {0x3808, 0x01},
- {0x3809, 0x70},
- {0x380a, 0x01},
- {0x380b, 0x30},
- {0x380c, 0x06},
- {0x380d, 0xb0},
- {0x3810, 0x00},
- {0x3811, 0x04},
- {0x3812, 0x00},
- {0x3813, 0x04},
- {0x3814, 0x31},
- {0x3815, 0x31},
- {0x4008, 0x00},
- {0x4009, 0x03},
- {0x5081, 0x41},
- {0x5708, 0x00}, //add for full size flip off and mirror off 2014/09/11
- {0x5704, 0x10},
- {0x5705, 0xa0},
- {0x5706, 0x0c},
- {0x5707, 0x78},
- {0x3820, 0xc2},
- {0x3821, 0x01},
- // {0x5090, 0x0c},
{}
};
-/*
- * 336x256 30fps VBlanking 1lane 10Bit (binning)
- */
-static struct ov2680_reg const ov2680_QVGA_30fps[] = {
- {0x3086, 0x01},
- {0x370a, 0x23},
- {0x3801, 0xa0},
- {0x3802, 0x00},
- {0x3803, 0x78},
- {0x3804, 0x03},
- {0x3805, 0x4f},
- {0x3806, 0x02},
- {0x3807, 0x87},
- {0x3808, 0x01},
- {0x3809, 0x50},
- {0x380a, 0x01},
- {0x380b, 0x00},
- {0x380c, 0x06},
- {0x380d, 0xb0},
- {0x3810, 0x00},
- {0x3811, 0x04},
- {0x3812, 0x00},
- {0x3813, 0x04},
- {0x3814, 0x31},
- {0x3815, 0x31},
- {0x4008, 0x00},
- {0x4009, 0x03},
- {0x5081, 0x41},
- {0x5708, 0x00}, //add for full size flip off and mirror off 2014/09/11
- {0x5704, 0x10},
- {0x5705, 0xa0},
- {0x5706, 0x0c},
- {0x5707, 0x78},
- {0x3820, 0xc2},
- {0x3821, 0x01},
- // {0x5090, 0x0c},
- {}
-};
-
-/*
- * 656x496 30fps VBlanking 1lane 10Bit (binning)
- */
-static struct ov2680_reg const ov2680_656x496_30fps[] = {
- {0x3086, 0x01},
- {0x370a, 0x23},
- {0x3801, 0xa0},
- {0x3802, 0x00},
- {0x3803, 0x78},
- {0x3804, 0x05},
- {0x3805, 0xcf},
- {0x3806, 0x04},
- {0x3807, 0x67},
- {0x3808, 0x02},
- {0x3809, 0x90},
- {0x380a, 0x01},
- {0x380b, 0xf0},
- {0x380c, 0x06},
- {0x380d, 0xb0},
- {0x3810, 0x00},
- {0x3811, 0x04},
- {0x3812, 0x00},
- {0x3813, 0x04},
- {0x3814, 0x31},
- {0x3815, 0x31},
- {0x4008, 0x00},
- {0x4009, 0x03},
- {0x5081, 0x41},
- {0x5708, 0x00}, //add for full size flip off and mirror off 2014/09/11
- {0x5704, 0x10},
- {0x5705, 0xa0},
- {0x5706, 0x0c},
- {0x5707, 0x78},
- {0x3820, 0xc2},
- {0x3821, 0x01},
- // {0x5090, 0x0c},
- {}
-};
-
-/*
- * 720x592 30fps VBlanking 1lane 10Bit (binning)
- */
-static struct ov2680_reg const ov2680_720x592_30fps[] = {
- {0x3086, 0x01},
- {0x370a, 0x23},
- {0x3801, 0x00}, // X_ADDR_START;
- {0x3802, 0x00},
- {0x3803, 0x00}, // Y_ADDR_START;
- {0x3804, 0x05},
- {0x3805, 0xaf}, // X_ADDR_END;
- {0x3806, 0x04},
- {0x3807, 0xaf}, // Y_ADDR_END;
- {0x3808, 0x02},
- {0x3809, 0xd0}, // X_OUTPUT_SIZE;
- {0x380a, 0x02},
- {0x380b, 0x50}, // Y_OUTPUT_SIZE;
- {0x380c, 0x06},
- {0x380d, 0xac}, // HTS;
- {0x3810, 0x00},
- {0x3811, 0x00},
- {0x3812, 0x00},
- {0x3813, 0x00},
- {0x3814, 0x31},
- {0x3815, 0x31},
- {0x4008, 0x00},
- {0x4009, 0x03},
- {0x5708, 0x00},
- {0x5704, 0x02},
- {0x5705, 0xd0}, // X_WIN;
- {0x5706, 0x02},
- {0x5707, 0x50}, // Y_WIN;
- {0x3820, 0xc2}, // FLIP_FORMAT;
- {0x3821, 0x01}, // MIRROR_FORMAT;
- {0x5090, 0x00}, // PRE ISP CTRL16, default value is 0x0C;
- // BIT[3]: Mirror order, BG or GB;
- // BIT[2]: Flip order, BR or RB;
- {0x5081, 0x41},
- {}
-};
-
-/*
- * 800x600 30fps VBlanking 1lane 10Bit (binning)
- */
-static struct ov2680_reg const ov2680_800x600_30fps[] = {
- {0x3086, 0x01},
- {0x370a, 0x23},
- {0x3801, 0x00}, /* hstart 0 */
- {0x3802, 0x00},
- {0x3803, 0x00}, /* vstart 0 */
- {0x3804, 0x06},
- {0x3805, 0x4f}, /* hend 1615 */
- {0x3806, 0x04},
- {0x3807, 0xbf}, /* vend 1215 */
- {0x3808, 0x03},
- {0x3809, 0x20}, /* hsize 800 */
- {0x380a, 0x02},
- {0x380b, 0x58}, /* vsize 600 */
- {0x380c, 0x06},
- {0x380d, 0xac}, /* htotal 1708 */
- {0x3810, 0x00},
- {0x3811, 0x00},
- {0x3812, 0x00},
- {0x3813, 0x00},
- {0x3814, 0x31},
- {0x3815, 0x31},
- {0x5708, 0x00},
- {0x5704, 0x03},
- {0x5705, 0x20},
- {0x5706, 0x02},
- {0x5707, 0x58},
- {0x3820, 0xc2},
- {0x3821, 0x01},
- {0x5090, 0x00},
- {0x4008, 0x00},
- {0x4009, 0x03},
- {0x5081, 0x41},
- {}
-};
-
-/*
- * 720p=1280*720 30fps VBlanking 1lane 10Bit (no-Scaling)
- */
-static struct ov2680_reg const ov2680_720p_30fps[] = {
- {0x3086, 0x00},
- {0x370a, 0x21},
- {0x3801, 0xa0}, /* hstart 160 */
- {0x3802, 0x00},
- {0x3803, 0xf2}, /* vstart 242 */
- {0x3804, 0x05},
- {0x3805, 0xbf}, /* hend 1471 */
- {0x3806, 0x03},
- {0x3807, 0xdd}, /* vend 989 */
- {0x3808, 0x05},
- {0x3809, 0x10}, /* hsize 1296 */
- {0x380a, 0x02},
- {0x380b, 0xe0}, /* vsize 736 */
- {0x380c, 0x06},
- {0x380d, 0xa8}, /* htotal 1704 */
- {0x3810, 0x00},
- {0x3811, 0x08},
- {0x3812, 0x00},
- {0x3813, 0x06},
- {0x3814, 0x11},
- {0x3815, 0x11},
- {0x4008, 0x02},
- {0x4009, 0x09},
- {0x5081, 0x41},
- {0x5708, 0x00}, //add for full size flip off and mirror off 2014/09/11
- {0x5704, 0x10},
- {0x5705, 0xa0},
- {0x5706, 0x0c},
- {0x5707, 0x78},
- {0x3820, 0xc0},
- {0x3821, 0x00},
- // {0x5090, 0x0c},
- {}
-};
-
-/*
- * 1296x976 30fps VBlanking 1lane 10Bit(no-scaling)
- */
-static struct ov2680_reg const ov2680_1296x976_30fps[] = {
- {0x3086, 0x00},
- {0x370a, 0x21},
- {0x3801, 0xa0}, /* hstart 160 */
- {0x3802, 0x00},
- {0x3803, 0x78}, /* vstart 120 */
- {0x3804, 0x05},
- {0x3805, 0xbf}, /* hend 1471 */
- {0x3806, 0x04},
- {0x3807, 0x57}, /* vend 1111 */
- {0x3808, 0x05},
- {0x3809, 0x10}, /* hsize 1296 */
- {0x380a, 0x03},
- {0x380b, 0xd0}, /* vsize 976 */
- {0x380c, 0x06},
- {0x380d, 0xa8}, /* htotal 1704 */
- {0x3810, 0x00},
- {0x3811, 0x08},
- {0x3812, 0x00},
- {0x3813, 0x08},
- {0x3814, 0x11},
- {0x3815, 0x11},
- {0x4008, 0x02},
- {0x4009, 0x09},
- {0x5081, 0x41},
- {0x5708, 0x00}, //add for full size flip off and mirror off 2014/09/11
- {0x5704, 0x10},
- {0x5705, 0xa0},
- {0x5706, 0x0c},
- {0x5707, 0x78},
- {0x3820, 0xc0},
- {0x3821, 0x00}, //mirror/flip
- // {0x5090, 0x0c},
- {}
-};
-
-/*
- * 1456*1096 30fps VBlanking 1lane 10bit(no-scaling)
- */
-static struct ov2680_reg const ov2680_1456x1096_30fps[] = {
- {0x3086, 0x00},
- {0x370a, 0x21},
- {0x3801, 0x90},
- {0x3802, 0x00},
- {0x3803, 0x78},
- {0x3804, 0x06},
- {0x3805, 0x4f},
- {0x3806, 0x04},
- {0x3807, 0xC0},
- {0x3808, 0x05},
- {0x3809, 0xb0},
- {0x380a, 0x04},
- {0x380b, 0x48},
- {0x380c, 0x06},
- {0x380d, 0xa8},
- {0x3810, 0x00},
- {0x3811, 0x08},
- {0x3812, 0x00},
- {0x3813, 0x00},
- {0x3814, 0x11},
- {0x3815, 0x11},
- {0x4008, 0x02},
- {0x4009, 0x09},
- {0x5081, 0x41},
- {0x5708, 0x00}, //add for full size flip off and mirror off 2014/09/11
- {0x5704, 0x10},
- {0x5705, 0xa0},
- {0x5706, 0x0c},
- {0x5707, 0x78},
- {0x3820, 0xc0},
- {0x3821, 0x00},
- // {0x5090, 0x0c},
- {}
-};
-
-/*
- *1616x916 30fps VBlanking 1lane 10bit
- */
-
-static struct ov2680_reg const ov2680_1616x916_30fps[] = {
- {0x3086, 0x00},
- {0x370a, 0x21},
- {0x3801, 0x00},
- {0x3802, 0x00},
- {0x3803, 0x96},
- {0x3804, 0x06},
- {0x3805, 0x4f},
- {0x3806, 0x04},
- {0x3807, 0x39},
- {0x3808, 0x06},
- {0x3809, 0x50},
- {0x380a, 0x03},
- {0x380b, 0x94},
- {0x380c, 0x06},
- {0x380d, 0xa8},
- {0x3810, 0x00},
- {0x3811, 0x00},
- {0x3812, 0x00},
- {0x3813, 0x08},
- {0x3814, 0x11},
- {0x3815, 0x11},
- {0x4008, 0x02},
- {0x4009, 0x09},
- {0x5081, 0x41},
- {0x5708, 0x01}, //add for full size flip off and mirror off 2014/09/11
- {0x5704, 0x06},
- {0x5705, 0x50},
- {0x5706, 0x03},
- {0x5707, 0x94},
- {0x3820, 0xc0},
- {0x3821, 0x00},
- // {0x5090, 0x0C},
- {}
-};
-
-/*
- * 1616x1082 30fps VBlanking 1lane 10Bit
- */
-static struct ov2680_reg const ov2680_1616x1082_30fps[] = {
- {0x3086, 0x00},
- {0x370a, 0x21},
- {0x3801, 0x00},
- {0x3802, 0x00},
- {0x3803, 0x86},
- {0x3804, 0x06},
- {0x3805, 0x4f},
- {0x3806, 0x04},
- {0x3807, 0xbf},
- {0x3808, 0x06},
- {0x3809, 0x50},
- {0x380a, 0x04},
- {0x380b, 0x3a},
- {0x380c, 0x06},
- {0x380d, 0xa8},
- {0x3810, 0x00},
- {0x3811, 0x00},
- {0x3812, 0x00},
- {0x3813, 0x00},
- {0x3814, 0x11},
- {0x3815, 0x11},
- {0x5708, 0x01}, //add for full size flip off and mirror off 2014/09/11
- {0x5704, 0x06},
- {0x5705, 0x50},
- {0x5706, 0x04},
- {0x5707, 0x3a},
- {0x3820, 0xc0},
- {0x3821, 0x00},
- // {0x5090, 0x0C},
- {0x4008, 0x02},
- {0x4009, 0x09},
- {0x5081, 0x41},
- {}
-};
-
-/*
- * 1616x1216 30fps VBlanking 1lane 10Bit
- */
-static struct ov2680_reg const ov2680_1616x1216_30fps[] = {
- {0x3086, 0x00},
- {0x370a, 0x21},
- {0x3801, 0x00},
- {0x3802, 0x00},
- {0x3803, 0x00},
- {0x3804, 0x06},
- {0x3805, 0x4f},
- {0x3806, 0x04},
- {0x3807, 0xbf},
- {0x3808, 0x06},
- {0x3809, 0x50},//50},//4line for mirror and flip
- {0x380a, 0x04},
- {0x380b, 0xc0},//c0},
- {0x380c, 0x06},
- {0x380d, 0xa8},
- {0x3810, 0x00},
- {0x3811, 0x00},
- {0x3812, 0x00},
- {0x3813, 0x00},
- {0x3814, 0x11},
- {0x3815, 0x11},
- {0x4008, 0x00},
- {0x4009, 0x0b},
- {0x5081, 0x01},
- {0x5708, 0x01}, //add for full size flip off and mirror off 2014/09/11
- {0x5704, 0x06},
- {0x5705, 0x50},
- {0x5706, 0x04},
- {0x5707, 0xcc},
- {0x3820, 0xc0},
- {0x3821, 0x00},
- // {0x5090, 0x0C},
- {}
-};
-
-static struct ov2680_resolution ov2680_res_preview[] = {
- {
- .width = 1616,
- .height = 1216,
- .pix_clk_freq = 66,
- .fps = 30,
- .pixels_per_line = 1698,//1704,
- .lines_per_frame = 1294,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
- .skip_frames = 3,
- .regs = ov2680_1616x1216_30fps,
- },
- {
- .width = 1616,
- .height = 1082,
- .pix_clk_freq = 66,
- .fps = 30,
- .pixels_per_line = 1698,//1704,
- .lines_per_frame = 1294,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
- .skip_frames = 3,
- .regs = ov2680_1616x1082_30fps,
- },
- {
- .width = 1616,
- .height = 916,
- .fps = 30,
- .pix_clk_freq = 66,
- .pixels_per_line = 1698,//1704,
- .lines_per_frame = 1294,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
- .skip_frames = 3,
- .regs = ov2680_1616x916_30fps,
- },
- {
- .width = 1456,
- .height = 1096,
- .fps = 30,
- .pix_clk_freq = 66,
- .pixels_per_line = 1698,//1704,
- .lines_per_frame = 1294,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
- .skip_frames = 3,
- .regs = ov2680_1456x1096_30fps,
- },
- {
- .width = 1296,
- .height = 976,
- .fps = 30,
- .pix_clk_freq = 66,
- .pixels_per_line = 1698,//1704,
- .lines_per_frame = 1294,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
- .skip_frames = 3,
- .regs = ov2680_1296x976_30fps,
- },
- {
- .width = 1296,
- .height = 736,
- .fps = 60,
- .pix_clk_freq = 66,
- .pixels_per_line = 1698,//1704,
- .lines_per_frame = 1294,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
- .skip_frames = 3,
- .regs = ov2680_720p_30fps,
- },
- {
- .width = 800,
- .height = 600,
- .fps = 60,
- .pix_clk_freq = 66,
- .pixels_per_line = 1698,//1704,
- .lines_per_frame = 1294,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
- .skip_frames = 3,
- .regs = ov2680_800x600_30fps,
- },
- {
- .width = 720,
- .height = 592,
- .fps = 60,
- .pix_clk_freq = 66,
- .pixels_per_line = 1698,//1704,
- .lines_per_frame = 1294,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
- .skip_frames = 3,
- .regs = ov2680_720x592_30fps,
- },
- {
- .width = 656,
- .height = 496,
- .fps = 60,
- .pix_clk_freq = 66,
- .pixels_per_line = 1698,//1704,
- .lines_per_frame = 1294,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
- .skip_frames = 3,
- .regs = ov2680_656x496_30fps,
- },
- {
- .width = 336,
- .height = 256,
- .fps = 60,
- .pix_clk_freq = 66,
- .pixels_per_line = 1698,//1704,
- .lines_per_frame = 1294,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
- .skip_frames = 3,
- .regs = ov2680_QVGA_30fps,
- },
- {
- .width = 352,
- .height = 288,
- .fps = 60,
- .pix_clk_freq = 66,
- .pixels_per_line = 1698,//1704,
- .lines_per_frame = 1294,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
- .skip_frames = 3,
- .regs = ov2680_CIF_30fps,
- },
- {
- .width = 176,
- .height = 144,
- .fps = 60,
- .pix_clk_freq = 66,
- .pixels_per_line = 1698,//1704,
- .lines_per_frame = 1294,
- .bin_factor_x = 0,
- .bin_factor_y = 0,
- .bin_mode = 0,
- .skip_frames = 3,
- .regs = ov2680_QCIF_30fps,
- },
-};
-
-#define N_RES_PREVIEW (ARRAY_SIZE(ov2680_res_preview))
-
#endif
diff --git a/drivers/staging/media/atomisp/i2c/ov2722.h b/drivers/staging/media/atomisp/i2c/ov2722.h
index d6e2510bc01c..640d3ffcaa5c 100644
--- a/drivers/staging/media/atomisp/i2c/ov2722.h
+++ b/drivers/staging/media/atomisp/i2c/ov2722.h
@@ -39,9 +39,6 @@
#define I2C_RETRY_COUNT 5
#define OV2722_FOCAL_LENGTH_NUM 278 /*2.78mm*/
-#define OV2722_FOCAL_LENGTH_DEM 100
-#define OV2722_F_NUMBER_DEFAULT_NUM 26
-#define OV2722_F_NUMBER_DEM 10
#define MAX_FMTS 1
@@ -180,9 +177,6 @@ struct ov2722_resolution {
u32 skip_frames;
u16 pixels_per_line;
u16 lines_per_frame;
- u8 bin_factor_x;
- u8 bin_factor_y;
- u8 bin_mode;
bool used;
int mipi_freq;
};
@@ -204,8 +198,7 @@ struct ov2722_device {
struct ov2722_resolution *res;
struct camera_sensor_platform_data *platform_data;
- int vt_pix_clk_freq_mhz;
- int run_mode;
+ int power_on;
u16 pixels_per_line;
u16 lines_per_frame;
u8 type;
@@ -1113,9 +1106,6 @@ static struct ov2722_resolution ov2722_res_preview[] = {
.used = 0,
.pixels_per_line = 2260,
.lines_per_frame = 1244,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.skip_frames = 3,
.regs = ov2722_1632_1092_30fps,
.mipi_freq = 422400,
@@ -1129,9 +1119,6 @@ static struct ov2722_resolution ov2722_res_preview[] = {
.used = 0,
.pixels_per_line = 2260,
.lines_per_frame = 1244,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.skip_frames = 3,
.regs = ov2722_1452_1092_30fps,
.mipi_freq = 422400,
@@ -1145,9 +1132,6 @@ static struct ov2722_resolution ov2722_res_preview[] = {
.used = 0,
.pixels_per_line = 2068,
.lines_per_frame = 1114,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.skip_frames = 3,
.regs = ov2722_1080p_30fps,
.mipi_freq = 345600,
@@ -1171,9 +1155,6 @@ struct ov2722_resolution ov2722_res_still[] = {
.used = 0,
.pixels_per_line = 2260,
.lines_per_frame = 1244,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.skip_frames = 3,
.regs = ov2722_1632_1092_30fps,
.mipi_freq = 422400,
@@ -1187,9 +1168,6 @@ struct ov2722_resolution ov2722_res_still[] = {
.used = 0,
.pixels_per_line = 2260,
.lines_per_frame = 1244,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.skip_frames = 3,
.regs = ov2722_1452_1092_30fps,
.mipi_freq = 422400,
@@ -1203,9 +1181,6 @@ struct ov2722_resolution ov2722_res_still[] = {
.used = 0,
.pixels_per_line = 2068,
.lines_per_frame = 1114,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.skip_frames = 3,
.regs = ov2722_1080p_30fps,
.mipi_freq = 345600,
@@ -1224,9 +1199,6 @@ struct ov2722_resolution ov2722_res_video[] = {
.used = 0,
.pixels_per_line = 2048,
.lines_per_frame = 1184,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.skip_frames = 3,
.regs = ov2722_QVGA_30fps,
.mipi_freq = 364800,
@@ -1240,9 +1212,6 @@ struct ov2722_resolution ov2722_res_video[] = {
.used = 0,
.pixels_per_line = 2048,
.lines_per_frame = 1184,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.skip_frames = 3,
.regs = ov2722_480P_30fps,
},
@@ -1255,9 +1224,6 @@ struct ov2722_resolution ov2722_res_video[] = {
.used = 0,
.pixels_per_line = 2068,
.lines_per_frame = 1114,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.skip_frames = 3,
.regs = ov2722_1080p_30fps,
.mipi_freq = 345600,
diff --git a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c
index c1cd631455e6..da8c3b1d3bcd 100644
--- a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c
+++ b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c
@@ -415,123 +415,6 @@ static int ov5693_write_reg_array(struct i2c_client *client,
return __ov5693_flush_reg_array(client, &ctrl);
}
-static int ov5693_g_focal(struct v4l2_subdev *sd, s32 *val)
-{
- *val = (OV5693_FOCAL_LENGTH_NUM << 16) | OV5693_FOCAL_LENGTH_DEM;
- return 0;
-}
-
-static int ov5693_g_fnumber(struct v4l2_subdev *sd, s32 *val)
-{
- /*const f number for imx*/
- *val = (OV5693_F_NUMBER_DEFAULT_NUM << 16) | OV5693_F_NUMBER_DEM;
- return 0;
-}
-
-static int ov5693_g_fnumber_range(struct v4l2_subdev *sd, s32 *val)
-{
- *val = (OV5693_F_NUMBER_DEFAULT_NUM << 24) |
- (OV5693_F_NUMBER_DEM << 16) |
- (OV5693_F_NUMBER_DEFAULT_NUM << 8) | OV5693_F_NUMBER_DEM;
- return 0;
-}
-
-static int ov5693_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val)
-{
- struct ov5693_device *dev = to_ov5693_sensor(sd);
-
- *val = ov5693_res[dev->fmt_idx].bin_factor_x;
-
- return 0;
-}
-
-static int ov5693_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val)
-{
- struct ov5693_device *dev = to_ov5693_sensor(sd);
-
- *val = ov5693_res[dev->fmt_idx].bin_factor_y;
-
- return 0;
-}
-
-static int ov5693_get_intg_factor(struct i2c_client *client,
- struct camera_mipi_info *info,
- const struct ov5693_resolution *res)
-{
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct ov5693_device *dev = to_ov5693_sensor(sd);
- struct atomisp_sensor_mode_data *buf = &info->data;
- unsigned int pix_clk_freq_hz;
- u16 reg_val;
- int ret;
-
- if (!info)
- return -EINVAL;
-
- /* pixel clock */
- pix_clk_freq_hz = res->pix_clk_freq * 1000000;
-
- dev->vt_pix_clk_freq_mhz = pix_clk_freq_hz;
- buf->vt_pix_clk_freq_mhz = pix_clk_freq_hz;
-
- /* get integration time */
- buf->coarse_integration_time_min = OV5693_COARSE_INTG_TIME_MIN;
- buf->coarse_integration_time_max_margin =
- OV5693_COARSE_INTG_TIME_MAX_MARGIN;
-
- buf->fine_integration_time_min = OV5693_FINE_INTG_TIME_MIN;
- buf->fine_integration_time_max_margin =
- OV5693_FINE_INTG_TIME_MAX_MARGIN;
-
- buf->fine_integration_time_def = OV5693_FINE_INTG_TIME_MIN;
- buf->frame_length_lines = res->lines_per_frame;
- buf->line_length_pck = res->pixels_per_line;
- buf->read_mode = res->bin_mode;
-
- /* get the cropping and output resolution to ISP for this mode. */
- ret = ov5693_read_reg(client, OV5693_16BIT,
- OV5693_HORIZONTAL_START_H, &reg_val);
- if (ret)
- return ret;
- buf->crop_horizontal_start = reg_val;
-
- ret = ov5693_read_reg(client, OV5693_16BIT,
- OV5693_VERTICAL_START_H, &reg_val);
- if (ret)
- return ret;
- buf->crop_vertical_start = reg_val;
-
- ret = ov5693_read_reg(client, OV5693_16BIT,
- OV5693_HORIZONTAL_END_H, &reg_val);
- if (ret)
- return ret;
- buf->crop_horizontal_end = reg_val;
-
- ret = ov5693_read_reg(client, OV5693_16BIT,
- OV5693_VERTICAL_END_H, &reg_val);
- if (ret)
- return ret;
- buf->crop_vertical_end = reg_val;
-
- ret = ov5693_read_reg(client, OV5693_16BIT,
- OV5693_HORIZONTAL_OUTPUT_SIZE_H, &reg_val);
- if (ret)
- return ret;
- buf->output_width = reg_val;
-
- ret = ov5693_read_reg(client, OV5693_16BIT,
- OV5693_VERTICAL_OUTPUT_SIZE_H, &reg_val);
- if (ret)
- return ret;
- buf->output_height = reg_val;
-
- buf->binning_factor_x = res->bin_factor_x ?
- res->bin_factor_x : 1;
- buf->binning_factor_y = res->bin_factor_y ?
- res->bin_factor_y : 1;
- return 0;
-}
-
static long __ov5693_set_exposure(struct v4l2_subdev *sd, int coarse_itg,
int gain, int digitgain)
@@ -1107,27 +990,12 @@ static int ov5693_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_EXPOSURE_ABSOLUTE:
ret = ov5693_q_exposure(&dev->sd, &ctrl->val);
break;
- case V4L2_CID_FOCAL_ABSOLUTE:
- ret = ov5693_g_focal(&dev->sd, &ctrl->val);
- break;
- case V4L2_CID_FNUMBER_ABSOLUTE:
- ret = ov5693_g_fnumber(&dev->sd, &ctrl->val);
- break;
- case V4L2_CID_FNUMBER_RANGE:
- ret = ov5693_g_fnumber_range(&dev->sd, &ctrl->val);
- break;
case V4L2_CID_FOCUS_ABSOLUTE:
ret = ov5693_q_focus_abs(&dev->sd, &ctrl->val);
break;
case V4L2_CID_FOCUS_STATUS:
ret = ov5693_q_focus_status(&dev->sd, &ctrl->val);
break;
- case V4L2_CID_BIN_FACTOR_HORZ:
- ret = ov5693_g_bin_factor_x(&dev->sd, &ctrl->val);
- break;
- case V4L2_CID_BIN_FACTOR_VERT:
- ret = ov5693_g_bin_factor_y(&dev->sd, &ctrl->val);
- break;
default:
ret = -EINVAL;
}
@@ -1154,39 +1022,6 @@ static const struct v4l2_ctrl_config ov5693_controls[] = {
},
{
.ops = &ctrl_ops,
- .id = V4L2_CID_FOCAL_ABSOLUTE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "focal length",
- .min = OV5693_FOCAL_LENGTH_DEFAULT,
- .max = OV5693_FOCAL_LENGTH_DEFAULT,
- .step = 0x01,
- .def = OV5693_FOCAL_LENGTH_DEFAULT,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_FNUMBER_ABSOLUTE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "f-number",
- .min = OV5693_F_NUMBER_DEFAULT,
- .max = OV5693_F_NUMBER_DEFAULT,
- .step = 0x01,
- .def = OV5693_F_NUMBER_DEFAULT,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_FNUMBER_RANGE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "f-number range",
- .min = OV5693_F_NUMBER_RANGE,
- .max = OV5693_F_NUMBER_RANGE,
- .step = 0x01,
- .def = OV5693_F_NUMBER_RANGE,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
.id = V4L2_CID_FOCUS_ABSOLUTE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "focus move absolute",
@@ -1240,28 +1075,6 @@ static const struct v4l2_ctrl_config ov5693_controls[] = {
.def = 0,
.flags = 0,
},
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_BIN_FACTOR_HORZ,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "horizontal binning factor",
- .min = 0,
- .max = OV5693_BIN_FACTOR_MAX,
- .step = 1,
- .def = 0,
- .flags = 0,
- },
- {
- .ops = &ctrl_ops,
- .id = V4L2_CID_BIN_FACTOR_VERT,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "vertical binning factor",
- .min = 0,
- .max = OV5693_BIN_FACTOR_MAX,
- .step = 1,
- .def = 0,
- .flags = 0,
- },
};
static int ov5693_init(struct v4l2_subdev *sd)
@@ -1659,18 +1472,10 @@ static int ov5693_set_fmt(struct v4l2_subdev *sd,
if (ret)
dev_warn(&client->dev, "ov5693 stream off err\n");
- ret = ov5693_get_intg_factor(client, ov5693_info,
- &ov5693_res[dev->fmt_idx]);
- if (ret) {
- dev_err(&client->dev, "failed to get integration_factor\n");
- goto err;
- }
-
ov5693_info->metadata_width = fmt->width * 10 / 8;
ov5693_info->metadata_height = 1;
ov5693_info->metadata_effective_width = &ov5693_embedded_effective_size;
-err:
mutex_unlock(&dev->input_lock);
return ret;
}
diff --git a/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h b/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h
index a1366666f49c..5e17eaf8fd6e 100644
--- a/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h
+++ b/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h
@@ -198,9 +198,6 @@ struct ov5693_resolution {
int pix_clk_freq;
u16 pixels_per_line;
u16 lines_per_frame;
- u8 bin_factor_x;
- u8 bin_factor_y;
- u8 bin_mode;
bool used;
};
@@ -228,7 +225,6 @@ struct ov5693_device {
struct camera_sensor_platform_data *platform_data;
ktime_t timestamp_t_focus_abs;
- int vt_pix_clk_freq_mhz;
int fmt_idx;
int run_mode;
int otp_size;
@@ -1110,9 +1106,6 @@ static struct ov5693_resolution ov5693_res_preview[] = {
.used = 0,
.pixels_per_line = 2688,
.lines_per_frame = 1984,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.regs = ov5693_736x496_30fps,
},
{
@@ -1124,9 +1117,6 @@ static struct ov5693_resolution ov5693_res_preview[] = {
.used = 0,
.pixels_per_line = 2688,
.lines_per_frame = 1984,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.regs = ov5693_1616x1216_30fps,
},
{
@@ -1138,9 +1128,6 @@ static struct ov5693_resolution ov5693_res_preview[] = {
.used = 0,
.pixels_per_line = 2688,
.lines_per_frame = 1984,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.regs = ov5693_2576x1456_30fps,
},
{
@@ -1152,9 +1139,6 @@ static struct ov5693_resolution ov5693_res_preview[] = {
.used = 0,
.pixels_per_line = 2688,
.lines_per_frame = 1984,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.regs = ov5693_2576x1936_30fps,
},
};
@@ -1176,9 +1160,6 @@ struct ov5693_resolution ov5693_res_still[] = {
.used = 0,
.pixels_per_line = 2688,
.lines_per_frame = 1984,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.regs = ov5693_736x496_30fps,
},
{
@@ -1190,9 +1171,6 @@ struct ov5693_resolution ov5693_res_still[] = {
.used = 0,
.pixels_per_line = 2688,
.lines_per_frame = 1984,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.regs = ov5693_1424x1168_30fps,
},
{
@@ -1204,9 +1182,6 @@ struct ov5693_resolution ov5693_res_still[] = {
.used = 0,
.pixels_per_line = 2688,
.lines_per_frame = 1984,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.regs = ov5693_1616x1216_30fps,
},
{
@@ -1218,9 +1193,6 @@ struct ov5693_resolution ov5693_res_still[] = {
.used = 0,
.pixels_per_line = 2688,
.lines_per_frame = 1984,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.regs = ov5693_2592x1456_30fps,
},
{
@@ -1232,9 +1204,6 @@ struct ov5693_resolution ov5693_res_still[] = {
.used = 0,
.pixels_per_line = 2688,
.lines_per_frame = 1984,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.regs = ov5693_2592x1944_30fps,
},
};
@@ -1251,9 +1220,6 @@ struct ov5693_resolution ov5693_res_video[] = {
.used = 0,
.pixels_per_line = 2688,
.lines_per_frame = 1984,
- .bin_factor_x = 2,
- .bin_factor_y = 2,
- .bin_mode = 1,
.regs = ov5693_736x496,
},
{
@@ -1265,9 +1231,6 @@ struct ov5693_resolution ov5693_res_video[] = {
.used = 0,
.pixels_per_line = 2688,
.lines_per_frame = 1984,
- .bin_factor_x = 2,
- .bin_factor_y = 2,
- .bin_mode = 1,
.regs = ov5693_336x256,
},
{
@@ -1279,9 +1242,6 @@ struct ov5693_resolution ov5693_res_video[] = {
.used = 0,
.pixels_per_line = 2688,
.lines_per_frame = 1984,
- .bin_factor_x = 2,
- .bin_factor_y = 2,
- .bin_mode = 1,
.regs = ov5693_368x304,
},
{
@@ -1293,9 +1253,6 @@ struct ov5693_resolution ov5693_res_video[] = {
.used = 0,
.pixels_per_line = 2688,
.lines_per_frame = 1984,
- .bin_factor_x = 2,
- .bin_factor_y = 2,
- .bin_mode = 1,
.regs = ov5693_192x160,
},
{
@@ -1307,9 +1264,6 @@ struct ov5693_resolution ov5693_res_video[] = {
.used = 0,
.pixels_per_line = 2688,
.lines_per_frame = 1984,
- .bin_factor_x = 2,
- .bin_factor_y = 2,
- .bin_mode = 0,
.regs = ov5693_1296x736,
},
{
@@ -1321,9 +1275,6 @@ struct ov5693_resolution ov5693_res_video[] = {
.used = 0,
.pixels_per_line = 2688,
.lines_per_frame = 1984,
- .bin_factor_x = 2,
- .bin_factor_y = 2,
- .bin_mode = 0,
.regs = ov5693_1296x976,
},
{
@@ -1335,9 +1286,6 @@ struct ov5693_resolution ov5693_res_video[] = {
.used = 0,
.pixels_per_line = 2688,
.lines_per_frame = 1984,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.regs = ov5693_1636p_30fps,
},
{
@@ -1349,9 +1297,6 @@ struct ov5693_resolution ov5693_res_video[] = {
.used = 0,
.pixels_per_line = 2688,
.lines_per_frame = 1984,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.regs = ov5693_1940x1096,
},
{
@@ -1363,9 +1308,6 @@ struct ov5693_resolution ov5693_res_video[] = {
.used = 0,
.pixels_per_line = 2688,
.lines_per_frame = 1984,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.regs = ov5693_2592x1456_30fps,
},
{
@@ -1377,9 +1319,6 @@ struct ov5693_resolution ov5693_res_video[] = {
.used = 0,
.pixels_per_line = 2688,
.lines_per_frame = 1984,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
.regs = ov5693_2592x1944_30fps,
},
};
diff --git a/drivers/staging/media/atomisp/include/linux/atomisp.h b/drivers/staging/media/atomisp/include/linux/atomisp.h
index 3f602b5aaff9..63b1bcd35399 100644
--- a/drivers/staging/media/atomisp/include/linux/atomisp.h
+++ b/drivers/staging/media/atomisp/include/linux/atomisp.h
@@ -586,20 +586,6 @@ struct atomisp_shading_table {
__u16 *data[ATOMISP_NUM_SC_COLORS];
};
-struct atomisp_makernote_info {
- /* bits 31-16: numerator, bits 15-0: denominator */
- unsigned int focal_length;
- /* bits 31-16: numerator, bits 15-0: denominator*/
- unsigned int f_number_curr;
- /*
- * bits 31-24: max f-number numerator
- * bits 23-16: max f-number denominator
- * bits 15-8: min f-number numerator
- * bits 7-0: min f-number denominator
- */
- unsigned int f_number_range;
-};
-
/* parameter for MACC */
#define ATOMISP_NUM_MACC_AXES 16
struct atomisp_macc_table {
@@ -650,28 +636,6 @@ struct atomisp_overlay {
unsigned int overlay_start_y;
};
-/* Sensor resolution specific data for AE calculation.*/
-struct atomisp_sensor_mode_data {
- unsigned int coarse_integration_time_min;
- unsigned int coarse_integration_time_max_margin;
- unsigned int fine_integration_time_min;
- unsigned int fine_integration_time_max_margin;
- unsigned int fine_integration_time_def;
- unsigned int frame_length_lines;
- unsigned int line_length_pck;
- unsigned int read_mode;
- unsigned int vt_pix_clk_freq_mhz;
- unsigned int crop_horizontal_start; /* Sensor crop start cord. (x0,y0)*/
- unsigned int crop_vertical_start;
- unsigned int crop_horizontal_end; /* Sensor crop end cord. (x1,y1)*/
- unsigned int crop_vertical_end;
- unsigned int output_width; /* input size to ISP after binning/scaling */
- unsigned int output_height;
- u8 binning_factor_x; /* horizontal binning factor used */
- u8 binning_factor_y; /* vertical binning factor used */
- u16 hts;
-};
-
struct atomisp_exposure {
unsigned int integration_time[8];
unsigned int shutter_speed[8];
@@ -914,8 +878,6 @@ struct atomisp_sensor_ae_bracketing_lut {
_IOR('v', BASE_VIDIOC_PRIVATE + 10, struct atomisp_morph_table)
#define ATOMISP_IOC_S_ISP_GDC_TAB \
_IOW('v', BASE_VIDIOC_PRIVATE + 10, struct atomisp_morph_table)
-#define ATOMISP_IOC_ISP_MAKERNOTE \
- _IOWR('v', BASE_VIDIOC_PRIVATE + 11, struct atomisp_makernote_info)
/* macc parameter control*/
#define ATOMISP_IOC_G_ISP_MACC \
@@ -961,10 +923,6 @@ struct atomisp_sensor_ae_bracketing_lut {
#define ATOMISP_IOC_CAMERA_BRIDGE \
_IOWR('v', BASE_VIDIOC_PRIVATE + 19, struct atomisp_bc_video_package)
-/* Sensor resolution specific info for AE */
-#define ATOMISP_IOC_G_SENSOR_MODE_DATA \
- _IOR('v', BASE_VIDIOC_PRIVATE + 20, struct atomisp_sensor_mode_data)
-
#define ATOMISP_IOC_S_EXPOSURE \
_IOW('v', BASE_VIDIOC_PRIVATE + 21, struct atomisp_exposure)
@@ -1093,10 +1051,6 @@ struct atomisp_sensor_ae_bracketing_lut {
* Exposure, Flash and privacy (indicator) light controls, to be upstreamed */
#define V4L2_CID_CAMERA_LASTP1 (V4L2_CID_CAMERA_CLASS_BASE + 1024)
-#define V4L2_CID_FOCAL_ABSOLUTE (V4L2_CID_CAMERA_LASTP1 + 0)
-#define V4L2_CID_FNUMBER_ABSOLUTE (V4L2_CID_CAMERA_LASTP1 + 1)
-#define V4L2_CID_FNUMBER_RANGE (V4L2_CID_CAMERA_LASTP1 + 2)
-
/* Flash related CIDs, see also:
* http://linuxtv.org/downloads/v4l-dvb-apis/extended-controls.html\
* #flash-controls */
@@ -1117,10 +1071,6 @@ struct atomisp_sensor_ae_bracketing_lut {
/* Query Focus Status */
#define V4L2_CID_FOCUS_STATUS (V4L2_CID_CAMERA_LASTP1 + 14)
-/* Query sensor's binning factor */
-#define V4L2_CID_BIN_FACTOR_HORZ (V4L2_CID_CAMERA_LASTP1 + 15)
-#define V4L2_CID_BIN_FACTOR_VERT (V4L2_CID_CAMERA_LASTP1 + 16)
-
/* number of frames to skip at stream start */
#define V4L2_CID_G_SKIP_FRAMES (V4L2_CID_CAMERA_LASTP1 + 17)
diff --git a/drivers/staging/media/atomisp/include/linux/atomisp_gmin_platform.h b/drivers/staging/media/atomisp/include/linux/atomisp_gmin_platform.h
index 5463d11d4295..64bd54835c32 100644
--- a/drivers/staging/media/atomisp/include/linux/atomisp_gmin_platform.h
+++ b/drivers/staging/media/atomisp/include/linux/atomisp_gmin_platform.h
@@ -21,8 +21,6 @@
int atomisp_register_i2c_module(struct v4l2_subdev *subdev,
struct camera_sensor_platform_data *plat_data,
enum intel_v4l2_subdev_type type);
-struct v4l2_subdev *atomisp_gmin_find_subdev(struct i2c_adapter *adapter,
- struct i2c_board_info *board_info);
int atomisp_gmin_remove_subdev(struct v4l2_subdev *sd);
int gmin_get_var_int(struct device *dev, bool is_gmin,
const char *var, int def);
diff --git a/drivers/staging/media/atomisp/include/linux/atomisp_platform.h b/drivers/staging/media/atomisp/include/linux/atomisp_platform.h
index 0253661d4332..539b21d39d3b 100644
--- a/drivers/staging/media/atomisp/include/linux/atomisp_platform.h
+++ b/drivers/staging/media/atomisp/include/linux/atomisp_platform.h
@@ -125,13 +125,7 @@ struct intel_v4l2_subdev_id {
enum atomisp_camera_port port;
};
-struct intel_v4l2_subdev_i2c_board_info {
- struct i2c_board_info board_info;
- int i2c_adapter_id;
-};
-
struct intel_v4l2_subdev_table {
- struct intel_v4l2_subdev_i2c_board_info v4l2_subdev;
enum intel_v4l2_subdev_type type;
enum atomisp_camera_port port;
struct v4l2_subdev *subdev;
@@ -210,7 +204,6 @@ struct camera_mipi_info {
unsigned int num_lanes;
enum atomisp_input_format input_format;
enum atomisp_bayer_order raw_bayer_order;
- struct atomisp_sensor_mode_data data;
enum atomisp_input_format metadata_format;
u32 metadata_width;
u32 metadata_height;
@@ -218,6 +211,10 @@ struct camera_mipi_info {
};
const struct atomisp_platform_data *atomisp_get_platform_data(void);
+int atomisp_register_sensor_no_gmin(struct v4l2_subdev *subdev, u32 lanes,
+ enum atomisp_input_format format,
+ enum atomisp_bayer_order bayer_order);
+void atomisp_unregister_subdev(struct v4l2_subdev *subdev);
/* API from old platform_camera.h, new CPUID implementation */
#define __IS_SOC(x) (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && \
diff --git a/drivers/staging/media/atomisp/notes.txt b/drivers/staging/media/atomisp/notes.txt
index d3cf6ed547ae..c04c283ff438 100644
--- a/drivers/staging/media/atomisp/notes.txt
+++ b/drivers/staging/media/atomisp/notes.txt
@@ -36,12 +36,6 @@ a camera_mipi_info struct. This struct is allocated/managed by
the core atomisp code. The most important parts of the struct
are filled by the atomisp core itself, like e.g. the port number.
-The sensor drivers on a set_fmt call do fill in camera_mipi_info.data
-which is a atomisp_sensor_mode_data struct. This gets filled from
-a function called <sensor_name>_get_intg_factor(). This struct is not
-used by the atomisp code at all. It is returned to userspace by
-a ATOMISP_IOC_G_SENSOR_MODE_DATA and the Android userspace does use this.
-
Other members of camera_mipi_info which are set by some drivers are:
-metadata_width, metadata_height, metadata_effective_width, set by
the ov5693 driver (and used by the atomisp core)
diff --git a/drivers/staging/media/atomisp/pci/atomisp_cmd.c b/drivers/staging/media/atomisp/pci/atomisp_cmd.c
index d8c7e7367386..47f18ac5e40e 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_cmd.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_cmd.c
@@ -280,14 +280,14 @@ int atomisp_freq_scaling(struct atomisp_device *isp,
done:
dev_dbg(isp->dev, "DFS target frequency=%d.\n", new_freq);
- if ((new_freq == isp->sw_contex.running_freq) && !force)
+ if ((new_freq == isp->running_freq) && !force)
return 0;
dev_dbg(isp->dev, "Programming DFS frequency to %d\n", new_freq);
ret = write_target_freq_to_hw(isp, new_freq);
if (!ret) {
- isp->sw_contex.running_freq = new_freq;
+ isp->running_freq = new_freq;
trace_ipu_pstate(new_freq, -1);
}
return ret;
@@ -679,7 +679,8 @@ void atomisp_buffer_done(struct ia_css_frame *frame, enum vb2_buffer_state state
vb2_buffer_done(&frame->vb.vb2_buf, state);
}
-void atomisp_flush_video_pipe(struct atomisp_video_pipe *pipe, bool warn_on_css_frames)
+void atomisp_flush_video_pipe(struct atomisp_video_pipe *pipe, enum vb2_buffer_state state,
+ bool warn_on_css_frames)
{
struct ia_css_frame *frame, *_frame;
unsigned long irqflags;
@@ -689,15 +690,15 @@ void atomisp_flush_video_pipe(struct atomisp_video_pipe *pipe, bool warn_on_css_
list_for_each_entry_safe(frame, _frame, &pipe->buffers_in_css, queue) {
if (warn_on_css_frames)
dev_warn(pipe->isp->dev, "Warning: CSS frames queued on flush\n");
- atomisp_buffer_done(frame, VB2_BUF_STATE_ERROR);
+ atomisp_buffer_done(frame, state);
}
list_for_each_entry_safe(frame, _frame, &pipe->activeq, queue)
- atomisp_buffer_done(frame, VB2_BUF_STATE_ERROR);
+ atomisp_buffer_done(frame, state);
list_for_each_entry_safe(frame, _frame, &pipe->buffers_waiting_for_param, queue) {
pipe->frame_request_config_id[frame->vb.vb2_buf.index] = 0;
- atomisp_buffer_done(frame, VB2_BUF_STATE_ERROR);
+ atomisp_buffer_done(frame, state);
}
spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
@@ -706,10 +707,10 @@ void atomisp_flush_video_pipe(struct atomisp_video_pipe *pipe, bool warn_on_css_
/* Returns queued buffers back to video-core */
void atomisp_flush_bufs_and_wakeup(struct atomisp_sub_device *asd)
{
- atomisp_flush_video_pipe(&asd->video_out_capture, false);
- atomisp_flush_video_pipe(&asd->video_out_vf, false);
- atomisp_flush_video_pipe(&asd->video_out_preview, false);
- atomisp_flush_video_pipe(&asd->video_out_video_capture, false);
+ atomisp_flush_video_pipe(&asd->video_out_capture, VB2_BUF_STATE_ERROR, false);
+ atomisp_flush_video_pipe(&asd->video_out_vf, VB2_BUF_STATE_ERROR, false);
+ atomisp_flush_video_pipe(&asd->video_out_preview, VB2_BUF_STATE_ERROR, false);
+ atomisp_flush_video_pipe(&asd->video_out_video_capture, VB2_BUF_STATE_ERROR, false);
}
/* clean out the parameters that did not apply */
@@ -4211,25 +4212,6 @@ int atomisp_digital_zoom(struct atomisp_sub_device *asd, int flag,
return 0;
}
-/*
- * Function to get sensor specific info for current resolution,
- * which will be used for auto exposure conversion.
- */
-int atomisp_get_sensor_mode_data(struct atomisp_sub_device *asd,
- struct atomisp_sensor_mode_data *config)
-{
- struct camera_mipi_info *mipi_info;
- struct atomisp_device *isp = asd->isp;
-
- mipi_info = atomisp_to_sensor_mipi_info(
- isp->inputs[asd->input_curr].camera);
- if (!mipi_info)
- return -EINVAL;
-
- memcpy(config, &mipi_info->data, sizeof(*config));
- return 0;
-}
-
static void __atomisp_update_stream_env(struct atomisp_sub_device *asd,
u16 stream_index, struct atomisp_input_stream_info *stream_info)
{
@@ -5010,7 +4992,6 @@ int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f)
struct v4l2_subdev_format vformat = {
.which = V4L2_SUBDEV_FORMAT_ACTIVE,
};
- struct v4l2_mbus_framefmt *ffmt = &vformat.format;
struct v4l2_rect isp_sink_crop;
u16 source_pad = atomisp_subdev_source_pad(vdev);
struct v4l2_subdev_fh fh;
@@ -5049,17 +5030,17 @@ int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f)
/* Ensure that the resolution is equal or below the maximum supported */
vformat.which = V4L2_SUBDEV_FORMAT_ACTIVE;
- v4l2_fill_mbus_format(ffmt, &f->fmt.pix, format_bridge->mbus_code);
- ffmt->height += padding_h;
- ffmt->width += padding_w;
+ v4l2_fill_mbus_format(&vformat.format, &f->fmt.pix, format_bridge->mbus_code);
+ vformat.format.height += padding_h;
+ vformat.format.width += padding_w;
ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera, pad,
set_fmt, NULL, &vformat);
if (ret)
return ret;
- f->fmt.pix.width = ffmt->width - padding_w;
- f->fmt.pix.height = ffmt->height - padding_h;
+ f->fmt.pix.width = vformat.format.width - padding_w;
+ f->fmt.pix.height = vformat.format.height - padding_h;
snr_fmt = f->fmt.pix;
backup_fmt = snr_fmt;
@@ -5182,9 +5163,6 @@ int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f)
if (!atomisp_subdev_format_conversion(asd, source_pad)) {
padding_w = 0;
padding_h = 0;
- } else if (IS_BYT) {
- padding_w = 12;
- padding_h = 12;
}
/* construct resolution supported by isp */
@@ -5492,42 +5470,6 @@ out:
return ret;
}
-int atomisp_exif_makernote(struct atomisp_sub_device *asd,
- struct atomisp_makernote_info *config)
-{
- struct v4l2_control ctrl;
- struct atomisp_device *isp = asd->isp;
-
- ctrl.id = V4L2_CID_FOCAL_ABSOLUTE;
- if (v4l2_g_ctrl
- (isp->inputs[asd->input_curr].camera->ctrl_handler, &ctrl)) {
- dev_warn(isp->dev, "failed to g_ctrl for focal length\n");
- return -EINVAL;
- } else {
- config->focal_length = ctrl.value;
- }
-
- ctrl.id = V4L2_CID_FNUMBER_ABSOLUTE;
- if (v4l2_g_ctrl
- (isp->inputs[asd->input_curr].camera->ctrl_handler, &ctrl)) {
- dev_warn(isp->dev, "failed to g_ctrl for f-number\n");
- return -EINVAL;
- } else {
- config->f_number_curr = ctrl.value;
- }
-
- ctrl.id = V4L2_CID_FNUMBER_RANGE;
- if (v4l2_g_ctrl
- (isp->inputs[asd->input_curr].camera->ctrl_handler, &ctrl)) {
- dev_warn(isp->dev, "failed to g_ctrl for f number range\n");
- return -EINVAL;
- } else {
- config->f_number_range = ctrl.value;
- }
-
- return 0;
-}
-
int atomisp_offline_capture_configure(struct atomisp_sub_device *asd,
struct atomisp_cont_capture_conf *cvf_config)
{
diff --git a/drivers/staging/media/atomisp/pci/atomisp_cmd.h b/drivers/staging/media/atomisp/pci/atomisp_cmd.h
index b8911491581a..733b9f8cd06f 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_cmd.h
+++ b/drivers/staging/media/atomisp/pci/atomisp_cmd.h
@@ -57,7 +57,8 @@ struct atomisp_video_pipe *atomisp_to_video_pipe(struct video_device *dev);
int atomisp_reset(struct atomisp_device *isp);
int atomisp_buffers_in_css(struct atomisp_video_pipe *pipe);
void atomisp_buffer_done(struct ia_css_frame *frame, enum vb2_buffer_state state);
-void atomisp_flush_video_pipe(struct atomisp_video_pipe *pipe, bool warn_on_css_frames);
+void atomisp_flush_video_pipe(struct atomisp_video_pipe *pipe, enum vb2_buffer_state state,
+ bool warn_on_css_frames);
void atomisp_flush_bufs_and_wakeup(struct atomisp_sub_device *asd);
void atomisp_clear_css_buffer_counters(struct atomisp_sub_device *asd);
@@ -258,9 +259,6 @@ int atomisp_makeup_css_parameters(struct atomisp_sub_device *asd,
int atomisp_compare_grid(struct atomisp_sub_device *asd,
struct atomisp_grid_info *atomgrid);
-int atomisp_get_sensor_mode_data(struct atomisp_sub_device *asd,
- struct atomisp_sensor_mode_data *config);
-
/* This function looks up the closest available resolution. */
int atomisp_try_fmt(struct video_device *vdev, struct v4l2_pix_format *f,
bool *res_overflow);
@@ -273,9 +271,6 @@ int atomisp_set_shading_table(struct atomisp_sub_device *asd,
int atomisp_offline_capture_configure(struct atomisp_sub_device *asd,
struct atomisp_cont_capture_conf *cvf_config);
-int atomisp_exif_makernote(struct atomisp_sub_device *asd,
- struct atomisp_makernote_info *config);
-
void atomisp_free_internal_buffers(struct atomisp_sub_device *asd);
int atomisp_s_ae_window(struct atomisp_sub_device *asd,
diff --git a/drivers/staging/media/atomisp/pci/atomisp_csi2.c b/drivers/staging/media/atomisp/pci/atomisp_csi2.c
index 4a9268bac8a9..b00bc0b7aaad 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_csi2.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_csi2.c
@@ -175,47 +175,8 @@ static const struct v4l2_subdev_ops csi2_ops = {
.pad = &csi2_pad_ops,
};
-/*
- * csi2_link_setup - Setup CSI2 connections.
- * @entity : Pointer to media entity structure
- * @local : Pointer to local pad array
- * @remote : Pointer to remote pad array
- * @flags : Link flags
- * return -EINVAL or zero on success
- */
-static int csi2_link_setup(struct media_entity *entity,
- const struct media_pad *local,
- const struct media_pad *remote, u32 flags)
-{
- struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
- struct atomisp_mipi_csi2_device *csi2 = v4l2_get_subdevdata(sd);
- u32 result = local->index | is_media_entity_v4l2_subdev(remote->entity);
-
- switch (result) {
- case CSI2_PAD_SOURCE | MEDIA_ENT_F_OLD_BASE:
- /* not supported yet */
- return -EINVAL;
-
- case CSI2_PAD_SOURCE | MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN:
- if (flags & MEDIA_LNK_FL_ENABLED) {
- if (csi2->output & ~CSI2_OUTPUT_ISP_SUBDEV)
- return -EBUSY;
- csi2->output |= CSI2_OUTPUT_ISP_SUBDEV;
- } else {
- csi2->output &= ~CSI2_OUTPUT_ISP_SUBDEV;
- }
- break;
-
- default:
- /* Link from camera to CSI2 is fixed... */
- return -EINVAL;
- }
- return 0;
-}
-
/* media operations */
static const struct media_entity_operations csi2_media_ops = {
- .link_setup = csi2_link_setup,
.link_validate = v4l2_subdev_link_validate,
};
@@ -242,7 +203,7 @@ static int mipi_csi2_init_entities(struct atomisp_mipi_csi2_device *csi2,
pads[CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
me->ops = &csi2_media_ops;
- me->function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN;
+ me->function = MEDIA_ENT_F_VID_IF_BRIDGE;
ret = media_entity_pads_init(me, CSI2_PADS_NUM, pads);
if (ret < 0)
return ret;
diff --git a/drivers/staging/media/atomisp/pci/atomisp_csi2.h b/drivers/staging/media/atomisp/pci/atomisp_csi2.h
index e35711be8a37..b245b2f5ce99 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_csi2.h
+++ b/drivers/staging/media/atomisp/pci/atomisp_csi2.h
@@ -25,9 +25,6 @@
#define CSI2_PAD_SOURCE 1
#define CSI2_PADS_NUM 2
-#define CSI2_OUTPUT_ISP_SUBDEV BIT(0)
-#define CSI2_OUTPUT_MEMORY BIT(1)
-
struct atomisp_device;
struct v4l2_device;
struct atomisp_sub_device;
@@ -39,8 +36,6 @@ struct atomisp_mipi_csi2_device {
struct v4l2_ctrl_handler ctrls;
struct atomisp_device *isp;
-
- u32 output; /* output direction */
};
int atomisp_csi2_set_ffmt(struct v4l2_subdev *sd,
diff --git a/drivers/staging/media/atomisp/pci/atomisp_fops.c b/drivers/staging/media/atomisp/pci/atomisp_fops.c
index acea7492847d..ce01479bdd68 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_fops.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_fops.c
@@ -80,7 +80,7 @@ static int atomisp_queue_setup(struct vb2_queue *vq,
out:
mutex_unlock(&pipe->asd->isp->mutex);
- return 0;
+ return ret;
}
static int atomisp_buf_init(struct vb2_buffer *vb)
@@ -624,7 +624,7 @@ static void atomisp_buf_cleanup(struct vb2_buffer *vb)
hmm_free(frame->data);
}
-static const struct vb2_ops atomisp_vb2_ops = {
+const struct vb2_ops atomisp_vb2_ops = {
.queue_setup = atomisp_queue_setup,
.buf_init = atomisp_buf_init,
.buf_cleanup = atomisp_buf_cleanup,
@@ -633,40 +633,6 @@ static const struct vb2_ops atomisp_vb2_ops = {
.stop_streaming = atomisp_stop_streaming,
};
-static int atomisp_init_pipe(struct atomisp_video_pipe *pipe)
-{
- int ret;
-
- /* init locks */
- spin_lock_init(&pipe->irq_lock);
- mutex_init(&pipe->vb_queue_mutex);
-
- /* Init videobuf2 queue structure */
- pipe->vb_queue.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- pipe->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR;
- pipe->vb_queue.buf_struct_size = sizeof(struct ia_css_frame);
- pipe->vb_queue.ops = &atomisp_vb2_ops;
- pipe->vb_queue.mem_ops = &vb2_vmalloc_memops;
- pipe->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- ret = vb2_queue_init(&pipe->vb_queue);
- if (ret)
- return ret;
-
- pipe->vdev.queue = &pipe->vb_queue;
- pipe->vdev.queue->lock = &pipe->vb_queue_mutex;
-
- INIT_LIST_HEAD(&pipe->activeq);
- INIT_LIST_HEAD(&pipe->buffers_waiting_for_param);
- INIT_LIST_HEAD(&pipe->per_frame_params);
- memset(pipe->frame_request_config_id, 0,
- VIDEO_MAX_FRAME * sizeof(unsigned int));
- memset(pipe->frame_params, 0,
- VIDEO_MAX_FRAME *
- sizeof(struct atomisp_css_params_with_list *));
-
- return 0;
-}
-
static void atomisp_dev_init_struct(struct atomisp_device *isp)
{
unsigned int i;
@@ -681,7 +647,7 @@ static void atomisp_dev_init_struct(struct atomisp_device *isp)
* For Merrifield, frequency is scalable.
* After boot-up, the default frequency is 200MHz.
*/
- isp->sw_contex.running_freq = ISP_FREQ_200MHZ;
+ isp->running_freq = ISP_FREQ_200MHZ;
}
static void atomisp_subdev_init_struct(struct atomisp_sub_device *asd)
@@ -757,25 +723,6 @@ static int atomisp_open(struct file *file)
mutex_lock(&isp->mutex);
asd->subdev.devnode = vdev;
- /* Deferred firmware loading case. */
- if (isp->css_env.isp_css_fw.bytes == 0) {
- dev_err(isp->dev, "Deferred firmware load.\n");
- isp->firmware = atomisp_load_firmware(isp);
- if (!isp->firmware) {
- dev_err(isp->dev, "Failed to load ISP firmware.\n");
- ret = -ENOENT;
- goto error;
- }
- ret = atomisp_css_load_firmware(isp);
- if (ret) {
- dev_err(isp->dev, "Failed to init css.\n");
- goto error;
- }
- /* No need to keep FW in memory anymore. */
- release_firmware(isp->firmware);
- isp->firmware = NULL;
- isp->css_env.isp_css_fw.data = NULL;
- }
if (!isp->input_cnt) {
dev_err(isp->dev, "no camera attached\n");
@@ -792,10 +739,6 @@ static int atomisp_open(struct file *file)
return -EBUSY;
}
- ret = atomisp_init_pipe(pipe);
- if (ret)
- goto error;
-
if (atomisp_dev_users(isp)) {
dev_dbg(isp->dev, "skip init isp in open\n");
goto init_subdev;
@@ -821,13 +764,13 @@ init_subdev:
goto done;
atomisp_subdev_init_struct(asd);
+ /* Ensure that a mode is set */
+ v4l2_ctrl_s_ctrl(asd->run_mode, pipe->default_run_mode);
done:
pipe->users++;
mutex_unlock(&isp->mutex);
- /* Ensure that a mode is set */
- v4l2_ctrl_s_ctrl(asd->run_mode, pipe->default_run_mode);
return 0;
@@ -885,13 +828,17 @@ static int atomisp_release(struct file *file)
atomisp_css_free_stat_buffers(asd);
atomisp_free_internal_buffers(asd);
- ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera,
- core, s_power, 0);
- if (ret)
- dev_warn(isp->dev, "Failed to power-off sensor\n");
- /* clear the asd field to show this camera is not used */
- isp->inputs[asd->input_curr].asd = NULL;
+ if (isp->inputs[asd->input_curr].asd == asd) {
+ ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera,
+ core, s_power, 0);
+ if (ret && ret != -ENOIOCTLCMD)
+ dev_warn(isp->dev, "Failed to power-off sensor\n");
+
+ /* clear the asd field to show this camera is not used */
+ isp->inputs[asd->input_curr].asd = NULL;
+ }
+
spin_lock_irqsave(&isp->lock, flags);
asd->streaming = ATOMISP_DEVICE_STREAMING_DISABLED;
spin_unlock_irqrestore(&isp->lock, flags);
@@ -901,12 +848,6 @@ static int atomisp_release(struct file *file)
atomisp_destroy_pipes_stream_force(asd);
- if (defer_fw_load) {
- ia_css_unload_firmware();
- isp->css_env.isp_css_fw.data = NULL;
- isp->css_env.isp_css_fw.bytes = 0;
- }
-
ret = v4l2_subdev_call(isp->flash, core, s_power, 0);
if (ret < 0 && ret != -ENODEV && ret != -ENOIOCTLCMD)
dev_warn(isp->dev, "Failed to power-off flash\n");
diff --git a/drivers/staging/media/atomisp/pci/atomisp_fops.h b/drivers/staging/media/atomisp/pci/atomisp_fops.h
index 10e43126b693..883c1851c1c9 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_fops.h
+++ b/drivers/staging/media/atomisp/pci/atomisp_fops.h
@@ -31,8 +31,7 @@ unsigned int atomisp_sub_dev_users(struct atomisp_sub_device *asd);
int atomisp_qbuffers_to_css(struct atomisp_sub_device *asd);
+extern const struct vb2_ops atomisp_vb2_ops;
extern const struct v4l2_file_operations atomisp_fops;
-extern bool defer_fw_load;
-
#endif /* __ATOMISP_FOPS_H__ */
diff --git a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c
index 3d41fab661cf..7fc7dfa56172 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c
@@ -57,8 +57,12 @@ enum clock_rate {
#define LDO_1P8V_OFF 0x58 /* ... bottom bit is "enabled" */
/* CRYSTAL COVE PMIC register set */
-#define CRYSTAL_1P8V_REG 0x57
-#define CRYSTAL_2P8V_REG 0x5d
+#define CRYSTAL_BYT_1P8V_REG 0x5d
+#define CRYSTAL_BYT_2P8V_REG 0x66
+
+#define CRYSTAL_CHT_1P8V_REG 0x57
+#define CRYSTAL_CHT_2P8V_REG 0x5d
+
#define CRYSTAL_ON 0x63
#define CRYSTAL_OFF 0x62
@@ -145,7 +149,6 @@ int atomisp_register_i2c_module(struct v4l2_subdev *subdev,
enum intel_v4l2_subdev_type type)
{
int i;
- struct i2c_board_info *bi;
struct gmin_subdev *gs;
struct i2c_client *client = v4l2_get_subdevdata(subdev);
struct acpi_device *adev = ACPI_COMPANION(&client->dev);
@@ -158,6 +161,14 @@ int atomisp_register_i2c_module(struct v4l2_subdev *subdev,
* tickled during suspend/resume. This has caused power and
* performance issues on multiple devices.
*/
+
+ /*
+ * Turn off the device before disabling ACPI power resources
+ * (the sensor driver has already probed it at this point).
+ * This avoids leaking the reference count of the (possibly shared)
+ * ACPI power resources which were enabled/referenced before probe().
+ */
+ acpi_device_set_power(adev, ACPI_STATE_D3_COLD);
adev->power.flags.power_resources = 0;
for (i = 0; i < MAX_SUBDEVS; i++)
@@ -179,36 +190,10 @@ int atomisp_register_i2c_module(struct v4l2_subdev *subdev,
pdata.subdevs[i].type = type;
pdata.subdevs[i].port = gs->csi_port;
pdata.subdevs[i].subdev = subdev;
- pdata.subdevs[i].v4l2_subdev.i2c_adapter_id = client->adapter->nr;
-
- /* Convert i2c_client to i2c_board_info */
- bi = &pdata.subdevs[i].v4l2_subdev.board_info;
- memcpy(bi->type, client->name, I2C_NAME_SIZE);
- bi->flags = client->flags;
- bi->addr = client->addr;
- bi->irq = client->irq;
- bi->platform_data = plat_data;
-
return 0;
}
EXPORT_SYMBOL_GPL(atomisp_register_i2c_module);
-struct v4l2_subdev *atomisp_gmin_find_subdev(struct i2c_adapter *adapter,
- struct i2c_board_info *board_info)
-{
- int i;
-
- for (i = 0; i < MAX_SUBDEVS && pdata.subdevs[i].type; i++) {
- struct intel_v4l2_subdev_table *sd = &pdata.subdevs[i];
-
- if (sd->v4l2_subdev.i2c_adapter_id == adapter->nr &&
- sd->v4l2_subdev.board_info.addr == board_info->addr)
- return sd->subdev;
- }
- return NULL;
-}
-EXPORT_SYMBOL_GPL(atomisp_gmin_find_subdev);
-
int atomisp_gmin_remove_subdev(struct v4l2_subdev *sd)
{
int i, j;
@@ -843,6 +828,7 @@ static int gmin_v1p8_ctrl(struct v4l2_subdev *subdev, int on)
struct gmin_subdev *gs = find_gmin_subdev(subdev);
int ret;
int value;
+ int reg;
if (!gs || gs->v1p8_on == on)
return 0;
@@ -898,10 +884,15 @@ static int gmin_v1p8_ctrl(struct v4l2_subdev *subdev, int on)
LDO10_REG, value, 0xff);
break;
case PMIC_CRYSTALCOVE:
+ if (IS_ISP2401)
+ reg = CRYSTAL_CHT_1P8V_REG;
+ else
+ reg = CRYSTAL_BYT_1P8V_REG;
+
value = on ? CRYSTAL_ON : CRYSTAL_OFF;
ret = gmin_i2c_write(subdev->dev, gs->pwm_i2c_addr,
- CRYSTAL_1P8V_REG, value, 0xff);
+ reg, value, 0xff);
break;
default:
dev_err(subdev->dev, "Couldn't set power mode for v1p8\n");
@@ -918,6 +909,7 @@ static int gmin_v2p8_ctrl(struct v4l2_subdev *subdev, int on)
struct gmin_subdev *gs = find_gmin_subdev(subdev);
int ret;
int value;
+ int reg;
if (WARN_ON(!gs))
return -ENODEV;
@@ -974,10 +966,15 @@ static int gmin_v2p8_ctrl(struct v4l2_subdev *subdev, int on)
LDO9_REG, value, 0xff);
break;
case PMIC_CRYSTALCOVE:
+ if (IS_ISP2401)
+ reg = CRYSTAL_CHT_2P8V_REG;
+ else
+ reg = CRYSTAL_BYT_2P8V_REG;
+
value = on ? CRYSTAL_ON : CRYSTAL_OFF;
ret = gmin_i2c_write(subdev->dev, gs->pwm_i2c_addr,
- CRYSTAL_2P8V_REG, value, 0xff);
+ reg, value, 0xff);
break;
default:
dev_err(subdev->dev, "Couldn't set power mode for v2p8\n");
@@ -1095,6 +1092,67 @@ static int gmin_csi_cfg(struct v4l2_subdev *sd, int flag)
return 0;
}
+int atomisp_register_sensor_no_gmin(struct v4l2_subdev *subdev, u32 lanes,
+ enum atomisp_input_format format,
+ enum atomisp_bayer_order bayer_order)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(subdev);
+ struct acpi_device *adev = ACPI_COMPANION(&client->dev);
+ int i, ret, clock_num, port = 0;
+
+ if (adev) {
+ /* Get ACPI _PR0 derived clock to determine the csi_port default */
+ if (acpi_device_power_manageable(adev)) {
+ clock_num = atomisp_get_acpi_power(&client->dev);
+
+ /* Compare clock to CsiPort 1 pmc-clock used in the CHT/BYT reference designs */
+ if (IS_ISP2401)
+ port = clock_num == 4 ? 1 : 0;
+ else
+ port = clock_num == 0 ? 1 : 0;
+ }
+
+ port = gmin_get_var_int(&client->dev, false, "CsiPort", port);
+ lanes = gmin_get_var_int(&client->dev, false, "CsiLanes", lanes);
+ }
+
+ for (i = 0; i < MAX_SUBDEVS; i++)
+ if (!pdata.subdevs[i].type)
+ break;
+
+ if (i >= MAX_SUBDEVS) {
+ dev_err(&client->dev, "Error too many subdevs already registered\n");
+ return -ENOMEM;
+ }
+
+ ret = camera_sensor_csi_alloc(subdev, port, lanes, format, bayer_order);
+ if (ret)
+ return ret;
+
+ pdata.subdevs[i].type = RAW_CAMERA;
+ pdata.subdevs[i].port = port;
+ pdata.subdevs[i].subdev = subdev;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(atomisp_register_sensor_no_gmin);
+
+void atomisp_unregister_subdev(struct v4l2_subdev *subdev)
+{
+ int i;
+
+ for (i = 0; i < MAX_SUBDEVS; i++) {
+ if (pdata.subdevs[i].subdev != subdev)
+ continue;
+
+ camera_sensor_csi_free(subdev);
+ pdata.subdevs[i].subdev = NULL;
+ pdata.subdevs[i].type = 0;
+ pdata.subdevs[i].port = 0;
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(atomisp_unregister_subdev);
+
static struct camera_vcm_control *gmin_get_vcm_ctrl(struct v4l2_subdev *subdev,
char *camera_module)
{
diff --git a/drivers/staging/media/atomisp/pci/atomisp_internal.h b/drivers/staging/media/atomisp/pci/atomisp_internal.h
index 653e6d74a966..fa38d91420cf 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_internal.h
+++ b/drivers/staging/media/atomisp/pci/atomisp_internal.h
@@ -194,10 +194,6 @@ struct atomisp_regs {
u32 csi_access_viol;
};
-struct atomisp_sw_contex {
- int running_freq;
-};
-
#define ATOMISP_DEVICE_STREAMING_DISABLED 0
#define ATOMISP_DEVICE_STREAMING_ENABLED 1
#define ATOMISP_DEVICE_STREAMING_STOPPING 2
@@ -214,6 +210,7 @@ struct atomisp_device {
void __iomem *base;
const struct firmware *firmware;
+ struct dev_pm_domain pm_domain;
struct pm_qos_request pm_qos;
s32 max_isr_latency;
@@ -242,7 +239,6 @@ struct atomisp_device {
struct v4l2_subdev *motor;
struct atomisp_regs saved_regs;
- struct atomisp_sw_contex sw_contex;
struct atomisp_css_env css_env;
/* isp timeout status flag */
@@ -257,6 +253,7 @@ struct atomisp_device {
unsigned int mipi_frame_size;
const struct atomisp_dfs_config *dfs;
unsigned int hpll_freq;
+ unsigned int running_freq;
bool css_initialized;
};
diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
index cb01ba65c88f..d1314bdbf7d5 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
@@ -173,24 +173,6 @@ static struct v4l2_queryctrl ci_v4l2_controls[] = {
.default_value = 1,
},
{
- .id = V4L2_CID_BIN_FACTOR_HORZ,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Horizontal binning factor",
- .minimum = 0,
- .maximum = 10,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_BIN_FACTOR_VERT,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Vertical binning factor",
- .minimum = 0,
- .maximum = 10,
- .step = 1,
- .default_value = 0,
- },
- {
.id = V4L2_CID_2A_STATUS,
.type = V4L2_CTRL_TYPE_BITMASK,
.name = "AE and AWB status",
@@ -636,10 +618,10 @@ static int atomisp_enum_input(struct file *file, void *fh,
static unsigned int
atomisp_subdev_streaming_count(struct atomisp_sub_device *asd)
{
- return asd->video_out_preview.vb_queue.start_streaming_called
- + asd->video_out_capture.vb_queue.start_streaming_called
- + asd->video_out_video_capture.vb_queue.start_streaming_called
- + asd->video_out_vf.vb_queue.start_streaming_called;
+ return vb2_start_streaming_called(&asd->video_out_preview.vb_queue) +
+ vb2_start_streaming_called(&asd->video_out_capture.vb_queue) +
+ vb2_start_streaming_called(&asd->video_out_video_capture.vb_queue) +
+ vb2_start_streaming_called(&asd->video_out_vf.vb_queue);
}
unsigned int atomisp_streaming_count(struct atomisp_device *isp)
@@ -718,7 +700,7 @@ static int atomisp_s_input(struct file *file, void *fh, unsigned int input)
asd->input_curr != input) {
ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera,
core, s_power, 0);
- if (ret)
+ if (ret && ret != -ENOIOCTLCMD)
dev_warn(isp->dev,
"Failed to power-off sensor\n");
/* clear the asd field to show this camera is not used */
@@ -727,7 +709,7 @@ static int atomisp_s_input(struct file *file, void *fh, unsigned int input)
/* powe on the new sensor */
ret = v4l2_subdev_call(isp->inputs[input].camera, core, s_power, 1);
- if (ret) {
+ if (ret && ret != -ENOIOCTLCMD) {
dev_err(isp->dev, "Failed to power-on sensor\n");
return ret;
}
@@ -1067,13 +1049,23 @@ error:
return -ENOMEM;
}
+/*
+ * FIXME the abuse of buf->reserved2 in the qbuf and dqbuf wrappers comes from
+ * the original atomisp buffer handling and should be replaced with proper V4L2
+ * per frame parameters use.
+ *
+ * Once this is fixed these wrappers can be removed, replacing them with direct
+ * calls to vb2_ioctl_[d]qbuf().
+ */
static int atomisp_qbuf_wrapper(struct file *file, void *fh, struct v4l2_buffer *buf)
{
struct video_device *vdev = video_devdata(file);
struct atomisp_device *isp = video_get_drvdata(vdev);
struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev);
- /* FIXME this abuse of buf->reserved2 comes from the original atomisp buffer handling */
+ if (buf->index >= vdev->queue->num_buffers)
+ return -EINVAL;
+
if (!atomisp_is_vf_pipe(pipe) &&
(buf->reserved2 & ATOMISP_BUFFER_HAS_PER_FRAME_SETTING)) {
/* this buffer will have a per-frame parameter */
@@ -1106,7 +1098,6 @@ static int atomisp_dqbuf_wrapper(struct file *file, void *fh, struct v4l2_buffer
vb = pipe->vb_queue.bufs[buf->index];
frame = vb_to_frame(vb);
- /* FIXME this abuse of buf->reserved* comes from the original atomisp buffer handling */
buf->reserved = asd->frame_status[buf->index];
/*
@@ -1354,7 +1345,7 @@ int atomisp_start_streaming(struct vb2_queue *vq, unsigned int count)
ret = atomisp_css_start(asd, css_pipe_id, false);
if (ret) {
- atomisp_flush_video_pipe(pipe, true);
+ atomisp_flush_video_pipe(pipe, VB2_BUF_STATE_QUEUED, true);
goto out_unlock;
}
@@ -1530,7 +1521,7 @@ void atomisp_stop_streaming(struct vb2_queue *vq)
css_pipe_id = atomisp_get_css_pipe_id(asd);
atomisp_css_stop(asd, css_pipe_id, false);
- atomisp_flush_video_pipe(pipe, true);
+ atomisp_flush_video_pipe(pipe, VB2_BUF_STATE_ERROR, true);
atomisp_subdev_cleanup_pending_events(asd);
stopsensor:
@@ -1631,7 +1622,6 @@ static int atomisp_g_ctrl(struct file *file, void *fh,
switch (control->id) {
case V4L2_CID_IRIS_ABSOLUTE:
case V4L2_CID_EXPOSURE_ABSOLUTE:
- case V4L2_CID_FNUMBER_ABSOLUTE:
case V4L2_CID_2A_STATUS:
case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:
case V4L2_CID_EXPOSURE:
@@ -1828,9 +1818,6 @@ static int atomisp_camera_g_ext_ctrls(struct file *file, void *fh,
case V4L2_CID_EXPOSURE_ABSOLUTE:
case V4L2_CID_EXPOSURE_AUTO:
case V4L2_CID_IRIS_ABSOLUTE:
- case V4L2_CID_FNUMBER_ABSOLUTE:
- case V4L2_CID_BIN_FACTOR_HORZ:
- case V4L2_CID_BIN_FACTOR_VERT:
case V4L2_CID_3A_LOCK:
case V4L2_CID_TEST_PATTERN:
case V4L2_CID_TEST_PATTERN_COLOR_R:
@@ -1940,7 +1927,6 @@ static int atomisp_camera_s_ext_ctrls(struct file *file, void *fh,
case V4L2_CID_EXPOSURE_AUTO:
case V4L2_CID_EXPOSURE_METERING:
case V4L2_CID_IRIS_ABSOLUTE:
- case V4L2_CID_FNUMBER_ABSOLUTE:
case V4L2_CID_VCM_TIMING:
case V4L2_CID_VCM_SLEW:
case V4L2_CID_3A_LOCK:
@@ -2276,14 +2262,6 @@ static long atomisp_vidioc_default(struct file *file, void *fh,
err = atomisp_fixed_pattern_table(asd, arg);
break;
- case ATOMISP_IOC_ISP_MAKERNOTE:
- err = atomisp_exif_makernote(asd, arg);
- break;
-
- case ATOMISP_IOC_G_SENSOR_MODE_DATA:
- err = atomisp_get_sensor_mode_data(asd, arg);
- break;
-
case ATOMISP_IOC_G_MOTOR_PRIV_INT_DATA:
if (motor)
err = v4l2_subdev_call(motor, core, ioctl, cmd, arg);
diff --git a/drivers/staging/media/atomisp/pci/atomisp_subdev.c b/drivers/staging/media/atomisp/pci/atomisp_subdev.c
index cadc468b4c2f..9cfb85c61db6 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_subdev.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_subdev.c
@@ -25,9 +25,11 @@
#include <media/v4l2-event.h>
#include <media/v4l2-mediabus.h>
+#include <media/videobuf2-vmalloc.h>
#include "atomisp_cmd.h"
#include "atomisp_common.h"
#include "atomisp_compat.h"
+#include "atomisp_fops.h"
#include "atomisp_internal.h"
const struct atomisp_in_fmt_conv atomisp_in_fmt_conv[] = {
@@ -574,40 +576,6 @@ static int isp_subdev_set_selection(struct v4l2_subdev *sd,
sel->target, sel->flags, &sel->r);
}
-static int atomisp_get_sensor_bin_factor(struct atomisp_sub_device *asd)
-{
- struct v4l2_control ctrl = {0};
- struct atomisp_device *isp = asd->isp;
- int hbin, vbin;
- int ret;
-
- if (isp->inputs[asd->input_curr].type == FILE_INPUT ||
- isp->inputs[asd->input_curr].type == TEST_PATTERN)
- return 0;
-
- ctrl.id = V4L2_CID_BIN_FACTOR_HORZ;
- ret =
- v4l2_g_ctrl(isp->inputs[asd->input_curr].camera->ctrl_handler,
- &ctrl);
- hbin = ctrl.value;
- ctrl.id = V4L2_CID_BIN_FACTOR_VERT;
- ret |=
- v4l2_g_ctrl(isp->inputs[asd->input_curr].camera->ctrl_handler,
- &ctrl);
- vbin = ctrl.value;
-
- /*
- * ISP needs to know binning factor from sensor.
- * In case horizontal and vertical sensor's binning factors
- * are different or sensor does not support binning factor CID,
- * ISP will apply default 0 value.
- */
- if (ret || hbin != vbin)
- hbin = 0;
-
- return hbin;
-}
-
void atomisp_subdev_set_ffmt(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
uint32_t which,
@@ -645,7 +613,7 @@ void atomisp_subdev_set_ffmt(struct v4l2_subdev *sd,
ATOMISP_INPUT_STREAM_GENERAL, ffmt);
atomisp_css_input_set_binning_factor(isp_sd,
ATOMISP_INPUT_STREAM_GENERAL,
- atomisp_get_sensor_bin_factor(isp_sd));
+ 0);
atomisp_css_input_set_bayer_order(isp_sd, ATOMISP_INPUT_STREAM_GENERAL,
fc->bayer_order);
atomisp_css_input_set_format(isp_sd, ATOMISP_INPUT_STREAM_GENERAL,
@@ -746,85 +714,8 @@ static void isp_subdev_init_params(struct atomisp_sub_device *asd)
}
}
-/*
-* isp_subdev_link_setup - Setup isp subdev connections
-* @entity: ispsubdev media entity
-* @local: Pad at the local end of the link
-* @remote: Pad at the remote end of the link
-* @flags: Link flags
-*
-* return -EINVAL or zero on success
-*/
-static int isp_subdev_link_setup(struct media_entity *entity,
- const struct media_pad *local,
- const struct media_pad *remote, u32 flags)
-{
- struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
- struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
- struct atomisp_device *isp = isp_sd->isp;
- unsigned int i;
-
- switch (local->index | is_media_entity_v4l2_subdev(remote->entity)) {
- case ATOMISP_SUBDEV_PAD_SINK | MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN:
- /* Read from the sensor CSI2-ports. */
- if (!(flags & MEDIA_LNK_FL_ENABLED)) {
- isp_sd->input = ATOMISP_SUBDEV_INPUT_NONE;
- break;
- }
-
- if (isp_sd->input != ATOMISP_SUBDEV_INPUT_NONE)
- return -EBUSY;
-
- for (i = 0; i < ATOMISP_CAMERA_NR_PORTS; i++) {
- if (remote->entity != &isp->csi2_port[i].subdev.entity)
- continue;
-
- isp_sd->input = ATOMISP_SUBDEV_INPUT_CSI2_PORT1 + i;
- return 0;
- }
-
- return -EINVAL;
-
- case ATOMISP_SUBDEV_PAD_SINK | MEDIA_ENT_F_OLD_BASE:
- /* read from memory */
- if (flags & MEDIA_LNK_FL_ENABLED) {
- if (isp_sd->input >= ATOMISP_SUBDEV_INPUT_CSI2_PORT1 &&
- isp_sd->input < (ATOMISP_SUBDEV_INPUT_CSI2_PORT1
- + ATOMISP_CAMERA_NR_PORTS))
- return -EBUSY;
- isp_sd->input = ATOMISP_SUBDEV_INPUT_MEMORY;
- } else {
- if (isp_sd->input == ATOMISP_SUBDEV_INPUT_MEMORY)
- isp_sd->input = ATOMISP_SUBDEV_INPUT_NONE;
- }
- break;
-
- case ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW | MEDIA_ENT_F_OLD_BASE:
- /* always write to memory */
- break;
-
- case ATOMISP_SUBDEV_PAD_SOURCE_VF | MEDIA_ENT_F_OLD_BASE:
- /* always write to memory */
- break;
-
- case ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE | MEDIA_ENT_F_OLD_BASE:
- /* always write to memory */
- break;
-
- case ATOMISP_SUBDEV_PAD_SOURCE_VIDEO | MEDIA_ENT_F_OLD_BASE:
- /* always write to memory */
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
/* media operations */
static const struct media_entity_operations isp_subdev_media_ops = {
- .link_setup = isp_subdev_link_setup,
.link_validate = v4l2_subdev_link_validate,
/* .set_power = v4l2_subdev_set_power, */
};
@@ -1057,23 +948,37 @@ static const struct v4l2_ctrl_config ctrl_depth_mode = {
.def = 0,
};
-static void atomisp_init_subdev_pipe(struct atomisp_sub_device *asd,
- struct atomisp_video_pipe *pipe, enum v4l2_buf_type buf_type)
+static int atomisp_init_subdev_pipe(struct atomisp_sub_device *asd,
+ struct atomisp_video_pipe *pipe, enum v4l2_buf_type buf_type)
{
+ int ret;
+
pipe->type = buf_type;
pipe->asd = asd;
pipe->isp = asd->isp;
spin_lock_init(&pipe->irq_lock);
mutex_init(&pipe->vb_queue_mutex);
+
+ /* Init videobuf2 queue structure */
+ pipe->vb_queue.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ pipe->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR;
+ pipe->vb_queue.buf_struct_size = sizeof(struct ia_css_frame);
+ pipe->vb_queue.ops = &atomisp_vb2_ops;
+ pipe->vb_queue.mem_ops = &vb2_vmalloc_memops;
+ pipe->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ ret = vb2_queue_init(&pipe->vb_queue);
+ if (ret)
+ return ret;
+
+ pipe->vdev.queue = &pipe->vb_queue;
+ pipe->vdev.queue->lock = &pipe->vb_queue_mutex;
+
INIT_LIST_HEAD(&pipe->buffers_in_css);
INIT_LIST_HEAD(&pipe->activeq);
INIT_LIST_HEAD(&pipe->buffers_waiting_for_param);
INIT_LIST_HEAD(&pipe->per_frame_params);
- memset(pipe->frame_request_config_id,
- 0, VIDEO_MAX_FRAME * sizeof(unsigned int));
- memset(pipe->frame_params,
- 0, VIDEO_MAX_FRAME *
- sizeof(struct atomisp_css_params_with_list *));
+
+ return 0;
}
/*
@@ -1089,8 +994,6 @@ static int isp_subdev_init_entities(struct atomisp_sub_device *asd)
struct media_entity *me = &sd->entity;
int ret;
- asd->input = ATOMISP_SUBDEV_INPUT_NONE;
-
v4l2_subdev_init(sd, &isp_subdev_v4l2_ops);
sprintf(sd->name, "ATOMISP_SUBDEV_%d", asd->index);
v4l2_set_subdevdata(sd, asd);
@@ -1114,22 +1017,30 @@ static int isp_subdev_init_entities(struct atomisp_sub_device *asd)
MEDIA_BUS_FMT_SBGGR10_1X10;
me->ops = &isp_subdev_media_ops;
- me->function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN;
+ me->function = MEDIA_ENT_F_PROC_VIDEO_ISP;
ret = media_entity_pads_init(me, ATOMISP_SUBDEV_PADS_NUM, pads);
if (ret < 0)
return ret;
- atomisp_init_subdev_pipe(asd, &asd->video_out_preview,
- V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ ret = atomisp_init_subdev_pipe(asd, &asd->video_out_preview,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ if (ret)
+ return ret;
- atomisp_init_subdev_pipe(asd, &asd->video_out_vf,
- V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ ret = atomisp_init_subdev_pipe(asd, &asd->video_out_vf,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ if (ret)
+ return ret;
- atomisp_init_subdev_pipe(asd, &asd->video_out_capture,
- V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ ret = atomisp_init_subdev_pipe(asd, &asd->video_out_capture,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ if (ret)
+ return ret;
- atomisp_init_subdev_pipe(asd, &asd->video_out_video_capture,
- V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ ret = atomisp_init_subdev_pipe(asd, &asd->video_out_video_capture,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ if (ret)
+ return ret;
ret = atomisp_video_init(&asd->video_out_capture, "CAPTURE",
ATOMISP_RUN_MODE_STILL_CAPTURE);
diff --git a/drivers/staging/media/atomisp/pci/atomisp_subdev.h b/drivers/staging/media/atomisp/pci/atomisp_subdev.h
index bd2872cbb50c..daa6077a83bd 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_subdev.h
+++ b/drivers/staging/media/atomisp/pci/atomisp_subdev.h
@@ -30,18 +30,6 @@
/* EXP_ID's ranger is 1 ~ 250 */
#define ATOMISP_MAX_EXP_ID (250)
-enum atomisp_subdev_input_entity {
- ATOMISP_SUBDEV_INPUT_NONE,
- ATOMISP_SUBDEV_INPUT_MEMORY,
- ATOMISP_SUBDEV_INPUT_CSI2,
- /*
- * The following enum for CSI2 port must go together in one row.
- * Otherwise it breaks the code logic.
- */
- ATOMISP_SUBDEV_INPUT_CSI2_PORT1,
- ATOMISP_SUBDEV_INPUT_CSI2_PORT2,
- ATOMISP_SUBDEV_INPUT_CSI2_PORT3,
-};
#define ATOMISP_SUBDEV_PAD_SINK 0
/* capture output for still frames */
@@ -267,7 +255,6 @@ struct atomisp_sub_device {
struct atomisp_pad_format fmt[ATOMISP_SUBDEV_PADS_NUM];
u16 capture_pad; /* main capture pad; defines much of isp config */
- enum atomisp_subdev_input_entity input;
unsigned int output;
struct atomisp_video_pipe video_out_capture; /* capture output */
struct atomisp_video_pipe video_out_vf; /* viewfinder output */
diff --git a/drivers/staging/media/atomisp/pci/atomisp_tpg.c b/drivers/staging/media/atomisp/pci/atomisp_tpg.c
index e29a96da5f98..074826a5b706 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_tpg.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_tpg.c
@@ -152,7 +152,7 @@ int atomisp_tpg_init(struct atomisp_device *isp)
v4l2_set_subdevdata(sd, tpg);
pads[0].flags = MEDIA_PAD_FL_SINK;
- me->function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN;
+ me->function = MEDIA_ENT_F_PROC_VIDEO_ISP;
ret = media_entity_pads_init(me, 1, pads);
if (ret < 0)
diff --git a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c
index e786b81921da..ba628f7cf385 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c
@@ -19,6 +19,7 @@
*/
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
#include <linux/pm_qos.h>
#include <linux/timer.h>
@@ -57,12 +58,6 @@ static uint skip_fwload;
module_param(skip_fwload, uint, 0644);
MODULE_PARM_DESC(skip_fwload, "Skip atomisp firmware load");
-/* memory optimization: deferred firmware loading */
-bool defer_fw_load;
-module_param(defer_fw_load, bool, 0644);
-MODULE_PARM_DESC(defer_fw_load,
- "Defer FW loading until device is opened (default:disable)");
-
/* cross componnet debug message flag */
int dbg_level;
module_param(dbg_level, int, 0644);
@@ -524,7 +519,7 @@ static int atomisp_save_iunit_reg(struct atomisp_device *isp)
return 0;
}
-static int __maybe_unused atomisp_restore_iunit_reg(struct atomisp_device *isp)
+static int atomisp_restore_iunit_reg(struct atomisp_device *isp)
{
struct pci_dev *pdev = to_pci_dev(isp->dev);
@@ -637,31 +632,21 @@ done:
*/
static void punit_ddr_dvfs_enable(bool enable)
{
- int door_bell = 1 << 8;
- int max_wait = 30;
int reg;
iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, MRFLD_ISPSSDVFS, &reg);
if (enable) {
reg &= ~(MRFLD_BIT0 | MRFLD_BIT1);
} else {
- reg |= (MRFLD_BIT1 | door_bell);
+ reg |= MRFLD_BIT1;
reg &= ~(MRFLD_BIT0);
}
iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, MRFLD_ISPSSDVFS, reg);
-
- /* Check Req_ACK to see freq status, wait until door_bell is cleared */
- while ((reg & door_bell) && max_wait--) {
- iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, MRFLD_ISPSSDVFS, &reg);
- usleep_range(100, 500);
- }
-
- if (max_wait == -1)
- pr_info("DDR DVFS, door bell is not cleared within 3ms\n");
}
static int atomisp_mrfld_power(struct atomisp_device *isp, bool enable)
{
+ struct pci_dev *pdev = to_pci_dev(isp->dev);
unsigned long timeout;
u32 val = enable ? MRFLD_ISPSSPM0_IUNIT_POWER_ON :
MRFLD_ISPSSPM0_IUNIT_POWER_OFF;
@@ -669,16 +654,10 @@ static int atomisp_mrfld_power(struct atomisp_device *isp, bool enable)
dev_dbg(isp->dev, "IUNIT power-%s.\n", enable ? "on" : "off");
/* WA for P-Unit, if DVFS enabled, ISP timeout observed */
- if (IS_CHT && enable)
+ if (IS_CHT && enable) {
punit_ddr_dvfs_enable(false);
-
- /*
- * FIXME:WA for ECS28A, with this sleep, CTS
- * android.hardware.camera2.cts.CameraDeviceTest#testCameraDeviceAbort
- * PASS, no impact on other platforms
- */
- if (IS_BYT && enable)
- msleep(10);
+ msleep(20);
+ }
/* Write to ISPSSPM0 bit[1:0] to power on/off the IUNIT */
iosf_mbi_modify(BT_MBI_UNIT_PMC, MBI_REG_READ, MRFLD_ISPSSPM0,
@@ -703,6 +682,7 @@ static int atomisp_mrfld_power(struct atomisp_device *isp, bool enable)
tmp = (tmp >> MRFLD_ISPSSPM0_ISPSSS_OFFSET) & MRFLD_ISPSSPM0_ISPSSC_MASK;
if (tmp == val) {
trace_ipu_cstate(enable);
+ pdev->current_state = enable ? PCI_D0 : PCI_D3cold;
return 0;
}
@@ -743,6 +723,7 @@ int atomisp_power_off(struct device *dev)
pci_write_config_dword(pdev, MRFLD_PCI_CSI_CONTROL, reg);
cpu_latency_qos_update_request(&isp->pm_qos, PM_QOS_DEFAULT_VALUE);
+ pci_save_state(pdev);
return atomisp_mrfld_power(isp, false);
}
@@ -756,6 +737,7 @@ int atomisp_power_on(struct device *dev)
if (ret)
return ret;
+ pci_restore_state(to_pci_dev(dev));
cpu_latency_qos_update_request(&isp->pm_qos, isp->max_isr_latency);
/*restore register values for iUnit and iUnitPHY registers*/
@@ -767,7 +749,7 @@ int atomisp_power_on(struct device *dev)
return atomisp_css_init(isp);
}
-static int __maybe_unused atomisp_suspend(struct device *dev)
+static int atomisp_suspend(struct device *dev)
{
struct atomisp_device *isp = (struct atomisp_device *)
dev_get_drvdata(dev);
@@ -790,10 +772,12 @@ static int __maybe_unused atomisp_suspend(struct device *dev)
}
spin_unlock_irqrestore(&isp->lock, flags);
+ pm_runtime_resume(dev);
+
return atomisp_power_off(dev);
}
-static int __maybe_unused atomisp_resume(struct device *dev)
+static int atomisp_resume(struct device *dev)
{
return atomisp_power_on(dev);
}
@@ -953,45 +937,9 @@ static int atomisp_subdev_probe(struct atomisp_device *isp)
/* FIXME: should, instead, use I2C probe */
for (subdevs = pdata->subdevs; subdevs->type; ++subdevs) {
- struct v4l2_subdev *subdev;
- struct i2c_board_info *board_info =
- &subdevs->v4l2_subdev.board_info;
- struct i2c_adapter *adapter =
- i2c_get_adapter(subdevs->v4l2_subdev.i2c_adapter_id);
-
- dev_info(isp->dev, "Probing Subdev %s\n", board_info->type);
-
- if (!adapter) {
- dev_err(isp->dev,
- "Failed to find i2c adapter for subdev %s\n",
- board_info->type);
- break;
- }
-
- /* In G-Min, the sensor devices will already be probed
- * (via ACPI) and registered, do not create new
- * ones */
- subdev = atomisp_gmin_find_subdev(adapter, board_info);
- if (!subdev) {
- dev_warn(isp->dev, "Subdev %s not found\n",
- board_info->type);
+ ret = v4l2_device_register_subdev(&isp->v4l2_dev, subdevs->subdev);
+ if (ret)
continue;
- }
- ret = v4l2_device_register_subdev(&isp->v4l2_dev, subdev);
- if (ret) {
- dev_warn(isp->dev, "Subdev %s detection fail\n",
- board_info->type);
- continue;
- }
-
- if (!subdev) {
- dev_warn(isp->dev, "Subdev %s detection fail\n",
- board_info->type);
- continue;
- }
-
- dev_info(isp->dev, "Subdev %s successfully register\n",
- board_info->type);
switch (subdevs->type) {
case RAW_CAMERA:
@@ -1008,7 +956,7 @@ static int atomisp_subdev_probe(struct atomisp_device *isp)
isp->inputs[isp->input_cnt].type = subdevs->type;
isp->inputs[isp->input_cnt].port = subdevs->port;
- isp->inputs[isp->input_cnt].camera = subdev;
+ isp->inputs[isp->input_cnt].camera = subdevs->subdev;
isp->inputs[isp->input_cnt].sensor_index = 0;
/*
* initialize the subdev frame size, then next we can
@@ -1020,22 +968,18 @@ static int atomisp_subdev_probe(struct atomisp_device *isp)
break;
case CAMERA_MOTOR:
if (isp->motor) {
- dev_warn(isp->dev,
- "too many atomisp motors, ignored %s\n",
- board_info->type);
+ dev_warn(isp->dev, "too many atomisp motors\n");
continue;
}
- isp->motor = subdev;
+ isp->motor = subdevs->subdev;
break;
case LED_FLASH:
case XENON_FLASH:
if (isp->flash) {
- dev_warn(isp->dev,
- "too many atomisp flash devices, ignored %s\n",
- board_info->type);
+ dev_warn(isp->dev, "too many atomisp flash devices\n");
continue;
}
- isp->flash = subdev;
+ isp->flash = subdevs->subdev;
break;
default:
dev_dbg(isp->dev, "unknown subdev probed\n");
@@ -1524,21 +1468,17 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
isp->max_isr_latency = ATOMISP_MAX_ISR_LATENCY;
/* Load isp firmware from user space */
- if (!defer_fw_load) {
- isp->firmware = atomisp_load_firmware(isp);
- if (!isp->firmware) {
- err = -ENOENT;
- dev_dbg(&pdev->dev, "Firmware load failed\n");
- goto load_fw_fail;
- }
+ isp->firmware = atomisp_load_firmware(isp);
+ if (!isp->firmware) {
+ err = -ENOENT;
+ dev_dbg(&pdev->dev, "Firmware load failed\n");
+ goto load_fw_fail;
+ }
- err = sh_css_check_firmware_version(isp->dev, isp->firmware->data);
- if (err) {
- dev_dbg(&pdev->dev, "Firmware version check failed\n");
- goto fw_validation_fail;
- }
- } else {
- dev_info(&pdev->dev, "Firmware load will be deferred\n");
+ err = sh_css_check_firmware_version(isp->dev, isp->firmware->data);
+ if (err) {
+ dev_dbg(&pdev->dev, "Firmware version check failed\n");
+ goto fw_validation_fail;
}
pci_set_master(pdev);
@@ -1603,6 +1543,26 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
/* save the iunit context only once after all the values are init'ed. */
atomisp_save_iunit_reg(isp);
+ /*
+ * The atomisp does not use standard PCI power-management through the
+ * PCI config space. Instead this driver directly tells the P-Unit to
+ * disable the ISP over the IOSF. The standard PCI subsystem pm_ops will
+ * try to access the config space before (resume) / after (suspend) this
+ * driver has turned the ISP on / off, resulting in the following errors:
+ *
+ * "Unable to change power state from D0 to D3hot, device inaccessible"
+ * "Unable to change power state from D3cold to D0, device inaccessible"
+ *
+ * To avoid these errors override the pm_domain so that all the PCI
+ * subsys suspend / resume handling is skipped.
+ */
+ isp->pm_domain.ops.runtime_suspend = atomisp_power_off;
+ isp->pm_domain.ops.runtime_resume = atomisp_power_on;
+ isp->pm_domain.ops.suspend = atomisp_suspend;
+ isp->pm_domain.ops.resume = atomisp_resume;
+
+ dev_pm_domain_set(&pdev->dev, &isp->pm_domain);
+
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_allow(&pdev->dev);
@@ -1618,14 +1578,10 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
}
/* Load firmware into ISP memory */
- if (!defer_fw_load) {
- err = atomisp_css_load_firmware(isp);
- if (err) {
- dev_err(&pdev->dev, "Failed to init css.\n");
- goto css_init_fail;
- }
- } else {
- dev_dbg(&pdev->dev, "Skip css init.\n");
+ err = atomisp_css_load_firmware(isp);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to init css.\n");
+ goto css_init_fail;
}
/* Clear FW image from memory */
release_firmware(isp->firmware);
@@ -1645,6 +1601,7 @@ css_init_fail:
request_irq_fail:
hmm_cleanup();
pm_runtime_get_noresume(&pdev->dev);
+ dev_pm_domain_set(&pdev->dev, NULL);
atomisp_unregister_entities(isp);
register_entities_fail:
atomisp_uninitialize_modules(isp);
@@ -1697,6 +1654,7 @@ static void atomisp_pci_remove(struct pci_dev *pdev)
pm_runtime_forbid(&pdev->dev);
pm_runtime_get_noresume(&pdev->dev);
+ dev_pm_domain_set(&pdev->dev, NULL);
cpu_latency_qos_remove_request(&isp->pm_qos);
atomisp_msi_irq_uninit(isp);
@@ -1721,17 +1679,8 @@ static const struct pci_device_id atomisp_pci_tbl[] = {
MODULE_DEVICE_TABLE(pci, atomisp_pci_tbl);
-static const struct dev_pm_ops atomisp_pm_ops = {
- .runtime_suspend = atomisp_power_off,
- .runtime_resume = atomisp_power_on,
- .suspend = atomisp_suspend,
- .resume = atomisp_resume,
-};
static struct pci_driver atomisp_pci_driver = {
- .driver = {
- .pm = &atomisp_pm_ops,
- },
.name = "atomisp-isp2",
.id_table = atomisp_pci_tbl,
.probe = atomisp_pci_probe,
diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_dma_private.h b/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_dma_private.h
index a313e1dc7c71..d65fe9ec9049 100644
--- a/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_dma_private.h
+++ b/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_dma_private.h
@@ -34,8 +34,6 @@ void isys2401_dma_reg_store(const isys2401_dma_ID_t dma_id,
reg_loc = ISYS2401_DMA_BASE[dma_id] + (reg * sizeof(hrt_data));
- ia_css_print("isys dma store at addr(0x%x) val(%u)\n", reg_loc,
- (unsigned int)value);
ia_css_device_store_uint32(reg_loc, value);
}
diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/vmem.c b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/vmem.c
index 6620f091442f..d9cdfbc50197 100644
--- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/vmem.c
+++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/vmem.c
@@ -28,10 +28,18 @@ typedef hive_uedge *hive_wide;
/* Copied from SDK: sim_semantics.c */
/* subword bits move like this: MSB[____xxxx____]LSB -> MSB[00000000xxxx]LSB */
-#define SUBWORD(w, start, end) (((w) & (((1ULL << ((end) - 1)) - 1) << 1 | 1)) >> (start))
+static inline hive_uedge
+subword(hive_uedge w, unsigned int start, unsigned int end)
+{
+ return (w & (((1ULL << (end - 1)) - 1) << 1 | 1)) >> start;
+}
/* inverse subword bits move like this: MSB[xxxx____xxxx]LSB -> MSB[xxxx0000xxxx]LSB */
-#define INV_SUBWORD(w, start, end) ((w) & (~(((1ULL << ((end) - 1)) - 1) << 1 | 1) | ((1ULL << (start)) - 1)))
+static inline hive_uedge
+inv_subword(hive_uedge w, unsigned int start, unsigned int end)
+{
+ return w & (~(((1ULL << (end - 1)) - 1) << 1 | 1) | ((1ULL << start) - 1));
+}
#define uedge_bits (8 * sizeof(hive_uedge))
#define move_lower_bits(target, target_bit, src, src_bit) move_subword(target, target_bit, src, 0, src_bit)
@@ -50,18 +58,18 @@ move_subword(
unsigned int start_bit = target_bit % uedge_bits;
unsigned int subword_width = src_end - src_start;
- hive_uedge src_subword = SUBWORD(src, src_start, src_end);
+ hive_uedge src_subword = subword(src, src_start, src_end);
if (subword_width + start_bit > uedge_bits) { /* overlap */
hive_uedge old_val1;
- hive_uedge old_val0 = INV_SUBWORD(target[start_elem], start_bit, uedge_bits);
+ hive_uedge old_val0 = inv_subword(target[start_elem], start_bit, uedge_bits);
target[start_elem] = old_val0 | (src_subword << start_bit);
- old_val1 = INV_SUBWORD(target[start_elem + 1], 0,
+ old_val1 = inv_subword(target[start_elem + 1], 0,
subword_width + start_bit - uedge_bits);
target[start_elem + 1] = old_val1 | (src_subword >> (uedge_bits - start_bit));
} else {
- hive_uedge old_val = INV_SUBWORD(target[start_elem], start_bit,
+ hive_uedge old_val = inv_subword(target[start_elem], start_bit,
start_bit + subword_width);
target[start_elem] = old_val | (src_subword << start_bit);
diff --git a/drivers/staging/media/atomisp/pci/hmm/hmm_bo.c b/drivers/staging/media/atomisp/pci/hmm/hmm_bo.c
index 5e53eed8ae95..095cd0ba8c21 100644
--- a/drivers/staging/media/atomisp/pci/hmm/hmm_bo.c
+++ b/drivers/staging/media/atomisp/pci/hmm/hmm_bo.c
@@ -1072,7 +1072,7 @@ int hmm_bo_mmap(struct vm_area_struct *vma, struct hmm_buffer_object *bo)
vma->vm_private_data = bo;
vma->vm_ops = &hmm_bo_vm_ops;
- vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
+ vm_flags_set(vma, VM_IO | VM_DONTEXPAND | VM_DONTDUMP);
/*
* call hmm_bo_vm_open explicitly.
diff --git a/drivers/staging/media/atomisp/pci/sh_css.c b/drivers/staging/media/atomisp/pci/sh_css.c
index 726cb7aa4ecd..93789500416f 100644
--- a/drivers/staging/media/atomisp/pci/sh_css.c
+++ b/drivers/staging/media/atomisp/pci/sh_css.c
@@ -97,9 +97,6 @@
*/
#define JPEG_BYTES (16 * 1024 * 1024)
-#define STATS_ENABLED(stage) (stage && stage->binary && stage->binary->info && \
- (stage->binary->info->sp.enable.s3a || stage->binary->info->sp.enable.dis))
-
struct sh_css my_css;
int __printf(1, 0) (*sh_css_printf)(const char *fmt, va_list args) = NULL;
@@ -3743,7 +3740,9 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe,
* The SP will read the params after it got
* empty 3a and dis
*/
- if (STATS_ENABLED(stage)) {
+ if (stage->binary && stage->binary->info &&
+ (stage->binary->info->sp.enable.s3a ||
+ stage->binary->info->sp.enable.dis)) {
/* there is a stage that needs it */
return_err = ia_css_bufq_enqueue_buffer(thread_id,
queue_id,
diff --git a/drivers/staging/media/atomisp/pci/sh_css_params.c b/drivers/staging/media/atomisp/pci/sh_css_params.c
index f08564f58242..588f2adab058 100644
--- a/drivers/staging/media/atomisp/pci/sh_css_params.c
+++ b/drivers/staging/media/atomisp/pci/sh_css_params.c
@@ -98,17 +98,27 @@
#include "sh_css_frac.h"
#include "ia_css_bufq.h"
-#define FPNTBL_BYTES(binary) \
- (sizeof(char) * (binary)->in_frame_info.res.height * \
- (binary)->in_frame_info.padded_width)
+static size_t fpntbl_bytes(const struct ia_css_binary *binary)
+{
+ return array3_size(sizeof(char),
+ binary->in_frame_info.res.height,
+ binary->in_frame_info.padded_width);
+}
-#define SCTBL_BYTES(binary) \
- (sizeof(unsigned short) * (binary)->sctbl_height * \
- (binary)->sctbl_aligned_width_per_color * IA_CSS_SC_NUM_COLORS)
+static size_t sctbl_bytes(const struct ia_css_binary *binary)
+{
+ return size_mul(sizeof(unsigned short),
+ array3_size(binary->sctbl_height,
+ binary->sctbl_aligned_width_per_color,
+ IA_CSS_SC_NUM_COLORS));
+}
-#define MORPH_PLANE_BYTES(binary) \
- (SH_CSS_MORPH_TABLE_ELEM_BYTES * (binary)->morph_tbl_aligned_width * \
- (binary)->morph_tbl_height)
+static size_t morph_plane_bytes(const struct ia_css_binary *binary)
+{
+ return array3_size(SH_CSS_MORPH_TABLE_ELEM_BYTES,
+ binary->morph_tbl_aligned_width,
+ binary->morph_tbl_height);
+}
/* We keep a second copy of the ptr struct for the SP to access.
Again, this would not be necessary on the chip. */
@@ -3279,7 +3289,7 @@ sh_css_params_write_to_ddr_internal(
if (binary->info->sp.enable.fpnr) {
buff_realloced = reallocate_buffer(&ddr_map->fpn_tbl,
&ddr_map_size->fpn_tbl,
- (size_t)(FPNTBL_BYTES(binary)),
+ fpntbl_bytes(binary),
params->config_changed[IA_CSS_FPN_ID],
&err);
if (err) {
@@ -3304,7 +3314,7 @@ sh_css_params_write_to_ddr_internal(
buff_realloced = reallocate_buffer(&ddr_map->sc_tbl,
&ddr_map_size->sc_tbl,
- SCTBL_BYTES(binary),
+ sctbl_bytes(binary),
params->sc_table_changed,
&err);
if (err) {
@@ -3538,8 +3548,7 @@ sh_css_params_write_to_ddr_internal(
buff_realloced |=
reallocate_buffer(virt_addr_tetra_x[i],
virt_size_tetra_x[i],
- (size_t)
- (MORPH_PLANE_BYTES(binary)),
+ morph_plane_bytes(binary),
params->morph_table_changed,
&err);
if (err) {
@@ -3549,8 +3558,7 @@ sh_css_params_write_to_ddr_internal(
buff_realloced |=
reallocate_buffer(virt_addr_tetra_y[i],
virt_size_tetra_y[i],
- (size_t)
- (MORPH_PLANE_BYTES(binary)),
+ morph_plane_bytes(binary),
params->morph_table_changed,
&err);
if (err) {
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/Kconfig b/drivers/staging/media/av7110/Kconfig
index 1571eab31926..9faf9d2d4001 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/Kconfig
+++ b/drivers/staging/media/av7110/Kconfig
@@ -5,7 +5,7 @@ config DVB_AV7110_IR
default DVB_AV7110
config DVB_AV7110
- tristate "AV7110 cards (DEPRECATED)"
+ tristate "AV7110 cards"
depends on DVB_CORE && PCI && I2C
select TTPCI_EEPROM
select VIDEO_SAA7146_VV
@@ -35,13 +35,10 @@ config DVB_AV7110
kernel image by adding the filename to the EXTRA_FIRMWARE
configuration option string.
- This driver is deprecated and is scheduled for removal by
- the beginning of 2023. See the TODO file for more information.
-
Say Y if you own such a card and want to use it.
config DVB_AV7110_OSD
- bool "AV7110 OSD support (DEPRECATED)"
+ bool "AV7110 OSD support"
depends on DVB_AV7110
default y if DVB_AV7110=y || DVB_AV7110=m
help
@@ -52,13 +49,10 @@ config DVB_AV7110_OSD
Anyway, some popular DVB software like VDR uses this OSD to render
its menus, so say Y if you want to use this software.
- This driver is deprecated and is scheduled for removal by
- the beginning of 2023. See the TODO file for more information.
-
All other people say N.
config DVB_BUDGET_PATCH
- tristate "AV7110 cards with Budget Patch (DEPRECATED)"
+ tristate "AV7110 cards with Budget Patch"
depends on DVB_BUDGET_CORE && I2C
depends on DVB_AV7110
select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
@@ -74,9 +68,6 @@ config DVB_BUDGET_PATCH
standard AV7110 driver prior to loading this
driver.
- This driver is deprecated and is scheduled for removal by
- the beginning of 2023. See the TODO file for more information.
-
Say Y if you own such a card and want to use it.
To compile this driver as a module, choose M here: the
@@ -89,7 +80,7 @@ if DVB_AV7110
# it if we drop support for AV7110, as no other driver will use it.
config DVB_SP8870
- tristate "Spase sp8870 based (DEPRECATED)"
+ tristate "Spase sp8870 based"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
@@ -100,7 +91,4 @@ config DVB_SP8870
download/extract it, and then copy it to /usr/lib/hotplug/firmware
or /lib/firmware (depending on configuration of firmware hotplug).
- This driver is deprecated and is scheduled for removal by
- the beginning of 2023. See the TODO file for more information.
-
endif
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/Makefile b/drivers/staging/media/av7110/Makefile
index c04cd0a59109..307b267598ea 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/Makefile
+++ b/drivers/staging/media/av7110/Makefile
@@ -18,6 +18,5 @@ obj-$(CONFIG_DVB_SP8870) += sp8870.o
ccflags-y += -I $(srctree)/drivers/media/dvb-frontends
ccflags-y += -I $(srctree)/drivers/media/tuners
+ccflags-y += -I $(srctree)/drivers/media/pci/ttpci
ccflags-y += -I $(srctree)/drivers/media/common
-ccflags-y += -I $(srctree)/drivers/staging/media/deprecated/saa7146/ttpci
-ccflags-y += -I $(srctree)/drivers/staging/media/deprecated/saa7146/common
diff --git a/drivers/staging/media/av7110/TODO b/drivers/staging/media/av7110/TODO
new file mode 100644
index 000000000000..60062d8441b3
--- /dev/null
+++ b/drivers/staging/media/av7110/TODO
@@ -0,0 +1,3 @@
+- This driver is too old and relies on a different API.
+ Drop it from Kernel on a couple of versions.
+- Cleanup patches for the drivers here won't be accepted.
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-bilingual-channel-select.rst b/drivers/staging/media/av7110/audio-bilingual-channel-select.rst
index 33b5363317f1..33b5363317f1 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio-bilingual-channel-select.rst
+++ b/drivers/staging/media/av7110/audio-bilingual-channel-select.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-channel-select.rst b/drivers/staging/media/av7110/audio-channel-select.rst
index 74093df92a68..74093df92a68 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio-channel-select.rst
+++ b/drivers/staging/media/av7110/audio-channel-select.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-clear-buffer.rst b/drivers/staging/media/av7110/audio-clear-buffer.rst
index a0ebb0278260..a0ebb0278260 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio-clear-buffer.rst
+++ b/drivers/staging/media/av7110/audio-clear-buffer.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-continue.rst b/drivers/staging/media/av7110/audio-continue.rst
index a2e9850f37f2..a2e9850f37f2 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio-continue.rst
+++ b/drivers/staging/media/av7110/audio-continue.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-fclose.rst b/drivers/staging/media/av7110/audio-fclose.rst
index 77857d578e83..77857d578e83 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio-fclose.rst
+++ b/drivers/staging/media/av7110/audio-fclose.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-fopen.rst b/drivers/staging/media/av7110/audio-fopen.rst
index 774daaab3bad..774daaab3bad 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio-fopen.rst
+++ b/drivers/staging/media/av7110/audio-fopen.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-fwrite.rst b/drivers/staging/media/av7110/audio-fwrite.rst
index 7b096ac2b6c4..7b096ac2b6c4 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio-fwrite.rst
+++ b/drivers/staging/media/av7110/audio-fwrite.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-get-capabilities.rst b/drivers/staging/media/av7110/audio-get-capabilities.rst
index 6d9eb71dad17..6d9eb71dad17 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio-get-capabilities.rst
+++ b/drivers/staging/media/av7110/audio-get-capabilities.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-get-status.rst b/drivers/staging/media/av7110/audio-get-status.rst
index 7ae8db2e65e9..7ae8db2e65e9 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio-get-status.rst
+++ b/drivers/staging/media/av7110/audio-get-status.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-pause.rst b/drivers/staging/media/av7110/audio-pause.rst
index d37d1ddce4df..d37d1ddce4df 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio-pause.rst
+++ b/drivers/staging/media/av7110/audio-pause.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-play.rst b/drivers/staging/media/av7110/audio-play.rst
index e591930b6ca7..e591930b6ca7 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio-play.rst
+++ b/drivers/staging/media/av7110/audio-play.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-select-source.rst b/drivers/staging/media/av7110/audio-select-source.rst
index 6a0c0f365eb1..6a0c0f365eb1 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio-select-source.rst
+++ b/drivers/staging/media/av7110/audio-select-source.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-av-sync.rst b/drivers/staging/media/av7110/audio-set-av-sync.rst
index 85a8016bf025..85a8016bf025 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-av-sync.rst
+++ b/drivers/staging/media/av7110/audio-set-av-sync.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-bypass-mode.rst b/drivers/staging/media/av7110/audio-set-bypass-mode.rst
index 80d551a2053a..80d551a2053a 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-bypass-mode.rst
+++ b/drivers/staging/media/av7110/audio-set-bypass-mode.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-id.rst b/drivers/staging/media/av7110/audio-set-id.rst
index 39ad846d412d..39ad846d412d 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-id.rst
+++ b/drivers/staging/media/av7110/audio-set-id.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-mixer.rst b/drivers/staging/media/av7110/audio-set-mixer.rst
index 45dbdf4801e0..45dbdf4801e0 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-mixer.rst
+++ b/drivers/staging/media/av7110/audio-set-mixer.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-mute.rst b/drivers/staging/media/av7110/audio-set-mute.rst
index 987751f92967..987751f92967 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-mute.rst
+++ b/drivers/staging/media/av7110/audio-set-mute.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-streamtype.rst b/drivers/staging/media/av7110/audio-set-streamtype.rst
index 77d73c74882f..77d73c74882f 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-streamtype.rst
+++ b/drivers/staging/media/av7110/audio-set-streamtype.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-stop.rst b/drivers/staging/media/av7110/audio-stop.rst
index d77f786fd797..d77f786fd797 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio-stop.rst
+++ b/drivers/staging/media/av7110/audio-stop.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio.rst b/drivers/staging/media/av7110/audio.rst
index aa753336b31f..aa753336b31f 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio.rst
+++ b/drivers/staging/media/av7110/audio.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio_data_types.rst b/drivers/staging/media/av7110/audio_data_types.rst
index 4744529136a8..4744529136a8 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio_data_types.rst
+++ b/drivers/staging/media/av7110/audio_data_types.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio_function_calls.rst b/drivers/staging/media/av7110/audio_function_calls.rst
index fa5ba9539caf..fa5ba9539caf 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/audio_function_calls.rst
+++ b/drivers/staging/media/av7110/audio_function_calls.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110.c b/drivers/staging/media/av7110/av7110.c
index df81a9b744c2..df81a9b744c2 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/av7110.c
+++ b/drivers/staging/media/av7110/av7110.c
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110.h b/drivers/staging/media/av7110/av7110.h
index 9fde69b38f1c..809d938ae166 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/av7110.h
+++ b/drivers/staging/media/av7110/av7110.h
@@ -33,7 +33,7 @@
#include "stv0297.h"
#include "l64781.h"
-#include "saa7146_vv.h"
+#include <media/drv-intf/saa7146_vv.h>
#define ANALOG_TUNER_VES1820 1
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_av.c b/drivers/staging/media/av7110/av7110_av.c
index 0bf513c26b6b..0bf513c26b6b 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/av7110_av.c
+++ b/drivers/staging/media/av7110/av7110_av.c
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_av.h b/drivers/staging/media/av7110/av7110_av.h
index 71bbd4391f57..71bbd4391f57 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/av7110_av.h
+++ b/drivers/staging/media/av7110/av7110_av.h
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_ca.c b/drivers/staging/media/av7110/av7110_ca.c
index c1338e074a3d..c1338e074a3d 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/av7110_ca.c
+++ b/drivers/staging/media/av7110/av7110_ca.c
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_ca.h b/drivers/staging/media/av7110/av7110_ca.h
index a6e3f2955730..a6e3f2955730 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/av7110_ca.h
+++ b/drivers/staging/media/av7110/av7110_ca.h
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_hw.c b/drivers/staging/media/av7110/av7110_hw.c
index 93ca31e38ddd..93ca31e38ddd 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/av7110_hw.c
+++ b/drivers/staging/media/av7110/av7110_hw.c
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_hw.h b/drivers/staging/media/av7110/av7110_hw.h
index 6380d8950c69..6380d8950c69 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/av7110_hw.h
+++ b/drivers/staging/media/av7110/av7110_hw.h
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_ipack.c b/drivers/staging/media/av7110/av7110_ipack.c
index 30330ed01ce8..30330ed01ce8 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/av7110_ipack.c
+++ b/drivers/staging/media/av7110/av7110_ipack.c
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_ipack.h b/drivers/staging/media/av7110/av7110_ipack.h
index 943ec899bb93..943ec899bb93 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/av7110_ipack.h
+++ b/drivers/staging/media/av7110/av7110_ipack.h
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_ir.c b/drivers/staging/media/av7110/av7110_ir.c
index a851ba328e4a..a851ba328e4a 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/av7110_ir.c
+++ b/drivers/staging/media/av7110/av7110_ir.c
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_v4l.c b/drivers/staging/media/av7110/av7110_v4l.c
index c89f536f699c..c89f536f699c 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/av7110_v4l.c
+++ b/drivers/staging/media/av7110/av7110_v4l.c
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/budget-patch.c b/drivers/staging/media/av7110/budget-patch.c
index d173c8ade6a7..d173c8ade6a7 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/budget-patch.c
+++ b/drivers/staging/media/av7110/budget-patch.c
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/dvb_filter.c b/drivers/staging/media/av7110/dvb_filter.c
index 8c2eca5dcdc9..8c2eca5dcdc9 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/dvb_filter.c
+++ b/drivers/staging/media/av7110/dvb_filter.c
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/dvb_filter.h b/drivers/staging/media/av7110/dvb_filter.h
index 67a3c6333bca..67a3c6333bca 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/dvb_filter.h
+++ b/drivers/staging/media/av7110/dvb_filter.h
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/sp8870.c b/drivers/staging/media/av7110/sp8870.c
index 9767159aeb9b..9767159aeb9b 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/sp8870.c
+++ b/drivers/staging/media/av7110/sp8870.c
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/sp8870.h b/drivers/staging/media/av7110/sp8870.h
index 5eacf39f425e..5eacf39f425e 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/sp8870.h
+++ b/drivers/staging/media/av7110/sp8870.h
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-clear-buffer.rst b/drivers/staging/media/av7110/video-clear-buffer.rst
index a7730559bbb2..a7730559bbb2 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-clear-buffer.rst
+++ b/drivers/staging/media/av7110/video-clear-buffer.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-command.rst b/drivers/staging/media/av7110/video-command.rst
index cae9445eb3af..cae9445eb3af 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-command.rst
+++ b/drivers/staging/media/av7110/video-command.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-continue.rst b/drivers/staging/media/av7110/video-continue.rst
index bc34bf3989e4..bc34bf3989e4 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-continue.rst
+++ b/drivers/staging/media/av7110/video-continue.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-fast-forward.rst b/drivers/staging/media/av7110/video-fast-forward.rst
index e71fa8d6965b..e71fa8d6965b 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-fast-forward.rst
+++ b/drivers/staging/media/av7110/video-fast-forward.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-fclose.rst b/drivers/staging/media/av7110/video-fclose.rst
index 01d24d548439..01d24d548439 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-fclose.rst
+++ b/drivers/staging/media/av7110/video-fclose.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-fopen.rst b/drivers/staging/media/av7110/video-fopen.rst
index 1371b083e4e8..1371b083e4e8 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-fopen.rst
+++ b/drivers/staging/media/av7110/video-fopen.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-freeze.rst b/drivers/staging/media/av7110/video-freeze.rst
index 4321f257cb70..4321f257cb70 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-freeze.rst
+++ b/drivers/staging/media/av7110/video-freeze.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-fwrite.rst b/drivers/staging/media/av7110/video-fwrite.rst
index a07fd7d7a40e..a07fd7d7a40e 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-fwrite.rst
+++ b/drivers/staging/media/av7110/video-fwrite.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-get-capabilities.rst b/drivers/staging/media/av7110/video-get-capabilities.rst
index 01e09f56656c..01e09f56656c 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-get-capabilities.rst
+++ b/drivers/staging/media/av7110/video-get-capabilities.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-get-event.rst b/drivers/staging/media/av7110/video-get-event.rst
index 90382bc36cfe..90382bc36cfe 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-get-event.rst
+++ b/drivers/staging/media/av7110/video-get-event.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-get-frame-count.rst b/drivers/staging/media/av7110/video-get-frame-count.rst
index b48ac8c58a41..b48ac8c58a41 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-get-frame-count.rst
+++ b/drivers/staging/media/av7110/video-get-frame-count.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-get-pts.rst b/drivers/staging/media/av7110/video-get-pts.rst
index fedaff41be0b..fedaff41be0b 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-get-pts.rst
+++ b/drivers/staging/media/av7110/video-get-pts.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-get-size.rst b/drivers/staging/media/av7110/video-get-size.rst
index de34331c5bd1..de34331c5bd1 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-get-size.rst
+++ b/drivers/staging/media/av7110/video-get-size.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-get-status.rst b/drivers/staging/media/av7110/video-get-status.rst
index 9b86fbf411d4..9b86fbf411d4 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-get-status.rst
+++ b/drivers/staging/media/av7110/video-get-status.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-play.rst b/drivers/staging/media/av7110/video-play.rst
index 35ac8b98fdbf..35ac8b98fdbf 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-play.rst
+++ b/drivers/staging/media/av7110/video-play.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-select-source.rst b/drivers/staging/media/av7110/video-select-source.rst
index 929a20985d53..929a20985d53 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-select-source.rst
+++ b/drivers/staging/media/av7110/video-select-source.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-set-blank.rst b/drivers/staging/media/av7110/video-set-blank.rst
index 70249a6ba125..70249a6ba125 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-set-blank.rst
+++ b/drivers/staging/media/av7110/video-set-blank.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-set-display-format.rst b/drivers/staging/media/av7110/video-set-display-format.rst
index 1de4f40ae732..1de4f40ae732 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-set-display-format.rst
+++ b/drivers/staging/media/av7110/video-set-display-format.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-set-format.rst b/drivers/staging/media/av7110/video-set-format.rst
index bb64e37ae081..bb64e37ae081 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-set-format.rst
+++ b/drivers/staging/media/av7110/video-set-format.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-set-streamtype.rst b/drivers/staging/media/av7110/video-set-streamtype.rst
index 1f31c048bdbc..1f31c048bdbc 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-set-streamtype.rst
+++ b/drivers/staging/media/av7110/video-set-streamtype.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-slowmotion.rst b/drivers/staging/media/av7110/video-slowmotion.rst
index 1478fcc30cb8..1478fcc30cb8 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-slowmotion.rst
+++ b/drivers/staging/media/av7110/video-slowmotion.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-stillpicture.rst b/drivers/staging/media/av7110/video-stillpicture.rst
index d25384222a20..d25384222a20 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-stillpicture.rst
+++ b/drivers/staging/media/av7110/video-stillpicture.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-stop.rst b/drivers/staging/media/av7110/video-stop.rst
index 96f61c5b48a2..96f61c5b48a2 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-stop.rst
+++ b/drivers/staging/media/av7110/video-stop.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-try-command.rst b/drivers/staging/media/av7110/video-try-command.rst
index 79bf3dfb8a32..79bf3dfb8a32 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video-try-command.rst
+++ b/drivers/staging/media/av7110/video-try-command.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video.rst b/drivers/staging/media/av7110/video.rst
index 808705b769a1..808705b769a1 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video.rst
+++ b/drivers/staging/media/av7110/video.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video_function_calls.rst b/drivers/staging/media/av7110/video_function_calls.rst
index 20a897be5dca..20a897be5dca 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video_function_calls.rst
+++ b/drivers/staging/media/av7110/video_function_calls.rst
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video_types.rst b/drivers/staging/media/av7110/video_types.rst
index c4557d328b7a..c4557d328b7a 100644
--- a/drivers/staging/media/deprecated/saa7146/av7110/video_types.rst
+++ b/drivers/staging/media/av7110/video_types.rst
diff --git a/drivers/staging/media/deprecated/cpia2/Kconfig b/drivers/staging/media/deprecated/cpia2/Kconfig
deleted file mode 100644
index ee3b25a759d4..000000000000
--- a/drivers/staging/media/deprecated/cpia2/Kconfig
+++ /dev/null
@@ -1,13 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-config VIDEO_CPIA2
- tristate "CPiA2 Video For Linux (DEPRECATED)"
- depends on USB && VIDEO_DEV
- help
- This is the video4linux driver for cameras based on Vision's CPiA2
- (Colour Processor Interface ASIC), such as the Digital Blue QX5
- Microscope. If you have one of these cameras, say Y here
-
- This driver is deprecated and is scheduled for removal by
- the beginning of 2023. See the TODO file for more information.
-
- This driver is also available as a module (cpia2).
diff --git a/drivers/staging/media/deprecated/cpia2/Makefile b/drivers/staging/media/deprecated/cpia2/Makefile
deleted file mode 100644
index 05664141f4d7..000000000000
--- a/drivers/staging/media/deprecated/cpia2/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-cpia2-objs := cpia2_v4l.o cpia2_usb.o cpia2_core.o
-
-obj-$(CONFIG_VIDEO_CPIA2) += cpia2.o
diff --git a/drivers/staging/media/deprecated/cpia2/TODO b/drivers/staging/media/deprecated/cpia2/TODO
deleted file mode 100644
index 92ac8718d164..000000000000
--- a/drivers/staging/media/deprecated/cpia2/TODO
+++ /dev/null
@@ -1,6 +0,0 @@
-The cpia2 driver does not use the vb2 framework for streaming
-video, instead it implements this in the driver.
-
-To prevent removal of this driver early 2023 it has to be
-converted to use vb2. Contact the linux-media@vger.kernel.org
-mailing list if you want to do this.
diff --git a/drivers/staging/media/deprecated/cpia2/cpia2.h b/drivers/staging/media/deprecated/cpia2/cpia2.h
deleted file mode 100644
index 57b7f1ea68da..000000000000
--- a/drivers/staging/media/deprecated/cpia2/cpia2.h
+++ /dev/null
@@ -1,475 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/****************************************************************************
- *
- * Filename: cpia2.h
- *
- * Copyright 2001, STMicrolectronics, Inc.
- *
- * Contact: steve.miller@st.com
- *
- * Description:
- * This is a USB driver for CPiA2 based video cameras.
- *
- * This driver is modelled on the cpia usb driver by
- * Jochen Scharrlach and Johannes Erdfeldt.
- *
- ****************************************************************************/
-
-#ifndef __CPIA2_H__
-#define __CPIA2_H__
-
-#include <linux/videodev2.h>
-#include <linux/usb.h>
-#include <linux/poll.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-ctrls.h>
-
-#include "cpia2_registers.h"
-
-/* define for verbose debug output */
-//#define _CPIA2_DEBUG_
-
-/***
- * Image defines
- ***/
-
-/* Misc constants */
-#define ALLOW_CORRUPT 0 /* Causes collater to discard checksum */
-
-/* USB Transfer mode */
-#define XFER_ISOC 0
-#define XFER_BULK 1
-
-/* USB Alternates */
-#define USBIF_CMDONLY 0
-#define USBIF_BULK 1
-#define USBIF_ISO_1 2 /* 128 bytes/ms */
-#define USBIF_ISO_2 3 /* 384 bytes/ms */
-#define USBIF_ISO_3 4 /* 640 bytes/ms */
-#define USBIF_ISO_4 5 /* 768 bytes/ms */
-#define USBIF_ISO_5 6 /* 896 bytes/ms */
-#define USBIF_ISO_6 7 /* 1023 bytes/ms */
-
-/* Flicker Modes */
-#define NEVER_FLICKER 0
-#define FLICKER_60 60
-#define FLICKER_50 50
-
-/* Debug flags */
-#define DEBUG_NONE 0
-#define DEBUG_REG 0x00000001
-#define DEBUG_DUMP_PATCH 0x00000002
-#define DEBUG_DUMP_REGS 0x00000004
-
-/***
- * Video frame sizes
- ***/
-enum {
- VIDEOSIZE_VGA = 0, /* 640x480 */
- VIDEOSIZE_CIF, /* 352x288 */
- VIDEOSIZE_QVGA, /* 320x240 */
- VIDEOSIZE_QCIF, /* 176x144 */
- VIDEOSIZE_288_216,
- VIDEOSIZE_256_192,
- VIDEOSIZE_224_168,
- VIDEOSIZE_192_144,
-};
-
-#define STV_IMAGE_CIF_ROWS 288
-#define STV_IMAGE_CIF_COLS 352
-
-#define STV_IMAGE_QCIF_ROWS 144
-#define STV_IMAGE_QCIF_COLS 176
-
-#define STV_IMAGE_VGA_ROWS 480
-#define STV_IMAGE_VGA_COLS 640
-
-#define STV_IMAGE_QVGA_ROWS 240
-#define STV_IMAGE_QVGA_COLS 320
-
-#define JPEG_MARKER_COM (1<<6) /* Comment segment */
-
-/***
- * Enums
- ***/
-/* Sensor types available with cpia2 asics */
-enum sensors {
- CPIA2_SENSOR_410,
- CPIA2_SENSOR_500
-};
-
-/* Asic types available in the CPiA2 architecture */
-#define CPIA2_ASIC_672 0x67
-
-/* Device types (stv672, stv676, etc) */
-#define DEVICE_STV_672 0x0001
-#define DEVICE_STV_676 0x0002
-
-enum frame_status {
- FRAME_EMPTY,
- FRAME_READING, /* In the process of being grabbed into */
- FRAME_READY, /* Ready to be read */
- FRAME_ERROR,
-};
-
-/***
- * Register access (for USB request byte)
- ***/
-enum {
- CAMERAACCESS_SYSTEM = 0,
- CAMERAACCESS_VC,
- CAMERAACCESS_VP,
- CAMERAACCESS_IDATA
-};
-
-#define CAMERAACCESS_TYPE_BLOCK 0x00
-#define CAMERAACCESS_TYPE_RANDOM 0x04
-#define CAMERAACCESS_TYPE_MASK 0x08
-#define CAMERAACCESS_TYPE_REPEAT 0x0C
-
-#define TRANSFER_READ 0
-#define TRANSFER_WRITE 1
-
-#define DEFAULT_ALT USBIF_ISO_6
-#define DEFAULT_BRIGHTNESS 0x46
-#define DEFAULT_CONTRAST 0x93
-#define DEFAULT_SATURATION 0x7f
-
-/* Power state */
-#define HI_POWER_MODE CPIA2_SYSTEM_CONTROL_HIGH_POWER
-#define LO_POWER_MODE CPIA2_SYSTEM_CONTROL_LOW_POWER
-
-
-/********
- * Commands
- *******/
-enum {
- CPIA2_CMD_NONE = 0,
- CPIA2_CMD_GET_VERSION,
- CPIA2_CMD_GET_PNP_ID,
- CPIA2_CMD_GET_ASIC_TYPE,
- CPIA2_CMD_GET_SENSOR,
- CPIA2_CMD_GET_VP_DEVICE,
- CPIA2_CMD_GET_VP_BRIGHTNESS,
- CPIA2_CMD_SET_VP_BRIGHTNESS,
- CPIA2_CMD_GET_CONTRAST,
- CPIA2_CMD_SET_CONTRAST,
- CPIA2_CMD_GET_VP_SATURATION,
- CPIA2_CMD_SET_VP_SATURATION,
- CPIA2_CMD_GET_VP_GPIO_DIRECTION,
- CPIA2_CMD_SET_VP_GPIO_DIRECTION,
- CPIA2_CMD_GET_VP_GPIO_DATA,
- CPIA2_CMD_SET_VP_GPIO_DATA,
- CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION,
- CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION,
- CPIA2_CMD_GET_VC_MP_GPIO_DATA,
- CPIA2_CMD_SET_VC_MP_GPIO_DATA,
- CPIA2_CMD_ENABLE_PACKET_CTRL,
- CPIA2_CMD_GET_FLICKER_MODES,
- CPIA2_CMD_SET_FLICKER_MODES,
- CPIA2_CMD_RESET_FIFO, /* clear fifo and enable stream block */
- CPIA2_CMD_SET_HI_POWER,
- CPIA2_CMD_SET_LOW_POWER,
- CPIA2_CMD_CLEAR_V2W_ERR,
- CPIA2_CMD_SET_USER_MODE,
- CPIA2_CMD_GET_USER_MODE,
- CPIA2_CMD_FRAMERATE_REQ,
- CPIA2_CMD_SET_COMPRESSION_STATE,
- CPIA2_CMD_GET_WAKEUP,
- CPIA2_CMD_SET_WAKEUP,
- CPIA2_CMD_GET_PW_CONTROL,
- CPIA2_CMD_SET_PW_CONTROL,
- CPIA2_CMD_GET_SYSTEM_CTRL,
- CPIA2_CMD_SET_SYSTEM_CTRL,
- CPIA2_CMD_GET_VP_SYSTEM_STATE,
- CPIA2_CMD_GET_VP_SYSTEM_CTRL,
- CPIA2_CMD_SET_VP_SYSTEM_CTRL,
- CPIA2_CMD_GET_VP_EXP_MODES,
- CPIA2_CMD_SET_VP_EXP_MODES,
- CPIA2_CMD_GET_DEVICE_CONFIG,
- CPIA2_CMD_SET_DEVICE_CONFIG,
- CPIA2_CMD_SET_SERIAL_ADDR,
- CPIA2_CMD_SET_SENSOR_CR1,
- CPIA2_CMD_GET_VC_CONTROL,
- CPIA2_CMD_SET_VC_CONTROL,
- CPIA2_CMD_SET_TARGET_KB,
- CPIA2_CMD_SET_DEF_JPEG_OPT,
- CPIA2_CMD_REHASH_VP4,
- CPIA2_CMD_GET_USER_EFFECTS,
- CPIA2_CMD_SET_USER_EFFECTS
-};
-
-enum user_cmd {
- COMMAND_NONE = 0x00000001,
- COMMAND_SET_FPS = 0x00000002,
- COMMAND_SET_COLOR_PARAMS = 0x00000004,
- COMMAND_GET_COLOR_PARAMS = 0x00000008,
- COMMAND_SET_FORMAT = 0x00000010, /* size, etc */
- COMMAND_SET_FLICKER = 0x00000020
-};
-
-/***
- * Some defines specific to the 676 chip
- ***/
-#define CAMACC_CIF 0x01
-#define CAMACC_VGA 0x02
-#define CAMACC_QCIF 0x04
-#define CAMACC_QVGA 0x08
-
-
-struct cpia2_register {
- u8 index;
- u8 value;
-};
-
-struct cpia2_reg_mask {
- u8 index;
- u8 and_mask;
- u8 or_mask;
- u8 fill;
-};
-
-struct cpia2_command {
- u32 command;
- u8 req_mode; /* (Block or random) | registerBank */
- u8 reg_count;
- u8 direction;
- u8 start;
- union reg_types {
- struct cpia2_register registers[32];
- struct cpia2_reg_mask masks[16];
- u8 block_data[64];
- u8 *patch_data; /* points to function defined block */
- } buffer;
-};
-
-struct camera_params {
- struct {
- u8 firmware_revision_hi; /* For system register set (bank 0) */
- u8 firmware_revision_lo;
- u8 asic_id; /* Video Compressor set (bank 1) */
- u8 asic_rev;
- u8 vp_device_hi; /* Video Processor set (bank 2) */
- u8 vp_device_lo;
- u8 sensor_flags;
- u8 sensor_rev;
- } version;
-
- struct {
- u32 device_type; /* enumerated from vendor/product ids.
- * Currently, either STV_672 or STV_676 */
- u16 vendor;
- u16 product;
- u16 device_revision;
- } pnp_id;
-
- struct {
- u8 brightness; /* CPIA2_VP_EXPOSURE_TARGET */
- u8 contrast; /* Note: this is CPIA2_VP_YRANGE */
- u8 saturation; /* CPIA2_VP_SATURATION */
- } color_params;
-
- struct {
- u8 cam_register;
- u8 flicker_mode_req; /* 1 if flicker on, else never flicker */
- } flicker_control;
-
- struct {
- u8 jpeg_options;
- u8 creep_period;
- u8 user_squeeze;
- u8 inhibit_htables;
- } compression;
-
- struct {
- u8 ohsize; /* output image size */
- u8 ovsize;
- u8 hcrop; /* cropping start_pos/4 */
- u8 vcrop;
- u8 hphase; /* scaling registers */
- u8 vphase;
- u8 hispan;
- u8 vispan;
- u8 hicrop;
- u8 vicrop;
- u8 hifraction;
- u8 vifraction;
- } image_size;
-
- struct {
- int width; /* actual window width */
- int height; /* actual window height */
- } roi;
-
- struct {
- u8 video_mode;
- u8 frame_rate;
- u8 video_size; /* Not a register, just a convenience for cropped sizes */
- u8 gpio_direction;
- u8 gpio_data;
- u8 system_ctrl;
- u8 system_state;
- u8 lowlight_boost; /* Bool: 0 = off, 1 = on */
- u8 device_config;
- u8 exposure_modes;
- u8 user_effects;
- } vp_params;
-
- struct {
- u8 pw_control;
- u8 wakeup;
- u8 vc_control;
- u8 vc_mp_direction;
- u8 vc_mp_data;
- u8 quality;
- } vc_params;
-
- struct {
- u8 power_mode;
- u8 system_ctrl;
- u8 stream_mode; /* This is the current alternate for usb drivers */
- u8 allow_corrupt;
- } camera_state;
-};
-
-#define NUM_SBUF 2
-
-struct cpia2_sbuf {
- char *data;
- struct urb *urb;
-};
-
-struct framebuf {
- u64 ts;
- unsigned long seq;
- int num;
- int length;
- int max_length;
- volatile enum frame_status status;
- u8 *data;
- struct framebuf *next;
-};
-
-struct camera_data {
- /* locks */
- struct v4l2_device v4l2_dev;
- struct mutex v4l2_lock; /* serialize file operations */
- struct v4l2_ctrl_handler hdl;
- struct {
- /* Lights control cluster */
- struct v4l2_ctrl *top_light;
- struct v4l2_ctrl *bottom_light;
- };
- struct v4l2_ctrl *usb_alt;
-
- /* camera status */
- int first_image_seen;
- enum sensors sensor_type;
- u8 flush;
- struct v4l2_fh *stream_fh;
- u8 mmapped;
- int streaming; /* 0 = no, 1 = yes */
- int xfer_mode; /* XFER_BULK or XFER_ISOC */
- struct camera_params params; /* camera settings */
-
- /* v4l */
- int video_size; /* VIDEO_SIZE_ */
- struct video_device vdev; /* v4l videodev */
- u32 width;
- u32 height; /* Its size */
- __u32 pixelformat; /* Format fourcc */
-
- /* USB */
- struct usb_device *dev;
- unsigned char iface;
- unsigned int cur_alt;
- unsigned int old_alt;
- struct cpia2_sbuf sbuf[NUM_SBUF]; /* Double buffering */
-
- wait_queue_head_t wq_stream;
-
- /* Buffering */
- u32 frame_size;
- int num_frames;
- unsigned long frame_count;
- u8 *frame_buffer; /* frame buffer data */
- struct framebuf *buffers;
- struct framebuf * volatile curbuff;
- struct framebuf *workbuff;
-
- /* MJPEG Extension */
- int APPn; /* Number of APP segment to be written, must be 0..15 */
- int APP_len; /* Length of data in JPEG APPn segment */
- char APP_data[60]; /* Data in the JPEG APPn segment. */
-
- int COM_len; /* Length of data in JPEG COM segment */
- char COM_data[60]; /* Data in JPEG COM segment */
-};
-
-/* v4l */
-int cpia2_register_camera(struct camera_data *cam);
-void cpia2_unregister_camera(struct camera_data *cam);
-void cpia2_camera_release(struct v4l2_device *v4l2_dev);
-
-/* core */
-int cpia2_reset_camera(struct camera_data *cam);
-int cpia2_set_low_power(struct camera_data *cam);
-void cpia2_dbg_dump_registers(struct camera_data *cam);
-int cpia2_match_video_size(int width, int height);
-void cpia2_set_camera_state(struct camera_data *cam);
-void cpia2_save_camera_state(struct camera_data *cam);
-void cpia2_set_color_params(struct camera_data *cam);
-void cpia2_set_brightness(struct camera_data *cam, unsigned char value);
-void cpia2_set_contrast(struct camera_data *cam, unsigned char value);
-void cpia2_set_saturation(struct camera_data *cam, unsigned char value);
-int cpia2_set_flicker_mode(struct camera_data *cam, int mode);
-void cpia2_set_format(struct camera_data *cam);
-int cpia2_send_command(struct camera_data *cam, struct cpia2_command *cmd);
-int cpia2_do_command(struct camera_data *cam,
- unsigned int command,
- unsigned char direction, unsigned char param);
-void cpia2_deinit_camera_struct(struct camera_data *cam, struct usb_interface *intf);
-struct camera_data *cpia2_init_camera_struct(struct usb_interface *intf);
-int cpia2_init_camera(struct camera_data *cam);
-int cpia2_allocate_buffers(struct camera_data *cam);
-void cpia2_free_buffers(struct camera_data *cam);
-long cpia2_read(struct camera_data *cam,
- char __user *buf, unsigned long count, int noblock);
-__poll_t cpia2_poll(struct camera_data *cam,
- struct file *filp, poll_table *wait);
-int cpia2_remap_buffer(struct camera_data *cam, struct vm_area_struct *vma);
-void cpia2_set_property_flip(struct camera_data *cam, int prop_val);
-void cpia2_set_property_mirror(struct camera_data *cam, int prop_val);
-int cpia2_set_gpio(struct camera_data *cam, unsigned char setting);
-int cpia2_set_fps(struct camera_data *cam, int framerate);
-
-/* usb */
-int cpia2_usb_init(void);
-void cpia2_usb_cleanup(void);
-int cpia2_usb_transfer_cmd(struct camera_data *cam, void *registers,
- u8 request, u8 start, u8 count, u8 direction);
-int cpia2_usb_stream_start(struct camera_data *cam, unsigned int alternate);
-int cpia2_usb_stream_stop(struct camera_data *cam);
-int cpia2_usb_stream_pause(struct camera_data *cam);
-int cpia2_usb_stream_resume(struct camera_data *cam);
-int cpia2_usb_change_streaming_alternate(struct camera_data *cam,
- unsigned int alt);
-
-
-/* ----------------------- debug functions ---------------------- */
-#ifdef _CPIA2_DEBUG_
-#define ALOG(lev, fmt, args...) printk(lev "%s:%d %s(): " fmt, __FILE__, __LINE__, __func__, ## args)
-#define LOG(fmt, args...) ALOG(KERN_INFO, fmt, ## args)
-#define ERR(fmt, args...) ALOG(KERN_ERR, fmt, ## args)
-#define DBG(fmt, args...) ALOG(KERN_DEBUG, fmt, ## args)
-#else
-#define ALOG(fmt,args...) printk(fmt,##args)
-#define LOG(fmt,args...) ALOG(KERN_INFO "cpia2: "fmt,##args)
-#define ERR(fmt,args...) ALOG(KERN_ERR "cpia2: "fmt,##args)
-#define DBG(fmn,args...) do {} while(0)
-#endif
-/* No function or lineno, for shorter lines */
-#define KINFO(fmt, args...) printk(KERN_INFO fmt,##args)
-
-#endif
diff --git a/drivers/staging/media/deprecated/cpia2/cpia2_core.c b/drivers/staging/media/deprecated/cpia2/cpia2_core.c
deleted file mode 100644
index b5a2d06fb356..000000000000
--- a/drivers/staging/media/deprecated/cpia2/cpia2_core.c
+++ /dev/null
@@ -1,2434 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/****************************************************************************
- *
- * Filename: cpia2_core.c
- *
- * Copyright 2001, STMicrolectronics, Inc.
- * Contact: steve.miller@st.com
- *
- * Description:
- * This is a USB driver for CPia2 based video cameras.
- * The infrastructure of this driver is based on the cpia usb driver by
- * Jochen Scharrlach and Johannes Erdfeldt.
- *
- * Stripped of 2.4 stuff ready for main kernel submit by
- * Alan Cox <alan@lxorguk.ukuu.org.uk>
- *
- ****************************************************************************/
-
-#include "cpia2.h"
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/vmalloc.h>
-#include <linux/firmware.h>
-#include <linux/sched/signal.h>
-
-#define FIRMWARE "cpia2/stv0672_vp4.bin"
-MODULE_FIRMWARE(FIRMWARE);
-
-/* #define _CPIA2_DEBUG_ */
-
-#ifdef _CPIA2_DEBUG_
-
-static const char *block_name[] = {
- "System",
- "VC",
- "VP",
- "IDATA"
-};
-#endif
-
-static unsigned int debugs_on; /* default 0 - DEBUG_REG */
-
-
-/******************************************************************************
- *
- * Forward Declarations
- *
- *****************************************************************************/
-static int apply_vp_patch(struct camera_data *cam);
-static int set_default_user_mode(struct camera_data *cam);
-static int set_vw_size(struct camera_data *cam, int size);
-static int configure_sensor(struct camera_data *cam,
- int reqwidth, int reqheight);
-static int config_sensor_410(struct camera_data *cam,
- int reqwidth, int reqheight);
-static int config_sensor_500(struct camera_data *cam,
- int reqwidth, int reqheight);
-static int set_all_properties(struct camera_data *cam);
-static void wake_system(struct camera_data *cam);
-static void set_lowlight_boost(struct camera_data *cam);
-static void reset_camera_struct(struct camera_data *cam);
-static int cpia2_set_high_power(struct camera_data *cam);
-
-/* Here we want the physical address of the memory.
- * This is used when initializing the contents of the
- * area and marking the pages as reserved.
- */
-static inline unsigned long kvirt_to_pa(unsigned long adr)
-{
- unsigned long kva, ret;
-
- kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
- kva |= adr & (PAGE_SIZE-1); /* restore the offset */
- ret = __pa(kva);
- return ret;
-}
-
-static void *rvmalloc(unsigned long size)
-{
- void *mem;
- unsigned long adr;
-
- /* Round it off to PAGE_SIZE */
- size = PAGE_ALIGN(size);
-
- mem = vmalloc_32(size);
- if (!mem)
- return NULL;
-
- memset(mem, 0, size); /* Clear the ram out, no junk to the user */
- adr = (unsigned long) mem;
-
- while ((long)size > 0) {
- SetPageReserved(vmalloc_to_page((void *)adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
- return mem;
-}
-
-static void rvfree(void *mem, unsigned long size)
-{
- unsigned long adr;
-
- if (!mem)
- return;
-
- size = PAGE_ALIGN(size);
-
- adr = (unsigned long) mem;
- while ((long)size > 0) {
- ClearPageReserved(vmalloc_to_page((void *)adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
- vfree(mem);
-}
-
-/******************************************************************************
- *
- * cpia2_do_command
- *
- * Send an arbitrary command to the camera. For commands that read from
- * the camera, copy the buffers into the proper param structures.
- *****************************************************************************/
-int cpia2_do_command(struct camera_data *cam,
- u32 command, u8 direction, u8 param)
-{
- int retval = 0;
- struct cpia2_command cmd;
- unsigned int device = cam->params.pnp_id.device_type;
-
- cmd.command = command;
- cmd.reg_count = 2; /* default */
- cmd.direction = direction;
-
- /***
- * Set up the command.
- ***/
- switch (command) {
- case CPIA2_CMD_GET_VERSION:
- cmd.req_mode =
- CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
- cmd.start = CPIA2_SYSTEM_DEVICE_HI;
- break;
- case CPIA2_CMD_GET_PNP_ID:
- cmd.req_mode =
- CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
- cmd.reg_count = 8;
- cmd.start = CPIA2_SYSTEM_DESCRIP_VID_HI;
- break;
- case CPIA2_CMD_GET_ASIC_TYPE:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
- cmd.start = CPIA2_VC_ASIC_ID;
- break;
- case CPIA2_CMD_GET_SENSOR:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
- cmd.start = CPIA2_VP_SENSOR_FLAGS;
- break;
- case CPIA2_CMD_GET_VP_DEVICE:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
- cmd.start = CPIA2_VP_DEVICEH;
- break;
- case CPIA2_CMD_SET_VP_BRIGHTNESS:
- cmd.buffer.block_data[0] = param;
- fallthrough;
- case CPIA2_CMD_GET_VP_BRIGHTNESS:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
- cmd.reg_count = 1;
- if (device == DEVICE_STV_672)
- cmd.start = CPIA2_VP4_EXPOSURE_TARGET;
- else
- cmd.start = CPIA2_VP5_EXPOSURE_TARGET;
- break;
- case CPIA2_CMD_SET_CONTRAST:
- cmd.buffer.block_data[0] = param;
- fallthrough;
- case CPIA2_CMD_GET_CONTRAST:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
- cmd.reg_count = 1;
- cmd.start = CPIA2_VP_YRANGE;
- break;
- case CPIA2_CMD_SET_VP_SATURATION:
- cmd.buffer.block_data[0] = param;
- fallthrough;
- case CPIA2_CMD_GET_VP_SATURATION:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
- cmd.reg_count = 1;
- if (device == DEVICE_STV_672)
- cmd.start = CPIA2_VP_SATURATION;
- else
- cmd.start = CPIA2_VP5_MCUVSATURATION;
- break;
- case CPIA2_CMD_SET_VP_GPIO_DATA:
- cmd.buffer.block_data[0] = param;
- fallthrough;
- case CPIA2_CMD_GET_VP_GPIO_DATA:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
- cmd.reg_count = 1;
- cmd.start = CPIA2_VP_GPIO_DATA;
- break;
- case CPIA2_CMD_SET_VP_GPIO_DIRECTION:
- cmd.buffer.block_data[0] = param;
- fallthrough;
- case CPIA2_CMD_GET_VP_GPIO_DIRECTION:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
- cmd.reg_count = 1;
- cmd.start = CPIA2_VP_GPIO_DIRECTION;
- break;
- case CPIA2_CMD_SET_VC_MP_GPIO_DATA:
- cmd.buffer.block_data[0] = param;
- fallthrough;
- case CPIA2_CMD_GET_VC_MP_GPIO_DATA:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
- cmd.reg_count = 1;
- cmd.start = CPIA2_VC_MP_DATA;
- break;
- case CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION:
- cmd.buffer.block_data[0] = param;
- fallthrough;
- case CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
- cmd.reg_count = 1;
- cmd.start = CPIA2_VC_MP_DIR;
- break;
- case CPIA2_CMD_ENABLE_PACKET_CTRL:
- cmd.req_mode =
- CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
- cmd.start = CPIA2_SYSTEM_INT_PACKET_CTRL;
- cmd.reg_count = 1;
- cmd.buffer.block_data[0] = param;
- break;
- case CPIA2_CMD_SET_FLICKER_MODES:
- cmd.buffer.block_data[0] = param;
- fallthrough;
- case CPIA2_CMD_GET_FLICKER_MODES:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
- cmd.reg_count = 1;
- cmd.start = CPIA2_VP_FLICKER_MODES;
- break;
- case CPIA2_CMD_RESET_FIFO: /* clear fifo and enable stream block */
- cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
- cmd.reg_count = 2;
- cmd.start = 0;
- cmd.buffer.registers[0].index = CPIA2_VC_ST_CTRL;
- cmd.buffer.registers[0].value = CPIA2_VC_ST_CTRL_SRC_VC |
- CPIA2_VC_ST_CTRL_DST_USB | CPIA2_VC_ST_CTRL_EOF_DETECT;
- cmd.buffer.registers[1].index = CPIA2_VC_ST_CTRL;
- cmd.buffer.registers[1].value = CPIA2_VC_ST_CTRL_SRC_VC |
- CPIA2_VC_ST_CTRL_DST_USB |
- CPIA2_VC_ST_CTRL_EOF_DETECT |
- CPIA2_VC_ST_CTRL_FIFO_ENABLE;
- break;
- case CPIA2_CMD_SET_HI_POWER:
- cmd.req_mode =
- CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_SYSTEM;
- cmd.reg_count = 2;
- cmd.buffer.registers[0].index =
- CPIA2_SYSTEM_SYSTEM_CONTROL;
- cmd.buffer.registers[1].index =
- CPIA2_SYSTEM_SYSTEM_CONTROL;
- cmd.buffer.registers[0].value = CPIA2_SYSTEM_CONTROL_CLEAR_ERR;
- cmd.buffer.registers[1].value =
- CPIA2_SYSTEM_CONTROL_HIGH_POWER;
- break;
- case CPIA2_CMD_SET_LOW_POWER:
- cmd.req_mode =
- CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
- cmd.reg_count = 1;
- cmd.start = CPIA2_SYSTEM_SYSTEM_CONTROL;
- cmd.buffer.block_data[0] = 0;
- break;
- case CPIA2_CMD_CLEAR_V2W_ERR:
- cmd.req_mode =
- CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
- cmd.reg_count = 1;
- cmd.start = CPIA2_SYSTEM_SYSTEM_CONTROL;
- cmd.buffer.block_data[0] = CPIA2_SYSTEM_CONTROL_CLEAR_ERR;
- break;
- case CPIA2_CMD_SET_USER_MODE:
- cmd.buffer.block_data[0] = param;
- fallthrough;
- case CPIA2_CMD_GET_USER_MODE:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
- cmd.reg_count = 1;
- if (device == DEVICE_STV_672)
- cmd.start = CPIA2_VP4_USER_MODE;
- else
- cmd.start = CPIA2_VP5_USER_MODE;
- break;
- case CPIA2_CMD_FRAMERATE_REQ:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
- cmd.reg_count = 1;
- if (device == DEVICE_STV_672)
- cmd.start = CPIA2_VP4_FRAMERATE_REQUEST;
- else
- cmd.start = CPIA2_VP5_FRAMERATE_REQUEST;
- cmd.buffer.block_data[0] = param;
- break;
- case CPIA2_CMD_SET_WAKEUP:
- cmd.buffer.block_data[0] = param;
- fallthrough;
- case CPIA2_CMD_GET_WAKEUP:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
- cmd.reg_count = 1;
- cmd.start = CPIA2_VC_WAKEUP;
- break;
- case CPIA2_CMD_SET_PW_CONTROL:
- cmd.buffer.block_data[0] = param;
- fallthrough;
- case CPIA2_CMD_GET_PW_CONTROL:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
- cmd.reg_count = 1;
- cmd.start = CPIA2_VC_PW_CTRL;
- break;
- case CPIA2_CMD_GET_VP_SYSTEM_STATE:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
- cmd.reg_count = 1;
- cmd.start = CPIA2_VP_SYSTEMSTATE;
- break;
- case CPIA2_CMD_SET_SYSTEM_CTRL:
- cmd.buffer.block_data[0] = param;
- fallthrough;
- case CPIA2_CMD_GET_SYSTEM_CTRL:
- cmd.req_mode =
- CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
- cmd.reg_count = 1;
- cmd.start = CPIA2_SYSTEM_SYSTEM_CONTROL;
- break;
- case CPIA2_CMD_SET_VP_SYSTEM_CTRL:
- cmd.buffer.block_data[0] = param;
- fallthrough;
- case CPIA2_CMD_GET_VP_SYSTEM_CTRL:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
- cmd.reg_count = 1;
- cmd.start = CPIA2_VP_SYSTEMCTRL;
- break;
- case CPIA2_CMD_SET_VP_EXP_MODES:
- cmd.buffer.block_data[0] = param;
- fallthrough;
- case CPIA2_CMD_GET_VP_EXP_MODES:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
- cmd.reg_count = 1;
- cmd.start = CPIA2_VP_EXPOSURE_MODES;
- break;
- case CPIA2_CMD_SET_DEVICE_CONFIG:
- cmd.buffer.block_data[0] = param;
- fallthrough;
- case CPIA2_CMD_GET_DEVICE_CONFIG:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
- cmd.reg_count = 1;
- cmd.start = CPIA2_VP_DEVICE_CONFIG;
- break;
- case CPIA2_CMD_SET_SERIAL_ADDR:
- cmd.buffer.block_data[0] = param;
- cmd.req_mode =
- CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
- cmd.reg_count = 1;
- cmd.start = CPIA2_SYSTEM_VP_SERIAL_ADDR;
- break;
- case CPIA2_CMD_SET_SENSOR_CR1:
- cmd.buffer.block_data[0] = param;
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
- cmd.reg_count = 1;
- cmd.start = CPIA2_SENSOR_CR1;
- break;
- case CPIA2_CMD_SET_VC_CONTROL:
- cmd.buffer.block_data[0] = param;
- fallthrough;
- case CPIA2_CMD_GET_VC_CONTROL:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
- cmd.reg_count = 1;
- cmd.start = CPIA2_VC_VC_CTRL;
- break;
- case CPIA2_CMD_SET_TARGET_KB:
- cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
- cmd.reg_count = 1;
- cmd.buffer.registers[0].index = CPIA2_VC_VC_TARGET_KB;
- cmd.buffer.registers[0].value = param;
- break;
- case CPIA2_CMD_SET_DEF_JPEG_OPT:
- cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
- cmd.reg_count = 4;
- cmd.buffer.registers[0].index = CPIA2_VC_VC_JPEG_OPT;
- cmd.buffer.registers[0].value =
- CPIA2_VC_VC_JPEG_OPT_DOUBLE_SQUEEZE;
- cmd.buffer.registers[1].index = CPIA2_VC_VC_USER_SQUEEZE;
- cmd.buffer.registers[1].value = 20;
- cmd.buffer.registers[2].index = CPIA2_VC_VC_CREEP_PERIOD;
- cmd.buffer.registers[2].value = 2;
- cmd.buffer.registers[3].index = CPIA2_VC_VC_JPEG_OPT;
- cmd.buffer.registers[3].value = CPIA2_VC_VC_JPEG_OPT_DEFAULT;
- break;
- case CPIA2_CMD_REHASH_VP4:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
- cmd.reg_count = 1;
- cmd.start = CPIA2_VP_REHASH_VALUES;
- cmd.buffer.block_data[0] = param;
- break;
- case CPIA2_CMD_SET_USER_EFFECTS: /* Note: Be careful with this as
- this register can also affect
- flicker modes */
- cmd.buffer.block_data[0] = param;
- fallthrough;
- case CPIA2_CMD_GET_USER_EFFECTS:
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
- cmd.reg_count = 1;
- if (device == DEVICE_STV_672)
- cmd.start = CPIA2_VP4_USER_EFFECTS;
- else
- cmd.start = CPIA2_VP5_USER_EFFECTS;
- break;
- default:
- LOG("DoCommand received invalid command\n");
- return -EINVAL;
- }
-
- retval = cpia2_send_command(cam, &cmd);
- if (retval) {
- return retval;
- }
-
- /***
- * Now copy any results from a read into the appropriate param struct.
- ***/
- switch (command) {
- case CPIA2_CMD_GET_VERSION:
- cam->params.version.firmware_revision_hi =
- cmd.buffer.block_data[0];
- cam->params.version.firmware_revision_lo =
- cmd.buffer.block_data[1];
- break;
- case CPIA2_CMD_GET_PNP_ID:
- cam->params.pnp_id.vendor = (cmd.buffer.block_data[0] << 8) |
- cmd.buffer.block_data[1];
- cam->params.pnp_id.product = (cmd.buffer.block_data[2] << 8) |
- cmd.buffer.block_data[3];
- cam->params.pnp_id.device_revision =
- (cmd.buffer.block_data[4] << 8) |
- cmd.buffer.block_data[5];
- if (cam->params.pnp_id.vendor == 0x553) {
- if (cam->params.pnp_id.product == 0x100) {
- cam->params.pnp_id.device_type = DEVICE_STV_672;
- } else if (cam->params.pnp_id.product == 0x140 ||
- cam->params.pnp_id.product == 0x151) {
- cam->params.pnp_id.device_type = DEVICE_STV_676;
- }
- }
- break;
- case CPIA2_CMD_GET_ASIC_TYPE:
- cam->params.version.asic_id = cmd.buffer.block_data[0];
- cam->params.version.asic_rev = cmd.buffer.block_data[1];
- break;
- case CPIA2_CMD_GET_SENSOR:
- cam->params.version.sensor_flags = cmd.buffer.block_data[0];
- cam->params.version.sensor_rev = cmd.buffer.block_data[1];
- break;
- case CPIA2_CMD_GET_VP_DEVICE:
- cam->params.version.vp_device_hi = cmd.buffer.block_data[0];
- cam->params.version.vp_device_lo = cmd.buffer.block_data[1];
- break;
- case CPIA2_CMD_GET_VP_GPIO_DATA:
- cam->params.vp_params.gpio_data = cmd.buffer.block_data[0];
- break;
- case CPIA2_CMD_GET_VP_GPIO_DIRECTION:
- cam->params.vp_params.gpio_direction = cmd.buffer.block_data[0];
- break;
- case CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION:
- cam->params.vc_params.vc_mp_direction =cmd.buffer.block_data[0];
- break;
- case CPIA2_CMD_GET_VC_MP_GPIO_DATA:
- cam->params.vc_params.vc_mp_data = cmd.buffer.block_data[0];
- break;
- case CPIA2_CMD_GET_FLICKER_MODES:
- cam->params.flicker_control.cam_register =
- cmd.buffer.block_data[0];
- break;
- case CPIA2_CMD_GET_WAKEUP:
- cam->params.vc_params.wakeup = cmd.buffer.block_data[0];
- break;
- case CPIA2_CMD_GET_PW_CONTROL:
- cam->params.vc_params.pw_control = cmd.buffer.block_data[0];
- break;
- case CPIA2_CMD_GET_SYSTEM_CTRL:
- cam->params.camera_state.system_ctrl = cmd.buffer.block_data[0];
- break;
- case CPIA2_CMD_GET_VP_SYSTEM_STATE:
- cam->params.vp_params.system_state = cmd.buffer.block_data[0];
- break;
- case CPIA2_CMD_GET_VP_SYSTEM_CTRL:
- cam->params.vp_params.system_ctrl = cmd.buffer.block_data[0];
- break;
- case CPIA2_CMD_GET_VP_EXP_MODES:
- cam->params.vp_params.exposure_modes = cmd.buffer.block_data[0];
- break;
- case CPIA2_CMD_GET_DEVICE_CONFIG:
- cam->params.vp_params.device_config = cmd.buffer.block_data[0];
- break;
- case CPIA2_CMD_GET_VC_CONTROL:
- cam->params.vc_params.vc_control = cmd.buffer.block_data[0];
- break;
- case CPIA2_CMD_GET_USER_MODE:
- cam->params.vp_params.video_mode = cmd.buffer.block_data[0];
- break;
- case CPIA2_CMD_GET_USER_EFFECTS:
- cam->params.vp_params.user_effects = cmd.buffer.block_data[0];
- break;
- default:
- break;
- }
- return retval;
-}
-
-/******************************************************************************
- *
- * cpia2_send_command
- *
- *****************************************************************************/
-
-#define DIR(cmd) ((cmd->direction == TRANSFER_WRITE) ? "Write" : "Read")
-#define BINDEX(cmd) (cmd->req_mode & 0x03)
-
-int cpia2_send_command(struct camera_data *cam, struct cpia2_command *cmd)
-{
- u8 count;
- u8 start;
- u8 *buffer;
- int retval;
-
- switch (cmd->req_mode & 0x0c) {
- case CAMERAACCESS_TYPE_RANDOM:
- count = cmd->reg_count * sizeof(struct cpia2_register);
- start = 0;
- buffer = (u8 *) & cmd->buffer;
- if (debugs_on & DEBUG_REG)
- DBG("%s Random: Register block %s\n", DIR(cmd),
- block_name[BINDEX(cmd)]);
- break;
- case CAMERAACCESS_TYPE_BLOCK:
- count = cmd->reg_count;
- start = cmd->start;
- buffer = cmd->buffer.block_data;
- if (debugs_on & DEBUG_REG)
- DBG("%s Block: Register block %s\n", DIR(cmd),
- block_name[BINDEX(cmd)]);
- break;
- case CAMERAACCESS_TYPE_MASK:
- count = cmd->reg_count * sizeof(struct cpia2_reg_mask);
- start = 0;
- buffer = (u8 *) & cmd->buffer;
- if (debugs_on & DEBUG_REG)
- DBG("%s Mask: Register block %s\n", DIR(cmd),
- block_name[BINDEX(cmd)]);
- break;
- case CAMERAACCESS_TYPE_REPEAT: /* For patch blocks only */
- count = cmd->reg_count;
- start = cmd->start;
- buffer = cmd->buffer.block_data;
- if (debugs_on & DEBUG_REG)
- DBG("%s Repeat: Register block %s\n", DIR(cmd),
- block_name[BINDEX(cmd)]);
- break;
- default:
- LOG("%s: invalid request mode\n",__func__);
- return -EINVAL;
- }
-
- retval = cpia2_usb_transfer_cmd(cam,
- buffer,
- cmd->req_mode,
- start, count, cmd->direction);
-#ifdef _CPIA2_DEBUG_
- if (debugs_on & DEBUG_REG) {
- int i;
- for (i = 0; i < cmd->reg_count; i++) {
- if((cmd->req_mode & 0x0c) == CAMERAACCESS_TYPE_BLOCK)
- KINFO("%s Block: [0x%02X] = 0x%02X\n",
- DIR(cmd), start + i, buffer[i]);
- if((cmd->req_mode & 0x0c) == CAMERAACCESS_TYPE_RANDOM)
- KINFO("%s Random: [0x%02X] = 0x%02X\n",
- DIR(cmd), cmd->buffer.registers[i].index,
- cmd->buffer.registers[i].value);
- }
- }
-#endif
-
- return retval;
-};
-
-/*************
- * Functions to implement camera functionality
- *************/
-/******************************************************************************
- *
- * cpia2_get_version_info
- *
- *****************************************************************************/
-static void cpia2_get_version_info(struct camera_data *cam)
-{
- cpia2_do_command(cam, CPIA2_CMD_GET_VERSION, TRANSFER_READ, 0);
- cpia2_do_command(cam, CPIA2_CMD_GET_PNP_ID, TRANSFER_READ, 0);
- cpia2_do_command(cam, CPIA2_CMD_GET_ASIC_TYPE, TRANSFER_READ, 0);
- cpia2_do_command(cam, CPIA2_CMD_GET_SENSOR, TRANSFER_READ, 0);
- cpia2_do_command(cam, CPIA2_CMD_GET_VP_DEVICE, TRANSFER_READ, 0);
-}
-
-/******************************************************************************
- *
- * cpia2_reset_camera
- *
- * Called at least during the open process, sets up initial params.
- *****************************************************************************/
-int cpia2_reset_camera(struct camera_data *cam)
-{
- u8 tmp_reg;
- int retval = 0;
- int target_kb;
- int i;
- struct cpia2_command cmd;
-
- /***
- * VC setup
- ***/
- retval = configure_sensor(cam,
- cam->params.roi.width,
- cam->params.roi.height);
- if (retval < 0) {
- ERR("Couldn't configure sensor, error=%d\n", retval);
- return retval;
- }
-
- /* Clear FIFO and route/enable stream block */
- cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
- cmd.direction = TRANSFER_WRITE;
- cmd.reg_count = 2;
- cmd.buffer.registers[0].index = CPIA2_VC_ST_CTRL;
- cmd.buffer.registers[0].value = CPIA2_VC_ST_CTRL_SRC_VC |
- CPIA2_VC_ST_CTRL_DST_USB | CPIA2_VC_ST_CTRL_EOF_DETECT;
- cmd.buffer.registers[1].index = CPIA2_VC_ST_CTRL;
- cmd.buffer.registers[1].value = CPIA2_VC_ST_CTRL_SRC_VC |
- CPIA2_VC_ST_CTRL_DST_USB |
- CPIA2_VC_ST_CTRL_EOF_DETECT | CPIA2_VC_ST_CTRL_FIFO_ENABLE;
-
- cpia2_send_command(cam, &cmd);
-
- cpia2_set_high_power(cam);
-
- if (cam->params.pnp_id.device_type == DEVICE_STV_672) {
- /* Enable button notification */
- cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_SYSTEM;
- cmd.buffer.registers[0].index = CPIA2_SYSTEM_INT_PACKET_CTRL;
- cmd.buffer.registers[0].value =
- CPIA2_SYSTEM_INT_PACKET_CTRL_ENABLE_SW_XX;
- cmd.reg_count = 1;
- cpia2_send_command(cam, &cmd);
- }
-
- schedule_timeout_interruptible(msecs_to_jiffies(100));
-
- if (cam->params.pnp_id.device_type == DEVICE_STV_672)
- retval = apply_vp_patch(cam);
-
- /* wait for vp to go to sleep */
- schedule_timeout_interruptible(msecs_to_jiffies(100));
-
- /***
- * If this is a 676, apply VP5 fixes before we start streaming
- ***/
- if (cam->params.pnp_id.device_type == DEVICE_STV_676) {
- cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VP;
-
- /* The following writes improve the picture */
- cmd.buffer.registers[0].index = CPIA2_VP5_MYBLACK_LEVEL;
- cmd.buffer.registers[0].value = 0; /* reduce from the default
- * rec 601 pedestal of 16 */
- cmd.buffer.registers[1].index = CPIA2_VP5_MCYRANGE;
- cmd.buffer.registers[1].value = 0x92; /* increase from 100% to
- * (256/256 - 31) to fill
- * available range */
- cmd.buffer.registers[2].index = CPIA2_VP5_MYCEILING;
- cmd.buffer.registers[2].value = 0xFF; /* Increase from the
- * default rec 601 ceiling
- * of 240 */
- cmd.buffer.registers[3].index = CPIA2_VP5_MCUVSATURATION;
- cmd.buffer.registers[3].value = 0xFF; /* Increase from the rec
- * 601 100% level (128)
- * to 145-192 */
- cmd.buffer.registers[4].index = CPIA2_VP5_ANTIFLKRSETUP;
- cmd.buffer.registers[4].value = 0x80; /* Inhibit the
- * anti-flicker */
-
- /* The following 4 writes are a fix to allow QVGA to work at 30 fps */
- cmd.buffer.registers[5].index = CPIA2_VP_RAM_ADDR_H;
- cmd.buffer.registers[5].value = 0x01;
- cmd.buffer.registers[6].index = CPIA2_VP_RAM_ADDR_L;
- cmd.buffer.registers[6].value = 0xE3;
- cmd.buffer.registers[7].index = CPIA2_VP_RAM_DATA;
- cmd.buffer.registers[7].value = 0x02;
- cmd.buffer.registers[8].index = CPIA2_VP_RAM_DATA;
- cmd.buffer.registers[8].value = 0xFC;
-
- cmd.direction = TRANSFER_WRITE;
- cmd.reg_count = 9;
-
- cpia2_send_command(cam, &cmd);
- }
-
- /* Activate all settings and start the data stream */
- /* Set user mode */
- set_default_user_mode(cam);
-
- /* Give VP time to wake up */
- schedule_timeout_interruptible(msecs_to_jiffies(100));
-
- set_all_properties(cam);
-
- cpia2_do_command(cam, CPIA2_CMD_GET_USER_MODE, TRANSFER_READ, 0);
- DBG("After SetAllProperties(cam), user mode is 0x%0X\n",
- cam->params.vp_params.video_mode);
-
- /***
- * Set audio regulator off. This and the code to set the compresison
- * state are too complex to form a CPIA2_CMD_, and seem to be somewhat
- * intertwined. This stuff came straight from the windows driver.
- ***/
- /* Turn AutoExposure off in VP and enable the serial bridge to the sensor */
- cpia2_do_command(cam, CPIA2_CMD_GET_VP_SYSTEM_CTRL, TRANSFER_READ, 0);
- tmp_reg = cam->params.vp_params.system_ctrl;
- cmd.buffer.registers[0].value = tmp_reg &
- (tmp_reg & (CPIA2_VP_SYSTEMCTRL_HK_CONTROL ^ 0xFF));
-
- cpia2_do_command(cam, CPIA2_CMD_GET_DEVICE_CONFIG, TRANSFER_READ, 0);
- cmd.buffer.registers[1].value = cam->params.vp_params.device_config |
- CPIA2_VP_DEVICE_CONFIG_SERIAL_BRIDGE;
- cmd.buffer.registers[0].index = CPIA2_VP_SYSTEMCTRL;
- cmd.buffer.registers[1].index = CPIA2_VP_DEVICE_CONFIG;
- cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VP;
- cmd.reg_count = 2;
- cmd.direction = TRANSFER_WRITE;
- cmd.start = 0;
- cpia2_send_command(cam, &cmd);
-
- /* Set the correct I2C address in the CPiA-2 system register */
- cpia2_do_command(cam,
- CPIA2_CMD_SET_SERIAL_ADDR,
- TRANSFER_WRITE,
- CPIA2_SYSTEM_VP_SERIAL_ADDR_SENSOR);
-
- /* Now have sensor access - set bit to turn the audio regulator off */
- cpia2_do_command(cam,
- CPIA2_CMD_SET_SENSOR_CR1,
- TRANSFER_WRITE, CPIA2_SENSOR_CR1_DOWN_AUDIO_REGULATOR);
-
- /* Set the correct I2C address in the CPiA-2 system register */
- if (cam->params.pnp_id.device_type == DEVICE_STV_672)
- cpia2_do_command(cam,
- CPIA2_CMD_SET_SERIAL_ADDR,
- TRANSFER_WRITE,
- CPIA2_SYSTEM_VP_SERIAL_ADDR_VP); // 0x88
- else
- cpia2_do_command(cam,
- CPIA2_CMD_SET_SERIAL_ADDR,
- TRANSFER_WRITE,
- CPIA2_SYSTEM_VP_SERIAL_ADDR_676_VP); // 0x8a
-
- /* increase signal drive strength */
- if (cam->params.pnp_id.device_type == DEVICE_STV_676)
- cpia2_do_command(cam,
- CPIA2_CMD_SET_VP_EXP_MODES,
- TRANSFER_WRITE,
- CPIA2_VP_EXPOSURE_MODES_COMPILE_EXP);
-
- /* Start autoexposure */
- cpia2_do_command(cam, CPIA2_CMD_GET_DEVICE_CONFIG, TRANSFER_READ, 0);
- cmd.buffer.registers[0].value = cam->params.vp_params.device_config &
- (CPIA2_VP_DEVICE_CONFIG_SERIAL_BRIDGE ^ 0xFF);
-
- cpia2_do_command(cam, CPIA2_CMD_GET_VP_SYSTEM_CTRL, TRANSFER_READ, 0);
- cmd.buffer.registers[1].value =
- cam->params.vp_params.system_ctrl | CPIA2_VP_SYSTEMCTRL_HK_CONTROL;
-
- cmd.buffer.registers[0].index = CPIA2_VP_DEVICE_CONFIG;
- cmd.buffer.registers[1].index = CPIA2_VP_SYSTEMCTRL;
- cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VP;
- cmd.reg_count = 2;
- cmd.direction = TRANSFER_WRITE;
-
- cpia2_send_command(cam, &cmd);
-
- /* Set compression state */
- cpia2_do_command(cam, CPIA2_CMD_GET_VC_CONTROL, TRANSFER_READ, 0);
- if (cam->params.compression.inhibit_htables) {
- tmp_reg = cam->params.vc_params.vc_control |
- CPIA2_VC_VC_CTRL_INHIBIT_H_TABLES;
- } else {
- tmp_reg = cam->params.vc_params.vc_control &
- ~CPIA2_VC_VC_CTRL_INHIBIT_H_TABLES;
- }
- cpia2_do_command(cam, CPIA2_CMD_SET_VC_CONTROL, TRANSFER_WRITE,tmp_reg);
-
- /* Set target size (kb) on vc
- This is a heuristic based on the quality parameter and the raw
- framesize in kB divided by 16 (the compression factor when the
- quality is 100%) */
- target_kb = (cam->width * cam->height * 2 / 16384) *
- cam->params.vc_params.quality / 100;
- if (target_kb < 1)
- target_kb = 1;
- cpia2_do_command(cam, CPIA2_CMD_SET_TARGET_KB,
- TRANSFER_WRITE, target_kb);
-
- /* Wiggle VC Reset */
- /***
- * First read and wait a bit.
- ***/
- for (i = 0; i < 50; i++) {
- cpia2_do_command(cam, CPIA2_CMD_GET_PW_CONTROL,
- TRANSFER_READ, 0);
- }
-
- tmp_reg = cam->params.vc_params.pw_control;
- tmp_reg &= ~CPIA2_VC_PW_CTRL_VC_RESET_N;
-
- cpia2_do_command(cam, CPIA2_CMD_SET_PW_CONTROL, TRANSFER_WRITE,tmp_reg);
-
- tmp_reg |= CPIA2_VC_PW_CTRL_VC_RESET_N;
- cpia2_do_command(cam, CPIA2_CMD_SET_PW_CONTROL, TRANSFER_WRITE,tmp_reg);
-
- cpia2_do_command(cam, CPIA2_CMD_SET_DEF_JPEG_OPT, TRANSFER_WRITE, 0);
-
- cpia2_do_command(cam, CPIA2_CMD_GET_USER_MODE, TRANSFER_READ, 0);
- DBG("After VC RESET, user mode is 0x%0X\n",
- cam->params.vp_params.video_mode);
-
- return retval;
-}
-
-/******************************************************************************
- *
- * cpia2_set_high_power
- *
- *****************************************************************************/
-static int cpia2_set_high_power(struct camera_data *cam)
-{
- int i;
- for (i = 0; i <= 50; i++) {
- /* Read system status */
- cpia2_do_command(cam,CPIA2_CMD_GET_SYSTEM_CTRL,TRANSFER_READ,0);
-
- /* If there is an error, clear it */
- if(cam->params.camera_state.system_ctrl &
- CPIA2_SYSTEM_CONTROL_V2W_ERR)
- cpia2_do_command(cam, CPIA2_CMD_CLEAR_V2W_ERR,
- TRANSFER_WRITE, 0);
-
- /* Try to set high power mode */
- cpia2_do_command(cam, CPIA2_CMD_SET_SYSTEM_CTRL,
- TRANSFER_WRITE, 1);
-
- /* Try to read something in VP to check if everything is awake */
- cpia2_do_command(cam, CPIA2_CMD_GET_VP_SYSTEM_STATE,
- TRANSFER_READ, 0);
- if (cam->params.vp_params.system_state &
- CPIA2_VP_SYSTEMSTATE_HK_ALIVE) {
- break;
- } else if (i == 50) {
- cam->params.camera_state.power_mode = LO_POWER_MODE;
- ERR("Camera did not wake up\n");
- return -EIO;
- }
- }
-
- DBG("System now in high power state\n");
- cam->params.camera_state.power_mode = HI_POWER_MODE;
- return 0;
-}
-
-/******************************************************************************
- *
- * cpia2_set_low_power
- *
- *****************************************************************************/
-int cpia2_set_low_power(struct camera_data *cam)
-{
- cam->params.camera_state.power_mode = LO_POWER_MODE;
- cpia2_do_command(cam, CPIA2_CMD_SET_SYSTEM_CTRL, TRANSFER_WRITE, 0);
- return 0;
-}
-
-/******************************************************************************
- *
- * apply_vp_patch
- *
- *****************************************************************************/
-static int cpia2_send_onebyte_command(struct camera_data *cam,
- struct cpia2_command *cmd,
- u8 start, u8 datum)
-{
- cmd->buffer.block_data[0] = datum;
- cmd->start = start;
- cmd->reg_count = 1;
- return cpia2_send_command(cam, cmd);
-}
-
-static int apply_vp_patch(struct camera_data *cam)
-{
- const struct firmware *fw;
- const char fw_name[] = FIRMWARE;
- int i, ret;
- struct cpia2_command cmd;
-
- ret = request_firmware(&fw, fw_name, &cam->dev->dev);
- if (ret) {
- printk(KERN_ERR "cpia2: failed to load VP patch \"%s\"\n",
- fw_name);
- return ret;
- }
-
- cmd.req_mode = CAMERAACCESS_TYPE_REPEAT | CAMERAACCESS_VP;
- cmd.direction = TRANSFER_WRITE;
-
- /* First send the start address... */
- cpia2_send_onebyte_command(cam, &cmd, 0x0A, fw->data[0]); /* hi */
- cpia2_send_onebyte_command(cam, &cmd, 0x0B, fw->data[1]); /* lo */
-
- /* ... followed by the data payload */
- for (i = 2; i < fw->size; i += 64) {
- cmd.start = 0x0C; /* Data */
- cmd.reg_count = min_t(uint, 64, fw->size - i);
- memcpy(cmd.buffer.block_data, &fw->data[i], cmd.reg_count);
- cpia2_send_command(cam, &cmd);
- }
-
- /* Next send the start address... */
- cpia2_send_onebyte_command(cam, &cmd, 0x0A, fw->data[0]); /* hi */
- cpia2_send_onebyte_command(cam, &cmd, 0x0B, fw->data[1]); /* lo */
-
- /* ... followed by the 'goto' command */
- cpia2_send_onebyte_command(cam, &cmd, 0x0D, 1);
-
- release_firmware(fw);
- return 0;
-}
-
-/******************************************************************************
- *
- * set_default_user_mode
- *
- *****************************************************************************/
-static int set_default_user_mode(struct camera_data *cam)
-{
- unsigned char user_mode;
- unsigned char frame_rate;
- int width = cam->params.roi.width;
- int height = cam->params.roi.height;
-
- switch (cam->params.version.sensor_flags) {
- case CPIA2_VP_SENSOR_FLAGS_404:
- case CPIA2_VP_SENSOR_FLAGS_407:
- case CPIA2_VP_SENSOR_FLAGS_409:
- case CPIA2_VP_SENSOR_FLAGS_410:
- if ((width > STV_IMAGE_QCIF_COLS)
- || (height > STV_IMAGE_QCIF_ROWS)) {
- user_mode = CPIA2_VP_USER_MODE_CIF;
- } else {
- user_mode = CPIA2_VP_USER_MODE_QCIFDS;
- }
- frame_rate = CPIA2_VP_FRAMERATE_30;
- break;
- case CPIA2_VP_SENSOR_FLAGS_500:
- if ((width > STV_IMAGE_CIF_COLS)
- || (height > STV_IMAGE_CIF_ROWS)) {
- user_mode = CPIA2_VP_USER_MODE_VGA;
- } else {
- user_mode = CPIA2_VP_USER_MODE_QVGADS;
- }
- if (cam->params.pnp_id.device_type == DEVICE_STV_672)
- frame_rate = CPIA2_VP_FRAMERATE_15;
- else
- frame_rate = CPIA2_VP_FRAMERATE_30;
- break;
- default:
- LOG("%s: Invalid sensor flag value 0x%0X\n",__func__,
- cam->params.version.sensor_flags);
- return -EINVAL;
- }
-
- DBG("Sensor flag = 0x%0x, user mode = 0x%0x, frame rate = 0x%X\n",
- cam->params.version.sensor_flags, user_mode, frame_rate);
- cpia2_do_command(cam, CPIA2_CMD_SET_USER_MODE, TRANSFER_WRITE,
- user_mode);
- if(cam->params.vp_params.frame_rate > 0 &&
- frame_rate > cam->params.vp_params.frame_rate)
- frame_rate = cam->params.vp_params.frame_rate;
-
- cpia2_set_fps(cam, frame_rate);
-
-// if (cam->params.pnp_id.device_type == DEVICE_STV_676)
-// cpia2_do_command(cam,
-// CPIA2_CMD_SET_VP_SYSTEM_CTRL,
-// TRANSFER_WRITE,
-// CPIA2_VP_SYSTEMCTRL_HK_CONTROL |
-// CPIA2_VP_SYSTEMCTRL_POWER_CONTROL);
-
- return 0;
-}
-
-/******************************************************************************
- *
- * cpia2_match_video_size
- *
- * return the best match, where 'best' is as always
- * the largest that is not bigger than what is requested.
- *****************************************************************************/
-int cpia2_match_video_size(int width, int height)
-{
- if (width >= STV_IMAGE_VGA_COLS && height >= STV_IMAGE_VGA_ROWS)
- return VIDEOSIZE_VGA;
-
- if (width >= STV_IMAGE_CIF_COLS && height >= STV_IMAGE_CIF_ROWS)
- return VIDEOSIZE_CIF;
-
- if (width >= STV_IMAGE_QVGA_COLS && height >= STV_IMAGE_QVGA_ROWS)
- return VIDEOSIZE_QVGA;
-
- if (width >= 288 && height >= 216)
- return VIDEOSIZE_288_216;
-
- if (width >= 256 && height >= 192)
- return VIDEOSIZE_256_192;
-
- if (width >= 224 && height >= 168)
- return VIDEOSIZE_224_168;
-
- if (width >= 192 && height >= 144)
- return VIDEOSIZE_192_144;
-
- if (width >= STV_IMAGE_QCIF_COLS && height >= STV_IMAGE_QCIF_ROWS)
- return VIDEOSIZE_QCIF;
-
- return -1;
-}
-
-/******************************************************************************
- *
- * SetVideoSize
- *
- *****************************************************************************/
-static int set_vw_size(struct camera_data *cam, int size)
-{
- int retval = 0;
-
- cam->params.vp_params.video_size = size;
-
- switch (size) {
- case VIDEOSIZE_VGA:
- DBG("Setting size to VGA\n");
- cam->params.roi.width = STV_IMAGE_VGA_COLS;
- cam->params.roi.height = STV_IMAGE_VGA_ROWS;
- cam->width = STV_IMAGE_VGA_COLS;
- cam->height = STV_IMAGE_VGA_ROWS;
- break;
- case VIDEOSIZE_CIF:
- DBG("Setting size to CIF\n");
- cam->params.roi.width = STV_IMAGE_CIF_COLS;
- cam->params.roi.height = STV_IMAGE_CIF_ROWS;
- cam->width = STV_IMAGE_CIF_COLS;
- cam->height = STV_IMAGE_CIF_ROWS;
- break;
- case VIDEOSIZE_QVGA:
- DBG("Setting size to QVGA\n");
- cam->params.roi.width = STV_IMAGE_QVGA_COLS;
- cam->params.roi.height = STV_IMAGE_QVGA_ROWS;
- cam->width = STV_IMAGE_QVGA_COLS;
- cam->height = STV_IMAGE_QVGA_ROWS;
- break;
- case VIDEOSIZE_288_216:
- cam->params.roi.width = 288;
- cam->params.roi.height = 216;
- cam->width = 288;
- cam->height = 216;
- break;
- case VIDEOSIZE_256_192:
- cam->width = 256;
- cam->height = 192;
- cam->params.roi.width = 256;
- cam->params.roi.height = 192;
- break;
- case VIDEOSIZE_224_168:
- cam->width = 224;
- cam->height = 168;
- cam->params.roi.width = 224;
- cam->params.roi.height = 168;
- break;
- case VIDEOSIZE_192_144:
- cam->width = 192;
- cam->height = 144;
- cam->params.roi.width = 192;
- cam->params.roi.height = 144;
- break;
- case VIDEOSIZE_QCIF:
- DBG("Setting size to QCIF\n");
- cam->params.roi.width = STV_IMAGE_QCIF_COLS;
- cam->params.roi.height = STV_IMAGE_QCIF_ROWS;
- cam->width = STV_IMAGE_QCIF_COLS;
- cam->height = STV_IMAGE_QCIF_ROWS;
- break;
- default:
- retval = -EINVAL;
- }
- return retval;
-}
-
-/******************************************************************************
- *
- * configure_sensor
- *
- *****************************************************************************/
-static int configure_sensor(struct camera_data *cam,
- int req_width, int req_height)
-{
- int retval;
-
- switch (cam->params.version.sensor_flags) {
- case CPIA2_VP_SENSOR_FLAGS_404:
- case CPIA2_VP_SENSOR_FLAGS_407:
- case CPIA2_VP_SENSOR_FLAGS_409:
- case CPIA2_VP_SENSOR_FLAGS_410:
- retval = config_sensor_410(cam, req_width, req_height);
- break;
- case CPIA2_VP_SENSOR_FLAGS_500:
- retval = config_sensor_500(cam, req_width, req_height);
- break;
- default:
- return -EINVAL;
- }
-
- return retval;
-}
-
-/******************************************************************************
- *
- * config_sensor_410
- *
- *****************************************************************************/
-static int config_sensor_410(struct camera_data *cam,
- int req_width, int req_height)
-{
- struct cpia2_command cmd;
- int i = 0;
- int image_size;
- int image_type;
- int width = req_width;
- int height = req_height;
-
- /***
- * Make sure size doesn't exceed CIF.
- ***/
- if (width > STV_IMAGE_CIF_COLS)
- width = STV_IMAGE_CIF_COLS;
- if (height > STV_IMAGE_CIF_ROWS)
- height = STV_IMAGE_CIF_ROWS;
-
- image_size = cpia2_match_video_size(width, height);
-
- DBG("Config 410: width = %d, height = %d\n", width, height);
- DBG("Image size returned is %d\n", image_size);
- if (image_size >= 0) {
- set_vw_size(cam, image_size);
- width = cam->params.roi.width;
- height = cam->params.roi.height;
-
- DBG("After set_vw_size(), width = %d, height = %d\n",
- width, height);
- if (width <= 176 && height <= 144) {
- DBG("image type = VIDEOSIZE_QCIF\n");
- image_type = VIDEOSIZE_QCIF;
- }
- else if (width <= 320 && height <= 240) {
- DBG("image type = VIDEOSIZE_QVGA\n");
- image_type = VIDEOSIZE_QVGA;
- }
- else {
- DBG("image type = VIDEOSIZE_CIF\n");
- image_type = VIDEOSIZE_CIF;
- }
- } else {
- ERR("ConfigSensor410 failed\n");
- return -EINVAL;
- }
-
- cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
- cmd.direction = TRANSFER_WRITE;
-
- /* VC Format */
- cmd.buffer.registers[i].index = CPIA2_VC_VC_FORMAT;
- if (image_type == VIDEOSIZE_CIF) {
- cmd.buffer.registers[i++].value =
- (u8) (CPIA2_VC_VC_FORMAT_UFIRST |
- CPIA2_VC_VC_FORMAT_SHORTLINE);
- } else {
- cmd.buffer.registers[i++].value =
- (u8) CPIA2_VC_VC_FORMAT_UFIRST;
- }
-
- /* VC Clocks */
- cmd.buffer.registers[i].index = CPIA2_VC_VC_CLOCKS;
- if (image_type == VIDEOSIZE_QCIF) {
- if (cam->params.pnp_id.device_type == DEVICE_STV_672) {
- cmd.buffer.registers[i++].value=
- (u8)(CPIA2_VC_VC_672_CLOCKS_CIF_DIV_BY_3 |
- CPIA2_VC_VC_672_CLOCKS_SCALING |
- CPIA2_VC_VC_CLOCKS_LOGDIV2);
- DBG("VC_Clocks (0xc4) should be B\n");
- }
- else {
- cmd.buffer.registers[i++].value=
- (u8)(CPIA2_VC_VC_676_CLOCKS_CIF_DIV_BY_3 |
- CPIA2_VC_VC_CLOCKS_LOGDIV2);
- }
- } else {
- if (cam->params.pnp_id.device_type == DEVICE_STV_672) {
- cmd.buffer.registers[i++].value =
- (u8) (CPIA2_VC_VC_672_CLOCKS_CIF_DIV_BY_3 |
- CPIA2_VC_VC_CLOCKS_LOGDIV0);
- }
- else {
- cmd.buffer.registers[i++].value =
- (u8) (CPIA2_VC_VC_676_CLOCKS_CIF_DIV_BY_3 |
- CPIA2_VC_VC_676_CLOCKS_SCALING |
- CPIA2_VC_VC_CLOCKS_LOGDIV0);
- }
- }
- DBG("VC_Clocks (0xc4) = 0x%0X\n", cmd.buffer.registers[i-1].value);
-
- /* Input reqWidth from VC */
- cmd.buffer.registers[i].index = CPIA2_VC_VC_IHSIZE_LO;
- if (image_type == VIDEOSIZE_QCIF)
- cmd.buffer.registers[i++].value =
- (u8) (STV_IMAGE_QCIF_COLS / 4);
- else
- cmd.buffer.registers[i++].value =
- (u8) (STV_IMAGE_CIF_COLS / 4);
-
- /* Timings */
- cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_HI;
- if (image_type == VIDEOSIZE_QCIF)
- cmd.buffer.registers[i++].value = (u8) 0;
- else
- cmd.buffer.registers[i++].value = (u8) 1;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_LO;
- if (image_type == VIDEOSIZE_QCIF)
- cmd.buffer.registers[i++].value = (u8) 208;
- else
- cmd.buffer.registers[i++].value = (u8) 160;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_HI;
- if (image_type == VIDEOSIZE_QCIF)
- cmd.buffer.registers[i++].value = (u8) 0;
- else
- cmd.buffer.registers[i++].value = (u8) 1;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_LO;
- if (image_type == VIDEOSIZE_QCIF)
- cmd.buffer.registers[i++].value = (u8) 160;
- else
- cmd.buffer.registers[i++].value = (u8) 64;
-
- /* Output Image Size */
- cmd.buffer.registers[i].index = CPIA2_VC_VC_OHSIZE;
- cmd.buffer.registers[i++].value = cam->params.roi.width / 4;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_OVSIZE;
- cmd.buffer.registers[i++].value = cam->params.roi.height / 4;
-
- /* Cropping */
- cmd.buffer.registers[i].index = CPIA2_VC_VC_HCROP;
- if (image_type == VIDEOSIZE_QCIF)
- cmd.buffer.registers[i++].value =
- (u8) (((STV_IMAGE_QCIF_COLS / 4) - (width / 4)) / 2);
- else
- cmd.buffer.registers[i++].value =
- (u8) (((STV_IMAGE_CIF_COLS / 4) - (width / 4)) / 2);
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_VCROP;
- if (image_type == VIDEOSIZE_QCIF)
- cmd.buffer.registers[i++].value =
- (u8) (((STV_IMAGE_QCIF_ROWS / 4) - (height / 4)) / 2);
- else
- cmd.buffer.registers[i++].value =
- (u8) (((STV_IMAGE_CIF_ROWS / 4) - (height / 4)) / 2);
-
- /* Scaling registers (defaults) */
- cmd.buffer.registers[i].index = CPIA2_VC_VC_HPHASE;
- cmd.buffer.registers[i++].value = (u8) 0;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_VPHASE;
- cmd.buffer.registers[i++].value = (u8) 0;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_HISPAN;
- cmd.buffer.registers[i++].value = (u8) 31;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_VISPAN;
- cmd.buffer.registers[i++].value = (u8) 31;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_HICROP;
- cmd.buffer.registers[i++].value = (u8) 0;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_VICROP;
- cmd.buffer.registers[i++].value = (u8) 0;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_HFRACT;
- cmd.buffer.registers[i++].value = (u8) 0x81; /* = 8/1 = 8 (HIBYTE/LOBYTE) */
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_VFRACT;
- cmd.buffer.registers[i++].value = (u8) 0x81; /* = 8/1 = 8 (HIBYTE/LOBYTE) */
-
- cmd.reg_count = i;
-
- cpia2_send_command(cam, &cmd);
-
- return i;
-}
-
-
-/******************************************************************************
- *
- * config_sensor_500(cam)
- *
- *****************************************************************************/
-static int config_sensor_500(struct camera_data *cam,
- int req_width, int req_height)
-{
- struct cpia2_command cmd;
- int i = 0;
- int image_size = VIDEOSIZE_CIF;
- int image_type = VIDEOSIZE_VGA;
- int width = req_width;
- int height = req_height;
- unsigned int device = cam->params.pnp_id.device_type;
-
- image_size = cpia2_match_video_size(width, height);
-
- if (width > STV_IMAGE_CIF_COLS || height > STV_IMAGE_CIF_ROWS)
- image_type = VIDEOSIZE_VGA;
- else if (width > STV_IMAGE_QVGA_COLS || height > STV_IMAGE_QVGA_ROWS)
- image_type = VIDEOSIZE_CIF;
- else if (width > STV_IMAGE_QCIF_COLS || height > STV_IMAGE_QCIF_ROWS)
- image_type = VIDEOSIZE_QVGA;
- else
- image_type = VIDEOSIZE_QCIF;
-
- if (image_size >= 0) {
- set_vw_size(cam, image_size);
- width = cam->params.roi.width;
- height = cam->params.roi.height;
- } else {
- ERR("ConfigSensor500 failed\n");
- return -EINVAL;
- }
-
- DBG("image_size = %d, width = %d, height = %d, type = %d\n",
- image_size, width, height, image_type);
-
- cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC;
- cmd.direction = TRANSFER_WRITE;
- i = 0;
-
- /* VC Format */
- cmd.buffer.registers[i].index = CPIA2_VC_VC_FORMAT;
- cmd.buffer.registers[i].value = (u8) CPIA2_VC_VC_FORMAT_UFIRST;
- if (image_type == VIDEOSIZE_QCIF)
- cmd.buffer.registers[i].value |= (u8) CPIA2_VC_VC_FORMAT_DECIMATING;
- i++;
-
- /* VC Clocks */
- cmd.buffer.registers[i].index = CPIA2_VC_VC_CLOCKS;
- if (device == DEVICE_STV_672) {
- if (image_type == VIDEOSIZE_VGA)
- cmd.buffer.registers[i].value =
- (u8)CPIA2_VC_VC_CLOCKS_LOGDIV1;
- else
- cmd.buffer.registers[i].value =
- (u8)(CPIA2_VC_VC_672_CLOCKS_SCALING |
- CPIA2_VC_VC_CLOCKS_LOGDIV3);
- } else {
- if (image_type == VIDEOSIZE_VGA)
- cmd.buffer.registers[i].value =
- (u8)CPIA2_VC_VC_CLOCKS_LOGDIV0;
- else
- cmd.buffer.registers[i].value =
- (u8)(CPIA2_VC_VC_676_CLOCKS_SCALING |
- CPIA2_VC_VC_CLOCKS_LOGDIV2);
- }
- i++;
-
- DBG("VC_CLOCKS = 0x%X\n", cmd.buffer.registers[i-1].value);
-
- /* Input width from VP */
- cmd.buffer.registers[i].index = CPIA2_VC_VC_IHSIZE_LO;
- if (image_type == VIDEOSIZE_VGA)
- cmd.buffer.registers[i].value =
- (u8) (STV_IMAGE_VGA_COLS / 4);
- else
- cmd.buffer.registers[i].value =
- (u8) (STV_IMAGE_QVGA_COLS / 4);
- i++;
- DBG("Input width = %d\n", cmd.buffer.registers[i-1].value);
-
- /* Timings */
- cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_HI;
- if (image_type == VIDEOSIZE_VGA)
- cmd.buffer.registers[i++].value = (u8) 2;
- else
- cmd.buffer.registers[i++].value = (u8) 1;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_LO;
- if (image_type == VIDEOSIZE_VGA)
- cmd.buffer.registers[i++].value = (u8) 250;
- else if (image_type == VIDEOSIZE_QVGA)
- cmd.buffer.registers[i++].value = (u8) 125;
- else
- cmd.buffer.registers[i++].value = (u8) 160;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_HI;
- if (image_type == VIDEOSIZE_VGA)
- cmd.buffer.registers[i++].value = (u8) 2;
- else
- cmd.buffer.registers[i++].value = (u8) 1;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_LO;
- if (image_type == VIDEOSIZE_VGA)
- cmd.buffer.registers[i++].value = (u8) 12;
- else if (image_type == VIDEOSIZE_QVGA)
- cmd.buffer.registers[i++].value = (u8) 64;
- else
- cmd.buffer.registers[i++].value = (u8) 6;
-
- /* Output Image Size */
- cmd.buffer.registers[i].index = CPIA2_VC_VC_OHSIZE;
- if (image_type == VIDEOSIZE_QCIF)
- cmd.buffer.registers[i++].value = STV_IMAGE_CIF_COLS / 4;
- else
- cmd.buffer.registers[i++].value = width / 4;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_OVSIZE;
- if (image_type == VIDEOSIZE_QCIF)
- cmd.buffer.registers[i++].value = STV_IMAGE_CIF_ROWS / 4;
- else
- cmd.buffer.registers[i++].value = height / 4;
-
- /* Cropping */
- cmd.buffer.registers[i].index = CPIA2_VC_VC_HCROP;
- if (image_type == VIDEOSIZE_VGA)
- cmd.buffer.registers[i++].value =
- (u8) (((STV_IMAGE_VGA_COLS / 4) - (width / 4)) / 2);
- else if (image_type == VIDEOSIZE_QVGA)
- cmd.buffer.registers[i++].value =
- (u8) (((STV_IMAGE_QVGA_COLS / 4) - (width / 4)) / 2);
- else if (image_type == VIDEOSIZE_CIF)
- cmd.buffer.registers[i++].value =
- (u8) (((STV_IMAGE_CIF_COLS / 4) - (width / 4)) / 2);
- else /*if (image_type == VIDEOSIZE_QCIF)*/
- cmd.buffer.registers[i++].value =
- (u8) (((STV_IMAGE_QCIF_COLS / 4) - (width / 4)) / 2);
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_VCROP;
- if (image_type == VIDEOSIZE_VGA)
- cmd.buffer.registers[i++].value =
- (u8) (((STV_IMAGE_VGA_ROWS / 4) - (height / 4)) / 2);
- else if (image_type == VIDEOSIZE_QVGA)
- cmd.buffer.registers[i++].value =
- (u8) (((STV_IMAGE_QVGA_ROWS / 4) - (height / 4)) / 2);
- else if (image_type == VIDEOSIZE_CIF)
- cmd.buffer.registers[i++].value =
- (u8) (((STV_IMAGE_CIF_ROWS / 4) - (height / 4)) / 2);
- else /*if (image_type == VIDEOSIZE_QCIF)*/
- cmd.buffer.registers[i++].value =
- (u8) (((STV_IMAGE_QCIF_ROWS / 4) - (height / 4)) / 2);
-
- /* Scaling registers (defaults) */
- cmd.buffer.registers[i].index = CPIA2_VC_VC_HPHASE;
- if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
- cmd.buffer.registers[i++].value = (u8) 36;
- else
- cmd.buffer.registers[i++].value = (u8) 0;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_VPHASE;
- if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
- cmd.buffer.registers[i++].value = (u8) 32;
- else
- cmd.buffer.registers[i++].value = (u8) 0;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_HISPAN;
- if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
- cmd.buffer.registers[i++].value = (u8) 26;
- else
- cmd.buffer.registers[i++].value = (u8) 31;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_VISPAN;
- if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
- cmd.buffer.registers[i++].value = (u8) 21;
- else
- cmd.buffer.registers[i++].value = (u8) 31;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_HICROP;
- cmd.buffer.registers[i++].value = (u8) 0;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_VICROP;
- cmd.buffer.registers[i++].value = (u8) 0;
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_HFRACT;
- if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
- cmd.buffer.registers[i++].value = (u8) 0x2B; /* 2/11 */
- else
- cmd.buffer.registers[i++].value = (u8) 0x81; /* 8/1 */
-
- cmd.buffer.registers[i].index = CPIA2_VC_VC_VFRACT;
- if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF)
- cmd.buffer.registers[i++].value = (u8) 0x13; /* 1/3 */
- else
- cmd.buffer.registers[i++].value = (u8) 0x81; /* 8/1 */
-
- cmd.reg_count = i;
-
- cpia2_send_command(cam, &cmd);
-
- return i;
-}
-
-
-/******************************************************************************
- *
- * setallproperties
- *
- * This sets all user changeable properties to the values in cam->params.
- *****************************************************************************/
-static int set_all_properties(struct camera_data *cam)
-{
- /**
- * Don't set target_kb here, it will be set later.
- * framerate and user_mode were already set (set_default_user_mode).
- **/
-
- cpia2_usb_change_streaming_alternate(cam,
- cam->params.camera_state.stream_mode);
-
- cpia2_do_command(cam,
- CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION,
- TRANSFER_WRITE, cam->params.vp_params.gpio_direction);
- cpia2_do_command(cam, CPIA2_CMD_SET_VC_MP_GPIO_DATA, TRANSFER_WRITE,
- cam->params.vp_params.gpio_data);
-
- v4l2_ctrl_handler_setup(&cam->hdl);
-
- wake_system(cam);
-
- set_lowlight_boost(cam);
-
- return 0;
-}
-
-/******************************************************************************
- *
- * cpia2_save_camera_state
- *
- *****************************************************************************/
-void cpia2_save_camera_state(struct camera_data *cam)
-{
- cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, TRANSFER_READ, 0);
- cpia2_do_command(cam, CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION, TRANSFER_READ,
- 0);
- cpia2_do_command(cam, CPIA2_CMD_GET_VC_MP_GPIO_DATA, TRANSFER_READ, 0);
- /* Don't get framerate or target_kb. Trust the values we already have */
-}
-
-
-/******************************************************************************
- *
- * cpia2_set_flicker_mode
- *
- *****************************************************************************/
-int cpia2_set_flicker_mode(struct camera_data *cam, int mode)
-{
- unsigned char cam_reg;
- int err = 0;
-
- if(cam->params.pnp_id.device_type != DEVICE_STV_672)
- return -EINVAL;
-
- /* Set the appropriate bits in FLICKER_MODES, preserving the rest */
- if((err = cpia2_do_command(cam, CPIA2_CMD_GET_FLICKER_MODES,
- TRANSFER_READ, 0)))
- return err;
- cam_reg = cam->params.flicker_control.cam_register;
-
- switch(mode) {
- case NEVER_FLICKER:
- cam_reg |= CPIA2_VP_FLICKER_MODES_NEVER_FLICKER;
- cam_reg &= ~CPIA2_VP_FLICKER_MODES_50HZ;
- break;
- case FLICKER_60:
- cam_reg &= ~CPIA2_VP_FLICKER_MODES_NEVER_FLICKER;
- cam_reg &= ~CPIA2_VP_FLICKER_MODES_50HZ;
- break;
- case FLICKER_50:
- cam_reg &= ~CPIA2_VP_FLICKER_MODES_NEVER_FLICKER;
- cam_reg |= CPIA2_VP_FLICKER_MODES_50HZ;
- break;
- default:
- return -EINVAL;
- }
-
- if((err = cpia2_do_command(cam, CPIA2_CMD_SET_FLICKER_MODES,
- TRANSFER_WRITE, cam_reg)))
- return err;
-
- /* Set the appropriate bits in EXP_MODES, preserving the rest */
- if((err = cpia2_do_command(cam, CPIA2_CMD_GET_VP_EXP_MODES,
- TRANSFER_READ, 0)))
- return err;
- cam_reg = cam->params.vp_params.exposure_modes;
-
- if (mode == NEVER_FLICKER) {
- cam_reg |= CPIA2_VP_EXPOSURE_MODES_INHIBIT_FLICKER;
- } else {
- cam_reg &= ~CPIA2_VP_EXPOSURE_MODES_INHIBIT_FLICKER;
- }
-
- if((err = cpia2_do_command(cam, CPIA2_CMD_SET_VP_EXP_MODES,
- TRANSFER_WRITE, cam_reg)))
- return err;
-
- if((err = cpia2_do_command(cam, CPIA2_CMD_REHASH_VP4,
- TRANSFER_WRITE, 1)))
- return err;
-
- switch(mode) {
- case NEVER_FLICKER:
- case FLICKER_60:
- case FLICKER_50:
- cam->params.flicker_control.flicker_mode_req = mode;
- break;
- default:
- err = -EINVAL;
- }
-
- return err;
-}
-
-/******************************************************************************
- *
- * cpia2_set_property_flip
- *
- *****************************************************************************/
-void cpia2_set_property_flip(struct camera_data *cam, int prop_val)
-{
- unsigned char cam_reg;
-
- cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, TRANSFER_READ, 0);
- cam_reg = cam->params.vp_params.user_effects;
-
- if (prop_val)
- {
- cam_reg |= CPIA2_VP_USER_EFFECTS_FLIP;
- }
- else
- {
- cam_reg &= ~CPIA2_VP_USER_EFFECTS_FLIP;
- }
- cam->params.vp_params.user_effects = cam_reg;
- cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE,
- cam_reg);
-}
-
-/******************************************************************************
- *
- * cpia2_set_property_mirror
- *
- *****************************************************************************/
-void cpia2_set_property_mirror(struct camera_data *cam, int prop_val)
-{
- unsigned char cam_reg;
-
- cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, TRANSFER_READ, 0);
- cam_reg = cam->params.vp_params.user_effects;
-
- if (prop_val)
- {
- cam_reg |= CPIA2_VP_USER_EFFECTS_MIRROR;
- }
- else
- {
- cam_reg &= ~CPIA2_VP_USER_EFFECTS_MIRROR;
- }
- cam->params.vp_params.user_effects = cam_reg;
- cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE,
- cam_reg);
-}
-
-/******************************************************************************
- *
- * cpia2_set_gpio
- *
- *****************************************************************************/
-int cpia2_set_gpio(struct camera_data *cam, unsigned char setting)
-{
- int ret;
-
- /* Set the microport direction (register 0x90, should be defined
- * already) to 1 (user output), and set the microport data (0x91) to
- * the value in the ioctl argument.
- */
-
- ret = cpia2_do_command(cam,
- CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION,
- CPIA2_VC_MP_DIR_OUTPUT,
- 255);
- if (ret < 0)
- return ret;
- cam->params.vp_params.gpio_direction = 255;
-
- ret = cpia2_do_command(cam,
- CPIA2_CMD_SET_VC_MP_GPIO_DATA,
- CPIA2_VC_MP_DIR_OUTPUT,
- setting);
- if (ret < 0)
- return ret;
- cam->params.vp_params.gpio_data = setting;
-
- return 0;
-}
-
-/******************************************************************************
- *
- * cpia2_set_fps
- *
- *****************************************************************************/
-int cpia2_set_fps(struct camera_data *cam, int framerate)
-{
- int retval;
-
- switch(framerate) {
- case CPIA2_VP_FRAMERATE_30:
- case CPIA2_VP_FRAMERATE_25:
- if(cam->params.pnp_id.device_type == DEVICE_STV_672 &&
- cam->params.version.sensor_flags ==
- CPIA2_VP_SENSOR_FLAGS_500) {
- return -EINVAL;
- }
- fallthrough;
- case CPIA2_VP_FRAMERATE_15:
- case CPIA2_VP_FRAMERATE_12_5:
- case CPIA2_VP_FRAMERATE_7_5:
- case CPIA2_VP_FRAMERATE_6_25:
- break;
- default:
- return -EINVAL;
- }
-
- if (cam->params.pnp_id.device_type == DEVICE_STV_672 &&
- framerate == CPIA2_VP_FRAMERATE_15)
- framerate = 0; /* Work around bug in VP4 */
-
- retval = cpia2_do_command(cam,
- CPIA2_CMD_FRAMERATE_REQ,
- TRANSFER_WRITE,
- framerate);
-
- if(retval == 0)
- cam->params.vp_params.frame_rate = framerate;
-
- return retval;
-}
-
-/******************************************************************************
- *
- * cpia2_set_brightness
- *
- *****************************************************************************/
-void cpia2_set_brightness(struct camera_data *cam, unsigned char value)
-{
- /***
- * Don't let the register be set to zero - bug in VP4 - flash of full
- * brightness
- ***/
- if (cam->params.pnp_id.device_type == DEVICE_STV_672 && value == 0)
- value++;
- DBG("Setting brightness to %d (0x%0x)\n", value, value);
- cpia2_do_command(cam, CPIA2_CMD_SET_VP_BRIGHTNESS, TRANSFER_WRITE, value);
-}
-
-/******************************************************************************
- *
- * cpia2_set_contrast
- *
- *****************************************************************************/
-void cpia2_set_contrast(struct camera_data *cam, unsigned char value)
-{
- DBG("Setting contrast to %d (0x%0x)\n", value, value);
- cpia2_do_command(cam, CPIA2_CMD_SET_CONTRAST, TRANSFER_WRITE, value);
-}
-
-/******************************************************************************
- *
- * cpia2_set_saturation
- *
- *****************************************************************************/
-void cpia2_set_saturation(struct camera_data *cam, unsigned char value)
-{
- DBG("Setting saturation to %d (0x%0x)\n", value, value);
- cpia2_do_command(cam,CPIA2_CMD_SET_VP_SATURATION, TRANSFER_WRITE,value);
-}
-
-/******************************************************************************
- *
- * wake_system
- *
- *****************************************************************************/
-static void wake_system(struct camera_data *cam)
-{
- cpia2_do_command(cam, CPIA2_CMD_SET_WAKEUP, TRANSFER_WRITE, 0);
-}
-
-/******************************************************************************
- *
- * set_lowlight_boost
- *
- * Valid for STV500 sensor only
- *****************************************************************************/
-static void set_lowlight_boost(struct camera_data *cam)
-{
- struct cpia2_command cmd;
-
- if (cam->params.pnp_id.device_type != DEVICE_STV_672 ||
- cam->params.version.sensor_flags != CPIA2_VP_SENSOR_FLAGS_500)
- return;
-
- cmd.direction = TRANSFER_WRITE;
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
- cmd.reg_count = 3;
- cmd.start = CPIA2_VP_RAM_ADDR_H;
-
- cmd.buffer.block_data[0] = 0; /* High byte of address to write to */
- cmd.buffer.block_data[1] = 0x59; /* Low byte of address to write to */
- cmd.buffer.block_data[2] = 0; /* High byte of data to write */
-
- cpia2_send_command(cam, &cmd);
-
- if (cam->params.vp_params.lowlight_boost) {
- cmd.buffer.block_data[0] = 0x02; /* Low byte data to write */
- } else {
- cmd.buffer.block_data[0] = 0x06;
- }
- cmd.start = CPIA2_VP_RAM_DATA;
- cmd.reg_count = 1;
- cpia2_send_command(cam, &cmd);
-
- /* Rehash the VP4 values */
- cpia2_do_command(cam, CPIA2_CMD_REHASH_VP4, TRANSFER_WRITE, 1);
-}
-
-/******************************************************************************
- *
- * cpia2_set_format
- *
- * Assumes that new size is already set in param struct.
- *****************************************************************************/
-void cpia2_set_format(struct camera_data *cam)
-{
- cam->flush = true;
-
- cpia2_usb_stream_pause(cam);
-
- /* reset camera to new size */
- cpia2_set_low_power(cam);
- cpia2_reset_camera(cam);
- cam->flush = false;
-
- cpia2_dbg_dump_registers(cam);
-
- cpia2_usb_stream_resume(cam);
-}
-
-/******************************************************************************
- *
- * cpia2_dbg_dump_registers
- *
- *****************************************************************************/
-void cpia2_dbg_dump_registers(struct camera_data *cam)
-{
-#ifdef _CPIA2_DEBUG_
- struct cpia2_command cmd;
-
- if (!(debugs_on & DEBUG_DUMP_REGS))
- return;
-
- cmd.direction = TRANSFER_READ;
-
- /* Start with bank 0 (SYSTEM) */
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM;
- cmd.reg_count = 3;
- cmd.start = 0;
- cpia2_send_command(cam, &cmd);
- printk(KERN_DEBUG "System Device Hi = 0x%X\n",
- cmd.buffer.block_data[0]);
- printk(KERN_DEBUG "System Device Lo = 0x%X\n",
- cmd.buffer.block_data[1]);
- printk(KERN_DEBUG "System_system control = 0x%X\n",
- cmd.buffer.block_data[2]);
-
- /* Bank 1 (VC) */
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
- cmd.reg_count = 4;
- cmd.start = 0x80;
- cpia2_send_command(cam, &cmd);
- printk(KERN_DEBUG "ASIC_ID = 0x%X\n",
- cmd.buffer.block_data[0]);
- printk(KERN_DEBUG "ASIC_REV = 0x%X\n",
- cmd.buffer.block_data[1]);
- printk(KERN_DEBUG "PW_CONTRL = 0x%X\n",
- cmd.buffer.block_data[2]);
- printk(KERN_DEBUG "WAKEUP = 0x%X\n",
- cmd.buffer.block_data[3]);
-
- cmd.start = 0xA0; /* ST_CTRL */
- cmd.reg_count = 1;
- cpia2_send_command(cam, &cmd);
- printk(KERN_DEBUG "Stream ctrl = 0x%X\n",
- cmd.buffer.block_data[0]);
-
- cmd.start = 0xA4; /* Stream status */
- cpia2_send_command(cam, &cmd);
- printk(KERN_DEBUG "Stream status = 0x%X\n",
- cmd.buffer.block_data[0]);
-
- cmd.start = 0xA8; /* USB status */
- cmd.reg_count = 3;
- cpia2_send_command(cam, &cmd);
- printk(KERN_DEBUG "USB_CTRL = 0x%X\n",
- cmd.buffer.block_data[0]);
- printk(KERN_DEBUG "USB_STRM = 0x%X\n",
- cmd.buffer.block_data[1]);
- printk(KERN_DEBUG "USB_STATUS = 0x%X\n",
- cmd.buffer.block_data[2]);
-
- cmd.start = 0xAF; /* USB settings */
- cmd.reg_count = 1;
- cpia2_send_command(cam, &cmd);
- printk(KERN_DEBUG "USB settings = 0x%X\n",
- cmd.buffer.block_data[0]);
-
- cmd.start = 0xC0; /* VC stuff */
- cmd.reg_count = 26;
- cpia2_send_command(cam, &cmd);
- printk(KERN_DEBUG "VC Control = 0x%0X\n",
- cmd.buffer.block_data[0]);
- printk(KERN_DEBUG "VC Format = 0x%0X\n",
- cmd.buffer.block_data[3]);
- printk(KERN_DEBUG "VC Clocks = 0x%0X\n",
- cmd.buffer.block_data[4]);
- printk(KERN_DEBUG "VC IHSize = 0x%0X\n",
- cmd.buffer.block_data[5]);
- printk(KERN_DEBUG "VC Xlim Hi = 0x%0X\n",
- cmd.buffer.block_data[6]);
- printk(KERN_DEBUG "VC XLim Lo = 0x%0X\n",
- cmd.buffer.block_data[7]);
- printk(KERN_DEBUG "VC YLim Hi = 0x%0X\n",
- cmd.buffer.block_data[8]);
- printk(KERN_DEBUG "VC YLim Lo = 0x%0X\n",
- cmd.buffer.block_data[9]);
- printk(KERN_DEBUG "VC OHSize = 0x%0X\n",
- cmd.buffer.block_data[10]);
- printk(KERN_DEBUG "VC OVSize = 0x%0X\n",
- cmd.buffer.block_data[11]);
- printk(KERN_DEBUG "VC HCrop = 0x%0X\n",
- cmd.buffer.block_data[12]);
- printk(KERN_DEBUG "VC VCrop = 0x%0X\n",
- cmd.buffer.block_data[13]);
- printk(KERN_DEBUG "VC HPhase = 0x%0X\n",
- cmd.buffer.block_data[14]);
- printk(KERN_DEBUG "VC VPhase = 0x%0X\n",
- cmd.buffer.block_data[15]);
- printk(KERN_DEBUG "VC HIspan = 0x%0X\n",
- cmd.buffer.block_data[16]);
- printk(KERN_DEBUG "VC VIspan = 0x%0X\n",
- cmd.buffer.block_data[17]);
- printk(KERN_DEBUG "VC HiCrop = 0x%0X\n",
- cmd.buffer.block_data[18]);
- printk(KERN_DEBUG "VC ViCrop = 0x%0X\n",
- cmd.buffer.block_data[19]);
- printk(KERN_DEBUG "VC HiFract = 0x%0X\n",
- cmd.buffer.block_data[20]);
- printk(KERN_DEBUG "VC ViFract = 0x%0X\n",
- cmd.buffer.block_data[21]);
- printk(KERN_DEBUG "VC JPeg Opt = 0x%0X\n",
- cmd.buffer.block_data[22]);
- printk(KERN_DEBUG "VC Creep Per = 0x%0X\n",
- cmd.buffer.block_data[23]);
- printk(KERN_DEBUG "VC User Sq. = 0x%0X\n",
- cmd.buffer.block_data[24]);
- printk(KERN_DEBUG "VC Target KB = 0x%0X\n",
- cmd.buffer.block_data[25]);
-
- /*** VP ***/
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP;
- cmd.reg_count = 14;
- cmd.start = 0;
- cpia2_send_command(cam, &cmd);
-
- printk(KERN_DEBUG "VP Dev Hi = 0x%0X\n",
- cmd.buffer.block_data[0]);
- printk(KERN_DEBUG "VP Dev Lo = 0x%0X\n",
- cmd.buffer.block_data[1]);
- printk(KERN_DEBUG "VP Sys State = 0x%0X\n",
- cmd.buffer.block_data[2]);
- printk(KERN_DEBUG "VP Sys Ctrl = 0x%0X\n",
- cmd.buffer.block_data[3]);
- printk(KERN_DEBUG "VP Sensor flg = 0x%0X\n",
- cmd.buffer.block_data[5]);
- printk(KERN_DEBUG "VP Sensor Rev = 0x%0X\n",
- cmd.buffer.block_data[6]);
- printk(KERN_DEBUG "VP Dev Config = 0x%0X\n",
- cmd.buffer.block_data[7]);
- printk(KERN_DEBUG "VP GPIO_DIR = 0x%0X\n",
- cmd.buffer.block_data[8]);
- printk(KERN_DEBUG "VP GPIO_DATA = 0x%0X\n",
- cmd.buffer.block_data[9]);
- printk(KERN_DEBUG "VP Ram ADDR H = 0x%0X\n",
- cmd.buffer.block_data[10]);
- printk(KERN_DEBUG "VP Ram ADDR L = 0x%0X\n",
- cmd.buffer.block_data[11]);
- printk(KERN_DEBUG "VP RAM Data = 0x%0X\n",
- cmd.buffer.block_data[12]);
- printk(KERN_DEBUG "Do Call = 0x%0X\n",
- cmd.buffer.block_data[13]);
-
- if (cam->params.pnp_id.device_type == DEVICE_STV_672) {
- cmd.reg_count = 9;
- cmd.start = 0x0E;
- cpia2_send_command(cam, &cmd);
- printk(KERN_DEBUG "VP Clock Ctrl = 0x%0X\n",
- cmd.buffer.block_data[0]);
- printk(KERN_DEBUG "VP Patch Rev = 0x%0X\n",
- cmd.buffer.block_data[1]);
- printk(KERN_DEBUG "VP Vid Mode = 0x%0X\n",
- cmd.buffer.block_data[2]);
- printk(KERN_DEBUG "VP Framerate = 0x%0X\n",
- cmd.buffer.block_data[3]);
- printk(KERN_DEBUG "VP UserEffect = 0x%0X\n",
- cmd.buffer.block_data[4]);
- printk(KERN_DEBUG "VP White Bal = 0x%0X\n",
- cmd.buffer.block_data[5]);
- printk(KERN_DEBUG "VP WB thresh = 0x%0X\n",
- cmd.buffer.block_data[6]);
- printk(KERN_DEBUG "VP Exp Modes = 0x%0X\n",
- cmd.buffer.block_data[7]);
- printk(KERN_DEBUG "VP Exp Target = 0x%0X\n",
- cmd.buffer.block_data[8]);
-
- cmd.reg_count = 1;
- cmd.start = 0x1B;
- cpia2_send_command(cam, &cmd);
- printk(KERN_DEBUG "VP FlickerMds = 0x%0X\n",
- cmd.buffer.block_data[0]);
- } else {
- cmd.reg_count = 8 ;
- cmd.start = 0x0E;
- cpia2_send_command(cam, &cmd);
- printk(KERN_DEBUG "VP Clock Ctrl = 0x%0X\n",
- cmd.buffer.block_data[0]);
- printk(KERN_DEBUG "VP Patch Rev = 0x%0X\n",
- cmd.buffer.block_data[1]);
- printk(KERN_DEBUG "VP Vid Mode = 0x%0X\n",
- cmd.buffer.block_data[5]);
- printk(KERN_DEBUG "VP Framerate = 0x%0X\n",
- cmd.buffer.block_data[6]);
- printk(KERN_DEBUG "VP UserEffect = 0x%0X\n",
- cmd.buffer.block_data[7]);
-
- cmd.reg_count = 1;
- cmd.start = CPIA2_VP5_EXPOSURE_TARGET;
- cpia2_send_command(cam, &cmd);
- printk(KERN_DEBUG "VP5 Exp Target= 0x%0X\n",
- cmd.buffer.block_data[0]);
-
- cmd.reg_count = 4;
- cmd.start = 0x3A;
- cpia2_send_command(cam, &cmd);
- printk(KERN_DEBUG "VP5 MY Black = 0x%0X\n",
- cmd.buffer.block_data[0]);
- printk(KERN_DEBUG "VP5 MCY Range = 0x%0X\n",
- cmd.buffer.block_data[1]);
- printk(KERN_DEBUG "VP5 MYCEILING = 0x%0X\n",
- cmd.buffer.block_data[2]);
- printk(KERN_DEBUG "VP5 MCUV Sat = 0x%0X\n",
- cmd.buffer.block_data[3]);
- }
-#endif
-}
-
-/******************************************************************************
- *
- * reset_camera_struct
- *
- * Sets all values to the defaults
- *****************************************************************************/
-static void reset_camera_struct(struct camera_data *cam)
-{
- /***
- * The following parameter values are the defaults from the register map.
- ***/
- cam->params.vp_params.lowlight_boost = 0;
-
- /* FlickerModes */
- cam->params.flicker_control.flicker_mode_req = NEVER_FLICKER;
-
- /* jpeg params */
- cam->params.compression.jpeg_options = CPIA2_VC_VC_JPEG_OPT_DEFAULT;
- cam->params.compression.creep_period = 2;
- cam->params.compression.user_squeeze = 20;
- cam->params.compression.inhibit_htables = false;
-
- /* gpio params */
- cam->params.vp_params.gpio_direction = 0; /* write, the default safe mode */
- cam->params.vp_params.gpio_data = 0;
-
- /* Target kb params */
- cam->params.vc_params.quality = 100;
-
- /***
- * Set Sensor FPS as fast as possible.
- ***/
- if(cam->params.pnp_id.device_type == DEVICE_STV_672) {
- if(cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500)
- cam->params.vp_params.frame_rate = CPIA2_VP_FRAMERATE_15;
- else
- cam->params.vp_params.frame_rate = CPIA2_VP_FRAMERATE_30;
- } else {
- cam->params.vp_params.frame_rate = CPIA2_VP_FRAMERATE_30;
- }
-
- /***
- * Set default video mode as large as possible :
- * for vga sensor set to vga, for cif sensor set to CIF.
- ***/
- if (cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500) {
- cam->sensor_type = CPIA2_SENSOR_500;
- cam->video_size = VIDEOSIZE_VGA;
- cam->params.roi.width = STV_IMAGE_VGA_COLS;
- cam->params.roi.height = STV_IMAGE_VGA_ROWS;
- } else {
- cam->sensor_type = CPIA2_SENSOR_410;
- cam->video_size = VIDEOSIZE_CIF;
- cam->params.roi.width = STV_IMAGE_CIF_COLS;
- cam->params.roi.height = STV_IMAGE_CIF_ROWS;
- }
-
- cam->width = cam->params.roi.width;
- cam->height = cam->params.roi.height;
-}
-
-/******************************************************************************
- *
- * cpia2_init_camera_struct
- *
- * Deinitialize camera struct
- *****************************************************************************/
-void cpia2_deinit_camera_struct(struct camera_data *cam, struct usb_interface *intf)
-{
- v4l2_device_unregister(&cam->v4l2_dev);
- kfree(cam);
-}
-
-/******************************************************************************
- *
- * cpia2_init_camera_struct
- *
- * Initializes camera struct, does not call reset to fill in defaults.
- *****************************************************************************/
-struct camera_data *cpia2_init_camera_struct(struct usb_interface *intf)
-{
- struct camera_data *cam;
-
- cam = kzalloc(sizeof(*cam), GFP_KERNEL);
-
- if (!cam) {
- ERR("couldn't kmalloc cpia2 struct\n");
- return NULL;
- }
-
- cam->v4l2_dev.release = cpia2_camera_release;
- if (v4l2_device_register(&intf->dev, &cam->v4l2_dev) < 0) {
- v4l2_err(&cam->v4l2_dev, "couldn't register v4l2_device\n");
- kfree(cam);
- return NULL;
- }
-
- mutex_init(&cam->v4l2_lock);
- init_waitqueue_head(&cam->wq_stream);
-
- return cam;
-}
-
-/******************************************************************************
- *
- * cpia2_init_camera
- *
- * Initializes camera.
- *****************************************************************************/
-int cpia2_init_camera(struct camera_data *cam)
-{
- DBG("Start\n");
-
- cam->mmapped = false;
-
- /* Get sensor and asic types before reset. */
- cpia2_set_high_power(cam);
- cpia2_get_version_info(cam);
- if (cam->params.version.asic_id != CPIA2_ASIC_672) {
- ERR("Device IO error (asicID has incorrect value of 0x%X\n",
- cam->params.version.asic_id);
- return -ENODEV;
- }
-
- /* Set GPIO direction and data to a safe state. */
- cpia2_do_command(cam, CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION,
- TRANSFER_WRITE, 0);
- cpia2_do_command(cam, CPIA2_CMD_SET_VC_MP_GPIO_DATA,
- TRANSFER_WRITE, 0);
-
- /* resetting struct requires version info for sensor and asic types */
- reset_camera_struct(cam);
-
- cpia2_set_low_power(cam);
-
- DBG("End\n");
-
- return 0;
-}
-
-/******************************************************************************
- *
- * cpia2_allocate_buffers
- *
- *****************************************************************************/
-int cpia2_allocate_buffers(struct camera_data *cam)
-{
- int i;
-
- if(!cam->buffers) {
- u32 size = cam->num_frames*sizeof(struct framebuf);
- cam->buffers = kmalloc(size, GFP_KERNEL);
- if(!cam->buffers) {
- ERR("couldn't kmalloc frame buffer structures\n");
- return -ENOMEM;
- }
- }
-
- if(!cam->frame_buffer) {
- cam->frame_buffer = rvmalloc(cam->frame_size*cam->num_frames);
- if (!cam->frame_buffer) {
- ERR("couldn't vmalloc frame buffer data area\n");
- kfree(cam->buffers);
- cam->buffers = NULL;
- return -ENOMEM;
- }
- }
-
- for(i=0; i<cam->num_frames-1; ++i) {
- cam->buffers[i].next = &cam->buffers[i+1];
- cam->buffers[i].data = cam->frame_buffer +i*cam->frame_size;
- cam->buffers[i].status = FRAME_EMPTY;
- cam->buffers[i].length = 0;
- cam->buffers[i].max_length = 0;
- cam->buffers[i].num = i;
- }
- cam->buffers[i].next = cam->buffers;
- cam->buffers[i].data = cam->frame_buffer +i*cam->frame_size;
- cam->buffers[i].status = FRAME_EMPTY;
- cam->buffers[i].length = 0;
- cam->buffers[i].max_length = 0;
- cam->buffers[i].num = i;
- cam->curbuff = cam->buffers;
- cam->workbuff = cam->curbuff->next;
- DBG("buffers=%p, curbuff=%p, workbuff=%p\n", cam->buffers, cam->curbuff,
- cam->workbuff);
- return 0;
-}
-
-/******************************************************************************
- *
- * cpia2_free_buffers
- *
- *****************************************************************************/
-void cpia2_free_buffers(struct camera_data *cam)
-{
- if(cam->buffers) {
- kfree(cam->buffers);
- cam->buffers = NULL;
- }
- if(cam->frame_buffer) {
- rvfree(cam->frame_buffer, cam->frame_size*cam->num_frames);
- cam->frame_buffer = NULL;
- }
-}
-
-/******************************************************************************
- *
- * cpia2_read
- *
- *****************************************************************************/
-long cpia2_read(struct camera_data *cam,
- char __user *buf, unsigned long count, int noblock)
-{
- struct framebuf *frame;
-
- if (!count)
- return 0;
-
- if (!buf) {
- ERR("%s: buffer NULL\n",__func__);
- return -EINVAL;
- }
-
- if (!cam) {
- ERR("%s: Internal error, camera_data NULL!\n",__func__);
- return -EINVAL;
- }
-
- if (!cam->streaming) {
- /* Start streaming */
- cpia2_usb_stream_start(cam,
- cam->params.camera_state.stream_mode);
- }
-
- /* Copy cam->curbuff in case it changes while we're processing */
- frame = cam->curbuff;
- if (noblock && frame->status != FRAME_READY) {
- return -EAGAIN;
- }
-
- if (frame->status != FRAME_READY) {
- mutex_unlock(&cam->v4l2_lock);
- wait_event_interruptible(cam->wq_stream,
- !video_is_registered(&cam->vdev) ||
- (frame = cam->curbuff)->status == FRAME_READY);
- mutex_lock(&cam->v4l2_lock);
- if (signal_pending(current))
- return -ERESTARTSYS;
- if (!video_is_registered(&cam->vdev))
- return 0;
- }
-
- /* copy data to user space */
- if (frame->length > count)
- return -EFAULT;
- if (copy_to_user(buf, frame->data, frame->length))
- return -EFAULT;
-
- count = frame->length;
-
- frame->status = FRAME_EMPTY;
-
- return count;
-}
-
-/******************************************************************************
- *
- * cpia2_poll
- *
- *****************************************************************************/
-__poll_t cpia2_poll(struct camera_data *cam, struct file *filp,
- poll_table *wait)
-{
- __poll_t status = v4l2_ctrl_poll(filp, wait);
-
- if ((poll_requested_events(wait) & (EPOLLIN | EPOLLRDNORM)) &&
- !cam->streaming) {
- /* Start streaming */
- cpia2_usb_stream_start(cam,
- cam->params.camera_state.stream_mode);
- }
-
- poll_wait(filp, &cam->wq_stream, wait);
-
- if (cam->curbuff->status == FRAME_READY)
- status |= EPOLLIN | EPOLLRDNORM;
-
- return status;
-}
-
-/******************************************************************************
- *
- * cpia2_remap_buffer
- *
- *****************************************************************************/
-int cpia2_remap_buffer(struct camera_data *cam, struct vm_area_struct *vma)
-{
- const char *adr = (const char *)vma->vm_start;
- unsigned long size = vma->vm_end-vma->vm_start;
- unsigned long start_offset = vma->vm_pgoff << PAGE_SHIFT;
- unsigned long start = (unsigned long) adr;
- unsigned long page, pos;
-
- DBG("mmap offset:%ld size:%ld\n", start_offset, size);
-
- if (!video_is_registered(&cam->vdev))
- return -ENODEV;
-
- if (size > cam->frame_size*cam->num_frames ||
- (start_offset % cam->frame_size) != 0 ||
- (start_offset+size > cam->frame_size*cam->num_frames))
- return -EINVAL;
-
- pos = ((unsigned long) (cam->frame_buffer)) + start_offset;
- while (size > 0) {
- page = kvirt_to_pa(pos);
- if (remap_pfn_range(vma, start, page >> PAGE_SHIFT, PAGE_SIZE, PAGE_SHARED))
- return -EAGAIN;
- start += PAGE_SIZE;
- pos += PAGE_SIZE;
- if (size > PAGE_SIZE)
- size -= PAGE_SIZE;
- else
- size = 0;
- }
-
- cam->mmapped = true;
- return 0;
-}
diff --git a/drivers/staging/media/deprecated/cpia2/cpia2_registers.h b/drivers/staging/media/deprecated/cpia2/cpia2_registers.h
deleted file mode 100644
index 8c73812a15c9..000000000000
--- a/drivers/staging/media/deprecated/cpia2/cpia2_registers.h
+++ /dev/null
@@ -1,463 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/****************************************************************************
- *
- * Filename: cpia2registers.h
- *
- * Copyright 2001, STMicrolectronics, Inc.
- *
- * Description:
- * Definitions for the CPia2 register set
- *
- ****************************************************************************/
-
-#ifndef CPIA2_REGISTER_HEADER
-#define CPIA2_REGISTER_HEADER
-
-/***
- * System register set (Bank 0)
- ***/
-#define CPIA2_SYSTEM_DEVICE_HI 0x00
-#define CPIA2_SYSTEM_DEVICE_LO 0x01
-
-#define CPIA2_SYSTEM_SYSTEM_CONTROL 0x02
-#define CPIA2_SYSTEM_CONTROL_LOW_POWER 0x00
-#define CPIA2_SYSTEM_CONTROL_HIGH_POWER 0x01
-#define CPIA2_SYSTEM_CONTROL_SUSPEND 0x02
-#define CPIA2_SYSTEM_CONTROL_V2W_ERR 0x10
-#define CPIA2_SYSTEM_CONTROL_RB_ERR 0x10
-#define CPIA2_SYSTEM_CONTROL_CLEAR_ERR 0x80
-
-#define CPIA2_SYSTEM_INT_PACKET_CTRL 0x04
-#define CPIA2_SYSTEM_INT_PACKET_CTRL_ENABLE_SW_XX 0x01
-#define CPIA2_SYSTEM_INT_PACKET_CTRL_ENABLE_EOF 0x02
-#define CPIA2_SYSTEM_INT_PACKET_CTRL_ENABLE_INT1 0x04
-
-#define CPIA2_SYSTEM_CACHE_CTRL 0x05
-#define CPIA2_SYSTEM_CACHE_CTRL_CACHE_RESET 0x01
-#define CPIA2_SYSTEM_CACHE_CTRL_CACHE_FLUSH 0x02
-
-#define CPIA2_SYSTEM_SERIAL_CTRL 0x06
-#define CPIA2_SYSTEM_SERIAL_CTRL_NULL_CMD 0x00
-#define CPIA2_SYSTEM_SERIAL_CTRL_START_CMD 0x01
-#define CPIA2_SYSTEM_SERIAL_CTRL_STOP_CMD 0x02
-#define CPIA2_SYSTEM_SERIAL_CTRL_WRITE_CMD 0x03
-#define CPIA2_SYSTEM_SERIAL_CTRL_READ_ACK_CMD 0x04
-#define CPIA2_SYSTEM_SERIAL_CTRL_READ_NACK_CMD 0x05
-
-#define CPIA2_SYSTEM_SERIAL_DATA 0x07
-
-#define CPIA2_SYSTEM_VP_SERIAL_ADDR 0x08
-
-/***
- * I2C addresses for various devices in CPiA2
- ***/
-#define CPIA2_SYSTEM_VP_SERIAL_ADDR_SENSOR 0x20
-#define CPIA2_SYSTEM_VP_SERIAL_ADDR_VP 0x88
-#define CPIA2_SYSTEM_VP_SERIAL_ADDR_676_VP 0x8A
-
-#define CPIA2_SYSTEM_SPARE_REG1 0x09
-#define CPIA2_SYSTEM_SPARE_REG2 0x0A
-#define CPIA2_SYSTEM_SPARE_REG3 0x0B
-
-#define CPIA2_SYSTEM_MC_PORT_0 0x0C
-#define CPIA2_SYSTEM_MC_PORT_1 0x0D
-#define CPIA2_SYSTEM_MC_PORT_2 0x0E
-#define CPIA2_SYSTEM_MC_PORT_3 0x0F
-
-#define CPIA2_SYSTEM_STATUS_PKT 0x20
-#define CPIA2_SYSTEM_STATUS_PKT_END 0x27
-
-#define CPIA2_SYSTEM_DESCRIP_VID_HI 0x30
-#define CPIA2_SYSTEM_DESCRIP_VID_LO 0x31
-#define CPIA2_SYSTEM_DESCRIP_PID_HI 0x32
-#define CPIA2_SYSTEM_DESCRIP_PID_LO 0x33
-
-#define CPIA2_SYSTEM_FW_VERSION_HI 0x34
-#define CPIA2_SYSTEM_FW_VERSION_LO 0x35
-
-#define CPIA2_SYSTEM_CACHE_START_INDEX 0x80
-#define CPIA2_SYSTEM_CACHE_MAX_WRITES 0x10
-
-/***
- * VC register set (Bank 1)
- ***/
-#define CPIA2_VC_ASIC_ID 0x80
-
-#define CPIA2_VC_ASIC_REV 0x81
-
-#define CPIA2_VC_PW_CTRL 0x82
-#define CPIA2_VC_PW_CTRL_COLDSTART 0x01
-#define CPIA2_VC_PW_CTRL_CP_CLK_EN 0x02
-#define CPIA2_VC_PW_CTRL_VP_RESET_N 0x04
-#define CPIA2_VC_PW_CTRL_VC_CLK_EN 0x08
-#define CPIA2_VC_PW_CTRL_VC_RESET_N 0x10
-#define CPIA2_VC_PW_CTRL_GOTO_SUSPEND 0x20
-#define CPIA2_VC_PW_CTRL_UDC_SUSPEND 0x40
-#define CPIA2_VC_PW_CTRL_PWR_DOWN 0x80
-
-#define CPIA2_VC_WAKEUP 0x83
-#define CPIA2_VC_WAKEUP_SW_ENABLE 0x01
-#define CPIA2_VC_WAKEUP_XX_ENABLE 0x02
-#define CPIA2_VC_WAKEUP_SW_ATWAKEUP 0x04
-#define CPIA2_VC_WAKEUP_XX_ATWAKEUP 0x08
-
-#define CPIA2_VC_CLOCK_CTRL 0x84
-#define CPIA2_VC_CLOCK_CTRL_TESTUP72 0x01
-
-#define CPIA2_VC_INT_ENABLE 0x88
-#define CPIA2_VC_INT_ENABLE_XX_IE 0x01
-#define CPIA2_VC_INT_ENABLE_SW_IE 0x02
-#define CPIA2_VC_INT_ENABLE_VC_IE 0x04
-#define CPIA2_VC_INT_ENABLE_USBDATA_IE 0x08
-#define CPIA2_VC_INT_ENABLE_USBSETUP_IE 0x10
-#define CPIA2_VC_INT_ENABLE_USBCFG_IE 0x20
-
-#define CPIA2_VC_INT_FLAG 0x89
-#define CPIA2_VC_INT_ENABLE_XX_FLAG 0x01
-#define CPIA2_VC_INT_ENABLE_SW_FLAG 0x02
-#define CPIA2_VC_INT_ENABLE_VC_FLAG 0x04
-#define CPIA2_VC_INT_ENABLE_USBDATA_FLAG 0x08
-#define CPIA2_VC_INT_ENABLE_USBSETUP_FLAG 0x10
-#define CPIA2_VC_INT_ENABLE_USBCFG_FLAG 0x20
-#define CPIA2_VC_INT_ENABLE_SET_RESET_BIT 0x80
-
-#define CPIA2_VC_INT_STATE 0x8A
-#define CPIA2_VC_INT_STATE_XX_STATE 0x01
-#define CPIA2_VC_INT_STATE_SW_STATE 0x02
-
-#define CPIA2_VC_MP_DIR 0x90
-#define CPIA2_VC_MP_DIR_INPUT 0x00
-#define CPIA2_VC_MP_DIR_OUTPUT 0x01
-
-#define CPIA2_VC_MP_DATA 0x91
-
-#define CPIA2_VC_DP_CTRL 0x98
-#define CPIA2_VC_DP_CTRL_MODE_0 0x00
-#define CPIA2_VC_DP_CTRL_MODE_A 0x01
-#define CPIA2_VC_DP_CTRL_MODE_B 0x02
-#define CPIA2_VC_DP_CTRL_MODE_C 0x03
-#define CPIA2_VC_DP_CTRL_FAKE_FST 0x04
-
-#define CPIA2_VC_AD_CTRL 0x99
-#define CPIA2_VC_AD_CTRL_SRC_0 0x00
-#define CPIA2_VC_AD_CTRL_SRC_DIGI_A 0x01
-#define CPIA2_VC_AD_CTRL_SRC_REG 0x02
-#define CPIA2_VC_AD_CTRL_DST_USB 0x00
-#define CPIA2_VC_AD_CTRL_DST_REG 0x04
-
-#define CPIA2_VC_AD_TEST_IN 0x9B
-
-#define CPIA2_VC_AD_TEST_OUT 0x9C
-
-#define CPIA2_VC_AD_STATUS 0x9D
-#define CPIA2_VC_AD_STATUS_EMPTY 0x01
-#define CPIA2_VC_AD_STATUS_FULL 0x02
-
-#define CPIA2_VC_DP_DATA 0x9E
-
-#define CPIA2_VC_ST_CTRL 0xA0
-#define CPIA2_VC_ST_CTRL_SRC_VC 0x00
-#define CPIA2_VC_ST_CTRL_SRC_DP 0x01
-#define CPIA2_VC_ST_CTRL_SRC_REG 0x02
-
-#define CPIA2_VC_ST_CTRL_RAW_SELECT 0x04
-
-#define CPIA2_VC_ST_CTRL_DST_USB 0x00
-#define CPIA2_VC_ST_CTRL_DST_DP 0x08
-#define CPIA2_VC_ST_CTRL_DST_REG 0x10
-
-#define CPIA2_VC_ST_CTRL_FIFO_ENABLE 0x20
-#define CPIA2_VC_ST_CTRL_EOF_DETECT 0x40
-
-#define CPIA2_VC_ST_TEST 0xA1
-#define CPIA2_VC_ST_TEST_MODE_MANUAL 0x00
-#define CPIA2_VC_ST_TEST_MODE_INCREMENT 0x02
-
-#define CPIA2_VC_ST_TEST_AUTO_FILL 0x08
-
-#define CPIA2_VC_ST_TEST_REPEAT_FIFO 0x10
-
-#define CPIA2_VC_ST_TEST_IN 0xA2
-
-#define CPIA2_VC_ST_TEST_OUT 0xA3
-
-#define CPIA2_VC_ST_STATUS 0xA4
-#define CPIA2_VC_ST_STATUS_EMPTY 0x01
-#define CPIA2_VC_ST_STATUS_FULL 0x02
-
-#define CPIA2_VC_ST_FRAME_DETECT_1 0xA5
-
-#define CPIA2_VC_ST_FRAME_DETECT_2 0xA6
-
-#define CPIA2_VC_USB_CTRL 0xA8
-#define CPIA2_VC_USB_CTRL_CMD_STALLED 0x01
-#define CPIA2_VC_USB_CTRL_CMD_READY 0x02
-#define CPIA2_VC_USB_CTRL_CMD_STATUS 0x04
-#define CPIA2_VC_USB_CTRL_CMD_STATUS_DIR 0x08
-#define CPIA2_VC_USB_CTRL_CMD_NO_CLASH 0x10
-#define CPIA2_VC_USB_CTRL_CMD_MICRO_ACCESS 0x80
-
-#define CPIA2_VC_USB_STRM 0xA9
-#define CPIA2_VC_USB_STRM_ISO_ENABLE 0x01
-#define CPIA2_VC_USB_STRM_BLK_ENABLE 0x02
-#define CPIA2_VC_USB_STRM_INT_ENABLE 0x04
-#define CPIA2_VC_USB_STRM_AUD_ENABLE 0x08
-
-#define CPIA2_VC_USB_STATUS 0xAA
-#define CPIA2_VC_USB_STATUS_CMD_IN_PROGRESS 0x01
-#define CPIA2_VC_USB_STATUS_CMD_STATUS_STALL 0x02
-#define CPIA2_VC_USB_STATUS_CMD_HANDSHAKE 0x04
-#define CPIA2_VC_USB_STATUS_CMD_OVERRIDE 0x08
-#define CPIA2_VC_USB_STATUS_CMD_FIFO_BUSY 0x10
-#define CPIA2_VC_USB_STATUS_BULK_REPEAT_TXN 0x20
-#define CPIA2_VC_USB_STATUS_CONFIG_DONE 0x40
-#define CPIA2_VC_USB_STATUS_USB_SUSPEND 0x80
-
-#define CPIA2_VC_USB_CMDW 0xAB
-
-#define CPIA2_VC_USB_DATARW 0xAC
-
-#define CPIA2_VC_USB_INFO 0xAD
-
-#define CPIA2_VC_USB_CONFIG 0xAE
-
-#define CPIA2_VC_USB_SETTINGS 0xAF
-#define CPIA2_VC_USB_SETTINGS_CONFIG_MASK 0x03
-#define CPIA2_VC_USB_SETTINGS_INTERFACE_MASK 0x0C
-#define CPIA2_VC_USB_SETTINGS_ALTERNATE_MASK 0x70
-
-#define CPIA2_VC_USB_ISOLIM 0xB0
-
-#define CPIA2_VC_USB_ISOFAILS 0xB1
-
-#define CPIA2_VC_USB_ISOMAXPKTHI 0xB2
-
-#define CPIA2_VC_USB_ISOMAXPKTLO 0xB3
-
-#define CPIA2_VC_V2W_CTRL 0xB8
-#define CPIA2_VC_V2W_SELECT 0x01
-
-#define CPIA2_VC_V2W_SCL 0xB9
-
-#define CPIA2_VC_V2W_SDA 0xBA
-
-#define CPIA2_VC_VC_CTRL 0xC0
-#define CPIA2_VC_VC_CTRL_RUN 0x01
-#define CPIA2_VC_VC_CTRL_SINGLESHOT 0x02
-#define CPIA2_VC_VC_CTRL_IDLING 0x04
-#define CPIA2_VC_VC_CTRL_INHIBIT_H_TABLES 0x10
-#define CPIA2_VC_VC_CTRL_INHIBIT_Q_TABLES 0x20
-#define CPIA2_VC_VC_CTRL_INHIBIT_PRIVATE 0x40
-
-#define CPIA2_VC_VC_RESTART_IVAL_HI 0xC1
-
-#define CPIA2_VC_VC_RESTART_IVAL_LO 0xC2
-
-#define CPIA2_VC_VC_FORMAT 0xC3
-#define CPIA2_VC_VC_FORMAT_UFIRST 0x01
-#define CPIA2_VC_VC_FORMAT_MONO 0x02
-#define CPIA2_VC_VC_FORMAT_DECIMATING 0x04
-#define CPIA2_VC_VC_FORMAT_SHORTLINE 0x08
-#define CPIA2_VC_VC_FORMAT_SELFTEST 0x10
-
-#define CPIA2_VC_VC_CLOCKS 0xC4
-#define CPIA2_VC_VC_CLOCKS_CLKDIV_MASK 0x03
-#define CPIA2_VC_VC_672_CLOCKS_CIF_DIV_BY_3 0x04
-#define CPIA2_VC_VC_672_CLOCKS_SCALING 0x08
-#define CPIA2_VC_VC_CLOCKS_LOGDIV0 0x00
-#define CPIA2_VC_VC_CLOCKS_LOGDIV1 0x01
-#define CPIA2_VC_VC_CLOCKS_LOGDIV2 0x02
-#define CPIA2_VC_VC_CLOCKS_LOGDIV3 0x03
-#define CPIA2_VC_VC_676_CLOCKS_CIF_DIV_BY_3 0x08
-#define CPIA2_VC_VC_676_CLOCKS_SCALING 0x10
-
-#define CPIA2_VC_VC_IHSIZE_LO 0xC5
-
-#define CPIA2_VC_VC_XLIM_HI 0xC6
-
-#define CPIA2_VC_VC_XLIM_LO 0xC7
-
-#define CPIA2_VC_VC_YLIM_HI 0xC8
-
-#define CPIA2_VC_VC_YLIM_LO 0xC9
-
-#define CPIA2_VC_VC_OHSIZE 0xCA
-
-#define CPIA2_VC_VC_OVSIZE 0xCB
-
-#define CPIA2_VC_VC_HCROP 0xCC
-
-#define CPIA2_VC_VC_VCROP 0xCD
-
-#define CPIA2_VC_VC_HPHASE 0xCE
-
-#define CPIA2_VC_VC_VPHASE 0xCF
-
-#define CPIA2_VC_VC_HISPAN 0xD0
-
-#define CPIA2_VC_VC_VISPAN 0xD1
-
-#define CPIA2_VC_VC_HICROP 0xD2
-
-#define CPIA2_VC_VC_VICROP 0xD3
-
-#define CPIA2_VC_VC_HFRACT 0xD4
-#define CPIA2_VC_VC_HFRACT_DEN_MASK 0x0F
-#define CPIA2_VC_VC_HFRACT_NUM_MASK 0xF0
-
-#define CPIA2_VC_VC_VFRACT 0xD5
-#define CPIA2_VC_VC_VFRACT_DEN_MASK 0x0F
-#define CPIA2_VC_VC_VFRACT_NUM_MASK 0xF0
-
-#define CPIA2_VC_VC_JPEG_OPT 0xD6
-#define CPIA2_VC_VC_JPEG_OPT_DOUBLE_SQUEEZE 0x01
-#define CPIA2_VC_VC_JPEG_OPT_NO_DC_AUTO_SQUEEZE 0x02
-#define CPIA2_VC_VC_JPEG_OPT_AUTO_SQUEEZE 0x04
-#define CPIA2_VC_VC_JPEG_OPT_DEFAULT (CPIA2_VC_VC_JPEG_OPT_DOUBLE_SQUEEZE|\
- CPIA2_VC_VC_JPEG_OPT_AUTO_SQUEEZE)
-
-
-#define CPIA2_VC_VC_CREEP_PERIOD 0xD7
-#define CPIA2_VC_VC_USER_SQUEEZE 0xD8
-#define CPIA2_VC_VC_TARGET_KB 0xD9
-
-#define CPIA2_VC_VC_AUTO_SQUEEZE 0xE6
-
-
-/***
- * VP register set (Bank 2)
- ***/
-#define CPIA2_VP_DEVICEH 0
-#define CPIA2_VP_DEVICEL 1
-
-#define CPIA2_VP_SYSTEMSTATE 0x02
-#define CPIA2_VP_SYSTEMSTATE_HK_ALIVE 0x01
-
-#define CPIA2_VP_SYSTEMCTRL 0x03
-#define CPIA2_VP_SYSTEMCTRL_REQ_CLEAR_ERROR 0x80
-#define CPIA2_VP_SYSTEMCTRL_POWER_DOWN_PLL 0x20
-#define CPIA2_VP_SYSTEMCTRL_REQ_SUSPEND_STATE 0x10
-#define CPIA2_VP_SYSTEMCTRL_REQ_SERIAL_WAKEUP 0x08
-#define CPIA2_VP_SYSTEMCTRL_REQ_AUTOLOAD 0x04
-#define CPIA2_VP_SYSTEMCTRL_HK_CONTROL 0x02
-#define CPIA2_VP_SYSTEMCTRL_POWER_CONTROL 0x01
-
-#define CPIA2_VP_SENSOR_FLAGS 0x05
-#define CPIA2_VP_SENSOR_FLAGS_404 0x01
-#define CPIA2_VP_SENSOR_FLAGS_407 0x02
-#define CPIA2_VP_SENSOR_FLAGS_409 0x04
-#define CPIA2_VP_SENSOR_FLAGS_410 0x08
-#define CPIA2_VP_SENSOR_FLAGS_500 0x10
-
-#define CPIA2_VP_SENSOR_REV 0x06
-
-#define CPIA2_VP_DEVICE_CONFIG 0x07
-#define CPIA2_VP_DEVICE_CONFIG_SERIAL_BRIDGE 0x01
-
-#define CPIA2_VP_GPIO_DIRECTION 0x08
-#define CPIA2_VP_GPIO_READ 0xFF
-#define CPIA2_VP_GPIO_WRITE 0x00
-
-#define CPIA2_VP_GPIO_DATA 0x09
-
-#define CPIA2_VP_RAM_ADDR_H 0x0A
-#define CPIA2_VP_RAM_ADDR_L 0x0B
-#define CPIA2_VP_RAM_DATA 0x0C
-
-#define CPIA2_VP_PATCH_REV 0x0F
-
-#define CPIA2_VP4_USER_MODE 0x10
-#define CPIA2_VP5_USER_MODE 0x13
-#define CPIA2_VP_USER_MODE_CIF 0x01
-#define CPIA2_VP_USER_MODE_QCIFDS 0x02
-#define CPIA2_VP_USER_MODE_QCIFPTC 0x04
-#define CPIA2_VP_USER_MODE_QVGADS 0x08
-#define CPIA2_VP_USER_MODE_QVGAPTC 0x10
-#define CPIA2_VP_USER_MODE_VGA 0x20
-
-#define CPIA2_VP4_FRAMERATE_REQUEST 0x11
-#define CPIA2_VP5_FRAMERATE_REQUEST 0x14
-#define CPIA2_VP_FRAMERATE_60 0x80
-#define CPIA2_VP_FRAMERATE_50 0x40
-#define CPIA2_VP_FRAMERATE_30 0x20
-#define CPIA2_VP_FRAMERATE_25 0x10
-#define CPIA2_VP_FRAMERATE_15 0x08
-#define CPIA2_VP_FRAMERATE_12_5 0x04
-#define CPIA2_VP_FRAMERATE_7_5 0x02
-#define CPIA2_VP_FRAMERATE_6_25 0x01
-
-#define CPIA2_VP4_USER_EFFECTS 0x12
-#define CPIA2_VP5_USER_EFFECTS 0x15
-#define CPIA2_VP_USER_EFFECTS_COLBARS 0x01
-#define CPIA2_VP_USER_EFFECTS_COLBARS_GRAD 0x02
-#define CPIA2_VP_USER_EFFECTS_MIRROR 0x04
-#define CPIA2_VP_USER_EFFECTS_FLIP 0x40 // VP5 only
-
-/* NOTE: CPIA2_VP_EXPOSURE_MODES shares the same register as VP5 User
- * Effects */
-#define CPIA2_VP_EXPOSURE_MODES 0x15
-#define CPIA2_VP_EXPOSURE_MODES_INHIBIT_FLICKER 0x20
-#define CPIA2_VP_EXPOSURE_MODES_COMPILE_EXP 0x10
-
-#define CPIA2_VP4_EXPOSURE_TARGET 0x16 // VP4
-#define CPIA2_VP5_EXPOSURE_TARGET 0x20 // VP5
-
-#define CPIA2_VP_FLICKER_MODES 0x1B
-#define CPIA2_VP_FLICKER_MODES_50HZ 0x80
-#define CPIA2_VP_FLICKER_MODES_CUSTOM_FLT_FFREQ 0x40
-#define CPIA2_VP_FLICKER_MODES_NEVER_FLICKER 0x20
-#define CPIA2_VP_FLICKER_MODES_INHIBIT_RUB 0x10
-#define CPIA2_VP_FLICKER_MODES_ADJUST_LINE_FREQ 0x08
-#define CPIA2_VP_FLICKER_MODES_CUSTOM_INT_FFREQ 0x04
-
-#define CPIA2_VP_UMISC 0x1D
-#define CPIA2_VP_UMISC_FORCE_MONO 0x80
-#define CPIA2_VP_UMISC_FORCE_ID_MASK 0x40
-#define CPIA2_VP_UMISC_INHIBIT_AUTO_FGS 0x20
-#define CPIA2_VP_UMISC_INHIBIT_AUTO_DIMS 0x08
-#define CPIA2_VP_UMISC_OPT_FOR_SENSOR_DS 0x04
-#define CPIA2_VP_UMISC_INHIBIT_AUTO_MODE_INT 0x02
-
-#define CPIA2_VP5_ANTIFLKRSETUP 0x22 //34
-
-#define CPIA2_VP_INTERPOLATION 0x24
-#define CPIA2_VP_INTERPOLATION_EVEN_FIRST 0x40
-#define CPIA2_VP_INTERPOLATION_HJOG 0x20
-#define CPIA2_VP_INTERPOLATION_VJOG 0x10
-
-#define CPIA2_VP_GAMMA 0x25
-#define CPIA2_VP_DEFAULT_GAMMA 0x10
-
-#define CPIA2_VP_YRANGE 0x26
-
-#define CPIA2_VP_SATURATION 0x27
-
-#define CPIA2_VP5_MYBLACK_LEVEL 0x3A //58
-#define CPIA2_VP5_MCYRANGE 0x3B //59
-#define CPIA2_VP5_MYCEILING 0x3C //60
-#define CPIA2_VP5_MCUVSATURATION 0x3D //61
-
-
-#define CPIA2_VP_REHASH_VALUES 0x60
-
-
-/***
- * Common sensor registers
- ***/
-#define CPIA2_SENSOR_DEVICE_H 0x00
-#define CPIA2_SENSOR_DEVICE_L 0x01
-
-#define CPIA2_SENSOR_DATA_FORMAT 0x16
-#define CPIA2_SENSOR_DATA_FORMAT_HMIRROR 0x08
-#define CPIA2_SENSOR_DATA_FORMAT_VMIRROR 0x10
-
-#define CPIA2_SENSOR_CR1 0x76
-#define CPIA2_SENSOR_CR1_STAND_BY 0x01
-#define CPIA2_SENSOR_CR1_DOWN_RAMP_GEN 0x02
-#define CPIA2_SENSOR_CR1_DOWN_COLUMN_ADC 0x04
-#define CPIA2_SENSOR_CR1_DOWN_CAB_REGULATOR 0x08
-#define CPIA2_SENSOR_CR1_DOWN_AUDIO_REGULATOR 0x10
-#define CPIA2_SENSOR_CR1_DOWN_VRT_AMP 0x20
-#define CPIA2_SENSOR_CR1_DOWN_BAND_GAP 0x40
-
-#endif
diff --git a/drivers/staging/media/deprecated/cpia2/cpia2_usb.c b/drivers/staging/media/deprecated/cpia2/cpia2_usb.c
deleted file mode 100644
index cba03b286473..000000000000
--- a/drivers/staging/media/deprecated/cpia2/cpia2_usb.c
+++ /dev/null
@@ -1,966 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/****************************************************************************
- *
- * Filename: cpia2_usb.c
- *
- * Copyright 2001, STMicrolectronics, Inc.
- * Contact: steve.miller@st.com
- *
- * Description:
- * This is a USB driver for CPia2 based video cameras.
- * The infrastructure of this driver is based on the cpia usb driver by
- * Jochen Scharrlach and Johannes Erdfeldt.
- *
- * Stripped of 2.4 stuff ready for main kernel submit by
- * Alan Cox <alan@lxorguk.ukuu.org.uk>
- ****************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include <linux/module.h>
-
-#include "cpia2.h"
-
-static int frame_sizes[] = {
- 0, // USBIF_CMDONLY
- 0, // USBIF_BULK
- 128, // USBIF_ISO_1
- 384, // USBIF_ISO_2
- 640, // USBIF_ISO_3
- 768, // USBIF_ISO_4
- 896, // USBIF_ISO_5
- 1023, // USBIF_ISO_6
-};
-
-#define FRAMES_PER_DESC 10
-#define FRAME_SIZE_PER_DESC frame_sizes[cam->cur_alt]
-
-static void process_frame(struct camera_data *cam);
-static void cpia2_usb_complete(struct urb *urb);
-static int cpia2_usb_probe(struct usb_interface *intf,
- const struct usb_device_id *id);
-static void cpia2_usb_disconnect(struct usb_interface *intf);
-static int cpia2_usb_suspend(struct usb_interface *intf, pm_message_t message);
-static int cpia2_usb_resume(struct usb_interface *intf);
-
-static void free_sbufs(struct camera_data *cam);
-static void add_APPn(struct camera_data *cam);
-static void add_COM(struct camera_data *cam);
-static int submit_urbs(struct camera_data *cam);
-static int set_alternate(struct camera_data *cam, unsigned int alt);
-static int configure_transfer_mode(struct camera_data *cam, unsigned int alt);
-
-static const struct usb_device_id cpia2_id_table[] = {
- {USB_DEVICE(0x0553, 0x0100)},
- {USB_DEVICE(0x0553, 0x0140)},
- {USB_DEVICE(0x0553, 0x0151)}, /* STV0676 */
- {} /* Terminating entry */
-};
-MODULE_DEVICE_TABLE(usb, cpia2_id_table);
-
-static struct usb_driver cpia2_driver = {
- .name = "cpia2",
- .probe = cpia2_usb_probe,
- .disconnect = cpia2_usb_disconnect,
- .suspend = cpia2_usb_suspend,
- .resume = cpia2_usb_resume,
- .reset_resume = cpia2_usb_resume,
- .id_table = cpia2_id_table
-};
-
-
-/******************************************************************************
- *
- * process_frame
- *
- *****************************************************************************/
-static void process_frame(struct camera_data *cam)
-{
- static int frame_count;
-
- unsigned char *inbuff = cam->workbuff->data;
-
- DBG("Processing frame #%d, current:%d\n",
- cam->workbuff->num, cam->curbuff->num);
-
- if(cam->workbuff->length > cam->workbuff->max_length)
- cam->workbuff->max_length = cam->workbuff->length;
-
- if ((inbuff[0] == 0xFF) && (inbuff[1] == 0xD8)) {
- frame_count++;
- } else {
- cam->workbuff->status = FRAME_ERROR;
- DBG("Start of frame not found\n");
- return;
- }
-
- /***
- * Now the output buffer should have a JPEG image in it.
- ***/
- if(!cam->first_image_seen) {
- /* Always skip the first image after streaming
- * starts. It is almost certainly corrupt. */
- cam->first_image_seen = 1;
- cam->workbuff->status = FRAME_EMPTY;
- return;
- }
- if (cam->workbuff->length > 3) {
- if(cam->mmapped &&
- cam->workbuff->length < cam->workbuff->max_length) {
- /* No junk in the buffers */
- memset(cam->workbuff->data+cam->workbuff->length,
- 0, cam->workbuff->max_length-
- cam->workbuff->length);
- }
- cam->workbuff->max_length = cam->workbuff->length;
- cam->workbuff->status = FRAME_READY;
-
- if(!cam->mmapped && cam->num_frames > 2) {
- /* During normal reading, the most recent
- * frame will be read. If the current frame
- * hasn't started reading yet, it will never
- * be read, so mark it empty. If the buffer is
- * mmapped, or we have few buffers, we need to
- * wait for the user to free the buffer.
- *
- * NOTE: This is not entirely foolproof with 3
- * buffers, but it would take an EXTREMELY
- * overloaded system to cause problems (possible
- * image data corruption). Basically, it would
- * need to take more time to execute cpia2_read
- * than it would for the camera to send
- * cam->num_frames-2 frames before problems
- * could occur.
- */
- cam->curbuff->status = FRAME_EMPTY;
- }
- cam->curbuff = cam->workbuff;
- cam->workbuff = cam->workbuff->next;
- DBG("Changed buffers, work:%d, current:%d\n",
- cam->workbuff->num, cam->curbuff->num);
- return;
- } else {
- DBG("Not enough data for an image.\n");
- }
-
- cam->workbuff->status = FRAME_ERROR;
- return;
-}
-
-/******************************************************************************
- *
- * add_APPn
- *
- * Adds a user specified APPn record
- *****************************************************************************/
-static void add_APPn(struct camera_data *cam)
-{
- if(cam->APP_len > 0) {
- cam->workbuff->data[cam->workbuff->length++] = 0xFF;
- cam->workbuff->data[cam->workbuff->length++] = 0xE0+cam->APPn;
- cam->workbuff->data[cam->workbuff->length++] = 0;
- cam->workbuff->data[cam->workbuff->length++] = cam->APP_len+2;
- memcpy(cam->workbuff->data+cam->workbuff->length,
- cam->APP_data, cam->APP_len);
- cam->workbuff->length += cam->APP_len;
- }
-}
-
-/******************************************************************************
- *
- * add_COM
- *
- * Adds a user specified COM record
- *****************************************************************************/
-static void add_COM(struct camera_data *cam)
-{
- if(cam->COM_len > 0) {
- cam->workbuff->data[cam->workbuff->length++] = 0xFF;
- cam->workbuff->data[cam->workbuff->length++] = 0xFE;
- cam->workbuff->data[cam->workbuff->length++] = 0;
- cam->workbuff->data[cam->workbuff->length++] = cam->COM_len+2;
- memcpy(cam->workbuff->data+cam->workbuff->length,
- cam->COM_data, cam->COM_len);
- cam->workbuff->length += cam->COM_len;
- }
-}
-
-/******************************************************************************
- *
- * cpia2_usb_complete
- *
- * callback when incoming packet is received
- *****************************************************************************/
-static void cpia2_usb_complete(struct urb *urb)
-{
- int i;
- unsigned char *cdata;
- static bool frame_ready = false;
- struct camera_data *cam = (struct camera_data *) urb->context;
-
- if (urb->status!=0) {
- if (!(urb->status == -ENOENT ||
- urb->status == -ECONNRESET ||
- urb->status == -ESHUTDOWN))
- {
- DBG("urb->status = %d!\n", urb->status);
- }
- DBG("Stopping streaming\n");
- return;
- }
-
- if (!cam->streaming || !video_is_registered(&cam->vdev)) {
- LOG("Will now stop the streaming: streaming = %d, present=%d\n",
- cam->streaming, video_is_registered(&cam->vdev));
- return;
- }
-
- /***
- * Packet collater
- ***/
- //DBG("Collating %d packets\n", urb->number_of_packets);
- for (i = 0; i < urb->number_of_packets; i++) {
- u16 checksum, iso_checksum;
- int j;
- int n = urb->iso_frame_desc[i].actual_length;
- int st = urb->iso_frame_desc[i].status;
-
- if(cam->workbuff->status == FRAME_READY) {
- struct framebuf *ptr;
- /* Try to find an available buffer */
- DBG("workbuff full, searching\n");
- for (ptr = cam->workbuff->next;
- ptr != cam->workbuff;
- ptr = ptr->next)
- {
- if (ptr->status == FRAME_EMPTY) {
- ptr->status = FRAME_READING;
- ptr->length = 0;
- break;
- }
- }
- if (ptr == cam->workbuff)
- break; /* No READING or EMPTY buffers left */
-
- cam->workbuff = ptr;
- }
-
- if (cam->workbuff->status == FRAME_EMPTY ||
- cam->workbuff->status == FRAME_ERROR) {
- cam->workbuff->status = FRAME_READING;
- cam->workbuff->length = 0;
- }
-
- //DBG(" Packet %d length = %d, status = %d\n", i, n, st);
- cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
-
- if (st) {
- LOG("cpia2 data error: [%d] len=%d, status = %d\n",
- i, n, st);
- if(!ALLOW_CORRUPT)
- cam->workbuff->status = FRAME_ERROR;
- continue;
- }
-
- if(n<=2)
- continue;
-
- checksum = 0;
- for(j=0; j<n-2; ++j)
- checksum += cdata[j];
- iso_checksum = cdata[j] + cdata[j+1]*256;
- if(checksum != iso_checksum) {
- LOG("checksum mismatch: [%d] len=%d, calculated = %x, checksum = %x\n",
- i, n, (int)checksum, (int)iso_checksum);
- if(!ALLOW_CORRUPT) {
- cam->workbuff->status = FRAME_ERROR;
- continue;
- }
- }
- n -= 2;
-
- if(cam->workbuff->status != FRAME_READING) {
- if((0xFF == cdata[0] && 0xD8 == cdata[1]) ||
- (0xD8 == cdata[0] && 0xFF == cdata[1] &&
- 0 != cdata[2])) {
- /* frame is skipped, but increment total
- * frame count anyway */
- cam->frame_count++;
- }
- DBG("workbuff not reading, status=%d\n",
- cam->workbuff->status);
- continue;
- }
-
- if (cam->frame_size < cam->workbuff->length + n) {
- ERR("buffer overflow! length: %d, n: %d\n",
- cam->workbuff->length, n);
- cam->workbuff->status = FRAME_ERROR;
- if(cam->workbuff->length > cam->workbuff->max_length)
- cam->workbuff->max_length =
- cam->workbuff->length;
- continue;
- }
-
- if (cam->workbuff->length == 0) {
- int data_offset;
- if ((0xD8 == cdata[0]) && (0xFF == cdata[1])) {
- data_offset = 1;
- } else if((0xFF == cdata[0]) && (0xD8 == cdata[1])
- && (0xFF == cdata[2])) {
- data_offset = 2;
- } else {
- DBG("Ignoring packet, not beginning!\n");
- continue;
- }
- DBG("Start of frame pattern found\n");
- cam->workbuff->ts = ktime_get_ns();
- cam->workbuff->seq = cam->frame_count++;
- cam->workbuff->data[0] = 0xFF;
- cam->workbuff->data[1] = 0xD8;
- cam->workbuff->length = 2;
- add_APPn(cam);
- add_COM(cam);
- memcpy(cam->workbuff->data+cam->workbuff->length,
- cdata+data_offset, n-data_offset);
- cam->workbuff->length += n-data_offset;
- } else if (cam->workbuff->length > 0) {
- memcpy(cam->workbuff->data + cam->workbuff->length,
- cdata, n);
- cam->workbuff->length += n;
- }
-
- if ((cam->workbuff->length >= 3) &&
- (cam->workbuff->data[cam->workbuff->length - 3] == 0xFF) &&
- (cam->workbuff->data[cam->workbuff->length - 2] == 0xD9) &&
- (cam->workbuff->data[cam->workbuff->length - 1] == 0xFF)) {
- frame_ready = true;
- cam->workbuff->data[cam->workbuff->length - 1] = 0;
- cam->workbuff->length -= 1;
- } else if ((cam->workbuff->length >= 2) &&
- (cam->workbuff->data[cam->workbuff->length - 2] == 0xFF) &&
- (cam->workbuff->data[cam->workbuff->length - 1] == 0xD9)) {
- frame_ready = true;
- }
-
- if (frame_ready) {
- DBG("Workbuff image size = %d\n",cam->workbuff->length);
- process_frame(cam);
-
- frame_ready = false;
-
- if (waitqueue_active(&cam->wq_stream))
- wake_up_interruptible(&cam->wq_stream);
- }
- }
-
- if(cam->streaming) {
- /* resubmit */
- urb->dev = cam->dev;
- if ((i = usb_submit_urb(urb, GFP_ATOMIC)) != 0)
- ERR("%s: usb_submit_urb ret %d!\n", __func__, i);
- }
-}
-
-/******************************************************************************
- *
- * configure_transfer_mode
- *
- *****************************************************************************/
-static int configure_transfer_mode(struct camera_data *cam, unsigned int alt)
-{
- static unsigned char iso_regs[8][4] = {
- {0x00, 0x00, 0x00, 0x00},
- {0x00, 0x00, 0x00, 0x00},
- {0xB9, 0x00, 0x00, 0x7E},
- {0xB9, 0x00, 0x01, 0x7E},
- {0xB9, 0x00, 0x02, 0x7E},
- {0xB9, 0x00, 0x02, 0xFE},
- {0xB9, 0x00, 0x03, 0x7E},
- {0xB9, 0x00, 0x03, 0xFD}
- };
- struct cpia2_command cmd;
- unsigned char reg;
-
- if (!video_is_registered(&cam->vdev))
- return -ENODEV;
-
- /***
- * Write the isoc registers according to the alternate selected
- ***/
- cmd.direction = TRANSFER_WRITE;
- cmd.buffer.block_data[0] = iso_regs[alt][0];
- cmd.buffer.block_data[1] = iso_regs[alt][1];
- cmd.buffer.block_data[2] = iso_regs[alt][2];
- cmd.buffer.block_data[3] = iso_regs[alt][3];
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
- cmd.start = CPIA2_VC_USB_ISOLIM;
- cmd.reg_count = 4;
- cpia2_send_command(cam, &cmd);
-
- /***
- * Enable relevant streams before starting polling.
- * First read USB Stream Config Register.
- ***/
- cmd.direction = TRANSFER_READ;
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
- cmd.start = CPIA2_VC_USB_STRM;
- cmd.reg_count = 1;
- cpia2_send_command(cam, &cmd);
- reg = cmd.buffer.block_data[0];
-
- /* Clear iso, bulk, and int */
- reg &= ~(CPIA2_VC_USB_STRM_BLK_ENABLE |
- CPIA2_VC_USB_STRM_ISO_ENABLE |
- CPIA2_VC_USB_STRM_INT_ENABLE);
-
- if (alt == USBIF_BULK) {
- DBG("Enabling bulk xfer\n");
- reg |= CPIA2_VC_USB_STRM_BLK_ENABLE; /* Enable Bulk */
- cam->xfer_mode = XFER_BULK;
- } else if (alt >= USBIF_ISO_1) {
- DBG("Enabling ISOC xfer\n");
- reg |= CPIA2_VC_USB_STRM_ISO_ENABLE;
- cam->xfer_mode = XFER_ISOC;
- }
-
- cmd.buffer.block_data[0] = reg;
- cmd.direction = TRANSFER_WRITE;
- cmd.start = CPIA2_VC_USB_STRM;
- cmd.reg_count = 1;
- cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC;
- cpia2_send_command(cam, &cmd);
-
- return 0;
-}
-
-/******************************************************************************
- *
- * cpia2_usb_change_streaming_alternate
- *
- *****************************************************************************/
-int cpia2_usb_change_streaming_alternate(struct camera_data *cam,
- unsigned int alt)
-{
- int ret = 0;
-
- if(alt < USBIF_ISO_1 || alt > USBIF_ISO_6)
- return -EINVAL;
-
- if(alt == cam->params.camera_state.stream_mode)
- return 0;
-
- cpia2_usb_stream_pause(cam);
-
- configure_transfer_mode(cam, alt);
-
- cam->params.camera_state.stream_mode = alt;
-
- /* Reset the camera to prevent image quality degradation */
- cpia2_reset_camera(cam);
-
- cpia2_usb_stream_resume(cam);
-
- return ret;
-}
-
-/******************************************************************************
- *
- * set_alternate
- *
- *****************************************************************************/
-static int set_alternate(struct camera_data *cam, unsigned int alt)
-{
- int ret = 0;
-
- if(alt == cam->cur_alt)
- return 0;
-
- if (cam->cur_alt != USBIF_CMDONLY) {
- DBG("Changing from alt %d to %d\n", cam->cur_alt, USBIF_CMDONLY);
- ret = usb_set_interface(cam->dev, cam->iface, USBIF_CMDONLY);
- if (ret != 0)
- return ret;
- }
- if (alt != USBIF_CMDONLY) {
- DBG("Changing from alt %d to %d\n", USBIF_CMDONLY, alt);
- ret = usb_set_interface(cam->dev, cam->iface, alt);
- if (ret != 0)
- return ret;
- }
-
- cam->old_alt = cam->cur_alt;
- cam->cur_alt = alt;
-
- return ret;
-}
-
-/******************************************************************************
- *
- * free_sbufs
- *
- * Free all cam->sbuf[]. All non-NULL .data and .urb members that are non-NULL
- * are assumed to be allocated. Non-NULL .urb members are also assumed to be
- * submitted (and must therefore be killed before they are freed).
- *****************************************************************************/
-static void free_sbufs(struct camera_data *cam)
-{
- int i;
-
- for (i = 0; i < NUM_SBUF; i++) {
- if(cam->sbuf[i].urb) {
- usb_kill_urb(cam->sbuf[i].urb);
- usb_free_urb(cam->sbuf[i].urb);
- cam->sbuf[i].urb = NULL;
- }
- if(cam->sbuf[i].data) {
- kfree(cam->sbuf[i].data);
- cam->sbuf[i].data = NULL;
- }
- }
-}
-
-/*******
-* Convenience functions
-*******/
-/****************************************************************************
- *
- * write_packet
- *
- ***************************************************************************/
-static int write_packet(struct usb_device *udev,
- u8 request, u8 * registers, u16 start, size_t size)
-{
- unsigned char *buf;
- int ret;
-
- if (!registers || size <= 0)
- return -EINVAL;
-
- buf = kmemdup(registers, size, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- ret = usb_control_msg(udev,
- usb_sndctrlpipe(udev, 0),
- request,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- start, /* value */
- 0, /* index */
- buf, /* buffer */
- size,
- 1000);
-
- kfree(buf);
- return ret;
-}
-
-/****************************************************************************
- *
- * read_packet
- *
- ***************************************************************************/
-static int read_packet(struct usb_device *udev,
- u8 request, u8 * registers, u16 start, size_t size)
-{
- unsigned char *buf;
- int ret;
-
- if (!registers || size <= 0)
- return -EINVAL;
-
- buf = kmalloc(size, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- ret = usb_control_msg(udev,
- usb_rcvctrlpipe(udev, 0),
- request,
- USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_DEVICE,
- start, /* value */
- 0, /* index */
- buf, /* buffer */
- size,
- 1000);
-
- if (ret >= 0)
- memcpy(registers, buf, size);
-
- kfree(buf);
-
- return ret;
-}
-
-/******************************************************************************
- *
- * cpia2_usb_transfer_cmd
- *
- *****************************************************************************/
-int cpia2_usb_transfer_cmd(struct camera_data *cam,
- void *registers,
- u8 request, u8 start, u8 count, u8 direction)
-{
- int err = 0;
- struct usb_device *udev = cam->dev;
-
- if (!udev) {
- ERR("%s: Internal driver error: udev is NULL\n", __func__);
- return -EINVAL;
- }
-
- if (!registers) {
- ERR("%s: Internal driver error: register array is NULL\n", __func__);
- return -EINVAL;
- }
-
- if (direction == TRANSFER_READ) {
- err = read_packet(udev, request, (u8 *)registers, start, count);
- if (err > 0)
- err = 0;
- } else if (direction == TRANSFER_WRITE) {
- err =write_packet(udev, request, (u8 *)registers, start, count);
- if (err < 0) {
- LOG("Control message failed, err val = %d\n", err);
- LOG("Message: request = 0x%0X, start = 0x%0X\n",
- request, start);
- LOG("Message: count = %d, register[0] = 0x%0X\n",
- count, ((unsigned char *) registers)[0]);
- } else
- err=0;
- } else {
- LOG("Unexpected first byte of direction: %d\n",
- direction);
- return -EINVAL;
- }
-
- if(err != 0)
- LOG("Unexpected error: %d\n", err);
- return err;
-}
-
-
-/******************************************************************************
- *
- * submit_urbs
- *
- *****************************************************************************/
-static int submit_urbs(struct camera_data *cam)
-{
- struct urb *urb;
- int fx, err, i, j;
-
- for(i=0; i<NUM_SBUF; ++i) {
- if (cam->sbuf[i].data)
- continue;
- cam->sbuf[i].data =
- kmalloc_array(FRAME_SIZE_PER_DESC, FRAMES_PER_DESC,
- GFP_KERNEL);
- if (!cam->sbuf[i].data) {
- while (--i >= 0) {
- kfree(cam->sbuf[i].data);
- cam->sbuf[i].data = NULL;
- }
- return -ENOMEM;
- }
- }
-
- /* We double buffer the Isoc lists, and also know the polling
- * interval is every frame (1 == (1 << (bInterval -1))).
- */
- for(i=0; i<NUM_SBUF; ++i) {
- if(cam->sbuf[i].urb) {
- continue;
- }
- urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
- if (!urb) {
- for (j = 0; j < i; j++)
- usb_free_urb(cam->sbuf[j].urb);
- for (j = 0; j < NUM_SBUF; j++) {
- kfree(cam->sbuf[j].data);
- cam->sbuf[j].data = NULL;
- }
- return -ENOMEM;
- }
-
- cam->sbuf[i].urb = urb;
- urb->dev = cam->dev;
- urb->context = cam;
- urb->pipe = usb_rcvisocpipe(cam->dev, 1 /*ISOC endpoint*/);
- urb->transfer_flags = URB_ISO_ASAP;
- urb->transfer_buffer = cam->sbuf[i].data;
- urb->complete = cpia2_usb_complete;
- urb->number_of_packets = FRAMES_PER_DESC;
- urb->interval = 1;
- urb->transfer_buffer_length =
- FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
-
- for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
- urb->iso_frame_desc[fx].offset =
- FRAME_SIZE_PER_DESC * fx;
- urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
- }
- }
-
-
- /* Queue the ISO urbs, and resubmit in the completion handler */
- for(i=0; i<NUM_SBUF; ++i) {
- err = usb_submit_urb(cam->sbuf[i].urb, GFP_KERNEL);
- if (err) {
- ERR("usb_submit_urb[%d]() = %d\n", i, err);
- return err;
- }
- }
-
- return 0;
-}
-
-/******************************************************************************
- *
- * cpia2_usb_stream_start
- *
- *****************************************************************************/
-int cpia2_usb_stream_start(struct camera_data *cam, unsigned int alternate)
-{
- int ret;
- int old_alt;
-
- if(cam->streaming)
- return 0;
-
- if (cam->flush) {
- int i;
- DBG("Flushing buffers\n");
- for(i=0; i<cam->num_frames; ++i) {
- cam->buffers[i].status = FRAME_EMPTY;
- cam->buffers[i].length = 0;
- }
- cam->curbuff = &cam->buffers[0];
- cam->workbuff = cam->curbuff->next;
- cam->flush = false;
- }
-
- old_alt = cam->params.camera_state.stream_mode;
- cam->params.camera_state.stream_mode = 0;
- ret = cpia2_usb_change_streaming_alternate(cam, alternate);
- if (ret < 0) {
- int ret2;
- ERR("cpia2_usb_change_streaming_alternate() = %d!\n", ret);
- cam->params.camera_state.stream_mode = old_alt;
- ret2 = set_alternate(cam, USBIF_CMDONLY);
- if (ret2 < 0) {
- ERR("cpia2_usb_change_streaming_alternate(%d) =%d has already failed. Then tried to call set_alternate(USBIF_CMDONLY) = %d.\n",
- alternate, ret, ret2);
- }
- } else {
- cam->frame_count = 0;
- cam->streaming = 1;
- ret = cpia2_usb_stream_resume(cam);
- }
- return ret;
-}
-
-/******************************************************************************
- *
- * cpia2_usb_stream_pause
- *
- *****************************************************************************/
-int cpia2_usb_stream_pause(struct camera_data *cam)
-{
- int ret = 0;
- if(cam->streaming) {
- free_sbufs(cam);
- ret = set_alternate(cam, USBIF_CMDONLY);
- }
- return ret;
-}
-
-/******************************************************************************
- *
- * cpia2_usb_stream_resume
- *
- *****************************************************************************/
-int cpia2_usb_stream_resume(struct camera_data *cam)
-{
- int ret = 0;
- if(cam->streaming) {
- cam->first_image_seen = 0;
- ret = set_alternate(cam, cam->params.camera_state.stream_mode);
- if(ret == 0) {
- /* for some reason the user effects need to be set
- again when starting streaming. */
- cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE,
- cam->params.vp_params.user_effects);
- ret = submit_urbs(cam);
- }
- }
- return ret;
-}
-
-/******************************************************************************
- *
- * cpia2_usb_stream_stop
- *
- *****************************************************************************/
-int cpia2_usb_stream_stop(struct camera_data *cam)
-{
- int ret;
-
- ret = cpia2_usb_stream_pause(cam);
- cam->streaming = 0;
- configure_transfer_mode(cam, 0);
- return ret;
-}
-
-/******************************************************************************
- *
- * cpia2_usb_probe
- *
- * Probe and initialize.
- *****************************************************************************/
-static int cpia2_usb_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- struct usb_device *udev = interface_to_usbdev(intf);
- struct usb_interface_descriptor *interface;
- struct camera_data *cam;
- int ret;
-
- /* A multi-config CPiA2 camera? */
- if (udev->descriptor.bNumConfigurations != 1)
- return -ENODEV;
- interface = &intf->cur_altsetting->desc;
-
- /* If we get to this point, we found a CPiA2 camera */
- LOG("CPiA2 USB camera found\n");
-
- cam = cpia2_init_camera_struct(intf);
- if (cam == NULL)
- return -ENOMEM;
-
- cam->dev = udev;
- cam->iface = interface->bInterfaceNumber;
-
- ret = set_alternate(cam, USBIF_CMDONLY);
- if (ret < 0) {
- ERR("%s: usb_set_interface error (ret = %d)\n", __func__, ret);
- goto alt_err;
- }
-
-
- if((ret = cpia2_init_camera(cam)) < 0) {
- ERR("%s: failed to initialize cpia2 camera (ret = %d)\n", __func__, ret);
- goto alt_err;
- }
- LOG(" CPiA Version: %d.%02d (%d.%d)\n",
- cam->params.version.firmware_revision_hi,
- cam->params.version.firmware_revision_lo,
- cam->params.version.asic_id,
- cam->params.version.asic_rev);
- LOG(" CPiA PnP-ID: %04x:%04x:%04x\n",
- cam->params.pnp_id.vendor,
- cam->params.pnp_id.product,
- cam->params.pnp_id.device_revision);
- LOG(" SensorID: %d.(version %d)\n",
- cam->params.version.sensor_flags,
- cam->params.version.sensor_rev);
-
- usb_set_intfdata(intf, cam);
-
- ret = cpia2_register_camera(cam);
- if (ret < 0) {
- ERR("%s: Failed to register cpia2 camera (ret = %d)\n", __func__, ret);
- goto alt_err;
- }
-
- return 0;
-
-alt_err:
- cpia2_deinit_camera_struct(cam, intf);
- return ret;
-}
-
-/******************************************************************************
- *
- * cpia2_disconnect
- *
- *****************************************************************************/
-static void cpia2_usb_disconnect(struct usb_interface *intf)
-{
- struct camera_data *cam = usb_get_intfdata(intf);
- usb_set_intfdata(intf, NULL);
-
- DBG("Stopping stream\n");
- cpia2_usb_stream_stop(cam);
-
- mutex_lock(&cam->v4l2_lock);
- DBG("Unregistering camera\n");
- cpia2_unregister_camera(cam);
- v4l2_device_disconnect(&cam->v4l2_dev);
- mutex_unlock(&cam->v4l2_lock);
-
- if(cam->buffers) {
- DBG("Wakeup waiting processes\n");
- cam->curbuff->status = FRAME_READY;
- cam->curbuff->length = 0;
- wake_up_interruptible(&cam->wq_stream);
- }
-
- v4l2_device_put(&cam->v4l2_dev);
-
- LOG("CPiA2 camera disconnected.\n");
-}
-
-static int cpia2_usb_suspend(struct usb_interface *intf, pm_message_t message)
-{
- struct camera_data *cam = usb_get_intfdata(intf);
-
- mutex_lock(&cam->v4l2_lock);
- if (cam->streaming) {
- cpia2_usb_stream_stop(cam);
- cam->streaming = 1;
- }
- mutex_unlock(&cam->v4l2_lock);
-
- dev_info(&intf->dev, "going into suspend..\n");
- return 0;
-}
-
-/* Resume device - start device. */
-static int cpia2_usb_resume(struct usb_interface *intf)
-{
- struct camera_data *cam = usb_get_intfdata(intf);
-
- mutex_lock(&cam->v4l2_lock);
- v4l2_ctrl_handler_setup(&cam->hdl);
- if (cam->streaming) {
- cam->streaming = 0;
- cpia2_usb_stream_start(cam,
- cam->params.camera_state.stream_mode);
- }
- mutex_unlock(&cam->v4l2_lock);
-
- dev_info(&intf->dev, "coming out of suspend..\n");
- return 0;
-}
-
-/******************************************************************************
- *
- * usb_cpia2_init
- *
- *****************************************************************************/
-int cpia2_usb_init(void)
-{
- return usb_register(&cpia2_driver);
-}
-
-/******************************************************************************
- *
- * usb_cpia_cleanup
- *
- *****************************************************************************/
-void cpia2_usb_cleanup(void)
-{
- schedule_timeout(2 * HZ);
- usb_deregister(&cpia2_driver);
-}
diff --git a/drivers/staging/media/deprecated/cpia2/cpia2_v4l.c b/drivers/staging/media/deprecated/cpia2/cpia2_v4l.c
deleted file mode 100644
index 926ecfc9b64a..000000000000
--- a/drivers/staging/media/deprecated/cpia2/cpia2_v4l.c
+++ /dev/null
@@ -1,1226 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/****************************************************************************
- *
- * Filename: cpia2_v4l.c
- *
- * Copyright 2001, STMicrolectronics, Inc.
- * Contact: steve.miller@st.com
- * Copyright 2001,2005, Scott J. Bertin <scottbertin@yahoo.com>
- *
- * Description:
- * This is a USB driver for CPia2 based video cameras.
- * The infrastructure of this driver is based on the cpia usb driver by
- * Jochen Scharrlach and Johannes Erdfeldt.
- *
- * Stripped of 2.4 stuff ready for main kernel submit by
- * Alan Cox <alan@lxorguk.ukuu.org.uk>
- ****************************************************************************/
-
-#define CPIA_VERSION "3.0.1"
-
-#include <linux/module.h>
-#include <linux/time.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/videodev2.h>
-#include <linux/stringify.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-event.h>
-
-#include "cpia2.h"
-
-static int video_nr = -1;
-module_param(video_nr, int, 0);
-MODULE_PARM_DESC(video_nr, "video device to register (0=/dev/video0, etc)");
-
-static int buffer_size = 68 * 1024;
-module_param(buffer_size, int, 0);
-MODULE_PARM_DESC(buffer_size, "Size for each frame buffer in bytes (default 68k)");
-
-static int num_buffers = 3;
-module_param(num_buffers, int, 0);
-MODULE_PARM_DESC(num_buffers, "Number of frame buffers (1-"
- __stringify(VIDEO_MAX_FRAME) ", default 3)");
-
-static int alternate = DEFAULT_ALT;
-module_param(alternate, int, 0);
-MODULE_PARM_DESC(alternate, "USB Alternate (" __stringify(USBIF_ISO_1) "-"
- __stringify(USBIF_ISO_6) ", default "
- __stringify(DEFAULT_ALT) ")");
-
-static int flicker_mode;
-module_param(flicker_mode, int, 0);
-MODULE_PARM_DESC(flicker_mode, "Flicker frequency (0 (disabled), " __stringify(50) " or "
- __stringify(60) ", default 0)");
-
-MODULE_AUTHOR("Steve Miller (STMicroelectronics) <steve.miller@st.com>");
-MODULE_DESCRIPTION("V4L-driver for STMicroelectronics CPiA2 based cameras");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(CPIA_VERSION);
-
-#define ABOUT "V4L-Driver for Vision CPiA2 based cameras"
-#define CPIA2_CID_USB_ALT (V4L2_CID_USER_BASE | 0xf000)
-
-/******************************************************************************
- *
- * cpia2_open
- *
- *****************************************************************************/
-static int cpia2_open(struct file *file)
-{
- struct camera_data *cam = video_drvdata(file);
- int retval;
-
- if (mutex_lock_interruptible(&cam->v4l2_lock))
- return -ERESTARTSYS;
- retval = v4l2_fh_open(file);
- if (retval)
- goto open_unlock;
-
- if (v4l2_fh_is_singular_file(file)) {
- if (cpia2_allocate_buffers(cam)) {
- v4l2_fh_release(file);
- retval = -ENOMEM;
- goto open_unlock;
- }
-
- /* reset the camera */
- if (cpia2_reset_camera(cam) < 0) {
- v4l2_fh_release(file);
- retval = -EIO;
- goto open_unlock;
- }
-
- cam->APP_len = 0;
- cam->COM_len = 0;
- }
-
- cpia2_dbg_dump_registers(cam);
-open_unlock:
- mutex_unlock(&cam->v4l2_lock);
- return retval;
-}
-
-/******************************************************************************
- *
- * cpia2_close
- *
- *****************************************************************************/
-static int cpia2_close(struct file *file)
-{
- struct video_device *dev = video_devdata(file);
- struct camera_data *cam = video_get_drvdata(dev);
-
- mutex_lock(&cam->v4l2_lock);
- if (video_is_registered(&cam->vdev) && v4l2_fh_is_singular_file(file)) {
- cpia2_usb_stream_stop(cam);
-
- /* save camera state for later open */
- cpia2_save_camera_state(cam);
-
- cpia2_set_low_power(cam);
- cpia2_free_buffers(cam);
- }
-
- if (cam->stream_fh == file->private_data) {
- cam->stream_fh = NULL;
- cam->mmapped = 0;
- }
- mutex_unlock(&cam->v4l2_lock);
- return v4l2_fh_release(file);
-}
-
-/******************************************************************************
- *
- * cpia2_v4l_read
- *
- *****************************************************************************/
-static ssize_t cpia2_v4l_read(struct file *file, char __user *buf, size_t count,
- loff_t *off)
-{
- struct camera_data *cam = video_drvdata(file);
- int noblock = file->f_flags & O_NONBLOCK;
- ssize_t ret;
-
- if (!cam)
- return -EINVAL;
-
- if (mutex_lock_interruptible(&cam->v4l2_lock))
- return -ERESTARTSYS;
- ret = cpia2_read(cam, buf, count, noblock);
- mutex_unlock(&cam->v4l2_lock);
- return ret;
-}
-
-/******************************************************************************
- *
- * cpia2_v4l_poll
- *
- *****************************************************************************/
-static __poll_t cpia2_v4l_poll(struct file *filp, struct poll_table_struct *wait)
-{
- struct camera_data *cam = video_drvdata(filp);
- __poll_t res;
-
- mutex_lock(&cam->v4l2_lock);
- res = cpia2_poll(cam, filp, wait);
- mutex_unlock(&cam->v4l2_lock);
- return res;
-}
-
-static int sync(struct camera_data *cam, int frame_nr)
-{
- struct framebuf *frame = &cam->buffers[frame_nr];
-
- while (1) {
- if (frame->status == FRAME_READY)
- return 0;
-
- if (!cam->streaming) {
- frame->status = FRAME_READY;
- frame->length = 0;
- return 0;
- }
-
- mutex_unlock(&cam->v4l2_lock);
- wait_event_interruptible(cam->wq_stream,
- !cam->streaming ||
- frame->status == FRAME_READY);
- mutex_lock(&cam->v4l2_lock);
- if (signal_pending(current))
- return -ERESTARTSYS;
- if (!video_is_registered(&cam->vdev))
- return -ENOTTY;
- }
-}
-
-/******************************************************************************
- *
- * ioctl_querycap
- *
- * V4L2 device capabilities
- *
- *****************************************************************************/
-
-static int cpia2_querycap(struct file *file, void *fh, struct v4l2_capability *vc)
-{
- struct camera_data *cam = video_drvdata(file);
-
- strscpy(vc->driver, "cpia2", sizeof(vc->driver));
-
- if (cam->params.pnp_id.product == 0x151)
- strscpy(vc->card, "QX5 Microscope", sizeof(vc->card));
- else
- strscpy(vc->card, "CPiA2 Camera", sizeof(vc->card));
- switch (cam->params.pnp_id.device_type) {
- case DEVICE_STV_672:
- strcat(vc->card, " (672/");
- break;
- case DEVICE_STV_676:
- strcat(vc->card, " (676/");
- break;
- default:
- strcat(vc->card, " (XXX/");
- break;
- }
- switch (cam->params.version.sensor_flags) {
- case CPIA2_VP_SENSOR_FLAGS_404:
- strcat(vc->card, "404)");
- break;
- case CPIA2_VP_SENSOR_FLAGS_407:
- strcat(vc->card, "407)");
- break;
- case CPIA2_VP_SENSOR_FLAGS_409:
- strcat(vc->card, "409)");
- break;
- case CPIA2_VP_SENSOR_FLAGS_410:
- strcat(vc->card, "410)");
- break;
- case CPIA2_VP_SENSOR_FLAGS_500:
- strcat(vc->card, "500)");
- break;
- default:
- strcat(vc->card, "XXX)");
- break;
- }
-
- if (usb_make_path(cam->dev, vc->bus_info, sizeof(vc->bus_info)) < 0)
- memset(vc->bus_info, 0, sizeof(vc->bus_info));
- return 0;
-}
-
-/******************************************************************************
- *
- * ioctl_input
- *
- * V4L2 input get/set/enumerate
- *
- *****************************************************************************/
-
-static int cpia2_enum_input(struct file *file, void *fh, struct v4l2_input *i)
-{
- if (i->index)
- return -EINVAL;
- strscpy(i->name, "Camera", sizeof(i->name));
- i->type = V4L2_INPUT_TYPE_CAMERA;
- return 0;
-}
-
-static int cpia2_g_input(struct file *file, void *fh, unsigned int *i)
-{
- *i = 0;
- return 0;
-}
-
-static int cpia2_s_input(struct file *file, void *fh, unsigned int i)
-{
- return i ? -EINVAL : 0;
-}
-
-/******************************************************************************
- *
- * ioctl_enum_fmt
- *
- * V4L2 format enumerate
- *
- *****************************************************************************/
-
-static int cpia2_enum_fmt_vid_cap(struct file *file, void *fh,
- struct v4l2_fmtdesc *f)
-{
- if (f->index > 1)
- return -EINVAL;
-
- if (f->index == 0)
- f->pixelformat = V4L2_PIX_FMT_MJPEG;
- else
- f->pixelformat = V4L2_PIX_FMT_JPEG;
- return 0;
-}
-
-/******************************************************************************
- *
- * ioctl_try_fmt
- *
- * V4L2 format try
- *
- *****************************************************************************/
-
-static int cpia2_try_fmt_vid_cap(struct file *file, void *fh,
- struct v4l2_format *f)
-{
- struct camera_data *cam = video_drvdata(file);
-
- if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG &&
- f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG)
- return -EINVAL;
-
- f->fmt.pix.field = V4L2_FIELD_NONE;
- f->fmt.pix.bytesperline = 0;
- f->fmt.pix.sizeimage = cam->frame_size;
- f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
-
- switch (cpia2_match_video_size(f->fmt.pix.width, f->fmt.pix.height)) {
- case VIDEOSIZE_VGA:
- f->fmt.pix.width = 640;
- f->fmt.pix.height = 480;
- break;
- case VIDEOSIZE_CIF:
- f->fmt.pix.width = 352;
- f->fmt.pix.height = 288;
- break;
- case VIDEOSIZE_QVGA:
- f->fmt.pix.width = 320;
- f->fmt.pix.height = 240;
- break;
- case VIDEOSIZE_288_216:
- f->fmt.pix.width = 288;
- f->fmt.pix.height = 216;
- break;
- case VIDEOSIZE_256_192:
- f->fmt.pix.width = 256;
- f->fmt.pix.height = 192;
- break;
- case VIDEOSIZE_224_168:
- f->fmt.pix.width = 224;
- f->fmt.pix.height = 168;
- break;
- case VIDEOSIZE_192_144:
- f->fmt.pix.width = 192;
- f->fmt.pix.height = 144;
- break;
- case VIDEOSIZE_QCIF:
- default:
- f->fmt.pix.width = 176;
- f->fmt.pix.height = 144;
- break;
- }
-
- return 0;
-}
-
-/******************************************************************************
- *
- * ioctl_set_fmt
- *
- * V4L2 format set
- *
- *****************************************************************************/
-
-static int cpia2_s_fmt_vid_cap(struct file *file, void *_fh,
- struct v4l2_format *f)
-{
- struct camera_data *cam = video_drvdata(file);
- int err, frame;
-
- err = cpia2_try_fmt_vid_cap(file, _fh, f);
- if (err != 0)
- return err;
-
- cam->pixelformat = f->fmt.pix.pixelformat;
-
- /* NOTE: This should be set to 1 for MJPEG, but some apps don't handle
- * the missing Huffman table properly.
- */
- cam->params.compression.inhibit_htables = 0;
- /*f->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG;*/
-
- /* we set the video window to something smaller or equal to what
- * is requested by the user???
- */
- DBG("Requested width = %d, height = %d\n",
- f->fmt.pix.width, f->fmt.pix.height);
- if (f->fmt.pix.width != cam->width ||
- f->fmt.pix.height != cam->height) {
- cam->width = f->fmt.pix.width;
- cam->height = f->fmt.pix.height;
- cam->params.roi.width = f->fmt.pix.width;
- cam->params.roi.height = f->fmt.pix.height;
- cpia2_set_format(cam);
- }
-
- for (frame = 0; frame < cam->num_frames; ++frame) {
- if (cam->buffers[frame].status == FRAME_READING)
- if ((err = sync(cam, frame)) < 0)
- return err;
-
- cam->buffers[frame].status = FRAME_EMPTY;
- }
-
- return 0;
-}
-
-/******************************************************************************
- *
- * ioctl_get_fmt
- *
- * V4L2 format get
- *
- *****************************************************************************/
-
-static int cpia2_g_fmt_vid_cap(struct file *file, void *fh,
- struct v4l2_format *f)
-{
- struct camera_data *cam = video_drvdata(file);
-
- f->fmt.pix.width = cam->width;
- f->fmt.pix.height = cam->height;
- f->fmt.pix.pixelformat = cam->pixelformat;
- f->fmt.pix.field = V4L2_FIELD_NONE;
- f->fmt.pix.bytesperline = 0;
- f->fmt.pix.sizeimage = cam->frame_size;
- f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
-
- return 0;
-}
-
-/******************************************************************************
- *
- * ioctl_cropcap
- *
- * V4L2 query cropping capabilities
- * NOTE: cropping is currently disabled
- *
- *****************************************************************************/
-
-static int cpia2_g_selection(struct file *file, void *fh,
- struct v4l2_selection *s)
-{
- struct camera_data *cam = video_drvdata(file);
-
- if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- switch (s->target) {
- case V4L2_SEL_TGT_CROP_BOUNDS:
- case V4L2_SEL_TGT_CROP_DEFAULT:
- s->r.left = 0;
- s->r.top = 0;
- s->r.width = cam->width;
- s->r.height = cam->height;
- break;
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-struct framerate_info {
- int value;
- struct v4l2_fract period;
-};
-
-static const struct framerate_info framerate_controls[] = {
- { CPIA2_VP_FRAMERATE_6_25, { 4, 25 } },
- { CPIA2_VP_FRAMERATE_7_5, { 2, 15 } },
- { CPIA2_VP_FRAMERATE_12_5, { 2, 25 } },
- { CPIA2_VP_FRAMERATE_15, { 1, 15 } },
- { CPIA2_VP_FRAMERATE_25, { 1, 25 } },
- { CPIA2_VP_FRAMERATE_30, { 1, 30 } },
-};
-
-static int cpia2_g_parm(struct file *file, void *fh, struct v4l2_streamparm *p)
-{
- struct camera_data *cam = video_drvdata(file);
- struct v4l2_captureparm *cap = &p->parm.capture;
- int i;
-
- if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- cap->capability = V4L2_CAP_TIMEPERFRAME;
- cap->readbuffers = cam->num_frames;
- for (i = 0; i < ARRAY_SIZE(framerate_controls); i++)
- if (cam->params.vp_params.frame_rate == framerate_controls[i].value) {
- cap->timeperframe = framerate_controls[i].period;
- break;
- }
- return 0;
-}
-
-static int cpia2_s_parm(struct file *file, void *fh, struct v4l2_streamparm *p)
-{
- struct camera_data *cam = video_drvdata(file);
- struct v4l2_captureparm *cap = &p->parm.capture;
- struct v4l2_fract tpf = cap->timeperframe;
- int max = ARRAY_SIZE(framerate_controls) - 1;
- int ret;
- int i;
-
- ret = cpia2_g_parm(file, fh, p);
- if (ret || !tpf.denominator || !tpf.numerator)
- return ret;
-
- /* Maximum 15 fps for this model */
- if (cam->params.pnp_id.device_type == DEVICE_STV_672 &&
- cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500)
- max -= 2;
- for (i = 0; i <= max; i++) {
- struct v4l2_fract f1 = tpf;
- struct v4l2_fract f2 = framerate_controls[i].period;
-
- f1.numerator *= f2.denominator;
- f2.numerator *= f1.denominator;
- if (f1.numerator >= f2.numerator)
- break;
- }
- if (i > max)
- i = max;
- cap->timeperframe = framerate_controls[i].period;
- return cpia2_set_fps(cam, framerate_controls[i].value);
-}
-
-static const struct {
- u32 width;
- u32 height;
-} cpia2_framesizes[] = {
- { 640, 480 },
- { 352, 288 },
- { 320, 240 },
- { 288, 216 },
- { 256, 192 },
- { 224, 168 },
- { 192, 144 },
- { 176, 144 },
-};
-
-static int cpia2_enum_framesizes(struct file *file, void *fh,
- struct v4l2_frmsizeenum *fsize)
-{
- if (fsize->pixel_format != V4L2_PIX_FMT_MJPEG &&
- fsize->pixel_format != V4L2_PIX_FMT_JPEG)
- return -EINVAL;
- if (fsize->index >= ARRAY_SIZE(cpia2_framesizes))
- return -EINVAL;
- fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
- fsize->discrete.width = cpia2_framesizes[fsize->index].width;
- fsize->discrete.height = cpia2_framesizes[fsize->index].height;
-
- return 0;
-}
-
-static int cpia2_enum_frameintervals(struct file *file, void *fh,
- struct v4l2_frmivalenum *fival)
-{
- struct camera_data *cam = video_drvdata(file);
- int max = ARRAY_SIZE(framerate_controls) - 1;
- int i;
-
- if (fival->pixel_format != V4L2_PIX_FMT_MJPEG &&
- fival->pixel_format != V4L2_PIX_FMT_JPEG)
- return -EINVAL;
-
- /* Maximum 15 fps for this model */
- if (cam->params.pnp_id.device_type == DEVICE_STV_672 &&
- cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500)
- max -= 2;
- if (fival->index > max)
- return -EINVAL;
- for (i = 0; i < ARRAY_SIZE(cpia2_framesizes); i++)
- if (fival->width == cpia2_framesizes[i].width &&
- fival->height == cpia2_framesizes[i].height)
- break;
- if (i == ARRAY_SIZE(cpia2_framesizes))
- return -EINVAL;
- fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
- fival->discrete = framerate_controls[fival->index].period;
- return 0;
-}
-
-/******************************************************************************
- *
- * ioctl_s_ctrl
- *
- * V4L2 set the value of a control variable
- *
- *****************************************************************************/
-
-static int cpia2_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct camera_data *cam =
- container_of(ctrl->handler, struct camera_data, hdl);
- static const int flicker_table[] = {
- NEVER_FLICKER,
- FLICKER_50,
- FLICKER_60,
- };
-
- DBG("Set control id:%d, value:%d\n", ctrl->id, ctrl->val);
-
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- cpia2_set_brightness(cam, ctrl->val);
- break;
- case V4L2_CID_CONTRAST:
- cpia2_set_contrast(cam, ctrl->val);
- break;
- case V4L2_CID_SATURATION:
- cpia2_set_saturation(cam, ctrl->val);
- break;
- case V4L2_CID_HFLIP:
- cpia2_set_property_mirror(cam, ctrl->val);
- break;
- case V4L2_CID_VFLIP:
- cpia2_set_property_flip(cam, ctrl->val);
- break;
- case V4L2_CID_POWER_LINE_FREQUENCY:
- return cpia2_set_flicker_mode(cam, flicker_table[ctrl->val]);
- case V4L2_CID_ILLUMINATORS_1:
- return cpia2_set_gpio(cam, (cam->top_light->val << 6) |
- (cam->bottom_light->val << 7));
- case V4L2_CID_JPEG_ACTIVE_MARKER:
- cam->params.compression.inhibit_htables =
- !(ctrl->val & V4L2_JPEG_ACTIVE_MARKER_DHT);
- break;
- case V4L2_CID_JPEG_COMPRESSION_QUALITY:
- cam->params.vc_params.quality = ctrl->val;
- break;
- case CPIA2_CID_USB_ALT:
- cam->params.camera_state.stream_mode = ctrl->val;
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-/******************************************************************************
- *
- * ioctl_g_jpegcomp
- *
- * V4L2 get the JPEG compression parameters
- *
- *****************************************************************************/
-
-static int cpia2_g_jpegcomp(struct file *file, void *fh, struct v4l2_jpegcompression *parms)
-{
- struct camera_data *cam = video_drvdata(file);
-
- memset(parms, 0, sizeof(*parms));
-
- parms->quality = 80; // TODO: Can this be made meaningful?
-
- parms->jpeg_markers = V4L2_JPEG_MARKER_DQT | V4L2_JPEG_MARKER_DRI;
- if (!cam->params.compression.inhibit_htables)
- parms->jpeg_markers |= V4L2_JPEG_MARKER_DHT;
-
- parms->APPn = cam->APPn;
- parms->APP_len = cam->APP_len;
- if (cam->APP_len > 0) {
- memcpy(parms->APP_data, cam->APP_data, cam->APP_len);
- parms->jpeg_markers |= V4L2_JPEG_MARKER_APP;
- }
-
- parms->COM_len = cam->COM_len;
- if (cam->COM_len > 0) {
- memcpy(parms->COM_data, cam->COM_data, cam->COM_len);
- parms->jpeg_markers |= JPEG_MARKER_COM;
- }
-
- DBG("G_JPEGCOMP APP_len:%d COM_len:%d\n",
- parms->APP_len, parms->COM_len);
-
- return 0;
-}
-
-/******************************************************************************
- *
- * ioctl_s_jpegcomp
- *
- * V4L2 set the JPEG compression parameters
- * NOTE: quality and some jpeg_markers are ignored.
- *
- *****************************************************************************/
-
-static int cpia2_s_jpegcomp(struct file *file, void *fh,
- const struct v4l2_jpegcompression *parms)
-{
- struct camera_data *cam = video_drvdata(file);
-
- DBG("S_JPEGCOMP APP_len:%d COM_len:%d\n",
- parms->APP_len, parms->COM_len);
-
- cam->params.compression.inhibit_htables =
- !(parms->jpeg_markers & V4L2_JPEG_MARKER_DHT);
-
- if (parms->APP_len != 0) {
- if (parms->APP_len > 0 &&
- parms->APP_len <= sizeof(cam->APP_data) &&
- parms->APPn >= 0 && parms->APPn <= 15) {
- cam->APPn = parms->APPn;
- cam->APP_len = parms->APP_len;
- memcpy(cam->APP_data, parms->APP_data, parms->APP_len);
- } else {
- LOG("Bad APPn Params n=%d len=%d\n",
- parms->APPn, parms->APP_len);
- return -EINVAL;
- }
- } else {
- cam->APP_len = 0;
- }
-
- if (parms->COM_len != 0) {
- if (parms->COM_len > 0 &&
- parms->COM_len <= sizeof(cam->COM_data)) {
- cam->COM_len = parms->COM_len;
- memcpy(cam->COM_data, parms->COM_data, parms->COM_len);
- } else {
- LOG("Bad COM_len=%d\n", parms->COM_len);
- return -EINVAL;
- }
- }
-
- return 0;
-}
-
-/******************************************************************************
- *
- * ioctl_reqbufs
- *
- * V4L2 Initiate memory mapping.
- * NOTE: The user's request is ignored. For now the buffers are fixed.
- *
- *****************************************************************************/
-
-static int cpia2_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *req)
-{
- struct camera_data *cam = video_drvdata(file);
-
- if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- req->memory != V4L2_MEMORY_MMAP)
- return -EINVAL;
-
- DBG("REQBUFS requested:%d returning:%d\n", req->count, cam->num_frames);
- req->count = cam->num_frames;
- memset(&req->reserved, 0, sizeof(req->reserved));
-
- return 0;
-}
-
-/******************************************************************************
- *
- * ioctl_querybuf
- *
- * V4L2 Query memory buffer status.
- *
- *****************************************************************************/
-
-static int cpia2_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf)
-{
- struct camera_data *cam = video_drvdata(file);
-
- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- buf->index >= cam->num_frames)
- return -EINVAL;
-
- buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer;
- buf->length = cam->frame_size;
-
- buf->memory = V4L2_MEMORY_MMAP;
-
- if (cam->mmapped)
- buf->flags = V4L2_BUF_FLAG_MAPPED;
- else
- buf->flags = 0;
-
- buf->flags |= V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
-
- switch (cam->buffers[buf->index].status) {
- case FRAME_EMPTY:
- case FRAME_ERROR:
- case FRAME_READING:
- buf->bytesused = 0;
- buf->flags = V4L2_BUF_FLAG_QUEUED;
- break;
- case FRAME_READY:
- buf->bytesused = cam->buffers[buf->index].length;
- v4l2_buffer_set_timestamp(buf, cam->buffers[buf->index].ts);
- buf->sequence = cam->buffers[buf->index].seq;
- buf->flags = V4L2_BUF_FLAG_DONE;
- break;
- }
-
- DBG("QUERYBUF index:%d offset:%d flags:%d seq:%d bytesused:%d\n",
- buf->index, buf->m.offset, buf->flags, buf->sequence,
- buf->bytesused);
-
- return 0;
-}
-
-/******************************************************************************
- *
- * ioctl_qbuf
- *
- * V4L2 User is freeing buffer
- *
- *****************************************************************************/
-
-static int cpia2_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
-{
- struct camera_data *cam = video_drvdata(file);
-
- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- buf->memory != V4L2_MEMORY_MMAP ||
- buf->index >= cam->num_frames)
- return -EINVAL;
-
- DBG("QBUF #%d\n", buf->index);
-
- if (cam->buffers[buf->index].status == FRAME_READY)
- cam->buffers[buf->index].status = FRAME_EMPTY;
-
- return 0;
-}
-
-/******************************************************************************
- *
- * find_earliest_filled_buffer
- *
- * Helper for ioctl_dqbuf. Find the next ready buffer.
- *
- *****************************************************************************/
-
-static int find_earliest_filled_buffer(struct camera_data *cam)
-{
- int i;
- int found = -1;
-
- for (i = 0; i < cam->num_frames; i++) {
- if (cam->buffers[i].status == FRAME_READY) {
- if (found < 0) {
- found = i;
- } else {
- /* find which buffer is earlier */
- if (cam->buffers[i].ts < cam->buffers[found].ts)
- found = i;
- }
- }
- }
- return found;
-}
-
-/******************************************************************************
- *
- * ioctl_dqbuf
- *
- * V4L2 User is asking for a filled buffer.
- *
- *****************************************************************************/
-
-static int cpia2_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
-{
- struct camera_data *cam = video_drvdata(file);
- int frame;
-
- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- buf->memory != V4L2_MEMORY_MMAP)
- return -EINVAL;
-
- frame = find_earliest_filled_buffer(cam);
-
- if (frame < 0 && file->f_flags & O_NONBLOCK)
- return -EAGAIN;
-
- if (frame < 0) {
- /* Wait for a frame to become available */
- struct framebuf *cb = cam->curbuff;
-
- mutex_unlock(&cam->v4l2_lock);
- wait_event_interruptible(cam->wq_stream,
- !video_is_registered(&cam->vdev) ||
- (cb = cam->curbuff)->status == FRAME_READY);
- mutex_lock(&cam->v4l2_lock);
- if (signal_pending(current))
- return -ERESTARTSYS;
- if (!video_is_registered(&cam->vdev))
- return -ENOTTY;
- frame = cb->num;
- }
-
- buf->index = frame;
- buf->bytesused = cam->buffers[buf->index].length;
- buf->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE
- | V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- buf->field = V4L2_FIELD_NONE;
- v4l2_buffer_set_timestamp(buf, cam->buffers[buf->index].ts);
- buf->sequence = cam->buffers[buf->index].seq;
- buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer;
- buf->length = cam->frame_size;
- buf->reserved2 = 0;
- buf->request_fd = 0;
- memset(&buf->timecode, 0, sizeof(buf->timecode));
-
- DBG("DQBUF #%d status:%d seq:%d length:%d\n", buf->index,
- cam->buffers[buf->index].status, buf->sequence, buf->bytesused);
-
- return 0;
-}
-
-static int cpia2_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
-{
- struct camera_data *cam = video_drvdata(file);
- int ret = -EINVAL;
-
- DBG("VIDIOC_STREAMON, streaming=%d\n", cam->streaming);
- if (!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- if (!cam->streaming) {
- ret = cpia2_usb_stream_start(cam,
- cam->params.camera_state.stream_mode);
- if (!ret)
- v4l2_ctrl_grab(cam->usb_alt, true);
- }
- return ret;
-}
-
-static int cpia2_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
-{
- struct camera_data *cam = video_drvdata(file);
- int ret = -EINVAL;
-
- DBG("VIDIOC_STREAMOFF, streaming=%d\n", cam->streaming);
- if (!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- if (cam->streaming) {
- ret = cpia2_usb_stream_stop(cam);
- if (!ret)
- v4l2_ctrl_grab(cam->usb_alt, false);
- }
- return ret;
-}
-
-/******************************************************************************
- *
- * cpia2_mmap
- *
- *****************************************************************************/
-static int cpia2_mmap(struct file *file, struct vm_area_struct *area)
-{
- struct camera_data *cam = video_drvdata(file);
- int retval;
-
- if (mutex_lock_interruptible(&cam->v4l2_lock))
- return -ERESTARTSYS;
- retval = cpia2_remap_buffer(cam, area);
-
- if (!retval)
- cam->stream_fh = file->private_data;
- mutex_unlock(&cam->v4l2_lock);
- return retval;
-}
-
-/******************************************************************************
- *
- * reset_camera_struct_v4l
- *
- * Sets all values to the defaults
- *****************************************************************************/
-static void reset_camera_struct_v4l(struct camera_data *cam)
-{
- cam->width = cam->params.roi.width;
- cam->height = cam->params.roi.height;
-
- cam->frame_size = buffer_size;
- cam->num_frames = num_buffers;
-
- /* Flicker modes */
- cam->params.flicker_control.flicker_mode_req = flicker_mode;
-
- /* stream modes */
- cam->params.camera_state.stream_mode = alternate;
-
- cam->pixelformat = V4L2_PIX_FMT_JPEG;
-}
-
-static const struct v4l2_ioctl_ops cpia2_ioctl_ops = {
- .vidioc_querycap = cpia2_querycap,
- .vidioc_enum_input = cpia2_enum_input,
- .vidioc_g_input = cpia2_g_input,
- .vidioc_s_input = cpia2_s_input,
- .vidioc_enum_fmt_vid_cap = cpia2_enum_fmt_vid_cap,
- .vidioc_g_fmt_vid_cap = cpia2_g_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = cpia2_s_fmt_vid_cap,
- .vidioc_try_fmt_vid_cap = cpia2_try_fmt_vid_cap,
- .vidioc_g_jpegcomp = cpia2_g_jpegcomp,
- .vidioc_s_jpegcomp = cpia2_s_jpegcomp,
- .vidioc_g_selection = cpia2_g_selection,
- .vidioc_reqbufs = cpia2_reqbufs,
- .vidioc_querybuf = cpia2_querybuf,
- .vidioc_qbuf = cpia2_qbuf,
- .vidioc_dqbuf = cpia2_dqbuf,
- .vidioc_streamon = cpia2_streamon,
- .vidioc_streamoff = cpia2_streamoff,
- .vidioc_s_parm = cpia2_s_parm,
- .vidioc_g_parm = cpia2_g_parm,
- .vidioc_enum_framesizes = cpia2_enum_framesizes,
- .vidioc_enum_frameintervals = cpia2_enum_frameintervals,
- .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
- .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
-};
-
-/***
- * The v4l video device structure initialized for this device
- ***/
-static const struct v4l2_file_operations cpia2_fops = {
- .owner = THIS_MODULE,
- .open = cpia2_open,
- .release = cpia2_close,
- .read = cpia2_v4l_read,
- .poll = cpia2_v4l_poll,
- .unlocked_ioctl = video_ioctl2,
- .mmap = cpia2_mmap,
-};
-
-static const struct video_device cpia2_template = {
- /* I could not find any place for the old .initialize initializer?? */
- .name = "CPiA2 Camera",
- .fops = &cpia2_fops,
- .ioctl_ops = &cpia2_ioctl_ops,
- .release = video_device_release_empty,
-};
-
-void cpia2_camera_release(struct v4l2_device *v4l2_dev)
-{
- struct camera_data *cam =
- container_of(v4l2_dev, struct camera_data, v4l2_dev);
-
- v4l2_ctrl_handler_free(&cam->hdl);
- v4l2_device_unregister(&cam->v4l2_dev);
- kfree(cam);
-}
-
-static const struct v4l2_ctrl_ops cpia2_ctrl_ops = {
- .s_ctrl = cpia2_s_ctrl,
-};
-
-/******************************************************************************
- *
- * cpia2_register_camera
- *
- *****************************************************************************/
-int cpia2_register_camera(struct camera_data *cam)
-{
- struct v4l2_ctrl_handler *hdl = &cam->hdl;
- struct v4l2_ctrl_config cpia2_usb_alt = {
- .ops = &cpia2_ctrl_ops,
- .id = CPIA2_CID_USB_ALT,
- .name = "USB Alternate",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .min = USBIF_ISO_1,
- .max = USBIF_ISO_6,
- .step = 1,
- };
- int ret;
-
- v4l2_ctrl_handler_init(hdl, 12);
- v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
- V4L2_CID_BRIGHTNESS,
- cam->params.pnp_id.device_type == DEVICE_STV_672 ? 1 : 0,
- 255, 1, DEFAULT_BRIGHTNESS);
- v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
- V4L2_CID_CONTRAST, 0, 255, 1, DEFAULT_CONTRAST);
- v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
- V4L2_CID_SATURATION, 0, 255, 1, DEFAULT_SATURATION);
- v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
- V4L2_CID_HFLIP, 0, 1, 1, 0);
- v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
- V4L2_CID_JPEG_ACTIVE_MARKER, 0,
- V4L2_JPEG_ACTIVE_MARKER_DHT, 0,
- V4L2_JPEG_ACTIVE_MARKER_DHT);
- v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
- V4L2_CID_JPEG_COMPRESSION_QUALITY, 1,
- 100, 1, 100);
- cpia2_usb_alt.def = alternate;
- cam->usb_alt = v4l2_ctrl_new_custom(hdl, &cpia2_usb_alt, NULL);
- /* VP5 Only */
- if (cam->params.pnp_id.device_type != DEVICE_STV_672)
- v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
- V4L2_CID_VFLIP, 0, 1, 1, 0);
- /* Flicker control only valid for 672 */
- if (cam->params.pnp_id.device_type == DEVICE_STV_672)
- v4l2_ctrl_new_std_menu(hdl, &cpia2_ctrl_ops,
- V4L2_CID_POWER_LINE_FREQUENCY,
- V4L2_CID_POWER_LINE_FREQUENCY_60HZ,
- 0, 0);
- /* Light control only valid for the QX5 Microscope */
- if (cam->params.pnp_id.product == 0x151) {
- cam->top_light = v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
- V4L2_CID_ILLUMINATORS_1,
- 0, 1, 1, 0);
- cam->bottom_light = v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
- V4L2_CID_ILLUMINATORS_2,
- 0, 1, 1, 0);
- v4l2_ctrl_cluster(2, &cam->top_light);
- }
-
- if (hdl->error) {
- ret = hdl->error;
- v4l2_ctrl_handler_free(hdl);
- return ret;
- }
-
- cam->vdev = cpia2_template;
- video_set_drvdata(&cam->vdev, cam);
- cam->vdev.lock = &cam->v4l2_lock;
- cam->vdev.ctrl_handler = hdl;
- cam->vdev.v4l2_dev = &cam->v4l2_dev;
- cam->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING;
-
- reset_camera_struct_v4l(cam);
-
- /* register v4l device */
- if (video_register_device(&cam->vdev, VFL_TYPE_VIDEO, video_nr) < 0) {
- ERR("video_register_device failed\n");
- return -ENODEV;
- }
-
- return 0;
-}
-
-/******************************************************************************
- *
- * cpia2_unregister_camera
- *
- *****************************************************************************/
-void cpia2_unregister_camera(struct camera_data *cam)
-{
- video_unregister_device(&cam->vdev);
-}
-
-/******************************************************************************
- *
- * check_parameters
- *
- * Make sure that all user-supplied parameters are sensible
- *****************************************************************************/
-static void __init check_parameters(void)
-{
- if (buffer_size < PAGE_SIZE) {
- buffer_size = PAGE_SIZE;
- LOG("buffer_size too small, setting to %d\n", buffer_size);
- } else if (buffer_size > 1024 * 1024) {
- /* arbitrary upper limiit */
- buffer_size = 1024 * 1024;
- LOG("buffer_size ridiculously large, setting to %d\n",
- buffer_size);
- } else {
- buffer_size += PAGE_SIZE - 1;
- buffer_size &= ~(PAGE_SIZE - 1);
- }
-
- if (num_buffers < 1) {
- num_buffers = 1;
- LOG("num_buffers too small, setting to %d\n", num_buffers);
- } else if (num_buffers > VIDEO_MAX_FRAME) {
- num_buffers = VIDEO_MAX_FRAME;
- LOG("num_buffers too large, setting to %d\n", num_buffers);
- }
-
- if (alternate < USBIF_ISO_1 || alternate > USBIF_ISO_6) {
- alternate = DEFAULT_ALT;
- LOG("alternate specified is invalid, using %d\n", alternate);
- }
-
- if (flicker_mode != 0 && flicker_mode != FLICKER_50 && flicker_mode != FLICKER_60) {
- flicker_mode = 0;
- LOG("Flicker mode specified is invalid, using %d\n",
- flicker_mode);
- }
-
- DBG("Using %d buffers, each %d bytes, alternate=%d\n",
- num_buffers, buffer_size, alternate);
-}
-
-/************ Module Stuff ***************/
-
-/******************************************************************************
- *
- * cpia2_init/module_init
- *
- *****************************************************************************/
-static int __init cpia2_init(void)
-{
- LOG("%s v%s\n",
- ABOUT, CPIA_VERSION);
- check_parameters();
- return cpia2_usb_init();
-}
-
-/******************************************************************************
- *
- * cpia2_exit/module_exit
- *
- *****************************************************************************/
-static void __exit cpia2_exit(void)
-{
- cpia2_usb_cleanup();
- schedule_timeout(2 * HZ);
-}
-
-module_init(cpia2_init);
-module_exit(cpia2_exit);
diff --git a/drivers/staging/media/deprecated/fsl-viu/Kconfig b/drivers/staging/media/deprecated/fsl-viu/Kconfig
deleted file mode 100644
index 399892c69a18..000000000000
--- a/drivers/staging/media/deprecated/fsl-viu/Kconfig
+++ /dev/null
@@ -1,15 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-config VIDEO_VIU
- tristate "NXP VIU Video Driver (DEPRECATED)"
- depends on V4L_PLATFORM_DRIVERS
- depends on VIDEO_DEV && (PPC_MPC512x || COMPILE_TEST) && I2C
- select VIDEOBUF_DMA_CONTIG
- help
- Support for Freescale VIU video driver. This device captures
- video data, or overlays video on DIU frame buffer.
-
- This driver is deprecated and is scheduled for removal by
- the beginning of 2023. See the TODO file for more information.
-
- Say Y here if you want to enable VIU device on MPC5121e Rev2+.
- In doubt, say N.
diff --git a/drivers/staging/media/deprecated/fsl-viu/TODO b/drivers/staging/media/deprecated/fsl-viu/TODO
deleted file mode 100644
index ecb30a429689..000000000000
--- a/drivers/staging/media/deprecated/fsl-viu/TODO
+++ /dev/null
@@ -1,7 +0,0 @@
-This is one of the few drivers still not using the vb2
-framework, so this driver is now deprecated with the intent of
-removing it altogether by the beginning of 2023.
-
-In order to keep this driver it has to be converted to vb2.
-If someone is interested in doing this work, then contact the
-linux-media mailinglist (https://linuxtv.org/lists.php).
diff --git a/drivers/staging/media/deprecated/fsl-viu/fsl-viu.c b/drivers/staging/media/deprecated/fsl-viu/fsl-viu.c
deleted file mode 100644
index afc96f6db2a1..000000000000
--- a/drivers/staging/media/deprecated/fsl-viu/fsl-viu.c
+++ /dev/null
@@ -1,1599 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
- *
- * Freescale VIU video driver
- *
- * Authors: Hongjun Chen <hong-jun.chen@freescale.com>
- * Porting to 2.6.35 by DENX Software Engineering,
- * Anatolij Gustschin <agust@denx.de>
- */
-
-#include <linux/module.h>
-#include <linux/clk.h>
-#include <linux/kernel.h>
-#include <linux/i2c.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/of_platform.h>
-#include <linux/slab.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-fh.h>
-#include <media/v4l2-event.h>
-#include <media/videobuf-dma-contig.h>
-
-#define DRV_NAME "fsl_viu"
-#define VIU_VERSION "0.5.1"
-
-#define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */
-
-#define VIU_VID_MEM_LIMIT 4 /* Video memory limit, in Mb */
-
-/* I2C address of video decoder chip is 0x4A */
-#define VIU_VIDEO_DECODER_ADDR 0x25
-
-static int info_level;
-
-#define dprintk(level, fmt, arg...) \
- do { \
- if (level <= info_level) \
- printk(KERN_DEBUG "viu: " fmt , ## arg); \
- } while (0)
-
-/*
- * Basic structures
- */
-struct viu_fmt {
- u32 fourcc; /* v4l2 format id */
- u32 pixelformat;
- int depth;
-};
-
-static struct viu_fmt formats[] = {
- {
- .fourcc = V4L2_PIX_FMT_RGB565,
- .pixelformat = V4L2_PIX_FMT_RGB565,
- .depth = 16,
- }, {
- .fourcc = V4L2_PIX_FMT_RGB32,
- .pixelformat = V4L2_PIX_FMT_RGB32,
- .depth = 32,
- }
-};
-
-struct viu_dev;
-struct viu_buf;
-
-/* buffer for one video frame */
-struct viu_buf {
- /* common v4l buffer stuff -- must be first */
- struct videobuf_buffer vb;
- struct viu_fmt *fmt;
-};
-
-struct viu_dmaqueue {
- struct viu_dev *dev;
- struct list_head active;
- struct list_head queued;
- struct timer_list timeout;
-};
-
-struct viu_status {
- u32 field_irq;
- u32 vsync_irq;
- u32 hsync_irq;
- u32 vstart_irq;
- u32 dma_end_irq;
- u32 error_irq;
-};
-
-struct viu_reg {
- u32 status_cfg;
- u32 luminance;
- u32 chroma_r;
- u32 chroma_g;
- u32 chroma_b;
- u32 field_base_addr;
- u32 dma_inc;
- u32 picture_count;
- u32 req_alarm;
- u32 alpha;
-} __attribute__ ((packed));
-
-struct viu_dev {
- struct v4l2_device v4l2_dev;
- struct v4l2_ctrl_handler hdl;
- struct mutex lock;
- spinlock_t slock;
- int users;
-
- struct device *dev;
- /* various device info */
- struct video_device *vdev;
- struct viu_dmaqueue vidq;
- enum v4l2_field capfield;
- int field;
- int first;
- int dma_done;
-
- /* Hardware register area */
- struct viu_reg __iomem *vr;
-
- /* Interrupt vector */
- int irq;
- struct viu_status irqs;
-
- /* video overlay */
- struct v4l2_framebuffer ovbuf;
- struct viu_fmt *ovfmt;
- unsigned int ovenable;
- enum v4l2_field ovfield;
-
- /* crop */
- struct v4l2_rect crop_current;
-
- /* clock pointer */
- struct clk *clk;
-
- /* decoder */
- struct v4l2_subdev *decoder;
-
- v4l2_std_id std;
-};
-
-struct viu_fh {
- /* must remain the first field of this struct */
- struct v4l2_fh fh;
- struct viu_dev *dev;
-
- /* video capture */
- struct videobuf_queue vb_vidq;
- spinlock_t vbq_lock; /* spinlock for the videobuf queue */
-
- /* video overlay */
- struct v4l2_window win;
- struct v4l2_clip clips[1];
-
- /* video capture */
- struct viu_fmt *fmt;
- int width, height, sizeimage;
- enum v4l2_buf_type type;
-};
-
-static struct viu_reg reg_val;
-
-/*
- * Macro definitions of VIU registers
- */
-
-/* STATUS_CONFIG register */
-enum status_config {
- SOFT_RST = 1 << 0,
-
- ERR_MASK = 0x0f << 4, /* Error code mask */
- ERR_NO = 0x00, /* No error */
- ERR_DMA_V = 0x01 << 4, /* DMA in vertical active */
- ERR_DMA_VB = 0x02 << 4, /* DMA in vertical blanking */
- ERR_LINE_TOO_LONG = 0x04 << 4, /* Line too long */
- ERR_TOO_MANG_LINES = 0x05 << 4, /* Too many lines in field */
- ERR_LINE_TOO_SHORT = 0x06 << 4, /* Line too short */
- ERR_NOT_ENOUGH_LINE = 0x07 << 4, /* Not enough lines in field */
- ERR_FIFO_OVERFLOW = 0x08 << 4, /* FIFO overflow */
- ERR_FIFO_UNDERFLOW = 0x09 << 4, /* FIFO underflow */
- ERR_1bit_ECC = 0x0a << 4, /* One bit ECC error */
- ERR_MORE_ECC = 0x0b << 4, /* Two/more bits ECC error */
-
- INT_FIELD_EN = 0x01 << 8, /* Enable field interrupt */
- INT_VSYNC_EN = 0x01 << 9, /* Enable vsync interrupt */
- INT_HSYNC_EN = 0x01 << 10, /* Enable hsync interrupt */
- INT_VSTART_EN = 0x01 << 11, /* Enable vstart interrupt */
- INT_DMA_END_EN = 0x01 << 12, /* Enable DMA end interrupt */
- INT_ERROR_EN = 0x01 << 13, /* Enable error interrupt */
- INT_ECC_EN = 0x01 << 14, /* Enable ECC interrupt */
-
- INT_FIELD_STATUS = 0x01 << 16, /* field interrupt status */
- INT_VSYNC_STATUS = 0x01 << 17, /* vsync interrupt status */
- INT_HSYNC_STATUS = 0x01 << 18, /* hsync interrupt status */
- INT_VSTART_STATUS = 0x01 << 19, /* vstart interrupt status */
- INT_DMA_END_STATUS = 0x01 << 20, /* DMA end interrupt status */
- INT_ERROR_STATUS = 0x01 << 21, /* error interrupt status */
-
- DMA_ACT = 0x01 << 27, /* Enable DMA transfer */
- FIELD_NO = 0x01 << 28, /* Field number */
- DITHER_ON = 0x01 << 29, /* Dithering is on */
- ROUND_ON = 0x01 << 30, /* Round is on */
- MODE_32BIT = 1UL << 31, /* Data in RGBa888,
- * 0 in RGB565
- */
-};
-
-#define norm_maxw() 720
-#define norm_maxh() 576
-
-#define INT_ALL_STATUS (INT_FIELD_STATUS | INT_VSYNC_STATUS | \
- INT_HSYNC_STATUS | INT_VSTART_STATUS | \
- INT_DMA_END_STATUS | INT_ERROR_STATUS)
-
-#define NUM_FORMATS ARRAY_SIZE(formats)
-
-static irqreturn_t viu_intr(int irq, void *dev_id);
-
-static struct viu_fmt *format_by_fourcc(int fourcc)
-{
- int i;
-
- for (i = 0; i < NUM_FORMATS; i++) {
- if (formats[i].pixelformat == fourcc)
- return formats + i;
- }
-
- dprintk(0, "unknown pixelformat:'%4.4s'\n", (char *)&fourcc);
- return NULL;
-}
-
-static void viu_start_dma(struct viu_dev *dev)
-{
- struct viu_reg __iomem *vr = dev->vr;
-
- dev->field = 0;
-
- /* Enable DMA operation */
- iowrite32be(SOFT_RST, &vr->status_cfg);
- iowrite32be(INT_FIELD_EN, &vr->status_cfg);
-}
-
-static void viu_stop_dma(struct viu_dev *dev)
-{
- struct viu_reg __iomem *vr = dev->vr;
- int cnt = 100;
- u32 status_cfg;
-
- iowrite32be(0, &vr->status_cfg);
-
- /* Clear pending interrupts */
- status_cfg = ioread32be(&vr->status_cfg);
- if (status_cfg & 0x3f0000)
- iowrite32be(status_cfg & 0x3f0000, &vr->status_cfg);
-
- if (status_cfg & DMA_ACT) {
- do {
- status_cfg = ioread32be(&vr->status_cfg);
- if (status_cfg & INT_DMA_END_STATUS)
- break;
- } while (cnt--);
-
- if (cnt < 0) {
- /* timed out, issue soft reset */
- iowrite32be(SOFT_RST, &vr->status_cfg);
- iowrite32be(0, &vr->status_cfg);
- } else {
- /* clear DMA_END and other pending irqs */
- iowrite32be(status_cfg & 0x3f0000, &vr->status_cfg);
- }
- }
-
- dev->field = 0;
-}
-
-static int restart_video_queue(struct viu_dmaqueue *vidq)
-{
- struct viu_buf *buf, *prev;
-
- dprintk(1, "%s vidq=%p\n", __func__, vidq);
- if (!list_empty(&vidq->active)) {
- buf = list_entry(vidq->active.next, struct viu_buf, vb.queue);
- dprintk(2, "restart_queue [%p/%d]: restart dma\n",
- buf, buf->vb.i);
-
- viu_stop_dma(vidq->dev);
-
- /* cancel all outstanding capture requests */
- list_for_each_entry_safe(buf, prev, &vidq->active, vb.queue) {
- list_del(&buf->vb.queue);
- buf->vb.state = VIDEOBUF_ERROR;
- wake_up(&buf->vb.done);
- }
- mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT);
- return 0;
- }
-
- prev = NULL;
- for (;;) {
- if (list_empty(&vidq->queued))
- return 0;
- buf = list_entry(vidq->queued.next, struct viu_buf, vb.queue);
- if (prev == NULL) {
- list_move_tail(&buf->vb.queue, &vidq->active);
-
- dprintk(1, "Restarting video dma\n");
- viu_stop_dma(vidq->dev);
- viu_start_dma(vidq->dev);
-
- buf->vb.state = VIDEOBUF_ACTIVE;
- mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT);
- dprintk(2, "[%p/%d] restart_queue - first active\n",
- buf, buf->vb.i);
-
- } else if (prev->vb.width == buf->vb.width &&
- prev->vb.height == buf->vb.height &&
- prev->fmt == buf->fmt) {
- list_move_tail(&buf->vb.queue, &vidq->active);
- buf->vb.state = VIDEOBUF_ACTIVE;
- dprintk(2, "[%p/%d] restart_queue - move to active\n",
- buf, buf->vb.i);
- } else {
- return 0;
- }
- prev = buf;
- }
-}
-
-static void viu_vid_timeout(struct timer_list *t)
-{
- struct viu_dev *dev = from_timer(dev, t, vidq.timeout);
- struct viu_buf *buf;
- struct viu_dmaqueue *vidq = &dev->vidq;
-
- while (!list_empty(&vidq->active)) {
- buf = list_entry(vidq->active.next, struct viu_buf, vb.queue);
- list_del(&buf->vb.queue);
- buf->vb.state = VIDEOBUF_ERROR;
- wake_up(&buf->vb.done);
- dprintk(1, "viu/0: [%p/%d] timeout\n", buf, buf->vb.i);
- }
-
- restart_video_queue(vidq);
-}
-
-/*
- * Videobuf operations
- */
-static int buffer_setup(struct videobuf_queue *vq, unsigned int *count,
- unsigned int *size)
-{
- struct viu_fh *fh = vq->priv_data;
-
- *size = fh->width * fh->height * fh->fmt->depth >> 3;
- if (*count == 0)
- *count = 32;
-
- while (*size * *count > VIU_VID_MEM_LIMIT * 1024 * 1024)
- (*count)--;
-
- dprintk(1, "%s, count=%d, size=%d\n", __func__, *count, *size);
- return 0;
-}
-
-static void free_buffer(struct videobuf_queue *vq, struct viu_buf *buf)
-{
- struct videobuf_buffer *vb = &buf->vb;
- void *vaddr = NULL;
-
- videobuf_waiton(vq, &buf->vb, 0, 0);
-
- if (vq->int_ops && vq->int_ops->vaddr)
- vaddr = vq->int_ops->vaddr(vb);
-
- if (vaddr)
- videobuf_dma_contig_free(vq, &buf->vb);
-
- buf->vb.state = VIDEOBUF_NEEDS_INIT;
-}
-
-inline int buffer_activate(struct viu_dev *dev, struct viu_buf *buf)
-{
- struct viu_reg __iomem *vr = dev->vr;
- int bpp;
-
- /* setup the DMA base address */
- reg_val.field_base_addr = videobuf_to_dma_contig(&buf->vb);
-
- dprintk(1, "buffer_activate [%p/%d]: dma addr 0x%lx\n",
- buf, buf->vb.i, (unsigned long)reg_val.field_base_addr);
-
- /* interlace is on by default, set horizontal DMA increment */
- reg_val.status_cfg = 0;
- bpp = buf->fmt->depth >> 3;
- switch (bpp) {
- case 2:
- reg_val.status_cfg &= ~MODE_32BIT;
- reg_val.dma_inc = buf->vb.width * 2;
- break;
- case 4:
- reg_val.status_cfg |= MODE_32BIT;
- reg_val.dma_inc = buf->vb.width * 4;
- break;
- default:
- dprintk(0, "doesn't support color depth(%d)\n",
- bpp * 8);
- return -EINVAL;
- }
-
- /* setup picture_count register */
- reg_val.picture_count = (buf->vb.height / 2) << 16 |
- buf->vb.width;
-
- reg_val.status_cfg |= DMA_ACT | INT_DMA_END_EN | INT_FIELD_EN;
-
- buf->vb.state = VIDEOBUF_ACTIVE;
- dev->capfield = buf->vb.field;
-
- /* reset dma increment if needed */
- if (!V4L2_FIELD_HAS_BOTH(buf->vb.field))
- reg_val.dma_inc = 0;
-
- iowrite32be(reg_val.dma_inc, &vr->dma_inc);
- iowrite32be(reg_val.picture_count, &vr->picture_count);
- iowrite32be(reg_val.field_base_addr, &vr->field_base_addr);
- mod_timer(&dev->vidq.timeout, jiffies + BUFFER_TIMEOUT);
- return 0;
-}
-
-static int buffer_prepare(struct videobuf_queue *vq,
- struct videobuf_buffer *vb,
- enum v4l2_field field)
-{
- struct viu_fh *fh = vq->priv_data;
- struct viu_buf *buf = container_of(vb, struct viu_buf, vb);
- int rc;
-
- BUG_ON(fh->fmt == NULL);
-
- if (fh->width < 48 || fh->width > norm_maxw() ||
- fh->height < 32 || fh->height > norm_maxh())
- return -EINVAL;
- buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3;
- if (buf->vb.baddr != 0 && buf->vb.bsize < buf->vb.size)
- return -EINVAL;
-
- if (buf->fmt != fh->fmt ||
- buf->vb.width != fh->width ||
- buf->vb.height != fh->height ||
- buf->vb.field != field) {
- buf->fmt = fh->fmt;
- buf->vb.width = fh->width;
- buf->vb.height = fh->height;
- buf->vb.field = field;
- }
-
- if (buf->vb.state == VIDEOBUF_NEEDS_INIT) {
- rc = videobuf_iolock(vq, &buf->vb, NULL);
- if (rc != 0)
- goto fail;
-
- buf->vb.width = fh->width;
- buf->vb.height = fh->height;
- buf->vb.field = field;
- buf->fmt = fh->fmt;
- }
-
- buf->vb.state = VIDEOBUF_PREPARED;
- return 0;
-
-fail:
- free_buffer(vq, buf);
- return rc;
-}
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
- struct viu_buf *buf = container_of(vb, struct viu_buf, vb);
- struct viu_fh *fh = vq->priv_data;
- struct viu_dev *dev = fh->dev;
- struct viu_dmaqueue *vidq = &dev->vidq;
- struct viu_buf *prev;
-
- if (!list_empty(&vidq->queued)) {
- dprintk(1, "adding vb queue=%p\n", &buf->vb.queue);
- dprintk(1, "vidq pointer 0x%p, queued 0x%p\n",
- vidq, &vidq->queued);
- dprintk(1, "dev %p, queued: self %p, next %p, head %p\n",
- dev, &vidq->queued, vidq->queued.next,
- vidq->queued.prev);
- list_add_tail(&buf->vb.queue, &vidq->queued);
- buf->vb.state = VIDEOBUF_QUEUED;
- dprintk(2, "[%p/%d] buffer_queue - append to queued\n",
- buf, buf->vb.i);
- } else if (list_empty(&vidq->active)) {
- dprintk(1, "adding vb active=%p\n", &buf->vb.queue);
- list_add_tail(&buf->vb.queue, &vidq->active);
- buf->vb.state = VIDEOBUF_ACTIVE;
- mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT);
- dprintk(2, "[%p/%d] buffer_queue - first active\n",
- buf, buf->vb.i);
-
- buffer_activate(dev, buf);
- } else {
- dprintk(1, "adding vb queue2=%p\n", &buf->vb.queue);
- prev = list_entry(vidq->active.prev, struct viu_buf, vb.queue);
- if (prev->vb.width == buf->vb.width &&
- prev->vb.height == buf->vb.height &&
- prev->fmt == buf->fmt) {
- list_add_tail(&buf->vb.queue, &vidq->active);
- buf->vb.state = VIDEOBUF_ACTIVE;
- dprintk(2, "[%p/%d] buffer_queue - append to active\n",
- buf, buf->vb.i);
- } else {
- list_add_tail(&buf->vb.queue, &vidq->queued);
- buf->vb.state = VIDEOBUF_QUEUED;
- dprintk(2, "[%p/%d] buffer_queue - first queued\n",
- buf, buf->vb.i);
- }
- }
-}
-
-static void buffer_release(struct videobuf_queue *vq,
- struct videobuf_buffer *vb)
-{
- struct viu_buf *buf = container_of(vb, struct viu_buf, vb);
- struct viu_fh *fh = vq->priv_data;
- struct viu_dev *dev = (struct viu_dev *)fh->dev;
-
- viu_stop_dma(dev);
- free_buffer(vq, buf);
-}
-
-static const struct videobuf_queue_ops viu_video_qops = {
- .buf_setup = buffer_setup,
- .buf_prepare = buffer_prepare,
- .buf_queue = buffer_queue,
- .buf_release = buffer_release,
-};
-
-/*
- * IOCTL vidioc handling
- */
-static int vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
- strscpy(cap->driver, "viu", sizeof(cap->driver));
- strscpy(cap->card, "viu", sizeof(cap->card));
- strscpy(cap->bus_info, "platform:viu", sizeof(cap->bus_info));
- return 0;
-}
-
-static int vidioc_enum_fmt(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
-{
- int index = f->index;
-
- if (f->index >= NUM_FORMATS)
- return -EINVAL;
-
- f->pixelformat = formats[index].fourcc;
- return 0;
-}
-
-static int vidioc_g_fmt_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct viu_fh *fh = priv;
-
- f->fmt.pix.width = fh->width;
- f->fmt.pix.height = fh->height;
- f->fmt.pix.field = fh->vb_vidq.field;
- f->fmt.pix.pixelformat = fh->fmt->pixelformat;
- f->fmt.pix.bytesperline =
- (f->fmt.pix.width * fh->fmt->depth) >> 3;
- f->fmt.pix.sizeimage = fh->sizeimage;
- f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
- return 0;
-}
-
-static int vidioc_try_fmt_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct viu_fmt *fmt;
- unsigned int maxw, maxh;
-
- fmt = format_by_fourcc(f->fmt.pix.pixelformat);
- if (!fmt) {
- dprintk(1, "Fourcc format (0x%08x) invalid.",
- f->fmt.pix.pixelformat);
- return -EINVAL;
- }
-
- maxw = norm_maxw();
- maxh = norm_maxh();
-
- f->fmt.pix.field = V4L2_FIELD_INTERLACED;
- if (f->fmt.pix.height < 32)
- f->fmt.pix.height = 32;
- if (f->fmt.pix.height > maxh)
- f->fmt.pix.height = maxh;
- if (f->fmt.pix.width < 48)
- f->fmt.pix.width = 48;
- if (f->fmt.pix.width > maxw)
- f->fmt.pix.width = maxw;
- f->fmt.pix.width &= ~0x03;
- f->fmt.pix.bytesperline =
- (f->fmt.pix.width * fmt->depth) >> 3;
- f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
- f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
-
- return 0;
-}
-
-static int vidioc_s_fmt_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct viu_fh *fh = priv;
- int ret;
-
- ret = vidioc_try_fmt_cap(file, fh, f);
- if (ret < 0)
- return ret;
-
- fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
- fh->width = f->fmt.pix.width;
- fh->height = f->fmt.pix.height;
- fh->sizeimage = f->fmt.pix.sizeimage;
- fh->vb_vidq.field = f->fmt.pix.field;
- fh->type = f->type;
- return 0;
-}
-
-static int vidioc_g_fmt_overlay(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct viu_fh *fh = priv;
-
- f->fmt.win = fh->win;
- return 0;
-}
-
-static int verify_preview(struct viu_dev *dev, struct v4l2_window *win)
-{
- enum v4l2_field field;
- int maxw, maxh;
-
- if (dev->ovbuf.base == NULL)
- return -EINVAL;
- if (dev->ovfmt == NULL)
- return -EINVAL;
- if (win->w.width < 48 || win->w.height < 32)
- return -EINVAL;
-
- field = win->field;
- maxw = dev->crop_current.width;
- maxh = dev->crop_current.height;
-
- if (field == V4L2_FIELD_ANY) {
- field = (win->w.height > maxh/2)
- ? V4L2_FIELD_INTERLACED
- : V4L2_FIELD_TOP;
- }
- switch (field) {
- case V4L2_FIELD_TOP:
- case V4L2_FIELD_BOTTOM:
- maxh = maxh / 2;
- break;
- case V4L2_FIELD_INTERLACED:
- break;
- default:
- return -EINVAL;
- }
-
- win->field = field;
- if (win->w.width > maxw)
- win->w.width = maxw;
- if (win->w.height > maxh)
- win->w.height = maxh;
- return 0;
-}
-
-inline void viu_activate_overlay(struct viu_reg __iomem *vr)
-{
- iowrite32be(reg_val.field_base_addr, &vr->field_base_addr);
- iowrite32be(reg_val.dma_inc, &vr->dma_inc);
- iowrite32be(reg_val.picture_count, &vr->picture_count);
-}
-
-static int viu_setup_preview(struct viu_dev *dev, struct viu_fh *fh)
-{
- int bpp;
-
- dprintk(1, "%s %dx%d\n", __func__,
- fh->win.w.width, fh->win.w.height);
-
- reg_val.status_cfg = 0;
-
- /* setup window */
- reg_val.picture_count = (fh->win.w.height / 2) << 16 |
- fh->win.w.width;
-
- /* setup color depth and dma increment */
- bpp = dev->ovfmt->depth / 8;
- switch (bpp) {
- case 2:
- reg_val.status_cfg &= ~MODE_32BIT;
- reg_val.dma_inc = fh->win.w.width * 2;
- break;
- case 4:
- reg_val.status_cfg |= MODE_32BIT;
- reg_val.dma_inc = fh->win.w.width * 4;
- break;
- default:
- dprintk(0, "device doesn't support color depth(%d)\n",
- bpp * 8);
- return -EINVAL;
- }
-
- dev->ovfield = fh->win.field;
- if (!V4L2_FIELD_HAS_BOTH(dev->ovfield))
- reg_val.dma_inc = 0;
-
- reg_val.status_cfg |= DMA_ACT | INT_DMA_END_EN | INT_FIELD_EN;
-
- /* setup the base address of the overlay buffer */
- reg_val.field_base_addr = (u32)(long)dev->ovbuf.base;
-
- return 0;
-}
-
-static int vidioc_s_fmt_overlay(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct viu_fh *fh = priv;
- struct viu_dev *dev = (struct viu_dev *)fh->dev;
- unsigned long flags;
- int err;
-
- err = verify_preview(dev, &f->fmt.win);
- if (err)
- return err;
-
- fh->win = f->fmt.win;
-
- spin_lock_irqsave(&dev->slock, flags);
- viu_setup_preview(dev, fh);
- spin_unlock_irqrestore(&dev->slock, flags);
- return 0;
-}
-
-static int vidioc_try_fmt_overlay(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- return 0;
-}
-
-static int vidioc_overlay(struct file *file, void *priv, unsigned int on)
-{
- struct viu_fh *fh = priv;
- struct viu_dev *dev = (struct viu_dev *)fh->dev;
- unsigned long flags;
-
- if (on) {
- spin_lock_irqsave(&dev->slock, flags);
- viu_activate_overlay(dev->vr);
- dev->ovenable = 1;
-
- /* start dma */
- viu_start_dma(dev);
- spin_unlock_irqrestore(&dev->slock, flags);
- } else {
- viu_stop_dma(dev);
- dev->ovenable = 0;
- }
-
- return 0;
-}
-
-static int vidioc_g_fbuf(struct file *file, void *priv, struct v4l2_framebuffer *arg)
-{
- struct viu_fh *fh = priv;
- struct viu_dev *dev = fh->dev;
- struct v4l2_framebuffer *fb = arg;
-
- *fb = dev->ovbuf;
- fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
- return 0;
-}
-
-static int vidioc_s_fbuf(struct file *file, void *priv, const struct v4l2_framebuffer *arg)
-{
- struct viu_fh *fh = priv;
- struct viu_dev *dev = fh->dev;
- const struct v4l2_framebuffer *fb = arg;
- struct viu_fmt *fmt;
-
- if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO))
- return -EPERM;
-
- /* check args */
- fmt = format_by_fourcc(fb->fmt.pixelformat);
- if (fmt == NULL)
- return -EINVAL;
-
- /* ok, accept it */
- dev->ovbuf = *fb;
- dev->ovfmt = fmt;
- if (dev->ovbuf.fmt.bytesperline == 0) {
- dev->ovbuf.fmt.bytesperline =
- dev->ovbuf.fmt.width * fmt->depth / 8;
- }
- return 0;
-}
-
-static int vidioc_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *p)
-{
- struct viu_fh *fh = priv;
-
- return videobuf_reqbufs(&fh->vb_vidq, p);
-}
-
-static int vidioc_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *p)
-{
- struct viu_fh *fh = priv;
-
- return videobuf_querybuf(&fh->vb_vidq, p);
-}
-
-static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- struct viu_fh *fh = priv;
-
- return videobuf_qbuf(&fh->vb_vidq, p);
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- struct viu_fh *fh = priv;
-
- return videobuf_dqbuf(&fh->vb_vidq, p,
- file->f_flags & O_NONBLOCK);
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct viu_fh *fh = priv;
- struct viu_dev *dev = fh->dev;
-
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (fh->type != i)
- return -EINVAL;
-
- if (dev->ovenable)
- dev->ovenable = 0;
-
- viu_start_dma(fh->dev);
-
- return videobuf_streamon(&fh->vb_vidq);
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct viu_fh *fh = priv;
-
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (fh->type != i)
- return -EINVAL;
-
- viu_stop_dma(fh->dev);
-
- return videobuf_streamoff(&fh->vb_vidq);
-}
-
-#define decoder_call(viu, o, f, args...) \
- v4l2_subdev_call(viu->decoder, o, f, ##args)
-
-static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *std_id)
-{
- struct viu_fh *fh = priv;
-
- decoder_call(fh->dev, video, querystd, std_id);
- return 0;
-}
-
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)
-{
- struct viu_fh *fh = priv;
-
- fh->dev->std = id;
- decoder_call(fh->dev, video, s_std, id);
- return 0;
-}
-
-static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *std_id)
-{
- struct viu_fh *fh = priv;
-
- *std_id = fh->dev->std;
- return 0;
-}
-
-/* only one input in this driver */
-static int vidioc_enum_input(struct file *file, void *priv,
- struct v4l2_input *inp)
-{
- struct viu_fh *fh = priv;
-
- if (inp->index != 0)
- return -EINVAL;
-
- inp->type = V4L2_INPUT_TYPE_CAMERA;
- inp->std = fh->dev->vdev->tvnorms;
- strscpy(inp->name, "Camera", sizeof(inp->name));
- return 0;
-}
-
-static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
-{
- *i = 0;
- return 0;
-}
-
-static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
-{
- struct viu_fh *fh = priv;
-
- if (i)
- return -EINVAL;
-
- decoder_call(fh->dev, video, s_routing, i, 0, 0);
- return 0;
-}
-
-inline void viu_activate_next_buf(struct viu_dev *dev,
- struct viu_dmaqueue *viuq)
-{
- struct viu_dmaqueue *vidq = viuq;
- struct viu_buf *buf;
-
- /* launch another DMA operation for an active/queued buffer */
- if (!list_empty(&vidq->active)) {
- buf = list_entry(vidq->active.next, struct viu_buf,
- vb.queue);
- dprintk(1, "start another queued buffer: 0x%p\n", buf);
- buffer_activate(dev, buf);
- } else if (!list_empty(&vidq->queued)) {
- buf = list_entry(vidq->queued.next, struct viu_buf,
- vb.queue);
- list_del(&buf->vb.queue);
-
- dprintk(1, "start another queued buffer: 0x%p\n", buf);
- list_add_tail(&buf->vb.queue, &vidq->active);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buffer_activate(dev, buf);
- }
-}
-
-inline void viu_default_settings(struct viu_reg __iomem *vr)
-{
- iowrite32be(0x9512A254, &vr->luminance);
- iowrite32be(0x03310000, &vr->chroma_r);
- iowrite32be(0x06600F38, &vr->chroma_g);
- iowrite32be(0x00000409, &vr->chroma_b);
- iowrite32be(0x000000ff, &vr->alpha);
- iowrite32be(0x00000090, &vr->req_alarm);
- dprintk(1, "status reg: 0x%08x, field base: 0x%08x\n",
- ioread32be(&vr->status_cfg), ioread32be(&vr->field_base_addr));
-}
-
-static void viu_overlay_intr(struct viu_dev *dev, u32 status)
-{
- struct viu_reg __iomem *vr = dev->vr;
-
- if (status & INT_DMA_END_STATUS)
- dev->dma_done = 1;
-
- if (status & INT_FIELD_STATUS) {
- if (dev->dma_done) {
- u32 addr = reg_val.field_base_addr;
-
- dev->dma_done = 0;
- if (status & FIELD_NO)
- addr += reg_val.dma_inc;
-
- iowrite32be(addr, &vr->field_base_addr);
- iowrite32be(reg_val.dma_inc, &vr->dma_inc);
- iowrite32be((status & 0xffc0ffff) |
- (status & INT_ALL_STATUS) |
- reg_val.status_cfg, &vr->status_cfg);
- } else if (status & INT_VSYNC_STATUS) {
- iowrite32be((status & 0xffc0ffff) |
- (status & INT_ALL_STATUS) |
- reg_val.status_cfg, &vr->status_cfg);
- }
- }
-}
-
-static void viu_capture_intr(struct viu_dev *dev, u32 status)
-{
- struct viu_dmaqueue *vidq = &dev->vidq;
- struct viu_reg __iomem *vr = dev->vr;
- struct viu_buf *buf;
- int field_num;
- int need_two;
- int dma_done = 0;
-
- field_num = status & FIELD_NO;
- need_two = V4L2_FIELD_HAS_BOTH(dev->capfield);
-
- if (status & INT_DMA_END_STATUS) {
- dma_done = 1;
- if (((field_num == 0) && (dev->field == 0)) ||
- (field_num && (dev->field == 1)))
- dev->field++;
- }
-
- if (status & INT_FIELD_STATUS) {
- dprintk(1, "irq: field %d, done %d\n",
- !!field_num, dma_done);
- if (unlikely(dev->first)) {
- if (field_num == 0) {
- dev->first = 0;
- dprintk(1, "activate first buf\n");
- viu_activate_next_buf(dev, vidq);
- } else
- dprintk(1, "wait field 0\n");
- return;
- }
-
- /* setup buffer address for next dma operation */
- if (!list_empty(&vidq->active)) {
- u32 addr = reg_val.field_base_addr;
-
- if (field_num && need_two) {
- addr += reg_val.dma_inc;
- dprintk(1, "field 1, 0x%lx, dev field %d\n",
- (unsigned long)addr, dev->field);
- }
- iowrite32be(addr, &vr->field_base_addr);
- iowrite32be(reg_val.dma_inc, &vr->dma_inc);
- iowrite32be((status & 0xffc0ffff) |
- (status & INT_ALL_STATUS) |
- reg_val.status_cfg, &vr->status_cfg);
- return;
- }
- }
-
- if (dma_done && field_num && (dev->field == 2)) {
- dev->field = 0;
- buf = list_entry(vidq->active.next,
- struct viu_buf, vb.queue);
- dprintk(1, "viu/0: [%p/%d] 0x%lx/0x%lx: dma complete\n",
- buf, buf->vb.i,
- (unsigned long)videobuf_to_dma_contig(&buf->vb),
- (unsigned long)ioread32be(&vr->field_base_addr));
-
- if (waitqueue_active(&buf->vb.done)) {
- list_del(&buf->vb.queue);
- buf->vb.ts = ktime_get_ns();
- buf->vb.state = VIDEOBUF_DONE;
- buf->vb.field_count++;
- wake_up(&buf->vb.done);
- }
- /* activate next dma buffer */
- viu_activate_next_buf(dev, vidq);
- }
-}
-
-static irqreturn_t viu_intr(int irq, void *dev_id)
-{
- struct viu_dev *dev = (struct viu_dev *)dev_id;
- struct viu_reg __iomem *vr = dev->vr;
- u32 status;
- u32 error;
-
- status = ioread32be(&vr->status_cfg);
-
- if (status & INT_ERROR_STATUS) {
- dev->irqs.error_irq++;
- error = status & ERR_MASK;
- if (error)
- dprintk(1, "Err: error(%d), times:%d!\n",
- error >> 4, dev->irqs.error_irq);
- /* Clear interrupt error bit and error flags */
- iowrite32be((status & 0xffc0ffff) | INT_ERROR_STATUS,
- &vr->status_cfg);
- }
-
- if (status & INT_DMA_END_STATUS) {
- dev->irqs.dma_end_irq++;
- dev->dma_done = 1;
- dprintk(2, "VIU DMA end interrupt times: %d\n",
- dev->irqs.dma_end_irq);
- }
-
- if (status & INT_HSYNC_STATUS)
- dev->irqs.hsync_irq++;
-
- if (status & INT_FIELD_STATUS) {
- dev->irqs.field_irq++;
- dprintk(2, "VIU field interrupt times: %d\n",
- dev->irqs.field_irq);
- }
-
- if (status & INT_VSTART_STATUS)
- dev->irqs.vstart_irq++;
-
- if (status & INT_VSYNC_STATUS) {
- dev->irqs.vsync_irq++;
- dprintk(2, "VIU vsync interrupt times: %d\n",
- dev->irqs.vsync_irq);
- }
-
- /* clear all pending irqs */
- status = ioread32be(&vr->status_cfg);
- iowrite32be((status & 0xffc0ffff) | (status & INT_ALL_STATUS),
- &vr->status_cfg);
-
- if (dev->ovenable) {
- viu_overlay_intr(dev, status);
- return IRQ_HANDLED;
- }
-
- /* Capture mode */
- viu_capture_intr(dev, status);
- return IRQ_HANDLED;
-}
-
-/*
- * File operations for the device
- */
-static int viu_open(struct file *file)
-{
- struct video_device *vdev = video_devdata(file);
- struct viu_dev *dev = video_get_drvdata(vdev);
- struct viu_fh *fh;
- struct viu_reg __iomem *vr;
- int minor = vdev->minor;
- u32 status_cfg;
-
- dprintk(1, "viu: open (minor=%d)\n", minor);
-
- dev->users++;
- if (dev->users > 1) {
- dev->users--;
- return -EBUSY;
- }
-
- vr = dev->vr;
-
- dprintk(1, "open minor=%d type=%s users=%d\n", minor,
- v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users);
-
- if (mutex_lock_interruptible(&dev->lock)) {
- dev->users--;
- return -ERESTARTSYS;
- }
-
- /* allocate and initialize per filehandle data */
- fh = kzalloc(sizeof(*fh), GFP_KERNEL);
- if (!fh) {
- dev->users--;
- mutex_unlock(&dev->lock);
- return -ENOMEM;
- }
-
- v4l2_fh_init(&fh->fh, vdev);
- file->private_data = fh;
- fh->dev = dev;
-
- fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- fh->fmt = format_by_fourcc(V4L2_PIX_FMT_RGB32);
- fh->width = norm_maxw();
- fh->height = norm_maxh();
- dev->crop_current.width = fh->width;
- dev->crop_current.height = fh->height;
-
- dprintk(1, "Open: fh=%p, dev=%p, dev->vidq=%p\n", fh, dev, &dev->vidq);
- dprintk(1, "Open: list_empty queued=%d\n",
- list_empty(&dev->vidq.queued));
- dprintk(1, "Open: list_empty active=%d\n",
- list_empty(&dev->vidq.active));
-
- viu_default_settings(vr);
-
- status_cfg = ioread32be(&vr->status_cfg);
- iowrite32be(status_cfg & ~(INT_VSYNC_EN | INT_HSYNC_EN |
- INT_FIELD_EN | INT_VSTART_EN |
- INT_DMA_END_EN | INT_ERROR_EN | INT_ECC_EN),
- &vr->status_cfg);
-
- status_cfg = ioread32be(&vr->status_cfg);
- iowrite32be(status_cfg | INT_ALL_STATUS, &vr->status_cfg);
-
- spin_lock_init(&fh->vbq_lock);
- videobuf_queue_dma_contig_init(&fh->vb_vidq, &viu_video_qops,
- dev->dev, &fh->vbq_lock,
- fh->type, V4L2_FIELD_INTERLACED,
- sizeof(struct viu_buf), fh,
- &fh->dev->lock);
- v4l2_fh_add(&fh->fh);
- mutex_unlock(&dev->lock);
- return 0;
-}
-
-static ssize_t viu_read(struct file *file, char __user *data, size_t count,
- loff_t *ppos)
-{
- struct viu_fh *fh = file->private_data;
- struct viu_dev *dev = fh->dev;
- int ret = 0;
-
- dprintk(2, "%s\n", __func__);
- if (dev->ovenable)
- dev->ovenable = 0;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- if (mutex_lock_interruptible(&dev->lock))
- return -ERESTARTSYS;
- viu_start_dma(dev);
- ret = videobuf_read_stream(&fh->vb_vidq, data, count,
- ppos, 0, file->f_flags & O_NONBLOCK);
- mutex_unlock(&dev->lock);
- return ret;
- }
- return 0;
-}
-
-static __poll_t viu_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct viu_fh *fh = file->private_data;
- struct videobuf_queue *q = &fh->vb_vidq;
- struct viu_dev *dev = fh->dev;
- __poll_t req_events = poll_requested_events(wait);
- __poll_t res = v4l2_ctrl_poll(file, wait);
-
- if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
- return EPOLLERR;
-
- if (!(req_events & (EPOLLIN | EPOLLRDNORM)))
- return res;
-
- mutex_lock(&dev->lock);
- res |= videobuf_poll_stream(file, q, wait);
- mutex_unlock(&dev->lock);
- return res;
-}
-
-static int viu_release(struct file *file)
-{
- struct viu_fh *fh = file->private_data;
- struct viu_dev *dev = fh->dev;
- int minor = video_devdata(file)->minor;
-
- mutex_lock(&dev->lock);
- viu_stop_dma(dev);
- videobuf_stop(&fh->vb_vidq);
- videobuf_mmap_free(&fh->vb_vidq);
- v4l2_fh_del(&fh->fh);
- v4l2_fh_exit(&fh->fh);
- mutex_unlock(&dev->lock);
-
- kfree(fh);
-
- dev->users--;
- dprintk(1, "close (minor=%d, users=%d)\n",
- minor, dev->users);
- return 0;
-}
-
-static void viu_reset(struct viu_reg __iomem *reg)
-{
- iowrite32be(0, &reg->status_cfg);
- iowrite32be(0x9512a254, &reg->luminance);
- iowrite32be(0x03310000, &reg->chroma_r);
- iowrite32be(0x06600f38, &reg->chroma_g);
- iowrite32be(0x00000409, &reg->chroma_b);
- iowrite32be(0, &reg->field_base_addr);
- iowrite32be(0, &reg->dma_inc);
- iowrite32be(0x01e002d0, &reg->picture_count);
- iowrite32be(0x00000090, &reg->req_alarm);
- iowrite32be(0x000000ff, &reg->alpha);
-}
-
-static int viu_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct viu_fh *fh = file->private_data;
- struct viu_dev *dev = fh->dev;
- int ret;
-
- dprintk(1, "mmap called, vma=%p\n", vma);
-
- if (mutex_lock_interruptible(&dev->lock))
- return -ERESTARTSYS;
- ret = videobuf_mmap_mapper(&fh->vb_vidq, vma);
- mutex_unlock(&dev->lock);
-
- dprintk(1, "vma start=0x%08lx, size=%ld, ret=%d\n",
- (unsigned long)vma->vm_start,
- (unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
- ret);
-
- return ret;
-}
-
-static const struct v4l2_file_operations viu_fops = {
- .owner = THIS_MODULE,
- .open = viu_open,
- .release = viu_release,
- .read = viu_read,
- .poll = viu_poll,
- .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
- .mmap = viu_mmap,
-};
-
-static const struct v4l2_ioctl_ops viu_ioctl_ops = {
- .vidioc_querycap = vidioc_querycap,
- .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt,
- .vidioc_g_fmt_vid_cap = vidioc_g_fmt_cap,
- .vidioc_try_fmt_vid_cap = vidioc_try_fmt_cap,
- .vidioc_s_fmt_vid_cap = vidioc_s_fmt_cap,
- .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt,
- .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_overlay,
- .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_overlay,
- .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_overlay,
- .vidioc_overlay = vidioc_overlay,
- .vidioc_g_fbuf = vidioc_g_fbuf,
- .vidioc_s_fbuf = vidioc_s_fbuf,
- .vidioc_reqbufs = vidioc_reqbufs,
- .vidioc_querybuf = vidioc_querybuf,
- .vidioc_qbuf = vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
- .vidioc_g_std = vidioc_g_std,
- .vidioc_s_std = vidioc_s_std,
- .vidioc_querystd = vidioc_querystd,
- .vidioc_enum_input = vidioc_enum_input,
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
- .vidioc_log_status = v4l2_ctrl_log_status,
- .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
- .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
-};
-
-static const struct video_device viu_template = {
- .name = "FSL viu",
- .fops = &viu_fops,
- .minor = -1,
- .ioctl_ops = &viu_ioctl_ops,
- .release = video_device_release,
-
- .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL,
- .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
- V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_READWRITE,
-};
-
-static int viu_of_probe(struct platform_device *op)
-{
- struct viu_dev *viu_dev;
- struct video_device *vdev;
- struct resource r;
- struct viu_reg __iomem *viu_regs;
- struct i2c_adapter *ad;
- int ret, viu_irq;
- struct clk *clk;
-
- ret = of_address_to_resource(op->dev.of_node, 0, &r);
- if (ret) {
- dev_err(&op->dev, "Can't parse device node resource\n");
- return -ENODEV;
- }
-
- viu_irq = irq_of_parse_and_map(op->dev.of_node, 0);
- if (!viu_irq) {
- dev_err(&op->dev, "Error while mapping the irq\n");
- return -EINVAL;
- }
-
- /* request mem region */
- if (!devm_request_mem_region(&op->dev, r.start,
- sizeof(struct viu_reg), DRV_NAME)) {
- dev_err(&op->dev, "Error while requesting mem region\n");
- ret = -EBUSY;
- goto err_irq;
- }
-
- /* remap registers */
- viu_regs = devm_ioremap(&op->dev, r.start, sizeof(struct viu_reg));
- if (!viu_regs) {
- dev_err(&op->dev, "Can't map register set\n");
- ret = -ENOMEM;
- goto err_irq;
- }
-
- /* Prepare our private structure */
- viu_dev = devm_kzalloc(&op->dev, sizeof(struct viu_dev), GFP_KERNEL);
- if (!viu_dev) {
- dev_err(&op->dev, "Can't allocate private structure\n");
- ret = -ENOMEM;
- goto err_irq;
- }
-
- viu_dev->vr = viu_regs;
- viu_dev->irq = viu_irq;
- viu_dev->dev = &op->dev;
-
- /* init video dma queues */
- INIT_LIST_HEAD(&viu_dev->vidq.active);
- INIT_LIST_HEAD(&viu_dev->vidq.queued);
-
- snprintf(viu_dev->v4l2_dev.name,
- sizeof(viu_dev->v4l2_dev.name), "%s", "VIU");
- ret = v4l2_device_register(viu_dev->dev, &viu_dev->v4l2_dev);
- if (ret < 0) {
- dev_err(&op->dev, "v4l2_device_register() failed: %d\n", ret);
- goto err_irq;
- }
-
- ad = i2c_get_adapter(0);
- if (!ad) {
- ret = -EFAULT;
- dev_err(&op->dev, "couldn't get i2c adapter\n");
- goto err_v4l2;
- }
-
- v4l2_ctrl_handler_init(&viu_dev->hdl, 5);
- if (viu_dev->hdl.error) {
- ret = viu_dev->hdl.error;
- dev_err(&op->dev, "couldn't register control\n");
- goto err_i2c;
- }
- /* This control handler will inherit the control(s) from the
- sub-device(s). */
- viu_dev->v4l2_dev.ctrl_handler = &viu_dev->hdl;
- viu_dev->decoder = v4l2_i2c_new_subdev(&viu_dev->v4l2_dev, ad,
- "saa7113", VIU_VIDEO_DECODER_ADDR, NULL);
-
- timer_setup(&viu_dev->vidq.timeout, viu_vid_timeout, 0);
- viu_dev->std = V4L2_STD_NTSC_M;
- viu_dev->first = 1;
-
- /* Allocate memory for video device */
- vdev = video_device_alloc();
- if (vdev == NULL) {
- ret = -ENOMEM;
- goto err_hdl;
- }
-
- *vdev = viu_template;
-
- vdev->v4l2_dev = &viu_dev->v4l2_dev;
-
- viu_dev->vdev = vdev;
-
- /* initialize locks */
- mutex_init(&viu_dev->lock);
- viu_dev->vdev->lock = &viu_dev->lock;
- spin_lock_init(&viu_dev->slock);
-
- video_set_drvdata(viu_dev->vdev, viu_dev);
-
- mutex_lock(&viu_dev->lock);
-
- ret = video_register_device(viu_dev->vdev, VFL_TYPE_VIDEO, -1);
- if (ret < 0) {
- video_device_release(viu_dev->vdev);
- goto err_unlock;
- }
-
- /* enable VIU clock */
- clk = devm_clk_get(&op->dev, "ipg");
- if (IS_ERR(clk)) {
- dev_err(&op->dev, "failed to lookup the clock!\n");
- ret = PTR_ERR(clk);
- goto err_vdev;
- }
- ret = clk_prepare_enable(clk);
- if (ret) {
- dev_err(&op->dev, "failed to enable the clock!\n");
- goto err_vdev;
- }
- viu_dev->clk = clk;
-
- /* reset VIU module */
- viu_reset(viu_dev->vr);
-
- /* install interrupt handler */
- if (request_irq(viu_dev->irq, viu_intr, 0, "viu", (void *)viu_dev)) {
- dev_err(&op->dev, "Request VIU IRQ failed.\n");
- ret = -ENODEV;
- goto err_clk;
- }
-
- mutex_unlock(&viu_dev->lock);
-
- dev_info(&op->dev, "Freescale VIU Video Capture Board\n");
- return ret;
-
-err_clk:
- clk_disable_unprepare(viu_dev->clk);
-err_vdev:
- video_unregister_device(viu_dev->vdev);
-err_unlock:
- mutex_unlock(&viu_dev->lock);
-err_hdl:
- v4l2_ctrl_handler_free(&viu_dev->hdl);
-err_i2c:
- i2c_put_adapter(ad);
-err_v4l2:
- v4l2_device_unregister(&viu_dev->v4l2_dev);
-err_irq:
- irq_dispose_mapping(viu_irq);
- return ret;
-}
-
-static int viu_of_remove(struct platform_device *op)
-{
- struct v4l2_device *v4l2_dev = platform_get_drvdata(op);
- struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev);
- struct v4l2_subdev *sdev = list_entry(v4l2_dev->subdevs.next,
- struct v4l2_subdev, list);
- struct i2c_client *client = v4l2_get_subdevdata(sdev);
-
- free_irq(dev->irq, (void *)dev);
- irq_dispose_mapping(dev->irq);
-
- clk_disable_unprepare(dev->clk);
-
- v4l2_ctrl_handler_free(&dev->hdl);
- video_unregister_device(dev->vdev);
- i2c_put_adapter(client->adapter);
- v4l2_device_unregister(&dev->v4l2_dev);
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int viu_suspend(struct platform_device *op, pm_message_t state)
-{
- struct v4l2_device *v4l2_dev = platform_get_drvdata(op);
- struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev);
-
- clk_disable(dev->clk);
- return 0;
-}
-
-static int viu_resume(struct platform_device *op)
-{
- struct v4l2_device *v4l2_dev = platform_get_drvdata(op);
- struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev);
-
- clk_enable(dev->clk);
- return 0;
-}
-#endif
-
-/*
- * Initialization and module stuff
- */
-static const struct of_device_id mpc512x_viu_of_match[] = {
- {
- .compatible = "fsl,mpc5121-viu",
- },
- {},
-};
-MODULE_DEVICE_TABLE(of, mpc512x_viu_of_match);
-
-static struct platform_driver viu_of_platform_driver = {
- .probe = viu_of_probe,
- .remove = viu_of_remove,
-#ifdef CONFIG_PM
- .suspend = viu_suspend,
- .resume = viu_resume,
-#endif
- .driver = {
- .name = DRV_NAME,
- .of_match_table = mpc512x_viu_of_match,
- },
-};
-
-module_platform_driver(viu_of_platform_driver);
-
-MODULE_DESCRIPTION("Freescale Video-In(VIU)");
-MODULE_AUTHOR("Hongjun Chen");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(VIU_VERSION);
diff --git a/drivers/staging/media/deprecated/meye/Kconfig b/drivers/staging/media/deprecated/meye/Kconfig
deleted file mode 100644
index f135f8568c85..000000000000
--- a/drivers/staging/media/deprecated/meye/Kconfig
+++ /dev/null
@@ -1,19 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-config VIDEO_MEYE
- tristate "Sony Vaio Picturebook Motion Eye Video For Linux (DEPRECATED)"
- depends on PCI && VIDEO_DEV
- depends on SONY_LAPTOP
- depends on X86 || COMPILE_TEST
- help
- This is the video4linux driver for the Motion Eye camera found
- in the Vaio Picturebook laptops. Please read the material in
- <file:Documentation/admin-guide/media/meye.rst> for more information.
-
- If you say Y or M here, you need to say Y or M to "Sony Laptop
- Extras" in the misc device section.
-
- This driver is deprecated and is scheduled for removal by
- the beginning of 2023. See the TODO file for more information.
-
- To compile this driver as a module, choose M here: the
- module will be called meye.
diff --git a/drivers/staging/media/deprecated/meye/Makefile b/drivers/staging/media/deprecated/meye/Makefile
deleted file mode 100644
index 36f1f86f0d58..000000000000
--- a/drivers/staging/media/deprecated/meye/Makefile
+++ /dev/null
@@ -1,2 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_VIDEO_MEYE) += meye.o
diff --git a/drivers/staging/media/deprecated/meye/TODO b/drivers/staging/media/deprecated/meye/TODO
deleted file mode 100644
index 6d1d1433d5a0..000000000000
--- a/drivers/staging/media/deprecated/meye/TODO
+++ /dev/null
@@ -1,6 +0,0 @@
-The meye driver does not use the vb2 framework for streaming
-video, instead it implements this in the driver.
-
-To prevent removal of this driver early 2023 it has to be
-converted to use vb2. Contact the linux-media@vger.kernel.org
-mailing list if you want to do this.
diff --git a/drivers/staging/media/deprecated/meye/meye.c b/drivers/staging/media/deprecated/meye/meye.c
deleted file mode 100644
index 5d87efd9b95c..000000000000
--- a/drivers/staging/media/deprecated/meye/meye.c
+++ /dev/null
@@ -1,1814 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Motion Eye video4linux driver for Sony Vaio PictureBook
- *
- * Copyright (C) 2001-2004 Stelian Pop <stelian@popies.net>
- *
- * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
- *
- * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com>
- *
- * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras.
- *
- * Some parts borrowed from various video4linux drivers, especially
- * bttv-driver.c and zoran.c, see original files for credits.
- */
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/gfp.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-fh.h>
-#include <media/v4l2-event.h>
-#include <linux/uaccess.h>
-#include <asm/io.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/vmalloc.h>
-#include <linux/dma-mapping.h>
-
-#include "meye.h"
-#include <linux/meye.h>
-
-MODULE_AUTHOR("Stelian Pop <stelian@popies.net>");
-MODULE_DESCRIPTION("v4l2 driver for the MotionEye camera");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(MEYE_DRIVER_VERSION);
-
-/* number of grab buffers */
-static unsigned int gbuffers = 2;
-module_param(gbuffers, int, 0444);
-MODULE_PARM_DESC(gbuffers, "number of capture buffers, default is 2 (32 max)");
-
-/* size of a grab buffer */
-static unsigned int gbufsize = MEYE_MAX_BUFSIZE;
-module_param(gbufsize, int, 0444);
-MODULE_PARM_DESC(gbufsize, "size of the capture buffers, default is 614400 (will be rounded up to a page multiple)");
-
-/* /dev/videoX registration number */
-static int video_nr = -1;
-module_param(video_nr, int, 0444);
-MODULE_PARM_DESC(video_nr, "video device to register (0=/dev/video0, etc)");
-
-/* driver structure - only one possible */
-static struct meye meye;
-
-/****************************************************************************/
-/* Memory allocation routines (stolen from bttv-driver.c) */
-/****************************************************************************/
-static void *rvmalloc(unsigned long size)
-{
- void *mem;
- unsigned long adr;
-
- size = PAGE_ALIGN(size);
- mem = vmalloc_32(size);
- if (mem) {
- memset(mem, 0, size);
- adr = (unsigned long) mem;
- while (size > 0) {
- SetPageReserved(vmalloc_to_page((void *)adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
- }
- return mem;
-}
-
-static void rvfree(void * mem, unsigned long size)
-{
- unsigned long adr;
-
- if (mem) {
- adr = (unsigned long) mem;
- while ((long) size > 0) {
- ClearPageReserved(vmalloc_to_page((void *)adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
- vfree(mem);
- }
-}
-
-/*
- * return a page table pointing to N pages of locked memory
- *
- * NOTE: The meye device expects DMA addresses on 32 bits, we build
- * a table of 1024 entries = 4 bytes * 1024 = 4096 bytes.
- */
-static int ptable_alloc(void)
-{
- u32 *pt;
- int i;
-
- memset(meye.mchip_ptable, 0, sizeof(meye.mchip_ptable));
-
- /* give only 32 bit DMA addresses */
- if (dma_set_mask(&meye.mchip_dev->dev, DMA_BIT_MASK(32)))
- return -1;
-
- meye.mchip_ptable_toc = dma_alloc_coherent(&meye.mchip_dev->dev,
- PAGE_SIZE,
- &meye.mchip_dmahandle,
- GFP_KERNEL);
- if (!meye.mchip_ptable_toc) {
- meye.mchip_dmahandle = 0;
- return -1;
- }
-
- pt = meye.mchip_ptable_toc;
- for (i = 0; i < MCHIP_NB_PAGES; i++) {
- dma_addr_t dma;
- meye.mchip_ptable[i] = dma_alloc_coherent(&meye.mchip_dev->dev,
- PAGE_SIZE,
- &dma,
- GFP_KERNEL);
- if (!meye.mchip_ptable[i]) {
- int j;
- pt = meye.mchip_ptable_toc;
- for (j = 0; j < i; ++j) {
- dma = (dma_addr_t) *pt;
- dma_free_coherent(&meye.mchip_dev->dev,
- PAGE_SIZE,
- meye.mchip_ptable[j], dma);
- pt++;
- }
- dma_free_coherent(&meye.mchip_dev->dev,
- PAGE_SIZE,
- meye.mchip_ptable_toc,
- meye.mchip_dmahandle);
- meye.mchip_ptable_toc = NULL;
- meye.mchip_dmahandle = 0;
- return -1;
- }
- *pt = (u32) dma;
- pt++;
- }
- return 0;
-}
-
-static void ptable_free(void)
-{
- u32 *pt;
- int i;
-
- pt = meye.mchip_ptable_toc;
- for (i = 0; i < MCHIP_NB_PAGES; i++) {
- dma_addr_t dma = (dma_addr_t) *pt;
- if (meye.mchip_ptable[i])
- dma_free_coherent(&meye.mchip_dev->dev,
- PAGE_SIZE,
- meye.mchip_ptable[i], dma);
- pt++;
- }
-
- if (meye.mchip_ptable_toc)
- dma_free_coherent(&meye.mchip_dev->dev,
- PAGE_SIZE,
- meye.mchip_ptable_toc,
- meye.mchip_dmahandle);
-
- memset(meye.mchip_ptable, 0, sizeof(meye.mchip_ptable));
- meye.mchip_ptable_toc = NULL;
- meye.mchip_dmahandle = 0;
-}
-
-/* copy data from ptable into buf */
-static void ptable_copy(u8 *buf, int start, int size, int pt_pages)
-{
- int i;
-
- for (i = 0; i < (size / PAGE_SIZE) * PAGE_SIZE; i += PAGE_SIZE) {
- memcpy(buf + i, meye.mchip_ptable[start++], PAGE_SIZE);
- if (start >= pt_pages)
- start = 0;
- }
- memcpy(buf + i, meye.mchip_ptable[start], size % PAGE_SIZE);
-}
-
-/****************************************************************************/
-/* JPEG tables at different qualities to load into the VRJ chip */
-/****************************************************************************/
-
-/* return a set of quantisation tables based on a quality from 1 to 10 */
-static u16 *jpeg_quantisation_tables(int *length, int quality)
-{
- static u16 jpeg_tables[][70] = { {
- 0xdbff, 0x4300, 0xff00, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
- 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
- 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
- 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
- 0xffff, 0xffff, 0xffff,
- 0xdbff, 0x4300, 0xff01, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
- 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
- 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
- 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
- 0xffff, 0xffff, 0xffff,
- },
- {
- 0xdbff, 0x4300, 0x5000, 0x3c37, 0x3c46, 0x5032, 0x4146, 0x5a46,
- 0x5055, 0x785f, 0x82c8, 0x6e78, 0x786e, 0xaff5, 0x91b9, 0xffc8,
- 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
- 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
- 0xffff, 0xffff, 0xffff,
- 0xdbff, 0x4300, 0x5501, 0x5a5a, 0x6978, 0xeb78, 0x8282, 0xffeb,
- 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
- 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
- 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
- 0xffff, 0xffff, 0xffff,
- },
- {
- 0xdbff, 0x4300, 0x2800, 0x1e1c, 0x1e23, 0x2819, 0x2123, 0x2d23,
- 0x282b, 0x3c30, 0x4164, 0x373c, 0x3c37, 0x587b, 0x495d, 0x9164,
- 0x9980, 0x8f96, 0x8c80, 0xa08a, 0xe6b4, 0xa0c3, 0xdaaa, 0x8aad,
- 0xc88c, 0xcbff, 0xeeda, 0xfff5, 0xffff, 0xc19b, 0xffff, 0xfaff,
- 0xe6ff, 0xfffd, 0xfff8,
- 0xdbff, 0x4300, 0x2b01, 0x2d2d, 0x353c, 0x763c, 0x4141, 0xf876,
- 0x8ca5, 0xf8a5, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8,
- 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8,
- 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8,
- 0xf8f8, 0xf8f8, 0xfff8,
- },
- {
- 0xdbff, 0x4300, 0x1b00, 0x1412, 0x1417, 0x1b11, 0x1617, 0x1e17,
- 0x1b1c, 0x2820, 0x2b42, 0x2528, 0x2825, 0x3a51, 0x303d, 0x6042,
- 0x6555, 0x5f64, 0x5d55, 0x6a5b, 0x9978, 0x6a81, 0x9071, 0x5b73,
- 0x855d, 0x86b5, 0x9e90, 0xaba3, 0xabad, 0x8067, 0xc9bc, 0xa6ba,
- 0x99c7, 0xaba8, 0xffa4,
- 0xdbff, 0x4300, 0x1c01, 0x1e1e, 0x2328, 0x4e28, 0x2b2b, 0xa44e,
- 0x5d6e, 0xa46e, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4,
- 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4,
- 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4,
- 0xa4a4, 0xa4a4, 0xffa4,
- },
- {
- 0xdbff, 0x4300, 0x1400, 0x0f0e, 0x0f12, 0x140d, 0x1012, 0x1712,
- 0x1415, 0x1e18, 0x2132, 0x1c1e, 0x1e1c, 0x2c3d, 0x242e, 0x4932,
- 0x4c40, 0x474b, 0x4640, 0x5045, 0x735a, 0x5062, 0x6d55, 0x4556,
- 0x6446, 0x6588, 0x776d, 0x817b, 0x8182, 0x604e, 0x978d, 0x7d8c,
- 0x7396, 0x817e, 0xff7c,
- 0xdbff, 0x4300, 0x1501, 0x1717, 0x1a1e, 0x3b1e, 0x2121, 0x7c3b,
- 0x4653, 0x7c53, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c,
- 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c,
- 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c,
- 0x7c7c, 0x7c7c, 0xff7c,
- },
- {
- 0xdbff, 0x4300, 0x1000, 0x0c0b, 0x0c0e, 0x100a, 0x0d0e, 0x120e,
- 0x1011, 0x1813, 0x1a28, 0x1618, 0x1816, 0x2331, 0x1d25, 0x3a28,
- 0x3d33, 0x393c, 0x3833, 0x4037, 0x5c48, 0x404e, 0x5744, 0x3745,
- 0x5038, 0x516d, 0x5f57, 0x6762, 0x6768, 0x4d3e, 0x7971, 0x6470,
- 0x5c78, 0x6765, 0xff63,
- 0xdbff, 0x4300, 0x1101, 0x1212, 0x1518, 0x2f18, 0x1a1a, 0x632f,
- 0x3842, 0x6342, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363,
- 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363,
- 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363,
- 0x6363, 0x6363, 0xff63,
- },
- {
- 0xdbff, 0x4300, 0x0d00, 0x0a09, 0x0a0b, 0x0d08, 0x0a0b, 0x0e0b,
- 0x0d0e, 0x130f, 0x1520, 0x1213, 0x1312, 0x1c27, 0x171e, 0x2e20,
- 0x3129, 0x2e30, 0x2d29, 0x332c, 0x4a3a, 0x333e, 0x4636, 0x2c37,
- 0x402d, 0x4157, 0x4c46, 0x524e, 0x5253, 0x3e32, 0x615a, 0x505a,
- 0x4a60, 0x5251, 0xff4f,
- 0xdbff, 0x4300, 0x0e01, 0x0e0e, 0x1113, 0x2613, 0x1515, 0x4f26,
- 0x2d35, 0x4f35, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f,
- 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f,
- 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f,
- 0x4f4f, 0x4f4f, 0xff4f,
- },
- {
- 0xdbff, 0x4300, 0x0a00, 0x0707, 0x0708, 0x0a06, 0x0808, 0x0b08,
- 0x0a0a, 0x0e0b, 0x1018, 0x0d0e, 0x0e0d, 0x151d, 0x1116, 0x2318,
- 0x251f, 0x2224, 0x221f, 0x2621, 0x372b, 0x262f, 0x3429, 0x2129,
- 0x3022, 0x3141, 0x3934, 0x3e3b, 0x3e3e, 0x2e25, 0x4944, 0x3c43,
- 0x3748, 0x3e3d, 0xff3b,
- 0xdbff, 0x4300, 0x0a01, 0x0b0b, 0x0d0e, 0x1c0e, 0x1010, 0x3b1c,
- 0x2228, 0x3b28, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b,
- 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b,
- 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b,
- 0x3b3b, 0x3b3b, 0xff3b,
- },
- {
- 0xdbff, 0x4300, 0x0600, 0x0504, 0x0506, 0x0604, 0x0506, 0x0706,
- 0x0607, 0x0a08, 0x0a10, 0x090a, 0x0a09, 0x0e14, 0x0c0f, 0x1710,
- 0x1814, 0x1718, 0x1614, 0x1a16, 0x251d, 0x1a1f, 0x231b, 0x161c,
- 0x2016, 0x202c, 0x2623, 0x2927, 0x292a, 0x1f19, 0x302d, 0x282d,
- 0x2530, 0x2928, 0xff28,
- 0xdbff, 0x4300, 0x0701, 0x0707, 0x080a, 0x130a, 0x0a0a, 0x2813,
- 0x161a, 0x281a, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828,
- 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828,
- 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828,
- 0x2828, 0x2828, 0xff28,
- },
- {
- 0xdbff, 0x4300, 0x0300, 0x0202, 0x0203, 0x0302, 0x0303, 0x0403,
- 0x0303, 0x0504, 0x0508, 0x0405, 0x0504, 0x070a, 0x0607, 0x0c08,
- 0x0c0a, 0x0b0c, 0x0b0a, 0x0d0b, 0x120e, 0x0d10, 0x110e, 0x0b0e,
- 0x100b, 0x1016, 0x1311, 0x1514, 0x1515, 0x0f0c, 0x1817, 0x1416,
- 0x1218, 0x1514, 0xff14,
- 0xdbff, 0x4300, 0x0301, 0x0404, 0x0405, 0x0905, 0x0505, 0x1409,
- 0x0b0d, 0x140d, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414,
- 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414,
- 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414,
- 0x1414, 0x1414, 0xff14,
- },
- {
- 0xdbff, 0x4300, 0x0100, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
- 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
- 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
- 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
- 0x0101, 0x0101, 0xff01,
- 0xdbff, 0x4300, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
- 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
- 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
- 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
- 0x0101, 0x0101, 0xff01,
- } };
-
- if (quality < 0 || quality > 10) {
- printk(KERN_WARNING
- "meye: invalid quality level %d - using 8\n", quality);
- quality = 8;
- }
-
- *length = ARRAY_SIZE(jpeg_tables[quality]);
- return jpeg_tables[quality];
-}
-
-/* return a generic set of huffman tables */
-static u16 *jpeg_huffman_tables(int *length)
-{
- static u16 tables[] = {
- 0xC4FF, 0xB500, 0x0010, 0x0102, 0x0303, 0x0402, 0x0503, 0x0405,
- 0x0004, 0x0100, 0x017D, 0x0302, 0x0400, 0x0511, 0x2112, 0x4131,
- 0x1306, 0x6151, 0x2207, 0x1471, 0x8132, 0xA191, 0x2308, 0xB142,
- 0x15C1, 0xD152, 0x24F0, 0x6233, 0x8272, 0x0A09, 0x1716, 0x1918,
- 0x251A, 0x2726, 0x2928, 0x342A, 0x3635, 0x3837, 0x3A39, 0x4443,
- 0x4645, 0x4847, 0x4A49, 0x5453, 0x5655, 0x5857, 0x5A59, 0x6463,
- 0x6665, 0x6867, 0x6A69, 0x7473, 0x7675, 0x7877, 0x7A79, 0x8483,
- 0x8685, 0x8887, 0x8A89, 0x9392, 0x9594, 0x9796, 0x9998, 0xA29A,
- 0xA4A3, 0xA6A5, 0xA8A7, 0xAAA9, 0xB3B2, 0xB5B4, 0xB7B6, 0xB9B8,
- 0xC2BA, 0xC4C3, 0xC6C5, 0xC8C7, 0xCAC9, 0xD3D2, 0xD5D4, 0xD7D6,
- 0xD9D8, 0xE1DA, 0xE3E2, 0xE5E4, 0xE7E6, 0xE9E8, 0xF1EA, 0xF3F2,
- 0xF5F4, 0xF7F6, 0xF9F8, 0xFFFA,
- 0xC4FF, 0xB500, 0x0011, 0x0102, 0x0402, 0x0304, 0x0704, 0x0405,
- 0x0004, 0x0201, 0x0077, 0x0201, 0x1103, 0x0504, 0x3121, 0x1206,
- 0x5141, 0x6107, 0x1371, 0x3222, 0x0881, 0x4214, 0xA191, 0xC1B1,
- 0x2309, 0x5233, 0x15F0, 0x7262, 0x0AD1, 0x2416, 0xE134, 0xF125,
- 0x1817, 0x1A19, 0x2726, 0x2928, 0x352A, 0x3736, 0x3938, 0x433A,
- 0x4544, 0x4746, 0x4948, 0x534A, 0x5554, 0x5756, 0x5958, 0x635A,
- 0x6564, 0x6766, 0x6968, 0x736A, 0x7574, 0x7776, 0x7978, 0x827A,
- 0x8483, 0x8685, 0x8887, 0x8A89, 0x9392, 0x9594, 0x9796, 0x9998,
- 0xA29A, 0xA4A3, 0xA6A5, 0xA8A7, 0xAAA9, 0xB3B2, 0xB5B4, 0xB7B6,
- 0xB9B8, 0xC2BA, 0xC4C3, 0xC6C5, 0xC8C7, 0xCAC9, 0xD3D2, 0xD5D4,
- 0xD7D6, 0xD9D8, 0xE2DA, 0xE4E3, 0xE6E5, 0xE8E7, 0xEAE9, 0xF3F2,
- 0xF5F4, 0xF7F6, 0xF9F8, 0xFFFA,
- 0xC4FF, 0x1F00, 0x0000, 0x0501, 0x0101, 0x0101, 0x0101, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0201, 0x0403, 0x0605, 0x0807, 0x0A09,
- 0xFF0B,
- 0xC4FF, 0x1F00, 0x0001, 0x0103, 0x0101, 0x0101, 0x0101, 0x0101,
- 0x0000, 0x0000, 0x0000, 0x0201, 0x0403, 0x0605, 0x0807, 0x0A09,
- 0xFF0B
- };
-
- *length = ARRAY_SIZE(tables);
- return tables;
-}
-
-/****************************************************************************/
-/* MCHIP low-level functions */
-/****************************************************************************/
-
-/* returns the horizontal capture size */
-static inline int mchip_hsize(void)
-{
- return meye.params.subsample ? 320 : 640;
-}
-
-/* returns the vertical capture size */
-static inline int mchip_vsize(void)
-{
- return meye.params.subsample ? 240 : 480;
-}
-
-/* waits for a register to be available */
-static void mchip_sync(int reg)
-{
- u32 status;
- int i;
-
- if (reg == MCHIP_MM_FIFO_DATA) {
- for (i = 0; i < MCHIP_REG_TIMEOUT; i++) {
- status = readl(meye.mchip_mmregs +
- MCHIP_MM_FIFO_STATUS);
- if (!(status & MCHIP_MM_FIFO_WAIT)) {
- printk(KERN_WARNING "meye: fifo not ready\n");
- return;
- }
- if (status & MCHIP_MM_FIFO_READY)
- return;
- udelay(1);
- }
- } else if (reg > 0x80) {
- u32 mask = (reg < 0x100) ? MCHIP_HIC_STATUS_MCC_RDY
- : MCHIP_HIC_STATUS_VRJ_RDY;
- for (i = 0; i < MCHIP_REG_TIMEOUT; i++) {
- status = readl(meye.mchip_mmregs + MCHIP_HIC_STATUS);
- if (status & mask)
- return;
- udelay(1);
- }
- } else
- return;
- printk(KERN_WARNING
- "meye: mchip_sync() timeout on reg 0x%x status=0x%x\n",
- reg, status);
-}
-
-/* sets a value into the register */
-static inline void mchip_set(int reg, u32 v)
-{
- mchip_sync(reg);
- writel(v, meye.mchip_mmregs + reg);
-}
-
-/* get the register value */
-static inline u32 mchip_read(int reg)
-{
- mchip_sync(reg);
- return readl(meye.mchip_mmregs + reg);
-}
-
-/* wait for a register to become a particular value */
-static inline int mchip_delay(u32 reg, u32 v)
-{
- int n = 10;
- while (--n && mchip_read(reg) != v)
- udelay(1);
- return n;
-}
-
-/* setup subsampling */
-static void mchip_subsample(void)
-{
- mchip_set(MCHIP_MCC_R_SAMPLING, meye.params.subsample);
- mchip_set(MCHIP_MCC_R_XRANGE, mchip_hsize());
- mchip_set(MCHIP_MCC_R_YRANGE, mchip_vsize());
- mchip_set(MCHIP_MCC_B_XRANGE, mchip_hsize());
- mchip_set(MCHIP_MCC_B_YRANGE, mchip_vsize());
- mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE);
-}
-
-/* set the framerate into the mchip */
-static void mchip_set_framerate(void)
-{
- mchip_set(MCHIP_HIC_S_RATE, meye.params.framerate);
-}
-
-/* load some huffman and quantisation tables into the VRJ chip ready
- for JPEG compression */
-static void mchip_load_tables(void)
-{
- int i;
- int length;
- u16 *tables;
-
- tables = jpeg_huffman_tables(&length);
- for (i = 0; i < length; i++)
- writel(tables[i], meye.mchip_mmregs + MCHIP_VRJ_TABLE_DATA);
-
- tables = jpeg_quantisation_tables(&length, meye.params.quality);
- for (i = 0; i < length; i++)
- writel(tables[i], meye.mchip_mmregs + MCHIP_VRJ_TABLE_DATA);
-}
-
-/* setup the VRJ parameters in the chip */
-static void mchip_vrj_setup(u8 mode)
-{
- mchip_set(MCHIP_VRJ_BUS_MODE, 5);
- mchip_set(MCHIP_VRJ_SIGNAL_ACTIVE_LEVEL, 0x1f);
- mchip_set(MCHIP_VRJ_PDAT_USE, 1);
- mchip_set(MCHIP_VRJ_IRQ_FLAG, 0xa0);
- mchip_set(MCHIP_VRJ_MODE_SPECIFY, mode);
- mchip_set(MCHIP_VRJ_NUM_LINES, mchip_vsize());
- mchip_set(MCHIP_VRJ_NUM_PIXELS, mchip_hsize());
- mchip_set(MCHIP_VRJ_NUM_COMPONENTS, 0x1b);
- mchip_set(MCHIP_VRJ_LIMIT_COMPRESSED_LO, 0xFFFF);
- mchip_set(MCHIP_VRJ_LIMIT_COMPRESSED_HI, 0xFFFF);
- mchip_set(MCHIP_VRJ_COMP_DATA_FORMAT, 0xC);
- mchip_set(MCHIP_VRJ_RESTART_INTERVAL, 0);
- mchip_set(MCHIP_VRJ_SOF1, 0x601);
- mchip_set(MCHIP_VRJ_SOF2, 0x1502);
- mchip_set(MCHIP_VRJ_SOF3, 0x1503);
- mchip_set(MCHIP_VRJ_SOF4, 0x1596);
- mchip_set(MCHIP_VRJ_SOS, 0x0ed0);
-
- mchip_load_tables();
-}
-
-/* sets the DMA parameters into the chip */
-static void mchip_dma_setup(dma_addr_t dma_addr)
-{
- int i;
-
- mchip_set(MCHIP_MM_PT_ADDR, (u32)dma_addr);
- for (i = 0; i < 4; i++)
- mchip_set(MCHIP_MM_FIR(i), 0);
- meye.mchip_fnum = 0;
-}
-
-/* setup for DMA transfers - also zeros the framebuffer */
-static int mchip_dma_alloc(void)
-{
- if (!meye.mchip_dmahandle)
- if (ptable_alloc())
- return -1;
- return 0;
-}
-
-/* frees the DMA buffer */
-static void mchip_dma_free(void)
-{
- if (meye.mchip_dmahandle) {
- mchip_dma_setup(0);
- ptable_free();
- }
-}
-
-/* stop any existing HIC action and wait for any dma to complete then
- reset the dma engine */
-static void mchip_hic_stop(void)
-{
- int i, j;
-
- meye.mchip_mode = MCHIP_HIC_MODE_NOOP;
- if (!(mchip_read(MCHIP_HIC_STATUS) & MCHIP_HIC_STATUS_BUSY))
- return;
- for (i = 0; i < 20; ++i) {
- mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_STOP);
- mchip_delay(MCHIP_HIC_CMD, 0);
- for (j = 0; j < 100; ++j) {
- if (mchip_delay(MCHIP_HIC_STATUS,
- MCHIP_HIC_STATUS_IDLE))
- return;
- msleep(1);
- }
- printk(KERN_ERR "meye: need to reset HIC!\n");
-
- mchip_set(MCHIP_HIC_CTL, MCHIP_HIC_CTL_SOFT_RESET);
- msleep(250);
- }
- printk(KERN_ERR "meye: resetting HIC hanged!\n");
-}
-
-/****************************************************************************/
-/* MCHIP frame processing functions */
-/****************************************************************************/
-
-/* get the next ready frame from the dma engine */
-static u32 mchip_get_frame(void)
-{
- return mchip_read(MCHIP_MM_FIR(meye.mchip_fnum));
-}
-
-/* frees the current frame from the dma engine */
-static void mchip_free_frame(void)
-{
- mchip_set(MCHIP_MM_FIR(meye.mchip_fnum), 0);
- meye.mchip_fnum++;
- meye.mchip_fnum %= 4;
-}
-
-/* read one frame from the framebuffer assuming it was captured using
- a uncompressed transfer */
-static void mchip_cont_read_frame(u32 v, u8 *buf, int size)
-{
- int pt_id;
-
- pt_id = (v >> 17) & 0x3FF;
-
- ptable_copy(buf, pt_id, size, MCHIP_NB_PAGES);
-}
-
-/* read a compressed frame from the framebuffer */
-static int mchip_comp_read_frame(u32 v, u8 *buf, int size)
-{
- int pt_start, pt_end, trailer;
- int fsize;
- int i;
-
- pt_start = (v >> 19) & 0xFF;
- pt_end = (v >> 11) & 0xFF;
- trailer = (v >> 1) & 0x3FF;
-
- if (pt_end < pt_start)
- fsize = (MCHIP_NB_PAGES_MJPEG - pt_start) * PAGE_SIZE +
- pt_end * PAGE_SIZE + trailer * 4;
- else
- fsize = (pt_end - pt_start) * PAGE_SIZE + trailer * 4;
-
- if (fsize > size) {
- printk(KERN_WARNING "meye: oversized compressed frame %d\n",
- fsize);
- return -1;
- }
-
- ptable_copy(buf, pt_start, fsize, MCHIP_NB_PAGES_MJPEG);
-
-#ifdef MEYE_JPEG_CORRECTION
-
- /* Some mchip generated jpeg frames are incorrect. In most
- * (all ?) of those cases, the final EOI (0xff 0xd9) marker
- * is not present at the end of the frame.
- *
- * Since adding the final marker is not enough to restore
- * the jpeg integrity, we drop the frame.
- */
-
- for (i = fsize - 1; i > 0 && buf[i] == 0xff; i--) ;
-
- if (i < 2 || buf[i - 1] != 0xff || buf[i] != 0xd9)
- return -1;
-
-#endif
-
- return fsize;
-}
-
-/* take a picture into SDRAM */
-static void mchip_take_picture(void)
-{
- int i;
-
- mchip_hic_stop();
- mchip_subsample();
- mchip_dma_setup(meye.mchip_dmahandle);
-
- mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_STILL_CAP);
- mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START);
-
- mchip_delay(MCHIP_HIC_CMD, 0);
-
- for (i = 0; i < 100; ++i) {
- if (mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE))
- break;
- msleep(1);
- }
-}
-
-/* dma a previously taken picture into a buffer */
-static void mchip_get_picture(u8 *buf, int bufsize)
-{
- u32 v;
- int i;
-
- mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_STILL_OUT);
- mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START);
-
- mchip_delay(MCHIP_HIC_CMD, 0);
- for (i = 0; i < 100; ++i) {
- if (mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE))
- break;
- msleep(1);
- }
- for (i = 0; i < 4; ++i) {
- v = mchip_get_frame();
- if (v & MCHIP_MM_FIR_RDY) {
- mchip_cont_read_frame(v, buf, bufsize);
- break;
- }
- mchip_free_frame();
- }
-}
-
-/* start continuous dma capture */
-static void mchip_continuous_start(void)
-{
- mchip_hic_stop();
- mchip_subsample();
- mchip_set_framerate();
- mchip_dma_setup(meye.mchip_dmahandle);
-
- meye.mchip_mode = MCHIP_HIC_MODE_CONT_OUT;
-
- mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_CONT_OUT);
- mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START);
-
- mchip_delay(MCHIP_HIC_CMD, 0);
-}
-
-/* compress one frame into a buffer */
-static int mchip_compress_frame(u8 *buf, int bufsize)
-{
- u32 v;
- int len = -1, i;
-
- mchip_vrj_setup(0x3f);
- udelay(50);
-
- mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_STILL_COMP);
- mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START);
-
- mchip_delay(MCHIP_HIC_CMD, 0);
- for (i = 0; i < 100; ++i) {
- if (mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE))
- break;
- msleep(1);
- }
-
- for (i = 0; i < 4; ++i) {
- v = mchip_get_frame();
- if (v & MCHIP_MM_FIR_RDY) {
- len = mchip_comp_read_frame(v, buf, bufsize);
- break;
- }
- mchip_free_frame();
- }
- return len;
-}
-
-#if 0
-/* uncompress one image into a buffer */
-static int mchip_uncompress_frame(u8 *img, int imgsize, u8 *buf, int bufsize)
-{
- mchip_vrj_setup(0x3f);
- udelay(50);
-
- mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_STILL_DECOMP);
- mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START);
-
- mchip_delay(MCHIP_HIC_CMD, 0);
-
- return mchip_comp_read_frame(buf, bufsize);
-}
-#endif
-
-/* start continuous compressed capture */
-static void mchip_cont_compression_start(void)
-{
- mchip_hic_stop();
- mchip_vrj_setup(0x3f);
- mchip_subsample();
- mchip_set_framerate();
- mchip_dma_setup(meye.mchip_dmahandle);
-
- meye.mchip_mode = MCHIP_HIC_MODE_CONT_COMP;
-
- mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_CONT_COMP);
- mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START);
-
- mchip_delay(MCHIP_HIC_CMD, 0);
-}
-
-/****************************************************************************/
-/* Interrupt handling */
-/****************************************************************************/
-
-static irqreturn_t meye_irq(int irq, void *dev_id)
-{
- u32 v;
- int reqnr;
- static int sequence;
-
- v = mchip_read(MCHIP_MM_INTA);
-
- if (meye.mchip_mode != MCHIP_HIC_MODE_CONT_OUT &&
- meye.mchip_mode != MCHIP_HIC_MODE_CONT_COMP)
- return IRQ_NONE;
-
-again:
- v = mchip_get_frame();
- if (!(v & MCHIP_MM_FIR_RDY))
- return IRQ_HANDLED;
-
- if (meye.mchip_mode == MCHIP_HIC_MODE_CONT_OUT) {
- if (kfifo_out_locked(&meye.grabq, (unsigned char *)&reqnr,
- sizeof(int), &meye.grabq_lock) != sizeof(int)) {
- mchip_free_frame();
- return IRQ_HANDLED;
- }
- mchip_cont_read_frame(v, meye.grab_fbuffer + gbufsize * reqnr,
- mchip_hsize() * mchip_vsize() * 2);
- meye.grab_buffer[reqnr].size = mchip_hsize() * mchip_vsize() * 2;
- meye.grab_buffer[reqnr].state = MEYE_BUF_DONE;
- meye.grab_buffer[reqnr].ts = ktime_get_ns();
- meye.grab_buffer[reqnr].sequence = sequence++;
- kfifo_in_locked(&meye.doneq, (unsigned char *)&reqnr,
- sizeof(int), &meye.doneq_lock);
- wake_up_interruptible(&meye.proc_list);
- } else {
- int size;
- size = mchip_comp_read_frame(v, meye.grab_temp, gbufsize);
- if (size == -1) {
- mchip_free_frame();
- goto again;
- }
- if (kfifo_out_locked(&meye.grabq, (unsigned char *)&reqnr,
- sizeof(int), &meye.grabq_lock) != sizeof(int)) {
- mchip_free_frame();
- goto again;
- }
- memcpy(meye.grab_fbuffer + gbufsize * reqnr, meye.grab_temp,
- size);
- meye.grab_buffer[reqnr].size = size;
- meye.grab_buffer[reqnr].state = MEYE_BUF_DONE;
- meye.grab_buffer[reqnr].ts = ktime_get_ns();
- meye.grab_buffer[reqnr].sequence = sequence++;
- kfifo_in_locked(&meye.doneq, (unsigned char *)&reqnr,
- sizeof(int), &meye.doneq_lock);
- wake_up_interruptible(&meye.proc_list);
- }
- mchip_free_frame();
- goto again;
-}
-
-/****************************************************************************/
-/* video4linux integration */
-/****************************************************************************/
-
-static int meye_open(struct file *file)
-{
- int i;
-
- if (test_and_set_bit(0, &meye.in_use))
- return -EBUSY;
-
- mchip_hic_stop();
-
- if (mchip_dma_alloc()) {
- printk(KERN_ERR "meye: mchip framebuffer allocation failed\n");
- clear_bit(0, &meye.in_use);
- return -ENOBUFS;
- }
-
- for (i = 0; i < MEYE_MAX_BUFNBRS; i++)
- meye.grab_buffer[i].state = MEYE_BUF_UNUSED;
- kfifo_reset(&meye.grabq);
- kfifo_reset(&meye.doneq);
- return v4l2_fh_open(file);
-}
-
-static int meye_release(struct file *file)
-{
- mchip_hic_stop();
- mchip_dma_free();
- clear_bit(0, &meye.in_use);
- return v4l2_fh_release(file);
-}
-
-static int meyeioc_g_params(struct meye_params *p)
-{
- *p = meye.params;
- return 0;
-}
-
-static int meyeioc_s_params(struct meye_params *jp)
-{
- if (jp->subsample > 1)
- return -EINVAL;
-
- if (jp->quality > 10)
- return -EINVAL;
-
- if (jp->sharpness > 63 || jp->agc > 63 || jp->picture > 63)
- return -EINVAL;
-
- if (jp->framerate > 31)
- return -EINVAL;
-
- mutex_lock(&meye.lock);
-
- if (meye.params.subsample != jp->subsample ||
- meye.params.quality != jp->quality)
- mchip_hic_stop(); /* need restart */
-
- meye.params = *jp;
- sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERASHARPNESS,
- meye.params.sharpness);
- sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAAGC,
- meye.params.agc);
- sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAPICTURE,
- meye.params.picture);
- mutex_unlock(&meye.lock);
-
- return 0;
-}
-
-static int meyeioc_qbuf_capt(int *nb)
-{
- if (!meye.grab_fbuffer)
- return -EINVAL;
-
- if (*nb >= gbuffers)
- return -EINVAL;
-
- if (*nb < 0) {
- /* stop capture */
- mchip_hic_stop();
- return 0;
- }
-
- if (meye.grab_buffer[*nb].state != MEYE_BUF_UNUSED)
- return -EBUSY;
-
- mutex_lock(&meye.lock);
-
- if (meye.mchip_mode != MCHIP_HIC_MODE_CONT_COMP)
- mchip_cont_compression_start();
-
- meye.grab_buffer[*nb].state = MEYE_BUF_USING;
- kfifo_in_locked(&meye.grabq, (unsigned char *)nb, sizeof(int),
- &meye.grabq_lock);
- mutex_unlock(&meye.lock);
-
- return 0;
-}
-
-static int meyeioc_sync(struct file *file, void *fh, int *i)
-{
- int unused;
-
- if (*i < 0 || *i >= gbuffers)
- return -EINVAL;
-
- mutex_lock(&meye.lock);
- switch (meye.grab_buffer[*i].state) {
-
- case MEYE_BUF_UNUSED:
- mutex_unlock(&meye.lock);
- return -EINVAL;
- case MEYE_BUF_USING:
- if (file->f_flags & O_NONBLOCK) {
- mutex_unlock(&meye.lock);
- return -EAGAIN;
- }
- if (wait_event_interruptible(meye.proc_list,
- (meye.grab_buffer[*i].state != MEYE_BUF_USING))) {
- mutex_unlock(&meye.lock);
- return -EINTR;
- }
- fallthrough;
- case MEYE_BUF_DONE:
- meye.grab_buffer[*i].state = MEYE_BUF_UNUSED;
- if (kfifo_out_locked(&meye.doneq, (unsigned char *)&unused,
- sizeof(int), &meye.doneq_lock) != sizeof(int))
- break;
- }
- *i = meye.grab_buffer[*i].size;
- mutex_unlock(&meye.lock);
- return 0;
-}
-
-static int meyeioc_stillcapt(void)
-{
- if (!meye.grab_fbuffer)
- return -EINVAL;
-
- if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED)
- return -EBUSY;
-
- mutex_lock(&meye.lock);
- meye.grab_buffer[0].state = MEYE_BUF_USING;
- mchip_take_picture();
-
- mchip_get_picture(meye.grab_fbuffer,
- mchip_hsize() * mchip_vsize() * 2);
-
- meye.grab_buffer[0].state = MEYE_BUF_DONE;
- mutex_unlock(&meye.lock);
-
- return 0;
-}
-
-static int meyeioc_stilljcapt(int *len)
-{
- if (!meye.grab_fbuffer)
- return -EINVAL;
-
- if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED)
- return -EBUSY;
-
- mutex_lock(&meye.lock);
- meye.grab_buffer[0].state = MEYE_BUF_USING;
- *len = -1;
-
- while (*len == -1) {
- mchip_take_picture();
- *len = mchip_compress_frame(meye.grab_fbuffer, gbufsize);
- }
-
- meye.grab_buffer[0].state = MEYE_BUF_DONE;
- mutex_unlock(&meye.lock);
- return 0;
-}
-
-static int vidioc_querycap(struct file *file, void *fh,
- struct v4l2_capability *cap)
-{
- strscpy(cap->driver, "meye", sizeof(cap->driver));
- strscpy(cap->card, "meye", sizeof(cap->card));
- return 0;
-}
-
-static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
-{
- if (i->index != 0)
- return -EINVAL;
-
- strscpy(i->name, "Camera", sizeof(i->name));
- i->type = V4L2_INPUT_TYPE_CAMERA;
-
- return 0;
-}
-
-static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
-{
- *i = 0;
- return 0;
-}
-
-static int vidioc_s_input(struct file *file, void *fh, unsigned int i)
-{
- if (i != 0)
- return -EINVAL;
-
- return 0;
-}
-
-static int meye_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- mutex_lock(&meye.lock);
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- sony_pic_camera_command(
- SONY_PIC_COMMAND_SETCAMERABRIGHTNESS, ctrl->val);
- meye.brightness = ctrl->val << 10;
- break;
- case V4L2_CID_HUE:
- sony_pic_camera_command(
- SONY_PIC_COMMAND_SETCAMERAHUE, ctrl->val);
- meye.hue = ctrl->val << 10;
- break;
- case V4L2_CID_CONTRAST:
- sony_pic_camera_command(
- SONY_PIC_COMMAND_SETCAMERACONTRAST, ctrl->val);
- meye.contrast = ctrl->val << 10;
- break;
- case V4L2_CID_SATURATION:
- sony_pic_camera_command(
- SONY_PIC_COMMAND_SETCAMERACOLOR, ctrl->val);
- meye.colour = ctrl->val << 10;
- break;
- case V4L2_CID_MEYE_AGC:
- sony_pic_camera_command(
- SONY_PIC_COMMAND_SETCAMERAAGC, ctrl->val);
- meye.params.agc = ctrl->val;
- break;
- case V4L2_CID_SHARPNESS:
- sony_pic_camera_command(
- SONY_PIC_COMMAND_SETCAMERASHARPNESS, ctrl->val);
- meye.params.sharpness = ctrl->val;
- break;
- case V4L2_CID_MEYE_PICTURE:
- sony_pic_camera_command(
- SONY_PIC_COMMAND_SETCAMERAPICTURE, ctrl->val);
- meye.params.picture = ctrl->val;
- break;
- case V4L2_CID_JPEG_COMPRESSION_QUALITY:
- meye.params.quality = ctrl->val;
- break;
- case V4L2_CID_MEYE_FRAMERATE:
- meye.params.framerate = ctrl->val;
- break;
- default:
- mutex_unlock(&meye.lock);
- return -EINVAL;
- }
- mutex_unlock(&meye.lock);
-
- return 0;
-}
-
-static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh,
- struct v4l2_fmtdesc *f)
-{
- if (f->index > 1)
- return -EINVAL;
-
- if (f->index == 0) {
- /* standard YUV 422 capture */
- f->flags = 0;
- f->pixelformat = V4L2_PIX_FMT_YUYV;
- } else {
- /* compressed MJPEG capture */
- f->pixelformat = V4L2_PIX_FMT_MJPEG;
- }
-
- return 0;
-}
-
-static int vidioc_try_fmt_vid_cap(struct file *file, void *fh,
- struct v4l2_format *f)
-{
- if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV &&
- f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG)
- return -EINVAL;
-
- if (f->fmt.pix.field != V4L2_FIELD_ANY &&
- f->fmt.pix.field != V4L2_FIELD_NONE)
- return -EINVAL;
-
- f->fmt.pix.field = V4L2_FIELD_NONE;
-
- if (f->fmt.pix.width <= 320) {
- f->fmt.pix.width = 320;
- f->fmt.pix.height = 240;
- } else {
- f->fmt.pix.width = 640;
- f->fmt.pix.height = 480;
- }
-
- f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
- f->fmt.pix.sizeimage = f->fmt.pix.height *
- f->fmt.pix.bytesperline;
- f->fmt.pix.colorspace = 0;
-
- return 0;
-}
-
-static int vidioc_g_fmt_vid_cap(struct file *file, void *fh,
- struct v4l2_format *f)
-{
- switch (meye.mchip_mode) {
- case MCHIP_HIC_MODE_CONT_OUT:
- default:
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
- break;
- case MCHIP_HIC_MODE_CONT_COMP:
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
- break;
- }
-
- f->fmt.pix.field = V4L2_FIELD_NONE;
- f->fmt.pix.width = mchip_hsize();
- f->fmt.pix.height = mchip_vsize();
- f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
- f->fmt.pix.sizeimage = f->fmt.pix.height *
- f->fmt.pix.bytesperline;
-
- return 0;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *fh,
- struct v4l2_format *f)
-{
- if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV &&
- f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG)
- return -EINVAL;
-
- if (f->fmt.pix.field != V4L2_FIELD_ANY &&
- f->fmt.pix.field != V4L2_FIELD_NONE)
- return -EINVAL;
-
- f->fmt.pix.field = V4L2_FIELD_NONE;
- mutex_lock(&meye.lock);
-
- if (f->fmt.pix.width <= 320) {
- f->fmt.pix.width = 320;
- f->fmt.pix.height = 240;
- meye.params.subsample = 1;
- } else {
- f->fmt.pix.width = 640;
- f->fmt.pix.height = 480;
- meye.params.subsample = 0;
- }
-
- switch (f->fmt.pix.pixelformat) {
- case V4L2_PIX_FMT_YUYV:
- meye.mchip_mode = MCHIP_HIC_MODE_CONT_OUT;
- break;
- case V4L2_PIX_FMT_MJPEG:
- meye.mchip_mode = MCHIP_HIC_MODE_CONT_COMP;
- break;
- }
-
- mutex_unlock(&meye.lock);
- f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
- f->fmt.pix.sizeimage = f->fmt.pix.height *
- f->fmt.pix.bytesperline;
- f->fmt.pix.colorspace = 0;
-
- return 0;
-}
-
-static int vidioc_reqbufs(struct file *file, void *fh,
- struct v4l2_requestbuffers *req)
-{
- int i;
-
- if (req->memory != V4L2_MEMORY_MMAP)
- return -EINVAL;
-
- if (meye.grab_fbuffer && req->count == gbuffers) {
- /* already allocated, no modifications */
- return 0;
- }
-
- mutex_lock(&meye.lock);
- if (meye.grab_fbuffer) {
- for (i = 0; i < gbuffers; i++)
- if (meye.vma_use_count[i]) {
- mutex_unlock(&meye.lock);
- return -EINVAL;
- }
- rvfree(meye.grab_fbuffer, gbuffers * gbufsize);
- meye.grab_fbuffer = NULL;
- }
-
- gbuffers = max(2, min((int)req->count, MEYE_MAX_BUFNBRS));
- req->count = gbuffers;
- meye.grab_fbuffer = rvmalloc(gbuffers * gbufsize);
-
- if (!meye.grab_fbuffer) {
- printk(KERN_ERR "meye: v4l framebuffer allocation failed\n");
- mutex_unlock(&meye.lock);
- return -ENOMEM;
- }
-
- for (i = 0; i < gbuffers; i++)
- meye.vma_use_count[i] = 0;
-
- mutex_unlock(&meye.lock);
-
- return 0;
-}
-
-static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf)
-{
- unsigned int index = buf->index;
-
- if (index >= gbuffers)
- return -EINVAL;
-
- buf->bytesused = meye.grab_buffer[index].size;
- buf->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
-
- if (meye.grab_buffer[index].state == MEYE_BUF_USING)
- buf->flags |= V4L2_BUF_FLAG_QUEUED;
-
- if (meye.grab_buffer[index].state == MEYE_BUF_DONE)
- buf->flags |= V4L2_BUF_FLAG_DONE;
-
- buf->field = V4L2_FIELD_NONE;
- v4l2_buffer_set_timestamp(buf, meye.grab_buffer[index].ts);
- buf->sequence = meye.grab_buffer[index].sequence;
- buf->memory = V4L2_MEMORY_MMAP;
- buf->m.offset = index * gbufsize;
- buf->length = gbufsize;
-
- return 0;
-}
-
-static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
-{
- if (buf->memory != V4L2_MEMORY_MMAP)
- return -EINVAL;
-
- if (buf->index >= gbuffers)
- return -EINVAL;
-
- if (meye.grab_buffer[buf->index].state != MEYE_BUF_UNUSED)
- return -EINVAL;
-
- mutex_lock(&meye.lock);
- buf->flags |= V4L2_BUF_FLAG_QUEUED;
- buf->flags &= ~V4L2_BUF_FLAG_DONE;
- meye.grab_buffer[buf->index].state = MEYE_BUF_USING;
- kfifo_in_locked(&meye.grabq, (unsigned char *)&buf->index,
- sizeof(int), &meye.grabq_lock);
- mutex_unlock(&meye.lock);
-
- return 0;
-}
-
-static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
-{
- int reqnr;
-
- if (buf->memory != V4L2_MEMORY_MMAP)
- return -EINVAL;
-
- mutex_lock(&meye.lock);
-
- if (kfifo_len(&meye.doneq) == 0 && file->f_flags & O_NONBLOCK) {
- mutex_unlock(&meye.lock);
- return -EAGAIN;
- }
-
- if (wait_event_interruptible(meye.proc_list,
- kfifo_len(&meye.doneq) != 0) < 0) {
- mutex_unlock(&meye.lock);
- return -EINTR;
- }
-
- if (!kfifo_out_locked(&meye.doneq, (unsigned char *)&reqnr,
- sizeof(int), &meye.doneq_lock)) {
- mutex_unlock(&meye.lock);
- return -EBUSY;
- }
-
- if (meye.grab_buffer[reqnr].state != MEYE_BUF_DONE) {
- mutex_unlock(&meye.lock);
- return -EINVAL;
- }
-
- buf->index = reqnr;
- buf->bytesused = meye.grab_buffer[reqnr].size;
- buf->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- buf->field = V4L2_FIELD_NONE;
- v4l2_buffer_set_timestamp(buf, meye.grab_buffer[reqnr].ts);
- buf->sequence = meye.grab_buffer[reqnr].sequence;
- buf->memory = V4L2_MEMORY_MMAP;
- buf->m.offset = reqnr * gbufsize;
- buf->length = gbufsize;
- meye.grab_buffer[reqnr].state = MEYE_BUF_UNUSED;
- mutex_unlock(&meye.lock);
-
- return 0;
-}
-
-static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
-{
- mutex_lock(&meye.lock);
-
- switch (meye.mchip_mode) {
- case MCHIP_HIC_MODE_CONT_OUT:
- mchip_continuous_start();
- break;
- case MCHIP_HIC_MODE_CONT_COMP:
- mchip_cont_compression_start();
- break;
- default:
- mutex_unlock(&meye.lock);
- return -EINVAL;
- }
-
- mutex_unlock(&meye.lock);
-
- return 0;
-}
-
-static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
-{
- mutex_lock(&meye.lock);
- mchip_hic_stop();
- kfifo_reset(&meye.grabq);
- kfifo_reset(&meye.doneq);
-
- for (i = 0; i < MEYE_MAX_BUFNBRS; i++)
- meye.grab_buffer[i].state = MEYE_BUF_UNUSED;
-
- mutex_unlock(&meye.lock);
- return 0;
-}
-
-static long vidioc_default(struct file *file, void *fh, bool valid_prio,
- unsigned int cmd, void *arg)
-{
- switch (cmd) {
- case MEYEIOC_G_PARAMS:
- return meyeioc_g_params((struct meye_params *) arg);
-
- case MEYEIOC_S_PARAMS:
- return meyeioc_s_params((struct meye_params *) arg);
-
- case MEYEIOC_QBUF_CAPT:
- return meyeioc_qbuf_capt((int *) arg);
-
- case MEYEIOC_SYNC:
- return meyeioc_sync(file, fh, (int *) arg);
-
- case MEYEIOC_STILLCAPT:
- return meyeioc_stillcapt();
-
- case MEYEIOC_STILLJCAPT:
- return meyeioc_stilljcapt((int *) arg);
-
- default:
- return -ENOTTY;
- }
-
-}
-
-static __poll_t meye_poll(struct file *file, poll_table *wait)
-{
- __poll_t res = v4l2_ctrl_poll(file, wait);
-
- mutex_lock(&meye.lock);
- poll_wait(file, &meye.proc_list, wait);
- if (kfifo_len(&meye.doneq))
- res |= EPOLLIN | EPOLLRDNORM;
- mutex_unlock(&meye.lock);
- return res;
-}
-
-static void meye_vm_open(struct vm_area_struct *vma)
-{
- long idx = (long)vma->vm_private_data;
- meye.vma_use_count[idx]++;
-}
-
-static void meye_vm_close(struct vm_area_struct *vma)
-{
- long idx = (long)vma->vm_private_data;
- meye.vma_use_count[idx]--;
-}
-
-static const struct vm_operations_struct meye_vm_ops = {
- .open = meye_vm_open,
- .close = meye_vm_close,
-};
-
-static int meye_mmap(struct file *file, struct vm_area_struct *vma)
-{
- unsigned long start = vma->vm_start;
- unsigned long size = vma->vm_end - vma->vm_start;
- unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
- unsigned long page, pos;
-
- mutex_lock(&meye.lock);
- if (size > gbuffers * gbufsize || offset > gbuffers * gbufsize - size) {
- mutex_unlock(&meye.lock);
- return -EINVAL;
- }
- if (!meye.grab_fbuffer) {
- int i;
-
- /* lazy allocation */
- meye.grab_fbuffer = rvmalloc(gbuffers*gbufsize);
- if (!meye.grab_fbuffer) {
- printk(KERN_ERR "meye: v4l framebuffer allocation failed\n");
- mutex_unlock(&meye.lock);
- return -ENOMEM;
- }
- for (i = 0; i < gbuffers; i++)
- meye.vma_use_count[i] = 0;
- }
- pos = (unsigned long)meye.grab_fbuffer + offset;
-
- while (size > 0) {
- page = vmalloc_to_pfn((void *)pos);
- if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
- mutex_unlock(&meye.lock);
- return -EAGAIN;
- }
- start += PAGE_SIZE;
- pos += PAGE_SIZE;
- if (size > PAGE_SIZE)
- size -= PAGE_SIZE;
- else
- size = 0;
- }
-
- vma->vm_ops = &meye_vm_ops;
- vma->vm_flags &= ~VM_IO; /* not I/O memory */
- vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
- vma->vm_private_data = (void *) (offset / gbufsize);
- meye_vm_open(vma);
-
- mutex_unlock(&meye.lock);
- return 0;
-}
-
-static const struct v4l2_file_operations meye_fops = {
- .owner = THIS_MODULE,
- .open = meye_open,
- .release = meye_release,
- .mmap = meye_mmap,
- .unlocked_ioctl = video_ioctl2,
- .poll = meye_poll,
-};
-
-static const struct v4l2_ioctl_ops meye_ioctl_ops = {
- .vidioc_querycap = vidioc_querycap,
- .vidioc_enum_input = vidioc_enum_input,
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
- .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
- .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
- .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
- .vidioc_reqbufs = vidioc_reqbufs,
- .vidioc_querybuf = vidioc_querybuf,
- .vidioc_qbuf = vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
- .vidioc_log_status = v4l2_ctrl_log_status,
- .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
- .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
- .vidioc_default = vidioc_default,
-};
-
-static const struct video_device meye_template = {
- .name = "meye",
- .fops = &meye_fops,
- .ioctl_ops = &meye_ioctl_ops,
- .release = video_device_release_empty,
- .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING,
-};
-
-static const struct v4l2_ctrl_ops meye_ctrl_ops = {
- .s_ctrl = meye_s_ctrl,
-};
-
-static int __maybe_unused meye_suspend(struct device *dev)
-{
- meye.pm_mchip_mode = meye.mchip_mode;
- mchip_hic_stop();
- mchip_set(MCHIP_MM_INTA, 0x0);
- return 0;
-}
-
-static int __maybe_unused meye_resume(struct device *dev)
-{
- pci_write_config_word(meye.mchip_dev, MCHIP_PCI_SOFTRESET_SET, 1);
-
- mchip_delay(MCHIP_HIC_CMD, 0);
- mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE);
- msleep(1);
- mchip_set(MCHIP_VRJ_SOFT_RESET, 1);
- msleep(1);
- mchip_set(MCHIP_MM_PCI_MODE, 5);
- msleep(1);
- mchip_set(MCHIP_MM_INTA, MCHIP_MM_INTA_HIC_1_MASK);
-
- switch (meye.pm_mchip_mode) {
- case MCHIP_HIC_MODE_CONT_OUT:
- mchip_continuous_start();
- break;
- case MCHIP_HIC_MODE_CONT_COMP:
- mchip_cont_compression_start();
- break;
- }
- return 0;
-}
-
-static int meye_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
-{
- static const struct v4l2_ctrl_config ctrl_agc = {
- .id = V4L2_CID_MEYE_AGC,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .ops = &meye_ctrl_ops,
- .name = "AGC",
- .max = 63,
- .step = 1,
- .def = 48,
- .flags = V4L2_CTRL_FLAG_SLIDER,
- };
- static const struct v4l2_ctrl_config ctrl_picture = {
- .id = V4L2_CID_MEYE_PICTURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .ops = &meye_ctrl_ops,
- .name = "Picture",
- .max = 63,
- .step = 1,
- };
- static const struct v4l2_ctrl_config ctrl_framerate = {
- .id = V4L2_CID_MEYE_FRAMERATE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .ops = &meye_ctrl_ops,
- .name = "Framerate",
- .max = 31,
- .step = 1,
- };
- struct v4l2_device *v4l2_dev = &meye.v4l2_dev;
- int ret = -EBUSY;
- unsigned long mchip_adr;
-
- if (meye.mchip_dev != NULL) {
- printk(KERN_ERR "meye: only one device allowed!\n");
- return ret;
- }
-
- ret = v4l2_device_register(&pcidev->dev, v4l2_dev);
- if (ret < 0) {
- v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
- return ret;
- }
- ret = -ENOMEM;
- meye.mchip_dev = pcidev;
-
- meye.grab_temp = vmalloc(array_size(PAGE_SIZE, MCHIP_NB_PAGES_MJPEG));
- if (!meye.grab_temp)
- goto outvmalloc;
-
- spin_lock_init(&meye.grabq_lock);
- if (kfifo_alloc(&meye.grabq, sizeof(int) * MEYE_MAX_BUFNBRS,
- GFP_KERNEL))
- goto outkfifoalloc1;
-
- spin_lock_init(&meye.doneq_lock);
- if (kfifo_alloc(&meye.doneq, sizeof(int) * MEYE_MAX_BUFNBRS,
- GFP_KERNEL))
- goto outkfifoalloc2;
-
- meye.vdev = meye_template;
- meye.vdev.v4l2_dev = &meye.v4l2_dev;
-
- ret = sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 1);
- if (ret) {
- v4l2_err(v4l2_dev, "meye: unable to power on the camera\n");
- v4l2_err(v4l2_dev, "meye: did you enable the camera in sonypi using the module options ?\n");
- goto outsonypienable;
- }
-
- ret = pci_enable_device(meye.mchip_dev);
- if (ret) {
- v4l2_err(v4l2_dev, "meye: pci_enable_device failed\n");
- goto outenabledev;
- }
-
- ret = -EIO;
- mchip_adr = pci_resource_start(meye.mchip_dev,0);
- if (!mchip_adr) {
- v4l2_err(v4l2_dev, "meye: mchip has no device base address\n");
- goto outregions;
- }
- if (!request_mem_region(pci_resource_start(meye.mchip_dev, 0),
- pci_resource_len(meye.mchip_dev, 0),
- "meye")) {
- v4l2_err(v4l2_dev, "meye: request_mem_region failed\n");
- goto outregions;
- }
- meye.mchip_mmregs = ioremap(mchip_adr, MCHIP_MM_REGS);
- if (!meye.mchip_mmregs) {
- v4l2_err(v4l2_dev, "meye: ioremap failed\n");
- goto outremap;
- }
-
- meye.mchip_irq = pcidev->irq;
- if (request_irq(meye.mchip_irq, meye_irq,
- IRQF_SHARED, "meye", meye_irq)) {
- v4l2_err(v4l2_dev, "request_irq failed\n");
- goto outreqirq;
- }
-
- pci_write_config_byte(meye.mchip_dev, PCI_CACHE_LINE_SIZE, 8);
- pci_write_config_byte(meye.mchip_dev, PCI_LATENCY_TIMER, 64);
-
- pci_set_master(meye.mchip_dev);
-
- /* Ask the camera to perform a soft reset. */
- pci_write_config_word(meye.mchip_dev, MCHIP_PCI_SOFTRESET_SET, 1);
-
- mchip_delay(MCHIP_HIC_CMD, 0);
- mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE);
-
- msleep(1);
- mchip_set(MCHIP_VRJ_SOFT_RESET, 1);
-
- msleep(1);
- mchip_set(MCHIP_MM_PCI_MODE, 5);
-
- msleep(1);
- mchip_set(MCHIP_MM_INTA, MCHIP_MM_INTA_HIC_1_MASK);
-
- mutex_init(&meye.lock);
- init_waitqueue_head(&meye.proc_list);
-
- v4l2_ctrl_handler_init(&meye.hdl, 3);
- v4l2_ctrl_new_std(&meye.hdl, &meye_ctrl_ops,
- V4L2_CID_BRIGHTNESS, 0, 63, 1, 32);
- v4l2_ctrl_new_std(&meye.hdl, &meye_ctrl_ops,
- V4L2_CID_HUE, 0, 63, 1, 32);
- v4l2_ctrl_new_std(&meye.hdl, &meye_ctrl_ops,
- V4L2_CID_CONTRAST, 0, 63, 1, 32);
- v4l2_ctrl_new_std(&meye.hdl, &meye_ctrl_ops,
- V4L2_CID_SATURATION, 0, 63, 1, 32);
- v4l2_ctrl_new_custom(&meye.hdl, &ctrl_agc, NULL);
- v4l2_ctrl_new_std(&meye.hdl, &meye_ctrl_ops,
- V4L2_CID_SHARPNESS, 0, 63, 1, 32);
- v4l2_ctrl_new_custom(&meye.hdl, &ctrl_picture, NULL);
- v4l2_ctrl_new_std(&meye.hdl, &meye_ctrl_ops,
- V4L2_CID_JPEG_COMPRESSION_QUALITY, 0, 10, 1, 8);
- v4l2_ctrl_new_custom(&meye.hdl, &ctrl_framerate, NULL);
- if (meye.hdl.error) {
- v4l2_err(v4l2_dev, "couldn't register controls\n");
- goto outvideoreg;
- }
-
- v4l2_ctrl_handler_setup(&meye.hdl);
- meye.vdev.ctrl_handler = &meye.hdl;
-
- if (video_register_device(&meye.vdev, VFL_TYPE_VIDEO,
- video_nr) < 0) {
- v4l2_err(v4l2_dev, "video_register_device failed\n");
- goto outvideoreg;
- }
-
- v4l2_info(v4l2_dev, "Motion Eye Camera Driver v%s.\n",
- MEYE_DRIVER_VERSION);
- v4l2_info(v4l2_dev, "mchip KL5A72002 rev. %d, base %lx, irq %d\n",
- meye.mchip_dev->revision, mchip_adr, meye.mchip_irq);
-
- return 0;
-
-outvideoreg:
- v4l2_ctrl_handler_free(&meye.hdl);
- free_irq(meye.mchip_irq, meye_irq);
-outreqirq:
- iounmap(meye.mchip_mmregs);
-outremap:
- release_mem_region(pci_resource_start(meye.mchip_dev, 0),
- pci_resource_len(meye.mchip_dev, 0));
-outregions:
- pci_disable_device(meye.mchip_dev);
-outenabledev:
- sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 0);
-outsonypienable:
- kfifo_free(&meye.doneq);
-outkfifoalloc2:
- kfifo_free(&meye.grabq);
-outkfifoalloc1:
- vfree(meye.grab_temp);
-outvmalloc:
- return ret;
-}
-
-static void meye_remove(struct pci_dev *pcidev)
-{
- video_unregister_device(&meye.vdev);
-
- mchip_hic_stop();
-
- mchip_dma_free();
-
- /* disable interrupts */
- mchip_set(MCHIP_MM_INTA, 0x0);
-
- free_irq(meye.mchip_irq, meye_irq);
-
- iounmap(meye.mchip_mmregs);
-
- release_mem_region(pci_resource_start(meye.mchip_dev, 0),
- pci_resource_len(meye.mchip_dev, 0));
-
- pci_disable_device(meye.mchip_dev);
-
- sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 0);
-
- kfifo_free(&meye.doneq);
- kfifo_free(&meye.grabq);
-
- vfree(meye.grab_temp);
-
- if (meye.grab_fbuffer) {
- rvfree(meye.grab_fbuffer, gbuffers*gbufsize);
- meye.grab_fbuffer = NULL;
- }
-
- printk(KERN_INFO "meye: removed\n");
-}
-
-static const struct pci_device_id meye_pci_tbl[] = {
- { PCI_VDEVICE(KAWASAKI, PCI_DEVICE_ID_MCHIP_KL5A72002), 0 },
- { }
-};
-
-MODULE_DEVICE_TABLE(pci, meye_pci_tbl);
-
-static SIMPLE_DEV_PM_OPS(meye_pm_ops, meye_suspend, meye_resume);
-
-static struct pci_driver meye_driver = {
- .name = "meye",
- .id_table = meye_pci_tbl,
- .probe = meye_probe,
- .remove = meye_remove,
- .driver.pm = &meye_pm_ops,
-};
-
-static int __init meye_init(void)
-{
- gbuffers = max(2, min((int)gbuffers, MEYE_MAX_BUFNBRS));
- if (gbufsize > MEYE_MAX_BUFSIZE)
- gbufsize = MEYE_MAX_BUFSIZE;
- gbufsize = PAGE_ALIGN(gbufsize);
- printk(KERN_INFO "meye: using %d buffers with %dk (%dk total) for capture\n",
- gbuffers,
- gbufsize / 1024, gbuffers * gbufsize / 1024);
- return pci_register_driver(&meye_driver);
-}
-
-static void __exit meye_exit(void)
-{
- pci_unregister_driver(&meye_driver);
-}
-
-module_init(meye_init);
-module_exit(meye_exit);
diff --git a/drivers/staging/media/deprecated/meye/meye.h b/drivers/staging/media/deprecated/meye/meye.h
deleted file mode 100644
index 5fa6552cf93d..000000000000
--- a/drivers/staging/media/deprecated/meye/meye.h
+++ /dev/null
@@ -1,311 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Motion Eye video4linux driver for Sony Vaio PictureBook
- *
- * Copyright (C) 2001-2004 Stelian Pop <stelian@popies.net>
- *
- * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
- *
- * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com>
- *
- * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras.
- *
- * Some parts borrowed from various video4linux drivers, especially
- * bttv-driver.c and zoran.c, see original files for credits.
- */
-
-#ifndef _MEYE_PRIV_H_
-#define _MEYE_PRIV_H_
-
-#define MEYE_DRIVER_MAJORVERSION 1
-#define MEYE_DRIVER_MINORVERSION 14
-
-#define MEYE_DRIVER_VERSION __stringify(MEYE_DRIVER_MAJORVERSION) "." \
- __stringify(MEYE_DRIVER_MINORVERSION)
-
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/kfifo.h>
-#include <media/v4l2-ctrls.h>
-
-/****************************************************************************/
-/* Motion JPEG chip registers */
-/****************************************************************************/
-
-/* Motion JPEG chip PCI configuration registers */
-#define MCHIP_PCI_POWER_CSR 0x54
-#define MCHIP_PCI_MCORE_STATUS 0x60 /* see HIC_STATUS */
-#define MCHIP_PCI_HOSTUSEREQ_SET 0x64
-#define MCHIP_PCI_HOSTUSEREQ_CLR 0x68
-#define MCHIP_PCI_LOWPOWER_SET 0x6c
-#define MCHIP_PCI_LOWPOWER_CLR 0x70
-#define MCHIP_PCI_SOFTRESET_SET 0x74
-
-/* Motion JPEG chip memory mapped registers */
-#define MCHIP_MM_REGS 0x200 /* 512 bytes */
-#define MCHIP_REG_TIMEOUT 1000 /* reg access, ~us */
-#define MCHIP_MCC_VRJ_TIMEOUT 1000 /* MCC & VRJ access */
-
-#define MCHIP_MM_PCI_MODE 0x00 /* PCI access mode */
-#define MCHIP_MM_PCI_MODE_RETRY 0x00000001 /* retry mode */
-#define MCHIP_MM_PCI_MODE_MASTER 0x00000002 /* master access */
-#define MCHIP_MM_PCI_MODE_READ_LINE 0x00000004 /* read line */
-
-#define MCHIP_MM_INTA 0x04 /* Int status/mask */
-#define MCHIP_MM_INTA_MCC 0x00000001 /* MCC interrupt */
-#define MCHIP_MM_INTA_VRJ 0x00000002 /* VRJ interrupt */
-#define MCHIP_MM_INTA_HIC_1 0x00000004 /* one frame done */
-#define MCHIP_MM_INTA_HIC_1_MASK 0x00000400 /* 1: enable */
-#define MCHIP_MM_INTA_HIC_END 0x00000008 /* all frames done */
-#define MCHIP_MM_INTA_HIC_END_MASK 0x00000800
-#define MCHIP_MM_INTA_JPEG 0x00000010 /* decompress. error */
-#define MCHIP_MM_INTA_JPEG_MASK 0x00001000
-#define MCHIP_MM_INTA_CAPTURE 0x00000020 /* capture end */
-#define MCHIP_MM_INTA_PCI_ERR 0x00000040 /* PCI error */
-#define MCHIP_MM_INTA_PCI_ERR_MASK 0x00004000
-
-#define MCHIP_MM_PT_ADDR 0x08 /* page table address*/
- /* n*4kB */
-#define MCHIP_NB_PAGES 1024 /* pages for display */
-#define MCHIP_NB_PAGES_MJPEG 256 /* pages for mjpeg */
-
-#define MCHIP_MM_FIR(n) (0x0c+(n)*4) /* Frame info 0-3 */
-#define MCHIP_MM_FIR_RDY 0x00000001 /* frame ready */
-#define MCHIP_MM_FIR_FAILFR_MASK 0xf8000000 /* # of failed frames */
-#define MCHIP_MM_FIR_FAILFR_SHIFT 27
-
- /* continuous comp/decomp mode */
-#define MCHIP_MM_FIR_C_ENDL_MASK 0x000007fe /* end DW [10] */
-#define MCHIP_MM_FIR_C_ENDL_SHIFT 1
-#define MCHIP_MM_FIR_C_ENDP_MASK 0x0007f800 /* end page [8] */
-#define MCHIP_MM_FIR_C_ENDP_SHIFT 11
-#define MCHIP_MM_FIR_C_STARTP_MASK 0x07f80000 /* start page [8] */
-#define MCHIP_MM_FIR_C_STARTP_SHIFT 19
-
- /* continuous picture output mode */
-#define MCHIP_MM_FIR_O_STARTP_MASK 0x7ffe0000 /* start page [10] */
-#define MCHIP_MM_FIR_O_STARTP_SHIFT 17
-
-#define MCHIP_MM_FIFO_DATA 0x1c /* PCI TGT FIFO data */
-#define MCHIP_MM_FIFO_STATUS 0x20 /* PCI TGT FIFO stat */
-#define MCHIP_MM_FIFO_MASK 0x00000003
-#define MCHIP_MM_FIFO_WAIT_OR_READY 0x00000002 /* Bits common to WAIT & READY*/
-#define MCHIP_MM_FIFO_IDLE 0x0 /* HIC idle */
-#define MCHIP_MM_FIFO_IDLE1 0x1 /* idem ??? */
-#define MCHIP_MM_FIFO_WAIT 0x2 /* wait request */
-#define MCHIP_MM_FIFO_READY 0x3 /* data ready */
-
-#define MCHIP_HIC_HOST_USEREQ 0x40 /* host uses MCORE */
-
-#define MCHIP_HIC_TP_BUSY 0x44 /* taking picture */
-
-#define MCHIP_HIC_PIC_SAVED 0x48 /* pic in SDRAM */
-
-#define MCHIP_HIC_LOWPOWER 0x4c /* clock stopped */
-
-#define MCHIP_HIC_CTL 0x50 /* HIC control */
-#define MCHIP_HIC_CTL_SOFT_RESET 0x00000001 /* MCORE reset */
-#define MCHIP_HIC_CTL_MCORE_RDY 0x00000002 /* MCORE ready */
-
-#define MCHIP_HIC_CMD 0x54 /* HIC command */
-#define MCHIP_HIC_CMD_BITS 0x00000003 /* cmd width=[1:0]*/
-#define MCHIP_HIC_CMD_NOOP 0x0
-#define MCHIP_HIC_CMD_START 0x1
-#define MCHIP_HIC_CMD_STOP 0x2
-
-#define MCHIP_HIC_MODE 0x58
-#define MCHIP_HIC_MODE_NOOP 0x0
-#define MCHIP_HIC_MODE_STILL_CAP 0x1 /* still pic capt */
-#define MCHIP_HIC_MODE_DISPLAY 0x2 /* display */
-#define MCHIP_HIC_MODE_STILL_COMP 0x3 /* still pic comp. */
-#define MCHIP_HIC_MODE_STILL_DECOMP 0x4 /* still pic decomp. */
-#define MCHIP_HIC_MODE_CONT_COMP 0x5 /* cont capt+comp */
-#define MCHIP_HIC_MODE_CONT_DECOMP 0x6 /* cont decomp+disp */
-#define MCHIP_HIC_MODE_STILL_OUT 0x7 /* still pic output */
-#define MCHIP_HIC_MODE_CONT_OUT 0x8 /* cont output */
-
-#define MCHIP_HIC_STATUS 0x5c
-#define MCHIP_HIC_STATUS_MCC_RDY 0x00000001 /* MCC reg acc ok */
-#define MCHIP_HIC_STATUS_VRJ_RDY 0x00000002 /* VRJ reg acc ok */
-#define MCHIP_HIC_STATUS_IDLE 0x00000003
-#define MCHIP_HIC_STATUS_CAPDIS 0x00000004 /* cap/disp in prog */
-#define MCHIP_HIC_STATUS_COMPDEC 0x00000008 /* (de)comp in prog */
-#define MCHIP_HIC_STATUS_BUSY 0x00000010 /* HIC busy */
-
-#define MCHIP_HIC_S_RATE 0x60 /* MJPEG # frames */
-
-#define MCHIP_HIC_PCI_VFMT 0x64 /* video format */
-#define MCHIP_HIC_PCI_VFMT_YVYU 0x00000001 /* 0: V Y' U Y */
- /* 1: Y' V Y U */
-
-#define MCHIP_MCC_CMD 0x80 /* MCC commands */
-#define MCHIP_MCC_CMD_INITIAL 0x0 /* idle ? */
-#define MCHIP_MCC_CMD_IIC_START_SET 0x1
-#define MCHIP_MCC_CMD_IIC_END_SET 0x2
-#define MCHIP_MCC_CMD_FM_WRITE 0x3 /* frame memory */
-#define MCHIP_MCC_CMD_FM_READ 0x4
-#define MCHIP_MCC_CMD_FM_STOP 0x5
-#define MCHIP_MCC_CMD_CAPTURE 0x6
-#define MCHIP_MCC_CMD_DISPLAY 0x7
-#define MCHIP_MCC_CMD_END_DISP 0x8
-#define MCHIP_MCC_CMD_STILL_COMP 0x9
-#define MCHIP_MCC_CMD_STILL_DECOMP 0xa
-#define MCHIP_MCC_CMD_STILL_OUTPUT 0xb
-#define MCHIP_MCC_CMD_CONT_OUTPUT 0xc
-#define MCHIP_MCC_CMD_CONT_COMP 0xd
-#define MCHIP_MCC_CMD_CONT_DECOMP 0xe
-#define MCHIP_MCC_CMD_RESET 0xf /* MCC reset */
-
-#define MCHIP_MCC_IIC_WR 0x84
-
-#define MCHIP_MCC_MCC_WR 0x88
-
-#define MCHIP_MCC_MCC_RD 0x8c
-
-#define MCHIP_MCC_STATUS 0x90
-#define MCHIP_MCC_STATUS_CAPT 0x00000001 /* capturing */
-#define MCHIP_MCC_STATUS_DISP 0x00000002 /* displaying */
-#define MCHIP_MCC_STATUS_COMP 0x00000004 /* compressing */
-#define MCHIP_MCC_STATUS_DECOMP 0x00000008 /* decompressing */
-#define MCHIP_MCC_STATUS_MCC_WR 0x00000010 /* register ready */
-#define MCHIP_MCC_STATUS_MCC_RD 0x00000020 /* register ready */
-#define MCHIP_MCC_STATUS_IIC_WR 0x00000040 /* register ready */
-#define MCHIP_MCC_STATUS_OUTPUT 0x00000080 /* output in prog */
-
-#define MCHIP_MCC_SIG_POLARITY 0x94
-#define MCHIP_MCC_SIG_POL_VS_H 0x00000001 /* VS active-high */
-#define MCHIP_MCC_SIG_POL_HS_H 0x00000002 /* HS active-high */
-#define MCHIP_MCC_SIG_POL_DOE_H 0x00000004 /* DOE active-high */
-
-#define MCHIP_MCC_IRQ 0x98
-#define MCHIP_MCC_IRQ_CAPDIS_STRT 0x00000001 /* cap/disp started */
-#define MCHIP_MCC_IRQ_CAPDIS_STRT_MASK 0x00000010
-#define MCHIP_MCC_IRQ_CAPDIS_END 0x00000002 /* cap/disp ended */
-#define MCHIP_MCC_IRQ_CAPDIS_END_MASK 0x00000020
-#define MCHIP_MCC_IRQ_COMPDEC_STRT 0x00000004 /* (de)comp started */
-#define MCHIP_MCC_IRQ_COMPDEC_STRT_MASK 0x00000040
-#define MCHIP_MCC_IRQ_COMPDEC_END 0x00000008 /* (de)comp ended */
-#define MCHIP_MCC_IRQ_COMPDEC_END_MASK 0x00000080
-
-#define MCHIP_MCC_HSTART 0x9c /* video in */
-#define MCHIP_MCC_VSTART 0xa0
-#define MCHIP_MCC_HCOUNT 0xa4
-#define MCHIP_MCC_VCOUNT 0xa8
-#define MCHIP_MCC_R_XBASE 0xac /* capt/disp */
-#define MCHIP_MCC_R_YBASE 0xb0
-#define MCHIP_MCC_R_XRANGE 0xb4
-#define MCHIP_MCC_R_YRANGE 0xb8
-#define MCHIP_MCC_B_XBASE 0xbc /* comp/decomp */
-#define MCHIP_MCC_B_YBASE 0xc0
-#define MCHIP_MCC_B_XRANGE 0xc4
-#define MCHIP_MCC_B_YRANGE 0xc8
-
-#define MCHIP_MCC_R_SAMPLING 0xcc /* 1: 1:4 */
-
-#define MCHIP_VRJ_CMD 0x100 /* VRJ commands */
-
-/* VRJ registers (see table 12.2.4) */
-#define MCHIP_VRJ_COMPRESSED_DATA 0x1b0
-#define MCHIP_VRJ_PIXEL_DATA 0x1b8
-
-#define MCHIP_VRJ_BUS_MODE 0x100
-#define MCHIP_VRJ_SIGNAL_ACTIVE_LEVEL 0x108
-#define MCHIP_VRJ_PDAT_USE 0x110
-#define MCHIP_VRJ_MODE_SPECIFY 0x118
-#define MCHIP_VRJ_LIMIT_COMPRESSED_LO 0x120
-#define MCHIP_VRJ_LIMIT_COMPRESSED_HI 0x124
-#define MCHIP_VRJ_COMP_DATA_FORMAT 0x128
-#define MCHIP_VRJ_TABLE_DATA 0x140
-#define MCHIP_VRJ_RESTART_INTERVAL 0x148
-#define MCHIP_VRJ_NUM_LINES 0x150
-#define MCHIP_VRJ_NUM_PIXELS 0x158
-#define MCHIP_VRJ_NUM_COMPONENTS 0x160
-#define MCHIP_VRJ_SOF1 0x168
-#define MCHIP_VRJ_SOF2 0x170
-#define MCHIP_VRJ_SOF3 0x178
-#define MCHIP_VRJ_SOF4 0x180
-#define MCHIP_VRJ_SOS 0x188
-#define MCHIP_VRJ_SOFT_RESET 0x190
-
-#define MCHIP_VRJ_STATUS 0x1c0
-#define MCHIP_VRJ_STATUS_BUSY 0x00001
-#define MCHIP_VRJ_STATUS_COMP_ACCESS 0x00002
-#define MCHIP_VRJ_STATUS_PIXEL_ACCESS 0x00004
-#define MCHIP_VRJ_STATUS_ERROR 0x00008
-
-#define MCHIP_VRJ_IRQ_FLAG 0x1c8
-#define MCHIP_VRJ_ERROR_REPORT 0x1d8
-
-#define MCHIP_VRJ_START_COMMAND 0x1a0
-
-/****************************************************************************/
-/* Driver definitions. */
-/****************************************************************************/
-
-/* Sony Programmable I/O Controller for accessing the camera commands */
-#include <linux/sony-laptop.h>
-
-/* private API definitions */
-#include <linux/meye.h>
-#include <linux/mutex.h>
-
-
-/* Enable jpg software correction */
-#define MEYE_JPEG_CORRECTION 1
-
-/* Maximum size of a buffer */
-#define MEYE_MAX_BUFSIZE 614400 /* 640 * 480 * 2 */
-
-/* Maximum number of buffers */
-#define MEYE_MAX_BUFNBRS 32
-
-/* State of a buffer */
-#define MEYE_BUF_UNUSED 0 /* not used */
-#define MEYE_BUF_USING 1 /* currently grabbing / playing */
-#define MEYE_BUF_DONE 2 /* done */
-
-/* grab buffer */
-struct meye_grab_buffer {
- int state; /* state of buffer */
- unsigned long size; /* size of jpg frame */
- u64 ts; /* timestamp */
- unsigned long sequence; /* sequence number */
-};
-
-/* size of kfifos containing buffer indices */
-#define MEYE_QUEUE_SIZE MEYE_MAX_BUFNBRS
-
-/* Motion Eye device structure */
-struct meye {
- struct v4l2_device v4l2_dev; /* Main v4l2_device struct */
- struct v4l2_ctrl_handler hdl;
- struct pci_dev *mchip_dev; /* pci device */
- u8 mchip_irq; /* irq */
- u8 mchip_mode; /* actual mchip mode: HIC_MODE... */
- u8 mchip_fnum; /* current mchip frame number */
- unsigned char __iomem *mchip_mmregs;/* mchip: memory mapped registers */
- u8 *mchip_ptable[MCHIP_NB_PAGES];/* mchip: ptable */
- void *mchip_ptable_toc; /* mchip: ptable toc */
- dma_addr_t mchip_dmahandle; /* mchip: dma handle to ptable toc */
- unsigned char *grab_fbuffer; /* capture framebuffer */
- unsigned char *grab_temp; /* temporary buffer */
- /* list of buffers */
- struct meye_grab_buffer grab_buffer[MEYE_MAX_BUFNBRS];
- int vma_use_count[MEYE_MAX_BUFNBRS]; /* mmap count */
- struct mutex lock; /* mutex for open/mmap... */
- struct kfifo grabq; /* queue for buffers to be grabbed */
- spinlock_t grabq_lock; /* lock protecting the queue */
- struct kfifo doneq; /* queue for grabbed buffers */
- spinlock_t doneq_lock; /* lock protecting the queue */
- wait_queue_head_t proc_list; /* wait queue */
- struct video_device vdev; /* video device parameters */
- u16 brightness;
- u16 hue;
- u16 contrast;
- u16 colour;
- struct meye_params params; /* additional parameters */
- unsigned long in_use; /* set to 1 if the device is in use */
- u8 pm_mchip_mode; /* old mchip mode */
-};
-
-#endif
diff --git a/drivers/staging/media/deprecated/saa7146/Kconfig b/drivers/staging/media/deprecated/saa7146/Kconfig
deleted file mode 100644
index 54154da79f59..000000000000
--- a/drivers/staging/media/deprecated/saa7146/Kconfig
+++ /dev/null
@@ -1,5 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-source "drivers/staging/media/deprecated/saa7146/common/Kconfig"
-source "drivers/staging/media/deprecated/saa7146/av7110/Kconfig"
-source "drivers/staging/media/deprecated/saa7146/saa7146/Kconfig"
-source "drivers/staging/media/deprecated/saa7146/ttpci/Kconfig"
diff --git a/drivers/staging/media/deprecated/saa7146/Makefile b/drivers/staging/media/deprecated/saa7146/Makefile
deleted file mode 100644
index 68e7aa10c639..000000000000
--- a/drivers/staging/media/deprecated/saa7146/Makefile
+++ /dev/null
@@ -1,2 +0,0 @@
- # SPDX-License-Identifier: GPL-2.0-only
-obj-y += common/ av7110/ saa7146/ ttpci/
diff --git a/drivers/staging/media/deprecated/saa7146/av7110/TODO b/drivers/staging/media/deprecated/saa7146/av7110/TODO
deleted file mode 100644
index 38817e04bb67..000000000000
--- a/drivers/staging/media/deprecated/saa7146/av7110/TODO
+++ /dev/null
@@ -1,9 +0,0 @@
-- This driver is too old and relies on a different API.
- Drop it from Kernel on a couple of versions.
-- Cleanup patches for the drivers here won't be accepted.
-
-These drivers are now deprecated with the intent of
-removing them altogether by the beginning of 2023.
-
-If someone is interested in doing this work, then contact the
-linux-media mailinglist (https://linuxtv.org/lists.php).
diff --git a/drivers/staging/media/deprecated/saa7146/common/saa7146.h b/drivers/staging/media/deprecated/saa7146/common/saa7146.h
deleted file mode 100644
index 71ce63c99cb4..000000000000
--- a/drivers/staging/media/deprecated/saa7146/common/saa7146.h
+++ /dev/null
@@ -1,472 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __SAA7146__
-#define __SAA7146__
-
-#include <linux/delay.h> /* for delay-stuff */
-#include <linux/slab.h> /* for kmalloc/kfree */
-#include <linux/pci.h> /* for pci-config-stuff, vendor ids etc. */
-#include <linux/init.h> /* for "__init" */
-#include <linux/interrupt.h> /* for IMMEDIATE_BH */
-#include <linux/kmod.h> /* for kernel module loader */
-#include <linux/i2c.h> /* for i2c subsystem */
-#include <asm/io.h> /* for accessing devices */
-#include <linux/stringify.h>
-#include <linux/mutex.h>
-#include <linux/scatterlist.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-ctrls.h>
-
-#include <linux/vmalloc.h> /* for vmalloc() */
-#include <linux/mm.h> /* for vmalloc_to_page() */
-
-#define saa7146_write(sxy,adr,dat) writel((dat),(sxy->mem+(adr)))
-#define saa7146_read(sxy,adr) readl(sxy->mem+(adr))
-
-extern unsigned int saa7146_debug;
-
-#ifndef DEBUG_VARIABLE
- #define DEBUG_VARIABLE saa7146_debug
-#endif
-
-#define ERR(fmt, ...) pr_err("%s: " fmt, __func__, ##__VA_ARGS__)
-
-#define _DBG(mask, fmt, ...) \
-do { \
- if (DEBUG_VARIABLE & mask) \
- pr_debug("%s(): " fmt, __func__, ##__VA_ARGS__); \
-} while (0)
-
-/* simple debug messages */
-#define DEB_S(fmt, ...) _DBG(0x01, fmt, ##__VA_ARGS__)
-/* more detailed debug messages */
-#define DEB_D(fmt, ...) _DBG(0x02, fmt, ##__VA_ARGS__)
-/* print enter and exit of functions */
-#define DEB_EE(fmt, ...) _DBG(0x04, fmt, ##__VA_ARGS__)
-/* i2c debug messages */
-#define DEB_I2C(fmt, ...) _DBG(0x08, fmt, ##__VA_ARGS__)
-/* vbi debug messages */
-#define DEB_VBI(fmt, ...) _DBG(0x10, fmt, ##__VA_ARGS__)
-/* interrupt debug messages */
-#define DEB_INT(fmt, ...) _DBG(0x20, fmt, ##__VA_ARGS__)
-/* capture debug messages */
-#define DEB_CAP(fmt, ...) _DBG(0x40, fmt, ##__VA_ARGS__)
-
-#define SAA7146_ISR_CLEAR(x,y) \
- saa7146_write(x, ISR, (y));
-
-struct module;
-
-struct saa7146_dev;
-struct saa7146_extension;
-struct saa7146_vv;
-
-/* saa7146 page table */
-struct saa7146_pgtable {
- unsigned int size;
- __le32 *cpu;
- dma_addr_t dma;
- /* used for offsets for u,v planes for planar capture modes */
- unsigned long offset;
- /* used for custom pagetables (used for example by budget dvb cards) */
- struct scatterlist *slist;
- int nents;
-};
-
-struct saa7146_pci_extension_data {
- struct saa7146_extension *ext;
- void *ext_priv; /* most likely a name string */
-};
-
-#define MAKE_EXTENSION_PCI(x_var, x_vendor, x_device) \
- { \
- .vendor = PCI_VENDOR_ID_PHILIPS, \
- .device = PCI_DEVICE_ID_PHILIPS_SAA7146, \
- .subvendor = x_vendor, \
- .subdevice = x_device, \
- .driver_data = (unsigned long)& x_var, \
- }
-
-struct saa7146_extension
-{
- char name[32]; /* name of the device */
-#define SAA7146_USE_I2C_IRQ 0x1
-#define SAA7146_I2C_SHORT_DELAY 0x2
- int flags;
-
- /* pairs of subvendor and subdevice ids for
- supported devices, last entry 0xffff, 0xfff */
- struct module *module;
- struct pci_driver driver;
- const struct pci_device_id *pci_tbl;
-
- /* extension functions */
- int (*probe)(struct saa7146_dev *);
- int (*attach)(struct saa7146_dev *, struct saa7146_pci_extension_data *);
- int (*detach)(struct saa7146_dev*);
-
- u32 irq_mask; /* mask to indicate, which irq-events are handled by the extension */
- void (*irq_func)(struct saa7146_dev*, u32* irq_mask);
-};
-
-struct saa7146_dma
-{
- dma_addr_t dma_handle;
- __le32 *cpu_addr;
-};
-
-struct saa7146_dev
-{
- struct module *module;
-
- struct v4l2_device v4l2_dev;
- struct v4l2_ctrl_handler ctrl_handler;
-
- /* different device locks */
- spinlock_t slock;
- struct mutex v4l2_lock;
-
- unsigned char __iomem *mem; /* pointer to mapped IO memory */
- u32 revision; /* chip revision; needed for bug-workarounds*/
-
- /* pci-device & irq stuff*/
- char name[32];
- struct pci_dev *pci;
- u32 int_todo;
- spinlock_t int_slock;
-
- /* extension handling */
- struct saa7146_extension *ext; /* indicates if handled by extension */
- void *ext_priv; /* pointer for extension private use (most likely some private data) */
- struct saa7146_ext_vv *ext_vv_data;
-
- /* per device video/vbi information (if available) */
- struct saa7146_vv *vv_data;
- void (*vv_callback)(struct saa7146_dev *dev, unsigned long status);
-
- /* i2c-stuff */
- struct mutex i2c_lock;
-
- u32 i2c_bitrate;
- struct saa7146_dma d_i2c; /* pointer to i2c memory */
- wait_queue_head_t i2c_wq;
- int i2c_op;
-
- /* memories */
- struct saa7146_dma d_rps0;
- struct saa7146_dma d_rps1;
-};
-
-static inline struct saa7146_dev *to_saa7146_dev(struct v4l2_device *v4l2_dev)
-{
- return container_of(v4l2_dev, struct saa7146_dev, v4l2_dev);
-}
-
-/* from saa7146_i2c.c */
-int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate);
-
-/* from saa7146_core.c */
-int saa7146_register_extension(struct saa7146_extension*);
-int saa7146_unregister_extension(struct saa7146_extension*);
-struct saa7146_format* saa7146_format_by_fourcc(struct saa7146_dev *dev, int fourcc);
-int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt);
-void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt);
-int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt, struct scatterlist *list, int length );
-void *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt);
-void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, void *mem, struct saa7146_pgtable *pt);
-void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data);
-int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop);
-
-/* some memory sizes */
-#define SAA7146_I2C_MEM ( 1*PAGE_SIZE)
-#define SAA7146_RPS_MEM ( 1*PAGE_SIZE)
-
-/* some i2c constants */
-#define SAA7146_I2C_TIMEOUT 100 /* i2c-timeout-value in ms */
-#define SAA7146_I2C_RETRIES 3 /* how many times shall we retry an i2c-operation? */
-#define SAA7146_I2C_DELAY 5 /* time we wait after certain i2c-operations */
-
-/* unsorted defines */
-#define ME1 0x0000000800
-#define PV1 0x0000000008
-
-/* gpio defines */
-#define SAA7146_GPIO_INPUT 0x00
-#define SAA7146_GPIO_IRQHI 0x10
-#define SAA7146_GPIO_IRQLO 0x20
-#define SAA7146_GPIO_IRQHL 0x30
-#define SAA7146_GPIO_OUTLO 0x40
-#define SAA7146_GPIO_OUTHI 0x50
-
-/* debi defines */
-#define DEBINOSWAP 0x000e0000
-
-/* define for the register programming sequencer (rps) */
-#define CMD_NOP 0x00000000 /* No operation */
-#define CMD_CLR_EVENT 0x00000000 /* Clear event */
-#define CMD_SET_EVENT 0x10000000 /* Set signal event */
-#define CMD_PAUSE 0x20000000 /* Pause */
-#define CMD_CHECK_LATE 0x30000000 /* Check late */
-#define CMD_UPLOAD 0x40000000 /* Upload */
-#define CMD_STOP 0x50000000 /* Stop */
-#define CMD_INTERRUPT 0x60000000 /* Interrupt */
-#define CMD_JUMP 0x80000000 /* Jump */
-#define CMD_WR_REG 0x90000000 /* Write (load) register */
-#define CMD_RD_REG 0xa0000000 /* Read (store) register */
-#define CMD_WR_REG_MASK 0xc0000000 /* Write register with mask */
-
-#define CMD_OAN MASK_27
-#define CMD_INV MASK_26
-#define CMD_SIG4 MASK_25
-#define CMD_SIG3 MASK_24
-#define CMD_SIG2 MASK_23
-#define CMD_SIG1 MASK_22
-#define CMD_SIG0 MASK_21
-#define CMD_O_FID_B MASK_14
-#define CMD_E_FID_B MASK_13
-#define CMD_O_FID_A MASK_12
-#define CMD_E_FID_A MASK_11
-
-/* some events and command modifiers for rps1 squarewave generator */
-#define EVT_HS (1<<15) // Source Line Threshold reached
-#define EVT_VBI_B (1<<9) // VSYNC Event
-#define RPS_OAN (1<<27) // 1: OR events, 0: AND events
-#define RPS_INV (1<<26) // Invert (compound) event
-#define GPIO3_MSK 0xFF000000 // GPIO #3 control bits
-
-/* Bit mask constants */
-#define MASK_00 0x00000001 /* Mask value for bit 0 */
-#define MASK_01 0x00000002 /* Mask value for bit 1 */
-#define MASK_02 0x00000004 /* Mask value for bit 2 */
-#define MASK_03 0x00000008 /* Mask value for bit 3 */
-#define MASK_04 0x00000010 /* Mask value for bit 4 */
-#define MASK_05 0x00000020 /* Mask value for bit 5 */
-#define MASK_06 0x00000040 /* Mask value for bit 6 */
-#define MASK_07 0x00000080 /* Mask value for bit 7 */
-#define MASK_08 0x00000100 /* Mask value for bit 8 */
-#define MASK_09 0x00000200 /* Mask value for bit 9 */
-#define MASK_10 0x00000400 /* Mask value for bit 10 */
-#define MASK_11 0x00000800 /* Mask value for bit 11 */
-#define MASK_12 0x00001000 /* Mask value for bit 12 */
-#define MASK_13 0x00002000 /* Mask value for bit 13 */
-#define MASK_14 0x00004000 /* Mask value for bit 14 */
-#define MASK_15 0x00008000 /* Mask value for bit 15 */
-#define MASK_16 0x00010000 /* Mask value for bit 16 */
-#define MASK_17 0x00020000 /* Mask value for bit 17 */
-#define MASK_18 0x00040000 /* Mask value for bit 18 */
-#define MASK_19 0x00080000 /* Mask value for bit 19 */
-#define MASK_20 0x00100000 /* Mask value for bit 20 */
-#define MASK_21 0x00200000 /* Mask value for bit 21 */
-#define MASK_22 0x00400000 /* Mask value for bit 22 */
-#define MASK_23 0x00800000 /* Mask value for bit 23 */
-#define MASK_24 0x01000000 /* Mask value for bit 24 */
-#define MASK_25 0x02000000 /* Mask value for bit 25 */
-#define MASK_26 0x04000000 /* Mask value for bit 26 */
-#define MASK_27 0x08000000 /* Mask value for bit 27 */
-#define MASK_28 0x10000000 /* Mask value for bit 28 */
-#define MASK_29 0x20000000 /* Mask value for bit 29 */
-#define MASK_30 0x40000000 /* Mask value for bit 30 */
-#define MASK_31 0x80000000 /* Mask value for bit 31 */
-
-#define MASK_B0 0x000000ff /* Mask value for byte 0 */
-#define MASK_B1 0x0000ff00 /* Mask value for byte 1 */
-#define MASK_B2 0x00ff0000 /* Mask value for byte 2 */
-#define MASK_B3 0xff000000 /* Mask value for byte 3 */
-
-#define MASK_W0 0x0000ffff /* Mask value for word 0 */
-#define MASK_W1 0xffff0000 /* Mask value for word 1 */
-
-#define MASK_PA 0xfffffffc /* Mask value for physical address */
-#define MASK_PR 0xfffffffe /* Mask value for protection register */
-#define MASK_ER 0xffffffff /* Mask value for the entire register */
-
-#define MASK_NONE 0x00000000 /* No mask */
-
-/* register aliases */
-#define BASE_ODD1 0x00 /* Video DMA 1 registers */
-#define BASE_EVEN1 0x04
-#define PROT_ADDR1 0x08
-#define PITCH1 0x0C
-#define BASE_PAGE1 0x10 /* Video DMA 1 base page */
-#define NUM_LINE_BYTE1 0x14
-
-#define BASE_ODD2 0x18 /* Video DMA 2 registers */
-#define BASE_EVEN2 0x1C
-#define PROT_ADDR2 0x20
-#define PITCH2 0x24
-#define BASE_PAGE2 0x28 /* Video DMA 2 base page */
-#define NUM_LINE_BYTE2 0x2C
-
-#define BASE_ODD3 0x30 /* Video DMA 3 registers */
-#define BASE_EVEN3 0x34
-#define PROT_ADDR3 0x38
-#define PITCH3 0x3C
-#define BASE_PAGE3 0x40 /* Video DMA 3 base page */
-#define NUM_LINE_BYTE3 0x44
-
-#define PCI_BT_V1 0x48 /* Video/FIFO 1 */
-#define PCI_BT_V2 0x49 /* Video/FIFO 2 */
-#define PCI_BT_V3 0x4A /* Video/FIFO 3 */
-#define PCI_BT_DEBI 0x4B /* DEBI */
-#define PCI_BT_A 0x4C /* Audio */
-
-#define DD1_INIT 0x50 /* Init setting of DD1 interface */
-
-#define DD1_STREAM_B 0x54 /* DD1 B video data stream handling */
-#define DD1_STREAM_A 0x56 /* DD1 A video data stream handling */
-
-#define BRS_CTRL 0x58 /* BRS control register */
-#define HPS_CTRL 0x5C /* HPS control register */
-#define HPS_V_SCALE 0x60 /* HPS vertical scale */
-#define HPS_V_GAIN 0x64 /* HPS vertical ACL and gain */
-#define HPS_H_PRESCALE 0x68 /* HPS horizontal prescale */
-#define HPS_H_SCALE 0x6C /* HPS horizontal scale */
-#define BCS_CTRL 0x70 /* BCS control */
-#define CHROMA_KEY_RANGE 0x74
-#define CLIP_FORMAT_CTRL 0x78 /* HPS outputs formats & clipping */
-
-#define DEBI_CONFIG 0x7C
-#define DEBI_COMMAND 0x80
-#define DEBI_PAGE 0x84
-#define DEBI_AD 0x88
-
-#define I2C_TRANSFER 0x8C
-#define I2C_STATUS 0x90
-
-#define BASE_A1_IN 0x94 /* Audio 1 input DMA */
-#define PROT_A1_IN 0x98
-#define PAGE_A1_IN 0x9C
-
-#define BASE_A1_OUT 0xA0 /* Audio 1 output DMA */
-#define PROT_A1_OUT 0xA4
-#define PAGE_A1_OUT 0xA8
-
-#define BASE_A2_IN 0xAC /* Audio 2 input DMA */
-#define PROT_A2_IN 0xB0
-#define PAGE_A2_IN 0xB4
-
-#define BASE_A2_OUT 0xB8 /* Audio 2 output DMA */
-#define PROT_A2_OUT 0xBC
-#define PAGE_A2_OUT 0xC0
-
-#define RPS_PAGE0 0xC4 /* RPS task 0 page register */
-#define RPS_PAGE1 0xC8 /* RPS task 1 page register */
-
-#define RPS_THRESH0 0xCC /* HBI threshold for task 0 */
-#define RPS_THRESH1 0xD0 /* HBI threshold for task 1 */
-
-#define RPS_TOV0 0xD4 /* RPS timeout for task 0 */
-#define RPS_TOV1 0xD8 /* RPS timeout for task 1 */
-
-#define IER 0xDC /* Interrupt enable register */
-
-#define GPIO_CTRL 0xE0 /* GPIO 0-3 register */
-
-#define EC1SSR 0xE4 /* Event cnt set 1 source select */
-#define EC2SSR 0xE8 /* Event cnt set 2 source select */
-#define ECT1R 0xEC /* Event cnt set 1 thresholds */
-#define ECT2R 0xF0 /* Event cnt set 2 thresholds */
-
-#define ACON1 0xF4
-#define ACON2 0xF8
-
-#define MC1 0xFC /* Main control register 1 */
-#define MC2 0x100 /* Main control register 2 */
-
-#define RPS_ADDR0 0x104 /* RPS task 0 address register */
-#define RPS_ADDR1 0x108 /* RPS task 1 address register */
-
-#define ISR 0x10C /* Interrupt status register */
-#define PSR 0x110 /* Primary status register */
-#define SSR 0x114 /* Secondary status register */
-
-#define EC1R 0x118 /* Event counter set 1 register */
-#define EC2R 0x11C /* Event counter set 2 register */
-
-#define PCI_VDP1 0x120 /* Video DMA pointer of FIFO 1 */
-#define PCI_VDP2 0x124 /* Video DMA pointer of FIFO 2 */
-#define PCI_VDP3 0x128 /* Video DMA pointer of FIFO 3 */
-#define PCI_ADP1 0x12C /* Audio DMA pointer of audio out 1 */
-#define PCI_ADP2 0x130 /* Audio DMA pointer of audio in 1 */
-#define PCI_ADP3 0x134 /* Audio DMA pointer of audio out 2 */
-#define PCI_ADP4 0x138 /* Audio DMA pointer of audio in 2 */
-#define PCI_DMA_DDP 0x13C /* DEBI DMA pointer */
-
-#define LEVEL_REP 0x140,
-#define A_TIME_SLOT1 0x180, /* from 180 - 1BC */
-#define A_TIME_SLOT2 0x1C0, /* from 1C0 - 1FC */
-
-/* isr masks */
-#define SPCI_PPEF 0x80000000 /* PCI parity error */
-#define SPCI_PABO 0x40000000 /* PCI access error (target or master abort) */
-#define SPCI_PPED 0x20000000 /* PCI parity error on 'real time data' */
-#define SPCI_RPS_I1 0x10000000 /* Interrupt issued by RPS1 */
-#define SPCI_RPS_I0 0x08000000 /* Interrupt issued by RPS0 */
-#define SPCI_RPS_LATE1 0x04000000 /* RPS task 1 is late */
-#define SPCI_RPS_LATE0 0x02000000 /* RPS task 0 is late */
-#define SPCI_RPS_E1 0x01000000 /* RPS error from task 1 */
-#define SPCI_RPS_E0 0x00800000 /* RPS error from task 0 */
-#define SPCI_RPS_TO1 0x00400000 /* RPS timeout task 1 */
-#define SPCI_RPS_TO0 0x00200000 /* RPS timeout task 0 */
-#define SPCI_UPLD 0x00100000 /* RPS in upload */
-#define SPCI_DEBI_S 0x00080000 /* DEBI status */
-#define SPCI_DEBI_E 0x00040000 /* DEBI error */
-#define SPCI_IIC_S 0x00020000 /* I2C status */
-#define SPCI_IIC_E 0x00010000 /* I2C error */
-#define SPCI_A2_IN 0x00008000 /* Audio 2 input DMA protection / limit */
-#define SPCI_A2_OUT 0x00004000 /* Audio 2 output DMA protection / limit */
-#define SPCI_A1_IN 0x00002000 /* Audio 1 input DMA protection / limit */
-#define SPCI_A1_OUT 0x00001000 /* Audio 1 output DMA protection / limit */
-#define SPCI_AFOU 0x00000800 /* Audio FIFO over- / underflow */
-#define SPCI_V_PE 0x00000400 /* Video protection address */
-#define SPCI_VFOU 0x00000200 /* Video FIFO over- / underflow */
-#define SPCI_FIDA 0x00000100 /* Field ID video port A */
-#define SPCI_FIDB 0x00000080 /* Field ID video port B */
-#define SPCI_PIN3 0x00000040 /* GPIO pin 3 */
-#define SPCI_PIN2 0x00000020 /* GPIO pin 2 */
-#define SPCI_PIN1 0x00000010 /* GPIO pin 1 */
-#define SPCI_PIN0 0x00000008 /* GPIO pin 0 */
-#define SPCI_ECS 0x00000004 /* Event counter 1, 2, 4, 5 */
-#define SPCI_EC3S 0x00000002 /* Event counter 3 */
-#define SPCI_EC0S 0x00000001 /* Event counter 0 */
-
-/* i2c */
-#define SAA7146_I2C_ABORT (1<<7)
-#define SAA7146_I2C_SPERR (1<<6)
-#define SAA7146_I2C_APERR (1<<5)
-#define SAA7146_I2C_DTERR (1<<4)
-#define SAA7146_I2C_DRERR (1<<3)
-#define SAA7146_I2C_AL (1<<2)
-#define SAA7146_I2C_ERR (1<<1)
-#define SAA7146_I2C_BUSY (1<<0)
-
-#define SAA7146_I2C_START (0x3)
-#define SAA7146_I2C_CONT (0x2)
-#define SAA7146_I2C_STOP (0x1)
-#define SAA7146_I2C_NOP (0x0)
-
-#define SAA7146_I2C_BUS_BIT_RATE_6400 (0x500)
-#define SAA7146_I2C_BUS_BIT_RATE_3200 (0x100)
-#define SAA7146_I2C_BUS_BIT_RATE_480 (0x400)
-#define SAA7146_I2C_BUS_BIT_RATE_320 (0x600)
-#define SAA7146_I2C_BUS_BIT_RATE_240 (0x700)
-#define SAA7146_I2C_BUS_BIT_RATE_120 (0x000)
-#define SAA7146_I2C_BUS_BIT_RATE_80 (0x200)
-#define SAA7146_I2C_BUS_BIT_RATE_60 (0x300)
-
-static inline void SAA7146_IER_DISABLE(struct saa7146_dev *x, unsigned y)
-{
- unsigned long flags;
- spin_lock_irqsave(&x->int_slock, flags);
- saa7146_write(x, IER, saa7146_read(x, IER) & ~y);
- spin_unlock_irqrestore(&x->int_slock, flags);
-}
-
-static inline void SAA7146_IER_ENABLE(struct saa7146_dev *x, unsigned y)
-{
- unsigned long flags;
- spin_lock_irqsave(&x->int_slock, flags);
- saa7146_write(x, IER, saa7146_read(x, IER) | y);
- spin_unlock_irqrestore(&x->int_slock, flags);
-}
-
-#endif
diff --git a/drivers/staging/media/deprecated/saa7146/common/saa7146_vv.h b/drivers/staging/media/deprecated/saa7146/common/saa7146_vv.h
deleted file mode 100644
index d7bd916fe3ad..000000000000
--- a/drivers/staging/media/deprecated/saa7146/common/saa7146_vv.h
+++ /dev/null
@@ -1,266 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __SAA7146_VV__
-#define __SAA7146_VV__
-
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-fh.h>
-#include <media/videobuf-dma-sg.h>
-#include "saa7146.h"
-
-#define MAX_SAA7146_CAPTURE_BUFFERS 32 /* arbitrary */
-#define BUFFER_TIMEOUT (HZ/2) /* 0.5 seconds */
-
-#define WRITE_RPS0(x) do { \
- dev->d_rps0.cpu_addr[ count++ ] = cpu_to_le32(x); \
- } while (0);
-
-#define WRITE_RPS1(x) do { \
- dev->d_rps1.cpu_addr[ count++ ] = cpu_to_le32(x); \
- } while (0);
-
-struct saa7146_video_dma {
- u32 base_odd;
- u32 base_even;
- u32 prot_addr;
- u32 pitch;
- u32 base_page;
- u32 num_line_byte;
-};
-
-#define FORMAT_BYTE_SWAP 0x1
-#define FORMAT_IS_PLANAR 0x2
-
-struct saa7146_format {
- u32 pixelformat;
- u32 trans;
- u8 depth;
- u8 flags;
- u8 swap;
-};
-
-struct saa7146_standard
-{
- char *name;
- v4l2_std_id id;
-
- int v_offset; /* number of lines of vertical offset before processing */
- int v_field; /* number of lines in a field for HPS to process */
-
- int h_offset; /* horizontal offset of processing window */
- int h_pixels; /* number of horizontal pixels to process */
-
- int v_max_out;
- int h_max_out;
-};
-
-/* buffer for one video/vbi frame */
-struct saa7146_buf {
- /* common v4l buffer stuff -- must be first */
- struct videobuf_buffer vb;
-
- /* saa7146 specific */
- struct v4l2_pix_format *fmt;
- int (*activate)(struct saa7146_dev *dev,
- struct saa7146_buf *buf,
- struct saa7146_buf *next);
-
- /* page tables */
- struct saa7146_pgtable pt[3];
-};
-
-struct saa7146_dmaqueue {
- struct saa7146_dev *dev;
- struct saa7146_buf *curr;
- struct list_head queue;
- struct timer_list timeout;
-};
-
-struct saa7146_overlay {
- struct saa7146_fh *fh;
- struct v4l2_window win;
- struct v4l2_clip clips[16];
- int nclips;
-};
-
-/* per open data */
-struct saa7146_fh {
- /* Must be the first field! */
- struct v4l2_fh fh;
- struct saa7146_dev *dev;
-
- /* video capture */
- struct videobuf_queue video_q;
-
- /* vbi capture */
- struct videobuf_queue vbi_q;
-
- unsigned int resources; /* resource management for device open */
-};
-
-#define STATUS_OVERLAY 0x01
-#define STATUS_CAPTURE 0x02
-
-struct saa7146_vv
-{
- /* vbi capture */
- struct saa7146_dmaqueue vbi_dmaq;
- struct v4l2_vbi_format vbi_fmt;
- struct timer_list vbi_read_timeout;
- struct file *vbi_read_timeout_file;
- /* vbi workaround interrupt queue */
- wait_queue_head_t vbi_wq;
- int vbi_fieldcount;
- struct saa7146_fh *vbi_streaming;
-
- int video_status;
- struct saa7146_fh *video_fh;
-
- /* video overlay */
- struct saa7146_overlay ov;
- struct v4l2_framebuffer ov_fb;
- struct saa7146_format *ov_fmt;
- struct saa7146_fh *ov_suspend;
-
- /* video capture */
- struct saa7146_dmaqueue video_dmaq;
- struct v4l2_pix_format video_fmt;
- enum v4l2_field last_field;
-
- /* common: fixme? shouldn't this be in saa7146_fh?
- (this leads to a more complicated question: shall the driver
- store the different settings (for example S_INPUT) for every open
- and restore it appropriately, or should all settings be common for
- all opens? currently, we do the latter, like all other
- drivers do... */
- struct saa7146_standard *standard;
-
- int vflip;
- int hflip;
- int current_hps_source;
- int current_hps_sync;
-
- struct saa7146_dma d_clipping; /* pointer to clipping memory */
-
- unsigned int resources; /* resource management for device */
-};
-
-/* flags */
-#define SAA7146_USE_PORT_B_FOR_VBI 0x2 /* use input port b for vbi hardware bug workaround */
-
-struct saa7146_ext_vv
-{
- /* information about the video capabilities of the device */
- int inputs;
- int audios;
- u32 capabilities;
- int flags;
-
- /* additionally supported transmission standards */
- struct saa7146_standard *stds;
- int num_stds;
- int (*std_callback)(struct saa7146_dev*, struct saa7146_standard *);
-
- /* the extension can override this */
- struct v4l2_ioctl_ops vid_ops;
- struct v4l2_ioctl_ops vbi_ops;
- /* pointer to the saa7146 core ops */
- const struct v4l2_ioctl_ops *core_ops;
-
- struct v4l2_file_operations vbi_fops;
-};
-
-struct saa7146_use_ops {
- void (*init)(struct saa7146_dev *, struct saa7146_vv *);
- int(*open)(struct saa7146_dev *, struct file *);
- void (*release)(struct saa7146_dev *, struct file *);
- void (*irq_done)(struct saa7146_dev *, unsigned long status);
- ssize_t (*read)(struct file *, char __user *, size_t, loff_t *);
-};
-
-/* from saa7146_fops.c */
-int saa7146_register_device(struct video_device *vid, struct saa7146_dev *dev, char *name, int type);
-int saa7146_unregister_device(struct video_device *vid, struct saa7146_dev *dev);
-void saa7146_buffer_finish(struct saa7146_dev *dev, struct saa7146_dmaqueue *q, int state);
-void saa7146_buffer_next(struct saa7146_dev *dev, struct saa7146_dmaqueue *q,int vbi);
-int saa7146_buffer_queue(struct saa7146_dev *dev, struct saa7146_dmaqueue *q, struct saa7146_buf *buf);
-void saa7146_buffer_timeout(struct timer_list *t);
-void saa7146_dma_free(struct saa7146_dev* dev,struct videobuf_queue *q,
- struct saa7146_buf *buf);
-
-int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv);
-int saa7146_vv_release(struct saa7146_dev* dev);
-
-/* from saa7146_hlp.c */
-int saa7146_enable_overlay(struct saa7146_fh *fh);
-void saa7146_disable_overlay(struct saa7146_fh *fh);
-
-void saa7146_set_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next);
-void saa7146_write_out_dma(struct saa7146_dev* dev, int which, struct saa7146_video_dma* vdma) ;
-void saa7146_set_hps_source_and_sync(struct saa7146_dev *saa, int source, int sync);
-void saa7146_set_gpio(struct saa7146_dev *saa, u8 pin, u8 data);
-
-/* from saa7146_video.c */
-extern const struct v4l2_ioctl_ops saa7146_video_ioctl_ops;
-extern const struct v4l2_ioctl_ops saa7146_vbi_ioctl_ops;
-extern const struct saa7146_use_ops saa7146_video_uops;
-int saa7146_start_preview(struct saa7146_fh *fh);
-int saa7146_stop_preview(struct saa7146_fh *fh);
-long saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *arg);
-int saa7146_s_ctrl(struct v4l2_ctrl *ctrl);
-
-/* from saa7146_vbi.c */
-extern const struct saa7146_use_ops saa7146_vbi_uops;
-
-/* resource management functions */
-int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit);
-void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits);
-
-#define RESOURCE_DMA1_HPS 0x1
-#define RESOURCE_DMA2_CLP 0x2
-#define RESOURCE_DMA3_BRS 0x4
-
-/* saa7146 source inputs */
-#define SAA7146_HPS_SOURCE_PORT_A 0x00
-#define SAA7146_HPS_SOURCE_PORT_B 0x01
-#define SAA7146_HPS_SOURCE_YPB_CPA 0x02
-#define SAA7146_HPS_SOURCE_YPA_CPB 0x03
-
-/* sync inputs */
-#define SAA7146_HPS_SYNC_PORT_A 0x00
-#define SAA7146_HPS_SYNC_PORT_B 0x01
-
-/* some memory sizes */
-/* max. 16 clipping rectangles */
-#define SAA7146_CLIPPING_MEM (16 * 4 * sizeof(u32))
-
-/* some defines for the various clipping-modes */
-#define SAA7146_CLIPPING_RECT 0x4
-#define SAA7146_CLIPPING_RECT_INVERTED 0x5
-#define SAA7146_CLIPPING_MASK 0x6
-#define SAA7146_CLIPPING_MASK_INVERTED 0x7
-
-/* output formats: each entry holds four information */
-#define RGB08_COMPOSED 0x0217 /* composed is used in the sense of "not-planar" */
-/* this means: planar?=0, yuv2rgb-conversation-mode=2, dither=yes(=1), format-mode = 7 */
-#define RGB15_COMPOSED 0x0213
-#define RGB16_COMPOSED 0x0210
-#define RGB24_COMPOSED 0x0201
-#define RGB32_COMPOSED 0x0202
-
-#define Y8 0x0006
-#define YUV411_COMPOSED 0x0003
-#define YUV422_COMPOSED 0x0000
-/* this means: planar?=1, yuv2rgb-conversion-mode=0, dither=no(=0), format-mode = b */
-#define YUV411_DECOMPOSED 0x100b
-#define YUV422_DECOMPOSED 0x1009
-#define YUV420_DECOMPOSED 0x100a
-
-#define IS_PLANAR(x) (x & 0xf000)
-
-/* misc defines */
-#define SAA7146_NO_SWAP (0x0)
-#define SAA7146_TWO_BYTE_SWAP (0x1)
-#define SAA7146_FOUR_BYTE_SWAP (0x2)
-
-#endif
diff --git a/drivers/staging/media/deprecated/saa7146/saa7146/TODO b/drivers/staging/media/deprecated/saa7146/saa7146/TODO
deleted file mode 100644
index c9ae2ec79cea..000000000000
--- a/drivers/staging/media/deprecated/saa7146/saa7146/TODO
+++ /dev/null
@@ -1,7 +0,0 @@
-The saa7146-based drivers are one of the few drivers still not using
-the vb2 framework, so these drivers are now deprecated with the intent of
-removing them altogether by the beginning of 2023.
-
-In order to keep these drivers they have to be converted to vb2.
-If someone is interested in doing this work, then contact the
-linux-media mailinglist (https://linuxtv.org/lists.php).
diff --git a/drivers/staging/media/deprecated/saa7146/ttpci/TODO b/drivers/staging/media/deprecated/saa7146/ttpci/TODO
deleted file mode 100644
index c9ae2ec79cea..000000000000
--- a/drivers/staging/media/deprecated/saa7146/ttpci/TODO
+++ /dev/null
@@ -1,7 +0,0 @@
-The saa7146-based drivers are one of the few drivers still not using
-the vb2 framework, so these drivers are now deprecated with the intent of
-removing them altogether by the beginning of 2023.
-
-In order to keep these drivers they have to be converted to vb2.
-If someone is interested in doing this work, then contact the
-linux-media mailinglist (https://linuxtv.org/lists.php).
diff --git a/drivers/staging/media/deprecated/stkwebcam/Kconfig b/drivers/staging/media/deprecated/stkwebcam/Kconfig
deleted file mode 100644
index 7234498e634a..000000000000
--- a/drivers/staging/media/deprecated/stkwebcam/Kconfig
+++ /dev/null
@@ -1,18 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-config VIDEO_STKWEBCAM
- tristate "USB Syntek DC1125 Camera support (DEPRECATED)"
- depends on VIDEO_DEV
- depends on MEDIA_USB_SUPPORT && MEDIA_CAMERA_SUPPORT
- help
- Say Y here if you want to use this type of camera.
- Supported devices are typically found in some Asus laptops,
- with USB id 174f:a311 and 05e1:0501. Other Syntek cameras
- may be supported by the stk11xx driver, from which this is
- derived, see <http://sourceforge.net/projects/syntekdriver/>
-
- This driver is deprecated and is scheduled for removal by
- the end of 2022. See the TODO file for more information.
-
- To compile this driver as a module, choose M here: the
- module will be called stkwebcam.
-
diff --git a/drivers/staging/media/deprecated/stkwebcam/Makefile b/drivers/staging/media/deprecated/stkwebcam/Makefile
deleted file mode 100644
index 17ad7b6f43d0..000000000000
--- a/drivers/staging/media/deprecated/stkwebcam/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-stkwebcam-objs := stk-webcam.o stk-sensor.o
-
-obj-$(CONFIG_VIDEO_STKWEBCAM) += stkwebcam.o
-
diff --git a/drivers/staging/media/deprecated/stkwebcam/TODO b/drivers/staging/media/deprecated/stkwebcam/TODO
deleted file mode 100644
index 735304a72729..000000000000
--- a/drivers/staging/media/deprecated/stkwebcam/TODO
+++ /dev/null
@@ -1,12 +0,0 @@
-This is a very old driver for very old hardware (specifically
-laptops that use this sensor). In addition according to reports
-the picture quality is quite bad.
-
-This is also one of the few drivers still not using the vb2
-framework (or even the old videobuf framework!), so this driver
-is now deprecated with the intent of removing it altogether by
-the end of 2022.
-
-In order to keep this driver it has to be converted to vb2.
-If someone is interested in doing this work, then contact the
-linux-media mailinglist (https://linuxtv.org/lists.php).
diff --git a/drivers/staging/media/deprecated/stkwebcam/stk-sensor.c b/drivers/staging/media/deprecated/stkwebcam/stk-sensor.c
deleted file mode 100644
index 94aa6a27f934..000000000000
--- a/drivers/staging/media/deprecated/stkwebcam/stk-sensor.c
+++ /dev/null
@@ -1,587 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/* stk-sensor.c: Driver for ov96xx sensor (used in some Syntek webcams)
- *
- * Copyright 2007-2008 Jaime Velasco Juan <jsagarribay@gmail.com>
- *
- * Some parts derived from ov7670.c:
- * Copyright 2006 One Laptop Per Child Association, Inc. Written
- * by Jonathan Corbet with substantial inspiration from Mark
- * McClelland's ovcamchip code.
- *
- * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
- *
- * This file may be distributed under the terms of the GNU General
- */
-
-/* Controlling the sensor via the STK1125 vendor specific control interface:
- * The camera uses an OmniVision sensor and the stk1125 provides an
- * SCCB(i2c)-USB bridge which let us program the sensor.
- * In my case the sensor id is 0x9652, it can be read from sensor's register
- * 0x0A and 0x0B as follows:
- * - read register #R:
- * output #R to index 0x0208
- * output 0x0070 to index 0x0200
- * input 1 byte from index 0x0201 (some kind of status register)
- * until its value is 0x01
- * input 1 byte from index 0x0209. This is the value of #R
- * - write value V to register #R
- * output #R to index 0x0204
- * output V to index 0x0205
- * output 0x0005 to index 0x0200
- * input 1 byte from index 0x0201 until its value becomes 0x04
- */
-
-/* It seems the i2c bus is controlled with these registers */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include "stk-webcam.h"
-
-#define STK_IIC_BASE (0x0200)
-# define STK_IIC_OP (STK_IIC_BASE)
-# define STK_IIC_OP_TX (0x05)
-# define STK_IIC_OP_RX (0x70)
-# define STK_IIC_STAT (STK_IIC_BASE+1)
-# define STK_IIC_STAT_TX_OK (0x04)
-# define STK_IIC_STAT_RX_OK (0x01)
-/* I don't know what does this register.
- * when it is 0x00 or 0x01, we cannot talk to the sensor,
- * other values work */
-# define STK_IIC_ENABLE (STK_IIC_BASE+2)
-# define STK_IIC_ENABLE_NO (0x00)
-/* This is what the driver writes in windows */
-# define STK_IIC_ENABLE_YES (0x1e)
-/*
- * Address of the slave. Seems like the binary driver look for the
- * sensor in multiple places, attempting a reset sequence.
- * We only know about the ov9650
- */
-# define STK_IIC_ADDR (STK_IIC_BASE+3)
-# define STK_IIC_TX_INDEX (STK_IIC_BASE+4)
-# define STK_IIC_TX_VALUE (STK_IIC_BASE+5)
-# define STK_IIC_RX_INDEX (STK_IIC_BASE+8)
-# define STK_IIC_RX_VALUE (STK_IIC_BASE+9)
-
-#define MAX_RETRIES (50)
-
-#define SENSOR_ADDRESS (0x60)
-
-/* From ov7670.c (These registers aren't fully accurate) */
-
-/* Registers */
-#define REG_GAIN 0x00 /* Gain lower 8 bits (rest in vref) */
-#define REG_BLUE 0x01 /* blue gain */
-#define REG_RED 0x02 /* red gain */
-#define REG_VREF 0x03 /* Pieces of GAIN, VSTART, VSTOP */
-#define REG_COM1 0x04 /* Control 1 */
-#define COM1_CCIR656 0x40 /* CCIR656 enable */
-#define COM1_QFMT 0x20 /* QVGA/QCIF format */
-#define COM1_SKIP_0 0x00 /* Do not skip any row */
-#define COM1_SKIP_2 0x04 /* Skip 2 rows of 4 */
-#define COM1_SKIP_3 0x08 /* Skip 3 rows of 4 */
-#define REG_BAVE 0x05 /* U/B Average level */
-#define REG_GbAVE 0x06 /* Y/Gb Average level */
-#define REG_AECHH 0x07 /* AEC MS 5 bits */
-#define REG_RAVE 0x08 /* V/R Average level */
-#define REG_COM2 0x09 /* Control 2 */
-#define COM2_SSLEEP 0x10 /* Soft sleep mode */
-#define REG_PID 0x0a /* Product ID MSB */
-#define REG_VER 0x0b /* Product ID LSB */
-#define REG_COM3 0x0c /* Control 3 */
-#define COM3_SWAP 0x40 /* Byte swap */
-#define COM3_SCALEEN 0x08 /* Enable scaling */
-#define COM3_DCWEN 0x04 /* Enable downsamp/crop/window */
-#define REG_COM4 0x0d /* Control 4 */
-#define REG_COM5 0x0e /* All "reserved" */
-#define REG_COM6 0x0f /* Control 6 */
-#define REG_AECH 0x10 /* More bits of AEC value */
-#define REG_CLKRC 0x11 /* Clock control */
-#define CLK_PLL 0x80 /* Enable internal PLL */
-#define CLK_EXT 0x40 /* Use external clock directly */
-#define CLK_SCALE 0x3f /* Mask for internal clock scale */
-#define REG_COM7 0x12 /* Control 7 */
-#define COM7_RESET 0x80 /* Register reset */
-#define COM7_FMT_MASK 0x38
-#define COM7_FMT_SXGA 0x00
-#define COM7_FMT_VGA 0x40
-#define COM7_FMT_CIF 0x20 /* CIF format */
-#define COM7_FMT_QVGA 0x10 /* QVGA format */
-#define COM7_FMT_QCIF 0x08 /* QCIF format */
-#define COM7_RGB 0x04 /* bits 0 and 2 - RGB format */
-#define COM7_YUV 0x00 /* YUV */
-#define COM7_BAYER 0x01 /* Bayer format */
-#define COM7_PBAYER 0x05 /* "Processed bayer" */
-#define REG_COM8 0x13 /* Control 8 */
-#define COM8_FASTAEC 0x80 /* Enable fast AGC/AEC */
-#define COM8_AECSTEP 0x40 /* Unlimited AEC step size */
-#define COM8_BFILT 0x20 /* Band filter enable */
-#define COM8_AGC 0x04 /* Auto gain enable */
-#define COM8_AWB 0x02 /* White balance enable */
-#define COM8_AEC 0x01 /* Auto exposure enable */
-#define REG_COM9 0x14 /* Control 9 - gain ceiling */
-#define REG_COM10 0x15 /* Control 10 */
-#define COM10_HSYNC 0x40 /* HSYNC instead of HREF */
-#define COM10_PCLK_HB 0x20 /* Suppress PCLK on horiz blank */
-#define COM10_HREF_REV 0x08 /* Reverse HREF */
-#define COM10_VS_LEAD 0x04 /* VSYNC on clock leading edge */
-#define COM10_VS_NEG 0x02 /* VSYNC negative */
-#define COM10_HS_NEG 0x01 /* HSYNC negative */
-#define REG_HSTART 0x17 /* Horiz start high bits */
-#define REG_HSTOP 0x18 /* Horiz stop high bits */
-#define REG_VSTART 0x19 /* Vert start high bits */
-#define REG_VSTOP 0x1a /* Vert stop high bits */
-#define REG_PSHFT 0x1b /* Pixel delay after HREF */
-#define REG_MIDH 0x1c /* Manuf. ID high */
-#define REG_MIDL 0x1d /* Manuf. ID low */
-#define REG_MVFP 0x1e /* Mirror / vflip */
-#define MVFP_MIRROR 0x20 /* Mirror image */
-#define MVFP_FLIP 0x10 /* Vertical flip */
-
-#define REG_AEW 0x24 /* AGC upper limit */
-#define REG_AEB 0x25 /* AGC lower limit */
-#define REG_VPT 0x26 /* AGC/AEC fast mode op region */
-#define REG_ADVFL 0x2d /* Insert dummy lines (LSB) */
-#define REG_ADVFH 0x2e /* Insert dummy lines (MSB) */
-#define REG_HSYST 0x30 /* HSYNC rising edge delay */
-#define REG_HSYEN 0x31 /* HSYNC falling edge delay */
-#define REG_HREF 0x32 /* HREF pieces */
-#define REG_TSLB 0x3a /* lots of stuff */
-#define TSLB_YLAST 0x04 /* UYVY or VYUY - see com13 */
-#define TSLB_BYTEORD 0x08 /* swap bytes in 16bit mode? */
-#define REG_COM11 0x3b /* Control 11 */
-#define COM11_NIGHT 0x80 /* NIght mode enable */
-#define COM11_NMFR 0x60 /* Two bit NM frame rate */
-#define COM11_HZAUTO 0x10 /* Auto detect 50/60 Hz */
-#define COM11_50HZ 0x08 /* Manual 50Hz select */
-#define COM11_EXP 0x02
-#define REG_COM12 0x3c /* Control 12 */
-#define COM12_HREF 0x80 /* HREF always */
-#define REG_COM13 0x3d /* Control 13 */
-#define COM13_GAMMA 0x80 /* Gamma enable */
-#define COM13_UVSAT 0x40 /* UV saturation auto adjustment */
-#define COM13_CMATRIX 0x10 /* Enable color matrix for RGB or YUV */
-#define COM13_UVSWAP 0x01 /* V before U - w/TSLB */
-#define REG_COM14 0x3e /* Control 14 */
-#define COM14_DCWEN 0x10 /* DCW/PCLK-scale enable */
-#define REG_EDGE 0x3f /* Edge enhancement factor */
-#define REG_COM15 0x40 /* Control 15 */
-#define COM15_R10F0 0x00 /* Data range 10 to F0 */
-#define COM15_R01FE 0x80 /* 01 to FE */
-#define COM15_R00FF 0xc0 /* 00 to FF */
-#define COM15_RGB565 0x10 /* RGB565 output */
-#define COM15_RGBFIXME 0x20 /* FIXME */
-#define COM15_RGB555 0x30 /* RGB555 output */
-#define REG_COM16 0x41 /* Control 16 */
-#define COM16_AWBGAIN 0x08 /* AWB gain enable */
-#define REG_COM17 0x42 /* Control 17 */
-#define COM17_AECWIN 0xc0 /* AEC window - must match COM4 */
-#define COM17_CBAR 0x08 /* DSP Color bar */
-
-/*
- * This matrix defines how the colors are generated, must be
- * tweaked to adjust hue and saturation.
- *
- * Order: v-red, v-green, v-blue, u-red, u-green, u-blue
- *
- * They are nine-bit signed quantities, with the sign bit
- * stored in 0x58. Sign for v-red is bit 0, and up from there.
- */
-#define REG_CMATRIX_BASE 0x4f
-#define CMATRIX_LEN 6
-#define REG_CMATRIX_SIGN 0x58
-
-
-#define REG_BRIGHT 0x55 /* Brightness */
-#define REG_CONTRAS 0x56 /* Contrast control */
-
-#define REG_GFIX 0x69 /* Fix gain control */
-
-#define REG_RGB444 0x8c /* RGB 444 control */
-#define R444_ENABLE 0x02 /* Turn on RGB444, overrides 5x5 */
-#define R444_RGBX 0x01 /* Empty nibble at end */
-
-#define REG_HAECC1 0x9f /* Hist AEC/AGC control 1 */
-#define REG_HAECC2 0xa0 /* Hist AEC/AGC control 2 */
-
-#define REG_BD50MAX 0xa5 /* 50hz banding step limit */
-#define REG_HAECC3 0xa6 /* Hist AEC/AGC control 3 */
-#define REG_HAECC4 0xa7 /* Hist AEC/AGC control 4 */
-#define REG_HAECC5 0xa8 /* Hist AEC/AGC control 5 */
-#define REG_HAECC6 0xa9 /* Hist AEC/AGC control 6 */
-#define REG_HAECC7 0xaa /* Hist AEC/AGC control 7 */
-#define REG_BD60MAX 0xab /* 60hz banding step limit */
-
-
-
-
-/* Returns 0 if OK */
-static int stk_sensor_outb(struct stk_camera *dev, u8 reg, u8 val)
-{
- int i = 0;
- u8 tmpval = 0;
-
- if (stk_camera_write_reg(dev, STK_IIC_TX_INDEX, reg))
- return 1;
- if (stk_camera_write_reg(dev, STK_IIC_TX_VALUE, val))
- return 1;
- if (stk_camera_write_reg(dev, STK_IIC_OP, STK_IIC_OP_TX))
- return 1;
- do {
- if (stk_camera_read_reg(dev, STK_IIC_STAT, &tmpval))
- return 1;
- i++;
- } while (tmpval == 0 && i < MAX_RETRIES);
- if (tmpval != STK_IIC_STAT_TX_OK) {
- if (tmpval)
- pr_err("stk_sensor_outb failed, status=0x%02x\n",
- tmpval);
- return 1;
- } else
- return 0;
-}
-
-static int stk_sensor_inb(struct stk_camera *dev, u8 reg, u8 *val)
-{
- int i = 0;
- u8 tmpval = 0;
-
- if (stk_camera_write_reg(dev, STK_IIC_RX_INDEX, reg))
- return 1;
- if (stk_camera_write_reg(dev, STK_IIC_OP, STK_IIC_OP_RX))
- return 1;
- do {
- if (stk_camera_read_reg(dev, STK_IIC_STAT, &tmpval))
- return 1;
- i++;
- } while (tmpval == 0 && i < MAX_RETRIES);
- if (tmpval != STK_IIC_STAT_RX_OK) {
- if (tmpval)
- pr_err("stk_sensor_inb failed, status=0x%02x\n",
- tmpval);
- return 1;
- }
-
- if (stk_camera_read_reg(dev, STK_IIC_RX_VALUE, &tmpval))
- return 1;
-
- *val = tmpval;
- return 0;
-}
-
-static int stk_sensor_write_regvals(struct stk_camera *dev,
- struct regval *rv)
-{
- int ret;
- if (rv == NULL)
- return 0;
- while (rv->reg != 0xff || rv->val != 0xff) {
- ret = stk_sensor_outb(dev, rv->reg, rv->val);
- if (ret != 0)
- return ret;
- rv++;
- }
- return 0;
-}
-
-int stk_sensor_sleep(struct stk_camera *dev)
-{
- u8 tmp;
- return stk_sensor_inb(dev, REG_COM2, &tmp)
- || stk_sensor_outb(dev, REG_COM2, tmp|COM2_SSLEEP);
-}
-
-int stk_sensor_wakeup(struct stk_camera *dev)
-{
- u8 tmp;
- return stk_sensor_inb(dev, REG_COM2, &tmp)
- || stk_sensor_outb(dev, REG_COM2, tmp&~COM2_SSLEEP);
-}
-
-static struct regval ov_initvals[] = {
- {REG_CLKRC, CLK_PLL},
- {REG_COM11, 0x01},
- {0x6a, 0x7d},
- {REG_AECH, 0x40},
- {REG_GAIN, 0x00},
- {REG_BLUE, 0x80},
- {REG_RED, 0x80},
- /* Do not enable fast AEC for now */
- /*{REG_COM8, COM8_FASTAEC|COM8_AECSTEP|COM8_BFILT|COM8_AGC|COM8_AEC},*/
- {REG_COM8, COM8_AECSTEP|COM8_BFILT|COM8_AGC|COM8_AEC},
- {0x39, 0x50}, {0x38, 0x93},
- {0x37, 0x00}, {0x35, 0x81},
- {REG_COM5, 0x20},
- {REG_COM1, 0x00},
- {REG_COM3, 0x00},
- {REG_COM4, 0x00},
- {REG_PSHFT, 0x00},
- {0x16, 0x07},
- {0x33, 0xe2}, {0x34, 0xbf},
- {REG_COM16, 0x00},
- {0x96, 0x04},
- /* Gamma curve values */
-/* { 0x7a, 0x20 }, { 0x7b, 0x10 },
- { 0x7c, 0x1e }, { 0x7d, 0x35 },
- { 0x7e, 0x5a }, { 0x7f, 0x69 },
- { 0x80, 0x76 }, { 0x81, 0x80 },
- { 0x82, 0x88 }, { 0x83, 0x8f },
- { 0x84, 0x96 }, { 0x85, 0xa3 },
- { 0x86, 0xaf }, { 0x87, 0xc4 },
- { 0x88, 0xd7 }, { 0x89, 0xe8 },
-*/
- {REG_GFIX, 0x40},
- {0x8e, 0x00},
- {REG_COM12, 0x73},
- {0x8f, 0xdf}, {0x8b, 0x06},
- {0x8c, 0x20},
- {0x94, 0x88}, {0x95, 0x88},
-/* {REG_COM15, 0xc1}, TODO */
- {0x29, 0x3f},
- {REG_COM6, 0x42},
- {REG_BD50MAX, 0x80},
- {REG_HAECC6, 0xb8}, {REG_HAECC7, 0x92},
- {REG_BD60MAX, 0x0a},
- {0x90, 0x00}, {0x91, 0x00},
- {REG_HAECC1, 0x00}, {REG_HAECC2, 0x00},
- {REG_AEW, 0x68}, {REG_AEB, 0x5c},
- {REG_VPT, 0xc3},
- {REG_COM9, 0x2e},
- {0x2a, 0x00}, {0x2b, 0x00},
-
- {0xff, 0xff}, /* END MARKER */
-};
-
-/* Probe the I2C bus and initialise the sensor chip */
-int stk_sensor_init(struct stk_camera *dev)
-{
- u8 idl = 0;
- u8 idh = 0;
-
- if (stk_camera_write_reg(dev, STK_IIC_ENABLE, STK_IIC_ENABLE_YES)
- || stk_camera_write_reg(dev, STK_IIC_ADDR, SENSOR_ADDRESS)
- || stk_sensor_outb(dev, REG_COM7, COM7_RESET)) {
- pr_err("Sensor resetting failed\n");
- return -ENODEV;
- }
- msleep(10);
- /* Read the manufacturer ID: ov = 0x7FA2 */
- if (stk_sensor_inb(dev, REG_MIDH, &idh)
- || stk_sensor_inb(dev, REG_MIDL, &idl)) {
- pr_err("Strange error reading sensor ID\n");
- return -ENODEV;
- }
- if (idh != 0x7f || idl != 0xa2) {
- pr_err("Huh? you don't have a sensor from ovt\n");
- return -ENODEV;
- }
- if (stk_sensor_inb(dev, REG_PID, &idh)
- || stk_sensor_inb(dev, REG_VER, &idl)) {
- pr_err("Could not read sensor model\n");
- return -ENODEV;
- }
- stk_sensor_write_regvals(dev, ov_initvals);
- msleep(10);
- pr_info("OmniVision sensor detected, id %02X%02X at address %x\n",
- idh, idl, SENSOR_ADDRESS);
- return 0;
-}
-
-/* V4L2_PIX_FMT_UYVY */
-static struct regval ov_fmt_uyvy[] = {
- {REG_TSLB, TSLB_YLAST|0x08 },
- { 0x4f, 0x80 }, /* "matrix coefficient 1" */
- { 0x50, 0x80 }, /* "matrix coefficient 2" */
- { 0x51, 0 }, /* vb */
- { 0x52, 0x22 }, /* "matrix coefficient 4" */
- { 0x53, 0x5e }, /* "matrix coefficient 5" */
- { 0x54, 0x80 }, /* "matrix coefficient 6" */
- {REG_COM13, COM13_UVSAT|COM13_CMATRIX},
- {REG_COM15, COM15_R00FF },
- {0xff, 0xff}, /* END MARKER */
-};
-/* V4L2_PIX_FMT_YUYV */
-static struct regval ov_fmt_yuyv[] = {
- {REG_TSLB, 0 },
- { 0x4f, 0x80 }, /* "matrix coefficient 1" */
- { 0x50, 0x80 }, /* "matrix coefficient 2" */
- { 0x51, 0 }, /* vb */
- { 0x52, 0x22 }, /* "matrix coefficient 4" */
- { 0x53, 0x5e }, /* "matrix coefficient 5" */
- { 0x54, 0x80 }, /* "matrix coefficient 6" */
- {REG_COM13, COM13_UVSAT|COM13_CMATRIX},
- {REG_COM15, COM15_R00FF },
- {0xff, 0xff}, /* END MARKER */
-};
-
-/* V4L2_PIX_FMT_RGB565X rrrrrggg gggbbbbb */
-static struct regval ov_fmt_rgbr[] = {
- { REG_RGB444, 0 }, /* No RGB444 please */
- {REG_TSLB, 0x00},
- { REG_COM1, 0x0 },
- { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */
- { 0x4f, 0xb3 }, /* "matrix coefficient 1" */
- { 0x50, 0xb3 }, /* "matrix coefficient 2" */
- { 0x51, 0 }, /* vb */
- { 0x52, 0x3d }, /* "matrix coefficient 4" */
- { 0x53, 0xa7 }, /* "matrix coefficient 5" */
- { 0x54, 0xe4 }, /* "matrix coefficient 6" */
- { REG_COM13, COM13_GAMMA },
- { REG_COM15, COM15_RGB565|COM15_R00FF },
- { 0xff, 0xff },
-};
-
-/* V4L2_PIX_FMT_RGB565 gggbbbbb rrrrrggg */
-static struct regval ov_fmt_rgbp[] = {
- { REG_RGB444, 0 }, /* No RGB444 please */
- {REG_TSLB, TSLB_BYTEORD },
- { REG_COM1, 0x0 },
- { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */
- { 0x4f, 0xb3 }, /* "matrix coefficient 1" */
- { 0x50, 0xb3 }, /* "matrix coefficient 2" */
- { 0x51, 0 }, /* vb */
- { 0x52, 0x3d }, /* "matrix coefficient 4" */
- { 0x53, 0xa7 }, /* "matrix coefficient 5" */
- { 0x54, 0xe4 }, /* "matrix coefficient 6" */
- { REG_COM13, COM13_GAMMA },
- { REG_COM15, COM15_RGB565|COM15_R00FF },
- { 0xff, 0xff },
-};
-
-/* V4L2_PIX_FMT_SRGGB8 */
-static struct regval ov_fmt_bayer[] = {
- /* This changes color order */
- {REG_TSLB, 0x40}, /* BGGR */
- /* {REG_TSLB, 0x08}, */ /* BGGR with vertical image flipping */
- {REG_COM15, COM15_R00FF },
- {0xff, 0xff}, /* END MARKER */
-};
-/*
- * Store a set of start/stop values into the camera.
- */
-static int stk_sensor_set_hw(struct stk_camera *dev,
- int hstart, int hstop, int vstart, int vstop)
-{
- int ret;
- unsigned char v;
-/*
- * Horizontal: 11 bits, top 8 live in hstart and hstop. Bottom 3 of
- * hstart are in href[2:0], bottom 3 of hstop in href[5:3]. There is
- * a mystery "edge offset" value in the top two bits of href.
- */
- ret = stk_sensor_outb(dev, REG_HSTART, (hstart >> 3) & 0xff);
- ret += stk_sensor_outb(dev, REG_HSTOP, (hstop >> 3) & 0xff);
- ret += stk_sensor_inb(dev, REG_HREF, &v);
- v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x7);
- msleep(10);
- ret += stk_sensor_outb(dev, REG_HREF, v);
-/*
- * Vertical: similar arrangement (note: this is different from ov7670.c)
- */
- ret += stk_sensor_outb(dev, REG_VSTART, (vstart >> 3) & 0xff);
- ret += stk_sensor_outb(dev, REG_VSTOP, (vstop >> 3) & 0xff);
- ret += stk_sensor_inb(dev, REG_VREF, &v);
- v = (v & 0xc0) | ((vstop & 0x7) << 3) | (vstart & 0x7);
- msleep(10);
- ret += stk_sensor_outb(dev, REG_VREF, v);
- return ret;
-}
-
-
-int stk_sensor_configure(struct stk_camera *dev)
-{
- int com7;
- /*
- * We setup the sensor to output dummy lines in low-res modes,
- * so we don't get absurdly hight framerates.
- */
- unsigned dummylines;
- int flip;
- struct regval *rv;
-
- switch (dev->vsettings.mode) {
- case MODE_QCIF: com7 = COM7_FMT_QCIF;
- dummylines = 604;
- break;
- case MODE_QVGA: com7 = COM7_FMT_QVGA;
- dummylines = 267;
- break;
- case MODE_CIF: com7 = COM7_FMT_CIF;
- dummylines = 412;
- break;
- case MODE_VGA: com7 = COM7_FMT_VGA;
- dummylines = 11;
- break;
- case MODE_SXGA: com7 = COM7_FMT_SXGA;
- dummylines = 0;
- break;
- default:
- pr_err("Unsupported mode %d\n", dev->vsettings.mode);
- return -EFAULT;
- }
- switch (dev->vsettings.palette) {
- case V4L2_PIX_FMT_UYVY:
- com7 |= COM7_YUV;
- rv = ov_fmt_uyvy;
- break;
- case V4L2_PIX_FMT_YUYV:
- com7 |= COM7_YUV;
- rv = ov_fmt_yuyv;
- break;
- case V4L2_PIX_FMT_RGB565:
- com7 |= COM7_RGB;
- rv = ov_fmt_rgbp;
- break;
- case V4L2_PIX_FMT_RGB565X:
- com7 |= COM7_RGB;
- rv = ov_fmt_rgbr;
- break;
- case V4L2_PIX_FMT_SBGGR8:
- com7 |= COM7_PBAYER;
- rv = ov_fmt_bayer;
- break;
- default:
- pr_err("Unsupported colorspace\n");
- return -EFAULT;
- }
- /*FIXME sometimes the sensor go to a bad state
- stk_sensor_write_regvals(dev, ov_initvals); */
- stk_sensor_outb(dev, REG_COM7, com7);
- msleep(50);
- stk_sensor_write_regvals(dev, rv);
- flip = (dev->vsettings.vflip?MVFP_FLIP:0)
- | (dev->vsettings.hflip?MVFP_MIRROR:0);
- stk_sensor_outb(dev, REG_MVFP, flip);
- if (dev->vsettings.palette == V4L2_PIX_FMT_SBGGR8
- && !dev->vsettings.vflip)
- stk_sensor_outb(dev, REG_TSLB, 0x08);
- stk_sensor_outb(dev, REG_ADVFH, dummylines >> 8);
- stk_sensor_outb(dev, REG_ADVFL, dummylines & 0xff);
- msleep(50);
- switch (dev->vsettings.mode) {
- case MODE_VGA:
- if (stk_sensor_set_hw(dev, 302, 1582, 6, 486))
- pr_err("stk_sensor_set_hw failed (VGA)\n");
- break;
- case MODE_SXGA:
- case MODE_CIF:
- case MODE_QVGA:
- case MODE_QCIF:
- /*FIXME These settings seem ignored by the sensor
- if (stk_sensor_set_hw(dev, 220, 1500, 10, 1034))
- pr_err("stk_sensor_set_hw failed (SXGA)\n");
- */
- break;
- }
- msleep(10);
- return 0;
-}
-
-int stk_sensor_set_brightness(struct stk_camera *dev, int br)
-{
- if (br < 0 || br > 0xff)
- return -EINVAL;
- stk_sensor_outb(dev, REG_AEB, max(0x00, br - 6));
- stk_sensor_outb(dev, REG_AEW, min(0xff, br + 6));
- return 0;
-}
-
diff --git a/drivers/staging/media/deprecated/stkwebcam/stk-webcam.c b/drivers/staging/media/deprecated/stkwebcam/stk-webcam.c
deleted file mode 100644
index 787edb3d47c2..000000000000
--- a/drivers/staging/media/deprecated/stkwebcam/stk-webcam.c
+++ /dev/null
@@ -1,1434 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * stk-webcam.c : Driver for Syntek 1125 USB webcam controller
- *
- * Copyright (C) 2006 Nicolas VIVIEN
- * Copyright 2007-2008 Jaime Velasco Juan <jsagarribay@gmail.com>
- *
- * Some parts are inspired from cafe_ccic.c
- * Copyright 2006-2007 Jonathan Corbet
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-
-#include <linux/dmi.h>
-#include <linux/usb.h>
-#include <linux/mm.h>
-#include <linux/vmalloc.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-event.h>
-
-#include "stk-webcam.h"
-
-
-static int hflip = -1;
-module_param(hflip, int, 0444);
-MODULE_PARM_DESC(hflip, "Horizontal image flip (mirror). Defaults to 0");
-
-static int vflip = -1;
-module_param(vflip, int, 0444);
-MODULE_PARM_DESC(vflip, "Vertical image flip. Defaults to 0");
-
-static int debug;
-module_param(debug, int, 0444);
-MODULE_PARM_DESC(debug, "Debug v4l ioctls. Defaults to 0");
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jaime Velasco Juan <jsagarribay@gmail.com> and Nicolas VIVIEN");
-MODULE_DESCRIPTION("Syntek DC1125 webcam driver");
-
-/* Some cameras have audio interfaces, we aren't interested in those */
-static const struct usb_device_id stkwebcam_table[] = {
- { USB_DEVICE_AND_INTERFACE_INFO(0x174f, 0xa311, 0xff, 0xff, 0xff) },
- { USB_DEVICE_AND_INTERFACE_INFO(0x05e1, 0x0501, 0xff, 0xff, 0xff) },
- { }
-};
-MODULE_DEVICE_TABLE(usb, stkwebcam_table);
-
-/*
- * The stk webcam laptop module is mounted upside down in some laptops :(
- *
- * Some background information (thanks to Hans de Goede for providing this):
- *
- * 1) Once upon a time the stkwebcam driver was written
- *
- * 2) The webcam in question was used mostly in Asus laptop models, including
- * the laptop of the original author of the driver, and in these models, in
- * typical Asus fashion (see the long long list for uvc cams inside v4l-utils),
- * they mounted the webcam-module the wrong way up. So the hflip and vflip
- * module options were given a default value of 1 (the correct value for
- * upside down mounted models)
- *
- * 3) Years later I got a bug report from a user with a laptop with stkwebcam,
- * where the module was actually mounted the right way up, and thus showed
- * upside down under Linux. So now I was facing the choice of 2 options:
- *
- * a) Add a not-upside-down list to stkwebcam, which overrules the default.
- *
- * b) Do it like all the other drivers do, and make the default right for
- * cams mounted the proper way and add an upside-down model list, with
- * models where we need to flip-by-default.
- *
- * Despite knowing that going b) would cause a period of pain where we were
- * building the table I opted to go for option b), since a) is just too ugly,
- * and worse different from how every other driver does it leading to
- * confusion in the long run. This change was made in kernel 3.6.
- *
- * So for any user report about upside-down images since kernel 3.6 ask them
- * to provide the output of 'sudo dmidecode' so the laptop can be added in
- * the table below.
- */
-static const struct dmi_system_id stk_upside_down_dmi_table[] = {
- {
- .ident = "ASUS G1",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
- DMI_MATCH(DMI_PRODUCT_NAME, "G1")
- }
- }, {
- .ident = "ASUS F3JC",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
- DMI_MATCH(DMI_PRODUCT_NAME, "F3JC")
- }
- },
- {
- .ident = "T12Rg-H",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "HCL Infosystems Limited"),
- DMI_MATCH(DMI_PRODUCT_NAME, "T12Rg-H")
- }
- },
- {
- .ident = "ASUS A6VM",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
- DMI_MATCH(DMI_PRODUCT_NAME, "A6VM")
- }
- },
- {
- .ident = "ASUS A6JC",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
- DMI_MATCH(DMI_PRODUCT_NAME, "A6JC")
- }
- },
- {}
-};
-
-
-/*
- * Basic stuff
- */
-int stk_camera_write_reg(struct stk_camera *dev, u16 index, u8 value)
-{
- struct usb_device *udev = dev->udev;
- int ret;
-
- ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
- 0x01,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- value,
- index,
- NULL,
- 0,
- 500);
- if (ret < 0)
- return ret;
- else
- return 0;
-}
-
-int stk_camera_read_reg(struct stk_camera *dev, u16 index, u8 *value)
-{
- struct usb_device *udev = dev->udev;
- int ret;
-
- ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
- 0x00,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0x00,
- index,
- &dev->read_reg_scratch,
- sizeof(u8),
- 500);
- if (ret >= 0)
- *value = dev->read_reg_scratch;
-
- if (ret < 0)
- return ret;
- else
- return 0;
-}
-
-static int stk_start_stream(struct stk_camera *dev)
-{
- u8 value;
- int i, ret;
- u8 value_116, value_117;
-
-
- if (!is_present(dev))
- return -ENODEV;
- if (!is_memallocd(dev) || !is_initialised(dev)) {
- pr_err("FIXME: Buffers are not allocated\n");
- return -EFAULT;
- }
- ret = usb_set_interface(dev->udev, 0, 5);
-
- if (ret < 0)
- pr_err("usb_set_interface failed !\n");
- if (stk_sensor_wakeup(dev))
- pr_err("error awaking the sensor\n");
-
- stk_camera_read_reg(dev, 0x0116, &value_116);
- stk_camera_read_reg(dev, 0x0117, &value_117);
-
- stk_camera_write_reg(dev, 0x0116, 0x0000);
- stk_camera_write_reg(dev, 0x0117, 0x0000);
-
- stk_camera_read_reg(dev, 0x0100, &value);
- stk_camera_write_reg(dev, 0x0100, value | 0x80);
-
- stk_camera_write_reg(dev, 0x0116, value_116);
- stk_camera_write_reg(dev, 0x0117, value_117);
- for (i = 0; i < MAX_ISO_BUFS; i++) {
- if (dev->isobufs[i].urb) {
- ret = usb_submit_urb(dev->isobufs[i].urb, GFP_KERNEL);
- atomic_inc(&dev->urbs_used);
- if (ret)
- return ret;
- }
- }
- set_streaming(dev);
- return 0;
-}
-
-static int stk_stop_stream(struct stk_camera *dev)
-{
- u8 value;
- int i;
- if (is_present(dev)) {
- stk_camera_read_reg(dev, 0x0100, &value);
- stk_camera_write_reg(dev, 0x0100, value & ~0x80);
- if (dev->isobufs != NULL) {
- for (i = 0; i < MAX_ISO_BUFS; i++) {
- if (dev->isobufs[i].urb)
- usb_kill_urb(dev->isobufs[i].urb);
- }
- }
- unset_streaming(dev);
-
- if (usb_set_interface(dev->udev, 0, 0))
- pr_err("usb_set_interface failed !\n");
- if (stk_sensor_sleep(dev))
- pr_err("error suspending the sensor\n");
- }
- return 0;
-}
-
-/*
- * This seems to be the shortest init sequence we
- * must do in order to find the sensor
- * Bit 5 of reg. 0x0000 here is important, when reset to 0 the sensor
- * is also reset. Maybe powers down it?
- * Rest of values don't make a difference
- */
-
-static struct regval stk1125_initvals[] = {
- /*TODO: What means this sequence? */
- {0x0000, 0x24},
- {0x0100, 0x21},
- {0x0002, 0x68},
- {0x0003, 0x80},
- {0x0005, 0x00},
- {0x0007, 0x03},
- {0x000d, 0x00},
- {0x000f, 0x02},
- {0x0300, 0x12},
- {0x0350, 0x41},
- {0x0351, 0x00},
- {0x0352, 0x00},
- {0x0353, 0x00},
- {0x0018, 0x10},
- {0x0019, 0x00},
- {0x001b, 0x0e},
- {0x001c, 0x46},
- {0x0300, 0x80},
- {0x001a, 0x04},
- {0x0110, 0x00},
- {0x0111, 0x00},
- {0x0112, 0x00},
- {0x0113, 0x00},
-
- {0xffff, 0xff},
-};
-
-
-static int stk_initialise(struct stk_camera *dev)
-{
- struct regval *rv;
- int ret;
- if (!is_present(dev))
- return -ENODEV;
- if (is_initialised(dev))
- return 0;
- rv = stk1125_initvals;
- while (rv->reg != 0xffff) {
- ret = stk_camera_write_reg(dev, rv->reg, rv->val);
- if (ret)
- return ret;
- rv++;
- }
- if (stk_sensor_init(dev) == 0) {
- set_initialised(dev);
- return 0;
- } else
- return -1;
-}
-
-/* *********************************************** */
-/*
- * This function is called as an URB transfert is complete (Isochronous pipe).
- * So, the traitement is done in interrupt time, so it has be fast, not crash,
- * and not stall. Neat.
- */
-static void stk_isoc_handler(struct urb *urb)
-{
- int i;
- int ret;
- int framelen;
- unsigned long flags;
-
- unsigned char *fill = NULL;
- unsigned char *iso_buf = NULL;
-
- struct stk_camera *dev;
- struct stk_sio_buffer *fb;
-
- dev = (struct stk_camera *) urb->context;
-
- if (dev == NULL) {
- pr_err("isoc_handler called with NULL device !\n");
- return;
- }
-
- if (urb->status == -ENOENT || urb->status == -ECONNRESET
- || urb->status == -ESHUTDOWN) {
- atomic_dec(&dev->urbs_used);
- return;
- }
-
- spin_lock_irqsave(&dev->spinlock, flags);
-
- if (urb->status != -EINPROGRESS && urb->status != 0) {
- pr_err("isoc_handler: urb->status == %d\n", urb->status);
- goto resubmit;
- }
-
- if (list_empty(&dev->sio_avail)) {
- /*FIXME Stop streaming after a while */
- pr_err_ratelimited("isoc_handler without available buffer!\n");
- goto resubmit;
- }
- fb = list_first_entry(&dev->sio_avail,
- struct stk_sio_buffer, list);
- fill = fb->buffer + fb->v4lbuf.bytesused;
-
- for (i = 0; i < urb->number_of_packets; i++) {
- if (urb->iso_frame_desc[i].status != 0) {
- if (urb->iso_frame_desc[i].status != -EXDEV)
- pr_err("Frame %d has error %d\n",
- i, urb->iso_frame_desc[i].status);
- continue;
- }
- framelen = urb->iso_frame_desc[i].actual_length;
- iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
-
- if (framelen <= 4)
- continue; /* no data */
-
- /*
- * we found something informational from there
- * the isoc frames have to type of headers
- * type1: 00 xx 00 00 or 20 xx 00 00
- * type2: 80 xx 00 00 00 00 00 00 or a0 xx 00 00 00 00 00 00
- * xx is a sequencer which has never been seen over 0x3f
- * imho data written down looks like bayer, i see similarities
- * after every 640 bytes
- */
- if (*iso_buf & 0x80) {
- framelen -= 8;
- iso_buf += 8;
- /* This marks a new frame */
- if (fb->v4lbuf.bytesused != 0
- && fb->v4lbuf.bytesused != dev->frame_size) {
- pr_err_ratelimited("frame %d, bytesused=%d, skipping\n",
- i, fb->v4lbuf.bytesused);
- fb->v4lbuf.bytesused = 0;
- fill = fb->buffer;
- } else if (fb->v4lbuf.bytesused == dev->frame_size) {
- if (list_is_singular(&dev->sio_avail)) {
- /* Always reuse the last buffer */
- fb->v4lbuf.bytesused = 0;
- fill = fb->buffer;
- } else {
- list_move_tail(dev->sio_avail.next,
- &dev->sio_full);
- wake_up(&dev->wait_frame);
- fb = list_first_entry(&dev->sio_avail,
- struct stk_sio_buffer, list);
- fb->v4lbuf.bytesused = 0;
- fill = fb->buffer;
- }
- }
- } else {
- framelen -= 4;
- iso_buf += 4;
- }
-
- /* Our buffer is full !!! */
- if (framelen + fb->v4lbuf.bytesused > dev->frame_size) {
- pr_err_ratelimited("Frame buffer overflow, lost sync\n");
- /*FIXME Do something here? */
- continue;
- }
- spin_unlock_irqrestore(&dev->spinlock, flags);
- memcpy(fill, iso_buf, framelen);
- spin_lock_irqsave(&dev->spinlock, flags);
- fill += framelen;
-
- /* New size of our buffer */
- fb->v4lbuf.bytesused += framelen;
- }
-
-resubmit:
- spin_unlock_irqrestore(&dev->spinlock, flags);
- urb->dev = dev->udev;
- ret = usb_submit_urb(urb, GFP_ATOMIC);
- if (ret != 0) {
- pr_err("Error (%d) re-submitting urb in stk_isoc_handler\n",
- ret);
- }
-}
-
-/* -------------------------------------------- */
-
-static int stk_prepare_iso(struct stk_camera *dev)
-{
- void *kbuf;
- int i, j;
- struct urb *urb;
- struct usb_device *udev;
-
- if (dev == NULL)
- return -ENXIO;
- udev = dev->udev;
-
- if (dev->isobufs)
- pr_err("isobufs already allocated. Bad\n");
- else
- dev->isobufs = kcalloc(MAX_ISO_BUFS, sizeof(*dev->isobufs),
- GFP_KERNEL);
- if (dev->isobufs == NULL) {
- pr_err("Unable to allocate iso buffers\n");
- return -ENOMEM;
- }
- for (i = 0; i < MAX_ISO_BUFS; i++) {
- if (dev->isobufs[i].data == NULL) {
- kbuf = kzalloc(ISO_BUFFER_SIZE, GFP_KERNEL);
- if (kbuf == NULL) {
- pr_err("Failed to allocate iso buffer %d\n", i);
- goto isobufs_out;
- }
- dev->isobufs[i].data = kbuf;
- } else
- pr_err("isobuf data already allocated\n");
- if (dev->isobufs[i].urb == NULL) {
- urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL);
- if (urb == NULL)
- goto isobufs_out;
- dev->isobufs[i].urb = urb;
- } else {
- pr_err("Killing URB\n");
- usb_kill_urb(dev->isobufs[i].urb);
- urb = dev->isobufs[i].urb;
- }
- urb->interval = 1;
- urb->dev = udev;
- urb->pipe = usb_rcvisocpipe(udev, dev->isoc_ep);
- urb->transfer_flags = URB_ISO_ASAP;
- urb->transfer_buffer = dev->isobufs[i].data;
- urb->transfer_buffer_length = ISO_BUFFER_SIZE;
- urb->complete = stk_isoc_handler;
- urb->context = dev;
- urb->start_frame = 0;
- urb->number_of_packets = ISO_FRAMES_PER_DESC;
-
- for (j = 0; j < ISO_FRAMES_PER_DESC; j++) {
- urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE;
- urb->iso_frame_desc[j].length = ISO_MAX_FRAME_SIZE;
- }
- }
- set_memallocd(dev);
- return 0;
-
-isobufs_out:
- for (i = 0; i < MAX_ISO_BUFS && dev->isobufs[i].data; i++)
- kfree(dev->isobufs[i].data);
- for (i = 0; i < MAX_ISO_BUFS && dev->isobufs[i].urb; i++)
- usb_free_urb(dev->isobufs[i].urb);
- kfree(dev->isobufs);
- dev->isobufs = NULL;
- return -ENOMEM;
-}
-
-static void stk_clean_iso(struct stk_camera *dev)
-{
- int i;
-
- if (dev == NULL || dev->isobufs == NULL)
- return;
-
- for (i = 0; i < MAX_ISO_BUFS; i++) {
- struct urb *urb;
-
- urb = dev->isobufs[i].urb;
- if (urb) {
- if (atomic_read(&dev->urbs_used) && is_present(dev))
- usb_kill_urb(urb);
- usb_free_urb(urb);
- }
- kfree(dev->isobufs[i].data);
- }
- kfree(dev->isobufs);
- dev->isobufs = NULL;
- unset_memallocd(dev);
-}
-
-static int stk_setup_siobuf(struct stk_camera *dev, int index)
-{
- struct stk_sio_buffer *buf = dev->sio_bufs + index;
- INIT_LIST_HEAD(&buf->list);
- buf->v4lbuf.length = PAGE_ALIGN(dev->frame_size);
- buf->buffer = vmalloc_user(buf->v4lbuf.length);
- if (buf->buffer == NULL)
- return -ENOMEM;
- buf->mapcount = 0;
- buf->dev = dev;
- buf->v4lbuf.index = index;
- buf->v4lbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- buf->v4lbuf.flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- buf->v4lbuf.field = V4L2_FIELD_NONE;
- buf->v4lbuf.memory = V4L2_MEMORY_MMAP;
- buf->v4lbuf.m.offset = 2*index*buf->v4lbuf.length;
- return 0;
-}
-
-static int stk_free_sio_buffers(struct stk_camera *dev)
-{
- int i;
- int nbufs;
- unsigned long flags;
- if (dev->n_sbufs == 0 || dev->sio_bufs == NULL)
- return 0;
- /*
- * If any buffers are mapped, we cannot free them at all.
- */
- for (i = 0; i < dev->n_sbufs; i++) {
- if (dev->sio_bufs[i].mapcount > 0)
- return -EBUSY;
- }
- /*
- * OK, let's do it.
- */
- spin_lock_irqsave(&dev->spinlock, flags);
- INIT_LIST_HEAD(&dev->sio_avail);
- INIT_LIST_HEAD(&dev->sio_full);
- nbufs = dev->n_sbufs;
- dev->n_sbufs = 0;
- spin_unlock_irqrestore(&dev->spinlock, flags);
- for (i = 0; i < nbufs; i++)
- vfree(dev->sio_bufs[i].buffer);
- kfree(dev->sio_bufs);
- dev->sio_bufs = NULL;
- return 0;
-}
-
-static int stk_prepare_sio_buffers(struct stk_camera *dev, unsigned n_sbufs)
-{
- int i;
- if (dev->sio_bufs != NULL)
- pr_err("sio_bufs already allocated\n");
- else {
- dev->sio_bufs = kcalloc(n_sbufs,
- sizeof(struct stk_sio_buffer),
- GFP_KERNEL);
- if (dev->sio_bufs == NULL)
- return -ENOMEM;
- for (i = 0; i < n_sbufs; i++) {
- if (stk_setup_siobuf(dev, i))
- return (dev->n_sbufs > 1 ? 0 : -ENOMEM);
- dev->n_sbufs = i+1;
- }
- }
- return 0;
-}
-
-static int stk_allocate_buffers(struct stk_camera *dev, unsigned n_sbufs)
-{
- int err;
- err = stk_prepare_iso(dev);
- if (err) {
- stk_clean_iso(dev);
- return err;
- }
- err = stk_prepare_sio_buffers(dev, n_sbufs);
- if (err) {
- stk_free_sio_buffers(dev);
- return err;
- }
- return 0;
-}
-
-static void stk_free_buffers(struct stk_camera *dev)
-{
- stk_clean_iso(dev);
- stk_free_sio_buffers(dev);
-}
-/* -------------------------------------------- */
-
-/* v4l file operations */
-
-static int v4l_stk_open(struct file *fp)
-{
- struct stk_camera *dev = video_drvdata(fp);
- int err;
-
- if (dev == NULL || !is_present(dev))
- return -ENXIO;
-
- if (mutex_lock_interruptible(&dev->lock))
- return -ERESTARTSYS;
- if (!dev->first_init)
- stk_camera_write_reg(dev, 0x0, 0x24);
- else
- dev->first_init = 0;
-
- err = v4l2_fh_open(fp);
- if (!err)
- usb_autopm_get_interface(dev->interface);
- mutex_unlock(&dev->lock);
- return err;
-}
-
-static int v4l_stk_release(struct file *fp)
-{
- struct stk_camera *dev = video_drvdata(fp);
-
- mutex_lock(&dev->lock);
- if (dev->owner == fp) {
- stk_stop_stream(dev);
- stk_free_buffers(dev);
- stk_camera_write_reg(dev, 0x0, 0x49); /* turn off the LED */
- unset_initialised(dev);
- dev->owner = NULL;
- }
-
- usb_autopm_put_interface(dev->interface);
- mutex_unlock(&dev->lock);
- return v4l2_fh_release(fp);
-}
-
-static ssize_t stk_read(struct file *fp, char __user *buf,
- size_t count, loff_t *f_pos)
-{
- int i;
- int ret;
- unsigned long flags;
- struct stk_sio_buffer *sbuf;
- struct stk_camera *dev = video_drvdata(fp);
-
- if (!is_present(dev))
- return -EIO;
- if (dev->owner && (!dev->reading || dev->owner != fp))
- return -EBUSY;
- dev->owner = fp;
- if (!is_streaming(dev)) {
- if (stk_initialise(dev)
- || stk_allocate_buffers(dev, 3)
- || stk_start_stream(dev))
- return -ENOMEM;
- dev->reading = 1;
- spin_lock_irqsave(&dev->spinlock, flags);
- for (i = 0; i < dev->n_sbufs; i++) {
- list_add_tail(&dev->sio_bufs[i].list, &dev->sio_avail);
- dev->sio_bufs[i].v4lbuf.flags = V4L2_BUF_FLAG_QUEUED;
- }
- spin_unlock_irqrestore(&dev->spinlock, flags);
- }
- if (*f_pos == 0) {
- if (fp->f_flags & O_NONBLOCK && list_empty(&dev->sio_full))
- return -EWOULDBLOCK;
- ret = wait_event_interruptible(dev->wait_frame,
- !list_empty(&dev->sio_full) || !is_present(dev));
- if (ret)
- return ret;
- if (!is_present(dev))
- return -EIO;
- }
- if (count + *f_pos > dev->frame_size)
- count = dev->frame_size - *f_pos;
- spin_lock_irqsave(&dev->spinlock, flags);
- if (list_empty(&dev->sio_full)) {
- spin_unlock_irqrestore(&dev->spinlock, flags);
- pr_err("BUG: No siobufs ready\n");
- return 0;
- }
- sbuf = list_first_entry(&dev->sio_full, struct stk_sio_buffer, list);
- spin_unlock_irqrestore(&dev->spinlock, flags);
-
- if (copy_to_user(buf, sbuf->buffer + *f_pos, count))
- return -EFAULT;
-
- *f_pos += count;
-
- if (*f_pos >= dev->frame_size) {
- *f_pos = 0;
- spin_lock_irqsave(&dev->spinlock, flags);
- list_move_tail(&sbuf->list, &dev->sio_avail);
- spin_unlock_irqrestore(&dev->spinlock, flags);
- }
- return count;
-}
-
-static ssize_t v4l_stk_read(struct file *fp, char __user *buf,
- size_t count, loff_t *f_pos)
-{
- struct stk_camera *dev = video_drvdata(fp);
- int ret;
-
- if (mutex_lock_interruptible(&dev->lock))
- return -ERESTARTSYS;
- ret = stk_read(fp, buf, count, f_pos);
- mutex_unlock(&dev->lock);
- return ret;
-}
-
-static __poll_t v4l_stk_poll(struct file *fp, poll_table *wait)
-{
- struct stk_camera *dev = video_drvdata(fp);
- __poll_t res = v4l2_ctrl_poll(fp, wait);
-
- poll_wait(fp, &dev->wait_frame, wait);
-
- if (!is_present(dev))
- return EPOLLERR;
-
- if (!list_empty(&dev->sio_full))
- return res | EPOLLIN | EPOLLRDNORM;
-
- return res;
-}
-
-
-static void stk_v4l_vm_open(struct vm_area_struct *vma)
-{
- struct stk_sio_buffer *sbuf = vma->vm_private_data;
- sbuf->mapcount++;
-}
-static void stk_v4l_vm_close(struct vm_area_struct *vma)
-{
- struct stk_sio_buffer *sbuf = vma->vm_private_data;
- sbuf->mapcount--;
- if (sbuf->mapcount == 0)
- sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_MAPPED;
-}
-static const struct vm_operations_struct stk_v4l_vm_ops = {
- .open = stk_v4l_vm_open,
- .close = stk_v4l_vm_close
-};
-
-static int v4l_stk_mmap(struct file *fp, struct vm_area_struct *vma)
-{
- unsigned int i;
- int ret;
- unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
- struct stk_camera *dev = video_drvdata(fp);
- struct stk_sio_buffer *sbuf = NULL;
-
- if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED))
- return -EINVAL;
-
- for (i = 0; i < dev->n_sbufs; i++) {
- if (dev->sio_bufs[i].v4lbuf.m.offset == offset) {
- sbuf = dev->sio_bufs + i;
- break;
- }
- }
- if (sbuf == NULL)
- return -EINVAL;
- ret = remap_vmalloc_range(vma, sbuf->buffer, 0);
- if (ret)
- return ret;
- vma->vm_flags |= VM_DONTEXPAND;
- vma->vm_private_data = sbuf;
- vma->vm_ops = &stk_v4l_vm_ops;
- sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_MAPPED;
- stk_v4l_vm_open(vma);
- return 0;
-}
-
-/* v4l ioctl handlers */
-
-static int stk_vidioc_querycap(struct file *filp,
- void *priv, struct v4l2_capability *cap)
-{
- struct stk_camera *dev = video_drvdata(filp);
-
- strscpy(cap->driver, "stk", sizeof(cap->driver));
- strscpy(cap->card, "stk", sizeof(cap->card));
- usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
- return 0;
-}
-
-static int stk_vidioc_enum_input(struct file *filp,
- void *priv, struct v4l2_input *input)
-{
- if (input->index != 0)
- return -EINVAL;
-
- strscpy(input->name, "Syntek USB Camera", sizeof(input->name));
- input->type = V4L2_INPUT_TYPE_CAMERA;
- return 0;
-}
-
-
-static int stk_vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
- *i = 0;
- return 0;
-}
-
-static int stk_vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
- return i ? -EINVAL : 0;
-}
-
-static int stk_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct stk_camera *dev =
- container_of(ctrl->handler, struct stk_camera, hdl);
-
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- return stk_sensor_set_brightness(dev, ctrl->val);
- case V4L2_CID_HFLIP:
- if (dmi_check_system(stk_upside_down_dmi_table))
- dev->vsettings.hflip = !ctrl->val;
- else
- dev->vsettings.hflip = ctrl->val;
- return 0;
- case V4L2_CID_VFLIP:
- if (dmi_check_system(stk_upside_down_dmi_table))
- dev->vsettings.vflip = !ctrl->val;
- else
- dev->vsettings.vflip = ctrl->val;
- return 0;
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-
-static int stk_vidioc_enum_fmt_vid_cap(struct file *filp,
- void *priv, struct v4l2_fmtdesc *fmtd)
-{
- switch (fmtd->index) {
- case 0:
- fmtd->pixelformat = V4L2_PIX_FMT_RGB565;
- break;
- case 1:
- fmtd->pixelformat = V4L2_PIX_FMT_RGB565X;
- break;
- case 2:
- fmtd->pixelformat = V4L2_PIX_FMT_UYVY;
- break;
- case 3:
- fmtd->pixelformat = V4L2_PIX_FMT_SBGGR8;
- break;
- case 4:
- fmtd->pixelformat = V4L2_PIX_FMT_YUYV;
- break;
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-static struct stk_size {
- unsigned w;
- unsigned h;
- enum stk_mode m;
-} stk_sizes[] = {
- { .w = 1280, .h = 1024, .m = MODE_SXGA, },
- { .w = 640, .h = 480, .m = MODE_VGA, },
- { .w = 352, .h = 288, .m = MODE_CIF, },
- { .w = 320, .h = 240, .m = MODE_QVGA, },
- { .w = 176, .h = 144, .m = MODE_QCIF, },
-};
-
-static int stk_vidioc_g_fmt_vid_cap(struct file *filp,
- void *priv, struct v4l2_format *f)
-{
- struct v4l2_pix_format *pix_format = &f->fmt.pix;
- struct stk_camera *dev = video_drvdata(filp);
- int i;
-
- for (i = 0; i < ARRAY_SIZE(stk_sizes) &&
- stk_sizes[i].m != dev->vsettings.mode; i++)
- ;
- if (i == ARRAY_SIZE(stk_sizes)) {
- pr_err("ERROR: mode invalid\n");
- return -EINVAL;
- }
- pix_format->width = stk_sizes[i].w;
- pix_format->height = stk_sizes[i].h;
- pix_format->field = V4L2_FIELD_NONE;
- pix_format->colorspace = V4L2_COLORSPACE_SRGB;
- pix_format->pixelformat = dev->vsettings.palette;
- if (dev->vsettings.palette == V4L2_PIX_FMT_SBGGR8)
- pix_format->bytesperline = pix_format->width;
- else
- pix_format->bytesperline = 2 * pix_format->width;
- pix_format->sizeimage = pix_format->bytesperline
- * pix_format->height;
- return 0;
-}
-
-static int stk_try_fmt_vid_cap(struct file *filp,
- struct v4l2_format *fmtd, int *idx)
-{
- int i;
- switch (fmtd->fmt.pix.pixelformat) {
- case V4L2_PIX_FMT_RGB565:
- case V4L2_PIX_FMT_RGB565X:
- case V4L2_PIX_FMT_UYVY:
- case V4L2_PIX_FMT_YUYV:
- case V4L2_PIX_FMT_SBGGR8:
- break;
- default:
- return -EINVAL;
- }
- for (i = 1; i < ARRAY_SIZE(stk_sizes); i++) {
- if (fmtd->fmt.pix.width > stk_sizes[i].w)
- break;
- }
- if (i == ARRAY_SIZE(stk_sizes)
- || (abs(fmtd->fmt.pix.width - stk_sizes[i-1].w)
- < abs(fmtd->fmt.pix.width - stk_sizes[i].w))) {
- fmtd->fmt.pix.height = stk_sizes[i-1].h;
- fmtd->fmt.pix.width = stk_sizes[i-1].w;
- if (idx)
- *idx = i - 1;
- } else {
- fmtd->fmt.pix.height = stk_sizes[i].h;
- fmtd->fmt.pix.width = stk_sizes[i].w;
- if (idx)
- *idx = i;
- }
-
- fmtd->fmt.pix.field = V4L2_FIELD_NONE;
- fmtd->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
- if (fmtd->fmt.pix.pixelformat == V4L2_PIX_FMT_SBGGR8)
- fmtd->fmt.pix.bytesperline = fmtd->fmt.pix.width;
- else
- fmtd->fmt.pix.bytesperline = 2 * fmtd->fmt.pix.width;
- fmtd->fmt.pix.sizeimage = fmtd->fmt.pix.bytesperline
- * fmtd->fmt.pix.height;
- return 0;
-}
-
-static int stk_vidioc_try_fmt_vid_cap(struct file *filp,
- void *priv, struct v4l2_format *fmtd)
-{
- return stk_try_fmt_vid_cap(filp, fmtd, NULL);
-}
-
-static int stk_setup_format(struct stk_camera *dev)
-{
- int i = 0;
- int depth;
- if (dev->vsettings.palette == V4L2_PIX_FMT_SBGGR8)
- depth = 1;
- else
- depth = 2;
- while (i < ARRAY_SIZE(stk_sizes) &&
- stk_sizes[i].m != dev->vsettings.mode)
- i++;
- if (i == ARRAY_SIZE(stk_sizes)) {
- pr_err("Something is broken in %s\n", __func__);
- return -EFAULT;
- }
- /* This registers controls some timings, not sure of what. */
- stk_camera_write_reg(dev, 0x001b, 0x0e);
- if (dev->vsettings.mode == MODE_SXGA)
- stk_camera_write_reg(dev, 0x001c, 0x0e);
- else
- stk_camera_write_reg(dev, 0x001c, 0x46);
- /*
- * Registers 0x0115 0x0114 are the size of each line (bytes),
- * regs 0x0117 0x0116 are the height of the image.
- */
- stk_camera_write_reg(dev, 0x0115,
- ((stk_sizes[i].w * depth) >> 8) & 0xff);
- stk_camera_write_reg(dev, 0x0114,
- (stk_sizes[i].w * depth) & 0xff);
- stk_camera_write_reg(dev, 0x0117,
- (stk_sizes[i].h >> 8) & 0xff);
- stk_camera_write_reg(dev, 0x0116,
- stk_sizes[i].h & 0xff);
- return stk_sensor_configure(dev);
-}
-
-static int stk_vidioc_s_fmt_vid_cap(struct file *filp,
- void *priv, struct v4l2_format *fmtd)
-{
- int ret;
- int idx;
- struct stk_camera *dev = video_drvdata(filp);
-
- if (dev == NULL)
- return -ENODEV;
- if (!is_present(dev))
- return -ENODEV;
- if (is_streaming(dev))
- return -EBUSY;
- if (dev->owner)
- return -EBUSY;
- ret = stk_try_fmt_vid_cap(filp, fmtd, &idx);
- if (ret)
- return ret;
-
- dev->vsettings.palette = fmtd->fmt.pix.pixelformat;
- stk_free_buffers(dev);
- dev->frame_size = fmtd->fmt.pix.sizeimage;
- dev->vsettings.mode = stk_sizes[idx].m;
-
- stk_initialise(dev);
- return stk_setup_format(dev);
-}
-
-static int stk_vidioc_reqbufs(struct file *filp,
- void *priv, struct v4l2_requestbuffers *rb)
-{
- struct stk_camera *dev = video_drvdata(filp);
-
- if (dev == NULL)
- return -ENODEV;
- if (rb->memory != V4L2_MEMORY_MMAP)
- return -EINVAL;
- if (is_streaming(dev)
- || (dev->owner && dev->owner != filp))
- return -EBUSY;
- stk_free_buffers(dev);
- if (rb->count == 0) {
- stk_camera_write_reg(dev, 0x0, 0x49); /* turn off the LED */
- unset_initialised(dev);
- dev->owner = NULL;
- return 0;
- }
- dev->owner = filp;
-
- /*FIXME If they ask for zero, we must stop streaming and free */
- if (rb->count < 3)
- rb->count = 3;
- /* Arbitrary limit */
- else if (rb->count > 5)
- rb->count = 5;
-
- stk_allocate_buffers(dev, rb->count);
- rb->count = dev->n_sbufs;
- return 0;
-}
-
-static int stk_vidioc_querybuf(struct file *filp,
- void *priv, struct v4l2_buffer *buf)
-{
- struct stk_camera *dev = video_drvdata(filp);
- struct stk_sio_buffer *sbuf;
-
- if (buf->index >= dev->n_sbufs)
- return -EINVAL;
- sbuf = dev->sio_bufs + buf->index;
- *buf = sbuf->v4lbuf;
- return 0;
-}
-
-static int stk_vidioc_qbuf(struct file *filp,
- void *priv, struct v4l2_buffer *buf)
-{
- struct stk_camera *dev = video_drvdata(filp);
- struct stk_sio_buffer *sbuf;
- unsigned long flags;
-
- if (buf->memory != V4L2_MEMORY_MMAP)
- return -EINVAL;
-
- if (buf->index >= dev->n_sbufs)
- return -EINVAL;
- sbuf = dev->sio_bufs + buf->index;
- if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_QUEUED)
- return 0;
- sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_QUEUED;
- sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_DONE;
- spin_lock_irqsave(&dev->spinlock, flags);
- list_add_tail(&sbuf->list, &dev->sio_avail);
- *buf = sbuf->v4lbuf;
- spin_unlock_irqrestore(&dev->spinlock, flags);
- return 0;
-}
-
-static int stk_vidioc_dqbuf(struct file *filp,
- void *priv, struct v4l2_buffer *buf)
-{
- struct stk_camera *dev = video_drvdata(filp);
- struct stk_sio_buffer *sbuf;
- unsigned long flags;
- int ret;
-
- if (!is_streaming(dev))
- return -EINVAL;
-
- if (filp->f_flags & O_NONBLOCK && list_empty(&dev->sio_full))
- return -EWOULDBLOCK;
- ret = wait_event_interruptible(dev->wait_frame,
- !list_empty(&dev->sio_full) || !is_present(dev));
- if (ret)
- return ret;
- if (!is_present(dev))
- return -EIO;
-
- spin_lock_irqsave(&dev->spinlock, flags);
- sbuf = list_first_entry(&dev->sio_full, struct stk_sio_buffer, list);
- list_del_init(&sbuf->list);
- spin_unlock_irqrestore(&dev->spinlock, flags);
- sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED;
- sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_DONE;
- sbuf->v4lbuf.sequence = ++dev->sequence;
- v4l2_buffer_set_timestamp(&sbuf->v4lbuf, ktime_get_ns());
-
- *buf = sbuf->v4lbuf;
- return 0;
-}
-
-static int stk_vidioc_streamon(struct file *filp,
- void *priv, enum v4l2_buf_type type)
-{
- struct stk_camera *dev = video_drvdata(filp);
- if (is_streaming(dev))
- return 0;
- if (dev->sio_bufs == NULL)
- return -EINVAL;
- dev->sequence = 0;
- return stk_start_stream(dev);
-}
-
-static int stk_vidioc_streamoff(struct file *filp,
- void *priv, enum v4l2_buf_type type)
-{
- struct stk_camera *dev = video_drvdata(filp);
- unsigned long flags;
- int i;
- stk_stop_stream(dev);
- spin_lock_irqsave(&dev->spinlock, flags);
- INIT_LIST_HEAD(&dev->sio_avail);
- INIT_LIST_HEAD(&dev->sio_full);
- for (i = 0; i < dev->n_sbufs; i++) {
- INIT_LIST_HEAD(&dev->sio_bufs[i].list);
- dev->sio_bufs[i].v4lbuf.flags = 0;
- }
- spin_unlock_irqrestore(&dev->spinlock, flags);
- return 0;
-}
-
-
-static int stk_vidioc_g_parm(struct file *filp,
- void *priv, struct v4l2_streamparm *sp)
-{
- /*FIXME This is not correct */
- sp->parm.capture.timeperframe.numerator = 1;
- sp->parm.capture.timeperframe.denominator = 30;
- sp->parm.capture.readbuffers = 2;
- return 0;
-}
-
-static int stk_vidioc_enum_framesizes(struct file *filp,
- void *priv, struct v4l2_frmsizeenum *frms)
-{
- if (frms->index >= ARRAY_SIZE(stk_sizes))
- return -EINVAL;
- switch (frms->pixel_format) {
- case V4L2_PIX_FMT_RGB565:
- case V4L2_PIX_FMT_RGB565X:
- case V4L2_PIX_FMT_UYVY:
- case V4L2_PIX_FMT_YUYV:
- case V4L2_PIX_FMT_SBGGR8:
- frms->type = V4L2_FRMSIZE_TYPE_DISCRETE;
- frms->discrete.width = stk_sizes[frms->index].w;
- frms->discrete.height = stk_sizes[frms->index].h;
- return 0;
- default: return -EINVAL;
- }
-}
-
-static const struct v4l2_ctrl_ops stk_ctrl_ops = {
- .s_ctrl = stk_s_ctrl,
-};
-
-static const struct v4l2_file_operations v4l_stk_fops = {
- .owner = THIS_MODULE,
- .open = v4l_stk_open,
- .release = v4l_stk_release,
- .read = v4l_stk_read,
- .poll = v4l_stk_poll,
- .mmap = v4l_stk_mmap,
- .unlocked_ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops v4l_stk_ioctl_ops = {
- .vidioc_querycap = stk_vidioc_querycap,
- .vidioc_enum_fmt_vid_cap = stk_vidioc_enum_fmt_vid_cap,
- .vidioc_try_fmt_vid_cap = stk_vidioc_try_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = stk_vidioc_s_fmt_vid_cap,
- .vidioc_g_fmt_vid_cap = stk_vidioc_g_fmt_vid_cap,
- .vidioc_enum_input = stk_vidioc_enum_input,
- .vidioc_s_input = stk_vidioc_s_input,
- .vidioc_g_input = stk_vidioc_g_input,
- .vidioc_reqbufs = stk_vidioc_reqbufs,
- .vidioc_querybuf = stk_vidioc_querybuf,
- .vidioc_qbuf = stk_vidioc_qbuf,
- .vidioc_dqbuf = stk_vidioc_dqbuf,
- .vidioc_streamon = stk_vidioc_streamon,
- .vidioc_streamoff = stk_vidioc_streamoff,
- .vidioc_g_parm = stk_vidioc_g_parm,
- .vidioc_enum_framesizes = stk_vidioc_enum_framesizes,
- .vidioc_log_status = v4l2_ctrl_log_status,
- .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
- .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
-};
-
-static void stk_v4l_dev_release(struct video_device *vd)
-{
- struct stk_camera *dev = vdev_to_camera(vd);
-
- if (dev->sio_bufs != NULL || dev->isobufs != NULL)
- pr_err("We are leaking memory\n");
- usb_put_intf(dev->interface);
- usb_put_dev(dev->udev);
-
- v4l2_ctrl_handler_free(&dev->hdl);
- v4l2_device_unregister(&dev->v4l2_dev);
- kfree(dev);
-}
-
-static const struct video_device stk_v4l_data = {
- .name = "stkwebcam",
- .fops = &v4l_stk_fops,
- .ioctl_ops = &v4l_stk_ioctl_ops,
- .release = stk_v4l_dev_release,
-};
-
-
-static int stk_register_video_device(struct stk_camera *dev)
-{
- int err;
-
- dev->vdev = stk_v4l_data;
- dev->vdev.lock = &dev->lock;
- dev->vdev.v4l2_dev = &dev->v4l2_dev;
- dev->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING;
- video_set_drvdata(&dev->vdev, dev);
- err = video_register_device(&dev->vdev, VFL_TYPE_VIDEO, -1);
- if (err)
- pr_err("v4l registration failed\n");
- else
- pr_info("Syntek USB2.0 Camera is now controlling device %s\n",
- video_device_node_name(&dev->vdev));
- return err;
-}
-
-
-/* USB Stuff */
-
-static int stk_camera_probe(struct usb_interface *interface,
- const struct usb_device_id *id)
-{
- struct v4l2_ctrl_handler *hdl;
- int err = 0;
- int i;
-
- struct stk_camera *dev = NULL;
- struct usb_device *udev = interface_to_usbdev(interface);
- struct usb_host_interface *iface_desc;
- struct usb_endpoint_descriptor *endpoint;
-
- dev = kzalloc(sizeof(struct stk_camera), GFP_KERNEL);
- if (dev == NULL) {
- pr_err("Out of memory !\n");
- return -ENOMEM;
- }
- err = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
- if (err < 0) {
- dev_err(&udev->dev, "couldn't register v4l2_device\n");
- kfree(dev);
- return err;
- }
- hdl = &dev->hdl;
- v4l2_ctrl_handler_init(hdl, 3);
- v4l2_ctrl_new_std(hdl, &stk_ctrl_ops,
- V4L2_CID_BRIGHTNESS, 0, 0xff, 0x1, 0x60);
- v4l2_ctrl_new_std(hdl, &stk_ctrl_ops,
- V4L2_CID_HFLIP, 0, 1, 1, 1);
- v4l2_ctrl_new_std(hdl, &stk_ctrl_ops,
- V4L2_CID_VFLIP, 0, 1, 1, 1);
- if (hdl->error) {
- err = hdl->error;
- dev_err(&udev->dev, "couldn't register control\n");
- goto error;
- }
- dev->v4l2_dev.ctrl_handler = hdl;
-
- spin_lock_init(&dev->spinlock);
- mutex_init(&dev->lock);
- init_waitqueue_head(&dev->wait_frame);
- dev->first_init = 1; /* webcam LED management */
-
- dev->udev = usb_get_dev(udev);
- dev->interface = interface;
- usb_get_intf(interface);
-
- if (hflip != -1)
- dev->vsettings.hflip = hflip;
- else if (dmi_check_system(stk_upside_down_dmi_table))
- dev->vsettings.hflip = 1;
- else
- dev->vsettings.hflip = 0;
- if (vflip != -1)
- dev->vsettings.vflip = vflip;
- else if (dmi_check_system(stk_upside_down_dmi_table))
- dev->vsettings.vflip = 1;
- else
- dev->vsettings.vflip = 0;
- dev->n_sbufs = 0;
- set_present(dev);
-
- /* Set up the endpoint information
- * use only the first isoc-in endpoint
- * for the current alternate setting */
- iface_desc = interface->cur_altsetting;
-
- for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
- endpoint = &iface_desc->endpoint[i].desc;
-
- if (!dev->isoc_ep
- && usb_endpoint_is_isoc_in(endpoint)) {
- /* we found an isoc in endpoint */
- dev->isoc_ep = usb_endpoint_num(endpoint);
- break;
- }
- }
- if (!dev->isoc_ep) {
- pr_err("Could not find isoc-in endpoint\n");
- err = -ENODEV;
- goto error_put;
- }
- dev->vsettings.palette = V4L2_PIX_FMT_RGB565;
- dev->vsettings.mode = MODE_VGA;
- dev->frame_size = 640 * 480 * 2;
-
- INIT_LIST_HEAD(&dev->sio_avail);
- INIT_LIST_HEAD(&dev->sio_full);
-
- usb_set_intfdata(interface, dev);
-
- err = stk_register_video_device(dev);
- if (err)
- goto error_put;
-
- return 0;
-
-error_put:
- usb_put_intf(interface);
- usb_put_dev(dev->udev);
-error:
- v4l2_ctrl_handler_free(hdl);
- v4l2_device_unregister(&dev->v4l2_dev);
- kfree(dev);
- return err;
-}
-
-static void stk_camera_disconnect(struct usb_interface *interface)
-{
- struct stk_camera *dev = usb_get_intfdata(interface);
-
- usb_set_intfdata(interface, NULL);
- unset_present(dev);
-
- wake_up_interruptible(&dev->wait_frame);
-
- pr_info("Syntek USB2.0 Camera release resources device %s\n",
- video_device_node_name(&dev->vdev));
-
- video_unregister_device(&dev->vdev);
-}
-
-#ifdef CONFIG_PM
-static int stk_camera_suspend(struct usb_interface *intf, pm_message_t message)
-{
- struct stk_camera *dev = usb_get_intfdata(intf);
- if (is_streaming(dev)) {
- stk_stop_stream(dev);
- /* yes, this is ugly */
- set_streaming(dev);
- }
- return 0;
-}
-
-static int stk_camera_resume(struct usb_interface *intf)
-{
- struct stk_camera *dev = usb_get_intfdata(intf);
- if (!is_initialised(dev))
- return 0;
- unset_initialised(dev);
- stk_initialise(dev);
- stk_camera_write_reg(dev, 0x0, 0x49);
- stk_setup_format(dev);
- if (is_streaming(dev))
- stk_start_stream(dev);
- return 0;
-}
-#endif
-
-static struct usb_driver stk_camera_driver = {
- .name = "stkwebcam",
- .probe = stk_camera_probe,
- .disconnect = stk_camera_disconnect,
- .id_table = stkwebcam_table,
-#ifdef CONFIG_PM
- .suspend = stk_camera_suspend,
- .resume = stk_camera_resume,
-#endif
-};
-
-module_usb_driver(stk_camera_driver);
diff --git a/drivers/staging/media/deprecated/stkwebcam/stk-webcam.h b/drivers/staging/media/deprecated/stkwebcam/stk-webcam.h
deleted file mode 100644
index 136decffe9ce..000000000000
--- a/drivers/staging/media/deprecated/stkwebcam/stk-webcam.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * stk-webcam.h : Driver for Syntek 1125 USB webcam controller
- *
- * Copyright (C) 2006 Nicolas VIVIEN
- * Copyright 2007-2008 Jaime Velasco Juan <jsagarribay@gmail.com>
- */
-
-#ifndef STKWEBCAM_H
-#define STKWEBCAM_H
-
-#include <linux/usb.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-common.h>
-
-#define DRIVER_VERSION "v0.0.1"
-#define DRIVER_VERSION_NUM 0x000001
-
-#define MAX_ISO_BUFS 3
-#define ISO_FRAMES_PER_DESC 16
-#define ISO_MAX_FRAME_SIZE 3 * 1024
-#define ISO_BUFFER_SIZE (ISO_FRAMES_PER_DESC * ISO_MAX_FRAME_SIZE)
-
-struct stk_iso_buf {
- void *data;
- int length;
- int read;
- struct urb *urb;
-};
-
-/* Streaming IO buffers */
-struct stk_sio_buffer {
- struct v4l2_buffer v4lbuf;
- char *buffer;
- int mapcount;
- struct stk_camera *dev;
- struct list_head list;
-};
-
-enum stk_mode {MODE_VGA, MODE_SXGA, MODE_CIF, MODE_QVGA, MODE_QCIF};
-
-struct stk_video {
- enum stk_mode mode;
- __u32 palette;
- int hflip;
- int vflip;
-};
-
-enum stk_status {
- S_PRESENT = 1,
- S_INITIALISED = 2,
- S_MEMALLOCD = 4,
- S_STREAMING = 8,
-};
-#define is_present(dev) ((dev)->status & S_PRESENT)
-#define is_initialised(dev) ((dev)->status & S_INITIALISED)
-#define is_streaming(dev) ((dev)->status & S_STREAMING)
-#define is_memallocd(dev) ((dev)->status & S_MEMALLOCD)
-#define set_present(dev) ((dev)->status = S_PRESENT)
-#define unset_present(dev) ((dev)->status &= \
- ~(S_PRESENT|S_INITIALISED|S_STREAMING))
-#define set_initialised(dev) ((dev)->status |= S_INITIALISED)
-#define unset_initialised(dev) ((dev)->status &= ~S_INITIALISED)
-#define set_memallocd(dev) ((dev)->status |= S_MEMALLOCD)
-#define unset_memallocd(dev) ((dev)->status &= ~S_MEMALLOCD)
-#define set_streaming(dev) ((dev)->status |= S_STREAMING)
-#define unset_streaming(dev) ((dev)->status &= ~S_STREAMING)
-
-struct regval {
- unsigned reg;
- unsigned val;
-};
-
-struct stk_camera {
- struct v4l2_device v4l2_dev;
- struct v4l2_ctrl_handler hdl;
- struct video_device vdev;
- struct usb_device *udev;
- struct usb_interface *interface;
- int webcam_model;
- struct file *owner;
- struct mutex lock;
- int first_init;
-
- u8 isoc_ep;
-
- /* Not sure if this is right */
- atomic_t urbs_used;
-
- struct stk_video vsettings;
-
- enum stk_status status;
-
- spinlock_t spinlock;
- wait_queue_head_t wait_frame;
-
- struct stk_iso_buf *isobufs;
-
- int frame_size;
- /* Streaming buffers */
- int reading;
- unsigned int n_sbufs;
- struct stk_sio_buffer *sio_bufs;
- struct list_head sio_avail;
- struct list_head sio_full;
- unsigned sequence;
-
- u8 read_reg_scratch;
-};
-
-#define vdev_to_camera(d) container_of(d, struct stk_camera, vdev)
-
-int stk_camera_write_reg(struct stk_camera *, u16, u8);
-int stk_camera_read_reg(struct stk_camera *, u16, u8 *);
-
-int stk_sensor_init(struct stk_camera *);
-int stk_sensor_configure(struct stk_camera *);
-int stk_sensor_sleep(struct stk_camera *dev);
-int stk_sensor_wakeup(struct stk_camera *dev);
-int stk_sensor_set_brightness(struct stk_camera *dev, int br);
-
-#endif
diff --git a/drivers/staging/media/deprecated/tm6000/Kconfig b/drivers/staging/media/deprecated/tm6000/Kconfig
deleted file mode 100644
index 73d72e49eb28..000000000000
--- a/drivers/staging/media/deprecated/tm6000/Kconfig
+++ /dev/null
@@ -1,37 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-config VIDEO_TM6000
- tristate "TV Master TM5600/6000/6010 driver (DEPRECATED)"
- depends on VIDEO_DEV && I2C && INPUT && RC_CORE && USB
- select VIDEO_TUNER
- select MEDIA_TUNER_XC2028
- select MEDIA_TUNER_XC5000
- select VIDEOBUF_VMALLOC
- help
- Support for TM5600/TM6000/TM6010 USB Device
-
- Since these cards have no MPEG decoder onboard, they transmit
- only compressed MPEG data over the usb bus, so you need
- an external software decoder to watch TV on your computer.
-
- This driver is deprecated and is scheduled for removal by
- the beginning of 2023. See the TODO file for more information.
-
- Say Y if you own such a device and want to use it.
-
-config VIDEO_TM6000_ALSA
- tristate "TV Master TM5600/6000/6010 audio support"
- depends on VIDEO_TM6000 && SND
- select SND_PCM
- help
- This is a video4linux driver for direct (DMA) audio for
- TM5600/TM6000/TM6010 USB Devices.
-
- To compile this driver as a module, choose M here: the
- module will be called tm6000-alsa.
-
-config VIDEO_TM6000_DVB
- tristate "DVB Support for tm6000 based TV cards"
- depends on VIDEO_TM6000 && DVB_CORE && USB
- select DVB_ZL10353
- help
- This adds support for DVB cards based on the tm5600/tm6000 chip.
diff --git a/drivers/staging/media/deprecated/tm6000/Makefile b/drivers/staging/media/deprecated/tm6000/Makefile
deleted file mode 100644
index 75247a02a485..000000000000
--- a/drivers/staging/media/deprecated/tm6000/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-tm6000-y := tm6000-cards.o \
- tm6000-core.o \
- tm6000-i2c.o \
- tm6000-video.o \
- tm6000-stds.o \
- tm6000-input.o
-
-obj-$(CONFIG_VIDEO_TM6000) += tm6000.o
-obj-$(CONFIG_VIDEO_TM6000_ALSA) += tm6000-alsa.o
-obj-$(CONFIG_VIDEO_TM6000_DVB) += tm6000-dvb.o
-
-ccflags-y += -I $(srctree)/drivers/media/tuners
-ccflags-y += -I $(srctree)/drivers/media/dvb-frontends
diff --git a/drivers/staging/media/deprecated/tm6000/TODO b/drivers/staging/media/deprecated/tm6000/TODO
deleted file mode 100644
index ecb30a429689..000000000000
--- a/drivers/staging/media/deprecated/tm6000/TODO
+++ /dev/null
@@ -1,7 +0,0 @@
-This is one of the few drivers still not using the vb2
-framework, so this driver is now deprecated with the intent of
-removing it altogether by the beginning of 2023.
-
-In order to keep this driver it has to be converted to vb2.
-If someone is interested in doing this work, then contact the
-linux-media mailinglist (https://linuxtv.org/lists.php).
diff --git a/drivers/staging/media/deprecated/tm6000/tm6000-alsa.c b/drivers/staging/media/deprecated/tm6000/tm6000-alsa.c
deleted file mode 100644
index a19a46770c2b..000000000000
--- a/drivers/staging/media/deprecated/tm6000/tm6000-alsa.c
+++ /dev/null
@@ -1,440 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-// Support for audio capture for tm5600/6000/6010
-// Copyright (c) 2007-2008 Mauro Carvalho Chehab <mchehab@kernel.org>
-//
-// Based on cx88-alsa.c
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/interrupt.h>
-#include <linux/usb.h>
-#include <linux/slab.h>
-
-#include <linux/delay.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/control.h>
-#include <sound/initval.h>
-
-
-#include "tm6000.h"
-#include "tm6000-regs.h"
-
-#undef dprintk
-
-#define dprintk(level, fmt, arg...) do { \
- if (debug >= level) \
- printk(KERN_INFO "%s/1: " fmt, chip->core->name , ## arg); \
- } while (0)
-
-/****************************************************************************
- Module global static vars
- ****************************************************************************/
-
-static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
-
-static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
-
-module_param_array(enable, bool, NULL, 0444);
-MODULE_PARM_DESC(enable, "Enable tm6000x soundcard. default enabled.");
-
-module_param_array(index, int, NULL, 0444);
-MODULE_PARM_DESC(index, "Index value for tm6000x capture interface(s).");
-
-
-/****************************************************************************
- Module macros
- ****************************************************************************/
-
-MODULE_DESCRIPTION("ALSA driver module for tm5600/tm6000/tm6010 based TV cards");
-MODULE_AUTHOR("Mauro Carvalho Chehab");
-MODULE_LICENSE("GPL v2");
-static unsigned int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "enable debug messages");
-
-/****************************************************************************
- Module specific functions
- ****************************************************************************/
-
-/*
- * BOARD Specific: Sets audio DMA
- */
-
-static int _tm6000_start_audio_dma(struct snd_tm6000_card *chip)
-{
- struct tm6000_core *core = chip->core;
-
- dprintk(1, "Starting audio DMA\n");
-
- /* Enables audio */
- tm6000_set_reg_mask(core, TM6010_REQ07_RCC_ACTIVE_IF, 0x40, 0x40);
-
- tm6000_set_audio_bitrate(core, 48000);
-
- return 0;
-}
-
-/*
- * BOARD Specific: Resets audio DMA
- */
-static int _tm6000_stop_audio_dma(struct snd_tm6000_card *chip)
-{
- struct tm6000_core *core = chip->core;
-
- dprintk(1, "Stopping audio DMA\n");
-
- /* Disables audio */
- tm6000_set_reg_mask(core, TM6010_REQ07_RCC_ACTIVE_IF, 0x00, 0x40);
-
- return 0;
-}
-
-/****************************************************************************
- ALSA PCM Interface
- ****************************************************************************/
-
-/*
- * Digital hardware definition
- */
-#define DEFAULT_FIFO_SIZE 4096
-
-static const struct snd_pcm_hardware snd_tm6000_digital_hw = {
- .info = SNDRV_PCM_INFO_BATCH |
- SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP_VALID,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
-
- .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_KNOT,
- .rate_min = 48000,
- .rate_max = 48000,
- .channels_min = 2,
- .channels_max = 2,
- .period_bytes_min = 64,
- .period_bytes_max = 12544,
- .periods_min = 2,
- .periods_max = 98,
- .buffer_bytes_max = 62720 * 8,
-};
-
-/*
- * audio pcm capture open callback
- */
-static int snd_tm6000_pcm_open(struct snd_pcm_substream *substream)
-{
- struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- int err;
-
- err = snd_pcm_hw_constraint_pow2(runtime, 0,
- SNDRV_PCM_HW_PARAM_PERIODS);
- if (err < 0)
- goto _error;
-
- chip->substream = substream;
-
- runtime->hw = snd_tm6000_digital_hw;
- snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
-
- return 0;
-_error:
- dprintk(1, "Error opening PCM!\n");
- return err;
-}
-
-/*
- * audio close callback
- */
-static int snd_tm6000_close(struct snd_pcm_substream *substream)
-{
- struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
- struct tm6000_core *core = chip->core;
-
- if (atomic_read(&core->stream_started) > 0) {
- atomic_set(&core->stream_started, 0);
- schedule_work(&core->wq_trigger);
- }
-
- return 0;
-}
-
-static int tm6000_fillbuf(struct tm6000_core *core, char *buf, int size)
-{
- struct snd_tm6000_card *chip = core->adev;
- struct snd_pcm_substream *substream = chip->substream;
- struct snd_pcm_runtime *runtime;
- int period_elapsed = 0;
- unsigned int stride, buf_pos;
- int length;
-
- if (atomic_read(&core->stream_started) == 0)
- return 0;
-
- if (!size || !substream) {
- dprintk(1, "substream was NULL\n");
- return -EINVAL;
- }
-
- runtime = substream->runtime;
- if (!runtime || !runtime->dma_area) {
- dprintk(1, "runtime was NULL\n");
- return -EINVAL;
- }
-
- buf_pos = chip->buf_pos;
- stride = runtime->frame_bits >> 3;
-
- if (stride == 0) {
- dprintk(1, "stride is zero\n");
- return -EINVAL;
- }
-
- length = size / stride;
- if (length == 0) {
- dprintk(1, "%s: length was zero\n", __func__);
- return -EINVAL;
- }
-
- dprintk(1, "Copying %d bytes at %p[%d] - buf size=%d x %d\n", size,
- runtime->dma_area, buf_pos,
- (unsigned int)runtime->buffer_size, stride);
-
- if (buf_pos + length >= runtime->buffer_size) {
- unsigned int cnt = runtime->buffer_size - buf_pos;
- memcpy(runtime->dma_area + buf_pos * stride, buf, cnt * stride);
- memcpy(runtime->dma_area, buf + cnt * stride,
- length * stride - cnt * stride);
- } else
- memcpy(runtime->dma_area + buf_pos * stride, buf,
- length * stride);
-
- snd_pcm_stream_lock(substream);
-
- chip->buf_pos += length;
- if (chip->buf_pos >= runtime->buffer_size)
- chip->buf_pos -= runtime->buffer_size;
-
- chip->period_pos += length;
- if (chip->period_pos >= runtime->period_size) {
- chip->period_pos -= runtime->period_size;
- period_elapsed = 1;
- }
-
- snd_pcm_stream_unlock(substream);
-
- if (period_elapsed)
- snd_pcm_period_elapsed(substream);
-
- return 0;
-}
-
-/*
- * prepare callback
- */
-static int snd_tm6000_prepare(struct snd_pcm_substream *substream)
-{
- struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
-
- chip->buf_pos = 0;
- chip->period_pos = 0;
-
- return 0;
-}
-
-
-/*
- * trigger callback
- */
-static void audio_trigger(struct work_struct *work)
-{
- struct tm6000_core *core = container_of(work, struct tm6000_core,
- wq_trigger);
- struct snd_tm6000_card *chip = core->adev;
-
- if (atomic_read(&core->stream_started)) {
- dprintk(1, "starting capture");
- _tm6000_start_audio_dma(chip);
- } else {
- dprintk(1, "stopping capture");
- _tm6000_stop_audio_dma(chip);
- }
-}
-
-static int snd_tm6000_card_trigger(struct snd_pcm_substream *substream, int cmd)
-{
- struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
- struct tm6000_core *core = chip->core;
- int err = 0;
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_START:
- atomic_set(&core->stream_started, 1);
- break;
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_STOP:
- atomic_set(&core->stream_started, 0);
- break;
- default:
- err = -EINVAL;
- break;
- }
- schedule_work(&core->wq_trigger);
-
- return err;
-}
-/*
- * pointer callback
- */
-static snd_pcm_uframes_t snd_tm6000_pointer(struct snd_pcm_substream *substream)
-{
- struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
-
- return chip->buf_pos;
-}
-
-/*
- * operators
- */
-static const struct snd_pcm_ops snd_tm6000_pcm_ops = {
- .open = snd_tm6000_pcm_open,
- .close = snd_tm6000_close,
- .prepare = snd_tm6000_prepare,
- .trigger = snd_tm6000_card_trigger,
- .pointer = snd_tm6000_pointer,
-};
-
-/*
- * create a PCM device
- */
-
-/* FIXME: Control interface - How to control volume/mute? */
-
-/****************************************************************************
- Basic Flow for Sound Devices
- ****************************************************************************/
-
-/*
- * Alsa Constructor - Component probe
- */
-static int tm6000_audio_init(struct tm6000_core *dev)
-{
- struct snd_card *card;
- struct snd_tm6000_card *chip;
- int rc;
- static int devnr;
- char component[14];
- struct snd_pcm *pcm;
-
- if (!dev)
- return 0;
-
- if (devnr >= SNDRV_CARDS)
- return -ENODEV;
-
- if (!enable[devnr])
- return -ENOENT;
-
- rc = snd_card_new(&dev->udev->dev, index[devnr], "tm6000",
- THIS_MODULE, 0, &card);
- if (rc < 0) {
- snd_printk(KERN_ERR "cannot create card instance %d\n", devnr);
- return rc;
- }
- strscpy(card->driver, "tm6000-alsa", sizeof(card->driver));
- strscpy(card->shortname, "TM5600/60x0", sizeof(card->shortname));
- sprintf(card->longname, "TM5600/60x0 Audio at bus %d device %d",
- dev->udev->bus->busnum, dev->udev->devnum);
-
- sprintf(component, "USB%04x:%04x",
- le16_to_cpu(dev->udev->descriptor.idVendor),
- le16_to_cpu(dev->udev->descriptor.idProduct));
- snd_component_add(card, component);
-
- chip = kzalloc(sizeof(struct snd_tm6000_card), GFP_KERNEL);
- if (!chip) {
- rc = -ENOMEM;
- goto error;
- }
-
- chip->core = dev;
- chip->card = card;
- dev->adev = chip;
- spin_lock_init(&chip->reg_lock);
-
- rc = snd_pcm_new(card, "TM6000 Audio", 0, 0, 1, &pcm);
- if (rc < 0)
- goto error_chip;
-
- pcm->info_flags = 0;
- pcm->private_data = chip;
- strscpy(pcm->name, "Trident TM5600/60x0", sizeof(pcm->name));
-
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_tm6000_pcm_ops);
- snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0);
-
- INIT_WORK(&dev->wq_trigger, audio_trigger);
- rc = snd_card_register(card);
- if (rc < 0)
- goto error_chip;
-
- dprintk(1, "Registered audio driver for %s\n", card->longname);
-
- return 0;
-
-error_chip:
- kfree(chip);
- dev->adev = NULL;
-error:
- snd_card_free(card);
- return rc;
-}
-
-static int tm6000_audio_fini(struct tm6000_core *dev)
-{
- struct snd_tm6000_card *chip;
-
- if (!dev)
- return 0;
- chip = dev->adev;
-
- if (!chip)
- return 0;
-
- if (!chip->card)
- return 0;
-
- snd_card_free(chip->card);
- chip->card = NULL;
- kfree(chip);
- dev->adev = NULL;
-
- return 0;
-}
-
-static struct tm6000_ops audio_ops = {
- .type = TM6000_AUDIO,
- .name = "TM6000 Audio Extension",
- .init = tm6000_audio_init,
- .fini = tm6000_audio_fini,
- .fillbuf = tm6000_fillbuf,
-};
-
-static int __init tm6000_alsa_register(void)
-{
- return tm6000_register_extension(&audio_ops);
-}
-
-static void __exit tm6000_alsa_unregister(void)
-{
- tm6000_unregister_extension(&audio_ops);
-}
-
-module_init(tm6000_alsa_register);
-module_exit(tm6000_alsa_unregister);
diff --git a/drivers/staging/media/deprecated/tm6000/tm6000-cards.c b/drivers/staging/media/deprecated/tm6000/tm6000-cards.c
deleted file mode 100644
index 98f4a63adc2a..000000000000
--- a/drivers/staging/media/deprecated/tm6000/tm6000-cards.c
+++ /dev/null
@@ -1,1397 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-// tm6000-cards.c - driver for TM5600/TM6000/TM6010 USB video capture devices
-//
-// Copyright (c) 2006-2007 Mauro Carvalho Chehab <mchehab@kernel.org>
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/usb.h>
-#include <linux/slab.h>
-#include <media/v4l2-common.h>
-#include <media/tuner.h>
-#include <media/i2c/tvaudio.h>
-#include <media/rc-map.h>
-
-#include "tm6000.h"
-#include "tm6000-regs.h"
-#include "xc2028.h"
-#include "xc5000.h"
-
-#define TM6000_BOARD_UNKNOWN 0
-#define TM5600_BOARD_GENERIC 1
-#define TM6000_BOARD_GENERIC 2
-#define TM6010_BOARD_GENERIC 3
-#define TM5600_BOARD_10MOONS_UT821 4
-#define TM5600_BOARD_10MOONS_UT330 5
-#define TM6000_BOARD_ADSTECH_DUAL_TV 6
-#define TM6000_BOARD_FREECOM_AND_SIMILAR 7
-#define TM6000_BOARD_ADSTECH_MINI_DUAL_TV 8
-#define TM6010_BOARD_HAUPPAUGE_900H 9
-#define TM6010_BOARD_BEHOLD_WANDER 10
-#define TM6010_BOARD_BEHOLD_VOYAGER 11
-#define TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE 12
-#define TM6010_BOARD_TWINHAN_TU501 13
-#define TM6010_BOARD_BEHOLD_WANDER_LITE 14
-#define TM6010_BOARD_BEHOLD_VOYAGER_LITE 15
-#define TM5600_BOARD_TERRATEC_GRABSTER 16
-
-#define is_generic(model) ((model == TM6000_BOARD_UNKNOWN) || \
- (model == TM5600_BOARD_GENERIC) || \
- (model == TM6000_BOARD_GENERIC) || \
- (model == TM6010_BOARD_GENERIC))
-
-#define TM6000_MAXBOARDS 16
-static unsigned int card[] = {[0 ... (TM6000_MAXBOARDS - 1)] = UNSET };
-
-module_param_array(card, int, NULL, 0444);
-
-static unsigned long tm6000_devused;
-
-
-struct tm6000_board {
- char *name;
- char eename[16]; /* EEPROM name */
- unsigned eename_size; /* size of EEPROM name */
- unsigned eename_pos; /* Position where it appears at ROM */
-
- struct tm6000_capabilities caps;
-
- enum tm6000_devtype type; /* variant of the chipset */
- int tuner_type; /* type of the tuner */
- int tuner_addr; /* tuner address */
- int demod_addr; /* demodulator address */
-
- struct tm6000_gpio gpio;
-
- struct tm6000_input vinput[3];
- struct tm6000_input rinput;
-
- char *ir_codes;
-};
-
-static struct tm6000_board tm6000_boards[] = {
- [TM6000_BOARD_UNKNOWN] = {
- .name = "Unknown tm6000 video grabber",
- .caps = {
- .has_tuner = 1,
- .has_eeprom = 1,
- },
- .gpio = {
- .tuner_reset = TM6000_GPIO_1,
- },
- .vinput = { {
- .type = TM6000_INPUT_TV,
- .vmux = TM6000_VMUX_VIDEO_B,
- .amux = TM6000_AMUX_ADC1,
- }, {
- .type = TM6000_INPUT_COMPOSITE1,
- .vmux = TM6000_VMUX_VIDEO_A,
- .amux = TM6000_AMUX_ADC2,
- }, {
- .type = TM6000_INPUT_SVIDEO,
- .vmux = TM6000_VMUX_VIDEO_AB,
- .amux = TM6000_AMUX_ADC2,
- },
- },
- },
- [TM5600_BOARD_GENERIC] = {
- .name = "Generic tm5600 board",
- .type = TM5600,
- .tuner_type = TUNER_XC2028,
- .tuner_addr = 0xc2 >> 1,
- .caps = {
- .has_tuner = 1,
- .has_eeprom = 1,
- },
- .gpio = {
- .tuner_reset = TM6000_GPIO_1,
- },
- .vinput = { {
- .type = TM6000_INPUT_TV,
- .vmux = TM6000_VMUX_VIDEO_B,
- .amux = TM6000_AMUX_ADC1,
- }, {
- .type = TM6000_INPUT_COMPOSITE1,
- .vmux = TM6000_VMUX_VIDEO_A,
- .amux = TM6000_AMUX_ADC2,
- }, {
- .type = TM6000_INPUT_SVIDEO,
- .vmux = TM6000_VMUX_VIDEO_AB,
- .amux = TM6000_AMUX_ADC2,
- },
- },
- },
- [TM6000_BOARD_GENERIC] = {
- .name = "Generic tm6000 board",
- .tuner_type = TUNER_XC2028,
- .tuner_addr = 0xc2 >> 1,
- .caps = {
- .has_tuner = 1,
- .has_eeprom = 1,
- },
- .gpio = {
- .tuner_reset = TM6000_GPIO_1,
- },
- .vinput = { {
- .type = TM6000_INPUT_TV,
- .vmux = TM6000_VMUX_VIDEO_B,
- .amux = TM6000_AMUX_ADC1,
- }, {
- .type = TM6000_INPUT_COMPOSITE1,
- .vmux = TM6000_VMUX_VIDEO_A,
- .amux = TM6000_AMUX_ADC2,
- }, {
- .type = TM6000_INPUT_SVIDEO,
- .vmux = TM6000_VMUX_VIDEO_AB,
- .amux = TM6000_AMUX_ADC2,
- },
- },
- },
- [TM6010_BOARD_GENERIC] = {
- .name = "Generic tm6010 board",
- .type = TM6010,
- .tuner_type = TUNER_XC2028,
- .tuner_addr = 0xc2 >> 1,
- .demod_addr = 0x1e >> 1,
- .caps = {
- .has_tuner = 1,
- .has_dvb = 1,
- .has_zl10353 = 1,
- .has_eeprom = 1,
- .has_remote = 1,
- },
- .gpio = {
- .tuner_reset = TM6010_GPIO_2,
- .tuner_on = TM6010_GPIO_3,
- .demod_reset = TM6010_GPIO_1,
- .demod_on = TM6010_GPIO_4,
- .power_led = TM6010_GPIO_7,
- .dvb_led = TM6010_GPIO_5,
- .ir = TM6010_GPIO_0,
- },
- .vinput = { {
- .type = TM6000_INPUT_TV,
- .vmux = TM6000_VMUX_VIDEO_B,
- .amux = TM6000_AMUX_SIF1,
- }, {
- .type = TM6000_INPUT_COMPOSITE1,
- .vmux = TM6000_VMUX_VIDEO_A,
- .amux = TM6000_AMUX_ADC2,
- }, {
- .type = TM6000_INPUT_SVIDEO,
- .vmux = TM6000_VMUX_VIDEO_AB,
- .amux = TM6000_AMUX_ADC2,
- },
- },
- },
- [TM5600_BOARD_10MOONS_UT821] = {
- .name = "10Moons UT 821",
- .tuner_type = TUNER_XC2028,
- .eename = { '1', '0', 'M', 'O', 'O', 'N', 'S', '5', '6', '0', '0', 0xff, 0x45, 0x5b},
- .eename_size = 14,
- .eename_pos = 0x14,
- .type = TM5600,
- .tuner_addr = 0xc2 >> 1,
- .caps = {
- .has_tuner = 1,
- .has_eeprom = 1,
- },
- .gpio = {
- .tuner_reset = TM6000_GPIO_1,
- },
- .vinput = { {
- .type = TM6000_INPUT_TV,
- .vmux = TM6000_VMUX_VIDEO_B,
- .amux = TM6000_AMUX_ADC1,
- }, {
- .type = TM6000_INPUT_COMPOSITE1,
- .vmux = TM6000_VMUX_VIDEO_A,
- .amux = TM6000_AMUX_ADC2,
- }, {
- .type = TM6000_INPUT_SVIDEO,
- .vmux = TM6000_VMUX_VIDEO_AB,
- .amux = TM6000_AMUX_ADC2,
- },
- },
- },
- [TM5600_BOARD_10MOONS_UT330] = {
- .name = "10Moons UT 330",
- .tuner_type = TUNER_PHILIPS_FQ1216AME_MK4,
- .tuner_addr = 0xc8 >> 1,
- .caps = {
- .has_tuner = 1,
- .has_dvb = 0,
- .has_zl10353 = 0,
- .has_eeprom = 1,
- },
- .vinput = { {
- .type = TM6000_INPUT_TV,
- .vmux = TM6000_VMUX_VIDEO_B,
- .amux = TM6000_AMUX_ADC1,
- }, {
- .type = TM6000_INPUT_COMPOSITE1,
- .vmux = TM6000_VMUX_VIDEO_A,
- .amux = TM6000_AMUX_ADC2,
- }, {
- .type = TM6000_INPUT_SVIDEO,
- .vmux = TM6000_VMUX_VIDEO_AB,
- .amux = TM6000_AMUX_ADC2,
- },
- },
- },
- [TM6000_BOARD_ADSTECH_DUAL_TV] = {
- .name = "ADSTECH Dual TV USB",
- .tuner_type = TUNER_XC2028,
- .tuner_addr = 0xc8 >> 1,
- .caps = {
- .has_tuner = 1,
- .has_tda9874 = 1,
- .has_dvb = 1,
- .has_zl10353 = 1,
- .has_eeprom = 1,
- },
- .vinput = { {
- .type = TM6000_INPUT_TV,
- .vmux = TM6000_VMUX_VIDEO_B,
- .amux = TM6000_AMUX_ADC1,
- }, {
- .type = TM6000_INPUT_COMPOSITE1,
- .vmux = TM6000_VMUX_VIDEO_A,
- .amux = TM6000_AMUX_ADC2,
- }, {
- .type = TM6000_INPUT_SVIDEO,
- .vmux = TM6000_VMUX_VIDEO_AB,
- .amux = TM6000_AMUX_ADC2,
- },
- },
- },
- [TM6000_BOARD_FREECOM_AND_SIMILAR] = {
- .name = "Freecom Hybrid Stick / Moka DVB-T Receiver Dual",
- .tuner_type = TUNER_XC2028, /* has a XC3028 */
- .tuner_addr = 0xc2 >> 1,
- .demod_addr = 0x1e >> 1,
- .caps = {
- .has_tuner = 1,
- .has_dvb = 1,
- .has_zl10353 = 1,
- .has_eeprom = 0,
- .has_remote = 1,
- },
- .gpio = {
- .tuner_reset = TM6000_GPIO_4,
- },
- .vinput = { {
- .type = TM6000_INPUT_TV,
- .vmux = TM6000_VMUX_VIDEO_B,
- .amux = TM6000_AMUX_ADC1,
- }, {
- .type = TM6000_INPUT_COMPOSITE1,
- .vmux = TM6000_VMUX_VIDEO_A,
- .amux = TM6000_AMUX_ADC2,
- }, {
- .type = TM6000_INPUT_SVIDEO,
- .vmux = TM6000_VMUX_VIDEO_AB,
- .amux = TM6000_AMUX_ADC2,
- },
- },
- },
- [TM6000_BOARD_ADSTECH_MINI_DUAL_TV] = {
- .name = "ADSTECH Mini Dual TV USB",
- .tuner_type = TUNER_XC2028, /* has a XC3028 */
- .tuner_addr = 0xc8 >> 1,
- .demod_addr = 0x1e >> 1,
- .caps = {
- .has_tuner = 1,
- .has_dvb = 1,
- .has_zl10353 = 1,
- .has_eeprom = 0,
- },
- .gpio = {
- .tuner_reset = TM6000_GPIO_4,
- },
- .vinput = { {
- .type = TM6000_INPUT_TV,
- .vmux = TM6000_VMUX_VIDEO_B,
- .amux = TM6000_AMUX_ADC1,
- }, {
- .type = TM6000_INPUT_COMPOSITE1,
- .vmux = TM6000_VMUX_VIDEO_A,
- .amux = TM6000_AMUX_ADC2,
- }, {
- .type = TM6000_INPUT_SVIDEO,
- .vmux = TM6000_VMUX_VIDEO_AB,
- .amux = TM6000_AMUX_ADC2,
- },
- },
- },
- [TM6010_BOARD_HAUPPAUGE_900H] = {
- .name = "Hauppauge WinTV HVR-900H / WinTV USB2-Stick",
- .eename = { 'H', 0, 'V', 0, 'R', 0, '9', 0, '0', 0, '0', 0, 'H', 0 },
- .eename_size = 14,
- .eename_pos = 0x42,
- .tuner_type = TUNER_XC2028, /* has a XC3028 */
- .tuner_addr = 0xc2 >> 1,
- .demod_addr = 0x1e >> 1,
- .type = TM6010,
- .ir_codes = RC_MAP_HAUPPAUGE,
- .caps = {
- .has_tuner = 1,
- .has_dvb = 1,
- .has_zl10353 = 1,
- .has_eeprom = 1,
- .has_remote = 1,
- },
- .gpio = {
- .tuner_reset = TM6010_GPIO_2,
- .tuner_on = TM6010_GPIO_3,
- .demod_reset = TM6010_GPIO_1,
- .demod_on = TM6010_GPIO_4,
- .power_led = TM6010_GPIO_7,
- .dvb_led = TM6010_GPIO_5,
- .ir = TM6010_GPIO_0,
- },
- .vinput = { {
- .type = TM6000_INPUT_TV,
- .vmux = TM6000_VMUX_VIDEO_B,
- .amux = TM6000_AMUX_SIF1,
- }, {
- .type = TM6000_INPUT_COMPOSITE1,
- .vmux = TM6000_VMUX_VIDEO_A,
- .amux = TM6000_AMUX_ADC2,
- }, {
- .type = TM6000_INPUT_SVIDEO,
- .vmux = TM6000_VMUX_VIDEO_AB,
- .amux = TM6000_AMUX_ADC2,
- },
- },
- },
- [TM6010_BOARD_BEHOLD_WANDER] = {
- .name = "Beholder Wander DVB-T/TV/FM USB2.0",
- .tuner_type = TUNER_XC5000,
- .tuner_addr = 0xc2 >> 1,
- .demod_addr = 0x1e >> 1,
- .type = TM6010,
- .caps = {
- .has_tuner = 1,
- .has_dvb = 1,
- .has_zl10353 = 1,
- .has_eeprom = 1,
- .has_remote = 1,
- .has_radio = 1,
- },
- .gpio = {
- .tuner_reset = TM6010_GPIO_0,
- .demod_reset = TM6010_GPIO_1,
- .power_led = TM6010_GPIO_6,
- },
- .vinput = { {
- .type = TM6000_INPUT_TV,
- .vmux = TM6000_VMUX_VIDEO_B,
- .amux = TM6000_AMUX_SIF1,
- }, {
- .type = TM6000_INPUT_COMPOSITE1,
- .vmux = TM6000_VMUX_VIDEO_A,
- .amux = TM6000_AMUX_ADC2,
- }, {
- .type = TM6000_INPUT_SVIDEO,
- .vmux = TM6000_VMUX_VIDEO_AB,
- .amux = TM6000_AMUX_ADC2,
- },
- },
- .rinput = {
- .type = TM6000_INPUT_RADIO,
- .amux = TM6000_AMUX_ADC1,
- },
- },
- [TM6010_BOARD_BEHOLD_VOYAGER] = {
- .name = "Beholder Voyager TV/FM USB2.0",
- .tuner_type = TUNER_XC5000,
- .tuner_addr = 0xc2 >> 1,
- .type = TM6010,
- .caps = {
- .has_tuner = 1,
- .has_dvb = 0,
- .has_zl10353 = 0,
- .has_eeprom = 1,
- .has_remote = 1,
- .has_radio = 1,
- },
- .gpio = {
- .tuner_reset = TM6010_GPIO_0,
- .power_led = TM6010_GPIO_6,
- },
- .vinput = { {
- .type = TM6000_INPUT_TV,
- .vmux = TM6000_VMUX_VIDEO_B,
- .amux = TM6000_AMUX_SIF1,
- }, {
- .type = TM6000_INPUT_COMPOSITE1,
- .vmux = TM6000_VMUX_VIDEO_A,
- .amux = TM6000_AMUX_ADC2,
- }, {
- .type = TM6000_INPUT_SVIDEO,
- .vmux = TM6000_VMUX_VIDEO_AB,
- .amux = TM6000_AMUX_ADC2,
- },
- },
- .rinput = {
- .type = TM6000_INPUT_RADIO,
- .amux = TM6000_AMUX_ADC1,
- },
- },
- [TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE] = {
- .name = "Terratec Cinergy Hybrid XE / Cinergy Hybrid-Stick",
- .tuner_type = TUNER_XC2028, /* has a XC3028 */
- .tuner_addr = 0xc2 >> 1,
- .demod_addr = 0x1e >> 1,
- .type = TM6010,
- .caps = {
- .has_tuner = 1,
- .has_dvb = 1,
- .has_zl10353 = 1,
- .has_eeprom = 1,
- .has_remote = 1,
- .has_radio = 1,
- },
- .gpio = {
- .tuner_reset = TM6010_GPIO_2,
- .tuner_on = TM6010_GPIO_3,
- .demod_reset = TM6010_GPIO_1,
- .demod_on = TM6010_GPIO_4,
- .power_led = TM6010_GPIO_7,
- .dvb_led = TM6010_GPIO_5,
- .ir = TM6010_GPIO_0,
- },
- .ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS,
- .vinput = { {
- .type = TM6000_INPUT_TV,
- .vmux = TM6000_VMUX_VIDEO_B,
- .amux = TM6000_AMUX_SIF1,
- }, {
- .type = TM6000_INPUT_COMPOSITE1,
- .vmux = TM6000_VMUX_VIDEO_A,
- .amux = TM6000_AMUX_ADC2,
- }, {
- .type = TM6000_INPUT_SVIDEO,
- .vmux = TM6000_VMUX_VIDEO_AB,
- .amux = TM6000_AMUX_ADC2,
- },
- },
- .rinput = {
- .type = TM6000_INPUT_RADIO,
- .amux = TM6000_AMUX_SIF1,
- },
- },
- [TM5600_BOARD_TERRATEC_GRABSTER] = {
- .name = "Terratec Grabster AV 150/250 MX",
- .type = TM5600,
- .tuner_type = TUNER_ABSENT,
- .vinput = { {
- .type = TM6000_INPUT_TV,
- .vmux = TM6000_VMUX_VIDEO_B,
- .amux = TM6000_AMUX_ADC1,
- }, {
- .type = TM6000_INPUT_COMPOSITE1,
- .vmux = TM6000_VMUX_VIDEO_A,
- .amux = TM6000_AMUX_ADC2,
- }, {
- .type = TM6000_INPUT_SVIDEO,
- .vmux = TM6000_VMUX_VIDEO_AB,
- .amux = TM6000_AMUX_ADC2,
- },
- },
- },
- [TM6010_BOARD_TWINHAN_TU501] = {
- .name = "Twinhan TU501(704D1)",
- .tuner_type = TUNER_XC2028, /* has a XC3028 */
- .tuner_addr = 0xc2 >> 1,
- .demod_addr = 0x1e >> 1,
- .type = TM6010,
- .caps = {
- .has_tuner = 1,
- .has_dvb = 1,
- .has_zl10353 = 1,
- .has_eeprom = 1,
- .has_remote = 1,
- },
- .gpio = {
- .tuner_reset = TM6010_GPIO_2,
- .tuner_on = TM6010_GPIO_3,
- .demod_reset = TM6010_GPIO_1,
- .demod_on = TM6010_GPIO_4,
- .power_led = TM6010_GPIO_7,
- .dvb_led = TM6010_GPIO_5,
- .ir = TM6010_GPIO_0,
- },
- .vinput = { {
- .type = TM6000_INPUT_TV,
- .vmux = TM6000_VMUX_VIDEO_B,
- .amux = TM6000_AMUX_SIF1,
- }, {
- .type = TM6000_INPUT_COMPOSITE1,
- .vmux = TM6000_VMUX_VIDEO_A,
- .amux = TM6000_AMUX_ADC2,
- }, {
- .type = TM6000_INPUT_SVIDEO,
- .vmux = TM6000_VMUX_VIDEO_AB,
- .amux = TM6000_AMUX_ADC2,
- },
- },
- },
- [TM6010_BOARD_BEHOLD_WANDER_LITE] = {
- .name = "Beholder Wander Lite DVB-T/TV/FM USB2.0",
- .tuner_type = TUNER_XC5000,
- .tuner_addr = 0xc2 >> 1,
- .demod_addr = 0x1e >> 1,
- .type = TM6010,
- .caps = {
- .has_tuner = 1,
- .has_dvb = 1,
- .has_zl10353 = 1,
- .has_eeprom = 1,
- .has_remote = 0,
- .has_radio = 1,
- },
- .gpio = {
- .tuner_reset = TM6010_GPIO_0,
- .demod_reset = TM6010_GPIO_1,
- .power_led = TM6010_GPIO_6,
- },
- .vinput = { {
- .type = TM6000_INPUT_TV,
- .vmux = TM6000_VMUX_VIDEO_B,
- .amux = TM6000_AMUX_SIF1,
- },
- },
- .rinput = {
- .type = TM6000_INPUT_RADIO,
- .amux = TM6000_AMUX_ADC1,
- },
- },
- [TM6010_BOARD_BEHOLD_VOYAGER_LITE] = {
- .name = "Beholder Voyager Lite TV/FM USB2.0",
- .tuner_type = TUNER_XC5000,
- .tuner_addr = 0xc2 >> 1,
- .type = TM6010,
- .caps = {
- .has_tuner = 1,
- .has_dvb = 0,
- .has_zl10353 = 0,
- .has_eeprom = 1,
- .has_remote = 0,
- .has_radio = 1,
- },
- .gpio = {
- .tuner_reset = TM6010_GPIO_0,
- .power_led = TM6010_GPIO_6,
- },
- .vinput = { {
- .type = TM6000_INPUT_TV,
- .vmux = TM6000_VMUX_VIDEO_B,
- .amux = TM6000_AMUX_SIF1,
- },
- },
- .rinput = {
- .type = TM6000_INPUT_RADIO,
- .amux = TM6000_AMUX_ADC1,
- },
- },
-};
-
-/* table of devices that work with this driver */
-static const struct usb_device_id tm6000_id_table[] = {
- { USB_DEVICE(0x6000, 0x0001), .driver_info = TM5600_BOARD_GENERIC },
- { USB_DEVICE(0x6000, 0x0002), .driver_info = TM6010_BOARD_GENERIC },
- { USB_DEVICE(0x06e1, 0xf332), .driver_info = TM6000_BOARD_ADSTECH_DUAL_TV },
- { USB_DEVICE(0x14aa, 0x0620), .driver_info = TM6000_BOARD_FREECOM_AND_SIMILAR },
- { USB_DEVICE(0x06e1, 0xb339), .driver_info = TM6000_BOARD_ADSTECH_MINI_DUAL_TV },
- { USB_DEVICE(0x2040, 0x6600), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
- { USB_DEVICE(0x2040, 0x6601), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
- { USB_DEVICE(0x2040, 0x6610), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
- { USB_DEVICE(0x2040, 0x6611), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
- { USB_DEVICE(0x6000, 0xdec0), .driver_info = TM6010_BOARD_BEHOLD_WANDER },
- { USB_DEVICE(0x6000, 0xdec1), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER },
- { USB_DEVICE(0x0ccd, 0x0086), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE },
- { USB_DEVICE(0x0ccd, 0x00A5), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE },
- { USB_DEVICE(0x0ccd, 0x0079), .driver_info = TM5600_BOARD_TERRATEC_GRABSTER },
- { USB_DEVICE(0x13d3, 0x3240), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
- { USB_DEVICE(0x13d3, 0x3241), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
- { USB_DEVICE(0x13d3, 0x3243), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
- { USB_DEVICE(0x13d3, 0x3264), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
- { USB_DEVICE(0x6000, 0xdec2), .driver_info = TM6010_BOARD_BEHOLD_WANDER_LITE },
- { USB_DEVICE(0x6000, 0xdec3), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER_LITE },
- { }
-};
-MODULE_DEVICE_TABLE(usb, tm6000_id_table);
-
-/* Control power led for show some activity */
-void tm6000_flash_led(struct tm6000_core *dev, u8 state)
-{
- /* Power LED unconfigured */
- if (!dev->gpio.power_led)
- return;
-
- /* ON Power LED */
- if (state) {
- switch (dev->model) {
- case TM6010_BOARD_HAUPPAUGE_900H:
- case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
- case TM6010_BOARD_TWINHAN_TU501:
- tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
- dev->gpio.power_led, 0x00);
- break;
- case TM6010_BOARD_BEHOLD_WANDER:
- case TM6010_BOARD_BEHOLD_VOYAGER:
- case TM6010_BOARD_BEHOLD_WANDER_LITE:
- case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
- tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
- dev->gpio.power_led, 0x01);
- break;
- }
- }
- /* OFF Power LED */
- else {
- switch (dev->model) {
- case TM6010_BOARD_HAUPPAUGE_900H:
- case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
- case TM6010_BOARD_TWINHAN_TU501:
- tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
- dev->gpio.power_led, 0x01);
- break;
- case TM6010_BOARD_BEHOLD_WANDER:
- case TM6010_BOARD_BEHOLD_VOYAGER:
- case TM6010_BOARD_BEHOLD_WANDER_LITE:
- case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
- tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
- dev->gpio.power_led, 0x00);
- break;
- }
- }
-}
-
-/* Tuner callback to provide the proper gpio changes needed for xc5000 */
-int tm6000_xc5000_callback(void *ptr, int component, int command, int arg)
-{
- int rc = 0;
- struct tm6000_core *dev = ptr;
-
- if (dev->tuner_type != TUNER_XC5000)
- return 0;
-
- switch (command) {
- case XC5000_TUNER_RESET:
- tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
- dev->gpio.tuner_reset, 0x01);
- msleep(15);
- tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
- dev->gpio.tuner_reset, 0x00);
- msleep(15);
- tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
- dev->gpio.tuner_reset, 0x01);
- break;
- }
- return rc;
-}
-EXPORT_SYMBOL_GPL(tm6000_xc5000_callback);
-
-/* Tuner callback to provide the proper gpio changes needed for xc2028 */
-
-int tm6000_tuner_callback(void *ptr, int component, int command, int arg)
-{
- int rc = 0;
- struct tm6000_core *dev = ptr;
-
- if (dev->tuner_type != TUNER_XC2028)
- return 0;
-
- switch (command) {
- case XC2028_RESET_CLK:
- tm6000_ir_wait(dev, 0);
-
- tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT,
- 0x02, arg);
- msleep(10);
- rc = tm6000_i2c_reset(dev, 10);
- break;
- case XC2028_TUNER_RESET:
- /* Reset codes during load firmware */
- switch (arg) {
- case 0:
- /* newer tuner can faster reset */
- switch (dev->model) {
- case TM5600_BOARD_10MOONS_UT821:
- tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
- dev->gpio.tuner_reset, 0x01);
- tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
- 0x300, 0x01);
- msleep(10);
- tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
- dev->gpio.tuner_reset, 0x00);
- tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
- 0x300, 0x00);
- msleep(10);
- tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
- dev->gpio.tuner_reset, 0x01);
- tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
- 0x300, 0x01);
- break;
- case TM6010_BOARD_HAUPPAUGE_900H:
- case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
- case TM6010_BOARD_TWINHAN_TU501:
- tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
- dev->gpio.tuner_reset, 0x01);
- msleep(60);
- tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
- dev->gpio.tuner_reset, 0x00);
- msleep(75);
- tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
- dev->gpio.tuner_reset, 0x01);
- msleep(60);
- break;
- default:
- tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
- dev->gpio.tuner_reset, 0x00);
- msleep(130);
- tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
- dev->gpio.tuner_reset, 0x01);
- msleep(130);
- break;
- }
-
- tm6000_ir_wait(dev, 1);
- break;
- case 1:
- tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT,
- 0x02, 0x01);
- msleep(10);
- break;
- case 2:
- rc = tm6000_i2c_reset(dev, 100);
- break;
- }
- break;
- case XC2028_I2C_FLUSH:
- tm6000_set_reg(dev, REQ_50_SET_START, 0, 0);
- tm6000_set_reg(dev, REQ_51_SET_STOP, 0, 0);
- break;
- }
- return rc;
-}
-EXPORT_SYMBOL_GPL(tm6000_tuner_callback);
-
-int tm6000_cards_setup(struct tm6000_core *dev)
-{
- /*
- * Board-specific initialization sequence. Handles all GPIO
- * initialization sequences that are board-specific.
- * Up to now, all found devices use GPIO1 and GPIO4 at the same way.
- * Probably, they're all based on some reference device. Due to that,
- * there's a common routine at the end to handle those GPIO's. Devices
- * that use different pinups or init sequences can just return at
- * the board-specific session.
- */
- switch (dev->model) {
- case TM6010_BOARD_HAUPPAUGE_900H:
- case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
- case TM6010_BOARD_TWINHAN_TU501:
- case TM6010_BOARD_GENERIC:
- /* Turn xceive 3028 on */
- tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.tuner_on, 0x01);
- msleep(15);
- /* Turn zarlink zl10353 on */
- tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00);
- msleep(15);
- /* Reset zarlink zl10353 */
- tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00);
- msleep(50);
- tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01);
- msleep(15);
- /* Turn zarlink zl10353 off */
- tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x01);
- msleep(15);
- /* ir ? */
- tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.ir, 0x01);
- msleep(15);
- /* Power led on (blue) */
- tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x00);
- msleep(15);
- /* DVB led off (orange) */
- tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.dvb_led, 0x01);
- msleep(15);
- /* Turn zarlink zl10353 on */
- tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00);
- msleep(15);
- break;
- case TM6010_BOARD_BEHOLD_WANDER:
- case TM6010_BOARD_BEHOLD_WANDER_LITE:
- /* Power led on (blue) */
- tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01);
- msleep(15);
- /* Reset zarlink zl10353 */
- tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00);
- msleep(50);
- tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01);
- msleep(15);
- break;
- case TM6010_BOARD_BEHOLD_VOYAGER:
- case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
- /* Power led on (blue) */
- tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01);
- msleep(15);
- break;
- default:
- break;
- }
-
- /*
- * Default initialization. Most of the devices seem to use GPIO1
- * and GPIO4.on the same way, so, this handles the common sequence
- * used by most devices.
- * If a device uses a different sequence or different GPIO pins for
- * reset, just add the code at the board-specific part
- */
-
- if (dev->gpio.tuner_reset) {
- int rc;
- int i;
-
- for (i = 0; i < 2; i++) {
- rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
- dev->gpio.tuner_reset, 0x00);
- if (rc < 0) {
- printk(KERN_ERR "Error %i doing tuner reset\n", rc);
- return rc;
- }
-
- msleep(10); /* Just to be conservative */
- rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
- dev->gpio.tuner_reset, 0x01);
- if (rc < 0) {
- printk(KERN_ERR "Error %i doing tuner reset\n", rc);
- return rc;
- }
- }
- } else {
- printk(KERN_ERR "Tuner reset is not configured\n");
- return -1;
- }
-
- msleep(50);
-
- return 0;
-};
-
-static void tm6000_config_tuner(struct tm6000_core *dev)
-{
- struct tuner_setup tun_setup;
-
- /* Load tuner module */
- v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- "tuner", dev->tuner_addr, NULL);
-
- memset(&tun_setup, 0, sizeof(tun_setup));
- tun_setup.type = dev->tuner_type;
- tun_setup.addr = dev->tuner_addr;
-
- tun_setup.mode_mask = 0;
- if (dev->caps.has_tuner)
- tun_setup.mode_mask |= (T_ANALOG_TV | T_RADIO);
-
- switch (dev->tuner_type) {
- case TUNER_XC2028:
- tun_setup.tuner_callback = tm6000_tuner_callback;
- break;
- case TUNER_XC5000:
- tun_setup.tuner_callback = tm6000_xc5000_callback;
- break;
- }
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
-
- switch (dev->tuner_type) {
- case TUNER_XC2028: {
- struct v4l2_priv_tun_config xc2028_cfg;
- struct xc2028_ctrl ctl;
-
- memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
- memset(&ctl, 0, sizeof(ctl));
-
- ctl.demod = XC3028_FE_ZARLINK456;
-
- xc2028_cfg.tuner = TUNER_XC2028;
- xc2028_cfg.priv = &ctl;
-
- switch (dev->model) {
- case TM6010_BOARD_HAUPPAUGE_900H:
- case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
- case TM6010_BOARD_TWINHAN_TU501:
- ctl.max_len = 80;
- ctl.fname = "xc3028L-v36.fw";
- break;
- default:
- if (dev->dev_type == TM6010)
- ctl.fname = "xc3028-v27.fw";
- else
- ctl.fname = "xc3028-v24.fw";
- }
-
- printk(KERN_INFO "Setting firmware parameters for xc2028\n");
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config,
- &xc2028_cfg);
-
- }
- break;
- case TUNER_XC5000:
- {
- struct v4l2_priv_tun_config xc5000_cfg;
- struct xc5000_config ctl = {
- .i2c_address = dev->tuner_addr,
- .if_khz = 4570,
- .radio_input = XC5000_RADIO_FM1_MONO,
- };
-
- xc5000_cfg.tuner = TUNER_XC5000;
- xc5000_cfg.priv = &ctl;
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config,
- &xc5000_cfg);
- }
- break;
- default:
- printk(KERN_INFO "Unknown tuner type. Tuner is not configured.\n");
- break;
- }
-}
-
-static int fill_board_specific_data(struct tm6000_core *dev)
-{
- int rc;
-
- dev->dev_type = tm6000_boards[dev->model].type;
- dev->tuner_type = tm6000_boards[dev->model].tuner_type;
- dev->tuner_addr = tm6000_boards[dev->model].tuner_addr;
-
- dev->gpio = tm6000_boards[dev->model].gpio;
-
- dev->ir_codes = tm6000_boards[dev->model].ir_codes;
-
- dev->demod_addr = tm6000_boards[dev->model].demod_addr;
-
- dev->caps = tm6000_boards[dev->model].caps;
-
- dev->vinput[0] = tm6000_boards[dev->model].vinput[0];
- dev->vinput[1] = tm6000_boards[dev->model].vinput[1];
- dev->vinput[2] = tm6000_boards[dev->model].vinput[2];
- dev->rinput = tm6000_boards[dev->model].rinput;
-
- /* setup per-model quirks */
- switch (dev->model) {
- case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
- case TM6010_BOARD_HAUPPAUGE_900H:
- dev->quirks |= TM6000_QUIRK_NO_USB_DELAY;
- break;
-
- default:
- break;
- }
-
- /* initialize hardware */
- rc = tm6000_init(dev);
- if (rc < 0)
- return rc;
-
- return v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
-}
-
-
-static void use_alternative_detection_method(struct tm6000_core *dev)
-{
- int i, model = -1;
-
- if (!dev->eedata_size)
- return;
-
- for (i = 0; i < ARRAY_SIZE(tm6000_boards); i++) {
- if (!tm6000_boards[i].eename_size)
- continue;
- if (dev->eedata_size < tm6000_boards[i].eename_pos +
- tm6000_boards[i].eename_size)
- continue;
-
- if (!memcmp(&dev->eedata[tm6000_boards[i].eename_pos],
- tm6000_boards[i].eename,
- tm6000_boards[i].eename_size)) {
- model = i;
- break;
- }
- }
- if (model < 0) {
- printk(KERN_INFO "Device has eeprom but is currently unknown\n");
- return;
- }
-
- dev->model = model;
-
- printk(KERN_INFO "Device identified via eeprom as %s (type = %d)\n",
- tm6000_boards[model].name, model);
-}
-
-#if defined(CONFIG_MODULES) && defined(MODULE)
-static void request_module_async(struct work_struct *work)
-{
- struct tm6000_core *dev = container_of(work, struct tm6000_core,
- request_module_wk);
-
- request_module("tm6000-alsa");
-
- if (dev->caps.has_dvb)
- request_module("tm6000-dvb");
-}
-
-static void request_modules(struct tm6000_core *dev)
-{
- INIT_WORK(&dev->request_module_wk, request_module_async);
- schedule_work(&dev->request_module_wk);
-}
-
-static void flush_request_modules(struct tm6000_core *dev)
-{
- flush_work(&dev->request_module_wk);
-}
-#else
-#define request_modules(dev)
-#define flush_request_modules(dev)
-#endif /* CONFIG_MODULES */
-
-static int tm6000_init_dev(struct tm6000_core *dev)
-{
- struct v4l2_frequency f;
- int rc = 0;
-
- mutex_init(&dev->lock);
- mutex_lock(&dev->lock);
-
- if (!is_generic(dev->model)) {
- rc = fill_board_specific_data(dev);
- if (rc < 0)
- goto err;
-
- /* register i2c bus */
- rc = tm6000_i2c_register(dev);
- if (rc < 0)
- goto err;
- } else {
- /* register i2c bus */
- rc = tm6000_i2c_register(dev);
- if (rc < 0)
- goto err;
-
- use_alternative_detection_method(dev);
-
- rc = fill_board_specific_data(dev);
- if (rc < 0)
- goto err;
- }
-
- /* Default values for STD and resolutions */
- dev->width = 720;
- dev->height = 480;
- dev->norm = V4L2_STD_NTSC_M;
-
- /* Configure tuner */
- tm6000_config_tuner(dev);
-
- /* Set video standard */
- v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std, dev->norm);
-
- /* Set tuner frequency - also loads firmware on xc2028/xc3028 */
- f.tuner = 0;
- f.type = V4L2_TUNER_ANALOG_TV;
- f.frequency = 3092; /* 193.25 MHz */
- dev->freq = f.frequency;
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
-
- if (dev->caps.has_tda9874)
- v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- "tvaudio", I2C_ADDR_TDA9874, NULL);
-
- /* register and initialize V4L2 */
- rc = tm6000_v4l2_register(dev);
- if (rc < 0)
- goto err;
-
- tm6000_add_into_devlist(dev);
- tm6000_init_extension(dev);
-
- tm6000_ir_init(dev);
-
- request_modules(dev);
-
- mutex_unlock(&dev->lock);
- return 0;
-
-err:
- mutex_unlock(&dev->lock);
- return rc;
-}
-
-/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
-#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
-
-static void get_max_endpoint(struct usb_device *udev,
- struct usb_host_interface *alt,
- char *msgtype,
- struct usb_host_endpoint *curr_e,
- struct tm6000_endpoint *tm_ep)
-{
- u16 tmp = le16_to_cpu(curr_e->desc.wMaxPacketSize);
- unsigned int size = tmp & 0x7ff;
-
- if (udev->speed == USB_SPEED_HIGH)
- size = size * hb_mult(tmp);
-
- if (size > tm_ep->maxsize) {
- tm_ep->endp = curr_e;
- tm_ep->maxsize = size;
- tm_ep->bInterfaceNumber = alt->desc.bInterfaceNumber;
- tm_ep->bAlternateSetting = alt->desc.bAlternateSetting;
-
- printk(KERN_INFO "tm6000: %s endpoint: 0x%02x (max size=%u bytes)\n",
- msgtype, curr_e->desc.bEndpointAddress,
- size);
- }
-}
-
-/*
- * tm6000_usb_probe()
- * checks for supported devices
- */
-static int tm6000_usb_probe(struct usb_interface *interface,
- const struct usb_device_id *id)
-{
- struct usb_device *usbdev;
- struct tm6000_core *dev;
- int i, rc;
- int nr = 0;
- char *speed;
-
- usbdev = usb_get_dev(interface_to_usbdev(interface));
-
- /* Selects the proper interface */
- rc = usb_set_interface(usbdev, 0, 1);
- if (rc < 0)
- goto report_failure;
-
- /* Check to see next free device and mark as used */
- nr = find_first_zero_bit(&tm6000_devused, TM6000_MAXBOARDS);
- if (nr >= TM6000_MAXBOARDS) {
- printk(KERN_ERR "tm6000: Supports only %i tm60xx boards.\n", TM6000_MAXBOARDS);
- rc = -ENOMEM;
- goto put_device;
- }
-
- /* Create and initialize dev struct */
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (!dev) {
- rc = -ENOMEM;
- goto put_device;
- }
- spin_lock_init(&dev->slock);
- mutex_init(&dev->usb_lock);
-
- /* Increment usage count */
- set_bit(nr, &tm6000_devused);
- snprintf(dev->name, 29, "tm6000 #%d", nr);
-
- dev->model = id->driver_info;
- if (card[nr] < ARRAY_SIZE(tm6000_boards))
- dev->model = card[nr];
-
- dev->udev = usbdev;
- dev->devno = nr;
-
- switch (usbdev->speed) {
- case USB_SPEED_LOW:
- speed = "1.5";
- break;
- case USB_SPEED_UNKNOWN:
- case USB_SPEED_FULL:
- speed = "12";
- break;
- case USB_SPEED_HIGH:
- speed = "480";
- break;
- default:
- speed = "unknown";
- }
-
- /* Get endpoints */
- for (i = 0; i < interface->num_altsetting; i++) {
- int ep;
-
- for (ep = 0; ep < interface->altsetting[i].desc.bNumEndpoints; ep++) {
- struct usb_host_endpoint *e;
- int dir_out;
-
- e = &interface->altsetting[i].endpoint[ep];
-
- dir_out = ((e->desc.bEndpointAddress &
- USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT);
-
- printk(KERN_INFO "tm6000: alt %d, interface %i, class %i\n",
- i,
- interface->altsetting[i].desc.bInterfaceNumber,
- interface->altsetting[i].desc.bInterfaceClass);
-
- switch (e->desc.bmAttributes) {
- case USB_ENDPOINT_XFER_BULK:
- if (!dir_out) {
- get_max_endpoint(usbdev,
- &interface->altsetting[i],
- "Bulk IN", e,
- &dev->bulk_in);
- } else {
- get_max_endpoint(usbdev,
- &interface->altsetting[i],
- "Bulk OUT", e,
- &dev->bulk_out);
- }
- break;
- case USB_ENDPOINT_XFER_ISOC:
- if (!dir_out) {
- get_max_endpoint(usbdev,
- &interface->altsetting[i],
- "ISOC IN", e,
- &dev->isoc_in);
- } else {
- get_max_endpoint(usbdev,
- &interface->altsetting[i],
- "ISOC OUT", e,
- &dev->isoc_out);
- }
- break;
- case USB_ENDPOINT_XFER_INT:
- if (!dir_out) {
- get_max_endpoint(usbdev,
- &interface->altsetting[i],
- "INT IN", e,
- &dev->int_in);
- } else {
- get_max_endpoint(usbdev,
- &interface->altsetting[i],
- "INT OUT", e,
- &dev->int_out);
- }
- break;
- }
- }
- }
-
-
- printk(KERN_INFO "tm6000: New video device @ %s Mbps (%04x:%04x, ifnum %d)\n",
- speed,
- le16_to_cpu(dev->udev->descriptor.idVendor),
- le16_to_cpu(dev->udev->descriptor.idProduct),
- interface->altsetting->desc.bInterfaceNumber);
-
-/* check if the the device has the iso in endpoint at the correct place */
- if (!dev->isoc_in.endp) {
- printk(KERN_ERR "tm6000: probing error: no IN ISOC endpoint!\n");
- rc = -ENODEV;
- goto free_device;
- }
-
- /* save our data pointer in this interface device */
- usb_set_intfdata(interface, dev);
-
- printk(KERN_INFO "tm6000: Found %s\n", tm6000_boards[dev->model].name);
-
- rc = tm6000_init_dev(dev);
- if (rc < 0)
- goto free_device;
-
- return 0;
-
-free_device:
- kfree(dev);
-report_failure:
- printk(KERN_ERR "tm6000: Error %d while registering\n", rc);
-
- clear_bit(nr, &tm6000_devused);
-put_device:
- usb_put_dev(usbdev);
- return rc;
-}
-
-/*
- * tm6000_usb_disconnect()
- * called when the device gets disconnected
- * video device will be unregistered on v4l2_close in case it is still open
- */
-static void tm6000_usb_disconnect(struct usb_interface *interface)
-{
- struct tm6000_core *dev = usb_get_intfdata(interface);
- usb_set_intfdata(interface, NULL);
-
- if (!dev)
- return;
-
- printk(KERN_INFO "tm6000: disconnecting %s\n", dev->name);
-
- flush_request_modules(dev);
-
- tm6000_ir_fini(dev);
-
- if (dev->gpio.power_led) {
- switch (dev->model) {
- case TM6010_BOARD_HAUPPAUGE_900H:
- case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
- case TM6010_BOARD_TWINHAN_TU501:
- /* Power led off */
- tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
- dev->gpio.power_led, 0x01);
- msleep(15);
- break;
- case TM6010_BOARD_BEHOLD_WANDER:
- case TM6010_BOARD_BEHOLD_VOYAGER:
- case TM6010_BOARD_BEHOLD_WANDER_LITE:
- case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
- /* Power led off */
- tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
- dev->gpio.power_led, 0x00);
- msleep(15);
- break;
- }
- }
- tm6000_v4l2_unregister(dev);
-
- tm6000_i2c_unregister(dev);
-
- v4l2_device_unregister(&dev->v4l2_dev);
-
- dev->state |= DEV_DISCONNECTED;
-
- usb_put_dev(dev->udev);
-
- tm6000_close_extension(dev);
- tm6000_remove_from_devlist(dev);
-
- clear_bit(dev->devno, &tm6000_devused);
- kfree(dev);
-}
-
-static struct usb_driver tm6000_usb_driver = {
- .name = "tm6000",
- .probe = tm6000_usb_probe,
- .disconnect = tm6000_usb_disconnect,
- .id_table = tm6000_id_table,
-};
-
-module_usb_driver(tm6000_usb_driver);
-
-MODULE_DESCRIPTION("Trident TVMaster TM5600/TM6000/TM6010 USB2 adapter");
-MODULE_AUTHOR("Mauro Carvalho Chehab");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/media/deprecated/tm6000/tm6000-core.c b/drivers/staging/media/deprecated/tm6000/tm6000-core.c
deleted file mode 100644
index 5c8cbc5d6f72..000000000000
--- a/drivers/staging/media/deprecated/tm6000/tm6000-core.c
+++ /dev/null
@@ -1,916 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-// tm6000-core.c - driver for TM5600/TM6000/TM6010 USB video capture devices
-//
-// Copyright (c) 2006-2007 Mauro Carvalho Chehab <mchehab@kernel.org>
-//
-// Copyright (c) 2007 Michel Ludwig <michel.ludwig@gmail.com>
-// - DVB-T support
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include <linux/i2c.h>
-#include "tm6000.h"
-#include "tm6000-regs.h"
-#include <media/v4l2-common.h>
-#include <media/tuner.h>
-
-#define USB_TIMEOUT (5 * HZ) /* ms */
-
-int tm6000_read_write_usb(struct tm6000_core *dev, u8 req_type, u8 req,
- u16 value, u16 index, u8 *buf, u16 len)
-{
- int ret, i;
- unsigned int pipe;
- u8 *data = NULL;
- int delay = 5000;
-
- if (len) {
- data = kzalloc(len, GFP_KERNEL);
- if (!data)
- return -ENOMEM;
- }
-
- mutex_lock(&dev->usb_lock);
-
- if (req_type & USB_DIR_IN)
- pipe = usb_rcvctrlpipe(dev->udev, 0);
- else {
- pipe = usb_sndctrlpipe(dev->udev, 0);
- memcpy(data, buf, len);
- }
-
- if (tm6000_debug & V4L2_DEBUG_I2C) {
- printk(KERN_DEBUG "(dev %p, pipe %08x): ", dev->udev, pipe);
-
- printk(KERN_CONT "%s: %02x %02x %02x %02x %02x %02x %02x %02x ",
- (req_type & USB_DIR_IN) ? " IN" : "OUT",
- req_type, req, value&0xff, value>>8, index&0xff,
- index>>8, len&0xff, len>>8);
-
- if (!(req_type & USB_DIR_IN)) {
- printk(KERN_CONT ">>> ");
- for (i = 0; i < len; i++)
- printk(KERN_CONT " %02x", buf[i]);
- printk(KERN_CONT "\n");
- }
- }
-
- ret = usb_control_msg(dev->udev, pipe, req, req_type, value, index,
- data, len, USB_TIMEOUT);
-
- if (req_type & USB_DIR_IN)
- memcpy(buf, data, len);
-
- if (tm6000_debug & V4L2_DEBUG_I2C) {
- if (ret < 0) {
- if (req_type & USB_DIR_IN)
- printk(KERN_DEBUG "<<< (len=%d)\n", len);
-
- printk(KERN_CONT "%s: Error #%d\n", __func__, ret);
- } else if (req_type & USB_DIR_IN) {
- printk(KERN_CONT "<<< ");
- for (i = 0; i < len; i++)
- printk(KERN_CONT " %02x", buf[i]);
- printk(KERN_CONT "\n");
- }
- }
-
- kfree(data);
-
- if (dev->quirks & TM6000_QUIRK_NO_USB_DELAY)
- delay = 0;
-
- if (req == REQ_16_SET_GET_I2C_WR1_RDN && !(req_type & USB_DIR_IN)) {
- unsigned int tsleep;
- /* Calculate delay time, 14000us for 64 bytes */
- tsleep = (len * 200) + 200;
- if (tsleep < delay)
- tsleep = delay;
- usleep_range(tsleep, tsleep + 1000);
- }
- else if (delay)
- usleep_range(delay, delay + 1000);
-
- mutex_unlock(&dev->usb_lock);
- return ret;
-}
-
-int tm6000_set_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index)
-{
- return
- tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR,
- req, value, index, NULL, 0);
-}
-EXPORT_SYMBOL_GPL(tm6000_set_reg);
-
-int tm6000_get_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index)
-{
- int rc;
- u8 buf[1];
-
- rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
- value, index, buf, 1);
-
- if (rc < 0)
- return rc;
-
- return *buf;
-}
-EXPORT_SYMBOL_GPL(tm6000_get_reg);
-
-int tm6000_set_reg_mask(struct tm6000_core *dev, u8 req, u16 value,
- u16 index, u16 mask)
-{
- int rc;
- u8 buf[1];
- u8 new_index;
-
- rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
- value, 0, buf, 1);
-
- if (rc < 0)
- return rc;
-
- new_index = (buf[0] & ~mask) | (index & mask);
-
- if (new_index == buf[0])
- return 0;
-
- return tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR,
- req, value, new_index, NULL, 0);
-}
-EXPORT_SYMBOL_GPL(tm6000_set_reg_mask);
-
-int tm6000_get_reg16(struct tm6000_core *dev, u8 req, u16 value, u16 index)
-{
- int rc;
- u8 buf[2];
-
- rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
- value, index, buf, 2);
-
- if (rc < 0)
- return rc;
-
- return buf[1]|buf[0]<<8;
-}
-
-int tm6000_get_reg32(struct tm6000_core *dev, u8 req, u16 value, u16 index)
-{
- int rc;
- u8 buf[4];
-
- rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
- value, index, buf, 4);
-
- if (rc < 0)
- return rc;
-
- return buf[3] | buf[2] << 8 | buf[1] << 16 | buf[0] << 24;
-}
-
-int tm6000_i2c_reset(struct tm6000_core *dev, u16 tsleep)
-{
- int rc;
-
- rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_CLK, 0);
- if (rc < 0)
- return rc;
-
- msleep(tsleep);
-
- rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_CLK, 1);
- msleep(tsleep);
-
- return rc;
-}
-
-void tm6000_set_fourcc_format(struct tm6000_core *dev)
-{
- if (dev->dev_type == TM6010) {
- int val;
-
- val = tm6000_get_reg(dev, TM6010_REQ07_RCC_ACTIVE_IF, 0) & 0xfc;
- if (dev->fourcc == V4L2_PIX_FMT_UYVY)
- tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_IF, val);
- else
- tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_IF, val | 1);
- } else {
- if (dev->fourcc == V4L2_PIX_FMT_UYVY)
- tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0xd0);
- else
- tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0x90);
- }
-}
-
-static void tm6000_set_vbi(struct tm6000_core *dev)
-{
- /*
- * FIXME:
- * VBI lines and start/end are different between 60Hz and 50Hz
- * So, it is very likely that we need to change the config to
- * something that takes it into account, doing something different
- * if (dev->norm & V4L2_STD_525_60)
- */
-
- if (dev->dev_type == TM6010) {
- tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01);
- tm6000_set_reg(dev, TM6010_REQ07_R41_TELETEXT_VBI_CODE1, 0x27);
- tm6000_set_reg(dev, TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL, 0x55);
- tm6000_set_reg(dev, TM6010_REQ07_R43_VBI_DATA_TYPE_LINE7, 0x66);
- tm6000_set_reg(dev, TM6010_REQ07_R44_VBI_DATA_TYPE_LINE8, 0x66);
- tm6000_set_reg(dev, TM6010_REQ07_R45_VBI_DATA_TYPE_LINE9, 0x66);
- tm6000_set_reg(dev,
- TM6010_REQ07_R46_VBI_DATA_TYPE_LINE10, 0x66);
- tm6000_set_reg(dev,
- TM6010_REQ07_R47_VBI_DATA_TYPE_LINE11, 0x66);
- tm6000_set_reg(dev,
- TM6010_REQ07_R48_VBI_DATA_TYPE_LINE12, 0x66);
- tm6000_set_reg(dev,
- TM6010_REQ07_R49_VBI_DATA_TYPE_LINE13, 0x66);
- tm6000_set_reg(dev,
- TM6010_REQ07_R4A_VBI_DATA_TYPE_LINE14, 0x66);
- tm6000_set_reg(dev,
- TM6010_REQ07_R4B_VBI_DATA_TYPE_LINE15, 0x66);
- tm6000_set_reg(dev,
- TM6010_REQ07_R4C_VBI_DATA_TYPE_LINE16, 0x66);
- tm6000_set_reg(dev,
- TM6010_REQ07_R4D_VBI_DATA_TYPE_LINE17, 0x66);
- tm6000_set_reg(dev,
- TM6010_REQ07_R4E_VBI_DATA_TYPE_LINE18, 0x66);
- tm6000_set_reg(dev,
- TM6010_REQ07_R4F_VBI_DATA_TYPE_LINE19, 0x66);
- tm6000_set_reg(dev,
- TM6010_REQ07_R50_VBI_DATA_TYPE_LINE20, 0x66);
- tm6000_set_reg(dev,
- TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21, 0x66);
- tm6000_set_reg(dev,
- TM6010_REQ07_R52_VBI_DATA_TYPE_LINE22, 0x66);
- tm6000_set_reg(dev,
- TM6010_REQ07_R53_VBI_DATA_TYPE_LINE23, 0x00);
- tm6000_set_reg(dev,
- TM6010_REQ07_R54_VBI_DATA_TYPE_RLINES, 0x00);
- tm6000_set_reg(dev,
- TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN, 0x01);
- tm6000_set_reg(dev,
- TM6010_REQ07_R56_VBI_LOOP_FILTER_I_GAIN, 0x00);
- tm6000_set_reg(dev,
- TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN, 0x02);
- tm6000_set_reg(dev, TM6010_REQ07_R58_VBI_CAPTION_DTO1, 0x35);
- tm6000_set_reg(dev, TM6010_REQ07_R59_VBI_CAPTION_DTO0, 0xa0);
- tm6000_set_reg(dev, TM6010_REQ07_R5A_VBI_TELETEXT_DTO1, 0x11);
- tm6000_set_reg(dev, TM6010_REQ07_R5B_VBI_TELETEXT_DTO0, 0x4c);
- tm6000_set_reg(dev, TM6010_REQ07_R40_TELETEXT_VBI_CODE0, 0x01);
- tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x00);
- }
-}
-
-int tm6000_init_analog_mode(struct tm6000_core *dev)
-{
- struct v4l2_frequency f;
-
- if (dev->dev_type == TM6010) {
- u8 active = TM6010_REQ07_RCC_ACTIVE_IF_AUDIO_ENABLE;
-
- if (!dev->radio)
- active |= TM6010_REQ07_RCC_ACTIVE_IF_VIDEO_ENABLE;
-
- /* Enable video and audio */
- tm6000_set_reg_mask(dev, TM6010_REQ07_RCC_ACTIVE_IF,
- active, 0x60);
- /* Disable TS input */
- tm6000_set_reg_mask(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE,
- 0x00, 0x40);
- } else {
- /* Enables soft reset */
- tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01);
-
- if (dev->scaler)
- /* Disable Hfilter and Enable TS Drop err */
- tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x20);
- else /* Enable Hfilter and disable TS Drop err */
- tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x80);
-
- tm6000_set_reg(dev, TM6010_REQ07_RC3_HSTART1, 0x88);
- tm6000_set_reg(dev, TM6000_REQ07_RDA_CLK_SEL, 0x23);
- tm6000_set_reg(dev, TM6010_REQ07_RD1_ADDR_FOR_REQ1, 0xc0);
- tm6000_set_reg(dev, TM6010_REQ07_RD2_ADDR_FOR_REQ2, 0xd8);
- tm6000_set_reg(dev, TM6010_REQ07_RD6_ENDP_REQ1_REQ2, 0x06);
- tm6000_set_reg(dev, TM6000_REQ07_RDF_PWDOWN_ACLK, 0x1f);
-
- /* AP Software reset */
- tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x08);
- tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x00);
-
- tm6000_set_fourcc_format(dev);
-
- /* Disables soft reset */
- tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x00);
- }
- msleep(20);
-
- /* Tuner firmware can now be loaded */
-
- /*
- * FIXME: This is a hack! xc3028 "sleeps" when no channel is detected
- * for more than a few seconds. Not sure why, as this behavior does
- * not happen on other devices with xc3028. So, I suspect that it
- * is yet another bug at tm6000. After start sleeping, decoding
- * doesn't start automatically. Instead, it requires some
- * I2C commands to wake it up. As we want to have image at the
- * beginning, we needed to add this hack. The better would be to
- * discover some way to make tm6000 to wake up without this hack.
- */
- f.frequency = dev->freq;
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
-
- msleep(100);
- tm6000_set_standard(dev);
- tm6000_set_vbi(dev);
- tm6000_set_audio_bitrate(dev, 48000);
-
- /* switch dvb led off */
- if (dev->gpio.dvb_led) {
- tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
- dev->gpio.dvb_led, 0x01);
- }
-
- return 0;
-}
-
-int tm6000_init_digital_mode(struct tm6000_core *dev)
-{
- if (dev->dev_type == TM6010) {
- /* Disable video and audio */
- tm6000_set_reg_mask(dev, TM6010_REQ07_RCC_ACTIVE_IF,
- 0x00, 0x60);
- /* Enable TS input */
- tm6000_set_reg_mask(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE,
- 0x40, 0x40);
- /* all power down, but not the digital data port */
- tm6000_set_reg(dev, TM6010_REQ07_RFE_POWER_DOWN, 0x28);
- tm6000_set_reg(dev, TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xfc);
- tm6000_set_reg(dev, TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0xff);
- } else {
- tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x08);
- tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x00);
- tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01);
- tm6000_set_reg(dev, TM6000_REQ07_RDF_PWDOWN_ACLK, 0x08);
- tm6000_set_reg(dev, TM6000_REQ07_RE2_VADC_STATUS_CTL, 0x0c);
- tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0xff);
- tm6000_set_reg(dev, TM6000_REQ07_REB_VADC_AADC_MODE, 0xd8);
- tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x40);
- tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0xd0);
- tm6000_set_reg(dev, TM6010_REQ07_RC3_HSTART1, 0x09);
- tm6000_set_reg(dev, TM6000_REQ07_RDA_CLK_SEL, 0x37);
- tm6000_set_reg(dev, TM6010_REQ07_RD1_ADDR_FOR_REQ1, 0xd8);
- tm6000_set_reg(dev, TM6010_REQ07_RD2_ADDR_FOR_REQ2, 0xc0);
- tm6000_set_reg(dev, TM6010_REQ07_RD6_ENDP_REQ1_REQ2, 0x60);
-
- tm6000_set_reg(dev, TM6000_REQ07_RE2_VADC_STATUS_CTL, 0x0c);
- tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0xff);
- tm6000_set_reg(dev, TM6000_REQ07_REB_VADC_AADC_MODE, 0x08);
- msleep(50);
-
- tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
- msleep(50);
- tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x01);
- msleep(50);
- tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
- msleep(100);
- }
-
- /* switch dvb led on */
- if (dev->gpio.dvb_led) {
- tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
- dev->gpio.dvb_led, 0x00);
- }
-
- return 0;
-}
-EXPORT_SYMBOL(tm6000_init_digital_mode);
-
-struct reg_init {
- u8 req;
- u8 reg;
- u8 val;
-};
-
-/* The meaning of those initializations are unknown */
-static struct reg_init tm6000_init_tab[] = {
- /* REG VALUE */
- { TM6000_REQ07_RDF_PWDOWN_ACLK, 0x1f },
- { TM6010_REQ07_RFF_SOFT_RESET, 0x08 },
- { TM6010_REQ07_RFF_SOFT_RESET, 0x00 },
- { TM6010_REQ07_RD5_POWERSAVE, 0x4f },
- { TM6000_REQ07_RDA_CLK_SEL, 0x23 },
- { TM6000_REQ07_RDB_OUT_SEL, 0x08 },
- { TM6000_REQ07_RE2_VADC_STATUS_CTL, 0x00 },
- { TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x10 },
- { TM6000_REQ07_RE5_VADC_INP_LPF_SEL2, 0x00 },
- { TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0x00 },
- { TM6000_REQ07_REB_VADC_AADC_MODE, 0x64 }, /* 48000 bits/sample, external input */
- { TM6000_REQ07_REE_VADC_CTRL_SEL_CONTROL, 0xc2 },
-
- { TM6010_REQ07_R3F_RESET, 0x01 }, /* Start of soft reset */
- { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x00 },
- { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x07 },
- { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
- { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00 },
- { TM6010_REQ07_R05_NOISE_THRESHOLD, 0x64 },
- { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01 },
- { TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, 0x82 },
- { TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, 0x36 },
- { TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, 0x50 },
- { TM6010_REQ07_R0C_CHROMA_AGC_CONTROL, 0x6a },
- { TM6010_REQ07_R11_AGC_PEAK_CONTROL, 0xc9 },
- { TM6010_REQ07_R12_AGC_GATE_STARTH, 0x07 },
- { TM6010_REQ07_R13_AGC_GATE_STARTL, 0x3b },
- { TM6010_REQ07_R14_AGC_GATE_WIDTH, 0x47 },
- { TM6010_REQ07_R15_AGC_BP_DELAY, 0x6f },
- { TM6010_REQ07_R17_HLOOP_MAXSTATE, 0xcd },
- { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e },
- { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b },
- { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2 },
- { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9 },
- { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
- { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
- { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
- { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
- { TM6010_REQ07_R20_HSYNC_RISING_EDGE_TIME, 0x3c },
- { TM6010_REQ07_R21_HSYNC_PHASE_OFFSET, 0x3c },
- { TM6010_REQ07_R2D_CHROMA_BURST_END, 0x48 },
- { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 },
- { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 },
- { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 },
- { TM6010_REQ07_R32_VSYNC_HLOCK_MIN, 0x74 },
- { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c },
- { TM6010_REQ07_R34_VSYNC_AGC_MIN, 0x74 },
- { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c },
- { TM6010_REQ07_R36_VSYNC_VBI_MIN, 0x7a },
- { TM6010_REQ07_R37_VSYNC_VBI_MAX, 0x26 },
- { TM6010_REQ07_R38_VSYNC_THRESHOLD, 0x40 },
- { TM6010_REQ07_R39_VSYNC_TIME_CONSTANT, 0x0a },
- { TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL, 0x55 },
- { TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21, 0x11 },
- { TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN, 0x01 },
- { TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN, 0x02 },
- { TM6010_REQ07_R58_VBI_CAPTION_DTO1, 0x35 },
- { TM6010_REQ07_R59_VBI_CAPTION_DTO0, 0xa0 },
- { TM6010_REQ07_R80_COMB_FILTER_TRESHOLD, 0x15 },
- { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 },
- { TM6010_REQ07_RC1_TRESHOLD, 0xd0 },
- { TM6010_REQ07_RC3_HSTART1, 0x88 },
- { TM6010_REQ07_R3F_RESET, 0x00 }, /* End of the soft reset */
- { TM6010_REQ05_R18_IMASK7, 0x00 },
-};
-
-static struct reg_init tm6010_init_tab[] = {
- { TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x00 },
- { TM6010_REQ07_RC4_HSTART0, 0xa0 },
- { TM6010_REQ07_RC6_HEND0, 0x40 },
- { TM6010_REQ07_RCA_VEND0, 0x31 },
- { TM6010_REQ07_RCC_ACTIVE_IF, 0xe1 },
- { TM6010_REQ07_RE0_DVIDEO_SOURCE, 0x03 },
- { TM6010_REQ07_RFE_POWER_DOWN, 0x7f },
-
- { TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0 },
- { TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4 },
- { TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf8 },
- { TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x00 },
- { TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf2 },
- { TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xf0 },
- { TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2 },
- { TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x60 },
- { TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc },
-
- { TM6010_REQ07_R3F_RESET, 0x01 },
- { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x00 },
- { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x07 },
- { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
- { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00 },
- { TM6010_REQ07_R05_NOISE_THRESHOLD, 0x64 },
- { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01 },
- { TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, 0x82 },
- { TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, 0x36 },
- { TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, 0x50 },
- { TM6010_REQ07_R0C_CHROMA_AGC_CONTROL, 0x6a },
- { TM6010_REQ07_R11_AGC_PEAK_CONTROL, 0xc9 },
- { TM6010_REQ07_R12_AGC_GATE_STARTH, 0x07 },
- { TM6010_REQ07_R13_AGC_GATE_STARTL, 0x3b },
- { TM6010_REQ07_R14_AGC_GATE_WIDTH, 0x47 },
- { TM6010_REQ07_R15_AGC_BP_DELAY, 0x6f },
- { TM6010_REQ07_R17_HLOOP_MAXSTATE, 0xcd },
- { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e },
- { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b },
- { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2 },
- { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9 },
- { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
- { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
- { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
- { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
- { TM6010_REQ07_R20_HSYNC_RISING_EDGE_TIME, 0x3c },
- { TM6010_REQ07_R21_HSYNC_PHASE_OFFSET, 0x3c },
- { TM6010_REQ07_R2D_CHROMA_BURST_END, 0x48 },
- { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 },
- { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 },
- { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 },
- { TM6010_REQ07_R32_VSYNC_HLOCK_MIN, 0x74 },
- { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c },
- { TM6010_REQ07_R34_VSYNC_AGC_MIN, 0x74 },
- { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c },
- { TM6010_REQ07_R36_VSYNC_VBI_MIN, 0x7a },
- { TM6010_REQ07_R37_VSYNC_VBI_MAX, 0x26 },
- { TM6010_REQ07_R38_VSYNC_THRESHOLD, 0x40 },
- { TM6010_REQ07_R39_VSYNC_TIME_CONSTANT, 0x0a },
- { TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL, 0x55 },
- { TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21, 0x11 },
- { TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN, 0x01 },
- { TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN, 0x02 },
- { TM6010_REQ07_R58_VBI_CAPTION_DTO1, 0x35 },
- { TM6010_REQ07_R59_VBI_CAPTION_DTO0, 0xa0 },
- { TM6010_REQ07_R80_COMB_FILTER_TRESHOLD, 0x15 },
- { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 },
- { TM6010_REQ07_RC1_TRESHOLD, 0xd0 },
- { TM6010_REQ07_RC3_HSTART1, 0x88 },
- { TM6010_REQ07_R3F_RESET, 0x00 },
-
- { TM6010_REQ05_R18_IMASK7, 0x00 },
-
- { TM6010_REQ07_RDC_IR_LEADER1, 0xaa },
- { TM6010_REQ07_RDD_IR_LEADER0, 0x30 },
- { TM6010_REQ07_RDE_IR_PULSE_CNT1, 0x20 },
- { TM6010_REQ07_RDF_IR_PULSE_CNT0, 0xd0 },
- { REQ_04_EN_DISABLE_MCU_INT, 0x02, 0x00 },
- { TM6010_REQ07_RD8_IR, 0x0f },
-
- /* set remote wakeup key:any key wakeup */
- { TM6010_REQ07_RE5_REMOTE_WAKEUP, 0xfe },
- { TM6010_REQ07_RDA_IR_WAKEUP_SEL, 0xff },
-};
-
-int tm6000_init(struct tm6000_core *dev)
-{
- int board, rc = 0, i, size;
- struct reg_init *tab;
-
- /* Check board revision */
- board = tm6000_get_reg32(dev, REQ_40_GET_VERSION, 0, 0);
- if (board >= 0) {
- switch (board & 0xff) {
- case 0xf3:
- printk(KERN_INFO "Found tm6000\n");
- if (dev->dev_type != TM6000)
- dev->dev_type = TM6000;
- break;
- case 0xf4:
- printk(KERN_INFO "Found tm6010\n");
- if (dev->dev_type != TM6010)
- dev->dev_type = TM6010;
- break;
- default:
- printk(KERN_INFO "Unknown board version = 0x%08x\n", board);
- }
- } else
- printk(KERN_ERR "Error %i while retrieving board version\n", board);
-
- if (dev->dev_type == TM6010) {
- tab = tm6010_init_tab;
- size = ARRAY_SIZE(tm6010_init_tab);
- } else {
- tab = tm6000_init_tab;
- size = ARRAY_SIZE(tm6000_init_tab);
- }
-
- /* Load board's initialization table */
- for (i = 0; i < size; i++) {
- rc = tm6000_set_reg(dev, tab[i].req, tab[i].reg, tab[i].val);
- if (rc < 0) {
- printk(KERN_ERR "Error %i while setting req %d, reg %d to value %d\n",
- rc,
- tab[i].req, tab[i].reg, tab[i].val);
- return rc;
- }
- }
-
- msleep(5); /* Just to be conservative */
-
- rc = tm6000_cards_setup(dev);
-
- return rc;
-}
-
-
-int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate)
-{
- int val = 0;
- u8 areg_f0 = 0x60; /* ADC MCLK = 250 Fs */
- u8 areg_0a = 0x91; /* SIF 48KHz */
-
- switch (bitrate) {
- case 48000:
- areg_f0 = 0x60; /* ADC MCLK = 250 Fs */
- areg_0a = 0x91; /* SIF 48KHz */
- dev->audio_bitrate = bitrate;
- break;
- case 32000:
- areg_f0 = 0x00; /* ADC MCLK = 375 Fs */
- areg_0a = 0x90; /* SIF 32KHz */
- dev->audio_bitrate = bitrate;
- break;
- default:
- return -EINVAL;
- }
-
-
- /* enable I2S, if we use sif or external I2S device */
- if (dev->dev_type == TM6010) {
- val = tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, areg_0a);
- if (val < 0)
- return val;
-
- val = tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
- areg_f0, 0xf0);
- if (val < 0)
- return val;
- } else {
- val = tm6000_set_reg_mask(dev, TM6000_REQ07_REB_VADC_AADC_MODE,
- areg_f0, 0xf0);
- if (val < 0)
- return val;
- }
- return 0;
-}
-EXPORT_SYMBOL_GPL(tm6000_set_audio_bitrate);
-
-int tm6000_set_audio_rinput(struct tm6000_core *dev)
-{
- if (dev->dev_type == TM6010) {
- /* Audio crossbar setting, default SIF1 */
- u8 areg_f0;
- u8 areg_07 = 0x10;
-
- switch (dev->rinput.amux) {
- case TM6000_AMUX_SIF1:
- case TM6000_AMUX_SIF2:
- areg_f0 = 0x03;
- areg_07 = 0x30;
- break;
- case TM6000_AMUX_ADC1:
- areg_f0 = 0x00;
- break;
- case TM6000_AMUX_ADC2:
- areg_f0 = 0x08;
- break;
- case TM6000_AMUX_I2S:
- areg_f0 = 0x04;
- break;
- default:
- printk(KERN_INFO "%s: audio input doesn't support\n",
- dev->name);
- return 0;
- break;
- }
- /* Set audio input crossbar */
- tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
- areg_f0, 0x0f);
- /* Mux overflow workaround */
- tm6000_set_reg_mask(dev, TM6010_REQ07_R07_OUTPUT_CONTROL,
- areg_07, 0xf0);
- } else {
- u8 areg_eb;
- /* Audio setting, default LINE1 */
- switch (dev->rinput.amux) {
- case TM6000_AMUX_ADC1:
- areg_eb = 0x00;
- break;
- case TM6000_AMUX_ADC2:
- areg_eb = 0x04;
- break;
- default:
- printk(KERN_INFO "%s: audio input doesn't support\n",
- dev->name);
- return 0;
- break;
- }
- /* Set audio input */
- tm6000_set_reg_mask(dev, TM6000_REQ07_REB_VADC_AADC_MODE,
- areg_eb, 0x0f);
- }
- return 0;
-}
-
-static void tm6010_set_mute_sif(struct tm6000_core *dev, u8 mute)
-{
- u8 mute_reg = 0;
-
- if (mute)
- mute_reg = 0x08;
-
- tm6000_set_reg_mask(dev, TM6010_REQ08_R0A_A_I2S_MOD, mute_reg, 0x08);
-}
-
-static void tm6010_set_mute_adc(struct tm6000_core *dev, u8 mute)
-{
- u8 mute_reg = 0;
-
- if (mute)
- mute_reg = 0x20;
-
- if (dev->dev_type == TM6010) {
- tm6000_set_reg_mask(dev, TM6010_REQ08_RF2_LEFT_CHANNEL_VOL,
- mute_reg, 0x20);
- tm6000_set_reg_mask(dev, TM6010_REQ08_RF3_RIGHT_CHANNEL_VOL,
- mute_reg, 0x20);
- } else {
- tm6000_set_reg_mask(dev, TM6000_REQ07_REC_VADC_AADC_LVOL,
- mute_reg, 0x20);
- tm6000_set_reg_mask(dev, TM6000_REQ07_RED_VADC_AADC_RVOL,
- mute_reg, 0x20);
- }
-}
-
-int tm6000_tvaudio_set_mute(struct tm6000_core *dev, u8 mute)
-{
- enum tm6000_mux mux;
-
- if (dev->radio)
- mux = dev->rinput.amux;
- else
- mux = dev->vinput[dev->input].amux;
-
- switch (mux) {
- case TM6000_AMUX_SIF1:
- case TM6000_AMUX_SIF2:
- if (dev->dev_type == TM6010)
- tm6010_set_mute_sif(dev, mute);
- else {
- printk(KERN_INFO "ERROR: TM5600 and TM6000 don't has SIF audio inputs. Please check the %s configuration.\n",
- dev->name);
- return -EINVAL;
- }
- break;
- case TM6000_AMUX_ADC1:
- case TM6000_AMUX_ADC2:
- tm6010_set_mute_adc(dev, mute);
- break;
- default:
- return -EINVAL;
- break;
- }
- return 0;
-}
-
-static void tm6010_set_volume_sif(struct tm6000_core *dev, int vol)
-{
- u8 vol_reg;
-
- vol_reg = vol & 0x0F;
-
- if (vol < 0)
- vol_reg |= 0x40;
-
- tm6000_set_reg(dev, TM6010_REQ08_R07_A_LEFT_VOL, vol_reg);
- tm6000_set_reg(dev, TM6010_REQ08_R08_A_RIGHT_VOL, vol_reg);
-}
-
-static void tm6010_set_volume_adc(struct tm6000_core *dev, int vol)
-{
- u8 vol_reg;
-
- vol_reg = (vol + 0x10) & 0x1f;
-
- if (dev->dev_type == TM6010) {
- tm6000_set_reg(dev, TM6010_REQ08_RF2_LEFT_CHANNEL_VOL, vol_reg);
- tm6000_set_reg(dev, TM6010_REQ08_RF3_RIGHT_CHANNEL_VOL, vol_reg);
- } else {
- tm6000_set_reg(dev, TM6000_REQ07_REC_VADC_AADC_LVOL, vol_reg);
- tm6000_set_reg(dev, TM6000_REQ07_RED_VADC_AADC_RVOL, vol_reg);
- }
-}
-
-void tm6000_set_volume(struct tm6000_core *dev, int vol)
-{
- enum tm6000_mux mux;
-
- if (dev->radio) {
- mux = dev->rinput.amux;
- vol += 8; /* Offset to 0 dB */
- } else
- mux = dev->vinput[dev->input].amux;
-
- switch (mux) {
- case TM6000_AMUX_SIF1:
- case TM6000_AMUX_SIF2:
- if (dev->dev_type == TM6010)
- tm6010_set_volume_sif(dev, vol);
- else
- printk(KERN_INFO "ERROR: TM5600 and TM6000 don't has SIF audio inputs. Please check the %s configuration.\n",
- dev->name);
- break;
- case TM6000_AMUX_ADC1:
- case TM6000_AMUX_ADC2:
- tm6010_set_volume_adc(dev, vol);
- break;
- default:
- break;
- }
-}
-
-static LIST_HEAD(tm6000_devlist);
-static DEFINE_MUTEX(tm6000_devlist_mutex);
-
-/*
- * tm6000_realease_resource()
- */
-
-void tm6000_remove_from_devlist(struct tm6000_core *dev)
-{
- mutex_lock(&tm6000_devlist_mutex);
- list_del(&dev->devlist);
- mutex_unlock(&tm6000_devlist_mutex);
-};
-
-void tm6000_add_into_devlist(struct tm6000_core *dev)
-{
- mutex_lock(&tm6000_devlist_mutex);
- list_add_tail(&dev->devlist, &tm6000_devlist);
- mutex_unlock(&tm6000_devlist_mutex);
-};
-
-/*
- * Extension interface
- */
-
-static LIST_HEAD(tm6000_extension_devlist);
-
-int tm6000_call_fillbuf(struct tm6000_core *dev, enum tm6000_ops_type type,
- char *buf, int size)
-{
- struct tm6000_ops *ops = NULL;
-
- /* FIXME: tm6000_extension_devlist_lock should be a spinlock */
-
- list_for_each_entry(ops, &tm6000_extension_devlist, next) {
- if (ops->fillbuf && ops->type == type)
- ops->fillbuf(dev, buf, size);
- }
-
- return 0;
-}
-
-int tm6000_register_extension(struct tm6000_ops *ops)
-{
- struct tm6000_core *dev = NULL;
-
- mutex_lock(&tm6000_devlist_mutex);
- list_add_tail(&ops->next, &tm6000_extension_devlist);
- list_for_each_entry(dev, &tm6000_devlist, devlist) {
- ops->init(dev);
- printk(KERN_INFO "%s: Initialized (%s) extension\n",
- dev->name, ops->name);
- }
- mutex_unlock(&tm6000_devlist_mutex);
- return 0;
-}
-EXPORT_SYMBOL(tm6000_register_extension);
-
-void tm6000_unregister_extension(struct tm6000_ops *ops)
-{
- struct tm6000_core *dev = NULL;
-
- mutex_lock(&tm6000_devlist_mutex);
- list_for_each_entry(dev, &tm6000_devlist, devlist)
- ops->fini(dev);
-
- printk(KERN_INFO "tm6000: Remove (%s) extension\n", ops->name);
- list_del(&ops->next);
- mutex_unlock(&tm6000_devlist_mutex);
-}
-EXPORT_SYMBOL(tm6000_unregister_extension);
-
-void tm6000_init_extension(struct tm6000_core *dev)
-{
- struct tm6000_ops *ops = NULL;
-
- mutex_lock(&tm6000_devlist_mutex);
- list_for_each_entry(ops, &tm6000_extension_devlist, next) {
- if (ops->init)
- ops->init(dev);
- }
- mutex_unlock(&tm6000_devlist_mutex);
-}
-
-void tm6000_close_extension(struct tm6000_core *dev)
-{
- struct tm6000_ops *ops = NULL;
-
- mutex_lock(&tm6000_devlist_mutex);
- list_for_each_entry(ops, &tm6000_extension_devlist, next) {
- if (ops->fini)
- ops->fini(dev);
- }
- mutex_unlock(&tm6000_devlist_mutex);
-}
diff --git a/drivers/staging/media/deprecated/tm6000/tm6000-dvb.c b/drivers/staging/media/deprecated/tm6000/tm6000-dvb.c
deleted file mode 100644
index ee04973cbf93..000000000000
--- a/drivers/staging/media/deprecated/tm6000/tm6000-dvb.c
+++ /dev/null
@@ -1,454 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * tm6000-dvb.c - dvb-t support for TM5600/TM6000/TM6010 USB video capture devices
- *
- * Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-
-#include "tm6000.h"
-#include "tm6000-regs.h"
-
-#include "zl10353.h"
-
-#include <media/tuner.h>
-
-#include "xc2028.h"
-#include "xc5000.h"
-
-MODULE_DESCRIPTION("DVB driver extension module for tm5600/6000/6010 based TV cards");
-MODULE_AUTHOR("Mauro Carvalho Chehab");
-MODULE_LICENSE("GPL");
-
-static int debug;
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "enable debug message");
-
-static inline void print_err_status(struct tm6000_core *dev,
- int packet, int status)
-{
- char *errmsg = "Unknown";
-
- switch (status) {
- case -ENOENT:
- errmsg = "unlinked synchronously";
- break;
- case -ECONNRESET:
- errmsg = "unlinked asynchronously";
- break;
- case -ENOSR:
- errmsg = "Buffer error (overrun)";
- break;
- case -EPIPE:
- errmsg = "Stalled (device not responding)";
- break;
- case -EOVERFLOW:
- errmsg = "Babble (bad cable?)";
- break;
- case -EPROTO:
- errmsg = "Bit-stuff error (bad cable?)";
- break;
- case -EILSEQ:
- errmsg = "CRC/Timeout (could be anything)";
- break;
- case -ETIME:
- errmsg = "Device does not respond";
- break;
- }
- if (packet < 0) {
- dprintk(dev, 1, "URB status %d [%s].\n",
- status, errmsg);
- } else {
- dprintk(dev, 1, "URB packet %d, status %d [%s].\n",
- packet, status, errmsg);
- }
-}
-
-static void tm6000_urb_received(struct urb *urb)
-{
- int ret;
- struct tm6000_core *dev = urb->context;
-
- switch (urb->status) {
- case 0:
- case -ETIMEDOUT:
- break;
- case -ENOENT:
- case -ECONNRESET:
- case -ESHUTDOWN:
- return;
- default:
- print_err_status(dev, 0, urb->status);
- }
-
- if (urb->actual_length > 0)
- dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer,
- urb->actual_length);
-
- if (dev->dvb->streams > 0) {
- ret = usb_submit_urb(urb, GFP_ATOMIC);
- if (ret < 0) {
- printk(KERN_ERR "tm6000: error %s\n", __func__);
- kfree(urb->transfer_buffer);
- usb_free_urb(urb);
- dev->dvb->bulk_urb = NULL;
- }
- }
-}
-
-static int tm6000_start_stream(struct tm6000_core *dev)
-{
- int ret;
- unsigned int pipe, size;
- struct tm6000_dvb *dvb = dev->dvb;
-
- printk(KERN_INFO "tm6000: got start stream request %s\n", __func__);
-
- if (dev->mode != TM6000_MODE_DIGITAL) {
- tm6000_init_digital_mode(dev);
- dev->mode = TM6000_MODE_DIGITAL;
- }
-
- dvb->bulk_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!dvb->bulk_urb)
- return -ENOMEM;
-
- pipe = usb_rcvbulkpipe(dev->udev, dev->bulk_in.endp->desc.bEndpointAddress
- & USB_ENDPOINT_NUMBER_MASK);
-
- size = usb_maxpacket(dev->udev, pipe);
- size = size * 15; /* 512 x 8 or 12 or 15 */
-
- dvb->bulk_urb->transfer_buffer = kzalloc(size, GFP_KERNEL);
- if (!dvb->bulk_urb->transfer_buffer) {
- usb_free_urb(dvb->bulk_urb);
- dvb->bulk_urb = NULL;
- return -ENOMEM;
- }
-
- usb_fill_bulk_urb(dvb->bulk_urb, dev->udev, pipe,
- dvb->bulk_urb->transfer_buffer,
- size,
- tm6000_urb_received, dev);
-
- ret = usb_clear_halt(dev->udev, pipe);
- if (ret < 0) {
- printk(KERN_ERR "tm6000: error %i in %s during pipe reset\n",
- ret, __func__);
-
- kfree(dvb->bulk_urb->transfer_buffer);
- usb_free_urb(dvb->bulk_urb);
- dvb->bulk_urb = NULL;
- return ret;
- } else
- printk(KERN_ERR "tm6000: pipe reset\n");
-
-/* mutex_lock(&tm6000_driver.open_close_mutex); */
- ret = usb_submit_urb(dvb->bulk_urb, GFP_ATOMIC);
-
-/* mutex_unlock(&tm6000_driver.open_close_mutex); */
- if (ret) {
- printk(KERN_ERR "tm6000: submit of urb failed (error=%i)\n",
- ret);
-
- kfree(dvb->bulk_urb->transfer_buffer);
- usb_free_urb(dvb->bulk_urb);
- dvb->bulk_urb = NULL;
- return ret;
- }
-
- return 0;
-}
-
-static void tm6000_stop_stream(struct tm6000_core *dev)
-{
- struct tm6000_dvb *dvb = dev->dvb;
-
- if (dvb->bulk_urb) {
- printk(KERN_INFO "urb killing\n");
- usb_kill_urb(dvb->bulk_urb);
- printk(KERN_INFO "urb buffer free\n");
- kfree(dvb->bulk_urb->transfer_buffer);
- usb_free_urb(dvb->bulk_urb);
- dvb->bulk_urb = NULL;
- }
-}
-
-static int tm6000_start_feed(struct dvb_demux_feed *feed)
-{
- struct dvb_demux *demux = feed->demux;
- struct tm6000_core *dev = demux->priv;
- struct tm6000_dvb *dvb = dev->dvb;
- printk(KERN_INFO "tm6000: got start feed request %s\n", __func__);
-
- mutex_lock(&dvb->mutex);
- if (dvb->streams == 0) {
- dvb->streams = 1;
-/* mutex_init(&tm6000_dev->streming_mutex); */
- tm6000_start_stream(dev);
- } else
- ++(dvb->streams);
- mutex_unlock(&dvb->mutex);
-
- return 0;
-}
-
-static int tm6000_stop_feed(struct dvb_demux_feed *feed)
-{
- struct dvb_demux *demux = feed->demux;
- struct tm6000_core *dev = demux->priv;
- struct tm6000_dvb *dvb = dev->dvb;
-
- printk(KERN_INFO "tm6000: got stop feed request %s\n", __func__);
-
- mutex_lock(&dvb->mutex);
-
- printk(KERN_INFO "stream %#x\n", dvb->streams);
- --(dvb->streams);
- if (dvb->streams == 0) {
- printk(KERN_INFO "stop stream\n");
- tm6000_stop_stream(dev);
-/* mutex_destroy(&tm6000_dev->streaming_mutex); */
- }
- mutex_unlock(&dvb->mutex);
-/* mutex_destroy(&tm6000_dev->streaming_mutex); */
-
- return 0;
-}
-
-static int tm6000_dvb_attach_frontend(struct tm6000_core *dev)
-{
- struct tm6000_dvb *dvb = dev->dvb;
-
- if (dev->caps.has_zl10353) {
- struct zl10353_config config = {
- .demod_address = dev->demod_addr,
- .no_tuner = 1,
- .parallel_ts = 1,
- .if2 = 45700,
- .disable_i2c_gate_ctrl = 1,
- };
-
- dvb->frontend = dvb_attach(zl10353_attach, &config,
- &dev->i2c_adap);
- } else {
- printk(KERN_ERR "tm6000: no frontend defined for the device!\n");
- return -1;
- }
-
- return (!dvb->frontend) ? -1 : 0;
-}
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-static int register_dvb(struct tm6000_core *dev)
-{
- int ret = -1;
- struct tm6000_dvb *dvb = dev->dvb;
-
- mutex_init(&dvb->mutex);
-
- dvb->streams = 0;
-
- /* attach the frontend */
- ret = tm6000_dvb_attach_frontend(dev);
- if (ret < 0) {
- printk(KERN_ERR "tm6000: couldn't attach the frontend!\n");
- goto err;
- }
-
- ret = dvb_register_adapter(&dvb->adapter, "Trident TVMaster 6000 DVB-T",
- THIS_MODULE, &dev->udev->dev, adapter_nr);
- if (ret < 0) {
- pr_err("tm6000: couldn't register the adapter!\n");
- goto err;
- }
-
- dvb->adapter.priv = dev;
-
- if (dvb->frontend) {
- switch (dev->tuner_type) {
- case TUNER_XC2028: {
- struct xc2028_config cfg = {
- .i2c_adap = &dev->i2c_adap,
- .i2c_addr = dev->tuner_addr,
- };
-
- dvb->frontend->callback = tm6000_tuner_callback;
- ret = dvb_register_frontend(&dvb->adapter, dvb->frontend);
- if (ret < 0) {
- printk(KERN_ERR
- "tm6000: couldn't register frontend\n");
- goto adapter_err;
- }
-
- if (!dvb_attach(xc2028_attach, dvb->frontend, &cfg)) {
- printk(KERN_ERR "tm6000: couldn't register frontend (xc3028)\n");
- ret = -EINVAL;
- goto frontend_err;
- }
- printk(KERN_INFO "tm6000: XC2028/3028 asked to be attached to frontend!\n");
- break;
- }
- case TUNER_XC5000: {
- struct xc5000_config cfg = {
- .i2c_address = dev->tuner_addr,
- };
-
- dvb->frontend->callback = tm6000_xc5000_callback;
- ret = dvb_register_frontend(&dvb->adapter, dvb->frontend);
- if (ret < 0) {
- printk(KERN_ERR
- "tm6000: couldn't register frontend\n");
- goto adapter_err;
- }
-
- if (!dvb_attach(xc5000_attach, dvb->frontend, &dev->i2c_adap, &cfg)) {
- printk(KERN_ERR "tm6000: couldn't register frontend (xc5000)\n");
- ret = -EINVAL;
- goto frontend_err;
- }
- printk(KERN_INFO "tm6000: XC5000 asked to be attached to frontend!\n");
- break;
- }
- }
- } else
- printk(KERN_ERR "tm6000: no frontend found\n");
-
- dvb->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING
- | DMX_MEMORY_BASED_FILTERING;
- dvb->demux.priv = dev;
- dvb->demux.filternum = 8;
- dvb->demux.feednum = 8;
- dvb->demux.start_feed = tm6000_start_feed;
- dvb->demux.stop_feed = tm6000_stop_feed;
- dvb->demux.write_to_decoder = NULL;
- ret = dvb_dmx_init(&dvb->demux);
- if (ret < 0) {
- printk(KERN_ERR "tm6000: dvb_dmx_init failed (errno = %d)\n", ret);
- goto frontend_err;
- }
-
- dvb->dmxdev.filternum = dev->dvb->demux.filternum;
- dvb->dmxdev.demux = &dev->dvb->demux.dmx;
- dvb->dmxdev.capabilities = 0;
-
- ret = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
- if (ret < 0) {
- printk(KERN_ERR "tm6000: dvb_dmxdev_init failed (errno = %d)\n", ret);
- goto dvb_dmx_err;
- }
-
- return 0;
-
-dvb_dmx_err:
- dvb_dmx_release(&dvb->demux);
-frontend_err:
- if (dvb->frontend) {
- dvb_unregister_frontend(dvb->frontend);
- dvb_frontend_detach(dvb->frontend);
- }
-adapter_err:
- dvb_unregister_adapter(&dvb->adapter);
-err:
- return ret;
-}
-
-static void unregister_dvb(struct tm6000_core *dev)
-{
- struct tm6000_dvb *dvb = dev->dvb;
-
- if (dvb->bulk_urb) {
- struct urb *bulk_urb = dvb->bulk_urb;
-
- kfree(bulk_urb->transfer_buffer);
- bulk_urb->transfer_buffer = NULL;
- usb_unlink_urb(bulk_urb);
- usb_free_urb(bulk_urb);
- }
-
-/* mutex_lock(&tm6000_driver.open_close_mutex); */
- if (dvb->frontend) {
- dvb_unregister_frontend(dvb->frontend);
- dvb_frontend_detach(dvb->frontend);
- }
-
- dvb_dmxdev_release(&dvb->dmxdev);
- dvb_dmx_release(&dvb->demux);
- dvb_unregister_adapter(&dvb->adapter);
- mutex_destroy(&dvb->mutex);
-/* mutex_unlock(&tm6000_driver.open_close_mutex); */
-}
-
-static int dvb_init(struct tm6000_core *dev)
-{
- struct tm6000_dvb *dvb;
- int rc;
-
- if (!dev)
- return 0;
-
- if (!dev->caps.has_dvb)
- return 0;
-
- if (dev->udev->speed == USB_SPEED_FULL) {
- printk(KERN_INFO "This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware PID filter)\n");
- return 0;
- }
-
- dvb = kzalloc(sizeof(struct tm6000_dvb), GFP_KERNEL);
- if (!dvb)
- return -ENOMEM;
-
- dev->dvb = dvb;
-
- rc = register_dvb(dev);
- if (rc < 0) {
- kfree(dvb);
- dev->dvb = NULL;
- return 0;
- }
-
- return 0;
-}
-
-static int dvb_fini(struct tm6000_core *dev)
-{
- if (!dev)
- return 0;
-
- if (!dev->caps.has_dvb)
- return 0;
-
- if (dev->dvb) {
- unregister_dvb(dev);
- kfree(dev->dvb);
- dev->dvb = NULL;
- }
-
- return 0;
-}
-
-static struct tm6000_ops dvb_ops = {
- .type = TM6000_DVB,
- .name = "TM6000 dvb Extension",
- .init = dvb_init,
- .fini = dvb_fini,
-};
-
-static int __init tm6000_dvb_register(void)
-{
- return tm6000_register_extension(&dvb_ops);
-}
-
-static void __exit tm6000_dvb_unregister(void)
-{
- tm6000_unregister_extension(&dvb_ops);
-}
-
-module_init(tm6000_dvb_register);
-module_exit(tm6000_dvb_unregister);
diff --git a/drivers/staging/media/deprecated/tm6000/tm6000-i2c.c b/drivers/staging/media/deprecated/tm6000/tm6000-i2c.c
deleted file mode 100644
index 7554b93b82e6..000000000000
--- a/drivers/staging/media/deprecated/tm6000/tm6000-i2c.c
+++ /dev/null
@@ -1,317 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-// tm6000-i2c.c - driver for TM5600/TM6000/TM6010 USB video capture devices
-//
-// Copyright (c) 2006-2007 Mauro Carvalho Chehab <mchehab@kernel.org>
-//
-// Copyright (c) 2007 Michel Ludwig <michel.ludwig@gmail.com>
-// - Fix SMBus Read Byte command
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/usb.h>
-#include <linux/i2c.h>
-
-#include "tm6000.h"
-#include "tm6000-regs.h"
-#include <media/v4l2-common.h>
-#include <media/tuner.h>
-#include "xc2028.h"
-
-
-/* ----------------------------------------------------------- */
-
-static unsigned int i2c_debug;
-module_param(i2c_debug, int, 0644);
-MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
-
-#define i2c_dprintk(lvl, fmt, args...) if (i2c_debug >= lvl) do { \
- printk(KERN_DEBUG "%s at %s: " fmt, \
- dev->name, __func__, ##args); } while (0)
-
-static int tm6000_i2c_send_regs(struct tm6000_core *dev, unsigned char addr,
- __u8 reg, char *buf, int len)
-{
- int rc;
- unsigned int i2c_packet_limit = 16;
-
- if (dev->dev_type == TM6010)
- i2c_packet_limit = 80;
-
- if (!buf)
- return -1;
-
- if (len < 1 || len > i2c_packet_limit) {
- printk(KERN_ERR "Incorrect length of i2c packet = %d, limit set to %d\n",
- len, i2c_packet_limit);
- return -1;
- }
-
- /* capture mutex */
- rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR |
- USB_RECIP_DEVICE, REQ_16_SET_GET_I2C_WR1_RDN,
- addr | reg << 8, 0, buf, len);
-
- if (rc < 0) {
- /* release mutex */
- return rc;
- }
-
- /* release mutex */
- return rc;
-}
-
-/* Generic read - doesn't work fine with 16bit registers */
-static int tm6000_i2c_recv_regs(struct tm6000_core *dev, unsigned char addr,
- __u8 reg, char *buf, int len)
-{
- int rc;
- u8 b[2];
- unsigned int i2c_packet_limit = 16;
-
- if (dev->dev_type == TM6010)
- i2c_packet_limit = 64;
-
- if (!buf)
- return -1;
-
- if (len < 1 || len > i2c_packet_limit) {
- printk(KERN_ERR "Incorrect length of i2c packet = %d, limit set to %d\n",
- len, i2c_packet_limit);
- return -1;
- }
-
- /* capture mutex */
- if ((dev->caps.has_zl10353) && (dev->demod_addr << 1 == addr) && (reg % 2 == 0)) {
- /*
- * Workaround an I2C bug when reading from zl10353
- */
- reg -= 1;
- len += 1;
-
- rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- REQ_16_SET_GET_I2C_WR1_RDN, addr | reg << 8, 0, b, len);
-
- *buf = b[1];
- } else {
- rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- REQ_16_SET_GET_I2C_WR1_RDN, addr | reg << 8, 0, buf, len);
- }
-
- /* release mutex */
- return rc;
-}
-
-/*
- * read from a 16bit register
- * for example xc2028, xc3028 or xc3028L
- */
-static int tm6000_i2c_recv_regs16(struct tm6000_core *dev, unsigned char addr,
- __u16 reg, char *buf, int len)
-{
- int rc;
- unsigned char ureg;
-
- if (!buf || len != 2)
- return -1;
-
- /* capture mutex */
- if (dev->dev_type == TM6010) {
- ureg = reg & 0xFF;
- rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR |
- USB_RECIP_DEVICE, REQ_16_SET_GET_I2C_WR1_RDN,
- addr | (reg & 0xFF00), 0, &ureg, 1);
-
- if (rc < 0) {
- /* release mutex */
- return rc;
- }
-
- rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR |
- USB_RECIP_DEVICE, REQ_35_AFTEK_TUNER_READ,
- reg, 0, buf, len);
- } else {
- rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR |
- USB_RECIP_DEVICE, REQ_14_SET_GET_I2C_WR2_RDN,
- addr, reg, buf, len);
- }
-
- /* release mutex */
- return rc;
-}
-
-static int tm6000_i2c_xfer(struct i2c_adapter *i2c_adap,
- struct i2c_msg msgs[], int num)
-{
- struct tm6000_core *dev = i2c_adap->algo_data;
- int addr, rc, i, byte;
-
- for (i = 0; i < num; i++) {
- addr = (msgs[i].addr << 1) & 0xff;
- i2c_dprintk(2, "%s %s addr=0x%x len=%d:",
- (msgs[i].flags & I2C_M_RD) ? "read" : "write",
- i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len);
- if (msgs[i].flags & I2C_M_RD) {
- /* read request without preceding register selection */
- /*
- * The TM6000 only supports a read transaction
- * immediately after a 1 or 2 byte write to select
- * a register. We cannot fulfill this request.
- */
- i2c_dprintk(2, " read without preceding write not supported");
- rc = -EOPNOTSUPP;
- goto err;
- } else if (i + 1 < num && msgs[i].len <= 2 &&
- (msgs[i + 1].flags & I2C_M_RD) &&
- msgs[i].addr == msgs[i + 1].addr) {
- /* 1 or 2 byte write followed by a read */
- if (i2c_debug >= 2)
- for (byte = 0; byte < msgs[i].len; byte++)
- printk(KERN_CONT " %02x", msgs[i].buf[byte]);
- i2c_dprintk(2, "; joined to read %s len=%d:",
- i == num - 2 ? "stop" : "nonstop",
- msgs[i + 1].len);
-
- if (msgs[i].len == 2) {
- rc = tm6000_i2c_recv_regs16(dev, addr,
- msgs[i].buf[0] << 8 | msgs[i].buf[1],
- msgs[i + 1].buf, msgs[i + 1].len);
- } else {
- rc = tm6000_i2c_recv_regs(dev, addr, msgs[i].buf[0],
- msgs[i + 1].buf, msgs[i + 1].len);
- }
-
- i++;
-
- if (addr == dev->tuner_addr << 1) {
- tm6000_set_reg(dev, REQ_50_SET_START, 0, 0);
- tm6000_set_reg(dev, REQ_51_SET_STOP, 0, 0);
- }
- if (i2c_debug >= 2)
- for (byte = 0; byte < msgs[i].len; byte++)
- printk(KERN_CONT " %02x", msgs[i].buf[byte]);
- } else {
- /* write bytes */
- if (i2c_debug >= 2)
- for (byte = 0; byte < msgs[i].len; byte++)
- printk(KERN_CONT " %02x", msgs[i].buf[byte]);
- rc = tm6000_i2c_send_regs(dev, addr, msgs[i].buf[0],
- msgs[i].buf + 1, msgs[i].len - 1);
- }
- if (i2c_debug >= 2)
- printk(KERN_CONT "\n");
- if (rc < 0)
- goto err;
- }
-
- return num;
-err:
- i2c_dprintk(2, " ERROR: %i\n", rc);
- return rc;
-}
-
-static int tm6000_i2c_eeprom(struct tm6000_core *dev)
-{
- int i, rc;
- unsigned char *p = dev->eedata;
- unsigned char bytes[17];
-
- dev->i2c_client.addr = 0xa0 >> 1;
- dev->eedata_size = 0;
-
- bytes[16] = '\0';
- for (i = 0; i < sizeof(dev->eedata); ) {
- *p = i;
- rc = tm6000_i2c_recv_regs(dev, 0xa0, i, p, 1);
- if (rc < 1) {
- if (p == dev->eedata)
- goto noeeprom;
- else {
- printk(KERN_WARNING
- "%s: i2c eeprom read error (err=%d)\n",
- dev->name, rc);
- }
- return -EINVAL;
- }
- dev->eedata_size++;
- p++;
- if (0 == (i % 16))
- printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i);
- printk(KERN_CONT " %02x", dev->eedata[i]);
- if ((dev->eedata[i] >= ' ') && (dev->eedata[i] <= 'z'))
- bytes[i%16] = dev->eedata[i];
- else
- bytes[i%16] = '.';
-
- i++;
-
- if (0 == (i % 16)) {
- bytes[16] = '\0';
- printk(KERN_CONT " %s\n", bytes);
- }
- }
- if (0 != (i%16)) {
- bytes[i%16] = '\0';
- for (i %= 16; i < 16; i++)
- printk(KERN_CONT " ");
- printk(KERN_CONT " %s\n", bytes);
- }
-
- return 0;
-
-noeeprom:
- printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n",
- dev->name, rc);
- return -EINVAL;
-}
-
-/* ----------------------------------------------------------- */
-
-/*
- * functionality()
- */
-static u32 functionality(struct i2c_adapter *adap)
-{
- return I2C_FUNC_SMBUS_EMUL;
-}
-
-static const struct i2c_algorithm tm6000_algo = {
- .master_xfer = tm6000_i2c_xfer,
- .functionality = functionality,
-};
-
-/* ----------------------------------------------------------- */
-
-/*
- * tm6000_i2c_register()
- * register i2c bus
- */
-int tm6000_i2c_register(struct tm6000_core *dev)
-{
- int rc;
-
- dev->i2c_adap.owner = THIS_MODULE;
- dev->i2c_adap.algo = &tm6000_algo;
- dev->i2c_adap.dev.parent = &dev->udev->dev;
- strscpy(dev->i2c_adap.name, dev->name, sizeof(dev->i2c_adap.name));
- dev->i2c_adap.algo_data = dev;
- i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
- rc = i2c_add_adapter(&dev->i2c_adap);
- if (rc)
- return rc;
-
- dev->i2c_client.adapter = &dev->i2c_adap;
- strscpy(dev->i2c_client.name, "tm6000 internal", I2C_NAME_SIZE);
- tm6000_i2c_eeprom(dev);
-
- return 0;
-}
-
-/*
- * tm6000_i2c_unregister()
- * unregister i2c_bus
- */
-int tm6000_i2c_unregister(struct tm6000_core *dev)
-{
- i2c_del_adapter(&dev->i2c_adap);
- return 0;
-}
diff --git a/drivers/staging/media/deprecated/tm6000/tm6000-input.c b/drivers/staging/media/deprecated/tm6000/tm6000-input.c
deleted file mode 100644
index 5136e9e202f1..000000000000
--- a/drivers/staging/media/deprecated/tm6000/tm6000-input.c
+++ /dev/null
@@ -1,503 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * tm6000-input.c - driver for TM5600/TM6000/TM6010 USB video capture devices
- *
- * Copyright (C) 2010 Stefan Ringel <stefan.ringel@arcor.de>
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-
-#include <linux/input.h>
-#include <linux/usb.h>
-
-#include <media/rc-core.h>
-
-#include "tm6000.h"
-#include "tm6000-regs.h"
-
-static unsigned int ir_debug;
-module_param(ir_debug, int, 0644);
-MODULE_PARM_DESC(ir_debug, "debug message level");
-
-static unsigned int enable_ir = 1;
-module_param(enable_ir, int, 0644);
-MODULE_PARM_DESC(enable_ir, "enable ir (default is enable)");
-
-static unsigned int ir_clock_mhz = 12;
-module_param(ir_clock_mhz, int, 0644);
-MODULE_PARM_DESC(ir_clock_mhz, "ir clock, in MHz");
-
-#define URB_SUBMIT_DELAY 100 /* ms - Delay to submit an URB request on retrial and init */
-#define URB_INT_LED_DELAY 100 /* ms - Delay to turn led on again on int mode */
-
-#undef dprintk
-
-#define dprintk(level, fmt, arg...) do {\
- if (ir_debug >= level) \
- printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \
- } while (0)
-
-struct tm6000_ir_poll_result {
- u16 rc_data;
-};
-
-struct tm6000_IR {
- struct tm6000_core *dev;
- struct rc_dev *rc;
- char name[32];
- char phys[32];
-
- /* poll expernal decoder */
- int polling;
- struct delayed_work work;
- u8 wait:1;
- u8 pwled:2;
- u8 submit_urb:1;
- struct urb *int_urb;
-
- /* IR device properties */
- u64 rc_proto;
-};
-
-void tm6000_ir_wait(struct tm6000_core *dev, u8 state)
-{
- struct tm6000_IR *ir = dev->ir;
-
- if (!dev->ir)
- return;
-
- dprintk(2, "%s: %i\n",__func__, ir->wait);
-
- if (state)
- ir->wait = 1;
- else
- ir->wait = 0;
-}
-
-static int tm6000_ir_config(struct tm6000_IR *ir)
-{
- struct tm6000_core *dev = ir->dev;
- u32 pulse = 0, leader = 0;
-
- dprintk(2, "%s\n",__func__);
-
- /*
- * The IR decoder supports RC-5 or NEC, with a configurable timing.
- * The timing configuration there is not that accurate, as it uses
- * approximate values. The NEC spec mentions a 562.5 unit period,
- * and RC-5 uses a 888.8 period.
- * Currently, driver assumes a clock provided by a 12 MHz XTAL, but
- * a modprobe parameter can adjust it.
- * Adjustments are required for other timings.
- * It seems that the 900ms timing for NEC is used to detect a RC-5
- * IR, in order to discard such decoding
- */
-
- switch (ir->rc_proto) {
- case RC_PROTO_BIT_NEC:
- leader = 900; /* ms */
- pulse = 700; /* ms - the actual value would be 562 */
- break;
- default:
- case RC_PROTO_BIT_RC5:
- leader = 900; /* ms - from the NEC decoding */
- pulse = 1780; /* ms - The actual value would be 1776 */
- break;
- }
-
- pulse = ir_clock_mhz * pulse;
- leader = ir_clock_mhz * leader;
- if (ir->rc_proto == RC_PROTO_BIT_NEC)
- leader = leader | 0x8000;
-
- dprintk(2, "%s: %s, %d MHz, leader = 0x%04x, pulse = 0x%06x \n",
- __func__,
- (ir->rc_proto == RC_PROTO_BIT_NEC) ? "NEC" : "RC-5",
- ir_clock_mhz, leader, pulse);
-
- /* Remote WAKEUP = enable, normal mode, from IR decoder output */
- tm6000_set_reg(dev, TM6010_REQ07_RE5_REMOTE_WAKEUP, 0xfe);
-
- /* Enable IR reception on non-busrt mode */
- tm6000_set_reg(dev, TM6010_REQ07_RD8_IR, 0x2f);
-
- /* IR_WKUP_SEL = Low byte in decoded IR data */
- tm6000_set_reg(dev, TM6010_REQ07_RDA_IR_WAKEUP_SEL, 0xff);
- /* IR_WKU_ADD code */
- tm6000_set_reg(dev, TM6010_REQ07_RDB_IR_WAKEUP_ADD, 0xff);
-
- tm6000_set_reg(dev, TM6010_REQ07_RDC_IR_LEADER1, leader >> 8);
- tm6000_set_reg(dev, TM6010_REQ07_RDD_IR_LEADER0, leader);
-
- tm6000_set_reg(dev, TM6010_REQ07_RDE_IR_PULSE_CNT1, pulse >> 8);
- tm6000_set_reg(dev, TM6010_REQ07_RDF_IR_PULSE_CNT0, pulse);
-
- if (!ir->polling)
- tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 0);
- else
- tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 1);
- msleep(10);
-
- /* Shows that IR is working via the LED */
- tm6000_flash_led(dev, 0);
- msleep(100);
- tm6000_flash_led(dev, 1);
- ir->pwled = 1;
-
- return 0;
-}
-
-static void tm6000_ir_keydown(struct tm6000_IR *ir,
- const char *buf, unsigned int len)
-{
- u8 device, command;
- u32 scancode;
- enum rc_proto protocol;
-
- if (len < 1)
- return;
-
- command = buf[0];
- device = (len > 1 ? buf[1] : 0x0);
- switch (ir->rc_proto) {
- case RC_PROTO_BIT_RC5:
- protocol = RC_PROTO_RC5;
- scancode = RC_SCANCODE_RC5(device, command);
- break;
- case RC_PROTO_BIT_NEC:
- protocol = RC_PROTO_NEC;
- scancode = RC_SCANCODE_NEC(device, command);
- break;
- default:
- protocol = RC_PROTO_OTHER;
- scancode = RC_SCANCODE_OTHER(device << 8 | command);
- break;
- }
-
- dprintk(1, "%s, protocol: 0x%04x, scancode: 0x%08x\n",
- __func__, protocol, scancode);
- rc_keydown(ir->rc, protocol, scancode, 0);
-}
-
-static void tm6000_ir_urb_received(struct urb *urb)
-{
- struct tm6000_core *dev = urb->context;
- struct tm6000_IR *ir = dev->ir;
- char *buf;
-
- dprintk(2, "%s\n",__func__);
- if (urb->status < 0 || urb->actual_length <= 0) {
- printk(KERN_INFO "tm6000: IR URB failure: status: %i, length %i\n",
- urb->status, urb->actual_length);
- ir->submit_urb = 1;
- schedule_delayed_work(&ir->work, msecs_to_jiffies(URB_SUBMIT_DELAY));
- return;
- }
- buf = urb->transfer_buffer;
-
- if (ir_debug)
- print_hex_dump(KERN_DEBUG, "tm6000: IR data: ",
- DUMP_PREFIX_OFFSET,16, 1,
- buf, urb->actual_length, false);
-
- tm6000_ir_keydown(ir, urb->transfer_buffer, urb->actual_length);
-
- usb_submit_urb(urb, GFP_ATOMIC);
- /*
- * Flash the led. We can't do it here, as it is running on IRQ context.
- * So, use the scheduler to do it, in a few ms.
- */
- ir->pwled = 2;
- schedule_delayed_work(&ir->work, msecs_to_jiffies(10));
-}
-
-static void tm6000_ir_handle_key(struct work_struct *work)
-{
- struct tm6000_IR *ir = container_of(work, struct tm6000_IR, work.work);
- struct tm6000_core *dev = ir->dev;
- int rc;
- u8 buf[2];
-
- if (ir->wait)
- return;
-
- dprintk(3, "%s\n",__func__);
-
- rc = tm6000_read_write_usb(dev, USB_DIR_IN |
- USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- REQ_02_GET_IR_CODE, 0, 0, buf, 2);
- if (rc < 0)
- return;
-
- /* Check if something was read */
- if ((buf[0] & 0xff) == 0xff) {
- if (!ir->pwled) {
- tm6000_flash_led(dev, 1);
- ir->pwled = 1;
- }
- return;
- }
-
- tm6000_ir_keydown(ir, buf, rc);
- tm6000_flash_led(dev, 0);
- ir->pwled = 0;
-
- /* Re-schedule polling */
- schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
-}
-
-static void tm6000_ir_int_work(struct work_struct *work)
-{
- struct tm6000_IR *ir = container_of(work, struct tm6000_IR, work.work);
- struct tm6000_core *dev = ir->dev;
- int rc;
-
- dprintk(3, "%s, submit_urb = %d, pwled = %d\n",__func__, ir->submit_urb,
- ir->pwled);
-
- if (ir->submit_urb) {
- dprintk(3, "Resubmit urb\n");
- tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 0);
-
- rc = usb_submit_urb(ir->int_urb, GFP_ATOMIC);
- if (rc < 0) {
- printk(KERN_ERR "tm6000: Can't submit an IR interrupt. Error %i\n",
- rc);
- /* Retry in 100 ms */
- schedule_delayed_work(&ir->work, msecs_to_jiffies(URB_SUBMIT_DELAY));
- return;
- }
- ir->submit_urb = 0;
- }
-
- /* Led is enabled only if USB submit doesn't fail */
- if (ir->pwled == 2) {
- tm6000_flash_led(dev, 0);
- ir->pwled = 0;
- schedule_delayed_work(&ir->work, msecs_to_jiffies(URB_INT_LED_DELAY));
- } else if (!ir->pwled) {
- tm6000_flash_led(dev, 1);
- ir->pwled = 1;
- }
-}
-
-static int tm6000_ir_start(struct rc_dev *rc)
-{
- struct tm6000_IR *ir = rc->priv;
-
- dprintk(2, "%s\n",__func__);
-
- schedule_delayed_work(&ir->work, 0);
-
- return 0;
-}
-
-static void tm6000_ir_stop(struct rc_dev *rc)
-{
- struct tm6000_IR *ir = rc->priv;
-
- dprintk(2, "%s\n",__func__);
-
- cancel_delayed_work_sync(&ir->work);
-}
-
-static int tm6000_ir_change_protocol(struct rc_dev *rc, u64 *rc_proto)
-{
- struct tm6000_IR *ir = rc->priv;
-
- if (!ir)
- return 0;
-
- dprintk(2, "%s\n",__func__);
-
- ir->rc_proto = *rc_proto;
-
- tm6000_ir_config(ir);
- /* TODO */
- return 0;
-}
-
-static int __tm6000_ir_int_start(struct rc_dev *rc)
-{
- struct tm6000_IR *ir = rc->priv;
- struct tm6000_core *dev;
- int pipe, size;
- int err = -ENOMEM;
-
- if (!ir)
- return -ENODEV;
- dev = ir->dev;
-
- dprintk(2, "%s\n",__func__);
-
- ir->int_urb = usb_alloc_urb(0, GFP_ATOMIC);
- if (!ir->int_urb)
- return -ENOMEM;
-
- pipe = usb_rcvintpipe(dev->udev,
- dev->int_in.endp->desc.bEndpointAddress
- & USB_ENDPOINT_NUMBER_MASK);
-
- size = usb_maxpacket(dev->udev, pipe);
- dprintk(1, "IR max size: %d\n", size);
-
- ir->int_urb->transfer_buffer = kzalloc(size, GFP_ATOMIC);
- if (!ir->int_urb->transfer_buffer) {
- usb_free_urb(ir->int_urb);
- return err;
- }
- dprintk(1, "int interval: %d\n", dev->int_in.endp->desc.bInterval);
-
- usb_fill_int_urb(ir->int_urb, dev->udev, pipe,
- ir->int_urb->transfer_buffer, size,
- tm6000_ir_urb_received, dev,
- dev->int_in.endp->desc.bInterval);
-
- ir->submit_urb = 1;
- schedule_delayed_work(&ir->work, msecs_to_jiffies(URB_SUBMIT_DELAY));
-
- return 0;
-}
-
-static void __tm6000_ir_int_stop(struct rc_dev *rc)
-{
- struct tm6000_IR *ir = rc->priv;
-
- if (!ir || !ir->int_urb)
- return;
-
- dprintk(2, "%s\n",__func__);
-
- usb_kill_urb(ir->int_urb);
- kfree(ir->int_urb->transfer_buffer);
- usb_free_urb(ir->int_urb);
- ir->int_urb = NULL;
-}
-
-int tm6000_ir_int_start(struct tm6000_core *dev)
-{
- struct tm6000_IR *ir = dev->ir;
-
- if (!ir)
- return 0;
-
- return __tm6000_ir_int_start(ir->rc);
-}
-
-void tm6000_ir_int_stop(struct tm6000_core *dev)
-{
- struct tm6000_IR *ir = dev->ir;
-
- if (!ir || !ir->rc)
- return;
-
- __tm6000_ir_int_stop(ir->rc);
-}
-
-int tm6000_ir_init(struct tm6000_core *dev)
-{
- struct tm6000_IR *ir;
- struct rc_dev *rc;
- int err = -ENOMEM;
- u64 rc_proto;
-
- if (!enable_ir)
- return -ENODEV;
-
- if (!dev->caps.has_remote)
- return 0;
-
- if (!dev->ir_codes)
- return 0;
-
- ir = kzalloc(sizeof(*ir), GFP_ATOMIC);
- rc = rc_allocate_device(RC_DRIVER_SCANCODE);
- if (!ir || !rc)
- goto out;
-
- dprintk(2, "%s\n", __func__);
-
- /* record handles to ourself */
- ir->dev = dev;
- dev->ir = ir;
- ir->rc = rc;
-
- /* input setup */
- rc->allowed_protocols = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_NEC;
- /* Needed, in order to support NEC remotes with 24 or 32 bits */
- rc->scancode_mask = 0xffff;
- rc->priv = ir;
- rc->change_protocol = tm6000_ir_change_protocol;
- if (dev->int_in.endp) {
- rc->open = __tm6000_ir_int_start;
- rc->close = __tm6000_ir_int_stop;
- INIT_DELAYED_WORK(&ir->work, tm6000_ir_int_work);
- } else {
- rc->open = tm6000_ir_start;
- rc->close = tm6000_ir_stop;
- ir->polling = 50;
- INIT_DELAYED_WORK(&ir->work, tm6000_ir_handle_key);
- }
-
- snprintf(ir->name, sizeof(ir->name), "tm5600/60x0 IR (%s)",
- dev->name);
-
- usb_make_path(dev->udev, ir->phys, sizeof(ir->phys));
- strlcat(ir->phys, "/input0", sizeof(ir->phys));
-
- rc_proto = RC_PROTO_BIT_UNKNOWN;
- tm6000_ir_change_protocol(rc, &rc_proto);
-
- rc->device_name = ir->name;
- rc->input_phys = ir->phys;
- rc->input_id.bustype = BUS_USB;
- rc->input_id.version = 1;
- rc->input_id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
- rc->input_id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
- rc->map_name = dev->ir_codes;
- rc->driver_name = "tm6000";
- rc->dev.parent = &dev->udev->dev;
-
- /* ir register */
- err = rc_register_device(rc);
- if (err)
- goto out;
-
- return 0;
-
-out:
- dev->ir = NULL;
- rc_free_device(rc);
- kfree(ir);
- return err;
-}
-
-int tm6000_ir_fini(struct tm6000_core *dev)
-{
- struct tm6000_IR *ir = dev->ir;
-
- /* skip detach on non attached board */
-
- if (!ir)
- return 0;
-
- dprintk(2, "%s\n",__func__);
-
- if (!ir->polling)
- __tm6000_ir_int_stop(ir->rc);
-
- tm6000_ir_stop(ir->rc);
-
- /* Turn off the led */
- tm6000_flash_led(dev, 0);
- ir->pwled = 0;
-
- rc_unregister_device(ir->rc);
-
- kfree(ir);
- dev->ir = NULL;
-
- return 0;
-}
diff --git a/drivers/staging/media/deprecated/tm6000/tm6000-regs.h b/drivers/staging/media/deprecated/tm6000/tm6000-regs.h
deleted file mode 100644
index 6a181f2e7ef2..000000000000
--- a/drivers/staging/media/deprecated/tm6000/tm6000-regs.h
+++ /dev/null
@@ -1,588 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * tm6000-regs.h - driver for TM5600/TM6000/TM6010 USB video capture devices
- *
- * Copyright (c) 2006-2007 Mauro Carvalho Chehab <mchehab@kernel.org>
- */
-
-/*
- * Define TV Master TM5600/TM6000/TM6010 Request codes
- */
-#define REQ_00_SET_IR_VALUE 0
-#define REQ_01_SET_WAKEUP_IRCODE 1
-#define REQ_02_GET_IR_CODE 2
-#define REQ_03_SET_GET_MCU_PIN 3
-#define REQ_04_EN_DISABLE_MCU_INT 4
-#define REQ_05_SET_GET_USBREG 5
- /* Write: RegNum, Value, 0 */
- /* Read : RegNum, Value, 1, RegStatus */
-#define REQ_06_SET_GET_USBREG_BIT 6
-#define REQ_07_SET_GET_AVREG 7
- /* Write: RegNum, Value, 0 */
- /* Read : RegNum, Value, 1, RegStatus */
-#define REQ_08_SET_GET_AVREG_BIT 8
-#define REQ_09_SET_GET_TUNER_FQ 9
-#define REQ_10_SET_TUNER_SYSTEM 10
-#define REQ_11_SET_EEPROM_ADDR 11
-#define REQ_12_SET_GET_EEPROMBYTE 12
-#define REQ_13_GET_EEPROM_SEQREAD 13
-#define REQ_14_SET_GET_I2C_WR2_RDN 14
-#define REQ_15_SET_GET_I2CBYTE 15
- /* Write: Subaddr, Slave Addr, value, 0 */
- /* Read : Subaddr, Slave Addr, value, 1 */
-#define REQ_16_SET_GET_I2C_WR1_RDN 16
- /* Subaddr, Slave Addr, 0, length */
-#define REQ_17_SET_GET_I2CFP 17
- /* Write: Slave Addr, register, value */
- /* Read : Slave Addr, register, 2, data */
-#define REQ_20_DATA_TRANSFER 20
-#define REQ_30_I2C_WRITE 30
-#define REQ_31_I2C_READ 31
-#define REQ_35_AFTEK_TUNER_READ 35
-#define REQ_40_GET_VERSION 40
-#define REQ_50_SET_START 50
-#define REQ_51_SET_STOP 51
-#define REQ_52_TRANSMIT_DATA 52
-#define REQ_53_SPI_INITIAL 53
-#define REQ_54_SPI_SETSTART 54
-#define REQ_55_SPI_INOUTDATA 55
-#define REQ_56_SPI_SETSTOP 56
-
-/*
- * Define TV Master TM5600/TM6000/TM6010 GPIO lines
- */
-
-#define TM6000_GPIO_CLK 0x101
-#define TM6000_GPIO_DATA 0x100
-
-#define TM6000_GPIO_1 0x102
-#define TM6000_GPIO_2 0x103
-#define TM6000_GPIO_3 0x104
-#define TM6000_GPIO_4 0x300
-#define TM6000_GPIO_5 0x301
-#define TM6000_GPIO_6 0x304
-#define TM6000_GPIO_7 0x305
-
-/* tm6010 defines GPIO with different values */
-#define TM6010_GPIO_0 0x0102
-#define TM6010_GPIO_1 0x0103
-#define TM6010_GPIO_2 0x0104
-#define TM6010_GPIO_3 0x0105
-#define TM6010_GPIO_4 0x0106
-#define TM6010_GPIO_5 0x0107
-#define TM6010_GPIO_6 0x0300
-#define TM6010_GPIO_7 0x0301
-#define TM6010_GPIO_9 0x0305
-/*
- * Define TV Master TM5600/TM6000/TM6010 URB message codes and length
- */
-
-enum {
- TM6000_URB_MSG_VIDEO = 1,
- TM6000_URB_MSG_AUDIO,
- TM6000_URB_MSG_VBI,
- TM6000_URB_MSG_PTS,
- TM6000_URB_MSG_ERR,
-};
-
-/* Define specific TM6000 Video decoder registers */
-#define TM6000_REQ07_RD8_TEST_SEL 0x07, 0xd8
-#define TM6000_REQ07_RD9_A_SIM_SEL 0x07, 0xd9
-#define TM6000_REQ07_RDA_CLK_SEL 0x07, 0xda
-#define TM6000_REQ07_RDB_OUT_SEL 0x07, 0xdb
-#define TM6000_REQ07_RDC_NSEL_I2S 0x07, 0xdc
-#define TM6000_REQ07_RDD_GPIO2_MDRV 0x07, 0xdd
-#define TM6000_REQ07_RDE_GPIO1_MDRV 0x07, 0xde
-#define TM6000_REQ07_RDF_PWDOWN_ACLK 0x07, 0xdf
-#define TM6000_REQ07_RE0_VADC_REF_CTL 0x07, 0xe0
-#define TM6000_REQ07_RE1_VADC_DACLIMP 0x07, 0xe1
-#define TM6000_REQ07_RE2_VADC_STATUS_CTL 0x07, 0xe2
-#define TM6000_REQ07_RE3_VADC_INP_LPF_SEL1 0x07, 0xe3
-#define TM6000_REQ07_RE4_VADC_TARGET1 0x07, 0xe4
-#define TM6000_REQ07_RE5_VADC_INP_LPF_SEL2 0x07, 0xe5
-#define TM6000_REQ07_RE6_VADC_TARGET2 0x07, 0xe6
-#define TM6000_REQ07_RE7_VADC_AGAIN_CTL 0x07, 0xe7
-#define TM6000_REQ07_RE8_VADC_PWDOWN_CTL 0x07, 0xe8
-#define TM6000_REQ07_RE9_VADC_INPUT_CTL1 0x07, 0xe9
-#define TM6000_REQ07_REA_VADC_INPUT_CTL2 0x07, 0xea
-#define TM6000_REQ07_REB_VADC_AADC_MODE 0x07, 0xeb
-#define TM6000_REQ07_REC_VADC_AADC_LVOL 0x07, 0xec
-#define TM6000_REQ07_RED_VADC_AADC_RVOL 0x07, 0xed
-#define TM6000_REQ07_REE_VADC_CTRL_SEL_CONTROL 0x07, 0xee
-#define TM6000_REQ07_REF_VADC_GAIN_MAP_CTL 0x07, 0xef
-#define TM6000_REQ07_RFD_BIST_ERR_VST_LOW 0x07, 0xfd
-#define TM6000_REQ07_RFE_BIST_ERR_VST_HIGH 0x07, 0xfe
-
-/* Define TM6000/TM6010 Video decoder registers */
-#define TM6010_REQ07_R00_VIDEO_CONTROL0 0x07, 0x00
-#define TM6010_REQ07_R01_VIDEO_CONTROL1 0x07, 0x01
-#define TM6010_REQ07_R02_VIDEO_CONTROL2 0x07, 0x02
-#define TM6010_REQ07_R03_YC_SEP_CONTROL 0x07, 0x03
-#define TM6010_REQ07_R04_LUMA_HAGC_CONTROL 0x07, 0x04
-#define TM6010_REQ07_R05_NOISE_THRESHOLD 0x07, 0x05
-#define TM6010_REQ07_R06_AGC_GATE_THRESHOLD 0x07, 0x06
-#define TM6010_REQ07_R07_OUTPUT_CONTROL 0x07, 0x07
-#define TM6010_REQ07_R08_LUMA_CONTRAST_ADJ 0x07, 0x08
-#define TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ 0x07, 0x09
-#define TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ 0x07, 0x0a
-#define TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ 0x07, 0x0b
-#define TM6010_REQ07_R0C_CHROMA_AGC_CONTROL 0x07, 0x0c
-#define TM6010_REQ07_R0D_CHROMA_KILL_LEVEL 0x07, 0x0d
-#define TM6010_REQ07_R0F_CHROMA_AUTO_POSITION 0x07, 0x0f
-#define TM6010_REQ07_R10_AGC_PEAK_NOMINAL 0x07, 0x10
-#define TM6010_REQ07_R11_AGC_PEAK_CONTROL 0x07, 0x11
-#define TM6010_REQ07_R12_AGC_GATE_STARTH 0x07, 0x12
-#define TM6010_REQ07_R13_AGC_GATE_STARTL 0x07, 0x13
-#define TM6010_REQ07_R14_AGC_GATE_WIDTH 0x07, 0x14
-#define TM6010_REQ07_R15_AGC_BP_DELAY 0x07, 0x15
-#define TM6010_REQ07_R16_LOCK_COUNT 0x07, 0x16
-#define TM6010_REQ07_R17_HLOOP_MAXSTATE 0x07, 0x17
-#define TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3 0x07, 0x18
-#define TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2 0x07, 0x19
-#define TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1 0x07, 0x1a
-#define TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0 0x07, 0x1b
-#define TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3 0x07, 0x1c
-#define TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2 0x07, 0x1d
-#define TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1 0x07, 0x1e
-#define TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0 0x07, 0x1f
-#define TM6010_REQ07_R20_HSYNC_RISING_EDGE_TIME 0x07, 0x20
-#define TM6010_REQ07_R21_HSYNC_PHASE_OFFSET 0x07, 0x21
-#define TM6010_REQ07_R22_HSYNC_PLL_START_TIME 0x07, 0x22
-#define TM6010_REQ07_R23_HSYNC_PLL_END_TIME 0x07, 0x23
-#define TM6010_REQ07_R24_HSYNC_TIP_START_TIME 0x07, 0x24
-#define TM6010_REQ07_R25_HSYNC_TIP_END_TIME 0x07, 0x25
-#define TM6010_REQ07_R26_HSYNC_RISING_EDGE_START 0x07, 0x26
-#define TM6010_REQ07_R27_HSYNC_RISING_EDGE_END 0x07, 0x27
-#define TM6010_REQ07_R28_BACKPORCH_START 0x07, 0x28
-#define TM6010_REQ07_R29_BACKPORCH_END 0x07, 0x29
-#define TM6010_REQ07_R2A_HSYNC_FILTER_START 0x07, 0x2a
-#define TM6010_REQ07_R2B_HSYNC_FILTER_END 0x07, 0x2b
-#define TM6010_REQ07_R2C_CHROMA_BURST_START 0x07, 0x2c
-#define TM6010_REQ07_R2D_CHROMA_BURST_END 0x07, 0x2d
-#define TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART 0x07, 0x2e
-#define TM6010_REQ07_R2F_ACTIVE_VIDEO_HWIDTH 0x07, 0x2f
-#define TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART 0x07, 0x30
-#define TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT 0x07, 0x31
-#define TM6010_REQ07_R32_VSYNC_HLOCK_MIN 0x07, 0x32
-#define TM6010_REQ07_R33_VSYNC_HLOCK_MAX 0x07, 0x33
-#define TM6010_REQ07_R34_VSYNC_AGC_MIN 0x07, 0x34
-#define TM6010_REQ07_R35_VSYNC_AGC_MAX 0x07, 0x35
-#define TM6010_REQ07_R36_VSYNC_VBI_MIN 0x07, 0x36
-#define TM6010_REQ07_R37_VSYNC_VBI_MAX 0x07, 0x37
-#define TM6010_REQ07_R38_VSYNC_THRESHOLD 0x07, 0x38
-#define TM6010_REQ07_R39_VSYNC_TIME_CONSTANT 0x07, 0x39
-#define TM6010_REQ07_R3A_STATUS1 0x07, 0x3a
-#define TM6010_REQ07_R3B_STATUS2 0x07, 0x3b
-#define TM6010_REQ07_R3C_STATUS3 0x07, 0x3c
-#define TM6010_REQ07_R3F_RESET 0x07, 0x3f
-#define TM6010_REQ07_R40_TELETEXT_VBI_CODE0 0x07, 0x40
-#define TM6010_REQ07_R41_TELETEXT_VBI_CODE1 0x07, 0x41
-#define TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL 0x07, 0x42
-#define TM6010_REQ07_R43_VBI_DATA_TYPE_LINE7 0x07, 0x43
-#define TM6010_REQ07_R44_VBI_DATA_TYPE_LINE8 0x07, 0x44
-#define TM6010_REQ07_R45_VBI_DATA_TYPE_LINE9 0x07, 0x45
-#define TM6010_REQ07_R46_VBI_DATA_TYPE_LINE10 0x07, 0x46
-#define TM6010_REQ07_R47_VBI_DATA_TYPE_LINE11 0x07, 0x47
-#define TM6010_REQ07_R48_VBI_DATA_TYPE_LINE12 0x07, 0x48
-#define TM6010_REQ07_R49_VBI_DATA_TYPE_LINE13 0x07, 0x49
-#define TM6010_REQ07_R4A_VBI_DATA_TYPE_LINE14 0x07, 0x4a
-#define TM6010_REQ07_R4B_VBI_DATA_TYPE_LINE15 0x07, 0x4b
-#define TM6010_REQ07_R4C_VBI_DATA_TYPE_LINE16 0x07, 0x4c
-#define TM6010_REQ07_R4D_VBI_DATA_TYPE_LINE17 0x07, 0x4d
-#define TM6010_REQ07_R4E_VBI_DATA_TYPE_LINE18 0x07, 0x4e
-#define TM6010_REQ07_R4F_VBI_DATA_TYPE_LINE19 0x07, 0x4f
-#define TM6010_REQ07_R50_VBI_DATA_TYPE_LINE20 0x07, 0x50
-#define TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21 0x07, 0x51
-#define TM6010_REQ07_R52_VBI_DATA_TYPE_LINE22 0x07, 0x52
-#define TM6010_REQ07_R53_VBI_DATA_TYPE_LINE23 0x07, 0x53
-#define TM6010_REQ07_R54_VBI_DATA_TYPE_RLINES 0x07, 0x54
-#define TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN 0x07, 0x55
-#define TM6010_REQ07_R56_VBI_LOOP_FILTER_I_GAIN 0x07, 0x56
-#define TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN 0x07, 0x57
-#define TM6010_REQ07_R58_VBI_CAPTION_DTO1 0x07, 0x58
-#define TM6010_REQ07_R59_VBI_CAPTION_DTO0 0x07, 0x59
-#define TM6010_REQ07_R5A_VBI_TELETEXT_DTO1 0x07, 0x5a
-#define TM6010_REQ07_R5B_VBI_TELETEXT_DTO0 0x07, 0x5b
-#define TM6010_REQ07_R5C_VBI_WSS625_DTO1 0x07, 0x5c
-#define TM6010_REQ07_R5D_VBI_WSS625_DTO0 0x07, 0x5d
-#define TM6010_REQ07_R5E_VBI_CAPTION_FRAME_START 0x07, 0x5e
-#define TM6010_REQ07_R5F_VBI_WSS625_FRAME_START 0x07, 0x5f
-#define TM6010_REQ07_R60_TELETEXT_FRAME_START 0x07, 0x60
-#define TM6010_REQ07_R61_VBI_CCDATA1 0x07, 0x61
-#define TM6010_REQ07_R62_VBI_CCDATA2 0x07, 0x62
-#define TM6010_REQ07_R63_VBI_WSS625_DATA1 0x07, 0x63
-#define TM6010_REQ07_R64_VBI_WSS625_DATA2 0x07, 0x64
-#define TM6010_REQ07_R65_VBI_DATA_STATUS 0x07, 0x65
-#define TM6010_REQ07_R66_VBI_CAPTION_START 0x07, 0x66
-#define TM6010_REQ07_R67_VBI_WSS625_START 0x07, 0x67
-#define TM6010_REQ07_R68_VBI_TELETEXT_START 0x07, 0x68
-#define TM6010_REQ07_R70_HSYNC_DTO_INC_STATUS3 0x07, 0x70
-#define TM6010_REQ07_R71_HSYNC_DTO_INC_STATUS2 0x07, 0x71
-#define TM6010_REQ07_R72_HSYNC_DTO_INC_STATUS1 0x07, 0x72
-#define TM6010_REQ07_R73_HSYNC_DTO_INC_STATUS0 0x07, 0x73
-#define TM6010_REQ07_R74_CHROMA_DTO_INC_STATUS3 0x07, 0x74
-#define TM6010_REQ07_R75_CHROMA_DTO_INC_STATUS2 0x07, 0x75
-#define TM6010_REQ07_R76_CHROMA_DTO_INC_STATUS1 0x07, 0x76
-#define TM6010_REQ07_R77_CHROMA_DTO_INC_STATUS0 0x07, 0x77
-#define TM6010_REQ07_R78_AGC_AGAIN_STATUS 0x07, 0x78
-#define TM6010_REQ07_R79_AGC_DGAIN_STATUS 0x07, 0x79
-#define TM6010_REQ07_R7A_CHROMA_MAG_STATUS 0x07, 0x7a
-#define TM6010_REQ07_R7B_CHROMA_GAIN_STATUS1 0x07, 0x7b
-#define TM6010_REQ07_R7C_CHROMA_GAIN_STATUS0 0x07, 0x7c
-#define TM6010_REQ07_R7D_CORDIC_FREQ_STATUS 0x07, 0x7d
-#define TM6010_REQ07_R7F_STATUS_NOISE 0x07, 0x7f
-#define TM6010_REQ07_R80_COMB_FILTER_TRESHOLD 0x07, 0x80
-#define TM6010_REQ07_R82_COMB_FILTER_CONFIG 0x07, 0x82
-#define TM6010_REQ07_R83_CHROMA_LOCK_CONFIG 0x07, 0x83
-#define TM6010_REQ07_R84_NOISE_NTSC_C 0x07, 0x84
-#define TM6010_REQ07_R85_NOISE_PAL_C 0x07, 0x85
-#define TM6010_REQ07_R86_NOISE_PHASE_C 0x07, 0x86
-#define TM6010_REQ07_R87_NOISE_PHASE_Y 0x07, 0x87
-#define TM6010_REQ07_R8A_CHROMA_LOOPFILTER_STATE 0x07, 0x8a
-#define TM6010_REQ07_R8B_CHROMA_HRESAMPLER 0x07, 0x8b
-#define TM6010_REQ07_R8D_CPUMP_DELAY_ADJ 0x07, 0x8d
-#define TM6010_REQ07_R8E_CPUMP_ADJ 0x07, 0x8e
-#define TM6010_REQ07_R8F_CPUMP_DELAY 0x07, 0x8f
-
-/* Define TM6000/TM6010 Miscellaneous registers */
-#define TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE 0x07, 0xc0
-#define TM6010_REQ07_RC1_TRESHOLD 0x07, 0xc1
-#define TM6010_REQ07_RC2_HSYNC_WIDTH 0x07, 0xc2
-#define TM6010_REQ07_RC3_HSTART1 0x07, 0xc3
-#define TM6010_REQ07_RC4_HSTART0 0x07, 0xc4
-#define TM6010_REQ07_RC5_HEND1 0x07, 0xc5
-#define TM6010_REQ07_RC6_HEND0 0x07, 0xc6
-#define TM6010_REQ07_RC7_VSTART1 0x07, 0xc7
-#define TM6010_REQ07_RC8_VSTART0 0x07, 0xc8
-#define TM6010_REQ07_RC9_VEND1 0x07, 0xc9
-#define TM6010_REQ07_RCA_VEND0 0x07, 0xca
-#define TM6010_REQ07_RCB_DELAY 0x07, 0xcb
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RCC_ACTIVE_IF 0x07, 0xcc
-#define TM6010_REQ07_RCC_ACTIVE_IF_VIDEO_ENABLE (1 << 5)
-#define TM6010_REQ07_RCC_ACTIVE_IF_AUDIO_ENABLE (1 << 6)
-#define TM6010_REQ07_RD0_USB_PERIPHERY_CONTROL 0x07, 0xd0
-#define TM6010_REQ07_RD1_ADDR_FOR_REQ1 0x07, 0xd1
-#define TM6010_REQ07_RD2_ADDR_FOR_REQ2 0x07, 0xd2
-#define TM6010_REQ07_RD3_ADDR_FOR_REQ3 0x07, 0xd3
-#define TM6010_REQ07_RD4_ADDR_FOR_REQ4 0x07, 0xd4
-#define TM6010_REQ07_RD5_POWERSAVE 0x07, 0xd5
-#define TM6010_REQ07_RD6_ENDP_REQ1_REQ2 0x07, 0xd6
-#define TM6010_REQ07_RD7_ENDP_REQ3_REQ4 0x07, 0xd7
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RD8_IR 0x07, 0xd8
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RD9_IR_BSIZE 0x07, 0xd9
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RDA_IR_WAKEUP_SEL 0x07, 0xda
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RDB_IR_WAKEUP_ADD 0x07, 0xdb
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RDC_IR_LEADER1 0x07, 0xdc
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RDD_IR_LEADER0 0x07, 0xdd
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RDE_IR_PULSE_CNT1 0x07, 0xde
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RDF_IR_PULSE_CNT0 0x07, 0xdf
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RE0_DVIDEO_SOURCE 0x07, 0xe0
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RE0_DVIDEO_SOURCE_IF 0x07, 0xe1
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RE2_OUT_SEL2 0x07, 0xe2
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RE3_OUT_SEL1 0x07, 0xe3
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RE4_OUT_SEL0 0x07, 0xe4
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RE5_REMOTE_WAKEUP 0x07, 0xe5
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RE7_PUB_GPIO 0x07, 0xe7
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RE8_TYPESEL_MOS_I2S 0x07, 0xe8
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RE9_TYPESEL_MOS_TS 0x07, 0xe9
-/* ONLY for TM6010 */
-#define TM6010_REQ07_REA_TYPESEL_MOS_CCIR 0x07, 0xea
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RF0_BIST_CRC_RESULT0 0x07, 0xf0
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RF1_BIST_CRC_RESULT1 0x07, 0xf1
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RF2_BIST_CRC_RESULT2 0x07, 0xf2
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RF3_BIST_CRC_RESULT3 0x07, 0xf3
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RF4_BIST_ERR_VST2 0x07, 0xf4
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RF5_BIST_ERR_VST1 0x07, 0xf5
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RF6_BIST_ERR_VST0 0x07, 0xf6
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RF7_BIST 0x07, 0xf7
-/* ONLY for TM6010 */
-#define TM6010_REQ07_RFE_POWER_DOWN 0x07, 0xfe
-#define TM6010_REQ07_RFF_SOFT_RESET 0x07, 0xff
-
-/* Define TM6000/TM6010 USB registers */
-#define TM6010_REQ05_R00_MAIN_CTRL 0x05, 0x00
-#define TM6010_REQ05_R01_DEVADDR 0x05, 0x01
-#define TM6010_REQ05_R02_TEST 0x05, 0x02
-#define TM6010_REQ05_R04_SOFN0 0x05, 0x04
-#define TM6010_REQ05_R05_SOFN1 0x05, 0x05
-#define TM6010_REQ05_R06_SOFTM0 0x05, 0x06
-#define TM6010_REQ05_R07_SOFTM1 0x05, 0x07
-#define TM6010_REQ05_R08_PHY_TEST 0x05, 0x08
-#define TM6010_REQ05_R09_VCTL 0x05, 0x09
-#define TM6010_REQ05_R0A_VSTA 0x05, 0x0a
-#define TM6010_REQ05_R0B_CX_CFG 0x05, 0x0b
-#define TM6010_REQ05_R0C_ENDP0_REG0 0x05, 0x0c
-#define TM6010_REQ05_R10_GMASK 0x05, 0x10
-#define TM6010_REQ05_R11_IMASK0 0x05, 0x11
-#define TM6010_REQ05_R12_IMASK1 0x05, 0x12
-#define TM6010_REQ05_R13_IMASK2 0x05, 0x13
-#define TM6010_REQ05_R14_IMASK3 0x05, 0x14
-#define TM6010_REQ05_R15_IMASK4 0x05, 0x15
-#define TM6010_REQ05_R16_IMASK5 0x05, 0x16
-#define TM6010_REQ05_R17_IMASK6 0x05, 0x17
-#define TM6010_REQ05_R18_IMASK7 0x05, 0x18
-#define TM6010_REQ05_R19_ZEROP0 0x05, 0x19
-#define TM6010_REQ05_R1A_ZEROP1 0x05, 0x1a
-#define TM6010_REQ05_R1C_FIFO_EMP0 0x05, 0x1c
-#define TM6010_REQ05_R1D_FIFO_EMP1 0x05, 0x1d
-#define TM6010_REQ05_R20_IRQ_GROUP 0x05, 0x20
-#define TM6010_REQ05_R21_IRQ_SOURCE0 0x05, 0x21
-#define TM6010_REQ05_R22_IRQ_SOURCE1 0x05, 0x22
-#define TM6010_REQ05_R23_IRQ_SOURCE2 0x05, 0x23
-#define TM6010_REQ05_R24_IRQ_SOURCE3 0x05, 0x24
-#define TM6010_REQ05_R25_IRQ_SOURCE4 0x05, 0x25
-#define TM6010_REQ05_R26_IRQ_SOURCE5 0x05, 0x26
-#define TM6010_REQ05_R27_IRQ_SOURCE6 0x05, 0x27
-#define TM6010_REQ05_R28_IRQ_SOURCE7 0x05, 0x28
-#define TM6010_REQ05_R29_SEQ_ERR0 0x05, 0x29
-#define TM6010_REQ05_R2A_SEQ_ERR1 0x05, 0x2a
-#define TM6010_REQ05_R2B_SEQ_ABORT0 0x05, 0x2b
-#define TM6010_REQ05_R2C_SEQ_ABORT1 0x05, 0x2c
-#define TM6010_REQ05_R2D_TX_ZERO0 0x05, 0x2d
-#define TM6010_REQ05_R2E_TX_ZERO1 0x05, 0x2e
-#define TM6010_REQ05_R2F_IDLE_CNT 0x05, 0x2f
-#define TM6010_REQ05_R30_FNO_P1 0x05, 0x30
-#define TM6010_REQ05_R31_FNO_P2 0x05, 0x31
-#define TM6010_REQ05_R32_FNO_P3 0x05, 0x32
-#define TM6010_REQ05_R33_FNO_P4 0x05, 0x33
-#define TM6010_REQ05_R34_FNO_P5 0x05, 0x34
-#define TM6010_REQ05_R35_FNO_P6 0x05, 0x35
-#define TM6010_REQ05_R36_FNO_P7 0x05, 0x36
-#define TM6010_REQ05_R37_FNO_P8 0x05, 0x37
-#define TM6010_REQ05_R38_FNO_P9 0x05, 0x38
-#define TM6010_REQ05_R30_FNO_P10 0x05, 0x39
-#define TM6010_REQ05_R30_FNO_P11 0x05, 0x3a
-#define TM6010_REQ05_R30_FNO_P12 0x05, 0x3b
-#define TM6010_REQ05_R30_FNO_P13 0x05, 0x3c
-#define TM6010_REQ05_R30_FNO_P14 0x05, 0x3d
-#define TM6010_REQ05_R30_FNO_P15 0x05, 0x3e
-#define TM6010_REQ05_R40_IN_MAXPS_LOW1 0x05, 0x40
-#define TM6010_REQ05_R41_IN_MAXPS_HIGH1 0x05, 0x41
-#define TM6010_REQ05_R42_IN_MAXPS_LOW2 0x05, 0x42
-#define TM6010_REQ05_R43_IN_MAXPS_HIGH2 0x05, 0x43
-#define TM6010_REQ05_R44_IN_MAXPS_LOW3 0x05, 0x44
-#define TM6010_REQ05_R45_IN_MAXPS_HIGH3 0x05, 0x45
-#define TM6010_REQ05_R46_IN_MAXPS_LOW4 0x05, 0x46
-#define TM6010_REQ05_R47_IN_MAXPS_HIGH4 0x05, 0x47
-#define TM6010_REQ05_R48_IN_MAXPS_LOW5 0x05, 0x48
-#define TM6010_REQ05_R49_IN_MAXPS_HIGH5 0x05, 0x49
-#define TM6010_REQ05_R4A_IN_MAXPS_LOW6 0x05, 0x4a
-#define TM6010_REQ05_R4B_IN_MAXPS_HIGH6 0x05, 0x4b
-#define TM6010_REQ05_R4C_IN_MAXPS_LOW7 0x05, 0x4c
-#define TM6010_REQ05_R4D_IN_MAXPS_HIGH7 0x05, 0x4d
-#define TM6010_REQ05_R4E_IN_MAXPS_LOW8 0x05, 0x4e
-#define TM6010_REQ05_R4F_IN_MAXPS_HIGH8 0x05, 0x4f
-#define TM6010_REQ05_R50_IN_MAXPS_LOW9 0x05, 0x50
-#define TM6010_REQ05_R51_IN_MAXPS_HIGH9 0x05, 0x51
-#define TM6010_REQ05_R40_IN_MAXPS_LOW10 0x05, 0x52
-#define TM6010_REQ05_R41_IN_MAXPS_HIGH10 0x05, 0x53
-#define TM6010_REQ05_R40_IN_MAXPS_LOW11 0x05, 0x54
-#define TM6010_REQ05_R41_IN_MAXPS_HIGH11 0x05, 0x55
-#define TM6010_REQ05_R40_IN_MAXPS_LOW12 0x05, 0x56
-#define TM6010_REQ05_R41_IN_MAXPS_HIGH12 0x05, 0x57
-#define TM6010_REQ05_R40_IN_MAXPS_LOW13 0x05, 0x58
-#define TM6010_REQ05_R41_IN_MAXPS_HIGH13 0x05, 0x59
-#define TM6010_REQ05_R40_IN_MAXPS_LOW14 0x05, 0x5a
-#define TM6010_REQ05_R41_IN_MAXPS_HIGH14 0x05, 0x5b
-#define TM6010_REQ05_R40_IN_MAXPS_LOW15 0x05, 0x5c
-#define TM6010_REQ05_R41_IN_MAXPS_HIGH15 0x05, 0x5d
-#define TM6010_REQ05_R60_OUT_MAXPS_LOW1 0x05, 0x60
-#define TM6010_REQ05_R61_OUT_MAXPS_HIGH1 0x05, 0x61
-#define TM6010_REQ05_R62_OUT_MAXPS_LOW2 0x05, 0x62
-#define TM6010_REQ05_R63_OUT_MAXPS_HIGH2 0x05, 0x63
-#define TM6010_REQ05_R64_OUT_MAXPS_LOW3 0x05, 0x64
-#define TM6010_REQ05_R65_OUT_MAXPS_HIGH3 0x05, 0x65
-#define TM6010_REQ05_R66_OUT_MAXPS_LOW4 0x05, 0x66
-#define TM6010_REQ05_R67_OUT_MAXPS_HIGH4 0x05, 0x67
-#define TM6010_REQ05_R68_OUT_MAXPS_LOW5 0x05, 0x68
-#define TM6010_REQ05_R69_OUT_MAXPS_HIGH5 0x05, 0x69
-#define TM6010_REQ05_R6A_OUT_MAXPS_LOW6 0x05, 0x6a
-#define TM6010_REQ05_R6B_OUT_MAXPS_HIGH6 0x05, 0x6b
-#define TM6010_REQ05_R6C_OUT_MAXPS_LOW7 0x05, 0x6c
-#define TM6010_REQ05_R6D_OUT_MAXPS_HIGH7 0x05, 0x6d
-#define TM6010_REQ05_R6E_OUT_MAXPS_LOW8 0x05, 0x6e
-#define TM6010_REQ05_R6F_OUT_MAXPS_HIGH8 0x05, 0x6f
-#define TM6010_REQ05_R70_OUT_MAXPS_LOW9 0x05, 0x70
-#define TM6010_REQ05_R71_OUT_MAXPS_HIGH9 0x05, 0x71
-#define TM6010_REQ05_R60_OUT_MAXPS_LOW10 0x05, 0x72
-#define TM6010_REQ05_R61_OUT_MAXPS_HIGH10 0x05, 0x73
-#define TM6010_REQ05_R60_OUT_MAXPS_LOW11 0x05, 0x74
-#define TM6010_REQ05_R61_OUT_MAXPS_HIGH11 0x05, 0x75
-#define TM6010_REQ05_R60_OUT_MAXPS_LOW12 0x05, 0x76
-#define TM6010_REQ05_R61_OUT_MAXPS_HIGH12 0x05, 0x77
-#define TM6010_REQ05_R60_OUT_MAXPS_LOW13 0x05, 0x78
-#define TM6010_REQ05_R61_OUT_MAXPS_HIGH13 0x05, 0x79
-#define TM6010_REQ05_R60_OUT_MAXPS_LOW14 0x05, 0x7a
-#define TM6010_REQ05_R61_OUT_MAXPS_HIGH14 0x05, 0x7b
-#define TM6010_REQ05_R60_OUT_MAXPS_LOW15 0x05, 0x7c
-#define TM6010_REQ05_R61_OUT_MAXPS_HIGH15 0x05, 0x7d
-#define TM6010_REQ05_R80_FIFO0 0x05, 0x80
-#define TM6010_REQ05_R81_FIFO1 0x05, 0x81
-#define TM6010_REQ05_R82_FIFO2 0x05, 0x82
-#define TM6010_REQ05_R83_FIFO3 0x05, 0x83
-#define TM6010_REQ05_R84_FIFO4 0x05, 0x84
-#define TM6010_REQ05_R85_FIFO5 0x05, 0x85
-#define TM6010_REQ05_R86_FIFO6 0x05, 0x86
-#define TM6010_REQ05_R87_FIFO7 0x05, 0x87
-#define TM6010_REQ05_R88_FIFO8 0x05, 0x88
-#define TM6010_REQ05_R89_FIFO9 0x05, 0x89
-#define TM6010_REQ05_R81_FIFO10 0x05, 0x8a
-#define TM6010_REQ05_R81_FIFO11 0x05, 0x8b
-#define TM6010_REQ05_R81_FIFO12 0x05, 0x8c
-#define TM6010_REQ05_R81_FIFO13 0x05, 0x8d
-#define TM6010_REQ05_R81_FIFO14 0x05, 0x8e
-#define TM6010_REQ05_R81_FIFO15 0x05, 0x8f
-#define TM6010_REQ05_R90_CFG_FIFO0 0x05, 0x90
-#define TM6010_REQ05_R91_CFG_FIFO1 0x05, 0x91
-#define TM6010_REQ05_R92_CFG_FIFO2 0x05, 0x92
-#define TM6010_REQ05_R93_CFG_FIFO3 0x05, 0x93
-#define TM6010_REQ05_R94_CFG_FIFO4 0x05, 0x94
-#define TM6010_REQ05_R95_CFG_FIFO5 0x05, 0x95
-#define TM6010_REQ05_R96_CFG_FIFO6 0x05, 0x96
-#define TM6010_REQ05_R97_CFG_FIFO7 0x05, 0x97
-#define TM6010_REQ05_R98_CFG_FIFO8 0x05, 0x98
-#define TM6010_REQ05_R99_CFG_FIFO9 0x05, 0x99
-#define TM6010_REQ05_R91_CFG_FIFO10 0x05, 0x9a
-#define TM6010_REQ05_R91_CFG_FIFO11 0x05, 0x9b
-#define TM6010_REQ05_R91_CFG_FIFO12 0x05, 0x9c
-#define TM6010_REQ05_R91_CFG_FIFO13 0x05, 0x9d
-#define TM6010_REQ05_R91_CFG_FIFO14 0x05, 0x9e
-#define TM6010_REQ05_R91_CFG_FIFO15 0x05, 0x9f
-#define TM6010_REQ05_RA0_CTL_FIFO0 0x05, 0xa0
-#define TM6010_REQ05_RA1_CTL_FIFO1 0x05, 0xa1
-#define TM6010_REQ05_RA2_CTL_FIFO2 0x05, 0xa2
-#define TM6010_REQ05_RA3_CTL_FIFO3 0x05, 0xa3
-#define TM6010_REQ05_RA4_CTL_FIFO4 0x05, 0xa4
-#define TM6010_REQ05_RA5_CTL_FIFO5 0x05, 0xa5
-#define TM6010_REQ05_RA6_CTL_FIFO6 0x05, 0xa6
-#define TM6010_REQ05_RA7_CTL_FIFO7 0x05, 0xa7
-#define TM6010_REQ05_RA8_CTL_FIFO8 0x05, 0xa8
-#define TM6010_REQ05_RA9_CTL_FIFO9 0x05, 0xa9
-#define TM6010_REQ05_RA1_CTL_FIFO10 0x05, 0xaa
-#define TM6010_REQ05_RA1_CTL_FIFO11 0x05, 0xab
-#define TM6010_REQ05_RA1_CTL_FIFO12 0x05, 0xac
-#define TM6010_REQ05_RA1_CTL_FIFO13 0x05, 0xad
-#define TM6010_REQ05_RA1_CTL_FIFO14 0x05, 0xae
-#define TM6010_REQ05_RA1_CTL_FIFO15 0x05, 0xaf
-#define TM6010_REQ05_RB0_BC_LOW_FIFO0 0x05, 0xb0
-#define TM6010_REQ05_RB1_BC_LOW_FIFO1 0x05, 0xb1
-#define TM6010_REQ05_RB2_BC_LOW_FIFO2 0x05, 0xb2
-#define TM6010_REQ05_RB3_BC_LOW_FIFO3 0x05, 0xb3
-#define TM6010_REQ05_RB4_BC_LOW_FIFO4 0x05, 0xb4
-#define TM6010_REQ05_RB5_BC_LOW_FIFO5 0x05, 0xb5
-#define TM6010_REQ05_RB6_BC_LOW_FIFO6 0x05, 0xb6
-#define TM6010_REQ05_RB7_BC_LOW_FIFO7 0x05, 0xb7
-#define TM6010_REQ05_RB8_BC_LOW_FIFO8 0x05, 0xb8
-#define TM6010_REQ05_RB9_BC_LOW_FIFO9 0x05, 0xb9
-#define TM6010_REQ05_RB1_BC_LOW_FIFO10 0x05, 0xba
-#define TM6010_REQ05_RB1_BC_LOW_FIFO11 0x05, 0xbb
-#define TM6010_REQ05_RB1_BC_LOW_FIFO12 0x05, 0xbc
-#define TM6010_REQ05_RB1_BC_LOW_FIFO13 0x05, 0xbd
-#define TM6010_REQ05_RB1_BC_LOW_FIFO14 0x05, 0xbe
-#define TM6010_REQ05_RB1_BC_LOW_FIFO15 0x05, 0xbf
-#define TM6010_REQ05_RC0_DATA_FIFO0 0x05, 0xc0
-#define TM6010_REQ05_RC4_DATA_FIFO1 0x05, 0xc4
-#define TM6010_REQ05_RC8_DATA_FIFO2 0x05, 0xc8
-#define TM6010_REQ05_RCC_DATA_FIFO3 0x05, 0xcc
-#define TM6010_REQ05_RD0_DATA_FIFO4 0x05, 0xd0
-#define TM6010_REQ05_RD4_DATA_FIFO5 0x05, 0xd4
-#define TM6010_REQ05_RD8_DATA_FIFO6 0x05, 0xd8
-#define TM6010_REQ05_RDC_DATA_FIFO7 0x05, 0xdc
-#define TM6010_REQ05_RE0_DATA_FIFO8 0x05, 0xe0
-#define TM6010_REQ05_RE4_DATA_FIFO9 0x05, 0xe4
-#define TM6010_REQ05_RC4_DATA_FIFO10 0x05, 0xe8
-#define TM6010_REQ05_RC4_DATA_FIFO11 0x05, 0xec
-#define TM6010_REQ05_RC4_DATA_FIFO12 0x05, 0xf0
-#define TM6010_REQ05_RC4_DATA_FIFO13 0x05, 0xf4
-#define TM6010_REQ05_RC4_DATA_FIFO14 0x05, 0xf8
-#define TM6010_REQ05_RC4_DATA_FIFO15 0x05, 0xfc
-
-/* Define TM6010 Audio decoder registers */
-/* This core available only in TM6010 */
-#define TM6010_REQ08_R00_A_VERSION 0x08, 0x00
-#define TM6010_REQ08_R01_A_INIT 0x08, 0x01
-#define TM6010_REQ08_R02_A_FIX_GAIN_CTRL 0x08, 0x02
-#define TM6010_REQ08_R03_A_AUTO_GAIN_CTRL 0x08, 0x03
-#define TM6010_REQ08_R04_A_SIF_AMP_CTRL 0x08, 0x04
-#define TM6010_REQ08_R05_A_STANDARD_MOD 0x08, 0x05
-#define TM6010_REQ08_R06_A_SOUND_MOD 0x08, 0x06
-#define TM6010_REQ08_R07_A_LEFT_VOL 0x08, 0x07
-#define TM6010_REQ08_R08_A_RIGHT_VOL 0x08, 0x08
-#define TM6010_REQ08_R09_A_MAIN_VOL 0x08, 0x09
-#define TM6010_REQ08_R0A_A_I2S_MOD 0x08, 0x0a
-#define TM6010_REQ08_R0B_A_ASD_THRES1 0x08, 0x0b
-#define TM6010_REQ08_R0C_A_ASD_THRES2 0x08, 0x0c
-#define TM6010_REQ08_R0D_A_AMD_THRES 0x08, 0x0d
-#define TM6010_REQ08_R0E_A_MONO_THRES1 0x08, 0x0e
-#define TM6010_REQ08_R0F_A_MONO_THRES2 0x08, 0x0f
-#define TM6010_REQ08_R10_A_MUTE_THRES1 0x08, 0x10
-#define TM6010_REQ08_R11_A_MUTE_THRES2 0x08, 0x11
-#define TM6010_REQ08_R12_A_AGC_U 0x08, 0x12
-#define TM6010_REQ08_R13_A_AGC_ERR_T 0x08, 0x13
-#define TM6010_REQ08_R14_A_AGC_GAIN_INIT 0x08, 0x14
-#define TM6010_REQ08_R15_A_AGC_STEP_THR 0x08, 0x15
-#define TM6010_REQ08_R16_A_AGC_GAIN_MAX 0x08, 0x16
-#define TM6010_REQ08_R17_A_AGC_GAIN_MIN 0x08, 0x17
-#define TM6010_REQ08_R18_A_TR_CTRL 0x08, 0x18
-#define TM6010_REQ08_R19_A_FH_2FH_GAIN 0x08, 0x19
-#define TM6010_REQ08_R1A_A_NICAM_SER_MAX 0x08, 0x1a
-#define TM6010_REQ08_R1B_A_NICAM_SER_MIN 0x08, 0x1b
-#define TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT 0x08, 0x1e
-#define TM6010_REQ08_R1F_A_TEST_INTF_SEL 0x08, 0x1f
-#define TM6010_REQ08_R20_A_TEST_PIN_SEL 0x08, 0x20
-#define TM6010_REQ08_R21_A_AGC_ERR 0x08, 0x21
-#define TM6010_REQ08_R22_A_AGC_GAIN 0x08, 0x22
-#define TM6010_REQ08_R23_A_NICAM_INFO 0x08, 0x23
-#define TM6010_REQ08_R24_A_SER 0x08, 0x24
-#define TM6010_REQ08_R25_A_C1_AMP 0x08, 0x25
-#define TM6010_REQ08_R26_A_C2_AMP 0x08, 0x26
-#define TM6010_REQ08_R27_A_NOISE_AMP 0x08, 0x27
-#define TM6010_REQ08_R28_A_AUDIO_MODE_RES 0x08, 0x28
-
-/* Define TM6010 Video ADC registers */
-#define TM6010_REQ08_RE0_ADC_REF 0x08, 0xe0
-#define TM6010_REQ08_RE1_DAC_CLMP 0x08, 0xe1
-#define TM6010_REQ08_RE2_POWER_DOWN_CTRL1 0x08, 0xe2
-#define TM6010_REQ08_RE3_ADC_IN1_SEL 0x08, 0xe3
-#define TM6010_REQ08_RE4_ADC_IN2_SEL 0x08, 0xe4
-#define TM6010_REQ08_RE5_GAIN_PARAM 0x08, 0xe5
-#define TM6010_REQ08_RE6_POWER_DOWN_CTRL2 0x08, 0xe6
-#define TM6010_REQ08_RE7_REG_GAIN_Y 0x08, 0xe7
-#define TM6010_REQ08_RE8_REG_GAIN_C 0x08, 0xe8
-#define TM6010_REQ08_RE9_BIAS_CTRL 0x08, 0xe9
-#define TM6010_REQ08_REA_BUFF_DRV_CTRL 0x08, 0xea
-#define TM6010_REQ08_REB_SIF_GAIN_CTRL 0x08, 0xeb
-#define TM6010_REQ08_REC_REVERSE_YC_CTRL 0x08, 0xec
-#define TM6010_REQ08_RED_GAIN_SEL 0x08, 0xed
-
-/* Define TM6010 Audio ADC registers */
-#define TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG 0x08, 0xf0
-#define TM6010_REQ08_RF1_AADC_POWER_DOWN 0x08, 0xf1
-#define TM6010_REQ08_RF2_LEFT_CHANNEL_VOL 0x08, 0xf2
-#define TM6010_REQ08_RF3_RIGHT_CHANNEL_VOL 0x08, 0xf3
diff --git a/drivers/staging/media/deprecated/tm6000/tm6000-stds.c b/drivers/staging/media/deprecated/tm6000/tm6000-stds.c
deleted file mode 100644
index 858cb4f3a9ca..000000000000
--- a/drivers/staging/media/deprecated/tm6000/tm6000-stds.c
+++ /dev/null
@@ -1,623 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-// tm6000-stds.c - driver for TM5600/TM6000/TM6010 USB video capture devices
-//
-// Copyright (c) 2007 Mauro Carvalho Chehab <mchehab@kernel.org>
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include "tm6000.h"
-#include "tm6000-regs.h"
-
-static unsigned int tm6010_a_mode;
-module_param(tm6010_a_mode, int, 0644);
-MODULE_PARM_DESC(tm6010_a_mode, "set tm6010 sif audio mode");
-
-struct tm6000_reg_settings {
- unsigned char req;
- unsigned char reg;
- unsigned char value;
-};
-
-
-struct tm6000_std_settings {
- v4l2_std_id id;
- struct tm6000_reg_settings *common;
-};
-
-static struct tm6000_reg_settings composite_pal_m[] = {
- { TM6010_REQ07_R3F_RESET, 0x01 },
- { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x04 },
- { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e },
- { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
- { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00 },
- { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 },
- { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e },
- { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x83 },
- { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x0a },
- { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe0 },
- { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
- { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
- { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
- { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
- { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 },
- { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x20 },
- { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 },
- { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c },
- { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c },
- { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 },
- { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f },
- { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc },
- { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 },
- { TM6010_REQ07_R3F_RESET, 0x00 },
- { 0, 0, 0 }
-};
-
-static struct tm6000_reg_settings composite_pal_nc[] = {
- { TM6010_REQ07_R3F_RESET, 0x01 },
- { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x36 },
- { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e },
- { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
- { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02 },
- { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 },
- { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e },
- { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x91 },
- { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x1f },
- { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x0c },
- { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
- { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
- { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
- { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
- { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c },
- { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c },
- { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 },
- { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c },
- { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c },
- { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 },
- { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f },
- { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc },
- { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 },
- { TM6010_REQ07_R3F_RESET, 0x00 },
- { 0, 0, 0 }
-};
-
-static struct tm6000_reg_settings composite_pal[] = {
- { TM6010_REQ07_R3F_RESET, 0x01 },
- { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x32 },
- { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e },
- { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
- { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02 },
- { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 },
- { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x25 },
- { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0xd5 },
- { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x63 },
- { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x50 },
- { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
- { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
- { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
- { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
- { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c },
- { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c },
- { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 },
- { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c },
- { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c },
- { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 },
- { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f },
- { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc },
- { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 },
- { TM6010_REQ07_R3F_RESET, 0x00 },
- { 0, 0, 0 }
-};
-
-static struct tm6000_reg_settings composite_secam[] = {
- { TM6010_REQ07_R3F_RESET, 0x01 },
- { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x38 },
- { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e },
- { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
- { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02 },
- { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 },
- { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24 },
- { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92 },
- { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8 },
- { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xed },
- { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
- { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
- { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
- { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
- { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c },
- { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c },
- { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 },
- { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x2c },
- { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x18 },
- { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 },
- { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0xff },
- { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 },
- { TM6010_REQ07_R3F_RESET, 0x00 },
- { 0, 0, 0 }
-};
-
-static struct tm6000_reg_settings composite_ntsc[] = {
- { TM6010_REQ07_R3F_RESET, 0x01 },
- { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x00 },
- { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0f },
- { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
- { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00 },
- { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 },
- { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e },
- { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b },
- { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2 },
- { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9 },
- { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
- { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
- { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
- { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
- { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 },
- { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 },
- { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 },
- { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c },
- { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c },
- { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 },
- { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f },
- { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdd },
- { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 },
- { TM6010_REQ07_R3F_RESET, 0x00 },
- { 0, 0, 0 }
-};
-
-static struct tm6000_std_settings composite_stds[] = {
- { .id = V4L2_STD_PAL_M, .common = composite_pal_m, },
- { .id = V4L2_STD_PAL_Nc, .common = composite_pal_nc, },
- { .id = V4L2_STD_PAL, .common = composite_pal, },
- { .id = V4L2_STD_SECAM, .common = composite_secam, },
- { .id = V4L2_STD_NTSC, .common = composite_ntsc, },
-};
-
-static struct tm6000_reg_settings svideo_pal_m[] = {
- { TM6010_REQ07_R3F_RESET, 0x01 },
- { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x05 },
- { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e },
- { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
- { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04 },
- { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 },
- { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e },
- { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x83 },
- { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x0a },
- { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe0 },
- { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
- { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
- { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
- { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
- { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 },
- { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 },
- { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 },
- { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c },
- { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c },
- { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 },
- { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f },
- { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc },
- { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 },
- { TM6010_REQ07_R3F_RESET, 0x00 },
- { 0, 0, 0 }
-};
-
-static struct tm6000_reg_settings svideo_pal_nc[] = {
- { TM6010_REQ07_R3F_RESET, 0x01 },
- { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x37 },
- { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e },
- { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
- { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04 },
- { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 },
- { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e },
- { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x91 },
- { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x1f },
- { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x0c },
- { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
- { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
- { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
- { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
- { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 },
- { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 },
- { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 },
- { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c },
- { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c },
- { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 },
- { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f },
- { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc },
- { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 },
- { TM6010_REQ07_R3F_RESET, 0x00 },
- { 0, 0, 0 }
-};
-
-static struct tm6000_reg_settings svideo_pal[] = {
- { TM6010_REQ07_R3F_RESET, 0x01 },
- { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x33 },
- { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e },
- { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
- { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04 },
- { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x30 },
- { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x25 },
- { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0xd5 },
- { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x63 },
- { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x50 },
- { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
- { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
- { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
- { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
- { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c },
- { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2a },
- { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 },
- { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c },
- { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c },
- { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 },
- { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f },
- { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc },
- { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 },
- { TM6010_REQ07_R3F_RESET, 0x00 },
- { 0, 0, 0 }
-};
-
-static struct tm6000_reg_settings svideo_secam[] = {
- { TM6010_REQ07_R3F_RESET, 0x01 },
- { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x39 },
- { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e },
- { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
- { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x03 },
- { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 },
- { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24 },
- { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92 },
- { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8 },
- { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xed },
- { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
- { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
- { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
- { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
- { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c },
- { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2a },
- { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 },
- { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x2c },
- { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x18 },
- { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 },
- { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0xff },
- { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 },
- { TM6010_REQ07_R3F_RESET, 0x00 },
- { 0, 0, 0 }
-};
-
-static struct tm6000_reg_settings svideo_ntsc[] = {
- { TM6010_REQ07_R3F_RESET, 0x01 },
- { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x01 },
- { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0f },
- { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f },
- { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x03 },
- { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x30 },
- { TM6010_REQ07_R17_HLOOP_MAXSTATE, 0x8b },
- { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e },
- { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b },
- { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2 },
- { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9 },
- { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c },
- { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc },
- { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc },
- { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd },
- { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 },
- { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 },
- { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 },
- { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c },
- { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c },
- { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 },
- { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f },
- { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdd },
- { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 },
- { TM6010_REQ07_R3F_RESET, 0x00 },
- { 0, 0, 0 }
-};
-
-static struct tm6000_std_settings svideo_stds[] = {
- { .id = V4L2_STD_PAL_M, .common = svideo_pal_m, },
- { .id = V4L2_STD_PAL_Nc, .common = svideo_pal_nc, },
- { .id = V4L2_STD_PAL, .common = svideo_pal, },
- { .id = V4L2_STD_SECAM, .common = svideo_secam, },
- { .id = V4L2_STD_NTSC, .common = svideo_ntsc, },
-};
-
-static int tm6000_set_audio_std(struct tm6000_core *dev)
-{
- uint8_t areg_02 = 0x04; /* GC1 Fixed gain 0dB */
- uint8_t areg_05 = 0x01; /* Auto 4.5 = M Japan, Auto 6.5 = DK */
- uint8_t areg_06 = 0x02; /* Auto de-emphasis, manual channel mode */
-
- if (dev->radio) {
- tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x00);
- tm6000_set_reg(dev, TM6010_REQ08_R02_A_FIX_GAIN_CTRL, 0x04);
- tm6000_set_reg(dev, TM6010_REQ08_R03_A_AUTO_GAIN_CTRL, 0x00);
- tm6000_set_reg(dev, TM6010_REQ08_R04_A_SIF_AMP_CTRL, 0x80);
- tm6000_set_reg(dev, TM6010_REQ08_R05_A_STANDARD_MOD, 0x0c);
- /* set mono or stereo */
- if (dev->amode == V4L2_TUNER_MODE_MONO)
- tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x00);
- else if (dev->amode == V4L2_TUNER_MODE_STEREO)
- tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x02);
- tm6000_set_reg(dev, TM6010_REQ08_R09_A_MAIN_VOL, 0x18);
- tm6000_set_reg(dev, TM6010_REQ08_R0C_A_ASD_THRES2, 0x0a);
- tm6000_set_reg(dev, TM6010_REQ08_R0D_A_AMD_THRES, 0x40);
- tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfe);
- tm6000_set_reg(dev, TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT, 0x13);
- tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x80);
- tm6000_set_reg(dev, TM6010_REQ07_RFE_POWER_DOWN, 0xff);
- return 0;
- }
-
- /*
- * STD/MN shouldn't be affected by tm6010_a_mode, as there's just one
- * audio standard for each V4L2_STD type.
- */
- if ((dev->norm & V4L2_STD_NTSC) == V4L2_STD_NTSC_M_KR) {
- areg_05 |= 0x04;
- } else if ((dev->norm & V4L2_STD_NTSC) == V4L2_STD_NTSC_M_JP) {
- areg_05 |= 0x43;
- } else if (dev->norm & V4L2_STD_MN) {
- areg_05 |= 0x22;
- } else switch (tm6010_a_mode) {
- /* auto */
- case 0:
- if ((dev->norm & V4L2_STD_SECAM) == V4L2_STD_SECAM_L)
- areg_05 |= 0x00;
- else /* Other PAL/SECAM standards */
- areg_05 |= 0x10;
- break;
- /* A2 */
- case 1:
- if (dev->norm & V4L2_STD_DK)
- areg_05 = 0x09;
- else
- areg_05 = 0x05;
- break;
- /* NICAM */
- case 2:
- if (dev->norm & V4L2_STD_DK) {
- areg_05 = 0x06;
- } else if (dev->norm & V4L2_STD_PAL_I) {
- areg_05 = 0x08;
- } else if (dev->norm & V4L2_STD_SECAM_L) {
- areg_05 = 0x0a;
- areg_02 = 0x02;
- } else {
- areg_05 = 0x07;
- }
- break;
- /* other */
- case 3:
- if (dev->norm & V4L2_STD_DK) {
- areg_05 = 0x0b;
- } else {
- areg_05 = 0x02;
- }
- break;
- }
-
- tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x00);
- tm6000_set_reg(dev, TM6010_REQ08_R02_A_FIX_GAIN_CTRL, areg_02);
- tm6000_set_reg(dev, TM6010_REQ08_R03_A_AUTO_GAIN_CTRL, 0x00);
- tm6000_set_reg(dev, TM6010_REQ08_R04_A_SIF_AMP_CTRL, 0xa0);
- tm6000_set_reg(dev, TM6010_REQ08_R05_A_STANDARD_MOD, areg_05);
- tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, areg_06);
- tm6000_set_reg(dev, TM6010_REQ08_R07_A_LEFT_VOL, 0x00);
- tm6000_set_reg(dev, TM6010_REQ08_R08_A_RIGHT_VOL, 0x00);
- tm6000_set_reg(dev, TM6010_REQ08_R09_A_MAIN_VOL, 0x08);
- tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, 0x91);
- tm6000_set_reg(dev, TM6010_REQ08_R0B_A_ASD_THRES1, 0x20);
- tm6000_set_reg(dev, TM6010_REQ08_R0C_A_ASD_THRES2, 0x12);
- tm6000_set_reg(dev, TM6010_REQ08_R0D_A_AMD_THRES, 0x20);
- tm6000_set_reg(dev, TM6010_REQ08_R0E_A_MONO_THRES1, 0xf0);
- tm6000_set_reg(dev, TM6010_REQ08_R0F_A_MONO_THRES2, 0x80);
- tm6000_set_reg(dev, TM6010_REQ08_R10_A_MUTE_THRES1, 0xc0);
- tm6000_set_reg(dev, TM6010_REQ08_R11_A_MUTE_THRES2, 0x80);
- tm6000_set_reg(dev, TM6010_REQ08_R12_A_AGC_U, 0x12);
- tm6000_set_reg(dev, TM6010_REQ08_R13_A_AGC_ERR_T, 0xfe);
- tm6000_set_reg(dev, TM6010_REQ08_R14_A_AGC_GAIN_INIT, 0x20);
- tm6000_set_reg(dev, TM6010_REQ08_R15_A_AGC_STEP_THR, 0x14);
- tm6000_set_reg(dev, TM6010_REQ08_R16_A_AGC_GAIN_MAX, 0xfe);
- tm6000_set_reg(dev, TM6010_REQ08_R17_A_AGC_GAIN_MIN, 0x01);
- tm6000_set_reg(dev, TM6010_REQ08_R18_A_TR_CTRL, 0xa0);
- tm6000_set_reg(dev, TM6010_REQ08_R19_A_FH_2FH_GAIN, 0x32);
- tm6000_set_reg(dev, TM6010_REQ08_R1A_A_NICAM_SER_MAX, 0x64);
- tm6000_set_reg(dev, TM6010_REQ08_R1B_A_NICAM_SER_MIN, 0x20);
- tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0x1c, 0x00);
- tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0x1d, 0x00);
- tm6000_set_reg(dev, TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT, 0x13);
- tm6000_set_reg(dev, TM6010_REQ08_R1F_A_TEST_INTF_SEL, 0x00);
- tm6000_set_reg(dev, TM6010_REQ08_R20_A_TEST_PIN_SEL, 0x00);
- tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x80);
-
- return 0;
-}
-
-void tm6000_get_std_res(struct tm6000_core *dev)
-{
- /* Currently, those are the only supported resoltions */
- if (dev->norm & V4L2_STD_525_60)
- dev->height = 480;
- else
- dev->height = 576;
-
- dev->width = 720;
-}
-
-static int tm6000_load_std(struct tm6000_core *dev, struct tm6000_reg_settings *set)
-{
- int i, rc;
-
- /* Load board's initialization table */
- for (i = 0; set[i].req; i++) {
- rc = tm6000_set_reg(dev, set[i].req, set[i].reg, set[i].value);
- if (rc < 0) {
- printk(KERN_ERR "Error %i while setting req %d, reg %d to value %d\n",
- rc, set[i].req, set[i].reg, set[i].value);
- return rc;
- }
- }
-
- return 0;
-}
-
-int tm6000_set_standard(struct tm6000_core *dev)
-{
- struct tm6000_input *input;
- int i, rc = 0;
- u8 reg_07_fe = 0x8a;
- u8 reg_08_f1 = 0xfc;
- u8 reg_08_e2 = 0xf0;
- u8 reg_08_e6 = 0x0f;
-
- tm6000_get_std_res(dev);
-
- if (!dev->radio)
- input = &dev->vinput[dev->input];
- else
- input = &dev->rinput;
-
- if (dev->dev_type == TM6010) {
- switch (input->vmux) {
- case TM6000_VMUX_VIDEO_A:
- tm6000_set_reg(dev, TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4);
- tm6000_set_reg(dev, TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1);
- tm6000_set_reg(dev, TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0);
- tm6000_set_reg(dev, TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2);
- tm6000_set_reg(dev, TM6010_REQ08_RED_GAIN_SEL, 0xe8);
- reg_07_fe |= 0x01;
- break;
- case TM6000_VMUX_VIDEO_B:
- tm6000_set_reg(dev, TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8);
- tm6000_set_reg(dev, TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1);
- tm6000_set_reg(dev, TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0);
- tm6000_set_reg(dev, TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2);
- tm6000_set_reg(dev, TM6010_REQ08_RED_GAIN_SEL, 0xe8);
- reg_07_fe |= 0x01;
- break;
- case TM6000_VMUX_VIDEO_AB:
- tm6000_set_reg(dev, TM6010_REQ08_RE3_ADC_IN1_SEL, 0xfc);
- tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf8);
- reg_08_e6 = 0x00;
- tm6000_set_reg(dev, TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf2);
- tm6000_set_reg(dev, TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xf0);
- tm6000_set_reg(dev, TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2);
- tm6000_set_reg(dev, TM6010_REQ08_RED_GAIN_SEL, 0xe0);
- break;
- default:
- break;
- }
- switch (input->amux) {
- case TM6000_AMUX_ADC1:
- tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
- 0x00, 0x0f);
- /* Mux overflow workaround */
- tm6000_set_reg_mask(dev, TM6010_REQ07_R07_OUTPUT_CONTROL,
- 0x10, 0xf0);
- break;
- case TM6000_AMUX_ADC2:
- tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
- 0x08, 0x0f);
- /* Mux overflow workaround */
- tm6000_set_reg_mask(dev, TM6010_REQ07_R07_OUTPUT_CONTROL,
- 0x10, 0xf0);
- break;
- case TM6000_AMUX_SIF1:
- reg_08_e2 |= 0x02;
- reg_08_e6 = 0x08;
- reg_07_fe |= 0x40;
- reg_08_f1 |= 0x02;
- tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3);
- tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
- 0x02, 0x0f);
- /* Mux overflow workaround */
- tm6000_set_reg_mask(dev, TM6010_REQ07_R07_OUTPUT_CONTROL,
- 0x30, 0xf0);
- break;
- case TM6000_AMUX_SIF2:
- reg_08_e2 |= 0x02;
- reg_08_e6 = 0x08;
- reg_07_fe |= 0x40;
- reg_08_f1 |= 0x02;
- tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf7);
- tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
- 0x02, 0x0f);
- /* Mux overflow workaround */
- tm6000_set_reg_mask(dev, TM6010_REQ07_R07_OUTPUT_CONTROL,
- 0x30, 0xf0);
- break;
- default:
- break;
- }
- tm6000_set_reg(dev, TM6010_REQ08_RE2_POWER_DOWN_CTRL1, reg_08_e2);
- tm6000_set_reg(dev, TM6010_REQ08_RE6_POWER_DOWN_CTRL2, reg_08_e6);
- tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, reg_08_f1);
- tm6000_set_reg(dev, TM6010_REQ07_RFE_POWER_DOWN, reg_07_fe);
- } else {
- switch (input->vmux) {
- case TM6000_VMUX_VIDEO_A:
- tm6000_set_reg(dev, TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x10);
- tm6000_set_reg(dev, TM6000_REQ07_RE5_VADC_INP_LPF_SEL2, 0x00);
- tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0x0f);
- tm6000_set_reg(dev,
- REQ_03_SET_GET_MCU_PIN, input->v_gpio, 0);
- break;
- case TM6000_VMUX_VIDEO_B:
- tm6000_set_reg(dev, TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x00);
- tm6000_set_reg(dev, TM6000_REQ07_RE5_VADC_INP_LPF_SEL2, 0x00);
- tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0x0f);
- tm6000_set_reg(dev,
- REQ_03_SET_GET_MCU_PIN, input->v_gpio, 0);
- break;
- case TM6000_VMUX_VIDEO_AB:
- tm6000_set_reg(dev, TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x10);
- tm6000_set_reg(dev, TM6000_REQ07_RE5_VADC_INP_LPF_SEL2, 0x10);
- tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0x00);
- tm6000_set_reg(dev,
- REQ_03_SET_GET_MCU_PIN, input->v_gpio, 1);
- break;
- default:
- break;
- }
- switch (input->amux) {
- case TM6000_AMUX_ADC1:
- tm6000_set_reg_mask(dev,
- TM6000_REQ07_REB_VADC_AADC_MODE, 0x00, 0x0f);
- break;
- case TM6000_AMUX_ADC2:
- tm6000_set_reg_mask(dev,
- TM6000_REQ07_REB_VADC_AADC_MODE, 0x04, 0x0f);
- break;
- default:
- break;
- }
- }
- if (input->type == TM6000_INPUT_SVIDEO) {
- for (i = 0; i < ARRAY_SIZE(svideo_stds); i++) {
- if (dev->norm & svideo_stds[i].id) {
- rc = tm6000_load_std(dev, svideo_stds[i].common);
- goto ret;
- }
- }
- return -EINVAL;
- } else {
- for (i = 0; i < ARRAY_SIZE(composite_stds); i++) {
- if (dev->norm & composite_stds[i].id) {
- rc = tm6000_load_std(dev, composite_stds[i].common);
- goto ret;
- }
- }
- return -EINVAL;
- }
-
-ret:
- if (rc < 0)
- return rc;
-
- if ((dev->dev_type == TM6010) &&
- ((input->amux == TM6000_AMUX_SIF1) ||
- (input->amux == TM6000_AMUX_SIF2)))
- tm6000_set_audio_std(dev);
-
- msleep(40);
-
- return 0;
-}
diff --git a/drivers/staging/media/deprecated/tm6000/tm6000-usb-isoc.h b/drivers/staging/media/deprecated/tm6000/tm6000-usb-isoc.h
deleted file mode 100644
index e3c6933f854d..000000000000
--- a/drivers/staging/media/deprecated/tm6000/tm6000-usb-isoc.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * tm6000-buf.c - driver for TM5600/TM6000/TM6010 USB video capture devices
- *
- * Copyright (c) 2006-2007 Mauro Carvalho Chehab <mchehab@kernel.org>
- */
-
-#include <linux/videodev2.h>
-
-#define TM6000_URB_MSG_LEN 180
-
-struct usb_isoc_ctl {
- /* max packet size of isoc transaction */
- int max_pkt_size;
-
- /* number of allocated urbs */
- int num_bufs;
-
- /* urb for isoc transfers */
- struct urb **urb;
-
- /* transfer buffers for isoc transfer */
- char **transfer_buffer;
-
- /* Last buffer command and region */
- u8 cmd;
- int pos, size, pktsize;
-
- /* Last field: ODD or EVEN? */
- int vfield, field;
-
- /* Stores incomplete commands */
- u32 tmp_buf;
- int tmp_buf_len;
-
- /* Stores already requested buffers */
- struct tm6000_buffer *buf;
-};
diff --git a/drivers/staging/media/deprecated/tm6000/tm6000-video.c b/drivers/staging/media/deprecated/tm6000/tm6000-video.c
deleted file mode 100644
index e06ed21edbdd..000000000000
--- a/drivers/staging/media/deprecated/tm6000/tm6000-video.c
+++ /dev/null
@@ -1,1703 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-// tm6000-video.c - driver for TM5600/TM6000/TM6010 USB video capture devices
-//
-// Copyright (c) 2006-2007 Mauro Carvalho Chehab <mchehab@kernel.org>
-//
-// Copyright (c) 2007 Michel Ludwig <michel.ludwig@gmail.com>
-// - Fixed module load/unload
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/random.h>
-#include <linux/usb.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-event.h>
-#include <media/tuner.h>
-#include <linux/interrupt.h>
-#include <linux/kthread.h>
-#include <linux/highmem.h>
-#include <linux/freezer.h>
-
-#include "tm6000-regs.h"
-#include "tm6000.h"
-
-#define BUFFER_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */
-
-/* Limits minimum and default number of buffers */
-#define TM6000_MIN_BUF 4
-#define TM6000_DEF_BUF 8
-
-#define TM6000_NUM_URB_BUF 8
-
-#define TM6000_MAX_ISO_PACKETS 46 /* Max number of ISO packets */
-
-/* Declare static vars that will be used as parameters */
-static unsigned int vid_limit = 16; /* Video memory limit, in Mb */
-static int video_nr = -1; /* /dev/videoN, -1 for autodetect */
-static int radio_nr = -1; /* /dev/radioN, -1 for autodetect */
-static bool keep_urb; /* keep urb buffers allocated */
-
-/* Debug level */
-int tm6000_debug;
-EXPORT_SYMBOL_GPL(tm6000_debug);
-
-static struct tm6000_fmt format[] = {
- {
- .fourcc = V4L2_PIX_FMT_YUYV,
- .depth = 16,
- }, {
- .fourcc = V4L2_PIX_FMT_UYVY,
- .depth = 16,
- }, {
- .fourcc = V4L2_PIX_FMT_TM6000,
- .depth = 16,
- }
-};
-
-/* ------------------------------------------------------------------
- * DMA and thread functions
- * ------------------------------------------------------------------
- */
-
-#define norm_maxw(a) 720
-#define norm_maxh(a) 576
-
-#define norm_minw(a) norm_maxw(a)
-#define norm_minh(a) norm_maxh(a)
-
-/*
- * video-buf generic routine to get the next available buffer
- */
-static inline void get_next_buf(struct tm6000_dmaqueue *dma_q,
- struct tm6000_buffer **buf)
-{
- struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
-
- if (list_empty(&dma_q->active)) {
- dprintk(dev, V4L2_DEBUG_QUEUE, "No active queue to serve\n");
- *buf = NULL;
- return;
- }
-
- *buf = list_entry(dma_q->active.next,
- struct tm6000_buffer, vb.queue);
-}
-
-/*
- * Announces that a buffer were filled and request the next
- */
-static inline void buffer_filled(struct tm6000_core *dev,
- struct tm6000_dmaqueue *dma_q,
- struct tm6000_buffer *buf)
-{
- /* Advice that buffer was filled */
- dprintk(dev, V4L2_DEBUG_ISOC, "[%p/%d] wakeup\n", buf, buf->vb.i);
- buf->vb.state = VIDEOBUF_DONE;
- buf->vb.field_count++;
- buf->vb.ts = ktime_get_ns();
-
- list_del(&buf->vb.queue);
- wake_up(&buf->vb.done);
-}
-
-/*
- * Identify the tm5600/6000 buffer header type and properly handles
- */
-static int copy_streams(u8 *data, unsigned long len,
- struct urb *urb)
-{
- struct tm6000_dmaqueue *dma_q = urb->context;
- struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
- u8 *ptr = data, *endp = data+len;
- unsigned long header = 0;
- int rc = 0;
- unsigned int cmd, cpysize, pktsize, size, field, block, line, pos = 0;
- struct tm6000_buffer *vbuf = NULL;
- char *voutp = NULL;
- unsigned int linewidth;
-
- if (!dev->radio) {
- /* get video buffer */
- get_next_buf(dma_q, &vbuf);
-
- if (!vbuf)
- return rc;
- voutp = videobuf_to_vmalloc(&vbuf->vb);
-
- if (!voutp)
- return 0;
- }
-
- for (ptr = data; ptr < endp;) {
- if (!dev->isoc_ctl.cmd) {
- /* Header */
- if (dev->isoc_ctl.tmp_buf_len > 0) {
- /* from last urb or packet */
- header = dev->isoc_ctl.tmp_buf;
- if (4 - dev->isoc_ctl.tmp_buf_len > 0) {
- memcpy((u8 *)&header +
- dev->isoc_ctl.tmp_buf_len,
- ptr,
- 4 - dev->isoc_ctl.tmp_buf_len);
- ptr += 4 - dev->isoc_ctl.tmp_buf_len;
- }
- dev->isoc_ctl.tmp_buf_len = 0;
- } else {
- if (ptr + 3 >= endp) {
- /* have incomplete header */
- dev->isoc_ctl.tmp_buf_len = endp - ptr;
- memcpy(&dev->isoc_ctl.tmp_buf, ptr,
- dev->isoc_ctl.tmp_buf_len);
- return rc;
- }
- /* Seek for sync */
- for (; ptr < endp - 3; ptr++) {
- if (*(ptr + 3) == 0x47)
- break;
- }
- /* Get message header */
- header = *(unsigned long *)ptr;
- ptr += 4;
- }
-
- /* split the header fields */
- size = ((header & 0x7e) << 1);
- if (size > 0)
- size -= 4;
- block = (header >> 7) & 0xf;
- field = (header >> 11) & 0x1;
- line = (header >> 12) & 0x1ff;
- cmd = (header >> 21) & 0x7;
- /* Validates header fields */
- if (size > TM6000_URB_MSG_LEN)
- size = TM6000_URB_MSG_LEN;
- pktsize = TM6000_URB_MSG_LEN;
- /*
- * calculate position in buffer and change the buffer
- */
- switch (cmd) {
- case TM6000_URB_MSG_VIDEO:
- if (!dev->radio) {
- if ((dev->isoc_ctl.vfield != field) &&
- (field == 1)) {
- /*
- * Announces that a new buffer
- * were filled
- */
- buffer_filled(dev, dma_q, vbuf);
- dprintk(dev, V4L2_DEBUG_ISOC,
- "new buffer filled\n");
- get_next_buf(dma_q, &vbuf);
- if (!vbuf)
- return rc;
- voutp = videobuf_to_vmalloc(&vbuf->vb);
- if (!voutp)
- return rc;
- memset(voutp, 0, vbuf->vb.size);
- }
- linewidth = vbuf->vb.width << 1;
- pos = ((line << 1) - field - 1) *
- linewidth + block * TM6000_URB_MSG_LEN;
- /* Don't allow to write out of the buffer */
- if (pos + size > vbuf->vb.size)
- cmd = TM6000_URB_MSG_ERR;
- dev->isoc_ctl.vfield = field;
- }
- break;
- case TM6000_URB_MSG_VBI:
- break;
- case TM6000_URB_MSG_AUDIO:
- case TM6000_URB_MSG_PTS:
- size = pktsize; /* Size is always 180 bytes */
- break;
- }
- } else {
- /* Continue the last copy */
- cmd = dev->isoc_ctl.cmd;
- size = dev->isoc_ctl.size;
- pos = dev->isoc_ctl.pos;
- pktsize = dev->isoc_ctl.pktsize;
- field = dev->isoc_ctl.field;
- }
- cpysize = (endp - ptr > size) ? size : endp - ptr;
- if (cpysize) {
- /* copy data in different buffers */
- switch (cmd) {
- case TM6000_URB_MSG_VIDEO:
- /* Fills video buffer */
- if (vbuf)
- memcpy(&voutp[pos], ptr, cpysize);
- break;
- case TM6000_URB_MSG_AUDIO: {
- int i;
- for (i = 0; i < cpysize; i += 2)
- swab16s((u16 *)(ptr + i));
-
- tm6000_call_fillbuf(dev, TM6000_AUDIO, ptr, cpysize);
- break;
- }
- case TM6000_URB_MSG_VBI:
- /* Need some code to copy vbi buffer */
- break;
- case TM6000_URB_MSG_PTS: {
- /* Need some code to copy pts */
- u32 pts;
- pts = *(u32 *)ptr;
- dprintk(dev, V4L2_DEBUG_ISOC, "field %d, PTS %x",
- field, pts);
- break;
- }
- }
- }
- if (ptr + pktsize > endp) {
- /*
- * End of URB packet, but cmd processing is not
- * complete. Preserve the state for a next packet
- */
- dev->isoc_ctl.pos = pos + cpysize;
- dev->isoc_ctl.size = size - cpysize;
- dev->isoc_ctl.cmd = cmd;
- dev->isoc_ctl.field = field;
- dev->isoc_ctl.pktsize = pktsize - (endp - ptr);
- ptr += endp - ptr;
- } else {
- dev->isoc_ctl.cmd = 0;
- ptr += pktsize;
- }
- }
- return 0;
-}
-
-/*
- * Identify the tm5600/6000 buffer header type and properly handles
- */
-static int copy_multiplexed(u8 *ptr, unsigned long len,
- struct urb *urb)
-{
- struct tm6000_dmaqueue *dma_q = urb->context;
- struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
- unsigned int pos = dev->isoc_ctl.pos, cpysize;
- int rc = 1;
- struct tm6000_buffer *buf;
- char *outp = NULL;
-
- get_next_buf(dma_q, &buf);
- if (buf)
- outp = videobuf_to_vmalloc(&buf->vb);
-
- if (!outp)
- return 0;
-
- while (len > 0) {
- cpysize = min(len, buf->vb.size-pos);
- memcpy(&outp[pos], ptr, cpysize);
- pos += cpysize;
- ptr += cpysize;
- len -= cpysize;
- if (pos >= buf->vb.size) {
- pos = 0;
- /* Announces that a new buffer were filled */
- buffer_filled(dev, dma_q, buf);
- dprintk(dev, V4L2_DEBUG_ISOC, "new buffer filled\n");
- get_next_buf(dma_q, &buf);
- if (!buf)
- break;
- outp = videobuf_to_vmalloc(&(buf->vb));
- if (!outp)
- return rc;
- pos = 0;
- }
- }
-
- dev->isoc_ctl.pos = pos;
- return rc;
-}
-
-static inline void print_err_status(struct tm6000_core *dev,
- int packet, int status)
-{
- char *errmsg = "Unknown";
-
- switch (status) {
- case -ENOENT:
- errmsg = "unlinked synchronously";
- break;
- case -ECONNRESET:
- errmsg = "unlinked asynchronously";
- break;
- case -ENOSR:
- errmsg = "Buffer error (overrun)";
- break;
- case -EPIPE:
- errmsg = "Stalled (device not responding)";
- break;
- case -EOVERFLOW:
- errmsg = "Babble (bad cable?)";
- break;
- case -EPROTO:
- errmsg = "Bit-stuff error (bad cable?)";
- break;
- case -EILSEQ:
- errmsg = "CRC/Timeout (could be anything)";
- break;
- case -ETIME:
- errmsg = "Device does not respond";
- break;
- }
- if (packet < 0) {
- dprintk(dev, V4L2_DEBUG_QUEUE, "URB status %d [%s].\n",
- status, errmsg);
- } else {
- dprintk(dev, V4L2_DEBUG_QUEUE, "URB packet %d, status %d [%s].\n",
- packet, status, errmsg);
- }
-}
-
-
-/*
- * Controls the isoc copy of each urb packet
- */
-static inline int tm6000_isoc_copy(struct urb *urb)
-{
- struct tm6000_dmaqueue *dma_q = urb->context;
- struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
- int i, len = 0, rc = 1, status;
- char *p;
-
- if (urb->status < 0) {
- print_err_status(dev, -1, urb->status);
- return 0;
- }
-
- for (i = 0; i < urb->number_of_packets; i++) {
- status = urb->iso_frame_desc[i].status;
-
- if (status < 0) {
- print_err_status(dev, i, status);
- continue;
- }
-
- len = urb->iso_frame_desc[i].actual_length;
-
- if (len > 0) {
- p = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
- if (!urb->iso_frame_desc[i].status) {
- if ((dev->fourcc) == V4L2_PIX_FMT_TM6000) {
- rc = copy_multiplexed(p, len, urb);
- if (rc <= 0)
- return rc;
- } else {
- copy_streams(p, len, urb);
- }
- }
- }
- }
- return rc;
-}
-
-/* ------------------------------------------------------------------
- * URB control
- * ------------------------------------------------------------------
- */
-
-/*
- * IRQ callback, called by URB callback
- */
-static void tm6000_irq_callback(struct urb *urb)
-{
- struct tm6000_dmaqueue *dma_q = urb->context;
- struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
- unsigned long flags;
- int i;
-
- switch (urb->status) {
- case 0:
- case -ETIMEDOUT:
- break;
-
- case -ECONNRESET:
- case -ENOENT:
- case -ESHUTDOWN:
- return;
-
- default:
- tm6000_err("urb completion error %d.\n", urb->status);
- break;
- }
-
- spin_lock_irqsave(&dev->slock, flags);
- tm6000_isoc_copy(urb);
- spin_unlock_irqrestore(&dev->slock, flags);
-
- /* Reset urb buffers */
- for (i = 0; i < urb->number_of_packets; i++) {
- urb->iso_frame_desc[i].status = 0;
- urb->iso_frame_desc[i].actual_length = 0;
- }
-
- urb->status = usb_submit_urb(urb, GFP_ATOMIC);
- if (urb->status)
- tm6000_err("urb resubmit failed (error=%i)\n",
- urb->status);
-}
-
-/*
- * Allocate URB buffers
- */
-static int tm6000_alloc_urb_buffers(struct tm6000_core *dev)
-{
- int num_bufs = TM6000_NUM_URB_BUF;
- int i;
-
- if (dev->urb_buffer)
- return 0;
-
- dev->urb_buffer = kmalloc_array(num_bufs, sizeof(*dev->urb_buffer),
- GFP_KERNEL);
- if (!dev->urb_buffer)
- return -ENOMEM;
-
- dev->urb_dma = kmalloc_array(num_bufs, sizeof(*dev->urb_dma),
- GFP_KERNEL);
- if (!dev->urb_dma)
- return -ENOMEM;
-
- for (i = 0; i < num_bufs; i++) {
- dev->urb_buffer[i] = usb_alloc_coherent(
- dev->udev, dev->urb_size,
- GFP_KERNEL, &dev->urb_dma[i]);
- if (!dev->urb_buffer[i]) {
- tm6000_err("unable to allocate %i bytes for transfer buffer %i\n",
- dev->urb_size, i);
- return -ENOMEM;
- }
- memset(dev->urb_buffer[i], 0, dev->urb_size);
- }
-
- return 0;
-}
-
-/*
- * Free URB buffers
- */
-static int tm6000_free_urb_buffers(struct tm6000_core *dev)
-{
- int i;
-
- if (!dev->urb_buffer)
- return 0;
-
- for (i = 0; i < TM6000_NUM_URB_BUF; i++) {
- if (dev->urb_buffer[i]) {
- usb_free_coherent(dev->udev,
- dev->urb_size,
- dev->urb_buffer[i],
- dev->urb_dma[i]);
- dev->urb_buffer[i] = NULL;
- }
- }
- kfree(dev->urb_buffer);
- kfree(dev->urb_dma);
- dev->urb_buffer = NULL;
- dev->urb_dma = NULL;
-
- return 0;
-}
-
-/*
- * Stop and Deallocate URBs
- */
-static void tm6000_uninit_isoc(struct tm6000_core *dev)
-{
- struct urb *urb;
- int i;
-
- dev->isoc_ctl.buf = NULL;
- for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
- urb = dev->isoc_ctl.urb[i];
- if (urb) {
- usb_kill_urb(urb);
- usb_unlink_urb(urb);
- usb_free_urb(urb);
- dev->isoc_ctl.urb[i] = NULL;
- }
- dev->isoc_ctl.transfer_buffer[i] = NULL;
- }
-
- if (!keep_urb)
- tm6000_free_urb_buffers(dev);
-
- kfree(dev->isoc_ctl.urb);
- kfree(dev->isoc_ctl.transfer_buffer);
-
- dev->isoc_ctl.urb = NULL;
- dev->isoc_ctl.transfer_buffer = NULL;
- dev->isoc_ctl.num_bufs = 0;
-}
-
-/*
- * Assign URBs and start IRQ
- */
-static int tm6000_prepare_isoc(struct tm6000_core *dev)
-{
- struct tm6000_dmaqueue *dma_q = &dev->vidq;
- int i, j, sb_size, pipe, size, max_packets;
- int num_bufs = TM6000_NUM_URB_BUF;
- struct urb *urb;
-
- /* De-allocates all pending stuff */
- tm6000_uninit_isoc(dev);
- /* Stop interrupt USB pipe */
- tm6000_ir_int_stop(dev);
-
- usb_set_interface(dev->udev,
- dev->isoc_in.bInterfaceNumber,
- dev->isoc_in.bAlternateSetting);
-
- /* Start interrupt USB pipe */
- tm6000_ir_int_start(dev);
-
- pipe = usb_rcvisocpipe(dev->udev,
- dev->isoc_in.endp->desc.bEndpointAddress &
- USB_ENDPOINT_NUMBER_MASK);
-
- size = usb_maxpacket(dev->udev, pipe);
-
- if (size > dev->isoc_in.maxsize)
- size = dev->isoc_in.maxsize;
-
- dev->isoc_ctl.max_pkt_size = size;
-
- max_packets = TM6000_MAX_ISO_PACKETS;
- sb_size = max_packets * size;
- dev->urb_size = sb_size;
-
- dev->isoc_ctl.num_bufs = num_bufs;
-
- dev->isoc_ctl.urb = kmalloc_array(num_bufs, sizeof(void *),
- GFP_KERNEL);
- if (!dev->isoc_ctl.urb)
- return -ENOMEM;
-
- dev->isoc_ctl.transfer_buffer = kmalloc_array(num_bufs,
- sizeof(void *),
- GFP_KERNEL);
- if (!dev->isoc_ctl.transfer_buffer) {
- kfree(dev->isoc_ctl.urb);
- return -ENOMEM;
- }
-
- dprintk(dev, V4L2_DEBUG_QUEUE, "Allocating %d x %d packets (%d bytes) of %d bytes each to handle %u size\n",
- max_packets, num_bufs, sb_size,
- dev->isoc_in.maxsize, size);
-
-
- if (tm6000_alloc_urb_buffers(dev) < 0) {
- tm6000_err("cannot allocate memory for urb buffers\n");
-
- /* call free, as some buffers might have been allocated */
- tm6000_free_urb_buffers(dev);
- kfree(dev->isoc_ctl.urb);
- kfree(dev->isoc_ctl.transfer_buffer);
- return -ENOMEM;
- }
-
- /* allocate urbs and transfer buffers */
- for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
- urb = usb_alloc_urb(max_packets, GFP_KERNEL);
- if (!urb) {
- tm6000_uninit_isoc(dev);
- tm6000_free_urb_buffers(dev);
- return -ENOMEM;
- }
- dev->isoc_ctl.urb[i] = urb;
-
- urb->transfer_dma = dev->urb_dma[i];
- dev->isoc_ctl.transfer_buffer[i] = dev->urb_buffer[i];
-
- usb_fill_bulk_urb(urb, dev->udev, pipe,
- dev->isoc_ctl.transfer_buffer[i], sb_size,
- tm6000_irq_callback, dma_q);
- urb->interval = dev->isoc_in.endp->desc.bInterval;
- urb->number_of_packets = max_packets;
- urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
-
- for (j = 0; j < max_packets; j++) {
- urb->iso_frame_desc[j].offset = size * j;
- urb->iso_frame_desc[j].length = size;
- }
- }
-
- return 0;
-}
-
-static int tm6000_start_thread(struct tm6000_core *dev)
-{
- struct tm6000_dmaqueue *dma_q = &dev->vidq;
- int i;
-
- dma_q->frame = 0;
- dma_q->ini_jiffies = jiffies;
-
- init_waitqueue_head(&dma_q->wq);
-
- /* submit urbs and enables IRQ */
- for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
- int rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC);
- if (rc) {
- tm6000_err("submit of urb %i failed (error=%i)\n", i,
- rc);
- tm6000_uninit_isoc(dev);
- return rc;
- }
- }
-
- return 0;
-}
-
-/* ------------------------------------------------------------------
- * Videobuf operations
- * ------------------------------------------------------------------
- */
-
-static int
-buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
-{
- struct tm6000_fh *fh = vq->priv_data;
-
- *size = fh->fmt->depth * fh->width * fh->height >> 3;
- if (0 == *count)
- *count = TM6000_DEF_BUF;
-
- if (*count < TM6000_MIN_BUF)
- *count = TM6000_MIN_BUF;
-
- while (*size * *count > vid_limit * 1024 * 1024)
- (*count)--;
-
- return 0;
-}
-
-static void free_buffer(struct videobuf_queue *vq, struct tm6000_buffer *buf)
-{
- struct tm6000_fh *fh = vq->priv_data;
- struct tm6000_core *dev = fh->dev;
- unsigned long flags;
-
- /* We used to wait for the buffer to finish here, but this didn't work
- because, as we were keeping the state as VIDEOBUF_QUEUED,
- videobuf_queue_cancel marked it as finished for us.
- (Also, it could wedge forever if the hardware was misconfigured.)
-
- This should be safe; by the time we get here, the buffer isn't
- queued anymore. If we ever start marking the buffers as
- VIDEOBUF_ACTIVE, it won't be, though.
- */
- spin_lock_irqsave(&dev->slock, flags);
- if (dev->isoc_ctl.buf == buf)
- dev->isoc_ctl.buf = NULL;
- spin_unlock_irqrestore(&dev->slock, flags);
-
- videobuf_vmalloc_free(&buf->vb);
- buf->vb.state = VIDEOBUF_NEEDS_INIT;
-}
-
-static int
-buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
- enum v4l2_field field)
-{
- struct tm6000_fh *fh = vq->priv_data;
- struct tm6000_buffer *buf = container_of(vb, struct tm6000_buffer, vb);
- struct tm6000_core *dev = fh->dev;
- int rc = 0;
-
- BUG_ON(NULL == fh->fmt);
-
-
- /* FIXME: It assumes depth=2 */
- /* The only currently supported format is 16 bits/pixel */
- buf->vb.size = fh->fmt->depth*fh->width*fh->height >> 3;
- if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
- return -EINVAL;
-
- if (buf->fmt != fh->fmt ||
- buf->vb.width != fh->width ||
- buf->vb.height != fh->height ||
- buf->vb.field != field) {
- buf->fmt = fh->fmt;
- buf->vb.width = fh->width;
- buf->vb.height = fh->height;
- buf->vb.field = field;
- buf->vb.state = VIDEOBUF_NEEDS_INIT;
- }
-
- if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- rc = videobuf_iolock(vq, &buf->vb, NULL);
- if (rc != 0)
- goto fail;
- }
-
- if (!dev->isoc_ctl.num_bufs) {
- rc = tm6000_prepare_isoc(dev);
- if (rc < 0)
- goto fail;
-
- rc = tm6000_start_thread(dev);
- if (rc < 0)
- goto fail;
-
- }
-
- buf->vb.state = VIDEOBUF_PREPARED;
- return 0;
-
-fail:
- free_buffer(vq, buf);
- return rc;
-}
-
-static void
-buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
- struct tm6000_buffer *buf = container_of(vb, struct tm6000_buffer, vb);
- struct tm6000_fh *fh = vq->priv_data;
- struct tm6000_core *dev = fh->dev;
- struct tm6000_dmaqueue *vidq = &dev->vidq;
-
- buf->vb.state = VIDEOBUF_QUEUED;
- list_add_tail(&buf->vb.queue, &vidq->active);
-}
-
-static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
- struct tm6000_buffer *buf = container_of(vb, struct tm6000_buffer, vb);
-
- free_buffer(vq, buf);
-}
-
-static const struct videobuf_queue_ops tm6000_video_qops = {
- .buf_setup = buffer_setup,
- .buf_prepare = buffer_prepare,
- .buf_queue = buffer_queue,
- .buf_release = buffer_release,
-};
-
-/* ------------------------------------------------------------------
- * IOCTL handling
- * ------------------------------------------------------------------
- */
-
-static bool is_res_read(struct tm6000_core *dev, struct tm6000_fh *fh)
-{
- /* Is the current fh handling it? if so, that's OK */
- if (dev->resources == fh && dev->is_res_read)
- return true;
-
- return false;
-}
-
-static bool is_res_streaming(struct tm6000_core *dev, struct tm6000_fh *fh)
-{
- /* Is the current fh handling it? if so, that's OK */
- if (dev->resources == fh)
- return true;
-
- return false;
-}
-
-static bool res_get(struct tm6000_core *dev, struct tm6000_fh *fh,
- bool is_res_read)
-{
- /* Is the current fh handling it? if so, that's OK */
- if (dev->resources == fh && dev->is_res_read == is_res_read)
- return true;
-
- /* is it free? */
- if (dev->resources)
- return false;
-
- /* grab it */
- dev->resources = fh;
- dev->is_res_read = is_res_read;
- dprintk(dev, V4L2_DEBUG_RES_LOCK, "res: get\n");
- return true;
-}
-
-static void res_free(struct tm6000_core *dev, struct tm6000_fh *fh)
-{
- /* Is the current fh handling it? if so, that's OK */
- if (dev->resources != fh)
- return;
-
- dev->resources = NULL;
- dprintk(dev, V4L2_DEBUG_RES_LOCK, "res: put\n");
-}
-
-/* ------------------------------------------------------------------
- * IOCTL vidioc handling
- * ------------------------------------------------------------------
- */
-static int vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
- struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev;
-
- strscpy(cap->driver, "tm6000", sizeof(cap->driver));
- strscpy(cap->card, "Trident TM5600/6000/6010", sizeof(cap->card));
- usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
- V4L2_CAP_DEVICE_CAPS;
- if (dev->tuner_type != TUNER_ABSENT)
- cap->capabilities |= V4L2_CAP_TUNER;
- if (dev->caps.has_radio)
- cap->capabilities |= V4L2_CAP_RADIO;
-
- return 0;
-}
-
-static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
-{
- if (f->index >= ARRAY_SIZE(format))
- return -EINVAL;
-
- f->pixelformat = format[f->index].fourcc;
- return 0;
-}
-
-static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct tm6000_fh *fh = priv;
-
- f->fmt.pix.width = fh->width;
- f->fmt.pix.height = fh->height;
- f->fmt.pix.field = fh->vb_vidq.field;
- f->fmt.pix.pixelformat = fh->fmt->fourcc;
- f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
- f->fmt.pix.bytesperline =
- (f->fmt.pix.width * fh->fmt->depth) >> 3;
- f->fmt.pix.sizeimage =
- f->fmt.pix.height * f->fmt.pix.bytesperline;
-
- return 0;
-}
-
-static struct tm6000_fmt *format_by_fourcc(unsigned int fourcc)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(format); i++)
- if (format[i].fourcc == fourcc)
- return format+i;
- return NULL;
-}
-
-static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev;
- struct tm6000_fmt *fmt;
- enum v4l2_field field;
-
- fmt = format_by_fourcc(f->fmt.pix.pixelformat);
- if (NULL == fmt) {
- dprintk(dev, 2, "Fourcc format (0x%08x) invalid.\n",
- f->fmt.pix.pixelformat);
- return -EINVAL;
- }
-
- field = V4L2_FIELD_INTERLACED;
-
- tm6000_get_std_res(dev);
-
- f->fmt.pix.width = dev->width;
- f->fmt.pix.height = dev->height;
-
- f->fmt.pix.width &= ~0x01;
-
- f->fmt.pix.field = field;
-
- f->fmt.pix.bytesperline =
- (f->fmt.pix.width * fmt->depth) >> 3;
- f->fmt.pix.sizeimage =
- f->fmt.pix.height * f->fmt.pix.bytesperline;
- f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
-
- return 0;
-}
-
-/*FIXME: This seems to be generic enough to be at videodev2 */
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct tm6000_fh *fh = priv;
- struct tm6000_core *dev = fh->dev;
- int ret = vidioc_try_fmt_vid_cap(file, fh, f);
- if (ret < 0)
- return ret;
-
- fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
- fh->width = f->fmt.pix.width;
- fh->height = f->fmt.pix.height;
- fh->vb_vidq.field = f->fmt.pix.field;
- fh->type = f->type;
-
- dev->fourcc = f->fmt.pix.pixelformat;
-
- tm6000_set_fourcc_format(dev);
-
- return 0;
-}
-
-static int vidioc_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *p)
-{
- struct tm6000_fh *fh = priv;
-
- return videobuf_reqbufs(&fh->vb_vidq, p);
-}
-
-static int vidioc_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *p)
-{
- struct tm6000_fh *fh = priv;
-
- return videobuf_querybuf(&fh->vb_vidq, p);
-}
-
-static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- struct tm6000_fh *fh = priv;
-
- return videobuf_qbuf(&fh->vb_vidq, p);
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- struct tm6000_fh *fh = priv;
-
- return videobuf_dqbuf(&fh->vb_vidq, p,
- file->f_flags & O_NONBLOCK);
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct tm6000_fh *fh = priv;
- struct tm6000_core *dev = fh->dev;
-
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (i != fh->type)
- return -EINVAL;
-
- if (!res_get(dev, fh, false))
- return -EBUSY;
- return videobuf_streamon(&fh->vb_vidq);
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct tm6000_fh *fh = priv;
- struct tm6000_core *dev = fh->dev;
-
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- if (i != fh->type)
- return -EINVAL;
-
- videobuf_streamoff(&fh->vb_vidq);
- res_free(dev, fh);
-
- return 0;
-}
-
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
-{
- int rc = 0;
- struct tm6000_fh *fh = priv;
- struct tm6000_core *dev = fh->dev;
-
- dev->norm = norm;
- rc = tm6000_init_analog_mode(dev);
-
- fh->width = dev->width;
- fh->height = dev->height;
-
- if (rc < 0)
- return rc;
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std, dev->norm);
-
- return 0;
-}
-
-static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm)
-{
- struct tm6000_fh *fh = priv;
- struct tm6000_core *dev = fh->dev;
-
- *norm = dev->norm;
- return 0;
-}
-
-static const char *iname[] = {
- [TM6000_INPUT_TV] = "Television",
- [TM6000_INPUT_COMPOSITE1] = "Composite 1",
- [TM6000_INPUT_COMPOSITE2] = "Composite 2",
- [TM6000_INPUT_SVIDEO] = "S-Video",
-};
-
-static int vidioc_enum_input(struct file *file, void *priv,
- struct v4l2_input *i)
-{
- struct tm6000_fh *fh = priv;
- struct tm6000_core *dev = fh->dev;
- unsigned int n;
-
- n = i->index;
- if (n >= 3)
- return -EINVAL;
-
- if (!dev->vinput[n].type)
- return -EINVAL;
-
- i->index = n;
-
- if (dev->vinput[n].type == TM6000_INPUT_TV)
- i->type = V4L2_INPUT_TYPE_TUNER;
- else
- i->type = V4L2_INPUT_TYPE_CAMERA;
-
- strscpy(i->name, iname[dev->vinput[n].type], sizeof(i->name));
-
- i->std = TM6000_STD;
-
- return 0;
-}
-
-static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
-{
- struct tm6000_fh *fh = priv;
- struct tm6000_core *dev = fh->dev;
-
- *i = dev->input;
-
- return 0;
-}
-
-static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
-{
- struct tm6000_fh *fh = priv;
- struct tm6000_core *dev = fh->dev;
- int rc = 0;
-
- if (i >= 3)
- return -EINVAL;
- if (!dev->vinput[i].type)
- return -EINVAL;
-
- dev->input = i;
-
- rc = vidioc_s_std(file, priv, dev->norm);
-
- return rc;
-}
-
-/* --- controls ---------------------------------------------- */
-
-static int tm6000_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct tm6000_core *dev = container_of(ctrl->handler, struct tm6000_core, ctrl_handler);
- u8 val = ctrl->val;
-
- switch (ctrl->id) {
- case V4L2_CID_CONTRAST:
- tm6000_set_reg(dev, TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, val);
- return 0;
- case V4L2_CID_BRIGHTNESS:
- tm6000_set_reg(dev, TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, val);
- return 0;
- case V4L2_CID_SATURATION:
- tm6000_set_reg(dev, TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, val);
- return 0;
- case V4L2_CID_HUE:
- tm6000_set_reg(dev, TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ, val);
- return 0;
- }
- return -EINVAL;
-}
-
-static const struct v4l2_ctrl_ops tm6000_ctrl_ops = {
- .s_ctrl = tm6000_s_ctrl,
-};
-
-static int tm6000_radio_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct tm6000_core *dev = container_of(ctrl->handler,
- struct tm6000_core, radio_ctrl_handler);
- u8 val = ctrl->val;
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- dev->ctl_mute = val;
- tm6000_tvaudio_set_mute(dev, val);
- return 0;
- case V4L2_CID_AUDIO_VOLUME:
- dev->ctl_volume = val;
- tm6000_set_volume(dev, val);
- return 0;
- }
- return -EINVAL;
-}
-
-static const struct v4l2_ctrl_ops tm6000_radio_ctrl_ops = {
- .s_ctrl = tm6000_radio_s_ctrl,
-};
-
-static int vidioc_g_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
-{
- struct tm6000_fh *fh = priv;
- struct tm6000_core *dev = fh->dev;
-
- if (UNSET == dev->tuner_type)
- return -ENOTTY;
- if (0 != t->index)
- return -EINVAL;
-
- strscpy(t->name, "Television", sizeof(t->name));
- t->type = V4L2_TUNER_ANALOG_TV;
- t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO;
- t->rangehigh = 0xffffffffUL;
- t->rxsubchans = V4L2_TUNER_SUB_STEREO;
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
-
- t->audmode = dev->amode;
-
- return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv,
- const struct v4l2_tuner *t)
-{
- struct tm6000_fh *fh = priv;
- struct tm6000_core *dev = fh->dev;
-
- if (UNSET == dev->tuner_type)
- return -ENOTTY;
- if (0 != t->index)
- return -EINVAL;
-
- if (t->audmode > V4L2_TUNER_MODE_STEREO)
- dev->amode = V4L2_TUNER_MODE_STEREO;
- else
- dev->amode = t->audmode;
- dprintk(dev, 3, "audio mode: %x\n", t->audmode);
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
-
- return 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
-{
- struct tm6000_fh *fh = priv;
- struct tm6000_core *dev = fh->dev;
-
- if (UNSET == dev->tuner_type)
- return -ENOTTY;
- if (f->tuner)
- return -EINVAL;
-
- f->frequency = dev->freq;
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, f);
-
- return 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
- const struct v4l2_frequency *f)
-{
- struct tm6000_fh *fh = priv;
- struct tm6000_core *dev = fh->dev;
-
- if (UNSET == dev->tuner_type)
- return -ENOTTY;
- if (f->tuner != 0)
- return -EINVAL;
-
- dev->freq = f->frequency;
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, f);
-
- return 0;
-}
-
-static int radio_g_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
-{
- struct tm6000_fh *fh = file->private_data;
- struct tm6000_core *dev = fh->dev;
-
- if (0 != t->index)
- return -EINVAL;
-
- memset(t, 0, sizeof(*t));
- strscpy(t->name, "Radio", sizeof(t->name));
- t->type = V4L2_TUNER_RADIO;
- t->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
- t->rxsubchans = V4L2_TUNER_SUB_STEREO;
- t->audmode = V4L2_TUNER_MODE_STEREO;
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
-
- return 0;
-}
-
-static int radio_s_tuner(struct file *file, void *priv,
- const struct v4l2_tuner *t)
-{
- struct tm6000_fh *fh = file->private_data;
- struct tm6000_core *dev = fh->dev;
-
- if (0 != t->index)
- return -EINVAL;
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
- return 0;
-}
-
-/* ------------------------------------------------------------------
- File operations for the device
- ------------------------------------------------------------------*/
-
-static int __tm6000_open(struct file *file)
-{
- struct video_device *vdev = video_devdata(file);
- struct tm6000_core *dev = video_drvdata(file);
- struct tm6000_fh *fh;
- enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- int rc;
- int radio = 0;
-
- dprintk(dev, V4L2_DEBUG_OPEN, "tm6000: open called (dev=%s)\n",
- video_device_node_name(vdev));
-
- switch (vdev->vfl_type) {
- case VFL_TYPE_VIDEO:
- type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- break;
- case VFL_TYPE_VBI:
- type = V4L2_BUF_TYPE_VBI_CAPTURE;
- break;
- case VFL_TYPE_RADIO:
- radio = 1;
- break;
- default:
- return -EINVAL;
- }
-
- /* If more than one user, mutex should be added */
- dev->users++;
-
- dprintk(dev, V4L2_DEBUG_OPEN, "open dev=%s type=%s users=%d\n",
- video_device_node_name(vdev), v4l2_type_names[type],
- dev->users);
-
- /* allocate + initialize per filehandle data */
- fh = kzalloc(sizeof(*fh), GFP_KERNEL);
- if (NULL == fh) {
- dev->users--;
- return -ENOMEM;
- }
-
- v4l2_fh_init(&fh->fh, vdev);
- file->private_data = fh;
- fh->dev = dev;
- fh->radio = radio;
- dev->radio = radio;
- fh->type = type;
- dev->fourcc = format[0].fourcc;
-
- fh->fmt = format_by_fourcc(dev->fourcc);
-
- tm6000_get_std_res(dev);
-
- fh->width = dev->width;
- fh->height = dev->height;
-
- dprintk(dev, V4L2_DEBUG_OPEN, "Open: fh=%p, dev=%p, dev->vidq=%p\n",
- fh, dev, &dev->vidq);
- dprintk(dev, V4L2_DEBUG_OPEN, "Open: list_empty queued=%d\n",
- list_empty(&dev->vidq.queued));
- dprintk(dev, V4L2_DEBUG_OPEN, "Open: list_empty active=%d\n",
- list_empty(&dev->vidq.active));
-
- /* initialize hardware on analog mode */
- rc = tm6000_init_analog_mode(dev);
- if (rc < 0) {
- v4l2_fh_exit(&fh->fh);
- kfree(fh);
- return rc;
- }
-
- dev->mode = TM6000_MODE_ANALOG;
-
- if (!fh->radio) {
- videobuf_queue_vmalloc_init(&fh->vb_vidq, &tm6000_video_qops,
- NULL, &dev->slock,
- fh->type,
- V4L2_FIELD_INTERLACED,
- sizeof(struct tm6000_buffer), fh, &dev->lock);
- } else {
- dprintk(dev, V4L2_DEBUG_OPEN, "video_open: setting radio device\n");
- tm6000_set_audio_rinput(dev);
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_radio);
- tm6000_prepare_isoc(dev);
- tm6000_start_thread(dev);
- }
- v4l2_fh_add(&fh->fh);
-
- return 0;
-}
-
-static int tm6000_open(struct file *file)
-{
- struct video_device *vdev = video_devdata(file);
- int res;
-
- mutex_lock(vdev->lock);
- res = __tm6000_open(file);
- mutex_unlock(vdev->lock);
- return res;
-}
-
-static ssize_t
-tm6000_read(struct file *file, char __user *data, size_t count, loff_t *pos)
-{
- struct tm6000_fh *fh = file->private_data;
- struct tm6000_core *dev = fh->dev;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- int res;
-
- if (!res_get(fh->dev, fh, true))
- return -EBUSY;
-
- if (mutex_lock_interruptible(&dev->lock))
- return -ERESTARTSYS;
- res = videobuf_read_stream(&fh->vb_vidq, data, count, pos, 0,
- file->f_flags & O_NONBLOCK);
- mutex_unlock(&dev->lock);
- return res;
- }
- return 0;
-}
-
-static __poll_t
-__tm6000_poll(struct file *file, struct poll_table_struct *wait)
-{
- __poll_t req_events = poll_requested_events(wait);
- struct tm6000_fh *fh = file->private_data;
- struct tm6000_buffer *buf;
- __poll_t res = 0;
-
- if (v4l2_event_pending(&fh->fh))
- res = EPOLLPRI;
- else if (req_events & EPOLLPRI)
- poll_wait(file, &fh->fh.wait, wait);
- if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
- return res | EPOLLERR;
-
- if (!!is_res_streaming(fh->dev, fh))
- return res | EPOLLERR;
-
- if (!is_res_read(fh->dev, fh)) {
- /* streaming capture */
- if (list_empty(&fh->vb_vidq.stream))
- return res | EPOLLERR;
- buf = list_entry(fh->vb_vidq.stream.next, struct tm6000_buffer, vb.stream);
- poll_wait(file, &buf->vb.done, wait);
- if (buf->vb.state == VIDEOBUF_DONE ||
- buf->vb.state == VIDEOBUF_ERROR)
- return res | EPOLLIN | EPOLLRDNORM;
- } else if (req_events & (EPOLLIN | EPOLLRDNORM)) {
- /* read() capture */
- return res | videobuf_poll_stream(file, &fh->vb_vidq, wait);
- }
- return res;
-}
-
-static __poll_t tm6000_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct tm6000_fh *fh = file->private_data;
- struct tm6000_core *dev = fh->dev;
- __poll_t res;
-
- mutex_lock(&dev->lock);
- res = __tm6000_poll(file, wait);
- mutex_unlock(&dev->lock);
- return res;
-}
-
-static int tm6000_release(struct file *file)
-{
- struct tm6000_fh *fh = file->private_data;
- struct tm6000_core *dev = fh->dev;
- struct video_device *vdev = video_devdata(file);
-
- dprintk(dev, V4L2_DEBUG_OPEN, "tm6000: close called (dev=%s, users=%d)\n",
- video_device_node_name(vdev), dev->users);
-
- mutex_lock(&dev->lock);
- dev->users--;
-
- res_free(dev, fh);
-
- if (!dev->users) {
- tm6000_uninit_isoc(dev);
-
- /* Stop interrupt USB pipe */
- tm6000_ir_int_stop(dev);
-
- usb_reset_configuration(dev->udev);
-
- if (dev->int_in.endp)
- usb_set_interface(dev->udev,
- dev->isoc_in.bInterfaceNumber, 2);
- else
- usb_set_interface(dev->udev,
- dev->isoc_in.bInterfaceNumber, 0);
-
- /* Start interrupt USB pipe */
- tm6000_ir_int_start(dev);
-
- if (!fh->radio)
- videobuf_mmap_free(&fh->vb_vidq);
- }
- v4l2_fh_del(&fh->fh);
- v4l2_fh_exit(&fh->fh);
- kfree(fh);
- mutex_unlock(&dev->lock);
-
- return 0;
-}
-
-static int tm6000_mmap(struct file *file, struct vm_area_struct * vma)
-{
- struct tm6000_fh *fh = file->private_data;
- struct tm6000_core *dev = fh->dev;
- int res;
-
- if (mutex_lock_interruptible(&dev->lock))
- return -ERESTARTSYS;
- res = videobuf_mmap_mapper(&fh->vb_vidq, vma);
- mutex_unlock(&dev->lock);
- return res;
-}
-
-static const struct v4l2_file_operations tm6000_fops = {
- .owner = THIS_MODULE,
- .open = tm6000_open,
- .release = tm6000_release,
- .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
- .read = tm6000_read,
- .poll = tm6000_poll,
- .mmap = tm6000_mmap,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
- .vidioc_querycap = vidioc_querycap,
- .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
- .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
- .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
- .vidioc_s_std = vidioc_s_std,
- .vidioc_g_std = vidioc_g_std,
- .vidioc_enum_input = vidioc_enum_input,
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
- .vidioc_g_tuner = vidioc_g_tuner,
- .vidioc_s_tuner = vidioc_s_tuner,
- .vidioc_g_frequency = vidioc_g_frequency,
- .vidioc_s_frequency = vidioc_s_frequency,
- .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_subscribe_event = v4l2_ctrl_subscribe_event,
- .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
-};
-
-static struct video_device tm6000_template = {
- .name = "tm6000",
- .fops = &tm6000_fops,
- .ioctl_ops = &video_ioctl_ops,
- .release = video_device_release_empty,
- .tvnorms = TM6000_STD,
-};
-
-static const struct v4l2_file_operations radio_fops = {
- .owner = THIS_MODULE,
- .open = tm6000_open,
- .poll = v4l2_ctrl_poll,
- .release = tm6000_release,
- .unlocked_ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops radio_ioctl_ops = {
- .vidioc_querycap = vidioc_querycap,
- .vidioc_g_tuner = radio_g_tuner,
- .vidioc_s_tuner = radio_s_tuner,
- .vidioc_g_frequency = vidioc_g_frequency,
- .vidioc_s_frequency = vidioc_s_frequency,
- .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
- .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
-};
-
-static struct video_device tm6000_radio_template = {
- .name = "tm6000",
- .fops = &radio_fops,
- .ioctl_ops = &radio_ioctl_ops,
-};
-
-/* -----------------------------------------------------------------
- * Initialization and module stuff
- * ------------------------------------------------------------------
- */
-
-static void vdev_init(struct tm6000_core *dev,
- struct video_device *vfd,
- const struct video_device
- *template, const char *type_name)
-{
- *vfd = *template;
- vfd->v4l2_dev = &dev->v4l2_dev;
- vfd->release = video_device_release_empty;
- vfd->lock = &dev->lock;
-
- snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name);
-
- video_set_drvdata(vfd, dev);
-}
-
-int tm6000_v4l2_register(struct tm6000_core *dev)
-{
- int ret = 0;
-
- v4l2_ctrl_handler_init(&dev->ctrl_handler, 6);
- v4l2_ctrl_handler_init(&dev->radio_ctrl_handler, 2);
- v4l2_ctrl_new_std(&dev->radio_ctrl_handler, &tm6000_radio_ctrl_ops,
- V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
- v4l2_ctrl_new_std(&dev->radio_ctrl_handler, &tm6000_radio_ctrl_ops,
- V4L2_CID_AUDIO_VOLUME, -15, 15, 1, 0);
- v4l2_ctrl_new_std(&dev->ctrl_handler, &tm6000_ctrl_ops,
- V4L2_CID_BRIGHTNESS, 0, 255, 1, 54);
- v4l2_ctrl_new_std(&dev->ctrl_handler, &tm6000_ctrl_ops,
- V4L2_CID_CONTRAST, 0, 255, 1, 119);
- v4l2_ctrl_new_std(&dev->ctrl_handler, &tm6000_ctrl_ops,
- V4L2_CID_SATURATION, 0, 255, 1, 112);
- v4l2_ctrl_new_std(&dev->ctrl_handler, &tm6000_ctrl_ops,
- V4L2_CID_HUE, -128, 127, 1, 0);
- v4l2_ctrl_add_handler(&dev->ctrl_handler,
- &dev->radio_ctrl_handler, NULL, false);
-
- if (dev->radio_ctrl_handler.error)
- ret = dev->radio_ctrl_handler.error;
- if (!ret && dev->ctrl_handler.error)
- ret = dev->ctrl_handler.error;
- if (ret)
- goto free_ctrl;
-
- vdev_init(dev, &dev->vfd, &tm6000_template, "video");
-
- dev->vfd.ctrl_handler = &dev->ctrl_handler;
- dev->vfd.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
- V4L2_CAP_READWRITE;
- if (dev->tuner_type != TUNER_ABSENT)
- dev->vfd.device_caps |= V4L2_CAP_TUNER;
-
- /* init video dma queues */
- INIT_LIST_HEAD(&dev->vidq.active);
- INIT_LIST_HEAD(&dev->vidq.queued);
-
- ret = video_register_device(&dev->vfd, VFL_TYPE_VIDEO, video_nr);
-
- if (ret < 0) {
- printk(KERN_INFO "%s: can't register video device\n",
- dev->name);
- goto free_ctrl;
- }
-
- printk(KERN_INFO "%s: registered device %s\n",
- dev->name, video_device_node_name(&dev->vfd));
-
- if (dev->caps.has_radio) {
- vdev_init(dev, &dev->radio_dev, &tm6000_radio_template,
- "radio");
- dev->radio_dev.ctrl_handler = &dev->radio_ctrl_handler;
- dev->radio_dev.device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER;
- ret = video_register_device(&dev->radio_dev, VFL_TYPE_RADIO,
- radio_nr);
- if (ret < 0) {
- printk(KERN_INFO "%s: can't register radio device\n",
- dev->name);
- goto unreg_video;
- }
-
- printk(KERN_INFO "%s: registered device %s\n",
- dev->name, video_device_node_name(&dev->radio_dev));
- }
-
- printk(KERN_INFO "Trident TVMaster TM5600/TM6000/TM6010 USB2 board (Load status: %d)\n", ret);
- return ret;
-
-unreg_video:
- video_unregister_device(&dev->vfd);
-free_ctrl:
- v4l2_ctrl_handler_free(&dev->ctrl_handler);
- v4l2_ctrl_handler_free(&dev->radio_ctrl_handler);
- return ret;
-}
-
-int tm6000_v4l2_unregister(struct tm6000_core *dev)
-{
- video_unregister_device(&dev->vfd);
-
- /* if URB buffers are still allocated free them now */
- tm6000_free_urb_buffers(dev);
-
- video_unregister_device(&dev->radio_dev);
- return 0;
-}
-
-int tm6000_v4l2_exit(void)
-{
- return 0;
-}
-
-module_param(video_nr, int, 0);
-MODULE_PARM_DESC(video_nr, "Allow changing video device number");
-
-module_param_named(debug, tm6000_debug, int, 0444);
-MODULE_PARM_DESC(debug, "activates debug info");
-
-module_param(vid_limit, int, 0644);
-MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
-
-module_param(keep_urb, bool, 0);
-MODULE_PARM_DESC(keep_urb, "Keep urb buffers allocated even when the device is closed by the user");
diff --git a/drivers/staging/media/deprecated/tm6000/tm6000.h b/drivers/staging/media/deprecated/tm6000/tm6000.h
deleted file mode 100644
index c08c95312739..000000000000
--- a/drivers/staging/media/deprecated/tm6000/tm6000.h
+++ /dev/null
@@ -1,396 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * tm6000.h - driver for TM5600/TM6000/TM6010 USB video capture devices
- *
- * Copyright (c) 2006-2007 Mauro Carvalho Chehab <mchehab@kernel.org>
- *
- * Copyright (c) 2007 Michel Ludwig <michel.ludwig@gmail.com>
- * - DVB-T support
- */
-
-#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
-#include <media/videobuf-vmalloc.h>
-#include "tm6000-usb-isoc.h"
-#include <linux/i2c.h>
-#include <linux/mutex.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-fh.h>
-
-#include <linux/dvb/frontend.h>
-#include <media/dvb_demux.h>
-#include <media/dvb_frontend.h>
-#include <media/dmxdev.h>
-
-/* Inputs */
-enum tm6000_itype {
- TM6000_INPUT_TV = 1,
- TM6000_INPUT_COMPOSITE1,
- TM6000_INPUT_COMPOSITE2,
- TM6000_INPUT_SVIDEO,
- TM6000_INPUT_DVB,
- TM6000_INPUT_RADIO,
-};
-
-enum tm6000_mux {
- TM6000_VMUX_VIDEO_A = 1,
- TM6000_VMUX_VIDEO_B,
- TM6000_VMUX_VIDEO_AB,
- TM6000_AMUX_ADC1,
- TM6000_AMUX_ADC2,
- TM6000_AMUX_SIF1,
- TM6000_AMUX_SIF2,
- TM6000_AMUX_I2S,
-};
-
-enum tm6000_devtype {
- TM6000 = 0,
- TM5600,
- TM6010,
-};
-
-struct tm6000_input {
- enum tm6000_itype type;
- enum tm6000_mux vmux;
- enum tm6000_mux amux;
- unsigned int v_gpio;
- unsigned int a_gpio;
-};
-
-/* ------------------------------------------------------------------
- * Basic structures
- * ------------------------------------------------------------------
- */
-
-struct tm6000_fmt {
- u32 fourcc; /* v4l2 format id */
- int depth;
-};
-
-/* buffer for one video frame */
-struct tm6000_buffer {
- /* common v4l buffer stuff -- must be first */
- struct videobuf_buffer vb;
-
- struct tm6000_fmt *fmt;
-};
-
-struct tm6000_dmaqueue {
- struct list_head active;
- struct list_head queued;
-
- /* thread for generating video stream*/
- struct task_struct *kthread;
- wait_queue_head_t wq;
- /* Counters to control fps rate */
- int frame;
- int ini_jiffies;
-};
-
-/* device states */
-enum tm6000_core_state {
- DEV_INITIALIZED = 0x01,
- DEV_DISCONNECTED = 0x02,
- DEV_MISCONFIGURED = 0x04,
-};
-
-/* io methods */
-enum tm6000_io_method {
- IO_NONE,
- IO_READ,
- IO_MMAP,
-};
-
-enum tm6000_mode {
- TM6000_MODE_UNKNOWN = 0,
- TM6000_MODE_ANALOG,
- TM6000_MODE_DIGITAL,
-};
-
-struct tm6000_gpio {
- int tuner_reset;
- int tuner_on;
- int demod_reset;
- int demod_on;
- int power_led;
- int dvb_led;
- int ir;
-};
-
-struct tm6000_capabilities {
- unsigned int has_tuner:1;
- unsigned int has_tda9874:1;
- unsigned int has_dvb:1;
- unsigned int has_zl10353:1;
- unsigned int has_eeprom:1;
- unsigned int has_remote:1;
- unsigned int has_radio:1;
-};
-
-struct tm6000_dvb {
- struct dvb_adapter adapter;
- struct dvb_demux demux;
- struct dvb_frontend *frontend;
- struct dmxdev dmxdev;
- unsigned int streams;
- struct urb *bulk_urb;
- struct mutex mutex;
-};
-
-struct snd_tm6000_card {
- struct snd_card *card;
- spinlock_t reg_lock;
- struct tm6000_core *core;
- struct snd_pcm_substream *substream;
-
- /* temporary data for buffer fill processing */
- unsigned buf_pos;
- unsigned period_pos;
-};
-
-struct tm6000_endpoint {
- struct usb_host_endpoint *endp;
- __u8 bInterfaceNumber;
- __u8 bAlternateSetting;
- unsigned maxsize;
-};
-
-#define TM6000_QUIRK_NO_USB_DELAY (1 << 0)
-
-struct tm6000_core {
- /* generic device properties */
- char name[30]; /* name (including minor) of the device */
- int model; /* index in the device_data struct */
- int devno; /* marks the number of this device */
- enum tm6000_devtype dev_type; /* type of device */
- unsigned char eedata[256]; /* Eeprom data */
- unsigned eedata_size; /* Size of the eeprom info */
-
- v4l2_std_id norm; /* Current norm */
- int width, height; /* Selected resolution */
-
- enum tm6000_core_state state;
-
- /* Device Capabilities*/
- struct tm6000_capabilities caps;
-
- /* Used to load alsa/dvb */
- struct work_struct request_module_wk;
-
- /* Tuner configuration */
- int tuner_type; /* type of the tuner */
- int tuner_addr; /* tuner address */
-
- struct tm6000_gpio gpio;
-
- char *ir_codes;
-
- __u8 radio;
-
- /* Demodulator configuration */
- int demod_addr; /* demodulator address */
-
- int audio_bitrate;
- /* i2c i/o */
- struct i2c_adapter i2c_adap;
- struct i2c_client i2c_client;
-
-
- /* extension */
- struct list_head devlist;
-
- /* video for linux */
- int users;
-
- /* various device info */
- struct tm6000_fh *resources; /* Points to fh that is streaming */
- bool is_res_read;
-
- struct video_device vfd;
- struct video_device radio_dev;
- struct tm6000_dmaqueue vidq;
- struct v4l2_device v4l2_dev;
- struct v4l2_ctrl_handler ctrl_handler;
- struct v4l2_ctrl_handler radio_ctrl_handler;
-
- int input;
- struct tm6000_input vinput[3]; /* video input */
- struct tm6000_input rinput; /* radio input */
-
- int freq;
- unsigned int fourcc;
-
- enum tm6000_mode mode;
-
- int ctl_mute; /* audio */
- int ctl_volume;
- int amode;
-
- /* DVB-T support */
- struct tm6000_dvb *dvb;
-
- /* audio support */
- struct snd_tm6000_card *adev;
- struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */
- atomic_t stream_started; /* stream should be running if true */
-
- struct tm6000_IR *ir;
-
- /* locks */
- struct mutex lock;
- struct mutex usb_lock;
-
- /* usb transfer */
- struct usb_device *udev; /* the usb device */
-
- struct tm6000_endpoint bulk_in, bulk_out, isoc_in, isoc_out;
- struct tm6000_endpoint int_in, int_out;
-
- /* scaler!=0 if scaler is active*/
- int scaler;
-
- /* Isoc control struct */
- struct usb_isoc_ctl isoc_ctl;
-
- spinlock_t slock;
-
- /* urb dma buffers */
- char **urb_buffer;
- dma_addr_t *urb_dma;
- unsigned int urb_size;
-
- unsigned long quirks;
-};
-
-enum tm6000_ops_type {
- TM6000_AUDIO = 0x10,
- TM6000_DVB = 0x20,
-};
-
-struct tm6000_ops {
- struct list_head next;
- char *name;
- enum tm6000_ops_type type;
- int (*init)(struct tm6000_core *);
- int (*fini)(struct tm6000_core *);
- int (*fillbuf)(struct tm6000_core *, char *buf, int size);
-};
-
-struct tm6000_fh {
- struct v4l2_fh fh;
- struct tm6000_core *dev;
- unsigned int radio;
-
- /* video capture */
- struct tm6000_fmt *fmt;
- unsigned int width, height;
- struct videobuf_queue vb_vidq;
-
- enum v4l2_buf_type type;
-};
-
-#define TM6000_STD (V4L2_STD_PAL|V4L2_STD_PAL_N|V4L2_STD_PAL_Nc| \
- V4L2_STD_PAL_M|V4L2_STD_PAL_60|V4L2_STD_NTSC_M| \
- V4L2_STD_NTSC_M_JP|V4L2_STD_SECAM)
-
-/* In tm6000-cards.c */
-
-int tm6000_tuner_callback(void *ptr, int component, int command, int arg);
-int tm6000_xc5000_callback(void *ptr, int component, int command, int arg);
-int tm6000_cards_setup(struct tm6000_core *dev);
-void tm6000_flash_led(struct tm6000_core *dev, u8 state);
-
-/* In tm6000-core.c */
-
-int tm6000_read_write_usb(struct tm6000_core *dev, u8 reqtype, u8 req,
- u16 value, u16 index, u8 *buf, u16 len);
-int tm6000_get_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index);
-int tm6000_get_reg16(struct tm6000_core *dev, u8 req, u16 value, u16 index);
-int tm6000_get_reg32(struct tm6000_core *dev, u8 req, u16 value, u16 index);
-int tm6000_set_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index);
-int tm6000_set_reg_mask(struct tm6000_core *dev, u8 req, u16 value,
- u16 index, u16 mask);
-int tm6000_i2c_reset(struct tm6000_core *dev, u16 tsleep);
-int tm6000_init(struct tm6000_core *dev);
-int tm6000_reset(struct tm6000_core *dev);
-
-int tm6000_init_analog_mode(struct tm6000_core *dev);
-int tm6000_init_digital_mode(struct tm6000_core *dev);
-int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate);
-int tm6000_set_audio_rinput(struct tm6000_core *dev);
-int tm6000_tvaudio_set_mute(struct tm6000_core *dev, u8 mute);
-void tm6000_set_volume(struct tm6000_core *dev, int vol);
-
-int tm6000_v4l2_register(struct tm6000_core *dev);
-int tm6000_v4l2_unregister(struct tm6000_core *dev);
-int tm6000_v4l2_exit(void);
-void tm6000_set_fourcc_format(struct tm6000_core *dev);
-
-void tm6000_remove_from_devlist(struct tm6000_core *dev);
-void tm6000_add_into_devlist(struct tm6000_core *dev);
-int tm6000_register_extension(struct tm6000_ops *ops);
-void tm6000_unregister_extension(struct tm6000_ops *ops);
-void tm6000_init_extension(struct tm6000_core *dev);
-void tm6000_close_extension(struct tm6000_core *dev);
-int tm6000_call_fillbuf(struct tm6000_core *dev, enum tm6000_ops_type type,
- char *buf, int size);
-
-
-/* In tm6000-stds.c */
-void tm6000_get_std_res(struct tm6000_core *dev);
-int tm6000_set_standard(struct tm6000_core *dev);
-
-/* In tm6000-i2c.c */
-int tm6000_i2c_register(struct tm6000_core *dev);
-int tm6000_i2c_unregister(struct tm6000_core *dev);
-
-/* In tm6000-queue.c */
-
-int tm6000_v4l2_mmap(struct file *filp, struct vm_area_struct *vma);
-
-int tm6000_vidioc_streamon(struct file *file, void *priv,
- enum v4l2_buf_type i);
-int tm6000_vidioc_streamoff(struct file *file, void *priv,
- enum v4l2_buf_type i);
-int tm6000_vidioc_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *rb);
-int tm6000_vidioc_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *b);
-int tm6000_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b);
-int tm6000_vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b);
-ssize_t tm6000_v4l2_read(struct file *filp, char __user * buf, size_t count,
- loff_t *f_pos);
-unsigned int tm6000_v4l2_poll(struct file *file,
- struct poll_table_struct *wait);
-int tm6000_queue_init(struct tm6000_core *dev);
-
-/* In tm6000-alsa.c */
-/*int tm6000_audio_init(struct tm6000_core *dev, int idx);*/
-
-/* In tm6000-input.c */
-int tm6000_ir_init(struct tm6000_core *dev);
-int tm6000_ir_fini(struct tm6000_core *dev);
-void tm6000_ir_wait(struct tm6000_core *dev, u8 state);
-int tm6000_ir_int_start(struct tm6000_core *dev);
-void tm6000_ir_int_stop(struct tm6000_core *dev);
-
-/* Debug stuff */
-
-extern int tm6000_debug;
-
-#define dprintk(dev, level, fmt, arg...) do {\
- if (tm6000_debug & level) \
- printk(KERN_INFO "(%lu) %s %s :"fmt, jiffies, \
- dev->name, __func__ , ##arg); } while (0)
-
-#define V4L2_DEBUG_REG 0x0004
-#define V4L2_DEBUG_I2C 0x0008
-#define V4L2_DEBUG_QUEUE 0x0010
-#define V4L2_DEBUG_ISOC 0x0020
-#define V4L2_DEBUG_RES_LOCK 0x0040 /* Resource locking */
-#define V4L2_DEBUG_OPEN 0x0080 /* video open/close debug */
-
-#define tm6000_err(fmt, arg...) do {\
- printk(KERN_ERR "tm6000 %s :"fmt, \
- __func__ , ##arg); } while (0)
diff --git a/drivers/staging/media/deprecated/zr364xx/Kconfig b/drivers/staging/media/deprecated/zr364xx/Kconfig
deleted file mode 100644
index ea29c9d8dca2..000000000000
--- a/drivers/staging/media/deprecated/zr364xx/Kconfig
+++ /dev/null
@@ -1,18 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-config USB_ZR364XX
- tristate "USB ZR364XX Camera support (DEPRECATED)"
- depends on USB && VIDEO_DEV
- select VIDEOBUF_GEN
- select VIDEOBUF_VMALLOC
- help
- Say Y here if you want to connect this type of camera to your
- computer's USB port.
- See <file:Documentation/admin-guide/media/zr364xx.rst> for more info
- and list of supported cameras.
-
- This driver is deprecated and is scheduled for removal by
- the beginning of 2023. See the TODO file for more information.
-
- To compile this driver as a module, choose M here: the
- module will be called zr364xx.
-
diff --git a/drivers/staging/media/deprecated/zr364xx/Makefile b/drivers/staging/media/deprecated/zr364xx/Makefile
deleted file mode 100644
index edab017d499c..000000000000
--- a/drivers/staging/media/deprecated/zr364xx/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_USB_ZR364XX) += zr364xx.o
-
diff --git a/drivers/staging/media/deprecated/zr364xx/TODO b/drivers/staging/media/deprecated/zr364xx/TODO
deleted file mode 100644
index ecb30a429689..000000000000
--- a/drivers/staging/media/deprecated/zr364xx/TODO
+++ /dev/null
@@ -1,7 +0,0 @@
-This is one of the few drivers still not using the vb2
-framework, so this driver is now deprecated with the intent of
-removing it altogether by the beginning of 2023.
-
-In order to keep this driver it has to be converted to vb2.
-If someone is interested in doing this work, then contact the
-linux-media mailinglist (https://linuxtv.org/lists.php).
diff --git a/drivers/staging/media/deprecated/zr364xx/zr364xx.c b/drivers/staging/media/deprecated/zr364xx/zr364xx.c
deleted file mode 100644
index 538a330046ec..000000000000
--- a/drivers/staging/media/deprecated/zr364xx/zr364xx.c
+++ /dev/null
@@ -1,1635 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Zoran 364xx based USB webcam module version 0.73
- *
- * Allows you to use your USB webcam with V4L2 applications
- * This is still in heavy development !
- *
- * Copyright (C) 2004 Antoine Jacquet <royale@zerezo.com>
- * http://royale.zerezo.com/zr364xx/
- *
- * Heavily inspired by usb-skeleton.c, vicam.c, cpia.c and spca50x.c drivers
- * V4L2 version inspired by meye.c driver
- *
- * Some video buffer code by Lamarque based on s2255drv.c and vivi.c drivers.
- */
-
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/usb.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/highmem.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-fh.h>
-#include <media/v4l2-event.h>
-#include <media/videobuf-vmalloc.h>
-
-
-/* Version Information */
-#define DRIVER_VERSION "0.7.4"
-#define DRIVER_AUTHOR "Antoine Jacquet, http://royale.zerezo.com/"
-#define DRIVER_DESC "Zoran 364xx"
-
-
-/* Camera */
-#define FRAMES 1
-#define MAX_FRAME_SIZE 200000
-#define BUFFER_SIZE 0x1000
-#define CTRL_TIMEOUT 500
-
-#define ZR364XX_DEF_BUFS 4
-#define ZR364XX_READ_IDLE 0
-#define ZR364XX_READ_FRAME 1
-
-/* Debug macro */
-#define DBG(fmt, args...) \
- do { \
- if (debug) { \
- printk(KERN_INFO KBUILD_MODNAME " " fmt, ##args); \
- } \
- } while (0)
-
-/*#define FULL_DEBUG 1*/
-#ifdef FULL_DEBUG
-#define _DBG DBG
-#else
-#define _DBG(fmt, args...)
-#endif
-
-/* Init methods, need to find nicer names for these
- * the exact names of the chipsets would be the best if someone finds it */
-#define METHOD0 0
-#define METHOD1 1
-#define METHOD2 2
-#define METHOD3 3
-
-
-/* Module parameters */
-static int debug;
-static int mode;
-
-
-/* Module parameters interface */
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Debug level");
-module_param(mode, int, 0644);
-MODULE_PARM_DESC(mode, "0 = 320x240, 1 = 160x120, 2 = 640x480");
-
-
-/* Devices supported by this driver
- * .driver_info contains the init method used by the camera */
-static const struct usb_device_id device_table[] = {
- {USB_DEVICE(0x08ca, 0x0109), .driver_info = METHOD0 },
- {USB_DEVICE(0x041e, 0x4024), .driver_info = METHOD0 },
- {USB_DEVICE(0x0d64, 0x0108), .driver_info = METHOD0 },
- {USB_DEVICE(0x0546, 0x3187), .driver_info = METHOD0 },
- {USB_DEVICE(0x0d64, 0x3108), .driver_info = METHOD0 },
- {USB_DEVICE(0x0595, 0x4343), .driver_info = METHOD0 },
- {USB_DEVICE(0x0bb0, 0x500d), .driver_info = METHOD0 },
- {USB_DEVICE(0x0feb, 0x2004), .driver_info = METHOD0 },
- {USB_DEVICE(0x055f, 0xb500), .driver_info = METHOD0 },
- {USB_DEVICE(0x08ca, 0x2062), .driver_info = METHOD2 },
- {USB_DEVICE(0x052b, 0x1a18), .driver_info = METHOD1 },
- {USB_DEVICE(0x04c8, 0x0729), .driver_info = METHOD0 },
- {USB_DEVICE(0x04f2, 0xa208), .driver_info = METHOD0 },
- {USB_DEVICE(0x0784, 0x0040), .driver_info = METHOD1 },
- {USB_DEVICE(0x06d6, 0x0034), .driver_info = METHOD0 },
- {USB_DEVICE(0x0a17, 0x0062), .driver_info = METHOD2 },
- {USB_DEVICE(0x06d6, 0x003b), .driver_info = METHOD0 },
- {USB_DEVICE(0x0a17, 0x004e), .driver_info = METHOD2 },
- {USB_DEVICE(0x041e, 0x405d), .driver_info = METHOD2 },
- {USB_DEVICE(0x08ca, 0x2102), .driver_info = METHOD3 },
- {USB_DEVICE(0x06d6, 0x003d), .driver_info = METHOD0 },
- {} /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(usb, device_table);
-
-/* frame structure */
-struct zr364xx_framei {
- unsigned long ulState; /* ulState:ZR364XX_READ_IDLE,
- ZR364XX_READ_FRAME */
- void *lpvbits; /* image data */
- unsigned long cur_size; /* current data copied to it */
-};
-
-/* image buffer structure */
-struct zr364xx_bufferi {
- unsigned long dwFrames; /* number of frames in buffer */
- struct zr364xx_framei frame[FRAMES]; /* array of FRAME structures */
-};
-
-struct zr364xx_dmaqueue {
- struct list_head active;
- struct zr364xx_camera *cam;
-};
-
-struct zr364xx_pipeinfo {
- u32 transfer_size;
- u8 *transfer_buffer;
- u32 state;
- void *stream_urb;
- void *cam; /* back pointer to zr364xx_camera struct */
- u32 err_count;
- u32 idx;
-};
-
-struct zr364xx_fmt {
- u32 fourcc;
- int depth;
-};
-
-/* image formats. */
-static const struct zr364xx_fmt formats[] = {
- {
- .fourcc = V4L2_PIX_FMT_JPEG,
- .depth = 24
- }
-};
-
-/* Camera stuff */
-struct zr364xx_camera {
- struct usb_device *udev; /* save off the usb device pointer */
- struct usb_interface *interface;/* the interface for this device */
- struct v4l2_device v4l2_dev;
- struct v4l2_ctrl_handler ctrl_handler;
- struct video_device vdev; /* v4l video device */
- struct v4l2_fh *owner; /* owns the streaming */
- int nb;
- struct zr364xx_bufferi buffer;
- int skip;
- int width;
- int height;
- int method;
- struct mutex lock;
-
- spinlock_t slock;
- struct zr364xx_dmaqueue vidq;
- int last_frame;
- int cur_frame;
- unsigned long frame_count;
- int b_acquire;
- struct zr364xx_pipeinfo pipe[1];
-
- u8 read_endpoint;
-
- const struct zr364xx_fmt *fmt;
- struct videobuf_queue vb_vidq;
- bool was_streaming;
-};
-
-/* buffer for one video frame */
-struct zr364xx_buffer {
- /* common v4l buffer stuff -- must be first */
- struct videobuf_buffer vb;
- const struct zr364xx_fmt *fmt;
-};
-
-/* function used to send initialisation commands to the camera */
-static int send_control_msg(struct usb_device *udev, u8 request, u16 value,
- u16 index, unsigned char *cp, u16 size)
-{
- int status;
-
- unsigned char *transfer_buffer = kmemdup(cp, size, GFP_KERNEL);
- if (!transfer_buffer)
- return -ENOMEM;
-
- status = usb_control_msg(udev,
- usb_sndctrlpipe(udev, 0),
- request,
- USB_DIR_OUT | USB_TYPE_VENDOR |
- USB_RECIP_DEVICE, value, index,
- transfer_buffer, size, CTRL_TIMEOUT);
-
- kfree(transfer_buffer);
- return status;
-}
-
-
-/* Control messages sent to the camera to initialize it
- * and launch the capture */
-typedef struct {
- unsigned int value;
- unsigned int size;
- unsigned char *bytes;
-} message;
-
-/* method 0 */
-static unsigned char m0d1[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-static unsigned char m0d2[] = { 0, 0, 0, 0, 0, 0 };
-static unsigned char m0d3[] = { 0, 0 };
-static message m0[] = {
- {0x1f30, 0, NULL},
- {0xd000, 0, NULL},
- {0x3370, sizeof(m0d1), m0d1},
- {0x2000, 0, NULL},
- {0x2f0f, 0, NULL},
- {0x2610, sizeof(m0d2), m0d2},
- {0xe107, 0, NULL},
- {0x2502, 0, NULL},
- {0x1f70, 0, NULL},
- {0xd000, 0, NULL},
- {0x9a01, sizeof(m0d3), m0d3},
- {-1, -1, NULL}
-};
-
-/* method 1 */
-static unsigned char m1d1[] = { 0xff, 0xff };
-static unsigned char m1d2[] = { 0x00, 0x00 };
-static message m1[] = {
- {0x1f30, 0, NULL},
- {0xd000, 0, NULL},
- {0xf000, 0, NULL},
- {0x2000, 0, NULL},
- {0x2f0f, 0, NULL},
- {0x2650, 0, NULL},
- {0xe107, 0, NULL},
- {0x2502, sizeof(m1d1), m1d1},
- {0x1f70, 0, NULL},
- {0xd000, 0, NULL},
- {0xd000, 0, NULL},
- {0xd000, 0, NULL},
- {0x9a01, sizeof(m1d2), m1d2},
- {-1, -1, NULL}
-};
-
-/* method 2 */
-static unsigned char m2d1[] = { 0xff, 0xff };
-static message m2[] = {
- {0x1f30, 0, NULL},
- {0xf000, 0, NULL},
- {0x2000, 0, NULL},
- {0x2f0f, 0, NULL},
- {0x2650, 0, NULL},
- {0xe107, 0, NULL},
- {0x2502, sizeof(m2d1), m2d1},
- {0x1f70, 0, NULL},
- {-1, -1, NULL}
-};
-
-/* init table */
-static message *init[4] = { m0, m1, m2, m2 };
-
-
-/* JPEG static data in header (Huffman table, etc) */
-static unsigned char header1[] = {
- 0xFF, 0xD8,
- /*
- 0xFF, 0xE0, 0x00, 0x10, 'J', 'F', 'I', 'F',
- 0x00, 0x01, 0x01, 0x00, 0x33, 0x8A, 0x00, 0x00, 0x33, 0x88,
- */
- 0xFF, 0xDB, 0x00, 0x84
-};
-static unsigned char header2[] = {
- 0xFF, 0xC4, 0x00, 0x1F, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
- 0xFF, 0xC4, 0x00, 0xB5, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02,
- 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7D, 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, 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, 0xFF, 0xC4, 0x00, 0x1F,
- 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04,
- 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xFF, 0xC4, 0x00, 0xB5,
- 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05,
- 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 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, 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, 0xFF, 0xC0, 0x00, 0x11, 0x08, 0x00, 0xF0, 0x01,
- 0x40, 0x03, 0x01, 0x21, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01,
- 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11,
- 0x00, 0x3F, 0x00
-};
-static unsigned char header3;
-
-/* ------------------------------------------------------------------
- Videobuf operations
- ------------------------------------------------------------------*/
-
-static int buffer_setup(struct videobuf_queue *vq, unsigned int *count,
- unsigned int *size)
-{
- struct zr364xx_camera *cam = vq->priv_data;
-
- *size = cam->width * cam->height * (cam->fmt->depth >> 3);
-
- if (*count == 0)
- *count = ZR364XX_DEF_BUFS;
-
- if (*size * *count > ZR364XX_DEF_BUFS * 1024 * 1024)
- *count = (ZR364XX_DEF_BUFS * 1024 * 1024) / *size;
-
- return 0;
-}
-
-static void free_buffer(struct videobuf_queue *vq, struct zr364xx_buffer *buf)
-{
- _DBG("%s\n", __func__);
-
- videobuf_vmalloc_free(&buf->vb);
- buf->vb.state = VIDEOBUF_NEEDS_INIT;
-}
-
-static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
- enum v4l2_field field)
-{
- struct zr364xx_camera *cam = vq->priv_data;
- struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer,
- vb);
- int rc;
-
- DBG("%s, field=%d\n", __func__, field);
- if (!cam->fmt)
- return -EINVAL;
-
- buf->vb.size = cam->width * cam->height * (cam->fmt->depth >> 3);
-
- if (buf->vb.baddr != 0 && buf->vb.bsize < buf->vb.size) {
- DBG("invalid buffer prepare\n");
- return -EINVAL;
- }
-
- buf->fmt = cam->fmt;
- buf->vb.width = cam->width;
- buf->vb.height = cam->height;
- buf->vb.field = field;
-
- if (buf->vb.state == VIDEOBUF_NEEDS_INIT) {
- rc = videobuf_iolock(vq, &buf->vb, NULL);
- if (rc < 0)
- goto fail;
- }
-
- buf->vb.state = VIDEOBUF_PREPARED;
- return 0;
-fail:
- free_buffer(vq, buf);
- return rc;
-}
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
- struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer,
- vb);
- struct zr364xx_camera *cam = vq->priv_data;
-
- _DBG("%s\n", __func__);
-
- buf->vb.state = VIDEOBUF_QUEUED;
- list_add_tail(&buf->vb.queue, &cam->vidq.active);
-}
-
-static void buffer_release(struct videobuf_queue *vq,
- struct videobuf_buffer *vb)
-{
- struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer,
- vb);
-
- _DBG("%s\n", __func__);
- free_buffer(vq, buf);
-}
-
-static const struct videobuf_queue_ops zr364xx_video_qops = {
- .buf_setup = buffer_setup,
- .buf_prepare = buffer_prepare,
- .buf_queue = buffer_queue,
- .buf_release = buffer_release,
-};
-
-/********************/
-/* V4L2 integration */
-/********************/
-static int zr364xx_vidioc_streamon(struct file *file, void *priv,
- enum v4l2_buf_type type);
-
-static ssize_t zr364xx_read(struct file *file, char __user *buf, size_t count,
- loff_t * ppos)
-{
- struct zr364xx_camera *cam = video_drvdata(file);
- int err = 0;
-
- _DBG("%s\n", __func__);
-
- if (!buf)
- return -EINVAL;
-
- if (!count)
- return -EINVAL;
-
- if (mutex_lock_interruptible(&cam->lock))
- return -ERESTARTSYS;
-
- err = zr364xx_vidioc_streamon(file, file->private_data,
- V4L2_BUF_TYPE_VIDEO_CAPTURE);
- if (err == 0) {
- DBG("%s: reading %d bytes at pos %d.\n", __func__,
- (int) count, (int) *ppos);
-
- /* NoMan Sux ! */
- err = videobuf_read_one(&cam->vb_vidq, buf, count, ppos,
- file->f_flags & O_NONBLOCK);
- }
- mutex_unlock(&cam->lock);
- return err;
-}
-
-/* video buffer vmalloc implementation based partly on VIVI driver which is
- * Copyright (c) 2006 by
- * Mauro Carvalho Chehab <mchehab--a.t--infradead.org>
- * Ted Walther <ted--a.t--enumera.com>
- * John Sokol <sokol--a.t--videotechnology.com>
- * http://v4l.videotechnology.com/
- *
- */
-static void zr364xx_fillbuff(struct zr364xx_camera *cam,
- struct zr364xx_buffer *buf,
- int jpgsize)
-{
- int pos = 0;
- const char *tmpbuf;
- char *vbuf = videobuf_to_vmalloc(&buf->vb);
- unsigned long last_frame;
-
- if (!vbuf)
- return;
-
- last_frame = cam->last_frame;
- if (last_frame != -1) {
- tmpbuf = (const char *)cam->buffer.frame[last_frame].lpvbits;
- switch (buf->fmt->fourcc) {
- case V4L2_PIX_FMT_JPEG:
- buf->vb.size = jpgsize;
- memcpy(vbuf, tmpbuf, buf->vb.size);
- break;
- default:
- printk(KERN_DEBUG KBUILD_MODNAME ": unknown format?\n");
- }
- cam->last_frame = -1;
- } else {
- printk(KERN_ERR KBUILD_MODNAME ": =======no frame\n");
- return;
- }
- DBG("%s: Buffer %p size= %d\n", __func__, vbuf, pos);
- /* tell v4l buffer was filled */
-
- buf->vb.field_count = cam->frame_count * 2;
- buf->vb.ts = ktime_get_ns();
- buf->vb.state = VIDEOBUF_DONE;
-}
-
-static int zr364xx_got_frame(struct zr364xx_camera *cam, int jpgsize)
-{
- struct zr364xx_dmaqueue *dma_q = &cam->vidq;
- struct zr364xx_buffer *buf;
- unsigned long flags = 0;
- int rc = 0;
-
- DBG("wakeup: %p\n", &dma_q);
- spin_lock_irqsave(&cam->slock, flags);
-
- if (list_empty(&dma_q->active)) {
- DBG("No active queue to serve\n");
- rc = -1;
- goto unlock;
- }
- buf = list_entry(dma_q->active.next,
- struct zr364xx_buffer, vb.queue);
-
- if (!waitqueue_active(&buf->vb.done)) {
- /* no one active */
- rc = -1;
- goto unlock;
- }
- list_del(&buf->vb.queue);
- buf->vb.ts = ktime_get_ns();
- DBG("[%p/%d] wakeup\n", buf, buf->vb.i);
- zr364xx_fillbuff(cam, buf, jpgsize);
- wake_up(&buf->vb.done);
- DBG("wakeup [buf/i] [%p/%d]\n", buf, buf->vb.i);
-unlock:
- spin_unlock_irqrestore(&cam->slock, flags);
- return rc;
-}
-
-/* this function moves the usb stream read pipe data
- * into the system buffers.
- * returns 0 on success, EAGAIN if more data to process (call this
- * function again).
- */
-static int zr364xx_read_video_callback(struct zr364xx_camera *cam,
- struct zr364xx_pipeinfo *pipe_info,
- struct urb *purb)
-{
- unsigned char *pdest;
- unsigned char *psrc;
- s32 idx = cam->cur_frame;
- struct zr364xx_framei *frm = &cam->buffer.frame[idx];
- int i = 0;
- unsigned char *ptr = NULL;
-
- _DBG("buffer to user\n");
-
- /* swap bytes if camera needs it */
- if (cam->method == METHOD0) {
- u16 *buf = (u16 *)pipe_info->transfer_buffer;
- for (i = 0; i < purb->actual_length/2; i++)
- swab16s(buf + i);
- }
-
- /* search done. now find out if should be acquiring */
- if (!cam->b_acquire) {
- /* we found a frame, but this channel is turned off */
- frm->ulState = ZR364XX_READ_IDLE;
- return -EINVAL;
- }
-
- psrc = (u8 *)pipe_info->transfer_buffer;
- ptr = pdest = frm->lpvbits;
-
- if (frm->ulState == ZR364XX_READ_IDLE) {
- if (purb->actual_length < 128) {
- /* header incomplete */
- dev_info(&cam->udev->dev,
- "%s: buffer (%d bytes) too small to hold jpeg header. Discarding.\n",
- __func__, purb->actual_length);
- return -EINVAL;
- }
-
- frm->ulState = ZR364XX_READ_FRAME;
- frm->cur_size = 0;
-
- _DBG("jpeg header, ");
- memcpy(ptr, header1, sizeof(header1));
- ptr += sizeof(header1);
- header3 = 0;
- memcpy(ptr, &header3, 1);
- ptr++;
- memcpy(ptr, psrc, 64);
- ptr += 64;
- header3 = 1;
- memcpy(ptr, &header3, 1);
- ptr++;
- memcpy(ptr, psrc + 64, 64);
- ptr += 64;
- memcpy(ptr, header2, sizeof(header2));
- ptr += sizeof(header2);
- memcpy(ptr, psrc + 128,
- purb->actual_length - 128);
- ptr += purb->actual_length - 128;
- _DBG("header : %d %d %d %d %d %d %d %d %d\n",
- psrc[0], psrc[1], psrc[2],
- psrc[3], psrc[4], psrc[5],
- psrc[6], psrc[7], psrc[8]);
- frm->cur_size = ptr - pdest;
- } else {
- if (frm->cur_size + purb->actual_length > MAX_FRAME_SIZE) {
- dev_info(&cam->udev->dev,
- "%s: buffer (%d bytes) too small to hold frame data. Discarding frame data.\n",
- __func__, MAX_FRAME_SIZE);
- } else {
- pdest += frm->cur_size;
- memcpy(pdest, psrc, purb->actual_length);
- frm->cur_size += purb->actual_length;
- }
- }
- /*_DBG("cur_size %lu urb size %d\n", frm->cur_size,
- purb->actual_length);*/
-
- if (purb->actual_length < pipe_info->transfer_size) {
- _DBG("****************Buffer[%d]full*************\n", idx);
- cam->last_frame = cam->cur_frame;
- cam->cur_frame++;
- /* end of system frame ring buffer, start at zero */
- if (cam->cur_frame == cam->buffer.dwFrames)
- cam->cur_frame = 0;
-
- /* frame ready */
- /* go back to find the JPEG EOI marker */
- ptr = pdest = frm->lpvbits;
- ptr += frm->cur_size - 2;
- while (ptr > pdest) {
- if (*ptr == 0xFF && *(ptr + 1) == 0xD9
- && *(ptr + 2) == 0xFF)
- break;
- ptr--;
- }
- if (ptr == pdest)
- DBG("No EOI marker\n");
-
- /* Sometimes there is junk data in the middle of the picture,
- * we want to skip this bogus frames */
- while (ptr > pdest) {
- if (*ptr == 0xFF && *(ptr + 1) == 0xFF
- && *(ptr + 2) == 0xFF)
- break;
- ptr--;
- }
- if (ptr != pdest) {
- DBG("Bogus frame ? %d\n", ++(cam->nb));
- } else if (cam->b_acquire) {
- /* we skip the 2 first frames which are usually buggy */
- if (cam->skip)
- cam->skip--;
- else {
- _DBG("jpeg(%lu): %d %d %d %d %d %d %d %d\n",
- frm->cur_size,
- pdest[0], pdest[1], pdest[2], pdest[3],
- pdest[4], pdest[5], pdest[6], pdest[7]);
-
- zr364xx_got_frame(cam, frm->cur_size);
- }
- }
- cam->frame_count++;
- frm->ulState = ZR364XX_READ_IDLE;
- frm->cur_size = 0;
- }
- /* done successfully */
- return 0;
-}
-
-static int zr364xx_vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
- struct zr364xx_camera *cam = video_drvdata(file);
-
- strscpy(cap->driver, DRIVER_DESC, sizeof(cap->driver));
- if (cam->udev->product)
- strscpy(cap->card, cam->udev->product, sizeof(cap->card));
- strscpy(cap->bus_info, dev_name(&cam->udev->dev),
- sizeof(cap->bus_info));
- return 0;
-}
-
-static int zr364xx_vidioc_enum_input(struct file *file, void *priv,
- struct v4l2_input *i)
-{
- if (i->index != 0)
- return -EINVAL;
- strscpy(i->name, DRIVER_DESC " Camera", sizeof(i->name));
- i->type = V4L2_INPUT_TYPE_CAMERA;
- return 0;
-}
-
-static int zr364xx_vidioc_g_input(struct file *file, void *priv,
- unsigned int *i)
-{
- *i = 0;
- return 0;
-}
-
-static int zr364xx_vidioc_s_input(struct file *file, void *priv,
- unsigned int i)
-{
- if (i != 0)
- return -EINVAL;
- return 0;
-}
-
-static int zr364xx_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct zr364xx_camera *cam =
- container_of(ctrl->handler, struct zr364xx_camera, ctrl_handler);
- int temp;
-
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- /* hardware brightness */
- send_control_msg(cam->udev, 1, 0x2001, 0, NULL, 0);
- temp = (0x60 << 8) + 127 - ctrl->val;
- send_control_msg(cam->udev, 1, temp, 0, NULL, 0);
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int zr364xx_vidioc_enum_fmt_vid_cap(struct file *file,
- void *priv, struct v4l2_fmtdesc *f)
-{
- if (f->index > 0)
- return -EINVAL;
- f->pixelformat = formats[0].fourcc;
- return 0;
-}
-
-static char *decode_fourcc(__u32 pixelformat, char *buf)
-{
- buf[0] = pixelformat & 0xff;
- buf[1] = (pixelformat >> 8) & 0xff;
- buf[2] = (pixelformat >> 16) & 0xff;
- buf[3] = (pixelformat >> 24) & 0xff;
- buf[4] = '\0';
- return buf;
-}
-
-static int zr364xx_vidioc_try_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct zr364xx_camera *cam = video_drvdata(file);
- char pixelformat_name[5];
-
- if (!cam)
- return -ENODEV;
-
- if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG) {
- DBG("%s: unsupported pixelformat V4L2_PIX_FMT_%s\n", __func__,
- decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name));
- return -EINVAL;
- }
-
- if (!(f->fmt.pix.width == 160 && f->fmt.pix.height == 120) &&
- !(f->fmt.pix.width == 640 && f->fmt.pix.height == 480)) {
- f->fmt.pix.width = 320;
- f->fmt.pix.height = 240;
- }
-
- f->fmt.pix.field = V4L2_FIELD_NONE;
- f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
- f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
- f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
- DBG("%s: V4L2_PIX_FMT_%s (%d) ok!\n", __func__,
- decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name),
- f->fmt.pix.field);
- return 0;
-}
-
-static int zr364xx_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct zr364xx_camera *cam;
-
- if (!file)
- return -ENODEV;
- cam = video_drvdata(file);
-
- f->fmt.pix.pixelformat = formats[0].fourcc;
- f->fmt.pix.field = V4L2_FIELD_NONE;
- f->fmt.pix.width = cam->width;
- f->fmt.pix.height = cam->height;
- f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
- f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
- f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
- return 0;
-}
-
-static int zr364xx_vidioc_s_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct zr364xx_camera *cam = video_drvdata(file);
- struct videobuf_queue *q = &cam->vb_vidq;
- char pixelformat_name[5];
- int ret = zr364xx_vidioc_try_fmt_vid_cap(file, cam, f);
- int i;
-
- if (ret < 0)
- return ret;
-
- mutex_lock(&q->vb_lock);
-
- if (videobuf_queue_is_busy(&cam->vb_vidq)) {
- DBG("%s queue busy\n", __func__);
- ret = -EBUSY;
- goto out;
- }
-
- if (cam->owner) {
- DBG("%s can't change format after started\n", __func__);
- ret = -EBUSY;
- goto out;
- }
-
- cam->width = f->fmt.pix.width;
- cam->height = f->fmt.pix.height;
- DBG("%s: %dx%d mode selected\n", __func__,
- cam->width, cam->height);
- f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
- f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
- f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
- cam->vb_vidq.field = f->fmt.pix.field;
-
- if (f->fmt.pix.width == 160 && f->fmt.pix.height == 120)
- mode = 1;
- else if (f->fmt.pix.width == 640 && f->fmt.pix.height == 480)
- mode = 2;
- else
- mode = 0;
-
- m0d1[0] = mode;
- m1[2].value = 0xf000 + mode;
- m2[1].value = 0xf000 + mode;
-
- /* special case for METHOD3, the modes are different */
- if (cam->method == METHOD3) {
- switch (mode) {
- case 1:
- m2[1].value = 0xf000 + 4;
- break;
- case 2:
- m2[1].value = 0xf000 + 0;
- break;
- default:
- m2[1].value = 0xf000 + 1;
- break;
- }
- }
-
- header2[437] = cam->height / 256;
- header2[438] = cam->height % 256;
- header2[439] = cam->width / 256;
- header2[440] = cam->width % 256;
-
- for (i = 0; init[cam->method][i].size != -1; i++) {
- ret =
- send_control_msg(cam->udev, 1, init[cam->method][i].value,
- 0, init[cam->method][i].bytes,
- init[cam->method][i].size);
- if (ret < 0) {
- dev_err(&cam->udev->dev,
- "error during resolution change sequence: %d\n", i);
- goto out;
- }
- }
-
- /* Added some delay here, since opening/closing the camera quickly,
- * like Ekiga does during its startup, can crash the webcam
- */
- mdelay(100);
- cam->skip = 2;
- ret = 0;
-
-out:
- mutex_unlock(&q->vb_lock);
-
- DBG("%s: V4L2_PIX_FMT_%s (%d) ok!\n", __func__,
- decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name),
- f->fmt.pix.field);
- return ret;
-}
-
-static int zr364xx_vidioc_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *p)
-{
- struct zr364xx_camera *cam = video_drvdata(file);
-
- if (cam->owner && cam->owner != priv)
- return -EBUSY;
- return videobuf_reqbufs(&cam->vb_vidq, p);
-}
-
-static int zr364xx_vidioc_querybuf(struct file *file,
- void *priv,
- struct v4l2_buffer *p)
-{
- int rc;
- struct zr364xx_camera *cam = video_drvdata(file);
- rc = videobuf_querybuf(&cam->vb_vidq, p);
- return rc;
-}
-
-static int zr364xx_vidioc_qbuf(struct file *file,
- void *priv,
- struct v4l2_buffer *p)
-{
- int rc;
- struct zr364xx_camera *cam = video_drvdata(file);
- _DBG("%s\n", __func__);
- if (cam->owner && cam->owner != priv)
- return -EBUSY;
- rc = videobuf_qbuf(&cam->vb_vidq, p);
- return rc;
-}
-
-static int zr364xx_vidioc_dqbuf(struct file *file,
- void *priv,
- struct v4l2_buffer *p)
-{
- int rc;
- struct zr364xx_camera *cam = video_drvdata(file);
- _DBG("%s\n", __func__);
- if (cam->owner && cam->owner != priv)
- return -EBUSY;
- rc = videobuf_dqbuf(&cam->vb_vidq, p, file->f_flags & O_NONBLOCK);
- return rc;
-}
-
-static void read_pipe_completion(struct urb *purb)
-{
- struct zr364xx_pipeinfo *pipe_info;
- struct zr364xx_camera *cam;
- int pipe;
-
- pipe_info = purb->context;
- _DBG("%s %p, status %d\n", __func__, purb, purb->status);
- if (!pipe_info) {
- printk(KERN_ERR KBUILD_MODNAME ": no context!\n");
- return;
- }
-
- cam = pipe_info->cam;
- if (!cam) {
- printk(KERN_ERR KBUILD_MODNAME ": no context!\n");
- return;
- }
-
- /* if shutting down, do not resubmit, exit immediately */
- if (purb->status == -ESHUTDOWN) {
- DBG("%s, err shutdown\n", __func__);
- pipe_info->err_count++;
- return;
- }
-
- if (pipe_info->state == 0) {
- DBG("exiting USB pipe\n");
- return;
- }
-
- if (purb->actual_length > pipe_info->transfer_size) {
- dev_err(&cam->udev->dev, "wrong number of bytes\n");
- return;
- }
-
- if (purb->status == 0)
- zr364xx_read_video_callback(cam, pipe_info, purb);
- else {
- pipe_info->err_count++;
- DBG("%s: failed URB %d\n", __func__, purb->status);
- }
-
- pipe = usb_rcvbulkpipe(cam->udev, cam->read_endpoint);
-
- /* reuse urb */
- usb_fill_bulk_urb(pipe_info->stream_urb, cam->udev,
- pipe,
- pipe_info->transfer_buffer,
- pipe_info->transfer_size,
- read_pipe_completion, pipe_info);
-
- if (pipe_info->state != 0) {
- purb->status = usb_submit_urb(pipe_info->stream_urb,
- GFP_ATOMIC);
-
- if (purb->status)
- dev_err(&cam->udev->dev,
- "error submitting urb (error=%i)\n",
- purb->status);
- } else
- DBG("read pipe complete state 0\n");
-}
-
-static int zr364xx_start_readpipe(struct zr364xx_camera *cam)
-{
- int pipe;
- int retval;
- struct zr364xx_pipeinfo *pipe_info = cam->pipe;
- pipe = usb_rcvbulkpipe(cam->udev, cam->read_endpoint);
- DBG("%s: start pipe IN x%x\n", __func__, cam->read_endpoint);
-
- pipe_info->state = 1;
- pipe_info->err_count = 0;
- pipe_info->stream_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!pipe_info->stream_urb)
- return -ENOMEM;
- /* transfer buffer allocated in board_init */
- usb_fill_bulk_urb(pipe_info->stream_urb, cam->udev,
- pipe,
- pipe_info->transfer_buffer,
- pipe_info->transfer_size,
- read_pipe_completion, pipe_info);
-
- DBG("submitting URB %p\n", pipe_info->stream_urb);
- retval = usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL);
- if (retval) {
- usb_free_urb(pipe_info->stream_urb);
- printk(KERN_ERR KBUILD_MODNAME ": start read pipe failed\n");
- return retval;
- }
-
- return 0;
-}
-
-static void zr364xx_stop_readpipe(struct zr364xx_camera *cam)
-{
- struct zr364xx_pipeinfo *pipe_info;
-
- if (!cam) {
- printk(KERN_ERR KBUILD_MODNAME ": invalid device\n");
- return;
- }
- DBG("stop read pipe\n");
- pipe_info = cam->pipe;
- if (pipe_info) {
- if (pipe_info->state != 0)
- pipe_info->state = 0;
-
- if (pipe_info->stream_urb) {
- /* cancel urb */
- usb_kill_urb(pipe_info->stream_urb);
- usb_free_urb(pipe_info->stream_urb);
- pipe_info->stream_urb = NULL;
- }
- }
- return;
-}
-
-/* starts acquisition process */
-static int zr364xx_start_acquire(struct zr364xx_camera *cam)
-{
- int j;
-
- DBG("start acquire\n");
-
- cam->last_frame = -1;
- cam->cur_frame = 0;
- for (j = 0; j < FRAMES; j++) {
- cam->buffer.frame[j].ulState = ZR364XX_READ_IDLE;
- cam->buffer.frame[j].cur_size = 0;
- }
- cam->b_acquire = 1;
- return 0;
-}
-
-static inline int zr364xx_stop_acquire(struct zr364xx_camera *cam)
-{
- cam->b_acquire = 0;
- return 0;
-}
-
-static int zr364xx_prepare(struct zr364xx_camera *cam)
-{
- int res;
- int i, j;
-
- for (i = 0; init[cam->method][i].size != -1; i++) {
- res = send_control_msg(cam->udev, 1, init[cam->method][i].value,
- 0, init[cam->method][i].bytes,
- init[cam->method][i].size);
- if (res < 0) {
- dev_err(&cam->udev->dev,
- "error during open sequence: %d\n", i);
- return res;
- }
- }
-
- cam->skip = 2;
- cam->last_frame = -1;
- cam->cur_frame = 0;
- cam->frame_count = 0;
- for (j = 0; j < FRAMES; j++) {
- cam->buffer.frame[j].ulState = ZR364XX_READ_IDLE;
- cam->buffer.frame[j].cur_size = 0;
- }
- v4l2_ctrl_handler_setup(&cam->ctrl_handler);
- return 0;
-}
-
-static int zr364xx_vidioc_streamon(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct zr364xx_camera *cam = video_drvdata(file);
- int res;
-
- DBG("%s\n", __func__);
-
- if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- if (cam->owner && cam->owner != priv)
- return -EBUSY;
-
- res = zr364xx_prepare(cam);
- if (res)
- return res;
- res = videobuf_streamon(&cam->vb_vidq);
- if (res == 0) {
- zr364xx_start_acquire(cam);
- cam->owner = file->private_data;
- }
- return res;
-}
-
-static int zr364xx_vidioc_streamoff(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct zr364xx_camera *cam = video_drvdata(file);
-
- DBG("%s\n", __func__);
- if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (cam->owner && cam->owner != priv)
- return -EBUSY;
- zr364xx_stop_acquire(cam);
- return videobuf_streamoff(&cam->vb_vidq);
-}
-
-
-/* open the camera */
-static int zr364xx_open(struct file *file)
-{
- struct zr364xx_camera *cam = video_drvdata(file);
- int err;
-
- DBG("%s\n", __func__);
-
- if (mutex_lock_interruptible(&cam->lock))
- return -ERESTARTSYS;
-
- err = v4l2_fh_open(file);
- if (err)
- goto out;
-
- /* Added some delay here, since opening/closing the camera quickly,
- * like Ekiga does during its startup, can crash the webcam
- */
- mdelay(100);
- err = 0;
-
-out:
- mutex_unlock(&cam->lock);
- DBG("%s: %d\n", __func__, err);
- return err;
-}
-
-static void zr364xx_board_uninit(struct zr364xx_camera *cam)
-{
- unsigned long i;
-
- zr364xx_stop_readpipe(cam);
-
- /* release sys buffers */
- for (i = 0; i < FRAMES; i++) {
- if (cam->buffer.frame[i].lpvbits) {
- DBG("vfree %p\n", cam->buffer.frame[i].lpvbits);
- vfree(cam->buffer.frame[i].lpvbits);
- }
- cam->buffer.frame[i].lpvbits = NULL;
- }
-
- /* release transfer buffer */
- kfree(cam->pipe->transfer_buffer);
-}
-
-static void zr364xx_release(struct v4l2_device *v4l2_dev)
-{
- struct zr364xx_camera *cam =
- container_of(v4l2_dev, struct zr364xx_camera, v4l2_dev);
-
- videobuf_mmap_free(&cam->vb_vidq);
- v4l2_ctrl_handler_free(&cam->ctrl_handler);
- zr364xx_board_uninit(cam);
- v4l2_device_unregister(&cam->v4l2_dev);
- kfree(cam);
-}
-
-/* release the camera */
-static int zr364xx_close(struct file *file)
-{
- struct zr364xx_camera *cam;
- struct usb_device *udev;
- int i;
-
- DBG("%s\n", __func__);
- cam = video_drvdata(file);
-
- mutex_lock(&cam->lock);
- udev = cam->udev;
-
- if (file->private_data == cam->owner) {
- /* turn off stream */
- if (cam->b_acquire)
- zr364xx_stop_acquire(cam);
- videobuf_streamoff(&cam->vb_vidq);
-
- for (i = 0; i < 2; i++) {
- send_control_msg(udev, 1, init[cam->method][i].value,
- 0, init[cam->method][i].bytes,
- init[cam->method][i].size);
- }
- cam->owner = NULL;
- }
-
- /* Added some delay here, since opening/closing the camera quickly,
- * like Ekiga does during its startup, can crash the webcam
- */
- mdelay(100);
- mutex_unlock(&cam->lock);
- return v4l2_fh_release(file);
-}
-
-
-static int zr364xx_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct zr364xx_camera *cam = video_drvdata(file);
- int ret;
-
- if (!cam) {
- DBG("%s: cam == NULL\n", __func__);
- return -ENODEV;
- }
- DBG("mmap called, vma=%p\n", vma);
-
- ret = videobuf_mmap_mapper(&cam->vb_vidq, vma);
-
- DBG("vma start=0x%08lx, size=%ld, ret=%d\n",
- (unsigned long)vma->vm_start,
- (unsigned long)vma->vm_end - (unsigned long)vma->vm_start, ret);
- return ret;
-}
-
-static __poll_t zr364xx_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct zr364xx_camera *cam = video_drvdata(file);
- struct videobuf_queue *q = &cam->vb_vidq;
- __poll_t res = v4l2_ctrl_poll(file, wait);
-
- _DBG("%s\n", __func__);
-
- return res | videobuf_poll_stream(file, q, wait);
-}
-
-static const struct v4l2_ctrl_ops zr364xx_ctrl_ops = {
- .s_ctrl = zr364xx_s_ctrl,
-};
-
-static const struct v4l2_file_operations zr364xx_fops = {
- .owner = THIS_MODULE,
- .open = zr364xx_open,
- .release = zr364xx_close,
- .read = zr364xx_read,
- .mmap = zr364xx_mmap,
- .unlocked_ioctl = video_ioctl2,
- .poll = zr364xx_poll,
-};
-
-static const struct v4l2_ioctl_ops zr364xx_ioctl_ops = {
- .vidioc_querycap = zr364xx_vidioc_querycap,
- .vidioc_enum_fmt_vid_cap = zr364xx_vidioc_enum_fmt_vid_cap,
- .vidioc_try_fmt_vid_cap = zr364xx_vidioc_try_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = zr364xx_vidioc_s_fmt_vid_cap,
- .vidioc_g_fmt_vid_cap = zr364xx_vidioc_g_fmt_vid_cap,
- .vidioc_enum_input = zr364xx_vidioc_enum_input,
- .vidioc_g_input = zr364xx_vidioc_g_input,
- .vidioc_s_input = zr364xx_vidioc_s_input,
- .vidioc_streamon = zr364xx_vidioc_streamon,
- .vidioc_streamoff = zr364xx_vidioc_streamoff,
- .vidioc_reqbufs = zr364xx_vidioc_reqbufs,
- .vidioc_querybuf = zr364xx_vidioc_querybuf,
- .vidioc_qbuf = zr364xx_vidioc_qbuf,
- .vidioc_dqbuf = zr364xx_vidioc_dqbuf,
- .vidioc_log_status = v4l2_ctrl_log_status,
- .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
- .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
-};
-
-static const struct video_device zr364xx_template = {
- .name = DRIVER_DESC,
- .fops = &zr364xx_fops,
- .ioctl_ops = &zr364xx_ioctl_ops,
- .release = video_device_release_empty,
- .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING,
-};
-
-
-
-/*******************/
-/* USB integration */
-/*******************/
-static int zr364xx_board_init(struct zr364xx_camera *cam)
-{
- struct zr364xx_pipeinfo *pipe = cam->pipe;
- unsigned long i;
- int err;
-
- DBG("board init: %p\n", cam);
- memset(pipe, 0, sizeof(*pipe));
- pipe->cam = cam;
- pipe->transfer_size = BUFFER_SIZE;
-
- pipe->transfer_buffer = kzalloc(pipe->transfer_size,
- GFP_KERNEL);
- if (!pipe->transfer_buffer) {
- DBG("out of memory!\n");
- return -ENOMEM;
- }
-
- cam->b_acquire = 0;
- cam->frame_count = 0;
-
- /*** start create system buffers ***/
- for (i = 0; i < FRAMES; i++) {
- /* always allocate maximum size for system buffers */
- cam->buffer.frame[i].lpvbits = vmalloc(MAX_FRAME_SIZE);
-
- DBG("valloc %p, idx %lu, pdata %p\n",
- &cam->buffer.frame[i], i,
- cam->buffer.frame[i].lpvbits);
- if (!cam->buffer.frame[i].lpvbits) {
- printk(KERN_INFO KBUILD_MODNAME ": out of memory. Using less frames\n");
- break;
- }
- }
-
- if (i == 0) {
- printk(KERN_INFO KBUILD_MODNAME ": out of memory. Aborting\n");
- err = -ENOMEM;
- goto err_free;
- } else
- cam->buffer.dwFrames = i;
-
- /* make sure internal states are set */
- for (i = 0; i < FRAMES; i++) {
- cam->buffer.frame[i].ulState = ZR364XX_READ_IDLE;
- cam->buffer.frame[i].cur_size = 0;
- }
-
- cam->cur_frame = 0;
- cam->last_frame = -1;
- /*** end create system buffers ***/
-
- /* start read pipe */
- err = zr364xx_start_readpipe(cam);
- if (err)
- goto err_free_frames;
-
- DBG(": board initialized\n");
- return 0;
-
-err_free_frames:
- for (i = 0; i < FRAMES; i++)
- vfree(cam->buffer.frame[i].lpvbits);
-err_free:
- kfree(cam->pipe->transfer_buffer);
- cam->pipe->transfer_buffer = NULL;
- return err;
-}
-
-static int zr364xx_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- struct usb_device *udev = interface_to_usbdev(intf);
- struct zr364xx_camera *cam = NULL;
- struct usb_host_interface *iface_desc;
- struct usb_endpoint_descriptor *endpoint;
- struct v4l2_ctrl_handler *hdl;
- int err;
- int i;
-
- DBG("probing...\n");
-
- dev_info(&intf->dev, DRIVER_DESC " compatible webcam plugged\n");
- dev_info(&intf->dev, "model %04x:%04x detected\n",
- le16_to_cpu(udev->descriptor.idVendor),
- le16_to_cpu(udev->descriptor.idProduct));
-
- cam = kzalloc(sizeof(*cam), GFP_KERNEL);
- if (!cam)
- return -ENOMEM;
-
- err = v4l2_device_register(&intf->dev, &cam->v4l2_dev);
- if (err < 0) {
- dev_err(&udev->dev, "couldn't register v4l2_device\n");
- goto free_cam;
- }
- hdl = &cam->ctrl_handler;
- v4l2_ctrl_handler_init(hdl, 1);
- v4l2_ctrl_new_std(hdl, &zr364xx_ctrl_ops,
- V4L2_CID_BRIGHTNESS, 0, 127, 1, 64);
- if (hdl->error) {
- err = hdl->error;
- dev_err(&udev->dev, "couldn't register control\n");
- goto free_hdlr_and_unreg_dev;
- }
- /* save the init method used by this camera */
- cam->method = id->driver_info;
- mutex_init(&cam->lock);
- cam->vdev = zr364xx_template;
- cam->vdev.lock = &cam->lock;
- cam->vdev.v4l2_dev = &cam->v4l2_dev;
- cam->vdev.ctrl_handler = &cam->ctrl_handler;
- video_set_drvdata(&cam->vdev, cam);
-
- cam->udev = udev;
-
- switch (mode) {
- case 1:
- dev_info(&udev->dev, "160x120 mode selected\n");
- cam->width = 160;
- cam->height = 120;
- break;
- case 2:
- dev_info(&udev->dev, "640x480 mode selected\n");
- cam->width = 640;
- cam->height = 480;
- break;
- default:
- dev_info(&udev->dev, "320x240 mode selected\n");
- cam->width = 320;
- cam->height = 240;
- break;
- }
-
- m0d1[0] = mode;
- m1[2].value = 0xf000 + mode;
- m2[1].value = 0xf000 + mode;
-
- /* special case for METHOD3, the modes are different */
- if (cam->method == METHOD3) {
- switch (mode) {
- case 1:
- m2[1].value = 0xf000 + 4;
- break;
- case 2:
- m2[1].value = 0xf000 + 0;
- break;
- default:
- m2[1].value = 0xf000 + 1;
- break;
- }
- }
-
- header2[437] = cam->height / 256;
- header2[438] = cam->height % 256;
- header2[439] = cam->width / 256;
- header2[440] = cam->width % 256;
-
- cam->nb = 0;
-
- DBG("dev: %p, udev %p interface %p\n", cam, cam->udev, intf);
-
- /* set up the endpoint information */
- iface_desc = intf->cur_altsetting;
- DBG("num endpoints %d\n", iface_desc->desc.bNumEndpoints);
- for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
- endpoint = &iface_desc->endpoint[i].desc;
- if (!cam->read_endpoint && usb_endpoint_is_bulk_in(endpoint)) {
- /* we found the bulk in endpoint */
- cam->read_endpoint = endpoint->bEndpointAddress;
- }
- }
-
- if (!cam->read_endpoint) {
- err = -ENOMEM;
- dev_err(&intf->dev, "Could not find bulk-in endpoint\n");
- goto free_hdlr_and_unreg_dev;
- }
-
- /* v4l */
- INIT_LIST_HEAD(&cam->vidq.active);
- cam->vidq.cam = cam;
-
- usb_set_intfdata(intf, cam);
-
- /* load zr364xx board specific */
- err = zr364xx_board_init(cam);
- if (err)
- goto free_hdlr_and_unreg_dev;
- err = v4l2_ctrl_handler_setup(hdl);
- if (err)
- goto board_uninit;
-
- spin_lock_init(&cam->slock);
-
- cam->fmt = formats;
-
- videobuf_queue_vmalloc_init(&cam->vb_vidq, &zr364xx_video_qops,
- NULL, &cam->slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_NONE,
- sizeof(struct zr364xx_buffer), cam, &cam->lock);
-
- err = video_register_device(&cam->vdev, VFL_TYPE_VIDEO, -1);
- if (err) {
- dev_err(&udev->dev, "video_register_device failed\n");
- goto board_uninit;
- }
- cam->v4l2_dev.release = zr364xx_release;
-
- dev_info(&udev->dev, DRIVER_DESC " controlling device %s\n",
- video_device_node_name(&cam->vdev));
- return 0;
-
-board_uninit:
- zr364xx_board_uninit(cam);
-free_hdlr_and_unreg_dev:
- v4l2_ctrl_handler_free(hdl);
- v4l2_device_unregister(&cam->v4l2_dev);
-free_cam:
- kfree(cam);
- return err;
-}
-
-
-static void zr364xx_disconnect(struct usb_interface *intf)
-{
- struct zr364xx_camera *cam = usb_get_intfdata(intf);
-
- mutex_lock(&cam->lock);
- usb_set_intfdata(intf, NULL);
- dev_info(&intf->dev, DRIVER_DESC " webcam unplugged\n");
- video_unregister_device(&cam->vdev);
- v4l2_device_disconnect(&cam->v4l2_dev);
-
- /* stops the read pipe if it is running */
- if (cam->b_acquire)
- zr364xx_stop_acquire(cam);
-
- zr364xx_stop_readpipe(cam);
- mutex_unlock(&cam->lock);
- v4l2_device_put(&cam->v4l2_dev);
-}
-
-
-#ifdef CONFIG_PM
-static int zr364xx_suspend(struct usb_interface *intf, pm_message_t message)
-{
- struct zr364xx_camera *cam = usb_get_intfdata(intf);
-
- cam->was_streaming = cam->b_acquire;
- if (!cam->was_streaming)
- return 0;
- zr364xx_stop_acquire(cam);
- zr364xx_stop_readpipe(cam);
- return 0;
-}
-
-static int zr364xx_resume(struct usb_interface *intf)
-{
- struct zr364xx_camera *cam = usb_get_intfdata(intf);
- int res;
-
- if (!cam->was_streaming)
- return 0;
-
- res = zr364xx_start_readpipe(cam);
- if (res)
- return res;
-
- res = zr364xx_prepare(cam);
- if (res)
- goto err_prepare;
-
- zr364xx_start_acquire(cam);
- return 0;
-
-err_prepare:
- zr364xx_stop_readpipe(cam);
- return res;
-}
-#endif
-
-/**********************/
-/* Module integration */
-/**********************/
-
-static struct usb_driver zr364xx_driver = {
- .name = "zr364xx",
- .probe = zr364xx_probe,
- .disconnect = zr364xx_disconnect,
-#ifdef CONFIG_PM
- .suspend = zr364xx_suspend,
- .resume = zr364xx_resume,
- .reset_resume = zr364xx_resume,
-#endif
- .id_table = device_table
-};
-
-module_usb_driver(zr364xx_driver);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c
index 5c3cc7de209d..44d87fe30d52 100644
--- a/drivers/staging/media/imx/imx-media-csi.c
+++ b/drivers/staging/media/imx/imx-media-csi.c
@@ -779,11 +779,8 @@ static int csi_start(struct csi_priv *priv)
goto idmac_stop;
/* start the frame interval monitor */
- if (priv->fim && priv->dest == IPU_CSI_DEST_IDMAC) {
- ret = imx_media_fim_set_stream(priv->fim, output_fi, true);
- if (ret)
- goto idmac_stop;
- }
+ if (priv->fim && priv->dest == IPU_CSI_DEST_IDMAC)
+ imx_media_fim_set_stream(priv->fim, output_fi, true);
ret = ipu_csi_enable(priv->csi);
if (ret) {
diff --git a/drivers/staging/media/imx/imx-media-fim.c b/drivers/staging/media/imx/imx-media-fim.c
index fb6590dcfc36..e28a33d9dec7 100644
--- a/drivers/staging/media/imx/imx-media-fim.c
+++ b/drivers/staging/media/imx/imx-media-fim.c
@@ -68,7 +68,10 @@ struct imx_media_fim {
bool stream_on;
};
-#define icap_enabled(fim) ((fim)->icap_flags != IRQ_TYPE_NONE)
+static bool icap_enabled(struct imx_media_fim *fim)
+{
+ return fim->icap_flags != IRQ_TYPE_NONE;
+}
static void update_fim_nominal(struct imx_media_fim *fim,
const struct v4l2_fract *fi)
@@ -368,12 +371,11 @@ void imx_media_fim_eof_monitor(struct imx_media_fim *fim, ktime_t timestamp)
}
/* Called by the subdev in its s_stream callback */
-int imx_media_fim_set_stream(struct imx_media_fim *fim,
- const struct v4l2_fract *fi,
- bool on)
+void imx_media_fim_set_stream(struct imx_media_fim *fim,
+ const struct v4l2_fract *fi,
+ bool on)
{
unsigned long flags;
- int ret = 0;
v4l2_ctrl_lock(fim->ctrl[FIM_CL_ENABLE]);
@@ -393,7 +395,6 @@ int imx_media_fim_set_stream(struct imx_media_fim *fim,
fim->stream_on = on;
out:
v4l2_ctrl_unlock(fim->ctrl[FIM_CL_ENABLE]);
- return ret;
}
int imx_media_fim_add_controls(struct imx_media_fim *fim)
diff --git a/drivers/staging/media/imx/imx-media.h b/drivers/staging/media/imx/imx-media.h
index f679249d82e4..6f9a46573edd 100644
--- a/drivers/staging/media/imx/imx-media.h
+++ b/drivers/staging/media/imx/imx-media.h
@@ -246,9 +246,9 @@ int imx_media_dev_notifier_register(struct imx_media_dev *imxmd,
/* imx-media-fim.c */
struct imx_media_fim;
void imx_media_fim_eof_monitor(struct imx_media_fim *fim, ktime_t timestamp);
-int imx_media_fim_set_stream(struct imx_media_fim *fim,
- const struct v4l2_fract *frame_interval,
- bool on);
+void imx_media_fim_set_stream(struct imx_media_fim *fim,
+ const struct v4l2_fract *frame_interval,
+ bool on);
int imx_media_fim_add_controls(struct imx_media_fim *fim);
struct imx_media_fim *imx_media_fim_init(struct v4l2_subdev *sd);
void imx_media_fim_free(struct imx_media_fim *fim);
diff --git a/drivers/staging/media/meson/vdec/esparser.c b/drivers/staging/media/meson/vdec/esparser.c
index 86ccc8937afc..7b15fc54efe4 100644
--- a/drivers/staging/media/meson/vdec/esparser.c
+++ b/drivers/staging/media/meson/vdec/esparser.c
@@ -314,8 +314,7 @@ esparser_queue(struct amvdec_session *sess, struct vb2_v4l2_buffer *vbuf)
num_dst_bufs = codec_ops->num_pending_bufs(sess);
num_dst_bufs += v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx);
- if (sess->fmt_out->pixfmt == V4L2_PIX_FMT_VP9)
- num_dst_bufs -= 3;
+ num_dst_bufs -= 3;
if (esparser_vififo_get_free_space(sess) < payload_size ||
atomic_read(&sess->esparser_queued_bufs) >= num_dst_bufs)
diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c
index 0ad70faa9ba0..05548eab7daa 100644
--- a/drivers/staging/media/omap4iss/iss_video.c
+++ b/drivers/staging/media/omap4iss/iss_video.c
@@ -201,39 +201,34 @@ iss_video_remote_subdev(struct iss_video *video, u32 *pad)
/* Return a pointer to the ISS video instance at the far end of the pipeline. */
static struct iss_video *
-iss_video_far_end(struct iss_video *video)
+iss_video_far_end(struct iss_video *video, struct iss_pipeline *pipe)
{
- struct media_graph graph;
- struct media_entity *entity = &video->video.entity;
- struct media_device *mdev = entity->graph_obj.mdev;
+ struct media_pipeline_entity_iter iter;
+ struct media_entity *entity;
struct iss_video *far_end = NULL;
+ int ret;
- mutex_lock(&mdev->graph_mutex);
-
- if (media_graph_walk_init(&graph, mdev)) {
- mutex_unlock(&mdev->graph_mutex);
- return NULL;
- }
+ ret = media_pipeline_entity_iter_init(&pipe->pipe, &iter);
+ if (ret)
+ return ERR_PTR(-ENOMEM);
- media_graph_walk_start(&graph, entity);
+ media_pipeline_for_each_entity(&pipe->pipe, &iter, entity) {
+ struct iss_video *other;
- while ((entity = media_graph_walk_next(&graph))) {
if (entity == &video->video.entity)
continue;
if (!is_media_entity_v4l2_video_device(entity))
continue;
- far_end = to_iss_video(media_entity_to_video_device(entity));
- if (far_end->type != video->type)
+ other = to_iss_video(media_entity_to_video_device(entity));
+ if (other->type != video->type) {
+ far_end = other;
break;
-
- far_end = NULL;
+ }
}
- mutex_unlock(&mdev->graph_mutex);
-
- media_graph_walk_cleanup(&graph);
+ media_pipeline_entity_iter_cleanup(&iter);
return far_end;
}
@@ -850,12 +845,12 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
{
struct iss_video_fh *vfh = to_iss_video_fh(fh);
struct iss_video *video = video_drvdata(file);
- struct media_graph graph;
- struct media_entity *entity = &video->video.entity;
- struct media_device *mdev = entity->graph_obj.mdev;
+ struct media_device *mdev = video->video.entity.graph_obj.mdev;
+ struct media_pipeline_pad_iter iter;
enum iss_pipeline_state state;
struct iss_pipeline *pipe;
struct iss_video *far_end;
+ struct media_pad *pad;
unsigned long flags;
int ret;
@@ -873,13 +868,9 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
pipe->external_rate = 0;
pipe->external_bpp = 0;
- ret = media_entity_enum_init(&pipe->ent_enum, entity->graph_obj.mdev);
- if (ret)
- goto err_graph_walk_init;
-
- ret = media_graph_walk_init(&graph, entity->graph_obj.mdev);
+ ret = media_entity_enum_init(&pipe->ent_enum, mdev);
if (ret)
- goto err_graph_walk_init;
+ goto err_entity_enum_init;
if (video->iss->pdata->set_constraints)
video->iss->pdata->set_constraints(video->iss, true);
@@ -888,11 +879,8 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
if (ret < 0)
goto err_media_pipeline_start;
- mutex_lock(&mdev->graph_mutex);
- media_graph_walk_start(&graph, entity);
- while ((entity = media_graph_walk_next(&graph)))
- media_entity_enum_set(&pipe->ent_enum, entity);
- mutex_unlock(&mdev->graph_mutex);
+ media_pipeline_for_each_pad(&pipe->pipe, &iter, pad)
+ media_entity_enum_set(&pipe->ent_enum, pad->entity);
/*
* Verify that the currently configured format matches the output of
@@ -909,7 +897,11 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
* Find the ISS video node connected at the far end of the pipeline and
* update the pipeline.
*/
- far_end = iss_video_far_end(video);
+ far_end = iss_video_far_end(video, pipe);
+ if (IS_ERR(far_end)) {
+ ret = PTR_ERR(far_end);
+ goto err_iss_video_check_format;
+ }
if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
state = ISS_PIPELINE_STREAM_OUTPUT | ISS_PIPELINE_IDLE_OUTPUT;
@@ -966,8 +958,6 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
spin_unlock_irqrestore(&video->qlock, flags);
}
- media_graph_walk_cleanup(&graph);
-
mutex_unlock(&video->stream_lock);
return 0;
@@ -981,9 +971,7 @@ err_media_pipeline_start:
video->iss->pdata->set_constraints(video->iss, false);
video->queue = NULL;
- media_graph_walk_cleanup(&graph);
-
-err_graph_walk_init:
+err_entity_enum_init:
media_entity_enum_cleanup(&pipe->ent_enum);
mutex_unlock(&video->stream_lock);
diff --git a/drivers/staging/pi433/TODO b/drivers/staging/pi433/TODO
index 5cf3fd99d521..23c808fc99de 100644
--- a/drivers/staging/pi433/TODO
+++ b/drivers/staging/pi433/TODO
@@ -3,3 +3,6 @@
* Some missing data (marked with ###) needs to be added in the documentation
* Change (struct pi433_tx_cfg)->bit_rate to be a u32 so that we can support
bit rates up to 300kbps per the spec.
+ -> This configuration needs to be moved to sysfs instead of being done through
+ IOCTL. Going forward, we need to port userspace tools to use sysfs instead
+ of IOCTL and then we would delete IOCTL.
diff --git a/drivers/staging/pi433/pi433_if.c b/drivers/staging/pi433/pi433_if.c
index d4e06a3929f3..b59f6a4cb611 100644
--- a/drivers/staging/pi433/pi433_if.c
+++ b/drivers/staging/pi433/pi433_if.c
@@ -55,6 +55,7 @@
static dev_t pi433_dev;
static DEFINE_IDR(pi433_idr);
static DEFINE_MUTEX(minor_lock); /* Protect idr accesses */
+static struct dentry *root_dir; /* debugfs root directory for the driver */
static struct class *pi433_class; /* mainly for udev to create /dev/pi433 */
@@ -1306,8 +1307,7 @@ static int pi433_probe(struct spi_device *spi)
/* spi setup */
spi_set_drvdata(spi, device);
- entry = debugfs_create_dir(dev_name(device->dev),
- debugfs_lookup(KBUILD_MODNAME, NULL));
+ entry = debugfs_create_dir(dev_name(device->dev), root_dir);
debugfs_create_file("regs", 0400, entry, device, &pi433_debugfs_regs_fops);
return 0;
@@ -1333,9 +1333,8 @@ RX_failed:
static void pi433_remove(struct spi_device *spi)
{
struct pi433_device *device = spi_get_drvdata(spi);
- struct dentry *mod_entry = debugfs_lookup(KBUILD_MODNAME, NULL);
- debugfs_remove(debugfs_lookup(dev_name(device->dev), mod_entry));
+ debugfs_lookup_and_remove(dev_name(device->dev), root_dir);
/* free GPIOs */
free_gpio(device);
@@ -1408,7 +1407,7 @@ static int __init pi433_init(void)
return PTR_ERR(pi433_class);
}
- debugfs_create_dir(KBUILD_MODNAME, NULL);
+ root_dir = debugfs_create_dir(KBUILD_MODNAME, NULL);
status = spi_register_driver(&pi433_spi_driver);
if (status < 0) {
@@ -1427,7 +1426,7 @@ static void __exit pi433_exit(void)
spi_unregister_driver(&pi433_spi_driver);
class_destroy(pi433_class);
unregister_chrdev(MAJOR(pi433_dev), pi433_spi_driver.driver.name);
- debugfs_remove_recursive(debugfs_lookup(KBUILD_MODNAME, NULL));
+ debugfs_remove(root_dir);
}
module_exit(pi433_exit);
diff --git a/drivers/staging/r8188eu/core/rtw_cmd.c b/drivers/staging/r8188eu/core/rtw_cmd.c
index 19b2f73d481d..ca9e3d4ee7f4 100644
--- a/drivers/staging/r8188eu/core/rtw_cmd.c
+++ b/drivers/staging/r8188eu/core/rtw_cmd.c
@@ -28,32 +28,6 @@ void rtw_free_evt_priv(struct evt_priv *pevtpriv)
}
}
-/* Calling Context:
- *
- * rtw_enqueue_cmd can only be called between kernel thread,
- * since only spin_lock is used.
- *
- * ISR/Call-Back functions can't call this sub-function.
- */
-
-static int _rtw_enqueue_cmd(struct __queue *queue, struct cmd_obj *obj)
-{
- unsigned long flags;
-
- if (!obj)
- goto exit;
-
- spin_lock_irqsave(&queue->lock, flags);
-
- list_add_tail(&obj->list, &queue->queue);
-
- spin_unlock_irqrestore(&queue->lock, flags);
-
-exit:
-
- return _SUCCESS;
-}
-
int rtw_init_cmd_priv(struct cmd_priv *pcmdpriv)
{
init_completion(&pcmdpriv->enqueue_cmd);
@@ -65,8 +39,6 @@ int rtw_init_cmd_priv(struct cmd_priv *pcmdpriv)
/* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */
- pcmdpriv->cmd_seq = 1;
-
pcmdpriv->cmd_allocated_buf = kzalloc(MAX_CMDSZ + CMDBUFF_ALIGN_SZ,
GFP_KERNEL);
@@ -127,28 +99,25 @@ static int rtw_cmd_filter(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj)
u32 rtw_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj)
{
- int res = _FAIL;
+ unsigned long flags;
struct adapter *padapter = pcmdpriv->padapter;
if (!cmd_obj)
- goto exit;
+ return _FAIL;
cmd_obj->padapter = padapter;
- res = rtw_cmd_filter(pcmdpriv, cmd_obj);
- if (res == _FAIL) {
+ if (rtw_cmd_filter(pcmdpriv, cmd_obj) == _FAIL) {
rtw_free_cmd_obj(cmd_obj);
- goto exit;
+ return _FAIL;
}
- res = _rtw_enqueue_cmd(&pcmdpriv->cmd_queue, cmd_obj);
-
- if (res == _SUCCESS)
- complete(&pcmdpriv->enqueue_cmd);
-
-exit:
+ spin_lock_irqsave(&pcmdpriv->cmd_queue.lock, flags);
+ list_add_tail(&cmd_obj->list, &pcmdpriv->cmd_queue.queue);
+ spin_unlock_irqrestore(&pcmdpriv->cmd_queue.lock, flags);
- return res;
+ complete(&pcmdpriv->enqueue_cmd);
+ return _SUCCESS;
}
struct cmd_obj *rtw_dequeue_cmd(struct cmd_priv *pcmdpriv)
@@ -233,8 +202,6 @@ _next:
ret = cmd_hdl(pcmd->padapter, pcmdbuf);
pcmd->res = ret;
}
-
- pcmdpriv->cmd_seq++;
} else {
pcmd->res = H2C_PARAMETERS_ERROR;
}
@@ -1201,24 +1168,20 @@ static void rtw_chk_hi_queue_hdl(struct adapter *padapter)
}
}
-u8 rtw_chk_hi_queue_cmd(struct adapter *padapter)
+void rtw_chk_hi_queue_cmd(struct adapter *padapter)
{
struct cmd_obj *ph2c;
struct drvextra_cmd_parm *pdrvextra_cmd_parm;
struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
- u8 res = _SUCCESS;
ph2c = kzalloc(sizeof(*ph2c), GFP_ATOMIC);
- if (!ph2c) {
- res = _FAIL;
- goto exit;
- }
+ if (!ph2c)
+ return;
pdrvextra_cmd_parm = kzalloc(sizeof(*pdrvextra_cmd_parm), GFP_ATOMIC);
if (!pdrvextra_cmd_parm) {
kfree(ph2c);
- res = _FAIL;
- goto exit;
+ return;
}
pdrvextra_cmd_parm->ec_id = CHECK_HIQ_WK_CID;
@@ -1227,9 +1190,7 @@ u8 rtw_chk_hi_queue_cmd(struct adapter *padapter)
init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
- res = rtw_enqueue_cmd(pcmdpriv, ph2c);
-exit:
- return res;
+ rtw_enqueue_cmd(pcmdpriv, ph2c);
}
u8 rtw_c2h_wk_cmd(struct adapter *padapter, u8 *c2h_evt)
diff --git a/drivers/staging/r8188eu/core/rtw_fw.c b/drivers/staging/r8188eu/core/rtw_fw.c
index 682c65b1e04c..1e4baf74ecd5 100644
--- a/drivers/staging/r8188eu/core/rtw_fw.c
+++ b/drivers/staging/r8188eu/core/rtw_fw.c
@@ -89,9 +89,8 @@ static int block_write(struct adapter *padapter, u8 *buffer, u32 size)
addr = FW_8188E_START_ADDRESS + i * block_size;
data = buffer + i * block_size;
- ret = rtw_writeN(padapter, addr, block_size, data);
- if (ret == _FAIL)
- goto exit;
+ if (rtw_writeN(padapter, addr, block_size, data))
+ return _FAIL;
}
if (remain) {
@@ -105,9 +104,8 @@ static int block_write(struct adapter *padapter, u8 *buffer, u32 size)
addr = FW_8188E_START_ADDRESS + offset + i * block_size;
data = buffer + offset + i * block_size;
- ret = rtw_writeN(padapter, addr, block_size, data);
- if (ret == _FAIL)
- goto exit;
+ if (rtw_writeN(padapter, addr, block_size, data))
+ return _FAIL;
}
}
diff --git a/drivers/staging/r8188eu/core/rtw_mlme.c b/drivers/staging/r8188eu/core/rtw_mlme.c
index b272123626ac..fb7d0e161fdd 100644
--- a/drivers/staging/r8188eu/core/rtw_mlme.c
+++ b/drivers/staging/r8188eu/core/rtw_mlme.c
@@ -444,8 +444,6 @@ static void update_current_network(struct adapter *adapter, struct wlan_bssid_ex
if (check_fwstate(pmlmepriv, _FW_LINKED) &&
is_same_network(&pmlmepriv->cur_network.network, pnetwork)) {
update_network(&pmlmepriv->cur_network.network, pnetwork, adapter, true);
- rtw_update_protection(adapter, (pmlmepriv->cur_network.network.IEs) + sizeof(struct ndis_802_11_fixed_ie),
- pmlmepriv->cur_network.network.IELength);
}
}
@@ -1027,9 +1025,6 @@ static void rtw_joinbss_update_network(struct adapter *padapter, struct wlan_net
break;
}
- rtw_update_protection(padapter, (cur_network->network.IEs) +
- sizeof(struct ndis_802_11_fixed_ie),
- (cur_network->network.IELength));
rtw_update_ht_cap(padapter, cur_network->network.IEs, cur_network->network.IELength);
}
diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c
index 1b9cf7596a76..dc181e491b34 100644
--- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c
+++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c
@@ -3735,35 +3735,18 @@ static unsigned int on_action_public_p2p(struct recv_frame *precv_frame)
return _SUCCESS;
}
-static void on_action_public_vendor(struct recv_frame *precv_frame)
-{
- u8 *pframe = precv_frame->rx_data;
- u8 *frame_body = pframe + sizeof(struct ieee80211_hdr_3addr);
-
- if (!memcmp(frame_body + 2, P2P_OUI, 4))
- on_action_public_p2p(precv_frame);
-}
-
-static void on_action_public_default(struct recv_frame *precv_frame)
-{
- u8 *pframe = precv_frame->rx_data;
- u8 *frame_body = pframe + sizeof(struct ieee80211_hdr_3addr);
- u8 token;
-
- token = frame_body[2];
-
- rtw_action_public_decache(precv_frame, token);
-}
-
static void on_action_public(struct adapter *padapter, struct recv_frame *precv_frame)
{
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)precv_frame->rx_data;
+ u8 *frame_body = (u8 *)&mgmt->u;
/* All members of the action enum start with action_code. */
- if (mgmt->u.action.u.s1g.action_code == WLAN_PUB_ACTION_VENDOR_SPECIFIC)
- on_action_public_vendor(precv_frame);
- else
- on_action_public_default(precv_frame);
+ if (mgmt->u.action.u.s1g.action_code == WLAN_PUB_ACTION_VENDOR_SPECIFIC) {
+ if (!memcmp(frame_body + 2, P2P_OUI, 4))
+ on_action_public_p2p(precv_frame);
+ } else {
+ rtw_action_public_decache(precv_frame, frame_body[2]);
+ }
}
static void OnAction_p2p(struct adapter *padapter, struct recv_frame *precv_frame)
diff --git a/drivers/staging/r8188eu/core/rtw_pwrctrl.c b/drivers/staging/r8188eu/core/rtw_pwrctrl.c
index 5290ac36f08c..051cdcb11ff5 100644
--- a/drivers/staging/r8188eu/core/rtw_pwrctrl.c
+++ b/drivers/staging/r8188eu/core/rtw_pwrctrl.c
@@ -8,7 +8,7 @@
#include "../include/osdep_intf.h"
#include "../include/linux/usb.h"
-void ips_enter(struct adapter *padapter)
+static void ips_enter(struct adapter *padapter)
{
struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
struct xmit_priv *pxmit_priv = &padapter->xmitpriv;
@@ -25,21 +25,20 @@ void ips_enter(struct adapter *padapter)
pwrpriv->ips_mode = pwrpriv->ips_mode_req;
pwrpriv->ips_enter_cnts++;
- if (rf_off == pwrpriv->change_rfpwrstate) {
- pwrpriv->bpower_saving = true;
+ pwrpriv->bpower_saving = true;
- if (pwrpriv->ips_mode == IPS_LEVEL_2)
- pwrpriv->bkeepfwalive = true;
+ if (pwrpriv->ips_mode == IPS_LEVEL_2)
+ pwrpriv->bkeepfwalive = true;
+
+ rtw_ips_pwr_down(padapter);
+ pwrpriv->rf_pwrstate = rf_off;
- rtw_ips_pwr_down(padapter);
- pwrpriv->rf_pwrstate = rf_off;
- }
pwrpriv->bips_processing = false;
mutex_unlock(&pwrpriv->lock);
}
-int ips_leave(struct adapter *padapter)
+static int ips_leave(struct adapter *padapter)
{
struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
struct security_priv *psecuritypriv = &padapter->securitypriv;
@@ -51,7 +50,6 @@ int ips_leave(struct adapter *padapter)
if ((pwrpriv->rf_pwrstate == rf_off) && (!pwrpriv->bips_processing)) {
pwrpriv->bips_processing = true;
- pwrpriv->change_rfpwrstate = rf_on;
pwrpriv->ips_leave_cnts++;
result = rtw_ips_pwr_up(padapter);
@@ -133,10 +131,9 @@ void rtw_ps_processor(struct adapter *padapter)
if (!rtw_pwr_unassociated_idle(padapter))
goto exit;
- if (pwrpriv->rf_pwrstate == rf_on) {
- pwrpriv->change_rfpwrstate = rf_off;
+ if (pwrpriv->rf_pwrstate == rf_on)
ips_enter(padapter);
- }
+
exit:
rtw_set_pwr_state_check_timer(&padapter->pwrctrlpriv);
pwrpriv->ps_processing = false;
diff --git a/drivers/staging/r8188eu/core/rtw_recv.c b/drivers/staging/r8188eu/core/rtw_recv.c
index 631c500dda42..fc7568cf948b 100644
--- a/drivers/staging/r8188eu/core/rtw_recv.c
+++ b/drivers/staging/r8188eu/core/rtw_recv.c
@@ -38,7 +38,7 @@ void _rtw_init_sta_recv_priv(struct sta_recv_priv *psta_recvpriv)
static int rtl8188eu_init_recv_priv(struct adapter *padapter)
{
struct recv_priv *precvpriv = &padapter->recvpriv;
- int i, res = _SUCCESS;
+ int i, err = 0;
struct recv_buf *precvbuf;
tasklet_init(&precvpriv->recv_tasklet,
@@ -50,10 +50,8 @@ static int rtl8188eu_init_recv_priv(struct adapter *padapter)
precvpriv->pallocated_recv_buf = kzalloc(NR_RECVBUFF * sizeof(struct recv_buf) + 4,
GFP_KERNEL);
- if (!precvpriv->pallocated_recv_buf) {
- res = _FAIL;
- goto exit;
- }
+ if (!precvpriv->pallocated_recv_buf)
+ return -ENOMEM;
precvpriv->precv_buf = (u8 *)ALIGN((size_t)(precvpriv->pallocated_recv_buf), 4);
@@ -64,7 +62,7 @@ static int rtl8188eu_init_recv_priv(struct adapter *padapter)
precvbuf->reuse = false;
precvbuf->purb = usb_alloc_urb(0, GFP_KERNEL);
if (!precvbuf->purb) {
- res = _FAIL;
+ err = -ENOMEM;
break;
}
precvbuf->adapter = padapter;
@@ -94,17 +92,15 @@ static int rtl8188eu_init_recv_priv(struct adapter *padapter)
pskb = NULL;
}
}
-exit:
- return res;
+
+ return err;
}
int _rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter)
{
int i;
-
struct recv_frame *precvframe;
-
- int res = _SUCCESS;
+ int err;
spin_lock_init(&precvpriv->lock);
@@ -117,11 +113,8 @@ int _rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter)
precvpriv->free_recvframe_cnt = NR_RECVFRAME;
precvpriv->pallocated_frame_buf = vzalloc(NR_RECVFRAME * sizeof(struct recv_frame) + RXFRAME_ALIGN_SZ);
-
- if (!precvpriv->pallocated_frame_buf) {
- res = _FAIL;
- goto exit;
- }
+ if (!precvpriv->pallocated_frame_buf)
+ return -ENOMEM;
precvpriv->precv_frame_buf = (u8 *)ALIGN((size_t)(precvpriv->pallocated_frame_buf), RXFRAME_ALIGN_SZ);
@@ -141,15 +134,14 @@ int _rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter)
}
precvpriv->rx_pending_cnt = 1;
- res = rtl8188eu_init_recv_priv(padapter);
+ err = rtl8188eu_init_recv_priv(padapter);
timer_setup(&precvpriv->signal_stat_timer, rtw_signal_stat_timer_hdl, 0);
precvpriv->signal_stat_sampling_interval = 1000; /* ms */
rtw_set_signal_stat_timer(precvpriv);
-exit:
- return res;
+ return err;
}
static void rtl8188eu_free_recv_priv(struct adapter *padapter)
diff --git a/drivers/staging/r8188eu/core/rtw_sta_mgt.c b/drivers/staging/r8188eu/core/rtw_sta_mgt.c
index b4aee8623099..e1ae1859686e 100644
--- a/drivers/staging/r8188eu/core/rtw_sta_mgt.c
+++ b/drivers/staging/r8188eu/core/rtw_sta_mgt.c
@@ -260,22 +260,22 @@ void rtw_free_stainfo(struct adapter *padapter, struct sta_info *psta)
spin_lock_bh(&pxmitpriv->lock);
- rtw_free_xmitframe_queue(pxmitpriv, &psta->sleep_q);
+ rtw_free_xmitframe_list(pxmitpriv, get_list_head(&psta->sleep_q));
psta->sleepq_len = 0;
- rtw_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->vo_q.sta_pending);
+ rtw_free_xmitframe_list(pxmitpriv, &pstaxmitpriv->vo_q.sta_pending);
list_del_init(&pstaxmitpriv->vo_q.tx_pending);
- rtw_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->vi_q.sta_pending);
+ rtw_free_xmitframe_list(pxmitpriv, &pstaxmitpriv->vi_q.sta_pending);
list_del_init(&pstaxmitpriv->vi_q.tx_pending);
- rtw_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->bk_q.sta_pending);
+ rtw_free_xmitframe_list(pxmitpriv, &pstaxmitpriv->bk_q.sta_pending);
list_del_init(&pstaxmitpriv->bk_q.tx_pending);
- rtw_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->be_q.sta_pending);
+ rtw_free_xmitframe_list(pxmitpriv, &pstaxmitpriv->be_q.sta_pending);
list_del_init(&pstaxmitpriv->be_q.tx_pending);
@@ -391,8 +391,7 @@ void rtw_free_all_stainfo(struct adapter *padapter)
/* any station allocated can be searched by hash list */
struct sta_info *rtw_get_stainfo(struct sta_priv *pstapriv, u8 *hwaddr)
{
- struct list_head *plist, *phead;
- struct sta_info *psta = NULL;
+ struct sta_info *ploop, *psta = NULL;
u32 index;
u8 *addr;
u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
@@ -409,18 +408,11 @@ struct sta_info *rtw_get_stainfo(struct sta_priv *pstapriv, u8 *hwaddr)
spin_lock_bh(&pstapriv->sta_hash_lock);
- phead = &pstapriv->sta_hash[index];
- plist = phead->next;
-
- while (phead != plist) {
- psta = container_of(plist, struct sta_info, hash_list);
-
- if ((!memcmp(psta->hwaddr, addr, ETH_ALEN))) {
- /* if found the matched address */
+ list_for_each_entry(ploop, &pstapriv->sta_hash[index], hash_list) {
+ if (!memcmp(ploop->hwaddr, addr, ETH_ALEN)) {
+ psta = ploop;
break;
}
- psta = NULL;
- plist = plist->next;
}
spin_unlock_bh(&pstapriv->sta_hash_lock);
diff --git a/drivers/staging/r8188eu/core/rtw_xmit.c b/drivers/staging/r8188eu/core/rtw_xmit.c
index 34494f08c0cd..df88b3e29e77 100644
--- a/drivers/staging/r8188eu/core/rtw_xmit.c
+++ b/drivers/staging/r8188eu/core/rtw_xmit.c
@@ -17,7 +17,7 @@ static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 };
static void _init_txservq(struct tx_servq *ptxservq)
{
INIT_LIST_HEAD(&ptxservq->tx_pending);
- rtw_init_queue(&ptxservq->sta_pending);
+ INIT_LIST_HEAD(&ptxservq->sta_pending);
ptxservq->qcnt = 0;
}
@@ -29,8 +29,6 @@ void _rtw_init_sta_xmit_priv(struct sta_xmit_priv *psta_xmitpriv)
_init_txservq(&psta_xmitpriv->bk_q);
_init_txservq(&psta_xmitpriv->vi_q);
_init_txservq(&psta_xmitpriv->vo_q);
- INIT_LIST_HEAD(&psta_xmitpriv->legacy_dz);
- INIT_LIST_HEAD(&psta_xmitpriv->apsd);
}
static int rtw_xmit_resource_alloc(struct adapter *padapter, struct xmit_buf *pxmitbuf,
@@ -41,7 +39,6 @@ static int rtw_xmit_resource_alloc(struct adapter *padapter, struct xmit_buf *px
return -ENOMEM;
pxmitbuf->pbuf = (u8 *)ALIGN((size_t)(pxmitbuf->pallocated_buf), XMITBUF_ALIGN_SZ);
- pxmitbuf->dma_transfer_addr = 0;
pxmitbuf->pxmit_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!pxmitbuf->pxmit_urb) {
@@ -70,7 +67,6 @@ int _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter)
/* We don't need to memset padapter->XXX to zero, because adapter is allocated by vzalloc(). */
spin_lock_init(&pxmitpriv->lock);
- sema_init(&pxmitpriv->terminate_xmitthread_sema, 0);
/*
* Please insert all the queue initializaiton using rtw_init_queue below
@@ -78,11 +74,10 @@ int _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter)
pxmitpriv->adapter = padapter;
- rtw_init_queue(&pxmitpriv->be_pending);
- rtw_init_queue(&pxmitpriv->bk_pending);
- rtw_init_queue(&pxmitpriv->vi_pending);
- rtw_init_queue(&pxmitpriv->vo_pending);
- rtw_init_queue(&pxmitpriv->bm_pending);
+ INIT_LIST_HEAD(&pxmitpriv->be_pending);
+ INIT_LIST_HEAD(&pxmitpriv->bk_pending);
+ INIT_LIST_HEAD(&pxmitpriv->vi_pending);
+ INIT_LIST_HEAD(&pxmitpriv->vo_pending);
rtw_init_queue(&pxmitpriv->free_xmit_queue);
@@ -153,7 +148,7 @@ int _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter)
goto free_xmitbuf;
}
- pxmitbuf->flags = XMIT_VO_QUEUE;
+ pxmitbuf->high_queue = false;
list_add_tail(&pxmitbuf->list, &pxmitpriv->free_xmitbuf_queue.queue);
pxmitbuf++;
@@ -192,26 +187,14 @@ int _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter)
if (rtw_alloc_hwxmits(padapter))
goto free_xmit_extbuf;
- rtw_init_hwxmits(pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry);
-
for (i = 0; i < 4; i++)
pxmitpriv->wmm_para_seq[i] = i;
- pxmitpriv->txirp_cnt = 1;
-
- sema_init(&pxmitpriv->tx_retevt, 0);
-
- /* per AC pending irp */
- pxmitpriv->beq_cnt = 0;
- pxmitpriv->bkq_cnt = 0;
- pxmitpriv->viq_cnt = 0;
- pxmitpriv->voq_cnt = 0;
-
pxmitpriv->ack_tx = false;
mutex_init(&pxmitpriv->ack_tx_mutex);
rtw_sctx_init(&pxmitpriv->ack_tx_ops, 0);
- rtl8188eu_init_xmit_priv(padapter);
+ tasklet_init(&pxmitpriv->xmit_tasklet, rtl8188eu_xmit_tasklet, (unsigned long)padapter);
return 0;
@@ -296,7 +279,7 @@ void _rtw_free_xmit_priv(struct xmit_priv *pxmitpriv)
vfree(pxmitpriv->pallocated_xmit_extbuf);
- rtw_free_hwxmits(padapter);
+ kfree(pxmitpriv->hwxmits);
mutex_destroy(&pxmitpriv->ack_tx_mutex);
}
@@ -761,28 +744,27 @@ static s32 xmitframe_addmic(struct adapter *padapter, struct xmit_frame *pxmitfr
return _SUCCESS;
}
-static s32 xmitframe_swencrypt(struct adapter *padapter, struct xmit_frame *pxmitframe)
+static void xmitframe_swencrypt(struct adapter *padapter, struct xmit_frame *pxmitframe)
{
struct pkt_attrib *pattrib = &pxmitframe->attrib;
- if (pattrib->bswenc) {
- switch (pattrib->encrypt) {
- case _WEP40_:
- case _WEP104_:
- rtw_wep_encrypt(padapter, pxmitframe);
- break;
- case _TKIP_:
- rtw_tkip_encrypt(padapter, pxmitframe);
- break;
- case _AES_:
- rtw_aes_encrypt(padapter, pxmitframe);
- break;
- default:
- break;
- }
- }
+ if (!pattrib->bswenc)
+ return;
- return _SUCCESS;
+ switch (pattrib->encrypt) {
+ case _WEP40_:
+ case _WEP104_:
+ rtw_wep_encrypt(padapter, pxmitframe);
+ break;
+ case _TKIP_:
+ rtw_tkip_encrypt(padapter, pxmitframe);
+ break;
+ case _AES_:
+ rtw_aes_encrypt(padapter, pxmitframe);
+ break;
+ default:
+ break;
+ }
}
s32 rtw_make_wlanhdr(struct adapter *padapter, u8 *hdr, struct pkt_attrib *pattrib)
@@ -792,9 +774,7 @@ s32 rtw_make_wlanhdr(struct adapter *padapter, u8 *hdr, struct pkt_attrib *pattr
struct ieee80211_hdr *pwlanhdr = (struct ieee80211_hdr *)hdr;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct qos_priv *pqospriv = &pmlmepriv->qospriv;
- u8 qos_option = false;
-
- int res = _SUCCESS;
+ bool qos_option;
__le16 *fctrl = &pwlanhdr->frame_control;
struct sta_info *psta;
@@ -810,106 +790,99 @@ s32 rtw_make_wlanhdr(struct adapter *padapter, u8 *hdr, struct pkt_attrib *pattr
SetFrameSubType(fctrl, pattrib->subtype);
- if (pattrib->subtype & IEEE80211_FTYPE_DATA) {
- if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
- /* to_ds = 1, fr_ds = 0; */
- /* Data transfer to AP */
- SetToDs(fctrl);
- memcpy(pwlanhdr->addr1, get_bssid(pmlmepriv), ETH_ALEN);
- memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN);
- memcpy(pwlanhdr->addr3, pattrib->dst, ETH_ALEN);
-
- if (pqospriv->qos_option)
- qos_option = true;
- } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
- /* to_ds = 0, fr_ds = 1; */
- SetFrDs(fctrl);
- memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN);
- memcpy(pwlanhdr->addr2, get_bssid(pmlmepriv), ETH_ALEN);
- memcpy(pwlanhdr->addr3, pattrib->src, ETH_ALEN);
-
- if (psta->qos_option)
- qos_option = true;
- } else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) ||
- check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) {
- memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN);
- memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN);
- memcpy(pwlanhdr->addr3, get_bssid(pmlmepriv), ETH_ALEN);
-
- if (psta->qos_option)
- qos_option = true;
- } else {
- res = _FAIL;
- goto exit;
- }
+ if (!(pattrib->subtype & IEEE80211_FTYPE_DATA))
+ return _SUCCESS;
+
+ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
+ /* to_ds = 1, fr_ds = 0; */
+ /* Data transfer to AP */
+ SetToDs(fctrl);
+ memcpy(pwlanhdr->addr1, get_bssid(pmlmepriv), ETH_ALEN);
+ memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN);
+ memcpy(pwlanhdr->addr3, pattrib->dst, ETH_ALEN);
+ qos_option = pqospriv->qos_option;
+ } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+ /* to_ds = 0, fr_ds = 1; */
+ SetFrDs(fctrl);
+ memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN);
+ memcpy(pwlanhdr->addr2, get_bssid(pmlmepriv), ETH_ALEN);
+ memcpy(pwlanhdr->addr3, pattrib->src, ETH_ALEN);
+ qos_option = psta->qos_option;
+ } else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) ||
+ check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) {
+ memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN);
+ memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN);
+ memcpy(pwlanhdr->addr3, get_bssid(pmlmepriv), ETH_ALEN);
+ qos_option = psta->qos_option;
+ } else {
+ return _FAIL;
+ }
- if (pattrib->mdata)
- SetMData(fctrl);
+ if (pattrib->mdata)
+ SetMData(fctrl);
- if (pattrib->encrypt)
- SetPrivacy(fctrl);
+ if (pattrib->encrypt)
+ SetPrivacy(fctrl);
- if (qos_option) {
- qc = (unsigned short *)(hdr + pattrib->hdrlen - 2);
+ if (qos_option) {
+ qc = (unsigned short *)(hdr + pattrib->hdrlen - 2);
- if (pattrib->priority)
- SetPriority(qc, pattrib->priority);
+ if (pattrib->priority)
+ SetPriority(qc, pattrib->priority);
- SetEOSP(qc, pattrib->eosp);
+ SetEOSP(qc, pattrib->eosp);
- SetAckpolicy(qc, pattrib->ack_policy);
- }
+ SetAckpolicy(qc, pattrib->ack_policy);
+ }
- /* TODO: fill HT Control Field */
+ /* TODO: fill HT Control Field */
- /* Update Seq Num will be handled by f/w */
- if (psta) {
- psta->sta_xmitpriv.txseq_tid[pattrib->priority]++;
- psta->sta_xmitpriv.txseq_tid[pattrib->priority] &= 0xFFF;
+ /* Update Seq Num will be handled by f/w */
+ if (psta) {
+ psta->sta_xmitpriv.txseq_tid[pattrib->priority]++;
+ psta->sta_xmitpriv.txseq_tid[pattrib->priority] &= 0xFFF;
- pattrib->seqnum = psta->sta_xmitpriv.txseq_tid[pattrib->priority];
+ pattrib->seqnum = psta->sta_xmitpriv.txseq_tid[pattrib->priority];
- SetSeqNum(hdr, pattrib->seqnum);
+ SetSeqNum(hdr, pattrib->seqnum);
- /* check if enable ampdu */
- if (pattrib->ht_en && psta->htpriv.ampdu_enable) {
- if (psta->htpriv.agg_enable_bitmap & BIT(pattrib->priority))
- pattrib->ampdu_en = true;
- }
+ /* check if enable ampdu */
+ if (pattrib->ht_en && psta->htpriv.ampdu_enable) {
+ if (psta->htpriv.agg_enable_bitmap & BIT(pattrib->priority))
+ pattrib->ampdu_en = true;
+ }
- /* re-check if enable ampdu by BA_starting_seqctrl */
- if (pattrib->ampdu_en) {
- u16 tx_seq;
+ /* re-check if enable ampdu by BA_starting_seqctrl */
+ if (pattrib->ampdu_en) {
+ u16 tx_seq;
- tx_seq = psta->BA_starting_seqctrl[pattrib->priority & 0x0f];
+ tx_seq = psta->BA_starting_seqctrl[pattrib->priority & 0x0f];
- /* check BA_starting_seqctrl */
- if (SN_LESS(pattrib->seqnum, tx_seq)) {
- pattrib->ampdu_en = false;/* AGG BK */
- } else if (SN_EQUAL(pattrib->seqnum, tx_seq)) {
- psta->BA_starting_seqctrl[pattrib->priority & 0x0f] = (tx_seq + 1) & 0xfff;
+ /* check BA_starting_seqctrl */
+ if (SN_LESS(pattrib->seqnum, tx_seq)) {
+ pattrib->ampdu_en = false;/* AGG BK */
+ } else if (SN_EQUAL(pattrib->seqnum, tx_seq)) {
+ psta->BA_starting_seqctrl[pattrib->priority & 0x0f] = (tx_seq + 1) & 0xfff;
- pattrib->ampdu_en = true;/* AGG EN */
- } else {
- psta->BA_starting_seqctrl[pattrib->priority & 0x0f] = (pattrib->seqnum + 1) & 0xfff;
- pattrib->ampdu_en = true;/* AGG EN */
- }
+ pattrib->ampdu_en = true;/* AGG EN */
+ } else {
+ psta->BA_starting_seqctrl[pattrib->priority & 0x0f] = (pattrib->seqnum + 1) & 0xfff;
+ pattrib->ampdu_en = true;/* AGG EN */
}
}
}
-exit:
- return res;
+ return _SUCCESS;
}
s32 rtw_txframes_pending(struct adapter *padapter)
{
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
- return (!list_empty(&pxmitpriv->be_pending.queue) ||
- !list_empty(&pxmitpriv->bk_pending.queue) ||
- !list_empty(&pxmitpriv->vi_pending.queue) ||
- !list_empty(&pxmitpriv->vo_pending.queue));
+ return (!list_empty(&pxmitpriv->be_pending) ||
+ !list_empty(&pxmitpriv->bk_pending) ||
+ !list_empty(&pxmitpriv->vi_pending) ||
+ !list_empty(&pxmitpriv->vo_pending));
}
s32 rtw_txframes_sta_ac_pending(struct adapter *padapter, struct pkt_attrib *pattrib)
@@ -1010,25 +983,23 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct
/* adding icv, if necessary... */
if (pattrib->iv_len) {
- if (psta) {
- switch (pattrib->encrypt) {
- case _WEP40_:
- case _WEP104_:
- WEP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx);
- break;
- case _TKIP_:
- if (bmcst)
- TKIP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx);
- else
- TKIP_IV(pattrib->iv, psta->dot11txpn, 0);
- break;
- case _AES_:
- if (bmcst)
- AES_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx);
- else
- AES_IV(pattrib->iv, psta->dot11txpn, 0);
- break;
- }
+ switch (pattrib->encrypt) {
+ case _WEP40_:
+ case _WEP104_:
+ WEP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx);
+ break;
+ case _TKIP_:
+ if (bmcst)
+ TKIP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx);
+ else
+ TKIP_IV(pattrib->iv, psta->dot11txpn, 0);
+ break;
+ case _AES_:
+ if (bmcst)
+ AES_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx);
+ else
+ AES_IV(pattrib->iv, psta->dot11txpn, 0);
+ break;
}
memcpy(pframe, pattrib->iv, pattrib->iv_len);
@@ -1126,40 +1097,6 @@ s32 rtw_put_snap(u8 *data, u16 h_proto)
return SNAP_SIZE + sizeof(u16);
}
-void rtw_update_protection(struct adapter *padapter, u8 *ie, uint ie_len)
-{
- uint protection;
- u8 *perp;
- int erp_len;
- struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
- struct registry_priv *pregistrypriv = &padapter->registrypriv;
-
- switch (pxmitpriv->vcs_setting) {
- case DISABLE_VCS:
- pxmitpriv->vcs = NONE_VCS;
- break;
- case ENABLE_VCS:
- break;
- case AUTO_VCS:
- default:
- perp = rtw_get_ie(ie, _ERPINFO_IE_, &erp_len, ie_len);
- if (!perp) {
- pxmitpriv->vcs = NONE_VCS;
- } else {
- protection = (*(perp + 2)) & BIT(1);
- if (protection) {
- if (pregistrypriv->vcs_type == RTS_CTS)
- pxmitpriv->vcs = RTS_CTS;
- else
- pxmitpriv->vcs = CTS_TO_SELF;
- } else {
- pxmitpriv->vcs = NONE_VCS;
- }
- }
- break;
- }
-}
-
void rtw_count_tx_stats(struct adapter *padapter, struct xmit_frame *pxmitframe, int sz)
{
struct sta_info *psta = NULL;
@@ -1319,38 +1256,32 @@ struct xmit_frame *rtw_alloc_xmitframe(struct xmit_priv *pxmitpriv)/* _queue *pf
spin_lock_bh(&pfree_xmit_queue->lock);
- if (list_empty(&pfree_xmit_queue->queue)) {
- pxframe = NULL;
- } else {
- phead = get_list_head(pfree_xmit_queue);
-
- plist = phead->next;
-
- pxframe = container_of(plist, struct xmit_frame, list);
+ if (list_empty(&pfree_xmit_queue->queue))
+ goto out;
- list_del_init(&pxframe->list);
- }
+ phead = get_list_head(pfree_xmit_queue);
+ plist = phead->next;
+ pxframe = container_of(plist, struct xmit_frame, list);
+ list_del_init(&pxframe->list);
- if (pxframe) { /* default value setting */
- pxmitpriv->free_xmitframe_cnt--;
+ pxmitpriv->free_xmitframe_cnt--;
- pxframe->buf_addr = NULL;
- pxframe->pxmitbuf = NULL;
+ pxframe->buf_addr = NULL;
+ pxframe->pxmitbuf = NULL;
- memset(&pxframe->attrib, 0, sizeof(struct pkt_attrib));
- /* pxframe->attrib.psta = NULL; */
+ memset(&pxframe->attrib, 0, sizeof(struct pkt_attrib));
+ /* pxframe->attrib.psta = NULL; */
- pxframe->frame_tag = DATA_FRAMETAG;
+ pxframe->frame_tag = DATA_FRAMETAG;
- pxframe->pkt = NULL;
- pxframe->pkt_offset = 1;/* default use pkt_offset to fill tx desc */
+ pxframe->pkt = NULL;
+ pxframe->pkt_offset = 1;/* default use pkt_offset to fill tx desc */
- pxframe->agg_num = 1;
- pxframe->ack_report = 0;
- }
+ pxframe->agg_num = 1;
+ pxframe->ack_report = 0;
+out:
spin_unlock_bh(&pfree_xmit_queue->lock);
-
return pxframe;
}
@@ -1386,101 +1317,49 @@ exit:
return _SUCCESS;
}
-void rtw_free_xmitframe_queue(struct xmit_priv *pxmitpriv, struct __queue *pframequeue)
+void rtw_free_xmitframe_list(struct xmit_priv *pxmitpriv, struct list_head *xframe_list)
{
- struct list_head *plist, *phead;
- struct xmit_frame *pxmitframe;
-
- spin_lock_bh(&pframequeue->lock);
-
- phead = get_list_head(pframequeue);
- plist = phead->next;
-
- while (phead != plist) {
- pxmitframe = container_of(plist, struct xmit_frame, list);
-
- plist = plist->next;
+ struct xmit_frame *pxmitframe, *tmp_xmitframe;
+ list_for_each_entry_safe(pxmitframe, tmp_xmitframe, xframe_list, list)
rtw_free_xmitframe(pxmitpriv, pxmitframe);
- }
- spin_unlock_bh(&pframequeue->lock);
-}
-
-s32 rtw_xmitframe_enqueue(struct adapter *padapter, struct xmit_frame *pxmitframe)
-{
- if (rtw_xmit_classifier(padapter, pxmitframe) == _FAIL) {
-/* pxmitframe->pkt = NULL; */
- return _FAIL;
- }
-
- return _SUCCESS;
-}
-
-static struct xmit_frame *dequeue_one_xmitframe(struct xmit_priv *pxmitpriv, struct hw_xmit *phwxmit, struct tx_servq *ptxservq, struct __queue *pframe_queue)
-{
- struct list_head *xmitframe_plist, *xmitframe_phead;
- struct xmit_frame *pxmitframe = NULL;
-
- xmitframe_phead = get_list_head(pframe_queue);
- xmitframe_plist = xmitframe_phead->next;
-
- if (xmitframe_phead != xmitframe_plist) {
- pxmitframe = container_of(xmitframe_plist, struct xmit_frame, list);
-
- xmitframe_plist = xmitframe_plist->next;
-
- list_del_init(&pxmitframe->list);
-
- ptxservq->qcnt--;
- }
- return pxmitframe;
}
-struct xmit_frame *rtw_dequeue_xframe(struct xmit_priv *pxmitpriv, struct hw_xmit *phwxmit_i, int entry)
+struct xmit_frame *rtw_dequeue_xframe(struct xmit_priv *pxmitpriv, struct hw_xmit *phwxmit_i)
{
- struct list_head *sta_plist, *sta_phead;
struct hw_xmit *phwxmit;
- struct tx_servq *ptxservq = NULL;
- struct __queue *pframe_queue = NULL;
+ struct tx_servq *ptxservq, *tmp_txservq;
+ struct list_head *xframe_list;
struct xmit_frame *pxmitframe = NULL;
struct adapter *padapter = pxmitpriv->adapter;
struct registry_priv *pregpriv = &padapter->registrypriv;
- int i, inx[4];
-
- inx[0] = 0; inx[1] = 1; inx[2] = 2; inx[3] = 3;
+ int i, inx[] = { 0, 1, 2, 3 };
if (pregpriv->wifi_spec == 1) {
- int j;
-
- for (j = 0; j < 4; j++)
- inx[j] = pxmitpriv->wmm_para_seq[j];
+ for (i = 0; i < ARRAY_SIZE(inx); i++)
+ inx[i] = pxmitpriv->wmm_para_seq[i];
}
spin_lock_bh(&pxmitpriv->lock);
- for (i = 0; i < entry; i++) {
+ for (i = 0; i < HWXMIT_ENTRY; i++) {
phwxmit = phwxmit_i + inx[i];
+ list_for_each_entry_safe(ptxservq, tmp_txservq, phwxmit->sta_list, tx_pending) {
+ xframe_list = &ptxservq->sta_pending;
+ if (list_empty(xframe_list))
+ continue;
- sta_phead = get_list_head(phwxmit->sta_queue);
- sta_plist = sta_phead->next;
-
- while (sta_phead != sta_plist) {
- ptxservq = container_of(sta_plist, struct tx_servq, tx_pending);
-
- pframe_queue = &ptxservq->sta_pending;
+ pxmitframe = container_of(xframe_list->next, struct xmit_frame, list);
+ list_del_init(&pxmitframe->list);
- pxmitframe = dequeue_one_xmitframe(pxmitpriv, phwxmit, ptxservq, pframe_queue);
+ phwxmit->accnt--;
+ ptxservq->qcnt--;
- if (pxmitframe) {
- phwxmit->accnt--;
+ /* Remove sta node when there are no pending packets. */
+ if (list_empty(xframe_list))
+ list_del_init(&ptxservq->tx_pending);
- /* Remove sta node when there are no pending packets. */
- if (list_empty(&pframe_queue->queue)) /* must be done after get_next and before break */
- list_del_init(&ptxservq->tx_pending);
- goto exit;
- }
-
- sta_plist = sta_plist->next;
+ goto exit;
}
}
exit:
@@ -1547,9 +1426,9 @@ s32 rtw_xmit_classifier(struct adapter *padapter, struct xmit_frame *pxmitframe)
ptxservq = rtw_get_sta_pending(padapter, psta, pattrib->priority, (u8 *)(&ac_index));
if (list_empty(&ptxservq->tx_pending))
- list_add_tail(&ptxservq->tx_pending, get_list_head(phwxmits[ac_index].sta_queue));
+ list_add_tail(&ptxservq->tx_pending, phwxmits[ac_index].sta_list);
- list_add_tail(&pxmitframe->list, get_list_head(&ptxservq->sta_pending));
+ list_add_tail(&pxmitframe->list, &ptxservq->sta_pending);
ptxservq->qcnt++;
phwxmits[ac_index].accnt++;
exit:
@@ -1562,39 +1441,20 @@ int rtw_alloc_hwxmits(struct adapter *padapter)
struct hw_xmit *hwxmits;
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
- pxmitpriv->hwxmit_entry = HWXMIT_ENTRY;
-
- pxmitpriv->hwxmits = kzalloc(sizeof(struct hw_xmit) * pxmitpriv->hwxmit_entry, GFP_KERNEL);
+ pxmitpriv->hwxmits = kcalloc(HWXMIT_ENTRY, sizeof(struct hw_xmit), GFP_KERNEL);
if (!pxmitpriv->hwxmits)
return -ENOMEM;
hwxmits = pxmitpriv->hwxmits;
- hwxmits[0].sta_queue = &pxmitpriv->vo_pending;
- hwxmits[1].sta_queue = &pxmitpriv->vi_pending;
- hwxmits[2].sta_queue = &pxmitpriv->be_pending;
- hwxmits[3].sta_queue = &pxmitpriv->bk_pending;
+ hwxmits[0].sta_list = &pxmitpriv->vo_pending;
+ hwxmits[1].sta_list = &pxmitpriv->vi_pending;
+ hwxmits[2].sta_list = &pxmitpriv->be_pending;
+ hwxmits[3].sta_list = &pxmitpriv->bk_pending;
return 0;
}
-void rtw_free_hwxmits(struct adapter *padapter)
-{
- struct hw_xmit *hwxmits;
- struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
-
- hwxmits = pxmitpriv->hwxmits;
- kfree(hwxmits);
-}
-
-void rtw_init_hwxmits(struct hw_xmit *phwxmit, int entry)
-{
- int i;
-
- for (i = 0; i < entry; i++, phwxmit++)
- phwxmit->accnt = 0;
-}
-
static int rtw_br_client_tx(struct adapter *padapter, struct sk_buff **pskb)
{
struct sk_buff *skb = *pskb;
@@ -1743,15 +1603,6 @@ u32 rtw_get_ff_hwaddr(struct xmit_frame *pxmitframe)
return addr;
}
-static void do_queue_select(struct adapter *padapter, struct pkt_attrib *pattrib)
-{
- u8 qsel;
-
- qsel = pattrib->priority;
-
- pattrib->qsel = qsel;
-}
-
/*
* The main transmit(tx) entry
*
@@ -1765,18 +1616,14 @@ s32 rtw_xmit(struct adapter *padapter, struct sk_buff **ppkt)
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
struct xmit_frame *pxmitframe = NULL;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
- void *br_port = NULL;
s32 res;
pxmitframe = rtw_alloc_xmitframe(pxmitpriv);
if (!pxmitframe)
return -1;
- rcu_read_lock();
- br_port = rcu_dereference(padapter->pnetdev->rx_handler_data);
- rcu_read_unlock();
-
- if (br_port && check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_ADHOC_STATE)) {
+ if (rcu_access_pointer(padapter->pnetdev->rx_handler_data) &&
+ check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_ADHOC_STATE)) {
res = rtw_br_client_tx(padapter, ppkt);
if (res == -1) {
rtw_free_xmitframe(pxmitpriv, pxmitframe);
@@ -1794,7 +1641,7 @@ s32 rtw_xmit(struct adapter *padapter, struct sk_buff **ppkt)
rtw_led_control(padapter, LED_CTL_TX);
- do_queue_select(padapter, &pxmitframe->attrib);
+ pxmitframe->attrib.qsel = pxmitframe->attrib.priority;
spin_lock_bh(&pxmitpriv->lock);
if (xmitframe_enqueue_for_sleeping_sta(padapter, pxmitframe)) {
@@ -1911,16 +1758,15 @@ int xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_fra
return ret;
}
-static void dequeue_xmitframes_to_sleeping_queue(struct adapter *padapter, struct sta_info *psta, struct __queue *pframequeue)
+static void dequeue_xmitframes_to_sleeping_queue(struct adapter *padapter, struct sta_info *psta, struct list_head *phead)
{
- struct list_head *plist, *phead;
+ struct list_head *plist;
u8 ac_index;
struct tx_servq *ptxservq;
struct pkt_attrib *pattrib;
struct xmit_frame *pxmitframe;
struct hw_xmit *phwxmits = padapter->xmitpriv.hwxmits;
- phead = get_list_head(pframequeue);
plist = phead->next;
while (phead != plist) {
diff --git a/drivers/staging/r8188eu/hal/rtl8188e_cmd.c b/drivers/staging/r8188eu/hal/rtl8188e_cmd.c
index 8310d7f53982..788904d4655c 100644
--- a/drivers/staging/r8188eu/hal/rtl8188e_cmd.c
+++ b/drivers/staging/r8188eu/hal/rtl8188e_cmd.c
@@ -193,9 +193,9 @@ void rtl8188e_set_FwPwrMode_cmd(struct adapter *adapt, u8 Mode)
}
-void rtl8188e_set_FwMediaStatus_cmd(struct adapter *adapt, __le16 mstatus_rpt)
+void rtl8188e_set_FwMediaStatus_cmd(struct adapter *adapt, u16 mstatus_rpt)
{
- u16 mst_rpt = le16_to_cpu(mstatus_rpt);
+ __le16 mst_rpt = cpu_to_le16(mstatus_rpt);
FillH2CCmd_88E(adapt, H2C_COM_MEDIA_STATUS_RPT, sizeof(mst_rpt), (u8 *)&mst_rpt);
}
diff --git a/drivers/staging/r8188eu/hal/rtl8188e_phycfg.c b/drivers/staging/r8188eu/hal/rtl8188e_phycfg.c
index b7f3c7a670fb..f4edf4a8f5c2 100644
--- a/drivers/staging/r8188eu/hal/rtl8188e_phycfg.c
+++ b/drivers/staging/r8188eu/hal/rtl8188e_phycfg.c
@@ -315,21 +315,20 @@ rtl8188e_PHY_SetRFReg(
* 08/12/2008 MHC Create Version 0.
*
*---------------------------------------------------------------------------*/
-s32 PHY_MACConfig8188E(struct adapter *Adapter)
+int PHY_MACConfig8188E(struct adapter *Adapter)
{
struct hal_data_8188e *pHalData = &Adapter->haldata;
- int rtStatus = _SUCCESS;
+ int err;
/* */
/* Config MAC */
/* */
- if (ODM_ReadAndConfig_MAC_REG_8188E(&pHalData->odmpriv))
- rtStatus = _FAIL;
+ err = ODM_ReadAndConfig_MAC_REG_8188E(&pHalData->odmpriv);
/* 2010.07.13 AMPDU aggregation number B */
rtw_write16(Adapter, REG_MAX_AGGR_NUM, MAX_AGGR_NUM);
- return rtStatus;
+ return err;
}
/**
@@ -450,13 +449,15 @@ static int phy_BB8188E_Config_ParaFile(struct adapter *Adapter)
{
struct eeprom_priv *pEEPROM = &Adapter->eeprompriv;
struct hal_data_8188e *pHalData = &Adapter->haldata;
+ int err;
/* */
/* 1. Read PHY_REG.TXT BB INIT!! */
/* We will separate as 88C / 92C according to chip version */
/* */
- if (ODM_ReadAndConfig_PHY_REG_1T_8188E(&pHalData->odmpriv))
- return _FAIL;
+ err = ODM_ReadAndConfig_PHY_REG_1T_8188E(&pHalData->odmpriv);
+ if (err)
+ return err;
/* 2. If EEPROM or EFUSE autoload OK, We must config by PHY_REG_PG.txt */
if (!pEEPROM->bautoload_fail_flag) {
@@ -465,10 +466,11 @@ static int phy_BB8188E_Config_ParaFile(struct adapter *Adapter)
}
/* 3. BB AGC table Initialization */
- if (ODM_ReadAndConfig_AGC_TAB_1T_8188E(&pHalData->odmpriv))
- return _FAIL;
+ err = ODM_ReadAndConfig_AGC_TAB_1T_8188E(&pHalData->odmpriv);
+ if (err)
+ return err;
- return _SUCCESS;
+ return 0;
}
int
@@ -476,18 +478,17 @@ PHY_BBConfig8188E(
struct adapter *Adapter
)
{
- int rtStatus = _SUCCESS;
struct hal_data_8188e *pHalData = &Adapter->haldata;
u16 RegVal;
u8 CrystalCap;
- int res;
+ int err;
phy_InitBBRFRegisterDefinition(Adapter);
/* Enable BB and RF */
- res = rtw_read16(Adapter, REG_SYS_FUNC_EN, &RegVal);
- if (res)
- return _FAIL;
+ err = rtw_read16(Adapter, REG_SYS_FUNC_EN, &RegVal);
+ if (err)
+ return err;
rtw_write16(Adapter, REG_SYS_FUNC_EN, (u16)(RegVal | BIT(13) | BIT(0) | BIT(1)));
@@ -498,13 +499,13 @@ PHY_BBConfig8188E(
rtw_write8(Adapter, REG_SYS_FUNC_EN, FEN_USBA | FEN_USBD | FEN_BB_GLB_RSTn | FEN_BBRSTB);
/* Config BB and AGC */
- rtStatus = phy_BB8188E_Config_ParaFile(Adapter);
+ err = phy_BB8188E_Config_ParaFile(Adapter);
/* write 0x24[16:11] = 0x24[22:17] = CrystalCap */
CrystalCap = pHalData->CrystalCap & 0x3F;
rtl8188e_PHY_SetBBReg(Adapter, REG_AFE_XTAL_CTRL, 0x7ff800, (CrystalCap | (CrystalCap << 6)));
- return rtStatus;
+ return err;
}
static void getTxPowerIndex88E(struct adapter *Adapter, u8 channel, u8 *cckPowerLevel,
diff --git a/drivers/staging/r8188eu/hal/rtl8188e_rf6052.c b/drivers/staging/r8188eu/hal/rtl8188e_rf6052.c
index e5ec6e563fbd..1988fb6e780a 100644
--- a/drivers/staging/r8188eu/hal/rtl8188e_rf6052.c
+++ b/drivers/staging/r8188eu/hal/rtl8188e_rf6052.c
@@ -371,7 +371,7 @@ int phy_RF6052_Config_ParaFile(struct adapter *Adapter)
struct bb_reg_def *pPhyReg;
struct hal_data_8188e *pHalData = &Adapter->haldata;
u32 u4RegValue = 0;
- int rtStatus = _SUCCESS;
+ int err;
/* Initialize RF */
@@ -396,11 +396,10 @@ int phy_RF6052_Config_ParaFile(struct adapter *Adapter)
udelay(1);/* PlatformStallExecution(1); */
/*----Initialize RF fom connfiguration file----*/
- if (ODM_ReadAndConfig_RadioA_1T_8188E(&pHalData->odmpriv))
- rtStatus = _FAIL;
+ err = ODM_ReadAndConfig_RadioA_1T_8188E(&pHalData->odmpriv);
/*----Restore RFENV control type----*/;
rtl8188e_PHY_SetBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV, u4RegValue);
- return rtStatus;
+ return err;
}
diff --git a/drivers/staging/r8188eu/hal/rtl8188eu_xmit.c b/drivers/staging/r8188eu/hal/rtl8188eu_xmit.c
index 6d1f56d1f9d7..3ffab4953a5c 100644
--- a/drivers/staging/r8188eu/hal/rtl8188eu_xmit.c
+++ b/drivers/staging/r8188eu/hal/rtl8188eu_xmit.c
@@ -9,16 +9,6 @@
#include "../include/usb_ops.h"
#include "../include/rtl8188e_hal.h"
-s32 rtl8188eu_init_xmit_priv(struct adapter *adapt)
-{
- struct xmit_priv *pxmitpriv = &adapt->xmitpriv;
-
- tasklet_init(&pxmitpriv->xmit_tasklet,
- rtl8188eu_xmit_tasklet,
- (unsigned long)adapt);
- return _SUCCESS;
-}
-
static void rtl8188eu_cal_txdesc_chksum(struct tx_desc *ptxdesc)
{
u16 *usptr = (u16 *)ptxdesc;
@@ -147,7 +137,7 @@ static void fill_txdesc_phy(struct pkt_attrib *pattrib, __le32 *pdw)
}
}
-static s32 update_txdesc(struct xmit_frame *pxmitframe, u8 *pmem, s32 sz, u8 bagg_pkt)
+static s32 update_txdesc(struct xmit_frame *pxmitframe, u8 *pmem, s32 sz)
{
uint qsel;
u8 data_rate, pwr_status, offset;
@@ -329,7 +319,7 @@ static s32 rtw_dump_xframe(struct adapter *adapt, struct xmit_frame *pxmitframe)
sz = pattrib->last_txcmdsz;
}
- pull = update_txdesc(pxmitframe, mem_addr, sz, false);
+ pull = update_txdesc(pxmitframe, mem_addr, sz);
if (pull) {
mem_addr += PACKET_OFFSET_SZ; /* pull txdesc head */
@@ -375,11 +365,13 @@ static u32 xmitframe_need_length(struct xmit_frame *pxmitframe)
return len;
}
-bool rtl8188eu_xmitframe_complete(struct adapter *adapt, struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf)
+bool rtl8188eu_xmitframe_complete(struct adapter *adapt)
{
+ struct xmit_priv *pxmitpriv = &adapt->xmitpriv;
struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(adapt);
struct xmit_frame *pxmitframe = NULL;
struct xmit_frame *pfirstframe = NULL;
+ struct xmit_buf *pxmitbuf;
/* aggregate variable */
struct hw_xmit *phwxmit;
@@ -403,17 +395,11 @@ bool rtl8188eu_xmitframe_complete(struct adapter *adapt, struct xmit_priv *pxmit
else
bulksize = USB_FULL_SPEED_BULK_SIZE;
- /* check xmitbuffer is ok */
- if (!pxmitbuf) {
- pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv);
- if (!pxmitbuf)
- return false;
- }
-
- /* 3 1. pick up first frame */
- rtw_free_xmitframe(pxmitpriv, pxmitframe);
+ pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv);
+ if (!pxmitbuf)
+ return false;
- pxmitframe = rtw_dequeue_xframe(pxmitpriv, pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry);
+ pxmitframe = rtw_dequeue_xframe(pxmitpriv, pxmitpriv->hwxmits);
if (!pxmitframe) {
/* no more xmit frame, release xmit buffer */
rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
@@ -475,7 +461,7 @@ bool rtl8188eu_xmitframe_complete(struct adapter *adapt, struct xmit_priv *pxmit
}
spin_lock_bh(&pxmitpriv->lock);
- xmitframe_phead = get_list_head(&ptxservq->sta_pending);
+ xmitframe_phead = &ptxservq->sta_pending;
xmitframe_plist = xmitframe_phead->next;
while (xmitframe_phead != xmitframe_plist) {
@@ -503,7 +489,7 @@ bool rtl8188eu_xmitframe_complete(struct adapter *adapt, struct xmit_priv *pxmit
rtw_xmit_complete(adapt, pxmitframe);
/* (len - TXDESC_SIZE) == pxmitframe->attrib.last_txcmdsz */
- update_txdesc(pxmitframe, pxmitframe->buf_addr, pxmitframe->attrib.last_txcmdsz, true);
+ update_txdesc(pxmitframe, pxmitframe->buf_addr, pxmitframe->attrib.last_txcmdsz);
/* don't need xmitframe any more */
rtw_free_xmitframe(pxmitpriv, pxmitframe);
@@ -526,7 +512,7 @@ bool rtl8188eu_xmitframe_complete(struct adapter *adapt, struct xmit_priv *pxmit
}
} /* end while (aggregate same priority and same DA(AP or STA) frames) */
- if (list_empty(&ptxservq->sta_pending.queue))
+ if (list_empty(&ptxservq->sta_pending))
list_del_init(&ptxservq->tx_pending);
spin_unlock_bh(&pxmitpriv->lock);
@@ -543,7 +529,7 @@ bool rtl8188eu_xmitframe_complete(struct adapter *adapt, struct xmit_priv *pxmit
pfirstframe->pkt_offset--;
}
- update_txdesc(pfirstframe, pfirstframe->buf_addr, pfirstframe->attrib.last_txcmdsz, true);
+ update_txdesc(pfirstframe, pfirstframe->buf_addr, pfirstframe->attrib.last_txcmdsz);
/* 3 4. write xmit buffer to USB FIFO */
ff_hwaddr = rtw_get_ff_hwaddr(pfirstframe);
@@ -610,7 +596,7 @@ static s32 pre_xmitframe(struct adapter *adapt, struct xmit_frame *pxmitframe)
return true;
enqueue:
- res = rtw_xmitframe_enqueue(adapt, pxmitframe);
+ res = rtw_xmit_classifier(adapt, pxmitframe);
spin_unlock_bh(&pxmitpriv->lock);
if (res != _SUCCESS) {
diff --git a/drivers/staging/r8188eu/hal/usb_halinit.c b/drivers/staging/r8188eu/hal/usb_halinit.c
index d28b4dc2a767..a1051ac1cac4 100644
--- a/drivers/staging/r8188eu/hal/usb_halinit.c
+++ b/drivers/staging/r8188eu/hal/usb_halinit.c
@@ -600,20 +600,17 @@ u32 rtl8188eu_hal_init(struct adapter *Adapter)
Adapter->pwrctrlpriv.bFwCurrentInPSMode = false;
haldata->LastHMEBoxNum = 0;
- status = PHY_MACConfig8188E(Adapter);
- if (status == _FAIL)
- goto exit;
+ if (PHY_MACConfig8188E(Adapter))
+ return _FAIL;
/* */
/* d. Initialize BB related configurations. */
/* */
- status = PHY_BBConfig8188E(Adapter);
- if (status == _FAIL)
- goto exit;
+ if (PHY_BBConfig8188E(Adapter))
+ return _FAIL;
- status = phy_RF6052_Config_ParaFile(Adapter);
- if (status == _FAIL)
- goto exit;
+ if (phy_RF6052_Config_ParaFile(Adapter))
+ return _FAIL;
status = rtl8188e_iol_efuse_patch(Adapter);
if (status == _FAIL)
@@ -851,29 +848,25 @@ u32 rtl8188eu_hal_deinit(struct adapter *Adapter)
return _SUCCESS;
}
-unsigned int rtl8188eu_inirp_init(struct adapter *Adapter)
+int rtl8188eu_inirp_init(struct adapter *Adapter)
{
u8 i;
struct recv_buf *precvbuf;
- uint status;
struct recv_priv *precvpriv = &Adapter->recvpriv;
-
- status = _SUCCESS;
+ int ret;
/* issue Rx irp to receive data */
precvbuf = (struct recv_buf *)precvpriv->precv_buf;
for (i = 0; i < NR_RECVBUFF; i++) {
- if (!rtw_read_port(Adapter, (unsigned char *)precvbuf)) {
- status = _FAIL;
- goto exit;
- }
+ ret = rtw_read_port(Adapter, precvbuf);
+ if (ret)
+ return ret;
precvbuf++;
precvpriv->free_recv_buf_queue_cnt--;
}
-exit:
- return status;
+ return 0;
}
/* */
diff --git a/drivers/staging/r8188eu/hal/usb_ops_linux.c b/drivers/staging/r8188eu/hal/usb_ops_linux.c
index 7c72f5e04d9b..9611b19ab55b 100644
--- a/drivers/staging/r8188eu/hal/usb_ops_linux.c
+++ b/drivers/staging/r8188eu/hal/usb_ops_linux.c
@@ -7,9 +7,12 @@
#include "../include/usb_ops.h"
#include "../include/rtl8188e_hal.h"
-static int usb_read(struct intf_hdl *intf, u16 value, void *data, u8 size)
+#define VENDOR_CMD_MAX_DATA_LEN 254
+
+#define RTW_USB_CONTROL_MSG_TIMEOUT 500/* ms */
+
+static int usb_read(struct adapter *adapt, u16 value, void *data, u8 size)
{
- struct adapter *adapt = intf->padapter;
struct dvobj_priv *dvobjpriv = adapter_to_dvobj(adapt);
struct usb_device *udev = dvobjpriv->pusbdev;
int status;
@@ -50,9 +53,8 @@ static int usb_read(struct intf_hdl *intf, u16 value, void *data, u8 size)
return status;
}
-static int usb_write(struct intf_hdl *intf, u16 value, void *data, u8 size)
+static int usb_write(struct adapter *adapt, u16 value, void *data, u8 size)
{
- struct adapter *adapt = intf->padapter;
struct dvobj_priv *dvobjpriv = adapter_to_dvobj(adapt);
struct usb_device *udev = dvobjpriv->pusbdev;
int status;
@@ -95,22 +97,18 @@ static int usb_write(struct intf_hdl *intf, u16 value, void *data, u8 size)
int __must_check rtw_read8(struct adapter *adapter, u32 addr, u8 *data)
{
- struct io_priv *io_priv = &adapter->iopriv;
- struct intf_hdl *intf = &io_priv->intf;
u16 value = addr & 0xffff;
- return usb_read(intf, value, data, 1);
+ return usb_read(adapter, value, data, 1);
}
int __must_check rtw_read16(struct adapter *adapter, u32 addr, u16 *data)
{
- struct io_priv *io_priv = &adapter->iopriv;
- struct intf_hdl *intf = &io_priv->intf;
u16 value = addr & 0xffff;
__le16 le_data;
int res;
- res = usb_read(intf, value, &le_data, 2);
+ res = usb_read(adapter, value, &le_data, 2);
if (res)
return res;
@@ -121,13 +119,11 @@ int __must_check rtw_read16(struct adapter *adapter, u32 addr, u16 *data)
int __must_check rtw_read32(struct adapter *adapter, u32 addr, u32 *data)
{
- struct io_priv *io_priv = &adapter->iopriv;
- struct intf_hdl *intf = &io_priv->intf;
u16 value = addr & 0xffff;
__le32 le_data;
int res;
- res = usb_read(intf, value, &le_data, 4);
+ res = usb_read(adapter, value, &le_data, 4);
if (res)
return res;
@@ -138,55 +134,44 @@ int __must_check rtw_read32(struct adapter *adapter, u32 addr, u32 *data)
int rtw_write8(struct adapter *adapter, u32 addr, u8 val)
{
- struct io_priv *io_priv = &adapter->iopriv;
- struct intf_hdl *intf = &io_priv->intf;
u16 value = addr & 0xffff;
int ret;
- ret = usb_write(intf, value, &val, 1);
+ ret = usb_write(adapter, value, &val, 1);
return RTW_STATUS_CODE(ret);
}
int rtw_write16(struct adapter *adapter, u32 addr, u16 val)
{
- struct io_priv *io_priv = &adapter->iopriv;
- struct intf_hdl *intf = &io_priv->intf;
u16 value = addr & 0xffff;
__le16 data = cpu_to_le16(val);
int ret;
- ret = usb_write(intf, value, &data, 2);
+ ret = usb_write(adapter, value, &data, 2);
return RTW_STATUS_CODE(ret);
}
int rtw_write32(struct adapter *adapter, u32 addr, u32 val)
{
- struct io_priv *io_priv = &adapter->iopriv;
- struct intf_hdl *intf = &io_priv->intf;
u16 value = addr & 0xffff;
__le32 data = cpu_to_le32(val);
int ret;
- ret = usb_write(intf, value, &data, 4);
+ ret = usb_write(adapter, value, &data, 4);
return RTW_STATUS_CODE(ret);
}
int rtw_writeN(struct adapter *adapter, u32 addr, u32 length, u8 *data)
{
- struct io_priv *io_priv = &adapter->iopriv;
- struct intf_hdl *intf = &io_priv->intf;
u16 value = addr & 0xffff;
- int ret;
if (length > VENDOR_CMD_MAX_DATA_LEN)
- return _FAIL;
+ return -EINVAL;
- ret = usb_write(intf, value, data, length);
-
- return RTW_STATUS_CODE(ret);
+ return usb_write(adapter, value, data, length);
}
static void handle_txrpt_ccx_88e(struct adapter *adapter, u8 *buf)
@@ -363,7 +348,7 @@ void rtl8188eu_recv_tasklet(unsigned long priv)
}
}
-static void usb_read_port_complete(struct urb *purb, struct pt_regs *regs)
+static void usb_read_port_complete(struct urb *purb)
{
struct recv_buf *precvbuf = (struct recv_buf *)purb->context;
struct adapter *adapt = (struct adapter *)precvbuf->adapter;
@@ -379,7 +364,7 @@ static void usb_read_port_complete(struct urb *purb, struct pt_regs *regs)
if (purb->status == 0) { /* SUCCESS */
if ((purb->actual_length > MAX_RECVBUF_SZ) || (purb->actual_length < RXDESC_SIZE)) {
precvbuf->reuse = true;
- rtw_read_port(adapt, (unsigned char *)precvbuf);
+ rtw_read_port(adapt, precvbuf);
} else {
rtw_reset_continual_urb_error(adapter_to_dvobj(adapt));
@@ -391,7 +376,7 @@ static void usb_read_port_complete(struct urb *purb, struct pt_regs *regs)
precvbuf->pskb = NULL;
precvbuf->reuse = false;
- rtw_read_port(adapt, (unsigned char *)precvbuf);
+ rtw_read_port(adapt, precvbuf);
}
} else {
skb_put(precvbuf->pskb, purb->actual_length);
@@ -411,7 +396,7 @@ static void usb_read_port_complete(struct urb *purb, struct pt_regs *regs)
case -EPROTO:
case -EOVERFLOW:
precvbuf->reuse = true;
- rtw_read_port(adapt, (unsigned char *)precvbuf);
+ rtw_read_port(adapt, precvbuf);
break;
case -EINPROGRESS:
break;
@@ -421,10 +406,9 @@ static void usb_read_port_complete(struct urb *purb, struct pt_regs *regs)
}
}
-u32 rtw_read_port(struct adapter *adapter, u8 *rmem)
+int rtw_read_port(struct adapter *adapter, struct recv_buf *precvbuf)
{
struct urb *purb = NULL;
- struct recv_buf *precvbuf = (struct recv_buf *)rmem;
struct dvobj_priv *pdvobj = adapter_to_dvobj(adapter);
struct recv_priv *precvpriv = &adapter->recvpriv;
struct usb_device *pusbd = pdvobj->pusbdev;
@@ -432,13 +416,12 @@ u32 rtw_read_port(struct adapter *adapter, u8 *rmem)
unsigned int pipe;
size_t tmpaddr = 0;
size_t alignment = 0;
- u32 ret = _SUCCESS;
if (adapter->bDriverStopped || adapter->bSurpriseRemoved)
- return _FAIL;
+ return -EPERM;
if (!precvbuf)
- return _FAIL;
+ return -ENOMEM;
if (!precvbuf->reuse || !precvbuf->pskb) {
precvbuf->pskb = skb_dequeue(&precvpriv->free_recv_skb_queue);
@@ -450,7 +433,7 @@ u32 rtw_read_port(struct adapter *adapter, u8 *rmem)
if (!precvbuf->reuse || !precvbuf->pskb) {
precvbuf->pskb = netdev_alloc_skb(adapter->pnetdev, MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ);
if (!precvbuf->pskb)
- return _FAIL;
+ return -ENOMEM;
tmpaddr = (size_t)precvbuf->pskb->data;
alignment = tmpaddr & (RECVBUFF_ALIGN_SZ - 1);
@@ -474,29 +457,20 @@ u32 rtw_read_port(struct adapter *adapter, u8 *rmem)
err = usb_submit_urb(purb, GFP_ATOMIC);
if ((err) && (err != (-EPERM)))
- ret = _FAIL;
+ return err;
- return ret;
+ return 0;
}
void rtl8188eu_xmit_tasklet(unsigned long priv)
{
- int ret = false;
struct adapter *adapt = (struct adapter *)priv;
- struct xmit_priv *pxmitpriv = &adapt->xmitpriv;
if (check_fwstate(&adapt->mlmepriv, _FW_UNDER_SURVEY))
return;
- while (1) {
- if ((adapt->bDriverStopped) ||
- (adapt->bSurpriseRemoved) ||
- (adapt->bWritePortCancel))
- break;
-
- ret = rtl8188eu_xmitframe_complete(adapt, pxmitpriv, NULL);
-
- if (!ret)
+ do {
+ if (adapt->bDriverStopped || adapt->bSurpriseRemoved || adapt->bWritePortCancel)
break;
- }
+ } while (rtl8188eu_xmitframe_complete(adapt));
}
diff --git a/drivers/staging/r8188eu/include/drv_types.h b/drivers/staging/r8188eu/include/drv_types.h
index 8fef5759c36a..159990facb8a 100644
--- a/drivers/staging/r8188eu/include/drv_types.h
+++ b/drivers/staging/r8188eu/include/drv_types.h
@@ -152,7 +152,6 @@ struct adapter {
struct mlme_ext_priv mlmeextpriv;
struct cmd_priv cmdpriv;
struct evt_priv evtpriv;
- struct io_priv iopriv;
struct xmit_priv xmitpriv;
struct recv_priv recvpriv;
struct sta_priv stapriv;
@@ -172,8 +171,6 @@ struct adapter {
s8 signal_strength;
void *cmdThread;
- void (*intf_start)(struct adapter *adapter);
- void (*intf_stop)(struct adapter *adapter);
struct net_device *pnetdev;
/* used by rtw_rereg_nd_name related function */
@@ -187,7 +184,6 @@ struct adapter {
int bup;
struct net_device_stats stats;
struct iw_statistics iwstats;
- struct proc_dir_entry *dir_dev;/* for proc directory */
int net_closed;
u8 bFWReady;
diff --git a/drivers/staging/r8188eu/include/hal_intf.h b/drivers/staging/r8188eu/include/hal_intf.h
index ac6e3f95c5b7..296aa5b8268d 100644
--- a/drivers/staging/r8188eu/include/hal_intf.h
+++ b/drivers/staging/r8188eu/include/hal_intf.h
@@ -26,7 +26,7 @@ void UpdateHalRAMask8188EUsb(struct adapter *adapt, u32 mac_id, u8 rssi_level);
int rtl8188e_IOL_exec_cmds_sync(struct adapter *adapter,
struct xmit_frame *xmit_frame, u32 max_wating_ms, u32 bndy_cnt);
-unsigned int rtl8188eu_inirp_init(struct adapter *Adapter);
+int rtl8188eu_inirp_init(struct adapter *Adapter);
uint rtw_hal_init(struct adapter *padapter);
uint rtw_hal_deinit(struct adapter *padapter);
diff --git a/drivers/staging/r8188eu/include/osdep_intf.h b/drivers/staging/r8188eu/include/osdep_intf.h
index 6d66cb57225e..457fb3852a19 100644
--- a/drivers/staging/r8188eu/include/osdep_intf.h
+++ b/drivers/staging/r8188eu/include/osdep_intf.h
@@ -7,38 +7,6 @@
#include "osdep_service.h"
#include "drv_types.h"
-struct intf_priv {
- u8 *intf_dev;
- u32 max_iosz; /* USB2.0: 128, USB1.1: 64, SDIO:64 */
- u32 max_xmitsz; /* USB2.0: unlimited, SDIO:512 */
- u32 max_recvsz; /* USB2.0: unlimited, SDIO:512 */
-
- u8 *io_rwmem;
- u8 *allocated_io_rwmem;
- u32 io_wsz; /* unit: 4bytes */
- u32 io_rsz;/* unit: 4bytes */
- u8 intf_status;
-
- void (*_bus_io)(u8 *priv);
-
-/*
-Under Sync. IRP (SDIO/USB)
-A protection mechanism is necessary for the io_rwmem(read/write protocol)
-
-Under Async. IRP (SDIO/USB)
-The protection mechanism is through the pending queue.
-*/
- struct mutex ioctl_mutex;
- /* when in USB, IO is through interrupt in/out endpoints */
- struct usb_device *udev;
- struct urb *piorw_urb;
- u8 io_irp_cnt;
- u8 bio_irp_pending;
- struct timer_list io_timer;
- u8 bio_irp_timeout;
- u8 bio_timer_cancel;
-};
-
int netdev_open(struct net_device *pnetdev);
int netdev_close(struct net_device *pnetdev);
diff --git a/drivers/staging/r8188eu/include/rtl8188e_cmd.h b/drivers/staging/r8188eu/include/rtl8188e_cmd.h
index 1e01c1662f9a..c785cf8ed683 100644
--- a/drivers/staging/r8188eu/include/rtl8188e_cmd.h
+++ b/drivers/staging/r8188eu/include/rtl8188e_cmd.h
@@ -85,6 +85,6 @@ void rtl8188e_Add_RateATid(struct adapter *padapter, u32 bitmap, u8 arg,
void rtl8188e_set_p2p_ps_offload_cmd(struct adapter *adapt, u8 p2p_ps_state);
void CheckFwRsvdPageContent(struct adapter *adapt);
-void rtl8188e_set_FwMediaStatus_cmd(struct adapter *adapt, __le16 mstatus_rpt);
+void rtl8188e_set_FwMediaStatus_cmd(struct adapter *adapt, u16 mstatus_rpt);
#endif/* __RTL8188E_CMD_H__ */
diff --git a/drivers/staging/r8188eu/include/rtl8188e_spec.h b/drivers/staging/r8188eu/include/rtl8188e_spec.h
index 3fa3b3e5dd64..25b31417cd58 100644
--- a/drivers/staging/r8188eu/include/rtl8188e_spec.h
+++ b/drivers/staging/r8188eu/include/rtl8188e_spec.h
@@ -510,28 +510,7 @@ Default: 00b.
/* 8192C BW_OPMODE bits (Offset 0x203, 8bit) */
#define BW_OPMODE_20MHZ BIT(2)
-/* 8192C CAM Config Setting (offset 0x250, 1 byte) */
-#define CAM_VALID BIT(15)
-#define CAM_NOTVALID 0x0000
-#define CAM_USEDK BIT(5)
-
-#define CAM_CONTENT_COUNT 8
-
-#define CAM_NONE 0x0
-#define CAM_WEP40 0x01
-#define CAM_TKIP 0x02
-#define CAM_AES 0x04
-#define CAM_WEP104 0x05
-#define CAM_SMS4 0x6
-
-#define TOTAL_CAM_ENTRY 32
-#define HALF_CAM_ENTRY 16
-
-#define CAM_CONFIG_USEDK true
-#define CAM_CONFIG_NO_USEDK false
-
#define CAM_WRITE BIT(16)
-#define CAM_READ 0x00000000
#define CAM_POLLINIG BIT(31)
#define SCR_UseDK 0x01
diff --git a/drivers/staging/r8188eu/include/rtl8188e_xmit.h b/drivers/staging/r8188eu/include/rtl8188e_xmit.h
index 6db7fabebea9..a023dd792da7 100644
--- a/drivers/staging/r8188eu/include/rtl8188e_xmit.h
+++ b/drivers/staging/r8188eu/include/rtl8188e_xmit.h
@@ -5,17 +5,7 @@
#define __RTL8188E_XMIT_H__
#define MAX_TX_AGG_PACKET_NUMBER 0xFF
-/* */
-/* Queue Select Value in TxDesc */
-/* */
-#define QSLT_BK 0x2/* 0x01 */
-#define QSLT_BE 0x0
-#define QSLT_VI 0x5/* 0x4 */
-#define QSLT_VO 0x7/* 0x6 */
-#define QSLT_BEACON 0x10
-#define QSLT_HIGH 0x11
#define QSLT_MGNT 0x12
-#define QSLT_CMD 0x13
/* For 88e early mode */
#define SET_EARLYMODE_PKTNUM(__paddr, __value) \
@@ -131,14 +121,10 @@ struct txrpt_ccx_88e {
void rtl8188e_fill_fake_txdesc(struct adapter *padapter, u8 *pDesc,
u32 BufferLen, u8 IsPsPoll, u8 IsBTQosNull);
-s32 rtl8188eu_init_xmit_priv(struct adapter *padapter);
s32 rtl8188eu_hal_xmit(struct adapter *padapter, struct xmit_frame *frame);
s32 rtl8188eu_mgnt_xmit(struct adapter *padapter, struct xmit_frame *frame);
s32 rtl8188eu_xmit_buf_handler(struct adapter *padapter);
-#define hal_xmit_handler rtl8188eu_xmit_buf_handler
void rtl8188eu_xmit_tasklet(unsigned long priv);
-bool rtl8188eu_xmitframe_complete(struct adapter *padapter,
- struct xmit_priv *pxmitpriv,
- struct xmit_buf *pxmitbuf);
+bool rtl8188eu_xmitframe_complete(struct adapter *padapter);
#endif /* __RTL8188E_XMIT_H__ */
diff --git a/drivers/staging/r8188eu/include/rtw_cmd.h b/drivers/staging/r8188eu/include/rtw_cmd.h
index c330a4435b31..e8eecd52d1d8 100644
--- a/drivers/staging/r8188eu/include/rtw_cmd.h
+++ b/drivers/staging/r8188eu/include/rtw_cmd.h
@@ -32,7 +32,6 @@ struct cmd_priv {
struct completion start_cmd_thread;
struct completion stop_cmd_thread;
struct __queue cmd_queue;
- u8 cmd_seq;
u8 *cmd_buf; /* shall be non-paged, and 4 bytes aligned */
u8 *cmd_allocated_buf;
u8 *rsp_buf; /* shall be non-paged, and 4 bytes aligned */
@@ -744,7 +743,7 @@ u8 rtw_rpt_timer_cfg_cmd(struct adapter *padapter, u16 minRptTime);
u8 rtw_antenna_select_cmd(struct adapter *padapter, u8 antenna, u8 enqueue);
u8 rtw_ps_cmd(struct adapter *padapter);
-u8 rtw_chk_hi_queue_cmd(struct adapter *padapter);
+void rtw_chk_hi_queue_cmd(struct adapter *padapter);
u8 rtw_set_chplan_cmd(struct adapter *padapter, u8 chplan);
diff --git a/drivers/staging/r8188eu/include/rtw_io.h b/drivers/staging/r8188eu/include/rtw_io.h
index e9744694204b..e1718f739cc9 100644
--- a/drivers/staging/r8188eu/include/rtw_io.h
+++ b/drivers/staging/r8188eu/include/rtw_io.h
@@ -16,215 +16,10 @@
#include <linux/usb.h>
#include <linux/usb/ch9.h>
-#define rtw_usb_buffer_alloc(dev, size, dma) \
- usb_alloc_coherent((dev), (size), (in_interrupt() ? \
- GFP_ATOMIC : GFP_KERNEL), (dma))
-#define rtw_usb_buffer_free(dev, size, addr, dma) \
- usb_free_coherent((dev), (size), (addr), (dma))
-
-#define NUM_IOREQ 8
-
-#define MAX_PROT_SZ (64-16)
-
-#define _IOREADY 0
-#define _IO_WAIT_COMPLETE 1
-#define _IO_WAIT_RSP 2
-
-/* IO COMMAND TYPE */
-#define _IOSZ_MASK_ (0x7F)
-#define _IO_WRITE_ BIT(7)
-#define _IO_FIXED_ BIT(8)
-#define _IO_BURST_ BIT(9)
-#define _IO_BYTE_ BIT(10)
-#define _IO_HW_ BIT(11)
-#define _IO_WORD_ BIT(12)
-#define _IO_SYNC_ BIT(13)
-#define _IO_CMDMASK_ (0x1F80)
-
-/*
- For prompt mode accessing, caller shall free io_req
- Otherwise, io_handler will free io_req
-*/
-
-/* IO STATUS TYPE */
-#define _IO_ERR_ BIT(2)
-#define _IO_SUCCESS_ BIT(1)
-#define _IO_DONE_ BIT(0)
-
-#define IO_RD32 (_IO_SYNC_ | _IO_WORD_)
-#define IO_RD16 (_IO_SYNC_ | _IO_HW_)
-#define IO_RD8 (_IO_SYNC_ | _IO_BYTE_)
-
-#define IO_RD32_ASYNC (_IO_WORD_)
-#define IO_RD16_ASYNC (_IO_HW_)
-#define IO_RD8_ASYNC (_IO_BYTE_)
-
-#define IO_WR32 (_IO_WRITE_ | _IO_SYNC_ | _IO_WORD_)
-#define IO_WR16 (_IO_WRITE_ | _IO_SYNC_ | _IO_HW_)
-#define IO_WR8 (_IO_WRITE_ | _IO_SYNC_ | _IO_BYTE_)
-
-#define IO_WR32_ASYNC (_IO_WRITE_ | _IO_WORD_)
-#define IO_WR16_ASYNC (_IO_WRITE_ | _IO_HW_)
-#define IO_WR8_ASYNC (_IO_WRITE_ | _IO_BYTE_)
-
-/*
- Only Sync. burst accessing is provided.
-*/
-
-#define IO_WR_BURST(x) \
- (_IO_WRITE_ | _IO_SYNC_ | _IO_BURST_ | ((x) & _IOSZ_MASK_))
-#define IO_RD_BURST(x) \
- (_IO_SYNC_ | _IO_BURST_ | ((x) & _IOSZ_MASK_))
-
-/* below is for the intf_option bit defition... */
-
-#define _INTF_ASYNC_ BIT(0) /* support async io */
-
-struct intf_priv;
-struct intf_hdl;
-struct io_queue;
-
-struct io_req {
- struct list_head list;
- u32 addr;
- u32 val;
- u32 command;
- u32 status;
- u8 *pbuf;
- struct semaphore sema;
-
- void (*_async_io_callback)(struct adapter *padater,
- struct io_req *pio_req, u8 *cnxt);
- u8 *cnxt;
-};
-
-struct intf_hdl {
- struct adapter *padapter;
- struct dvobj_priv *pintf_dev;
-};
-
-struct reg_protocol_rd {
-#ifdef __LITTLE_ENDIAN
- /* DW1 */
- u32 NumOfTrans:4;
- u32 Reserved1:4;
- u32 Reserved2:24;
- /* DW2 */
- u32 ByteCount:7;
- u32 WriteEnable:1; /* 0:read, 1:write */
- u32 FixOrContinuous:1; /* 0:continuous, 1: Fix */
- u32 BurstMode:1;
- u32 Byte1Access:1;
- u32 Byte2Access:1;
- u32 Byte4Access:1;
- u32 Reserved3:3;
- u32 Reserved4:16;
- /* DW3 */
- u32 BusAddress;
- /* DW4 */
- /* u32 Value; */
-#else
-/* DW1 */
- u32 Reserved1:4;
- u32 NumOfTrans:4;
- u32 Reserved2:24;
- /* DW2 */
- u32 WriteEnable:1;
- u32 ByteCount:7;
- u32 Reserved3:3;
- u32 Byte4Access:1;
-
- u32 Byte2Access:1;
- u32 Byte1Access:1;
- u32 BurstMode:1;
- u32 FixOrContinuous:1;
- u32 Reserved4:16;
- /* DW3 */
- u32 BusAddress;
-
- /* DW4 */
-#endif
-};
-
-struct reg_protocol_wt {
-#ifdef __LITTLE_ENDIAN
- /* DW1 */
- u32 NumOfTrans:4;
- u32 Reserved1:4;
- u32 Reserved2:24;
- /* DW2 */
- u32 ByteCount:7;
- u32 WriteEnable:1; /* 0:read, 1:write */
- u32 FixOrContinuous:1; /* 0:continuous, 1: Fix */
- u32 BurstMode:1;
- u32 Byte1Access:1;
- u32 Byte2Access:1;
- u32 Byte4Access:1;
- u32 Reserved3:3;
- u32 Reserved4:16;
- /* DW3 */
- u32 BusAddress;
- /* DW4 */
- u32 Value;
-#else
- /* DW1 */
- u32 Reserved1 :4;
- u32 NumOfTrans:4;
- u32 Reserved2:24;
- /* DW2 */
- u32 WriteEnable:1;
- u32 ByteCount:7;
- u32 Reserved3:3;
- u32 Byte4Access:1;
- u32 Byte2Access:1;
- u32 Byte1Access:1;
- u32 BurstMode:1;
- u32 FixOrContinuous:1;
- u32 Reserved4:16;
- /* DW3 */
- u32 BusAddress;
- /* DW4 */
- u32 Value;
-#endif
-};
-
-/*
-Below is the data structure used by _io_handler
-*/
-
-struct io_queue {
- spinlock_t lock;
- struct list_head free_ioreqs;
- struct list_head pending; /* The io_req list that will be served
- * in the single protocol read/write.*/
- struct list_head processing;
- u8 *free_ioreqs_buf; /* 4-byte aligned */
- u8 *pallocated_free_ioreqs_buf;
- struct intf_hdl intf;
-};
-
-struct io_priv {
- struct adapter *padapter;
- struct intf_hdl intf;
-};
-
-uint ioreq_flush(struct adapter *adapter, struct io_queue *ioqueue);
-void sync_ioreq_enqueue(struct io_req *preq, struct io_queue *ioqueue);
-uint sync_ioreq_flush(struct adapter *adapter, struct io_queue *ioqueue);
-uint free_ioreq(struct io_req *preq, struct io_queue *pio_queue);
-struct io_req *alloc_ioreq(struct io_queue *pio_q);
-
-uint register_intf_hdl(u8 *dev, struct intf_hdl *pintfhdl);
-void unregister_intf_hdl(struct intf_hdl *pintfhdl);
-
-void _rtw_attrib_read(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
-void _rtw_attrib_write(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
-
int __must_check rtw_read8(struct adapter *adapter, u32 addr, u8 *data);
int __must_check rtw_read16(struct adapter *adapter, u32 addr, u16 *data);
int __must_check rtw_read32(struct adapter *adapter, u32 addr, u32 *data);
-void _rtw_read_mem(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
-u32 rtw_read_port(struct adapter *adapter, u8 *pmem);
+int rtw_read_port(struct adapter *adapter, struct recv_buf *precvbuf);
void rtw_read_port_cancel(struct adapter *adapter);
int rtw_write8(struct adapter *adapter, u32 addr, u8 val);
@@ -232,57 +27,7 @@ int rtw_write16(struct adapter *adapter, u32 addr, u16 val);
int rtw_write32(struct adapter *adapter, u32 addr, u32 val);
int rtw_writeN(struct adapter *adapter, u32 addr, u32 length, u8 *pdata);
-void _rtw_write_mem(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
u32 rtw_write_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
void rtw_write_port_cancel(struct adapter *adapter);
-void rtw_write_scsi(struct adapter *adapter, u32 cnt, u8 *pmem);
-
-/* ioreq */
-void ioreq_read8(struct adapter *adapter, u32 addr, u8 *pval);
-void ioreq_read16(struct adapter *adapter, u32 addr, u16 *pval);
-void ioreq_read32(struct adapter *adapter, u32 addr, u32 *pval);
-void ioreq_write8(struct adapter *adapter, u32 addr, u8 val);
-void ioreq_write16(struct adapter *adapter, u32 addr, u16 val);
-void ioreq_write32(struct adapter *adapter, u32 addr, u32 val);
-
-uint async_read8(struct adapter *adapter, u32 addr, u8 *pbuff,
- void (*_async_io_callback)(struct adapter *padater,
- struct io_req *pio_req,
- u8 *cnxt), u8 *cnxt);
-uint async_read16(struct adapter *adapter, u32 addr, u8 *pbuff,
- void (*_async_io_callback)(struct adapter *padater,
- struct io_req *pio_req,
- u8 *cnxt), u8 *cnxt);
-uint async_read32(struct adapter *adapter, u32 addr, u8 *pbuff,
- void (*_async_io_callback)(struct adapter *padater,
- struct io_req *pio_req,
- u8 *cnxt), u8 *cnxt);
-
-void async_read_mem(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
-void async_read_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
-
-void async_write8(struct adapter *adapter, u32 addr, u8 val,
- void (*_async_io_callback)(struct adapter *padater,
- struct io_req *pio_req,
- u8 *cnxt), u8 *cnxt);
-void async_write16(struct adapter *adapter, u32 addr, u16 val,
- void (*_async_io_callback)(struct adapter *padater,
- struct io_req *pio_req,
- u8 *cnxt), u8 *cnxt);
-void async_write32(struct adapter *adapter, u32 addr, u32 val,
- void (*_async_io_callback)(struct adapter *padater,
- struct io_req *pio_req,
- u8 *cnxt), u8 *cnxt);
-
-void async_write_mem(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
-void async_write_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
-
-uint alloc_io_queue(struct adapter *adapter);
-void free_io_queue(struct adapter *adapter);
-void async_bus_io(struct io_queue *pio_q);
-void bus_sync_io(struct io_queue *pio_q);
-u32 _ioreq2rwmem(struct io_queue *pio_q);
-void dev_power_down(struct adapter *Adapter, u8 bpwrup);
-
#endif /* _RTL8711_IO_H_ */
diff --git a/drivers/staging/r8188eu/include/rtw_pwrctrl.h b/drivers/staging/r8188eu/include/rtw_pwrctrl.h
index 6e9fdd66fad1..9f5cffd8bfb1 100644
--- a/drivers/staging/r8188eu/include/rtw_pwrctrl.h
+++ b/drivers/staging/r8188eu/include/rtw_pwrctrl.h
@@ -71,7 +71,6 @@ struct pwrctrl_priv {
int pwr_state_check_interval;
enum rt_rf_power_state rf_pwrstate;/* cur power state */
- enum rt_rf_power_state change_rfpwrstate;
u8 bkeepfwalive;
};
@@ -99,8 +98,6 @@ void rtw_set_firmware_ps_mode(struct adapter *adapter, u8 mode);
void rtw_set_ps_mode(struct adapter *adapter, u8 ps_mode, u8 smart_ps,
u8 bcn_ant_mode);
void LeaveAllPowerSaveMode(struct adapter *adapter);
-void ips_enter(struct adapter *padapter);
-int ips_leave(struct adapter *padapter);
void rtw_ps_processor(struct adapter *padapter);
diff --git a/drivers/staging/r8188eu/include/rtw_xmit.h b/drivers/staging/r8188eu/include/rtw_xmit.h
index 6e7ebea5362d..feeac85aedb0 100644
--- a/drivers/staging/r8188eu/include/rtw_xmit.h
+++ b/drivers/staging/r8188eu/include/rtw_xmit.h
@@ -97,7 +97,7 @@ union txdesc {
};
struct hw_xmit {
- struct __queue *sta_queue;
+ struct list_head *sta_list;
int accnt;
};
@@ -152,14 +152,7 @@ struct pkt_attrib {
#define NULL_FRAMETAG (0x0)
#define DATA_FRAMETAG 0x01
-#define L2_FRAMETAG 0x02
#define MGNT_FRAMETAG 0x03
-#define AMSDU_FRAMETAG 0x04
-
-#define EII_FRAMETAG 0x05
-#define IEEE8023_FRAMETAG 0x06
-
-#define MP_FRAMETAG 0x07
#define TXAGG_FRAMETAG 0x08
@@ -196,14 +189,11 @@ struct xmit_buf {
u8 *pbuf;
void *priv_data;
u16 ext_tag; /* 0: Normal xmitbuf, 1: extension xmitbuf. */
- u16 flags;
+ bool high_queue;
u32 alloc_sz;
u32 len;
struct submit_ctx *sctx;
- u32 ff_hwaddr;
struct urb *pxmit_urb;
- dma_addr_t dma_transfer_addr; /* (in) dma addr for transfer_buffer */
- u8 bpending[8];
int last[8];
};
@@ -223,21 +213,16 @@ struct xmit_frame {
struct tx_servq {
struct list_head tx_pending;
- struct __queue sta_pending;
+ struct list_head sta_pending;
int qcnt;
};
struct sta_xmit_priv {
spinlock_t lock;
- int option;
- int apsd_setting; /* When bit mask is on, the associated edca
- * queue supports APSD. */
struct tx_servq be_q; /* priority == 0,3 */
struct tx_servq bk_q; /* priority == 1,2 */
struct tx_servq vi_q; /* priority == 4,5 */
struct tx_servq vo_q; /* priority == 6,7 */
- struct list_head legacy_dz;
- struct list_head apsd;
u16 txseq_tid[16];
};
@@ -252,46 +237,28 @@ struct hw_txqueue {
int ac_tag;
};
-struct agg_pkt_info {
- u16 offset;
- u16 pkt_len;
-};
-
struct xmit_priv {
spinlock_t lock;
- struct semaphore terminate_xmitthread_sema;
- struct __queue be_pending;
- struct __queue bk_pending;
- struct __queue vi_pending;
- struct __queue vo_pending;
- struct __queue bm_pending;
+ struct list_head be_pending;
+ struct list_head bk_pending;
+ struct list_head vi_pending;
+ struct list_head vo_pending;
u8 *pallocated_frame_buf;
u8 *pxmit_frame_buf;
uint free_xmitframe_cnt;
struct __queue free_xmit_queue;
uint frag_len;
struct adapter *adapter;
- u8 vcs_setting;
- u8 vcs;
- u8 vcs_type;
u64 tx_bytes;
u64 tx_pkts;
u64 tx_drop;
u64 last_tx_bytes;
u64 last_tx_pkts;
struct hw_xmit *hwxmits;
- u8 hwxmit_entry;
u8 wmm_para_seq[4];/* sequence for wmm ac parameter strength
* from large to small. it's value is 0->vo,
* 1->vi, 2->be, 3->bk. */
- struct semaphore tx_retevt;/* all tx return event; */
- u8 txirp_cnt;/* */
struct tasklet_struct xmit_tasklet;
- /* per AC pending irp */
- int beq_cnt;
- int bkq_cnt;
- int viq_cnt;
- int voq_cnt;
struct __queue free_xmitbuf_queue;
struct __queue pending_xmitbuf_queue;
u8 *pallocated_xmitbuf;
@@ -324,7 +291,6 @@ s32 rtw_free_xmitbuf(struct xmit_priv *pxmitpriv,
struct xmit_buf *pxmitbuf);
void rtw_count_tx_stats(struct adapter *padapter,
struct xmit_frame *pxmitframe, int sz);
-void rtw_update_protection(struct adapter *padapter, u8 *ie, uint ie_len);
s32 rtw_make_wlanhdr(struct adapter *padapter, u8 *hdr,
struct pkt_attrib *pattrib);
s32 rtw_put_snap(u8 *data, u16 h_proto);
@@ -332,14 +298,11 @@ s32 rtw_put_snap(u8 *data, u16 h_proto);
struct xmit_frame *rtw_alloc_xmitframe(struct xmit_priv *pxmitpriv);
s32 rtw_free_xmitframe(struct xmit_priv *pxmitpriv,
struct xmit_frame *pxmitframe);
-void rtw_free_xmitframe_queue(struct xmit_priv *pxmitpriv,
- struct __queue *pframequeue);
+void rtw_free_xmitframe_list(struct xmit_priv *pxmitpriv, struct list_head *xframe_list);
struct tx_servq *rtw_get_sta_pending(struct adapter *padapter,
struct sta_info *psta, int up, u8 *ac);
-s32 rtw_xmitframe_enqueue(struct adapter *padapter,
- struct xmit_frame *pxmitframe);
struct xmit_frame *rtw_dequeue_xframe(struct xmit_priv *pxmitpriv,
- struct hw_xmit *phwxmit_i, int entry);
+ struct hw_xmit *phwxmit_i);
s32 rtw_xmit_classifier(struct adapter *padapter,
struct xmit_frame *pxmitframe);
@@ -350,11 +313,9 @@ void _rtw_init_sta_xmit_priv(struct sta_xmit_priv *psta_xmitpriv);
s32 rtw_txframes_pending(struct adapter *padapter);
s32 rtw_txframes_sta_ac_pending(struct adapter *padapter,
struct pkt_attrib *pattrib);
-void rtw_init_hwxmits(struct hw_xmit *phwxmit, int entry);
int _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter);
void _rtw_free_xmit_priv(struct xmit_priv *pxmitpriv);
int rtw_alloc_hwxmits(struct adapter *padapter);
-void rtw_free_hwxmits(struct adapter *padapter);
s32 rtw_xmit(struct adapter *padapter, struct sk_buff **pkt);
int xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_frame *pxmitframe);
diff --git a/drivers/staging/r8188eu/include/usb_ops.h b/drivers/staging/r8188eu/include/usb_ops.h
index ddc46cb44358..5bd8ce37aebf 100644
--- a/drivers/staging/r8188eu/include/usb_ops.h
+++ b/drivers/staging/r8188eu/include/usb_ops.h
@@ -17,8 +17,6 @@
#define MAX_VENDOR_REQ_CMD_SIZE 254 /* 8188cu SIE Support */
#define MAX_USB_IO_CTL_SIZE (MAX_VENDOR_REQ_CMD_SIZE + ALIGNMENT_UNIT)
-#include "usb_ops_linux.h"
-
/*
* Increase and check if the continual_urb_error of this @param dvobjprivei
* is larger than MAX_CONTINUAL_URB_ERR
diff --git a/drivers/staging/r8188eu/include/usb_ops_linux.h b/drivers/staging/r8188eu/include/usb_ops_linux.h
deleted file mode 100644
index 966688eedf66..000000000000
--- a/drivers/staging/r8188eu/include/usb_ops_linux.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
-/* Copyright(c) 2007 - 2011 Realtek Corporation. */
-
-#ifndef __USB_OPS_LINUX_H__
-#define __USB_OPS_LINUX_H__
-
-#define VENDOR_CMD_MAX_DATA_LEN 254
-
-#define RTW_USB_CONTROL_MSG_TIMEOUT_TEST 10/* ms */
-#define RTW_USB_CONTROL_MSG_TIMEOUT 500/* ms */
-
-#define MAX_USBCTRL_VENDORREQ_TIMES 10
-
-#define RTW_USB_BULKOUT_TIME 5000/* ms */
-
-#define _usbctrl_vendorreq_async_callback(urb, regs) \
- _usbctrl_vendorreq_async_callback(urb)
-#define usb_bulkout_zero_complete(purb, regs) \
- usb_bulkout_zero_complete(purb)
-#define usb_write_mem_complete(purb, regs) \
- usb_write_mem_complete(purb)
-#define usb_write_port_complete(purb, regs) \
- usb_write_port_complete(purb)
-#define usb_read_port_complete(purb, regs) \
- usb_read_port_complete(purb)
-#define usb_read_interrupt_complete(purb, regs) \
- usb_read_interrupt_complete(purb)
-
-#endif
diff --git a/drivers/staging/r8188eu/os_dep/ioctl_linux.c b/drivers/staging/r8188eu/os_dep/ioctl_linux.c
index 8e9b7b0664bc..e0a819970546 100644
--- a/drivers/staging/r8188eu/os_dep/ioctl_linux.c
+++ b/drivers/staging/r8188eu/os_dep/ioctl_linux.c
@@ -3061,8 +3061,7 @@ static int rtw_rereg_nd_name(struct net_device *dev,
char *reg_ifname;
reg_ifname = padapter->registrypriv.if2name;
- strncpy(rereg_priv->old_ifname, reg_ifname, IFNAMSIZ);
- rereg_priv->old_ifname[IFNAMSIZ - 1] = 0;
+ strscpy(rereg_priv->old_ifname, reg_ifname, IFNAMSIZ);
}
if (wrqu->data.length > IFNAMSIZ)
@@ -3084,8 +3083,7 @@ static int rtw_rereg_nd_name(struct net_device *dev,
rtw_ips_mode_req(&padapter->pwrctrlpriv, rereg_priv->old_ips_mode);
}
- strncpy(rereg_priv->old_ifname, new_ifname, IFNAMSIZ);
- rereg_priv->old_ifname[IFNAMSIZ - 1] = 0;
+ strscpy(rereg_priv->old_ifname, new_ifname, IFNAMSIZ);
if (!memcmp(new_ifname, "disable%d", 9)) {
/* free network queue for Android's timming issue */
diff --git a/drivers/staging/r8188eu/os_dep/os_intfs.c b/drivers/staging/r8188eu/os_dep/os_intfs.c
index 2f59bb994796..dc419fd1ffa5 100644
--- a/drivers/staging/r8188eu/os_dep/os_intfs.c
+++ b/drivers/staging/r8188eu/os_dep/os_intfs.c
@@ -392,9 +392,6 @@ static void rtw_init_default_value(struct adapter *padapter)
struct security_priv *psecuritypriv = &padapter->securitypriv;
/* xmit_priv */
- pxmitpriv->vcs_setting = pregistrypriv->vrtl_carrier_sense;
- pxmitpriv->vcs = pregistrypriv->vcs_type;
- pxmitpriv->vcs_type = pregistrypriv->vcs_type;
pxmitpriv->frag_len = pregistrypriv->frag_thresh;
/* mlme_priv */
@@ -485,7 +482,7 @@ u8 rtw_init_drv_sw(struct adapter *padapter)
goto free_mlme_ext;
}
- if (_rtw_init_recv_priv(&padapter->recvpriv, padapter) == _FAIL) {
+ if (_rtw_init_recv_priv(&padapter->recvpriv, padapter)) {
dev_err(dvobj_to_dev(padapter->dvobj), "_rtw_init_recv_priv failed\n");
goto free_xmit_priv;
}
@@ -634,8 +631,8 @@ static int _netdev_open(struct net_device *pnetdev)
pr_info("can't init mlme_ext_priv\n");
goto netdev_open_error;
}
- if (padapter->intf_start)
- padapter->intf_start(padapter);
+ if (rtl8188eu_inirp_init(padapter))
+ goto netdev_open_error;
rtw_led_control(padapter, LED_CTL_NO_LINK);
@@ -687,8 +684,8 @@ static int ips_netdrv_open(struct adapter *padapter)
if (status == _FAIL)
goto netdev_open_error;
- if (padapter->intf_start)
- padapter->intf_start(padapter);
+ if (rtl8188eu_inirp_init(padapter))
+ goto netdev_open_error;
rtw_set_pwr_state_check_timer(&padapter->pwrctrlpriv);
_set_timer(&padapter->mlmepriv.dynamic_chk_timer, 5000);
@@ -764,8 +761,8 @@ void rtw_ips_dev_unload(struct adapter *padapter)
{
rtw_fifo_cleanup(padapter);
- if (padapter->intf_stop)
- padapter->intf_stop(padapter);
+ rtw_read_port_cancel(padapter);
+ rtw_write_port_cancel(padapter);
/* s5. */
if (!padapter->bSurpriseRemoved)
diff --git a/drivers/staging/r8188eu/os_dep/usb_intf.c b/drivers/staging/r8188eu/os_dep/usb_intf.c
index 5fbfbcd95de2..74a16d1757ce 100644
--- a/drivers/staging/r8188eu/os_dep/usb_intf.c
+++ b/drivers/staging/r8188eu/os_dep/usb_intf.c
@@ -152,22 +152,6 @@ static void usb_dvobj_deinit(struct usb_interface *usb_intf)
}
-static void usb_intf_start(struct adapter *padapter)
-{
- rtl8188eu_inirp_init(padapter);
-}
-
-static void usb_intf_stop(struct adapter *padapter)
-{
- /* cancel in irp */
- rtw_read_port_cancel(padapter);
-
- /* cancel out irp */
- rtw_write_port_cancel(padapter);
-
- /* todo:cancel other irps */
-}
-
static void rtw_dev_unload(struct adapter *padapter)
{
if (padapter->bup) {
@@ -175,8 +159,9 @@ static void rtw_dev_unload(struct adapter *padapter)
if (padapter->xmitpriv.ack_tx)
rtw_ack_tx_done(&padapter->xmitpriv, RTW_SCTX_DONE_DRV_STOP);
/* s3. */
- if (padapter->intf_stop)
- padapter->intf_stop(padapter);
+ rtw_read_port_cancel(padapter);
+ rtw_write_port_cancel(padapter);
+
/* s4. */
rtw_stop_drv_threads(padapter);
@@ -290,8 +275,6 @@ static int rtw_usb_if1_init(struct dvobj_priv *dvobj, struct usb_interface *pusb
{
struct adapter *padapter = NULL;
struct net_device *pnetdev = NULL;
- struct io_priv *piopriv;
- struct intf_hdl *pintf;
int ret;
padapter = vzalloc(sizeof(*padapter));
@@ -315,16 +298,6 @@ static int rtw_usb_if1_init(struct dvobj_priv *dvobj, struct usb_interface *pusb
SET_NETDEV_DEV(pnetdev, dvobj_to_dev(dvobj));
padapter = rtw_netdev_priv(pnetdev);
- padapter->intf_start = &usb_intf_start;
- padapter->intf_stop = &usb_intf_stop;
-
- /* step init_io_priv */
- piopriv = &padapter->iopriv;
- pintf = &piopriv->intf;
- piopriv->padapter = padapter;
- pintf->padapter = padapter;
- pintf->pintf_dev = adapter_to_dvobj(padapter);
-
/* step read_chip_version */
rtl8188e_read_chip_version(padapter);
diff --git a/drivers/staging/r8188eu/os_dep/usb_ops_linux.c b/drivers/staging/r8188eu/os_dep/usb_ops_linux.c
index 220e592b757c..ca09f7ed7e4d 100644
--- a/drivers/staging/r8188eu/os_dep/usb_ops_linux.c
+++ b/drivers/staging/r8188eu/os_dep/usb_ops_linux.c
@@ -4,7 +4,6 @@
#define _USB_OPS_LINUX_C_
#include "../include/drv_types.h"
-#include "../include/usb_ops_linux.h"
#include "../include/rtl8188e_recv.h"
static unsigned int ffaddr2pipehdl(struct dvobj_priv *pdvobj, u32 addr)
@@ -29,68 +28,40 @@ void rtw_read_port_cancel(struct adapter *padapter)
for (i = 0; i < NR_RECVBUFF; i++) {
precvbuf->reuse = true;
- if (precvbuf->purb)
- usb_kill_urb(precvbuf->purb);
+ usb_kill_urb(precvbuf->purb);
precvbuf++;
}
}
-static void usb_write_port_complete(struct urb *purb, struct pt_regs *regs)
+static void usb_write_port_complete(struct urb *purb)
{
struct xmit_buf *pxmitbuf = (struct xmit_buf *)purb->context;
- struct adapter *padapter = pxmitbuf->padapter;
- struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+ struct adapter *padapter = pxmitbuf->padapter;
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
- switch (pxmitbuf->flags) {
- case VO_QUEUE_INX:
- pxmitpriv->voq_cnt--;
- break;
- case VI_QUEUE_INX:
- pxmitpriv->viq_cnt--;
- break;
- case BE_QUEUE_INX:
- pxmitpriv->beq_cnt--;
- break;
- case BK_QUEUE_INX:
- pxmitpriv->bkq_cnt--;
- break;
- case HIGH_QUEUE_INX:
+ if (pxmitbuf->high_queue)
rtw_chk_hi_queue_cmd(padapter);
+
+ switch (purb->status) {
+ case 0:
+ case -EINPROGRESS:
+ case -ENOENT:
+ case -ECONNRESET:
+ case -EPIPE:
+ case -EPROTO:
+ break;
+ case -ESHUTDOWN:
+ padapter->bDriverStopped = true;
break;
default:
+ padapter->bSurpriseRemoved = true;
break;
}
- if (padapter->bSurpriseRemoved || padapter->bDriverStopped ||
- padapter->bWritePortCancel)
- goto check_completion;
-
- if (purb->status) {
- if (purb->status == -EINPROGRESS) {
- goto check_completion;
- } else if (purb->status == -ENOENT) {
- goto check_completion;
- } else if (purb->status == -ECONNRESET) {
- goto check_completion;
- } else if (purb->status == -ESHUTDOWN) {
- padapter->bDriverStopped = true;
- goto check_completion;
- } else if ((purb->status != -EPIPE) && (purb->status != -EPROTO)) {
- padapter->bSurpriseRemoved = true;
-
- goto check_completion;
- }
- }
-
-check_completion:
rtw_sctx_done_err(&pxmitbuf->sctx,
- purb->status ? RTW_SCTX_DONE_WRITE_PORT_ERR :
- RTW_SCTX_DONE_SUCCESS);
-
+ purb->status ? RTW_SCTX_DONE_WRITE_PORT_ERR : RTW_SCTX_DONE_SUCCESS);
rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
-
tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
-
}
u32 rtw_write_port(struct adapter *padapter, u32 addr, u32 cnt, u8 *wmem)
@@ -112,32 +83,7 @@ u32 rtw_write_port(struct adapter *padapter, u32 addr, u32 cnt, u8 *wmem)
}
spin_lock_irqsave(&pxmitpriv->lock, irqL);
-
- switch (addr) {
- case VO_QUEUE_INX:
- pxmitpriv->voq_cnt++;
- pxmitbuf->flags = VO_QUEUE_INX;
- break;
- case VI_QUEUE_INX:
- pxmitpriv->viq_cnt++;
- pxmitbuf->flags = VI_QUEUE_INX;
- break;
- case BE_QUEUE_INX:
- pxmitpriv->beq_cnt++;
- pxmitbuf->flags = BE_QUEUE_INX;
- break;
- case BK_QUEUE_INX:
- pxmitpriv->bkq_cnt++;
- pxmitbuf->flags = BK_QUEUE_INX;
- break;
- case HIGH_QUEUE_INX:
- pxmitbuf->flags = HIGH_QUEUE_INX;
- break;
- default:
- pxmitbuf->flags = MGT_QUEUE_INX;
- break;
- }
-
+ pxmitbuf->high_queue = (addr == HIGH_QUEUE_INX);
spin_unlock_irqrestore(&pxmitpriv->lock, irqL);
purb = pxmitbuf->pxmit_urb;
@@ -154,14 +100,8 @@ u32 rtw_write_port(struct adapter *padapter, u32 addr, u32 cnt, u8 *wmem)
status = usb_submit_urb(purb, GFP_ATOMIC);
if (status) {
rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_WRITE_PORT_ERR);
-
- switch (status) {
- case -ENODEV:
+ if (status == -ENODEV)
padapter->bDriverStopped = true;
- break;
- default:
- break;
- }
goto exit;
}
@@ -184,15 +124,13 @@ void rtw_write_port_cancel(struct adapter *padapter)
padapter->bWritePortCancel = true;
for (i = 0; i < NR_XMITBUFF; i++) {
- if (pxmitbuf->pxmit_urb)
- usb_kill_urb(pxmitbuf->pxmit_urb);
+ usb_kill_urb(pxmitbuf->pxmit_urb);
pxmitbuf++;
}
pxmitbuf = (struct xmit_buf *)padapter->xmitpriv.pxmit_extbuf;
for (i = 0; i < NR_XMIT_EXTBUFF; i++) {
- if (pxmitbuf->pxmit_urb)
- usb_kill_urb(pxmitbuf->pxmit_urb);
+ usb_kill_urb(pxmitbuf->pxmit_urb);
pxmitbuf++;
}
}
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c
index ab2e9b729883..73a86e1d0701 100644
--- a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c
+++ b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c
@@ -21,7 +21,7 @@ void rtl92e_set_bandwidth(struct net_device *dev,
return;
}
- for (eRFPath = 0; eRFPath < priv->NumTotalRFPath; eRFPath++) {
+ for (eRFPath = 0; eRFPath < priv->num_total_rf_path; eRFPath++) {
if (!rtl92e_is_legal_rf_path(dev, eRFPath))
continue;
@@ -63,14 +63,14 @@ bool rtl92e_config_rf(struct net_device *dev)
u8 ConstRetryTimes = 5, RetryTimes = 5;
u8 ret = 0;
- priv->NumTotalRFPath = RTL819X_TOTAL_RF_PATH;
+ priv->num_total_rf_path = RTL819X_TOTAL_RF_PATH;
for (eRFPath = (enum rf90_radio_path)RF90_PATH_A;
- eRFPath < priv->NumTotalRFPath; eRFPath++) {
+ eRFPath < priv->num_total_rf_path; eRFPath++) {
if (!rtl92e_is_legal_rf_path(dev, eRFPath))
continue;
- pPhyReg = &priv->PHYRegDef[eRFPath];
+ pPhyReg = &priv->phy_reg_def[eRFPath];
switch (eRFPath) {
case RF90_PATH_A:
@@ -150,11 +150,11 @@ void rtl92e_set_cck_tx_power(struct net_device *dev, u8 powerlevel)
struct r8192_priv *priv = rtllib_priv(dev);
TxAGC = powerlevel;
- if (priv->bDynamicTxLowPower) {
- if (priv->CustomerID == RT_CID_819x_Netcore)
+ if (priv->dynamic_tx_low_pwr) {
+ if (priv->customer_id == RT_CID_819X_NETCORE)
TxAGC = 0x22;
else
- TxAGC += priv->CckPwEnl;
+ TxAGC += priv->cck_pwr_enl;
}
if (TxAGC > 0x24)
TxAGC = 0x24;
@@ -169,7 +169,7 @@ void rtl92e_set_ofdm_tx_power(struct net_device *dev, u8 powerlevel)
u16 RegOffset[6] = {0xe00, 0xe04, 0xe10, 0xe14, 0xe18, 0xe1c};
u8 byte0, byte1, byte2, byte3;
- powerBase0 = powerlevel + priv->LegacyHTTxPowerDiff;
+ powerBase0 = powerlevel + priv->legacy_ht_tx_pwr_diff;
powerBase0 = (powerBase0 << 24) | (powerBase0 << 16) |
(powerBase0 << 8) | powerBase0;
powerBase1 = powerlevel;
@@ -177,7 +177,7 @@ void rtl92e_set_ofdm_tx_power(struct net_device *dev, u8 powerlevel)
(powerBase1 << 8) | powerBase1;
for (index = 0; index < 6; index++) {
- writeVal = (u32)(priv->MCSTxPowerLevelOriginalOffset[index] +
+ writeVal = (u32)(priv->mcs_tx_pwr_level_org_offset[index] +
((index < 2) ? powerBase0 : powerBase1));
byte0 = writeVal & 0x7f;
byte1 = (writeVal & 0x7f00) >> 8;
@@ -195,10 +195,10 @@ void rtl92e_set_ofdm_tx_power(struct net_device *dev, u8 powerlevel)
if (index == 3) {
writeVal_tmp = (byte3 << 24) | (byte2 << 16) |
(byte1 << 8) | byte0;
- priv->Pwr_Track = writeVal_tmp;
+ priv->pwr_track = writeVal_tmp;
}
- if (priv->bDynamicTxHighPower)
+ if (priv->dynamic_tx_high_pwr)
writeVal = 0x03030303;
else
writeVal = (byte3 << 24) | (byte2 << 16) |
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c
index 8bf06f736ffb..eba8364d0ff2 100644
--- a/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c
+++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c
@@ -76,7 +76,7 @@ bool rtl92e_send_cmd_pkt(struct net_device *dev, u32 type, const void *data,
} while (frag_offset < len);
- rtl92e_writeb(dev, TPPoll, TPPoll_CQ);
+ rtl92e_writeb(dev, TP_POLL, TP_POLL_CQ);
Failed:
return rt_status;
}
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c
index f02e67f68e23..0b5b2ae27f9e 100644
--- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c
+++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c
@@ -54,22 +54,16 @@ static void _rtl92e_update_msr(struct net_device *dev)
switch (priv->rtllib->iw_mode) {
case IW_MODE_INFRA:
if (priv->rtllib->state == RTLLIB_LINKED)
- msr |= (MSR_LINK_MANAGED << MSR_LINK_SHIFT);
- else
- msr |= (MSR_LINK_NONE << MSR_LINK_SHIFT);
+ msr |= MSR_LINK_MANAGED;
LedAction = LED_CTL_LINK;
break;
case IW_MODE_ADHOC:
if (priv->rtllib->state == RTLLIB_LINKED)
- msr |= (MSR_LINK_ADHOC << MSR_LINK_SHIFT);
- else
- msr |= (MSR_LINK_NONE << MSR_LINK_SHIFT);
+ msr |= MSR_LINK_ADHOC;
break;
case IW_MODE_MASTER:
if (priv->rtllib->state == RTLLIB_LINKED)
- msr |= (MSR_LINK_MASTER << MSR_LINK_SHIFT);
- else
- msr |= (MSR_LINK_NONE << MSR_LINK_SHIFT);
+ msr |= MSR_LINK_MASTER;
break;
default:
break;
@@ -127,7 +121,7 @@ void rtl92e_set_reg(struct net_device *dev, u8 variable, u8 *val)
Type = val[0];
RegRCR = rtl92e_readl(dev, RCR);
- priv->ReceiveConfig = RegRCR;
+ priv->receive_config = RegRCR;
if (Type)
RegRCR |= (RCR_CBSSID);
@@ -135,7 +129,7 @@ void rtl92e_set_reg(struct net_device *dev, u8 variable, u8 *val)
RegRCR &= (~RCR_CBSSID);
rtl92e_writel(dev, RCR, RegRCR);
- priv->ReceiveConfig = RegRCR;
+ priv->receive_config = RegRCR;
}
break;
@@ -222,41 +216,41 @@ void rtl92e_set_reg(struct net_device *dev, u8 variable, u8 *val)
union aci_aifsn *pAciAifsn = (union aci_aifsn *)&
(qos_parameters->aifs[0]);
u8 acm = pAciAifsn->f.acm;
- u8 AcmCtrl = rtl92e_readb(dev, AcmHwCtrl);
+ u8 AcmCtrl = rtl92e_readb(dev, ACM_HW_CTRL);
if (acm) {
switch (eACI) {
case AC0_BE:
- AcmCtrl |= AcmHw_BeqEn;
+ AcmCtrl |= ACM_HW_BEQ_EN;
break;
case AC2_VI:
- AcmCtrl |= AcmHw_ViqEn;
+ AcmCtrl |= ACM_HW_VIQ_EN;
break;
case AC3_VO:
- AcmCtrl |= AcmHw_VoqEn;
+ AcmCtrl |= ACM_HW_VOQ_EN;
break;
}
} else {
switch (eACI) {
case AC0_BE:
- AcmCtrl &= (~AcmHw_BeqEn);
+ AcmCtrl &= (~ACM_HW_BEQ_EN);
break;
case AC2_VI:
- AcmCtrl &= (~AcmHw_ViqEn);
+ AcmCtrl &= (~ACM_HW_VIQ_EN);
break;
case AC3_VO:
- AcmCtrl &= (~AcmHw_BeqEn);
+ AcmCtrl &= (~ACM_HW_BEQ_EN);
break;
default:
break;
}
}
- rtl92e_writeb(dev, AcmHwCtrl, AcmCtrl);
+ rtl92e_writeb(dev, ACM_HW_CTRL, AcmCtrl);
break;
}
@@ -292,21 +286,21 @@ static void _rtl92e_read_eeprom_info(struct net_device *dev)
if (EEPROMId != RTL8190_EEPROM_ID) {
netdev_err(dev, "%s(): Invalid EEPROM ID: %x\n", __func__,
EEPROMId);
- priv->AutoloadFailFlag = true;
+ priv->autoload_fail_flag = true;
} else {
- priv->AutoloadFailFlag = false;
+ priv->autoload_fail_flag = false;
}
- if (!priv->AutoloadFailFlag) {
+ if (!priv->autoload_fail_flag) {
priv->eeprom_vid = rtl92e_eeprom_read(dev, EEPROM_VID >> 1);
priv->eeprom_did = rtl92e_eeprom_read(dev, EEPROM_DID >> 1);
usValue = rtl92e_eeprom_read(dev,
(EEPROM_Customer_ID >> 1)) >> 8;
- priv->eeprom_CustomerID = usValue & 0xff;
+ priv->eeprom_customer_id = usValue & 0xff;
usValue = rtl92e_eeprom_read(dev,
EEPROM_ICVersion_ChannelPlan>>1);
- priv->eeprom_ChannelPlan = usValue&0xff;
+ priv->eeprom_chnl_plan = usValue&0xff;
IC_Version = (usValue & 0xff00)>>8;
ICVer8192 = IC_Version & 0xf;
@@ -327,11 +321,11 @@ static void _rtl92e_read_eeprom_info(struct net_device *dev)
priv->card_8192_version = VERSION_8190_BD;
priv->eeprom_vid = 0;
priv->eeprom_did = 0;
- priv->eeprom_CustomerID = 0;
- priv->eeprom_ChannelPlan = 0;
+ priv->eeprom_customer_id = 0;
+ priv->eeprom_chnl_plan = 0;
}
- if (!priv->AutoloadFailFlag) {
+ if (!priv->autoload_fail_flag) {
u8 addr[ETH_ALEN];
for (i = 0; i < 6; i += 2) {
@@ -345,125 +339,94 @@ static void _rtl92e_read_eeprom_info(struct net_device *dev)
}
if (priv->card_8192_version > VERSION_8190_BD)
- priv->bTXPowerDataReadFromEEPORM = true;
+ priv->tx_pwr_data_read_from_eeprom = true;
else
- priv->bTXPowerDataReadFromEEPORM = false;
+ priv->tx_pwr_data_read_from_eeprom = false;
priv->rf_type = RTL819X_DEFAULT_RF_TYPE;
if (priv->card_8192_version > VERSION_8190_BD) {
- if (!priv->AutoloadFailFlag) {
+ if (!priv->autoload_fail_flag) {
tempval = (rtl92e_eeprom_read(dev,
(EEPROM_RFInd_PowerDiff >> 1))) & 0xff;
- priv->EEPROMLegacyHTTxPowerDiff = tempval & 0xf;
+ priv->eeprom_legacy_ht_tx_pwr_diff = tempval & 0xf;
if (tempval&0x80)
priv->rf_type = RF_1T2R;
else
priv->rf_type = RF_2T4R;
} else {
- priv->EEPROMLegacyHTTxPowerDiff = 0x04;
+ priv->eeprom_legacy_ht_tx_pwr_diff = 0x04;
}
- if (!priv->AutoloadFailFlag)
- priv->EEPROMThermalMeter = ((rtl92e_eeprom_read(dev,
+ if (!priv->autoload_fail_flag)
+ priv->eeprom_thermal_meter = ((rtl92e_eeprom_read(dev,
(EEPROM_ThermalMeter>>1))) &
0xff00) >> 8;
else
- priv->EEPROMThermalMeter = EEPROM_Default_ThermalMeter;
- priv->TSSI_13dBm = priv->EEPROMThermalMeter * 100;
+ priv->eeprom_thermal_meter = EEPROM_Default_ThermalMeter;
+ priv->tssi_13dBm = priv->eeprom_thermal_meter * 100;
if (priv->epromtype == EEPROM_93C46) {
- if (!priv->AutoloadFailFlag) {
+ if (!priv->autoload_fail_flag) {
usValue = rtl92e_eeprom_read(dev,
EEPROM_TxPwDiff_CrystalCap >> 1);
- priv->EEPROMAntPwDiff = usValue & 0x0fff;
- priv->EEPROMCrystalCap = (usValue & 0xf000)
+ priv->eeprom_ant_pwr_diff = usValue & 0x0fff;
+ priv->eeprom_crystal_cap = (usValue & 0xf000)
>> 12;
} else {
- priv->EEPROMAntPwDiff =
+ priv->eeprom_ant_pwr_diff =
EEPROM_Default_AntTxPowerDiff;
- priv->EEPROMCrystalCap =
+ priv->eeprom_crystal_cap =
EEPROM_Default_TxPwDiff_CrystalCap;
}
for (i = 0; i < 14; i += 2) {
- if (!priv->AutoloadFailFlag)
+ if (!priv->autoload_fail_flag)
usValue = rtl92e_eeprom_read(dev,
(EEPROM_TxPwIndex_CCK + i) >> 1);
else
usValue = EEPROM_Default_TxPower;
- *((u16 *)(&priv->EEPROMTxPowerLevelCCK[i])) =
+ *((u16 *)(&priv->eeprom_tx_pwr_level_cck[i])) =
usValue;
}
for (i = 0; i < 14; i += 2) {
- if (!priv->AutoloadFailFlag)
+ if (!priv->autoload_fail_flag)
usValue = rtl92e_eeprom_read(dev,
(EEPROM_TxPwIndex_OFDM_24G + i) >> 1);
else
usValue = EEPROM_Default_TxPower;
- *((u16 *)(&priv->EEPROMTxPowerLevelOFDM24G[i]))
+ *((u16 *)(&priv->eeprom_tx_pwr_level_ofdm24g[i]))
= usValue;
}
}
if (priv->epromtype == EEPROM_93C46) {
for (i = 0; i < 14; i++) {
- priv->TxPowerLevelCCK[i] =
- priv->EEPROMTxPowerLevelCCK[i];
- priv->TxPowerLevelOFDM24G[i] =
- priv->EEPROMTxPowerLevelOFDM24G[i];
+ priv->tx_pwr_level_cck[i] =
+ priv->eeprom_tx_pwr_level_cck[i];
+ priv->tx_pwr_level_ofdm_24g[i] =
+ priv->eeprom_tx_pwr_level_ofdm24g[i];
}
- priv->LegacyHTTxPowerDiff =
- priv->EEPROMLegacyHTTxPowerDiff;
- priv->AntennaTxPwDiff[0] = priv->EEPROMAntPwDiff & 0xf;
- priv->AntennaTxPwDiff[1] = (priv->EEPROMAntPwDiff &
+ priv->legacy_ht_tx_pwr_diff =
+ priv->eeprom_legacy_ht_tx_pwr_diff;
+ priv->antenna_tx_pwr_diff[0] = priv->eeprom_ant_pwr_diff & 0xf;
+ priv->antenna_tx_pwr_diff[1] = (priv->eeprom_ant_pwr_diff &
0xf0) >> 4;
- priv->AntennaTxPwDiff[2] = (priv->EEPROMAntPwDiff &
+ priv->antenna_tx_pwr_diff[2] = (priv->eeprom_ant_pwr_diff &
0xf00) >> 8;
- priv->CrystalCap = priv->EEPROMCrystalCap;
- priv->ThermalMeter[0] = priv->EEPROMThermalMeter & 0xf;
- priv->ThermalMeter[1] = (priv->EEPROMThermalMeter &
+ priv->crystal_cap = priv->eeprom_crystal_cap;
+ priv->thermal_meter[0] = priv->eeprom_thermal_meter & 0xf;
+ priv->thermal_meter[1] = (priv->eeprom_thermal_meter &
0xf0) >> 4;
} else if (priv->epromtype == EEPROM_93C56) {
-
- for (i = 0; i < 3; i++) {
- priv->TxPowerLevelCCK_A[i] =
- priv->EEPROMRfACCKChnl1TxPwLevel[0];
- priv->TxPowerLevelOFDM24G_A[i] =
- priv->EEPROMRfAOfdmChnlTxPwLevel[0];
- priv->TxPowerLevelCCK_C[i] =
- priv->EEPROMRfCCCKChnl1TxPwLevel[0];
- priv->TxPowerLevelOFDM24G_C[i] =
- priv->EEPROMRfCOfdmChnlTxPwLevel[0];
- }
- for (i = 3; i < 9; i++) {
- priv->TxPowerLevelCCK_A[i] =
- priv->EEPROMRfACCKChnl1TxPwLevel[1];
- priv->TxPowerLevelOFDM24G_A[i] =
- priv->EEPROMRfAOfdmChnlTxPwLevel[1];
- priv->TxPowerLevelCCK_C[i] =
- priv->EEPROMRfCCCKChnl1TxPwLevel[1];
- priv->TxPowerLevelOFDM24G_C[i] =
- priv->EEPROMRfCOfdmChnlTxPwLevel[1];
- }
- for (i = 9; i < 14; i++) {
- priv->TxPowerLevelCCK_A[i] =
- priv->EEPROMRfACCKChnl1TxPwLevel[2];
- priv->TxPowerLevelOFDM24G_A[i] =
- priv->EEPROMRfAOfdmChnlTxPwLevel[2];
- priv->TxPowerLevelCCK_C[i] =
- priv->EEPROMRfCCCKChnl1TxPwLevel[2];
- priv->TxPowerLevelOFDM24G_C[i] =
- priv->EEPROMRfCOfdmChnlTxPwLevel[2];
- }
- priv->LegacyHTTxPowerDiff =
- priv->EEPROMLegacyHTTxPowerDiff;
- priv->AntennaTxPwDiff[0] = 0;
- priv->AntennaTxPwDiff[1] = 0;
- priv->AntennaTxPwDiff[2] = 0;
- priv->CrystalCap = priv->EEPROMCrystalCap;
- priv->ThermalMeter[0] = priv->EEPROMThermalMeter & 0xf;
- priv->ThermalMeter[1] = (priv->EEPROMThermalMeter &
+ priv->legacy_ht_tx_pwr_diff =
+ priv->eeprom_legacy_ht_tx_pwr_diff;
+ priv->antenna_tx_pwr_diff[0] = 0;
+ priv->antenna_tx_pwr_diff[1] = 0;
+ priv->antenna_tx_pwr_diff[2] = 0;
+ priv->crystal_cap = priv->eeprom_crystal_cap;
+ priv->thermal_meter[0] = priv->eeprom_thermal_meter & 0xf;
+ priv->thermal_meter[1] = (priv->eeprom_thermal_meter &
0xf0) >> 4;
}
}
@@ -473,41 +436,41 @@ static void _rtl92e_read_eeprom_info(struct net_device *dev)
priv->rf_chip = RF_8256;
if (priv->reg_chnl_plan == 0xf)
- priv->ChannelPlan = priv->eeprom_ChannelPlan;
+ priv->chnl_plan = priv->eeprom_chnl_plan;
else
- priv->ChannelPlan = priv->reg_chnl_plan;
+ priv->chnl_plan = priv->reg_chnl_plan;
if (priv->eeprom_vid == 0x1186 && priv->eeprom_did == 0x3304)
- priv->CustomerID = RT_CID_DLINK;
+ priv->customer_id = RT_CID_DLINK;
- switch (priv->eeprom_CustomerID) {
+ switch (priv->eeprom_customer_id) {
case EEPROM_CID_DEFAULT:
- priv->CustomerID = RT_CID_DEFAULT;
+ priv->customer_id = RT_CID_DEFAULT;
break;
case EEPROM_CID_CAMEO:
- priv->CustomerID = RT_CID_819x_CAMEO;
+ priv->customer_id = RT_CID_819x_CAMEO;
break;
case EEPROM_CID_RUNTOP:
- priv->CustomerID = RT_CID_819x_RUNTOP;
+ priv->customer_id = RT_CID_819x_RUNTOP;
break;
case EEPROM_CID_NetCore:
- priv->CustomerID = RT_CID_819x_Netcore;
+ priv->customer_id = RT_CID_819X_NETCORE;
break;
case EEPROM_CID_TOSHIBA:
- priv->CustomerID = RT_CID_TOSHIBA;
- if (priv->eeprom_ChannelPlan&0x80)
- priv->ChannelPlan = priv->eeprom_ChannelPlan&0x7f;
+ priv->customer_id = RT_CID_TOSHIBA;
+ if (priv->eeprom_chnl_plan & 0x80)
+ priv->chnl_plan = priv->eeprom_chnl_plan & 0x7f;
else
- priv->ChannelPlan = 0x0;
+ priv->chnl_plan = 0x0;
break;
case EEPROM_CID_Nettronix:
- priv->CustomerID = RT_CID_Nettronix;
+ priv->customer_id = RT_CID_Nettronix;
break;
case EEPROM_CID_Pronet:
- priv->CustomerID = RT_CID_PRONET;
+ priv->customer_id = RT_CID_PRONET;
break;
case EEPROM_CID_DLINK:
- priv->CustomerID = RT_CID_DLINK;
+ priv->customer_id = RT_CID_DLINK;
break;
case EEPROM_CID_WHQL:
@@ -516,9 +479,9 @@ static void _rtl92e_read_eeprom_info(struct net_device *dev)
break;
}
- if (priv->ChannelPlan > CHANNEL_PLAN_LEN - 1)
- priv->ChannelPlan = 0;
- priv->ChannelPlan = COUNTRY_CODE_WORLD_WIDE_13;
+ if (priv->chnl_plan > CHANNEL_PLAN_LEN - 1)
+ priv->chnl_plan = 0;
+ priv->chnl_plan = COUNTRY_CODE_WORLD_WIDE_13;
if (priv->eeprom_vid == 0x1186 && priv->eeprom_did == 0x3304)
priv->rtllib->bSupportRemoteWakeUp = true;
@@ -594,8 +557,8 @@ static void _rtl92e_hwconfig(struct net_device *dev)
rtl92e_writel(dev, RRSR, regRRSR);
rtl92e_writew(dev, RETRY_LIMIT,
- priv->ShortRetryLimit << RETRY_LIMIT_SHORT_SHIFT |
- priv->LongRetryLimit << RETRY_LIMIT_LONG_SHIFT);
+ priv->short_retry_limit << RETRY_LIMIT_SHORT_SHIFT |
+ priv->long_retry_limit << RETRY_LIMIT_LONG_SHIFT);
}
bool rtl92e_start_adapter(struct net_device *dev)
@@ -614,21 +577,21 @@ bool rtl92e_start_adapter(struct net_device *dev)
start:
rtl92e_reset_desc_ring(dev);
- priv->Rf_Mode = RF_OP_By_SW_3wire;
+ priv->rf_mode = RF_OP_By_SW_3wire;
if (priv->rst_progress == RESET_TYPE_NORESET) {
rtl92e_writeb(dev, ANAPAR, 0x37);
mdelay(500);
}
- priv->pFirmware->status = FW_STATUS_0_INIT;
+ priv->fw_info->status = FW_STATUS_0_INIT;
ulRegRead = rtl92e_readl(dev, CPU_GEN);
- if (priv->pFirmware->status == FW_STATUS_0_INIT)
+ if (priv->fw_info->status == FW_STATUS_0_INIT)
ulRegRead |= CPU_GEN_SYSTEM_RESET;
- else if (priv->pFirmware->status == FW_STATUS_5_READY)
+ else if (priv->fw_info->status == FW_STATUS_5_READY)
ulRegRead |= CPU_GEN_FIRMWARE_RESET;
else
netdev_err(dev, "%s(): undefined firmware state: %d.\n",
- __func__, priv->pFirmware->status);
+ __func__, priv->fw_info->status);
rtl92e_writel(dev, CPU_GEN, ulRegRead);
@@ -647,13 +610,13 @@ start:
return rtStatus;
}
- priv->LoopbackMode = RTL819X_NO_LOOPBACK;
+ priv->loopback_mode = RTL819X_NO_LOOPBACK;
if (priv->rst_progress == RESET_TYPE_NORESET) {
ulRegRead = rtl92e_readl(dev, CPU_GEN);
- if (priv->LoopbackMode == RTL819X_NO_LOOPBACK)
+ if (priv->loopback_mode == RTL819X_NO_LOOPBACK)
ulRegRead = (ulRegRead & CPU_GEN_NO_LOOPBACK_MSK) |
CPU_GEN_NO_LOOPBACK_SET;
- else if (priv->LoopbackMode == RTL819X_MAC_LOOPBACK)
+ else if (priv->loopback_mode == RTL819X_MAC_LOOPBACK)
ulRegRead |= CPU_CCK_LOOPBACK;
else
netdev_err(dev, "%s: Invalid loopback mode setting.\n",
@@ -666,11 +629,11 @@ start:
_rtl92e_hwconfig(dev);
rtl92e_writeb(dev, CMDR, CR_RE | CR_TE);
- rtl92e_writeb(dev, PCIF, ((MXDMA2_NoLimit<<MXDMA2_RX_SHIFT) |
- (MXDMA2_NoLimit<<MXDMA2_TX_SHIFT)));
+ rtl92e_writeb(dev, PCIF, ((MXDMA2_NO_LIMIT << MXDMA2_RX_SHIFT) |
+ (MXDMA2_NO_LIMIT << MXDMA2_TX_SHIFT)));
rtl92e_writel(dev, MAC0, ((u32 *)dev->dev_addr)[0]);
rtl92e_writew(dev, MAC4, ((u16 *)(dev->dev_addr + 4))[0]);
- rtl92e_writel(dev, RCR, priv->ReceiveConfig);
+ rtl92e_writel(dev, RCR, priv->receive_config);
rtl92e_writel(dev, RQPN1, NUM_OF_PAGE_IN_FW_QUEUE_BK <<
RSVD_FW_QUEUE_PAGE_BK_SHIFT |
@@ -724,7 +687,7 @@ start:
}
tmpvalue = rtl92e_readb(dev, IC_VERRSION);
- priv->IC_Cut = tmpvalue;
+ priv->ic_cut = tmpvalue;
bfirmwareok = rtl92e_init_fw(dev);
if (!bfirmwareok) {
@@ -760,19 +723,19 @@ start:
}
if (priv->rtllib->FwRWRF)
- priv->Rf_Mode = RF_OP_By_FW;
+ priv->rf_mode = RF_OP_By_FW;
else
- priv->Rf_Mode = RF_OP_By_SW_3wire;
+ priv->rf_mode = RF_OP_By_SW_3wire;
if (priv->rst_progress == RESET_TYPE_NORESET) {
rtl92e_dm_init_txpower_tracking(dev);
- if (priv->IC_Cut >= IC_VersionCut_D) {
+ if (priv->ic_cut >= IC_VersionCut_D) {
tmpRegA = rtl92e_get_bb_reg(dev, rOFDM0_XATxIQImbalance,
bMaskDWord);
rtl92e_get_bb_reg(dev, rOFDM0_XCTxIQImbalance, bMaskDWord);
- for (i = 0; i < TxBBGainTableLength; i++) {
+ for (i = 0; i < TX_BB_GAIN_TABLE_LEN; i++) {
if (tmpRegA == dm_tx_bb_gain[i]) {
priv->rfa_txpowertrackingindex = i;
priv->rfa_txpowertrackingindex_real = i;
@@ -785,16 +748,16 @@ start:
TempCCk = rtl92e_get_bb_reg(dev, rCCK0_TxFilter1,
bMaskByte2);
- for (i = 0; i < CCKTxBBGainTableLength; i++) {
+ for (i = 0; i < CCK_TX_BB_GAIN_TABLE_LEN; i++) {
if (TempCCk == dm_cck_tx_bb_gain[i][0]) {
- priv->CCKPresentAttentuation_20Mdefault = i;
+ priv->cck_present_attn_20m_def = i;
break;
}
}
- priv->CCKPresentAttentuation_40Mdefault = 0;
- priv->CCKPresentAttentuation_difference = 0;
+ priv->cck_present_attn_40m_def = 0;
+ priv->cck_present_attn_diff = 0;
priv->cck_present_attn =
- priv->CCKPresentAttentuation_20Mdefault;
+ priv->cck_present_attn_20m_def;
priv->btxpower_tracking = false;
}
}
@@ -860,9 +823,9 @@ void rtl92e_link_change(struct net_device *dev)
if (ieee->intel_promiscuous_md_info.promiscuous_on)
;
else
- priv->ReceiveConfig = reg |= RCR_CBSSID;
+ priv->receive_config = reg |= RCR_CBSSID;
} else
- priv->ReceiveConfig = reg &= ~RCR_CBSSID;
+ priv->receive_config = reg &= ~RCR_CBSSID;
rtl92e_writel(dev, RCR, reg);
}
@@ -874,12 +837,12 @@ void rtl92e_set_monitor_mode(struct net_device *dev, bool bAllowAllDA,
struct r8192_priv *priv = rtllib_priv(dev);
if (bAllowAllDA)
- priv->ReceiveConfig |= RCR_AAP;
+ priv->receive_config |= RCR_AAP;
else
- priv->ReceiveConfig &= ~RCR_AAP;
+ priv->receive_config &= ~RCR_AAP;
if (WriteIntoReg)
- rtl92e_writel(dev, RCR, priv->ReceiveConfig);
+ rtl92e_writel(dev, RCR, priv->receive_config);
}
static u8 _rtl92e_rate_mgn_to_hw(u8 rate)
@@ -1068,13 +1031,13 @@ void rtl92e_fill_tx_desc(struct net_device *dev, struct tx_desc *pdesc,
pTxFwInfo->RtsShort = (pTxFwInfo->RtsHT == 0) ?
(cb_desc->bRTSUseShortPreamble ? 1 : 0) :
(cb_desc->bRTSUseShortGI ? 1 : 0);
- if (priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20_40) {
+ if (priv->current_chnl_bw == HT_CHANNEL_WIDTH_20_40) {
if (cb_desc->bPacketBW) {
pTxFwInfo->TxBandwidth = 1;
pTxFwInfo->TxSubCarrier = 0;
} else {
pTxFwInfo->TxBandwidth = 0;
- pTxFwInfo->TxSubCarrier = priv->nCur40MhzPrimeSC;
+ pTxFwInfo->TxSubCarrier = priv->n_cur_40mhz_prime_sc;
}
} else {
pTxFwInfo->TxBandwidth = 0;
@@ -1327,11 +1290,10 @@ static void _rtl92e_query_rxphystatus(
{
struct phy_sts_ofdm_819xpci *pofdm_buf;
struct phy_sts_cck_819xpci *pcck_buf;
- struct phy_ofdm_rx_status_rxsc_sgien_exintfflag *prxsc;
u8 *prxpkt;
- u8 i, max_spatial_stream, tmp_rxsnr, tmp_rxevm, rxsc_sgien_exflg;
+ u8 i, max_spatial_stream, tmp_rxevm;
s8 rx_pwr[4], rx_pwr_all = 0;
- s8 rx_snrX, rx_evmX;
+ s8 rx_evmX;
u8 evm, pwdb_all;
u32 RSSI, total_rssi = 0;
u8 is_cck_rate = 0;
@@ -1339,8 +1301,6 @@ static void _rtl92e_query_rxphystatus(
static u8 check_reg824;
static u32 reg824_bit9;
- priv->stats.numqry_phystatus++;
-
is_cck_rate = rx_hal_is_cck_rate(pdrvinfo);
memset(precord_stats, 0, sizeof(struct rtllib_rx_stats));
pstats->bPacketMatchBSSID = precord_stats->bPacketMatchBSSID =
@@ -1372,7 +1332,6 @@ static void _rtl92e_query_rxphystatus(
if (is_cck_rate) {
u8 report;
- priv->stats.numqry_phystatusCCK++;
if (!reg824_bit9) {
report = pcck_buf->cck_agc_rpt & 0xc0;
report >>= 6;
@@ -1447,7 +1406,6 @@ static void _rtl92e_query_rxphystatus(
precord_stats->RxMIMOSignalQuality[1] = -1;
}
} else {
- priv->stats.numqry_phystatusHT++;
for (i = RF90_PATH_A; i < RF90_PATH_MAX; i++) {
if (priv->brfpath_rxenable[i])
rf_rx_num++;
@@ -1455,11 +1413,6 @@ static void _rtl92e_query_rxphystatus(
rx_pwr[i] = ((pofdm_buf->trsw_gain_X[i] & 0x3F) *
2) - 110;
- tmp_rxsnr = pofdm_buf->rxsnr_X[i];
- rx_snrX = (s8)(tmp_rxsnr);
- rx_snrX /= 2;
- priv->stats.rxSNRdB[i] = (long)rx_snrX;
-
RSSI = rtl92e_rx_db_to_percent(rx_pwr[i]);
if (priv->brfpath_rxenable[i])
total_rssi += RSSI;
@@ -1499,15 +1452,6 @@ static void _rtl92e_query_rxphystatus(
precord_stats->RxMIMOSignalQuality[i] = evm & 0xff;
}
}
-
-
- rxsc_sgien_exflg = pofdm_buf->rxsc_sgien_exflg;
- prxsc = (struct phy_ofdm_rx_status_rxsc_sgien_exintfflag *)
- &rxsc_sgien_exflg;
- if (pdrvinfo->BW)
- priv->stats.received_bwtype[1+prxsc->rxsc]++;
- else
- priv->stats.received_bwtype[0]++;
}
if (is_cck_rate) {
@@ -1570,7 +1514,6 @@ static void _rtl92e_process_phyinfo(struct r8192_priv *priv, u8 *buffer,
if (!bcheck)
return;
- priv->stats.num_process_phyinfo++;
if (!prev_st->bIsCCK && prev_st->bPacketToSelf) {
for (rfpath = RF90_PATH_A; rfpath < RF90_PATH_C; rfpath++) {
if (!rtl92e_is_legal_rf_path(priv->rtllib->dev, rfpath))
@@ -1605,17 +1548,17 @@ static void _rtl92e_process_phyinfo(struct r8192_priv *priv, u8 *buffer,
PHY_Beacon_RSSI_SLID_WIN_MAX) {
slide_beacon_adc_pwdb_statistics =
PHY_Beacon_RSSI_SLID_WIN_MAX;
- last_beacon_adc_pwdb = priv->stats.Slide_Beacon_pwdb
+ last_beacon_adc_pwdb = priv->stats.slide_beacon_pwdb
[slide_beacon_adc_pwdb_index];
- priv->stats.Slide_Beacon_Total -= last_beacon_adc_pwdb;
+ priv->stats.slide_beacon_total -= last_beacon_adc_pwdb;
}
- priv->stats.Slide_Beacon_Total += prev_st->RxPWDBAll;
- priv->stats.Slide_Beacon_pwdb[slide_beacon_adc_pwdb_index] =
+ priv->stats.slide_beacon_total += prev_st->RxPWDBAll;
+ priv->stats.slide_beacon_pwdb[slide_beacon_adc_pwdb_index] =
prev_st->RxPWDBAll;
slide_beacon_adc_pwdb_index++;
if (slide_beacon_adc_pwdb_index >= PHY_Beacon_RSSI_SLID_WIN_MAX)
slide_beacon_adc_pwdb_index = 0;
- prev_st->RxPWDBAll = priv->stats.Slide_Beacon_Total /
+ prev_st->RxPWDBAll = priv->stats.slide_beacon_total /
slide_beacon_adc_pwdb_statistics;
if (prev_st->RxPWDBAll >= 3)
prev_st->RxPWDBAll -= 3;
@@ -1659,7 +1602,6 @@ static void _rtl92e_process_phyinfo(struct r8192_priv *priv, u8 *buffer,
tmp_val = priv->stats.slide_evm_total /
slide_evm_statistics;
- priv->stats.signal_quality = tmp_val;
priv->stats.last_signal_strength_inpercent = tmp_val;
}
@@ -1716,10 +1658,6 @@ static void _rtl92e_translate_rx_signal_stats(struct net_device *dev,
ether_addr_equal(praddr, priv->rtllib->dev->dev_addr);
if (WLAN_FC_GET_FRAMETYPE(fc) == RTLLIB_STYPE_BEACON)
bPacketBeacon = true;
- if (bpacket_match_bssid)
- priv->stats.numpacket_matchbssid++;
- if (bpacket_toself)
- priv->stats.numpacket_toself++;
_rtl92e_process_phyinfo(priv, tmp_buf, &previous_stats, pstats);
_rtl92e_query_rxphystatus(priv, pstats, pdesc, pdrvinfo,
&previous_stats, bpacket_match_bssid,
@@ -1734,18 +1672,12 @@ static void _rtl92e_update_received_rate_histogram_stats(
struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev);
u32 rcvType = 1;
u32 rateIndex;
- u32 preamble_guardinterval;
if (pstats->bCRC)
rcvType = 2;
else if (pstats->bICV)
rcvType = 3;
- if (pstats->bShortPreamble)
- preamble_guardinterval = 1;
- else
- preamble_guardinterval = 0;
-
switch (pstats->rate) {
case MGN_1M:
rateIndex = 0;
@@ -1835,7 +1767,6 @@ static void _rtl92e_update_received_rate_histogram_stats(
rateIndex = 28;
break;
}
- priv->stats.received_preamble_GI[preamble_guardinterval][rateIndex]++;
priv->stats.received_rate_histogram[0][rateIndex]++;
priv->stats.received_rate_histogram[rcvType][rateIndex]++;
}
@@ -1843,7 +1774,6 @@ static void _rtl92e_update_received_rate_histogram_stats(
bool rtl92e_get_rx_stats(struct net_device *dev, struct rtllib_rx_stats *stats,
struct rx_desc *pdesc, struct sk_buff *skb)
{
- struct r8192_priv *priv = rtllib_priv(dev);
struct rx_fwinfo *pDrvInfo = NULL;
stats->bICV = pdesc->ICV;
@@ -1856,15 +1786,6 @@ bool rtl92e_get_rx_stats(struct net_device *dev, struct rtllib_rx_stats *stats,
if (stats->bHwError) {
stats->bShift = false;
-
- if (pdesc->CRC32) {
- if (pdesc->Length < 500)
- priv->stats.rxcrcerrmin++;
- else if (pdesc->Length > 1000)
- priv->stats.rxcrcerrmax++;
- else
- priv->stats.rxcrcerrmid++;
- }
return false;
}
@@ -1895,7 +1816,7 @@ bool rtl92e_get_rx_stats(struct net_device *dev, struct rtllib_rx_stats *stats,
stats->RxIs40MHzPacket = pDrvInfo->BW;
_rtl92e_translate_rx_signal_stats(dev, skb, stats, pdesc, pDrvInfo);
- skb_trim(skb, skb->len - 4/*sCrcLng*/);
+ skb_trim(skb, skb->len - S_CRC_LEN);
stats->packetlength = stats->Length-4;
@@ -1940,7 +1861,7 @@ void rtl92e_stop_adapter(struct net_device *dev, bool reset)
rtl92e_writeb(dev, PMR, 0x5);
- rtl92e_writeb(dev, MacBlkCtrl, 0xa);
+ rtl92e_writeb(dev, MAC_BLK_CTRL, 0xa);
}
}
@@ -2010,10 +1931,10 @@ rtl92e_init_variables(struct net_device *dev)
priv->rtllib->tx_headroom = sizeof(struct tx_fwinfo_8190pci);
- priv->ShortRetryLimit = 0x30;
- priv->LongRetryLimit = 0x30;
+ priv->short_retry_limit = 0x30;
+ priv->long_retry_limit = 0x30;
- priv->ReceiveConfig = RCR_ADD3 |
+ priv->receive_config = RCR_ADD3 |
RCR_AMF | RCR_ADF |
RCR_AICV |
RCR_AB | RCR_AM | RCR_APM |
@@ -2027,8 +1948,6 @@ rtl92e_init_variables(struct net_device *dev)
IMR_RDU | IMR_RXFOVW | IMR_TXFOVW |
IMR_BcnInt | IMR_TBDOK | IMR_TBDER);
- priv->PwrDomainProtect = false;
-
priv->bfirst_after_down = false;
}
@@ -2098,21 +2017,21 @@ bool rtl92e_is_rx_stuck(struct net_device *dev)
u8 SilentResetRxSoltNum = 4;
rx_chk_cnt++;
- if (priv->undecorated_smoothed_pwdb >= (RateAdaptiveTH_High+5)) {
+ if (priv->undecorated_smoothed_pwdb >= (RATE_ADAPTIVE_TH_HIGH + 5)) {
rx_chk_cnt = 0;
- } else if ((priv->undecorated_smoothed_pwdb < (RateAdaptiveTH_High + 5))
- && (((priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) &&
- (priv->undecorated_smoothed_pwdb >= RateAdaptiveTH_Low_40M))
- || ((priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20) &&
- (priv->undecorated_smoothed_pwdb >= RateAdaptiveTH_Low_20M)))) {
+ } else if ((priv->undecorated_smoothed_pwdb < (RATE_ADAPTIVE_TH_HIGH + 5))
+ && (((priv->current_chnl_bw != HT_CHANNEL_WIDTH_20) &&
+ (priv->undecorated_smoothed_pwdb >= RATE_ADAPTIVE_TH_LOW_40M))
+ || ((priv->current_chnl_bw == HT_CHANNEL_WIDTH_20) &&
+ (priv->undecorated_smoothed_pwdb >= RATE_ADAPTIVE_TH_LOW_20M)))) {
if (rx_chk_cnt < 2)
return bStuck;
rx_chk_cnt = 0;
- } else if ((((priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) &&
- (priv->undecorated_smoothed_pwdb < RateAdaptiveTH_Low_40M)) ||
- ((priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20) &&
- (priv->undecorated_smoothed_pwdb < RateAdaptiveTH_Low_20M))) &&
- priv->undecorated_smoothed_pwdb >= VeryLowRSSI) {
+ } else if ((((priv->current_chnl_bw != HT_CHANNEL_WIDTH_20) &&
+ (priv->undecorated_smoothed_pwdb < RATE_ADAPTIVE_TH_LOW_40M)) ||
+ ((priv->current_chnl_bw == HT_CHANNEL_WIDTH_20) &&
+ (priv->undecorated_smoothed_pwdb < RATE_ADAPTIVE_TH_LOW_20M))) &&
+ priv->undecorated_smoothed_pwdb >= VERY_LOW_RSSI) {
if (rx_chk_cnt < 4)
return bStuck;
rx_chk_cnt = 0;
@@ -2123,24 +2042,24 @@ bool rtl92e_is_rx_stuck(struct net_device *dev)
}
- SlotIndex = (priv->SilentResetRxSlotIndex++)%SilentResetRxSoltNum;
+ SlotIndex = (priv->silent_reset_rx_slot_index++)%SilentResetRxSoltNum;
if (priv->rx_ctr == RegRxCounter) {
- priv->SilentResetRxStuckEvent[SlotIndex] = 1;
+ priv->silent_reset_rx_stuck_event[SlotIndex] = 1;
for (i = 0; i < SilentResetRxSoltNum; i++)
- TotalRxStuckCount += priv->SilentResetRxStuckEvent[i];
+ TotalRxStuckCount += priv->silent_reset_rx_stuck_event[i];
if (TotalRxStuckCount == SilentResetRxSoltNum) {
bStuck = true;
for (i = 0; i < SilentResetRxSoltNum; i++)
TotalRxStuckCount +=
- priv->SilentResetRxStuckEvent[i];
+ priv->silent_reset_rx_stuck_event[i];
}
} else {
- priv->SilentResetRxStuckEvent[SlotIndex] = 0;
+ priv->silent_reset_rx_stuck_event[SlotIndex] = 0;
}
priv->rx_ctr = RegRxCounter;
@@ -2154,10 +2073,10 @@ bool rtl92e_is_tx_stuck(struct net_device *dev)
bool bStuck = false;
u16 RegTxCounter = rtl92e_readw(dev, 0x128);
- if (priv->TxCounter == RegTxCounter)
+ if (priv->tx_counter == RegTxCounter)
bStuck = true;
- priv->TxCounter = RegTxCounter;
+ priv->tx_counter = RegTxCounter;
return bStuck;
}
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c
index 789d288d7503..b011ec8c8a41 100644
--- a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c
+++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c
@@ -51,7 +51,7 @@ static bool _rtl92e_fw_check_ready(struct net_device *dev,
u8 load_fw_status)
{
struct r8192_priv *priv = rtllib_priv(dev);
- struct rt_firmware *pfirmware = priv->pFirmware;
+ struct rt_firmware *pfirmware = priv->fw_info;
bool rt_status = true;
switch (load_fw_status) {
@@ -134,7 +134,7 @@ bool rtl92e_init_fw(struct net_device *dev)
enum opt_rst_type rst_opt = OPT_SYSTEM_RESET;
enum firmware_init_step starting_state = FW_INIT_STEP0_BOOT;
- struct rt_firmware *pfirmware = priv->pFirmware;
+ struct rt_firmware *pfirmware = priv->fw_info;
netdev_dbg(dev, " PlatformInitFirmware()==>\n");
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_hw.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_hw.h
index 3e223151d4b7..99640c4779f7 100644
--- a/drivers/staging/rtl8192e/rtl8192e/r8192E_hw.h
+++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_hw.h
@@ -8,141 +8,72 @@
#define R8180_HW
enum baseband_config {
- BaseBand_Config_PHY_REG = 0,
- BaseBand_Config_AGC_TAB = 1,
+ BB_CONFIG_PHY_REG = 0,
+ BB_CONFIG_AGC_TAB = 1,
};
-#define RTL8187_REQT_READ 0xc0
-#define RTL8187_REQT_WRITE 0x40
-#define RTL8187_REQ_GET_REGS 0x05
-#define RTL8187_REQ_SET_REGS 0x05
-
-#define MAX_TX_URB 5
-#define MAX_RX_URB 16
-#define RX_URB_SIZE 9100
-
-#define BB_ANTATTEN_CHAN14 0x0c
-#define BB_ANTENNA_B 0x40
-
-#define BB_HOST_BANG (1<<30)
-#define BB_HOST_BANG_EN (1<<2)
-#define BB_HOST_BANG_CLK (1<<1)
-#define BB_HOST_BANG_RW (1<<3)
-#define BB_HOST_BANG_DATA 1
-
#define RTL8190_EEPROM_ID 0x8129
#define EEPROM_VID 0x02
#define EEPROM_DID 0x04
#define EEPROM_NODE_ADDRESS_BYTE_0 0x0C
-#define EEPROM_TxPowerDiff 0x1F
-
-
-#define EEPROM_PwDiff 0x21
-#define EEPROM_CrystalCap 0x22
-
-
-
-#define EEPROM_TxPwIndex_CCK_V1 0x29
-#define EEPROM_TxPwIndex_OFDM_24G_V1 0x2C
-#define EEPROM_TxPwIndex_Ver 0x27
-
-#define EEPROM_Default_TxPowerDiff 0x0
#define EEPROM_Default_ThermalMeter 0x77
#define EEPROM_Default_AntTxPowerDiff 0x0
#define EEPROM_Default_TxPwDiff_CrystalCap 0x5
-#define EEPROM_Default_PwDiff 0x4
-#define EEPROM_Default_CrystalCap 0x5
#define EEPROM_Default_TxPower 0x1010
#define EEPROM_ICVersion_ChannelPlan 0x7C
#define EEPROM_Customer_ID 0x7B
#define EEPROM_RFInd_PowerDiff 0x28
+
#define EEPROM_ThermalMeter 0x29
#define EEPROM_TxPwDiff_CrystalCap 0x2A
#define EEPROM_TxPwIndex_CCK 0x2C
#define EEPROM_TxPwIndex_OFDM_24G 0x3A
-#define EEPROM_Default_TxPowerLevel 0x10
-#define EEPROM_IC_VER 0x7d
-#define EEPROM_CRC 0x7e
#define EEPROM_CID_DEFAULT 0x0
#define EEPROM_CID_CAMEO 0x1
#define EEPROM_CID_RUNTOP 0x2
-#define EEPROM_CID_Senao 0x3
#define EEPROM_CID_TOSHIBA 0x4
#define EEPROM_CID_NetCore 0x5
#define EEPROM_CID_Nettronix 0x6
#define EEPROM_CID_Pronet 0x7
#define EEPROM_CID_DLINK 0x8
#define EEPROM_CID_WHQL 0xFE
-enum _RTL8192Pci_HW {
+enum _RTL8192PCI_HW {
MAC0 = 0x000,
- MAC1 = 0x001,
- MAC2 = 0x002,
- MAC3 = 0x003,
MAC4 = 0x004,
- MAC5 = 0x005,
PCIF = 0x009,
-#define MXDMA2_16bytes 0x000
-#define MXDMA2_32bytes 0x001
-#define MXDMA2_64bytes 0x010
-#define MXDMA2_128bytes 0x011
-#define MXDMA2_256bytes 0x100
-#define MXDMA2_512bytes 0x101
-#define MXDMA2_1024bytes 0x110
-#define MXDMA2_NoLimit 0x7
+#define MXDMA2_NO_LIMIT 0x7
-#define MULRW_SHIFT 3
#define MXDMA2_RX_SHIFT 4
#define MXDMA2_TX_SHIFT 0
PMR = 0x00c,
EPROM_CMD = 0x00e,
-#define EPROM_CMD_RESERVED_MASK BIT5
+
#define EPROM_CMD_9356SEL BIT4
#define EPROM_CMD_OPERATING_MODE_SHIFT 6
-#define EPROM_CMD_OPERATING_MODE_MASK ((1<<7)|(1<<6))
-#define EPROM_CMD_CONFIG 0x3
#define EPROM_CMD_NORMAL 0
-#define EPROM_CMD_LOAD 1
#define EPROM_CMD_PROGRAM 2
#define EPROM_CS_BIT 3
#define EPROM_CK_BIT 2
#define EPROM_W_BIT 1
#define EPROM_R_BIT 0
- AFR = 0x010,
-#define AFR_CardBEn (1<<0)
-#define AFR_CLKRUN_SEL (1<<1)
-#define AFR_FuncRegEn (1<<2)
-
ANAPAR = 0x17,
#define BB_GLOBAL_RESET_BIT 0x1
BB_GLOBAL_RESET = 0x020,
BSSIDR = 0x02E,
CMDR = 0x037,
-#define CR_RST 0x10
#define CR_RE 0x08
#define CR_TE 0x04
-#define CR_MulRW 0x01
SIFS = 0x03E,
- TCR = 0x040,
RCR = 0x044,
-#define RCR_FILTER_MASK (BIT0 | BIT1 | BIT2 | BIT3 | BIT5 | BIT12 | \
- BIT18 | BIT19 | BIT20 | BIT21 | BIT22 | BIT23)
#define RCR_ONLYERLPKT BIT31
-#define RCR_ENCS2 BIT30
-#define RCR_ENCS1 BIT29
-#define RCR_ENMBID BIT27
-#define RCR_ACKTXBW (BIT24|BIT25)
#define RCR_CBSSID BIT23
-#define RCR_APWRMGT BIT22
#define RCR_ADD3 BIT21
#define RCR_AMF BIT20
-#define RCR_ACF BIT19
#define RCR_ADF BIT18
-#define RCR_RXFTH BIT13
#define RCR_AICV BIT12
-#define RCR_ACRC32 BIT5
#define RCR_AB BIT3
#define RCR_AM BIT2
#define RCR_APM BIT1
@@ -151,8 +82,6 @@ enum _RTL8192Pci_HW {
#define RCR_FIFO_OFFSET 13
SLOT_TIME = 0x049,
ACK_TIMEOUT = 0x04c,
- PIFS_TIME = 0x04d,
- USTIME = 0x04e,
EDCAPARA_BE = 0x050,
EDCAPARA_BK = 0x054,
EDCAPARA_VO = 0x058,
@@ -161,53 +90,25 @@ enum _RTL8192Pci_HW {
#define AC_PARAM_ECW_MAX_OFFSET 12
#define AC_PARAM_ECW_MIN_OFFSET 8
#define AC_PARAM_AIFS_OFFSET 0
- RFPC = 0x05F,
- CWRR = 0x060,
BCN_TCFG = 0x062,
#define BCN_TCFG_CW_SHIFT 8
#define BCN_TCFG_IFS 0
BCN_INTERVAL = 0x070,
ATIMWND = 0x072,
BCN_DRV_EARLY_INT = 0x074,
-#define BCN_DRV_EARLY_INT_SWBCN_SHIFT 8
-#define BCN_DRV_EARLY_INT_TIME_SHIFT 0
BCN_DMATIME = 0x076,
BCN_ERR_THRESH = 0x078,
RWCAM = 0x0A0,
-#define CAM_CM_SecCAMPolling BIT31
-#define CAM_CM_SecCAMClr BIT30
-#define CAM_CM_SecCAMWE BIT16
-#define CAM_VALID BIT15
-#define CAM_NOTVALID 0x0000
-#define CAM_USEDK BIT5
-
-#define CAM_NONE 0x0
-#define CAM_WEP40 0x01
-#define CAM_TKIP 0x02
-#define CAM_AES 0x04
-#define CAM_WEP104 0x05
-
#define TOTAL_CAM_ENTRY 32
-
-#define CAM_CONFIG_USEDK true
-#define CAM_CONFIG_NO_USEDK false
-#define CAM_WRITE BIT16
-#define CAM_READ 0x00000000
-#define CAM_POLLINIG BIT31
-#define SCR_UseDK 0x01
WCAMI = 0x0A4,
- RCAMO = 0x0A8,
SECR = 0x0B0,
#define SCR_TxUseDK BIT0
#define SCR_RxUseDK BIT1
#define SCR_TxEncEnable BIT2
#define SCR_RxDecEnable BIT3
-#define SCR_SKByA2 BIT4
#define SCR_NoSKMC BIT5
SWREGULATOR = 0x0BD,
INTA_MASK = 0x0f4,
-#define IMR8190_DISABLED 0x0
-#define IMR_ATIMEND BIT28
#define IMR_TBDOK BIT27
#define IMR_TBDER BIT26
#define IMR_TXFOVW BIT15
@@ -227,30 +128,10 @@ enum _RTL8192Pci_HW {
#define IMR_VODOK BIT1
#define IMR_ROK BIT0
ISR = 0x0f8,
- TPPoll = 0x0fd,
-#define TPPoll_BKQ BIT0
-#define TPPoll_BEQ BIT1
-#define TPPoll_VIQ BIT2
-#define TPPoll_VOQ BIT3
-#define TPPoll_BQ BIT4
-#define TPPoll_CQ BIT5
-#define TPPoll_MQ BIT6
-#define TPPoll_HQ BIT7
-#define TPPoll_HCCAQ BIT8
-#define TPPoll_StopBK BIT9
-#define TPPoll_StopBE BIT10
-#define TPPoll_StopVI BIT11
-#define TPPoll_StopVO BIT12
-#define TPPoll_StopMgt BIT13
-#define TPPoll_StopHigh BIT14
-#define TPPoll_StopHCCA BIT15
-#define TPPoll_SHIFT 8
-
+ TP_POLL = 0x0fd,
+#define TP_POLL_CQ BIT5
PSR = 0x0ff,
-#define PSR_GEN 0x0
-#define PSR_CPU 0x1
CPU_GEN = 0x100,
- BB_RESET = 0x101,
#define CPU_CCK_LOOPBACK 0x00030000
#define CPU_GEN_SYSTEM_RESET 0x00000001
#define CPU_GEN_FIRMWARE_RESET 0x00000008
@@ -261,31 +142,13 @@ enum _RTL8192Pci_HW {
#define CPU_GEN_PWR_STB_CPU 0x00000004
#define CPU_GEN_NO_LOOPBACK_MSK 0xFFF8FFFF
#define CPU_GEN_NO_LOOPBACK_SET 0x00080000
-#define CPU_GEN_GPIO_UART 0x00007000
-
- LED1Cfg = 0x154,
- LED0Cfg = 0x155,
-
- AcmAvg = 0x170,
- AcmHwCtrl = 0x171,
-#define AcmHw_HwEn BIT0
-#define AcmHw_BeqEn BIT1
-#define AcmHw_ViqEn BIT2
-#define AcmHw_VoqEn BIT3
-#define AcmHw_BeqStatus BIT4
-#define AcmHw_ViqStatus BIT5
-#define AcmHw_VoqStatus BIT6
- AcmFwCtrl = 0x172,
-#define AcmFw_BeqStatus BIT0
-#define AcmFw_ViqStatus BIT1
-#define AcmFw_VoqStatus BIT2
- VOAdmTime = 0x174,
- VIAdmTime = 0x178,
- BEAdmTime = 0x17C,
+ ACM_HW_CTRL = 0x171,
+#define ACM_HW_BEQ_EN BIT1
+#define ACM_HW_VIQ_EN BIT2
+#define ACM_HW_VOQ_EN BIT3
RQPN1 = 0x180,
RQPN2 = 0x184,
RQPN3 = 0x188,
- QPRR = 0x1E0,
QPNR = 0x1F0,
BQDA = 0x200,
HQDA = 0x204,
@@ -296,51 +159,21 @@ enum _RTL8192Pci_HW {
VIQDA = 0x218,
BEQDA = 0x21C,
BKQDA = 0x220,
- RCQDA = 0x224,
RDQDA = 0x228,
- MAR0 = 0x240,
- MAR4 = 0x244,
-
- CCX_PERIOD = 0x250,
- CLM_RESULT = 0x251,
- NHM_PERIOD = 0x252,
-
- NHM_THRESHOLD0 = 0x253,
- NHM_THRESHOLD1 = 0x254,
- NHM_THRESHOLD2 = 0x255,
- NHM_THRESHOLD3 = 0x256,
- NHM_THRESHOLD4 = 0x257,
- NHM_THRESHOLD5 = 0x258,
- NHM_THRESHOLD6 = 0x259,
-
- MCTRL = 0x25A,
-
- NHM_RPI_COUNTER0 = 0x264,
- NHM_RPI_COUNTER1 = 0x265,
- NHM_RPI_COUNTER2 = 0x266,
- NHM_RPI_COUNTER3 = 0x267,
- NHM_RPI_COUNTER4 = 0x268,
- NHM_RPI_COUNTER5 = 0x269,
- NHM_RPI_COUNTER6 = 0x26A,
- NHM_RPI_COUNTER7 = 0x26B,
WFCRC0 = 0x2f0,
WFCRC1 = 0x2f4,
WFCRC2 = 0x2f8,
BW_OPMODE = 0x300,
-#define BW_OPMODE_11J BIT0
#define BW_OPMODE_5G BIT1
#define BW_OPMODE_20MHZ BIT2
IC_VERRSION = 0x301,
MSR = 0x303,
-#define MSR_LINK_MASK ((1<<0)|(1<<1))
+#define MSR_LINK_MASK (BIT(1) | BIT(0))
#define MSR_LINK_MANAGED 2
-#define MSR_LINK_NONE 0
-#define MSR_LINK_SHIFT 0
#define MSR_LINK_ADHOC 1
#define MSR_LINK_MASTER 3
-#define MSR_LINK_ENEDCA (1<<4)
#define MSR_NOLINK 0x00
#define MSR_ADHOC 0x01
@@ -352,12 +185,7 @@ enum _RTL8192Pci_HW {
#define RETRY_LIMIT_LONG_SHIFT 0
TSFR = 0x308,
RRSR = 0x310,
-#define RRSR_RSC_OFFSET 21
#define RRSR_SHORT_OFFSET 23
-#define RRSR_RSC_DUPLICATE 0x600000
-#define RRSR_RSC_UPSUBCHNL 0x400000
-#define RRSR_RSC_LOWSUBCHNL 0x200000
-#define RRSR_SHORT 0x800000
#define RRSR_1M BIT0
#define RRSR_2M BIT1
#define RRSR_5_5M BIT2
@@ -370,14 +198,6 @@ enum _RTL8192Pci_HW {
#define RRSR_36M BIT9
#define RRSR_48M BIT10
#define RRSR_54M BIT11
-#define RRSR_MCS0 BIT12
-#define RRSR_MCS1 BIT13
-#define RRSR_MCS2 BIT14
-#define RRSR_MCS3 BIT15
-#define RRSR_MCS4 BIT16
-#define RRSR_MCS5 BIT17
-#define RRSR_MCS6 BIT18
-#define RRSR_MCS7 BIT19
#define BRSR_AckShortPmb BIT23
UFWP = 0x318,
RATR0 = 0x320,
@@ -419,21 +239,14 @@ enum _RTL8192Pci_HW {
RATR_MCS11 | RATR_MCS12 | RATR_MCS13 | \
RATR_MCS14|RATR_MCS15)
-
DRIVER_RSSI = 0x32c,
MCS_TXAGC = 0x340,
CCK_TXAGC = 0x348,
- MacBlkCtrl = 0x403,
-
-}
-;
+ MAC_BLK_CTRL = 0x403,
+};
#define GPI 0x108
-#define GPO 0x109
-#define GPE 0x10a
-
-#define HWSET_MAX_SIZE_92S 128
-#define ANAPAR_FOR_8192PciE 0x17
+#define ANAPAR_FOR_8192PCIE 0x17
#endif
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c
index a813eded4cb3..c6cbdea6d5b2 100644
--- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c
+++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c
@@ -94,24 +94,24 @@ static u32 _rtl92e_phy_rf_read(struct net_device *dev,
struct r8192_priv *priv = rtllib_priv(dev);
u32 ret = 0;
u32 NewOffset = 0;
- struct bb_reg_definition *pPhyReg = &priv->PHYRegDef[eRFPath];
+ struct bb_reg_definition *pPhyReg = &priv->phy_reg_def[eRFPath];
Offset &= 0x3f;
if (priv->rf_chip == RF_8256) {
rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter4, 0xf00, 0x0);
if (Offset >= 31) {
- priv->RfReg0Value[eRFPath] |= 0x140;
+ priv->rf_reg_0value[eRFPath] |= 0x140;
rtl92e_set_bb_reg(dev, pPhyReg->rf3wireOffset,
bMaskDWord,
- (priv->RfReg0Value[eRFPath]<<16));
+ (priv->rf_reg_0value[eRFPath] << 16));
NewOffset = Offset - 30;
} else if (Offset >= 16) {
- priv->RfReg0Value[eRFPath] |= 0x100;
- priv->RfReg0Value[eRFPath] &= (~0x40);
+ priv->rf_reg_0value[eRFPath] |= 0x100;
+ priv->rf_reg_0value[eRFPath] &= (~0x40);
rtl92e_set_bb_reg(dev, pPhyReg->rf3wireOffset,
bMaskDWord,
- (priv->RfReg0Value[eRFPath]<<16));
+ (priv->rf_reg_0value[eRFPath] << 16));
NewOffset = Offset - 15;
} else
@@ -130,10 +130,10 @@ static u32 _rtl92e_phy_rf_read(struct net_device *dev,
bLSSIReadBackData);
if (priv->rf_chip == RF_8256) {
- priv->RfReg0Value[eRFPath] &= 0xebf;
+ priv->rf_reg_0value[eRFPath] &= 0xebf;
rtl92e_set_bb_reg(dev, pPhyReg->rf3wireOffset, bMaskDWord,
- (priv->RfReg0Value[eRFPath] << 16));
+ (priv->rf_reg_0value[eRFPath] << 16));
rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter4, 0x300, 0x3);
}
@@ -149,24 +149,24 @@ static void _rtl92e_phy_rf_write(struct net_device *dev,
{
struct r8192_priv *priv = rtllib_priv(dev);
u32 DataAndAddr = 0, NewOffset = 0;
- struct bb_reg_definition *pPhyReg = &priv->PHYRegDef[eRFPath];
+ struct bb_reg_definition *pPhyReg = &priv->phy_reg_def[eRFPath];
Offset &= 0x3f;
if (priv->rf_chip == RF_8256) {
rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter4, 0xf00, 0x0);
if (Offset >= 31) {
- priv->RfReg0Value[eRFPath] |= 0x140;
+ priv->rf_reg_0value[eRFPath] |= 0x140;
rtl92e_set_bb_reg(dev, pPhyReg->rf3wireOffset,
bMaskDWord,
- (priv->RfReg0Value[eRFPath] << 16));
+ (priv->rf_reg_0value[eRFPath] << 16));
NewOffset = Offset - 30;
} else if (Offset >= 16) {
- priv->RfReg0Value[eRFPath] |= 0x100;
- priv->RfReg0Value[eRFPath] &= (~0x40);
+ priv->rf_reg_0value[eRFPath] |= 0x100;
+ priv->rf_reg_0value[eRFPath] &= (~0x40);
rtl92e_set_bb_reg(dev, pPhyReg->rf3wireOffset,
bMaskDWord,
- (priv->RfReg0Value[eRFPath] << 16));
+ (priv->rf_reg_0value[eRFPath] << 16));
NewOffset = Offset - 15;
} else
NewOffset = Offset;
@@ -179,14 +179,14 @@ static void _rtl92e_phy_rf_write(struct net_device *dev,
rtl92e_set_bb_reg(dev, pPhyReg->rf3wireOffset, bMaskDWord, DataAndAddr);
if (Offset == 0x0)
- priv->RfReg0Value[eRFPath] = Data;
+ priv->rf_reg_0value[eRFPath] = Data;
if (priv->rf_chip == RF_8256) {
if (Offset != 0) {
- priv->RfReg0Value[eRFPath] &= 0xebf;
+ priv->rf_reg_0value[eRFPath] &= 0xebf;
rtl92e_set_bb_reg(dev, pPhyReg->rf3wireOffset,
bMaskDWord,
- (priv->RfReg0Value[eRFPath] << 16));
+ (priv->rf_reg_0value[eRFPath] << 16));
}
rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter4, 0x300, 0x3);
}
@@ -203,7 +203,7 @@ void rtl92e_set_rf_reg(struct net_device *dev, enum rf90_radio_path eRFPath,
if (priv->rtllib->rf_power_state != rf_on && !priv->being_init_adapter)
return;
- if (priv->Rf_Mode == RF_OP_By_FW) {
+ if (priv->rf_mode == RF_OP_By_FW) {
if (BitMask != bMask12Bits) {
Original_Value = _rtl92e_phy_rf_fw_read(dev, eRFPath,
RegAddr);
@@ -240,7 +240,7 @@ u32 rtl92e_get_rf_reg(struct net_device *dev, enum rf90_radio_path eRFPath,
if (priv->rtllib->rf_power_state != rf_on && !priv->being_init_adapter)
return 0;
mutex_lock(&priv->rf_mutex);
- if (priv->Rf_Mode == RF_OP_By_FW) {
+ if (priv->rf_mode == RF_OP_By_FW) {
Original_Value = _rtl92e_phy_rf_fw_read(dev, eRFPath, RegAddr);
udelay(200);
} else {
@@ -306,7 +306,7 @@ void rtl92e_config_mac(struct net_device *dev)
u32 *pdwArray = NULL;
struct r8192_priv *priv = rtllib_priv(dev);
- if (priv->bTXPowerDataReadFromEEPORM) {
+ if (priv->tx_pwr_data_read_from_eeprom) {
dwArrayLen = MACPHY_Array_PGLength;
pdwArray = Rtl819XMACPHY_Array_PG;
@@ -342,13 +342,13 @@ static void _rtl92e_phy_config_bb(struct net_device *dev, u8 ConfigType)
Rtl819XPHY_REGArray_Table = Rtl819XPHY_REG_1T2RArray;
}
- if (ConfigType == BaseBand_Config_PHY_REG) {
+ if (ConfigType == BB_CONFIG_PHY_REG) {
for (i = 0; i < PHY_REGArrayLen; i += 2) {
rtl92e_set_bb_reg(dev, Rtl819XPHY_REGArray_Table[i],
bMaskDWord,
Rtl819XPHY_REGArray_Table[i+1]);
}
- } else if (ConfigType == BaseBand_Config_AGC_TAB) {
+ } else if (ConfigType == BB_CONFIG_AGC_TAB) {
for (i = 0; i < AGCTAB_ArrayLen; i += 2) {
rtl92e_set_bb_reg(dev, Rtl819XAGCTAB_Array_Table[i],
bMaskDWord,
@@ -361,90 +361,90 @@ static void _rtl92e_init_bb_rf_reg_def(struct net_device *dev)
{
struct r8192_priv *priv = rtllib_priv(dev);
- priv->PHYRegDef[RF90_PATH_A].rfintfs = rFPGA0_XAB_RFInterfaceSW;
- priv->PHYRegDef[RF90_PATH_B].rfintfs = rFPGA0_XAB_RFInterfaceSW;
- priv->PHYRegDef[RF90_PATH_C].rfintfs = rFPGA0_XCD_RFInterfaceSW;
- priv->PHYRegDef[RF90_PATH_D].rfintfs = rFPGA0_XCD_RFInterfaceSW;
-
- priv->PHYRegDef[RF90_PATH_A].rfintfi = rFPGA0_XAB_RFInterfaceRB;
- priv->PHYRegDef[RF90_PATH_B].rfintfi = rFPGA0_XAB_RFInterfaceRB;
- priv->PHYRegDef[RF90_PATH_C].rfintfi = rFPGA0_XCD_RFInterfaceRB;
- priv->PHYRegDef[RF90_PATH_D].rfintfi = rFPGA0_XCD_RFInterfaceRB;
-
- priv->PHYRegDef[RF90_PATH_A].rfintfo = rFPGA0_XA_RFInterfaceOE;
- priv->PHYRegDef[RF90_PATH_B].rfintfo = rFPGA0_XB_RFInterfaceOE;
- priv->PHYRegDef[RF90_PATH_C].rfintfo = rFPGA0_XC_RFInterfaceOE;
- priv->PHYRegDef[RF90_PATH_D].rfintfo = rFPGA0_XD_RFInterfaceOE;
-
- priv->PHYRegDef[RF90_PATH_A].rfintfe = rFPGA0_XA_RFInterfaceOE;
- priv->PHYRegDef[RF90_PATH_B].rfintfe = rFPGA0_XB_RFInterfaceOE;
- priv->PHYRegDef[RF90_PATH_C].rfintfe = rFPGA0_XC_RFInterfaceOE;
- priv->PHYRegDef[RF90_PATH_D].rfintfe = rFPGA0_XD_RFInterfaceOE;
-
- priv->PHYRegDef[RF90_PATH_A].rf3wireOffset = rFPGA0_XA_LSSIParameter;
- priv->PHYRegDef[RF90_PATH_B].rf3wireOffset = rFPGA0_XB_LSSIParameter;
- priv->PHYRegDef[RF90_PATH_C].rf3wireOffset = rFPGA0_XC_LSSIParameter;
- priv->PHYRegDef[RF90_PATH_D].rf3wireOffset = rFPGA0_XD_LSSIParameter;
-
- priv->PHYRegDef[RF90_PATH_A].rfLSSI_Select = rFPGA0_XAB_RFParameter;
- priv->PHYRegDef[RF90_PATH_B].rfLSSI_Select = rFPGA0_XAB_RFParameter;
- priv->PHYRegDef[RF90_PATH_C].rfLSSI_Select = rFPGA0_XCD_RFParameter;
- priv->PHYRegDef[RF90_PATH_D].rfLSSI_Select = rFPGA0_XCD_RFParameter;
-
- priv->PHYRegDef[RF90_PATH_A].rfTxGainStage = rFPGA0_TxGainStage;
- priv->PHYRegDef[RF90_PATH_B].rfTxGainStage = rFPGA0_TxGainStage;
- priv->PHYRegDef[RF90_PATH_C].rfTxGainStage = rFPGA0_TxGainStage;
- priv->PHYRegDef[RF90_PATH_D].rfTxGainStage = rFPGA0_TxGainStage;
-
- priv->PHYRegDef[RF90_PATH_A].rfHSSIPara1 = rFPGA0_XA_HSSIParameter1;
- priv->PHYRegDef[RF90_PATH_B].rfHSSIPara1 = rFPGA0_XB_HSSIParameter1;
- priv->PHYRegDef[RF90_PATH_C].rfHSSIPara1 = rFPGA0_XC_HSSIParameter1;
- priv->PHYRegDef[RF90_PATH_D].rfHSSIPara1 = rFPGA0_XD_HSSIParameter1;
-
- priv->PHYRegDef[RF90_PATH_A].rfHSSIPara2 = rFPGA0_XA_HSSIParameter2;
- priv->PHYRegDef[RF90_PATH_B].rfHSSIPara2 = rFPGA0_XB_HSSIParameter2;
- priv->PHYRegDef[RF90_PATH_C].rfHSSIPara2 = rFPGA0_XC_HSSIParameter2;
- priv->PHYRegDef[RF90_PATH_D].rfHSSIPara2 = rFPGA0_XD_HSSIParameter2;
-
- priv->PHYRegDef[RF90_PATH_A].rfSwitchControl = rFPGA0_XAB_SwitchControl;
- priv->PHYRegDef[RF90_PATH_B].rfSwitchControl = rFPGA0_XAB_SwitchControl;
- priv->PHYRegDef[RF90_PATH_C].rfSwitchControl = rFPGA0_XCD_SwitchControl;
- priv->PHYRegDef[RF90_PATH_D].rfSwitchControl = rFPGA0_XCD_SwitchControl;
-
- priv->PHYRegDef[RF90_PATH_A].rfAGCControl1 = rOFDM0_XAAGCCore1;
- priv->PHYRegDef[RF90_PATH_B].rfAGCControl1 = rOFDM0_XBAGCCore1;
- priv->PHYRegDef[RF90_PATH_C].rfAGCControl1 = rOFDM0_XCAGCCore1;
- priv->PHYRegDef[RF90_PATH_D].rfAGCControl1 = rOFDM0_XDAGCCore1;
-
- priv->PHYRegDef[RF90_PATH_A].rfAGCControl2 = rOFDM0_XAAGCCore2;
- priv->PHYRegDef[RF90_PATH_B].rfAGCControl2 = rOFDM0_XBAGCCore2;
- priv->PHYRegDef[RF90_PATH_C].rfAGCControl2 = rOFDM0_XCAGCCore2;
- priv->PHYRegDef[RF90_PATH_D].rfAGCControl2 = rOFDM0_XDAGCCore2;
-
- priv->PHYRegDef[RF90_PATH_A].rfRxIQImbalance = rOFDM0_XARxIQImbalance;
- priv->PHYRegDef[RF90_PATH_B].rfRxIQImbalance = rOFDM0_XBRxIQImbalance;
- priv->PHYRegDef[RF90_PATH_C].rfRxIQImbalance = rOFDM0_XCRxIQImbalance;
- priv->PHYRegDef[RF90_PATH_D].rfRxIQImbalance = rOFDM0_XDRxIQImbalance;
-
- priv->PHYRegDef[RF90_PATH_A].rfRxAFE = rOFDM0_XARxAFE;
- priv->PHYRegDef[RF90_PATH_B].rfRxAFE = rOFDM0_XBRxAFE;
- priv->PHYRegDef[RF90_PATH_C].rfRxAFE = rOFDM0_XCRxAFE;
- priv->PHYRegDef[RF90_PATH_D].rfRxAFE = rOFDM0_XDRxAFE;
-
- priv->PHYRegDef[RF90_PATH_A].rfTxIQImbalance = rOFDM0_XATxIQImbalance;
- priv->PHYRegDef[RF90_PATH_B].rfTxIQImbalance = rOFDM0_XBTxIQImbalance;
- priv->PHYRegDef[RF90_PATH_C].rfTxIQImbalance = rOFDM0_XCTxIQImbalance;
- priv->PHYRegDef[RF90_PATH_D].rfTxIQImbalance = rOFDM0_XDTxIQImbalance;
-
- priv->PHYRegDef[RF90_PATH_A].rfTxAFE = rOFDM0_XATxAFE;
- priv->PHYRegDef[RF90_PATH_B].rfTxAFE = rOFDM0_XBTxAFE;
- priv->PHYRegDef[RF90_PATH_C].rfTxAFE = rOFDM0_XCTxAFE;
- priv->PHYRegDef[RF90_PATH_D].rfTxAFE = rOFDM0_XDTxAFE;
-
- priv->PHYRegDef[RF90_PATH_A].rfLSSIReadBack = rFPGA0_XA_LSSIReadBack;
- priv->PHYRegDef[RF90_PATH_B].rfLSSIReadBack = rFPGA0_XB_LSSIReadBack;
- priv->PHYRegDef[RF90_PATH_C].rfLSSIReadBack = rFPGA0_XC_LSSIReadBack;
- priv->PHYRegDef[RF90_PATH_D].rfLSSIReadBack = rFPGA0_XD_LSSIReadBack;
+ priv->phy_reg_def[RF90_PATH_A].rfintfs = rFPGA0_XAB_RFInterfaceSW;
+ priv->phy_reg_def[RF90_PATH_B].rfintfs = rFPGA0_XAB_RFInterfaceSW;
+ priv->phy_reg_def[RF90_PATH_C].rfintfs = rFPGA0_XCD_RFInterfaceSW;
+ priv->phy_reg_def[RF90_PATH_D].rfintfs = rFPGA0_XCD_RFInterfaceSW;
+
+ priv->phy_reg_def[RF90_PATH_A].rfintfi = rFPGA0_XAB_RFInterfaceRB;
+ priv->phy_reg_def[RF90_PATH_B].rfintfi = rFPGA0_XAB_RFInterfaceRB;
+ priv->phy_reg_def[RF90_PATH_C].rfintfi = rFPGA0_XCD_RFInterfaceRB;
+ priv->phy_reg_def[RF90_PATH_D].rfintfi = rFPGA0_XCD_RFInterfaceRB;
+
+ priv->phy_reg_def[RF90_PATH_A].rfintfo = rFPGA0_XA_RFInterfaceOE;
+ priv->phy_reg_def[RF90_PATH_B].rfintfo = rFPGA0_XB_RFInterfaceOE;
+ priv->phy_reg_def[RF90_PATH_C].rfintfo = rFPGA0_XC_RFInterfaceOE;
+ priv->phy_reg_def[RF90_PATH_D].rfintfo = rFPGA0_XD_RFInterfaceOE;
+
+ priv->phy_reg_def[RF90_PATH_A].rfintfe = rFPGA0_XA_RFInterfaceOE;
+ priv->phy_reg_def[RF90_PATH_B].rfintfe = rFPGA0_XB_RFInterfaceOE;
+ priv->phy_reg_def[RF90_PATH_C].rfintfe = rFPGA0_XC_RFInterfaceOE;
+ priv->phy_reg_def[RF90_PATH_D].rfintfe = rFPGA0_XD_RFInterfaceOE;
+
+ priv->phy_reg_def[RF90_PATH_A].rf3wireOffset = rFPGA0_XA_LSSIParameter;
+ priv->phy_reg_def[RF90_PATH_B].rf3wireOffset = rFPGA0_XB_LSSIParameter;
+ priv->phy_reg_def[RF90_PATH_C].rf3wireOffset = rFPGA0_XC_LSSIParameter;
+ priv->phy_reg_def[RF90_PATH_D].rf3wireOffset = rFPGA0_XD_LSSIParameter;
+
+ priv->phy_reg_def[RF90_PATH_A].rfLSSI_Select = rFPGA0_XAB_RFParameter;
+ priv->phy_reg_def[RF90_PATH_B].rfLSSI_Select = rFPGA0_XAB_RFParameter;
+ priv->phy_reg_def[RF90_PATH_C].rfLSSI_Select = rFPGA0_XCD_RFParameter;
+ priv->phy_reg_def[RF90_PATH_D].rfLSSI_Select = rFPGA0_XCD_RFParameter;
+
+ priv->phy_reg_def[RF90_PATH_A].rfTxGainStage = rFPGA0_TxGainStage;
+ priv->phy_reg_def[RF90_PATH_B].rfTxGainStage = rFPGA0_TxGainStage;
+ priv->phy_reg_def[RF90_PATH_C].rfTxGainStage = rFPGA0_TxGainStage;
+ priv->phy_reg_def[RF90_PATH_D].rfTxGainStage = rFPGA0_TxGainStage;
+
+ priv->phy_reg_def[RF90_PATH_A].rfHSSIPara1 = rFPGA0_XA_HSSIParameter1;
+ priv->phy_reg_def[RF90_PATH_B].rfHSSIPara1 = rFPGA0_XB_HSSIParameter1;
+ priv->phy_reg_def[RF90_PATH_C].rfHSSIPara1 = rFPGA0_XC_HSSIParameter1;
+ priv->phy_reg_def[RF90_PATH_D].rfHSSIPara1 = rFPGA0_XD_HSSIParameter1;
+
+ priv->phy_reg_def[RF90_PATH_A].rfHSSIPara2 = rFPGA0_XA_HSSIParameter2;
+ priv->phy_reg_def[RF90_PATH_B].rfHSSIPara2 = rFPGA0_XB_HSSIParameter2;
+ priv->phy_reg_def[RF90_PATH_C].rfHSSIPara2 = rFPGA0_XC_HSSIParameter2;
+ priv->phy_reg_def[RF90_PATH_D].rfHSSIPara2 = rFPGA0_XD_HSSIParameter2;
+
+ priv->phy_reg_def[RF90_PATH_A].rfSwitchControl = rFPGA0_XAB_SwitchControl;
+ priv->phy_reg_def[RF90_PATH_B].rfSwitchControl = rFPGA0_XAB_SwitchControl;
+ priv->phy_reg_def[RF90_PATH_C].rfSwitchControl = rFPGA0_XCD_SwitchControl;
+ priv->phy_reg_def[RF90_PATH_D].rfSwitchControl = rFPGA0_XCD_SwitchControl;
+
+ priv->phy_reg_def[RF90_PATH_A].rfAGCControl1 = rOFDM0_XAAGCCore1;
+ priv->phy_reg_def[RF90_PATH_B].rfAGCControl1 = rOFDM0_XBAGCCore1;
+ priv->phy_reg_def[RF90_PATH_C].rfAGCControl1 = rOFDM0_XCAGCCore1;
+ priv->phy_reg_def[RF90_PATH_D].rfAGCControl1 = rOFDM0_XDAGCCore1;
+
+ priv->phy_reg_def[RF90_PATH_A].rfAGCControl2 = rOFDM0_XAAGCCore2;
+ priv->phy_reg_def[RF90_PATH_B].rfAGCControl2 = rOFDM0_XBAGCCore2;
+ priv->phy_reg_def[RF90_PATH_C].rfAGCControl2 = rOFDM0_XCAGCCore2;
+ priv->phy_reg_def[RF90_PATH_D].rfAGCControl2 = rOFDM0_XDAGCCore2;
+
+ priv->phy_reg_def[RF90_PATH_A].rfRxIQImbalance = rOFDM0_XARxIQImbalance;
+ priv->phy_reg_def[RF90_PATH_B].rfRxIQImbalance = rOFDM0_XBRxIQImbalance;
+ priv->phy_reg_def[RF90_PATH_C].rfRxIQImbalance = rOFDM0_XCRxIQImbalance;
+ priv->phy_reg_def[RF90_PATH_D].rfRxIQImbalance = rOFDM0_XDRxIQImbalance;
+
+ priv->phy_reg_def[RF90_PATH_A].rfRxAFE = rOFDM0_XARxAFE;
+ priv->phy_reg_def[RF90_PATH_B].rfRxAFE = rOFDM0_XBRxAFE;
+ priv->phy_reg_def[RF90_PATH_C].rfRxAFE = rOFDM0_XCRxAFE;
+ priv->phy_reg_def[RF90_PATH_D].rfRxAFE = rOFDM0_XDRxAFE;
+
+ priv->phy_reg_def[RF90_PATH_A].rfTxIQImbalance = rOFDM0_XATxIQImbalance;
+ priv->phy_reg_def[RF90_PATH_B].rfTxIQImbalance = rOFDM0_XBTxIQImbalance;
+ priv->phy_reg_def[RF90_PATH_C].rfTxIQImbalance = rOFDM0_XCTxIQImbalance;
+ priv->phy_reg_def[RF90_PATH_D].rfTxIQImbalance = rOFDM0_XDTxIQImbalance;
+
+ priv->phy_reg_def[RF90_PATH_A].rfTxAFE = rOFDM0_XATxAFE;
+ priv->phy_reg_def[RF90_PATH_B].rfTxAFE = rOFDM0_XBTxAFE;
+ priv->phy_reg_def[RF90_PATH_C].rfTxAFE = rOFDM0_XCTxAFE;
+ priv->phy_reg_def[RF90_PATH_D].rfTxAFE = rOFDM0_XDTxAFE;
+
+ priv->phy_reg_def[RF90_PATH_A].rfLSSIReadBack = rFPGA0_XA_LSSIReadBack;
+ priv->phy_reg_def[RF90_PATH_B].rfLSSIReadBack = rFPGA0_XB_LSSIReadBack;
+ priv->phy_reg_def[RF90_PATH_C].rfLSSIReadBack = rFPGA0_XC_LSSIReadBack;
+ priv->phy_reg_def[RF90_PATH_D].rfLSSIReadBack = rFPGA0_XD_LSSIReadBack;
}
@@ -526,25 +526,25 @@ static bool _rtl92e_bb_config_para_file(struct net_device *dev)
return rtStatus;
}
rtl92e_set_bb_reg(dev, rFPGA0_RFMOD, bCCKEn|bOFDMEn, 0x0);
- _rtl92e_phy_config_bb(dev, BaseBand_Config_PHY_REG);
+ _rtl92e_phy_config_bb(dev, BB_CONFIG_PHY_REG);
dwRegValue = rtl92e_readl(dev, CPU_GEN);
rtl92e_writel(dev, CPU_GEN, (dwRegValue|CPU_GEN_BB_RST));
- _rtl92e_phy_config_bb(dev, BaseBand_Config_AGC_TAB);
+ _rtl92e_phy_config_bb(dev, BB_CONFIG_AGC_TAB);
- if (priv->IC_Cut > VERSION_8190_BD) {
+ if (priv->ic_cut > VERSION_8190_BD) {
if (priv->rf_type == RF_2T4R)
- dwRegValue = priv->AntennaTxPwDiff[2]<<8 |
- priv->AntennaTxPwDiff[1]<<4 |
- priv->AntennaTxPwDiff[0];
+ dwRegValue = priv->antenna_tx_pwr_diff[2] << 8 |
+ priv->antenna_tx_pwr_diff[1] << 4 |
+ priv->antenna_tx_pwr_diff[0];
else
dwRegValue = 0x0;
rtl92e_set_bb_reg(dev, rFPGA0_TxGainStage,
(bXBTxAGC|bXCTxAGC|bXDTxAGC), dwRegValue);
- dwRegValue = priv->CrystalCap;
+ dwRegValue = priv->crystal_cap;
rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter1, bXtalCap92x,
dwRegValue);
}
@@ -561,65 +561,43 @@ void rtl92e_get_tx_power(struct net_device *dev)
{
struct r8192_priv *priv = rtllib_priv(dev);
- priv->MCSTxPowerLevelOriginalOffset[0] =
+ priv->mcs_tx_pwr_level_org_offset[0] =
rtl92e_readl(dev, rTxAGC_Rate18_06);
- priv->MCSTxPowerLevelOriginalOffset[1] =
+ priv->mcs_tx_pwr_level_org_offset[1] =
rtl92e_readl(dev, rTxAGC_Rate54_24);
- priv->MCSTxPowerLevelOriginalOffset[2] =
+ priv->mcs_tx_pwr_level_org_offset[2] =
rtl92e_readl(dev, rTxAGC_Mcs03_Mcs00);
- priv->MCSTxPowerLevelOriginalOffset[3] =
+ priv->mcs_tx_pwr_level_org_offset[3] =
rtl92e_readl(dev, rTxAGC_Mcs07_Mcs04);
- priv->MCSTxPowerLevelOriginalOffset[4] =
+ priv->mcs_tx_pwr_level_org_offset[4] =
rtl92e_readl(dev, rTxAGC_Mcs11_Mcs08);
- priv->MCSTxPowerLevelOriginalOffset[5] =
+ priv->mcs_tx_pwr_level_org_offset[5] =
rtl92e_readl(dev, rTxAGC_Mcs15_Mcs12);
- priv->DefaultInitialGain[0] = rtl92e_readb(dev, rOFDM0_XAAGCCore1);
- priv->DefaultInitialGain[1] = rtl92e_readb(dev, rOFDM0_XBAGCCore1);
- priv->DefaultInitialGain[2] = rtl92e_readb(dev, rOFDM0_XCAGCCore1);
- priv->DefaultInitialGain[3] = rtl92e_readb(dev, rOFDM0_XDAGCCore1);
+ priv->def_initial_gain[0] = rtl92e_readb(dev, rOFDM0_XAAGCCore1);
+ priv->def_initial_gain[1] = rtl92e_readb(dev, rOFDM0_XBAGCCore1);
+ priv->def_initial_gain[2] = rtl92e_readb(dev, rOFDM0_XCAGCCore1);
+ priv->def_initial_gain[3] = rtl92e_readb(dev, rOFDM0_XDAGCCore1);
priv->framesync = rtl92e_readb(dev, rOFDM0_RxDetector3);
- priv->framesyncC34 = rtl92e_readl(dev, rOFDM0_RxDetector2);
- priv->SifsTime = rtl92e_readw(dev, SIFS);
}
void rtl92e_set_tx_power(struct net_device *dev, u8 channel)
{
struct r8192_priv *priv = rtllib_priv(dev);
u8 powerlevel = 0, powerlevelOFDM24G = 0;
- s8 ant_pwr_diff;
- u32 u4RegValue;
if (priv->epromtype == EEPROM_93C46) {
- powerlevel = priv->TxPowerLevelCCK[channel-1];
- powerlevelOFDM24G = priv->TxPowerLevelOFDM24G[channel-1];
+ powerlevel = priv->tx_pwr_level_cck[channel - 1];
+ powerlevelOFDM24G = priv->tx_pwr_level_ofdm_24g[channel - 1];
} else if (priv->epromtype == EEPROM_93C56) {
- if (priv->rf_type == RF_1T2R) {
- powerlevel = priv->TxPowerLevelCCK_C[channel-1];
- powerlevelOFDM24G = priv->TxPowerLevelOFDM24G_C[channel-1];
- } else if (priv->rf_type == RF_2T4R) {
- powerlevel = priv->TxPowerLevelCCK_A[channel-1];
- powerlevelOFDM24G = priv->TxPowerLevelOFDM24G_A[channel-1];
-
- ant_pwr_diff = priv->TxPowerLevelOFDM24G_C[channel-1]
- - priv->TxPowerLevelOFDM24G_A[channel-1];
-
- priv->RF_C_TxPwDiff = ant_pwr_diff;
-
- ant_pwr_diff &= 0xf;
-
- priv->AntennaTxPwDiff[2] = 0;
- priv->AntennaTxPwDiff[1] = (u8)(ant_pwr_diff);
- priv->AntennaTxPwDiff[0] = 0;
-
- u4RegValue = priv->AntennaTxPwDiff[2]<<8 |
- priv->AntennaTxPwDiff[1]<<4 |
- priv->AntennaTxPwDiff[0];
+ if (priv->rf_type == RF_2T4R) {
+ priv->antenna_tx_pwr_diff[2] = 0;
+ priv->antenna_tx_pwr_diff[1] = 0;
+ priv->antenna_tx_pwr_diff[0] = 0;
rtl92e_set_bb_reg(dev, rFPGA0_TxGainStage,
- (bXBTxAGC|bXCTxAGC|bXDTxAGC),
- u4RegValue);
+ (bXBTxAGC | bXCTxAGC | bXDTxAGC), 0);
}
}
switch (priv->rf_chip) {
@@ -726,8 +704,8 @@ u8 rtl92e_config_rf_path(struct net_device *dev, enum rf90_radio_path eRFPath)
static void _rtl92e_set_tx_power_level(struct net_device *dev, u8 channel)
{
struct r8192_priv *priv = rtllib_priv(dev);
- u8 powerlevel = priv->TxPowerLevelCCK[channel-1];
- u8 powerlevelOFDM24G = priv->TxPowerLevelOFDM24G[channel-1];
+ u8 powerlevel = priv->tx_pwr_level_cck[channel - 1];
+ u8 powerlevelOFDM24G = priv->tx_pwr_level_ofdm_24g[channel - 1];
switch (priv->rf_chip) {
case RF_8225:
@@ -886,7 +864,7 @@ static u8 _rtl92e_phy_switch_channel_step(struct net_device *dev, u8 channel,
continue;
switch (CurrentCmd->CmdID) {
case CmdID_SetTxPowerLevel:
- if (priv->IC_Cut > VERSION_8190_BD)
+ if (priv->ic_cut > VERSION_8190_BD)
_rtl92e_set_tx_power_level(dev,
channel);
break;
@@ -904,7 +882,7 @@ static u8 _rtl92e_phy_switch_channel_step(struct net_device *dev, u8 channel,
break;
case CmdID_RF_WriteReg:
for (eRFPath = 0; eRFPath <
- priv->NumTotalRFPath; eRFPath++)
+ priv->num_total_rf_path; eRFPath++)
rtl92e_set_rf_reg(dev,
(enum rf90_radio_path)eRFPath,
CurrentCmd->Para1, bMask12Bits,
@@ -929,8 +907,8 @@ static void _rtl92e_phy_switch_channel(struct net_device *dev, u8 channel)
u32 delay = 0;
while (!_rtl92e_phy_switch_channel_step(dev, channel,
- &priv->SwChnlStage,
- &priv->SwChnlStep, &delay)) {
+ &priv->sw_chnl_stage,
+ &priv->sw_chnl_step, &delay)) {
if (delay > 0)
msleep(delay);
if (!priv->up)
@@ -954,7 +932,7 @@ u8 rtl92e_set_channel(struct net_device *dev, u8 channel)
netdev_err(dev, "%s(): Driver is not initialized\n", __func__);
return false;
}
- if (priv->SwChnlInProgress)
+ if (priv->sw_chnl_in_progress)
return false;
@@ -987,18 +965,18 @@ u8 rtl92e_set_channel(struct net_device *dev, u8 channel)
break;
}
- priv->SwChnlInProgress = true;
+ priv->sw_chnl_in_progress = true;
if (channel == 0)
channel = 1;
priv->chan = channel;
- priv->SwChnlStage = 0;
- priv->SwChnlStep = 0;
+ priv->sw_chnl_stage = 0;
+ priv->sw_chnl_step = 0;
if (priv->up)
_rtl92e_phy_switch_channel_work_item(dev);
- priv->SwChnlInProgress = false;
+ priv->sw_chnl_in_progress = false;
return true;
}
@@ -1006,16 +984,16 @@ static void _rtl92e_cck_tx_power_track_bw_switch_tssi(struct net_device *dev)
{
struct r8192_priv *priv = rtllib_priv(dev);
- switch (priv->CurrentChannelBW) {
+ switch (priv->current_chnl_bw) {
case HT_CHANNEL_WIDTH_20:
priv->cck_present_attn =
- priv->CCKPresentAttentuation_20Mdefault +
- priv->CCKPresentAttentuation_difference;
+ priv->cck_present_attn_20m_def +
+ priv->cck_present_attn_diff;
if (priv->cck_present_attn >
- (CCKTxBBGainTableLength-1))
+ (CCK_TX_BB_GAIN_TABLE_LEN - 1))
priv->cck_present_attn =
- CCKTxBBGainTableLength-1;
+ CCK_TX_BB_GAIN_TABLE_LEN - 1;
if (priv->cck_present_attn < 0)
priv->cck_present_attn = 0;
@@ -1034,13 +1012,13 @@ static void _rtl92e_cck_tx_power_track_bw_switch_tssi(struct net_device *dev)
case HT_CHANNEL_WIDTH_20_40:
priv->cck_present_attn =
- priv->CCKPresentAttentuation_40Mdefault +
- priv->CCKPresentAttentuation_difference;
+ priv->cck_present_attn_40m_def +
+ priv->cck_present_attn_diff;
if (priv->cck_present_attn >
- (CCKTxBBGainTableLength - 1))
+ (CCK_TX_BB_GAIN_TABLE_LEN - 1))
priv->cck_present_attn =
- CCKTxBBGainTableLength-1;
+ CCK_TX_BB_GAIN_TABLE_LEN - 1;
if (priv->cck_present_attn < 0)
priv->cck_present_attn = 0;
@@ -1070,15 +1048,15 @@ static void _rtl92e_cck_tx_power_track_bw_switch_thermal(struct net_device *dev)
priv->bcck_in_ch14)
priv->bcck_in_ch14 = false;
- switch (priv->CurrentChannelBW) {
+ switch (priv->current_chnl_bw) {
case HT_CHANNEL_WIDTH_20:
- if (priv->Record_CCK_20Mindex == 0)
- priv->Record_CCK_20Mindex = 6;
- priv->CCK_index = priv->Record_CCK_20Mindex;
+ if (priv->rec_cck_20m_idx == 0)
+ priv->rec_cck_20m_idx = 6;
+ priv->cck_index = priv->rec_cck_20m_idx;
break;
case HT_CHANNEL_WIDTH_20_40:
- priv->CCK_index = priv->Record_CCK_40Mindex;
+ priv->cck_index = priv->rec_cck_40m_idx;
break;
}
rtl92e_dm_cck_txpower_adjust(dev, priv->bcck_in_ch14);
@@ -1088,7 +1066,7 @@ static void _rtl92e_cck_tx_power_track_bw_switch(struct net_device *dev)
{
struct r8192_priv *priv = rtllib_priv(dev);
- if (priv->IC_Cut >= IC_VersionCut_D)
+ if (priv->ic_cut >= IC_VersionCut_D)
_rtl92e_cck_tx_power_track_bw_switch_tssi(dev);
else
_rtl92e_cck_tx_power_track_bw_switch_thermal(dev);
@@ -1101,7 +1079,7 @@ static void _rtl92e_set_bw_mode_work_item(struct net_device *dev)
u8 regBwOpMode;
if (priv->rf_chip == RF_PSEUDO_11N) {
- priv->SetBWModeInProgress = false;
+ priv->set_bw_mode_in_progress = false;
return;
}
if (!priv->up) {
@@ -1110,7 +1088,7 @@ static void _rtl92e_set_bw_mode_work_item(struct net_device *dev)
}
regBwOpMode = rtl92e_readb(dev, BW_OPMODE);
- switch (priv->CurrentChannelBW) {
+ switch (priv->current_chnl_bw) {
case HT_CHANNEL_WIDTH_20:
regBwOpMode |= BW_OPMODE_20MHZ;
rtl92e_writeb(dev, BW_OPMODE, regBwOpMode);
@@ -1123,11 +1101,11 @@ static void _rtl92e_set_bw_mode_work_item(struct net_device *dev)
default:
netdev_err(dev, "%s(): unknown Bandwidth: %#X\n", __func__,
- priv->CurrentChannelBW);
+ priv->current_chnl_bw);
break;
}
- switch (priv->CurrentChannelBW) {
+ switch (priv->current_chnl_bw) {
case HT_CHANNEL_WIDTH_20:
rtl92e_set_bb_reg(dev, rFPGA0_RFMOD, bRFMOD, 0x0);
rtl92e_set_bb_reg(dev, rFPGA1_RFMOD, bRFMOD, 0x0);
@@ -1156,15 +1134,15 @@ static void _rtl92e_set_bw_mode_work_item(struct net_device *dev)
}
rtl92e_set_bb_reg(dev, rCCK0_System, bCCKSideBand,
- (priv->nCur40MhzPrimeSC>>1));
+ (priv->n_cur_40mhz_prime_sc>>1));
rtl92e_set_bb_reg(dev, rOFDM1_LSTF, 0xC00,
- priv->nCur40MhzPrimeSC);
+ priv->n_cur_40mhz_prime_sc);
rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter1, 0x00100000, 0);
break;
default:
netdev_err(dev, "%s(): unknown Bandwidth: %#X\n", __func__,
- priv->CurrentChannelBW);
+ priv->current_chnl_bw);
break;
}
@@ -1174,7 +1152,7 @@ static void _rtl92e_set_bw_mode_work_item(struct net_device *dev)
break;
case RF_8256:
- rtl92e_set_bandwidth(dev, priv->CurrentChannelBW);
+ rtl92e_set_bandwidth(dev, priv->current_chnl_bw);
break;
case RF_8258:
@@ -1190,7 +1168,7 @@ static void _rtl92e_set_bw_mode_work_item(struct net_device *dev)
}
atomic_dec(&(priv->rtllib->atm_swbw));
- priv->SetBWModeInProgress = false;
+ priv->set_bw_mode_in_progress = false;
}
void rtl92e_set_bw_mode(struct net_device *dev, enum ht_channel_width bandwidth,
@@ -1199,20 +1177,20 @@ void rtl92e_set_bw_mode(struct net_device *dev, enum ht_channel_width bandwidth,
struct r8192_priv *priv = rtllib_priv(dev);
- if (priv->SetBWModeInProgress)
+ if (priv->set_bw_mode_in_progress)
return;
atomic_inc(&(priv->rtllib->atm_swbw));
- priv->SetBWModeInProgress = true;
+ priv->set_bw_mode_in_progress = true;
- priv->CurrentChannelBW = bandwidth;
+ priv->current_chnl_bw = bandwidth;
if (Offset == HT_EXTCHNL_OFFSET_LOWER)
- priv->nCur40MhzPrimeSC = HAL_PRIME_CHNL_OFFSET_UPPER;
+ priv->n_cur_40mhz_prime_sc = HAL_PRIME_CHNL_OFFSET_UPPER;
else if (Offset == HT_EXTCHNL_OFFSET_UPPER)
- priv->nCur40MhzPrimeSC = HAL_PRIME_CHNL_OFFSET_LOWER;
+ priv->n_cur_40mhz_prime_sc = HAL_PRIME_CHNL_OFFSET_LOWER;
else
- priv->nCur40MhzPrimeSC = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+ priv->n_cur_40mhz_prime_sc = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
_rtl92e_set_bw_mode_work_item(dev);
@@ -1295,7 +1273,7 @@ void rtl92e_set_rf_off(struct net_device *dev)
rtl92e_set_bb_reg(dev, rOFDM1_TRxPathEnable, 0xf, 0x0);
rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter1, 0x60, 0x0);
rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter1, 0x4, 0x0);
- rtl92e_writeb(dev, ANAPAR_FOR_8192PciE, 0x07);
+ rtl92e_writeb(dev, ANAPAR_FOR_8192PCIE, 0x07);
}
@@ -1309,9 +1287,9 @@ static bool _rtl92e_set_rf_power_state(struct net_device *dev,
u8 i = 0, QueueID = 0;
struct rtl8192_tx_ring *ring = NULL;
- if (priv->SetRFPowerStateInProgress)
+ if (priv->set_rf_pwr_state_in_progress)
return false;
- priv->SetRFPowerStateInProgress = true;
+ priv->set_rf_pwr_state_in_progress = true;
switch (priv->rf_chip) {
case RF_8256:
@@ -1331,7 +1309,7 @@ static bool _rtl92e_set_rf_power_state(struct net_device *dev,
netdev_err(dev,
"%s(): Failed to initialize Adapter.\n",
__func__);
- priv->SetRFPowerStateInProgress = false;
+ priv->set_rf_pwr_state_in_progress = false;
return false;
}
@@ -1438,7 +1416,7 @@ static bool _rtl92e_set_rf_power_state(struct net_device *dev,
}
}
- priv->SetRFPowerStateInProgress = false;
+ priv->set_rf_pwr_state_in_progress = false;
return bResult;
}
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phyreg.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_phyreg.h
index 433272a2aae8..f846f109ed98 100644
--- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phyreg.h
+++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phyreg.h
@@ -42,8 +42,6 @@
#define CCK_TXAGC 0x348
/* Mac block on/off control register */
-#define MacBlkCtrl 0x403
-
#define rFPGA0_RFMOD 0x800 /* RF mode & CCK TxSC */
#define rFPGA0_TxInfo 0x804
#define rFPGA0_PSDFunction 0x808
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c
index f8fbe78ccad9..104b16cfa979 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c
@@ -692,16 +692,13 @@ static int _rtl92e_sta_up(struct net_device *dev, bool is_silent_reset)
priv->rtllib->ieee_up = 1;
priv->up_first_time = 0;
- priv->bfirst_init = true;
init_status = priv->ops->initialize_adapter(dev);
if (!init_status) {
netdev_err(dev, "%s(): Initialization failed!\n", __func__);
- priv->bfirst_init = false;
return -1;
}
RT_CLEAR_PS_LEVEL(psc, RT_RF_OFF_LEVL_HALT_NIC);
- priv->bfirst_init = false;
if (priv->polling_timer_on == 0)
rtl92e_check_rfctrl_gpio_timer(&priv->gpio_polling_timer);
@@ -837,7 +834,6 @@ static void _rtl92e_init_priv_variable(struct net_device *dev)
priv->blinked_ingpio = false;
priv->being_init_adapter = false;
priv->bdisable_nic = false;
- priv->bfirst_init = false;
priv->txringcount = 64;
priv->rxbuffersize = 9100;
priv->rxringcount = MAX_RX_COUNT;
@@ -862,7 +858,7 @@ static void _rtl92e_init_priv_variable(struct net_device *dev)
priv->cck_present_attn = 0;
priv->rfa_txpowertrackingindex = 0;
priv->rfc_txpowertrackingindex = 0;
- priv->CckPwEnl = 6;
+ priv->cck_pwr_enl = 6;
priv->rst_progress = RESET_TYPE_NORESET;
priv->force_reset = false;
memset(priv->rtllib->swcamtable, 0, sizeof(struct sw_cam_table) * 32);
@@ -872,7 +868,7 @@ static void _rtl92e_init_priv_variable(struct net_device *dev)
priv->rtllib->rf_off_reason = 0;
priv->rf_change_in_progress = false;
priv->hw_rf_off_action = 0;
- priv->SetRFPowerStateInProgress = false;
+ priv->set_rf_pwr_state_in_progress = false;
priv->rtllib->pwr_save_ctrl.bLeisurePs = true;
priv->rtllib->LPSDelayCnt = 0;
priv->rtllib->sta_sleep = LPS_IS_WAKE;
@@ -891,8 +887,8 @@ static void _rtl92e_init_priv_variable(struct net_device *dev)
priv->card_type = PCI;
- priv->pFirmware = vzalloc(sizeof(struct rt_firmware));
- if (!priv->pFirmware)
+ priv->fw_info = vzalloc(sizeof(struct rt_firmware));
+ if (!priv->fw_info)
netdev_err(dev,
"rtl8192e: Unable to allocate space for firmware\n");
@@ -952,13 +948,13 @@ static short _rtl92e_get_channel_map(struct net_device *dev)
return -1;
}
- if (priv->ChannelPlan >= COUNTRY_CODE_MAX) {
+ if (priv->chnl_plan >= COUNTRY_CODE_MAX) {
netdev_info(dev,
"rtl819x_init:Error channel plan! Set to default.\n");
- priv->ChannelPlan = COUNTRY_CODE_FCC;
+ priv->chnl_plan = COUNTRY_CODE_FCC;
}
dot11d_init(priv->rtllib);
- dot11d_channel_map(priv->ChannelPlan, priv->rtllib);
+ dot11d_channel_map(priv->chnl_plan, priv->rtllib);
for (i = 1; i <= 11; i++)
(priv->rtllib->active_channel_map)[i] = 1;
(priv->rtllib->active_channel_map)[12] = 2;
@@ -1138,7 +1134,7 @@ static void _rtl92e_if_silent_reset(struct net_device *dev)
goto END;
}
priv->rf_change_in_progress = true;
- priv->bResetInProgress = true;
+ priv->reset_in_progress = true;
spin_unlock_irqrestore(&priv->rf_ps_lock, flag);
RESET_START:
@@ -1229,7 +1225,7 @@ RESET_START:
END:
priv->rst_progress = RESET_TYPE_NORESET;
priv->reset_count++;
- priv->bResetInProgress = false;
+ priv->reset_in_progress = false;
rtl92e_writeb(dev, UFWP, 1);
}
@@ -1397,7 +1393,7 @@ static void _rtl92e_watchdog_wq_cb(void *data)
if ((priv->force_reset || ResetType == RESET_TYPE_SILENT))
_rtl92e_if_silent_reset(dev);
priv->force_reset = false;
- priv->bResetInProgress = false;
+ priv->reset_in_progress = false;
}
static void _rtl92e_watchdog_timer_cb(struct timer_list *t)
@@ -1486,7 +1482,7 @@ static void _rtl92e_hard_data_xmit(struct sk_buff *skb, struct net_device *dev,
u8 queue_index = tcb_desc->queue_index;
if ((priv->rtllib->rf_power_state == rf_off) || !priv->up ||
- priv->bResetInProgress) {
+ priv->reset_in_progress) {
kfree_skb(skb);
return;
}
@@ -1519,7 +1515,7 @@ static int _rtl92e_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (queue_index != TXCMD_QUEUE) {
if ((priv->rtllib->rf_power_state == rf_off) ||
- !priv->up || priv->bResetInProgress) {
+ !priv->up || priv->reset_in_progress) {
kfree_skb(skb);
return 0;
}
@@ -1620,11 +1616,7 @@ static short _rtl92e_tx(struct net_device *dev, struct sk_buff *skb)
type = WLAN_FC_GET_TYPE(fc);
pda_addr = header->addr1;
- if (is_broadcast_ether_addr(pda_addr))
- priv->stats.txbytesbroadcast += skb->len - fwinfo_size;
- else if (is_multicast_ether_addr(pda_addr))
- priv->stats.txbytesmulticast += skb->len - fwinfo_size;
- else
+ if (!is_broadcast_ether_addr(pda_addr) && !is_multicast_ether_addr(pda_addr))
priv->stats.txbytesunicast += skb->len - fwinfo_size;
spin_lock_irqsave(&priv->irq_th_lock, flags);
@@ -1654,7 +1646,7 @@ static short _rtl92e_tx(struct net_device *dev, struct sk_buff *skb)
spin_unlock_irqrestore(&priv->irq_th_lock, flags);
netif_trans_update(dev);
- rtl92e_writew(dev, TPPoll, 0x01 << tcb_desc->queue_index);
+ rtl92e_writew(dev, TP_POLL, 0x01 << tcb_desc->queue_index);
return 0;
}
@@ -1807,9 +1799,9 @@ void rtl92e_update_rx_pkt_timestamp(struct net_device *dev,
struct r8192_priv *priv = rtllib_priv(dev);
if (stats->bIsAMPDU && !stats->bFirstMPDU)
- stats->mac_time = priv->LastRxDescTSF;
+ stats->mac_time = priv->last_rx_desc_tsf;
else
- priv->LastRxDescTSF = stats->mac_time;
+ priv->last_rx_desc_tsf = stats->mac_time;
}
long rtl92e_translate_to_dbm(struct r8192_priv *priv, u8 signal_strength_index)
@@ -1914,7 +1906,7 @@ static void _rtl92e_rx_normal(struct net_device *dev)
skb_put(skb, pdesc->Length);
skb_reserve(skb, stats.RxDrvInfoSize +
stats.RxBufShift);
- skb_trim(skb, skb->len - 4/*sCrcLng*/);
+ skb_trim(skb, skb->len - S_CRC_LEN);
rtllib_hdr = (struct rtllib_hdr_1addr *)skb->data;
if (!is_multicast_ether_addr(rtllib_hdr->addr1)) {
/* unicast packet */
@@ -1930,19 +1922,11 @@ static void _rtl92e_rx_normal(struct net_device *dev)
priv->rtllib->LedControlHandler(dev,
LED_CTL_RX);
- if (stats.bCRC) {
- if (type != RTLLIB_FTYPE_MGMT)
- priv->stats.rxdatacrcerr++;
- else
- priv->stats.rxmgmtcrcerr++;
- }
-
skb_len = skb->len;
if (!rtllib_rx(priv->rtllib, skb, &stats)) {
dev_kfree_skb_any(skb);
} else {
- priv->stats.rxok++;
if (unicast_packet)
priv->stats.rxbytesunicast += skb_len;
}
@@ -2135,7 +2119,6 @@ static irqreturn_t _rtl92e_irq(int irq, void *netdev)
spin_lock_irqsave(&priv->irq_th_lock, flags);
priv->ops->interrupt_recognized(dev, &inta, &intb);
- priv->stats.shints++;
if (!inta) {
spin_unlock_irqrestore(&priv->irq_th_lock, flags);
@@ -2147,21 +2130,12 @@ static irqreturn_t _rtl92e_irq(int irq, void *netdev)
goto done;
}
- priv->stats.ints++;
-
if (!netif_running(dev)) {
spin_unlock_irqrestore(&priv->irq_th_lock, flags);
goto done;
}
- if (inta & IMR_TBDOK)
- priv->stats.txbeaconokint++;
-
- if (inta & IMR_TBDER)
- priv->stats.txbeaconerr++;
-
if (inta & IMR_MGNTDOK) {
- priv->stats.txmanageokint++;
_rtl92e_tx_isr(dev, MGNT_QUEUE);
spin_unlock_irqrestore(&priv->irq_th_lock, flags);
if (priv->rtllib->ack_tx_to_ieee) {
@@ -2173,57 +2147,43 @@ static irqreturn_t _rtl92e_irq(int irq, void *netdev)
spin_lock_irqsave(&priv->irq_th_lock, flags);
}
- if (inta & IMR_COMDOK) {
- priv->stats.txcmdpktokint++;
+ if (inta & IMR_COMDOK)
_rtl92e_tx_isr(dev, TXCMD_QUEUE);
- }
if (inta & IMR_HIGHDOK)
_rtl92e_tx_isr(dev, HIGH_QUEUE);
- if (inta & IMR_ROK) {
- priv->stats.rxint++;
+ if (inta & IMR_ROK)
tasklet_schedule(&priv->irq_rx_tasklet);
- }
if (inta & IMR_BcnInt)
tasklet_schedule(&priv->irq_prepare_beacon_tasklet);
if (inta & IMR_RDU) {
- priv->stats.rxrdu++;
rtl92e_writel(dev, INTA_MASK,
rtl92e_readl(dev, INTA_MASK) & ~IMR_RDU);
tasklet_schedule(&priv->irq_rx_tasklet);
}
- if (inta & IMR_RXFOVW) {
- priv->stats.rxoverflow++;
+ if (inta & IMR_RXFOVW)
tasklet_schedule(&priv->irq_rx_tasklet);
- }
-
- if (inta & IMR_TXFOVW)
- priv->stats.txoverflow++;
if (inta & IMR_BKDOK) {
- priv->stats.txbkokint++;
priv->rtllib->link_detect_info.NumTxOkInPeriod++;
_rtl92e_tx_isr(dev, BK_QUEUE);
}
if (inta & IMR_BEDOK) {
- priv->stats.txbeokint++;
priv->rtllib->link_detect_info.NumTxOkInPeriod++;
_rtl92e_tx_isr(dev, BE_QUEUE);
}
if (inta & IMR_VIDOK) {
- priv->stats.txviokint++;
priv->rtllib->link_detect_info.NumTxOkInPeriod++;
_rtl92e_tx_isr(dev, VI_QUEUE);
}
if (inta & IMR_VODOK) {
- priv->stats.txvookint++;
priv->rtllib->link_detect_info.NumTxOkInPeriod++;
_rtl92e_tx_isr(dev, VO_QUEUE);
}
@@ -2386,8 +2346,8 @@ static void _rtl92e_pci_disconnect(struct pci_dev *pdev)
priv->polling_timer_on = 0;
_rtl92e_down(dev, true);
rtl92e_dm_deinit(dev);
- vfree(priv->pFirmware);
- priv->pFirmware = NULL;
+ vfree(priv->fw_info);
+ priv->fw_info = NULL;
_rtl92e_free_rx_ring(dev);
for (i = 0; i < MAX_TX_QUEUE_COUNT; i++)
_rtl92e_free_tx_ring(dev, i);
@@ -2423,7 +2383,6 @@ bool rtl92e_enable_nic(struct net_device *dev)
return false;
}
- priv->bfirst_init = true;
init_status = priv->ops->initialize_adapter(dev);
if (!init_status) {
netdev_warn(dev, "%s(): Initialization failed!\n", __func__);
@@ -2431,7 +2390,6 @@ bool rtl92e_enable_nic(struct net_device *dev)
return false;
}
RT_CLEAR_PS_LEVEL(psc, RT_RF_OFF_LEVL_HALT_NIC);
- priv->bfirst_init = false;
rtl92e_irq_enable(dev);
priv->bdisable_nic = false;
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h
index cceb77492363..fd96eef90c7f 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h
@@ -90,11 +90,11 @@
#define PHY_RSSI_SLID_WIN_MAX 100
-#define TxBBGainTableLength 37
-#define CCKTxBBGainTableLength 23
+#define TX_BB_GAIN_TABLE_LEN 37
+#define CCK_TX_BB_GAIN_TABLE_LEN 23
#define CHANNEL_PLAN_LEN 10
-#define sCrcLng 4
+#define S_CRC_LEN 4
#define NIC_SEND_HANG_THRESHOLD_NORMAL 4
#define NIC_SEND_HANG_THRESHOLD_POWERSAVE 8
@@ -145,35 +145,13 @@ enum rt_rf_type_819xu {
enum rt_customer_id {
RT_CID_DEFAULT = 0,
- RT_CID_8187_ALPHA0 = 1,
- RT_CID_8187_SERCOMM_PS = 2,
- RT_CID_8187_HW_LED = 3,
- RT_CID_8187_NETGEAR = 4,
- RT_CID_WHQL = 5,
RT_CID_819x_CAMEO = 6,
RT_CID_819x_RUNTOP = 7,
- RT_CID_819x_Senao = 8,
RT_CID_TOSHIBA = 9,
- RT_CID_819x_Netcore = 10,
+ RT_CID_819X_NETCORE = 10,
RT_CID_Nettronix = 11,
RT_CID_DLINK = 12,
RT_CID_PRONET = 13,
- RT_CID_COREGA = 14,
- RT_CID_819x_ALPHA = 15,
- RT_CID_819x_Sitecom = 16,
- RT_CID_CCX = 17,
- RT_CID_819x_Lenovo = 18,
- RT_CID_819x_QMI = 19,
- RT_CID_819x_Edimax_Belkin = 20,
- RT_CID_819x_Sercomm_Belkin = 21,
- RT_CID_819x_CAMEO1 = 22,
- RT_CID_819x_MSI = 23,
- RT_CID_819x_Acer = 24,
- RT_CID_819x_HP = 27,
- RT_CID_819x_CLEVO = 28,
- RT_CID_819x_Arcadyan_Belkin = 29,
- RT_CID_819x_SAMSUNG = 30,
- RT_CID_819x_WNC_COREGA = 31,
};
enum reset_type {
@@ -183,37 +161,7 @@ enum reset_type {
};
struct rt_stats {
- unsigned long rxrdu;
- unsigned long rxok;
- unsigned long rxdatacrcerr;
- unsigned long rxmgmtcrcerr;
- unsigned long rxcrcerrmin;
- unsigned long rxcrcerrmid;
- unsigned long rxcrcerrmax;
unsigned long received_rate_histogram[4][32];
- unsigned long received_preamble_GI[2][32];
- unsigned long numpacket_matchbssid;
- unsigned long numpacket_toself;
- unsigned long num_process_phyinfo;
- unsigned long numqry_phystatus;
- unsigned long numqry_phystatusCCK;
- unsigned long numqry_phystatusHT;
- unsigned long received_bwtype[5];
- unsigned long rxoverflow;
- unsigned long rxint;
- unsigned long ints;
- unsigned long shints;
- unsigned long txoverflow;
- unsigned long txbeokint;
- unsigned long txbkokint;
- unsigned long txviokint;
- unsigned long txvookint;
- unsigned long txbeaconokint;
- unsigned long txbeaconerr;
- unsigned long txmanageokint;
- unsigned long txcmdpktokint;
- unsigned long txbytesmulticast;
- unsigned long txbytesbroadcast;
unsigned long txbytesunicast;
unsigned long rxbytesunicast;
unsigned long txretrycount;
@@ -223,14 +171,12 @@ struct rt_stats {
unsigned long slide_rssi_total;
unsigned long slide_evm_total;
long signal_strength;
- long signal_quality;
long last_signal_strength_inpercent;
long recv_signal_power;
u8 rx_rssi_percentage[4];
u8 rx_evm_percentage[2];
- long rxSNRdB[4];
- u32 Slide_Beacon_pwdb[100];
- u32 Slide_Beacon_Total;
+ u32 slide_beacon_pwdb[100];
+ u32 slide_beacon_total;
u32 CurrentShowTxate;
};
@@ -257,8 +203,6 @@ struct rtl8192_tx_ring {
struct sk_buff_head queue;
};
-
-
struct rtl819x_ops {
enum nic_t nic_type;
void (*get_eeprom_size)(struct net_device *dev);
@@ -298,7 +242,6 @@ struct r8192_priv {
struct pci_dev *pdev;
struct pci_dev *bridge_pdev;
- bool bfirst_init;
bool bfirst_after_down;
bool being_init_adapter;
@@ -317,16 +260,15 @@ struct r8192_priv {
struct work_struct reset_wq;
- enum rt_customer_id CustomerID;
-
+ enum rt_customer_id customer_id;
enum rt_rf_type_819xu rf_chip;
- enum ht_channel_width CurrentChannelBW;
- struct bb_reg_definition PHYRegDef[4];
+ enum ht_channel_width current_chnl_bw;
+ struct bb_reg_definition phy_reg_def[4];
struct rate_adaptive rate_adaptive;
- struct rt_firmware *pFirmware;
- enum rtl819x_loopback LoopbackMode;
+ struct rt_firmware *fw_info;
+ enum rtl819x_loopback loopback_mode;
struct timer_list watch_dog_timer;
struct timer_list fsync_timer;
@@ -360,9 +302,9 @@ struct r8192_priv {
int rxringcount;
u16 rxbuffersize;
- u64 LastRxDescTSF;
+ u64 last_rx_desc_tsf;
- u32 ReceiveConfig;
+ u32 receive_config;
u8 retry_data;
u8 retry_rts;
u16 rts;
@@ -371,8 +313,8 @@ struct r8192_priv {
int txringcount;
atomic_t tx_pending[0x10];
- u16 ShortRetryLimit;
- u16 LongRetryLimit;
+ u16 short_retry_limit;
+ u16 long_retry_limit;
bool hw_radio_off;
bool blinked_ingpio;
@@ -396,94 +338,82 @@ struct r8192_priv {
u32 irq_mask[2];
- u8 Rf_Mode;
+ u8 rf_mode;
enum nic_t card_8192;
u8 card_8192_version;
u8 rf_type;
- u8 IC_Cut;
+ u8 ic_cut;
char nick[IW_ESSID_MAX_SIZE + 1];
u8 check_roaming_cnt;
- u32 SilentResetRxSlotIndex;
- u32 SilentResetRxStuckEvent[MAX_SILENT_RESET_RX_SLOT_NUM];
+ u32 silent_reset_rx_slot_index;
+ u32 silent_reset_rx_stuck_event[MAX_SILENT_RESET_RX_SLOT_NUM];
u16 basic_rate;
u8 short_preamble;
u8 dot11_current_preamble_mode;
u8 slot_time;
- u16 SifsTime;
- bool AutoloadFailFlag;
+ bool autoload_fail_flag;
short epromtype;
u16 eeprom_vid;
u16 eeprom_did;
- u8 eeprom_CustomerID;
- u16 eeprom_ChannelPlan;
+ u8 eeprom_customer_id;
+ u16 eeprom_chnl_plan;
- u8 EEPROMTxPowerLevelCCK[14];
- u8 EEPROMTxPowerLevelOFDM24G[14];
- u8 EEPROMRfACCKChnl1TxPwLevel[3];
- u8 EEPROMRfAOfdmChnlTxPwLevel[3];
- u8 EEPROMRfCCCKChnl1TxPwLevel[3];
- u8 EEPROMRfCOfdmChnlTxPwLevel[3];
- u16 EEPROMAntPwDiff;
- u8 EEPROMThermalMeter;
- u8 EEPROMCrystalCap;
+ u8 eeprom_tx_pwr_level_cck[14];
+ u8 eeprom_tx_pwr_level_ofdm24g[14];
+ u16 eeprom_ant_pwr_diff;
+ u8 eeprom_thermal_meter;
+ u8 eeprom_crystal_cap;
- u8 EEPROMLegacyHTTxPowerDiff;
+ u8 eeprom_legacy_ht_tx_pwr_diff;
- u8 CrystalCap;
- u8 ThermalMeter[2];
+ u8 crystal_cap;
+ u8 thermal_meter[2];
- u8 SwChnlInProgress;
- u8 SwChnlStage;
- u8 SwChnlStep;
- u8 SetBWModeInProgress;
+ u8 sw_chnl_in_progress;
+ u8 sw_chnl_stage;
+ u8 sw_chnl_step;
+ u8 set_bw_mode_in_progress;
- u8 nCur40MhzPrimeSC;
+ u8 n_cur_40mhz_prime_sc;
- u32 RfReg0Value[4];
- u8 NumTotalRFPath;
+ u32 rf_reg_0value[4];
+ u8 num_total_rf_path;
bool brfpath_rxenable[4];
- bool bTXPowerDataReadFromEEPORM;
+ bool tx_pwr_data_read_from_eeprom;
u16 reg_chnl_plan;
- u16 ChannelPlan;
+ u16 chnl_plan;
u8 hw_rf_off_action;
bool rf_change_in_progress;
- bool SetRFPowerStateInProgress;
+ bool set_rf_pwr_state_in_progress;
bool bdisable_nic;
- u8 DM_Type;
-
- u8 CckPwEnl;
- u16 TSSI_13dBm;
- u32 Pwr_Track;
- u8 CCKPresentAttentuation_20Mdefault;
- u8 CCKPresentAttentuation_40Mdefault;
- s8 CCKPresentAttentuation_difference;
+ u8 cck_pwr_enl;
+ u16 tssi_13dBm;
+ u32 pwr_track;
+ u8 cck_present_attn_20m_def;
+ u8 cck_present_attn_40m_def;
+ s8 cck_present_attn_diff;
s8 cck_present_attn;
long undecorated_smoothed_pwdb;
- u32 MCSTxPowerLevelOriginalOffset[6];
- u8 TxPowerLevelCCK[14];
- u8 TxPowerLevelCCK_A[14];
- u8 TxPowerLevelCCK_C[14];
- u8 TxPowerLevelOFDM24G[14];
- u8 TxPowerLevelOFDM24G_A[14];
- u8 TxPowerLevelOFDM24G_C[14];
- u8 LegacyHTTxPowerDiff;
- s8 RF_C_TxPwDiff;
- u8 AntennaTxPwDiff[3];
-
- bool bDynamicTxHighPower;
- bool bDynamicTxLowPower;
- bool bLastDTPFlag_High;
- bool bLastDTPFlag_Low;
+ u32 mcs_tx_pwr_level_org_offset[6];
+ u8 tx_pwr_level_cck[14];
+ u8 tx_pwr_level_ofdm_24g[14];
+ u8 legacy_ht_tx_pwr_diff;
+ u8 antenna_tx_pwr_diff[3];
+
+ bool dynamic_tx_high_pwr;
+ bool dynamic_tx_low_pwr;
+ bool last_dtp_flag_high;
+ bool last_dtp_flag_low;
u8 rfa_txpowertrackingindex;
u8 rfa_txpowertrackingindex_real;
@@ -494,42 +424,38 @@ struct r8192_priv {
bool bcck_in_ch14;
u8 txpower_count;
- bool btxpower_trackingInit;
+ bool tx_pwr_tracking_init;
- u8 OFDM_index[2];
- u8 CCK_index;
+ u8 ofdm_index[2];
+ u8 cck_index;
- u8 Record_CCK_20Mindex;
- u8 Record_CCK_40Mindex;
+ u8 rec_cck_20m_idx;
+ u8 rec_cck_40m_idx;
struct init_gain initgain_backup;
- u8 DefaultInitialGain[4];
+ u8 def_initial_gain[4];
bool bis_any_nonbepkts;
bool bcurrent_turbo_EDCA;
bool bis_cur_rdlstate;
bool bfsync_processing;
u32 rate_record;
- u32 rateCountDiffRecord;
- u32 ContinueDiffCount;
+ u32 rate_count_diff_rec;
+ u32 continue_diff_count;
bool bswitch_fsync;
u8 framesync;
- u32 framesyncC34;
- u8 framesyncMonitor;
+ u8 frame_sync_monitor;
u32 reset_count;
enum reset_type rst_progress;
- u16 TxCounter;
+ u16 tx_counter;
u16 rx_ctr;
- bool bResetInProgress;
+ bool reset_in_progress;
bool force_reset;
bool force_lps;
bool chan_forced;
-
- u8 PwrDomainProtect;
- u8 H2CTxCmdSeq;
};
extern const struct ethtool_ops rtl819x_ethtool_ops;
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
index a18393c8a833..d8455b23e555 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
@@ -46,7 +46,7 @@ static u32 edca_setting_UL[HT_IOT_PEER_MAX] = {
0x5e4332
};
-const u32 dm_tx_bb_gain[TxBBGainTableLength] = {
+const u32 dm_tx_bb_gain[TX_BB_GAIN_TABLE_LEN] = {
0x7f8001fe, /* 12 dB */
0x788001e2, /* 11 dB */
0x71c001c7,
@@ -86,7 +86,7 @@ const u32 dm_tx_bb_gain[TxBBGainTableLength] = {
0x10000040, /* -24 dB */
};
-const u8 dm_cck_tx_bb_gain[CCKTxBBGainTableLength][8] = {
+const u8 dm_cck_tx_bb_gain[CCK_TX_BB_GAIN_TABLE_LEN][8] = {
{0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04},
{0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04},
{0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03},
@@ -112,7 +112,7 @@ const u8 dm_cck_tx_bb_gain[CCKTxBBGainTableLength][8] = {
{0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01}
};
-const u8 dm_cck_tx_bb_gain_ch14[CCKTxBBGainTableLength][8] = {
+const u8 dm_cck_tx_bb_gain_ch14[CCK_TX_BB_GAIN_TABLE_LEN][8] = {
{0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00},
{0x33, 0x32, 0x2b, 0x19, 0x00, 0x00, 0x00, 0x00},
{0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00},
@@ -144,7 +144,7 @@ const u8 dm_cck_tx_bb_gain_ch14[CCKTxBBGainTableLength][8] = {
/*------------------------Define global variable-----------------------------*/
struct dig_t dm_digtable;
-struct drx_path_sel DM_RxPathSelTable;
+struct drx_path_sel dm_rx_path_sel_table;
/*------------------------Define global variable-----------------------------*/
@@ -203,8 +203,6 @@ void rtl92e_dm_init(struct net_device *dev)
{
struct r8192_priv *priv = rtllib_priv(dev);
- priv->DM_Type = DM_Type_ByDriver;
-
priv->undecorated_smoothed_pwdb = -1;
_rtl92e_dm_init_dynamic_tx_power(dev);
@@ -284,15 +282,15 @@ void rtl92e_init_adaptive_rate(struct net_device *dev)
struct rate_adaptive *pra = &priv->rate_adaptive;
pra->ratr_state = DM_RATR_STA_MAX;
- pra->high2low_rssi_thresh_for_ra = RateAdaptiveTH_High;
- pra->low2high_rssi_thresh_for_ra20M = RateAdaptiveTH_Low_20M+5;
- pra->low2high_rssi_thresh_for_ra40M = RateAdaptiveTH_Low_40M+5;
+ pra->high2low_rssi_thresh_for_ra = RATE_ADAPTIVE_TH_HIGH;
+ pra->low2high_rssi_thresh_for_ra20M = RATE_ADAPTIVE_TH_LOW_20M + 5;
+ pra->low2high_rssi_thresh_for_ra40M = RATE_ADAPTIVE_TH_LOW_40M + 5;
- pra->high_rssi_thresh_for_ra = RateAdaptiveTH_High+5;
- pra->low_rssi_thresh_for_ra20M = RateAdaptiveTH_Low_20M;
- pra->low_rssi_thresh_for_ra40M = RateAdaptiveTH_Low_40M;
+ pra->high_rssi_thresh_for_ra = RATE_ADAPTIVE_TH_HIGH + 5;
+ pra->low_rssi_thresh_for_ra20M = RATE_ADAPTIVE_TH_LOW_20M;
+ pra->low_rssi_thresh_for_ra40M = RATE_ADAPTIVE_TH_LOW_40M;
- if (priv->CustomerID == RT_CID_819x_Netcore)
+ if (priv->customer_id == RT_CID_819X_NETCORE)
pra->ping_rssi_enable = 1;
else
pra->ping_rssi_enable = 0;
@@ -353,7 +351,7 @@ static void _rtl92e_dm_check_rate_adaptive(struct net_device *dev)
(pra->middle_rssi_threshold_ratr & (~BIT31)) |
((bshort_gi_enabled) ? BIT31 : 0);
- if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) {
+ if (priv->current_chnl_bw != HT_CHANNEL_WIDTH_20) {
pra->low_rssi_threshold_ratr =
(pra->low_rssi_threshold_ratr_40M & (~BIT31)) |
((bshort_gi_enabled) ? BIT31 : 0);
@@ -368,15 +366,15 @@ static void _rtl92e_dm_check_rate_adaptive(struct net_device *dev)
if (pra->ratr_state == DM_RATR_STA_HIGH) {
HighRSSIThreshForRA = pra->high2low_rssi_thresh_for_ra;
- LowRSSIThreshForRA = (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) ?
+ LowRSSIThreshForRA = (priv->current_chnl_bw != HT_CHANNEL_WIDTH_20) ?
(pra->low_rssi_thresh_for_ra40M) : (pra->low_rssi_thresh_for_ra20M);
} else if (pra->ratr_state == DM_RATR_STA_LOW) {
HighRSSIThreshForRA = pra->high_rssi_thresh_for_ra;
- LowRSSIThreshForRA = (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) ?
+ LowRSSIThreshForRA = (priv->current_chnl_bw != HT_CHANNEL_WIDTH_20) ?
(pra->low2high_rssi_thresh_for_ra40M) : (pra->low2high_rssi_thresh_for_ra20M);
} else {
HighRSSIThreshForRA = pra->high_rssi_thresh_for_ra;
- LowRSSIThreshForRA = (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) ?
+ LowRSSIThreshForRA = (priv->current_chnl_bw != HT_CHANNEL_WIDTH_20) ?
(pra->low_rssi_thresh_for_ra40M) : (pra->low_rssi_thresh_for_ra20M);
}
@@ -443,8 +441,8 @@ static void _rtl92e_dm_bandwidth_autoswitch(struct net_device *dev)
{
struct r8192_priv *priv = rtllib_priv(dev);
- if (priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20 ||
- !priv->rtllib->bandwidth_auto_switch.bautoswitch_enable)
+ if (priv->current_chnl_bw == HT_CHANNEL_WIDTH_20 ||
+ !priv->rtllib->bandwidth_auto_switch.bautoswitch_enable)
return;
if (!priv->rtllib->bandwidth_auto_switch.bforced_tx20Mhz) {
if (priv->undecorated_smoothed_pwdb <=
@@ -457,7 +455,7 @@ static void _rtl92e_dm_bandwidth_autoswitch(struct net_device *dev)
}
}
-static u32 OFDMSwingTable[OFDM_Table_Length] = {
+static u32 OFDMSwingTable[OFDM_TABLE_LEN] = {
0x7f8001fe,
0x71c001c7,
0x65400195,
@@ -479,7 +477,7 @@ static u32 OFDMSwingTable[OFDM_Table_Length] = {
0x10000040
};
-static u8 CCKSwingTable_Ch1_Ch13[CCK_Table_length][8] = {
+static u8 CCKSwingTable_Ch1_Ch13[CCK_TABLE_LEN][8] = {
{0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04},
{0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03},
{0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03},
@@ -494,7 +492,7 @@ static u8 CCKSwingTable_Ch1_Ch13[CCK_Table_length][8] = {
{0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01}
};
-static u8 CCKSwingTable_Ch14[CCK_Table_length][8] = {
+static u8 CCKSwingTable_Ch14[CCK_TABLE_LEN][8] = {
{0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00},
{0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00},
{0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00},
@@ -570,8 +568,8 @@ static void _rtl92e_dm_tx_update_tssi_strong_signal(struct net_device *dev,
struct r8192_priv *p = rtllib_priv(dev);
if (RF_Type == RF_2T4R) {
- if ((p->rfa_txpowertrackingindex < TxBBGainTableLength - 1) &&
- (p->rfc_txpowertrackingindex < TxBBGainTableLength - 1)) {
+ if ((p->rfa_txpowertrackingindex < TX_BB_GAIN_TABLE_LEN - 1) &&
+ (p->rfc_txpowertrackingindex < TX_BB_GAIN_TABLE_LEN - 1)) {
p->rfa_txpowertrackingindex++;
p->rfa_txpowertrackingindex_real++;
rtl92e_set_bb_reg(dev, rOFDM0_XATxIQImbalance,
@@ -585,13 +583,13 @@ static void _rtl92e_dm_tx_update_tssi_strong_signal(struct net_device *dev,
} else {
rtl92e_set_bb_reg(dev, rOFDM0_XATxIQImbalance,
bMaskDWord,
- dm_tx_bb_gain[TxBBGainTableLength - 1]);
+ dm_tx_bb_gain[TX_BB_GAIN_TABLE_LEN - 1]);
rtl92e_set_bb_reg(dev, rOFDM0_XCTxIQImbalance,
bMaskDWord,
- dm_tx_bb_gain[TxBBGainTableLength - 1]);
+ dm_tx_bb_gain[TX_BB_GAIN_TABLE_LEN - 1]);
}
} else {
- if (p->rfa_txpowertrackingindex < (TxBBGainTableLength - 1)) {
+ if (p->rfa_txpowertrackingindex < (TX_BB_GAIN_TABLE_LEN - 1)) {
p->rfa_txpowertrackingindex++;
p->rfa_txpowertrackingindex_real++;
rtl92e_set_bb_reg(dev, rOFDM0_XATxIQImbalance,
@@ -600,7 +598,7 @@ static void _rtl92e_dm_tx_update_tssi_strong_signal(struct net_device *dev,
} else {
rtl92e_set_bb_reg(dev, rOFDM0_XATxIQImbalance,
bMaskDWord,
- dm_tx_bb_gain[TxBBGainTableLength - 1]);
+ dm_tx_bb_gain[TX_BB_GAIN_TABLE_LEN - 1]);
}
}
}
@@ -615,14 +613,14 @@ static void _rtl92e_dm_tx_power_tracking_callback_tssi(struct net_device *dev)
u8 RF_Type, tmp_report[5] = {0, 0, 0, 0, 0};
u32 Value;
u8 Pwr_Flag;
- u16 Avg_TSSI_Meas, TSSI_13dBm, Avg_TSSI_Meas_from_driver = 0;
+ u16 Avg_TSSI_Meas, tssi_13dBm, Avg_TSSI_Meas_from_driver = 0;
u32 delta = 0;
rtl92e_writeb(dev, Pw_Track_Flag, 0);
rtl92e_writeb(dev, FW_Busy_Flag, 0);
priv->rtllib->bdynamic_txpower_enable = false;
- powerlevelOFDM24G = priv->Pwr_Track >> 24;
+ powerlevelOFDM24G = priv->pwr_track >> 24;
RF_Type = priv->rf_type;
Value = (RF_Type<<8) | powerlevelOFDM24G;
@@ -640,7 +638,7 @@ static void _rtl92e_dm_tx_power_tracking_callback_tssi(struct net_device *dev)
if (Pwr_Flag == 0) {
mdelay(1);
- if (priv->bResetInProgress) {
+ if (priv->reset_in_progress) {
rtl92e_writeb(dev, Pw_Track_Flag, 0);
rtl92e_writeb(dev, FW_Busy_Flag, 0);
return;
@@ -688,12 +686,12 @@ static void _rtl92e_dm_tx_power_tracking_callback_tssi(struct net_device *dev)
Avg_TSSI_Meas_from_driver += tmp_report[k];
Avg_TSSI_Meas_from_driver *= 100 / 5;
- TSSI_13dBm = priv->TSSI_13dBm;
+ tssi_13dBm = priv->tssi_13dBm;
- if (Avg_TSSI_Meas_from_driver > TSSI_13dBm)
- delta = Avg_TSSI_Meas_from_driver - TSSI_13dBm;
+ if (Avg_TSSI_Meas_from_driver > tssi_13dBm)
+ delta = Avg_TSSI_Meas_from_driver - tssi_13dBm;
else
- delta = TSSI_13dBm - Avg_TSSI_Meas_from_driver;
+ delta = tssi_13dBm - Avg_TSSI_Meas_from_driver;
if (delta <= E_FOR_TX_POWER_TRACK) {
priv->rtllib->bdynamic_txpower_enable = true;
@@ -701,36 +699,36 @@ static void _rtl92e_dm_tx_power_tracking_callback_tssi(struct net_device *dev)
rtl92e_writeb(dev, FW_Busy_Flag, 0);
return;
}
- if (Avg_TSSI_Meas_from_driver < TSSI_13dBm - E_FOR_TX_POWER_TRACK)
+ if (Avg_TSSI_Meas_from_driver < tssi_13dBm - E_FOR_TX_POWER_TRACK)
_rtl92e_dm_tx_update_tssi_weak_signal(dev,
RF_Type);
else
_rtl92e_dm_tx_update_tssi_strong_signal(dev, RF_Type);
if (RF_Type == RF_2T4R) {
- priv->CCKPresentAttentuation_difference
+ priv->cck_present_attn_diff
= priv->rfa_txpowertrackingindex - priv->rfa_txpowertracking_default;
} else {
- priv->CCKPresentAttentuation_difference
+ priv->cck_present_attn_diff
= priv->rfa_txpowertrackingindex_real - priv->rfa_txpowertracking_default;
}
- if (priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20)
+ if (priv->current_chnl_bw == HT_CHANNEL_WIDTH_20)
priv->cck_present_attn =
- priv->CCKPresentAttentuation_20Mdefault +
- priv->CCKPresentAttentuation_difference;
+ priv->cck_present_attn_20m_def +
+ priv->cck_present_attn_diff;
else
priv->cck_present_attn =
- priv->CCKPresentAttentuation_40Mdefault +
- priv->CCKPresentAttentuation_difference;
+ priv->cck_present_attn_40m_def +
+ priv->cck_present_attn_diff;
- if (priv->cck_present_attn > (CCKTxBBGainTableLength-1))
- priv->cck_present_attn = CCKTxBBGainTableLength-1;
+ if (priv->cck_present_attn > (CCK_TX_BB_GAIN_TABLE_LEN - 1))
+ priv->cck_present_attn = CCK_TX_BB_GAIN_TABLE_LEN - 1;
if (priv->cck_present_attn < 0)
priv->cck_present_attn = 0;
if (priv->cck_present_attn > -1 &&
- priv->cck_present_attn < CCKTxBBGainTableLength) {
+ priv->cck_present_attn < CCK_TX_BB_GAIN_TABLE_LEN) {
if (priv->rtllib->current_network.channel == 14 &&
!priv->bcck_in_ch14) {
priv->bcck_in_ch14 = true;
@@ -742,8 +740,8 @@ static void _rtl92e_dm_tx_power_tracking_callback_tssi(struct net_device *dev)
rtl92e_dm_cck_txpower_adjust(dev, priv->bcck_in_ch14);
}
- if (priv->CCKPresentAttentuation_difference <= -12 ||
- priv->CCKPresentAttentuation_difference >= 24) {
+ if (priv->cck_present_attn_diff <= -12 ||
+ priv->cck_present_attn_diff >= 24) {
priv->rtllib->bdynamic_txpower_enable = true;
rtl92e_writeb(dev, Pw_Track_Flag, 0);
rtl92e_writeb(dev, FW_Busy_Flag, 0);
@@ -770,22 +768,22 @@ static void _rtl92e_dm_tx_power_tracking_cb_thermal(struct net_device *dev)
u8 tmpOFDMindex, tmpCCKindex, tmpCCK20Mindex, tmpCCK40Mindex, tmpval;
int i = 0, CCKSwingNeedUpdate = 0;
- if (!priv->btxpower_trackingInit) {
+ if (!priv->tx_pwr_tracking_init) {
tmpRegA = rtl92e_get_bb_reg(dev, rOFDM0_XATxIQImbalance,
bMaskDWord);
- for (i = 0; i < OFDM_Table_Length; i++) {
+ for (i = 0; i < OFDM_TABLE_LEN; i++) {
if (tmpRegA == OFDMSwingTable[i])
- priv->OFDM_index[0] = i;
+ priv->ofdm_index[0] = i;
}
TempCCk = rtl92e_get_bb_reg(dev, rCCK0_TxFilter1, bMaskByte2);
- for (i = 0; i < CCK_Table_length; i++) {
+ for (i = 0; i < CCK_TABLE_LEN; i++) {
if (TempCCk == (u32)CCKSwingTable_Ch1_Ch13[i][0]) {
- priv->CCK_index = i;
+ priv->cck_index = i;
break;
}
}
- priv->btxpower_trackingInit = true;
+ priv->tx_pwr_tracking_init = true;
return;
}
@@ -794,21 +792,21 @@ static void _rtl92e_dm_tx_power_tracking_cb_thermal(struct net_device *dev)
return;
if (tmpRegA >= 12)
tmpRegA = 12;
- priv->ThermalMeter[0] = ThermalMeterVal;
- priv->ThermalMeter[1] = ThermalMeterVal;
+ priv->thermal_meter[0] = ThermalMeterVal;
+ priv->thermal_meter[1] = ThermalMeterVal;
- if (priv->ThermalMeter[0] >= (u8)tmpRegA) {
- tmpOFDMindex = tmpCCK20Mindex = 6+(priv->ThermalMeter[0] -
+ if (priv->thermal_meter[0] >= (u8)tmpRegA) {
+ tmpOFDMindex = tmpCCK20Mindex = 6+(priv->thermal_meter[0] -
(u8)tmpRegA);
tmpCCK40Mindex = tmpCCK20Mindex - 6;
- if (tmpOFDMindex >= OFDM_Table_Length)
- tmpOFDMindex = OFDM_Table_Length-1;
- if (tmpCCK20Mindex >= CCK_Table_length)
- tmpCCK20Mindex = CCK_Table_length-1;
- if (tmpCCK40Mindex >= CCK_Table_length)
- tmpCCK40Mindex = CCK_Table_length-1;
+ if (tmpOFDMindex >= OFDM_TABLE_LEN)
+ tmpOFDMindex = OFDM_TABLE_LEN - 1;
+ if (tmpCCK20Mindex >= CCK_TABLE_LEN)
+ tmpCCK20Mindex = CCK_TABLE_LEN - 1;
+ if (tmpCCK40Mindex >= CCK_TABLE_LEN)
+ tmpCCK40Mindex = CCK_TABLE_LEN - 1;
} else {
- tmpval = (u8)tmpRegA - priv->ThermalMeter[0];
+ tmpval = (u8)tmpRegA - priv->thermal_meter[0];
if (tmpval >= 6) {
tmpOFDMindex = 0;
tmpCCK20Mindex = 0;
@@ -818,13 +816,13 @@ static void _rtl92e_dm_tx_power_tracking_cb_thermal(struct net_device *dev)
}
tmpCCK40Mindex = 0;
}
- if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)
+ if (priv->current_chnl_bw != HT_CHANNEL_WIDTH_20)
tmpCCKindex = tmpCCK40Mindex;
else
tmpCCKindex = tmpCCK20Mindex;
- priv->Record_CCK_20Mindex = tmpCCK20Mindex;
- priv->Record_CCK_40Mindex = tmpCCK40Mindex;
+ priv->rec_cck_20m_idx = tmpCCK20Mindex;
+ priv->rec_cck_40m_idx = tmpCCK40Mindex;
if (priv->rtllib->current_network.channel == 14 &&
!priv->bcck_in_ch14) {
@@ -836,17 +834,17 @@ static void _rtl92e_dm_tx_power_tracking_cb_thermal(struct net_device *dev)
CCKSwingNeedUpdate = 1;
}
- if (priv->CCK_index != tmpCCKindex) {
- priv->CCK_index = tmpCCKindex;
+ if (priv->cck_index != tmpCCKindex) {
+ priv->cck_index = tmpCCKindex;
CCKSwingNeedUpdate = 1;
}
if (CCKSwingNeedUpdate)
rtl92e_dm_cck_txpower_adjust(dev, priv->bcck_in_ch14);
- if (priv->OFDM_index[0] != tmpOFDMindex) {
- priv->OFDM_index[0] = tmpOFDMindex;
+ if (priv->ofdm_index[0] != tmpOFDMindex) {
+ priv->ofdm_index[0] = tmpOFDMindex;
rtl92e_set_bb_reg(dev, rOFDM0_XATxIQImbalance, bMaskDWord,
- OFDMSwingTable[priv->OFDM_index[0]]);
+ OFDMSwingTable[priv->ofdm_index[0]]);
}
priv->txpower_count = 0;
}
@@ -857,7 +855,7 @@ void rtl92e_dm_txpower_tracking_wq(void *data)
struct r8192_priv, txpower_tracking_wq);
struct net_device *dev = priv->rtllib->dev;
- if (priv->IC_Cut >= IC_VersionCut_D)
+ if (priv->ic_cut >= IC_VersionCut_D)
_rtl92e_dm_tx_power_tracking_callback_tssi(dev);
else
_rtl92e_dm_tx_power_tracking_cb_thermal(dev);
@@ -870,7 +868,7 @@ static void _rtl92e_dm_initialize_tx_power_tracking_tssi(struct net_device *dev)
priv->btxpower_tracking = true;
priv->txpower_count = 0;
- priv->btxpower_trackingInit = false;
+ priv->tx_pwr_tracking_init = false;
}
@@ -884,14 +882,14 @@ static void _rtl92e_dm_init_tx_power_tracking_thermal(struct net_device *dev)
else
priv->btxpower_tracking = false;
priv->txpower_count = 0;
- priv->btxpower_trackingInit = false;
+ priv->tx_pwr_tracking_init = false;
}
void rtl92e_dm_init_txpower_tracking(struct net_device *dev)
{
struct r8192_priv *priv = rtllib_priv(dev);
- if (priv->IC_Cut >= IC_VersionCut_D)
+ if (priv->ic_cut >= IC_VersionCut_D)
_rtl92e_dm_initialize_tx_power_tracking_tssi(dev);
else
_rtl92e_dm_init_tx_power_tracking_thermal(dev);
@@ -952,7 +950,7 @@ static void _rtl92e_dm_check_tx_power_tracking(struct net_device *dev)
{
struct r8192_priv *priv = rtllib_priv(dev);
- if (priv->IC_Cut >= IC_VersionCut_D)
+ if (priv->ic_cut >= IC_VersionCut_D)
_rtl92e_dm_check_tx_power_tracking_tssi(dev);
else
_rtl92e_dm_check_tx_power_tracking_thermal(dev);
@@ -1005,30 +1003,30 @@ static void _rtl92e_dm_cck_tx_power_adjust_thermal_meter(struct net_device *dev,
TempVal = 0;
if (!bInCH14) {
- TempVal = CCKSwingTable_Ch1_Ch13[priv->CCK_index][0] +
- (CCKSwingTable_Ch1_Ch13[priv->CCK_index][1] << 8);
+ TempVal = CCKSwingTable_Ch1_Ch13[priv->cck_index][0] +
+ (CCKSwingTable_Ch1_Ch13[priv->cck_index][1] << 8);
rtl92e_set_bb_reg(dev, rCCK0_TxFilter1, bMaskHWord, TempVal);
- TempVal = CCKSwingTable_Ch1_Ch13[priv->CCK_index][2] +
- (CCKSwingTable_Ch1_Ch13[priv->CCK_index][3] << 8) +
- (CCKSwingTable_Ch1_Ch13[priv->CCK_index][4] << 16)+
- (CCKSwingTable_Ch1_Ch13[priv->CCK_index][5] << 24);
+ TempVal = CCKSwingTable_Ch1_Ch13[priv->cck_index][2] +
+ (CCKSwingTable_Ch1_Ch13[priv->cck_index][3] << 8) +
+ (CCKSwingTable_Ch1_Ch13[priv->cck_index][4] << 16)+
+ (CCKSwingTable_Ch1_Ch13[priv->cck_index][5] << 24);
rtl92e_set_bb_reg(dev, rCCK0_TxFilter2, bMaskDWord, TempVal);
- TempVal = CCKSwingTable_Ch1_Ch13[priv->CCK_index][6] +
- (CCKSwingTable_Ch1_Ch13[priv->CCK_index][7] << 8);
+ TempVal = CCKSwingTable_Ch1_Ch13[priv->cck_index][6] +
+ (CCKSwingTable_Ch1_Ch13[priv->cck_index][7] << 8);
rtl92e_set_bb_reg(dev, rCCK0_DebugPort, bMaskLWord, TempVal);
} else {
- TempVal = CCKSwingTable_Ch14[priv->CCK_index][0] +
- (CCKSwingTable_Ch14[priv->CCK_index][1] << 8);
+ TempVal = CCKSwingTable_Ch14[priv->cck_index][0] +
+ (CCKSwingTable_Ch14[priv->cck_index][1] << 8);
rtl92e_set_bb_reg(dev, rCCK0_TxFilter1, bMaskHWord, TempVal);
- TempVal = CCKSwingTable_Ch14[priv->CCK_index][2] +
- (CCKSwingTable_Ch14[priv->CCK_index][3] << 8) +
- (CCKSwingTable_Ch14[priv->CCK_index][4] << 16)+
- (CCKSwingTable_Ch14[priv->CCK_index][5] << 24);
+ TempVal = CCKSwingTable_Ch14[priv->cck_index][2] +
+ (CCKSwingTable_Ch14[priv->cck_index][3] << 8) +
+ (CCKSwingTable_Ch14[priv->cck_index][4] << 16)+
+ (CCKSwingTable_Ch14[priv->cck_index][5] << 24);
rtl92e_set_bb_reg(dev, rCCK0_TxFilter2, bMaskDWord, TempVal);
- TempVal = CCKSwingTable_Ch14[priv->CCK_index][6] +
- (CCKSwingTable_Ch14[priv->CCK_index][7]<<8);
+ TempVal = CCKSwingTable_Ch14[priv->cck_index][6] +
+ (CCKSwingTable_Ch14[priv->cck_index][7]<<8);
rtl92e_set_bb_reg(dev, rCCK0_DebugPort, bMaskLWord, TempVal);
}
@@ -1038,7 +1036,7 @@ void rtl92e_dm_cck_txpower_adjust(struct net_device *dev, bool binch14)
{
struct r8192_priv *priv = rtllib_priv(dev);
- if (priv->IC_Cut >= IC_VersionCut_D)
+ if (priv->ic_cut >= IC_VersionCut_D)
_rtl92e_dm_cck_tx_power_adjust_tssi(dev, binch14);
else
_rtl92e_dm_cck_tx_power_adjust_thermal_meter(dev, binch14);
@@ -1075,7 +1073,7 @@ void rtl92e_dm_restore_state(struct net_device *dev)
ratr_value &= ~(RATE_ALL_OFDM_2SS);
rtl92e_writel(dev, RATR0, ratr_value);
rtl92e_writeb(dev, UFWP, 1);
- if (priv->btxpower_trackingInit && priv->btxpower_tracking)
+ if (priv->tx_pwr_tracking_init && priv->btxpower_tracking)
_rtl92e_dm_tx_power_reset_recovery(dev);
_rtl92e_dm_bb_initialgain_restore(dev);
@@ -1150,7 +1148,7 @@ static void _rtl92e_dm_dig_init(struct net_device *dev)
dm_digtable.rssi_val = 50;
dm_digtable.backoff_val = DM_DIG_BACKOFF;
dm_digtable.rx_gain_range_max = DM_DIG_MAX;
- if (priv->CustomerID == RT_CID_819x_Netcore)
+ if (priv->customer_id == RT_CID_819X_NETCORE)
dm_digtable.rx_gain_range_min = DM_DIG_MIN_Netcore;
else
dm_digtable.rx_gain_range_min = DM_DIG_MIN;
@@ -1260,7 +1258,7 @@ static void _rtl92e_dm_ctrl_initgain_byrssi_false_alarm(struct net_device *dev)
rtl92e_writeb(dev, rOFDM0_XCAGCCore1, 0x17);
rtl92e_writeb(dev, rOFDM0_XDAGCCore1, 0x17);
- if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)
+ if (priv->current_chnl_bw != HT_CHANNEL_WIDTH_20)
rtl92e_writeb(dev, (rOFDM0_XATxAFE+3), 0x00);
else
rtl92e_writeb(dev, rOFDM0_RxDetector1, 0x42);
@@ -1297,7 +1295,7 @@ static void _rtl92e_dm_ctrl_initgain_byrssi_false_alarm(struct net_device *dev)
rtl92e_writeb(dev, rOFDM0_XDAGCCore1, 0x20);
}
- if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)
+ if (priv->current_chnl_bw != HT_CHANNEL_WIDTH_20)
rtl92e_writeb(dev, (rOFDM0_XATxAFE+3), 0x20);
else
rtl92e_writeb(dev, rOFDM0_RxDetector1, 0x44);
@@ -1328,7 +1326,7 @@ static void _rtl92e_dm_ctrl_initgain_byrssi_highpwr(struct net_device *dev)
return;
dm_digtable.dig_highpwr_state = DM_STA_DIG_ON;
- if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)
+ if (priv->current_chnl_bw != HT_CHANNEL_WIDTH_20)
rtl92e_writeb(dev, (rOFDM0_XATxAFE+3), 0x10);
else
rtl92e_writeb(dev, rOFDM0_RxDetector1, 0x43);
@@ -1342,7 +1340,7 @@ static void _rtl92e_dm_ctrl_initgain_byrssi_highpwr(struct net_device *dev)
dm_digtable.rssi_high_power_lowthresh) &&
(priv->undecorated_smoothed_pwdb >=
dm_digtable.rssi_high_thresh)) {
- if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)
+ if (priv->current_chnl_bw != HT_CHANNEL_WIDTH_20)
rtl92e_writeb(dev, (rOFDM0_XATxAFE+3), 0x20);
else
rtl92e_writeb(dev, rOFDM0_RxDetector1, 0x44);
@@ -1378,12 +1376,12 @@ static void _rtl92e_dm_initial_gain(struct net_device *dev)
dm_digtable.cur_ig_value = gain_range;
} else {
if (dm_digtable.cur_ig_value == 0)
- dm_digtable.cur_ig_value = priv->DefaultInitialGain[0];
+ dm_digtable.cur_ig_value = priv->def_initial_gain[0];
else
dm_digtable.cur_ig_value = dm_digtable.pre_ig_value;
}
} else {
- dm_digtable.cur_ig_value = priv->DefaultInitialGain[0];
+ dm_digtable.cur_ig_value = priv->def_initial_gain[0];
dm_digtable.pre_ig_value = 0;
}
@@ -1453,18 +1451,18 @@ static void _rtl92e_dm_pd_th(struct net_device *dev)
if ((dm_digtable.prepd_thstate != dm_digtable.curpd_thstate) ||
(initialized <= 3) || force_write) {
if (dm_digtable.curpd_thstate == DIG_PD_AT_LOW_POWER) {
- if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)
+ if (priv->current_chnl_bw != HT_CHANNEL_WIDTH_20)
rtl92e_writeb(dev, (rOFDM0_XATxAFE+3), 0x00);
else
rtl92e_writeb(dev, rOFDM0_RxDetector1, 0x42);
} else if (dm_digtable.curpd_thstate ==
DIG_PD_AT_NORMAL_POWER) {
- if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)
+ if (priv->current_chnl_bw != HT_CHANNEL_WIDTH_20)
rtl92e_writeb(dev, (rOFDM0_XATxAFE+3), 0x20);
else
rtl92e_writeb(dev, rOFDM0_RxDetector1, 0x44);
} else if (dm_digtable.curpd_thstate == DIG_PD_AT_HIGH_POWER) {
- if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)
+ if (priv->current_chnl_bw != HT_CHANNEL_WIDTH_20)
rtl92e_writeb(dev, (rOFDM0_XATxAFE+3), 0x10);
else
rtl92e_writeb(dev, rOFDM0_RxDetector1, 0x43);
@@ -1651,7 +1649,7 @@ static void _rtl92e_dm_init_wa_broadcom_iot(struct net_device *dev)
struct rt_hi_throughput *ht_info = priv->rtllib->ht_info;
ht_info->bWAIotBroadcom = false;
- ht_info->WAIotTH = WAIotTHVal;
+ ht_info->WAIotTH = WA_IOT_TH_VAL;
}
static void _rtl92e_dm_check_rf_ctrl_gpio(void *data)
@@ -1722,7 +1720,7 @@ void rtl92e_dm_rf_pathcheck_wq(void *data)
else
priv->brfpath_rxenable[i] = false;
}
- if (!DM_RxPathSelTable.Enable)
+ if (!dm_rx_path_sel_table.enable)
return;
_rtl92e_dm_rx_path_sel_byrssi(dev);
@@ -1733,18 +1731,18 @@ static void _rtl92e_dm_init_rx_path_selection(struct net_device *dev)
u8 i;
struct r8192_priv *priv = rtllib_priv(dev);
- DM_RxPathSelTable.Enable = 1;
- DM_RxPathSelTable.SS_TH_low = RxPathSelection_SS_TH_low;
- DM_RxPathSelTable.diff_TH = RxPathSelection_diff_TH;
- if (priv->CustomerID == RT_CID_819x_Netcore)
- DM_RxPathSelTable.cck_method = CCK_Rx_Version_2;
+ dm_rx_path_sel_table.enable = 1;
+ dm_rx_path_sel_table.ss_th_low = RX_PATH_SEL_SS_TH_LOW;
+ dm_rx_path_sel_table.diff_th = RX_PATH_SEL_DIFF_TH;
+ if (priv->customer_id == RT_CID_819X_NETCORE)
+ dm_rx_path_sel_table.cck_method = CCK_Rx_Version_2;
else
- DM_RxPathSelTable.cck_method = CCK_Rx_Version_1;
- DM_RxPathSelTable.disabledRF = 0;
+ dm_rx_path_sel_table.cck_method = CCK_Rx_Version_1;
+ dm_rx_path_sel_table.disabled_rf = 0;
for (i = 0; i < 4; i++) {
- DM_RxPathSelTable.rf_rssi[i] = 50;
- DM_RxPathSelTable.cck_pwdb_sta[i] = -64;
- DM_RxPathSelTable.rf_enable_rssi_th[i] = 100;
+ dm_rx_path_sel_table.rf_rssi[i] = 50;
+ dm_rx_path_sel_table.cck_pwdb_sta[i] = -64;
+ dm_rx_path_sel_table.rf_enable_rssi_th[i] = 100;
}
}
@@ -1771,22 +1769,22 @@ static void _rtl92e_dm_rx_path_sel_byrssi(struct net_device *dev)
return;
if (!cck_Rx_Path_initialized) {
- DM_RxPathSelTable.cck_Rx_path = (rtl92e_readb(dev, 0xa07)&0xf);
+ dm_rx_path_sel_table.cck_rx_path = (rtl92e_readb(dev, 0xa07)&0xf);
cck_Rx_Path_initialized = 1;
}
- DM_RxPathSelTable.disabledRF = 0xf;
- DM_RxPathSelTable.disabledRF &= ~(rtl92e_readb(dev, 0xc04));
+ dm_rx_path_sel_table.disabled_rf = 0xf;
+ dm_rx_path_sel_table.disabled_rf &= ~(rtl92e_readb(dev, 0xc04));
if (priv->rtllib->mode == WIRELESS_MODE_B)
- DM_RxPathSelTable.cck_method = CCK_Rx_Version_2;
+ dm_rx_path_sel_table.cck_method = CCK_Rx_Version_2;
for (i = 0; i < RF90_PATH_MAX; i++) {
- DM_RxPathSelTable.rf_rssi[i] = priv->stats.rx_rssi_percentage[i];
+ dm_rx_path_sel_table.rf_rssi[i] = priv->stats.rx_rssi_percentage[i];
if (priv->brfpath_rxenable[i]) {
rf_num++;
- cur_rf_rssi = DM_RxPathSelTable.rf_rssi[i];
+ cur_rf_rssi = dm_rx_path_sel_table.rf_rssi[i];
if (rf_num == 1) {
max_rssi_index = min_rssi_index = sec_rssi_index = i;
@@ -1834,12 +1832,12 @@ static void _rtl92e_dm_rx_path_sel_byrssi(struct net_device *dev)
}
rf_num = 0;
- if (DM_RxPathSelTable.cck_method == CCK_Rx_Version_2) {
+ if (dm_rx_path_sel_table.cck_method == CCK_Rx_Version_2) {
for (i = 0; i < RF90_PATH_MAX; i++) {
if (priv->brfpath_rxenable[i]) {
rf_num++;
cur_cck_pwdb =
- DM_RxPathSelTable.cck_pwdb_sta[i];
+ dm_rx_path_sel_table.cck_pwdb_sta[i];
if (rf_num == 1) {
cck_rx_ver2_max_index = i;
@@ -1896,17 +1894,17 @@ static void _rtl92e_dm_rx_path_sel_byrssi(struct net_device *dev)
}
update_cck_rx_path = 0;
- if (DM_RxPathSelTable.cck_method == CCK_Rx_Version_2) {
+ if (dm_rx_path_sel_table.cck_method == CCK_Rx_Version_2) {
cck_default_Rx = cck_rx_ver2_max_index;
cck_optional_Rx = cck_rx_ver2_sec_index;
if (tmp_cck_max_pwdb != -64)
update_cck_rx_path = 1;
}
- if (tmp_min_rssi < DM_RxPathSelTable.SS_TH_low && disabled_rf_cnt < 2) {
+ if (tmp_min_rssi < dm_rx_path_sel_table.ss_th_low && disabled_rf_cnt < 2) {
if ((tmp_max_rssi - tmp_min_rssi) >=
- DM_RxPathSelTable.diff_TH) {
- DM_RxPathSelTable.rf_enable_rssi_th[min_rssi_index] =
+ dm_rx_path_sel_table.diff_th) {
+ dm_rx_path_sel_table.rf_enable_rssi_th[min_rssi_index] =
tmp_max_rssi+5;
rtl92e_set_bb_reg(dev, rOFDM0_TRxPathEnable,
0x1<<min_rssi_index, 0x0);
@@ -1914,7 +1912,7 @@ static void _rtl92e_dm_rx_path_sel_byrssi(struct net_device *dev)
0x1<<min_rssi_index, 0x0);
disabled_rf_cnt++;
}
- if (DM_RxPathSelTable.cck_method == CCK_Rx_Version_1) {
+ if (dm_rx_path_sel_table.cck_method == CCK_Rx_Version_1) {
cck_default_Rx = max_rssi_index;
cck_optional_Rx = sec_rssi_index;
if (tmp_max_rssi)
@@ -1923,24 +1921,24 @@ static void _rtl92e_dm_rx_path_sel_byrssi(struct net_device *dev)
}
if (update_cck_rx_path) {
- DM_RxPathSelTable.cck_Rx_path = (cck_default_Rx<<2) |
+ dm_rx_path_sel_table.cck_rx_path = (cck_default_Rx<<2) |
(cck_optional_Rx);
rtl92e_set_bb_reg(dev, rCCK0_AFESetting, 0x0f000000,
- DM_RxPathSelTable.cck_Rx_path);
+ dm_rx_path_sel_table.cck_rx_path);
}
- if (DM_RxPathSelTable.disabledRF) {
+ if (dm_rx_path_sel_table.disabled_rf) {
for (i = 0; i < 4; i++) {
- if ((DM_RxPathSelTable.disabledRF>>i) & 0x1) {
+ if ((dm_rx_path_sel_table.disabled_rf >> i) & 0x1) {
if (tmp_max_rssi >=
- DM_RxPathSelTable.rf_enable_rssi_th[i]) {
+ dm_rx_path_sel_table.rf_enable_rssi_th[i]) {
rtl92e_set_bb_reg(dev,
rOFDM0_TRxPathEnable,
0x1 << i, 0x1);
rtl92e_set_bb_reg(dev,
rOFDM1_TRxPathEnable,
0x1 << i, 0x1);
- DM_RxPathSelTable.rf_enable_rssi_th[i]
+ dm_rx_path_sel_table.rf_enable_rssi_th[i]
= 100;
disabled_rf_cnt--;
}
@@ -1969,7 +1967,7 @@ static void _rtl92e_dm_init_fsync(struct net_device *dev)
priv->rtllib->fsync_firstdiff_ratethreshold = 100;
priv->rtllib->fsync_seconddiff_ratethreshold = 200;
priv->rtllib->fsync_state = Default_Fsync;
- priv->framesyncMonitor = 1;
+ priv->frame_sync_monitor = 1;
timer_setup(&priv->fsync_timer, _rtl92e_dm_fsync_timer_callback, 0);
}
@@ -2008,31 +2006,31 @@ static void _rtl92e_dm_fsync_timer_callback(struct timer_list *t)
priv->rate_record;
else
rate_count_diff = rate_count - priv->rate_record;
- if (rate_count_diff < priv->rateCountDiffRecord) {
+ if (rate_count_diff < priv->rate_count_diff_rec) {
- u32 DiffNum = priv->rateCountDiffRecord -
+ u32 DiffNum = priv->rate_count_diff_rec -
rate_count_diff;
if (DiffNum >=
priv->rtllib->fsync_seconddiff_ratethreshold)
- priv->ContinueDiffCount++;
+ priv->continue_diff_count++;
else
- priv->ContinueDiffCount = 0;
+ priv->continue_diff_count = 0;
- if (priv->ContinueDiffCount >= 2) {
+ if (priv->continue_diff_count >= 2) {
bSwitchFromCountDiff = true;
- priv->ContinueDiffCount = 0;
+ priv->continue_diff_count = 0;
}
} else {
- priv->ContinueDiffCount = 0;
+ priv->continue_diff_count = 0;
}
if (rate_count_diff <=
priv->rtllib->fsync_firstdiff_ratethreshold) {
bSwitchFromCountDiff = true;
- priv->ContinueDiffCount = 0;
+ priv->continue_diff_count = 0;
}
priv->rate_record = rate_count;
- priv->rateCountDiffRecord = rate_count_diff;
+ priv->rate_count_diff_rec = rate_count_diff;
if (priv->undecorated_smoothed_pwdb >
priv->rtllib->fsync_rssi_threshold &&
bSwitchFromCountDiff) {
@@ -2073,7 +2071,7 @@ static void _rtl92e_dm_fsync_timer_callback(struct timer_list *t)
rtl92e_writeb(dev, 0xC36, 0x5c);
rtl92e_writeb(dev, 0xC3e, 0x96);
}
- priv->ContinueDiffCount = 0;
+ priv->continue_diff_count = 0;
rtl92e_writel(dev, rOFDM0_RxDetector2, 0x465c52cd);
}
}
@@ -2114,7 +2112,7 @@ static void _rtl92e_dm_end_sw_fsync(struct net_device *dev)
rtl92e_writeb(dev, 0xC3e, 0x96);
}
- priv->ContinueDiffCount = 0;
+ priv->continue_diff_count = 0;
rtl92e_writel(dev, rOFDM0_RxDetector2, 0x465c52cd);
}
@@ -2125,8 +2123,8 @@ static void _rtl92e_dm_start_sw_fsync(struct net_device *dev)
u32 rate_bitmap;
priv->rate_record = 0;
- priv->ContinueDiffCount = 0;
- priv->rateCountDiffRecord = 0;
+ priv->continue_diff_count = 0;
+ priv->rate_count_diff_rec = 0;
priv->bswitch_fsync = false;
if (priv->rtllib->mode == WIRELESS_MODE_N_24G) {
@@ -2196,7 +2194,7 @@ static void _rtl92e_dm_check_fsync(struct net_device *dev)
}
}
- if (priv->framesyncMonitor) {
+ if (priv->frame_sync_monitor) {
if (reg_c38_State != RegC38_Fsync_AP_BCM) {
rtl92e_writeb(dev, rOFDM0_RxDetector3, 0x95);
@@ -2218,7 +2216,7 @@ static void _rtl92e_dm_check_fsync(struct net_device *dev)
break;
}
- if (priv->framesyncMonitor) {
+ if (priv->frame_sync_monitor) {
if (priv->rtllib->state == RTLLIB_LINKED) {
if (priv->undecorated_smoothed_pwdb <=
RegC38_TH) {
@@ -2249,7 +2247,7 @@ static void _rtl92e_dm_check_fsync(struct net_device *dev)
}
}
}
- if (priv->framesyncMonitor) {
+ if (priv->frame_sync_monitor) {
if (priv->reset_count != reset_cnt) {
rtl92e_writeb(dev, rOFDM0_RxDetector3,
priv->framesync);
@@ -2271,10 +2269,10 @@ static void _rtl92e_dm_init_dynamic_tx_power(struct net_device *dev)
struct r8192_priv *priv = rtllib_priv(dev);
priv->rtllib->bdynamic_txpower_enable = true;
- priv->bLastDTPFlag_High = false;
- priv->bLastDTPFlag_Low = false;
- priv->bDynamicTxHighPower = false;
- priv->bDynamicTxLowPower = false;
+ priv->last_dtp_flag_high = false;
+ priv->last_dtp_flag_low = false;
+ priv->dynamic_tx_high_pwr = false;
+ priv->dynamic_tx_low_pwr = false;
}
static void _rtl92e_dm_dynamic_tx_power(struct net_device *dev)
@@ -2284,8 +2282,8 @@ static void _rtl92e_dm_dynamic_tx_power(struct net_device *dev)
unsigned int txlowpower_threshold = 0;
if (!priv->rtllib->bdynamic_txpower_enable) {
- priv->bDynamicTxHighPower = false;
- priv->bDynamicTxLowPower = false;
+ priv->dynamic_tx_high_pwr = false;
+ priv->dynamic_tx_low_pwr = false;
return;
}
if ((priv->rtllib->ht_info->IOTPeer == HT_IOT_PEER_ATHEROS) &&
@@ -2299,28 +2297,28 @@ static void _rtl92e_dm_dynamic_tx_power(struct net_device *dev)
if (priv->rtllib->state == RTLLIB_LINKED) {
if (priv->undecorated_smoothed_pwdb >= txhipower_threshold) {
- priv->bDynamicTxHighPower = true;
- priv->bDynamicTxLowPower = false;
+ priv->dynamic_tx_high_pwr = true;
+ priv->dynamic_tx_low_pwr = false;
} else {
if (priv->undecorated_smoothed_pwdb <
- txlowpower_threshold && priv->bDynamicTxHighPower)
- priv->bDynamicTxHighPower = false;
+ txlowpower_threshold && priv->dynamic_tx_high_pwr)
+ priv->dynamic_tx_high_pwr = false;
if (priv->undecorated_smoothed_pwdb < 35)
- priv->bDynamicTxLowPower = true;
+ priv->dynamic_tx_low_pwr = true;
else if (priv->undecorated_smoothed_pwdb >= 40)
- priv->bDynamicTxLowPower = false;
+ priv->dynamic_tx_low_pwr = false;
}
} else {
- priv->bDynamicTxHighPower = false;
- priv->bDynamicTxLowPower = false;
+ priv->dynamic_tx_high_pwr = false;
+ priv->dynamic_tx_low_pwr = false;
}
- if ((priv->bDynamicTxHighPower != priv->bLastDTPFlag_High) ||
- (priv->bDynamicTxLowPower != priv->bLastDTPFlag_Low)) {
+ if ((priv->dynamic_tx_high_pwr != priv->last_dtp_flag_high) ||
+ (priv->dynamic_tx_low_pwr != priv->last_dtp_flag_low)) {
rtl92e_set_tx_power(dev, priv->rtllib->current_network.channel);
}
- priv->bLastDTPFlag_High = priv->bDynamicTxHighPower;
- priv->bLastDTPFlag_Low = priv->bDynamicTxLowPower;
+ priv->last_dtp_flag_high = priv->dynamic_tx_high_pwr;
+ priv->last_dtp_flag_low = priv->dynamic_tx_low_pwr;
}
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h
index 1d4d7d98a859..01587e2fec65 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h
@@ -7,10 +7,9 @@
#ifndef __R8192UDM_H__
#define __R8192UDM_H__
-
/*--------------------------Define Parameters-------------------------------*/
-#define OFDM_Table_Length 19
-#define CCK_Table_length 12
+#define OFDM_TABLE_LEN 19
+#define CCK_TABLE_LEN 12
#define DM_DIG_THRESH_HIGH 40
#define DM_DIG_THRESH_LOW 35
@@ -26,15 +25,15 @@
#define DM_DIG_MIN 0x1c
#define DM_DIG_MIN_Netcore 0x12
-#define RxPathSelection_SS_TH_low 30
-#define RxPathSelection_diff_TH 18
+#define RX_PATH_SEL_SS_TH_LOW 30
+#define RX_PATH_SEL_DIFF_TH 18
-#define RateAdaptiveTH_High 50
-#define RateAdaptiveTH_Low_20M 30
-#define RateAdaptiveTH_Low_40M 10
-#define VeryLowRSSI 15
+#define RATE_ADAPTIVE_TH_HIGH 50
+#define RATE_ADAPTIVE_TH_LOW_20M 30
+#define RATE_ADAPTIVE_TH_LOW_40M 10
+#define VERY_LOW_RSSI 15
-#define WAIotTHVal 25
+#define WA_IOT_TH_VAL 25
#define E_FOR_TX_POWER_TRACK 300
#define TX_POWER_NEAR_FIELD_THRESH_HIGH 68
@@ -47,11 +46,8 @@
#define TX_RETRY_COUNT_REG 0x1ac
#define RegC38_TH 20
-#define DM_Type_ByDriver 1
-
/*--------------------------Define Parameters-------------------------------*/
-
/*------------------------------Define structure----------------------------*/
struct dig_t {
u8 dig_enable_flag;
@@ -90,7 +86,6 @@ enum dm_dig_sta {
DM_STA_DIG_MAX
};
-
enum dm_ratr_sta {
DM_RATR_STA_HIGH = 0,
DM_RATR_STA_MIDDLE = 1,
@@ -130,13 +125,13 @@ enum dm_dig_cs_ratio {
};
struct drx_path_sel {
- u8 Enable;
+ u8 enable;
u8 cck_method;
- u8 cck_Rx_path;
+ u8 cck_rx_path;
- u8 SS_TH_low;
- u8 diff_TH;
- u8 disabledRF;
+ u8 ss_th_low;
+ u8 diff_th;
+ u8 disabled_rf;
u8 reserved;
u8 rf_rssi[4];
@@ -150,29 +145,26 @@ enum dm_cck_rx_path_method {
CCK_Rx_Version_MAX
};
-
struct dcmd_txcmd {
u32 op;
u32 length;
u32 value;
};
-/*------------------------------Define structure----------------------------*/
+/*------------------------------Define structure----------------------------*/
/*------------------------Export global variable----------------------------*/
extern struct dig_t dm_digtable;
-extern struct drx_path_sel DM_RxPathSelTable;
/* Pre-calculated gain tables */
-extern const u32 dm_tx_bb_gain[TxBBGainTableLength];
-extern const u8 dm_cck_tx_bb_gain[CCKTxBBGainTableLength][8];
-extern const u8 dm_cck_tx_bb_gain_ch14[CCKTxBBGainTableLength][8];
+extern const u32 dm_tx_bb_gain[TX_BB_GAIN_TABLE_LEN];
+extern const u8 dm_cck_tx_bb_gain[CCK_TX_BB_GAIN_TABLE_LEN][8];
+extern const u8 dm_cck_tx_bb_gain_ch14[CCK_TX_BB_GAIN_TABLE_LEN][8];
/* Maps table index to iq amplify gain (dB, 12 to -24dB) */
#define dm_tx_bb_gain_idx_to_amplify(idx) (-idx + 12)
/*------------------------Export global variable----------------------------*/
-
/*--------------------------Exported Function prototype---------------------*/
/*--------------------------Exported Function prototype---------------------*/
@@ -181,7 +173,6 @@ void rtl92e_dm_deinit(struct net_device *dev);
void rtl92e_dm_watchdog(struct net_device *dev);
-
void rtl92e_init_adaptive_rate(struct net_device *dev);
void rtl92e_dm_txpower_tracking_wq(void *data);
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c
index 82b45c61ac75..9c80dc1b6e12 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c
@@ -41,7 +41,7 @@ int rtl92e_suspend(struct device *dev_d)
rtl92e_writel(dev, WFCRC1, 0xffffffff);
rtl92e_writel(dev, WFCRC2, 0xffffffff);
rtl92e_writeb(dev, PMR, 0x5);
- rtl92e_writeb(dev, MacBlkCtrl, 0xa);
+ rtl92e_writeb(dev, MAC_BLK_CTRL, 0xa);
}
out_pci_suspend:
netdev_info(dev, "WOL is %s\n", priv->rtllib->bSupportRemoteWakeUp ?
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211.h b/drivers/staging/rtl8192u/ieee80211/ieee80211.h
index c5c43d2fb93e..694d1b18f81c 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211.h
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211.h
@@ -1823,7 +1823,7 @@ struct ieee80211_device {
struct work_struct associate_procedure_wq;
struct delayed_work softmac_scan_wq;
struct delayed_work associate_retry_wq;
- struct delayed_work start_ibss_wq;
+ struct delayed_work start_ibss_wq;
struct work_struct wx_sync_scan_wq;
struct workqueue_struct *wq;
// Qos related. Added by Annie, 2005-11-01.
diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c
index f1fc077ed29c..0fcae6871108 100644
--- a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c
+++ b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c
@@ -653,7 +653,7 @@ static void Hal_EfusePowerSwitch(
if (PwrState) {
- /* To avoid cannot access efuse regsiters after disable/enable several times during DTM test. */
+ /* To avoid cannot access efuse registers after disable/enable several times during DTM test. */
/* Suggested by SD1 IsaacHsu. 2013.07.08, added by tynli. */
tempval = rtw_read8(padapter, SDIO_LOCAL_BASE|SDIO_REG_HSUS_CTRL);
if (tempval & BIT(0)) { /* SDIO local register is suspend */
@@ -1693,7 +1693,7 @@ void rtl8723b_InitBeaconParameters(struct adapter *padapter)
rtw_write8(padapter, REG_BCNDMATIM, BCN_DMA_ATIME_INT_TIME_8723B); /* 2ms */
/* Suggested by designer timchen. Change beacon AIFS to the largest number */
- /* beacause test chip does not contension before sending beacon. by tynli. 2009.11.03 */
+ /* because test chip does not contension before sending beacon. by tynli. 2009.11.03 */
rtw_write16(padapter, REG_BCNTCFG, 0x660F);
pHalData->RegBcnCtrlVal = rtw_read8(padapter, REG_BCN_CTRL);
@@ -2089,7 +2089,7 @@ void Hal_EfuseParseIDCode(struct adapter *padapter, u8 *hwinfo)
u16 EEPROMId;
- /* Checl 0x8129 again for making sure autoload status!! */
+ /* Check 0x8129 again for making sure autoload status!! */
EEPROMId = le16_to_cpu(*((__le16 *)hwinfo));
if (EEPROMId != RTL_EEPROM_ID) {
pEEPROM->bautoload_fail_flag = true;
@@ -2510,7 +2510,7 @@ static void rtl8723b_cal_txdesc_chksum(struct tx_desc *ptxdesc)
/* Clear first */
ptxdesc->txdw7 &= cpu_to_le32(0xffff0000);
- /* checksume is always calculated by first 32 bytes, */
+ /* checksum is always calculated by first 32 bytes, */
/* and it doesn't depend on TX DESC length. */
/* Thomas, Lucas@SD4, 20130515 */
count = 16;
@@ -2723,7 +2723,7 @@ static void rtl8723b_fill_default_txdesc(
* multicast / mgnt frame should be controlled by Hw because Fw
* will also send null data which we cannot control when Fw LPS
* enable.
- * --> default enable non-Qos data sequense number. 2010.06.23.
+ * --> default enable non-Qos data sequence number. 2010.06.23.
* by tynli.
* (2) Enable HW SEQ control for beacon packet, because we use
* Hw beacon.
@@ -2777,7 +2777,7 @@ void rtl8723b_fill_fake_txdesc(
SET_TX_DESC_PKT_SIZE_8723B(pDesc, BufferLen); /* Buffer size + command header */
SET_TX_DESC_QUEUE_SEL_8723B(pDesc, QSLT_MGNT); /* Fixed queue of Mgnt queue */
- /* Set NAVUSEHDR to prevent Ps-poll AId filed to be changed to error vlaue by Hw. */
+ /* Set NAVUSEHDR to prevent Ps-poll AId filed to be changed to error value by Hw. */
if (IsPsPoll) {
SET_TX_DESC_NAV_USE_HDR_8723B(pDesc, 1);
} else {
@@ -3406,7 +3406,7 @@ void SetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val)
/* polling bit, and No Write enable, and address */
ulCommand = CAM_CONTENT_COUNT*ucIndex+i;
ulCommand = ulCommand | CAM_POLLINIG | CAM_WRITE;
- /* write content 0 is equall to mark invalid */
+ /* write content 0 is equal to mark as invalid */
rtw_write32(padapter, WCAMI, ulContent); /* mdelay(40); */
rtw_write32(padapter, RWCAM, ulCommand); /* mdelay(40); */
}
diff --git a/drivers/staging/rts5208/ms.c b/drivers/staging/rts5208/ms.c
index 14449f8afad5..bfeb5873bf3b 100644
--- a/drivers/staging/rts5208/ms.c
+++ b/drivers/staging/rts5208/ms.c
@@ -1768,6 +1768,8 @@ static int ms_copy_page(struct rtsx_chip *chip, u16 old_blk, u16 new_blk,
retval = ms_set_rw_reg_addr(chip, OVERWRITE_FLAG, MS_EXTRA_SIZE,
SYSTEM_PARAM, (6 + MS_EXTRA_SIZE));
+ if (retval != STATUS_SUCCESS)
+ return STATUS_FAIL;
ms_set_err_code(chip, MS_NO_ERROR);
diff --git a/drivers/staging/vc04_services/Makefile b/drivers/staging/vc04_services/Makefile
index 1fd191e2e2a5..44794bdf6173 100644
--- a/drivers/staging/vc04_services/Makefile
+++ b/drivers/staging/vc04_services/Makefile
@@ -15,5 +15,3 @@ obj-$(CONFIG_SND_BCM2835) += bcm2835-audio/
obj-$(CONFIG_VIDEO_BCM2835) += bcm2835-camera/
obj-$(CONFIG_BCM2835_VCHIQ_MMAL) += vchiq-mmal/
-ccflags-y += -I $(srctree)/$(src)/include
-
diff --git a/drivers/staging/vc04_services/bcm2835-audio/Makefile b/drivers/staging/vc04_services/bcm2835-audio/Makefile
index d59fe4dde615..01ceebdf88e7 100644
--- a/drivers/staging/vc04_services/bcm2835-audio/Makefile
+++ b/drivers/staging/vc04_services/bcm2835-audio/Makefile
@@ -1,5 +1,3 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_SND_BCM2835) += snd-bcm2835.o
snd-bcm2835-objs := bcm2835.o bcm2835-ctl.o bcm2835-pcm.o bcm2835-vchiq.o
-
-ccflags-y += -I $(srctree)/$(src)/../include -D__VCCOREVER__=0x04000000
diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
index f4c2c9506d86..d74110ca17ab 100644
--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
@@ -91,17 +91,17 @@ static int bcm2835_audio_send_simple(struct bcm2835_audio_instance *instance,
return bcm2835_audio_send_msg(instance, &m, wait);
}
-static enum vchiq_status audio_vchi_callback(struct vchiq_instance *vchiq_instance,
- enum vchiq_reason reason,
- struct vchiq_header *header,
- unsigned int handle, void *userdata)
+static int audio_vchi_callback(struct vchiq_instance *vchiq_instance,
+ enum vchiq_reason reason,
+ struct vchiq_header *header,
+ unsigned int handle, void *userdata)
{
struct bcm2835_audio_instance *instance = vchiq_get_service_userdata(vchiq_instance,
handle);
struct vc_audio_msg *m;
if (reason != VCHIQ_MESSAGE_AVAILABLE)
- return VCHIQ_SUCCESS;
+ return 0;
m = (void *)header->data;
if (m->type == VC_AUDIO_MSG_TYPE_RESULT) {
@@ -119,7 +119,7 @@ static enum vchiq_status audio_vchi_callback(struct vchiq_instance *vchiq_instan
}
vchiq_release_message(vchiq_instance, instance->service_handle, header);
- return VCHIQ_SUCCESS;
+ return 0;
}
static int
diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
index 38b7451d77b2..0a81383c475a 100644
--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h
@@ -6,11 +6,12 @@
#include <linux/device.h>
#include <linux/wait.h>
-#include <linux/raspberrypi/vchiq.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm-indirect.h>
+#include "../include/linux/raspberrypi/vchiq.h"
+
#define MAX_SUBSTREAMS (8)
#define AVAIL_SUBSTREAMS_MASK (0xff)
diff --git a/drivers/staging/vc04_services/bcm2835-camera/Makefile b/drivers/staging/vc04_services/bcm2835-camera/Makefile
index 3a76d6ade428..203b93899b20 100644
--- a/drivers/staging/vc04_services/bcm2835-camera/Makefile
+++ b/drivers/staging/vc04_services/bcm2835-camera/Makefile
@@ -4,8 +4,3 @@ bcm2835-v4l2-$(CONFIG_VIDEO_BCM2835) := \
controls.o
obj-$(CONFIG_VIDEO_BCM2835) += bcm2835-v4l2.o
-
-ccflags-y += \
- -I $(srctree)/$(src)/.. \
- -I $(srctree)/$(src)/../vchiq-mmal/ \
- -D__VCCOREVER__=0x04000000
diff --git a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
index 797ebe2a973a..4f81765912ea 100644
--- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
+++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
@@ -26,11 +26,11 @@
#include <linux/delay.h>
#include <linux/platform_device.h>
-#include "mmal-common.h"
-#include "mmal-encodings.h"
-#include "mmal-vchiq.h"
-#include "mmal-msg.h"
-#include "mmal-parameters.h"
+#include "../vchiq-mmal/mmal-common.h"
+#include "../vchiq-mmal/mmal-encodings.h"
+#include "../vchiq-mmal/mmal-vchiq.h"
+#include "../vchiq-mmal/mmal-msg.h"
+#include "../vchiq-mmal/mmal-parameters.h"
#include "bcm2835-camera.h"
#define MIN_WIDTH 32
diff --git a/drivers/staging/vc04_services/bcm2835-camera/controls.c b/drivers/staging/vc04_services/bcm2835-camera/controls.c
index 5644d1d457b9..6bce45925bf1 100644
--- a/drivers/staging/vc04_services/bcm2835-camera/controls.c
+++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c
@@ -23,9 +23,9 @@
#include <media/v4l2-event.h>
#include <media/v4l2-common.h>
-#include "mmal-common.h"
-#include "mmal-vchiq.h"
-#include "mmal-parameters.h"
+#include "../vchiq-mmal/mmal-common.h"
+#include "../vchiq-mmal/mmal-vchiq.h"
+#include "../vchiq-mmal/mmal-parameters.h"
#include "bcm2835-camera.h"
/* The supported V4L2_CID_AUTO_EXPOSURE_BIAS values are from -4.0 to +4.0.
diff --git a/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h b/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h
index 690ab7165b2c..66965da11443 100644
--- a/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h
+++ b/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h
@@ -17,12 +17,6 @@ enum vchiq_reason {
VCHIQ_BULK_RECEIVE_ABORTED /* service, -, bulk_userdata */
};
-enum vchiq_status {
- VCHIQ_ERROR = -1,
- VCHIQ_SUCCESS = 0,
- VCHIQ_RETRY = 1
-};
-
enum vchiq_bulk_mode {
VCHIQ_BULK_MODE_CALLBACK,
VCHIQ_BULK_MODE_BLOCKING,
@@ -57,11 +51,11 @@ struct vchiq_instance;
struct vchiq_service_base {
int fourcc;
- enum vchiq_status (*callback)(struct vchiq_instance *instance,
- enum vchiq_reason reason,
- struct vchiq_header *header,
- unsigned int handle,
- void *bulk_userdata);
+ int (*callback)(struct vchiq_instance *instance,
+ enum vchiq_reason reason,
+ struct vchiq_header *header,
+ unsigned int handle,
+ void *bulk_userdata);
void *userdata;
};
@@ -74,11 +68,11 @@ struct vchiq_completion_data_kernel {
struct vchiq_service_params_kernel {
int fourcc;
- enum vchiq_status (*callback)(struct vchiq_instance *instance,
- enum vchiq_reason reason,
- struct vchiq_header *header,
- unsigned int handle,
- void *bulk_userdata);
+ int (*callback)(struct vchiq_instance *instance,
+ enum vchiq_reason reason,
+ struct vchiq_header *header,
+ unsigned int handle,
+ void *bulk_userdata);
void *userdata;
short version; /* Increment for non-trivial changes */
short version_min; /* Update for incompatible changes */
@@ -87,32 +81,31 @@ struct vchiq_service_params_kernel {
struct vchiq_instance;
extern int vchiq_initialise(struct vchiq_instance **pinstance);
-extern enum vchiq_status vchiq_shutdown(struct vchiq_instance *instance);
-extern enum vchiq_status vchiq_connect(struct vchiq_instance *instance);
-extern enum vchiq_status vchiq_open_service(struct vchiq_instance *instance,
- const struct vchiq_service_params_kernel *params,
- unsigned int *pservice);
-extern enum vchiq_status vchiq_close_service(struct vchiq_instance *instance,
- unsigned int service);
-extern enum vchiq_status vchiq_use_service(struct vchiq_instance *instance, unsigned int service);
-extern enum vchiq_status vchiq_release_service(struct vchiq_instance *instance,
- unsigned int service);
+extern int vchiq_shutdown(struct vchiq_instance *instance);
+extern int vchiq_connect(struct vchiq_instance *instance);
+extern int vchiq_open_service(struct vchiq_instance *instance,
+ const struct vchiq_service_params_kernel *params,
+ unsigned int *pservice);
+extern int vchiq_close_service(struct vchiq_instance *instance,
+ unsigned int service);
+extern int vchiq_use_service(struct vchiq_instance *instance, unsigned int service);
+extern int vchiq_release_service(struct vchiq_instance *instance,
+ unsigned int service);
extern void vchiq_msg_queue_push(struct vchiq_instance *instance, unsigned int handle,
struct vchiq_header *header);
extern void vchiq_release_message(struct vchiq_instance *instance, unsigned int service,
struct vchiq_header *header);
extern int vchiq_queue_kernel_message(struct vchiq_instance *instance, unsigned int handle,
void *data, unsigned int size);
-extern enum vchiq_status vchiq_bulk_transmit(struct vchiq_instance *instance, unsigned int service,
- const void *data, unsigned int size, void *userdata,
- enum vchiq_bulk_mode mode);
-extern enum vchiq_status vchiq_bulk_receive(struct vchiq_instance *instance, unsigned int service,
- void *data, unsigned int size, void *userdata,
- enum vchiq_bulk_mode mode);
+extern int vchiq_bulk_transmit(struct vchiq_instance *instance, unsigned int service,
+ const void *data, unsigned int size, void *userdata,
+ enum vchiq_bulk_mode mode);
+extern int vchiq_bulk_receive(struct vchiq_instance *instance, unsigned int service,
+ void *data, unsigned int size, void *userdata,
+ enum vchiq_bulk_mode mode);
extern void *vchiq_get_service_userdata(struct vchiq_instance *instance, unsigned int service);
-extern enum vchiq_status vchiq_get_peer_version(struct vchiq_instance *instance,
- unsigned int handle,
- short *peer_version);
+extern int vchiq_get_peer_version(struct vchiq_instance *instance, unsigned int handle,
+ short *peer_version);
extern struct vchiq_header *vchiq_msg_hold(struct vchiq_instance *instance, unsigned int handle);
#endif /* VCHIQ_H */
diff --git a/drivers/staging/vc04_services/interface/TODO b/drivers/staging/vc04_services/interface/TODO
index 97085a0b3223..6d9d4a800aa7 100644
--- a/drivers/staging/vc04_services/interface/TODO
+++ b/drivers/staging/vc04_services/interface/TODO
@@ -40,11 +40,6 @@ beneficial to go over all of them and, if correct, comment on their merits.
Extra points to whomever confidently reviews the remote_event_*() family of
functions.
-* Get rid of custom function return values
-
-Most functions use a custom set of return values, we should force proper Linux
-error numbers. Special care is needed for VCHIQ_RETRY.
-
* Reformat core code with more sane indentations
The code follows the 80 characters limitation yet tends to go 3 or 4 levels of
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
index dc33490ba7fb..cddcd3c596c9 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
@@ -151,7 +151,7 @@ static struct semaphore g_free_fragments_sema;
static DEFINE_SEMAPHORE(g_free_fragments_mutex);
-static enum vchiq_status
+static int
vchiq_blocking_bulk_transfer(struct vchiq_instance *instance, unsigned int handle, void *data,
unsigned int size, enum vchiq_bulk_dir dir);
@@ -501,7 +501,7 @@ int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state *state)
vchiq_slot_zero = vchiq_init_slots(slot_mem, slot_mem_size);
if (!vchiq_slot_zero)
- return -EINVAL;
+ return -ENOMEM;
vchiq_slot_zero->platform_data[VCHIQ_PLATFORM_FRAGMENTS_OFFSET_IDX] =
(int)slot_phys + slot_mem_size;
@@ -541,9 +541,15 @@ int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state *state)
channelbase = slot_phys;
err = rpi_firmware_property(fw, RPI_FIRMWARE_VCHIQ_INIT,
&channelbase, sizeof(channelbase));
- if (err || channelbase) {
- dev_err(dev, "failed to set channelbase\n");
- return err ? : -ENXIO;
+ if (err) {
+ dev_err(dev, "failed to send firmware property: %d\n", err);
+ return err;
+ }
+
+ if (channelbase) {
+ dev_err(dev, "failed to set channelbase (response: %x)\n",
+ channelbase);
+ return -ENXIO;
}
vchiq_log_info(vchiq_arm_log_level, "vchiq_init - done (slots %pK, phys %pad)",
@@ -722,13 +728,13 @@ void free_bulk_waiter(struct vchiq_instance *instance)
}
}
-enum vchiq_status vchiq_shutdown(struct vchiq_instance *instance)
+int vchiq_shutdown(struct vchiq_instance *instance)
{
- enum vchiq_status status = VCHIQ_SUCCESS;
+ int status = 0;
struct vchiq_state *state = instance->state;
if (mutex_lock_killable(&state->mutex))
- return VCHIQ_RETRY;
+ return -EAGAIN;
/* Remove all services */
vchiq_shutdown_internal(state, instance);
@@ -749,19 +755,19 @@ static int vchiq_is_connected(struct vchiq_instance *instance)
return instance->connected;
}
-enum vchiq_status vchiq_connect(struct vchiq_instance *instance)
+int vchiq_connect(struct vchiq_instance *instance)
{
- enum vchiq_status status;
+ int status;
struct vchiq_state *state = instance->state;
if (mutex_lock_killable(&state->mutex)) {
vchiq_log_trace(vchiq_core_log_level, "%s: call to mutex_lock failed", __func__);
- status = VCHIQ_RETRY;
+ status = -EAGAIN;
goto failed;
}
status = vchiq_connect_internal(state, instance);
- if (status == VCHIQ_SUCCESS)
+ if (!status)
instance->connected = 1;
mutex_unlock(&state->mutex);
@@ -773,12 +779,12 @@ failed:
}
EXPORT_SYMBOL(vchiq_connect);
-static enum vchiq_status
+static int
vchiq_add_service(struct vchiq_instance *instance,
const struct vchiq_service_params_kernel *params,
unsigned int *phandle)
{
- enum vchiq_status status;
+ int status;
struct vchiq_state *state = instance->state;
struct vchiq_service *service = NULL;
int srvstate;
@@ -793,9 +799,9 @@ vchiq_add_service(struct vchiq_instance *instance,
if (service) {
*phandle = service->handle;
- status = VCHIQ_SUCCESS;
+ status = 0;
} else {
- status = VCHIQ_ERROR;
+ status = -EINVAL;
}
vchiq_log_trace(vchiq_core_log_level, "%s(%p): returning %d", __func__, instance, status);
@@ -803,12 +809,12 @@ vchiq_add_service(struct vchiq_instance *instance,
return status;
}
-enum vchiq_status
+int
vchiq_open_service(struct vchiq_instance *instance,
const struct vchiq_service_params_kernel *params,
unsigned int *phandle)
{
- enum vchiq_status status = VCHIQ_ERROR;
+ int status = -EINVAL;
struct vchiq_state *state = instance->state;
struct vchiq_service *service = NULL;
@@ -822,7 +828,7 @@ vchiq_open_service(struct vchiq_instance *instance,
if (service) {
*phandle = service->handle;
status = vchiq_open_service_internal(service, current->pid);
- if (status != VCHIQ_SUCCESS) {
+ if (status) {
vchiq_remove_service(instance, service->handle);
*phandle = VCHIQ_SERVICE_HANDLE_INVALID;
}
@@ -835,11 +841,11 @@ failed:
}
EXPORT_SYMBOL(vchiq_open_service);
-enum vchiq_status
+int
vchiq_bulk_transmit(struct vchiq_instance *instance, unsigned int handle, const void *data,
unsigned int size, void *userdata, enum vchiq_bulk_mode mode)
{
- enum vchiq_status status;
+ int status;
while (1) {
switch (mode) {
@@ -855,15 +861,15 @@ vchiq_bulk_transmit(struct vchiq_instance *instance, unsigned int handle, const
VCHIQ_BULK_TRANSMIT);
break;
default:
- return VCHIQ_ERROR;
+ return -EINVAL;
}
/*
- * vchiq_*_bulk_transfer() may return VCHIQ_RETRY, so we need
+ * vchiq_*_bulk_transfer() may return -EAGAIN, so we need
* to implement a retry mechanism since this function is
* supposed to block until queued
*/
- if (status != VCHIQ_RETRY)
+ if (status != -EAGAIN)
break;
msleep(1);
@@ -873,11 +879,11 @@ vchiq_bulk_transmit(struct vchiq_instance *instance, unsigned int handle, const
}
EXPORT_SYMBOL(vchiq_bulk_transmit);
-enum vchiq_status vchiq_bulk_receive(struct vchiq_instance *instance, unsigned int handle,
- void *data, unsigned int size, void *userdata,
- enum vchiq_bulk_mode mode)
+int vchiq_bulk_receive(struct vchiq_instance *instance, unsigned int handle,
+ void *data, unsigned int size, void *userdata,
+ enum vchiq_bulk_mode mode)
{
- enum vchiq_status status;
+ int status;
while (1) {
switch (mode) {
@@ -892,15 +898,15 @@ enum vchiq_status vchiq_bulk_receive(struct vchiq_instance *instance, unsigned i
VCHIQ_BULK_RECEIVE);
break;
default:
- return VCHIQ_ERROR;
+ return -EINVAL;
}
/*
- * vchiq_*_bulk_transfer() may return VCHIQ_RETRY, so we need
+ * vchiq_*_bulk_transfer() may return -EAGAIN, so we need
* to implement a retry mechanism since this function is
* supposed to block until queued
*/
- if (status != VCHIQ_RETRY)
+ if (status != -EAGAIN)
break;
msleep(1);
@@ -910,17 +916,17 @@ enum vchiq_status vchiq_bulk_receive(struct vchiq_instance *instance, unsigned i
}
EXPORT_SYMBOL(vchiq_bulk_receive);
-static enum vchiq_status
+static int
vchiq_blocking_bulk_transfer(struct vchiq_instance *instance, unsigned int handle, void *data,
unsigned int size, enum vchiq_bulk_dir dir)
{
struct vchiq_service *service;
- enum vchiq_status status;
+ int status;
struct bulk_waiter_node *waiter = NULL, *iter;
service = find_service_by_handle(instance, handle);
if (!service)
- return VCHIQ_ERROR;
+ return -EINVAL;
vchiq_service_put(service);
@@ -954,14 +960,14 @@ vchiq_blocking_bulk_transfer(struct vchiq_instance *instance, unsigned int handl
waiter = kzalloc(sizeof(*waiter), GFP_KERNEL);
if (!waiter) {
vchiq_log_error(vchiq_core_log_level, "%s - out of memory", __func__);
- return VCHIQ_ERROR;
+ return -ENOMEM;
}
}
status = vchiq_bulk_transfer(instance, handle, data, NULL, size,
&waiter->bulk_waiter,
VCHIQ_BULK_MODE_BLOCKING, dir);
- if ((status != VCHIQ_RETRY) || fatal_signal_pending(current) || !waiter->bulk_waiter.bulk) {
+ if ((status != -EAGAIN) || fatal_signal_pending(current) || !waiter->bulk_waiter.bulk) {
struct vchiq_bulk *bulk = waiter->bulk_waiter.bulk;
if (bulk) {
@@ -983,7 +989,7 @@ vchiq_blocking_bulk_transfer(struct vchiq_instance *instance, unsigned int handl
return status;
}
-static enum vchiq_status
+static int
add_completion(struct vchiq_instance *instance, enum vchiq_reason reason,
struct vchiq_header *header, struct user_service *user_service,
void *bulk_userdata)
@@ -1001,10 +1007,10 @@ add_completion(struct vchiq_instance *instance, enum vchiq_reason reason,
DEBUG_COUNT(COMPLETION_QUEUE_FULL_COUNT);
if (wait_for_completion_interruptible(&instance->remove_event)) {
vchiq_log_info(vchiq_arm_log_level, "service_callback interrupted");
- return VCHIQ_RETRY;
+ return -EAGAIN;
} else if (instance->closing) {
vchiq_log_info(vchiq_arm_log_level, "service_callback closing");
- return VCHIQ_SUCCESS;
+ return 0;
}
DEBUG_TRACE(SERVICE_CALLBACK_LINE);
}
@@ -1041,10 +1047,10 @@ add_completion(struct vchiq_instance *instance, enum vchiq_reason reason,
complete(&instance->insert_event);
- return VCHIQ_SUCCESS;
+ return 0;
}
-enum vchiq_status
+int
service_callback(struct vchiq_instance *instance, enum vchiq_reason reason,
struct vchiq_header *header, unsigned int handle, void *bulk_userdata)
{
@@ -1066,14 +1072,14 @@ service_callback(struct vchiq_instance *instance, enum vchiq_reason reason,
service = handle_to_service(instance, handle);
if (WARN_ON(!service)) {
rcu_read_unlock();
- return VCHIQ_SUCCESS;
+ return 0;
}
user_service = (struct user_service *)service->base.userdata;
if (!instance || instance->closing) {
rcu_read_unlock();
- return VCHIQ_SUCCESS;
+ return 0;
}
/*
@@ -1103,14 +1109,14 @@ service_callback(struct vchiq_instance *instance, enum vchiq_reason reason,
*/
if ((user_service->message_available_pos -
instance->completion_remove) < 0) {
- enum vchiq_status status;
+ int status;
vchiq_log_info(vchiq_arm_log_level,
"Inserting extra MESSAGE_AVAILABLE");
DEBUG_TRACE(SERVICE_CALLBACK_LINE);
status = add_completion(instance, reason, NULL, user_service,
bulk_userdata);
- if (status != VCHIQ_SUCCESS) {
+ if (status) {
DEBUG_TRACE(SERVICE_CALLBACK_LINE);
vchiq_service_put(service);
return status;
@@ -1122,12 +1128,12 @@ service_callback(struct vchiq_instance *instance, enum vchiq_reason reason,
vchiq_log_info(vchiq_arm_log_level, "%s interrupted", __func__);
DEBUG_TRACE(SERVICE_CALLBACK_LINE);
vchiq_service_put(service);
- return VCHIQ_RETRY;
+ return -EAGAIN;
} else if (instance->closing) {
vchiq_log_info(vchiq_arm_log_level, "%s closing", __func__);
DEBUG_TRACE(SERVICE_CALLBACK_LINE);
vchiq_service_put(service);
- return VCHIQ_ERROR;
+ return -EINVAL;
}
DEBUG_TRACE(SERVICE_CALLBACK_LINE);
spin_lock(&msg_queue_spinlock);
@@ -1158,7 +1164,7 @@ service_callback(struct vchiq_instance *instance, enum vchiq_reason reason,
vchiq_service_put(service);
if (skip_completion)
- return VCHIQ_SUCCESS;
+ return 0;
return add_completion(instance, reason, header, user_service,
bulk_userdata);
@@ -1314,7 +1320,7 @@ vchiq_get_state(void)
* Autosuspend related functionality
*/
-static enum vchiq_status
+static int
vchiq_keepalive_vchiq_callback(struct vchiq_instance *instance,
enum vchiq_reason reason,
struct vchiq_header *header,
@@ -1330,7 +1336,7 @@ vchiq_keepalive_thread_func(void *v)
struct vchiq_state *state = (struct vchiq_state *)v;
struct vchiq_arm_state *arm_state = vchiq_platform_get_arm_state(state);
- enum vchiq_status status;
+ int status;
struct vchiq_instance *instance;
unsigned int ka_handle;
int ret;
@@ -1350,14 +1356,14 @@ vchiq_keepalive_thread_func(void *v)
}
status = vchiq_connect(instance);
- if (status != VCHIQ_SUCCESS) {
+ if (status) {
vchiq_log_error(vchiq_susp_log_level, "%s vchiq_connect failed %d", __func__,
status);
goto shutdown;
}
status = vchiq_add_service(instance, &params, &ka_handle);
- if (status != VCHIQ_SUCCESS) {
+ if (status) {
vchiq_log_error(vchiq_susp_log_level, "%s vchiq_open_service failed %d", __func__,
status);
goto shutdown;
@@ -1386,14 +1392,14 @@ vchiq_keepalive_thread_func(void *v)
while (uc--) {
atomic_inc(&arm_state->ka_use_ack_count);
status = vchiq_use_service(instance, ka_handle);
- if (status != VCHIQ_SUCCESS) {
+ if (status) {
vchiq_log_error(vchiq_susp_log_level,
"%s vchiq_use_service error %d", __func__, status);
}
}
while (rc--) {
status = vchiq_release_service(instance, ka_handle);
- if (status != VCHIQ_SUCCESS) {
+ if (status) {
vchiq_log_error(vchiq_susp_log_level,
"%s vchiq_release_service error %d", __func__,
status);
@@ -1446,13 +1452,13 @@ vchiq_use_internal(struct vchiq_state *state, struct vchiq_service *service,
write_unlock_bh(&arm_state->susp_res_lock);
if (!ret) {
- enum vchiq_status status = VCHIQ_SUCCESS;
+ int status = 0;
long ack_cnt = atomic_xchg(&arm_state->ka_use_ack_count, 0);
- while (ack_cnt && (status == VCHIQ_SUCCESS)) {
+ while (ack_cnt && !status) {
/* Send the use notify to videocore */
status = vchiq_send_remote_use_active(state);
- if (status == VCHIQ_SUCCESS)
+ if (!status)
ack_cnt--;
else
atomic_add(ack_cnt, &arm_state->ka_use_ack_count);
@@ -1587,10 +1593,10 @@ vchiq_instance_set_trace(struct vchiq_instance *instance, int trace)
instance->trace = (trace != 0);
}
-enum vchiq_status
+int
vchiq_use_service(struct vchiq_instance *instance, unsigned int handle)
{
- enum vchiq_status ret = VCHIQ_ERROR;
+ int ret = -EINVAL;
struct vchiq_service *service = find_service_by_handle(instance, handle);
if (service) {
@@ -1601,10 +1607,10 @@ vchiq_use_service(struct vchiq_instance *instance, unsigned int handle)
}
EXPORT_SYMBOL(vchiq_use_service);
-enum vchiq_status
+int
vchiq_release_service(struct vchiq_instance *instance, unsigned int handle)
{
- enum vchiq_status ret = VCHIQ_ERROR;
+ int ret = -EINVAL;
struct vchiq_service *service = find_service_by_handle(instance, handle);
if (service) {
@@ -1695,11 +1701,11 @@ vchiq_dump_service_use_state(struct vchiq_state *state)
kfree(service_data);
}
-enum vchiq_status
+int
vchiq_check_service(struct vchiq_service *service)
{
struct vchiq_arm_state *arm_state;
- enum vchiq_status ret = VCHIQ_ERROR;
+ int ret = -EINVAL;
if (!service || !service->state)
goto out;
@@ -1708,10 +1714,10 @@ vchiq_check_service(struct vchiq_service *service)
read_lock_bh(&arm_state->susp_res_lock);
if (service->service_use_count)
- ret = VCHIQ_SUCCESS;
+ ret = 0;
read_unlock_bh(&arm_state->susp_res_lock);
- if (ret == VCHIQ_ERROR) {
+ if (ret) {
vchiq_log_error(vchiq_susp_log_level,
"%s ERROR - %c%c%c%c:%d service count %d, state count %d", __func__,
VCHIQ_FOURCC_AS_4CHARS(service->base.fourcc), service->client_id,
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h
index cd20eb18f275..2fb31f9b527f 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h
@@ -85,13 +85,13 @@ extern struct vchiq_state g_state;
extern struct vchiq_state *
vchiq_get_state(void);
-enum vchiq_status
+int
vchiq_use_service(struct vchiq_instance *instance, unsigned int handle);
-extern enum vchiq_status
+extern int
vchiq_release_service(struct vchiq_instance *instance, unsigned int handle);
-extern enum vchiq_status
+extern int
vchiq_check_service(struct vchiq_service *service);
extern void
@@ -137,7 +137,7 @@ static inline int vchiq_register_chrdev(struct device *parent) { return 0; }
#endif /* IS_ENABLED(CONFIG_VCHIQ_CDEV) */
-extern enum vchiq_status
+extern int
service_callback(struct vchiq_instance *vchiq_instance, enum vchiq_reason reason,
struct vchiq_header *header, unsigned int handle, void *bulk_userdata);
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c
index 45ed30bfdbf5..596894338cb4 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c
@@ -463,22 +463,22 @@ mark_service_closing(struct vchiq_service *service)
mark_service_closing_internal(service, 0);
}
-static inline enum vchiq_status
+static inline int
make_service_callback(struct vchiq_service *service, enum vchiq_reason reason,
struct vchiq_header *header, void *bulk_userdata)
{
- enum vchiq_status status;
+ int status;
vchiq_log_trace(vchiq_core_log_level, "%d: callback:%d (%s, %pK, %pK)",
service->state->id, service->localport, reason_names[reason],
header, bulk_userdata);
status = service->base.callback(service->instance, reason, header, service->handle,
bulk_userdata);
- if (status == VCHIQ_ERROR) {
+ if (status && (status != -EAGAIN)) {
vchiq_log_warning(vchiq_core_log_level,
"%d: ignoring ERROR from callback to service %x",
service->state->id, service->handle);
- status = VCHIQ_SUCCESS;
+ status = 0;
}
if (reason != VCHIQ_MESSAGE_AVAILABLE)
@@ -498,6 +498,7 @@ vchiq_set_conn_state(struct vchiq_state *state, enum vchiq_connstate newstate)
vchiq_platform_conn_state_changed(state, oldstate, newstate);
}
+/* This initialises a single remote_event, and the associated wait_queue. */
static inline void
remote_event_create(wait_queue_head_t *wq, struct remote_event *event)
{
@@ -536,6 +537,10 @@ remote_event_wait(wait_queue_head_t *wq, struct remote_event *event)
return 1;
}
+/*
+ * Acknowledge that the event has been signalled, and wake any waiters. Usually
+ * called as a result of the doorbell being rung.
+ */
static inline void
remote_event_signal_local(wait_queue_head_t *wq, struct remote_event *event)
{
@@ -544,6 +549,7 @@ remote_event_signal_local(wait_queue_head_t *wq, struct remote_event *event)
wake_up_all(wq);
}
+/* Check if a single event has been signalled, waking the waiters if it has. */
static inline void
remote_event_poll(wait_queue_head_t *wq, struct remote_event *event)
{
@@ -551,6 +557,10 @@ remote_event_poll(wait_queue_head_t *wq, struct remote_event *event)
remote_event_signal_local(wq, event);
}
+/*
+ * VCHIQ used a small, fixed number of remote events. It is simplest to
+ * enumerate them here for polling.
+ */
void
remote_event_pollall(struct vchiq_state *state)
{
@@ -900,7 +910,7 @@ copy_message_data(ssize_t (*copy_callback)(void *context, void *dest, size_t off
}
/* Called by the slot handler and application threads */
-static enum vchiq_status
+static int
queue_message(struct vchiq_state *state, struct vchiq_service *service,
int msgid,
ssize_t (*copy_callback)(void *context, void *dest,
@@ -922,7 +932,7 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service,
if (!(flags & QMFLAGS_NO_MUTEX_LOCK) &&
mutex_lock_killable(&state->slot_mutex))
- return VCHIQ_RETRY;
+ return -EAGAIN;
if (type == VCHIQ_MSG_DATA) {
int tx_end_index;
@@ -930,7 +940,7 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service,
if (!service) {
WARN(1, "%s: service is NULL\n", __func__);
mutex_unlock(&state->slot_mutex);
- return VCHIQ_ERROR;
+ return -EINVAL;
}
WARN_ON(flags & (QMFLAGS_NO_MUTEX_LOCK |
@@ -939,7 +949,7 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service,
if (service->closing) {
/* The service has been closed */
mutex_unlock(&state->slot_mutex);
- return VCHIQ_ERROR;
+ return -EHOSTDOWN;
}
quota = &state->service_quotas[service->localport];
@@ -963,7 +973,7 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service,
mutex_unlock(&state->slot_mutex);
if (wait_for_completion_interruptible(&state->data_quota_event))
- return VCHIQ_RETRY;
+ return -EAGAIN;
mutex_lock(&state->slot_mutex);
spin_lock(&quota_spinlock);
@@ -987,15 +997,15 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service,
VCHIQ_SERVICE_STATS_INC(service, quota_stalls);
mutex_unlock(&state->slot_mutex);
if (wait_for_completion_interruptible(&quota->quota_event))
- return VCHIQ_RETRY;
+ return -EAGAIN;
if (service->closing)
- return VCHIQ_ERROR;
+ return -EHOSTDOWN;
if (mutex_lock_killable(&state->slot_mutex))
- return VCHIQ_RETRY;
+ return -EAGAIN;
if (service->srvstate != VCHIQ_SRVSTATE_OPEN) {
/* The service has been closed */
mutex_unlock(&state->slot_mutex);
- return VCHIQ_ERROR;
+ return -EHOSTDOWN;
}
spin_lock(&quota_spinlock);
tx_end_index = SLOT_QUEUE_INDEX_FROM_POS(state->local_tx_pos + stride - 1);
@@ -1015,7 +1025,7 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service,
*/
if (!(flags & QMFLAGS_NO_MUTEX_LOCK))
mutex_unlock(&state->slot_mutex);
- return VCHIQ_RETRY;
+ return -EAGAIN;
}
if (type == VCHIQ_MSG_DATA) {
@@ -1037,7 +1047,7 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service,
if (callback_result < 0) {
mutex_unlock(&state->slot_mutex);
VCHIQ_SERVICE_STATS_INC(service, error_count);
- return VCHIQ_ERROR;
+ return -EINVAL;
}
if (SRVTRACE_ENABLED(service,
@@ -1135,11 +1145,11 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service,
remote_event_signal(&state->remote->trigger);
- return VCHIQ_SUCCESS;
+ return 0;
}
/* Called by the slot handler and application threads */
-static enum vchiq_status
+static int
queue_message_sync(struct vchiq_state *state, struct vchiq_service *service,
int msgid,
ssize_t (*copy_callback)(void *context, void *dest,
@@ -1154,7 +1164,7 @@ queue_message_sync(struct vchiq_state *state, struct vchiq_service *service,
if (VCHIQ_MSG_TYPE(msgid) != VCHIQ_MSG_RESUME &&
mutex_lock_killable(&state->sync_mutex))
- return VCHIQ_RETRY;
+ return -EAGAIN;
remote_event_wait(&state->sync_release_event, &local->sync_release);
@@ -1185,7 +1195,7 @@ queue_message_sync(struct vchiq_state *state, struct vchiq_service *service,
if (callback_result < 0) {
mutex_unlock(&state->slot_mutex);
VCHIQ_SERVICE_STATS_INC(service, error_count);
- return VCHIQ_ERROR;
+ return -EINVAL;
}
if (service) {
@@ -1223,7 +1233,7 @@ queue_message_sync(struct vchiq_state *state, struct vchiq_service *service,
if (VCHIQ_MSG_TYPE(msgid) != VCHIQ_MSG_PAUSE)
mutex_unlock(&state->sync_mutex);
- return VCHIQ_SUCCESS;
+ return 0;
}
static inline void
@@ -1299,11 +1309,11 @@ get_bulk_reason(struct vchiq_bulk *bulk)
}
/* Called by the slot handler - don't hold the bulk mutex */
-static enum vchiq_status
+static int
notify_bulks(struct vchiq_service *service, struct vchiq_bulk_queue *queue,
int retry_poll)
{
- enum vchiq_status status = VCHIQ_SUCCESS;
+ int status = 0;
vchiq_log_trace(vchiq_core_log_level, "%d: nb:%d %cx - p=%x rn=%x r=%x", service->state->id,
service->localport, (queue == &service->bulk_tx) ? 't' : 'r',
@@ -1348,7 +1358,7 @@ notify_bulks(struct vchiq_service *service, struct vchiq_bulk_queue *queue,
get_bulk_reason(bulk);
status = make_service_callback(service, reason, NULL,
bulk->userdata);
- if (status == VCHIQ_RETRY)
+ if (status == -EAGAIN)
break;
}
}
@@ -1357,9 +1367,9 @@ notify_bulks(struct vchiq_service *service, struct vchiq_bulk_queue *queue,
complete(&service->bulk_remove_event);
}
if (!retry_poll)
- status = VCHIQ_SUCCESS;
+ status = 0;
- if (status == VCHIQ_RETRY)
+ if (status == -EAGAIN)
request_poll(service->state, service, (queue == &service->bulk_tx) ?
VCHIQ_POLL_TXNOTIFY : VCHIQ_POLL_RXNOTIFY);
@@ -1398,13 +1408,12 @@ poll_services_of_group(struct vchiq_state *state, int group)
*/
service->public_fourcc = VCHIQ_FOURCC_INVALID;
- if (vchiq_close_service_internal(service, NO_CLOSE_RECVD) !=
- VCHIQ_SUCCESS)
+ if (vchiq_close_service_internal(service, NO_CLOSE_RECVD))
request_poll(state, service, VCHIQ_POLL_REMOVE);
} else if (service_flags & BIT(VCHIQ_POLL_TERMINATE)) {
vchiq_log_info(vchiq_core_log_level, "%d: ps - terminate %d<->%d",
state->id, service->localport, service->remoteport);
- if (vchiq_close_service_internal(service, NO_CLOSE_RECVD) != VCHIQ_SUCCESS)
+ if (vchiq_close_service_internal(service, NO_CLOSE_RECVD))
request_poll(state, service, VCHIQ_POLL_TERMINATE);
}
if (service_flags & BIT(VCHIQ_POLL_TXNOTIFY))
@@ -1527,14 +1536,14 @@ parse_open(struct vchiq_state *state, struct vchiq_header *header)
/* Acknowledge the OPEN */
if (service->sync) {
if (queue_message_sync(state, NULL, openack_id, memcpy_copy_callback,
- &ack_payload, sizeof(ack_payload), 0) == VCHIQ_RETRY)
+ &ack_payload, sizeof(ack_payload), 0) == -EAGAIN)
goto bail_not_ready;
/* The service is now open */
set_service_state(service, VCHIQ_SRVSTATE_OPENSYNC);
} else {
if (queue_message(state, NULL, openack_id, memcpy_copy_callback,
- &ack_payload, sizeof(ack_payload), 0) == VCHIQ_RETRY)
+ &ack_payload, sizeof(ack_payload), 0) == -EAGAIN)
goto bail_not_ready;
/* The service is now open */
@@ -1549,7 +1558,7 @@ parse_open(struct vchiq_state *state, struct vchiq_header *header)
fail_open:
/* No available service, or an invalid request - send a CLOSE */
if (queue_message(state, NULL, MAKE_CLOSE(0, VCHIQ_MSG_SRCPORT(msgid)),
- NULL, NULL, 0, 0) == VCHIQ_RETRY)
+ NULL, NULL, 0, 0) == -EAGAIN)
goto bail_not_ready;
return 1;
@@ -1688,7 +1697,7 @@ parse_message(struct vchiq_state *state, struct vchiq_header *header)
mark_service_closing_internal(service, 1);
- if (vchiq_close_service_internal(service, CLOSE_RECVD) == VCHIQ_RETRY)
+ if (vchiq_close_service_internal(service, CLOSE_RECVD) == -EAGAIN)
goto bail_not_ready;
vchiq_log_info(vchiq_core_log_level, "Close Service %c%c%c%c s:%u d:%d",
@@ -1705,7 +1714,7 @@ parse_message(struct vchiq_state *state, struct vchiq_header *header)
claim_slot(state->rx_info);
DEBUG_TRACE(PARSE_LINE);
if (make_service_callback(service, VCHIQ_MESSAGE_AVAILABLE, header,
- NULL) == VCHIQ_RETRY) {
+ NULL) == -EAGAIN) {
DEBUG_TRACE(PARSE_LINE);
goto bail_not_ready;
}
@@ -1803,7 +1812,7 @@ parse_message(struct vchiq_state *state, struct vchiq_header *header)
if (state->conn_state != VCHIQ_CONNSTATE_PAUSE_SENT) {
/* Send a PAUSE in response */
if (queue_message(state, NULL, MAKE_PAUSE, NULL, NULL, 0,
- QMFLAGS_NO_MUTEX_UNLOCK) == VCHIQ_RETRY)
+ QMFLAGS_NO_MUTEX_UNLOCK) == -EAGAIN)
goto bail_not_ready;
}
/* At this point slot_mutex is held */
@@ -1920,7 +1929,7 @@ handle_poll(struct vchiq_state *state)
case VCHIQ_CONNSTATE_PAUSING:
if (queue_message(state, NULL, MAKE_PAUSE, NULL, NULL, 0,
- QMFLAGS_NO_MUTEX_UNLOCK) != VCHIQ_RETRY) {
+ QMFLAGS_NO_MUTEX_UNLOCK) != -EAGAIN) {
vchiq_set_conn_state(state, VCHIQ_CONNSTATE_PAUSE_SENT);
} else {
/* Retry later */
@@ -1930,7 +1939,7 @@ handle_poll(struct vchiq_state *state)
case VCHIQ_CONNSTATE_RESUMING:
if (queue_message(state, NULL, MAKE_RESUME, NULL, NULL, 0,
- QMFLAGS_NO_MUTEX_LOCK) != VCHIQ_RETRY) {
+ QMFLAGS_NO_MUTEX_LOCK) != -EAGAIN) {
vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTED);
} else {
/*
@@ -2086,9 +2095,9 @@ sync_func(void *v)
if ((service->remoteport == remoteport) &&
(service->srvstate == VCHIQ_SRVSTATE_OPENSYNC)) {
if (make_service_callback(service, VCHIQ_MESSAGE_AVAILABLE, header,
- NULL) == VCHIQ_RETRY)
+ NULL) == -EAGAIN)
vchiq_log_error(vchiq_sync_log_level,
- "synchronous callback to service %d returns VCHIQ_RETRY",
+ "synchronous callback to service %d returns -EAGAIN",
localport);
}
break;
@@ -2486,7 +2495,7 @@ vchiq_add_service_internal(struct vchiq_state *state,
return service;
}
-enum vchiq_status
+int
vchiq_open_service_internal(struct vchiq_service *service, int client_id)
{
struct vchiq_open_payload payload = {
@@ -2495,7 +2504,7 @@ vchiq_open_service_internal(struct vchiq_service *service, int client_id)
service->version,
service->version_min
};
- enum vchiq_status status = VCHIQ_SUCCESS;
+ int status = 0;
service->client_id = client_id;
vchiq_use_service_internal(service);
@@ -2506,12 +2515,12 @@ vchiq_open_service_internal(struct vchiq_service *service, int client_id)
sizeof(payload),
QMFLAGS_IS_BLOCKING);
- if (status != VCHIQ_SUCCESS)
+ if (status)
return status;
/* Wait for the ACK/NAK */
if (wait_for_completion_interruptible(&service->remove_event)) {
- status = VCHIQ_RETRY;
+ status = -EAGAIN;
vchiq_release_service_internal(service);
} else if ((service->srvstate != VCHIQ_SRVSTATE_OPEN) &&
(service->srvstate != VCHIQ_SRVSTATE_OPENSYNC)) {
@@ -2521,7 +2530,7 @@ vchiq_open_service_internal(struct vchiq_service *service, int client_id)
service->state->id,
srvstate_names[service->srvstate],
kref_read(&service->ref_count));
- status = VCHIQ_ERROR;
+ status = -EINVAL;
VCHIQ_SERVICE_STATS_INC(service, error_count);
vchiq_release_service_internal(service);
}
@@ -2592,7 +2601,7 @@ release_service_messages(struct vchiq_service *service)
static int
do_abort_bulks(struct vchiq_service *service)
{
- enum vchiq_status status;
+ int status;
/* Abort any outstanding bulk transfers */
if (mutex_lock_killable(&service->bulk_mutex))
@@ -2602,17 +2611,17 @@ do_abort_bulks(struct vchiq_service *service)
mutex_unlock(&service->bulk_mutex);
status = notify_bulks(service, &service->bulk_tx, NO_RETRY_POLL);
- if (status != VCHIQ_SUCCESS)
+ if (status)
return 0;
status = notify_bulks(service, &service->bulk_rx, NO_RETRY_POLL);
- return (status == VCHIQ_SUCCESS);
+ return !status;
}
-static enum vchiq_status
+static int
close_service_complete(struct vchiq_service *service, int failstate)
{
- enum vchiq_status status;
+ int status;
int is_server = (service->public_fourcc != VCHIQ_FOURCC_INVALID);
int newstate;
@@ -2639,12 +2648,12 @@ close_service_complete(struct vchiq_service *service, int failstate)
vchiq_log_error(vchiq_core_log_level, "%s(%x) called in state %s", __func__,
service->handle, srvstate_names[service->srvstate]);
WARN(1, "%s in unexpected state\n", __func__);
- return VCHIQ_ERROR;
+ return -EINVAL;
}
status = make_service_callback(service, VCHIQ_SERVICE_CLOSED, NULL, NULL);
- if (status != VCHIQ_RETRY) {
+ if (status != -EAGAIN) {
int uc = service->service_use_count;
int i;
/* Complete the close process */
@@ -2674,11 +2683,11 @@ close_service_complete(struct vchiq_service *service, int failstate)
}
/* Called by the slot handler */
-enum vchiq_status
+int
vchiq_close_service_internal(struct vchiq_service *service, int close_recvd)
{
struct vchiq_state *state = service->state;
- enum vchiq_status status = VCHIQ_SUCCESS;
+ int status = 0;
int is_server = (service->public_fourcc != VCHIQ_FOURCC_INVALID);
int close_id = MAKE_CLOSE(service->localport,
VCHIQ_MSG_DSTPORT(service->remoteport));
@@ -2696,7 +2705,7 @@ vchiq_close_service_internal(struct vchiq_service *service, int close_recvd)
__func__, srvstate_names[service->srvstate]);
} else if (is_server) {
if (service->srvstate == VCHIQ_SRVSTATE_LISTENING) {
- status = VCHIQ_ERROR;
+ status = -EINVAL;
} else {
service->client_id = 0;
service->remoteport = VCHIQ_PORT_FREE;
@@ -2725,16 +2734,16 @@ vchiq_close_service_internal(struct vchiq_service *service, int close_recvd)
case VCHIQ_SRVSTATE_OPEN:
if (close_recvd) {
if (!do_abort_bulks(service))
- status = VCHIQ_RETRY;
+ status = -EAGAIN;
}
release_service_messages(service);
- if (status == VCHIQ_SUCCESS)
+ if (!status)
status = queue_message(state, service, close_id, NULL,
NULL, 0, QMFLAGS_NO_MUTEX_UNLOCK);
- if (status != VCHIQ_SUCCESS) {
+ if (status) {
if (service->srvstate == VCHIQ_SRVSTATE_OPENSYNC)
mutex_unlock(&state->sync_mutex);
break;
@@ -2764,11 +2773,11 @@ vchiq_close_service_internal(struct vchiq_service *service, int close_recvd)
break;
if (!do_abort_bulks(service)) {
- status = VCHIQ_RETRY;
+ status = -EAGAIN;
break;
}
- if (status == VCHIQ_SUCCESS)
+ if (!status)
status = close_service_complete(service, VCHIQ_SRVSTATE_CLOSERECVD);
break;
@@ -2832,7 +2841,7 @@ vchiq_free_service_internal(struct vchiq_service *service)
vchiq_service_put(service);
}
-enum vchiq_status
+int
vchiq_connect_internal(struct vchiq_state *state, struct vchiq_instance *instance)
{
struct vchiq_service *service;
@@ -2848,21 +2857,21 @@ vchiq_connect_internal(struct vchiq_state *state, struct vchiq_instance *instanc
if (state->conn_state == VCHIQ_CONNSTATE_DISCONNECTED) {
if (queue_message(state, NULL, MAKE_CONNECT, NULL, NULL, 0,
- QMFLAGS_IS_BLOCKING) == VCHIQ_RETRY)
- return VCHIQ_RETRY;
+ QMFLAGS_IS_BLOCKING) == -EAGAIN)
+ return -EAGAIN;
vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTING);
}
if (state->conn_state == VCHIQ_CONNSTATE_CONNECTING) {
if (wait_for_completion_interruptible(&state->connect))
- return VCHIQ_RETRY;
+ return -EAGAIN;
vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTED);
complete(&state->connect);
}
- return VCHIQ_SUCCESS;
+ return 0;
}
void
@@ -2879,15 +2888,15 @@ vchiq_shutdown_internal(struct vchiq_state *state, struct vchiq_instance *instan
}
}
-enum vchiq_status
+int
vchiq_close_service(struct vchiq_instance *instance, unsigned int handle)
{
/* Unregister the service */
struct vchiq_service *service = find_service_by_handle(instance, handle);
- enum vchiq_status status = VCHIQ_SUCCESS;
+ int status = 0;
if (!service)
- return VCHIQ_ERROR;
+ return -EINVAL;
vchiq_log_info(vchiq_core_log_level, "%d: close_service:%d",
service->state->id, service->localport);
@@ -2896,14 +2905,14 @@ vchiq_close_service(struct vchiq_instance *instance, unsigned int handle)
(service->srvstate == VCHIQ_SRVSTATE_LISTENING) ||
(service->srvstate == VCHIQ_SRVSTATE_HIDDEN)) {
vchiq_service_put(service);
- return VCHIQ_ERROR;
+ return -EINVAL;
}
mark_service_closing(service);
if (current == service->state->slot_handler_thread) {
status = vchiq_close_service_internal(service, NO_CLOSE_RECVD);
- WARN_ON(status == VCHIQ_RETRY);
+ WARN_ON(status == -EAGAIN);
} else {
/* Mark the service for termination by the slot handler */
request_poll(service->state, service, VCHIQ_POLL_TERMINATE);
@@ -2911,7 +2920,7 @@ vchiq_close_service(struct vchiq_instance *instance, unsigned int handle)
while (1) {
if (wait_for_completion_interruptible(&service->remove_event)) {
- status = VCHIQ_RETRY;
+ status = -EAGAIN;
break;
}
@@ -2926,10 +2935,10 @@ vchiq_close_service(struct vchiq_instance *instance, unsigned int handle)
srvstate_names[service->srvstate]);
}
- if ((status == VCHIQ_SUCCESS) &&
+ if (!status &&
(service->srvstate != VCHIQ_SRVSTATE_FREE) &&
(service->srvstate != VCHIQ_SRVSTATE_LISTENING))
- status = VCHIQ_ERROR;
+ status = -EINVAL;
vchiq_service_put(service);
@@ -2937,22 +2946,22 @@ vchiq_close_service(struct vchiq_instance *instance, unsigned int handle)
}
EXPORT_SYMBOL(vchiq_close_service);
-enum vchiq_status
+int
vchiq_remove_service(struct vchiq_instance *instance, unsigned int handle)
{
/* Unregister the service */
struct vchiq_service *service = find_service_by_handle(instance, handle);
- enum vchiq_status status = VCHIQ_SUCCESS;
+ int status = 0;
if (!service)
- return VCHIQ_ERROR;
+ return -EINVAL;
vchiq_log_info(vchiq_core_log_level, "%d: remove_service:%d",
service->state->id, service->localport);
if (service->srvstate == VCHIQ_SRVSTATE_FREE) {
vchiq_service_put(service);
- return VCHIQ_ERROR;
+ return -EINVAL;
}
mark_service_closing(service);
@@ -2966,14 +2975,14 @@ vchiq_remove_service(struct vchiq_instance *instance, unsigned int handle)
service->public_fourcc = VCHIQ_FOURCC_INVALID;
status = vchiq_close_service_internal(service, NO_CLOSE_RECVD);
- WARN_ON(status == VCHIQ_RETRY);
+ WARN_ON(status == -EAGAIN);
} else {
/* Mark the service for removal by the slot handler */
request_poll(service->state, service, VCHIQ_POLL_REMOVE);
}
while (1) {
if (wait_for_completion_interruptible(&service->remove_event)) {
- status = VCHIQ_RETRY;
+ status = -EAGAIN;
break;
}
@@ -2987,9 +2996,8 @@ vchiq_remove_service(struct vchiq_instance *instance, unsigned int handle)
srvstate_names[service->srvstate]);
}
- if ((status == VCHIQ_SUCCESS) &&
- (service->srvstate != VCHIQ_SRVSTATE_FREE))
- status = VCHIQ_ERROR;
+ if (!status && (service->srvstate != VCHIQ_SRVSTATE_FREE))
+ status = -EINVAL;
vchiq_service_put(service);
@@ -2998,15 +3006,15 @@ vchiq_remove_service(struct vchiq_instance *instance, unsigned int handle)
/*
* This function may be called by kernel threads or user threads.
- * User threads may receive VCHIQ_RETRY to indicate that a signal has been
+ * User threads may receive -EAGAIN to indicate that a signal has been
* received and the call should be retried after being returned to user
* context.
* When called in blocking mode, the userdata field points to a bulk_waiter
* structure.
*/
-enum vchiq_status vchiq_bulk_transfer(struct vchiq_instance *instance, unsigned int handle,
- void *offset, void __user *uoffset, int size, void *userdata,
- enum vchiq_bulk_mode mode, enum vchiq_bulk_dir dir)
+int vchiq_bulk_transfer(struct vchiq_instance *instance, unsigned int handle,
+ void *offset, void __user *uoffset, int size, void *userdata,
+ enum vchiq_bulk_mode mode, enum vchiq_bulk_dir dir)
{
struct vchiq_service *service = find_service_by_handle(instance, handle);
struct vchiq_bulk_queue *queue;
@@ -3016,7 +3024,7 @@ enum vchiq_status vchiq_bulk_transfer(struct vchiq_instance *instance, unsigned
const char dir_char = (dir == VCHIQ_BULK_TRANSMIT) ? 't' : 'r';
const int dir_msgtype = (dir == VCHIQ_BULK_TRANSMIT) ?
VCHIQ_MSG_BULK_TX : VCHIQ_MSG_BULK_RX;
- enum vchiq_status status = VCHIQ_ERROR;
+ int status = -EINVAL;
int payload[2];
if (!service)
@@ -3028,7 +3036,7 @@ enum vchiq_status vchiq_bulk_transfer(struct vchiq_instance *instance, unsigned
if (!offset && !uoffset)
goto error_exit;
- if (vchiq_check_service(service) != VCHIQ_SUCCESS)
+ if (vchiq_check_service(service))
goto error_exit;
switch (mode) {
@@ -3055,7 +3063,7 @@ enum vchiq_status vchiq_bulk_transfer(struct vchiq_instance *instance, unsigned
&service->bulk_tx : &service->bulk_rx;
if (mutex_lock_killable(&service->bulk_mutex)) {
- status = VCHIQ_RETRY;
+ status = -EAGAIN;
goto error_exit;
}
@@ -3064,11 +3072,11 @@ enum vchiq_status vchiq_bulk_transfer(struct vchiq_instance *instance, unsigned
do {
mutex_unlock(&service->bulk_mutex);
if (wait_for_completion_interruptible(&service->bulk_remove_event)) {
- status = VCHIQ_RETRY;
+ status = -EAGAIN;
goto error_exit;
}
if (mutex_lock_killable(&service->bulk_mutex)) {
- status = VCHIQ_RETRY;
+ status = -EAGAIN;
goto error_exit;
}
} while (queue->local_insert == queue->remove +
@@ -3101,7 +3109,7 @@ enum vchiq_status vchiq_bulk_transfer(struct vchiq_instance *instance, unsigned
* claim it here to ensure that isn't happening
*/
if (mutex_lock_killable(&state->slot_mutex)) {
- status = VCHIQ_RETRY;
+ status = -EAGAIN;
goto cancel_bulk_error_exit;
}
@@ -3121,7 +3129,7 @@ enum vchiq_status vchiq_bulk_transfer(struct vchiq_instance *instance, unsigned
QMFLAGS_IS_BLOCKING |
QMFLAGS_NO_MUTEX_LOCK |
QMFLAGS_NO_MUTEX_UNLOCK);
- if (status != VCHIQ_SUCCESS)
+ if (status)
goto unlock_both_error_exit;
queue->local_insert++;
@@ -3136,14 +3144,14 @@ enum vchiq_status vchiq_bulk_transfer(struct vchiq_instance *instance, unsigned
waiting:
vchiq_service_put(service);
- status = VCHIQ_SUCCESS;
+ status = 0;
if (bulk_waiter) {
bulk_waiter->bulk = bulk;
if (wait_for_completion_interruptible(&bulk_waiter->event))
- status = VCHIQ_RETRY;
+ status = -EAGAIN;
else if (bulk_waiter->actual == VCHIQ_BULK_ACTUAL_ABORTED)
- status = VCHIQ_ERROR;
+ status = -EINVAL;
}
return status;
@@ -3161,7 +3169,7 @@ error_exit:
return status;
}
-enum vchiq_status
+int
vchiq_queue_message(struct vchiq_instance *instance, unsigned int handle,
ssize_t (*copy_callback)(void *context, void *dest,
size_t offset, size_t maxsize),
@@ -3169,13 +3177,13 @@ vchiq_queue_message(struct vchiq_instance *instance, unsigned int handle,
size_t size)
{
struct vchiq_service *service = find_service_by_handle(instance, handle);
- enum vchiq_status status = VCHIQ_ERROR;
+ int status = -EINVAL;
int data_id;
if (!service)
goto error_exit;
- if (vchiq_check_service(service) != VCHIQ_SUCCESS)
+ if (vchiq_check_service(service))
goto error_exit;
if (!size) {
@@ -3200,7 +3208,7 @@ vchiq_queue_message(struct vchiq_instance *instance, unsigned int handle,
copy_callback, context, size, 1);
break;
default:
- status = VCHIQ_ERROR;
+ status = -EINVAL;
break;
}
@@ -3214,18 +3222,18 @@ error_exit:
int vchiq_queue_kernel_message(struct vchiq_instance *instance, unsigned int handle, void *data,
unsigned int size)
{
- enum vchiq_status status;
+ int status;
while (1) {
status = vchiq_queue_message(instance, handle, memcpy_copy_callback,
data, size);
/*
- * vchiq_queue_message() may return VCHIQ_RETRY, so we need to
+ * vchiq_queue_message() may return -EAGAIN, so we need to
* implement a retry mechanism since this function is supposed
* to block until queued
*/
- if (status != VCHIQ_RETRY)
+ if (status != -EAGAIN)
break;
msleep(1);
@@ -3277,23 +3285,23 @@ release_message_sync(struct vchiq_state *state, struct vchiq_header *header)
remote_event_signal(&state->remote->sync_release);
}
-enum vchiq_status
+int
vchiq_get_peer_version(struct vchiq_instance *instance, unsigned int handle, short *peer_version)
{
- enum vchiq_status status = VCHIQ_ERROR;
+ int status = -EINVAL;
struct vchiq_service *service = find_service_by_handle(instance, handle);
if (!service)
goto exit;
- if (vchiq_check_service(service) != VCHIQ_SUCCESS)
+ if (vchiq_check_service(service))
goto exit;
if (!peer_version)
goto exit;
*peer_version = service->peer_version;
- status = VCHIQ_SUCCESS;
+ status = 0;
exit:
if (service)
@@ -3640,18 +3648,18 @@ vchiq_loud_error_footer(void)
"============================================================================");
}
-enum vchiq_status vchiq_send_remote_use(struct vchiq_state *state)
+int vchiq_send_remote_use(struct vchiq_state *state)
{
if (state->conn_state == VCHIQ_CONNSTATE_DISCONNECTED)
- return VCHIQ_RETRY;
+ return -ENOTCONN;
return queue_message(state, NULL, MAKE_REMOTE_USE, NULL, NULL, 0, 0);
}
-enum vchiq_status vchiq_send_remote_use_active(struct vchiq_state *state)
+int vchiq_send_remote_use_active(struct vchiq_state *state)
{
if (state->conn_state == VCHIQ_CONNSTATE_DISCONNECTED)
- return VCHIQ_RETRY;
+ return -ENOTCONN;
return queue_message(state, NULL, MAKE_REMOTE_USE_ACTIVE,
NULL, NULL, 0, 0);
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h
index 8b4a38f5b3f2..ec1a3caefaea 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h
@@ -10,8 +10,8 @@
#include <linux/kref.h>
#include <linux/rcupdate.h>
#include <linux/wait.h>
-#include <linux/raspberrypi/vchiq.h>
+#include "../../include/linux/raspberrypi/vchiq.h"
#include "vchiq_cfg.h"
/* Do this so that we can test-build the code on non-rpi systems */
@@ -166,6 +166,24 @@ struct vchiq_bulk_queue {
struct vchiq_bulk bulks[VCHIQ_NUM_SERVICE_BULKS];
};
+/*
+ * Remote events provide a way of presenting several virtual doorbells to a
+ * peer (ARM host to VPU) using only one physical doorbell. They can be thought
+ * of as a way for the peer to signal a semaphore, in this case implemented as
+ * a workqueue.
+ *
+ * Remote events remain signalled until acknowledged by the receiver, and they
+ * are non-counting. They are designed in such a way as to minimise the number
+ * of interrupts and avoid unnecessary waiting.
+ *
+ * A remote_event is as small data structures that live in shared memory. It
+ * comprises two booleans - armed and fired:
+ *
+ * The sender sets fired when they signal the receiver.
+ * If fired is set, the receiver has been signalled and need not wait.
+ * The receiver sets the armed field before they begin to wait.
+ * If armed is set, the receiver is waiting and wishes to be woken by interrupt.
+ */
struct remote_event {
int armed;
int fired;
@@ -458,7 +476,7 @@ vchiq_init_slots(void *mem_base, int mem_size);
extern int
vchiq_init_state(struct vchiq_state *state, struct vchiq_slot_zero *slot_zero, struct device *dev);
-extern enum vchiq_status
+extern int
vchiq_connect_internal(struct vchiq_state *state, struct vchiq_instance *instance);
struct vchiq_service *
@@ -467,10 +485,10 @@ vchiq_add_service_internal(struct vchiq_state *state,
int srvstate, struct vchiq_instance *instance,
void (*userdata_term)(void *userdata));
-extern enum vchiq_status
+extern int
vchiq_open_service_internal(struct vchiq_service *service, int client_id);
-extern enum vchiq_status
+extern int
vchiq_close_service_internal(struct vchiq_service *service, int close_recvd);
extern void
@@ -485,7 +503,7 @@ vchiq_shutdown_internal(struct vchiq_state *state, struct vchiq_instance *instan
extern void
remote_event_pollall(struct vchiq_state *state);
-extern enum vchiq_status
+extern int
vchiq_bulk_transfer(struct vchiq_instance *instance, unsigned int handle, void *offset,
void __user *uoffset, int size, void *userdata, enum vchiq_bulk_mode mode,
enum vchiq_bulk_dir dir);
@@ -536,7 +554,7 @@ vchiq_service_get(struct vchiq_service *service);
extern void
vchiq_service_put(struct vchiq_service *service);
-extern enum vchiq_status
+extern int
vchiq_queue_message(struct vchiq_instance *instance, unsigned int handle,
ssize_t (*copy_callback)(void *context, void *dest,
size_t offset, size_t maxsize),
@@ -568,13 +586,13 @@ void vchiq_on_remote_release(struct vchiq_state *state);
int vchiq_platform_init_state(struct vchiq_state *state);
-enum vchiq_status vchiq_check_service(struct vchiq_service *service);
+int vchiq_check_service(struct vchiq_service *service);
void vchiq_on_remote_use_active(struct vchiq_state *state);
-enum vchiq_status vchiq_send_remote_use(struct vchiq_state *state);
+int vchiq_send_remote_use(struct vchiq_state *state);
-enum vchiq_status vchiq_send_remote_use_active(struct vchiq_state *state);
+int vchiq_send_remote_use_active(struct vchiq_state *state);
void vchiq_platform_conn_state_changed(struct vchiq_state *state,
enum vchiq_connstate oldstate,
@@ -584,7 +602,7 @@ void vchiq_set_conn_state(struct vchiq_state *state, enum vchiq_connstate newsta
void vchiq_log_dump_mem(const char *label, u32 addr, const void *void_mem, size_t num_bytes);
-enum vchiq_status vchiq_remove_service(struct vchiq_instance *instance, unsigned int service);
+int vchiq_remove_service(struct vchiq_instance *instance, unsigned int service);
int vchiq_get_client_id(struct vchiq_instance *instance, unsigned int service);
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c
index 7e297494437e..841e1a535642 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c
@@ -112,7 +112,7 @@ vchiq_ioc_queue_message(struct vchiq_instance *instance, unsigned int handle,
struct vchiq_element *elements, unsigned long count)
{
struct vchiq_io_copy_callback_context context;
- enum vchiq_status status = VCHIQ_SUCCESS;
+ int status = 0;
unsigned long i;
size_t total_size = 0;
@@ -130,9 +130,9 @@ vchiq_ioc_queue_message(struct vchiq_instance *instance, unsigned int handle,
status = vchiq_queue_message(instance, handle, vchiq_ioc_copy_element_data,
&context, total_size);
- if (status == VCHIQ_ERROR)
+ if (status == -EINVAL)
return -EIO;
- else if (status == VCHIQ_RETRY)
+ else if (status == -EAGAIN)
return -EINTR;
return 0;
}
@@ -142,7 +142,7 @@ static int vchiq_ioc_create_service(struct vchiq_instance *instance,
{
struct user_service *user_service = NULL;
struct vchiq_service *service;
- enum vchiq_status status = VCHIQ_SUCCESS;
+ int status = 0;
struct vchiq_service_params_kernel params;
int srvstate;
@@ -190,9 +190,9 @@ static int vchiq_ioc_create_service(struct vchiq_instance *instance,
if (args->is_open) {
status = vchiq_open_service_internal(service, instance->pid);
- if (status != VCHIQ_SUCCESS) {
+ if (status) {
vchiq_remove_service(instance, service->handle);
- return (status == VCHIQ_RETRY) ?
+ return (status == -EAGAIN) ?
-EINTR : -EIO;
}
}
@@ -338,7 +338,7 @@ static int vchiq_irq_queue_bulk_tx_rx(struct vchiq_instance *instance,
goto out;
}
- if ((status != VCHIQ_RETRY) || fatal_signal_pending(current) ||
+ if ((status != -EAGAIN) || fatal_signal_pending(current) ||
!waiter->bulk_waiter.bulk) {
if (waiter->bulk_waiter.bulk) {
/* Cancel the signal when the transfer completes. */
@@ -364,9 +364,9 @@ out:
vchiq_service_put(service);
if (ret)
return ret;
- else if (status == VCHIQ_ERROR)
+ else if (status == -EINVAL)
return -EIO;
- else if (status == VCHIQ_RETRY)
+ else if (status == -EAGAIN)
return -EINTR;
return 0;
}
@@ -577,7 +577,7 @@ static long
vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct vchiq_instance *instance = file->private_data;
- enum vchiq_status status = VCHIQ_SUCCESS;
+ int status = 0;
struct vchiq_service *service = NULL;
long ret = 0;
int i, rc;
@@ -598,12 +598,12 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
instance, &i))) {
status = vchiq_remove_service(instance, service->handle);
vchiq_service_put(service);
- if (status != VCHIQ_SUCCESS)
+ if (status)
break;
}
service = NULL;
- if (status == VCHIQ_SUCCESS) {
+ if (!status) {
/* Wake the completion thread and ask it to exit */
instance->closing = 1;
complete(&instance->insert_event);
@@ -627,7 +627,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
status = vchiq_connect_internal(instance->state, instance);
mutex_unlock(&instance->state->mutex);
- if (status == VCHIQ_SUCCESS)
+ if (!status)
instance->connected = 1;
else
vchiq_log_error(vchiq_arm_log_level,
@@ -675,7 +675,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
status = (cmd == VCHIQ_IOC_CLOSE_SERVICE) ?
vchiq_close_service(instance, service->handle) :
vchiq_remove_service(instance, service->handle);
- if (status != VCHIQ_SUCCESS)
+ if (status)
break;
}
@@ -686,7 +686,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
*/
if (user_service->close_pending &&
wait_for_completion_interruptible(&user_service->close_event))
- status = VCHIQ_RETRY;
+ status = -EAGAIN;
break;
}
@@ -862,13 +862,13 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
vchiq_service_put(service);
if (ret == 0) {
- if (status == VCHIQ_ERROR)
+ if (status == -EINVAL)
ret = -EIO;
- else if (status == VCHIQ_RETRY)
+ else if (status == -EAGAIN)
ret = -EINTR;
}
- if ((status == VCHIQ_SUCCESS) && (ret < 0) && (ret != -EINTR) && (ret != -EWOULDBLOCK))
+ if (!status && (ret < 0) && (ret != -EINTR) && (ret != -EWOULDBLOCK))
vchiq_log_info(vchiq_arm_log_level,
" ioctl instance %pK, cmd %s -> status %d, %ld",
instance, (_IOC_NR(cmd) <= VCHIQ_IOC_MAX) ?
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_ioctl.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_ioctl.h
index 86d77f2eeea5..17550831f86c 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_ioctl.h
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_ioctl.h
@@ -5,17 +5,18 @@
#define VCHIQ_IOCTLS_H
#include <linux/ioctl.h>
-#include <linux/raspberrypi/vchiq.h>
+
+#include "../../include/linux/raspberrypi/vchiq.h"
#define VCHIQ_IOC_MAGIC 0xc4
#define VCHIQ_INVALID_HANDLE (~0)
struct vchiq_service_params {
int fourcc;
- enum vchiq_status __user (*callback)(enum vchiq_reason reason,
- struct vchiq_header *header,
- unsigned int handle,
- void *bulk_userdata);
+ int __user (*callback)(enum vchiq_reason reason,
+ struct vchiq_header *header,
+ unsigned int handle,
+ void *bulk_userdata);
void __user *userdata;
short version; /* Increment for non-trivial changes */
short version_min; /* Update for incompatible changes */
diff --git a/drivers/staging/vc04_services/vchiq-mmal/Makefile b/drivers/staging/vc04_services/vchiq-mmal/Makefile
index b2a830f48acc..6937f6534c26 100644
--- a/drivers/staging/vc04_services/vchiq-mmal/Makefile
+++ b/drivers/staging/vc04_services/vchiq-mmal/Makefile
@@ -2,8 +2,3 @@
bcm2835-mmal-vchiq-objs := mmal-vchiq.o
obj-$(CONFIG_BCM2835_VCHIQ_MMAL) += bcm2835-mmal-vchiq.o
-
-ccflags-y += \
- -I$(srctree)/$(src)/.. \
- -I$(srctree)/$(src)/../include \
- -D__VCCOREVER__=0x04000000
diff --git a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
index 294b184d4a49..258aa0e37f55 100644
--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
@@ -23,9 +23,9 @@
#include <linux/slab.h>
#include <linux/completion.h>
#include <linux/vmalloc.h>
-#include <linux/raspberrypi/vchiq.h>
#include <media/videobuf2-vmalloc.h>
+#include "../include/linux/raspberrypi/vchiq.h"
#include "mmal-common.h"
#include "mmal-vchiq.h"
#include "mmal-msg.h"
@@ -245,7 +245,7 @@ static void event_to_host_cb(struct vchiq_mmal_instance *instance,
/* workqueue scheduled callback
*
* we do this because it is important we do not call any other vchiq
- * sync calls from witin the message delivery thread
+ * sync calls from within the message delivery thread
*/
static void buffer_work_cb(struct work_struct *work)
{
@@ -548,10 +548,9 @@ static void bulk_abort_cb(struct vchiq_mmal_instance *instance,
}
/* incoming event service callback */
-static enum vchiq_status service_callback(struct vchiq_instance *vchiq_instance,
- enum vchiq_reason reason,
- struct vchiq_header *header,
- unsigned int handle, void *bulk_ctx)
+static int service_callback(struct vchiq_instance *vchiq_instance,
+ enum vchiq_reason reason, struct vchiq_header *header,
+ unsigned int handle, void *bulk_ctx)
{
struct vchiq_mmal_instance *instance = vchiq_get_service_userdata(vchiq_instance, handle);
u32 msg_len;
@@ -560,7 +559,7 @@ static enum vchiq_status service_callback(struct vchiq_instance *vchiq_instance,
if (!instance) {
pr_err("Message callback passed NULL instance\n");
- return VCHIQ_SUCCESS;
+ return 0;
}
switch (reason) {
@@ -644,7 +643,7 @@ static enum vchiq_status service_callback(struct vchiq_instance *vchiq_instance,
break;
}
- return VCHIQ_SUCCESS;
+ return 0;
}
static int send_synchronous_mmal_msg(struct vchiq_mmal_instance *instance,
diff --git a/drivers/staging/vme_user/vme.h b/drivers/staging/vme_user/vme.h
index 98da8d039d60..faa9816046a9 100644
--- a/drivers/staging/vme_user/vme.h
+++ b/drivers/staging/vme_user/vme.h
@@ -2,6 +2,8 @@
#ifndef _VME_H_
#define _VME_H_
+#include <linux/bitops.h>
+
/* Resource Type */
enum vme_resource_type {
VME_MASTER,
@@ -54,20 +56,20 @@ enum vme_resource_type {
#define VME_R_ROBIN_MODE 0x1
#define VME_PRIORITY_MODE 0x2
-#define VME_DMA_PATTERN (1<<0)
-#define VME_DMA_PCI (1<<1)
-#define VME_DMA_VME (1<<2)
+#define VME_DMA_PATTERN BIT(0)
+#define VME_DMA_PCI BIT(1)
+#define VME_DMA_VME BIT(2)
-#define VME_DMA_PATTERN_BYTE (1<<0)
-#define VME_DMA_PATTERN_WORD (1<<1)
-#define VME_DMA_PATTERN_INCREMENT (1<<2)
+#define VME_DMA_PATTERN_BYTE BIT(0)
+#define VME_DMA_PATTERN_WORD BIT(1)
+#define VME_DMA_PATTERN_INCREMENT BIT(2)
-#define VME_DMA_VME_TO_MEM (1<<0)
-#define VME_DMA_MEM_TO_VME (1<<1)
-#define VME_DMA_VME_TO_VME (1<<2)
-#define VME_DMA_MEM_TO_MEM (1<<3)
-#define VME_DMA_PATTERN_TO_VME (1<<4)
-#define VME_DMA_PATTERN_TO_MEM (1<<5)
+#define VME_DMA_VME_TO_MEM BIT(0)
+#define VME_DMA_MEM_TO_VME BIT(1)
+#define VME_DMA_VME_TO_VME BIT(2)
+#define VME_DMA_MEM_TO_MEM BIT(3)
+#define VME_DMA_PATTERN_TO_VME BIT(4)
+#define VME_DMA_PATTERN_TO_MEM BIT(5)
struct vme_dma_attr {
u32 type;
diff --git a/drivers/staging/vme_user/vme_bridge.h b/drivers/staging/vme_user/vme_bridge.h
index 0bbefe9851d7..11df0a5e7f7b 100644
--- a/drivers/staging/vme_user/vme_bridge.h
+++ b/drivers/staging/vme_user/vme_bridge.h
@@ -4,7 +4,7 @@
#include "vme.h"
-#define VME_CRCSR_BUF_SIZE (508*1024)
+#define VME_CRCSR_BUF_SIZE (508 * 1024)
/*
* Resource structures
*/
@@ -84,7 +84,7 @@ struct vme_error_handler {
unsigned long long end; /* End of error window */
unsigned long long first_error; /* Address of the first error */
u32 aspace; /* Address space of error window*/
- unsigned num_errors; /* Number of errors */
+ unsigned int num_errors; /* Number of errors */
};
struct vme_callback {
@@ -128,45 +128,45 @@ struct vme_bridge {
struct mutex irq_mtx;
/* Slave Functions */
- int (*slave_get) (struct vme_slave_resource *, int *,
+ int (*slave_get)(struct vme_slave_resource *, int *,
unsigned long long *, unsigned long long *, dma_addr_t *,
u32 *, u32 *);
- int (*slave_set) (struct vme_slave_resource *, int, unsigned long long,
+ int (*slave_set)(struct vme_slave_resource *, int, unsigned long long,
unsigned long long, dma_addr_t, u32, u32);
/* Master Functions */
- int (*master_get) (struct vme_master_resource *, int *,
+ int (*master_get)(struct vme_master_resource *, int *,
unsigned long long *, unsigned long long *, u32 *, u32 *,
u32 *);
- int (*master_set) (struct vme_master_resource *, int,
+ int (*master_set)(struct vme_master_resource *, int,
unsigned long long, unsigned long long, u32, u32, u32);
- ssize_t (*master_read) (struct vme_master_resource *, void *, size_t,
+ ssize_t (*master_read)(struct vme_master_resource *, void *, size_t,
loff_t);
- ssize_t (*master_write) (struct vme_master_resource *, void *, size_t,
+ ssize_t (*master_write)(struct vme_master_resource *, void *, size_t,
loff_t);
- unsigned int (*master_rmw) (struct vme_master_resource *, unsigned int,
+ unsigned int (*master_rmw)(struct vme_master_resource *, unsigned int,
unsigned int, unsigned int, loff_t);
/* DMA Functions */
- int (*dma_list_add) (struct vme_dma_list *, struct vme_dma_attr *,
+ int (*dma_list_add)(struct vme_dma_list *, struct vme_dma_attr *,
struct vme_dma_attr *, size_t);
- int (*dma_list_exec) (struct vme_dma_list *);
- int (*dma_list_empty) (struct vme_dma_list *);
+ int (*dma_list_exec)(struct vme_dma_list *);
+ int (*dma_list_empty)(struct vme_dma_list *);
/* Interrupt Functions */
- void (*irq_set) (struct vme_bridge *, int, int, int);
- int (*irq_generate) (struct vme_bridge *, int, int);
+ void (*irq_set)(struct vme_bridge *, int, int, int);
+ int (*irq_generate)(struct vme_bridge *, int, int);
/* Location monitor functions */
- int (*lm_set) (struct vme_lm_resource *, unsigned long long, u32, u32);
- int (*lm_get) (struct vme_lm_resource *, unsigned long long *, u32 *,
+ int (*lm_set)(struct vme_lm_resource *, unsigned long long, u32, u32);
+ int (*lm_get)(struct vme_lm_resource *, unsigned long long *, u32 *,
u32 *);
int (*lm_attach)(struct vme_lm_resource *, int,
void (*callback)(void *), void *);
- int (*lm_detach) (struct vme_lm_resource *, int);
+ int (*lm_detach)(struct vme_lm_resource *, int);
/* CR/CSR space functions */
- int (*slot_get) (struct vme_bridge *);
+ int (*slot_get)(struct vme_bridge *);
/* Bridge parent interface */
void *(*alloc_consistent)(struct device *dev, size_t size,
diff --git a/drivers/staging/wlan-ng/hfa384x.h b/drivers/staging/wlan-ng/hfa384x.h
index 0611e37df6ac..e33dd1b9c40e 100644
--- a/drivers/staging/wlan-ng/hfa384x.h
+++ b/drivers/staging/wlan-ng/hfa384x.h
@@ -904,40 +904,6 @@ union hfa384x_usbin {
*--------------------------------------------------------------------
*/
-struct hfa384x_pdr_pcb_partnum {
- u8 num[8];
-} __packed;
-
-struct hfa384x_pdr_pcb_tracenum {
- u8 num[8];
-} __packed;
-
-struct hfa384x_pdr_nic_serial {
- u8 num[12];
-} __packed;
-
-struct hfa384x_pdr_mkk_measurements {
- double carrier_freq;
- double occupied_band;
- double power_density;
- double tx_spur_f1;
- double tx_spur_f2;
- double tx_spur_f3;
- double tx_spur_f4;
- double tx_spur_l1;
- double tx_spur_l2;
- double tx_spur_l3;
- double tx_spur_l4;
- double rx_spur_f1;
- double rx_spur_f2;
- double rx_spur_l1;
- double rx_spur_l2;
-} __packed;
-
-struct hfa384x_pdr_nic_ramsize {
- u8 size[12]; /* units of KB */
-} __packed;
-
struct hfa384x_pdr_mfisuprange {
u16 id;
u16 variant;
@@ -959,150 +925,13 @@ struct hfa384x_pdr_nicid {
u16 minor;
} __packed;
-struct hfa384x_pdr_refdac_measurements {
- u16 value[0];
-} __packed;
-
-struct hfa384x_pdr_vgdac_measurements {
- u16 value[0];
-} __packed;
-
-struct hfa384x_pdr_level_comp_measurements {
- u16 value[0];
-} __packed;
-
-struct hfa384x_pdr_mac_address {
- u8 addr[6];
-} __packed;
-
-struct hfa384x_pdr_mkk_callname {
- u8 callname[8];
-} __packed;
-
-struct hfa384x_pdr_regdomain {
- u16 numdomains;
- u16 domain[5];
-} __packed;
-
-struct hfa384x_pdr_allowed_channel {
- u16 ch_bitmap;
-} __packed;
-
-struct hfa384x_pdr_default_channel {
- u16 channel;
-} __packed;
-
-struct hfa384x_pdr_privacy_option {
- u16 available;
-} __packed;
-
-struct hfa384x_pdr_temptype {
- u16 type;
-} __packed;
-
-struct hfa384x_pdr_refdac_setup {
- u16 ch_value[14];
-} __packed;
-
-struct hfa384x_pdr_vgdac_setup {
- u16 ch_value[14];
-} __packed;
-
-struct hfa384x_pdr_level_comp_setup {
- u16 ch_value[14];
-} __packed;
-
-struct hfa384x_pdr_trimdac_setup {
- u16 trimidac;
- u16 trimqdac;
-} __packed;
-
-struct hfa384x_pdr_ifr_setting {
- u16 value[3];
-} __packed;
-
-struct hfa384x_pdr_rfr_setting {
- u16 value[3];
-} __packed;
-
-struct hfa384x_pdr_hfa3861_baseline {
- u16 value[50];
-} __packed;
-
-struct hfa384x_pdr_hfa3861_shadow {
- u32 value[32];
-} __packed;
-
-struct hfa384x_pdr_hfa3861_ifrf {
- u32 value[20];
-} __packed;
-
-struct hfa384x_pdr_hfa3861_chcalsp {
- u16 value[14];
-} __packed;
-
-struct hfa384x_pdr_hfa3861_chcali {
- u16 value[17];
-} __packed;
-
-struct hfa384x_pdr_hfa3861_nic_config {
- u16 config_bitmap;
-} __packed;
-
-struct hfa384x_pdr_hfo_delay {
- u8 hfo_delay;
-} __packed;
-
-struct hfa384x_pdr_hfa3861_manf_testsp {
- u16 value[30];
-} __packed;
-
-struct hfa384x_pdr_hfa3861_manf_testi {
- u16 value[30];
-} __packed;
-
-struct hfa384x_pdr_end_of_pda {
- u16 crc;
-} __packed;
-
struct hfa384x_pdrec {
__le16 len; /* in words */
__le16 code;
union pdr {
- struct hfa384x_pdr_pcb_partnum pcb_partnum;
- struct hfa384x_pdr_pcb_tracenum pcb_tracenum;
- struct hfa384x_pdr_nic_serial nic_serial;
- struct hfa384x_pdr_mkk_measurements mkk_measurements;
- struct hfa384x_pdr_nic_ramsize nic_ramsize;
struct hfa384x_pdr_mfisuprange mfisuprange;
struct hfa384x_pdr_cfisuprange cfisuprange;
struct hfa384x_pdr_nicid nicid;
- struct hfa384x_pdr_refdac_measurements refdac_measurements;
- struct hfa384x_pdr_vgdac_measurements vgdac_measurements;
- struct hfa384x_pdr_level_comp_measurements level_compc_measurements;
- struct hfa384x_pdr_mac_address mac_address;
- struct hfa384x_pdr_mkk_callname mkk_callname;
- struct hfa384x_pdr_regdomain regdomain;
- struct hfa384x_pdr_allowed_channel allowed_channel;
- struct hfa384x_pdr_default_channel default_channel;
- struct hfa384x_pdr_privacy_option privacy_option;
- struct hfa384x_pdr_temptype temptype;
- struct hfa384x_pdr_refdac_setup refdac_setup;
- struct hfa384x_pdr_vgdac_setup vgdac_setup;
- struct hfa384x_pdr_level_comp_setup level_comp_setup;
- struct hfa384x_pdr_trimdac_setup trimdac_setup;
- struct hfa384x_pdr_ifr_setting ifr_setting;
- struct hfa384x_pdr_rfr_setting rfr_setting;
- struct hfa384x_pdr_hfa3861_baseline hfa3861_baseline;
- struct hfa384x_pdr_hfa3861_shadow hfa3861_shadow;
- struct hfa384x_pdr_hfa3861_ifrf hfa3861_ifrf;
- struct hfa384x_pdr_hfa3861_chcalsp hfa3861_chcalsp;
- struct hfa384x_pdr_hfa3861_chcali hfa3861_chcali;
- struct hfa384x_pdr_hfa3861_nic_config nic_config;
- struct hfa384x_pdr_hfo_delay hfo_delay;
- struct hfa384x_pdr_hfa3861_manf_testsp hfa3861_manf_testsp;
- struct hfa384x_pdr_hfa3861_manf_testi hfa3861_manf_testi;
- struct hfa384x_pdr_end_of_pda end_of_pda;
} data;
} __packed;
diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c
index 69a4c9581e80..e7425549e39c 100644
--- a/drivers/target/target_core_pscsi.c
+++ b/drivers/target/target_core_pscsi.c
@@ -144,8 +144,7 @@ static void pscsi_tape_read_blocksize(struct se_device *dev,
cdb[0] = MODE_SENSE;
cdb[4] = 0x0c; /* 12 bytes */
- ret = scsi_execute_req(sdev, cdb, DMA_FROM_DEVICE, buf, 12, NULL,
- HZ, 1, NULL);
+ ret = scsi_execute_cmd(sdev, cdb, REQ_OP_DRV_IN, buf, 12, HZ, 1, NULL);
if (ret)
goto out_free;
@@ -195,8 +194,8 @@ pscsi_get_inquiry_vpd_serial(struct scsi_device *sdev, struct t10_wwn *wwn)
cdb[2] = 0x80; /* Unit Serial Number */
put_unaligned_be16(INQUIRY_VPD_SERIAL_LEN, &cdb[3]);
- ret = scsi_execute_req(sdev, cdb, DMA_FROM_DEVICE, buf,
- INQUIRY_VPD_SERIAL_LEN, NULL, HZ, 1, NULL);
+ ret = scsi_execute_cmd(sdev, cdb, REQ_OP_DRV_IN, buf,
+ INQUIRY_VPD_SERIAL_LEN, HZ, 1, NULL);
if (ret)
goto out_free;
@@ -230,9 +229,8 @@ pscsi_get_inquiry_vpd_device_ident(struct scsi_device *sdev,
cdb[2] = 0x83; /* Device Identifier */
put_unaligned_be16(INQUIRY_VPD_DEVICE_IDENTIFIER_LEN, &cdb[3]);
- ret = scsi_execute_req(sdev, cdb, DMA_FROM_DEVICE, buf,
- INQUIRY_VPD_DEVICE_IDENTIFIER_LEN,
- NULL, HZ, 1, NULL);
+ ret = scsi_execute_cmd(sdev, cdb, REQ_OP_DRV_IN, buf,
+ INQUIRY_VPD_DEVICE_IDENTIFIER_LEN, HZ, 1, NULL);
if (ret)
goto out;
diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c
index 2940559c3086..15ffc8d2ac7b 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -1928,7 +1928,7 @@ static int tcmu_mmap(struct uio_info *info, struct vm_area_struct *vma)
{
struct tcmu_dev *udev = container_of(info, struct tcmu_dev, uio_info);
- vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
+ vm_flags_set(vma, VM_DONTEXPAND | VM_DONTDUMP);
vma->vm_ops = &tcmu_vm_ops;
vma->vm_private_data = udev;
diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
index 98da206cd761..452cbb8ad484 100644
--- a/drivers/tee/tee_core.c
+++ b/drivers/tee/tee_core.c
@@ -1207,7 +1207,7 @@ static int tee_client_device_match(struct device *dev,
return 0;
}
-static int tee_client_device_uevent(struct device *dev,
+static int tee_client_device_uevent(const struct device *dev,
struct kobj_uevent_env *env)
{
uuid_t *dev_id = &to_tee_client_device(dev)->id.uuid;
diff --git a/drivers/thermal/qcom/lmh.c b/drivers/thermal/qcom/lmh.c
index 4122a51e9874..f6edb12ec004 100644
--- a/drivers/thermal/qcom/lmh.c
+++ b/drivers/thermal/qcom/lmh.c
@@ -10,7 +10,7 @@
#include <linux/platform_device.h>
#include <linux/of_platform.h>
#include <linux/slab.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#define LMH_NODE_DCVS 0x44435653
#define LMH_CLUSTER0_NODE_ID 0x6370302D
diff --git a/drivers/thunderbolt/acpi.c b/drivers/thunderbolt/acpi.c
index 317e4f5fdb97..628225deb8fe 100644
--- a/drivers/thunderbolt/acpi.c
+++ b/drivers/thunderbolt/acpi.c
@@ -36,16 +36,13 @@ static acpi_status tb_acpi_add_link(acpi_handle handle, u32 level, void *data,
* We need to do this because the xHCI driver might not yet be
* bound so the USB3 SuperSpeed ports are not yet created.
*/
- dev = acpi_get_first_physical_node(adev);
- while (!dev) {
- adev = acpi_dev_parent(adev);
- if (!adev)
- break;
+ do {
dev = acpi_get_first_physical_node(adev);
- }
+ if (dev)
+ break;
- if (!dev)
- goto out_put;
+ adev = acpi_dev_parent(adev);
+ } while (adev);
/*
* Check that the device is PCIe. This is because USB3
diff --git a/drivers/thunderbolt/ctl.c b/drivers/thunderbolt/ctl.c
index 0c661a706160..6e7d28e8d81a 100644
--- a/drivers/thunderbolt/ctl.c
+++ b/drivers/thunderbolt/ctl.c
@@ -230,7 +230,6 @@ static int check_config_address(struct tb_cfg_address addr,
static struct tb_cfg_result decode_error(const struct ctl_pkg *response)
{
struct cfg_error_pkg *pkg = response->buffer;
- struct tb_ctl *ctl = response->ctl;
struct tb_cfg_result res = { 0 };
res.response_route = tb_cfg_get_route(&pkg->header);
res.response_port = 0;
@@ -239,13 +238,6 @@ static struct tb_cfg_result decode_error(const struct ctl_pkg *response)
if (res.err)
return res;
- if (pkg->zero1)
- tb_ctl_warn(ctl, "pkg->zero1 is %#x\n", pkg->zero1);
- if (pkg->zero2)
- tb_ctl_warn(ctl, "pkg->zero2 is %#x\n", pkg->zero2);
- if (pkg->zero3)
- tb_ctl_warn(ctl, "pkg->zero3 is %#x\n", pkg->zero3);
-
res.err = 1;
res.tb_error = pkg->error;
res.response_port = pkg->port;
@@ -416,6 +408,7 @@ static int tb_async_error(const struct ctl_pkg *pkg)
case TB_CFG_ERROR_LINK_ERROR:
case TB_CFG_ERROR_HEC_ERROR_DETECTED:
case TB_CFG_ERROR_FLOW_CONTROL_ERROR:
+ case TB_CFG_ERROR_DP_BW:
return true;
default:
@@ -736,6 +729,47 @@ void tb_ctl_stop(struct tb_ctl *ctl)
/* public interface, commands */
/**
+ * tb_cfg_ack_notification() - Ack notification
+ * @ctl: Control channel to use
+ * @route: Router that originated the event
+ * @error: Pointer to the notification package
+ *
+ * Call this as response for non-plug notification to ack it. Returns
+ * %0 on success or an error code on failure.
+ */
+int tb_cfg_ack_notification(struct tb_ctl *ctl, u64 route,
+ const struct cfg_error_pkg *error)
+{
+ struct cfg_ack_pkg pkg = {
+ .header = tb_cfg_make_header(route),
+ };
+ const char *name;
+
+ switch (error->error) {
+ case TB_CFG_ERROR_LINK_ERROR:
+ name = "link error";
+ break;
+ case TB_CFG_ERROR_HEC_ERROR_DETECTED:
+ name = "HEC error";
+ break;
+ case TB_CFG_ERROR_FLOW_CONTROL_ERROR:
+ name = "flow control error";
+ break;
+ case TB_CFG_ERROR_DP_BW:
+ name = "DP_BW";
+ break;
+ default:
+ name = "unknown";
+ break;
+ }
+
+ tb_ctl_dbg(ctl, "acking %s (%#x) notification on %llx\n", name,
+ error->error, route);
+
+ return tb_ctl_tx(ctl, &pkg, sizeof(pkg), TB_CFG_PKG_NOTIFY_ACK);
+}
+
+/**
* tb_cfg_ack_plug() - Ack hot plug/unplug event
* @ctl: Control channel to use
* @route: Router that originated the event
@@ -754,7 +788,7 @@ int tb_cfg_ack_plug(struct tb_ctl *ctl, u64 route, u32 port, bool unplug)
.pg = unplug ? TB_CFG_ERROR_PG_HOT_UNPLUG
: TB_CFG_ERROR_PG_HOT_PLUG,
};
- tb_ctl_dbg(ctl, "acking hot %splug event on %llx:%x\n",
+ tb_ctl_dbg(ctl, "acking hot %splug event on %llx:%u\n",
unplug ? "un" : "", route, port);
return tb_ctl_tx(ctl, &pkg, sizeof(pkg), TB_CFG_PKG_ERROR);
}
diff --git a/drivers/thunderbolt/ctl.h b/drivers/thunderbolt/ctl.h
index 7c7d80f96c0c..eec5c953c743 100644
--- a/drivers/thunderbolt/ctl.h
+++ b/drivers/thunderbolt/ctl.h
@@ -122,6 +122,8 @@ static inline struct tb_cfg_header tb_cfg_make_header(u64 route)
return header;
}
+int tb_cfg_ack_notification(struct tb_ctl *ctl, u64 route,
+ const struct cfg_error_pkg *error);
int tb_cfg_ack_plug(struct tb_ctl *ctl, u64 route, u32 port, bool unplug);
struct tb_cfg_result tb_cfg_reset(struct tb_ctl *ctl, u64 route);
struct tb_cfg_result tb_cfg_read_raw(struct tb_ctl *ctl, void *buffer,
diff --git a/drivers/thunderbolt/debugfs.c b/drivers/thunderbolt/debugfs.c
index 834bcad42e9f..4339e706cc3a 100644
--- a/drivers/thunderbolt/debugfs.c
+++ b/drivers/thunderbolt/debugfs.c
@@ -1159,7 +1159,10 @@ static void port_cap_show(struct tb_port *port, struct seq_file *s,
if (tb_port_is_pcie_down(port) || tb_port_is_pcie_up(port)) {
length = PORT_CAP_PCIE_LEN;
} else if (tb_port_is_dpin(port) || tb_port_is_dpout(port)) {
- length = PORT_CAP_DP_LEN;
+ if (usb4_dp_port_bw_mode_supported(port))
+ length = PORT_CAP_DP_LEN + 1;
+ else
+ length = PORT_CAP_DP_LEN;
} else if (tb_port_is_usb3_down(port) ||
tb_port_is_usb3_up(port)) {
length = PORT_CAP_USB3_LEN;
diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c
index 363d712aa364..3370e18ba05f 100644
--- a/drivers/thunderbolt/switch.c
+++ b/drivers/thunderbolt/switch.c
@@ -513,36 +513,44 @@ int tb_wait_for_port(struct tb_port *port, bool wait_if_unplugged)
while (retries--) {
state = tb_port_state(port);
- if (state < 0)
- return state;
- if (state == TB_PORT_DISABLED) {
+ switch (state) {
+ case TB_PORT_DISABLED:
tb_port_dbg(port, "is disabled (state: 0)\n");
return 0;
- }
- if (state == TB_PORT_UNPLUGGED) {
+
+ case TB_PORT_UNPLUGGED:
if (wait_if_unplugged) {
/* used during resume */
tb_port_dbg(port,
"is unplugged (state: 7), retrying...\n");
msleep(100);
- continue;
+ break;
}
tb_port_dbg(port, "is unplugged (state: 7)\n");
return 0;
- }
- if (state == TB_PORT_UP) {
- tb_port_dbg(port, "is connected, link is up (state: 2)\n");
+
+ case TB_PORT_UP:
+ case TB_PORT_TX_CL0S:
+ case TB_PORT_RX_CL0S:
+ case TB_PORT_CL1:
+ case TB_PORT_CL2:
+ tb_port_dbg(port, "is connected, link is up (state: %d)\n", state);
return 1;
+
+ default:
+ if (state < 0)
+ return state;
+
+ /*
+ * After plug-in the state is TB_PORT_CONNECTING. Give it some
+ * time.
+ */
+ tb_port_dbg(port,
+ "is connected, link is not up (state: %d), retrying...\n",
+ state);
+ msleep(100);
}
- /*
- * After plug-in the state is TB_PORT_CONNECTING. Give it some
- * time.
- */
- tb_port_dbg(port,
- "is connected, link is not up (state: %d), retrying...\n",
- state);
- msleep(100);
}
tb_port_warn(port,
"failed to reach state TB_PORT_UP. Ignoring port...\n");
@@ -2176,9 +2184,9 @@ static void tb_switch_release(struct device *dev)
kfree(sw);
}
-static int tb_switch_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int tb_switch_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct tb_switch *sw = tb_to_switch(dev);
+ const struct tb_switch *sw = tb_to_switch(dev);
const char *type;
if (sw->config.thunderbolt_version == USB4_VERSION_1_0) {
diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c
index 3f1ab30c4fb1..7bfbc9ca9ba4 100644
--- a/drivers/thunderbolt/tb.c
+++ b/drivers/thunderbolt/tb.c
@@ -16,7 +16,8 @@
#include "tb_regs.h"
#include "tunnel.h"
-#define TB_TIMEOUT 100 /* ms */
+#define TB_TIMEOUT 100 /* ms */
+#define MAX_GROUPS 7 /* max Group_ID is 7 */
/**
* struct tb_cm - Simple Thunderbolt connection manager
@@ -28,12 +29,14 @@
* after cfg has been paused.
* @remove_work: Work used to remove any unplugged routers after
* runtime resume
+ * @groups: Bandwidth groups used in this domain.
*/
struct tb_cm {
struct list_head tunnel_list;
struct list_head dp_resources;
bool hotplug_active;
struct delayed_work remove_work;
+ struct tb_bandwidth_group groups[MAX_GROUPS];
};
static inline struct tb *tcm_to_tb(struct tb_cm *tcm)
@@ -49,6 +52,112 @@ struct tb_hotplug_event {
bool unplug;
};
+static void tb_init_bandwidth_groups(struct tb_cm *tcm)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(tcm->groups); i++) {
+ struct tb_bandwidth_group *group = &tcm->groups[i];
+
+ group->tb = tcm_to_tb(tcm);
+ group->index = i + 1;
+ INIT_LIST_HEAD(&group->ports);
+ }
+}
+
+static void tb_bandwidth_group_attach_port(struct tb_bandwidth_group *group,
+ struct tb_port *in)
+{
+ if (!group || WARN_ON(in->group))
+ return;
+
+ in->group = group;
+ list_add_tail(&in->group_list, &group->ports);
+
+ tb_port_dbg(in, "attached to bandwidth group %d\n", group->index);
+}
+
+static struct tb_bandwidth_group *tb_find_free_bandwidth_group(struct tb_cm *tcm)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(tcm->groups); i++) {
+ struct tb_bandwidth_group *group = &tcm->groups[i];
+
+ if (list_empty(&group->ports))
+ return group;
+ }
+
+ return NULL;
+}
+
+static struct tb_bandwidth_group *
+tb_attach_bandwidth_group(struct tb_cm *tcm, struct tb_port *in,
+ struct tb_port *out)
+{
+ struct tb_bandwidth_group *group;
+ struct tb_tunnel *tunnel;
+
+ /*
+ * Find all DP tunnels that go through all the same USB4 links
+ * as this one. Because we always setup tunnels the same way we
+ * can just check for the routers at both ends of the tunnels
+ * and if they are the same we have a match.
+ */
+ list_for_each_entry(tunnel, &tcm->tunnel_list, list) {
+ if (!tb_tunnel_is_dp(tunnel))
+ continue;
+
+ if (tunnel->src_port->sw == in->sw &&
+ tunnel->dst_port->sw == out->sw) {
+ group = tunnel->src_port->group;
+ if (group) {
+ tb_bandwidth_group_attach_port(group, in);
+ return group;
+ }
+ }
+ }
+
+ /* Pick up next available group then */
+ group = tb_find_free_bandwidth_group(tcm);
+ if (group)
+ tb_bandwidth_group_attach_port(group, in);
+ else
+ tb_port_warn(in, "no available bandwidth groups\n");
+
+ return group;
+}
+
+static void tb_discover_bandwidth_group(struct tb_cm *tcm, struct tb_port *in,
+ struct tb_port *out)
+{
+ if (usb4_dp_port_bw_mode_enabled(in)) {
+ int index, i;
+
+ index = usb4_dp_port_group_id(in);
+ for (i = 0; i < ARRAY_SIZE(tcm->groups); i++) {
+ if (tcm->groups[i].index == index) {
+ tb_bandwidth_group_attach_port(&tcm->groups[i], in);
+ return;
+ }
+ }
+ }
+
+ tb_attach_bandwidth_group(tcm, in, out);
+}
+
+static void tb_detach_bandwidth_group(struct tb_port *in)
+{
+ struct tb_bandwidth_group *group = in->group;
+
+ if (group) {
+ in->group = NULL;
+ list_del_init(&in->group_list);
+
+ tb_port_dbg(in, "detached from bandwidth group %d\n", group->index);
+ }
+}
+
static void tb_handle_hotplug(struct work_struct *work);
static void tb_queue_hotplug(struct tb *tb, u64 route, u8 port, bool unplug)
@@ -193,9 +302,14 @@ static void tb_discover_tunnels(struct tb *tb)
parent = tb_switch_parent(parent);
}
} else if (tb_tunnel_is_dp(tunnel)) {
+ struct tb_port *in = tunnel->src_port;
+ struct tb_port *out = tunnel->dst_port;
+
/* Keep the domain from powering down */
- pm_runtime_get_sync(&tunnel->src_port->sw->dev);
- pm_runtime_get_sync(&tunnel->dst_port->sw->dev);
+ pm_runtime_get_sync(&in->sw->dev);
+ pm_runtime_get_sync(&out->sw->dev);
+
+ tb_discover_bandwidth_group(tcm, in, out);
}
}
}
@@ -350,10 +464,13 @@ static int tb_available_bandwidth(struct tb *tb, struct tb_port *src_port,
struct tb_tunnel *tunnel;
struct tb_port *port;
- tb_port_dbg(dst_port, "calculating available bandwidth\n");
+ tb_dbg(tb, "calculating available bandwidth between %llx:%u <-> %llx:%u\n",
+ tb_route(src_port->sw), src_port->port, tb_route(dst_port->sw),
+ dst_port->port);
tunnel = tb_find_first_usb3_tunnel(tb, src_port, dst_port);
- if (tunnel) {
+ if (tunnel && tunnel->src_port != src_port &&
+ tunnel->dst_port != dst_port) {
ret = tb_tunnel_consumed_bandwidth(tunnel, &usb3_consumed_up,
&usb3_consumed_down);
if (ret)
@@ -387,7 +504,8 @@ static int tb_available_bandwidth(struct tb *tb, struct tb_port *src_port,
up_bw -= up_bw / 10;
down_bw = up_bw;
- tb_port_dbg(port, "link total bandwidth %d Mb/s\n", up_bw);
+ tb_port_dbg(port, "link total bandwidth %d/%d Mb/s\n", up_bw,
+ down_bw);
/*
* Find all DP tunnels that cross the port and reduce
@@ -396,12 +514,24 @@ static int tb_available_bandwidth(struct tb *tb, struct tb_port *src_port,
list_for_each_entry(tunnel, &tcm->tunnel_list, list) {
int dp_consumed_up, dp_consumed_down;
+ if (tb_tunnel_is_invalid(tunnel))
+ continue;
+
if (!tb_tunnel_is_dp(tunnel))
continue;
if (!tb_tunnel_port_on_path(tunnel, port))
continue;
+ /*
+ * Ignore the DP tunnel between src_port and
+ * dst_port because it is the same tunnel and we
+ * may be re-calculating estimated bandwidth.
+ */
+ if (tunnel->src_port == src_port &&
+ tunnel->dst_port == dst_port)
+ continue;
+
ret = tb_tunnel_consumed_bandwidth(tunnel,
&dp_consumed_up,
&dp_consumed_down);
@@ -762,6 +892,7 @@ static void tb_deactivate_and_free_tunnel(struct tb_tunnel *tunnel)
switch (tunnel->type) {
case TB_TUNNEL_DP:
+ tb_detach_bandwidth_group(src_port);
/*
* In case of DP tunnel make sure the DP IN resource is
* deallocated properly.
@@ -879,6 +1010,99 @@ out:
return tb_find_unused_port(sw, TB_TYPE_PCIE_DOWN);
}
+static void
+tb_recalc_estimated_bandwidth_for_group(struct tb_bandwidth_group *group)
+{
+ struct tb_tunnel *first_tunnel;
+ struct tb *tb = group->tb;
+ struct tb_port *in;
+ int ret;
+
+ tb_dbg(tb, "re-calculating bandwidth estimation for group %u\n",
+ group->index);
+
+ first_tunnel = NULL;
+ list_for_each_entry(in, &group->ports, group_list) {
+ int estimated_bw, estimated_up, estimated_down;
+ struct tb_tunnel *tunnel;
+ struct tb_port *out;
+
+ if (!usb4_dp_port_bw_mode_enabled(in))
+ continue;
+
+ tunnel = tb_find_tunnel(tb, TB_TUNNEL_DP, in, NULL);
+ if (WARN_ON(!tunnel))
+ break;
+
+ if (!first_tunnel) {
+ /*
+ * Since USB3 bandwidth is shared by all DP
+ * tunnels under the host router USB4 port, even
+ * if they do not begin from the host router, we
+ * can release USB3 bandwidth just once and not
+ * for each tunnel separately.
+ */
+ first_tunnel = tunnel;
+ ret = tb_release_unused_usb3_bandwidth(tb,
+ first_tunnel->src_port, first_tunnel->dst_port);
+ if (ret) {
+ tb_port_warn(in,
+ "failed to release unused bandwidth\n");
+ break;
+ }
+ }
+
+ out = tunnel->dst_port;
+ ret = tb_available_bandwidth(tb, in, out, &estimated_up,
+ &estimated_down);
+ if (ret) {
+ tb_port_warn(in,
+ "failed to re-calculate estimated bandwidth\n");
+ break;
+ }
+
+ /*
+ * Estimated bandwidth includes:
+ * - already allocated bandwidth for the DP tunnel
+ * - available bandwidth along the path
+ * - bandwidth allocated for USB 3.x but not used.
+ */
+ tb_port_dbg(in, "re-calculated estimated bandwidth %u/%u Mb/s\n",
+ estimated_up, estimated_down);
+
+ if (in->sw->config.depth < out->sw->config.depth)
+ estimated_bw = estimated_down;
+ else
+ estimated_bw = estimated_up;
+
+ if (usb4_dp_port_set_estimated_bw(in, estimated_bw))
+ tb_port_warn(in, "failed to update estimated bandwidth\n");
+ }
+
+ if (first_tunnel)
+ tb_reclaim_usb3_bandwidth(tb, first_tunnel->src_port,
+ first_tunnel->dst_port);
+
+ tb_dbg(tb, "bandwidth estimation for group %u done\n", group->index);
+}
+
+static void tb_recalc_estimated_bandwidth(struct tb *tb)
+{
+ struct tb_cm *tcm = tb_priv(tb);
+ int i;
+
+ tb_dbg(tb, "bandwidth consumption changed, re-calculating estimated bandwidth\n");
+
+ for (i = 0; i < ARRAY_SIZE(tcm->groups); i++) {
+ struct tb_bandwidth_group *group = &tcm->groups[i];
+
+ if (!list_empty(&group->ports))
+ tb_recalc_estimated_bandwidth_for_group(group);
+ }
+
+ tb_dbg(tb, "bandwidth re-calculation done\n");
+}
+
static struct tb_port *tb_find_dp_out(struct tb *tb, struct tb_port *in)
{
struct tb_port *host_port, *port;
@@ -892,7 +1116,7 @@ static struct tb_port *tb_find_dp_out(struct tb *tb, struct tb_port *in)
continue;
if (tb_port_is_enabled(port)) {
- tb_port_dbg(port, "in use\n");
+ tb_port_dbg(port, "DP OUT in use\n");
continue;
}
@@ -941,7 +1165,7 @@ static void tb_tunnel_dp(struct tb *tb)
continue;
if (tb_port_is_enabled(port)) {
- tb_port_dbg(port, "in use\n");
+ tb_port_dbg(port, "DP IN in use\n");
continue;
}
@@ -993,17 +1217,19 @@ static void tb_tunnel_dp(struct tb *tb)
goto err_rpm_put;
}
+ if (!tb_attach_bandwidth_group(tcm, in, out))
+ goto err_dealloc_dp;
+
/* Make all unused USB3 bandwidth available for the new DP tunnel */
ret = tb_release_unused_usb3_bandwidth(tb, in, out);
if (ret) {
tb_warn(tb, "failed to release unused bandwidth\n");
- goto err_dealloc_dp;
+ goto err_detach_group;
}
- ret = tb_available_bandwidth(tb, in, out, &available_up,
- &available_down);
+ ret = tb_available_bandwidth(tb, in, out, &available_up, &available_down);
if (ret)
- goto err_reclaim;
+ goto err_reclaim_usb;
tb_dbg(tb, "available bandwidth for new DP tunnel %u/%u Mb/s\n",
available_up, available_down);
@@ -1012,7 +1238,7 @@ static void tb_tunnel_dp(struct tb *tb)
available_down);
if (!tunnel) {
tb_port_dbg(out, "could not allocate DP tunnel\n");
- goto err_reclaim;
+ goto err_reclaim_usb;
}
if (tb_tunnel_activate(tunnel)) {
@@ -1022,6 +1248,10 @@ static void tb_tunnel_dp(struct tb *tb)
list_add_tail(&tunnel->list, &tcm->tunnel_list);
tb_reclaim_usb3_bandwidth(tb, in, out);
+
+ /* Update the domain with the new bandwidth estimation */
+ tb_recalc_estimated_bandwidth(tb);
+
/*
* In case of DP tunnel exists, change host router's 1st children
* TMU mode to HiFi for CL0s to work.
@@ -1032,8 +1262,10 @@ static void tb_tunnel_dp(struct tb *tb)
err_free:
tb_tunnel_free(tunnel);
-err_reclaim:
+err_reclaim_usb:
tb_reclaim_usb3_bandwidth(tb, in, out);
+err_detach_group:
+ tb_detach_bandwidth_group(in);
err_dealloc_dp:
tb_switch_dealloc_dp_resource(in->sw, in);
err_rpm_put:
@@ -1066,6 +1298,7 @@ static void tb_dp_resource_unavailable(struct tb *tb, struct tb_port *port)
* See if there is another DP OUT port that can be used for
* to create another tunnel.
*/
+ tb_recalc_estimated_bandwidth(tb);
tb_tunnel_dp(tb);
}
@@ -1313,6 +1546,7 @@ static void tb_handle_hotplug(struct work_struct *work)
if (port->dual_link_port)
port->dual_link_port->remote = NULL;
/* Maybe we can create another DP tunnel */
+ tb_recalc_estimated_bandwidth(tb);
tb_tunnel_dp(tb);
} else if (port->xdomain) {
struct tb_xdomain *xd = tb_xdomain_get(port->xdomain);
@@ -1370,6 +1604,239 @@ out:
kfree(ev);
}
+static int tb_alloc_dp_bandwidth(struct tb_tunnel *tunnel, int *requested_up,
+ int *requested_down)
+{
+ int allocated_up, allocated_down, available_up, available_down, ret;
+ int requested_up_corrected, requested_down_corrected, granularity;
+ int max_up, max_down, max_up_rounded, max_down_rounded;
+ struct tb *tb = tunnel->tb;
+ struct tb_port *in, *out;
+
+ ret = tb_tunnel_allocated_bandwidth(tunnel, &allocated_up, &allocated_down);
+ if (ret)
+ return ret;
+
+ in = tunnel->src_port;
+ out = tunnel->dst_port;
+
+ tb_port_dbg(in, "bandwidth allocated currently %d/%d Mb/s\n",
+ allocated_up, allocated_down);
+
+ /*
+ * If we get rounded up request from graphics side, say HBR2 x 4
+ * that is 17500 instead of 17280 (this is because of the
+ * granularity), we allow it too. Here the graphics has already
+ * negotiated with the DPRX the maximum possible rates (which is
+ * 17280 in this case).
+ *
+ * Since the link cannot go higher than 17280 we use that in our
+ * calculations but the DP IN adapter Allocated BW write must be
+ * the same value (17500) otherwise the adapter will mark it as
+ * failed for graphics.
+ */
+ ret = tb_tunnel_maximum_bandwidth(tunnel, &max_up, &max_down);
+ if (ret)
+ return ret;
+
+ ret = usb4_dp_port_granularity(in);
+ if (ret < 0)
+ return ret;
+ granularity = ret;
+
+ max_up_rounded = roundup(max_up, granularity);
+ max_down_rounded = roundup(max_down, granularity);
+
+ /*
+ * This will "fix" the request down to the maximum supported
+ * rate * lanes if it is at the maximum rounded up level.
+ */
+ requested_up_corrected = *requested_up;
+ if (requested_up_corrected == max_up_rounded)
+ requested_up_corrected = max_up;
+ else if (requested_up_corrected < 0)
+ requested_up_corrected = 0;
+ requested_down_corrected = *requested_down;
+ if (requested_down_corrected == max_down_rounded)
+ requested_down_corrected = max_down;
+ else if (requested_down_corrected < 0)
+ requested_down_corrected = 0;
+
+ tb_port_dbg(in, "corrected bandwidth request %d/%d Mb/s\n",
+ requested_up_corrected, requested_down_corrected);
+
+ if ((*requested_up >= 0 && requested_up_corrected > max_up_rounded) ||
+ (*requested_down >= 0 && requested_down_corrected > max_down_rounded)) {
+ tb_port_dbg(in, "bandwidth request too high (%d/%d Mb/s > %d/%d Mb/s)\n",
+ requested_up_corrected, requested_down_corrected,
+ max_up_rounded, max_down_rounded);
+ return -ENOBUFS;
+ }
+
+ if ((*requested_up >= 0 && requested_up_corrected <= allocated_up) ||
+ (*requested_down >= 0 && requested_down_corrected <= allocated_down)) {
+ /*
+ * If requested bandwidth is less or equal than what is
+ * currently allocated to that tunnel we simply change
+ * the reservation of the tunnel. Since all the tunnels
+ * going out from the same USB4 port are in the same
+ * group the released bandwidth will be taken into
+ * account for the other tunnels automatically below.
+ */
+ return tb_tunnel_alloc_bandwidth(tunnel, requested_up,
+ requested_down);
+ }
+
+ /*
+ * More bandwidth is requested. Release all the potential
+ * bandwidth from USB3 first.
+ */
+ ret = tb_release_unused_usb3_bandwidth(tb, in, out);
+ if (ret)
+ return ret;
+
+ /*
+ * Then go over all tunnels that cross the same USB4 ports (they
+ * are also in the same group but we use the same function here
+ * that we use with the normal bandwidth allocation).
+ */
+ ret = tb_available_bandwidth(tb, in, out, &available_up, &available_down);
+ if (ret)
+ goto reclaim;
+
+ tb_port_dbg(in, "bandwidth available for allocation %d/%d Mb/s\n",
+ available_up, available_down);
+
+ if ((*requested_up >= 0 && available_up >= requested_up_corrected) ||
+ (*requested_down >= 0 && available_down >= requested_down_corrected)) {
+ ret = tb_tunnel_alloc_bandwidth(tunnel, requested_up,
+ requested_down);
+ } else {
+ ret = -ENOBUFS;
+ }
+
+reclaim:
+ tb_reclaim_usb3_bandwidth(tb, in, out);
+ return ret;
+}
+
+static void tb_handle_dp_bandwidth_request(struct work_struct *work)
+{
+ struct tb_hotplug_event *ev = container_of(work, typeof(*ev), work);
+ int requested_bw, requested_up, requested_down, ret;
+ struct tb_port *in, *out;
+ struct tb_tunnel *tunnel;
+ struct tb *tb = ev->tb;
+ struct tb_cm *tcm = tb_priv(tb);
+ struct tb_switch *sw;
+
+ pm_runtime_get_sync(&tb->dev);
+
+ mutex_lock(&tb->lock);
+ if (!tcm->hotplug_active)
+ goto unlock;
+
+ sw = tb_switch_find_by_route(tb, ev->route);
+ if (!sw) {
+ tb_warn(tb, "bandwidth request from non-existent router %llx\n",
+ ev->route);
+ goto unlock;
+ }
+
+ in = &sw->ports[ev->port];
+ if (!tb_port_is_dpin(in)) {
+ tb_port_warn(in, "bandwidth request to non-DP IN adapter\n");
+ goto unlock;
+ }
+
+ tb_port_dbg(in, "handling bandwidth allocation request\n");
+
+ if (!usb4_dp_port_bw_mode_enabled(in)) {
+ tb_port_warn(in, "bandwidth allocation mode not enabled\n");
+ goto unlock;
+ }
+
+ ret = usb4_dp_port_requested_bw(in);
+ if (ret < 0) {
+ if (ret == -ENODATA)
+ tb_port_dbg(in, "no bandwidth request active\n");
+ else
+ tb_port_warn(in, "failed to read requested bandwidth\n");
+ goto unlock;
+ }
+ requested_bw = ret;
+
+ tb_port_dbg(in, "requested bandwidth %d Mb/s\n", requested_bw);
+
+ tunnel = tb_find_tunnel(tb, TB_TUNNEL_DP, in, NULL);
+ if (!tunnel) {
+ tb_port_warn(in, "failed to find tunnel\n");
+ goto unlock;
+ }
+
+ out = tunnel->dst_port;
+
+ if (in->sw->config.depth < out->sw->config.depth) {
+ requested_up = -1;
+ requested_down = requested_bw;
+ } else {
+ requested_up = requested_bw;
+ requested_down = -1;
+ }
+
+ ret = tb_alloc_dp_bandwidth(tunnel, &requested_up, &requested_down);
+ if (ret) {
+ if (ret == -ENOBUFS)
+ tb_port_warn(in, "not enough bandwidth available\n");
+ else
+ tb_port_warn(in, "failed to change bandwidth allocation\n");
+ } else {
+ tb_port_dbg(in, "bandwidth allocation changed to %d/%d Mb/s\n",
+ requested_up, requested_down);
+
+ /* Update other clients about the allocation change */
+ tb_recalc_estimated_bandwidth(tb);
+ }
+
+unlock:
+ mutex_unlock(&tb->lock);
+
+ pm_runtime_mark_last_busy(&tb->dev);
+ pm_runtime_put_autosuspend(&tb->dev);
+}
+
+static void tb_queue_dp_bandwidth_request(struct tb *tb, u64 route, u8 port)
+{
+ struct tb_hotplug_event *ev;
+
+ ev = kmalloc(sizeof(*ev), GFP_KERNEL);
+ if (!ev)
+ return;
+
+ ev->tb = tb;
+ ev->route = route;
+ ev->port = port;
+ INIT_WORK(&ev->work, tb_handle_dp_bandwidth_request);
+ queue_work(tb->wq, &ev->work);
+}
+
+static void tb_handle_notification(struct tb *tb, u64 route,
+ const struct cfg_error_pkg *error)
+{
+ if (tb_cfg_ack_notification(tb->ctl, route, error))
+ tb_warn(tb, "could not ack notification on %llx\n", route);
+
+ switch (error->error) {
+ case TB_CFG_ERROR_DP_BW:
+ tb_queue_dp_bandwidth_request(tb, route, error->port);
+ break;
+
+ default:
+ /* Ack is enough */
+ return;
+ }
+}
+
/*
* tb_schedule_hotplug_handler() - callback function for the control channel
*
@@ -1379,15 +1846,19 @@ static void tb_handle_event(struct tb *tb, enum tb_cfg_pkg_type type,
const void *buf, size_t size)
{
const struct cfg_event_pkg *pkg = buf;
- u64 route;
+ u64 route = tb_cfg_get_route(&pkg->header);
- if (type != TB_CFG_PKG_EVENT) {
+ switch (type) {
+ case TB_CFG_PKG_ERROR:
+ tb_handle_notification(tb, route, (const struct cfg_error_pkg *)buf);
+ return;
+ case TB_CFG_PKG_EVENT:
+ break;
+ default:
tb_warn(tb, "unexpected event %#x, ignoring\n", type);
return;
}
- route = tb_cfg_get_route(&pkg->header);
-
if (tb_cfg_ack_plug(tb->ctl, route, pkg->port, pkg->unplug)) {
tb_warn(tb, "could not ack plug event on %llx:%x\n", route,
pkg->port);
@@ -1817,6 +2288,7 @@ struct tb *tb_probe(struct tb_nhi *nhi)
INIT_LIST_HEAD(&tcm->tunnel_list);
INIT_LIST_HEAD(&tcm->dp_resources);
INIT_DELAYED_WORK(&tcm->remove_work, tb_remove_work);
+ tb_init_bandwidth_groups(tcm);
tb_dbg(tb, "using software connection manager\n");
diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h
index f9786976f5ec..cbb20a277346 100644
--- a/drivers/thunderbolt/tb.h
+++ b/drivers/thunderbolt/tb.h
@@ -224,6 +224,23 @@ struct tb_switch {
};
/**
+ * struct tb_bandwidth_group - Bandwidth management group
+ * @tb: Pointer to the domain the group belongs to
+ * @index: Index of the group (aka Group_ID). Valid values %1-%7
+ * @ports: DP IN adapters belonging to this group are linked here
+ *
+ * Any tunnel that requires isochronous bandwidth (that's DP for now) is
+ * attached to a bandwidth group. All tunnels going through the same
+ * USB4 links share the same group and can dynamically distribute the
+ * bandwidth within the group.
+ */
+struct tb_bandwidth_group {
+ struct tb *tb;
+ int index;
+ struct list_head ports;
+};
+
+/**
* struct tb_port - a thunderbolt port, part of a tb_switch
* @config: Cached port configuration read from registers
* @sw: Switch the port belongs to
@@ -247,6 +264,9 @@ struct tb_switch {
* @ctl_credits: Buffers reserved for control path
* @dma_credits: Number of credits allocated for DMA tunneling for all
* DMA paths through this port.
+ * @group: Bandwidth allocation group the adapter is assigned to. Only
+ * used for DP IN adapters for now.
+ * @group_list: The adapter is linked to the group's list of ports through this
*
* In USB4 terminology this structure represents an adapter (protocol or
* lane adapter).
@@ -272,6 +292,8 @@ struct tb_port {
unsigned int total_credits;
unsigned int ctl_credits;
unsigned int dma_credits;
+ struct tb_bandwidth_group *group;
+ struct list_head group_list;
};
/**
@@ -815,7 +837,7 @@ static inline bool tb_is_switch(const struct device *dev)
return dev->type == &tb_switch_type;
}
-static inline struct tb_switch *tb_to_switch(struct device *dev)
+static inline struct tb_switch *tb_to_switch(const struct device *dev)
{
if (tb_is_switch(dev))
return container_of(dev, struct tb_switch, dev);
@@ -1047,7 +1069,7 @@ void tb_port_lane_bonding_disable(struct tb_port *port);
int tb_port_wait_for_link_width(struct tb_port *port, int width,
int timeout_msec);
int tb_port_update_credits(struct tb_port *port);
-bool tb_port_is_clx_enabled(struct tb_port *port, enum tb_clx clx);
+bool tb_port_is_clx_enabled(struct tb_port *port, unsigned int clx);
int tb_switch_find_vse_cap(struct tb_switch *sw, enum tb_switch_vse_cap vsec);
int tb_switch_find_cap(struct tb_switch *sw, enum tb_switch_cap cap);
@@ -1238,6 +1260,21 @@ int usb4_usb3_port_allocate_bandwidth(struct tb_port *port, int *upstream_bw,
int usb4_usb3_port_release_bandwidth(struct tb_port *port, int *upstream_bw,
int *downstream_bw);
+int usb4_dp_port_set_cm_id(struct tb_port *port, int cm_id);
+bool usb4_dp_port_bw_mode_supported(struct tb_port *port);
+bool usb4_dp_port_bw_mode_enabled(struct tb_port *port);
+int usb4_dp_port_set_cm_bw_mode_supported(struct tb_port *port, bool supported);
+int usb4_dp_port_group_id(struct tb_port *port);
+int usb4_dp_port_set_group_id(struct tb_port *port, int group_id);
+int usb4_dp_port_nrd(struct tb_port *port, int *rate, int *lanes);
+int usb4_dp_port_set_nrd(struct tb_port *port, int rate, int lanes);
+int usb4_dp_port_granularity(struct tb_port *port);
+int usb4_dp_port_set_granularity(struct tb_port *port, int granularity);
+int usb4_dp_port_set_estimated_bw(struct tb_port *port, int bw);
+int usb4_dp_port_allocated_bw(struct tb_port *port);
+int usb4_dp_port_allocate_bw(struct tb_port *port, int bw);
+int usb4_dp_port_requested_bw(struct tb_port *port);
+
static inline bool tb_is_usb4_port_device(const struct device *dev)
{
return dev->type == &usb4_port_device_type;
diff --git a/drivers/thunderbolt/tb_msgs.h b/drivers/thunderbolt/tb_msgs.h
index 33c4c7aed56d..3234bff07899 100644
--- a/drivers/thunderbolt/tb_msgs.h
+++ b/drivers/thunderbolt/tb_msgs.h
@@ -29,6 +29,7 @@ enum tb_cfg_error {
TB_CFG_ERROR_HEC_ERROR_DETECTED = 12,
TB_CFG_ERROR_FLOW_CONTROL_ERROR = 13,
TB_CFG_ERROR_LOCK = 15,
+ TB_CFG_ERROR_DP_BW = 32,
};
/* common header */
@@ -64,14 +65,16 @@ struct cfg_write_pkg {
/* TB_CFG_PKG_ERROR */
struct cfg_error_pkg {
struct tb_cfg_header header;
- enum tb_cfg_error error:4;
- u32 zero1:4;
+ enum tb_cfg_error error:8;
u32 port:6;
- u32 zero2:2; /* Both should be zero, still they are different fields. */
- u32 zero3:14;
+ u32 reserved:16;
u32 pg:2;
} __packed;
+struct cfg_ack_pkg {
+ struct tb_cfg_header header;
+};
+
#define TB_CFG_ERROR_PG_HOT_PLUG 0x2
#define TB_CFG_ERROR_PG_HOT_UNPLUG 0x3
diff --git a/drivers/thunderbolt/tb_regs.h b/drivers/thunderbolt/tb_regs.h
index 3c38b0cb8f74..2636423748cd 100644
--- a/drivers/thunderbolt/tb_regs.h
+++ b/drivers/thunderbolt/tb_regs.h
@@ -50,6 +50,10 @@ enum tb_port_state {
TB_PORT_DISABLED = 0, /* tb_cap_phy.disable == 1 */
TB_PORT_CONNECTING = 1, /* retry */
TB_PORT_UP = 2,
+ TB_PORT_TX_CL0S = 3,
+ TB_PORT_RX_CL0S = 4,
+ TB_PORT_CL1 = 5,
+ TB_PORT_CL2 = 6,
TB_PORT_UNPLUGGED = 7,
};
@@ -381,15 +385,42 @@ struct tb_regs_port_header {
#define ADP_DP_CS_1_AUX_RX_HOPID_MASK GENMASK(21, 11)
#define ADP_DP_CS_1_AUX_RX_HOPID_SHIFT 11
#define ADP_DP_CS_2 0x02
+#define ADP_DP_CS_2_NRD_MLC_MASK GENMASK(2, 0)
#define ADP_DP_CS_2_HDP BIT(6)
+#define ADP_DP_CS_2_NRD_MLR_MASK GENMASK(9, 7)
+#define ADP_DP_CS_2_NRD_MLR_SHIFT 7
+#define ADP_DP_CS_2_CA BIT(10)
+#define ADP_DP_CS_2_GR_MASK GENMASK(12, 11)
+#define ADP_DP_CS_2_GR_SHIFT 11
+#define ADP_DP_CS_2_GR_0_25G 0x0
+#define ADP_DP_CS_2_GR_0_5G 0x1
+#define ADP_DP_CS_2_GR_1G 0x2
+#define ADP_DP_CS_2_GROUP_ID_MASK GENMASK(15, 13)
+#define ADP_DP_CS_2_GROUP_ID_SHIFT 13
+#define ADP_DP_CS_2_CM_ID_MASK GENMASK(19, 16)
+#define ADP_DP_CS_2_CM_ID_SHIFT 16
+#define ADP_DP_CS_2_CMMS BIT(20)
+#define ADP_DP_CS_2_ESTIMATED_BW_MASK GENMASK(31, 24)
+#define ADP_DP_CS_2_ESTIMATED_BW_SHIFT 24
#define ADP_DP_CS_3 0x03
#define ADP_DP_CS_3_HDPC BIT(9)
#define DP_LOCAL_CAP 0x04
#define DP_REMOTE_CAP 0x05
+/* For DP IN adapter */
+#define DP_STATUS 0x06
+#define DP_STATUS_ALLOCATED_BW_MASK GENMASK(31, 24)
+#define DP_STATUS_ALLOCATED_BW_SHIFT 24
+/* For DP OUT adapter */
#define DP_STATUS_CTRL 0x06
#define DP_STATUS_CTRL_CMHS BIT(25)
#define DP_STATUS_CTRL_UF BIT(26)
#define DP_COMMON_CAP 0x07
+/* Only if DP IN supports BW allocation mode */
+#define ADP_DP_CS_8 0x08
+#define ADP_DP_CS_8_REQUESTED_BW_MASK GENMASK(7, 0)
+#define ADP_DP_CS_8_DPME BIT(30)
+#define ADP_DP_CS_8_DR BIT(31)
+
/*
* DP_COMMON_CAP offsets work also for DP_LOCAL_CAP and DP_REMOTE_CAP
* with exception of DPRX done.
@@ -406,7 +437,12 @@ struct tb_regs_port_header {
#define DP_COMMON_CAP_2_LANES 0x1
#define DP_COMMON_CAP_4_LANES 0x2
#define DP_COMMON_CAP_LTTPR_NS BIT(27)
+#define DP_COMMON_CAP_BW_MODE BIT(28)
#define DP_COMMON_CAP_DPRX_DONE BIT(31)
+/* Only present if DP IN supports BW allocation mode */
+#define ADP_DP_CS_8 0x08
+#define ADP_DP_CS_8_DPME BIT(30)
+#define ADP_DP_CS_8_DR BIT(31)
/* PCIe adapter registers */
#define ADP_PCIE_CS_0 0x00
diff --git a/drivers/thunderbolt/tunnel.c b/drivers/thunderbolt/tunnel.c
index 1fc3c29b24f8..9099ae73e78f 100644
--- a/drivers/thunderbolt/tunnel.c
+++ b/drivers/thunderbolt/tunnel.c
@@ -9,6 +9,7 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/list.h>
+#include <linux/ktime.h>
#include "tunnel.h"
#include "tb.h"
@@ -44,12 +45,17 @@
/* Minimum number of credits for DMA path */
#define TB_MIN_DMA_CREDITS 1U
+static bool bw_alloc_mode = true;
+module_param(bw_alloc_mode, bool, 0444);
+MODULE_PARM_DESC(bw_alloc_mode,
+ "enable bandwidth allocation mode if supported (default: true)");
+
static const char * const tb_tunnel_names[] = { "PCI", "DP", "DMA", "USB3" };
#define __TB_TUNNEL_PRINT(level, tunnel, fmt, arg...) \
do { \
struct tb_tunnel *__tunnel = (tunnel); \
- level(__tunnel->tb, "%llx:%x <-> %llx:%x (%s): " fmt, \
+ level(__tunnel->tb, "%llx:%u <-> %llx:%u (%s): " fmt, \
tb_route(__tunnel->src_port->sw), \
__tunnel->src_port->port, \
tb_route(__tunnel->dst_port->sw), \
@@ -339,9 +345,10 @@ static bool tb_dp_is_usb4(const struct tb_switch *sw)
return tb_switch_is_usb4(sw) || tb_switch_is_titan_ridge(sw);
}
-static int tb_dp_cm_handshake(struct tb_port *in, struct tb_port *out)
+static int tb_dp_cm_handshake(struct tb_port *in, struct tb_port *out,
+ int timeout_msec)
{
- int timeout = 10;
+ ktime_t timeout = ktime_add_ms(ktime_get(), timeout_msec);
u32 val;
int ret;
@@ -368,8 +375,8 @@ static int tb_dp_cm_handshake(struct tb_port *in, struct tb_port *out)
return ret;
if (!(val & DP_STATUS_CTRL_CMHS))
return 0;
- usleep_range(10, 100);
- } while (timeout--);
+ usleep_range(100, 150);
+ } while (ktime_before(ktime_get(), timeout));
return -ETIMEDOUT;
}
@@ -519,7 +526,7 @@ static int tb_dp_xchg_caps(struct tb_tunnel *tunnel)
* Perform connection manager handshake between IN and OUT ports
* before capabilities exchange can take place.
*/
- ret = tb_dp_cm_handshake(in, out);
+ ret = tb_dp_cm_handshake(in, out, 1500);
if (ret)
return ret;
@@ -597,6 +604,133 @@ static int tb_dp_xchg_caps(struct tb_tunnel *tunnel)
in->cap_adap + DP_REMOTE_CAP, 1);
}
+static int tb_dp_bw_alloc_mode_enable(struct tb_tunnel *tunnel)
+{
+ int ret, estimated_bw, granularity, tmp;
+ struct tb_port *out = tunnel->dst_port;
+ struct tb_port *in = tunnel->src_port;
+ u32 out_dp_cap, out_rate, out_lanes;
+ u32 in_dp_cap, in_rate, in_lanes;
+ u32 rate, lanes;
+
+ if (!bw_alloc_mode)
+ return 0;
+
+ ret = usb4_dp_port_set_cm_bw_mode_supported(in, true);
+ if (ret)
+ return ret;
+
+ ret = usb4_dp_port_set_group_id(in, in->group->index);
+ if (ret)
+ return ret;
+
+ /*
+ * Get the non-reduced rate and lanes based on the lowest
+ * capability of both adapters.
+ */
+ ret = tb_port_read(in, &in_dp_cap, TB_CFG_PORT,
+ in->cap_adap + DP_LOCAL_CAP, 1);
+ if (ret)
+ return ret;
+
+ ret = tb_port_read(out, &out_dp_cap, TB_CFG_PORT,
+ out->cap_adap + DP_LOCAL_CAP, 1);
+ if (ret)
+ return ret;
+
+ in_rate = tb_dp_cap_get_rate(in_dp_cap);
+ in_lanes = tb_dp_cap_get_lanes(in_dp_cap);
+ out_rate = tb_dp_cap_get_rate(out_dp_cap);
+ out_lanes = tb_dp_cap_get_lanes(out_dp_cap);
+
+ rate = min(in_rate, out_rate);
+ lanes = min(in_lanes, out_lanes);
+ tmp = tb_dp_bandwidth(rate, lanes);
+
+ tb_port_dbg(in, "non-reduced bandwidth %u Mb/s x%u = %u Mb/s\n", rate,
+ lanes, tmp);
+
+ ret = usb4_dp_port_set_nrd(in, rate, lanes);
+ if (ret)
+ return ret;
+
+ for (granularity = 250; tmp / granularity > 255 && granularity <= 1000;
+ granularity *= 2)
+ ;
+
+ tb_port_dbg(in, "granularity %d Mb/s\n", granularity);
+
+ /*
+ * Returns -EINVAL if granularity above is outside of the
+ * accepted ranges.
+ */
+ ret = usb4_dp_port_set_granularity(in, granularity);
+ if (ret)
+ return ret;
+
+ /*
+ * Bandwidth estimation is pretty much what we have in
+ * max_up/down fields. For discovery we just read what the
+ * estimation was set to.
+ */
+ if (in->sw->config.depth < out->sw->config.depth)
+ estimated_bw = tunnel->max_down;
+ else
+ estimated_bw = tunnel->max_up;
+
+ tb_port_dbg(in, "estimated bandwidth %d Mb/s\n", estimated_bw);
+
+ ret = usb4_dp_port_set_estimated_bw(in, estimated_bw);
+ if (ret)
+ return ret;
+
+ /* Initial allocation should be 0 according the spec */
+ ret = usb4_dp_port_allocate_bw(in, 0);
+ if (ret)
+ return ret;
+
+ tb_port_dbg(in, "bandwidth allocation mode enabled\n");
+ return 0;
+}
+
+static int tb_dp_init(struct tb_tunnel *tunnel)
+{
+ struct tb_port *in = tunnel->src_port;
+ struct tb_switch *sw = in->sw;
+ struct tb *tb = in->sw->tb;
+ int ret;
+
+ ret = tb_dp_xchg_caps(tunnel);
+ if (ret)
+ return ret;
+
+ if (!tb_switch_is_usb4(sw))
+ return 0;
+
+ if (!usb4_dp_port_bw_mode_supported(in))
+ return 0;
+
+ tb_port_dbg(in, "bandwidth allocation mode supported\n");
+
+ ret = usb4_dp_port_set_cm_id(in, tb->index);
+ if (ret)
+ return ret;
+
+ return tb_dp_bw_alloc_mode_enable(tunnel);
+}
+
+static void tb_dp_deinit(struct tb_tunnel *tunnel)
+{
+ struct tb_port *in = tunnel->src_port;
+
+ if (!usb4_dp_port_bw_mode_supported(in))
+ return;
+ if (usb4_dp_port_bw_mode_enabled(in)) {
+ usb4_dp_port_set_cm_bw_mode_supported(in, false);
+ tb_port_dbg(in, "bandwidth allocation mode disabled\n");
+ }
+}
+
static int tb_dp_activate(struct tb_tunnel *tunnel, bool active)
{
int ret;
@@ -634,49 +768,275 @@ static int tb_dp_activate(struct tb_tunnel *tunnel, bool active)
return 0;
}
+/* max_bw is rounded up to next granularity */
+static int tb_dp_nrd_bandwidth(struct tb_tunnel *tunnel, int *max_bw)
+{
+ struct tb_port *in = tunnel->src_port;
+ int ret, rate, lanes, nrd_bw;
+
+ ret = usb4_dp_port_nrd(in, &rate, &lanes);
+ if (ret)
+ return ret;
+
+ nrd_bw = tb_dp_bandwidth(rate, lanes);
+
+ if (max_bw) {
+ ret = usb4_dp_port_granularity(in);
+ if (ret < 0)
+ return ret;
+ *max_bw = roundup(nrd_bw, ret);
+ }
+
+ return nrd_bw;
+}
+
+static int tb_dp_bw_mode_consumed_bandwidth(struct tb_tunnel *tunnel,
+ int *consumed_up, int *consumed_down)
+{
+ struct tb_port *out = tunnel->dst_port;
+ struct tb_port *in = tunnel->src_port;
+ int ret, allocated_bw, max_bw;
+
+ if (!usb4_dp_port_bw_mode_enabled(in))
+ return -EOPNOTSUPP;
+
+ if (!tunnel->bw_mode)
+ return -EOPNOTSUPP;
+
+ /* Read what was allocated previously if any */
+ ret = usb4_dp_port_allocated_bw(in);
+ if (ret < 0)
+ return ret;
+ allocated_bw = ret;
+
+ ret = tb_dp_nrd_bandwidth(tunnel, &max_bw);
+ if (ret < 0)
+ return ret;
+ if (allocated_bw == max_bw)
+ allocated_bw = ret;
+
+ tb_port_dbg(in, "consumed bandwidth through allocation mode %d Mb/s\n",
+ allocated_bw);
+
+ if (in->sw->config.depth < out->sw->config.depth) {
+ *consumed_up = 0;
+ *consumed_down = allocated_bw;
+ } else {
+ *consumed_up = allocated_bw;
+ *consumed_down = 0;
+ }
+
+ return 0;
+}
+
+static int tb_dp_allocated_bandwidth(struct tb_tunnel *tunnel, int *allocated_up,
+ int *allocated_down)
+{
+ struct tb_port *out = tunnel->dst_port;
+ struct tb_port *in = tunnel->src_port;
+
+ /*
+ * If we have already set the allocated bandwidth then use that.
+ * Otherwise we read it from the DPRX.
+ */
+ if (usb4_dp_port_bw_mode_enabled(in) && tunnel->bw_mode) {
+ int ret, allocated_bw, max_bw;
+
+ ret = usb4_dp_port_allocated_bw(in);
+ if (ret < 0)
+ return ret;
+ allocated_bw = ret;
+
+ ret = tb_dp_nrd_bandwidth(tunnel, &max_bw);
+ if (ret < 0)
+ return ret;
+ if (allocated_bw == max_bw)
+ allocated_bw = ret;
+
+ if (in->sw->config.depth < out->sw->config.depth) {
+ *allocated_up = 0;
+ *allocated_down = allocated_bw;
+ } else {
+ *allocated_up = allocated_bw;
+ *allocated_down = 0;
+ }
+ return 0;
+ }
+
+ return tunnel->consumed_bandwidth(tunnel, allocated_up,
+ allocated_down);
+}
+
+static int tb_dp_alloc_bandwidth(struct tb_tunnel *tunnel, int *alloc_up,
+ int *alloc_down)
+{
+ struct tb_port *out = tunnel->dst_port;
+ struct tb_port *in = tunnel->src_port;
+ int max_bw, ret, tmp;
+
+ if (!usb4_dp_port_bw_mode_enabled(in))
+ return -EOPNOTSUPP;
+
+ ret = tb_dp_nrd_bandwidth(tunnel, &max_bw);
+ if (ret < 0)
+ return ret;
+
+ if (in->sw->config.depth < out->sw->config.depth) {
+ tmp = min(*alloc_down, max_bw);
+ ret = usb4_dp_port_allocate_bw(in, tmp);
+ if (ret)
+ return ret;
+ *alloc_down = tmp;
+ *alloc_up = 0;
+ } else {
+ tmp = min(*alloc_up, max_bw);
+ ret = usb4_dp_port_allocate_bw(in, tmp);
+ if (ret)
+ return ret;
+ *alloc_down = 0;
+ *alloc_up = tmp;
+ }
+
+ /* Now we can use BW mode registers to figure out the bandwidth */
+ /* TODO: need to handle discovery too */
+ tunnel->bw_mode = true;
+ return 0;
+}
+
+static int tb_dp_read_dprx(struct tb_tunnel *tunnel, u32 *rate, u32 *lanes,
+ int timeout_msec)
+{
+ ktime_t timeout = ktime_add_ms(ktime_get(), timeout_msec);
+ struct tb_port *in = tunnel->src_port;
+
+ /*
+ * Wait for DPRX done. Normally it should be already set for
+ * active tunnel.
+ */
+ do {
+ u32 val;
+ int ret;
+
+ ret = tb_port_read(in, &val, TB_CFG_PORT,
+ in->cap_adap + DP_COMMON_CAP, 1);
+ if (ret)
+ return ret;
+
+ if (val & DP_COMMON_CAP_DPRX_DONE) {
+ *rate = tb_dp_cap_get_rate(val);
+ *lanes = tb_dp_cap_get_lanes(val);
+
+ tb_port_dbg(in, "consumed bandwidth through DPRX %d Mb/s\n",
+ tb_dp_bandwidth(*rate, *lanes));
+ return 0;
+ }
+ usleep_range(100, 150);
+ } while (ktime_before(ktime_get(), timeout));
+
+ return -ETIMEDOUT;
+}
+
+/* Read cap from tunnel DP IN */
+static int tb_dp_read_cap(struct tb_tunnel *tunnel, unsigned int cap, u32 *rate,
+ u32 *lanes)
+{
+ struct tb_port *in = tunnel->src_port;
+ u32 val;
+ int ret;
+
+ switch (cap) {
+ case DP_LOCAL_CAP:
+ case DP_REMOTE_CAP:
+ break;
+
+ default:
+ tb_tunnel_WARN(tunnel, "invalid capability index %#x\n", cap);
+ return -EINVAL;
+ }
+
+ /*
+ * Read from the copied remote cap so that we take into account
+ * if capabilities were reduced during exchange.
+ */
+ ret = tb_port_read(in, &val, TB_CFG_PORT, in->cap_adap + cap, 1);
+ if (ret)
+ return ret;
+
+ *rate = tb_dp_cap_get_rate(val);
+ *lanes = tb_dp_cap_get_lanes(val);
+
+ tb_port_dbg(in, "bandwidth from %#x capability %d Mb/s\n", cap,
+ tb_dp_bandwidth(*rate, *lanes));
+ return 0;
+}
+
+static int tb_dp_maximum_bandwidth(struct tb_tunnel *tunnel, int *max_up,
+ int *max_down)
+{
+ struct tb_port *in = tunnel->src_port;
+ u32 rate, lanes;
+ int ret;
+
+ /*
+ * DP IN adapter DP_LOCAL_CAP gets updated to the lowest AUX read
+ * parameter values so this so we can use this to determine the
+ * maximum possible bandwidth over this link.
+ */
+ ret = tb_dp_read_cap(tunnel, DP_LOCAL_CAP, &rate, &lanes);
+ if (ret)
+ return ret;
+
+ if (in->sw->config.depth < tunnel->dst_port->sw->config.depth) {
+ *max_up = 0;
+ *max_down = tb_dp_bandwidth(rate, lanes);
+ } else {
+ *max_up = tb_dp_bandwidth(rate, lanes);
+ *max_down = 0;
+ }
+
+ return 0;
+}
+
static int tb_dp_consumed_bandwidth(struct tb_tunnel *tunnel, int *consumed_up,
int *consumed_down)
{
struct tb_port *in = tunnel->src_port;
const struct tb_switch *sw = in->sw;
- u32 val, rate = 0, lanes = 0;
+ u32 rate = 0, lanes = 0;
int ret;
if (tb_dp_is_usb4(sw)) {
- int timeout = 20;
-
/*
- * Wait for DPRX done. Normally it should be already set
- * for active tunnel.
+ * On USB4 routers check if the bandwidth allocation
+ * mode is enabled first and then read the bandwidth
+ * through those registers.
*/
- do {
- ret = tb_port_read(in, &val, TB_CFG_PORT,
- in->cap_adap + DP_COMMON_CAP, 1);
- if (ret)
+ ret = tb_dp_bw_mode_consumed_bandwidth(tunnel, consumed_up,
+ consumed_down);
+ if (ret < 0) {
+ if (ret != -EOPNOTSUPP)
return ret;
-
- if (val & DP_COMMON_CAP_DPRX_DONE) {
- rate = tb_dp_cap_get_rate(val);
- lanes = tb_dp_cap_get_lanes(val);
- break;
- }
- msleep(250);
- } while (timeout--);
-
- if (!timeout)
- return -ETIMEDOUT;
- } else if (sw->generation >= 2) {
+ } else if (!ret) {
+ return 0;
+ }
/*
- * Read from the copied remote cap so that we take into
- * account if capabilities were reduced during exchange.
+ * Then see if the DPRX negotiation is ready and if yes
+ * return that bandwidth (it may be smaller than the
+ * reduced one). Otherwise return the remote (possibly
+ * reduced) caps.
*/
- ret = tb_port_read(in, &val, TB_CFG_PORT,
- in->cap_adap + DP_REMOTE_CAP, 1);
+ ret = tb_dp_read_dprx(tunnel, &rate, &lanes, 150);
+ if (ret) {
+ if (ret == -ETIMEDOUT)
+ ret = tb_dp_read_cap(tunnel, DP_REMOTE_CAP,
+ &rate, &lanes);
+ if (ret)
+ return ret;
+ }
+ } else if (sw->generation >= 2) {
+ ret = tb_dp_read_cap(tunnel, DP_REMOTE_CAP, &rate, &lanes);
if (ret)
return ret;
-
- rate = tb_dp_cap_get_rate(val);
- lanes = tb_dp_cap_get_lanes(val);
} else {
/* No bandwidth management for legacy devices */
*consumed_up = 0;
@@ -798,8 +1158,12 @@ struct tb_tunnel *tb_tunnel_discover_dp(struct tb *tb, struct tb_port *in,
if (!tunnel)
return NULL;
- tunnel->init = tb_dp_xchg_caps;
+ tunnel->init = tb_dp_init;
+ tunnel->deinit = tb_dp_deinit;
tunnel->activate = tb_dp_activate;
+ tunnel->maximum_bandwidth = tb_dp_maximum_bandwidth;
+ tunnel->allocated_bandwidth = tb_dp_allocated_bandwidth;
+ tunnel->alloc_bandwidth = tb_dp_alloc_bandwidth;
tunnel->consumed_bandwidth = tb_dp_consumed_bandwidth;
tunnel->src_port = in;
@@ -887,8 +1251,12 @@ struct tb_tunnel *tb_tunnel_alloc_dp(struct tb *tb, struct tb_port *in,
if (!tunnel)
return NULL;
- tunnel->init = tb_dp_xchg_caps;
+ tunnel->init = tb_dp_init;
+ tunnel->deinit = tb_dp_deinit;
tunnel->activate = tb_dp_activate;
+ tunnel->maximum_bandwidth = tb_dp_maximum_bandwidth;
+ tunnel->allocated_bandwidth = tb_dp_allocated_bandwidth;
+ tunnel->alloc_bandwidth = tb_dp_alloc_bandwidth;
tunnel->consumed_bandwidth = tb_dp_consumed_bandwidth;
tunnel->src_port = in;
tunnel->dst_port = out;
@@ -1714,6 +2082,72 @@ static bool tb_tunnel_is_active(const struct tb_tunnel *tunnel)
}
/**
+ * tb_tunnel_maximum_bandwidth() - Return maximum possible bandwidth
+ * @tunnel: Tunnel to check
+ * @max_up: Maximum upstream bandwidth in Mb/s
+ * @max_down: Maximum downstream bandwidth in Mb/s
+ *
+ * Returns maximum possible bandwidth this tunnel can go if not limited
+ * by other bandwidth clients. If the tunnel does not support this
+ * returns %-EOPNOTSUPP.
+ */
+int tb_tunnel_maximum_bandwidth(struct tb_tunnel *tunnel, int *max_up,
+ int *max_down)
+{
+ if (!tb_tunnel_is_active(tunnel))
+ return -EINVAL;
+
+ if (tunnel->maximum_bandwidth)
+ return tunnel->maximum_bandwidth(tunnel, max_up, max_down);
+ return -EOPNOTSUPP;
+}
+
+/**
+ * tb_tunnel_allocated_bandwidth() - Return bandwidth allocated for the tunnel
+ * @tunnel: Tunnel to check
+ * @allocated_up: Currently allocated upstream bandwidth in Mb/s is stored here
+ * @allocated_down: Currently allocated downstream bandwidth in Mb/s is
+ * stored here
+ *
+ * Returns the bandwidth allocated for the tunnel. This may be higher
+ * than what the tunnel actually consumes.
+ */
+int tb_tunnel_allocated_bandwidth(struct tb_tunnel *tunnel, int *allocated_up,
+ int *allocated_down)
+{
+ if (!tb_tunnel_is_active(tunnel))
+ return -EINVAL;
+
+ if (tunnel->allocated_bandwidth)
+ return tunnel->allocated_bandwidth(tunnel, allocated_up,
+ allocated_down);
+ return -EOPNOTSUPP;
+}
+
+/**
+ * tb_tunnel_alloc_bandwidth() - Change tunnel bandwidth allocation
+ * @tunnel: Tunnel whose bandwidth allocation to change
+ * @alloc_up: New upstream bandwidth in Mb/s
+ * @alloc_down: New downstream bandwidth in Mb/s
+ *
+ * Tries to change tunnel bandwidth allocation. If succeeds returns %0
+ * and updates @alloc_up and @alloc_down to that was actually allocated
+ * (it may not be the same as passed originally). Returns negative errno
+ * in case of failure.
+ */
+int tb_tunnel_alloc_bandwidth(struct tb_tunnel *tunnel, int *alloc_up,
+ int *alloc_down)
+{
+ if (!tb_tunnel_is_active(tunnel))
+ return -EINVAL;
+
+ if (tunnel->alloc_bandwidth)
+ return tunnel->alloc_bandwidth(tunnel, alloc_up, alloc_down);
+
+ return -EOPNOTSUPP;
+}
+
+/**
* tb_tunnel_consumed_bandwidth() - Return bandwidth consumed by the tunnel
* @tunnel: Tunnel to check
* @consumed_up: Consumed bandwidth in Mb/s from @dst_port to @src_port.
diff --git a/drivers/thunderbolt/tunnel.h b/drivers/thunderbolt/tunnel.h
index bb4d1f1d6d0b..bf690f7beeee 100644
--- a/drivers/thunderbolt/tunnel.h
+++ b/drivers/thunderbolt/tunnel.h
@@ -29,6 +29,9 @@ enum tb_tunnel_type {
* @init: Optional tunnel specific initialization
* @deinit: Optional tunnel specific de-initialization
* @activate: Optional tunnel specific activation/deactivation
+ * @maximum_bandwidth: Returns maximum possible bandwidth for this tunnel
+ * @allocated_bandwidth: Return how much bandwidth is allocated for the tunnel
+ * @alloc_bandwidth: Change tunnel bandwidth allocation
* @consumed_bandwidth: Return how much bandwidth the tunnel consumes
* @release_unused_bandwidth: Release all unused bandwidth
* @reclaim_available_bandwidth: Reclaim back available bandwidth
@@ -40,6 +43,8 @@ enum tb_tunnel_type {
* Only set if the bandwidth needs to be limited.
* @allocated_up: Allocated upstream bandwidth (only for USB3)
* @allocated_down: Allocated downstream bandwidth (only for USB3)
+ * @bw_mode: DP bandwidth allocation mode registers can be used to
+ * determine consumed and allocated bandwidth
*/
struct tb_tunnel {
struct tb *tb;
@@ -50,6 +55,12 @@ struct tb_tunnel {
int (*init)(struct tb_tunnel *tunnel);
void (*deinit)(struct tb_tunnel *tunnel);
int (*activate)(struct tb_tunnel *tunnel, bool activate);
+ int (*maximum_bandwidth)(struct tb_tunnel *tunnel, int *max_up,
+ int *max_down);
+ int (*allocated_bandwidth)(struct tb_tunnel *tunnel, int *allocated_up,
+ int *allocated_down);
+ int (*alloc_bandwidth)(struct tb_tunnel *tunnel, int *alloc_up,
+ int *alloc_down);
int (*consumed_bandwidth)(struct tb_tunnel *tunnel, int *consumed_up,
int *consumed_down);
int (*release_unused_bandwidth)(struct tb_tunnel *tunnel);
@@ -62,6 +73,7 @@ struct tb_tunnel {
int max_down;
int allocated_up;
int allocated_down;
+ bool bw_mode;
};
struct tb_tunnel *tb_tunnel_discover_pci(struct tb *tb, struct tb_port *down,
@@ -92,6 +104,12 @@ void tb_tunnel_deactivate(struct tb_tunnel *tunnel);
bool tb_tunnel_is_invalid(struct tb_tunnel *tunnel);
bool tb_tunnel_port_on_path(const struct tb_tunnel *tunnel,
const struct tb_port *port);
+int tb_tunnel_maximum_bandwidth(struct tb_tunnel *tunnel, int *max_up,
+ int *max_down);
+int tb_tunnel_allocated_bandwidth(struct tb_tunnel *tunnel, int *allocated_up,
+ int *allocated_down);
+int tb_tunnel_alloc_bandwidth(struct tb_tunnel *tunnel, int *alloc_up,
+ int *alloc_down);
int tb_tunnel_consumed_bandwidth(struct tb_tunnel *tunnel, int *consumed_up,
int *consumed_down);
int tb_tunnel_release_unused_bandwidth(struct tb_tunnel *tunnel);
diff --git a/drivers/thunderbolt/usb4.c b/drivers/thunderbolt/usb4.c
index 2ed50fcbcca7..1e5e9c147a31 100644
--- a/drivers/thunderbolt/usb4.c
+++ b/drivers/thunderbolt/usb4.c
@@ -2186,3 +2186,575 @@ err_request:
usb4_usb3_port_clear_cm_request(port);
return ret;
}
+
+static bool is_usb4_dpin(const struct tb_port *port)
+{
+ if (!tb_port_is_dpin(port))
+ return false;
+ if (!tb_switch_is_usb4(port->sw))
+ return false;
+ return true;
+}
+
+/**
+ * usb4_dp_port_set_cm_id() - Assign CM ID to the DP IN adapter
+ * @port: DP IN adapter
+ * @cm_id: CM ID to assign
+ *
+ * Sets CM ID for the @port. Returns %0 on success and negative errno
+ * otherwise. Speficially returns %-EOPNOTSUPP if the @port does not
+ * support this.
+ */
+int usb4_dp_port_set_cm_id(struct tb_port *port, int cm_id)
+{
+ u32 val;
+ int ret;
+
+ if (!is_usb4_dpin(port))
+ return -EOPNOTSUPP;
+
+ ret = tb_port_read(port, &val, TB_CFG_PORT,
+ port->cap_adap + ADP_DP_CS_2, 1);
+ if (ret)
+ return ret;
+
+ val &= ~ADP_DP_CS_2_CM_ID_MASK;
+ val |= cm_id << ADP_DP_CS_2_CM_ID_SHIFT;
+
+ return tb_port_write(port, &val, TB_CFG_PORT,
+ port->cap_adap + ADP_DP_CS_2, 1);
+}
+
+/**
+ * usb4_dp_port_bw_mode_supported() - Is the bandwidth allocation mode supported
+ * @port: DP IN adapter to check
+ *
+ * Can be called to any DP IN adapter. Returns true if the adapter
+ * supports USB4 bandwidth allocation mode, false otherwise.
+ */
+bool usb4_dp_port_bw_mode_supported(struct tb_port *port)
+{
+ int ret;
+ u32 val;
+
+ if (!is_usb4_dpin(port))
+ return false;
+
+ ret = tb_port_read(port, &val, TB_CFG_PORT,
+ port->cap_adap + DP_LOCAL_CAP, 1);
+ if (ret)
+ return false;
+
+ return !!(val & DP_COMMON_CAP_BW_MODE);
+}
+
+/**
+ * usb4_dp_port_bw_mode_enabled() - Is the bandwidth allocation mode enabled
+ * @port: DP IN adapter to check
+ *
+ * Can be called to any DP IN adapter. Returns true if the bandwidth
+ * allocation mode has been enabled, false otherwise.
+ */
+bool usb4_dp_port_bw_mode_enabled(struct tb_port *port)
+{
+ int ret;
+ u32 val;
+
+ if (!is_usb4_dpin(port))
+ return false;
+
+ ret = tb_port_read(port, &val, TB_CFG_PORT,
+ port->cap_adap + ADP_DP_CS_8, 1);
+ if (ret)
+ return false;
+
+ return !!(val & ADP_DP_CS_8_DPME);
+}
+
+/**
+ * usb4_dp_port_set_cm_bw_mode_supported() - Set/clear CM support for bandwidth allocation mode
+ * @port: DP IN adapter
+ * @supported: Does the CM support bandwidth allocation mode
+ *
+ * Can be called to any DP IN adapter. Sets or clears the CM support bit
+ * of the DP IN adapter. Returns %0 in success and negative errno
+ * otherwise. Specifically returns %-OPNOTSUPP if the passed in adapter
+ * does not support this.
+ */
+int usb4_dp_port_set_cm_bw_mode_supported(struct tb_port *port, bool supported)
+{
+ u32 val;
+ int ret;
+
+ if (!is_usb4_dpin(port))
+ return -EOPNOTSUPP;
+
+ ret = tb_port_read(port, &val, TB_CFG_PORT,
+ port->cap_adap + ADP_DP_CS_2, 1);
+ if (ret)
+ return ret;
+
+ if (supported)
+ val |= ADP_DP_CS_2_CMMS;
+ else
+ val &= ~ADP_DP_CS_2_CMMS;
+
+ return tb_port_write(port, &val, TB_CFG_PORT,
+ port->cap_adap + ADP_DP_CS_2, 1);
+}
+
+/**
+ * usb4_dp_port_group_id() - Return Group ID assigned for the adapter
+ * @port: DP IN adapter
+ *
+ * Reads bandwidth allocation Group ID from the DP IN adapter and
+ * returns it. If the adapter does not support setting Group_ID
+ * %-EOPNOTSUPP is returned.
+ */
+int usb4_dp_port_group_id(struct tb_port *port)
+{
+ u32 val;
+ int ret;
+
+ if (!is_usb4_dpin(port))
+ return -EOPNOTSUPP;
+
+ ret = tb_port_read(port, &val, TB_CFG_PORT,
+ port->cap_adap + ADP_DP_CS_2, 1);
+ if (ret)
+ return ret;
+
+ return (val & ADP_DP_CS_2_GROUP_ID_MASK) >> ADP_DP_CS_2_GROUP_ID_SHIFT;
+}
+
+/**
+ * usb4_dp_port_set_group_id() - Set adapter Group ID
+ * @port: DP IN adapter
+ * @group_id: Group ID for the adapter
+ *
+ * Sets bandwidth allocation mode Group ID for the DP IN adapter.
+ * Returns %0 in case of success and negative errno otherwise.
+ * Specifically returns %-EOPNOTSUPP if the adapter does not support
+ * this.
+ */
+int usb4_dp_port_set_group_id(struct tb_port *port, int group_id)
+{
+ u32 val;
+ int ret;
+
+ if (!is_usb4_dpin(port))
+ return -EOPNOTSUPP;
+
+ ret = tb_port_read(port, &val, TB_CFG_PORT,
+ port->cap_adap + ADP_DP_CS_2, 1);
+ if (ret)
+ return ret;
+
+ val &= ~ADP_DP_CS_2_GROUP_ID_MASK;
+ val |= group_id << ADP_DP_CS_2_GROUP_ID_SHIFT;
+
+ return tb_port_write(port, &val, TB_CFG_PORT,
+ port->cap_adap + ADP_DP_CS_2, 1);
+}
+
+/**
+ * usb4_dp_port_nrd() - Read non-reduced rate and lanes
+ * @port: DP IN adapter
+ * @rate: Non-reduced rate in Mb/s is placed here
+ * @lanes: Non-reduced lanes are placed here
+ *
+ * Reads the non-reduced rate and lanes from the DP IN adapter. Returns
+ * %0 in success and negative errno otherwise. Specifically returns
+ * %-EOPNOTSUPP if the adapter does not support this.
+ */
+int usb4_dp_port_nrd(struct tb_port *port, int *rate, int *lanes)
+{
+ u32 val, tmp;
+ int ret;
+
+ if (!is_usb4_dpin(port))
+ return -EOPNOTSUPP;
+
+ ret = tb_port_read(port, &val, TB_CFG_PORT,
+ port->cap_adap + ADP_DP_CS_2, 1);
+ if (ret)
+ return ret;
+
+ tmp = (val & ADP_DP_CS_2_NRD_MLR_MASK) >> ADP_DP_CS_2_NRD_MLR_SHIFT;
+ switch (tmp) {
+ case DP_COMMON_CAP_RATE_RBR:
+ *rate = 1620;
+ break;
+ case DP_COMMON_CAP_RATE_HBR:
+ *rate = 2700;
+ break;
+ case DP_COMMON_CAP_RATE_HBR2:
+ *rate = 5400;
+ break;
+ case DP_COMMON_CAP_RATE_HBR3:
+ *rate = 8100;
+ break;
+ }
+
+ tmp = val & ADP_DP_CS_2_NRD_MLC_MASK;
+ switch (tmp) {
+ case DP_COMMON_CAP_1_LANE:
+ *lanes = 1;
+ break;
+ case DP_COMMON_CAP_2_LANES:
+ *lanes = 2;
+ break;
+ case DP_COMMON_CAP_4_LANES:
+ *lanes = 4;
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * usb4_dp_port_set_nrd() - Set non-reduced rate and lanes
+ * @port: DP IN adapter
+ * @rate: Non-reduced rate in Mb/s
+ * @lanes: Non-reduced lanes
+ *
+ * Before the capabilities reduction this function can be used to set
+ * the non-reduced values for the DP IN adapter. Returns %0 in success
+ * and negative errno otherwise. If the adapter does not support this
+ * %-EOPNOTSUPP is returned.
+ */
+int usb4_dp_port_set_nrd(struct tb_port *port, int rate, int lanes)
+{
+ u32 val;
+ int ret;
+
+ if (!is_usb4_dpin(port))
+ return -EOPNOTSUPP;
+
+ ret = tb_port_read(port, &val, TB_CFG_PORT,
+ port->cap_adap + ADP_DP_CS_2, 1);
+ if (ret)
+ return ret;
+
+ val &= ~ADP_DP_CS_2_NRD_MLR_MASK;
+
+ switch (rate) {
+ case 1620:
+ break;
+ case 2700:
+ val |= (DP_COMMON_CAP_RATE_HBR << ADP_DP_CS_2_NRD_MLR_SHIFT)
+ & ADP_DP_CS_2_NRD_MLR_MASK;
+ break;
+ case 5400:
+ val |= (DP_COMMON_CAP_RATE_HBR2 << ADP_DP_CS_2_NRD_MLR_SHIFT)
+ & ADP_DP_CS_2_NRD_MLR_MASK;
+ break;
+ case 8100:
+ val |= (DP_COMMON_CAP_RATE_HBR3 << ADP_DP_CS_2_NRD_MLR_SHIFT)
+ & ADP_DP_CS_2_NRD_MLR_MASK;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ val &= ~ADP_DP_CS_2_NRD_MLC_MASK;
+
+ switch (lanes) {
+ case 1:
+ break;
+ case 2:
+ val |= DP_COMMON_CAP_2_LANES;
+ break;
+ case 4:
+ val |= DP_COMMON_CAP_4_LANES;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return tb_port_write(port, &val, TB_CFG_PORT,
+ port->cap_adap + ADP_DP_CS_2, 1);
+}
+
+/**
+ * usb4_dp_port_granularity() - Return granularity for the bandwidth values
+ * @port: DP IN adapter
+ *
+ * Reads the programmed granularity from @port. If the DP IN adapter does
+ * not support bandwidth allocation mode returns %-EOPNOTSUPP and negative
+ * errno in other error cases.
+ */
+int usb4_dp_port_granularity(struct tb_port *port)
+{
+ u32 val;
+ int ret;
+
+ if (!is_usb4_dpin(port))
+ return -EOPNOTSUPP;
+
+ ret = tb_port_read(port, &val, TB_CFG_PORT,
+ port->cap_adap + ADP_DP_CS_2, 1);
+ if (ret)
+ return ret;
+
+ val &= ADP_DP_CS_2_GR_MASK;
+ val >>= ADP_DP_CS_2_GR_SHIFT;
+
+ switch (val) {
+ case ADP_DP_CS_2_GR_0_25G:
+ return 250;
+ case ADP_DP_CS_2_GR_0_5G:
+ return 500;
+ case ADP_DP_CS_2_GR_1G:
+ return 1000;
+ }
+
+ return -EINVAL;
+}
+
+/**
+ * usb4_dp_port_set_granularity() - Set granularity for the bandwidth values
+ * @port: DP IN adapter
+ * @granularity: Granularity in Mb/s. Supported values: 1000, 500 and 250.
+ *
+ * Sets the granularity used with the estimated, allocated and requested
+ * bandwidth. Returns %0 in success and negative errno otherwise. If the
+ * adapter does not support this %-EOPNOTSUPP is returned.
+ */
+int usb4_dp_port_set_granularity(struct tb_port *port, int granularity)
+{
+ u32 val;
+ int ret;
+
+ if (!is_usb4_dpin(port))
+ return -EOPNOTSUPP;
+
+ ret = tb_port_read(port, &val, TB_CFG_PORT,
+ port->cap_adap + ADP_DP_CS_2, 1);
+ if (ret)
+ return ret;
+
+ val &= ~ADP_DP_CS_2_GR_MASK;
+
+ switch (granularity) {
+ case 250:
+ val |= ADP_DP_CS_2_GR_0_25G << ADP_DP_CS_2_GR_SHIFT;
+ break;
+ case 500:
+ val |= ADP_DP_CS_2_GR_0_5G << ADP_DP_CS_2_GR_SHIFT;
+ break;
+ case 1000:
+ val |= ADP_DP_CS_2_GR_1G << ADP_DP_CS_2_GR_SHIFT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return tb_port_write(port, &val, TB_CFG_PORT,
+ port->cap_adap + ADP_DP_CS_2, 1);
+}
+
+/**
+ * usb4_dp_port_set_estimated_bw() - Set estimated bandwidth
+ * @port: DP IN adapter
+ * @bw: Estimated bandwidth in Mb/s.
+ *
+ * Sets the estimated bandwidth to @bw. Set the granularity by calling
+ * usb4_dp_port_set_granularity() before calling this. The @bw is round
+ * down to the closest granularity multiplier. Returns %0 in success
+ * and negative errno otherwise. Specifically returns %-EOPNOTSUPP if
+ * the adapter does not support this.
+ */
+int usb4_dp_port_set_estimated_bw(struct tb_port *port, int bw)
+{
+ u32 val, granularity;
+ int ret;
+
+ if (!is_usb4_dpin(port))
+ return -EOPNOTSUPP;
+
+ ret = usb4_dp_port_granularity(port);
+ if (ret < 0)
+ return ret;
+ granularity = ret;
+
+ ret = tb_port_read(port, &val, TB_CFG_PORT,
+ port->cap_adap + ADP_DP_CS_2, 1);
+ if (ret)
+ return ret;
+
+ val &= ~ADP_DP_CS_2_ESTIMATED_BW_MASK;
+ val |= (bw / granularity) << ADP_DP_CS_2_ESTIMATED_BW_SHIFT;
+
+ return tb_port_write(port, &val, TB_CFG_PORT,
+ port->cap_adap + ADP_DP_CS_2, 1);
+}
+
+/**
+ * usb4_dp_port_allocated_bw() - Return allocated bandwidth
+ * @port: DP IN adapter
+ *
+ * Reads and returns allocated bandwidth for @port in Mb/s (taking into
+ * account the programmed granularity). Returns negative errno in case
+ * of error.
+ */
+int usb4_dp_port_allocated_bw(struct tb_port *port)
+{
+ u32 val, granularity;
+ int ret;
+
+ if (!is_usb4_dpin(port))
+ return -EOPNOTSUPP;
+
+ ret = usb4_dp_port_granularity(port);
+ if (ret < 0)
+ return ret;
+ granularity = ret;
+
+ ret = tb_port_read(port, &val, TB_CFG_PORT,
+ port->cap_adap + DP_STATUS, 1);
+ if (ret)
+ return ret;
+
+ val &= DP_STATUS_ALLOCATED_BW_MASK;
+ val >>= DP_STATUS_ALLOCATED_BW_SHIFT;
+
+ return val * granularity;
+}
+
+static int __usb4_dp_port_set_cm_ack(struct tb_port *port, bool ack)
+{
+ u32 val;
+ int ret;
+
+ ret = tb_port_read(port, &val, TB_CFG_PORT,
+ port->cap_adap + ADP_DP_CS_2, 1);
+ if (ret)
+ return ret;
+
+ if (ack)
+ val |= ADP_DP_CS_2_CA;
+ else
+ val &= ~ADP_DP_CS_2_CA;
+
+ return tb_port_write(port, &val, TB_CFG_PORT,
+ port->cap_adap + ADP_DP_CS_2, 1);
+}
+
+static inline int usb4_dp_port_set_cm_ack(struct tb_port *port)
+{
+ return __usb4_dp_port_set_cm_ack(port, true);
+}
+
+static int usb4_dp_port_wait_and_clear_cm_ack(struct tb_port *port,
+ int timeout_msec)
+{
+ ktime_t end;
+ u32 val;
+ int ret;
+
+ ret = __usb4_dp_port_set_cm_ack(port, false);
+ if (ret)
+ return ret;
+
+ end = ktime_add_ms(ktime_get(), timeout_msec);
+ do {
+ ret = tb_port_read(port, &val, TB_CFG_PORT,
+ port->cap_adap + ADP_DP_CS_8, 1);
+ if (ret)
+ return ret;
+
+ if (!(val & ADP_DP_CS_8_DR))
+ break;
+
+ usleep_range(50, 100);
+ } while (ktime_before(ktime_get(), end));
+
+ if (val & ADP_DP_CS_8_DR)
+ return -ETIMEDOUT;
+
+ ret = tb_port_read(port, &val, TB_CFG_PORT,
+ port->cap_adap + ADP_DP_CS_2, 1);
+ if (ret)
+ return ret;
+
+ val &= ~ADP_DP_CS_2_CA;
+ return tb_port_write(port, &val, TB_CFG_PORT,
+ port->cap_adap + ADP_DP_CS_2, 1);
+}
+
+/**
+ * usb4_dp_port_allocate_bw() - Set allocated bandwidth
+ * @port: DP IN adapter
+ * @bw: New allocated bandwidth in Mb/s
+ *
+ * Communicates the new allocated bandwidth with the DPCD (graphics
+ * driver). Takes into account the programmed granularity. Returns %0 in
+ * success and negative errno in case of error.
+ */
+int usb4_dp_port_allocate_bw(struct tb_port *port, int bw)
+{
+ u32 val, granularity;
+ int ret;
+
+ if (!is_usb4_dpin(port))
+ return -EOPNOTSUPP;
+
+ ret = usb4_dp_port_granularity(port);
+ if (ret < 0)
+ return ret;
+ granularity = ret;
+
+ ret = tb_port_read(port, &val, TB_CFG_PORT,
+ port->cap_adap + DP_STATUS, 1);
+ if (ret)
+ return ret;
+
+ val &= ~DP_STATUS_ALLOCATED_BW_MASK;
+ val |= (bw / granularity) << DP_STATUS_ALLOCATED_BW_SHIFT;
+
+ ret = tb_port_write(port, &val, TB_CFG_PORT,
+ port->cap_adap + DP_STATUS, 1);
+ if (ret)
+ return ret;
+
+ ret = usb4_dp_port_set_cm_ack(port);
+ if (ret)
+ return ret;
+
+ return usb4_dp_port_wait_and_clear_cm_ack(port, 500);
+}
+
+/**
+ * usb4_dp_port_requested_bw() - Read requested bandwidth
+ * @port: DP IN adapter
+ *
+ * Reads the DPCD (graphics driver) requested bandwidth and returns it
+ * in Mb/s. Takes the programmed granularity into account. In case of
+ * error returns negative errno. Specifically returns %-EOPNOTSUPP if
+ * the adapter does not support bandwidth allocation mode, and %ENODATA
+ * if there is no active bandwidth request from the graphics driver.
+ */
+int usb4_dp_port_requested_bw(struct tb_port *port)
+{
+ u32 val, granularity;
+ int ret;
+
+ if (!is_usb4_dpin(port))
+ return -EOPNOTSUPP;
+
+ ret = usb4_dp_port_granularity(port);
+ if (ret < 0)
+ return ret;
+ granularity = ret;
+
+ ret = tb_port_read(port, &val, TB_CFG_PORT,
+ port->cap_adap + ADP_DP_CS_8, 1);
+ if (ret)
+ return ret;
+
+ if (!(val & ADP_DP_CS_8_DR))
+ return -ENODATA;
+
+ return (val & ADP_DP_CS_8_REQUESTED_BW_MASK) * granularity;
+}
diff --git a/drivers/thunderbolt/xdomain.c b/drivers/thunderbolt/xdomain.c
index 3c51e47dd86b..a48335c95d39 100644
--- a/drivers/thunderbolt/xdomain.c
+++ b/drivers/thunderbolt/xdomain.c
@@ -881,7 +881,7 @@ static ssize_t key_show(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR_RO(key);
-static int get_modalias(struct tb_service *svc, char *buf, size_t size)
+static int get_modalias(const struct tb_service *svc, char *buf, size_t size)
{
return snprintf(buf, size, "tbsvc:k%sp%08Xv%08Xr%08X", svc->key,
svc->prtcid, svc->prtcvers, svc->prtcrevs);
@@ -953,9 +953,9 @@ static const struct attribute_group *tb_service_attr_groups[] = {
NULL,
};
-static int tb_service_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int tb_service_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct tb_service *svc = container_of(dev, struct tb_service, dev);
+ const struct tb_service *svc = container_of_const(dev, struct tb_service, dev);
char modalias[64];
get_modalias(svc, modalias, sizeof(modalias));
diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c
index f52266766df9..d7515d61659e 100644
--- a/drivers/tty/amiserial.c
+++ b/drivers/tty/amiserial.c
@@ -502,7 +502,7 @@ static int startup(struct tty_struct *tty, struct serial_state *info)
*/
change_speed(tty, info, NULL);
- tty_port_set_initialized(port, 1);
+ tty_port_set_initialized(port, true);
local_irq_restore(flags);
return 0;
@@ -556,7 +556,7 @@ static void shutdown(struct tty_struct *tty, struct serial_state *info)
set_bit(TTY_IO_ERROR, &tty->flags);
- tty_port_set_initialized(&info->tport, 0);
+ tty_port_set_initialized(&info->tport, false);
local_irq_restore(flags);
}
@@ -1329,7 +1329,7 @@ static void rs_hangup(struct tty_struct *tty)
rs_flush_buffer(tty);
shutdown(tty, info);
info->tport.count = 0;
- tty_port_set_active(&info->tport, 0);
+ tty_port_set_active(&info->tport, false);
info->tport.tty = NULL;
wake_up_interruptible(&info->tport.open_wait);
}
@@ -1454,18 +1454,18 @@ static const struct tty_operations serial_ops = {
.proc_show = rs_proc_show,
};
-static int amiga_carrier_raised(struct tty_port *port)
+static bool amiga_carrier_raised(struct tty_port *port)
{
return !(ciab.pra & SER_DCD);
}
-static void amiga_dtr_rts(struct tty_port *port, int raise)
+static void amiga_dtr_rts(struct tty_port *port, bool active)
{
struct serial_state *info = container_of(port, struct serial_state,
tport);
unsigned long flags;
- if (raise)
+ if (active)
info->MCR |= SER_DTR|SER_RTS;
else
info->MCR &= ~(SER_DTR|SER_RTS);
diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c
index a683e21df19c..10c10cfdf92a 100644
--- a/drivers/tty/hvc/hvc_console.c
+++ b/drivers/tty/hvc/hvc_console.c
@@ -376,7 +376,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
/* We are ready... raise DTR/RTS */
if (C_BAUD(tty))
if (hp->ops->dtr_rts)
- hp->ops->dtr_rts(hp, 1);
+ hp->ops->dtr_rts(hp, true);
tty_port_set_initialized(&hp->port, true);
}
@@ -406,7 +406,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
if (C_HUPCL(tty))
if (hp->ops->dtr_rts)
- hp->ops->dtr_rts(hp, 0);
+ hp->ops->dtr_rts(hp, false);
if (hp->ops->notifier_del)
hp->ops->notifier_del(hp, hp->data);
diff --git a/drivers/tty/hvc/hvc_console.h b/drivers/tty/hvc/hvc_console.h
index 18d005814e4b..9668f821db01 100644
--- a/drivers/tty/hvc/hvc_console.h
+++ b/drivers/tty/hvc/hvc_console.h
@@ -66,7 +66,7 @@ struct hv_ops {
int (*tiocmset)(struct hvc_struct *hp, unsigned int set, unsigned int clear);
/* Callbacks to handle tty ports */
- void (*dtr_rts)(struct hvc_struct *hp, int raise);
+ void (*dtr_rts)(struct hvc_struct *hp, bool active);
};
/* Register a vterm and a slot index for use as a console (console_init) */
diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c
index 7d49a872de48..543f35ddf523 100644
--- a/drivers/tty/hvc/hvc_iucv.c
+++ b/drivers/tty/hvc/hvc_iucv.c
@@ -658,13 +658,13 @@ static void hvc_iucv_notifier_hangup(struct hvc_struct *hp, int id)
/**
* hvc_iucv_dtr_rts() - HVC notifier for handling DTR/RTS
* @hp: Pointer the HVC device (struct hvc_struct)
- * @raise: Non-zero to raise or zero to lower DTR/RTS lines
+ * @active: True to raise or false to lower DTR/RTS lines
*
* This routine notifies the HVC back-end to raise or lower DTR/RTS
* lines. Raising DTR/RTS is ignored. Lowering DTR/RTS indicates to
* drop the IUCV connection (similar to hang up the modem).
*/
-static void hvc_iucv_dtr_rts(struct hvc_struct *hp, int raise)
+static void hvc_iucv_dtr_rts(struct hvc_struct *hp, bool active)
{
struct hvc_iucv_private *priv;
struct iucv_path *path;
@@ -672,7 +672,7 @@ static void hvc_iucv_dtr_rts(struct hvc_struct *hp, int raise)
/* Raising the DTR/RTS is ignored as IUCV connections can be
* established at any times.
*/
- if (raise)
+ if (active)
return;
priv = hvc_iucv_get_private(hp->vtermno);
diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c
index 4ba24963685e..1de1a09bf82d 100644
--- a/drivers/tty/hvc/hvcs.c
+++ b/drivers/tty/hvc/hvcs.c
@@ -52,6 +52,7 @@
#include <linux/device.h>
#include <linux/init.h>
+#include <linux/completion.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/kref.h>
@@ -285,6 +286,7 @@ struct hvcs_struct {
char p_location_code[HVCS_CLC_LENGTH + 1]; /* CLC + Null Term */
struct list_head next; /* list management */
struct vio_dev *vdev;
+ struct completion *destroyed;
};
static LIST_HEAD(hvcs_structs);
@@ -432,7 +434,7 @@ static ssize_t hvcs_index_show(struct device *dev, struct device_attribute *attr
static DEVICE_ATTR(index, S_IRUGO, hvcs_index_show, NULL);
-static struct attribute *hvcs_attrs[] = {
+static struct attribute *hvcs_dev_attrs[] = {
&dev_attr_partner_vtys.attr,
&dev_attr_partner_clcs.attr,
&dev_attr_current_vty.attr,
@@ -441,9 +443,7 @@ static struct attribute *hvcs_attrs[] = {
NULL,
};
-static struct attribute_group hvcs_attr_group = {
- .attrs = hvcs_attrs,
-};
+ATTRIBUTE_GROUPS(hvcs_dev);
static ssize_t rescan_show(struct device_driver *ddp, char *buf)
{
@@ -468,6 +468,13 @@ static ssize_t rescan_store(struct device_driver *ddp, const char * buf,
static DRIVER_ATTR_RW(rescan);
+static struct attribute *hvcs_attrs[] = {
+ &driver_attr_rescan.attr,
+ NULL,
+};
+
+ATTRIBUTE_GROUPS(hvcs);
+
static void hvcs_kick(void)
{
hvcs_kicked = 1;
@@ -658,11 +665,13 @@ static void hvcs_destruct_port(struct tty_port *p)
{
struct hvcs_struct *hvcsd = container_of(p, struct hvcs_struct, port);
struct vio_dev *vdev;
+ struct completion *comp;
unsigned long flags;
spin_lock(&hvcs_structs_lock);
spin_lock_irqsave(&hvcsd->lock, flags);
+ comp = hvcsd->destroyed;
/* the list_del poisons the pointers */
list_del(&(hvcsd->next));
@@ -682,15 +691,16 @@ static void hvcs_destruct_port(struct tty_port *p)
hvcsd->p_unit_address = 0;
hvcsd->p_partition_ID = 0;
+ hvcsd->destroyed = NULL;
hvcs_return_index(hvcsd->index);
memset(&hvcsd->p_location_code[0], 0x00, HVCS_CLC_LENGTH + 1);
spin_unlock_irqrestore(&hvcsd->lock, flags);
spin_unlock(&hvcs_structs_lock);
- sysfs_remove_group(&vdev->dev.kobj, &hvcs_attr_group);
-
kfree(hvcsd);
+ if (comp)
+ complete(comp);
}
static const struct tty_port_operations hvcs_port_ops = {
@@ -721,7 +731,6 @@ static int hvcs_probe(
{
struct hvcs_struct *hvcsd;
int index, rc;
- int retval;
if (!dev || !id) {
printk(KERN_ERR "HVCS: probed with invalid parameter.\n");
@@ -778,13 +787,6 @@ static int hvcs_probe(
list_add_tail(&(hvcsd->next), &hvcs_structs);
spin_unlock(&hvcs_structs_lock);
- retval = sysfs_create_group(&dev->dev.kobj, &hvcs_attr_group);
- if (retval) {
- printk(KERN_ERR "HVCS: Can't create sysfs attrs for vty-server@%X\n",
- hvcsd->vdev->unit_address);
- return retval;
- }
-
printk(KERN_INFO "HVCS: vty-server@%X added to the vio bus.\n", dev->unit_address);
/*
@@ -797,6 +799,7 @@ static int hvcs_probe(
static void hvcs_remove(struct vio_dev *dev)
{
struct hvcs_struct *hvcsd = dev_get_drvdata(&dev->dev);
+ DECLARE_COMPLETION_ONSTACK(comp);
unsigned long flags;
struct tty_struct *tty;
@@ -804,24 +807,22 @@ static void hvcs_remove(struct vio_dev *dev)
spin_lock_irqsave(&hvcsd->lock, flags);
- tty = hvcsd->port.tty;
+ hvcsd->destroyed = &comp;
+ tty = tty_port_tty_get(&hvcsd->port);
spin_unlock_irqrestore(&hvcsd->lock, flags);
/*
- * Let the last holder of this object cause it to be removed, which
- * would probably be tty_hangup below.
- */
- tty_port_put(&hvcsd->port);
-
- /*
- * The hangup is a scheduled function which will auto chain call
- * hvcs_hangup. The tty should always be valid at this time unless a
+ * The tty should always be valid at this time unless a
* simultaneous tty close already cleaned up the hvcs_struct.
*/
- if (tty)
- tty_hangup(tty);
+ if (tty) {
+ tty_vhangup(tty);
+ tty_kref_put(tty);
+ }
+ tty_port_put(&hvcsd->port);
+ wait_for_completion(&comp);
printk(KERN_INFO "HVCS: vty-server@%X removed from the"
" vio bus.\n", dev->unit_address);
};
@@ -831,6 +832,10 @@ static struct vio_driver hvcs_vio_driver = {
.probe = hvcs_probe,
.remove = hvcs_remove,
.name = hvcs_driver_name,
+ .driver = {
+ .groups = hvcs_groups,
+ .dev_groups = hvcs_dev_groups,
+ },
};
/* Only called from hvcs_get_pi please */
@@ -1171,7 +1176,10 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
hvcsd = tty->driver_data;
spin_lock_irqsave(&hvcsd->lock, flags);
- if (--hvcsd->port.count == 0) {
+ if (hvcsd->port.count == 0) {
+ spin_unlock_irqrestore(&hvcsd->lock, flags);
+ return;
+ } else if (--hvcsd->port.count == 0) {
vio_disable_interrupts(hvcsd->vdev);
@@ -1215,12 +1223,9 @@ static void hvcs_hangup(struct tty_struct * tty)
{
struct hvcs_struct *hvcsd = tty->driver_data;
unsigned long flags;
- int temp_open_count;
int irq;
spin_lock_irqsave(&hvcsd->lock, flags);
- /* Preserve this so that we know how many kref refs to put */
- temp_open_count = hvcsd->port.count;
/*
* Don't kref put inside the spinlock because the destruction
@@ -1230,11 +1235,7 @@ static void hvcs_hangup(struct tty_struct * tty)
vio_disable_interrupts(hvcsd->vdev);
hvcsd->todo_mask = 0;
-
- /* I don't think the tty needs the hvcs_struct pointer after a hangup */
- tty->driver_data = NULL;
hvcsd->port.tty = NULL;
-
hvcsd->port.count = 0;
/* This will drop any buffered data on the floor which is OK in a hangup
@@ -1247,21 +1248,6 @@ static void hvcs_hangup(struct tty_struct * tty)
spin_unlock_irqrestore(&hvcsd->lock, flags);
free_irq(irq, hvcsd);
-
- /*
- * We need to kref_put() for every open_count we have since the
- * tty_hangup() function doesn't invoke a close per open connection on a
- * non-console device.
- */
- while(temp_open_count) {
- --temp_open_count;
- /*
- * The final put will trigger destruction of the hvcs_struct.
- * NOTE: If this hangup was signaled from user space then the
- * final put will never happen.
- */
- tty_port_put(&hvcsd->port);
- }
}
/*
@@ -1525,13 +1511,6 @@ static int __init hvcs_module_init(void)
pr_info("HVCS: Driver registered.\n");
- /* This needs to be done AFTER the vio_register_driver() call or else
- * the kobjects won't be initialized properly.
- */
- rc = driver_create_file(&(hvcs_vio_driver.driver), &driver_attr_rescan);
- if (rc)
- pr_warn("HVCS: Failed to create rescan file (err %d)\n", rc);
-
return 0;
}
@@ -1556,8 +1535,6 @@ static void __exit hvcs_module_exit(void)
hvcs_pi_buff = NULL;
spin_unlock(&hvcs_pi_lock);
- driver_remove_file(&hvcs_vio_driver.driver, &driver_attr_rescan);
-
tty_unregister_driver(hvcs_tty_driver);
hvcs_free_index_list();
diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c
index 35b6fddf0341..42fa4c878b2e 100644
--- a/drivers/tty/moxa.c
+++ b/drivers/tty/moxa.c
@@ -501,16 +501,16 @@ static int moxa_tiocmset(struct tty_struct *tty,
static void moxa_poll(struct timer_list *);
static void moxa_set_tty_param(struct tty_struct *, const struct ktermios *);
static void moxa_shutdown(struct tty_port *);
-static int moxa_carrier_raised(struct tty_port *);
-static void moxa_dtr_rts(struct tty_port *, int);
+static bool moxa_carrier_raised(struct tty_port *);
+static void moxa_dtr_rts(struct tty_port *, bool);
/*
* moxa board interface functions:
*/
static void MoxaPortEnable(struct moxa_port *);
static void MoxaPortDisable(struct moxa_port *);
static int MoxaPortSetTermio(struct moxa_port *, struct ktermios *, speed_t);
-static int MoxaPortGetLineOut(struct moxa_port *, int *, int *);
-static void MoxaPortLineCtrl(struct moxa_port *, int, int);
+static int MoxaPortGetLineOut(struct moxa_port *, bool *, bool *);
+static void MoxaPortLineCtrl(struct moxa_port *, bool, bool);
static void MoxaPortFlowCtrl(struct moxa_port *, int, int, int, int, int);
static int MoxaPortLineStatus(struct moxa_port *);
static void MoxaPortFlushData(struct moxa_port *, int);
@@ -1432,7 +1432,7 @@ static void moxa_shutdown(struct tty_port *port)
MoxaPortFlushData(ch, 2);
}
-static int moxa_carrier_raised(struct tty_port *port)
+static bool moxa_carrier_raised(struct tty_port *port)
{
struct moxa_port *ch = container_of(port, struct moxa_port, port);
int dcd;
@@ -1443,10 +1443,10 @@ static int moxa_carrier_raised(struct tty_port *port)
return dcd;
}
-static void moxa_dtr_rts(struct tty_port *port, int onoff)
+static void moxa_dtr_rts(struct tty_port *port, bool active)
{
struct moxa_port *ch = container_of(port, struct moxa_port, port);
- MoxaPortLineCtrl(ch, onoff, onoff);
+ MoxaPortLineCtrl(ch, active, active);
}
@@ -1481,10 +1481,10 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
if (!tty_port_initialized(&ch->port)) {
ch->statusflags = 0;
moxa_set_tty_param(tty, &tty->termios);
- MoxaPortLineCtrl(ch, 1, 1);
+ MoxaPortLineCtrl(ch, true, true);
MoxaPortEnable(ch);
MoxaSetFifo(ch, ch->type == PORT_16550A);
- tty_port_set_initialized(&ch->port, 1);
+ tty_port_set_initialized(&ch->port, true);
}
mutex_unlock(&ch->port.mutex);
mutex_unlock(&moxa_openlock);
@@ -1557,19 +1557,21 @@ static unsigned int moxa_chars_in_buffer(struct tty_struct *tty)
static int moxa_tiocmget(struct tty_struct *tty)
{
struct moxa_port *ch = tty->driver_data;
- int flag = 0, dtr, rts;
+ bool dtr_active, rts_active;
+ int flag = 0;
+ int status;
- MoxaPortGetLineOut(ch, &dtr, &rts);
- if (dtr)
+ MoxaPortGetLineOut(ch, &dtr_active, &rts_active);
+ if (dtr_active)
flag |= TIOCM_DTR;
- if (rts)
+ if (rts_active)
flag |= TIOCM_RTS;
- dtr = MoxaPortLineStatus(ch);
- if (dtr & 1)
+ status = MoxaPortLineStatus(ch);
+ if (status & 1)
flag |= TIOCM_CTS;
- if (dtr & 2)
+ if (status & 2)
flag |= TIOCM_DSR;
- if (dtr & 4)
+ if (status & 4)
flag |= TIOCM_CD;
return flag;
}
@@ -1577,8 +1579,8 @@ static int moxa_tiocmget(struct tty_struct *tty)
static int moxa_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear)
{
+ bool dtr_active, rts_active;
struct moxa_port *ch;
- int dtr, rts;
mutex_lock(&moxa_openlock);
ch = tty->driver_data;
@@ -1587,16 +1589,16 @@ static int moxa_tiocmset(struct tty_struct *tty,
return -EINVAL;
}
- MoxaPortGetLineOut(ch, &dtr, &rts);
+ MoxaPortGetLineOut(ch, &dtr_active, &rts_active);
if (set & TIOCM_RTS)
- rts = 1;
+ rts_active = true;
if (set & TIOCM_DTR)
- dtr = 1;
+ dtr_active = true;
if (clear & TIOCM_RTS)
- rts = 0;
+ rts_active = false;
if (clear & TIOCM_DTR)
- dtr = 0;
- MoxaPortLineCtrl(ch, dtr, rts);
+ dtr_active = false;
+ MoxaPortLineCtrl(ch, dtr_active, rts_active);
mutex_unlock(&moxa_openlock);
return 0;
}
@@ -1664,8 +1666,8 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
u16 __iomem *ip)
{
struct tty_struct *tty = tty_port_tty_get(&p->port);
+ bool inited = tty_port_initialized(&p->port);
void __iomem *ofsAddr;
- unsigned int inited = tty_port_initialized(&p->port);
u16 intr;
if (tty) {
@@ -1877,12 +1879,12 @@ static void MoxaPortFlushData(struct moxa_port *port, int mode)
*
* Function 13: Get the DTR/RTS state of this port.
* Syntax:
- * int MoxaPortGetLineOut(int port, int *dtrState, int *rtsState);
+ * int MoxaPortGetLineOut(int port, bool *dtrState, bool *rtsState);
* int port : port number (0 - 127)
- * int * dtrState : pointer to INT to receive the current DTR
+ * bool * dtr_active : pointer to bool to receive the current DTR
* state. (if NULL, this function will not
* write to this address)
- * int * rtsState : pointer to INT to receive the current RTS
+ * bool * rts_active : pointer to bool to receive the current RTS
* state. (if NULL, this function will not
* write to this address)
*
@@ -1892,10 +1894,10 @@ static void MoxaPortFlushData(struct moxa_port *port, int mode)
*
* Function 14: Setting the DTR/RTS output state of this port.
* Syntax:
- * void MoxaPortLineCtrl(int port, int dtrState, int rtsState);
+ * void MoxaPortLineCtrl(int port, bool dtrState, bool rtsState);
* int port : port number (0 - 127)
- * int dtrState : DTR output state (0: off, 1: on)
- * int rtsState : RTS output state (0: off, 1: on)
+ * bool dtr_active : DTR output state
+ * bool rts_active : RTS output state
*
*
* Function 15: Setting the flow control of this port.
@@ -2103,24 +2105,24 @@ static int MoxaPortSetTermio(struct moxa_port *port, struct ktermios *termio,
return baud;
}
-static int MoxaPortGetLineOut(struct moxa_port *port, int *dtrState,
- int *rtsState)
+static int MoxaPortGetLineOut(struct moxa_port *port, bool *dtr_active,
+ bool *rts_active)
{
- if (dtrState)
- *dtrState = !!(port->lineCtrl & DTR_ON);
- if (rtsState)
- *rtsState = !!(port->lineCtrl & RTS_ON);
+ if (dtr_active)
+ *dtr_active = port->lineCtrl & DTR_ON;
+ if (rts_active)
+ *rts_active = port->lineCtrl & RTS_ON;
return 0;
}
-static void MoxaPortLineCtrl(struct moxa_port *port, int dtr, int rts)
+static void MoxaPortLineCtrl(struct moxa_port *port, bool dtr_active, bool rts_active)
{
u8 mode = 0;
- if (dtr)
+ if (dtr_active)
mode |= DTR_ON;
- if (rts)
+ if (rts_active)
mode |= RTS_ON;
port->lineCtrl = mode;
moxafunc(port->tableAddr, FC_LineControl, mode);
diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c
index 2436e0b10f9a..ef3116e87975 100644
--- a/drivers/tty/mxser.c
+++ b/drivers/tty/mxser.c
@@ -458,13 +458,14 @@ static void __mxser_stop_tx(struct mxser_port *info)
outb(info->IER, info->ioaddr + UART_IER);
}
-static int mxser_carrier_raised(struct tty_port *port)
+static bool mxser_carrier_raised(struct tty_port *port)
{
struct mxser_port *mp = container_of(port, struct mxser_port, port);
- return (inb(mp->ioaddr + UART_MSR) & UART_MSR_DCD)?1:0;
+
+ return inb(mp->ioaddr + UART_MSR) & UART_MSR_DCD;
}
-static void mxser_dtr_rts(struct tty_port *port, int on)
+static void mxser_dtr_rts(struct tty_port *port, bool active)
{
struct mxser_port *mp = container_of(port, struct mxser_port, port);
unsigned long flags;
@@ -472,7 +473,7 @@ static void mxser_dtr_rts(struct tty_port *port, int on)
spin_lock_irqsave(&mp->slock, flags);
mcr = inb(mp->ioaddr + UART_MCR);
- if (on)
+ if (active)
mcr |= UART_MCR_DTR | UART_MCR_RTS;
else
mcr &= ~(UART_MCR_DTR | UART_MCR_RTS);
@@ -1063,7 +1064,7 @@ static int mxser_set_serial_info(struct tty_struct *tty,
} else {
retval = mxser_activate(port, tty);
if (retval == 0)
- tty_port_set_initialized(port, 1);
+ tty_port_set_initialized(port, true);
}
mutex_unlock(&port->mutex);
return retval;
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index 348d85c13f91..7aa05ebed8e1 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -318,6 +318,11 @@ struct gsm_mux {
struct gsm_control *pending_cmd;/* Our current pending command */
spinlock_t control_lock; /* Protects the pending command */
+ /* Keep-alive */
+ struct timer_list ka_timer; /* Keep-alive response timer */
+ u8 ka_num; /* Keep-alive match pattern */
+ signed int ka_retries; /* Keep-alive retry counter, -1 if not yet initialized */
+
/* Configuration */
int adaption; /* 1 or 2 supported */
u8 ftype; /* UI or UIH */
@@ -325,6 +330,7 @@ struct gsm_mux {
unsigned int t3; /* Power wake-up timer in seconds. */
int n2; /* Retry count */
u8 k; /* Window size */
+ u32 keep_alive; /* Control channel keep-alive in 10ms */
/* Statistics (not currently exposed) */
unsigned long bad_fcs;
@@ -540,6 +546,11 @@ static u8 gsm_encode_modem(const struct gsm_dlci *dlci)
modembits |= MDM_IC;
if (dlci->modem_tx & TIOCM_CD || dlci->gsm->initiator)
modembits |= MDM_DV;
+ /* special mappings for passive side to operate as UE */
+ if (dlci->modem_tx & TIOCM_OUT1)
+ modembits |= MDM_IC;
+ if (dlci->modem_tx & TIOCM_OUT2)
+ modembits |= MDM_DV;
return modembits;
}
@@ -1531,6 +1542,7 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
if (brk & 0x01)
tty_insert_flip_char(&dlci->port, 0, TTY_BREAK);
dlci->modem_rx = mlines;
+ wake_up_interruptible(&dlci->gsm->event);
}
/**
@@ -1897,11 +1909,13 @@ static void gsm_control_response(struct gsm_mux *gsm, unsigned int command,
const u8 *data, int clen)
{
struct gsm_control *ctrl;
+ struct gsm_dlci *dlci;
unsigned long flags;
spin_lock_irqsave(&gsm->control_lock, flags);
ctrl = gsm->pending_cmd;
+ dlci = gsm->dlci[0];
command |= 1;
/* Does the reply match our command */
if (ctrl != NULL && (command == ctrl->cmd || command == CMD_NSC)) {
@@ -1916,6 +1930,53 @@ static void gsm_control_response(struct gsm_mux *gsm, unsigned int command,
/* Or did we receive the PN response to our PN command */
} else if (command == CMD_PN) {
gsm_control_negotiation(gsm, 0, data, clen);
+ /* Or did we receive the TEST response to our TEST command */
+ } else if (command == CMD_TEST && clen == 1 && *data == gsm->ka_num) {
+ gsm->ka_retries = -1; /* trigger new keep-alive message */
+ if (dlci && !dlci->dead)
+ mod_timer(&gsm->ka_timer, jiffies + gsm->keep_alive * HZ / 100);
+ }
+ spin_unlock_irqrestore(&gsm->control_lock, flags);
+}
+
+/**
+ * gsm_control_keep_alive - check timeout or start keep-alive
+ * @t: timer contained in our gsm object
+ *
+ * Called off the keep-alive timer expiry signaling that our link
+ * partner is not responding anymore. Link will be closed.
+ * This is also called to startup our timer.
+ */
+
+static void gsm_control_keep_alive(struct timer_list *t)
+{
+ struct gsm_mux *gsm = from_timer(gsm, t, ka_timer);
+ unsigned long flags;
+
+ spin_lock_irqsave(&gsm->control_lock, flags);
+ if (gsm->ka_num && gsm->ka_retries == 0) {
+ /* Keep-alive expired -> close the link */
+ if (debug & DBG_ERRORS)
+ pr_debug("%s keep-alive timed out\n", __func__);
+ spin_unlock_irqrestore(&gsm->control_lock, flags);
+ if (gsm->dlci[0])
+ gsm_dlci_begin_close(gsm->dlci[0]);
+ return;
+ } else if (gsm->keep_alive && gsm->dlci[0] && !gsm->dlci[0]->dead) {
+ if (gsm->ka_retries > 0) {
+ /* T2 expired for keep-alive -> resend */
+ gsm->ka_retries--;
+ } else {
+ /* Start keep-alive timer */
+ gsm->ka_num++;
+ if (!gsm->ka_num)
+ gsm->ka_num++;
+ gsm->ka_retries = (signed int)gsm->n2;
+ }
+ gsm_control_command(gsm, CMD_TEST, &gsm->ka_num,
+ sizeof(gsm->ka_num));
+ mod_timer(&gsm->ka_timer,
+ jiffies + gsm->t2 * HZ / 100);
}
spin_unlock_irqrestore(&gsm->control_lock, flags);
}
@@ -2059,14 +2120,16 @@ static void gsm_dlci_close(struct gsm_dlci *dlci)
tty_port_tty_hangup(&dlci->port, false);
gsm_dlci_clear_queues(dlci->gsm, dlci);
/* Ensure that gsmtty_open() can return. */
- tty_port_set_initialized(&dlci->port, 0);
+ tty_port_set_initialized(&dlci->port, false);
wake_up_interruptible(&dlci->port.open_wait);
- } else
+ } else {
+ del_timer(&dlci->gsm->ka_timer);
dlci->gsm->dead = true;
+ }
/* A DLCI 0 close is a MUX termination so we need to kick that
back to userspace somehow */
gsm_dlci_data_kick(dlci);
- wake_up(&dlci->gsm->event);
+ wake_up_all(&dlci->gsm->event);
}
/**
@@ -2078,6 +2141,8 @@ static void gsm_dlci_close(struct gsm_dlci *dlci)
static void gsm_dlci_open(struct gsm_dlci *dlci)
{
+ struct gsm_mux *gsm = dlci->gsm;
+
/* Note that SABM UA .. SABM UA first UA lost can mean that we go
open -> open */
del_timer(&dlci->t1);
@@ -2087,8 +2152,15 @@ static void gsm_dlci_open(struct gsm_dlci *dlci)
if (debug & DBG_ERRORS)
pr_debug("DLCI %d goes open.\n", dlci->addr);
/* Send current modem state */
- if (dlci->addr)
+ if (dlci->addr) {
gsm_modem_update(dlci, 0);
+ } else {
+ /* Start keep-alive control */
+ gsm->ka_num = 0;
+ gsm->ka_retries = -1;
+ mod_timer(&gsm->ka_timer,
+ jiffies + gsm->keep_alive * HZ / 100);
+ }
gsm_dlci_data_kick(dlci);
wake_up(&dlci->gsm->event);
}
@@ -2267,6 +2339,7 @@ static void gsm_dlci_begin_close(struct gsm_dlci *dlci)
dlci->state = DLCI_CLOSING;
gsm_command(dlci->gsm, dlci->addr, DISC|PF);
mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
+ wake_up_interruptible(&gsm->event);
}
/**
@@ -2840,6 +2913,7 @@ static void gsm_cleanup_mux(struct gsm_mux *gsm, bool disc)
/* Finish outstanding timers, making sure they are done */
del_timer_sync(&gsm->kick_timer);
del_timer_sync(&gsm->t2_timer);
+ del_timer_sync(&gsm->ka_timer);
/* Finish writing to ldisc */
flush_work(&gsm->tx_work);
@@ -2987,6 +3061,7 @@ static struct gsm_mux *gsm_alloc_mux(void)
INIT_LIST_HEAD(&gsm->tx_data_list);
timer_setup(&gsm->kick_timer, gsm_kick_timer, 0);
timer_setup(&gsm->t2_timer, gsm_control_retransmit, 0);
+ timer_setup(&gsm->ka_timer, gsm_control_keep_alive, 0);
INIT_WORK(&gsm->tx_work, gsmld_write_task);
init_waitqueue_head(&gsm->event);
spin_lock_init(&gsm->control_lock);
@@ -3003,6 +3078,7 @@ static struct gsm_mux *gsm_alloc_mux(void)
gsm->mru = 64; /* Default to encoding 1 so these should be 64 */
gsm->mtu = 64;
gsm->dead = true; /* Avoid early tty opens */
+ gsm->keep_alive = 0; /* Disabled */
/* Store the instance to the mux array or abort if no space is
* available.
@@ -3138,6 +3214,29 @@ static int gsm_config(struct gsm_mux *gsm, struct gsm_config *c)
return 0;
}
+static void gsm_copy_config_ext_values(struct gsm_mux *gsm,
+ struct gsm_config_ext *ce)
+{
+ memset(ce, 0, sizeof(*ce));
+ ce->keep_alive = gsm->keep_alive;
+}
+
+static int gsm_config_ext(struct gsm_mux *gsm, struct gsm_config_ext *ce)
+{
+ unsigned int i;
+
+ /*
+ * Check that userspace doesn't put stuff in here to prevent breakages
+ * in the future.
+ */
+ for (i = 0; i < ARRAY_SIZE(ce->reserved); i++)
+ if (ce->reserved[i])
+ return -EINVAL;
+
+ gsm->keep_alive = ce->keep_alive;
+ return 0;
+}
+
/**
* gsmld_output - write to link
* @gsm: our mux
@@ -3456,6 +3555,7 @@ static int gsmld_ioctl(struct tty_struct *tty, unsigned int cmd,
unsigned long arg)
{
struct gsm_config c;
+ struct gsm_config_ext ce;
struct gsm_mux *gsm = tty->disc_data;
unsigned int base;
@@ -3472,6 +3572,15 @@ static int gsmld_ioctl(struct tty_struct *tty, unsigned int cmd,
case GSMIOC_GETFIRST:
base = mux_num_to_base(gsm);
return put_user(base + 1, (__u32 __user *)arg);
+ case GSMIOC_GETCONF_EXT:
+ gsm_copy_config_ext_values(gsm, &ce);
+ if (copy_to_user((void __user *)arg, &ce, sizeof(ce)))
+ return -EFAULT;
+ return 0;
+ case GSMIOC_SETCONF_EXT:
+ if (copy_from_user(&ce, (void __user *)arg, sizeof(ce)))
+ return -EFAULT;
+ return gsm_config_ext(gsm, &ce);
default:
return n_tty_ioctl_helper(tty, cmd, arg);
}
@@ -3770,16 +3879,43 @@ static int gsm_modem_update(struct gsm_dlci *dlci, u8 brk)
return -EPROTONOSUPPORT;
}
-static int gsm_carrier_raised(struct tty_port *port)
+/**
+ * gsm_wait_modem_change - wait for modem status line change
+ * @dlci: channel
+ * @mask: modem status line bits
+ *
+ * The function returns if:
+ * - any given modem status line bit changed
+ * - the wait event function got interrupted (e.g. by a signal)
+ * - the underlying DLCI was closed
+ * - the underlying ldisc device was removed
+ */
+static int gsm_wait_modem_change(struct gsm_dlci *dlci, u32 mask)
+{
+ struct gsm_mux *gsm = dlci->gsm;
+ u32 old = dlci->modem_rx;
+ int ret;
+
+ ret = wait_event_interruptible(gsm->event, gsm->dead ||
+ dlci->state != DLCI_OPEN ||
+ (old ^ dlci->modem_rx) & mask);
+ if (gsm->dead)
+ return -ENODEV;
+ if (dlci->state != DLCI_OPEN)
+ return -EL2NSYNC;
+ return ret;
+}
+
+static bool gsm_carrier_raised(struct tty_port *port)
{
struct gsm_dlci *dlci = container_of(port, struct gsm_dlci, port);
struct gsm_mux *gsm = dlci->gsm;
/* Not yet open so no carrier info */
if (dlci->state != DLCI_OPEN)
- return 0;
+ return false;
if (debug & DBG_CD_ON)
- return 1;
+ return true;
/*
* Basic mode with control channel in ADM mode may not respond
@@ -3787,16 +3923,16 @@ static int gsm_carrier_raised(struct tty_port *port)
*/
if (gsm->encoding == GSM_BASIC_OPT &&
gsm->dlci[0]->mode == DLCI_MODE_ADM && !dlci->modem_rx)
- return 1;
+ return true;
return dlci->modem_rx & TIOCM_CD;
}
-static void gsm_dtr_rts(struct tty_port *port, int onoff)
+static void gsm_dtr_rts(struct tty_port *port, bool active)
{
struct gsm_dlci *dlci = container_of(port, struct gsm_dlci, port);
unsigned int modem_tx = dlci->modem_tx;
- if (onoff)
+ if (active)
modem_tx |= TIOCM_DTR | TIOCM_RTS;
else
modem_tx &= ~(TIOCM_DTR | TIOCM_RTS);
@@ -3880,7 +4016,7 @@ static int gsmtty_open(struct tty_struct *tty, struct file *filp)
dlci->modem_rx = 0;
/* We could in theory open and close before we wait - eg if we get
a DM straight back. This is ok as that will have caused a hangup */
- tty_port_set_initialized(port, 1);
+ tty_port_set_initialized(port, true);
/* Start sending off SABM messages */
if (gsm->initiator)
gsm_dlci_begin_open(dlci);
@@ -4029,6 +4165,8 @@ static int gsmtty_ioctl(struct tty_struct *tty,
gsm_destroy_network(dlci);
mutex_unlock(&dlci->mutex);
return 0;
+ case TIOCMIWAIT:
+ return gsm_wait_modem_change(dlci, (u32)arg);
default:
return -ENOIOCTLCMD;
}
diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c
index 0180e1e4e75d..aa80de3a8194 100644
--- a/drivers/tty/serdev/core.c
+++ b/drivers/tty/serdev/core.c
@@ -42,7 +42,7 @@ static struct attribute *serdev_device_attrs[] = {
};
ATTRIBUTE_GROUPS(serdev_device);
-static int serdev_device_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int serdev_device_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
int rc;
diff --git a/drivers/tty/serial/8250/8250_dfl.c b/drivers/tty/serial/8250/8250_dfl.c
new file mode 100644
index 000000000000..6c5ff019df4b
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_dfl.c
@@ -0,0 +1,167 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for FPGA UART
+ *
+ * Copyright (C) 2022 Intel Corporation.
+ *
+ * Authors:
+ * Ananda Ravuri <ananda.ravuri@intel.com>
+ * Matthew Gerlach <matthew.gerlach@linux.intel.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/device.h>
+#include <linux/dfl.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/types.h>
+
+#include <linux/serial.h>
+#include <linux/serial_8250.h>
+
+#define DFHv1_PARAM_ID_CLK_FRQ 0x2
+#define DFHv1_PARAM_ID_FIFO_LEN 0x3
+
+#define DFHv1_PARAM_ID_REG_LAYOUT 0x4
+#define DFHv1_PARAM_REG_LAYOUT_WIDTH GENMASK_ULL(63, 32)
+#define DFHv1_PARAM_REG_LAYOUT_SHIFT GENMASK_ULL(31, 0)
+
+struct dfl_uart {
+ int line;
+};
+
+static int dfh_get_u64_param_val(struct dfl_device *dfl_dev, int param_id, u64 *pval)
+{
+ size_t psize;
+ u64 *p;
+
+ p = dfh_find_param(dfl_dev, param_id, &psize);
+ if (IS_ERR(p))
+ return PTR_ERR(p);
+
+ if (psize != sizeof(*pval))
+ return -EINVAL;
+
+ *pval = *p;
+
+ return 0;
+}
+
+static int dfl_uart_get_params(struct dfl_device *dfl_dev, struct uart_8250_port *uart)
+{
+ struct device *dev = &dfl_dev->dev;
+ u64 fifo_len, clk_freq, reg_layout;
+ u32 reg_width;
+ int ret;
+
+ ret = dfh_get_u64_param_val(dfl_dev, DFHv1_PARAM_ID_CLK_FRQ, &clk_freq);
+ if (ret)
+ return dev_err_probe(dev, ret, "missing CLK_FRQ param\n");
+
+ uart->port.uartclk = clk_freq;
+
+ ret = dfh_get_u64_param_val(dfl_dev, DFHv1_PARAM_ID_FIFO_LEN, &fifo_len);
+ if (ret)
+ return dev_err_probe(dev, ret, "missing FIFO_LEN param\n");
+
+ switch (fifo_len) {
+ case 32:
+ uart->port.type = PORT_ALTR_16550_F32;
+ break;
+
+ case 64:
+ uart->port.type = PORT_ALTR_16550_F64;
+ break;
+
+ case 128:
+ uart->port.type = PORT_ALTR_16550_F128;
+ break;
+
+ default:
+ return dev_err_probe(dev, -EINVAL, "unsupported FIFO_LEN %llu\n", fifo_len);
+ }
+
+ ret = dfh_get_u64_param_val(dfl_dev, DFHv1_PARAM_ID_REG_LAYOUT, &reg_layout);
+ if (ret)
+ return dev_err_probe(dev, ret, "missing REG_LAYOUT param\n");
+
+ uart->port.regshift = FIELD_GET(DFHv1_PARAM_REG_LAYOUT_SHIFT, reg_layout);
+ reg_width = FIELD_GET(DFHv1_PARAM_REG_LAYOUT_WIDTH, reg_layout);
+ switch (reg_width) {
+ case 4:
+ uart->port.iotype = UPIO_MEM32;
+ break;
+
+ case 2:
+ uart->port.iotype = UPIO_MEM16;
+ break;
+
+ default:
+ return dev_err_probe(dev, -EINVAL, "unsupported reg-width %u\n", reg_width);
+
+ }
+
+ return 0;
+}
+
+static int dfl_uart_probe(struct dfl_device *dfl_dev)
+{
+ struct device *dev = &dfl_dev->dev;
+ struct uart_8250_port uart = { };
+ struct dfl_uart *dfluart;
+ int ret;
+
+ uart.port.flags = UPF_IOREMAP;
+ uart.port.mapbase = dfl_dev->mmio_res.start;
+ uart.port.mapsize = resource_size(&dfl_dev->mmio_res);
+
+ ret = dfl_uart_get_params(dfl_dev, &uart);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed uart feature walk\n");
+
+ if (dfl_dev->num_irqs == 1)
+ uart.port.irq = dfl_dev->irqs[0];
+
+ dfluart = devm_kzalloc(dev, sizeof(*dfluart), GFP_KERNEL);
+ if (!dfluart)
+ return -ENOMEM;
+
+ dfluart->line = serial8250_register_8250_port(&uart);
+ if (dfluart->line < 0)
+ return dev_err_probe(dev, dfluart->line, "unable to register 8250 port.\n");
+
+ dev_set_drvdata(dev, dfluart);
+
+ return 0;
+}
+
+static void dfl_uart_remove(struct dfl_device *dfl_dev)
+{
+ struct dfl_uart *dfluart = dev_get_drvdata(&dfl_dev->dev);
+
+ serial8250_unregister_port(dfluart->line);
+}
+
+#define FME_FEATURE_ID_UART 0x24
+
+static const struct dfl_device_id dfl_uart_ids[] = {
+ { FME_ID, FME_FEATURE_ID_UART },
+ { }
+};
+MODULE_DEVICE_TABLE(dfl, dfl_uart_ids);
+
+static struct dfl_driver dfl_uart_driver = {
+ .drv = {
+ .name = "dfl-uart",
+ },
+ .id_table = dfl_uart_ids,
+ .probe = dfl_uart_probe,
+ .remove = dfl_uart_remove,
+};
+module_dfl_driver(dfl_uart_driver);
+
+MODULE_DESCRIPTION("DFL Intel UART driver");
+MODULE_AUTHOR("Intel Corporation");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c
index f271becfc46c..0ebde0ab8167 100644
--- a/drivers/tty/serial/8250/8250_early.c
+++ b/drivers/tty/serial/8250/8250_early.c
@@ -136,11 +136,11 @@ static void __init init_port(struct earlycon_device *device)
unsigned char c;
unsigned int ier;
- serial8250_early_out(port, UART_LCR, 0x3); /* 8n1 */
+ serial8250_early_out(port, UART_LCR, UART_LCR_WLEN8); /* 8n1 */
ier = serial8250_early_in(port, UART_IER);
serial8250_early_out(port, UART_IER, ier & UART_IER_UUE); /* no interrupt */
serial8250_early_out(port, UART_FCR, 0); /* no fifo */
- serial8250_early_out(port, UART_MCR, 0x3); /* DTR + RTS */
+ serial8250_early_out(port, UART_MCR, UART_MCR_DTR | UART_MCR_RTS);
if (port->uartclk) {
divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * device->baud);
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index 8e9f247590bd..c55be6fda0ca 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -24,6 +24,7 @@
#include <asm/io.h>
#include "8250.h"
+#include "8250_pcilib.h"
/*
* init function returns:
@@ -89,28 +90,7 @@ static int
setup_port(struct serial_private *priv, struct uart_8250_port *port,
u8 bar, unsigned int offset, int regshift)
{
- struct pci_dev *dev = priv->dev;
-
- if (bar >= PCI_STD_NUM_BARS)
- return -EINVAL;
-
- if (pci_resource_flags(dev, bar) & IORESOURCE_MEM) {
- if (!pcim_iomap(dev, bar, 0) && !pcim_iomap_table(dev))
- return -ENOMEM;
-
- port->port.iotype = UPIO_MEM;
- port->port.iobase = 0;
- port->port.mapbase = pci_resource_start(dev, bar) + offset;
- port->port.membase = pcim_iomap_table(dev)[bar] + offset;
- port->port.regshift = regshift;
- } else {
- port->port.iotype = UPIO_PORT;
- port->port.iobase = pci_resource_start(dev, bar) + offset;
- port->port.mapbase = 0;
- port->port.membase = NULL;
- port->port.regshift = 0;
- }
- return 0;
+ return serial8250_pci_setup_port(priv->dev, port, bar, offset, regshift);
}
/*
@@ -5757,3 +5737,4 @@ module_pci_driver(serial_pci_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Generic 8250/16x50 PCI serial probe module");
MODULE_DEVICE_TABLE(pci, serial_pci_tbl);
+MODULE_IMPORT_NS(SERIAL_8250_PCI);
diff --git a/drivers/tty/serial/8250/8250_pci1xxxx.c b/drivers/tty/serial/8250/8250_pci1xxxx.c
new file mode 100644
index 000000000000..a3b25779d921
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_pci1xxxx.c
@@ -0,0 +1,494 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Probe module for 8250/16550-type MCHP PCI serial ports.
+ *
+ * Based on drivers/tty/serial/8250/8250_pci.c,
+ *
+ * Copyright (C) 2022 Microchip Technology Inc., All Rights Reserved.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/serial_core.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/units.h>
+#include <linux/tty.h>
+
+#include <asm/byteorder.h>
+
+#include "8250.h"
+#include "8250_pcilib.h"
+
+#define PCI_DEVICE_ID_EFAR_PCI12000 0xa002
+#define PCI_DEVICE_ID_EFAR_PCI11010 0xa012
+#define PCI_DEVICE_ID_EFAR_PCI11101 0xa022
+#define PCI_DEVICE_ID_EFAR_PCI11400 0xa032
+#define PCI_DEVICE_ID_EFAR_PCI11414 0xa042
+
+#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_4p 0x0001
+#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p012 0x0002
+#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p013 0x0003
+#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p023 0x0004
+#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p123 0x0005
+#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p01 0x0006
+#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p02 0x0007
+#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p03 0x0008
+#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p12 0x0009
+#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p13 0x000a
+#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p23 0x000b
+#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p0 0x000c
+#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p1 0x000d
+#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p2 0x000e
+#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p3 0x000f
+
+#define PCI_SUBDEVICE_ID_EFAR_PCI12000 PCI_DEVICE_ID_EFAR_PCI12000
+#define PCI_SUBDEVICE_ID_EFAR_PCI11010 PCI_DEVICE_ID_EFAR_PCI11010
+#define PCI_SUBDEVICE_ID_EFAR_PCI11101 PCI_DEVICE_ID_EFAR_PCI11101
+#define PCI_SUBDEVICE_ID_EFAR_PCI11400 PCI_DEVICE_ID_EFAR_PCI11400
+#define PCI_SUBDEVICE_ID_EFAR_PCI11414 PCI_DEVICE_ID_EFAR_PCI11414
+
+#define UART_ACTV_REG 0x11
+#define UART_BLOCK_SET_ACTIVE BIT(0)
+
+#define UART_PCI_CTRL_REG 0x80
+#define UART_PCI_CTRL_SET_MULTIPLE_MSI BIT(4)
+#define UART_PCI_CTRL_D3_CLK_ENABLE BIT(0)
+
+#define ADCL_CFG_REG 0x40
+#define ADCL_CFG_POL_SEL BIT(2)
+#define ADCL_CFG_PIN_SEL BIT(1)
+#define ADCL_CFG_EN BIT(0)
+
+#define UART_BIT_SAMPLE_CNT 16
+#define BAUD_CLOCK_DIV_INT_MSK GENMASK(31, 8)
+#define ADCL_CFG_RTS_DELAY_MASK GENMASK(11, 8)
+#define UART_CLOCK_DEFAULT (62500 * HZ_PER_KHZ)
+
+#define UART_WAKE_REG 0x8C
+#define UART_WAKE_MASK_REG 0x90
+#define UART_WAKE_N_PIN BIT(2)
+#define UART_WAKE_NCTS BIT(1)
+#define UART_WAKE_INT BIT(0)
+#define UART_WAKE_SRCS \
+ (UART_WAKE_N_PIN | UART_WAKE_NCTS | UART_WAKE_INT)
+
+#define UART_BAUD_CLK_DIVISOR_REG 0x54
+
+#define UART_RESET_REG 0x94
+#define UART_RESET_D3_RESET_DISABLE BIT(16)
+
+#define MAX_PORTS 4
+#define PORT_OFFSET 0x100
+
+static const int logical_to_physical_port_idx[][MAX_PORTS] = {
+ {0, 1, 2, 3}, /* PCI12000, PCI11010, PCI11101, PCI11400, PCI11414 */
+ {0, 1, 2, 3}, /* PCI4p */
+ {0, 1, 2, -1}, /* PCI3p012 */
+ {0, 1, 3, -1}, /* PCI3p013 */
+ {0, 2, 3, -1}, /* PCI3p023 */
+ {1, 2, 3, -1}, /* PCI3p123 */
+ {0, 1, -1, -1}, /* PCI2p01 */
+ {0, 2, -1, -1}, /* PCI2p02 */
+ {0, 3, -1, -1}, /* PCI2p03 */
+ {1, 2, -1, -1}, /* PCI2p12 */
+ {1, 3, -1, -1}, /* PCI2p13 */
+ {2, 3, -1, -1}, /* PCI2p23 */
+ {0, -1, -1, -1}, /* PCI1p0 */
+ {1, -1, -1, -1}, /* PCI1p1 */
+ {2, -1, -1, -1}, /* PCI1p2 */
+ {3, -1, -1, -1}, /* PCI1p3 */
+};
+
+struct pci1xxxx_8250 {
+ unsigned int nr;
+ void __iomem *membase;
+ int line[];
+};
+
+static int pci1xxxx_get_num_ports(struct pci_dev *dev)
+{
+ switch (dev->subsystem_device) {
+ case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p0:
+ case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p1:
+ case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p2:
+ case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p3:
+ case PCI_SUBDEVICE_ID_EFAR_PCI12000:
+ case PCI_SUBDEVICE_ID_EFAR_PCI11010:
+ case PCI_SUBDEVICE_ID_EFAR_PCI11101:
+ case PCI_SUBDEVICE_ID_EFAR_PCI11400:
+ default:
+ return 1;
+ case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p01:
+ case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p02:
+ case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p03:
+ case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p12:
+ case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p13:
+ case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p23:
+ return 2;
+ case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p012:
+ case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p123:
+ case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p013:
+ case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p023:
+ return 3;
+ case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_4p:
+ case PCI_SUBDEVICE_ID_EFAR_PCI11414:
+ return 4;
+ }
+}
+
+static unsigned int pci1xxxx_get_divisor(struct uart_port *port,
+ unsigned int baud, unsigned int *frac)
+{
+ unsigned int quot;
+
+ /*
+ * Calculate baud rate sampling period in nanoseconds.
+ * Fractional part x denotes x/255 parts of a nanosecond.
+ */
+ quot = NSEC_PER_SEC / (baud * UART_BIT_SAMPLE_CNT);
+ *frac = (NSEC_PER_SEC - quot * baud * UART_BIT_SAMPLE_CNT) *
+ 255 / UART_BIT_SAMPLE_CNT / baud;
+
+ return quot;
+}
+
+static void pci1xxxx_set_divisor(struct uart_port *port, unsigned int baud,
+ unsigned int quot, unsigned int frac)
+{
+ writel(FIELD_PREP(BAUD_CLOCK_DIV_INT_MSK, quot) | frac,
+ port->membase + UART_BAUD_CLK_DIVISOR_REG);
+}
+
+static int pci1xxxx_rs485_config(struct uart_port *port,
+ struct ktermios *termios,
+ struct serial_rs485 *rs485)
+{
+ u32 delay_in_baud_periods;
+ u32 baud_period_in_ns;
+ u32 mode_cfg = 0;
+ u32 clock_div;
+
+ /*
+ * pci1xxxx's uart hardware supports only RTS delay after
+ * Tx and in units of bit times to a maximum of 15
+ */
+ if (rs485->flags & SER_RS485_ENABLED) {
+ mode_cfg = ADCL_CFG_EN | ADCL_CFG_PIN_SEL;
+
+ if (!(rs485->flags & SER_RS485_RTS_ON_SEND))
+ mode_cfg |= ADCL_CFG_POL_SEL;
+
+ if (rs485->delay_rts_after_send) {
+ clock_div = readl(port->membase + UART_BAUD_CLK_DIVISOR_REG);
+ baud_period_in_ns =
+ FIELD_GET(BAUD_CLOCK_DIV_INT_MSK, clock_div) *
+ UART_BIT_SAMPLE_CNT;
+ delay_in_baud_periods =
+ rs485->delay_rts_after_send * NSEC_PER_MSEC /
+ baud_period_in_ns;
+ delay_in_baud_periods =
+ min_t(u32, delay_in_baud_periods,
+ FIELD_MAX(ADCL_CFG_RTS_DELAY_MASK));
+ mode_cfg |= FIELD_PREP(ADCL_CFG_RTS_DELAY_MASK,
+ delay_in_baud_periods);
+ rs485->delay_rts_after_send =
+ baud_period_in_ns * delay_in_baud_periods /
+ NSEC_PER_MSEC;
+ }
+ }
+ writel(mode_cfg, port->membase + ADCL_CFG_REG);
+ return 0;
+}
+
+static const struct serial_rs485 pci1xxxx_rs485_supported = {
+ .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND |
+ SER_RS485_RTS_AFTER_SEND,
+ .delay_rts_after_send = 1,
+ /* Delay RTS before send is not supported */
+};
+
+static bool pci1xxxx_port_suspend(int line)
+{
+ struct uart_8250_port *up = serial8250_get_port(line);
+ struct uart_port *port = &up->port;
+ struct tty_port *tport = &port->state->port;
+ unsigned long flags;
+ bool ret = false;
+ u8 wakeup_mask;
+
+ mutex_lock(&tport->mutex);
+ if (port->suspended == 0 && port->dev) {
+ wakeup_mask = readb(up->port.membase + UART_WAKE_MASK_REG);
+
+ spin_lock_irqsave(&port->lock, flags);
+ port->mctrl &= ~TIOCM_OUT2;
+ port->ops->set_mctrl(port, port->mctrl);
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ ret = (wakeup_mask & UART_WAKE_SRCS) != UART_WAKE_SRCS;
+ }
+
+ writeb(UART_WAKE_SRCS, port->membase + UART_WAKE_REG);
+ mutex_unlock(&tport->mutex);
+
+ return ret;
+}
+
+static void pci1xxxx_port_resume(int line)
+{
+ struct uart_8250_port *up = serial8250_get_port(line);
+ struct uart_port *port = &up->port;
+ struct tty_port *tport = &port->state->port;
+ unsigned long flags;
+
+ mutex_lock(&tport->mutex);
+ writeb(UART_BLOCK_SET_ACTIVE, port->membase + UART_ACTV_REG);
+ writeb(UART_WAKE_SRCS, port->membase + UART_WAKE_REG);
+
+ if (port->suspended == 0) {
+ spin_lock_irqsave(&port->lock, flags);
+ port->mctrl |= TIOCM_OUT2;
+ port->ops->set_mctrl(port, port->mctrl);
+ spin_unlock_irqrestore(&port->lock, flags);
+ }
+ mutex_unlock(&tport->mutex);
+}
+
+static int pci1xxxx_suspend(struct device *dev)
+{
+ struct pci1xxxx_8250 *priv = dev_get_drvdata(dev);
+ struct pci_dev *pcidev = to_pci_dev(dev);
+ bool wakeup = false;
+ unsigned int data;
+ void __iomem *p;
+ int i;
+
+ for (i = 0; i < priv->nr; i++) {
+ if (priv->line[i] >= 0) {
+ serial8250_suspend_port(priv->line[i]);
+ wakeup |= pci1xxxx_port_suspend(priv->line[i]);
+ }
+ }
+
+ p = pci_ioremap_bar(pcidev, 0);
+ if (!p) {
+ dev_err(dev, "remapping of bar 0 memory failed");
+ return -ENOMEM;
+ }
+
+ data = readl(p + UART_RESET_REG);
+ writel(data | UART_RESET_D3_RESET_DISABLE, p + UART_RESET_REG);
+
+ if (wakeup)
+ writeb(UART_PCI_CTRL_D3_CLK_ENABLE, p + UART_PCI_CTRL_REG);
+
+ iounmap(p);
+ device_set_wakeup_enable(dev, true);
+ pci_wake_from_d3(pcidev, true);
+
+ return 0;
+}
+
+static int pci1xxxx_resume(struct device *dev)
+{
+ struct pci1xxxx_8250 *priv = dev_get_drvdata(dev);
+ struct pci_dev *pcidev = to_pci_dev(dev);
+ unsigned int data;
+ void __iomem *p;
+ int i;
+
+ p = pci_ioremap_bar(pcidev, 0);
+ if (!p) {
+ dev_err(dev, "remapping of bar 0 memory failed");
+ return -ENOMEM;
+ }
+
+ data = readl(p + UART_RESET_REG);
+ writel(data & ~UART_RESET_D3_RESET_DISABLE, p + UART_RESET_REG);
+ iounmap(p);
+
+ for (i = 0; i < priv->nr; i++) {
+ if (priv->line[i] >= 0) {
+ pci1xxxx_port_resume(priv->line[i]);
+ serial8250_resume_port(priv->line[i]);
+ }
+ }
+
+ return 0;
+}
+
+static int pci1xxxx_setup(struct pci_dev *pdev,
+ struct uart_8250_port *port, int port_idx)
+{
+ int ret;
+
+ port->port.flags |= UPF_FIXED_TYPE | UPF_SKIP_TEST;
+ port->port.type = PORT_MCHP16550A;
+ port->port.set_termios = serial8250_do_set_termios;
+ port->port.get_divisor = pci1xxxx_get_divisor;
+ port->port.set_divisor = pci1xxxx_set_divisor;
+ port->port.rs485_config = pci1xxxx_rs485_config;
+ port->port.rs485_supported = pci1xxxx_rs485_supported;
+
+ ret = serial8250_pci_setup_port(pdev, port, 0, PORT_OFFSET * port_idx, 0);
+ if (ret < 0)
+ return ret;
+
+ writeb(UART_BLOCK_SET_ACTIVE, port->port.membase + UART_ACTV_REG);
+ writeb(UART_WAKE_SRCS, port->port.membase + UART_WAKE_REG);
+ writeb(UART_WAKE_N_PIN, port->port.membase + UART_WAKE_MASK_REG);
+
+ return 0;
+}
+
+static unsigned int pci1xxxx_get_max_port(int subsys_dev)
+{
+ unsigned int i = MAX_PORTS;
+
+ if (subsys_dev < ARRAY_SIZE(logical_to_physical_port_idx))
+ while (i--) {
+ if (logical_to_physical_port_idx[subsys_dev][i] != -1)
+ return logical_to_physical_port_idx[subsys_dev][i] + 1;
+ }
+
+ if (subsys_dev == PCI_SUBDEVICE_ID_EFAR_PCI11414)
+ return 4;
+
+ return 1;
+}
+
+static int pci1xxxx_logical_to_physical_port_translate(int subsys_dev, int port)
+{
+ if (subsys_dev < ARRAY_SIZE(logical_to_physical_port_idx))
+ return logical_to_physical_port_idx[subsys_dev][port];
+
+ return logical_to_physical_port_idx[0][port];
+}
+
+static int pci1xxxx_serial_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct device *dev = &pdev->dev;
+ struct pci1xxxx_8250 *priv;
+ struct uart_8250_port uart;
+ unsigned int max_vec_reqd;
+ unsigned int nr_ports, i;
+ int num_vectors;
+ int subsys_dev;
+ int port_idx;
+ int rc;
+
+ rc = pcim_enable_device(pdev);
+ if (rc)
+ return rc;
+
+ nr_ports = pci1xxxx_get_num_ports(pdev);
+
+ priv = devm_kzalloc(dev, struct_size(priv, line, nr_ports), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->membase = pci_ioremap_bar(pdev, 0);
+ if (!priv->membase)
+ return -ENOMEM;
+
+ pci_set_master(pdev);
+
+ priv->nr = nr_ports;
+
+ subsys_dev = pdev->subsystem_device;
+ max_vec_reqd = pci1xxxx_get_max_port(subsys_dev);
+
+ num_vectors = pci_alloc_irq_vectors(pdev, 1, max_vec_reqd, PCI_IRQ_ALL_TYPES);
+ if (num_vectors < 0) {
+ pci_iounmap(pdev, priv->membase);
+ return num_vectors;
+ }
+
+ memset(&uart, 0, sizeof(uart));
+ uart.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT;
+ uart.port.uartclk = UART_CLOCK_DEFAULT;
+ uart.port.dev = dev;
+
+ if (num_vectors == max_vec_reqd)
+ writeb(UART_PCI_CTRL_SET_MULTIPLE_MSI, priv->membase + UART_PCI_CTRL_REG);
+
+ for (i = 0; i < nr_ports; i++) {
+ priv->line[i] = -ENODEV;
+
+ port_idx = pci1xxxx_logical_to_physical_port_translate(subsys_dev, i);
+
+ if (num_vectors == max_vec_reqd)
+ uart.port.irq = pci_irq_vector(pdev, port_idx);
+ else
+ uart.port.irq = pci_irq_vector(pdev, 0);
+
+ rc = pci1xxxx_setup(pdev, &uart, port_idx);
+ if (rc) {
+ dev_warn(dev, "Failed to setup port %u\n", i);
+ continue;
+ }
+
+ priv->line[i] = serial8250_register_8250_port(&uart);
+ if (priv->line[i] < 0) {
+ dev_warn(dev,
+ "Couldn't register serial port %lx, irq %d, type %d, error %d\n",
+ uart.port.iobase, uart.port.irq, uart.port.iotype,
+ priv->line[i]);
+ }
+ }
+
+ pci_set_drvdata(pdev, priv);
+
+ return 0;
+}
+
+static void pci1xxxx_serial_remove(struct pci_dev *dev)
+{
+ struct pci1xxxx_8250 *priv = pci_get_drvdata(dev);
+ unsigned int i;
+
+ for (i = 0; i < priv->nr; i++) {
+ if (priv->line[i] >= 0)
+ serial8250_unregister_port(priv->line[i]);
+ }
+
+ pci_free_irq_vectors(dev);
+ pci_iounmap(dev, priv->membase);
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(pci1xxxx_pm_ops, pci1xxxx_suspend, pci1xxxx_resume);
+
+static const struct pci_device_id pci1xxxx_pci_tbl[] = {
+ { PCI_VDEVICE(EFAR, PCI_DEVICE_ID_EFAR_PCI11010) },
+ { PCI_VDEVICE(EFAR, PCI_DEVICE_ID_EFAR_PCI11101) },
+ { PCI_VDEVICE(EFAR, PCI_DEVICE_ID_EFAR_PCI11400) },
+ { PCI_VDEVICE(EFAR, PCI_DEVICE_ID_EFAR_PCI11414) },
+ { PCI_VDEVICE(EFAR, PCI_DEVICE_ID_EFAR_PCI12000) },
+ {}
+};
+MODULE_DEVICE_TABLE(pci, pci1xxxx_pci_tbl);
+
+static struct pci_driver pci1xxxx_pci_driver = {
+ .name = "pci1xxxx serial",
+ .probe = pci1xxxx_serial_probe,
+ .remove = pci1xxxx_serial_remove,
+ .driver = {
+ .pm = pm_sleep_ptr(&pci1xxxx_pm_ops),
+ },
+ .id_table = pci1xxxx_pci_tbl,
+};
+module_pci_driver(pci1xxxx_pci_driver);
+
+static_assert((ARRAY_SIZE(logical_to_physical_port_idx) == PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p3 + 1));
+
+MODULE_IMPORT_NS(SERIAL_8250_PCI);
+MODULE_DESCRIPTION("Microchip Technology Inc. PCIe to UART module");
+MODULE_AUTHOR("Kumaravel Thiagarajan <kumaravel.thiagarajan@microchip.com>");
+MODULE_AUTHOR("Tharun Kumar P <tharunkumar.pasumarthi@microchip.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250/8250_pcilib.c b/drivers/tty/serial/8250/8250_pcilib.c
new file mode 100644
index 000000000000..d234e9194feb
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_pcilib.c
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * 8250 PCI library.
+ *
+ * Copyright (C) 2001 Russell King, All Rights Reserved.
+ */
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+
+#include "8250.h"
+#include "8250_pcilib.h"
+
+int serial8250_pci_setup_port(struct pci_dev *dev, struct uart_8250_port *port,
+ u8 bar, unsigned int offset, int regshift)
+{
+ if (bar >= PCI_STD_NUM_BARS)
+ return -EINVAL;
+
+ if (pci_resource_flags(dev, bar) & IORESOURCE_MEM) {
+ if (!pcim_iomap(dev, bar, 0) && !pcim_iomap_table(dev))
+ return -ENOMEM;
+
+ port->port.iotype = UPIO_MEM;
+ port->port.iobase = 0;
+ port->port.mapbase = pci_resource_start(dev, bar) + offset;
+ port->port.membase = pcim_iomap_table(dev)[bar] + offset;
+ port->port.regshift = regshift;
+ } else {
+ port->port.iotype = UPIO_PORT;
+ port->port.iobase = pci_resource_start(dev, bar) + offset;
+ port->port.mapbase = 0;
+ port->port.membase = NULL;
+ port->port.regshift = 0;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(serial8250_pci_setup_port, SERIAL_8250_PCI);
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250/8250_pcilib.h b/drivers/tty/serial/8250/8250_pcilib.h
new file mode 100644
index 000000000000..1aaf1b50ce9c
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_pcilib.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * 8250 PCI library header file.
+ *
+ * Copyright (C) 2001 Russell King, All Rights Reserved.
+ */
+
+#include <linux/types.h>
+
+struct pci_dev;
+
+struct uart_8250_port;
+
+int serial8250_pci_setup_port(struct pci_dev *dev, struct uart_8250_port *port, u8 bar,
+ unsigned int offset, int regshift);
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index beba8f38b3dc..fa43df05342b 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -313,6 +313,14 @@ static const struct serial8250_config uart_config[] = {
.rxtrig_bytes = {1, 4, 8, 14},
.flags = UART_CAP_FIFO,
},
+ [PORT_MCHP16550A] = {
+ .name = "MCHP16550A",
+ .fifo_size = 256,
+ .tx_loadsz = 256,
+ .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01,
+ .rxtrig_bytes = {2, 66, 130, 194},
+ .flags = UART_CAP_FIFO,
+ },
};
/* Uart divisor latch read */
@@ -1050,11 +1058,12 @@ static void autoconfig_16550a(struct uart_8250_port *up)
serial_out(up, UART_LCR, 0);
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
UART_FCR7_64BYTE);
- status1 = serial_in(up, UART_IIR) >> 5;
+ status1 = serial_in(up, UART_IIR) & (UART_IIR_64BYTE_FIFO |
+ UART_IIR_FIFO_ENABLED);
serial_out(up, UART_FCR, 0);
serial_out(up, UART_LCR, 0);
- if (status1 == 7)
+ if (status1 == (UART_IIR_64BYTE_FIFO | UART_IIR_FIFO_ENABLED))
up->port.type = PORT_16550A_FSL64;
else
DEBUG_AUTOCONF("Motorola 8xxx DUART ");
@@ -1122,17 +1131,20 @@ static void autoconfig_16550a(struct uart_8250_port *up)
*/
serial_out(up, UART_LCR, 0);
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
- status1 = serial_in(up, UART_IIR) >> 5;
+ status1 = serial_in(up, UART_IIR) & (UART_IIR_64BYTE_FIFO | UART_IIR_FIFO_ENABLED);
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
- status2 = serial_in(up, UART_IIR) >> 5;
+ status2 = serial_in(up, UART_IIR) & (UART_IIR_64BYTE_FIFO | UART_IIR_FIFO_ENABLED);
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+
serial_out(up, UART_LCR, 0);
DEBUG_AUTOCONF("iir1=%d iir2=%d ", status1, status2);
- if (status1 == 6 && status2 == 7) {
+ if (status1 == UART_IIR_FIFO_ENABLED_16550A &&
+ status2 == (UART_IIR_64BYTE_FIFO | UART_IIR_FIFO_ENABLED_16550A)) {
up->port.type = PORT_16750;
up->capabilities |= UART_CAP_AFE | UART_CAP_SLEEP;
return;
@@ -1236,14 +1248,14 @@ static void autoconfig(struct uart_8250_port *up)
* Mask out IER[7:4] bits for test as some UARTs (e.g. TL
* 16C754B) allow only to modify them if an EFR bit is set.
*/
- scratch2 = serial_in(up, UART_IER) & 0x0f;
- serial_out(up, UART_IER, 0x0F);
+ scratch2 = serial_in(up, UART_IER) & UART_IER_ALL_INTR;
+ serial_out(up, UART_IER, UART_IER_ALL_INTR);
#ifdef __i386__
outb(0, 0x080);
#endif
- scratch3 = serial_in(up, UART_IER) & 0x0f;
+ scratch3 = serial_in(up, UART_IER) & UART_IER_ALL_INTR;
serial_out(up, UART_IER, scratch);
- if (scratch2 != 0 || scratch3 != 0x0F) {
+ if (scratch2 != 0 || scratch3 != UART_IER_ALL_INTR) {
/*
* We failed; there's nothing here
*/
@@ -1267,10 +1279,10 @@ static void autoconfig(struct uart_8250_port *up)
* that conflicts with COM 1-4 --- we hope!
*/
if (!(port->flags & UPF_SKIP_TEST)) {
- serial8250_out_MCR(up, UART_MCR_LOOP | 0x0A);
- status1 = serial_in(up, UART_MSR) & 0xF0;
+ serial8250_out_MCR(up, UART_MCR_LOOP | UART_MCR_OUT2 | UART_MCR_RTS);
+ status1 = serial_in(up, UART_MSR) & UART_MSR_STATUS_BITS;
serial8250_out_MCR(up, save_mcr);
- if (status1 != 0x90) {
+ if (status1 != (UART_MSR_DCD | UART_MSR_CTS)) {
spin_unlock_irqrestore(&port->lock, flags);
DEBUG_AUTOCONF("LOOP test failed (%02x) ",
status1);
@@ -1293,22 +1305,19 @@ static void autoconfig(struct uart_8250_port *up)
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
- /* Assign this as it is to truncate any bits above 7. */
- scratch = serial_in(up, UART_IIR);
-
- switch (scratch >> 6) {
- case 0:
+ switch (serial_in(up, UART_IIR) & UART_IIR_FIFO_ENABLED) {
+ case UART_IIR_FIFO_ENABLED_8250:
autoconfig_8250(up);
break;
- case 1:
- port->type = PORT_UNKNOWN;
- break;
- case 2:
+ case UART_IIR_FIFO_ENABLED_16550:
port->type = PORT_16550;
break;
- case 3:
+ case UART_IIR_FIFO_ENABLED_16550A:
autoconfig_16550a(up);
break;
+ default:
+ port->type = PORT_UNKNOWN;
+ break;
}
#ifdef CONFIG_SERIAL_8250_RSA
@@ -1394,7 +1403,7 @@ static void autoconfig_irq(struct uart_8250_port *up)
serial8250_out_MCR(up,
UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);
}
- serial_out(up, UART_IER, 0x0f); /* enable all intrs */
+ serial_out(up, UART_IER, UART_IER_ALL_INTR);
serial_in(up, UART_LSR);
serial_in(up, UART_RX);
serial_in(up, UART_IIR);
@@ -1511,8 +1520,6 @@ static inline void __stop_tx(struct uart_8250_port *p)
u16 lsr = serial_lsr_in(p);
u64 stop_delay = 0;
- p->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
-
if (!(lsr & UART_LSR_THRE))
return;
/*
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index b0f62345bc84..978dc196c29b 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -129,9 +129,13 @@ config SERIAL_8250_DMA
This builds DMA support that can be used with 8250/16650
compatible UART controllers that support DMA signaling.
+config SERIAL_8250_PCILIB
+ bool
+
config SERIAL_8250_PCI
tristate "8250/16550 PCI device support"
depends on SERIAL_8250 && PCI
+ select SERIAL_8250_PCILIB
default SERIAL_8250
help
This builds standard PCI serial support. You may be able to
@@ -291,6 +295,17 @@ config SERIAL_8250_HUB6
To compile this driver as a module, choose M here: the module
will be called 8250_hub6.
+config SERIAL_8250_PCI1XXXX
+ tristate "Microchip 8250 based serial port"
+ depends on SERIAL_8250 && PCI
+ select SERIAL_8250_PCILIB
+ default SERIAL_8250
+ help
+ Select this option if you have a setup with Microchip PCIe
+ Switch with serial port enabled and wish to enable 8250
+ serial driver for the serial interface. This driver support
+ will ensure to support baud rates upto 1.5Mpbs.
+
#
# Misc. options/drivers.
#
@@ -370,6 +385,18 @@ config SERIAL_8250_FSL
erratum for Freescale 16550 UARTs in the 8250 driver. It also
enables support for ACPI enumeration.
+config SERIAL_8250_DFL
+ tristate "DFL bus driver for Altera 16550 UART"
+ depends on SERIAL_8250 && FPGA_DFL
+ help
+ This option enables support for a Device Feature List (DFL) bus
+ driver for the Altera 16550 UART. One or more Altera 16550 UARTs
+ can be instantiated in a FPGA and then be discovered during
+ enumeration of the DFL bus.
+
+ To compile this driver as a module, chose M here: the
+ module will be called 8250_dfl.
+
config SERIAL_8250_DW
tristate "Support for Synopsys DesignWare 8250 quirks"
depends on SERIAL_8250
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index 1615bfdde2a0..4fc2fc1f41b6 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_SERIAL_8250) += 8250.o 8250_base.o
8250_base-$(CONFIG_SERIAL_8250_DMA) += 8250_dma.o
8250_base-$(CONFIG_SERIAL_8250_DWLIB) += 8250_dwlib.o
8250_base-$(CONFIG_SERIAL_8250_FINTEK) += 8250_fintek.o
+8250_base-$(CONFIG_SERIAL_8250_PCILIB) += 8250_pcilib.o
obj-$(CONFIG_SERIAL_8250_PARISC) += 8250_parisc.o
obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o
obj-$(CONFIG_SERIAL_8250_EXAR) += 8250_exar.o
@@ -26,8 +27,10 @@ obj-$(CONFIG_SERIAL_8250_ACCENT) += 8250_accent.o
obj-$(CONFIG_SERIAL_8250_BOCA) += 8250_boca.o
obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554) += 8250_exar_st16c554.o
obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o
+obj-$(CONFIG_SERIAL_8250_PCI1XXXX) += 8250_pci1xxxx.o
obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o
obj-$(CONFIG_SERIAL_8250_MEN_MCB) += 8250_men_mcb.o
+obj-$(CONFIG_SERIAL_8250_DFL) += 8250_dfl.o
obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o
obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o
obj-$(CONFIG_SERIAL_8250_IOC3) += 8250_ioc3.o
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index ed0672d2d0ef..625358f44419 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -73,17 +73,17 @@ config SERIAL_AMBA_PL011_CONSOLE
your boot loader (lilo or loadlin) about how to pass options to the
kernel at boot time.)
-config SERIAL_EARLYCON_ARM_SEMIHOST
- bool "Early console using ARM semihosting"
- depends on ARM64 || ARM
+config SERIAL_EARLYCON_SEMIHOST
+ bool "Early console using Arm compatible semihosting"
+ depends on ARM64 || ARM || RISCV
select SERIAL_CORE
select SERIAL_CORE_CONSOLE
select SERIAL_EARLYCON
help
- Support for early debug console using ARM semihosting. This enables
- the console before standard serial driver is probed. This is enabled
- with "earlycon=smh" on the kernel command line. The console is
- enabled when early_param is processed.
+ Support for early debug console using Arm compatible semihosting.
+ This enables the console before standard serial driver is probed.
+ This is enabled with "earlycon=smh" on the kernel command line.
+ The console is enabled when early_param is processed.
config SERIAL_EARLYCON_RISCV_SBI
bool "Early console using RISC-V SBI"
@@ -1507,7 +1507,7 @@ config SERIAL_MILBEAUT_USIO_CONSOLE
config SERIAL_LITEUART
tristate "LiteUART serial port support"
depends on HAS_IOMEM
- depends on OF || COMPILE_TEST
+ depends on OF
depends on LITEX || COMPILE_TEST
select SERIAL_CORE
help
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 238a9557b487..cd9afd9e3018 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -6,7 +6,7 @@
obj-$(CONFIG_SERIAL_CORE) += serial_core.o
obj-$(CONFIG_SERIAL_EARLYCON) += earlycon.o
-obj-$(CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST) += earlycon-arm-semihost.o
+obj-$(CONFIG_SERIAL_EARLYCON_SEMIHOST) += earlycon-semihost.o
obj-$(CONFIG_SERIAL_EARLYCON_RISCV_SBI) += earlycon-riscv-sbi.o
# These Sparc drivers have to appear before others such as 8250
diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c
index 748e8b1cf4f7..59e25f2b6632 100644
--- a/drivers/tty/serial/arc_uart.c
+++ b/drivers/tty/serial/arc_uart.c
@@ -631,12 +631,6 @@ static int arc_serial_probe(struct platform_device *pdev)
return uart_add_one_port(&arc_uart_driver, &arc_uart_ports[dev_id].port);
}
-static int arc_serial_remove(struct platform_device *pdev)
-{
- /* This will never be called */
- return 0;
-}
-
static const struct of_device_id arc_uart_dt_ids[] = {
{ .compatible = "snps,arc-uart" },
{ /* Sentinel */ }
@@ -645,7 +639,6 @@ MODULE_DEVICE_TABLE(of, arc_uart_dt_ids);
static struct platform_driver arc_platform_driver = {
.probe = arc_serial_probe,
- .remove = arc_serial_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = arc_uart_dt_ids,
diff --git a/drivers/tty/serial/earlycon-arm-semihost.c b/drivers/tty/serial/earlycon-semihost.c
index fcdec5f42376..e4692a8433f9 100644
--- a/drivers/tty/serial/earlycon-arm-semihost.c
+++ b/drivers/tty/serial/earlycon-semihost.c
@@ -11,30 +11,7 @@
#include <linux/console.h>
#include <linux/init.h>
#include <linux/serial_core.h>
-
-#ifdef CONFIG_THUMB2_KERNEL
-#define SEMIHOST_SWI "0xab"
-#else
-#define SEMIHOST_SWI "0x123456"
-#endif
-
-/*
- * Semihosting-based debug console
- */
-static void smh_putc(struct uart_port *port, unsigned char c)
-{
-#ifdef CONFIG_ARM64
- asm volatile("mov x1, %0\n"
- "mov x0, #3\n"
- "hlt 0xf000\n"
- : : "r" (&c) : "x0", "x1", "memory");
-#else
- asm volatile("mov r1, %0\n"
- "mov r0, #3\n"
- "svc " SEMIHOST_SWI "\n"
- : : "r" (&c) : "r0", "r1", "memory");
-#endif
-}
+#include <asm/semihost.h>
static void smh_write(struct console *con, const char *s, unsigned n)
{
diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c
index 4f6e9bf57169..a5fbb6ed38ae 100644
--- a/drivers/tty/serial/earlycon.c
+++ b/drivers/tty/serial/earlycon.c
@@ -120,7 +120,13 @@ static int __init parse_options(struct earlycon_device *device, char *options)
}
if (options) {
+ char *uartclk;
+
device->baud = simple_strtoul(options, NULL, 0);
+ uartclk = strchr(options, ',');
+ if (uartclk && kstrtouint(uartclk + 1, 0, &port->uartclk) < 0)
+ pr_warn("[%s] unsupported earlycon uart clkrate option\n",
+ options);
length = min(strcspn(options, " ") + 1,
(size_t)(sizeof(device->options)));
strscpy(device->options, options, length);
@@ -139,7 +145,8 @@ static int __init register_earlycon(char *buf, const struct earlycon_id *match)
buf = NULL;
spin_lock_init(&port->lock);
- port->uartclk = BASE_BAUD * 16;
+ if (!port->uartclk)
+ port->uartclk = BASE_BAUD * 16;
if (port->mapbase)
port->membase = earlycon_map(port->mapbase, 64);
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index 5e69fb73f570..e945f41b93d4 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -5,6 +5,8 @@
* Copyright 2012-2014 Freescale Semiconductor, Inc.
*/
+#include <linux/bitfield.h>
+#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/console.h>
#include <linux/delay.h>
@@ -181,7 +183,7 @@
#define UARTCTRL_SBK 0x00010000
#define UARTCTRL_MA1IE 0x00008000
#define UARTCTRL_MA2IE 0x00004000
-#define UARTCTRL_IDLECFG 0x00000100
+#define UARTCTRL_IDLECFG GENMASK(10, 8)
#define UARTCTRL_LOOPS 0x00000080
#define UARTCTRL_DOZEEN 0x00000040
#define UARTCTRL_RSRC 0x00000020
@@ -199,6 +201,7 @@
#define UARTDATA_MASK 0x3ff
#define UARTMODIR_IREN 0x00020000
+#define UARTMODIR_RTSWATER GENMASK(10, 8)
#define UARTMODIR_TXCTSSRC 0x00000020
#define UARTMODIR_TXCTSC 0x00000010
#define UARTMODIR_RXRTSE 0x00000008
@@ -212,6 +215,7 @@
#define UARTFIFO_RXUF 0x00010000
#define UARTFIFO_TXFLUSH 0x00008000
#define UARTFIFO_RXFLUSH 0x00004000
+#define UARTFIFO_RXIDEN GENMASK(12, 10)
#define UARTFIFO_TXOFE 0x00000200
#define UARTFIFO_RXUFE 0x00000100
#define UARTFIFO_TXFE 0x00000080
@@ -238,7 +242,7 @@
#define DRIVER_NAME "fsl-lpuart"
#define DEV_NAME "ttyLP"
-#define UART_NR 6
+#define UART_NR 8
/* IMX lpuart has four extra unused regs located at the beginning */
#define IMX_REG_OFF 0x10
@@ -248,6 +252,7 @@ enum lpuart_type {
LS1021A_LPUART,
LS1028A_LPUART,
IMX7ULP_LPUART,
+ IMX8ULP_LPUART,
IMX8QXP_LPUART,
IMXRT1050_LPUART,
};
@@ -260,6 +265,7 @@ struct lpuart_port {
unsigned int txfifo_size;
unsigned int rxfifo_size;
+ u8 rx_watermark;
bool lpuart_dma_tx_use;
bool lpuart_dma_rx_use;
struct dma_chan *dma_tx_chan;
@@ -286,38 +292,52 @@ struct lpuart_soc_data {
enum lpuart_type devtype;
char iotype;
u8 reg_off;
+ u8 rx_watermark;
};
static const struct lpuart_soc_data vf_data = {
.devtype = VF610_LPUART,
.iotype = UPIO_MEM,
+ .rx_watermark = 1,
};
static const struct lpuart_soc_data ls1021a_data = {
.devtype = LS1021A_LPUART,
.iotype = UPIO_MEM32BE,
+ .rx_watermark = 1,
};
static const struct lpuart_soc_data ls1028a_data = {
.devtype = LS1028A_LPUART,
.iotype = UPIO_MEM32,
+ .rx_watermark = 1,
};
static struct lpuart_soc_data imx7ulp_data = {
.devtype = IMX7ULP_LPUART,
.iotype = UPIO_MEM32,
.reg_off = IMX_REG_OFF,
+ .rx_watermark = 1,
+};
+
+static struct lpuart_soc_data imx8ulp_data = {
+ .devtype = IMX8ULP_LPUART,
+ .iotype = UPIO_MEM32,
+ .reg_off = IMX_REG_OFF,
+ .rx_watermark = 3,
};
static struct lpuart_soc_data imx8qxp_data = {
.devtype = IMX8QXP_LPUART,
.iotype = UPIO_MEM32,
.reg_off = IMX_REG_OFF,
+ .rx_watermark = 31,
};
static struct lpuart_soc_data imxrt1050_data = {
.devtype = IMXRT1050_LPUART,
.iotype = UPIO_MEM32,
.reg_off = IMX_REG_OFF,
+ .rx_watermark = 1,
};
static const struct of_device_id lpuart_dt_ids[] = {
@@ -325,6 +345,7 @@ static const struct of_device_id lpuart_dt_ids[] = {
{ .compatible = "fsl,ls1021a-lpuart", .data = &ls1021a_data, },
{ .compatible = "fsl,ls1028a-lpuart", .data = &ls1028a_data, },
{ .compatible = "fsl,imx7ulp-lpuart", .data = &imx7ulp_data, },
+ { .compatible = "fsl,imx8ulp-lpuart", .data = &imx8ulp_data, },
{ .compatible = "fsl,imx8qxp-lpuart", .data = &imx8qxp_data, },
{ .compatible = "fsl,imxrt1050-lpuart", .data = &imxrt1050_data},
{ /* sentinel */ }
@@ -345,6 +366,11 @@ static inline bool is_imx7ulp_lpuart(struct lpuart_port *sport)
return sport->devtype == IMX7ULP_LPUART;
}
+static inline bool is_imx8ulp_lpuart(struct lpuart_port *sport)
+{
+ return sport->devtype == IMX8ULP_LPUART;
+}
+
static inline bool is_imx8qxp_lpuart(struct lpuart_port *sport)
{
return sport->devtype == IMX8QXP_LPUART;
@@ -1387,9 +1413,9 @@ static int lpuart32_config_rs485(struct uart_port *port, struct ktermios *termio
* Note: UART is assumed to be active high.
*/
if (rs485->flags & SER_RS485_RTS_ON_SEND)
- modem &= ~UARTMODEM_TXRTSPOL;
- else if (rs485->flags & SER_RS485_RTS_AFTER_SEND)
modem |= UARTMODEM_TXRTSPOL;
+ else if (rs485->flags & SER_RS485_RTS_AFTER_SEND)
+ modem &= ~UARTMODEM_TXRTSPOL;
}
lpuart32_write(&sport->port, modem, UARTMODIR);
@@ -1462,12 +1488,32 @@ static void lpuart_break_ctl(struct uart_port *port, int break_state)
static void lpuart32_break_ctl(struct uart_port *port, int break_state)
{
- unsigned long temp;
+ unsigned long temp, modem;
+ struct tty_struct *tty;
+ unsigned int cflag = 0;
+
+ tty = tty_port_tty_get(&port->state->port);
+ if (tty) {
+ cflag = tty->termios.c_cflag;
+ tty_kref_put(tty);
+ }
temp = lpuart32_read(port, UARTCTRL) & ~UARTCTRL_SBK;
+ modem = lpuart32_read(port, UARTMODIR);
- if (break_state != 0)
+ if (break_state != 0) {
temp |= UARTCTRL_SBK;
+ /*
+ * LPUART CTS has higher priority than SBK, need to disable CTS before
+ * asserting SBK to avoid any interference if flow control is enabled.
+ */
+ if (cflag & CRTSCTS && modem & UARTMODIR_TXCTSE)
+ lpuart32_write(port, modem & ~UARTMODIR_TXCTSE, UARTMODIR);
+ } else {
+ /* Re-enable the CTS when break off. */
+ if (cflag & CRTSCTS && !(modem & UARTMODIR_TXCTSE))
+ lpuart32_write(port, modem | UARTMODIR_TXCTSE, UARTMODIR);
+ }
lpuart32_write(port, temp, UARTCTRL);
}
@@ -1497,8 +1543,10 @@ static void lpuart_setup_watermark(struct lpuart_port *sport)
writeb(UARTSFIFO_RXUF, sport->port.membase + UARTSFIFO);
}
+ if (uart_console(&sport->port))
+ sport->rx_watermark = 1;
writeb(0, sport->port.membase + UARTTWFIFO);
- writeb(1, sport->port.membase + UARTRWFIFO);
+ writeb(sport->rx_watermark, sport->port.membase + UARTRWFIFO);
/* Restore cr2 */
writeb(cr2_saved, sport->port.membase + UARTCR2);
@@ -1523,19 +1571,30 @@ static void lpuart32_setup_watermark(struct lpuart_port *sport)
ctrl = lpuart32_read(&sport->port, UARTCTRL);
ctrl_saved = ctrl;
ctrl &= ~(UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_TE |
- UARTCTRL_RIE | UARTCTRL_RE);
+ UARTCTRL_RIE | UARTCTRL_RE | UARTCTRL_ILIE);
lpuart32_write(&sport->port, ctrl, UARTCTRL);
/* enable FIFO mode */
val = lpuart32_read(&sport->port, UARTFIFO);
val |= UARTFIFO_TXFE | UARTFIFO_RXFE;
val |= UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH;
+ val |= FIELD_PREP(UARTFIFO_RXIDEN, 0x3);
lpuart32_write(&sport->port, val, UARTFIFO);
/* set the watermark */
- val = (0x1 << UARTWATER_RXWATER_OFF) | (0x0 << UARTWATER_TXWATER_OFF);
+ if (uart_console(&sport->port))
+ sport->rx_watermark = 1;
+ val = (sport->rx_watermark << UARTWATER_RXWATER_OFF) |
+ (0x0 << UARTWATER_TXWATER_OFF);
lpuart32_write(&sport->port, val, UARTWATER);
+ /* set RTS watermark */
+ if (!uart_console(&sport->port)) {
+ val = lpuart32_read(&sport->port, UARTMODIR);
+ val |= FIELD_PREP(UARTMODIR_RTSWATER, sport->rxfifo_size >> 1);
+ lpuart32_write(&sport->port, val, UARTMODIR);
+ }
+
/* Restore cr2 */
lpuart32_write(&sport->port, ctrl_saved, UARTCTRL);
}
@@ -1547,7 +1606,8 @@ static void lpuart32_setup_watermark_enable(struct lpuart_port *sport)
lpuart32_setup_watermark(sport);
temp = lpuart32_read(&sport->port, UARTCTRL);
- temp |= UARTCTRL_RE | UARTCTRL_TE | UARTCTRL_ILIE;
+ temp |= UARTCTRL_RE | UARTCTRL_TE;
+ temp |= FIELD_PREP(UARTCTRL_IDLECFG, 0x7);
lpuart32_write(&sport->port, temp, UARTCTRL);
}
@@ -1679,19 +1739,23 @@ static int lpuart_startup(struct uart_port *port)
return 0;
}
+static void lpuart32_hw_disable(struct lpuart_port *sport)
+{
+ unsigned long temp;
+
+ temp = lpuart32_read(&sport->port, UARTCTRL);
+ temp &= ~(UARTCTRL_RIE | UARTCTRL_ILIE | UARTCTRL_RE |
+ UARTCTRL_TIE | UARTCTRL_TE);
+ lpuart32_write(&sport->port, temp, UARTCTRL);
+}
+
static void lpuart32_configure(struct lpuart_port *sport)
{
unsigned long temp;
- if (sport->lpuart_dma_rx_use) {
- /* RXWATER must be 0 */
- temp = lpuart32_read(&sport->port, UARTWATER);
- temp &= ~(UARTWATER_WATER_MASK << UARTWATER_RXWATER_OFF);
- lpuart32_write(&sport->port, temp, UARTWATER);
- }
temp = lpuart32_read(&sport->port, UARTCTRL);
if (!sport->lpuart_dma_rx_use)
- temp |= UARTCTRL_RIE;
+ temp |= UARTCTRL_RIE | UARTCTRL_ILIE;
if (!sport->lpuart_dma_tx_use)
temp |= UARTCTRL_TIE;
lpuart32_write(&sport->port, temp, UARTCTRL);
@@ -1703,11 +1767,12 @@ static void lpuart32_hw_setup(struct lpuart_port *sport)
spin_lock_irqsave(&sport->port.lock, flags);
- lpuart32_setup_watermark_enable(sport);
+ lpuart32_hw_disable(sport);
lpuart_rx_dma_startup(sport);
lpuart_tx_dma_startup(sport);
+ lpuart32_setup_watermark_enable(sport);
lpuart32_configure(sport);
spin_unlock_irqrestore(&sport->port.lock, flags);
@@ -1796,10 +1861,19 @@ static void lpuart32_shutdown(struct uart_port *port)
spin_lock_irqsave(&port->lock, flags);
- /* disable Rx/Tx and interrupts */
+ /* clear status */
+ temp = lpuart32_read(&sport->port, UARTSTAT);
+ lpuart32_write(&sport->port, temp, UARTSTAT);
+
+ /* disable Rx/Tx DMA */
+ temp = lpuart32_read(port, UARTBAUD);
+ temp &= ~(UARTBAUD_TDMAE | UARTBAUD_RDMAE);
+ lpuart32_write(port, temp, UARTBAUD);
+
+ /* disable Rx/Tx and interrupts and break condition */
temp = lpuart32_read(port, UARTCTRL);
- temp &= ~(UARTCTRL_TE | UARTCTRL_RE |
- UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_RIE);
+ temp &= ~(UARTCTRL_TE | UARTCTRL_RE | UARTCTRL_ILIE |
+ UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_RIE | UARTCTRL_SBK);
lpuart32_write(port, temp, UARTCTRL);
spin_unlock_irqrestore(&port->lock, flags);
@@ -2631,7 +2705,7 @@ static int lpuart_global_reset(struct lpuart_port *sport)
return ret;
}
- if (is_imx7ulp_lpuart(sport) || is_imx8qxp_lpuart(sport)) {
+ if (is_imx7ulp_lpuart(sport) || is_imx8ulp_lpuart(sport) || is_imx8qxp_lpuart(sport)) {
/*
* If the transmitter is used by earlycon, wait for transmit engine to
* complete and then reset.
@@ -2688,6 +2762,7 @@ static int lpuart_probe(struct platform_device *pdev)
sport->port.dev = &pdev->dev;
sport->port.type = PORT_LPUART;
sport->devtype = sdata->devtype;
+ sport->rx_watermark = sdata->rx_watermark;
ret = platform_get_irq(pdev, 0);
if (ret < 0)
return ret;
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 757825edb0cd..523f296d5747 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -210,12 +210,8 @@ struct imx_port {
struct mctrl_gpios *gpios;
- /* shadow registers */
- unsigned int ucr1;
- unsigned int ucr2;
- unsigned int ucr3;
- unsigned int ucr4;
- unsigned int ufcr;
+ /* counter to stop 0xff flood */
+ int idle_counter;
/* DMA fields */
unsigned int dma_is_enabled:1;
@@ -273,59 +269,14 @@ static const struct of_device_id imx_uart_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, imx_uart_dt_ids);
-static void imx_uart_writel(struct imx_port *sport, u32 val, u32 offset)
-{
- switch (offset) {
- case UCR1:
- sport->ucr1 = val;
- break;
- case UCR2:
- sport->ucr2 = val;
- break;
- case UCR3:
- sport->ucr3 = val;
- break;
- case UCR4:
- sport->ucr4 = val;
- break;
- case UFCR:
- sport->ufcr = val;
- break;
- default:
- break;
- }
+static inline void imx_uart_writel(struct imx_port *sport, u32 val, u32 offset)
+{
writel(val, sport->port.membase + offset);
}
-static u32 imx_uart_readl(struct imx_port *sport, u32 offset)
+static inline u32 imx_uart_readl(struct imx_port *sport, u32 offset)
{
- switch (offset) {
- case UCR1:
- return sport->ucr1;
- break;
- case UCR2:
- /*
- * UCR2_SRST is the only bit in the cached registers that might
- * differ from the value that was last written. As it only
- * automatically becomes one after being cleared, reread
- * conditionally.
- */
- if (!(sport->ucr2 & UCR2_SRST))
- sport->ucr2 = readl(sport->port.membase + offset);
- return sport->ucr2;
- break;
- case UCR3:
- return sport->ucr3;
- break;
- case UCR4:
- return sport->ucr4;
- break;
- case UFCR:
- return sport->ufcr;
- break;
- default:
- return readl(sport->port.membase + offset);
- }
+ return readl(sport->port.membase + offset);
}
static inline unsigned imx_uart_uts_reg(struct imx_port *sport)
@@ -398,6 +349,41 @@ static void start_hrtimer_ms(struct hrtimer *hrt, unsigned long msec)
}
/* called with port.lock taken and irqs off */
+static void imx_uart_soft_reset(struct imx_port *sport)
+{
+ int i = 10;
+ u32 ucr2, ubir, ubmr, uts;
+
+ /*
+ * According to the Reference Manual description of the UART SRST bit:
+ *
+ * "Reset the transmit and receive state machines,
+ * all FIFOs and register USR1, USR2, UBIR, UBMR, UBRC, URXD, UTXD
+ * and UTS[6-3]".
+ *
+ * We don't need to restore the old values from USR1, USR2, URXD and
+ * UTXD. UBRC is read only, so only save/restore the other three
+ * registers.
+ */
+ ubir = imx_uart_readl(sport, UBIR);
+ ubmr = imx_uart_readl(sport, UBMR);
+ uts = imx_uart_readl(sport, IMX21_UTS);
+
+ ucr2 = imx_uart_readl(sport, UCR2);
+ imx_uart_writel(sport, ucr2 & ~UCR2_SRST, UCR2);
+
+ while (!(imx_uart_readl(sport, UCR2) & UCR2_SRST) && (--i > 0))
+ udelay(1);
+
+ /* Restore the registers */
+ imx_uart_writel(sport, ubir, UBIR);
+ imx_uart_writel(sport, ubmr, UBMR);
+ imx_uart_writel(sport, uts, IMX21_UTS);
+
+ sport->idle_counter = 0;
+}
+
+/* called with port.lock taken and irqs off */
static void imx_uart_start_rx(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
@@ -476,7 +462,8 @@ static void imx_uart_stop_tx(struct uart_port *port)
imx_uart_rts_inactive(sport, &ucr2);
imx_uart_writel(sport, ucr2, UCR2);
- imx_uart_start_rx(port);
+ if (!port->rs485_rx_during_tx_gpio)
+ imx_uart_start_rx(port);
sport->tx_state = OFF;
}
@@ -705,7 +692,8 @@ static void imx_uart_start_tx(struct uart_port *port)
imx_uart_rts_inactive(sport, &ucr2);
imx_uart_writel(sport, ucr2, UCR2);
- if (!(port->rs485.flags & SER_RS485_RX_DURING_TX))
+ if (!(port->rs485.flags & SER_RS485_RX_DURING_TX) &&
+ !port->rs485_rx_during_tx_gpio)
imx_uart_stop_rx(port);
sport->tx_state = WAIT_AFTER_RTS;
@@ -771,7 +759,7 @@ static irqreturn_t __imx_uart_rtsint(int irq, void *dev_id)
imx_uart_writel(sport, USR1_RTSD, USR1);
usr1 = imx_uart_readl(sport, USR1) & USR1_RTSS;
- uart_handle_cts_change(&sport->port, !!usr1);
+ uart_handle_cts_change(&sport->port, usr1);
wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
return IRQ_HANDLED;
@@ -801,33 +789,73 @@ static irqreturn_t imx_uart_txint(int irq, void *dev_id)
return IRQ_HANDLED;
}
+/* Check if hardware Rx flood is in progress, and issue soft reset to stop it.
+ * This is to be called from Rx ISRs only when some bytes were actually
+ * received.
+ *
+ * A way to reproduce the flood (checked on iMX6SX) is: open iMX UART at 9600
+ * 8N1, and from external source send 0xf0 char at 115200 8N1. In about 90% of
+ * cases this starts a flood of "receiving" of 0xff characters by the iMX6 UART
+ * that is terminated by any activity on RxD line, or could be stopped by
+ * issuing soft reset to the UART (just stop/start of RX does not help). Note
+ * that what we do here is sending isolated start bit about 2.4 times shorter
+ * than it is to be on UART configured baud rate.
+ */
+static void imx_uart_check_flood(struct imx_port *sport, u32 usr2)
+{
+ /* To detect hardware 0xff flood we monitor RxD line between RX
+ * interrupts to isolate "receiving" of char(s) with no activity
+ * on RxD line, that'd never happen on actual data transfers.
+ *
+ * We use USR2_WAKE bit to check for activity on RxD line, but we have a
+ * race here if we clear USR2_WAKE when receiving of a char is in
+ * progress, so we might get RX interrupt later with USR2_WAKE bit
+ * cleared. Note though that as we don't try to clear USR2_WAKE when we
+ * detected no activity, this race may hide actual activity only once.
+ *
+ * Yet another case where receive interrupt may occur without RxD
+ * activity is expiration of aging timer, so we consider this as well.
+ *
+ * We use 'idle_counter' to ensure that we got at least so many RX
+ * interrupts without any detected activity on RxD line. 2 cases
+ * described plus 1 to be on the safe side gives us a margin of 3,
+ * below. In practice I was not able to produce a false positive to
+ * induce soft reset at regular data transfers even using 1 as the
+ * margin, so 3 is actually very strong.
+ *
+ * We count interrupts, not chars in 'idle-counter' for simplicity.
+ */
+
+ if (usr2 & USR2_WAKE) {
+ imx_uart_writel(sport, USR2_WAKE, USR2);
+ sport->idle_counter = 0;
+ } else if (++sport->idle_counter > 3) {
+ dev_warn(sport->port.dev, "RX flood detected: soft reset.");
+ imx_uart_soft_reset(sport); /* also clears 'sport->idle_counter' */
+ }
+}
+
static irqreturn_t __imx_uart_rxint(int irq, void *dev_id)
{
struct imx_port *sport = dev_id;
- unsigned int rx, flg, ignored = 0;
struct tty_port *port = &sport->port.state->port;
+ u32 usr2, rx;
- while (imx_uart_readl(sport, USR2) & USR2_RDR) {
- u32 usr2;
+ /* If we received something, check for 0xff flood */
+ usr2 = imx_uart_readl(sport, USR2);
+ if (usr2 & USR2_RDR)
+ imx_uart_check_flood(sport, usr2);
- flg = TTY_NORMAL;
+ while ((rx = imx_uart_readl(sport, URXD0)) & URXD_CHARRDY) {
+ unsigned int flg = TTY_NORMAL;
sport->port.icount.rx++;
- rx = imx_uart_readl(sport, URXD0);
-
- usr2 = imx_uart_readl(sport, USR2);
- if (usr2 & USR2_BRCD) {
- imx_uart_writel(sport, USR2_BRCD, USR2);
- if (uart_handle_break(&sport->port))
- continue;
- }
-
- if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx))
- continue;
-
if (unlikely(rx & URXD_ERR)) {
- if (rx & URXD_BRK)
+ if (rx & URXD_BRK) {
sport->port.icount.brk++;
+ if (uart_handle_break(&sport->port))
+ continue;
+ }
else if (rx & URXD_PRERR)
sport->port.icount.parity++;
else if (rx & URXD_FRMERR)
@@ -835,11 +863,8 @@ static irqreturn_t __imx_uart_rxint(int irq, void *dev_id)
if (rx & URXD_OVRRUN)
sport->port.icount.overrun++;
- if (rx & sport->port.ignore_status_mask) {
- if (++ignored > 100)
- goto out;
+ if (rx & sport->port.ignore_status_mask)
continue;
- }
rx &= (sport->port.read_status_mask | 0xFF);
@@ -853,16 +878,17 @@ static irqreturn_t __imx_uart_rxint(int irq, void *dev_id)
flg = TTY_OVERRUN;
sport->port.sysrq = 0;
+ } else if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx)) {
+ continue;
}
if (sport->port.ignore_status_mask & URXD_DUMMY_READ)
- goto out;
+ continue;
if (tty_insert_flip_char(port, rx, flg) == 0)
sport->port.icount.buf_overrun++;
}
-out:
tty_flip_buffer_push(port);
return IRQ_HANDLED;
@@ -1147,55 +1173,62 @@ static void imx_uart_dma_rx_callback(void *data)
status = dmaengine_tx_status(chan, sport->rx_cookie, &state);
if (status == DMA_ERROR) {
+ spin_lock(&sport->port.lock);
imx_uart_clear_rx_errors(sport);
+ spin_unlock(&sport->port.lock);
return;
}
- if (!(sport->port.ignore_status_mask & URXD_DUMMY_READ)) {
+ /*
+ * The state-residue variable represents the empty space
+ * relative to the entire buffer. Taking this in consideration
+ * the head is always calculated base on the buffer total
+ * length - DMA transaction residue. The UART script from the
+ * SDMA firmware will jump to the next buffer descriptor,
+ * once a DMA transaction if finalized (IMX53 RM - A.4.1.2.4).
+ * Taking this in consideration the tail is always at the
+ * beginning of the buffer descriptor that contains the head.
+ */
- /*
- * The state-residue variable represents the empty space
- * relative to the entire buffer. Taking this in consideration
- * the head is always calculated base on the buffer total
- * length - DMA transaction residue. The UART script from the
- * SDMA firmware will jump to the next buffer descriptor,
- * once a DMA transaction if finalized (IMX53 RM - A.4.1.2.4).
- * Taking this in consideration the tail is always at the
- * beginning of the buffer descriptor that contains the head.
- */
+ /* Calculate the head */
+ rx_ring->head = sg_dma_len(sgl) - state.residue;
+
+ /* Calculate the tail. */
+ bd_size = sg_dma_len(sgl) / sport->rx_periods;
+ rx_ring->tail = ((rx_ring->head-1) / bd_size) * bd_size;
- /* Calculate the head */
- rx_ring->head = sg_dma_len(sgl) - state.residue;
+ if (rx_ring->head <= sg_dma_len(sgl) &&
+ rx_ring->head > rx_ring->tail) {
- /* Calculate the tail. */
- bd_size = sg_dma_len(sgl) / sport->rx_periods;
- rx_ring->tail = ((rx_ring->head-1) / bd_size) * bd_size;
+ /* Move data from tail to head */
+ r_bytes = rx_ring->head - rx_ring->tail;
- if (rx_ring->head <= sg_dma_len(sgl) &&
- rx_ring->head > rx_ring->tail) {
+ /* If we received something, check for 0xff flood */
+ spin_lock(&sport->port.lock);
+ imx_uart_check_flood(sport, imx_uart_readl(sport, USR2));
+ spin_unlock(&sport->port.lock);
- /* Move data from tail to head */
- r_bytes = rx_ring->head - rx_ring->tail;
+ if (!(sport->port.ignore_status_mask & URXD_DUMMY_READ)) {
/* CPU claims ownership of RX DMA buffer */
dma_sync_sg_for_cpu(sport->port.dev, sgl, 1,
- DMA_FROM_DEVICE);
+ DMA_FROM_DEVICE);
w_bytes = tty_insert_flip_string(port,
- sport->rx_buf + rx_ring->tail, r_bytes);
+ sport->rx_buf + rx_ring->tail, r_bytes);
/* UART retrieves ownership of RX DMA buffer */
dma_sync_sg_for_device(sport->port.dev, sgl, 1,
- DMA_FROM_DEVICE);
+ DMA_FROM_DEVICE);
if (w_bytes != r_bytes)
sport->port.icount.buf_overrun++;
sport->port.icount.rx += w_bytes;
- } else {
- WARN_ON(rx_ring->head > sg_dma_len(sgl));
- WARN_ON(rx_ring->head <= rx_ring->tail);
}
+ } else {
+ WARN_ON(rx_ring->head > sg_dma_len(sgl));
+ WARN_ON(rx_ring->head <= rx_ring->tail);
}
if (w_bytes) {
@@ -1271,6 +1304,8 @@ static void imx_uart_clear_rx_errors(struct imx_port *sport)
imx_uart_writel(sport, USR2_ORE, USR2);
}
+ sport->idle_counter = 0;
+
}
#define TXTL_DEFAULT 2 /* reset default */
@@ -1398,7 +1433,7 @@ static void imx_uart_disable_dma(struct imx_port *sport)
static int imx_uart_startup(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
- int retval, i;
+ int retval;
unsigned long flags;
int dma_is_inited = 0;
u32 ucr1, ucr2, ucr3, ucr4, uts;
@@ -1430,15 +1465,9 @@ static int imx_uart_startup(struct uart_port *port)
dma_is_inited = 1;
spin_lock_irqsave(&sport->port.lock, flags);
- /* Reset fifo's and state machines */
- i = 100;
- ucr2 = imx_uart_readl(sport, UCR2);
- ucr2 &= ~UCR2_SRST;
- imx_uart_writel(sport, ucr2, UCR2);
-
- while (!(imx_uart_readl(sport, UCR2) & UCR2_SRST) && (--i > 0))
- udelay(1);
+ /* Reset fifo's and state machines */
+ imx_uart_soft_reset(sport);
/*
* Finally, clear and enable interrupts
@@ -1564,7 +1593,8 @@ static void imx_uart_shutdown(struct uart_port *port)
spin_lock_irqsave(&sport->port.lock, flags);
ucr1 = imx_uart_readl(sport, UCR1);
- ucr1 &= ~(UCR1_TRDYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_RXDMAEN | UCR1_ATDMAEN);
+ ucr1 &= ~(UCR1_TRDYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_RXDMAEN |
+ UCR1_ATDMAEN | UCR1_SNDBRK);
/* See SER_RS485_ENABLED/UTS_LOOP comment in imx_uart_probe() */
if (port->rs485.flags & SER_RS485_ENABLED &&
port->rs485.flags & SER_RS485_RTS_ON_SEND &&
@@ -1593,8 +1623,6 @@ static void imx_uart_flush_buffer(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
struct scatterlist *sgl = &sport->tx_sgl[0];
- u32 ucr2;
- int i = 100, ubir, ubmr, uts;
if (!sport->dma_chan_tx)
return;
@@ -1612,32 +1640,8 @@ static void imx_uart_flush_buffer(struct uart_port *port)
sport->dma_is_txing = 0;
}
- /*
- * According to the Reference Manual description of the UART SRST bit:
- *
- * "Reset the transmit and receive state machines,
- * all FIFOs and register USR1, USR2, UBIR, UBMR, UBRC, URXD, UTXD
- * and UTS[6-3]".
- *
- * We don't need to restore the old values from USR1, USR2, URXD and
- * UTXD. UBRC is read only, so only save/restore the other three
- * registers.
- */
- ubir = imx_uart_readl(sport, UBIR);
- ubmr = imx_uart_readl(sport, UBMR);
- uts = imx_uart_readl(sport, IMX21_UTS);
-
- ucr2 = imx_uart_readl(sport, UCR2);
- ucr2 &= ~UCR2_SRST;
- imx_uart_writel(sport, ucr2, UCR2);
-
- while (!(imx_uart_readl(sport, UCR2) & UCR2_SRST) && (--i > 0))
- udelay(1);
+ imx_uart_soft_reset(sport);
- /* Restore the registers */
- imx_uart_writel(sport, ubir, UBIR);
- imx_uart_writel(sport, ubmr, UBMR);
- imx_uart_writel(sport, uts, IMX21_UTS);
}
static void
@@ -1955,6 +1959,10 @@ static int imx_uart_rs485_config(struct uart_port *port, struct ktermios *termio
rs485conf->flags & SER_RS485_RX_DURING_TX)
imx_uart_start_rx(port);
+ if (port->rs485_rx_during_tx_gpio)
+ gpiod_set_value_cansleep(port->rs485_rx_during_tx_gpio,
+ !!(rs485conf->flags & SER_RS485_RX_DURING_TX));
+
return 0;
}
@@ -2340,13 +2348,6 @@ static int imx_uart_probe(struct platform_device *pdev)
return ret;
}
- /* initialize shadow register values */
- sport->ucr1 = readl(sport->port.membase + UCR1);
- sport->ucr2 = readl(sport->port.membase + UCR2);
- sport->ucr3 = readl(sport->port.membase + UCR3);
- sport->ucr4 = readl(sport->port.membase + UCR4);
- sport->ufcr = readl(sport->port.membase + UFCR);
-
ret = uart_get_rs485_mode(&sport->port);
if (ret) {
clk_disable_unprepare(sport->clk_ipg);
@@ -2374,6 +2375,11 @@ static int imx_uart_probe(struct platform_device *pdev)
ucr1 &= ~(UCR1_ADEN | UCR1_TRDYEN | UCR1_IDEN | UCR1_RRDYEN | UCR1_RTSDEN);
imx_uart_writel(sport, ucr1, UCR1);
+ /* Disable Ageing Timer interrupt */
+ ucr2 = imx_uart_readl(sport, UCR2);
+ ucr2 &= ~UCR2_ATEN;
+ imx_uart_writel(sport, ucr2, UCR2);
+
/*
* In case RS485 is enabled without GPIO RTS control, the UART IP
* is used to control CTS signal. Keep both the UART and Receiver
diff --git a/drivers/tty/serial/liteuart.c b/drivers/tty/serial/liteuart.c
index 062812fe1b09..80de3a42b67b 100644
--- a/drivers/tty/serial/liteuart.c
+++ b/drivers/tty/serial/liteuart.c
@@ -5,7 +5,9 @@
* Copyright (C) 2019-2020 Antmicro <www.antmicro.com>
*/
+#include <linux/bits.h>
#include <linux/console.h>
+#include <linux/interrupt.h>
#include <linux/litex.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -38,13 +40,13 @@
#define OFF_EV_ENABLE 0x14
/* events */
-#define EV_TX 0x1
-#define EV_RX 0x2
+#define EV_TX BIT(0)
+#define EV_RX BIT(1)
struct liteuart_port {
struct uart_port port;
struct timer_list timer;
- u32 id;
+ u8 irq_reg;
};
#define to_liteuart_port(port) container_of(port, struct liteuart_port, port)
@@ -57,7 +59,7 @@ static struct console liteuart_console;
static struct uart_driver liteuart_driver = {
.owner = THIS_MODULE,
- .driver_name = "liteuart",
+ .driver_name = KBUILD_MODNAME,
.dev_name = "ttyLXU",
.major = 0,
.minor = 0,
@@ -67,38 +69,95 @@ static struct uart_driver liteuart_driver = {
#endif
};
-static void liteuart_timer(struct timer_list *t)
+static void liteuart_update_irq_reg(struct uart_port *port, bool set, u8 mask)
+{
+ struct liteuart_port *uart = to_liteuart_port(port);
+
+ if (set)
+ uart->irq_reg |= mask;
+ else
+ uart->irq_reg &= ~mask;
+
+ if (port->irq)
+ litex_write8(port->membase + OFF_EV_ENABLE, uart->irq_reg);
+}
+
+static void liteuart_stop_tx(struct uart_port *port)
+{
+ liteuart_update_irq_reg(port, false, EV_TX);
+}
+
+static void liteuart_start_tx(struct uart_port *port)
+{
+ liteuart_update_irq_reg(port, true, EV_TX);
+}
+
+static void liteuart_stop_rx(struct uart_port *port)
+{
+ struct liteuart_port *uart = to_liteuart_port(port);
+
+ /* just delete timer */
+ del_timer(&uart->timer);
+}
+
+static void liteuart_rx_chars(struct uart_port *port)
{
- struct liteuart_port *uart = from_timer(uart, t, timer);
- struct uart_port *port = &uart->port;
unsigned char __iomem *membase = port->membase;
- unsigned int flg = TTY_NORMAL;
- int ch;
- unsigned long status;
+ u8 ch;
- while ((status = !litex_read8(membase + OFF_RXEMPTY)) == 1) {
+ while (!litex_read8(membase + OFF_RXEMPTY)) {
ch = litex_read8(membase + OFF_RXTX);
port->icount.rx++;
/* necessary for RXEMPTY to refresh its value */
- litex_write8(membase + OFF_EV_PENDING, EV_TX | EV_RX);
+ litex_write8(membase + OFF_EV_PENDING, EV_RX);
/* no overflow bits in status */
if (!(uart_handle_sysrq_char(port, ch)))
- uart_insert_char(port, status, 0, ch, flg);
-
- tty_flip_buffer_push(&port->state->port);
+ uart_insert_char(port, 1, 0, ch, TTY_NORMAL);
}
- mod_timer(&uart->timer, jiffies + uart_poll_timeout(port));
+ tty_flip_buffer_push(&port->state->port);
}
-static void liteuart_putchar(struct uart_port *port, unsigned char ch)
+static void liteuart_tx_chars(struct uart_port *port)
{
- while (litex_read8(port->membase + OFF_TXFULL))
- cpu_relax();
+ u8 ch;
- litex_write8(port->membase + OFF_RXTX, ch);
+ uart_port_tx(port, ch,
+ !litex_read8(port->membase + OFF_TXFULL),
+ litex_write8(port->membase + OFF_RXTX, ch));
+}
+
+static irqreturn_t liteuart_interrupt(int irq, void *data)
+{
+ struct liteuart_port *uart = data;
+ struct uart_port *port = &uart->port;
+ unsigned long flags;
+ u8 isr;
+
+ /*
+ * if polling, the context would be "in_serving_softirq", so use
+ * irq[save|restore] spin_lock variants to cover all possibilities
+ */
+ spin_lock_irqsave(&port->lock, flags);
+ isr = litex_read8(port->membase + OFF_EV_PENDING) & uart->irq_reg;
+ if (isr & EV_RX)
+ liteuart_rx_chars(port);
+ if (isr & EV_TX)
+ liteuart_tx_chars(port);
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ return IRQ_RETVAL(isr);
+}
+
+static void liteuart_timer(struct timer_list *t)
+{
+ struct liteuart_port *uart = from_timer(uart, t, timer);
+ struct uart_port *port = &uart->port;
+
+ liteuart_interrupt(0, port);
+ mod_timer(&uart->timer, jiffies + uart_poll_timeout(port));
}
static unsigned int liteuart_tx_empty(struct uart_port *port)
@@ -120,60 +179,49 @@ static unsigned int liteuart_get_mctrl(struct uart_port *port)
return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
}
-static void liteuart_stop_tx(struct uart_port *port)
-{
-}
-
-static void liteuart_start_tx(struct uart_port *port)
+static int liteuart_startup(struct uart_port *port)
{
- struct circ_buf *xmit = &port->state->xmit;
- unsigned char ch;
-
- if (unlikely(port->x_char)) {
- litex_write8(port->membase + OFF_RXTX, port->x_char);
- port->icount.tx++;
- port->x_char = 0;
- } else if (!uart_circ_empty(xmit)) {
- while (xmit->head != xmit->tail) {
- ch = xmit->buf[xmit->tail];
- uart_xmit_advance(port, 1);
- liteuart_putchar(port, ch);
+ struct liteuart_port *uart = to_liteuart_port(port);
+ unsigned long flags;
+ int ret;
+
+ if (port->irq) {
+ ret = request_irq(port->irq, liteuart_interrupt, 0,
+ KBUILD_MODNAME, uart);
+ if (ret) {
+ dev_warn(port->dev,
+ "line %d irq %d failed: switch to polling\n",
+ port->line, port->irq);
+ port->irq = 0;
}
}
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
- uart_write_wakeup(port);
-}
-
-static void liteuart_stop_rx(struct uart_port *port)
-{
- struct liteuart_port *uart = to_liteuart_port(port);
+ spin_lock_irqsave(&port->lock, flags);
+ /* only enabling rx irqs during startup */
+ liteuart_update_irq_reg(port, true, EV_RX);
+ spin_unlock_irqrestore(&port->lock, flags);
- /* just delete timer */
- del_timer(&uart->timer);
-}
+ if (!port->irq) {
+ timer_setup(&uart->timer, liteuart_timer, 0);
+ mod_timer(&uart->timer, jiffies + uart_poll_timeout(port));
+ }
-static void liteuart_break_ctl(struct uart_port *port, int break_state)
-{
- /* LiteUART doesn't support sending break signal */
+ return 0;
}
-static int liteuart_startup(struct uart_port *port)
+static void liteuart_shutdown(struct uart_port *port)
{
struct liteuart_port *uart = to_liteuart_port(port);
+ unsigned long flags;
- /* disable events */
- litex_write8(port->membase + OFF_EV_ENABLE, 0);
-
- /* prepare timer for polling */
- timer_setup(&uart->timer, liteuart_timer, 0);
- mod_timer(&uart->timer, jiffies + uart_poll_timeout(port));
-
- return 0;
-}
+ spin_lock_irqsave(&port->lock, flags);
+ liteuart_update_irq_reg(port, false, EV_RX | EV_TX);
+ spin_unlock_irqrestore(&port->lock, flags);
-static void liteuart_shutdown(struct uart_port *port)
-{
+ if (port->irq)
+ free_irq(port->irq, port);
+ else
+ del_timer_sync(&uart->timer);
}
static void liteuart_set_termios(struct uart_port *port, struct ktermios *new,
@@ -196,15 +244,6 @@ static const char *liteuart_type(struct uart_port *port)
return "liteuart";
}
-static void liteuart_release_port(struct uart_port *port)
-{
-}
-
-static int liteuart_request_port(struct uart_port *port)
-{
- return 0;
-}
-
static void liteuart_config_port(struct uart_port *port, int flags)
{
/*
@@ -231,13 +270,10 @@ static const struct uart_ops liteuart_ops = {
.stop_tx = liteuart_stop_tx,
.start_tx = liteuart_start_tx,
.stop_rx = liteuart_stop_rx,
- .break_ctl = liteuart_break_ctl,
.startup = liteuart_startup,
.shutdown = liteuart_shutdown,
.set_termios = liteuart_set_termios,
.type = liteuart_type,
- .release_port = liteuart_release_port,
- .request_port = liteuart_request_port,
.config_port = liteuart_config_port,
.verify_port = liteuart_verify_port,
};
@@ -249,6 +285,23 @@ static int liteuart_probe(struct platform_device *pdev)
struct xa_limit limit;
int dev_id, ret;
+ uart = devm_kzalloc(&pdev->dev, sizeof(struct liteuart_port), GFP_KERNEL);
+ if (!uart)
+ return -ENOMEM;
+
+ port = &uart->port;
+
+ /* get membase */
+ port->membase = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+ if (IS_ERR(port->membase))
+ return PTR_ERR(port->membase);
+
+ ret = platform_get_irq_optional(pdev, 0);
+ if (ret < 0 && ret != -ENXIO)
+ return ret;
+ if (ret > 0)
+ port->irq = ret;
+
/* look for aliases; auto-enumerate for free index if not found */
dev_id = of_alias_get_id(pdev->dev.of_node, "serial");
if (dev_id < 0)
@@ -256,32 +309,16 @@ static int liteuart_probe(struct platform_device *pdev)
else
limit = XA_LIMIT(dev_id, dev_id);
- uart = devm_kzalloc(&pdev->dev, sizeof(struct liteuart_port), GFP_KERNEL);
- if (!uart)
- return -ENOMEM;
-
ret = xa_alloc(&liteuart_array, &dev_id, uart, limit, GFP_KERNEL);
if (ret)
return ret;
- uart->id = dev_id;
- port = &uart->port;
-
- /* get membase */
- port->membase = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
- if (IS_ERR(port->membase)) {
- ret = PTR_ERR(port->membase);
- goto err_erase_id;
- }
-
/* values not from device tree */
port->dev = &pdev->dev;
port->iotype = UPIO_MEM;
port->flags = UPF_BOOT_AUTOCONF;
port->ops = &liteuart_ops;
- port->regshift = 2;
port->fifosize = 16;
- port->iobase = 1;
port->type = PORT_UNKNOWN;
port->line = dev_id;
spin_lock_init(&port->lock);
@@ -295,7 +332,7 @@ static int liteuart_probe(struct platform_device *pdev)
return 0;
err_erase_id:
- xa_erase(&liteuart_array, uart->id);
+ xa_erase(&liteuart_array, dev_id);
return ret;
}
@@ -303,10 +340,10 @@ err_erase_id:
static int liteuart_remove(struct platform_device *pdev)
{
struct uart_port *port = platform_get_drvdata(pdev);
- struct liteuart_port *uart = to_liteuart_port(port);
+ unsigned int line = port->line;
uart_remove_one_port(&liteuart_driver, port);
- xa_erase(&liteuart_array, uart->id);
+ xa_erase(&liteuart_array, line);
return 0;
}
@@ -321,13 +358,21 @@ static struct platform_driver liteuart_platform_driver = {
.probe = liteuart_probe,
.remove = liteuart_remove,
.driver = {
- .name = "liteuart",
+ .name = KBUILD_MODNAME,
.of_match_table = liteuart_of_match,
},
};
#ifdef CONFIG_SERIAL_LITEUART_CONSOLE
+static void liteuart_putchar(struct uart_port *port, unsigned char ch)
+{
+ while (litex_read8(port->membase + OFF_TXFULL))
+ cpu_relax();
+
+ litex_write8(port->membase + OFF_RXTX, ch);
+}
+
static void liteuart_console_write(struct console *co, const char *s,
unsigned int count)
{
@@ -367,7 +412,7 @@ static int liteuart_console_setup(struct console *co, char *options)
}
static struct console liteuart_console = {
- .name = "liteuart",
+ .name = KBUILD_MODNAME,
.write = liteuart_console_write,
.device = uart_console_device,
.setup = liteuart_console_setup,
@@ -415,12 +460,10 @@ static int __init liteuart_init(void)
return res;
res = platform_driver_register(&liteuart_platform_driver);
- if (res) {
+ if (res)
uart_unregister_driver(&liteuart_driver);
- return res;
- }
- return 0;
+ return res;
}
static void __exit liteuart_exit(void)
diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c
index bb74f23251fe..86dcbff8faa3 100644
--- a/drivers/tty/serial/max3100.c
+++ b/drivers/tty/serial/max3100.c
@@ -247,7 +247,7 @@ static int max3100_handlerx(struct max3100_port *s, u16 rx)
cts = (rx & MAX3100_CTS) > 0;
if (s->cts != cts) {
s->cts = cts;
- uart_handle_cts_change(&s->port, cts ? TIOCM_CTS : 0);
+ uart_handle_cts_change(&s->port, cts);
}
return ret;
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
index 4eb24e3407f8..e9cacfe7e032 100644
--- a/drivers/tty/serial/max310x.c
+++ b/drivers/tty/serial/max310x.c
@@ -819,8 +819,7 @@ static irqreturn_t max310x_port_irq(struct max310x_port *s, int portno)
if (ists & MAX310X_IRQ_CTS_BIT) {
lsr = max310x_port_read(port, MAX310X_LSR_IRQSTS_REG);
- uart_handle_cts_change(port,
- !!(lsr & MAX310X_LSR_CTS_BIT));
+ uart_handle_cts_change(port, lsr & MAX310X_LSR_CTS_BIT);
}
if (rxlen)
max310x_handle_rx(port, rxlen);
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index 843798e63084..90953e679e38 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -1120,6 +1120,7 @@ msm_find_best_baud(struct uart_port *port, unsigned int baud,
static int msm_set_baud_rate(struct uart_port *port, unsigned int baud,
unsigned long *saved_flags)
+ __must_hold(&port->lock)
{
unsigned int rxstale, watermark, mask;
struct msm_port *msm_port = to_msm_port(port);
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index 9576ba8bbc40..cc83b772b7ca 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -1775,7 +1775,7 @@ static void pch_uart_exit_port(struct eg20t_port *priv)
char name[32];
snprintf(name, sizeof(name), "uart%d_regs", priv->port.line);
- debugfs_remove(debugfs_lookup(name, NULL));
+ debugfs_lookup_and_remove(name, NULL);
uart_remove_one_port(&pch_uart_driver, &priv->port);
free_page((unsigned long)priv->rxbuf.buf);
}
diff --git a/drivers/tty/serial/pic32_uart.c b/drivers/tty/serial/pic32_uart.c
index ba3435263c1f..196a4e678451 100644
--- a/drivers/tty/serial/pic32_uart.c
+++ b/drivers/tty/serial/pic32_uart.c
@@ -889,6 +889,8 @@ static int pic32_uart_probe(struct platform_device *pdev)
sport->irq_rx = irq_of_parse_and_map(np, 1);
sport->irq_tx = irq_of_parse_and_map(np, 2);
sport->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(sport->clk))
+ return PTR_ERR(sport->clk);
sport->dev = &pdev->dev;
/* Hardware flow control: gpios
diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c
index 57f04f8bf504..d69592e5e2ec 100644
--- a/drivers/tty/serial/qcom_geni_serial.c
+++ b/drivers/tty/serial/qcom_geni_serial.c
@@ -16,7 +16,7 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/pm_wakeirq.h>
-#include <linux/qcom-geni-se.h>
+#include <linux/soc/qcom/geni-se.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/slab.h>
@@ -39,76 +39,70 @@
#define SE_UART_MANUAL_RFR 0x2ac
/* SE_UART_TRANS_CFG */
-#define UART_TX_PAR_EN BIT(0)
-#define UART_CTS_MASK BIT(1)
-
-/* SE_UART_TX_WORD_LEN */
-#define TX_WORD_LEN_MSK GENMASK(9, 0)
+#define UART_TX_PAR_EN BIT(0)
+#define UART_CTS_MASK BIT(1)
/* SE_UART_TX_STOP_BIT_LEN */
-#define TX_STOP_BIT_LEN_MSK GENMASK(23, 0)
-#define TX_STOP_BIT_LEN_1 0
-#define TX_STOP_BIT_LEN_1_5 1
-#define TX_STOP_BIT_LEN_2 2
-
-/* SE_UART_TX_TRANS_LEN */
-#define TX_TRANS_LEN_MSK GENMASK(23, 0)
+#define TX_STOP_BIT_LEN_1 0
+#define TX_STOP_BIT_LEN_2 2
/* SE_UART_RX_TRANS_CFG */
-#define UART_RX_INS_STATUS_BIT BIT(2)
-#define UART_RX_PAR_EN BIT(3)
+#define UART_RX_PAR_EN BIT(3)
/* SE_UART_RX_WORD_LEN */
-#define RX_WORD_LEN_MASK GENMASK(9, 0)
+#define RX_WORD_LEN_MASK GENMASK(9, 0)
/* SE_UART_RX_STALE_CNT */
-#define RX_STALE_CNT GENMASK(23, 0)
+#define RX_STALE_CNT GENMASK(23, 0)
/* SE_UART_TX_PARITY_CFG/RX_PARITY_CFG */
-#define PAR_CALC_EN BIT(0)
-#define PAR_MODE_MSK GENMASK(2, 1)
-#define PAR_MODE_SHFT 1
-#define PAR_EVEN 0x00
-#define PAR_ODD 0x01
-#define PAR_SPACE 0x10
-#define PAR_MARK 0x11
+#define PAR_CALC_EN BIT(0)
+#define PAR_EVEN 0x00
+#define PAR_ODD 0x01
+#define PAR_SPACE 0x10
/* SE_UART_MANUAL_RFR register fields */
-#define UART_MANUAL_RFR_EN BIT(31)
-#define UART_RFR_NOT_READY BIT(1)
-#define UART_RFR_READY BIT(0)
+#define UART_MANUAL_RFR_EN BIT(31)
+#define UART_RFR_NOT_READY BIT(1)
+#define UART_RFR_READY BIT(0)
/* UART M_CMD OP codes */
-#define UART_START_TX 0x1
-#define UART_START_BREAK 0x4
-#define UART_STOP_BREAK 0x5
+#define UART_START_TX 0x1
/* UART S_CMD OP codes */
-#define UART_START_READ 0x1
-#define UART_PARAM 0x1
-
-#define UART_OVERSAMPLING 32
-#define STALE_TIMEOUT 16
-#define DEFAULT_BITS_PER_CHAR 10
-#define GENI_UART_CONS_PORTS 1
-#define GENI_UART_PORTS 3
-#define DEF_FIFO_DEPTH_WORDS 16
-#define DEF_TX_WM 2
-#define DEF_FIFO_WIDTH_BITS 32
-#define UART_RX_WM 2
+#define UART_START_READ 0x1
+#define UART_PARAM 0x1
+#define UART_PARAM_RFR_OPEN BIT(7)
+
+#define UART_OVERSAMPLING 32
+#define STALE_TIMEOUT 16
+#define DEFAULT_BITS_PER_CHAR 10
+#define GENI_UART_CONS_PORTS 1
+#define GENI_UART_PORTS 3
+#define DEF_FIFO_DEPTH_WORDS 16
+#define DEF_TX_WM 2
+#define DEF_FIFO_WIDTH_BITS 32
+#define UART_RX_WM 2
/* SE_UART_LOOPBACK_CFG */
-#define RX_TX_SORTED BIT(0)
-#define CTS_RTS_SORTED BIT(1)
-#define RX_TX_CTS_RTS_SORTED (RX_TX_SORTED | CTS_RTS_SORTED)
+#define RX_TX_SORTED BIT(0)
+#define CTS_RTS_SORTED BIT(1)
+#define RX_TX_CTS_RTS_SORTED (RX_TX_SORTED | CTS_RTS_SORTED)
/* UART pin swap value */
-#define DEFAULT_IO_MACRO_IO0_IO1_MASK GENMASK(3, 0)
+#define DEFAULT_IO_MACRO_IO0_IO1_MASK GENMASK(3, 0)
#define IO_MACRO_IO0_SEL 0x3
-#define DEFAULT_IO_MACRO_IO2_IO3_MASK GENMASK(15, 4)
+#define DEFAULT_IO_MACRO_IO2_IO3_MASK GENMASK(15, 4)
#define IO_MACRO_IO2_IO3_SWAP 0x4640
/* We always configure 4 bytes per FIFO word */
-#define BYTES_PER_FIFO_WORD 4
+#define BYTES_PER_FIFO_WORD 4U
+
+#define DMA_RX_BUF_SIZE 2048
+
+struct qcom_geni_device_data {
+ bool console;
+ enum geni_se_xfer_mode mode;
+};
struct qcom_geni_private_data {
/* NOTE: earlycon port will have NULL here */
@@ -128,10 +122,11 @@ struct qcom_geni_serial_port {
u32 tx_fifo_depth;
u32 tx_fifo_width;
u32 rx_fifo_depth;
+ dma_addr_t tx_dma_addr;
+ dma_addr_t rx_dma_addr;
bool setup;
- int (*handle_rx)(struct uart_port *uport, u32 bytes, bool drop);
unsigned int baud;
- void *rx_fifo;
+ void *rx_buf;
u32 loopback;
bool brk;
@@ -141,44 +136,42 @@ struct qcom_geni_serial_port {
bool cts_rts_swap;
struct qcom_geni_private_data private_data;
+ const struct qcom_geni_device_data *dev_data;
};
static const struct uart_ops qcom_geni_console_pops;
static const struct uart_ops qcom_geni_uart_pops;
static struct uart_driver qcom_geni_console_driver;
static struct uart_driver qcom_geni_uart_driver;
-static int handle_rx_console(struct uart_port *uport, u32 bytes, bool drop);
-static int handle_rx_uart(struct uart_port *uport, u32 bytes, bool drop);
-static unsigned int qcom_geni_serial_tx_empty(struct uart_port *port);
-static void qcom_geni_serial_stop_rx(struct uart_port *uport);
-static void qcom_geni_serial_handle_rx(struct uart_port *uport, bool drop);
-#define to_dev_port(ptr, member) \
- container_of(ptr, struct qcom_geni_serial_port, member)
+static inline struct qcom_geni_serial_port *to_dev_port(struct uart_port *uport)
+{
+ return container_of(uport, struct qcom_geni_serial_port, uport);
+}
static struct qcom_geni_serial_port qcom_geni_uart_ports[GENI_UART_PORTS] = {
[0] = {
.uport = {
- .iotype = UPIO_MEM,
- .ops = &qcom_geni_uart_pops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 0,
+ .iotype = UPIO_MEM,
+ .ops = &qcom_geni_uart_pops,
+ .flags = UPF_BOOT_AUTOCONF,
+ .line = 0,
},
},
[1] = {
.uport = {
- .iotype = UPIO_MEM,
- .ops = &qcom_geni_uart_pops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 1,
+ .iotype = UPIO_MEM,
+ .ops = &qcom_geni_uart_pops,
+ .flags = UPF_BOOT_AUTOCONF,
+ .line = 1,
},
},
[2] = {
.uport = {
- .iotype = UPIO_MEM,
- .ops = &qcom_geni_uart_pops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 2,
+ .iotype = UPIO_MEM,
+ .ops = &qcom_geni_uart_pops,
+ .flags = UPF_BOOT_AUTOCONF,
+ .line = 2,
},
},
};
@@ -195,7 +188,7 @@ static struct qcom_geni_serial_port qcom_geni_console_port = {
static int qcom_geni_serial_request_port(struct uart_port *uport)
{
struct platform_device *pdev = to_platform_device(uport->dev);
- struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
+ struct qcom_geni_serial_port *port = to_dev_port(uport);
uport->membase = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(uport->membase))
@@ -232,7 +225,7 @@ static void qcom_geni_serial_set_mctrl(struct uart_port *uport,
unsigned int mctrl)
{
u32 uart_manual_rfr = 0;
- struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
+ struct qcom_geni_serial_port *port = to_dev_port(uport);
if (uart_console(uport))
return;
@@ -262,6 +255,16 @@ static struct qcom_geni_serial_port *get_port_from_line(int line, bool console)
return port;
}
+static bool qcom_geni_serial_main_active(struct uart_port *uport)
+{
+ return readl(uport->membase + SE_GENI_STATUS) & M_GENI_CMD_ACTIVE;
+}
+
+static bool qcom_geni_serial_secondary_active(struct uart_port *uport)
+{
+ return readl(uport->membase + SE_GENI_STATUS) & S_GENI_CMD_ACTIVE;
+}
+
static bool qcom_geni_serial_poll_bit(struct uart_port *uport,
int offset, int field, bool set)
{
@@ -273,7 +276,7 @@ static bool qcom_geni_serial_poll_bit(struct uart_port *uport,
struct qcom_geni_private_data *private_data = uport->private_data;
if (private_data->drv) {
- port = to_dev_port(uport, uport);
+ port = to_dev_port(uport);
baud = port->baud;
if (!baud)
baud = 115200;
@@ -338,7 +341,6 @@ static void qcom_geni_serial_abort_rx(struct uart_port *uport)
}
#ifdef CONFIG_CONSOLE_POLL
-
static int qcom_geni_serial_get_char(struct uart_port *uport)
{
struct qcom_geni_private_data *private_data = uport->private_data;
@@ -521,12 +523,12 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s,
spin_unlock_irqrestore(&uport->lock, flags);
}
-static int handle_rx_console(struct uart_port *uport, u32 bytes, bool drop)
+static void handle_rx_console(struct uart_port *uport, u32 bytes, bool drop)
{
u32 i;
unsigned char buf[sizeof(u32)];
struct tty_port *tport;
- struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
+ struct qcom_geni_serial_port *port = to_dev_port(uport);
tport = &uport->state->port;
for (i = 0; i < bytes; ) {
@@ -556,30 +558,21 @@ static int handle_rx_console(struct uart_port *uport, u32 bytes, bool drop)
}
if (!drop)
tty_flip_buffer_push(tport);
- return 0;
}
#else
-static int handle_rx_console(struct uart_port *uport, u32 bytes, bool drop)
+static void handle_rx_console(struct uart_port *uport, u32 bytes, bool drop)
{
- return -EPERM;
-}
+}
#endif /* CONFIG_SERIAL_QCOM_GENI_CONSOLE */
-static int handle_rx_uart(struct uart_port *uport, u32 bytes, bool drop)
+static void handle_rx_uart(struct uart_port *uport, u32 bytes, bool drop)
{
- struct tty_port *tport;
- struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
- u32 num_bytes_pw = port->tx_fifo_width / BITS_PER_BYTE;
- u32 words = ALIGN(bytes, num_bytes_pw) / num_bytes_pw;
+ struct qcom_geni_serial_port *port = to_dev_port(uport);
+ struct tty_port *tport = &uport->state->port;
int ret;
- tport = &uport->state->port;
- ioread32_rep(uport->membase + SE_GENI_RX_FIFOn, port->rx_fifo, words);
- if (drop)
- return 0;
-
- ret = tty_insert_flip_string(tport, port->rx_fifo, bytes);
+ ret = tty_insert_flip_string(tport, port->rx_buf, bytes);
if (ret != bytes) {
dev_err(uport->dev, "%s:Unable to push data ret %d_bytes %d\n",
__func__, ret, bytes);
@@ -587,19 +580,82 @@ static int handle_rx_uart(struct uart_port *uport, u32 bytes, bool drop)
}
uport->icount.rx += ret;
tty_flip_buffer_push(tport);
- return ret;
}
-static void qcom_geni_serial_start_tx(struct uart_port *uport)
+static unsigned int qcom_geni_serial_tx_empty(struct uart_port *uport)
{
- u32 irq_en;
- u32 status;
+ return !readl(uport->membase + SE_GENI_TX_FIFO_STATUS);
+}
+
+static void qcom_geni_serial_stop_tx_dma(struct uart_port *uport)
+{
+ struct qcom_geni_serial_port *port = to_dev_port(uport);
+ bool done;
+ u32 m_irq_en;
- status = readl(uport->membase + SE_GENI_STATUS);
- if (status & M_GENI_CMD_ACTIVE)
+ if (!qcom_geni_serial_main_active(uport))
return;
- if (!qcom_geni_serial_tx_empty(uport))
+ if (port->rx_dma_addr) {
+ geni_se_tx_dma_unprep(&port->se, port->tx_dma_addr,
+ port->tx_remaining);
+ port->tx_dma_addr = 0;
+ port->tx_remaining = 0;
+ }
+
+ m_irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN);
+ writel(m_irq_en, uport->membase + SE_GENI_M_IRQ_EN);
+ geni_se_cancel_m_cmd(&port->se);
+
+ done = qcom_geni_serial_poll_bit(uport, SE_GENI_S_IRQ_STATUS,
+ S_CMD_CANCEL_EN, true);
+ if (!done) {
+ geni_se_abort_m_cmd(&port->se);
+ done = qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
+ M_CMD_ABORT_EN, true);
+ if (!done)
+ dev_err_ratelimited(uport->dev, "M_CMD_ABORT_EN not set");
+ writel(M_CMD_ABORT_EN, uport->membase + SE_GENI_M_IRQ_CLEAR);
+ }
+
+ writel(M_CMD_CANCEL_EN, uport->membase + SE_GENI_M_IRQ_CLEAR);
+}
+
+static void qcom_geni_serial_start_tx_dma(struct uart_port *uport)
+{
+ struct qcom_geni_serial_port *port = to_dev_port(uport);
+ struct circ_buf *xmit = &uport->state->xmit;
+ unsigned int xmit_size;
+ int ret;
+
+ if (port->tx_dma_addr)
+ return;
+
+ xmit_size = uart_circ_chars_pending(xmit);
+ if (xmit_size < WAKEUP_CHARS)
+ uart_write_wakeup(uport);
+
+ xmit_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+
+ qcom_geni_serial_setup_tx(uport, xmit_size);
+
+ ret = geni_se_tx_dma_prep(&port->se, &xmit->buf[xmit->tail],
+ xmit_size, &port->tx_dma_addr);
+ if (ret) {
+ dev_err(uport->dev, "unable to start TX SE DMA: %d\n", ret);
+ qcom_geni_serial_stop_tx_dma(uport);
+ return;
+ }
+
+ port->tx_remaining = xmit_size;
+}
+
+static void qcom_geni_serial_start_tx_fifo(struct uart_port *uport)
+{
+ u32 irq_en;
+
+ if (qcom_geni_serial_main_active(uport) ||
+ !qcom_geni_serial_tx_empty(uport))
return;
irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN);
@@ -609,19 +665,17 @@ static void qcom_geni_serial_start_tx(struct uart_port *uport)
writel(irq_en, uport->membase + SE_GENI_M_IRQ_EN);
}
-static void qcom_geni_serial_stop_tx(struct uart_port *uport)
+static void qcom_geni_serial_stop_tx_fifo(struct uart_port *uport)
{
u32 irq_en;
- u32 status;
- struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
+ struct qcom_geni_serial_port *port = to_dev_port(uport);
irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN);
irq_en &= ~(M_CMD_DONE_EN | M_TX_FIFO_WATERMARK_EN);
writel(0, uport->membase + SE_GENI_TX_WATERMARK_REG);
writel(irq_en, uport->membase + SE_GENI_M_IRQ_EN);
- status = readl(uport->membase + SE_GENI_STATUS);
/* Possible stop tx is called multiple times. */
- if (!(status & M_GENI_CMD_ACTIVE))
+ if (!qcom_geni_serial_main_active(uport))
return;
geni_se_cancel_m_cmd(&port->se);
@@ -635,32 +689,34 @@ static void qcom_geni_serial_stop_tx(struct uart_port *uport)
writel(M_CMD_CANCEL_EN, uport->membase + SE_GENI_M_IRQ_CLEAR);
}
-static void qcom_geni_serial_start_rx(struct uart_port *uport)
+static void qcom_geni_serial_handle_rx_fifo(struct uart_port *uport, bool drop)
{
- u32 irq_en;
u32 status;
- struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
-
- status = readl(uport->membase + SE_GENI_STATUS);
- if (status & S_GENI_CMD_ACTIVE)
- qcom_geni_serial_stop_rx(uport);
-
- geni_se_setup_s_cmd(&port->se, UART_START_READ, 0);
+ u32 word_cnt;
+ u32 last_word_byte_cnt;
+ u32 last_word_partial;
+ u32 total_bytes;
- irq_en = readl(uport->membase + SE_GENI_S_IRQ_EN);
- irq_en |= S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN;
- writel(irq_en, uport->membase + SE_GENI_S_IRQ_EN);
+ status = readl(uport->membase + SE_GENI_RX_FIFO_STATUS);
+ word_cnt = status & RX_FIFO_WC_MSK;
+ last_word_partial = status & RX_LAST;
+ last_word_byte_cnt = (status & RX_LAST_BYTE_VALID_MSK) >>
+ RX_LAST_BYTE_VALID_SHFT;
- irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN);
- irq_en |= M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN;
- writel(irq_en, uport->membase + SE_GENI_M_IRQ_EN);
+ if (!word_cnt)
+ return;
+ total_bytes = BYTES_PER_FIFO_WORD * (word_cnt - 1);
+ if (last_word_partial && last_word_byte_cnt)
+ total_bytes += last_word_byte_cnt;
+ else
+ total_bytes += BYTES_PER_FIFO_WORD;
+ handle_rx_console(uport, total_bytes, drop);
}
-static void qcom_geni_serial_stop_rx(struct uart_port *uport)
+static void qcom_geni_serial_stop_rx_fifo(struct uart_port *uport)
{
u32 irq_en;
- u32 status;
- struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
+ struct qcom_geni_serial_port *port = to_dev_port(uport);
u32 s_irq_status;
irq_en = readl(uport->membase + SE_GENI_S_IRQ_EN);
@@ -671,9 +727,7 @@ static void qcom_geni_serial_stop_rx(struct uart_port *uport)
irq_en &= ~(M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN);
writel(irq_en, uport->membase + SE_GENI_M_IRQ_EN);
- status = readl(uport->membase + SE_GENI_STATUS);
- /* Possible stop rx is called multiple times. */
- if (!(status & S_GENI_CMD_ACTIVE))
+ if (!qcom_geni_serial_secondary_active(uport))
return;
geni_se_cancel_s_cmd(&port->se);
@@ -686,52 +740,154 @@ static void qcom_geni_serial_stop_rx(struct uart_port *uport)
s_irq_status = readl(uport->membase + SE_GENI_S_IRQ_STATUS);
/* Flush the Rx buffer */
if (s_irq_status & S_RX_FIFO_LAST_EN)
- qcom_geni_serial_handle_rx(uport, true);
+ qcom_geni_serial_handle_rx_fifo(uport, true);
writel(s_irq_status, uport->membase + SE_GENI_S_IRQ_CLEAR);
- status = readl(uport->membase + SE_GENI_STATUS);
- if (status & S_GENI_CMD_ACTIVE)
+ if (qcom_geni_serial_secondary_active(uport))
qcom_geni_serial_abort_rx(uport);
}
-static void qcom_geni_serial_handle_rx(struct uart_port *uport, bool drop)
+static void qcom_geni_serial_start_rx_fifo(struct uart_port *uport)
{
- u32 status;
- u32 word_cnt;
- u32 last_word_byte_cnt;
- u32 last_word_partial;
- u32 total_bytes;
- struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
+ u32 irq_en;
+ struct qcom_geni_serial_port *port = to_dev_port(uport);
- status = readl(uport->membase + SE_GENI_RX_FIFO_STATUS);
- word_cnt = status & RX_FIFO_WC_MSK;
- last_word_partial = status & RX_LAST;
- last_word_byte_cnt = (status & RX_LAST_BYTE_VALID_MSK) >>
- RX_LAST_BYTE_VALID_SHFT;
+ if (qcom_geni_serial_secondary_active(uport))
+ qcom_geni_serial_stop_rx_fifo(uport);
- if (!word_cnt)
+ geni_se_setup_s_cmd(&port->se, UART_START_READ, 0);
+
+ irq_en = readl(uport->membase + SE_GENI_S_IRQ_EN);
+ irq_en |= S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN;
+ writel(irq_en, uport->membase + SE_GENI_S_IRQ_EN);
+
+ irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN);
+ irq_en |= M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN;
+ writel(irq_en, uport->membase + SE_GENI_M_IRQ_EN);
+}
+
+static void qcom_geni_serial_stop_rx_dma(struct uart_port *uport)
+{
+ struct qcom_geni_serial_port *port = to_dev_port(uport);
+
+ if (!qcom_geni_serial_secondary_active(uport))
return;
- total_bytes = BYTES_PER_FIFO_WORD * (word_cnt - 1);
- if (last_word_partial && last_word_byte_cnt)
- total_bytes += last_word_byte_cnt;
- else
- total_bytes += BYTES_PER_FIFO_WORD;
- port->handle_rx(uport, total_bytes, drop);
+
+ geni_se_cancel_s_cmd(&port->se);
+ qcom_geni_serial_poll_bit(uport, SE_GENI_S_IRQ_STATUS,
+ S_CMD_CANCEL_EN, true);
+
+ if (qcom_geni_serial_secondary_active(uport))
+ qcom_geni_serial_abort_rx(uport);
+
+ if (port->rx_dma_addr) {
+ geni_se_rx_dma_unprep(&port->se, port->rx_dma_addr,
+ DMA_RX_BUF_SIZE);
+ port->rx_dma_addr = 0;
+ }
+}
+
+static void qcom_geni_serial_start_rx_dma(struct uart_port *uport)
+{
+ struct qcom_geni_serial_port *port = to_dev_port(uport);
+ int ret;
+
+ if (qcom_geni_serial_secondary_active(uport))
+ qcom_geni_serial_stop_rx_dma(uport);
+
+ geni_se_setup_s_cmd(&port->se, UART_START_READ, UART_PARAM_RFR_OPEN);
+
+ ret = geni_se_rx_dma_prep(&port->se, port->rx_buf,
+ DMA_RX_BUF_SIZE,
+ &port->rx_dma_addr);
+ if (ret) {
+ dev_err(uport->dev, "unable to start RX SE DMA: %d\n", ret);
+ qcom_geni_serial_stop_rx_dma(uport);
+ }
+}
+
+static void qcom_geni_serial_handle_rx_dma(struct uart_port *uport, bool drop)
+{
+ struct qcom_geni_serial_port *port = to_dev_port(uport);
+ u32 rx_in;
+ int ret;
+
+ if (!qcom_geni_serial_secondary_active(uport))
+ return;
+
+ if (!port->rx_dma_addr)
+ return;
+
+ geni_se_rx_dma_unprep(&port->se, port->rx_dma_addr, DMA_RX_BUF_SIZE);
+ port->rx_dma_addr = 0;
+
+ rx_in = readl(uport->membase + SE_DMA_RX_LEN_IN);
+ if (!rx_in) {
+ dev_warn(uport->dev, "serial engine reports 0 RX bytes in!\n");
+ return;
+ }
+
+ if (!drop)
+ handle_rx_uart(uport, rx_in, drop);
+
+ ret = geni_se_rx_dma_prep(&port->se, port->rx_buf,
+ DMA_RX_BUF_SIZE,
+ &port->rx_dma_addr);
+ if (ret) {
+ dev_err(uport->dev, "unable to start RX SE DMA: %d\n", ret);
+ qcom_geni_serial_stop_rx_dma(uport);
+ }
+}
+
+static void qcom_geni_serial_start_rx(struct uart_port *uport)
+{
+ uport->ops->start_rx(uport);
+}
+
+static void qcom_geni_serial_stop_rx(struct uart_port *uport)
+{
+ uport->ops->stop_rx(uport);
+}
+
+static void qcom_geni_serial_stop_tx(struct uart_port *uport)
+{
+ uport->ops->stop_tx(uport);
+}
+
+static void qcom_geni_serial_send_chunk_fifo(struct uart_port *uport,
+ unsigned int chunk)
+{
+ struct qcom_geni_serial_port *port = to_dev_port(uport);
+ struct circ_buf *xmit = &uport->state->xmit;
+ unsigned int tx_bytes, c, remaining = chunk;
+ u8 buf[BYTES_PER_FIFO_WORD];
+
+ while (remaining) {
+ memset(buf, 0, sizeof(buf));
+ tx_bytes = min(remaining, BYTES_PER_FIFO_WORD);
+
+ for (c = 0; c < tx_bytes ; c++) {
+ buf[c] = xmit->buf[xmit->tail];
+ uart_xmit_advance(uport, 1);
+ }
+
+ iowrite32_rep(uport->membase + SE_GENI_TX_FIFOn, buf, 1);
+
+ remaining -= tx_bytes;
+ port->tx_remaining -= tx_bytes;
+ }
}
-static void qcom_geni_serial_handle_tx(struct uart_port *uport, bool done,
- bool active)
+static void qcom_geni_serial_handle_tx_fifo(struct uart_port *uport,
+ bool done, bool active)
{
- struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
+ struct qcom_geni_serial_port *port = to_dev_port(uport);
struct circ_buf *xmit = &uport->state->xmit;
size_t avail;
- size_t remaining;
size_t pending;
- int i;
u32 status;
u32 irq_en;
unsigned int chunk;
- int tail;
status = readl(uport->membase + SE_GENI_TX_FIFO_STATUS);
@@ -743,14 +899,13 @@ static void qcom_geni_serial_handle_tx(struct uart_port *uport, bool done,
/* All data has been transmitted and acknowledged as received */
if (!pending && !status && done) {
- qcom_geni_serial_stop_tx(uport);
+ qcom_geni_serial_stop_tx_fifo(uport);
goto out_write_wakeup;
}
avail = port->tx_fifo_depth - (status & TX_FIFO_WC);
avail *= BYTES_PER_FIFO_WORD;
- tail = xmit->tail;
chunk = min(avail, pending);
if (!chunk)
goto out_write_wakeup;
@@ -765,29 +920,7 @@ static void qcom_geni_serial_handle_tx(struct uart_port *uport, bool done,
uport->membase + SE_GENI_M_IRQ_EN);
}
- remaining = chunk;
- for (i = 0; i < chunk; ) {
- unsigned int tx_bytes;
- u8 buf[sizeof(u32)];
- int c;
-
- memset(buf, 0, sizeof(buf));
- tx_bytes = min_t(size_t, remaining, BYTES_PER_FIFO_WORD);
-
- for (c = 0; c < tx_bytes ; c++) {
- buf[c] = xmit->buf[tail++];
- tail &= UART_XMIT_SIZE - 1;
- }
-
- iowrite32_rep(uport->membase + SE_GENI_TX_FIFOn, buf, 1);
-
- i += tx_bytes;
- uport->icount.tx += tx_bytes;
- remaining -= tx_bytes;
- port->tx_remaining -= tx_bytes;
- }
-
- xmit->tail = tail;
+ qcom_geni_serial_send_chunk_fifo(uport, chunk);
/*
* The tx fifo watermark is level triggered and latched. Though we had
@@ -809,16 +942,36 @@ out_write_wakeup:
uart_write_wakeup(uport);
}
+static void qcom_geni_serial_handle_tx_dma(struct uart_port *uport)
+{
+ struct qcom_geni_serial_port *port = to_dev_port(uport);
+ struct circ_buf *xmit = &uport->state->xmit;
+
+ uart_xmit_advance(uport, port->tx_remaining);
+ geni_se_tx_dma_unprep(&port->se, port->tx_dma_addr, port->tx_remaining);
+ port->tx_dma_addr = 0;
+ port->tx_remaining = 0;
+
+ if (!uart_circ_empty(xmit))
+ qcom_geni_serial_start_tx_dma(uport);
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(uport);
+}
+
static irqreturn_t qcom_geni_serial_isr(int isr, void *dev)
{
u32 m_irq_en;
u32 m_irq_status;
u32 s_irq_status;
u32 geni_status;
+ u32 dma;
+ u32 dma_tx_status;
+ u32 dma_rx_status;
struct uart_port *uport = dev;
bool drop_rx = false;
struct tty_port *tport = &uport->state->port;
- struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
+ struct qcom_geni_serial_port *port = to_dev_port(uport);
if (uport->suspended)
return IRQ_NONE;
@@ -827,10 +980,15 @@ static irqreturn_t qcom_geni_serial_isr(int isr, void *dev)
m_irq_status = readl(uport->membase + SE_GENI_M_IRQ_STATUS);
s_irq_status = readl(uport->membase + SE_GENI_S_IRQ_STATUS);
+ dma_tx_status = readl(uport->membase + SE_DMA_TX_IRQ_STAT);
+ dma_rx_status = readl(uport->membase + SE_DMA_RX_IRQ_STAT);
geni_status = readl(uport->membase + SE_GENI_STATUS);
+ dma = readl(uport->membase + SE_GENI_DMA_MODE_EN);
m_irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN);
writel(m_irq_status, uport->membase + SE_GENI_M_IRQ_CLEAR);
writel(s_irq_status, uport->membase + SE_GENI_S_IRQ_CLEAR);
+ writel(dma_tx_status, uport->membase + SE_DMA_TX_IRQ_CLR);
+ writel(dma_rx_status, uport->membase + SE_DMA_RX_IRQ_CLR);
if (WARN_ON(m_irq_status & M_ILLEGAL_CMD_EN))
goto out_unlock;
@@ -840,23 +998,44 @@ static irqreturn_t qcom_geni_serial_isr(int isr, void *dev)
tty_insert_flip_char(tport, 0, TTY_OVERRUN);
}
- if (m_irq_status & m_irq_en & (M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN))
- qcom_geni_serial_handle_tx(uport, m_irq_status & M_CMD_DONE_EN,
- geni_status & M_GENI_CMD_ACTIVE);
-
- if (s_irq_status & S_GP_IRQ_0_EN || s_irq_status & S_GP_IRQ_1_EN) {
+ if (s_irq_status & (S_GP_IRQ_0_EN | S_GP_IRQ_1_EN)) {
if (s_irq_status & S_GP_IRQ_0_EN)
uport->icount.parity++;
drop_rx = true;
- } else if (s_irq_status & S_GP_IRQ_2_EN ||
- s_irq_status & S_GP_IRQ_3_EN) {
+ } else if (s_irq_status & (S_GP_IRQ_2_EN | S_GP_IRQ_3_EN)) {
uport->icount.brk++;
port->brk = true;
}
- if (s_irq_status & S_RX_FIFO_WATERMARK_EN ||
- s_irq_status & S_RX_FIFO_LAST_EN)
- qcom_geni_serial_handle_rx(uport, drop_rx);
+ if (dma) {
+ if (dma_tx_status & TX_DMA_DONE)
+ qcom_geni_serial_handle_tx_dma(uport);
+
+ if (dma_rx_status) {
+ if (dma_rx_status & RX_RESET_DONE)
+ goto out_unlock;
+
+ if (dma_rx_status & RX_DMA_PARITY_ERR) {
+ uport->icount.parity++;
+ drop_rx = true;
+ }
+
+ if (dma_rx_status & RX_DMA_BREAK)
+ uport->icount.brk++;
+
+ if (dma_rx_status & (RX_DMA_DONE | RX_EOT))
+ qcom_geni_serial_handle_rx_dma(uport, drop_rx);
+ }
+ } else {
+ if (m_irq_status & m_irq_en &
+ (M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN))
+ qcom_geni_serial_handle_tx_fifo(uport,
+ m_irq_status & M_CMD_DONE_EN,
+ geni_status & M_GENI_CMD_ACTIVE);
+
+ if (s_irq_status & (S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN))
+ qcom_geni_serial_handle_rx_fifo(uport, drop_rx);
+ }
out_unlock:
uart_unlock_and_check_sysrq(uport);
@@ -876,11 +1055,11 @@ static int setup_fifos(struct qcom_geni_serial_port *port)
uport->fifosize =
(port->tx_fifo_depth * port->tx_fifo_width) / BITS_PER_BYTE;
- if (port->rx_fifo && (old_rx_fifo_depth != port->rx_fifo_depth) && port->rx_fifo_depth) {
- port->rx_fifo = devm_krealloc(uport->dev, port->rx_fifo,
- port->rx_fifo_depth * sizeof(u32),
- GFP_KERNEL);
- if (!port->rx_fifo)
+ if (port->rx_buf && (old_rx_fifo_depth != port->rx_fifo_depth) && port->rx_fifo_depth) {
+ port->rx_buf = devm_krealloc(uport->dev, port->rx_buf,
+ port->rx_fifo_depth * sizeof(u32),
+ GFP_KERNEL);
+ if (!port->rx_buf)
return -ENOMEM;
}
@@ -891,11 +1070,13 @@ static int setup_fifos(struct qcom_geni_serial_port *port)
static void qcom_geni_serial_shutdown(struct uart_port *uport)
{
disable_irq(uport->irq);
+ qcom_geni_serial_stop_tx(uport);
+ qcom_geni_serial_stop_rx(uport);
}
static int qcom_geni_serial_port_setup(struct uart_port *uport)
{
- struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
+ struct qcom_geni_serial_port *port = to_dev_port(uport);
u32 rxstale = DEFAULT_BITS_PER_CHAR * STALE_TIMEOUT;
u32 proto;
u32 pin_swap;
@@ -937,7 +1118,7 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport)
geni_se_config_packing(&port->se, BITS_PER_BYTE, BYTES_PER_FIFO_WORD,
false, true, true);
geni_se_init(&port->se, UART_RX_WM, port->rx_fifo_depth - 2);
- geni_se_select_mode(&port->se, GENI_SE_FIFO);
+ geni_se_select_mode(&port->se, port->dev_data->mode);
qcom_geni_serial_start_rx(uport);
port->setup = true;
@@ -947,7 +1128,7 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport)
static int qcom_geni_serial_startup(struct uart_port *uport)
{
int ret;
- struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
+ struct qcom_geni_serial_port *port = to_dev_port(uport);
if (!port->setup) {
ret = qcom_geni_serial_port_setup(uport);
@@ -1033,7 +1214,7 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport,
u32 stop_bit_len;
unsigned int clk_div;
u32 ser_clk_cfg;
- struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
+ struct qcom_geni_serial_port *port = to_dev_port(uport);
unsigned long clk_rate;
u32 ver, sampling_rate;
unsigned int avg_bw_core;
@@ -1137,11 +1318,6 @@ out_restart_rx:
qcom_geni_serial_start_rx(uport);
}
-static unsigned int qcom_geni_serial_tx_empty(struct uart_port *uport)
-{
- return !readl(uport->membase + SE_GENI_TX_FIFO_STATUS);
-}
-
#ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE
static int qcom_geni_console_setup(struct console *co, char *options)
{
@@ -1323,7 +1499,7 @@ static struct uart_driver qcom_geni_uart_driver = {
static void qcom_geni_serial_pm(struct uart_port *uport,
unsigned int new_state, unsigned int old_state)
{
- struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
+ struct qcom_geni_serial_port *port = to_dev_port(uport);
/* If we've never been called, treat it as off */
if (old_state == UART_PM_STATE_UNDEFINED)
@@ -1341,10 +1517,10 @@ static void qcom_geni_serial_pm(struct uart_port *uport,
static const struct uart_ops qcom_geni_console_pops = {
.tx_empty = qcom_geni_serial_tx_empty,
- .stop_tx = qcom_geni_serial_stop_tx,
- .start_tx = qcom_geni_serial_start_tx,
- .stop_rx = qcom_geni_serial_stop_rx,
- .start_rx = qcom_geni_serial_start_rx,
+ .stop_tx = qcom_geni_serial_stop_tx_fifo,
+ .start_tx = qcom_geni_serial_start_tx_fifo,
+ .stop_rx = qcom_geni_serial_stop_rx_fifo,
+ .start_rx = qcom_geni_serial_start_rx_fifo,
.set_termios = qcom_geni_serial_set_termios,
.startup = qcom_geni_serial_startup,
.request_port = qcom_geni_serial_request_port,
@@ -1362,9 +1538,10 @@ static const struct uart_ops qcom_geni_console_pops = {
static const struct uart_ops qcom_geni_uart_pops = {
.tx_empty = qcom_geni_serial_tx_empty,
- .stop_tx = qcom_geni_serial_stop_tx,
- .start_tx = qcom_geni_serial_start_tx,
- .stop_rx = qcom_geni_serial_stop_rx,
+ .stop_tx = qcom_geni_serial_stop_tx_dma,
+ .start_tx = qcom_geni_serial_start_tx_dma,
+ .start_rx = qcom_geni_serial_start_rx_dma,
+ .stop_rx = qcom_geni_serial_stop_rx_dma,
.set_termios = qcom_geni_serial_set_termios,
.startup = qcom_geni_serial_startup,
.request_port = qcom_geni_serial_request_port,
@@ -1384,13 +1561,14 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
struct uart_port *uport;
struct resource *res;
int irq;
- bool console = false;
struct uart_driver *drv;
+ const struct qcom_geni_device_data *data;
- if (of_device_is_compatible(pdev->dev.of_node, "qcom,geni-debug-uart"))
- console = true;
+ data = of_device_get_match_data(&pdev->dev);
+ if (!data)
+ return -EINVAL;
- if (console) {
+ if (data->console) {
drv = &qcom_geni_console_driver;
line = of_alias_get_id(pdev->dev.of_node, "serial");
} else {
@@ -1400,7 +1578,7 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
line = of_alias_get_id(pdev->dev.of_node, "hsuart");
}
- port = get_port_from_line(line, console);
+ port = get_port_from_line(line, data->console);
if (IS_ERR(port)) {
dev_err(&pdev->dev, "Invalid line %d\n", line);
return PTR_ERR(port);
@@ -1412,6 +1590,7 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
return -ENODEV;
uport->dev = &pdev->dev;
+ port->dev_data = data;
port->se.dev = &pdev->dev;
port->se.wrapper = dev_get_drvdata(pdev->dev.parent);
port->se.clk = devm_clk_get(&pdev->dev, "se");
@@ -1430,10 +1609,10 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
port->rx_fifo_depth = DEF_FIFO_DEPTH_WORDS;
port->tx_fifo_width = DEF_FIFO_WIDTH_BITS;
- if (!console) {
- port->rx_fifo = devm_kcalloc(uport->dev,
- port->rx_fifo_depth, sizeof(u32), GFP_KERNEL);
- if (!port->rx_fifo)
+ if (!data->console) {
+ port->rx_buf = devm_kzalloc(uport->dev,
+ DMA_RX_BUF_SIZE, GFP_KERNEL);
+ if (!port->rx_buf)
return -ENOMEM;
}
@@ -1460,7 +1639,7 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
uport->irq = irq;
uport->has_sysrq = IS_ENABLED(CONFIG_SERIAL_QCOM_GENI_CONSOLE);
- if (!console)
+ if (!data->console)
port->wakeup_irq = platform_get_irq_optional(pdev, 1);
if (of_property_read_bool(pdev->dev.of_node, "rx-tx-swap"))
@@ -1482,7 +1661,6 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
port->private_data.drv = drv;
uport->private_data = &port->private_data;
platform_set_drvdata(pdev, port);
- port->handle_rx = console ? handle_rx_console : handle_rx_uart;
ret = uart_add_one_port(drv, uport);
if (ret)
@@ -1594,6 +1772,16 @@ static int qcom_geni_serial_sys_hib_resume(struct device *dev)
return ret;
}
+static const struct qcom_geni_device_data qcom_geni_console_data = {
+ .console = true,
+ .mode = GENI_SE_FIFO,
+};
+
+static const struct qcom_geni_device_data qcom_geni_uart_data = {
+ .console = false,
+ .mode = GENI_SE_DMA,
+};
+
static const struct dev_pm_ops qcom_geni_serial_pm_ops = {
.suspend = pm_sleep_ptr(qcom_geni_serial_sys_suspend),
.resume = pm_sleep_ptr(qcom_geni_serial_sys_resume),
@@ -1604,8 +1792,14 @@ static const struct dev_pm_ops qcom_geni_serial_pm_ops = {
};
static const struct of_device_id qcom_geni_serial_match_table[] = {
- { .compatible = "qcom,geni-debug-uart", },
- { .compatible = "qcom,geni-uart", },
+ {
+ .compatible = "qcom,geni-debug-uart",
+ .data = &qcom_geni_console_data,
+ },
+ {
+ .compatible = "qcom,geni-uart",
+ .data = &qcom_geni_uart_data,
+ },
{}
};
MODULE_DEVICE_TABLE(of, qcom_geni_serial_match_table);
diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
index 39f92eb1e698..29c94be09159 100644
--- a/drivers/tty/serial/sc16is7xx.c
+++ b/drivers/tty/serial/sc16is7xx.c
@@ -1423,25 +1423,6 @@ static int sc16is7xx_probe(struct device *dev,
}
sched_set_fifo(s->kworker_task);
-#ifdef CONFIG_GPIOLIB
- if (devtype->nr_gpio) {
- /* Setup GPIO cotroller */
- s->gpio.owner = THIS_MODULE;
- s->gpio.parent = dev;
- s->gpio.label = dev_name(dev);
- s->gpio.direction_input = sc16is7xx_gpio_direction_input;
- s->gpio.get = sc16is7xx_gpio_get;
- s->gpio.direction_output = sc16is7xx_gpio_direction_output;
- s->gpio.set = sc16is7xx_gpio_set;
- s->gpio.base = -1;
- s->gpio.ngpio = devtype->nr_gpio;
- s->gpio.can_sleep = 1;
- ret = gpiochip_add_data(&s->gpio, s);
- if (ret)
- goto out_thread;
- }
-#endif
-
/* reset device, purging any pending irq / data */
regmap_write(s->regmap, SC16IS7XX_IOCONTROL_REG << SC16IS7XX_REG_SHIFT,
SC16IS7XX_IOCONTROL_SRESET_BIT);
@@ -1518,6 +1499,25 @@ static int sc16is7xx_probe(struct device *dev,
s->p[u].irda_mode = true;
}
+#ifdef CONFIG_GPIOLIB
+ if (devtype->nr_gpio) {
+ /* Setup GPIO cotroller */
+ s->gpio.owner = THIS_MODULE;
+ s->gpio.parent = dev;
+ s->gpio.label = dev_name(dev);
+ s->gpio.direction_input = sc16is7xx_gpio_direction_input;
+ s->gpio.get = sc16is7xx_gpio_get;
+ s->gpio.direction_output = sc16is7xx_gpio_direction_output;
+ s->gpio.set = sc16is7xx_gpio_set;
+ s->gpio.base = -1;
+ s->gpio.ngpio = devtype->nr_gpio;
+ s->gpio.can_sleep = 1;
+ ret = gpiochip_add_data(&s->gpio, s);
+ if (ret)
+ goto out_thread;
+ }
+#endif
+
/*
* Setup interrupt. We first try to acquire the IRQ line as level IRQ.
* If that succeeds, we can allow sharing the interrupt as well.
@@ -1537,18 +1537,19 @@ static int sc16is7xx_probe(struct device *dev,
if (!ret)
return 0;
-out_ports:
- for (i--; i >= 0; i--) {
- uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port);
- clear_bit(s->p[i].port.line, &sc16is7xx_lines);
- }
-
#ifdef CONFIG_GPIOLIB
if (devtype->nr_gpio)
gpiochip_remove(&s->gpio);
out_thread:
#endif
+
+out_ports:
+ for (i--; i >= 0; i--) {
+ uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port);
+ clear_bit(s->p[i].port.line, &sc16is7xx_lines);
+ }
+
kthread_stop(s->kworker_task);
out_clk:
diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c
index 7df687822634..4f2fc5f7bb19 100644
--- a/drivers/tty/serial/sccnxp.c
+++ b/drivers/tty/serial/sccnxp.c
@@ -913,23 +913,13 @@ static int sccnxp_probe(struct platform_device *pdev)
} else if (PTR_ERR(s->regulator) == -EPROBE_DEFER)
return -EPROBE_DEFER;
- clk = devm_clk_get(&pdev->dev, NULL);
+ clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
if (ret == -EPROBE_DEFER)
goto err_out;
uartclk = 0;
} else {
- ret = clk_prepare_enable(clk);
- if (ret)
- goto err_out;
-
- ret = devm_add_action_or_reset(&pdev->dev,
- (void(*)(void *))clk_disable_unprepare,
- clk);
- if (ret)
- goto err_out;
-
uartclk = clk_get_rate(clk);
}
diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c
index e5b9773db5e3..1cf08b33456c 100644
--- a/drivers/tty/serial/serial-tegra.c
+++ b/drivers/tty/serial/serial-tegra.c
@@ -1046,6 +1046,7 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup)
if (tup->cdata->fifo_mode_enable_status) {
ret = tegra_uart_wait_fifo_mode_enabled(tup);
if (ret < 0) {
+ clk_disable_unprepare(tup->uart_clk);
dev_err(tup->uport.dev,
"Failed to enable FIFO mode: %d\n", ret);
return ret;
@@ -1067,6 +1068,7 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup)
*/
ret = tegra_set_baudrate(tup, TEGRA_UART_DEFAULT_BAUD);
if (ret < 0) {
+ clk_disable_unprepare(tup->uart_clk);
dev_err(tup->uport.dev, "Failed to set baud rate\n");
return ret;
}
@@ -1226,10 +1228,13 @@ static int tegra_uart_startup(struct uart_port *u)
dev_name(u->dev), tup);
if (ret < 0) {
dev_err(u->dev, "Failed to register ISR for IRQ %d\n", u->irq);
- goto fail_hw_init;
+ goto fail_request_irq;
}
return 0;
+fail_request_irq:
+ /* tup->uart_clk is already enabled in tegra_uart_hw_init */
+ clk_disable_unprepare(tup->uart_clk);
fail_hw_init:
if (!tup->use_rx_pio)
tegra_uart_dma_channel_free(tup, true);
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index ec874f3a567c..2bd32c8ece39 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -169,9 +169,9 @@ uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear)
#define uart_set_mctrl(port, set) uart_update_mctrl(port, set, 0)
#define uart_clear_mctrl(port, clear) uart_update_mctrl(port, 0, clear)
-static void uart_port_dtr_rts(struct uart_port *uport, int raise)
+static void uart_port_dtr_rts(struct uart_port *uport, bool active)
{
- if (raise)
+ if (active)
uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
else
uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
@@ -182,7 +182,7 @@ static void uart_port_dtr_rts(struct uart_port *uport, int raise)
* will be serialised by the per-port mutex.
*/
static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
- int init_hw)
+ bool init_hw)
{
struct uart_port *uport = uart_port_check(state);
unsigned long flags;
@@ -239,7 +239,7 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
* port is open and ready to respond.
*/
if (init_hw && C_BAUD(tty))
- uart_port_dtr_rts(uport, 1);
+ uart_port_dtr_rts(uport, true);
}
/*
@@ -254,7 +254,7 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
}
static int uart_startup(struct tty_struct *tty, struct uart_state *state,
- int init_hw)
+ bool init_hw)
{
struct tty_port *port = &state->port;
int retval;
@@ -290,7 +290,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
set_bit(TTY_IO_ERROR, &tty->flags);
if (tty_port_initialized(port)) {
- tty_port_set_initialized(port, 0);
+ tty_port_set_initialized(port, false);
/*
* Turn off DTR and RTS early.
@@ -302,7 +302,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
}
if (!tty || C_HUPCL(tty))
- uart_port_dtr_rts(uport, 0);
+ uart_port_dtr_rts(uport, false);
uart_port_shutdown(port);
}
@@ -312,7 +312,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
* a DCD drop (hangup) at just the right time. Clear suspended bit so
* we don't try to resume a port that has been shutdown.
*/
- tty_port_set_suspended(port, 0);
+ tty_port_set_suspended(port, false);
/*
* Do not free() the transmit buffer page under the port lock since
@@ -997,7 +997,7 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
uart_change_speed(tty, state, NULL);
}
} else {
- retval = uart_startup(tty, state, 1);
+ retval = uart_startup(tty, state, true);
if (retval == 0)
tty_port_set_initialized(port, true);
if (retval > 0)
@@ -1165,7 +1165,7 @@ static int uart_do_autoconfig(struct tty_struct *tty, struct uart_state *state)
*/
uport->ops->config_port(uport, flags);
- ret = uart_startup(tty, state, 1);
+ ret = uart_startup(tty, state, true);
if (ret == 0)
tty_port_set_initialized(port, true);
if (ret > 0)
@@ -1725,7 +1725,7 @@ static void uart_tty_port_shutdown(struct tty_port *port)
* a DCD drop (hangup) at just the right time. Clear suspended bit so
* we don't try to resume a port that has been shutdown.
*/
- tty_port_set_suspended(port, 0);
+ tty_port_set_suspended(port, false);
/*
* Free the transmit buffer.
@@ -1827,7 +1827,7 @@ static void uart_hangup(struct tty_struct *tty)
spin_lock_irqsave(&port->lock, flags);
port->count = 0;
spin_unlock_irqrestore(&port->lock, flags);
- tty_port_set_active(port, 0);
+ tty_port_set_active(port, false);
tty_port_tty_set(port, NULL);
if (uport && !uart_console(uport))
uart_change_pm(state, UART_PM_STATE_OFF);
@@ -1861,7 +1861,7 @@ static void uart_port_shutdown(struct tty_port *port)
}
}
-static int uart_carrier_raised(struct tty_port *port)
+static bool uart_carrier_raised(struct tty_port *port)
{
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport;
@@ -1875,18 +1875,17 @@ static int uart_carrier_raised(struct tty_port *port)
* continue and not sleep
*/
if (WARN_ON(!uport))
- return 1;
+ return true;
spin_lock_irq(&uport->lock);
uart_enable_ms(uport);
mctrl = uport->ops->get_mctrl(uport);
spin_unlock_irq(&uport->lock);
uart_port_deref(uport);
- if (mctrl & TIOCM_CAR)
- return 1;
- return 0;
+
+ return mctrl & TIOCM_CAR;
}
-static void uart_dtr_rts(struct tty_port *port, int raise)
+static void uart_dtr_rts(struct tty_port *port, bool active)
{
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport;
@@ -1894,7 +1893,7 @@ static void uart_dtr_rts(struct tty_port *port, int raise)
uport = uart_port_ref(state);
if (!uport)
return;
- uart_port_dtr_rts(uport, raise);
+ uart_port_dtr_rts(uport, active);
uart_port_deref(uport);
}
@@ -1943,9 +1942,9 @@ static int uart_port_activate(struct tty_port *port, struct tty_struct *tty)
/*
* Start up the serial port.
*/
- ret = uart_startup(tty, state, 0);
+ ret = uart_startup(tty, state, false);
if (ret > 0)
- tty_port_set_active(port, 1);
+ tty_port_set_active(port, true);
return ret;
}
@@ -2349,8 +2348,8 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
int tries;
unsigned int mctrl;
- tty_port_set_suspended(port, 1);
- tty_port_set_initialized(port, 0);
+ tty_port_set_suspended(port, true);
+ tty_port_set_initialized(port, false);
spin_lock_irq(&uport->lock);
ops->stop_tx(uport);
@@ -2461,7 +2460,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
uart_rs485_config(uport);
ops->start_tx(uport);
spin_unlock_irq(&uport->lock);
- tty_port_set_initialized(port, 1);
+ tty_port_set_initialized(port, true);
} else {
/*
* Failed to resume - maybe hardware went away?
@@ -2472,7 +2471,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
}
}
- tty_port_set_suspended(port, 0);
+ tty_port_set_suspended(port, false);
}
mutex_unlock(&port->mutex);
@@ -3258,11 +3257,11 @@ EXPORT_SYMBOL(uart_match_port);
/**
* uart_handle_dcd_change - handle a change of carrier detect state
* @uport: uart_port structure for the open port
- * @status: new carrier detect status, nonzero if active
+ * @active: new carrier detect status
*
* Caller must hold uport->lock.
*/
-void uart_handle_dcd_change(struct uart_port *uport, unsigned int status)
+void uart_handle_dcd_change(struct uart_port *uport, bool active)
{
struct tty_port *port = &uport->state->port;
struct tty_struct *tty = port->tty;
@@ -3274,7 +3273,7 @@ void uart_handle_dcd_change(struct uart_port *uport, unsigned int status)
ld = tty_ldisc_ref(tty);
if (ld) {
if (ld->ops->dcd_change)
- ld->ops->dcd_change(tty, status);
+ ld->ops->dcd_change(tty, active);
tty_ldisc_deref(ld);
}
}
@@ -3282,7 +3281,7 @@ void uart_handle_dcd_change(struct uart_port *uport, unsigned int status)
uport->icount.dcd++;
if (uart_dcd_enabled(uport)) {
- if (status)
+ if (active)
wake_up_interruptible(&port->open_wait);
else if (tty)
tty_hangup(tty);
@@ -3293,11 +3292,11 @@ EXPORT_SYMBOL_GPL(uart_handle_dcd_change);
/**
* uart_handle_cts_change - handle a change of clear-to-send state
* @uport: uart_port structure for the open port
- * @status: new clear to send status, nonzero if active
+ * @active: new clear-to-send status
*
* Caller must hold uport->lock.
*/
-void uart_handle_cts_change(struct uart_port *uport, unsigned int status)
+void uart_handle_cts_change(struct uart_port *uport, bool active)
{
lockdep_assert_held_once(&uport->lock);
@@ -3305,13 +3304,13 @@ void uart_handle_cts_change(struct uart_port *uport, unsigned int status)
if (uart_softcts_mode(uport)) {
if (uport->hw_stopped) {
- if (status) {
+ if (active) {
uport->hw_stopped = 0;
uport->ops->start_tx(uport);
uart_write_wakeup(uport);
}
} else {
- if (!status) {
+ if (!active) {
uport->hw_stopped = 1;
uport->ops->stop_tx(uport);
}
@@ -3415,6 +3414,7 @@ int uart_get_rs485_mode(struct uart_port *port)
struct device *dev = port->dev;
u32 rs485_delay[2];
int ret;
+ int rx_during_tx_gpio_flag;
ret = device_property_read_u32_array(dev, "rs485-rts-delay",
rs485_delay, 2);
@@ -3463,6 +3463,17 @@ int uart_get_rs485_mode(struct uart_port *port)
if (port->rs485_term_gpio)
port->rs485_supported.flags |= SER_RS485_TERMINATE_BUS;
+ rx_during_tx_gpio_flag = (rs485conf->flags & SER_RS485_RX_DURING_TX) ?
+ GPIOD_OUT_HIGH : GPIOD_OUT_LOW;
+ port->rs485_rx_during_tx_gpio = devm_gpiod_get_optional(dev,
+ "rs485-rx-during-tx",
+ rx_during_tx_gpio_flag);
+ if (IS_ERR(port->rs485_rx_during_tx_gpio)) {
+ ret = PTR_ERR(port->rs485_rx_during_tx_gpio);
+ port->rs485_rx_during_tx_gpio = NULL;
+ return dev_err_probe(dev, ret, "Cannot get rs485-rx-during-tx-gpios\n");
+ }
+
return 0;
}
EXPORT_SYMBOL_GPL(uart_get_rs485_mode);
diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 409e91d6829a..767ff9fdb2e5 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -226,7 +226,11 @@ static int stm32_usart_config_rs485(struct uart_port *port, struct ktermios *ter
stm32_usart_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));
- rs485conf->flags |= SER_RS485_RX_DURING_TX;
+ if (port->rs485_rx_during_tx_gpio)
+ gpiod_set_value_cansleep(port->rs485_rx_during_tx_gpio,
+ !!(rs485conf->flags & SER_RS485_RX_DURING_TX));
+ else
+ rs485conf->flags |= SER_RS485_RX_DURING_TX;
if (rs485conf->flags & SER_RS485_ENABLED) {
cr1 = readl_relaxed(port->membase + ofs->cr1);
diff --git a/drivers/tty/serial/sunhv.c b/drivers/tty/serial/sunhv.c
index 16c746a63258..7d38c33ef506 100644
--- a/drivers/tty/serial/sunhv.c
+++ b/drivers/tty/serial/sunhv.c
@@ -87,10 +87,10 @@ static int receive_chars_getchar(struct uart_port *port)
if (c == CON_HUP) {
hung_up = 1;
- uart_handle_dcd_change(port, 0);
+ uart_handle_dcd_change(port, false);
} else if (hung_up) {
hung_up = 0;
- uart_handle_dcd_change(port, 1);
+ uart_handle_dcd_change(port, true);
}
if (port->state == NULL) {
@@ -133,7 +133,7 @@ static int receive_chars_read(struct uart_port *port)
bytes_read = 1;
} else if (stat == CON_HUP) {
hung_up = 1;
- uart_handle_dcd_change(port, 0);
+ uart_handle_dcd_change(port, false);
continue;
} else {
/* HV_EWOULDBLOCK, etc. */
@@ -143,7 +143,7 @@ static int receive_chars_read(struct uart_port *port)
if (hung_up) {
hung_up = 0;
- uart_handle_dcd_change(port, 1);
+ uart_handle_dcd_change(port, true);
}
if (port->sysrq != 0 && *con_read_page) {
diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c
index b09b6496ee3e..32c7a5b43f8e 100644
--- a/drivers/tty/serial/ucc_uart.c
+++ b/drivers/tty/serial/ucc_uart.c
@@ -1468,6 +1468,8 @@ static int ucc_uart_remove(struct platform_device *ofdev)
uart_remove_one_port(&ucc_uart_driver, &qe_port->port);
+ of_node_put(qe_port->np);
+
kfree(qe_port);
return 0;
diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c
index 72b76cdde534..33f258d6fef9 100644
--- a/drivers/tty/synclink_gt.c
+++ b/drivers/tty/synclink_gt.c
@@ -694,7 +694,7 @@ static void hangup(struct tty_struct *tty)
info->port.count = 0;
info->port.tty = NULL;
spin_unlock_irqrestore(&info->port.lock, flags);
- tty_port_set_active(&info->port, 0);
+ tty_port_set_active(&info->port, false);
mutex_unlock(&info->port.mutex);
wake_up_interruptible(&info->port.open_wait);
@@ -2354,7 +2354,7 @@ static int startup(struct slgt_info *info)
if (info->port.tty)
clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
- tty_port_set_initialized(&info->port, 1);
+ tty_port_set_initialized(&info->port, true);
return 0;
}
@@ -2401,7 +2401,7 @@ static void shutdown(struct slgt_info *info)
if (info->port.tty)
set_bit(TTY_IO_ERROR, &info->port.tty->flags);
- tty_port_set_initialized(&info->port, 0);
+ tty_port_set_initialized(&info->port, false);
}
static void program_hw(struct slgt_info *info)
@@ -3126,7 +3126,7 @@ static int tiocmset(struct tty_struct *tty,
return 0;
}
-static int carrier_raised(struct tty_port *port)
+static bool carrier_raised(struct tty_port *port)
{
unsigned long flags;
struct slgt_info *info = container_of(port, struct slgt_info, port);
@@ -3134,16 +3134,17 @@ static int carrier_raised(struct tty_port *port)
spin_lock_irqsave(&info->lock,flags);
get_gtsignals(info);
spin_unlock_irqrestore(&info->lock,flags);
- return (info->signals & SerialSignal_DCD) ? 1 : 0;
+
+ return info->signals & SerialSignal_DCD;
}
-static void dtr_rts(struct tty_port *port, int on)
+static void dtr_rts(struct tty_port *port, bool active)
{
unsigned long flags;
struct slgt_info *info = container_of(port, struct slgt_info, port);
spin_lock_irqsave(&info->lock,flags);
- if (on)
+ if (active)
info->signals |= SerialSignal_RTS | SerialSignal_DTR;
else
info->signals &= ~(SerialSignal_RTS | SerialSignal_DTR);
@@ -3162,14 +3163,14 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
int retval;
bool do_clocal = false;
unsigned long flags;
- int cd;
+ bool cd;
struct tty_port *port = &info->port;
DBGINFO(("%s block_til_ready\n", tty->driver->name));
if (filp->f_flags & O_NONBLOCK || tty_io_error(tty)) {
/* nonblock mode is set or port is not enabled */
- tty_port_set_active(port, 1);
+ tty_port_set_active(port, true);
return 0;
}
@@ -3226,7 +3227,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
port->blocked_open--;
if (!retval)
- tty_port_set_active(port, 1);
+ tty_port_set_active(port, true);
DBGINFO(("%s block_til_ready ready, rc=%d\n", tty->driver->name, retval));
return retval;
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 3149114bf130..36fb945fdad4 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -1224,14 +1224,16 @@ static struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver,
{
struct tty_struct *tty;
- if (driver->ops->lookup)
+ if (driver->ops->lookup) {
if (!file)
tty = ERR_PTR(-EIO);
else
tty = driver->ops->lookup(driver, file, idx);
- else
+ } else {
+ if (idx >= driver->num)
+ return ERR_PTR(-EINVAL);
tty = driver->ttys[idx];
-
+ }
if (!IS_ERR(tty))
tty_kref_get(tty);
return tty;
diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c
index ce511557b98b..12983ce4e43e 100644
--- a/drivers/tty/tty_ioctl.c
+++ b/drivers/tty/tty_ioctl.c
@@ -270,13 +270,13 @@ EXPORT_SYMBOL(tty_termios_copy_hw);
* between the two termios structures, or a speed change is needed.
*/
-int tty_termios_hw_change(const struct ktermios *a, const struct ktermios *b)
+bool tty_termios_hw_change(const struct ktermios *a, const struct ktermios *b)
{
if (a->c_ispeed != b->c_ispeed || a->c_ospeed != b->c_ospeed)
- return 1;
+ return true;
if ((a->c_cflag ^ b->c_cflag) & ~(HUPCL | CREAD | CLOCAL))
- return 1;
- return 0;
+ return true;
+ return false;
}
EXPORT_SYMBOL(tty_termios_hw_change);
diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
index dce08a6d7b5e..a788a6bf487d 100644
--- a/drivers/tty/tty_port.c
+++ b/drivers/tty/tty_port.c
@@ -367,7 +367,7 @@ static void tty_port_shutdown(struct tty_port *port, struct tty_struct *tty)
goto out;
if (tty_port_initialized(port)) {
- tty_port_set_initialized(port, 0);
+ tty_port_set_initialized(port, false);
/*
* Drop DTR/RTS if HUPCL is set. This causes any attached
* modem to hang up the line.
@@ -403,7 +403,7 @@ void tty_port_hangup(struct tty_port *port)
set_bit(TTY_IO_ERROR, &tty->flags);
port->tty = NULL;
spin_unlock_irqrestore(&port->lock, flags);
- tty_port_set_active(port, 0);
+ tty_port_set_active(port, false);
tty_port_shutdown(port, tty);
tty_kref_put(tty);
wake_up_interruptible(&port->open_wait);
@@ -444,10 +444,10 @@ EXPORT_SYMBOL_GPL(tty_port_tty_wakeup);
* to hide some internal details. This will eventually become entirely
* internal to the tty port.
*/
-int tty_port_carrier_raised(struct tty_port *port)
+bool tty_port_carrier_raised(struct tty_port *port)
{
if (port->ops->carrier_raised == NULL)
- return 1;
+ return true;
return port->ops->carrier_raised(port);
}
EXPORT_SYMBOL(tty_port_carrier_raised);
@@ -463,7 +463,7 @@ EXPORT_SYMBOL(tty_port_carrier_raised);
void tty_port_raise_dtr_rts(struct tty_port *port)
{
if (port->ops->dtr_rts)
- port->ops->dtr_rts(port, 1);
+ port->ops->dtr_rts(port, true);
}
EXPORT_SYMBOL(tty_port_raise_dtr_rts);
@@ -478,7 +478,7 @@ EXPORT_SYMBOL(tty_port_raise_dtr_rts);
void tty_port_lower_dtr_rts(struct tty_port *port)
{
if (port->ops->dtr_rts)
- port->ops->dtr_rts(port, 0);
+ port->ops->dtr_rts(port, false);
}
EXPORT_SYMBOL(tty_port_lower_dtr_rts);
@@ -518,14 +518,14 @@ int tty_port_block_til_ready(struct tty_port *port,
* the port has just hung up or is in another error state.
*/
if (tty_io_error(tty)) {
- tty_port_set_active(port, 1);
+ tty_port_set_active(port, true);
return 0;
}
if (filp == NULL || (filp->f_flags & O_NONBLOCK)) {
/* Indicate we are open */
if (C_BAUD(tty))
tty_port_raise_dtr_rts(port);
- tty_port_set_active(port, 1);
+ tty_port_set_active(port, true);
return 0;
}
@@ -588,7 +588,7 @@ int tty_port_block_til_ready(struct tty_port *port,
port->blocked_open--;
spin_unlock_irqrestore(&port->lock, flags);
if (retval == 0)
- tty_port_set_active(port, 1);
+ tty_port_set_active(port, true);
return retval;
}
EXPORT_SYMBOL(tty_port_block_til_ready);
@@ -695,7 +695,7 @@ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
wake_up_interruptible(&port->open_wait);
}
spin_unlock_irqrestore(&port->lock, flags);
- tty_port_set_active(port, 0);
+ tty_port_set_active(port, false);
}
EXPORT_SYMBOL(tty_port_close_end);
@@ -788,7 +788,7 @@ int tty_port_open(struct tty_port *port, struct tty_struct *tty,
return retval;
}
}
- tty_port_set_initialized(port, 1);
+ tty_port_set_initialized(port, true);
}
mutex_unlock(&port->mutex);
return tty_port_block_til_ready(port, tty, filp);
diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c
index f566eb1839dc..1dc07f9214d5 100644
--- a/drivers/tty/vt/vc_screen.c
+++ b/drivers/tty/vt/vc_screen.c
@@ -403,10 +403,11 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
unsigned int this_round, skip = 0;
int size;
- ret = -ENXIO;
vc = vcs_vc(inode, &viewed);
- if (!vc)
- goto unlock_out;
+ if (!vc) {
+ ret = -ENXIO;
+ break;
+ }
/* Check whether we are above size each round,
* as copy_to_user at the end of this loop
@@ -414,10 +415,8 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
*/
size = vcs_size(vc, attr, uni_mode);
if (size < 0) {
- if (read)
- break;
ret = size;
- goto unlock_out;
+ break;
}
if (pos >= size)
break;
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 981d2bfcf9a5..57a5c23b51d4 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -316,73 +316,55 @@ void schedule_console_callback(void)
* Code to manage unicode-based screen buffers
*/
-#ifdef NO_VC_UNI_SCREEN
-/* this disables and optimizes related code away at compile time */
-#define get_vc_uniscr(vc) NULL
-#else
-#define get_vc_uniscr(vc) vc->vc_uni_screen
-#endif
-
-#define VC_UNI_SCREEN_DEBUG 0
-
-typedef uint32_t char32_t;
-
/*
* Our screen buffer is preceded by an array of line pointers so that
* scrolling only implies some pointer shuffling.
*/
-struct uni_screen {
- char32_t *lines[0];
-};
-static struct uni_screen *vc_uniscr_alloc(unsigned int cols, unsigned int rows)
+static u32 **vc_uniscr_alloc(unsigned int cols, unsigned int rows)
{
- struct uni_screen *uniscr;
+ u32 **uni_lines;
void *p;
- unsigned int memsize, i;
+ unsigned int memsize, i, col_size = cols * sizeof(**uni_lines);
/* allocate everything in one go */
- memsize = cols * rows * sizeof(char32_t);
- memsize += rows * sizeof(char32_t *);
- p = vzalloc(memsize);
- if (!p)
+ memsize = col_size * rows;
+ memsize += rows * sizeof(*uni_lines);
+ uni_lines = vzalloc(memsize);
+ if (!uni_lines)
return NULL;
/* initial line pointers */
- uniscr = p;
- p = uniscr->lines + rows;
+ p = uni_lines + rows;
for (i = 0; i < rows; i++) {
- uniscr->lines[i] = p;
- p += cols * sizeof(char32_t);
+ uni_lines[i] = p;
+ p += col_size;
}
- return uniscr;
+
+ return uni_lines;
}
-static void vc_uniscr_free(struct uni_screen *uniscr)
+static void vc_uniscr_free(u32 **uni_lines)
{
- vfree(uniscr);
+ vfree(uni_lines);
}
-static void vc_uniscr_set(struct vc_data *vc, struct uni_screen *new_uniscr)
+static void vc_uniscr_set(struct vc_data *vc, u32 **new_uni_lines)
{
- vc_uniscr_free(vc->vc_uni_screen);
- vc->vc_uni_screen = new_uniscr;
+ vc_uniscr_free(vc->vc_uni_lines);
+ vc->vc_uni_lines = new_uni_lines;
}
-static void vc_uniscr_putc(struct vc_data *vc, char32_t uc)
+static void vc_uniscr_putc(struct vc_data *vc, u32 uc)
{
- struct uni_screen *uniscr = get_vc_uniscr(vc);
-
- if (uniscr)
- uniscr->lines[vc->state.y][vc->state.x] = uc;
+ if (vc->vc_uni_lines)
+ vc->vc_uni_lines[vc->state.y][vc->state.x] = uc;
}
static void vc_uniscr_insert(struct vc_data *vc, unsigned int nr)
{
- struct uni_screen *uniscr = get_vc_uniscr(vc);
-
- if (uniscr) {
- char32_t *ln = uniscr->lines[vc->state.y];
+ if (vc->vc_uni_lines) {
+ u32 *ln = vc->vc_uni_lines[vc->state.y];
unsigned int x = vc->state.x, cols = vc->vc_cols;
memmove(&ln[x + nr], &ln[x], (cols - x - nr) * sizeof(*ln));
@@ -392,10 +374,8 @@ static void vc_uniscr_insert(struct vc_data *vc, unsigned int nr)
static void vc_uniscr_delete(struct vc_data *vc, unsigned int nr)
{
- struct uni_screen *uniscr = get_vc_uniscr(vc);
-
- if (uniscr) {
- char32_t *ln = uniscr->lines[vc->state.y];
+ if (vc->vc_uni_lines) {
+ u32 *ln = vc->vc_uni_lines[vc->state.y];
unsigned int x = vc->state.x, cols = vc->vc_cols;
memcpy(&ln[x], &ln[x + nr], (cols - x - nr) * sizeof(*ln));
@@ -406,86 +386,84 @@ static void vc_uniscr_delete(struct vc_data *vc, unsigned int nr)
static void vc_uniscr_clear_line(struct vc_data *vc, unsigned int x,
unsigned int nr)
{
- struct uni_screen *uniscr = get_vc_uniscr(vc);
-
- if (uniscr) {
- char32_t *ln = uniscr->lines[vc->state.y];
-
- memset32(&ln[x], ' ', nr);
- }
+ if (vc->vc_uni_lines)
+ memset32(&vc->vc_uni_lines[vc->state.y][x], ' ', nr);
}
static void vc_uniscr_clear_lines(struct vc_data *vc, unsigned int y,
unsigned int nr)
{
- struct uni_screen *uniscr = get_vc_uniscr(vc);
+ if (vc->vc_uni_lines)
+ while (nr--)
+ memset32(vc->vc_uni_lines[y++], ' ', vc->vc_cols);
+}
+
+/* juggling array rotation algorithm (complexity O(N), size complexity O(1)) */
+static void juggle_array(u32 **array, unsigned int size, unsigned int nr)
+{
+ unsigned int gcd_idx;
- if (uniscr) {
- unsigned int cols = vc->vc_cols;
+ for (gcd_idx = 0; gcd_idx < gcd(nr, size); gcd_idx++) {
+ u32 *gcd_idx_val = array[gcd_idx];
+ unsigned int dst_idx = gcd_idx;
- while (nr--)
- memset32(uniscr->lines[y++], ' ', cols);
+ while (1) {
+ unsigned int src_idx = (dst_idx + nr) % size;
+ if (src_idx == gcd_idx)
+ break;
+
+ array[dst_idx] = array[src_idx];
+ dst_idx = src_idx;
+ }
+
+ array[dst_idx] = gcd_idx_val;
}
}
-static void vc_uniscr_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
- enum con_scroll dir, unsigned int nr)
+static void vc_uniscr_scroll(struct vc_data *vc, unsigned int top,
+ unsigned int bottom, enum con_scroll dir,
+ unsigned int nr)
{
- struct uni_screen *uniscr = get_vc_uniscr(vc);
+ u32 **uni_lines = vc->vc_uni_lines;
+ unsigned int size = bottom - top;
- if (uniscr) {
- unsigned int i, j, k, sz, d, clear;
+ if (!uni_lines)
+ return;
- sz = b - t;
- clear = b - nr;
- d = nr;
- if (dir == SM_DOWN) {
- clear = t;
- d = sz - nr;
- }
- for (i = 0; i < gcd(d, sz); i++) {
- char32_t *tmp = uniscr->lines[t + i];
- j = i;
- while (1) {
- k = j + d;
- if (k >= sz)
- k -= sz;
- if (k == i)
- break;
- uniscr->lines[t + j] = uniscr->lines[t + k];
- j = k;
- }
- uniscr->lines[t + j] = tmp;
- }
- vc_uniscr_clear_lines(vc, clear, nr);
+ if (dir == SM_DOWN) {
+ juggle_array(&uni_lines[top], size, size - nr);
+ vc_uniscr_clear_lines(vc, top, nr);
+ } else {
+ juggle_array(&uni_lines[top], size, nr);
+ vc_uniscr_clear_lines(vc, bottom - nr, nr);
}
}
-static void vc_uniscr_copy_area(struct uni_screen *dst,
+static void vc_uniscr_copy_area(u32 **dst_lines,
unsigned int dst_cols,
unsigned int dst_rows,
- struct uni_screen *src,
+ u32 **src_lines,
unsigned int src_cols,
unsigned int src_top_row,
unsigned int src_bot_row)
{
unsigned int dst_row = 0;
- if (!dst)
+ if (!dst_lines)
return;
while (src_top_row < src_bot_row) {
- char32_t *src_line = src->lines[src_top_row];
- char32_t *dst_line = dst->lines[dst_row];
+ u32 *src_line = src_lines[src_top_row];
+ u32 *dst_line = dst_lines[dst_row];
- memcpy(dst_line, src_line, src_cols * sizeof(char32_t));
+ memcpy(dst_line, src_line, src_cols * sizeof(*src_line));
if (dst_cols - src_cols)
memset32(dst_line + src_cols, ' ', dst_cols - src_cols);
src_top_row++;
dst_row++;
}
while (dst_row < dst_rows) {
- char32_t *dst_line = dst->lines[dst_row];
+ u32 *dst_line = dst_lines[dst_row];
memset32(dst_line, ' ', dst_cols);
dst_row++;
@@ -500,23 +478,20 @@ static void vc_uniscr_copy_area(struct uni_screen *dst,
*/
int vc_uniscr_check(struct vc_data *vc)
{
- struct uni_screen *uniscr;
+ u32 **uni_lines;
unsigned short *p;
int x, y, mask;
- if (__is_defined(NO_VC_UNI_SCREEN))
- return -EOPNOTSUPP;
-
WARN_CONSOLE_UNLOCKED();
if (!vc->vc_utf)
return -ENODATA;
- if (vc->vc_uni_screen)
+ if (vc->vc_uni_lines)
return 0;
- uniscr = vc_uniscr_alloc(vc->vc_cols, vc->vc_rows);
- if (!uniscr)
+ uni_lines = vc_uniscr_alloc(vc->vc_cols, vc->vc_rows);
+ if (!uni_lines)
return -ENOMEM;
/*
@@ -528,14 +503,15 @@ int vc_uniscr_check(struct vc_data *vc)
p = (unsigned short *)vc->vc_origin;
mask = vc->vc_hi_font_mask | 0xff;
for (y = 0; y < vc->vc_rows; y++) {
- char32_t *line = uniscr->lines[y];
+ u32 *line = uni_lines[y];
for (x = 0; x < vc->vc_cols; x++) {
u16 glyph = scr_readw(p++) & mask;
line[x] = inverse_translate(vc, glyph, true);
}
}
- vc->vc_uni_screen = uniscr;
+ vc->vc_uni_lines = uni_lines;
+
return 0;
}
@@ -547,11 +523,12 @@ int vc_uniscr_check(struct vc_data *vc)
void vc_uniscr_copy_line(const struct vc_data *vc, void *dest, bool viewed,
unsigned int row, unsigned int col, unsigned int nr)
{
- struct uni_screen *uniscr = get_vc_uniscr(vc);
+ u32 **uni_lines = vc->vc_uni_lines;
int offset = row * vc->vc_size_row + col * 2;
unsigned long pos;
- BUG_ON(!uniscr);
+ if (WARN_ON_ONCE(!uni_lines))
+ return;
pos = (unsigned long)screenpos(vc, offset, viewed);
if (pos >= vc->vc_origin && pos < vc->vc_scr_end) {
@@ -562,7 +539,7 @@ void vc_uniscr_copy_line(const struct vc_data *vc, void *dest, bool viewed,
*/
row = (pos - vc->vc_origin) / vc->vc_size_row;
col = ((pos - vc->vc_origin) % vc->vc_size_row) / 2;
- memcpy(dest, &uniscr->lines[row][col], nr * sizeof(char32_t));
+ memcpy(dest, &uni_lines[row][col], nr * sizeof(u32));
} else {
/*
* Scrollback is active. For now let's simply backtranslate
@@ -572,7 +549,7 @@ void vc_uniscr_copy_line(const struct vc_data *vc, void *dest, bool viewed,
*/
u16 *p = (u16 *)pos;
int mask = vc->vc_hi_font_mask | 0xff;
- char32_t *uni_buf = dest;
+ u32 *uni_buf = dest;
while (nr--) {
u16 glyph = scr_readw(p++) & mask;
*uni_buf++ = inverse_translate(vc, glyph, true);
@@ -580,64 +557,31 @@ void vc_uniscr_copy_line(const struct vc_data *vc, void *dest, bool viewed,
}
}
-/* this is for validation and debugging only */
-static void vc_uniscr_debug_check(struct vc_data *vc)
+static void con_scroll(struct vc_data *vc, unsigned int top,
+ unsigned int bottom, enum con_scroll dir,
+ unsigned int nr)
{
- struct uni_screen *uniscr = get_vc_uniscr(vc);
- unsigned short *p;
- int x, y, mask;
+ unsigned int rows = bottom - top;
+ u16 *clear, *dst, *src;
- if (!VC_UNI_SCREEN_DEBUG || !uniscr)
+ if (top + nr >= bottom)
+ nr = rows - 1;
+ if (bottom > vc->vc_rows || top >= bottom || nr < 1)
return;
- WARN_CONSOLE_UNLOCKED();
-
- /*
- * Make sure our unicode screen translates into the same glyphs
- * as the actual screen. This is brutal indeed.
- */
- p = (unsigned short *)vc->vc_origin;
- mask = vc->vc_hi_font_mask | 0xff;
- for (y = 0; y < vc->vc_rows; y++) {
- char32_t *line = uniscr->lines[y];
- for (x = 0; x < vc->vc_cols; x++) {
- u16 glyph = scr_readw(p++) & mask;
- char32_t uc = line[x];
- int tc = conv_uni_to_pc(vc, uc);
- if (tc == -4)
- tc = conv_uni_to_pc(vc, 0xfffd);
- if (tc == -4)
- tc = conv_uni_to_pc(vc, '?');
- if (tc != glyph)
- pr_err_ratelimited(
- "%s: mismatch at %d,%d: glyph=%#x tc=%#x\n",
- __func__, x, y, glyph, tc);
- }
- }
-}
-
-
-static void con_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
- enum con_scroll dir, unsigned int nr)
-{
- u16 *clear, *d, *s;
-
- if (t + nr >= b)
- nr = b - t - 1;
- if (b > vc->vc_rows || t >= b || nr < 1)
- return;
- vc_uniscr_scroll(vc, t, b, dir, nr);
- if (con_is_visible(vc) && vc->vc_sw->con_scroll(vc, t, b, dir, nr))
+ vc_uniscr_scroll(vc, top, bottom, dir, nr);
+ if (con_is_visible(vc) &&
+ vc->vc_sw->con_scroll(vc, top, bottom, dir, nr))
return;
- s = clear = (u16 *)(vc->vc_origin + vc->vc_size_row * t);
- d = (u16 *)(vc->vc_origin + vc->vc_size_row * (t + nr));
+ src = clear = (u16 *)(vc->vc_origin + vc->vc_size_row * top);
+ dst = (u16 *)(vc->vc_origin + vc->vc_size_row * (top + nr));
if (dir == SM_UP) {
- clear = s + (b - t - nr) * vc->vc_cols;
- swap(s, d);
+ clear = src + (rows - nr) * vc->vc_cols;
+ swap(src, dst);
}
- scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row);
+ scr_memmovew(dst, src, (rows - nr) * vc->vc_size_row);
scr_memsetw(clear, vc->vc_video_erase_char, vc->vc_size_row * nr);
}
@@ -1201,7 +1145,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
unsigned int new_cols, new_rows, new_row_size, new_screen_size;
unsigned int user;
unsigned short *oldscreen, *newscreen;
- struct uni_screen *new_uniscr = NULL;
+ u32 **new_uniscr = NULL;
WARN_CONSOLE_UNLOCKED();
@@ -1245,7 +1189,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
if (!newscreen)
return -ENOMEM;
- if (get_vc_uniscr(vc)) {
+ if (vc->vc_uni_lines) {
new_uniscr = vc_uniscr_alloc(new_cols, new_rows);
if (!new_uniscr) {
kfree(newscreen);
@@ -1297,7 +1241,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
end = old_origin + old_row_size * min(old_rows, new_rows);
vc_uniscr_copy_area(new_uniscr, new_cols, new_rows,
- get_vc_uniscr(vc), rlth/2, first_copied_row,
+ vc->vc_uni_lines, rlth/2, first_copied_row,
min(old_rows, new_rows));
vc_uniscr_set(vc, new_uniscr);
@@ -2959,7 +2903,6 @@ rescan_last_byte:
goto rescan_last_byte;
}
con_flush(vc, &draw);
- vc_uniscr_debug_check(vc);
console_conditional_schedule();
notify_update(vc);
console_unlock();
@@ -3156,8 +3099,14 @@ static struct tty_driver *vt_console_device(struct console *c, int *index)
return console_driver;
}
+static int vt_console_setup(struct console *co, char *options)
+{
+ return co->index >= MAX_NR_CONSOLES ? -EINVAL : 0;
+}
+
static struct console vt_console_driver = {
.name = "tty",
+ .setup = vt_console_setup,
.write = vt_console_print,
.device = vt_console_device,
.unblank = unblank_screen,
@@ -4574,26 +4523,30 @@ void reset_palette(struct vc_data *vc)
/*
* Font switching
*
- * Currently we only support fonts up to 32 pixels wide, at a maximum height
- * of 32 pixels. Userspace fontdata is stored with 32 bytes (shorts/ints,
- * depending on width) reserved for each character which is kinda wasty, but
- * this is done in order to maintain compatibility with the EGA/VGA fonts. It
- * is up to the actual low-level console-driver convert data into its favorite
- * format (maybe we should add a `fontoffset' field to the `display'
- * structure so we won't have to convert the fontdata all the time.
+ * Currently we only support fonts up to 128 pixels wide, at a maximum height
+ * of 128 pixels. Userspace fontdata may have to be stored with 32 bytes
+ * (shorts/ints, depending on width) reserved for each character which is
+ * kinda wasty, but this is done in order to maintain compatibility with the
+ * EGA/VGA fonts. It is up to the actual low-level console-driver convert data
+ * into its favorite format (maybe we should add a `fontoffset' field to the
+ * `display' structure so we won't have to convert the fontdata all the time.
* /Jes
*/
-#define max_font_size 65536
+#define max_font_width 64
+#define max_font_height 128
+#define max_font_glyphs 512
+#define max_font_size (max_font_glyphs*max_font_width*max_font_height)
static int con_font_get(struct vc_data *vc, struct console_font_op *op)
{
struct console_font font;
int rc = -EINVAL;
int c;
+ unsigned int vpitch = op->op == KD_FONT_OP_GET_TALL ? op->height : 32;
if (op->data) {
- font.data = kmalloc(max_font_size, GFP_KERNEL);
+ font.data = kvmalloc(max_font_size, GFP_KERNEL);
if (!font.data)
return -ENOMEM;
} else
@@ -4603,7 +4556,7 @@ static int con_font_get(struct vc_data *vc, struct console_font_op *op)
if (vc->vc_mode != KD_TEXT)
rc = -EINVAL;
else if (vc->vc_sw->con_font_get)
- rc = vc->vc_sw->con_font_get(vc, &font);
+ rc = vc->vc_sw->con_font_get(vc, &font, vpitch);
else
rc = -ENOSYS;
console_unlock();
@@ -4611,7 +4564,7 @@ static int con_font_get(struct vc_data *vc, struct console_font_op *op)
if (rc)
goto out;
- c = (font.width+7)/8 * 32 * font.charcount;
+ c = (font.width+7)/8 * vpitch * font.charcount;
if (op->data && font.charcount > op->charcount)
rc = -ENOSPC;
@@ -4628,7 +4581,7 @@ static int con_font_get(struct vc_data *vc, struct console_font_op *op)
rc = -EFAULT;
out:
- kfree(font.data);
+ kvfree(font.data);
return rc;
}
@@ -4637,16 +4590,20 @@ static int con_font_set(struct vc_data *vc, struct console_font_op *op)
struct console_font font;
int rc = -EINVAL;
int size;
+ unsigned int vpitch = op->op == KD_FONT_OP_SET_TALL ? op->height : 32;
if (vc->vc_mode != KD_TEXT)
return -EINVAL;
if (!op->data)
return -EINVAL;
- if (op->charcount > 512)
+ if (op->charcount > max_font_glyphs)
+ return -EINVAL;
+ if (op->width <= 0 || op->width > max_font_width || !op->height ||
+ op->height > max_font_height)
return -EINVAL;
- if (op->width <= 0 || op->width > 32 || !op->height || op->height > 32)
+ if (vpitch < op->height)
return -EINVAL;
- size = (op->width+7)/8 * 32 * op->charcount;
+ size = (op->width+7)/8 * vpitch * op->charcount;
if (size > max_font_size)
return -ENOSPC;
@@ -4664,7 +4621,7 @@ static int con_font_set(struct vc_data *vc, struct console_font_op *op)
else if (vc->vc_sw->con_font_set) {
if (vc_is_sel(vc))
clear_selection();
- rc = vc->vc_sw->con_font_set(vc, &font, op->flags);
+ rc = vc->vc_sw->con_font_set(vc, &font, vpitch, op->flags);
} else
rc = -ENOSYS;
console_unlock();
@@ -4710,8 +4667,10 @@ int con_font_op(struct vc_data *vc, struct console_font_op *op)
{
switch (op->op) {
case KD_FONT_OP_SET:
+ case KD_FONT_OP_SET_TALL:
return con_font_set(vc, op);
case KD_FONT_OP_GET:
+ case KD_FONT_OP_GET_TALL:
return con_font_get(vc, op);
case KD_FONT_OP_SET_DEFAULT:
return con_font_default(vc, op);
@@ -4740,10 +4699,11 @@ EXPORT_SYMBOL_GPL(screen_glyph);
u32 screen_glyph_unicode(const struct vc_data *vc, int n)
{
- struct uni_screen *uniscr = get_vc_uniscr(vc);
+ u32 **uni_lines = vc->vc_uni_lines;
+
+ if (uni_lines)
+ return uni_lines[n / vc->vc_cols][n % vc->vc_cols];
- if (uniscr)
- return uniscr->lines[n / vc->vc_cols][n % vc->vc_cols];
return inverse_translate(vc, screen_glyph(vc, n * 2), true);
}
EXPORT_SYMBOL_GPL(screen_glyph_unicode);
diff --git a/drivers/ufs/core/Makefile b/drivers/ufs/core/Makefile
index 62f38c5bf857..4d02e0f2de10 100644
--- a/drivers/ufs/core/Makefile
+++ b/drivers/ufs/core/Makefile
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_SCSI_UFSHCD) += ufshcd-core.o
-ufshcd-core-y += ufshcd.o ufs-sysfs.o
+ufshcd-core-y += ufshcd.o ufs-sysfs.o ufs-mcq.o
ufshcd-core-$(CONFIG_DEBUG_FS) += ufs-debugfs.o
ufshcd-core-$(CONFIG_SCSI_UFS_BSG) += ufs_bsg.o
ufshcd-core-$(CONFIG_SCSI_UFS_CRYPTO) += ufshcd-crypto.o
diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c
new file mode 100644
index 000000000000..31df052fbc41
--- /dev/null
+++ b/drivers/ufs/core/ufs-mcq.c
@@ -0,0 +1,431 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022 Qualcomm Innovation Center. All rights reserved.
+ *
+ * Authors:
+ * Asutosh Das <quic_asutoshd@quicinc.com>
+ * Can Guo <quic_cang@quicinc.com>
+ */
+
+#include <asm/unaligned.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include "ufshcd-priv.h"
+
+#define MAX_QUEUE_SUP GENMASK(7, 0)
+#define UFS_MCQ_MIN_RW_QUEUES 2
+#define UFS_MCQ_MIN_READ_QUEUES 0
+#define UFS_MCQ_NUM_DEV_CMD_QUEUES 1
+#define UFS_MCQ_MIN_POLL_QUEUES 0
+#define QUEUE_EN_OFFSET 31
+#define QUEUE_ID_OFFSET 16
+
+#define MAX_DEV_CMD_ENTRIES 2
+#define MCQ_CFG_MAC_MASK GENMASK(16, 8)
+#define MCQ_QCFG_SIZE 0x40
+#define MCQ_ENTRY_SIZE_IN_DWORD 8
+#define CQE_UCD_BA GENMASK_ULL(63, 7)
+
+static int rw_queue_count_set(const char *val, const struct kernel_param *kp)
+{
+ return param_set_uint_minmax(val, kp, UFS_MCQ_MIN_RW_QUEUES,
+ num_possible_cpus());
+}
+
+static const struct kernel_param_ops rw_queue_count_ops = {
+ .set = rw_queue_count_set,
+ .get = param_get_uint,
+};
+
+static unsigned int rw_queues;
+module_param_cb(rw_queues, &rw_queue_count_ops, &rw_queues, 0644);
+MODULE_PARM_DESC(rw_queues,
+ "Number of interrupt driven I/O queues used for rw. Default value is nr_cpus");
+
+static int read_queue_count_set(const char *val, const struct kernel_param *kp)
+{
+ return param_set_uint_minmax(val, kp, UFS_MCQ_MIN_READ_QUEUES,
+ num_possible_cpus());
+}
+
+static const struct kernel_param_ops read_queue_count_ops = {
+ .set = read_queue_count_set,
+ .get = param_get_uint,
+};
+
+static unsigned int read_queues;
+module_param_cb(read_queues, &read_queue_count_ops, &read_queues, 0644);
+MODULE_PARM_DESC(read_queues,
+ "Number of interrupt driven read queues used for read. Default value is 0");
+
+static int poll_queue_count_set(const char *val, const struct kernel_param *kp)
+{
+ return param_set_uint_minmax(val, kp, UFS_MCQ_MIN_POLL_QUEUES,
+ num_possible_cpus());
+}
+
+static const struct kernel_param_ops poll_queue_count_ops = {
+ .set = poll_queue_count_set,
+ .get = param_get_uint,
+};
+
+static unsigned int poll_queues = 1;
+module_param_cb(poll_queues, &poll_queue_count_ops, &poll_queues, 0644);
+MODULE_PARM_DESC(poll_queues,
+ "Number of poll queues used for r/w. Default value is 1");
+
+/**
+ * ufshcd_mcq_config_mac - Set the #Max Activ Cmds.
+ * @hba: per adapter instance
+ * @max_active_cmds: maximum # of active commands to the device at any time.
+ *
+ * The controller won't send more than the max_active_cmds to the device at
+ * any time.
+ */
+void ufshcd_mcq_config_mac(struct ufs_hba *hba, u32 max_active_cmds)
+{
+ u32 val;
+
+ val = ufshcd_readl(hba, REG_UFS_MCQ_CFG);
+ val &= ~MCQ_CFG_MAC_MASK;
+ val |= FIELD_PREP(MCQ_CFG_MAC_MASK, max_active_cmds);
+ ufshcd_writel(hba, val, REG_UFS_MCQ_CFG);
+}
+
+/**
+ * ufshcd_mcq_req_to_hwq - find the hardware queue on which the
+ * request would be issued.
+ * @hba: per adapter instance
+ * @req: pointer to the request to be issued
+ *
+ * Returns the hardware queue instance on which the request would
+ * be queued.
+ */
+struct ufs_hw_queue *ufshcd_mcq_req_to_hwq(struct ufs_hba *hba,
+ struct request *req)
+{
+ u32 utag = blk_mq_unique_tag(req);
+ u32 hwq = blk_mq_unique_tag_to_hwq(utag);
+
+ /* uhq[0] is used to serve device commands */
+ return &hba->uhq[hwq + UFSHCD_MCQ_IO_QUEUE_OFFSET];
+}
+
+/**
+ * ufshcd_mcq_decide_queue_depth - decide the queue depth
+ * @hba: per adapter instance
+ *
+ * Returns queue-depth on success, non-zero on error
+ *
+ * MAC - Max. Active Command of the Host Controller (HC)
+ * HC wouldn't send more than this commands to the device.
+ * It is mandatory to implement get_hba_mac() to enable MCQ mode.
+ * Calculates and adjusts the queue depth based on the depth
+ * supported by the HC and ufs device.
+ */
+int ufshcd_mcq_decide_queue_depth(struct ufs_hba *hba)
+{
+ int mac;
+
+ /* Mandatory to implement get_hba_mac() */
+ mac = ufshcd_mcq_vops_get_hba_mac(hba);
+ if (mac < 0) {
+ dev_err(hba->dev, "Failed to get mac, err=%d\n", mac);
+ return mac;
+ }
+
+ WARN_ON_ONCE(!hba->dev_info.bqueuedepth);
+ /*
+ * max. value of bqueuedepth = 256, mac is host dependent.
+ * It is mandatory for UFS device to define bQueueDepth if
+ * shared queuing architecture is enabled.
+ */
+ return min_t(int, mac, hba->dev_info.bqueuedepth);
+}
+
+static int ufshcd_mcq_config_nr_queues(struct ufs_hba *hba)
+{
+ int i;
+ u32 hba_maxq, rem, tot_queues;
+ struct Scsi_Host *host = hba->host;
+
+ hba_maxq = FIELD_GET(MAX_QUEUE_SUP, hba->mcq_capabilities);
+
+ tot_queues = UFS_MCQ_NUM_DEV_CMD_QUEUES + read_queues + poll_queues +
+ rw_queues;
+
+ if (hba_maxq < tot_queues) {
+ dev_err(hba->dev, "Total queues (%d) exceeds HC capacity (%d)\n",
+ tot_queues, hba_maxq);
+ return -EOPNOTSUPP;
+ }
+
+ rem = hba_maxq - UFS_MCQ_NUM_DEV_CMD_QUEUES;
+
+ if (rw_queues) {
+ hba->nr_queues[HCTX_TYPE_DEFAULT] = rw_queues;
+ rem -= hba->nr_queues[HCTX_TYPE_DEFAULT];
+ } else {
+ rw_queues = num_possible_cpus();
+ }
+
+ if (poll_queues) {
+ hba->nr_queues[HCTX_TYPE_POLL] = poll_queues;
+ rem -= hba->nr_queues[HCTX_TYPE_POLL];
+ }
+
+ if (read_queues) {
+ hba->nr_queues[HCTX_TYPE_READ] = read_queues;
+ rem -= hba->nr_queues[HCTX_TYPE_READ];
+ }
+
+ if (!hba->nr_queues[HCTX_TYPE_DEFAULT])
+ hba->nr_queues[HCTX_TYPE_DEFAULT] = min3(rem, rw_queues,
+ num_possible_cpus());
+
+ for (i = 0; i < HCTX_MAX_TYPES; i++)
+ host->nr_hw_queues += hba->nr_queues[i];
+
+ hba->nr_hw_queues = host->nr_hw_queues + UFS_MCQ_NUM_DEV_CMD_QUEUES;
+ return 0;
+}
+
+int ufshcd_mcq_memory_alloc(struct ufs_hba *hba)
+{
+ struct ufs_hw_queue *hwq;
+ size_t utrdl_size, cqe_size;
+ int i;
+
+ for (i = 0; i < hba->nr_hw_queues; i++) {
+ hwq = &hba->uhq[i];
+
+ utrdl_size = sizeof(struct utp_transfer_req_desc) *
+ hwq->max_entries;
+ hwq->sqe_base_addr = dmam_alloc_coherent(hba->dev, utrdl_size,
+ &hwq->sqe_dma_addr,
+ GFP_KERNEL);
+ if (!hwq->sqe_dma_addr) {
+ dev_err(hba->dev, "SQE allocation failed\n");
+ return -ENOMEM;
+ }
+
+ cqe_size = sizeof(struct cq_entry) * hwq->max_entries;
+ hwq->cqe_base_addr = dmam_alloc_coherent(hba->dev, cqe_size,
+ &hwq->cqe_dma_addr,
+ GFP_KERNEL);
+ if (!hwq->cqe_dma_addr) {
+ dev_err(hba->dev, "CQE allocation failed\n");
+ return -ENOMEM;
+ }
+ }
+
+ return 0;
+}
+
+
+/* Operation and runtime registers configuration */
+#define MCQ_CFG_n(r, i) ((r) + MCQ_QCFG_SIZE * (i))
+#define MCQ_OPR_OFFSET_n(p, i) \
+ (hba->mcq_opr[(p)].offset + hba->mcq_opr[(p)].stride * (i))
+
+static void __iomem *mcq_opr_base(struct ufs_hba *hba,
+ enum ufshcd_mcq_opr n, int i)
+{
+ struct ufshcd_mcq_opr_info_t *opr = &hba->mcq_opr[n];
+
+ return opr->base + opr->stride * i;
+}
+
+u32 ufshcd_mcq_read_cqis(struct ufs_hba *hba, int i)
+{
+ return readl(mcq_opr_base(hba, OPR_CQIS, i) + REG_CQIS);
+}
+
+void ufshcd_mcq_write_cqis(struct ufs_hba *hba, u32 val, int i)
+{
+ writel(val, mcq_opr_base(hba, OPR_CQIS, i) + REG_CQIS);
+}
+EXPORT_SYMBOL_GPL(ufshcd_mcq_write_cqis);
+
+/*
+ * Current MCQ specification doesn't provide a Task Tag or its equivalent in
+ * the Completion Queue Entry. Find the Task Tag using an indirect method.
+ */
+static int ufshcd_mcq_get_tag(struct ufs_hba *hba,
+ struct ufs_hw_queue *hwq,
+ struct cq_entry *cqe)
+{
+ u64 addr;
+
+ /* sizeof(struct utp_transfer_cmd_desc) must be a multiple of 128 */
+ BUILD_BUG_ON(sizeof(struct utp_transfer_cmd_desc) & GENMASK(6, 0));
+
+ /* Bits 63:7 UCD base address, 6:5 are reserved, 4:0 is SQ ID */
+ addr = (le64_to_cpu(cqe->command_desc_base_addr) & CQE_UCD_BA) -
+ hba->ucdl_dma_addr;
+
+ return div_u64(addr, sizeof(struct utp_transfer_cmd_desc));
+}
+
+static void ufshcd_mcq_process_cqe(struct ufs_hba *hba,
+ struct ufs_hw_queue *hwq)
+{
+ struct cq_entry *cqe = ufshcd_mcq_cur_cqe(hwq);
+ int tag = ufshcd_mcq_get_tag(hba, hwq, cqe);
+
+ ufshcd_compl_one_cqe(hba, tag, cqe);
+}
+
+unsigned long ufshcd_mcq_poll_cqe_nolock(struct ufs_hba *hba,
+ struct ufs_hw_queue *hwq)
+{
+ unsigned long completed_reqs = 0;
+
+ ufshcd_mcq_update_cq_tail_slot(hwq);
+ while (!ufshcd_mcq_is_cq_empty(hwq)) {
+ ufshcd_mcq_process_cqe(hba, hwq);
+ ufshcd_mcq_inc_cq_head_slot(hwq);
+ completed_reqs++;
+ }
+
+ if (completed_reqs)
+ ufshcd_mcq_update_cq_head(hwq);
+
+ return completed_reqs;
+}
+EXPORT_SYMBOL_GPL(ufshcd_mcq_poll_cqe_nolock);
+
+unsigned long ufshcd_mcq_poll_cqe_lock(struct ufs_hba *hba,
+ struct ufs_hw_queue *hwq)
+{
+ unsigned long completed_reqs;
+
+ spin_lock(&hwq->cq_lock);
+ completed_reqs = ufshcd_mcq_poll_cqe_nolock(hba, hwq);
+ spin_unlock(&hwq->cq_lock);
+
+ return completed_reqs;
+}
+
+void ufshcd_mcq_make_queues_operational(struct ufs_hba *hba)
+{
+ struct ufs_hw_queue *hwq;
+ u16 qsize;
+ int i;
+
+ for (i = 0; i < hba->nr_hw_queues; i++) {
+ hwq = &hba->uhq[i];
+ hwq->id = i;
+ qsize = hwq->max_entries * MCQ_ENTRY_SIZE_IN_DWORD - 1;
+
+ /* Submission Queue Lower Base Address */
+ ufsmcq_writelx(hba, lower_32_bits(hwq->sqe_dma_addr),
+ MCQ_CFG_n(REG_SQLBA, i));
+ /* Submission Queue Upper Base Address */
+ ufsmcq_writelx(hba, upper_32_bits(hwq->sqe_dma_addr),
+ MCQ_CFG_n(REG_SQUBA, i));
+ /* Submission Queue Doorbell Address Offset */
+ ufsmcq_writelx(hba, MCQ_OPR_OFFSET_n(OPR_SQD, i),
+ MCQ_CFG_n(REG_SQDAO, i));
+ /* Submission Queue Interrupt Status Address Offset */
+ ufsmcq_writelx(hba, MCQ_OPR_OFFSET_n(OPR_SQIS, i),
+ MCQ_CFG_n(REG_SQISAO, i));
+
+ /* Completion Queue Lower Base Address */
+ ufsmcq_writelx(hba, lower_32_bits(hwq->cqe_dma_addr),
+ MCQ_CFG_n(REG_CQLBA, i));
+ /* Completion Queue Upper Base Address */
+ ufsmcq_writelx(hba, upper_32_bits(hwq->cqe_dma_addr),
+ MCQ_CFG_n(REG_CQUBA, i));
+ /* Completion Queue Doorbell Address Offset */
+ ufsmcq_writelx(hba, MCQ_OPR_OFFSET_n(OPR_CQD, i),
+ MCQ_CFG_n(REG_CQDAO, i));
+ /* Completion Queue Interrupt Status Address Offset */
+ ufsmcq_writelx(hba, MCQ_OPR_OFFSET_n(OPR_CQIS, i),
+ MCQ_CFG_n(REG_CQISAO, i));
+
+ /* Save the base addresses for quicker access */
+ hwq->mcq_sq_head = mcq_opr_base(hba, OPR_SQD, i) + REG_SQHP;
+ hwq->mcq_sq_tail = mcq_opr_base(hba, OPR_SQD, i) + REG_SQTP;
+ hwq->mcq_cq_head = mcq_opr_base(hba, OPR_CQD, i) + REG_CQHP;
+ hwq->mcq_cq_tail = mcq_opr_base(hba, OPR_CQD, i) + REG_CQTP;
+
+ /* Reinitializing is needed upon HC reset */
+ hwq->sq_tail_slot = hwq->cq_tail_slot = hwq->cq_head_slot = 0;
+
+ /* Enable Tail Entry Push Status interrupt only for non-poll queues */
+ if (i < hba->nr_hw_queues - hba->nr_queues[HCTX_TYPE_POLL])
+ writel(1, mcq_opr_base(hba, OPR_CQIS, i) + REG_CQIE);
+
+ /* Completion Queue Enable|Size to Completion Queue Attribute */
+ ufsmcq_writel(hba, (1 << QUEUE_EN_OFFSET) | qsize,
+ MCQ_CFG_n(REG_CQATTR, i));
+
+ /*
+ * Submission Qeueue Enable|Size|Completion Queue ID to
+ * Submission Queue Attribute
+ */
+ ufsmcq_writel(hba, (1 << QUEUE_EN_OFFSET) | qsize |
+ (i << QUEUE_ID_OFFSET),
+ MCQ_CFG_n(REG_SQATTR, i));
+ }
+}
+
+void ufshcd_mcq_enable_esi(struct ufs_hba *hba)
+{
+ ufshcd_writel(hba, ufshcd_readl(hba, REG_UFS_MEM_CFG) | 0x2,
+ REG_UFS_MEM_CFG);
+}
+EXPORT_SYMBOL_GPL(ufshcd_mcq_enable_esi);
+
+void ufshcd_mcq_config_esi(struct ufs_hba *hba, struct msi_msg *msg)
+{
+ ufshcd_writel(hba, msg->address_lo, REG_UFS_ESILBA);
+ ufshcd_writel(hba, msg->address_hi, REG_UFS_ESIUBA);
+}
+EXPORT_SYMBOL_GPL(ufshcd_mcq_config_esi);
+
+int ufshcd_mcq_init(struct ufs_hba *hba)
+{
+ struct Scsi_Host *host = hba->host;
+ struct ufs_hw_queue *hwq;
+ int ret, i;
+
+ ret = ufshcd_mcq_config_nr_queues(hba);
+ if (ret)
+ return ret;
+
+ ret = ufshcd_vops_mcq_config_resource(hba);
+ if (ret)
+ return ret;
+
+ ret = ufshcd_mcq_vops_op_runtime_config(hba);
+ if (ret) {
+ dev_err(hba->dev, "Operation runtime config failed, ret=%d\n",
+ ret);
+ return ret;
+ }
+ hba->uhq = devm_kzalloc(hba->dev,
+ hba->nr_hw_queues * sizeof(struct ufs_hw_queue),
+ GFP_KERNEL);
+ if (!hba->uhq) {
+ dev_err(hba->dev, "ufs hw queue memory allocation failed\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < hba->nr_hw_queues; i++) {
+ hwq = &hba->uhq[i];
+ hwq->max_entries = hba->nutrs;
+ spin_lock_init(&hwq->sq_lock);
+ spin_lock_init(&hwq->cq_lock);
+ }
+
+ /* The very first HW queue serves device commands */
+ hba->dev_cmd_queue = &hba->uhq[0];
+ /* Give dev_cmd_queue the minimal number of entries */
+ hba->dev_cmd_queue->max_entries = MAX_DEV_CMD_ENTRIES;
+
+ host->host_tagset = 1;
+ return 0;
+}
diff --git a/drivers/ufs/core/ufs_bsg.c b/drivers/ufs/core/ufs_bsg.c
index b99e3f3dc4ef..0d38e7fa34cc 100644
--- a/drivers/ufs/core/ufs_bsg.c
+++ b/drivers/ufs/core/ufs_bsg.c
@@ -6,6 +6,7 @@
*/
#include <linux/bsg-lib.h>
+#include <linux/dma-mapping.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
#include "ufs_bsg.h"
@@ -16,31 +17,11 @@ static int ufs_bsg_get_query_desc_size(struct ufs_hba *hba, int *desc_len,
struct utp_upiu_query *qr)
{
int desc_size = be16_to_cpu(qr->length);
- int desc_id = qr->idn;
if (desc_size <= 0)
return -EINVAL;
- ufshcd_map_desc_id_to_length(hba, desc_id, desc_len);
- if (!*desc_len)
- return -EINVAL;
-
- *desc_len = min_t(int, *desc_len, desc_size);
-
- return 0;
-}
-
-static int ufs_bsg_verify_query_size(struct ufs_hba *hba,
- unsigned int request_len,
- unsigned int reply_len)
-{
- int min_req_len = sizeof(struct ufs_bsg_request);
- int min_rsp_len = sizeof(struct ufs_bsg_reply);
-
- if (min_req_len > request_len || min_rsp_len > reply_len) {
- dev_err(hba->dev, "not enough space assigned\n");
- return -EINVAL;
- }
+ *desc_len = min_t(int, QUERY_DESC_MAX_SIZE, desc_size);
return 0;
}
@@ -83,23 +64,84 @@ out:
return 0;
}
+static int ufs_bsg_exec_advanced_rpmb_req(struct ufs_hba *hba, struct bsg_job *job)
+{
+ struct ufs_rpmb_request *rpmb_request = job->request;
+ struct ufs_rpmb_reply *rpmb_reply = job->reply;
+ struct bsg_buffer *payload = NULL;
+ enum dma_data_direction dir;
+ struct scatterlist *sg_list = NULL;
+ int rpmb_req_type;
+ int sg_cnt = 0;
+ int ret;
+ int data_len;
+
+ if (hba->ufs_version < ufshci_version(4, 0) || !hba->dev_info.b_advanced_rpmb_en ||
+ !(hba->capabilities & MASK_EHSLUTRD_SUPPORTED))
+ return -EINVAL;
+
+ if (rpmb_request->ehs_req.length != 2 || rpmb_request->ehs_req.ehs_type != 1)
+ return -EINVAL;
+
+ rpmb_req_type = be16_to_cpu(rpmb_request->ehs_req.meta.req_resp_type);
+
+ switch (rpmb_req_type) {
+ case UFS_RPMB_WRITE_KEY:
+ case UFS_RPMB_READ_CNT:
+ case UFS_RPMB_PURGE_ENABLE:
+ dir = DMA_NONE;
+ break;
+ case UFS_RPMB_WRITE:
+ case UFS_RPMB_SEC_CONF_WRITE:
+ dir = DMA_TO_DEVICE;
+ break;
+ case UFS_RPMB_READ:
+ case UFS_RPMB_SEC_CONF_READ:
+ case UFS_RPMB_PURGE_STATUS_READ:
+ dir = DMA_FROM_DEVICE;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (dir != DMA_NONE) {
+ payload = &job->request_payload;
+ if (!payload || !payload->payload_len || !payload->sg_cnt)
+ return -EINVAL;
+
+ sg_cnt = dma_map_sg(hba->host->dma_dev, payload->sg_list, payload->sg_cnt, dir);
+ if (unlikely(!sg_cnt))
+ return -ENOMEM;
+ sg_list = payload->sg_list;
+ data_len = payload->payload_len;
+ }
+
+ ret = ufshcd_advanced_rpmb_req_handler(hba, &rpmb_request->bsg_request.upiu_req,
+ &rpmb_reply->bsg_reply.upiu_rsp, &rpmb_request->ehs_req,
+ &rpmb_reply->ehs_rsp, sg_cnt, sg_list, dir);
+
+ if (dir != DMA_NONE) {
+ dma_unmap_sg(hba->host->dma_dev, payload->sg_list, payload->sg_cnt, dir);
+
+ if (!ret)
+ rpmb_reply->bsg_reply.reply_payload_rcv_len = data_len;
+ }
+
+ return ret;
+}
+
static int ufs_bsg_request(struct bsg_job *job)
{
struct ufs_bsg_request *bsg_request = job->request;
struct ufs_bsg_reply *bsg_reply = job->reply;
struct ufs_hba *hba = shost_priv(dev_to_shost(job->dev->parent));
- unsigned int req_len = job->request_len;
- unsigned int reply_len = job->reply_len;
struct uic_command uc = {};
int msgcode;
- uint8_t *desc_buff = NULL;
+ uint8_t *buff = NULL;
int desc_len = 0;
enum query_opcode desc_op = UPIU_QUERY_OPCODE_NOP;
int ret;
-
- ret = ufs_bsg_verify_query_size(hba, req_len, reply_len);
- if (ret)
- goto out;
+ bool rpmb = false;
bsg_reply->reply_payload_rcv_len = 0;
@@ -109,34 +151,39 @@ static int ufs_bsg_request(struct bsg_job *job)
switch (msgcode) {
case UPIU_TRANSACTION_QUERY_REQ:
desc_op = bsg_request->upiu_req.qr.opcode;
- ret = ufs_bsg_alloc_desc_buffer(hba, job, &desc_buff,
- &desc_len, desc_op);
- if (ret) {
- ufshcd_rpm_put_sync(hba);
+ ret = ufs_bsg_alloc_desc_buffer(hba, job, &buff, &desc_len, desc_op);
+ if (ret)
goto out;
- }
-
fallthrough;
case UPIU_TRANSACTION_NOP_OUT:
case UPIU_TRANSACTION_TASK_REQ:
ret = ufshcd_exec_raw_upiu_cmd(hba, &bsg_request->upiu_req,
&bsg_reply->upiu_rsp, msgcode,
- desc_buff, &desc_len, desc_op);
+ buff, &desc_len, desc_op);
if (ret)
- dev_err(hba->dev,
- "exe raw upiu: error code %d\n", ret);
-
+ dev_err(hba->dev, "exe raw upiu: error code %d\n", ret);
+ else if (desc_op == UPIU_QUERY_OPCODE_READ_DESC && desc_len) {
+ bsg_reply->reply_payload_rcv_len =
+ sg_copy_from_buffer(job->request_payload.sg_list,
+ job->request_payload.sg_cnt,
+ buff, desc_len);
+ }
break;
case UPIU_TRANSACTION_UIC_CMD:
memcpy(&uc, &bsg_request->upiu_req.uc, UIC_CMD_SIZE);
ret = ufshcd_send_uic_cmd(hba, &uc);
if (ret)
- dev_err(hba->dev,
- "send uic cmd: error code %d\n", ret);
+ dev_err(hba->dev, "send uic cmd: error code %d\n", ret);
memcpy(&bsg_reply->upiu_rsp.uc, &uc, UIC_CMD_SIZE);
break;
+ case UPIU_TRANSACTION_ARPMB_CMD:
+ rpmb = true;
+ ret = ufs_bsg_exec_advanced_rpmb_req(hba, job);
+ if (ret)
+ dev_err(hba->dev, "ARPMB OP failed: error code %d\n", ret);
+ break;
default:
ret = -ENOTSUPP;
dev_err(hba->dev, "unsupported msgcode 0x%x\n", msgcode);
@@ -144,22 +191,11 @@ static int ufs_bsg_request(struct bsg_job *job)
break;
}
- ufshcd_rpm_put_sync(hba);
-
- if (!desc_buff)
- goto out;
-
- if (desc_op == UPIU_QUERY_OPCODE_READ_DESC && desc_len)
- bsg_reply->reply_payload_rcv_len =
- sg_copy_from_buffer(job->request_payload.sg_list,
- job->request_payload.sg_cnt,
- desc_buff, desc_len);
-
- kfree(desc_buff);
-
out:
+ ufshcd_rpm_put_sync(hba);
+ kfree(buff);
bsg_reply->result = ret;
- job->reply_len = sizeof(struct ufs_bsg_reply);
+ job->reply_len = !rpmb ? sizeof(struct ufs_bsg_reply) : sizeof(struct ufs_rpmb_reply);
/* complete the job here only if no error */
if (ret == 0)
bsg_job_done(job, ret, bsg_reply->reply_payload_rcv_len);
diff --git a/drivers/ufs/core/ufshcd-priv.h b/drivers/ufs/core/ufshcd-priv.h
index a9e8e1f5afe7..529f8507a5e4 100644
--- a/drivers/ufs/core/ufshcd-priv.h
+++ b/drivers/ufs/core/ufshcd-priv.h
@@ -61,7 +61,24 @@ int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode,
int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
enum flag_idn idn, u8 index, bool *flag_res);
void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit);
-
+void ufshcd_compl_one_cqe(struct ufs_hba *hba, int task_tag,
+ struct cq_entry *cqe);
+int ufshcd_mcq_init(struct ufs_hba *hba);
+int ufshcd_mcq_decide_queue_depth(struct ufs_hba *hba);
+int ufshcd_mcq_memory_alloc(struct ufs_hba *hba);
+void ufshcd_mcq_make_queues_operational(struct ufs_hba *hba);
+void ufshcd_mcq_config_mac(struct ufs_hba *hba, u32 max_active_cmds);
+void ufshcd_mcq_select_mcq_mode(struct ufs_hba *hba);
+u32 ufshcd_mcq_read_cqis(struct ufs_hba *hba, int i);
+void ufshcd_mcq_write_cqis(struct ufs_hba *hba, u32 val, int i);
+unsigned long ufshcd_mcq_poll_cqe_nolock(struct ufs_hba *hba,
+ struct ufs_hw_queue *hwq);
+struct ufs_hw_queue *ufshcd_mcq_req_to_hwq(struct ufs_hba *hba,
+ struct request *req);
+unsigned long ufshcd_mcq_poll_cqe_lock(struct ufs_hba *hba,
+ struct ufs_hw_queue *hwq);
+
+#define UFSHCD_MCQ_IO_QUEUE_OFFSET 1
#define SD_ASCII_STD true
#define SD_RAW false
int ufshcd_read_string_desc(struct ufs_hba *hba, u8 desc_index,
@@ -70,9 +87,6 @@ int ufshcd_read_string_desc(struct ufs_hba *hba, u8 desc_index,
int ufshcd_hold(struct ufs_hba *hba, bool async);
void ufshcd_release(struct ufs_hba *hba);
-void ufshcd_map_desc_id_to_length(struct ufs_hba *hba, enum desc_idn desc_id,
- int *desc_length);
-
int ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd);
int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba,
@@ -226,6 +240,53 @@ static inline void ufshcd_vops_config_scaling_param(struct ufs_hba *hba,
hba->vops->config_scaling_param(hba, p, data);
}
+static inline void ufshcd_vops_reinit_notify(struct ufs_hba *hba)
+{
+ if (hba->vops && hba->vops->reinit_notify)
+ hba->vops->reinit_notify(hba);
+}
+
+static inline int ufshcd_vops_mcq_config_resource(struct ufs_hba *hba)
+{
+ if (hba->vops && hba->vops->mcq_config_resource)
+ return hba->vops->mcq_config_resource(hba);
+
+ return -EOPNOTSUPP;
+}
+
+static inline int ufshcd_mcq_vops_get_hba_mac(struct ufs_hba *hba)
+{
+ if (hba->vops && hba->vops->get_hba_mac)
+ return hba->vops->get_hba_mac(hba);
+
+ return -EOPNOTSUPP;
+}
+
+static inline int ufshcd_mcq_vops_op_runtime_config(struct ufs_hba *hba)
+{
+ if (hba->vops && hba->vops->op_runtime_config)
+ return hba->vops->op_runtime_config(hba);
+
+ return -EOPNOTSUPP;
+}
+
+static inline int ufshcd_vops_get_outstanding_cqs(struct ufs_hba *hba,
+ unsigned long *ocqs)
+{
+ if (hba->vops && hba->vops->get_outstanding_cqs)
+ return hba->vops->get_outstanding_cqs(hba, ocqs);
+
+ return -EOPNOTSUPP;
+}
+
+static inline int ufshcd_mcq_vops_config_esi(struct ufs_hba *hba)
+{
+ if (hba->vops && hba->vops->config_esi)
+ return hba->vops->config_esi(hba);
+
+ return -EOPNOTSUPP;
+}
+
extern const struct ufs_pm_lvl_states ufs_pm_lvl_states[];
/**
@@ -302,4 +363,44 @@ static inline bool ufs_is_valid_unit_desc_lun(struct ufs_dev_info *dev_info, u8
return lun == UFS_UPIU_RPMB_WLUN || (lun < dev_info->max_lu_supported);
}
+static inline void ufshcd_inc_sq_tail(struct ufs_hw_queue *q)
+{
+ u32 mask = q->max_entries - 1;
+ u32 val;
+
+ q->sq_tail_slot = (q->sq_tail_slot + 1) & mask;
+ val = q->sq_tail_slot * sizeof(struct utp_transfer_req_desc);
+ writel(val, q->mcq_sq_tail);
+}
+
+static inline void ufshcd_mcq_update_cq_tail_slot(struct ufs_hw_queue *q)
+{
+ u32 val = readl(q->mcq_cq_tail);
+
+ q->cq_tail_slot = val / sizeof(struct cq_entry);
+}
+
+static inline bool ufshcd_mcq_is_cq_empty(struct ufs_hw_queue *q)
+{
+ return q->cq_head_slot == q->cq_tail_slot;
+}
+
+static inline void ufshcd_mcq_inc_cq_head_slot(struct ufs_hw_queue *q)
+{
+ q->cq_head_slot++;
+ if (q->cq_head_slot == q->max_entries)
+ q->cq_head_slot = 0;
+}
+
+static inline void ufshcd_mcq_update_cq_head(struct ufs_hw_queue *q)
+{
+ writel(q->cq_head_slot * sizeof(struct cq_entry), q->mcq_cq_head);
+}
+
+static inline struct cq_entry *ufshcd_mcq_cur_cqe(struct ufs_hw_queue *q)
+{
+ struct cq_entry *cqe = q->cqe_base_addr;
+
+ return cqe + q->cq_head_slot;
+}
#endif /* _UFSHCD_PRIV_H_ */
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index 3a1c4d31e010..276a82b2e5ee 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -43,6 +43,12 @@
#define UFSHCD_ENABLE_INTRS (UTP_TRANSFER_REQ_COMPL |\
UTP_TASK_REQ_COMPL |\
UFSHCD_ERROR_MASK)
+
+#define UFSHCD_ENABLE_MCQ_INTRS (UTP_TASK_REQ_COMPL |\
+ UFSHCD_ERROR_MASK |\
+ MCQ_CQ_EVENT_STATUS)
+
+
/* UIC command timeout, unit: ms */
#define UIC_CMD_TIMEOUT 500
@@ -56,6 +62,9 @@
/* Query request timeout */
#define QUERY_REQ_TIMEOUT 1500 /* 1.5 seconds */
+/* Advanced RPMB request timeout */
+#define ADVANCED_RPMB_REQ_TIMEOUT 3000 /* 3 seconds */
+
/* Task management command timeout */
#define TM_CMD_TIMEOUT 100 /* msecs */
@@ -89,6 +98,33 @@
/* Polling time to wait for fDeviceInit */
#define FDEVICEINIT_COMPL_TIMEOUT 1500 /* millisecs */
+/* UFSHC 4.0 compliant HC support this mode, refer param_set_mcq_mode() */
+static bool use_mcq_mode = true;
+
+static bool is_mcq_supported(struct ufs_hba *hba)
+{
+ return hba->mcq_sup && use_mcq_mode;
+}
+
+static int param_set_mcq_mode(const char *val, const struct kernel_param *kp)
+{
+ int ret;
+
+ ret = param_set_bool(val, kp);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static const struct kernel_param_ops mcq_mode_ops = {
+ .set = param_set_mcq_mode,
+ .get = param_get_bool,
+};
+
+module_param_cb(use_mcq_mode, &mcq_mode_ops, &use_mcq_mode, 0644);
+MODULE_PARM_DESC(use_mcq_mode, "Control MCQ mode for controllers starting from UFSHCI 4.0. 1 - enable MCQ, 0 - disable MCQ. MCQ is enabled by default");
+
#define ufshcd_toggle_vreg(_dev, _vreg, _on) \
({ \
int _ret; \
@@ -528,7 +564,7 @@ void ufshcd_print_trs(struct ufs_hba *hba, unsigned long bitmap, bool pr_prdt)
prdt_length = le16_to_cpu(
lrbp->utr_descriptor_ptr->prd_table_length);
if (hba->quirks & UFSHCD_QUIRK_PRDT_BYTE_GRAN)
- prdt_length /= sizeof(struct ufshcd_sg_entry);
+ prdt_length /= ufshcd_sg_entry_size(hba);
dev_err(hba->dev,
"UPIU[%d] - PRDT - %d entries phys@0x%llx\n",
@@ -537,7 +573,7 @@ void ufshcd_print_trs(struct ufs_hba *hba, unsigned long bitmap, bool pr_prdt)
if (pr_prdt)
ufshcd_hex_dump("UPIU PRDT: ", lrbp->ucd_prdt_ptr,
- sizeof(struct ufshcd_sg_entry) * prdt_length);
+ ufshcd_sg_entry_size(hba) * prdt_length);
}
}
@@ -740,12 +776,17 @@ static inline bool ufshcd_is_device_present(struct ufs_hba *hba)
/**
* ufshcd_get_tr_ocs - Get the UTRD Overall Command Status
* @lrbp: pointer to local command reference block
+ * @cqe: pointer to the completion queue entry
*
* This function is used to get the OCS field from UTRD
* Returns the OCS field in the UTRD
*/
-static enum utp_ocs ufshcd_get_tr_ocs(struct ufshcd_lrb *lrbp)
+static enum utp_ocs ufshcd_get_tr_ocs(struct ufshcd_lrb *lrbp,
+ struct cq_entry *cqe)
{
+ if (cqe)
+ return le32_to_cpu(cqe->status) & MASK_OCS;
+
return le32_to_cpu(lrbp->utr_descriptor_ptr->header.dword_2) & MASK_OCS;
}
@@ -1121,6 +1162,12 @@ static u32 ufshcd_pending_cmds(struct ufs_hba *hba)
return pending;
}
+/*
+ * Wait until all pending SCSI commands and TMFs have finished or the timeout
+ * has expired.
+ *
+ * Return: 0 upon success; -EBUSY upon timeout.
+ */
static int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba,
u64 wait_timeout_us)
{
@@ -1154,7 +1201,7 @@ static int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba,
}
spin_unlock_irqrestore(hba->host->host_lock, flags);
- schedule();
+ io_schedule_timeout(msecs_to_jiffies(20));
if (ktime_to_us(ktime_sub(ktime_get(), start)) >
wait_timeout_us) {
timeout = true;
@@ -1225,9 +1272,14 @@ static int ufshcd_scale_gear(struct ufs_hba *hba, bool scale_up)
return ret;
}
-static int ufshcd_clock_scaling_prepare(struct ufs_hba *hba)
+/*
+ * Wait until all pending SCSI commands and TMFs have finished or the timeout
+ * has expired.
+ *
+ * Return: 0 upon success; -EBUSY upon timeout.
+ */
+static int ufshcd_clock_scaling_prepare(struct ufs_hba *hba, u64 timeout_us)
{
- #define DOORBELL_CLR_TOUT_US (1000 * 1000) /* 1 sec */
int ret = 0;
/*
* make sure that there are no outstanding requests when
@@ -1238,7 +1290,7 @@ static int ufshcd_clock_scaling_prepare(struct ufs_hba *hba)
down_write(&hba->clk_scaling_lock);
if (!hba->clk_scaling.is_allowed ||
- ufshcd_wait_for_doorbell_clr(hba, DOORBELL_CLR_TOUT_US)) {
+ ufshcd_wait_for_doorbell_clr(hba, timeout_us)) {
ret = -EBUSY;
up_write(&hba->clk_scaling_lock);
mutex_unlock(&hba->wb_mutex);
@@ -1280,7 +1332,7 @@ static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool scale_up)
{
int ret = 0;
- ret = ufshcd_clock_scaling_prepare(hba);
+ ret = ufshcd_clock_scaling_prepare(hba, 1 * USEC_PER_SEC);
if (ret)
return ret;
@@ -2136,9 +2188,11 @@ static void ufshcd_update_monitor(struct ufs_hba *hba, const struct ufshcd_lrb *
* ufshcd_send_command - Send SCSI or device management commands
* @hba: per adapter instance
* @task_tag: Task tag of the command
+ * @hwq: pointer to hardware queue instance
*/
static inline
-void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag)
+void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag,
+ struct ufs_hw_queue *hwq)
{
struct ufshcd_lrb *lrbp = &hba->lrb[task_tag];
unsigned long flags;
@@ -2152,12 +2206,24 @@ void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag)
if (unlikely(ufshcd_should_inform_monitor(hba, lrbp)))
ufshcd_start_monitor(hba, lrbp);
- spin_lock_irqsave(&hba->outstanding_lock, flags);
- if (hba->vops && hba->vops->setup_xfer_req)
- hba->vops->setup_xfer_req(hba, task_tag, !!lrbp->cmd);
- __set_bit(task_tag, &hba->outstanding_reqs);
- ufshcd_writel(hba, 1 << task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL);
- spin_unlock_irqrestore(&hba->outstanding_lock, flags);
+ if (is_mcq_enabled(hba)) {
+ int utrd_size = sizeof(struct utp_transfer_req_desc);
+
+ spin_lock(&hwq->sq_lock);
+ memcpy(hwq->sqe_base_addr + (hwq->sq_tail_slot * utrd_size),
+ lrbp->utr_descriptor_ptr, utrd_size);
+ ufshcd_inc_sq_tail(hwq);
+ spin_unlock(&hwq->sq_lock);
+ } else {
+ spin_lock_irqsave(&hba->outstanding_lock, flags);
+ if (hba->vops && hba->vops->setup_xfer_req)
+ hba->vops->setup_xfer_req(hba, lrbp->task_tag,
+ !!lrbp->cmd);
+ __set_bit(lrbp->task_tag, &hba->outstanding_reqs);
+ ufshcd_writel(hba, 1 << lrbp->task_tag,
+ REG_UTP_TRANSFER_REQ_DOOR_BELL);
+ spin_unlock_irqrestore(&hba->outstanding_lock, flags);
+ }
}
/**
@@ -2245,6 +2311,14 @@ static inline int ufshcd_hba_capabilities(struct ufs_hba *hba)
if (err)
dev_err(hba->dev, "crypto setup failed\n");
+ hba->mcq_sup = FIELD_GET(MASK_MCQ_SUPPORT, hba->capabilities);
+ if (!hba->mcq_sup)
+ return err;
+
+ hba->mcq_capabilities = ufshcd_readl(hba, REG_MCQCAP);
+ hba->ext_iid_sup = FIELD_GET(MASK_EXT_IID_SUPPORT,
+ hba->mcq_capabilities);
+
return err;
}
@@ -2397,38 +2471,30 @@ int ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
}
/**
- * ufshcd_map_sg - Map scatter-gather list to prdt
- * @hba: per adapter instance
- * @lrbp: pointer to local reference block
- *
- * Returns 0 in case of success, non-zero value in case of failure
+ * ufshcd_sgl_to_prdt - SG list to PRTD (Physical Region Description Table, 4DW format)
+ * @hba: per-adapter instance
+ * @lrbp: pointer to local reference block
+ * @sg_entries: The number of sg lists actually used
+ * @sg_list: Pointer to SG list
*/
-static int ufshcd_map_sg(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
+static void ufshcd_sgl_to_prdt(struct ufs_hba *hba, struct ufshcd_lrb *lrbp, int sg_entries,
+ struct scatterlist *sg_list)
{
- struct ufshcd_sg_entry *prd_table;
+ struct ufshcd_sg_entry *prd;
struct scatterlist *sg;
- struct scsi_cmnd *cmd;
- int sg_segments;
int i;
- cmd = lrbp->cmd;
- sg_segments = scsi_dma_map(cmd);
- if (sg_segments < 0)
- return sg_segments;
-
- if (sg_segments) {
+ if (sg_entries) {
if (hba->quirks & UFSHCD_QUIRK_PRDT_BYTE_GRAN)
lrbp->utr_descriptor_ptr->prd_table_length =
- cpu_to_le16((sg_segments *
- sizeof(struct ufshcd_sg_entry)));
+ cpu_to_le16(sg_entries * ufshcd_sg_entry_size(hba));
else
- lrbp->utr_descriptor_ptr->prd_table_length =
- cpu_to_le16(sg_segments);
+ lrbp->utr_descriptor_ptr->prd_table_length = cpu_to_le16(sg_entries);
- prd_table = lrbp->ucd_prdt_ptr;
+ prd = lrbp->ucd_prdt_ptr;
- scsi_for_each_sg(cmd, sg, sg_segments, i) {
+ for_each_sg(sg_list, sg, sg_entries, i) {
const unsigned int len = sg_dma_len(sg);
/*
@@ -2440,13 +2506,32 @@ static int ufshcd_map_sg(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
* indicates 4 bytes, '7' indicates 8 bytes, etc."
*/
WARN_ONCE(len > 256 * 1024, "len = %#x\n", len);
- prd_table[i].size = cpu_to_le32(len - 1);
- prd_table[i].addr = cpu_to_le64(sg->dma_address);
- prd_table[i].reserved = 0;
+ prd->size = cpu_to_le32(len - 1);
+ prd->addr = cpu_to_le64(sg->dma_address);
+ prd->reserved = 0;
+ prd = (void *)prd + ufshcd_sg_entry_size(hba);
}
} else {
lrbp->utr_descriptor_ptr->prd_table_length = 0;
}
+}
+
+/**
+ * ufshcd_map_sg - Map scatter-gather list to prdt
+ * @hba: per adapter instance
+ * @lrbp: pointer to local reference block
+ *
+ * Returns 0 in case of success, non-zero value in case of failure
+ */
+static int ufshcd_map_sg(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
+{
+ struct scsi_cmnd *cmd = lrbp->cmd;
+ int sg_segments = scsi_dma_map(cmd);
+
+ if (sg_segments < 0)
+ return sg_segments;
+
+ ufshcd_sgl_to_prdt(hba, lrbp, sg_segments, scsi_sglist(cmd));
return 0;
}
@@ -2494,14 +2579,15 @@ static void ufshcd_disable_intr(struct ufs_hba *hba, u32 intrs)
}
/**
- * ufshcd_prepare_req_desc_hdr() - Fills the requests header
+ * ufshcd_prepare_req_desc_hdr - Fill UTP Transfer request descriptor header according to request
* descriptor according to request
* @lrbp: pointer to local reference block
* @upiu_flags: flags required in the header
* @cmd_dir: requests data direction
+ * @ehs_length: Total EHS Length (in 32‐bytes units of all Extra Header Segments)
*/
-static void ufshcd_prepare_req_desc_hdr(struct ufshcd_lrb *lrbp,
- u8 *upiu_flags, enum dma_data_direction cmd_dir)
+static void ufshcd_prepare_req_desc_hdr(struct ufshcd_lrb *lrbp, u8 *upiu_flags,
+ enum dma_data_direction cmd_dir, int ehs_length)
{
struct utp_transfer_req_desc *req_desc = lrbp->utr_descriptor_ptr;
u32 data_direction;
@@ -2520,8 +2606,8 @@ static void ufshcd_prepare_req_desc_hdr(struct ufshcd_lrb *lrbp,
*upiu_flags = UPIU_CMD_FLAGS_NONE;
}
- dword_0 = data_direction | (lrbp->command_type
- << UPIU_COMMAND_TYPE_OFFSET);
+ dword_0 = data_direction | (lrbp->command_type << UPIU_COMMAND_TYPE_OFFSET) |
+ ehs_length << 8;
if (lrbp->intr_cmd)
dword_0 |= UTP_REQ_DESC_INT_CMD;
@@ -2576,8 +2662,7 @@ void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufshcd_lrb *lrbp, u8 upiu_flags)
}
/**
- * ufshcd_prepare_utp_query_req_upiu() - fills the utp_transfer_req_desc,
- * for query requsts
+ * ufshcd_prepare_utp_query_req_upiu() - fill the utp_transfer_req_desc for query request
* @hba: UFS hba
* @lrbp: local reference block pointer
* @upiu_flags: flags
@@ -2648,7 +2733,7 @@ static int ufshcd_compose_devman_upiu(struct ufs_hba *hba,
else
lrbp->command_type = UTP_CMD_TYPE_UFS_STORAGE;
- ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags, DMA_NONE);
+ ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags, DMA_NONE, 0);
if (hba->dev_cmd.type == DEV_CMD_TYPE_QUERY)
ufshcd_prepare_utp_query_req_upiu(hba, lrbp, upiu_flags);
else if (hba->dev_cmd.type == DEV_CMD_TYPE_NOP)
@@ -2676,8 +2761,7 @@ static int ufshcd_comp_scsi_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
lrbp->command_type = UTP_CMD_TYPE_UFS_STORAGE;
if (likely(lrbp->cmd)) {
- ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags,
- lrbp->cmd->sc_data_direction);
+ ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags, lrbp->cmd->sc_data_direction, 0);
ufshcd_prepare_utp_scsi_cmd_upiu(lrbp, upiu_flags);
} else {
ret = -EINVAL;
@@ -2709,33 +2793,38 @@ static inline bool is_device_wlun(struct scsi_device *sdev)
*/
static void ufshcd_map_queues(struct Scsi_Host *shost)
{
- int i;
+ struct ufs_hba *hba = shost_priv(shost);
+ int i, queue_offset = 0;
+
+ if (!is_mcq_supported(hba)) {
+ hba->nr_queues[HCTX_TYPE_DEFAULT] = 1;
+ hba->nr_queues[HCTX_TYPE_READ] = 0;
+ hba->nr_queues[HCTX_TYPE_POLL] = 1;
+ hba->nr_hw_queues = 1;
+ }
for (i = 0; i < shost->nr_maps; i++) {
struct blk_mq_queue_map *map = &shost->tag_set.map[i];
- switch (i) {
- case HCTX_TYPE_DEFAULT:
- case HCTX_TYPE_POLL:
- map->nr_queues = 1;
- break;
- case HCTX_TYPE_READ:
- map->nr_queues = 0;
+ map->nr_queues = hba->nr_queues[i];
+ if (!map->nr_queues)
continue;
- default:
- WARN_ON_ONCE(true);
- }
- map->queue_offset = 0;
+ map->queue_offset = queue_offset;
+ if (i == HCTX_TYPE_POLL && !is_mcq_supported(hba))
+ map->queue_offset = 0;
+
blk_mq_map_queues(map);
+ queue_offset += map->nr_queues;
}
}
static void ufshcd_init_lrb(struct ufs_hba *hba, struct ufshcd_lrb *lrb, int i)
{
- struct utp_transfer_cmd_desc *cmd_descp = hba->ucdl_base_addr;
+ struct utp_transfer_cmd_desc *cmd_descp = (void *)hba->ucdl_base_addr +
+ i * sizeof_utp_transfer_cmd_desc(hba);
struct utp_transfer_req_desc *utrdlp = hba->utrdl_base_addr;
dma_addr_t cmd_desc_element_addr = hba->ucdl_dma_addr +
- i * sizeof(struct utp_transfer_cmd_desc);
+ i * sizeof_utp_transfer_cmd_desc(hba);
u16 response_offset = offsetof(struct utp_transfer_cmd_desc,
response_upiu);
u16 prdt_offset = offsetof(struct utp_transfer_cmd_desc, prd_table);
@@ -2743,11 +2832,11 @@ static void ufshcd_init_lrb(struct ufs_hba *hba, struct ufshcd_lrb *lrb, int i)
lrb->utr_descriptor_ptr = utrdlp + i;
lrb->utrd_dma_addr = hba->utrdl_dma_addr +
i * sizeof(struct utp_transfer_req_desc);
- lrb->ucd_req_ptr = (struct utp_upiu_req *)(cmd_descp + i);
+ lrb->ucd_req_ptr = (struct utp_upiu_req *)cmd_descp->command_upiu;
lrb->ucd_req_dma_addr = cmd_desc_element_addr;
- lrb->ucd_rsp_ptr = (struct utp_upiu_rsp *)cmd_descp[i].response_upiu;
+ lrb->ucd_rsp_ptr = (struct utp_upiu_rsp *)cmd_descp->response_upiu;
lrb->ucd_rsp_dma_addr = cmd_desc_element_addr + response_offset;
- lrb->ucd_prdt_ptr = cmd_descp[i].prd_table;
+ lrb->ucd_prdt_ptr = (struct ufshcd_sg_entry *)cmd_descp->prd_table;
lrb->ucd_prdt_dma_addr = cmd_desc_element_addr + prdt_offset;
}
@@ -2764,6 +2853,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
int tag = scsi_cmd_to_rq(cmd)->tag;
struct ufshcd_lrb *lrbp;
int err = 0;
+ struct ufs_hw_queue *hwq = NULL;
WARN_ONCE(tag < 0 || tag >= hba->nutrs, "Invalid tag %d\n", tag);
@@ -2848,7 +2938,10 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
goto out;
}
- ufshcd_send_command(hba, tag);
+ if (is_mcq_enabled(hba))
+ hwq = ufshcd_mcq_req_to_hwq(hba, scsi_cmd_to_rq(cmd));
+
+ ufshcd_send_command(hba, tag, hwq);
out:
rcu_read_unlock();
@@ -2943,6 +3036,12 @@ ufshcd_dev_cmd_completion(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
dev_err(hba->dev, "%s: Reject UPIU not fully implemented\n",
__func__);
break;
+ case UPIU_TRANSACTION_RESPONSE:
+ if (hba->dev_cmd.type != DEV_CMD_TYPE_RPMB) {
+ err = -EINVAL;
+ dev_err(hba->dev, "%s: unexpected response %x\n", __func__, resp);
+ }
+ break;
default:
err = -EINVAL;
dev_err(hba->dev, "%s: Invalid device management cmd response: %x\n",
@@ -2972,7 +3071,7 @@ retry:
* not trigger any race conditions.
*/
hba->dev_cmd.complete = NULL;
- err = ufshcd_get_tr_ocs(lrbp);
+ err = ufshcd_get_tr_ocs(lrbp, hba->dev_cmd.cqe);
if (!err)
err = ufshcd_dev_cmd_completion(hba, lrbp);
} else {
@@ -3008,6 +3107,22 @@ retry:
} else {
dev_err(hba->dev, "%s: failed to clear tag %d\n",
__func__, lrbp->task_tag);
+
+ spin_lock_irqsave(&hba->outstanding_lock, flags);
+ pending = test_bit(lrbp->task_tag,
+ &hba->outstanding_reqs);
+ if (pending)
+ hba->dev_cmd.complete = NULL;
+ spin_unlock_irqrestore(&hba->outstanding_lock, flags);
+
+ if (!pending) {
+ /*
+ * The completion handler ran while we tried to
+ * clear the command.
+ */
+ time_left = 1;
+ goto retry;
+ }
}
}
@@ -3043,10 +3158,11 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba *hba,
goto out;
hba->dev_cmd.complete = &wait;
+ hba->dev_cmd.cqe = NULL;
ufshcd_add_query_upiu_trace(hba, UFS_QUERY_SEND, lrbp->ucd_req_ptr);
- ufshcd_send_command(hba, tag);
+ ufshcd_send_command(hba, tag, hba->dev_cmd_queue);
err = ufshcd_wait_for_dev_cmd(hba, lrbp, timeout);
ufshcd_add_query_upiu_trace(hba, err ? UFS_QUERY_ERR : UFS_QUERY_COMP,
(struct utp_upiu_req *)lrbp->ucd_rsp_ptr);
@@ -3367,37 +3483,6 @@ int ufshcd_query_descriptor_retry(struct ufs_hba *hba,
}
/**
- * ufshcd_map_desc_id_to_length - map descriptor IDN to its length
- * @hba: Pointer to adapter instance
- * @desc_id: descriptor idn value
- * @desc_len: mapped desc length (out)
- */
-void ufshcd_map_desc_id_to_length(struct ufs_hba *hba, enum desc_idn desc_id,
- int *desc_len)
-{
- if (desc_id >= QUERY_DESC_IDN_MAX || desc_id == QUERY_DESC_IDN_RFU_0 ||
- desc_id == QUERY_DESC_IDN_RFU_1)
- *desc_len = 0;
- else
- *desc_len = hba->desc_size[desc_id];
-}
-EXPORT_SYMBOL(ufshcd_map_desc_id_to_length);
-
-static void ufshcd_update_desc_length(struct ufs_hba *hba,
- enum desc_idn desc_id, int desc_index,
- unsigned char desc_len)
-{
- if (hba->desc_size[desc_id] == QUERY_DESC_MAX_SIZE &&
- desc_id != QUERY_DESC_IDN_STRING && desc_index != UFS_RPMB_UNIT)
- /* For UFS 3.1, the normal unit descriptor is 10 bytes larger
- * than the RPMB unit, however, both descriptors share the same
- * desc_idn, to cover both unit descriptors with one length, we
- * choose the normal unit descriptor length by desc_index.
- */
- hba->desc_size[desc_id] = desc_len;
-}
-
-/**
* ufshcd_read_desc_param - read the specified descriptor parameter
* @hba: Pointer to adapter instance
* @desc_id: descriptor idn value
@@ -3417,26 +3502,13 @@ int ufshcd_read_desc_param(struct ufs_hba *hba,
{
int ret;
u8 *desc_buf;
- int buff_len;
+ int buff_len = QUERY_DESC_MAX_SIZE;
bool is_kmalloc = true;
/* Safety check */
if (desc_id >= QUERY_DESC_IDN_MAX || !param_size)
return -EINVAL;
- /* Get the length of descriptor */
- ufshcd_map_desc_id_to_length(hba, desc_id, &buff_len);
- if (!buff_len) {
- dev_err(hba->dev, "%s: Failed to get desc length\n", __func__);
- return -EINVAL;
- }
-
- if (param_offset >= buff_len) {
- dev_err(hba->dev, "%s: Invalid offset 0x%x in descriptor IDN 0x%x, length 0x%x\n",
- __func__, param_offset, desc_id, buff_len);
- return -EINVAL;
- }
-
/* Check whether we need temp memory */
if (param_offset != 0 || param_size < buff_len) {
desc_buf = kzalloc(buff_len, GFP_KERNEL);
@@ -3449,15 +3521,24 @@ int ufshcd_read_desc_param(struct ufs_hba *hba,
/* Request for full descriptor */
ret = ufshcd_query_descriptor_retry(hba, UPIU_QUERY_OPCODE_READ_DESC,
- desc_id, desc_index, 0,
- desc_buf, &buff_len);
-
+ desc_id, desc_index, 0,
+ desc_buf, &buff_len);
if (ret) {
dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d, desc_index %d, param_offset %d, ret %d\n",
__func__, desc_id, desc_index, param_offset, ret);
goto out;
}
+ /* Update descriptor length */
+ buff_len = desc_buf[QUERY_DESC_LENGTH_OFFSET];
+
+ if (param_offset >= buff_len) {
+ dev_err(hba->dev, "%s: Invalid offset 0x%x in descriptor IDN 0x%x, length 0x%x\n",
+ __func__, param_offset, desc_id, buff_len);
+ ret = -EINVAL;
+ goto out;
+ }
+
/* Sanity check */
if (desc_buf[QUERY_DESC_DESC_TYPE_OFFSET] != desc_id) {
dev_err(hba->dev, "%s: invalid desc_id %d in descriptor header\n",
@@ -3466,10 +3547,6 @@ int ufshcd_read_desc_param(struct ufs_hba *hba,
goto out;
}
- /* Update descriptor length */
- buff_len = desc_buf[QUERY_DESC_LENGTH_OFFSET];
- ufshcd_update_desc_length(hba, desc_id, desc_index, buff_len);
-
if (is_kmalloc) {
/* Make sure we don't copy more data than available */
if (param_offset >= buff_len)
@@ -3656,7 +3733,7 @@ static int ufshcd_memory_alloc(struct ufs_hba *hba)
size_t utmrdl_size, utrdl_size, ucdl_size;
/* Allocate memory for UTP command descriptors */
- ucdl_size = (sizeof(struct utp_transfer_cmd_desc) * hba->nutrs);
+ ucdl_size = sizeof_utp_transfer_cmd_desc(hba) * hba->nutrs;
hba->ucdl_base_addr = dmam_alloc_coherent(hba->dev,
ucdl_size,
&hba->ucdl_dma_addr,
@@ -3664,12 +3741,9 @@ static int ufshcd_memory_alloc(struct ufs_hba *hba)
/*
* UFSHCI requires UTP command descriptor to be 128 byte aligned.
- * make sure hba->ucdl_dma_addr is aligned to PAGE_SIZE
- * if hba->ucdl_dma_addr is aligned to PAGE_SIZE, then it will
- * be aligned to 128 bytes as well
*/
if (!hba->ucdl_base_addr ||
- WARN_ON(hba->ucdl_dma_addr & (PAGE_SIZE - 1))) {
+ WARN_ON(hba->ucdl_dma_addr & (128 - 1))) {
dev_err(hba->dev,
"Command Descriptor Memory allocation failed\n");
goto out;
@@ -3685,13 +3759,21 @@ static int ufshcd_memory_alloc(struct ufs_hba *hba)
&hba->utrdl_dma_addr,
GFP_KERNEL);
if (!hba->utrdl_base_addr ||
- WARN_ON(hba->utrdl_dma_addr & (PAGE_SIZE - 1))) {
+ WARN_ON(hba->utrdl_dma_addr & (1024 - 1))) {
dev_err(hba->dev,
"Transfer Descriptor Memory allocation failed\n");
goto out;
}
/*
+ * Skip utmrdl allocation; it may have been
+ * allocated during first pass and not released during
+ * MCQ memory allocation.
+ * See ufshcd_release_sdb_queue() and ufshcd_config_mcq()
+ */
+ if (hba->utmrdl_base_addr)
+ goto skip_utmrdl;
+ /*
* Allocate memory for UTP Task Management descriptors
* UFSHCI requires 1024 byte alignment of UTMRD
*/
@@ -3701,12 +3783,13 @@ static int ufshcd_memory_alloc(struct ufs_hba *hba)
&hba->utmrdl_dma_addr,
GFP_KERNEL);
if (!hba->utmrdl_base_addr ||
- WARN_ON(hba->utmrdl_dma_addr & (PAGE_SIZE - 1))) {
+ WARN_ON(hba->utmrdl_dma_addr & (1024 - 1))) {
dev_err(hba->dev,
"Task Management Descriptor Memory allocation failed\n");
goto out;
}
+skip_utmrdl:
/* Allocate memory for local reference block */
hba->lrb = devm_kcalloc(hba->dev,
hba->nutrs, sizeof(struct ufshcd_lrb),
@@ -3750,7 +3833,7 @@ static void ufshcd_host_memory_configure(struct ufs_hba *hba)
prdt_offset =
offsetof(struct utp_transfer_cmd_desc, prd_table);
- cmd_desc_size = sizeof(struct utp_transfer_cmd_desc);
+ cmd_desc_size = sizeof_utp_transfer_cmd_desc(hba);
cmd_desc_dma_addr = hba->ucdl_dma_addr;
for (i = 0; i < hba->nutrs; i++) {
@@ -4907,7 +4990,7 @@ static void ufshcd_setup_links(struct ufs_hba *hba, struct scsi_device *sdev)
*/
static void ufshcd_lu_init(struct ufs_hba *hba, struct scsi_device *sdev)
{
- int len = hba->desc_size[QUERY_DESC_IDN_UNIT];
+ int len = QUERY_DESC_MAX_SIZE;
u8 lun = ufshcd_scsi_to_upiu_lun(sdev->lun);
u8 lun_qdepth = hba->nutrs;
u8 *desc_buf;
@@ -4942,6 +5025,12 @@ static void ufshcd_lu_init(struct ufs_hba *hba, struct scsi_device *sdev)
desc_buf[UNIT_DESC_PARAM_LU_WR_PROTECT] == UFS_LU_POWER_ON_WP)
hba->dev_info.is_lu_power_on_wp = true;
+ /* In case of RPMB LU, check if advanced RPMB mode is enabled */
+ if (desc_buf[UNIT_DESC_PARAM_UNIT_INDEX] == UFS_UPIU_RPMB_WLUN &&
+ desc_buf[RPMB_UNIT_DESC_PARAM_REGION_EN] & BIT(4))
+ hba->dev_info.b_advanced_rpmb_en = true;
+
+
kfree(desc_buf);
set_qdepth:
/*
@@ -5030,8 +5119,8 @@ static int ufshcd_slave_configure(struct scsi_device *sdev)
ufshcd_hpb_configure(hba, sdev);
blk_queue_update_dma_pad(q, PRDT_DATA_BYTE_COUNT_PAD - 1);
- if (hba->quirks & UFSHCD_QUIRK_ALIGN_SG_WITH_PAGE_SIZE)
- blk_queue_update_dma_alignment(q, PAGE_SIZE - 1);
+ if (hba->quirks & UFSHCD_QUIRK_4KB_DMA_ALIGNMENT)
+ blk_queue_update_dma_alignment(q, 4096 - 1);
/*
* Block runtime-pm until all consumers are added.
* Refer ufshcd_setup_links().
@@ -5130,18 +5219,20 @@ ufshcd_scsi_cmd_status(struct ufshcd_lrb *lrbp, int scsi_status)
* ufshcd_transfer_rsp_status - Get overall status of the response
* @hba: per adapter instance
* @lrbp: pointer to local reference block of completed command
+ * @cqe: pointer to the completion queue entry
*
* Returns result of the command to notify SCSI midlayer
*/
static inline int
-ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
+ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp,
+ struct cq_entry *cqe)
{
int result = 0;
int scsi_status;
enum utp_ocs ocs;
/* overall command status of utrd */
- ocs = ufshcd_get_tr_ocs(lrbp);
+ ocs = ufshcd_get_tr_ocs(lrbp, cqe);
if (hba->quirks & UFSHCD_QUIRK_BROKEN_OCS_FATAL_ERROR) {
if (be32_to_cpu(lrbp->ucd_rsp_ptr->header.dword_1) &
@@ -5306,42 +5397,53 @@ static void ufshcd_release_scsi_cmd(struct ufs_hba *hba,
}
/**
- * __ufshcd_transfer_req_compl - handle SCSI and query command completion
+ * ufshcd_compl_one_cqe - handle a completion queue entry
* @hba: per adapter instance
- * @completed_reqs: bitmask that indicates which requests to complete
+ * @task_tag: the task tag of the request to be completed
+ * @cqe: pointer to the completion queue entry
*/
-static void __ufshcd_transfer_req_compl(struct ufs_hba *hba,
- unsigned long completed_reqs)
+void ufshcd_compl_one_cqe(struct ufs_hba *hba, int task_tag,
+ struct cq_entry *cqe)
{
struct ufshcd_lrb *lrbp;
struct scsi_cmnd *cmd;
- int index;
-
- for_each_set_bit(index, &completed_reqs, hba->nutrs) {
- lrbp = &hba->lrb[index];
- lrbp->compl_time_stamp = ktime_get();
- lrbp->compl_time_stamp_local_clock = local_clock();
- cmd = lrbp->cmd;
- if (cmd) {
- if (unlikely(ufshcd_should_inform_monitor(hba, lrbp)))
- ufshcd_update_monitor(hba, lrbp);
- ufshcd_add_command_trace(hba, index, UFS_CMD_COMP);
- cmd->result = ufshcd_transfer_rsp_status(hba, lrbp);
- ufshcd_release_scsi_cmd(hba, lrbp);
- /* Do not touch lrbp after scsi done */
- scsi_done(cmd);
- } else if (lrbp->command_type == UTP_CMD_TYPE_DEV_MANAGE ||
- lrbp->command_type == UTP_CMD_TYPE_UFS_STORAGE) {
- if (hba->dev_cmd.complete) {
- ufshcd_add_command_trace(hba, index,
- UFS_DEV_COMP);
- complete(hba->dev_cmd.complete);
- ufshcd_clk_scaling_update_busy(hba);
- }
+
+ lrbp = &hba->lrb[task_tag];
+ lrbp->compl_time_stamp = ktime_get();
+ cmd = lrbp->cmd;
+ if (cmd) {
+ if (unlikely(ufshcd_should_inform_monitor(hba, lrbp)))
+ ufshcd_update_monitor(hba, lrbp);
+ ufshcd_add_command_trace(hba, task_tag, UFS_CMD_COMP);
+ cmd->result = ufshcd_transfer_rsp_status(hba, lrbp, cqe);
+ ufshcd_release_scsi_cmd(hba, lrbp);
+ /* Do not touch lrbp after scsi done */
+ scsi_done(cmd);
+ } else if (lrbp->command_type == UTP_CMD_TYPE_DEV_MANAGE ||
+ lrbp->command_type == UTP_CMD_TYPE_UFS_STORAGE) {
+ if (hba->dev_cmd.complete) {
+ hba->dev_cmd.cqe = cqe;
+ ufshcd_add_command_trace(hba, task_tag, UFS_DEV_COMP);
+ complete(hba->dev_cmd.complete);
+ ufshcd_clk_scaling_update_busy(hba);
}
}
}
+/**
+ * __ufshcd_transfer_req_compl - handle SCSI and query command completion
+ * @hba: per adapter instance
+ * @completed_reqs: bitmask that indicates which requests to complete
+ */
+static void __ufshcd_transfer_req_compl(struct ufs_hba *hba,
+ unsigned long completed_reqs)
+{
+ int tag;
+
+ for_each_set_bit(tag, &completed_reqs, hba->nutrs)
+ ufshcd_compl_one_cqe(hba, tag, NULL);
+}
+
/* Any value that is not an existing queue number is fine for this constant. */
enum {
UFSHCD_POLL_FROM_INTERRUPT_CONTEXT = -1
@@ -5371,6 +5473,13 @@ static int ufshcd_poll(struct Scsi_Host *shost, unsigned int queue_num)
struct ufs_hba *hba = shost_priv(shost);
unsigned long completed_reqs, flags;
u32 tr_doorbell;
+ struct ufs_hw_queue *hwq;
+
+ if (is_mcq_enabled(hba)) {
+ hwq = &hba->uhq[queue_num + UFSHCD_MCQ_IO_QUEUE_OFFSET];
+
+ return ufshcd_mcq_poll_cqe_lock(hba, hwq);
+ }
spin_lock_irqsave(&hba->outstanding_lock, flags);
tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
@@ -6604,6 +6713,40 @@ static irqreturn_t ufshcd_tmc_handler(struct ufs_hba *hba)
}
/**
+ * ufshcd_handle_mcq_cq_events - handle MCQ completion queue events
+ * @hba: per adapter instance
+ *
+ * Returns IRQ_HANDLED if interrupt is handled
+ */
+static irqreturn_t ufshcd_handle_mcq_cq_events(struct ufs_hba *hba)
+{
+ struct ufs_hw_queue *hwq;
+ unsigned long outstanding_cqs;
+ unsigned int nr_queues;
+ int i, ret;
+ u32 events;
+
+ ret = ufshcd_vops_get_outstanding_cqs(hba, &outstanding_cqs);
+ if (ret)
+ outstanding_cqs = (1U << hba->nr_hw_queues) - 1;
+
+ /* Exclude the poll queues */
+ nr_queues = hba->nr_hw_queues - hba->nr_queues[HCTX_TYPE_POLL];
+ for_each_set_bit(i, &outstanding_cqs, nr_queues) {
+ hwq = &hba->uhq[i];
+
+ events = ufshcd_mcq_read_cqis(hba, i);
+ if (events)
+ ufshcd_mcq_write_cqis(hba, events, i);
+
+ if (events & UFSHCD_MCQ_CQIS_TAIL_ENT_PUSH_STS)
+ ufshcd_mcq_poll_cqe_nolock(hba, hwq);
+ }
+
+ return IRQ_HANDLED;
+}
+
+/**
* ufshcd_sl_intr - Interrupt service routine
* @hba: per adapter instance
* @intr_status: contains interrupts generated by the controller
@@ -6628,6 +6771,9 @@ static irqreturn_t ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status)
if (intr_status & UTP_TRANSFER_REQ_COMPL)
retval |= ufshcd_transfer_req_compl(hba);
+ if (intr_status & MCQ_CQ_EVENT_STATUS)
+ retval |= ufshcd_handle_mcq_cq_events(hba);
+
return retval;
}
@@ -6876,7 +7022,7 @@ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba,
/* update the task tag in the request upiu */
req_upiu->header.dword_0 |= cpu_to_be32(tag);
- ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags, DMA_NONE);
+ ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags, DMA_NONE, 0);
/* just copy the upiu request as it is */
memcpy(lrbp->ucd_req_ptr, req_upiu, sizeof(*lrbp->ucd_req_ptr));
@@ -6895,7 +7041,7 @@ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba,
ufshcd_add_query_upiu_trace(hba, UFS_QUERY_SEND, lrbp->ucd_req_ptr);
- ufshcd_send_command(hba, tag);
+ ufshcd_send_command(hba, tag, hba->dev_cmd_queue);
/*
* ignore the returning value here - ufshcd_check_query_response is
* bound to fail since dev_cmd.query and dev_cmd.type were left empty.
@@ -7000,6 +7146,100 @@ int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba,
}
/**
+ * ufshcd_advanced_rpmb_req_handler - handle advanced RPMB request
+ * @hba: per adapter instance
+ * @req_upiu: upiu request
+ * @rsp_upiu: upiu reply
+ * @req_ehs: EHS field which contains Advanced RPMB Request Message
+ * @rsp_ehs: EHS field which returns Advanced RPMB Response Message
+ * @sg_cnt: The number of sg lists actually used
+ * @sg_list: Pointer to SG list when DATA IN/OUT UPIU is required in ARPMB operation
+ * @dir: DMA direction
+ *
+ * Returns zero on success, non-zero on failure
+ */
+int ufshcd_advanced_rpmb_req_handler(struct ufs_hba *hba, struct utp_upiu_req *req_upiu,
+ struct utp_upiu_req *rsp_upiu, struct ufs_ehs *req_ehs,
+ struct ufs_ehs *rsp_ehs, int sg_cnt, struct scatterlist *sg_list,
+ enum dma_data_direction dir)
+{
+ DECLARE_COMPLETION_ONSTACK(wait);
+ const u32 tag = hba->reserved_slot;
+ struct ufshcd_lrb *lrbp;
+ int err = 0;
+ int result;
+ u8 upiu_flags;
+ u8 *ehs_data;
+ u16 ehs_len;
+
+ /* Protects use of hba->reserved_slot. */
+ ufshcd_hold(hba, false);
+ mutex_lock(&hba->dev_cmd.lock);
+ down_read(&hba->clk_scaling_lock);
+
+ lrbp = &hba->lrb[tag];
+ WARN_ON(lrbp->cmd);
+ lrbp->cmd = NULL;
+ lrbp->task_tag = tag;
+ lrbp->lun = UFS_UPIU_RPMB_WLUN;
+
+ lrbp->intr_cmd = true;
+ ufshcd_prepare_lrbp_crypto(NULL, lrbp);
+ hba->dev_cmd.type = DEV_CMD_TYPE_RPMB;
+
+ /* Advanced RPMB starts from UFS 4.0, so its command type is UTP_CMD_TYPE_UFS_STORAGE */
+ lrbp->command_type = UTP_CMD_TYPE_UFS_STORAGE;
+
+ ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags, dir, 2);
+
+ /* update the task tag and LUN in the request upiu */
+ req_upiu->header.dword_0 |= cpu_to_be32(upiu_flags << 16 | UFS_UPIU_RPMB_WLUN << 8 | tag);
+
+ /* copy the UPIU(contains CDB) request as it is */
+ memcpy(lrbp->ucd_req_ptr, req_upiu, sizeof(*lrbp->ucd_req_ptr));
+ /* Copy EHS, starting with byte32, immediately after the CDB package */
+ memcpy(lrbp->ucd_req_ptr + 1, req_ehs, sizeof(*req_ehs));
+
+ if (dir != DMA_NONE && sg_list)
+ ufshcd_sgl_to_prdt(hba, lrbp, sg_cnt, sg_list);
+
+ memset(lrbp->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp));
+
+ hba->dev_cmd.complete = &wait;
+
+ ufshcd_send_command(hba, tag, hba->dev_cmd_queue);
+
+ err = ufshcd_wait_for_dev_cmd(hba, lrbp, ADVANCED_RPMB_REQ_TIMEOUT);
+
+ if (!err) {
+ /* Just copy the upiu response as it is */
+ memcpy(rsp_upiu, lrbp->ucd_rsp_ptr, sizeof(*rsp_upiu));
+ /* Get the response UPIU result */
+ result = ufshcd_get_rsp_upiu_result(lrbp->ucd_rsp_ptr);
+
+ ehs_len = be32_to_cpu(lrbp->ucd_rsp_ptr->header.dword_2) >> 24;
+ /*
+ * Since the bLength in EHS indicates the total size of the EHS Header and EHS Data
+ * in 32 Byte units, the value of the bLength Request/Response for Advanced RPMB
+ * Message is 02h
+ */
+ if (ehs_len == 2 && rsp_ehs) {
+ /*
+ * ucd_rsp_ptr points to a buffer with a length of 512 bytes
+ * (ALIGNED_UPIU_SIZE = 512), and the EHS data just starts from byte32
+ */
+ ehs_data = (u8 *)lrbp->ucd_rsp_ptr + EHS_OFFSET_IN_RESPONSE;
+ memcpy(rsp_ehs, ehs_data, ehs_len * 32);
+ }
+ }
+
+ up_read(&hba->clk_scaling_lock);
+ mutex_unlock(&hba->dev_cmd.lock);
+ ufshcd_release(hba);
+ return err ? : result;
+}
+
+/**
* ufshcd_eh_device_reset_handler() - Reset a single logical unit.
* @cmd: SCSI command pointer
*
@@ -7441,12 +7681,11 @@ static u32 ufshcd_get_max_icc_level(int sup_curr_uA, u32 start_scan,
* In case regulators are not initialized we'll return 0
* @hba: per-adapter instance
* @desc_buf: power descriptor buffer to extract ICC levels from.
- * @len: length of desc_buff
*
* Returns calculated ICC level
*/
static u32 ufshcd_find_max_sup_active_icc_level(struct ufs_hba *hba,
- const u8 *desc_buf, int len)
+ const u8 *desc_buf)
{
u32 icc_level = 0;
@@ -7488,25 +7727,23 @@ out:
static void ufshcd_set_active_icc_lvl(struct ufs_hba *hba)
{
int ret;
- int buff_len = hba->desc_size[QUERY_DESC_IDN_POWER];
u8 *desc_buf;
u32 icc_level;
- desc_buf = kmalloc(buff_len, GFP_KERNEL);
+ desc_buf = kzalloc(QUERY_DESC_MAX_SIZE, GFP_KERNEL);
if (!desc_buf)
return;
ret = ufshcd_read_desc_param(hba, QUERY_DESC_IDN_POWER, 0, 0,
- desc_buf, buff_len);
+ desc_buf, QUERY_DESC_MAX_SIZE);
if (ret) {
dev_err(hba->dev,
- "%s: Failed reading power descriptor.len = %d ret = %d",
- __func__, buff_len, ret);
+ "%s: Failed reading power descriptor ret = %d",
+ __func__, ret);
goto out;
}
- icc_level = ufshcd_find_max_sup_active_icc_level(hba, desc_buf,
- buff_len);
+ icc_level = ufshcd_find_max_sup_active_icc_level(hba, desc_buf);
dev_dbg(hba->dev, "%s: setting icc_level 0x%x", __func__, icc_level);
ret = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_WRITE_ATTR,
@@ -7616,10 +7853,6 @@ static void ufshcd_wb_probe(struct ufs_hba *hba, const u8 *desc_buf)
(hba->dev_quirks & UFS_DEVICE_QUIRK_SUPPORT_EXTENDED_FEATURES)))
goto wb_disabled;
- if (hba->desc_size[QUERY_DESC_IDN_DEVICE] <
- DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP + 4)
- goto wb_disabled;
-
ext_ufs_feature = get_unaligned_be32(desc_buf +
DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP);
@@ -7690,6 +7923,31 @@ static void ufshcd_temp_notif_probe(struct ufs_hba *hba, const u8 *desc_buf)
}
}
+static void ufshcd_ext_iid_probe(struct ufs_hba *hba, u8 *desc_buf)
+{
+ struct ufs_dev_info *dev_info = &hba->dev_info;
+ u32 ext_ufs_feature;
+ u32 ext_iid_en = 0;
+ int err;
+
+ /* Only UFS-4.0 and above may support EXT_IID */
+ if (dev_info->wspecversion < 0x400)
+ goto out;
+
+ ext_ufs_feature = get_unaligned_be32(desc_buf +
+ DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP);
+ if (!(ext_ufs_feature & UFS_DEV_EXT_IID_SUP))
+ goto out;
+
+ err = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR,
+ QUERY_ATTR_IDN_EXT_IID_EN, 0, 0, &ext_iid_en);
+ if (err)
+ dev_err(hba->dev, "failed reading bEXTIIDEn. err = %d\n", err);
+
+out:
+ dev_info->b_ext_iid_en = ext_iid_en;
+}
+
void ufshcd_fixup_dev_quirks(struct ufs_hba *hba,
const struct ufs_dev_quirk *fixups)
{
@@ -7727,14 +7985,14 @@ static int ufs_get_device_desc(struct ufs_hba *hba)
u8 *desc_buf;
struct ufs_dev_info *dev_info = &hba->dev_info;
- desc_buf = kmalloc(QUERY_DESC_MAX_SIZE, GFP_KERNEL);
+ desc_buf = kzalloc(QUERY_DESC_MAX_SIZE, GFP_KERNEL);
if (!desc_buf) {
err = -ENOMEM;
goto out;
}
err = ufshcd_read_desc_param(hba, QUERY_DESC_IDN_DEVICE, 0, 0, desc_buf,
- hba->desc_size[QUERY_DESC_IDN_DEVICE]);
+ QUERY_DESC_MAX_SIZE);
if (err) {
dev_err(hba->dev, "%s: Failed reading Device Desc. err = %d\n",
__func__, err);
@@ -7751,6 +8009,7 @@ static int ufs_get_device_desc(struct ufs_hba *hba)
/* getting Specification Version in big endian format */
dev_info->wspecversion = desc_buf[DEVICE_DESC_PARAM_SPEC_VER] << 8 |
desc_buf[DEVICE_DESC_PARAM_SPEC_VER + 1];
+ dev_info->bqueuedepth = desc_buf[DEVICE_DESC_PARAM_Q_DPTH];
b_ufs_feature_sup = desc_buf[DEVICE_DESC_PARAM_UFS_FEAT];
model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME];
@@ -7788,6 +8047,9 @@ static int ufs_get_device_desc(struct ufs_hba *hba)
ufshcd_temp_notif_probe(hba, desc_buf);
+ if (hba->ext_iid_sup)
+ ufshcd_ext_iid_probe(hba, desc_buf);
+
/*
* ufshcd_read_string_desc returns size of the string
* reset the error value
@@ -7981,18 +8243,16 @@ static void ufshcd_clear_dbg_ufs_stats(struct ufs_hba *hba)
static int ufshcd_device_geo_params_init(struct ufs_hba *hba)
{
int err;
- size_t buff_len;
u8 *desc_buf;
- buff_len = hba->desc_size[QUERY_DESC_IDN_GEOMETRY];
- desc_buf = kmalloc(buff_len, GFP_KERNEL);
+ desc_buf = kzalloc(QUERY_DESC_MAX_SIZE, GFP_KERNEL);
if (!desc_buf) {
err = -ENOMEM;
goto out;
}
err = ufshcd_read_desc_param(hba, QUERY_DESC_IDN_GEOMETRY, 0, 0,
- desc_buf, buff_len);
+ desc_buf, QUERY_DESC_MAX_SIZE);
if (err) {
dev_err(hba->dev, "%s: Failed reading Geometry Desc. err = %d\n",
__func__, err);
@@ -8004,7 +8264,7 @@ static int ufshcd_device_geo_params_init(struct ufs_hba *hba)
else if (desc_buf[GEOMETRY_DESC_PARAM_MAX_NUM_LUN] == 0)
hba->dev_info.max_lu_supported = 8;
- if (hba->desc_size[QUERY_DESC_IDN_GEOMETRY] >=
+ if (desc_buf[QUERY_DESC_LENGTH_OFFSET] >=
GEOMETRY_DESC_PARAM_HPB_MAX_ACTIVE_REGS)
ufshpb_get_geo_info(hba, desc_buf);
@@ -8089,11 +8349,7 @@ out:
static int ufshcd_device_params_init(struct ufs_hba *hba)
{
bool flag;
- int ret, i;
-
- /* Init device descriptor sizes */
- for (i = 0; i < QUERY_DESC_IDN_MAX; i++)
- hba->desc_size[i] = QUERY_DESC_MAX_SIZE;
+ int ret;
/* Init UFS geometry descriptor related parameters */
ret = ufshcd_device_geo_params_init(hba);
@@ -8161,27 +8417,96 @@ out:
return ret;
}
-/**
- * ufshcd_probe_hba - probe hba to detect device and initialize it
- * @hba: per-adapter instance
- * @init_dev_params: whether or not to call ufshcd_device_params_init().
- *
- * Execute link-startup and verify device initialization
- */
-static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params)
+/* SDB - Single Doorbell */
+static void ufshcd_release_sdb_queue(struct ufs_hba *hba, int nutrs)
+{
+ size_t ucdl_size, utrdl_size;
+
+ ucdl_size = sizeof(struct utp_transfer_cmd_desc) * nutrs;
+ dmam_free_coherent(hba->dev, ucdl_size, hba->ucdl_base_addr,
+ hba->ucdl_dma_addr);
+
+ utrdl_size = sizeof(struct utp_transfer_req_desc) * nutrs;
+ dmam_free_coherent(hba->dev, utrdl_size, hba->utrdl_base_addr,
+ hba->utrdl_dma_addr);
+
+ devm_kfree(hba->dev, hba->lrb);
+}
+
+static int ufshcd_alloc_mcq(struct ufs_hba *hba)
{
int ret;
- unsigned long flags;
- ktime_t start = ktime_get();
+ int old_nutrs = hba->nutrs;
+
+ ret = ufshcd_mcq_decide_queue_depth(hba);
+ if (ret < 0)
+ return ret;
+
+ hba->nutrs = ret;
+ ret = ufshcd_mcq_init(hba);
+ if (ret)
+ goto err;
+
+ /*
+ * Previously allocated memory for nutrs may not be enough in MCQ mode.
+ * Number of supported tags in MCQ mode may be larger than SDB mode.
+ */
+ if (hba->nutrs != old_nutrs) {
+ ufshcd_release_sdb_queue(hba, old_nutrs);
+ ret = ufshcd_memory_alloc(hba);
+ if (ret)
+ goto err;
+ ufshcd_host_memory_configure(hba);
+ }
+
+ ret = ufshcd_mcq_memory_alloc(hba);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ hba->nutrs = old_nutrs;
+ return ret;
+}
+
+static void ufshcd_config_mcq(struct ufs_hba *hba)
+{
+ int ret;
+
+ ret = ufshcd_mcq_vops_config_esi(hba);
+ dev_info(hba->dev, "ESI %sconfigured\n", ret ? "is not " : "");
+
+ ufshcd_enable_intr(hba, UFSHCD_ENABLE_MCQ_INTRS);
+ ufshcd_mcq_make_queues_operational(hba);
+ ufshcd_mcq_config_mac(hba, hba->nutrs);
+
+ hba->host->can_queue = hba->nutrs - UFSHCD_NUM_RESERVED;
+ hba->reserved_slot = hba->nutrs - UFSHCD_NUM_RESERVED;
+
+ /* Select MCQ mode */
+ ufshcd_writel(hba, ufshcd_readl(hba, REG_UFS_MEM_CFG) | 0x1,
+ REG_UFS_MEM_CFG);
+ hba->mcq_enabled = true;
+
+ dev_info(hba->dev, "MCQ configured, nr_queues=%d, io_queues=%d, read_queue=%d, poll_queues=%d, queue_depth=%d\n",
+ hba->nr_hw_queues, hba->nr_queues[HCTX_TYPE_DEFAULT],
+ hba->nr_queues[HCTX_TYPE_READ], hba->nr_queues[HCTX_TYPE_POLL],
+ hba->nutrs);
+}
+
+static int ufshcd_device_init(struct ufs_hba *hba, bool init_dev_params)
+{
+ int ret;
+ struct Scsi_Host *host = hba->host;
hba->ufshcd_state = UFSHCD_STATE_RESET;
ret = ufshcd_link_startup(hba);
if (ret)
- goto out;
+ return ret;
if (hba->quirks & UFSHCD_QUIRK_SKIP_PH_CONFIGURATION)
- goto out;
+ return ret;
/* Debug counters initialization */
ufshcd_clear_dbg_ufs_stats(hba);
@@ -8189,15 +8514,19 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params)
/* UniPro link is active now */
ufshcd_set_link_active(hba);
+ /* Reconfigure MCQ upon reset */
+ if (is_mcq_enabled(hba) && !init_dev_params)
+ ufshcd_config_mcq(hba);
+
/* Verify device initialization by sending NOP OUT UPIU */
ret = ufshcd_verify_dev_init(hba);
if (ret)
- goto out;
+ return ret;
/* Initiate UFS initialization, and waiting until completion */
ret = ufshcd_complete_dev_init(hba);
if (ret)
- goto out;
+ return ret;
/*
* Initialize UFS device parameters used by driver, these
@@ -8206,7 +8535,25 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params)
if (init_dev_params) {
ret = ufshcd_device_params_init(hba);
if (ret)
- goto out;
+ return ret;
+ if (is_mcq_supported(hba) && !hba->scsi_host_added) {
+ ret = ufshcd_alloc_mcq(hba);
+ if (ret) {
+ /* Continue with SDB mode */
+ use_mcq_mode = false;
+ dev_err(hba->dev, "MCQ mode is disabled, err=%d\n",
+ ret);
+ }
+ ret = scsi_add_host(host, hba->dev);
+ if (ret) {
+ dev_err(hba->dev, "scsi_add_host failed\n");
+ return ret;
+ }
+ hba->scsi_host_added = true;
+ }
+ /* MCQ may be disabled if ufshcd_alloc_mcq() fails */
+ if (is_mcq_supported(hba) && use_mcq_mode)
+ ufshcd_config_mcq(hba);
}
ufshcd_tune_unipro_params(hba);
@@ -8227,11 +8574,51 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params)
if (ret) {
dev_err(hba->dev, "%s: Failed setting power mode, err = %d\n",
__func__, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * ufshcd_probe_hba - probe hba to detect device and initialize it
+ * @hba: per-adapter instance
+ * @init_dev_params: whether or not to call ufshcd_device_params_init().
+ *
+ * Execute link-startup and verify device initialization
+ */
+static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params)
+{
+ ktime_t start = ktime_get();
+ unsigned long flags;
+ int ret;
+
+ ret = ufshcd_device_init(hba, init_dev_params);
+ if (ret)
+ goto out;
+
+ if (hba->quirks & UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH) {
+ /* Reset the device and controller before doing reinit */
+ ufshcd_device_reset(hba);
+ ufshcd_hba_stop(hba);
+ ufshcd_vops_reinit_notify(hba);
+ ret = ufshcd_hba_enable(hba);
+ if (ret) {
+ dev_err(hba->dev, "Host controller enable failed\n");
+ ufshcd_print_evt_hist(hba);
+ ufshcd_print_host_state(hba);
goto out;
}
- ufshcd_print_pwr_info(hba);
+
+ /* Reinit the device */
+ ret = ufshcd_device_init(hba, init_dev_params);
+ if (ret)
+ goto out;
}
+ ufshcd_print_pwr_info(hba);
+
/*
* bActiveICCLevel is volatile for UFS device (as per latest v2.1 spec)
* and for removable UFS card as well, hence always set the parameter.
@@ -8359,7 +8746,6 @@ static struct scsi_host_template ufshcd_driver_template = {
.max_host_blocked = 1,
.track_queue_depth = 1,
.sdev_groups = ufshcd_driver_groups,
- .dma_boundary = PAGE_SIZE - 1,
.rpm_autosuspend_delay = RPM_AUTOSUSPEND_DELAY_MS,
};
@@ -9453,6 +9839,7 @@ static int ufshcd_resume(struct ufs_hba *hba)
/* enable the host irq as host controller would be active soon */
ufshcd_enable_irq(hba);
+
goto out;
disable_vreg:
@@ -9616,6 +10003,56 @@ void ufshcd_remove(struct ufs_hba *hba)
}
EXPORT_SYMBOL_GPL(ufshcd_remove);
+#ifdef CONFIG_PM_SLEEP
+int ufshcd_system_freeze(struct device *dev)
+{
+
+ return ufshcd_system_suspend(dev);
+
+}
+EXPORT_SYMBOL_GPL(ufshcd_system_freeze);
+
+int ufshcd_system_restore(struct device *dev)
+{
+
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+ int ret;
+
+ ret = ufshcd_system_resume(dev);
+ if (ret)
+ return ret;
+
+ /* Configure UTRL and UTMRL base address registers */
+ ufshcd_writel(hba, lower_32_bits(hba->utrdl_dma_addr),
+ REG_UTP_TRANSFER_REQ_LIST_BASE_L);
+ ufshcd_writel(hba, upper_32_bits(hba->utrdl_dma_addr),
+ REG_UTP_TRANSFER_REQ_LIST_BASE_H);
+ ufshcd_writel(hba, lower_32_bits(hba->utmrdl_dma_addr),
+ REG_UTP_TASK_REQ_LIST_BASE_L);
+ ufshcd_writel(hba, upper_32_bits(hba->utmrdl_dma_addr),
+ REG_UTP_TASK_REQ_LIST_BASE_H);
+ /*
+ * Make sure that UTRL and UTMRL base address registers
+ * are updated with the latest queue addresses. Only after
+ * updating these addresses, we can queue the new commands.
+ */
+ mb();
+
+ /* Resuming from hibernate, assume that link was OFF */
+ ufshcd_set_link_off(hba);
+
+ return 0;
+
+}
+EXPORT_SYMBOL_GPL(ufshcd_system_restore);
+
+int ufshcd_system_thaw(struct device *dev)
+{
+ return ufshcd_system_resume(dev);
+}
+EXPORT_SYMBOL_GPL(ufshcd_system_thaw);
+#endif /* CONFIG_PM_SLEEP */
+
/**
* ufshcd_dealloc_host - deallocate Host Bus Adapter (HBA)
* @hba: pointer to Host Bus Adapter (HBA)
@@ -9674,6 +10111,7 @@ int ufshcd_alloc_host(struct device *dev, struct ufs_hba **hba_handle)
hba->dev = dev;
hba->dev_ref_clk_freq = REF_CLK_FREQ_INVAL;
hba->nop_out_timeout = NOP_OUT_TIMEOUT;
+ ufshcd_set_sg_entry_size(hba, sizeof(struct ufshcd_sg_entry));
INIT_LIST_HEAD(&hba->clk_list_head);
spin_lock_init(&hba->outstanding_lock);
@@ -9823,10 +10261,12 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
hba->is_irq_enabled = true;
}
- err = scsi_add_host(host, hba->dev);
- if (err) {
- dev_err(hba->dev, "scsi_add_host failed\n");
- goto out_disable;
+ if (!is_mcq_supported(hba)) {
+ err = scsi_add_host(host, hba->dev);
+ if (err) {
+ dev_err(hba->dev, "scsi_add_host failed\n");
+ goto out_disable;
+ }
}
hba->tmf_tag_set = (struct blk_mq_tag_set) {
@@ -10054,11 +10494,6 @@ static int __init ufshcd_core_init(void)
{
int ret;
- /* Verify that there are no gaps in struct utp_transfer_cmd_desc. */
- static_assert(sizeof(struct utp_transfer_cmd_desc) ==
- 2 * ALIGNED_UPIU_SIZE +
- SG_ALL * sizeof(struct ufshcd_sg_entry));
-
ufs_debugfs_init();
ret = scsi_register_driver(&ufs_dev_wlun_template.gendrv);
diff --git a/drivers/ufs/core/ufshpb.c b/drivers/ufs/core/ufshpb.c
index 994f4ac9df5a..a46a7666c891 100644
--- a/drivers/ufs/core/ufshpb.c
+++ b/drivers/ufs/core/ufshpb.c
@@ -2382,12 +2382,10 @@ static int ufshpb_get_lu_info(struct ufs_hba *hba, int lun,
{
u16 max_active_rgns;
u8 lu_enable;
- int size;
+ int size = QUERY_DESC_MAX_SIZE;
int ret;
char desc_buf[QUERY_DESC_MAX_SIZE];
- ufshcd_map_desc_id_to_length(hba, QUERY_DESC_IDN_UNIT, &size);
-
ufshcd_rpm_get_sync(hba);
ret = ufshcd_query_descriptor_retry(hba, UPIU_QUERY_OPCODE_READ_DESC,
QUERY_DESC_IDN_UNIT, lun, 0,
diff --git a/drivers/ufs/host/Kconfig b/drivers/ufs/host/Kconfig
index 4cc2dbd79ed0..663881437921 100644
--- a/drivers/ufs/host/Kconfig
+++ b/drivers/ufs/host/Kconfig
@@ -57,8 +57,9 @@ config SCSI_UFS_DWC_TC_PLATFORM
config SCSI_UFS_QCOM
tristate "QCOM specific hooks to UFS controller platform driver"
depends on SCSI_UFSHCD_PLATFORM && ARCH_QCOM
+ depends on GENERIC_MSI_IRQ
+ depends on RESET_CONTROLLER
select QCOM_SCM if SCSI_UFS_CRYPTO
- select RESET_CONTROLLER
help
This selects the QCOM specific additions to UFSHCD platform driver.
UFS host on QCOM needs some vendor specific configuration before
@@ -124,3 +125,19 @@ config SCSI_UFS_EXYNOS
Select this if you have UFS host controller on Samsung Exynos SoC.
If unsure, say N.
+
+config SCSI_UFS_VARIABLE_SG_ENTRY_SIZE
+ bool
+ default y if SCSI_UFS_EXYNOS && SCSI_UFS_CRYPTO
+
+config SCSI_UFS_SPRD
+ tristate "Unisoc specific hooks to UFS controller platform driver"
+ depends on SCSI_UFSHCD_PLATFORM && (ARCH_SPRD || COMPILE_TEST)
+ help
+ This selects the Unisoc specific additions to UFSHCD platform driver.
+ UFS host on Unisoc needs some vendor specific configuration before
+ accessing the hardware which includes PHY configuration and vendor
+ specific registers.
+
+ Select this if you have UFS controller on Unisoc chipset.
+ If unsure, say N.
diff --git a/drivers/ufs/host/Makefile b/drivers/ufs/host/Makefile
index 7717ca93e7d5..d7c5bf7fa512 100644
--- a/drivers/ufs/host/Makefile
+++ b/drivers/ufs/host/Makefile
@@ -12,4 +12,5 @@ obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.o
obj-$(CONFIG_SCSI_UFS_HISI) += ufs-hisi.o
obj-$(CONFIG_SCSI_UFS_MEDIATEK) += ufs-mediatek.o
obj-$(CONFIG_SCSI_UFS_RENESAS) += ufs-renesas.o
+obj-$(CONFIG_SCSI_UFS_SPRD) += ufs-sprd.o
obj-$(CONFIG_SCSI_UFS_TI_J721E) += ti-j721e-ufs.o
diff --git a/drivers/ufs/host/ufs-exynos.c b/drivers/ufs/host/ufs-exynos.c
index c3628a8645a5..7c985fc38db1 100644
--- a/drivers/ufs/host/ufs-exynos.c
+++ b/drivers/ufs/host/ufs-exynos.c
@@ -1300,6 +1300,14 @@ static int exynos_ufs_hce_enable_notify(struct ufs_hba *hba,
switch (status) {
case PRE_CHANGE:
+ /*
+ * The maximum segment size must be set after scsi_host_alloc()
+ * has been called and before LUN scanning starts
+ * (ufshcd_async_scan()). Note: this callback may also be called
+ * from other functions than ufshcd_init().
+ */
+ hba->host->max_segment_size = 4096;
+
if (ufs->drv_data->pre_hce_enable) {
ret = ufs->drv_data->pre_hce_enable(ufs);
if (ret)
@@ -1673,7 +1681,7 @@ static const struct exynos_ufs_drv_data exynos_ufs_drvs = {
UFSHCD_QUIRK_BROKEN_OCS_FATAL_ERROR |
UFSHCI_QUIRK_SKIP_MANUAL_WB_FLUSH_CTRL |
UFSHCD_QUIRK_SKIP_DEF_UNIPRO_TIMEOUT_SETTING |
- UFSHCD_QUIRK_ALIGN_SG_WITH_PAGE_SIZE,
+ UFSHCD_QUIRK_4KB_DMA_ALIGNMENT,
.opts = EXYNOS_UFS_OPT_HAS_APB_CLK_CTRL |
EXYNOS_UFS_OPT_BROKEN_AUTO_CLK_CTRL |
EXYNOS_UFS_OPT_BROKEN_RX_SEL_IDX |
diff --git a/drivers/ufs/host/ufs-qcom-ice.c b/drivers/ufs/host/ufs-qcom-ice.c
index 62387ccd5b30..453978877ae9 100644
--- a/drivers/ufs/host/ufs-qcom-ice.c
+++ b/drivers/ufs/host/ufs-qcom-ice.c
@@ -8,7 +8,7 @@
#include <linux/delay.h>
#include <linux/platform_device.h>
-#include <linux/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_scm.h>
#include "ufs-qcom.h"
diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c
index 8ad1415e10b6..34fc453f3eb1 100644
--- a/drivers/ufs/host/ufs-qcom.c
+++ b/drivers/ufs/host/ufs-qcom.c
@@ -22,8 +22,11 @@
#include <ufs/ufshci.h>
#include <ufs/ufs_quirks.h>
-#define UFS_QCOM_DEFAULT_DBG_PRINT_EN \
- (UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_TEST_BUS_EN)
+#define MCQ_QCFGPTR_MASK GENMASK(7, 0)
+#define MCQ_QCFGPTR_UNIT 0x200
+#define MCQ_SQATTR_OFFSET(c) \
+ ((((c) >> 16) & MCQ_QCFGPTR_MASK) * MCQ_QCFGPTR_UNIT)
+#define MCQ_QCFG_SIZE 0x40
enum {
TSTBUS_UAWM,
@@ -52,12 +55,6 @@ static struct ufs_qcom_host *rcdev_to_ufs_host(struct reset_controller_dev *rcd)
return container_of(rcd, struct ufs_qcom_host, rcdev);
}
-static void ufs_qcom_dump_regs_wrapper(struct ufs_hba *hba, int offset, int len,
- const char *prefix, void *priv)
-{
- ufshcd_dump_regs(hba, offset, len * 4, prefix);
-}
-
static int ufs_qcom_host_clk_get(struct device *dev,
const char *name, struct clk **clk_out, bool optional)
{
@@ -110,7 +107,7 @@ static void ufs_qcom_disable_lane_clks(struct ufs_qcom_host *host)
static int ufs_qcom_enable_lane_clks(struct ufs_qcom_host *host)
{
- int err = 0;
+ int err;
struct device *dev = host->hba->dev;
if (host->is_lane_clks_enabled)
@@ -119,7 +116,7 @@ static int ufs_qcom_enable_lane_clks(struct ufs_qcom_host *host)
err = ufs_qcom_host_clk_enable(dev, "rx_lane0_sync_clk",
host->rx_l0_sync_clk);
if (err)
- goto out;
+ return err;
err = ufs_qcom_host_clk_enable(dev, "tx_lane0_sync_clk",
host->tx_l0_sync_clk);
@@ -137,7 +134,8 @@ static int ufs_qcom_enable_lane_clks(struct ufs_qcom_host *host)
goto disable_rx_l1;
host->is_lane_clks_enabled = true;
- goto out;
+
+ return 0;
disable_rx_l1:
clk_disable_unprepare(host->rx_l1_sync_clk);
@@ -145,7 +143,7 @@ disable_tx_l0:
clk_disable_unprepare(host->tx_l0_sync_clk);
disable_rx_l0:
clk_disable_unprepare(host->rx_l0_sync_clk);
-out:
+
return err;
}
@@ -160,25 +158,25 @@ static int ufs_qcom_init_lane_clks(struct ufs_qcom_host *host)
err = ufs_qcom_host_clk_get(dev, "rx_lane0_sync_clk",
&host->rx_l0_sync_clk, false);
if (err)
- goto out;
+ return err;
err = ufs_qcom_host_clk_get(dev, "tx_lane0_sync_clk",
&host->tx_l0_sync_clk, false);
if (err)
- goto out;
+ return err;
/* In case of single lane per direction, don't read lane1 clocks */
if (host->hba->lanes_per_direction > 1) {
err = ufs_qcom_host_clk_get(dev, "rx_lane1_sync_clk",
&host->rx_l1_sync_clk, false);
if (err)
- goto out;
+ return err;
err = ufs_qcom_host_clk_get(dev, "tx_lane1_sync_clk",
&host->tx_l1_sync_clk, true);
}
-out:
- return err;
+
+ return 0;
}
static int ufs_qcom_check_hibern8(struct ufs_hba *hba)
@@ -226,6 +224,10 @@ static void ufs_qcom_select_unipro_mode(struct ufs_qcom_host *host)
ufshcd_rmwl(host->hba, QUNIPRO_SEL,
ufs_qcom_cap_qunipro(host) ? QUNIPRO_SEL : 0,
REG_UFS_CFG1);
+
+ if (host->hw_ver.major == 0x05)
+ ufshcd_rmwl(host->hba, QUNIPRO_G4_SEL, 0, REG_UFS_CFG0);
+
/* make sure above configuration is applied before we return */
mb();
}
@@ -241,7 +243,7 @@ static int ufs_qcom_host_reset(struct ufs_hba *hba)
if (!host->core_reset) {
dev_warn(hba->dev, "%s: reset control not set\n", __func__);
- goto out;
+ return 0;
}
reenable_intr = hba->is_irq_enabled;
@@ -252,7 +254,7 @@ static int ufs_qcom_host_reset(struct ufs_hba *hba)
if (ret) {
dev_err(hba->dev, "%s: core_reset assert failed, err = %d\n",
__func__, ret);
- goto out;
+ return ret;
}
/*
@@ -274,16 +276,35 @@ static int ufs_qcom_host_reset(struct ufs_hba *hba)
hba->is_irq_enabled = true;
}
-out:
- return ret;
+ return 0;
+}
+
+static u32 ufs_qcom_get_hs_gear(struct ufs_hba *hba)
+{
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+
+ if (host->hw_ver.major == 0x1) {
+ /*
+ * HS-G3 operations may not reliably work on legacy QCOM
+ * UFS host controller hardware even though capability
+ * exchange during link startup phase may end up
+ * negotiating maximum supported gear as G3.
+ * Hence downgrade the maximum supported gear to HS-G2.
+ */
+ return UFS_HS_G2;
+ } else if (host->hw_ver.major >= 0x4) {
+ return UFS_QCOM_MAX_GEAR(ufshcd_readl(hba, REG_UFS_PARAM0));
+ }
+
+ /* Default is HS-G3 */
+ return UFS_HS_G3;
}
static int ufs_qcom_power_up_sequence(struct ufs_hba *hba)
{
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
struct phy *phy = host->generic_phy;
- int ret = 0;
- bool is_rate_B = UFS_QCOM_LIMIT_HS_RATE == PA_HS_MODE_B;
+ int ret;
/* Reset UFS Host Controller and PHY */
ret = ufs_qcom_host_reset(hba);
@@ -291,17 +312,16 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba)
dev_warn(hba->dev, "%s: host reset returned %d\n",
__func__, ret);
- if (is_rate_B)
- phy_set_mode(phy, PHY_MODE_UFS_HS_B);
-
/* phy initialization - calibrate the phy */
ret = phy_init(phy);
if (ret) {
dev_err(hba->dev, "%s: phy init failed, ret = %d\n",
__func__, ret);
- goto out;
+ return ret;
}
+ phy_set_mode_ext(phy, PHY_MODE_UFS_HS_B, host->hs_gear);
+
/* power on phy - start serdes and phy's power and clocks */
ret = phy_power_on(phy);
if (ret) {
@@ -316,7 +336,7 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba)
out_disable_phy:
phy_exit(phy);
-out:
+
return ret;
}
@@ -374,7 +394,6 @@ static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba,
static int ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear,
u32 hs, u32 rate, bool update_link_startup_timer)
{
- int ret = 0;
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
struct ufs_clk_info *clki;
u32 core_clk_period_in_ns;
@@ -409,11 +428,11 @@ static int ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear,
* Aggregation logic.
*/
if (ufs_qcom_cap_qunipro(host) && !ufshcd_is_intr_aggr_allowed(hba))
- goto out;
+ return 0;
if (gear == 0) {
dev_err(hba->dev, "%s: invalid gear = %d\n", __func__, gear);
- goto out_error;
+ return -EINVAL;
}
list_for_each_entry(clki, &hba->clk_list_head, list) {
@@ -436,7 +455,7 @@ static int ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear,
}
if (ufs_qcom_cap_qunipro(host))
- goto out;
+ return 0;
core_clk_period_in_ns = NSEC_PER_SEC / core_clk_rate;
core_clk_period_in_ns <<= OFFSET_CLK_NS_REG;
@@ -451,7 +470,7 @@ static int ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear,
"%s: index %d exceeds table size %zu\n",
__func__, gear,
ARRAY_SIZE(hs_fr_table_rA));
- goto out_error;
+ return -EINVAL;
}
tx_clk_cycles_per_us = hs_fr_table_rA[gear-1][1];
} else if (rate == PA_HS_MODE_B) {
@@ -460,13 +479,13 @@ static int ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear,
"%s: index %d exceeds table size %zu\n",
__func__, gear,
ARRAY_SIZE(hs_fr_table_rB));
- goto out_error;
+ return -EINVAL;
}
tx_clk_cycles_per_us = hs_fr_table_rB[gear-1][1];
} else {
dev_err(hba->dev, "%s: invalid rate = %d\n",
__func__, rate);
- goto out_error;
+ return -EINVAL;
}
break;
case SLOWAUTO_MODE:
@@ -476,14 +495,14 @@ static int ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear,
"%s: index %d exceeds table size %zu\n",
__func__, gear,
ARRAY_SIZE(pwm_fr_table));
- goto out_error;
+ return -EINVAL;
}
tx_clk_cycles_per_us = pwm_fr_table[gear-1][1];
break;
case UNCHANGED:
default:
dev_err(hba->dev, "%s: invalid mode = %d\n", __func__, hs);
- goto out_error;
+ return -EINVAL;
}
if (ufshcd_readl(hba, REG_UFS_TX_SYMBOL_CLK_NS_US) !=
@@ -498,21 +517,17 @@ static int ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear,
mb();
}
- if (update_link_startup_timer) {
+ if (update_link_startup_timer && host->hw_ver.major != 0x5) {
ufshcd_writel(hba, ((core_clk_rate / MSEC_PER_SEC) * 100),
- REG_UFS_PA_LINK_STARTUP_TIMER);
+ REG_UFS_CFG0);
/*
* make sure that this configuration is applied before
* we return
*/
mb();
}
- goto out;
-out_error:
- ret = -EINVAL;
-out:
- return ret;
+ return 0;
}
static int ufs_qcom_link_startup_notify(struct ufs_hba *hba,
@@ -527,8 +542,7 @@ static int ufs_qcom_link_startup_notify(struct ufs_hba *hba,
0, true)) {
dev_err(hba->dev, "%s: ufs_qcom_cfg_timers() failed\n",
__func__);
- err = -EINVAL;
- goto out;
+ return -EINVAL;
}
if (ufs_qcom_cap_qunipro(host))
@@ -554,7 +568,6 @@ static int ufs_qcom_link_startup_notify(struct ufs_hba *hba,
break;
}
-out:
return err;
}
@@ -691,8 +704,7 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
if (!dev_req_params) {
pr_err("%s: incoming dev_req_params is NULL\n", __func__);
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
switch (status) {
@@ -700,29 +712,21 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
ufshcd_init_pwr_dev_param(&ufs_qcom_cap);
ufs_qcom_cap.hs_rate = UFS_QCOM_LIMIT_HS_RATE;
- if (host->hw_ver.major == 0x1) {
- /*
- * HS-G3 operations may not reliably work on legacy QCOM
- * UFS host controller hardware even though capability
- * exchange during link startup phase may end up
- * negotiating maximum supported gear as G3.
- * Hence downgrade the maximum supported gear to HS-G2.
- */
- if (ufs_qcom_cap.hs_tx_gear > UFS_HS_G2)
- ufs_qcom_cap.hs_tx_gear = UFS_HS_G2;
- if (ufs_qcom_cap.hs_rx_gear > UFS_HS_G2)
- ufs_qcom_cap.hs_rx_gear = UFS_HS_G2;
- }
+ /* This driver only supports symmetic gear setting i.e., hs_tx_gear == hs_rx_gear */
+ ufs_qcom_cap.hs_tx_gear = ufs_qcom_cap.hs_rx_gear = ufs_qcom_get_hs_gear(hba);
ret = ufshcd_get_pwr_dev_param(&ufs_qcom_cap,
dev_max_params,
dev_req_params);
if (ret) {
- pr_err("%s: failed to determine capabilities\n",
+ dev_err(hba->dev, "%s: failed to determine capabilities\n",
__func__);
- goto out;
+ return ret;
}
+ /* Use the agreed gear */
+ host->hs_gear = dev_req_params->gear_tx;
+
/* enable the device ref clock before changing to HS mode */
if (!ufshcd_is_hs_mode(&hba->pwr_info) &&
ufshcd_is_hs_mode(dev_req_params))
@@ -761,7 +765,7 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
ret = -EINVAL;
break;
}
-out:
+
return ret;
}
@@ -773,14 +777,11 @@ static int ufs_qcom_quirk_host_pa_saveconfigtime(struct ufs_hba *hba)
err = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_VS_CONFIG_REG1),
&pa_vs_config_reg1);
if (err)
- goto out;
+ return err;
/* Allow extension of MSB bits of PA_SaveConfigTime attribute */
- err = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_VS_CONFIG_REG1),
+ return ufshcd_dme_set(hba, UIC_ARG_MIB(PA_VS_CONFIG_REG1),
(pa_vs_config_reg1 | (1 << 12)));
-
-out:
- return err;
}
static int ufs_qcom_apply_dev_quirks(struct ufs_hba *hba)
@@ -839,6 +840,9 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba)
| UFSHCD_QUIRK_DME_PEER_ACCESS_AUTO_MODE
| UFSHCD_QUIRK_BROKEN_PA_RXHSUNTERMCAP);
}
+
+ if (host->hw_ver.major > 0x3)
+ hba->quirks |= UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH;
}
static void ufs_qcom_set_caps(struct ufs_hba *hba)
@@ -906,8 +910,6 @@ ufs_qcom_reset_assert(struct reset_controller_dev *rcdev, unsigned long id)
{
struct ufs_qcom_host *host = rcdev_to_ufs_host(rcdev);
- /* Currently this code only knows about a single reset. */
- WARN_ON(id);
ufs_qcom_assert_reset(host->hba);
/* provide 1ms delay to let the reset pulse propagate. */
usleep_range(1000, 1100);
@@ -919,8 +921,6 @@ ufs_qcom_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id)
{
struct ufs_qcom_host *host = rcdev_to_ufs_host(rcdev);
- /* Currently this code only knows about a single reset. */
- WARN_ON(id);
ufs_qcom_deassert_reset(host->hba);
/*
@@ -957,9 +957,8 @@ static int ufs_qcom_init(struct ufs_hba *hba)
host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
if (!host) {
- err = -ENOMEM;
dev_err(dev, "%s: no memory for qcom ufs host\n", __func__);
- goto out;
+ return -ENOMEM;
}
/* Make a two way bind between the qcom host and the hba */
@@ -980,10 +979,8 @@ static int ufs_qcom_init(struct ufs_hba *hba)
host->rcdev.owner = dev->driver->owner;
host->rcdev.nr_resets = 1;
err = devm_reset_controller_register(dev, &host->rcdev);
- if (err) {
+ if (err)
dev_warn(dev, "Failed to register reset controller\n");
- err = 0;
- }
if (!has_acpi_companion(dev)) {
host->generic_phy = devm_phy_get(dev, "ufsphy");
@@ -1046,20 +1043,24 @@ static int ufs_qcom_init(struct ufs_hba *hba)
if (hba->dev->id < MAX_UFS_QCOM_HOSTS)
ufs_qcom_hosts[hba->dev->id] = host;
- host->dbg_print_en |= UFS_QCOM_DEFAULT_DBG_PRINT_EN;
ufs_qcom_get_default_testbus_cfg(host);
err = ufs_qcom_testbus_config(host);
- if (err) {
+ if (err)
+ /* Failure is non-fatal */
dev_warn(dev, "%s: failed to configure the testbus %d\n",
__func__, err);
- err = 0;
- }
- goto out;
+ /*
+ * Power up the PHY using the minimum supported gear (UFS_HS_G2).
+ * Switching to max gear will be performed during reinit if supported.
+ */
+ host->hs_gear = UFS_HS_G2;
+
+ return 0;
out_variant_clear:
ufshcd_set_variant(hba, NULL);
-out:
+
return err;
}
@@ -1085,7 +1086,7 @@ static int ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(struct ufs_hba *hba,
UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL),
&core_clk_ctrl_reg);
if (err)
- goto out;
+ return err;
core_clk_ctrl_reg &= ~DME_VS_CORE_CLK_CTRL_MAX_CORE_CLK_1US_CYCLES_MASK;
core_clk_ctrl_reg |= clk_cycles;
@@ -1093,11 +1094,9 @@ static int ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(struct ufs_hba *hba,
/* Clear CORE_CLK_DIV_EN */
core_clk_ctrl_reg &= ~DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT;
- err = ufshcd_dme_set(hba,
+ return ufshcd_dme_set(hba,
UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL),
core_clk_ctrl_reg);
-out:
- return err;
}
static int ufs_qcom_clk_scale_up_pre_change(struct ufs_hba *hba)
@@ -1180,7 +1179,7 @@ static int ufs_qcom_clk_scale_notify(struct ufs_hba *hba,
if (err || !dev_req_params) {
ufshcd_uic_hibern8_exit(hba);
- goto out;
+ return err;
}
ufs_qcom_cfg_timers(hba,
@@ -1191,81 +1190,14 @@ static int ufs_qcom_clk_scale_notify(struct ufs_hba *hba,
ufshcd_uic_hibern8_exit(hba);
}
-out:
- return err;
-}
-
-static void ufs_qcom_print_hw_debug_reg_all(struct ufs_hba *hba,
- void *priv, void (*print_fn)(struct ufs_hba *hba,
- int offset, int num_regs, const char *str, void *priv))
-{
- u32 reg;
- struct ufs_qcom_host *host;
-
- if (unlikely(!hba)) {
- pr_err("%s: hba is NULL\n", __func__);
- return;
- }
- if (unlikely(!print_fn)) {
- dev_err(hba->dev, "%s: print_fn is NULL\n", __func__);
- return;
- }
-
- host = ufshcd_get_variant(hba);
- if (!(host->dbg_print_en & UFS_QCOM_DBG_PRINT_REGS_EN))
- return;
-
- reg = ufs_qcom_get_debug_reg_offset(host, UFS_UFS_DBG_RD_REG_OCSC);
- print_fn(hba, reg, 44, "UFS_UFS_DBG_RD_REG_OCSC ", priv);
-
- reg = ufshcd_readl(hba, REG_UFS_CFG1);
- reg |= UTP_DBG_RAMS_EN;
- ufshcd_writel(hba, reg, REG_UFS_CFG1);
-
- reg = ufs_qcom_get_debug_reg_offset(host, UFS_UFS_DBG_RD_EDTL_RAM);
- print_fn(hba, reg, 32, "UFS_UFS_DBG_RD_EDTL_RAM ", priv);
-
- reg = ufs_qcom_get_debug_reg_offset(host, UFS_UFS_DBG_RD_DESC_RAM);
- print_fn(hba, reg, 128, "UFS_UFS_DBG_RD_DESC_RAM ", priv);
-
- reg = ufs_qcom_get_debug_reg_offset(host, UFS_UFS_DBG_RD_PRDT_RAM);
- print_fn(hba, reg, 64, "UFS_UFS_DBG_RD_PRDT_RAM ", priv);
-
- /* clear bit 17 - UTP_DBG_RAMS_EN */
- ufshcd_rmwl(hba, UTP_DBG_RAMS_EN, 0, REG_UFS_CFG1);
-
- reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_UAWM);
- print_fn(hba, reg, 4, "UFS_DBG_RD_REG_UAWM ", priv);
-
- reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_UARM);
- print_fn(hba, reg, 4, "UFS_DBG_RD_REG_UARM ", priv);
-
- reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_TXUC);
- print_fn(hba, reg, 48, "UFS_DBG_RD_REG_TXUC ", priv);
-
- reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_RXUC);
- print_fn(hba, reg, 27, "UFS_DBG_RD_REG_RXUC ", priv);
-
- reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_DFC);
- print_fn(hba, reg, 19, "UFS_DBG_RD_REG_DFC ", priv);
-
- reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_TRLUT);
- print_fn(hba, reg, 34, "UFS_DBG_RD_REG_TRLUT ", priv);
-
- reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_TMRLUT);
- print_fn(hba, reg, 9, "UFS_DBG_RD_REG_TMRLUT ", priv);
+ return 0;
}
static void ufs_qcom_enable_test_bus(struct ufs_qcom_host *host)
{
- if (host->dbg_print_en & UFS_QCOM_DBG_PRINT_TEST_BUS_EN) {
- ufshcd_rmwl(host->hba, UFS_REG_TEST_BUS_EN,
- UFS_REG_TEST_BUS_EN, REG_UFS_CFG1);
- ufshcd_rmwl(host->hba, TEST_BUS_EN, TEST_BUS_EN, REG_UFS_CFG1);
- } else {
- ufshcd_rmwl(host->hba, UFS_REG_TEST_BUS_EN, 0, REG_UFS_CFG1);
- ufshcd_rmwl(host->hba, TEST_BUS_EN, 0, REG_UFS_CFG1);
- }
+ ufshcd_rmwl(host->hba, UFS_REG_TEST_BUS_EN,
+ UFS_REG_TEST_BUS_EN, REG_UFS_CFG1);
+ ufshcd_rmwl(host->hba, TEST_BUS_EN, TEST_BUS_EN, REG_UFS_CFG1);
}
static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host)
@@ -1374,10 +1306,53 @@ int ufs_qcom_testbus_config(struct ufs_qcom_host *host)
static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba)
{
+ u32 reg;
+ struct ufs_qcom_host *host;
+
+ host = ufshcd_get_variant(hba);
+
ufshcd_dump_regs(hba, REG_UFS_SYS1CLK_1US, 16 * 4,
"HCI Vendor Specific Registers ");
- ufs_qcom_print_hw_debug_reg_all(hba, NULL, ufs_qcom_dump_regs_wrapper);
+ reg = ufs_qcom_get_debug_reg_offset(host, UFS_UFS_DBG_RD_REG_OCSC);
+ ufshcd_dump_regs(hba, reg, 44 * 4, "UFS_UFS_DBG_RD_REG_OCSC ");
+
+ reg = ufshcd_readl(hba, REG_UFS_CFG1);
+ reg |= UTP_DBG_RAMS_EN;
+ ufshcd_writel(hba, reg, REG_UFS_CFG1);
+
+ reg = ufs_qcom_get_debug_reg_offset(host, UFS_UFS_DBG_RD_EDTL_RAM);
+ ufshcd_dump_regs(hba, reg, 32 * 4, "UFS_UFS_DBG_RD_EDTL_RAM ");
+
+ reg = ufs_qcom_get_debug_reg_offset(host, UFS_UFS_DBG_RD_DESC_RAM);
+ ufshcd_dump_regs(hba, reg, 128 * 4, "UFS_UFS_DBG_RD_DESC_RAM ");
+
+ reg = ufs_qcom_get_debug_reg_offset(host, UFS_UFS_DBG_RD_PRDT_RAM);
+ ufshcd_dump_regs(hba, reg, 64 * 4, "UFS_UFS_DBG_RD_PRDT_RAM ");
+
+ /* clear bit 17 - UTP_DBG_RAMS_EN */
+ ufshcd_rmwl(hba, UTP_DBG_RAMS_EN, 0, REG_UFS_CFG1);
+
+ reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_UAWM);
+ ufshcd_dump_regs(hba, reg, 4 * 4, "UFS_DBG_RD_REG_UAWM ");
+
+ reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_UARM);
+ ufshcd_dump_regs(hba, reg, 4 * 4, "UFS_DBG_RD_REG_UARM ");
+
+ reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_TXUC);
+ ufshcd_dump_regs(hba, reg, 48 * 4, "UFS_DBG_RD_REG_TXUC ");
+
+ reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_RXUC);
+ ufshcd_dump_regs(hba, reg, 27 * 4, "UFS_DBG_RD_REG_RXUC ");
+
+ reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_DFC);
+ ufshcd_dump_regs(hba, reg, 19 * 4, "UFS_DBG_RD_REG_DFC ");
+
+ reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_TRLUT);
+ ufshcd_dump_regs(hba, reg, 34 * 4, "UFS_DBG_RD_REG_TRLUT ");
+
+ reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_TMRLUT);
+ ufshcd_dump_regs(hba, reg, 9 * 4, "UFS_DBG_RD_REG_TMRLUT ");
}
/**
@@ -1424,6 +1399,236 @@ static void ufs_qcom_config_scaling_param(struct ufs_hba *hba,
}
#endif
+static void ufs_qcom_reinit_notify(struct ufs_hba *hba)
+{
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+
+ phy_power_off(host->generic_phy);
+}
+
+/* Resources */
+static const struct ufshcd_res_info ufs_res_info[RES_MAX] = {
+ {.name = "ufs_mem",},
+ {.name = "mcq",},
+ /* Submission Queue DAO */
+ {.name = "mcq_sqd",},
+ /* Submission Queue Interrupt Status */
+ {.name = "mcq_sqis",},
+ /* Completion Queue DAO */
+ {.name = "mcq_cqd",},
+ /* Completion Queue Interrupt Status */
+ {.name = "mcq_cqis",},
+ /* MCQ vendor specific */
+ {.name = "mcq_vs",},
+};
+
+static int ufs_qcom_mcq_config_resource(struct ufs_hba *hba)
+{
+ struct platform_device *pdev = to_platform_device(hba->dev);
+ struct ufshcd_res_info *res;
+ struct resource *res_mem, *res_mcq;
+ int i, ret = 0;
+
+ memcpy(hba->res, ufs_res_info, sizeof(ufs_res_info));
+
+ for (i = 0; i < RES_MAX; i++) {
+ res = &hba->res[i];
+ res->resource = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM,
+ res->name);
+ if (!res->resource) {
+ dev_info(hba->dev, "Resource %s not provided\n", res->name);
+ if (i == RES_UFS)
+ return -ENOMEM;
+ continue;
+ } else if (i == RES_UFS) {
+ res_mem = res->resource;
+ res->base = hba->mmio_base;
+ continue;
+ }
+
+ res->base = devm_ioremap_resource(hba->dev, res->resource);
+ if (IS_ERR(res->base)) {
+ dev_err(hba->dev, "Failed to map res %s, err=%d\n",
+ res->name, (int)PTR_ERR(res->base));
+ res->base = NULL;
+ ret = PTR_ERR(res->base);
+ return ret;
+ }
+ }
+
+ /* MCQ resource provided in DT */
+ res = &hba->res[RES_MCQ];
+ /* Bail if MCQ resource is provided */
+ if (res->base)
+ goto out;
+
+ /* Explicitly allocate MCQ resource from ufs_mem */
+ res_mcq = devm_kzalloc(hba->dev, sizeof(*res_mcq), GFP_KERNEL);
+ if (!res_mcq)
+ return ret;
+
+ res_mcq->start = res_mem->start +
+ MCQ_SQATTR_OFFSET(hba->mcq_capabilities);
+ res_mcq->end = res_mcq->start + hba->nr_hw_queues * MCQ_QCFG_SIZE - 1;
+ res_mcq->flags = res_mem->flags;
+ res_mcq->name = "mcq";
+
+ ret = insert_resource(&iomem_resource, res_mcq);
+ if (ret) {
+ dev_err(hba->dev, "Failed to insert MCQ resource, err=%d\n",
+ ret);
+ goto insert_res_err;
+ }
+
+ res->base = devm_ioremap_resource(hba->dev, res_mcq);
+ if (IS_ERR(res->base)) {
+ dev_err(hba->dev, "MCQ registers mapping failed, err=%d\n",
+ (int)PTR_ERR(res->base));
+ ret = PTR_ERR(res->base);
+ goto ioremap_err;
+ }
+
+out:
+ hba->mcq_base = res->base;
+ return 0;
+ioremap_err:
+ res->base = NULL;
+ remove_resource(res_mcq);
+insert_res_err:
+ devm_kfree(hba->dev, res_mcq);
+ return ret;
+}
+
+static int ufs_qcom_op_runtime_config(struct ufs_hba *hba)
+{
+ struct ufshcd_res_info *mem_res, *sqdao_res;
+ struct ufshcd_mcq_opr_info_t *opr;
+ int i;
+
+ mem_res = &hba->res[RES_UFS];
+ sqdao_res = &hba->res[RES_MCQ_SQD];
+
+ if (!mem_res->base || !sqdao_res->base)
+ return -EINVAL;
+
+ for (i = 0; i < OPR_MAX; i++) {
+ opr = &hba->mcq_opr[i];
+ opr->offset = sqdao_res->resource->start -
+ mem_res->resource->start + 0x40 * i;
+ opr->stride = 0x100;
+ opr->base = sqdao_res->base + 0x40 * i;
+ }
+
+ return 0;
+}
+
+static int ufs_qcom_get_hba_mac(struct ufs_hba *hba)
+{
+ /* Qualcomm HC supports up to 64 */
+ return MAX_SUPP_MAC;
+}
+
+static int ufs_qcom_get_outstanding_cqs(struct ufs_hba *hba,
+ unsigned long *ocqs)
+{
+ struct ufshcd_res_info *mcq_vs_res = &hba->res[RES_MCQ_VS];
+
+ if (!mcq_vs_res->base)
+ return -EINVAL;
+
+ *ocqs = readl(mcq_vs_res->base + UFS_MEM_CQIS_VS);
+
+ return 0;
+}
+
+static void ufs_qcom_write_msi_msg(struct msi_desc *desc, struct msi_msg *msg)
+{
+ struct device *dev = msi_desc_to_dev(desc);
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+
+ ufshcd_mcq_config_esi(hba, msg);
+}
+
+static irqreturn_t ufs_qcom_mcq_esi_handler(int irq, void *__hba)
+{
+ struct ufs_hba *hba = __hba;
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+ u32 id = irq - host->esi_base;
+ struct ufs_hw_queue *hwq = &hba->uhq[id];
+
+ ufshcd_mcq_write_cqis(hba, 0x1, id);
+ ufshcd_mcq_poll_cqe_nolock(hba, hwq);
+
+ return IRQ_HANDLED;
+}
+
+static int ufs_qcom_config_esi(struct ufs_hba *hba)
+{
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+ struct msi_desc *desc;
+ struct msi_desc *failed_desc = NULL;
+ int nr_irqs, ret;
+
+ if (host->esi_enabled)
+ return 0;
+ else if (host->esi_base < 0)
+ return -EINVAL;
+
+ /*
+ * 1. We only handle CQs as of now.
+ * 2. Poll queues do not need ESI.
+ */
+ nr_irqs = hba->nr_hw_queues - hba->nr_queues[HCTX_TYPE_POLL];
+ ret = platform_msi_domain_alloc_irqs(hba->dev, nr_irqs,
+ ufs_qcom_write_msi_msg);
+ if (ret)
+ goto out;
+
+ msi_for_each_desc(desc, hba->dev, MSI_DESC_ALL) {
+ if (!desc->msi_index)
+ host->esi_base = desc->irq;
+
+ ret = devm_request_irq(hba->dev, desc->irq,
+ ufs_qcom_mcq_esi_handler,
+ IRQF_SHARED, "qcom-mcq-esi", hba);
+ if (ret) {
+ dev_err(hba->dev, "%s: Fail to request IRQ for %d, err = %d\n",
+ __func__, desc->irq, ret);
+ failed_desc = desc;
+ break;
+ }
+ }
+
+ if (ret) {
+ /* Rewind */
+ msi_for_each_desc(desc, hba->dev, MSI_DESC_ALL) {
+ if (desc == failed_desc)
+ break;
+ devm_free_irq(hba->dev, desc->irq, hba);
+ }
+ platform_msi_domain_free_irqs(hba->dev);
+ } else {
+ if (host->hw_ver.major == 6 && host->hw_ver.minor == 0 &&
+ host->hw_ver.step == 0) {
+ ufshcd_writel(hba,
+ ufshcd_readl(hba, REG_UFS_CFG3) | 0x1F000,
+ REG_UFS_CFG3);
+ }
+ ufshcd_mcq_enable_esi(hba);
+ }
+
+out:
+ if (ret) {
+ host->esi_base = -1;
+ dev_warn(hba->dev, "Failed to request Platform MSI %d\n", ret);
+ } else {
+ host->esi_enabled = true;
+ }
+
+ return ret;
+}
+
/*
* struct ufs_hba_qcom_vops - UFS QCOM specific variant operations
*
@@ -1447,6 +1652,12 @@ static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = {
.device_reset = ufs_qcom_device_reset,
.config_scaling_param = ufs_qcom_config_scaling_param,
.program_key = ufs_qcom_ice_program_key,
+ .reinit_notify = ufs_qcom_reinit_notify,
+ .mcq_config_resource = ufs_qcom_mcq_config_resource,
+ .get_hba_mac = ufs_qcom_get_hba_mac,
+ .op_runtime_config = ufs_qcom_op_runtime_config,
+ .get_outstanding_cqs = ufs_qcom_get_outstanding_cqs,
+ .config_esi = ufs_qcom_config_esi,
};
/**
@@ -1463,9 +1674,9 @@ static int ufs_qcom_probe(struct platform_device *pdev)
/* Perform generic probe */
err = ufshcd_pltfrm_init(pdev, &ufs_hba_qcom_vops);
if (err)
- dev_err(dev, "ufshcd_pltfrm_init() failed %d\n", err);
+ return dev_err_probe(dev, err, "ufshcd_pltfrm_init() failed\n");
- return err;
+ return 0;
}
/**
@@ -1480,6 +1691,7 @@ static int ufs_qcom_remove(struct platform_device *pdev)
pm_runtime_get_sync(&(pdev)->dev);
ufshcd_remove(hba);
+ platform_msi_domain_free_irqs(hba->dev);
return 0;
}
@@ -1498,10 +1710,16 @@ MODULE_DEVICE_TABLE(acpi, ufs_qcom_acpi_match);
#endif
static const struct dev_pm_ops ufs_qcom_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(ufshcd_system_suspend, ufshcd_system_resume)
SET_RUNTIME_PM_OPS(ufshcd_runtime_suspend, ufshcd_runtime_resume, NULL)
.prepare = ufshcd_suspend_prepare,
.complete = ufshcd_resume_complete,
+#ifdef CONFIG_PM_SLEEP
+ .suspend = ufshcd_system_suspend,
+ .resume = ufshcd_system_resume,
+ .freeze = ufshcd_system_freeze,
+ .restore = ufshcd_system_restore,
+ .thaw = ufshcd_system_thaw,
+#endif
};
static struct platform_driver ufs_qcom_pltform = {
diff --git a/drivers/ufs/host/ufs-qcom.h b/drivers/ufs/host/ufs-qcom.h
index 44466a395bb5..39e774254fb2 100644
--- a/drivers/ufs/host/ufs-qcom.h
+++ b/drivers/ufs/host/ufs-qcom.h
@@ -16,13 +16,11 @@
#define HBRN8_POLL_TOUT_MS 100
#define DEFAULT_CLK_RATE_HZ 1000000
#define BUS_VECTOR_NAME_LEN 32
+#define MAX_SUPP_MAC 64
-#define UFS_HW_VER_MAJOR_SHFT (28)
-#define UFS_HW_VER_MAJOR_MASK (0x000F << UFS_HW_VER_MAJOR_SHFT)
-#define UFS_HW_VER_MINOR_SHFT (16)
-#define UFS_HW_VER_MINOR_MASK (0x0FFF << UFS_HW_VER_MINOR_SHFT)
-#define UFS_HW_VER_STEP_SHFT (0)
-#define UFS_HW_VER_STEP_MASK (0xFFFF << UFS_HW_VER_STEP_SHFT)
+#define UFS_HW_VER_MAJOR_MASK GENMASK(31, 28)
+#define UFS_HW_VER_MINOR_MASK GENMASK(27, 16)
+#define UFS_HW_VER_STEP_MASK GENMASK(15, 0)
/* vendor specific pre-defined parameters */
#define SLOW 1
@@ -36,8 +34,10 @@ enum {
REG_UFS_TX_SYMBOL_CLK_NS_US = 0xC4,
REG_UFS_LOCAL_PORT_ID_REG = 0xC8,
REG_UFS_PA_ERR_CODE = 0xCC,
- REG_UFS_RETRY_TIMER_REG = 0xD0,
- REG_UFS_PA_LINK_STARTUP_TIMER = 0xD8,
+ /* On older UFS revisions, this register is called "RETRY_TIMER_REG" */
+ REG_UFS_PARAM0 = 0xD0,
+ /* On older UFS revisions, this register is called "REG_UFS_PA_LINK_STARTUP_TIMER" */
+ REG_UFS_CFG0 = 0xD8,
REG_UFS_CFG1 = 0xDC,
REG_UFS_CFG2 = 0xE0,
REG_UFS_HW_VERSION = 0xE4,
@@ -53,6 +53,8 @@ enum {
* added in HW Version 3.0.0
*/
UFS_AH8_CFG = 0xFC,
+
+ REG_UFS_CFG3 = 0x271C,
};
/* QCOM UFS host controller vendor specific debug registers */
@@ -72,28 +74,43 @@ enum {
UFS_UFS_DBG_RD_EDTL_RAM = 0x1900,
};
+enum {
+ UFS_MEM_CQIS_VS = 0x8,
+};
+
#define UFS_CNTLR_2_x_x_VEN_REGS_OFFSET(x) (0x000 + x)
#define UFS_CNTLR_3_x_x_VEN_REGS_OFFSET(x) (0x400 + x)
+/* bit definitions for REG_UFS_CFG0 register */
+#define QUNIPRO_G4_SEL BIT(5)
+
/* bit definitions for REG_UFS_CFG1 register */
-#define QUNIPRO_SEL 0x1
-#define UTP_DBG_RAMS_EN 0x20000
+#define QUNIPRO_SEL BIT(0)
+#define UFS_PHY_SOFT_RESET BIT(1)
+#define UTP_DBG_RAMS_EN BIT(17)
#define TEST_BUS_EN BIT(18)
#define TEST_BUS_SEL GENMASK(22, 19)
#define UFS_REG_TEST_BUS_EN BIT(30)
+#define UFS_PHY_RESET_ENABLE 1
+#define UFS_PHY_RESET_DISABLE 0
+
/* bit definitions for REG_UFS_CFG2 register */
-#define UAWM_HW_CGC_EN (1 << 0)
-#define UARM_HW_CGC_EN (1 << 1)
-#define TXUC_HW_CGC_EN (1 << 2)
-#define RXUC_HW_CGC_EN (1 << 3)
-#define DFC_HW_CGC_EN (1 << 4)
-#define TRLUT_HW_CGC_EN (1 << 5)
-#define TMRLUT_HW_CGC_EN (1 << 6)
-#define OCSC_HW_CGC_EN (1 << 7)
+#define UAWM_HW_CGC_EN BIT(0)
+#define UARM_HW_CGC_EN BIT(1)
+#define TXUC_HW_CGC_EN BIT(2)
+#define RXUC_HW_CGC_EN BIT(3)
+#define DFC_HW_CGC_EN BIT(4)
+#define TRLUT_HW_CGC_EN BIT(5)
+#define TMRLUT_HW_CGC_EN BIT(6)
+#define OCSC_HW_CGC_EN BIT(7)
+
+/* bit definitions for REG_UFS_PARAM0 */
+#define MAX_HS_GEAR_MASK GENMASK(6, 4)
+#define UFS_QCOM_MAX_GEAR(x) FIELD_GET(MAX_HS_GEAR_MASK, (x))
/* bit definition for UFS_UFS_TEST_BUS_CTRL_n */
-#define TEST_BUS_SUB_SEL_MASK 0x1F /* All XXX_SEL fields are 5 bits wide */
+#define TEST_BUS_SUB_SEL_MASK GENMASK(4, 0) /* All XXX_SEL fields are 5 bits wide */
#define REG_UFS_CFG2_CGC_EN_ALL (UAWM_HW_CGC_EN | UARM_HW_CGC_EN |\
TXUC_HW_CGC_EN | RXUC_HW_CGC_EN |\
@@ -101,26 +118,11 @@ enum {
TMRLUT_HW_CGC_EN | OCSC_HW_CGC_EN)
/* bit offset */
-enum {
- OFFSET_UFS_PHY_SOFT_RESET = 1,
- OFFSET_CLK_NS_REG = 10,
-};
+#define OFFSET_CLK_NS_REG 0xa
/* bit masks */
-enum {
- MASK_UFS_PHY_SOFT_RESET = 0x2,
- MASK_TX_SYMBOL_CLK_1US_REG = 0x3FF,
- MASK_CLK_NS_REG = 0xFFFC00,
-};
-
-/* QCOM UFS debug print bit mask */
-#define UFS_QCOM_DBG_PRINT_REGS_EN BIT(0)
-#define UFS_QCOM_DBG_PRINT_ICE_REGS_EN BIT(1)
-#define UFS_QCOM_DBG_PRINT_TEST_BUS_EN BIT(2)
-
-#define UFS_QCOM_DBG_PRINT_ALL \
- (UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_ICE_REGS_EN | \
- UFS_QCOM_DBG_PRINT_TEST_BUS_EN)
+#define MASK_TX_SYMBOL_CLK_1US_REG GENMASK(9, 0)
+#define MASK_CLK_NS_REG GENMASK(23, 10)
/* QUniPro Vendor specific attributes */
#define PA_VS_CONFIG_REG1 0x9000
@@ -135,15 +137,15 @@ ufs_qcom_get_controller_revision(struct ufs_hba *hba,
{
u32 ver = ufshcd_readl(hba, REG_UFS_HW_VERSION);
- *major = (ver & UFS_HW_VER_MAJOR_MASK) >> UFS_HW_VER_MAJOR_SHFT;
- *minor = (ver & UFS_HW_VER_MINOR_MASK) >> UFS_HW_VER_MINOR_SHFT;
- *step = (ver & UFS_HW_VER_STEP_MASK) >> UFS_HW_VER_STEP_SHFT;
+ *major = FIELD_GET(UFS_HW_VER_MAJOR_MASK, ver);
+ *minor = FIELD_GET(UFS_HW_VER_MINOR_MASK, ver);
+ *step = FIELD_GET(UFS_HW_VER_STEP_MASK, ver);
};
static inline void ufs_qcom_assert_reset(struct ufs_hba *hba)
{
- ufshcd_rmwl(hba, MASK_UFS_PHY_SOFT_RESET,
- 1 << OFFSET_UFS_PHY_SOFT_RESET, REG_UFS_CFG1);
+ ufshcd_rmwl(hba, UFS_PHY_SOFT_RESET, FIELD_PREP(UFS_PHY_SOFT_RESET, UFS_PHY_RESET_ENABLE),
+ REG_UFS_CFG1);
/*
* Make sure assertion of ufs phy reset is written to
@@ -154,8 +156,8 @@ static inline void ufs_qcom_assert_reset(struct ufs_hba *hba)
static inline void ufs_qcom_deassert_reset(struct ufs_hba *hba)
{
- ufshcd_rmwl(hba, MASK_UFS_PHY_SOFT_RESET,
- 0 << OFFSET_UFS_PHY_SOFT_RESET, REG_UFS_CFG1);
+ ufshcd_rmwl(hba, UFS_PHY_SOFT_RESET, FIELD_PREP(UFS_PHY_SOFT_RESET, UFS_PHY_RESET_DISABLE),
+ REG_UFS_CFG1);
/*
* Make sure de-assertion of ufs phy reset is written to
@@ -212,8 +214,6 @@ struct ufs_qcom_host {
u32 dev_ref_clk_en_mask;
- /* Bitmask for enabling debug prints */
- u32 dbg_print_en;
struct ufs_qcom_testbus testbus;
/* Reset control of HCI */
@@ -221,6 +221,11 @@ struct ufs_qcom_host {
struct reset_controller_dev rcdev;
struct gpio_desc *device_reset;
+
+ u32 hs_gear;
+
+ int esi_base;
+ bool esi_enabled;
};
static inline u32
diff --git a/drivers/ufs/host/ufs-sprd.c b/drivers/ufs/host/ufs-sprd.c
new file mode 100644
index 000000000000..051f3f40d92c
--- /dev/null
+++ b/drivers/ufs/host/ufs-sprd.c
@@ -0,0 +1,458 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * UNISOC UFS Host Controller driver
+ *
+ * Copyright (C) 2022 Unisoc, Inc.
+ * Author: Zhe Wang <zhe.wang1@unisoc.com>
+ */
+
+#include <linux/arm-smccc.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <linux/regulator/consumer.h>
+
+#include <ufs/ufshcd.h>
+#include "ufshcd-pltfrm.h"
+#include "ufs-sprd.h"
+
+static const struct of_device_id ufs_sprd_of_match[];
+
+static struct ufs_sprd_priv *ufs_sprd_get_priv_data(struct ufs_hba *hba)
+{
+ struct ufs_sprd_host *host = ufshcd_get_variant(hba);
+
+ WARN_ON(!host->priv);
+ return host->priv;
+}
+
+static void ufs_sprd_regmap_update(struct ufs_sprd_priv *priv, unsigned int index,
+ unsigned int reg, unsigned int bits, unsigned int val)
+{
+ regmap_update_bits(priv->sysci[index].regmap, reg, bits, val);
+}
+
+static void ufs_sprd_regmap_read(struct ufs_sprd_priv *priv, unsigned int index,
+ unsigned int reg, unsigned int *val)
+{
+ regmap_read(priv->sysci[index].regmap, reg, val);
+}
+
+static void ufs_sprd_get_unipro_ver(struct ufs_hba *hba)
+{
+ struct ufs_sprd_host *host = ufshcd_get_variant(hba);
+
+ if (ufshcd_dme_get(hba, UIC_ARG_MIB(PA_LOCALVERINFO), &host->unipro_ver))
+ host->unipro_ver = 0;
+}
+
+static void ufs_sprd_ctrl_uic_compl(struct ufs_hba *hba, bool enable)
+{
+ u32 set = ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
+
+ if (enable == true)
+ set |= UIC_COMMAND_COMPL;
+ else
+ set &= ~UIC_COMMAND_COMPL;
+ ufshcd_writel(hba, set, REG_INTERRUPT_ENABLE);
+}
+
+static int ufs_sprd_get_reset_ctrl(struct device *dev, struct ufs_sprd_rst *rci)
+{
+ rci->rc = devm_reset_control_get(dev, rci->name);
+ if (IS_ERR(rci->rc)) {
+ dev_err(dev, "failed to get reset ctrl:%s\n", rci->name);
+ return PTR_ERR(rci->rc);
+ }
+
+ return 0;
+}
+
+static int ufs_sprd_get_syscon_reg(struct device *dev, struct ufs_sprd_syscon *sysci)
+{
+ sysci->regmap = syscon_regmap_lookup_by_phandle(dev->of_node, sysci->name);
+ if (IS_ERR(sysci->regmap)) {
+ dev_err(dev, "failed to get ufs syscon:%s\n", sysci->name);
+ return PTR_ERR(sysci->regmap);
+ }
+
+ return 0;
+}
+
+static int ufs_sprd_get_vreg(struct device *dev, struct ufs_sprd_vreg *vregi)
+{
+ vregi->vreg = devm_regulator_get(dev, vregi->name);
+ if (IS_ERR(vregi->vreg)) {
+ dev_err(dev, "failed to get vreg:%s\n", vregi->name);
+ return PTR_ERR(vregi->vreg);
+ }
+
+ return 0;
+}
+
+static int ufs_sprd_parse_dt(struct device *dev, struct ufs_hba *hba, struct ufs_sprd_host *host)
+{
+ u32 i;
+ struct ufs_sprd_priv *priv = host->priv;
+ int ret = 0;
+
+ /* Parse UFS reset ctrl info */
+ for (i = 0; i < SPRD_UFS_RST_MAX; i++) {
+ if (!priv->rci[i].name)
+ continue;
+ ret = ufs_sprd_get_reset_ctrl(dev, &priv->rci[i]);
+ if (ret)
+ goto out;
+ }
+
+ /* Parse UFS syscon reg info */
+ for (i = 0; i < SPRD_UFS_SYSCON_MAX; i++) {
+ if (!priv->sysci[i].name)
+ continue;
+ ret = ufs_sprd_get_syscon_reg(dev, &priv->sysci[i]);
+ if (ret)
+ goto out;
+ }
+
+ /* Parse UFS vreg info */
+ for (i = 0; i < SPRD_UFS_VREG_MAX; i++) {
+ if (!priv->vregi[i].name)
+ continue;
+ ret = ufs_sprd_get_vreg(dev, &priv->vregi[i]);
+ if (ret)
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+static int ufs_sprd_common_init(struct ufs_hba *hba)
+{
+ struct device *dev = hba->dev;
+ struct ufs_sprd_host *host;
+ struct platform_device __maybe_unused *pdev = to_platform_device(dev);
+ const struct of_device_id *of_id;
+ int ret = 0;
+
+ host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
+ if (!host)
+ return -ENOMEM;
+
+ of_id = of_match_node(ufs_sprd_of_match, pdev->dev.of_node);
+ if (of_id->data != NULL)
+ host->priv = container_of(of_id->data, struct ufs_sprd_priv,
+ ufs_hba_sprd_vops);
+
+ host->hba = hba;
+ ufshcd_set_variant(hba, host);
+
+ hba->caps |= UFSHCD_CAP_CLK_GATING |
+ UFSHCD_CAP_CRYPTO |
+ UFSHCD_CAP_WB_EN;
+ hba->quirks |= UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS;
+
+ ret = ufs_sprd_parse_dt(dev, hba, host);
+
+ return ret;
+}
+
+static int sprd_ufs_pwr_change_notify(struct ufs_hba *hba,
+ enum ufs_notify_change_status status,
+ struct ufs_pa_layer_attr *dev_max_params,
+ struct ufs_pa_layer_attr *dev_req_params)
+{
+ struct ufs_sprd_host *host = ufshcd_get_variant(hba);
+
+ if (status == PRE_CHANGE) {
+ memcpy(dev_req_params, dev_max_params,
+ sizeof(struct ufs_pa_layer_attr));
+ if (host->unipro_ver >= UFS_UNIPRO_VER_1_8)
+ ufshcd_dme_configure_adapt(hba, dev_req_params->gear_tx,
+ PA_INITIAL_ADAPT);
+ }
+
+ return 0;
+}
+
+static int ufs_sprd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op,
+ enum ufs_notify_change_status status)
+{
+ unsigned long flags;
+
+ if (status == PRE_CHANGE) {
+ if (ufshcd_is_auto_hibern8_supported(hba)) {
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ ufshcd_writel(hba, 0, REG_AUTO_HIBERNATE_IDLE_TIMER);
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ }
+ }
+
+ return 0;
+}
+
+static void ufs_sprd_n6_host_reset(struct ufs_hba *hba)
+{
+ struct ufs_sprd_priv *priv = ufs_sprd_get_priv_data(hba);
+
+ dev_info(hba->dev, "ufs host reset!\n");
+
+ reset_control_assert(priv->rci[SPRD_UFSHCI_SOFT_RST].rc);
+ usleep_range(1000, 1100);
+ reset_control_deassert(priv->rci[SPRD_UFSHCI_SOFT_RST].rc);
+}
+
+static int ufs_sprd_n6_device_reset(struct ufs_hba *hba)
+{
+ struct ufs_sprd_priv *priv = ufs_sprd_get_priv_data(hba);
+
+ dev_info(hba->dev, "ufs device reset!\n");
+
+ reset_control_assert(priv->rci[SPRD_UFS_DEV_RST].rc);
+ usleep_range(1000, 1100);
+ reset_control_deassert(priv->rci[SPRD_UFS_DEV_RST].rc);
+
+ return 0;
+}
+
+static void ufs_sprd_n6_key_acc_enable(struct ufs_hba *hba)
+{
+ u32 val;
+ u32 retry = 10;
+ struct arm_smccc_res res;
+
+check_hce:
+ /* Key access only can be enabled under HCE enable */
+ val = ufshcd_readl(hba, REG_CONTROLLER_ENABLE);
+ if (!(val & CONTROLLER_ENABLE)) {
+ ufs_sprd_n6_host_reset(hba);
+ val |= CONTROLLER_ENABLE;
+ ufshcd_writel(hba, val, REG_CONTROLLER_ENABLE);
+ usleep_range(1000, 1100);
+ if (retry) {
+ retry--;
+ goto check_hce;
+ }
+ goto disable_crypto;
+ }
+
+ arm_smccc_smc(SPRD_SIP_SVC_STORAGE_UFS_CRYPTO_ENABLE,
+ 0, 0, 0, 0, 0, 0, 0, &res);
+ if (!res.a0)
+ return;
+
+disable_crypto:
+ dev_err(hba->dev, "key reg access enable fail, disable crypto\n");
+ hba->caps &= ~UFSHCD_CAP_CRYPTO;
+}
+
+static int ufs_sprd_n6_init(struct ufs_hba *hba)
+{
+ struct ufs_sprd_priv *priv;
+ int ret = 0;
+
+ ret = ufs_sprd_common_init(hba);
+ if (ret != 0)
+ return ret;
+
+ priv = ufs_sprd_get_priv_data(hba);
+
+ ret = regulator_enable(priv->vregi[SPRD_UFS_VDD_MPHY].vreg);
+ if (ret)
+ return -ENODEV;
+
+ if (hba->caps & UFSHCD_CAP_CRYPTO)
+ ufs_sprd_n6_key_acc_enable(hba);
+
+ return 0;
+}
+
+static int ufs_sprd_n6_phy_init(struct ufs_hba *hba)
+{
+ int ret = 0;
+ uint32_t val = 0;
+ uint32_t retry = 10;
+ uint32_t offset;
+ struct ufs_sprd_priv *priv = ufs_sprd_get_priv_data(hba);
+
+ ufshcd_dme_set(hba, UIC_ARG_MIB(CBREFCLKCTRL2), 0x90);
+ ufshcd_dme_set(hba, UIC_ARG_MIB(CBCRCTRL), 0x01);
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(RXSQCONTROL,
+ UIC_ARG_MPHY_RX_GEN_SEL_INDEX(0)), 0x01);
+ ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(RXSQCONTROL,
+ UIC_ARG_MPHY_RX_GEN_SEL_INDEX(1)), 0x01);
+ ufshcd_dme_set(hba, UIC_ARG_MIB(VS_MPHYCFGUPDT), 0x01);
+ ufshcd_dme_set(hba, UIC_ARG_MIB(CBRATESEL), 0x01);
+
+ do {
+ /* phy_sram_init_done */
+ ufs_sprd_regmap_read(priv, SPRD_UFS_ANLG, 0xc, &val);
+ if ((val & 0x1) == 0x1) {
+ for (offset = 0x40; offset < 0x42; offset++) {
+ /* Lane afe calibration */
+ ufshcd_dme_set(hba, UIC_ARG_MIB(CBCREGADDRLSB), 0x1c);
+ ufshcd_dme_set(hba, UIC_ARG_MIB(CBCREGADDRMSB), offset);
+ ufshcd_dme_set(hba, UIC_ARG_MIB(CBCREGWRLSB), 0x04);
+ ufshcd_dme_set(hba, UIC_ARG_MIB(CBCREGWRMSB), 0x00);
+ ufshcd_dme_set(hba, UIC_ARG_MIB(CBCREGRDWRSEL), 0x01);
+ ufshcd_dme_set(hba, UIC_ARG_MIB(VS_MPHYCFGUPDT), 0x01);
+ }
+
+ goto update_phy;
+ }
+ udelay(1000);
+ retry--;
+ } while (retry > 0);
+
+ ret = -ETIMEDOUT;
+ goto out;
+
+update_phy:
+ /* phy_sram_ext_ld_done */
+ ufs_sprd_regmap_update(priv, SPRD_UFS_ANLG, 0xc, 0x2, 0);
+ ufshcd_dme_set(hba, UIC_ARG_MIB(VS_MPHYCFGUPDT), 0x01);
+ ufshcd_dme_set(hba, UIC_ARG_MIB(VS_MPHYDISABLE), 0x0);
+out:
+ return ret;
+}
+
+
+static int sprd_ufs_n6_hce_enable_notify(struct ufs_hba *hba,
+ enum ufs_notify_change_status status)
+{
+ int err = 0;
+ struct ufs_sprd_priv *priv = ufs_sprd_get_priv_data(hba);
+
+ if (status == PRE_CHANGE) {
+ /* phy_sram_ext_ld_done */
+ ufs_sprd_regmap_update(priv, SPRD_UFS_ANLG, 0xc, 0x2, 0x2);
+ /* phy_sram_bypass */
+ ufs_sprd_regmap_update(priv, SPRD_UFS_ANLG, 0xc, 0x4, 0x4);
+
+ ufs_sprd_n6_host_reset(hba);
+
+ if (hba->caps & UFSHCD_CAP_CRYPTO)
+ ufs_sprd_n6_key_acc_enable(hba);
+ }
+
+ if (status == POST_CHANGE) {
+ err = ufs_sprd_n6_phy_init(hba);
+ if (err) {
+ dev_err(hba->dev, "Phy setup failed (%d)\n", err);
+ goto out;
+ }
+
+ ufs_sprd_get_unipro_ver(hba);
+ }
+out:
+ return err;
+}
+
+static void sprd_ufs_n6_h8_notify(struct ufs_hba *hba,
+ enum uic_cmd_dme cmd,
+ enum ufs_notify_change_status status)
+{
+ struct ufs_sprd_priv *priv = ufs_sprd_get_priv_data(hba);
+
+ if (status == PRE_CHANGE) {
+ if (cmd == UIC_CMD_DME_HIBER_ENTER)
+ /*
+ * Disable UIC COMPL INTR to prevent access to UFSHCI after
+ * checking HCS.UPMCRS
+ */
+ ufs_sprd_ctrl_uic_compl(hba, false);
+
+ if (cmd == UIC_CMD_DME_HIBER_EXIT) {
+ ufs_sprd_regmap_update(priv, SPRD_UFS_AON_APB, APB_UFSDEV_REG,
+ APB_UFSDEV_REFCLK_EN, APB_UFSDEV_REFCLK_EN);
+ ufs_sprd_regmap_update(priv, SPRD_UFS_AON_APB, APB_USB31PLL_CTRL,
+ APB_USB31PLLV_REF2MPHY, APB_USB31PLLV_REF2MPHY);
+ }
+ }
+
+ if (status == POST_CHANGE) {
+ if (cmd == UIC_CMD_DME_HIBER_EXIT)
+ ufs_sprd_ctrl_uic_compl(hba, true);
+
+ if (cmd == UIC_CMD_DME_HIBER_ENTER) {
+ ufs_sprd_regmap_update(priv, SPRD_UFS_AON_APB, APB_UFSDEV_REG,
+ APB_UFSDEV_REFCLK_EN, 0);
+ ufs_sprd_regmap_update(priv, SPRD_UFS_AON_APB, APB_USB31PLL_CTRL,
+ APB_USB31PLLV_REF2MPHY, 0);
+ }
+ }
+}
+
+static struct ufs_sprd_priv n6_ufs = {
+ .rci[SPRD_UFSHCI_SOFT_RST] = { .name = "controller", },
+ .rci[SPRD_UFS_DEV_RST] = { .name = "device", },
+
+ .sysci[SPRD_UFS_ANLG] = { .name = "sprd,ufs-anlg-syscon", },
+ .sysci[SPRD_UFS_AON_APB] = { .name = "sprd,aon-apb-syscon", },
+
+ .vregi[SPRD_UFS_VDD_MPHY] = { .name = "vdd-mphy", },
+
+ .ufs_hba_sprd_vops = {
+ .name = "sprd,ums9620-ufs",
+ .init = ufs_sprd_n6_init,
+ .hce_enable_notify = sprd_ufs_n6_hce_enable_notify,
+ .pwr_change_notify = sprd_ufs_pwr_change_notify,
+ .hibern8_notify = sprd_ufs_n6_h8_notify,
+ .device_reset = ufs_sprd_n6_device_reset,
+ .suspend = ufs_sprd_suspend,
+ },
+};
+
+static const struct of_device_id __maybe_unused ufs_sprd_of_match[] = {
+ { .compatible = "sprd,ums9620-ufs", .data = &n6_ufs.ufs_hba_sprd_vops},
+ {},
+};
+MODULE_DEVICE_TABLE(of, ufs_sprd_of_match);
+
+static int ufs_sprd_probe(struct platform_device *pdev)
+{
+ int err;
+ struct device *dev = &pdev->dev;
+ const struct of_device_id *of_id;
+
+ of_id = of_match_node(ufs_sprd_of_match, dev->of_node);
+ err = ufshcd_pltfrm_init(pdev, of_id->data);
+ if (err)
+ dev_err(dev, "ufshcd_pltfrm_init() failed %d\n", err);
+
+ return err;
+}
+
+static int ufs_sprd_remove(struct platform_device *pdev)
+{
+ struct ufs_hba *hba = platform_get_drvdata(pdev);
+
+ pm_runtime_get_sync(&(pdev)->dev);
+ ufshcd_remove(hba);
+ return 0;
+}
+
+static const struct dev_pm_ops ufs_sprd_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(ufshcd_system_suspend, ufshcd_system_resume)
+ SET_RUNTIME_PM_OPS(ufshcd_runtime_suspend, ufshcd_runtime_resume, NULL)
+ .prepare = ufshcd_suspend_prepare,
+ .complete = ufshcd_resume_complete,
+};
+
+static struct platform_driver ufs_sprd_pltform = {
+ .probe = ufs_sprd_probe,
+ .remove = ufs_sprd_remove,
+ .shutdown = ufshcd_pltfrm_shutdown,
+ .driver = {
+ .name = "ufshcd-sprd",
+ .pm = &ufs_sprd_pm_ops,
+ .of_match_table = of_match_ptr(ufs_sprd_of_match),
+ },
+};
+module_platform_driver(ufs_sprd_pltform);
+
+MODULE_AUTHOR("Zhe Wang <zhe.wang1@unisoc.com>");
+MODULE_DESCRIPTION("Unisoc UFS Host Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/ufs/host/ufs-sprd.h b/drivers/ufs/host/ufs-sprd.h
new file mode 100644
index 000000000000..26ad5c3af4c1
--- /dev/null
+++ b/drivers/ufs/host/ufs-sprd.h
@@ -0,0 +1,85 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * UNISOC UFS Host Controller driver
+ *
+ * Copyright (C) 2022 Unisoc, Inc.
+ * Author: Zhe Wang <zhe.wang1@unisoc.com>
+ */
+
+#ifndef _UFS_SPRD_H_
+#define _UFS_SPRD_H_
+
+/* Vendor specific attributes */
+#define RXSQCONTROL 0x8009
+#define CBRATESEL 0x8114
+#define CBCREGADDRLSB 0x8116
+#define CBCREGADDRMSB 0x8117
+#define CBCREGWRLSB 0x8118
+#define CBCREGWRMSB 0x8119
+#define CBCREGRDWRSEL 0x811C
+#define CBCRCTRL 0x811F
+#define CBREFCLKCTRL2 0x8132
+#define VS_MPHYDISABLE 0xD0C1
+
+#define APB_UFSDEV_REG 0xCE8
+#define APB_UFSDEV_REFCLK_EN 0x2
+#define APB_USB31PLL_CTRL 0xCFC
+#define APB_USB31PLLV_REF2MPHY 0x1
+
+#define SPRD_SIP_SVC_STORAGE_UFS_CRYPTO_ENABLE \
+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
+ ARM_SMCCC_SMC_32, \
+ ARM_SMCCC_OWNER_SIP, \
+ 0x0301)
+
+enum SPRD_UFS_RST_INDEX {
+ SPRD_UFSHCI_SOFT_RST,
+ SPRD_UFS_DEV_RST,
+
+ SPRD_UFS_RST_MAX
+};
+
+enum SPRD_UFS_SYSCON_INDEX {
+ SPRD_UFS_ANLG,
+ SPRD_UFS_AON_APB,
+
+ SPRD_UFS_SYSCON_MAX
+};
+
+enum SPRD_UFS_VREG_INDEX {
+ SPRD_UFS_VDD_MPHY,
+
+ SPRD_UFS_VREG_MAX
+};
+
+struct ufs_sprd_rst {
+ const char *name;
+ struct reset_control *rc;
+};
+
+struct ufs_sprd_syscon {
+ const char *name;
+ struct regmap *regmap;
+};
+
+struct ufs_sprd_vreg {
+ const char *name;
+ struct regulator *vreg;
+};
+
+struct ufs_sprd_priv {
+ struct ufs_sprd_rst rci[SPRD_UFS_RST_MAX];
+ struct ufs_sprd_syscon sysci[SPRD_UFS_SYSCON_MAX];
+ struct ufs_sprd_vreg vregi[SPRD_UFS_VREG_MAX];
+ const struct ufs_hba_variant_ops ufs_hba_sprd_vops;
+};
+
+struct ufs_sprd_host {
+ struct ufs_hba *hba;
+ struct ufs_sprd_priv *priv;
+ void __iomem *ufs_dbg_mmio;
+
+ enum ufs_unipro_ver unipro_ver;
+};
+
+#endif /* _UFS_SPRD_H_ */
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
index 43afbb7c5ab9..62082d64ece0 100644
--- a/drivers/uio/uio.c
+++ b/drivers/uio/uio.c
@@ -713,7 +713,7 @@ static const struct vm_operations_struct uio_logical_vm_ops = {
static int uio_mmap_logical(struct vm_area_struct *vma)
{
- vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
+ vm_flags_set(vma, VM_DONTEXPAND | VM_DONTDUMP);
vma->vm_ops = &uio_logical_vm_ops;
return 0;
}
diff --git a/drivers/usb/cdns3/cdnsp-gadget.c b/drivers/usb/cdns3/cdnsp-gadget.c
index f9aa50ff14d4..fff9ec9c391f 100644
--- a/drivers/usb/cdns3/cdnsp-gadget.c
+++ b/drivers/usb/cdns3/cdnsp-gadget.c
@@ -378,7 +378,7 @@ int cdnsp_ep_enqueue(struct cdnsp_ep *pep, struct cdnsp_request *preq)
ret = cdnsp_queue_bulk_tx(pdev, preq);
break;
case USB_ENDPOINT_XFER_ISOC:
- ret = cdnsp_queue_isoc_tx_prepare(pdev, preq);
+ ret = cdnsp_queue_isoc_tx(pdev, preq);
}
if (ret)
diff --git a/drivers/usb/cdns3/cdnsp-gadget.h b/drivers/usb/cdns3/cdnsp-gadget.h
index f740fa6089d8..e1b5801fdddf 100644
--- a/drivers/usb/cdns3/cdnsp-gadget.h
+++ b/drivers/usb/cdns3/cdnsp-gadget.h
@@ -1532,8 +1532,8 @@ void cdnsp_queue_stop_endpoint(struct cdnsp_device *pdev,
unsigned int ep_index);
int cdnsp_queue_ctrl_tx(struct cdnsp_device *pdev, struct cdnsp_request *preq);
int cdnsp_queue_bulk_tx(struct cdnsp_device *pdev, struct cdnsp_request *preq);
-int cdnsp_queue_isoc_tx_prepare(struct cdnsp_device *pdev,
- struct cdnsp_request *preq);
+int cdnsp_queue_isoc_tx(struct cdnsp_device *pdev,
+ struct cdnsp_request *preq);
void cdnsp_queue_configure_endpoint(struct cdnsp_device *pdev,
dma_addr_t in_ctx_ptr);
void cdnsp_queue_reset_ep(struct cdnsp_device *pdev, unsigned int ep_index);
diff --git a/drivers/usb/cdns3/cdnsp-ring.c b/drivers/usb/cdns3/cdnsp-ring.c
index b23e543b3a3d..07f6068342d4 100644
--- a/drivers/usb/cdns3/cdnsp-ring.c
+++ b/drivers/usb/cdns3/cdnsp-ring.c
@@ -1333,6 +1333,20 @@ static int cdnsp_handle_tx_event(struct cdnsp_device *pdev,
ep_ring->dequeue, td->last_trb,
ep_trb_dma);
+ desc = td->preq->pep->endpoint.desc;
+
+ if (ep_seg) {
+ ep_trb = &ep_seg->trbs[(ep_trb_dma - ep_seg->dma)
+ / sizeof(*ep_trb)];
+
+ trace_cdnsp_handle_transfer(ep_ring,
+ (struct cdnsp_generic_trb *)ep_trb);
+
+ if (pep->skip && usb_endpoint_xfer_isoc(desc) &&
+ td->last_trb != ep_trb)
+ return -EAGAIN;
+ }
+
/*
* Skip the Force Stopped Event. The event_trb(ep_trb_dma)
* of FSE is not in the current TD pointed by ep_ring->dequeue
@@ -1347,7 +1361,6 @@ static int cdnsp_handle_tx_event(struct cdnsp_device *pdev,
goto cleanup;
}
- desc = td->preq->pep->endpoint.desc;
if (!ep_seg) {
if (!pep->skip || !usb_endpoint_xfer_isoc(desc)) {
/* Something is busted, give up! */
@@ -1374,12 +1387,6 @@ static int cdnsp_handle_tx_event(struct cdnsp_device *pdev,
goto cleanup;
}
- ep_trb = &ep_seg->trbs[(ep_trb_dma - ep_seg->dma)
- / sizeof(*ep_trb)];
-
- trace_cdnsp_handle_transfer(ep_ring,
- (struct cdnsp_generic_trb *)ep_trb);
-
if (cdnsp_trb_is_noop(ep_trb))
goto cleanup;
@@ -1726,11 +1733,6 @@ static unsigned int count_sg_trbs_needed(struct cdnsp_request *preq)
return num_trbs;
}
-static unsigned int count_isoc_trbs_needed(struct cdnsp_request *preq)
-{
- return cdnsp_count_trbs(preq->request.dma, preq->request.length);
-}
-
static void cdnsp_check_trb_math(struct cdnsp_request *preq, int running_total)
{
if (running_total != preq->request.length)
@@ -2192,28 +2194,48 @@ static unsigned int
}
/* Queue function isoc transfer */
-static int cdnsp_queue_isoc_tx(struct cdnsp_device *pdev,
- struct cdnsp_request *preq)
+int cdnsp_queue_isoc_tx(struct cdnsp_device *pdev,
+ struct cdnsp_request *preq)
{
- int trb_buff_len, td_len, td_remain_len, ret;
+ unsigned int trb_buff_len, td_len, td_remain_len, block_len;
unsigned int burst_count, last_burst_pkt;
unsigned int total_pkt_count, max_pkt;
struct cdnsp_generic_trb *start_trb;
+ struct scatterlist *sg = NULL;
bool more_trbs_coming = true;
struct cdnsp_ring *ep_ring;
+ unsigned int num_sgs = 0;
int running_total = 0;
u32 field, length_field;
+ u64 addr, send_addr;
int start_cycle;
int trbs_per_td;
- u64 addr;
- int i;
+ int i, sent_len, ret;
ep_ring = preq->pep->ring;
+
+ td_len = preq->request.length;
+
+ if (preq->request.num_sgs) {
+ num_sgs = preq->request.num_sgs;
+ sg = preq->request.sg;
+ addr = (u64)sg_dma_address(sg);
+ block_len = sg_dma_len(sg);
+ trbs_per_td = count_sg_trbs_needed(preq);
+ } else {
+ addr = (u64)preq->request.dma;
+ block_len = td_len;
+ trbs_per_td = count_trbs_needed(preq);
+ }
+
+ ret = cdnsp_prepare_transfer(pdev, preq, trbs_per_td);
+ if (ret)
+ return ret;
+
start_trb = &ep_ring->enqueue->generic;
start_cycle = ep_ring->cycle_state;
- td_len = preq->request.length;
- addr = (u64)preq->request.dma;
td_remain_len = td_len;
+ send_addr = addr;
max_pkt = usb_endpoint_maxp(preq->pep->endpoint.desc);
total_pkt_count = DIV_ROUND_UP(td_len, max_pkt);
@@ -2225,11 +2247,6 @@ static int cdnsp_queue_isoc_tx(struct cdnsp_device *pdev,
burst_count = cdnsp_get_burst_count(pdev, preq, total_pkt_count);
last_burst_pkt = cdnsp_get_last_burst_packet_count(pdev, preq,
total_pkt_count);
- trbs_per_td = count_isoc_trbs_needed(preq);
-
- ret = cdnsp_prepare_transfer(pdev, preq, trbs_per_td);
- if (ret)
- goto cleanup;
/*
* Set isoc specific data for the first TRB in a TD.
@@ -2248,6 +2265,7 @@ static int cdnsp_queue_isoc_tx(struct cdnsp_device *pdev,
/* Calculate TRB length. */
trb_buff_len = TRB_BUFF_LEN_UP_TO_BOUNDARY(addr);
+ trb_buff_len = min(trb_buff_len, block_len);
if (trb_buff_len > td_remain_len)
trb_buff_len = td_remain_len;
@@ -2256,7 +2274,8 @@ static int cdnsp_queue_isoc_tx(struct cdnsp_device *pdev,
trb_buff_len, td_len, preq,
more_trbs_coming, 0);
- length_field = TRB_LEN(trb_buff_len) | TRB_INTR_TARGET(0);
+ length_field = TRB_LEN(trb_buff_len) | TRB_TD_SIZE(remainder) |
+ TRB_INTR_TARGET(0);
/* Only first TRB is isoc, overwrite otherwise. */
if (i) {
@@ -2281,12 +2300,27 @@ static int cdnsp_queue_isoc_tx(struct cdnsp_device *pdev,
}
cdnsp_queue_trb(pdev, ep_ring, more_trbs_coming,
- lower_32_bits(addr), upper_32_bits(addr),
+ lower_32_bits(send_addr), upper_32_bits(send_addr),
length_field, field);
running_total += trb_buff_len;
addr += trb_buff_len;
td_remain_len -= trb_buff_len;
+
+ sent_len = trb_buff_len;
+ while (sg && sent_len >= block_len) {
+ /* New sg entry */
+ --num_sgs;
+ sent_len -= block_len;
+ if (num_sgs != 0) {
+ sg = sg_next(sg);
+ block_len = sg_dma_len(sg);
+ addr = (u64)sg_dma_address(sg);
+ addr += sent_len;
+ }
+ }
+ block_len -= sent_len;
+ send_addr = addr;
}
/* Check TD length */
@@ -2324,30 +2358,6 @@ cleanup:
return ret;
}
-int cdnsp_queue_isoc_tx_prepare(struct cdnsp_device *pdev,
- struct cdnsp_request *preq)
-{
- struct cdnsp_ring *ep_ring;
- u32 ep_state;
- int num_trbs;
- int ret;
-
- ep_ring = preq->pep->ring;
- ep_state = GET_EP_CTX_STATE(preq->pep->out_ctx);
- num_trbs = count_isoc_trbs_needed(preq);
-
- /*
- * Check the ring to guarantee there is enough room for the whole
- * request. Do not insert any td of the USB Request to the ring if the
- * check failed.
- */
- ret = cdnsp_prepare_ring(pdev, ep_ring, ep_state, num_trbs, GFP_ATOMIC);
- if (ret)
- return ret;
-
- return cdnsp_queue_isoc_tx(pdev, preq);
-}
-
/**** Command Ring Operations ****/
/*
* Generic function for queuing a command TRB on the command ring.
diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c
index 0dc482542d85..2eeccf4ec9d6 100644
--- a/drivers/usb/chipidea/ci_hdrc_imx.c
+++ b/drivers/usb/chipidea/ci_hdrc_imx.c
@@ -413,15 +413,19 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
data->phy = devm_usb_get_phy_by_phandle(dev, "fsl,usbphy", 0);
if (IS_ERR(data->phy)) {
ret = PTR_ERR(data->phy);
- if (ret != -ENODEV)
+ if (ret != -ENODEV) {
+ dev_err_probe(dev, ret, "Failed to parse fsl,usbphy\n");
goto err_clk;
+ }
data->phy = devm_usb_get_phy_by_phandle(dev, "phys", 0);
if (IS_ERR(data->phy)) {
ret = PTR_ERR(data->phy);
- if (ret == -ENODEV)
+ if (ret == -ENODEV) {
data->phy = NULL;
- else
+ } else {
+ dev_err_probe(dev, ret, "Failed to parse phys\n");
goto err_clk;
+ }
}
}
diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c
index faf6b078b6c4..bbc610e5bd69 100644
--- a/drivers/usb/chipidea/debug.c
+++ b/drivers/usb/chipidea/debug.c
@@ -364,5 +364,5 @@ void dbg_create_files(struct ci_hdrc *ci)
*/
void dbg_remove_files(struct ci_hdrc *ci)
{
- debugfs_remove(debugfs_lookup(dev_name(ci->dev), usb_debug_root));
+ debugfs_lookup_and_remove(dev_name(ci->dev), usb_debug_root);
}
diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c
index acdb13316cd0..c57c1a71a513 100644
--- a/drivers/usb/chipidea/usbmisc_imx.c
+++ b/drivers/usb/chipidea/usbmisc_imx.c
@@ -1263,14 +1263,8 @@ static int usbmisc_imx_probe(struct platform_device *pdev)
return 0;
}
-static int usbmisc_imx_remove(struct platform_device *pdev)
-{
- return 0;
-}
-
static struct platform_driver usbmisc_imx_driver = {
.probe = usbmisc_imx_probe,
- .remove = usbmisc_imx_remove,
.driver = {
.name = "usbmisc_imx",
.of_match_table = usbmisc_imx_dt_ids,
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 36bf051b345b..11da5fb284d0 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -651,13 +651,13 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
return tty_port_open(&acm->port, tty, filp);
}
-static void acm_port_dtr_rts(struct tty_port *port, int raise)
+static void acm_port_dtr_rts(struct tty_port *port, bool active)
{
struct acm *acm = container_of(port, struct acm, port);
int val;
int res;
- if (raise)
+ if (active)
val = USB_CDC_CTRL_DTR | USB_CDC_CTRL_RTS;
else
val = 0;
diff --git a/drivers/usb/common/ulpi.c b/drivers/usb/common/ulpi.c
index d7c8461976ce..a98b2108376a 100644
--- a/drivers/usb/common/ulpi.c
+++ b/drivers/usb/common/ulpi.c
@@ -55,9 +55,9 @@ static int ulpi_match(struct device *dev, struct device_driver *driver)
return 0;
}
-static int ulpi_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int ulpi_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct ulpi *ulpi = to_ulpi_dev(dev);
+ const struct ulpi *ulpi = to_ulpi_dev(dev);
int ret;
ret = of_device_uevent_modalias(dev, env);
@@ -271,7 +271,7 @@ static int ulpi_regs_show(struct seq_file *seq, void *data)
}
DEFINE_SHOW_ATTRIBUTE(ulpi_regs);
-#define ULPI_ROOT debugfs_lookup(KBUILD_MODNAME, NULL)
+static struct dentry *ulpi_root;
static int ulpi_register(struct device *dev, struct ulpi *ulpi)
{
@@ -301,7 +301,7 @@ static int ulpi_register(struct device *dev, struct ulpi *ulpi)
return ret;
}
- root = debugfs_create_dir(dev_name(dev), ULPI_ROOT);
+ root = debugfs_create_dir(dev_name(dev), ulpi_root);
debugfs_create_file("regs", 0444, root, ulpi, &ulpi_regs_fops);
dev_dbg(&ulpi->dev, "registered ULPI PHY: vendor %04x, product %04x\n",
@@ -349,8 +349,7 @@ EXPORT_SYMBOL_GPL(ulpi_register_interface);
*/
void ulpi_unregister_interface(struct ulpi *ulpi)
{
- debugfs_remove_recursive(debugfs_lookup(dev_name(&ulpi->dev),
- ULPI_ROOT));
+ debugfs_lookup_and_remove(dev_name(&ulpi->dev), ulpi_root);
device_unregister(&ulpi->dev);
}
EXPORT_SYMBOL_GPL(ulpi_unregister_interface);
@@ -360,12 +359,11 @@ EXPORT_SYMBOL_GPL(ulpi_unregister_interface);
static int __init ulpi_init(void)
{
int ret;
- struct dentry *root;
- root = debugfs_create_dir(KBUILD_MODNAME, NULL);
+ ulpi_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
ret = bus_register(&ulpi_bus);
if (ret)
- debugfs_remove(root);
+ debugfs_remove(ulpi_root);
return ret;
}
subsys_initcall(ulpi_init);
@@ -373,7 +371,7 @@ subsys_initcall(ulpi_init);
static void __exit ulpi_exit(void)
{
bus_unregister(&ulpi_bus);
- debugfs_remove_recursive(ULPI_ROOT);
+ debugfs_remove(ulpi_root);
}
module_exit(ulpi_exit);
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 837f3e57f580..e501a03d6c70 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -279,8 +279,7 @@ static int usbdev_mmap(struct file *file, struct vm_area_struct *vma)
}
}
- vma->vm_flags |= VM_IO;
- vma->vm_flags |= (VM_DONTEXPAND | VM_DONTDUMP);
+ vm_flags_set(vma, VM_IO | VM_DONTEXPAND | VM_DONTDUMP);
vma->vm_ops = &usbdev_vm_ops;
vma->vm_private_data = usbm;
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 7e7e119c253f..a0e076c6f3a4 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -899,14 +899,14 @@ static int usb_device_match(struct device *dev, struct device_driver *drv)
return 0;
}
-static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int usb_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct usb_device *usb_dev;
+ const struct usb_device *usb_dev;
if (is_usb_device(dev)) {
usb_dev = to_usb_device(dev);
} else if (is_usb_interface(dev)) {
- struct usb_interface *intf = to_usb_interface(dev);
+ const struct usb_interface *intf = to_usb_interface(dev);
usb_dev = interface_to_usbdev(intf);
} else {
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 9eca403af2a8..97a0f8faea6e 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -2389,9 +2389,8 @@ static int usb_enumerate_device_otg(struct usb_device *udev)
* usb_enumerate_device - Read device configs/intfs/otg (usbcore-internal)
* @udev: newly addressed device (in ADDRESS state)
*
- * This is only called by usb_new_device() and usb_authorize_device()
- * and FIXME -- all comments that apply to them apply here wrt to
- * environment.
+ * This is only called by usb_new_device() -- all comments that apply there
+ * apply here wrt to environment.
*
* If the device is WUSB and not authorized, we don't attempt to read
* the string descriptors, as they will be errored out by the device
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 127fac1af676..cc404bb7e8f7 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -1819,11 +1819,11 @@ void usb_authorize_interface(struct usb_interface *intf)
}
}
-static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int usb_if_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct usb_device *usb_dev;
- struct usb_interface *intf;
- struct usb_host_interface *alt;
+ const struct usb_device *usb_dev;
+ const struct usb_interface *intf;
+ const struct usb_host_interface *alt;
intf = to_usb_interface(dev);
usb_dev = interface_to_usbdev(intf);
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 8217032dfb85..b63f78e48c74 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -869,11 +869,7 @@ read_descriptors(struct file *filp, struct kobject *kobj,
size_t srclen, n;
int cfgno;
void *src;
- int retval;
- retval = usb_lock_device_interruptible(udev);
- if (retval < 0)
- return -EINTR;
/* The binary attribute begins with the device descriptor.
* Following that are the raw descriptor entries for all the
* configurations (config plus subsidiary descriptors).
@@ -898,7 +894,6 @@ read_descriptors(struct file *filp, struct kobject *kobj,
off -= srclen;
}
}
- usb_unlock_device(udev);
return count - nleft;
}
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 11b15d7b357a..34742fbbd84d 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -423,9 +423,9 @@ static void usb_release_dev(struct device *dev)
kfree(udev);
}
-static int usb_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int usb_dev_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct usb_device *usb_dev;
+ const struct usb_device *usb_dev;
usb_dev = to_usb_device(dev);
@@ -505,10 +505,10 @@ static const struct dev_pm_ops usb_device_pm_ops = {
#endif /* CONFIG_PM */
-static char *usb_devnode(struct device *dev,
+static char *usb_devnode(const struct device *dev,
umode_t *mode, kuid_t *uid, kgid_t *gid)
{
- struct usb_device *usb_dev;
+ const struct usb_device *usb_dev;
usb_dev = to_usb_device(dev);
return kasprintf(GFP_KERNEL, "bus/usb/%03d/%03d",
@@ -998,7 +998,7 @@ static void usb_debugfs_init(void)
static void usb_debugfs_cleanup(void)
{
- debugfs_remove(debugfs_lookup("devices", usb_debug_root));
+ debugfs_lookup_and_remove("devices", usb_debug_root);
}
/*
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 8f9959ba9fd4..582ebd9cf9c2 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -1117,6 +1117,7 @@ struct dwc3_scratchpad_array {
* address.
* @num_ep_resized: carries the current number endpoints which have had its tx
* fifo resized.
+ * @debug_root: root debugfs directory for this device to put its files in.
*/
struct dwc3 {
struct work_struct drd_work;
@@ -1332,6 +1333,7 @@ struct dwc3 {
int max_cfg_eps;
int last_fifo_depth;
int num_ep_resized;
+ struct dentry *debug_root;
};
#define INCRX_BURST_MODE 0
diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h
index 48b44b88dc25..8bb2c9e3b9ac 100644
--- a/drivers/usb/dwc3/debug.h
+++ b/drivers/usb/dwc3/debug.h
@@ -414,11 +414,14 @@ static inline const char *dwc3_gadget_generic_cmd_status_string(int status)
#ifdef CONFIG_DEBUG_FS
extern void dwc3_debugfs_create_endpoint_dir(struct dwc3_ep *dep);
+extern void dwc3_debugfs_remove_endpoint_dir(struct dwc3_ep *dep);
extern void dwc3_debugfs_init(struct dwc3 *d);
extern void dwc3_debugfs_exit(struct dwc3 *d);
#else
static inline void dwc3_debugfs_create_endpoint_dir(struct dwc3_ep *dep)
{ }
+static inline void dwc3_debugfs_remove_endpoint_dir(struct dwc3_ep *dep)
+{ }
static inline void dwc3_debugfs_init(struct dwc3 *d)
{ }
static inline void dwc3_debugfs_exit(struct dwc3 *d)
diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c
index f2b7675c7f62..850df0e6bcab 100644
--- a/drivers/usb/dwc3/debugfs.c
+++ b/drivers/usb/dwc3/debugfs.c
@@ -873,27 +873,23 @@ static const struct dwc3_ep_file_map dwc3_ep_file_map[] = {
{ "GDBGEPINFO", &dwc3_ep_info_register_fops, },
};
-static void dwc3_debugfs_create_endpoint_files(struct dwc3_ep *dep,
- struct dentry *parent)
+void dwc3_debugfs_create_endpoint_dir(struct dwc3_ep *dep)
{
+ struct dentry *dir;
int i;
+ dir = debugfs_create_dir(dep->name, dep->dwc->debug_root);
for (i = 0; i < ARRAY_SIZE(dwc3_ep_file_map); i++) {
const struct file_operations *fops = dwc3_ep_file_map[i].fops;
const char *name = dwc3_ep_file_map[i].name;
- debugfs_create_file(name, 0444, parent, dep, fops);
+ debugfs_create_file(name, 0444, dir, dep, fops);
}
}
-void dwc3_debugfs_create_endpoint_dir(struct dwc3_ep *dep)
+void dwc3_debugfs_remove_endpoint_dir(struct dwc3_ep *dep)
{
- struct dentry *dir;
- struct dentry *root;
-
- root = debugfs_lookup(dev_name(dep->dwc->dev), usb_debug_root);
- dir = debugfs_create_dir(dep->name, root);
- dwc3_debugfs_create_endpoint_files(dep, dir);
+ debugfs_lookup_and_remove(dep->name, dep->dwc->debug_root);
}
void dwc3_debugfs_init(struct dwc3 *dwc)
@@ -911,6 +907,7 @@ void dwc3_debugfs_init(struct dwc3 *dwc)
dwc->regset->base = dwc->regs - DWC3_GLOBALS_REGS_START;
root = debugfs_create_dir(dev_name(dwc->dev), usb_debug_root);
+ dwc->debug_root = root;
debugfs_create_regset32("regdump", 0444, root, dwc->regset);
debugfs_create_file("lsp_dump", 0644, root, dwc, &dwc3_lsp_fops);
@@ -929,6 +926,6 @@ void dwc3_debugfs_init(struct dwc3 *dwc)
void dwc3_debugfs_exit(struct dwc3 *dwc)
{
- debugfs_remove(debugfs_lookup(dev_name(dwc->dev), usb_debug_root));
+ debugfs_lookup_and_remove(dev_name(dwc->dev), usb_debug_root);
kfree(dwc->regset);
}
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index 89c9ab2b19f8..a23ddbb81979 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -47,6 +47,7 @@
#define PCI_DEVICE_ID_INTEL_ADLS 0x7ae1
#define PCI_DEVICE_ID_INTEL_RPL 0xa70e
#define PCI_DEVICE_ID_INTEL_RPLS 0x7a61
+#define PCI_DEVICE_ID_INTEL_MTLM 0x7eb1
#define PCI_DEVICE_ID_INTEL_MTLP 0x7ec1
#define PCI_DEVICE_ID_INTEL_MTL 0x7e7e
#define PCI_DEVICE_ID_INTEL_TGL 0x9a15
@@ -467,6 +468,9 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_RPLS),
(kernel_ulong_t) &dwc3_pci_intel_swnode, },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTLM),
+ (kernel_ulong_t) &dwc3_pci_intel_swnode, },
+
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTLP),
(kernel_ulong_t) &dwc3_pci_intel_swnode, },
diff --git a/drivers/usb/dwc3/dwc3-xilinx.c b/drivers/usb/dwc3/dwc3-xilinx.c
index 0745e9f11b2e..2c36f97652ca 100644
--- a/drivers/usb/dwc3/dwc3-xilinx.c
+++ b/drivers/usb/dwc3/dwc3-xilinx.c
@@ -14,7 +14,6 @@
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/gpio/consumer.h>
-#include <linux/of_gpio.h>
#include <linux/of_platform.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 89dcfac01235..3c63fa97a680 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -3194,9 +3194,7 @@ static void dwc3_gadget_free_endpoints(struct dwc3 *dwc)
list_del(&dep->endpoint.ep_list);
}
- debugfs_remove_recursive(debugfs_lookup(dep->name,
- debugfs_lookup(dev_name(dep->dwc->dev),
- usb_debug_root)));
+ dwc3_debugfs_remove_endpoint_dir(dep);
kfree(dep);
}
}
diff --git a/drivers/usb/early/xhci-dbc.c b/drivers/usb/early/xhci-dbc.c
index 797047154820..341408410ed9 100644
--- a/drivers/usb/early/xhci-dbc.c
+++ b/drivers/usb/early/xhci-dbc.c
@@ -499,8 +499,7 @@ static int xdbc_bulk_transfer(void *data, int size, bool read)
addr = xdbc.in_dma;
xdbc.flags |= XDBC_FLAGS_IN_PROCESS;
} else {
- memset(xdbc.out_buf, 0, XDBC_MAX_PACKET);
- memcpy(xdbc.out_buf, data, size);
+ memcpy_and_pad(xdbc.out_buf, XDBC_MAX_PACKET, data, size, 0);
addr = xdbc.out_dma;
xdbc.flags |= XDBC_FLAGS_OUT_PROCESS;
}
@@ -874,13 +873,14 @@ retry:
static void early_xdbc_write(struct console *con, const char *str, u32 n)
{
- static char buf[XDBC_MAX_PACKET];
+ /* static variables are zeroed, so buf is always NULL terminated */
+ static char buf[XDBC_MAX_PACKET + 1];
int chunk, ret;
int use_cr = 0;
if (!xdbc.xdbc_reg)
return;
- memset(buf, 0, XDBC_MAX_PACKET);
+
while (n > 0) {
for (chunk = 0; chunk < XDBC_MAX_PACKET && n > 0; str++, chunk++, n--) {
diff --git a/drivers/usb/fotg210/Kconfig b/drivers/usb/fotg210/Kconfig
index 2b05968735ba..87a16258274e 100644
--- a/drivers/usb/fotg210/Kconfig
+++ b/drivers/usb/fotg210/Kconfig
@@ -29,7 +29,7 @@ config USB_FOTG210_UDC
bool "Faraday FOTG210 USB Peripheral Controller support"
help
Faraday USB2.0 OTG controller which can be configured as
- high speed or full speed USB device. This driver suppports
+ high speed or full speed USB device. This driver supports
Bulk Transfer so far.
Say "y" to link the driver statically, or "m" to build a
diff --git a/drivers/usb/fotg210/fotg210-core.c b/drivers/usb/fotg210/fotg210-core.c
index ee740a6da463..cb75464ab290 100644
--- a/drivers/usb/fotg210/fotg210-core.c
+++ b/drivers/usb/fotg210/fotg210-core.c
@@ -6,6 +6,7 @@
* driver.
*/
#include <linux/bitops.h>
+#include <linux/clk.h>
#include <linux/device.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
@@ -17,6 +18,11 @@
#include "fotg210.h"
+/* Role Register 0x80 */
+#define FOTG210_RR 0x80
+#define FOTG210_RR_ID BIT(21) /* 1 = B-device, 0 = A-device */
+#define FOTG210_RR_CROLE BIT(20) /* 1 = device, 0 = host */
+
/*
* Gemini-specific initialization function, only executed on the
* Gemini SoC using the global misc control register.
@@ -33,9 +39,10 @@
#define GEMINI_MISC_USB0_MINI_B BIT(29)
#define GEMINI_MISC_USB1_MINI_B BIT(30)
-static int fotg210_gemini_init(struct device *dev, struct resource *res,
+static int fotg210_gemini_init(struct fotg210 *fotg, struct resource *res,
enum usb_dr_mode mode)
{
+ struct device *dev = fotg->dev;
struct device_node *np = dev->of_node;
struct regmap *map;
bool wakeup;
@@ -43,10 +50,9 @@ static int fotg210_gemini_init(struct device *dev, struct resource *res,
int ret;
map = syscon_regmap_lookup_by_phandle(np, "syscon");
- if (IS_ERR(map)) {
- dev_err(dev, "no syscon\n");
- return PTR_ERR(map);
- }
+ if (IS_ERR(map))
+ return dev_err_probe(dev, PTR_ERR(map), "no syscon\n");
+ fotg->map = map;
wakeup = of_property_read_bool(np, "wakeup-source");
/*
@@ -55,6 +61,7 @@ static int fotg210_gemini_init(struct device *dev, struct resource *res,
*/
mask = 0;
if (res->start == 0x69000000) {
+ fotg->port = GEMINI_PORT_1;
mask = GEMINI_MISC_USB1_VBUS_ON | GEMINI_MISC_USB1_MINI_B |
GEMINI_MISC_USB1_WAKEUP;
if (mode == USB_DR_MODE_HOST)
@@ -64,6 +71,7 @@ static int fotg210_gemini_init(struct device *dev, struct resource *res,
if (wakeup)
val |= GEMINI_MISC_USB1_WAKEUP;
} else {
+ fotg->port = GEMINI_PORT_0;
mask = GEMINI_MISC_USB0_VBUS_ON | GEMINI_MISC_USB0_MINI_B |
GEMINI_MISC_USB0_WAKEUP;
if (mode == USB_DR_MODE_HOST)
@@ -85,27 +93,74 @@ static int fotg210_gemini_init(struct device *dev, struct resource *res,
return 0;
}
+/**
+ * fotg210_vbus() - Called by gadget driver to enable/disable VBUS
+ * @enable: true to enable VBUS, false to disable VBUS
+ */
+void fotg210_vbus(struct fotg210 *fotg, bool enable)
+{
+ u32 mask;
+ u32 val;
+ int ret;
+
+ switch (fotg->port) {
+ case GEMINI_PORT_0:
+ mask = GEMINI_MISC_USB0_VBUS_ON;
+ val = enable ? GEMINI_MISC_USB0_VBUS_ON : 0;
+ break;
+ case GEMINI_PORT_1:
+ mask = GEMINI_MISC_USB1_VBUS_ON;
+ val = enable ? GEMINI_MISC_USB1_VBUS_ON : 0;
+ break;
+ default:
+ return;
+ }
+ ret = regmap_update_bits(fotg->map, GEMINI_GLOBAL_MISC_CTRL, mask, val);
+ if (ret)
+ dev_err(fotg->dev, "failed to %s VBUS\n",
+ enable ? "enable" : "disable");
+ dev_info(fotg->dev, "%s: %s VBUS\n", __func__, enable ? "enable" : "disable");
+}
+
static int fotg210_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
enum usb_dr_mode mode;
+ struct fotg210 *fotg;
+ u32 val;
int ret;
+ fotg = devm_kzalloc(dev, sizeof(*fotg), GFP_KERNEL);
+ if (!fotg)
+ return -ENOMEM;
+ fotg->dev = dev;
+
+ fotg->base = devm_platform_get_and_ioremap_resource(pdev, 0, &fotg->res);
+ if (IS_ERR(fotg->base))
+ return PTR_ERR(fotg->base);
+
+ fotg->pclk = devm_clk_get_optional_enabled(dev, "PCLK");
+ if (IS_ERR(fotg->pclk))
+ return PTR_ERR(fotg->pclk);
+
mode = usb_get_dr_mode(dev);
if (of_device_is_compatible(dev->of_node, "cortina,gemini-usb")) {
- struct resource *res;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- ret = fotg210_gemini_init(dev, res, mode);
+ ret = fotg210_gemini_init(fotg, fotg->res, mode);
if (ret)
return ret;
}
- if (mode == USB_DR_MODE_PERIPHERAL)
- ret = fotg210_udc_probe(pdev);
- else
- ret = fotg210_hcd_probe(pdev);
+ val = readl(fotg->base + FOTG210_RR);
+ if (mode == USB_DR_MODE_PERIPHERAL) {
+ if (!(val & FOTG210_RR_CROLE))
+ dev_err(dev, "block not in device role\n");
+ ret = fotg210_udc_probe(pdev, fotg);
+ } else {
+ if (val & FOTG210_RR_CROLE)
+ dev_err(dev, "block not in host role\n");
+ ret = fotg210_hcd_probe(pdev, fotg);
+ }
return ret;
}
@@ -127,7 +182,9 @@ static int fotg210_remove(struct platform_device *pdev)
#ifdef CONFIG_OF
static const struct of_device_id fotg210_of_match[] = {
+ { .compatible = "faraday,fotg200" },
{ .compatible = "faraday,fotg210" },
+ /* TODO: can we also handle FUSB220? */
{},
};
MODULE_DEVICE_TABLE(of, fotg210_of_match);
diff --git a/drivers/usb/fotg210/fotg210-hcd.c b/drivers/usb/fotg210/fotg210-hcd.c
index 51ac93a2eb98..929106c16b29 100644
--- a/drivers/usb/fotg210/fotg210-hcd.c
+++ b/drivers/usb/fotg210/fotg210-hcd.c
@@ -33,7 +33,6 @@
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/iopoll.h>
-#include <linux/clk.h>
#include <asm/byteorder.h>
#include <asm/irq.h>
@@ -862,7 +861,7 @@ static inline void remove_debug_files(struct fotg210_hcd *fotg210)
{
struct usb_bus *bus = &fotg210_to_hcd(fotg210)->self;
- debugfs_remove(debugfs_lookup(bus->bus_name, fotg210_debug_root));
+ debugfs_lookup_and_remove(bus->bus_name, fotg210_debug_root);
}
/* handshake - spin reading hc until handshake completes or fails
@@ -4687,14 +4686,11 @@ static ssize_t uframe_periodic_max_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct fotg210_hcd *fotg210;
- int n;
fotg210 = hcd_to_fotg210(bus_to_hcd(dev_get_drvdata(dev)));
- n = scnprintf(buf, PAGE_SIZE, "%d\n", fotg210->uframe_periodic_max);
- return n;
+ return sysfs_emit(buf, "%d\n", fotg210->uframe_periodic_max);
}
-
static ssize_t uframe_periodic_max_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
@@ -4706,8 +4702,10 @@ static ssize_t uframe_periodic_max_store(struct device *dev,
ssize_t ret;
fotg210 = hcd_to_fotg210(bus_to_hcd(dev_get_drvdata(dev)));
- if (kstrtouint(buf, 0, &uframe_periodic_max) < 0)
- return -EINVAL;
+
+ ret = kstrtouint(buf, 0, &uframe_periodic_max);
+ if (ret)
+ return ret;
if (uframe_periodic_max < 100 || uframe_periodic_max >= 125) {
fotg210_info(fotg210, "rejecting invalid request for uframe_periodic_max=%u\n",
@@ -5557,11 +5555,10 @@ static void fotg210_init(struct fotg210_hcd *fotg210)
* then invokes the start() method for the HCD associated with it
* through the hotplug entry's driver_data.
*/
-int fotg210_hcd_probe(struct platform_device *pdev)
+int fotg210_hcd_probe(struct platform_device *pdev, struct fotg210 *fotg)
{
struct device *dev = &pdev->dev;
struct usb_hcd *hcd;
- struct resource *res;
int irq;
int retval;
struct fotg210_hcd *fotg210;
@@ -5578,70 +5575,42 @@ int fotg210_hcd_probe(struct platform_device *pdev)
hcd = usb_create_hcd(&fotg210_fotg210_hc_driver, dev,
dev_name(dev));
if (!hcd) {
- dev_err(dev, "failed to create hcd\n");
- retval = -ENOMEM;
+ retval = dev_err_probe(dev, -ENOMEM, "failed to create hcd\n");
goto fail_create_hcd;
}
hcd->has_tt = 1;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- hcd->regs = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(hcd->regs)) {
- retval = PTR_ERR(hcd->regs);
- goto failed_put_hcd;
- }
+ hcd->regs = fotg->base;
- hcd->rsrc_start = res->start;
- hcd->rsrc_len = resource_size(res);
+ hcd->rsrc_start = fotg->res->start;
+ hcd->rsrc_len = resource_size(fotg->res);
fotg210 = hcd_to_fotg210(hcd);
+ fotg210->fotg = fotg;
fotg210->caps = hcd->regs;
- /* It's OK not to supply this clock */
- fotg210->pclk = clk_get(dev, "PCLK");
- if (!IS_ERR(fotg210->pclk)) {
- retval = clk_prepare_enable(fotg210->pclk);
- if (retval) {
- dev_err(dev, "failed to enable PCLK\n");
- goto failed_put_hcd;
- }
- } else if (PTR_ERR(fotg210->pclk) == -EPROBE_DEFER) {
- /*
- * Percolate deferrals, for anything else,
- * just live without the clocking.
- */
- retval = PTR_ERR(fotg210->pclk);
- goto failed_dis_clk;
- }
-
retval = fotg210_setup(hcd);
if (retval)
- goto failed_dis_clk;
+ goto failed_put_hcd;
fotg210_init(fotg210);
retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (retval) {
- dev_err(dev, "failed to add hcd with err %d\n", retval);
- goto failed_dis_clk;
+ dev_err_probe(dev, retval, "failed to add hcd\n");
+ goto failed_put_hcd;
}
device_wakeup_enable(hcd->self.controller);
platform_set_drvdata(pdev, hcd);
return retval;
-failed_dis_clk:
- if (!IS_ERR(fotg210->pclk)) {
- clk_disable_unprepare(fotg210->pclk);
- clk_put(fotg210->pclk);
- }
failed_put_hcd:
usb_put_hcd(hcd);
fail_create_hcd:
- dev_err(dev, "init %s fail, %d\n", dev_name(dev), retval);
- return retval;
+ return dev_err_probe(dev, retval, "init %s fail\n", dev_name(dev));
}
/*
@@ -5652,12 +5621,6 @@ fail_create_hcd:
int fotg210_hcd_remove(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
- struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
-
- if (!IS_ERR(fotg210->pclk)) {
- clk_disable_unprepare(fotg210->pclk);
- clk_put(fotg210->pclk);
- }
usb_remove_hcd(hcd);
usb_put_hcd(hcd);
diff --git a/drivers/usb/fotg210/fotg210-hcd.h b/drivers/usb/fotg210/fotg210-hcd.h
index 0781442b7a24..13c9342982ee 100644
--- a/drivers/usb/fotg210/fotg210-hcd.h
+++ b/drivers/usb/fotg210/fotg210-hcd.h
@@ -182,6 +182,7 @@ struct fotg210_hcd { /* one per controller */
# define INCR(x) do {} while (0)
#endif
+ struct fotg210 *fotg; /* Overarching FOTG210 device */
/* silicon clock */
struct clk *pclk;
};
diff --git a/drivers/usb/fotg210/fotg210-udc.c b/drivers/usb/fotg210/fotg210-udc.c
index eb076746f032..f7ea84070554 100644
--- a/drivers/usb/fotg210/fotg210-udc.c
+++ b/drivers/usb/fotg210/fotg210-udc.c
@@ -7,6 +7,7 @@
* Author : Yuan-Hsin Chen <yhchen@faraday-tech.com>
*/
+#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/interrupt.h>
@@ -15,7 +16,6 @@
#include <linux/platform_device.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
-#include <linux/clk.h>
#include <linux/usb/otg.h>
#include <linux/usb/phy.h>
@@ -29,6 +29,14 @@ static const char udc_name[] = "fotg210_udc";
static const char * const fotg210_ep_name[] = {
"ep0", "ep1", "ep2", "ep3", "ep4"};
+static void fotg210_ack_int(struct fotg210_udc *fotg210, u32 offset, u32 mask)
+{
+ u32 value = ioread32(fotg210->reg + offset);
+
+ value &= ~mask;
+ iowrite32(value, fotg210->reg + offset);
+}
+
static void fotg210_disable_fifo_int(struct fotg210_ep *ep)
{
u32 value = ioread32(ep->fotg210->reg + FOTG210_DMISGR1);
@@ -304,8 +312,7 @@ static void fotg210_wait_dma_done(struct fotg210_ep *ep)
goto dma_reset;
} while (!(value & DISGR2_DMA_CMPLT));
- value &= ~DISGR2_DMA_CMPLT;
- iowrite32(value, ep->fotg210->reg + FOTG210_DISGR2);
+ fotg210_ack_int(ep->fotg210, FOTG210_DISGR2, DISGR2_DMA_CMPLT);
return;
dma_reset:
@@ -710,6 +717,20 @@ static int fotg210_is_epnstall(struct fotg210_ep *ep)
return value & INOUTEPMPSR_STL_EP ? 1 : 0;
}
+/* For EP0 requests triggered by this driver (currently GET_STATUS response) */
+static void fotg210_ep0_complete(struct usb_ep *_ep, struct usb_request *req)
+{
+ struct fotg210_ep *ep;
+ struct fotg210_udc *fotg210;
+
+ ep = container_of(_ep, struct fotg210_ep, ep);
+ fotg210 = ep->fotg210;
+
+ if (req->status || req->actual != req->length) {
+ dev_warn(&fotg210->gadget.dev, "EP0 request failed: %d\n", req->status);
+ }
+}
+
static void fotg210_get_status(struct fotg210_udc *fotg210,
struct usb_ctrlrequest *ctrl)
{
@@ -831,14 +852,6 @@ static void fotg210_ep0in(struct fotg210_udc *fotg210)
}
}
-static void fotg210_clear_comabt_int(struct fotg210_udc *fotg210)
-{
- u32 value = ioread32(fotg210->reg + FOTG210_DISGR0);
-
- value &= ~DISGR0_CX_COMABT_INT;
- iowrite32(value, fotg210->reg + FOTG210_DISGR0);
-}
-
static void fotg210_in_fifo_handler(struct fotg210_ep *ep)
{
struct fotg210_request *req = list_entry(ep->queue.next,
@@ -880,60 +893,43 @@ static irqreturn_t fotg210_irq(int irq, void *_fotg210)
void __iomem *reg = fotg210->reg + FOTG210_DISGR2;
u32 int_grp2 = ioread32(reg);
u32 int_msk2 = ioread32(fotg210->reg + FOTG210_DMISGR2);
- u32 value;
int_grp2 &= ~int_msk2;
if (int_grp2 & DISGR2_USBRST_INT) {
usb_gadget_udc_reset(&fotg210->gadget,
fotg210->driver);
- value = ioread32(reg);
- value &= ~DISGR2_USBRST_INT;
- iowrite32(value, reg);
+ fotg210_ack_int(fotg210, FOTG210_DISGR2, DISGR2_USBRST_INT);
pr_info("fotg210 udc reset\n");
}
if (int_grp2 & DISGR2_SUSP_INT) {
- value = ioread32(reg);
- value &= ~DISGR2_SUSP_INT;
- iowrite32(value, reg);
+ fotg210_ack_int(fotg210, FOTG210_DISGR2, DISGR2_SUSP_INT);
pr_info("fotg210 udc suspend\n");
}
if (int_grp2 & DISGR2_RESM_INT) {
- value = ioread32(reg);
- value &= ~DISGR2_RESM_INT;
- iowrite32(value, reg);
+ fotg210_ack_int(fotg210, FOTG210_DISGR2, DISGR2_RESM_INT);
pr_info("fotg210 udc resume\n");
}
if (int_grp2 & DISGR2_ISO_SEQ_ERR_INT) {
- value = ioread32(reg);
- value &= ~DISGR2_ISO_SEQ_ERR_INT;
- iowrite32(value, reg);
+ fotg210_ack_int(fotg210, FOTG210_DISGR2, DISGR2_ISO_SEQ_ERR_INT);
pr_info("fotg210 iso sequence error\n");
}
if (int_grp2 & DISGR2_ISO_SEQ_ABORT_INT) {
- value = ioread32(reg);
- value &= ~DISGR2_ISO_SEQ_ABORT_INT;
- iowrite32(value, reg);
+ fotg210_ack_int(fotg210, FOTG210_DISGR2, DISGR2_ISO_SEQ_ABORT_INT);
pr_info("fotg210 iso sequence abort\n");
}
if (int_grp2 & DISGR2_TX0BYTE_INT) {
fotg210_clear_tx0byte(fotg210);
- value = ioread32(reg);
- value &= ~DISGR2_TX0BYTE_INT;
- iowrite32(value, reg);
+ fotg210_ack_int(fotg210, FOTG210_DISGR2, DISGR2_TX0BYTE_INT);
pr_info("fotg210 transferred 0 byte\n");
}
if (int_grp2 & DISGR2_RX0BYTE_INT) {
fotg210_clear_rx0byte(fotg210);
- value = ioread32(reg);
- value &= ~DISGR2_RX0BYTE_INT;
- iowrite32(value, reg);
+ fotg210_ack_int(fotg210, FOTG210_DISGR2, DISGR2_RX0BYTE_INT);
pr_info("fotg210 received 0 byte\n");
}
if (int_grp2 & DISGR2_DMA_ERROR) {
- value = ioread32(reg);
- value &= ~DISGR2_DMA_ERROR;
- iowrite32(value, reg);
+ fotg210_ack_int(fotg210, FOTG210_DISGR2, DISGR2_DMA_ERROR);
}
}
@@ -947,7 +943,7 @@ static irqreturn_t fotg210_irq(int irq, void *_fotg210)
/* the highest priority in this source register */
if (int_grp0 & DISGR0_CX_COMABT_INT) {
- fotg210_clear_comabt_int(fotg210);
+ fotg210_ack_int(fotg210, FOTG210_DISGR0, DISGR0_CX_COMABT_INT);
pr_info("fotg210 CX command abort\n");
}
@@ -1015,6 +1011,10 @@ static int fotg210_udc_start(struct usb_gadget *g,
/* hook up the driver */
fotg210->driver = driver;
+ fotg210->gadget.dev.of_node = fotg210->dev->of_node;
+ fotg210->gadget.speed = USB_SPEED_UNKNOWN;
+
+ dev_info(fotg210->dev, "bound driver %s\n", driver->driver.name);
if (!IS_ERR_OR_NULL(fotg210->phy)) {
ret = otg_set_peripheral(fotg210->phy->otg,
@@ -1023,6 +1023,11 @@ static int fotg210_udc_start(struct usb_gadget *g,
dev_err(fotg210->dev, "can't bind to phy\n");
}
+ /* chip enable */
+ value = ioread32(fotg210->reg + FOTG210_DMCR);
+ value |= DMCR_CHIP_EN;
+ iowrite32(value, fotg210->reg + FOTG210_DMCR);
+
/* enable device global interrupt */
value = ioread32(fotg210->reg + FOTG210_DMCR);
value |= DMCR_GLINT_EN;
@@ -1039,6 +1044,15 @@ static void fotg210_init(struct fotg210_udc *fotg210)
iowrite32(GMIR_MHC_INT | GMIR_MOTG_INT | GMIR_INT_POLARITY,
fotg210->reg + FOTG210_GMIR);
+ /* mask interrupts for groups other than 0-2 */
+ iowrite32(~(DMIGR_MINT_G0 | DMIGR_MINT_G1 | DMIGR_MINT_G2),
+ fotg210->reg + FOTG210_DMIGR);
+
+ /* udc software reset */
+ iowrite32(DMCR_SFRST, fotg210->reg + FOTG210_DMCR);
+ /* Better wait a bit, but without a datasheet, no idea how long. */
+ usleep_range(100, 200);
+
/* disable device global interrupt */
value = ioread32(fotg210->reg + FOTG210_DMCR);
value &= ~DMCR_GLINT_EN;
@@ -1071,15 +1085,33 @@ static int fotg210_udc_stop(struct usb_gadget *g)
fotg210_init(fotg210);
fotg210->driver = NULL;
+ fotg210->gadget.speed = USB_SPEED_UNKNOWN;
spin_unlock_irqrestore(&fotg210->lock, flags);
return 0;
}
+/**
+ * fotg210_vbus_session - Called by external transceiver to enable/disable udc
+ * @_gadget: usb gadget
+ * @is_active: 0 if should disable UDC VBUS, 1 if should enable
+ *
+ * Returns 0
+ */
+static int fotg210_vbus_session(struct usb_gadget *g, int is_active)
+{
+ struct fotg210_udc *fotg210 = gadget_to_fotg210(g);
+
+ /* Call down to core integration layer to drive or disable VBUS */
+ fotg210_vbus(fotg210->fotg, is_active);
+ return 0;
+}
+
static const struct usb_gadget_ops fotg210_gadget_ops = {
.udc_start = fotg210_udc_start,
.udc_stop = fotg210_udc_stop,
+ .vbus_session = fotg210_vbus_session,
};
/**
@@ -1133,34 +1165,22 @@ int fotg210_udc_remove(struct platform_device *pdev)
for (i = 0; i < FOTG210_MAX_NUM_EP; i++)
kfree(fotg210->ep[i]);
- if (!IS_ERR(fotg210->pclk))
- clk_disable_unprepare(fotg210->pclk);
-
kfree(fotg210);
return 0;
}
-int fotg210_udc_probe(struct platform_device *pdev)
+int fotg210_udc_probe(struct platform_device *pdev, struct fotg210 *fotg)
{
- struct resource *res;
struct fotg210_udc *fotg210 = NULL;
struct device *dev = &pdev->dev;
int irq;
int ret = 0;
int i;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- pr_err("platform_get_resource error.\n");
- return -ENODEV;
- }
-
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- pr_err("could not get irq\n");
- return -ENODEV;
- }
+ if (irq < 0)
+ return irq;
/* initialize udc */
fotg210 = kzalloc(sizeof(struct fotg210_udc), GFP_KERNEL);
@@ -1168,35 +1188,19 @@ int fotg210_udc_probe(struct platform_device *pdev)
return -ENOMEM;
fotg210->dev = dev;
-
- /* It's OK not to supply this clock */
- fotg210->pclk = devm_clk_get(dev, "PCLK");
- if (!IS_ERR(fotg210->pclk)) {
- ret = clk_prepare_enable(fotg210->pclk);
- if (ret) {
- dev_err(dev, "failed to enable PCLK\n");
- goto err;
- }
- } else if (PTR_ERR(fotg210->pclk) == -EPROBE_DEFER) {
- /*
- * Percolate deferrals, for anything else,
- * just live without the clocking.
- */
- ret = -EPROBE_DEFER;
- goto err;
- }
+ fotg210->fotg = fotg;
fotg210->phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0);
if (IS_ERR(fotg210->phy)) {
ret = PTR_ERR(fotg210->phy);
if (ret == -EPROBE_DEFER)
- goto err_pclk;
+ goto err_free;
dev_info(dev, "no PHY found\n");
fotg210->phy = NULL;
} else {
ret = usb_phy_init(fotg210->phy);
if (ret)
- goto err_pclk;
+ goto err_free;
dev_info(dev, "found and initialized PHY\n");
}
@@ -1208,11 +1212,7 @@ int fotg210_udc_probe(struct platform_device *pdev)
goto err_alloc;
}
- fotg210->reg = ioremap(res->start, resource_size(res));
- if (fotg210->reg == NULL) {
- dev_err(dev, "ioremap error\n");
- goto err_alloc;
- }
+ fotg210->reg = fotg->base;
spin_lock_init(&fotg210->lock);
@@ -1261,6 +1261,8 @@ int fotg210_udc_probe(struct platform_device *pdev)
if (fotg210->ep0_req == NULL)
goto err_map;
+ fotg210->ep0_req->complete = fotg210_ep0_complete;
+
fotg210_init(fotg210);
fotg210_disable_unplug(fotg210);
@@ -1268,7 +1270,7 @@ int fotg210_udc_probe(struct platform_device *pdev)
ret = request_irq(irq, fotg210_irq, IRQF_SHARED,
udc_name, fotg210);
if (ret < 0) {
- dev_err(dev, "request_irq error (%d)\n", ret);
+ dev_err_probe(dev, ret, "request_irq error\n");
goto err_req;
}
@@ -1297,11 +1299,8 @@ err_map:
err_alloc:
for (i = 0; i < FOTG210_MAX_NUM_EP; i++)
kfree(fotg210->ep[i]);
-err_pclk:
- if (!IS_ERR(fotg210->pclk))
- clk_disable_unprepare(fotg210->pclk);
-err:
+err_free:
kfree(fotg210);
return ret;
}
diff --git a/drivers/usb/fotg210/fotg210-udc.h b/drivers/usb/fotg210/fotg210-udc.h
index fadb57ca8d78..252cb2b8e2fe 100644
--- a/drivers/usb/fotg210/fotg210-udc.h
+++ b/drivers/usb/fotg210/fotg210-udc.h
@@ -58,6 +58,8 @@
/* Device Mask of Interrupt Group Register (0x130) */
#define FOTG210_DMIGR 0x130
+#define DMIGR_MINT_G2 (1 << 2)
+#define DMIGR_MINT_G1 (1 << 1)
#define DMIGR_MINT_G0 (1 << 0)
/* Device Mask of Interrupt Source Group 0(0x134) */
@@ -231,11 +233,11 @@ struct fotg210_ep {
struct fotg210_udc {
spinlock_t lock; /* protect the struct */
void __iomem *reg;
- struct clk *pclk;
unsigned long irq_trigger;
struct device *dev;
+ struct fotg210 *fotg;
struct usb_phy *phy;
struct usb_gadget gadget;
struct usb_gadget_driver *driver;
diff --git a/drivers/usb/fotg210/fotg210.h b/drivers/usb/fotg210/fotg210.h
index ef79d8323d89..c44c0afe2956 100644
--- a/drivers/usb/fotg210/fotg210.h
+++ b/drivers/usb/fotg210/fotg210.h
@@ -2,13 +2,31 @@
#ifndef __FOTG210_H
#define __FOTG210_H
+enum gemini_port {
+ GEMINI_PORT_NONE = 0,
+ GEMINI_PORT_0,
+ GEMINI_PORT_1,
+};
+
+struct fotg210 {
+ struct device *dev;
+ struct resource *res;
+ void __iomem *base;
+ struct clk *pclk;
+ struct regmap *map;
+ enum gemini_port port;
+};
+
+void fotg210_vbus(struct fotg210 *fotg, bool enable);
+
#ifdef CONFIG_USB_FOTG210_HCD
-int fotg210_hcd_probe(struct platform_device *pdev);
+int fotg210_hcd_probe(struct platform_device *pdev, struct fotg210 *fotg);
int fotg210_hcd_remove(struct platform_device *pdev);
int fotg210_hcd_init(void);
void fotg210_hcd_cleanup(void);
#else
-static inline int fotg210_hcd_probe(struct platform_device *pdev)
+static inline int fotg210_hcd_probe(struct platform_device *pdev,
+ struct fotg210 *fotg)
{
return 0;
}
@@ -26,10 +44,11 @@ static inline void fotg210_hcd_cleanup(void)
#endif
#ifdef CONFIG_USB_FOTG210_UDC
-int fotg210_udc_probe(struct platform_device *pdev);
+int fotg210_udc_probe(struct platform_device *pdev, struct fotg210 *fotg);
int fotg210_udc_remove(struct platform_device *pdev);
#else
-static inline int fotg210_udc_probe(struct platform_device *pdev)
+static inline int fotg210_udc_probe(struct platform_device *pdev,
+ struct fotg210 *fotg)
{
return 0;
}
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 4fa2ddf322b4..336db8f92afa 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -203,6 +203,7 @@ config USB_F_UAC2
config USB_F_UVC
tristate
+ select UVC_COMMON
config USB_F_MIDI
tristate
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 403563c06477..fa7dd6cf014d 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -14,9 +14,11 @@
#include <linux/device.h>
#include <linux/utsname.h>
#include <linux/bitfield.h>
+#include <linux/uuid.h>
#include <linux/usb/composite.h>
#include <linux/usb/otg.h>
+#include <linux/usb/webusb.h>
#include <asm/unaligned.h>
#include "u_os_desc.h"
@@ -713,14 +715,16 @@ static int bos_desc(struct usb_composite_dev *cdev)
* A SuperSpeed device shall include the USB2.0 extension descriptor
* and shall support LPM when operating in USB2.0 HS mode.
*/
- usb_ext = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
- bos->bNumDeviceCaps++;
- le16_add_cpu(&bos->wTotalLength, USB_DT_USB_EXT_CAP_SIZE);
- usb_ext->bLength = USB_DT_USB_EXT_CAP_SIZE;
- usb_ext->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
- usb_ext->bDevCapabilityType = USB_CAP_TYPE_EXT;
- usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT |
- USB_BESL_SUPPORT | besl);
+ if (cdev->gadget->lpm_capable) {
+ usb_ext = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
+ bos->bNumDeviceCaps++;
+ le16_add_cpu(&bos->wTotalLength, USB_DT_USB_EXT_CAP_SIZE);
+ usb_ext->bLength = USB_DT_USB_EXT_CAP_SIZE;
+ usb_ext->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
+ usb_ext->bDevCapabilityType = USB_CAP_TYPE_EXT;
+ usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT |
+ USB_BESL_SUPPORT | besl);
+ }
/*
* The Superspeed USB Capability descriptor shall be implemented by all
@@ -821,6 +825,37 @@ static int bos_desc(struct usb_composite_dev *cdev)
}
}
+ /* The WebUSB Platform Capability descriptor */
+ if (cdev->use_webusb) {
+ struct usb_plat_dev_cap_descriptor *webusb_cap;
+ struct usb_webusb_cap_data *webusb_cap_data;
+ guid_t webusb_uuid = WEBUSB_UUID;
+
+ webusb_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
+ webusb_cap_data = (struct usb_webusb_cap_data *) webusb_cap->CapabilityData;
+ bos->bNumDeviceCaps++;
+ le16_add_cpu(&bos->wTotalLength,
+ USB_DT_USB_PLAT_DEV_CAP_SIZE(USB_WEBUSB_CAP_DATA_SIZE));
+
+ webusb_cap->bLength = USB_DT_USB_PLAT_DEV_CAP_SIZE(USB_WEBUSB_CAP_DATA_SIZE);
+ webusb_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
+ webusb_cap->bDevCapabilityType = USB_PLAT_DEV_CAP_TYPE;
+ webusb_cap->bReserved = 0;
+ export_guid(webusb_cap->UUID, &webusb_uuid);
+
+ if (cdev->bcd_webusb_version != 0)
+ webusb_cap_data->bcdVersion = cpu_to_le16(cdev->bcd_webusb_version);
+ else
+ webusb_cap_data->bcdVersion = WEBUSB_VERSION_1_00;
+
+ webusb_cap_data->bVendorCode = cdev->b_webusb_vendor_code;
+
+ if (strnlen(cdev->landing_page, sizeof(cdev->landing_page)) > 0)
+ webusb_cap_data->iLandingPage = WEBUSB_LANDING_PAGE_PRESENT;
+ else
+ webusb_cap_data->iLandingPage = WEBUSB_LANDING_PAGE_NOT_PRESENT;
+ }
+
return le16_to_cpu(bos->wTotalLength);
}
@@ -1744,7 +1779,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
cdev->desc.bcdUSB = cpu_to_le16(0x0210);
}
} else {
- if (gadget->lpm_capable)
+ if (gadget->lpm_capable || cdev->use_webusb)
cdev->desc.bcdUSB = cpu_to_le16(0x0201);
else
cdev->desc.bcdUSB = cpu_to_le16(0x0200);
@@ -1779,7 +1814,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
break;
case USB_DT_BOS:
if (gadget_is_superspeed(gadget) ||
- gadget->lpm_capable) {
+ gadget->lpm_capable || cdev->use_webusb) {
value = bos_desc(cdev);
value = min(w_length, (u16) value);
}
@@ -2013,6 +2048,53 @@ unknown:
goto check_value;
}
+ /*
+ * WebUSB URL descriptor handling, following:
+ * https://wicg.github.io/webusb/#device-requests
+ */
+ if (cdev->use_webusb &&
+ ctrl->bRequestType == (USB_DIR_IN | USB_TYPE_VENDOR) &&
+ w_index == WEBUSB_GET_URL &&
+ w_value == WEBUSB_LANDING_PAGE_PRESENT &&
+ ctrl->bRequest == cdev->b_webusb_vendor_code) {
+ unsigned int landing_page_length;
+ unsigned int landing_page_offset;
+ struct webusb_url_descriptor *url_descriptor =
+ (struct webusb_url_descriptor *)cdev->req->buf;
+
+ url_descriptor->bDescriptorType = WEBUSB_URL_DESCRIPTOR_TYPE;
+
+ if (strncasecmp(cdev->landing_page, "https://", 8) == 0) {
+ landing_page_offset = 8;
+ url_descriptor->bScheme = WEBUSB_URL_SCHEME_HTTPS;
+ } else if (strncasecmp(cdev->landing_page, "http://", 7) == 0) {
+ landing_page_offset = 7;
+ url_descriptor->bScheme = WEBUSB_URL_SCHEME_HTTP;
+ } else {
+ landing_page_offset = 0;
+ url_descriptor->bScheme = WEBUSB_URL_SCHEME_NONE;
+ }
+
+ landing_page_length = strnlen(cdev->landing_page,
+ sizeof(url_descriptor->URL)
+ - WEBUSB_URL_DESCRIPTOR_HEADER_LENGTH + landing_page_offset);
+
+ if (ctrl->wLength < WEBUSB_URL_DESCRIPTOR_HEADER_LENGTH
+ + landing_page_length)
+ landing_page_length = ctrl->wLength
+ - WEBUSB_URL_DESCRIPTOR_HEADER_LENGTH + landing_page_offset;
+
+ memcpy(url_descriptor->URL,
+ cdev->landing_page + landing_page_offset,
+ landing_page_length - landing_page_offset);
+ url_descriptor->bLength = landing_page_length
+ - landing_page_offset + WEBUSB_URL_DESCRIPTOR_HEADER_LENGTH;
+
+ value = url_descriptor->bLength;
+
+ goto check_value;
+ }
+
VDBG(cdev,
"non-core control req%02x.%02x v%04x i%04x l%d\n",
ctrl->bRequestType, ctrl->bRequest,
diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c
index 0853536cbf2e..b9f1136aa0a2 100644
--- a/drivers/usb/gadget/configfs.c
+++ b/drivers/usb/gadget/configfs.c
@@ -7,6 +7,7 @@
#include <linux/nls.h>
#include <linux/usb/composite.h>
#include <linux/usb/gadget_configfs.h>
+#include <linux/usb/webusb.h>
#include "configfs.h"
#include "u_f.h"
#include "u_os_desc.h"
@@ -39,6 +40,7 @@ struct gadget_info {
struct config_group configs_group;
struct config_group strings_group;
struct config_group os_desc_group;
+ struct config_group webusb_group;
struct mutex lock;
struct usb_gadget_strings *gstrings[MAX_USB_STRING_LANGS + 1];
@@ -50,6 +52,11 @@ struct gadget_info {
bool use_os_desc;
char b_vendor_code;
char qw_sign[OS_STRING_QW_SIGN_LEN];
+ bool use_webusb;
+ u16 bcd_webusb_version;
+ u8 b_webusb_vendor_code;
+ char landing_page[WEBUSB_URL_RAW_MAX_LENGTH];
+
spinlock_t spinlock;
bool unbind;
};
@@ -79,7 +86,7 @@ static inline struct gadget_info *cfg_to_gadget_info(struct config_usb_cfg *cfg)
return container_of(cfg->c.cdev, struct gadget_info, cdev);
}
-struct gadget_strings {
+struct gadget_language {
struct usb_gadget_strings stringtab_dev;
struct usb_string strings[USB_GADGET_FIRST_AVAIL_IDX];
char *manufacturer;
@@ -88,6 +95,8 @@ struct gadget_strings {
struct config_group group;
struct list_head list;
+ struct list_head gadget_strings;
+ unsigned int nstrings;
};
struct gadget_config_name {
@@ -365,9 +374,9 @@ static struct configfs_attribute *gadget_root_attrs[] = {
NULL,
};
-static inline struct gadget_strings *to_gadget_strings(struct config_item *item)
+static inline struct gadget_language *to_gadget_language(struct config_item *item)
{
- return container_of(to_config_group(item), struct gadget_strings,
+ return container_of(to_config_group(item), struct gadget_language,
group);
}
@@ -430,6 +439,12 @@ static int config_usb_cfg_link(
* from another gadget or a random directory.
* Also a function instance can only be linked once.
*/
+
+ if (gi->composite.gadget_driver.udc_name) {
+ ret = -EINVAL;
+ goto out;
+ }
+
list_for_each_entry(iter, &gi->available_func, cfs_list) {
if (iter != fi)
continue;
@@ -755,20 +770,20 @@ static const struct config_item_type config_desc_type = {
.ct_owner = THIS_MODULE,
};
-GS_STRINGS_RW(gadget_strings, manufacturer);
-GS_STRINGS_RW(gadget_strings, product);
-GS_STRINGS_RW(gadget_strings, serialnumber);
+GS_STRINGS_RW(gadget_language, manufacturer);
+GS_STRINGS_RW(gadget_language, product);
+GS_STRINGS_RW(gadget_language, serialnumber);
-static struct configfs_attribute *gadget_strings_langid_attrs[] = {
- &gadget_strings_attr_manufacturer,
- &gadget_strings_attr_product,
- &gadget_strings_attr_serialnumber,
+static struct configfs_attribute *gadget_language_langid_attrs[] = {
+ &gadget_language_attr_manufacturer,
+ &gadget_language_attr_product,
+ &gadget_language_attr_serialnumber,
NULL,
};
-static void gadget_strings_attr_release(struct config_item *item)
+static void gadget_language_attr_release(struct config_item *item)
{
- struct gadget_strings *gs = to_gadget_strings(item);
+ struct gadget_language *gs = to_gadget_language(item);
kfree(gs->manufacturer);
kfree(gs->product);
@@ -778,8 +793,317 @@ static void gadget_strings_attr_release(struct config_item *item)
kfree(gs);
}
-USB_CONFIG_STRING_RW_OPS(gadget_strings);
-USB_CONFIG_STRINGS_LANG(gadget_strings, gadget_info);
+static struct configfs_item_operations gadget_language_langid_item_ops = {
+ .release = gadget_language_attr_release,
+};
+
+static ssize_t gadget_string_id_show(struct config_item *item, char *page)
+{
+ struct gadget_string *string = to_gadget_string(item);
+ int ret;
+
+ ret = sprintf(page, "%u\n", string->usb_string.id);
+ return ret;
+}
+CONFIGFS_ATTR_RO(gadget_string_, id);
+
+static ssize_t gadget_string_s_show(struct config_item *item, char *page)
+{
+ struct gadget_string *string = to_gadget_string(item);
+ int ret;
+
+ ret = snprintf(page, sizeof(string->string), "%s\n", string->string);
+ return ret;
+}
+
+static ssize_t gadget_string_s_store(struct config_item *item, const char *page,
+ size_t len)
+{
+ struct gadget_string *string = to_gadget_string(item);
+ int size = min(sizeof(string->string), len + 1);
+
+ if (len > USB_MAX_STRING_LEN)
+ return -EINVAL;
+
+ return strscpy(string->string, page, size);
+}
+CONFIGFS_ATTR(gadget_string_, s);
+
+static struct configfs_attribute *gadget_string_attrs[] = {
+ &gadget_string_attr_id,
+ &gadget_string_attr_s,
+ NULL,
+};
+
+static void gadget_string_release(struct config_item *item)
+{
+ struct gadget_string *string = to_gadget_string(item);
+
+ kfree(string);
+}
+
+static struct configfs_item_operations gadget_string_item_ops = {
+ .release = gadget_string_release,
+};
+
+static const struct config_item_type gadget_string_type = {
+ .ct_item_ops = &gadget_string_item_ops,
+ .ct_attrs = gadget_string_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct config_item *gadget_language_string_make(struct config_group *group,
+ const char *name)
+{
+ struct gadget_language *language;
+ struct gadget_string *string;
+
+ language = to_gadget_language(&group->cg_item);
+
+ string = kzalloc(sizeof(*string), GFP_KERNEL);
+ if (!string)
+ return ERR_PTR(-ENOMEM);
+
+ string->usb_string.id = language->nstrings++;
+ string->usb_string.s = string->string;
+ list_add_tail(&string->list, &language->gadget_strings);
+
+ config_item_init_type_name(&string->item, name, &gadget_string_type);
+
+ return &string->item;
+}
+
+static void gadget_language_string_drop(struct config_group *group,
+ struct config_item *item)
+{
+ struct gadget_language *language;
+ struct gadget_string *string;
+ unsigned int i = USB_GADGET_FIRST_AVAIL_IDX;
+
+ language = to_gadget_language(&group->cg_item);
+ string = to_gadget_string(item);
+
+ list_del(&string->list);
+ language->nstrings--;
+
+ /* Reset the ids for the language's strings to guarantee a continuous set */
+ list_for_each_entry(string, &language->gadget_strings, list)
+ string->usb_string.id = i++;
+}
+
+static struct configfs_group_operations gadget_language_langid_group_ops = {
+ .make_item = gadget_language_string_make,
+ .drop_item = gadget_language_string_drop,
+};
+
+static struct config_item_type gadget_language_type = {
+ .ct_item_ops = &gadget_language_langid_item_ops,
+ .ct_group_ops = &gadget_language_langid_group_ops,
+ .ct_attrs = gadget_language_langid_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct config_group *gadget_language_make(struct config_group *group,
+ const char *name)
+{
+ struct gadget_info *gi;
+ struct gadget_language *gs;
+ struct gadget_language *new;
+ int langs = 0;
+ int ret;
+
+ new = kzalloc(sizeof(*new), GFP_KERNEL);
+ if (!new)
+ return ERR_PTR(-ENOMEM);
+
+ ret = check_user_usb_string(name, &new->stringtab_dev);
+ if (ret)
+ goto err;
+ config_group_init_type_name(&new->group, name,
+ &gadget_language_type);
+
+ gi = container_of(group, struct gadget_info, strings_group);
+ ret = -EEXIST;
+ list_for_each_entry(gs, &gi->string_list, list) {
+ if (gs->stringtab_dev.language == new->stringtab_dev.language)
+ goto err;
+ langs++;
+ }
+ ret = -EOVERFLOW;
+ if (langs >= MAX_USB_STRING_LANGS)
+ goto err;
+
+ list_add_tail(&new->list, &gi->string_list);
+ INIT_LIST_HEAD(&new->gadget_strings);
+
+ /* We have the default manufacturer, product and serialnumber strings */
+ new->nstrings = 3;
+ return &new->group;
+err:
+ kfree(new);
+ return ERR_PTR(ret);
+}
+
+static void gadget_language_drop(struct config_group *group,
+ struct config_item *item)
+{
+ config_item_put(item);
+}
+
+static struct configfs_group_operations gadget_language_group_ops = {
+ .make_group = &gadget_language_make,
+ .drop_item = &gadget_language_drop,
+};
+
+static struct config_item_type gadget_language_strings_type = {
+ .ct_group_ops = &gadget_language_group_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+static inline struct gadget_info *webusb_item_to_gadget_info(
+ struct config_item *item)
+{
+ return container_of(to_config_group(item),
+ struct gadget_info, webusb_group);
+}
+
+static ssize_t webusb_use_show(struct config_item *item, char *page)
+{
+ return sysfs_emit(page, "%d\n",
+ webusb_item_to_gadget_info(item)->use_webusb);
+}
+
+static ssize_t webusb_use_store(struct config_item *item, const char *page,
+ size_t len)
+{
+ struct gadget_info *gi = webusb_item_to_gadget_info(item);
+ int ret;
+ bool use;
+
+ ret = kstrtobool(page, &use);
+ if (ret)
+ return ret;
+
+ mutex_lock(&gi->lock);
+ gi->use_webusb = use;
+ mutex_unlock(&gi->lock);
+
+ return len;
+}
+
+static ssize_t webusb_bcdVersion_show(struct config_item *item, char *page)
+{
+ return sysfs_emit(page, "0x%04x\n",
+ webusb_item_to_gadget_info(item)->bcd_webusb_version);
+}
+
+static ssize_t webusb_bcdVersion_store(struct config_item *item,
+ const char *page, size_t len)
+{
+ struct gadget_info *gi = webusb_item_to_gadget_info(item);
+ u16 bcdVersion;
+ int ret;
+
+ ret = kstrtou16(page, 0, &bcdVersion);
+ if (ret)
+ return ret;
+
+ ret = is_valid_bcd(bcdVersion);
+ if (ret)
+ return ret;
+
+ mutex_lock(&gi->lock);
+ gi->bcd_webusb_version = bcdVersion;
+ mutex_unlock(&gi->lock);
+
+ return len;
+}
+
+static ssize_t webusb_bVendorCode_show(struct config_item *item, char *page)
+{
+ return sysfs_emit(page, "0x%02x\n",
+ webusb_item_to_gadget_info(item)->b_webusb_vendor_code);
+}
+
+static ssize_t webusb_bVendorCode_store(struct config_item *item,
+ const char *page, size_t len)
+{
+ struct gadget_info *gi = webusb_item_to_gadget_info(item);
+ int ret;
+ u8 b_vendor_code;
+
+ ret = kstrtou8(page, 0, &b_vendor_code);
+ if (ret)
+ return ret;
+
+ mutex_lock(&gi->lock);
+ gi->b_webusb_vendor_code = b_vendor_code;
+ mutex_unlock(&gi->lock);
+
+ return len;
+}
+
+static ssize_t webusb_landingPage_show(struct config_item *item, char *page)
+{
+ return sysfs_emit(page, "%s\n", webusb_item_to_gadget_info(item)->landing_page);
+}
+
+static ssize_t webusb_landingPage_store(struct config_item *item, const char *page,
+ size_t len)
+{
+ struct gadget_info *gi = webusb_item_to_gadget_info(item);
+ unsigned int bytes_to_strip = 0;
+ int l = len;
+
+ if (page[l - 1] == '\n') {
+ --l;
+ ++bytes_to_strip;
+ }
+
+ if (l > sizeof(gi->landing_page)) {
+ pr_err("webusb: landingPage URL too long\n");
+ return -EINVAL;
+ }
+
+ // validation
+ if (strncasecmp(page, "https://", 8) == 0)
+ bytes_to_strip = 8;
+ else if (strncasecmp(page, "http://", 7) == 0)
+ bytes_to_strip = 7;
+ else
+ bytes_to_strip = 0;
+
+ if (l > U8_MAX - WEBUSB_URL_DESCRIPTOR_HEADER_LENGTH + bytes_to_strip) {
+ pr_err("webusb: landingPage URL %d bytes too long for given URL scheme\n",
+ l - U8_MAX + WEBUSB_URL_DESCRIPTOR_HEADER_LENGTH - bytes_to_strip);
+ return -EINVAL;
+ }
+
+ mutex_lock(&gi->lock);
+ // ensure 0 bytes are set, in case the new landing page is shorter then the old one.
+ memcpy_and_pad(gi->landing_page, sizeof(gi->landing_page), page, l, 0);
+ mutex_unlock(&gi->lock);
+
+ return len;
+}
+
+CONFIGFS_ATTR(webusb_, use);
+CONFIGFS_ATTR(webusb_, bVendorCode);
+CONFIGFS_ATTR(webusb_, bcdVersion);
+CONFIGFS_ATTR(webusb_, landingPage);
+
+static struct configfs_attribute *webusb_attrs[] = {
+ &webusb_attr_use,
+ &webusb_attr_bcdVersion,
+ &webusb_attr_bVendorCode,
+ &webusb_attr_landingPage,
+ NULL,
+};
+
+static struct config_item_type webusb_type = {
+ .ct_attrs = webusb_attrs,
+ .ct_owner = THIS_MODULE,
+};
static inline struct gadget_info *os_desc_item_to_gadget_info(
struct config_item *item)
@@ -801,15 +1125,15 @@ static ssize_t os_desc_use_store(struct config_item *item, const char *page,
int ret;
bool use;
- mutex_lock(&gi->lock);
ret = kstrtobool(page, &use);
- if (!ret) {
- gi->use_os_desc = use;
- ret = len;
- }
+ if (ret)
+ return ret;
+
+ mutex_lock(&gi->lock);
+ gi->use_os_desc = use;
mutex_unlock(&gi->lock);
- return ret;
+ return len;
}
static ssize_t os_desc_b_vendor_code_show(struct config_item *item, char *page)
@@ -825,15 +1149,15 @@ static ssize_t os_desc_b_vendor_code_store(struct config_item *item,
int ret;
u8 b_vendor_code;
- mutex_lock(&gi->lock);
ret = kstrtou8(page, 0, &b_vendor_code);
- if (!ret) {
- gi->b_vendor_code = b_vendor_code;
- ret = len;
- }
+ if (ret)
+ return ret;
+
+ mutex_lock(&gi->lock);
+ gi->b_vendor_code = b_vendor_code;
mutex_unlock(&gi->lock);
- return ret;
+ return len;
}
static ssize_t os_desc_qw_sign_show(struct config_item *item, char *page)
@@ -958,15 +1282,15 @@ static ssize_t ext_prop_type_store(struct config_item *item,
u8 type;
int ret;
- if (desc->opts_mutex)
- mutex_lock(desc->opts_mutex);
ret = kstrtou8(page, 0, &type);
if (ret)
- goto end;
- if (type < USB_EXT_PROP_UNICODE || type > USB_EXT_PROP_UNICODE_MULTI) {
- ret = -EINVAL;
- goto end;
- }
+ return ret;
+
+ if (type < USB_EXT_PROP_UNICODE || type > USB_EXT_PROP_UNICODE_MULTI)
+ return -EINVAL;
+
+ if (desc->opts_mutex)
+ mutex_lock(desc->opts_mutex);
if ((ext_prop->type == USB_EXT_PROP_BINARY ||
ext_prop->type == USB_EXT_PROP_LE32 ||
@@ -983,12 +1307,10 @@ static ssize_t ext_prop_type_store(struct config_item *item,
type == USB_EXT_PROP_BE32))
ext_prop->data_len >>= 1;
ext_prop->type = type;
- ret = len;
-end:
if (desc->opts_mutex)
mutex_unlock(desc->opts_mutex);
- return ret;
+ return len;
}
static ssize_t ext_prop_data_show(struct config_item *item, char *page)
@@ -1273,6 +1595,80 @@ static void purge_configs_funcs(struct gadget_info *gi)
}
}
+static struct usb_string *
+configfs_attach_gadget_strings(struct gadget_info *gi)
+{
+ struct usb_gadget_strings **gadget_strings;
+ struct gadget_language *language;
+ struct gadget_string *string;
+ unsigned int nlangs = 0;
+ struct list_head *iter;
+ struct usb_string *us;
+ unsigned int i = 0;
+ int nstrings = -1;
+ unsigned int j;
+
+ list_for_each(iter, &gi->string_list)
+ nlangs++;
+
+ /* Bail out early if no languages are configured */
+ if (!nlangs)
+ return NULL;
+
+ gadget_strings = kcalloc(nlangs + 1, /* including NULL terminator */
+ sizeof(struct usb_gadget_strings *), GFP_KERNEL);
+ if (!gadget_strings)
+ return ERR_PTR(-ENOMEM);
+
+ list_for_each_entry(language, &gi->string_list, list) {
+ struct usb_string *stringtab;
+
+ if (nstrings == -1) {
+ nstrings = language->nstrings;
+ } else if (nstrings != language->nstrings) {
+ pr_err("languages must contain the same number of strings\n");
+ us = ERR_PTR(-EINVAL);
+ goto cleanup;
+ }
+
+ stringtab = kcalloc(language->nstrings + 1, sizeof(struct usb_string),
+ GFP_KERNEL);
+ if (!stringtab) {
+ us = ERR_PTR(-ENOMEM);
+ goto cleanup;
+ }
+
+ stringtab[USB_GADGET_MANUFACTURER_IDX].id = USB_GADGET_MANUFACTURER_IDX;
+ stringtab[USB_GADGET_MANUFACTURER_IDX].s = language->manufacturer;
+ stringtab[USB_GADGET_PRODUCT_IDX].id = USB_GADGET_PRODUCT_IDX;
+ stringtab[USB_GADGET_PRODUCT_IDX].s = language->product;
+ stringtab[USB_GADGET_SERIAL_IDX].id = USB_GADGET_SERIAL_IDX;
+ stringtab[USB_GADGET_SERIAL_IDX].s = language->serialnumber;
+
+ j = USB_GADGET_FIRST_AVAIL_IDX;
+ list_for_each_entry(string, &language->gadget_strings, list) {
+ memcpy(&stringtab[j], &string->usb_string, sizeof(struct usb_string));
+ j++;
+ }
+
+ language->stringtab_dev.strings = stringtab;
+ gadget_strings[i] = &language->stringtab_dev;
+ i++;
+ }
+
+ us = usb_gstrings_attach(&gi->cdev, gadget_strings, nstrings);
+
+cleanup:
+ list_for_each_entry(language, &gi->string_list, list) {
+ kfree(language->stringtab_dev.strings);
+ language->stringtab_dev.strings = NULL;
+ }
+
+ kfree(gadget_strings);
+
+ return us;
+}
+
static int configfs_composite_bind(struct usb_gadget *gadget,
struct usb_gadget_driver *gdriver)
{
@@ -1316,22 +1712,7 @@ static int configfs_composite_bind(struct usb_gadget *gadget,
/* init all strings */
if (!list_empty(&gi->string_list)) {
- struct gadget_strings *gs;
-
- i = 0;
- list_for_each_entry(gs, &gi->string_list, list) {
-
- gi->gstrings[i] = &gs->stringtab_dev;
- gs->stringtab_dev.strings = gs->strings;
- gs->strings[USB_GADGET_MANUFACTURER_IDX].s =
- gs->manufacturer;
- gs->strings[USB_GADGET_PRODUCT_IDX].s = gs->product;
- gs->strings[USB_GADGET_SERIAL_IDX].s = gs->serialnumber;
- i++;
- }
- gi->gstrings[i] = NULL;
- s = usb_gstrings_attach(&gi->cdev, gi->gstrings,
- USB_GADGET_FIRST_AVAIL_IDX);
+ s = configfs_attach_gadget_strings(gi);
if (IS_ERR(s)) {
ret = PTR_ERR(s);
goto err_comp_cleanup;
@@ -1340,6 +1721,15 @@ static int configfs_composite_bind(struct usb_gadget *gadget,
gi->cdev.desc.iManufacturer = s[USB_GADGET_MANUFACTURER_IDX].id;
gi->cdev.desc.iProduct = s[USB_GADGET_PRODUCT_IDX].id;
gi->cdev.desc.iSerialNumber = s[USB_GADGET_SERIAL_IDX].id;
+
+ gi->cdev.usb_strings = s;
+ }
+
+ if (gi->use_webusb) {
+ cdev->use_webusb = true;
+ cdev->bcd_webusb_version = gi->bcd_webusb_version;
+ cdev->b_webusb_vendor_code = gi->b_webusb_vendor_code;
+ memcpy(cdev->landing_page, gi->landing_page, WEBUSB_URL_RAW_MAX_LENGTH);
}
if (gi->use_os_desc) {
@@ -1598,13 +1988,17 @@ static struct config_group *gadgets_make(
configfs_add_default_group(&gi->configs_group, &gi->group);
config_group_init_type_name(&gi->strings_group, "strings",
- &gadget_strings_strings_type);
+ &gadget_language_strings_type);
configfs_add_default_group(&gi->strings_group, &gi->group);
config_group_init_type_name(&gi->os_desc_group, "os_desc",
&os_desc_type);
configfs_add_default_group(&gi->os_desc_group, &gi->group);
+ config_group_init_type_name(&gi->webusb_group, "webusb",
+ &webusb_type);
+ configfs_add_default_group(&gi->webusb_group, &gi->group);
+
gi->composite.bind = configfs_do_nothing;
gi->composite.unbind = configfs_do_nothing;
gi->composite.suspend = NULL;
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index 8ad354741380..ddfc537c7526 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -830,8 +830,7 @@ static void ffs_user_copy_worker(struct work_struct *work)
{
struct ffs_io_data *io_data = container_of(work, struct ffs_io_data,
work);
- int ret = io_data->req->status ? io_data->req->status :
- io_data->req->actual;
+ int ret = io_data->status;
bool kiocb_has_eventfd = io_data->kiocb->ki_flags & IOCB_EVENTFD;
if (io_data->read && ret > 0) {
@@ -845,8 +844,6 @@ static void ffs_user_copy_worker(struct work_struct *work)
if (io_data->ffs->ffs_eventfd && !kiocb_has_eventfd)
eventfd_signal(io_data->ffs->ffs_eventfd, 1);
- usb_ep_free_request(io_data->ep, io_data->req);
-
if (io_data->read)
kfree(io_data->to_free);
ffs_free_buffer(io_data);
@@ -861,6 +858,9 @@ static void ffs_epfile_async_io_complete(struct usb_ep *_ep,
ENTER();
+ io_data->status = req->status ? req->status : req->actual;
+ usb_ep_free_request(_ep, req);
+
INIT_WORK(&io_data->work, ffs_user_copy_worker);
queue_work(ffs->io_completion_wq, &io_data->work);
}
diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
index 32f2c1645467..5e919fb65833 100644
--- a/drivers/usb/gadget/function/f_uvc.c
+++ b/drivers/usb/gadget/function/f_uvc.c
@@ -76,14 +76,14 @@ static struct usb_interface_descriptor uvc_control_intf = {
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = UVC_INTF_VIDEO_CONTROL,
.bAlternateSetting = 0,
- .bNumEndpoints = 1,
+ .bNumEndpoints = 0,
.bInterfaceClass = USB_CLASS_VIDEO,
.bInterfaceSubClass = UVC_SC_VIDEOCONTROL,
.bInterfaceProtocol = 0x00,
.iInterface = 0,
};
-static struct usb_endpoint_descriptor uvc_control_ep = {
+static struct usb_endpoint_descriptor uvc_interrupt_ep = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN,
@@ -92,8 +92,8 @@ static struct usb_endpoint_descriptor uvc_control_ep = {
.bInterval = 8,
};
-static struct usb_ss_ep_comp_descriptor uvc_ss_control_comp = {
- .bLength = sizeof(uvc_ss_control_comp),
+static struct usb_ss_ep_comp_descriptor uvc_ss_interrupt_comp = {
+ .bLength = sizeof(uvc_ss_interrupt_comp),
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
/* The following 3 values can be tweaked if necessary. */
.bMaxBurst = 0,
@@ -101,7 +101,7 @@ static struct usb_ss_ep_comp_descriptor uvc_ss_control_comp = {
.wBytesPerInterval = cpu_to_le16(UVC_STATUS_MAX_PACKET_SIZE),
};
-static struct uvc_control_endpoint_descriptor uvc_control_cs_ep = {
+static struct uvc_control_endpoint_descriptor uvc_interrupt_cs_ep = {
.bLength = UVC_DT_CONTROL_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_CS_ENDPOINT,
.bDescriptorSubType = UVC_EP_INTERRUPT,
@@ -300,14 +300,17 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
if (alt)
return -EINVAL;
- uvcg_info(f, "reset UVC Control\n");
- usb_ep_disable(uvc->control_ep);
+ if (uvc->enable_interrupt_ep) {
+ uvcg_info(f, "reset UVC interrupt endpoint\n");
+ usb_ep_disable(uvc->interrupt_ep);
- if (!uvc->control_ep->desc)
- if (config_ep_by_speed(cdev->gadget, f, uvc->control_ep))
- return -EINVAL;
+ if (!uvc->interrupt_ep->desc)
+ if (config_ep_by_speed(cdev->gadget, f,
+ uvc->interrupt_ep))
+ return -EINVAL;
- usb_ep_enable(uvc->control_ep);
+ usb_ep_enable(uvc->interrupt_ep);
+ }
if (uvc->state == UVC_STATE_DISCONNECTED) {
memset(&v4l2_event, 0, sizeof(v4l2_event));
@@ -385,7 +388,8 @@ uvc_function_disable(struct usb_function *f)
uvc->state = UVC_STATE_DISCONNECTED;
usb_ep_disable(uvc->video.ep);
- usb_ep_disable(uvc->control_ep);
+ if (uvc->enable_interrupt_ep)
+ usb_ep_disable(uvc->interrupt_ep);
}
/* --------------------------------------------------------------------------
@@ -474,6 +478,25 @@ uvc_register_video(struct uvc_device *uvc)
} \
} while (0)
+#define UVC_COPY_XU_DESCRIPTOR(mem, dst, desc) \
+ do { \
+ *(dst)++ = mem; \
+ memcpy(mem, desc, 22); /* bLength to bNrInPins */ \
+ mem += 22; \
+ \
+ memcpy(mem, (desc)->baSourceID, (desc)->bNrInPins); \
+ mem += (desc)->bNrInPins; \
+ \
+ memcpy(mem, &(desc)->bControlSize, 1); \
+ mem++; \
+ \
+ memcpy(mem, (desc)->bmControls, (desc)->bControlSize); \
+ mem += (desc)->bControlSize; \
+ \
+ memcpy(mem, &(desc)->iExtension, 1); \
+ mem++; \
+ } while (0)
+
static struct usb_descriptor_header **
uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
{
@@ -485,6 +508,7 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
const struct usb_descriptor_header * const *src;
struct usb_descriptor_header **dst;
struct usb_descriptor_header **hdr;
+ struct uvcg_extension *xu;
unsigned int control_size;
unsigned int streaming_size;
unsigned int n_desc;
@@ -521,9 +545,9 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
* uvc_iad
* uvc_control_intf
* Class-specific UVC control descriptors
- * uvc_control_ep
- * uvc_control_cs_ep
- * uvc_ss_control_comp (for SS only)
+ * uvc_interrupt_ep
+ * uvc_interrupt_cs_ep
+ * uvc_ss_interrupt_comp (for SS only)
* uvc_streaming_intf_alt0
* Class-specific UVC streaming descriptors
* uvc_{fs|hs}_streaming
@@ -533,14 +557,17 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
control_size = 0;
streaming_size = 0;
bytes = uvc_iad.bLength + uvc_control_intf.bLength
- + uvc_control_ep.bLength + uvc_control_cs_ep.bLength
+ uvc_streaming_intf_alt0.bLength;
- if (speed == USB_SPEED_SUPER) {
- bytes += uvc_ss_control_comp.bLength;
- n_desc = 6;
- } else {
- n_desc = 5;
+ n_desc = 3;
+ if (uvc->enable_interrupt_ep) {
+ bytes += uvc_interrupt_ep.bLength + uvc_interrupt_cs_ep.bLength;
+ n_desc += 2;
+
+ if (speed == USB_SPEED_SUPER) {
+ bytes += uvc_ss_interrupt_comp.bLength;
+ n_desc += 1;
+ }
}
for (src = (const struct usb_descriptor_header **)uvc_control_desc;
@@ -549,6 +576,13 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
bytes += (*src)->bLength;
n_desc++;
}
+
+ list_for_each_entry(xu, uvc->desc.extension_units, list) {
+ control_size += xu->desc.bLength;
+ bytes += xu->desc.bLength;
+ n_desc++;
+ }
+
for (src = (const struct usb_descriptor_header **)uvc_streaming_cls;
*src; ++src) {
streaming_size += (*src)->bLength;
@@ -575,15 +609,22 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
uvc_control_header = mem;
UVC_COPY_DESCRIPTORS(mem, dst,
(const struct usb_descriptor_header **)uvc_control_desc);
+
+ list_for_each_entry(xu, uvc->desc.extension_units, list)
+ UVC_COPY_XU_DESCRIPTOR(mem, dst, &xu->desc);
+
uvc_control_header->wTotalLength = cpu_to_le16(control_size);
uvc_control_header->bInCollection = 1;
uvc_control_header->baInterfaceNr[0] = uvc->streaming_intf;
- UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_ep);
- if (speed == USB_SPEED_SUPER)
- UVC_COPY_DESCRIPTOR(mem, dst, &uvc_ss_control_comp);
+ if (uvc->enable_interrupt_ep) {
+ UVC_COPY_DESCRIPTOR(mem, dst, &uvc_interrupt_ep);
+ if (speed == USB_SPEED_SUPER)
+ UVC_COPY_DESCRIPTOR(mem, dst, &uvc_ss_interrupt_comp);
+
+ UVC_COPY_DESCRIPTOR(mem, dst, &uvc_interrupt_cs_ep);
+ }
- UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_cs_ep);
UVC_COPY_DESCRIPTOR(mem, dst, &uvc_streaming_intf_alt0);
uvc_streaming_header = mem;
@@ -603,6 +644,7 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
{
struct usb_composite_dev *cdev = c->cdev;
struct uvc_device *uvc = to_uvc(f);
+ struct uvcg_extension *xu;
struct usb_string *us;
unsigned int max_packet_mult;
unsigned int max_packet_size;
@@ -666,12 +708,16 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
(opts->streaming_maxburst + 1));
/* Allocate endpoints. */
- ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep);
- if (!ep) {
- uvcg_info(f, "Unable to allocate control EP\n");
- goto error;
+ if (opts->enable_interrupt_ep) {
+ ep = usb_ep_autoconfig(cdev->gadget, &uvc_interrupt_ep);
+ if (!ep) {
+ uvcg_info(f, "Unable to allocate interrupt EP\n");
+ goto error;
+ }
+ uvc->interrupt_ep = ep;
+ uvc_control_intf.bNumEndpoints = 1;
}
- uvc->control_ep = ep;
+ uvc->enable_interrupt_ep = opts->enable_interrupt_ep;
if (gadget_is_superspeed(c->cdev->gadget))
ep = usb_ep_autoconfig_ss(cdev->gadget, &uvc_ss_streaming_ep,
@@ -691,6 +737,18 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
uvc_hs_streaming_ep.bEndpointAddress = uvc->video.ep->address;
uvc_ss_streaming_ep.bEndpointAddress = uvc->video.ep->address;
+ /*
+ * XUs can have an arbitrary string descriptor describing them. If they
+ * have one pick up the ID.
+ */
+ list_for_each_entry(xu, &opts->extension_units, list)
+ if (xu->string_descriptor_index)
+ xu->desc.iExtension = cdev->usb_strings[xu->string_descriptor_index].id;
+
+ /*
+ * We attach the hard-coded defaults incase the user does not provide
+ * any more appropriate strings through configfs.
+ */
uvc_en_us_strings[UVC_STRING_CONTROL_IDX].s = opts->function_name;
us = usb_gstrings_attach(cdev, uvc_function_strings,
ARRAY_SIZE(uvc_en_us_strings));
@@ -698,11 +756,15 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
ret = PTR_ERR(us);
goto error;
}
- uvc_iad.iFunction = us[UVC_STRING_CONTROL_IDX].id;
- uvc_control_intf.iInterface = us[UVC_STRING_CONTROL_IDX].id;
- ret = us[UVC_STRING_STREAMING_IDX].id;
- uvc_streaming_intf_alt0.iInterface = ret;
- uvc_streaming_intf_alt1.iInterface = ret;
+
+ uvc_iad.iFunction = opts->iad_index ? cdev->usb_strings[opts->iad_index].id :
+ us[UVC_STRING_CONTROL_IDX].id;
+ uvc_streaming_intf_alt0.iInterface = opts->vs0_index ?
+ cdev->usb_strings[opts->vs0_index].id :
+ us[UVC_STRING_STREAMING_IDX].id;
+ uvc_streaming_intf_alt1.iInterface = opts->vs1_index ?
+ cdev->usb_strings[opts->vs1_index].id :
+ us[UVC_STRING_STREAMING_IDX].id;
/* Allocate interface IDs. */
if ((ret = usb_interface_id(c, f)) < 0)
@@ -803,7 +865,6 @@ static struct usb_function_instance *uvc_alloc_inst(void)
struct uvc_camera_terminal_descriptor *cd;
struct uvc_processing_unit_descriptor *pd;
struct uvc_output_terminal_descriptor *od;
- struct uvc_color_matching_descriptor *md;
struct uvc_descriptor_header **ctl_cls;
int ret;
@@ -852,13 +913,12 @@ static struct usb_function_instance *uvc_alloc_inst(void)
od->bSourceID = 2;
od->iTerminal = 0;
- md = &opts->uvc_color_matching;
- md->bLength = UVC_DT_COLOR_MATCHING_SIZE;
- md->bDescriptorType = USB_DT_CS_INTERFACE;
- md->bDescriptorSubType = UVC_VS_COLORFORMAT;
- md->bColorPrimaries = 1;
- md->bTransferCharacteristics = 1;
- md->bMatrixCoefficients = 4;
+ /*
+ * With the ability to add XUs to the UVC function graph, we need to be
+ * able to allocate unique unit IDs to them. The IDs are 1-based, with
+ * the CT, PU and OT above consuming the first 3.
+ */
+ opts->last_unit_id = 3;
/* Prepare fs control class descriptors for configfs-based gadgets */
ctl_cls = opts->uvc_fs_control_cls;
@@ -880,6 +940,8 @@ static struct usb_function_instance *uvc_alloc_inst(void)
opts->ss_control =
(const struct uvc_descriptor_header * const *)ctl_cls;
+ INIT_LIST_HEAD(&opts->extension_units);
+
opts->streaming_interval = 1;
opts->streaming_maxpacket = 1024;
snprintf(opts->function_name, sizeof(opts->function_name), "UVC Camera");
@@ -1011,6 +1073,8 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi)
return ERR_PTR(-EBUSY);
}
+ uvc->desc.extension_units = &opts->extension_units;
+
++opts->refcnt;
mutex_unlock(&opts->lock);
diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c
index e06022873df1..f259975dfba4 100644
--- a/drivers/usb/gadget/function/u_ether.c
+++ b/drivers/usb/gadget/function/u_ether.c
@@ -17,6 +17,7 @@
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
+#include <linux/usb/composite.h>
#include "u_ether.h"
@@ -103,41 +104,6 @@ static inline int qlen(struct usb_gadget *gadget, unsigned qmult)
/*-------------------------------------------------------------------------*/
-/* REVISIT there must be a better way than having two sets
- * of debug calls ...
- */
-
-#undef DBG
-#undef VDBG
-#undef ERROR
-#undef INFO
-
-#define xprintk(d, level, fmt, args...) \
- printk(level "%s: " fmt , (d)->net->name , ## args)
-
-#ifdef DEBUG
-#undef DEBUG
-#define DBG(dev, fmt, args...) \
- xprintk(dev , KERN_DEBUG , fmt , ## args)
-#else
-#define DBG(dev, fmt, args...) \
- do { } while (0)
-#endif /* DEBUG */
-
-#ifdef VERBOSE_DEBUG
-#define VDBG DBG
-#else
-#define VDBG(dev, fmt, args...) \
- do { } while (0)
-#endif /* DEBUG */
-
-#define ERROR(dev, fmt, args...) \
- xprintk(dev , KERN_ERR , fmt , ## args)
-#define INFO(dev, fmt, args...) \
- xprintk(dev , KERN_INFO , fmt , ## args)
-
-/*-------------------------------------------------------------------------*/
-
/* NETWORK DRIVER HOOKUP (to the layer above this driver) */
static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p)
@@ -846,13 +812,11 @@ struct net_device *gether_setup_name_default(const char *netname)
snprintf(net->name, sizeof(net->name), "%s%%d", netname);
eth_random_addr(dev->dev_mac);
- pr_warn("using random %s ethernet address\n", "self");
/* by default we always have a random MAC address */
net->addr_assign_type = NET_ADDR_RANDOM;
eth_random_addr(dev->host_mac);
- pr_warn("using random %s ethernet address\n", "host");
net->netdev_ops = &eth_netdev_ops;
diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c
index 840626e064e1..a0ca47fbff0f 100644
--- a/drivers/usb/gadget/function/u_serial.c
+++ b/drivers/usb/gadget/function/u_serial.c
@@ -82,6 +82,9 @@
#define WRITE_BUF_SIZE 8192 /* TX only */
#define GS_CONSOLE_BUF_SIZE 8192
+/* Prevents race conditions while accessing gser->ioport */
+static DEFINE_SPINLOCK(serial_port_lock);
+
/* console info */
struct gs_console {
struct console console;
@@ -1375,8 +1378,10 @@ void gserial_disconnect(struct gserial *gser)
if (!port)
return;
+ spin_lock_irqsave(&serial_port_lock, flags);
+
/* tell the TTY glue not to do I/O here any more */
- spin_lock_irqsave(&port->port_lock, flags);
+ spin_lock(&port->port_lock);
gs_console_disconnect(port);
@@ -1391,7 +1396,8 @@ void gserial_disconnect(struct gserial *gser)
tty_hangup(port->port.tty);
}
port->suspended = false;
- spin_unlock_irqrestore(&port->port_lock, flags);
+ spin_unlock(&port->port_lock);
+ spin_unlock_irqrestore(&serial_port_lock, flags);
/* disable endpoints, aborting down any active I/O */
usb_ep_disable(gser->out);
@@ -1425,10 +1431,19 @@ EXPORT_SYMBOL_GPL(gserial_suspend);
void gserial_resume(struct gserial *gser)
{
- struct gs_port *port = gser->ioport;
+ struct gs_port *port;
unsigned long flags;
- spin_lock_irqsave(&port->port_lock, flags);
+ spin_lock_irqsave(&serial_port_lock, flags);
+ port = gser->ioport;
+
+ if (!port) {
+ spin_unlock_irqrestore(&serial_port_lock, flags);
+ return;
+ }
+
+ spin_lock(&port->port_lock);
+ spin_unlock(&serial_port_lock);
port->suspended = false;
if (!port->start_delayed) {
spin_unlock_irqrestore(&port->port_lock, flags);
diff --git a/drivers/usb/gadget/function/u_uvc.h b/drivers/usb/gadget/function/u_uvc.h
index 24b8681b0d6f..1ce58f61253c 100644
--- a/drivers/usb/gadget/function/u_uvc.h
+++ b/drivers/usb/gadget/function/u_uvc.h
@@ -28,6 +28,9 @@ struct f_uvc_opts {
unsigned int control_interface;
unsigned int streaming_interface;
char function_name[32];
+ unsigned int last_unit_id;
+
+ bool enable_interrupt_ep;
/*
* Control descriptors array pointers for full-/high-speed and
@@ -52,7 +55,6 @@ struct f_uvc_opts {
struct uvc_camera_terminal_descriptor uvc_camera_terminal;
struct uvc_processing_unit_descriptor uvc_processing;
struct uvc_output_terminal_descriptor uvc_output_terminal;
- struct uvc_color_matching_descriptor uvc_color_matching;
/*
* Control descriptors pointers arrays for full-/high-speed and
@@ -65,6 +67,12 @@ struct f_uvc_opts {
struct uvc_descriptor_header *uvc_ss_control_cls[5];
/*
+ * Control descriptors for extension units. There could be any number
+ * of these, including none at all.
+ */
+ struct list_head extension_units;
+
+ /*
* Streaming descriptors for full-speed, high-speed and super-speed.
* Used by configfs only, must not be touched by legacy gadgets. The
* arrays are allocated at runtime as the number of descriptors isn't
@@ -75,6 +83,14 @@ struct f_uvc_opts {
struct uvc_descriptor_header **uvc_ss_streaming_cls;
/*
+ * Indexes into the function's string descriptors allowing users to set
+ * custom descriptions rather than the hard-coded defaults.
+ */
+ u8 iad_index;
+ u8 vs0_index;
+ u8 vs1_index;
+
+ /*
* Read/write access to configfs attributes is handled by configfs.
*
* This lock protects the descriptors from concurrent access by
diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h
index 40226b1f7e14..100475b1363e 100644
--- a/drivers/usb/gadget/function/uvc.h
+++ b/drivers/usb/gadget/function/uvc.h
@@ -143,12 +143,14 @@ struct uvc_device {
const struct uvc_descriptor_header * const *fs_streaming;
const struct uvc_descriptor_header * const *hs_streaming;
const struct uvc_descriptor_header * const *ss_streaming;
+ struct list_head *extension_units;
} desc;
unsigned int control_intf;
- struct usb_ep *control_ep;
+ struct usb_ep *interrupt_ep;
struct usb_request *control_req;
void *control_buf;
+ bool enable_interrupt_ep;
unsigned int streaming_intf;
diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c
index 76cb60d13049..62b759bb7613 100644
--- a/drivers/usb/gadget/function/uvc_configfs.c
+++ b/drivers/usb/gadget/function/uvc_configfs.c
@@ -13,6 +13,7 @@
#include "uvc_configfs.h"
#include <linux/sort.h>
+#include <linux/usb/video.h>
/* -----------------------------------------------------------------------------
* Global Utility Structures and Macros
@@ -46,6 +47,71 @@ static int uvcg_config_compare_u32(const void *l, const void *r)
return li < ri ? -1 : li == ri ? 0 : 1;
}
+static inline int __uvcg_count_item_entries(char *buf, void *priv, unsigned int size)
+{
+ ++*((int *)priv);
+ return 0;
+}
+
+static inline int __uvcg_fill_item_entries(char *buf, void *priv, unsigned int size)
+{
+ unsigned int num;
+ u8 **values;
+ int ret;
+
+ ret = kstrtouint(buf, 0, &num);
+ if (ret)
+ return ret;
+
+ if (num != (num & GENMASK((size * 8) - 1, 0)))
+ return -ERANGE;
+
+ values = priv;
+ memcpy(*values, &num, size);
+ *values += size;
+
+ return 0;
+}
+
+static int __uvcg_iter_item_entries(const char *page, size_t len,
+ int (*fun)(char *, void *, unsigned int),
+ void *priv, unsigned int size)
+{
+ /* sign, base 2 representation, newline, terminator */
+ unsigned int bufsize = 1 + size * 8 + 1 + 1;
+ const char *pg = page;
+ int i, ret = 0;
+ char *buf;
+
+ if (!fun)
+ return -EINVAL;
+
+ buf = kzalloc(bufsize, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ while (pg - page < len) {
+ i = 0;
+ while (i < sizeof(buf) && (pg - page < len) &&
+ *pg != '\0' && *pg != '\n')
+ buf[i++] = *pg++;
+ if (i == sizeof(buf)) {
+ ret = -EINVAL;
+ goto out_free_buf;
+ }
+ while ((pg - page < len) && (*pg == '\0' || *pg == '\n'))
+ ++pg;
+ buf[i] = '\0';
+ ret = fun(buf, priv, size);
+ if (ret)
+ goto out_free_buf;
+ }
+
+out_free_buf:
+ kfree(buf);
+ return ret;
+}
+
struct uvcg_config_group_type {
struct config_item_type type;
const char *name;
@@ -483,11 +549,68 @@ UVC_ATTR_RO(uvcg_default_output_, cname, aname)
UVCG_DEFAULT_OUTPUT_ATTR(b_terminal_id, bTerminalID, 8);
UVCG_DEFAULT_OUTPUT_ATTR(w_terminal_type, wTerminalType, 16);
UVCG_DEFAULT_OUTPUT_ATTR(b_assoc_terminal, bAssocTerminal, 8);
-UVCG_DEFAULT_OUTPUT_ATTR(b_source_id, bSourceID, 8);
UVCG_DEFAULT_OUTPUT_ATTR(i_terminal, iTerminal, 8);
#undef UVCG_DEFAULT_OUTPUT_ATTR
+static ssize_t uvcg_default_output_b_source_id_show(struct config_item *item,
+ char *page)
+{
+ struct config_group *group = to_config_group(item);
+ struct f_uvc_opts *opts;
+ struct config_item *opts_item;
+ struct mutex *su_mutex = &group->cg_subsys->su_mutex;
+ struct uvc_output_terminal_descriptor *cd;
+ int result;
+
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+ opts_item = group->cg_item.ci_parent->ci_parent->
+ ci_parent->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+ cd = &opts->uvc_output_terminal;
+
+ mutex_lock(&opts->lock);
+ result = sprintf(page, "%u\n", le8_to_cpu(cd->bSourceID));
+ mutex_unlock(&opts->lock);
+
+ mutex_unlock(su_mutex);
+
+ return result;
+}
+
+static ssize_t uvcg_default_output_b_source_id_store(struct config_item *item,
+ const char *page, size_t len)
+{
+ struct config_group *group = to_config_group(item);
+ struct f_uvc_opts *opts;
+ struct config_item *opts_item;
+ struct mutex *su_mutex = &group->cg_subsys->su_mutex;
+ struct uvc_output_terminal_descriptor *cd;
+ int result;
+ u8 num;
+
+ result = kstrtou8(page, 0, &num);
+ if (result)
+ return result;
+
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+ opts_item = group->cg_item.ci_parent->ci_parent->
+ ci_parent->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+ cd = &opts->uvc_output_terminal;
+
+ mutex_lock(&opts->lock);
+ cd->bSourceID = num;
+ mutex_unlock(&opts->lock);
+
+ mutex_unlock(su_mutex);
+
+ return len;
+}
+UVC_ATTR(uvcg_default_output_, b_source_id, bSourceID);
+
static struct configfs_attribute *uvcg_default_output_attrs[] = {
&uvcg_default_output_attr_b_terminal_id,
&uvcg_default_output_attr_w_terminal_type,
@@ -540,6 +663,537 @@ static const struct uvcg_config_group_type uvcg_terminal_grp_type = {
};
/* -----------------------------------------------------------------------------
+ * control/extensions
+ */
+
+#define UVCG_EXTENSION_ATTR(cname, aname, ro...) \
+static ssize_t uvcg_extension_##cname##_show(struct config_item *item, \
+ char *page) \
+{ \
+ struct config_group *group = to_config_group(item->ci_parent); \
+ struct mutex *su_mutex = &group->cg_subsys->su_mutex; \
+ struct uvcg_extension *xu = to_uvcg_extension(item); \
+ struct config_item *opts_item; \
+ struct f_uvc_opts *opts; \
+ int ret; \
+ \
+ mutex_lock(su_mutex); \
+ \
+ opts_item = item->ci_parent->ci_parent->ci_parent; \
+ opts = to_f_uvc_opts(opts_item); \
+ \
+ mutex_lock(&opts->lock); \
+ ret = sprintf(page, "%u\n", xu->desc.aname); \
+ mutex_unlock(&opts->lock); \
+ \
+ mutex_unlock(su_mutex); \
+ \
+ return ret; \
+} \
+UVC_ATTR##ro(uvcg_extension_, cname, aname)
+
+UVCG_EXTENSION_ATTR(b_length, bLength, _RO);
+UVCG_EXTENSION_ATTR(b_unit_id, bUnitID, _RO);
+UVCG_EXTENSION_ATTR(i_extension, iExtension, _RO);
+
+static ssize_t uvcg_extension_b_num_controls_store(struct config_item *item,
+ const char *page, size_t len)
+{
+ struct config_group *group = to_config_group(item->ci_parent);
+ struct mutex *su_mutex = &group->cg_subsys->su_mutex;
+ struct uvcg_extension *xu = to_uvcg_extension(item);
+ struct config_item *opts_item;
+ struct f_uvc_opts *opts;
+ int ret;
+ u8 num;
+
+ ret = kstrtou8(page, 0, &num);
+ if (ret)
+ return ret;
+
+ mutex_lock(su_mutex);
+
+ opts_item = item->ci_parent->ci_parent->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+
+ mutex_lock(&opts->lock);
+ xu->desc.bNumControls = num;
+ mutex_unlock(&opts->lock);
+
+ mutex_unlock(su_mutex);
+
+ return len;
+}
+UVCG_EXTENSION_ATTR(b_num_controls, bNumControls);
+
+/*
+ * In addition to storing bNrInPins, this function needs to realloc the
+ * memory for the baSourceID array and additionally expand bLength.
+ */
+static ssize_t uvcg_extension_b_nr_in_pins_store(struct config_item *item,
+ const char *page, size_t len)
+{
+ struct config_group *group = to_config_group(item->ci_parent);
+ struct mutex *su_mutex = &group->cg_subsys->su_mutex;
+ struct uvcg_extension *xu = to_uvcg_extension(item);
+ struct config_item *opts_item;
+ struct f_uvc_opts *opts;
+ void *tmp_buf;
+ int ret;
+ u8 num;
+
+ ret = kstrtou8(page, 0, &num);
+ if (ret)
+ return ret;
+
+ mutex_lock(su_mutex);
+
+ opts_item = item->ci_parent->ci_parent->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+
+ mutex_lock(&opts->lock);
+
+ if (num == xu->desc.bNrInPins) {
+ ret = len;
+ goto unlock;
+ }
+
+ tmp_buf = krealloc_array(xu->desc.baSourceID, num, sizeof(u8),
+ GFP_KERNEL | __GFP_ZERO);
+ if (!tmp_buf) {
+ ret = -ENOMEM;
+ goto unlock;
+ }
+
+ xu->desc.baSourceID = tmp_buf;
+ xu->desc.bNrInPins = num;
+ xu->desc.bLength = UVC_DT_EXTENSION_UNIT_SIZE(xu->desc.bNrInPins,
+ xu->desc.bControlSize);
+
+ ret = len;
+
+unlock:
+ mutex_unlock(&opts->lock);
+ mutex_unlock(su_mutex);
+ return ret;
+}
+UVCG_EXTENSION_ATTR(b_nr_in_pins, bNrInPins);
+
+/*
+ * In addition to storing bControlSize, this function needs to realloc the
+ * memory for the bmControls array and additionally expand bLength.
+ */
+static ssize_t uvcg_extension_b_control_size_store(struct config_item *item,
+ const char *page, size_t len)
+{
+ struct config_group *group = to_config_group(item->ci_parent);
+ struct mutex *su_mutex = &group->cg_subsys->su_mutex;
+ struct uvcg_extension *xu = to_uvcg_extension(item);
+ struct config_item *opts_item;
+ struct f_uvc_opts *opts;
+ void *tmp_buf;
+ int ret;
+ u8 num;
+
+ ret = kstrtou8(page, 0, &num);
+ if (ret)
+ return ret;
+
+ mutex_lock(su_mutex);
+
+ opts_item = item->ci_parent->ci_parent->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+
+ mutex_lock(&opts->lock);
+
+ if (num == xu->desc.bControlSize) {
+ ret = len;
+ goto unlock;
+ }
+
+ tmp_buf = krealloc_array(xu->desc.bmControls, num, sizeof(u8),
+ GFP_KERNEL | __GFP_ZERO);
+ if (!tmp_buf) {
+ ret = -ENOMEM;
+ goto unlock;
+ }
+
+ xu->desc.bmControls = tmp_buf;
+ xu->desc.bControlSize = num;
+ xu->desc.bLength = UVC_DT_EXTENSION_UNIT_SIZE(xu->desc.bNrInPins,
+ xu->desc.bControlSize);
+
+ ret = len;
+
+unlock:
+ mutex_unlock(&opts->lock);
+ mutex_unlock(su_mutex);
+ return ret;
+}
+
+UVCG_EXTENSION_ATTR(b_control_size, bControlSize);
+
+static ssize_t uvcg_extension_guid_extension_code_show(struct config_item *item,
+ char *page)
+{
+ struct config_group *group = to_config_group(item->ci_parent);
+ struct mutex *su_mutex = &group->cg_subsys->su_mutex;
+ struct uvcg_extension *xu = to_uvcg_extension(item);
+ struct config_item *opts_item;
+ struct f_uvc_opts *opts;
+
+ mutex_lock(su_mutex);
+
+ opts_item = item->ci_parent->ci_parent->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+
+ mutex_lock(&opts->lock);
+ memcpy(page, xu->desc.guidExtensionCode, sizeof(xu->desc.guidExtensionCode));
+ mutex_unlock(&opts->lock);
+
+ mutex_unlock(su_mutex);
+
+ return sizeof(xu->desc.guidExtensionCode);
+}
+
+static ssize_t uvcg_extension_guid_extension_code_store(struct config_item *item,
+ const char *page, size_t len)
+{
+ struct config_group *group = to_config_group(item->ci_parent);
+ struct mutex *su_mutex = &group->cg_subsys->su_mutex;
+ struct uvcg_extension *xu = to_uvcg_extension(item);
+ struct config_item *opts_item;
+ struct f_uvc_opts *opts;
+ int ret;
+
+ mutex_lock(su_mutex);
+
+ opts_item = item->ci_parent->ci_parent->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+
+ mutex_lock(&opts->lock);
+ memcpy(xu->desc.guidExtensionCode, page,
+ min(sizeof(xu->desc.guidExtensionCode), len));
+ mutex_unlock(&opts->lock);
+
+ mutex_unlock(su_mutex);
+
+ ret = sizeof(xu->desc.guidExtensionCode);
+
+ return ret;
+}
+
+UVC_ATTR(uvcg_extension_, guid_extension_code, guidExtensionCode);
+
+static ssize_t uvcg_extension_ba_source_id_show(struct config_item *item,
+ char *page)
+{
+ struct config_group *group = to_config_group(item->ci_parent);
+ struct mutex *su_mutex = &group->cg_subsys->su_mutex;
+ struct uvcg_extension *xu = to_uvcg_extension(item);
+ struct config_item *opts_item;
+ struct f_uvc_opts *opts;
+ char *pg = page;
+ int ret, i;
+
+ mutex_lock(su_mutex);
+
+ opts_item = item->ci_parent->ci_parent->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+
+ mutex_lock(&opts->lock);
+ for (ret = 0, i = 0; i < xu->desc.bNrInPins; ++i) {
+ ret += sprintf(pg, "%u\n", xu->desc.baSourceID[i]);
+ pg = page + ret;
+ }
+ mutex_unlock(&opts->lock);
+
+ mutex_unlock(su_mutex);
+
+ return ret;
+}
+
+static ssize_t uvcg_extension_ba_source_id_store(struct config_item *item,
+ const char *page, size_t len)
+{
+ struct config_group *group = to_config_group(item->ci_parent);
+ struct mutex *su_mutex = &group->cg_subsys->su_mutex;
+ struct uvcg_extension *xu = to_uvcg_extension(item);
+ struct config_item *opts_item;
+ struct f_uvc_opts *opts;
+ u8 *source_ids, *iter;
+ int ret, n = 0;
+
+ mutex_lock(su_mutex);
+
+ opts_item = item->ci_parent->ci_parent->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+
+ mutex_lock(&opts->lock);
+
+ ret = __uvcg_iter_item_entries(page, len, __uvcg_count_item_entries, &n,
+ sizeof(u8));
+ if (ret)
+ goto unlock;
+
+ iter = source_ids = kcalloc(n, sizeof(u8), GFP_KERNEL);
+ if (!source_ids) {
+ ret = -ENOMEM;
+ goto unlock;
+ }
+
+ ret = __uvcg_iter_item_entries(page, len, __uvcg_fill_item_entries, &iter,
+ sizeof(u8));
+ if (ret) {
+ kfree(source_ids);
+ goto unlock;
+ }
+
+ kfree(xu->desc.baSourceID);
+ xu->desc.baSourceID = source_ids;
+ xu->desc.bNrInPins = n;
+ xu->desc.bLength = UVC_DT_EXTENSION_UNIT_SIZE(xu->desc.bNrInPins,
+ xu->desc.bControlSize);
+
+ ret = len;
+
+unlock:
+ mutex_unlock(&opts->lock);
+ mutex_unlock(su_mutex);
+ return ret;
+}
+UVC_ATTR(uvcg_extension_, ba_source_id, baSourceID);
+
+static ssize_t uvcg_extension_bm_controls_show(struct config_item *item,
+ char *page)
+{
+ struct config_group *group = to_config_group(item->ci_parent);
+ struct mutex *su_mutex = &group->cg_subsys->su_mutex;
+ struct uvcg_extension *xu = to_uvcg_extension(item);
+ struct config_item *opts_item;
+ struct f_uvc_opts *opts;
+ char *pg = page;
+ int ret, i;
+
+ mutex_lock(su_mutex);
+
+ opts_item = item->ci_parent->ci_parent->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+
+ mutex_lock(&opts->lock);
+ for (ret = 0, i = 0; i < xu->desc.bControlSize; ++i) {
+ ret += sprintf(pg, "0x%02x\n", xu->desc.bmControls[i]);
+ pg = page + ret;
+ }
+ mutex_unlock(&opts->lock);
+
+ mutex_unlock(su_mutex);
+
+ return ret;
+}
+
+static ssize_t uvcg_extension_bm_controls_store(struct config_item *item,
+ const char *page, size_t len)
+{
+ struct config_group *group = to_config_group(item->ci_parent);
+ struct mutex *su_mutex = &group->cg_subsys->su_mutex;
+ struct uvcg_extension *xu = to_uvcg_extension(item);
+ struct config_item *opts_item;
+ struct f_uvc_opts *opts;
+ u8 *bm_controls, *iter;
+ int ret, n = 0;
+
+ mutex_lock(su_mutex);
+
+ opts_item = item->ci_parent->ci_parent->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+
+ mutex_lock(&opts->lock);
+
+ ret = __uvcg_iter_item_entries(page, len, __uvcg_count_item_entries, &n,
+ sizeof(u8));
+ if (ret)
+ goto unlock;
+
+ iter = bm_controls = kcalloc(n, sizeof(u8), GFP_KERNEL);
+ if (!bm_controls) {
+ ret = -ENOMEM;
+ goto unlock;
+ }
+
+ ret = __uvcg_iter_item_entries(page, len, __uvcg_fill_item_entries, &iter,
+ sizeof(u8));
+ if (ret) {
+ kfree(bm_controls);
+ goto unlock;
+ }
+
+ kfree(xu->desc.bmControls);
+ xu->desc.bmControls = bm_controls;
+ xu->desc.bControlSize = n;
+ xu->desc.bLength = UVC_DT_EXTENSION_UNIT_SIZE(xu->desc.bNrInPins,
+ xu->desc.bControlSize);
+
+ ret = len;
+
+unlock:
+ mutex_unlock(&opts->lock);
+ mutex_unlock(su_mutex);
+ return ret;
+}
+
+UVC_ATTR(uvcg_extension_, bm_controls, bmControls);
+
+static struct configfs_attribute *uvcg_extension_attrs[] = {
+ &uvcg_extension_attr_b_length,
+ &uvcg_extension_attr_b_unit_id,
+ &uvcg_extension_attr_b_num_controls,
+ &uvcg_extension_attr_b_nr_in_pins,
+ &uvcg_extension_attr_b_control_size,
+ &uvcg_extension_attr_guid_extension_code,
+ &uvcg_extension_attr_ba_source_id,
+ &uvcg_extension_attr_bm_controls,
+ &uvcg_extension_attr_i_extension,
+ NULL,
+};
+
+static void uvcg_extension_release(struct config_item *item)
+{
+ struct uvcg_extension *xu = container_of(item, struct uvcg_extension, item);
+
+ kfree(xu);
+}
+
+static int uvcg_extension_allow_link(struct config_item *src, struct config_item *tgt)
+{
+ struct mutex *su_mutex = &src->ci_group->cg_subsys->su_mutex;
+ struct uvcg_extension *xu = to_uvcg_extension(src);
+ struct config_item *gadget_item;
+ struct gadget_string *string;
+ struct config_item *strings;
+ int ret = 0;
+
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+ /* Validate that the target of the link is an entry in strings/<langid> */
+ gadget_item = src->ci_parent->ci_parent->ci_parent->ci_parent->ci_parent;
+ strings = config_group_find_item(to_config_group(gadget_item), "strings");
+ if (!strings || tgt->ci_parent->ci_parent != strings) {
+ ret = -EINVAL;
+ goto put_strings;
+ }
+
+ string = to_gadget_string(tgt);
+ xu->string_descriptor_index = string->usb_string.id;
+
+put_strings:
+ config_item_put(strings);
+ mutex_unlock(su_mutex);
+
+ return ret;
+}
+
+static void uvcg_extension_drop_link(struct config_item *src, struct config_item *tgt)
+{
+ struct mutex *su_mutex = &src->ci_group->cg_subsys->su_mutex;
+ struct uvcg_extension *xu = to_uvcg_extension(src);
+ struct config_item *opts_item;
+ struct f_uvc_opts *opts;
+
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+ opts_item = src->ci_parent->ci_parent->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+
+ mutex_lock(&opts->lock);
+
+ xu->string_descriptor_index = 0;
+
+ mutex_unlock(&opts->lock);
+
+ mutex_unlock(su_mutex);
+}
+
+static struct configfs_item_operations uvcg_extension_item_ops = {
+ .release = uvcg_extension_release,
+ .allow_link = uvcg_extension_allow_link,
+ .drop_link = uvcg_extension_drop_link,
+};
+
+static const struct config_item_type uvcg_extension_type = {
+ .ct_item_ops = &uvcg_extension_item_ops,
+ .ct_attrs = uvcg_extension_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+static void uvcg_extension_drop(struct config_group *group, struct config_item *item)
+{
+ struct uvcg_extension *xu = container_of(item, struct uvcg_extension, item);
+ struct config_item *opts_item;
+ struct f_uvc_opts *opts;
+
+ opts_item = group->cg_item.ci_parent->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+
+ mutex_lock(&opts->lock);
+
+ config_item_put(item);
+ list_del(&xu->list);
+ kfree(xu->desc.baSourceID);
+ kfree(xu->desc.bmControls);
+
+ mutex_unlock(&opts->lock);
+}
+
+static struct config_item *uvcg_extension_make(struct config_group *group, const char *name)
+{
+ struct config_item *opts_item;
+ struct uvcg_extension *xu;
+ struct f_uvc_opts *opts;
+
+ opts_item = group->cg_item.ci_parent->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+
+ xu = kzalloc(sizeof(*xu), GFP_KERNEL);
+ if (!xu)
+ return ERR_PTR(-ENOMEM);
+
+ xu->desc.bLength = UVC_DT_EXTENSION_UNIT_SIZE(0, 0);
+ xu->desc.bDescriptorType = USB_DT_CS_INTERFACE;
+ xu->desc.bDescriptorSubType = UVC_VC_EXTENSION_UNIT;
+ xu->desc.bNumControls = 0;
+ xu->desc.bNrInPins = 0;
+ xu->desc.baSourceID = NULL;
+ xu->desc.bControlSize = 0;
+ xu->desc.bmControls = NULL;
+
+ mutex_lock(&opts->lock);
+
+ xu->desc.bUnitID = ++opts->last_unit_id;
+
+ config_item_init_type_name(&xu->item, name, &uvcg_extension_type);
+ list_add_tail(&xu->list, &opts->extension_units);
+
+ mutex_unlock(&opts->lock);
+
+ return &xu->item;
+}
+
+static struct configfs_group_operations uvcg_extensions_grp_ops = {
+ .make_item = uvcg_extension_make,
+ .drop_item = uvcg_extension_drop,
+};
+
+static const struct uvcg_config_group_type uvcg_extensions_grp_type = {
+ .type = {
+ .ct_item_ops = &uvcg_config_item_ops,
+ .ct_group_ops = &uvcg_extensions_grp_ops,
+ .ct_owner = THIS_MODULE,
+ },
+ .name = "extensions",
+};
+
+/* -----------------------------------------------------------------------------
* control/class/{fs|ss}
*/
@@ -716,8 +1370,61 @@ static ssize_t uvcg_default_control_b_interface_number_show(
UVC_ATTR_RO(uvcg_default_control_, b_interface_number, bInterfaceNumber);
+static ssize_t uvcg_default_control_enable_interrupt_ep_show(
+ struct config_item *item, char *page)
+{
+ struct config_group *group = to_config_group(item);
+ struct mutex *su_mutex = &group->cg_subsys->su_mutex;
+ struct config_item *opts_item;
+ struct f_uvc_opts *opts;
+ int result = 0;
+
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+ opts_item = item->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+
+ mutex_lock(&opts->lock);
+ result += sprintf(page, "%u\n", opts->enable_interrupt_ep);
+ mutex_unlock(&opts->lock);
+
+ mutex_unlock(su_mutex);
+
+ return result;
+}
+
+static ssize_t uvcg_default_control_enable_interrupt_ep_store(
+ struct config_item *item, const char *page, size_t len)
+{
+ struct config_group *group = to_config_group(item);
+ struct mutex *su_mutex = &group->cg_subsys->su_mutex;
+ struct config_item *opts_item;
+ struct f_uvc_opts *opts;
+ ssize_t ret;
+ u8 num;
+
+ ret = kstrtou8(page, 0, &num);
+ if (ret)
+ return ret;
+
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+ opts_item = item->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+
+ mutex_lock(&opts->lock);
+ opts->enable_interrupt_ep = num;
+ mutex_unlock(&opts->lock);
+
+ mutex_unlock(su_mutex);
+
+ return len;
+}
+UVC_ATTR(uvcg_default_control_, enable_interrupt_ep, enable_interrupt_ep);
+
static struct configfs_attribute *uvcg_default_control_attrs[] = {
&uvcg_default_control_attr_b_interface_number,
+ &uvcg_default_control_attr_enable_interrupt_ep,
NULL,
};
@@ -733,6 +1440,7 @@ static const struct uvcg_config_group_type uvcg_control_grp_type = {
&uvcg_processing_grp_type,
&uvcg_terminal_grp_type,
&uvcg_control_class_grp_type,
+ &uvcg_extensions_grp_type,
NULL,
},
};
@@ -747,6 +1455,100 @@ static const char * const uvcg_format_names[] = {
"mjpeg",
};
+static struct uvcg_color_matching *
+uvcg_format_get_default_color_match(struct config_item *streaming)
+{
+ struct config_item *color_matching_item, *cm_default;
+ struct uvcg_color_matching *color_match;
+
+ color_matching_item = config_group_find_item(to_config_group(streaming),
+ "color_matching");
+ if (!color_matching_item)
+ return NULL;
+
+ cm_default = config_group_find_item(to_config_group(color_matching_item),
+ "default");
+ config_item_put(color_matching_item);
+ if (!cm_default)
+ return NULL;
+
+ color_match = to_uvcg_color_matching(to_config_group(cm_default));
+ config_item_put(cm_default);
+
+ return color_match;
+}
+
+static int uvcg_format_allow_link(struct config_item *src, struct config_item *tgt)
+{
+ struct mutex *su_mutex = &src->ci_group->cg_subsys->su_mutex;
+ struct uvcg_color_matching *color_matching_desc;
+ struct config_item *streaming, *color_matching;
+ struct uvcg_format *fmt;
+ int ret = 0;
+
+ mutex_lock(su_mutex);
+
+ streaming = src->ci_parent->ci_parent;
+ color_matching = config_group_find_item(to_config_group(streaming), "color_matching");
+ if (!color_matching || color_matching != tgt->ci_parent) {
+ ret = -EINVAL;
+ goto out_put_cm;
+ }
+
+ fmt = to_uvcg_format(src);
+
+ /*
+ * There's always a color matching descriptor associated with the format
+ * but without a symlink it should only ever be the default one. If it's
+ * not the default, there's already a symlink and we should bail out.
+ */
+ color_matching_desc = uvcg_format_get_default_color_match(streaming);
+ if (fmt->color_matching != color_matching_desc) {
+ ret = -EBUSY;
+ goto out_put_cm;
+ }
+
+ color_matching_desc->refcnt--;
+
+ color_matching_desc = to_uvcg_color_matching(to_config_group(tgt));
+ fmt->color_matching = color_matching_desc;
+ color_matching_desc->refcnt++;
+
+out_put_cm:
+ config_item_put(color_matching);
+ mutex_unlock(su_mutex);
+
+ return ret;
+}
+
+static void uvcg_format_drop_link(struct config_item *src, struct config_item *tgt)
+{
+ struct mutex *su_mutex = &src->ci_group->cg_subsys->su_mutex;
+ struct uvcg_color_matching *color_matching_desc;
+ struct config_item *streaming;
+ struct uvcg_format *fmt;
+
+ mutex_lock(su_mutex);
+
+ color_matching_desc = to_uvcg_color_matching(to_config_group(tgt));
+ color_matching_desc->refcnt--;
+
+ streaming = src->ci_parent->ci_parent;
+ color_matching_desc = uvcg_format_get_default_color_match(streaming);
+
+ fmt = to_uvcg_format(src);
+ fmt->color_matching = color_matching_desc;
+ color_matching_desc->refcnt++;
+
+ mutex_unlock(su_mutex);
+}
+
+static struct configfs_item_operations uvcg_format_item_operations = {
+ .release = uvcg_config_item_release,
+ .allow_link = uvcg_format_allow_link,
+ .drop_link = uvcg_format_drop_link,
+};
+
static ssize_t uvcg_format_bma_controls_show(struct uvcg_format *f, char *page)
{
struct f_uvc_opts *opts;
@@ -1131,57 +1933,6 @@ static ssize_t uvcg_frame_dw_frame_interval_show(struct config_item *item,
return result;
}
-static inline int __uvcg_count_frm_intrv(char *buf, void *priv)
-{
- ++*((int *)priv);
- return 0;
-}
-
-static inline int __uvcg_fill_frm_intrv(char *buf, void *priv)
-{
- u32 num, **interv;
- int ret;
-
- ret = kstrtou32(buf, 0, &num);
- if (ret)
- return ret;
-
- interv = priv;
- **interv = num;
- ++*interv;
-
- return 0;
-}
-
-static int __uvcg_iter_frm_intrv(const char *page, size_t len,
- int (*fun)(char *, void *), void *priv)
-{
- /* sign, base 2 representation, newline, terminator */
- char buf[1 + sizeof(u32) * 8 + 1 + 1];
- const char *pg = page;
- int i, ret;
-
- if (!fun)
- return -EINVAL;
-
- while (pg - page < len) {
- i = 0;
- while (i < sizeof(buf) && (pg - page < len) &&
- *pg != '\0' && *pg != '\n')
- buf[i++] = *pg++;
- if (i == sizeof(buf))
- return -EINVAL;
- while ((pg - page < len) && (*pg == '\0' || *pg == '\n'))
- ++pg;
- buf[i] = '\0';
- ret = fun(buf, priv);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
static ssize_t uvcg_frame_dw_frame_interval_store(struct config_item *item,
const char *page, size_t len)
{
@@ -1205,7 +1956,7 @@ static ssize_t uvcg_frame_dw_frame_interval_store(struct config_item *item,
goto end;
}
- ret = __uvcg_iter_frm_intrv(page, len, __uvcg_count_frm_intrv, &n);
+ ret = __uvcg_iter_item_entries(page, len, __uvcg_count_item_entries, &n, sizeof(u32));
if (ret)
goto end;
@@ -1215,7 +1966,7 @@ static ssize_t uvcg_frame_dw_frame_interval_store(struct config_item *item,
goto end;
}
- ret = __uvcg_iter_frm_intrv(page, len, __uvcg_fill_frm_intrv, &tmp);
+ ret = __uvcg_iter_item_entries(page, len, __uvcg_fill_item_entries, &tmp, sizeof(u32));
if (ret) {
kfree(frm_intrv);
goto end;
@@ -1547,7 +2298,7 @@ static struct configfs_attribute *uvcg_uncompressed_attrs[] = {
};
static const struct config_item_type uvcg_uncompressed_type = {
- .ct_item_ops = &uvcg_config_item_ops,
+ .ct_item_ops = &uvcg_format_item_operations,
.ct_group_ops = &uvcg_uncompressed_group_ops,
.ct_attrs = uvcg_uncompressed_attrs,
.ct_owner = THIS_MODULE,
@@ -1560,8 +2311,15 @@ static struct config_group *uvcg_uncompressed_make(struct config_group *group,
'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00,
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
};
+ struct uvcg_color_matching *color_match;
+ struct config_item *streaming;
struct uvcg_uncompressed *h;
+ streaming = group->cg_item.ci_parent;
+ color_match = uvcg_format_get_default_color_match(streaming);
+ if (!color_match)
+ return ERR_PTR(-EINVAL);
+
h = kzalloc(sizeof(*h), GFP_KERNEL);
if (!h)
return ERR_PTR(-ENOMEM);
@@ -1579,6 +2337,8 @@ static struct config_group *uvcg_uncompressed_make(struct config_group *group,
INIT_LIST_HEAD(&h->fmt.frames);
h->fmt.type = UVCG_UNCOMPRESSED;
+ h->fmt.color_matching = color_match;
+ color_match->refcnt++;
config_group_init_type_name(&h->fmt.group, name,
&uvcg_uncompressed_type);
@@ -1734,7 +2494,7 @@ static struct configfs_attribute *uvcg_mjpeg_attrs[] = {
};
static const struct config_item_type uvcg_mjpeg_type = {
- .ct_item_ops = &uvcg_config_item_ops,
+ .ct_item_ops = &uvcg_format_item_operations,
.ct_group_ops = &uvcg_mjpeg_group_ops,
.ct_attrs = uvcg_mjpeg_attrs,
.ct_owner = THIS_MODULE,
@@ -1743,8 +2503,15 @@ static const struct config_item_type uvcg_mjpeg_type = {
static struct config_group *uvcg_mjpeg_make(struct config_group *group,
const char *name)
{
+ struct uvcg_color_matching *color_match;
+ struct config_item *streaming;
struct uvcg_mjpeg *h;
+ streaming = group->cg_item.ci_parent;
+ color_match = uvcg_format_get_default_color_match(streaming);
+ if (!color_match)
+ return ERR_PTR(-EINVAL);
+
h = kzalloc(sizeof(*h), GFP_KERNEL);
if (!h)
return ERR_PTR(-ENOMEM);
@@ -1760,6 +2527,8 @@ static struct config_group *uvcg_mjpeg_make(struct config_group *group,
INIT_LIST_HEAD(&h->fmt.frames);
h->fmt.type = UVCG_MJPEG;
+ h->fmt.color_matching = color_match;
+ color_match->refcnt++;
config_group_init_type_name(&h->fmt.group, name,
&uvcg_mjpeg_type);
@@ -1783,70 +2552,159 @@ static const struct uvcg_config_group_type uvcg_mjpeg_grp_type = {
* streaming/color_matching/default
*/
-#define UVCG_DEFAULT_COLOR_MATCHING_ATTR(cname, aname, bits) \
-static ssize_t uvcg_default_color_matching_##cname##_show( \
+#define UVCG_COLOR_MATCHING_ATTR(cname, aname, bits) \
+static ssize_t uvcg_color_matching_##cname##_show( \
struct config_item *item, char *page) \
{ \
struct config_group *group = to_config_group(item); \
+ struct uvcg_color_matching *color_match = \
+ to_uvcg_color_matching(group); \
struct f_uvc_opts *opts; \
struct config_item *opts_item; \
struct mutex *su_mutex = &group->cg_subsys->su_mutex; \
- struct uvc_color_matching_descriptor *cd; \
int result; \
\
mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
\
opts_item = group->cg_item.ci_parent->ci_parent->ci_parent; \
opts = to_f_uvc_opts(opts_item); \
- cd = &opts->uvc_color_matching; \
\
mutex_lock(&opts->lock); \
- result = sprintf(page, "%u\n", le##bits##_to_cpu(cd->aname)); \
+ result = sprintf(page, "%u\n", \
+ le##bits##_to_cpu(color_match->desc.aname)); \
mutex_unlock(&opts->lock); \
\
mutex_unlock(su_mutex); \
return result; \
} \
\
-UVC_ATTR_RO(uvcg_default_color_matching_, cname, aname)
+static ssize_t uvcg_color_matching_##cname##_store( \
+ struct config_item *item, const char *page, size_t len) \
+{ \
+ struct config_group *group = to_config_group(item); \
+ struct mutex *su_mutex = &group->cg_subsys->su_mutex; \
+ struct uvcg_color_matching *color_match = \
+ to_uvcg_color_matching(group); \
+ struct f_uvc_opts *opts; \
+ struct config_item *opts_item; \
+ int ret; \
+ u##bits num; \
+ \
+ ret = kstrtou##bits(page, 0, &num); \
+ if (ret) \
+ return ret; \
+ \
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
+ \
+ if (color_match->refcnt) { \
+ ret = -EBUSY; \
+ goto unlock_su; \
+ } \
+ \
+ opts_item = group->cg_item.ci_parent->ci_parent->ci_parent; \
+ opts = to_f_uvc_opts(opts_item); \
+ \
+ mutex_lock(&opts->lock); \
+ \
+ color_match->desc.aname = num; \
+ ret = len; \
+ \
+ mutex_unlock(&opts->lock); \
+unlock_su: \
+ mutex_unlock(su_mutex); \
+ \
+ return ret; \
+} \
+UVC_ATTR(uvcg_color_matching_, cname, aname)
-UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_color_primaries, bColorPrimaries, 8);
-UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_transfer_characteristics,
- bTransferCharacteristics, 8);
-UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_matrix_coefficients, bMatrixCoefficients, 8);
+UVCG_COLOR_MATCHING_ATTR(b_color_primaries, bColorPrimaries, 8);
+UVCG_COLOR_MATCHING_ATTR(b_transfer_characteristics, bTransferCharacteristics, 8);
+UVCG_COLOR_MATCHING_ATTR(b_matrix_coefficients, bMatrixCoefficients, 8);
-#undef UVCG_DEFAULT_COLOR_MATCHING_ATTR
+#undef UVCG_COLOR_MATCHING_ATTR
-static struct configfs_attribute *uvcg_default_color_matching_attrs[] = {
- &uvcg_default_color_matching_attr_b_color_primaries,
- &uvcg_default_color_matching_attr_b_transfer_characteristics,
- &uvcg_default_color_matching_attr_b_matrix_coefficients,
+static struct configfs_attribute *uvcg_color_matching_attrs[] = {
+ &uvcg_color_matching_attr_b_color_primaries,
+ &uvcg_color_matching_attr_b_transfer_characteristics,
+ &uvcg_color_matching_attr_b_matrix_coefficients,
NULL,
};
-static const struct uvcg_config_group_type uvcg_default_color_matching_type = {
- .type = {
- .ct_item_ops = &uvcg_config_item_ops,
- .ct_attrs = uvcg_default_color_matching_attrs,
- .ct_owner = THIS_MODULE,
- },
- .name = "default",
+static void uvcg_color_matching_release(struct config_item *item)
+{
+ struct uvcg_color_matching *color_match =
+ to_uvcg_color_matching(to_config_group(item));
+
+ kfree(color_match);
+}
+
+static struct configfs_item_operations uvcg_color_matching_item_ops = {
+ .release = uvcg_color_matching_release,
+};
+
+static const struct config_item_type uvcg_color_matching_type = {
+ .ct_item_ops = &uvcg_color_matching_item_ops,
+ .ct_attrs = uvcg_color_matching_attrs,
+ .ct_owner = THIS_MODULE,
};
/* -----------------------------------------------------------------------------
* streaming/color_matching
*/
+static struct config_group *uvcg_color_matching_make(struct config_group *group,
+ const char *name)
+{
+ struct uvcg_color_matching *color_match;
+
+ color_match = kzalloc(sizeof(*color_match), GFP_KERNEL);
+ if (!color_match)
+ return ERR_PTR(-ENOMEM);
+
+ color_match->desc.bLength = UVC_DT_COLOR_MATCHING_SIZE;
+ color_match->desc.bDescriptorType = USB_DT_CS_INTERFACE;
+ color_match->desc.bDescriptorSubType = UVC_VS_COLORFORMAT;
+
+ config_group_init_type_name(&color_match->group, name,
+ &uvcg_color_matching_type);
+
+ return &color_match->group;
+}
+
+static struct configfs_group_operations uvcg_color_matching_grp_group_ops = {
+ .make_group = uvcg_color_matching_make,
+};
+
+static int uvcg_color_matching_create_children(struct config_group *parent)
+{
+ struct uvcg_color_matching *color_match;
+
+ color_match = kzalloc(sizeof(*color_match), GFP_KERNEL);
+ if (!color_match)
+ return -ENOMEM;
+
+ color_match->desc.bLength = UVC_DT_COLOR_MATCHING_SIZE;
+ color_match->desc.bDescriptorType = USB_DT_CS_INTERFACE;
+ color_match->desc.bDescriptorSubType = UVC_VS_COLORFORMAT;
+ color_match->desc.bColorPrimaries = UVC_COLOR_PRIMARIES_BT_709_SRGB;
+ color_match->desc.bTransferCharacteristics = UVC_TRANSFER_CHARACTERISTICS_BT_709;
+ color_match->desc.bMatrixCoefficients = UVC_MATRIX_COEFFICIENTS_SMPTE_170M;
+
+ config_group_init_type_name(&color_match->group, "default",
+ &uvcg_color_matching_type);
+ configfs_add_default_group(&color_match->group, parent);
+
+ return 0;
+}
+
static const struct uvcg_config_group_type uvcg_color_matching_grp_type = {
.type = {
.ct_item_ops = &uvcg_config_item_ops,
+ .ct_group_ops = &uvcg_color_matching_grp_group_ops,
.ct_owner = THIS_MODULE,
},
.name = "color_matching",
- .children = (const struct uvcg_config_group_type*[]) {
- &uvcg_default_color_matching_type,
- NULL,
- },
+ .create_children = uvcg_color_matching_create_children,
};
/* -----------------------------------------------------------------------------
@@ -1880,7 +2738,8 @@ static inline struct uvc_descriptor_header
enum uvcg_strm_type {
UVCG_HEADER = 0,
UVCG_FORMAT,
- UVCG_FRAME
+ UVCG_FRAME,
+ UVCG_COLOR_MATCHING,
};
/*
@@ -1930,6 +2789,11 @@ static int __uvcg_iter_strm_cls(struct uvcg_streaming_header *h,
if (ret)
return ret;
}
+
+ ret = fun(f->fmt->color_matching, priv2, priv3, 0,
+ UVCG_COLOR_MATCHING);
+ if (ret)
+ return ret;
}
return ret;
@@ -1985,6 +2849,12 @@ static int __uvcg_cnt_strm(void *priv1, void *priv2, void *priv3, int n,
*size += frm->frame.b_frame_interval_type * sz;
}
break;
+ case UVCG_COLOR_MATCHING: {
+ struct uvcg_color_matching *color_match = priv1;
+
+ *size += sizeof(color_match->desc);
+ }
+ break;
}
++*count;
@@ -2070,6 +2940,13 @@ static int __uvcg_fill_strm(void *priv1, void *priv2, void *priv3, int n,
frm->frame.b_frame_interval_type);
}
break;
+ case UVCG_COLOR_MATCHING: {
+ struct uvcg_color_matching *color_match = priv1;
+
+ memcpy(*dest, &color_match->desc, sizeof(color_match->desc));
+ *dest += sizeof(color_match->desc);
+ }
+ break;
}
return 0;
@@ -2109,7 +2986,7 @@ static int uvcg_streaming_class_allow_link(struct config_item *src,
if (ret)
goto unlock;
- count += 2; /* color_matching, NULL */
+ count += 1; /* NULL */
*class_array = kcalloc(count, sizeof(void *), GFP_KERNEL);
if (!*class_array) {
ret = -ENOMEM;
@@ -2136,7 +3013,6 @@ static int uvcg_streaming_class_allow_link(struct config_item *src,
kfree(data_save);
goto unlock;
}
- *cl_arr = (struct uvc_descriptor_header *)&opts->uvc_color_matching;
++target_hdr->linked;
ret = 0;
@@ -2298,8 +3174,68 @@ static void uvc_func_item_release(struct config_item *item)
usb_put_function_instance(&opts->func_inst);
}
+static int uvc_func_allow_link(struct config_item *src, struct config_item *tgt)
+{
+ struct mutex *su_mutex = &src->ci_group->cg_subsys->su_mutex;
+ struct gadget_string *string;
+ struct config_item *strings;
+ struct f_uvc_opts *opts;
+ int ret = 0;
+
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+ /* Validate that the target is an entry in strings/<langid> */
+ strings = config_group_find_item(to_config_group(src->ci_parent->ci_parent),
+ "strings");
+ if (!strings || tgt->ci_parent->ci_parent != strings) {
+ ret = -EINVAL;
+ goto put_strings;
+ }
+
+ string = to_gadget_string(tgt);
+
+ opts = to_f_uvc_opts(src);
+ mutex_lock(&opts->lock);
+
+ if (!strcmp(tgt->ci_name, "iad_desc"))
+ opts->iad_index = string->usb_string.id;
+ else if (!strcmp(tgt->ci_name, "vs0_desc"))
+ opts->vs0_index = string->usb_string.id;
+ else if (!strcmp(tgt->ci_name, "vs1_desc"))
+ opts->vs1_index = string->usb_string.id;
+ else
+ ret = -EINVAL;
+
+ mutex_unlock(&opts->lock);
+
+put_strings:
+ config_item_put(strings);
+ mutex_unlock(su_mutex);
+
+ return ret;
+}
+
+static void uvc_func_drop_link(struct config_item *src, struct config_item *tgt)
+{
+ struct f_uvc_opts *opts;
+
+ opts = to_f_uvc_opts(src);
+ mutex_lock(&opts->lock);
+
+ if (!strcmp(tgt->ci_name, "iad_desc"))
+ opts->iad_index = 0;
+ else if (!strcmp(tgt->ci_name, "vs0_desc"))
+ opts->vs0_index = 0;
+ else if (!strcmp(tgt->ci_name, "vs1_desc"))
+ opts->vs1_index = 0;
+
+ mutex_unlock(&opts->lock);
+}
+
static struct configfs_item_operations uvc_func_item_ops = {
.release = uvc_func_item_release,
+ .allow_link = uvc_func_allow_link,
+ .drop_link = uvc_func_drop_link,
};
#define UVCG_OPTS_ATTR(cname, aname, limit) \
diff --git a/drivers/usb/gadget/function/uvc_configfs.h b/drivers/usb/gadget/function/uvc_configfs.h
index ad2ec8c4c78c..c6a690158138 100644
--- a/drivers/usb/gadget/function/uvc_configfs.h
+++ b/drivers/usb/gadget/function/uvc_configfs.h
@@ -37,18 +37,28 @@ static inline struct uvcg_control_header *to_uvcg_control_header(struct config_i
return container_of(item, struct uvcg_control_header, item);
}
+struct uvcg_color_matching {
+ struct config_group group;
+ struct uvc_color_matching_descriptor desc;
+ unsigned int refcnt;
+};
+
+#define to_uvcg_color_matching(group_ptr) \
+container_of(group_ptr, struct uvcg_color_matching, group)
+
enum uvcg_format_type {
UVCG_UNCOMPRESSED = 0,
UVCG_MJPEG,
};
struct uvcg_format {
- struct config_group group;
- enum uvcg_format_type type;
- unsigned linked;
- struct list_head frames;
- unsigned num_frames;
- __u8 bmaControls[UVCG_STREAMING_CONTROL_SIZE];
+ struct config_group group;
+ enum uvcg_format_type type;
+ unsigned linked;
+ struct list_head frames;
+ unsigned num_frames;
+ __u8 bmaControls[UVCG_STREAMING_CONTROL_SIZE];
+ struct uvcg_color_matching *color_matching;
};
struct uvcg_format_ptr {
@@ -132,6 +142,36 @@ static inline struct uvcg_mjpeg *to_uvcg_mjpeg(struct config_item *item)
return container_of(to_uvcg_format(item), struct uvcg_mjpeg, fmt);
}
+/* -----------------------------------------------------------------------------
+ * control/extensions/<NAME>
+ */
+
+struct uvcg_extension_unit_descriptor {
+ u8 bLength;
+ u8 bDescriptorType;
+ u8 bDescriptorSubType;
+ u8 bUnitID;
+ u8 guidExtensionCode[16];
+ u8 bNumControls;
+ u8 bNrInPins;
+ u8 *baSourceID;
+ u8 bControlSize;
+ u8 *bmControls;
+ u8 iExtension;
+} __packed;
+
+struct uvcg_extension {
+ struct config_item item;
+ struct list_head list;
+ u8 string_descriptor_index;
+ struct uvcg_extension_unit_descriptor desc;
+};
+
+static inline struct uvcg_extension *to_uvcg_extension(struct config_item *item)
+{
+ return container_of(item, struct uvcg_extension, item);
+}
+
int uvcg_attach_configfs(struct f_uvc_opts *opts);
#endif /* UVC_CONFIGFS_H */
diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c
index a189b08bba80..3f0a9795c0d4 100644
--- a/drivers/usb/gadget/function/uvc_v4l2.c
+++ b/drivers/usb/gadget/function/uvc_v4l2.c
@@ -11,6 +11,7 @@
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/usb/g_uvc.h>
+#include <linux/usb/uvc.h>
#include <linux/videodev2.h>
#include <linux/vmalloc.h>
#include <linux/wait.h>
@@ -18,7 +19,6 @@
#include <media/v4l2-dev.h>
#include <media/v4l2-event.h>
#include <media/v4l2-ioctl.h>
-#include <media/v4l2-uvc.h>
#include "f_uvc.h"
#include "uvc.h"
@@ -27,10 +27,10 @@
#include "uvc_v4l2.h"
#include "uvc_configfs.h"
-static struct uvc_format_desc *to_uvc_format(struct uvcg_format *uformat)
+static const struct uvc_format_desc *to_uvc_format(struct uvcg_format *uformat)
{
char guid[16] = UVC_GUID_FORMAT_MJPEG;
- struct uvc_format_desc *format;
+ const struct uvc_format_desc *format;
struct uvcg_uncompressed *unc;
if (uformat->type == UVCG_UNCOMPRESSED) {
@@ -119,7 +119,7 @@ static struct uvcg_format *find_format_by_pix(struct uvc_device *uvc,
struct uvcg_format *uformat = NULL;
list_for_each_entry(format, &uvc->header->formats, entry) {
- struct uvc_format_desc *fmtdesc = to_uvc_format(format->fmt);
+ const struct uvc_format_desc *fmtdesc = to_uvc_format(format->fmt);
if (fmtdesc->fcc == pixelformat) {
uformat = format->fmt;
@@ -364,7 +364,7 @@ uvc_v4l2_enum_format(struct file *file, void *fh, struct v4l2_fmtdesc *f)
{
struct video_device *vdev = video_devdata(file);
struct uvc_device *uvc = video_get_drvdata(vdev);
- struct uvc_format_desc *fmtdesc;
+ const struct uvc_format_desc *fmtdesc;
struct uvcg_format *uformat;
if (f->index >= uvc->header->num_fmt)
@@ -374,15 +374,9 @@ uvc_v4l2_enum_format(struct file *file, void *fh, struct v4l2_fmtdesc *f)
if (!uformat)
return -EINVAL;
- if (uformat->type != UVCG_UNCOMPRESSED)
- f->flags |= V4L2_FMT_FLAG_COMPRESSED;
-
fmtdesc = to_uvc_format(uformat);
f->pixelformat = fmtdesc->fcc;
- strscpy(f->description, fmtdesc->name, sizeof(f->description));
- f->description[strlen(fmtdesc->name) - 1] = 0;
-
return 0;
}
diff --git a/drivers/usb/gadget/legacy/hid.c b/drivers/usb/gadget/legacy/hid.c
index 1187ee4f316a..133daf88162e 100644
--- a/drivers/usb/gadget/legacy/hid.c
+++ b/drivers/usb/gadget/legacy/hid.c
@@ -133,14 +133,11 @@ static struct usb_configuration config_driver = {
static int hid_bind(struct usb_composite_dev *cdev)
{
struct usb_gadget *gadget = cdev->gadget;
- struct list_head *tmp;
struct hidg_func_node *n = NULL, *m, *iter_n;
struct f_hid_opts *hid_opts;
- int status, funcs = 0;
-
- list_for_each(tmp, &hidg_func_list)
- funcs++;
+ int status, funcs;
+ funcs = list_count_nodes(&hidg_func_list);
if (!funcs)
return -ENODEV;
diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig
index 511ab57cdc81..83cae6bb12eb 100644
--- a/drivers/usb/gadget/udc/Kconfig
+++ b/drivers/usb/gadget/udc/Kconfig
@@ -179,9 +179,20 @@ config USB_RENESAS_USBHS_UDC
dynamically linked module called "renesas_usbhs" and force all
gadget drivers to also be dynamically linked.
+config USB_RZV2M_USB3DRD
+ tristate 'Renesas USB3.1 DRD controller'
+ depends on ARCH_R9A09G011 || COMPILE_TEST
+ help
+ Renesas USB3.1 DRD controller is a USB DRD controller
+ that supports both host and device switching.
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "rzv2m_usb3drd".
+
config USB_RENESAS_USB3
tristate 'Renesas USB3.0 Peripheral controller'
depends on ARCH_RENESAS || COMPILE_TEST
+ depends on USB_RZV2M_USB3DRD || !USB_RZV2M_USB3DRD
depends on EXTCON
select USB_ROLE_SWITCH
help
@@ -192,6 +203,17 @@ config USB_RENESAS_USB3
dynamically linked module called "renesas_usb3" and force all
gadget drivers to also be dynamically linked.
+config USB_RENESAS_USBF
+ tristate 'Renesas USB Function controller'
+ depends on ARCH_RENESAS || COMPILE_TEST
+ help
+ Renesas USB Function controller is a USB peripheral controller
+ available on RZ/N1 Renesas SoCs.
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "renesas_usbf" and force all
+ gadget drivers to also be dynamically linked.
+
config USB_PXA27X
tristate "PXA 27x"
depends on HAS_IOMEM
diff --git a/drivers/usb/gadget/udc/Makefile b/drivers/usb/gadget/udc/Makefile
index 239ea22bdfd9..ee569f63c74a 100644
--- a/drivers/usb/gadget/udc/Makefile
+++ b/drivers/usb/gadget/udc/Makefile
@@ -26,6 +26,8 @@ obj-$(CONFIG_USB_TEGRA_XUDC) += tegra-xudc.o
obj-$(CONFIG_USB_M66592) += m66592-udc.o
obj-$(CONFIG_USB_R8A66597) += r8a66597-udc.o
obj-$(CONFIG_USB_RENESAS_USB3) += renesas_usb3.o
+obj-$(CONFIG_USB_RZV2M_USB3DRD) += rzv2m_usb3drd.o
+obj-$(CONFIG_USB_RENESAS_USBF) += renesas_usbf.o
obj-$(CONFIG_USB_FSL_QE) += fsl_qe_udc.o
obj-$(CONFIG_USB_LPC32XX) += lpc32xx_udc.o
obj-$(CONFIG_USB_EG20T) += pch_udc.o
diff --git a/drivers/usb/gadget/udc/bcm63xx_udc.c b/drivers/usb/gadget/udc/bcm63xx_udc.c
index d04d72f5816e..a3055dd4acfb 100644
--- a/drivers/usb/gadget/udc/bcm63xx_udc.c
+++ b/drivers/usb/gadget/udc/bcm63xx_udc.c
@@ -2171,7 +2171,6 @@ static int bcm63xx_iudma_dbg_show(struct seq_file *s, void *p)
for (ch_idx = 0; ch_idx < BCM63XX_NUM_IUDMA; ch_idx++) {
struct iudma_ch *iudma = &udc->iudma[ch_idx];
- struct list_head *pos;
seq_printf(s, "IUDMA channel %d -- ", ch_idx);
switch (iudma_defaults[ch_idx].ep_type) {
@@ -2204,14 +2203,10 @@ static int bcm63xx_iudma_dbg_show(struct seq_file *s, void *p)
seq_printf(s, " desc: %d/%d used", iudma->n_bds_used,
iudma->n_bds);
- if (iudma->bep) {
- i = 0;
- list_for_each(pos, &iudma->bep->queue)
- i++;
- seq_printf(s, "; %d queued\n", i);
- } else {
+ if (iudma->bep)
+ seq_printf(s, "; %zu queued\n", list_count_nodes(&iudma->bep->queue));
+ else
seq_printf(s, "\n");
- }
for (i = 0; i < iudma->n_bds; i++) {
struct bcm_enet_desc *d = &iudma->bd_ring[i];
@@ -2258,7 +2253,7 @@ static void bcm63xx_udc_init_debugfs(struct bcm63xx_udc *udc)
*/
static void bcm63xx_udc_cleanup_debugfs(struct bcm63xx_udc *udc)
{
- debugfs_remove(debugfs_lookup(udc->gadget.name, usb_debug_root));
+ debugfs_lookup_and_remove(udc->gadget.name, usb_debug_root);
}
/***********************************************************************
diff --git a/drivers/usb/gadget/udc/fusb300_udc.c b/drivers/usb/gadget/udc/fusb300_udc.c
index 5954800d652c..08ba9c8c1e67 100644
--- a/drivers/usb/gadget/udc/fusb300_udc.c
+++ b/drivers/usb/gadget/udc/fusb300_udc.c
@@ -1346,6 +1346,7 @@ static int fusb300_remove(struct platform_device *pdev)
usb_del_gadget_udc(&fusb300->gadget);
iounmap(fusb300->reg);
free_irq(platform_get_irq(pdev, 0), fusb300);
+ free_irq(platform_get_irq(pdev, 1), fusb300);
fusb300_free_request(&fusb300->ep[0]->ep, fusb300->ep0_req);
for (i = 0; i < FUSB300_MAX_NUM_EP; i++)
@@ -1431,7 +1432,7 @@ static int fusb300_probe(struct platform_device *pdev)
IRQF_SHARED, udc_name, fusb300);
if (ret < 0) {
pr_err("request_irq1 error (%d)\n", ret);
- goto clean_up;
+ goto err_request_irq1;
}
INIT_LIST_HEAD(&fusb300->gadget.ep_list);
@@ -1470,7 +1471,7 @@ static int fusb300_probe(struct platform_device *pdev)
GFP_KERNEL);
if (fusb300->ep0_req == NULL) {
ret = -ENOMEM;
- goto clean_up3;
+ goto err_alloc_request;
}
init_controller(fusb300);
@@ -1485,7 +1486,10 @@ static int fusb300_probe(struct platform_device *pdev)
err_add_udc:
fusb300_free_request(&fusb300->ep[0]->ep, fusb300->ep0_req);
-clean_up3:
+err_alloc_request:
+ free_irq(ires1->start, fusb300);
+
+err_request_irq1:
free_irq(ires->start, fusb300);
clean_up:
diff --git a/drivers/usb/gadget/udc/gr_udc.c b/drivers/usb/gadget/udc/gr_udc.c
index 85cdc0af3bf9..09762559912d 100644
--- a/drivers/usb/gadget/udc/gr_udc.c
+++ b/drivers/usb/gadget/udc/gr_udc.c
@@ -215,7 +215,7 @@ static void gr_dfs_create(struct gr_udc *dev)
static void gr_dfs_delete(struct gr_udc *dev)
{
- debugfs_remove(debugfs_lookup(dev_name(dev->dev), usb_debug_root));
+ debugfs_lookup_and_remove(dev_name(dev->dev), usb_debug_root);
}
#else /* !CONFIG_USB_GADGET_DEBUG_FS */
diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c
index cea10cdb83ae..fe62db32dd0e 100644
--- a/drivers/usb/gadget/udc/lpc32xx_udc.c
+++ b/drivers/usb/gadget/udc/lpc32xx_udc.c
@@ -532,7 +532,7 @@ static void create_debug_file(struct lpc32xx_udc *udc)
static void remove_debug_file(struct lpc32xx_udc *udc)
{
- debugfs_remove(debugfs_lookup(debug_filename, NULL));
+ debugfs_lookup_and_remove(debug_filename, NULL);
}
#else
diff --git a/drivers/usb/gadget/udc/pxa25x_udc.c b/drivers/usb/gadget/udc/pxa25x_udc.c
index e19b84a46a1e..df0551ecc810 100644
--- a/drivers/usb/gadget/udc/pxa25x_udc.c
+++ b/drivers/usb/gadget/udc/pxa25x_udc.c
@@ -1340,7 +1340,7 @@ DEFINE_SHOW_ATTRIBUTE(udc_debug);
debugfs_create_file(dev->gadget.name, \
S_IRUGO, NULL, dev, &udc_debug_fops); \
} while (0)
-#define remove_debug_files(dev) debugfs_remove(debugfs_lookup(dev->gadget.name, NULL))
+#define remove_debug_files(dev) debugfs_lookup_and_remove(dev->gadget.name, NULL)
#else /* !CONFIG_USB_GADGET_DEBUG_FILES */
diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c
index ac980d6a4740..0ecdfd2ba9e9 100644
--- a/drivers/usb/gadget/udc/pxa27x_udc.c
+++ b/drivers/usb/gadget/udc/pxa27x_udc.c
@@ -215,7 +215,7 @@ static void pxa_init_debugfs(struct pxa_udc *udc)
static void pxa_cleanup_debugfs(struct pxa_udc *udc)
{
- debugfs_remove(debugfs_lookup(udc->gadget.name, usb_debug_root));
+ debugfs_lookup_and_remove(udc->gadget.name, usb_debug_root);
}
#else
diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c
index 615ba0a6fbee..bee6bceafc4f 100644
--- a/drivers/usb/gadget/udc/renesas_usb3.c
+++ b/drivers/usb/gadget/udc/renesas_usb3.c
@@ -7,6 +7,7 @@
#include <linux/debugfs.h>
#include <linux/delay.h>
+#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/extcon-provider.h>
@@ -27,6 +28,7 @@
#include <linux/usb/gadget.h>
#include <linux/usb/of.h>
#include <linux/usb/role.h>
+#include <linux/usb/rzv2m_usb3drd.h>
/* register definitions */
#define USB3_AXI_INT_STA 0x008
@@ -334,7 +336,7 @@ struct renesas_usb3_priv {
struct renesas_usb3 {
void __iomem *reg;
- struct reset_control *drd_rstc;
+ void __iomem *drd_reg;
struct reset_control *usbp_rstc;
struct usb_gadget gadget;
@@ -426,6 +428,46 @@ static void usb3_clear_bit(struct renesas_usb3 *usb3, u32 bits, u32 offs)
usb3_write(usb3, val, offs);
}
+static void usb3_drd_write(struct renesas_usb3 *usb3, u32 data, u32 offs)
+{
+ void __iomem *reg;
+
+ if (usb3->is_rzv2m)
+ reg = usb3->drd_reg + offs - USB3_DRD_CON(usb3);
+ else
+ reg = usb3->reg + offs;
+
+ iowrite32(data, reg);
+}
+
+static u32 usb3_drd_read(struct renesas_usb3 *usb3, u32 offs)
+{
+ void __iomem *reg;
+
+ if (usb3->is_rzv2m)
+ reg = usb3->drd_reg + offs - USB3_DRD_CON(usb3);
+ else
+ reg = usb3->reg + offs;
+
+ return ioread32(reg);
+}
+
+static void usb3_drd_set_bit(struct renesas_usb3 *usb3, u32 bits, u32 offs)
+{
+ u32 val = usb3_drd_read(usb3, offs);
+
+ val |= bits;
+ usb3_drd_write(usb3, val, offs);
+}
+
+static void usb3_drd_clear_bit(struct renesas_usb3 *usb3, u32 bits, u32 offs)
+{
+ u32 val = usb3_drd_read(usb3, offs);
+
+ val &= ~bits;
+ usb3_drd_write(usb3, val, offs);
+}
+
static int usb3_wait(struct renesas_usb3 *usb3, u32 reg, u32 mask,
u32 expected)
{
@@ -474,7 +516,7 @@ static void usb3_disable_pipe_irq(struct renesas_usb3 *usb3, int num)
static bool usb3_is_host(struct renesas_usb3 *usb3)
{
- return !(usb3_read(usb3, USB3_DRD_CON(usb3)) & DRD_CON_PERI_CON);
+ return !(usb3_drd_read(usb3, USB3_DRD_CON(usb3)) & DRD_CON_PERI_CON);
}
static void usb3_init_axi_bridge(struct renesas_usb3 *usb3)
@@ -683,18 +725,18 @@ static void usb3_set_mode(struct renesas_usb3 *usb3, bool host)
{
if (usb3->is_rzv2m) {
if (host) {
- usb3_set_bit(usb3, DRD_CON_PERI_RST, USB3_DRD_CON(usb3));
- usb3_clear_bit(usb3, DRD_CON_HOST_RST, USB3_DRD_CON(usb3));
+ usb3_drd_set_bit(usb3, DRD_CON_PERI_RST, USB3_DRD_CON(usb3));
+ usb3_drd_clear_bit(usb3, DRD_CON_HOST_RST, USB3_DRD_CON(usb3));
} else {
- usb3_set_bit(usb3, DRD_CON_HOST_RST, USB3_DRD_CON(usb3));
- usb3_clear_bit(usb3, DRD_CON_PERI_RST, USB3_DRD_CON(usb3));
+ usb3_drd_set_bit(usb3, DRD_CON_HOST_RST, USB3_DRD_CON(usb3));
+ usb3_drd_clear_bit(usb3, DRD_CON_PERI_RST, USB3_DRD_CON(usb3));
}
}
if (host)
- usb3_clear_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON(usb3));
+ usb3_drd_clear_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON(usb3));
else
- usb3_set_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON(usb3));
+ usb3_drd_set_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON(usb3));
}
static void usb3_set_mode_by_role_sw(struct renesas_usb3 *usb3, bool host)
@@ -710,9 +752,9 @@ static void usb3_set_mode_by_role_sw(struct renesas_usb3 *usb3, bool host)
static void usb3_vbus_out(struct renesas_usb3 *usb3, bool enable)
{
if (enable)
- usb3_set_bit(usb3, DRD_CON_VBOUT, USB3_DRD_CON(usb3));
+ usb3_drd_set_bit(usb3, DRD_CON_VBOUT, USB3_DRD_CON(usb3));
else
- usb3_clear_bit(usb3, DRD_CON_VBOUT, USB3_DRD_CON(usb3));
+ usb3_drd_clear_bit(usb3, DRD_CON_VBOUT, USB3_DRD_CON(usb3));
}
static void usb3_mode_config(struct renesas_usb3 *usb3, bool host, bool a_dev)
@@ -733,7 +775,7 @@ static void usb3_mode_config(struct renesas_usb3 *usb3, bool host, bool a_dev)
static bool usb3_is_a_device(struct renesas_usb3 *usb3)
{
- return !(usb3_read(usb3, USB3_USB_OTG_STA(usb3)) & USB_OTG_IDMON(usb3));
+ return !(usb3_drd_read(usb3, USB3_USB_OTG_STA(usb3)) & USB_OTG_IDMON(usb3));
}
static void usb3_check_id(struct renesas_usb3 *usb3)
@@ -756,8 +798,8 @@ static void renesas_usb3_init_controller(struct renesas_usb3 *usb3)
usb3_set_bit(usb3, USB_COM_CON_PN_WDATAIF_NL |
USB_COM_CON_PN_RDATAIF_NL | USB_COM_CON_PN_LSTTR_PP,
USB3_USB_COM_CON);
- usb3_write(usb3, USB_OTG_IDMON(usb3), USB3_USB_OTG_INT_STA(usb3));
- usb3_write(usb3, USB_OTG_IDMON(usb3), USB3_USB_OTG_INT_ENA(usb3));
+ usb3_drd_write(usb3, USB_OTG_IDMON(usb3), USB3_USB_OTG_INT_STA(usb3));
+ usb3_drd_write(usb3, USB_OTG_IDMON(usb3), USB3_USB_OTG_INT_ENA(usb3));
usb3_check_id(usb3);
usb3_check_vbus(usb3);
@@ -767,7 +809,7 @@ static void renesas_usb3_stop_controller(struct renesas_usb3 *usb3)
{
usb3_disconnect(usb3);
usb3_write(usb3, 0, USB3_P0_INT_ENA);
- usb3_write(usb3, 0, USB3_USB_OTG_INT_ENA(usb3));
+ usb3_drd_write(usb3, 0, USB3_USB_OTG_INT_ENA(usb3));
usb3_write(usb3, 0, USB3_USB_INT_ENA_1);
usb3_write(usb3, 0, USB3_USB_INT_ENA_2);
usb3_write(usb3, 0, USB3_AXI_INT_ENA);
@@ -2024,11 +2066,11 @@ static void usb3_irq_idmon_change(struct renesas_usb3 *usb3)
static void usb3_irq_otg_int(struct renesas_usb3 *usb3)
{
- u32 otg_int_sta = usb3_read(usb3, USB3_USB_OTG_INT_STA(usb3));
+ u32 otg_int_sta = usb3_drd_read(usb3, USB3_USB_OTG_INT_STA(usb3));
- otg_int_sta &= usb3_read(usb3, USB3_USB_OTG_INT_ENA(usb3));
+ otg_int_sta &= usb3_drd_read(usb3, USB3_USB_OTG_INT_ENA(usb3));
if (otg_int_sta)
- usb3_write(usb3, otg_int_sta, USB3_USB_OTG_INT_STA(usb3));
+ usb3_drd_write(usb3, otg_int_sta, USB3_USB_OTG_INT_STA(usb3));
if (otg_int_sta & USB_OTG_IDMON(usb3))
usb3_irq_idmon_change(usb3);
@@ -2325,6 +2367,9 @@ static int renesas_usb3_start(struct usb_gadget *gadget,
usb3 = gadget_to_renesas_usb3(gadget);
+ if (usb3->is_rzv2m && usb3_is_a_device(usb3))
+ return -EBUSY;
+
/* hook up the driver */
usb3->driver = driver;
@@ -2333,6 +2378,10 @@ static int renesas_usb3_start(struct usb_gadget *gadget,
pm_runtime_get_sync(usb3_to_dev(usb3));
+ /* Peripheral Reset */
+ if (usb3->is_rzv2m)
+ rzv2m_usb3drd_reset(usb3_to_dev(usb3)->parent, false);
+
renesas_usb3_init_controller(usb3);
return 0;
@@ -2345,8 +2394,10 @@ static int renesas_usb3_stop(struct usb_gadget *gadget)
usb3->softconnect = false;
usb3->gadget.speed = USB_SPEED_UNKNOWN;
usb3->driver = NULL;
- renesas_usb3_stop_controller(usb3);
+ if (usb3->is_rzv2m)
+ rzv2m_usb3drd_reset(usb3_to_dev(usb3)->parent, false);
+ renesas_usb3_stop_controller(usb3);
if (usb3->phy)
phy_exit(usb3->phy);
@@ -2406,18 +2457,29 @@ static void handle_ext_role_switch_states(struct device *dev,
switch (role) {
case USB_ROLE_NONE:
usb3->connection_state = USB_ROLE_NONE;
- if (cur_role == USB_ROLE_HOST)
+ if (!usb3->is_rzv2m && cur_role == USB_ROLE_HOST)
device_release_driver(host);
- if (usb3->driver)
+ if (usb3->driver) {
+ if (usb3->is_rzv2m)
+ rzv2m_usb3drd_reset(dev->parent, false);
usb3_disconnect(usb3);
+ }
usb3_vbus_out(usb3, false);
+
+ if (usb3->is_rzv2m) {
+ rzv2m_usb3drd_reset(dev->parent, true);
+ device_release_driver(host);
+ }
break;
case USB_ROLE_DEVICE:
if (usb3->connection_state == USB_ROLE_NONE) {
usb3->connection_state = USB_ROLE_DEVICE;
usb3_set_mode(usb3, false);
- if (usb3->driver)
+ if (usb3->driver) {
+ if (usb3->is_rzv2m)
+ renesas_usb3_init_controller(usb3);
usb3_connect(usb3);
+ }
} else if (cur_role == USB_ROLE_HOST) {
device_release_driver(host);
usb3_set_mode(usb3, false);
@@ -2428,8 +2490,11 @@ static void handle_ext_role_switch_states(struct device *dev,
break;
case USB_ROLE_HOST:
if (usb3->connection_state == USB_ROLE_NONE) {
- if (usb3->driver)
+ if (usb3->driver) {
+ if (usb3->is_rzv2m)
+ rzv2m_usb3drd_reset(dev->parent, false);
usb3_disconnect(usb3);
+ }
usb3->connection_state = USB_ROLE_HOST;
usb3_set_mode(usb3, true);
@@ -2600,7 +2665,6 @@ static int renesas_usb3_remove(struct platform_device *pdev)
usb_del_gadget_udc(&usb3->gadget);
reset_control_assert(usb3->usbp_rstc);
- reset_control_assert(usb3->drd_rstc);
renesas_usb3_dma_free_prd(usb3, &pdev->dev);
__renesas_usb3_ep_free_request(usb3->ep0_req);
@@ -2788,7 +2852,7 @@ static struct usb_role_switch_desc renesas_usb3_role_switch_desc = {
static int renesas_usb3_probe(struct platform_device *pdev)
{
struct renesas_usb3 *usb3;
- int irq, drd_irq, ret;
+ int irq, ret;
const struct renesas_usb3_priv *priv;
const struct soc_device_attribute *attr;
@@ -2802,12 +2866,6 @@ static int renesas_usb3_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
- if (priv->is_rzv2m) {
- drd_irq = platform_get_irq_byname(pdev, "drd");
- if (drd_irq < 0)
- return drd_irq;
- }
-
usb3 = devm_kzalloc(&pdev->dev, sizeof(*usb3), GFP_KERNEL);
if (!usb3)
return -ENOMEM;
@@ -2836,9 +2894,12 @@ static int renesas_usb3_probe(struct platform_device *pdev)
return ret;
if (usb3->is_rzv2m) {
- ret = devm_request_irq(&pdev->dev, drd_irq,
+ struct rzv2m_usb3drd *ddata = dev_get_drvdata(pdev->dev.parent);
+
+ usb3->drd_reg = ddata->reg;
+ ret = devm_request_irq(ddata->dev, ddata->drd_irq,
renesas_usb3_otg_irq, 0,
- dev_name(&pdev->dev), usb3);
+ dev_name(ddata->dev), usb3);
if (ret < 0)
return ret;
}
@@ -2873,21 +2934,13 @@ static int renesas_usb3_probe(struct platform_device *pdev)
goto err_add_udc;
}
- usb3->drd_rstc = devm_reset_control_get_optional_shared(&pdev->dev,
- "drd_reset");
- if (IS_ERR(usb3->drd_rstc)) {
- ret = PTR_ERR(usb3->drd_rstc);
- goto err_add_udc;
- }
-
usb3->usbp_rstc = devm_reset_control_get_optional_shared(&pdev->dev,
- "aresetn_p");
+ NULL);
if (IS_ERR(usb3->usbp_rstc)) {
ret = PTR_ERR(usb3->usbp_rstc);
goto err_add_udc;
}
- reset_control_deassert(usb3->drd_rstc);
reset_control_deassert(usb3->usbp_rstc);
pm_runtime_enable(&pdev->dev);
@@ -2933,7 +2986,6 @@ err_dev_create:
err_reset:
reset_control_assert(usb3->usbp_rstc);
- reset_control_assert(usb3->drd_rstc);
err_add_udc:
renesas_usb3_dma_free_prd(usb3, &pdev->dev);
diff --git a/drivers/usb/gadget/udc/renesas_usbf.c b/drivers/usb/gadget/udc/renesas_usbf.c
new file mode 100644
index 000000000000..cb23e62e8a87
--- /dev/null
+++ b/drivers/usb/gadget/udc/renesas_usbf.c
@@ -0,0 +1,3406 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas USBF USB Function driver
+ *
+ * Copyright 2022 Schneider Electric
+ * Author: Herve Codina <herve.codina@bootlin.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/kfifo.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/pm_runtime.h>
+#include <linux/types.h>
+#include <linux/usb/composite.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/role.h>
+
+#define USBF_NUM_ENDPOINTS 16
+#define USBF_EP0_MAX_PCKT_SIZE 64
+
+/* EPC registers */
+#define USBF_REG_USB_CONTROL 0x000
+#define USBF_USB_PUE2 BIT(2)
+#define USBF_USB_CONNECTB BIT(3)
+#define USBF_USB_DEFAULT BIT(4)
+#define USBF_USB_CONF BIT(5)
+#define USBF_USB_SUSPEND BIT(6)
+#define USBF_USB_RSUM_IN BIT(7)
+#define USBF_USB_SOF_RCV BIT(8)
+#define USBF_USB_FORCEFS BIT(9)
+#define USBF_USB_INT_SEL BIT(10)
+#define USBF_USB_SOF_CLK_MODE BIT(11)
+
+#define USBF_REG_USB_STATUS 0x004
+#define USBF_USB_RSUM_OUT BIT(1)
+#define USBF_USB_SPND_OUT BIT(2)
+#define USBF_USB_USB_RST BIT(3)
+#define USBF_USB_DEFAULT_ST BIT(4)
+#define USBF_USB_CONF_ST BIT(5)
+#define USBF_USB_SPEED_MODE BIT(6)
+#define USBF_USB_SOF_DELAY_STATUS BIT(31)
+
+#define USBF_REG_USB_ADDRESS 0x008
+#define USBF_USB_SOF_STATUS BIT(15)
+#define USBF_USB_SET_USB_ADDR(_a) ((_a) << 16)
+#define USBF_USB_GET_FRAME(_r) ((_r) & 0x7FF)
+
+#define USBF_REG_SETUP_DATA0 0x018
+#define USBF_REG_SETUP_DATA1 0x01C
+#define USBF_REG_USB_INT_STA 0x020
+#define USBF_USB_RSUM_INT BIT(1)
+#define USBF_USB_SPND_INT BIT(2)
+#define USBF_USB_USB_RST_INT BIT(3)
+#define USBF_USB_SOF_INT BIT(4)
+#define USBF_USB_SOF_ERROR_INT BIT(5)
+#define USBF_USB_SPEED_MODE_INT BIT(6)
+#define USBF_USB_EPN_INT(_n) (BIT(8) << (_n)) /* n=0..15 */
+
+#define USBF_REG_USB_INT_ENA 0x024
+#define USBF_USB_RSUM_EN BIT(1)
+#define USBF_USB_SPND_EN BIT(2)
+#define USBF_USB_USB_RST_EN BIT(3)
+#define USBF_USB_SOF_EN BIT(4)
+#define USBF_USB_SOF_ERROR_EN BIT(5)
+#define USBF_USB_SPEED_MODE_EN BIT(6)
+#define USBF_USB_EPN_EN(_n) (BIT(8) << (_n)) /* n=0..15 */
+
+#define USBF_BASE_EP0 0x028
+/* EP0 registers offsets from Base + USBF_BASE_EP0 (EP0 regs area) */
+#define USBF_REG_EP0_CONTROL 0x00
+#define USBF_EP0_ONAK BIT(0)
+#define USBF_EP0_INAK BIT(1)
+#define USBF_EP0_STL BIT(2)
+#define USBF_EP0_PERR_NAK_CLR BIT(3)
+#define USBF_EP0_INAK_EN BIT(4)
+#define USBF_EP0_DW_MASK (0x3 << 5)
+#define USBF_EP0_DW(_s) ((_s) << 5)
+#define USBF_EP0_DEND BIT(7)
+#define USBF_EP0_BCLR BIT(8)
+#define USBF_EP0_PIDCLR BIT(9)
+#define USBF_EP0_AUTO BIT(16)
+#define USBF_EP0_OVERSEL BIT(17)
+#define USBF_EP0_STGSEL BIT(18)
+
+#define USBF_REG_EP0_STATUS 0x04
+#define USBF_EP0_SETUP_INT BIT(0)
+#define USBF_EP0_STG_START_INT BIT(1)
+#define USBF_EP0_STG_END_INT BIT(2)
+#define USBF_EP0_STALL_INT BIT(3)
+#define USBF_EP0_IN_INT BIT(4)
+#define USBF_EP0_OUT_INT BIT(5)
+#define USBF_EP0_OUT_OR_INT BIT(6)
+#define USBF_EP0_OUT_NULL_INT BIT(7)
+#define USBF_EP0_IN_EMPTY BIT(8)
+#define USBF_EP0_IN_FULL BIT(9)
+#define USBF_EP0_IN_DATA BIT(10)
+#define USBF_EP0_IN_NAK_INT BIT(11)
+#define USBF_EP0_OUT_EMPTY BIT(12)
+#define USBF_EP0_OUT_FULL BIT(13)
+#define USBF_EP0_OUT_NULL BIT(14)
+#define USBF_EP0_OUT_NAK_INT BIT(15)
+#define USBF_EP0_PERR_NAK_INT BIT(16)
+#define USBF_EP0_PERR_NAK BIT(17)
+#define USBF_EP0_PID BIT(18)
+
+#define USBF_REG_EP0_INT_ENA 0x08
+#define USBF_EP0_SETUP_EN BIT(0)
+#define USBF_EP0_STG_START_EN BIT(1)
+#define USBF_EP0_STG_END_EN BIT(2)
+#define USBF_EP0_STALL_EN BIT(3)
+#define USBF_EP0_IN_EN BIT(4)
+#define USBF_EP0_OUT_EN BIT(5)
+#define USBF_EP0_OUT_OR_EN BIT(6)
+#define USBF_EP0_OUT_NULL_EN BIT(7)
+#define USBF_EP0_IN_NAK_EN BIT(11)
+#define USBF_EP0_OUT_NAK_EN BIT(15)
+#define USBF_EP0_PERR_NAK_EN BIT(16)
+
+#define USBF_REG_EP0_LENGTH 0x0C
+#define USBF_EP0_LDATA (0x7FF << 0)
+#define USBF_REG_EP0_READ 0x10
+#define USBF_REG_EP0_WRITE 0x14
+
+#define USBF_BASE_EPN(_n) (0x040 + (_n) * 0x020)
+/* EPn registers offsets from Base + USBF_BASE_EPN(n-1). n=1..15 */
+#define USBF_REG_EPN_CONTROL 0x000
+#define USBF_EPN_ONAK BIT(0)
+#define USBF_EPN_OSTL BIT(2)
+#define USBF_EPN_ISTL BIT(3)
+#define USBF_EPN_OSTL_EN BIT(4)
+#define USBF_EPN_DW_MASK (0x3 << 5)
+#define USBF_EPN_DW(_s) ((_s) << 5)
+#define USBF_EPN_DEND BIT(7)
+#define USBF_EPN_CBCLR BIT(8)
+#define USBF_EPN_BCLR BIT(9)
+#define USBF_EPN_OPIDCLR BIT(10)
+#define USBF_EPN_IPIDCLR BIT(11)
+#define USBF_EPN_AUTO BIT(16)
+#define USBF_EPN_OVERSEL BIT(17)
+#define USBF_EPN_MODE_MASK (0x3 << 24)
+#define USBF_EPN_MODE_BULK (0x0 << 24)
+#define USBF_EPN_MODE_INTR (0x1 << 24)
+#define USBF_EPN_MODE_ISO (0x2 << 24)
+#define USBF_EPN_DIR0 BIT(26)
+#define USBF_EPN_BUF_TYPE_DOUBLE BIT(30)
+#define USBF_EPN_EN BIT(31)
+
+#define USBF_REG_EPN_STATUS 0x004
+#define USBF_EPN_IN_EMPTY BIT(0)
+#define USBF_EPN_IN_FULL BIT(1)
+#define USBF_EPN_IN_DATA BIT(2)
+#define USBF_EPN_IN_INT BIT(3)
+#define USBF_EPN_IN_STALL_INT BIT(4)
+#define USBF_EPN_IN_NAK_ERR_INT BIT(5)
+#define USBF_EPN_IN_END_INT BIT(7)
+#define USBF_EPN_IPID BIT(10)
+#define USBF_EPN_OUT_EMPTY BIT(16)
+#define USBF_EPN_OUT_FULL BIT(17)
+#define USBF_EPN_OUT_NULL_INT BIT(18)
+#define USBF_EPN_OUT_INT BIT(19)
+#define USBF_EPN_OUT_STALL_INT BIT(20)
+#define USBF_EPN_OUT_NAK_ERR_INT BIT(21)
+#define USBF_EPN_OUT_OR_INT BIT(22)
+#define USBF_EPN_OUT_END_INT BIT(23)
+#define USBF_EPN_ISO_CRC BIT(24)
+#define USBF_EPN_ISO_OR BIT(26)
+#define USBF_EPN_OUT_NOTKN BIT(27)
+#define USBF_EPN_ISO_OPID BIT(28)
+#define USBF_EPN_ISO_PIDERR BIT(29)
+
+#define USBF_REG_EPN_INT_ENA 0x008
+#define USBF_EPN_IN_EN BIT(3)
+#define USBF_EPN_IN_STALL_EN BIT(4)
+#define USBF_EPN_IN_NAK_ERR_EN BIT(5)
+#define USBF_EPN_IN_END_EN BIT(7)
+#define USBF_EPN_OUT_NULL_EN BIT(18)
+#define USBF_EPN_OUT_EN BIT(19)
+#define USBF_EPN_OUT_STALL_EN BIT(20)
+#define USBF_EPN_OUT_NAK_ERR_EN BIT(21)
+#define USBF_EPN_OUT_OR_EN BIT(22)
+#define USBF_EPN_OUT_END_EN BIT(23)
+
+#define USBF_REG_EPN_DMA_CTRL 0x00C
+#define USBF_EPN_DMAMODE0 BIT(0)
+#define USBF_EPN_DMA_EN BIT(4)
+#define USBF_EPN_STOP_SET BIT(8)
+#define USBF_EPN_BURST_SET BIT(9)
+#define USBF_EPN_DEND_SET BIT(10)
+#define USBF_EPN_STOP_MODE BIT(11)
+
+#define USBF_REG_EPN_PCKT_ADRS 0x010
+#define USBF_EPN_MPKT(_l) ((_l) << 0)
+#define USBF_EPN_BASEAD(_a) ((_a) << 16)
+
+#define USBF_REG_EPN_LEN_DCNT 0x014
+#define USBF_EPN_GET_LDATA(_r) ((_r) & 0x7FF)
+#define USBF_EPN_SET_DMACNT(_c) ((_c) << 16)
+#define USBF_EPN_GET_DMACNT(_r) (((_r) >> 16) & 0x1ff)
+
+#define USBF_REG_EPN_READ 0x018
+#define USBF_REG_EPN_WRITE 0x01C
+
+/* AHB-EPC Bridge registers */
+#define USBF_REG_AHBSCTR 0x1000
+#define USBF_REG_AHBMCTR 0x1004
+#define USBF_SYS_WBURST_TYPE BIT(2)
+#define USBF_SYS_ARBITER_CTR BIT(31)
+
+#define USBF_REG_AHBBINT 0x1008
+#define USBF_SYS_ERR_MASTER (0x0F << 0)
+#define USBF_SYS_SBUS_ERRINT0 BIT(4)
+#define USBF_SYS_SBUS_ERRINT1 BIT(5)
+#define USBF_SYS_MBUS_ERRINT BIT(6)
+#define USBF_SYS_VBUS_INT BIT(13)
+#define USBF_SYS_DMA_ENDINT_EPN(_n) (BIT(16) << (_n)) /* _n=1..15 */
+
+#define USBF_REG_AHBBINTEN 0x100C
+#define USBF_SYS_SBUS_ERRINT0EN BIT(4)
+#define USBF_SYS_SBUS_ERRINT1EN BIT(5)
+#define USBF_SYS_MBUS_ERRINTEN BIT(6)
+#define USBF_SYS_VBUS_INTEN BIT(13)
+#define USBF_SYS_DMA_ENDINTEN_EPN(_n) (BIT(16) << (_n)) /* _n=1..15 */
+
+#define USBF_REG_EPCTR 0x1010
+#define USBF_SYS_EPC_RST BIT(0)
+#define USBF_SYS_PLL_RST BIT(2)
+#define USBF_SYS_PLL_LOCK BIT(4)
+#define USBF_SYS_PLL_RESUME BIT(5)
+#define USBF_SYS_VBUS_LEVEL BIT(8)
+#define USBF_SYS_DIRPD BIT(12)
+
+#define USBF_REG_USBSSVER 0x1020
+#define USBF_REG_USBSSCONF 0x1024
+#define USBF_SYS_DMA_AVAILABLE(_n) (BIT(0) << (_n)) /* _n=0..15 */
+#define USBF_SYS_EP_AVAILABLE(_n) (BIT(16) << (_n)) /* _n=0..15 */
+
+#define USBF_BASE_DMA_EPN(_n) (0x1110 + (_n) * 0x010)
+/* EPn DMA registers offsets from Base USBF_BASE_DMA_EPN(n-1). n=1..15*/
+#define USBF_REG_DMA_EPN_DCR1 0x00
+#define USBF_SYS_EPN_REQEN BIT(0)
+#define USBF_SYS_EPN_DIR0 BIT(1)
+#define USBF_SYS_EPN_SET_DMACNT(_c) ((_c) << 16)
+#define USBF_SYS_EPN_GET_DMACNT(_r) (((_r) >> 16) & 0x0FF)
+
+#define USBF_REG_DMA_EPN_DCR2 0x04
+#define USBF_SYS_EPN_MPKT(_s) ((_s) << 0)
+#define USBF_SYS_EPN_LMPKT(_l) ((_l) << 16)
+
+#define USBF_REG_DMA_EPN_TADR 0x08
+
+/* USB request */
+struct usbf_req {
+ struct usb_request req;
+ struct list_head queue;
+ unsigned int is_zero_sent : 1;
+ unsigned int is_mapped : 1;
+ enum {
+ USBF_XFER_START,
+ USBF_XFER_WAIT_DMA,
+ USBF_XFER_SEND_NULL,
+ USBF_XFER_WAIT_END,
+ USBF_XFER_WAIT_DMA_SHORT,
+ USBF_XFER_WAIT_BRIDGE,
+ } xfer_step;
+ size_t dma_size;
+};
+
+/* USB Endpoint */
+struct usbf_ep {
+ struct usb_ep ep;
+ char name[32];
+ struct list_head queue;
+ unsigned int is_processing : 1;
+ unsigned int is_in : 1;
+ struct usbf_udc *udc;
+ void __iomem *regs;
+ void __iomem *dma_regs;
+ unsigned int id : 8;
+ unsigned int disabled : 1;
+ unsigned int is_wedged : 1;
+ unsigned int delayed_status : 1;
+ u32 status;
+ void (*bridge_on_dma_end)(struct usbf_ep *ep);
+};
+
+enum usbf_ep0state {
+ EP0_IDLE,
+ EP0_IN_DATA_PHASE,
+ EP0_OUT_DATA_PHASE,
+ EP0_OUT_STATUS_START_PHASE,
+ EP0_OUT_STATUS_PHASE,
+ EP0_OUT_STATUS_END_PHASE,
+ EP0_IN_STATUS_START_PHASE,
+ EP0_IN_STATUS_PHASE,
+ EP0_IN_STATUS_END_PHASE,
+};
+
+struct usbf_udc {
+ struct usb_gadget gadget;
+ struct usb_gadget_driver *driver;
+ struct device *dev;
+ void __iomem *regs;
+ spinlock_t lock;
+ bool is_remote_wakeup;
+ bool is_usb_suspended;
+ struct usbf_ep ep[USBF_NUM_ENDPOINTS];
+ /* for EP0 control messages */
+ enum usbf_ep0state ep0state;
+ struct usbf_req setup_reply;
+ u8 ep0_buf[USBF_EP0_MAX_PCKT_SIZE];
+};
+
+struct usbf_ep_info {
+ const char *name;
+ struct usb_ep_caps caps;
+ u16 base_addr;
+ unsigned int is_double : 1;
+ u16 maxpacket_limit;
+};
+
+#define USBF_SINGLE_BUFFER 0
+#define USBF_DOUBLE_BUFFER 1
+#define USBF_EP_INFO(_name, _caps, _base_addr, _is_double, _maxpacket_limit) \
+ { \
+ .name = _name, \
+ .caps = _caps, \
+ .base_addr = _base_addr, \
+ .is_double = _is_double, \
+ .maxpacket_limit = _maxpacket_limit, \
+ }
+
+/* This table is computed from the recommended values provided in the SOC
+ * datasheet. The buffer type (single/double) and the endpoint type cannot
+ * be changed. The mapping in internal RAM (base_addr and number of words)
+ * for each endpoints depends on the max packet size and the buffer type.
+ */
+static const struct usbf_ep_info usbf_ep_info[USBF_NUM_ENDPOINTS] = {
+ /* ep0: buf @0x0000 64 bytes, fixed 32 words */
+ [0] = USBF_EP_INFO("ep0-ctrl",
+ USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL,
+ USB_EP_CAPS_DIR_ALL),
+ 0x0000, USBF_SINGLE_BUFFER, USBF_EP0_MAX_PCKT_SIZE),
+ /* ep1: buf @0x0020, 2 buffers 512 bytes -> (512 * 2 / 4) words */
+ [1] = USBF_EP_INFO("ep1-bulk",
+ USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK,
+ USB_EP_CAPS_DIR_ALL),
+ 0x0020, USBF_DOUBLE_BUFFER, 512),
+ /* ep2: buf @0x0120, 2 buffers 512 bytes -> (512 * 2 / 4) words */
+ [2] = USBF_EP_INFO("ep2-bulk",
+ USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK,
+ USB_EP_CAPS_DIR_ALL),
+ 0x0120, USBF_DOUBLE_BUFFER, 512),
+ /* ep3: buf @0x0220, 1 buffer 512 bytes -> (512 * 2 / 4) words */
+ [3] = USBF_EP_INFO("ep3-bulk",
+ USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK,
+ USB_EP_CAPS_DIR_ALL),
+ 0x0220, USBF_SINGLE_BUFFER, 512),
+ /* ep4: buf @0x02A0, 1 buffer 512 bytes -> (512 * 1 / 4) words */
+ [4] = USBF_EP_INFO("ep4-bulk",
+ USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK,
+ USB_EP_CAPS_DIR_ALL),
+ 0x02A0, USBF_SINGLE_BUFFER, 512),
+ /* ep5: buf @0x0320, 1 buffer 512 bytes -> (512 * 2 / 4) words */
+ [5] = USBF_EP_INFO("ep5-bulk",
+ USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK,
+ USB_EP_CAPS_DIR_ALL),
+ 0x0320, USBF_SINGLE_BUFFER, 512),
+ /* ep6: buf @0x03A0, 1 buffer 1024 bytes -> (1024 * 1 / 4) words */
+ [6] = USBF_EP_INFO("ep6-int",
+ USB_EP_CAPS(USB_EP_CAPS_TYPE_INT,
+ USB_EP_CAPS_DIR_ALL),
+ 0x03A0, USBF_SINGLE_BUFFER, 1024),
+ /* ep7: buf @0x04A0, 1 buffer 1024 bytes -> (1024 * 1 / 4) words */
+ [7] = USBF_EP_INFO("ep7-int",
+ USB_EP_CAPS(USB_EP_CAPS_TYPE_INT,
+ USB_EP_CAPS_DIR_ALL),
+ 0x04A0, USBF_SINGLE_BUFFER, 1024),
+ /* ep8: buf @0x0520, 1 buffer 1024 bytes -> (1024 * 1 / 4) words */
+ [8] = USBF_EP_INFO("ep8-int",
+ USB_EP_CAPS(USB_EP_CAPS_TYPE_INT,
+ USB_EP_CAPS_DIR_ALL),
+ 0x0520, USBF_SINGLE_BUFFER, 1024),
+ /* ep9: buf @0x0620, 1 buffer 1024 bytes -> (1024 * 1 / 4) words */
+ [9] = USBF_EP_INFO("ep9-int",
+ USB_EP_CAPS(USB_EP_CAPS_TYPE_INT,
+ USB_EP_CAPS_DIR_ALL),
+ 0x0620, USBF_SINGLE_BUFFER, 1024),
+ /* ep10: buf @0x0720, 2 buffers 1024 bytes -> (1024 * 2 / 4) words */
+ [10] = USBF_EP_INFO("ep10-iso",
+ USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO,
+ USB_EP_CAPS_DIR_ALL),
+ 0x0720, USBF_DOUBLE_BUFFER, 1024),
+ /* ep11: buf @0x0920, 2 buffers 1024 bytes -> (1024 * 2 / 4) words */
+ [11] = USBF_EP_INFO("ep11-iso",
+ USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO,
+ USB_EP_CAPS_DIR_ALL),
+ 0x0920, USBF_DOUBLE_BUFFER, 1024),
+ /* ep12: buf @0x0B20, 2 buffers 1024 bytes -> (1024 * 2 / 4) words */
+ [12] = USBF_EP_INFO("ep12-iso",
+ USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO,
+ USB_EP_CAPS_DIR_ALL),
+ 0x0B20, USBF_DOUBLE_BUFFER, 1024),
+ /* ep13: buf @0x0D20, 2 buffers 1024 bytes -> (1024 * 2 / 4) words */
+ [13] = USBF_EP_INFO("ep13-iso",
+ USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO,
+ USB_EP_CAPS_DIR_ALL),
+ 0x0D20, USBF_DOUBLE_BUFFER, 1024),
+ /* ep14: buf @0x0F20, 2 buffers 1024 bytes -> (1024 * 2 / 4) words */
+ [14] = USBF_EP_INFO("ep14-iso",
+ USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO,
+ USB_EP_CAPS_DIR_ALL),
+ 0x0F20, USBF_DOUBLE_BUFFER, 1024),
+ /* ep15: buf @0x1120, 2 buffers 1024 bytes -> (1024 * 2 / 4) words */
+ [15] = USBF_EP_INFO("ep15-iso",
+ USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO,
+ USB_EP_CAPS_DIR_ALL),
+ 0x1120, USBF_DOUBLE_BUFFER, 1024),
+};
+
+static inline u32 usbf_reg_readl(struct usbf_udc *udc, uint offset)
+{
+ return readl(udc->regs + offset);
+}
+
+static inline void usbf_reg_writel(struct usbf_udc *udc, uint offset, u32 val)
+{
+ writel(val, udc->regs + offset);
+}
+
+static inline void usbf_reg_bitset(struct usbf_udc *udc, uint offset, u32 set)
+{
+ u32 tmp;
+
+ tmp = usbf_reg_readl(udc, offset);
+ tmp |= set;
+ usbf_reg_writel(udc, offset, tmp);
+}
+
+static inline void usbf_reg_bitclr(struct usbf_udc *udc, uint offset, u32 clr)
+{
+ u32 tmp;
+
+ tmp = usbf_reg_readl(udc, offset);
+ tmp &= ~clr;
+ usbf_reg_writel(udc, offset, tmp);
+}
+
+static inline void usbf_reg_clrset(struct usbf_udc *udc, uint offset,
+ u32 clr, u32 set)
+{
+ u32 tmp;
+
+ tmp = usbf_reg_readl(udc, offset);
+ tmp &= ~clr;
+ tmp |= set;
+ usbf_reg_writel(udc, offset, tmp);
+}
+
+static inline u32 usbf_ep_reg_readl(struct usbf_ep *ep, uint offset)
+{
+ return readl(ep->regs + offset);
+}
+
+static inline void usbf_ep_reg_read_rep(struct usbf_ep *ep, uint offset,
+ void *dst, uint count)
+{
+ readsl(ep->regs + offset, dst, count);
+}
+
+static inline void usbf_ep_reg_writel(struct usbf_ep *ep, uint offset, u32 val)
+{
+ writel(val, ep->regs + offset);
+}
+
+static inline void usbf_ep_reg_write_rep(struct usbf_ep *ep, uint offset,
+ const void *src, uint count)
+{
+ writesl(ep->regs + offset, src, count);
+}
+
+static inline void usbf_ep_reg_bitset(struct usbf_ep *ep, uint offset, u32 set)
+{
+ u32 tmp;
+
+ tmp = usbf_ep_reg_readl(ep, offset);
+ tmp |= set;
+ usbf_ep_reg_writel(ep, offset, tmp);
+}
+
+static inline void usbf_ep_reg_bitclr(struct usbf_ep *ep, uint offset, u32 clr)
+{
+ u32 tmp;
+
+ tmp = usbf_ep_reg_readl(ep, offset);
+ tmp &= ~clr;
+ usbf_ep_reg_writel(ep, offset, tmp);
+}
+
+static inline void usbf_ep_reg_clrset(struct usbf_ep *ep, uint offset,
+ u32 clr, u32 set)
+{
+ u32 tmp;
+
+ tmp = usbf_ep_reg_readl(ep, offset);
+ tmp &= ~clr;
+ tmp |= set;
+ usbf_ep_reg_writel(ep, offset, tmp);
+}
+
+static inline u32 usbf_ep_dma_reg_readl(struct usbf_ep *ep, uint offset)
+{
+ return readl(ep->dma_regs + offset);
+}
+
+static inline void usbf_ep_dma_reg_writel(struct usbf_ep *ep, uint offset,
+ u32 val)
+{
+ writel(val, ep->dma_regs + offset);
+}
+
+static inline void usbf_ep_dma_reg_bitset(struct usbf_ep *ep, uint offset,
+ u32 set)
+{
+ u32 tmp;
+
+ tmp = usbf_ep_dma_reg_readl(ep, offset);
+ tmp |= set;
+ usbf_ep_dma_reg_writel(ep, offset, tmp);
+}
+
+static inline void usbf_ep_dma_reg_bitclr(struct usbf_ep *ep, uint offset,
+ u32 clr)
+{
+ u32 tmp;
+
+ tmp = usbf_ep_dma_reg_readl(ep, offset);
+ tmp &= ~clr;
+ usbf_ep_dma_reg_writel(ep, offset, tmp);
+}
+
+static inline void usbf_ep_dma_reg_clrset(struct usbf_ep *ep, uint offset,
+ u32 clr, u32 set)
+{
+ u32 tmp;
+
+ tmp = usbf_ep_dma_reg_readl(ep, offset);
+ tmp &= ~clr;
+ tmp |= set;
+ usbf_ep_dma_reg_writel(ep, offset, tmp);
+}
+
+static void usbf_ep0_send_null(struct usbf_ep *ep0, bool is_data1)
+{
+ u32 set;
+
+ set = USBF_EP0_DEND;
+ if (is_data1)
+ set |= USBF_EP0_PIDCLR;
+
+ usbf_ep_reg_bitset(ep0, USBF_REG_EP0_CONTROL, set);
+}
+
+static int usbf_ep0_pio_in(struct usbf_ep *ep0, struct usbf_req *req)
+{
+ unsigned int left;
+ unsigned int nb;
+ const void *buf;
+ u32 ctrl;
+ u32 last;
+
+ left = req->req.length - req->req.actual;
+
+ if (left == 0) {
+ if (!req->is_zero_sent) {
+ if (req->req.length == 0) {
+ dev_dbg(ep0->udc->dev, "ep0 send null\n");
+ usbf_ep0_send_null(ep0, false);
+ req->is_zero_sent = 1;
+ return -EINPROGRESS;
+ }
+ if ((req->req.actual % ep0->ep.maxpacket) == 0) {
+ if (req->req.zero) {
+ dev_dbg(ep0->udc->dev, "ep0 send null\n");
+ usbf_ep0_send_null(ep0, false);
+ req->is_zero_sent = 1;
+ return -EINPROGRESS;
+ }
+ }
+ }
+ return 0;
+ }
+
+ if (left > ep0->ep.maxpacket)
+ left = ep0->ep.maxpacket;
+
+ buf = req->req.buf;
+ buf += req->req.actual;
+
+ nb = left / sizeof(u32);
+ if (nb) {
+ usbf_ep_reg_write_rep(ep0, USBF_REG_EP0_WRITE, buf, nb);
+ buf += (nb * sizeof(u32));
+ req->req.actual += (nb * sizeof(u32));
+ left -= (nb * sizeof(u32));
+ }
+ ctrl = usbf_ep_reg_readl(ep0, USBF_REG_EP0_CONTROL);
+ ctrl &= ~USBF_EP0_DW_MASK;
+ if (left) {
+ memcpy(&last, buf, left);
+ usbf_ep_reg_writel(ep0, USBF_REG_EP0_WRITE, last);
+ ctrl |= USBF_EP0_DW(left);
+ req->req.actual += left;
+ }
+ usbf_ep_reg_writel(ep0, USBF_REG_EP0_CONTROL, ctrl | USBF_EP0_DEND);
+
+ dev_dbg(ep0->udc->dev, "ep0 send %u/%u\n",
+ req->req.actual, req->req.length);
+
+ return -EINPROGRESS;
+}
+
+static int usbf_ep0_pio_out(struct usbf_ep *ep0, struct usbf_req *req)
+{
+ int req_status = 0;
+ unsigned int count;
+ unsigned int recv;
+ unsigned int left;
+ unsigned int nb;
+ void *buf;
+ u32 last;
+
+ if (ep0->status & USBF_EP0_OUT_INT) {
+ recv = usbf_ep_reg_readl(ep0, USBF_REG_EP0_LENGTH) & USBF_EP0_LDATA;
+ count = recv;
+
+ buf = req->req.buf;
+ buf += req->req.actual;
+
+ left = req->req.length - req->req.actual;
+
+ dev_dbg(ep0->udc->dev, "ep0 recv %u, left %u\n", count, left);
+
+ if (left > ep0->ep.maxpacket)
+ left = ep0->ep.maxpacket;
+
+ if (count > left) {
+ req_status = -EOVERFLOW;
+ count = left;
+ }
+
+ if (count) {
+ nb = count / sizeof(u32);
+ if (nb) {
+ usbf_ep_reg_read_rep(ep0, USBF_REG_EP0_READ,
+ buf, nb);
+ buf += (nb * sizeof(u32));
+ req->req.actual += (nb * sizeof(u32));
+ count -= (nb * sizeof(u32));
+ }
+ if (count) {
+ last = usbf_ep_reg_readl(ep0, USBF_REG_EP0_READ);
+ memcpy(buf, &last, count);
+ req->req.actual += count;
+ }
+ }
+ dev_dbg(ep0->udc->dev, "ep0 recv %u/%u\n",
+ req->req.actual, req->req.length);
+
+ if (req_status) {
+ dev_dbg(ep0->udc->dev, "ep0 req.status=%d\n", req_status);
+ req->req.status = req_status;
+ return 0;
+ }
+
+ if (recv < ep0->ep.maxpacket) {
+ dev_dbg(ep0->udc->dev, "ep0 short packet\n");
+ /* This is a short packet -> It is the end */
+ req->req.status = 0;
+ return 0;
+ }
+
+ /* The Data stage of a control transfer from an endpoint to the
+ * host is complete when the endpoint does one of the following:
+ * - Has transferred exactly the expected amount of data
+ * - Transfers a packet with a payload size less than
+ * wMaxPacketSize or transfers a zero-length packet
+ */
+ if (req->req.actual == req->req.length) {
+ req->req.status = 0;
+ return 0;
+ }
+ }
+
+ if (ep0->status & USBF_EP0_OUT_NULL_INT) {
+ /* NULL packet received */
+ dev_dbg(ep0->udc->dev, "ep0 null packet\n");
+ if (req->req.actual != req->req.length) {
+ req->req.status = req->req.short_not_ok ?
+ -EREMOTEIO : 0;
+ } else {
+ req->req.status = 0;
+ }
+ return 0;
+ }
+
+ return -EINPROGRESS;
+}
+
+static void usbf_ep0_fifo_flush(struct usbf_ep *ep0)
+{
+ u32 sts;
+ int ret;
+
+ usbf_ep_reg_bitset(ep0, USBF_REG_EP0_CONTROL, USBF_EP0_BCLR);
+
+ ret = readl_poll_timeout_atomic(ep0->regs + USBF_REG_EP0_STATUS, sts,
+ (sts & (USBF_EP0_IN_DATA | USBF_EP0_IN_EMPTY)) == USBF_EP0_IN_EMPTY,
+ 0, 10000);
+ if (ret)
+ dev_err(ep0->udc->dev, "ep0 flush fifo timed out\n");
+
+}
+
+static void usbf_epn_send_null(struct usbf_ep *epn)
+{
+ usbf_ep_reg_bitset(epn, USBF_REG_EPN_CONTROL, USBF_EPN_DEND);
+}
+
+static void usbf_epn_send_residue(struct usbf_ep *epn, const void *buf,
+ unsigned int size)
+{
+ u32 tmp;
+
+ memcpy(&tmp, buf, size);
+ usbf_ep_reg_writel(epn, USBF_REG_EPN_WRITE, tmp);
+
+ usbf_ep_reg_clrset(epn, USBF_REG_EPN_CONTROL,
+ USBF_EPN_DW_MASK,
+ USBF_EPN_DW(size) | USBF_EPN_DEND);
+}
+
+static int usbf_epn_pio_in(struct usbf_ep *epn, struct usbf_req *req)
+{
+ unsigned int left;
+ unsigned int nb;
+ const void *buf;
+
+ left = req->req.length - req->req.actual;
+
+ if (left == 0) {
+ if (!req->is_zero_sent) {
+ if (req->req.length == 0) {
+ dev_dbg(epn->udc->dev, "ep%u send_null\n", epn->id);
+ usbf_epn_send_null(epn);
+ req->is_zero_sent = 1;
+ return -EINPROGRESS;
+ }
+ if ((req->req.actual % epn->ep.maxpacket) == 0) {
+ if (req->req.zero) {
+ dev_dbg(epn->udc->dev, "ep%u send_null\n",
+ epn->id);
+ usbf_epn_send_null(epn);
+ req->is_zero_sent = 1;
+ return -EINPROGRESS;
+ }
+ }
+ }
+ return 0;
+ }
+
+ if (left > epn->ep.maxpacket)
+ left = epn->ep.maxpacket;
+
+ buf = req->req.buf;
+ buf += req->req.actual;
+
+ nb = left / sizeof(u32);
+ if (nb) {
+ usbf_ep_reg_write_rep(epn, USBF_REG_EPN_WRITE, buf, nb);
+ buf += (nb * sizeof(u32));
+ req->req.actual += (nb * sizeof(u32));
+ left -= (nb * sizeof(u32));
+ }
+
+ if (left) {
+ usbf_epn_send_residue(epn, buf, left);
+ req->req.actual += left;
+ } else {
+ usbf_ep_reg_clrset(epn, USBF_REG_EPN_CONTROL,
+ USBF_EPN_DW_MASK,
+ USBF_EPN_DEND);
+ }
+
+ dev_dbg(epn->udc->dev, "ep%u send %u/%u\n", epn->id, req->req.actual,
+ req->req.length);
+
+ return -EINPROGRESS;
+}
+
+static void usbf_epn_enable_in_end_int(struct usbf_ep *epn)
+{
+ usbf_ep_reg_bitset(epn, USBF_REG_EPN_INT_ENA, USBF_EPN_IN_END_EN);
+}
+
+static int usbf_epn_dma_in(struct usbf_ep *epn, struct usbf_req *req)
+{
+ unsigned int left;
+ u32 npkt;
+ u32 lastpkt;
+ int ret;
+
+ if (!IS_ALIGNED((uintptr_t)req->req.buf, 4)) {
+ dev_dbg(epn->udc->dev, "ep%u buf unaligned -> fallback pio\n",
+ epn->id);
+ return usbf_epn_pio_in(epn, req);
+ }
+
+ left = req->req.length - req->req.actual;
+
+ switch (req->xfer_step) {
+ default:
+ case USBF_XFER_START:
+ if (left == 0) {
+ dev_dbg(epn->udc->dev, "ep%u send null\n", epn->id);
+ usbf_epn_send_null(epn);
+ req->xfer_step = USBF_XFER_WAIT_END;
+ break;
+ }
+ if (left < 4) {
+ dev_dbg(epn->udc->dev, "ep%u send residue %u\n", epn->id,
+ left);
+ usbf_epn_send_residue(epn,
+ req->req.buf + req->req.actual, left);
+ req->req.actual += left;
+ req->xfer_step = USBF_XFER_WAIT_END;
+ break;
+ }
+
+ ret = usb_gadget_map_request(&epn->udc->gadget, &req->req, 1);
+ if (ret < 0) {
+ dev_err(epn->udc->dev, "usb_gadget_map_request failed (%d)\n",
+ ret);
+ return ret;
+ }
+ req->is_mapped = 1;
+
+ npkt = DIV_ROUND_UP(left, epn->ep.maxpacket);
+ lastpkt = (left % epn->ep.maxpacket);
+ if (lastpkt == 0)
+ lastpkt = epn->ep.maxpacket;
+ lastpkt &= ~0x3; /* DMA is done on 32bit units */
+
+ usbf_ep_dma_reg_writel(epn, USBF_REG_DMA_EPN_DCR2,
+ USBF_SYS_EPN_MPKT(epn->ep.maxpacket) | USBF_SYS_EPN_LMPKT(lastpkt));
+ usbf_ep_dma_reg_writel(epn, USBF_REG_DMA_EPN_TADR,
+ req->req.dma);
+ usbf_ep_dma_reg_writel(epn, USBF_REG_DMA_EPN_DCR1,
+ USBF_SYS_EPN_SET_DMACNT(npkt));
+ usbf_ep_dma_reg_bitset(epn, USBF_REG_DMA_EPN_DCR1,
+ USBF_SYS_EPN_REQEN);
+
+ usbf_ep_reg_writel(epn, USBF_REG_EPN_LEN_DCNT, USBF_EPN_SET_DMACNT(npkt));
+
+ usbf_ep_reg_bitset(epn, USBF_REG_EPN_CONTROL, USBF_EPN_AUTO);
+
+ /* The end of DMA transfer at the USBF level needs to be handle
+ * after the detection of the end of DMA transfer at the brige
+ * level.
+ * To force this sequence, EPN_IN_END_EN will be set by the
+ * detection of the end of transfer at bridge level (ie. bridge
+ * interrupt).
+ */
+ usbf_ep_reg_bitclr(epn, USBF_REG_EPN_INT_ENA,
+ USBF_EPN_IN_EN | USBF_EPN_IN_END_EN);
+ epn->bridge_on_dma_end = usbf_epn_enable_in_end_int;
+
+ /* Clear any pending IN_END interrupt */
+ usbf_ep_reg_writel(epn, USBF_REG_EPN_STATUS, ~(u32)USBF_EPN_IN_END_INT);
+
+ usbf_ep_reg_writel(epn, USBF_REG_EPN_DMA_CTRL,
+ USBF_EPN_BURST_SET | USBF_EPN_DMAMODE0);
+ usbf_ep_reg_bitset(epn, USBF_REG_EPN_DMA_CTRL,
+ USBF_EPN_DMA_EN);
+
+ req->dma_size = (npkt - 1) * epn->ep.maxpacket + lastpkt;
+
+ dev_dbg(epn->udc->dev, "ep%u dma xfer %zu\n", epn->id,
+ req->dma_size);
+
+ req->xfer_step = USBF_XFER_WAIT_DMA;
+ break;
+
+ case USBF_XFER_WAIT_DMA:
+ if (!(epn->status & USBF_EPN_IN_END_INT)) {
+ dev_dbg(epn->udc->dev, "ep%u dma not done\n", epn->id);
+ break;
+ }
+ dev_dbg(epn->udc->dev, "ep%u dma done\n", epn->id);
+
+ usb_gadget_unmap_request(&epn->udc->gadget, &req->req, 1);
+ req->is_mapped = 0;
+
+ usbf_ep_reg_bitclr(epn, USBF_REG_EPN_CONTROL, USBF_EPN_AUTO);
+
+ usbf_ep_reg_clrset(epn, USBF_REG_EPN_INT_ENA,
+ USBF_EPN_IN_END_EN,
+ USBF_EPN_IN_EN);
+
+ req->req.actual += req->dma_size;
+
+ left = req->req.length - req->req.actual;
+ if (left) {
+ usbf_ep_reg_writel(epn, USBF_REG_EPN_STATUS, ~(u32)USBF_EPN_IN_INT);
+
+ dev_dbg(epn->udc->dev, "ep%u send residue %u\n", epn->id,
+ left);
+ usbf_epn_send_residue(epn,
+ req->req.buf + req->req.actual, left);
+ req->req.actual += left;
+ req->xfer_step = USBF_XFER_WAIT_END;
+ break;
+ }
+
+ if (req->req.actual % epn->ep.maxpacket) {
+ /* last packet was a short packet. Tell the hardware to
+ * send it right now.
+ */
+ dev_dbg(epn->udc->dev, "ep%u send short\n", epn->id);
+ usbf_ep_reg_writel(epn, USBF_REG_EPN_STATUS,
+ ~(u32)USBF_EPN_IN_INT);
+ usbf_ep_reg_bitset(epn, USBF_REG_EPN_CONTROL,
+ USBF_EPN_DEND);
+
+ req->xfer_step = USBF_XFER_WAIT_END;
+ break;
+ }
+
+ /* Last packet size was a maxpacket size
+ * Send null packet if needed
+ */
+ if (req->req.zero) {
+ req->xfer_step = USBF_XFER_SEND_NULL;
+ break;
+ }
+
+ /* No more action to do. Wait for the end of the USB transfer */
+ req->xfer_step = USBF_XFER_WAIT_END;
+ break;
+
+ case USBF_XFER_SEND_NULL:
+ dev_dbg(epn->udc->dev, "ep%u send null\n", epn->id);
+ usbf_epn_send_null(epn);
+ req->xfer_step = USBF_XFER_WAIT_END;
+ break;
+
+ case USBF_XFER_WAIT_END:
+ if (!(epn->status & USBF_EPN_IN_INT)) {
+ dev_dbg(epn->udc->dev, "ep%u end not done\n", epn->id);
+ break;
+ }
+ dev_dbg(epn->udc->dev, "ep%u send done %u/%u\n", epn->id,
+ req->req.actual, req->req.length);
+ req->xfer_step = USBF_XFER_START;
+ return 0;
+ }
+
+ return -EINPROGRESS;
+}
+
+static void usbf_epn_recv_residue(struct usbf_ep *epn, void *buf,
+ unsigned int size)
+{
+ u32 last;
+
+ last = usbf_ep_reg_readl(epn, USBF_REG_EPN_READ);
+ memcpy(buf, &last, size);
+}
+
+static int usbf_epn_pio_out(struct usbf_ep *epn, struct usbf_req *req)
+{
+ int req_status = 0;
+ unsigned int count;
+ unsigned int recv;
+ unsigned int left;
+ unsigned int nb;
+ void *buf;
+
+ if (epn->status & USBF_EPN_OUT_INT) {
+ recv = USBF_EPN_GET_LDATA(
+ usbf_ep_reg_readl(epn, USBF_REG_EPN_LEN_DCNT));
+ count = recv;
+
+ buf = req->req.buf;
+ buf += req->req.actual;
+
+ left = req->req.length - req->req.actual;
+
+ dev_dbg(epn->udc->dev, "ep%u recv %u, left %u, mpkt %u\n", epn->id,
+ recv, left, epn->ep.maxpacket);
+
+ if (left > epn->ep.maxpacket)
+ left = epn->ep.maxpacket;
+
+ if (count > left) {
+ req_status = -EOVERFLOW;
+ count = left;
+ }
+
+ if (count) {
+ nb = count / sizeof(u32);
+ if (nb) {
+ usbf_ep_reg_read_rep(epn, USBF_REG_EPN_READ,
+ buf, nb);
+ buf += (nb * sizeof(u32));
+ req->req.actual += (nb * sizeof(u32));
+ count -= (nb * sizeof(u32));
+ }
+ if (count) {
+ usbf_epn_recv_residue(epn, buf, count);
+ req->req.actual += count;
+ }
+ }
+ dev_dbg(epn->udc->dev, "ep%u recv %u/%u\n", epn->id,
+ req->req.actual, req->req.length);
+
+ if (req_status) {
+ dev_dbg(epn->udc->dev, "ep%u req.status=%d\n", epn->id,
+ req_status);
+ req->req.status = req_status;
+ return 0;
+ }
+
+ if (recv < epn->ep.maxpacket) {
+ dev_dbg(epn->udc->dev, "ep%u short packet\n", epn->id);
+ /* This is a short packet -> It is the end */
+ req->req.status = 0;
+ return 0;
+ }
+
+ /* Request full -> complete */
+ if (req->req.actual == req->req.length) {
+ req->req.status = 0;
+ return 0;
+ }
+ }
+
+ if (epn->status & USBF_EPN_OUT_NULL_INT) {
+ /* NULL packet received */
+ dev_dbg(epn->udc->dev, "ep%u null packet\n", epn->id);
+ if (req->req.actual != req->req.length) {
+ req->req.status = req->req.short_not_ok ?
+ -EREMOTEIO : 0;
+ } else {
+ req->req.status = 0;
+ }
+ return 0;
+ }
+
+ return -EINPROGRESS;
+}
+
+static void usbf_epn_enable_out_end_int(struct usbf_ep *epn)
+{
+ usbf_ep_reg_bitset(epn, USBF_REG_EPN_INT_ENA, USBF_EPN_OUT_END_EN);
+}
+
+static void usbf_epn_process_queue(struct usbf_ep *epn);
+
+static void usbf_epn_dma_out_send_dma(struct usbf_ep *epn, dma_addr_t addr, u32 npkt, bool is_short)
+{
+ usbf_ep_dma_reg_writel(epn, USBF_REG_DMA_EPN_DCR2, USBF_SYS_EPN_MPKT(epn->ep.maxpacket));
+ usbf_ep_dma_reg_writel(epn, USBF_REG_DMA_EPN_TADR, addr);
+
+ if (is_short) {
+ usbf_ep_dma_reg_writel(epn, USBF_REG_DMA_EPN_DCR1,
+ USBF_SYS_EPN_SET_DMACNT(1) | USBF_SYS_EPN_DIR0);
+ usbf_ep_dma_reg_bitset(epn, USBF_REG_DMA_EPN_DCR1,
+ USBF_SYS_EPN_REQEN);
+
+ usbf_ep_reg_writel(epn, USBF_REG_EPN_LEN_DCNT,
+ USBF_EPN_SET_DMACNT(0));
+
+ /* The end of DMA transfer at the USBF level needs to be handled
+ * after the detection of the end of DMA transfer at the brige
+ * level.
+ * To force this sequence, enabling the OUT_END interrupt will
+ * be donee by the detection of the end of transfer at bridge
+ * level (ie. bridge interrupt).
+ */
+ usbf_ep_reg_bitclr(epn, USBF_REG_EPN_INT_ENA,
+ USBF_EPN_OUT_EN | USBF_EPN_OUT_NULL_EN | USBF_EPN_OUT_END_EN);
+ epn->bridge_on_dma_end = usbf_epn_enable_out_end_int;
+
+ /* Clear any pending OUT_END interrupt */
+ usbf_ep_reg_writel(epn, USBF_REG_EPN_STATUS,
+ ~(u32)USBF_EPN_OUT_END_INT);
+
+ usbf_ep_reg_writel(epn, USBF_REG_EPN_DMA_CTRL,
+ USBF_EPN_STOP_MODE | USBF_EPN_STOP_SET | USBF_EPN_DMAMODE0);
+ usbf_ep_reg_bitset(epn, USBF_REG_EPN_DMA_CTRL,
+ USBF_EPN_DMA_EN);
+ return;
+ }
+
+ usbf_ep_dma_reg_writel(epn, USBF_REG_DMA_EPN_DCR1,
+ USBF_SYS_EPN_SET_DMACNT(npkt) | USBF_SYS_EPN_DIR0);
+ usbf_ep_dma_reg_bitset(epn, USBF_REG_DMA_EPN_DCR1,
+ USBF_SYS_EPN_REQEN);
+
+ usbf_ep_reg_writel(epn, USBF_REG_EPN_LEN_DCNT,
+ USBF_EPN_SET_DMACNT(npkt));
+
+ /* Here, the bridge may or may not generate an interrupt to signal the
+ * end of DMA transfer.
+ * Keep only OUT_END interrupt and let handle the bridge later during
+ * the OUT_END processing.
+ */
+ usbf_ep_reg_clrset(epn, USBF_REG_EPN_INT_ENA,
+ USBF_EPN_OUT_EN | USBF_EPN_OUT_NULL_EN,
+ USBF_EPN_OUT_END_EN);
+
+ /* Disable bridge interrupt. It will be renabled later */
+ usbf_reg_bitclr(epn->udc, USBF_REG_AHBBINTEN,
+ USBF_SYS_DMA_ENDINTEN_EPN(epn->id));
+
+ /* Clear any pending DMA_END interrupt at bridge level */
+ usbf_reg_writel(epn->udc, USBF_REG_AHBBINT,
+ USBF_SYS_DMA_ENDINT_EPN(epn->id));
+
+ /* Clear any pending OUT_END interrupt */
+ usbf_ep_reg_writel(epn, USBF_REG_EPN_STATUS,
+ ~(u32)USBF_EPN_OUT_END_INT);
+
+ usbf_ep_reg_writel(epn, USBF_REG_EPN_DMA_CTRL,
+ USBF_EPN_STOP_MODE | USBF_EPN_STOP_SET | USBF_EPN_DMAMODE0 | USBF_EPN_BURST_SET);
+ usbf_ep_reg_bitset(epn, USBF_REG_EPN_DMA_CTRL,
+ USBF_EPN_DMA_EN);
+}
+
+static size_t usbf_epn_dma_out_complete_dma(struct usbf_ep *epn, bool is_short)
+{
+ u32 dmacnt;
+ u32 tmp;
+ int ret;
+
+ /* Restore interrupt mask */
+ usbf_ep_reg_clrset(epn, USBF_REG_EPN_INT_ENA,
+ USBF_EPN_OUT_END_EN,
+ USBF_EPN_OUT_EN | USBF_EPN_OUT_NULL_EN);
+
+ if (is_short) {
+ /* Nothing more to do when the DMA was for a short packet */
+ return 0;
+ }
+
+ /* Enable the bridge interrupt */
+ usbf_reg_bitset(epn->udc, USBF_REG_AHBBINTEN,
+ USBF_SYS_DMA_ENDINTEN_EPN(epn->id));
+
+ tmp = usbf_ep_reg_readl(epn, USBF_REG_EPN_LEN_DCNT);
+ dmacnt = USBF_EPN_GET_DMACNT(tmp);
+
+ if (dmacnt) {
+ /* Some packet were not received (halted by a short or a null
+ * packet.
+ * The bridge never raises an interrupt in this case.
+ * Wait for the end of transfer at bridge level
+ */
+ ret = readl_poll_timeout_atomic(
+ epn->dma_regs + USBF_REG_DMA_EPN_DCR1,
+ tmp, (USBF_SYS_EPN_GET_DMACNT(tmp) == dmacnt),
+ 0, 10000);
+ if (ret) {
+ dev_err(epn->udc->dev, "ep%u wait bridge timed out\n",
+ epn->id);
+ }
+
+ usbf_ep_dma_reg_bitclr(epn, USBF_REG_DMA_EPN_DCR1,
+ USBF_SYS_EPN_REQEN);
+
+ /* The dmacnt value tells how many packet were not transferred
+ * from the maximum number of packet we set for the DMA transfer.
+ * Compute the left DMA size based on this value.
+ */
+ return dmacnt * epn->ep.maxpacket;
+ }
+
+ return 0;
+}
+
+static int usbf_epn_dma_out(struct usbf_ep *epn, struct usbf_req *req)
+{
+ unsigned int dma_left;
+ unsigned int count;
+ unsigned int recv;
+ unsigned int left;
+ u32 npkt;
+ int ret;
+
+ if (!IS_ALIGNED((uintptr_t)req->req.buf, 4)) {
+ dev_dbg(epn->udc->dev, "ep%u buf unaligned -> fallback pio\n",
+ epn->id);
+ return usbf_epn_pio_out(epn, req);
+ }
+
+ switch (req->xfer_step) {
+ default:
+ case USBF_XFER_START:
+ if (epn->status & USBF_EPN_OUT_NULL_INT) {
+ dev_dbg(epn->udc->dev, "ep%u null packet\n", epn->id);
+ if (req->req.actual != req->req.length) {
+ req->req.status = req->req.short_not_ok ?
+ -EREMOTEIO : 0;
+ } else {
+ req->req.status = 0;
+ }
+ return 0;
+ }
+
+ if (!(epn->status & USBF_EPN_OUT_INT)) {
+ dev_dbg(epn->udc->dev, "ep%u OUT_INT not set -> spurious\n",
+ epn->id);
+ break;
+ }
+
+ recv = USBF_EPN_GET_LDATA(
+ usbf_ep_reg_readl(epn, USBF_REG_EPN_LEN_DCNT));
+ if (!recv) {
+ dev_dbg(epn->udc->dev, "ep%u recv = 0 -> spurious\n",
+ epn->id);
+ break;
+ }
+
+ left = req->req.length - req->req.actual;
+
+ dev_dbg(epn->udc->dev, "ep%u recv %u, left %u, mpkt %u\n", epn->id,
+ recv, left, epn->ep.maxpacket);
+
+ if (recv > left) {
+ dev_err(epn->udc->dev, "ep%u overflow (%u/%u)\n",
+ epn->id, recv, left);
+ req->req.status = -EOVERFLOW;
+ return -EOVERFLOW;
+ }
+
+ if (recv < epn->ep.maxpacket) {
+ /* Short packet received */
+ dev_dbg(epn->udc->dev, "ep%u short packet\n", epn->id);
+ if (recv <= 3) {
+ usbf_epn_recv_residue(epn,
+ req->req.buf + req->req.actual, recv);
+ req->req.actual += recv;
+
+ dev_dbg(epn->udc->dev, "ep%u recv done %u/%u\n",
+ epn->id, req->req.actual, req->req.length);
+
+ req->xfer_step = USBF_XFER_START;
+ return 0;
+ }
+
+ ret = usb_gadget_map_request(&epn->udc->gadget, &req->req, 0);
+ if (ret < 0) {
+ dev_err(epn->udc->dev, "map request failed (%d)\n",
+ ret);
+ return ret;
+ }
+ req->is_mapped = 1;
+
+ usbf_epn_dma_out_send_dma(epn,
+ req->req.dma + req->req.actual,
+ 1, true);
+ req->dma_size = recv & ~0x3;
+
+ dev_dbg(epn->udc->dev, "ep%u dma short xfer %zu\n", epn->id,
+ req->dma_size);
+
+ req->xfer_step = USBF_XFER_WAIT_DMA_SHORT;
+ break;
+ }
+
+ ret = usb_gadget_map_request(&epn->udc->gadget, &req->req, 0);
+ if (ret < 0) {
+ dev_err(epn->udc->dev, "map request failed (%d)\n",
+ ret);
+ return ret;
+ }
+ req->is_mapped = 1;
+
+ /* Use the maximum DMA size according to the request buffer.
+ * We will adjust the received size later at the end of the DMA
+ * transfer with the left size computed from
+ * usbf_epn_dma_out_complete_dma().
+ */
+ npkt = left / epn->ep.maxpacket;
+ usbf_epn_dma_out_send_dma(epn,
+ req->req.dma + req->req.actual,
+ npkt, false);
+ req->dma_size = npkt * epn->ep.maxpacket;
+
+ dev_dbg(epn->udc->dev, "ep%u dma xfer %zu (%u)\n", epn->id,
+ req->dma_size, npkt);
+
+ req->xfer_step = USBF_XFER_WAIT_DMA;
+ break;
+
+ case USBF_XFER_WAIT_DMA_SHORT:
+ if (!(epn->status & USBF_EPN_OUT_END_INT)) {
+ dev_dbg(epn->udc->dev, "ep%u dma short not done\n", epn->id);
+ break;
+ }
+ dev_dbg(epn->udc->dev, "ep%u dma short done\n", epn->id);
+
+ usbf_epn_dma_out_complete_dma(epn, true);
+
+ usb_gadget_unmap_request(&epn->udc->gadget, &req->req, 0);
+ req->is_mapped = 0;
+
+ req->req.actual += req->dma_size;
+
+ recv = USBF_EPN_GET_LDATA(
+ usbf_ep_reg_readl(epn, USBF_REG_EPN_LEN_DCNT));
+
+ count = recv & 0x3;
+ if (count) {
+ dev_dbg(epn->udc->dev, "ep%u recv residue %u\n", epn->id,
+ count);
+ usbf_epn_recv_residue(epn,
+ req->req.buf + req->req.actual, count);
+ req->req.actual += count;
+ }
+
+ dev_dbg(epn->udc->dev, "ep%u recv done %u/%u\n", epn->id,
+ req->req.actual, req->req.length);
+
+ req->xfer_step = USBF_XFER_START;
+ return 0;
+
+ case USBF_XFER_WAIT_DMA:
+ if (!(epn->status & USBF_EPN_OUT_END_INT)) {
+ dev_dbg(epn->udc->dev, "ep%u dma not done\n", epn->id);
+ break;
+ }
+ dev_dbg(epn->udc->dev, "ep%u dma done\n", epn->id);
+
+ dma_left = usbf_epn_dma_out_complete_dma(epn, false);
+ if (dma_left) {
+ /* Adjust the final DMA size with */
+ count = req->dma_size - dma_left;
+
+ dev_dbg(epn->udc->dev, "ep%u dma xfer done %u\n", epn->id,
+ count);
+
+ req->req.actual += count;
+
+ if (epn->status & USBF_EPN_OUT_NULL_INT) {
+ /* DMA was stopped by a null packet reception */
+ dev_dbg(epn->udc->dev, "ep%u dma stopped by null pckt\n",
+ epn->id);
+ usb_gadget_unmap_request(&epn->udc->gadget,
+ &req->req, 0);
+ req->is_mapped = 0;
+
+ usbf_ep_reg_writel(epn, USBF_REG_EPN_STATUS,
+ ~(u32)USBF_EPN_OUT_NULL_INT);
+
+ if (req->req.actual != req->req.length) {
+ req->req.status = req->req.short_not_ok ?
+ -EREMOTEIO : 0;
+ } else {
+ req->req.status = 0;
+ }
+ dev_dbg(epn->udc->dev, "ep%u recv done %u/%u\n",
+ epn->id, req->req.actual, req->req.length);
+ req->xfer_step = USBF_XFER_START;
+ return 0;
+ }
+
+ recv = USBF_EPN_GET_LDATA(
+ usbf_ep_reg_readl(epn, USBF_REG_EPN_LEN_DCNT));
+ left = req->req.length - req->req.actual;
+ if (recv > left) {
+ dev_err(epn->udc->dev,
+ "ep%u overflow (%u/%u)\n", epn->id,
+ recv, left);
+ req->req.status = -EOVERFLOW;
+ usb_gadget_unmap_request(&epn->udc->gadget,
+ &req->req, 0);
+ req->is_mapped = 0;
+
+ req->xfer_step = USBF_XFER_START;
+ return -EOVERFLOW;
+ }
+
+ if (recv > 3) {
+ usbf_epn_dma_out_send_dma(epn,
+ req->req.dma + req->req.actual,
+ 1, true);
+ req->dma_size = recv & ~0x3;
+
+ dev_dbg(epn->udc->dev, "ep%u dma short xfer %zu\n",
+ epn->id, req->dma_size);
+
+ req->xfer_step = USBF_XFER_WAIT_DMA_SHORT;
+ break;
+ }
+
+ usb_gadget_unmap_request(&epn->udc->gadget, &req->req, 0);
+ req->is_mapped = 0;
+
+ count = recv & 0x3;
+ if (count) {
+ dev_dbg(epn->udc->dev, "ep%u recv residue %u\n",
+ epn->id, count);
+ usbf_epn_recv_residue(epn,
+ req->req.buf + req->req.actual, count);
+ req->req.actual += count;
+ }
+
+ dev_dbg(epn->udc->dev, "ep%u recv done %u/%u\n", epn->id,
+ req->req.actual, req->req.length);
+
+ req->xfer_step = USBF_XFER_START;
+ return 0;
+ }
+
+ /* Process queue at bridge interrupt only */
+ usbf_ep_reg_bitclr(epn, USBF_REG_EPN_INT_ENA,
+ USBF_EPN_OUT_END_EN | USBF_EPN_OUT_EN | USBF_EPN_OUT_NULL_EN);
+ epn->status = 0;
+ epn->bridge_on_dma_end = usbf_epn_process_queue;
+
+ req->xfer_step = USBF_XFER_WAIT_BRIDGE;
+ break;
+
+ case USBF_XFER_WAIT_BRIDGE:
+ dev_dbg(epn->udc->dev, "ep%u bridge transfers done\n", epn->id);
+
+ /* Restore interrupt mask */
+ usbf_ep_reg_clrset(epn, USBF_REG_EPN_INT_ENA,
+ USBF_EPN_OUT_END_EN,
+ USBF_EPN_OUT_EN | USBF_EPN_OUT_NULL_EN);
+
+ usb_gadget_unmap_request(&epn->udc->gadget, &req->req, 0);
+ req->is_mapped = 0;
+
+ req->req.actual += req->dma_size;
+
+ req->xfer_step = USBF_XFER_START;
+ left = req->req.length - req->req.actual;
+ if (!left) {
+ /* No more data can be added to the buffer */
+ dev_dbg(epn->udc->dev, "ep%u recv done %u/%u\n", epn->id,
+ req->req.actual, req->req.length);
+ return 0;
+ }
+ dev_dbg(epn->udc->dev, "ep%u recv done %u/%u, wait more data\n",
+ epn->id, req->req.actual, req->req.length);
+ break;
+ }
+
+ return -EINPROGRESS;
+}
+
+static void usbf_epn_dma_stop(struct usbf_ep *epn)
+{
+ usbf_ep_dma_reg_bitclr(epn, USBF_REG_DMA_EPN_DCR1, USBF_SYS_EPN_REQEN);
+
+ /* In the datasheet:
+ * If EP[m]_REQEN = 0b is set during DMA transfer, AHB-EPC stops DMA
+ * after 1 packet transfer completed.
+ * Therefore, wait sufficient time for ensuring DMA transfer
+ * completion. The WAIT time depends on the system, especially AHB
+ * bus activity
+ * So arbitrary 10ms would be sufficient.
+ */
+ mdelay(10);
+
+ usbf_ep_reg_bitclr(epn, USBF_REG_EPN_DMA_CTRL, USBF_EPN_DMA_EN);
+}
+
+static void usbf_epn_dma_abort(struct usbf_ep *epn, struct usbf_req *req)
+{
+ dev_dbg(epn->udc->dev, "ep%u %s dma abort\n", epn->id,
+ epn->is_in ? "in" : "out");
+
+ epn->bridge_on_dma_end = NULL;
+
+ usbf_epn_dma_stop(epn);
+
+ usb_gadget_unmap_request(&epn->udc->gadget, &req->req,
+ epn->is_in ? 1 : 0);
+ req->is_mapped = 0;
+
+ usbf_ep_reg_bitclr(epn, USBF_REG_EPN_CONTROL, USBF_EPN_AUTO);
+
+ if (epn->is_in) {
+ usbf_ep_reg_clrset(epn, USBF_REG_EPN_INT_ENA,
+ USBF_EPN_IN_END_EN,
+ USBF_EPN_IN_EN);
+ } else {
+ usbf_ep_reg_clrset(epn, USBF_REG_EPN_INT_ENA,
+ USBF_EPN_OUT_END_EN,
+ USBF_EPN_OUT_EN | USBF_EPN_OUT_NULL_EN);
+ }
+
+ /* As dma is stopped, be sure that no DMA interrupt are pending */
+ usbf_ep_reg_writel(epn, USBF_REG_EPN_STATUS,
+ USBF_EPN_IN_END_INT | USBF_EPN_OUT_END_INT);
+
+ usbf_reg_writel(epn->udc, USBF_REG_AHBBINT, USBF_SYS_DMA_ENDINT_EPN(epn->id));
+
+ /* Enable DMA interrupt the bridge level */
+ usbf_reg_bitset(epn->udc, USBF_REG_AHBBINTEN,
+ USBF_SYS_DMA_ENDINTEN_EPN(epn->id));
+
+ /* Reset transfer step */
+ req->xfer_step = USBF_XFER_START;
+}
+
+static void usbf_epn_fifo_flush(struct usbf_ep *epn)
+{
+ u32 ctrl;
+ u32 sts;
+ int ret;
+
+ dev_dbg(epn->udc->dev, "ep%u %s fifo flush\n", epn->id,
+ epn->is_in ? "in" : "out");
+
+ ctrl = usbf_ep_reg_readl(epn, USBF_REG_EPN_CONTROL);
+ usbf_ep_reg_writel(epn, USBF_REG_EPN_CONTROL, ctrl | USBF_EPN_BCLR);
+
+ if (ctrl & USBF_EPN_DIR0)
+ return;
+
+ ret = readl_poll_timeout_atomic(epn->regs + USBF_REG_EPN_STATUS, sts,
+ (sts & (USBF_EPN_IN_DATA | USBF_EPN_IN_EMPTY)) == USBF_EPN_IN_EMPTY,
+ 0, 10000);
+ if (ret)
+ dev_err(epn->udc->dev, "ep%u flush fifo timed out\n", epn->id);
+}
+
+static void usbf_ep_req_done(struct usbf_ep *ep, struct usbf_req *req,
+ int status)
+{
+ list_del_init(&req->queue);
+
+ if (status) {
+ req->req.status = status;
+ } else {
+ if (req->req.status == -EINPROGRESS)
+ req->req.status = status;
+ }
+
+ dev_dbg(ep->udc->dev, "ep%u %s req done length %u/%u, status=%d\n", ep->id,
+ ep->is_in ? "in" : "out",
+ req->req.actual, req->req.length, req->req.status);
+
+ if (req->is_mapped)
+ usbf_epn_dma_abort(ep, req);
+
+ spin_unlock(&ep->udc->lock);
+ usb_gadget_giveback_request(&ep->ep, &req->req);
+ spin_lock(&ep->udc->lock);
+}
+
+static void usbf_ep_nuke(struct usbf_ep *ep, int status)
+{
+ struct usbf_req *req;
+
+ dev_dbg(ep->udc->dev, "ep%u %s nuke status %d\n", ep->id,
+ ep->is_in ? "in" : "out",
+ status);
+
+ while (!list_empty(&ep->queue)) {
+ req = list_first_entry(&ep->queue, struct usbf_req, queue);
+ usbf_ep_req_done(ep, req, status);
+ }
+
+ if (ep->id == 0)
+ usbf_ep0_fifo_flush(ep);
+ else
+ usbf_epn_fifo_flush(ep);
+}
+
+static bool usbf_ep_is_stalled(struct usbf_ep *ep)
+{
+ u32 ctrl;
+
+ if (ep->id == 0) {
+ ctrl = usbf_ep_reg_readl(ep, USBF_REG_EP0_CONTROL);
+ return (ctrl & USBF_EP0_STL) ? true : false;
+ }
+
+ ctrl = usbf_ep_reg_readl(ep, USBF_REG_EPN_CONTROL);
+ if (ep->is_in)
+ return (ctrl & USBF_EPN_ISTL) ? true : false;
+
+ return (ctrl & USBF_EPN_OSTL) ? true : false;
+}
+
+static int usbf_epn_start_queue(struct usbf_ep *epn)
+{
+ struct usbf_req *req;
+ int ret;
+
+ if (usbf_ep_is_stalled(epn))
+ return 0;
+
+ req = list_first_entry_or_null(&epn->queue, struct usbf_req, queue);
+
+ if (epn->is_in) {
+ if (req && !epn->is_processing) {
+ ret = epn->dma_regs ?
+ usbf_epn_dma_in(epn, req) :
+ usbf_epn_pio_in(epn, req);
+ if (ret != -EINPROGRESS) {
+ dev_err(epn->udc->dev,
+ "queued next request not in progress\n");
+ /* The request cannot be completed (ie
+ * ret == 0) on the first call.
+ * stall and nuke the endpoint
+ */
+ return ret ? ret : -EIO;
+ }
+ }
+ } else {
+ if (req) {
+ /* Clear ONAK to accept OUT tokens */
+ usbf_ep_reg_bitclr(epn, USBF_REG_EPN_CONTROL,
+ USBF_EPN_ONAK);
+
+ /* Enable interrupts */
+ usbf_ep_reg_bitset(epn, USBF_REG_EPN_INT_ENA,
+ USBF_EPN_OUT_INT | USBF_EPN_OUT_NULL_INT);
+ } else {
+ /* Disable incoming data and interrupt.
+ * They will be enable on next usb_eb_queue call
+ */
+ usbf_ep_reg_bitset(epn, USBF_REG_EPN_CONTROL,
+ USBF_EPN_ONAK);
+ usbf_ep_reg_bitclr(epn, USBF_REG_EPN_INT_ENA,
+ USBF_EPN_OUT_INT | USBF_EPN_OUT_NULL_INT);
+ }
+ }
+ return 0;
+}
+
+static int usbf_ep_process_queue(struct usbf_ep *ep)
+{
+ int (*usbf_ep_xfer)(struct usbf_ep *ep, struct usbf_req *req);
+ struct usbf_req *req;
+ int is_processing;
+ int ret;
+
+ if (ep->is_in) {
+ usbf_ep_xfer = usbf_ep0_pio_in;
+ if (ep->id) {
+ usbf_ep_xfer = ep->dma_regs ?
+ usbf_epn_dma_in : usbf_epn_pio_in;
+ }
+ } else {
+ usbf_ep_xfer = usbf_ep0_pio_out;
+ if (ep->id) {
+ usbf_ep_xfer = ep->dma_regs ?
+ usbf_epn_dma_out : usbf_epn_pio_out;
+ }
+ }
+
+ req = list_first_entry_or_null(&ep->queue, struct usbf_req, queue);
+ if (!req) {
+ dev_err(ep->udc->dev,
+ "no request available for ep%u %s process\n", ep->id,
+ ep->is_in ? "in" : "out");
+ return -ENOENT;
+ }
+
+ do {
+ /* Were going to read the FIFO for this current request.
+ * NAK any other incoming data to avoid a race condition if no
+ * more request are available.
+ */
+ if (!ep->is_in && ep->id != 0) {
+ usbf_ep_reg_bitset(ep, USBF_REG_EPN_CONTROL,
+ USBF_EPN_ONAK);
+ }
+
+ ret = usbf_ep_xfer(ep, req);
+ if (ret == -EINPROGRESS) {
+ if (!ep->is_in && ep->id != 0) {
+ /* The current request needs more data.
+ * Allow incoming data
+ */
+ usbf_ep_reg_bitclr(ep, USBF_REG_EPN_CONTROL,
+ USBF_EPN_ONAK);
+ }
+ return ret;
+ }
+
+ is_processing = ep->is_processing;
+ ep->is_processing = 1;
+ usbf_ep_req_done(ep, req, ret);
+ ep->is_processing = is_processing;
+
+ if (ret) {
+ /* An error was detected during the request transfer.
+ * Any pending DMA transfers were aborted by the
+ * usbf_ep_req_done() call.
+ * It's time to flush the fifo
+ */
+ if (ep->id == 0)
+ usbf_ep0_fifo_flush(ep);
+ else
+ usbf_epn_fifo_flush(ep);
+ }
+
+ req = list_first_entry_or_null(&ep->queue, struct usbf_req,
+ queue);
+
+ if (ep->is_in)
+ continue;
+
+ if (ep->id != 0) {
+ if (req) {
+ /* An other request is available.
+ * Allow incoming data
+ */
+ usbf_ep_reg_bitclr(ep, USBF_REG_EPN_CONTROL,
+ USBF_EPN_ONAK);
+ } else {
+ /* No request queued. Disable interrupts.
+ * They will be enabled on usb_ep_queue
+ */
+ usbf_ep_reg_bitclr(ep, USBF_REG_EPN_INT_ENA,
+ USBF_EPN_OUT_INT | USBF_EPN_OUT_NULL_INT);
+ }
+ }
+ /* Do not recall usbf_ep_xfer() */
+ return req ? -EINPROGRESS : 0;
+
+ } while (req);
+
+ return 0;
+}
+
+static void usbf_ep_stall(struct usbf_ep *ep, bool stall)
+{
+ struct usbf_req *first;
+
+ dev_dbg(ep->udc->dev, "ep%u %s %s\n", ep->id,
+ ep->is_in ? "in" : "out",
+ stall ? "stall" : "unstall");
+
+ if (ep->id == 0) {
+ if (stall)
+ usbf_ep_reg_bitset(ep, USBF_REG_EP0_CONTROL, USBF_EP0_STL);
+ else
+ usbf_ep_reg_bitclr(ep, USBF_REG_EP0_CONTROL, USBF_EP0_STL);
+ return;
+ }
+
+ if (stall) {
+ if (ep->is_in)
+ usbf_ep_reg_bitset(ep, USBF_REG_EPN_CONTROL,
+ USBF_EPN_ISTL);
+ else
+ usbf_ep_reg_bitset(ep, USBF_REG_EPN_CONTROL,
+ USBF_EPN_OSTL | USBF_EPN_OSTL_EN);
+ } else {
+ first = list_first_entry_or_null(&ep->queue, struct usbf_req, queue);
+ if (first && first->is_mapped) {
+ /* This can appear if the host halts an endpoint using
+ * SET_FEATURE and then un-halts the endpoint
+ */
+ usbf_epn_dma_abort(ep, first);
+ }
+ usbf_epn_fifo_flush(ep);
+ if (ep->is_in) {
+ usbf_ep_reg_clrset(ep, USBF_REG_EPN_CONTROL,
+ USBF_EPN_ISTL,
+ USBF_EPN_IPIDCLR);
+ } else {
+ usbf_ep_reg_clrset(ep, USBF_REG_EPN_CONTROL,
+ USBF_EPN_OSTL,
+ USBF_EPN_OSTL_EN | USBF_EPN_OPIDCLR);
+ }
+ usbf_epn_start_queue(ep);
+ }
+}
+
+static void usbf_ep0_enable(struct usbf_ep *ep0)
+{
+ usbf_ep_reg_writel(ep0, USBF_REG_EP0_CONTROL, USBF_EP0_INAK_EN | USBF_EP0_BCLR);
+
+ usbf_ep_reg_writel(ep0, USBF_REG_EP0_INT_ENA,
+ USBF_EP0_SETUP_EN | USBF_EP0_STG_START_EN | USBF_EP0_STG_END_EN |
+ USBF_EP0_OUT_EN | USBF_EP0_OUT_NULL_EN | USBF_EP0_IN_EN);
+
+ ep0->udc->ep0state = EP0_IDLE;
+ ep0->disabled = 0;
+
+ /* enable interrupts for the ep0 */
+ usbf_reg_bitset(ep0->udc, USBF_REG_USB_INT_ENA, USBF_USB_EPN_EN(0));
+}
+
+static int usbf_epn_enable(struct usbf_ep *epn)
+{
+ u32 base_addr;
+ u32 ctrl;
+
+ base_addr = usbf_ep_info[epn->id].base_addr;
+ usbf_ep_reg_writel(epn, USBF_REG_EPN_PCKT_ADRS,
+ USBF_EPN_BASEAD(base_addr) | USBF_EPN_MPKT(epn->ep.maxpacket));
+
+ /* OUT transfer interrupt are enabled during usb_ep_queue */
+ if (epn->is_in) {
+ /* Will be changed in DMA processing */
+ usbf_ep_reg_writel(epn, USBF_REG_EPN_INT_ENA, USBF_EPN_IN_EN);
+ }
+
+ /* Clear, set endpoint direction, set IN/OUT STL, and enable
+ * Send NAK for Data out as request are not queued yet
+ */
+ ctrl = USBF_EPN_EN | USBF_EPN_BCLR;
+ if (epn->is_in)
+ ctrl |= USBF_EPN_OSTL | USBF_EPN_OSTL_EN;
+ else
+ ctrl |= USBF_EPN_DIR0 | USBF_EPN_ISTL | USBF_EPN_OSTL_EN | USBF_EPN_ONAK;
+ usbf_ep_reg_writel(epn, USBF_REG_EPN_CONTROL, ctrl);
+
+ return 0;
+}
+
+static int usbf_ep_enable(struct usb_ep *_ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct usbf_ep *ep = container_of(_ep, struct usbf_ep, ep);
+ struct usbf_udc *udc = ep->udc;
+ unsigned long flags;
+ int ret;
+
+ if (ep->id == 0)
+ return -EINVAL;
+
+ if (!desc || desc->bDescriptorType != USB_DT_ENDPOINT)
+ return -EINVAL;
+
+ dev_dbg(ep->udc->dev, "ep%u %s mpkts %d\n", ep->id,
+ usb_endpoint_dir_in(desc) ? "in" : "out",
+ usb_endpoint_maxp(desc));
+
+ spin_lock_irqsave(&ep->udc->lock, flags);
+ ep->is_in = usb_endpoint_dir_in(desc);
+ ep->ep.maxpacket = usb_endpoint_maxp(desc);
+
+ ret = usbf_epn_enable(ep);
+ if (ret)
+ goto end;
+
+ ep->disabled = 0;
+
+ /* enable interrupts for this endpoint */
+ usbf_reg_bitset(udc, USBF_REG_USB_INT_ENA, USBF_USB_EPN_EN(ep->id));
+
+ /* enable DMA interrupt at bridge level if DMA is used */
+ if (ep->dma_regs) {
+ ep->bridge_on_dma_end = NULL;
+ usbf_reg_bitset(udc, USBF_REG_AHBBINTEN,
+ USBF_SYS_DMA_ENDINTEN_EPN(ep->id));
+ }
+
+ ret = 0;
+end:
+ spin_unlock_irqrestore(&ep->udc->lock, flags);
+ return ret;
+}
+
+static int usbf_epn_disable(struct usbf_ep *epn)
+{
+ /* Disable interrupts */
+ usbf_ep_reg_writel(epn, USBF_REG_EPN_INT_ENA, 0);
+
+ /* Disable endpoint */
+ usbf_ep_reg_bitclr(epn, USBF_REG_EPN_CONTROL, USBF_EPN_EN);
+
+ /* remove anything that was pending */
+ usbf_ep_nuke(epn, -ESHUTDOWN);
+
+ return 0;
+}
+
+static int usbf_ep_disable(struct usb_ep *_ep)
+{
+ struct usbf_ep *ep = container_of(_ep, struct usbf_ep, ep);
+ struct usbf_udc *udc = ep->udc;
+ unsigned long flags;
+ int ret;
+
+ if (ep->id == 0)
+ return -EINVAL;
+
+ dev_dbg(ep->udc->dev, "ep%u %s mpkts %d\n", ep->id,
+ ep->is_in ? "in" : "out", ep->ep.maxpacket);
+
+ spin_lock_irqsave(&ep->udc->lock, flags);
+ ep->disabled = 1;
+ /* Disable DMA interrupt */
+ if (ep->dma_regs) {
+ usbf_reg_bitclr(udc, USBF_REG_AHBBINTEN,
+ USBF_SYS_DMA_ENDINTEN_EPN(ep->id));
+ ep->bridge_on_dma_end = NULL;
+ }
+ /* disable interrupts for this endpoint */
+ usbf_reg_bitclr(udc, USBF_REG_USB_INT_ENA, USBF_USB_EPN_EN(ep->id));
+ /* and the endpoint itself */
+ ret = usbf_epn_disable(ep);
+ spin_unlock_irqrestore(&ep->udc->lock, flags);
+
+ return ret;
+}
+
+static int usbf_ep0_queue(struct usbf_ep *ep0, struct usbf_req *req,
+ gfp_t gfp_flags)
+{
+ int ret;
+
+ req->req.actual = 0;
+ req->req.status = -EINPROGRESS;
+ req->is_zero_sent = 0;
+
+ list_add_tail(&req->queue, &ep0->queue);
+
+ if (ep0->udc->ep0state == EP0_IN_STATUS_START_PHASE)
+ return 0;
+
+ if (!ep0->is_in)
+ return 0;
+
+ if (ep0->udc->ep0state == EP0_IN_STATUS_PHASE) {
+ if (req->req.length) {
+ dev_err(ep0->udc->dev,
+ "request lng %u for ep0 in status phase\n",
+ req->req.length);
+ return -EINVAL;
+ }
+ ep0->delayed_status = 0;
+ }
+ if (!ep0->is_processing) {
+ ret = usbf_ep0_pio_in(ep0, req);
+ if (ret != -EINPROGRESS) {
+ dev_err(ep0->udc->dev,
+ "queued request not in progress\n");
+ /* The request cannot be completed (ie
+ * ret == 0) on the first call
+ */
+ return ret ? ret : -EIO;
+ }
+ }
+
+ return 0;
+}
+
+static int usbf_epn_queue(struct usbf_ep *ep, struct usbf_req *req,
+ gfp_t gfp_flags)
+{
+ int was_empty;
+ int ret;
+
+ if (ep->disabled) {
+ dev_err(ep->udc->dev, "ep%u request queue while disable\n",
+ ep->id);
+ return -ESHUTDOWN;
+ }
+
+ req->req.actual = 0;
+ req->req.status = -EINPROGRESS;
+ req->is_zero_sent = 0;
+ req->xfer_step = USBF_XFER_START;
+
+ was_empty = list_empty(&ep->queue);
+ list_add_tail(&req->queue, &ep->queue);
+ if (was_empty) {
+ ret = usbf_epn_start_queue(ep);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+static int usbf_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
+ gfp_t gfp_flags)
+{
+ struct usbf_req *req = container_of(_req, struct usbf_req, req);
+ struct usbf_ep *ep = container_of(_ep, struct usbf_ep, ep);
+ struct usbf_udc *udc = ep->udc;
+ unsigned long flags;
+ int ret;
+
+ if (!_req || !_req->buf)
+ return -EINVAL;
+
+ if (!udc || !udc->driver)
+ return -EINVAL;
+
+ dev_dbg(ep->udc->dev, "ep%u %s req queue length %u, zero %u, short_not_ok %u\n",
+ ep->id, ep->is_in ? "in" : "out",
+ req->req.length, req->req.zero, req->req.short_not_ok);
+
+ spin_lock_irqsave(&ep->udc->lock, flags);
+ if (ep->id == 0)
+ ret = usbf_ep0_queue(ep, req, gfp_flags);
+ else
+ ret = usbf_epn_queue(ep, req, gfp_flags);
+ spin_unlock_irqrestore(&ep->udc->lock, flags);
+ return ret;
+}
+
+static int usbf_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct usbf_req *req = container_of(_req, struct usbf_req, req);
+ struct usbf_ep *ep = container_of(_ep, struct usbf_ep, ep);
+ unsigned long flags;
+ int is_processing;
+ int first;
+ int ret;
+
+ spin_lock_irqsave(&ep->udc->lock, flags);
+
+ dev_dbg(ep->udc->dev, "ep%u %s req dequeue length %u/%u\n",
+ ep->id, ep->is_in ? "in" : "out",
+ req->req.actual, req->req.length);
+
+ first = list_is_first(&req->queue, &ep->queue);
+
+ /* Complete the request but avoid any operation that could be done
+ * if a new request is queued during the request completion
+ */
+ is_processing = ep->is_processing;
+ ep->is_processing = 1;
+ usbf_ep_req_done(ep, req, -ECONNRESET);
+ ep->is_processing = is_processing;
+
+ if (first) {
+ /* The first item in the list was dequeued.
+ * This item could already be submitted to the hardware.
+ * So, flush the fifo
+ */
+ if (ep->id)
+ usbf_epn_fifo_flush(ep);
+ else
+ usbf_ep0_fifo_flush(ep);
+ }
+
+ if (ep->id == 0) {
+ /* We dequeue a request on ep0. On this endpoint, we can have
+ * 1 request related to the data stage and/or 1 request
+ * related to the status stage.
+ * We dequeue one of them and so the USB control transaction
+ * is no more coherent. The simple way to be consistent after
+ * dequeuing is to stall and nuke the endpoint and wait the
+ * next SETUP packet.
+ */
+ usbf_ep_stall(ep, true);
+ usbf_ep_nuke(ep, -ECONNRESET);
+ ep->udc->ep0state = EP0_IDLE;
+ goto end;
+ }
+
+ if (!first)
+ goto end;
+
+ ret = usbf_epn_start_queue(ep);
+ if (ret) {
+ usbf_ep_stall(ep, true);
+ usbf_ep_nuke(ep, -EIO);
+ }
+end:
+ spin_unlock_irqrestore(&ep->udc->lock, flags);
+ return 0;
+}
+
+static struct usb_request *usbf_ep_alloc_request(struct usb_ep *_ep,
+ gfp_t gfp_flags)
+{
+ struct usbf_req *req;
+
+ if (!_ep)
+ return NULL;
+
+ req = kzalloc(sizeof(*req), gfp_flags);
+ if (!req)
+ return NULL;
+
+ INIT_LIST_HEAD(&req->queue);
+
+ return &req->req;
+}
+
+static void usbf_ep_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct usbf_req *req;
+ unsigned long flags;
+ struct usbf_ep *ep;
+
+ if (!_ep || !_req)
+ return;
+
+ req = container_of(_req, struct usbf_req, req);
+ ep = container_of(_ep, struct usbf_ep, ep);
+
+ spin_lock_irqsave(&ep->udc->lock, flags);
+ list_del_init(&req->queue);
+ spin_unlock_irqrestore(&ep->udc->lock, flags);
+ kfree(req);
+}
+
+static int usbf_ep_set_halt(struct usb_ep *_ep, int halt)
+{
+ struct usbf_ep *ep = container_of(_ep, struct usbf_ep, ep);
+ unsigned long flags;
+ int ret;
+
+ if (ep->id == 0)
+ return -EINVAL;
+
+ spin_lock_irqsave(&ep->udc->lock, flags);
+
+ if (!list_empty(&ep->queue)) {
+ ret = -EAGAIN;
+ goto end;
+ }
+
+ usbf_ep_stall(ep, halt);
+ if (!halt)
+ ep->is_wedged = 0;
+
+ ret = 0;
+end:
+ spin_unlock_irqrestore(&ep->udc->lock, flags);
+
+ return ret;
+}
+
+static int usbf_ep_set_wedge(struct usb_ep *_ep)
+{
+ struct usbf_ep *ep = container_of(_ep, struct usbf_ep, ep);
+ unsigned long flags;
+ int ret;
+
+ if (ep->id == 0)
+ return -EINVAL;
+
+ spin_lock_irqsave(&ep->udc->lock, flags);
+ if (!list_empty(&ep->queue)) {
+ ret = -EAGAIN;
+ goto end;
+ }
+ usbf_ep_stall(ep, 1);
+ ep->is_wedged = 1;
+
+ ret = 0;
+end:
+ spin_unlock_irqrestore(&ep->udc->lock, flags);
+ return ret;
+}
+
+static struct usb_ep_ops usbf_ep_ops = {
+ .enable = usbf_ep_enable,
+ .disable = usbf_ep_disable,
+ .queue = usbf_ep_queue,
+ .dequeue = usbf_ep_dequeue,
+ .set_halt = usbf_ep_set_halt,
+ .set_wedge = usbf_ep_set_wedge,
+ .alloc_request = usbf_ep_alloc_request,
+ .free_request = usbf_ep_free_request,
+};
+
+static void usbf_ep0_req_complete(struct usb_ep *_ep, struct usb_request *_req)
+{
+}
+
+static void usbf_ep0_fill_req(struct usbf_ep *ep0, struct usbf_req *req,
+ void *buf, unsigned int length,
+ void (*complete)(struct usb_ep *_ep,
+ struct usb_request *_req))
+{
+ if (buf && length)
+ memcpy(ep0->udc->ep0_buf, buf, length);
+
+ req->req.buf = ep0->udc->ep0_buf;
+ req->req.length = length;
+ req->req.dma = 0;
+ req->req.zero = true;
+ req->req.complete = complete ? complete : usbf_ep0_req_complete;
+ req->req.status = -EINPROGRESS;
+ req->req.context = NULL;
+ req->req.actual = 0;
+}
+
+static struct usbf_ep *usbf_get_ep_by_addr(struct usbf_udc *udc, u8 address)
+{
+ struct usbf_ep *ep;
+ unsigned int i;
+
+ if ((address & USB_ENDPOINT_NUMBER_MASK) == 0)
+ return &udc->ep[0];
+
+ for (i = 1; i < ARRAY_SIZE(udc->ep); i++) {
+ ep = &udc->ep[i];
+
+ if (!ep->ep.desc)
+ continue;
+
+ if (ep->ep.desc->bEndpointAddress == address)
+ return ep;
+ }
+
+ return NULL;
+}
+
+static int usbf_req_delegate(struct usbf_udc *udc,
+ const struct usb_ctrlrequest *ctrlrequest)
+{
+ int ret;
+
+ spin_unlock(&udc->lock);
+ ret = udc->driver->setup(&udc->gadget, ctrlrequest);
+ spin_lock(&udc->lock);
+ if (ret < 0) {
+ dev_dbg(udc->dev, "udc driver setup failed %d\n", ret);
+ return ret;
+ }
+ if (ret == USB_GADGET_DELAYED_STATUS) {
+ dev_dbg(udc->dev, "delayed status set\n");
+ udc->ep[0].delayed_status = 1;
+ return 0;
+ }
+ return ret;
+}
+
+static int usbf_req_get_status(struct usbf_udc *udc,
+ const struct usb_ctrlrequest *ctrlrequest)
+{
+ struct usbf_ep *ep;
+ u16 status_data;
+ u16 wLength;
+ u16 wValue;
+ u16 wIndex;
+
+ wValue = le16_to_cpu(ctrlrequest->wValue);
+ wLength = le16_to_cpu(ctrlrequest->wLength);
+ wIndex = le16_to_cpu(ctrlrequest->wIndex);
+
+ switch (ctrlrequest->bRequestType) {
+ case USB_DIR_IN | USB_RECIP_DEVICE | USB_TYPE_STANDARD:
+ if ((wValue != 0) || (wIndex != 0) || (wLength != 2))
+ goto delegate;
+
+ status_data = 0;
+ if (udc->gadget.is_selfpowered)
+ status_data |= BIT(USB_DEVICE_SELF_POWERED);
+
+ if (udc->is_remote_wakeup)
+ status_data |= BIT(USB_DEVICE_REMOTE_WAKEUP);
+
+ break;
+
+ case USB_DIR_IN | USB_RECIP_ENDPOINT | USB_TYPE_STANDARD:
+ if ((wValue != 0) || (wLength != 2))
+ goto delegate;
+
+ ep = usbf_get_ep_by_addr(udc, wIndex);
+ if (!ep)
+ return -EINVAL;
+
+ status_data = 0;
+ if (usbf_ep_is_stalled(ep))
+ status_data |= cpu_to_le16(1);
+ break;
+
+ case USB_DIR_IN | USB_RECIP_INTERFACE | USB_TYPE_STANDARD:
+ if ((wValue != 0) || (wLength != 2))
+ goto delegate;
+ status_data = 0;
+ break;
+
+ default:
+ goto delegate;
+ }
+
+ usbf_ep0_fill_req(&udc->ep[0], &udc->setup_reply, &status_data,
+ sizeof(status_data), NULL);
+ usbf_ep0_queue(&udc->ep[0], &udc->setup_reply, GFP_ATOMIC);
+
+ return 0;
+
+delegate:
+ return usbf_req_delegate(udc, ctrlrequest);
+}
+
+static int usbf_req_clear_set_feature(struct usbf_udc *udc,
+ const struct usb_ctrlrequest *ctrlrequest,
+ bool is_set)
+{
+ struct usbf_ep *ep;
+ u16 wLength;
+ u16 wValue;
+ u16 wIndex;
+
+ wValue = le16_to_cpu(ctrlrequest->wValue);
+ wLength = le16_to_cpu(ctrlrequest->wLength);
+ wIndex = le16_to_cpu(ctrlrequest->wIndex);
+
+ switch (ctrlrequest->bRequestType) {
+ case USB_DIR_OUT | USB_RECIP_DEVICE:
+ if ((wIndex != 0) || (wLength != 0))
+ goto delegate;
+
+ if (wValue != cpu_to_le16(USB_DEVICE_REMOTE_WAKEUP))
+ goto delegate;
+
+ udc->is_remote_wakeup = is_set;
+ break;
+
+ case USB_DIR_OUT | USB_RECIP_ENDPOINT:
+ if (wLength != 0)
+ goto delegate;
+
+ ep = usbf_get_ep_by_addr(udc, wIndex);
+ if (!ep)
+ return -EINVAL;
+
+ if ((ep->id == 0) && is_set) {
+ /* Endpoint 0 cannot be halted (stalled)
+ * Returning an error code leads to a STALL on this ep0
+ * but keep the automate in a consistent state.
+ */
+ return -EINVAL;
+ }
+ if (ep->is_wedged && !is_set) {
+ /* Ignore CLEAR_FEATURE(HALT ENDPOINT) when the
+ * endpoint is wedged
+ */
+ break;
+ }
+ usbf_ep_stall(ep, is_set);
+ break;
+
+ default:
+ goto delegate;
+ }
+
+ return 0;
+
+delegate:
+ return usbf_req_delegate(udc, ctrlrequest);
+}
+
+static void usbf_ep0_req_set_address_complete(struct usb_ep *_ep,
+ struct usb_request *_req)
+{
+ struct usbf_ep *ep = container_of(_ep, struct usbf_ep, ep);
+
+ /* The status phase of the SET_ADDRESS request is completed ... */
+ if (_req->status == 0) {
+ /* ... without any errors -> Signaled the state to the core. */
+ usb_gadget_set_state(&ep->udc->gadget, USB_STATE_ADDRESS);
+ }
+
+ /* In case of request failure, there is no need to revert the address
+ * value set to the hardware as the hardware will take care of the
+ * value only if the status stage is completed normally.
+ */
+}
+
+static int usbf_req_set_address(struct usbf_udc *udc,
+ const struct usb_ctrlrequest *ctrlrequest)
+{
+ u16 wLength;
+ u16 wValue;
+ u16 wIndex;
+ u32 addr;
+
+ wValue = le16_to_cpu(ctrlrequest->wValue);
+ wLength = le16_to_cpu(ctrlrequest->wLength);
+ wIndex = le16_to_cpu(ctrlrequest->wIndex);
+
+ if (ctrlrequest->bRequestType != (USB_DIR_OUT | USB_RECIP_DEVICE))
+ goto delegate;
+
+ if ((wIndex != 0) || (wLength != 0) || (wValue > 127))
+ return -EINVAL;
+
+ addr = wValue;
+ /* The hardware will take care of this USB address after the status
+ * stage of the SET_ADDRESS request is completed normally.
+ * It is safe to write it now
+ */
+ usbf_reg_writel(udc, USBF_REG_USB_ADDRESS, USBF_USB_SET_USB_ADDR(addr));
+
+ /* Queued the status request */
+ usbf_ep0_fill_req(&udc->ep[0], &udc->setup_reply, NULL, 0,
+ usbf_ep0_req_set_address_complete);
+ usbf_ep0_queue(&udc->ep[0], &udc->setup_reply, GFP_ATOMIC);
+
+ return 0;
+
+delegate:
+ return usbf_req_delegate(udc, ctrlrequest);
+}
+
+static int usbf_req_set_configuration(struct usbf_udc *udc,
+ const struct usb_ctrlrequest *ctrlrequest)
+{
+ u16 wLength;
+ u16 wValue;
+ u16 wIndex;
+ int ret;
+
+ ret = usbf_req_delegate(udc, ctrlrequest);
+ if (ret)
+ return ret;
+
+ wValue = le16_to_cpu(ctrlrequest->wValue);
+ wLength = le16_to_cpu(ctrlrequest->wLength);
+ wIndex = le16_to_cpu(ctrlrequest->wIndex);
+
+ if ((ctrlrequest->bRequestType != (USB_DIR_OUT | USB_RECIP_DEVICE)) ||
+ (wIndex != 0) || (wLength != 0)) {
+ /* No error detected by driver->setup() but it is not an USB2.0
+ * Ch9 SET_CONFIGURATION.
+ * Nothing more to do
+ */
+ return 0;
+ }
+
+ if (wValue & 0x00FF) {
+ usbf_reg_bitset(udc, USBF_REG_USB_CONTROL, USBF_USB_CONF);
+ } else {
+ usbf_reg_bitclr(udc, USBF_REG_USB_CONTROL, USBF_USB_CONF);
+ /* Go back to Address State */
+ spin_unlock(&udc->lock);
+ usb_gadget_set_state(&udc->gadget, USB_STATE_ADDRESS);
+ spin_lock(&udc->lock);
+ }
+
+ return 0;
+}
+
+static int usbf_handle_ep0_setup(struct usbf_ep *ep0)
+{
+ union {
+ struct usb_ctrlrequest ctrlreq;
+ u32 raw[2];
+ } crq;
+ struct usbf_udc *udc = ep0->udc;
+ int ret;
+
+ /* Read setup data (ie the USB control request) */
+ crq.raw[0] = usbf_reg_readl(udc, USBF_REG_SETUP_DATA0);
+ crq.raw[1] = usbf_reg_readl(udc, USBF_REG_SETUP_DATA1);
+
+ dev_dbg(ep0->udc->dev,
+ "ep0 req%02x.%02x, wValue 0x%04x, wIndex 0x%04x, wLength 0x%04x\n",
+ crq.ctrlreq.bRequestType, crq.ctrlreq.bRequest,
+ crq.ctrlreq.wValue, crq.ctrlreq.wIndex, crq.ctrlreq.wLength);
+
+ /* Set current EP0 state according to the received request */
+ if (crq.ctrlreq.wLength) {
+ if (crq.ctrlreq.bRequestType & USB_DIR_IN) {
+ udc->ep0state = EP0_IN_DATA_PHASE;
+ usbf_ep_reg_clrset(ep0, USBF_REG_EP0_CONTROL,
+ USBF_EP0_INAK,
+ USBF_EP0_INAK_EN);
+ ep0->is_in = 1;
+ } else {
+ udc->ep0state = EP0_OUT_DATA_PHASE;
+ usbf_ep_reg_bitclr(ep0, USBF_REG_EP0_CONTROL,
+ USBF_EP0_ONAK);
+ ep0->is_in = 0;
+ }
+ } else {
+ udc->ep0state = EP0_IN_STATUS_START_PHASE;
+ ep0->is_in = 1;
+ }
+
+ /* We starts a new control transfer -> Clear the delayed status flag */
+ ep0->delayed_status = 0;
+
+ if ((crq.ctrlreq.bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD) {
+ /* This is not a USB standard request -> delelate */
+ goto delegate;
+ }
+
+ switch (crq.ctrlreq.bRequest) {
+ case USB_REQ_GET_STATUS:
+ ret = usbf_req_get_status(udc, &crq.ctrlreq);
+ break;
+
+ case USB_REQ_CLEAR_FEATURE:
+ ret = usbf_req_clear_set_feature(udc, &crq.ctrlreq, false);
+ break;
+
+ case USB_REQ_SET_FEATURE:
+ ret = usbf_req_clear_set_feature(udc, &crq.ctrlreq, true);
+ break;
+
+ case USB_REQ_SET_ADDRESS:
+ ret = usbf_req_set_address(udc, &crq.ctrlreq);
+ break;
+
+ case USB_REQ_SET_CONFIGURATION:
+ ret = usbf_req_set_configuration(udc, &crq.ctrlreq);
+ break;
+
+ default:
+ goto delegate;
+ }
+
+ return ret;
+
+delegate:
+ return usbf_req_delegate(udc, &crq.ctrlreq);
+}
+
+static int usbf_handle_ep0_data_status(struct usbf_ep *ep0,
+ const char *ep0state_name,
+ enum usbf_ep0state next_ep0state)
+{
+ struct usbf_udc *udc = ep0->udc;
+ int ret;
+
+ ret = usbf_ep_process_queue(ep0);
+ switch (ret) {
+ case -ENOENT:
+ dev_err(udc->dev,
+ "no request available for ep0 %s phase\n",
+ ep0state_name);
+ break;
+ case -EINPROGRESS:
+ /* More data needs to be processed */
+ ret = 0;
+ break;
+ case 0:
+ /* All requests in the queue are processed */
+ udc->ep0state = next_ep0state;
+ break;
+ default:
+ dev_err(udc->dev,
+ "process queue failed for ep0 %s phase (%d)\n",
+ ep0state_name, ret);
+ break;
+ }
+ return ret;
+}
+
+static int usbf_handle_ep0_out_status_start(struct usbf_ep *ep0)
+{
+ struct usbf_udc *udc = ep0->udc;
+ struct usbf_req *req;
+
+ usbf_ep_reg_clrset(ep0, USBF_REG_EP0_CONTROL,
+ USBF_EP0_ONAK,
+ USBF_EP0_PIDCLR);
+ ep0->is_in = 0;
+
+ req = list_first_entry_or_null(&ep0->queue, struct usbf_req, queue);
+ if (!req) {
+ usbf_ep0_fill_req(ep0, &udc->setup_reply, NULL, 0, NULL);
+ usbf_ep0_queue(ep0, &udc->setup_reply, GFP_ATOMIC);
+ } else {
+ if (req->req.length) {
+ dev_err(udc->dev,
+ "queued request length %u for ep0 out status phase\n",
+ req->req.length);
+ }
+ }
+ udc->ep0state = EP0_OUT_STATUS_PHASE;
+ return 0;
+}
+
+static int usbf_handle_ep0_in_status_start(struct usbf_ep *ep0)
+{
+ struct usbf_udc *udc = ep0->udc;
+ struct usbf_req *req;
+ int ret;
+
+ usbf_ep_reg_clrset(ep0, USBF_REG_EP0_CONTROL,
+ USBF_EP0_INAK,
+ USBF_EP0_INAK_EN | USBF_EP0_PIDCLR);
+ ep0->is_in = 1;
+
+ /* Queue request for status if needed */
+ req = list_first_entry_or_null(&ep0->queue, struct usbf_req, queue);
+ if (!req) {
+ if (ep0->delayed_status) {
+ dev_dbg(ep0->udc->dev,
+ "EP0_IN_STATUS_START_PHASE ep0->delayed_status set\n");
+ udc->ep0state = EP0_IN_STATUS_PHASE;
+ return 0;
+ }
+
+ usbf_ep0_fill_req(ep0, &udc->setup_reply, NULL,
+ 0, NULL);
+ usbf_ep0_queue(ep0, &udc->setup_reply,
+ GFP_ATOMIC);
+
+ req = list_first_entry_or_null(&ep0->queue, struct usbf_req, queue);
+ } else {
+ if (req->req.length) {
+ dev_err(udc->dev,
+ "queued request length %u for ep0 in status phase\n",
+ req->req.length);
+ }
+ }
+
+ ret = usbf_ep0_pio_in(ep0, req);
+ if (ret != -EINPROGRESS) {
+ usbf_ep_req_done(ep0, req, ret);
+ udc->ep0state = EP0_IN_STATUS_END_PHASE;
+ return 0;
+ }
+
+ udc->ep0state = EP0_IN_STATUS_PHASE;
+ return 0;
+}
+
+static void usbf_ep0_interrupt(struct usbf_ep *ep0)
+{
+ struct usbf_udc *udc = ep0->udc;
+ u32 sts, prev_sts;
+ int prev_ep0state;
+ int ret;
+
+ ep0->status = usbf_ep_reg_readl(ep0, USBF_REG_EP0_STATUS);
+ usbf_ep_reg_writel(ep0, USBF_REG_EP0_STATUS, ~ep0->status);
+
+ dev_dbg(ep0->udc->dev, "ep0 status=0x%08x, enable=%08x\n, ctrl=0x%08x\n",
+ ep0->status,
+ usbf_ep_reg_readl(ep0, USBF_REG_EP0_INT_ENA),
+ usbf_ep_reg_readl(ep0, USBF_REG_EP0_CONTROL));
+
+ sts = ep0->status & (USBF_EP0_SETUP_INT | USBF_EP0_IN_INT | USBF_EP0_OUT_INT |
+ USBF_EP0_OUT_NULL_INT | USBF_EP0_STG_START_INT |
+ USBF_EP0_STG_END_INT);
+
+ ret = 0;
+ do {
+ dev_dbg(ep0->udc->dev, "udc->ep0state=%d\n", udc->ep0state);
+
+ prev_sts = sts;
+ prev_ep0state = udc->ep0state;
+ switch (udc->ep0state) {
+ case EP0_IDLE:
+ if (!(sts & USBF_EP0_SETUP_INT))
+ break;
+
+ sts &= ~USBF_EP0_SETUP_INT;
+ dev_dbg(ep0->udc->dev, "ep0 handle setup\n");
+ ret = usbf_handle_ep0_setup(ep0);
+ break;
+
+ case EP0_IN_DATA_PHASE:
+ if (!(sts & USBF_EP0_IN_INT))
+ break;
+
+ sts &= ~USBF_EP0_IN_INT;
+ dev_dbg(ep0->udc->dev, "ep0 handle in data phase\n");
+ ret = usbf_handle_ep0_data_status(ep0,
+ "in data", EP0_OUT_STATUS_START_PHASE);
+ break;
+
+ case EP0_OUT_STATUS_START_PHASE:
+ if (!(sts & USBF_EP0_STG_START_INT))
+ break;
+
+ sts &= ~USBF_EP0_STG_START_INT;
+ dev_dbg(ep0->udc->dev, "ep0 handle out status start phase\n");
+ ret = usbf_handle_ep0_out_status_start(ep0);
+ break;
+
+ case EP0_OUT_STATUS_PHASE:
+ if (!(sts & (USBF_EP0_OUT_INT | USBF_EP0_OUT_NULL_INT)))
+ break;
+
+ sts &= ~(USBF_EP0_OUT_INT | USBF_EP0_OUT_NULL_INT);
+ dev_dbg(ep0->udc->dev, "ep0 handle out status phase\n");
+ ret = usbf_handle_ep0_data_status(ep0,
+ "out status",
+ EP0_OUT_STATUS_END_PHASE);
+ break;
+
+ case EP0_OUT_STATUS_END_PHASE:
+ if (!(sts & (USBF_EP0_STG_END_INT | USBF_EP0_SETUP_INT)))
+ break;
+
+ sts &= ~USBF_EP0_STG_END_INT;
+ dev_dbg(ep0->udc->dev, "ep0 handle out status end phase\n");
+ udc->ep0state = EP0_IDLE;
+ break;
+
+ case EP0_OUT_DATA_PHASE:
+ if (!(sts & (USBF_EP0_OUT_INT | USBF_EP0_OUT_NULL_INT)))
+ break;
+
+ sts &= ~(USBF_EP0_OUT_INT | USBF_EP0_OUT_NULL_INT);
+ dev_dbg(ep0->udc->dev, "ep0 handle out data phase\n");
+ ret = usbf_handle_ep0_data_status(ep0,
+ "out data", EP0_IN_STATUS_START_PHASE);
+ break;
+
+ case EP0_IN_STATUS_START_PHASE:
+ if (!(sts & USBF_EP0_STG_START_INT))
+ break;
+
+ sts &= ~USBF_EP0_STG_START_INT;
+ dev_dbg(ep0->udc->dev, "ep0 handle in status start phase\n");
+ ret = usbf_handle_ep0_in_status_start(ep0);
+ break;
+
+ case EP0_IN_STATUS_PHASE:
+ if (!(sts & USBF_EP0_IN_INT))
+ break;
+
+ sts &= ~USBF_EP0_IN_INT;
+ dev_dbg(ep0->udc->dev, "ep0 handle in status phase\n");
+ ret = usbf_handle_ep0_data_status(ep0,
+ "in status", EP0_IN_STATUS_END_PHASE);
+ break;
+
+ case EP0_IN_STATUS_END_PHASE:
+ if (!(sts & (USBF_EP0_STG_END_INT | USBF_EP0_SETUP_INT)))
+ break;
+
+ sts &= ~USBF_EP0_STG_END_INT;
+ dev_dbg(ep0->udc->dev, "ep0 handle in status end\n");
+ udc->ep0state = EP0_IDLE;
+ break;
+
+ default:
+ udc->ep0state = EP0_IDLE;
+ break;
+ }
+
+ if (ret) {
+ dev_dbg(ep0->udc->dev, "ep0 failed (%d)\n", ret);
+ /* Failure -> stall.
+ * This stall state will be automatically cleared when
+ * the IP receives the next SETUP packet
+ */
+ usbf_ep_stall(ep0, true);
+
+ /* Remove anything that was pending */
+ usbf_ep_nuke(ep0, -EPROTO);
+
+ udc->ep0state = EP0_IDLE;
+ break;
+ }
+
+ } while ((prev_ep0state != udc->ep0state) || (prev_sts != sts));
+
+ dev_dbg(ep0->udc->dev, "ep0 done udc->ep0state=%d, status=0x%08x. next=0x%08x\n",
+ udc->ep0state, sts,
+ usbf_ep_reg_readl(ep0, USBF_REG_EP0_STATUS));
+}
+
+static void usbf_epn_process_queue(struct usbf_ep *epn)
+{
+ int ret;
+
+ ret = usbf_ep_process_queue(epn);
+ switch (ret) {
+ case -ENOENT:
+ dev_warn(epn->udc->dev, "ep%u %s, no request available\n",
+ epn->id, epn->is_in ? "in" : "out");
+ break;
+ case -EINPROGRESS:
+ /* More data needs to be processed */
+ ret = 0;
+ break;
+ case 0:
+ /* All requests in the queue are processed */
+ break;
+ default:
+ dev_err(epn->udc->dev, "ep%u %s, process queue failed (%d)\n",
+ epn->id, epn->is_in ? "in" : "out", ret);
+ break;
+ }
+
+ if (ret) {
+ dev_dbg(epn->udc->dev, "ep%u %s failed (%d)\n", epn->id,
+ epn->is_in ? "in" : "out", ret);
+ usbf_ep_stall(epn, true);
+ usbf_ep_nuke(epn, ret);
+ }
+}
+
+static void usbf_epn_interrupt(struct usbf_ep *epn)
+{
+ u32 sts;
+ u32 ena;
+
+ epn->status = usbf_ep_reg_readl(epn, USBF_REG_EPN_STATUS);
+ ena = usbf_ep_reg_readl(epn, USBF_REG_EPN_INT_ENA);
+ usbf_ep_reg_writel(epn, USBF_REG_EPN_STATUS, ~(epn->status & ena));
+
+ dev_dbg(epn->udc->dev, "ep%u %s status=0x%08x, enable=%08x\n, ctrl=0x%08x\n",
+ epn->id, epn->is_in ? "in" : "out", epn->status, ena,
+ usbf_ep_reg_readl(epn, USBF_REG_EPN_CONTROL));
+
+ if (epn->disabled) {
+ dev_warn(epn->udc->dev, "ep%u %s, interrupt while disabled\n",
+ epn->id, epn->is_in ? "in" : "out");
+ return;
+ }
+
+ sts = epn->status & ena;
+
+ if (sts & (USBF_EPN_IN_END_INT | USBF_EPN_IN_INT)) {
+ sts &= ~(USBF_EPN_IN_END_INT | USBF_EPN_IN_INT);
+ dev_dbg(epn->udc->dev, "ep%u %s process queue (in interrupts)\n",
+ epn->id, epn->is_in ? "in" : "out");
+ usbf_epn_process_queue(epn);
+ }
+
+ if (sts & (USBF_EPN_OUT_END_INT | USBF_EPN_OUT_INT | USBF_EPN_OUT_NULL_INT)) {
+ sts &= ~(USBF_EPN_OUT_END_INT | USBF_EPN_OUT_INT | USBF_EPN_OUT_NULL_INT);
+ dev_dbg(epn->udc->dev, "ep%u %s process queue (out interrupts)\n",
+ epn->id, epn->is_in ? "in" : "out");
+ usbf_epn_process_queue(epn);
+ }
+
+ dev_dbg(epn->udc->dev, "ep%u %s done status=0x%08x. next=0x%08x\n",
+ epn->id, epn->is_in ? "in" : "out",
+ sts, usbf_ep_reg_readl(epn, USBF_REG_EPN_STATUS));
+}
+
+static void usbf_ep_reset(struct usbf_ep *ep)
+{
+ ep->status = 0;
+ /* Remove anything that was pending */
+ usbf_ep_nuke(ep, -ESHUTDOWN);
+}
+
+static void usbf_reset(struct usbf_udc *udc)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(udc->ep); i++) {
+ if (udc->ep[i].disabled)
+ continue;
+
+ usbf_ep_reset(&udc->ep[i]);
+ }
+
+ if (usbf_reg_readl(udc, USBF_REG_USB_STATUS) & USBF_USB_SPEED_MODE)
+ udc->gadget.speed = USB_SPEED_HIGH;
+ else
+ udc->gadget.speed = USB_SPEED_FULL;
+
+ /* Remote wakeup feature must be disabled on USB bus reset */
+ udc->is_remote_wakeup = false;
+
+ /* Enable endpoint zero */
+ usbf_ep0_enable(&udc->ep[0]);
+
+ if (udc->driver) {
+ /* Signal the reset */
+ spin_unlock(&udc->lock);
+ usb_gadget_udc_reset(&udc->gadget, udc->driver);
+ spin_lock(&udc->lock);
+ }
+}
+
+static void usbf_driver_suspend(struct usbf_udc *udc)
+{
+ if (udc->is_usb_suspended) {
+ dev_dbg(udc->dev, "already suspended\n");
+ return;
+ }
+
+ dev_dbg(udc->dev, "do usb suspend\n");
+ udc->is_usb_suspended = true;
+
+ if (udc->driver && udc->driver->suspend) {
+ spin_unlock(&udc->lock);
+ udc->driver->suspend(&udc->gadget);
+ spin_lock(&udc->lock);
+
+ /* The datasheet tells to set the USB_CONTROL register SUSPEND
+ * bit when the USB bus suspend is detected.
+ * This bit stops the clocks (clocks for EPC, SIE, USBPHY) but
+ * these clocks seems not used only by the USB device. Some
+ * UARTs can be lost ...
+ * So, do not set the USB_CONTROL register SUSPEND bit.
+ */
+ }
+}
+
+static void usbf_driver_resume(struct usbf_udc *udc)
+{
+ if (!udc->is_usb_suspended)
+ return;
+
+ dev_dbg(udc->dev, "do usb resume\n");
+ udc->is_usb_suspended = false;
+
+ if (udc->driver && udc->driver->resume) {
+ spin_unlock(&udc->lock);
+ udc->driver->resume(&udc->gadget);
+ spin_lock(&udc->lock);
+ }
+}
+
+static irqreturn_t usbf_epc_irq(int irq, void *_udc)
+{
+ struct usbf_udc *udc = (struct usbf_udc *)_udc;
+ unsigned long flags;
+ struct usbf_ep *ep;
+ u32 int_sts;
+ u32 int_en;
+ int i;
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ int_en = usbf_reg_readl(udc, USBF_REG_USB_INT_ENA);
+ int_sts = usbf_reg_readl(udc, USBF_REG_USB_INT_STA) & int_en;
+ usbf_reg_writel(udc, USBF_REG_USB_INT_STA, ~int_sts);
+
+ dev_dbg(udc->dev, "int_sts=0x%08x\n", int_sts);
+
+ if (int_sts & USBF_USB_RSUM_INT) {
+ dev_dbg(udc->dev, "handle resume\n");
+ usbf_driver_resume(udc);
+ }
+
+ if (int_sts & USBF_USB_USB_RST_INT) {
+ dev_dbg(udc->dev, "handle bus reset\n");
+ usbf_driver_resume(udc);
+ usbf_reset(udc);
+ }
+
+ if (int_sts & USBF_USB_SPEED_MODE_INT) {
+ if (usbf_reg_readl(udc, USBF_REG_USB_STATUS) & USBF_USB_SPEED_MODE)
+ udc->gadget.speed = USB_SPEED_HIGH;
+ else
+ udc->gadget.speed = USB_SPEED_FULL;
+ dev_dbg(udc->dev, "handle speed change (%s)\n",
+ udc->gadget.speed == USB_SPEED_HIGH ? "High" : "Full");
+ }
+
+ if (int_sts & USBF_USB_EPN_INT(0)) {
+ usbf_driver_resume(udc);
+ usbf_ep0_interrupt(&udc->ep[0]);
+ }
+
+ for (i = 1; i < ARRAY_SIZE(udc->ep); i++) {
+ ep = &udc->ep[i];
+
+ if (int_sts & USBF_USB_EPN_INT(i)) {
+ usbf_driver_resume(udc);
+ usbf_epn_interrupt(ep);
+ }
+ }
+
+ if (int_sts & USBF_USB_SPND_INT) {
+ dev_dbg(udc->dev, "handle suspend\n");
+ usbf_driver_suspend(udc);
+ }
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t usbf_ahb_epc_irq(int irq, void *_udc)
+{
+ struct usbf_udc *udc = (struct usbf_udc *)_udc;
+ unsigned long flags;
+ struct usbf_ep *epn;
+ u32 sysbint;
+ void (*ep_action)(struct usbf_ep *epn);
+ int i;
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ /* Read and ack interrupts */
+ sysbint = usbf_reg_readl(udc, USBF_REG_AHBBINT);
+ usbf_reg_writel(udc, USBF_REG_AHBBINT, sysbint);
+
+ if ((sysbint & USBF_SYS_VBUS_INT) == USBF_SYS_VBUS_INT) {
+ if (usbf_reg_readl(udc, USBF_REG_EPCTR) & USBF_SYS_VBUS_LEVEL) {
+ dev_dbg(udc->dev, "handle vbus (1)\n");
+ spin_unlock(&udc->lock);
+ usb_udc_vbus_handler(&udc->gadget, true);
+ usb_gadget_set_state(&udc->gadget, USB_STATE_POWERED);
+ spin_lock(&udc->lock);
+ } else {
+ dev_dbg(udc->dev, "handle vbus (0)\n");
+ udc->is_usb_suspended = false;
+ spin_unlock(&udc->lock);
+ usb_udc_vbus_handler(&udc->gadget, false);
+ usb_gadget_set_state(&udc->gadget,
+ USB_STATE_NOTATTACHED);
+ spin_lock(&udc->lock);
+ }
+ }
+
+ for (i = 1; i < ARRAY_SIZE(udc->ep); i++) {
+ if (sysbint & USBF_SYS_DMA_ENDINT_EPN(i)) {
+ epn = &udc->ep[i];
+ dev_dbg(epn->udc->dev,
+ "ep%u handle DMA complete. action=%ps\n",
+ epn->id, epn->bridge_on_dma_end);
+ ep_action = epn->bridge_on_dma_end;
+ if (ep_action) {
+ epn->bridge_on_dma_end = NULL;
+ ep_action(epn);
+ }
+ }
+ }
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+static int usbf_udc_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
+{
+ struct usbf_udc *udc = container_of(gadget, struct usbf_udc, gadget);
+ unsigned long flags;
+
+ dev_info(udc->dev, "start (driver '%s')\n", driver->driver.name);
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ /* hook up the driver */
+ udc->driver = driver;
+
+ /* Enable VBUS interrupt */
+ usbf_reg_writel(udc, USBF_REG_AHBBINTEN, USBF_SYS_VBUS_INTEN);
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return 0;
+}
+
+static int usbf_udc_stop(struct usb_gadget *gadget)
+{
+ struct usbf_udc *udc = container_of(gadget, struct usbf_udc, gadget);
+ unsigned long flags;
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ /* Disable VBUS interrupt */
+ usbf_reg_writel(udc, USBF_REG_AHBBINTEN, 0);
+
+ udc->driver = NULL;
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ dev_info(udc->dev, "stopped\n");
+
+ return 0;
+}
+
+static int usbf_get_frame(struct usb_gadget *gadget)
+{
+ struct usbf_udc *udc = container_of(gadget, struct usbf_udc, gadget);
+
+ return USBF_USB_GET_FRAME(usbf_reg_readl(udc, USBF_REG_USB_ADDRESS));
+}
+
+static void usbf_attach(struct usbf_udc *udc)
+{
+ /* Enable USB signal to Function PHY
+ * D+ signal Pull-up
+ * Disable endpoint 0, it will be automatically enable when a USB reset
+ * is received.
+ * Disable the other endpoints
+ */
+ usbf_reg_clrset(udc, USBF_REG_USB_CONTROL,
+ USBF_USB_CONNECTB | USBF_USB_DEFAULT | USBF_USB_CONF,
+ USBF_USB_PUE2);
+
+ /* Enable reset and mode change interrupts */
+ usbf_reg_bitset(udc, USBF_REG_USB_INT_ENA,
+ USBF_USB_USB_RST_EN | USBF_USB_SPEED_MODE_EN | USBF_USB_RSUM_EN | USBF_USB_SPND_EN);
+}
+
+static void usbf_detach(struct usbf_udc *udc)
+{
+ int i;
+
+ /* Disable interrupts */
+ usbf_reg_writel(udc, USBF_REG_USB_INT_ENA, 0);
+
+ for (i = 0; i < ARRAY_SIZE(udc->ep); i++) {
+ if (udc->ep[i].disabled)
+ continue;
+
+ usbf_ep_reset(&udc->ep[i]);
+ }
+
+ /* Disable USB signal to Function PHY
+ * Do not Pull-up D+ signal
+ * Disable endpoint 0
+ * Disable the other endpoints
+ */
+ usbf_reg_clrset(udc, USBF_REG_USB_CONTROL,
+ USBF_USB_PUE2 | USBF_USB_DEFAULT | USBF_USB_CONF,
+ USBF_USB_CONNECTB);
+}
+
+static int usbf_pullup(struct usb_gadget *gadget, int is_on)
+{
+ struct usbf_udc *udc = container_of(gadget, struct usbf_udc, gadget);
+ unsigned long flags;
+
+ dev_dbg(udc->dev, "pullup %d\n", is_on);
+
+ spin_lock_irqsave(&udc->lock, flags);
+ if (is_on)
+ usbf_attach(udc);
+ else
+ usbf_detach(udc);
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return 0;
+}
+
+static int usbf_udc_set_selfpowered(struct usb_gadget *gadget,
+ int is_selfpowered)
+{
+ struct usbf_udc *udc = container_of(gadget, struct usbf_udc, gadget);
+ unsigned long flags;
+
+ spin_lock_irqsave(&udc->lock, flags);
+ gadget->is_selfpowered = (is_selfpowered != 0);
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return 0;
+}
+
+static int usbf_udc_wakeup(struct usb_gadget *gadget)
+{
+ struct usbf_udc *udc = container_of(gadget, struct usbf_udc, gadget);
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ if (!udc->is_remote_wakeup) {
+ dev_dbg(udc->dev, "remote wakeup not allowed\n");
+ ret = -EINVAL;
+ goto end;
+ }
+
+ dev_dbg(udc->dev, "do wakeup\n");
+
+ /* Send the resume signal */
+ usbf_reg_bitset(udc, USBF_REG_USB_CONTROL, USBF_USB_RSUM_IN);
+ usbf_reg_bitclr(udc, USBF_REG_USB_CONTROL, USBF_USB_RSUM_IN);
+
+ ret = 0;
+end:
+ spin_unlock_irqrestore(&udc->lock, flags);
+ return ret;
+}
+
+static struct usb_gadget_ops usbf_gadget_ops = {
+ .get_frame = usbf_get_frame,
+ .pullup = usbf_pullup,
+ .udc_start = usbf_udc_start,
+ .udc_stop = usbf_udc_stop,
+ .set_selfpowered = usbf_udc_set_selfpowered,
+ .wakeup = usbf_udc_wakeup,
+};
+
+static int usbf_epn_check(struct usbf_ep *epn)
+{
+ const char *type_txt;
+ const char *buf_txt;
+ int ret = 0;
+ u32 ctrl;
+
+ ctrl = usbf_ep_reg_readl(epn, USBF_REG_EPN_CONTROL);
+
+ switch (ctrl & USBF_EPN_MODE_MASK) {
+ case USBF_EPN_MODE_BULK:
+ type_txt = "bulk";
+ if (epn->ep.caps.type_control || epn->ep.caps.type_iso ||
+ !epn->ep.caps.type_bulk || epn->ep.caps.type_int) {
+ dev_err(epn->udc->dev,
+ "ep%u caps mismatch, bulk expected\n", epn->id);
+ ret = -EINVAL;
+ }
+ break;
+ case USBF_EPN_MODE_INTR:
+ type_txt = "intr";
+ if (epn->ep.caps.type_control || epn->ep.caps.type_iso ||
+ epn->ep.caps.type_bulk || !epn->ep.caps.type_int) {
+ dev_err(epn->udc->dev,
+ "ep%u caps mismatch, int expected\n", epn->id);
+ ret = -EINVAL;
+ }
+ break;
+ case USBF_EPN_MODE_ISO:
+ type_txt = "iso";
+ if (epn->ep.caps.type_control || !epn->ep.caps.type_iso ||
+ epn->ep.caps.type_bulk || epn->ep.caps.type_int) {
+ dev_err(epn->udc->dev,
+ "ep%u caps mismatch, iso expected\n", epn->id);
+ ret = -EINVAL;
+ }
+ break;
+ default:
+ type_txt = "unknown";
+ dev_err(epn->udc->dev, "ep%u unknown type\n", epn->id);
+ ret = -EINVAL;
+ break;
+ }
+
+ if (ctrl & USBF_EPN_BUF_TYPE_DOUBLE) {
+ buf_txt = "double";
+ if (!usbf_ep_info[epn->id].is_double) {
+ dev_err(epn->udc->dev,
+ "ep%u buffer mismatch, double expected\n",
+ epn->id);
+ ret = -EINVAL;
+ }
+ } else {
+ buf_txt = "single";
+ if (usbf_ep_info[epn->id].is_double) {
+ dev_err(epn->udc->dev,
+ "ep%u buffer mismatch, single expected\n",
+ epn->id);
+ ret = -EINVAL;
+ }
+ }
+
+ dev_dbg(epn->udc->dev, "ep%u (%s) %s, %s buffer %u, checked %s\n",
+ epn->id, epn->ep.name, type_txt, buf_txt,
+ epn->ep.maxpacket_limit, ret ? "failed" : "ok");
+
+ return ret;
+}
+
+static int usbf_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct usbf_udc *udc;
+ struct usbf_ep *ep;
+ unsigned int i;
+ int irq;
+ int ret;
+
+ udc = devm_kzalloc(dev, sizeof(*udc), GFP_KERNEL);
+ if (!udc)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, udc);
+
+ udc->dev = dev;
+ spin_lock_init(&udc->lock);
+
+ udc->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(udc->regs))
+ return PTR_ERR(udc->regs);
+
+ devm_pm_runtime_enable(&pdev->dev);
+ ret = pm_runtime_resume_and_get(&pdev->dev);
+ if (ret < 0)
+ return ret;
+
+ dev_info(dev, "USBF version: %08x\n",
+ usbf_reg_readl(udc, USBF_REG_USBSSVER));
+
+ /* Resetting the PLL is handled via the clock driver as it has common
+ * registers with USB Host
+ */
+ usbf_reg_bitclr(udc, USBF_REG_EPCTR, USBF_SYS_EPC_RST);
+
+ /* modify in register gadget process */
+ udc->gadget.speed = USB_SPEED_FULL;
+ udc->gadget.max_speed = USB_SPEED_HIGH;
+ udc->gadget.ops = &usbf_gadget_ops;
+
+ udc->gadget.name = dev->driver->name;
+ udc->gadget.dev.parent = dev;
+ udc->gadget.ep0 = &udc->ep[0].ep;
+
+ /* The hardware DMA controller needs dma addresses aligned on 32bit.
+ * A fallback to pio is done if DMA addresses are not aligned.
+ */
+ udc->gadget.quirk_avoids_skb_reserve = 1;
+
+ INIT_LIST_HEAD(&udc->gadget.ep_list);
+ /* we have a canned request structure to allow sending packets as reply
+ * to get_status requests
+ */
+ INIT_LIST_HEAD(&udc->setup_reply.queue);
+
+ for (i = 0; i < ARRAY_SIZE(udc->ep); i++) {
+ ep = &udc->ep[i];
+
+ if (!(usbf_reg_readl(udc, USBF_REG_USBSSCONF) &
+ USBF_SYS_EP_AVAILABLE(i))) {
+ continue;
+ }
+
+ INIT_LIST_HEAD(&ep->queue);
+
+ ep->id = i;
+ ep->disabled = 1;
+ ep->udc = udc;
+ ep->ep.ops = &usbf_ep_ops;
+ ep->ep.name = usbf_ep_info[i].name;
+ ep->ep.caps = usbf_ep_info[i].caps;
+ usb_ep_set_maxpacket_limit(&ep->ep,
+ usbf_ep_info[i].maxpacket_limit);
+
+ if (ep->id == 0) {
+ ep->regs = ep->udc->regs + USBF_BASE_EP0;
+ } else {
+ ep->regs = ep->udc->regs + USBF_BASE_EPN(ep->id - 1);
+ ret = usbf_epn_check(ep);
+ if (ret)
+ return ret;
+ if (usbf_reg_readl(udc, USBF_REG_USBSSCONF) &
+ USBF_SYS_DMA_AVAILABLE(i)) {
+ ep->dma_regs = ep->udc->regs +
+ USBF_BASE_DMA_EPN(ep->id - 1);
+ }
+ list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+ }
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+ ret = devm_request_irq(dev, irq, usbf_epc_irq, 0, "usbf-epc", udc);
+ if (ret) {
+ dev_err(dev, "cannot request irq %d err %d\n", irq, ret);
+ return ret;
+ }
+
+ irq = platform_get_irq(pdev, 1);
+ if (irq < 0)
+ return irq;
+ ret = devm_request_irq(dev, irq, usbf_ahb_epc_irq, 0, "usbf-ahb-epc", udc);
+ if (ret) {
+ dev_err(dev, "cannot request irq %d err %d\n", irq, ret);
+ return ret;
+ }
+
+ usbf_reg_bitset(udc, USBF_REG_AHBMCTR, USBF_SYS_WBURST_TYPE);
+
+ usbf_reg_bitset(udc, USBF_REG_USB_CONTROL,
+ USBF_USB_INT_SEL | USBF_USB_SOF_RCV | USBF_USB_SOF_CLK_MODE);
+
+ ret = usb_add_gadget_udc(dev, &udc->gadget);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int usbf_remove(struct platform_device *pdev)
+{
+ struct usbf_udc *udc = platform_get_drvdata(pdev);
+
+ usb_del_gadget_udc(&udc->gadget);
+
+ pm_runtime_put(&pdev->dev);
+
+ return 0;
+}
+
+static const struct of_device_id usbf_match[] = {
+ { .compatible = "renesas,rzn1-usbf" },
+ {} /* sentinel */
+};
+MODULE_DEVICE_TABLE(of, usbf_match);
+
+static struct platform_driver udc_driver = {
+ .driver = {
+ .name = "usbf_renesas",
+ .owner = THIS_MODULE,
+ .of_match_table = usbf_match,
+ },
+ .probe = usbf_probe,
+ .remove = usbf_remove,
+};
+
+module_platform_driver(udc_driver);
+
+MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");
+MODULE_DESCRIPTION("Renesas R-Car Gen3 & RZ/N1 USB Function driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/udc/rzv2m_usb3drd.c b/drivers/usb/gadget/udc/rzv2m_usb3drd.c
new file mode 100644
index 000000000000..3c8bbf843038
--- /dev/null
+++ b/drivers/usb/gadget/udc/rzv2m_usb3drd.c
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas RZ/V2M USB3DRD driver
+ *
+ * Copyright (C) 2022 Renesas Electronics Corporation
+ */
+
+#include <linux/io.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <linux/usb/rzv2m_usb3drd.h>
+
+#define USB_PERI_DRD_CON 0x000
+
+#define USB_PERI_DRD_CON_PERI_RST BIT(31)
+#define USB_PERI_DRD_CON_HOST_RST BIT(30)
+#define USB_PERI_DRD_CON_PERI_CON BIT(24)
+
+static void rzv2m_usb3drd_set_bit(struct rzv2m_usb3drd *usb3, u32 bits,
+ u32 offs)
+{
+ u32 val = readl(usb3->reg + offs);
+
+ val |= bits;
+ writel(val, usb3->reg + offs);
+}
+
+static void rzv2m_usb3drd_clear_bit(struct rzv2m_usb3drd *usb3, u32 bits,
+ u32 offs)
+{
+ u32 val = readl(usb3->reg + offs);
+
+ val &= ~bits;
+ writel(val, usb3->reg + offs);
+}
+
+void rzv2m_usb3drd_reset(struct device *dev, bool host)
+{
+ struct rzv2m_usb3drd *usb3 = dev_get_drvdata(dev);
+
+ if (host) {
+ rzv2m_usb3drd_clear_bit(usb3, USB_PERI_DRD_CON_PERI_CON,
+ USB_PERI_DRD_CON);
+ rzv2m_usb3drd_clear_bit(usb3, USB_PERI_DRD_CON_HOST_RST,
+ USB_PERI_DRD_CON);
+ rzv2m_usb3drd_set_bit(usb3, USB_PERI_DRD_CON_PERI_RST,
+ USB_PERI_DRD_CON);
+ } else {
+ rzv2m_usb3drd_set_bit(usb3, USB_PERI_DRD_CON_PERI_CON,
+ USB_PERI_DRD_CON);
+ rzv2m_usb3drd_set_bit(usb3, USB_PERI_DRD_CON_HOST_RST,
+ USB_PERI_DRD_CON);
+ rzv2m_usb3drd_clear_bit(usb3, USB_PERI_DRD_CON_PERI_RST,
+ USB_PERI_DRD_CON);
+ }
+}
+EXPORT_SYMBOL_GPL(rzv2m_usb3drd_reset);
+
+static int rzv2m_usb3drd_remove(struct platform_device *pdev)
+{
+ struct rzv2m_usb3drd *usb3 = platform_get_drvdata(pdev);
+
+ of_platform_depopulate(usb3->dev);
+ pm_runtime_put(usb3->dev);
+ pm_runtime_disable(&pdev->dev);
+ reset_control_assert(usb3->drd_rstc);
+
+ return 0;
+}
+
+static int rzv2m_usb3drd_probe(struct platform_device *pdev)
+{
+ struct rzv2m_usb3drd *usb3;
+ int ret;
+
+ usb3 = devm_kzalloc(&pdev->dev, sizeof(*usb3), GFP_KERNEL);
+ if (!usb3)
+ return -ENOMEM;
+
+ usb3->dev = &pdev->dev;
+
+ usb3->drd_irq = platform_get_irq_byname(pdev, "drd");
+ if (usb3->drd_irq < 0)
+ return usb3->drd_irq;
+
+ usb3->reg = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(usb3->reg))
+ return PTR_ERR(usb3->reg);
+
+ platform_set_drvdata(pdev, usb3);
+
+ usb3->drd_rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
+ if (IS_ERR(usb3->drd_rstc))
+ return dev_err_probe(&pdev->dev, PTR_ERR(usb3->drd_rstc),
+ "failed to get drd reset");
+
+ reset_control_deassert(usb3->drd_rstc);
+ pm_runtime_enable(&pdev->dev);
+ ret = pm_runtime_resume_and_get(usb3->dev);
+ if (ret)
+ goto err_rst;
+
+ ret = of_platform_populate(usb3->dev->of_node, NULL, NULL, usb3->dev);
+ if (ret)
+ goto err_pm;
+
+ return 0;
+
+err_pm:
+ pm_runtime_put(usb3->dev);
+
+err_rst:
+ pm_runtime_disable(&pdev->dev);
+ reset_control_assert(usb3->drd_rstc);
+ return ret;
+}
+
+static const struct of_device_id rzv2m_usb3drd_of_match[] = {
+ { .compatible = "renesas,rzv2m-usb3drd", },
+ { /* Sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, rzv2m_usb3drd_of_match);
+
+static struct platform_driver rzv2m_usb3drd_driver = {
+ .driver = {
+ .name = "rzv2m-usb3drd",
+ .of_match_table = of_match_ptr(rzv2m_usb3drd_of_match),
+ },
+ .probe = rzv2m_usb3drd_probe,
+ .remove = rzv2m_usb3drd_remove,
+};
+module_platform_driver(rzv2m_usb3drd_driver);
+
+MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>");
+MODULE_DESCRIPTION("Renesas RZ/V2M USB3DRD driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:rzv2m_usb3drd");
diff --git a/drivers/usb/gadget/udc/tegra-xudc.c b/drivers/usb/gadget/udc/tegra-xudc.c
index 76919d7570d2..2b71b33725f1 100644
--- a/drivers/usb/gadget/udc/tegra-xudc.c
+++ b/drivers/usb/gadget/udc/tegra-xudc.c
@@ -796,21 +796,16 @@ static int tegra_xudc_get_phy_index(struct tegra_xudc *xudc,
return -1;
}
-static int tegra_xudc_vbus_notify(struct notifier_block *nb,
- unsigned long action, void *data)
+static void tegra_xudc_update_data_role(struct tegra_xudc *xudc,
+ struct usb_phy *usbphy)
{
- struct tegra_xudc *xudc = container_of(nb, struct tegra_xudc,
- vbus_nb);
- struct usb_phy *usbphy = (struct usb_phy *)data;
int phy_index;
- dev_dbg(xudc->dev, "%s(): event is %d\n", __func__, usbphy->last_event);
-
if ((xudc->device_mode && usbphy->last_event == USB_EVENT_VBUS) ||
(!xudc->device_mode && usbphy->last_event != USB_EVENT_VBUS)) {
dev_dbg(xudc->dev, "Same role(%d) received. Ignore",
xudc->device_mode);
- return NOTIFY_OK;
+ return;
}
xudc->device_mode = (usbphy->last_event == USB_EVENT_VBUS) ? true :
@@ -826,6 +821,18 @@ static int tegra_xudc_vbus_notify(struct notifier_block *nb,
xudc->curr_usbphy = usbphy;
schedule_work(&xudc->usb_role_sw_work);
}
+}
+
+static int tegra_xudc_vbus_notify(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct tegra_xudc *xudc = container_of(nb, struct tegra_xudc,
+ vbus_nb);
+ struct usb_phy *usbphy = (struct usb_phy *)data;
+
+ dev_dbg(xudc->dev, "%s(): event is %d\n", __func__, usbphy->last_event);
+
+ tegra_xudc_update_data_role(xudc, usbphy);
return NOTIFY_OK;
}
@@ -3521,7 +3528,7 @@ static int tegra_xudc_phy_get(struct tegra_xudc *xudc)
/* Get usb-phy, if utmi phy is available */
xudc->usbphy[i] = devm_usb_get_phy_by_node(xudc->dev,
xudc->utmi_phy[i]->dev.of_node,
- &xudc->vbus_nb);
+ NULL);
if (IS_ERR(xudc->usbphy[i])) {
err = PTR_ERR(xudc->usbphy[i]);
dev_err_probe(xudc->dev, err,
@@ -3660,6 +3667,19 @@ static struct tegra_xudc_soc tegra194_xudc_soc_data = {
.has_ipfs = false,
};
+static struct tegra_xudc_soc tegra234_xudc_soc_data = {
+ .clock_names = tegra186_xudc_clock_names,
+ .num_clks = ARRAY_SIZE(tegra186_xudc_clock_names),
+ .num_phys = 4,
+ .u1_enable = true,
+ .u2_enable = true,
+ .lpm_enable = true,
+ .invalid_seq_num = false,
+ .pls_quirk = false,
+ .port_reset_quirk = false,
+ .has_ipfs = false,
+};
+
static const struct of_device_id tegra_xudc_of_match[] = {
{
.compatible = "nvidia,tegra210-xudc",
@@ -3673,6 +3693,10 @@ static const struct of_device_id tegra_xudc_of_match[] = {
.compatible = "nvidia,tegra194-xudc",
.data = &tegra194_xudc_soc_data
},
+ {
+ .compatible = "nvidia,tegra234-xudc",
+ .data = &tegra234_xudc_soc_data
+ },
{ }
};
MODULE_DEVICE_TABLE(of, tegra_xudc_of_match);
@@ -3856,6 +3880,14 @@ static int tegra_xudc_probe(struct platform_device *pdev)
goto free_eps;
}
+ for (i = 0; i < xudc->soc->num_phys; i++) {
+ if (!xudc->usbphy[i])
+ continue;
+
+ usb_register_notifier(xudc->usbphy[i], &xudc->vbus_nb);
+ tegra_xudc_update_data_role(xudc, xudc->usbphy[i]);
+ }
+
return 0;
free_eps:
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index a97923897c8e..eacb603ad1b2 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -53,7 +53,6 @@ config USB_XHCI_PCI_RENESAS
config USB_XHCI_PLATFORM
tristate "Generic xHCI driver for a platform device"
- select USB_XHCI_RCAR if ARCH_RENESAS
help
Adds an xHCI host driver for a generic platform device, which
provides a memory space and an irq.
@@ -91,10 +90,20 @@ config USB_XHCI_RCAR
tristate "xHCI support for Renesas R-Car SoCs"
depends on USB_XHCI_PLATFORM
depends on ARCH_RENESAS || COMPILE_TEST
+ default ARCH_RENESAS
help
Say 'Y' to enable the support for the xHCI host controller
found in Renesas R-Car ARM SoCs.
+config USB_XHCI_RZV2M
+ bool "xHCI support for Renesas RZ/V2M SoC"
+ depends on USB_XHCI_RCAR
+ depends on ARCH_R9A09G011 || COMPILE_TEST
+ depends on USB_RZV2M_USB3DRD=y || (USB_RZV2M_USB3DRD=USB_XHCI_RCAR)
+ help
+ Say 'Y' to enable the support for the xHCI host controller
+ found in Renesas RZ/V2M SoC.
+
config USB_XHCI_TEGRA
tristate "xHCI support for NVIDIA Tegra SoCs"
depends on PHY_TEGRA_XUSB
@@ -535,17 +544,6 @@ config USB_OHCI_HCD_SSB
If unsure, say N.
-config USB_OHCI_SH
- bool "OHCI support for SuperH USB controller (DEPRECATED)"
- depends on SUPERH || COMPILE_TEST
- select USB_OHCI_HCD_PLATFORM
- help
- This option is deprecated now and the driver was removed, use
- USB_OHCI_HCD_PLATFORM instead.
-
- Enables support for the on-chip OHCI controller on the SuperH.
- If you use the PCI OHCI controller, this option is not necessary.
-
config USB_OHCI_EXYNOS
tristate "OHCI support for Samsung S5P/Exynos SoC Series"
depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 6d8ee264c9b2..5a13712f367d 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -25,14 +25,13 @@ xhci-plat-hcd-y := xhci-plat.o
ifneq ($(CONFIG_USB_XHCI_MVEBU), )
xhci-plat-hcd-y += xhci-mvebu.o
endif
-ifneq ($(CONFIG_USB_XHCI_RCAR), )
- xhci-plat-hcd-y += xhci-rcar.o
-endif
-
ifneq ($(CONFIG_DEBUG_FS),)
xhci-hcd-y += xhci-debugfs.o
endif
+xhci-rcar-hcd-y += xhci-rcar.o
+xhci-rcar-hcd-$(CONFIG_USB_XHCI_RZV2M) += xhci-rzv2m.o
+
obj-$(CONFIG_USB_PCI) += pci-quirks.o
obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o
@@ -72,6 +71,7 @@ obj-$(CONFIG_USB_XHCI_PCI) += xhci-pci.o
obj-$(CONFIG_USB_XHCI_PCI_RENESAS) += xhci-pci-renesas.o
obj-$(CONFIG_USB_XHCI_PLATFORM) += xhci-plat-hcd.o
obj-$(CONFIG_USB_XHCI_HISTB) += xhci-histb.o
+obj-$(CONFIG_USB_XHCI_RCAR) += xhci-rcar-hcd.o
obj-$(CONFIG_USB_XHCI_MTK) += xhci-mtk-hcd.o
obj-$(CONFIG_USB_XHCI_TEGRA) += xhci-tegra.o
obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o
diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c
index a333231616f4..47c9f06c3d84 100644
--- a/drivers/usb/host/ehci-exynos.c
+++ b/drivers/usb/host/ehci-exynos.c
@@ -80,19 +80,11 @@ static int exynos_ehci_get_phy(struct device *dev,
return -EINVAL;
}
- phy = devm_of_phy_get(dev, child, NULL);
+ phy = devm_of_phy_optional_get(dev, child, NULL);
exynos_ehci->phy[phy_number] = phy;
if (IS_ERR(phy)) {
- ret = PTR_ERR(phy);
- if (ret == -EPROBE_DEFER) {
- of_node_put(child);
- return ret;
- } else if (ret != -ENOSYS && ret != -ENODEV) {
- dev_err(dev,
- "Error retrieving usb2 phy: %d\n", ret);
- of_node_put(child);
- return ret;
- }
+ of_node_put(child);
+ return PTR_ERR(phy);
}
}
@@ -108,12 +100,10 @@ static int exynos_ehci_phy_enable(struct device *dev)
int ret = 0;
for (i = 0; ret == 0 && i < PHY_NUMBER; i++)
- if (!IS_ERR(exynos_ehci->phy[i]))
- ret = phy_power_on(exynos_ehci->phy[i]);
+ ret = phy_power_on(exynos_ehci->phy[i]);
if (ret)
for (i--; i >= 0; i--)
- if (!IS_ERR(exynos_ehci->phy[i]))
- phy_power_off(exynos_ehci->phy[i]);
+ phy_power_off(exynos_ehci->phy[i]);
return ret;
}
@@ -125,8 +115,7 @@ static void exynos_ehci_phy_disable(struct device *dev)
int i;
for (i = 0; i < PHY_NUMBER; i++)
- if (!IS_ERR(exynos_ehci->phy[i]))
- phy_power_off(exynos_ehci->phy[i]);
+ phy_power_off(exynos_ehci->phy[i]);
}
static void exynos_setup_vbus_gpio(struct device *dev)
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index 38d06e5abfbb..d74fa5ba845b 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -712,7 +712,7 @@ static struct platform_driver ehci_fsl_driver = {
.remove = fsl_ehci_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
.driver = {
- .name = "fsl-ehci",
+ .name = DRV_NAME,
.pm = EHCI_FSL_PM_OPS,
},
};
diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c
index e5df17522892..46c6a152b865 100644
--- a/drivers/usb/host/fsl-mph-dr-of.c
+++ b/drivers/usb/host/fsl-mph-dr-of.c
@@ -112,8 +112,7 @@ static struct platform_device *fsl_usb2_device_register(
goto error;
}
- pdev->dev.of_node = ofdev->dev.of_node;
- pdev->dev.of_node_reused = true;
+ device_set_of_node_from_dev(&pdev->dev, &ofdev->dev);
retval = platform_device_add(pdev);
if (retval)
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index 4f564d71bb0b..49ae01487af4 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -1205,7 +1205,7 @@ static void create_debug_file(struct isp116x *isp116x)
static void remove_debug_file(struct isp116x *isp116x)
{
- debugfs_remove(debugfs_lookup(hcd_name, usb_debug_root));
+ debugfs_lookup_and_remove(hcd_name, usb_debug_root);
}
#else
diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c
index 0e14d1d07709..b0da143ef4be 100644
--- a/drivers/usb/host/isp1362-hcd.c
+++ b/drivers/usb/host/isp1362-hcd.c
@@ -2170,7 +2170,7 @@ static void create_debug_file(struct isp1362_hcd *isp1362_hcd)
static void remove_debug_file(struct isp1362_hcd *isp1362_hcd)
{
- debugfs_remove(debugfs_lookup("isp1362", usb_debug_root));
+ debugfs_lookup_and_remove("isp1362", usb_debug_root);
}
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c
index 352e3ac2b377..28d1524ee2fa 100644
--- a/drivers/usb/host/max3421-hcd.c
+++ b/drivers/usb/host/max3421-hcd.c
@@ -72,12 +72,6 @@
#define USB_MAX_FRAME_NUMBER 0x7ff
#define USB_MAX_RETRIES 3 /* # of retries before error is reported */
-/*
- * Max. # of times we're willing to retransmit a request immediately in
- * resposne to a NAK. Afterwards, we fall back on trying once a frame.
- */
-#define NAK_MAX_FAST_RETRANSMITS 2
-
#define POWER_BUDGET 500 /* in mA; use 8 for low-power port testing */
/* Port-change mask: */
@@ -924,11 +918,8 @@ max3421_handle_error(struct usb_hcd *hcd, u8 hrsl)
* Device wasn't ready for data or has no data
* available: retry the packet again.
*/
- if (max3421_ep->naks++ < NAK_MAX_FAST_RETRANSMITS) {
- max3421_next_transfer(hcd, 1);
- switch_sndfifo = 0;
- } else
- max3421_slow_retransmit(hcd);
+ max3421_next_transfer(hcd, 1);
+ switch_sndfifo = 0;
break;
}
if (switch_sndfifo)
@@ -1436,7 +1427,7 @@ max3421_spi_thread(void *dev_id)
* use spi_wr_buf().
*/
for (i = 0; i < ARRAY_SIZE(max3421_hcd->iopins); ++i) {
- u8 val = spi_rd8(hcd, MAX3421_REG_IOPINS1);
+ u8 val = spi_rd8(hcd, MAX3421_REG_IOPINS1 + i);
val = ((val & 0xf0) |
(max3421_hcd->iopins[i] & 0x0f));
diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c
index 8d7977fd5d3b..8af17c1ee5cc 100644
--- a/drivers/usb/host/ohci-exynos.c
+++ b/drivers/usb/host/ohci-exynos.c
@@ -69,19 +69,11 @@ static int exynos_ohci_get_phy(struct device *dev,
return -EINVAL;
}
- phy = devm_of_phy_get(dev, child, NULL);
+ phy = devm_of_phy_optional_get(dev, child, NULL);
exynos_ohci->phy[phy_number] = phy;
if (IS_ERR(phy)) {
- ret = PTR_ERR(phy);
- if (ret == -EPROBE_DEFER) {
- of_node_put(child);
- return ret;
- } else if (ret != -ENOSYS && ret != -ENODEV) {
- dev_err(dev,
- "Error retrieving usb2 phy: %d\n", ret);
- of_node_put(child);
- return ret;
- }
+ of_node_put(child);
+ return PTR_ERR(phy);
}
}
@@ -97,12 +89,10 @@ static int exynos_ohci_phy_enable(struct device *dev)
int ret = 0;
for (i = 0; ret == 0 && i < PHY_NUMBER; i++)
- if (!IS_ERR(exynos_ohci->phy[i]))
- ret = phy_power_on(exynos_ohci->phy[i]);
+ ret = phy_power_on(exynos_ohci->phy[i]);
if (ret)
for (i--; i >= 0; i--)
- if (!IS_ERR(exynos_ohci->phy[i]))
- phy_power_off(exynos_ohci->phy[i]);
+ phy_power_off(exynos_ohci->phy[i]);
return ret;
}
@@ -114,8 +104,7 @@ static void exynos_ohci_phy_disable(struct device *dev)
int i;
for (i = 0; i < PHY_NUMBER; i++)
- if (!IS_ERR(exynos_ohci->phy[i]))
- phy_power_off(exynos_ohci->phy[i]);
+ phy_power_off(exynos_ohci->phy[i]);
}
static int exynos_ohci_probe(struct platform_device *pdev)
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index d206bd95c7bb..b8b90eec9107 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -1501,7 +1501,7 @@ static void create_debug_file(struct sl811 *sl811)
static void remove_debug_file(struct sl811 *sl811)
{
- debugfs_remove(debugfs_lookup("sl811h", usb_debug_root));
+ debugfs_lookup_and_remove("sl811h", usb_debug_root);
}
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index c22b51af83fc..7cdc2fa7c28f 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -536,8 +536,8 @@ static void release_uhci(struct uhci_hcd *uhci)
uhci->is_initialized = 0;
spin_unlock_irq(&uhci->lock);
- debugfs_remove(debugfs_lookup(uhci_to_hcd(uhci)->self.bus_name,
- uhci_debugfs_root));
+ debugfs_lookup_and_remove(uhci_to_hcd(uhci)->self.bus_name,
+ uhci_debugfs_root);
for (i = 0; i < UHCI_NUM_SKELQH; i++)
uhci_free_qh(uhci, uhci->skelqh[i]);
@@ -700,7 +700,7 @@ err_alloc_frame_cpu:
uhci->frame, uhci->frame_dma_handle);
err_alloc_frame:
- debugfs_remove(debugfs_lookup(hcd->self.bus_name, uhci_debugfs_root));
+ debugfs_lookup_and_remove(hcd->self.bus_name, uhci_debugfs_root);
return retval;
}
diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c
index dc832ddf7033..0bc7fe11f749 100644
--- a/drivers/usb/host/xhci-debugfs.c
+++ b/drivers/usb/host/xhci-debugfs.c
@@ -692,7 +692,7 @@ void xhci_debugfs_init(struct xhci_hcd *xhci)
"command-ring",
xhci->debugfs_root);
- xhci_debugfs_create_ring_dir(xhci, &xhci->event_ring,
+ xhci_debugfs_create_ring_dir(xhci, &xhci->interrupter->event_ring,
"event-ring",
xhci->debugfs_root);
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 94c94db3faf6..0054d02239e2 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -578,13 +578,16 @@ void xhci_ring_device(struct xhci_hcd *xhci, int slot_id)
return;
}
-static void xhci_disable_port(struct usb_hcd *hcd, struct xhci_hcd *xhci,
- u16 wIndex, __le32 __iomem *addr, u32 port_status)
+static void xhci_disable_port(struct xhci_hcd *xhci, struct xhci_port *port)
{
+ struct usb_hcd *hcd;
+ u32 portsc;
+
+ hcd = port->rhub->hcd;
+
/* Don't allow the USB core to disable SuperSpeed ports. */
if (hcd->speed >= HCD_USB3) {
- xhci_dbg(xhci, "Ignoring request to disable "
- "SuperSpeed port.\n");
+ xhci_dbg(xhci, "Ignoring request to disable SuperSpeed port.\n");
return;
}
@@ -594,11 +597,15 @@ static void xhci_disable_port(struct usb_hcd *hcd, struct xhci_hcd *xhci,
return;
}
+ portsc = readl(port->addr);
+ portsc = xhci_port_state_to_neutral(portsc);
+
/* Write 1 to disable the port */
- writel(port_status | PORT_PE, addr);
- port_status = readl(addr);
+ writel(portsc | PORT_PE, port->addr);
+
+ portsc = readl(port->addr);
xhci_dbg(xhci, "disable port %d-%d, portsc: 0x%x\n",
- hcd->self.busnum, wIndex + 1, port_status);
+ hcd->self.busnum, port->hcd_portnum + 1, portsc);
}
static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue,
@@ -666,20 +673,18 @@ struct xhci_hub *xhci_get_rhub(struct usb_hcd *hcd)
* It will release and re-aquire the lock while calling ACPI
* method.
*/
-static void xhci_set_port_power(struct xhci_hcd *xhci, struct usb_hcd *hcd,
- u16 index, bool on, unsigned long *flags)
+static void xhci_set_port_power(struct xhci_hcd *xhci, struct xhci_port *port,
+ bool on, unsigned long *flags)
__must_hold(&xhci->lock)
{
- struct xhci_hub *rhub;
- struct xhci_port *port;
+ struct usb_hcd *hcd;
u32 temp;
- rhub = xhci_get_rhub(hcd);
- port = rhub->ports[index];
+ hcd = port->rhub->hcd;
temp = readl(port->addr);
xhci_dbg(xhci, "set port power %d-%d %s, portsc: 0x%x\n",
- hcd->self.busnum, index + 1, on ? "ON" : "OFF", temp);
+ hcd->self.busnum, port->hcd_portnum + 1, on ? "ON" : "OFF", temp);
temp = xhci_port_state_to_neutral(temp);
@@ -694,10 +699,10 @@ static void xhci_set_port_power(struct xhci_hcd *xhci, struct usb_hcd *hcd,
spin_unlock_irqrestore(&xhci->lock, *flags);
temp = usb_acpi_power_manageable(hcd->self.root_hub,
- index);
+ port->hcd_portnum);
if (temp)
usb_acpi_set_power_state(hcd->self.root_hub,
- index, on);
+ port->hcd_portnum, on);
spin_lock_irqsave(&xhci->lock, *flags);
}
@@ -721,7 +726,6 @@ static int xhci_enter_test_mode(struct xhci_hcd *xhci,
u16 test_mode, u16 wIndex, unsigned long *flags)
__must_hold(&xhci->lock)
{
- struct usb_hcd *usb3_hcd = xhci_get_usb3_hcd(xhci);
int i, retval;
/* Disable all Device Slots */
@@ -742,10 +746,10 @@ static int xhci_enter_test_mode(struct xhci_hcd *xhci,
xhci_dbg(xhci, "Disable all port (PP = 0)\n");
/* Power off USB3 ports*/
for (i = 0; i < xhci->usb3_rhub.num_ports; i++)
- xhci_set_port_power(xhci, usb3_hcd, i, false, flags);
+ xhci_set_port_power(xhci, xhci->usb3_rhub.ports[i], false, flags);
/* Power off USB2 ports*/
for (i = 0; i < xhci->usb2_rhub.num_ports; i++)
- xhci_set_port_power(xhci, xhci->main_hcd, i, false, flags);
+ xhci_set_port_power(xhci, xhci->usb2_rhub.ports[i], false, flags);
/* Stop the controller */
xhci_dbg(xhci, "Stop controller\n");
retval = xhci_halt(xhci);
@@ -920,7 +924,7 @@ static void xhci_del_comp_mod_timer(struct xhci_hcd *xhci, u32 status,
}
static int xhci_handle_usb2_port_link_resume(struct xhci_port *port,
- u32 *status, u32 portsc,
+ u32 portsc,
unsigned long *flags)
{
struct xhci_bus_state *bus_state;
@@ -935,11 +939,10 @@ static int xhci_handle_usb2_port_link_resume(struct xhci_port *port,
wIndex = port->hcd_portnum;
if ((portsc & PORT_RESET) || !(portsc & PORT_PE)) {
- *status = 0xffffffff;
return -EINVAL;
}
/* did port event handler already start resume timing? */
- if (!bus_state->resume_done[wIndex]) {
+ if (!port->resume_timestamp) {
/* If not, maybe we are in a host initated resume? */
if (test_bit(wIndex, &bus_state->resuming_ports)) {
/* Host initated resume doesn't time the resume
@@ -956,28 +959,29 @@ static int xhci_handle_usb2_port_link_resume(struct xhci_port *port,
msecs_to_jiffies(USB_RESUME_TIMEOUT);
set_bit(wIndex, &bus_state->resuming_ports);
- bus_state->resume_done[wIndex] = timeout;
+ port->resume_timestamp = timeout;
mod_timer(&hcd->rh_timer, timeout);
usb_hcd_start_port_resume(&hcd->self, wIndex);
}
/* Has resume been signalled for USB_RESUME_TIME yet? */
- } else if (time_after_eq(jiffies, bus_state->resume_done[wIndex])) {
+ } else if (time_after_eq(jiffies, port->resume_timestamp)) {
int time_left;
xhci_dbg(xhci, "resume USB2 port %d-%d\n",
hcd->self.busnum, wIndex + 1);
- bus_state->resume_done[wIndex] = 0;
+ port->resume_timestamp = 0;
clear_bit(wIndex, &bus_state->resuming_ports);
- set_bit(wIndex, &bus_state->rexit_ports);
+ reinit_completion(&port->rexit_done);
+ port->rexit_active = true;
xhci_test_and_clear_bit(xhci, port, PORT_PLC);
xhci_set_link_state(xhci, port, XDEV_U0);
spin_unlock_irqrestore(&xhci->lock, *flags);
time_left = wait_for_completion_timeout(
- &bus_state->rexit_done[wIndex],
+ &port->rexit_done,
msecs_to_jiffies(XHCI_MAX_REXIT_TIMEOUT_MS));
spin_lock_irqsave(&xhci->lock, *flags);
@@ -986,7 +990,6 @@ static int xhci_handle_usb2_port_link_resume(struct xhci_port *port,
wIndex + 1);
if (!slot_id) {
xhci_dbg(xhci, "slot_id is zero\n");
- *status = 0xffffffff;
return -ENODEV;
}
xhci_ring_device(xhci, slot_id);
@@ -995,22 +998,19 @@ static int xhci_handle_usb2_port_link_resume(struct xhci_port *port,
xhci_warn(xhci, "Port resume timed out, port %d-%d: 0x%x\n",
hcd->self.busnum, wIndex + 1, port_status);
- *status |= USB_PORT_STAT_SUSPEND;
- clear_bit(wIndex, &bus_state->rexit_ports);
+ /*
+ * keep rexit_active set if U0 transition failed so we
+ * know to report PORT_STAT_SUSPEND status back to
+ * usbcore. It will be cleared later once the port is
+ * out of RESUME/U3 state
+ */
}
usb_hcd_end_port_resume(&hcd->self, wIndex);
bus_state->port_c_suspend |= 1 << wIndex;
bus_state->suspended_ports &= ~(1 << wIndex);
- } else {
- /*
- * The resume has been signaling for less than
- * USB_RESUME_TIME. Report the port status as SUSPEND,
- * let the usbcore check port status again and clear
- * resume signaling later.
- */
- *status |= USB_PORT_STAT_SUSPEND;
}
+
return 0;
}
@@ -1087,7 +1087,7 @@ static void xhci_get_usb2_port_status(struct xhci_port *port, u32 *status,
struct xhci_bus_state *bus_state;
u32 link_state;
u32 portnum;
- int ret;
+ int err;
bus_state = &port->rhub->bus_state;
link_state = portsc & PORT_PLS_MASK;
@@ -1103,22 +1103,34 @@ static void xhci_get_usb2_port_status(struct xhci_port *port, u32 *status,
if (link_state == XDEV_U2)
*status |= USB_PORT_STAT_L1;
if (link_state == XDEV_U0) {
- if (bus_state->resume_done[portnum])
- usb_hcd_end_port_resume(&port->rhub->hcd->self,
- portnum);
- bus_state->resume_done[portnum] = 0;
- clear_bit(portnum, &bus_state->resuming_ports);
if (bus_state->suspended_ports & (1 << portnum)) {
bus_state->suspended_ports &= ~(1 << portnum);
bus_state->port_c_suspend |= 1 << portnum;
}
}
if (link_state == XDEV_RESUME) {
- ret = xhci_handle_usb2_port_link_resume(port, status,
- portsc, flags);
- if (ret)
- return;
+ err = xhci_handle_usb2_port_link_resume(port, portsc,
+ flags);
+ if (err < 0)
+ *status = 0xffffffff;
+ else if (port->resume_timestamp || port->rexit_active)
+ *status |= USB_PORT_STAT_SUSPEND;
+ }
+ }
+
+ /*
+ * Clear usb2 resume signalling variables if port is no longer suspended
+ * or resuming. Port either resumed to U0/U1/U2, disconnected, or in a
+ * error state. Resume related variables should be cleared in all those cases.
+ */
+ if (link_state != XDEV_U3 && link_state != XDEV_RESUME) {
+ if (port->resume_timestamp ||
+ test_bit(portnum, &bus_state->resuming_ports)) {
+ port->resume_timestamp = 0;
+ clear_bit(portnum, &bus_state->resuming_ports);
+ usb_hcd_end_port_resume(&port->rhub->hcd->self, portnum);
}
+ port->rexit_active = 0;
}
}
@@ -1174,18 +1186,6 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
else
xhci_get_usb2_port_status(port, &status, raw_port_status,
flags);
- /*
- * Clear stale usb2 resume signalling variables in case port changed
- * state during resume signalling. For example on error
- */
- if ((bus_state->resume_done[wIndex] ||
- test_bit(wIndex, &bus_state->resuming_ports)) &&
- (raw_port_status & PORT_PLS_MASK) != XDEV_U3 &&
- (raw_port_status & PORT_PLS_MASK) != XDEV_RESUME) {
- bus_state->resume_done[wIndex] = 0;
- clear_bit(wIndex, &bus_state->resuming_ports);
- usb_hcd_end_port_resume(&hcd->self, wIndex);
- }
if (bus_state->port_c_suspend & (1 << wIndex))
status |= USB_PORT_STAT_C_SUSPEND << 16;
@@ -1209,11 +1209,14 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u16 test_mode = 0;
struct xhci_hub *rhub;
struct xhci_port **ports;
+ struct xhci_port *port;
+ int portnum1;
rhub = xhci_get_rhub(hcd);
ports = rhub->ports;
max_ports = rhub->num_ports;
bus_state = &rhub->bus_state;
+ portnum1 = wIndex & 0xff;
spin_lock_irqsave(&xhci->lock, flags);
switch (typeReq) {
@@ -1247,10 +1250,12 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
spin_unlock_irqrestore(&xhci->lock, flags);
return retval;
case GetPortStatus:
- if (!wIndex || wIndex > max_ports)
+ if (!portnum1 || portnum1 > max_ports)
goto error;
+
wIndex--;
- temp = readl(ports[wIndex]->addr);
+ port = ports[portnum1 - 1];
+ temp = readl(port->addr);
if (temp == ~(u32)0) {
xhci_hc_died(xhci);
retval = -ENODEV;
@@ -1263,7 +1268,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
goto error;
xhci_dbg(xhci, "Get port status %d-%d read: 0x%x, return 0x%x",
- hcd->self.busnum, wIndex + 1, temp, status);
+ hcd->self.busnum, portnum1, temp, status);
put_unaligned(cpu_to_le32(status), (__le32 *) buf);
/* if USB 3.1 extended port status return additional 4 bytes */
@@ -1275,7 +1280,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
retval = -EINVAL;
break;
}
- port_li = readl(ports[wIndex]->addr + PORTLI);
+ port_li = readl(port->addr + PORTLI);
status = xhci_get_ext_port_status(temp, port_li);
put_unaligned_le32(status, &buf[4]);
}
@@ -1289,11 +1294,14 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
test_mode = (wIndex & 0xff00) >> 8;
/* The MSB of wIndex is the U1/U2 timeout */
timeout = (wIndex & 0xff00) >> 8;
+
wIndex &= 0xff;
- if (!wIndex || wIndex > max_ports)
+ if (!portnum1 || portnum1 > max_ports)
goto error;
+
+ port = ports[portnum1 - 1];
wIndex--;
- temp = readl(ports[wIndex]->addr);
+ temp = readl(port->addr);
if (temp == ~(u32)0) {
xhci_hc_died(xhci);
retval = -ENODEV;
@@ -1303,11 +1311,10 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
/* FIXME: What new port features do we need to support? */
switch (wValue) {
case USB_PORT_FEAT_SUSPEND:
- temp = readl(ports[wIndex]->addr);
+ temp = readl(port->addr);
if ((temp & PORT_PLS_MASK) != XDEV_U0) {
/* Resume the port to U0 first */
- xhci_set_link_state(xhci, ports[wIndex],
- XDEV_U0);
+ xhci_set_link_state(xhci, port, XDEV_U0);
spin_unlock_irqrestore(&xhci->lock, flags);
msleep(10);
spin_lock_irqsave(&xhci->lock, flags);
@@ -1316,16 +1323,16 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
* a port unless the port reports that it is in the
* enabled (PED = ‘1’,PLS < ‘3’) state.
*/
- temp = readl(ports[wIndex]->addr);
+ temp = readl(port->addr);
if ((temp & PORT_PE) == 0 || (temp & PORT_RESET)
|| (temp & PORT_PLS_MASK) >= XDEV_U3) {
xhci_warn(xhci, "USB core suspending port %d-%d not in U0/U1/U2\n",
- hcd->self.busnum, wIndex + 1);
+ hcd->self.busnum, portnum1);
goto error;
}
slot_id = xhci_find_slot_id_by_port(hcd, xhci,
- wIndex + 1);
+ portnum1);
if (!slot_id) {
xhci_warn(xhci, "slot_id is zero\n");
goto error;
@@ -1335,21 +1342,21 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
xhci_stop_device(xhci, slot_id, 1);
spin_lock_irqsave(&xhci->lock, flags);
- xhci_set_link_state(xhci, ports[wIndex], XDEV_U3);
+ xhci_set_link_state(xhci, port, XDEV_U3);
spin_unlock_irqrestore(&xhci->lock, flags);
msleep(10); /* wait device to enter */
spin_lock_irqsave(&xhci->lock, flags);
- temp = readl(ports[wIndex]->addr);
+ temp = readl(port->addr);
bus_state->suspended_ports |= 1 << wIndex;
break;
case USB_PORT_FEAT_LINK_STATE:
- temp = readl(ports[wIndex]->addr);
+ temp = readl(port->addr);
/* Disable port */
if (link_state == USB_SS_PORT_LS_SS_DISABLED) {
xhci_dbg(xhci, "Disable port %d-%d\n",
- hcd->self.busnum, wIndex + 1);
+ hcd->self.busnum, portnum1);
temp = xhci_port_state_to_neutral(temp);
/*
* Clear all change bits, so that we get a new
@@ -1358,18 +1365,17 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
temp |= PORT_CSC | PORT_PEC | PORT_WRC |
PORT_OCC | PORT_RC | PORT_PLC |
PORT_CEC;
- writel(temp | PORT_PE, ports[wIndex]->addr);
- temp = readl(ports[wIndex]->addr);
+ writel(temp | PORT_PE, port->addr);
+ temp = readl(port->addr);
break;
}
/* Put link in RxDetect (enable port) */
if (link_state == USB_SS_PORT_LS_RX_DETECT) {
xhci_dbg(xhci, "Enable port %d-%d\n",
- hcd->self.busnum, wIndex + 1);
- xhci_set_link_state(xhci, ports[wIndex],
- link_state);
- temp = readl(ports[wIndex]->addr);
+ hcd->self.busnum, portnum1);
+ xhci_set_link_state(xhci, port, link_state);
+ temp = readl(port->addr);
break;
}
@@ -1399,11 +1405,10 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
}
xhci_dbg(xhci, "Enable compliance mode transition for port %d-%d\n",
- hcd->self.busnum, wIndex + 1);
- xhci_set_link_state(xhci, ports[wIndex],
- link_state);
+ hcd->self.busnum, portnum1);
+ xhci_set_link_state(xhci, port, link_state);
- temp = readl(ports[wIndex]->addr);
+ temp = readl(port->addr);
break;
}
/* Port must be enabled */
@@ -1414,8 +1419,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
/* Can't set port link state above '3' (U3) */
if (link_state > USB_SS_PORT_LS_U3) {
xhci_warn(xhci, "Cannot set port %d-%d link state %d\n",
- hcd->self.busnum, wIndex + 1,
- link_state);
+ hcd->self.busnum, portnum1, link_state);
goto error;
}
@@ -1437,30 +1441,29 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
pls == XDEV_RESUME ||
pls == XDEV_RECOVERY) {
wait_u0 = true;
- reinit_completion(&bus_state->u3exit_done[wIndex]);
+ reinit_completion(&port->u3exit_done);
}
if (pls <= XDEV_U3) /* U1, U2, U3 */
- xhci_set_link_state(xhci, ports[wIndex],
- USB_SS_PORT_LS_U0);
+ xhci_set_link_state(xhci, port, USB_SS_PORT_LS_U0);
if (!wait_u0) {
if (pls > XDEV_U3)
goto error;
break;
}
spin_unlock_irqrestore(&xhci->lock, flags);
- if (!wait_for_completion_timeout(&bus_state->u3exit_done[wIndex],
+ if (!wait_for_completion_timeout(&port->u3exit_done,
msecs_to_jiffies(500)))
xhci_dbg(xhci, "missing U0 port change event for port %d-%d\n",
- hcd->self.busnum, wIndex + 1);
+ hcd->self.busnum, portnum1);
spin_lock_irqsave(&xhci->lock, flags);
- temp = readl(ports[wIndex]->addr);
+ temp = readl(port->addr);
break;
}
if (link_state == USB_SS_PORT_LS_U3) {
int retries = 16;
slot_id = xhci_find_slot_id_by_port(hcd, xhci,
- wIndex + 1);
+ portnum1);
if (slot_id) {
/* unlock to execute stop endpoint
* commands */
@@ -1469,16 +1472,16 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
xhci_stop_device(xhci, slot_id, 1);
spin_lock_irqsave(&xhci->lock, flags);
}
- xhci_set_link_state(xhci, ports[wIndex], USB_SS_PORT_LS_U3);
+ xhci_set_link_state(xhci, port, USB_SS_PORT_LS_U3);
spin_unlock_irqrestore(&xhci->lock, flags);
while (retries--) {
usleep_range(4000, 8000);
- temp = readl(ports[wIndex]->addr);
+ temp = readl(port->addr);
if ((temp & PORT_PLS_MASK) == XDEV_U3)
break;
}
spin_lock_irqsave(&xhci->lock, flags);
- temp = readl(ports[wIndex]->addr);
+ temp = readl(port->addr);
bus_state->suspended_ports |= 1 << wIndex;
}
break;
@@ -1489,43 +1492,42 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
* However, hub_wq will ignore the roothub events until
* the roothub is registered.
*/
- xhci_set_port_power(xhci, hcd, wIndex, true, &flags);
+ xhci_set_port_power(xhci, port, true, &flags);
break;
case USB_PORT_FEAT_RESET:
temp = (temp | PORT_RESET);
- writel(temp, ports[wIndex]->addr);
+ writel(temp, port->addr);
- temp = readl(ports[wIndex]->addr);
+ temp = readl(port->addr);
xhci_dbg(xhci, "set port reset, actual port %d-%d status = 0x%x\n",
- hcd->self.busnum, wIndex + 1, temp);
+ hcd->self.busnum, portnum1, temp);
break;
case USB_PORT_FEAT_REMOTE_WAKE_MASK:
- xhci_set_remote_wake_mask(xhci, ports[wIndex],
- wake_mask);
- temp = readl(ports[wIndex]->addr);
+ xhci_set_remote_wake_mask(xhci, port, wake_mask);
+ temp = readl(port->addr);
xhci_dbg(xhci, "set port remote wake mask, actual port %d-%d status = 0x%x\n",
- hcd->self.busnum, wIndex + 1, temp);
+ hcd->self.busnum, portnum1, temp);
break;
case USB_PORT_FEAT_BH_PORT_RESET:
temp |= PORT_WR;
- writel(temp, ports[wIndex]->addr);
- temp = readl(ports[wIndex]->addr);
+ writel(temp, port->addr);
+ temp = readl(port->addr);
break;
case USB_PORT_FEAT_U1_TIMEOUT:
if (hcd->speed < HCD_USB3)
goto error;
- temp = readl(ports[wIndex]->addr + PORTPMSC);
+ temp = readl(port->addr + PORTPMSC);
temp &= ~PORT_U1_TIMEOUT_MASK;
temp |= PORT_U1_TIMEOUT(timeout);
- writel(temp, ports[wIndex]->addr + PORTPMSC);
+ writel(temp, port->addr + PORTPMSC);
break;
case USB_PORT_FEAT_U2_TIMEOUT:
if (hcd->speed < HCD_USB3)
goto error;
- temp = readl(ports[wIndex]->addr + PORTPMSC);
+ temp = readl(port->addr + PORTPMSC);
temp &= ~PORT_U2_TIMEOUT_MASK;
temp |= PORT_U2_TIMEOUT(timeout);
- writel(temp, ports[wIndex]->addr + PORTPMSC);
+ writel(temp, port->addr + PORTPMSC);
break;
case USB_PORT_FEAT_TEST:
/* 4.19.6 Port Test Modes (USB2 Test Mode) */
@@ -1541,13 +1543,16 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
goto error;
}
/* unblock any posted writes */
- temp = readl(ports[wIndex]->addr);
+ temp = readl(port->addr);
break;
case ClearPortFeature:
- if (!wIndex || wIndex > max_ports)
+ if (!portnum1 || portnum1 > max_ports)
goto error;
+
+ port = ports[portnum1 - 1];
+
wIndex--;
- temp = readl(ports[wIndex]->addr);
+ temp = readl(port->addr);
if (temp == ~(u32)0) {
xhci_hc_died(xhci);
retval = -ENODEV;
@@ -1557,7 +1562,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
temp = xhci_port_state_to_neutral(temp);
switch (wValue) {
case USB_PORT_FEAT_SUSPEND:
- temp = readl(ports[wIndex]->addr);
+ temp = readl(port->addr);
xhci_dbg(xhci, "clear USB_PORT_FEAT_SUSPEND\n");
xhci_dbg(xhci, "PORTSC %04x\n", temp);
if (temp & PORT_RESET)
@@ -1568,20 +1573,18 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
set_bit(wIndex, &bus_state->resuming_ports);
usb_hcd_start_port_resume(&hcd->self, wIndex);
- xhci_set_link_state(xhci, ports[wIndex],
- XDEV_RESUME);
+ xhci_set_link_state(xhci, port, XDEV_RESUME);
spin_unlock_irqrestore(&xhci->lock, flags);
msleep(USB_RESUME_TIMEOUT);
spin_lock_irqsave(&xhci->lock, flags);
- xhci_set_link_state(xhci, ports[wIndex],
- XDEV_U0);
+ xhci_set_link_state(xhci, port, XDEV_U0);
clear_bit(wIndex, &bus_state->resuming_ports);
usb_hcd_end_port_resume(&hcd->self, wIndex);
}
bus_state->port_c_suspend |= 1 << wIndex;
slot_id = xhci_find_slot_id_by_port(hcd, xhci,
- wIndex + 1);
+ portnum1);
if (!slot_id) {
xhci_dbg(xhci, "slot_id is zero\n");
goto error;
@@ -1599,14 +1602,13 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
case USB_PORT_FEAT_C_PORT_LINK_STATE:
case USB_PORT_FEAT_C_PORT_CONFIG_ERROR:
xhci_clear_port_change_bit(xhci, wValue, wIndex,
- ports[wIndex]->addr, temp);
+ port->addr, temp);
break;
case USB_PORT_FEAT_ENABLE:
- xhci_disable_port(hcd, xhci, wIndex,
- ports[wIndex]->addr, temp);
+ xhci_disable_port(xhci, port);
break;
case USB_PORT_FEAT_POWER:
- xhci_set_port_power(xhci, hcd, wIndex, false, &flags);
+ xhci_set_port_power(xhci, port, false, &flags);
break;
case USB_PORT_FEAT_TEST:
retval = xhci_exit_test_mode(xhci);
@@ -1623,6 +1625,7 @@ error:
spin_unlock_irqrestore(&xhci->lock, flags);
return retval;
}
+EXPORT_SYMBOL_GPL(xhci_hub_control);
/*
* Returns 0 if the status hasn't changed, or the number of bytes in buf.
@@ -1687,8 +1690,8 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
if ((temp & mask) != 0 ||
(bus_state->port_c_suspend & 1 << i) ||
- (bus_state->resume_done[i] && time_after_eq(
- jiffies, bus_state->resume_done[i]))) {
+ (ports[i]->resume_timestamp && time_after_eq(
+ jiffies, ports[i]->resume_timestamp))) {
buf[(i + 1) / 8] |= 1 << (i + 1) % 8;
status = 1;
}
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 81ca2bc1f0be..d0a9467aa5fc 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -1819,17 +1819,43 @@ int xhci_alloc_erst(struct xhci_hcd *xhci,
return 0;
}
-void xhci_free_erst(struct xhci_hcd *xhci, struct xhci_erst *erst)
+static void
+xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
{
- size_t size;
struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
+ size_t erst_size;
+ u64 tmp64;
+ u32 tmp;
- size = sizeof(struct xhci_erst_entry) * (erst->num_entries);
- if (erst->entries)
- dma_free_coherent(dev, size,
- erst->entries,
- erst->erst_dma_addr);
- erst->entries = NULL;
+ if (!ir)
+ return;
+
+ erst_size = sizeof(struct xhci_erst_entry) * (ir->erst.num_entries);
+ if (ir->erst.entries)
+ dma_free_coherent(dev, erst_size,
+ ir->erst.entries,
+ ir->erst.erst_dma_addr);
+ ir->erst.entries = NULL;
+
+ /*
+ * Clean out interrupter registers except ERSTBA. Clearing either the
+ * low or high 32 bits of ERSTBA immediately causes the controller to
+ * dereference the partially cleared 64 bit address, causing IOMMU error.
+ */
+ tmp = readl(&ir->ir_set->erst_size);
+ tmp &= ERST_SIZE_MASK;
+ writel(tmp, &ir->ir_set->erst_size);
+
+ tmp64 = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
+ tmp64 &= (u64) ERST_PTR_MASK;
+ xhci_write_64(xhci, tmp64, &ir->ir_set->erst_dequeue);
+
+ /* free interrrupter event ring */
+ if (ir->event_ring)
+ xhci_ring_free(xhci, ir->event_ring);
+ ir->event_ring = NULL;
+
+ kfree(ir);
}
void xhci_mem_cleanup(struct xhci_hcd *xhci)
@@ -1839,12 +1865,9 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
cancel_delayed_work_sync(&xhci->cmd_timer);
- xhci_free_erst(xhci, &xhci->erst);
-
- if (xhci->event_ring)
- xhci_ring_free(xhci, xhci->event_ring);
- xhci->event_ring = NULL;
- xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed event ring");
+ xhci_free_interrupter(xhci, xhci->interrupter);
+ xhci->interrupter = NULL;
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed primary event ring");
if (xhci->cmd_ring)
xhci_ring_free(xhci, xhci->cmd_ring);
@@ -1929,176 +1952,18 @@ no_bw:
xhci->usb3_rhub.bus_state.bus_suspended = 0;
}
-static int xhci_test_trb_in_td(struct xhci_hcd *xhci,
- struct xhci_segment *input_seg,
- union xhci_trb *start_trb,
- union xhci_trb *end_trb,
- dma_addr_t input_dma,
- struct xhci_segment *result_seg,
- char *test_name, int test_number)
-{
- unsigned long long start_dma;
- unsigned long long end_dma;
- struct xhci_segment *seg;
-
- start_dma = xhci_trb_virt_to_dma(input_seg, start_trb);
- end_dma = xhci_trb_virt_to_dma(input_seg, end_trb);
-
- seg = trb_in_td(xhci, input_seg, start_trb, end_trb, input_dma, false);
- if (seg != result_seg) {
- xhci_warn(xhci, "WARN: %s TRB math test %d failed!\n",
- test_name, test_number);
- xhci_warn(xhci, "Tested TRB math w/ seg %p and "
- "input DMA 0x%llx\n",
- input_seg,
- (unsigned long long) input_dma);
- xhci_warn(xhci, "starting TRB %p (0x%llx DMA), "
- "ending TRB %p (0x%llx DMA)\n",
- start_trb, start_dma,
- end_trb, end_dma);
- xhci_warn(xhci, "Expected seg %p, got seg %p\n",
- result_seg, seg);
- trb_in_td(xhci, input_seg, start_trb, end_trb, input_dma,
- true);
- return -1;
- }
- return 0;
-}
-
-/* TRB math checks for xhci_trb_in_td(), using the command and event rings. */
-static int xhci_check_trb_in_td_math(struct xhci_hcd *xhci)
-{
- struct {
- dma_addr_t input_dma;
- struct xhci_segment *result_seg;
- } simple_test_vector [] = {
- /* A zeroed DMA field should fail */
- { 0, NULL },
- /* One TRB before the ring start should fail */
- { xhci->event_ring->first_seg->dma - 16, NULL },
- /* One byte before the ring start should fail */
- { xhci->event_ring->first_seg->dma - 1, NULL },
- /* Starting TRB should succeed */
- { xhci->event_ring->first_seg->dma, xhci->event_ring->first_seg },
- /* Ending TRB should succeed */
- { xhci->event_ring->first_seg->dma + (TRBS_PER_SEGMENT - 1)*16,
- xhci->event_ring->first_seg },
- /* One byte after the ring end should fail */
- { xhci->event_ring->first_seg->dma + (TRBS_PER_SEGMENT - 1)*16 + 1, NULL },
- /* One TRB after the ring end should fail */
- { xhci->event_ring->first_seg->dma + (TRBS_PER_SEGMENT)*16, NULL },
- /* An address of all ones should fail */
- { (dma_addr_t) (~0), NULL },
- };
- struct {
- struct xhci_segment *input_seg;
- union xhci_trb *start_trb;
- union xhci_trb *end_trb;
- dma_addr_t input_dma;
- struct xhci_segment *result_seg;
- } complex_test_vector [] = {
- /* Test feeding a valid DMA address from a different ring */
- { .input_seg = xhci->event_ring->first_seg,
- .start_trb = xhci->event_ring->first_seg->trbs,
- .end_trb = &xhci->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 1],
- .input_dma = xhci->cmd_ring->first_seg->dma,
- .result_seg = NULL,
- },
- /* Test feeding a valid end TRB from a different ring */
- { .input_seg = xhci->event_ring->first_seg,
- .start_trb = xhci->event_ring->first_seg->trbs,
- .end_trb = &xhci->cmd_ring->first_seg->trbs[TRBS_PER_SEGMENT - 1],
- .input_dma = xhci->cmd_ring->first_seg->dma,
- .result_seg = NULL,
- },
- /* Test feeding a valid start and end TRB from a different ring */
- { .input_seg = xhci->event_ring->first_seg,
- .start_trb = xhci->cmd_ring->first_seg->trbs,
- .end_trb = &xhci->cmd_ring->first_seg->trbs[TRBS_PER_SEGMENT - 1],
- .input_dma = xhci->cmd_ring->first_seg->dma,
- .result_seg = NULL,
- },
- /* TRB in this ring, but after this TD */
- { .input_seg = xhci->event_ring->first_seg,
- .start_trb = &xhci->event_ring->first_seg->trbs[0],
- .end_trb = &xhci->event_ring->first_seg->trbs[3],
- .input_dma = xhci->event_ring->first_seg->dma + 4*16,
- .result_seg = NULL,
- },
- /* TRB in this ring, but before this TD */
- { .input_seg = xhci->event_ring->first_seg,
- .start_trb = &xhci->event_ring->first_seg->trbs[3],
- .end_trb = &xhci->event_ring->first_seg->trbs[6],
- .input_dma = xhci->event_ring->first_seg->dma + 2*16,
- .result_seg = NULL,
- },
- /* TRB in this ring, but after this wrapped TD */
- { .input_seg = xhci->event_ring->first_seg,
- .start_trb = &xhci->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 3],
- .end_trb = &xhci->event_ring->first_seg->trbs[1],
- .input_dma = xhci->event_ring->first_seg->dma + 2*16,
- .result_seg = NULL,
- },
- /* TRB in this ring, but before this wrapped TD */
- { .input_seg = xhci->event_ring->first_seg,
- .start_trb = &xhci->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 3],
- .end_trb = &xhci->event_ring->first_seg->trbs[1],
- .input_dma = xhci->event_ring->first_seg->dma + (TRBS_PER_SEGMENT - 4)*16,
- .result_seg = NULL,
- },
- /* TRB not in this ring, and we have a wrapped TD */
- { .input_seg = xhci->event_ring->first_seg,
- .start_trb = &xhci->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 3],
- .end_trb = &xhci->event_ring->first_seg->trbs[1],
- .input_dma = xhci->cmd_ring->first_seg->dma + 2*16,
- .result_seg = NULL,
- },
- };
-
- unsigned int num_tests;
- int i, ret;
-
- num_tests = ARRAY_SIZE(simple_test_vector);
- for (i = 0; i < num_tests; i++) {
- ret = xhci_test_trb_in_td(xhci,
- xhci->event_ring->first_seg,
- xhci->event_ring->first_seg->trbs,
- &xhci->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 1],
- simple_test_vector[i].input_dma,
- simple_test_vector[i].result_seg,
- "Simple", i);
- if (ret < 0)
- return ret;
- }
-
- num_tests = ARRAY_SIZE(complex_test_vector);
- for (i = 0; i < num_tests; i++) {
- ret = xhci_test_trb_in_td(xhci,
- complex_test_vector[i].input_seg,
- complex_test_vector[i].start_trb,
- complex_test_vector[i].end_trb,
- complex_test_vector[i].input_dma,
- complex_test_vector[i].result_seg,
- "Complex", i);
- if (ret < 0)
- return ret;
- }
- xhci_dbg(xhci, "TRB math tests passed.\n");
- return 0;
-}
-
-static void xhci_set_hc_event_deq(struct xhci_hcd *xhci)
+static void xhci_set_hc_event_deq(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
{
u64 temp;
dma_addr_t deq;
- deq = xhci_trb_virt_to_dma(xhci->event_ring->deq_seg,
- xhci->event_ring->dequeue);
+ deq = xhci_trb_virt_to_dma(ir->event_ring->deq_seg,
+ ir->event_ring->dequeue);
if (!deq)
xhci_warn(xhci, "WARN something wrong with SW event ring "
"dequeue ptr.\n");
/* Update HC event ring dequeue pointer */
- temp = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
+ temp = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
temp &= ERST_PTR_MASK;
/* Don't clear the EHB bit (which is RW1C) because
* there might be more events to service.
@@ -2108,7 +1973,7 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci)
"// Write event ring dequeue pointer, "
"preserving EHB bit");
xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK) | temp,
- &xhci->ir_set->erst_dequeue);
+ &ir->ir_set->erst_dequeue);
}
static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
@@ -2289,6 +2154,9 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
xhci->hw_ports[i].addr = &xhci->op_regs->port_status_base +
NUM_PORT_REGS * i;
xhci->hw_ports[i].hw_portnum = i;
+
+ init_completion(&xhci->hw_ports[i].rexit_done);
+ init_completion(&xhci->hw_ports[i].u3exit_done);
}
xhci->rh_bw = kcalloc_node(num_ports, sizeof(*xhci->rh_bw), flags,
@@ -2375,6 +2243,68 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
return 0;
}
+static struct xhci_interrupter *
+xhci_alloc_interrupter(struct xhci_hcd *xhci, unsigned int intr_num, gfp_t flags)
+{
+ struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
+ struct xhci_interrupter *ir;
+ u64 erst_base;
+ u32 erst_size;
+ int ret;
+
+ if (intr_num > xhci->max_interrupters) {
+ xhci_warn(xhci, "Can't allocate interrupter %d, max interrupters %d\n",
+ intr_num, xhci->max_interrupters);
+ return NULL;
+ }
+
+ if (xhci->interrupter) {
+ xhci_warn(xhci, "Can't allocate already set up interrupter %d\n", intr_num);
+ return NULL;
+ }
+
+ ir = kzalloc_node(sizeof(*ir), flags, dev_to_node(dev));
+ if (!ir)
+ return NULL;
+
+ ir->ir_set = &xhci->run_regs->ir_set[intr_num];
+ ir->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, TYPE_EVENT,
+ 0, flags);
+ if (!ir->event_ring) {
+ xhci_warn(xhci, "Failed to allocate interrupter %d event ring\n", intr_num);
+ goto fail_ir;
+ }
+
+ ret = xhci_alloc_erst(xhci, ir->event_ring, &ir->erst, flags);
+ if (ret) {
+ xhci_warn(xhci, "Failed to allocate interrupter %d erst\n", intr_num);
+ goto fail_ev;
+
+ }
+ /* set ERST count with the number of entries in the segment table */
+ erst_size = readl(&ir->ir_set->erst_size);
+ erst_size &= ERST_SIZE_MASK;
+ erst_size |= ERST_NUM_SEGS;
+ writel(erst_size, &ir->ir_set->erst_size);
+
+ erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base);
+ erst_base &= ERST_PTR_MASK;
+ erst_base |= (ir->erst.erst_dma_addr & (u64) ~ERST_PTR_MASK);
+ xhci_write_64(xhci, erst_base, &ir->ir_set->erst_base);
+
+ /* Set the event ring dequeue address of this interrupter */
+ xhci_set_hc_event_deq(xhci, ir);
+
+ return ir;
+
+fail_ev:
+ xhci_ring_free(xhci, ir->event_ring);
+fail_ir:
+ kfree(ir);
+
+ return NULL;
+}
+
int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
{
dma_addr_t dma;
@@ -2382,7 +2312,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
unsigned int val, val2;
u64 val_64;
u32 page_size, temp;
- int i, ret;
+ int i;
INIT_LIST_HEAD(&xhci->cmd_list);
@@ -2495,48 +2425,13 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
" from cap regs base addr", val);
xhci->dba = (void __iomem *) xhci->cap_regs + val;
/* Set ir_set to interrupt register set 0 */
- xhci->ir_set = &xhci->run_regs->ir_set[0];
-
- /*
- * Event ring setup: Allocate a normal ring, but also setup
- * the event ring segment table (ERST). Section 4.9.3.
- */
- xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Allocating event ring");
- xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, TYPE_EVENT,
- 0, flags);
- if (!xhci->event_ring)
- goto fail;
- if (xhci_check_trb_in_td_math(xhci) < 0)
- goto fail;
-
- ret = xhci_alloc_erst(xhci, xhci->event_ring, &xhci->erst, flags);
- if (ret)
- goto fail;
-
- /* set ERST count with the number of entries in the segment table */
- val = readl(&xhci->ir_set->erst_size);
- val &= ERST_SIZE_MASK;
- val |= ERST_NUM_SEGS;
- xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "// Write ERST size = %i to ir_set 0 (some bits preserved)",
- val);
- writel(val, &xhci->ir_set->erst_size);
+ /* allocate and set up primary interrupter with an event ring. */
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "// Set ERST entries to point to event ring.");
- /* set the segment table base address */
- xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "// Set ERST base address for ir_set 0 = 0x%llx",
- (unsigned long long)xhci->erst.erst_dma_addr);
- val_64 = xhci_read_64(xhci, &xhci->ir_set->erst_base);
- val_64 &= ERST_PTR_MASK;
- val_64 |= (xhci->erst.erst_dma_addr & (u64) ~ERST_PTR_MASK);
- xhci_write_64(xhci, val_64, &xhci->ir_set->erst_base);
-
- /* Set the event ring dequeue address */
- xhci_set_hc_event_deq(xhci);
- xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "Wrote ERST address to ir_set 0.");
+ "Allocating primary event ring");
+ xhci->interrupter = xhci_alloc_interrupter(xhci, 0, flags);
+ if (!xhci->interrupter)
+ goto fail;
xhci->isoc_bei_interval = AVOID_BEI_INTERVAL_MAX;
@@ -2547,13 +2442,6 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
*/
for (i = 0; i < MAX_HC_SLOTS; i++)
xhci->devs[i] = NULL;
- for (i = 0; i < USB_MAXCHILDREN; i++) {
- xhci->usb2_rhub.bus_state.resume_done[i] = 0;
- xhci->usb3_rhub.bus_state.resume_done[i] = 0;
- /* Only the USB 2.0 completions will ever be used. */
- init_completion(&xhci->usb2_rhub.bus_state.rexit_done[i]);
- init_completion(&xhci->usb3_rhub.bus_state.u3exit_done[i]);
- }
if (scratchpad_alloc(xhci, flags))
goto fail;
diff --git a/drivers/usb/host/xhci-mvebu.c b/drivers/usb/host/xhci-mvebu.c
index 60651a50770f..87f1597a0e5a 100644
--- a/drivers/usb/host/xhci-mvebu.c
+++ b/drivers/usb/host/xhci-mvebu.c
@@ -32,7 +32,7 @@ static void xhci_mvebu_mbus_config(void __iomem *base,
/* Program each DRAM CS in a seperate window */
for (win = 0; win < dram->num_cs; win++) {
- const struct mbus_dram_window *cs = dram->cs + win;
+ const struct mbus_dram_window *cs = &dram->cs[win];
writel(((cs->size - 1) & 0xffff0000) | (cs->mbus_attr << 8) |
(dram->mbus_dram_target_id << 4) | 1,
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 5fb55bf19493..b9f9625467d6 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -19,11 +19,11 @@
#include <linux/slab.h>
#include <linux/acpi.h>
#include <linux/usb/of.h>
+#include <linux/reset.h>
#include "xhci.h"
#include "xhci-plat.h"
#include "xhci-mvebu.h"
-#include "xhci-rcar.h"
static struct hc_driver __read_mostly xhci_plat_hc_driver;
@@ -114,14 +114,6 @@ static const struct xhci_plat_priv xhci_plat_marvell_armada3700 = {
.init_quirk = xhci_mvebu_a3700_init_quirk,
};
-static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen2 = {
- SET_XHCI_PLAT_PRIV_FOR_RCAR(XHCI_RCAR_FIRMWARE_NAME_V1)
-};
-
-static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen3 = {
- SET_XHCI_PLAT_PRIV_FOR_RCAR(XHCI_RCAR_FIRMWARE_NAME_V3)
-};
-
static const struct xhci_plat_priv xhci_plat_brcm = {
.quirks = XHCI_RESET_ON_RESUME | XHCI_SUSPEND_RESUME_CLKS,
};
@@ -141,27 +133,6 @@ static const struct of_device_id usb_xhci_of_match[] = {
.compatible = "marvell,armada3700-xhci",
.data = &xhci_plat_marvell_armada3700,
}, {
- .compatible = "renesas,xhci-r8a7790",
- .data = &xhci_plat_renesas_rcar_gen2,
- }, {
- .compatible = "renesas,xhci-r8a7791",
- .data = &xhci_plat_renesas_rcar_gen2,
- }, {
- .compatible = "renesas,xhci-r8a7793",
- .data = &xhci_plat_renesas_rcar_gen2,
- }, {
- .compatible = "renesas,xhci-r8a7795",
- .data = &xhci_plat_renesas_rcar_gen3,
- }, {
- .compatible = "renesas,xhci-r8a7796",
- .data = &xhci_plat_renesas_rcar_gen3,
- }, {
- .compatible = "renesas,rcar-gen2-xhci",
- .data = &xhci_plat_renesas_rcar_gen2,
- }, {
- .compatible = "renesas,rcar-gen3-xhci",
- .data = &xhci_plat_renesas_rcar_gen3,
- }, {
.compatible = "brcm,xhci-brcm-v2",
.data = &xhci_plat_brcm,
}, {
@@ -173,11 +144,10 @@ static const struct of_device_id usb_xhci_of_match[] = {
MODULE_DEVICE_TABLE(of, usb_xhci_of_match);
#endif
-static int xhci_plat_probe(struct platform_device *pdev)
+int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev, const struct xhci_plat_priv *priv_match)
{
- const struct xhci_plat_priv *priv_match;
const struct hc_driver *driver;
- struct device *sysdev, *tmpdev;
+ struct device *tmpdev;
struct xhci_hcd *xhci;
struct resource *res;
struct usb_hcd *hcd, *usb3_hcd;
@@ -195,31 +165,10 @@ static int xhci_plat_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
- /*
- * sysdev must point to a device that is known to the system firmware
- * or PCI hardware. We handle these three cases here:
- * 1. xhci_plat comes from firmware
- * 2. xhci_plat is child of a device from firmware (dwc3-plat)
- * 3. xhci_plat is grandchild of a pci device (dwc3-pci)
- */
- for (sysdev = &pdev->dev; sysdev; sysdev = sysdev->parent) {
- if (is_of_node(sysdev->fwnode) ||
- is_acpi_device_node(sysdev->fwnode))
- break;
-#ifdef CONFIG_PCI
- else if (sysdev->bus == &pci_bus_type)
- break;
-#endif
- }
-
if (!sysdev)
sysdev = &pdev->dev;
- if (WARN_ON(!sysdev->dma_mask))
- /* Platform did not initialize dma_mask */
- ret = dma_coerce_mask_and_coherent(sysdev, DMA_BIT_MASK(64));
- else
- ret = dma_set_mask_and_coherent(sysdev, DMA_BIT_MASK(64));
+ ret = dma_set_mask_and_coherent(sysdev, DMA_BIT_MASK(64));
if (ret)
return ret;
@@ -257,25 +206,30 @@ static int xhci_plat_probe(struct platform_device *pdev)
goto put_hcd;
}
- ret = clk_prepare_enable(xhci->reg_clk);
- if (ret)
- goto put_hcd;
-
xhci->clk = devm_clk_get_optional(&pdev->dev, NULL);
if (IS_ERR(xhci->clk)) {
ret = PTR_ERR(xhci->clk);
- goto disable_reg_clk;
+ goto put_hcd;
}
+ xhci->reset = devm_reset_control_array_get_optional_shared(&pdev->dev);
+ if (IS_ERR(xhci->reset)) {
+ ret = PTR_ERR(xhci->reset);
+ goto put_hcd;
+ }
+
+ ret = reset_control_deassert(xhci->reset);
+ if (ret)
+ goto put_hcd;
+
+ ret = clk_prepare_enable(xhci->reg_clk);
+ if (ret)
+ goto err_reset;
+
ret = clk_prepare_enable(xhci->clk);
if (ret)
goto disable_reg_clk;
- if (pdev->dev.of_node)
- priv_match = of_device_get_match_data(&pdev->dev);
- else
- priv_match = dev_get_platdata(&pdev->dev);
-
if (priv_match) {
priv = hcd_to_xhci_priv(hcd);
/* Just copy data for now */
@@ -377,6 +331,9 @@ disable_clk:
disable_reg_clk:
clk_disable_unprepare(xhci->reg_clk);
+err_reset:
+ reset_control_assert(xhci->reset);
+
put_hcd:
usb_put_hcd(hcd);
@@ -386,8 +343,50 @@ disable_runtime:
return ret;
}
+EXPORT_SYMBOL_GPL(xhci_plat_probe);
+
+static int xhci_generic_plat_probe(struct platform_device *pdev)
+{
+ const struct xhci_plat_priv *priv_match;
+ struct device *sysdev;
+ int ret;
+
+ /*
+ * sysdev must point to a device that is known to the system firmware
+ * or PCI hardware. We handle these three cases here:
+ * 1. xhci_plat comes from firmware
+ * 2. xhci_plat is child of a device from firmware (dwc3-plat)
+ * 3. xhci_plat is grandchild of a pci device (dwc3-pci)
+ */
+ for (sysdev = &pdev->dev; sysdev; sysdev = sysdev->parent) {
+ if (is_of_node(sysdev->fwnode) ||
+ is_acpi_device_node(sysdev->fwnode))
+ break;
+#ifdef CONFIG_PCI
+ else if (sysdev->bus == &pci_bus_type)
+ break;
+#endif
+ }
+
+ if (!sysdev)
+ sysdev = &pdev->dev;
+
+ if (WARN_ON(!sysdev->dma_mask)) {
+ /* Platform did not initialize dma_mask */
+ ret = dma_coerce_mask_and_coherent(sysdev, DMA_BIT_MASK(64));
+ if (ret)
+ return ret;
+ }
+
+ if (pdev->dev.of_node)
+ priv_match = of_device_get_match_data(&pdev->dev);
+ else
+ priv_match = dev_get_platdata(&pdev->dev);
+
+ return xhci_plat_probe(pdev, sysdev, priv_match);
+}
-static int xhci_plat_remove(struct platform_device *dev)
+int xhci_plat_remove(struct platform_device *dev)
{
struct usb_hcd *hcd = platform_get_drvdata(dev);
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
@@ -412,6 +411,7 @@ static int xhci_plat_remove(struct platform_device *dev)
clk_disable_unprepare(clk);
clk_disable_unprepare(reg_clk);
+ reset_control_assert(xhci->reset);
usb_put_hcd(hcd);
pm_runtime_disable(&dev->dev);
@@ -420,6 +420,7 @@ static int xhci_plat_remove(struct platform_device *dev)
return 0;
}
+EXPORT_SYMBOL_GPL(xhci_plat_remove);
static int __maybe_unused xhci_plat_suspend(struct device *dev)
{
@@ -496,13 +497,14 @@ static int __maybe_unused xhci_plat_runtime_resume(struct device *dev)
return xhci_resume(xhci, 0);
}
-static const struct dev_pm_ops xhci_plat_pm_ops = {
+const struct dev_pm_ops xhci_plat_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(xhci_plat_suspend, xhci_plat_resume)
SET_RUNTIME_PM_OPS(xhci_plat_runtime_suspend,
xhci_plat_runtime_resume,
NULL)
};
+EXPORT_SYMBOL_GPL(xhci_plat_pm_ops);
#ifdef CONFIG_ACPI
static const struct acpi_device_id usb_xhci_acpi_match[] = {
@@ -513,8 +515,8 @@ static const struct acpi_device_id usb_xhci_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, usb_xhci_acpi_match);
#endif
-static struct platform_driver usb_xhci_driver = {
- .probe = xhci_plat_probe,
+static struct platform_driver usb_generic_xhci_driver = {
+ .probe = xhci_generic_plat_probe,
.remove = xhci_plat_remove,
.shutdown = usb_hcd_platform_shutdown,
.driver = {
@@ -529,13 +531,13 @@ MODULE_ALIAS("platform:xhci-hcd");
static int __init xhci_plat_init(void)
{
xhci_init_driver(&xhci_plat_hc_driver, &xhci_plat_overrides);
- return platform_driver_register(&usb_xhci_driver);
+ return platform_driver_register(&usb_generic_xhci_driver);
}
module_init(xhci_plat_init);
static void __exit xhci_plat_exit(void)
{
- platform_driver_unregister(&usb_xhci_driver);
+ platform_driver_unregister(&usb_generic_xhci_driver);
}
module_exit(xhci_plat_exit);
diff --git a/drivers/usb/host/xhci-plat.h b/drivers/usb/host/xhci-plat.h
index 1fb149d1fbce..83b5b5aa9f8e 100644
--- a/drivers/usb/host/xhci-plat.h
+++ b/drivers/usb/host/xhci-plat.h
@@ -21,4 +21,11 @@ struct xhci_plat_priv {
#define hcd_to_xhci_priv(h) ((struct xhci_plat_priv *)hcd_to_xhci(h)->priv)
#define xhci_to_priv(x) ((struct xhci_plat_priv *)(x)->priv)
+
+int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev,
+ const struct xhci_plat_priv *priv_match);
+
+int xhci_plat_remove(struct platform_device *dev);
+extern const struct dev_pm_ops xhci_plat_pm_ops;
+
#endif /* _XHCI_PLAT_H */
diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c
index aef0258a7160..7f18509a1d39 100644
--- a/drivers/usb/host/xhci-rcar.c
+++ b/drivers/usb/host/xhci-rcar.c
@@ -10,12 +10,17 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/usb/phy.h>
#include <linux/sys_soc.h>
#include "xhci.h"
#include "xhci-plat.h"
-#include "xhci-rcar.h"
+#include "xhci-rzv2m.h"
+
+#define XHCI_RCAR_FIRMWARE_NAME_V1 "r8a779x_usb3_v1.dlmem"
+#define XHCI_RCAR_FIRMWARE_NAME_V2 "r8a779x_usb3_v2.dlmem"
+#define XHCI_RCAR_FIRMWARE_NAME_V3 "r8a779x_usb3_v3.dlmem"
/*
* - The V3 firmware is for almost all R-Car Gen3 (except r8a7795 ES1.x)
@@ -108,7 +113,7 @@ static int xhci_rcar_is_gen2(struct device *dev)
of_device_is_compatible(node, "renesas,rcar-gen2-xhci");
}
-void xhci_rcar_start(struct usb_hcd *hcd)
+static void xhci_rcar_start(struct usb_hcd *hcd)
{
u32 temp;
@@ -203,7 +208,7 @@ static bool xhci_rcar_wait_for_pll_active(struct usb_hcd *hcd)
}
/* This function needs to initialize a "phy" of usb before */
-int xhci_rcar_init_quirk(struct usb_hcd *hcd)
+static int xhci_rcar_init_quirk(struct usb_hcd *hcd)
{
/* If hcd->regs is NULL, we don't just call the following function */
if (!hcd->regs)
@@ -215,7 +220,7 @@ int xhci_rcar_init_quirk(struct usb_hcd *hcd)
return xhci_rcar_download_firmware(hcd);
}
-int xhci_rcar_resume_quirk(struct usb_hcd *hcd)
+static int xhci_rcar_resume_quirk(struct usb_hcd *hcd)
{
int ret;
@@ -225,3 +230,92 @@ int xhci_rcar_resume_quirk(struct usb_hcd *hcd)
return ret;
}
+
+/*
+ * On R-Car Gen2 and Gen3, the AC64 bit (bit 0) of HCCPARAMS1 is set
+ * to 1. However, these SoCs don't support 64-bit address memory
+ * pointers. So, this driver clears the AC64 bit of xhci->hcc_params
+ * to call dma_set_coherent_mask(dev, DMA_BIT_MASK(32)) in
+ * xhci_gen_setup() by using the XHCI_NO_64BIT_SUPPORT quirk.
+ *
+ * And, since the firmware/internal CPU control the USBSTS.STS_HALT
+ * and the process speed is down when the roothub port enters U3,
+ * long delay for the handshake of STS_HALT is neeed in xhci_suspend()
+ * by using the XHCI_SLOW_SUSPEND quirk.
+ */
+#define SET_XHCI_PLAT_PRIV_FOR_RCAR(firmware) \
+ .firmware_name = firmware, \
+ .quirks = XHCI_NO_64BIT_SUPPORT | XHCI_TRUST_TX_LENGTH | \
+ XHCI_SLOW_SUSPEND, \
+ .init_quirk = xhci_rcar_init_quirk, \
+ .plat_start = xhci_rcar_start, \
+ .resume_quirk = xhci_rcar_resume_quirk,
+
+static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen2 = {
+ SET_XHCI_PLAT_PRIV_FOR_RCAR(XHCI_RCAR_FIRMWARE_NAME_V1)
+};
+
+static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen3 = {
+ SET_XHCI_PLAT_PRIV_FOR_RCAR(XHCI_RCAR_FIRMWARE_NAME_V3)
+};
+
+static const struct xhci_plat_priv xhci_plat_renesas_rzv2m = {
+ .quirks = XHCI_NO_64BIT_SUPPORT | XHCI_TRUST_TX_LENGTH |
+ XHCI_SLOW_SUSPEND,
+ .init_quirk = xhci_rzv2m_init_quirk,
+ .plat_start = xhci_rzv2m_start,
+};
+
+static const struct of_device_id usb_xhci_of_match[] = {
+ {
+ .compatible = "renesas,xhci-r8a7790",
+ .data = &xhci_plat_renesas_rcar_gen2,
+ }, {
+ .compatible = "renesas,xhci-r8a7791",
+ .data = &xhci_plat_renesas_rcar_gen2,
+ }, {
+ .compatible = "renesas,xhci-r8a7793",
+ .data = &xhci_plat_renesas_rcar_gen2,
+ }, {
+ .compatible = "renesas,xhci-r8a7795",
+ .data = &xhci_plat_renesas_rcar_gen3,
+ }, {
+ .compatible = "renesas,xhci-r8a7796",
+ .data = &xhci_plat_renesas_rcar_gen3,
+ }, {
+ .compatible = "renesas,rcar-gen2-xhci",
+ .data = &xhci_plat_renesas_rcar_gen2,
+ }, {
+ .compatible = "renesas,rcar-gen3-xhci",
+ .data = &xhci_plat_renesas_rcar_gen3,
+ }, {
+ .compatible = "renesas,rzv2m-xhci",
+ .data = &xhci_plat_renesas_rzv2m,
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, usb_xhci_of_match);
+
+static int xhci_renesas_probe(struct platform_device *pdev)
+{
+ const struct xhci_plat_priv *priv_match;
+
+ priv_match = of_device_get_match_data(&pdev->dev);
+
+ return xhci_plat_probe(pdev, NULL, priv_match);
+}
+
+static struct platform_driver usb_xhci_renesas_driver = {
+ .probe = xhci_renesas_probe,
+ .remove = xhci_plat_remove,
+ .shutdown = usb_hcd_platform_shutdown,
+ .driver = {
+ .name = "xhci-renesas-hcd",
+ .pm = &xhci_plat_pm_ops,
+ .of_match_table = of_match_ptr(usb_xhci_of_match),
+ },
+};
+module_platform_driver(usb_xhci_renesas_driver);
+
+MODULE_DESCRIPTION("xHCI Platform Host Controller Driver for Renesas R-Car and RZ");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/host/xhci-rcar.h b/drivers/usb/host/xhci-rcar.h
deleted file mode 100644
index 048ad3b8a6c7..000000000000
--- a/drivers/usb/host/xhci-rcar.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * drivers/usb/host/xhci-rcar.h
- *
- * Copyright (C) 2014 Renesas Electronics Corporation
- */
-
-#ifndef _XHCI_RCAR_H
-#define _XHCI_RCAR_H
-
-#define XHCI_RCAR_FIRMWARE_NAME_V1 "r8a779x_usb3_v1.dlmem"
-#define XHCI_RCAR_FIRMWARE_NAME_V2 "r8a779x_usb3_v2.dlmem"
-#define XHCI_RCAR_FIRMWARE_NAME_V3 "r8a779x_usb3_v3.dlmem"
-
-#if IS_ENABLED(CONFIG_USB_XHCI_RCAR)
-void xhci_rcar_start(struct usb_hcd *hcd);
-int xhci_rcar_init_quirk(struct usb_hcd *hcd);
-int xhci_rcar_resume_quirk(struct usb_hcd *hcd);
-#else
-static inline void xhci_rcar_start(struct usb_hcd *hcd)
-{
-}
-
-static inline int xhci_rcar_init_quirk(struct usb_hcd *hcd)
-{
- return 0;
-}
-
-static inline int xhci_rcar_resume_quirk(struct usb_hcd *hcd)
-{
- return 0;
-}
-#endif
-
-/*
- * On R-Car Gen2 and Gen3, the AC64 bit (bit 0) of HCCPARAMS1 is set
- * to 1. However, these SoCs don't support 64-bit address memory
- * pointers. So, this driver clears the AC64 bit of xhci->hcc_params
- * to call dma_set_coherent_mask(dev, DMA_BIT_MASK(32)) in
- * xhci_gen_setup() by using the XHCI_NO_64BIT_SUPPORT quirk.
- *
- * And, since the firmware/internal CPU control the USBSTS.STS_HALT
- * and the process speed is down when the roothub port enters U3,
- * long delay for the handshake of STS_HALT is neeed in xhci_suspend()
- * by using the XHCI_SLOW_SUSPEND quirk.
- */
-#define SET_XHCI_PLAT_PRIV_FOR_RCAR(firmware) \
- .firmware_name = firmware, \
- .quirks = XHCI_NO_64BIT_SUPPORT | XHCI_TRUST_TX_LENGTH | \
- XHCI_SLOW_SUSPEND, \
- .init_quirk = xhci_rcar_init_quirk, \
- .plat_start = xhci_rcar_start, \
- .resume_quirk = xhci_rcar_resume_quirk,
-
-#endif /* _XHCI_RCAR_H */
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index f5b0e1ce22af..eb788c60c1c0 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1833,7 +1833,8 @@ static void xhci_cavium_reset_phy_quirk(struct xhci_hcd *xhci)
}
static void handle_port_status(struct xhci_hcd *xhci,
- union xhci_trb *event)
+ struct xhci_interrupter *ir,
+ union xhci_trb *event)
{
struct usb_hcd *hcd;
u32 port_id;
@@ -1856,7 +1857,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
if ((port_id <= 0) || (port_id > max_ports)) {
xhci_warn(xhci, "Port change event with invalid port ID %d\n",
port_id);
- inc_deq(xhci, xhci->event_ring);
+ inc_deq(xhci, ir->event_ring);
return;
}
@@ -1923,7 +1924,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
goto cleanup;
} else if (!test_bit(hcd_portnum, &bus_state->resuming_ports)) {
xhci_dbg(xhci, "resume HS port %d\n", port_id);
- bus_state->resume_done[hcd_portnum] = jiffies +
+ port->resume_timestamp = jiffies +
msecs_to_jiffies(USB_RESUME_TIMEOUT);
set_bit(hcd_portnum, &bus_state->resuming_ports);
/* Do the rest in GetPortStatus after resume time delay.
@@ -1932,7 +1933,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
*/
set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
mod_timer(&hcd->rh_timer,
- bus_state->resume_done[hcd_portnum]);
+ port->resume_timestamp);
usb_hcd_start_port_resume(&hcd->self, hcd_portnum);
bogus_port_status = true;
}
@@ -1944,7 +1945,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
(portsc & PORT_PLS_MASK) == XDEV_U1 ||
(portsc & PORT_PLS_MASK) == XDEV_U2)) {
xhci_dbg(xhci, "resume SS port %d finished\n", port_id);
- complete(&bus_state->u3exit_done[hcd_portnum]);
+ complete(&port->u3exit_done);
/* We've just brought the device into U0/1/2 through either the
* Resume state after a device remote wakeup, or through the
* U3Exit state after a host-initiated resume. If it's a device
@@ -1969,10 +1970,9 @@ static void handle_port_status(struct xhci_hcd *xhci,
* RExit to a disconnect state). If so, let the driver know it's
* out of the RExit state.
*/
- if (!DEV_SUPERSPEED_ANY(portsc) && hcd->speed < HCD_USB3 &&
- test_and_clear_bit(hcd_portnum,
- &bus_state->rexit_ports)) {
- complete(&bus_state->rexit_done[hcd_portnum]);
+ if (hcd->speed < HCD_USB3 && port->rexit_active) {
+ complete(&port->rexit_done);
+ port->rexit_active = false;
bogus_port_status = true;
goto cleanup;
}
@@ -1986,7 +1986,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
cleanup:
/* Update event ring dequeue pointer before dropping the lock */
- inc_deq(xhci, xhci->event_ring);
+ inc_deq(xhci, ir->event_ring);
/* Don't make the USB core poll the roothub if we got a bad port status
* change event. Besides, at that point we can't tell which roothub
@@ -2519,7 +2519,8 @@ finish_td:
* At this point, the host controller is probably hosed and should be reset.
*/
static int handle_tx_event(struct xhci_hcd *xhci,
- struct xhci_transfer_event *event)
+ struct xhci_interrupter *ir,
+ struct xhci_transfer_event *event)
{
struct xhci_virt_ep *ep;
struct xhci_ring *ep_ring;
@@ -2531,7 +2532,6 @@ static int handle_tx_event(struct xhci_hcd *xhci,
union xhci_trb *ep_trb;
int status = -EINPROGRESS;
struct xhci_ep_ctx *ep_ctx;
- struct list_head *tmp;
u32 trb_comp_code;
int td_num = 0;
bool handling_skipped_tds = false;
@@ -2585,10 +2585,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
}
/* Count current td numbers if ep->skip is set */
- if (ep->skip) {
- list_for_each(tmp, &ep_ring->td_list)
- td_num++;
- }
+ if (ep->skip)
+ td_num += list_count_nodes(&ep_ring->td_list);
/* Look for common error cases */
switch (trb_comp_code) {
@@ -2871,7 +2869,7 @@ cleanup:
* processing missed tds.
*/
if (!handling_skipped_tds)
- inc_deq(xhci, xhci->event_ring);
+ inc_deq(xhci, ir->event_ring);
/*
* If ep->skip is set, it means there are missed tds on the
@@ -2886,8 +2884,8 @@ cleanup:
err_out:
xhci_err(xhci, "@%016llx %08x %08x %08x %08x\n",
(unsigned long long) xhci_trb_virt_to_dma(
- xhci->event_ring->deq_seg,
- xhci->event_ring->dequeue),
+ ir->event_ring->deq_seg,
+ ir->event_ring->dequeue),
lower_32_bits(le64_to_cpu(event->buffer)),
upper_32_bits(le64_to_cpu(event->buffer)),
le32_to_cpu(event->transfer_len),
@@ -2901,7 +2899,7 @@ err_out:
* Returns >0 for "possibly more events to process" (caller should call again),
* otherwise 0 if done. In future, <0 returns should indicate error code.
*/
-static int xhci_handle_event(struct xhci_hcd *xhci)
+static int xhci_handle_event(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
{
union xhci_trb *event;
int update_ptrs = 1;
@@ -2909,18 +2907,18 @@ static int xhci_handle_event(struct xhci_hcd *xhci)
int ret;
/* Event ring hasn't been allocated yet. */
- if (!xhci->event_ring || !xhci->event_ring->dequeue) {
- xhci_err(xhci, "ERROR event ring not ready\n");
+ if (!ir || !ir->event_ring || !ir->event_ring->dequeue) {
+ xhci_err(xhci, "ERROR interrupter not ready\n");
return -ENOMEM;
}
- event = xhci->event_ring->dequeue;
+ event = ir->event_ring->dequeue;
/* Does the HC or OS own the TRB? */
if ((le32_to_cpu(event->event_cmd.flags) & TRB_CYCLE) !=
- xhci->event_ring->cycle_state)
+ ir->event_ring->cycle_state)
return 0;
- trace_xhci_handle_event(xhci->event_ring, &event->generic);
+ trace_xhci_handle_event(ir->event_ring, &event->generic);
/*
* Barrier between reading the TRB_CYCLE (valid) flag above and any
@@ -2935,11 +2933,11 @@ static int xhci_handle_event(struct xhci_hcd *xhci)
handle_cmd_completion(xhci, &event->event_cmd);
break;
case TRB_PORT_STATUS:
- handle_port_status(xhci, event);
+ handle_port_status(xhci, ir, event);
update_ptrs = 0;
break;
case TRB_TRANSFER:
- ret = handle_tx_event(xhci, &event->trans_event);
+ ret = handle_tx_event(xhci, ir, &event->trans_event);
if (ret >= 0)
update_ptrs = 0;
break;
@@ -2963,7 +2961,7 @@ static int xhci_handle_event(struct xhci_hcd *xhci)
if (update_ptrs)
/* Update SW event ring dequeue pointer */
- inc_deq(xhci, xhci->event_ring);
+ inc_deq(xhci, ir->event_ring);
/* Are there more items on the event ring? Caller will call us again to
* check.
@@ -2977,16 +2975,17 @@ static int xhci_handle_event(struct xhci_hcd *xhci)
* - To avoid "Event Ring Full Error" condition
*/
static void xhci_update_erst_dequeue(struct xhci_hcd *xhci,
- union xhci_trb *event_ring_deq)
+ struct xhci_interrupter *ir,
+ union xhci_trb *event_ring_deq)
{
u64 temp_64;
dma_addr_t deq;
- temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
+ temp_64 = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
/* If necessary, update the HW's version of the event ring deq ptr. */
- if (event_ring_deq != xhci->event_ring->dequeue) {
- deq = xhci_trb_virt_to_dma(xhci->event_ring->deq_seg,
- xhci->event_ring->dequeue);
+ if (event_ring_deq != ir->event_ring->dequeue) {
+ deq = xhci_trb_virt_to_dma(ir->event_ring->deq_seg,
+ ir->event_ring->dequeue);
if (deq == 0)
xhci_warn(xhci, "WARN something wrong with SW event ring dequeue ptr\n");
/*
@@ -3004,7 +3003,7 @@ static void xhci_update_erst_dequeue(struct xhci_hcd *xhci,
/* Clear the event handler busy flag (RW1C) */
temp_64 |= ERST_EHB;
- xhci_write_64(xhci, temp_64, &xhci->ir_set->erst_dequeue);
+ xhci_write_64(xhci, temp_64, &ir->ir_set->erst_dequeue);
}
/*
@@ -3016,6 +3015,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
union xhci_trb *event_ring_deq;
+ struct xhci_interrupter *ir;
irqreturn_t ret = IRQ_NONE;
u64 temp_64;
u32 status;
@@ -3053,11 +3053,13 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
status |= STS_EINT;
writel(status, &xhci->op_regs->status);
+ /* This is the handler of the primary interrupter */
+ ir = xhci->interrupter;
if (!hcd->msi_enabled) {
u32 irq_pending;
- irq_pending = readl(&xhci->ir_set->irq_pending);
+ irq_pending = readl(&ir->ir_set->irq_pending);
irq_pending |= IMAN_IP;
- writel(irq_pending, &xhci->ir_set->irq_pending);
+ writel(irq_pending, &ir->ir_set->irq_pending);
}
if (xhci->xhc_state & XHCI_STATE_DYING ||
@@ -3067,22 +3069,22 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
/* Clear the event handler busy flag (RW1C);
* the event ring should be empty.
*/
- temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
+ temp_64 = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
xhci_write_64(xhci, temp_64 | ERST_EHB,
- &xhci->ir_set->erst_dequeue);
+ &ir->ir_set->erst_dequeue);
ret = IRQ_HANDLED;
goto out;
}
- event_ring_deq = xhci->event_ring->dequeue;
+ event_ring_deq = ir->event_ring->dequeue;
/* FIXME this should be a delayed service routine
* that clears the EHB.
*/
- while (xhci_handle_event(xhci) > 0) {
+ while (xhci_handle_event(xhci, ir) > 0) {
if (event_loop++ < TRBS_PER_SEGMENT / 2)
continue;
- xhci_update_erst_dequeue(xhci, event_ring_deq);
- event_ring_deq = xhci->event_ring->dequeue;
+ xhci_update_erst_dequeue(xhci, ir, event_ring_deq);
+ event_ring_deq = ir->event_ring->dequeue;
/* ring is half-full, force isoc trbs to interrupt more often */
if (xhci->isoc_bei_interval > AVOID_BEI_INTERVAL_MIN)
@@ -3091,7 +3093,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
event_loop = 0;
}
- xhci_update_erst_dequeue(xhci, event_ring_deq);
+ xhci_update_erst_dequeue(xhci, ir, event_ring_deq);
ret = IRQ_HANDLED;
out:
diff --git a/drivers/usb/host/xhci-rzv2m.c b/drivers/usb/host/xhci-rzv2m.c
new file mode 100644
index 000000000000..ec65b24eafa8
--- /dev/null
+++ b/drivers/usb/host/xhci-rzv2m.c
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * xHCI host controller driver for RZ/V2M
+ *
+ * Copyright (C) 2022 Renesas Electronics Corporation
+ */
+
+#include <linux/usb/rzv2m_usb3drd.h>
+#include "xhci-plat.h"
+#include "xhci-rzv2m.h"
+
+#define RZV2M_USB3_INTEN 0x1044 /* Interrupt Enable */
+
+#define RZV2M_USB3_INT_XHC_ENA BIT(0)
+#define RZV2M_USB3_INT_HSE_ENA BIT(2)
+#define RZV2M_USB3_INT_ENA_VAL (RZV2M_USB3_INT_XHC_ENA \
+ | RZV2M_USB3_INT_HSE_ENA)
+
+int xhci_rzv2m_init_quirk(struct usb_hcd *hcd)
+{
+ struct device *dev = hcd->self.controller;
+
+ rzv2m_usb3drd_reset(dev->parent, true);
+
+ return 0;
+}
+
+void xhci_rzv2m_start(struct usb_hcd *hcd)
+{
+ u32 int_en;
+
+ if (hcd->regs) {
+ /* Interrupt Enable */
+ int_en = readl(hcd->regs + RZV2M_USB3_INTEN);
+ int_en |= RZV2M_USB3_INT_ENA_VAL;
+ writel(int_en, hcd->regs + RZV2M_USB3_INTEN);
+ }
+}
diff --git a/drivers/usb/host/xhci-rzv2m.h b/drivers/usb/host/xhci-rzv2m.h
new file mode 100644
index 000000000000..12448b0e8d5b
--- /dev/null
+++ b/drivers/usb/host/xhci-rzv2m.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __XHCI_RZV2M_H
+#define __XHCI_RZV2M_H
+
+#if IS_ENABLED(CONFIG_USB_XHCI_RZV2M)
+void xhci_rzv2m_start(struct usb_hcd *hcd);
+int xhci_rzv2m_init_quirk(struct usb_hcd *hcd);
+#else
+static inline void xhci_rzv2m_start(struct usb_hcd *hcd) {}
+static inline int xhci_rzv2m_init_quirk(struct usb_hcd *hcd)
+{
+ return -EINVAL;
+}
+#endif
+
+#endif /* __XHCI_RZV2M_H */
diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c
index bdb776553826..1ff22f675930 100644
--- a/drivers/usb/host/xhci-tegra.c
+++ b/drivers/usb/host/xhci-tegra.c
@@ -44,6 +44,9 @@
#define XUSB_CFG_4 0x010
#define XUSB_BASE_ADDR_SHIFT 15
#define XUSB_BASE_ADDR_MASK 0x1ffff
+#define XUSB_CFG_7 0x01c
+#define XUSB_BASE2_ADDR_SHIFT 16
+#define XUSB_BASE2_ADDR_MASK 0xffff
#define XUSB_CFG_16 0x040
#define XUSB_CFG_24 0x060
#define XUSB_CFG_AXI_CFG 0x0f8
@@ -75,6 +78,20 @@
#define MBOX_SMI_INTR_FW_HANG BIT(1)
#define MBOX_SMI_INTR_EN BIT(3)
+/* BAR2 registers */
+#define XUSB_BAR2_ARU_MBOX_CMD 0x004
+#define XUSB_BAR2_ARU_MBOX_DATA_IN 0x008
+#define XUSB_BAR2_ARU_MBOX_DATA_OUT 0x00c
+#define XUSB_BAR2_ARU_MBOX_OWNER 0x010
+#define XUSB_BAR2_ARU_SMI_INTR 0x014
+#define XUSB_BAR2_ARU_SMI_ARU_FW_SCRATCH_DATA0 0x01c
+#define XUSB_BAR2_ARU_IFRDMA_CFG0 0x0e0
+#define XUSB_BAR2_ARU_IFRDMA_CFG1 0x0e4
+#define XUSB_BAR2_ARU_IFRDMA_STREAMID_FIELD 0x0e8
+#define XUSB_BAR2_ARU_C11_CSBRANGE 0x9c
+#define XUSB_BAR2_ARU_FW_SCRATCH 0x1000
+#define XUSB_BAR2_CSB_BASE_ADDR 0x2000
+
/* IPFS registers */
#define IPFS_XUSB_HOST_MSI_BAR_SZ_0 0x0c0
#define IPFS_XUSB_HOST_MSI_AXI_BAR_ST_0 0x0c4
@@ -111,6 +128,9 @@
#define IMFILLRNG1_TAG_HI_SHIFT 16
#define XUSB_FALC_IMFILLCTL 0x158
+/* CSB ARU registers */
+#define XUSB_CSB_ARU_SCRATCH0 0x100100
+
/* MP CSB registers */
#define XUSB_CSB_MP_ILOAD_ATTR 0x101a00
#define XUSB_CSB_MP_ILOAD_BASE_LO 0x101a04
@@ -131,6 +151,9 @@
#define IMEM_BLOCK_SIZE 256
+#define FW_IOCTL_TYPE_SHIFT 24
+#define FW_IOCTL_CFGTBL_READ 17
+
struct tegra_xusb_fw_header {
__le32 boot_loadaddr_in_imem;
__le32 boot_codedfi_offset;
@@ -175,6 +198,7 @@ struct tegra_xusb_mbox_regs {
u16 data_in;
u16 data_out;
u16 owner;
+ u16 smi_intr;
};
struct tegra_xusb_context_soc {
@@ -189,6 +213,14 @@ struct tegra_xusb_context_soc {
} fpci;
};
+struct tegra_xusb;
+struct tegra_xusb_soc_ops {
+ u32 (*mbox_reg_readl)(struct tegra_xusb *tegra, unsigned int offset);
+ void (*mbox_reg_writel)(struct tegra_xusb *tegra, u32 value, unsigned int offset);
+ u32 (*csb_reg_readl)(struct tegra_xusb *tegra, unsigned int offset);
+ void (*csb_reg_writel)(struct tegra_xusb *tegra, u32 value, unsigned int offset);
+};
+
struct tegra_xusb_soc {
const char *firmware;
const char * const *supply_names;
@@ -205,11 +237,14 @@ struct tegra_xusb_soc {
} ports;
struct tegra_xusb_mbox_regs mbox;
+ const struct tegra_xusb_soc_ops *ops;
bool scale_ss_clock;
bool has_ipfs;
bool lpm_support;
bool otg_reset_sspi;
+
+ bool has_bar2;
};
struct tegra_xusb_context {
@@ -230,6 +265,8 @@ struct tegra_xusb {
void __iomem *ipfs_base;
void __iomem *fpci_base;
+ void __iomem *bar2_base;
+ struct resource *bar2;
const struct tegra_xusb_soc *soc;
@@ -274,6 +311,7 @@ struct tegra_xusb {
bool suspended;
struct tegra_xusb_context context;
+ u8 lp0_utmi_pad_mask;
};
static struct hc_driver __read_mostly tegra_xhci_hc_driver;
@@ -300,8 +338,34 @@ static inline void ipfs_writel(struct tegra_xusb *tegra, u32 value,
writel(value, tegra->ipfs_base + offset);
}
+static inline u32 bar2_readl(struct tegra_xusb *tegra, unsigned int offset)
+{
+ return readl(tegra->bar2_base + offset);
+}
+
+static inline void bar2_writel(struct tegra_xusb *tegra, u32 value,
+ unsigned int offset)
+{
+ writel(value, tegra->bar2_base + offset);
+}
+
static u32 csb_readl(struct tegra_xusb *tegra, unsigned int offset)
{
+ const struct tegra_xusb_soc_ops *ops = tegra->soc->ops;
+
+ return ops->csb_reg_readl(tegra, offset);
+}
+
+static void csb_writel(struct tegra_xusb *tegra, u32 value,
+ unsigned int offset)
+{
+ const struct tegra_xusb_soc_ops *ops = tegra->soc->ops;
+
+ ops->csb_reg_writel(tegra, value, offset);
+}
+
+static u32 fpci_csb_readl(struct tegra_xusb *tegra, unsigned int offset)
+{
u32 page = CSB_PAGE_SELECT(offset);
u32 ofs = CSB_PAGE_OFFSET(offset);
@@ -310,8 +374,8 @@ static u32 csb_readl(struct tegra_xusb *tegra, unsigned int offset)
return fpci_readl(tegra, XUSB_CFG_CSB_BASE_ADDR + ofs);
}
-static void csb_writel(struct tegra_xusb *tegra, u32 value,
- unsigned int offset)
+static void fpci_csb_writel(struct tegra_xusb *tegra, u32 value,
+ unsigned int offset)
{
u32 page = CSB_PAGE_SELECT(offset);
u32 ofs = CSB_PAGE_OFFSET(offset);
@@ -320,6 +384,26 @@ static void csb_writel(struct tegra_xusb *tegra, u32 value,
fpci_writel(tegra, value, XUSB_CFG_CSB_BASE_ADDR + ofs);
}
+static u32 bar2_csb_readl(struct tegra_xusb *tegra, unsigned int offset)
+{
+ u32 page = CSB_PAGE_SELECT(offset);
+ u32 ofs = CSB_PAGE_OFFSET(offset);
+
+ bar2_writel(tegra, page, XUSB_BAR2_ARU_C11_CSBRANGE);
+
+ return bar2_readl(tegra, XUSB_BAR2_CSB_BASE_ADDR + ofs);
+}
+
+static void bar2_csb_writel(struct tegra_xusb *tegra, u32 value,
+ unsigned int offset)
+{
+ u32 page = CSB_PAGE_SELECT(offset);
+ u32 ofs = CSB_PAGE_OFFSET(offset);
+
+ bar2_writel(tegra, page, XUSB_BAR2_ARU_C11_CSBRANGE);
+ bar2_writel(tegra, value, XUSB_BAR2_CSB_BASE_ADDR + ofs);
+}
+
static int tegra_xusb_set_ss_clk(struct tegra_xusb *tegra,
unsigned long rate)
{
@@ -451,6 +535,7 @@ static bool tegra_xusb_mbox_cmd_requires_ack(enum tegra_xusb_mbox_cmd cmd)
static int tegra_xusb_mbox_send(struct tegra_xusb *tegra,
const struct tegra_xusb_mbox_msg *msg)
{
+ const struct tegra_xusb_soc_ops *ops = tegra->soc->ops;
bool wait_for_idle = false;
u32 value;
@@ -459,15 +544,15 @@ static int tegra_xusb_mbox_send(struct tegra_xusb *tegra,
* ACK/NAK messages.
*/
if (!(msg->cmd == MBOX_CMD_ACK || msg->cmd == MBOX_CMD_NAK)) {
- value = fpci_readl(tegra, tegra->soc->mbox.owner);
+ value = ops->mbox_reg_readl(tegra, tegra->soc->mbox.owner);
if (value != MBOX_OWNER_NONE) {
dev_err(tegra->dev, "mailbox is busy\n");
return -EBUSY;
}
- fpci_writel(tegra, MBOX_OWNER_SW, tegra->soc->mbox.owner);
+ ops->mbox_reg_writel(tegra, MBOX_OWNER_SW, tegra->soc->mbox.owner);
- value = fpci_readl(tegra, tegra->soc->mbox.owner);
+ value = ops->mbox_reg_readl(tegra, tegra->soc->mbox.owner);
if (value != MBOX_OWNER_SW) {
dev_err(tegra->dev, "failed to acquire mailbox\n");
return -EBUSY;
@@ -477,17 +562,17 @@ static int tegra_xusb_mbox_send(struct tegra_xusb *tegra,
}
value = tegra_xusb_mbox_pack(msg);
- fpci_writel(tegra, value, tegra->soc->mbox.data_in);
+ ops->mbox_reg_writel(tegra, value, tegra->soc->mbox.data_in);
- value = fpci_readl(tegra, tegra->soc->mbox.cmd);
+ value = ops->mbox_reg_readl(tegra, tegra->soc->mbox.cmd);
value |= MBOX_INT_EN | MBOX_DEST_FALC;
- fpci_writel(tegra, value, tegra->soc->mbox.cmd);
+ ops->mbox_reg_writel(tegra, value, tegra->soc->mbox.cmd);
if (wait_for_idle) {
unsigned long timeout = jiffies + msecs_to_jiffies(250);
while (time_before(jiffies, timeout)) {
- value = fpci_readl(tegra, tegra->soc->mbox.owner);
+ value = ops->mbox_reg_readl(tegra, tegra->soc->mbox.owner);
if (value == MBOX_OWNER_NONE)
break;
@@ -495,7 +580,7 @@ static int tegra_xusb_mbox_send(struct tegra_xusb *tegra,
}
if (time_after(jiffies, timeout))
- value = fpci_readl(tegra, tegra->soc->mbox.owner);
+ value = ops->mbox_reg_readl(tegra, tegra->soc->mbox.owner);
if (value != MBOX_OWNER_NONE)
return -ETIMEDOUT;
@@ -507,11 +592,12 @@ static int tegra_xusb_mbox_send(struct tegra_xusb *tegra,
static irqreturn_t tegra_xusb_mbox_irq(int irq, void *data)
{
struct tegra_xusb *tegra = data;
+ const struct tegra_xusb_soc_ops *ops = tegra->soc->ops;
u32 value;
/* clear mailbox interrupts */
- value = fpci_readl(tegra, XUSB_CFG_ARU_SMI_INTR);
- fpci_writel(tegra, value, XUSB_CFG_ARU_SMI_INTR);
+ value = ops->mbox_reg_readl(tegra, tegra->soc->mbox.smi_intr);
+ ops->mbox_reg_writel(tegra, value, tegra->soc->mbox.smi_intr);
if (value & MBOX_SMI_INTR_FW_HANG)
dev_err(tegra->dev, "controller firmware hang\n");
@@ -664,6 +750,7 @@ static void tegra_xusb_mbox_handle(struct tegra_xusb *tegra,
static irqreturn_t tegra_xusb_mbox_thread(int irq, void *data)
{
struct tegra_xusb *tegra = data;
+ const struct tegra_xusb_soc_ops *ops = tegra->soc->ops;
struct tegra_xusb_mbox_msg msg;
u32 value;
@@ -672,16 +759,16 @@ static irqreturn_t tegra_xusb_mbox_thread(int irq, void *data)
if (pm_runtime_suspended(tegra->dev) || tegra->suspended)
goto out;
- value = fpci_readl(tegra, tegra->soc->mbox.data_out);
+ value = ops->mbox_reg_readl(tegra, tegra->soc->mbox.data_out);
tegra_xusb_mbox_unpack(&msg, value);
- value = fpci_readl(tegra, tegra->soc->mbox.cmd);
+ value = ops->mbox_reg_readl(tegra, tegra->soc->mbox.cmd);
value &= ~MBOX_DEST_SMI;
- fpci_writel(tegra, value, tegra->soc->mbox.cmd);
+ ops->mbox_reg_writel(tegra, value, tegra->soc->mbox.cmd);
/* clear mailbox owner if no ACK/NAK is required */
if (!tegra_xusb_mbox_cmd_requires_ack(msg.cmd))
- fpci_writel(tegra, MBOX_OWNER_NONE, tegra->soc->mbox.owner);
+ ops->mbox_reg_writel(tegra, MBOX_OWNER_NONE, tegra->soc->mbox.owner);
tegra_xusb_mbox_handle(tegra, &msg);
@@ -709,6 +796,15 @@ static void tegra_xusb_config(struct tegra_xusb *tegra)
value |= regs & (XUSB_BASE_ADDR_MASK << XUSB_BASE_ADDR_SHIFT);
fpci_writel(tegra, value, XUSB_CFG_4);
+ /* Program BAR2 space */
+ if (tegra->bar2) {
+ value = fpci_readl(tegra, XUSB_CFG_7);
+ value &= ~(XUSB_BASE2_ADDR_MASK << XUSB_BASE2_ADDR_SHIFT);
+ value |= tegra->bar2->start &
+ (XUSB_BASE2_ADDR_MASK << XUSB_BASE2_ADDR_SHIFT);
+ fpci_writel(tegra, value, XUSB_CFG_7);
+ }
+
usleep_range(100, 200);
/* Enable bus master */
@@ -881,21 +977,36 @@ static int tegra_xusb_request_firmware(struct tegra_xusb *tegra)
return 0;
}
-static int tegra_xusb_load_firmware(struct tegra_xusb *tegra)
+static int tegra_xusb_wait_for_falcon(struct tegra_xusb *tegra)
+{
+ struct xhci_cap_regs __iomem *cap_regs;
+ struct xhci_op_regs __iomem *op_regs;
+ int ret;
+ u32 value;
+
+ cap_regs = tegra->regs;
+ op_regs = tegra->regs + HC_LENGTH(readl(&cap_regs->hc_capbase));
+
+ ret = readl_poll_timeout(&op_regs->status, value, !(value & STS_CNR), 1000, 200000);
+
+ if (ret)
+ dev_err(tegra->dev, "XHCI Controller not ready. Falcon state: 0x%x\n",
+ csb_readl(tegra, XUSB_FALC_CPUCTL));
+
+ return ret;
+}
+
+static int tegra_xusb_load_firmware_rom(struct tegra_xusb *tegra)
{
unsigned int code_tag_blocks, code_size_blocks, code_blocks;
- struct xhci_cap_regs __iomem *cap = tegra->regs;
struct tegra_xusb_fw_header *header;
struct device *dev = tegra->dev;
- struct xhci_op_regs __iomem *op;
- unsigned long timeout;
time64_t timestamp;
u64 address;
u32 value;
int err;
header = (struct tegra_xusb_fw_header *)tegra->fw.virt;
- op = tegra->regs + HC_LENGTH(readl(&cap->hc_capbase));
if (csb_readl(tegra, XUSB_CSB_MP_ILOAD_BASE_LO) != 0) {
dev_info(dev, "Firmware already loaded, Falcon state %#x\n",
@@ -968,30 +1079,54 @@ static int tegra_xusb_load_firmware(struct tegra_xusb *tegra)
/* Boot Falcon CPU and wait for USBSTS_CNR to get cleared. */
csb_writel(tegra, CPUCTL_STARTCPU, XUSB_FALC_CPUCTL);
- timeout = jiffies + msecs_to_jiffies(200);
+ if (tegra_xusb_wait_for_falcon(tegra))
+ return -EIO;
- do {
- value = readl(&op->status);
- if ((value & STS_CNR) == 0)
- break;
+ timestamp = le32_to_cpu(header->fwimg_created_time);
+
+ dev_info(dev, "Firmware timestamp: %ptTs UTC\n", &timestamp);
+
+ return 0;
+}
+
+static u32 tegra_xusb_read_firmware_header(struct tegra_xusb *tegra, u32 offset)
+{
+ /*
+ * We only accept reading the firmware config table
+ * The offset should not exceed the fw header structure
+ */
+ if (offset >= sizeof(struct tegra_xusb_fw_header))
+ return 0;
- usleep_range(1000, 2000);
- } while (time_is_after_jiffies(timeout));
+ bar2_writel(tegra, (FW_IOCTL_CFGTBL_READ << FW_IOCTL_TYPE_SHIFT) | offset,
+ XUSB_BAR2_ARU_FW_SCRATCH);
+ return bar2_readl(tegra, XUSB_BAR2_ARU_SMI_ARU_FW_SCRATCH_DATA0);
+}
- value = readl(&op->status);
- if (value & STS_CNR) {
- value = csb_readl(tegra, XUSB_FALC_CPUCTL);
- dev_err(dev, "XHCI controller not read: %#010x\n", value);
+static int tegra_xusb_init_ifr_firmware(struct tegra_xusb *tegra)
+{
+ time64_t timestamp;
+
+ if (tegra_xusb_wait_for_falcon(tegra))
return -EIO;
- }
- timestamp = le32_to_cpu(header->fwimg_created_time);
+#define offsetof_32(X, Y) ((u8)(offsetof(X, Y) / sizeof(__le32)))
+ timestamp = tegra_xusb_read_firmware_header(tegra, offsetof_32(struct tegra_xusb_fw_header,
+ fwimg_created_time) << 2);
- dev_info(dev, "Firmware timestamp: %ptTs UTC\n", &timestamp);
+ dev_info(tegra->dev, "Firmware timestamp: %ptTs UTC\n", &timestamp);
return 0;
}
+static int tegra_xusb_load_firmware(struct tegra_xusb *tegra)
+{
+ if (!tegra->soc->firmware)
+ return tegra_xusb_init_ifr_firmware(tegra);
+ else
+ return tegra_xusb_load_firmware_rom(tegra);
+}
+
static void tegra_xusb_powerdomain_remove(struct device *dev,
struct tegra_xusb *tegra)
{
@@ -1435,6 +1570,10 @@ static int tegra_xusb_probe(struct platform_device *pdev)
tegra->ipfs_base = devm_platform_ioremap_resource(pdev, 2);
if (IS_ERR(tegra->ipfs_base))
return PTR_ERR(tegra->ipfs_base);
+ } else if (tegra->soc->has_bar2) {
+ tegra->bar2_base = devm_platform_get_and_ioremap_resource(pdev, 2, &tegra->bar2);
+ if (IS_ERR(tegra->bar2_base))
+ return PTR_ERR(tegra->bar2_base);
}
tegra->xhci_irq = platform_get_irq(pdev, 0);
@@ -1651,10 +1790,13 @@ static int tegra_xusb_probe(struct platform_device *pdev)
goto disable_phy;
}
- err = tegra_xusb_request_firmware(tegra);
- if (err < 0) {
- dev_err(&pdev->dev, "failed to request firmware: %d\n", err);
- goto disable_phy;
+ if (tegra->soc->firmware) {
+ err = tegra_xusb_request_firmware(tegra);
+ if (err < 0) {
+ dev_err(&pdev->dev,
+ "failed to request firmware: %d\n", err);
+ goto disable_phy;
+ }
}
err = tegra_xusb_unpowergate_partitions(tegra);
@@ -1951,10 +2093,24 @@ static void tegra_xhci_disable_phy_wake(struct tegra_xusb *tegra)
struct tegra_xusb_padctl *padctl = tegra->padctl;
unsigned int i;
+ for (i = 0; i < tegra->num_usb_phys; i++) {
+ struct phy *phy = tegra_xusb_get_phy(tegra, "usb2", i);
+
+ if (!phy)
+ continue;
+
+ if (tegra_xusb_padctl_remote_wake_detected(padctl, phy))
+ tegra_phy_xusb_utmi_pad_power_on(phy);
+ }
+
for (i = 0; i < tegra->num_phys; i++) {
if (!tegra->phys[i])
continue;
+ if (tegra_xusb_padctl_remote_wake_detected(padctl, tegra->phys[i]))
+ dev_dbg(tegra->dev, "%pOF remote wake detected\n",
+ tegra->phys[i]->dev.of_node);
+
tegra_xusb_padctl_disable_phy_wake(padctl, tegra->phys[i]);
}
}
@@ -1972,6 +2128,28 @@ static void tegra_xhci_disable_phy_sleepwalk(struct tegra_xusb *tegra)
}
}
+static void tegra_xhci_program_utmi_power_lp0_exit(struct tegra_xusb *tegra)
+{
+ unsigned int i, index_to_usb2;
+ struct phy *phy;
+
+ for (i = 0; i < tegra->soc->num_types; i++) {
+ if (strcmp(tegra->soc->phy_types[i].name, "usb2") == 0)
+ index_to_usb2 = i;
+ }
+
+ for (i = 0; i < tegra->num_usb_phys; i++) {
+ if (!is_host_mode_phy(tegra, index_to_usb2, i))
+ continue;
+
+ phy = tegra_xusb_get_phy(tegra, "usb2", i);
+ if (tegra->lp0_utmi_pad_mask & BIT(i))
+ tegra_phy_xusb_utmi_pad_power_on(phy);
+ else
+ tegra_phy_xusb_utmi_pad_power_down(phy);
+ }
+}
+
static int tegra_xusb_enter_elpg(struct tegra_xusb *tegra, bool runtime)
{
struct xhci_hcd *xhci = hcd_to_xhci(tegra->hcd);
@@ -1980,6 +2158,7 @@ static int tegra_xusb_enter_elpg(struct tegra_xusb *tegra, bool runtime)
unsigned int i;
int err;
u32 usbcmd;
+ u32 portsc;
dev_dbg(dev, "entering ELPG\n");
@@ -1993,6 +2172,15 @@ static int tegra_xusb_enter_elpg(struct tegra_xusb *tegra, bool runtime)
goto out;
}
+ for (i = 0; i < tegra->num_usb_phys; i++) {
+ if (!xhci->usb2_rhub.ports[i])
+ continue;
+ portsc = readl(xhci->usb2_rhub.ports[i]->addr);
+ tegra->lp0_utmi_pad_mask &= ~BIT(i);
+ if (((portsc & PORT_PLS_MASK) == XDEV_U3) || ((portsc & DEV_SPEED_MASK) == XDEV_FS))
+ tegra->lp0_utmi_pad_mask |= BIT(i);
+ }
+
err = xhci_suspend(xhci, wakeup);
if (err < 0) {
dev_err(tegra->dev, "failed to suspend XHCI: %d\n", err);
@@ -2066,6 +2254,8 @@ static int tegra_xusb_exit_elpg(struct tegra_xusb *tegra, bool runtime)
phy_power_on(tegra->phys[i]);
}
+ if (tegra->suspended)
+ tegra_xhci_program_utmi_power_lp0_exit(tegra);
tegra_xusb_config(tegra);
tegra_xusb_restore_context(tegra);
@@ -2271,6 +2461,13 @@ static const struct tegra_xusb_context_soc tegra124_xusb_context = {
},
};
+static const struct tegra_xusb_soc_ops tegra124_ops = {
+ .mbox_reg_readl = &fpci_readl,
+ .mbox_reg_writel = &fpci_writel,
+ .csb_reg_readl = &fpci_csb_readl,
+ .csb_reg_writel = &fpci_csb_writel,
+};
+
static const struct tegra_xusb_soc tegra124_soc = {
.firmware = "nvidia/tegra124/xusb.bin",
.supply_names = tegra124_supply_names,
@@ -2286,11 +2483,13 @@ static const struct tegra_xusb_soc tegra124_soc = {
.scale_ss_clock = true,
.has_ipfs = true,
.otg_reset_sspi = false,
+ .ops = &tegra124_ops,
.mbox = {
.cmd = 0xe4,
.data_in = 0xe8,
.data_out = 0xec,
.owner = 0xf0,
+ .smi_intr = XUSB_CFG_ARU_SMI_INTR,
},
};
MODULE_FIRMWARE("nvidia/tegra124/xusb.bin");
@@ -2322,11 +2521,13 @@ static const struct tegra_xusb_soc tegra210_soc = {
.scale_ss_clock = false,
.has_ipfs = true,
.otg_reset_sspi = true,
+ .ops = &tegra124_ops,
.mbox = {
.cmd = 0xe4,
.data_in = 0xe8,
.data_out = 0xec,
.owner = 0xf0,
+ .smi_intr = XUSB_CFG_ARU_SMI_INTR,
},
};
MODULE_FIRMWARE("nvidia/tegra210/xusb.bin");
@@ -2363,11 +2564,13 @@ static const struct tegra_xusb_soc tegra186_soc = {
.scale_ss_clock = false,
.has_ipfs = false,
.otg_reset_sspi = false,
+ .ops = &tegra124_ops,
.mbox = {
.cmd = 0xe4,
.data_in = 0xe8,
.data_out = 0xec,
.owner = 0xf0,
+ .smi_intr = XUSB_CFG_ARU_SMI_INTR,
},
.lpm_support = true,
};
@@ -2394,21 +2597,56 @@ static const struct tegra_xusb_soc tegra194_soc = {
.scale_ss_clock = false,
.has_ipfs = false,
.otg_reset_sspi = false,
+ .ops = &tegra124_ops,
.mbox = {
.cmd = 0x68,
.data_in = 0x6c,
.data_out = 0x70,
.owner = 0x74,
+ .smi_intr = XUSB_CFG_ARU_SMI_INTR,
},
.lpm_support = true,
};
MODULE_FIRMWARE("nvidia/tegra194/xusb.bin");
+static const struct tegra_xusb_soc_ops tegra234_ops = {
+ .mbox_reg_readl = &bar2_readl,
+ .mbox_reg_writel = &bar2_writel,
+ .csb_reg_readl = &bar2_csb_readl,
+ .csb_reg_writel = &bar2_csb_writel,
+};
+
+static const struct tegra_xusb_soc tegra234_soc = {
+ .supply_names = tegra194_supply_names,
+ .num_supplies = ARRAY_SIZE(tegra194_supply_names),
+ .phy_types = tegra194_phy_types,
+ .num_types = ARRAY_SIZE(tegra194_phy_types),
+ .context = &tegra186_xusb_context,
+ .ports = {
+ .usb3 = { .offset = 0, .count = 4, },
+ .usb2 = { .offset = 4, .count = 4, },
+ },
+ .scale_ss_clock = false,
+ .has_ipfs = false,
+ .otg_reset_sspi = false,
+ .ops = &tegra234_ops,
+ .mbox = {
+ .cmd = XUSB_BAR2_ARU_MBOX_CMD,
+ .data_in = XUSB_BAR2_ARU_MBOX_DATA_IN,
+ .data_out = XUSB_BAR2_ARU_MBOX_DATA_OUT,
+ .owner = XUSB_BAR2_ARU_MBOX_OWNER,
+ .smi_intr = XUSB_BAR2_ARU_SMI_INTR,
+ },
+ .lpm_support = true,
+ .has_bar2 = true,
+};
+
static const struct of_device_id tegra_xusb_of_match[] = {
{ .compatible = "nvidia,tegra124-xusb", .data = &tegra124_soc },
{ .compatible = "nvidia,tegra210-xusb", .data = &tegra210_soc },
{ .compatible = "nvidia,tegra186-xusb", .data = &tegra186_soc },
{ .compatible = "nvidia,tegra194-xusb", .data = &tegra194_soc },
+ { .compatible = "nvidia,tegra234-xusb", .data = &tegra234_soc },
{ },
};
MODULE_DEVICE_TABLE(of, tegra_xusb_of_match);
@@ -2437,8 +2675,84 @@ static int tegra_xhci_setup(struct usb_hcd *hcd)
return xhci_gen_setup(hcd, tegra_xhci_quirks);
}
+static int tegra_xhci_hub_control(struct usb_hcd *hcd, u16 type_req, u16 value, u16 index,
+ char *buf, u16 length)
+{
+ struct tegra_xusb *tegra = dev_get_drvdata(hcd->self.controller);
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+ struct xhci_hub *rhub;
+ struct xhci_bus_state *bus_state;
+ int port = (index & 0xff) - 1;
+ unsigned int i;
+ struct xhci_port **ports;
+ u32 portsc;
+ int ret;
+ struct phy *phy;
+
+ rhub = &xhci->usb2_rhub;
+ bus_state = &rhub->bus_state;
+ if (bus_state->resuming_ports && hcd->speed == HCD_USB2) {
+ ports = rhub->ports;
+ i = rhub->num_ports;
+ while (i--) {
+ if (!test_bit(i, &bus_state->resuming_ports))
+ continue;
+ portsc = readl(ports[i]->addr);
+ if ((portsc & PORT_PLS_MASK) == XDEV_RESUME)
+ tegra_phy_xusb_utmi_pad_power_on(
+ tegra_xusb_get_phy(tegra, "usb2", (int) i));
+ }
+ }
+
+ if (hcd->speed == HCD_USB2) {
+ phy = tegra_xusb_get_phy(tegra, "usb2", port);
+ if ((type_req == ClearPortFeature) && (value == USB_PORT_FEAT_SUSPEND)) {
+ if (!index || index > rhub->num_ports)
+ return -EPIPE;
+ tegra_phy_xusb_utmi_pad_power_on(phy);
+ }
+ if ((type_req == SetPortFeature) && (value == USB_PORT_FEAT_RESET)) {
+ if (!index || index > rhub->num_ports)
+ return -EPIPE;
+ ports = rhub->ports;
+ portsc = readl(ports[port]->addr);
+ if (portsc & PORT_CONNECT)
+ tegra_phy_xusb_utmi_pad_power_on(phy);
+ }
+ }
+
+ ret = xhci_hub_control(hcd, type_req, value, index, buf, length);
+ if (ret < 0)
+ return ret;
+
+ if (hcd->speed == HCD_USB2) {
+ /* Use phy where we set previously */
+ if ((type_req == SetPortFeature) && (value == USB_PORT_FEAT_SUSPEND))
+ /* We don't suspend the PAD while HNP role swap happens on the OTG port */
+ if (!((hcd->self.otg_port == (port + 1)) && hcd->self.b_hnp_enable))
+ tegra_phy_xusb_utmi_pad_power_down(phy);
+
+ if ((type_req == ClearPortFeature) && (value == USB_PORT_FEAT_C_CONNECTION)) {
+ ports = rhub->ports;
+ portsc = readl(ports[port]->addr);
+ if (!(portsc & PORT_CONNECT)) {
+ /* We don't suspend the PAD while HNP role swap happens on the OTG
+ * port
+ */
+ if (!((hcd->self.otg_port == (port + 1)) && hcd->self.b_hnp_enable))
+ tegra_phy_xusb_utmi_pad_power_down(phy);
+ }
+ }
+ if ((type_req == SetPortFeature) && (value == USB_PORT_FEAT_TEST))
+ tegra_phy_xusb_utmi_pad_power_on(phy);
+ }
+
+ return ret;
+}
+
static const struct xhci_driver_overrides tegra_xhci_overrides __initconst = {
.reset = tegra_xhci_setup,
+ .hub_control = tegra_xhci_hub_control,
};
static int __init tegra_xusb_init(void)
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 2b280beb0011..6183ce8574b1 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -292,6 +292,32 @@ static void xhci_zero_64b_regs(struct xhci_hcd *xhci)
xhci_info(xhci, "Fault detected\n");
}
+static int xhci_enable_interrupter(struct xhci_interrupter *ir)
+{
+ u32 iman;
+
+ if (!ir || !ir->ir_set)
+ return -EINVAL;
+
+ iman = readl(&ir->ir_set->irq_pending);
+ writel(ER_IRQ_ENABLE(iman), &ir->ir_set->irq_pending);
+
+ return 0;
+}
+
+static int xhci_disable_interrupter(struct xhci_interrupter *ir)
+{
+ u32 iman;
+
+ if (!ir || !ir->ir_set)
+ return -EINVAL;
+
+ iman = readl(&ir->ir_set->irq_pending);
+ writel(ER_IRQ_DISABLE(iman), &ir->ir_set->irq_pending);
+
+ return 0;
+}
+
#ifdef CONFIG_USB_PCI
/*
* Set up MSI
@@ -610,9 +636,9 @@ static int xhci_init(struct usb_hcd *hcd)
/*-------------------------------------------------------------------------*/
-
static int xhci_run_finished(struct xhci_hcd *xhci)
{
+ struct xhci_interrupter *ir = xhci->interrupter;
unsigned long flags;
u32 temp;
@@ -628,8 +654,7 @@ static int xhci_run_finished(struct xhci_hcd *xhci)
writel(temp, &xhci->op_regs->command);
xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Enable primary interrupter");
- temp = readl(&xhci->ir_set->irq_pending);
- writel(ER_IRQ_ENABLE(temp), &xhci->ir_set->irq_pending);
+ xhci_enable_interrupter(ir);
if (xhci_start(xhci)) {
xhci_halt(xhci);
@@ -665,7 +690,7 @@ int xhci_run(struct usb_hcd *hcd)
u64 temp_64;
int ret;
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
-
+ struct xhci_interrupter *ir = xhci->interrupter;
/* Start the xHCI host controller running only after the USB 2.0 roothub
* is setup.
*/
@@ -680,17 +705,17 @@ int xhci_run(struct usb_hcd *hcd)
if (ret)
return ret;
- temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
+ temp_64 = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
temp_64 &= ~ERST_PTR_MASK;
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
"ERST deq = 64'h%0lx", (long unsigned int) temp_64);
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
"// Set the interrupt modulation register");
- temp = readl(&xhci->ir_set->irq_control);
+ temp = readl(&ir->ir_set->irq_control);
temp &= ~ER_IRQ_INTERVAL_MASK;
temp |= (xhci->imod_interval / 250) & ER_IRQ_INTERVAL_MASK;
- writel(temp, &xhci->ir_set->irq_control);
+ writel(temp, &ir->ir_set->irq_control);
if (xhci->quirks & XHCI_NEC_HOST) {
struct xhci_command *command;
@@ -733,6 +758,7 @@ static void xhci_stop(struct usb_hcd *hcd)
{
u32 temp;
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+ struct xhci_interrupter *ir = xhci->interrupter;
mutex_lock(&xhci->mutex);
@@ -769,8 +795,7 @@ static void xhci_stop(struct usb_hcd *hcd)
"// Disabling event ring interrupts");
temp = readl(&xhci->op_regs->status);
writel((temp & ~0x1fff) | STS_EINT, &xhci->op_regs->status);
- temp = readl(&xhci->ir_set->irq_pending);
- writel(ER_IRQ_DISABLE(temp), &xhci->ir_set->irq_pending);
+ xhci_disable_interrupter(ir);
xhci_dbg_trace(xhci, trace_xhci_dbg_init, "cleaning up memory");
xhci_mem_cleanup(xhci);
@@ -832,28 +857,36 @@ EXPORT_SYMBOL_GPL(xhci_shutdown);
#ifdef CONFIG_PM
static void xhci_save_registers(struct xhci_hcd *xhci)
{
+ struct xhci_interrupter *ir = xhci->interrupter;
+
xhci->s3.command = readl(&xhci->op_regs->command);
xhci->s3.dev_nt = readl(&xhci->op_regs->dev_notification);
xhci->s3.dcbaa_ptr = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr);
xhci->s3.config_reg = readl(&xhci->op_regs->config_reg);
- xhci->s3.erst_size = readl(&xhci->ir_set->erst_size);
- xhci->s3.erst_base = xhci_read_64(xhci, &xhci->ir_set->erst_base);
- xhci->s3.erst_dequeue = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
- xhci->s3.irq_pending = readl(&xhci->ir_set->irq_pending);
- xhci->s3.irq_control = readl(&xhci->ir_set->irq_control);
+
+ if (!ir)
+ return;
+
+ ir->s3_erst_size = readl(&ir->ir_set->erst_size);
+ ir->s3_erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base);
+ ir->s3_erst_dequeue = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
+ ir->s3_irq_pending = readl(&ir->ir_set->irq_pending);
+ ir->s3_irq_control = readl(&ir->ir_set->irq_control);
}
static void xhci_restore_registers(struct xhci_hcd *xhci)
{
+ struct xhci_interrupter *ir = xhci->interrupter;
+
writel(xhci->s3.command, &xhci->op_regs->command);
writel(xhci->s3.dev_nt, &xhci->op_regs->dev_notification);
xhci_write_64(xhci, xhci->s3.dcbaa_ptr, &xhci->op_regs->dcbaa_ptr);
writel(xhci->s3.config_reg, &xhci->op_regs->config_reg);
- writel(xhci->s3.erst_size, &xhci->ir_set->erst_size);
- xhci_write_64(xhci, xhci->s3.erst_base, &xhci->ir_set->erst_base);
- xhci_write_64(xhci, xhci->s3.erst_dequeue, &xhci->ir_set->erst_dequeue);
- writel(xhci->s3.irq_pending, &xhci->ir_set->irq_pending);
- writel(xhci->s3.irq_control, &xhci->ir_set->irq_control);
+ writel(ir->s3_erst_size, &ir->ir_set->erst_size);
+ xhci_write_64(xhci, ir->s3_erst_base, &ir->ir_set->erst_base);
+ xhci_write_64(xhci, ir->s3_erst_dequeue, &ir->ir_set->erst_dequeue);
+ writel(ir->s3_irq_pending, &ir->ir_set->irq_pending);
+ writel(ir->s3_irq_control, &ir->ir_set->irq_control);
}
static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci)
@@ -1218,8 +1251,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
xhci_dbg(xhci, "// Disabling event ring interrupts\n");
temp = readl(&xhci->op_regs->status);
writel((temp & ~0x1fff) | STS_EINT, &xhci->op_regs->status);
- temp = readl(&xhci->ir_set->irq_pending);
- writel(ER_IRQ_DISABLE(temp), &xhci->ir_set->irq_pending);
+ xhci_disable_interrupter(xhci->interrupter);
xhci_dbg(xhci, "cleaning up memory\n");
xhci_mem_cleanup(xhci);
@@ -5334,6 +5366,11 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
if (xhci->hci_version > 0x100)
xhci->hcc_params2 = readl(&xhci->cap_regs->hcc_params2);
+ /* xhci-plat or xhci-pci might have set max_interrupters already */
+ if ((!xhci->max_interrupters) ||
+ xhci->max_interrupters > HCS_MAX_INTRS(xhci->hcs_params1))
+ xhci->max_interrupters = HCS_MAX_INTRS(xhci->hcs_params1);
+
xhci->quirks |= quirks;
get_quirks(dev, xhci);
@@ -5518,6 +5555,8 @@ void xhci_init_driver(struct hc_driver *drv,
drv->reset_bandwidth = over->reset_bandwidth;
if (over->update_hub_device)
drv->update_hub_device = over->update_hub_device;
+ if (over->hub_control)
+ drv->hub_control = over->hub_control;
}
}
EXPORT_SYMBOL_GPL(xhci_init_driver);
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index dcee7f3207ad..786002bb35db 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -513,6 +513,9 @@ struct xhci_intr_reg {
/* Preserve bits 16:31 of erst_size */
#define ERST_SIZE_MASK (0xffff << 16)
+/* erst_base bitmasks */
+#define ERST_BASE_RSVDP (0x3f)
+
/* erst_dequeue bitmasks */
/* Dequeue ERST Segment Index (DESI) - Segment number (or alias)
* where the current dequeue pointer lies. This is an optional HW hint.
@@ -1684,11 +1687,6 @@ struct s3_save {
u32 dev_nt;
u64 dcbaa_ptr;
u32 config_reg;
- u32 irq_pending;
- u32 irq_control;
- u32 erst_size;
- u64 erst_base;
- u64 erst_dequeue;
};
/* Use for lpm */
@@ -1706,16 +1704,22 @@ struct xhci_bus_state {
u32 port_c_suspend;
u32 suspended_ports;
u32 port_remote_wakeup;
- unsigned long resume_done[USB_MAXCHILDREN];
/* which ports have started to resume */
unsigned long resuming_ports;
- /* Which ports are waiting on RExit to U0 transition. */
- unsigned long rexit_ports;
- struct completion rexit_done[USB_MAXCHILDREN];
- struct completion u3exit_done[USB_MAXCHILDREN];
};
-
+struct xhci_interrupter {
+ struct xhci_ring *event_ring;
+ struct xhci_erst erst;
+ struct xhci_intr_reg __iomem *ir_set;
+ unsigned int intr_num;
+ /* For interrupter registers save and restore over suspend/resume */
+ u32 s3_irq_pending;
+ u32 s3_irq_control;
+ u32 s3_erst_size;
+ u64 s3_erst_base;
+ u64 s3_erst_dequeue;
+};
/*
* It can take up to 20 ms to transition from RExit to U0 on the
* Intel Lynx Point LP xHCI host.
@@ -1736,6 +1740,10 @@ struct xhci_port {
struct xhci_hub *rhub;
struct xhci_port_cap *port_cap;
unsigned int lpm_incapable:1;
+ unsigned long resume_timestamp;
+ bool rexit_active;
+ struct completion rexit_done;
+ struct completion u3exit_done;
};
struct xhci_hub {
@@ -1758,8 +1766,6 @@ struct xhci_hcd {
struct xhci_op_regs __iomem *op_regs;
struct xhci_run_regs __iomem *run_regs;
struct xhci_doorbell_array __iomem *dba;
- /* Our HCD's current interrupter register set */
- struct xhci_intr_reg __iomem *ir_set;
/* Cached register copies of read-only HC data */
__u32 hcs_params1;
@@ -1774,7 +1780,7 @@ struct xhci_hcd {
u8 sbrn;
u16 hci_version;
u8 max_slots;
- u8 max_interrupters;
+ u16 max_interrupters;
u8 max_ports;
u8 isoc_threshold;
/* imod_interval in ns (I * 250ns) */
@@ -1794,6 +1800,7 @@ struct xhci_hcd {
struct reset_control *reset;
/* data structures */
struct xhci_device_context_array *dcbaa;
+ struct xhci_interrupter *interrupter;
struct xhci_ring *cmd_ring;
unsigned int cmd_ring_state;
#define CMD_RING_STATE_RUNNING (1 << 0)
@@ -1804,8 +1811,7 @@ struct xhci_hcd {
struct delayed_work cmd_timer;
struct completion cmd_ring_stop_completion;
struct xhci_command *current_cmd;
- struct xhci_ring *event_ring;
- struct xhci_erst erst;
+
/* Scratchpad */
struct xhci_scratchpad *scratchpad;
@@ -1946,6 +1952,8 @@ struct xhci_driver_overrides {
void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *);
int (*update_hub_device)(struct usb_hcd *hcd, struct usb_device *hdev,
struct usb_tt *tt, gfp_t mem_flags);
+ int (*hub_control)(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
+ u16 wIndex, char *buf, u16 wLength);
};
#define XHCI_CFC_DELAY 10
diff --git a/drivers/usb/misc/onboard_usb_hub.c b/drivers/usb/misc/onboard_usb_hub.c
index 969c4c4f2ae9..5402e4b7267b 100644
--- a/drivers/usb/misc/onboard_usb_hub.c
+++ b/drivers/usb/misc/onboard_usb_hub.c
@@ -333,6 +333,7 @@ static struct platform_driver onboard_hub_driver = {
#define VENDOR_ID_MICROCHIP 0x0424
#define VENDOR_ID_REALTEK 0x0bda
#define VENDOR_ID_TI 0x0451
+#define VENDOR_ID_VIA 0x2109
/*
* Returns the onboard_hub platform device that is associated with the USB
@@ -407,6 +408,7 @@ static void onboard_hub_usbdev_disconnect(struct usb_device *udev)
static const struct usb_device_id onboard_hub_id_table[] = {
{ USB_DEVICE(VENDOR_ID_GENESYS, 0x0608) }, /* Genesys Logic GL850G USB 2.0 */
+ { USB_DEVICE(VENDOR_ID_GENESYS, 0x0610) }, /* Genesys Logic GL852G USB 2.0 */
{ USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2514) }, /* USB2514B USB 2.0 */
{ USB_DEVICE(VENDOR_ID_REALTEK, 0x0411) }, /* RTS5411 USB 3.1 */
{ USB_DEVICE(VENDOR_ID_REALTEK, 0x5411) }, /* RTS5411 USB 2.1 */
@@ -414,6 +416,8 @@ static const struct usb_device_id onboard_hub_id_table[] = {
{ USB_DEVICE(VENDOR_ID_REALTEK, 0x5414) }, /* RTS5414 USB 2.1 */
{ USB_DEVICE(VENDOR_ID_TI, 0x8140) }, /* TI USB8041 3.0 */
{ USB_DEVICE(VENDOR_ID_TI, 0x8142) }, /* TI USB8041 2.0 */
+ { USB_DEVICE(VENDOR_ID_VIA, 0x0817) }, /* VIA VL817 3.1 */
+ { USB_DEVICE(VENDOR_ID_VIA, 0x2817) }, /* VIA VL817 2.0 */
{}
};
MODULE_DEVICE_TABLE(usb, onboard_hub_id_table);
diff --git a/drivers/usb/misc/onboard_usb_hub.h b/drivers/usb/misc/onboard_usb_hub.h
index 62129a6a1ba5..0a943a154649 100644
--- a/drivers/usb/misc/onboard_usb_hub.h
+++ b/drivers/usb/misc/onboard_usb_hub.h
@@ -26,15 +26,26 @@ static const struct onboard_hub_pdata genesys_gl850g_data = {
.reset_us = 3,
};
+static const struct onboard_hub_pdata genesys_gl852g_data = {
+ .reset_us = 50,
+};
+
+static const struct onboard_hub_pdata vialab_vl817_data = {
+ .reset_us = 10,
+};
+
static const struct of_device_id onboard_hub_match[] = {
{ .compatible = "usb424,2514", .data = &microchip_usb424_data, },
{ .compatible = "usb451,8140", .data = &ti_tusb8041_data, },
{ .compatible = "usb451,8142", .data = &ti_tusb8041_data, },
{ .compatible = "usb5e3,608", .data = &genesys_gl850g_data, },
+ { .compatible = "usb5e3,610", .data = &genesys_gl852g_data, },
{ .compatible = "usbbda,411", .data = &realtek_rts5411_data, },
{ .compatible = "usbbda,5411", .data = &realtek_rts5411_data, },
{ .compatible = "usbbda,414", .data = &realtek_rts5411_data, },
{ .compatible = "usbbda,5414", .data = &realtek_rts5411_data, },
+ { .compatible = "usb2109,817", .data = &vialab_vl817_data, },
+ { .compatible = "usb2109,2817", .data = &vialab_vl817_data, },
{}
};
diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c
index 094e812e9e69..abb1cd35d8a6 100644
--- a/drivers/usb/mon/mon_bin.c
+++ b/drivers/usb/mon/mon_bin.c
@@ -1272,8 +1272,7 @@ static int mon_bin_mmap(struct file *filp, struct vm_area_struct *vma)
if (vma->vm_flags & VM_WRITE)
return -EPERM;
- vma->vm_flags &= ~VM_MAYWRITE;
- vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
+ vm_flags_mod(vma, VM_DONTEXPAND | VM_DONTDUMP, VM_MAYWRITE);
vma->vm_private_data = filp->private_data;
mon_bin_vma_open(vma);
return 0;
diff --git a/drivers/usb/mtu3/mtu3_gadget.c b/drivers/usb/mtu3/mtu3_gadget.c
index 80236e7b0895..c0264d5426bf 100644
--- a/drivers/usb/mtu3/mtu3_gadget.c
+++ b/drivers/usb/mtu3/mtu3_gadget.c
@@ -133,10 +133,9 @@ static int mtu3_ep_disable(struct mtu3_ep *mep)
{
struct mtu3 *mtu = mep->mtu;
- mtu3_qmu_stop(mep);
-
/* abort all pending requests */
nuke(mep, -ESHUTDOWN);
+ mtu3_qmu_stop(mep);
mtu3_deconfig_ep(mtu, mep);
mtu3_gpd_ring_free(mep);
diff --git a/drivers/usb/mtu3/mtu3_hw_regs.h b/drivers/usb/mtu3/mtu3_hw_regs.h
index 519a58301f45..ee30ae0a4b54 100644
--- a/drivers/usb/mtu3/mtu3_hw_regs.h
+++ b/drivers/usb/mtu3/mtu3_hw_regs.h
@@ -128,6 +128,7 @@
#define TX_FIFOEMPTY BIT(24)
#define TX_SENTSTALL BIT(22)
#define TX_SENDSTALL BIT(21)
+#define TX_FLUSHFIFO BIT(20)
#define TX_TXPKTRDY BIT(16)
#define TX_TXMAXPKTSZ_MSK GENMASK(10, 0)
#define TX_TXMAXPKTSZ(x) ((x) & TX_TXMAXPKTSZ_MSK)
diff --git a/drivers/usb/mtu3/mtu3_qmu.c b/drivers/usb/mtu3/mtu3_qmu.c
index 2ea3157ddb6e..a2fdab8b63b2 100644
--- a/drivers/usb/mtu3/mtu3_qmu.c
+++ b/drivers/usb/mtu3/mtu3_qmu.c
@@ -388,6 +388,9 @@ void mtu3_qmu_stop(struct mtu3_ep *mep)
}
mtu3_writel(mbase, qcsr, QMU_Q_STOP);
+ if (mep->is_in)
+ mtu3_setbits(mbase, MU3D_EP_TXCR0(epnum), TX_FLUSHFIFO);
+
ret = readl_poll_timeout_atomic(mbase + qcsr, value,
!(value & QMU_Q_ACTIVE), 1, 1000);
if (ret) {
@@ -395,6 +398,10 @@ void mtu3_qmu_stop(struct mtu3_ep *mep)
return;
}
+ /* flush fifo again to make sure the fifo is empty */
+ if (mep->is_in)
+ mtu3_setbits(mbase, MU3D_EP_TXCR0(epnum), TX_FLUSHFIFO);
+
dev_dbg(mtu->dev, "%s's qmu stop now!\n", mep->name);
}
diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c
index a4e55b0c52cf..d47e5c94587b 100644
--- a/drivers/usb/musb/da8xx.c
+++ b/drivers/usb/musb/da8xx.c
@@ -368,8 +368,10 @@ static int da8xx_musb_init(struct musb *musb)
/* Returns zero if e.g. not clocked */
rev = musb_readl(reg_base, DA8XX_USB_REVISION_REG);
- if (!rev)
+ if (!rev) {
+ ret = -ENODEV;
goto fail;
+ }
musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
if (IS_ERR_OR_NULL(musb->xceiv)) {
diff --git a/drivers/usb/musb/mediatek.c b/drivers/usb/musb/mediatek.c
index cad991380b0c..27b9bd258340 100644
--- a/drivers/usb/musb/mediatek.c
+++ b/drivers/usb/musb/mediatek.c
@@ -294,7 +294,8 @@ static int mtk_musb_init(struct musb *musb)
err_phy_power_on:
phy_exit(glue->phy);
err_phy_init:
- mtk_otg_switch_exit(glue);
+ if (musb->port_mode == MUSB_OTG)
+ mtk_otg_switch_exit(glue);
return ret;
}
diff --git a/drivers/usb/musb/sunxi.c b/drivers/usb/musb/sunxi.c
index 7f9a999cd5ff..9b622cd9b2bd 100644
--- a/drivers/usb/musb/sunxi.c
+++ b/drivers/usb/musb/sunxi.c
@@ -15,6 +15,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/phy/phy-sun4i-usb.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
@@ -67,6 +68,13 @@
#define SUNXI_MUSB_FL_NO_CONFIGDATA 7
#define SUNXI_MUSB_FL_PHY_MODE_PEND 8
+struct sunxi_musb_cfg {
+ const struct musb_hdrc_config *hdrc_config;
+ bool has_sram;
+ bool has_reset;
+ bool no_configdata;
+};
+
/* Our read/write methods need access and do not get passed in a musb ref :| */
static struct musb *sunxi_musb;
@@ -621,11 +629,10 @@ static const struct musb_platform_ops sunxi_musb_ops = {
.post_root_reset_end = sunxi_musb_post_root_reset_end,
};
-/* Allwinner OTG supports up to 5 endpoints */
-#define SUNXI_MUSB_MAX_EP_NUM 6
#define SUNXI_MUSB_RAM_BITS 11
-static struct musb_fifo_cfg sunxi_musb_mode_cfg[] = {
+/* Allwinner OTG supports up to 5 endpoints */
+static struct musb_fifo_cfg sunxi_musb_mode_cfg_5eps[] = {
MUSB_EP_FIFO_SINGLE(1, FIFO_TX, 512),
MUSB_EP_FIFO_SINGLE(1, FIFO_RX, 512),
MUSB_EP_FIFO_SINGLE(2, FIFO_TX, 512),
@@ -639,9 +646,7 @@ static struct musb_fifo_cfg sunxi_musb_mode_cfg[] = {
};
/* H3/V3s OTG supports only 4 endpoints */
-#define SUNXI_MUSB_MAX_EP_NUM_H3 5
-
-static struct musb_fifo_cfg sunxi_musb_mode_cfg_h3[] = {
+static struct musb_fifo_cfg sunxi_musb_mode_cfg_4eps[] = {
MUSB_EP_FIFO_SINGLE(1, FIFO_TX, 512),
MUSB_EP_FIFO_SINGLE(1, FIFO_RX, 512),
MUSB_EP_FIFO_SINGLE(2, FIFO_TX, 512),
@@ -652,31 +657,33 @@ static struct musb_fifo_cfg sunxi_musb_mode_cfg_h3[] = {
MUSB_EP_FIFO_SINGLE(4, FIFO_RX, 512),
};
-static const struct musb_hdrc_config sunxi_musb_hdrc_config = {
- .fifo_cfg = sunxi_musb_mode_cfg,
- .fifo_cfg_size = ARRAY_SIZE(sunxi_musb_mode_cfg),
+static const struct musb_hdrc_config sunxi_musb_hdrc_config_5eps = {
+ .fifo_cfg = sunxi_musb_mode_cfg_5eps,
+ .fifo_cfg_size = ARRAY_SIZE(sunxi_musb_mode_cfg_5eps),
.multipoint = true,
.dyn_fifo = true,
- .num_eps = SUNXI_MUSB_MAX_EP_NUM,
+ /* Two FIFOs per endpoint, plus ep_0. */
+ .num_eps = (ARRAY_SIZE(sunxi_musb_mode_cfg_5eps) / 2) + 1,
.ram_bits = SUNXI_MUSB_RAM_BITS,
};
-static struct musb_hdrc_config sunxi_musb_hdrc_config_h3 = {
- .fifo_cfg = sunxi_musb_mode_cfg_h3,
- .fifo_cfg_size = ARRAY_SIZE(sunxi_musb_mode_cfg_h3),
+static const struct musb_hdrc_config sunxi_musb_hdrc_config_4eps = {
+ .fifo_cfg = sunxi_musb_mode_cfg_4eps,
+ .fifo_cfg_size = ARRAY_SIZE(sunxi_musb_mode_cfg_4eps),
.multipoint = true,
.dyn_fifo = true,
- .num_eps = SUNXI_MUSB_MAX_EP_NUM_H3,
+ /* Two FIFOs per endpoint, plus ep_0. */
+ .num_eps = (ARRAY_SIZE(sunxi_musb_mode_cfg_4eps) / 2) + 1,
.ram_bits = SUNXI_MUSB_RAM_BITS,
};
-
static int sunxi_musb_probe(struct platform_device *pdev)
{
struct musb_hdrc_platform_data pdata;
struct platform_device_info pinfo;
struct sunxi_glue *glue;
struct device_node *np = pdev->dev.of_node;
+ const struct sunxi_musb_cfg *cfg;
int ret;
if (!np) {
@@ -713,26 +720,25 @@ static int sunxi_musb_probe(struct platform_device *pdev)
return -EINVAL;
}
pdata.platform_ops = &sunxi_musb_ops;
- if (!of_device_is_compatible(np, "allwinner,sun8i-h3-musb"))
- pdata.config = &sunxi_musb_hdrc_config;
- else
- pdata.config = &sunxi_musb_hdrc_config_h3;
+
+ cfg = of_device_get_match_data(&pdev->dev);
+ if (!cfg)
+ return -EINVAL;
+
+ pdata.config = cfg->hdrc_config;
glue->dev = &pdev->dev;
INIT_WORK(&glue->work, sunxi_musb_work);
glue->host_nb.notifier_call = sunxi_musb_host_notifier;
- if (of_device_is_compatible(np, "allwinner,sun4i-a10-musb"))
+ if (cfg->has_sram)
set_bit(SUNXI_MUSB_FL_HAS_SRAM, &glue->flags);
- if (of_device_is_compatible(np, "allwinner,sun6i-a31-musb"))
+ if (cfg->has_reset)
set_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags);
- if (of_device_is_compatible(np, "allwinner,sun8i-a33-musb") ||
- of_device_is_compatible(np, "allwinner,sun8i-h3-musb")) {
- set_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags);
+ if (cfg->no_configdata)
set_bit(SUNXI_MUSB_FL_NO_CONFIGDATA, &glue->flags);
- }
glue->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(glue->clk)) {
@@ -810,11 +816,46 @@ static int sunxi_musb_remove(struct platform_device *pdev)
return 0;
}
+static const struct sunxi_musb_cfg sun4i_a10_musb_cfg = {
+ .hdrc_config = &sunxi_musb_hdrc_config_5eps,
+ .has_sram = true,
+};
+
+static const struct sunxi_musb_cfg sun6i_a31_musb_cfg = {
+ .hdrc_config = &sunxi_musb_hdrc_config_5eps,
+ .has_reset = true,
+};
+
+static const struct sunxi_musb_cfg sun8i_a33_musb_cfg = {
+ .hdrc_config = &sunxi_musb_hdrc_config_5eps,
+ .has_reset = true,
+ .no_configdata = true,
+};
+
+static const struct sunxi_musb_cfg sun8i_h3_musb_cfg = {
+ .hdrc_config = &sunxi_musb_hdrc_config_4eps,
+ .has_reset = true,
+ .no_configdata = true,
+};
+
+static const struct sunxi_musb_cfg suniv_f1c100s_musb_cfg = {
+ .hdrc_config = &sunxi_musb_hdrc_config_5eps,
+ .has_sram = true,
+ .has_reset = true,
+ .no_configdata = true,
+};
+
static const struct of_device_id sunxi_musb_match[] = {
- { .compatible = "allwinner,sun4i-a10-musb", },
- { .compatible = "allwinner,sun6i-a31-musb", },
- { .compatible = "allwinner,sun8i-a33-musb", },
- { .compatible = "allwinner,sun8i-h3-musb", },
+ { .compatible = "allwinner,sun4i-a10-musb",
+ .data = &sun4i_a10_musb_cfg, },
+ { .compatible = "allwinner,sun6i-a31-musb",
+ .data = &sun6i_a31_musb_cfg, },
+ { .compatible = "allwinner,sun8i-a33-musb",
+ .data = &sun8i_a33_musb_cfg, },
+ { .compatible = "allwinner,sun8i-h3-musb",
+ .data = &sun8i_h3_musb_cfg, },
+ { .compatible = "allwinner,suniv-f1c100s-musb",
+ .data = &suniv_f1c100s_musb_cfg, },
{}
};
MODULE_DEVICE_TABLE(of, sunxi_musb_match);
diff --git a/drivers/usb/phy/phy.c b/drivers/usb/phy/phy.c
index 1b24492bb4e5..4b468bde19cf 100644
--- a/drivers/usb/phy/phy.c
+++ b/drivers/usb/phy/phy.c
@@ -80,7 +80,7 @@ static struct usb_phy *__of_usb_find_phy(struct device_node *node)
return ERR_PTR(-EPROBE_DEFER);
}
-static struct usb_phy *__device_to_usb_phy(struct device *dev)
+static struct usb_phy *__device_to_usb_phy(const struct device *dev)
{
struct usb_phy *usb_phy;
@@ -145,9 +145,9 @@ static void usb_phy_notify_charger_work(struct work_struct *work)
kobject_uevent(&usb_phy->dev->kobj, KOBJ_CHANGE);
}
-static int usb_phy_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int usb_phy_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct usb_phy *usb_phy;
+ const struct usb_phy *usb_phy;
char uchger_state[50] = { 0 };
char uchger_type[50] = { 0 };
unsigned long flags;
diff --git a/drivers/usb/roles/class.c b/drivers/usb/roles/class.c
index eacb46ec2ab3..56814ef80c24 100644
--- a/drivers/usb/roles/class.c
+++ b/drivers/usb/roles/class.c
@@ -274,8 +274,7 @@ static const struct attribute_group *usb_role_switch_groups[] = {
NULL,
};
-static int
-usb_role_switch_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int usb_role_switch_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
int ret;
diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c
index da19a5fa414f..c3ea3a46ed76 100644
--- a/drivers/usb/serial/console.c
+++ b/drivers/usb/serial/console.c
@@ -169,7 +169,7 @@ static int usb_console_setup(struct console *co, char *options)
tty_save_termios(tty);
tty_kref_put(tty);
}
- tty_port_set_initialized(&port->port, 1);
+ tty_port_set_initialized(&port->port, true);
}
/* Now that any required fake tty operations are completed restore
* the tty port count */
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index ee5ac4ef7e16..e6d8d9b35ad0 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -402,6 +402,8 @@ static void option_instat_callback(struct urb *urb);
#define LONGCHEER_VENDOR_ID 0x1c9e
/* 4G Systems products */
+/* This one was sold as the VW and Skoda "Carstick LTE" */
+#define FOUR_G_SYSTEMS_PRODUCT_CARSTICK_LTE 0x7605
/* This is the 4G XS Stick W14 a.k.a. Mobilcom Debitel Surf-Stick *
* It seems to contain a Qualcomm QSC6240/6290 chipset */
#define FOUR_G_SYSTEMS_PRODUCT_W14 0x9603
@@ -1976,6 +1978,8 @@ static const struct usb_device_id option_ids[] = {
.driver_info = RSVD(2) },
{ USB_DEVICE(AIRPLUS_VENDOR_ID, AIRPLUS_PRODUCT_MCD650) },
{ USB_DEVICE(TLAYTECH_VENDOR_ID, TLAYTECH_PRODUCT_TEU800) },
+ { USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_CARSTICK_LTE),
+ .driver_info = RSVD(0) },
{ USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W14),
.driver_info = NCTRL(0) | NCTRL(1) },
{ USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W100),
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 164521ee10c6..f8404073558b 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -754,7 +754,7 @@ static struct usb_serial_driver *search_serial_device(
return NULL;
}
-static int serial_port_carrier_raised(struct tty_port *port)
+static bool serial_port_carrier_raised(struct tty_port *port)
{
struct usb_serial_port *p = container_of(port, struct usb_serial_port, port);
struct usb_serial_driver *drv = p->serial->type;
@@ -762,10 +762,10 @@ static int serial_port_carrier_raised(struct tty_port *port)
if (drv->carrier_raised)
return drv->carrier_raised(p);
/* No carrier control - don't block */
- return 1;
+ return true;
}
-static void serial_port_dtr_rts(struct tty_port *port, int on)
+static void serial_port_dtr_rts(struct tty_port *port, bool on)
{
struct usb_serial_port *p = container_of(port, struct usb_serial_port, port);
struct usb_serial_driver *drv = p->serial->type;
diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c
index 6012603f3630..97c66c0d91f4 100644
--- a/drivers/usb/storage/ene_ub6250.c
+++ b/drivers/usb/storage/ene_ub6250.c
@@ -939,7 +939,7 @@ static int ms_lib_process_bootblock(struct us_data *us, u16 PhyBlock, u8 *PageDa
struct ms_lib_type_extdat ExtraData;
struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
- PageBuffer = kmalloc(MS_BYTES_PER_PAGE, GFP_KERNEL);
+ PageBuffer = kzalloc(MS_BYTES_PER_PAGE * 2, GFP_KERNEL);
if (PageBuffer == NULL)
return (u32)-1;
diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c
index 50b24096eb7f..662cd043b50e 100644
--- a/drivers/usb/typec/altmodes/displayport.c
+++ b/drivers/usb/typec/altmodes/displayport.c
@@ -146,6 +146,7 @@ static int dp_altmode_status_update(struct dp_altmode *dp)
if (dp->hpd != hpd) {
drm_connector_oob_hotplug_event(dp->connector_fwnode);
dp->hpd = hpd;
+ sysfs_notify(&dp->alt->dev.kobj, "displayport", "hpd");
}
}
@@ -276,9 +277,11 @@ static int dp_altmode_vdm(struct typec_altmode *alt,
case CMDT_RSP_ACK:
switch (cmd) {
case CMD_ENTER_MODE:
+ typec_altmode_update_active(alt, true);
dp->state = DP_STATE_UPDATE;
break;
case CMD_EXIT_MODE:
+ typec_altmode_update_active(alt, false);
dp->data.status = 0;
dp->data.conf = 0;
break;
@@ -514,9 +517,18 @@ static ssize_t pin_assignment_show(struct device *dev,
}
static DEVICE_ATTR_RW(pin_assignment);
+static ssize_t hpd_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct dp_altmode *dp = dev_get_drvdata(dev);
+
+ return sysfs_emit(buf, "%d\n", dp->hpd);
+}
+static DEVICE_ATTR_RO(hpd);
+
static struct attribute *dp_altmode_attrs[] = {
&dev_attr_configuration.attr,
&dev_attr_pin_assignment.attr,
+ &dev_attr_hpd.attr,
NULL
};
diff --git a/drivers/usb/typec/bus.c b/drivers/usb/typec/bus.c
index 31c2a3130cad..098f0efaa58d 100644
--- a/drivers/usb/typec/bus.c
+++ b/drivers/usb/typec/bus.c
@@ -11,6 +11,22 @@
#include "bus.h"
#include "class.h"
#include "mux.h"
+#include "retimer.h"
+
+static inline int
+typec_altmode_set_retimer(struct altmode *alt, unsigned long conf, void *data)
+{
+ struct typec_retimer_state state;
+
+ if (!alt->retimer)
+ return 0;
+
+ state.alt = &alt->adev;
+ state.mode = conf;
+ state.data = data;
+
+ return typec_retimer_set(alt->retimer, &state);
+}
static inline int
typec_altmode_set_mux(struct altmode *alt, unsigned long conf, void *data)
@@ -27,6 +43,19 @@ typec_altmode_set_mux(struct altmode *alt, unsigned long conf, void *data)
return typec_mux_set(alt->mux, &state);
}
+/* Wrapper to set various Type-C port switches together. */
+static inline int
+typec_altmode_set_switches(struct altmode *alt, unsigned long conf, void *data)
+{
+ int ret;
+
+ ret = typec_altmode_set_retimer(alt, conf, data);
+ if (ret)
+ return ret;
+
+ return typec_altmode_set_mux(alt, conf, data);
+}
+
static int typec_altmode_set_state(struct typec_altmode *adev,
unsigned long conf, void *data)
{
@@ -35,7 +64,7 @@ static int typec_altmode_set_state(struct typec_altmode *adev,
port_altmode = is_port ? to_altmode(adev) : to_altmode(adev)->partner;
- return typec_altmode_set_mux(port_altmode, conf, data);
+ return typec_altmode_set_switches(port_altmode, conf, data);
}
/* -------------------------------------------------------------------------- */
@@ -73,7 +102,7 @@ int typec_altmode_notify(struct typec_altmode *adev,
is_port = is_typec_port(adev->dev.parent);
partner = altmode->partner;
- ret = typec_altmode_set_mux(is_port ? altmode : partner, conf, data);
+ ret = typec_altmode_set_switches(is_port ? altmode : partner, conf, data);
if (ret)
return ret;
@@ -321,9 +350,9 @@ static int typec_match(struct device *dev, struct device_driver *driver)
return 0;
}
-static int typec_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int typec_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct typec_altmode *altmode = to_typec_altmode(dev);
+ const struct typec_altmode *altmode = to_typec_altmode(dev);
if (add_uevent_var(env, "SVID=%04X", altmode->svid))
return -ENOMEM;
diff --git a/drivers/usb/typec/bus.h b/drivers/usb/typec/bus.h
index 56dec268d4dd..c89168857417 100644
--- a/drivers/usb/typec/bus.h
+++ b/drivers/usb/typec/bus.h
@@ -7,11 +7,13 @@
struct bus_type;
struct typec_mux;
+struct typec_retimer;
struct altmode {
unsigned int id;
struct typec_altmode adev;
struct typec_mux *mux;
+ struct typec_retimer *retimer;
enum typec_port_data roles;
diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c
index 5897905cb4f0..cc3182f70673 100644
--- a/drivers/usb/typec/class.c
+++ b/drivers/usb/typec/class.c
@@ -583,6 +583,7 @@ void typec_unregister_altmode(struct typec_altmode *adev)
{
if (IS_ERR_OR_NULL(adev))
return;
+ typec_retimer_put(to_altmode(adev)->retimer);
typec_mux_put(to_altmode(adev)->mux);
device_unregister(&adev->dev);
}
@@ -1737,7 +1738,7 @@ static const struct attribute_group *typec_groups[] = {
NULL
};
-static int typec_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int typec_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
int ret;
@@ -2108,16 +2109,26 @@ typec_port_register_altmode(struct typec_port *port,
{
struct typec_altmode *adev;
struct typec_mux *mux;
+ struct typec_retimer *retimer;
mux = typec_mux_get(&port->dev, desc);
if (IS_ERR(mux))
return ERR_CAST(mux);
+ retimer = typec_retimer_get(&port->dev);
+ if (IS_ERR(retimer)) {
+ typec_mux_put(mux);
+ return ERR_CAST(retimer);
+ }
+
adev = typec_register_altmode(&port->dev, desc);
- if (IS_ERR(adev))
+ if (IS_ERR(adev)) {
+ typec_retimer_put(retimer);
typec_mux_put(mux);
- else
+ } else {
to_altmode(adev)->mux = mux;
+ to_altmode(adev)->retimer = retimer;
+ }
return adev;
}
diff --git a/drivers/usb/typec/hd3ss3220.c b/drivers/usb/typec/hd3ss3220.c
index f128664cb130..746ef3a75b76 100644
--- a/drivers/usb/typec/hd3ss3220.c
+++ b/drivers/usb/typec/hd3ss3220.c
@@ -14,6 +14,7 @@
#include <linux/slab.h>
#include <linux/usb/typec.h>
#include <linux/delay.h>
+#include <linux/workqueue.h>
#define HD3SS3220_REG_CN_STAT_CTRL 0x09
#define HD3SS3220_REG_GEN_CTRL 0x0A
@@ -37,6 +38,9 @@ struct hd3ss3220 {
struct regmap *regmap;
struct usb_role_switch *role_sw;
struct typec_port *port;
+ struct delayed_work output_poll_work;
+ enum usb_role role_state;
+ bool poll;
};
static int hd3ss3220_set_source_pref(struct hd3ss3220 *hd3ss3220, int src_pref)
@@ -118,6 +122,22 @@ static void hd3ss3220_set_role(struct hd3ss3220 *hd3ss3220)
default:
break;
}
+
+ hd3ss3220->role_state = role_state;
+}
+
+static void output_poll_execute(struct work_struct *work)
+{
+ struct delayed_work *delayed_work = to_delayed_work(work);
+ struct hd3ss3220 *hd3ss3220 = container_of(delayed_work,
+ struct hd3ss3220,
+ output_poll_work);
+ enum usb_role role_state = hd3ss3220_get_attached_state(hd3ss3220);
+
+ if (hd3ss3220->role_state != role_state)
+ hd3ss3220_set_role(hd3ss3220);
+
+ schedule_delayed_work(&hd3ss3220->output_poll_work, HZ);
}
static irqreturn_t hd3ss3220_irq(struct hd3ss3220 *hd3ss3220)
@@ -223,6 +243,9 @@ static int hd3ss3220_probe(struct i2c_client *client)
"hd3ss3220", &client->dev);
if (ret)
goto err_unreg_port;
+ } else {
+ INIT_DELAYED_WORK(&hd3ss3220->output_poll_work, output_poll_execute);
+ hd3ss3220->poll = true;
}
ret = i2c_smbus_read_byte_data(client, HD3SS3220_REG_DEV_REV);
@@ -231,6 +254,9 @@ static int hd3ss3220_probe(struct i2c_client *client)
fwnode_handle_put(connector);
+ if (hd3ss3220->poll)
+ schedule_delayed_work(&hd3ss3220->output_poll_work, HZ);
+
dev_info(&client->dev, "probed revision=0x%x\n", ret);
return 0;
@@ -248,6 +274,9 @@ static void hd3ss3220_remove(struct i2c_client *client)
{
struct hd3ss3220 *hd3ss3220 = i2c_get_clientdata(client);
+ if (hd3ss3220->poll)
+ cancel_delayed_work_sync(&hd3ss3220->output_poll_work);
+
typec_unregister_port(hd3ss3220->port);
usb_role_switch_put(hd3ss3220->role_sw);
}
diff --git a/drivers/usb/typec/mux/Kconfig b/drivers/usb/typec/mux/Kconfig
index 5eb2c17d72c1..c46fa4f9d3df 100644
--- a/drivers/usb/typec/mux/Kconfig
+++ b/drivers/usb/typec/mux/Kconfig
@@ -12,6 +12,12 @@ config TYPEC_MUX_FSA4480
common USB Type-C connector.
If compiled as a module, the module will be named fsa4480.
+config TYPEC_MUX_GPIO_SBU
+ tristate "Generic GPIO based SBU mux for USB Type-C applications"
+ help
+ Say Y or M if your system uses a GPIO based mux for managing the
+ connected state and the swapping of the SBU lines in a Type-C port.
+
config TYPEC_MUX_PI3USB30532
tristate "Pericom PI3USB30532 Type-C cross switch driver"
depends on I2C
diff --git a/drivers/usb/typec/mux/Makefile b/drivers/usb/typec/mux/Makefile
index e52a56c16bfb..dda67e19b58b 100644
--- a/drivers/usb/typec/mux/Makefile
+++ b/drivers/usb/typec/mux/Makefile
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_TYPEC_MUX_FSA4480) += fsa4480.o
+obj-$(CONFIG_TYPEC_MUX_GPIO_SBU) += gpio-sbu-mux.o
obj-$(CONFIG_TYPEC_MUX_PI3USB30532) += pi3usb30532.o
obj-$(CONFIG_TYPEC_MUX_INTEL_PMC) += intel_pmc_mux.o
diff --git a/drivers/usb/typec/mux/gpio-sbu-mux.c b/drivers/usb/typec/mux/gpio-sbu-mux.c
new file mode 100644
index 000000000000..f62516dafe8f
--- /dev/null
+++ b/drivers/usb/typec/mux/gpio-sbu-mux.c
@@ -0,0 +1,172 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2022 Linaro Ltd.
+ */
+
+#include <linux/bits.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/gpio/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/usb/typec_dp.h>
+#include <linux/usb/typec_mux.h>
+
+struct gpio_sbu_mux {
+ struct gpio_desc *enable_gpio;
+ struct gpio_desc *select_gpio;
+
+ struct typec_switch_dev *sw;
+ struct typec_mux_dev *mux;
+
+ struct mutex lock; /* protect enabled and swapped */
+ bool enabled;
+ bool swapped;
+};
+
+static int gpio_sbu_switch_set(struct typec_switch_dev *sw,
+ enum typec_orientation orientation)
+{
+ struct gpio_sbu_mux *sbu_mux = typec_switch_get_drvdata(sw);
+ bool enabled;
+ bool swapped;
+
+ mutex_lock(&sbu_mux->lock);
+
+ enabled = sbu_mux->enabled;
+ swapped = sbu_mux->swapped;
+
+ switch (orientation) {
+ case TYPEC_ORIENTATION_NONE:
+ enabled = false;
+ break;
+ case TYPEC_ORIENTATION_NORMAL:
+ swapped = false;
+ break;
+ case TYPEC_ORIENTATION_REVERSE:
+ swapped = true;
+ break;
+ }
+
+ if (enabled != sbu_mux->enabled)
+ gpiod_set_value(sbu_mux->enable_gpio, enabled);
+
+ if (swapped != sbu_mux->swapped)
+ gpiod_set_value(sbu_mux->select_gpio, swapped);
+
+ sbu_mux->enabled = enabled;
+ sbu_mux->swapped = swapped;
+
+ mutex_unlock(&sbu_mux->lock);
+
+ return 0;
+}
+
+static int gpio_sbu_mux_set(struct typec_mux_dev *mux,
+ struct typec_mux_state *state)
+{
+ struct gpio_sbu_mux *sbu_mux = typec_mux_get_drvdata(mux);
+
+ mutex_lock(&sbu_mux->lock);
+
+ switch (state->mode) {
+ case TYPEC_STATE_SAFE:
+ case TYPEC_STATE_USB:
+ sbu_mux->enabled = false;
+ break;
+ case TYPEC_DP_STATE_C:
+ case TYPEC_DP_STATE_D:
+ case TYPEC_DP_STATE_E:
+ sbu_mux->enabled = true;
+ break;
+ default:
+ break;
+ }
+
+ gpiod_set_value(sbu_mux->enable_gpio, sbu_mux->enabled);
+
+ mutex_unlock(&sbu_mux->lock);
+
+ return 0;
+}
+
+static int gpio_sbu_mux_probe(struct platform_device *pdev)
+{
+ struct typec_switch_desc sw_desc = { };
+ struct typec_mux_desc mux_desc = { };
+ struct device *dev = &pdev->dev;
+ struct gpio_sbu_mux *sbu_mux;
+
+ sbu_mux = devm_kzalloc(dev, sizeof(*sbu_mux), GFP_KERNEL);
+ if (!sbu_mux)
+ return -ENOMEM;
+
+ mutex_init(&sbu_mux->lock);
+
+ sbu_mux->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
+ if (IS_ERR(sbu_mux->enable_gpio))
+ return dev_err_probe(dev, PTR_ERR(sbu_mux->enable_gpio),
+ "unable to acquire enable gpio\n");
+
+ sbu_mux->select_gpio = devm_gpiod_get(dev, "select", GPIOD_OUT_LOW);
+ if (IS_ERR(sbu_mux->select_gpio))
+ return dev_err_probe(dev, PTR_ERR(sbu_mux->select_gpio),
+ "unable to acquire select gpio\n");
+
+ sw_desc.drvdata = sbu_mux;
+ sw_desc.fwnode = dev_fwnode(dev);
+ sw_desc.set = gpio_sbu_switch_set;
+
+ sbu_mux->sw = typec_switch_register(dev, &sw_desc);
+ if (IS_ERR(sbu_mux->sw))
+ return dev_err_probe(dev, PTR_ERR(sbu_mux->sw),
+ "failed to register typec switch\n");
+
+ mux_desc.drvdata = sbu_mux;
+ mux_desc.fwnode = dev_fwnode(dev);
+ mux_desc.set = gpio_sbu_mux_set;
+
+ sbu_mux->mux = typec_mux_register(dev, &mux_desc);
+ if (IS_ERR(sbu_mux->mux)) {
+ typec_switch_unregister(sbu_mux->sw);
+ return dev_err_probe(dev, PTR_ERR(sbu_mux->mux),
+ "failed to register typec mux\n");
+ }
+
+ platform_set_drvdata(pdev, sbu_mux);
+
+ return 0;
+}
+
+static int gpio_sbu_mux_remove(struct platform_device *pdev)
+{
+ struct gpio_sbu_mux *sbu_mux = platform_get_drvdata(pdev);
+
+ gpiod_set_value(sbu_mux->enable_gpio, 0);
+
+ typec_mux_unregister(sbu_mux->mux);
+ typec_switch_unregister(sbu_mux->sw);
+
+ return 0;
+}
+
+static const struct of_device_id gpio_sbu_mux_match[] = {
+ { .compatible = "gpio-sbu-mux", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, gpio_sbu_mux_match);
+
+static struct platform_driver gpio_sbu_mux_driver = {
+ .probe = gpio_sbu_mux_probe,
+ .remove = gpio_sbu_mux_remove,
+ .driver = {
+ .name = "gpio_sbu_mux",
+ .of_match_table = gpio_sbu_mux_match,
+ },
+};
+module_platform_driver(gpio_sbu_mux_driver);
+
+MODULE_DESCRIPTION("GPIO based SBU mux driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/typec/mux/intel_pmc_mux.c b/drivers/usb/typec/mux/intel_pmc_mux.c
index fdbf3694e21f..34e4188a40ff 100644
--- a/drivers/usb/typec/mux/intel_pmc_mux.c
+++ b/drivers/usb/typec/mux/intel_pmc_mux.c
@@ -602,20 +602,21 @@ static int pmc_usb_probe_iom(struct pmc_usb *pmc)
int ret;
for (dev_id = &iom_acpi_ids[0]; dev_id->id[0]; dev_id++) {
- if (acpi_dev_present(dev_id->id, NULL, -1)) {
- pmc->iom_port_status_offset = (u32)dev_id->driver_data;
- adev = acpi_dev_get_first_match_dev(dev_id->id, NULL, -1);
+ adev = acpi_dev_get_first_match_dev(dev_id->id, NULL, -1);
+ if (adev)
break;
- }
}
-
if (!adev)
return -ENODEV;
+ pmc->iom_port_status_offset = (u32)dev_id->driver_data;
+
INIT_LIST_HEAD(&resource_list);
ret = acpi_dev_get_memory_resources(adev, &resource_list);
- if (ret < 0)
+ if (ret < 0) {
+ acpi_dev_put(adev);
return ret;
+ }
rentry = list_first_entry_or_null(&resource_list, struct resource_entry, node);
if (rentry)
diff --git a/drivers/usb/typec/pd.c b/drivers/usb/typec/pd.c
index dc72005d68db..59c537a5e600 100644
--- a/drivers/usb/typec/pd.c
+++ b/drivers/usb/typec/pd.c
@@ -49,6 +49,13 @@ usb_suspend_supported_show(struct device *dev, struct device_attribute *attr, ch
static DEVICE_ATTR_RO(usb_suspend_supported);
static ssize_t
+higher_capability_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_HIGHER_CAP));
+}
+static DEVICE_ATTR_RO(higher_capability);
+
+static ssize_t
unconstrained_power_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_EXTPOWER));
@@ -161,7 +168,7 @@ static struct device_type source_fixed_supply_type = {
static struct attribute *sink_fixed_supply_attrs[] = {
&dev_attr_dual_role_power.attr,
- &dev_attr_usb_suspend_supported.attr,
+ &dev_attr_higher_capability.attr,
&dev_attr_unconstrained_power.attr,
&dev_attr_usb_communication_capable.attr,
&dev_attr_dual_role_data.attr,
diff --git a/drivers/usb/typec/retimer.h b/drivers/usb/typec/retimer.h
index e34bd23323be..d6a5ef9881e1 100644
--- a/drivers/usb/typec/retimer.h
+++ b/drivers/usb/typec/retimer.h
@@ -12,7 +12,7 @@ struct typec_retimer {
#define to_typec_retimer(_dev_) container_of(_dev_, struct typec_retimer, dev)
-const struct device_type typec_retimer_dev_type;
+extern const struct device_type typec_retimer_dev_type;
#define is_typec_retimer(dev) ((dev)->type == &typec_retimer_dev_type)
diff --git a/drivers/usb/typec/tcpm/Makefile b/drivers/usb/typec/tcpm/Makefile
index 906d9dced8e7..08e57bb499cb 100644
--- a/drivers/usb/typec/tcpm/Makefile
+++ b/drivers/usb/typec/tcpm/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_TYPEC_RT1711H) += tcpci_rt1711h.o
obj-$(CONFIG_TYPEC_MT6360) += tcpci_mt6360.o
obj-$(CONFIG_TYPEC_TCPCI_MT6370) += tcpci_mt6370.o
obj-$(CONFIG_TYPEC_TCPCI_MAXIM) += tcpci_maxim.o
+tcpci_maxim-y += tcpci_maxim_core.o maxim_contaminant.o
diff --git a/drivers/usb/typec/tcpm/maxim_contaminant.c b/drivers/usb/typec/tcpm/maxim_contaminant.c
new file mode 100644
index 000000000000..f8504a90da26
--- /dev/null
+++ b/drivers/usb/typec/tcpm/maxim_contaminant.c
@@ -0,0 +1,387 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2022 Google, Inc
+ *
+ * USB-C module to reduce wakeups due to contaminants.
+ */
+
+#include <linux/device.h>
+#include <linux/irqreturn.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/usb/tcpci.h>
+#include <linux/usb/tcpm.h>
+#include <linux/usb/typec.h>
+
+#include "tcpci_maxim.h"
+
+enum fladc_select {
+ CC1_SCALE1 = 1,
+ CC1_SCALE2,
+ CC2_SCALE1,
+ CC2_SCALE2,
+ SBU1,
+ SBU2,
+};
+
+#define FLADC_1uA_LSB_MV 25
+/* High range CC */
+#define FLADC_CC_HIGH_RANGE_LSB_MV 208
+/* Low range CC */
+#define FLADC_CC_LOW_RANGE_LSB_MV 126
+
+/* 1uA current source */
+#define FLADC_CC_SCALE1 1
+/* 5 uA current source */
+#define FLADC_CC_SCALE2 5
+
+#define FLADC_1uA_CC_OFFSET_MV 300
+#define FLADC_CC_HIGH_RANGE_OFFSET_MV 624
+#define FLADC_CC_LOW_RANGE_OFFSET_MV 378
+
+#define CONTAMINANT_THRESHOLD_SBU_K 1000
+#define CONTAMINANT_THRESHOLD_CC_K 1000
+
+#define READ1_SLEEP_MS 10
+#define READ2_SLEEP_MS 5
+
+#define STATUS_CHECK(reg, mask, val) (((reg) & (mask)) == (val))
+
+#define IS_CC_OPEN(cc_status) \
+ (STATUS_CHECK((cc_status), TCPC_CC_STATUS_CC1_MASK << TCPC_CC_STATUS_CC1_SHIFT, \
+ TCPC_CC_STATE_SRC_OPEN) && STATUS_CHECK((cc_status), \
+ TCPC_CC_STATUS_CC2_MASK << \
+ TCPC_CC_STATUS_CC2_SHIFT, \
+ TCPC_CC_STATE_SRC_OPEN))
+
+static int max_contaminant_adc_to_mv(struct max_tcpci_chip *chip, enum fladc_select channel,
+ bool ua_src, u8 fladc)
+{
+ /* SBU channels only have 1 scale with 1uA. */
+ if ((ua_src && (channel == CC1_SCALE2 || channel == CC2_SCALE2 || channel == SBU1 ||
+ channel == SBU2)))
+ /* Mean of range */
+ return FLADC_1uA_CC_OFFSET_MV + (fladc * FLADC_1uA_LSB_MV);
+ else if (!ua_src && (channel == CC1_SCALE1 || channel == CC2_SCALE1))
+ return FLADC_CC_HIGH_RANGE_OFFSET_MV + (fladc * FLADC_CC_HIGH_RANGE_LSB_MV);
+ else if (!ua_src && (channel == CC1_SCALE2 || channel == CC2_SCALE2))
+ return FLADC_CC_LOW_RANGE_OFFSET_MV + (fladc * FLADC_CC_LOW_RANGE_LSB_MV);
+
+ dev_err_once(chip->dev, "ADC ERROR: SCALE UNKNOWN");
+
+ return -EINVAL;
+}
+
+static int max_contaminant_read_adc_mv(struct max_tcpci_chip *chip, enum fladc_select channel,
+ int sleep_msec, bool raw, bool ua_src)
+{
+ struct regmap *regmap = chip->data.regmap;
+ u8 fladc;
+ int ret;
+
+ /* Channel & scale select */
+ ret = regmap_update_bits(regmap, TCPC_VENDOR_ADC_CTRL1, ADCINSEL_MASK,
+ channel << ADC_CHANNEL_OFFSET);
+ if (ret < 0)
+ return ret;
+
+ /* Enable ADC */
+ ret = regmap_update_bits(regmap, TCPC_VENDOR_ADC_CTRL1, ADCEN, ADCEN);
+ if (ret < 0)
+ return ret;
+
+ usleep_range(sleep_msec * 1000, (sleep_msec + 1) * 1000);
+ ret = max_tcpci_read8(chip, TCPC_VENDOR_FLADC_STATUS, &fladc);
+ if (ret < 0)
+ return ret;
+
+ /* Disable ADC */
+ ret = regmap_update_bits(regmap, TCPC_VENDOR_ADC_CTRL1, ADCEN, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_update_bits(regmap, TCPC_VENDOR_ADC_CTRL1, ADCINSEL_MASK, 0);
+ if (ret < 0)
+ return ret;
+
+ if (!raw)
+ return max_contaminant_adc_to_mv(chip, channel, ua_src, fladc);
+ else
+ return fladc;
+}
+
+static int max_contaminant_read_resistance_kohm(struct max_tcpci_chip *chip,
+ enum fladc_select channel, int sleep_msec, bool raw)
+{
+ struct regmap *regmap = chip->data.regmap;
+ int mv;
+ int ret;
+
+ if (channel == CC1_SCALE1 || channel == CC2_SCALE1 || channel == CC1_SCALE2 ||
+ channel == CC2_SCALE2) {
+ /* Enable 1uA current source */
+ ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, CCLPMODESEL_MASK,
+ ULTRA_LOW_POWER_MODE);
+ if (ret < 0)
+ return ret;
+
+ /* Enable 1uA current source */
+ ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, CCRPCTRL_MASK, UA_1_SRC);
+ if (ret < 0)
+ return ret;
+
+ /* OVP disable */
+ ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, CCOVPDIS, CCOVPDIS);
+ if (ret < 0)
+ return ret;
+
+ mv = max_contaminant_read_adc_mv(chip, channel, sleep_msec, raw, true);
+ if (mv < 0)
+ return ret;
+
+ /* OVP enable */
+ ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, CCOVPDIS, 0);
+ if (ret < 0)
+ return ret;
+ /* returns KOhm as 1uA source is used. */
+ return mv;
+ }
+
+ ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, SBUOVPDIS, SBUOVPDIS);
+ if (ret < 0)
+ return ret;
+
+ /* SBU switches auto configure when channel is selected. */
+ /* Enable 1ua current source */
+ ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, SBURPCTRL, SBURPCTRL);
+ if (ret < 0)
+ return ret;
+
+ mv = max_contaminant_read_adc_mv(chip, channel, sleep_msec, raw, true);
+ if (mv < 0)
+ return ret;
+ /* Disable current source */
+ ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, SBURPCTRL, 0);
+ if (ret < 0)
+ return ret;
+
+ /* OVP disable */
+ ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, SBUOVPDIS, 0);
+ if (ret < 0)
+ return ret;
+
+ return mv;
+}
+
+static int max_contaminant_read_comparators(struct max_tcpci_chip *chip, u8 *vendor_cc_status2_cc1,
+ u8 *vendor_cc_status2_cc2)
+{
+ struct regmap *regmap = chip->data.regmap;
+ int ret;
+
+ /* Enable 80uA source */
+ ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, CCRPCTRL_MASK, UA_80_SRC);
+ if (ret < 0)
+ return ret;
+
+ /* Enable comparators */
+ ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL1, CCCOMPEN, CCCOMPEN);
+ if (ret < 0)
+ return ret;
+
+ /* Sleep to allow comparators settle */
+ usleep_range(5000, 6000);
+ ret = regmap_update_bits(regmap, TCPC_TCPC_CTRL, TCPC_TCPC_CTRL_ORIENTATION, PLUG_ORNT_CC1);
+ if (ret < 0)
+ return ret;
+
+ usleep_range(5000, 6000);
+ ret = max_tcpci_read8(chip, VENDOR_CC_STATUS2, vendor_cc_status2_cc1);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_update_bits(regmap, TCPC_TCPC_CTRL, TCPC_TCPC_CTRL_ORIENTATION, PLUG_ORNT_CC2);
+ if (ret < 0)
+ return ret;
+
+ usleep_range(5000, 6000);
+ ret = max_tcpci_read8(chip, VENDOR_CC_STATUS2, vendor_cc_status2_cc2);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL1, CCCOMPEN, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, CCRPCTRL_MASK, 0);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int max_contaminant_detect_contaminant(struct max_tcpci_chip *chip)
+{
+ int cc1_k, cc2_k, sbu1_k, sbu2_k, ret;
+ u8 vendor_cc_status2_cc1 = 0xff, vendor_cc_status2_cc2 = 0xff;
+ u8 role_ctrl = 0, role_ctrl_backup = 0;
+ int inferred_state = NOT_DETECTED;
+
+ ret = max_tcpci_read8(chip, TCPC_ROLE_CTRL, &role_ctrl);
+ if (ret < 0)
+ return NOT_DETECTED;
+
+ role_ctrl_backup = role_ctrl;
+ role_ctrl = 0x0F;
+ ret = max_tcpci_write8(chip, TCPC_ROLE_CTRL, role_ctrl);
+ if (ret < 0)
+ return NOT_DETECTED;
+
+ cc1_k = max_contaminant_read_resistance_kohm(chip, CC1_SCALE2, READ1_SLEEP_MS, false);
+ if (cc1_k < 0)
+ goto exit;
+
+ cc2_k = max_contaminant_read_resistance_kohm(chip, CC2_SCALE2, READ2_SLEEP_MS, false);
+ if (cc2_k < 0)
+ goto exit;
+
+ sbu1_k = max_contaminant_read_resistance_kohm(chip, SBU1, READ1_SLEEP_MS, false);
+ if (sbu1_k < 0)
+ goto exit;
+
+ sbu2_k = max_contaminant_read_resistance_kohm(chip, SBU2, READ2_SLEEP_MS, false);
+ if (sbu2_k < 0)
+ goto exit;
+
+ ret = max_contaminant_read_comparators(chip, &vendor_cc_status2_cc1,
+ &vendor_cc_status2_cc2);
+
+ if (ret < 0)
+ goto exit;
+
+ if ((!(CC1_VUFP_RD0P5 & vendor_cc_status2_cc1) ||
+ !(CC2_VUFP_RD0P5 & vendor_cc_status2_cc2)) &&
+ !(CC1_VUFP_RD0P5 & vendor_cc_status2_cc1 && CC2_VUFP_RD0P5 & vendor_cc_status2_cc2))
+ inferred_state = SINK;
+ else if ((cc1_k < CONTAMINANT_THRESHOLD_CC_K || cc2_k < CONTAMINANT_THRESHOLD_CC_K) &&
+ (sbu1_k < CONTAMINANT_THRESHOLD_SBU_K || sbu2_k < CONTAMINANT_THRESHOLD_SBU_K))
+ inferred_state = DETECTED;
+
+ if (inferred_state == NOT_DETECTED)
+ max_tcpci_write8(chip, TCPC_ROLE_CTRL, role_ctrl_backup);
+ else
+ max_tcpci_write8(chip, TCPC_ROLE_CTRL, (TCPC_ROLE_CTRL_DRP | 0xA));
+
+ return inferred_state;
+exit:
+ max_tcpci_write8(chip, TCPC_ROLE_CTRL, role_ctrl_backup);
+ return NOT_DETECTED;
+}
+
+static int max_contaminant_enable_dry_detection(struct max_tcpci_chip *chip)
+{
+ struct regmap *regmap = chip->data.regmap;
+ u8 temp;
+ int ret;
+
+ ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL3, CCWTRDEB_MASK | CCWTRSEL_MASK
+ | WTRCYCLE_MASK, CCWTRDEB_1MS << CCWTRDEB_SHIFT |
+ CCWTRSEL_1V << CCWTRSEL_SHIFT | WTRCYCLE_4_8_S <<
+ WTRCYCLE_SHIFT);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_update_bits(regmap, TCPC_ROLE_CTRL, TCPC_ROLE_CTRL_DRP, TCPC_ROLE_CTRL_DRP);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL1, CCCONNDRY, CCCONNDRY);
+ if (ret < 0)
+ return ret;
+ ret = max_tcpci_read8(chip, TCPC_VENDOR_CC_CTRL1, &temp);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, CCLPMODESEL_MASK,
+ ULTRA_LOW_POWER_MODE);
+ if (ret < 0)
+ return ret;
+ ret = max_tcpci_read8(chip, TCPC_VENDOR_CC_CTRL2, &temp);
+ if (ret < 0)
+ return ret;
+
+ /* Enable Look4Connection before sending the command */
+ ret = regmap_update_bits(regmap, TCPC_TCPC_CTRL, TCPC_TCPC_CTRL_EN_LK4CONN_ALRT,
+ TCPC_TCPC_CTRL_EN_LK4CONN_ALRT);
+ if (ret < 0)
+ return ret;
+
+ ret = max_tcpci_write8(chip, TCPC_COMMAND, TCPC_CMD_LOOK4CONNECTION);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+bool max_contaminant_is_contaminant(struct max_tcpci_chip *chip, bool disconnect_while_debounce)
+{
+ u8 cc_status, pwr_cntl;
+ int ret;
+
+ ret = max_tcpci_read8(chip, TCPC_CC_STATUS, &cc_status);
+ if (ret < 0)
+ return false;
+
+ ret = max_tcpci_read8(chip, TCPC_POWER_CTRL, &pwr_cntl);
+ if (ret < 0)
+ return false;
+
+ if (chip->contaminant_state == NOT_DETECTED || chip->contaminant_state == SINK) {
+ if (!disconnect_while_debounce)
+ msleep(100);
+
+ ret = max_tcpci_read8(chip, TCPC_CC_STATUS, &cc_status);
+ if (ret < 0)
+ return false;
+
+ if (IS_CC_OPEN(cc_status)) {
+ u8 role_ctrl, role_ctrl_backup;
+
+ ret = max_tcpci_read8(chip, TCPC_ROLE_CTRL, &role_ctrl);
+ if (ret < 0)
+ return false;
+
+ role_ctrl_backup = role_ctrl;
+ role_ctrl |= 0x0F;
+ role_ctrl &= ~(TCPC_ROLE_CTRL_DRP);
+ ret = max_tcpci_write8(chip, TCPC_ROLE_CTRL, role_ctrl);
+ if (ret < 0)
+ return false;
+
+ chip->contaminant_state = max_contaminant_detect_contaminant(chip);
+
+ ret = max_tcpci_write8(chip, TCPC_ROLE_CTRL, role_ctrl_backup);
+ if (ret < 0)
+ return false;
+
+ if (chip->contaminant_state == DETECTED) {
+ max_contaminant_enable_dry_detection(chip);
+ return true;
+ }
+ }
+ return false;
+ } else if (chip->contaminant_state == DETECTED) {
+ if (STATUS_CHECK(cc_status, TCPC_CC_STATUS_TOGGLING, 0)) {
+ chip->contaminant_state = max_contaminant_detect_contaminant(chip);
+ if (chip->contaminant_state == DETECTED) {
+ max_contaminant_enable_dry_detection(chip);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+MODULE_DESCRIPTION("MAXIM TCPC CONTAMINANT Module");
+MODULE_AUTHOR("Badhri Jagan Sridharan <badhri@google.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/typec/tcpm/tcpci.c b/drivers/usb/typec/tcpm/tcpci.c
index fe781a38dc82..8da23240afbe 100644
--- a/drivers/usb/typec/tcpm/tcpci.c
+++ b/drivers/usb/typec/tcpm/tcpci.c
@@ -33,6 +33,7 @@ struct tcpci {
struct tcpm_port *port;
struct regmap *regmap;
+ unsigned int alert_mask;
bool controls_vbus;
@@ -403,6 +404,14 @@ static void tcpci_frs_sourcing_vbus(struct tcpc_dev *dev)
tcpci->data->frs_sourcing_vbus(tcpci, tcpci->data);
}
+static void tcpci_check_contaminant(struct tcpc_dev *dev)
+{
+ struct tcpci *tcpci = tcpc_to_tcpci(dev);
+
+ if (tcpci->data->check_contaminant)
+ tcpci->data->check_contaminant(tcpci, tcpci->data);
+}
+
static int tcpci_set_bist_data(struct tcpc_dev *tcpc, bool enable)
{
struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
@@ -632,6 +641,9 @@ static int tcpci_init(struct tcpc_dev *tcpc)
if (ret < 0)
return ret;
}
+
+ tcpci->alert_mask = reg;
+
return tcpci_write16(tcpci, TCPC_ALERT_MASK, reg);
}
@@ -715,7 +727,7 @@ irqreturn_t tcpci_irq(struct tcpci *tcpci)
else if (status & TCPC_ALERT_TX_FAILED)
tcpm_pd_transmit_complete(tcpci->port, TCPC_TX_FAILED);
- return IRQ_HANDLED;
+ return IRQ_RETVAL(status & tcpci->alert_mask);
}
EXPORT_SYMBOL_GPL(tcpci_irq);
@@ -778,6 +790,9 @@ struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data)
tcpci->tcpc.frs_sourcing_vbus = tcpci_frs_sourcing_vbus;
tcpci->tcpc.set_partner_usb_comm_capable = tcpci_set_partner_usb_comm_capable;
+ if (tcpci->data->check_contaminant)
+ tcpci->tcpc.check_contaminant = tcpci_check_contaminant;
+
if (tcpci->data->auto_discharge_disconnect) {
tcpci->tcpc.enable_auto_vbus_discharge = tcpci_enable_auto_vbus_discharge;
tcpci->tcpc.set_auto_vbus_discharge_threshold =
@@ -838,7 +853,7 @@ static int tcpci_probe(struct i2c_client *client)
err = devm_request_threaded_irq(&client->dev, client->irq, NULL,
_tcpci_irq,
- IRQF_ONESHOT | IRQF_TRIGGER_LOW,
+ IRQF_SHARED | IRQF_ONESHOT | IRQF_TRIGGER_LOW,
dev_name(&client->dev), chip);
if (err < 0) {
tcpci_unregister_port(chip->tcpci);
diff --git a/drivers/usb/typec/tcpm/tcpci_maxim.h b/drivers/usb/typec/tcpm/tcpci_maxim.h
new file mode 100644
index 000000000000..2c1c4d161b0d
--- /dev/null
+++ b/drivers/usb/typec/tcpm/tcpci_maxim.h
@@ -0,0 +1,89 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2022 Google, Inc
+ *
+ * MAXIM TCPC header file.
+ */
+#ifndef TCPCI_MAXIM_H_
+#define TCPCI_MAXIM_H_
+
+#define VENDOR_CC_STATUS2 0x85
+#define CC1_VUFP_RD0P5 BIT(1)
+#define CC2_VUFP_RD0P5 BIT(5)
+#define TCPC_VENDOR_FLADC_STATUS 0x89
+
+#define TCPC_VENDOR_CC_CTRL1 0x8c
+#define CCCONNDRY BIT(7)
+#define CCCOMPEN BIT(5)
+
+#define TCPC_VENDOR_CC_CTRL2 0x8d
+#define SBUOVPDIS BIT(7)
+#define CCOVPDIS BIT(6)
+#define SBURPCTRL BIT(5)
+#define CCLPMODESEL_MASK GENMASK(4, 3)
+#define ULTRA_LOW_POWER_MODE BIT(3)
+#define CCRPCTRL_MASK GENMASK(2, 0)
+#define UA_1_SRC 1
+#define UA_80_SRC 3
+
+#define TCPC_VENDOR_CC_CTRL3 0x8e
+#define CCWTRDEB_MASK GENMASK(7, 6)
+#define CCWTRDEB_SHIFT 6
+#define CCWTRDEB_1MS 1
+#define CCWTRSEL_MASK GENMASK(5, 3)
+#define CCWTRSEL_SHIFT 3
+#define CCWTRSEL_1V 0x4
+#define CCLADDERDIS BIT(2)
+#define WTRCYCLE_MASK BIT(0)
+#define WTRCYCLE_SHIFT 0
+#define WTRCYCLE_2_4_S 0
+#define WTRCYCLE_4_8_S 1
+
+#define TCPC_VENDOR_ADC_CTRL1 0x91
+#define ADCINSEL_MASK GENMASK(7, 5)
+#define ADC_CHANNEL_OFFSET 5
+#define ADCEN BIT(0)
+
+enum contamiant_state {
+ NOT_DETECTED,
+ DETECTED,
+ SINK,
+};
+
+/*
+ * @potential_contaminant:
+ * Last returned result to tcpm indicating whether the TCPM port
+ * has potential contaminant.
+ */
+struct max_tcpci_chip {
+ struct tcpci_data data;
+ struct tcpci *tcpci;
+ struct device *dev;
+ struct i2c_client *client;
+ struct tcpm_port *port;
+ enum contamiant_state contaminant_state;
+};
+
+static inline int max_tcpci_read16(struct max_tcpci_chip *chip, unsigned int reg, u16 *val)
+{
+ return regmap_raw_read(chip->data.regmap, reg, val, sizeof(u16));
+}
+
+static inline int max_tcpci_write16(struct max_tcpci_chip *chip, unsigned int reg, u16 val)
+{
+ return regmap_raw_write(chip->data.regmap, reg, &val, sizeof(u16));
+}
+
+static inline int max_tcpci_read8(struct max_tcpci_chip *chip, unsigned int reg, u8 *val)
+{
+ return regmap_raw_read(chip->data.regmap, reg, val, sizeof(u8));
+}
+
+static inline int max_tcpci_write8(struct max_tcpci_chip *chip, unsigned int reg, u8 val)
+{
+ return regmap_raw_write(chip->data.regmap, reg, &val, sizeof(u8));
+}
+
+bool max_contaminant_is_contaminant(struct max_tcpci_chip *chip, bool disconnect_while_debounce);
+
+#endif // TCPCI_MAXIM_H_
diff --git a/drivers/usb/typec/tcpm/tcpci_maxim.c b/drivers/usb/typec/tcpm/tcpci_maxim_core.c
index 83e140ffcc3e..f32cda2a5e3a 100644
--- a/drivers/usb/typec/tcpm/tcpci_maxim.c
+++ b/drivers/usb/typec/tcpm/tcpci_maxim_core.c
@@ -1,6 +1,6 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright (C) 2020, Google LLC
+ * Copyright (C) 2020 - 2022, Google LLC
*
* MAXIM TCPCI based TCPC driver
*/
@@ -15,6 +15,8 @@
#include <linux/usb/tcpm.h>
#include <linux/usb/typec.h>
+#include "tcpci_maxim.h"
+
#define PD_ACTIVITY_TIMEOUT_MS 10000
#define TCPC_VENDOR_ALERT 0x80
@@ -39,14 +41,6 @@
#define MAX_BUCK_BOOST_SOURCE 0xa
#define MAX_BUCK_BOOST_SINK 0x5
-struct max_tcpci_chip {
- struct tcpci_data data;
- struct tcpci *tcpci;
- struct device *dev;
- struct i2c_client *client;
- struct tcpm_port *port;
-};
-
static const struct regmap_range max_tcpci_tcpci_range[] = {
regmap_reg_range(0x00, 0x95)
};
@@ -68,26 +62,6 @@ static struct max_tcpci_chip *tdata_to_max_tcpci(struct tcpci_data *tdata)
return container_of(tdata, struct max_tcpci_chip, data);
}
-static int max_tcpci_read16(struct max_tcpci_chip *chip, unsigned int reg, u16 *val)
-{
- return regmap_raw_read(chip->data.regmap, reg, val, sizeof(u16));
-}
-
-static int max_tcpci_write16(struct max_tcpci_chip *chip, unsigned int reg, u16 val)
-{
- return regmap_raw_write(chip->data.regmap, reg, &val, sizeof(u16));
-}
-
-static int max_tcpci_read8(struct max_tcpci_chip *chip, unsigned int reg, u8 *val)
-{
- return regmap_raw_read(chip->data.regmap, reg, val, sizeof(u8));
-}
-
-static int max_tcpci_write8(struct max_tcpci_chip *chip, unsigned int reg, u8 val)
-{
- return regmap_raw_write(chip->data.regmap, reg, &val, sizeof(u8));
-}
-
static void max_tcpci_init_regs(struct max_tcpci_chip *chip)
{
u16 alert_mask = 0;
@@ -348,8 +322,14 @@ static irqreturn_t _max_tcpci_irq(struct max_tcpci_chip *chip, u16 status)
if (status & TCPC_ALERT_VBUS_DISCNCT)
tcpm_vbus_change(chip->port);
- if (status & TCPC_ALERT_CC_STATUS)
- tcpm_cc_change(chip->port);
+ if (status & TCPC_ALERT_CC_STATUS) {
+ if (chip->contaminant_state == DETECTED || tcpm_port_is_toggling(chip->port)) {
+ if (!max_contaminant_is_contaminant(chip, false))
+ tcpm_port_clean(chip->port);
+ } else {
+ tcpm_cc_change(chip->port);
+ }
+ }
if (status & TCPC_ALERT_POWER_STATUS)
process_power_status(chip);
@@ -438,6 +418,14 @@ static int tcpci_init(struct tcpci *tcpci, struct tcpci_data *data)
return -1;
}
+static void max_tcpci_check_contaminant(struct tcpci *tcpci, struct tcpci_data *tdata)
+{
+ struct max_tcpci_chip *chip = tdata_to_max_tcpci(tdata);
+
+ if (!max_contaminant_is_contaminant(chip, true))
+ tcpm_port_clean(chip->port);
+}
+
static int max_tcpci_probe(struct i2c_client *client)
{
int ret;
@@ -471,6 +459,7 @@ static int max_tcpci_probe(struct i2c_client *client)
chip->data.auto_discharge_disconnect = true;
chip->data.vbus_vsafe0v = true;
chip->data.set_partner_usb_comm_capable = max_tcpci_set_partner_usb_comm_capable;
+ chip->data.check_contaminant = max_tcpci_check_contaminant;
max_tcpci_init_regs(chip);
chip->tcpci = tcpci_register_port(chip->dev, &chip->data);
diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
index 59b366b5c614..a0d943d78580 100644
--- a/drivers/usb/typec/tcpm/tcpm.c
+++ b/drivers/usb/typec/tcpm/tcpm.c
@@ -36,6 +36,7 @@
#define FOREACH_STATE(S) \
S(INVALID_STATE), \
S(TOGGLING), \
+ S(CHECK_CONTAMINANT), \
S(SRC_UNATTACHED), \
S(SRC_ATTACH_WAIT), \
S(SRC_ATTACHED), \
@@ -249,6 +250,7 @@ enum frs_typec_current {
#define TCPM_RESET_EVENT BIT(2)
#define TCPM_FRS_EVENT BIT(3)
#define TCPM_SOURCING_VBUS BIT(4)
+#define TCPM_PORT_CLEAN BIT(5)
#define LOG_BUFFER_ENTRIES 1024
#define LOG_BUFFER_ENTRY_SIZE 128
@@ -483,6 +485,13 @@ struct tcpm_port {
* SNK_READY for non-pd link.
*/
bool slow_charger_loop;
+
+ /*
+ * When true indicates that the lower level drivers indicate potential presence
+ * of contaminant in the connector pins based on the tcpm state machine
+ * transitions.
+ */
+ bool potential_contaminant;
#ifdef CONFIG_DEBUG_FS
struct dentry *dentry;
struct mutex logbuffer_lock; /* log buffer access lock */
@@ -647,7 +656,7 @@ static void tcpm_log(struct tcpm_port *port, const char *fmt, ...)
/* Do not log while disconnected and unattached */
if (tcpm_port_is_disconnected(port) &&
(port->state == SRC_UNATTACHED || port->state == SNK_UNATTACHED ||
- port->state == TOGGLING))
+ port->state == TOGGLING || port->state == CHECK_CONTAMINANT))
return;
va_start(args, fmt);
@@ -1693,14 +1702,11 @@ static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev,
}
break;
case CMD_ENTER_MODE:
- if (adev && pdev) {
- typec_altmode_update_active(pdev, true);
+ if (adev && pdev)
*adev_action = ADEV_QUEUE_VDM_SEND_EXIT_MODE_ON_FAIL;
- }
return 0;
case CMD_EXIT_MODE:
if (adev && pdev) {
- typec_altmode_update_active(pdev, false);
/* Back to USB Operation */
*adev_action = ADEV_NOTIFY_USB_AND_QUEUE_VDM;
return 0;
@@ -3904,15 +3910,28 @@ static void run_state_machine(struct tcpm_port *port)
unsigned int msecs;
enum tcpm_state upcoming_state;
+ if (port->tcpc->check_contaminant && port->state != CHECK_CONTAMINANT)
+ port->potential_contaminant = ((port->enter_state == SRC_ATTACH_WAIT &&
+ port->state == SRC_UNATTACHED) ||
+ (port->enter_state == SNK_ATTACH_WAIT &&
+ port->state == SNK_UNATTACHED));
+
port->enter_state = port->state;
switch (port->state) {
case TOGGLING:
break;
+ case CHECK_CONTAMINANT:
+ port->tcpc->check_contaminant(port->tcpc);
+ break;
/* SRC states */
case SRC_UNATTACHED:
if (!port->non_pd_role_swap)
tcpm_swap_complete(port, -ENOTCONN);
tcpm_src_detach(port);
+ if (port->potential_contaminant) {
+ tcpm_set_state(port, CHECK_CONTAMINANT, 0);
+ break;
+ }
if (tcpm_start_toggling(port, tcpm_rp_cc(port))) {
tcpm_set_state(port, TOGGLING, 0);
break;
@@ -4150,6 +4169,10 @@ static void run_state_machine(struct tcpm_port *port)
tcpm_swap_complete(port, -ENOTCONN);
tcpm_pps_complete(port, -ENOTCONN);
tcpm_snk_detach(port);
+ if (port->potential_contaminant) {
+ tcpm_set_state(port, CHECK_CONTAMINANT, 0);
+ break;
+ }
if (tcpm_start_toggling(port, TYPEC_CC_RD)) {
tcpm_set_state(port, TOGGLING, 0);
break;
@@ -4925,6 +4948,9 @@ static void _tcpm_cc_change(struct tcpm_port *port, enum typec_cc_status cc1,
else if (tcpm_port_is_sink(port))
tcpm_set_state(port, SNK_ATTACH_WAIT, 0);
break;
+ case CHECK_CONTAMINANT:
+ /* Wait for Toggling to be resumed */
+ break;
case SRC_UNATTACHED:
case ACC_UNATTACHED:
if (tcpm_port_is_debug(port) || tcpm_port_is_audio(port) ||
@@ -5424,6 +5450,15 @@ static void tcpm_pd_event_handler(struct kthread_work *work)
port->vbus_source = true;
_tcpm_pd_vbus_on(port);
}
+ if (events & TCPM_PORT_CLEAN) {
+ tcpm_log(port, "port clean");
+ if (port->state == CHECK_CONTAMINANT) {
+ if (tcpm_start_toggling(port, tcpm_rp_cc(port)))
+ tcpm_set_state(port, TOGGLING, 0);
+ else
+ tcpm_set_state(port, tcpm_default_state(port), 0);
+ }
+ }
spin_lock(&port->pd_event_lock);
}
@@ -5476,6 +5511,21 @@ void tcpm_sourcing_vbus(struct tcpm_port *port)
}
EXPORT_SYMBOL_GPL(tcpm_sourcing_vbus);
+void tcpm_port_clean(struct tcpm_port *port)
+{
+ spin_lock(&port->pd_event_lock);
+ port->pd_events |= TCPM_PORT_CLEAN;
+ spin_unlock(&port->pd_event_lock);
+ kthread_queue_work(port->wq, &port->event_work);
+}
+EXPORT_SYMBOL_GPL(tcpm_port_clean);
+
+bool tcpm_port_is_toggling(struct tcpm_port *port)
+{
+ return port->port_type == TYPEC_PORT_DRP && port->state == TOGGLING;
+}
+EXPORT_SYMBOL_GPL(tcpm_port_is_toggling);
+
static void tcpm_enable_frs_work(struct kthread_work *work)
{
struct tcpm_port *port = container_of(work, struct tcpm_port, enable_frs);
diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c
index 46a4d8b128f0..485b90c13078 100644
--- a/drivers/usb/typec/tipd/core.c
+++ b/drivers/usb/typec/tipd/core.c
@@ -95,6 +95,7 @@ struct tps6598x {
struct power_supply_desc psy_desc;
enum power_supply_usb_type usb_type;
+ int wakeup;
u16 pwr_status;
};
@@ -846,6 +847,12 @@ static int tps6598x_probe(struct i2c_client *client)
i2c_set_clientdata(client, tps);
fwnode_handle_put(fwnode);
+ tps->wakeup = device_property_read_bool(tps->dev, "wakeup-source");
+ if (tps->wakeup) {
+ device_init_wakeup(&client->dev, true);
+ enable_irq_wake(client->irq);
+ }
+
return 0;
err_disconnect:
@@ -870,6 +877,36 @@ static void tps6598x_remove(struct i2c_client *client)
usb_role_switch_put(tps->role_sw);
}
+static int __maybe_unused tps6598x_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct tps6598x *tps = i2c_get_clientdata(client);
+
+ if (tps->wakeup) {
+ disable_irq(client->irq);
+ enable_irq_wake(client->irq);
+ }
+
+ return 0;
+}
+
+static int __maybe_unused tps6598x_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct tps6598x *tps = i2c_get_clientdata(client);
+
+ if (tps->wakeup) {
+ disable_irq_wake(client->irq);
+ enable_irq(client->irq);
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops tps6598x_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(tps6598x_suspend, tps6598x_resume)
+};
+
static const struct of_device_id tps6598x_of_match[] = {
{ .compatible = "ti,tps6598x", },
{ .compatible = "apple,cd321x", },
@@ -886,6 +923,7 @@ MODULE_DEVICE_TABLE(i2c, tps6598x_id);
static struct i2c_driver tps6598x_i2c_driver = {
.driver = {
.name = "tps6598x",
+ .pm = &tps6598x_pm_ops,
.of_match_table = tps6598x_of_match,
},
.probe_new = tps6598x_probe,
diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
index 1cf8947c6d66..f632350f6dcb 100644
--- a/drivers/usb/typec/ucsi/ucsi.c
+++ b/drivers/usb/typec/ucsi/ucsi.c
@@ -567,8 +567,9 @@ static void ucsi_unregister_altmodes(struct ucsi_connector *con, u8 recipient)
}
}
-static int ucsi_get_pdos(struct ucsi_connector *con, int is_partner,
- u32 *pdos, int offset, int num_pdos)
+static int ucsi_read_pdos(struct ucsi_connector *con,
+ enum typec_role role, int is_partner,
+ u32 *pdos, int offset, int num_pdos)
{
struct ucsi *ucsi = con->ucsi;
u64 command;
@@ -578,7 +579,7 @@ static int ucsi_get_pdos(struct ucsi_connector *con, int is_partner,
command |= UCSI_GET_PDOS_PARTNER_PDO(is_partner);
command |= UCSI_GET_PDOS_PDO_OFFSET(offset);
command |= UCSI_GET_PDOS_NUM_PDOS(num_pdos - 1);
- command |= UCSI_GET_PDOS_SRC_PDOS;
+ command |= is_source(role) ? UCSI_GET_PDOS_SRC_PDOS : 0;
ret = ucsi_send_command(ucsi, command, pdos + offset,
num_pdos * sizeof(u32));
if (ret < 0 && ret != -ETIMEDOUT)
@@ -587,30 +588,43 @@ static int ucsi_get_pdos(struct ucsi_connector *con, int is_partner,
return ret;
}
-static int ucsi_get_src_pdos(struct ucsi_connector *con)
+static int ucsi_get_pdos(struct ucsi_connector *con, enum typec_role role,
+ int is_partner, u32 *pdos)
{
+ u8 num_pdos;
int ret;
/* UCSI max payload means only getting at most 4 PDOs at a time */
- ret = ucsi_get_pdos(con, 1, con->src_pdos, 0, UCSI_MAX_PDOS);
+ ret = ucsi_read_pdos(con, role, is_partner, pdos, 0, UCSI_MAX_PDOS);
if (ret < 0)
return ret;
- con->num_pdos = ret / sizeof(u32); /* number of bytes to 32-bit PDOs */
- if (con->num_pdos < UCSI_MAX_PDOS)
- return 0;
+ num_pdos = ret / sizeof(u32); /* number of bytes to 32-bit PDOs */
+ if (num_pdos < UCSI_MAX_PDOS)
+ return num_pdos;
/* get the remaining PDOs, if any */
- ret = ucsi_get_pdos(con, 1, con->src_pdos, UCSI_MAX_PDOS,
- PDO_MAX_OBJECTS - UCSI_MAX_PDOS);
+ ret = ucsi_read_pdos(con, role, is_partner, pdos, UCSI_MAX_PDOS,
+ PDO_MAX_OBJECTS - UCSI_MAX_PDOS);
if (ret < 0)
return ret;
- con->num_pdos += ret / sizeof(u32);
+ return ret / sizeof(u32) + num_pdos;
+}
+
+static int ucsi_get_src_pdos(struct ucsi_connector *con)
+{
+ int ret;
+
+ ret = ucsi_get_pdos(con, TYPEC_SOURCE, 1, con->src_pdos);
+ if (ret < 0)
+ return ret;
+
+ con->num_pdos = ret;
ucsi_port_psy_changed(con);
- return 0;
+ return ret;
}
static int ucsi_check_altmodes(struct ucsi_connector *con)
@@ -635,6 +649,72 @@ static int ucsi_check_altmodes(struct ucsi_connector *con)
return ret;
}
+static int ucsi_register_partner_pdos(struct ucsi_connector *con)
+{
+ struct usb_power_delivery_desc desc = { con->ucsi->cap.pd_version };
+ struct usb_power_delivery_capabilities_desc caps;
+ struct usb_power_delivery_capabilities *cap;
+ int ret;
+
+ if (con->partner_pd)
+ return 0;
+
+ con->partner_pd = usb_power_delivery_register(NULL, &desc);
+ if (IS_ERR(con->partner_pd))
+ return PTR_ERR(con->partner_pd);
+
+ ret = ucsi_get_pdos(con, TYPEC_SOURCE, 1, caps.pdo);
+ if (ret > 0) {
+ if (ret < PDO_MAX_OBJECTS)
+ caps.pdo[ret] = 0;
+
+ caps.role = TYPEC_SOURCE;
+ cap = usb_power_delivery_register_capabilities(con->partner_pd, &caps);
+ if (IS_ERR(cap))
+ return PTR_ERR(cap);
+
+ con->partner_source_caps = cap;
+
+ ret = typec_partner_set_usb_power_delivery(con->partner, con->partner_pd);
+ if (ret) {
+ usb_power_delivery_unregister_capabilities(con->partner_source_caps);
+ return ret;
+ }
+ }
+
+ ret = ucsi_get_pdos(con, TYPEC_SINK, 1, caps.pdo);
+ if (ret > 0) {
+ if (ret < PDO_MAX_OBJECTS)
+ caps.pdo[ret] = 0;
+
+ caps.role = TYPEC_SINK;
+
+ cap = usb_power_delivery_register_capabilities(con->partner_pd, &caps);
+ if (IS_ERR(cap))
+ return PTR_ERR(cap);
+
+ con->partner_sink_caps = cap;
+
+ ret = typec_partner_set_usb_power_delivery(con->partner, con->partner_pd);
+ if (ret) {
+ usb_power_delivery_unregister_capabilities(con->partner_sink_caps);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static void ucsi_unregister_partner_pdos(struct ucsi_connector *con)
+{
+ usb_power_delivery_unregister_capabilities(con->partner_sink_caps);
+ con->partner_sink_caps = NULL;
+ usb_power_delivery_unregister_capabilities(con->partner_source_caps);
+ con->partner_source_caps = NULL;
+ usb_power_delivery_unregister(con->partner_pd);
+ con->partner_pd = NULL;
+}
+
static void ucsi_pwr_opmode_change(struct ucsi_connector *con)
{
switch (UCSI_CONSTAT_PWR_OPMODE(con->status.flags)) {
@@ -643,6 +723,7 @@ static void ucsi_pwr_opmode_change(struct ucsi_connector *con)
typec_set_pwr_opmode(con->port, TYPEC_PWR_MODE_PD);
ucsi_partner_task(con, ucsi_get_src_pdos, 30, 0);
ucsi_partner_task(con, ucsi_check_altmodes, 30, 0);
+ ucsi_partner_task(con, ucsi_register_partner_pdos, 1, HZ);
break;
case UCSI_CONSTAT_PWR_OPMODE_TYPEC1_5:
con->rdo = 0;
@@ -701,6 +782,7 @@ static void ucsi_unregister_partner(struct ucsi_connector *con)
if (!con->partner)
return;
+ ucsi_unregister_partner_pdos(con);
ucsi_unregister_altmodes(con, UCSI_RECIPIENT_SOP);
typec_unregister_partner(con->partner);
con->partner = NULL;
@@ -805,6 +887,10 @@ static void ucsi_handle_connector_change(struct work_struct *work)
if (con->status.flags & UCSI_CONSTAT_CONNECTED) {
ucsi_register_partner(con);
ucsi_partner_task(con, ucsi_check_connection, 1, HZ);
+
+ if (UCSI_CONSTAT_PWR_OPMODE(con->status.flags) ==
+ UCSI_CONSTAT_PWR_OPMODE_PD)
+ ucsi_partner_task(con, ucsi_register_partner_pdos, 1, HZ);
} else {
ucsi_unregister_partner(con);
}
@@ -1041,6 +1127,9 @@ static struct fwnode_handle *ucsi_find_fwnode(struct ucsi_connector *con)
static int ucsi_register_port(struct ucsi *ucsi, int index)
{
+ struct usb_power_delivery_desc desc = { ucsi->cap.pd_version};
+ struct usb_power_delivery_capabilities_desc pd_caps;
+ struct usb_power_delivery_capabilities *pd_cap;
struct ucsi_connector *con = &ucsi->connector[index];
struct typec_capability *cap = &con->typec_cap;
enum typec_accessory *accessory = cap->accessory;
@@ -1120,6 +1209,41 @@ static int ucsi_register_port(struct ucsi *ucsi, int index)
goto out;
}
+ con->pd = usb_power_delivery_register(ucsi->dev, &desc);
+
+ ret = ucsi_get_pdos(con, TYPEC_SOURCE, 0, pd_caps.pdo);
+ if (ret > 0) {
+ if (ret < PDO_MAX_OBJECTS)
+ pd_caps.pdo[ret] = 0;
+
+ pd_caps.role = TYPEC_SOURCE;
+ pd_cap = usb_power_delivery_register_capabilities(con->pd, &pd_caps);
+ if (IS_ERR(pd_cap)) {
+ ret = PTR_ERR(pd_cap);
+ goto out;
+ }
+
+ con->port_source_caps = pd_cap;
+ typec_port_set_usb_power_delivery(con->port, con->pd);
+ }
+
+ memset(&pd_caps, 0, sizeof(pd_caps));
+ ret = ucsi_get_pdos(con, TYPEC_SINK, 0, pd_caps.pdo);
+ if (ret > 0) {
+ if (ret < PDO_MAX_OBJECTS)
+ pd_caps.pdo[ret] = 0;
+
+ pd_caps.role = TYPEC_SINK;
+ pd_cap = usb_power_delivery_register_capabilities(con->pd, &pd_caps);
+ if (IS_ERR(pd_cap)) {
+ ret = PTR_ERR(pd_cap);
+ goto out;
+ }
+
+ con->port_sink_caps = pd_cap;
+ typec_port_set_usb_power_delivery(con->port, con->pd);
+ }
+
/* Alternate modes */
ret = ucsi_register_altmodes(con, UCSI_RECIPIENT_CON);
if (ret) {
@@ -1158,8 +1282,8 @@ static int ucsi_register_port(struct ucsi *ucsi, int index)
if (con->status.flags & UCSI_CONSTAT_CONNECTED) {
typec_set_pwr_role(con->port,
!!(con->status.flags & UCSI_CONSTAT_PWR_DIR));
- ucsi_pwr_opmode_change(con);
ucsi_register_partner(con);
+ ucsi_pwr_opmode_change(con);
ucsi_port_psy_changed(con);
}
@@ -1265,6 +1389,13 @@ err_unregister:
ucsi_unregister_port_psy(con);
if (con->wq)
destroy_workqueue(con->wq);
+
+ usb_power_delivery_unregister_capabilities(con->port_sink_caps);
+ con->port_sink_caps = NULL;
+ usb_power_delivery_unregister_capabilities(con->port_source_caps);
+ con->port_source_caps = NULL;
+ usb_power_delivery_unregister(con->pd);
+ con->pd = NULL;
typec_unregister_port(con->port);
con->port = NULL;
}
@@ -1447,6 +1578,13 @@ void ucsi_unregister(struct ucsi *ucsi)
mutex_unlock(&ucsi->connector[i].lock);
destroy_workqueue(ucsi->connector[i].wq);
}
+
+ usb_power_delivery_unregister_capabilities(ucsi->connector[i].port_sink_caps);
+ ucsi->connector[i].port_sink_caps = NULL;
+ usb_power_delivery_unregister_capabilities(ucsi->connector[i].port_source_caps);
+ ucsi->connector[i].port_source_caps = NULL;
+ usb_power_delivery_unregister(ucsi->connector[i].pd);
+ ucsi->connector[i].pd = NULL;
typec_unregister_port(ucsi->connector[i].port);
}
diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h
index 60ce9fb6e745..c09af859f573 100644
--- a/drivers/usb/typec/ucsi/ucsi.h
+++ b/drivers/usb/typec/ucsi/ucsi.h
@@ -340,6 +340,14 @@ struct ucsi_connector {
u32 src_pdos[PDO_MAX_OBJECTS];
int num_pdos;
+ /* USB PD objects */
+ struct usb_power_delivery *pd;
+ struct usb_power_delivery_capabilities *port_source_caps;
+ struct usb_power_delivery_capabilities *port_sink_caps;
+ struct usb_power_delivery *partner_pd;
+ struct usb_power_delivery_capabilities *partner_source_caps;
+ struct usb_power_delivery_capabilities *partner_sink_caps;
+
struct usb_role_switch *usb_role_sw;
};
diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c
index 46441f1477f2..e0ed465bd518 100644
--- a/drivers/usb/typec/ucsi/ucsi_ccg.c
+++ b/drivers/usb/typec/ucsi/ucsi_ccg.c
@@ -643,7 +643,7 @@ static int ccg_request_irq(struct ucsi_ccg *uc)
{
unsigned long flags = IRQF_ONESHOT;
- if (!has_acpi_companion(uc->dev))
+ if (!dev_fwnode(uc->dev))
flags |= IRQF_TRIGGER_HIGH;
return request_threaded_irq(uc->irq, NULL, ccg_irq_handler, flags, dev_name(uc->dev), uc);
@@ -1342,6 +1342,7 @@ static int ucsi_ccg_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct ucsi_ccg *uc;
+ const char *fw_name;
int status;
uc = devm_kzalloc(dev, sizeof(*uc), GFP_KERNEL);
@@ -1357,9 +1358,15 @@ static int ucsi_ccg_probe(struct i2c_client *client)
INIT_WORK(&uc->pm_work, ccg_pm_workaround_work);
/* Only fail FW flashing when FW build information is not provided */
- status = device_property_read_u16(dev, "ccgx,firmware-build",
- &uc->fw_build);
- if (status)
+ status = device_property_read_string(dev, "firmware-name", &fw_name);
+ if (!status) {
+ if (!strcmp(fw_name, "nvidia,jetson-agx-xavier"))
+ uc->fw_build = CCG_FW_BUILD_NVIDIA_TEGRA;
+ else if (!strcmp(fw_name, "nvidia,gpu"))
+ uc->fw_build = CCG_FW_BUILD_NVIDIA;
+ }
+
+ if (!uc->fw_build)
dev_err(uc->dev, "failed to get FW build information\n");
/* reset ccg device and initialize ucsi */
@@ -1426,6 +1433,12 @@ static void ucsi_ccg_remove(struct i2c_client *client)
free_irq(uc->irq, uc);
}
+static const struct of_device_id ucsi_ccg_of_match_table[] = {
+ { .compatible = "cypress,cypd4226", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ucsi_ccg_of_match_table);
+
static const struct i2c_device_id ucsi_ccg_device_id[] = {
{"ccgx-ucsi", 0},
{}
@@ -1480,6 +1493,7 @@ static struct i2c_driver ucsi_ccg_driver = {
.pm = &ucsi_ccg_pm,
.dev_groups = ucsi_ccg_groups,
.acpi_match_table = amd_i2c_ucsi_match,
+ .of_match_table = ucsi_ccg_of_match_table,
},
.probe_new = ucsi_ccg_probe,
.remove = ucsi_ccg_remove,
diff --git a/drivers/vdpa/Kconfig b/drivers/vdpa/Kconfig
index 50f45d037611..cd6ad92f3f05 100644
--- a/drivers/vdpa/Kconfig
+++ b/drivers/vdpa/Kconfig
@@ -71,6 +71,18 @@ config MLX5_VDPA_NET
be executed by the hardware. It also supports a variety of stateless
offloads depending on the actual device used and firmware version.
+config MLX5_VDPA_STEERING_DEBUG
+ bool "expose steering counters on debugfs"
+ select MLX5_VDPA
+ help
+ Expose RX steering counters in debugfs to aid in debugging. For each VLAN
+ or non VLAN interface, two hardware counters are added to the RX flow
+ table: one for unicast and one for multicast.
+ The counters counts the number of packets and bytes and exposes them in
+ debugfs. Once can read the counters using, e.g.:
+ cat /sys/kernel/debug/mlx5/mlx5_core.sf.1/vdpa-0/rx/untagged/ucast/packets
+ cat /sys/kernel/debug/mlx5/mlx5_core.sf.1/vdpa-0/rx/untagged/mcast/bytes
+
config VP_VDPA
tristate "Virtio PCI bridge vDPA driver"
select VIRTIO_PCI_LIB
@@ -86,4 +98,22 @@ config ALIBABA_ENI_VDPA
VDPA driver for Alibaba ENI (Elastic Network Interface) which is built upon
virtio 0.9.5 specification.
+ config SNET_VDPA
+ tristate "SolidRun's vDPA driver for SolidNET"
+ depends on PCI_MSI && PCI_IOV && (HWMON || HWMON=n)
+
+ # This driver MAY create a HWMON device.
+ # Depending on (HWMON || HWMON=n) ensures that:
+ # If HWMON=n the driver can be compiled either as a module or built-in.
+ # If HWMON=y the driver can be compiled either as a module or built-in.
+ # If HWMON=m the driver is forced to be compiled as a module.
+ # By doing so, IS_ENABLED can be used instead of IS_REACHABLE
+
+ help
+ vDPA driver for SolidNET DPU.
+ With this driver, the VirtIO dataplane can be
+ offloaded to a SolidNET DPU.
+ This driver includes a HW monitor device that
+ reads health values from the DPU.
+
endif # VDPA
diff --git a/drivers/vdpa/Makefile b/drivers/vdpa/Makefile
index 15665563a7f4..59396ff2a318 100644
--- a/drivers/vdpa/Makefile
+++ b/drivers/vdpa/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_IFCVF) += ifcvf/
obj-$(CONFIG_MLX5_VDPA) += mlx5/
obj-$(CONFIG_VP_VDPA) += virtio_pci/
obj-$(CONFIG_ALIBABA_ENI_VDPA) += alibaba/
+obj-$(CONFIG_SNET_VDPA) += solidrun/
diff --git a/drivers/vdpa/ifcvf/ifcvf_base.c b/drivers/vdpa/ifcvf/ifcvf_base.c
index 3e4486bfa0b7..5563b3a773c7 100644
--- a/drivers/vdpa/ifcvf/ifcvf_base.c
+++ b/drivers/vdpa/ifcvf/ifcvf_base.c
@@ -10,11 +10,6 @@
#include "ifcvf_base.h"
-struct ifcvf_adapter *vf_to_adapter(struct ifcvf_hw *hw)
-{
- return container_of(hw, struct ifcvf_adapter, vf);
-}
-
u16 ifcvf_set_vq_vector(struct ifcvf_hw *hw, u16 qid, int vector)
{
struct virtio_pci_common_cfg __iomem *cfg = hw->common_cfg;
@@ -37,8 +32,6 @@ u16 ifcvf_set_config_vector(struct ifcvf_hw *hw, int vector)
static void __iomem *get_cap_addr(struct ifcvf_hw *hw,
struct virtio_pci_cap *cap)
{
- struct ifcvf_adapter *ifcvf;
- struct pci_dev *pdev;
u32 length, offset;
u8 bar;
@@ -46,17 +39,14 @@ static void __iomem *get_cap_addr(struct ifcvf_hw *hw,
offset = le32_to_cpu(cap->offset);
bar = cap->bar;
- ifcvf= vf_to_adapter(hw);
- pdev = ifcvf->pdev;
-
if (bar >= IFCVF_PCI_MAX_RESOURCE) {
- IFCVF_DBG(pdev,
+ IFCVF_DBG(hw->pdev,
"Invalid bar number %u to get capabilities\n", bar);
return NULL;
}
- if (offset + length > pci_resource_len(pdev, bar)) {
- IFCVF_DBG(pdev,
+ if (offset + length > pci_resource_len(hw->pdev, bar)) {
+ IFCVF_DBG(hw->pdev,
"offset(%u) + len(%u) overflows bar%u's capability\n",
offset, length, bar);
return NULL;
@@ -92,6 +82,7 @@ int ifcvf_init_hw(struct ifcvf_hw *hw, struct pci_dev *pdev)
IFCVF_ERR(pdev, "Failed to read PCI capability list\n");
return -EIO;
}
+ hw->pdev = pdev;
while (pos) {
ret = ifcvf_read_config_range(pdev, (u32 *)&cap,
@@ -215,15 +206,13 @@ u64 ifcvf_get_hw_features(struct ifcvf_hw *hw)
u64 ifcvf_get_features(struct ifcvf_hw *hw)
{
- return hw->hw_features;
+ return hw->dev_features;
}
int ifcvf_verify_min_features(struct ifcvf_hw *hw, u64 features)
{
- struct ifcvf_adapter *ifcvf = vf_to_adapter(hw);
-
if (!(features & BIT_ULL(VIRTIO_F_ACCESS_PLATFORM)) && features) {
- IFCVF_ERR(ifcvf->pdev, "VIRTIO_F_ACCESS_PLATFORM is not negotiated\n");
+ IFCVF_ERR(hw->pdev, "VIRTIO_F_ACCESS_PLATFORM is not negotiated\n");
return -EINVAL;
}
@@ -232,13 +221,11 @@ int ifcvf_verify_min_features(struct ifcvf_hw *hw, u64 features)
u32 ifcvf_get_config_size(struct ifcvf_hw *hw)
{
- struct ifcvf_adapter *adapter;
u32 net_config_size = sizeof(struct virtio_net_config);
u32 blk_config_size = sizeof(struct virtio_blk_config);
u32 cap_size = hw->cap_dev_config_size;
u32 config_size;
- adapter = vf_to_adapter(hw);
/* If the onboard device config space size is greater than
* the size of struct virtio_net/blk_config, only the spec
* implementing contents size is returned, this is very
@@ -253,7 +240,7 @@ u32 ifcvf_get_config_size(struct ifcvf_hw *hw)
break;
default:
config_size = 0;
- IFCVF_ERR(adapter->pdev, "VIRTIO ID %u not supported\n", hw->dev_type);
+ IFCVF_ERR(hw->pdev, "VIRTIO ID %u not supported\n", hw->dev_type);
}
return config_size;
@@ -301,14 +288,11 @@ static void ifcvf_set_features(struct ifcvf_hw *hw, u64 features)
static int ifcvf_config_features(struct ifcvf_hw *hw)
{
- struct ifcvf_adapter *ifcvf;
-
- ifcvf = vf_to_adapter(hw);
ifcvf_set_features(hw, hw->req_features);
ifcvf_add_status(hw, VIRTIO_CONFIG_S_FEATURES_OK);
if (!(ifcvf_get_status(hw) & VIRTIO_CONFIG_S_FEATURES_OK)) {
- IFCVF_ERR(ifcvf->pdev, "Failed to set FEATURES_OK status\n");
+ IFCVF_ERR(hw->pdev, "Failed to set FEATURES_OK status\n");
return -EIO;
}
diff --git a/drivers/vdpa/ifcvf/ifcvf_base.h b/drivers/vdpa/ifcvf/ifcvf_base.h
index f5563f665cc6..c20d1c40214e 100644
--- a/drivers/vdpa/ifcvf/ifcvf_base.h
+++ b/drivers/vdpa/ifcvf/ifcvf_base.h
@@ -19,6 +19,7 @@
#include <uapi/linux/virtio_blk.h>
#include <uapi/linux/virtio_config.h>
#include <uapi/linux/virtio_pci.h>
+#include <uapi/linux/vdpa.h>
#define N3000_DEVICE_ID 0x1041
#define N3000_SUBSYS_DEVICE_ID 0x001A
@@ -38,9 +39,6 @@
#define IFCVF_DBG(pdev, fmt, ...) dev_dbg(&pdev->dev, fmt, ##__VA_ARGS__)
#define IFCVF_INFO(pdev, fmt, ...) dev_info(&pdev->dev, fmt, ##__VA_ARGS__)
-#define ifcvf_private_to_vf(adapter) \
- (&((struct ifcvf_adapter *)adapter)->vf)
-
/* all vqs and config interrupt has its own vector */
#define MSIX_VECTOR_PER_VQ_AND_CONFIG 1
/* all vqs share a vector, and config interrupt has a separate vector */
@@ -78,6 +76,8 @@ struct ifcvf_hw {
u32 dev_type;
u64 req_features;
u64 hw_features;
+ /* provisioned device features */
+ u64 dev_features;
struct virtio_pci_common_cfg __iomem *common_cfg;
void __iomem *dev_cfg;
struct vring_info vring[IFCVF_MAX_QUEUES];
@@ -89,12 +89,13 @@ struct ifcvf_hw {
u16 nr_vring;
/* VIRTIO_PCI_CAP_DEVICE_CFG size */
u32 cap_dev_config_size;
+ struct pci_dev *pdev;
};
struct ifcvf_adapter {
struct vdpa_device vdpa;
struct pci_dev *pdev;
- struct ifcvf_hw vf;
+ struct ifcvf_hw *vf;
};
struct ifcvf_vring_lm_cfg {
@@ -109,6 +110,7 @@ struct ifcvf_lm_cfg {
struct ifcvf_vdpa_mgmt_dev {
struct vdpa_mgmt_dev mdev;
+ struct ifcvf_hw vf;
struct ifcvf_adapter *adapter;
struct pci_dev *pdev;
};
diff --git a/drivers/vdpa/ifcvf/ifcvf_main.c b/drivers/vdpa/ifcvf/ifcvf_main.c
index 44b29289aa19..7f78c47e40d6 100644
--- a/drivers/vdpa/ifcvf/ifcvf_main.c
+++ b/drivers/vdpa/ifcvf/ifcvf_main.c
@@ -69,10 +69,9 @@ static void ifcvf_free_irq_vectors(void *data)
pci_free_irq_vectors(data);
}
-static void ifcvf_free_per_vq_irq(struct ifcvf_adapter *adapter)
+static void ifcvf_free_per_vq_irq(struct ifcvf_hw *vf)
{
- struct pci_dev *pdev = adapter->pdev;
- struct ifcvf_hw *vf = &adapter->vf;
+ struct pci_dev *pdev = vf->pdev;
int i;
for (i = 0; i < vf->nr_vring; i++) {
@@ -83,10 +82,9 @@ static void ifcvf_free_per_vq_irq(struct ifcvf_adapter *adapter)
}
}
-static void ifcvf_free_vqs_reused_irq(struct ifcvf_adapter *adapter)
+static void ifcvf_free_vqs_reused_irq(struct ifcvf_hw *vf)
{
- struct pci_dev *pdev = adapter->pdev;
- struct ifcvf_hw *vf = &adapter->vf;
+ struct pci_dev *pdev = vf->pdev;
if (vf->vqs_reused_irq != -EINVAL) {
devm_free_irq(&pdev->dev, vf->vqs_reused_irq, vf);
@@ -95,20 +93,17 @@ static void ifcvf_free_vqs_reused_irq(struct ifcvf_adapter *adapter)
}
-static void ifcvf_free_vq_irq(struct ifcvf_adapter *adapter)
+static void ifcvf_free_vq_irq(struct ifcvf_hw *vf)
{
- struct ifcvf_hw *vf = &adapter->vf;
-
if (vf->msix_vector_status == MSIX_VECTOR_PER_VQ_AND_CONFIG)
- ifcvf_free_per_vq_irq(adapter);
+ ifcvf_free_per_vq_irq(vf);
else
- ifcvf_free_vqs_reused_irq(adapter);
+ ifcvf_free_vqs_reused_irq(vf);
}
-static void ifcvf_free_config_irq(struct ifcvf_adapter *adapter)
+static void ifcvf_free_config_irq(struct ifcvf_hw *vf)
{
- struct pci_dev *pdev = adapter->pdev;
- struct ifcvf_hw *vf = &adapter->vf;
+ struct pci_dev *pdev = vf->pdev;
if (vf->config_irq == -EINVAL)
return;
@@ -123,12 +118,12 @@ static void ifcvf_free_config_irq(struct ifcvf_adapter *adapter)
}
}
-static void ifcvf_free_irq(struct ifcvf_adapter *adapter)
+static void ifcvf_free_irq(struct ifcvf_hw *vf)
{
- struct pci_dev *pdev = adapter->pdev;
+ struct pci_dev *pdev = vf->pdev;
- ifcvf_free_vq_irq(adapter);
- ifcvf_free_config_irq(adapter);
+ ifcvf_free_vq_irq(vf);
+ ifcvf_free_config_irq(vf);
ifcvf_free_irq_vectors(pdev);
}
@@ -137,10 +132,9 @@ static void ifcvf_free_irq(struct ifcvf_adapter *adapter)
* It returns the number of allocated vectors, negative
* return value when fails.
*/
-static int ifcvf_alloc_vectors(struct ifcvf_adapter *adapter)
+static int ifcvf_alloc_vectors(struct ifcvf_hw *vf)
{
- struct pci_dev *pdev = adapter->pdev;
- struct ifcvf_hw *vf = &adapter->vf;
+ struct pci_dev *pdev = vf->pdev;
int max_intr, ret;
/* all queues and config interrupt */
@@ -160,10 +154,9 @@ static int ifcvf_alloc_vectors(struct ifcvf_adapter *adapter)
return ret;
}
-static int ifcvf_request_per_vq_irq(struct ifcvf_adapter *adapter)
+static int ifcvf_request_per_vq_irq(struct ifcvf_hw *vf)
{
- struct pci_dev *pdev = adapter->pdev;
- struct ifcvf_hw *vf = &adapter->vf;
+ struct pci_dev *pdev = vf->pdev;
int i, vector, ret, irq;
vf->vqs_reused_irq = -EINVAL;
@@ -190,15 +183,14 @@ static int ifcvf_request_per_vq_irq(struct ifcvf_adapter *adapter)
return 0;
err:
- ifcvf_free_irq(adapter);
+ ifcvf_free_irq(vf);
return -EFAULT;
}
-static int ifcvf_request_vqs_reused_irq(struct ifcvf_adapter *adapter)
+static int ifcvf_request_vqs_reused_irq(struct ifcvf_hw *vf)
{
- struct pci_dev *pdev = adapter->pdev;
- struct ifcvf_hw *vf = &adapter->vf;
+ struct pci_dev *pdev = vf->pdev;
int i, vector, ret, irq;
vector = 0;
@@ -224,15 +216,14 @@ static int ifcvf_request_vqs_reused_irq(struct ifcvf_adapter *adapter)
return 0;
err:
- ifcvf_free_irq(adapter);
+ ifcvf_free_irq(vf);
return -EFAULT;
}
-static int ifcvf_request_dev_irq(struct ifcvf_adapter *adapter)
+static int ifcvf_request_dev_irq(struct ifcvf_hw *vf)
{
- struct pci_dev *pdev = adapter->pdev;
- struct ifcvf_hw *vf = &adapter->vf;
+ struct pci_dev *pdev = vf->pdev;
int i, vector, ret, irq;
vector = 0;
@@ -265,29 +256,27 @@ static int ifcvf_request_dev_irq(struct ifcvf_adapter *adapter)
return 0;
err:
- ifcvf_free_irq(adapter);
+ ifcvf_free_irq(vf);
return -EFAULT;
}
-static int ifcvf_request_vq_irq(struct ifcvf_adapter *adapter)
+static int ifcvf_request_vq_irq(struct ifcvf_hw *vf)
{
- struct ifcvf_hw *vf = &adapter->vf;
int ret;
if (vf->msix_vector_status == MSIX_VECTOR_PER_VQ_AND_CONFIG)
- ret = ifcvf_request_per_vq_irq(adapter);
+ ret = ifcvf_request_per_vq_irq(vf);
else
- ret = ifcvf_request_vqs_reused_irq(adapter);
+ ret = ifcvf_request_vqs_reused_irq(vf);
return ret;
}
-static int ifcvf_request_config_irq(struct ifcvf_adapter *adapter)
+static int ifcvf_request_config_irq(struct ifcvf_hw *vf)
{
- struct pci_dev *pdev = adapter->pdev;
- struct ifcvf_hw *vf = &adapter->vf;
+ struct pci_dev *pdev = vf->pdev;
int config_vector, ret;
if (vf->msix_vector_status == MSIX_VECTOR_PER_VQ_AND_CONFIG)
@@ -320,17 +309,16 @@ static int ifcvf_request_config_irq(struct ifcvf_adapter *adapter)
return 0;
err:
- ifcvf_free_irq(adapter);
+ ifcvf_free_irq(vf);
return -EFAULT;
}
-static int ifcvf_request_irq(struct ifcvf_adapter *adapter)
+static int ifcvf_request_irq(struct ifcvf_hw *vf)
{
- struct ifcvf_hw *vf = &adapter->vf;
int nvectors, ret, max_intr;
- nvectors = ifcvf_alloc_vectors(adapter);
+ nvectors = ifcvf_alloc_vectors(vf);
if (nvectors <= 0)
return -EFAULT;
@@ -341,16 +329,16 @@ static int ifcvf_request_irq(struct ifcvf_adapter *adapter)
if (nvectors == 1) {
vf->msix_vector_status = MSIX_VECTOR_DEV_SHARED;
- ret = ifcvf_request_dev_irq(adapter);
+ ret = ifcvf_request_dev_irq(vf);
return ret;
}
- ret = ifcvf_request_vq_irq(adapter);
+ ret = ifcvf_request_vq_irq(vf);
if (ret)
return ret;
- ret = ifcvf_request_config_irq(adapter);
+ ret = ifcvf_request_config_irq(vf);
if (ret)
return ret;
@@ -358,9 +346,9 @@ static int ifcvf_request_irq(struct ifcvf_adapter *adapter)
return 0;
}
-static int ifcvf_start_datapath(void *private)
+static int ifcvf_start_datapath(struct ifcvf_adapter *adapter)
{
- struct ifcvf_hw *vf = ifcvf_private_to_vf(private);
+ struct ifcvf_hw *vf = adapter->vf;
u8 status;
int ret;
@@ -374,9 +362,9 @@ static int ifcvf_start_datapath(void *private)
return ret;
}
-static int ifcvf_stop_datapath(void *private)
+static int ifcvf_stop_datapath(struct ifcvf_adapter *adapter)
{
- struct ifcvf_hw *vf = ifcvf_private_to_vf(private);
+ struct ifcvf_hw *vf = adapter->vf;
int i;
for (i = 0; i < vf->nr_vring; i++)
@@ -389,7 +377,7 @@ static int ifcvf_stop_datapath(void *private)
static void ifcvf_reset_vring(struct ifcvf_adapter *adapter)
{
- struct ifcvf_hw *vf = ifcvf_private_to_vf(adapter);
+ struct ifcvf_hw *vf = adapter->vf;
int i;
for (i = 0; i < vf->nr_vring; i++) {
@@ -414,7 +402,7 @@ static struct ifcvf_hw *vdpa_to_vf(struct vdpa_device *vdpa_dev)
{
struct ifcvf_adapter *adapter = vdpa_to_adapter(vdpa_dev);
- return &adapter->vf;
+ return adapter->vf;
}
static u64 ifcvf_vdpa_get_device_features(struct vdpa_device *vdpa_dev)
@@ -479,7 +467,7 @@ static void ifcvf_vdpa_set_status(struct vdpa_device *vdpa_dev, u8 status)
if ((status & VIRTIO_CONFIG_S_DRIVER_OK) &&
!(status_old & VIRTIO_CONFIG_S_DRIVER_OK)) {
- ret = ifcvf_request_irq(adapter);
+ ret = ifcvf_request_irq(vf);
if (ret) {
status = ifcvf_get_status(vf);
status |= VIRTIO_CONFIG_S_FAILED;
@@ -511,7 +499,7 @@ static int ifcvf_vdpa_reset(struct vdpa_device *vdpa_dev)
if (status_old & VIRTIO_CONFIG_S_DRIVER_OK) {
ifcvf_stop_datapath(adapter);
- ifcvf_free_irq(adapter);
+ ifcvf_free_irq(vf);
}
ifcvf_reset_vring(adapter);
@@ -755,17 +743,37 @@ static int ifcvf_vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name,
struct vdpa_device *vdpa_dev;
struct pci_dev *pdev;
struct ifcvf_hw *vf;
+ u64 device_features;
int ret;
ifcvf_mgmt_dev = container_of(mdev, struct ifcvf_vdpa_mgmt_dev, mdev);
- if (!ifcvf_mgmt_dev->adapter)
- return -EOPNOTSUPP;
+ vf = &ifcvf_mgmt_dev->vf;
+ pdev = vf->pdev;
+ adapter = vdpa_alloc_device(struct ifcvf_adapter, vdpa,
+ &pdev->dev, &ifc_vdpa_ops, 1, 1, NULL, false);
+ if (IS_ERR(adapter)) {
+ IFCVF_ERR(pdev, "Failed to allocate vDPA structure");
+ return PTR_ERR(adapter);
+ }
- adapter = ifcvf_mgmt_dev->adapter;
- vf = &adapter->vf;
- pdev = adapter->pdev;
+ ifcvf_mgmt_dev->adapter = adapter;
+ adapter->pdev = pdev;
+ adapter->vdpa.dma_dev = &pdev->dev;
+ adapter->vdpa.mdev = mdev;
+ adapter->vf = vf;
vdpa_dev = &adapter->vdpa;
+ device_features = vf->hw_features;
+ if (config->mask & BIT_ULL(VDPA_ATTR_DEV_FEATURES)) {
+ if (config->device_features & ~device_features) {
+ IFCVF_ERR(pdev, "The provisioned features 0x%llx are not supported by this device with features 0x%llx\n",
+ config->device_features, device_features);
+ return -EINVAL;
+ }
+ device_features &= config->device_features;
+ }
+ vf->dev_features = device_features;
+
if (name)
ret = dev_set_name(&vdpa_dev->dev, "%s", name);
else
@@ -781,7 +789,6 @@ static int ifcvf_vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name,
return 0;
}
-
static void ifcvf_vdpa_dev_del(struct vdpa_mgmt_dev *mdev, struct vdpa_device *dev)
{
struct ifcvf_vdpa_mgmt_dev *ifcvf_mgmt_dev;
@@ -800,7 +807,6 @@ static int ifcvf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct ifcvf_vdpa_mgmt_dev *ifcvf_mgmt_dev;
struct device *dev = &pdev->dev;
- struct ifcvf_adapter *adapter;
struct ifcvf_hw *vf;
u32 dev_type;
int ret, i;
@@ -831,20 +837,16 @@ static int ifcvf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
}
pci_set_master(pdev);
-
- adapter = vdpa_alloc_device(struct ifcvf_adapter, vdpa,
- dev, &ifc_vdpa_ops, 1, 1, NULL, false);
- if (IS_ERR(adapter)) {
- IFCVF_ERR(pdev, "Failed to allocate vDPA structure");
- return PTR_ERR(adapter);
+ ifcvf_mgmt_dev = kzalloc(sizeof(struct ifcvf_vdpa_mgmt_dev), GFP_KERNEL);
+ if (!ifcvf_mgmt_dev) {
+ IFCVF_ERR(pdev, "Failed to alloc memory for the vDPA management device\n");
+ return -ENOMEM;
}
- vf = &adapter->vf;
+ vf = &ifcvf_mgmt_dev->vf;
vf->dev_type = get_dev_type(pdev);
vf->base = pcim_iomap_table(pdev);
-
- adapter->pdev = pdev;
- adapter->vdpa.dma_dev = &pdev->dev;
+ vf->pdev = pdev;
ret = ifcvf_init_hw(vf, pdev);
if (ret) {
@@ -858,16 +860,6 @@ static int ifcvf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
vf->hw_features = ifcvf_get_hw_features(vf);
vf->config_size = ifcvf_get_config_size(vf);
- ifcvf_mgmt_dev = kzalloc(sizeof(struct ifcvf_vdpa_mgmt_dev), GFP_KERNEL);
- if (!ifcvf_mgmt_dev) {
- IFCVF_ERR(pdev, "Failed to alloc memory for the vDPA management device\n");
- return -ENOMEM;
- }
-
- ifcvf_mgmt_dev->mdev.ops = &ifcvf_vdpa_mgmt_dev_ops;
- ifcvf_mgmt_dev->mdev.device = dev;
- ifcvf_mgmt_dev->adapter = adapter;
-
dev_type = get_dev_type(pdev);
switch (dev_type) {
case VIRTIO_ID_NET:
@@ -882,11 +874,11 @@ static int ifcvf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto err;
}
+ ifcvf_mgmt_dev->mdev.ops = &ifcvf_vdpa_mgmt_dev_ops;
+ ifcvf_mgmt_dev->mdev.device = dev;
ifcvf_mgmt_dev->mdev.max_supported_vqs = vf->nr_vring;
ifcvf_mgmt_dev->mdev.supported_features = vf->hw_features;
-
- adapter->vdpa.mdev = &ifcvf_mgmt_dev->mdev;
-
+ ifcvf_mgmt_dev->mdev.config_attr_mask = (1 << VDPA_ATTR_DEV_FEATURES);
ret = vdpa_mgmtdev_register(&ifcvf_mgmt_dev->mdev);
if (ret) {
diff --git a/drivers/vdpa/mlx5/Makefile b/drivers/vdpa/mlx5/Makefile
index f717978c83bf..e791394c33e3 100644
--- a/drivers/vdpa/mlx5/Makefile
+++ b/drivers/vdpa/mlx5/Makefile
@@ -1,4 +1,4 @@
subdir-ccflags-y += -I$(srctree)/drivers/vdpa/mlx5/core
obj-$(CONFIG_MLX5_VDPA_NET) += mlx5_vdpa.o
-mlx5_vdpa-$(CONFIG_MLX5_VDPA_NET) += net/mlx5_vnet.o core/resources.o core/mr.o
+mlx5_vdpa-$(CONFIG_MLX5_VDPA_NET) += net/mlx5_vnet.o core/resources.o core/mr.o net/debug.o
diff --git a/drivers/vdpa/mlx5/core/mr.c b/drivers/vdpa/mlx5/core/mr.c
index 0a1e0b0dc37e..03e543229791 100644
--- a/drivers/vdpa/mlx5/core/mr.c
+++ b/drivers/vdpa/mlx5/core/mr.c
@@ -503,7 +503,6 @@ void mlx5_vdpa_destroy_mr(struct mlx5_vdpa_dev *mvdev)
else
destroy_dma_mr(mvdev, mr);
- memset(mr, 0, sizeof(*mr));
mr->initialized = false;
out:
mutex_unlock(&mr->mkey_mtx);
diff --git a/drivers/vdpa/mlx5/core/resources.c b/drivers/vdpa/mlx5/core/resources.c
index 9800f9bec225..d5a59c9035fb 100644
--- a/drivers/vdpa/mlx5/core/resources.c
+++ b/drivers/vdpa/mlx5/core/resources.c
@@ -213,7 +213,7 @@ int mlx5_vdpa_create_mkey(struct mlx5_vdpa_dev *mvdev, u32 *mkey, u32 *in,
return err;
mkey_index = MLX5_GET(create_mkey_out, lout, mkey_index);
- *mkey |= mlx5_idx_to_mkey(mkey_index);
+ *mkey = mlx5_idx_to_mkey(mkey_index);
return 0;
}
@@ -233,6 +233,7 @@ static int init_ctrl_vq(struct mlx5_vdpa_dev *mvdev)
if (!mvdev->cvq.iotlb)
return -ENOMEM;
+ spin_lock_init(&mvdev->cvq.iommu_lock);
vringh_set_iotlb(&mvdev->cvq.vring, mvdev->cvq.iotlb, &mvdev->cvq.iommu_lock);
return 0;
diff --git a/drivers/vdpa/mlx5/net/debug.c b/drivers/vdpa/mlx5/net/debug.c
new file mode 100644
index 000000000000..60d6ac68cdc4
--- /dev/null
+++ b/drivers/vdpa/mlx5/net/debug.c
@@ -0,0 +1,152 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
+
+#include <linux/debugfs.h>
+#include <linux/mlx5/fs.h>
+#include "mlx5_vnet.h"
+
+static int tirn_show(struct seq_file *file, void *priv)
+{
+ struct mlx5_vdpa_net *ndev = file->private;
+
+ seq_printf(file, "0x%x\n", ndev->res.tirn);
+ return 0;
+}
+
+DEFINE_SHOW_ATTRIBUTE(tirn);
+
+void mlx5_vdpa_remove_tirn(struct mlx5_vdpa_net *ndev)
+{
+ if (ndev->debugfs)
+ debugfs_remove(ndev->res.tirn_dent);
+}
+
+void mlx5_vdpa_add_tirn(struct mlx5_vdpa_net *ndev)
+{
+ ndev->res.tirn_dent = debugfs_create_file("tirn", 0444, ndev->rx_dent,
+ ndev, &tirn_fops);
+}
+
+static int rx_flow_table_show(struct seq_file *file, void *priv)
+{
+ struct mlx5_vdpa_net *ndev = file->private;
+
+ seq_printf(file, "0x%x\n", mlx5_flow_table_id(ndev->rxft));
+ return 0;
+}
+
+DEFINE_SHOW_ATTRIBUTE(rx_flow_table);
+
+void mlx5_vdpa_remove_rx_flow_table(struct mlx5_vdpa_net *ndev)
+{
+ if (ndev->debugfs)
+ debugfs_remove(ndev->rx_table_dent);
+}
+
+void mlx5_vdpa_add_rx_flow_table(struct mlx5_vdpa_net *ndev)
+{
+ ndev->rx_table_dent = debugfs_create_file("table_id", 0444, ndev->rx_dent,
+ ndev, &rx_flow_table_fops);
+}
+
+#if defined(CONFIG_MLX5_VDPA_STEERING_DEBUG)
+static int packets_show(struct seq_file *file, void *priv)
+{
+ struct mlx5_vdpa_counter *counter = file->private;
+ u64 packets;
+ u64 bytes;
+ int err;
+
+ err = mlx5_fc_query(counter->mdev, counter->counter, &packets, &bytes);
+ if (err)
+ return err;
+
+ seq_printf(file, "0x%llx\n", packets);
+ return 0;
+}
+
+static int bytes_show(struct seq_file *file, void *priv)
+{
+ struct mlx5_vdpa_counter *counter = file->private;
+ u64 packets;
+ u64 bytes;
+ int err;
+
+ err = mlx5_fc_query(counter->mdev, counter->counter, &packets, &bytes);
+ if (err)
+ return err;
+
+ seq_printf(file, "0x%llx\n", bytes);
+ return 0;
+}
+
+DEFINE_SHOW_ATTRIBUTE(packets);
+DEFINE_SHOW_ATTRIBUTE(bytes);
+
+static void add_counter_node(struct mlx5_vdpa_counter *counter,
+ struct dentry *parent)
+{
+ debugfs_create_file("packets", 0444, parent, counter,
+ &packets_fops);
+ debugfs_create_file("bytes", 0444, parent, counter,
+ &bytes_fops);
+}
+
+void mlx5_vdpa_add_rx_counters(struct mlx5_vdpa_net *ndev,
+ struct macvlan_node *node)
+{
+ static const char *ut = "untagged";
+ char vidstr[9];
+ u16 vid;
+
+ node->ucast_counter.mdev = ndev->mvdev.mdev;
+ node->mcast_counter.mdev = ndev->mvdev.mdev;
+ if (node->tagged) {
+ vid = key2vid(node->macvlan);
+ snprintf(vidstr, sizeof(vidstr), "0x%x", vid);
+ } else {
+ strcpy(vidstr, ut);
+ }
+
+ node->dent = debugfs_create_dir(vidstr, ndev->rx_dent);
+ if (IS_ERR(node->dent)) {
+ node->dent = NULL;
+ return;
+ }
+
+ node->ucast_counter.dent = debugfs_create_dir("ucast", node->dent);
+ if (IS_ERR(node->ucast_counter.dent))
+ return;
+
+ add_counter_node(&node->ucast_counter, node->ucast_counter.dent);
+
+ node->mcast_counter.dent = debugfs_create_dir("mcast", node->dent);
+ if (IS_ERR(node->mcast_counter.dent))
+ return;
+
+ add_counter_node(&node->mcast_counter, node->mcast_counter.dent);
+}
+
+void mlx5_vdpa_remove_rx_counters(struct mlx5_vdpa_net *ndev,
+ struct macvlan_node *node)
+{
+ if (node->dent && ndev->debugfs)
+ debugfs_remove_recursive(node->dent);
+}
+#endif
+
+void mlx5_vdpa_add_debugfs(struct mlx5_vdpa_net *ndev)
+{
+ struct mlx5_core_dev *mdev;
+
+ mdev = ndev->mvdev.mdev;
+ ndev->debugfs = debugfs_create_dir(dev_name(&ndev->mvdev.vdev.dev),
+ mlx5_debugfs_get_dev_root(mdev));
+ if (!IS_ERR(ndev->debugfs))
+ ndev->rx_dent = debugfs_create_dir("rx", ndev->debugfs);
+}
+
+void mlx5_vdpa_remove_debugfs(struct dentry *dbg)
+{
+ debugfs_remove_recursive(dbg);
+}
diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c
index 3a6dbbc6440d..3a0e721aef05 100644
--- a/drivers/vdpa/mlx5/net/mlx5_vnet.c
+++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c
@@ -18,15 +18,12 @@
#include <linux/mlx5/mlx5_ifc_vdpa.h>
#include <linux/mlx5/mpfs.h>
#include "mlx5_vdpa.h"
+#include "mlx5_vnet.h"
MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>");
MODULE_DESCRIPTION("Mellanox VDPA driver");
MODULE_LICENSE("Dual BSD/GPL");
-#define to_mlx5_vdpa_ndev(__mvdev) \
- container_of(__mvdev, struct mlx5_vdpa_net, mvdev)
-#define to_mvdev(__vdev) container_of((__vdev), struct mlx5_vdpa_dev, vdev)
-
#define VALID_FEATURES_MASK \
(BIT_ULL(VIRTIO_NET_F_CSUM) | BIT_ULL(VIRTIO_NET_F_GUEST_CSUM) | \
BIT_ULL(VIRTIO_NET_F_CTRL_GUEST_OFFLOADS) | BIT_ULL(VIRTIO_NET_F_MTU) | BIT_ULL(VIRTIO_NET_F_MAC) | \
@@ -50,14 +47,6 @@ MODULE_LICENSE("Dual BSD/GPL");
#define MLX5V_UNTAGGED 0x1000
-struct mlx5_vdpa_net_resources {
- u32 tisn;
- u32 tdn;
- u32 tirn;
- u32 rqtn;
- bool valid;
-};
-
struct mlx5_vdpa_cq_buf {
struct mlx5_frag_buf_ctrl fbc;
struct mlx5_frag_buf frag_buf;
@@ -146,38 +135,6 @@ static bool is_index_valid(struct mlx5_vdpa_dev *mvdev, u16 idx)
return idx <= mvdev->max_idx;
}
-#define MLX5V_MACVLAN_SIZE 256
-
-struct mlx5_vdpa_net {
- struct mlx5_vdpa_dev mvdev;
- struct mlx5_vdpa_net_resources res;
- struct virtio_net_config config;
- struct mlx5_vdpa_virtqueue *vqs;
- struct vdpa_callback *event_cbs;
-
- /* Serialize vq resources creation and destruction. This is required
- * since memory map might change and we need to destroy and create
- * resources while driver in operational.
- */
- struct rw_semaphore reslock;
- struct mlx5_flow_table *rxft;
- bool setup;
- u32 cur_num_vqs;
- u32 rqt_size;
- bool nb_registered;
- struct notifier_block nb;
- struct vdpa_callback config_cb;
- struct mlx5_vdpa_wq_ent cvq_ent;
- struct hlist_head macvlan_hash[MLX5V_MACVLAN_SIZE];
-};
-
-struct macvlan_node {
- struct hlist_node hlist;
- struct mlx5_flow_handle *ucast_rule;
- struct mlx5_flow_handle *mcast_rule;
- u64 macvlan;
-};
-
static void free_resources(struct mlx5_vdpa_net *ndev);
static void init_mvqs(struct mlx5_vdpa_net *ndev);
static int setup_driver(struct mlx5_vdpa_dev *mvdev);
@@ -1431,36 +1388,85 @@ static int create_tir(struct mlx5_vdpa_net *ndev)
err = mlx5_vdpa_create_tir(&ndev->mvdev, in, &ndev->res.tirn);
kfree(in);
+ if (err)
+ return err;
+
+ mlx5_vdpa_add_tirn(ndev);
return err;
}
static void destroy_tir(struct mlx5_vdpa_net *ndev)
{
+ mlx5_vdpa_remove_tirn(ndev);
mlx5_vdpa_destroy_tir(&ndev->mvdev, ndev->res.tirn);
}
#define MAX_STEERING_ENT 0x8000
#define MAX_STEERING_GROUPS 2
+#if defined(CONFIG_MLX5_VDPA_STEERING_DEBUG)
+ #define NUM_DESTS 2
+#else
+ #define NUM_DESTS 1
+#endif
+
+static int add_steering_counters(struct mlx5_vdpa_net *ndev,
+ struct macvlan_node *node,
+ struct mlx5_flow_act *flow_act,
+ struct mlx5_flow_destination *dests)
+{
+#if defined(CONFIG_MLX5_VDPA_STEERING_DEBUG)
+ int err;
+
+ node->ucast_counter.counter = mlx5_fc_create(ndev->mvdev.mdev, false);
+ if (IS_ERR(node->ucast_counter.counter))
+ return PTR_ERR(node->ucast_counter.counter);
+
+ node->mcast_counter.counter = mlx5_fc_create(ndev->mvdev.mdev, false);
+ if (IS_ERR(node->mcast_counter.counter)) {
+ err = PTR_ERR(node->mcast_counter.counter);
+ goto err_mcast_counter;
+ }
+
+ dests[1].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
+ flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_COUNT;
+ return 0;
+
+err_mcast_counter:
+ mlx5_fc_destroy(ndev->mvdev.mdev, node->ucast_counter.counter);
+ return err;
+#else
+ return 0;
+#endif
+}
+
+static void remove_steering_counters(struct mlx5_vdpa_net *ndev,
+ struct macvlan_node *node)
+{
+#if defined(CONFIG_MLX5_VDPA_STEERING_DEBUG)
+ mlx5_fc_destroy(ndev->mvdev.mdev, node->mcast_counter.counter);
+ mlx5_fc_destroy(ndev->mvdev.mdev, node->ucast_counter.counter);
+#endif
+}
+
static int mlx5_vdpa_add_mac_vlan_rules(struct mlx5_vdpa_net *ndev, u8 *mac,
- u16 vid, bool tagged,
- struct mlx5_flow_handle **ucast,
- struct mlx5_flow_handle **mcast)
+ struct macvlan_node *node)
{
- struct mlx5_flow_destination dest = {};
+ struct mlx5_flow_destination dests[NUM_DESTS] = {};
struct mlx5_flow_act flow_act = {};
- struct mlx5_flow_handle *rule;
struct mlx5_flow_spec *spec;
void *headers_c;
void *headers_v;
u8 *dmac_c;
u8 *dmac_v;
int err;
+ u16 vid;
spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
if (!spec)
return -ENOMEM;
+ vid = key2vid(node->macvlan);
spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, outer_headers);
headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, outer_headers);
@@ -1472,44 +1478,58 @@ static int mlx5_vdpa_add_mac_vlan_rules(struct mlx5_vdpa_net *ndev, u8 *mac,
MLX5_SET(fte_match_set_lyr_2_4, headers_c, cvlan_tag, 1);
MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, first_vid);
}
- if (tagged) {
+ if (node->tagged) {
MLX5_SET(fte_match_set_lyr_2_4, headers_v, cvlan_tag, 1);
MLX5_SET(fte_match_set_lyr_2_4, headers_v, first_vid, vid);
}
flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
- dest.type = MLX5_FLOW_DESTINATION_TYPE_TIR;
- dest.tir_num = ndev->res.tirn;
- rule = mlx5_add_flow_rules(ndev->rxft, spec, &flow_act, &dest, 1);
- if (IS_ERR(rule))
- return PTR_ERR(rule);
+ dests[0].type = MLX5_FLOW_DESTINATION_TYPE_TIR;
+ dests[0].tir_num = ndev->res.tirn;
+ err = add_steering_counters(ndev, node, &flow_act, dests);
+ if (err)
+ goto out_free;
+
+#if defined(CONFIG_MLX5_VDPA_STEERING_DEBUG)
+ dests[1].counter_id = mlx5_fc_id(node->ucast_counter.counter);
+#endif
+ node->ucast_rule = mlx5_add_flow_rules(ndev->rxft, spec, &flow_act, dests, NUM_DESTS);
+ if (IS_ERR(node->ucast_rule)) {
+ err = PTR_ERR(node->ucast_rule);
+ goto err_ucast;
+ }
- *ucast = rule;
+#if defined(CONFIG_MLX5_VDPA_STEERING_DEBUG)
+ dests[1].counter_id = mlx5_fc_id(node->mcast_counter.counter);
+#endif
memset(dmac_c, 0, ETH_ALEN);
memset(dmac_v, 0, ETH_ALEN);
dmac_c[0] = 1;
dmac_v[0] = 1;
- rule = mlx5_add_flow_rules(ndev->rxft, spec, &flow_act, &dest, 1);
- kvfree(spec);
- if (IS_ERR(rule)) {
- err = PTR_ERR(rule);
+ node->mcast_rule = mlx5_add_flow_rules(ndev->rxft, spec, &flow_act, dests, NUM_DESTS);
+ if (IS_ERR(node->mcast_rule)) {
+ err = PTR_ERR(node->mcast_rule);
goto err_mcast;
}
-
- *mcast = rule;
+ kvfree(spec);
+ mlx5_vdpa_add_rx_counters(ndev, node);
return 0;
err_mcast:
- mlx5_del_flow_rules(*ucast);
+ mlx5_del_flow_rules(node->ucast_rule);
+err_ucast:
+ remove_steering_counters(ndev, node);
+out_free:
+ kvfree(spec);
return err;
}
static void mlx5_vdpa_del_mac_vlan_rules(struct mlx5_vdpa_net *ndev,
- struct mlx5_flow_handle *ucast,
- struct mlx5_flow_handle *mcast)
+ struct macvlan_node *node)
{
- mlx5_del_flow_rules(ucast);
- mlx5_del_flow_rules(mcast);
+ mlx5_vdpa_remove_rx_counters(ndev, node);
+ mlx5_del_flow_rules(node->ucast_rule);
+ mlx5_del_flow_rules(node->mcast_rule);
}
static u64 search_val(u8 *mac, u16 vlan, bool tagged)
@@ -1543,14 +1563,14 @@ static struct macvlan_node *mac_vlan_lookup(struct mlx5_vdpa_net *ndev, u64 valu
return NULL;
}
-static int mac_vlan_add(struct mlx5_vdpa_net *ndev, u8 *mac, u16 vlan, bool tagged) // vlan -> vid
+static int mac_vlan_add(struct mlx5_vdpa_net *ndev, u8 *mac, u16 vid, bool tagged)
{
struct macvlan_node *ptr;
u64 val;
u32 idx;
int err;
- val = search_val(mac, vlan, tagged);
+ val = search_val(mac, vid, tagged);
if (mac_vlan_lookup(ndev, val))
return -EEXIST;
@@ -1558,12 +1578,13 @@ static int mac_vlan_add(struct mlx5_vdpa_net *ndev, u8 *mac, u16 vlan, bool tagg
if (!ptr)
return -ENOMEM;
- err = mlx5_vdpa_add_mac_vlan_rules(ndev, ndev->config.mac, vlan, tagged,
- &ptr->ucast_rule, &ptr->mcast_rule);
+ ptr->tagged = tagged;
+ ptr->macvlan = val;
+ ptr->ndev = ndev;
+ err = mlx5_vdpa_add_mac_vlan_rules(ndev, ndev->config.mac, ptr);
if (err)
goto err_add;
- ptr->macvlan = val;
idx = hash_64(val, 8);
hlist_add_head(&ptr->hlist, &ndev->macvlan_hash[idx]);
return 0;
@@ -1582,7 +1603,8 @@ static void mac_vlan_del(struct mlx5_vdpa_net *ndev, u8 *mac, u16 vlan, bool tag
return;
hlist_del(&ptr->hlist);
- mlx5_vdpa_del_mac_vlan_rules(ndev, ptr->ucast_rule, ptr->mcast_rule);
+ mlx5_vdpa_del_mac_vlan_rules(ndev, ptr);
+ remove_steering_counters(ndev, ptr);
kfree(ptr);
}
@@ -1595,7 +1617,8 @@ static void clear_mac_vlan_table(struct mlx5_vdpa_net *ndev)
for (i = 0; i < MLX5V_MACVLAN_SIZE; i++) {
hlist_for_each_entry_safe(pos, n, &ndev->macvlan_hash[i], hlist) {
hlist_del(&pos->hlist);
- mlx5_vdpa_del_mac_vlan_rules(ndev, pos->ucast_rule, pos->mcast_rule);
+ mlx5_vdpa_del_mac_vlan_rules(ndev, pos);
+ remove_steering_counters(ndev, pos);
kfree(pos);
}
}
@@ -1621,6 +1644,7 @@ static int setup_steering(struct mlx5_vdpa_net *ndev)
mlx5_vdpa_warn(&ndev->mvdev, "failed to create flow table\n");
return PTR_ERR(ndev->rxft);
}
+ mlx5_vdpa_add_rx_flow_table(ndev);
err = mac_vlan_add(ndev, ndev->config.mac, 0, false);
if (err)
@@ -1629,6 +1653,7 @@ static int setup_steering(struct mlx5_vdpa_net *ndev)
return 0;
err_add:
+ mlx5_vdpa_remove_rx_flow_table(ndev);
mlx5_destroy_flow_table(ndev->rxft);
return err;
}
@@ -1636,6 +1661,7 @@ err_add:
static void teardown_steering(struct mlx5_vdpa_net *ndev)
{
clear_mac_vlan_table(ndev);
+ mlx5_vdpa_remove_rx_flow_table(ndev);
mlx5_destroy_flow_table(ndev->rxft);
}
@@ -2183,6 +2209,7 @@ static u64 get_supported_features(struct mlx5_core_dev *mdev)
mlx_vdpa_features |= BIT_ULL(VIRTIO_NET_F_STATUS);
mlx_vdpa_features |= BIT_ULL(VIRTIO_NET_F_MTU);
mlx_vdpa_features |= BIT_ULL(VIRTIO_NET_F_CTRL_VLAN);
+ mlx_vdpa_features |= BIT_ULL(VIRTIO_NET_F_MAC);
return mlx_vdpa_features;
}
@@ -2655,6 +2682,16 @@ static int mlx5_vdpa_set_map(struct vdpa_device *vdev, unsigned int asid,
return err;
}
+static struct device *mlx5_get_vq_dma_dev(struct vdpa_device *vdev, u16 idx)
+{
+ struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev);
+
+ if (is_ctrl_vq_idx(mvdev, idx))
+ return &vdev->dev;
+
+ return mvdev->vdev.dma_dev;
+}
+
static void mlx5_vdpa_free(struct vdpa_device *vdev)
{
struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev);
@@ -2870,6 +2907,7 @@ static const struct vdpa_config_ops mlx5_vdpa_ops = {
.get_generation = mlx5_vdpa_get_generation,
.set_map = mlx5_vdpa_set_map,
.set_group_asid = mlx5_set_group_asid,
+ .get_vq_dma_dev = mlx5_get_vq_dma_dev,
.free = mlx5_vdpa_free,
.suspend = mlx5_vdpa_suspend,
};
@@ -3009,6 +3047,8 @@ static int event_handler(struct notifier_block *nb, unsigned long event, void *p
struct mlx5_vdpa_wq_ent *wqent;
if (event == MLX5_EVENT_TYPE_PORT_CHANGE) {
+ if (!(ndev->mvdev.actual_features & BIT_ULL(VIRTIO_NET_F_STATUS)))
+ return NOTIFY_DONE;
switch (eqe->sub_type) {
case MLX5_PORT_CHANGE_SUBTYPE_DOWN:
case MLX5_PORT_CHANGE_SUBTYPE_ACTIVE:
@@ -3060,6 +3100,7 @@ static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name,
struct mlx5_vdpa_dev *mvdev;
struct mlx5_vdpa_net *ndev;
struct mlx5_core_dev *mdev;
+ u64 device_features;
u32 max_vqs;
u16 mtu;
int err;
@@ -3068,6 +3109,24 @@ static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name,
return -ENOSPC;
mdev = mgtdev->madev->mdev;
+ device_features = mgtdev->mgtdev.supported_features;
+ if (add_config->mask & BIT_ULL(VDPA_ATTR_DEV_FEATURES)) {
+ if (add_config->device_features & ~device_features) {
+ dev_warn(mdev->device,
+ "The provisioned features 0x%llx are not supported by this device with features 0x%llx\n",
+ add_config->device_features, device_features);
+ return -EINVAL;
+ }
+ device_features &= add_config->device_features;
+ }
+ if (!(device_features & BIT_ULL(VIRTIO_F_VERSION_1) &&
+ device_features & BIT_ULL(VIRTIO_F_ACCESS_PLATFORM))) {
+ dev_warn(mdev->device,
+ "Must provision minimum features 0x%llx for this device",
+ BIT_ULL(VIRTIO_F_VERSION_1) | BIT_ULL(VIRTIO_F_ACCESS_PLATFORM));
+ return -EOPNOTSUPP;
+ }
+
if (!(MLX5_CAP_DEV_VDPA_EMULATION(mdev, virtio_queue_type) &
MLX5_VIRTIO_EMULATION_CAP_VIRTIO_QUEUE_TYPE_SPLIT)) {
dev_warn(mdev->device, "missing support for split virtqueues\n");
@@ -3096,7 +3155,6 @@ static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name,
if (IS_ERR(ndev))
return PTR_ERR(ndev);
- ndev->mvdev.mlx_features = mgtdev->mgtdev.supported_features;
ndev->mvdev.max_vqs = max_vqs;
mvdev = &ndev->mvdev;
mvdev->mdev = mdev;
@@ -3118,20 +3176,26 @@ static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name,
goto err_alloc;
}
- err = query_mtu(mdev, &mtu);
- if (err)
- goto err_alloc;
+ if (device_features & BIT_ULL(VIRTIO_NET_F_MTU)) {
+ err = query_mtu(mdev, &mtu);
+ if (err)
+ goto err_alloc;
- ndev->config.mtu = cpu_to_mlx5vdpa16(mvdev, mtu);
+ ndev->config.mtu = cpu_to_mlx5vdpa16(mvdev, mtu);
+ }
- if (get_link_state(mvdev))
- ndev->config.status |= cpu_to_mlx5vdpa16(mvdev, VIRTIO_NET_S_LINK_UP);
- else
- ndev->config.status &= cpu_to_mlx5vdpa16(mvdev, ~VIRTIO_NET_S_LINK_UP);
+ if (device_features & BIT_ULL(VIRTIO_NET_F_STATUS)) {
+ if (get_link_state(mvdev))
+ ndev->config.status |= cpu_to_mlx5vdpa16(mvdev, VIRTIO_NET_S_LINK_UP);
+ else
+ ndev->config.status &= cpu_to_mlx5vdpa16(mvdev, ~VIRTIO_NET_S_LINK_UP);
+ }
if (add_config->mask & (1 << VDPA_ATTR_DEV_NET_CFG_MACADDR)) {
memcpy(ndev->config.mac, add_config->net.mac, ETH_ALEN);
- } else {
+ /* No bother setting mac address in config if not going to provision _F_MAC */
+ } else if ((add_config->mask & BIT_ULL(VDPA_ATTR_DEV_FEATURES)) == 0 ||
+ device_features & BIT_ULL(VIRTIO_NET_F_MAC)) {
err = mlx5_query_nic_vport_mac_address(mdev, 0, 0, config->mac);
if (err)
goto err_alloc;
@@ -3142,11 +3206,26 @@ static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name,
err = mlx5_mpfs_add_mac(pfmdev, config->mac);
if (err)
goto err_alloc;
-
- ndev->mvdev.mlx_features |= BIT_ULL(VIRTIO_NET_F_MAC);
+ } else if ((add_config->mask & BIT_ULL(VDPA_ATTR_DEV_FEATURES)) == 0) {
+ /*
+ * We used to clear _F_MAC feature bit if seeing
+ * zero mac address when device features are not
+ * specifically provisioned. Keep the behaviour
+ * so old scripts do not break.
+ */
+ device_features &= ~BIT_ULL(VIRTIO_NET_F_MAC);
+ } else if (device_features & BIT_ULL(VIRTIO_NET_F_MAC)) {
+ /* Don't provision zero mac address for _F_MAC */
+ mlx5_vdpa_warn(&ndev->mvdev,
+ "No mac address provisioned?\n");
+ err = -EINVAL;
+ goto err_alloc;
}
- config->max_virtqueue_pairs = cpu_to_mlx5vdpa16(mvdev, max_vqs / 2);
+ if (device_features & BIT_ULL(VIRTIO_NET_F_MQ))
+ config->max_virtqueue_pairs = cpu_to_mlx5vdpa16(mvdev, max_vqs / 2);
+
+ ndev->mvdev.mlx_features = device_features;
mvdev->vdev.dma_dev = &mdev->pdev->dev;
err = mlx5_vdpa_alloc_resources(&ndev->mvdev);
if (err)
@@ -3178,6 +3257,7 @@ static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name,
if (err)
goto err_reg;
+ mlx5_vdpa_add_debugfs(ndev);
mgtdev->ndev = ndev;
return 0;
@@ -3204,6 +3284,8 @@ static void mlx5_vdpa_dev_del(struct vdpa_mgmt_dev *v_mdev, struct vdpa_device *
struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev);
struct workqueue_struct *wq;
+ mlx5_vdpa_remove_debugfs(ndev->debugfs);
+ ndev->debugfs = NULL;
if (ndev->nb_registered) {
ndev->nb_registered = false;
mlx5_notifier_unregister(mvdev->mdev, &ndev->nb);
@@ -3243,7 +3325,8 @@ static int mlx5v_probe(struct auxiliary_device *adev,
mgtdev->mgtdev.id_table = id_table;
mgtdev->mgtdev.config_attr_mask = BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MACADDR) |
BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MAX_VQP) |
- BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MTU);
+ BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MTU) |
+ BIT_ULL(VDPA_ATTR_DEV_FEATURES);
mgtdev->mgtdev.max_supported_vqs =
MLX5_CAP_DEV_VDPA_EMULATION(mdev, max_num_virtio_queues) + 1;
mgtdev->mgtdev.supported_features = get_supported_features(mdev);
diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.h b/drivers/vdpa/mlx5/net/mlx5_vnet.h
new file mode 100644
index 000000000000..c90a89e1de4d
--- /dev/null
+++ b/drivers/vdpa/mlx5/net/mlx5_vnet.h
@@ -0,0 +1,94 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
+/* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
+
+#ifndef __MLX5_VNET_H__
+#define __MLX5_VNET_H__
+
+#include "mlx5_vdpa.h"
+
+#define to_mlx5_vdpa_ndev(__mvdev) \
+ container_of(__mvdev, struct mlx5_vdpa_net, mvdev)
+#define to_mvdev(__vdev) container_of((__vdev), struct mlx5_vdpa_dev, vdev)
+
+struct mlx5_vdpa_net_resources {
+ u32 tisn;
+ u32 tdn;
+ u32 tirn;
+ u32 rqtn;
+ bool valid;
+ struct dentry *tirn_dent;
+};
+
+#define MLX5V_MACVLAN_SIZE 256
+
+static inline u16 key2vid(u64 key)
+{
+ return (u16)(key >> 48) & 0xfff;
+}
+
+struct mlx5_vdpa_net {
+ struct mlx5_vdpa_dev mvdev;
+ struct mlx5_vdpa_net_resources res;
+ struct virtio_net_config config;
+ struct mlx5_vdpa_virtqueue *vqs;
+ struct vdpa_callback *event_cbs;
+
+ /* Serialize vq resources creation and destruction. This is required
+ * since memory map might change and we need to destroy and create
+ * resources while driver in operational.
+ */
+ struct rw_semaphore reslock;
+ struct mlx5_flow_table *rxft;
+ struct dentry *rx_dent;
+ struct dentry *rx_table_dent;
+ bool setup;
+ u32 cur_num_vqs;
+ u32 rqt_size;
+ bool nb_registered;
+ struct notifier_block nb;
+ struct vdpa_callback config_cb;
+ struct mlx5_vdpa_wq_ent cvq_ent;
+ struct hlist_head macvlan_hash[MLX5V_MACVLAN_SIZE];
+ struct dentry *debugfs;
+};
+
+struct mlx5_vdpa_counter {
+ struct mlx5_fc *counter;
+ struct dentry *dent;
+ struct mlx5_core_dev *mdev;
+};
+
+struct macvlan_node {
+ struct hlist_node hlist;
+ struct mlx5_flow_handle *ucast_rule;
+ struct mlx5_flow_handle *mcast_rule;
+ u64 macvlan;
+ struct mlx5_vdpa_net *ndev;
+ bool tagged;
+#if defined(CONFIG_MLX5_VDPA_STEERING_DEBUG)
+ struct dentry *dent;
+ struct mlx5_vdpa_counter ucast_counter;
+ struct mlx5_vdpa_counter mcast_counter;
+#endif
+};
+
+void mlx5_vdpa_add_debugfs(struct mlx5_vdpa_net *ndev);
+void mlx5_vdpa_remove_debugfs(struct dentry *dbg);
+void mlx5_vdpa_add_rx_flow_table(struct mlx5_vdpa_net *ndev);
+void mlx5_vdpa_remove_rx_flow_table(struct mlx5_vdpa_net *ndev);
+void mlx5_vdpa_add_tirn(struct mlx5_vdpa_net *ndev);
+void mlx5_vdpa_remove_tirn(struct mlx5_vdpa_net *ndev);
+#if defined(CONFIG_MLX5_VDPA_STEERING_DEBUG)
+void mlx5_vdpa_add_rx_counters(struct mlx5_vdpa_net *ndev,
+ struct macvlan_node *node);
+void mlx5_vdpa_remove_rx_counters(struct mlx5_vdpa_net *ndev,
+ struct macvlan_node *node);
+#else
+static inline void mlx5_vdpa_add_rx_counters(struct mlx5_vdpa_net *ndev,
+ struct macvlan_node *node) {}
+static inline void mlx5_vdpa_remove_rx_counters(struct mlx5_vdpa_net *ndev,
+ struct macvlan_node *node) {}
+#endif
+
+
+#endif /* __MLX5_VNET_H__ */
diff --git a/drivers/vdpa/solidrun/Makefile b/drivers/vdpa/solidrun/Makefile
new file mode 100644
index 000000000000..c0aa3415bf7b
--- /dev/null
+++ b/drivers/vdpa/solidrun/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_SNET_VDPA) += snet_vdpa.o
+snet_vdpa-$(CONFIG_SNET_VDPA) += snet_main.o
+ifdef CONFIG_HWMON
+snet_vdpa-$(CONFIG_SNET_VDPA) += snet_hwmon.o
+endif
diff --git a/drivers/vdpa/solidrun/snet_hwmon.c b/drivers/vdpa/solidrun/snet_hwmon.c
new file mode 100644
index 000000000000..e695e36ff753
--- /dev/null
+++ b/drivers/vdpa/solidrun/snet_hwmon.c
@@ -0,0 +1,188 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * SolidRun DPU driver for control plane
+ *
+ * Copyright (C) 2022 SolidRun
+ *
+ * Author: Alvaro Karsz <alvaro.karsz@solid-run.com>
+ *
+ */
+#include <linux/hwmon.h>
+
+#include "snet_vdpa.h"
+
+/* Monitor offsets */
+#define SNET_MON_TMP0_IN_OFF 0x00
+#define SNET_MON_TMP0_MAX_OFF 0x08
+#define SNET_MON_TMP0_CRIT_OFF 0x10
+#define SNET_MON_TMP1_IN_OFF 0x18
+#define SNET_MON_TMP1_CRIT_OFF 0x20
+#define SNET_MON_CURR_IN_OFF 0x28
+#define SNET_MON_CURR_MAX_OFF 0x30
+#define SNET_MON_CURR_CRIT_OFF 0x38
+#define SNET_MON_PWR_IN_OFF 0x40
+#define SNET_MON_VOLT_IN_OFF 0x48
+#define SNET_MON_VOLT_CRIT_OFF 0x50
+#define SNET_MON_VOLT_LCRIT_OFF 0x58
+
+static void snet_hwmon_read_reg(struct psnet *psnet, u32 reg, long *out)
+{
+ *out = psnet_read64(psnet, psnet->cfg.hwmon_off + reg);
+}
+
+static umode_t snet_howmon_is_visible(const void *data,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ return 0444;
+}
+
+static int snet_howmon_read(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ struct psnet *psnet = dev_get_drvdata(dev);
+ int ret = 0;
+
+ switch (type) {
+ case hwmon_in:
+ switch (attr) {
+ case hwmon_in_lcrit:
+ snet_hwmon_read_reg(psnet, SNET_MON_VOLT_LCRIT_OFF, val);
+ break;
+ case hwmon_in_crit:
+ snet_hwmon_read_reg(psnet, SNET_MON_VOLT_CRIT_OFF, val);
+ break;
+ case hwmon_in_input:
+ snet_hwmon_read_reg(psnet, SNET_MON_VOLT_IN_OFF, val);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ break;
+
+ case hwmon_power:
+ switch (attr) {
+ case hwmon_power_input:
+ snet_hwmon_read_reg(psnet, SNET_MON_PWR_IN_OFF, val);
+ break;
+
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ break;
+
+ case hwmon_curr:
+ switch (attr) {
+ case hwmon_curr_input:
+ snet_hwmon_read_reg(psnet, SNET_MON_CURR_IN_OFF, val);
+ break;
+ case hwmon_curr_max:
+ snet_hwmon_read_reg(psnet, SNET_MON_CURR_MAX_OFF, val);
+ break;
+ case hwmon_curr_crit:
+ snet_hwmon_read_reg(psnet, SNET_MON_CURR_CRIT_OFF, val);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ break;
+
+ case hwmon_temp:
+ switch (attr) {
+ case hwmon_temp_input:
+ if (channel == 0)
+ snet_hwmon_read_reg(psnet, SNET_MON_TMP0_IN_OFF, val);
+ else
+ snet_hwmon_read_reg(psnet, SNET_MON_TMP1_IN_OFF, val);
+ break;
+ case hwmon_temp_max:
+ if (channel == 0)
+ snet_hwmon_read_reg(psnet, SNET_MON_TMP0_MAX_OFF, val);
+ else
+ ret = -EOPNOTSUPP;
+ break;
+ case hwmon_temp_crit:
+ if (channel == 0)
+ snet_hwmon_read_reg(psnet, SNET_MON_TMP0_CRIT_OFF, val);
+ else
+ snet_hwmon_read_reg(psnet, SNET_MON_TMP1_CRIT_OFF, val);
+ break;
+
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ break;
+
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ return ret;
+}
+
+static int snet_hwmon_read_string(struct device *dev,
+ enum hwmon_sensor_types type, u32 attr,
+ int channel, const char **str)
+{
+ int ret = 0;
+
+ switch (type) {
+ case hwmon_in:
+ *str = "main_vin";
+ break;
+ case hwmon_power:
+ *str = "soc_pin";
+ break;
+ case hwmon_curr:
+ *str = "soc_iin";
+ break;
+ case hwmon_temp:
+ if (channel == 0)
+ *str = "power_stage_temp";
+ else
+ *str = "ic_junction_temp";
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ return ret;
+}
+
+static const struct hwmon_ops snet_hwmon_ops = {
+ .is_visible = snet_howmon_is_visible,
+ .read = snet_howmon_read,
+ .read_string = snet_hwmon_read_string
+};
+
+static const struct hwmon_channel_info *snet_hwmon_info[] = {
+ HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_LABEL),
+ HWMON_CHANNEL_INFO(power, HWMON_P_INPUT | HWMON_P_LABEL),
+ HWMON_CHANNEL_INFO(curr, HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_CRIT | HWMON_C_LABEL),
+ HWMON_CHANNEL_INFO(in, HWMON_I_INPUT | HWMON_I_CRIT | HWMON_I_LCRIT | HWMON_I_LABEL),
+ NULL
+};
+
+static const struct hwmon_chip_info snet_hwmono_info = {
+ .ops = &snet_hwmon_ops,
+ .info = snet_hwmon_info,
+};
+
+/* Create an HW monitor device */
+void psnet_create_hwmon(struct pci_dev *pdev)
+{
+ struct device *hwmon;
+ struct psnet *psnet = pci_get_drvdata(pdev);
+
+ snprintf(psnet->hwmon_name, SNET_NAME_SIZE, "snet_%s", pci_name(pdev));
+ hwmon = devm_hwmon_device_register_with_info(&pdev->dev, psnet->hwmon_name, psnet,
+ &snet_hwmono_info, NULL);
+ /* The monitor is not mandatory, Just alert user in case of an error */
+ if (IS_ERR(hwmon))
+ SNET_WARN(pdev, "Failed to create SNET hwmon, error %ld\n", PTR_ERR(hwmon));
+}
diff --git a/drivers/vdpa/solidrun/snet_main.c b/drivers/vdpa/solidrun/snet_main.c
new file mode 100644
index 000000000000..68de727398ed
--- /dev/null
+++ b/drivers/vdpa/solidrun/snet_main.c
@@ -0,0 +1,1111 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * SolidRun DPU driver for control plane
+ *
+ * Copyright (C) 2022 SolidRun
+ *
+ * Author: Alvaro Karsz <alvaro.karsz@solid-run.com>
+ *
+ */
+#include <linux/iopoll.h>
+
+#include "snet_vdpa.h"
+
+/* SNET DPU device ID */
+#define SNET_DEVICE_ID 0x1000
+/* SNET signature */
+#define SNET_SIGNATURE 0xD0D06363
+/* Max. config version that we can work with */
+#define SNET_CFG_VERSION 0x1
+/* Queue align */
+#define SNET_QUEUE_ALIGNMENT PAGE_SIZE
+/* Kick value to notify that new data is available */
+#define SNET_KICK_VAL 0x1
+#define SNET_CONFIG_OFF 0x0
+/* ACK timeout for a message */
+#define SNET_ACK_TIMEOUT 2000000
+/* How long we are willing to wait for a SNET device */
+#define SNET_DETECT_TIMEOUT 5000000
+/* How long should we wait for the DPU to read our config */
+#define SNET_READ_CFG_TIMEOUT 3000000
+/* Size of configs written to the DPU */
+#define SNET_GENERAL_CFG_LEN 36
+#define SNET_GENERAL_CFG_VQ_LEN 40
+
+enum snet_msg {
+ SNET_MSG_DESTROY = 1,
+};
+
+static struct snet *vdpa_to_snet(struct vdpa_device *vdpa)
+{
+ return container_of(vdpa, struct snet, vdpa);
+}
+
+static int snet_wait_for_msg_ack(struct snet *snet)
+{
+ struct pci_dev *pdev = snet->pdev;
+ int ret;
+ u32 val;
+
+ /* The DPU will clear the messages offset once messages
+ * are processed.
+ */
+ ret = readx_poll_timeout(ioread32, snet->bar + snet->psnet->cfg.msg_off,
+ val, !val, 10, SNET_ACK_TIMEOUT);
+ if (ret)
+ SNET_WARN(pdev, "Timeout waiting for message ACK\n");
+
+ return ret;
+}
+
+/* Sends a message to the DPU.
+ * If blocking is set, the function will return once the
+ * message was processed by the DPU (or timeout).
+ */
+static int snet_send_msg(struct snet *snet, u32 msg, bool blocking)
+{
+ int ret = 0;
+
+ /* Make sure the DPU acked last message before issuing a new one */
+ ret = snet_wait_for_msg_ack(snet);
+ if (ret)
+ return ret;
+
+ /* Write the message */
+ snet_write32(snet, snet->psnet->cfg.msg_off, msg);
+
+ if (blocking)
+ ret = snet_wait_for_msg_ack(snet);
+ else /* If non-blocking, flush the write by issuing a read */
+ snet_read32(snet, snet->psnet->cfg.msg_off);
+
+ return ret;
+}
+
+static irqreturn_t snet_cfg_irq_hndlr(int irq, void *data)
+{
+ struct snet *snet = data;
+ /* Call callback if any */
+ if (snet->cb.callback)
+ return snet->cb.callback(snet->cb.private);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t snet_vq_irq_hndlr(int irq, void *data)
+{
+ struct snet_vq *vq = data;
+ /* Call callback if any */
+ if (vq->cb.callback)
+ return vq->cb.callback(vq->cb.private);
+
+ return IRQ_HANDLED;
+}
+
+static void snet_free_irqs(struct snet *snet)
+{
+ struct psnet *psnet = snet->psnet;
+ struct pci_dev *pdev;
+ u32 i;
+
+ /* Which Device allcoated the IRQs? */
+ if (PSNET_FLAG_ON(psnet, SNET_CFG_FLAG_IRQ_PF))
+ pdev = snet->pdev->physfn;
+ else
+ pdev = snet->pdev;
+
+ /* Free config's IRQ */
+ if (snet->cfg_irq != -1) {
+ devm_free_irq(&pdev->dev, snet->cfg_irq, snet);
+ snet->cfg_irq = -1;
+ }
+ /* Free VQ IRQs */
+ for (i = 0; i < snet->cfg->vq_num; i++) {
+ if (snet->vqs[i] && snet->vqs[i]->irq != -1) {
+ devm_free_irq(&pdev->dev, snet->vqs[i]->irq, snet->vqs[i]);
+ snet->vqs[i]->irq = -1;
+ }
+ }
+
+ /* IRQ vectors are freed when the pci remove callback is called */
+}
+
+static int snet_set_vq_address(struct vdpa_device *vdev, u16 idx, u64 desc_area,
+ u64 driver_area, u64 device_area)
+{
+ struct snet *snet = vdpa_to_snet(vdev);
+ /* save received parameters in vqueue sturct */
+ snet->vqs[idx]->desc_area = desc_area;
+ snet->vqs[idx]->driver_area = driver_area;
+ snet->vqs[idx]->device_area = device_area;
+
+ return 0;
+}
+
+static void snet_set_vq_num(struct vdpa_device *vdev, u16 idx, u32 num)
+{
+ struct snet *snet = vdpa_to_snet(vdev);
+ /* save num in vqueue */
+ snet->vqs[idx]->num = num;
+}
+
+static void snet_kick_vq(struct vdpa_device *vdev, u16 idx)
+{
+ struct snet *snet = vdpa_to_snet(vdev);
+ /* not ready - ignore */
+ if (!snet->vqs[idx]->ready)
+ return;
+
+ iowrite32(SNET_KICK_VAL, snet->vqs[idx]->kick_ptr);
+}
+
+static void snet_set_vq_cb(struct vdpa_device *vdev, u16 idx, struct vdpa_callback *cb)
+{
+ struct snet *snet = vdpa_to_snet(vdev);
+
+ snet->vqs[idx]->cb.callback = cb->callback;
+ snet->vqs[idx]->cb.private = cb->private;
+}
+
+static void snet_set_vq_ready(struct vdpa_device *vdev, u16 idx, bool ready)
+{
+ struct snet *snet = vdpa_to_snet(vdev);
+
+ snet->vqs[idx]->ready = ready;
+}
+
+static bool snet_get_vq_ready(struct vdpa_device *vdev, u16 idx)
+{
+ struct snet *snet = vdpa_to_snet(vdev);
+
+ return snet->vqs[idx]->ready;
+}
+
+static int snet_set_vq_state(struct vdpa_device *vdev, u16 idx, const struct vdpa_vq_state *state)
+{
+ struct snet *snet = vdpa_to_snet(vdev);
+ /* Setting the VQ state is not supported.
+ * If the asked state is the same as the initial one
+ * we can ignore it.
+ */
+ if (SNET_HAS_FEATURE(snet, VIRTIO_F_RING_PACKED)) {
+ const struct vdpa_vq_state_packed *p = &state->packed;
+
+ if (p->last_avail_counter == 1 && p->last_used_counter == 1 &&
+ p->last_avail_idx == 0 && p->last_used_idx == 0)
+ return 0;
+ } else {
+ const struct vdpa_vq_state_split *s = &state->split;
+
+ if (s->avail_index == 0)
+ return 0;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+static int snet_get_vq_state(struct vdpa_device *vdev, u16 idx, struct vdpa_vq_state *state)
+{
+ /* Not supported */
+ return -EOPNOTSUPP;
+}
+
+static int snet_get_vq_irq(struct vdpa_device *vdev, u16 idx)
+{
+ struct snet *snet = vdpa_to_snet(vdev);
+
+ return snet->vqs[idx]->irq;
+}
+
+static u32 snet_get_vq_align(struct vdpa_device *vdev)
+{
+ return (u32)SNET_QUEUE_ALIGNMENT;
+}
+
+static int snet_reset_dev(struct snet *snet)
+{
+ struct pci_dev *pdev = snet->pdev;
+ int ret = 0;
+ u32 i;
+
+ /* If status is 0, nothing to do */
+ if (!snet->status)
+ return 0;
+
+ /* If DPU started, send a destroy message */
+ if (snet->status & VIRTIO_CONFIG_S_DRIVER_OK)
+ ret = snet_send_msg(snet, SNET_MSG_DESTROY, true);
+
+ /* Clear VQs */
+ for (i = 0; i < snet->cfg->vq_num; i++) {
+ if (!snet->vqs[i])
+ continue;
+ snet->vqs[i]->cb.callback = NULL;
+ snet->vqs[i]->cb.private = NULL;
+ snet->vqs[i]->desc_area = 0;
+ snet->vqs[i]->device_area = 0;
+ snet->vqs[i]->driver_area = 0;
+ snet->vqs[i]->ready = false;
+ }
+
+ /* Clear config callback */
+ snet->cb.callback = NULL;
+ snet->cb.private = NULL;
+ /* Free IRQs */
+ snet_free_irqs(snet);
+ /* Reset status */
+ snet->status = 0;
+ snet->dpu_ready = false;
+
+ if (ret)
+ SNET_WARN(pdev, "Incomplete reset to SNET[%u] device\n", snet->sid);
+ else
+ SNET_DBG(pdev, "Reset SNET[%u] device\n", snet->sid);
+
+ return 0;
+}
+
+static int snet_reset(struct vdpa_device *vdev)
+{
+ struct snet *snet = vdpa_to_snet(vdev);
+
+ return snet_reset_dev(snet);
+}
+
+static size_t snet_get_config_size(struct vdpa_device *vdev)
+{
+ struct snet *snet = vdpa_to_snet(vdev);
+
+ return (size_t)snet->cfg->cfg_size;
+}
+
+static u64 snet_get_features(struct vdpa_device *vdev)
+{
+ struct snet *snet = vdpa_to_snet(vdev);
+
+ return snet->cfg->features;
+}
+
+static int snet_set_drv_features(struct vdpa_device *vdev, u64 features)
+{
+ struct snet *snet = vdpa_to_snet(vdev);
+
+ snet->negotiated_features = snet->cfg->features & features;
+ return 0;
+}
+
+static u64 snet_get_drv_features(struct vdpa_device *vdev)
+{
+ struct snet *snet = vdpa_to_snet(vdev);
+
+ return snet->negotiated_features;
+}
+
+static u16 snet_get_vq_num_max(struct vdpa_device *vdev)
+{
+ struct snet *snet = vdpa_to_snet(vdev);
+
+ return (u16)snet->cfg->vq_size;
+}
+
+static void snet_set_config_cb(struct vdpa_device *vdev, struct vdpa_callback *cb)
+{
+ struct snet *snet = vdpa_to_snet(vdev);
+
+ snet->cb.callback = cb->callback;
+ snet->cb.private = cb->private;
+}
+
+static u32 snet_get_device_id(struct vdpa_device *vdev)
+{
+ struct snet *snet = vdpa_to_snet(vdev);
+
+ return snet->cfg->virtio_id;
+}
+
+static u32 snet_get_vendor_id(struct vdpa_device *vdev)
+{
+ return (u32)PCI_VENDOR_ID_SOLIDRUN;
+}
+
+static u8 snet_get_status(struct vdpa_device *vdev)
+{
+ struct snet *snet = vdpa_to_snet(vdev);
+
+ return snet->status;
+}
+
+static int snet_write_conf(struct snet *snet)
+{
+ u32 off, i, tmp;
+ int ret;
+
+ /* No need to write the config twice */
+ if (snet->dpu_ready)
+ return true;
+
+ /* Snet data :
+ *
+ * General data: SNET_GENERAL_CFG_LEN bytes long
+ * 0 0x4 0x8 0xC 0x10 0x14 0x1C 0x24
+ * | MAGIC NUMBER | CFG VER | SNET SID | NUMBER OF QUEUES | IRQ IDX | FEATURES | RSVD |
+ *
+ * For every VQ: SNET_GENERAL_CFG_VQ_LEN bytes long
+ * 0 0x4 0x8
+ * | VQ SID AND QUEUE SIZE | IRQ Index |
+ * | DESC AREA |
+ * | DEVICE AREA |
+ * | DRIVER AREA |
+ * | RESERVED |
+ *
+ * Magic number should be written last, this is the DPU indication that the data is ready
+ */
+
+ /* Init offset */
+ off = snet->psnet->cfg.host_cfg_off;
+
+ /* Ignore magic number for now */
+ off += 4;
+ snet_write32(snet, off, snet->psnet->negotiated_cfg_ver);
+ off += 4;
+ snet_write32(snet, off, snet->sid);
+ off += 4;
+ snet_write32(snet, off, snet->cfg->vq_num);
+ off += 4;
+ snet_write32(snet, off, snet->cfg_irq_idx);
+ off += 4;
+ snet_write64(snet, off, snet->negotiated_features);
+ off += 8;
+ /* Ignore reserved */
+ off += 8;
+ /* Write VQs */
+ for (i = 0 ; i < snet->cfg->vq_num ; i++) {
+ tmp = (i << 16) | (snet->vqs[i]->num & 0xFFFF);
+ snet_write32(snet, off, tmp);
+ off += 4;
+ snet_write32(snet, off, snet->vqs[i]->irq_idx);
+ off += 4;
+ snet_write64(snet, off, snet->vqs[i]->desc_area);
+ off += 8;
+ snet_write64(snet, off, snet->vqs[i]->device_area);
+ off += 8;
+ snet_write64(snet, off, snet->vqs[i]->driver_area);
+ off += 8;
+ /* Ignore reserved */
+ off += 8;
+ }
+
+ /* Clear snet messages address for this device */
+ snet_write32(snet, snet->psnet->cfg.msg_off, 0);
+ /* Write magic number - data is ready */
+ snet_write32(snet, snet->psnet->cfg.host_cfg_off, SNET_SIGNATURE);
+
+ /* The DPU will ACK the config by clearing the signature */
+ ret = readx_poll_timeout(ioread32, snet->bar + snet->psnet->cfg.host_cfg_off,
+ tmp, !tmp, 10, SNET_READ_CFG_TIMEOUT);
+ if (ret) {
+ SNET_ERR(snet->pdev, "Timeout waiting for the DPU to read the config\n");
+ return false;
+ }
+
+ /* set DPU flag */
+ snet->dpu_ready = true;
+
+ return true;
+}
+
+static int snet_request_irqs(struct pci_dev *pdev, struct snet *snet)
+{
+ int ret, i, irq;
+
+ /* Request config IRQ */
+ irq = pci_irq_vector(pdev, snet->cfg_irq_idx);
+ ret = devm_request_irq(&pdev->dev, irq, snet_cfg_irq_hndlr, 0,
+ snet->cfg_irq_name, snet);
+ if (ret) {
+ SNET_ERR(pdev, "Failed to request IRQ\n");
+ return ret;
+ }
+ snet->cfg_irq = irq;
+
+ /* Request IRQ for every VQ */
+ for (i = 0; i < snet->cfg->vq_num; i++) {
+ irq = pci_irq_vector(pdev, snet->vqs[i]->irq_idx);
+ ret = devm_request_irq(&pdev->dev, irq, snet_vq_irq_hndlr, 0,
+ snet->vqs[i]->irq_name, snet->vqs[i]);
+ if (ret) {
+ SNET_ERR(pdev, "Failed to request IRQ\n");
+ return ret;
+ }
+ snet->vqs[i]->irq = irq;
+ }
+ return 0;
+}
+
+static void snet_set_status(struct vdpa_device *vdev, u8 status)
+{
+ struct snet *snet = vdpa_to_snet(vdev);
+ struct psnet *psnet = snet->psnet;
+ struct pci_dev *pdev = snet->pdev;
+ int ret;
+ bool pf_irqs;
+
+ if (status == snet->status)
+ return;
+
+ if ((status & VIRTIO_CONFIG_S_DRIVER_OK) &&
+ !(snet->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
+ /* Request IRQs */
+ pf_irqs = PSNET_FLAG_ON(psnet, SNET_CFG_FLAG_IRQ_PF);
+ ret = snet_request_irqs(pf_irqs ? pdev->physfn : pdev, snet);
+ if (ret)
+ goto set_err;
+
+ /* Write config to the DPU */
+ if (snet_write_conf(snet)) {
+ SNET_INFO(pdev, "Create SNET[%u] device\n", snet->sid);
+ } else {
+ snet_free_irqs(snet);
+ goto set_err;
+ }
+ }
+
+ /* Save the new status */
+ snet->status = status;
+ return;
+
+set_err:
+ snet->status |= VIRTIO_CONFIG_S_FAILED;
+}
+
+static void snet_get_config(struct vdpa_device *vdev, unsigned int offset,
+ void *buf, unsigned int len)
+{
+ struct snet *snet = vdpa_to_snet(vdev);
+ void __iomem *cfg_ptr = snet->cfg->virtio_cfg + offset;
+ u8 *buf_ptr = buf;
+ u32 i;
+
+ /* check for offset error */
+ if (offset + len > snet->cfg->cfg_size)
+ return;
+
+ /* Write into buffer */
+ for (i = 0; i < len; i++)
+ *buf_ptr++ = ioread8(cfg_ptr + i);
+}
+
+static void snet_set_config(struct vdpa_device *vdev, unsigned int offset,
+ const void *buf, unsigned int len)
+{
+ struct snet *snet = vdpa_to_snet(vdev);
+ void __iomem *cfg_ptr = snet->cfg->virtio_cfg + offset;
+ const u8 *buf_ptr = buf;
+ u32 i;
+
+ /* check for offset error */
+ if (offset + len > snet->cfg->cfg_size)
+ return;
+
+ /* Write into PCI BAR */
+ for (i = 0; i < len; i++)
+ iowrite8(*buf_ptr++, cfg_ptr + i);
+}
+
+static const struct vdpa_config_ops snet_config_ops = {
+ .set_vq_address = snet_set_vq_address,
+ .set_vq_num = snet_set_vq_num,
+ .kick_vq = snet_kick_vq,
+ .set_vq_cb = snet_set_vq_cb,
+ .set_vq_ready = snet_set_vq_ready,
+ .get_vq_ready = snet_get_vq_ready,
+ .set_vq_state = snet_set_vq_state,
+ .get_vq_state = snet_get_vq_state,
+ .get_vq_irq = snet_get_vq_irq,
+ .get_vq_align = snet_get_vq_align,
+ .reset = snet_reset,
+ .get_config_size = snet_get_config_size,
+ .get_device_features = snet_get_features,
+ .set_driver_features = snet_set_drv_features,
+ .get_driver_features = snet_get_drv_features,
+ .get_vq_num_min = snet_get_vq_num_max,
+ .get_vq_num_max = snet_get_vq_num_max,
+ .set_config_cb = snet_set_config_cb,
+ .get_device_id = snet_get_device_id,
+ .get_vendor_id = snet_get_vendor_id,
+ .get_status = snet_get_status,
+ .set_status = snet_set_status,
+ .get_config = snet_get_config,
+ .set_config = snet_set_config,
+};
+
+static int psnet_open_pf_bar(struct pci_dev *pdev, struct psnet *psnet)
+{
+ char name[50];
+ int ret, i, mask = 0;
+ /* We don't know which BAR will be used to communicate..
+ * We will map every bar with len > 0.
+ *
+ * Later, we will discover the BAR and unmap all other BARs.
+ */
+ for (i = 0; i < PCI_STD_NUM_BARS; i++) {
+ if (pci_resource_len(pdev, i))
+ mask |= (1 << i);
+ }
+
+ /* No BAR can be used.. */
+ if (!mask) {
+ SNET_ERR(pdev, "Failed to find a PCI BAR\n");
+ return -ENODEV;
+ }
+
+ snprintf(name, sizeof(name), "psnet[%s]-bars", pci_name(pdev));
+ ret = pcim_iomap_regions(pdev, mask, name);
+ if (ret) {
+ SNET_ERR(pdev, "Failed to request and map PCI BARs\n");
+ return ret;
+ }
+
+ for (i = 0; i < PCI_STD_NUM_BARS; i++) {
+ if (mask & (1 << i))
+ psnet->bars[i] = pcim_iomap_table(pdev)[i];
+ }
+
+ return 0;
+}
+
+static int snet_open_vf_bar(struct pci_dev *pdev, struct snet *snet)
+{
+ char name[50];
+ int ret;
+
+ snprintf(name, sizeof(name), "snet[%s]-bar", pci_name(pdev));
+ /* Request and map BAR */
+ ret = pcim_iomap_regions(pdev, BIT(snet->psnet->cfg.vf_bar), name);
+ if (ret) {
+ SNET_ERR(pdev, "Failed to request and map PCI BAR for a VF\n");
+ return ret;
+ }
+
+ snet->bar = pcim_iomap_table(pdev)[snet->psnet->cfg.vf_bar];
+
+ return 0;
+}
+
+static void snet_free_cfg(struct snet_cfg *cfg)
+{
+ u32 i;
+
+ if (!cfg->devs)
+ return;
+
+ /* Free devices */
+ for (i = 0; i < cfg->devices_num; i++) {
+ if (!cfg->devs[i])
+ break;
+
+ kfree(cfg->devs[i]);
+ }
+ /* Free pointers to devices */
+ kfree(cfg->devs);
+}
+
+/* Detect which BAR is used for communication with the device. */
+static int psnet_detect_bar(struct psnet *psnet, u32 off)
+{
+ unsigned long exit_time;
+ int i;
+
+ exit_time = jiffies + usecs_to_jiffies(SNET_DETECT_TIMEOUT);
+
+ /* SNET DPU will write SNET's signature when the config is ready. */
+ while (time_before(jiffies, exit_time)) {
+ for (i = 0; i < PCI_STD_NUM_BARS; i++) {
+ /* Is this BAR mapped? */
+ if (!psnet->bars[i])
+ continue;
+
+ if (ioread32(psnet->bars[i] + off) == SNET_SIGNATURE)
+ return i;
+ }
+ usleep_range(1000, 10000);
+ }
+
+ return -ENODEV;
+}
+
+static void psnet_unmap_unused_bars(struct pci_dev *pdev, struct psnet *psnet)
+{
+ int i, mask = 0;
+
+ for (i = 0; i < PCI_STD_NUM_BARS; i++) {
+ if (psnet->bars[i] && i != psnet->barno)
+ mask |= (1 << i);
+ }
+
+ if (mask)
+ pcim_iounmap_regions(pdev, mask);
+}
+
+/* Read SNET config from PCI BAR */
+static int psnet_read_cfg(struct pci_dev *pdev, struct psnet *psnet)
+{
+ struct snet_cfg *cfg = &psnet->cfg;
+ u32 i, off;
+ int barno;
+
+ /* Move to where the config starts */
+ off = SNET_CONFIG_OFF;
+
+ /* Find BAR used for communication */
+ barno = psnet_detect_bar(psnet, off);
+ if (barno < 0) {
+ SNET_ERR(pdev, "SNET config is not ready.\n");
+ return barno;
+ }
+
+ /* Save used BAR number and unmap all other BARs */
+ psnet->barno = barno;
+ SNET_DBG(pdev, "Using BAR number %d\n", barno);
+
+ psnet_unmap_unused_bars(pdev, psnet);
+
+ /* load config from BAR */
+ cfg->key = psnet_read32(psnet, off);
+ off += 4;
+ cfg->cfg_size = psnet_read32(psnet, off);
+ off += 4;
+ cfg->cfg_ver = psnet_read32(psnet, off);
+ off += 4;
+ /* The negotiated config version is the lower one between this driver's config
+ * and the DPU's.
+ */
+ psnet->negotiated_cfg_ver = min_t(u32, cfg->cfg_ver, SNET_CFG_VERSION);
+ SNET_DBG(pdev, "SNET config version %u\n", psnet->negotiated_cfg_ver);
+
+ cfg->vf_num = psnet_read32(psnet, off);
+ off += 4;
+ cfg->vf_bar = psnet_read32(psnet, off);
+ off += 4;
+ cfg->host_cfg_off = psnet_read32(psnet, off);
+ off += 4;
+ cfg->max_size_host_cfg = psnet_read32(psnet, off);
+ off += 4;
+ cfg->virtio_cfg_off = psnet_read32(psnet, off);
+ off += 4;
+ cfg->kick_off = psnet_read32(psnet, off);
+ off += 4;
+ cfg->hwmon_off = psnet_read32(psnet, off);
+ off += 4;
+ cfg->msg_off = psnet_read32(psnet, off);
+ off += 4;
+ cfg->flags = psnet_read32(psnet, off);
+ off += 4;
+ /* Ignore Reserved */
+ off += sizeof(cfg->rsvd);
+
+ cfg->devices_num = psnet_read32(psnet, off);
+ off += 4;
+ /* Allocate memory to hold pointer to the devices */
+ cfg->devs = kcalloc(cfg->devices_num, sizeof(void *), GFP_KERNEL);
+ if (!cfg->devs)
+ return -ENOMEM;
+
+ /* Load device configuration from BAR */
+ for (i = 0; i < cfg->devices_num; i++) {
+ cfg->devs[i] = kzalloc(sizeof(*cfg->devs[i]), GFP_KERNEL);
+ if (!cfg->devs[i]) {
+ snet_free_cfg(cfg);
+ return -ENOMEM;
+ }
+ /* Read device config */
+ cfg->devs[i]->virtio_id = psnet_read32(psnet, off);
+ off += 4;
+ cfg->devs[i]->vq_num = psnet_read32(psnet, off);
+ off += 4;
+ cfg->devs[i]->vq_size = psnet_read32(psnet, off);
+ off += 4;
+ cfg->devs[i]->vfid = psnet_read32(psnet, off);
+ off += 4;
+ cfg->devs[i]->features = psnet_read64(psnet, off);
+ off += 8;
+ /* Ignore Reserved */
+ off += sizeof(cfg->devs[i]->rsvd);
+
+ cfg->devs[i]->cfg_size = psnet_read32(psnet, off);
+ off += 4;
+
+ /* Is the config witten to the DPU going to be too big? */
+ if (SNET_GENERAL_CFG_LEN + SNET_GENERAL_CFG_VQ_LEN * cfg->devs[i]->vq_num >
+ cfg->max_size_host_cfg) {
+ SNET_ERR(pdev, "Failed to read SNET config, the config is too big..\n");
+ snet_free_cfg(cfg);
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static int psnet_alloc_irq_vector(struct pci_dev *pdev, struct psnet *psnet)
+{
+ int ret = 0;
+ u32 i, irq_num = 0;
+
+ /* Let's count how many IRQs we need, 1 for every VQ + 1 for config change */
+ for (i = 0; i < psnet->cfg.devices_num; i++)
+ irq_num += psnet->cfg.devs[i]->vq_num + 1;
+
+ ret = pci_alloc_irq_vectors(pdev, irq_num, irq_num, PCI_IRQ_MSIX);
+ if (ret != irq_num) {
+ SNET_ERR(pdev, "Failed to allocate IRQ vectors\n");
+ return ret;
+ }
+ SNET_DBG(pdev, "Allocated %u IRQ vectors from physical function\n", irq_num);
+
+ return 0;
+}
+
+static int snet_alloc_irq_vector(struct pci_dev *pdev, struct snet_dev_cfg *snet_cfg)
+{
+ int ret = 0;
+ u32 irq_num;
+
+ /* We want 1 IRQ for every VQ + 1 for config change events */
+ irq_num = snet_cfg->vq_num + 1;
+
+ ret = pci_alloc_irq_vectors(pdev, irq_num, irq_num, PCI_IRQ_MSIX);
+ if (ret <= 0) {
+ SNET_ERR(pdev, "Failed to allocate IRQ vectors\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void snet_free_vqs(struct snet *snet)
+{
+ u32 i;
+
+ if (!snet->vqs)
+ return;
+
+ for (i = 0 ; i < snet->cfg->vq_num ; i++) {
+ if (!snet->vqs[i])
+ break;
+
+ kfree(snet->vqs[i]);
+ }
+ kfree(snet->vqs);
+}
+
+static int snet_build_vqs(struct snet *snet)
+{
+ u32 i;
+ /* Allocate the VQ pointers array */
+ snet->vqs = kcalloc(snet->cfg->vq_num, sizeof(void *), GFP_KERNEL);
+ if (!snet->vqs)
+ return -ENOMEM;
+
+ /* Allocate the VQs */
+ for (i = 0; i < snet->cfg->vq_num; i++) {
+ snet->vqs[i] = kzalloc(sizeof(*snet->vqs[i]), GFP_KERNEL);
+ if (!snet->vqs[i]) {
+ snet_free_vqs(snet);
+ return -ENOMEM;
+ }
+ /* Reset IRQ num */
+ snet->vqs[i]->irq = -1;
+ /* VQ serial ID */
+ snet->vqs[i]->sid = i;
+ /* Kick address - every VQ gets 4B */
+ snet->vqs[i]->kick_ptr = snet->bar + snet->psnet->cfg.kick_off +
+ snet->vqs[i]->sid * 4;
+ /* Clear kick address for this VQ */
+ iowrite32(0, snet->vqs[i]->kick_ptr);
+ }
+ return 0;
+}
+
+static int psnet_get_next_irq_num(struct psnet *psnet)
+{
+ int irq;
+
+ spin_lock(&psnet->lock);
+ irq = psnet->next_irq++;
+ spin_unlock(&psnet->lock);
+
+ return irq;
+}
+
+static void snet_reserve_irq_idx(struct pci_dev *pdev, struct snet *snet)
+{
+ struct psnet *psnet = snet->psnet;
+ int i;
+
+ /* one IRQ for every VQ, and one for config changes */
+ snet->cfg_irq_idx = psnet_get_next_irq_num(psnet);
+ snprintf(snet->cfg_irq_name, SNET_NAME_SIZE, "snet[%s]-cfg[%d]",
+ pci_name(pdev), snet->cfg_irq_idx);
+
+ for (i = 0; i < snet->cfg->vq_num; i++) {
+ /* Get next free IRQ ID */
+ snet->vqs[i]->irq_idx = psnet_get_next_irq_num(psnet);
+ /* Write IRQ name */
+ snprintf(snet->vqs[i]->irq_name, SNET_NAME_SIZE, "snet[%s]-vq[%d]",
+ pci_name(pdev), snet->vqs[i]->irq_idx);
+ }
+}
+
+/* Find a device config based on virtual function id */
+static struct snet_dev_cfg *snet_find_dev_cfg(struct snet_cfg *cfg, u32 vfid)
+{
+ u32 i;
+
+ for (i = 0; i < cfg->devices_num; i++) {
+ if (cfg->devs[i]->vfid == vfid)
+ return cfg->devs[i];
+ }
+ /* Oppss.. no config found.. */
+ return NULL;
+}
+
+/* Probe function for a physical PCI function */
+static int snet_vdpa_probe_pf(struct pci_dev *pdev)
+{
+ struct psnet *psnet;
+ int ret = 0;
+ bool pf_irqs = false;
+
+ ret = pcim_enable_device(pdev);
+ if (ret) {
+ SNET_ERR(pdev, "Failed to enable PCI device\n");
+ return ret;
+ }
+
+ /* Allocate a PCI physical function device */
+ psnet = kzalloc(sizeof(*psnet), GFP_KERNEL);
+ if (!psnet)
+ return -ENOMEM;
+
+ /* Init PSNET spinlock */
+ spin_lock_init(&psnet->lock);
+
+ pci_set_master(pdev);
+ pci_set_drvdata(pdev, psnet);
+
+ /* Open SNET MAIN BAR */
+ ret = psnet_open_pf_bar(pdev, psnet);
+ if (ret)
+ goto free_psnet;
+
+ /* Try to read SNET's config from PCI BAR */
+ ret = psnet_read_cfg(pdev, psnet);
+ if (ret)
+ goto free_psnet;
+
+ /* If SNET_CFG_FLAG_IRQ_PF flag is set, we should use
+ * PF MSI-X vectors
+ */
+ pf_irqs = PSNET_FLAG_ON(psnet, SNET_CFG_FLAG_IRQ_PF);
+
+ if (pf_irqs) {
+ ret = psnet_alloc_irq_vector(pdev, psnet);
+ if (ret)
+ goto free_cfg;
+ }
+
+ SNET_DBG(pdev, "Enable %u virtual functions\n", psnet->cfg.vf_num);
+ ret = pci_enable_sriov(pdev, psnet->cfg.vf_num);
+ if (ret) {
+ SNET_ERR(pdev, "Failed to enable SR-IOV\n");
+ goto free_irq;
+ }
+
+ /* Create HW monitor device */
+ if (PSNET_FLAG_ON(psnet, SNET_CFG_FLAG_HWMON)) {
+#if IS_ENABLED(CONFIG_HWMON)
+ psnet_create_hwmon(pdev);
+#else
+ SNET_WARN(pdev, "Can't start HWMON, CONFIG_HWMON is not enabled\n");
+#endif
+ }
+
+ return 0;
+
+free_irq:
+ if (pf_irqs)
+ pci_free_irq_vectors(pdev);
+free_cfg:
+ snet_free_cfg(&psnet->cfg);
+free_psnet:
+ kfree(psnet);
+ return ret;
+}
+
+/* Probe function for a virtual PCI function */
+static int snet_vdpa_probe_vf(struct pci_dev *pdev)
+{
+ struct pci_dev *pdev_pf = pdev->physfn;
+ struct psnet *psnet = pci_get_drvdata(pdev_pf);
+ struct snet_dev_cfg *dev_cfg;
+ struct snet *snet;
+ u32 vfid;
+ int ret;
+ bool pf_irqs = false;
+
+ /* Get virtual function id.
+ * (the DPU counts the VFs from 1)
+ */
+ ret = pci_iov_vf_id(pdev);
+ if (ret < 0) {
+ SNET_ERR(pdev, "Failed to find a VF id\n");
+ return ret;
+ }
+ vfid = ret + 1;
+
+ /* Find the snet_dev_cfg based on vfid */
+ dev_cfg = snet_find_dev_cfg(&psnet->cfg, vfid);
+ if (!dev_cfg) {
+ SNET_WARN(pdev, "Failed to find a VF config..\n");
+ return -ENODEV;
+ }
+
+ /* Which PCI device should allocate the IRQs?
+ * If the SNET_CFG_FLAG_IRQ_PF flag set, the PF device allocates the IRQs
+ */
+ pf_irqs = PSNET_FLAG_ON(psnet, SNET_CFG_FLAG_IRQ_PF);
+
+ ret = pcim_enable_device(pdev);
+ if (ret) {
+ SNET_ERR(pdev, "Failed to enable PCI VF device\n");
+ return ret;
+ }
+
+ /* Request for MSI-X IRQs */
+ if (!pf_irqs) {
+ ret = snet_alloc_irq_vector(pdev, dev_cfg);
+ if (ret)
+ return ret;
+ }
+
+ /* Allocate vdpa device */
+ snet = vdpa_alloc_device(struct snet, vdpa, &pdev->dev, &snet_config_ops, 1, 1, NULL,
+ false);
+ if (!snet) {
+ SNET_ERR(pdev, "Failed to allocate a vdpa device\n");
+ ret = -ENOMEM;
+ goto free_irqs;
+ }
+
+ /* Save pci device pointer */
+ snet->pdev = pdev;
+ snet->psnet = psnet;
+ snet->cfg = dev_cfg;
+ snet->dpu_ready = false;
+ snet->sid = vfid;
+ /* Reset IRQ value */
+ snet->cfg_irq = -1;
+
+ ret = snet_open_vf_bar(pdev, snet);
+ if (ret)
+ goto put_device;
+
+ /* Create a VirtIO config pointer */
+ snet->cfg->virtio_cfg = snet->bar + snet->psnet->cfg.virtio_cfg_off;
+
+ pci_set_master(pdev);
+ pci_set_drvdata(pdev, snet);
+
+ ret = snet_build_vqs(snet);
+ if (ret)
+ goto put_device;
+
+ /* Reserve IRQ indexes,
+ * The IRQs may be requested and freed multiple times,
+ * but the indexes won't change.
+ */
+ snet_reserve_irq_idx(pf_irqs ? pdev_pf : pdev, snet);
+
+ /*set DMA device*/
+ snet->vdpa.dma_dev = &pdev->dev;
+
+ /* Register VDPA device */
+ ret = vdpa_register_device(&snet->vdpa, snet->cfg->vq_num);
+ if (ret) {
+ SNET_ERR(pdev, "Failed to register vdpa device\n");
+ goto free_vqs;
+ }
+
+ return 0;
+
+free_vqs:
+ snet_free_vqs(snet);
+put_device:
+ put_device(&snet->vdpa.dev);
+free_irqs:
+ if (!pf_irqs)
+ pci_free_irq_vectors(pdev);
+ return ret;
+}
+
+static int snet_vdpa_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ if (pdev->is_virtfn)
+ return snet_vdpa_probe_vf(pdev);
+ else
+ return snet_vdpa_probe_pf(pdev);
+}
+
+static void snet_vdpa_remove_pf(struct pci_dev *pdev)
+{
+ struct psnet *psnet = pci_get_drvdata(pdev);
+
+ pci_disable_sriov(pdev);
+ /* If IRQs are allocated from the PF, we should free the IRQs */
+ if (PSNET_FLAG_ON(psnet, SNET_CFG_FLAG_IRQ_PF))
+ pci_free_irq_vectors(pdev);
+
+ snet_free_cfg(&psnet->cfg);
+ kfree(psnet);
+}
+
+static void snet_vdpa_remove_vf(struct pci_dev *pdev)
+{
+ struct snet *snet = pci_get_drvdata(pdev);
+ struct psnet *psnet = snet->psnet;
+
+ vdpa_unregister_device(&snet->vdpa);
+ snet_free_vqs(snet);
+ /* If IRQs are allocated from the VF, we should free the IRQs */
+ if (!PSNET_FLAG_ON(psnet, SNET_CFG_FLAG_IRQ_PF))
+ pci_free_irq_vectors(pdev);
+}
+
+static void snet_vdpa_remove(struct pci_dev *pdev)
+{
+ if (pdev->is_virtfn)
+ snet_vdpa_remove_vf(pdev);
+ else
+ snet_vdpa_remove_pf(pdev);
+}
+
+static struct pci_device_id snet_driver_pci_ids[] = {
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_SOLIDRUN, SNET_DEVICE_ID,
+ PCI_VENDOR_ID_SOLIDRUN, SNET_DEVICE_ID) },
+ { 0 },
+};
+
+MODULE_DEVICE_TABLE(pci, snet_driver_pci_ids);
+
+static struct pci_driver snet_vdpa_driver = {
+ .name = "snet-vdpa-driver",
+ .id_table = snet_driver_pci_ids,
+ .probe = snet_vdpa_probe,
+ .remove = snet_vdpa_remove,
+};
+
+module_pci_driver(snet_vdpa_driver);
+
+MODULE_AUTHOR("Alvaro Karsz <alvaro.karsz@solid-run.com>");
+MODULE_DESCRIPTION("SolidRun vDPA driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/vdpa/solidrun/snet_vdpa.h b/drivers/vdpa/solidrun/snet_vdpa.h
new file mode 100644
index 000000000000..b7f34169053f
--- /dev/null
+++ b/drivers/vdpa/solidrun/snet_vdpa.h
@@ -0,0 +1,194 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * SolidRun DPU driver for control plane
+ *
+ * Copyright (C) 2022 SolidRun
+ *
+ * Author: Alvaro Karsz <alvaro.karsz@solid-run.com>
+ *
+ */
+#ifndef _SNET_VDPA_H_
+#define _SNET_VDPA_H_
+
+#include <linux/vdpa.h>
+#include <linux/pci.h>
+
+#define SNET_NAME_SIZE 256
+
+#define SNET_ERR(pdev, fmt, ...) dev_err(&(pdev)->dev, "%s"fmt, "snet_vdpa: ", ##__VA_ARGS__)
+#define SNET_WARN(pdev, fmt, ...) dev_warn(&(pdev)->dev, "%s"fmt, "snet_vdpa: ", ##__VA_ARGS__)
+#define SNET_INFO(pdev, fmt, ...) dev_info(&(pdev)->dev, "%s"fmt, "snet_vdpa: ", ##__VA_ARGS__)
+#define SNET_DBG(pdev, fmt, ...) dev_dbg(&(pdev)->dev, "%s"fmt, "snet_vdpa: ", ##__VA_ARGS__)
+#define SNET_HAS_FEATURE(s, f) ((s)->negotiated_features & BIT_ULL(f))
+/* VQ struct */
+struct snet_vq {
+ /* VQ callback */
+ struct vdpa_callback cb;
+ /* desc base address */
+ u64 desc_area;
+ /* device base address */
+ u64 device_area;
+ /* driver base address */
+ u64 driver_area;
+ /* Queue size */
+ u32 num;
+ /* Serial ID for VQ */
+ u32 sid;
+ /* is ready flag */
+ bool ready;
+ /* IRQ number */
+ u32 irq;
+ /* IRQ index, DPU uses this to parse data from MSI-X table */
+ u32 irq_idx;
+ /* IRQ name */
+ char irq_name[SNET_NAME_SIZE];
+ /* pointer to mapped PCI BAR register used by this VQ to kick */
+ void __iomem *kick_ptr;
+};
+
+struct snet {
+ /* vdpa device */
+ struct vdpa_device vdpa;
+ /* Config callback */
+ struct vdpa_callback cb;
+ /* array of virqueues */
+ struct snet_vq **vqs;
+ /* Used features */
+ u64 negotiated_features;
+ /* Device serial ID */
+ u32 sid;
+ /* device status */
+ u8 status;
+ /* boolean indicating if snet config was passed to the device */
+ bool dpu_ready;
+ /* IRQ number */
+ u32 cfg_irq;
+ /* IRQ index, DPU uses this to parse data from MSI-X table */
+ u32 cfg_irq_idx;
+ /* IRQ name */
+ char cfg_irq_name[SNET_NAME_SIZE];
+ /* BAR to access the VF */
+ void __iomem *bar;
+ /* PCI device */
+ struct pci_dev *pdev;
+ /* Pointer to snet pdev parent device */
+ struct psnet *psnet;
+ /* Pointer to snet config device */
+ struct snet_dev_cfg *cfg;
+};
+
+struct snet_dev_cfg {
+ /* Device ID following VirtIO spec. */
+ u32 virtio_id;
+ /* Number of VQs for this device */
+ u32 vq_num;
+ /* Size of every VQ */
+ u32 vq_size;
+ /* Virtual Function id */
+ u32 vfid;
+ /* Device features, following VirtIO spec */
+ u64 features;
+ /* Reserved for future usage */
+ u32 rsvd[6];
+ /* VirtIO device specific config size */
+ u32 cfg_size;
+ /* VirtIO device specific config address */
+ void __iomem *virtio_cfg;
+} __packed;
+
+struct snet_cfg {
+ /* Magic key */
+ u32 key;
+ /* Size of total config in bytes */
+ u32 cfg_size;
+ /* Config version */
+ u32 cfg_ver;
+ /* Number of Virtual Functions to create */
+ u32 vf_num;
+ /* BAR to use for the VFs */
+ u32 vf_bar;
+ /* Where should we write the SNET's config */
+ u32 host_cfg_off;
+ /* Max. allowed size for a SNET's config */
+ u32 max_size_host_cfg;
+ /* VirtIO config offset in BAR */
+ u32 virtio_cfg_off;
+ /* Offset in PCI BAR for VQ kicks */
+ u32 kick_off;
+ /* Offset in PCI BAR for HW monitoring */
+ u32 hwmon_off;
+ /* Offset in PCI BAR for SNET messages */
+ u32 msg_off;
+ /* Config general flags - enum snet_cfg_flags */
+ u32 flags;
+ /* Reserved for future usage */
+ u32 rsvd[6];
+ /* Number of snet devices */
+ u32 devices_num;
+ /* The actual devices */
+ struct snet_dev_cfg **devs;
+} __packed;
+
+/* SolidNET PCIe device, one device per PCIe physical function */
+struct psnet {
+ /* PCI BARs */
+ void __iomem *bars[PCI_STD_NUM_BARS];
+ /* Negotiated config version */
+ u32 negotiated_cfg_ver;
+ /* Next IRQ index to use in case when the IRQs are allocated from this device */
+ u32 next_irq;
+ /* BAR number used to communicate with the device */
+ u8 barno;
+ /* spinlock to protect data that can be changed by SNET devices */
+ spinlock_t lock;
+ /* Pointer to the device's config read from BAR */
+ struct snet_cfg cfg;
+ /* Name of monitor device */
+ char hwmon_name[SNET_NAME_SIZE];
+};
+
+enum snet_cfg_flags {
+ /* Create a HWMON device */
+ SNET_CFG_FLAG_HWMON = BIT(0),
+ /* USE IRQs from the physical function */
+ SNET_CFG_FLAG_IRQ_PF = BIT(1),
+};
+
+#define PSNET_FLAG_ON(p, f) ((p)->cfg.flags & (f))
+
+static inline u32 psnet_read32(struct psnet *psnet, u32 off)
+{
+ return ioread32(psnet->bars[psnet->barno] + off);
+}
+
+static inline u32 snet_read32(struct snet *snet, u32 off)
+{
+ return ioread32(snet->bar + off);
+}
+
+static inline void snet_write32(struct snet *snet, u32 off, u32 val)
+{
+ iowrite32(val, snet->bar + off);
+}
+
+static inline u64 psnet_read64(struct psnet *psnet, u32 off)
+{
+ u64 val;
+ /* 64bits are written in 2 halves, low part first */
+ val = (u64)psnet_read32(psnet, off);
+ val |= ((u64)psnet_read32(psnet, off + 4) << 32);
+ return val;
+}
+
+static inline void snet_write64(struct snet *snet, u32 off, u64 val)
+{
+ /* The DPU expects a 64bit integer in 2 halves, the low part first */
+ snet_write32(snet, off, (u32)val);
+ snet_write32(snet, off + 4, (u32)(val >> 32));
+}
+
+#if IS_ENABLED(CONFIG_HWMON)
+void psnet_create_hwmon(struct pci_dev *pdev);
+#endif
+
+#endif //_SNET_VDPA_H_
diff --git a/drivers/vdpa/vdpa.c b/drivers/vdpa/vdpa.c
index 8ef7aa1365cc..965e32529eb8 100644
--- a/drivers/vdpa/vdpa.c
+++ b/drivers/vdpa/vdpa.c
@@ -39,6 +39,11 @@ static int vdpa_dev_probe(struct device *d)
u32 max_num, min_num = 1;
int ret = 0;
+ d->dma_mask = &d->coherent_dma_mask;
+ ret = dma_set_mask_and_coherent(d, DMA_BIT_MASK(64));
+ if (ret)
+ return ret;
+
max_num = ops->get_vq_num_max(vdev);
if (ops->get_vq_num_min)
min_num = ops->get_vq_num_min(vdev);
@@ -460,12 +465,28 @@ static int vdpa_nl_mgmtdev_handle_fill(struct sk_buff *msg, const struct vdpa_mg
return 0;
}
+static u64 vdpa_mgmtdev_get_classes(const struct vdpa_mgmt_dev *mdev,
+ unsigned int *nclasses)
+{
+ u64 supported_classes = 0;
+ unsigned int n = 0;
+
+ for (int i = 0; mdev->id_table[i].device; i++) {
+ if (mdev->id_table[i].device > 63)
+ continue;
+ supported_classes |= BIT_ULL(mdev->id_table[i].device);
+ n++;
+ }
+ if (nclasses)
+ *nclasses = n;
+
+ return supported_classes;
+}
+
static int vdpa_mgmtdev_fill(const struct vdpa_mgmt_dev *mdev, struct sk_buff *msg,
u32 portid, u32 seq, int flags)
{
- u64 supported_classes = 0;
void *hdr;
- int i = 0;
int err;
hdr = genlmsg_put(msg, portid, seq, &vdpa_nl_family, flags, VDPA_CMD_MGMTDEV_NEW);
@@ -475,14 +496,9 @@ static int vdpa_mgmtdev_fill(const struct vdpa_mgmt_dev *mdev, struct sk_buff *m
if (err)
goto msg_err;
- while (mdev->id_table[i].device) {
- if (mdev->id_table[i].device <= 63)
- supported_classes |= BIT_ULL(mdev->id_table[i].device);
- i++;
- }
-
if (nla_put_u64_64bit(msg, VDPA_ATTR_MGMTDEV_SUPPORTED_CLASSES,
- supported_classes, VDPA_ATTR_UNSPEC)) {
+ vdpa_mgmtdev_get_classes(mdev, NULL),
+ VDPA_ATTR_UNSPEC)) {
err = -EMSGSIZE;
goto msg_err;
}
@@ -566,13 +582,25 @@ out:
BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MTU) | \
BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MAX_VQP))
+/*
+ * Bitmask for all per-device features: feature bits VIRTIO_TRANSPORT_F_START
+ * through VIRTIO_TRANSPORT_F_END are unset, i.e. 0xfffffc000fffffff for
+ * all 64bit features. If the features are extended beyond 64 bits, or new
+ * "holes" are reserved for other type of features than per-device, this
+ * macro would have to be updated.
+ */
+#define VIRTIO_DEVICE_F_MASK (~0ULL << (VIRTIO_TRANSPORT_F_END + 1) | \
+ ((1ULL << VIRTIO_TRANSPORT_F_START) - 1))
+
static int vdpa_nl_cmd_dev_add_set_doit(struct sk_buff *skb, struct genl_info *info)
{
struct vdpa_dev_set_config config = {};
struct nlattr **nl_attrs = info->attrs;
struct vdpa_mgmt_dev *mdev;
+ unsigned int ncls = 0;
const u8 *macaddr;
const char *name;
+ u64 classes;
int err = 0;
if (!info->attrs[VDPA_ATTR_DEV_NAME])
@@ -601,8 +629,26 @@ static int vdpa_nl_cmd_dev_add_set_doit(struct sk_buff *skb, struct genl_info *i
config.mask |= BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MAX_VQP);
}
if (nl_attrs[VDPA_ATTR_DEV_FEATURES]) {
+ u64 missing = 0x0ULL;
+
config.device_features =
nla_get_u64(nl_attrs[VDPA_ATTR_DEV_FEATURES]);
+ if (nl_attrs[VDPA_ATTR_DEV_NET_CFG_MACADDR] &&
+ !(config.device_features & BIT_ULL(VIRTIO_NET_F_MAC)))
+ missing |= BIT_ULL(VIRTIO_NET_F_MAC);
+ if (nl_attrs[VDPA_ATTR_DEV_NET_CFG_MTU] &&
+ !(config.device_features & BIT_ULL(VIRTIO_NET_F_MTU)))
+ missing |= BIT_ULL(VIRTIO_NET_F_MTU);
+ if (nl_attrs[VDPA_ATTR_DEV_NET_CFG_MAX_VQP] &&
+ config.net.max_vq_pairs > 1 &&
+ !(config.device_features & BIT_ULL(VIRTIO_NET_F_MQ)))
+ missing |= BIT_ULL(VIRTIO_NET_F_MQ);
+ if (missing) {
+ NL_SET_ERR_MSG_FMT_MOD(info->extack,
+ "Missing features 0x%llx for provided attributes",
+ missing);
+ return -EINVAL;
+ }
config.mask |= BIT_ULL(VDPA_ATTR_DEV_FEATURES);
}
@@ -622,13 +668,33 @@ static int vdpa_nl_cmd_dev_add_set_doit(struct sk_buff *skb, struct genl_info *i
err = PTR_ERR(mdev);
goto err;
}
+
if ((config.mask & mdev->config_attr_mask) != config.mask) {
- NL_SET_ERR_MSG_MOD(info->extack,
- "All provided attributes are not supported");
+ NL_SET_ERR_MSG_FMT_MOD(info->extack,
+ "Some provided attributes are not supported: 0x%llx",
+ config.mask & ~mdev->config_attr_mask);
err = -EOPNOTSUPP;
goto err;
}
+ classes = vdpa_mgmtdev_get_classes(mdev, &ncls);
+ if (config.mask & VDPA_DEV_NET_ATTRS_MASK &&
+ !(classes & BIT_ULL(VIRTIO_ID_NET))) {
+ NL_SET_ERR_MSG_MOD(info->extack,
+ "Network class attributes provided on unsupported management device");
+ err = -EINVAL;
+ goto err;
+ }
+ if (!(config.mask & VDPA_DEV_NET_ATTRS_MASK) &&
+ config.mask & BIT_ULL(VDPA_ATTR_DEV_FEATURES) &&
+ classes & BIT_ULL(VIRTIO_ID_NET) && ncls > 1 &&
+ config.device_features & VIRTIO_DEVICE_F_MASK) {
+ NL_SET_ERR_MSG_MOD(info->extack,
+ "Management device supports multi-class while device features specified are ambiguous");
+ err = -EINVAL;
+ goto err;
+ }
+
err = mdev->ops->dev_add(mdev, name, &config);
err:
up_write(&vdpa_dev_lock);
@@ -841,18 +907,25 @@ static int vdpa_dev_net_mac_config_fill(struct sk_buff *msg, u64 features,
sizeof(config->mac), config->mac);
}
+static int vdpa_dev_net_status_config_fill(struct sk_buff *msg, u64 features,
+ const struct virtio_net_config *config)
+{
+ u16 val_u16;
+
+ if ((features & BIT_ULL(VIRTIO_NET_F_STATUS)) == 0)
+ return 0;
+
+ val_u16 = __virtio16_to_cpu(true, config->status);
+ return nla_put_u16(msg, VDPA_ATTR_DEV_NET_STATUS, val_u16);
+}
+
static int vdpa_dev_net_config_fill(struct vdpa_device *vdev, struct sk_buff *msg)
{
struct virtio_net_config config = {};
u64 features_device;
- u16 val_u16;
vdev->config->get_config(vdev, 0, &config, sizeof(config));
- val_u16 = __virtio16_to_cpu(true, config.status);
- if (nla_put_u16(msg, VDPA_ATTR_DEV_NET_STATUS, val_u16))
- return -EMSGSIZE;
-
features_device = vdev->config->get_device_features(vdev);
if (nla_put_u64_64bit(msg, VDPA_ATTR_DEV_FEATURES, features_device,
@@ -865,6 +938,9 @@ static int vdpa_dev_net_config_fill(struct vdpa_device *vdev, struct sk_buff *ms
if (vdpa_dev_net_mac_config_fill(msg, features_device, &config))
return -EMSGSIZE;
+ if (vdpa_dev_net_status_config_fill(msg, features_device, &config))
+ return -EMSGSIZE;
+
return vdpa_dev_net_mq_config_fill(msg, features_device, &config);
}
@@ -1011,7 +1087,7 @@ static int vdpa_dev_vendor_stats_fill(struct vdpa_device *vdev,
switch (device_id) {
case VIRTIO_ID_NET:
if (index > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX) {
- NL_SET_ERR_MSG_MOD(info->extack, "queue index excceeds max value");
+ NL_SET_ERR_MSG_MOD(info->extack, "queue index exceeds max value");
err = -ERANGE;
break;
}
diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim.c b/drivers/vdpa/vdpa_sim/vdpa_sim.c
index cb88891b44a8..6a0a65814626 100644
--- a/drivers/vdpa/vdpa_sim/vdpa_sim.c
+++ b/drivers/vdpa/vdpa_sim/vdpa_sim.c
@@ -17,7 +17,6 @@
#include <linux/vringh.h>
#include <linux/vdpa.h>
#include <linux/vhost_iotlb.h>
-#include <linux/iova.h>
#include <uapi/linux/vdpa.h>
#include "vdpa_sim.h"
@@ -45,13 +44,6 @@ static struct vdpasim *vdpa_to_sim(struct vdpa_device *vdpa)
return container_of(vdpa, struct vdpasim, vdpa);
}
-static struct vdpasim *dev_to_sim(struct device *dev)
-{
- struct vdpa_device *vdpa = dev_to_vdpa(dev);
-
- return vdpa_to_sim(vdpa);
-}
-
static void vdpasim_vq_notify(struct vringh *vring)
{
struct vdpasim_virtqueue *vq =
@@ -66,14 +58,16 @@ static void vdpasim_vq_notify(struct vringh *vring)
static void vdpasim_queue_ready(struct vdpasim *vdpasim, unsigned int idx)
{
struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx];
+ uint16_t last_avail_idx = vq->vring.last_avail_idx;
- vringh_init_iotlb(&vq->vring, vdpasim->features, vq->num, false,
+ vringh_init_iotlb(&vq->vring, vdpasim->features, vq->num, true,
(struct vring_desc *)(uintptr_t)vq->desc_addr,
(struct vring_avail *)
(uintptr_t)vq->driver_addr,
(struct vring_used *)
(uintptr_t)vq->device_addr);
+ vq->vring.last_avail_idx = last_avail_idx;
vq->vring.notify = vdpasim_vq_notify;
}
@@ -104,8 +98,12 @@ static void vdpasim_do_reset(struct vdpasim *vdpasim)
&vdpasim->iommu_lock);
}
- for (i = 0; i < vdpasim->dev_attr.nas; i++)
+ for (i = 0; i < vdpasim->dev_attr.nas; i++) {
vhost_iotlb_reset(&vdpasim->iommu[i]);
+ vhost_iotlb_add_range(&vdpasim->iommu[i], 0, ULONG_MAX,
+ 0, VHOST_MAP_RW);
+ vdpasim->iommu_pt[i] = true;
+ }
vdpasim->running = true;
spin_unlock(&vdpasim->iommu_lock);
@@ -115,133 +113,6 @@ static void vdpasim_do_reset(struct vdpasim *vdpasim)
++vdpasim->generation;
}
-static int dir_to_perm(enum dma_data_direction dir)
-{
- int perm = -EFAULT;
-
- switch (dir) {
- case DMA_FROM_DEVICE:
- perm = VHOST_MAP_WO;
- break;
- case DMA_TO_DEVICE:
- perm = VHOST_MAP_RO;
- break;
- case DMA_BIDIRECTIONAL:
- perm = VHOST_MAP_RW;
- break;
- default:
- break;
- }
-
- return perm;
-}
-
-static dma_addr_t vdpasim_map_range(struct vdpasim *vdpasim, phys_addr_t paddr,
- size_t size, unsigned int perm)
-{
- struct iova *iova;
- dma_addr_t dma_addr;
- int ret;
-
- /* We set the limit_pfn to the maximum (ULONG_MAX - 1) */
- iova = alloc_iova(&vdpasim->iova, size >> iova_shift(&vdpasim->iova),
- ULONG_MAX - 1, true);
- if (!iova)
- return DMA_MAPPING_ERROR;
-
- dma_addr = iova_dma_addr(&vdpasim->iova, iova);
-
- spin_lock(&vdpasim->iommu_lock);
- ret = vhost_iotlb_add_range(&vdpasim->iommu[0], (u64)dma_addr,
- (u64)dma_addr + size - 1, (u64)paddr, perm);
- spin_unlock(&vdpasim->iommu_lock);
-
- if (ret) {
- __free_iova(&vdpasim->iova, iova);
- return DMA_MAPPING_ERROR;
- }
-
- return dma_addr;
-}
-
-static void vdpasim_unmap_range(struct vdpasim *vdpasim, dma_addr_t dma_addr,
- size_t size)
-{
- spin_lock(&vdpasim->iommu_lock);
- vhost_iotlb_del_range(&vdpasim->iommu[0], (u64)dma_addr,
- (u64)dma_addr + size - 1);
- spin_unlock(&vdpasim->iommu_lock);
-
- free_iova(&vdpasim->iova, iova_pfn(&vdpasim->iova, dma_addr));
-}
-
-static dma_addr_t vdpasim_map_page(struct device *dev, struct page *page,
- unsigned long offset, size_t size,
- enum dma_data_direction dir,
- unsigned long attrs)
-{
- struct vdpasim *vdpasim = dev_to_sim(dev);
- phys_addr_t paddr = page_to_phys(page) + offset;
- int perm = dir_to_perm(dir);
-
- if (perm < 0)
- return DMA_MAPPING_ERROR;
-
- return vdpasim_map_range(vdpasim, paddr, size, perm);
-}
-
-static void vdpasim_unmap_page(struct device *dev, dma_addr_t dma_addr,
- size_t size, enum dma_data_direction dir,
- unsigned long attrs)
-{
- struct vdpasim *vdpasim = dev_to_sim(dev);
-
- vdpasim_unmap_range(vdpasim, dma_addr, size);
-}
-
-static void *vdpasim_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_addr, gfp_t flag,
- unsigned long attrs)
-{
- struct vdpasim *vdpasim = dev_to_sim(dev);
- phys_addr_t paddr;
- void *addr;
-
- addr = kmalloc(size, flag);
- if (!addr) {
- *dma_addr = DMA_MAPPING_ERROR;
- return NULL;
- }
-
- paddr = virt_to_phys(addr);
-
- *dma_addr = vdpasim_map_range(vdpasim, paddr, size, VHOST_MAP_RW);
- if (*dma_addr == DMA_MAPPING_ERROR) {
- kfree(addr);
- return NULL;
- }
-
- return addr;
-}
-
-static void vdpasim_free_coherent(struct device *dev, size_t size,
- void *vaddr, dma_addr_t dma_addr,
- unsigned long attrs)
-{
- struct vdpasim *vdpasim = dev_to_sim(dev);
-
- vdpasim_unmap_range(vdpasim, dma_addr, size);
-
- kfree(vaddr);
-}
-
-static const struct dma_map_ops vdpasim_dma_ops = {
- .map_page = vdpasim_map_page,
- .unmap_page = vdpasim_unmap_page,
- .alloc = vdpasim_alloc_coherent,
- .free = vdpasim_free_coherent,
-};
-
static const struct vdpa_config_ops vdpasim_config_ops;
static const struct vdpa_config_ops vdpasim_batch_config_ops;
@@ -249,10 +120,14 @@ struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *dev_attr,
const struct vdpa_dev_set_config *config)
{
const struct vdpa_config_ops *ops;
+ struct vdpa_device *vdpa;
struct vdpasim *vdpasim;
struct device *dev;
int i, ret = -ENOMEM;
+ if (!dev_attr->alloc_size)
+ return ERR_PTR(-EINVAL);
+
if (config->mask & BIT_ULL(VDPA_ATTR_DEV_FEATURES)) {
if (config->device_features &
~dev_attr->supported_features)
@@ -266,14 +141,16 @@ struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *dev_attr,
else
ops = &vdpasim_config_ops;
- vdpasim = vdpa_alloc_device(struct vdpasim, vdpa, NULL, ops,
- dev_attr->ngroups, dev_attr->nas,
- dev_attr->name, false);
- if (IS_ERR(vdpasim)) {
- ret = PTR_ERR(vdpasim);
+ vdpa = __vdpa_alloc_device(NULL, ops,
+ dev_attr->ngroups, dev_attr->nas,
+ dev_attr->alloc_size,
+ dev_attr->name, false);
+ if (IS_ERR(vdpa)) {
+ ret = PTR_ERR(vdpa);
goto err_alloc;
}
+ vdpasim = vdpa_to_sim(vdpa);
vdpasim->dev_attr = *dev_attr;
INIT_WORK(&vdpasim->work, dev_attr->work_fn);
spin_lock_init(&vdpasim->lock);
@@ -283,7 +160,6 @@ struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *dev_attr,
dev->dma_mask = &dev->coherent_dma_mask;
if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)))
goto err_iommu;
- set_dma_ops(dev, &vdpasim_dma_ops);
vdpasim->vdpa.mdev = dev_attr->mgmt_dev;
vdpasim->config = kzalloc(dev_attr->config_size, GFP_KERNEL);
@@ -300,6 +176,11 @@ struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *dev_attr,
if (!vdpasim->iommu)
goto err_iommu;
+ vdpasim->iommu_pt = kmalloc_array(vdpasim->dev_attr.nas,
+ sizeof(*vdpasim->iommu_pt), GFP_KERNEL);
+ if (!vdpasim->iommu_pt)
+ goto err_iommu;
+
for (i = 0; i < vdpasim->dev_attr.nas; i++)
vhost_iotlb_init(&vdpasim->iommu[i], max_iotlb_entries, 0);
@@ -311,13 +192,6 @@ struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *dev_attr,
vringh_set_iotlb(&vdpasim->vqs[i].vring, &vdpasim->iommu[0],
&vdpasim->iommu_lock);
- ret = iova_cache_get();
- if (ret)
- goto err_iommu;
-
- /* For simplicity we use an IOVA allocator with byte granularity */
- init_iova_domain(&vdpasim->iova, 1, 0);
-
vdpasim->vdpa.dma_dev = dev;
return vdpasim;
@@ -356,6 +230,12 @@ static void vdpasim_kick_vq(struct vdpa_device *vdpa, u16 idx)
struct vdpasim *vdpasim = vdpa_to_sim(vdpa);
struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx];
+ if (!vdpasim->running &&
+ (vdpasim->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
+ vdpasim->pending_kick = true;
+ return;
+ }
+
if (vq->ready)
schedule_work(&vdpasim->work);
}
@@ -418,6 +298,18 @@ static int vdpasim_get_vq_state(struct vdpa_device *vdpa, u16 idx,
return 0;
}
+static int vdpasim_get_vq_stats(struct vdpa_device *vdpa, u16 idx,
+ struct sk_buff *msg,
+ struct netlink_ext_ack *extack)
+{
+ struct vdpasim *vdpasim = vdpa_to_sim(vdpa);
+
+ if (vdpasim->dev_attr.get_stats)
+ return vdpasim->dev_attr.get_stats(vdpasim, idx,
+ msg, extack);
+ return -EOPNOTSUPP;
+}
+
static u32 vdpasim_get_vq_align(struct vdpa_device *vdpa)
{
return VDPASIM_QUEUE_ALIGN;
@@ -526,6 +418,27 @@ static int vdpasim_suspend(struct vdpa_device *vdpa)
return 0;
}
+static int vdpasim_resume(struct vdpa_device *vdpa)
+{
+ struct vdpasim *vdpasim = vdpa_to_sim(vdpa);
+ int i;
+
+ spin_lock(&vdpasim->lock);
+ vdpasim->running = true;
+
+ if (vdpasim->pending_kick) {
+ /* Process pending descriptors */
+ for (i = 0; i < vdpasim->dev_attr.nvqs; ++i)
+ vdpasim_kick_vq(vdpa, i);
+
+ vdpasim->pending_kick = false;
+ }
+
+ spin_unlock(&vdpasim->lock);
+
+ return 0;
+}
+
static size_t vdpasim_get_config_size(struct vdpa_device *vdpa)
{
struct vdpasim *vdpasim = vdpa_to_sim(vdpa);
@@ -621,6 +534,7 @@ static int vdpasim_set_map(struct vdpa_device *vdpa, unsigned int asid,
iommu = &vdpasim->iommu[asid];
vhost_iotlb_reset(iommu);
+ vdpasim->iommu_pt[asid] = false;
for (map = vhost_iotlb_itree_first(iotlb, start, last); map;
map = vhost_iotlb_itree_next(map, start, last)) {
@@ -649,6 +563,10 @@ static int vdpasim_dma_map(struct vdpa_device *vdpa, unsigned int asid,
return -EINVAL;
spin_lock(&vdpasim->iommu_lock);
+ if (vdpasim->iommu_pt[asid]) {
+ vhost_iotlb_reset(&vdpasim->iommu[asid]);
+ vdpasim->iommu_pt[asid] = false;
+ }
ret = vhost_iotlb_add_range_ctx(&vdpasim->iommu[asid], iova,
iova + size - 1, pa, perm, opaque);
spin_unlock(&vdpasim->iommu_lock);
@@ -664,6 +582,11 @@ static int vdpasim_dma_unmap(struct vdpa_device *vdpa, unsigned int asid,
if (asid >= vdpasim->dev_attr.nas)
return -EINVAL;
+ if (vdpasim->iommu_pt[asid]) {
+ vhost_iotlb_reset(&vdpasim->iommu[asid]);
+ vdpasim->iommu_pt[asid] = false;
+ }
+
spin_lock(&vdpasim->iommu_lock);
vhost_iotlb_del_range(&vdpasim->iommu[asid], iova, iova + size - 1);
spin_unlock(&vdpasim->iommu_lock);
@@ -683,15 +606,11 @@ static void vdpasim_free(struct vdpa_device *vdpa)
vringh_kiov_cleanup(&vdpasim->vqs[i].in_iov);
}
- if (vdpa_get_dma_dev(vdpa)) {
- put_iova_domain(&vdpasim->iova);
- iova_cache_put();
- }
-
kvfree(vdpasim->buffer);
for (i = 0; i < vdpasim->dev_attr.nas; i++)
vhost_iotlb_reset(&vdpasim->iommu[i]);
kfree(vdpasim->iommu);
+ kfree(vdpasim->iommu_pt);
kfree(vdpasim->vqs);
kfree(vdpasim->config);
}
@@ -704,6 +623,7 @@ static const struct vdpa_config_ops vdpasim_config_ops = {
.set_vq_ready = vdpasim_set_vq_ready,
.get_vq_ready = vdpasim_get_vq_ready,
.set_vq_state = vdpasim_set_vq_state,
+ .get_vendor_vq_stats = vdpasim_get_vq_stats,
.get_vq_state = vdpasim_get_vq_state,
.get_vq_align = vdpasim_get_vq_align,
.get_vq_group = vdpasim_get_vq_group,
@@ -718,6 +638,7 @@ static const struct vdpa_config_ops vdpasim_config_ops = {
.set_status = vdpasim_set_status,
.reset = vdpasim_reset,
.suspend = vdpasim_suspend,
+ .resume = vdpasim_resume,
.get_config_size = vdpasim_get_config_size,
.get_config = vdpasim_get_config,
.set_config = vdpasim_set_config,
@@ -737,6 +658,7 @@ static const struct vdpa_config_ops vdpasim_batch_config_ops = {
.set_vq_ready = vdpasim_set_vq_ready,
.get_vq_ready = vdpasim_get_vq_ready,
.set_vq_state = vdpasim_set_vq_state,
+ .get_vendor_vq_stats = vdpasim_get_vq_stats,
.get_vq_state = vdpasim_get_vq_state,
.get_vq_align = vdpasim_get_vq_align,
.get_vq_group = vdpasim_get_vq_group,
@@ -751,6 +673,7 @@ static const struct vdpa_config_ops vdpasim_batch_config_ops = {
.set_status = vdpasim_set_status,
.reset = vdpasim_reset,
.suspend = vdpasim_suspend,
+ .resume = vdpasim_resume,
.get_config_size = vdpasim_get_config_size,
.get_config = vdpasim_get_config,
.set_config = vdpasim_set_config,
diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim.h b/drivers/vdpa/vdpa_sim/vdpa_sim.h
index 0e78737dcc16..144858636c10 100644
--- a/drivers/vdpa/vdpa_sim/vdpa_sim.h
+++ b/drivers/vdpa/vdpa_sim/vdpa_sim.h
@@ -37,6 +37,7 @@ struct vdpasim_dev_attr {
struct vdpa_mgmt_dev *mgmt_dev;
const char *name;
u64 supported_features;
+ size_t alloc_size;
size_t config_size;
size_t buffer_size;
int nvqs;
@@ -47,6 +48,9 @@ struct vdpasim_dev_attr {
work_func_t work_fn;
void (*get_config)(struct vdpasim *vdpasim, void *config);
void (*set_config)(struct vdpasim *vdpasim, const void *config);
+ int (*get_stats)(struct vdpasim *vdpasim, u16 idx,
+ struct sk_buff *msg,
+ struct netlink_ext_ack *extack);
};
/* State of each vdpasim device */
@@ -60,13 +64,14 @@ struct vdpasim {
/* virtio config according to device type */
void *config;
struct vhost_iotlb *iommu;
- struct iova_domain iova;
+ bool *iommu_pt;
void *buffer;
u32 status;
u32 generation;
u64 features;
u32 groups;
bool running;
+ bool pending_kick;
/* spinlock to synchronize iommu table */
spinlock_t iommu_lock;
};
diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c b/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c
index f745926237a8..5117959bed8a 100644
--- a/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c
+++ b/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c
@@ -378,6 +378,7 @@ static int vdpasim_blk_dev_add(struct vdpa_mgmt_dev *mdev, const char *name,
dev_attr.nvqs = VDPASIM_BLK_VQ_NUM;
dev_attr.ngroups = VDPASIM_BLK_GROUP_NUM;
dev_attr.nas = VDPASIM_BLK_AS_NUM;
+ dev_attr.alloc_size = sizeof(struct vdpasim);
dev_attr.config_size = sizeof(struct virtio_blk_config);
dev_attr.get_config = vdpasim_blk_get_config;
dev_attr.work_fn = vdpasim_blk_work;
diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim_net.c b/drivers/vdpa/vdpa_sim/vdpa_sim_net.c
index 584b975a98a7..862f405362de 100644
--- a/drivers/vdpa/vdpa_sim/vdpa_sim_net.c
+++ b/drivers/vdpa/vdpa_sim/vdpa_sim_net.c
@@ -15,6 +15,7 @@
#include <linux/etherdevice.h>
#include <linux/vringh.h>
#include <linux/vdpa.h>
+#include <net/netlink.h>
#include <uapi/linux/virtio_net.h>
#include <uapi/linux/vdpa.h>
@@ -27,6 +28,7 @@
#define VDPASIM_NET_FEATURES (VDPASIM_FEATURES | \
(1ULL << VIRTIO_NET_F_MAC) | \
+ (1ULL << VIRTIO_NET_F_STATUS) | \
(1ULL << VIRTIO_NET_F_MTU) | \
(1ULL << VIRTIO_NET_F_CTRL_VQ) | \
(1ULL << VIRTIO_NET_F_CTRL_MAC_ADDR))
@@ -36,6 +38,34 @@
#define VDPASIM_NET_AS_NUM 2
#define VDPASIM_NET_GROUP_NUM 2
+struct vdpasim_dataq_stats {
+ struct u64_stats_sync syncp;
+ u64 pkts;
+ u64 bytes;
+ u64 drops;
+ u64 errors;
+ u64 overruns;
+};
+
+struct vdpasim_cq_stats {
+ struct u64_stats_sync syncp;
+ u64 requests;
+ u64 successes;
+ u64 errors;
+};
+
+struct vdpasim_net{
+ struct vdpasim vdpasim;
+ struct vdpasim_dataq_stats tx_stats;
+ struct vdpasim_dataq_stats rx_stats;
+ struct vdpasim_cq_stats cq_stats;
+};
+
+static struct vdpasim_net *sim_to_net(struct vdpasim *vdpasim)
+{
+ return container_of(vdpasim, struct vdpasim_net, vdpasim);
+}
+
static void vdpasim_net_complete(struct vdpasim_virtqueue *vq, size_t len)
{
/* Make sure data is wrote before advancing index */
@@ -96,9 +126,11 @@ static virtio_net_ctrl_ack vdpasim_handle_ctrl_mac(struct vdpasim *vdpasim,
static void vdpasim_handle_cvq(struct vdpasim *vdpasim)
{
struct vdpasim_virtqueue *cvq = &vdpasim->vqs[2];
+ struct vdpasim_net *net = sim_to_net(vdpasim);
virtio_net_ctrl_ack status = VIRTIO_NET_ERR;
struct virtio_net_ctrl_hdr ctrl;
size_t read, write;
+ u64 requests = 0, errors = 0, successes = 0;
int err;
if (!(vdpasim->features & (1ULL << VIRTIO_NET_F_CTRL_VQ)))
@@ -114,10 +146,13 @@ static void vdpasim_handle_cvq(struct vdpasim *vdpasim)
if (err <= 0)
break;
+ ++requests;
read = vringh_iov_pull_iotlb(&cvq->vring, &cvq->in_iov, &ctrl,
sizeof(ctrl));
- if (read != sizeof(ctrl))
+ if (read != sizeof(ctrl)) {
+ ++errors;
break;
+ }
switch (ctrl.class) {
case VIRTIO_NET_CTRL_MAC:
@@ -127,6 +162,11 @@ static void vdpasim_handle_cvq(struct vdpasim *vdpasim)
break;
}
+ if (status == VIRTIO_NET_OK)
+ ++successes;
+ else
+ ++errors;
+
/* Make sure data is wrote before advancing index */
smp_wmb();
@@ -144,6 +184,12 @@ static void vdpasim_handle_cvq(struct vdpasim *vdpasim)
cvq->cb(cvq->private);
local_bh_enable();
}
+
+ u64_stats_update_begin(&net->cq_stats.syncp);
+ net->cq_stats.requests += requests;
+ net->cq_stats.errors += errors;
+ net->cq_stats.successes += successes;
+ u64_stats_update_end(&net->cq_stats.syncp);
}
static void vdpasim_net_work(struct work_struct *work)
@@ -151,8 +197,10 @@ static void vdpasim_net_work(struct work_struct *work)
struct vdpasim *vdpasim = container_of(work, struct vdpasim, work);
struct vdpasim_virtqueue *txq = &vdpasim->vqs[1];
struct vdpasim_virtqueue *rxq = &vdpasim->vqs[0];
+ struct vdpasim_net *net = sim_to_net(vdpasim);
ssize_t read, write;
- int pkts = 0;
+ u64 tx_pkts = 0, rx_pkts = 0, tx_bytes = 0, rx_bytes = 0;
+ u64 rx_drops = 0, rx_overruns = 0, rx_errors = 0, tx_errors = 0;
int err;
spin_lock(&vdpasim->lock);
@@ -171,14 +219,21 @@ static void vdpasim_net_work(struct work_struct *work)
while (true) {
err = vringh_getdesc_iotlb(&txq->vring, &txq->out_iov, NULL,
&txq->head, GFP_ATOMIC);
- if (err <= 0)
+ if (err <= 0) {
+ if (err)
+ ++tx_errors;
break;
+ }
+ ++tx_pkts;
read = vringh_iov_pull_iotlb(&txq->vring, &txq->out_iov,
vdpasim->buffer,
PAGE_SIZE);
+ tx_bytes += read;
+
if (!receive_filter(vdpasim, read)) {
+ ++rx_drops;
vdpasim_net_complete(txq, 0);
continue;
}
@@ -186,19 +241,25 @@ static void vdpasim_net_work(struct work_struct *work)
err = vringh_getdesc_iotlb(&rxq->vring, NULL, &rxq->in_iov,
&rxq->head, GFP_ATOMIC);
if (err <= 0) {
+ ++rx_overruns;
vdpasim_net_complete(txq, 0);
break;
}
write = vringh_iov_push_iotlb(&rxq->vring, &rxq->in_iov,
vdpasim->buffer, read);
- if (write <= 0)
+ if (write <= 0) {
+ ++rx_errors;
break;
+ }
+
+ ++rx_pkts;
+ rx_bytes += write;
vdpasim_net_complete(txq, 0);
vdpasim_net_complete(rxq, write);
- if (++pkts > 4) {
+ if (tx_pkts > 4) {
schedule_work(&vdpasim->work);
goto out;
}
@@ -206,6 +267,145 @@ static void vdpasim_net_work(struct work_struct *work)
out:
spin_unlock(&vdpasim->lock);
+
+ u64_stats_update_begin(&net->tx_stats.syncp);
+ net->tx_stats.pkts += tx_pkts;
+ net->tx_stats.bytes += tx_bytes;
+ net->tx_stats.errors += tx_errors;
+ u64_stats_update_end(&net->tx_stats.syncp);
+
+ u64_stats_update_begin(&net->rx_stats.syncp);
+ net->rx_stats.pkts += rx_pkts;
+ net->rx_stats.bytes += rx_bytes;
+ net->rx_stats.drops += rx_drops;
+ net->rx_stats.errors += rx_errors;
+ net->rx_stats.overruns += rx_overruns;
+ u64_stats_update_end(&net->rx_stats.syncp);
+}
+
+static int vdpasim_net_get_stats(struct vdpasim *vdpasim, u16 idx,
+ struct sk_buff *msg,
+ struct netlink_ext_ack *extack)
+{
+ struct vdpasim_net *net = sim_to_net(vdpasim);
+ u64 rx_pkts, rx_bytes, rx_errors, rx_overruns, rx_drops;
+ u64 tx_pkts, tx_bytes, tx_errors, tx_drops;
+ u64 cq_requests, cq_successes, cq_errors;
+ unsigned int start;
+ int err = -EMSGSIZE;
+
+ switch(idx) {
+ case 0:
+ do {
+ start = u64_stats_fetch_begin(&net->rx_stats.syncp);
+ rx_pkts = net->rx_stats.pkts;
+ rx_bytes = net->rx_stats.bytes;
+ rx_errors = net->rx_stats.errors;
+ rx_overruns = net->rx_stats.overruns;
+ rx_drops = net->rx_stats.drops;
+ } while (u64_stats_fetch_retry(&net->rx_stats.syncp, start));
+
+ if (nla_put_string(msg, VDPA_ATTR_DEV_VENDOR_ATTR_NAME,
+ "rx packets"))
+ break;
+ if (nla_put_u64_64bit(msg, VDPA_ATTR_DEV_VENDOR_ATTR_VALUE,
+ rx_pkts, VDPA_ATTR_PAD))
+ break;
+ if (nla_put_string(msg, VDPA_ATTR_DEV_VENDOR_ATTR_NAME,
+ "rx bytes"))
+ break;
+ if (nla_put_u64_64bit(msg, VDPA_ATTR_DEV_VENDOR_ATTR_VALUE,
+ rx_bytes, VDPA_ATTR_PAD))
+ break;
+ if (nla_put_string(msg, VDPA_ATTR_DEV_VENDOR_ATTR_NAME,
+ "rx errors"))
+ break;
+ if (nla_put_u64_64bit(msg, VDPA_ATTR_DEV_VENDOR_ATTR_VALUE,
+ rx_errors, VDPA_ATTR_PAD))
+ break;
+ if (nla_put_string(msg, VDPA_ATTR_DEV_VENDOR_ATTR_NAME,
+ "rx overruns"))
+ break;
+ if (nla_put_u64_64bit(msg, VDPA_ATTR_DEV_VENDOR_ATTR_VALUE,
+ rx_overruns, VDPA_ATTR_PAD))
+ break;
+ if (nla_put_string(msg, VDPA_ATTR_DEV_VENDOR_ATTR_NAME,
+ "rx drops"))
+ break;
+ if (nla_put_u64_64bit(msg, VDPA_ATTR_DEV_VENDOR_ATTR_VALUE,
+ rx_drops, VDPA_ATTR_PAD))
+ break;
+ err = 0;
+ break;
+ case 1:
+ do {
+ start = u64_stats_fetch_begin(&net->tx_stats.syncp);
+ tx_pkts = net->tx_stats.pkts;
+ tx_bytes = net->tx_stats.bytes;
+ tx_errors = net->tx_stats.errors;
+ tx_drops = net->tx_stats.drops;
+ } while (u64_stats_fetch_retry(&net->tx_stats.syncp, start));
+
+ if (nla_put_string(msg, VDPA_ATTR_DEV_VENDOR_ATTR_NAME,
+ "tx packets"))
+ break;
+ if (nla_put_u64_64bit(msg, VDPA_ATTR_DEV_VENDOR_ATTR_VALUE,
+ tx_pkts, VDPA_ATTR_PAD))
+ break;
+ if (nla_put_string(msg, VDPA_ATTR_DEV_VENDOR_ATTR_NAME,
+ "tx bytes"))
+ break;
+ if (nla_put_u64_64bit(msg, VDPA_ATTR_DEV_VENDOR_ATTR_VALUE,
+ tx_bytes, VDPA_ATTR_PAD))
+ break;
+ if (nla_put_string(msg, VDPA_ATTR_DEV_VENDOR_ATTR_NAME,
+ "tx errors"))
+ break;
+ if (nla_put_u64_64bit(msg, VDPA_ATTR_DEV_VENDOR_ATTR_VALUE,
+ tx_errors, VDPA_ATTR_PAD))
+ break;
+ if (nla_put_string(msg, VDPA_ATTR_DEV_VENDOR_ATTR_NAME,
+ "tx drops"))
+ break;
+ if (nla_put_u64_64bit(msg, VDPA_ATTR_DEV_VENDOR_ATTR_VALUE,
+ tx_drops, VDPA_ATTR_PAD))
+ break;
+ err = 0;
+ break;
+ case 2:
+ do {
+ start = u64_stats_fetch_begin(&net->cq_stats.syncp);
+ cq_requests = net->cq_stats.requests;
+ cq_successes = net->cq_stats.successes;
+ cq_errors = net->cq_stats.errors;
+ } while (u64_stats_fetch_retry(&net->cq_stats.syncp, start));
+
+ if (nla_put_string(msg, VDPA_ATTR_DEV_VENDOR_ATTR_NAME,
+ "cvq requests"))
+ break;
+ if (nla_put_u64_64bit(msg, VDPA_ATTR_DEV_VENDOR_ATTR_VALUE,
+ cq_requests, VDPA_ATTR_PAD))
+ break;
+ if (nla_put_string(msg, VDPA_ATTR_DEV_VENDOR_ATTR_NAME,
+ "cvq successes"))
+ break;
+ if (nla_put_u64_64bit(msg, VDPA_ATTR_DEV_VENDOR_ATTR_VALUE,
+ cq_successes, VDPA_ATTR_PAD))
+ break;
+ if (nla_put_string(msg, VDPA_ATTR_DEV_VENDOR_ATTR_NAME,
+ "cvq errors"))
+ break;
+ if (nla_put_u64_64bit(msg, VDPA_ATTR_DEV_VENDOR_ATTR_VALUE,
+ cq_errors, VDPA_ATTR_PAD))
+ break;
+ err = 0;
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+
+ return err;
}
static void vdpasim_net_get_config(struct vdpasim *vdpasim, void *config)
@@ -242,6 +442,7 @@ static int vdpasim_net_dev_add(struct vdpa_mgmt_dev *mdev, const char *name,
const struct vdpa_dev_set_config *config)
{
struct vdpasim_dev_attr dev_attr = {};
+ struct vdpasim_net *net;
struct vdpasim *simdev;
int ret;
@@ -252,9 +453,11 @@ static int vdpasim_net_dev_add(struct vdpa_mgmt_dev *mdev, const char *name,
dev_attr.nvqs = VDPASIM_NET_VQ_NUM;
dev_attr.ngroups = VDPASIM_NET_GROUP_NUM;
dev_attr.nas = VDPASIM_NET_AS_NUM;
+ dev_attr.alloc_size = sizeof(struct vdpasim_net);
dev_attr.config_size = sizeof(struct virtio_net_config);
dev_attr.get_config = vdpasim_net_get_config;
dev_attr.work_fn = vdpasim_net_work;
+ dev_attr.get_stats = vdpasim_net_get_stats;
dev_attr.buffer_size = PAGE_SIZE;
simdev = vdpasim_create(&dev_attr, config);
@@ -267,6 +470,12 @@ static int vdpasim_net_dev_add(struct vdpa_mgmt_dev *mdev, const char *name,
if (ret)
goto reg_err;
+ net = sim_to_net(simdev);
+
+ u64_stats_init(&net->tx_stats.syncp);
+ u64_stats_init(&net->rx_stats.syncp);
+ u64_stats_init(&net->cq_stats.syncp);
+
return 0;
reg_err:
diff --git a/drivers/vdpa/vdpa_user/iova_domain.c b/drivers/vdpa/vdpa_user/iova_domain.c
index e682bc7ee6c9..5e4a77b9bae6 100644
--- a/drivers/vdpa/vdpa_user/iova_domain.c
+++ b/drivers/vdpa/vdpa_user/iova_domain.c
@@ -512,7 +512,7 @@ static int vduse_domain_mmap(struct file *file, struct vm_area_struct *vma)
{
struct vduse_iova_domain *domain = file->private_data;
- vma->vm_flags |= VM_DONTDUMP | VM_DONTEXPAND;
+ vm_flags_set(vma, VM_DONTDUMP | VM_DONTEXPAND);
vma->vm_private_data = domain;
vma->vm_ops = &vduse_domain_mmap_ops;
diff --git a/drivers/vfio/Kconfig b/drivers/vfio/Kconfig
index a8f544629467..89e06c981e43 100644
--- a/drivers/vfio/Kconfig
+++ b/drivers/vfio/Kconfig
@@ -32,6 +32,7 @@ config VFIO_IOMMU_SPAPR_TCE
tristate
depends on SPAPR_TCE_IOMMU
default VFIO
+endif
config VFIO_NOIOMMU
bool "VFIO No-IOMMU support"
@@ -46,7 +47,6 @@ config VFIO_NOIOMMU
this mode since there is no IOMMU to provide DMA translation.
If you don't know what to do here, say N.
-endif
config VFIO_VIRQFD
bool
diff --git a/drivers/vfio/container.c b/drivers/vfio/container.c
index b7a9560ab25e..d53d08f16973 100644
--- a/drivers/vfio/container.c
+++ b/drivers/vfio/container.c
@@ -29,13 +29,6 @@ static struct vfio {
struct mutex iommu_drivers_lock;
} vfio;
-#ifdef CONFIG_VFIO_NOIOMMU
-bool vfio_noiommu __read_mostly;
-module_param_named(enable_unsafe_noiommu_mode,
- vfio_noiommu, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(enable_unsafe_noiommu_mode, "Enable UNSAFE, no-IOMMU mode. This mode provides no device isolation, no DMA translation, no host kernel protection, cannot be used for device assignment to virtual machines, requires RAWIO permissions, and will taint the kernel. If you do not know what this is for, step away. (default: false)");
-#endif
-
static void *vfio_noiommu_open(unsigned long arg)
{
if (arg != VFIO_NOIOMMU_IOMMU)
@@ -367,7 +360,7 @@ static int vfio_fops_open(struct inode *inode, struct file *filep)
{
struct vfio_container *container;
- container = kzalloc(sizeof(*container), GFP_KERNEL);
+ container = kzalloc(sizeof(*container), GFP_KERNEL_ACCOUNT);
if (!container)
return -ENOMEM;
@@ -383,11 +376,6 @@ static int vfio_fops_open(struct inode *inode, struct file *filep)
static int vfio_fops_release(struct inode *inode, struct file *filep)
{
struct vfio_container *container = filep->private_data;
- struct vfio_iommu_driver *driver = container->iommu_driver;
-
- if (driver && driver->ops->notify)
- driver->ops->notify(container->iommu_data,
- VFIO_IOMMU_CONTAINER_CLOSE);
filep->private_data = NULL;
diff --git a/drivers/vfio/fsl-mc/vfio_fsl_mc.c b/drivers/vfio/fsl-mc/vfio_fsl_mc.c
index defeb8510ace..c89a047a4cd8 100644
--- a/drivers/vfio/fsl-mc/vfio_fsl_mc.c
+++ b/drivers/vfio/fsl-mc/vfio_fsl_mc.c
@@ -28,7 +28,7 @@ static int vfio_fsl_mc_open_device(struct vfio_device *core_vdev)
int i;
vdev->regions = kcalloc(count, sizeof(struct vfio_fsl_mc_region),
- GFP_KERNEL);
+ GFP_KERNEL_ACCOUNT);
if (!vdev->regions)
return -ENOMEM;
diff --git a/drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c b/drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c
index 64d01f3fb13d..c51229fccbd6 100644
--- a/drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c
+++ b/drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c
@@ -29,7 +29,7 @@ static int vfio_fsl_mc_irqs_allocate(struct vfio_fsl_mc_device *vdev)
irq_count = mc_dev->obj_desc.irq_count;
- mc_irq = kcalloc(irq_count, sizeof(*mc_irq), GFP_KERNEL);
+ mc_irq = kcalloc(irq_count, sizeof(*mc_irq), GFP_KERNEL_ACCOUNT);
if (!mc_irq)
return -ENOMEM;
@@ -77,7 +77,7 @@ static int vfio_set_trigger(struct vfio_fsl_mc_device *vdev,
if (fd < 0) /* Disable only */
return 0;
- irq->name = kasprintf(GFP_KERNEL, "vfio-irq[%d](%s)",
+ irq->name = kasprintf(GFP_KERNEL_ACCOUNT, "vfio-irq[%d](%s)",
hwirq, dev_name(&vdev->mc_dev->dev));
if (!irq->name)
return -ENOMEM;
diff --git a/drivers/vfio/group.c b/drivers/vfio/group.c
index bb24b2f0271e..27d5ba7cf9dc 100644
--- a/drivers/vfio/group.c
+++ b/drivers/vfio/group.c
@@ -133,11 +133,14 @@ static int vfio_group_ioctl_set_container(struct vfio_group *group,
iommufd = iommufd_ctx_from_file(f.file);
if (!IS_ERR(iommufd)) {
- u32 ioas_id;
+ if (IS_ENABLED(CONFIG_VFIO_NOIOMMU) &&
+ group->type == VFIO_NO_IOMMU)
+ ret = iommufd_vfio_compat_set_no_iommu(iommufd);
+ else
+ ret = iommufd_vfio_compat_ioas_create(iommufd);
- ret = iommufd_vfio_compat_ioas_id(iommufd, &ioas_id);
if (ret) {
- iommufd_ctx_put(group->iommufd);
+ iommufd_ctx_put(iommufd);
goto out_unlock;
}
@@ -154,6 +157,18 @@ out_unlock:
return ret;
}
+static void vfio_device_group_get_kvm_safe(struct vfio_device *device)
+{
+ spin_lock(&device->group->kvm_ref_lock);
+ if (!device->group->kvm)
+ goto unlock;
+
+ _vfio_device_get_kvm_safe(device, device->group->kvm);
+
+unlock:
+ spin_unlock(&device->group->kvm_ref_lock);
+}
+
static int vfio_device_group_open(struct vfio_device *device)
{
int ret;
@@ -164,13 +179,23 @@ static int vfio_device_group_open(struct vfio_device *device)
goto out_unlock;
}
+ mutex_lock(&device->dev_set->lock);
+
/*
- * Here we pass the KVM pointer with the group under the lock. If the
- * device driver will use it, it must obtain a reference and release it
- * during close_device.
+ * Before the first device open, get the KVM pointer currently
+ * associated with the group (if there is one) and obtain a reference
+ * now that will be held until the open_count reaches 0 again. Save
+ * the pointer in the device for use by drivers.
*/
- ret = vfio_device_open(device, device->group->iommufd,
- device->group->kvm);
+ if (device->open_count == 0)
+ vfio_device_group_get_kvm_safe(device);
+
+ ret = vfio_device_open(device, device->group->iommufd);
+
+ if (device->open_count == 0)
+ vfio_device_put_kvm(device);
+
+ mutex_unlock(&device->dev_set->lock);
out_unlock:
mutex_unlock(&device->group->group_lock);
@@ -180,7 +205,14 @@ out_unlock:
void vfio_device_group_close(struct vfio_device *device)
{
mutex_lock(&device->group->group_lock);
+ mutex_lock(&device->dev_set->lock);
+
vfio_device_close(device, device->group->iommufd);
+
+ if (device->open_count == 0)
+ vfio_device_put_kvm(device);
+
+ mutex_unlock(&device->dev_set->lock);
mutex_unlock(&device->group->group_lock);
}
@@ -450,6 +482,7 @@ static struct vfio_group *vfio_group_alloc(struct iommu_group *iommu_group,
refcount_set(&group->drivers, 1);
mutex_init(&group->group_lock);
+ spin_lock_init(&group->kvm_ref_lock);
INIT_LIST_HEAD(&group->device_list);
mutex_init(&group->device_lock);
group->iommu_group = iommu_group;
@@ -803,9 +836,9 @@ void vfio_file_set_kvm(struct file *file, struct kvm *kvm)
if (!vfio_file_is_group(file))
return;
- mutex_lock(&group->group_lock);
+ spin_lock(&group->kvm_ref_lock);
group->kvm = kvm;
- mutex_unlock(&group->group_lock);
+ spin_unlock(&group->kvm_ref_lock);
}
EXPORT_SYMBOL_GPL(vfio_file_set_kvm);
diff --git a/drivers/vfio/iommufd.c b/drivers/vfio/iommufd.c
index 4f82a6fa7c6c..db4efbd56042 100644
--- a/drivers/vfio/iommufd.c
+++ b/drivers/vfio/iommufd.c
@@ -18,6 +18,20 @@ int vfio_iommufd_bind(struct vfio_device *vdev, struct iommufd_ctx *ictx)
lockdep_assert_held(&vdev->dev_set->lock);
+ if (vfio_device_is_noiommu(vdev)) {
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+
+ /*
+ * Require no compat ioas to be assigned to proceed. The basic
+ * statement is that the user cannot have done something that
+ * implies they expected translation to exist
+ */
+ if (!iommufd_vfio_compat_ioas_get_id(ictx, &ioas_id))
+ return -EPERM;
+ return 0;
+ }
+
/*
* If the driver doesn't provide this op then it means the device does
* not do DMA at all. So nothing to do.
@@ -29,7 +43,7 @@ int vfio_iommufd_bind(struct vfio_device *vdev, struct iommufd_ctx *ictx)
if (ret)
return ret;
- ret = iommufd_vfio_compat_ioas_id(ictx, &ioas_id);
+ ret = iommufd_vfio_compat_ioas_get_id(ictx, &ioas_id);
if (ret)
goto err_unbind;
ret = vdev->ops->attach_ioas(vdev, &ioas_id);
@@ -52,6 +66,9 @@ void vfio_iommufd_unbind(struct vfio_device *vdev)
{
lockdep_assert_held(&vdev->dev_set->lock);
+ if (vfio_device_is_noiommu(vdev))
+ return;
+
if (vdev->ops->unbind_iommufd)
vdev->ops->unbind_iommufd(vdev);
}
diff --git a/drivers/vfio/mdev/Kconfig b/drivers/vfio/mdev/Kconfig
index 646dbed44eb2..e5fb84e07965 100644
--- a/drivers/vfio/mdev/Kconfig
+++ b/drivers/vfio/mdev/Kconfig
@@ -1,10 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
config VFIO_MDEV
- tristate "Mediated device driver framework"
- default n
- help
- Provides a framework to virtualize devices.
- See Documentation/driver-api/vfio-mediated-device.rst for more details.
-
- If you don't know what do here, say N.
+ tristate
diff --git a/drivers/vfio/mdev/mdev_sysfs.c b/drivers/vfio/mdev/mdev_sysfs.c
index abe3359dd477..e4490639d383 100644
--- a/drivers/vfio/mdev/mdev_sysfs.c
+++ b/drivers/vfio/mdev/mdev_sysfs.c
@@ -96,7 +96,7 @@ static MDEV_TYPE_ATTR_RO(device_api);
static ssize_t name_show(struct mdev_type *mtype,
struct mdev_type_attribute *attr, char *buf)
{
- return sprintf(buf, "%s\n",
+ return sysfs_emit(buf, "%s\n",
mtype->pretty_name ? mtype->pretty_name : mtype->sysfs_name);
}
diff --git a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
index 0bba3b05c6c7..a117eaf21c14 100644
--- a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
+++ b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
@@ -744,7 +744,7 @@ hisi_acc_vf_pci_resume(struct hisi_acc_vf_core_device *hisi_acc_vdev)
{
struct hisi_acc_vf_migration_file *migf;
- migf = kzalloc(sizeof(*migf), GFP_KERNEL);
+ migf = kzalloc(sizeof(*migf), GFP_KERNEL_ACCOUNT);
if (!migf)
return ERR_PTR(-ENOMEM);
@@ -863,7 +863,7 @@ hisi_acc_open_saving_migf(struct hisi_acc_vf_core_device *hisi_acc_vdev)
struct hisi_acc_vf_migration_file *migf;
int ret;
- migf = kzalloc(sizeof(*migf), GFP_KERNEL);
+ migf = kzalloc(sizeof(*migf), GFP_KERNEL_ACCOUNT);
if (!migf)
return ERR_PTR(-ENOMEM);
diff --git a/drivers/vfio/pci/mlx5/cmd.c b/drivers/vfio/pci/mlx5/cmd.c
index 64e68d13cb98..deed156e6165 100644
--- a/drivers/vfio/pci/mlx5/cmd.c
+++ b/drivers/vfio/pci/mlx5/cmd.c
@@ -7,6 +7,29 @@
enum { CQ_OK = 0, CQ_EMPTY = -1, CQ_POLL_ERR = -2 };
+static int mlx5vf_is_migratable(struct mlx5_core_dev *mdev, u16 func_id)
+{
+ int query_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
+ void *query_cap = NULL, *cap;
+ int ret;
+
+ query_cap = kzalloc(query_sz, GFP_KERNEL);
+ if (!query_cap)
+ return -ENOMEM;
+
+ ret = mlx5_vport_get_other_func_cap(mdev, func_id, query_cap,
+ MLX5_CAP_GENERAL_2);
+ if (ret)
+ goto out;
+
+ cap = MLX5_ADDR_OF(query_hca_cap_out, query_cap, capability);
+ if (!MLX5_GET(cmd_hca_cap_2, cap, migratable))
+ ret = -EOPNOTSUPP;
+out:
+ kfree(query_cap);
+ return ret;
+}
+
static int mlx5vf_cmd_get_vhca_id(struct mlx5_core_dev *mdev, u16 function_id,
u16 *vhca_id);
static void
@@ -195,6 +218,10 @@ void mlx5vf_cmd_set_migratable(struct mlx5vf_pci_core_device *mvdev,
if (mvdev->vf_id < 0)
goto end;
+ ret = mlx5vf_is_migratable(mvdev->mdev, mvdev->vf_id + 1);
+ if (ret)
+ goto end;
+
if (mlx5vf_cmd_get_vhca_id(mvdev->mdev, mvdev->vf_id + 1,
&mvdev->vhca_id))
goto end;
@@ -373,7 +400,7 @@ mlx5vf_alloc_data_buffer(struct mlx5_vf_migration_file *migf,
struct mlx5_vhca_data_buffer *buf;
int ret;
- buf = kzalloc(sizeof(*buf), GFP_KERNEL);
+ buf = kzalloc(sizeof(*buf), GFP_KERNEL_ACCOUNT);
if (!buf)
return ERR_PTR(-ENOMEM);
@@ -473,7 +500,7 @@ void mlx5vf_mig_file_cleanup_cb(struct work_struct *_work)
}
static int add_buf_header(struct mlx5_vhca_data_buffer *header_buf,
- size_t image_size)
+ size_t image_size, bool initial_pre_copy)
{
struct mlx5_vf_migration_file *migf = header_buf->migf;
struct mlx5_vf_migration_header header = {};
@@ -481,7 +508,9 @@ static int add_buf_header(struct mlx5_vhca_data_buffer *header_buf,
struct page *page;
u8 *to_buff;
- header.image_size = cpu_to_le64(image_size);
+ header.record_size = cpu_to_le64(image_size);
+ header.flags = cpu_to_le32(MLX5_MIGF_HEADER_FLAGS_TAG_MANDATORY);
+ header.tag = cpu_to_le32(MLX5_MIGF_HEADER_TAG_FW_DATA);
page = mlx5vf_get_migration_page(header_buf, 0);
if (!page)
return -EINVAL;
@@ -489,12 +518,13 @@ static int add_buf_header(struct mlx5_vhca_data_buffer *header_buf,
memcpy(to_buff, &header, sizeof(header));
kunmap_local(to_buff);
header_buf->length = sizeof(header);
- header_buf->header_image_size = image_size;
header_buf->start_pos = header_buf->migf->max_pos;
migf->max_pos += header_buf->length;
spin_lock_irqsave(&migf->list_lock, flags);
list_add_tail(&header_buf->buf_elm, &migf->buf_list);
spin_unlock_irqrestore(&migf->list_lock, flags);
+ if (initial_pre_copy)
+ migf->pre_copy_initial_bytes += sizeof(header);
return 0;
}
@@ -508,11 +538,14 @@ static void mlx5vf_save_callback(int status, struct mlx5_async_work *context)
if (!status) {
size_t image_size;
unsigned long flags;
+ bool initial_pre_copy = migf->state != MLX5_MIGF_STATE_PRE_COPY &&
+ !async_data->last_chunk;
image_size = MLX5_GET(save_vhca_state_out, async_data->out,
actual_image_size);
if (async_data->header_buf) {
- status = add_buf_header(async_data->header_buf, image_size);
+ status = add_buf_header(async_data->header_buf, image_size,
+ initial_pre_copy);
if (status)
goto err;
}
@@ -522,6 +555,8 @@ static void mlx5vf_save_callback(int status, struct mlx5_async_work *context)
spin_lock_irqsave(&migf->list_lock, flags);
list_add_tail(&async_data->buf->buf_elm, &migf->buf_list);
spin_unlock_irqrestore(&migf->list_lock, flags);
+ if (initial_pre_copy)
+ migf->pre_copy_initial_bytes += image_size;
migf->state = async_data->last_chunk ?
MLX5_MIGF_STATE_COMPLETE : MLX5_MIGF_STATE_PRE_COPY;
wake_up_interruptible(&migf->poll_wait);
@@ -583,11 +618,16 @@ int mlx5vf_cmd_save_vhca_state(struct mlx5vf_pci_core_device *mvdev,
}
if (MLX5VF_PRE_COPY_SUPP(mvdev)) {
- header_buf = mlx5vf_get_data_buffer(migf,
- sizeof(struct mlx5_vf_migration_header), DMA_NONE);
- if (IS_ERR(header_buf)) {
- err = PTR_ERR(header_buf);
- goto err_free;
+ if (async_data->last_chunk && migf->buf_header) {
+ header_buf = migf->buf_header;
+ migf->buf_header = NULL;
+ } else {
+ header_buf = mlx5vf_get_data_buffer(migf,
+ sizeof(struct mlx5_vf_migration_header), DMA_NONE);
+ if (IS_ERR(header_buf)) {
+ err = PTR_ERR(header_buf);
+ goto err_free;
+ }
}
}
@@ -790,7 +830,7 @@ static int mlx5vf_create_tracker(struct mlx5_core_dev *mdev,
node = interval_tree_iter_first(ranges, 0, ULONG_MAX);
for (i = 0; i < num_ranges; i++) {
void *addr_range_i_base = range_list_ptr + record_size * i;
- unsigned long length = node->last - node->start;
+ unsigned long length = node->last - node->start + 1;
MLX5_SET64(page_track_range, addr_range_i_base, start_address,
node->start);
@@ -800,7 +840,7 @@ static int mlx5vf_create_tracker(struct mlx5_core_dev *mdev,
}
WARN_ON(node);
- log_addr_space_size = ilog2(total_ranges_len);
+ log_addr_space_size = ilog2(roundup_pow_of_two(total_ranges_len));
if (log_addr_space_size <
(MLX5_CAP_ADV_VIRTUALIZATION(mdev, pg_track_log_min_addr_space)) ||
log_addr_space_size >
@@ -1032,18 +1072,18 @@ mlx5vf_create_rc_qp(struct mlx5_core_dev *mdev,
void *in;
int err;
- qp = kzalloc(sizeof(*qp), GFP_KERNEL);
+ qp = kzalloc(sizeof(*qp), GFP_KERNEL_ACCOUNT);
if (!qp)
return ERR_PTR(-ENOMEM);
- qp->rq.wqe_cnt = roundup_pow_of_two(max_recv_wr);
- log_rq_stride = ilog2(MLX5_SEND_WQE_DS);
- log_rq_sz = ilog2(qp->rq.wqe_cnt);
err = mlx5_db_alloc_node(mdev, &qp->db, mdev->priv.numa_node);
if (err)
goto err_free;
if (max_recv_wr) {
+ qp->rq.wqe_cnt = roundup_pow_of_two(max_recv_wr);
+ log_rq_stride = ilog2(MLX5_SEND_WQE_DS);
+ log_rq_sz = ilog2(qp->rq.wqe_cnt);
err = mlx5_frag_buf_alloc_node(mdev,
wq_get_byte_sz(log_rq_sz, log_rq_stride),
&qp->buf, mdev->priv.numa_node);
@@ -1213,12 +1253,13 @@ static int alloc_recv_pages(struct mlx5_vhca_recv_buf *recv_buf,
int i;
recv_buf->page_list = kvcalloc(npages, sizeof(*recv_buf->page_list),
- GFP_KERNEL);
+ GFP_KERNEL_ACCOUNT);
if (!recv_buf->page_list)
return -ENOMEM;
for (;;) {
- filled = alloc_pages_bulk_array(GFP_KERNEL, npages - done,
+ filled = alloc_pages_bulk_array(GFP_KERNEL_ACCOUNT,
+ npages - done,
recv_buf->page_list + done);
if (!filled)
goto err;
@@ -1248,7 +1289,7 @@ static int register_dma_recv_pages(struct mlx5_core_dev *mdev,
recv_buf->dma_addrs = kvcalloc(recv_buf->npages,
sizeof(*recv_buf->dma_addrs),
- GFP_KERNEL);
+ GFP_KERNEL_ACCOUNT);
if (!recv_buf->dma_addrs)
return -ENOMEM;
diff --git a/drivers/vfio/pci/mlx5/cmd.h b/drivers/vfio/pci/mlx5/cmd.h
index 5483171d57ad..aec4c69dd6c1 100644
--- a/drivers/vfio/pci/mlx5/cmd.h
+++ b/drivers/vfio/pci/mlx5/cmd.h
@@ -9,6 +9,7 @@
#include <linux/kernel.h>
#include <linux/vfio_pci_core.h>
#include <linux/mlx5/driver.h>
+#include <linux/mlx5/vport.h>
#include <linux/mlx5/cq.h>
#include <linux/mlx5/qp.h>
@@ -26,15 +27,33 @@ enum mlx5_vf_migf_state {
enum mlx5_vf_load_state {
MLX5_VF_LOAD_STATE_READ_IMAGE_NO_HEADER,
MLX5_VF_LOAD_STATE_READ_HEADER,
+ MLX5_VF_LOAD_STATE_PREP_HEADER_DATA,
+ MLX5_VF_LOAD_STATE_READ_HEADER_DATA,
MLX5_VF_LOAD_STATE_PREP_IMAGE,
MLX5_VF_LOAD_STATE_READ_IMAGE,
MLX5_VF_LOAD_STATE_LOAD_IMAGE,
};
+struct mlx5_vf_migration_tag_stop_copy_data {
+ __le64 stop_copy_size;
+};
+
+enum mlx5_vf_migf_header_flags {
+ MLX5_MIGF_HEADER_FLAGS_TAG_MANDATORY = 0,
+ MLX5_MIGF_HEADER_FLAGS_TAG_OPTIONAL = 1 << 0,
+};
+
+enum mlx5_vf_migf_header_tag {
+ MLX5_MIGF_HEADER_TAG_FW_DATA = 0,
+ MLX5_MIGF_HEADER_TAG_STOP_COPY_SIZE = 1 << 0,
+};
+
struct mlx5_vf_migration_header {
- __le64 image_size;
+ __le64 record_size;
/* For future use in case we may need to change the kernel protocol */
- __le64 flags;
+ __le32 flags; /* Use mlx5_vf_migf_header_flags */
+ __le32 tag; /* Use mlx5_vf_migf_header_tag */
+ __u8 data[]; /* Its size is given in the record_size */
};
struct mlx5_vhca_data_buffer {
@@ -42,7 +61,6 @@ struct mlx5_vhca_data_buffer {
loff_t start_pos;
u64 length;
u64 allocated_length;
- u64 header_image_size;
u32 mkey;
enum dma_data_direction dma_dir;
u8 dmaed:1;
@@ -72,6 +90,10 @@ struct mlx5_vf_migration_file {
enum mlx5_vf_load_state load_state;
u32 pdn;
loff_t max_pos;
+ u64 record_size;
+ u32 record_tag;
+ u64 stop_copy_prep_size;
+ u64 pre_copy_initial_bytes;
struct mlx5_vhca_data_buffer *buf;
struct mlx5_vhca_data_buffer *buf_header;
spinlock_t list_lock;
diff --git a/drivers/vfio/pci/mlx5/main.c b/drivers/vfio/pci/mlx5/main.c
index 9feb89c6d939..e897537a9e8a 100644
--- a/drivers/vfio/pci/mlx5/main.c
+++ b/drivers/vfio/pci/mlx5/main.c
@@ -21,8 +21,8 @@
#include "cmd.h"
-/* Arbitrary to prevent userspace from consuming endless memory */
-#define MAX_MIGRATION_SIZE (512*1024*1024)
+/* Device specification max LOAD size */
+#define MAX_LOAD_SIZE (BIT_ULL(__mlx5_bit_sz(load_vhca_state_in, size)) - 1)
static struct mlx5vf_pci_core_device *mlx5vf_drvdata(struct pci_dev *pdev)
{
@@ -73,12 +73,13 @@ int mlx5vf_add_migration_pages(struct mlx5_vhca_data_buffer *buf,
int ret;
to_fill = min_t(unsigned int, npages, PAGE_SIZE / sizeof(*page_list));
- page_list = kvzalloc(to_fill * sizeof(*page_list), GFP_KERNEL);
+ page_list = kvzalloc(to_fill * sizeof(*page_list), GFP_KERNEL_ACCOUNT);
if (!page_list)
return -ENOMEM;
do {
- filled = alloc_pages_bulk_array(GFP_KERNEL, to_fill, page_list);
+ filled = alloc_pages_bulk_array(GFP_KERNEL_ACCOUNT, to_fill,
+ page_list);
if (!filled) {
ret = -ENOMEM;
goto err;
@@ -87,7 +88,7 @@ int mlx5vf_add_migration_pages(struct mlx5_vhca_data_buffer *buf,
ret = sg_alloc_append_table_from_pages(
&buf->table, page_list, filled, 0,
filled << PAGE_SHIFT, UINT_MAX, SG_MAX_SINGLE_ALLOC,
- GFP_KERNEL);
+ GFP_KERNEL_ACCOUNT);
if (ret)
goto err;
@@ -303,6 +304,87 @@ static void mlx5vf_mark_err(struct mlx5_vf_migration_file *migf)
wake_up_interruptible(&migf->poll_wait);
}
+static int mlx5vf_add_stop_copy_header(struct mlx5_vf_migration_file *migf)
+{
+ size_t size = sizeof(struct mlx5_vf_migration_header) +
+ sizeof(struct mlx5_vf_migration_tag_stop_copy_data);
+ struct mlx5_vf_migration_tag_stop_copy_data data = {};
+ struct mlx5_vhca_data_buffer *header_buf = NULL;
+ struct mlx5_vf_migration_header header = {};
+ unsigned long flags;
+ struct page *page;
+ u8 *to_buff;
+ int ret;
+
+ header_buf = mlx5vf_get_data_buffer(migf, size, DMA_NONE);
+ if (IS_ERR(header_buf))
+ return PTR_ERR(header_buf);
+
+ header.record_size = cpu_to_le64(sizeof(data));
+ header.flags = cpu_to_le32(MLX5_MIGF_HEADER_FLAGS_TAG_OPTIONAL);
+ header.tag = cpu_to_le32(MLX5_MIGF_HEADER_TAG_STOP_COPY_SIZE);
+ page = mlx5vf_get_migration_page(header_buf, 0);
+ if (!page) {
+ ret = -EINVAL;
+ goto err;
+ }
+ to_buff = kmap_local_page(page);
+ memcpy(to_buff, &header, sizeof(header));
+ header_buf->length = sizeof(header);
+ data.stop_copy_size = cpu_to_le64(migf->buf->allocated_length);
+ memcpy(to_buff + sizeof(header), &data, sizeof(data));
+ header_buf->length += sizeof(data);
+ kunmap_local(to_buff);
+ header_buf->start_pos = header_buf->migf->max_pos;
+ migf->max_pos += header_buf->length;
+ spin_lock_irqsave(&migf->list_lock, flags);
+ list_add_tail(&header_buf->buf_elm, &migf->buf_list);
+ spin_unlock_irqrestore(&migf->list_lock, flags);
+ migf->pre_copy_initial_bytes = size;
+ return 0;
+err:
+ mlx5vf_put_data_buffer(header_buf);
+ return ret;
+}
+
+static int mlx5vf_prep_stop_copy(struct mlx5_vf_migration_file *migf,
+ size_t state_size)
+{
+ struct mlx5_vhca_data_buffer *buf;
+ size_t inc_state_size;
+ int ret;
+
+ /* let's be ready for stop_copy size that might grow by 10 percents */
+ if (check_add_overflow(state_size, state_size / 10, &inc_state_size))
+ inc_state_size = state_size;
+
+ buf = mlx5vf_get_data_buffer(migf, inc_state_size, DMA_FROM_DEVICE);
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
+
+ migf->buf = buf;
+ buf = mlx5vf_get_data_buffer(migf,
+ sizeof(struct mlx5_vf_migration_header), DMA_NONE);
+ if (IS_ERR(buf)) {
+ ret = PTR_ERR(buf);
+ goto err;
+ }
+
+ migf->buf_header = buf;
+ ret = mlx5vf_add_stop_copy_header(migf);
+ if (ret)
+ goto err_header;
+ return 0;
+
+err_header:
+ mlx5vf_put_data_buffer(migf->buf_header);
+ migf->buf_header = NULL;
+err:
+ mlx5vf_put_data_buffer(migf->buf);
+ migf->buf = NULL;
+ return ret;
+}
+
static long mlx5vf_precopy_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
@@ -313,7 +395,7 @@ static long mlx5vf_precopy_ioctl(struct file *filp, unsigned int cmd,
loff_t *pos = &filp->f_pos;
unsigned long minsz;
size_t inc_length = 0;
- bool end_of_data;
+ bool end_of_data = false;
int ret;
if (cmd != VFIO_MIG_GET_PRECOPY_INFO)
@@ -357,25 +439,19 @@ static long mlx5vf_precopy_ioctl(struct file *filp, unsigned int cmd,
goto err_migf_unlock;
}
- buf = mlx5vf_get_data_buff_from_pos(migf, *pos, &end_of_data);
- if (buf) {
- if (buf->start_pos == 0) {
- info.initial_bytes = buf->header_image_size - *pos;
- } else if (buf->start_pos ==
- sizeof(struct mlx5_vf_migration_header)) {
- /* First data buffer following the header */
- info.initial_bytes = buf->start_pos +
- buf->length - *pos;
- } else {
- info.dirty_bytes = buf->start_pos + buf->length - *pos;
- }
+ if (migf->pre_copy_initial_bytes > *pos) {
+ info.initial_bytes = migf->pre_copy_initial_bytes - *pos;
} else {
- if (!end_of_data) {
- ret = -EINVAL;
- goto err_migf_unlock;
+ buf = mlx5vf_get_data_buff_from_pos(migf, *pos, &end_of_data);
+ if (buf) {
+ info.dirty_bytes = buf->start_pos + buf->length - *pos;
+ } else {
+ if (!end_of_data) {
+ ret = -EINVAL;
+ goto err_migf_unlock;
+ }
+ info.dirty_bytes = inc_length;
}
-
- info.dirty_bytes = inc_length;
}
if (!end_of_data || !inc_length) {
@@ -440,10 +516,16 @@ static int mlx5vf_pci_save_device_inc_data(struct mlx5vf_pci_core_device *mvdev)
if (ret)
goto err;
- buf = mlx5vf_get_data_buffer(migf, length, DMA_FROM_DEVICE);
- if (IS_ERR(buf)) {
- ret = PTR_ERR(buf);
- goto err;
+ /* Checking whether we have a matching pre-allocated buffer that can fit */
+ if (migf->buf && migf->buf->allocated_length >= length) {
+ buf = migf->buf;
+ migf->buf = NULL;
+ } else {
+ buf = mlx5vf_get_data_buffer(migf, length, DMA_FROM_DEVICE);
+ if (IS_ERR(buf)) {
+ ret = PTR_ERR(buf);
+ goto err;
+ }
}
ret = mlx5vf_cmd_save_vhca_state(mvdev, migf, buf, true, false);
@@ -467,7 +549,7 @@ mlx5vf_pci_save_device_data(struct mlx5vf_pci_core_device *mvdev, bool track)
size_t length;
int ret;
- migf = kzalloc(sizeof(*migf), GFP_KERNEL);
+ migf = kzalloc(sizeof(*migf), GFP_KERNEL_ACCOUNT);
if (!migf)
return ERR_PTR(-ENOMEM);
@@ -502,6 +584,12 @@ mlx5vf_pci_save_device_data(struct mlx5vf_pci_core_device *mvdev, bool track)
if (ret)
goto out_pd;
+ if (track) {
+ ret = mlx5vf_prep_stop_copy(migf, length);
+ if (ret)
+ goto out_pd;
+ }
+
buf = mlx5vf_alloc_data_buffer(migf, length, DMA_FROM_DEVICE);
if (IS_ERR(buf)) {
ret = PTR_ERR(buf);
@@ -515,7 +603,7 @@ mlx5vf_pci_save_device_data(struct mlx5vf_pci_core_device *mvdev, bool track)
out_save:
mlx5vf_free_data_buffer(buf);
out_pd:
- mlx5vf_cmd_dealloc_pd(migf);
+ mlx5fv_cmd_clean_migf_resources(migf);
out_free:
fput(migf->filp);
end:
@@ -564,7 +652,7 @@ mlx5vf_resume_read_image_no_header(struct mlx5_vhca_data_buffer *vhca_buf,
{
int ret;
- if (requested_length > MAX_MIGRATION_SIZE)
+ if (requested_length > MAX_LOAD_SIZE)
return -ENOMEM;
if (vhca_buf->allocated_length < requested_length) {
@@ -616,6 +704,56 @@ mlx5vf_resume_read_image(struct mlx5_vf_migration_file *migf,
}
static int
+mlx5vf_resume_read_header_data(struct mlx5_vf_migration_file *migf,
+ struct mlx5_vhca_data_buffer *vhca_buf,
+ const char __user **buf, size_t *len,
+ loff_t *pos, ssize_t *done)
+{
+ size_t copy_len, to_copy;
+ size_t required_data;
+ u8 *to_buff;
+ int ret;
+
+ required_data = migf->record_size - vhca_buf->length;
+ to_copy = min_t(size_t, *len, required_data);
+ copy_len = to_copy;
+ while (to_copy) {
+ ret = mlx5vf_append_page_to_mig_buf(vhca_buf, buf, &to_copy, pos,
+ done);
+ if (ret)
+ return ret;
+ }
+
+ *len -= copy_len;
+ if (vhca_buf->length == migf->record_size) {
+ switch (migf->record_tag) {
+ case MLX5_MIGF_HEADER_TAG_STOP_COPY_SIZE:
+ {
+ struct page *page;
+
+ page = mlx5vf_get_migration_page(vhca_buf, 0);
+ if (!page)
+ return -EINVAL;
+ to_buff = kmap_local_page(page);
+ migf->stop_copy_prep_size = min_t(u64,
+ le64_to_cpup((__le64 *)to_buff), MAX_LOAD_SIZE);
+ kunmap_local(to_buff);
+ break;
+ }
+ default:
+ /* Optional tag */
+ break;
+ }
+
+ migf->load_state = MLX5_VF_LOAD_STATE_READ_HEADER;
+ migf->max_pos += migf->record_size;
+ vhca_buf->length = 0;
+ }
+
+ return 0;
+}
+
+static int
mlx5vf_resume_read_header(struct mlx5_vf_migration_file *migf,
struct mlx5_vhca_data_buffer *vhca_buf,
const char __user **buf,
@@ -645,23 +783,38 @@ mlx5vf_resume_read_header(struct mlx5_vf_migration_file *migf,
*len -= copy_len;
vhca_buf->length += copy_len;
if (vhca_buf->length == sizeof(struct mlx5_vf_migration_header)) {
- u64 flags;
+ u64 record_size;
+ u32 flags;
- vhca_buf->header_image_size = le64_to_cpup((__le64 *)to_buff);
- if (vhca_buf->header_image_size > MAX_MIGRATION_SIZE) {
+ record_size = le64_to_cpup((__le64 *)to_buff);
+ if (record_size > MAX_LOAD_SIZE) {
ret = -ENOMEM;
goto end;
}
- flags = le64_to_cpup((__le64 *)(to_buff +
+ migf->record_size = record_size;
+ flags = le32_to_cpup((__le32 *)(to_buff +
offsetof(struct mlx5_vf_migration_header, flags)));
- if (flags) {
- ret = -EOPNOTSUPP;
- goto end;
+ migf->record_tag = le32_to_cpup((__le32 *)(to_buff +
+ offsetof(struct mlx5_vf_migration_header, tag)));
+ switch (migf->record_tag) {
+ case MLX5_MIGF_HEADER_TAG_FW_DATA:
+ migf->load_state = MLX5_VF_LOAD_STATE_PREP_IMAGE;
+ break;
+ case MLX5_MIGF_HEADER_TAG_STOP_COPY_SIZE:
+ migf->load_state = MLX5_VF_LOAD_STATE_PREP_HEADER_DATA;
+ break;
+ default:
+ if (!(flags & MLX5_MIGF_HEADER_FLAGS_TAG_OPTIONAL)) {
+ ret = -EOPNOTSUPP;
+ goto end;
+ }
+ /* We may read and skip this optional record data */
+ migf->load_state = MLX5_VF_LOAD_STATE_PREP_HEADER_DATA;
}
- migf->load_state = MLX5_VF_LOAD_STATE_PREP_IMAGE;
migf->max_pos += vhca_buf->length;
+ vhca_buf->length = 0;
*has_work = true;
}
end:
@@ -705,9 +858,34 @@ static ssize_t mlx5vf_resume_write(struct file *filp, const char __user *buf,
if (ret)
goto out_unlock;
break;
+ case MLX5_VF_LOAD_STATE_PREP_HEADER_DATA:
+ if (vhca_buf_header->allocated_length < migf->record_size) {
+ mlx5vf_free_data_buffer(vhca_buf_header);
+
+ migf->buf_header = mlx5vf_alloc_data_buffer(migf,
+ migf->record_size, DMA_NONE);
+ if (IS_ERR(migf->buf_header)) {
+ ret = PTR_ERR(migf->buf_header);
+ migf->buf_header = NULL;
+ goto out_unlock;
+ }
+
+ vhca_buf_header = migf->buf_header;
+ }
+
+ vhca_buf_header->start_pos = migf->max_pos;
+ migf->load_state = MLX5_VF_LOAD_STATE_READ_HEADER_DATA;
+ break;
+ case MLX5_VF_LOAD_STATE_READ_HEADER_DATA:
+ ret = mlx5vf_resume_read_header_data(migf, vhca_buf_header,
+ &buf, &len, pos, &done);
+ if (ret)
+ goto out_unlock;
+ break;
case MLX5_VF_LOAD_STATE_PREP_IMAGE:
{
- u64 size = vhca_buf_header->header_image_size;
+ u64 size = max(migf->record_size,
+ migf->stop_copy_prep_size);
if (vhca_buf->allocated_length < size) {
mlx5vf_free_data_buffer(vhca_buf);
@@ -736,7 +914,7 @@ static ssize_t mlx5vf_resume_write(struct file *filp, const char __user *buf,
break;
case MLX5_VF_LOAD_STATE_READ_IMAGE:
ret = mlx5vf_resume_read_image(migf, vhca_buf,
- vhca_buf_header->header_image_size,
+ migf->record_size,
&buf, &len, pos, &done, &has_work);
if (ret)
goto out_unlock;
@@ -749,7 +927,6 @@ static ssize_t mlx5vf_resume_write(struct file *filp, const char __user *buf,
/* prep header buf for next image */
vhca_buf_header->length = 0;
- vhca_buf_header->header_image_size = 0;
/* prep data buf for next image */
vhca_buf->length = 0;
@@ -781,7 +958,7 @@ mlx5vf_pci_resume_device_data(struct mlx5vf_pci_core_device *mvdev)
struct mlx5_vhca_data_buffer *buf;
int ret;
- migf = kzalloc(sizeof(*migf), GFP_KERNEL);
+ migf = kzalloc(sizeof(*migf), GFP_KERNEL_ACCOUNT);
if (!migf)
return ERR_PTR(-ENOMEM);
diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c
index 4a350421c5f6..523e0144c86f 100644
--- a/drivers/vfio/pci/vfio_pci_config.c
+++ b/drivers/vfio/pci/vfio_pci_config.c
@@ -1244,7 +1244,7 @@ static int vfio_msi_cap_len(struct vfio_pci_core_device *vdev, u8 pos)
if (vdev->msi_perm)
return len;
- vdev->msi_perm = kmalloc(sizeof(struct perm_bits), GFP_KERNEL);
+ vdev->msi_perm = kmalloc(sizeof(struct perm_bits), GFP_KERNEL_ACCOUNT);
if (!vdev->msi_perm)
return -ENOMEM;
@@ -1731,11 +1731,11 @@ int vfio_config_init(struct vfio_pci_core_device *vdev)
* no requirements on the length of a capability, so the gap between
* capabilities needs byte granularity.
*/
- map = kmalloc(pdev->cfg_size, GFP_KERNEL);
+ map = kmalloc(pdev->cfg_size, GFP_KERNEL_ACCOUNT);
if (!map)
return -ENOMEM;
- vconfig = kmalloc(pdev->cfg_size, GFP_KERNEL);
+ vconfig = kmalloc(pdev->cfg_size, GFP_KERNEL_ACCOUNT);
if (!vconfig) {
kfree(map);
return -ENOMEM;
diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c
index 26a541cc64d1..a5ab416cf476 100644
--- a/drivers/vfio/pci/vfio_pci_core.c
+++ b/drivers/vfio/pci/vfio_pci_core.c
@@ -144,7 +144,8 @@ static void vfio_pci_probe_mmaps(struct vfio_pci_core_device *vdev)
* of the exclusive page in case that hot-add
* device's bar is assigned into it.
*/
- dummy_res = kzalloc(sizeof(*dummy_res), GFP_KERNEL);
+ dummy_res =
+ kzalloc(sizeof(*dummy_res), GFP_KERNEL_ACCOUNT);
if (dummy_res == NULL)
goto no_mmap;
@@ -863,7 +864,7 @@ int vfio_pci_core_register_dev_region(struct vfio_pci_core_device *vdev,
region = krealloc(vdev->region,
(vdev->num_regions + 1) * sizeof(*region),
- GFP_KERNEL);
+ GFP_KERNEL_ACCOUNT);
if (!region)
return -ENOMEM;
@@ -1644,7 +1645,7 @@ static int __vfio_pci_add_vma(struct vfio_pci_core_device *vdev,
{
struct vfio_pci_mmap_vma *mmap_vma;
- mmap_vma = kmalloc(sizeof(*mmap_vma), GFP_KERNEL);
+ mmap_vma = kmalloc(sizeof(*mmap_vma), GFP_KERNEL_ACCOUNT);
if (!mmap_vma)
return -ENOMEM;
@@ -1799,7 +1800,7 @@ int vfio_pci_core_mmap(struct vfio_device *core_vdev, struct vm_area_struct *vma
* See remap_pfn_range(), called from vfio_pci_fault() but we can't
* change vm_flags within the fault handler. Set them now.
*/
- vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP;
+ vm_flags_set(vma, VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP);
vma->vm_ops = &vfio_pci_mmap_ops;
return 0;
diff --git a/drivers/vfio/pci/vfio_pci_igd.c b/drivers/vfio/pci/vfio_pci_igd.c
index 5e6ca5926954..dd70e2431bd7 100644
--- a/drivers/vfio/pci/vfio_pci_igd.c
+++ b/drivers/vfio/pci/vfio_pci_igd.c
@@ -180,7 +180,7 @@ static int vfio_pci_igd_opregion_init(struct vfio_pci_core_device *vdev)
if (!addr || !(~addr))
return -ENODEV;
- opregionvbt = kzalloc(sizeof(*opregionvbt), GFP_KERNEL);
+ opregionvbt = kzalloc(sizeof(*opregionvbt), GFP_KERNEL_ACCOUNT);
if (!opregionvbt)
return -ENOMEM;
diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c
index 40c3d7cf163f..bffb0741518b 100644
--- a/drivers/vfio/pci/vfio_pci_intrs.c
+++ b/drivers/vfio/pci/vfio_pci_intrs.c
@@ -177,7 +177,7 @@ static int vfio_intx_enable(struct vfio_pci_core_device *vdev)
if (!vdev->pdev->irq)
return -ENODEV;
- vdev->ctx = kzalloc(sizeof(struct vfio_pci_irq_ctx), GFP_KERNEL);
+ vdev->ctx = kzalloc(sizeof(struct vfio_pci_irq_ctx), GFP_KERNEL_ACCOUNT);
if (!vdev->ctx)
return -ENOMEM;
@@ -216,7 +216,7 @@ static int vfio_intx_set_signal(struct vfio_pci_core_device *vdev, int fd)
if (fd < 0) /* Disable only */
return 0;
- vdev->ctx[0].name = kasprintf(GFP_KERNEL, "vfio-intx(%s)",
+ vdev->ctx[0].name = kasprintf(GFP_KERNEL_ACCOUNT, "vfio-intx(%s)",
pci_name(pdev));
if (!vdev->ctx[0].name)
return -ENOMEM;
@@ -284,7 +284,8 @@ static int vfio_msi_enable(struct vfio_pci_core_device *vdev, int nvec, bool msi
if (!is_irq_none(vdev))
return -EINVAL;
- vdev->ctx = kcalloc(nvec, sizeof(struct vfio_pci_irq_ctx), GFP_KERNEL);
+ vdev->ctx = kcalloc(nvec, sizeof(struct vfio_pci_irq_ctx),
+ GFP_KERNEL_ACCOUNT);
if (!vdev->ctx)
return -ENOMEM;
@@ -343,7 +344,8 @@ static int vfio_msi_set_vector_signal(struct vfio_pci_core_device *vdev,
if (fd < 0)
return 0;
- vdev->ctx[vector].name = kasprintf(GFP_KERNEL, "vfio-msi%s[%d](%s)",
+ vdev->ctx[vector].name = kasprintf(GFP_KERNEL_ACCOUNT,
+ "vfio-msi%s[%d](%s)",
msix ? "x" : "", vector,
pci_name(pdev));
if (!vdev->ctx[vector].name)
diff --git a/drivers/vfio/pci/vfio_pci_rdwr.c b/drivers/vfio/pci/vfio_pci_rdwr.c
index e352a033b4ae..e27de61ac9fe 100644
--- a/drivers/vfio/pci/vfio_pci_rdwr.c
+++ b/drivers/vfio/pci/vfio_pci_rdwr.c
@@ -470,7 +470,7 @@ int vfio_pci_ioeventfd(struct vfio_pci_core_device *vdev, loff_t offset,
goto out_unlock;
}
- ioeventfd = kzalloc(sizeof(*ioeventfd), GFP_KERNEL);
+ ioeventfd = kzalloc(sizeof(*ioeventfd), GFP_KERNEL_ACCOUNT);
if (!ioeventfd) {
ret = -ENOMEM;
goto out_unlock;
diff --git a/drivers/vfio/platform/vfio_platform_common.c b/drivers/vfio/platform/vfio_platform_common.c
index 1a0a238ffa35..e53757d1d095 100644
--- a/drivers/vfio/platform/vfio_platform_common.c
+++ b/drivers/vfio/platform/vfio_platform_common.c
@@ -142,7 +142,7 @@ static int vfio_platform_regions_init(struct vfio_platform_device *vdev)
cnt++;
vdev->regions = kcalloc(cnt, sizeof(struct vfio_platform_region),
- GFP_KERNEL);
+ GFP_KERNEL_ACCOUNT);
if (!vdev->regions)
return -ENOMEM;
@@ -150,9 +150,6 @@ static int vfio_platform_regions_init(struct vfio_platform_device *vdev)
struct resource *res =
vdev->get_resource(vdev, i);
- if (!res)
- goto err;
-
vdev->regions[i].addr = res->start;
vdev->regions[i].size = resource_size(res);
vdev->regions[i].flags = 0;
@@ -650,10 +647,13 @@ int vfio_platform_init_common(struct vfio_platform_device *vdev)
mutex_init(&vdev->igate);
ret = vfio_platform_get_reset(vdev);
- if (ret && vdev->reset_required)
+ if (ret && vdev->reset_required) {
dev_err(dev, "No reset function found for device %s\n",
vdev->name);
- return ret;
+ return ret;
+ }
+
+ return 0;
}
EXPORT_SYMBOL_GPL(vfio_platform_init_common);
diff --git a/drivers/vfio/platform/vfio_platform_irq.c b/drivers/vfio/platform/vfio_platform_irq.c
index c5b09ec0a3c9..665197caed89 100644
--- a/drivers/vfio/platform/vfio_platform_irq.c
+++ b/drivers/vfio/platform/vfio_platform_irq.c
@@ -186,9 +186,8 @@ static int vfio_set_trigger(struct vfio_platform_device *vdev, int index,
if (fd < 0) /* Disable only */
return 0;
-
- irq->name = kasprintf(GFP_KERNEL, "vfio-irq[%d](%s)",
- irq->hwirq, vdev->name);
+ irq->name = kasprintf(GFP_KERNEL_ACCOUNT, "vfio-irq[%d](%s)",
+ irq->hwirq, vdev->name);
if (!irq->name)
return -ENOMEM;
@@ -286,7 +285,8 @@ int vfio_platform_irq_init(struct vfio_platform_device *vdev)
while (vdev->get_irq(vdev, cnt) >= 0)
cnt++;
- vdev->irqs = kcalloc(cnt, sizeof(struct vfio_platform_irq), GFP_KERNEL);
+ vdev->irqs = kcalloc(cnt, sizeof(struct vfio_platform_irq),
+ GFP_KERNEL_ACCOUNT);
if (!vdev->irqs)
return -ENOMEM;
diff --git a/drivers/vfio/vfio.h b/drivers/vfio/vfio.h
index f8219a438bfb..7b19c621e0e6 100644
--- a/drivers/vfio/vfio.h
+++ b/drivers/vfio/vfio.h
@@ -10,16 +10,15 @@
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/module.h>
+#include <linux/vfio.h>
struct iommufd_ctx;
struct iommu_group;
-struct vfio_device;
struct vfio_container;
void vfio_device_put_registration(struct vfio_device *device);
bool vfio_device_try_get_registration(struct vfio_device *device);
-int vfio_device_open(struct vfio_device *device,
- struct iommufd_ctx *iommufd, struct kvm *kvm);
+int vfio_device_open(struct vfio_device *device, struct iommufd_ctx *iommufd);
void vfio_device_close(struct vfio_device *device,
struct iommufd_ctx *iommufd);
@@ -74,6 +73,7 @@ struct vfio_group {
struct file *opened_file;
struct blocking_notifier_head notifier;
struct iommufd_ctx *iommufd;
+ spinlock_t kvm_ref_lock;
};
int vfio_device_set_group(struct vfio_device *device,
@@ -88,12 +88,13 @@ bool vfio_device_has_container(struct vfio_device *device);
int __init vfio_group_init(void);
void vfio_group_cleanup(void);
-#if IS_ENABLED(CONFIG_VFIO_CONTAINER)
-/* events for the backend driver notify callback */
-enum vfio_iommu_notify_type {
- VFIO_IOMMU_CONTAINER_CLOSE = 0,
-};
+static inline bool vfio_device_is_noiommu(struct vfio_device *vdev)
+{
+ return IS_ENABLED(CONFIG_VFIO_NOIOMMU) &&
+ vdev->group->type == VFIO_NO_IOMMU;
+}
+#if IS_ENABLED(CONFIG_VFIO_CONTAINER)
/**
* struct vfio_iommu_driver_ops - VFIO IOMMU driver callbacks
*/
@@ -124,8 +125,6 @@ struct vfio_iommu_driver_ops {
void *data, size_t count, bool write);
struct iommu_domain *(*group_iommu_domain)(void *iommu_data,
struct iommu_group *group);
- void (*notify)(void *iommu_data,
- enum vfio_iommu_notify_type event);
};
struct vfio_iommu_driver {
@@ -251,4 +250,18 @@ extern bool vfio_noiommu __read_mostly;
enum { vfio_noiommu = false };
#endif
+#ifdef CONFIG_HAVE_KVM
+void _vfio_device_get_kvm_safe(struct vfio_device *device, struct kvm *kvm);
+void vfio_device_put_kvm(struct vfio_device *device);
+#else
+static inline void _vfio_device_get_kvm_safe(struct vfio_device *device,
+ struct kvm *kvm)
+{
+}
+
+static inline void vfio_device_put_kvm(struct vfio_device *device)
+{
+}
+#endif
+
#endif
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index 2209372f236d..493c31de0edb 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -37,7 +37,6 @@
#include <linux/vfio.h>
#include <linux/workqueue.h>
#include <linux/notifier.h>
-#include <linux/irqdomain.h>
#include "vfio.h"
#define DRIVER_VERSION "0.2"
@@ -72,11 +71,9 @@ struct vfio_iommu {
unsigned int vaddr_invalid_count;
uint64_t pgsize_bitmap;
uint64_t num_non_pinned_groups;
- wait_queue_head_t vaddr_wait;
bool v2;
bool nesting;
bool dirty_page_tracking;
- bool container_open;
struct list_head emulated_iommu_groups;
};
@@ -100,6 +97,8 @@ struct vfio_dma {
struct task_struct *task;
struct rb_root pfn_list; /* Ex-user pinned pfn list */
unsigned long *bitmap;
+ struct mm_struct *mm;
+ size_t locked_vm;
};
struct vfio_batch {
@@ -152,8 +151,6 @@ struct vfio_regions {
#define DIRTY_BITMAP_PAGES_MAX ((u64)INT_MAX)
#define DIRTY_BITMAP_SIZE_MAX DIRTY_BITMAP_BYTES(DIRTY_BITMAP_PAGES_MAX)
-#define WAITED 1
-
static int put_pfn(unsigned long pfn, int prot);
static struct vfio_iommu_group*
@@ -412,6 +409,19 @@ static int vfio_iova_put_vfio_pfn(struct vfio_dma *dma, struct vfio_pfn *vpfn)
return ret;
}
+static int mm_lock_acct(struct task_struct *task, struct mm_struct *mm,
+ bool lock_cap, long npage)
+{
+ int ret = mmap_write_lock_killable(mm);
+
+ if (ret)
+ return ret;
+
+ ret = __account_locked_vm(mm, abs(npage), npage > 0, task, lock_cap);
+ mmap_write_unlock(mm);
+ return ret;
+}
+
static int vfio_lock_acct(struct vfio_dma *dma, long npage, bool async)
{
struct mm_struct *mm;
@@ -420,16 +430,13 @@ static int vfio_lock_acct(struct vfio_dma *dma, long npage, bool async)
if (!npage)
return 0;
- mm = async ? get_task_mm(dma->task) : dma->task->mm;
- if (!mm)
+ mm = dma->mm;
+ if (async && !mmget_not_zero(mm))
return -ESRCH; /* process exited */
- ret = mmap_write_lock_killable(mm);
- if (!ret) {
- ret = __account_locked_vm(mm, abs(npage), npage > 0, dma->task,
- dma->lock_cap);
- mmap_write_unlock(mm);
- }
+ ret = mm_lock_acct(dma->task, mm, dma->lock_cap, npage);
+ if (!ret)
+ dma->locked_vm += npage;
if (async)
mmput(mm);
@@ -595,61 +602,6 @@ done:
return ret;
}
-static int vfio_wait(struct vfio_iommu *iommu)
-{
- DEFINE_WAIT(wait);
-
- prepare_to_wait(&iommu->vaddr_wait, &wait, TASK_KILLABLE);
- mutex_unlock(&iommu->lock);
- schedule();
- mutex_lock(&iommu->lock);
- finish_wait(&iommu->vaddr_wait, &wait);
- if (kthread_should_stop() || !iommu->container_open ||
- fatal_signal_pending(current)) {
- return -EFAULT;
- }
- return WAITED;
-}
-
-/*
- * Find dma struct and wait for its vaddr to be valid. iommu lock is dropped
- * if the task waits, but is re-locked on return. Return result in *dma_p.
- * Return 0 on success with no waiting, WAITED on success if waited, and -errno
- * on error.
- */
-static int vfio_find_dma_valid(struct vfio_iommu *iommu, dma_addr_t start,
- size_t size, struct vfio_dma **dma_p)
-{
- int ret = 0;
-
- do {
- *dma_p = vfio_find_dma(iommu, start, size);
- if (!*dma_p)
- return -EINVAL;
- else if (!(*dma_p)->vaddr_invalid)
- return ret;
- else
- ret = vfio_wait(iommu);
- } while (ret == WAITED);
-
- return ret;
-}
-
-/*
- * Wait for all vaddr in the dma_list to become valid. iommu lock is dropped
- * if the task waits, but is re-locked on return. Return 0 on success with no
- * waiting, WAITED on success if waited, and -errno on error.
- */
-static int vfio_wait_all_valid(struct vfio_iommu *iommu)
-{
- int ret = 0;
-
- while (iommu->vaddr_invalid_count && ret >= 0)
- ret = vfio_wait(iommu);
-
- return ret;
-}
-
/*
* Attempt to pin pages. We really don't want to track all the pfns and
* the iommu can only map chunks of consecutive pfns anyway, so get the
@@ -794,8 +746,8 @@ static int vfio_pin_page_external(struct vfio_dma *dma, unsigned long vaddr,
struct mm_struct *mm;
int ret;
- mm = get_task_mm(dma->task);
- if (!mm)
+ mm = dma->mm;
+ if (!mmget_not_zero(mm))
return -ENODEV;
ret = vaddr_get_pfns(mm, vaddr, 1, dma->prot, pfn_base, pages);
@@ -805,7 +757,7 @@ static int vfio_pin_page_external(struct vfio_dma *dma, unsigned long vaddr,
ret = 0;
if (do_accounting && !is_invalid_reserved_pfn(*pfn_base)) {
- ret = vfio_lock_acct(dma, 1, true);
+ ret = vfio_lock_acct(dma, 1, false);
if (ret) {
put_pfn(*pfn_base, dma->prot);
if (ret == -ENOMEM)
@@ -850,7 +802,6 @@ static int vfio_iommu_type1_pin_pages(void *iommu_data,
unsigned long remote_vaddr;
struct vfio_dma *dma;
bool do_accounting;
- dma_addr_t iova;
if (!iommu || !pages)
return -EINVAL;
@@ -861,20 +812,10 @@ static int vfio_iommu_type1_pin_pages(void *iommu_data,
mutex_lock(&iommu->lock);
- /*
- * Wait for all necessary vaddr's to be valid so they can be used in
- * the main loop without dropping the lock, to avoid racing vs unmap.
- */
-again:
- if (iommu->vaddr_invalid_count) {
- for (i = 0; i < npage; i++) {
- iova = user_iova + PAGE_SIZE * i;
- ret = vfio_find_dma_valid(iommu, iova, PAGE_SIZE, &dma);
- if (ret < 0)
- goto pin_done;
- if (ret == WAITED)
- goto again;
- }
+ if (WARN_ONCE(iommu->vaddr_invalid_count,
+ "vfio_pin_pages not allowed with VFIO_UPDATE_VADDR\n")) {
+ ret = -EBUSY;
+ goto pin_done;
}
/* Fail if no dma_umap notifier is registered */
@@ -892,6 +833,7 @@ again:
for (i = 0; i < npage; i++) {
unsigned long phys_pfn;
+ dma_addr_t iova;
struct vfio_pfn *vpfn;
iova = user_iova + PAGE_SIZE * i;
@@ -1174,11 +1116,10 @@ static void vfio_remove_dma(struct vfio_iommu *iommu, struct vfio_dma *dma)
vfio_unmap_unpin(iommu, dma, true);
vfio_unlink_dma(iommu, dma);
put_task_struct(dma->task);
+ mmdrop(dma->mm);
vfio_dma_bitmap_free(dma);
- if (dma->vaddr_invalid) {
+ if (dma->vaddr_invalid)
iommu->vaddr_invalid_count--;
- wake_up_all(&iommu->vaddr_wait);
- }
kfree(dma);
iommu->dma_avail++;
}
@@ -1343,6 +1284,12 @@ static int vfio_dma_do_unmap(struct vfio_iommu *iommu,
mutex_lock(&iommu->lock);
+ /* Cannot update vaddr if mdev is present. */
+ if (invalidate_vaddr && !list_empty(&iommu->emulated_iommu_groups)) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+
pgshift = __ffs(iommu->pgsize_bitmap);
pgsize = (size_t)1 << pgshift;
@@ -1480,7 +1427,8 @@ static int vfio_iommu_map(struct vfio_iommu *iommu, dma_addr_t iova,
list_for_each_entry(d, &iommu->domain_list, next) {
ret = iommu_map(d->domain, iova, (phys_addr_t)pfn << PAGE_SHIFT,
- npage << PAGE_SHIFT, prot | IOMMU_CACHE);
+ npage << PAGE_SHIFT, prot | IOMMU_CACHE,
+ GFP_KERNEL);
if (ret)
goto unwind;
@@ -1566,6 +1514,38 @@ static bool vfio_iommu_iova_dma_valid(struct vfio_iommu *iommu,
return list_empty(iova);
}
+static int vfio_change_dma_owner(struct vfio_dma *dma)
+{
+ struct task_struct *task = current->group_leader;
+ struct mm_struct *mm = current->mm;
+ long npage = dma->locked_vm;
+ bool lock_cap;
+ int ret;
+
+ if (mm == dma->mm)
+ return 0;
+
+ lock_cap = capable(CAP_IPC_LOCK);
+ ret = mm_lock_acct(task, mm, lock_cap, npage);
+ if (ret)
+ return ret;
+
+ if (mmget_not_zero(dma->mm)) {
+ mm_lock_acct(dma->task, dma->mm, dma->lock_cap, -npage);
+ mmput(dma->mm);
+ }
+
+ if (dma->task != task) {
+ put_task_struct(dma->task);
+ dma->task = get_task_struct(task);
+ }
+ mmdrop(dma->mm);
+ dma->mm = mm;
+ mmgrab(dma->mm);
+ dma->lock_cap = lock_cap;
+ return 0;
+}
+
static int vfio_dma_do_map(struct vfio_iommu *iommu,
struct vfio_iommu_type1_dma_map *map)
{
@@ -1615,10 +1595,12 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
dma->size != size) {
ret = -EINVAL;
} else {
+ ret = vfio_change_dma_owner(dma);
+ if (ret)
+ goto out_unlock;
dma->vaddr = vaddr;
dma->vaddr_invalid = false;
iommu->vaddr_invalid_count--;
- wake_up_all(&iommu->vaddr_wait);
}
goto out_unlock;
} else if (dma) {
@@ -1652,29 +1634,15 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
* against the locked memory limit and we need to be able to do both
* outside of this call path as pinning can be asynchronous via the
* external interfaces for mdev devices. RLIMIT_MEMLOCK requires a
- * task_struct and VM locked pages requires an mm_struct, however
- * holding an indefinite mm reference is not recommended, therefore we
- * only hold a reference to a task. We could hold a reference to
- * current, however QEMU uses this call path through vCPU threads,
- * which can be killed resulting in a NULL mm and failure in the unmap
- * path when called via a different thread. Avoid this problem by
- * using the group_leader as threads within the same group require
- * both CLONE_THREAD and CLONE_VM and will therefore use the same
- * mm_struct.
- *
- * Previously we also used the task for testing CAP_IPC_LOCK at the
- * time of pinning and accounting, however has_capability() makes use
- * of real_cred, a copy-on-write field, so we can't guarantee that it
- * matches group_leader, or in fact that it might not change by the
- * time it's evaluated. If a process were to call MAP_DMA with
- * CAP_IPC_LOCK but later drop it, it doesn't make sense that they
- * possibly see different results for an iommu_mapped vfio_dma vs
- * externally mapped. Therefore track CAP_IPC_LOCK in vfio_dma at the
- * time of calling MAP_DMA.
+ * task_struct. Save the group_leader so that all DMA tracking uses
+ * the same task, to make debugging easier. VM locked pages requires
+ * an mm_struct, so grab the mm in case the task dies.
*/
get_task_struct(current->group_leader);
dma->task = current->group_leader;
dma->lock_cap = capable(CAP_IPC_LOCK);
+ dma->mm = current->mm;
+ mmgrab(dma->mm);
dma->pfn_list = RB_ROOT;
@@ -1707,10 +1675,6 @@ static int vfio_iommu_replay(struct vfio_iommu *iommu,
unsigned long limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
int ret;
- ret = vfio_wait_all_valid(iommu);
- if (ret < 0)
- return ret;
-
/* Arbitrarily pick the first domain in the list for lookups */
if (!list_empty(&iommu->domain_list))
d = list_first_entry(&iommu->domain_list,
@@ -1777,8 +1741,8 @@ static int vfio_iommu_replay(struct vfio_iommu *iommu,
size = npage << PAGE_SHIFT;
}
- ret = iommu_map(domain->domain, iova, phys,
- size, dma->prot | IOMMU_CACHE);
+ ret = iommu_map(domain->domain, iova, phys, size,
+ dma->prot | IOMMU_CACHE, GFP_KERNEL);
if (ret) {
if (!dma->iommu_mapped) {
vfio_unpin_pages_remote(dma, iova,
@@ -1873,7 +1837,7 @@ static void vfio_test_domain_fgsp(struct vfio_domain *domain, struct list_head *
continue;
ret = iommu_map(domain->domain, start, page_to_phys(pages), PAGE_SIZE * 2,
- IOMMU_READ | IOMMU_WRITE | IOMMU_CACHE);
+ IOMMU_READ | IOMMU_WRITE | IOMMU_CACHE, GFP_KERNEL);
if (!ret) {
size_t unmapped = iommu_unmap(domain->domain, start, PAGE_SIZE);
@@ -2169,12 +2133,6 @@ static void vfio_iommu_iova_insert_copy(struct vfio_iommu *iommu,
list_splice_tail(iova_copy, iova);
}
-/* Redundantly walks non-present capabilities to simplify caller */
-static int vfio_iommu_device_capable(struct device *dev, void *data)
-{
- return device_iommu_capable(dev, (enum iommu_cap)data);
-}
-
static int vfio_iommu_domain_alloc(struct device *dev, void *data)
{
struct iommu_domain **domain = data;
@@ -2189,16 +2147,21 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,
struct vfio_iommu *iommu = iommu_data;
struct vfio_iommu_group *group;
struct vfio_domain *domain, *d;
- bool resv_msi, msi_remap;
+ bool resv_msi;
phys_addr_t resv_msi_base = 0;
struct iommu_domain_geometry *geo;
LIST_HEAD(iova_copy);
LIST_HEAD(group_resv_regions);
- int ret = -EINVAL;
+ int ret = -EBUSY;
mutex_lock(&iommu->lock);
+ /* Attach could require pinning, so disallow while vaddr is invalid. */
+ if (iommu->vaddr_invalid_count)
+ goto out_unlock;
+
/* Check for duplicates */
+ ret = -EINVAL;
if (vfio_iommu_find_iommu_group(iommu, iommu_group))
goto out_unlock;
@@ -2287,11 +2250,8 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,
INIT_LIST_HEAD(&domain->group_list);
list_add(&group->next, &domain->group_list);
- msi_remap = irq_domain_check_msi_remap() ||
- iommu_group_for_each_dev(iommu_group, (void *)IOMMU_CAP_INTR_REMAP,
- vfio_iommu_device_capable);
-
- if (!allow_unsafe_interrupts && !msi_remap) {
+ if (!allow_unsafe_interrupts &&
+ !iommu_group_has_isolated_msi(iommu_group)) {
pr_warn("%s: No interrupt remapping support. Use the module param \"allow_unsafe_interrupts\" to enable VFIO IOMMU support on this platform\n",
__func__);
ret = -EPERM;
@@ -2601,11 +2561,9 @@ static void *vfio_iommu_type1_open(unsigned long arg)
INIT_LIST_HEAD(&iommu->iova_list);
iommu->dma_list = RB_ROOT;
iommu->dma_avail = dma_entry_limit;
- iommu->container_open = true;
mutex_init(&iommu->lock);
mutex_init(&iommu->device_list_lock);
INIT_LIST_HEAD(&iommu->device_list);
- init_waitqueue_head(&iommu->vaddr_wait);
iommu->pgsize_bitmap = PAGE_MASK;
INIT_LIST_HEAD(&iommu->emulated_iommu_groups);
@@ -2669,6 +2627,16 @@ static int vfio_domains_have_enforce_cache_coherency(struct vfio_iommu *iommu)
return ret;
}
+static bool vfio_iommu_has_emulated(struct vfio_iommu *iommu)
+{
+ bool ret;
+
+ mutex_lock(&iommu->lock);
+ ret = !list_empty(&iommu->emulated_iommu_groups);
+ mutex_unlock(&iommu->lock);
+ return ret;
+}
+
static int vfio_iommu_type1_check_extension(struct vfio_iommu *iommu,
unsigned long arg)
{
@@ -2677,8 +2645,13 @@ static int vfio_iommu_type1_check_extension(struct vfio_iommu *iommu,
case VFIO_TYPE1v2_IOMMU:
case VFIO_TYPE1_NESTING_IOMMU:
case VFIO_UNMAP_ALL:
- case VFIO_UPDATE_VADDR:
return 1;
+ case VFIO_UPDATE_VADDR:
+ /*
+ * Disable this feature if mdevs are present. They cannot
+ * safely pin/unpin/rw while vaddrs are being updated.
+ */
+ return iommu && !vfio_iommu_has_emulated(iommu);
case VFIO_DMA_CC_IOMMU:
if (!iommu)
return 0;
@@ -3087,21 +3060,19 @@ static int vfio_iommu_type1_dma_rw_chunk(struct vfio_iommu *iommu,
struct vfio_dma *dma;
bool kthread = current->mm == NULL;
size_t offset;
- int ret;
*copied = 0;
- ret = vfio_find_dma_valid(iommu, user_iova, 1, &dma);
- if (ret < 0)
- return ret;
+ dma = vfio_find_dma(iommu, user_iova, 1);
+ if (!dma)
+ return -EINVAL;
if ((write && !(dma->prot & IOMMU_WRITE)) ||
!(dma->prot & IOMMU_READ))
return -EPERM;
- mm = get_task_mm(dma->task);
-
- if (!mm)
+ mm = dma->mm;
+ if (!mmget_not_zero(mm))
return -EPERM;
if (kthread)
@@ -3147,6 +3118,13 @@ static int vfio_iommu_type1_dma_rw(void *iommu_data, dma_addr_t user_iova,
size_t done;
mutex_lock(&iommu->lock);
+
+ if (WARN_ONCE(iommu->vaddr_invalid_count,
+ "vfio_dma_rw not allowed with VFIO_UPDATE_VADDR\n")) {
+ ret = -EBUSY;
+ goto out;
+ }
+
while (count > 0) {
ret = vfio_iommu_type1_dma_rw_chunk(iommu, user_iova, data,
count, write, &done);
@@ -3158,6 +3136,7 @@ static int vfio_iommu_type1_dma_rw(void *iommu_data, dma_addr_t user_iova,
user_iova += done;
}
+out:
mutex_unlock(&iommu->lock);
return ret;
}
@@ -3185,19 +3164,6 @@ vfio_iommu_type1_group_iommu_domain(void *iommu_data,
return domain;
}
-static void vfio_iommu_type1_notify(void *iommu_data,
- enum vfio_iommu_notify_type event)
-{
- struct vfio_iommu *iommu = iommu_data;
-
- if (event != VFIO_IOMMU_CONTAINER_CLOSE)
- return;
- mutex_lock(&iommu->lock);
- iommu->container_open = false;
- mutex_unlock(&iommu->lock);
- wake_up_all(&iommu->vaddr_wait);
-}
-
static const struct vfio_iommu_driver_ops vfio_iommu_driver_ops_type1 = {
.name = "vfio-iommu-type1",
.owner = THIS_MODULE,
@@ -3212,7 +3178,6 @@ static const struct vfio_iommu_driver_ops vfio_iommu_driver_ops_type1 = {
.unregister_device = vfio_iommu_type1_unregister_device,
.dma_rw = vfio_iommu_type1_dma_rw,
.group_iommu_domain = vfio_iommu_type1_group_iommu_domain,
- .notify = vfio_iommu_type1_notify,
};
static int __init vfio_iommu_type1_init(void)
diff --git a/drivers/vfio/vfio_main.c b/drivers/vfio/vfio_main.c
index 5177bb061b17..43bd6b76e2b6 100644
--- a/drivers/vfio/vfio_main.c
+++ b/drivers/vfio/vfio_main.c
@@ -16,6 +16,9 @@
#include <linux/fs.h>
#include <linux/idr.h>
#include <linux/iommu.h>
+#ifdef CONFIG_HAVE_KVM
+#include <linux/kvm_host.h>
+#endif
#include <linux/list.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
@@ -45,6 +48,13 @@ static struct vfio {
struct ida device_ida;
} vfio;
+#ifdef CONFIG_VFIO_NOIOMMU
+bool vfio_noiommu __read_mostly;
+module_param_named(enable_unsafe_noiommu_mode,
+ vfio_noiommu, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(enable_unsafe_noiommu_mode, "Enable UNSAFE, no-IOMMU mode. This mode provides no device isolation, no DMA translation, no host kernel protection, cannot be used for device assignment to virtual machines, requires RAWIO permissions, and will taint the kernel. If you do not know what this is for, step away. (default: false)");
+#endif
+
static DEFINE_XARRAY(vfio_device_set_xa);
int vfio_assign_device_set(struct vfio_device *device, void *set_id)
@@ -338,6 +348,55 @@ void vfio_unregister_group_dev(struct vfio_device *device)
}
EXPORT_SYMBOL_GPL(vfio_unregister_group_dev);
+#ifdef CONFIG_HAVE_KVM
+void _vfio_device_get_kvm_safe(struct vfio_device *device, struct kvm *kvm)
+{
+ void (*pfn)(struct kvm *kvm);
+ bool (*fn)(struct kvm *kvm);
+ bool ret;
+
+ lockdep_assert_held(&device->dev_set->lock);
+
+ pfn = symbol_get(kvm_put_kvm);
+ if (WARN_ON(!pfn))
+ return;
+
+ fn = symbol_get(kvm_get_kvm_safe);
+ if (WARN_ON(!fn)) {
+ symbol_put(kvm_put_kvm);
+ return;
+ }
+
+ ret = fn(kvm);
+ symbol_put(kvm_get_kvm_safe);
+ if (!ret) {
+ symbol_put(kvm_put_kvm);
+ return;
+ }
+
+ device->put_kvm = pfn;
+ device->kvm = kvm;
+}
+
+void vfio_device_put_kvm(struct vfio_device *device)
+{
+ lockdep_assert_held(&device->dev_set->lock);
+
+ if (!device->kvm)
+ return;
+
+ if (WARN_ON(!device->put_kvm))
+ goto clear;
+
+ device->put_kvm(device->kvm);
+ device->put_kvm = NULL;
+ symbol_put(kvm_put_kvm);
+
+clear:
+ device->kvm = NULL;
+}
+#endif
+
/* true if the vfio_device has open_device() called but not close_device() */
static bool vfio_assert_device_open(struct vfio_device *device)
{
@@ -345,7 +404,7 @@ static bool vfio_assert_device_open(struct vfio_device *device)
}
static int vfio_device_first_open(struct vfio_device *device,
- struct iommufd_ctx *iommufd, struct kvm *kvm)
+ struct iommufd_ctx *iommufd)
{
int ret;
@@ -361,7 +420,6 @@ static int vfio_device_first_open(struct vfio_device *device,
if (ret)
goto err_module_put;
- device->kvm = kvm;
if (device->ops->open_device) {
ret = device->ops->open_device(device);
if (ret)
@@ -370,7 +428,6 @@ static int vfio_device_first_open(struct vfio_device *device,
return 0;
err_unuse_iommu:
- device->kvm = NULL;
if (iommufd)
vfio_iommufd_unbind(device);
else
@@ -387,7 +444,6 @@ static void vfio_device_last_close(struct vfio_device *device,
if (device->ops->close_device)
device->ops->close_device(device);
- device->kvm = NULL;
if (iommufd)
vfio_iommufd_unbind(device);
else
@@ -395,19 +451,18 @@ static void vfio_device_last_close(struct vfio_device *device,
module_put(device->dev->driver->owner);
}
-int vfio_device_open(struct vfio_device *device,
- struct iommufd_ctx *iommufd, struct kvm *kvm)
+int vfio_device_open(struct vfio_device *device, struct iommufd_ctx *iommufd)
{
int ret = 0;
- mutex_lock(&device->dev_set->lock);
+ lockdep_assert_held(&device->dev_set->lock);
+
device->open_count++;
if (device->open_count == 1) {
- ret = vfio_device_first_open(device, iommufd, kvm);
+ ret = vfio_device_first_open(device, iommufd);
if (ret)
device->open_count--;
}
- mutex_unlock(&device->dev_set->lock);
return ret;
}
@@ -415,12 +470,12 @@ int vfio_device_open(struct vfio_device *device,
void vfio_device_close(struct vfio_device *device,
struct iommufd_ctx *iommufd)
{
- mutex_lock(&device->dev_set->lock);
+ lockdep_assert_held(&device->dev_set->lock);
+
vfio_assert_device_open(device);
if (device->open_count == 1)
vfio_device_last_close(device, iommufd);
device->open_count--;
- mutex_unlock(&device->dev_set->lock);
}
/*
diff --git a/drivers/vfio/virqfd.c b/drivers/vfio/virqfd.c
index 497a17b37865..29c564b7a6e1 100644
--- a/drivers/vfio/virqfd.c
+++ b/drivers/vfio/virqfd.c
@@ -112,7 +112,7 @@ int vfio_virqfd_enable(void *opaque,
int ret = 0;
__poll_t events;
- virqfd = kzalloc(sizeof(*virqfd), GFP_KERNEL);
+ virqfd = kzalloc(sizeof(*virqfd), GFP_KERNEL_ACCOUNT);
if (!virqfd)
return -ENOMEM;
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index 4c538b30fd76..07181cd8d52e 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -73,7 +73,8 @@ enum {
VHOST_NET_FEATURES = VHOST_FEATURES |
(1ULL << VHOST_NET_F_VIRTIO_NET_HDR) |
(1ULL << VIRTIO_NET_F_MRG_RXBUF) |
- (1ULL << VIRTIO_F_ACCESS_PLATFORM)
+ (1ULL << VIRTIO_F_ACCESS_PLATFORM) |
+ (1ULL << VIRTIO_F_RING_RESET)
};
enum {
@@ -1645,7 +1646,7 @@ static int vhost_net_set_features(struct vhost_net *n, u64 features)
goto out_unlock;
if ((features & (1ULL << VIRTIO_F_ACCESS_PLATFORM))) {
- if (vhost_init_device_iotlb(&n->dev, true))
+ if (vhost_init_device_iotlb(&n->dev))
goto out_unlock;
}
diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c
index d5ecb8876fc9..b244e7c0f514 100644
--- a/drivers/vhost/scsi.c
+++ b/drivers/vhost/scsi.c
@@ -2105,7 +2105,7 @@ static ssize_t vhost_scsi_tpg_attrib_fabric_prot_type_show(
struct vhost_scsi_tpg *tpg = container_of(se_tpg,
struct vhost_scsi_tpg, se_tpg);
- return sprintf(page, "%d\n", tpg->tv_fabric_prot_type);
+ return sysfs_emit(page, "%d\n", tpg->tv_fabric_prot_type);
}
CONFIGFS_ATTR(vhost_scsi_tpg_attrib_, fabric_prot_type);
@@ -2215,7 +2215,7 @@ static ssize_t vhost_scsi_tpg_nexus_show(struct config_item *item, char *page)
mutex_unlock(&tpg->tv_tpg_mutex);
return -ENODEV;
}
- ret = snprintf(page, PAGE_SIZE, "%s\n",
+ ret = sysfs_emit(page, "%s\n",
tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
mutex_unlock(&tpg->tv_tpg_mutex);
@@ -2440,7 +2440,7 @@ static void vhost_scsi_drop_tport(struct se_wwn *wwn)
static ssize_t
vhost_scsi_wwn_version_show(struct config_item *item, char *page)
{
- return sprintf(page, "TCM_VHOST fabric module %s on %s/%s"
+ return sysfs_emit(page, "TCM_VHOST fabric module %s on %s/%s"
"on "UTS_RELEASE"\n", VHOST_SCSI_VERSION, utsname()->sysname,
utsname()->machine);
}
diff --git a/drivers/vhost/test.c b/drivers/vhost/test.c
index bc8e7fb1e635..42c955a5b211 100644
--- a/drivers/vhost/test.c
+++ b/drivers/vhost/test.c
@@ -333,13 +333,10 @@ static long vhost_test_ioctl(struct file *f, unsigned int ioctl,
return -EFAULT;
return 0;
case VHOST_SET_FEATURES:
- printk(KERN_ERR "1\n");
if (copy_from_user(&features, featurep, sizeof features))
return -EFAULT;
- printk(KERN_ERR "2\n");
if (features & ~VHOST_FEATURES)
return -EOPNOTSUPP;
- printk(KERN_ERR "3\n");
return vhost_test_set_features(n, features);
case VHOST_RESET_OWNER:
return vhost_test_reset_owner(n);
diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c
index ec32f785dfde..dc12dbd5b43b 100644
--- a/drivers/vhost/vdpa.c
+++ b/drivers/vhost/vdpa.c
@@ -359,6 +359,14 @@ static bool vhost_vdpa_can_suspend(const struct vhost_vdpa *v)
return ops->suspend;
}
+static bool vhost_vdpa_can_resume(const struct vhost_vdpa *v)
+{
+ struct vdpa_device *vdpa = v->vdpa;
+ const struct vdpa_config_ops *ops = vdpa->config;
+
+ return ops->resume;
+}
+
static long vhost_vdpa_get_features(struct vhost_vdpa *v, u64 __user *featurep)
{
struct vdpa_device *vdpa = v->vdpa;
@@ -498,6 +506,21 @@ static long vhost_vdpa_suspend(struct vhost_vdpa *v)
return ops->suspend(vdpa);
}
+/* After a successful return of this ioctl the device resumes processing
+ * virtqueue descriptors. The device becomes fully operational the same way it
+ * was before it was suspended.
+ */
+static long vhost_vdpa_resume(struct vhost_vdpa *v)
+{
+ struct vdpa_device *vdpa = v->vdpa;
+ const struct vdpa_config_ops *ops = vdpa->config;
+
+ if (!ops->resume)
+ return -EOPNOTSUPP;
+
+ return ops->resume(vdpa);
+}
+
static long vhost_vdpa_vring_ioctl(struct vhost_vdpa *v, unsigned int cmd,
void __user *argp)
{
@@ -606,11 +629,15 @@ static long vhost_vdpa_unlocked_ioctl(struct file *filep,
if (copy_from_user(&features, featurep, sizeof(features)))
return -EFAULT;
if (features & ~(VHOST_VDPA_BACKEND_FEATURES |
- BIT_ULL(VHOST_BACKEND_F_SUSPEND)))
+ BIT_ULL(VHOST_BACKEND_F_SUSPEND) |
+ BIT_ULL(VHOST_BACKEND_F_RESUME)))
return -EOPNOTSUPP;
if ((features & BIT_ULL(VHOST_BACKEND_F_SUSPEND)) &&
!vhost_vdpa_can_suspend(v))
return -EOPNOTSUPP;
+ if ((features & BIT_ULL(VHOST_BACKEND_F_RESUME)) &&
+ !vhost_vdpa_can_resume(v))
+ return -EOPNOTSUPP;
vhost_set_backend_features(&v->vdev, features);
return 0;
}
@@ -662,6 +689,8 @@ static long vhost_vdpa_unlocked_ioctl(struct file *filep,
features = VHOST_VDPA_BACKEND_FEATURES;
if (vhost_vdpa_can_suspend(v))
features |= BIT_ULL(VHOST_BACKEND_F_SUSPEND);
+ if (vhost_vdpa_can_resume(v))
+ features |= BIT_ULL(VHOST_BACKEND_F_RESUME);
if (copy_to_user(featurep, &features, sizeof(features)))
r = -EFAULT;
break;
@@ -677,6 +706,9 @@ static long vhost_vdpa_unlocked_ioctl(struct file *filep,
case VHOST_VDPA_SUSPEND:
r = vhost_vdpa_suspend(v);
break;
+ case VHOST_VDPA_RESUME:
+ r = vhost_vdpa_resume(v);
+ break;
default:
r = vhost_dev_ioctl(&v->vdev, cmd, argp);
if (r == -ENOIOCTLCMD)
@@ -792,7 +824,7 @@ static int vhost_vdpa_map(struct vhost_vdpa *v, struct vhost_iotlb *iotlb,
r = ops->set_map(vdpa, asid, iotlb);
} else {
r = iommu_map(v->domain, iova, pa, size,
- perm_to_iommu_flags(perm));
+ perm_to_iommu_flags(perm), GFP_KERNEL);
}
if (r) {
vhost_iotlb_del_range(iotlb, iova, iova + size - 1);
@@ -1119,8 +1151,11 @@ static int vhost_vdpa_alloc_domain(struct vhost_vdpa *v)
if (!bus)
return -EFAULT;
- if (!device_iommu_capable(dma_dev, IOMMU_CAP_CACHE_COHERENCY))
+ if (!device_iommu_capable(dma_dev, IOMMU_CAP_CACHE_COHERENCY)) {
+ dev_warn_once(&v->dev,
+ "Failed to allocate domain, device is not IOMMU cache coherent capable\n");
return -ENOTSUPP;
+ }
v->domain = iommu_domain_alloc(bus);
if (!v->domain)
@@ -1315,7 +1350,7 @@ static int vhost_vdpa_mmap(struct file *file, struct vm_area_struct *vma)
if (vma->vm_end - vma->vm_start != notify.size)
return -ENOTSUPP;
- vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP;
+ vm_flags_set(vma, VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP);
vma->vm_ops = &vhost_vdpa_vm_ops;
return 0;
}
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index 43c9770b86e5..f11bdbe4c2c5 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -1730,7 +1730,7 @@ long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *arg
}
EXPORT_SYMBOL_GPL(vhost_vring_ioctl);
-int vhost_init_device_iotlb(struct vhost_dev *d, bool enabled)
+int vhost_init_device_iotlb(struct vhost_dev *d)
{
struct vhost_iotlb *niotlb, *oiotlb;
int i;
diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h
index 790b296271f1..1647b750169c 100644
--- a/drivers/vhost/vhost.h
+++ b/drivers/vhost/vhost.h
@@ -222,7 +222,7 @@ ssize_t vhost_chr_read_iter(struct vhost_dev *dev, struct iov_iter *to,
int noblock);
ssize_t vhost_chr_write_iter(struct vhost_dev *dev,
struct iov_iter *from);
-int vhost_init_device_iotlb(struct vhost_dev *d, bool enabled);
+int vhost_init_device_iotlb(struct vhost_dev *d);
void vhost_iotlb_map_free(struct vhost_iotlb *iotlb,
struct vhost_iotlb_map *map);
diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c
index 1f3b89c885cc..c8e6087769a1 100644
--- a/drivers/vhost/vsock.c
+++ b/drivers/vhost/vsock.c
@@ -793,7 +793,7 @@ static int vhost_vsock_set_features(struct vhost_vsock *vsock, u64 features)
}
if ((features & (1ULL << VIRTIO_F_ACCESS_PLATFORM))) {
- if (vhost_init_device_iotlb(&vsock->dev, true))
+ if (vhost_init_device_iotlb(&vsock->dev))
goto err;
}
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 936ba1e4d35e..4c33e971c0f0 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -90,13 +90,6 @@ config LCD_PLATFORM
This driver provides a platform-device registered LCD power
control interface.
-config LCD_TOSA
- tristate "Sharp SL-6000 LCD Driver"
- depends on I2C && SPI && MACH_TOSA
- help
- If you have an Sharp SL-6000 Zaurus say Y to enable a driver
- for its LCD.
-
config LCD_HP700
tristate "HP Jornada 700 series LCD Driver"
depends on SA1100_JORNADA720_SSP && !PREEMPTION
@@ -190,6 +183,14 @@ config BACKLIGHT_KTD253
which is a 1-wire GPIO-controlled backlight found in some mobile
phones.
+config BACKLIGHT_KTZ8866
+ tristate "Backlight Driver for Kinetic KTZ8866"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ Say Y to enable the backlight driver for the Kinetic KTZ8866
+ found in Xiaomi Mi Pad 5 series.
+
config BACKLIGHT_LM3533
tristate "Backlight Driver for LM3533"
depends on MFD_LM3533
@@ -288,13 +289,6 @@ config BACKLIGHT_APPLE
If you have an Intel-based Apple say Y to enable a driver for its
backlight.
-config BACKLIGHT_TOSA
- tristate "Sharp SL-6000 Backlight Driver"
- depends on I2C && MACH_TOSA && LCD_TOSA
- help
- If you have an Sharp SL-6000 Zaurus say Y to enable a driver
- for its backlight
-
config BACKLIGHT_QCOM_WLED
tristate "Qualcomm PMIC WLED Driver"
select REGMAP
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index e815f3f1deff..f72e1c3c59e9 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -15,7 +15,6 @@ obj-$(CONFIG_LCD_LTV350QV) += ltv350qv.o
obj-$(CONFIG_LCD_OTM3225A) += otm3225a.o
obj-$(CONFIG_LCD_PLATFORM) += platform_lcd.o
obj-$(CONFIG_LCD_TDO24M) += tdo24m.o
-obj-$(CONFIG_LCD_TOSA) += tosa_lcd.o
obj-$(CONFIG_LCD_VGG2432A4) += vgg2432a4.o
obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o
@@ -36,6 +35,7 @@ obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o
obj-$(CONFIG_BACKLIGHT_HP700) += jornada720_bl.o
obj-$(CONFIG_BACKLIGHT_IPAQ_MICRO) += ipaq_micro_bl.o
obj-$(CONFIG_BACKLIGHT_KTD253) += ktd253-backlight.o
+obj-$(CONFIG_BACKLIGHT_KTZ8866) += ktz8866.o
obj-$(CONFIG_BACKLIGHT_LM3533) += lm3533_bl.o
obj-$(CONFIG_BACKLIGHT_LM3630A) += lm3630a_bl.o
obj-$(CONFIG_BACKLIGHT_LM3639) += lm3639_bl.o
@@ -53,7 +53,6 @@ obj-$(CONFIG_BACKLIGHT_QCOM_WLED) += qcom-wled.o
obj-$(CONFIG_BACKLIGHT_RT4831) += rt4831-backlight.o
obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o
obj-$(CONFIG_BACKLIGHT_SKY81452) += sky81452-backlight.o
-obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o
obj-$(CONFIG_BACKLIGHT_TPS65217) += tps65217_bl.o
obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o
obj-$(CONFIG_BACKLIGHT_ARCXCNN) += arcxcnn_bl.o
diff --git a/drivers/video/backlight/aat2870_bl.c b/drivers/video/backlight/aat2870_bl.c
index a7af9adafad6..1cbb303e9c88 100644
--- a/drivers/video/backlight/aat2870_bl.c
+++ b/drivers/video/backlight/aat2870_bl.c
@@ -59,7 +59,7 @@ static int aat2870_bl_update_status(struct backlight_device *bd)
struct aat2870_bl_driver_data *aat2870_bl = bl_get_data(bd);
struct aat2870_data *aat2870 =
dev_get_drvdata(aat2870_bl->pdev->dev.parent);
- int brightness = bd->props.brightness;
+ int brightness = backlight_get_brightness(bd);
int ret;
if ((brightness < 0) || (bd->props.max_brightness < brightness)) {
@@ -70,11 +70,6 @@ static int aat2870_bl_update_status(struct backlight_device *bd)
dev_dbg(&bd->dev, "brightness=%d, power=%d, state=%d\n",
bd->props.brightness, bd->props.power, bd->props.state);
- if ((bd->props.power != FB_BLANK_UNBLANK) ||
- (bd->props.state & BL_CORE_FBBLANK) ||
- (bd->props.state & BL_CORE_SUSPENDED))
- brightness = 0;
-
ret = aat2870->write(aat2870, AAT2870_BLM,
(u8)aat2870_brightness(aat2870_bl, brightness));
if (ret < 0)
diff --git a/drivers/video/backlight/arcxcnn_bl.c b/drivers/video/backlight/arcxcnn_bl.c
index 555b036643fb..e610d7a1d13d 100644
--- a/drivers/video/backlight/arcxcnn_bl.c
+++ b/drivers/video/backlight/arcxcnn_bl.c
@@ -130,12 +130,9 @@ static int arcxcnn_set_brightness(struct arcxcnn *lp, u32 brightness)
static int arcxcnn_bl_update_status(struct backlight_device *bl)
{
struct arcxcnn *lp = bl_get_data(bl);
- u32 brightness = bl->props.brightness;
+ u32 brightness = backlight_get_brightness(bl);
int ret;
- if (bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
- brightness = 0;
-
ret = arcxcnn_set_brightness(lp, brightness);
if (ret)
return ret;
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
index b788ff3d0f45..6eea72aa8dbf 100644
--- a/drivers/video/backlight/backlight.c
+++ b/drivers/video/backlight/backlight.c
@@ -501,7 +501,7 @@ EXPORT_SYMBOL(backlight_device_get_by_type);
*
* This function looks up a backlight device by its name. It obtains a reference
* on the backlight device and it is the caller's responsibility to drop the
- * reference by calling backlight_put().
+ * reference by calling put_device().
*
* Returns:
* A pointer to the backlight device if found, otherwise NULL.
diff --git a/drivers/video/backlight/ipaq_micro_bl.c b/drivers/video/backlight/ipaq_micro_bl.c
index 85b16cc82878..f595b8c8cbb2 100644
--- a/drivers/video/backlight/ipaq_micro_bl.c
+++ b/drivers/video/backlight/ipaq_micro_bl.c
@@ -16,17 +16,12 @@
static int micro_bl_update_status(struct backlight_device *bd)
{
struct ipaq_micro *micro = dev_get_drvdata(&bd->dev);
- int intensity = bd->props.brightness;
+ int intensity = backlight_get_brightness(bd);
struct ipaq_micro_msg msg = {
.id = MSG_BACKLIGHT,
.tx_len = 3,
};
- if (bd->props.power != FB_BLANK_UNBLANK)
- intensity = 0;
- if (bd->props.state & (BL_CORE_FBBLANK | BL_CORE_SUSPENDED))
- intensity = 0;
-
/*
* Message format:
* Byte 0: backlight instance (usually 1)
diff --git a/drivers/video/backlight/ktd253-backlight.c b/drivers/video/backlight/ktd253-backlight.c
index 37aa5a669530..d7d43454f64a 100644
--- a/drivers/video/backlight/ktd253-backlight.c
+++ b/drivers/video/backlight/ktd253-backlight.c
@@ -173,12 +173,9 @@ static int ktd253_backlight_probe(struct platform_device *pdev)
}
ktd253->gpiod = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
- if (IS_ERR(ktd253->gpiod)) {
- ret = PTR_ERR(ktd253->gpiod);
- if (ret != -EPROBE_DEFER)
- dev_err(dev, "gpio line missing or invalid.\n");
- return ret;
- }
+ if (IS_ERR(ktd253->gpiod))
+ return dev_err_probe(dev, PTR_ERR(ktd253->gpiod),
+ "gpio line missing or invalid.\n");
gpiod_set_consumer_name(ktd253->gpiod, dev_name(dev));
/* Bring backlight to a known off state */
msleep(KTD253_T_OFF_MS);
diff --git a/drivers/video/backlight/ktz8866.c b/drivers/video/backlight/ktz8866.c
new file mode 100644
index 000000000000..d38c13ad39c7
--- /dev/null
+++ b/drivers/video/backlight/ktz8866.c
@@ -0,0 +1,208 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Backlight driver for the Kinetic KTZ8866
+ *
+ * Copyright (C) 2022, 2023 Jianhua Lu <lujianhua000@gmail.com>
+ */
+
+#include <linux/backlight.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+
+#define DEFAULT_BRIGHTNESS 1500
+#define MAX_BRIGHTNESS 2047
+#define REG_MAX 0x15
+
+/* reg */
+#define DEVICE_ID 0x01
+#define BL_CFG1 0x02
+#define BL_CFG2 0x03
+#define BL_BRT_LSB 0x04
+#define BL_BRT_MSB 0x05
+#define BL_EN 0x08
+#define LCD_BIAS_CFG1 0x09
+#define LCD_BIAS_CFG2 0x0A
+#define LCD_BIAS_CFG3 0x0B
+#define LCD_BOOST_CFG 0x0C
+#define OUTP_CFG 0x0D
+#define OUTN_CFG 0x0E
+#define FLAG 0x0F
+#define BL_OPTION1 0x10
+#define BL_OPTION2 0x11
+#define PWM2DIG_LSBs 0x12
+#define PWM2DIG_MSBs 0x13
+#define BL_DIMMING 0x14
+#define PWM_RAMP_TIME 0x15
+
+/* definition */
+#define BL_EN_BIT BIT(6)
+#define LCD_BIAS_EN 0x9F
+#define PWM_HYST 0x5
+
+struct ktz8866 {
+ struct i2c_client *client;
+ struct regmap *regmap;
+ bool led_on;
+ struct gpio_desc *enable_gpio;
+};
+
+static const struct regmap_config ktz8866_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = REG_MAX,
+};
+
+static int ktz8866_write(struct ktz8866 *ktz, unsigned int reg,
+ unsigned int val)
+{
+ return regmap_write(ktz->regmap, reg, val);
+}
+
+static int ktz8866_update_bits(struct ktz8866 *ktz, unsigned int reg,
+ unsigned int mask, unsigned int val)
+{
+ return regmap_update_bits(ktz->regmap, reg, mask, val);
+}
+
+static int ktz8866_backlight_update_status(struct backlight_device *backlight_dev)
+{
+ struct ktz8866 *ktz = bl_get_data(backlight_dev);
+ unsigned int brightness = backlight_get_brightness(backlight_dev);
+
+ if (!ktz->led_on && brightness > 0) {
+ ktz8866_update_bits(ktz, BL_EN, BL_EN_BIT, BL_EN_BIT);
+ ktz->led_on = true;
+ } else if (brightness == 0) {
+ ktz8866_update_bits(ktz, BL_EN, BL_EN_BIT, 0);
+ ktz->led_on = false;
+ }
+
+ /* Set brightness */
+ ktz8866_write(ktz, BL_BRT_LSB, brightness & 0x7);
+ ktz8866_write(ktz, BL_BRT_MSB, (brightness >> 3) & 0xFF);
+
+ return 0;
+}
+
+static const struct backlight_ops ktz8866_backlight_ops = {
+ .options = BL_CORE_SUSPENDRESUME,
+ .update_status = ktz8866_backlight_update_status,
+};
+
+static void ktz8866_init(struct ktz8866 *ktz)
+{
+ unsigned int val = 0;
+
+ if (of_property_read_u32(ktz->client->dev.of_node, "current-num-sinks", &val))
+ ktz8866_write(ktz, BL_EN, BIT(val) - 1);
+ else
+ /* Enable all 6 current sinks if the number of current sinks isn't specified. */
+ ktz8866_write(ktz, BL_EN, BIT(6) - 1);
+
+ if (of_property_read_u32(ktz->client->dev.of_node, "kinetic,current-ramp-delay-ms", &val)) {
+ if (val <= 128)
+ ktz8866_write(ktz, BL_CFG2, BIT(7) | (ilog2(val) << 3) | PWM_HYST);
+ else
+ ktz8866_write(ktz, BL_CFG2, BIT(7) | ((5 + val / 64) << 3) | PWM_HYST);
+ }
+
+ if (of_property_read_u32(ktz->client->dev.of_node, "kinetic,led-enable-ramp-delay-ms", &val)) {
+ if (val == 0)
+ ktz8866_write(ktz, BL_DIMMING, 0);
+ else {
+ unsigned int ramp_off_time = ilog2(val) + 1;
+ unsigned int ramp_on_time = ramp_off_time << 4;
+ ktz8866_write(ktz, BL_DIMMING, ramp_on_time | ramp_off_time);
+ }
+ }
+
+ if (of_property_read_bool(ktz->client->dev.of_node, "kinetic,enable-lcd-bias"))
+ ktz8866_write(ktz, LCD_BIAS_CFG1, LCD_BIAS_EN);
+}
+
+static int ktz8866_probe(struct i2c_client *client)
+{
+ struct backlight_device *backlight_dev;
+ struct backlight_properties props;
+ struct ktz8866 *ktz;
+ int ret = 0;
+
+ ktz = devm_kzalloc(&client->dev, sizeof(*ktz), GFP_KERNEL);
+ if (!ktz)
+ return -ENOMEM;
+
+ ktz->client = client;
+ ktz->regmap = devm_regmap_init_i2c(client, &ktz8866_regmap_config);
+ if (IS_ERR(ktz->regmap))
+ return dev_err_probe(&client->dev, PTR_ERR(ktz->regmap), "failed to init regmap\n");
+
+ ret = devm_regulator_get_enable(&client->dev, "vddpos");
+ if (ret)
+ return dev_err_probe(&client->dev, ret, "get regulator vddpos failed\n");
+ ret = devm_regulator_get_enable(&client->dev, "vddneg");
+ if (ret)
+ return dev_err_probe(&client->dev, ret, "get regulator vddneg failed\n");
+
+ ktz->enable_gpio = devm_gpiod_get_optional(&client->dev, "enable", GPIOD_OUT_HIGH);
+ if (IS_ERR(ktz->enable_gpio))
+ return PTR_ERR(ktz->enable_gpio);
+
+ memset(&props, 0, sizeof(props));
+ props.type = BACKLIGHT_RAW;
+ props.max_brightness = MAX_BRIGHTNESS;
+ props.brightness = DEFAULT_BRIGHTNESS;
+ props.scale = BACKLIGHT_SCALE_LINEAR;
+
+ backlight_dev = devm_backlight_device_register(&client->dev, "ktz8866-backlight",
+ &client->dev, ktz, &ktz8866_backlight_ops, &props);
+ if (IS_ERR(backlight_dev))
+ return dev_err_probe(&client->dev, PTR_ERR(backlight_dev),
+ "failed to register backlight device\n");
+
+ ktz8866_init(ktz);
+
+ i2c_set_clientdata(client, backlight_dev);
+ backlight_update_status(backlight_dev);
+
+ return 0;
+}
+
+static void ktz8866_remove(struct i2c_client *client)
+{
+ struct backlight_device *backlight_dev = i2c_get_clientdata(client);
+ backlight_dev->props.brightness = 0;
+ backlight_update_status(backlight_dev);
+}
+
+static const struct i2c_device_id ktz8866_ids[] = {
+ { "ktz8866", 0 },
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, ktz8866_ids);
+
+static const struct of_device_id ktz8866_match_table[] = {
+ {
+ .compatible = "kinetic,ktz8866",
+ },
+ {},
+};
+
+static struct i2c_driver ktz8866_driver = {
+ .driver = {
+ .name = "ktz8866",
+ .of_match_table = ktz8866_match_table,
+ },
+ .probe_new = ktz8866_probe,
+ .remove = ktz8866_remove,
+ .id_table = ktz8866_ids,
+};
+
+module_i2c_driver(ktz8866_driver);
+
+MODULE_DESCRIPTION("Kinetic KTZ8866 Backlight Driver");
+MODULE_AUTHOR("Jianhua Lu <lujianhua000@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index c0523a0269ee..fb388148d98f 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -28,7 +28,6 @@ struct pwm_bl_data {
struct regulator *power_supply;
struct gpio_desc *enable_gpio;
unsigned int scale;
- bool legacy;
unsigned int post_pwm_on_delay;
unsigned int pwm_off_delay;
int (*notify)(struct device *,
@@ -41,19 +40,16 @@ struct pwm_bl_data {
static void pwm_backlight_power_on(struct pwm_bl_data *pb)
{
- struct pwm_state state;
int err;
- pwm_get_state(pb->pwm, &state);
if (pb->enabled)
return;
- err = regulator_enable(pb->power_supply);
- if (err < 0)
- dev_err(pb->dev, "failed to enable power supply\n");
-
- state.enabled = true;
- pwm_apply_state(pb->pwm, &state);
+ if (pb->power_supply) {
+ err = regulator_enable(pb->power_supply);
+ if (err < 0)
+ dev_err(pb->dev, "failed to enable power supply\n");
+ }
if (pb->post_pwm_on_delay)
msleep(pb->post_pwm_on_delay);
@@ -66,9 +62,6 @@ static void pwm_backlight_power_on(struct pwm_bl_data *pb)
static void pwm_backlight_power_off(struct pwm_bl_data *pb)
{
- struct pwm_state state;
-
- pwm_get_state(pb->pwm, &state);
if (!pb->enabled)
return;
@@ -78,28 +71,22 @@ static void pwm_backlight_power_off(struct pwm_bl_data *pb)
if (pb->pwm_off_delay)
msleep(pb->pwm_off_delay);
- state.enabled = false;
- state.duty_cycle = 0;
- pwm_apply_state(pb->pwm, &state);
-
- regulator_disable(pb->power_supply);
+ if (pb->power_supply)
+ regulator_disable(pb->power_supply);
pb->enabled = false;
}
-static int compute_duty_cycle(struct pwm_bl_data *pb, int brightness)
+static int compute_duty_cycle(struct pwm_bl_data *pb, int brightness, struct pwm_state *state)
{
unsigned int lth = pb->lth_brightness;
- struct pwm_state state;
u64 duty_cycle;
- pwm_get_state(pb->pwm, &state);
-
if (pb->levels)
duty_cycle = pb->levels[brightness];
else
duty_cycle = brightness;
- duty_cycle *= state.period - lth;
+ duty_cycle *= state->period - lth;
do_div(duty_cycle, pb->scale);
return duty_cycle + lth;
@@ -116,11 +103,26 @@ static int pwm_backlight_update_status(struct backlight_device *bl)
if (brightness > 0) {
pwm_get_state(pb->pwm, &state);
- state.duty_cycle = compute_duty_cycle(pb, brightness);
+ state.duty_cycle = compute_duty_cycle(pb, brightness, &state);
+ state.enabled = true;
pwm_apply_state(pb->pwm, &state);
+
pwm_backlight_power_on(pb);
} else {
pwm_backlight_power_off(pb);
+
+ pwm_get_state(pb->pwm, &state);
+ state.duty_cycle = 0;
+ /*
+ * We cannot assume a disabled PWM to drive its output to the
+ * inactive state. If we have an enable GPIO and/or a regulator
+ * we assume that this isn't relevant and we can disable the PWM
+ * to save power. If however there is neither an enable GPIO nor
+ * a regulator keep the PWM on be sure to get a constant
+ * inactive output.
+ */
+ state.enabled = !pb->power_supply && !pb->enable_gpio;
+ pwm_apply_state(pb->pwm, &state);
}
if (pb->notify_after)
@@ -417,7 +419,7 @@ static int pwm_backlight_initial_power_state(const struct pwm_bl_data *pb)
if (pb->enable_gpio && gpiod_get_value_cansleep(pb->enable_gpio) == 0)
active = false;
- if (!regulator_is_enabled(pb->power_supply))
+ if (pb->power_supply && !regulator_is_enabled(pb->power_supply))
active = false;
if (!pwm_is_enabled(pb->pwm))
@@ -455,7 +457,6 @@ static int pwm_backlight_probe(struct platform_device *pdev)
struct platform_pwm_backlight_data defdata;
struct backlight_properties props;
struct backlight_device *bl;
- struct device_node *node = pdev->dev.of_node;
struct pwm_bl_data *pb;
struct pwm_state state;
unsigned int i;
@@ -499,19 +500,16 @@ static int pwm_backlight_probe(struct platform_device *pdev)
goto err_alloc;
}
- pb->power_supply = devm_regulator_get(&pdev->dev, "power");
+ pb->power_supply = devm_regulator_get_optional(&pdev->dev, "power");
if (IS_ERR(pb->power_supply)) {
ret = PTR_ERR(pb->power_supply);
- goto err_alloc;
+ if (ret == -ENODEV)
+ pb->power_supply = NULL;
+ else
+ goto err_alloc;
}
pb->pwm = devm_pwm_get(&pdev->dev, NULL);
- if (IS_ERR(pb->pwm) && PTR_ERR(pb->pwm) != -EPROBE_DEFER && !node) {
- dev_err(&pdev->dev, "unable to request PWM, trying legacy API\n");
- pb->legacy = true;
- pb->pwm = pwm_request(data->pwm_id, "pwm-backlight");
- }
-
if (IS_ERR(pb->pwm)) {
ret = PTR_ERR(pb->pwm);
if (ret != -EPROBE_DEFER)
@@ -604,8 +602,6 @@ static int pwm_backlight_probe(struct platform_device *pdev)
if (IS_ERR(bl)) {
dev_err(&pdev->dev, "failed to register backlight\n");
ret = PTR_ERR(bl);
- if (pb->legacy)
- pwm_free(pb->pwm);
goto err_alloc;
}
@@ -639,8 +635,6 @@ static int pwm_backlight_remove(struct platform_device *pdev)
if (pb->exit)
pb->exit(&pdev->dev);
- if (pb->legacy)
- pwm_free(pb->pwm);
return 0;
}
diff --git a/drivers/video/backlight/sky81452-backlight.c b/drivers/video/backlight/sky81452-backlight.c
index c95e0de7f4e7..0172438c38ce 100644
--- a/drivers/video/backlight/sky81452-backlight.c
+++ b/drivers/video/backlight/sky81452-backlight.c
@@ -41,7 +41,7 @@
#define SKY81452_MAX_BRIGHTNESS (SKY81452_CS + 1)
/**
- * struct sky81452_platform_data
+ * struct sky81452_bl_platform_data - backlight platform data
* @name: backlight driver name.
* If it is not defined, default name is lcd-backlight.
* @gpiod_enable:GPIO descriptor which control EN pin
diff --git a/drivers/video/backlight/tosa_bl.c b/drivers/video/backlight/tosa_bl.c
deleted file mode 100644
index 77b71f6c19b5..000000000000
--- a/drivers/video/backlight/tosa_bl.c
+++ /dev/null
@@ -1,172 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * LCD / Backlight control code for Sharp SL-6000x (tosa)
- *
- * Copyright (c) 2005 Dirk Opfer
- * Copyright (c) 2007,2008 Dmitry Baryshkov
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/spi/spi.h>
-#include <linux/i2c.h>
-#include <linux/gpio/consumer.h>
-#include <linux/fb.h>
-#include <linux/backlight.h>
-#include <linux/slab.h>
-
-#include <asm/mach/sharpsl_param.h>
-
-#include "tosa_bl.h"
-
-#define COMADJ_DEFAULT 97
-
-#define DAC_CH1 0
-#define DAC_CH2 1
-
-struct tosa_bl_data {
- struct i2c_client *i2c;
- struct backlight_device *bl;
- struct gpio_desc *gpio;
-
- int comadj;
-};
-
-static void tosa_bl_set_backlight(struct tosa_bl_data *data, int brightness)
-{
- struct spi_device *spi = dev_get_platdata(&data->i2c->dev);
-
- i2c_smbus_write_byte_data(data->i2c, DAC_CH1, data->comadj);
-
- /* SetBacklightDuty */
- i2c_smbus_write_byte_data(data->i2c, DAC_CH2, (u8)(brightness & 0xff));
-
- /* SetBacklightVR */
- gpiod_set_value(data->gpio, brightness & 0x100);
-
- tosa_bl_enable(spi, brightness);
-}
-
-static int tosa_bl_update_status(struct backlight_device *dev)
-{
- struct backlight_properties *props = &dev->props;
- struct tosa_bl_data *data = bl_get_data(dev);
- int power = max(props->power, props->fb_blank);
- int brightness = props->brightness;
-
- if (power)
- brightness = 0;
-
- tosa_bl_set_backlight(data, brightness);
-
- return 0;
-}
-
-static int tosa_bl_get_brightness(struct backlight_device *dev)
-{
- struct backlight_properties *props = &dev->props;
-
- return props->brightness;
-}
-
-static const struct backlight_ops bl_ops = {
- .get_brightness = tosa_bl_get_brightness,
- .update_status = tosa_bl_update_status,
-};
-
-static int tosa_bl_probe(struct i2c_client *client)
-{
- struct backlight_properties props;
- struct tosa_bl_data *data;
- int ret = 0;
-
- data = devm_kzalloc(&client->dev, sizeof(struct tosa_bl_data),
- GFP_KERNEL);
- if (!data)
- return -ENOMEM;
-
- data->comadj = sharpsl_param.comadj == -1 ? COMADJ_DEFAULT : sharpsl_param.comadj;
- data->gpio = devm_gpiod_get(&client->dev, "backlight", GPIOD_OUT_LOW);
- ret = PTR_ERR_OR_ZERO(data->gpio);
- if (ret) {
- dev_dbg(&data->bl->dev, "Unable to request gpio!\n");
- return ret;
- }
-
- i2c_set_clientdata(client, data);
- data->i2c = client;
-
- memset(&props, 0, sizeof(struct backlight_properties));
- props.type = BACKLIGHT_RAW;
- props.max_brightness = 512 - 1;
- data->bl = devm_backlight_device_register(&client->dev, "tosa-bl",
- &client->dev, data, &bl_ops,
- &props);
- if (IS_ERR(data->bl)) {
- ret = PTR_ERR(data->bl);
- goto err_reg;
- }
-
- data->bl->props.brightness = 69;
- data->bl->props.power = FB_BLANK_UNBLANK;
-
- backlight_update_status(data->bl);
-
- return 0;
-
-err_reg:
- data->bl = NULL;
- return ret;
-}
-
-static void tosa_bl_remove(struct i2c_client *client)
-{
- struct tosa_bl_data *data = i2c_get_clientdata(client);
-
- data->bl = NULL;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int tosa_bl_suspend(struct device *dev)
-{
- struct tosa_bl_data *data = dev_get_drvdata(dev);
-
- tosa_bl_set_backlight(data, 0);
-
- return 0;
-}
-
-static int tosa_bl_resume(struct device *dev)
-{
- struct tosa_bl_data *data = dev_get_drvdata(dev);
-
- backlight_update_status(data->bl);
- return 0;
-}
-#endif
-
-static SIMPLE_DEV_PM_OPS(tosa_bl_pm_ops, tosa_bl_suspend, tosa_bl_resume);
-
-static const struct i2c_device_id tosa_bl_id[] = {
- { "tosa-bl", 0 },
- { },
-};
-MODULE_DEVICE_TABLE(i2c, tosa_bl_id);
-
-static struct i2c_driver tosa_bl_driver = {
- .driver = {
- .name = "tosa-bl",
- .pm = &tosa_bl_pm_ops,
- },
- .probe_new = tosa_bl_probe,
- .remove = tosa_bl_remove,
- .id_table = tosa_bl_id,
-};
-
-module_i2c_driver(tosa_bl_driver);
-
-MODULE_AUTHOR("Dmitry Baryshkov");
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("LCD/Backlight control for Sharp SL-6000 PDA");
-
diff --git a/drivers/video/backlight/tosa_bl.h b/drivers/video/backlight/tosa_bl.h
deleted file mode 100644
index 589e17e6fdb2..000000000000
--- a/drivers/video/backlight/tosa_bl.h
+++ /dev/null
@@ -1,8 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-#ifndef _TOSA_BL_H
-#define _TOSA_BL_H
-
-struct spi_device;
-extern int tosa_bl_enable(struct spi_device *spi, int enable);
-
-#endif
diff --git a/drivers/video/backlight/tosa_lcd.c b/drivers/video/backlight/tosa_lcd.c
deleted file mode 100644
index 23d6c6bf0f54..000000000000
--- a/drivers/video/backlight/tosa_lcd.c
+++ /dev/null
@@ -1,284 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * LCD / Backlight control code for Sharp SL-6000x (tosa)
- *
- * Copyright (c) 2005 Dirk Opfer
- * Copyright (c) 2007,2008 Dmitry Baryshkov
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/spi/spi.h>
-#include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/gpio/consumer.h>
-#include <linux/delay.h>
-#include <linux/lcd.h>
-#include <linux/fb.h>
-
-#include <asm/mach/sharpsl_param.h>
-
-#include "tosa_bl.h"
-
-#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL)
-
-#define TG_REG0_VQV 0x0001
-#define TG_REG0_COLOR 0x0002
-#define TG_REG0_UD 0x0004
-#define TG_REG0_LR 0x0008
-
-/*
- * Timing Generator
- */
-#define TG_PNLCTL 0x00
-#define TG_TPOSCTL 0x01
-#define TG_DUTYCTL 0x02
-#define TG_GPOSR 0x03
-#define TG_GPODR1 0x04
-#define TG_GPODR2 0x05
-#define TG_PINICTL 0x06
-#define TG_HPOSCTL 0x07
-
-
-#define DAC_BASE 0x4e
-
-struct tosa_lcd_data {
- struct spi_device *spi;
- struct lcd_device *lcd;
- struct i2c_client *i2c;
- struct gpio_desc *gpiod_tg;
-
- int lcd_power;
- bool is_vga;
-};
-
-static int tosa_tg_send(struct spi_device *spi, int adrs, uint8_t data)
-{
- u8 buf[1];
- struct spi_message msg;
- struct spi_transfer xfer = {
- .len = 1,
- .cs_change = 0,
- .tx_buf = buf,
- };
-
- buf[0] = ((adrs & 0x07) << 5) | (data & 0x1f);
- spi_message_init(&msg);
- spi_message_add_tail(&xfer, &msg);
-
- return spi_sync(spi, &msg);
-}
-
-int tosa_bl_enable(struct spi_device *spi, int enable)
-{
- /* bl_enable GP04=1 otherwise GP04=0*/
- return tosa_tg_send(spi, TG_GPODR2, enable ? 0x01 : 0x00);
-}
-EXPORT_SYMBOL(tosa_bl_enable);
-
-static void tosa_lcd_tg_init(struct tosa_lcd_data *data)
-{
- /* TG on */
- gpiod_set_value(data->gpiod_tg, 0);
-
- mdelay(60);
-
- /* delayed 0clk TCTL signal for VGA */
- tosa_tg_send(data->spi, TG_TPOSCTL, 0x00);
- /* GPOS0=powercontrol, GPOS1=GPIO, GPOS2=TCTL */
- tosa_tg_send(data->spi, TG_GPOSR, 0x02);
-}
-
-static void tosa_lcd_tg_on(struct tosa_lcd_data *data)
-{
- struct spi_device *spi = data->spi;
- int value = TG_REG0_COLOR | TG_REG0_UD | TG_REG0_LR;
-
- if (data->is_vga)
- value |= TG_REG0_VQV;
-
- tosa_tg_send(spi, TG_PNLCTL, value);
-
- /* TG LCD pannel power up */
- tosa_tg_send(spi, TG_PINICTL, 0x4);
- mdelay(50);
-
- /* TG LCD GVSS */
- tosa_tg_send(spi, TG_PINICTL, 0x0);
-
- if (IS_ERR_OR_NULL(data->i2c)) {
- /*
- * after the pannel is powered up the first time,
- * we can access the i2c bus so probe for the DAC
- */
- struct i2c_adapter *adap = i2c_get_adapter(0);
- struct i2c_board_info info = {
- .dev_name = "tosa-bl",
- .type = "tosa-bl",
- .addr = DAC_BASE,
- .platform_data = data->spi,
- };
- data->i2c = i2c_new_client_device(adap, &info);
- }
-}
-
-static void tosa_lcd_tg_off(struct tosa_lcd_data *data)
-{
- struct spi_device *spi = data->spi;
-
- /* TG LCD VHSA off */
- tosa_tg_send(spi, TG_PINICTL, 0x4);
- mdelay(50);
-
- /* TG LCD signal off */
- tosa_tg_send(spi, TG_PINICTL, 0x6);
- mdelay(50);
-
- /* TG Off */
- gpiod_set_value(data->gpiod_tg, 1);
- mdelay(100);
-}
-
-int tosa_lcd_set_power(struct lcd_device *lcd, int power)
-{
- struct tosa_lcd_data *data = lcd_get_data(lcd);
-
- if (POWER_IS_ON(power) && !POWER_IS_ON(data->lcd_power))
- tosa_lcd_tg_on(data);
-
- if (!POWER_IS_ON(power) && POWER_IS_ON(data->lcd_power))
- tosa_lcd_tg_off(data);
-
- data->lcd_power = power;
- return 0;
-}
-
-static int tosa_lcd_get_power(struct lcd_device *lcd)
-{
- struct tosa_lcd_data *data = lcd_get_data(lcd);
-
- return data->lcd_power;
-}
-
-static int tosa_lcd_set_mode(struct lcd_device *lcd, struct fb_videomode *mode)
-{
- struct tosa_lcd_data *data = lcd_get_data(lcd);
-
- if (mode->xres == 320 || mode->yres == 320)
- data->is_vga = false;
- else
- data->is_vga = true;
-
- if (POWER_IS_ON(data->lcd_power))
- tosa_lcd_tg_on(data);
-
- return 0;
-}
-
-static struct lcd_ops tosa_lcd_ops = {
- .set_power = tosa_lcd_set_power,
- .get_power = tosa_lcd_get_power,
- .set_mode = tosa_lcd_set_mode,
-};
-
-static int tosa_lcd_probe(struct spi_device *spi)
-{
- int ret;
- struct tosa_lcd_data *data;
-
- data = devm_kzalloc(&spi->dev, sizeof(struct tosa_lcd_data),
- GFP_KERNEL);
- if (!data)
- return -ENOMEM;
-
- data->is_vga = true; /* default to VGA mode */
-
- /*
- * bits_per_word cannot be configured in platform data
- */
- spi->bits_per_word = 8;
-
- ret = spi_setup(spi);
- if (ret < 0)
- return ret;
-
- data->spi = spi;
- spi_set_drvdata(spi, data);
-
- data->gpiod_tg = devm_gpiod_get(&spi->dev, "tg #pwr", GPIOD_OUT_LOW);
- if (IS_ERR(data->gpiod_tg))
- return PTR_ERR(data->gpiod_tg);
-
- mdelay(60);
-
- tosa_lcd_tg_init(data);
-
- tosa_lcd_tg_on(data);
-
- data->lcd = devm_lcd_device_register(&spi->dev, "tosa-lcd", &spi->dev,
- data, &tosa_lcd_ops);
-
- if (IS_ERR(data->lcd)) {
- ret = PTR_ERR(data->lcd);
- data->lcd = NULL;
- goto err_register;
- }
-
- return 0;
-
-err_register:
- tosa_lcd_tg_off(data);
- return ret;
-}
-
-static void tosa_lcd_remove(struct spi_device *spi)
-{
- struct tosa_lcd_data *data = spi_get_drvdata(spi);
-
- i2c_unregister_device(data->i2c);
-
- tosa_lcd_tg_off(data);
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int tosa_lcd_suspend(struct device *dev)
-{
- struct tosa_lcd_data *data = dev_get_drvdata(dev);
-
- tosa_lcd_tg_off(data);
-
- return 0;
-}
-
-static int tosa_lcd_resume(struct device *dev)
-{
- struct tosa_lcd_data *data = dev_get_drvdata(dev);
-
- tosa_lcd_tg_init(data);
- if (POWER_IS_ON(data->lcd_power))
- tosa_lcd_tg_on(data);
- else
- tosa_lcd_tg_off(data);
-
- return 0;
-}
-#endif
-
-static SIMPLE_DEV_PM_OPS(tosa_lcd_pm_ops, tosa_lcd_suspend, tosa_lcd_resume);
-
-static struct spi_driver tosa_lcd_driver = {
- .driver = {
- .name = "tosa-lcd",
- .pm = &tosa_lcd_pm_ops,
- },
- .probe = tosa_lcd_probe,
- .remove = tosa_lcd_remove,
-};
-
-module_spi_driver(tosa_lcd_driver);
-
-MODULE_AUTHOR("Dmitry Baryshkov");
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("LCD/Backlight control for Sharp SL-6000 PDA");
-MODULE_ALIAS("spi:tosa-lcd");
diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c
index d9c682ae0392..e8e4f82cd4a1 100644
--- a/drivers/video/console/newport_con.c
+++ b/drivers/video/console/newport_con.c
@@ -497,7 +497,7 @@ static int newport_blank(struct vc_data *c, int blank, int mode_switch)
return 1;
}
-static int newport_set_font(int unit, struct console_font *op)
+static int newport_set_font(int unit, struct console_font *op, unsigned int vpitch)
{
int w = op->width;
int h = op->height;
@@ -507,7 +507,7 @@ static int newport_set_font(int unit, struct console_font *op)
/* ladis: when I grow up, there will be a day... and more sizes will
* be supported ;-) */
- if ((w != 8) || (h != 16)
+ if ((w != 8) || (h != 16) || (vpitch != 32)
|| (op->charcount != 256 && op->charcount != 512))
return -EINVAL;
@@ -569,9 +569,10 @@ static int newport_font_default(struct vc_data *vc, struct console_font *op, cha
return newport_set_def_font(vc->vc_num, op);
}
-static int newport_font_set(struct vc_data *vc, struct console_font *font, unsigned flags)
+static int newport_font_set(struct vc_data *vc, struct console_font *font,
+ unsigned int vpitch, unsigned int flags)
{
- return newport_set_font(vc->vc_num, font);
+ return newport_set_font(vc->vc_num, font, vpitch);
}
static bool newport_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c
index f304163e87e9..2cea69418a83 100644
--- a/drivers/video/console/sticon.c
+++ b/drivers/video/console/sticon.c
@@ -169,7 +169,8 @@ static int sticon_set_def_font(int unit, struct console_font *op)
return 0;
}
-static int sticon_set_font(struct vc_data *vc, struct console_font *op)
+static int sticon_set_font(struct vc_data *vc, struct console_font *op,
+ unsigned int vpitch)
{
struct sti_struct *sti = sticon_sti;
int vc_cols, vc_rows, vc_old_cols, vc_old_rows;
@@ -181,7 +182,7 @@ static int sticon_set_font(struct vc_data *vc, struct console_font *op)
struct sti_cooked_font *cooked_font;
unsigned char *data = op->data, *p;
- if ((w < 6) || (h < 6) || (w > 32) || (h > 32)
+ if ((w < 6) || (h < 6) || (w > 32) || (h > 32) || (vpitch != 32)
|| (op->charcount != 256 && op->charcount != 512))
return -EINVAL;
pitch = ALIGN(w, 8) / 8;
@@ -267,9 +268,9 @@ static int sticon_font_default(struct vc_data *vc, struct console_font *op, char
}
static int sticon_font_set(struct vc_data *vc, struct console_font *font,
- unsigned int flags)
+ unsigned int vpitch, unsigned int flags)
{
- return sticon_set_font(vc, font);
+ return sticon_set_font(vc, font, vpitch);
}
static void sticon_init(struct vc_data *c, int init)
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
index fcdf017e2665..e25ba523892e 100644
--- a/drivers/video/console/vgacon.c
+++ b/drivers/video/console/vgacon.c
@@ -1029,7 +1029,7 @@ static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight)
}
static int vgacon_font_set(struct vc_data *c, struct console_font *font,
- unsigned int flags)
+ unsigned int vpitch, unsigned int flags)
{
unsigned charcount = font->charcount;
int rc;
@@ -1037,7 +1037,7 @@ static int vgacon_font_set(struct vc_data *c, struct console_font *font,
if (vga_video_type < VIDEO_TYPE_EGAM)
return -EINVAL;
- if (font->width != VGA_FONTWIDTH ||
+ if (font->width != VGA_FONTWIDTH || font->height > 32 || vpitch != 32 ||
(charcount != 256 && charcount != 512))
return -EINVAL;
@@ -1050,9 +1050,9 @@ static int vgacon_font_set(struct vc_data *c, struct console_font *font,
return rc;
}
-static int vgacon_font_get(struct vc_data *c, struct console_font *font)
+static int vgacon_font_get(struct vc_data *c, struct console_font *font, unsigned int vpitch)
{
- if (vga_video_type < VIDEO_TYPE_EGAM)
+ if (vga_video_type < VIDEO_TYPE_EGAM || vpitch != 32)
return -EINVAL;
font->width = VGA_FONTWIDTH;
diff --git a/drivers/video/fbdev/68328fb.c b/drivers/video/fbdev/68328fb.c
index 7db03ed77c76..41df61b37a18 100644
--- a/drivers/video/fbdev/68328fb.c
+++ b/drivers/video/fbdev/68328fb.c
@@ -391,7 +391,7 @@ static int mc68x328fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
#ifndef MMU
/* this is uClinux (no MMU) specific code */
- vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
+ vm_flags_set(vma, VM_DONTEXPAND | VM_DONTDUMP);
vma->vm_start = videomemory;
return 0;
diff --git a/drivers/video/fbdev/clps711x-fb.c b/drivers/video/fbdev/clps711x-fb.c
index a1061c2f1640..45c75ff01eca 100644
--- a/drivers/video/fbdev/clps711x-fb.c
+++ b/drivers/video/fbdev/clps711x-fb.c
@@ -251,16 +251,8 @@ static int clps711x_fb_probe(struct platform_device *pdev)
goto out_fb_release;
}
- info->apertures = alloc_apertures(1);
- if (!info->apertures) {
- ret = -ENOMEM;
- goto out_fb_release;
- }
-
cfb->buffsize = resource_size(res);
info->fix.smem_start = res->start;
- info->apertures->ranges[0].base = info->fix.smem_start;
- info->apertures->ranges[0].size = cfb->buffsize;
cfb->clk = devm_clk_get(dev, NULL);
if (IS_ERR(cfb->clk)) {
@@ -345,7 +337,7 @@ static int clps711x_fb_probe(struct platform_device *pdev)
&clps711x_lcd_ops);
if (!IS_ERR(lcd))
return 0;
-
+
ret = PTR_ERR(lcd);
unregister_framebuffer(info);
diff --git a/drivers/video/fbdev/core/fb_defio.c b/drivers/video/fbdev/core/fb_defio.c
index 583cbcf09446..aa5f059d0222 100644
--- a/drivers/video/fbdev/core/fb_defio.c
+++ b/drivers/video/fbdev/core/fb_defio.c
@@ -157,10 +157,6 @@ static vm_fault_t fb_deferred_io_track_page(struct fb_info *info, unsigned long
/* protect against the workqueue changing the page list */
mutex_lock(&fbdefio->lock);
- /* first write in this cycle, notify the driver */
- if (fbdefio->first_io && list_empty(&fbdefio->pagereflist))
- fbdefio->first_io(info);
-
pageref = fb_deferred_io_pageref_get(info, offset, page);
if (WARN_ON_ONCE(!pageref)) {
ret = VM_FAULT_OOM;
@@ -232,9 +228,9 @@ static const struct address_space_operations fb_deferred_io_aops = {
int fb_deferred_io_mmap(struct fb_info *info, struct vm_area_struct *vma)
{
vma->vm_ops = &fb_deferred_io_vm_ops;
- vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
+ vm_flags_set(vma, VM_DONTEXPAND | VM_DONTDUMP);
if (!(info->flags & FBINFO_VIRTFB))
- vma->vm_flags |= VM_IO;
+ vm_flags_set(vma, VM_IO);
vma->vm_private_data = info;
return 0;
}
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 1b14c21af2b7..0a2c47df01f4 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -26,7 +26,7 @@
*
* Hardware cursor support added by Emmanuel Marty (core@ggi-project.org)
* Smart redraw scrolling, arbitrary font width support, 512char font support
- * and software scrollback added by
+ * and software scrollback added by
* Jakub Jelinek (jj@ultra.linux.cz)
*
* Random hacking by Martin Mares <mj@ucw.cz>
@@ -127,7 +127,7 @@ static int logo_shown = FBCON_LOGO_CANSHOW;
/* console mappings */
static unsigned int first_fb_vc;
static unsigned int last_fb_vc = MAX_NR_CONSOLES - 1;
-static int fbcon_is_default = 1;
+static int fbcon_is_default = 1;
static int primary_device = -1;
static int fbcon_has_console_bind;
@@ -415,12 +415,12 @@ static int __init fb_console_setup(char *this_opt)
strscpy(fontname, options + 5, sizeof(fontname));
continue;
}
-
+
if (!strncmp(options, "scrollback:", 11)) {
pr_warn("Ignoring scrollback size option\n");
continue;
}
-
+
if (!strncmp(options, "map:", 4)) {
options += 4;
if (*options) {
@@ -446,7 +446,7 @@ static int __init fb_console_setup(char *this_opt)
last_fb_vc = simple_strtoul(options, &options, 10) - 1;
if (last_fb_vc < first_fb_vc || last_fb_vc >= MAX_NR_CONSOLES)
last_fb_vc = MAX_NR_CONSOLES - 1;
- fbcon_is_default = 0;
+ fbcon_is_default = 0;
continue;
}
@@ -940,7 +940,7 @@ static const char *fbcon_startup(void)
info = fbcon_registered_fb[info_idx];
if (!info)
return NULL;
-
+
if (fbcon_open(info))
return NULL;
@@ -958,7 +958,7 @@ static const char *fbcon_startup(void)
set_blitting_type(vc, info);
/* Setup default font */
- if (!p->fontdata && !vc->vc_font.data) {
+ if (!p->fontdata) {
if (!fontname[0] || !(font = find_font(fontname)))
font = get_default_font(info->var.xres,
info->var.yres,
@@ -968,8 +968,6 @@ static const char *fbcon_startup(void)
vc->vc_font.height = font->height;
vc->vc_font.data = (void *)(p->fontdata = font->data);
vc->vc_font.charcount = font->charcount;
- } else {
- p->fontdata = vc->vc_font.data;
}
cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
@@ -1135,9 +1133,9 @@ static void fbcon_init(struct vc_data *vc, int init)
ops->p = &fb_display[fg_console];
}
-static void fbcon_free_font(struct fbcon_display *p, bool freefont)
+static void fbcon_free_font(struct fbcon_display *p)
{
- if (freefont && p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0))
+ if (p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0))
kfree(p->fontdata - FONT_EXTRA_WORDS * sizeof(int));
p->fontdata = NULL;
p->userfont = 0;
@@ -1172,8 +1170,8 @@ static void fbcon_deinit(struct vc_data *vc)
struct fb_info *info;
struct fbcon_ops *ops;
int idx;
- bool free_font = true;
+ fbcon_free_font(p);
idx = con2fb_map[vc->vc_num];
if (idx == -1)
@@ -1184,8 +1182,6 @@ static void fbcon_deinit(struct vc_data *vc)
if (!info)
goto finished;
- if (info->flags & FBINFO_MISC_FIRMWARE)
- free_font = false;
ops = info->fbcon_par;
if (!ops)
@@ -1197,9 +1193,8 @@ static void fbcon_deinit(struct vc_data *vc)
ops->initialized = false;
finished:
- fbcon_free_font(p, free_font);
- if (free_font)
- vc->vc_font.data = NULL;
+ fbcon_free_font(p);
+ vc->vc_font.data = NULL;
if (vc->vc_hi_font_mask && vc->vc_screenbuf)
set_vc_hi_font(vc, false);
@@ -1999,7 +1994,7 @@ static void updatescrollmode(struct fbcon_display *p,
#define PITCH(w) (((w) + 7) >> 3)
#define CALC_FONTSZ(h, p, c) ((h) * (p) * (c)) /* size = height * pitch * charcount */
-static int fbcon_resize(struct vc_data *vc, unsigned int width,
+static int fbcon_resize(struct vc_data *vc, unsigned int width,
unsigned int height, unsigned int user)
{
struct fb_info *info = fbcon_info_from_console(vc->vc_num);
@@ -2174,7 +2169,7 @@ static int fbcon_switch(struct vc_data *vc)
ops->update_start(info);
}
- fbcon_set_palette(vc, color_table);
+ fbcon_set_palette(vc, color_table);
fbcon_clear_margins(vc, 0);
if (logo_shown == FBCON_LOGO_DRAW) {
@@ -2271,7 +2266,7 @@ static int fbcon_debug_leave(struct vc_data *vc)
return 0;
}
-static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
+static int fbcon_get_font(struct vc_data *vc, struct console_font *font, unsigned int vpitch)
{
u8 *fontdata = vc->vc_font.data;
u8 *data = font->data;
@@ -2279,6 +2274,8 @@ static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
font->width = vc->vc_font.width;
font->height = vc->vc_font.height;
+ if (font->height > vpitch)
+ return -ENOSPC;
font->charcount = vc->vc_hi_font_mask ? 512 : 256;
if (!font->data)
return 0;
@@ -2290,8 +2287,8 @@ static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
for (i = 0; i < font->charcount; i++) {
memcpy(data, fontdata, j);
- memset(data + j, 0, 32 - j);
- data += 32;
+ memset(data + j, 0, vpitch - j);
+ data += vpitch;
fontdata += j;
}
} else if (font->width <= 16) {
@@ -2301,8 +2298,8 @@ static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
for (i = 0; i < font->charcount; i++) {
memcpy(data, fontdata, j);
- memset(data + j, 0, 64 - j);
- data += 64;
+ memset(data + j, 0, 2*vpitch - j);
+ data += 2*vpitch;
fontdata += j;
}
} else if (font->width <= 24) {
@@ -2316,8 +2313,8 @@ static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
*data++ = fontdata[2];
fontdata += sizeof(u32);
}
- memset(data, 0, 3 * (32 - j));
- data += 3 * (32 - j);
+ memset(data, 0, 3 * (vpitch - j));
+ data += 3 * (vpitch - j);
}
} else {
j = vc->vc_font.height * 4;
@@ -2326,8 +2323,8 @@ static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
for (i = 0; i < font->charcount; i++) {
memcpy(data, fontdata, j);
- memset(data + j, 0, 128 - j);
- data += 128;
+ memset(data + j, 0, 4 * vpitch - j);
+ data += 4 * vpitch;
fontdata += j;
}
}
@@ -2343,7 +2340,7 @@ static void set_vc_hi_font(struct vc_data *vc, bool set)
vc->vc_complement_mask >>= 1;
vc->vc_s_complement_mask >>= 1;
}
-
+
/* ++Edmund: reorder the attribute bits */
if (vc->vc_can_do_color) {
unsigned short *cp =
@@ -2366,7 +2363,7 @@ static void set_vc_hi_font(struct vc_data *vc, bool set)
vc->vc_complement_mask <<= 1;
vc->vc_s_complement_mask <<= 1;
}
-
+
/* ++Edmund: reorder the attribute bits */
{
unsigned short *cp =
@@ -2462,19 +2459,12 @@ err_out:
}
/*
- * User asked to set font; we are guaranteed that
- * a) width and height are in range 1..32
- * b) charcount does not exceed 512
- * but lets not assume that, since someone might someday want to use larger
- * fonts. And charcount of 512 is small for unicode support.
- *
- * However, user space gives the font in 32 rows , regardless of
- * actual font height. So a new API is needed if support for larger fonts
- * is ever implemented.
+ * User asked to set font; we are guaranteed that charcount does not exceed 512
+ * but lets not assume that, since charcount of 512 is small for unicode support.
*/
static int fbcon_set_font(struct vc_data *vc, struct console_font *font,
- unsigned int flags)
+ unsigned int vpitch, unsigned int flags)
{
struct fb_info *info = fbcon_info_from_console(vc->vc_num);
unsigned charcount = font->charcount;
@@ -2520,7 +2510,7 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font *font,
FNTSIZE(new_data) = size;
REFCOUNT(new_data) = 0; /* usage counter */
for (i=0; i< charcount; i++) {
- memcpy(new_data + i*h*pitch, data + i*32*pitch, h*pitch);
+ memcpy(new_data + i*h*pitch, data + i*vpitch*pitch, h*pitch);
}
/* Since linux has a nice crc32 function use it for counting font
@@ -2531,7 +2521,7 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font *font,
/* Check if the same font is on some other console already */
for (i = first_fb_vc; i <= last_fb_vc; i++) {
struct vc_data *tmp = vc_cons[i].d;
-
+
if (fb_display[i].userfont &&
fb_display[i].fontdata &&
FNTSUM(fb_display[i].fontdata) == csum &&
@@ -3439,5 +3429,5 @@ void __exit fb_console_exit(void)
do_unregister_con_driver(&fb_con);
console_unlock();
-}
+}
#endif
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index ab3545a00abc..875541ff185b 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -13,7 +13,6 @@
#include <linux/module.h>
-#include <linux/aperture.h>
#include <linux/compat.h>
#include <linux/types.h>
#include <linux/errno.h>
@@ -1657,32 +1656,6 @@ static void do_unregister_framebuffer(struct fb_info *fb_info)
put_fb_info(fb_info);
}
-static int fb_aperture_acquire_for_platform_device(struct fb_info *fb_info)
-{
- struct apertures_struct *ap = fb_info->apertures;
- struct device *dev = fb_info->device;
- struct platform_device *pdev;
- unsigned int i;
- int ret;
-
- if (!ap)
- return 0;
-
- if (!dev_is_platform(dev))
- return 0;
-
- pdev = to_platform_device(dev);
-
- for (ret = 0, i = 0; i < ap->count; ++i) {
- ret = devm_aperture_acquire_for_platform_device(pdev, ap->ranges[i].base,
- ap->ranges[i].size);
- if (ret)
- break;
- }
-
- return ret;
-}
-
/**
* register_framebuffer - registers a frame buffer device
* @fb_info: frame buffer info structure
@@ -1697,12 +1670,6 @@ register_framebuffer(struct fb_info *fb_info)
{
int ret;
- if (fb_info->flags & FBINFO_MISC_FIRMWARE) {
- ret = fb_aperture_acquire_for_platform_device(fb_info);
- if (ret)
- return ret;
- }
-
mutex_lock(&registration_lock);
ret = do_register_framebuffer(fb_info);
mutex_unlock(&registration_lock);
diff --git a/drivers/video/fbdev/core/fbsysfs.c b/drivers/video/fbdev/core/fbsysfs.c
index 4d7f63892dcc..0c33c4adcd79 100644
--- a/drivers/video/fbdev/core/fbsysfs.c
+++ b/drivers/video/fbdev/core/fbsysfs.c
@@ -88,7 +88,6 @@ void framebuffer_release(struct fb_info *info)
mutex_destroy(&info->bl_curve_mutex);
#endif
- kfree(info->apertures);
kfree(info);
}
EXPORT_SYMBOL(framebuffer_release);
diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c
index 16c1aaae9afa..a5779fb453a2 100644
--- a/drivers/video/fbdev/efifb.c
+++ b/drivers/video/fbdev/efifb.c
@@ -7,6 +7,7 @@
*
*/
+#include <linux/aperture.h>
#include <linux/kernel.h>
#include <linux/efi.h>
#include <linux/efi-bgrt.h>
@@ -49,6 +50,12 @@ static u64 mem_flags = EFI_MEMORY_WC | EFI_MEMORY_UC;
static struct pci_dev *efifb_pci_dev; /* dev with BAR covering the efifb */
+struct efifb_par {
+ u32 pseudo_palette[16];
+ resource_size_t base;
+ resource_size_t size;
+};
+
static struct fb_var_screeninfo efifb_defined = {
.activate = FB_ACTIVATE_NOW,
.height = -1,
@@ -249,6 +256,8 @@ static inline void efifb_show_boot_graphics(struct fb_info *info) {}
*/
static void efifb_destroy(struct fb_info *info)
{
+ struct efifb_par *par = info->par;
+
if (efifb_pci_dev)
pm_runtime_put(&efifb_pci_dev->dev);
@@ -260,8 +269,7 @@ static void efifb_destroy(struct fb_info *info)
}
if (request_mem_succeeded)
- release_mem_region(info->apertures->ranges[0].base,
- info->apertures->ranges[0].size);
+ release_mem_region(par->base, par->size);
fb_dealloc_cmap(&info->cmap);
framebuffer_release(info);
@@ -351,6 +359,7 @@ static u64 bar_offset;
static int efifb_probe(struct platform_device *dev)
{
struct fb_info *info;
+ struct efifb_par *par;
int err, orientation;
unsigned int size_vmode;
unsigned int size_remap;
@@ -447,22 +456,17 @@ static int efifb_probe(struct platform_device *dev)
efifb_fix.smem_start);
}
- info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev);
+ info = framebuffer_alloc(sizeof(*par), &dev->dev);
if (!info) {
err = -ENOMEM;
goto err_release_mem;
}
platform_set_drvdata(dev, info);
- info->pseudo_palette = info->par;
- info->par = NULL;
+ par = info->par;
+ info->pseudo_palette = par->pseudo_palette;
- info->apertures = alloc_apertures(1);
- if (!info->apertures) {
- err = -ENOMEM;
- goto err_release_fb;
- }
- info->apertures->ranges[0].base = efifb_fix.smem_start;
- info->apertures->ranges[0].size = size_remap;
+ par->base = efifb_fix.smem_start;
+ par->size = size_remap;
if (efi_enabled(EFI_MEMMAP) &&
!efi_mem_desc_lookup(efifb_fix.smem_start, &md)) {
@@ -551,7 +555,7 @@ static int efifb_probe(struct platform_device *dev)
info->fbops = &efifb_ops;
info->var = efifb_defined;
info->fix = efifb_fix;
- info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE;
+ info->flags = FBINFO_FLAG_DEFAULT;
orientation = drm_get_panel_orientation_quirk(efifb_defined.xres,
efifb_defined.yres);
@@ -584,6 +588,11 @@ static int efifb_probe(struct platform_device *dev)
if (efifb_pci_dev)
WARN_ON(pm_runtime_get_sync(&efifb_pci_dev->dev) < 0);
+ err = devm_aperture_acquire_for_platform_device(dev, par->base, par->size);
+ if (err) {
+ pr_err("efifb: cannot acquire aperture\n");
+ goto err_put_rpm_ref;
+ }
err = register_framebuffer(info);
if (err < 0) {
pr_err("efifb: cannot register framebuffer\n");
diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c
index a7f79f51f40c..ec3f6cf05f8c 100644
--- a/drivers/video/fbdev/hyperv_fb.c
+++ b/drivers/video/fbdev/hyperv_fb.c
@@ -994,13 +994,10 @@ static int hvfb_getmem(struct hv_device *hdev, struct fb_info *info)
struct pci_dev *pdev = NULL;
void __iomem *fb_virt;
int gen2vm = efi_enabled(EFI_BOOT);
+ resource_size_t base, size;
phys_addr_t paddr;
int ret;
- info->apertures = alloc_apertures(1);
- if (!info->apertures)
- return -ENOMEM;
-
if (!gen2vm) {
pdev = pci_get_device(PCI_VENDOR_ID_MICROSOFT,
PCI_DEVICE_ID_HYPERV_VIDEO, NULL);
@@ -1009,8 +1006,8 @@ static int hvfb_getmem(struct hv_device *hdev, struct fb_info *info)
return -ENODEV;
}
- info->apertures->ranges[0].base = pci_resource_start(pdev, 0);
- info->apertures->ranges[0].size = pci_resource_len(pdev, 0);
+ base = pci_resource_start(pdev, 0);
+ size = pci_resource_len(pdev, 0);
/*
* For Gen 1 VM, we can directly use the contiguous memory
@@ -1033,8 +1030,8 @@ static int hvfb_getmem(struct hv_device *hdev, struct fb_info *info)
}
pr_info("Unable to allocate enough contiguous physical memory on Gen 1 VM. Using MMIO instead.\n");
} else {
- info->apertures->ranges[0].base = screen_info.lfb_base;
- info->apertures->ranges[0].size = screen_info.lfb_size;
+ base = screen_info.lfb_base;
+ size = screen_info.lfb_size;
}
/*
@@ -1076,9 +1073,7 @@ static int hvfb_getmem(struct hv_device *hdev, struct fb_info *info)
info->screen_size = dio_fb_size;
getmem_done:
- aperture_remove_conflicting_devices(info->apertures->ranges[0].base,
- info->apertures->ranges[0].size,
- false, KBUILD_MODNAME);
+ aperture_remove_conflicting_devices(base, size, false, KBUILD_MODNAME);
if (gen2vm) {
/* framebuffer is reallocated, clear screen_info to avoid misuse from kexec */
diff --git a/drivers/video/fbdev/offb.c b/drivers/video/fbdev/offb.c
index 91001990e351..f7ad6bc9d02d 100644
--- a/drivers/video/fbdev/offb.c
+++ b/drivers/video/fbdev/offb.c
@@ -12,6 +12,7 @@
* more details.
*/
+#include <linux/aperture.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
@@ -53,10 +54,11 @@ struct offb_par {
volatile void __iomem *cmap_data;
int cmap_type;
int blanked;
+ u32 pseudo_palette[16];
+ resource_size_t base;
+ resource_size_t size;
};
-struct offb_par default_par;
-
#ifdef CONFIG_PPC32
extern boot_infos_t *boot_infos;
#endif
@@ -280,9 +282,11 @@ static int offb_set_par(struct fb_info *info)
static void offb_destroy(struct fb_info *info)
{
+ struct offb_par *par = info->par;
+
if (info->screen_base)
iounmap(info->screen_base);
- release_mem_region(info->apertures->ranges[0].base, info->apertures->ranges[0].size);
+ release_mem_region(par->base, par->size);
fb_dealloc_cmap(&info->cmap);
framebuffer_release(info);
}
@@ -393,11 +397,11 @@ static void offb_init_fb(struct platform_device *parent, const char *name,
int foreign_endian, struct device_node *dp)
{
unsigned long res_size = pitch * height;
- struct offb_par *par = &default_par;
unsigned long res_start = address;
struct fb_fix_screeninfo *fix;
struct fb_var_screeninfo *var;
struct fb_info *info;
+ struct offb_par *par;
if (!request_mem_region(res_start, res_size, "offb"))
return;
@@ -411,17 +415,15 @@ static void offb_init_fb(struct platform_device *parent, const char *name,
return;
}
- info = framebuffer_alloc(sizeof(u32) * 16, &parent->dev);
-
+ info = framebuffer_alloc(sizeof(*par), &parent->dev);
if (!info) {
release_mem_region(res_start, res_size);
return;
}
platform_set_drvdata(parent, info);
-
+ par = info->par;
fix = &info->fix;
var = &info->var;
- info->par = par;
if (name) {
strcpy(fix->id, "OFfb ");
@@ -506,20 +508,18 @@ static void offb_init_fb(struct platform_device *parent, const char *name,
var->sync = 0;
var->vmode = FB_VMODE_NONINTERLACED;
- /* set offb aperture size for generic probing */
- info->apertures = alloc_apertures(1);
- if (!info->apertures)
- goto out_aper;
- info->apertures->ranges[0].base = address;
- info->apertures->ranges[0].size = fix->smem_len;
+ par->base = address;
+ par->size = fix->smem_len;
info->fbops = &offb_ops;
info->screen_base = ioremap(address, fix->smem_len);
- info->pseudo_palette = (void *) (info + 1);
- info->flags = FBINFO_DEFAULT | FBINFO_MISC_FIRMWARE | foreign_endian;
+ info->pseudo_palette = par->pseudo_palette;
+ info->flags = FBINFO_DEFAULT | foreign_endian;
fb_alloc_cmap(&info->cmap, 256, 0);
+ if (devm_aperture_acquire_for_platform_device(parent, par->base, par->size) < 0)
+ goto out_err;
if (register_framebuffer(info) < 0)
goto out_err;
@@ -529,7 +529,6 @@ static void offb_init_fb(struct platform_device *parent, const char *name,
out_err:
fb_dealloc_cmap(&info->cmap);
iounmap(info->screen_base);
-out_aper:
iounmap(par->cmap_adr);
par->cmap_adr = NULL;
framebuffer_release(info);
diff --git a/drivers/video/fbdev/simplefb.c b/drivers/video/fbdev/simplefb.c
index e770b4a356b5..10d71879d340 100644
--- a/drivers/video/fbdev/simplefb.c
+++ b/drivers/video/fbdev/simplefb.c
@@ -12,6 +12,7 @@
* Copyright (C) 1996 Paul Mackerras
*/
+#include <linux/aperture.h>
#include <linux/errno.h>
#include <linux/fb.h>
#include <linux/io.h>
@@ -68,6 +69,8 @@ static int simplefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
struct simplefb_par {
u32 palette[PSEUDO_PALETTE_SIZE];
+ resource_size_t base;
+ resource_size_t size;
struct resource *mem;
#if defined CONFIG_OF && defined CONFIG_COMMON_CLK
bool clks_enabled;
@@ -472,16 +475,11 @@ static int simplefb_probe(struct platform_device *pdev)
info->var.blue = params.format->blue;
info->var.transp = params.format->transp;
- info->apertures = alloc_apertures(1);
- if (!info->apertures) {
- ret = -ENOMEM;
- goto error_fb_release;
- }
- info->apertures->ranges[0].base = info->fix.smem_start;
- info->apertures->ranges[0].size = info->fix.smem_len;
+ par->base = info->fix.smem_start;
+ par->size = info->fix.smem_len;
info->fbops = &simplefb_ops;
- info->flags = FBINFO_DEFAULT | FBINFO_MISC_FIRMWARE;
+ info->flags = FBINFO_DEFAULT;
info->screen_base = ioremap_wc(info->fix.smem_start,
info->fix.smem_len);
if (!info->screen_base) {
@@ -511,6 +509,11 @@ static int simplefb_probe(struct platform_device *pdev)
if (mem != res)
par->mem = mem; /* release in clean-up handler */
+ ret = devm_aperture_acquire_for_platform_device(pdev, par->base, par->size);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to acquire aperture: %d\n", ret);
+ goto error_regulators;
+ }
ret = register_framebuffer(info);
if (ret < 0) {
dev_err(&pdev->dev, "Unable to register simplefb: %d\n", ret);
diff --git a/drivers/video/fbdev/vesafb.c b/drivers/video/fbdev/vesafb.c
index 929d4775cb4b..3f8bdfcf51f0 100644
--- a/drivers/video/fbdev/vesafb.c
+++ b/drivers/video/fbdev/vesafb.c
@@ -9,6 +9,7 @@
*
*/
+#include <linux/aperture.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
@@ -31,6 +32,8 @@
struct vesafb_par {
u32 pseudo_palette[256];
+ resource_size_t base;
+ resource_size_t size;
int wc_cookie;
struct resource *region;
};
@@ -140,7 +143,7 @@ static int vesafb_setcolreg(unsigned regno, unsigned red, unsigned green,
* (according to the entries in the `var' structure). Return
* != 0 for invalid regno.
*/
-
+
if (regno >= info->cmap.len)
return 1;
@@ -191,7 +194,7 @@ static void vesafb_destroy(struct fb_info *info)
arch_phys_wc_del(par->wc_cookie);
if (info->screen_base)
iounmap(info->screen_base);
- release_mem_region(info->apertures->ranges[0].base, info->apertures->ranges[0].size);
+ release_mem_region(par->base, par->size);
framebuffer_release(info);
}
@@ -209,13 +212,13 @@ static struct fb_ops vesafb_ops = {
static int vesafb_setup(char *options)
{
char *this_opt;
-
+
if (!options || !*options)
return 0;
-
+
while ((this_opt = strsep(&options, ",")) != NULL) {
if (!*this_opt) continue;
-
+
if (! strcmp(this_opt, "inverse"))
inverse=1;
else if (! strcmp(this_opt, "redraw"))
@@ -316,14 +319,8 @@ static int vesafb_probe(struct platform_device *dev)
par = info->par;
info->pseudo_palette = par->pseudo_palette;
- /* set vesafb aperture size for generic probing */
- info->apertures = alloc_apertures(1);
- if (!info->apertures) {
- err = -ENOMEM;
- goto err;
- }
- info->apertures->ranges[0].base = screen_info.lfb_base;
- info->apertures->ranges[0].size = size_total;
+ par->base = screen_info.lfb_base;
+ par->size = size_total;
printk(KERN_INFO "vesafb: mode is %dx%dx%d, linelength=%d, pages=%d\n",
vesafb_defined.xres, vesafb_defined.yres, vesafb_defined.bits_per_pixel, vesafb_fix.line_length, screen_info.pages);
@@ -381,7 +378,7 @@ static int vesafb_probe(struct platform_device *dev)
vesafb_defined.pixclock = 10000000 / vesafb_defined.xres * 1000 / vesafb_defined.yres;
vesafb_defined.left_margin = (vesafb_defined.xres / 8) & 0xf8;
vesafb_defined.hsync_len = (vesafb_defined.xres / 8) & 0xf8;
-
+
vesafb_defined.red.offset = screen_info.red_pos;
vesafb_defined.red.length = screen_info.red_size;
vesafb_defined.green.offset = screen_info.green_pos;
@@ -460,27 +457,29 @@ static int vesafb_probe(struct platform_device *dev)
info->fbops = &vesafb_ops;
info->var = vesafb_defined;
info->fix = vesafb_fix;
- info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE |
- (ypan ? FBINFO_HWACCEL_YPAN : 0);
+ info->flags = FBINFO_FLAG_DEFAULT | (ypan ? FBINFO_HWACCEL_YPAN : 0);
if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
err = -ENOMEM;
goto err_release_region;
}
+ err = devm_aperture_acquire_for_platform_device(dev, par->base, par->size);
+ if (err)
+ goto err_fb_dealloc_cmap;
if (register_framebuffer(info)<0) {
err = -EINVAL;
- fb_dealloc_cmap(&info->cmap);
- goto err_release_region;
+ goto err_fb_dealloc_cmap;
}
fb_info(info, "%s frame buffer device\n", info->fix.id);
return 0;
+err_fb_dealloc_cmap:
+ fb_dealloc_cmap(&info->cmap);
err_release_region:
arch_phys_wc_del(par->wc_cookie);
if (info->screen_base)
iounmap(info->screen_base);
if (par->region)
release_region(0x3c0, 32);
-err:
framebuffer_release(info);
release_mem_region(vesafb_fix.smem_start, size_total);
return err;
diff --git a/drivers/video/fbdev/vga16fb.c b/drivers/video/fbdev/vga16fb.c
index af47f8217095..1a8ffdb2be26 100644
--- a/drivers/video/fbdev/vga16fb.c
+++ b/drivers/video/fbdev/vga16fb.c
@@ -10,6 +10,7 @@
* archive for more details.
*/
+#include <linux/aperture.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
@@ -1324,11 +1325,6 @@ static int vga16fb_probe(struct platform_device *dev)
ret = -ENOMEM;
goto err_fb_alloc;
}
- info->apertures = alloc_apertures(1);
- if (!info->apertures) {
- ret = -ENOMEM;
- goto err_ioremap;
- }
/* XXX share VGA_FB_PHYS_BASE and I/O region with vgacon and others */
info->screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS_BASE, 0);
@@ -1363,8 +1359,7 @@ static int vga16fb_probe(struct platform_device *dev)
info->fix = vga16fb_fix;
/* supports rectangles with widths of multiples of 8 */
info->pixmap.blit_x = 1 << 7 | 1 << 15 | 1 << 23 | 1 << 31;
- info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE |
- FBINFO_HWACCEL_YPAN;
+ info->flags = FBINFO_FLAG_DEFAULT | FBINFO_HWACCEL_YPAN;
i = (info->var.bits_per_pixel == 8) ? 256 : 16;
ret = fb_alloc_cmap(&info->cmap, i, 0);
@@ -1382,9 +1377,9 @@ static int vga16fb_probe(struct platform_device *dev)
vga16fb_update_fix(info);
- info->apertures->ranges[0].base = VGA_FB_PHYS_BASE;
- info->apertures->ranges[0].size = VGA_FB_PHYS_SIZE;
-
+ ret = devm_aperture_acquire_for_platform_device(dev, VGA_FB_PHYS_BASE, VGA_FB_PHYS_SIZE);
+ if (ret)
+ goto err_check_var;
if (register_framebuffer(info) < 0) {
printk(KERN_ERR "vga16fb: unable to register framebuffer\n");
ret = -EINVAL;
diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c
index b9a80aedee1b..3893dc29eb26 100644
--- a/drivers/virtio/virtio.c
+++ b/drivers/virtio/virtio.c
@@ -95,9 +95,9 @@ static int virtio_dev_match(struct device *_dv, struct device_driver *_dr)
return 0;
}
-static int virtio_uevent(struct device *_dv, struct kobj_uevent_env *env)
+static int virtio_uevent(const struct device *_dv, struct kobj_uevent_env *env)
{
- struct virtio_device *dev = dev_to_virtio(_dv);
+ const struct virtio_device *dev = dev_to_virtio(_dv);
return add_uevent_var(env, "MODALIAS=virtio:d%08Xv%08X",
dev->id.device, dev->id.vendor);
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index 723c4e29e1d3..41144b5246a8 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -202,6 +202,9 @@ struct vring_virtqueue {
/* DMA, allocation, and size information */
bool we_own_ring;
+ /* Device used for doing DMA */
+ struct device *dma_dev;
+
#ifdef DEBUG
/* They're supposed to lock for us. */
unsigned int in_use;
@@ -219,7 +222,8 @@ static struct virtqueue *__vring_new_virtqueue(unsigned int index,
bool context,
bool (*notify)(struct virtqueue *),
void (*callback)(struct virtqueue *),
- const char *name);
+ const char *name,
+ struct device *dma_dev);
static struct vring_desc_extra *vring_alloc_desc_extra(unsigned int num);
static void vring_free(struct virtqueue *_vq);
@@ -297,10 +301,11 @@ size_t virtio_max_dma_size(struct virtio_device *vdev)
EXPORT_SYMBOL_GPL(virtio_max_dma_size);
static void *vring_alloc_queue(struct virtio_device *vdev, size_t size,
- dma_addr_t *dma_handle, gfp_t flag)
+ dma_addr_t *dma_handle, gfp_t flag,
+ struct device *dma_dev)
{
if (vring_use_dma_api(vdev)) {
- return dma_alloc_coherent(vdev->dev.parent, size,
+ return dma_alloc_coherent(dma_dev, size,
dma_handle, flag);
} else {
void *queue = alloc_pages_exact(PAGE_ALIGN(size), flag);
@@ -330,10 +335,11 @@ static void *vring_alloc_queue(struct virtio_device *vdev, size_t size,
}
static void vring_free_queue(struct virtio_device *vdev, size_t size,
- void *queue, dma_addr_t dma_handle)
+ void *queue, dma_addr_t dma_handle,
+ struct device *dma_dev)
{
if (vring_use_dma_api(vdev))
- dma_free_coherent(vdev->dev.parent, size, queue, dma_handle);
+ dma_free_coherent(dma_dev, size, queue, dma_handle);
else
free_pages_exact(queue, PAGE_ALIGN(size));
}
@@ -341,11 +347,11 @@ static void vring_free_queue(struct virtio_device *vdev, size_t size,
/*
* The DMA ops on various arches are rather gnarly right now, and
* making all of the arch DMA ops work on the vring device itself
- * is a mess. For now, we use the parent device for DMA ops.
+ * is a mess.
*/
static inline struct device *vring_dma_dev(const struct vring_virtqueue *vq)
{
- return vq->vq.vdev->dev.parent;
+ return vq->dma_dev;
}
/* Map one sg entry. */
@@ -1032,11 +1038,12 @@ err_state:
}
static void vring_free_split(struct vring_virtqueue_split *vring_split,
- struct virtio_device *vdev)
+ struct virtio_device *vdev, struct device *dma_dev)
{
vring_free_queue(vdev, vring_split->queue_size_in_bytes,
vring_split->vring.desc,
- vring_split->queue_dma_addr);
+ vring_split->queue_dma_addr,
+ dma_dev);
kfree(vring_split->desc_state);
kfree(vring_split->desc_extra);
@@ -1046,7 +1053,8 @@ static int vring_alloc_queue_split(struct vring_virtqueue_split *vring_split,
struct virtio_device *vdev,
u32 num,
unsigned int vring_align,
- bool may_reduce_num)
+ bool may_reduce_num,
+ struct device *dma_dev)
{
void *queue = NULL;
dma_addr_t dma_addr;
@@ -1061,7 +1069,8 @@ static int vring_alloc_queue_split(struct vring_virtqueue_split *vring_split,
for (; num && vring_size(num, vring_align) > PAGE_SIZE; num /= 2) {
queue = vring_alloc_queue(vdev, vring_size(num, vring_align),
&dma_addr,
- GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO);
+ GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
+ dma_dev);
if (queue)
break;
if (!may_reduce_num)
@@ -1074,7 +1083,8 @@ static int vring_alloc_queue_split(struct vring_virtqueue_split *vring_split,
if (!queue) {
/* Try to get a single page. You are my only hope! */
queue = vring_alloc_queue(vdev, vring_size(num, vring_align),
- &dma_addr, GFP_KERNEL | __GFP_ZERO);
+ &dma_addr, GFP_KERNEL | __GFP_ZERO,
+ dma_dev);
}
if (!queue)
return -ENOMEM;
@@ -1100,21 +1110,22 @@ static struct virtqueue *vring_create_virtqueue_split(
bool context,
bool (*notify)(struct virtqueue *),
void (*callback)(struct virtqueue *),
- const char *name)
+ const char *name,
+ struct device *dma_dev)
{
struct vring_virtqueue_split vring_split = {};
struct virtqueue *vq;
int err;
err = vring_alloc_queue_split(&vring_split, vdev, num, vring_align,
- may_reduce_num);
+ may_reduce_num, dma_dev);
if (err)
return NULL;
vq = __vring_new_virtqueue(index, &vring_split, vdev, weak_barriers,
- context, notify, callback, name);
+ context, notify, callback, name, dma_dev);
if (!vq) {
- vring_free_split(&vring_split, vdev);
+ vring_free_split(&vring_split, vdev, dma_dev);
return NULL;
}
@@ -1132,7 +1143,8 @@ static int virtqueue_resize_split(struct virtqueue *_vq, u32 num)
err = vring_alloc_queue_split(&vring_split, vdev, num,
vq->split.vring_align,
- vq->split.may_reduce_num);
+ vq->split.may_reduce_num,
+ vring_dma_dev(vq));
if (err)
goto err;
@@ -1150,7 +1162,7 @@ static int virtqueue_resize_split(struct virtqueue *_vq, u32 num)
return 0;
err_state_extra:
- vring_free_split(&vring_split, vdev);
+ vring_free_split(&vring_split, vdev, vring_dma_dev(vq));
err:
virtqueue_reinit_split(vq);
return -ENOMEM;
@@ -1841,22 +1853,26 @@ static struct vring_desc_extra *vring_alloc_desc_extra(unsigned int num)
}
static void vring_free_packed(struct vring_virtqueue_packed *vring_packed,
- struct virtio_device *vdev)
+ struct virtio_device *vdev,
+ struct device *dma_dev)
{
if (vring_packed->vring.desc)
vring_free_queue(vdev, vring_packed->ring_size_in_bytes,
vring_packed->vring.desc,
- vring_packed->ring_dma_addr);
+ vring_packed->ring_dma_addr,
+ dma_dev);
if (vring_packed->vring.driver)
vring_free_queue(vdev, vring_packed->event_size_in_bytes,
vring_packed->vring.driver,
- vring_packed->driver_event_dma_addr);
+ vring_packed->driver_event_dma_addr,
+ dma_dev);
if (vring_packed->vring.device)
vring_free_queue(vdev, vring_packed->event_size_in_bytes,
vring_packed->vring.device,
- vring_packed->device_event_dma_addr);
+ vring_packed->device_event_dma_addr,
+ dma_dev);
kfree(vring_packed->desc_state);
kfree(vring_packed->desc_extra);
@@ -1864,7 +1880,7 @@ static void vring_free_packed(struct vring_virtqueue_packed *vring_packed,
static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
struct virtio_device *vdev,
- u32 num)
+ u32 num, struct device *dma_dev)
{
struct vring_packed_desc *ring;
struct vring_packed_desc_event *driver, *device;
@@ -1875,7 +1891,8 @@ static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
ring = vring_alloc_queue(vdev, ring_size_in_bytes,
&ring_dma_addr,
- GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO);
+ GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
+ dma_dev);
if (!ring)
goto err;
@@ -1887,7 +1904,8 @@ static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
driver = vring_alloc_queue(vdev, event_size_in_bytes,
&driver_event_dma_addr,
- GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO);
+ GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
+ dma_dev);
if (!driver)
goto err;
@@ -1897,7 +1915,8 @@ static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
device = vring_alloc_queue(vdev, event_size_in_bytes,
&device_event_dma_addr,
- GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO);
+ GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
+ dma_dev);
if (!device)
goto err;
@@ -1909,7 +1928,7 @@ static int vring_alloc_queue_packed(struct vring_virtqueue_packed *vring_packed,
return 0;
err:
- vring_free_packed(vring_packed, vdev);
+ vring_free_packed(vring_packed, vdev, dma_dev);
return -ENOMEM;
}
@@ -1987,13 +2006,14 @@ static struct virtqueue *vring_create_virtqueue_packed(
bool context,
bool (*notify)(struct virtqueue *),
void (*callback)(struct virtqueue *),
- const char *name)
+ const char *name,
+ struct device *dma_dev)
{
struct vring_virtqueue_packed vring_packed = {};
struct vring_virtqueue *vq;
int err;
- if (vring_alloc_queue_packed(&vring_packed, vdev, num))
+ if (vring_alloc_queue_packed(&vring_packed, vdev, num, dma_dev))
goto err_ring;
vq = kmalloc(sizeof(*vq), GFP_KERNEL);
@@ -2014,6 +2034,7 @@ static struct virtqueue *vring_create_virtqueue_packed(
vq->broken = false;
#endif
vq->packed_ring = true;
+ vq->dma_dev = dma_dev;
vq->use_dma_api = vring_use_dma_api(vdev);
vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC) &&
@@ -2040,7 +2061,7 @@ static struct virtqueue *vring_create_virtqueue_packed(
err_state_extra:
kfree(vq);
err_vq:
- vring_free_packed(&vring_packed, vdev);
+ vring_free_packed(&vring_packed, vdev, dma_dev);
err_ring:
return NULL;
}
@@ -2052,7 +2073,7 @@ static int virtqueue_resize_packed(struct virtqueue *_vq, u32 num)
struct virtio_device *vdev = _vq->vdev;
int err;
- if (vring_alloc_queue_packed(&vring_packed, vdev, num))
+ if (vring_alloc_queue_packed(&vring_packed, vdev, num, vring_dma_dev(vq)))
goto err_ring;
err = vring_alloc_state_extra_packed(&vring_packed);
@@ -2069,7 +2090,7 @@ static int virtqueue_resize_packed(struct virtqueue *_vq, u32 num)
return 0;
err_state_extra:
- vring_free_packed(&vring_packed, vdev);
+ vring_free_packed(&vring_packed, vdev, vring_dma_dev(vq));
err_ring:
virtqueue_reinit_packed(vq);
return -ENOMEM;
@@ -2481,7 +2502,8 @@ static struct virtqueue *__vring_new_virtqueue(unsigned int index,
bool context,
bool (*notify)(struct virtqueue *),
void (*callback)(struct virtqueue *),
- const char *name)
+ const char *name,
+ struct device *dma_dev)
{
struct vring_virtqueue *vq;
int err;
@@ -2507,6 +2529,7 @@ static struct virtqueue *__vring_new_virtqueue(unsigned int index,
#else
vq->broken = false;
#endif
+ vq->dma_dev = dma_dev;
vq->use_dma_api = vring_use_dma_api(vdev);
vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC) &&
@@ -2549,14 +2572,39 @@ struct virtqueue *vring_create_virtqueue(
if (virtio_has_feature(vdev, VIRTIO_F_RING_PACKED))
return vring_create_virtqueue_packed(index, num, vring_align,
vdev, weak_barriers, may_reduce_num,
- context, notify, callback, name);
+ context, notify, callback, name, vdev->dev.parent);
return vring_create_virtqueue_split(index, num, vring_align,
vdev, weak_barriers, may_reduce_num,
- context, notify, callback, name);
+ context, notify, callback, name, vdev->dev.parent);
}
EXPORT_SYMBOL_GPL(vring_create_virtqueue);
+struct virtqueue *vring_create_virtqueue_dma(
+ unsigned int index,
+ unsigned int num,
+ unsigned int vring_align,
+ struct virtio_device *vdev,
+ bool weak_barriers,
+ bool may_reduce_num,
+ bool context,
+ bool (*notify)(struct virtqueue *),
+ void (*callback)(struct virtqueue *),
+ const char *name,
+ struct device *dma_dev)
+{
+
+ if (virtio_has_feature(vdev, VIRTIO_F_RING_PACKED))
+ return vring_create_virtqueue_packed(index, num, vring_align,
+ vdev, weak_barriers, may_reduce_num,
+ context, notify, callback, name, dma_dev);
+
+ return vring_create_virtqueue_split(index, num, vring_align,
+ vdev, weak_barriers, may_reduce_num,
+ context, notify, callback, name, dma_dev);
+}
+EXPORT_SYMBOL_GPL(vring_create_virtqueue_dma);
+
/**
* virtqueue_resize - resize the vring of vq
* @_vq: the struct virtqueue we're talking about.
@@ -2645,7 +2693,8 @@ struct virtqueue *vring_new_virtqueue(unsigned int index,
vring_init(&vring_split.vring, num, pages, vring_align);
return __vring_new_virtqueue(index, &vring_split, vdev, weak_barriers,
- context, notify, callback, name);
+ context, notify, callback, name,
+ vdev->dev.parent);
}
EXPORT_SYMBOL_GPL(vring_new_virtqueue);
@@ -2658,17 +2707,20 @@ static void vring_free(struct virtqueue *_vq)
vring_free_queue(vq->vq.vdev,
vq->packed.ring_size_in_bytes,
vq->packed.vring.desc,
- vq->packed.ring_dma_addr);
+ vq->packed.ring_dma_addr,
+ vring_dma_dev(vq));
vring_free_queue(vq->vq.vdev,
vq->packed.event_size_in_bytes,
vq->packed.vring.driver,
- vq->packed.driver_event_dma_addr);
+ vq->packed.driver_event_dma_addr,
+ vring_dma_dev(vq));
vring_free_queue(vq->vq.vdev,
vq->packed.event_size_in_bytes,
vq->packed.vring.device,
- vq->packed.device_event_dma_addr);
+ vq->packed.device_event_dma_addr,
+ vring_dma_dev(vq));
kfree(vq->packed.desc_state);
kfree(vq->packed.desc_extra);
@@ -2676,7 +2728,8 @@ static void vring_free(struct virtqueue *_vq)
vring_free_queue(vq->vq.vdev,
vq->split.queue_size_in_bytes,
vq->split.vring.desc,
- vq->split.queue_dma_addr);
+ vq->split.queue_dma_addr,
+ vring_dma_dev(vq));
}
}
if (!vq->packed_ring) {
diff --git a/drivers/virtio/virtio_vdpa.c b/drivers/virtio/virtio_vdpa.c
index 9670cc79371d..d7f5af62ddaa 100644
--- a/drivers/virtio/virtio_vdpa.c
+++ b/drivers/virtio/virtio_vdpa.c
@@ -135,6 +135,7 @@ virtio_vdpa_setup_vq(struct virtio_device *vdev, unsigned int index,
{
struct virtio_vdpa_device *vd_dev = to_virtio_vdpa_device(vdev);
struct vdpa_device *vdpa = vd_get_vdpa(vdev);
+ struct device *dma_dev;
const struct vdpa_config_ops *ops = vdpa->config;
struct virtio_vdpa_vq_info *info;
struct vdpa_callback cb;
@@ -175,9 +176,15 @@ virtio_vdpa_setup_vq(struct virtio_device *vdev, unsigned int index,
/* Create the vring */
align = ops->get_vq_align(vdpa);
- vq = vring_create_virtqueue(index, max_num, align, vdev,
- true, may_reduce_num, ctx,
- virtio_vdpa_notify, callback, name);
+
+ if (ops->get_vq_dma_dev)
+ dma_dev = ops->get_vq_dma_dev(vdpa, index);
+ else
+ dma_dev = vdpa_get_dma_dev(vdpa);
+ vq = vring_create_virtqueue_dma(index, max_num, align, vdev,
+ true, may_reduce_num, ctx,
+ virtio_vdpa_notify, callback,
+ name, dma_dev);
if (!vq) {
err = -ENOMEM;
goto error_new_virtqueue;
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index 4a2ddf730a3a..9d199fed9628 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -170,7 +170,7 @@ static struct w1_family w1_default_family = {
.fops = &w1_default_fops,
};
-static int w1_uevent(struct device *dev, struct kobj_uevent_env *env);
+static int w1_uevent(const struct device *dev, struct kobj_uevent_env *env);
static struct bus_type w1_bus_type = {
.name = "w1",
@@ -577,11 +577,11 @@ void w1_destroy_master_attributes(struct w1_master *master)
sysfs_remove_group(&master->dev.kobj, &w1_master_defattr_group);
}
-static int w1_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int w1_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct w1_master *md = NULL;
- struct w1_slave *sl = NULL;
- char *event_owner, *name;
+ const struct w1_master *md = NULL;
+ const struct w1_slave *sl = NULL;
+ const char *event_owner, *name;
int err = 0;
if (dev->driver == &w1_master_driver) {
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 5de74686f12b..f0872970daf9 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -1871,7 +1871,9 @@ config GXP_WATCHDOG
config MT7621_WDT
tristate "Mediatek SoC watchdog"
select WATCHDOG_CORE
- depends on SOC_MT7620 || SOC_MT7621
+ select REGMAP_MMIO
+ select MFD_SYSCON
+ depends on SOC_MT7620 || SOC_MT7621 || COMPILE_TEST
help
Hardware driver for the Mediatek/Ralink MT7621/8 SoC Watchdog Timer.
diff --git a/drivers/watchdog/apple_wdt.c b/drivers/watchdog/apple_wdt.c
index 16aca21f13d6..eddeb0fede89 100644
--- a/drivers/watchdog/apple_wdt.c
+++ b/drivers/watchdog/apple_wdt.c
@@ -136,11 +136,6 @@ static int apple_wdt_restart(struct watchdog_device *wdd, unsigned long mode,
return 0;
}
-static void apple_wdt_clk_disable_unprepare(void *data)
-{
- clk_disable_unprepare(data);
-}
-
static struct watchdog_ops apple_wdt_ops = {
.owner = THIS_MODULE,
.start = apple_wdt_start,
@@ -162,7 +157,6 @@ static int apple_wdt_probe(struct platform_device *pdev)
struct apple_wdt *wdt;
struct clk *clk;
u32 wdt_ctrl;
- int ret;
wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
if (!wdt)
@@ -172,19 +166,9 @@ static int apple_wdt_probe(struct platform_device *pdev)
if (IS_ERR(wdt->regs))
return PTR_ERR(wdt->regs);
- clk = devm_clk_get(dev, NULL);
+ clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(clk))
return PTR_ERR(clk);
-
- ret = clk_prepare_enable(clk);
- if (ret)
- return ret;
-
- ret = devm_add_action_or_reset(dev, apple_wdt_clk_disable_unprepare,
- clk);
- if (ret)
- return ret;
-
wdt->clk_rate = clk_get_rate(clk);
if (!wdt->clk_rate)
return -EINVAL;
diff --git a/drivers/watchdog/armada_37xx_wdt.c b/drivers/watchdog/armada_37xx_wdt.c
index ac9fed1ef681..e58652939f8a 100644
--- a/drivers/watchdog/armada_37xx_wdt.c
+++ b/drivers/watchdog/armada_37xx_wdt.c
@@ -246,11 +246,6 @@ static const struct watchdog_ops armada_37xx_wdt_ops = {
.get_timeleft = armada_37xx_wdt_get_timeleft,
};
-static void armada_clk_disable_unprepare(void *data)
-{
- clk_disable_unprepare(data);
-}
-
static int armada_37xx_wdt_probe(struct platform_device *pdev)
{
struct armada_37xx_watchdog *dev;
@@ -280,18 +275,10 @@ static int armada_37xx_wdt_probe(struct platform_device *pdev)
return -ENOMEM;
/* init clock */
- dev->clk = devm_clk_get(&pdev->dev, NULL);
+ dev->clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(dev->clk))
return PTR_ERR(dev->clk);
- ret = clk_prepare_enable(dev->clk);
- if (ret)
- return ret;
- ret = devm_add_action_or_reset(&pdev->dev,
- armada_clk_disable_unprepare, dev->clk);
- if (ret)
- return ret;
-
dev->clk_rate = clk_get_rate(dev->clk);
if (!dev->clk_rate)
return -EINVAL;
diff --git a/drivers/watchdog/aspeed_wdt.c b/drivers/watchdog/aspeed_wdt.c
index 86b5331bc491..c1e79874a2bb 100644
--- a/drivers/watchdog/aspeed_wdt.c
+++ b/drivers/watchdog/aspeed_wdt.c
@@ -10,6 +10,7 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
+#include <linux/kstrtox.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
diff --git a/drivers/watchdog/at91rm9200_wdt.c b/drivers/watchdog/at91rm9200_wdt.c
index 5126454bb861..d57409c1a4d1 100644
--- a/drivers/watchdog/at91rm9200_wdt.c
+++ b/drivers/watchdog/at91rm9200_wdt.c
@@ -270,7 +270,7 @@ static int at91wdt_remove(struct platform_device *pdev)
misc_deregister(&at91wdt_miscdev);
at91wdt_miscdev.parent = NULL;
- return res;
+ return 0;
}
static void at91wdt_shutdown(struct platform_device *pdev)
diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c
index 292b5a1ca831..fed7be246442 100644
--- a/drivers/watchdog/at91sam9_wdt.c
+++ b/drivers/watchdog/at91sam9_wdt.c
@@ -206,10 +206,9 @@ static int at91_wdt_init(struct platform_device *pdev, struct at91wdt *wdt)
"min heartbeat and max heartbeat might be too close for the system to handle it correctly\n");
if ((tmp & AT91_WDT_WDFIEN) && wdt->irq) {
- err = request_irq(wdt->irq, wdt_interrupt,
- IRQF_SHARED | IRQF_IRQPOLL |
- IRQF_NO_SUSPEND,
- pdev->name, wdt);
+ err = devm_request_irq(dev, wdt->irq, wdt_interrupt,
+ IRQF_SHARED | IRQF_IRQPOLL | IRQF_NO_SUSPEND,
+ pdev->name, wdt);
if (err)
return err;
}
diff --git a/drivers/watchdog/bcm7038_wdt.c b/drivers/watchdog/bcm7038_wdt.c
index 9388838899ac..e038dd66b819 100644
--- a/drivers/watchdog/bcm7038_wdt.c
+++ b/drivers/watchdog/bcm7038_wdt.c
@@ -127,11 +127,6 @@ static const struct watchdog_ops bcm7038_wdt_ops = {
.get_timeleft = bcm7038_wdt_get_timeleft,
};
-static void bcm7038_clk_disable_unprepare(void *data)
-{
- clk_disable_unprepare(data);
-}
-
static int bcm7038_wdt_probe(struct platform_device *pdev)
{
struct bcm7038_wdt_platform_data *pdata = pdev->dev.platform_data;
@@ -153,17 +148,9 @@ static int bcm7038_wdt_probe(struct platform_device *pdev)
if (pdata && pdata->clk_name)
clk_name = pdata->clk_name;
- wdt->clk = devm_clk_get(dev, clk_name);
+ wdt->clk = devm_clk_get_enabled(dev, clk_name);
/* If unable to get clock, use default frequency */
if (!IS_ERR(wdt->clk)) {
- err = clk_prepare_enable(wdt->clk);
- if (err)
- return err;
- err = devm_add_action_or_reset(dev,
- bcm7038_clk_disable_unprepare,
- wdt->clk);
- if (err)
- return err;
wdt->rate = clk_get_rate(wdt->clk);
/* Prevent divide-by-zero exception */
if (!wdt->rate)
diff --git a/drivers/watchdog/cadence_wdt.c b/drivers/watchdog/cadence_wdt.c
index bc99e9164930..23d41043863f 100644
--- a/drivers/watchdog/cadence_wdt.c
+++ b/drivers/watchdog/cadence_wdt.c
@@ -274,11 +274,6 @@ static const struct watchdog_ops cdns_wdt_ops = {
.set_timeout = cdns_wdt_settimeout,
};
-static void cdns_clk_disable_unprepare(void *data)
-{
- clk_disable_unprepare(data);
-}
-
/************************Platform Operations*****************************/
/**
* cdns_wdt_probe - Probe call for the device.
@@ -333,21 +328,11 @@ static int cdns_wdt_probe(struct platform_device *pdev)
watchdog_stop_on_reboot(cdns_wdt_device);
watchdog_set_drvdata(cdns_wdt_device, wdt);
- wdt->clk = devm_clk_get(dev, NULL);
+ wdt->clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(wdt->clk))
return dev_err_probe(dev, PTR_ERR(wdt->clk),
"input clock not found\n");
- ret = clk_prepare_enable(wdt->clk);
- if (ret) {
- dev_err(dev, "unable to enable clock\n");
- return ret;
- }
- ret = devm_add_action_or_reset(dev, cdns_clk_disable_unprepare,
- wdt->clk);
- if (ret)
- return ret;
-
clock_f = clk_get_rate(wdt->clk);
if (clock_f <= CDNS_WDT_CLK_75MHZ) {
wdt->prescaler = CDNS_WDT_PRESCALE_512;
diff --git a/drivers/watchdog/da9062_wdt.c b/drivers/watchdog/da9062_wdt.c
index f02cbd530538..426962547df1 100644
--- a/drivers/watchdog/da9062_wdt.c
+++ b/drivers/watchdog/da9062_wdt.c
@@ -155,11 +155,20 @@ static int da9062_wdt_restart(struct watchdog_device *wdd, unsigned long action,
{
struct da9062_watchdog *wdt = watchdog_get_drvdata(wdd);
struct i2c_client *client = to_i2c_client(wdt->hw->dev);
+ union i2c_smbus_data msg;
int ret;
- /* Don't use regmap because it is not atomic safe */
- ret = i2c_smbus_write_byte_data(client, DA9062AA_CONTROL_F,
- DA9062AA_SHUTDOWN_MASK);
+ /*
+ * Don't use regmap because it is not atomic safe. Additionally, use
+ * unlocked flavor of i2c_smbus_xfer to avoid scenario where i2c bus
+ * might be previously locked by some process unable to release the
+ * lock due to interrupts already being disabled at this late stage.
+ */
+ msg.byte = DA9062AA_SHUTDOWN_MASK;
+ ret = __i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+ I2C_SMBUS_WRITE, DA9062AA_CONTROL_F,
+ I2C_SMBUS_BYTE_DATA, &msg);
+
if (ret < 0)
dev_alert(wdt->hw->dev, "Failed to shutdown (err = %d)\n",
ret);
diff --git a/drivers/watchdog/da9063_wdt.c b/drivers/watchdog/da9063_wdt.c
index 09a4af4c58fc..684667469b10 100644
--- a/drivers/watchdog/da9063_wdt.c
+++ b/drivers/watchdog/da9063_wdt.c
@@ -174,11 +174,20 @@ static int da9063_wdt_restart(struct watchdog_device *wdd, unsigned long action,
{
struct da9063 *da9063 = watchdog_get_drvdata(wdd);
struct i2c_client *client = to_i2c_client(da9063->dev);
+ union i2c_smbus_data msg;
int ret;
- /* Don't use regmap because it is not atomic safe */
- ret = i2c_smbus_write_byte_data(client, DA9063_REG_CONTROL_F,
- DA9063_SHUTDOWN);
+ /*
+ * Don't use regmap because it is not atomic safe. Additionally, use
+ * unlocked flavor of i2c_smbus_xfer to avoid scenario where i2c bus
+ * might previously be locked by some process unable to release the
+ * lock due to interrupts already being disabled at this late stage.
+ */
+ msg.byte = DA9063_SHUTDOWN;
+ ret = __i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+ I2C_SMBUS_WRITE, DA9063_REG_CONTROL_F,
+ I2C_SMBUS_BYTE_DATA, &msg);
+
if (ret < 0)
dev_alert(da9063->dev, "Failed to shutdown (err = %d)\n",
ret);
diff --git a/drivers/watchdog/davinci_wdt.c b/drivers/watchdog/davinci_wdt.c
index 584a56893b81..5f2184bda7b2 100644
--- a/drivers/watchdog/davinci_wdt.c
+++ b/drivers/watchdog/davinci_wdt.c
@@ -189,14 +189,8 @@ static const struct watchdog_ops davinci_wdt_ops = {
.restart = davinci_wdt_restart,
};
-static void davinci_clk_disable_unprepare(void *data)
-{
- clk_disable_unprepare(data);
-}
-
static int davinci_wdt_probe(struct platform_device *pdev)
{
- int ret = 0;
struct device *dev = &pdev->dev;
struct watchdog_device *wdd;
struct davinci_wdt_device *davinci_wdt;
@@ -205,21 +199,11 @@ static int davinci_wdt_probe(struct platform_device *pdev)
if (!davinci_wdt)
return -ENOMEM;
- davinci_wdt->clk = devm_clk_get(dev, NULL);
+ davinci_wdt->clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(davinci_wdt->clk))
return dev_err_probe(dev, PTR_ERR(davinci_wdt->clk),
"failed to get clock node\n");
- ret = clk_prepare_enable(davinci_wdt->clk);
- if (ret) {
- dev_err(dev, "failed to prepare clock\n");
- return ret;
- }
- ret = devm_add_action_or_reset(dev, davinci_clk_disable_unprepare,
- davinci_wdt->clk);
- if (ret)
- return ret;
-
platform_set_drvdata(pdev, davinci_wdt);
wdd = &davinci_wdt->wdd;
diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c
index 52962e8d11a6..462f15bd5ffa 100644
--- a/drivers/watchdog/dw_wdt.c
+++ b/drivers/watchdog/dw_wdt.c
@@ -663,6 +663,7 @@ static int dw_wdt_drv_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, dw_wdt);
watchdog_set_restart_priority(wdd, 128);
+ watchdog_stop_on_reboot(wdd);
ret = watchdog_register_device(wdd);
if (ret)
diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c
index e937b4dd28be..264857d314da 100644
--- a/drivers/watchdog/iTCO_wdt.c
+++ b/drivers/watchdog/iTCO_wdt.c
@@ -441,11 +441,10 @@ static bool iTCO_wdt_set_running(struct iTCO_wdt_private *p)
* Kernel Interfaces
*/
-static const struct watchdog_info ident = {
+static struct watchdog_info ident = {
.options = WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE,
- .firmware_version = 0,
.identity = DRV_NAME,
};
@@ -563,6 +562,7 @@ static int iTCO_wdt_probe(struct platform_device *pdev)
break;
}
+ ident.firmware_version = p->iTCO_version;
p->wddev.info = &ident,
p->wddev.ops = &iTCO_wdt_ops,
p->wddev.bootstatus = 0;
diff --git a/drivers/watchdog/imgpdc_wdt.c b/drivers/watchdog/imgpdc_wdt.c
index b57ff3787052..a55f801895d4 100644
--- a/drivers/watchdog/imgpdc_wdt.c
+++ b/drivers/watchdog/imgpdc_wdt.c
@@ -175,16 +175,11 @@ static const struct watchdog_ops pdc_wdt_ops = {
.restart = pdc_wdt_restart,
};
-static void pdc_clk_disable_unprepare(void *data)
-{
- clk_disable_unprepare(data);
-}
-
static int pdc_wdt_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
u64 div;
- int ret, val;
+ int val;
unsigned long clk_rate;
struct pdc_wdt_dev *pdc_wdt;
@@ -196,38 +191,18 @@ static int pdc_wdt_probe(struct platform_device *pdev)
if (IS_ERR(pdc_wdt->base))
return PTR_ERR(pdc_wdt->base);
- pdc_wdt->sys_clk = devm_clk_get(dev, "sys");
+ pdc_wdt->sys_clk = devm_clk_get_enabled(dev, "sys");
if (IS_ERR(pdc_wdt->sys_clk)) {
dev_err(dev, "failed to get the sys clock\n");
return PTR_ERR(pdc_wdt->sys_clk);
}
- pdc_wdt->wdt_clk = devm_clk_get(dev, "wdt");
+ pdc_wdt->wdt_clk = devm_clk_get_enabled(dev, "wdt");
if (IS_ERR(pdc_wdt->wdt_clk)) {
dev_err(dev, "failed to get the wdt clock\n");
return PTR_ERR(pdc_wdt->wdt_clk);
}
- ret = clk_prepare_enable(pdc_wdt->sys_clk);
- if (ret) {
- dev_err(dev, "could not prepare or enable sys clock\n");
- return ret;
- }
- ret = devm_add_action_or_reset(dev, pdc_clk_disable_unprepare,
- pdc_wdt->sys_clk);
- if (ret)
- return ret;
-
- ret = clk_prepare_enable(pdc_wdt->wdt_clk);
- if (ret) {
- dev_err(dev, "could not prepare or enable wdt clock\n");
- return ret;
- }
- ret = devm_add_action_or_reset(dev, pdc_clk_disable_unprepare,
- pdc_wdt->wdt_clk);
- if (ret)
- return ret;
-
/* We use the clock rate to calculate the max timeout */
clk_rate = clk_get_rate(pdc_wdt->wdt_clk);
if (clk_rate == 0) {
diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c
index d0c5d47ddede..19ab7b3d286b 100644
--- a/drivers/watchdog/imx2_wdt.c
+++ b/drivers/watchdog/imx2_wdt.c
@@ -27,6 +27,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/of_address.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/watchdog.h>
@@ -35,6 +36,7 @@
#define IMX2_WDT_WCR 0x00 /* Control Register */
#define IMX2_WDT_WCR_WT (0xFF << 8) /* -> Watchdog Timeout Field */
+#define IMX2_WDT_WCR_WDW BIT(7) /* -> Watchdog disable for WAIT */
#define IMX2_WDT_WCR_WDA BIT(5) /* -> External Reset WDOG_B */
#define IMX2_WDT_WCR_SRS BIT(4) /* -> Software Reset Signal */
#define IMX2_WDT_WCR_WRE BIT(3) /* -> WDOG Reset Enable */
@@ -60,13 +62,19 @@
#define WDOG_SEC_TO_COUNT(s) ((s * 2 - 1) << 8)
+struct imx2_wdt_data {
+ bool wdw_supported;
+};
+
struct imx2_wdt_device {
struct clk *clk;
struct regmap *regmap;
struct watchdog_device wdog;
+ const struct imx2_wdt_data *data;
bool ext_reset;
bool clk_is_on;
bool no_ping;
+ bool sleep_wait;
};
static bool nowayout = WATCHDOG_NOWAYOUT;
@@ -129,6 +137,9 @@ static inline void imx2_wdt_setup(struct watchdog_device *wdog)
/* Suspend timer in low power mode, write once-only */
val |= IMX2_WDT_WCR_WDZST;
+ /* Suspend timer in low power WAIT mode, write once-only */
+ if (wdev->sleep_wait)
+ val |= IMX2_WDT_WCR_WDW;
/* Strip the old watchdog Time-Out value */
val &= ~IMX2_WDT_WCR_WT;
/* Generate internal chip-level reset if WDOG times out */
@@ -292,6 +303,8 @@ static int __init imx2_wdt_probe(struct platform_device *pdev)
wdog->max_hw_heartbeat_ms = IMX2_WDT_MAX_TIME * 1000;
wdog->parent = dev;
+ wdev->data = of_device_get_match_data(dev);
+
ret = platform_get_irq(pdev, 0);
if (ret > 0)
if (!devm_request_irq(dev, ret, imx2_wdt_isr, 0,
@@ -313,9 +326,18 @@ static int __init imx2_wdt_probe(struct platform_device *pdev)
wdev->ext_reset = of_property_read_bool(dev->of_node,
"fsl,ext-reset-output");
+
+ if (of_property_read_bool(dev->of_node, "fsl,suspend-in-wait")) {
+ if (!wdev->data->wdw_supported) {
+ dev_err(dev, "suspend-in-wait not supported\n");
+ return -EINVAL;
+ }
+ wdev->sleep_wait = true;
+ }
+
/*
* The i.MX7D doesn't support low power mode, so we need to ping the watchdog
- * during suspend.
+ * during suspend. Interaction with "fsl,suspend-in-wait" is unknown!
*/
wdev->no_ping = !of_device_is_compatible(dev->of_node, "fsl,imx7d-wdt");
platform_set_drvdata(pdev, wdog);
@@ -417,9 +439,36 @@ static int __maybe_unused imx2_wdt_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(imx2_wdt_pm_ops, imx2_wdt_suspend,
imx2_wdt_resume);
+struct imx2_wdt_data imx_wdt = {
+ .wdw_supported = true,
+};
+
+struct imx2_wdt_data imx_wdt_legacy = {
+ .wdw_supported = false,
+};
+
static const struct of_device_id imx2_wdt_dt_ids[] = {
- { .compatible = "fsl,imx21-wdt", },
- { .compatible = "fsl,imx7d-wdt", },
+ { .compatible = "fsl,imx21-wdt", .data = &imx_wdt_legacy },
+ { .compatible = "fsl,imx25-wdt", .data = &imx_wdt },
+ { .compatible = "fsl,imx27-wdt", .data = &imx_wdt_legacy },
+ { .compatible = "fsl,imx31-wdt", .data = &imx_wdt_legacy },
+ { .compatible = "fsl,imx35-wdt", .data = &imx_wdt },
+ { .compatible = "fsl,imx50-wdt", .data = &imx_wdt },
+ { .compatible = "fsl,imx51-wdt", .data = &imx_wdt },
+ { .compatible = "fsl,imx53-wdt", .data = &imx_wdt },
+ { .compatible = "fsl,imx6q-wdt", .data = &imx_wdt },
+ { .compatible = "fsl,imx6sl-wdt", .data = &imx_wdt },
+ { .compatible = "fsl,imx6sll-wdt", .data = &imx_wdt },
+ { .compatible = "fsl,imx6sx-wdt", .data = &imx_wdt },
+ { .compatible = "fsl,imx6ul-wdt", .data = &imx_wdt },
+ { .compatible = "fsl,imx7d-wdt", .data = &imx_wdt },
+ { .compatible = "fsl,imx8mm-wdt", .data = &imx_wdt },
+ { .compatible = "fsl,imx8mn-wdt", .data = &imx_wdt },
+ { .compatible = "fsl,imx8mp-wdt", .data = &imx_wdt },
+ { .compatible = "fsl,imx8mq-wdt", .data = &imx_wdt },
+ { .compatible = "fsl,ls1012a-wdt", .data = &imx_wdt_legacy },
+ { .compatible = "fsl,ls1043a-wdt", .data = &imx_wdt_legacy },
+ { .compatible = "fsl,vf610-wdt", .data = &imx_wdt },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, imx2_wdt_dt_ids);
diff --git a/drivers/watchdog/imx7ulp_wdt.c b/drivers/watchdog/imx7ulp_wdt.c
index 2897902090b3..7ca486794ba7 100644
--- a/drivers/watchdog/imx7ulp_wdt.c
+++ b/drivers/watchdog/imx7ulp_wdt.c
@@ -299,11 +299,6 @@ static int imx7ulp_wdt_init(struct imx7ulp_wdt_device *wdt, unsigned int timeout
return ret;
}
-static void imx7ulp_wdt_action(void *data)
-{
- clk_disable_unprepare(data);
-}
-
static int imx7ulp_wdt_probe(struct platform_device *pdev)
{
struct imx7ulp_wdt_device *imx7ulp_wdt;
@@ -321,7 +316,7 @@ static int imx7ulp_wdt_probe(struct platform_device *pdev)
if (IS_ERR(imx7ulp_wdt->base))
return PTR_ERR(imx7ulp_wdt->base);
- imx7ulp_wdt->clk = devm_clk_get(dev, NULL);
+ imx7ulp_wdt->clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(imx7ulp_wdt->clk)) {
dev_err(dev, "Failed to get watchdog clock\n");
return PTR_ERR(imx7ulp_wdt->clk);
@@ -336,14 +331,6 @@ static int imx7ulp_wdt_probe(struct platform_device *pdev)
dev_info(dev, "imx7ulp wdt probe\n");
}
- ret = clk_prepare_enable(imx7ulp_wdt->clk);
- if (ret)
- return ret;
-
- ret = devm_add_action_or_reset(dev, imx7ulp_wdt_action, imx7ulp_wdt->clk);
- if (ret)
- return ret;
-
wdog = &imx7ulp_wdt->wdd;
wdog->info = &imx7ulp_wdt_info;
wdog->ops = &imx7ulp_wdt_ops;
diff --git a/drivers/watchdog/lpc18xx_wdt.c b/drivers/watchdog/lpc18xx_wdt.c
index 60b6d74f267d..1b9b5f21a0df 100644
--- a/drivers/watchdog/lpc18xx_wdt.c
+++ b/drivers/watchdog/lpc18xx_wdt.c
@@ -197,16 +197,10 @@ static const struct watchdog_ops lpc18xx_wdt_ops = {
.restart = lpc18xx_wdt_restart,
};
-static void lpc18xx_clk_disable_unprepare(void *data)
-{
- clk_disable_unprepare(data);
-}
-
static int lpc18xx_wdt_probe(struct platform_device *pdev)
{
struct lpc18xx_wdt_dev *lpc18xx_wdt;
struct device *dev = &pdev->dev;
- int ret;
lpc18xx_wdt = devm_kzalloc(dev, sizeof(*lpc18xx_wdt), GFP_KERNEL);
if (!lpc18xx_wdt)
@@ -216,38 +210,18 @@ static int lpc18xx_wdt_probe(struct platform_device *pdev)
if (IS_ERR(lpc18xx_wdt->base))
return PTR_ERR(lpc18xx_wdt->base);
- lpc18xx_wdt->reg_clk = devm_clk_get(dev, "reg");
+ lpc18xx_wdt->reg_clk = devm_clk_get_enabled(dev, "reg");
if (IS_ERR(lpc18xx_wdt->reg_clk)) {
dev_err(dev, "failed to get the reg clock\n");
return PTR_ERR(lpc18xx_wdt->reg_clk);
}
- lpc18xx_wdt->wdt_clk = devm_clk_get(dev, "wdtclk");
+ lpc18xx_wdt->wdt_clk = devm_clk_get_enabled(dev, "wdtclk");
if (IS_ERR(lpc18xx_wdt->wdt_clk)) {
dev_err(dev, "failed to get the wdt clock\n");
return PTR_ERR(lpc18xx_wdt->wdt_clk);
}
- ret = clk_prepare_enable(lpc18xx_wdt->reg_clk);
- if (ret) {
- dev_err(dev, "could not prepare or enable sys clock\n");
- return ret;
- }
- ret = devm_add_action_or_reset(dev, lpc18xx_clk_disable_unprepare,
- lpc18xx_wdt->reg_clk);
- if (ret)
- return ret;
-
- ret = clk_prepare_enable(lpc18xx_wdt->wdt_clk);
- if (ret) {
- dev_err(dev, "could not prepare or enable wdt clock\n");
- return ret;
- }
- ret = devm_add_action_or_reset(dev, lpc18xx_clk_disable_unprepare,
- lpc18xx_wdt->wdt_clk);
- if (ret)
- return ret;
-
/* We use the clock rate to calculate timeouts */
lpc18xx_wdt->clk_rate = clk_get_rate(lpc18xx_wdt->wdt_clk);
if (lpc18xx_wdt->clk_rate == 0) {
diff --git a/drivers/watchdog/meson_gxbb_wdt.c b/drivers/watchdog/meson_gxbb_wdt.c
index 981a2f7c3bec..35d80cb39856 100644
--- a/drivers/watchdog/meson_gxbb_wdt.c
+++ b/drivers/watchdog/meson_gxbb_wdt.c
@@ -146,16 +146,10 @@ static const struct of_device_id meson_gxbb_wdt_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, meson_gxbb_wdt_dt_ids);
-static void meson_clk_disable_unprepare(void *data)
-{
- clk_disable_unprepare(data);
-}
-
static int meson_gxbb_wdt_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct meson_gxbb_wdt *data;
- int ret;
u32 ctrl_reg;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
@@ -166,18 +160,10 @@ static int meson_gxbb_wdt_probe(struct platform_device *pdev)
if (IS_ERR(data->reg_base))
return PTR_ERR(data->reg_base);
- data->clk = devm_clk_get(dev, NULL);
+ data->clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(data->clk))
return PTR_ERR(data->clk);
- ret = clk_prepare_enable(data->clk);
- if (ret)
- return ret;
- ret = devm_add_action_or_reset(dev, meson_clk_disable_unprepare,
- data->clk);
- if (ret)
- return ret;
-
platform_set_drvdata(pdev, data);
data->wdt_dev.parent = dev;
diff --git a/drivers/watchdog/mt7621_wdt.c b/drivers/watchdog/mt7621_wdt.c
index a8aa3522cfda..442731bba194 100644
--- a/drivers/watchdog/mt7621_wdt.c
+++ b/drivers/watchdog/mt7621_wdt.c
@@ -15,8 +15,8 @@
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
#include <linux/mod_devicetable.h>
-
-#include <asm/mach-ralink/ralink_regs.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
#define SYSC_RSTSTAT 0x38
#define WDT_RST_CAUSE BIT(1)
@@ -31,8 +31,12 @@
#define TMR1CTL_RESTART BIT(9)
#define TMR1CTL_PRESCALE_SHIFT 16
-static void __iomem *mt7621_wdt_base;
-static struct reset_control *mt7621_wdt_reset;
+struct mt7621_wdt_data {
+ void __iomem *base;
+ struct reset_control *rst;
+ struct regmap *sysc;
+ struct watchdog_device wdt;
+};
static bool nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, bool, 0);
@@ -40,27 +44,31 @@ MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
-static inline void rt_wdt_w32(unsigned reg, u32 val)
+static inline void rt_wdt_w32(void __iomem *base, unsigned int reg, u32 val)
{
- iowrite32(val, mt7621_wdt_base + reg);
+ iowrite32(val, base + reg);
}
-static inline u32 rt_wdt_r32(unsigned reg)
+static inline u32 rt_wdt_r32(void __iomem *base, unsigned int reg)
{
- return ioread32(mt7621_wdt_base + reg);
+ return ioread32(base + reg);
}
static int mt7621_wdt_ping(struct watchdog_device *w)
{
- rt_wdt_w32(TIMER_REG_TMRSTAT, TMR1CTL_RESTART);
+ struct mt7621_wdt_data *drvdata = watchdog_get_drvdata(w);
+
+ rt_wdt_w32(drvdata->base, TIMER_REG_TMRSTAT, TMR1CTL_RESTART);
return 0;
}
static int mt7621_wdt_set_timeout(struct watchdog_device *w, unsigned int t)
{
+ struct mt7621_wdt_data *drvdata = watchdog_get_drvdata(w);
+
w->timeout = t;
- rt_wdt_w32(TIMER_REG_TMR1LOAD, t * 1000);
+ rt_wdt_w32(drvdata->base, TIMER_REG_TMR1LOAD, t * 1000);
mt7621_wdt_ping(w);
return 0;
@@ -68,36 +76,41 @@ static int mt7621_wdt_set_timeout(struct watchdog_device *w, unsigned int t)
static int mt7621_wdt_start(struct watchdog_device *w)
{
+ struct mt7621_wdt_data *drvdata = watchdog_get_drvdata(w);
u32 t;
/* set the prescaler to 1ms == 1000us */
- rt_wdt_w32(TIMER_REG_TMR1CTL, 1000 << TMR1CTL_PRESCALE_SHIFT);
+ rt_wdt_w32(drvdata->base, TIMER_REG_TMR1CTL, 1000 << TMR1CTL_PRESCALE_SHIFT);
mt7621_wdt_set_timeout(w, w->timeout);
- t = rt_wdt_r32(TIMER_REG_TMR1CTL);
+ t = rt_wdt_r32(drvdata->base, TIMER_REG_TMR1CTL);
t |= TMR1CTL_ENABLE;
- rt_wdt_w32(TIMER_REG_TMR1CTL, t);
+ rt_wdt_w32(drvdata->base, TIMER_REG_TMR1CTL, t);
return 0;
}
static int mt7621_wdt_stop(struct watchdog_device *w)
{
+ struct mt7621_wdt_data *drvdata = watchdog_get_drvdata(w);
u32 t;
mt7621_wdt_ping(w);
- t = rt_wdt_r32(TIMER_REG_TMR1CTL);
+ t = rt_wdt_r32(drvdata->base, TIMER_REG_TMR1CTL);
t &= ~TMR1CTL_ENABLE;
- rt_wdt_w32(TIMER_REG_TMR1CTL, t);
+ rt_wdt_w32(drvdata->base, TIMER_REG_TMR1CTL, t);
return 0;
}
-static int mt7621_wdt_bootcause(void)
+static int mt7621_wdt_bootcause(struct mt7621_wdt_data *d)
{
- if (rt_sysc_r32(SYSC_RSTSTAT) & WDT_RST_CAUSE)
+ u32 val;
+
+ regmap_read(d->sysc, SYSC_RSTSTAT, &val);
+ if (val & WDT_RST_CAUSE)
return WDIOF_CARDRESET;
return 0;
@@ -105,7 +118,9 @@ static int mt7621_wdt_bootcause(void)
static int mt7621_wdt_is_running(struct watchdog_device *w)
{
- return !!(rt_wdt_r32(TIMER_REG_TMR1CTL) & TMR1CTL_ENABLE);
+ struct mt7621_wdt_data *drvdata = watchdog_get_drvdata(w);
+
+ return !!(rt_wdt_r32(drvdata->base, TIMER_REG_TMR1CTL) & TMR1CTL_ENABLE);
}
static const struct watchdog_info mt7621_wdt_info = {
@@ -121,30 +136,47 @@ static const struct watchdog_ops mt7621_wdt_ops = {
.set_timeout = mt7621_wdt_set_timeout,
};
-static struct watchdog_device mt7621_wdt_dev = {
- .info = &mt7621_wdt_info,
- .ops = &mt7621_wdt_ops,
- .min_timeout = 1,
- .max_timeout = 0xfffful / 1000,
-};
-
static int mt7621_wdt_probe(struct platform_device *pdev)
{
+ struct device_node *np = pdev->dev.of_node;
struct device *dev = &pdev->dev;
- mt7621_wdt_base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(mt7621_wdt_base))
- return PTR_ERR(mt7621_wdt_base);
+ struct watchdog_device *mt7621_wdt;
+ struct mt7621_wdt_data *drvdata;
+ int err;
+
+ drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+
+ drvdata->sysc = syscon_regmap_lookup_by_phandle(np, "mediatek,sysctl");
+ if (IS_ERR(drvdata->sysc)) {
+ drvdata->sysc = syscon_regmap_lookup_by_compatible("mediatek,mt7621-sysc");
+ if (IS_ERR(drvdata->sysc))
+ return PTR_ERR(drvdata->sysc);
+ }
+
+ drvdata->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(drvdata->base))
+ return PTR_ERR(drvdata->base);
+
+ drvdata->rst = devm_reset_control_get_exclusive(dev, NULL);
+ if (!IS_ERR(drvdata->rst))
+ reset_control_deassert(drvdata->rst);
+
+ mt7621_wdt = &drvdata->wdt;
+ mt7621_wdt->info = &mt7621_wdt_info;
+ mt7621_wdt->ops = &mt7621_wdt_ops;
+ mt7621_wdt->min_timeout = 1;
+ mt7621_wdt->max_timeout = 0xfffful / 1000;
+ mt7621_wdt->parent = dev;
- mt7621_wdt_reset = devm_reset_control_get_exclusive(dev, NULL);
- if (!IS_ERR(mt7621_wdt_reset))
- reset_control_deassert(mt7621_wdt_reset);
+ mt7621_wdt->bootstatus = mt7621_wdt_bootcause(drvdata);
- mt7621_wdt_dev.bootstatus = mt7621_wdt_bootcause();
+ watchdog_init_timeout(mt7621_wdt, mt7621_wdt->max_timeout, dev);
+ watchdog_set_nowayout(mt7621_wdt, nowayout);
+ watchdog_set_drvdata(mt7621_wdt, drvdata);
- watchdog_init_timeout(&mt7621_wdt_dev, mt7621_wdt_dev.max_timeout,
- dev);
- watchdog_set_nowayout(&mt7621_wdt_dev, nowayout);
- if (mt7621_wdt_is_running(&mt7621_wdt_dev)) {
+ if (mt7621_wdt_is_running(mt7621_wdt)) {
/*
* Make sure to apply timeout from watchdog core, taking
* the prescaler of this driver here into account (the
@@ -154,17 +186,25 @@ static int mt7621_wdt_probe(struct platform_device *pdev)
* we first disable the watchdog, set the new prescaler
* and timeout, and then re-enable the watchdog.
*/
- mt7621_wdt_stop(&mt7621_wdt_dev);
- mt7621_wdt_start(&mt7621_wdt_dev);
- set_bit(WDOG_HW_RUNNING, &mt7621_wdt_dev.status);
+ mt7621_wdt_stop(mt7621_wdt);
+ mt7621_wdt_start(mt7621_wdt);
+ set_bit(WDOG_HW_RUNNING, &mt7621_wdt->status);
}
- return devm_watchdog_register_device(dev, &mt7621_wdt_dev);
+ err = devm_watchdog_register_device(dev, &drvdata->wdt);
+ if (err)
+ return err;
+
+ platform_set_drvdata(pdev, drvdata);
+
+ return 0;
}
static void mt7621_wdt_shutdown(struct platform_device *pdev)
{
- mt7621_wdt_stop(&mt7621_wdt_dev);
+ struct mt7621_wdt_data *drvdata = platform_get_drvdata(pdev);
+
+ mt7621_wdt_stop(&drvdata->wdt);
}
static const struct of_device_id mt7621_wdt_match[] = {
diff --git a/drivers/watchdog/mtk_wdt.c b/drivers/watchdog/mtk_wdt.c
index 3e6212591e69..a9c437598e7e 100644
--- a/drivers/watchdog/mtk_wdt.c
+++ b/drivers/watchdog/mtk_wdt.c
@@ -50,6 +50,7 @@
#define WDT_MODE_IRQ_EN (1 << 3)
#define WDT_MODE_AUTO_START (1 << 4)
#define WDT_MODE_DUAL_EN (1 << 6)
+#define WDT_MODE_CNT_SEL (1 << 8)
#define WDT_MODE_KEY 0x22000000
#define WDT_SWRST 0x14
@@ -70,6 +71,7 @@ struct mtk_wdt_dev {
spinlock_t lock; /* protects WDT_SWSYSRST reg */
struct reset_controller_dev rcdev;
bool disable_wdt_extrst;
+ bool reset_by_toprgu;
};
struct mtk_wdt_data {
@@ -279,6 +281,8 @@ static int mtk_wdt_start(struct watchdog_device *wdt_dev)
reg &= ~(WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN);
if (mtk_wdt->disable_wdt_extrst)
reg &= ~WDT_MODE_EXRST_EN;
+ if (mtk_wdt->reset_by_toprgu)
+ reg |= WDT_MODE_CNT_SEL;
reg |= (WDT_MODE_EN | WDT_MODE_KEY);
iowrite32(reg, wdt_base + WDT_MODE);
@@ -408,6 +412,9 @@ static int mtk_wdt_probe(struct platform_device *pdev)
mtk_wdt->disable_wdt_extrst =
of_property_read_bool(dev->of_node, "mediatek,disable-extrst");
+ mtk_wdt->reset_by_toprgu =
+ of_property_read_bool(dev->of_node, "mediatek,reset-by-toprgu");
+
return 0;
}
diff --git a/drivers/watchdog/of_xilinx_wdt.c b/drivers/watchdog/of_xilinx_wdt.c
index 3318544366b8..2a079ca04aa3 100644
--- a/drivers/watchdog/of_xilinx_wdt.c
+++ b/drivers/watchdog/of_xilinx_wdt.c
@@ -154,11 +154,6 @@ static u32 xwdt_selftest(struct xwdt_device *xdev)
return XWT_TIMER_FAILED;
}
-static void xwdt_clk_disable_unprepare(void *data)
-{
- clk_disable_unprepare(data);
-}
-
static int xwdt_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -193,7 +188,7 @@ static int xwdt_probe(struct platform_device *pdev)
watchdog_set_nowayout(xilinx_wdt_wdd, enable_once);
- xdev->clk = devm_clk_get(dev, NULL);
+ xdev->clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(xdev->clk)) {
if (PTR_ERR(xdev->clk) != -ENOENT)
return PTR_ERR(xdev->clk);
@@ -211,15 +206,6 @@ static int xwdt_probe(struct platform_device *pdev)
"The watchdog clock freq cannot be obtained\n");
} else {
pfreq = clk_get_rate(xdev->clk);
- rc = clk_prepare_enable(xdev->clk);
- if (rc) {
- dev_err(dev, "unable to enable clock\n");
- return rc;
- }
- rc = devm_add_action_or_reset(dev, xwdt_clk_disable_unprepare,
- xdev->clk);
- if (rc)
- return rc;
}
/*
diff --git a/drivers/watchdog/pcwd_usb.c b/drivers/watchdog/pcwd_usb.c
index 1bdaf17c1d38..8202f0a6b093 100644
--- a/drivers/watchdog/pcwd_usb.c
+++ b/drivers/watchdog/pcwd_usb.c
@@ -325,7 +325,8 @@ static int usb_pcwd_set_heartbeat(struct usb_pcwd_private *usb_pcwd, int t)
static int usb_pcwd_get_temperature(struct usb_pcwd_private *usb_pcwd,
int *temperature)
{
- unsigned char msb, lsb;
+ unsigned char msb = 0x00;
+ unsigned char lsb = 0x00;
usb_pcwd_send_command(usb_pcwd, CMD_READ_TEMP, &msb, &lsb);
@@ -341,7 +342,8 @@ static int usb_pcwd_get_temperature(struct usb_pcwd_private *usb_pcwd,
static int usb_pcwd_get_timeleft(struct usb_pcwd_private *usb_pcwd,
int *time_left)
{
- unsigned char msb, lsb;
+ unsigned char msb = 0x00;
+ unsigned char lsb = 0x00;
/* Read the time that's left before rebooting */
/* Note: if the board is not yet armed then we will read 0xFFFF */
diff --git a/drivers/watchdog/pic32-dmt.c b/drivers/watchdog/pic32-dmt.c
index f43062b3c4c8..bc4ccddc75a3 100644
--- a/drivers/watchdog/pic32-dmt.c
+++ b/drivers/watchdog/pic32-dmt.c
@@ -164,11 +164,6 @@ static struct watchdog_device pic32_dmt_wdd = {
.ops = &pic32_dmt_fops,
};
-static void pic32_clk_disable_unprepare(void *data)
-{
- clk_disable_unprepare(data);
-}
-
static int pic32_dmt_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -184,20 +179,12 @@ static int pic32_dmt_probe(struct platform_device *pdev)
if (IS_ERR(dmt->regs))
return PTR_ERR(dmt->regs);
- dmt->clk = devm_clk_get(dev, NULL);
+ dmt->clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(dmt->clk)) {
dev_err(dev, "clk not found\n");
return PTR_ERR(dmt->clk);
}
- ret = clk_prepare_enable(dmt->clk);
- if (ret)
- return ret;
- ret = devm_add_action_or_reset(dev, pic32_clk_disable_unprepare,
- dmt->clk);
- if (ret)
- return ret;
-
wdd->timeout = pic32_dmt_get_timeout_secs(dmt);
if (!wdd->timeout) {
dev_err(dev, "failed to read watchdog register timeout\n");
diff --git a/drivers/watchdog/pic32-wdt.c b/drivers/watchdog/pic32-wdt.c
index 41715d68d9e9..6d1a00222991 100644
--- a/drivers/watchdog/pic32-wdt.c
+++ b/drivers/watchdog/pic32-wdt.c
@@ -162,11 +162,6 @@ static const struct of_device_id pic32_wdt_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, pic32_wdt_dt_ids);
-static void pic32_clk_disable_unprepare(void *data)
-{
- clk_disable_unprepare(data);
-}
-
static int pic32_wdt_drv_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -186,22 +181,12 @@ static int pic32_wdt_drv_probe(struct platform_device *pdev)
if (!wdt->rst_base)
return -ENOMEM;
- wdt->clk = devm_clk_get(dev, NULL);
+ wdt->clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(wdt->clk)) {
dev_err(dev, "clk not found\n");
return PTR_ERR(wdt->clk);
}
- ret = clk_prepare_enable(wdt->clk);
- if (ret) {
- dev_err(dev, "clk enable failed\n");
- return ret;
- }
- ret = devm_add_action_or_reset(dev, pic32_clk_disable_unprepare,
- wdt->clk);
- if (ret)
- return ret;
-
if (pic32_wdt_is_win_enabled(wdt)) {
dev_err(dev, "windowed-clear mode is not supported.\n");
return -ENODEV;
diff --git a/drivers/watchdog/pnx4008_wdt.c b/drivers/watchdog/pnx4008_wdt.c
index e0ea133c1690..87a44a5675a1 100644
--- a/drivers/watchdog/pnx4008_wdt.c
+++ b/drivers/watchdog/pnx4008_wdt.c
@@ -179,11 +179,6 @@ static struct watchdog_device pnx4008_wdd = {
.max_timeout = MAX_HEARTBEAT,
};
-static void pnx4008_clk_disable_unprepare(void *data)
-{
- clk_disable_unprepare(data);
-}
-
static int pnx4008_wdt_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -195,18 +190,10 @@ static int pnx4008_wdt_probe(struct platform_device *pdev)
if (IS_ERR(wdt_base))
return PTR_ERR(wdt_base);
- wdt_clk = devm_clk_get(dev, NULL);
+ wdt_clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(wdt_clk))
return PTR_ERR(wdt_clk);
- ret = clk_prepare_enable(wdt_clk);
- if (ret)
- return ret;
- ret = devm_add_action_or_reset(dev, pnx4008_clk_disable_unprepare,
- wdt_clk);
- if (ret)
- return ret;
-
pnx4008_wdd.bootstatus = (readl(WDTIM_RES(wdt_base)) & WDOG_RESET) ?
WDIOF_CARDRESET : 0;
pnx4008_wdd.parent = dev;
diff --git a/drivers/watchdog/qcom-wdt.c b/drivers/watchdog/qcom-wdt.c
index 0d2209c5eaca..d776474dcdf3 100644
--- a/drivers/watchdog/qcom-wdt.c
+++ b/drivers/watchdog/qcom-wdt.c
@@ -175,11 +175,6 @@ static const struct watchdog_info qcom_wdt_pt_info = {
.identity = KBUILD_MODNAME,
};
-static void qcom_clk_disable_unprepare(void *data)
-{
- clk_disable_unprepare(data);
-}
-
static const struct qcom_wdt_match_data match_data_apcs_tmr = {
.offset = reg_offset_data_apcs_tmr,
.pretimeout = false,
@@ -226,21 +221,12 @@ static int qcom_wdt_probe(struct platform_device *pdev)
if (IS_ERR(wdt->base))
return PTR_ERR(wdt->base);
- clk = devm_clk_get(dev, NULL);
+ clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(clk)) {
dev_err(dev, "failed to get input clock\n");
return PTR_ERR(clk);
}
- ret = clk_prepare_enable(clk);
- if (ret) {
- dev_err(dev, "failed to setup clock\n");
- return ret;
- }
- ret = devm_add_action_or_reset(dev, qcom_clk_disable_unprepare, clk);
- if (ret)
- return ret;
-
/*
* We use the clock rate to calculate the max timeout, so ensure it's
* not zero to avoid a divide-by-zero exception.
diff --git a/drivers/watchdog/realtek_otto_wdt.c b/drivers/watchdog/realtek_otto_wdt.c
index 2a5298c5e8e4..2c30ddd574c5 100644
--- a/drivers/watchdog/realtek_otto_wdt.c
+++ b/drivers/watchdog/realtek_otto_wdt.c
@@ -235,27 +235,14 @@ static const struct watchdog_info otto_wdt_info = {
WDIOF_PRETIMEOUT,
};
-static void otto_wdt_clock_action(void *data)
-{
- clk_disable_unprepare(data);
-}
-
static int otto_wdt_probe_clk(struct otto_wdt_ctrl *ctrl)
{
- struct clk *clk = devm_clk_get(ctrl->dev, NULL);
- int ret;
+ struct clk *clk;
+ clk = devm_clk_get_enabled(ctrl->dev, NULL);
if (IS_ERR(clk))
return dev_err_probe(ctrl->dev, PTR_ERR(clk), "Failed to get clock\n");
- ret = clk_prepare_enable(clk);
- if (ret)
- return dev_err_probe(ctrl->dev, ret, "Failed to enable clock\n");
-
- ret = devm_add_action_or_reset(ctrl->dev, otto_wdt_clock_action, clk);
- if (ret)
- return ret;
-
ctrl->clk_rate_khz = clk_get_rate(clk) / 1000;
if (ctrl->clk_rate_khz == 0)
return dev_err_probe(ctrl->dev, -ENXIO, "Failed to get clock rate\n");
diff --git a/drivers/watchdog/rtd119x_wdt.c b/drivers/watchdog/rtd119x_wdt.c
index 834b94ff3f90..95c8d7abce42 100644
--- a/drivers/watchdog/rtd119x_wdt.c
+++ b/drivers/watchdog/rtd119x_wdt.c
@@ -94,16 +94,10 @@ static const struct of_device_id rtd119x_wdt_dt_ids[] = {
{ }
};
-static void rtd119x_clk_disable_unprepare(void *data)
-{
- clk_disable_unprepare(data);
-}
-
static int rtd119x_wdt_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct rtd119x_watchdog_device *data;
- int ret;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
@@ -113,18 +107,10 @@ static int rtd119x_wdt_probe(struct platform_device *pdev)
if (IS_ERR(data->base))
return PTR_ERR(data->base);
- data->clk = devm_clk_get(dev, NULL);
+ data->clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(data->clk))
return PTR_ERR(data->clk);
- ret = clk_prepare_enable(data->clk);
- if (ret)
- return ret;
- ret = devm_add_action_or_reset(dev, rtd119x_clk_disable_unprepare,
- data->clk);
- if (ret)
- return ret;
-
data->wdt_dev.info = &rtd119x_wdt_info;
data->wdt_dev.ops = &rtd119x_wdt_ops;
data->wdt_dev.timeout = 120;
diff --git a/drivers/watchdog/rzg2l_wdt.c b/drivers/watchdog/rzg2l_wdt.c
index 974a4194a8fd..d404953d0e0f 100644
--- a/drivers/watchdog/rzg2l_wdt.c
+++ b/drivers/watchdog/rzg2l_wdt.c
@@ -8,6 +8,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_device.h>
@@ -35,6 +36,8 @@
#define F2CYCLE_NSEC(f) (1000000000 / (f))
+#define RZV2M_A_NSEC 730
+
static bool nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
@@ -51,11 +54,35 @@ struct rzg2l_wdt_priv {
struct reset_control *rstc;
unsigned long osc_clk_rate;
unsigned long delay;
+ unsigned long minimum_assertion_period;
struct clk *pclk;
struct clk *osc_clk;
enum rz_wdt_type devtype;
};
+static int rzg2l_wdt_reset(struct rzg2l_wdt_priv *priv)
+{
+ int err, status;
+
+ if (priv->devtype == WDT_RZV2M) {
+ /* WDT needs TYPE-B reset control */
+ err = reset_control_assert(priv->rstc);
+ if (err)
+ return err;
+ ndelay(priv->minimum_assertion_period);
+ err = reset_control_deassert(priv->rstc);
+ if (err)
+ return err;
+ err = read_poll_timeout(reset_control_status, status,
+ status != 1, 0, 1000, false,
+ priv->rstc);
+ } else {
+ err = reset_control_reset(priv->rstc);
+ }
+
+ return err;
+}
+
static void rzg2l_wdt_wait_delay(struct rzg2l_wdt_priv *priv)
{
/* delay timer when change the setting register */
@@ -115,25 +142,23 @@ static int rzg2l_wdt_stop(struct watchdog_device *wdev)
{
struct rzg2l_wdt_priv *priv = watchdog_get_drvdata(wdev);
+ rzg2l_wdt_reset(priv);
pm_runtime_put(wdev->parent);
- reset_control_reset(priv->rstc);
return 0;
}
static int rzg2l_wdt_set_timeout(struct watchdog_device *wdev, unsigned int timeout)
{
- struct rzg2l_wdt_priv *priv = watchdog_get_drvdata(wdev);
-
wdev->timeout = timeout;
/*
* If the watchdog is active, reset the module for updating the WDTSET
- * register so that it is updated with new timeout values.
+ * register by calling rzg2l_wdt_stop() (which internally calls reset_control_reset()
+ * to reset the module) so that it is updated with new timeout values.
*/
if (watchdog_active(wdev)) {
- pm_runtime_put(wdev->parent);
- reset_control_reset(priv->rstc);
+ rzg2l_wdt_stop(wdev);
rzg2l_wdt_start(wdev);
}
@@ -156,6 +181,7 @@ static int rzg2l_wdt_restart(struct watchdog_device *wdev,
rzg2l_wdt_write(priv, PEEN_FORCE, PEEN);
} else {
/* RZ/V2M doesn't have parity error registers */
+ rzg2l_wdt_reset(priv);
wdev->timeout = 0;
@@ -253,6 +279,13 @@ static int rzg2l_wdt_probe(struct platform_device *pdev)
priv->devtype = (uintptr_t)of_device_get_match_data(dev);
+ if (priv->devtype == WDT_RZV2M) {
+ priv->minimum_assertion_period = RZV2M_A_NSEC +
+ 3 * F2CYCLE_NSEC(pclk_rate) + 5 *
+ max(F2CYCLE_NSEC(priv->osc_clk_rate),
+ F2CYCLE_NSEC(pclk_rate));
+ }
+
pm_runtime_enable(&pdev->dev);
priv->wdev.info = &rzg2l_wdt_ident;
diff --git a/drivers/watchdog/rzn1_wdt.c b/drivers/watchdog/rzn1_wdt.c
index 55ab384b9965..980c1717adb5 100644
--- a/drivers/watchdog/rzn1_wdt.c
+++ b/drivers/watchdog/rzn1_wdt.c
@@ -98,11 +98,6 @@ static const struct watchdog_ops rzn1_wdt_ops = {
.ping = rzn1_wdt_ping,
};
-static void rzn1_wdt_clk_disable_unprepare(void *data)
-{
- clk_disable_unprepare(data);
-}
-
static int rzn1_wdt_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -132,23 +127,12 @@ static int rzn1_wdt_probe(struct platform_device *pdev)
return ret;
}
- clk = devm_clk_get(dev, NULL);
+ clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(clk)) {
dev_err(dev, "failed to get the clock\n");
return PTR_ERR(clk);
}
- ret = clk_prepare_enable(clk);
- if (ret) {
- dev_err(dev, "failed to prepare/enable the clock\n");
- return ret;
- }
-
- ret = devm_add_action_or_reset(dev, rzn1_wdt_clk_disable_unprepare,
- clk);
- if (ret)
- return ret;
-
clk_rate = clk_get_rate(clk);
if (!clk_rate) {
dev_err(dev, "failed to get the clock rate\n");
diff --git a/drivers/watchdog/sbsa_gwdt.c b/drivers/watchdog/sbsa_gwdt.c
index 9791c74aebd4..63862803421f 100644
--- a/drivers/watchdog/sbsa_gwdt.c
+++ b/drivers/watchdog/sbsa_gwdt.c
@@ -150,6 +150,7 @@ static int sbsa_gwdt_set_timeout(struct watchdog_device *wdd,
struct sbsa_gwdt *gwdt = watchdog_get_drvdata(wdd);
wdd->timeout = timeout;
+ timeout = clamp_t(unsigned int, timeout, 1, wdd->max_hw_heartbeat_ms / 1000);
if (action)
sbsa_gwdt_reg_write(gwdt->clk * timeout, gwdt);
diff --git a/drivers/watchdog/visconti_wdt.c b/drivers/watchdog/visconti_wdt.c
index 83ef55e66ca8..cef0794708e7 100644
--- a/drivers/watchdog/visconti_wdt.c
+++ b/drivers/watchdog/visconti_wdt.c
@@ -112,11 +112,6 @@ static const struct watchdog_ops visconti_wdt_ops = {
.set_timeout = visconti_wdt_set_timeout,
};
-static void visconti_clk_disable_unprepare(void *data)
-{
- clk_disable_unprepare(data);
-}
-
static int visconti_wdt_probe(struct platform_device *pdev)
{
struct watchdog_device *wdev;
@@ -134,20 +129,10 @@ static int visconti_wdt_probe(struct platform_device *pdev)
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
- clk = devm_clk_get(dev, NULL);
+ clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(clk))
return dev_err_probe(dev, PTR_ERR(clk), "Could not get clock\n");
- ret = clk_prepare_enable(clk);
- if (ret) {
- dev_err(dev, "Could not enable clock\n");
- return ret;
- }
-
- ret = devm_add_action_or_reset(dev, visconti_clk_disable_unprepare, clk);
- if (ret)
- return ret;
-
clk_freq = clk_get_rate(clk);
if (!clk_freq)
return -EINVAL;
diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c
index 55574ed42504..0122e8796879 100644
--- a/drivers/watchdog/watchdog_dev.c
+++ b/drivers/watchdog/watchdog_dev.c
@@ -35,6 +35,7 @@
#include <linux/init.h> /* For __init/__exit/... */
#include <linux/hrtimer.h> /* For hrtimers */
#include <linux/kernel.h> /* For printk/panic/... */
+#include <linux/kstrtox.h> /* For kstrto* */
#include <linux/kthread.h> /* For kthread_work */
#include <linux/miscdevice.h> /* For handling misc devices */
#include <linux/module.h> /* For module stuff/... */
@@ -546,6 +547,24 @@ static ssize_t pretimeout_show(struct device *dev,
}
static DEVICE_ATTR_RO(pretimeout);
+static ssize_t options_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct watchdog_device *wdd = dev_get_drvdata(dev);
+
+ return sysfs_emit(buf, "0x%x\n", wdd->info->options);
+}
+static DEVICE_ATTR_RO(options);
+
+static ssize_t fw_version_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct watchdog_device *wdd = dev_get_drvdata(dev);
+
+ return sysfs_emit(buf, "%d\n", wdd->info->firmware_version);
+}
+static DEVICE_ATTR_RO(fw_version);
+
static ssize_t identity_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -617,6 +636,8 @@ static umode_t wdt_is_visible(struct kobject *kobj, struct attribute *attr,
}
static struct attribute *wdt_attrs[] = {
&dev_attr_state.attr,
+ &dev_attr_options.attr,
+ &dev_attr_fw_version.attr,
&dev_attr_identity.attr,
&dev_attr_timeout.attr,
&dev_attr_min_timeout.attr,
@@ -1061,8 +1082,8 @@ static int watchdog_cdev_register(struct watchdog_device *wdd)
if (wdd->id == 0) {
misc_deregister(&watchdog_miscdev);
old_wd_data = NULL;
- put_device(&wd_data->dev);
}
+ put_device(&wd_data->dev);
return err;
}
diff --git a/drivers/watchdog/wdat_wdt.c b/drivers/watchdog/wdat_wdt.c
index ce7a4a9e4b03..0ba99bed59fc 100644
--- a/drivers/watchdog/wdat_wdt.c
+++ b/drivers/watchdog/wdat_wdt.c
@@ -301,13 +301,12 @@ static const struct watchdog_info wdat_wdt_info = {
.identity = "wdat_wdt",
};
-static const struct watchdog_ops wdat_wdt_ops = {
+static struct watchdog_ops wdat_wdt_ops = {
.owner = THIS_MODULE,
.start = wdat_wdt_start,
.stop = wdat_wdt_stop,
.ping = wdat_wdt_ping,
.set_timeout = wdat_wdt_set_timeout,
- .get_timeleft = wdat_wdt_get_timeleft,
};
static int wdat_wdt_probe(struct platform_device *pdev)
@@ -436,6 +435,9 @@ static int wdat_wdt_probe(struct platform_device *pdev)
list_add_tail(&instr->node, instructions);
}
+ if (wdat->instructions[ACPI_WDAT_GET_CURRENT_COUNTDOWN])
+ wdat_wdt_ops.get_timeleft = wdat_wdt_get_timeleft;
+
wdat_wdt_boot_status(wdat);
wdat_wdt_set_running(wdat);
diff --git a/drivers/watchdog/ziirave_wdt.c b/drivers/watchdog/ziirave_wdt.c
index d0e88875443a..21ca08a694ee 100644
--- a/drivers/watchdog/ziirave_wdt.c
+++ b/drivers/watchdog/ziirave_wdt.c
@@ -593,8 +593,7 @@ static int ziirave_wdt_init_duration(struct i2c_client *client)
reset_duration);
}
-static int ziirave_wdt_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ziirave_wdt_probe(struct i2c_client *client)
{
int ret;
struct ziirave_wdt_data *w_priv;
@@ -732,7 +731,7 @@ static struct i2c_driver ziirave_wdt_driver = {
.name = "ziirave_wdt",
.of_match_table = zrv_wdt_of_match,
},
- .probe = ziirave_wdt_probe,
+ .probe_new = ziirave_wdt_probe,
.remove = ziirave_wdt_remove,
.id_table = ziirave_wdt_id,
};
diff --git a/drivers/xen/efi.c b/drivers/xen/efi.c
index d1ff2186ebb4..fb321cd6415a 100644
--- a/drivers/xen/efi.c
+++ b/drivers/xen/efi.c
@@ -26,6 +26,7 @@
#include <xen/interface/xen.h>
#include <xen/interface/platform.h>
+#include <xen/page.h>
#include <xen/xen.h>
#include <xen/xen-ops.h>
@@ -292,3 +293,63 @@ void __init xen_efi_runtime_setup(void)
efi.get_next_high_mono_count = xen_efi_get_next_high_mono_count;
efi.reset_system = xen_efi_reset_system;
}
+
+int efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md)
+{
+ static_assert(XEN_PAGE_SHIFT == EFI_PAGE_SHIFT,
+ "Mismatch between EFI_PAGE_SHIFT and XEN_PAGE_SHIFT");
+ struct xen_platform_op op;
+ union xenpf_efi_info *info = &op.u.firmware_info.u.efi_info;
+ int rc;
+
+ if (!efi_enabled(EFI_PARAVIRT) || efi_enabled(EFI_MEMMAP))
+ return __efi_mem_desc_lookup(phys_addr, out_md);
+ phys_addr &= ~(u64)(EFI_PAGE_SIZE - 1);
+ op = (struct xen_platform_op) {
+ .cmd = XENPF_firmware_info,
+ .u.firmware_info = {
+ .type = XEN_FW_EFI_INFO,
+ .index = XEN_FW_EFI_MEM_INFO,
+ .u.efi_info.mem.addr = phys_addr,
+ .u.efi_info.mem.size = U64_MAX - phys_addr,
+ },
+ };
+
+ rc = HYPERVISOR_platform_op(&op);
+ if (rc) {
+ pr_warn("Failed to lookup header 0x%llx in Xen memory map: error %d\n",
+ phys_addr, rc);
+ }
+
+ out_md->phys_addr = info->mem.addr;
+ out_md->num_pages = info->mem.size >> EFI_PAGE_SHIFT;
+ out_md->type = info->mem.type;
+ out_md->attribute = info->mem.attr;
+
+ return 0;
+}
+
+bool __init xen_efi_config_table_is_usable(const efi_guid_t *guid,
+ unsigned long table)
+{
+ efi_memory_desc_t md;
+ int rc;
+
+ if (!efi_enabled(EFI_PARAVIRT))
+ return true;
+
+ rc = efi_mem_desc_lookup(table, &md);
+ if (rc)
+ return false;
+
+ switch (md.type) {
+ case EFI_RUNTIME_SERVICES_CODE:
+ case EFI_RUNTIME_SERVICES_DATA:
+ case EFI_ACPI_RECLAIM_MEMORY:
+ case EFI_ACPI_MEMORY_NVS:
+ case EFI_RESERVED_TYPE:
+ return true;
+ default:
+ return false;
+ }
+}
diff --git a/drivers/xen/gntalloc.c b/drivers/xen/gntalloc.c
index a15729beb9d1..26ffb8755ffb 100644
--- a/drivers/xen/gntalloc.c
+++ b/drivers/xen/gntalloc.c
@@ -525,7 +525,7 @@ static int gntalloc_mmap(struct file *filp, struct vm_area_struct *vma)
vma->vm_private_data = vm_priv;
- vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
+ vm_flags_set(vma, VM_DONTEXPAND | VM_DONTDUMP);
vma->vm_ops = &gntalloc_vmops;
diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
index 4d9a3050de6a..61faea1f0663 100644
--- a/drivers/xen/gntdev.c
+++ b/drivers/xen/gntdev.c
@@ -1055,10 +1055,10 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma)
vma->vm_ops = &gntdev_vmops;
- vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP | VM_MIXEDMAP;
+ vm_flags_set(vma, VM_DONTEXPAND | VM_DONTDUMP | VM_MIXEDMAP);
if (use_ptemod)
- vma->vm_flags |= VM_DONTCOPY;
+ vm_flags_set(vma, VM_DONTCOPY);
vma->vm_private_data = map;
if (map->flags) {
diff --git a/drivers/xen/privcmd-buf.c b/drivers/xen/privcmd-buf.c
index dd5bbb6e1b6b..2fa10ca5be14 100644
--- a/drivers/xen/privcmd-buf.c
+++ b/drivers/xen/privcmd-buf.c
@@ -156,7 +156,7 @@ static int privcmd_buf_mmap(struct file *file, struct vm_area_struct *vma)
vma_priv->file_priv = file_priv;
vma_priv->users = 1;
- vma->vm_flags |= VM_IO | VM_DONTEXPAND;
+ vm_flags_set(vma, VM_IO | VM_DONTEXPAND);
vma->vm_ops = &privcmd_buf_vm_ops;
vma->vm_private_data = vma_priv;
diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c
index 1edf45ee9890..e2f580e30a86 100644
--- a/drivers/xen/privcmd.c
+++ b/drivers/xen/privcmd.c
@@ -934,8 +934,8 @@ static int privcmd_mmap(struct file *file, struct vm_area_struct *vma)
{
/* DONTCOPY is essential for Xen because copy_page_range doesn't know
* how to recreate these mappings */
- vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTCOPY |
- VM_DONTEXPAND | VM_DONTDUMP;
+ vm_flags_set(vma, VM_IO | VM_PFNMAP | VM_DONTCOPY |
+ VM_DONTEXPAND | VM_DONTDUMP);
vma->vm_ops = &privcmd_vm_ops;
vma->vm_private_data = NULL;
diff --git a/drivers/xen/pvcalls-back.c b/drivers/xen/pvcalls-back.c
index dcb00938de61..1f5219e12cc3 100644
--- a/drivers/xen/pvcalls-back.c
+++ b/drivers/xen/pvcalls-back.c
@@ -1191,7 +1191,7 @@ static void pvcalls_back_remove(struct xenbus_device *dev)
{
}
-static int pvcalls_back_uevent(struct xenbus_device *xdev,
+static int pvcalls_back_uevent(const struct xenbus_device *xdev,
struct kobj_uevent_env *env)
{
return 0;
diff --git a/drivers/xen/xenbus/xenbus_probe_backend.c b/drivers/xen/xenbus/xenbus_probe_backend.c
index 9c09f89d8278..da96c260e26b 100644
--- a/drivers/xen/xenbus/xenbus_probe_backend.c
+++ b/drivers/xen/xenbus/xenbus_probe_backend.c
@@ -92,12 +92,12 @@ static int backend_bus_id(char bus_id[XEN_BUS_ID_SIZE], const char *nodename)
return 0;
}
-static int xenbus_uevent_backend(struct device *dev,
+static int xenbus_uevent_backend(const struct device *dev,
struct kobj_uevent_env *env)
{
- struct xenbus_device *xdev;
- struct xenbus_driver *drv;
- struct xen_bus_type *bus;
+ const struct xenbus_device *xdev;
+ const struct xenbus_driver *drv;
+ const struct xen_bus_type *bus;
DPRINTK("");
diff --git a/drivers/xen/xenbus/xenbus_probe_frontend.c b/drivers/xen/xenbus/xenbus_probe_frontend.c
index f44d5a64351e..3f3836cb7279 100644
--- a/drivers/xen/xenbus/xenbus_probe_frontend.c
+++ b/drivers/xen/xenbus/xenbus_probe_frontend.c
@@ -73,10 +73,10 @@ static int xenbus_probe_frontend(struct xen_bus_type *bus, const char *type,
return err;
}
-static int xenbus_uevent_frontend(struct device *_dev,
+static int xenbus_uevent_frontend(const struct device *_dev,
struct kobj_uevent_env *env)
{
- struct xenbus_device *dev = to_xenbus_device(_dev);
+ const struct xenbus_device *dev = to_xenbus_device(_dev);
if (add_uevent_var(env, "MODALIAS=xen:%s", dev->devicetype))
return -ENOMEM;
diff --git a/drivers/zorro/zorro-driver.c b/drivers/zorro/zorro-driver.c
index 96f068830549..025edfccedcf 100644
--- a/drivers/zorro/zorro-driver.c
+++ b/drivers/zorro/zorro-driver.c
@@ -130,9 +130,9 @@ static int zorro_bus_match(struct device *dev, struct device_driver *drv)
return !!zorro_match_device(ids, z);
}
-static int zorro_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int zorro_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct zorro_dev *z;
+ const struct zorro_dev *z;
if (!dev)
return -ENODEV;